[
  {
    "path": ".agents/skills/canary/SKILL.md",
    "content": "---\nname: canary\ndescription: Triggers a canary release for a Storybook PR. Use when the user wants to publish a canary version, create a pre-release, or test a PR via npm.\nallowed-tools: Bash\n---\n\n# Publish Canary Release\n\nPublishes a canary version of Storybook from a PR to npm.\n\n## Usage\n\nTo trigger a canary release, run:\n\n```bash\ngh workflow run --repo storybookjs/storybook publish.yml --field pr=<PR_NUMBER>\n```\n\n## What happens\n\n1. GitHub Actions builds and publishes the PR as `0.0.0-pr-<PR_NUMBER>-sha-<SHORT_SHA>`\n2. The version is published to npm with the `canary` tag\n3. The PR body is updated with the exact version and install instructions\n\n## Version format\n\nThe canary version follows a **predictable structure**:\n\n```\n0.0.0-pr-<PR_NUMBER>-sha-<SHORT_SHA>\n```\n\n- `<PR_NUMBER>`: The PR number (e.g., `33526`)\n- `<SHORT_SHA>`: First 8 characters of the commit SHA (e.g., `a2e09fa2`)\n\n**Example:** For PR #33526 with commit `a2e09fa284a...`, the canary version is:\n`0.0.0-pr-33526-sha-a2e09fa2`\n\nYou can construct the version yourself if you know the PR number and the latest commit SHA on that PR.\n\n## After publishing\n\nCheck the PR body for the published version. It will show something like:\n\n> This pull request has been released as version `0.0.0-pr-33365-sha-b6656566`\n\nThen test with:\n\n```bash\nnpx storybook@<VERSION_FROM_PR> sandbox\n```\n\nOr upgrade an existing project:\n\n```bash\nnpx storybook@<VERSION_FROM_PR> upgrade\n```\n\n## Requirements\n\n- You must have admin permissions on the storybookjs/storybook repo\n- The PR must exist and be open\n- You need `gh` CLI authenticated\n\n## Monitor progress\n\nWatch the workflow run at:\nhttps://github.com/storybookjs/storybook/actions/workflows/publish.yml\n"
  },
  {
    "path": ".agents/skills/fix-linting-types-on-pr/SKILL.md",
    "content": "---\nname: fix-linting-types-on-pr\ndescription: Checks out a PR (including fork PRs), fixes all linting and TypeScript errors, then pushes the changes back. Use when asked to fix lint, types, or TS errors on a PR.\n---\n\n# Fix Linting and TypeScript Issues on a PR\n\nChecks out a PR, auto-fixes linting and TypeScript issues, and pushes the fixes.\n\n## Step 1 — Get the PR number\n\nIf the user provided a PR number, use it directly. Otherwise ask for it.\n\n## Step 2 — Check out the PR\n\nUse `gh pr checkout` so it works for both fork and non-fork PRs:\n\n```bash\ngh pr checkout <PR_NUMBER>\n```\n\nThis automatically sets up the correct remote tracking and switches to the PR branch, even when the PR comes from a fork.\n\n## Step 3 — Install dependencies\n\n```bash\nyarn\n```\n\n## Step 4 — Compile the repo\n\nCompiling first ensures TS declarations referenced by the linter are present:\n\n```bash\nyarn nx run-many -t compile\n```\n\n## Step 5 — Fix linting errors\n\n```bash\nyarn lint\n```\n\n## Step 6 — Fix TypeScript errors\n\nRun the TypeScript checker to surface remaining type errors:\n\n```bash\nyarn nx run-many -t check\n```\n\nRead the output carefully. Fix each type error manually by editing the relevant file(s). Common fixes:\n\n- Add or correct type annotations\n- Fix incorrect generics\n- Resolve `any` assignments that violate strict mode\n- Add missing imports or re-exports\n\nRe-run `yarn nx run-many -t check` after each batch of edits to confirm errors are resolved.\n\n## Step 7 — Commit the fixes\n\nStage only the files you changed:\n\n```bash\ngit add <files-you-modified>\ngit commit -m \"Maintenance: Fix linting and TypeScript errors\"\n```\n\nDo not use `git add -A` — avoid accidentally staging unrelated files.\n\n## Step 8 — Push the fixes\n\nFor fork PRs `gh pr checkout` sets up the correct upstream tracking. Push directly:\n\n```bash\ngit push\n```\n\n## Notes\n\n- Only fix errors that are clearly linting or TypeScript issues. Do not refactor logic.\n- If a TypeScript error requires a non-trivial code change, surface it to the user and ask before proceeding.\n- If `gh pr checkout` fails due to permissions on a fork, inform the user — they may need to grant write access to the fork or the maintainer must push directly.\n- After pushing, confirm with the user that the CI is green.\n"
  },
  {
    "path": ".agents/skills/github-qa-labels/SKILL.md",
    "content": "---\nname: github-qa-labels\ndescription: Label GitHub issues and PRs found during QA testing. Use when organizing QA findings with proper labels.\nallowed-tools: Bash\n---\n\n# GitHub QA Labels\n\nWhen creating or organizing issues/PRs found during QA testing, apply these labels.\n\n## QA tracking label\n\nAdd `upgrade:<version>` label to track all QA findings for a release:\n\n```bash\n# Create label if it doesn't exist\ngh label create \"upgrade:10.2\" --repo storybookjs/storybook --color \"0E8A16\" --description \"Issues/PRs found during 10.2 upgrade QA\"\n\n# Add to issue/PR\ngh issue edit <NUMBER> --repo storybookjs/storybook --add-label \"upgrade:10.2\"\ngh pr edit <NUMBER> --repo storybookjs/storybook --add-label \"upgrade:10.2\"\n```\n\n## Severity labels\n\nAdd `sev:S1` through `sev:S4` to **bugs only** (not docs or feature requests):\n\n```bash\ngh issue edit <NUMBER> --repo storybookjs/storybook --add-label \"sev:S2\"\n```\n\nSeverity levels:\n\n- **sev:S1**: Critical, blocking, no workaround\n- **sev:S2**: Significant issue, may have workaround\n- **sev:S3**: Moderate issue, workaround exists\n- **sev:S4**: Minor issue, edge case, easy workaround\n\n## What gets severity labels\n\n| Type                    | Severity label? |\n| ----------------------- | --------------- |\n| Bug (runtime error)     | Yes             |\n| Bug (type error)        | Yes             |\n| Bug (automigrate issue) | Yes             |\n| Documentation issue     | No              |\n| Feature request         | No              |\n| Enhancement             | No              |\n\n## Batch labeling\n\nLabel multiple issues at once:\n\n```bash\ngh issue edit 33524 --repo storybookjs/storybook --add-label \"upgrade:10.2\" && \\\ngh issue edit 33527 --repo storybookjs/storybook --add-label \"upgrade:10.2\" && \\\ngh pr edit 33526 --repo storybookjs/storybook --add-label \"upgrade:10.2\"\n```\n"
  },
  {
    "path": ".agents/skills/pr/SKILL.md",
    "content": "---\nname: pr\ndescription: Creates a pull request following Storybook conventions. Use when creating PRs, opening pull requests, or submitting changes for review.\nallowed-tools: Bash, Read\n---\n\n# Create Pull Request\n\nCreates a PR following Storybook conventions.\n\n## Title format\n\n`[Area]: [Description]`\n\n- Area is capitalized, no spaces (dashes allowed)\n- Examples:\n  - `CSFFactories: Fix type export`\n  - `Nextjs-Vite: Add support`\n  - `CLI: Fix automigrate issue`\n\n## Labels\n\nAdd these labels to the PR:\n\n**Category (required, pick one):**\n\n- `bug` - fixes incorrect behavior\n- `maintenance` - user-facing maintenance\n- `dependencies` - upgrading/downgrading deps\n- `build` - internal build/test updates (no changelog)\n- `cleanup` - minor cleanup (no changelog)\n- `documentation` - docs only (no changelog)\n- `feature request` - new feature\n- `BREAKING CHANGE` - breaks compatibility\n- `other` - doesn't fit above\n\n**CI (required, pick one):**\n\n- `ci:normal` - standard sandbox set; default for most code changes\n- `ci:merged` - merged sandbox set\n- `ci:daily` - daily sandbox set; use this when changes affect prerelease sandboxes or sandboxes pinned to a framework or React version other than latest\n- `ci:docs` - documentation-only changes (use with `documentation` category)\n\n## PR body\n\nRead `.github/PULL_REQUEST_TEMPLATE.md` from the repository root.\n\nCopy that template **EXACTLY**, including all HTML comments (`<!-- ... -->`). Fill in the relevant sections based on the changes, but keep all comments intact.\n\n## Command\n\nAlways create PRs in draft mode:\n\n```bash\ngh pr create --draft --title \"<Area>: <Description>\" --body \"<FILLED_TEMPLATE>\" --label \"<category>,<ci>\"\n```\n"
  },
  {
    "path": ".agents/skills/storybook-upgrade/SKILL.md",
    "content": "---\nname: storybook-upgrade\ndescription: Upgrade Storybook to a specific version (canary or release). Use this when upgrading Storybook packages in an external app, reproduction, or test project.\nallowed-tools: Bash\n---\n\n# Storybook Upgrade\n\nUpgrades all Storybook packages in a project to a specific version.\n\n## Why this matters for the monorepo\n\nThis skill is mainly for validating Storybook changes outside this repository.\n\n- QA a canary build from a Storybook PR in a downstream app\n- Reproduce or verify a bug in an external project\n\n## Usage\n\n```bash\nnpx storybook@<VERSION> upgrade\n```\n\n## Examples\n\n### Upgrade to canary version\n\n```bash\nnpx storybook@0.0.0-pr-33526-sha-a2e09fa2 upgrade\n```\n\n### Upgrade to latest stable\n\n```bash\nnpx storybook@latest upgrade\n```\n\n### Upgrade to specific release\n\n```bash\nnpx storybook@8.5.0 upgrade\n```\n\n## What it does\n\n1. Detects all `@storybook/*` packages in your project\n2. Upgrades them all to the specified version\n3. Handles peer dependencies automatically\n4. Works with npm, yarn, and pnpm\n\n## Important\n\n- **DO NOT** manually install storybook packages with `npm add` / `yarn add` / `pnpm add`\n- Always use `npx storybook@<version> upgrade` to ensure all packages stay in sync\n- The upgrade command handles version resolution across all storybook packages\n- **ALWAYS upgrade only 1 major version at a time!**\n  - Example: 8.x → 9.x → 10.x → canary of 10\n  - Never skip major versions (e.g., don't go from 8.x directly to 10.x)\n"
  },
  {
    "path": ".circleci/config.yml",
    "content": "version: 2.1\n\n# https://circleci.com/docs/guides/orchestrate/dynamic-config/\nsetup: true\n\norbs:\n  git-shallow-clone: guitarrapc/git-shallow-clone@2.8.0\n  continuation: circleci/continuation@2.0.1\n  node: circleci/node@7.2.1\n\nparameters:\n  ghBaseBranch:\n    default: next\n    description: The name of the base branch (the target of the PR)\n    type: string\n  ghPrNumber:\n    default: ''\n    description: The PR number\n    type: string\n  workflow:\n    default: skipped\n    description: Which workflow to run\n    enum:\n      - normal\n      - merged\n      - daily\n      - skipped\n      - docs\n    type: enum\n\njobs:\n  generate-and-run-config:\n    executor: \n      name: node/default\n      resource_class: small\n    steps:\n      - node/install:\n          install-yarn: true\n      - git-shallow-clone/checkout_advanced:\n          clone_options: '--depth 1'\n      - run:\n          name: Install dependencies\n          command: yarn workspaces focus @storybook/scripts\n      - run:\n          name: Generate config\n          command: |\n            yarn dlx jiti ./scripts/ci/main.ts --workflow=<< pipeline.parameters.workflow >>\n      - continuation/continue:\n          configuration_path: .circleci/config.generated.yml\nworkflows:\n  setup:\n    jobs:\n      - generate-and-run-config\n    when: pipeline.parameters.workflow != \"skipped\"\n"
  },
  {
    "path": ".cursor/environment.json",
    "content": "{\n  \"snapshot\": \"snapshot-20250521-0222c8bd-0a11-48ab-a2a8-380203843e05\",\n  \"install\": \"yarn && yarn task --task=compile --start-from=compile\",\n  \"start\": \"cd /workspace/code && yarn test\",\n  \"terminals\": []\n}\n"
  },
  {
    "path": ".cursor/rules/spy-mocking.mdc",
    "content": "---\ndescription: Rules for consistent and type-safe mocking in Vitest tests\nglobs: \"**/*.test.{ts,tsx,js,jsx}\"\nalwaysApply: true\n---\n\n# Spy Mocking Rules for Vitest Tests\n\n## Mocking Approach\n\nWhen mocking packages or files in Vitest-based tests, follow these rules:\n\n1. Use `vi.mock()` with the `spy: true` option for all package and file mocks\n2. Place all mocks at the top of the test file before any test cases\n3. Use `vi.mocked()` to type and access the mocked functions\n4. Implement mock behaviors in `beforeEach` blocks\n5. Mock all required dependencies that the test subject uses\n\n## Mock Implementation Rules\n\n1. Mock implementations should be placed in `beforeEach` blocks\n2. Each mock implementation should return a Promise for async functions\n3. Mock implementations should match the expected return type of the original function\n4. Use `vi.mocked()` to access and implement mock behaviors\n5. Mock all required properties and methods that the test subject uses\n\n## Avoided Patterns\n\nThe following mocking patterns should be avoided:\n\n1. Direct function mocking without `vi.mocked()`\n2. Mock implementations outside of `beforeEach` blocks\n3. Mocking without the `spy: true` option\n4. Inline mock implementations within test cases\n5. Mocking only a subset of required dependencies\n\n## Best Practices\n\n1. Mock at the highest level of abstraction needed\n2. Keep mock implementations simple and focused\n3. Use type-safe mocking with `vi.mocked()`\n4. Document complex mock behaviors\n5. Group related mocks together\n"
  },
  {
    "path": ".cursorrules",
    "content": "## Test Configuration\n\nThis Storybook repository uses Vitest as the test runner. Here are the key commands and configuration:\n\n### Test Scripts\n\n- `yarn test` - Run all tests (from root directory, delegates to `cd code; yarn test`)\n- `yarn test <test-name>` - Run focused tests matching the pattern\n- `yarn test:watch` - Run tests in watch mode\n- `yarn test:watch <test-name>` - Run focused tests in watch mode\n\n### Test Directory Structure\n\n- Tests are located in the `code/` directory\n- Vitest configuration is in `code/vitest.workspace.ts`\n- Test files typically follow the pattern `*.test.ts`, `*.test.tsx`, `*.spec.ts`, or `*.spec.tsx`\n\n### Running Tests in Cursor\n\n1. Use Cmd+Shift+P (or Ctrl+Shift+P) and search for \"Tasks: Run Task\"\n2. Select from the available test tasks:\n   - \"Run All Tests\" - Runs all tests\n   - \"Run Test (Watch Mode)\" - Runs tests in watch mode\n   - \"Run Focused Test\" - Prompts for test name/pattern to run specific tests\n   - \"Run Focused Test (Watch Mode)\" - Runs specific tests in watch mode\n\n### Vitest Configuration\n\n- Workspace configuration: `./code/vitest.workspace.ts`\n- Command line: `yarn --cwd code test`\n- Root directory for tests: `./code/`\n\n### Test Execution Context\n\n- Tests run from the `code/` directory\n- Use `NODE_OPTIONS=--max_old_space_size=4096` for memory optimization\n- Supports both watch mode and single-run execution\n\n### Focused Test Patterns\n\nWhen running focused tests, you can use:\n\n- File names: `Button.test.ts`\n- Test descriptions: `\"should render correctly\"`\n- Directory patterns: `components/`\n- Vitest patterns: `-t \"pattern\"` for test name matching\n\n### Test Mocking Rules\n\nFollow the spy mocking rules defined in `.cursor/rules/spy-mocking.mdc` for consistent mocking patterns with Vitest.\n"
  },
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\nend_of_line = lf\n\n[*.{js,json,ts,vue,svelte,html}]\nindent_style = space\nindent_size = 2\n\n[*.{yml,yaml}]\nquote_type = single\n"
  },
  {
    "path": ".git-blame-ignore-revs",
    "content": "34e364a0ca1d93555d36a7367d78e8e229493de8\nc0896915fb7fb9a8dd416b9aebca17abd909d1c1\na41c227037e7e7249b8b376f838f4f8bcc3e3e59\n13c46e6c0b7f3dd8cf4ba42d1cfd6714f4777d54\n0a4522a3f84773f39daec4820c49b8a92e9f9d11\ne12039c0593ba021ce27cb7245b6067677f27625\n513bb66bb9729ece57581b6eb50e5b338c47c0b9"
  },
  {
    "path": ".gitattributes",
    "content": "/**/.yarn/** linguist-generated\n* -text\n\n.github/workflows/*.lock.yml linguist-generated=true merge=ours"
  },
  {
    "path": ".github/DISCUSSION_TEMPLATE/help.yml",
    "content": "body:\n- type: markdown\n  id: intro\n  attributes:\n    value: |\n      Thanks for taking the time to start a new discussion!\n      \n      ### Before you post\n      Check if someone has already asked/answered your question in a previous discussion.\n      \n      ### When you're ready to post\n      Add labels to your discussion (e.g. React, Vue, Vite) to make it clearer for other users.\n\n- type: textarea\n  id: summary\n  attributes:\n    label: Summary\n    description: How can we help?\n  validations:\n    required: true\n      \n- type: textarea\n  id: additional-info\n  attributes:\n    label: Additional information\n    description: |\n      Share Your Storybook configuration (`main.js` or `main.ts`), your Storybook version number, any error messages, and any relevant dependencies. These help us get a clearer understanding of what might be going wrong.\n\n      P.S. Please [share code as text](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks) rather than as a screenshot! It makes debugging much easier and faster.\n  validations:\n    required: false\n      \n- type: input\n  id: reproduction\n  attributes:\n    label: Create a reproduction\n    description: |\n      Help us debug by creating a minimal reproduction with [https://storybook.new](https://storybook.new). Learn more about creating a reproduction [here](https://storybook.js.org/docs/react/contribute/how-to-reproduce).\n  validations:\n    required: false\n"
  },
  {
    "path": ".github/DISCUSSION_TEMPLATE/ideas.yml",
    "content": "labels:\n  - needs triage\n  - feature request\nbody:\n  - type: textarea\n    id: problem\n    attributes:\n      label: Is your feature request related to a problem? Please describe.\n      description: >-\n        A clear and concise description of the problem. E.g. I'm always\n        frustrated when [...]\n  - type: textarea\n    id: describe\n    attributes:\n      label: Describe the solution you'd like\n      description: What would you like to see added to Storybook to solve problem?\n    validations:\n      required: true\n  - type: textarea\n    id: alternatives\n    attributes:\n      label: Describe alternatives you've considered\n      description: Any alternative solutions or features you've considered.\n  - type: dropdown\n    id: help\n    attributes:\n      label: Are you able to assist to bring the feature to reality?\n      options:\n        - 'no'\n        - yes, I can\n    validations:\n      required: true\n  - type: textarea\n    id: context\n    attributes:\n      label: Additional context\n      description: Add any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/DISCUSSION_TEMPLATE/rfc.yml",
    "content": "title: '[RFC] '\nlabels: ['RFC']\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        # Request For Comments\n        Welcome! 👋\n\n        If you are interested in proposing a new feature or improvement to Storybook, then you are in the right place! \n        This template is designed to help users and contributors propose a solution to a problem, receive feedback, and finally gain alignment.\n        Thank you for taking the time to improve Storybook.\n  - type: textarea\n    id: summary\n    attributes:\n      label: Summary\n      description: |\n        A brief, 1-5 sentences explanation of the RFC.\n    validations:\n      required: true\n  - type: markdown\n    attributes:\n      value: |\n        ## The Problem\n  - type: textarea\n    id: problem-statement\n    attributes:\n      label: Problem Statement\n      description: |\n        A few sentences or bullets summarizing the problem we are trying to solve. Non-core members should be able to read this and understand why we are doing this.\n      placeholder: |\n        Doing X is hard because combining Y and Z makes Storybook go 💥...\n    validations:\n      required: true\n  - type: textarea\n    id: non-goals\n    attributes:\n      label: Non-goals\n      description: |\n        Key bullets explicitly outlining what is not in-scope.\n      placeholder: |\n        Making Y work with W is not part of this proposal because...\n  - type: markdown\n    attributes:\n      value: |\n        ## 🚀 Proposed Solution\n        Here is where you can get technical!\n        The goal of this section is to outline the technical changes necessary for the proposed solution.\n        In most cases, the content of this section will evolve as discussions take place.\n  - type: textarea\n    id: implementation\n    attributes:\n      label: Implementation\n      description: |\n        What are the high level technical (architecture, data structure, UI, etc) changes? Diagrams can be very helpful here.\n      placeholder: |\n        I propose a new API for integrating Y with Z to achieve X. The API will be...\n    validations:\n      required: true\n  - type: textarea\n    id: prior-art\n    attributes:\n      label: Prior Art\n      description: |\n        Has this been done before, maybe in the broader ecosystem?\n      placeholder: |\n        Project A has done something similar for a long time, and the B addon supports this by...\n  - type: textarea\n    id: deliverables\n    attributes:\n      label: Deliverables\n      description: |\n        List out the high-level deliverables that make up this body of work.\n        Each deliverable should be small enough to be reliably estimable but large enough to represent a meaningful delivery, usually one cycle (2 weeks) worth of work.\n      placeholder: |\n        1. Restructure Y to support incoming Z\n        2. Integrate Z into Y\n        3. Build V on top of Y and Z\n  - type: textarea\n    id: risks\n    attributes:\n      label: Risks\n      description: |\n        What risks might be introduced by this set of changes? How can we mitigate these risks?\n      placeholder: |\n        - This will make it harder to use X in this scenario because...\n  - type: textarea\n    id: unresolved-questions\n    attributes:\n      label: Unresolved Questions\n      description: |\n        Questions we hope to answer as part of this proposal review process.\n      value: |\n        - [ ] Using a to do list makes it easy to resolve the questions as we move the RFC along.\n  - type: textarea\n    id: alternatives\n    attributes:\n      label: Alternatives considered / Abandoned Ideas\n      description: |\n        Describe alternative approaches that have been considered and why they have been dropped.\n\n        As we discuss this project, it is common for some ideas to be abandoned. Instead of deleting them, let's document the rationale. This way, when people review this proposal in the future, they can avoid the same thinking path and pitfalls we have already learned from.\n      placeholder: |\n        I've considered combining U and I, but that is a worse solution because...\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "open_collective: storybook\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "content": "name: Bug report 🐞\ndescription: >-\n  Something is broken and you have a reliable reproduction? Let us know here.\n  For questions, please post in GitHub Discussion.\ntitle: '[Bug]: '\nlabels:\n  - needs triage\n  - bug\nbody:\n  - type: textarea\n    id: description\n    attributes:\n      label: Describe the bug\n      description: A clear and concise description of what the bug is\n    validations:\n      required: true\n  - type: input\n    id: repro-link\n    attributes:\n      label: Reproduction link\n      description: >-\n        Please provide a link to a reproduction of the issue. We accept reproductions hosted on GitHub, CodeSandbox, and StackBlitz. Due to the high volume of reports, we prioritize those with clear reproductions. The easiest way to create a reproduction is to use [storybook.new](https://storybook.new). For detailed guidance, please refer to our [documentation](https://storybook.js.org/docs/react/contribute/how-to-reproduce).\n\n        Important: If the provided URL is invalid (e.g., 404 error or private repository), we may close the issue. Thank you for your understanding!\n    validations:\n      required: true\n  - type: textarea\n    id: repro-steps\n    attributes:\n      label: Reproduction steps\n      description: >-\n        Include the steps to reproduce the issue using the provided link. Additionally, provide a clear and concise description of what you expected to happen.\n      placeholder: >-\n        1. Go to above link\n        2. Click on '....'\n        3. ...\n  - type: textarea\n    id: system\n    attributes:\n      label: System\n      description: Please paste the results of `npx storybook@latest info` here.\n      render: bash\n    validations:\n      required: true\n  - type: textarea\n    id: context\n    attributes:\n      label: Additional context\n      description: Add any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: View documentation 📚\n    url: https://storybook.js.org/docs/\n    about: Check out the official docs for answers to common questions.\n  - name: Feature requests 💡\n    url: https://github.com/storybookjs/storybook/discussions/new?category=ideas\n    about: Suggest a feature idea for this project.\n  - name: Open an RFC 🦄\n    url: https://github.com/storybookjs/storybook/discussions/new?category=rfc\n    about: Do you want to propose a more involved change to Storybook? Open an RFC (Request for Comments) to start a discussion.\n  - name: Questions 💭\n    url: https://github.com/storybookjs/storybook/discussions/new?category=help\n    about: Need support with a Storybook problem? Open up a help request.\n  - name: Discussions 🙌\n    url: https://github.com/storybookjs/storybook/discussions\n    about: Show off your Storybook or discuss the project.\n  - name: Community Discord 🎉\n    url: https://discord.gg/storybook\n    about: Meet other community members and get contributor help.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/tracking_issue.yml",
    "content": "name: Tracking Issue\ndescription: For tracking a large body of work. For internal use only.\ntitle: '[Tracking]: '\ntype: 'Tracking'\nbody:\n  - type: textarea\n    attributes:\n      label: Problem statement \n      description: A brief description of the problem we're trying to solve.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Milestones\n      description: |\n        A good milestone is a unit of work that is *shippable and usable*. This should be done in two weeks.\n        Milestone definitions should have:\n          * a clear goal (the title of the milestone)\n          * a specific person responsible for seeing through the milestone (the owner)\n          * the target completion date (complete by)\n          * a list of tasks to get the *one piece done*\n      value: |\n        ### M1: milestone 1\n        **Owner: `@mention`**\n        **Complete by: `@date`**\n        - [ ] task1\n        - [ ] task2\n        \n        ### M2: milestone 2\n        **Owner: `@mention`**\n        **Complete by: `@date`**\n        - [ ] task1\n        - [ ] task2\n        \n        ### Milestone n: be sure to always scope these in\n        **Owner: `@mention`**\n        **Complete by: `@date`**\n        - [ ]  Metric collection\n        - [ ]  Documentation\n        - [ ]  Blog posts\n        \n        **========= Everything below this line is strictly nice-to-have =========**\n        \n        ### Related issues that may be resolved by this project\n        - [ ] issue1\n        - [ ] issue2\n\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/update_docs.yml",
    "content": "name: Update docs ✍️\ndescription: >-\n  Find a mistake in our documentation, or have a suggestion to improve them? Let us know here.\ntitle: '[Documentation]: '\nlabels:\n  - needs triage\n  - documentation\nbody:\n  - type: textarea\n    id: description\n    attributes:\n      label: Describe the problem\n      description: A clear and concise description of what is wrong in the documentation or what you would like to improve. Please include URLs to the pages you're referring to.\n    validations:\n      required: true\n  - type: textarea\n    id: context\n    attributes:\n      label: Additional context\n      description: Add any other context about the problem here.\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "Closes #\n\n<!-- If your PR is related to an issue, provide the number(s) above; if it resolves multiple issues, be sure to break them up (e.g. \"closes #1000, closes #1001\"). -->\n\n<!--\n\nThank you for contributing to Storybook! Please submit all PRs to the `next` branch unless they are specific to the current release. Storybook maintainers cherry-pick bug and documentation fixes into the `main` branch as part of the release process, so you shouldn't need to worry about this. For additional guidance: https://storybook.js.org/docs/contribute\n\n-->\n\n## What I did\n\n<!-- Briefly describe what your PR does -->\n\n## Checklist for Contributors\n\n### Testing\n\n<!-- Please check (put an \"x\" inside the \"[ ]\") the applicable items below to communicate how to test your changes -->\n\n#### The changes in this PR are covered in the following automated tests:\n\n- [ ] stories\n- [ ] unit tests\n- [ ] integration tests\n- [ ] end-to-end tests\n\n#### Manual testing\n\n> [!CAUTION]\n> This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!\n\n<!-- Please include the steps to test your changes here. For example:\n\n1. Run a sandbox for template, e.g. `yarn task --task sandbox --start-from auto --template react-vite/default-ts`\n2. Open Storybook in your browser\n3. Access X story\n\n-->\n\n### Documentation\n\n<!-- Please check (put an \"x\" inside the \"[ ]\") the applicable items below to indicate which documentation has been updated. -->\n\n- [ ] Add or update documentation reflecting your changes\n- [ ] If you are deprecating/removing a feature, make sure to update\n      [MIGRATION.MD](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md)\n\n## Checklist for Maintainers\n\n- [ ] When this PR is ready for testing, make sure to add `ci:normal`, `ci:merged` or `ci:daily` GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in `code/lib/cli-storybook/src/sandbox-templates.ts`\n- [ ] Make sure this PR contains **one** of the labels below:\n   <details>\n     <summary>Available labels</summary>\n\n  - `bug`: Internal changes that fixes incorrect behavior.\n  - `maintenance`: User-facing maintenance tasks.\n  - `dependencies`: Upgrading (sometimes downgrading) dependencies.\n  - `build`: Internal-facing build tooling & test updates. Will not show up in release changelog.\n  - `cleanup`: Minor cleanup style change. Will not show up in release changelog.\n  - `documentation`: Documentation **only** changes. Will not show up in release changelog.\n  - `feature request`: Introducing a new feature.\n  - `BREAKING CHANGE`: Changes that break compatibility in some way with current major version.\n  - `other`: Changes that don't fit in the above categories.\n\n   </details>\n\n### 🦋 Canary release\n\n<!-- CANARY_RELEASE_SECTION -->\n\nThis PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the `@storybookjs/core` team here.\n\n_core team members can create a canary release [here](https://github.com/storybookjs/storybook/actions/workflows/publish.yml) or locally with `gh workflow run --repo storybookjs/storybook publish.yml --field pr=<PR_NUMBER>`_\n\n<!-- CANARY_RELEASE_SECTION -->\n\n<!-- BENCHMARK_SECTION -->\n<!-- BENCHMARK_SECTION -->\n"
  },
  {
    "path": ".github/actions/setup-node-and-install/action.yml",
    "content": "name: 'Setup Node.js and Install Dependencies'\ndescription: 'Sets up Node.js, caches dependencies, and installs packages for Storybook'\n\ninputs:\n  install-code-deps:\n    description: 'Whether to install code dependencies in addition to script dependencies'\n    required: false\n    default: 'false'\n\nruns:\n  using: 'composite'\n  steps:\n    - name: Setup Node.js\n      uses: actions/setup-node@v4\n      with:\n        node-version-file: '.nvmrc'\n\n    - name: Update npm to latest\n      shell: bash\n      run: npm install -g npm@latest\n\n    - name: Cache dependencies\n      uses: actions/cache@v4\n      with:\n        path: |\n          ~/.yarn/berry/cache\n        key: yarn-v1-${{ hashFiles('yarn.lock') }}\n        restore-keys: |\n          yarn-v1-${{ hashFiles('yarn.lock') }}\n          yarn-v1\n\n    - name: Install script dependencies\n      shell: bash\n      working-directory: scripts\n      run: yarn install\n\n    - name: Install code dependencies\n      if: inputs.install-code-deps == 'true'\n      shell: bash\n      working-directory: code\n      run: yarn install\n"
  },
  {
    "path": ".github/comments/good-first-issue.md",
    "content": "The issue was marked with the `good first issue` label by a maintainer.\n\nThis means that it is a good candidate for someone interested in contributing to the project, but does not know where to start.\n\nTo get started, read the [Contributing Guide](https://storybook.js.org/docs/contribute/how-to-contribute). When you are ready, open a PR and link back to this issue in the form of adding `Fixes #1234` to the PR description, where `1234` is the issue number. This will automatically close the issue when the PR gets merged, making it easier for us to keep track of what has been fixed.\n\nPlease remember to add tests to confirm your code changes will fix the issue and we do not regress in the future.\n\nIf you have any questions, feel free to ask below or hop onto the [Storybook Discord](https://discord.gg/storybook) and ask in the #contributing channel. We're looking forward to your contribution! ✨\n\n> [!NOTE]\n> There is no need to ask to be assigned or for permission (e.g. \"can I work on this?\"). Please, go ahead if there is no linked PR. :slightly_smiling_face:\n"
  },
  {
    "path": ".github/comments/invalid-link.md",
    "content": "We could not detect a valid reproduction link. **Make sure to follow the bug report template carefully.**\n\n### Why was this issue closed?\n\nTo be able to investigate, we need access to a reproduction to identify what triggered the issue. We need a link to a **public** GitHub repository, Stackblitz or CodeSandbox. The easiest way to create a reproduction is with [storybook.new](https://storybook.new).\n\nThe bug template that you filled out has a section called \"To reproduce\", which is where you should provide the link to the reproduction.\n\n- If you did not provide a link or the link you provided is not valid, we will close the issue.\n- If you provide a link to a private repository, we will close the issue.\n- If you provide a link to a repository but not in the correct section, we will close the issue.\n\n### What should I do?\n\nDepending on the reason the issue was closed, you can do the following:\n\n- If you did not provide a link, please open a new issue with a link to a reproduction.\n- If you provided a link to a private repository, please open a new issue with a link to a public repository.\n- If you provided a link to a repository but not in the correct section, please open a new issue with a link to a reproduction in the correct section.\n\n**In general, assume that we should not go through a lengthy onboarding process at your company code only to be able to verify an issue.**\n\n### My repository is private and cannot be public\n\nIn most cases, a private repo will not be a sufficient **minimal reproduction**, as this codebase might contain a lot of unrelated parts that would make our investigation take longer. Please do **not** make it public. Instead, create a new repository using the templates above, adding the relevant code to reproduce the issue. Common things to look out for:\n\n- Remove any code that is not related to the issue. (pages, API routes, irrelevant components, etc.)\n- Remove any dependencies that are not related to the issue.\n- Remove any third-party service that would require us to sign up for an account to reproduce the issue.\n- Remove any environment variables that are not related to the issue.\n- Remove private packages that we do not have access to.\n- If the issue is not related to a monorepo specifically, try to reproduce the issue without a complex monorepo setup\n\n### I did not open this issue, but it is relevant to me, what can I do to help?\n\nAnyone experiencing the same issue is welcome to provide a minimal reproduction following the above steps by opening a new issue.\n\n### I think my reproduction is good enough, why aren't you looking into it quickly?\n\nWe look into every Storybook issue and constantly monitor open issues for new comments.\n\nHowever, sometimes we might miss one or two due to the popularity/high traffic of the repository. We apologize, and kindly ask you to refrain from tagging core maintainers, as that will usually not result in increased priority.\n\nUpvoting issues to show your interest will help us prioritize and address them as quickly as possible. That said, every issue is important to us, and if an issue gets closed by accident, we encourage you to open a new one linking to the old issue and we will look into it.\n\n### Useful Resources\n\n- [Create a Storybook reproduction](https://storybook.js.org/docs/react/contribute/how-to-reproduce)\n- [How to create a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve)\n- [Contributing to Storybook](https://storybook.js.org/docs/contribute/how-to-contribute)\n"
  },
  {
    "path": ".github/copilot-mcp.json",
    "content": "{\n  \"mcpServers\": {\n    \"nx\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"nx-mcp@latest\"]\n    }\n  }\n}\n"
  },
  {
    "path": ".github/workflows/code-simplifier.lock.yml",
    "content": "#\n#    ___                   _   _      \n#   / _ \\                 | | (_)     \n#  | |_| | __ _  ___ _ __ | |_ _  ___ \n#  |  _  |/ _` |/ _ \\ '_ \\| __| |/ __|\n#  | | | | (_| |  __/ | | | |_| | (__ \n#  \\_| |_/\\__, |\\___|_| |_|\\__|_|\\___|\n#          __/ |\n#  _    _ |___/ \n# | |  | |                / _| |\n# | |  | | ___ _ __ _  __| |_| | _____      ____\n# | |/\\| |/ _ \\ '__| |/ /|  _| |/ _ \\ \\ /\\ / / ___|\n# \\  /\\  / (_) | | | | ( | | | | (_) \\ V  V /\\__ \\\n#  \\/  \\/ \\___/|_| |_|\\_\\|_| |_|\\___/ \\_/\\_/ |___/\n#\n# This file was automatically generated by gh-aw (v0.55.0). DO NOT EDIT.\n#\n# To update this file, edit github/gh-aw/.github/workflows/code-simplifier.md@852cb06ad52958b402ed982b69957ffc57ca0619 and run:\n#   gh aw compile\n# Not all edits will cause changes to this file.\n#\n# For more information: https://github.github.com/gh-aw/introduction/overview/\n#\n# Analyzes recently modified code and creates pull requests with simplifications that improve clarity, consistency, and maintainability while preserving functionality\n#\n# Source: github/gh-aw/.github/workflows/code-simplifier.md@852cb06ad52958b402ed982b69957ffc57ca0619\n#\n# Resolved workflow manifest:\n#   Imports:\n#     - shared/mood.md\n#     - shared/reporting.md\n#\n# gh-aw-metadata: {\"schema_version\":\"v2\",\"frontmatter_hash\":\"dbddcd7da0eefb6c24a3380b4e555d7aacd3ba78c14d79ebc131c33cb86f02ea\",\"compiler_version\":\"v0.55.0\",\"strict\":true}\n\nname: \"Code Simplifier\"\n\"on\":\n  schedule:\n  - cron: \"6 12 * * *\"\n    # Friendly format: daily (scattered)\n  # skip-if-match: is:pr is:open in:title \"[code-simplifier]\" # Skip-if-match processed as search check in pre-activation job\n  workflow_dispatch:\n\npermissions: {}\n\nconcurrency:\n  group: \"gh-aw-${{ github.workflow }}\"\n\nrun-name: \"Code Simplifier\"\n\njobs:\n  activation:\n    needs: pre_activation\n    if: needs.pre_activation.outputs.activated == 'true'\n    runs-on: ubuntu-slim\n    permissions:\n      contents: read\n    outputs:\n      comment_id: \"\"\n      comment_repo: \"\"\n      model: ${{ steps.generate_aw_info.outputs.model }}\n      secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }}\n    steps:\n      - name: Setup Scripts\n        uses: github/gh-aw/actions/setup@e211c855a20aa6cf9297b411466e1c382a8686db # v0.55.0\n        with:\n          destination: /opt/gh-aw/actions\n      - name: Generate agentic run info\n        id: generate_aw_info\n        env:\n          GH_AW_INFO_ENGINE_ID: \"copilot\"\n          GH_AW_INFO_ENGINE_NAME: \"GitHub Copilot CLI\"\n          GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }}\n          GH_AW_INFO_VERSION: \"\"\n          GH_AW_INFO_AGENT_VERSION: \"latest\"\n          GH_AW_INFO_CLI_VERSION: \"v0.55.0\"\n          GH_AW_INFO_WORKFLOW_NAME: \"Code Simplifier\"\n          GH_AW_INFO_EXPERIMENTAL: \"false\"\n          GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: \"true\"\n          GH_AW_INFO_STAGED: \"false\"\n          GH_AW_INFO_ALLOWED_DOMAINS: '[\"defaults\"]'\n          GH_AW_INFO_FIREWALL_ENABLED: \"true\"\n          GH_AW_INFO_AWF_VERSION: \"v0.23.0\"\n          GH_AW_INFO_AWMG_VERSION: \"\"\n          GH_AW_INFO_FIREWALL_TYPE: \"squid\"\n          GH_AW_COMPILED_STRICT: \"true\"\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        with:\n          script: |\n            const { main } = require('/opt/gh-aw/actions/generate_aw_info.cjs');\n            await main(core, context);\n      - name: Validate COPILOT_GITHUB_TOKEN secret\n        id: validate-secret\n        run: /opt/gh-aw/actions/validate_multi_secret.sh COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default\n        env:\n          COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}\n      - name: Checkout .github and .agents folders\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          sparse-checkout: |\n            .github\n            .agents\n          sparse-checkout-cone-mode: true\n          fetch-depth: 1\n          persist-credentials: false\n      - name: Check workflow file timestamps\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_WORKFLOW_FILE: \"code-simplifier.lock.yml\"\n        with:\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/check_workflow_timestamp_api.cjs');\n            await main();\n      - name: Create prompt with built-in context\n        env:\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n          GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}\n          GH_AW_GITHUB_ACTOR: ${{ github.actor }}\n          GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }}\n          GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }}\n          GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}\n          GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}\n          GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}\n          GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}\n          GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}\n        run: |\n          bash /opt/gh-aw/actions/create_prompt_first.sh\n          {\n          cat << 'GH_AW_PROMPT_EOF'\n          <system>\n          GH_AW_PROMPT_EOF\n          cat \"/opt/gh-aw/prompts/xpia.md\"\n          cat \"/opt/gh-aw/prompts/temp_folder_prompt.md\"\n          cat \"/opt/gh-aw/prompts/markdown.md\"\n          cat \"/opt/gh-aw/prompts/safe_outputs_prompt.md\"\n          cat << 'GH_AW_PROMPT_EOF'\n          <safe-output-tools>\n          Tools: create_pull_request, missing_tool, missing_data, noop\n          GH_AW_PROMPT_EOF\n          cat \"/opt/gh-aw/prompts/safe_outputs_create_pull_request.md\"\n          cat << 'GH_AW_PROMPT_EOF'\n          </safe-output-tools>\n          <github-context>\n          The following GitHub context information is available for this workflow:\n          {{#if __GH_AW_GITHUB_ACTOR__ }}\n          - **actor**: __GH_AW_GITHUB_ACTOR__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_REPOSITORY__ }}\n          - **repository**: __GH_AW_GITHUB_REPOSITORY__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_WORKSPACE__ }}\n          - **workspace**: __GH_AW_GITHUB_WORKSPACE__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }}\n          - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }}\n          - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }}\n          - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }}\n          - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_RUN_ID__ }}\n          - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__\n          {{/if}}\n          </github-context>\n          \n          GH_AW_PROMPT_EOF\n          cat << 'GH_AW_PROMPT_EOF'\n          </system>\n          GH_AW_PROMPT_EOF\n          cat << 'GH_AW_PROMPT_EOF'\n          {{#runtime-import .github/workflows/shared/mood.md}}\n          GH_AW_PROMPT_EOF\n          cat << 'GH_AW_PROMPT_EOF'\n          {{#runtime-import .github/workflows/shared/reporting.md}}\n          GH_AW_PROMPT_EOF\n          cat << 'GH_AW_PROMPT_EOF'\n          {{#runtime-import .github/workflows/code-simplifier.md}}\n          GH_AW_PROMPT_EOF\n          } > \"$GH_AW_PROMPT\"\n      - name: Interpolate variables and render templates\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n          GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}\n          GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}\n        with:\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/interpolate_prompt.cjs');\n            await main();\n      - name: Substitute placeholders\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n          GH_AW_GITHUB_ACTOR: ${{ github.actor }}\n          GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }}\n          GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }}\n          GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}\n          GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}\n          GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}\n          GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}\n          GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}\n          GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }}\n        with:\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            \n            const substitutePlaceholders = require('/opt/gh-aw/actions/substitute_placeholders.cjs');\n            \n            // Call the substitution function\n            return await substitutePlaceholders({\n              file: process.env.GH_AW_PROMPT,\n              substitutions: {\n                GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR,\n                GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID,\n                GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER,\n                GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER,\n                GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER,\n                GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY,\n                GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID,\n                GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE,\n                GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED\n              }\n            });\n      - name: Validate prompt placeholders\n        env:\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n        run: bash /opt/gh-aw/actions/validate_prompt_placeholders.sh\n      - name: Print prompt\n        env:\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n        run: bash /opt/gh-aw/actions/print_prompt_summary.sh\n      - name: Upload activation artifact\n        if: success()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7\n        with:\n          name: activation\n          path: |\n            /tmp/gh-aw/aw_info.json\n            /tmp/gh-aw/aw-prompts/prompt.txt\n          retention-days: 1\n\n  agent:\n    needs: activation\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n      issues: read\n      pull-requests: read\n    concurrency:\n      group: \"gh-aw-copilot-${{ github.workflow }}\"\n    env:\n      DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}\n      GH_AW_ASSETS_ALLOWED_EXTS: \"\"\n      GH_AW_ASSETS_BRANCH: \"\"\n      GH_AW_ASSETS_MAX_SIZE_KB: 0\n      GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs\n      GH_AW_SAFE_OUTPUTS: /opt/gh-aw/safeoutputs/outputs.jsonl\n      GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json\n      GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json\n      GH_AW_WORKFLOW_ID_SANITIZED: codesimplifier\n    outputs:\n      checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}\n      detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }}\n      detection_success: ${{ steps.detection_conclusion.outputs.success }}\n      has_patch: ${{ steps.collect_output.outputs.has_patch }}\n      inference_access_error: ${{ steps.detect-inference-error.outputs.inference_access_error || 'false' }}\n      model: ${{ needs.activation.outputs.model }}\n      output: ${{ steps.collect_output.outputs.output }}\n      output_types: ${{ steps.collect_output.outputs.output_types }}\n    steps:\n      - name: Setup Scripts\n        uses: github/gh-aw/actions/setup@e211c855a20aa6cf9297b411466e1c382a8686db # v0.55.0\n        with:\n          destination: /opt/gh-aw/actions\n      - name: Checkout repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n      - name: Create gh-aw temp directory\n        run: bash /opt/gh-aw/actions/create_gh_aw_tmp_dir.sh\n      - name: Configure Git credentials\n        env:\n          REPO_NAME: ${{ github.repository }}\n          SERVER_URL: ${{ github.server_url }}\n        run: |\n          git config --global user.email \"github-actions[bot]@users.noreply.github.com\"\n          git config --global user.name \"github-actions[bot]\"\n          git config --global am.keepcr true\n          # Re-authenticate git with GitHub token\n          SERVER_URL_STRIPPED=\"${SERVER_URL#https://}\"\n          git remote set-url origin \"https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git\"\n          echo \"Git configured with standard GitHub Actions identity\"\n      - name: Checkout PR branch\n        id: checkout-pr\n        if: |\n          (github.event.pull_request) || (github.event.issue.pull_request)\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n        with:\n          github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/checkout_pr_branch.cjs');\n            await main();\n      - name: Install GitHub Copilot CLI\n        run: /opt/gh-aw/actions/install_copilot_cli.sh latest\n      - name: Install awf binary\n        run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.23.0\n      - name: Determine automatic lockdown mode for GitHub MCP Server\n        id: determine-automatic-lockdown\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}\n          GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}\n        with:\n          script: |\n            const determineAutomaticLockdown = require('/opt/gh-aw/actions/determine_automatic_lockdown.cjs');\n            await determineAutomaticLockdown(github, context, core);\n      - name: Download container images\n        run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.8 ghcr.io/github/github-mcp-server:v0.31.0 node:lts-alpine\n      - name: Write Safe Outputs Config\n        run: |\n          mkdir -p /opt/gh-aw/safeoutputs\n          mkdir -p /tmp/gh-aw/safeoutputs\n          mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs\n          cat > /opt/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF'\n          {\"create_pull_request\":{\"expires\":24,\"max\":1,\"reviewers\":[\"copilot\"],\"title_prefix\":\"[code-simplifier] \"},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1}}\n          GH_AW_SAFE_OUTPUTS_CONFIG_EOF\n          cat > /opt/gh-aw/safeoutputs/tools.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_EOF'\n          [\n            {\n              \"description\": \"Create a new GitHub pull request to propose code changes. Use this after making file edits to submit them for review and merging. The PR will be created from the current branch with your committed changes. For code review comments on an existing PR, use create_pull_request_review_comment instead. CONSTRAINTS: Maximum 1 pull request(s) can be created. Title will be prefixed with \\\"[code-simplifier] \\\". Labels [\\\"refactoring\\\" \\\"code-quality\\\" \\\"automation\\\"] will be automatically added. Reviewers [\\\"copilot\\\"] will be assigned.\",\n              \"inputSchema\": {\n                \"additionalProperties\": false,\n                \"properties\": {\n                  \"body\": {\n                    \"description\": \"Detailed PR description in Markdown. Include what changes were made, why, testing notes, and any breaking changes. Do NOT repeat the title as a heading.\",\n                    \"type\": \"string\"\n                  },\n                  \"branch\": {\n                    \"description\": \"Source branch name containing the changes. If omitted, uses the current working branch.\",\n                    \"type\": \"string\"\n                  },\n                  \"draft\": {\n                    \"description\": \"Whether to create the PR as a draft. Draft PRs cannot be merged until marked as ready for review. Use mark_pull_request_as_ready_for_review to convert a draft PR. Default: true.\",\n                    \"type\": \"boolean\"\n                  },\n                  \"integrity\": {\n                    \"description\": \"Trustworthiness level of the message source (e.g., \\\"low\\\", \\\"medium\\\", \\\"high\\\").\",\n                    \"type\": \"string\"\n                  },\n                  \"labels\": {\n                    \"description\": \"Labels to categorize the PR (e.g., 'enhancement', 'bugfix'). Labels must exist in the repository.\",\n                    \"items\": {\n                      \"type\": \"string\"\n                    },\n                    \"type\": \"array\"\n                  },\n                  \"repo\": {\n                    \"description\": \"Target repository in 'owner/repo' format. For multi-repo workflows where the target repo differs from the workflow repo, this must match a repo in the allowed-repos list or the configured target-repo. If omitted, defaults to the configured target-repo (from safe-outputs config), NOT the workflow repository. In most cases, you should omit this parameter and let the system use the configured default.\",\n                    \"type\": \"string\"\n                  },\n                  \"secrecy\": {\n                    \"description\": \"Confidentiality level of the message content (e.g., \\\"public\\\", \\\"internal\\\", \\\"private\\\").\",\n                    \"type\": \"string\"\n                  },\n                  \"title\": {\n                    \"description\": \"Concise PR title describing the changes. Follow repository conventions (e.g., conventional commits). The title appears as the main heading.\",\n                    \"type\": \"string\"\n                  }\n                },\n                \"required\": [\n                  \"title\",\n                  \"body\"\n                ],\n                \"type\": \"object\"\n              },\n              \"name\": \"create_pull_request\"\n            },\n            {\n              \"description\": \"Report that a tool or capability needed to complete the task is not available, or share any information you deem important about missing functionality or limitations. Use this when you cannot accomplish what was requested because the required functionality is missing or access is restricted.\",\n              \"inputSchema\": {\n                \"additionalProperties\": false,\n                \"properties\": {\n                  \"alternatives\": {\n                    \"description\": \"Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).\",\n                    \"type\": \"string\"\n                  },\n                  \"integrity\": {\n                    \"description\": \"Trustworthiness level of the message source (e.g., \\\"low\\\", \\\"medium\\\", \\\"high\\\").\",\n                    \"type\": \"string\"\n                  },\n                  \"reason\": {\n                    \"description\": \"Explanation of why this tool is needed or what information you want to share about the limitation (max 256 characters).\",\n                    \"type\": \"string\"\n                  },\n                  \"secrecy\": {\n                    \"description\": \"Confidentiality level of the message content (e.g., \\\"public\\\", \\\"internal\\\", \\\"private\\\").\",\n                    \"type\": \"string\"\n                  },\n                  \"tool\": {\n                    \"description\": \"Optional: Name or description of the missing tool or capability (max 128 characters). Be specific about what functionality is needed.\",\n                    \"type\": \"string\"\n                  }\n                },\n                \"required\": [\n                  \"reason\"\n                ],\n                \"type\": \"object\"\n              },\n              \"name\": \"missing_tool\"\n            },\n            {\n              \"description\": \"Log a transparency message when no significant actions are needed. Use this to confirm workflow completion and provide visibility when analysis is complete but no changes or outputs are required (e.g., 'No issues found', 'All checks passed'). This ensures the workflow produces human-visible output even when no other actions are taken.\",\n              \"inputSchema\": {\n                \"additionalProperties\": false,\n                \"properties\": {\n                  \"integrity\": {\n                    \"description\": \"Trustworthiness level of the message source (e.g., \\\"low\\\", \\\"medium\\\", \\\"high\\\").\",\n                    \"type\": \"string\"\n                  },\n                  \"message\": {\n                    \"description\": \"Status or completion message to log. Should explain what was analyzed and the outcome (e.g., 'Code review complete - no issues found', 'Analysis complete - all tests passing').\",\n                    \"type\": \"string\"\n                  },\n                  \"secrecy\": {\n                    \"description\": \"Confidentiality level of the message content (e.g., \\\"public\\\", \\\"internal\\\", \\\"private\\\").\",\n                    \"type\": \"string\"\n                  }\n                },\n                \"required\": [\n                  \"message\"\n                ],\n                \"type\": \"object\"\n              },\n              \"name\": \"noop\"\n            },\n            {\n              \"description\": \"Report that data or information needed to complete the task is not available. Use this when you cannot accomplish what was requested because required data, context, or information is missing.\",\n              \"inputSchema\": {\n                \"additionalProperties\": false,\n                \"properties\": {\n                  \"alternatives\": {\n                    \"description\": \"Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).\",\n                    \"type\": \"string\"\n                  },\n                  \"context\": {\n                    \"description\": \"Additional context about the missing data or where it should come from (max 256 characters).\",\n                    \"type\": \"string\"\n                  },\n                  \"data_type\": {\n                    \"description\": \"Type or description of the missing data or information (max 128 characters). Be specific about what data is needed.\",\n                    \"type\": \"string\"\n                  },\n                  \"integrity\": {\n                    \"description\": \"Trustworthiness level of the message source (e.g., \\\"low\\\", \\\"medium\\\", \\\"high\\\").\",\n                    \"type\": \"string\"\n                  },\n                  \"reason\": {\n                    \"description\": \"Explanation of why this data is needed to complete the task (max 256 characters).\",\n                    \"type\": \"string\"\n                  },\n                  \"secrecy\": {\n                    \"description\": \"Confidentiality level of the message content (e.g., \\\"public\\\", \\\"internal\\\", \\\"private\\\").\",\n                    \"type\": \"string\"\n                  }\n                },\n                \"required\": [],\n                \"type\": \"object\"\n              },\n              \"name\": \"missing_data\"\n            }\n          ]\n          GH_AW_SAFE_OUTPUTS_TOOLS_EOF\n          cat > /opt/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_EOF'\n          {\n            \"create_pull_request\": {\n              \"defaultMax\": 1,\n              \"fields\": {\n                \"body\": {\n                  \"required\": true,\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 65000\n                },\n                \"branch\": {\n                  \"required\": true,\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 256\n                },\n                \"draft\": {\n                  \"type\": \"boolean\"\n                },\n                \"labels\": {\n                  \"type\": \"array\",\n                  \"itemType\": \"string\",\n                  \"itemSanitize\": true,\n                  \"itemMaxLength\": 128\n                },\n                \"repo\": {\n                  \"type\": \"string\",\n                  \"maxLength\": 256\n                },\n                \"title\": {\n                  \"required\": true,\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 128\n                }\n              }\n            },\n            \"missing_data\": {\n              \"defaultMax\": 20,\n              \"fields\": {\n                \"alternatives\": {\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 256\n                },\n                \"context\": {\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 256\n                },\n                \"data_type\": {\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 128\n                },\n                \"reason\": {\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 256\n                }\n              }\n            },\n            \"missing_tool\": {\n              \"defaultMax\": 20,\n              \"fields\": {\n                \"alternatives\": {\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 512\n                },\n                \"reason\": {\n                  \"required\": true,\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 256\n                },\n                \"tool\": {\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 128\n                }\n              }\n            },\n            \"noop\": {\n              \"defaultMax\": 1,\n              \"fields\": {\n                \"message\": {\n                  \"required\": true,\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 65000\n                }\n              }\n            }\n          }\n          GH_AW_SAFE_OUTPUTS_VALIDATION_EOF\n      - name: Generate Safe Outputs MCP Server Config\n        id: safe-outputs-config\n        run: |\n          # Generate a secure random API key (360 bits of entropy, 40+ chars)\n          # Mask immediately to prevent timing vulnerabilities\n          API_KEY=$(openssl rand -base64 45 | tr -d '/+=')\n          echo \"::add-mask::${API_KEY}\"\n          \n          PORT=3001\n          \n          # Set outputs for next steps\n          {\n            echo \"safe_outputs_api_key=${API_KEY}\"\n            echo \"safe_outputs_port=${PORT}\"\n          } >> \"$GITHUB_OUTPUT\"\n          \n          echo \"Safe Outputs MCP server will run on port ${PORT}\"\n          \n      - name: Start Safe Outputs MCP HTTP Server\n        id: safe-outputs-start\n        env:\n          DEBUG: '*'\n          GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }}\n          GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }}\n          GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json\n          GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json\n          GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs\n        run: |\n          # Environment variables are set above to prevent template injection\n          export DEBUG\n          export GH_AW_SAFE_OUTPUTS_PORT\n          export GH_AW_SAFE_OUTPUTS_API_KEY\n          export GH_AW_SAFE_OUTPUTS_TOOLS_PATH\n          export GH_AW_SAFE_OUTPUTS_CONFIG_PATH\n          export GH_AW_MCP_LOG_DIR\n          \n          bash /opt/gh-aw/actions/start_safe_outputs_server.sh\n          \n      - name: Start MCP Gateway\n        id: start-mcp-gateway\n        env:\n          GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}\n          GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }}\n          GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }}\n          GITHUB_MCP_LOCKDOWN: ${{ steps.determine-automatic-lockdown.outputs.lockdown == 'true' && '1' || '0' }}\n          GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n        run: |\n          set -eo pipefail\n          mkdir -p /tmp/gh-aw/mcp-config\n          \n          # Export gateway environment variables for MCP config and gateway script\n          export MCP_GATEWAY_PORT=\"80\"\n          export MCP_GATEWAY_DOMAIN=\"host.docker.internal\"\n          MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=')\n          echo \"::add-mask::${MCP_GATEWAY_API_KEY}\"\n          export MCP_GATEWAY_API_KEY\n          export MCP_GATEWAY_PAYLOAD_DIR=\"/tmp/gh-aw/mcp-payloads\"\n          mkdir -p \"${MCP_GATEWAY_PAYLOAD_DIR}\"\n          export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD=\"524288\"\n          export DEBUG=\"*\"\n          \n          export GH_AW_ENGINE=\"copilot\"\n          export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_LOCKDOWN -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '\"${GITHUB_WORKSPACE}\"':'\"${GITHUB_WORKSPACE}\"':rw ghcr.io/github/gh-aw-mcpg:v0.1.8'\n          \n          mkdir -p /home/runner/.copilot\n          cat << GH_AW_MCP_CONFIG_EOF | bash /opt/gh-aw/actions/start_mcp_gateway.sh\n          {\n            \"mcpServers\": {\n              \"github\": {\n                \"type\": \"stdio\",\n                \"container\": \"ghcr.io/github/github-mcp-server:v0.31.0\",\n                \"env\": {\n                  \"GITHUB_LOCKDOWN_MODE\": \"$GITHUB_MCP_LOCKDOWN\",\n                  \"GITHUB_PERSONAL_ACCESS_TOKEN\": \"\\${GITHUB_MCP_SERVER_TOKEN}\",\n                  \"GITHUB_READ_ONLY\": \"1\",\n                  \"GITHUB_TOOLSETS\": \"context,repos,issues,pull_requests\"\n                }\n              },\n              \"safeoutputs\": {\n                \"type\": \"http\",\n                \"url\": \"http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT\",\n                \"headers\": {\n                  \"Authorization\": \"\\${GH_AW_SAFE_OUTPUTS_API_KEY}\"\n                }\n              }\n            },\n            \"gateway\": {\n              \"port\": $MCP_GATEWAY_PORT,\n              \"domain\": \"${MCP_GATEWAY_DOMAIN}\",\n              \"apiKey\": \"${MCP_GATEWAY_API_KEY}\",\n              \"payloadDir\": \"${MCP_GATEWAY_PAYLOAD_DIR}\"\n            }\n          }\n          GH_AW_MCP_CONFIG_EOF\n      - name: Download activation artifact\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8\n        with:\n          name: activation\n          path: /tmp/gh-aw\n      - name: Clean git credentials\n        run: bash /opt/gh-aw/actions/clean_git_credentials.sh\n      - name: Execute GitHub Copilot CLI\n        id: agentic_execution\n        # Copilot CLI tool arguments (sorted):\n        timeout-minutes: 30\n        run: |\n          set -o pipefail\n          touch /tmp/gh-aw/agent-step-summary.md\n          # shellcheck disable=SC1003\n          sudo -E awf --env-all --container-workdir \"${GITHUB_WORKSPACE}\" --allow-domains \"api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com\" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \\\n            -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir \"${GITHUB_WORKSPACE}\" --disable-builtin-mcps --allow-all-tools --allow-all-paths --prompt \"$(cat /tmp/gh-aw/aw-prompts/prompt.txt)\"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log\n        env:\n          COPILOT_AGENT_RUNNER_TYPE: STANDALONE\n          COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}\n          COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }}\n          GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n          GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}\n          GITHUB_API_URL: ${{ github.api_url }}\n          GITHUB_HEAD_REF: ${{ github.head_ref }}\n          GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          GITHUB_REF_NAME: ${{ github.ref_name }}\n          GITHUB_SERVER_URL: ${{ github.server_url }}\n          GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md\n          GITHUB_WORKSPACE: ${{ github.workspace }}\n          XDG_CONFIG_HOME: /home/runner\n      - name: Detect inference access error\n        id: detect-inference-error\n        if: always()\n        continue-on-error: true\n        run: bash /opt/gh-aw/actions/detect_inference_access_error.sh\n      - name: Configure Git credentials\n        env:\n          REPO_NAME: ${{ github.repository }}\n          SERVER_URL: ${{ github.server_url }}\n        run: |\n          git config --global user.email \"github-actions[bot]@users.noreply.github.com\"\n          git config --global user.name \"github-actions[bot]\"\n          git config --global am.keepcr true\n          # Re-authenticate git with GitHub token\n          SERVER_URL_STRIPPED=\"${SERVER_URL#https://}\"\n          git remote set-url origin \"https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git\"\n          echo \"Git configured with standard GitHub Actions identity\"\n      - name: Copy Copilot session state files to logs\n        if: always()\n        continue-on-error: true\n        run: |\n          # Copy Copilot session state files to logs folder for artifact collection\n          # This ensures they are in /tmp/gh-aw/ where secret redaction can scan them\n          SESSION_STATE_DIR=\"$HOME/.copilot/session-state\"\n          LOGS_DIR=\"/tmp/gh-aw/sandbox/agent/logs\"\n          \n          if [ -d \"$SESSION_STATE_DIR\" ]; then\n            echo \"Copying Copilot session state files from $SESSION_STATE_DIR to $LOGS_DIR\"\n            mkdir -p \"$LOGS_DIR\"\n            cp -v \"$SESSION_STATE_DIR\"/*.jsonl \"$LOGS_DIR/\" 2>/dev/null || true\n            echo \"Session state files copied successfully\"\n          else\n            echo \"No session-state directory found at $SESSION_STATE_DIR\"\n          fi\n      - name: Stop MCP Gateway\n        if: always()\n        continue-on-error: true\n        env:\n          MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }}\n          MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }}\n          GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }}\n        run: |\n          bash /opt/gh-aw/actions/stop_mcp_gateway.sh \"$GATEWAY_PID\"\n      - name: Redact secrets in logs\n        if: always()\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        with:\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/redact_secrets.cjs');\n            await main();\n        env:\n          GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN'\n          SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}\n          SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}\n          SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}\n          SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      - name: Append agent step summary\n        if: always()\n        run: bash /opt/gh-aw/actions/append_agent_step_summary.sh\n      - name: Upload Safe Outputs\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7\n        with:\n          name: safe-output\n          path: ${{ env.GH_AW_SAFE_OUTPUTS }}\n          if-no-files-found: warn\n      - name: Ingest agent output\n        id: collect_output\n        if: always()\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}\n          GH_AW_ALLOWED_DOMAINS: \"api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com\"\n          GITHUB_SERVER_URL: ${{ github.server_url }}\n          GITHUB_API_URL: ${{ github.api_url }}\n        with:\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/collect_ndjson_output.cjs');\n            await main();\n      - name: Upload sanitized agent output\n        if: always() && env.GH_AW_AGENT_OUTPUT\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7\n        with:\n          name: agent-output\n          path: ${{ env.GH_AW_AGENT_OUTPUT }}\n          if-no-files-found: warn\n      - name: Upload engine output files\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7\n        with:\n          name: agent_outputs\n          path: |\n            /tmp/gh-aw/sandbox/agent/logs/\n            /tmp/gh-aw/redacted-urls.log\n          if-no-files-found: ignore\n      - name: Parse agent logs for step summary\n        if: always()\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/\n        with:\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/parse_copilot_log.cjs');\n            await main();\n      - name: Parse MCP Gateway logs for step summary\n        if: always()\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        with:\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/parse_mcp_gateway_log.cjs');\n            await main();\n      - name: Print firewall logs\n        if: always()\n        continue-on-error: true\n        env:\n          AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs\n        run: |\n          # Fix permissions on firewall logs so they can be uploaded as artifacts\n          # AWF runs with sudo, creating files owned by root\n          sudo chmod -R a+r /tmp/gh-aw/sandbox/firewall/logs 2>/dev/null || true\n          # Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step)\n          if command -v awf &> /dev/null; then\n            awf logs summary | tee -a \"$GITHUB_STEP_SUMMARY\"\n          else\n            echo 'AWF binary not installed, skipping firewall log summary'\n          fi\n      - name: Upload agent artifacts\n        if: always()\n        continue-on-error: true\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7\n        with:\n          name: agent-artifacts\n          path: |\n            /tmp/gh-aw/aw-prompts/prompt.txt\n            /tmp/gh-aw/mcp-logs/\n            /tmp/gh-aw/sandbox/firewall/logs/\n            /tmp/gh-aw/agent-stdio.log\n            /tmp/gh-aw/agent/\n            /tmp/gh-aw/aw-*.patch\n          if-no-files-found: ignore\n      # --- Threat Detection (inline) ---\n      - name: Check if detection needed\n        id: detection_guard\n        if: always()\n        env:\n          OUTPUT_TYPES: ${{ steps.collect_output.outputs.output_types }}\n          HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }}\n        run: |\n          if [[ -n \"$OUTPUT_TYPES\" || \"$HAS_PATCH\" == \"true\" ]]; then\n            echo \"run_detection=true\" >> \"$GITHUB_OUTPUT\"\n            echo \"Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH\"\n          else\n            echo \"run_detection=false\" >> \"$GITHUB_OUTPUT\"\n            echo \"Detection skipped: no agent outputs or patches to analyze\"\n          fi\n      - name: Clear MCP configuration for detection\n        if: always() && steps.detection_guard.outputs.run_detection == 'true'\n        run: |\n          rm -f /tmp/gh-aw/mcp-config/mcp-servers.json\n          rm -f /home/runner/.copilot/mcp-config.json\n          rm -f \"$GITHUB_WORKSPACE/.gemini/settings.json\"\n      - name: Prepare threat detection files\n        if: always() && steps.detection_guard.outputs.run_detection == 'true'\n        run: |\n          mkdir -p /tmp/gh-aw/threat-detection/aw-prompts\n          cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true\n          cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true\n          for f in /tmp/gh-aw/aw-*.patch; do\n            [ -f \"$f\" ] && cp \"$f\" /tmp/gh-aw/threat-detection/ 2>/dev/null || true\n          done\n          echo \"Prepared threat detection files:\"\n          ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true\n      - name: Setup threat detection\n        if: always() && steps.detection_guard.outputs.run_detection == 'true'\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          WORKFLOW_NAME: \"Code Simplifier\"\n          WORKFLOW_DESCRIPTION: \"Analyzes recently modified code and creates pull requests with simplifications that improve clarity, consistency, and maintainability while preserving functionality\"\n          HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }}\n        with:\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/setup_threat_detection.cjs');\n            await main();\n      - name: Ensure threat-detection directory and log\n        if: always() && steps.detection_guard.outputs.run_detection == 'true'\n        run: |\n          mkdir -p /tmp/gh-aw/threat-detection\n          touch /tmp/gh-aw/threat-detection/detection.log\n      - name: Execute GitHub Copilot CLI\n        if: always() && steps.detection_guard.outputs.run_detection == 'true'\n        id: detection_agentic_execution\n        # Copilot CLI tool arguments (sorted):\n        # --allow-tool shell(cat)\n        # --allow-tool shell(grep)\n        # --allow-tool shell(head)\n        # --allow-tool shell(jq)\n        # --allow-tool shell(ls)\n        # --allow-tool shell(tail)\n        # --allow-tool shell(wc)\n        timeout-minutes: 20\n        run: |\n          set -o pipefail\n          touch /tmp/gh-aw/agent-step-summary.md\n          # shellcheck disable=SC1003\n          sudo -E awf --env-all --container-workdir \"${GITHUB_WORKSPACE}\" --allow-domains \"api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,raw.githubusercontent.com,registry.npmjs.org,telemetry.enterprise.githubcopilot.com\" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \\\n            -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir \"${GITHUB_WORKSPACE}\" --disable-builtin-mcps --allow-tool '\\''shell(cat)'\\'' --allow-tool '\\''shell(grep)'\\'' --allow-tool '\\''shell(head)'\\'' --allow-tool '\\''shell(jq)'\\'' --allow-tool '\\''shell(ls)'\\'' --allow-tool '\\''shell(tail)'\\'' --allow-tool '\\''shell(wc)'\\'' --prompt \"$(cat /tmp/gh-aw/aw-prompts/prompt.txt)\"' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log\n        env:\n          COPILOT_AGENT_RUNNER_TYPE: STANDALONE\n          COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}\n          COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }}\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n          GITHUB_API_URL: ${{ github.api_url }}\n          GITHUB_HEAD_REF: ${{ github.head_ref }}\n          GITHUB_REF_NAME: ${{ github.ref_name }}\n          GITHUB_SERVER_URL: ${{ github.server_url }}\n          GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md\n          GITHUB_WORKSPACE: ${{ github.workspace }}\n          XDG_CONFIG_HOME: /home/runner\n      - name: Parse threat detection results\n        id: parse_detection_results\n        if: always() && steps.detection_guard.outputs.run_detection == 'true'\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        with:\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/parse_threat_detection_results.cjs');\n            await main();\n      - name: Upload threat detection log\n        if: always() && steps.detection_guard.outputs.run_detection == 'true'\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7\n        with:\n          name: threat-detection.log\n          path: /tmp/gh-aw/threat-detection/detection.log\n          if-no-files-found: ignore\n      - name: Set detection conclusion\n        id: detection_conclusion\n        if: always()\n        env:\n          RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }}\n          DETECTION_SUCCESS: ${{ steps.parse_detection_results.outputs.success }}\n        run: |\n          if [[ \"$RUN_DETECTION\" != \"true\" ]]; then\n            echo \"conclusion=skipped\" >> \"$GITHUB_OUTPUT\"\n            echo \"success=true\" >> \"$GITHUB_OUTPUT\"\n            echo \"Detection was not needed, marking as skipped\"\n          elif [[ \"$DETECTION_SUCCESS\" == \"true\" ]]; then\n            echo \"conclusion=success\" >> \"$GITHUB_OUTPUT\"\n            echo \"success=true\" >> \"$GITHUB_OUTPUT\"\n            echo \"Detection passed successfully\"\n          else\n            echo \"conclusion=failure\" >> \"$GITHUB_OUTPUT\"\n            echo \"success=false\" >> \"$GITHUB_OUTPUT\"\n            echo \"Detection found issues\"\n          fi\n\n  conclusion:\n    needs:\n      - activation\n      - agent\n      - safe_outputs\n    if: (always()) && (needs.agent.result != 'skipped')\n    runs-on: ubuntu-slim\n    permissions:\n      contents: write\n      issues: write\n      pull-requests: write\n    concurrency:\n      group: \"gh-aw-conclusion-code-simplifier\"\n      cancel-in-progress: false\n    outputs:\n      noop_message: ${{ steps.noop.outputs.noop_message }}\n      tools_reported: ${{ steps.missing_tool.outputs.tools_reported }}\n      total_count: ${{ steps.missing_tool.outputs.total_count }}\n    steps:\n      - name: Setup Scripts\n        uses: github/gh-aw/actions/setup@e211c855a20aa6cf9297b411466e1c382a8686db # v0.55.0\n        with:\n          destination: /opt/gh-aw/actions\n      - name: Download agent output artifact\n        id: download-agent-output\n        continue-on-error: true\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8\n        with:\n          name: agent-output\n          path: /tmp/gh-aw/safeoutputs/\n      - name: Setup agent output environment variable\n        if: steps.download-agent-output.outcome == 'success'\n        run: |\n          mkdir -p /tmp/gh-aw/safeoutputs/\n          find \"/tmp/gh-aw/safeoutputs/\" -type f -print\n          echo \"GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json\" >> \"$GITHUB_ENV\"\n      - name: Process No-Op Messages\n        id: noop\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}\n          GH_AW_NOOP_MAX: \"1\"\n          GH_AW_WORKFLOW_NAME: \"Code Simplifier\"\n          GH_AW_WORKFLOW_SOURCE: \"github/gh-aw/.github/workflows/code-simplifier.md@852cb06ad52958b402ed982b69957ffc57ca0619\"\n          GH_AW_WORKFLOW_SOURCE_URL: \"${{ github.server_url }}/github/gh-aw/tree/852cb06ad52958b402ed982b69957ffc57ca0619/.github/workflows/code-simplifier.md\"\n          GH_AW_TRACKER_ID: \"code-simplifier\"\n        with:\n          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/noop.cjs');\n            await main();\n      - name: Record Missing Tool\n        id: missing_tool\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}\n          GH_AW_WORKFLOW_NAME: \"Code Simplifier\"\n          GH_AW_WORKFLOW_SOURCE: \"github/gh-aw/.github/workflows/code-simplifier.md@852cb06ad52958b402ed982b69957ffc57ca0619\"\n          GH_AW_WORKFLOW_SOURCE_URL: \"${{ github.server_url }}/github/gh-aw/tree/852cb06ad52958b402ed982b69957ffc57ca0619/.github/workflows/code-simplifier.md\"\n          GH_AW_TRACKER_ID: \"code-simplifier\"\n        with:\n          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/missing_tool.cjs');\n            await main();\n      - name: Handle Agent Failure\n        id: handle_agent_failure\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}\n          GH_AW_WORKFLOW_NAME: \"Code Simplifier\"\n          GH_AW_WORKFLOW_SOURCE: \"github/gh-aw/.github/workflows/code-simplifier.md@852cb06ad52958b402ed982b69957ffc57ca0619\"\n          GH_AW_WORKFLOW_SOURCE_URL: \"${{ github.server_url }}/github/gh-aw/tree/852cb06ad52958b402ed982b69957ffc57ca0619/.github/workflows/code-simplifier.md\"\n          GH_AW_TRACKER_ID: \"code-simplifier\"\n          GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n          GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}\n          GH_AW_WORKFLOW_ID: \"code-simplifier\"\n          GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }}\n          GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }}\n          GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }}\n          GH_AW_CODE_PUSH_FAILURE_ERRORS: ${{ needs.safe_outputs.outputs.code_push_failure_errors }}\n          GH_AW_CODE_PUSH_FAILURE_COUNT: ${{ needs.safe_outputs.outputs.code_push_failure_count }}\n          GH_AW_GROUP_REPORTS: \"false\"\n          GH_AW_TIMEOUT_MINUTES: \"30\"\n        with:\n          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/handle_agent_failure.cjs');\n            await main();\n      - name: Handle No-Op Message\n        id: handle_noop_message\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}\n          GH_AW_WORKFLOW_NAME: \"Code Simplifier\"\n          GH_AW_WORKFLOW_SOURCE: \"github/gh-aw/.github/workflows/code-simplifier.md@852cb06ad52958b402ed982b69957ffc57ca0619\"\n          GH_AW_WORKFLOW_SOURCE_URL: \"${{ github.server_url }}/github/gh-aw/tree/852cb06ad52958b402ed982b69957ffc57ca0619/.github/workflows/code-simplifier.md\"\n          GH_AW_TRACKER_ID: \"code-simplifier\"\n          GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n          GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}\n          GH_AW_NOOP_MESSAGE: ${{ steps.noop.outputs.noop_message }}\n          GH_AW_NOOP_REPORT_AS_ISSUE: \"true\"\n        with:\n          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/handle_noop_message.cjs');\n            await main();\n      - name: Handle Create Pull Request Error\n        id: handle_create_pr_error\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}\n          GH_AW_WORKFLOW_NAME: \"Code Simplifier\"\n          GH_AW_WORKFLOW_SOURCE: \"github/gh-aw/.github/workflows/code-simplifier.md@852cb06ad52958b402ed982b69957ffc57ca0619\"\n          GH_AW_WORKFLOW_SOURCE_URL: \"${{ github.server_url }}/github/gh-aw/tree/852cb06ad52958b402ed982b69957ffc57ca0619/.github/workflows/code-simplifier.md\"\n          GH_AW_TRACKER_ID: \"code-simplifier\"\n          GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n        with:\n          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/handle_create_pr_error.cjs');\n            await main();\n\n  pre_activation:\n    runs-on: ubuntu-slim\n    outputs:\n      activated: ${{ (steps.check_membership.outputs.is_team_member == 'true') && (steps.check_skip_if_match.outputs.skip_check_ok == 'true') }}\n      matched_command: ''\n    steps:\n      - name: Setup Scripts\n        uses: github/gh-aw/actions/setup@e211c855a20aa6cf9297b411466e1c382a8686db # v0.55.0\n        with:\n          destination: /opt/gh-aw/actions\n      - name: Check team membership for workflow\n        id: check_membership\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_REQUIRED_ROLES: admin,maintainer,write\n        with:\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/check_membership.cjs');\n            await main();\n      - name: Check skip-if-match query\n        id: check_skip_if_match\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_SKIP_QUERY: \"is:pr is:open in:title \\\"[code-simplifier]\\\"\"\n          GH_AW_WORKFLOW_NAME: \"Code Simplifier\"\n          GH_AW_SKIP_MAX_MATCHES: \"1\"\n        with:\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/check_skip_if_match.cjs');\n            await main();\n\n  safe_outputs:\n    needs:\n      - activation\n      - agent\n    if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.agent.outputs.detection_success == 'true')\n    runs-on: ubuntu-slim\n    permissions:\n      contents: write\n      issues: write\n      pull-requests: write\n    timeout-minutes: 15\n    env:\n      GH_AW_CALLER_WORKFLOW_ID: \"${{ github.repository }}/code-simplifier\"\n      GH_AW_ENGINE_ID: \"copilot\"\n      GH_AW_TRACKER_ID: \"code-simplifier\"\n      GH_AW_WORKFLOW_ID: \"code-simplifier\"\n      GH_AW_WORKFLOW_NAME: \"Code Simplifier\"\n      GH_AW_WORKFLOW_SOURCE: \"github/gh-aw/.github/workflows/code-simplifier.md@852cb06ad52958b402ed982b69957ffc57ca0619\"\n      GH_AW_WORKFLOW_SOURCE_URL: \"${{ github.server_url }}/github/gh-aw/tree/852cb06ad52958b402ed982b69957ffc57ca0619/.github/workflows/code-simplifier.md\"\n    outputs:\n      code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }}\n      code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }}\n      create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }}\n      create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }}\n      created_pr_number: ${{ steps.process_safe_outputs.outputs.created_pr_number }}\n      created_pr_url: ${{ steps.process_safe_outputs.outputs.created_pr_url }}\n      process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }}\n      process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }}\n    steps:\n      - name: Setup Scripts\n        uses: github/gh-aw/actions/setup@e211c855a20aa6cf9297b411466e1c382a8686db # v0.55.0\n        with:\n          destination: /opt/gh-aw/actions\n      - name: Download agent output artifact\n        id: download-agent-output\n        continue-on-error: true\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8\n        with:\n          name: agent-output\n          path: /tmp/gh-aw/safeoutputs/\n      - name: Setup agent output environment variable\n        if: steps.download-agent-output.outcome == 'success'\n        run: |\n          mkdir -p /tmp/gh-aw/safeoutputs/\n          find \"/tmp/gh-aw/safeoutputs/\" -type f -print\n          echo \"GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json\" >> \"$GITHUB_ENV\"\n      - name: Download patch artifact\n        continue-on-error: true\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8\n        with:\n          name: agent-artifacts\n          path: /tmp/gh-aw/\n      - name: Checkout repository\n        if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request'))\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          ref: ${{ github.base_ref || github.event.pull_request.base.ref || github.ref_name || github.event.repository.default_branch }}\n          token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          persist-credentials: false\n          fetch-depth: 1\n      - name: Configure Git credentials\n        if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request'))\n        env:\n          REPO_NAME: ${{ github.repository }}\n          SERVER_URL: ${{ github.server_url }}\n          GIT_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n        run: |\n          git config --global user.email \"github-actions[bot]@users.noreply.github.com\"\n          git config --global user.name \"github-actions[bot]\"\n          git config --global am.keepcr true\n          # Re-authenticate git with GitHub token\n          SERVER_URL_STRIPPED=\"${SERVER_URL#https://}\"\n          git remote set-url origin \"https://x-access-token:${GIT_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git\"\n          echo \"Git configured with standard GitHub Actions identity\"\n      - name: Process Safe Outputs\n        id: process_safe_outputs\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}\n          GH_AW_ALLOWED_DOMAINS: \"api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com\"\n          GITHUB_SERVER_URL: ${{ github.server_url }}\n          GITHUB_API_URL: ${{ github.api_url }}\n          GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: \"{\\\"create_pull_request\\\":{\\\"expires\\\":24,\\\"labels\\\":[\\\"refactoring\\\",\\\"code-quality\\\",\\\"automation\\\"],\\\"max\\\":1,\\\"max_patch_size\\\":1024,\\\"reviewers\\\":[\\\"copilot\\\"],\\\"title_prefix\\\":\\\"[code-simplifier] \\\"},\\\"missing_data\\\":{},\\\"missing_tool\\\":{}}\"\n          GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }}\n        with:\n          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/safe_output_handler_manager.cjs');\n            await main();\n      - name: Upload safe output items manifest\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7\n        with:\n          name: safe-output-items\n          path: /tmp/safe-output-items.jsonl\n          if-no-files-found: warn\n\n"
  },
  {
    "path": ".github/workflows/code-simplifier.md",
    "content": "---\nname: Code Simplifier\ndescription: Analyzes recently modified code and creates pull requests with simplifications that improve clarity, consistency, and maintainability while preserving functionality\non:\n  schedule: daily\n  skip-if-match: 'is:pr is:open in:title \"[code-simplifier]\"'\n\npermissions:\n  contents: read\n  issues: read\n  pull-requests: read\n\ntracker-id: code-simplifier\n\nimports:\n  - shared/mood.md\n  - shared/reporting.md\n\nsafe-outputs:\n  create-pull-request:\n    title-prefix: '[code-simplifier] '\n    labels: [refactoring, code-quality, automation]\n    reviewers: [copilot]\n    expires: 1d\n\ntools:\n  github:\n    toolsets: [default]\n\ntimeout-minutes: 30\nstrict: true\nsource: github/gh-aw/.github/workflows/code-simplifier.md@852cb06ad52958b402ed982b69957ffc57ca0619\nengine: copilot\n---\n\n<!-- This prompt will be imported in the agentic workflow .github/workflows/code-simplifier.md at runtime. -->\n<!-- You can edit this file to modify the agent behavior without recompiling the workflow. -->\n\n# Code Simplifier Agent\n\nYou are an expert code simplification specialist focused on enhancing code clarity, consistency, and maintainability while preserving exact functionality. Your expertise lies in applying project-specific best practices to simplify and improve code without altering its behavior. You prioritize readable, explicit code over overly compact solutions. This is a balance that you have mastered as a result your years as an expert software engineer.\n\n## Your Mission\n\nAnalyze recently modified code from the last 24 hours and apply refinements that improve code quality while preserving all functionality. Create a pull request with the simplified code if improvements are found.\n\n## Current Context\n\n- **Repository**: ${{ github.repository }}\n- **Analysis Date**: $(date +%Y-%m-%d)\n- **Workspace**: ${{ github.workspace }}\n\n## Phase 1: Identify Recently Modified Code\n\n### 1.1 Find Recent Changes\n\nSearch for merged pull requests and commits from the last 24 hours:\n\n```bash\n# Get yesterday's date in ISO format\nYESTERDAY=$(date -d '1 day ago' '+%Y-%m-%d' 2>/dev/null || date -v-1d '+%Y-%m-%d')\n\n# List recent commits\ngit log --since=\"24 hours ago\" --pretty=format:\"%H %s\" --no-merges\n```\n\nUse GitHub tools to:\n\n- Search for pull requests merged in the last 24 hours: `repo:${{ github.repository }} is:pr is:merged merged:>=${YESTERDAY}`\n- Get details of merged PRs to understand what files were changed\n- List commits from the last 24 hours to identify modified files\n\n### 1.2 Extract Changed Files\n\nFor each merged PR or recent commit:\n\n- Use `pull_request_read` with `method: get_files` to list changed files\n- Use `get_commit` to see file changes in recent commits\n- Focus on source code files (`.go`, `.js`, `.ts`, `.tsx`, `.cjs`, `.py`, `.cs`, etc.)\n- Exclude test files, lock files, and generated files\n\n### 1.3 Determine Scope\n\nIf **no files were changed in the last 24 hours**, exit gracefully without creating a PR:\n\n```\n✅ No code changes detected in the last 24 hours.\nCode simplifier has nothing to process today.\n```\n\nIf **files were changed**, proceed to Phase 2.\n\n## Phase 2: Analyze and Simplify Code\n\n### 2.1 Review Project Standards\n\nBefore simplifying, review the project's coding standards from relevant documentation:\n\n- For Go projects: Check `AGENTS.md`, `DEVGUIDE.md`, or similar files\n- For JavaScript/TypeScript: Look for `CLAUDE.md`, style guides, or coding conventions\n- For Python: Check for style guides, PEP 8 adherence, or project-specific conventions\n- For .NET/C#: Check `.editorconfig`, `Directory.Build.props`, or coding conventions in docs\n\n**Key Standards to Apply:**\n\nFor **JavaScript/TypeScript** projects:\n\n- Use ES modules with proper import sorting and extensions\n- Prefer `function` keyword over arrow functions for top-level functions\n- Use explicit return type annotations for top-level functions\n- Follow proper React component patterns with explicit Props types\n- Use proper error handling patterns (avoid try/catch when possible)\n- Maintain consistent naming conventions\n\n### 2.2 Simplification Principles\n\nApply these refinements to the recently modified code:\n\n#### 1. Preserve Functionality\n\n- **NEVER** change what the code does - only how it does it\n- All original features, outputs, and behaviors must remain intact\n- Run tests before and after to ensure no behavioral changes\n\n#### 2. Enhance Clarity\n\n- Reduce unnecessary complexity and nesting\n- Eliminate redundant code and abstractions\n- Improve readability through clear variable and function names\n- Consolidate related logic\n- Remove unnecessary comments that describe obvious code\n- **IMPORTANT**: Avoid nested ternary operators - prefer switch statements or if/else chains\n- Choose clarity over brevity - explicit code is often better than compact code\n\n#### 3. Apply Project Standards\n\n- Use project-specific conventions and patterns\n- Follow established naming conventions\n- Apply consistent formatting\n- Use appropriate language features (modern syntax where beneficial)\n\n#### 4. Maintain Balance\n\nAvoid over-simplification that could:\n\n- Reduce code clarity or maintainability\n- Create overly clever solutions that are hard to understand\n- Combine too many concerns into single functions or components\n- Remove helpful abstractions that improve code organization\n- Prioritize \"fewer lines\" over readability (e.g., nested ternaries, dense one-liners)\n- Make the code harder to debug or extend\n\n### 2.3 Perform Code Analysis\n\nFor each changed file:\n\n1. **Read the file contents** using the edit or view tool\n2. **Identify refactoring opportunities**:\n   - Long functions that could be split\n   - Duplicate code patterns\n   - Complex conditionals that could be simplified\n   - Unclear variable names\n   - Missing or excessive comments\n   - Non-standard patterns\n3. **Design the simplification**:\n   - What specific changes will improve clarity?\n   - How can complexity be reduced?\n   - What patterns should be applied?\n   - Will this maintain all functionality?\n\n### 2.4 Apply Simplifications\n\nUse the **edit** tool to modify files:\n\n```bash\n# For each file with improvements:\n# 1. Read the current content\n# 2. Apply targeted edits to simplify code\n# 3. Ensure all functionality is preserved\n```\n\n**Guidelines for edits:**\n\n- Make surgical, targeted changes\n- One logical improvement per edit (but batch multiple edits in a single response)\n- Preserve all original behavior\n- Keep changes focused on recently modified code\n- Don't refactor unrelated code unless it improves understanding of the changes\n\n## Phase 3: Validate Changes\n\n### 3.1 Run Tests\n\nAfter making simplifications, run the project's test suite to ensure no functionality was broken:\n\n# For JavaScript/TypeScript projects\n\nyarn --cwd code vitest run --changed\n\n````\n\nIf tests fail:\n\n- Review the failures carefully\n- Revert changes that broke functionality\n- Adjust simplifications to preserve behavior\n- Re-run tests until they pass\n\n### 3.2 Run Linters\n\nEnsure code style is consistent:\n\n```\nyarn lint\n```\n\nFix any linting issues introduced by the simplifications.\n\n### 3.3 Check Build\n\nVerify the project still builds successfully:\n\n```\nyarn task --task \"compile\"\n```\n\n## Phase 4: Create Pull Request\n\n### 4.1 Determine If PR Is Needed\n\nOnly create a PR if:\n\n- ✅ You made actual code simplifications\n- ✅ All tests pass\n- ✅ Linting is clean\n- ✅ Build succeeds\n- ✅ Changes improve code quality without breaking functionality\n\nIf no improvements were made or changes broke tests, exit gracefully:\n\n```\n✅ Code analyzed from last 24 hours.\nNo simplifications needed - code already meets quality standards.\n```\n\n### 4.2 Generate PR Description\n\nIf creating a PR, use this structure:\n\n```markdown\n## Code Simplification - [Date]\n\nThis PR simplifies recently modified code to improve clarity, consistency, and maintainability while preserving all functionality.\n\n### Files Simplified\n\n- `path/to/file1.go` - [Brief description of improvements]\n- `path/to/file2.js` - [Brief description of improvements]\n\n### Improvements Made\n\n1. **Reduced Complexity**\n   - Simplified nested conditionals in `file1.go`\n   - Extracted helper function for repeated logic\n\n2. **Enhanced Clarity**\n   - Renamed variables for better readability\n   - Removed redundant comments\n   - Applied consistent naming conventions\n\n3. **Applied Project Standards**\n   - Used `function` keyword instead of arrow functions\n   - Added explicit type annotations\n   - Followed established patterns\n\n### Changes Based On\n\nRecent changes from:\n\n- #[PR_NUMBER] - [PR title]\n- Commit [SHORT_SHA] - [Commit message]\n\n### Testing\n\n- ✅ All tests pass (`make test-unit`)\n- ✅ Linting passes (`make lint`)\n- ✅ Build succeeds (`make build`)\n- ✅ No functional changes - behavior is identical\n\n### Review Focus\n\nPlease verify:\n\n- Functionality is preserved\n- Simplifications improve code quality\n- Changes align with project conventions\n- No unintended side effects\n\n---\n\n_Automated by Code Simplifier Agent - analyzing code from the last 24 hours_\n```\n\n### 4.3 Use Safe Outputs\n\nCreate the pull request using the safe-outputs configuration:\n\n- Title will be prefixed with `[code-simplifier]`\n- Labeled with `refactoring`, `code-quality`, `automation`\n- Assigned to `copilot` for review\n- Set as ready for review (not draft)\n\n## Important Guidelines\n\n### Scope Control\n\n- **Focus on recent changes**: Only refine code modified in the last 24 hours\n- **Don't over-refactor**: Avoid touching unrelated code\n- **Preserve interfaces**: Don't change public APIs or exported functions\n- **Incremental improvements**: Make targeted, surgical changes\n\n### Quality Standards\n\n- **Test first**: Always run tests after simplifications\n- **Preserve behavior**: Functionality must remain identical\n- **Follow conventions**: Apply project-specific patterns consistently\n- **Clear over clever**: Prioritize readability and maintainability\n\n### Exit Conditions\n\nExit gracefully without creating a PR if:\n\n- No code was changed in the last 24 hours\n- No simplifications are beneficial\n- Tests fail after changes\n- Build fails after changes\n- Changes are too risky or complex\n\n### Success Metrics\n\nA successful simplification:\n\n- ✅ Improves code clarity without changing behavior\n- ✅ Passes all tests and linting\n- ✅ Applies project-specific conventions\n- ✅ Makes code easier to understand and maintain\n- ✅ Focuses on recently modified code\n- ✅ Provides clear documentation of changes\n\n## Output Requirements\n\nYour output MUST either:\n\n1. **If no changes in last 24 hours**:\n\n   ```\n   ✅ No code changes detected in the last 24 hours.\n   Code simplifier has nothing to process today.\n   ```\n\n2. **If no simplifications beneficial**:\n\n   ```\n   ✅ Code analyzed from last 24 hours.\n   No simplifications needed - code already meets quality standards.\n   ```\n\n3. **If simplifications made**: Create a PR with the changes using safe-outputs\n\nBegin your code simplification analysis now. Find recently modified code, assess simplification opportunities, apply improvements while preserving functionality, validate changes, and create a PR if beneficial.\n````\n"
  },
  {
    "path": ".github/workflows/copilot-setup-steps.yml",
    "content": "name: 'Copilot Setup Steps'\n\n# Automatically run the setup steps when they are changed to allow for easy validation, and\n# allow manual testing through the repository's \"Actions\" tab\non:\n  workflow_dispatch:\n  push:\n    paths:\n      - .github/workflows/copilot-setup-steps.yml\n  pull_request:\n    paths:\n      - .github/workflows/copilot-setup-steps.yml\n\njobs:\n  # The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot.\n  copilot-setup-steps:\n    runs-on: ubuntu-latest\n\n    # Set the permissions to the lowest permissions possible needed for your steps.\n    # Copilot will be given its own token for its operations.\n    permissions:\n      contents: read\n\n    # You can define any steps you want, and they will run before the agent starts.\n    # If you do not check out your code, Copilot will do this for you.\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0\n\n      - name: Setup Node.js and Install Dependencies\n        uses: ./.github/actions/setup-node-and-install\n        with:\n          install-code-deps: true\n\n      - name: Compile\n        run: yarn nx run-many --targets compile --no-cloud\n"
  },
  {
    "path": ".github/workflows/cron-weekly.yml",
    "content": "name: Markdown Links Check\n# runs every monday at 9 am\non:\n  schedule:\n    - cron: \"0 9 * * 1\"\n\npermissions:\n  contents: read # to fetch repository files for markdown link checks\n\njobs:\n  check-links:\n    if: github.repository_owner == 'storybookjs'\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: gaurav-nelson/github-action-markdown-link-check@v1\n        # checks all markdown files from important folders including all subfolders\n        with:\n          # only show errors that occur instead of successful links + errors\n          use-quiet-mode: \"yes\"\n          # output full HTTP info for broken links\n          use-verbose-mode: \"yes\"\n          config-file: \".github/workflows/markdown-link-check-config.json\"\n      # Notify to Discord channel on failure\n      - name: Send Discord Notification\n        if: failure() # Only run this step if previous steps failed\n        run: |\n          curl -H \"Content-Type: application/json\" -X POST -d '{\"content\":\"The Markdown Links Check workflow has failed in the repository: [storybook]\"}' ${{ secrets.DISCORD_MONITORING_URL }}\n"
  },
  {
    "path": ".github/workflows/danger-js.yml",
    "content": "on:\n  pull_request:\n    types:\n      - opened\n      - synchronize\n      - reopened\n      - labeled\n      - unlabeled\n      - edited\n    branches:\n      - \"**\"\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.number }}\n  cancel-in-progress: true\n\nname: Danger JS\njobs:\n  dangerJS:\n    name: Danger JS\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - name: Danger JS\n        uses: docker://ghcr.io/danger/danger-js:13.0.5\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          args: --dangerfile scripts/dangerfile.js\n"
  },
  {
    "path": ".github/workflows/duplicate-code-detector.lock.yml",
    "content": "#\n#    ___                   _   _      \n#   / _ \\                 | | (_)     \n#  | |_| | __ _  ___ _ __ | |_ _  ___ \n#  |  _  |/ _` |/ _ \\ '_ \\| __| |/ __|\n#  | | | | (_| |  __/ | | | |_| | (__ \n#  \\_| |_/\\__, |\\___|_| |_|\\__|_|\\___|\n#          __/ |\n#  _    _ |___/ \n# | |  | |                / _| |\n# | |  | | ___ _ __ _  __| |_| | _____      ____\n# | |/\\| |/ _ \\ '__| |/ /|  _| |/ _ \\ \\ /\\ / / ___|\n# \\  /\\  / (_) | | | | ( | | | | (_) \\ V  V /\\__ \\\n#  \\/  \\/ \\___/|_| |_|\\_\\|_| |_|\\___/ \\_/\\_/ |___/\n#\n# This file was automatically generated by gh-aw (v0.55.0). DO NOT EDIT.\n#\n# To update this file, edit github/gh-aw/.github/workflows/duplicate-code-detector.md@852cb06ad52958b402ed982b69957ffc57ca0619 and run:\n#   gh aw compile\n# Not all edits will cause changes to this file.\n#\n# For more information: https://github.github.com/gh-aw/introduction/overview/\n#\n# Identifies duplicate code patterns across the codebase and suggests refactoring opportunities\n#\n# Source: github/gh-aw/.github/workflows/duplicate-code-detector.md@852cb06ad52958b402ed982b69957ffc57ca0619\n#\n# Resolved workflow manifest:\n#   Imports:\n#     - shared/mood.md\n#\n# gh-aw-metadata: {\"schema_version\":\"v2\",\"frontmatter_hash\":\"8f718997fab9f4077b50cf09e67d1c93cb5d11105def34e97ec4d56929ca4323\",\"compiler_version\":\"v0.55.0\",\"strict\":true}\n\nname: \"Duplicate Code Detector\"\n\"on\":\n  schedule:\n  - cron: \"12 8 * * *\"\n    # Friendly format: daily (scattered)\n  workflow_dispatch:\n\npermissions: {}\n\nconcurrency:\n  group: \"gh-aw-${{ github.workflow }}\"\n\nrun-name: \"Duplicate Code Detector\"\n\njobs:\n  activation:\n    runs-on: ubuntu-slim\n    permissions:\n      contents: read\n    outputs:\n      comment_id: \"\"\n      comment_repo: \"\"\n      model: ${{ steps.generate_aw_info.outputs.model }}\n      secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }}\n    steps:\n      - name: Setup Scripts\n        uses: github/gh-aw/actions/setup@e211c855a20aa6cf9297b411466e1c382a8686db # v0.55.0\n        with:\n          destination: /opt/gh-aw/actions\n      - name: Generate agentic run info\n        id: generate_aw_info\n        env:\n          GH_AW_INFO_ENGINE_ID: \"copilot\"\n          GH_AW_INFO_ENGINE_NAME: \"GitHub Copilot CLI\"\n          GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }}\n          GH_AW_INFO_VERSION: \"\"\n          GH_AW_INFO_AGENT_VERSION: \"latest\"\n          GH_AW_INFO_CLI_VERSION: \"v0.55.0\"\n          GH_AW_INFO_WORKFLOW_NAME: \"Duplicate Code Detector\"\n          GH_AW_INFO_EXPERIMENTAL: \"false\"\n          GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: \"true\"\n          GH_AW_INFO_STAGED: \"false\"\n          GH_AW_INFO_ALLOWED_DOMAINS: '[\"defaults\"]'\n          GH_AW_INFO_FIREWALL_ENABLED: \"true\"\n          GH_AW_INFO_AWF_VERSION: \"v0.23.0\"\n          GH_AW_INFO_AWMG_VERSION: \"\"\n          GH_AW_INFO_FIREWALL_TYPE: \"squid\"\n          GH_AW_COMPILED_STRICT: \"true\"\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        with:\n          script: |\n            const { main } = require('/opt/gh-aw/actions/generate_aw_info.cjs');\n            await main(core, context);\n      - name: Validate COPILOT_GITHUB_TOKEN secret\n        id: validate-secret\n        run: /opt/gh-aw/actions/validate_multi_secret.sh COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default\n        env:\n          COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}\n      - name: Checkout .github and .agents folders\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          sparse-checkout: |\n            .github\n            .agents\n          sparse-checkout-cone-mode: true\n          fetch-depth: 1\n          persist-credentials: false\n      - name: Check workflow file timestamps\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_WORKFLOW_FILE: \"duplicate-code-detector.lock.yml\"\n        with:\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/check_workflow_timestamp_api.cjs');\n            await main();\n      - name: Create prompt with built-in context\n        env:\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n          GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}\n          GH_AW_GITHUB_ACTOR: ${{ github.actor }}\n          GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }}\n          GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }}\n          GH_AW_GITHUB_EVENT_HEAD_COMMIT_ID: ${{ github.event.head_commit.id }}\n          GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}\n          GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}\n          GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}\n          GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}\n          GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}\n        run: |\n          bash /opt/gh-aw/actions/create_prompt_first.sh\n          {\n          cat << 'GH_AW_PROMPT_EOF'\n          <system>\n          GH_AW_PROMPT_EOF\n          cat \"/opt/gh-aw/prompts/xpia.md\"\n          cat \"/opt/gh-aw/prompts/temp_folder_prompt.md\"\n          cat \"/opt/gh-aw/prompts/markdown.md\"\n          cat \"/opt/gh-aw/prompts/safe_outputs_prompt.md\"\n          cat << 'GH_AW_PROMPT_EOF'\n          <safe-output-tools>\n          Tools: create_issue, missing_tool, missing_data, noop\n          </safe-output-tools>\n          <github-context>\n          The following GitHub context information is available for this workflow:\n          {{#if __GH_AW_GITHUB_ACTOR__ }}\n          - **actor**: __GH_AW_GITHUB_ACTOR__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_REPOSITORY__ }}\n          - **repository**: __GH_AW_GITHUB_REPOSITORY__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_WORKSPACE__ }}\n          - **workspace**: __GH_AW_GITHUB_WORKSPACE__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }}\n          - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }}\n          - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }}\n          - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }}\n          - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__\n          {{/if}}\n          {{#if __GH_AW_GITHUB_RUN_ID__ }}\n          - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__\n          {{/if}}\n          </github-context>\n          \n          GH_AW_PROMPT_EOF\n          cat << 'GH_AW_PROMPT_EOF'\n          </system>\n          GH_AW_PROMPT_EOF\n          cat << 'GH_AW_PROMPT_EOF'\n          {{#runtime-import .github/workflows/shared/mood.md}}\n          GH_AW_PROMPT_EOF\n          cat << 'GH_AW_PROMPT_EOF'\n          {{#runtime-import .github/workflows/duplicate-code-detector.md}}\n          GH_AW_PROMPT_EOF\n          } > \"$GH_AW_PROMPT\"\n      - name: Interpolate variables and render templates\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n          GH_AW_GITHUB_ACTOR: ${{ github.actor }}\n          GH_AW_GITHUB_EVENT_HEAD_COMMIT_ID: ${{ github.event.head_commit.id }}\n          GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}\n          GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}\n        with:\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/interpolate_prompt.cjs');\n            await main();\n      - name: Substitute placeholders\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n          GH_AW_GITHUB_ACTOR: ${{ github.actor }}\n          GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }}\n          GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }}\n          GH_AW_GITHUB_EVENT_HEAD_COMMIT_ID: ${{ github.event.head_commit.id }}\n          GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}\n          GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}\n          GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}\n          GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}\n          GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}\n        with:\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            \n            const substitutePlaceholders = require('/opt/gh-aw/actions/substitute_placeholders.cjs');\n            \n            // Call the substitution function\n            return await substitutePlaceholders({\n              file: process.env.GH_AW_PROMPT,\n              substitutions: {\n                GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR,\n                GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID,\n                GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER,\n                GH_AW_GITHUB_EVENT_HEAD_COMMIT_ID: process.env.GH_AW_GITHUB_EVENT_HEAD_COMMIT_ID,\n                GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER,\n                GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER,\n                GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY,\n                GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID,\n                GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE\n              }\n            });\n      - name: Validate prompt placeholders\n        env:\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n        run: bash /opt/gh-aw/actions/validate_prompt_placeholders.sh\n      - name: Print prompt\n        env:\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n        run: bash /opt/gh-aw/actions/print_prompt_summary.sh\n      - name: Upload activation artifact\n        if: success()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7\n        with:\n          name: activation\n          path: |\n            /tmp/gh-aw/aw_info.json\n            /tmp/gh-aw/aw-prompts/prompt.txt\n          retention-days: 1\n\n  agent:\n    needs: activation\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n      issues: read\n      pull-requests: read\n    concurrency:\n      group: \"gh-aw-copilot-${{ github.workflow }}\"\n    env:\n      DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}\n      GH_AW_ASSETS_ALLOWED_EXTS: \"\"\n      GH_AW_ASSETS_BRANCH: \"\"\n      GH_AW_ASSETS_MAX_SIZE_KB: 0\n      GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs\n      GH_AW_SAFE_OUTPUTS: /opt/gh-aw/safeoutputs/outputs.jsonl\n      GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json\n      GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json\n      GH_AW_WORKFLOW_ID_SANITIZED: duplicatecodedetector\n    outputs:\n      checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}\n      detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }}\n      detection_success: ${{ steps.detection_conclusion.outputs.success }}\n      has_patch: ${{ steps.collect_output.outputs.has_patch }}\n      inference_access_error: ${{ steps.detect-inference-error.outputs.inference_access_error || 'false' }}\n      model: ${{ needs.activation.outputs.model }}\n      output: ${{ steps.collect_output.outputs.output }}\n      output_types: ${{ steps.collect_output.outputs.output_types }}\n    steps:\n      - name: Setup Scripts\n        uses: github/gh-aw/actions/setup@e211c855a20aa6cf9297b411466e1c382a8686db # v0.55.0\n        with:\n          destination: /opt/gh-aw/actions\n      - name: Checkout repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n      - name: Create gh-aw temp directory\n        run: bash /opt/gh-aw/actions/create_gh_aw_tmp_dir.sh\n      - name: Configure Git credentials\n        env:\n          REPO_NAME: ${{ github.repository }}\n          SERVER_URL: ${{ github.server_url }}\n        run: |\n          git config --global user.email \"github-actions[bot]@users.noreply.github.com\"\n          git config --global user.name \"github-actions[bot]\"\n          git config --global am.keepcr true\n          # Re-authenticate git with GitHub token\n          SERVER_URL_STRIPPED=\"${SERVER_URL#https://}\"\n          git remote set-url origin \"https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git\"\n          echo \"Git configured with standard GitHub Actions identity\"\n      - name: Checkout PR branch\n        id: checkout-pr\n        if: |\n          (github.event.pull_request) || (github.event.issue.pull_request)\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n        with:\n          github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/checkout_pr_branch.cjs');\n            await main();\n      - name: Install GitHub Copilot CLI\n        run: /opt/gh-aw/actions/install_copilot_cli.sh latest\n      - name: Install awf binary\n        run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.23.0\n      - name: Determine automatic lockdown mode for GitHub MCP Server\n        id: determine-automatic-lockdown\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}\n          GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}\n        with:\n          script: |\n            const determineAutomaticLockdown = require('/opt/gh-aw/actions/determine_automatic_lockdown.cjs');\n            await determineAutomaticLockdown(github, context, core);\n      - name: Download container images\n        run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.8 ghcr.io/github/github-mcp-server:v0.31.0 ghcr.io/github/serena-mcp-server:latest node:lts-alpine\n      - name: Write Safe Outputs Config\n        run: |\n          mkdir -p /opt/gh-aw/safeoutputs\n          mkdir -p /tmp/gh-aw/safeoutputs\n          mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs\n          cat > /opt/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF'\n          {\"create_issue\":{\"max\":1},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1}}\n          GH_AW_SAFE_OUTPUTS_CONFIG_EOF\n          cat > /opt/gh-aw/safeoutputs/tools.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_EOF'\n          [\n            {\n              \"description\": \"Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 1 issue(s) can be created. Assignees [\\\"copilot\\\"] will be automatically assigned.\",\n              \"inputSchema\": {\n                \"additionalProperties\": false,\n                \"properties\": {\n                  \"body\": {\n                    \"description\": \"Detailed issue description in Markdown. Do NOT repeat the title as a heading since it already appears as the issue's h1. Include context, reproduction steps, or acceptance criteria as appropriate.\",\n                    \"type\": \"string\"\n                  },\n                  \"integrity\": {\n                    \"description\": \"Trustworthiness level of the message source (e.g., \\\"low\\\", \\\"medium\\\", \\\"high\\\").\",\n                    \"type\": \"string\"\n                  },\n                  \"labels\": {\n                    \"description\": \"Labels to categorize the issue (e.g., 'bug', 'enhancement'). Labels must exist in the repository.\",\n                    \"items\": {\n                      \"type\": \"string\"\n                    },\n                    \"type\": \"array\"\n                  },\n                  \"parent\": {\n                    \"description\": \"Parent issue number for creating sub-issues. This is the numeric ID from the GitHub URL (e.g., 42 in github.com/owner/repo/issues/42). Can also be a temporary_id (e.g., 'aw_abc123', 'aw_Test123') from a previously created issue in the same workflow run.\",\n                    \"type\": [\n                      \"number\",\n                      \"string\"\n                    ]\n                  },\n                  \"secrecy\": {\n                    \"description\": \"Confidentiality level of the message content (e.g., \\\"public\\\", \\\"internal\\\", \\\"private\\\").\",\n                    \"type\": \"string\"\n                  },\n                  \"temporary_id\": {\n                    \"description\": \"Unique temporary identifier for referencing this issue before it's created. Format: 'aw_' followed by 3 to 12 alphanumeric characters (e.g., 'aw_abc1', 'aw_Test123'). Use '#aw_ID' in body text to reference other issues by their temporary_id; these are replaced with actual issue numbers after creation.\",\n                    \"pattern\": \"^aw_[A-Za-z0-9]{3,12}$\",\n                    \"type\": \"string\"\n                  },\n                  \"title\": {\n                    \"description\": \"Concise issue title summarizing the bug, feature, or task. The title appears as the main heading, so keep it brief and descriptive.\",\n                    \"type\": \"string\"\n                  }\n                },\n                \"required\": [\n                  \"title\",\n                  \"body\"\n                ],\n                \"type\": \"object\"\n              },\n              \"name\": \"create_issue\"\n            },\n            {\n              \"description\": \"Report that a tool or capability needed to complete the task is not available, or share any information you deem important about missing functionality or limitations. Use this when you cannot accomplish what was requested because the required functionality is missing or access is restricted.\",\n              \"inputSchema\": {\n                \"additionalProperties\": false,\n                \"properties\": {\n                  \"alternatives\": {\n                    \"description\": \"Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).\",\n                    \"type\": \"string\"\n                  },\n                  \"integrity\": {\n                    \"description\": \"Trustworthiness level of the message source (e.g., \\\"low\\\", \\\"medium\\\", \\\"high\\\").\",\n                    \"type\": \"string\"\n                  },\n                  \"reason\": {\n                    \"description\": \"Explanation of why this tool is needed or what information you want to share about the limitation (max 256 characters).\",\n                    \"type\": \"string\"\n                  },\n                  \"secrecy\": {\n                    \"description\": \"Confidentiality level of the message content (e.g., \\\"public\\\", \\\"internal\\\", \\\"private\\\").\",\n                    \"type\": \"string\"\n                  },\n                  \"tool\": {\n                    \"description\": \"Optional: Name or description of the missing tool or capability (max 128 characters). Be specific about what functionality is needed.\",\n                    \"type\": \"string\"\n                  }\n                },\n                \"required\": [\n                  \"reason\"\n                ],\n                \"type\": \"object\"\n              },\n              \"name\": \"missing_tool\"\n            },\n            {\n              \"description\": \"Log a transparency message when no significant actions are needed. Use this to confirm workflow completion and provide visibility when analysis is complete but no changes or outputs are required (e.g., 'No issues found', 'All checks passed'). This ensures the workflow produces human-visible output even when no other actions are taken.\",\n              \"inputSchema\": {\n                \"additionalProperties\": false,\n                \"properties\": {\n                  \"integrity\": {\n                    \"description\": \"Trustworthiness level of the message source (e.g., \\\"low\\\", \\\"medium\\\", \\\"high\\\").\",\n                    \"type\": \"string\"\n                  },\n                  \"message\": {\n                    \"description\": \"Status or completion message to log. Should explain what was analyzed and the outcome (e.g., 'Code review complete - no issues found', 'Analysis complete - all tests passing').\",\n                    \"type\": \"string\"\n                  },\n                  \"secrecy\": {\n                    \"description\": \"Confidentiality level of the message content (e.g., \\\"public\\\", \\\"internal\\\", \\\"private\\\").\",\n                    \"type\": \"string\"\n                  }\n                },\n                \"required\": [\n                  \"message\"\n                ],\n                \"type\": \"object\"\n              },\n              \"name\": \"noop\"\n            },\n            {\n              \"description\": \"Report that data or information needed to complete the task is not available. Use this when you cannot accomplish what was requested because required data, context, or information is missing.\",\n              \"inputSchema\": {\n                \"additionalProperties\": false,\n                \"properties\": {\n                  \"alternatives\": {\n                    \"description\": \"Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).\",\n                    \"type\": \"string\"\n                  },\n                  \"context\": {\n                    \"description\": \"Additional context about the missing data or where it should come from (max 256 characters).\",\n                    \"type\": \"string\"\n                  },\n                  \"data_type\": {\n                    \"description\": \"Type or description of the missing data or information (max 128 characters). Be specific about what data is needed.\",\n                    \"type\": \"string\"\n                  },\n                  \"integrity\": {\n                    \"description\": \"Trustworthiness level of the message source (e.g., \\\"low\\\", \\\"medium\\\", \\\"high\\\").\",\n                    \"type\": \"string\"\n                  },\n                  \"reason\": {\n                    \"description\": \"Explanation of why this data is needed to complete the task (max 256 characters).\",\n                    \"type\": \"string\"\n                  },\n                  \"secrecy\": {\n                    \"description\": \"Confidentiality level of the message content (e.g., \\\"public\\\", \\\"internal\\\", \\\"private\\\").\",\n                    \"type\": \"string\"\n                  }\n                },\n                \"required\": [],\n                \"type\": \"object\"\n              },\n              \"name\": \"missing_data\"\n            }\n          ]\n          GH_AW_SAFE_OUTPUTS_TOOLS_EOF\n          cat > /opt/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_EOF'\n          {\n            \"create_issue\": {\n              \"defaultMax\": 1,\n              \"fields\": {\n                \"body\": {\n                  \"required\": true,\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 65000\n                },\n                \"labels\": {\n                  \"type\": \"array\",\n                  \"itemType\": \"string\",\n                  \"itemSanitize\": true,\n                  \"itemMaxLength\": 128\n                },\n                \"parent\": {\n                  \"issueOrPRNumber\": true\n                },\n                \"repo\": {\n                  \"type\": \"string\",\n                  \"maxLength\": 256\n                },\n                \"temporary_id\": {\n                  \"type\": \"string\"\n                },\n                \"title\": {\n                  \"required\": true,\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 128\n                }\n              }\n            },\n            \"missing_data\": {\n              \"defaultMax\": 20,\n              \"fields\": {\n                \"alternatives\": {\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 256\n                },\n                \"context\": {\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 256\n                },\n                \"data_type\": {\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 128\n                },\n                \"reason\": {\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 256\n                }\n              }\n            },\n            \"missing_tool\": {\n              \"defaultMax\": 20,\n              \"fields\": {\n                \"alternatives\": {\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 512\n                },\n                \"reason\": {\n                  \"required\": true,\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 256\n                },\n                \"tool\": {\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 128\n                }\n              }\n            },\n            \"noop\": {\n              \"defaultMax\": 1,\n              \"fields\": {\n                \"message\": {\n                  \"required\": true,\n                  \"type\": \"string\",\n                  \"sanitize\": true,\n                  \"maxLength\": 65000\n                }\n              }\n            }\n          }\n          GH_AW_SAFE_OUTPUTS_VALIDATION_EOF\n      - name: Generate Safe Outputs MCP Server Config\n        id: safe-outputs-config\n        run: |\n          # Generate a secure random API key (360 bits of entropy, 40+ chars)\n          # Mask immediately to prevent timing vulnerabilities\n          API_KEY=$(openssl rand -base64 45 | tr -d '/+=')\n          echo \"::add-mask::${API_KEY}\"\n          \n          PORT=3001\n          \n          # Set outputs for next steps\n          {\n            echo \"safe_outputs_api_key=${API_KEY}\"\n            echo \"safe_outputs_port=${PORT}\"\n          } >> \"$GITHUB_OUTPUT\"\n          \n          echo \"Safe Outputs MCP server will run on port ${PORT}\"\n          \n      - name: Start Safe Outputs MCP HTTP Server\n        id: safe-outputs-start\n        env:\n          DEBUG: '*'\n          GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }}\n          GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }}\n          GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json\n          GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json\n          GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs\n        run: |\n          # Environment variables are set above to prevent template injection\n          export DEBUG\n          export GH_AW_SAFE_OUTPUTS_PORT\n          export GH_AW_SAFE_OUTPUTS_API_KEY\n          export GH_AW_SAFE_OUTPUTS_TOOLS_PATH\n          export GH_AW_SAFE_OUTPUTS_CONFIG_PATH\n          export GH_AW_MCP_LOG_DIR\n          \n          bash /opt/gh-aw/actions/start_safe_outputs_server.sh\n          \n      - name: Start MCP Gateway\n        id: start-mcp-gateway\n        env:\n          GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}\n          GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }}\n          GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }}\n          GITHUB_MCP_LOCKDOWN: ${{ steps.determine-automatic-lockdown.outputs.lockdown == 'true' && '1' || '0' }}\n          GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n        run: |\n          set -eo pipefail\n          mkdir -p /tmp/gh-aw/mcp-config\n          \n          # Export gateway environment variables for MCP config and gateway script\n          export MCP_GATEWAY_PORT=\"80\"\n          export MCP_GATEWAY_DOMAIN=\"host.docker.internal\"\n          MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=')\n          echo \"::add-mask::${MCP_GATEWAY_API_KEY}\"\n          export MCP_GATEWAY_API_KEY\n          export MCP_GATEWAY_PAYLOAD_DIR=\"/tmp/gh-aw/mcp-payloads\"\n          mkdir -p \"${MCP_GATEWAY_PAYLOAD_DIR}\"\n          export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD=\"524288\"\n          export DEBUG=\"*\"\n          \n          export GH_AW_ENGINE=\"copilot\"\n          export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_LOCKDOWN -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '\"${GITHUB_WORKSPACE}\"':'\"${GITHUB_WORKSPACE}\"':rw ghcr.io/github/gh-aw-mcpg:v0.1.8'\n          \n          mkdir -p /home/runner/.copilot\n          cat << GH_AW_MCP_CONFIG_EOF | bash /opt/gh-aw/actions/start_mcp_gateway.sh\n          {\n            \"mcpServers\": {\n              \"github\": {\n                \"type\": \"stdio\",\n                \"container\": \"ghcr.io/github/github-mcp-server:v0.31.0\",\n                \"env\": {\n                  \"GITHUB_LOCKDOWN_MODE\": \"$GITHUB_MCP_LOCKDOWN\",\n                  \"GITHUB_PERSONAL_ACCESS_TOKEN\": \"\\${GITHUB_MCP_SERVER_TOKEN}\",\n                  \"GITHUB_READ_ONLY\": \"1\",\n                  \"GITHUB_TOOLSETS\": \"context,repos,issues,pull_requests\"\n                }\n              },\n              \"safeoutputs\": {\n                \"type\": \"http\",\n                \"url\": \"http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT\",\n                \"headers\": {\n                  \"Authorization\": \"\\${GH_AW_SAFE_OUTPUTS_API_KEY}\"\n                }\n              },\n              \"serena\": {\n                \"type\": \"stdio\",\n                \"container\": \"ghcr.io/github/serena-mcp-server:latest\",\n                \"args\": [\"--network\", \"host\"],\n                \"entrypoint\": \"serena\",\n                \"entrypointArgs\": [\"start-mcp-server\", \"--context\", \"codex\", \"--project\", \"\\${GITHUB_WORKSPACE}\"],\n                \"mounts\": [\"\\${GITHUB_WORKSPACE}:\\${GITHUB_WORKSPACE}:rw\"]\n              }\n            },\n            \"gateway\": {\n              \"port\": $MCP_GATEWAY_PORT,\n              \"domain\": \"${MCP_GATEWAY_DOMAIN}\",\n              \"apiKey\": \"${MCP_GATEWAY_API_KEY}\",\n              \"payloadDir\": \"${MCP_GATEWAY_PAYLOAD_DIR}\"\n            }\n          }\n          GH_AW_MCP_CONFIG_EOF\n      - name: Download activation artifact\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8\n        with:\n          name: activation\n          path: /tmp/gh-aw\n      - name: Clean git credentials\n        run: bash /opt/gh-aw/actions/clean_git_credentials.sh\n      - name: Execute GitHub Copilot CLI\n        id: agentic_execution\n        # Copilot CLI tool arguments (sorted):\n        timeout-minutes: 15\n        run: |\n          set -o pipefail\n          touch /tmp/gh-aw/agent-step-summary.md\n          # shellcheck disable=SC1003\n          sudo -E awf --env-all --container-workdir \"${GITHUB_WORKSPACE}\" --allow-domains \"api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com\" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \\\n            -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir \"${GITHUB_WORKSPACE}\" --disable-builtin-mcps --allow-all-tools --allow-all-paths --prompt \"$(cat /tmp/gh-aw/aw-prompts/prompt.txt)\"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log\n        env:\n          COPILOT_AGENT_RUNNER_TYPE: STANDALONE\n          COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}\n          COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }}\n          GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n          GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}\n          GITHUB_API_URL: ${{ github.api_url }}\n          GITHUB_HEAD_REF: ${{ github.head_ref }}\n          GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          GITHUB_REF_NAME: ${{ github.ref_name }}\n          GITHUB_SERVER_URL: ${{ github.server_url }}\n          GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md\n          GITHUB_WORKSPACE: ${{ github.workspace }}\n          XDG_CONFIG_HOME: /home/runner\n      - name: Detect inference access error\n        id: detect-inference-error\n        if: always()\n        continue-on-error: true\n        run: bash /opt/gh-aw/actions/detect_inference_access_error.sh\n      - name: Configure Git credentials\n        env:\n          REPO_NAME: ${{ github.repository }}\n          SERVER_URL: ${{ github.server_url }}\n        run: |\n          git config --global user.email \"github-actions[bot]@users.noreply.github.com\"\n          git config --global user.name \"github-actions[bot]\"\n          git config --global am.keepcr true\n          # Re-authenticate git with GitHub token\n          SERVER_URL_STRIPPED=\"${SERVER_URL#https://}\"\n          git remote set-url origin \"https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git\"\n          echo \"Git configured with standard GitHub Actions identity\"\n      - name: Copy Copilot session state files to logs\n        if: always()\n        continue-on-error: true\n        run: |\n          # Copy Copilot session state files to logs folder for artifact collection\n          # This ensures they are in /tmp/gh-aw/ where secret redaction can scan them\n          SESSION_STATE_DIR=\"$HOME/.copilot/session-state\"\n          LOGS_DIR=\"/tmp/gh-aw/sandbox/agent/logs\"\n          \n          if [ -d \"$SESSION_STATE_DIR\" ]; then\n            echo \"Copying Copilot session state files from $SESSION_STATE_DIR to $LOGS_DIR\"\n            mkdir -p \"$LOGS_DIR\"\n            cp -v \"$SESSION_STATE_DIR\"/*.jsonl \"$LOGS_DIR/\" 2>/dev/null || true\n            echo \"Session state files copied successfully\"\n          else\n            echo \"No session-state directory found at $SESSION_STATE_DIR\"\n          fi\n      - name: Stop MCP Gateway\n        if: always()\n        continue-on-error: true\n        env:\n          MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }}\n          MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }}\n          GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }}\n        run: |\n          bash /opt/gh-aw/actions/stop_mcp_gateway.sh \"$GATEWAY_PID\"\n      - name: Redact secrets in logs\n        if: always()\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        with:\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/redact_secrets.cjs');\n            await main();\n        env:\n          GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN'\n          SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}\n          SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}\n          SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}\n          SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      - name: Append agent step summary\n        if: always()\n        run: bash /opt/gh-aw/actions/append_agent_step_summary.sh\n      - name: Upload Safe Outputs\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7\n        with:\n          name: safe-output\n          path: ${{ env.GH_AW_SAFE_OUTPUTS }}\n          if-no-files-found: warn\n      - name: Ingest agent output\n        id: collect_output\n        if: always()\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}\n          GH_AW_ALLOWED_DOMAINS: \"api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com\"\n          GITHUB_SERVER_URL: ${{ github.server_url }}\n          GITHUB_API_URL: ${{ github.api_url }}\n        with:\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/collect_ndjson_output.cjs');\n            await main();\n      - name: Upload sanitized agent output\n        if: always() && env.GH_AW_AGENT_OUTPUT\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7\n        with:\n          name: agent-output\n          path: ${{ env.GH_AW_AGENT_OUTPUT }}\n          if-no-files-found: warn\n      - name: Upload engine output files\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7\n        with:\n          name: agent_outputs\n          path: |\n            /tmp/gh-aw/sandbox/agent/logs/\n            /tmp/gh-aw/redacted-urls.log\n          if-no-files-found: ignore\n      - name: Parse agent logs for step summary\n        if: always()\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/\n        with:\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/parse_copilot_log.cjs');\n            await main();\n      - name: Parse MCP Gateway logs for step summary\n        if: always()\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        with:\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/parse_mcp_gateway_log.cjs');\n            await main();\n      - name: Print firewall logs\n        if: always()\n        continue-on-error: true\n        env:\n          AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs\n        run: |\n          # Fix permissions on firewall logs so they can be uploaded as artifacts\n          # AWF runs with sudo, creating files owned by root\n          sudo chmod -R a+r /tmp/gh-aw/sandbox/firewall/logs 2>/dev/null || true\n          # Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step)\n          if command -v awf &> /dev/null; then\n            awf logs summary | tee -a \"$GITHUB_STEP_SUMMARY\"\n          else\n            echo 'AWF binary not installed, skipping firewall log summary'\n          fi\n      - name: Upload agent artifacts\n        if: always()\n        continue-on-error: true\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7\n        with:\n          name: agent-artifacts\n          path: |\n            /tmp/gh-aw/aw-prompts/prompt.txt\n            /tmp/gh-aw/mcp-logs/\n            /tmp/gh-aw/sandbox/firewall/logs/\n            /tmp/gh-aw/agent-stdio.log\n            /tmp/gh-aw/agent/\n          if-no-files-found: ignore\n      # --- Threat Detection (inline) ---\n      - name: Check if detection needed\n        id: detection_guard\n        if: always()\n        env:\n          OUTPUT_TYPES: ${{ steps.collect_output.outputs.output_types }}\n          HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }}\n        run: |\n          if [[ -n \"$OUTPUT_TYPES\" || \"$HAS_PATCH\" == \"true\" ]]; then\n            echo \"run_detection=true\" >> \"$GITHUB_OUTPUT\"\n            echo \"Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH\"\n          else\n            echo \"run_detection=false\" >> \"$GITHUB_OUTPUT\"\n            echo \"Detection skipped: no agent outputs or patches to analyze\"\n          fi\n      - name: Clear MCP configuration for detection\n        if: always() && steps.detection_guard.outputs.run_detection == 'true'\n        run: |\n          rm -f /tmp/gh-aw/mcp-config/mcp-servers.json\n          rm -f /home/runner/.copilot/mcp-config.json\n          rm -f \"$GITHUB_WORKSPACE/.gemini/settings.json\"\n      - name: Prepare threat detection files\n        if: always() && steps.detection_guard.outputs.run_detection == 'true'\n        run: |\n          mkdir -p /tmp/gh-aw/threat-detection/aw-prompts\n          cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true\n          cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true\n          for f in /tmp/gh-aw/aw-*.patch; do\n            [ -f \"$f\" ] && cp \"$f\" /tmp/gh-aw/threat-detection/ 2>/dev/null || true\n          done\n          echo \"Prepared threat detection files:\"\n          ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true\n      - name: Setup threat detection\n        if: always() && steps.detection_guard.outputs.run_detection == 'true'\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          WORKFLOW_NAME: \"Duplicate Code Detector\"\n          WORKFLOW_DESCRIPTION: \"Identifies duplicate code patterns across the codebase and suggests refactoring opportunities\"\n          HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }}\n        with:\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/setup_threat_detection.cjs');\n            await main();\n      - name: Ensure threat-detection directory and log\n        if: always() && steps.detection_guard.outputs.run_detection == 'true'\n        run: |\n          mkdir -p /tmp/gh-aw/threat-detection\n          touch /tmp/gh-aw/threat-detection/detection.log\n      - name: Execute GitHub Copilot CLI\n        if: always() && steps.detection_guard.outputs.run_detection == 'true'\n        id: detection_agentic_execution\n        # Copilot CLI tool arguments (sorted):\n        # --allow-tool shell(cat)\n        # --allow-tool shell(grep)\n        # --allow-tool shell(head)\n        # --allow-tool shell(jq)\n        # --allow-tool shell(ls)\n        # --allow-tool shell(tail)\n        # --allow-tool shell(wc)\n        timeout-minutes: 20\n        run: |\n          set -o pipefail\n          touch /tmp/gh-aw/agent-step-summary.md\n          # shellcheck disable=SC1003\n          sudo -E awf --env-all --container-workdir \"${GITHUB_WORKSPACE}\" --allow-domains \"api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,raw.githubusercontent.com,registry.npmjs.org,telemetry.enterprise.githubcopilot.com\" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \\\n            -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir \"${GITHUB_WORKSPACE}\" --disable-builtin-mcps --allow-tool '\\''shell(cat)'\\'' --allow-tool '\\''shell(grep)'\\'' --allow-tool '\\''shell(head)'\\'' --allow-tool '\\''shell(jq)'\\'' --allow-tool '\\''shell(ls)'\\'' --allow-tool '\\''shell(tail)'\\'' --allow-tool '\\''shell(wc)'\\'' --prompt \"$(cat /tmp/gh-aw/aw-prompts/prompt.txt)\"' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log\n        env:\n          COPILOT_AGENT_RUNNER_TYPE: STANDALONE\n          COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}\n          COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }}\n          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt\n          GITHUB_API_URL: ${{ github.api_url }}\n          GITHUB_HEAD_REF: ${{ github.head_ref }}\n          GITHUB_REF_NAME: ${{ github.ref_name }}\n          GITHUB_SERVER_URL: ${{ github.server_url }}\n          GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md\n          GITHUB_WORKSPACE: ${{ github.workspace }}\n          XDG_CONFIG_HOME: /home/runner\n      - name: Parse threat detection results\n        id: parse_detection_results\n        if: always() && steps.detection_guard.outputs.run_detection == 'true'\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        with:\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/parse_threat_detection_results.cjs');\n            await main();\n      - name: Upload threat detection log\n        if: always() && steps.detection_guard.outputs.run_detection == 'true'\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7\n        with:\n          name: threat-detection.log\n          path: /tmp/gh-aw/threat-detection/detection.log\n          if-no-files-found: ignore\n      - name: Set detection conclusion\n        id: detection_conclusion\n        if: always()\n        env:\n          RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }}\n          DETECTION_SUCCESS: ${{ steps.parse_detection_results.outputs.success }}\n        run: |\n          if [[ \"$RUN_DETECTION\" != \"true\" ]]; then\n            echo \"conclusion=skipped\" >> \"$GITHUB_OUTPUT\"\n            echo \"success=true\" >> \"$GITHUB_OUTPUT\"\n            echo \"Detection was not needed, marking as skipped\"\n          elif [[ \"$DETECTION_SUCCESS\" == \"true\" ]]; then\n            echo \"conclusion=success\" >> \"$GITHUB_OUTPUT\"\n            echo \"success=true\" >> \"$GITHUB_OUTPUT\"\n            echo \"Detection passed successfully\"\n          else\n            echo \"conclusion=failure\" >> \"$GITHUB_OUTPUT\"\n            echo \"success=false\" >> \"$GITHUB_OUTPUT\"\n            echo \"Detection found issues\"\n          fi\n\n  conclusion:\n    needs:\n      - activation\n      - agent\n      - safe_outputs\n    if: (always()) && (needs.agent.result != 'skipped')\n    runs-on: ubuntu-slim\n    permissions:\n      contents: read\n      issues: write\n    concurrency:\n      group: \"gh-aw-conclusion-duplicate-code-detector\"\n      cancel-in-progress: false\n    outputs:\n      noop_message: ${{ steps.noop.outputs.noop_message }}\n      tools_reported: ${{ steps.missing_tool.outputs.tools_reported }}\n      total_count: ${{ steps.missing_tool.outputs.total_count }}\n    steps:\n      - name: Setup Scripts\n        uses: github/gh-aw/actions/setup@e211c855a20aa6cf9297b411466e1c382a8686db # v0.55.0\n        with:\n          destination: /opt/gh-aw/actions\n      - name: Download agent output artifact\n        id: download-agent-output\n        continue-on-error: true\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8\n        with:\n          name: agent-output\n          path: /tmp/gh-aw/safeoutputs/\n      - name: Setup agent output environment variable\n        if: steps.download-agent-output.outcome == 'success'\n        run: |\n          mkdir -p /tmp/gh-aw/safeoutputs/\n          find \"/tmp/gh-aw/safeoutputs/\" -type f -print\n          echo \"GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json\" >> \"$GITHUB_ENV\"\n      - name: Process No-Op Messages\n        id: noop\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}\n          GH_AW_NOOP_MAX: \"1\"\n          GH_AW_WORKFLOW_NAME: \"Duplicate Code Detector\"\n          GH_AW_WORKFLOW_SOURCE: \"github/gh-aw/.github/workflows/duplicate-code-detector.md@852cb06ad52958b402ed982b69957ffc57ca0619\"\n          GH_AW_WORKFLOW_SOURCE_URL: \"${{ github.server_url }}/github/gh-aw/tree/852cb06ad52958b402ed982b69957ffc57ca0619/.github/workflows/duplicate-code-detector.md\"\n        with:\n          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/noop.cjs');\n            await main();\n      - name: Record Missing Tool\n        id: missing_tool\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}\n          GH_AW_WORKFLOW_NAME: \"Duplicate Code Detector\"\n          GH_AW_WORKFLOW_SOURCE: \"github/gh-aw/.github/workflows/duplicate-code-detector.md@852cb06ad52958b402ed982b69957ffc57ca0619\"\n          GH_AW_WORKFLOW_SOURCE_URL: \"${{ github.server_url }}/github/gh-aw/tree/852cb06ad52958b402ed982b69957ffc57ca0619/.github/workflows/duplicate-code-detector.md\"\n        with:\n          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/missing_tool.cjs');\n            await main();\n      - name: Handle Agent Failure\n        id: handle_agent_failure\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}\n          GH_AW_WORKFLOW_NAME: \"Duplicate Code Detector\"\n          GH_AW_WORKFLOW_SOURCE: \"github/gh-aw/.github/workflows/duplicate-code-detector.md@852cb06ad52958b402ed982b69957ffc57ca0619\"\n          GH_AW_WORKFLOW_SOURCE_URL: \"${{ github.server_url }}/github/gh-aw/tree/852cb06ad52958b402ed982b69957ffc57ca0619/.github/workflows/duplicate-code-detector.md\"\n          GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n          GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}\n          GH_AW_WORKFLOW_ID: \"duplicate-code-detector\"\n          GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }}\n          GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }}\n          GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }}\n          GH_AW_GROUP_REPORTS: \"false\"\n          GH_AW_TIMEOUT_MINUTES: \"15\"\n        with:\n          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/handle_agent_failure.cjs');\n            await main();\n      - name: Handle No-Op Message\n        id: handle_noop_message\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}\n          GH_AW_WORKFLOW_NAME: \"Duplicate Code Detector\"\n          GH_AW_WORKFLOW_SOURCE: \"github/gh-aw/.github/workflows/duplicate-code-detector.md@852cb06ad52958b402ed982b69957ffc57ca0619\"\n          GH_AW_WORKFLOW_SOURCE_URL: \"${{ github.server_url }}/github/gh-aw/tree/852cb06ad52958b402ed982b69957ffc57ca0619/.github/workflows/duplicate-code-detector.md\"\n          GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n          GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}\n          GH_AW_NOOP_MESSAGE: ${{ steps.noop.outputs.noop_message }}\n          GH_AW_NOOP_REPORT_AS_ISSUE: \"true\"\n        with:\n          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/handle_noop_message.cjs');\n            await main();\n\n  safe_outputs:\n    needs: agent\n    if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.agent.outputs.detection_success == 'true')\n    runs-on: ubuntu-slim\n    permissions:\n      contents: read\n      issues: write\n    timeout-minutes: 15\n    env:\n      GH_AW_CALLER_WORKFLOW_ID: \"${{ github.repository }}/duplicate-code-detector\"\n      GH_AW_ENGINE_ID: \"copilot\"\n      GH_AW_WORKFLOW_ID: \"duplicate-code-detector\"\n      GH_AW_WORKFLOW_NAME: \"Duplicate Code Detector\"\n      GH_AW_WORKFLOW_SOURCE: \"github/gh-aw/.github/workflows/duplicate-code-detector.md@852cb06ad52958b402ed982b69957ffc57ca0619\"\n      GH_AW_WORKFLOW_SOURCE_URL: \"${{ github.server_url }}/github/gh-aw/tree/852cb06ad52958b402ed982b69957ffc57ca0619/.github/workflows/duplicate-code-detector.md\"\n    outputs:\n      code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }}\n      code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }}\n      create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }}\n      create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }}\n      created_issue_number: ${{ steps.process_safe_outputs.outputs.created_issue_number }}\n      created_issue_url: ${{ steps.process_safe_outputs.outputs.created_issue_url }}\n      process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }}\n      process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }}\n    steps:\n      - name: Setup Scripts\n        uses: github/gh-aw/actions/setup@e211c855a20aa6cf9297b411466e1c382a8686db # v0.55.0\n        with:\n          destination: /opt/gh-aw/actions\n      - name: Download agent output artifact\n        id: download-agent-output\n        continue-on-error: true\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8\n        with:\n          name: agent-output\n          path: /tmp/gh-aw/safeoutputs/\n      - name: Setup agent output environment variable\n        if: steps.download-agent-output.outcome == 'success'\n        run: |\n          mkdir -p /tmp/gh-aw/safeoutputs/\n          find \"/tmp/gh-aw/safeoutputs/\" -type f -print\n          echo \"GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json\" >> \"$GITHUB_ENV\"\n      - name: Process Safe Outputs\n        id: process_safe_outputs\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}\n          GH_AW_ALLOWED_DOMAINS: \"api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com\"\n          GITHUB_SERVER_URL: ${{ github.server_url }}\n          GITHUB_API_URL: ${{ github.api_url }}\n          GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: \"{\\\"create_issue\\\":{\\\"assignees\\\":[\\\"copilot\\\"],\\\"max\\\":1},\\\"missing_data\\\":{},\\\"missing_tool\\\":{}}\"\n          GH_AW_ASSIGN_COPILOT: \"true\"\n        with:\n          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/safe_output_handler_manager.cjs');\n            await main();\n      - name: Assign Copilot to created issues\n        if: steps.process_safe_outputs.outputs.issues_to_assign_copilot != ''\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        env:\n          GH_AW_ISSUES_TO_ASSIGN_COPILOT: ${{ steps.process_safe_outputs.outputs.issues_to_assign_copilot }}\n        with:\n          github-token: ${{ secrets.GH_AW_AGENT_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}\n          script: |\n            const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');\n            setupGlobals(core, github, context, exec, io);\n            const { main } = require('/opt/gh-aw/actions/assign_copilot_to_created_issues.cjs');\n            await main();\n      - name: Upload safe output items manifest\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7\n        with:\n          name: safe-output-items\n          path: /tmp/safe-output-items.jsonl\n          if-no-files-found: warn\n\n"
  },
  {
    "path": ".github/workflows/duplicate-code-detector.md",
    "content": "---\nname: Duplicate Code Detector\ndescription: Identifies duplicate code patterns across the codebase and suggests refactoring opportunities\non:\n  workflow_dispatch:\n  schedule: daily\npermissions:\n  contents: read\n  issues: read\n  pull-requests: read\nengine: copilot\ntools:\n  serena: ['typescript']\nsafe-outputs:\n  create-issue:\n    expires: 2d\n    title-prefix: '[duplicate-code] '\n    labels: [code-quality, automated-analysis, cookie]\n    assignees: copilot\n    group: true\n    max: 3\ntimeout-minutes: 15\nstrict: true\nimports:\n  - shared/mood.md\nsource: github/gh-aw/.github/workflows/duplicate-code-detector.md@852cb06ad52958b402ed982b69957ffc57ca0619\n---\n\n# Duplicate Code Detection\n\nAnalyze code to identify duplicated patterns using Serena's semantic code analysis capabilities. Report significant findings that require refactoring.\n\n## Task\n\nDetect and report code duplication by:\n\n1. **Analyzing Recent Commits**: Review changes in the latest commits\n2. **Detecting Duplicated Code**: Identify similar or duplicated code patterns using semantic analysis\n3. **Reporting Findings**: Create a detailed issue if significant duplication is detected (threshold: >10 lines or 3+ similar patterns)\n\n## Context\n\n- **Repository**: ${{ github.repository }}\n- **Commit ID**: ${{ github.event.head_commit.id }}\n- **Triggered by**: @${{ github.actor }}\n\n## Analysis Workflow\n\n### 1. Project Activation\n\nActivate the project in Serena:\n\n- Use `activate_project` tool with workspace path `${{ github.workspace }}` (mounted repository directory)\n- This sets up the semantic code analysis environment\n\n### 2. Changed Files Analysis\n\nIdentify and analyze modified files:\n\n- Determine files changed in the recent commits\n- **ONLY analyze .ts and .tsx files** - exclude all other file types\n- **Exclude JavaScript files except .cjs** from analysis (files matching patterns: `*.js`, `*.mjs`, `*.jsx`, `*.ts`, `*.tsx`)\n- **Exclude test files** from analysis (files matching patterns: `*.test.<ts|tsx>`, `*.spec.<ts|tsx>`, or located in directories named `test`, `tests`, `__tests__`, or `spec`)\n- **Exclude workflow files** from analysis (files under `.github/workflows/*`)\n- Use `get_symbols_overview` to understand file structure\n- Use `read_file` to examine modified file contents\n\n### 3. Duplicate Detection\n\nApply semantic code analysis to find duplicates:\n\n**Symbol-Level Analysis**:\n\n- For significant functions/methods in changed files, use `find_symbol` to search for similarly named symbols\n- Use `find_referencing_symbols` to understand usage patterns\n- Identify functions with similar names in different files (e.g., `processData` across modules)\n\n**Pattern Search**:\n\n- Use `search_for_pattern` to find similar code patterns\n- Search for duplication indicators:\n  - Similar function signatures\n  - Repeated logic blocks\n  - Similar variable naming patterns\n  - Near-identical code blocks\n\n**Structural Analysis**:\n\n- Use `list_dir` and `find_file` to identify files with similar names or purposes\n- Compare symbol overviews across files for structural similarities\n\n### 4. Duplication Evaluation\n\nAssess findings to identify true code duplication:\n\n**Duplication Types**:\n\n- **Exact Duplication**: Identical code blocks in multiple locations\n- **Structural Duplication**: Same logic with minor variations (different variable names, etc.)\n- **Functional Duplication**: Different implementations of the same functionality\n- **Copy-Paste Programming**: Similar code blocks that could be extracted into shared utilities\n\n**Assessment Criteria**:\n\n- **Severity**: Amount of duplicated code (lines of code, number of occurrences)\n- **Impact**: Where duplication occurs (critical paths, frequently called code)\n- **Maintainability**: How duplication affects code maintainability\n- **Refactoring Opportunity**: Whether duplication can be easily refactored\n\n### 5. Issue Reporting\n\nCreate separate issues for each distinct duplication pattern found (maximum 3 patterns per run). Each pattern should get its own issue to enable focused remediation.\n\n**When to Create Issues**:\n\n- Only create issues if significant duplication is found (threshold: >10 lines of duplicated code OR 3+ instances of similar patterns)\n- **Create one issue per distinct pattern** - do NOT bundle multiple patterns in a single issue\n- Limit to the top 3 most significant patterns if more are found\n- Use the `create_issue` tool from safe-outputs MCP **once for each pattern**\n\n**Issue Contents for Each Pattern**:\n\n- **Executive Summary**: Brief description of this specific duplication pattern\n- **Duplication Details**: Specific locations and code blocks for this pattern only\n- **Severity Assessment**: Impact and maintainability concerns for this pattern\n- **Refactoring Recommendations**: Suggested approaches to eliminate this pattern\n- **Code Examples**: Concrete examples with file paths and line numbers for this pattern\n\n## Detection Scope\n\n### Report These Issues\n\n- Identical or nearly identical functions in different files\n- Repeated code blocks that could be extracted to utilities\n- Similar classes or modules with overlapping functionality\n- Copy-pasted code with minor modifications\n- Duplicated business logic across components\n\n### Skip These Patterns\n\n- Standard boilerplate code (imports, exports, etc.)\n- Test setup/teardown code (acceptable duplication in tests)\n- **All test files** (files matching: `*.test.<ts|tsx>`, `*.spec.<ts|tsx>`, or in `test/`, `tests/`, `__tests__/`, `spec/` directories)\n- **All workflow files** (files under `.github/workflows/*`)\n- Configuration files with similar structure\n- Language-specific patterns (constructors, getters/setters)\n- Small code snippets (<5 lines) unless highly repetitive\n\n### Analysis Depth\n\n- **File Type Restriction**: ONLY analyze .ts and .tsx files - ignore all other file types\n- **Primary Focus**: All .ts and .tsx files changed in the current push (excluding test files and workflow files)\n- **Secondary Analysis**: Check for duplication with existing .ts and .tsx codebase (excluding test files and workflow files)\n- **Cross-Reference**: Look for patterns across .ts and .tsx files in the repository\n- **Historical Context**: Consider if duplication is new or existing\n\n## Issue Template\n\nFor each distinct duplication pattern found, create a separate issue using this structure:\n\n````markdown\n# 🔍 Duplicate Code Detected: [Pattern Name]\n\n_Analysis of commit ${{ github.event.head_commit.id }}_\n\n**Assignee**: @copilot\n\n## Summary\n\n[Brief overview of this specific duplication pattern]\n\n## Duplication Details\n\n### Pattern: [Description]\n\n- **Severity**: High/Medium/Low\n- **Occurrences**: [Number of instances]\n- **Locations**:\n  - `path/to/file1.ext` (lines X-Y)\n  - `path/to/file2.ext` (lines A-B)\n- **Code Sample**:\n  ```[language]\n  [Example of duplicated code]\n  ```\n````\n\n## Impact Analysis\n\n- **Maintainability**: [How this affects code maintenance]\n- **Bug Risk**: [Potential for inconsistent fixes]\n- **Code Bloat**: [Impact on codebase size]\n\n## Refactoring Recommendations\n\n1. **[Recommendation 1]**\n   - Extract common functionality to: `suggested/path/utility.ext`\n   - Estimated effort: [hours/complexity]\n   - Benefits: [specific improvements]\n\n2. **[Recommendation 2]**\n   [... additional recommendations ...]\n\n## Implementation Checklist\n\n- [ ] Review duplication findings\n- [ ] Prioritize refactoring tasks\n- [ ] Create refactoring plan\n- [ ] Implement changes\n- [ ] Update tests\n- [ ] Verify no functionality broken\n\n## Analysis Metadata\n\n- **Analyzed Files**: [count]\n- **Detection Method**: Serena semantic code analysis\n- **Commit**: ${{ github.event.head_commit.id }}\n- **Analysis Date**: [timestamp]\n\n```\n\n## Operational Guidelines\n\n### Security\n- Never execute untrusted code or commands\n- Only use Serena's read-only analysis tools\n- Do not modify files during analysis\n\n### Efficiency\n- Focus on recently changed files first\n- Use semantic analysis for meaningful duplication, not superficial matches\n- Stay within timeout limits (balance thoroughness with execution time)\n\n### Accuracy\n- Verify findings before reporting\n- Distinguish between acceptable patterns and true duplication\n- Consider language-specific idioms and best practices\n- Provide specific, actionable recommendations\n\n### Issue Creation\n- Create **one issue per distinct duplication pattern** - do NOT bundle multiple patterns in a single issue\n- Limit to the top 3 most significant patterns if more are found\n- Only create issues if significant duplication is found\n- Include sufficient detail for SWE agents to understand and act on findings\n- Provide concrete examples with file paths and line numbers\n- Suggest practical refactoring approaches\n- Assign issue to @copilot for automated remediation\n- Use descriptive titles that clearly identify the specific pattern (e.g., \"Duplicate Code: Error Handling Pattern in Parser Module\")\n\n## Tool Usage Sequence\n\n1. **Project Setup**: `activate_project` with repository path\n2. **File Discovery**: `list_dir`, `find_file` for changed files\n3. **Symbol Analysis**: `get_symbols_overview` for structure understanding\n4. **Content Review**: `read_file` for detailed code examination\n5. **Pattern Matching**: `search_for_pattern` for similar code\n6. **Symbol Search**: `find_symbol` for duplicate function names\n7. **Reference Analysis**: `find_referencing_symbols` for usage patterns\n\n**Objective**: Improve code quality by identifying and reporting meaningful code duplication that impacts maintainability. Focus on actionable findings that enable automated or manual refactoring.\n```\n"
  },
  {
    "path": ".github/workflows/fork-checks.yml",
    "content": "name: Fork checks\n\n# This workflow is only for forks, so they can get basic checks in without a CircleCI API key\non:\n  push:\n\nenv:\n  NODE_OPTIONS: '--max_old_space_size=4096'\n\njobs:\n  check:\n    name: Core Type Checking\n    if: github.repository_owner != 'storybookjs'\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 2\n\n      - name: Setup Node.js and Install Dependencies\n        uses: ./.github/actions/setup-node-and-install\n        with:\n          install-code-deps: true\n\n      - name: check\n        run: yarn task --task check\n\n  formatting:\n    name: Core Formatting\n    if: github.repository_owner != 'storybookjs'\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 2\n\n      - name: Setup Node.js and Install Dependencies\n        uses: ./.github/actions/setup-node-and-install\n        with:\n          install-code-deps: true\n\n      - name: oxfmt\n        run: cd code && yarn lint:fmt\n\n  test:\n    strategy:\n      matrix:\n        os: [windows-latest, ubuntu-latest]\n    runs-on: ${{ matrix.os }}\n    name: Core Unit Tests, ${{ matrix.os }}\n    if: github.repository_owner != 'storybookjs'\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 2\n\n      - name: Setup Node.js and Install Dependencies\n        uses: ./.github/actions/setup-node-and-install\n        with:\n          install-code-deps: true\n\n      - name: compile\n        run: yarn task --task compile --start-from=compile\n\n      - name: Install Playwright Dependencies\n        run: cd code && yarn exec playwright install chromium --with-deps\n\n      - name: test\n        run: yarn test\n"
  },
  {
    "path": ".github/workflows/generate-sandboxes.yml",
    "content": "name: Generate and publish sandboxes\n\non:\n  schedule:\n    - cron: '2 2 */1 * *'\n  workflow_dispatch:\n  # To test fixes on push rather than wait for the scheduling, do the following:\n  # 1. Uncomment the lines below and add your branch.\n  # push:\n  #   branches:\n  #     - <your-branch-name>\n  # 2. Change the \"ref\" value to <your-branch-name> in the actions/checkout step below.\n  # 3. Comment out the whole \"generate-main\" job starting at line 77\n  # 4. 👉 DON'T FORGET TO UNDO THE STEPS BEFORE YOU MERGE YOUR CHANGES!\n\nenv:\n  YARN_ENABLE_IMMUTABLE_INSTALLS: 'false'\n  CLEANUP_SANDBOX_NODE_MODULES: 'true'\n  NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}\n\ndefaults:\n  run:\n    working-directory: ./code\n\njobs:\n  generate-next:\n    name: Generate to next\n    if: github.repository_owner == 'storybookjs'\n    runs-on: ubuntu-latest\n    steps:\n      - name: Remove unnecessary files to release disk space\n        working-directory: ${{ github.workspace }}\n        run: |\n          sudo rm -rf \\\n            /opt/ghc \\\n            /opt/google/chrome \\\n            /opt/microsoft/msedge \\\n            /opt/microsoft/powershell \\\n            /usr/lib/mono \\\n            /usr/local/julia* \\\n            /usr/local/lib/android \\\n            /usr/local/share/chromium \\\n            /usr/local/share/powershell \\\n            /usr/local/share/powershell \\\n            /usr/share/dotnet \\\n            /usr/share/swift\n\n      - uses: actions/checkout@v4\n        with:\n          ref: next\n\n      - uses: actions/setup-node@v4\n        with:\n          node-version-file: '.nvmrc'\n\n      - name: Setup git user\n        run: |\n          git config --global user.name \"storybook-bot\"\n          git config --global user.email \"32066757+storybook-bot@users.noreply.github.com\"\n\n      - name: Install dependencies\n        working-directory: ./scripts\n        run: node --experimental-modules ./check-dependencies.js\n\n      - name: Compile Storybook libraries\n        run: yarn task --task compile --start-from=auto --no-link\n\n      - name: Publish to local registry\n        run: yarn local-registry --publish\n\n      - name: Run local registry\n        run: yarn local-registry --open &\n\n      - name: Wait for registry\n        run: yarn wait-on tcp:127.0.0.1:6001\n\n      - name: Generate\n        id: generate\n        run: yarn generate-sandboxes --local-registry\n\n      - name: Publish\n        # publish sandboxes even if the generation fails, as some sandboxes might have been generated successfully\n        if: ${{ !cancelled() }}\n        run: yarn publish-sandboxes --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT }}@github.com/storybookjs/sandboxes.git --push --branch=next\n\n      - name: Report failure to Discord\n        if: failure()\n        env:\n          DISCORD_WEBHOOK: ${{ secrets.DISCORD_MONITORING_URL }}\n        uses: Ilshidur/action-discord@d2594079a10f1d6739ee50a2471f0ca57418b554\n        with:\n          args: |\n            The generation of some or all sandboxes on the **next** branch has failed.\n            [See the job summary for details](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})\n\n  generate-main:\n    name: Generate to main\n    if: github.repository_owner == 'storybookjs'\n    runs-on: ubuntu-latest\n    steps:\n      - name: Remove unnecessary files to release disk space\n        working-directory: ${{ github.workspace }}\n        run: |\n          sudo rm -rf \\\n            /opt/ghc \\\n            /opt/google/chrome \\\n            /opt/microsoft/msedge \\\n            /opt/microsoft/powershell \\\n            /usr/lib/mono \\\n            /usr/local/julia* \\\n            /usr/local/lib/android \\\n            /usr/local/share/chromium \\\n            /usr/local/share/powershell \\\n            /usr/local/share/powershell \\\n            /usr/share/dotnet \\\n            /usr/share/swift\n      - uses: actions/checkout@v4\n        with:\n          ref: main\n\n      - uses: actions/setup-node@v4\n        with:\n          node-version-file: '.nvmrc'\n\n      - name: Setup git user\n        run: |\n          git config --global user.name \"storybook-bot\"\n          git config --global user.email \"32066757+storybook-bot@users.noreply.github.com\"\n\n      - name: Install dependencies\n        working-directory: ./scripts\n        run: node --experimental-modules ./check-dependencies.js\n\n      - name: Compile Storybook libraries\n        run: yarn task --task compile --start-from=auto --no-link\n\n      - name: Publish to local registry\n        run: yarn local-registry --publish\n\n      - name: Run local registry\n        run: yarn local-registry --open &\n\n      - name: Wait for registry\n        run: yarn wait-on tcp:127.0.0.1:6001\n\n      - name: Generate\n        id: generate\n        run: yarn generate-sandboxes --local-registry\n\n      - name: Publish\n        # publish sandboxes even if the generation fails, as some sandboxes might have been generated successfully\n        if: ${{ !cancelled() }}\n        run: yarn publish-sandboxes --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT }}@github.com/storybookjs/sandboxes.git --push --branch=main\n\n      - name: Report failure to Discord\n        if: failure()\n        env:\n          DISCORD_WEBHOOK: ${{ secrets.DISCORD_MONITORING_URL }}\n        uses: Ilshidur/action-discord@d2594079a10f1d6739ee50a2471f0ca57418b554\n        with:\n          args: |\n            The generation of some or all sandboxes on the **main** branch has failed.\n            [See the job summary for details](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})\n"
  },
  {
    "path": ".github/workflows/handle-release-branches.yml",
    "content": "name: Handle Release Branches\n\non:\n  push:\n\njobs:\n  branch-checks:\n    if: github.repository_owner == 'storybookjs'\n    runs-on: ubuntu-latest\n    steps:\n      - id: get-branch\n        run: |\n          BRANCH=($(echo ${{ github.ref }} | sed -E 's/refs\\/heads\\///'))\n          echo \"branch=$BRANCH\" >> $GITHUB_ENV\n    outputs:\n      branch: ${{ env.branch }}\n      is-latest-branch: ${{ env.branch == 'main' }}\n      is-next-branch: ${{ env.branch == 'next' }}\n      is-release-branch: ${{ startsWith(env.branch, 'release-') }}\n      is-actionable-branch: ${{ env.branch == 'main' || env.branch == 'next' || startsWith(env.branch, 'release-') }}\n\n  handle-latest:\n    needs: branch-checks\n    if: ${{ needs.branch-checks.outputs.is-latest-branch == 'true' }}\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n\n      - run: curl -X POST \"https://api.netlify.com/build_hooks/${{ secrets.FRONTPAGE_HOOK }}\"\n\n  get-next-release-branch:\n    needs: branch-checks\n    if: ${{ needs.branch-checks.outputs.is-next-branch == 'true' || needs.branch-checks.outputs.is-release-branch == 'true' }}\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          ref: next\n          path: next\n\n      - id: next-version\n        uses: notiz-dev/github-action-json-property@release\n        with:\n          path: ${{ github.workspace }}/next/code/package.json\n          prop_path: version\n\n      - run: |\n          NEXT_RELEASE_BRANCH=($(echo ${{ steps.next-version.outputs.prop }} | sed -E 's/([0-9]+)\\.([0-9]+).*/release-\\1-\\2/'))\n          echo \"next-release-branch=$NEXT_RELEASE_BRANCH\" >> $GITHUB_ENV\n    outputs:\n      branch: ${{ env.next-release-branch }}\n\n  create-next-release-branch:\n    needs: [branch-checks, get-next-release-branch]\n    if: ${{ needs.branch-checks.outputs.is-next-branch == 'true' }}\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - run: |\n          set +e\n          REMOTE_BRANCH=$(git branch -r | grep origin/${{ needs.get-next-release-branch.outputs.branch }})\n          if [[ ! -z $REMOTE_BRANCH ]]; then git push origin --delete ${{ needs.get-next-release-branch.outputs.branch }}; fi\n          echo 'Pushing branch ${{ needs.get-next-release-branch.outputs.branch }}...'\n          git push -f origin ${{ needs.branch-checks.outputs.branch }}:${{ needs.get-next-release-branch.outputs.branch }}\n    outputs:\n      branch: ${{ needs.get-next-release-branch.outputs.branch }}\n\n  next-release-branch-check:\n    if: ${{ always() && github.repository_owner == 'storybookjs' }}\n    needs: [branch-checks, get-next-release-branch]\n    runs-on: ubuntu-latest\n    steps:\n      - run: |\n          IS_NEXT_RELEASE_BRANCH=${{ needs.branch-checks.outputs.branch == needs.get-next-release-branch.outputs.branch }}\n          echo \"is-next-release-branch=$IS_NEXT_RELEASE_BRANCH\" >> $GITHUB_ENV\n\n      - if: ${{ env.is-next-release-branch == 'true' }}\n        run: echo \"relevant-base-branch=next\" >> $GITHUB_ENV\n\n      - if: ${{ env.is-next-release-branch == 'true' }}\n        run: |\n          echo 'WARNING: Do not push directly to the `${{ needs.branch-checks.outputs.branch }}` branch. This branch is created and force-pushed over after pushing to the `${{ env.relevant-base-branch }}` branch and the changes you just pushed will be lost.'\n          exit 1\n    outputs:\n      check: ${{ env.is-next-release-branch }}\n\n  request-create-frontpage-branch:\n    if: ${{ always() && github.repository_owner == 'storybookjs' }}\n    needs:\n      [branch-checks, next-release-branch-check, create-next-release-branch]\n    runs-on: ubuntu-latest\n    steps:\n      - if: ${{ needs.branch-checks.outputs.is-actionable-branch == 'true' && needs.branch-checks.outputs.is-latest-branch == 'false' && needs.next-release-branch-check.outputs.check == 'false' }}\n        run: |\n          curl -X POST https://api.github.com/repos/storybookjs/frontpage/dispatches \\\n          -H 'Accept: application/vnd.github.v3+json' \\\n          -u ${{ secrets.FRONTPAGE_ACCESS_TOKEN }} \\\n          --data '{\"event_type\": \"request-create-frontpage-branch\", \"client_payload\": { \"branch\": \"${{ needs.create-next-release-branch.outputs.branch || needs.branch-checks.outputs.branch }}\" }}'\n"
  },
  {
    "path": ".github/workflows/markdown-link-check-config.json",
    "content": "{\n  \"replacementPatterns\": [\n    {\n      \"pattern\": \"^/\",\n      \"replacement\": \"./\"\n    }\n  ],\n  \"ignorePatterns\": [\n    {\n      \"pattern\": \"localhost\"\n    },\n    {\n      \"pattern\": \"https://github.com/storybookjs/storybook/pull/*\"\n    },\n    {\n      \"pattern\": \"https://stackblitz.com/*\"\n    },\n    {\n      \"pattern\": \"https://*.chromatic.com\"\n    },\n    {\n      \"pattern\": \"https://www.chromatic.com/build?*\"\n    },\n    {\n      \"pattern\": \"http://*.nodeca.com\"\n    },\n    {\n      \"pattern\": \"http://definitelytyped.org/*\"\n    },\n    {\n      \"pattern\": \"https://yoursite.com/*\"\n    },\n    {\n      \"pattern\": \"https://my-specific-domain.com\"\n    }\n  ],\n  \"aliveStatusCodes\": [429, 200]\n}\n"
  },
  {
    "path": ".github/workflows/nx.yml",
    "content": "name: nx\n\non:\n  push:\n    branches:\n      - next\n  # TODO use pull_request_target in the future to also run on forks\n  pull_request:\n    types: [opened, synchronize, labeled, reopened]\n  schedule:\n    - cron: '0 23 * * *'\n\npermissions:\n  actions: read\n  contents: read\n  statuses: write\n\nenv:\n  NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}\n\njobs:\n  nx:\n    if: >\n      github.repository == 'storybookjs/storybook' &&\n        ((github.event_name == 'pull_request' &&\n          github.event.pull_request.head.repo.full_name == github.repository &&\n          (contains(github.event.pull_request.labels.*.name, 'ci:normal') ||\n           contains(github.event.pull_request.labels.*.name, 'ci:merged') ||\n           contains(github.event.pull_request.labels.*.name, 'ci:daily'))\n        ) || (github.event_name == 'push' && github.ref == 'refs/heads/next') ||\n        (github.event_name == 'schedule'))\n\n    runs-on: ubuntu-latest\n    env:\n      ALL_TASKS: compile,check,knip,test,lint,fmt,sandbox,build,e2e-tests,e2e-tests-dev,test-runner,vitest-integration,check-sandbox,e2e-ui,jest,vitest,playwright-ct\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          filter: tree:0\n          fetch-depth: 0\n      - name: Set Nx tag(s)\n        id: tag\n        run: |\n          tags=\"normal\"\n          if [[ \"${{ github.event_name }}\" == \"pull_request\" ]]; then\n            if [[ \"${{ contains(github.event.pull_request.labels.*.name, 'ci:merged') }}\" == \"true\" ]]; then\n              tags=\"merged\"\n            fi\n            if [[ \"${{ contains(github.event.pull_request.labels.*.name, 'ci:daily') }}\" == \"true\" ]]; then\n              tags=\"daily\"\n            fi\n          fi\n\n          if [[ \"${{ github.event_name }}\" == \"push\" && \"${{ github.ref }}\" == \"refs/heads/next\" ]]; then\n            tags=\"merged\"\n          fi\n\n          if [[ \"${{ github.event_name }}\" == \"schedule\" ]]; then\n            tags=\"daily\"\n          fi\n\n          echo \"tag=$tags\" >> \"$GITHUB_OUTPUT\"\n      - name: Select distribution config\n        id: dist\n        run: |\n          if [[ \"${{ steps.tag.outputs.tag }}\" == \"daily\" ]]; then\n            echo \"config=./.nx/workflows/distribution-config-daily.yaml\" >> \"$GITHUB_OUTPUT\"\n          else\n            echo \"config=./.nx/workflows/distribution-config.yaml\" >> \"$GITHUB_OUTPUT\"\n          fi\n      - run: npx nx-cloud@latest start-ci-run --distribute-on=\"${{ steps.dist.outputs.config }}\" --stop-agents-after=\"$ALL_TASKS\"\n      - name: Create Nx Cloud Status (pending)\n        uses: actions/github-script@v7\n        with:\n          script: |\n            const tag = ${{ toJson(steps.tag.outputs.tag) }} || 'normal';\n\n            await github.rest.repos.createCommitStatus({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              sha: context.payload.pull_request?.head?.sha ?? context.sha,\n              state: 'pending',\n              target_url: `https://cloud.nx.app/orgs/606dcb5cdc2a2b00059cc0e9/workspaces/6929fbef73e98d8094d2a343/overview?branch=${\n                context.payload.pull_request?.number ?? 'next'\n              }`,\n              description: 'NX Cloud is running your tests',\n              context: `nx: ${tag}`,\n            });\n      - uses: actions/setup-node@v4\n        with:\n          node-version: 22\n          cache: 'yarn'\n      - run: yarn install --immutable\n      - uses: nrwl/nx-set-shas@v4\n      - id: nx\n        name: 'Run nx'\n        run: |\n          echo 'nx_output<<EOF' >> \"$GITHUB_OUTPUT\"\n          yarn nx run-many -t $ALL_TASKS -c production -p=\"tag:library,tag:ci:${{ steps.tag.outputs.tag }}\" | tee -a \"$GITHUB_OUTPUT\"\n          status=${PIPESTATUS[0]}\n          echo 'EOF' >> \"$GITHUB_OUTPUT\"\n          exit $status\n\n      - name: Create per-task Nx statuses\n        if: always()\n        uses: actions/github-script@v7\n        with:\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          script: |\n            const raw = ${{ toJson(steps.nx.outputs.nx_output) }} || '';\n            const tag = ${{ toJson(steps.tag.outputs.tag) }} || '';\n            const lines = raw.split('\\n');\n            const failures = [];\n            \n            for (const [i, line] of lines.entries()) {\n              if (!line.includes('✖')) continue;\n            \n              const task =\n                line.match(/✖\\s+([^│]+?)\\s{2,}/)?.[1].trim() ||\n                'Unknown Nx task';\n            \n              const url = lines\n                .slice(i + 1, i + 6)\n                .find(l => l.includes('Task logs:'))\n                ?.match(/Task logs:\\s*(https:\\/\\/cloud\\.nx\\.app\\/logs\\/\\S+)/)?.[1];\n            \n              failures.push({ task, url });\n            }\n            \n            const sha = context.payload.pull_request?.head?.sha ?? context.sha;\n            \n            // Per-task statuses (max 5)\n            for (const { task, url } of failures.slice(0, 5)) {\n              await github.rest.repos.createCommitStatus({\n                owner: context.repo.owner,\n                repo: context.repo.repo,\n                sha,\n                state: 'failure',\n                target_url: url ?? undefined,\n                context: `nx run ${task}`,\n                description: 'Your test failed on NX Cloud',\n              });\n            }\n            \n            const runMatches = raw.match(/https:\\/\\/cloud\\.nx\\.app\\/runs\\/\\S+/g);\n            const nxCloudUrl = runMatches ? runMatches[runMatches.length - 1] : undefined;\n\n            const failedCount = failures.length;\n\n            await github.rest.repos.createCommitStatus({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              sha,\n              state: failedCount ? 'failure' : 'success',\n              target_url: nxCloudUrl,\n              description: failedCount\n                ? `Nx Cloud run failed (${failedCount} tasks failed)`\n                : 'Nx Cloud run finished successfully',\n              context: `nx: ${tag}`,\n            });"
  },
  {
    "path": ".github/workflows/prepare-non-patch-release.yml",
    "content": "name: Prepare non-patch PR\nrun-name: Prepare non-patch PR, triggered by ${{ github.triggering_actor }}\n\non:\n  push:\n    branches:\n      - next\n  workflow_dispatch:\n    inputs:\n      release-type:\n        description: 'Which release type to use for bumping the version'\n        required: true\n        default: 'prerelease'\n        type: choice\n        options:\n          - prerelease\n          - prepatch\n          - preminor\n          - premajor\n          - patch\n          - minor\n          - major\n      pre-id:\n        description: For prerelease versions, what prerelease identifier to use, eg. 'alpha', 'beta', 'rc'\n        required: false\n        type: string\n\nenv:\n  PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1\n  PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1\n\nconcurrency:\n  group: ${{ github.workflow }}\n  cancel-in-progress: true\n\njobs:\n  prepare-non-patch-pull-request:\n    name: Prepare non-patch pull request\n    if: github.repository_owner == 'storybookjs'\n    runs-on: ubuntu-latest\n    environment: Release\n    defaults:\n      run:\n        working-directory: scripts\n    steps:\n      - name: Checkout next\n        uses: actions/checkout@v4\n        with:\n          ref: next\n          # this needs to be set to a high enough number that it will contain the last version tag\n          # as of May 2023, the whole repo had 55K commits\n          fetch-depth: 10000\n          token: ${{ secrets.GH_TOKEN }}\n\n      - name: Setup Node.js and Install Dependencies\n        uses: ./.github/actions/setup-node-and-install\n\n      - name: Check if pull request is frozen\n        if: github.event_name != 'workflow_dispatch'\n        id: check-frozen\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: yarn release:is-pr-frozen\n\n      - name: Cancel when frozen\n        if: steps.check-frozen.outputs.frozen == 'true' && github.event_name != 'workflow_dispatch'\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        # From https://stackoverflow.com/a/75809743\n        run: |\n          gh run cancel ${{ github.run_id }}\n          gh run watch ${{ github.run_id }}\n\n      # tags are needed to get changes and changelog generation\n      - name: Fetch git tags\n        run: git fetch --tags origin\n\n      - name: Check for unreleased changes\n        if: github.event_name != 'workflow_dispatch'\n        id: unreleased-changes\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: yarn release:unreleased-changes-exists\n\n      - name: Cancel when no release necessary\n        if: steps.unreleased-changes.outputs.has-changes-to-release == 'false' && github.event_name != 'workflow_dispatch'\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        # From https://stackoverflow.com/a/75809743\n        run: |\n          gh run cancel ${{ github.run_id }}\n          gh run watch ${{ github.run_id }}\n\n      - name: Bump version deferred\n        id: bump-version\n        run: |\n          yarn release:version --deferred --release-type ${{ inputs.release-type || 'prerelease' }} ${{ inputs.pre-id && format('{0} {1}', '--pre-id', inputs.pre-id) || '' }} --verbose\n\n      - name: Write changelog\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          yarn release:write-changelog ${{ steps.bump-version.outputs.next-version }} --verbose\n\n      - name: 'Commit changes to branch: version-non-patch-from-${{ steps.bump-version.outputs.current-version }}'\n        working-directory: .\n        run: |\n          git config --global user.name 'storybook-bot'\n          git config --global user.email '32066757+storybook-bot@users.noreply.github.com'\n          git checkout -b version-non-patch-from-${{ steps.bump-version.outputs.current-version }}\n          git add .\n          git commit --allow-empty --no-verify -m \"Write changelog for ${{ steps.bump-version.outputs.next-version }} [skip ci]\"\n          git push --force origin version-non-patch-from-${{ steps.bump-version.outputs.current-version }}\n\n      - name: Generate PR description\n        id: description\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: yarn release:generate-pr-description --current-version ${{ steps.bump-version.outputs.current-version }} --next-version ${{ steps.bump-version.outputs.next-version }} --verbose\n\n      - name: Create or update pull request\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          RELEASE_TYPE=${{ inputs.release-type || 'prerelease' }}\n          CAPITALIZED_RELEASE_TYPE=${RELEASE_TYPE^}\n          if PR_STATE=$(gh pr view --json state --jq .state 2>/dev/null) && [[ -n \"$PR_STATE\" && \"$PR_STATE\" == *\"OPEN\"* ]]; then\n            gh pr edit \\\n              --repo \"${{github.repository }}\" \\\n              --title \"Release: $CAPITALIZED_RELEASE_TYPE ${{ inputs.pre-id && format('{0} ', inputs.pre-id) }}${{ steps.bump-version.outputs.next-version }}\" \\\n              --body \"${{ steps.description.outputs.description }}\"\n          else\n            gh pr create \\\n              --repo \"${{github.repository }}\"\\\n              --title \"Release: $CAPITALIZED_RELEASE_TYPE ${{ inputs.pre-id && format('{0} ', inputs.pre-id) }}${{ steps.bump-version.outputs.next-version }}\" \\\n              --label \"release\" \\\n              --base next-release \\\n              --head version-non-patch-from-${{ steps.bump-version.outputs.current-version }} \\\n              --body \"${{ steps.description.outputs.description }}\"\n          fi\n\n      - name: Report job failure to Discord\n        if: failure()\n        env:\n          DISCORD_WEBHOOK: ${{ secrets.DISCORD_MONITORING_URL }}\n        uses: Ilshidur/action-discord@d2594079a10f1d6739ee50a2471f0ca57418b554\n        with:\n          args: 'The GitHub Action for preparing the release pull request bumping from v${{ steps.bump-version.outputs.current-version }} to v${{ steps.bump-version.outputs.next-version }} (triggered by ${{ github.triggering_actor }}) failed! See run at: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}'\n"
  },
  {
    "path": ".github/workflows/prepare-patch-release.yml",
    "content": "name: Prepare patch PR\nrun-name: Prepare patch PR, triggered by ${{ github.triggering_actor }}\n\non:\n  push:\n    branches:\n      - next\n  workflow_dispatch:\n\nenv:\n  PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1\n  PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1\n\nconcurrency:\n  group: ${{ github.workflow }}\n  cancel-in-progress: true\n\njobs:\n  prepare-patch-pull-request:\n    name: Prepare patch pull request\n    if: github.repository_owner == 'storybookjs'\n    runs-on: ubuntu-latest\n    environment: Release\n    defaults:\n      run:\n        working-directory: scripts\n    steps:\n      - name: Checkout main\n        uses: actions/checkout@v4\n        with:\n          ref: main\n          token: ${{ secrets.GH_TOKEN }}\n\n      - name: Setup Node.js and Install Dependencies\n        uses: ./.github/actions/setup-node-and-install\n\n      - name: Check if pull request is frozen\n        if: github.event_name != 'workflow_dispatch'\n        id: check-frozen\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: yarn release:is-pr-frozen --patch\n\n      - name: Cancel when frozen\n        if: steps.check-frozen.outputs.frozen == 'true' && github.event_name != 'workflow_dispatch'\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        # From https://stackoverflow.com/a/75809743\n        run: |\n          gh run cancel ${{ github.run_id }}\n          gh run watch ${{ github.run_id }}\n\n      - name: Check for unreleased changes\n        id: unreleased-changes\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: yarn release:unreleased-changes-exists --unpicked-patches\n\n      - name: Fetch next branch\n        run:\n          # depth needs to be set to a high enough number that it will contain all the merge commits to cherry-pick\n          # as of May 2023, the whole repo had 55K commits\n          git fetch --depth=2000 origin next\n\n      - name: Pick patches\n        id: pick-patches\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          git config --global user.name 'storybook-bot'\n          git config --global user.email '32066757+storybook-bot@users.noreply.github.com'\n          yarn release:pick-patches\n\n      - name: Cancel when no patches to pick\n        if: steps.pick-patches.outputs.no-patch-prs == 'true'\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        # From https://stackoverflow.com/a/75809743\n        run: |\n          gh run cancel ${{ github.run_id }}\n          gh run watch ${{ github.run_id }}\n\n      - name: Bump version deferred\n        id: bump-version\n        if: steps.unreleased-changes.outputs.has-changes-to-release == 'true'\n        run: |\n          yarn release:version --deferred --release-type patch --verbose\n\n      # We need the current version to set the branch name, even when not bumping the version\n      - name: Get current version\n        id: current-version\n        if: steps.unreleased-changes.outputs.has-changes-to-release == 'false'\n        run: |\n          yarn release:get-current-version --verbose\n\n      - name: Set version output\n        id: versions\n        run: |\n          echo \"current=${{ steps.bump-version.outputs.current-version || steps.current-version.outputs.current-version }}\" >> \"$GITHUB_OUTPUT\"\n          echo \"next=${{ steps.bump-version.outputs.next-version || steps.current-version.outputs.current-version }}\" >> \"$GITHUB_OUTPUT\"\n\n      - name: Write changelog\n        if: steps.unreleased-changes.outputs.has-changes-to-release == 'true'\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          yarn release:write-changelog ${{ steps.versions.outputs.next }} --unpicked-patches --verbose\n\n      - name: 'Commit changes to branch: version-patch-from-${{ steps.versions.outputs.current }}'\n        working-directory: .\n        run: |\n          git config --global user.name 'storybook-bot'\n          git config --global user.email '32066757+storybook-bot@users.noreply.github.com'\n          git checkout -b version-patch-from-${{ steps.versions.outputs.current }}\n          git add .\n          git commit --allow-empty --no-verify -m \"Write changelog for ${{ steps.versions.outputs.next }} [skip ci]\"\n          git push --force origin version-patch-from-${{ steps.versions.outputs.current }}\n\n      - name: Generate PR description\n        id: description\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: yarn release:generate-pr-description --unpicked-patches --manual-cherry-picks='${{ steps.pick-patches.outputs.failed-cherry-picks }}' ${{ steps.unreleased-changes.outputs.has-changes-to-release == 'true' && format('{0}={1} {2}={3}', '--current-version', steps.versions.outputs.current, '--next-version', steps.versions.outputs.next) || '' }} --verbose\n\n      - name: Create or update pull request with release\n        if: steps.unreleased-changes.outputs.has-changes-to-release == 'true'\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          if PR_STATE=$(gh pr view --json state --jq .state 2>/dev/null) && [[ -n \"$PR_STATE\" && \"$PR_STATE\" == *\"OPEN\"* ]]; then\n            gh pr edit \\\n              --repo \"${{github.repository }}\" \\\n              --title \"Release: Patch ${{ steps.versions.outputs.next }}\" \\\n              --body \"${{ steps.description.outputs.description }}\"\n          else\n            gh pr create \\\n              --repo \"${{github.repository }}\" \\\n              --title \"Release: Patch ${{ steps.versions.outputs.next }}\" \\\n              --label \"release\" \\\n              --base latest-release \\\n              --head version-patch-from-${{ steps.versions.outputs.current }} \\\n              --body \"${{ steps.description.outputs.description }}\"\n          fi\n\n      - name: Create or update pull request without release\n        if: steps.unreleased-changes.outputs.has-changes-to-release == 'false'\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          if PR_STATE=$(gh pr view --json state --jq .state 2>/dev/null) && [[ -n \"$PR_STATE\" && \"$PR_STATE\" == *\"OPEN\"* ]]; then\n            gh pr edit \\\n              --repo \"${{github.repository }}\"\\\n              --title \"Release: Merge patches to \\`main\\` (without version bump)\" \\\n              --body \"${{ steps.description.outputs.description }}\"\n          else\n            gh pr create \\\n              --repo \"${{github.repository }}\"\\\n              --title \"Release: Merge patches to \\`main\\` (without version bump)\" \\\n              --label \"release\" \\\n              --base latest-release \\\n              --head version-patch-from-${{ steps.versions.outputs.current }} \\\n              --body \"${{ steps.description.outputs.description }}\"\n          fi\n\n      - name: Report job failure to Discord\n        if: failure()\n        env:\n          DISCORD_WEBHOOK: ${{ secrets.DISCORD_MONITORING_URL }}\n        uses: Ilshidur/action-discord@d2594079a10f1d6739ee50a2471f0ca57418b554\n        with:\n          args: 'The GitHub Action for preparing the release pull request bumping from v${{ steps.versions.outputs.current }} to v${{ steps.versions.outputs.next }} (triggered by ${{ github.triggering_actor }}) failed! See run at: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}'\n"
  },
  {
    "path": ".github/workflows/publish.yml",
    "content": "name: Publish\nrun-name: \"${{ github.event_name == 'workflow_dispatch' && format('Publish Canary on PR #{0}, triggered by {1}', inputs.pr, github.triggering_actor) || format('Publish new version on {0}, triggered by {1}', github.ref_name, github.triggering_actor) }}\"\n\non:\n  push:\n    # Normal releases, major/minor/patch/prerelease\n    branches:\n      - latest-release\n      - next-release\n  workflow_dispatch:\n    # Manual canary releases on PRs\n    inputs:\n      pr:\n        description: \"⚠️ CANARY RELEASES ONLY - Enter the pull request number to create a canary release for\"\n        required: true\n        type: number\n  pull_request:\n    # Automated canary releases on PRs with the \"with-canary-release\"-suffix in the branch name\n    types: [opened, synchronize, reopened]\n\nenv:\n  PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1\n  PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1\n\npermissions:\n  id-token: write\n  contents: write\n  pull-requests: write\n\nconcurrency:\n  # Group concurrent runs based on the event type:\n  # - For workflow_dispatch and pull_request: group by PR number to allow only one canary release per PR\n  # - For push events: group by branch name to prevent multiple releases on the same branch\n  group: ${{ github.event_name == 'workflow_dispatch' && format('{0}-{1}', github.workflow, inputs.pr) || github.event_name == 'pull_request' && format('{0}-{1}', github.workflow, github.event.pull_request.number) || format('{0}-{1}', github.workflow, github.ref_name) }}\n  cancel-in-progress: ${{ github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request' }}\n\njobs:\n  publish-normal:\n    name: Publish normal version\n    runs-on: ubuntu-latest\n    if: |\n      github.repository_owner == 'storybookjs' &&\n      github.event_name == 'push' &&\n      (github.ref_name == 'latest-release' || github.ref_name == 'next-release') &&\n      contains(github.event.head_commit.message, '[skip ci]') != true\n    environment: Release\n    defaults:\n      run:\n        working-directory: scripts\n    steps:\n      - name: Checkout ${{ github.ref_name }}\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 100\n          token: ${{ secrets.GH_TOKEN }}\n\n      - name: Setup Node.js and Install Dependencies\n        uses: ./.github/actions/setup-node-and-install\n        with:\n          install-code-deps: true\n\n      - name: Cancel all release preparation runs\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: yarn release:cancel-preparation-runs\n\n      - name: Apply deferred version bump and commit\n        working-directory: .\n        env:\n          REF_NAME: ${{ github.ref_name }}\n        run: |\n          CURRENT_VERSION=$(cat ./code/package.json | jq '.version')\n          DEFERRED_NEXT_VERSION=$(cat ./code/package.json | jq '.deferredNextVersion')\n\n          if [[ \"$DEFERRED_NEXT_VERSION\" == \"null\" ]]; then\n              echo \"No deferred version set, not bumping versions\"\n              exit 0\n          fi\n          cd scripts\n          yarn release:version --apply --verbose\n          cd ..\n\n          git config --global user.name \"storybook-bot\"\n          git config --global user.email \"32066757+storybook-bot@users.noreply.github.com\"\n          git add .\n          git commit -m \"Bump version from $CURRENT_VERSION to $DEFERRED_NEXT_VERSION [skip ci]\" --no-verify --allow-empty\n          git push origin \"$REF_NAME\"\n\n      - name: Get current version\n        id: version\n        run: yarn release:get-current-version\n\n      - name: Check if publish is needed\n        id: publish-needed\n        env:\n          CURRENT_VERSION: ${{ steps.version.outputs.current-version }}\n        run: yarn release:is-version-published \"$CURRENT_VERSION\"\n\n      - name: Check release vs prerelease\n        if: steps.publish-needed.outputs.published == 'false'\n        id: is-prerelease\n        env:\n          CURRENT_VERSION: ${{ steps.version.outputs.current-version }}\n        run: yarn release:is-prerelease \"$CURRENT_VERSION\" --verbose\n\n      - name: Publish\n        env:\n          NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}\n        if: steps.publish-needed.outputs.published == 'false'\n        run: yarn release:publish --tag ${{ steps.is-prerelease.outputs.prerelease == 'true' && 'next' || 'latest' }} --verbose\n\n      - name: Get target branch\n        id: target\n        run: echo \"target=${{ github.ref_name == 'next-release' && 'next' || 'main' }}\" >> $GITHUB_OUTPUT\n\n      - name: Get changelog for ${{ steps.version.outputs.current-version }}\n        if: steps.publish-needed.outputs.published == 'false'\n        id: changelog\n        env:\n          CURRENT_VERSION: ${{ steps.version.outputs.current-version }}\n        run: yarn release:get-changelog-from-file \"$CURRENT_VERSION\"\n\n      # tags are needed to get list of patches to label as picked\n      - name: Fetch git tags\n        if: github.ref_name == 'latest-release'\n        run: git fetch --tags origin\n\n      # when this is a patch release from main, label any patch PRs included in the release\n      - name: Label patch PRs as picked\n        if: github.ref_name == 'latest-release'\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: yarn release:label-patches\n\n      - name: Create GitHub Release\n        if: steps.publish-needed.outputs.published == 'false'\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          CURRENT_VERSION: ${{ steps.version.outputs.current-version }}\n          REPOSITORY: ${{ github.repository }}\n          REF_NAME: ${{ github.ref_name }}\n          CHANGELOG: ${{ steps.changelog.outputs.changelog }}\n          IS_PRERELEASE: ${{ steps.is-prerelease.outputs.prerelease == 'true' && '--prerelease' || '' }}\n        run: |\n          gh release create \\\n          \"v$CURRENT_VERSION\" \\\n            --repo \"$REPOSITORY\" \\\n            --target \"$REF_NAME\" \\\n            --title \"v$CURRENT_VERSION\" \\\n            --notes \"$CHANGELOG\" \\\n            $IS_PRERELEASE\n\n      - name: Merge ${{ github.ref_name }} into ${{ steps.target.outputs.target }}\n        env:\n          REF_NAME: ${{ github.ref_name }}\n          TARGET_BRANCH: ${{ steps.target.outputs.target }}\n        run: |\n          git config --global user.name \"storybook-bot\"\n          git config --global user.email \"32066757+storybook-bot@users.noreply.github.com\"\n          git fetch origin \"$TARGET_BRANCH\"\n          git checkout \"$TARGET_BRANCH\"\n          git merge \"$REF_NAME\"\n          git push origin \"$TARGET_BRANCH\"\n\n      - name: Force push from 'next' to 'latest-release' and 'main' on minor/major releases\n        if: github.ref_name == 'next-release' && steps.is-prerelease.outputs.prerelease == 'false'\n        run: |\n          git checkout next\n          git pull\n          git push origin --force next:latest-release\n          git push origin --force next:main\n\n      - name: Sync CHANGELOG.md from `main` to `next`\n        if: steps.target.outputs.target == 'main'\n        working-directory: .\n        env:\n          CURRENT_VERSION: ${{ steps.version.outputs.current-version }}\n        run: |\n          git fetch origin next\n          git checkout next\n          git pull\n          git checkout origin/main ./CHANGELOG.md\n          git add ./CHANGELOG.md\n          git commit -m \"Update CHANGELOG.md for v$CURRENT_VERSION [skip ci]\" --no-verify --allow-empty\n          git push origin next\n\n      # Sync the next.json version file to the main branch so it gets deployed to the docs site\n      # but only if this is a prerelease, because in minor/major releases we're already force pushing next-release onto main, so it's already there\n      - name: Sync version JSONs from `next-release` to `main`\n        if: github.ref_name == 'next-release' && steps.is-prerelease.outputs.prerelease == 'true'\n        working-directory: .\n        env:\n          CURRENT_VERSION: ${{ steps.version.outputs.current-version }}\n        run: |\n          VERSION_FILE=\"./docs/versions/next.json\"\n          git fetch origin main\n          git checkout main\n          git pull\n          git checkout origin/next-release $VERSION_FILE\n          git add $VERSION_FILE\n          git commit -m \"Update $VERSION_FILE for v$CURRENT_VERSION\"\n          git push origin main\n\n      - name: Create Sentry release\n        if: steps.publish-needed.outputs.published == 'false'\n        uses: getsentry/action-release@v3\n        env:\n          SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}\n          SENTRY_ORG: ${{ secrets.SENTRY_ORG }}\n          SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}\n        with:\n          release: ${{ steps.version.outputs.current-version }}\n          environment: ${{ steps.is-prerelease.outputs.prerelease == 'true' && 'prerelease' || 'latest' }}\n\n      - name: Report job failure to Discord\n        if: failure()\n        env:\n          DISCORD_WEBHOOK: ${{ secrets.DISCORD_MONITORING_URL }}\n        uses: Ilshidur/action-discord@d2594079a10f1d6739ee50a2471f0ca57418b554\n        with:\n          args: \"The GitHub Action for publishing version ${{ steps.version.outputs.current-version }} (triggered by ${{ github.triggering_actor }}) failed! See run at: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\"\n\n  publish-canary:\n    name: Publish canary version\n    runs-on: ubuntu-latest\n    if: |\n      github.repository_owner == 'storybookjs' &&\n      (\n        github.event_name == 'workflow_dispatch' ||\n        (github.event_name == 'pull_request' && endsWith(github.head_ref, 'with-canary-release'))\n      ) &&\n      contains(github.event.head_commit.message, '[skip ci]') != true\n    environment: Release\n    steps:\n      - name: Fail if triggering actor is not administrator\n        uses: prince-chrismc/check-actor-permissions-action@87c6d9b36c730377858fd9719fbbac1b58fa678d\n        with:\n          permission: admin\n\n      - name: Get pull request information\n        id: info\n        env:\n          GH_TOKEN: ${{ secrets.GH_TOKEN }}\n          PR_NUMBER: ${{ github.event_name == 'workflow_dispatch' && inputs.pr || github.event.pull_request.number }}\n          REPOSITORY: ${{ github.repository }}\n        run: |\n          PR_INFO=$(gh pr view \"$PR_NUMBER\" --repo \"$REPOSITORY\" --json isCrossRepository,headRefOid,headRefName,headRepository,headRepositoryOwner --jq '{isFork: .isCrossRepository, owner: .headRepositoryOwner.login, repoName: .headRepository.name, branch: .headRefName, sha: .headRefOid}')\n          echo $PR_INFO\n          # Loop through each key-value pair in PR_INFO and set as step output\n          for key in $(echo \"$PR_INFO\" | jq -r 'keys[]'); do\n            value=$(echo \"$PR_INFO\" | jq -r \".$key\")\n            echo \"$key=$value\" >> \"$GITHUB_OUTPUT\"\n          done\n          echo \"repository=$(echo \"$PR_INFO\" | jq -r \".owner\")/$(echo \"$PR_INFO\" | jq -r \".repoName\")\" >> $GITHUB_OUTPUT\n          echo \"shortSha=$(echo \"$PR_INFO\" | jq -r \".sha\" | cut -c 1-8)\" >> $GITHUB_OUTPUT\n          echo \"date=$(date)\" >> $GITHUB_OUTPUT\n          echo \"timestamp=$(date +%s)\" >> $GITHUB_OUTPUT\n\n      - name: Checkout\n        uses: actions/checkout@v4\n        with:\n          repository: ${{ steps.info.outputs.isFork == 'true' && steps.info.outputs.repository || null }}\n          ref: ${{ steps.info.outputs.sha }}\n          token: ${{ secrets.GH_TOKEN }}\n\n      - name: Setup Node.js and Install Dependencies\n        uses: ./.github/actions/setup-node-and-install\n        with:\n          install-code-deps: true\n\n      - name: Set version\n        id: version\n        working-directory: scripts\n        env:\n          PR_NUMBER: ${{ github.event_name == 'workflow_dispatch' && inputs.pr || github.event.pull_request.number }}\n          SHORT_SHA: ${{ steps.info.outputs.shortSha }}\n        run: |\n          yarn release:version --exact \"0.0.0-pr-$PR_NUMBER-sha-$SHORT_SHA\" --verbose\n\n      - name: Publish v${{ steps.version.outputs.next-version }}\n        env:\n          NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}\n        working-directory: scripts\n        run: yarn release:publish --tag canary --verbose\n\n      - name: Replace Pull Request Body\n        uses: ivangabriele/find-and-replace-pull-request-body@042438c6cbfbacf6a4701d6042f59b1f73db2fd8\n        with:\n          githubToken: ${{ secrets.GH_TOKEN }}\n          prNumber: ${{ github.event_name == 'workflow_dispatch' && inputs.pr || '' }}\n          find: \"CANARY_RELEASE_SECTION\"\n          isHtmlCommentTag: true\n          replace: |\n            This pull request has been released as version `${{ steps.version.outputs.next-version }}`. Try it out in a new sandbox by running `npx storybook@${{ steps.version.outputs.next-version }} sandbox` or in an existing project with `npx storybook@${{ steps.version.outputs.next-version }} upgrade`.\n            <details>\n            <summary>More information</summary>\n\n            | | |\n            | --- | --- |\n            | **Published version** | [`${{ steps.version.outputs.next-version }}`](https://npmjs.com/package/storybook/v/${{ steps.version.outputs.next-version }}) |\n            | **Triggered by** | @${{ github.triggering_actor }} |\n            | **Repository** | [${{ steps.info.outputs.repository }}](https://github.com/${{ steps.info.outputs.repository }}) |\n            | **Branch** | [`${{ steps.info.outputs.branch }}`](https://github.com/${{ steps.info.outputs.repository }}/tree/${{ steps.info.outputs.branch }}) |\n            | **Commit** | [`${{ steps.info.outputs.shortSha }}`](https://github.com/${{ steps.info.outputs.repository }}/commit/${{ steps.info.outputs.sha }}) |\n            | **Datetime** | ${{ steps.info.outputs.date }} (`${{ steps.info.outputs.timestamp }}`) |\n            | **Workflow run** | [${{ github.run_id }}](https://github.com/storybookjs/storybook/actions/runs/${{ github.run_id }}) |\n\n            To request a new release of this pull request, mention the `@storybookjs/core` team.\n\n            _core team members can create a new canary release [here](https://github.com/storybookjs/storybook/actions/workflows/publish.yml) or locally with `gh workflow run --repo storybookjs/storybook publish.yml --field pr=${{ github.event_name == 'workflow_dispatch' && inputs.pr || github.event.pull_request.number }}`_\n            </details>\n\n      - name: Create failing comment on PR\n        if: failure()\n        env:\n          GH_TOKEN: ${{ secrets.GH_TOKEN }}\n          PR_NUMBER: ${{ github.event_name == 'workflow_dispatch' && inputs.pr || github.event.pull_request.number }}\n          REPOSITORY: ${{ github.repository }}\n          TRIGGERING_ACTOR: ${{ github.triggering_actor }}\n          RUN_ID: ${{ github.run_id }}\n        run: |\n          gh pr comment \"$PR_NUMBER\"\\\n            --repo \"$REPOSITORY\"\\\n            --body \"Failed to publish canary version of this pull request, triggered by @$TRIGGERING_ACTOR. See the failed workflow run at: https://github.com/$REPOSITORY/actions/runs/$RUN_ID\"\n"
  },
  {
    "path": ".github/workflows/shared/mood.md",
    "content": "."
  },
  {
    "path": ".github/workflows/shared/reporting.md",
    "content": "---\n# Report formatting guidelines\n---\n\n## Report Structure Guidelines\n\n### 1. Header Levels\n**Use h3 (###) or lower for all headers in your issue report to maintain proper document hierarchy.**\n\nWhen creating GitHub issues or discussions:\n- Use `###` (h3) for main sections (e.g., \"### Test Summary\")\n- Use `####` (h4) for subsections (e.g., \"#### Device-Specific Results\")\n- Never use `##` (h2) or `#` (h1) in reports - these are reserved for titles\n\n### 2. Progressive Disclosure\n**Wrap detailed test results in `<details><summary><b>Section Name</b></summary>` tags to improve readability and reduce scrolling.**\n\nUse collapsible sections for:\n- Verbose details (full test logs, raw data)\n- Secondary information (minor warnings, extra context)\n- Per-item breakdowns when there are many items\n\nAlways keep critical information visible (summary, critical issues, key metrics).\n\n### 3. Report Structure Pattern\n\n1. **Overview**: 1-2 paragraphs summarizing key findings\n2. **Critical Information**: Show immediately (summary stats, critical issues)\n3. **Details**: Use `<details><summary><b>Section Name</b></summary>` for expanded content\n4. **Context**: Add helpful metadata (workflow run, date, trigger)\n\n### Design Principles (Airbnb-Inspired)\n\nReports should:\n- **Build trust through clarity**: Most important info immediately visible\n- **Exceed expectations**: Add helpful context like trends, comparisons\n- **Create delight**: Use progressive disclosure to reduce overwhelm\n- **Maintain consistency**: Follow patterns across all reports\n\n### Example Report Structure\n\n```markdown\n### Summary\n- Key metric 1: value\n- Key metric 2: value\n- Status: ✅/⚠️/❌\n\n### Critical Issues\n[Always visible - these are important]\n\n<details>\n<summary><b>View Detailed Results</b></summary>\n\n[Comprehensive details, logs, traces]\n\n</details>\n\n<details>\n<summary><b>View All Warnings</b></summary>\n\n[Minor issues and potential problems]\n\n</details>\n\n### Recommendations\n[Actionable next steps - keep visible]\n```\n\n## Workflow Run References\n\n- Format run IDs as links: `[§12345](https://github.com/owner/repo/actions/runs/12345)`\n- Include up to 3 most relevant run URLs at end under `**References:**`\n- Do NOT add footer attribution (system adds automatically)\n"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "name: \"Close stale issues that need reproduction or more info from OP\"\non:\n  schedule:\n    - cron: \"30 1 * * *\"\n\npermissions:\n  issues: write # to close and label issues (actions/stale)\n  pull-requests: write # to mark stale pull requests (actions/stale)\n\njobs:\n  stale:\n    runs-on: ubuntu-latest\n    if: github.repository_owner == 'storybookjs'\n    steps:\n      - uses: actions/stale@v9\n        with:\n          stale-issue-message: \"Hi there! Thank you for opening this issue, but it has been marked as `stale` because we need more information to move forward. Could you please provide us with the requested reproduction or additional information that could help us better understand the problem? We'd love to resolve this issue, but we can't do it without your help!\"\n          close-issue-message: \"I'm afraid we need to close this issue for now, since we can't take any action without the requested reproduction or additional information. But please don't hesitate to open a new issue if the problem persists – we're always happy to help. Thanks so much for your understanding.\"\n          any-of-issue-labels: \"needs reproduction,needs more info\"\n          exempt-issue-labels: \"needs triage\"\n          labels-to-add-when-unstale: \"needs triage\"\n          days-before-issue-close: 7\n          days-before-issue-stale: 21\n          days-before-pr-close: -1\n          days-before-pr-stale: 10\n          exempt-draft-pr: true\n"
  },
  {
    "path": ".github/workflows/triage.yml",
    "content": "name: Triage issues\n\non:\n  issues:\n    types: [opened, labeled]\n  issue_comment:\n    types: [created]\n\nenv:\n  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\npermissions:\n  issues: write\n\njobs:\n  triage:\n    name: Nissuer\n    if: github.repository_owner == 'storybookjs'\n    runs-on: ubuntu-latest\n    steps:\n      - uses: balazsorban44/nissuer@1.10.0\n        with:\n          label-comments: |\n            {\n              \"good first issue\": \".github/comments/good-first-issue.md\"\n            }\n          reproduction-comment: \".github/comments/invalid-link.md\"\n          reproduction-hosts: \"github.com,codesandbox.io,stackblitz.com\"\n          reproduction-link-section: \"### Reproduction link(.*)### Reproduction steps\"\n          reproduction-invalid-label: \"needs reproduction\"\n          reproduction-issue-labels: \"bug,needs triage\"\n"
  },
  {
    "path": ".github/workflows/trigger-circle-ci-workflow.yml",
    "content": "name: Trigger CircleCI workflow\n\non:\n  # Use pull_request_target, as we don't need to check out the actual code of the fork in this script.\n  # And this is the only way to trigger the Circle CI API on forks as well.\n  pull_request_target:\n    types: [opened, synchronize, labeled, reopened]\n  push:\n    branches:\n      - next\n      - main\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\njobs:\n  get-branch:\n    if: github.repository_owner == 'storybookjs'\n    runs-on: ubuntu-latest\n    steps:\n      - id: get-branch\n        env:\n          # Stored as environment variable to prevent script injection\n          REF_NAME: ${{ github.ref_name }}\n          PR_REF_NAME: ${{ github.event.pull_request.head.ref }}\n        run: |\n          if  [ \"${{ github.event.pull_request.head.repo.fork }}\" = \"true\" ]; then\n            export BRANCH=pull/${{ github.event.pull_request.number }}/head\n            elif [ \"${{ github.event_name }}\" = \"push\" ]; then\n            export BRANCH=\"$REF_NAME\"\n            else\n            export BRANCH=\"$PR_REF_NAME\"\n          fi\n          echo \"$BRANCH\"\n          echo \"branch=$BRANCH\" >> $GITHUB_ENV\n    outputs:\n      branch: ${{ env.branch }}\n\n  get-parameters:\n    if: github.repository_owner == 'storybookjs'\n    runs-on: ubuntu-latest\n    steps:\n      - if: github.event_name == 'pull_request_target' && (contains(github.event.pull_request.labels.*.name, 'ci:normal'))\n        run: echo \"workflow=normal\" >> $GITHUB_ENV\n      - if: github.event_name == 'pull_request_target' && (contains(github.event.pull_request.labels.*.name, 'ci:docs'))\n        run: echo \"workflow=docs\" >> $GITHUB_ENV\n      - if: github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'ci:merged')\n        run: echo \"workflow=merged\" >> $GITHUB_ENV\n      - if: github.event_name == 'pull_request_target' && (contains(github.event.pull_request.labels.*.name, 'ci:daily'))\n        run: echo \"workflow=daily\" >> $GITHUB_ENV\n    outputs:\n      workflow: ${{ env.workflow }}\n      ghBaseBranch: ${{ github.event.pull_request.base.ref }}\n      ghPrNumber: ${{ github.event.pull_request.number }}\n\n  trigger-circle-ci-workflow:\n    runs-on: ubuntu-latest\n    needs: [get-branch, get-parameters]\n    if: github.repository_owner == 'storybookjs' && needs.get-parameters.outputs.workflow != ''\n    steps:\n      - name: Trigger Normal tests\n        uses: fjogeleit/http-request-action@v1\n        with:\n          url: 'https://circleci.com/api/v2/project/gh/storybookjs/storybook/pipeline'\n          method: 'POST'\n          customHeaders: '{\"Content-Type\": \"application/json\", \"Circle-Token\": \"${{ secrets.CIRCLE_CI_TOKEN }}\"}'\n          data: '{ \"branch\": \"${{needs.get-branch.outputs.branch}}\", \"parameters\": ${{toJson(needs.get-parameters.outputs)}} }'\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\n*.log\n.idea\n*.iml\n*.sw*\n!.swcrc\ndist\n*.DS_Store\n.cache\njunit.xml\ntest-results\n/repros\n/sandbox\n/bench\n/code/bench\n.verdaccio-cache\n.next\n/.npmrc\ntsconfig.vitest-temp.json\n\n.env.local\n\n# https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored\n.pnp.*\n.yarn/*\n!.yarn/patches\n!.yarn/plugins\n!.yarn/releases\n!.yarn/sdks\n!.yarn/versions\n\n# For sandboxes\n/**/.pnp.*\n/**/.yarn/*\n!/**/.yarn/patches\n!/**/.yarn/plugins\n!/**/.yarn/releases\n!/**/.yarn/sdks\n!/**/.yarn/versions\n\n# test-storybooks\ntest-storybooks/ember-cli/ember-output\ntest-storybooks/angular-cli/addon-jest.testresults.json\n\n.circleci/*.generated.yml\nnpm-shrinkwrap.json\n.tern-port\n.parcel-cache\ncoverage/\n*.lerna_backup\n/**/LICENSE\ncode/docs/public\npackage-lock.json\nstorybook-static\n.jest-test-results.json\n*.jar\n/false\n/addons/docs/common/config-*\ntsconfig.tsbuildinfo\n\ncode/test-results/\ncode/playwright-results/\ncode/playwright-report/\ncode/playwright/.cache/\ncode/bench-results/\n\n/packs\n.vite-inspect\n.nx/cache\n.nx/workspace-data\n!**/fixtures/**/yarn.lock\ncode/core/report\n\n*storybook.log\n\n.junie\nCLAUDE.local.md\n.claude\n.cursor/mcp.json\n.vscode/mcp.json\n.mcp.json\n.nx/polygraph"
  },
  {
    "path": ".husky/pre-commit",
    "content": "if [ -z \"$SKIP_STORYBOOK_GIT_HOOKS\" ]; then\n  yarn lint-staged\nfi\n"
  },
  {
    "path": ".lintstagedrc.mjs",
    "content": "import { detectAgent } from 'std-env';\n\nconst fmtCmd = detectAgent().name ? 'oxfmt' : 'oxfmt --check';\n\nexport default {\n  'code/**/*.{js,jsx,mjs,ts,tsx,html,json}': [fmtCmd, 'yarn --cwd code lint:js:cmd'],\n  'scripts/**/*.{html,js,json,jsx,mjs,ts,tsx}': ['yarn --cwd scripts lint:js:cmd'],\n  'docs/_snippets/**/*.{js,jsx,mjs,ts,tsx,html,json}': [fmtCmd],\n  '**/*.ejs': ['yarn --cwd scripts exec ejslint'],\n  '**/package.json': ['yarn --cwd scripts lint:package'],\n};\n"
  },
  {
    "path": ".mailmap",
    "content": "# --- instructions --- #\n\n# Add your account in this format:\nYour name here <yourname@example.com> # github:my-github-account, npm:my-npm-account, twitter:my-twitter-handle\n\n# supported:\n# github, npm, twitter, website\n\n# --- list ----------- #\n\nAaron Mc Adam <aaron@aaronmcadam.com>\nAruna Herath <aruna@kadira.io> <arunabherath@gmail.com>\nArunoda Susiripala <arunoda.susiripala@gmail.com>  Arunoda Susiripala <arunoda.susiripala@gmail.com>\nBenedikt D Valdez <benediktvaldez@users.noreply.github.com>  Benedikt D Valdez <benediktvaldez@users.noreply.github.com>\nDaniel Duan <dduan@squarespace.com> <dduan@yahoo.com> # github:danielduan, npm:danielduan, twitter:danduan\nDaniel James <daniel@thzinc.com> <djames@syncromatics.com>\nDanny Andrews <danny-andrews@users.noreply.github.com>  danny@ownlocal.com>\nDustin Kane <dkane@athenahealth.com> <dustinpkane@gmail.com>\nEli Sherer <eli.sherer@gmail.com>  elish <elish@payoneer.com>\nEvgeny Kochetkov <evgeny.kochetkov@me.com>  Evgeny Kochetkov <evgenykochetkov@users.noreply.github.com>\nFabien Bernard <fabien0102@hotmail.com>  Fabien BERNARD <fabien0102@hotmail.com>\nFernando Daciuk <f.daciuk@gmail.com> <fdaciuk@users.noreply.github.com>\nGert Hengeveld <info@ghengeveld.nl> <gert@chromatic.com>  # github:ghengeveld, npm:ghengeveld\nGreenkeeper <support@greenkeeper.io>  greenkeeper[bot] <greenkeeper[bot]@users.noreply.github.com>\nGreenkeeper <support@greenkeeper.io>  greenkeeperio-bot <support@greenkeeper.io>\nJason Schloer <jschloer@Jasons-Mac-Pro.local>  jschloer <jschloer@terragotech.com>\nJean-Michel Francois <jmfrancois@talend.com>  Jean-Michel FRANCOIS <jmfrancois@talend.com>\nJeff Carbonella <jeff.carbonella@gmail.com> <jeff@contactually.com>\nJeff Knaggs <jeef3@users.noreply.github.com> <mail@jeef3.com>\nJordan Gensler <jordan.gensler@airbnb.com> <jordangens@gmail.com>\nKanitkorn Sujautra <k.sujautra@gmail.com>  Kanitkorn S <lukyth@users.noreply.github.com>\nKent C. Dodds <kent@doddsfamily.us> <kent+github@doddsfamily.us>\nlarry <bshy522@gmail.com> <larry@yunify.com>\nMadushan Nishantha <j.l.madushan@gmail.com> <madushan1000@users.noreply.github.com>\nMarie-Laure Thuret <mthuret@users.noreply.github.com>  mthuret <marielaure.thuret@algolia.com>\nMax Hodges <max@whiterabbitjapan.com>  MaxHodges <max@whiterabbitjapan.com>\nMichael Shilman <shilman@lab80.co> <shilman@users.noreply.github.com>\nMichael Shilman <shilman@lab80.co> <michael@lab80.co>\nMuhammed Thanish <mnmtanish@gmail.com> <mnmtanish@users.noreply.github.com>\nNed Schwartz <ned@theinterned.net>  Ned Schwartz <ned@theinterned.net>\nJoe Nelson <Joe.Nelson@regence.com>  Nelson, Joe <Joe.Nelson@regence.com>\nNikolay Kozhuharenko <Nikolay.Kozhuharenko@gmail.com>  Nikolay <Nikolay.Kozhuharenko@gmail.com>\nNorbert de Langen <ndelangen@me.com>  # github:ndelangen, npm:ndelangen, twitter:norbertdelangen\nOleg Proskurin <regx@usul.su>  UsulPro <regx@usul.su>\nOrta <orta.therox@gmail.com>  orta <orta.therox@gmail.com>\nRitesh Kumar <ritz078@users.noreply.github.com>  Ritesh Kumar <rkritesh078@gmail.com>\nSylvain Bannier <sylvain.bannier@smile.fr>  Sylvain BANNIER <sylvain.bannier@smile.fr>\nTom Coleman <tom@percolatestudio.com>  Tom Coleman <tom@thesnail.org>\nTrevor Eyre <trevoreyre@gmail.com> # github:TrevorEyre, twitter:trevor_eyre\nWilliam Castandet <wcastand@gmail.com>  wcastand <wcastand@gmail.com>\nXavier Cazalot <xavier.cazalot@gmail.com>  xavcz <xavier.cazalot@gmail.com>\n"
  },
  {
    "path": ".nvmrc",
    "content": "22.22.1\n\n"
  },
  {
    "path": ".nx/workflows/agents.yaml",
    "content": "# copied from https://github.com/nrwl/nx-cloud-workflows/blob/main/launch-templates/linux.yaml\n# see https://github.com/nrwl/nx/blob/master/.nx/workflows/agents.yaml for inspiration\nlinux-init-steps: &linux-init-steps\n  - name: Checkout\n    uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml'\n  - name: Restore Node Modules Cache\n    uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'\n    inputs:\n      key: 'yarn.lock|.yarn/patches/**'\n      paths: |\n        ~/.yarn/berry\n      base-branch: 'next'\n  - name: Install Node\n    uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-node/main.yaml'\n  - name: Install Node Modules\n    script: |\n      yarn install --immutable\n\nlinux-browsers-init-steps: &linux-browsers-init-steps\n  - name: Checkout\n    uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml'\n  - name: Restore Node Modules Cache\n    uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'\n    inputs:\n      key: 'yarn.lock|.yarn/patches/**'\n      paths: |\n        ~/.yarn/berry\n      base-branch: 'next'\n  - name: Restore Browser Binary Cache\n    uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml'\n    inputs:\n      key: '\"browsers\"|yarn.lock|.yarn/patches/**'\n      paths: |\n        ~/.cache/ms-playwright\n      base-branch: 'next'\n  - name: Install Node\n    uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-node/main.yaml'\n  - name: Install Node Modules\n    script: |\n      yarn install --immutable\n  - name: Clean stale Storybook packages from yarn cache\n    # NX Cloud agents use the global yarn cache (enableGlobalCache: true) to\n    # avoid duplicating .yarn/cache across sandboxes. However, sandboxes install\n    # @storybook/* packages from a local verdaccio registry using the same\n    # version number but different contents on each run. The global cache may\n    # hold a stale copy from a previous pipeline, causing `yarn install` to\n    # silently use the published version instead of the local verdaccio build.\n    # Purging these entries forces yarn to fetch fresh copies from verdaccio.\n    # TODO: publish unique versions to verdaccio so this workaround is unnecessary.\n    script: |\n      rm -f ~/.yarn/berry/cache/storybook-npm-*.zip 2>/dev/null || true\n      rm -f ~/.yarn/berry/cache/@storybook-*.zip 2>/dev/null || true\n  - name: Install Browsers\n    script: |\n      yarn exec playwright install chromium --with-deps\n  - name: Verify\n    script: |\n      echo \"node:         $(node --version)\"\n      echo \"yarn:         $(yarn --version)\"\n      echo \"home:         $HOME\"\n      git diff --exit-code\n      yarn dedupe --check\n\ncommon-env-vars: &common-env-vars\n  STORYBOOK_DISABLE_TELEMETRY: true\n  IN_STORYBOOK_SANDBOX: true\n  STORYBOOK_SANDBOX_ROOT: ../storybook-sandboxes\n  STORYBOOK_NX_CLOUD_AGENT: true\n  CI: true\n  NODE_OPTIONS: --max_old_space_size=6144\n\nlaunch-templates:\n  linux-js:\n    # see for options: https://nx.dev/docs/reference/nx-cloud/launch-templates#launch-templatestemplate-nameresource-class\n    resource-class: 'docker_linux_amd64/extra_large+'\n    image: 'ubuntu22.04-node20.19-v2'\n    init-steps: *linux-init-steps\n    env: *common-env-vars\n  linux-browsers-js:\n    resource-class: 'docker_linux_amd64/extra_large+'\n    image: 'ubuntu22.04-node20.19-v2'\n    init-steps: *linux-browsers-init-steps\n    env: *common-env-vars\n  windows-js:\n    resource-class: 'windows/medium'\n    image: 'windows-2022'\n    # TODO init-steps:\n    env: *common-env-vars\n"
  },
  {
    "path": ".nx/workflows/distribution-config-daily.yaml",
    "content": "# Distribution config for daily/scheduled runs — more agents for faster throughput\ndistribute-on:\n  small-changeset: 15 linux-browsers-js, 1 linux-js\n  medium-changeset: 25 linux-browsers-js, 1 linux-js\n  large-changeset: 35 linux-browsers-js, 1 linux-js\n  extra-large-changeset: 59 linux-browsers-js, 1 linux-js\nassignment-rules:\n  - targets:\n      - compile\n    projects:\n      - core\n    run-on:\n      - agent: linux-js\n        parallelism: 1\n  - targets:\n      - compile\n    run-on:\n      - agent: linux-js\n        parallelism: 1\n      - agent: linux-browsers-js\n        parallelism: 1\n  - targets:\n      - check\n      - lint\n      - pretty-docs\n      - knip\n    run-on:\n      - agent: linux-js\n        parallelism: 6\n  - targets:\n      - '*'\n    run-on:\n      - agent: linux-browsers-js\n        parallelism: 1\n"
  },
  {
    "path": ".nx/workflows/distribution-config.yaml",
    "content": "# see https://github.com/nrwl/nx/blob/master/.nx/workflows/dynamic-changesets.yaml for inspiration\ndistribute-on:\n  small-changeset: 5 linux-browsers-js, 1 linux-js # Distribute on small if 1-25% of projects affected in PR\n  medium-changeset: 10 linux-browsers-js, 1 linux-js # Distribute on medium if 26-50% of projects affected in PR\n  large-changeset: 20 linux-browsers-js, 1 linux-js # Distribute on large if 51-75% of projects affected in PR\n  extra-large-changeset: 30 linux-browsers-js, 1 linux-js # Distribute on extra-large if 76-100% of projects affected in PR\nassignment-rules:\n  - targets:\n      - compile\n    projects:\n      - core\n    run-on:\n      - agent: linux-js\n        parallelism: 1\n  - targets:\n      - compile\n    run-on:\n      - agent: linux-js\n        parallelism: 1\n      - agent: linux-browsers-js\n        parallelism: 1\n  - targets:\n      - check\n      - lint\n      - knip\n    run-on:\n      - agent: linux-js\n        parallelism: 6\n  - targets:\n      - '*'\n    run-on:\n      - agent: linux-browsers-js\n        parallelism: 1\n"
  },
  {
    "path": ".oxfmtrc.json",
    "content": "{\n  \"$schema\": \"./node_modules/oxfmt/configuration_schema.json\",\n  \"printWidth\": 100,\n  \"tabWidth\": 2,\n  \"bracketSpacing\": true,\n  \"trailingComma\": \"es5\",\n  \"singleQuote\": true,\n  \"arrowParens\": \"always\",\n  \"sortPackageJson\": false,\n  \"ignorePatterns\": [\n    \"*.bundle.js\",\n    \"*.js.map\",\n    \".yarn\",\n    \".vscode\",\n    \".nx/cache\",\n    \".nx/workspace-data\",\n    \"dist\",\n    \"build\",\n    \"bench\",\n    \"coverage\",\n    \"node_modules\",\n    \"storybook-static\",\n    \"built-storybooks\",\n    \"ember-output\",\n    \"code/core/assets\",\n    \"code/core/report\",\n    \"code/core/src/core-server/presets/common-manager.ts\",\n    \"code/core/src/core-server/utils/__search-files-tests__\",\n    \"code/core/src/core-server/utils/__mockdata__/src/Empty.stories.ts\",\n    \"code/lib/codemod/src/transforms/__testfixtures__\",\n    \"code/frameworks/angular/template/**\",\n    \"code/lib/eslint-plugin\",\n    \"docs/versions/*.json\",\n    \".prettierrc\",\n    \"test-storybooks\",\n    \"*.yml\",\n    \"*.yaml\",\n    \"*.md\",\n    \"*.mdx\",\n    \"!docs/_snippets/**\"\n  ],\n  \"overrides\": [\n    {\n      \"files\": [\"docs/_snippets/**\"],\n      \"options\": {\n        \"trailingComma\": \"all\"\n      }\n    },\n    {\n      \"files\": [\"*.md\", \"*.mdx\"],\n      \"options\": {\n        \"importOrderSeparation\": false,\n        \"importOrderSortSpecifiers\": false\n      }\n    },\n    {\n      \"files\": [\"*.component.html\"],\n      \"options\": {\n        \"parser\": \"angular\"\n      }\n    },\n    {\n      \"files\": [\"**/frameworks/angular/src/**/*.ts\", \"**/frameworks/angular/template/**/*.ts\"],\n      \"options\": {\n        \"parser\": \"babel-ts\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": ".serena/.gitignore",
    "content": "/cache\n/project.local.yml\n"
  },
  {
    "path": ".serena/memories/project_overview.md",
    "content": "# Storybook - Project Overview\n\n## Purpose\nStorybook is an open-source UI development tool for building, testing, and documenting UI components in isolation.\nIt supports multiple frontend frameworks (React, Vue, Angular, Svelte, Web Components, Preact, Ember, HTML, etc.)\nand integrates with various build tools (Vite, Webpack5).\n\n## Version\nCurrent version: 10.2.x (as of March 2026)\n\n## Tech Stack\n- **Language**: TypeScript (strict mode), targeting ES2020\n- **Package Manager**: Yarn 4.10.3 (with workspaces)\n- **Node.js**: 22.21.1 (specified in `.nvmrc`)\n- **Monorepo Tool**: NX (with `--no-cloud` flag required to avoid NX Cloud login issues)\n- **Test Runner**: Vitest (primary), Playwright (E2E)\n- **Linting**: ESLint 8\n- **Formatting**: Oxfmt\n- **Bundlers**: Vite 7, Webpack 5, esbuild\n- **UI Libraries**: React 18, react-aria (use specific submodules, not root imports)\n- **Build System**: Custom build via `jiti ./scripts/build/build-package.ts`\n\n## Repository Structure\n```\nstorybook/\n├── code/                   # Main codebase\n│   ├── core/               # Core package (UI, API, manager, preview, server, etc.)\n│   ├── addons/             # Official addons (docs, controls, a11y, interactions, vitest, etc.)\n│   ├── builders/           # Build integrations (vite, webpack5, manager)\n│   ├── frameworks/         # Framework integrations (react-vite, nextjs, angular, vue3-vite, etc.)\n│   ├── renderers/          # Framework renderers (react, vue3, svelte, html, etc.)\n│   ├── lib/                # Shared libraries (cli, codemod, csf-tools, etc.)\n│   ├── presets/             # Preset packages\n│   ├── e2e-tests/          # Playwright E2E tests\n│   └── .storybook/         # Internal Storybook config (dogfooding)\n├── scripts/                # Build/CI/task scripts\n├── docs/                   # Documentation\n├── sandbox/                # Generated sandbox environments for testing\n└── test-storybooks/        # Test storybook configurations\n```\n\n## Key Packages\n- `@storybook/core` - Core functionality (UI, API, server, preview, channels, etc.)\n- `@storybook/react`, `@storybook/vue3`, etc. - Framework renderers\n- `@storybook/react-vite`, `@storybook/nextjs`, etc. - Framework integrations\n- `@storybook/addon-docs`, `@storybook/addon-a11y`, etc. - Official addons\n- `storybook` - CLI package\n- `create-storybook` - Project scaffolding\n"
  },
  {
    "path": ".serena/memories/style_and_conventions.md",
    "content": "# Code Style & Conventions\n\n## TypeScript\n- **Strict mode** enabled (`strict: true` in tsconfig)\n- Target: ES2020, Module: Preserve, ModuleResolution: bundler\n- `noImplicitAny: true`\n- JSX: preserve\n- No emit (handled by build tools, not tsc)\n\n## Prettier Configuration\n- Print width: 100\n- Tab width: 2\n- Single quotes: yes\n- Trailing commas: es5\n- Arrow parens: always\n- Brace style: 1tbs (one true brace style)\n- Import order (via @trivago/prettier-plugin-sort-imports):\n  1. `node:` builtins\n  2. `vitest`, `@testing-library`\n  3. `react`, `react-dom`\n  4. `storybook/internal`\n  5. `@storybook/[non-addon]`\n  6. `@storybook/addon-*`\n  7. Third-party modules\n  8. Relative imports (`./`, `../`)\n- Import order separation: yes (blank lines between groups)\n- Import specifiers sorted: yes\n\n## ESLint Rules (Notable)\n- `react-aria` and `react-stately`: must import from specific submodules (e.g., `@react-aria/overlays`), NOT root\n- `react-aria-components`: must use `react-aria-components/patched-dist/ComponentX` entrypoints for tree-shaking\n- `es-toolkit`: must use sub-exports (e.g., `es-toolkit/array`), NOT root import\n- `import-x/no-extraneous-dependencies`: off\n- `react/react-in-jsx-scope`: off\n- TypeScript `dot-notation` with `allowIndexSignaturePropertyAccess`\n- Custom local rules: `no-uncategorized-errors`, `storybook-monorepo-imports`, `no-duplicated-error-codes`\n\n## Naming Conventions\n- Files: kebab-case for most files (e.g., `my-component.ts`)\n- Components: PascalCase for React components\n- Types/Interfaces: PascalCase\n- Variables/functions: camelCase\n- Constants: UPPER_SNAKE_CASE for true constants, camelCase otherwise\n\n## Test Files\n- Pattern: `*.test.ts`, `*.test.tsx`, `*.spec.ts`, `*.spec.tsx`\n- Stories: `*.stories.ts`, `*.stories.tsx`\n- Test fixtures in `__testfixtures__/` directories\n- Tests in `__tests__/` directories or alongside source files\n\n## Monorepo Import Rules\n- Internal packages use `workspace:*` for dependencies\n- Custom ESLint rule `storybook-monorepo-imports` enforces correct import patterns within the monorepo\n"
  },
  {
    "path": ".serena/memories/suggested_commands.md",
    "content": "# Suggested Commands\n\n## Installation\n```bash\nyarn install          # Install all dependencies (from repo root)\n```\n\n## Building\n```bash\n# Compile a single package (always use --no-cloud to avoid NX Cloud issues)\nyarn nx compile core --no-cloud\nyarn nx compile @storybook/react --no-cloud\n\n# Compile all packages\nyarn nx run-many -t compile --no-cloud\n\n# Production build of a package\ncd code && yarn build\n```\n\n## Testing\n```bash\n# Run all unit tests (from repo root or code/)\ncd code && yarn test\n# or from root:\nyarn test\n\n# Run tests in watch mode\ncd code && yarn test:watch\n\n# Run specific test file\ncd code && yarn test:watch -- --project <project> <test-pattern>\n\n# E2E tests (Playwright)\ncd code && npx playwright test\n```\n\n## Linting & Formatting\n```bash\n# Run all linting\ncd code && yarn lint\n\n# Lint JS/TS only\ncd code && yarn lint:js\n\n# Format with Prettier\ncd code && yarn lint:prettier '**/*.{css,html,json,md,yml}'\n\n# Run knip (unused code detection)\ncd code && yarn knip\n```\n\n## Running the Internal Dev Storybook\n```bash\n# Must compile core first!\nyarn nx compile core --no-cloud\n\n# Then start the dev server (from code/ dir)\ncd code && yarn storybook:ui\n\n# Or with --ci flag (no interactive):\ncd code && yarn storybook:ui --ci\n\n# Build static storybook\ncd code && yarn storybook:ui:build\n```\n\n## Sandbox / Task System\n```bash\n# Start a sandbox with a specific template\nyarn start  # defaults to react-vite/default-ts\n\n# Run a task with a specific template\nyarn task --task dev --template react-vite/default-ts --start-from=install\n```\n\n## NX Commands\n```bash\n# Always use --no-cloud flag!\nyarn nx compile <package> --no-cloud\nyarn nx run-many -t compile --no-cloud\nyarn nx show projects --affected\n```\n\n## Git\n```bash\ngit status\ngit diff\ngit log --oneline -10\ngit checkout next   # main branch is \"next\"\n```\n\n## System Utilities (macOS/Darwin)\n```bash\nls, cd, pwd, cat, head, tail\ngrep, find, xargs\ncurl, wget\npython3, node\nopen <file>  # open in default app\npbcopy, pbpaste  # clipboard\n```\n"
  },
  {
    "path": ".serena/memories/task_completion_checklist.md",
    "content": "# Task Completion Checklist\n\nAfter completing a coding task, run through these steps:\n\n## 1. TypeScript Compilation\nEnsure the modified package(s) compile without errors:\n```bash\nyarn nx compile <package-name> --no-cloud\n```\n\n## 2. Linting\nRun lint on the changed files or the whole codebase:\n```bash\ncd code && yarn lint:js\n```\n\n## 3. Formatting\nEnsure code is properly formatted:\n```bash\ncd code && yarn lint:prettier '<changed-files>'\n```\n\n## 4. Unit Tests\nRun relevant tests:\n```bash\ncd code && yarn test <test-pattern>\n```\n\n## 5. Pre-commit Checks\nThe project uses husky + lint-staged for pre-commit hooks:\n- JS/TS files: ESLint with `--fix`\n- EJS files: ejslint\n- CSS/HTML/JSON/MD/YML: Prettier\n- package.json: lint:package\n\n## Notes\n- The main branch is `next` (not `main` or `master`)\n- Always use `--no-cloud` with NX commands\n- Before starting the dev server, ensure core is compiled: `yarn nx compile core --no-cloud`\n"
  },
  {
    "path": ".serena/project.yml",
    "content": "project_name: \"storybook\"\n\nlanguages:\n  - typescript\n\nencoding: \"utf-8\"\n\nignore_all_files_in_gitignore: true\nignored_paths: []\n\nread_only: false\n\nexcluded_tools: []\nincluded_optional_tools: []\nfixed_tools: []\n\nread_only_memory_patterns: []\n"
  },
  {
    "path": ".spelling",
    "content": "# markdown-spellcheck spelling configuration file\n# Format - lines beginning # are comments\n# global dictionary is at the start, file overrides afterwards\n# one word per line, to define a file override use ' - filename'\n# where filename is relative to this configuration file\naddon\naddons\napi\napollo\nbundlers\ncenter\ncentered\ncleanup\ncodemod\ncodemods\nCommonJS\nconfig\ncra\nCRNA\ndialog\nES2016\neslint\nEventEmitter\ngithub\nGraphiQL\ngraphql\nHMR\niframe\nIO\njavascript\njs\njscodeshift\nlerna\nlinkTo\nNode.js\nnpm\nonStory\nparams\npostmessage\nprerelease\nPRs\nrc\nREADME.md\nserializable\nsetOptions\nsetStories\nstorybook-ui\nstorybook.js.org\nstoryshots\nstoryshots'\nstyleguide-type\nstyleguides\nsvelte\nunisolated\nurl\nvue\nwebcomponents\nwebpack\nwebsocket\n"
  },
  {
    "path": ".vscode/extensions.json",
    "content": "{\n  \"recommendations\": [\n    \"dbaeumer.vscode-eslint\",\n    \"EditorConfig.EditorConfig\",\n    \"unifiedjs.vscode-mdx\",\n    \"yzhang.markdown-all-in-one\",\n    \"oxc.oxc-vscode\"\n  ]\n}"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": []\n}"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"[javascript][javascriptreact][typescript][typescriptreact][json][jsonc]\": {\n    \"editor.defaultFormatter\": \"oxc.oxc-vscode\",\n    \"editor.formatOnSave\": true\n  },\n  \"editor.codeActionsOnSave\": {\n    \"source.fixAll.eslint\": \"explicit\",\n    \"source.fixAll.oxc\": \"explicit\"\n  },\n  \"editor.formatOnSave\": true,\n  \"[mdx]\": {\n    \"editor.formatOnSave\": false\n  },\n  \"editor.tabSize\": 2,\n  \"eslint.options\": {\n    \"cache\": true,\n    \"cacheLocation\": \".cache/eslint\",\n    \"extensions\": [\n      \".js\",\n      \".jsx\",\n      \".mjs\",\n      \".json\",\n      \".ts\",\n      \".tsx\"\n    ]\n  },\n  \"eslint.useESLintClass\": true,\n  \"eslint.validate\": [\n    \"json\",\n    \"javascript\",\n    \"javascriptreact\",\n    \"html\",\n    \"typescript\",\n    \"typescriptreact\"\n  ],\n  \"eslint.workingDirectories\": [\n    \"./code\",\n    \"./scripts\"\n  ],\n  \"files.associations\": {\n    \"*.js\": \"javascriptreact\",\n    \".oxfmtrc.json\": \"json\"\n  },\n  \"javascript.preferences.importModuleSpecifier\": \"relative\",\n  \"javascript.preferences.quoteStyle\": \"single\",\n  \"js/ts.implicitProjectConfig.target\": \"ESNext\",\n  \"storyExplorer.storybookConfigDir\": \"./code/.storybook\",\n  \"typescript.format.enable\": false,\n  \"typescript.preferences.importModuleSpecifier\": \"relative\",\n  \"typescript.preferences.preferTypeOnlyAutoImports\": true,\n  \"typescript.preferences.quoteStyle\": \"single\",\n  \"typescript.preferGoToSourceDefinition\": true,\n  \"typescript.tsdk\": \"./node_modules/typescript/lib\",\n  \"vitest.workspaceConfig\": \"./code/vitest.workspace.ts\",\n  \"vitest.rootConfig\": \"./code/vitest.workspace.ts\",\n  \"oxc.fmt.configPath\": \".oxfmtrc.json\",\n  \"oxc.enable.oxlint\": false,\n}"
  },
  {
    "path": ".yarn/patches/@testing-library-user-event-npm-14.6.1-5da7e1d4e2.patch",
    "content": "diff --git a/dist/cjs/event/createEvent.js b/dist/cjs/event/createEvent.js\nindex b63c0093f492f5072ce2eabb74ca290144353548..5e68db5bb9f62aa43f1c849b185912b0b34021c8 100644\n--- a/dist/cjs/event/createEvent.js\n+++ b/dist/cjs/event/createEvent.js\n@@ -38,7 +38,16 @@ function createEvent(type, target, init) {\n     const window = getWindow.getWindow(target);\n     const { EventType, defaultInit } = eventMap.eventMap[type];\n     const event = new (getEventConstructors(window))[EventType](type, defaultInit);\n-    eventInitializer[EventType].forEach((f)=>f(event, init !== null && init !== undefined ? init : {}));\n+    var eventInit = {};\n+    for (var key in init) {\n+        if (Object.prototype.hasOwnProperty.call(init, key)) {\n+            eventInit[key] = init[key];\n+        }\n+    }\n+    eventInit.view = window;\n+    eventInitializer[EventType].forEach(function(f) {\n+        f(event, eventInit);\n+    });\n     return event;\n }\n /* istanbul ignore next */ function getEventConstructors(window) {\ndiff --git a/dist/cjs/utils/dataTransfer/Clipboard.js b/dist/cjs/utils/dataTransfer/Clipboard.js\nindex 434be791b156984a8b76287bc0cc6c8955df4203..e28a15e85e2dccff058a18b4b80b099b7016d688 100644\n--- a/dist/cjs/utils/dataTransfer/Clipboard.js\n+++ b/dist/cjs/utils/dataTransfer/Clipboard.js\n@@ -155,10 +155,18 @@ async function writeDataTransferToClipboard(document, clipboardData) {\n }\n const g = globalThis;\n /* istanbul ignore else */ if (typeof g.afterEach === 'function') {\n-    g.afterEach(()=>resetClipboardStubOnView(globalThis.window));\n+    g.afterEach(()=>{\n+        if(typeof globalThis.window !== 'undefined'){\n+            resetClipboardStubOnView(globalThis.window);\n+        }\n+    });\n }\n /* istanbul ignore else */ if (typeof g.afterAll === 'function') {\n-    g.afterAll(()=>detachClipboardStubFromView(globalThis.window));\n+    g.afterAll(()=>{\n+        if(typeof globalThis.window !== 'undefined'){\n+            detachClipboardStubFromView(globalThis.window);\n+        }\n+    });\n }\n \n exports.attachClipboardStubToView = attachClipboardStubToView;\ndiff --git a/dist/esm/event/createEvent.js b/dist/esm/event/createEvent.js\nindex 1c741ba446f40917727236e9e4ad29a20357d03a..9a4b63935923a9a271bfc9fd161fe7c477303256 100644\n--- a/dist/esm/event/createEvent.js\n+++ b/dist/esm/event/createEvent.js\n@@ -36,7 +36,16 @@ function createEvent(type, target, init) {\n     const window = getWindow(target);\n     const { EventType, defaultInit } = eventMap[type];\n     const event = new (getEventConstructors(window))[EventType](type, defaultInit);\n-    eventInitializer[EventType].forEach((f)=>f(event, init !== null && init !== undefined ? init : {}));\n+    var eventInit = {};\n+    for (var key in init) {\n+        if (Object.prototype.hasOwnProperty.call(init, key)) {\n+            eventInit[key] = init[key];\n+        }\n+    }\n+    eventInit.view = window;\n+    eventInitializer[EventType].forEach(function(f) {\n+        f(event, eventInit);\n+    });\n     return event;\n }\n /* istanbul ignore next */ function getEventConstructors(window) {\ndiff --git a/dist/esm/utils/dataTransfer/Clipboard.js b/dist/esm/utils/dataTransfer/Clipboard.js\nindex 2ed2676b52adaee045d2594b051c08a4b133e7df..337e644ed268ad4ad0ce9a601d6d0aec73264d5e 100644\n--- a/dist/esm/utils/dataTransfer/Clipboard.js\n+++ b/dist/esm/utils/dataTransfer/Clipboard.js\n@@ -153,10 +153,18 @@ async function writeDataTransferToClipboard(document, clipboardData) {\n }\n const g = globalThis;\n /* istanbul ignore else */ if (typeof g.afterEach === 'function') {\n-    g.afterEach(()=>resetClipboardStubOnView(globalThis.window));\n+    g.afterEach(()=>{\n+        if(typeof globalThis.window !== 'undefined'){\n+            resetClipboardStubOnView(globalThis.window);\n+        }\n+    });\n }\n /* istanbul ignore else */ if (typeof g.afterAll === 'function') {\n-    g.afterAll(()=>detachClipboardStubFromView(globalThis.window));\n+    g.afterAll(()=>{\n+        if(typeof globalThis.window !== 'undefined'){\n+            detachClipboardStubFromView(globalThis.window);\n+        }\n+    });\n }\n \n export { attachClipboardStubToView, createClipboardItem, detachClipboardStubFromView, readDataTransferFromClipboard, resetClipboardStubOnView, writeDataTransferToClipboard };\n"
  },
  {
    "path": ".yarn/patches/@types-babel__traverse-npm-7.20.6-fac4243243.patch",
    "content": "diff --git a/index.d.ts b/index.d.ts\nindex d6cccce88c306f0bd3c2ff529b0cdbda86a0d3e1..1d3f1b3f1c6a19cf8dffe490aaa097939d6f7f9a 100644\n--- a/index.d.ts\n+++ b/index.d.ts\n@@ -1,6 +1,6 @@\n import * as t from \"@babel/types\";\n-export import Node = t.Node;\n-export import RemovePropertiesOptions = t.RemovePropertiesOptions;\n+import { Node, RemovePropertiesOptions } from \"@babel/types\";\n+export { Node, RemovePropertiesOptions }\n \n declare const traverse: {\n     <S>(parent: Node, opts: TraverseOptions<S>, scope: Scope | undefined, state: S, parentPath?: NodePath): void;\n"
  },
  {
    "path": ".yarn/patches/@vitest-expect-npm-3.2.4-97c526d5cc.patch",
    "content": "diff --git a/dist/index.js b/dist/index.js\nindex db037119d94c99375829ae8b8c91e9a67a3ca845..4ebf87ff561d9d94af71e61cc52afe37f40a3c62 100644\n--- a/dist/index.js\n+++ b/dist/index.js\n@@ -6,7 +6,9 @@ import { processError } from '@vitest/utils/error';\n import { use, util } from 'chai';\n \n const MATCHERS_OBJECT = Symbol.for(\"matchers-object\");\n-const JEST_MATCHERS_OBJECT = Symbol.for(\"$$jest-matchers-object\");\n+// Patched this symbol for storybook, so that storybook/test can be used in a jest environment as well.\n+// Otherwise, vitest will override global jest matchers, and crash.\n+const JEST_MATCHERS_OBJECT = Symbol.for(\"$$jest-matchers-object-storybook\");\n const GLOBAL_EXPECT = Symbol.for(\"expect-global\");\n const ASYMMETRIC_MATCHERS_OBJECT = Symbol.for(\"asymmetric-matchers-object\");\n \n@@ -660,18 +662,22 @@ function getObjectSubset(object, subset, customTesters) {\n \n if (!Object.prototype.hasOwnProperty.call(globalThis, MATCHERS_OBJECT)) {\n \tconst globalState = new WeakMap();\n-\tconst matchers = Object.create(null);\n-\tconst customEqualityTesters = [];\n-\tconst asymmetricMatchers = Object.create(null);\n \tObject.defineProperty(globalThis, MATCHERS_OBJECT, { get: () => globalState });\n+}\n+if (!Object.prototype.hasOwnProperty.call(globalThis, JEST_MATCHERS_OBJECT)) {\n+  const matchers = Object.create(null);\n+  const customEqualityTesters = [];\n \tObject.defineProperty(globalThis, JEST_MATCHERS_OBJECT, {\n \t\tconfigurable: true,\n \t\tget: () => ({\n-\t\t\tstate: globalState.get(globalThis[GLOBAL_EXPECT]),\n+\t\t\tstate: globalThis[MATCHERS_OBJECT].get(globalThis[GLOBAL_EXPECT]),\n \t\t\tmatchers,\n \t\t\tcustomEqualityTesters\n \t\t})\n \t});\n+}\n+if (!Object.prototype.hasOwnProperty.call(globalThis, ASYMMETRIC_MATCHERS_OBJECT)) {\n+  const asymmetricMatchers = Object.create(null);\n \tObject.defineProperty(globalThis, ASYMMETRIC_MATCHERS_OBJECT, { get: () => asymmetricMatchers });\n }\n function getState(expect) {\n"
  },
  {
    "path": ".yarn/patches/react-aria-components-npm-1.12.2-6c5dcdafab.patch",
    "content": "diff --git a/dist/Button.mjs b/dist/Button.mjs\nindex cbc78bd98aa1b40634ff878b3039fd4aac636ce6..e5c8a179cf967d4a2e918535a3e23dcb1e53dd1d 100644\n--- a/dist/Button.mjs\n+++ b/dist/Button.mjs\n@@ -1,9 +1,11 @@\n import {useContextProps as $64fa3d84918910a7$export$29f1550f4b0d4415, useRenderProps as $64fa3d84918910a7$export$4d86445c2cf5e3} from \"./utils.mjs\";\n import {ProgressBarContext as $0393f8ab869a0f1a$export$e9f3bf65a26ce129} from \"./ProgressBar.mjs\";\n import {announce as $fM325$announce} from \"@react-aria/live-announcer\";\n-import {useButton as $fM325$useButton, useFocusRing as $fM325$useFocusRing, useHover as $fM325$useHover, useId as $fM325$useId, mergeProps as $fM325$mergeProps} from \"react-aria\";\n+import {useButton as $fM325$useButton} from \"@react-aria/button\";\n+import {useFocusRing as $fM325$useFocusRing} from \"@react-aria/focus\";\n+import {useHover as $fM325$useHover} from \"@react-aria/interactions\";\n+import {useId as $fM325$useId, mergeProps as $fM325$mergeProps, filterDOMProps as $fM325$filterDOMProps} from \"@react-aria/utils\";\n import {createHideableComponent as $fM325$createHideableComponent} from \"@react-aria/collections\";\n-import {filterDOMProps as $fM325$filterDOMProps} from \"@react-aria/utils\";\n import $fM325$react, {createContext as $fM325$createContext, useRef as $fM325$useRef, useEffect as $fM325$useEffect} from \"react\";\n \n /*\ndiff --git a/dist/Dialog.mjs b/dist/Dialog.mjs\nindex 58e616de102c40d6bc70d329fbf5115b48d114a8..4df96fc4ce7720caba20ea0b43fe1a8fa1a82f0b 100644\n--- a/dist/Dialog.mjs\n+++ b/dist/Dialog.mjs\n@@ -3,9 +3,12 @@ import {DEFAULT_SLOT as $64fa3d84918910a7$export$c62b8e45d58ddad9, Provider as $\n import {HeadingContext as $4e85f108e88277b8$export$d688439359537581} from \"./RSPContexts.mjs\";\n import {PopoverContext as $07b14b47974efb58$export$9b9a0cd73afb7ca4} from \"./Popover.mjs\";\n import {RootMenuTriggerStateContext as $3674c52c6b3c5bce$export$795aec4671cbae19} from \"./Menu.mjs\";\n-import {useOverlayTrigger as $6IYYA$useOverlayTrigger, useId as $6IYYA$useId, useDialog as $6IYYA$useDialog} from \"react-aria\";\n+// import {useOverlayTrigger as $6IYYA$useOverlayTrigger, useId as $6IYYA$useId, useDialog as $6IYYA$useDialog} from \"react-aria\";\n+import {useOverlayTrigger as $6IYYA$useOverlayTrigger} from \"@react-aria/overlays\";\n+import {useDialog as $6IYYA$useDialog} from \"@react-aria/dialog\";\n+import {useId as $6IYYA$useId} from \"@react-aria/utils\";\n import {useResizeObserver as $6IYYA$useResizeObserver, filterDOMProps as $6IYYA$filterDOMProps, mergeProps as $6IYYA$mergeProps} from \"@react-aria/utils\";\n-import {useMenuTriggerState as $6IYYA$useMenuTriggerState} from \"react-stately\";\n+import {useMenuTriggerState as $6IYYA$useMenuTriggerState} from \"@react-stately/menu\";\n import {PressResponder as $6IYYA$PressResponder} from \"@react-aria/interactions\";\n import $6IYYA$react, {createContext as $6IYYA$createContext, useRef as $6IYYA$useRef, useState as $6IYYA$useState, useCallback as $6IYYA$useCallback, forwardRef as $6IYYA$forwardRef, useContext as $6IYYA$useContext} from \"react\";\n \ndiff --git a/dist/Menu.mjs b/dist/Menu.mjs\nindex 97afd5048083b0b2384fecfa32813841097e1f50..dedd3e08f06c857a02918df94d49f14f378b0465 100644\n--- a/dist/Menu.mjs\n+++ b/dist/Menu.mjs\n@@ -7,10 +7,14 @@ import {OverlayTriggerStateContext as $de32f1b87079253c$export$d2f961adcb0afbe}\n import {PopoverContext as $07b14b47974efb58$export$9b9a0cd73afb7ca4} from \"./Popover.mjs\";\n import {SeparatorContext as $431f98aba6844401$export$6615d83f6de245ce} from \"./Separator.mjs\";\n import {TextContext as $514c0188e459b4c0$export$9afb8bc826b033ea} from \"./Text.mjs\";\n-import {useMenuTrigger as $kM2ZM$useMenuTrigger, useSubmenuTrigger as $kM2ZM$useSubmenuTrigger, useMenu as $kM2ZM$useMenu, FocusScope as $kM2ZM$FocusScope, mergeProps as $kM2ZM$mergeProps, useMenuSection as $kM2ZM$useMenuSection, useMenuItem as $kM2ZM$useMenuItem, useHover as $kM2ZM$useHover} from \"react-aria\";\n+import {useMenuTrigger as $kM2ZM$useMenuTrigger, useSubmenuTrigger as $kM2ZM$useSubmenuTrigger} from \"@react-aria/menu\";\n+import {useMenu as $kM2ZM$useMenu, useMenuSection as $kM2ZM$useMenuSection, useMenuItem as $kM2ZM$useMenuItem} from \"@react-aria/menu\";\n+import {FocusScope as $kM2ZM$FocusScope} from \"@react-aria/focus\";\n+import {mergeProps as $kM2ZM$mergeProps, useResizeObserver as $kM2ZM$useResizeObserver, useObjectRef as $kM2ZM$useObjectRef, filterDOMProps as $kM2ZM$filterDOMProps} from \"@react-aria/utils\";\n+import {useHover as $kM2ZM$useHover} from \"@react-aria/interactions\";\n import {CollectionNode as $kM2ZM$CollectionNode, createBranchComponent as $kM2ZM$createBranchComponent, CollectionBuilder as $kM2ZM$CollectionBuilder, Collection as $kM2ZM$Collection, SectionNode as $kM2ZM$SectionNode, createLeafComponent as $kM2ZM$createLeafComponent, ItemNode as $kM2ZM$ItemNode} from \"@react-aria/collections\";\n-import {useMenuTriggerState as $kM2ZM$useMenuTriggerState, useSubmenuTriggerState as $kM2ZM$useSubmenuTriggerState, useTreeState as $kM2ZM$useTreeState} from \"react-stately\";\n-import {useResizeObserver as $kM2ZM$useResizeObserver, useObjectRef as $kM2ZM$useObjectRef, filterDOMProps as $kM2ZM$filterDOMProps} from \"@react-aria/utils\";\n+import {useMenuTriggerState as $kM2ZM$useMenuTriggerState, useSubmenuTriggerState as $kM2ZM$useSubmenuTriggerState} from \"@react-stately/menu\";\n+import {useTreeState as $kM2ZM$useTreeState} from \"@react-stately/tree\";\n import {SelectionManager as $kM2ZM$SelectionManager, useMultipleSelectionState as $kM2ZM$useMultipleSelectionState} from \"@react-stately/selection\";\n import {PressResponder as $kM2ZM$PressResponder} from \"@react-aria/interactions\";\n import $kM2ZM$react, {createContext as $kM2ZM$createContext, useRef as $kM2ZM$useRef, useState as $kM2ZM$useState, useCallback as $kM2ZM$useCallback, useContext as $kM2ZM$useContext, forwardRef as $kM2ZM$forwardRef, useMemo as $kM2ZM$useMemo} from \"react\";\ndiff --git a/dist/Modal.mjs b/dist/Modal.mjs\nindex 124c3ee386ffb85864f38755af07c153b9d6fc35..59f68ddff9dbe6cda35a0185c916b20a7ed14106 100644\n--- a/dist/Modal.mjs\n+++ b/dist/Modal.mjs\n@@ -1,8 +1,10 @@\n import {Provider as $64fa3d84918910a7$export$2881499e37b75b9a, useContextProps as $64fa3d84918910a7$export$29f1550f4b0d4415, useRenderProps as $64fa3d84918910a7$export$4d86445c2cf5e3} from \"./utils.mjs\";\n import {OverlayTriggerStateContext as $de32f1b87079253c$export$d2f961adcb0afbe} from \"./Dialog.mjs\";\n-import {useIsSSR as $daTMi$useIsSSR, useModalOverlay as $daTMi$useModalOverlay, Overlay as $daTMi$Overlay, DismissButton as $daTMi$DismissButton} from \"react-aria\";\n+// import {useIsSSR as $daTMi$useIsSSR, useModalOverlay as $daTMi$useModalOverlay, Overlay as $daTMi$Overlay, DismissButton as $daTMi$DismissButton} from \"react-aria\";\n+import {useIsSSR as $daTMi$useIsSSR } from \"@react-aria/ssr\";\n+import {useModalOverlay as $daTMi$useModalOverlay, Overlay as $daTMi$Overlay, DismissButton as $daTMi$DismissButton} from \"@react-aria/overlays\";\n import {useObjectRef as $daTMi$useObjectRef, useExitAnimation as $daTMi$useExitAnimation, useEnterAnimation as $daTMi$useEnterAnimation, useViewportSize as $daTMi$useViewportSize, mergeProps as $daTMi$mergeProps, filterDOMProps as $daTMi$filterDOMProps, mergeRefs as $daTMi$mergeRefs} from \"@react-aria/utils\";\n-import {useOverlayTriggerState as $daTMi$useOverlayTriggerState} from \"react-stately\";\n+import {useOverlayTriggerState as $daTMi$useOverlayTriggerState} from \"@react-stately/overlays\";\n import $daTMi$react, {createContext as $daTMi$createContext, forwardRef as $daTMi$forwardRef, useContext as $daTMi$useContext, useRef as $daTMi$useRef, useMemo as $daTMi$useMemo} from \"react\";\n \n /*\ndiff --git a/dist/Popover.mjs b/dist/Popover.mjs\nindex 920cdb78159bb0b1c82a1cdd2d94957a23a3348d..6b644c20d6121b75446b647b9705f7e6cb9d6e75 100644\n--- a/dist/Popover.mjs\n+++ b/dist/Popover.mjs\n@@ -1,10 +1,11 @@\n import {useContextProps as $64fa3d84918910a7$export$29f1550f4b0d4415, useRenderProps as $64fa3d84918910a7$export$4d86445c2cf5e3} from \"./utils.mjs\";\n import {OverlayArrowContext as $44f671af83e7d9e0$export$2de4954e8ae13b9f} from \"./OverlayArrow.mjs\";\n import {OverlayTriggerStateContext as $de32f1b87079253c$export$d2f961adcb0afbe} from \"./Dialog.mjs\";\n-import {useLocale as $ehFet$useLocale, usePopover as $ehFet$usePopover, DismissButton as $ehFet$DismissButton, Overlay as $ehFet$Overlay} from \"react-aria\";\n+import {useLocale as $ehFet$useLocale} from \"@react-aria/i18n\";\n+import {usePopover as $ehFet$usePopover, DismissButton as $ehFet$DismissButton, Overlay as $ehFet$Overlay} from \"@react-aria/overlays\";\n import {useExitAnimation as $ehFet$useExitAnimation, useEnterAnimation as $ehFet$useEnterAnimation, useLayoutEffect as $ehFet$useLayoutEffect, mergeProps as $ehFet$mergeProps, filterDOMProps as $ehFet$filterDOMProps} from \"@react-aria/utils\";\n import {focusSafely as $ehFet$focusSafely} from \"@react-aria/interactions\";\n-import {useOverlayTriggerState as $ehFet$useOverlayTriggerState} from \"react-stately\";\n+import {useOverlayTriggerState as $ehFet$useOverlayTriggerState} from \"@react-stately/overlays\";\n import $ehFet$react, {createContext as $ehFet$createContext, forwardRef as $ehFet$forwardRef, useContext as $ehFet$useContext, useRef as $ehFet$useRef, useState as $ehFet$useState, useEffect as $ehFet$useEffect, useMemo as $ehFet$useMemo} from \"react\";\n import {useIsHidden as $ehFet$useIsHidden} from \"@react-aria/collections\";\n \ndiff --git a/dist/ProgressBar.mjs b/dist/ProgressBar.mjs\nindex 06d3286e3b287d5636f34bfd5c66a05054a51c81..3345b64094f7bf78f95179f00bb2e4500db60542 100644\n--- a/dist/ProgressBar.mjs\n+++ b/dist/ProgressBar.mjs\n@@ -1,6 +1,6 @@\n import {useContextProps as $64fa3d84918910a7$export$29f1550f4b0d4415, useRenderProps as $64fa3d84918910a7$export$4d86445c2cf5e3, useSlot as $64fa3d84918910a7$export$9d4c57ee4c6ffdd8} from \"./utils.mjs\";\n import {LabelContext as $01b77f81d0f07f68$export$75b6ee27786ba447} from \"./Label.mjs\";\n-import {useProgressBar as $hU2kz$useProgressBar} from \"react-aria\";\n+import {useProgressBar as $hU2kz$useProgressBar} from \"@react-aria/progress\";\n import {clamp as $hU2kz$clamp} from \"@react-stately/utils\";\n import {filterDOMProps as $hU2kz$filterDOMProps, mergeProps as $hU2kz$mergeProps} from \"@react-aria/utils\";\n import $hU2kz$react, {createContext as $hU2kz$createContext, forwardRef as $hU2kz$forwardRef} from \"react\";\ndiff --git a/dist/Separator.mjs b/dist/Separator.mjs\nindex 9989b084d7402c9dbee2b0a7dc4b72ea1462bf0e..8bd5e4e926f051db8efcb20a6794a7e27d606327 100644\n--- a/dist/Separator.mjs\n+++ b/dist/Separator.mjs\n@@ -1,5 +1,5 @@\n import {useContextProps as $64fa3d84918910a7$export$29f1550f4b0d4415} from \"./utils.mjs\";\n-import {useSeparator as $i9JCE$useSeparator} from \"react-aria\";\n+import {useSeparator as $i9JCE$useSeparator} from \"@react-aria/separator\";\n import {CollectionNode as $i9JCE$CollectionNode, createLeafComponent as $i9JCE$createLeafComponent} from \"@react-aria/collections\";\n import {filterDOMProps as $i9JCE$filterDOMProps, mergeProps as $i9JCE$mergeProps} from \"@react-aria/utils\";\n import $i9JCE$react, {createContext as $i9JCE$createContext} from \"react\";\ndiff --git a/dist/Tabs.mjs b/dist/Tabs.mjs\nindex 9d00500ac8fa5c5ae7db563fccc7a950b7070e53..1b27d380027f630e8329eda93176a19e635ebd66 100644\n--- a/dist/Tabs.mjs\n+++ b/dist/Tabs.mjs\n@@ -1,9 +1,13 @@\n import {CollectionRendererContext as $7135fc7d473fd974$export$4feb769f8ddf26c5, DefaultCollectionRenderer as $7135fc7d473fd974$export$a164736487e3f0ae, usePersistedKeys as $7135fc7d473fd974$export$90e00781bc59d8f9} from \"./Collection.mjs\";\n import {Provider as $64fa3d84918910a7$export$2881499e37b75b9a, useContextProps as $64fa3d84918910a7$export$29f1550f4b0d4415, useRenderProps as $64fa3d84918910a7$export$4d86445c2cf5e3, useSlottedContext as $64fa3d84918910a7$export$fabf2dc03a41866e} from \"./utils.mjs\";\n-import {useFocusRing as $7aSLZ$useFocusRing, mergeProps as $7aSLZ$mergeProps, useTabList as $7aSLZ$useTabList, useTab as $7aSLZ$useTab, useHover as $7aSLZ$useHover, useTabPanel as $7aSLZ$useTabPanel} from \"react-aria\";\n+// import {useFocusRing as $7aSLZ$useFocusRing, mergeProps as $7aSLZ$mergeProps, useTabList as $7aSLZ$useTabList, useTab as $7aSLZ$useTab, useHover as $7aSLZ$useHover, useTabPanel as $7aSLZ$useTabPanel} from \"react-aria\";\n+import {useFocusRing as $7aSLZ$useFocusRing} from \"@react-aria/focus\";\n+import {mergeProps as $7aSLZ$mergeProps } from \"@react-aria/utils\";\n+import {useTabList as $7aSLZ$useTabList, useTab as $7aSLZ$useTab, useTabPanel as $7aSLZ$useTabPanel} from \"@react-aria/tabs\";\n+import {useHover as $7aSLZ$useHover } from \"@react-aria/interactions\";\n import {CollectionBuilder as $7aSLZ$CollectionBuilder, Collection as $7aSLZ$Collection, CollectionNode as $7aSLZ$CollectionNode, createLeafComponent as $7aSLZ$createLeafComponent, createHideableComponent as $7aSLZ$createHideableComponent} from \"@react-aria/collections\";\n import {filterDOMProps as $7aSLZ$filterDOMProps, useObjectRef as $7aSLZ$useObjectRef, inertValue as $7aSLZ$inertValue} from \"@react-aria/utils\";\n-import {useTabListState as $7aSLZ$useTabListState} from \"react-stately\";\n+import {useTabListState as $7aSLZ$useTabListState} from \"@react-stately/tabs\";\n import $7aSLZ$react, {createContext as $7aSLZ$createContext, forwardRef as $7aSLZ$forwardRef, useMemo as $7aSLZ$useMemo, useContext as $7aSLZ$useContext} from \"react\";\n \n /*\ndiff --git a/dist/Tooltip.mjs b/dist/Tooltip.mjs\nindex 091fc6694595cb7d135155a76735f60b38922775..18bee4f45ee6c1c3d04e8d193f7629b230091bee 100644\n--- a/dist/Tooltip.mjs\n+++ b/dist/Tooltip.mjs\n@@ -1,9 +1,11 @@\n import {Provider as $64fa3d84918910a7$export$2881499e37b75b9a, useContextProps as $64fa3d84918910a7$export$29f1550f4b0d4415, useRenderProps as $64fa3d84918910a7$export$4d86445c2cf5e3} from \"./utils.mjs\";\n import {OverlayArrowContext as $44f671af83e7d9e0$export$2de4954e8ae13b9f} from \"./OverlayArrow.mjs\";\n-import {useTooltipTrigger as $cCslV$useTooltipTrigger, OverlayContainer as $cCslV$OverlayContainer, useOverlayPosition as $cCslV$useOverlayPosition, mergeProps as $cCslV$mergeProps, useTooltip as $cCslV$useTooltip} from \"react-aria\";\n-import {useExitAnimation as $cCslV$useExitAnimation, useEnterAnimation as $cCslV$useEnterAnimation, filterDOMProps as $cCslV$filterDOMProps} from \"@react-aria/utils\";\n+import {useTooltipTrigger as $cCslV$useTooltipTrigger} from \"@react-aria/tooltip\";\n+import {OverlayContainer as $cCslV$OverlayContainer, useOverlayPosition as $cCslV$useOverlayPosition} from \"@react-aria/overlays\";\n+import {mergeProps as $cCslV$mergeProps, useExitAnimation as $cCslV$useExitAnimation, useEnterAnimation as $cCslV$useEnterAnimation, filterDOMProps as $cCslV$filterDOMProps} from \"@react-aria/utils\";\n+import {useTooltip as $cCslV$useTooltip} from \"@react-aria/tooltip\";\n import {FocusableProvider as $cCslV$FocusableProvider} from \"@react-aria/focus\";\n-import {useTooltipTriggerState as $cCslV$useTooltipTriggerState} from \"react-stately\";\n+import {useTooltipTriggerState as $cCslV$useTooltipTriggerState} from \"@react-stately/tooltip\";\n import $cCslV$react, {createContext as $cCslV$createContext, useRef as $cCslV$useRef, forwardRef as $cCslV$forwardRef, useContext as $cCslV$useContext} from \"react\";\n \n /*\ndiff --git a/package.json b/package.json\nindex d3c48ef42b0d1374487a32ada1f1451ddcc4b0bd..356135b3598fc7a788d2fac161de25ea9409d432 100644\n--- a/package.json\n+++ b/package.json\n@@ -26,6 +26,10 @@\n       \"types\": \"./i18n/lang.d.ts\",\n       \"import\": \"./i18n/*.mjs\",\n       \"require\": \"./i18n/*.js\"\n+    },\n+    \"./patched-dist/*\": {\n+      \"import\": \"./dist/*.mjs\",\n+      \"types\": \"./dist/types.d.ts\"\n     }\n   },\n   \"files\": [\n"
  },
  {
    "path": ".yarn/releases/yarn-4.10.3.cjs",
    "content": "#!/usr/bin/env node\n/* eslint-disable */\n//prettier-ignore\n(()=>{var DGe=Object.create;var dU=Object.defineProperty;var PGe=Object.getOwnPropertyDescriptor;var bGe=Object.getOwnPropertyNames;var xGe=Object.getPrototypeOf,kGe=Object.prototype.hasOwnProperty;var Ie=(t=>typeof require<\"u\"?require:typeof Proxy<\"u\"?new Proxy(t,{get:(e,r)=>(typeof require<\"u\"?require:e)[r]}):t)(function(t){if(typeof require<\"u\")return require.apply(this,arguments);throw Error('Dynamic require of \"'+t+'\" is not supported')});var Ze=(t,e)=>()=>(t&&(e=t(t=0)),e);var _=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),Vt=(t,e)=>{for(var r in e)dU(t,r,{get:e[r],enumerable:!0})},QGe=(t,e,r,s)=>{if(e&&typeof e==\"object\"||typeof e==\"function\")for(let a of bGe(e))!kGe.call(t,a)&&a!==r&&dU(t,a,{get:()=>e[a],enumerable:!(s=PGe(e,a))||s.enumerable});return t};var ut=(t,e,r)=>(r=t!=null?DGe(xGe(t)):{},QGe(e||!t||!t.__esModule?dU(r,\"default\",{value:t,enumerable:!0}):r,t));var fi={};Vt(fi,{SAFE_TIME:()=>HX,S_IFDIR:()=>Jb,S_IFLNK:()=>Kb,S_IFMT:()=>Mf,S_IFREG:()=>N2});var Mf,Jb,N2,Kb,HX,jX=Ze(()=>{Mf=61440,Jb=16384,N2=32768,Kb=40960,HX=456789e3});var or={};Vt(or,{EBADF:()=>Mo,EBUSY:()=>RGe,EEXIST:()=>MGe,EINVAL:()=>FGe,EISDIR:()=>LGe,ENOENT:()=>NGe,ENOSYS:()=>TGe,ENOTDIR:()=>OGe,ENOTEMPTY:()=>_Ge,EOPNOTSUPP:()=>HGe,EROFS:()=>UGe,ERR_DIR_CLOSED:()=>mU});function Cc(t,e){return Object.assign(new Error(`${t}: ${e}`),{code:t})}function RGe(t){return Cc(\"EBUSY\",t)}function TGe(t,e){return Cc(\"ENOSYS\",`${t}, ${e}`)}function FGe(t){return Cc(\"EINVAL\",`invalid argument, ${t}`)}function Mo(t){return Cc(\"EBADF\",`bad file descriptor, ${t}`)}function NGe(t){return Cc(\"ENOENT\",`no such file or directory, ${t}`)}function OGe(t){return Cc(\"ENOTDIR\",`not a directory, ${t}`)}function LGe(t){return Cc(\"EISDIR\",`illegal operation on a directory, ${t}`)}function MGe(t){return Cc(\"EEXIST\",`file already exists, ${t}`)}function UGe(t){return Cc(\"EROFS\",`read-only filesystem, ${t}`)}function _Ge(t){return Cc(\"ENOTEMPTY\",`directory not empty, ${t}`)}function HGe(t){return Cc(\"EOPNOTSUPP\",`operation not supported, ${t}`)}function mU(){return Cc(\"ERR_DIR_CLOSED\",\"Directory handle was closed\")}var zb=Ze(()=>{});var $a={};Vt($a,{BigIntStatsEntry:()=>iE,DEFAULT_MODE:()=>IU,DirEntry:()=>yU,StatEntry:()=>nE,areStatsEqual:()=>CU,clearStats:()=>Zb,convertToBigIntStats:()=>GGe,makeDefaultStats:()=>GX,makeEmptyStats:()=>jGe});function GX(){return new nE}function jGe(){return Zb(GX())}function Zb(t){for(let e in t)if(Object.hasOwn(t,e)){let r=t[e];typeof r==\"number\"?t[e]=0:typeof r==\"bigint\"?t[e]=BigInt(0):EU.types.isDate(r)&&(t[e]=new Date(0))}return t}function GGe(t){let e=new iE;for(let r in t)if(Object.hasOwn(t,r)){let s=t[r];typeof s==\"number\"?e[r]=BigInt(s):EU.types.isDate(s)&&(e[r]=new Date(s))}return e.atimeNs=e.atimeMs*BigInt(1e6),e.mtimeNs=e.mtimeMs*BigInt(1e6),e.ctimeNs=e.ctimeMs*BigInt(1e6),e.birthtimeNs=e.birthtimeMs*BigInt(1e6),e}function CU(t,e){if(t.atimeMs!==e.atimeMs||t.birthtimeMs!==e.birthtimeMs||t.blksize!==e.blksize||t.blocks!==e.blocks||t.ctimeMs!==e.ctimeMs||t.dev!==e.dev||t.gid!==e.gid||t.ino!==e.ino||t.isBlockDevice()!==e.isBlockDevice()||t.isCharacterDevice()!==e.isCharacterDevice()||t.isDirectory()!==e.isDirectory()||t.isFIFO()!==e.isFIFO()||t.isFile()!==e.isFile()||t.isSocket()!==e.isSocket()||t.isSymbolicLink()!==e.isSymbolicLink()||t.mode!==e.mode||t.mtimeMs!==e.mtimeMs||t.nlink!==e.nlink||t.rdev!==e.rdev||t.size!==e.size||t.uid!==e.uid)return!1;let r=t,s=e;return!(r.atimeNs!==s.atimeNs||r.mtimeNs!==s.mtimeNs||r.ctimeNs!==s.ctimeNs||r.birthtimeNs!==s.birthtimeNs)}var EU,IU,yU,nE,iE,wU=Ze(()=>{EU=ut(Ie(\"util\")),IU=33188,yU=class{constructor(){this.name=\"\";this.path=\"\";this.mode=0}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){return(this.mode&61440)===16384}isFIFO(){return!1}isFile(){return(this.mode&61440)===32768}isSocket(){return!1}isSymbolicLink(){return(this.mode&61440)===40960}},nE=class{constructor(){this.uid=0;this.gid=0;this.size=0;this.blksize=0;this.atimeMs=0;this.mtimeMs=0;this.ctimeMs=0;this.birthtimeMs=0;this.atime=new Date(0);this.mtime=new Date(0);this.ctime=new Date(0);this.birthtime=new Date(0);this.dev=0;this.ino=0;this.mode=IU;this.nlink=1;this.rdev=0;this.blocks=1}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){return(this.mode&61440)===16384}isFIFO(){return!1}isFile(){return(this.mode&61440)===32768}isSocket(){return!1}isSymbolicLink(){return(this.mode&61440)===40960}},iE=class{constructor(){this.uid=BigInt(0);this.gid=BigInt(0);this.size=BigInt(0);this.blksize=BigInt(0);this.atimeMs=BigInt(0);this.mtimeMs=BigInt(0);this.ctimeMs=BigInt(0);this.birthtimeMs=BigInt(0);this.atimeNs=BigInt(0);this.mtimeNs=BigInt(0);this.ctimeNs=BigInt(0);this.birthtimeNs=BigInt(0);this.atime=new Date(0);this.mtime=new Date(0);this.ctime=new Date(0);this.birthtime=new Date(0);this.dev=BigInt(0);this.ino=BigInt(0);this.mode=BigInt(IU);this.nlink=BigInt(1);this.rdev=BigInt(0);this.blocks=BigInt(1)}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){return(this.mode&BigInt(61440))===BigInt(16384)}isFIFO(){return!1}isFile(){return(this.mode&BigInt(61440))===BigInt(32768)}isSocket(){return!1}isSymbolicLink(){return(this.mode&BigInt(61440))===BigInt(40960)}}});function JGe(t){let e,r;if(e=t.match(YGe))t=e[1];else if(r=t.match(VGe))t=`\\\\\\\\${r[1]?\".\\\\\":\"\"}${r[2]}`;else return t;return t.replace(/\\//g,\"\\\\\")}function KGe(t){t=t.replace(/\\\\/g,\"/\");let e,r;return(e=t.match(qGe))?t=`/${e[1]}`:(r=t.match(WGe))&&(t=`/unc/${r[1]?\".dot/\":\"\"}${r[2]}`),t}function Xb(t,e){return t===fe?WX(e):BU(e)}var O2,vt,Er,fe,J,qX,qGe,WGe,YGe,VGe,BU,WX,el=Ze(()=>{O2=ut(Ie(\"path\")),vt={root:\"/\",dot:\".\",parent:\"..\"},Er={home:\"~\",nodeModules:\"node_modules\",manifest:\"package.json\",lockfile:\"yarn.lock\",virtual:\"__virtual__\",pnpJs:\".pnp.js\",pnpCjs:\".pnp.cjs\",pnpData:\".pnp.data.json\",pnpEsmLoader:\".pnp.loader.mjs\",rc:\".yarnrc.yml\",env:\".env\"},fe=Object.create(O2.default),J=Object.create(O2.default.posix);fe.cwd=()=>process.cwd();J.cwd=process.platform===\"win32\"?()=>BU(process.cwd()):process.cwd;process.platform===\"win32\"&&(J.resolve=(...t)=>t.length>0&&J.isAbsolute(t[0])?O2.default.posix.resolve(...t):O2.default.posix.resolve(J.cwd(),...t));qX=function(t,e,r){return e=t.normalize(e),r=t.normalize(r),e===r?\".\":(e.endsWith(t.sep)||(e=e+t.sep),r.startsWith(e)?r.slice(e.length):null)};fe.contains=(t,e)=>qX(fe,t,e);J.contains=(t,e)=>qX(J,t,e);qGe=/^([a-zA-Z]:.*)$/,WGe=/^\\/\\/(\\.\\/)?(.*)$/,YGe=/^\\/([a-zA-Z]:.*)$/,VGe=/^\\/unc\\/(\\.dot\\/)?(.*)$/;BU=process.platform===\"win32\"?KGe:t=>t,WX=process.platform===\"win32\"?JGe:t=>t;fe.fromPortablePath=WX;fe.toPortablePath=BU});async function $b(t,e){let r=\"0123456789abcdef\";await t.mkdirPromise(e.indexPath,{recursive:!0});let s=[];for(let a of r)for(let n of r)s.push(t.mkdirPromise(t.pathUtils.join(e.indexPath,`${a}${n}`),{recursive:!0}));return await Promise.all(s),e.indexPath}async function YX(t,e,r,s,a){let n=t.pathUtils.normalize(e),c=r.pathUtils.normalize(s),f=[],p=[],{atime:h,mtime:E}=a.stableTime?{atime:dd,mtime:dd}:await r.lstatPromise(c);await t.mkdirpPromise(t.pathUtils.dirname(e),{utimes:[h,E]}),await vU(f,p,t,n,r,c,{...a,didParentExist:!0});for(let C of f)await C();await Promise.all(p.map(C=>C()))}async function vU(t,e,r,s,a,n,c){let f=c.didParentExist?await VX(r,s):null,p=await a.lstatPromise(n),{atime:h,mtime:E}=c.stableTime?{atime:dd,mtime:dd}:p,C;switch(!0){case p.isDirectory():C=await ZGe(t,e,r,s,f,a,n,p,c);break;case p.isFile():C=await eqe(t,e,r,s,f,a,n,p,c);break;case p.isSymbolicLink():C=await tqe(t,e,r,s,f,a,n,p,c);break;default:throw new Error(`Unsupported file type (${p.mode})`)}return(c.linkStrategy?.type!==\"HardlinkFromIndex\"||!p.isFile())&&((C||f?.mtime?.getTime()!==E.getTime()||f?.atime?.getTime()!==h.getTime())&&(e.push(()=>r.lutimesPromise(s,h,E)),C=!0),(f===null||(f.mode&511)!==(p.mode&511))&&(e.push(()=>r.chmodPromise(s,p.mode&511)),C=!0)),C}async function VX(t,e){try{return await t.lstatPromise(e)}catch{return null}}async function ZGe(t,e,r,s,a,n,c,f,p){if(a!==null&&!a.isDirectory())if(p.overwrite)t.push(async()=>r.removePromise(s)),a=null;else return!1;let h=!1;a===null&&(t.push(async()=>{try{await r.mkdirPromise(s,{mode:f.mode})}catch(S){if(S.code!==\"EEXIST\")throw S}}),h=!0);let E=await n.readdirPromise(c),C=p.didParentExist&&!a?{...p,didParentExist:!1}:p;if(p.stableSort)for(let S of E.sort())await vU(t,e,r,r.pathUtils.join(s,S),n,n.pathUtils.join(c,S),C)&&(h=!0);else(await Promise.all(E.map(async b=>{await vU(t,e,r,r.pathUtils.join(s,b),n,n.pathUtils.join(c,b),C)}))).some(b=>b)&&(h=!0);return h}async function XGe(t,e,r,s,a,n,c,f,p,h){let E=await n.checksumFilePromise(c,{algorithm:\"sha1\"}),C=420,S=f.mode&511,b=`${E}${S!==C?S.toString(8):\"\"}`,I=r.pathUtils.join(h.indexPath,E.slice(0,2),`${b}.dat`),T;(le=>(le[le.Lock=0]=\"Lock\",le[le.Rename=1]=\"Rename\"))(T||={});let N=1,U=await VX(r,I);if(a){let ie=U&&a.dev===U.dev&&a.ino===U.ino,ue=U?.mtimeMs!==zGe;if(ie&&ue&&h.autoRepair&&(N=0,U=null),!ie)if(p.overwrite)t.push(async()=>r.removePromise(s)),a=null;else return!1}let W=!U&&N===1?`${I}.${Math.floor(Math.random()*4294967296).toString(16).padStart(8,\"0\")}`:null,ee=!1;return t.push(async()=>{if(!U&&(N===0&&await r.lockPromise(I,async()=>{let ie=await n.readFilePromise(c);await r.writeFilePromise(I,ie)}),N===1&&W)){let ie=await n.readFilePromise(c);await r.writeFilePromise(W,ie);try{await r.linkPromise(W,I)}catch(ue){if(ue.code===\"EEXIST\")ee=!0,await r.unlinkPromise(W);else throw ue}}a||await r.linkPromise(I,s)}),e.push(async()=>{U||(await r.lutimesPromise(I,dd,dd),S!==C&&await r.chmodPromise(I,S)),W&&!ee&&await r.unlinkPromise(W)}),!1}async function $Ge(t,e,r,s,a,n,c,f,p){if(a!==null)if(p.overwrite)t.push(async()=>r.removePromise(s)),a=null;else return!1;return t.push(async()=>{let h=await n.readFilePromise(c);await r.writeFilePromise(s,h)}),!0}async function eqe(t,e,r,s,a,n,c,f,p){return p.linkStrategy?.type===\"HardlinkFromIndex\"?XGe(t,e,r,s,a,n,c,f,p,p.linkStrategy):$Ge(t,e,r,s,a,n,c,f,p)}async function tqe(t,e,r,s,a,n,c,f,p){if(a!==null)if(p.overwrite)t.push(async()=>r.removePromise(s)),a=null;else return!1;return t.push(async()=>{await r.symlinkPromise(Xb(r.pathUtils,await n.readlinkPromise(c)),s)}),!0}var dd,zGe,SU=Ze(()=>{el();dd=new Date(456789e3*1e3),zGe=dd.getTime()});function ex(t,e,r,s){let a=()=>{let n=r.shift();if(typeof n>\"u\")return null;let c=t.pathUtils.join(e,n);return Object.assign(t.statSync(c),{name:n,path:void 0})};return new L2(e,a,s)}var L2,JX=Ze(()=>{zb();L2=class{constructor(e,r,s={}){this.path=e;this.nextDirent=r;this.opts=s;this.closed=!1}throwIfClosed(){if(this.closed)throw mU()}async*[Symbol.asyncIterator](){try{let e;for(;(e=await this.read())!==null;)yield e}finally{await this.close()}}read(e){let r=this.readSync();return typeof e<\"u\"?e(null,r):Promise.resolve(r)}readSync(){return this.throwIfClosed(),this.nextDirent()}close(e){return this.closeSync(),typeof e<\"u\"?e(null):Promise.resolve()}closeSync(){this.throwIfClosed(),this.opts.onClose?.(),this.closed=!0}}});function KX(t,e){if(t!==e)throw new Error(`Invalid StatWatcher status: expected '${e}', got '${t}'`)}var zX,tx,ZX=Ze(()=>{zX=Ie(\"events\");wU();tx=class t extends zX.EventEmitter{constructor(r,s,{bigint:a=!1}={}){super();this.status=\"ready\";this.changeListeners=new Map;this.startTimeout=null;this.fakeFs=r,this.path=s,this.bigint=a,this.lastStats=this.stat()}static create(r,s,a){let n=new t(r,s,a);return n.start(),n}start(){KX(this.status,\"ready\"),this.status=\"running\",this.startTimeout=setTimeout(()=>{this.startTimeout=null,this.fakeFs.existsSync(this.path)||this.emit(\"change\",this.lastStats,this.lastStats)},3)}stop(){KX(this.status,\"running\"),this.status=\"stopped\",this.startTimeout!==null&&(clearTimeout(this.startTimeout),this.startTimeout=null),this.emit(\"stop\")}stat(){try{return this.fakeFs.statSync(this.path,{bigint:this.bigint})}catch{let r=this.bigint?new iE:new nE;return Zb(r)}}makeInterval(r){let s=setInterval(()=>{let a=this.stat(),n=this.lastStats;CU(a,n)||(this.lastStats=a,this.emit(\"change\",a,n))},r.interval);return r.persistent?s:s.unref()}registerChangeListener(r,s){this.addListener(\"change\",r),this.changeListeners.set(r,this.makeInterval(s))}unregisterChangeListener(r){this.removeListener(\"change\",r);let s=this.changeListeners.get(r);typeof s<\"u\"&&clearInterval(s),this.changeListeners.delete(r)}unregisterAllChangeListeners(){for(let r of this.changeListeners.keys())this.unregisterChangeListener(r)}hasChangeListeners(){return this.changeListeners.size>0}ref(){for(let r of this.changeListeners.values())r.ref();return this}unref(){for(let r of this.changeListeners.values())r.unref();return this}}});function sE(t,e,r,s){let a,n,c,f;switch(typeof r){case\"function\":a=!1,n=!0,c=5007,f=r;break;default:({bigint:a=!1,persistent:n=!0,interval:c=5007}=r),f=s;break}let p=rx.get(t);typeof p>\"u\"&&rx.set(t,p=new Map);let h=p.get(e);return typeof h>\"u\"&&(h=tx.create(t,e,{bigint:a}),p.set(e,h)),h.registerChangeListener(f,{persistent:n,interval:c}),h}function md(t,e,r){let s=rx.get(t);if(typeof s>\"u\")return;let a=s.get(e);typeof a>\"u\"||(typeof r>\"u\"?a.unregisterAllChangeListeners():a.unregisterChangeListener(r),a.hasChangeListeners()||(a.stop(),s.delete(e)))}function yd(t){let e=rx.get(t);if(!(typeof e>\"u\"))for(let r of e.keys())md(t,r)}var rx,DU=Ze(()=>{ZX();rx=new WeakMap});function rqe(t){let e=t.match(/\\r?\\n/g);if(e===null)return $X.EOL;let r=e.filter(a=>a===`\\r\n`).length,s=e.length-r;return r>s?`\\r\n`:`\n`}function Ed(t,e){return e.replace(/\\r?\\n/g,rqe(t))}var XX,$X,mp,Uf,Id=Ze(()=>{XX=Ie(\"crypto\"),$X=Ie(\"os\");SU();el();mp=class{constructor(e){this.pathUtils=e}async*genTraversePromise(e,{stableSort:r=!1}={}){let s=[e];for(;s.length>0;){let a=s.shift();if((await this.lstatPromise(a)).isDirectory()){let c=await this.readdirPromise(a);if(r)for(let f of c.sort())s.push(this.pathUtils.join(a,f));else throw new Error(\"Not supported\")}else yield a}}async checksumFilePromise(e,{algorithm:r=\"sha512\"}={}){let s=await this.openPromise(e,\"r\");try{let n=Buffer.allocUnsafeSlow(65536),c=(0,XX.createHash)(r),f=0;for(;(f=await this.readPromise(s,n,0,65536))!==0;)c.update(f===65536?n:n.slice(0,f));return c.digest(\"hex\")}finally{await this.closePromise(s)}}async removePromise(e,{recursive:r=!0,maxRetries:s=5}={}){let a;try{a=await this.lstatPromise(e)}catch(n){if(n.code===\"ENOENT\")return;throw n}if(a.isDirectory()){if(r){let n=await this.readdirPromise(e);await Promise.all(n.map(c=>this.removePromise(this.pathUtils.resolve(e,c))))}for(let n=0;n<=s;n++)try{await this.rmdirPromise(e);break}catch(c){if(c.code!==\"EBUSY\"&&c.code!==\"ENOTEMPTY\")throw c;n<s&&await new Promise(f=>setTimeout(f,n*100))}}else await this.unlinkPromise(e)}removeSync(e,{recursive:r=!0}={}){let s;try{s=this.lstatSync(e)}catch(a){if(a.code===\"ENOENT\")return;throw a}if(s.isDirectory()){if(r)for(let a of this.readdirSync(e))this.removeSync(this.pathUtils.resolve(e,a));this.rmdirSync(e)}else this.unlinkSync(e)}async mkdirpPromise(e,{chmod:r,utimes:s}={}){if(e=this.resolve(e),e===this.pathUtils.dirname(e))return;let a=e.split(this.pathUtils.sep),n;for(let c=2;c<=a.length;++c){let f=a.slice(0,c).join(this.pathUtils.sep);if(!this.existsSync(f)){try{await this.mkdirPromise(f)}catch(p){if(p.code===\"EEXIST\")continue;throw p}if(n??=f,r!=null&&await this.chmodPromise(f,r),s!=null)await this.utimesPromise(f,s[0],s[1]);else{let p=await this.statPromise(this.pathUtils.dirname(f));await this.utimesPromise(f,p.atime,p.mtime)}}}return n}mkdirpSync(e,{chmod:r,utimes:s}={}){if(e=this.resolve(e),e===this.pathUtils.dirname(e))return;let a=e.split(this.pathUtils.sep),n;for(let c=2;c<=a.length;++c){let f=a.slice(0,c).join(this.pathUtils.sep);if(!this.existsSync(f)){try{this.mkdirSync(f)}catch(p){if(p.code===\"EEXIST\")continue;throw p}if(n??=f,r!=null&&this.chmodSync(f,r),s!=null)this.utimesSync(f,s[0],s[1]);else{let p=this.statSync(this.pathUtils.dirname(f));this.utimesSync(f,p.atime,p.mtime)}}}return n}async copyPromise(e,r,{baseFs:s=this,overwrite:a=!0,stableSort:n=!1,stableTime:c=!1,linkStrategy:f=null}={}){return await YX(this,e,s,r,{overwrite:a,stableSort:n,stableTime:c,linkStrategy:f})}copySync(e,r,{baseFs:s=this,overwrite:a=!0}={}){let n=s.lstatSync(r),c=this.existsSync(e);if(n.isDirectory()){this.mkdirpSync(e);let p=s.readdirSync(r);for(let h of p)this.copySync(this.pathUtils.join(e,h),s.pathUtils.join(r,h),{baseFs:s,overwrite:a})}else if(n.isFile()){if(!c||a){c&&this.removeSync(e);let p=s.readFileSync(r);this.writeFileSync(e,p)}}else if(n.isSymbolicLink()){if(!c||a){c&&this.removeSync(e);let p=s.readlinkSync(r);this.symlinkSync(Xb(this.pathUtils,p),e)}}else throw new Error(`Unsupported file type (file: ${r}, mode: 0o${n.mode.toString(8).padStart(6,\"0\")})`);let f=n.mode&511;this.chmodSync(e,f)}async changeFilePromise(e,r,s={}){return Buffer.isBuffer(r)?this.changeFileBufferPromise(e,r,s):this.changeFileTextPromise(e,r,s)}async changeFileBufferPromise(e,r,{mode:s}={}){let a=Buffer.alloc(0);try{a=await this.readFilePromise(e)}catch{}Buffer.compare(a,r)!==0&&await this.writeFilePromise(e,r,{mode:s})}async changeFileTextPromise(e,r,{automaticNewlines:s,mode:a}={}){let n=\"\";try{n=await this.readFilePromise(e,\"utf8\")}catch{}let c=s?Ed(n,r):r;n!==c&&await this.writeFilePromise(e,c,{mode:a})}changeFileSync(e,r,s={}){return Buffer.isBuffer(r)?this.changeFileBufferSync(e,r,s):this.changeFileTextSync(e,r,s)}changeFileBufferSync(e,r,{mode:s}={}){let a=Buffer.alloc(0);try{a=this.readFileSync(e)}catch{}Buffer.compare(a,r)!==0&&this.writeFileSync(e,r,{mode:s})}changeFileTextSync(e,r,{automaticNewlines:s=!1,mode:a}={}){let n=\"\";try{n=this.readFileSync(e,\"utf8\")}catch{}let c=s?Ed(n,r):r;n!==c&&this.writeFileSync(e,c,{mode:a})}async movePromise(e,r){try{await this.renamePromise(e,r)}catch(s){if(s.code===\"EXDEV\")await this.copyPromise(r,e),await this.removePromise(e);else throw s}}moveSync(e,r){try{this.renameSync(e,r)}catch(s){if(s.code===\"EXDEV\")this.copySync(r,e),this.removeSync(e);else throw s}}async lockPromise(e,r){let s=`${e}.flock`,a=1e3/60,n=Date.now(),c=null,f=async()=>{let p;try{[p]=await this.readJsonPromise(s)}catch{return Date.now()-n<500}try{return process.kill(p,0),!0}catch{return!1}};for(;c===null;)try{c=await this.openPromise(s,\"wx\")}catch(p){if(p.code===\"EEXIST\"){if(!await f())try{await this.unlinkPromise(s);continue}catch{}if(Date.now()-n<60*1e3)await new Promise(h=>setTimeout(h,a));else throw new Error(`Couldn't acquire a lock in a reasonable time (via ${s})`)}else throw p}await this.writePromise(c,JSON.stringify([process.pid]));try{return await r()}finally{try{await this.closePromise(c),await this.unlinkPromise(s)}catch{}}}async readJsonPromise(e){let r=await this.readFilePromise(e,\"utf8\");try{return JSON.parse(r)}catch(s){throw s.message+=` (in ${e})`,s}}readJsonSync(e){let r=this.readFileSync(e,\"utf8\");try{return JSON.parse(r)}catch(s){throw s.message+=` (in ${e})`,s}}async writeJsonPromise(e,r,{compact:s=!1}={}){let a=s?0:2;return await this.writeFilePromise(e,`${JSON.stringify(r,null,a)}\n`)}writeJsonSync(e,r,{compact:s=!1}={}){let a=s?0:2;return this.writeFileSync(e,`${JSON.stringify(r,null,a)}\n`)}async preserveTimePromise(e,r){let s=await this.lstatPromise(e),a=await r();typeof a<\"u\"&&(e=a),await this.lutimesPromise(e,s.atime,s.mtime)}async preserveTimeSync(e,r){let s=this.lstatSync(e),a=r();typeof a<\"u\"&&(e=a),this.lutimesSync(e,s.atime,s.mtime)}},Uf=class extends mp{constructor(){super(J)}}});var _s,yp=Ze(()=>{Id();_s=class extends mp{getExtractHint(e){return this.baseFs.getExtractHint(e)}resolve(e){return this.mapFromBase(this.baseFs.resolve(this.mapToBase(e)))}getRealPath(){return this.mapFromBase(this.baseFs.getRealPath())}async openPromise(e,r,s){return this.baseFs.openPromise(this.mapToBase(e),r,s)}openSync(e,r,s){return this.baseFs.openSync(this.mapToBase(e),r,s)}async opendirPromise(e,r){return Object.assign(await this.baseFs.opendirPromise(this.mapToBase(e),r),{path:e})}opendirSync(e,r){return Object.assign(this.baseFs.opendirSync(this.mapToBase(e),r),{path:e})}async readPromise(e,r,s,a,n){return await this.baseFs.readPromise(e,r,s,a,n)}readSync(e,r,s,a,n){return this.baseFs.readSync(e,r,s,a,n)}async writePromise(e,r,s,a,n){return typeof r==\"string\"?await this.baseFs.writePromise(e,r,s):await this.baseFs.writePromise(e,r,s,a,n)}writeSync(e,r,s,a,n){return typeof r==\"string\"?this.baseFs.writeSync(e,r,s):this.baseFs.writeSync(e,r,s,a,n)}async closePromise(e){return this.baseFs.closePromise(e)}closeSync(e){this.baseFs.closeSync(e)}createReadStream(e,r){return this.baseFs.createReadStream(e!==null?this.mapToBase(e):e,r)}createWriteStream(e,r){return this.baseFs.createWriteStream(e!==null?this.mapToBase(e):e,r)}async realpathPromise(e){return this.mapFromBase(await this.baseFs.realpathPromise(this.mapToBase(e)))}realpathSync(e){return this.mapFromBase(this.baseFs.realpathSync(this.mapToBase(e)))}async existsPromise(e){return this.baseFs.existsPromise(this.mapToBase(e))}existsSync(e){return this.baseFs.existsSync(this.mapToBase(e))}accessSync(e,r){return this.baseFs.accessSync(this.mapToBase(e),r)}async accessPromise(e,r){return this.baseFs.accessPromise(this.mapToBase(e),r)}async statPromise(e,r){return this.baseFs.statPromise(this.mapToBase(e),r)}statSync(e,r){return this.baseFs.statSync(this.mapToBase(e),r)}async fstatPromise(e,r){return this.baseFs.fstatPromise(e,r)}fstatSync(e,r){return this.baseFs.fstatSync(e,r)}lstatPromise(e,r){return this.baseFs.lstatPromise(this.mapToBase(e),r)}lstatSync(e,r){return this.baseFs.lstatSync(this.mapToBase(e),r)}async fchmodPromise(e,r){return this.baseFs.fchmodPromise(e,r)}fchmodSync(e,r){return this.baseFs.fchmodSync(e,r)}async chmodPromise(e,r){return this.baseFs.chmodPromise(this.mapToBase(e),r)}chmodSync(e,r){return this.baseFs.chmodSync(this.mapToBase(e),r)}async fchownPromise(e,r,s){return this.baseFs.fchownPromise(e,r,s)}fchownSync(e,r,s){return this.baseFs.fchownSync(e,r,s)}async chownPromise(e,r,s){return this.baseFs.chownPromise(this.mapToBase(e),r,s)}chownSync(e,r,s){return this.baseFs.chownSync(this.mapToBase(e),r,s)}async renamePromise(e,r){return this.baseFs.renamePromise(this.mapToBase(e),this.mapToBase(r))}renameSync(e,r){return this.baseFs.renameSync(this.mapToBase(e),this.mapToBase(r))}async copyFilePromise(e,r,s=0){return this.baseFs.copyFilePromise(this.mapToBase(e),this.mapToBase(r),s)}copyFileSync(e,r,s=0){return this.baseFs.copyFileSync(this.mapToBase(e),this.mapToBase(r),s)}async appendFilePromise(e,r,s){return this.baseFs.appendFilePromise(this.fsMapToBase(e),r,s)}appendFileSync(e,r,s){return this.baseFs.appendFileSync(this.fsMapToBase(e),r,s)}async writeFilePromise(e,r,s){return this.baseFs.writeFilePromise(this.fsMapToBase(e),r,s)}writeFileSync(e,r,s){return this.baseFs.writeFileSync(this.fsMapToBase(e),r,s)}async unlinkPromise(e){return this.baseFs.unlinkPromise(this.mapToBase(e))}unlinkSync(e){return this.baseFs.unlinkSync(this.mapToBase(e))}async utimesPromise(e,r,s){return this.baseFs.utimesPromise(this.mapToBase(e),r,s)}utimesSync(e,r,s){return this.baseFs.utimesSync(this.mapToBase(e),r,s)}async lutimesPromise(e,r,s){return this.baseFs.lutimesPromise(this.mapToBase(e),r,s)}lutimesSync(e,r,s){return this.baseFs.lutimesSync(this.mapToBase(e),r,s)}async mkdirPromise(e,r){return this.baseFs.mkdirPromise(this.mapToBase(e),r)}mkdirSync(e,r){return this.baseFs.mkdirSync(this.mapToBase(e),r)}async rmdirPromise(e,r){return this.baseFs.rmdirPromise(this.mapToBase(e),r)}rmdirSync(e,r){return this.baseFs.rmdirSync(this.mapToBase(e),r)}async rmPromise(e,r){return this.baseFs.rmPromise(this.mapToBase(e),r)}rmSync(e,r){return this.baseFs.rmSync(this.mapToBase(e),r)}async linkPromise(e,r){return this.baseFs.linkPromise(this.mapToBase(e),this.mapToBase(r))}linkSync(e,r){return this.baseFs.linkSync(this.mapToBase(e),this.mapToBase(r))}async symlinkPromise(e,r,s){let a=this.mapToBase(r);if(this.pathUtils.isAbsolute(e))return this.baseFs.symlinkPromise(this.mapToBase(e),a,s);let n=this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(r),e)),c=this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(a),n);return this.baseFs.symlinkPromise(c,a,s)}symlinkSync(e,r,s){let a=this.mapToBase(r);if(this.pathUtils.isAbsolute(e))return this.baseFs.symlinkSync(this.mapToBase(e),a,s);let n=this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(r),e)),c=this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(a),n);return this.baseFs.symlinkSync(c,a,s)}async readFilePromise(e,r){return this.baseFs.readFilePromise(this.fsMapToBase(e),r)}readFileSync(e,r){return this.baseFs.readFileSync(this.fsMapToBase(e),r)}readdirPromise(e,r){return this.baseFs.readdirPromise(this.mapToBase(e),r)}readdirSync(e,r){return this.baseFs.readdirSync(this.mapToBase(e),r)}async readlinkPromise(e){return this.mapFromBase(await this.baseFs.readlinkPromise(this.mapToBase(e)))}readlinkSync(e){return this.mapFromBase(this.baseFs.readlinkSync(this.mapToBase(e)))}async truncatePromise(e,r){return this.baseFs.truncatePromise(this.mapToBase(e),r)}truncateSync(e,r){return this.baseFs.truncateSync(this.mapToBase(e),r)}async ftruncatePromise(e,r){return this.baseFs.ftruncatePromise(e,r)}ftruncateSync(e,r){return this.baseFs.ftruncateSync(e,r)}watch(e,r,s){return this.baseFs.watch(this.mapToBase(e),r,s)}watchFile(e,r,s){return this.baseFs.watchFile(this.mapToBase(e),r,s)}unwatchFile(e,r){return this.baseFs.unwatchFile(this.mapToBase(e),r)}fsMapToBase(e){return typeof e==\"number\"?e:this.mapToBase(e)}}});var _f,e$=Ze(()=>{yp();_f=class extends _s{constructor(e,{baseFs:r,pathUtils:s}){super(s),this.target=e,this.baseFs=r}getRealPath(){return this.target}getBaseFs(){return this.baseFs}mapFromBase(e){return e}mapToBase(e){return e}}});function t$(t){let e=t;return typeof t.path==\"string\"&&(e.path=fe.toPortablePath(t.path)),e}var r$,Yn,Cd=Ze(()=>{r$=ut(Ie(\"fs\"));Id();el();Yn=class extends Uf{constructor(e=r$.default){super(),this.realFs=e}getExtractHint(){return!1}getRealPath(){return vt.root}resolve(e){return J.resolve(e)}async openPromise(e,r,s){return await new Promise((a,n)=>{this.realFs.open(fe.fromPortablePath(e),r,s,this.makeCallback(a,n))})}openSync(e,r,s){return this.realFs.openSync(fe.fromPortablePath(e),r,s)}async opendirPromise(e,r){return await new Promise((s,a)=>{typeof r<\"u\"?this.realFs.opendir(fe.fromPortablePath(e),r,this.makeCallback(s,a)):this.realFs.opendir(fe.fromPortablePath(e),this.makeCallback(s,a))}).then(s=>{let a=s;return Object.defineProperty(a,\"path\",{value:e,configurable:!0,writable:!0}),a})}opendirSync(e,r){let a=typeof r<\"u\"?this.realFs.opendirSync(fe.fromPortablePath(e),r):this.realFs.opendirSync(fe.fromPortablePath(e));return Object.defineProperty(a,\"path\",{value:e,configurable:!0,writable:!0}),a}async readPromise(e,r,s=0,a=0,n=-1){return await new Promise((c,f)=>{this.realFs.read(e,r,s,a,n,(p,h)=>{p?f(p):c(h)})})}readSync(e,r,s,a,n){return this.realFs.readSync(e,r,s,a,n)}async writePromise(e,r,s,a,n){return await new Promise((c,f)=>typeof r==\"string\"?this.realFs.write(e,r,s,this.makeCallback(c,f)):this.realFs.write(e,r,s,a,n,this.makeCallback(c,f)))}writeSync(e,r,s,a,n){return typeof r==\"string\"?this.realFs.writeSync(e,r,s):this.realFs.writeSync(e,r,s,a,n)}async closePromise(e){await new Promise((r,s)=>{this.realFs.close(e,this.makeCallback(r,s))})}closeSync(e){this.realFs.closeSync(e)}createReadStream(e,r){let s=e!==null?fe.fromPortablePath(e):e;return this.realFs.createReadStream(s,r)}createWriteStream(e,r){let s=e!==null?fe.fromPortablePath(e):e;return this.realFs.createWriteStream(s,r)}async realpathPromise(e){return await new Promise((r,s)=>{this.realFs.realpath(fe.fromPortablePath(e),{},this.makeCallback(r,s))}).then(r=>fe.toPortablePath(r))}realpathSync(e){return fe.toPortablePath(this.realFs.realpathSync(fe.fromPortablePath(e),{}))}async existsPromise(e){return await new Promise(r=>{this.realFs.exists(fe.fromPortablePath(e),r)})}accessSync(e,r){return this.realFs.accessSync(fe.fromPortablePath(e),r)}async accessPromise(e,r){return await new Promise((s,a)=>{this.realFs.access(fe.fromPortablePath(e),r,this.makeCallback(s,a))})}existsSync(e){return this.realFs.existsSync(fe.fromPortablePath(e))}async statPromise(e,r){return await new Promise((s,a)=>{r?this.realFs.stat(fe.fromPortablePath(e),r,this.makeCallback(s,a)):this.realFs.stat(fe.fromPortablePath(e),this.makeCallback(s,a))})}statSync(e,r){return r?this.realFs.statSync(fe.fromPortablePath(e),r):this.realFs.statSync(fe.fromPortablePath(e))}async fstatPromise(e,r){return await new Promise((s,a)=>{r?this.realFs.fstat(e,r,this.makeCallback(s,a)):this.realFs.fstat(e,this.makeCallback(s,a))})}fstatSync(e,r){return r?this.realFs.fstatSync(e,r):this.realFs.fstatSync(e)}async lstatPromise(e,r){return await new Promise((s,a)=>{r?this.realFs.lstat(fe.fromPortablePath(e),r,this.makeCallback(s,a)):this.realFs.lstat(fe.fromPortablePath(e),this.makeCallback(s,a))})}lstatSync(e,r){return r?this.realFs.lstatSync(fe.fromPortablePath(e),r):this.realFs.lstatSync(fe.fromPortablePath(e))}async fchmodPromise(e,r){return await new Promise((s,a)=>{this.realFs.fchmod(e,r,this.makeCallback(s,a))})}fchmodSync(e,r){return this.realFs.fchmodSync(e,r)}async chmodPromise(e,r){return await new Promise((s,a)=>{this.realFs.chmod(fe.fromPortablePath(e),r,this.makeCallback(s,a))})}chmodSync(e,r){return this.realFs.chmodSync(fe.fromPortablePath(e),r)}async fchownPromise(e,r,s){return await new Promise((a,n)=>{this.realFs.fchown(e,r,s,this.makeCallback(a,n))})}fchownSync(e,r,s){return this.realFs.fchownSync(e,r,s)}async chownPromise(e,r,s){return await new Promise((a,n)=>{this.realFs.chown(fe.fromPortablePath(e),r,s,this.makeCallback(a,n))})}chownSync(e,r,s){return this.realFs.chownSync(fe.fromPortablePath(e),r,s)}async renamePromise(e,r){return await new Promise((s,a)=>{this.realFs.rename(fe.fromPortablePath(e),fe.fromPortablePath(r),this.makeCallback(s,a))})}renameSync(e,r){return this.realFs.renameSync(fe.fromPortablePath(e),fe.fromPortablePath(r))}async copyFilePromise(e,r,s=0){return await new Promise((a,n)=>{this.realFs.copyFile(fe.fromPortablePath(e),fe.fromPortablePath(r),s,this.makeCallback(a,n))})}copyFileSync(e,r,s=0){return this.realFs.copyFileSync(fe.fromPortablePath(e),fe.fromPortablePath(r),s)}async appendFilePromise(e,r,s){return await new Promise((a,n)=>{let c=typeof e==\"string\"?fe.fromPortablePath(e):e;s?this.realFs.appendFile(c,r,s,this.makeCallback(a,n)):this.realFs.appendFile(c,r,this.makeCallback(a,n))})}appendFileSync(e,r,s){let a=typeof e==\"string\"?fe.fromPortablePath(e):e;s?this.realFs.appendFileSync(a,r,s):this.realFs.appendFileSync(a,r)}async writeFilePromise(e,r,s){return await new Promise((a,n)=>{let c=typeof e==\"string\"?fe.fromPortablePath(e):e;s?this.realFs.writeFile(c,r,s,this.makeCallback(a,n)):this.realFs.writeFile(c,r,this.makeCallback(a,n))})}writeFileSync(e,r,s){let a=typeof e==\"string\"?fe.fromPortablePath(e):e;s?this.realFs.writeFileSync(a,r,s):this.realFs.writeFileSync(a,r)}async unlinkPromise(e){return await new Promise((r,s)=>{this.realFs.unlink(fe.fromPortablePath(e),this.makeCallback(r,s))})}unlinkSync(e){return this.realFs.unlinkSync(fe.fromPortablePath(e))}async utimesPromise(e,r,s){return await new Promise((a,n)=>{this.realFs.utimes(fe.fromPortablePath(e),r,s,this.makeCallback(a,n))})}utimesSync(e,r,s){this.realFs.utimesSync(fe.fromPortablePath(e),r,s)}async lutimesPromise(e,r,s){return await new Promise((a,n)=>{this.realFs.lutimes(fe.fromPortablePath(e),r,s,this.makeCallback(a,n))})}lutimesSync(e,r,s){this.realFs.lutimesSync(fe.fromPortablePath(e),r,s)}async mkdirPromise(e,r){return await new Promise((s,a)=>{this.realFs.mkdir(fe.fromPortablePath(e),r,this.makeCallback(s,a))})}mkdirSync(e,r){return this.realFs.mkdirSync(fe.fromPortablePath(e),r)}async rmdirPromise(e,r){return await new Promise((s,a)=>{r?this.realFs.rmdir(fe.fromPortablePath(e),r,this.makeCallback(s,a)):this.realFs.rmdir(fe.fromPortablePath(e),this.makeCallback(s,a))})}rmdirSync(e,r){return this.realFs.rmdirSync(fe.fromPortablePath(e),r)}async rmPromise(e,r){return await new Promise((s,a)=>{r?this.realFs.rm(fe.fromPortablePath(e),r,this.makeCallback(s,a)):this.realFs.rm(fe.fromPortablePath(e),this.makeCallback(s,a))})}rmSync(e,r){return this.realFs.rmSync(fe.fromPortablePath(e),r)}async linkPromise(e,r){return await new Promise((s,a)=>{this.realFs.link(fe.fromPortablePath(e),fe.fromPortablePath(r),this.makeCallback(s,a))})}linkSync(e,r){return this.realFs.linkSync(fe.fromPortablePath(e),fe.fromPortablePath(r))}async symlinkPromise(e,r,s){return await new Promise((a,n)=>{this.realFs.symlink(fe.fromPortablePath(e.replace(/\\/+$/,\"\")),fe.fromPortablePath(r),s,this.makeCallback(a,n))})}symlinkSync(e,r,s){return this.realFs.symlinkSync(fe.fromPortablePath(e.replace(/\\/+$/,\"\")),fe.fromPortablePath(r),s)}async readFilePromise(e,r){return await new Promise((s,a)=>{let n=typeof e==\"string\"?fe.fromPortablePath(e):e;this.realFs.readFile(n,r,this.makeCallback(s,a))})}readFileSync(e,r){let s=typeof e==\"string\"?fe.fromPortablePath(e):e;return this.realFs.readFileSync(s,r)}async readdirPromise(e,r){return await new Promise((s,a)=>{r?r.recursive&&process.platform===\"win32\"?r.withFileTypes?this.realFs.readdir(fe.fromPortablePath(e),r,this.makeCallback(n=>s(n.map(t$)),a)):this.realFs.readdir(fe.fromPortablePath(e),r,this.makeCallback(n=>s(n.map(fe.toPortablePath)),a)):this.realFs.readdir(fe.fromPortablePath(e),r,this.makeCallback(s,a)):this.realFs.readdir(fe.fromPortablePath(e),this.makeCallback(s,a))})}readdirSync(e,r){return r?r.recursive&&process.platform===\"win32\"?r.withFileTypes?this.realFs.readdirSync(fe.fromPortablePath(e),r).map(t$):this.realFs.readdirSync(fe.fromPortablePath(e),r).map(fe.toPortablePath):this.realFs.readdirSync(fe.fromPortablePath(e),r):this.realFs.readdirSync(fe.fromPortablePath(e))}async readlinkPromise(e){return await new Promise((r,s)=>{this.realFs.readlink(fe.fromPortablePath(e),this.makeCallback(r,s))}).then(r=>fe.toPortablePath(r))}readlinkSync(e){return fe.toPortablePath(this.realFs.readlinkSync(fe.fromPortablePath(e)))}async truncatePromise(e,r){return await new Promise((s,a)=>{this.realFs.truncate(fe.fromPortablePath(e),r,this.makeCallback(s,a))})}truncateSync(e,r){return this.realFs.truncateSync(fe.fromPortablePath(e),r)}async ftruncatePromise(e,r){return await new Promise((s,a)=>{this.realFs.ftruncate(e,r,this.makeCallback(s,a))})}ftruncateSync(e,r){return this.realFs.ftruncateSync(e,r)}watch(e,r,s){return this.realFs.watch(fe.fromPortablePath(e),r,s)}watchFile(e,r,s){return this.realFs.watchFile(fe.fromPortablePath(e),r,s)}unwatchFile(e,r){return this.realFs.unwatchFile(fe.fromPortablePath(e),r)}makeCallback(e,r){return(s,a)=>{s?r(s):e(a)}}}});var Sn,n$=Ze(()=>{Cd();yp();el();Sn=class extends _s{constructor(e,{baseFs:r=new Yn}={}){super(J),this.target=this.pathUtils.normalize(e),this.baseFs=r}getRealPath(){return this.pathUtils.resolve(this.baseFs.getRealPath(),this.target)}resolve(e){return this.pathUtils.isAbsolute(e)?J.normalize(e):this.baseFs.resolve(J.join(this.target,e))}mapFromBase(e){return e}mapToBase(e){return this.pathUtils.isAbsolute(e)?e:this.pathUtils.join(this.target,e)}}});var i$,Hf,s$=Ze(()=>{Cd();yp();el();i$=vt.root,Hf=class extends _s{constructor(e,{baseFs:r=new Yn}={}){super(J),this.target=this.pathUtils.resolve(vt.root,e),this.baseFs=r}getRealPath(){return this.pathUtils.resolve(this.baseFs.getRealPath(),this.pathUtils.relative(vt.root,this.target))}getTarget(){return this.target}getBaseFs(){return this.baseFs}mapToBase(e){let r=this.pathUtils.normalize(e);if(this.pathUtils.isAbsolute(e))return this.pathUtils.resolve(this.target,this.pathUtils.relative(i$,e));if(r.match(/^\\.\\.\\/?/))throw new Error(`Resolving this path (${e}) would escape the jail`);return this.pathUtils.resolve(this.target,e)}mapFromBase(e){return this.pathUtils.resolve(i$,this.pathUtils.relative(this.target,e))}}});var oE,o$=Ze(()=>{yp();oE=class extends _s{constructor(r,s){super(s);this.instance=null;this.factory=r}get baseFs(){return this.instance||(this.instance=this.factory()),this.instance}set baseFs(r){this.instance=r}mapFromBase(r){return r}mapToBase(r){return r}}});var wd,tl,e0,a$=Ze(()=>{wd=Ie(\"fs\");Id();Cd();DU();zb();el();tl=4278190080,e0=class extends Uf{constructor({baseFs:r=new Yn,filter:s=null,magicByte:a=42,maxOpenFiles:n=1/0,useCache:c=!0,maxAge:f=5e3,typeCheck:p=wd.constants.S_IFREG,getMountPoint:h,factoryPromise:E,factorySync:C}){if(Math.floor(a)!==a||!(a>1&&a<=127))throw new Error(\"The magic byte must be set to a round value between 1 and 127 included\");super();this.fdMap=new Map;this.nextFd=3;this.isMount=new Set;this.notMount=new Set;this.realPaths=new Map;this.limitOpenFilesTimeout=null;this.baseFs=r,this.mountInstances=c?new Map:null,this.factoryPromise=E,this.factorySync=C,this.filter=s,this.getMountPoint=h,this.magic=a<<24,this.maxAge=f,this.maxOpenFiles=n,this.typeCheck=p}getExtractHint(r){return this.baseFs.getExtractHint(r)}getRealPath(){return this.baseFs.getRealPath()}saveAndClose(){if(yd(this),this.mountInstances)for(let[r,{childFs:s}]of this.mountInstances.entries())s.saveAndClose?.(),this.mountInstances.delete(r)}discardAndClose(){if(yd(this),this.mountInstances)for(let[r,{childFs:s}]of this.mountInstances.entries())s.discardAndClose?.(),this.mountInstances.delete(r)}resolve(r){return this.baseFs.resolve(r)}remapFd(r,s){let a=this.nextFd++|this.magic;return this.fdMap.set(a,[r,s]),a}async openPromise(r,s,a){return await this.makeCallPromise(r,async()=>await this.baseFs.openPromise(r,s,a),async(n,{subPath:c})=>this.remapFd(n,await n.openPromise(c,s,a)))}openSync(r,s,a){return this.makeCallSync(r,()=>this.baseFs.openSync(r,s,a),(n,{subPath:c})=>this.remapFd(n,n.openSync(c,s,a)))}async opendirPromise(r,s){return await this.makeCallPromise(r,async()=>await this.baseFs.opendirPromise(r,s),async(a,{subPath:n})=>await a.opendirPromise(n,s),{requireSubpath:!1})}opendirSync(r,s){return this.makeCallSync(r,()=>this.baseFs.opendirSync(r,s),(a,{subPath:n})=>a.opendirSync(n,s),{requireSubpath:!1})}async readPromise(r,s,a,n,c){if((r&tl)!==this.magic)return await this.baseFs.readPromise(r,s,a,n,c);let f=this.fdMap.get(r);if(typeof f>\"u\")throw Mo(\"read\");let[p,h]=f;return await p.readPromise(h,s,a,n,c)}readSync(r,s,a,n,c){if((r&tl)!==this.magic)return this.baseFs.readSync(r,s,a,n,c);let f=this.fdMap.get(r);if(typeof f>\"u\")throw Mo(\"readSync\");let[p,h]=f;return p.readSync(h,s,a,n,c)}async writePromise(r,s,a,n,c){if((r&tl)!==this.magic)return typeof s==\"string\"?await this.baseFs.writePromise(r,s,a):await this.baseFs.writePromise(r,s,a,n,c);let f=this.fdMap.get(r);if(typeof f>\"u\")throw Mo(\"write\");let[p,h]=f;return typeof s==\"string\"?await p.writePromise(h,s,a):await p.writePromise(h,s,a,n,c)}writeSync(r,s,a,n,c){if((r&tl)!==this.magic)return typeof s==\"string\"?this.baseFs.writeSync(r,s,a):this.baseFs.writeSync(r,s,a,n,c);let f=this.fdMap.get(r);if(typeof f>\"u\")throw Mo(\"writeSync\");let[p,h]=f;return typeof s==\"string\"?p.writeSync(h,s,a):p.writeSync(h,s,a,n,c)}async closePromise(r){if((r&tl)!==this.magic)return await this.baseFs.closePromise(r);let s=this.fdMap.get(r);if(typeof s>\"u\")throw Mo(\"close\");this.fdMap.delete(r);let[a,n]=s;return await a.closePromise(n)}closeSync(r){if((r&tl)!==this.magic)return this.baseFs.closeSync(r);let s=this.fdMap.get(r);if(typeof s>\"u\")throw Mo(\"closeSync\");this.fdMap.delete(r);let[a,n]=s;return a.closeSync(n)}createReadStream(r,s){return r===null?this.baseFs.createReadStream(r,s):this.makeCallSync(r,()=>this.baseFs.createReadStream(r,s),(a,{archivePath:n,subPath:c})=>{let f=a.createReadStream(c,s);return f.path=fe.fromPortablePath(this.pathUtils.join(n,c)),f})}createWriteStream(r,s){return r===null?this.baseFs.createWriteStream(r,s):this.makeCallSync(r,()=>this.baseFs.createWriteStream(r,s),(a,{subPath:n})=>a.createWriteStream(n,s))}async realpathPromise(r){return await this.makeCallPromise(r,async()=>await this.baseFs.realpathPromise(r),async(s,{archivePath:a,subPath:n})=>{let c=this.realPaths.get(a);return typeof c>\"u\"&&(c=await this.baseFs.realpathPromise(a),this.realPaths.set(a,c)),this.pathUtils.join(c,this.pathUtils.relative(vt.root,await s.realpathPromise(n)))})}realpathSync(r){return this.makeCallSync(r,()=>this.baseFs.realpathSync(r),(s,{archivePath:a,subPath:n})=>{let c=this.realPaths.get(a);return typeof c>\"u\"&&(c=this.baseFs.realpathSync(a),this.realPaths.set(a,c)),this.pathUtils.join(c,this.pathUtils.relative(vt.root,s.realpathSync(n)))})}async existsPromise(r){return await this.makeCallPromise(r,async()=>await this.baseFs.existsPromise(r),async(s,{subPath:a})=>await s.existsPromise(a))}existsSync(r){return this.makeCallSync(r,()=>this.baseFs.existsSync(r),(s,{subPath:a})=>s.existsSync(a))}async accessPromise(r,s){return await this.makeCallPromise(r,async()=>await this.baseFs.accessPromise(r,s),async(a,{subPath:n})=>await a.accessPromise(n,s))}accessSync(r,s){return this.makeCallSync(r,()=>this.baseFs.accessSync(r,s),(a,{subPath:n})=>a.accessSync(n,s))}async statPromise(r,s){return await this.makeCallPromise(r,async()=>await this.baseFs.statPromise(r,s),async(a,{subPath:n})=>await a.statPromise(n,s))}statSync(r,s){return this.makeCallSync(r,()=>this.baseFs.statSync(r,s),(a,{subPath:n})=>a.statSync(n,s))}async fstatPromise(r,s){if((r&tl)!==this.magic)return this.baseFs.fstatPromise(r,s);let a=this.fdMap.get(r);if(typeof a>\"u\")throw Mo(\"fstat\");let[n,c]=a;return n.fstatPromise(c,s)}fstatSync(r,s){if((r&tl)!==this.magic)return this.baseFs.fstatSync(r,s);let a=this.fdMap.get(r);if(typeof a>\"u\")throw Mo(\"fstatSync\");let[n,c]=a;return n.fstatSync(c,s)}async lstatPromise(r,s){return await this.makeCallPromise(r,async()=>await this.baseFs.lstatPromise(r,s),async(a,{subPath:n})=>await a.lstatPromise(n,s))}lstatSync(r,s){return this.makeCallSync(r,()=>this.baseFs.lstatSync(r,s),(a,{subPath:n})=>a.lstatSync(n,s))}async fchmodPromise(r,s){if((r&tl)!==this.magic)return this.baseFs.fchmodPromise(r,s);let a=this.fdMap.get(r);if(typeof a>\"u\")throw Mo(\"fchmod\");let[n,c]=a;return n.fchmodPromise(c,s)}fchmodSync(r,s){if((r&tl)!==this.magic)return this.baseFs.fchmodSync(r,s);let a=this.fdMap.get(r);if(typeof a>\"u\")throw Mo(\"fchmodSync\");let[n,c]=a;return n.fchmodSync(c,s)}async chmodPromise(r,s){return await this.makeCallPromise(r,async()=>await this.baseFs.chmodPromise(r,s),async(a,{subPath:n})=>await a.chmodPromise(n,s))}chmodSync(r,s){return this.makeCallSync(r,()=>this.baseFs.chmodSync(r,s),(a,{subPath:n})=>a.chmodSync(n,s))}async fchownPromise(r,s,a){if((r&tl)!==this.magic)return this.baseFs.fchownPromise(r,s,a);let n=this.fdMap.get(r);if(typeof n>\"u\")throw Mo(\"fchown\");let[c,f]=n;return c.fchownPromise(f,s,a)}fchownSync(r,s,a){if((r&tl)!==this.magic)return this.baseFs.fchownSync(r,s,a);let n=this.fdMap.get(r);if(typeof n>\"u\")throw Mo(\"fchownSync\");let[c,f]=n;return c.fchownSync(f,s,a)}async chownPromise(r,s,a){return await this.makeCallPromise(r,async()=>await this.baseFs.chownPromise(r,s,a),async(n,{subPath:c})=>await n.chownPromise(c,s,a))}chownSync(r,s,a){return this.makeCallSync(r,()=>this.baseFs.chownSync(r,s,a),(n,{subPath:c})=>n.chownSync(c,s,a))}async renamePromise(r,s){return await this.makeCallPromise(r,async()=>await this.makeCallPromise(s,async()=>await this.baseFs.renamePromise(r,s),async()=>{throw Object.assign(new Error(\"EEXDEV: cross-device link not permitted\"),{code:\"EEXDEV\"})}),async(a,{subPath:n})=>await this.makeCallPromise(s,async()=>{throw Object.assign(new Error(\"EEXDEV: cross-device link not permitted\"),{code:\"EEXDEV\"})},async(c,{subPath:f})=>{if(a!==c)throw Object.assign(new Error(\"EEXDEV: cross-device link not permitted\"),{code:\"EEXDEV\"});return await a.renamePromise(n,f)}))}renameSync(r,s){return this.makeCallSync(r,()=>this.makeCallSync(s,()=>this.baseFs.renameSync(r,s),()=>{throw Object.assign(new Error(\"EEXDEV: cross-device link not permitted\"),{code:\"EEXDEV\"})}),(a,{subPath:n})=>this.makeCallSync(s,()=>{throw Object.assign(new Error(\"EEXDEV: cross-device link not permitted\"),{code:\"EEXDEV\"})},(c,{subPath:f})=>{if(a!==c)throw Object.assign(new Error(\"EEXDEV: cross-device link not permitted\"),{code:\"EEXDEV\"});return a.renameSync(n,f)}))}async copyFilePromise(r,s,a=0){let n=async(c,f,p,h)=>{if(a&wd.constants.COPYFILE_FICLONE_FORCE)throw Object.assign(new Error(`EXDEV: cross-device clone not permitted, copyfile '${f}' -> ${h}'`),{code:\"EXDEV\"});if(a&wd.constants.COPYFILE_EXCL&&await this.existsPromise(f))throw Object.assign(new Error(`EEXIST: file already exists, copyfile '${f}' -> '${h}'`),{code:\"EEXIST\"});let E;try{E=await c.readFilePromise(f)}catch{throw Object.assign(new Error(`EINVAL: invalid argument, copyfile '${f}' -> '${h}'`),{code:\"EINVAL\"})}await p.writeFilePromise(h,E)};return await this.makeCallPromise(r,async()=>await this.makeCallPromise(s,async()=>await this.baseFs.copyFilePromise(r,s,a),async(c,{subPath:f})=>await n(this.baseFs,r,c,f)),async(c,{subPath:f})=>await this.makeCallPromise(s,async()=>await n(c,f,this.baseFs,s),async(p,{subPath:h})=>c!==p?await n(c,f,p,h):await c.copyFilePromise(f,h,a)))}copyFileSync(r,s,a=0){let n=(c,f,p,h)=>{if(a&wd.constants.COPYFILE_FICLONE_FORCE)throw Object.assign(new Error(`EXDEV: cross-device clone not permitted, copyfile '${f}' -> ${h}'`),{code:\"EXDEV\"});if(a&wd.constants.COPYFILE_EXCL&&this.existsSync(f))throw Object.assign(new Error(`EEXIST: file already exists, copyfile '${f}' -> '${h}'`),{code:\"EEXIST\"});let E;try{E=c.readFileSync(f)}catch{throw Object.assign(new Error(`EINVAL: invalid argument, copyfile '${f}' -> '${h}'`),{code:\"EINVAL\"})}p.writeFileSync(h,E)};return this.makeCallSync(r,()=>this.makeCallSync(s,()=>this.baseFs.copyFileSync(r,s,a),(c,{subPath:f})=>n(this.baseFs,r,c,f)),(c,{subPath:f})=>this.makeCallSync(s,()=>n(c,f,this.baseFs,s),(p,{subPath:h})=>c!==p?n(c,f,p,h):c.copyFileSync(f,h,a)))}async appendFilePromise(r,s,a){return await this.makeCallPromise(r,async()=>await this.baseFs.appendFilePromise(r,s,a),async(n,{subPath:c})=>await n.appendFilePromise(c,s,a))}appendFileSync(r,s,a){return this.makeCallSync(r,()=>this.baseFs.appendFileSync(r,s,a),(n,{subPath:c})=>n.appendFileSync(c,s,a))}async writeFilePromise(r,s,a){return await this.makeCallPromise(r,async()=>await this.baseFs.writeFilePromise(r,s,a),async(n,{subPath:c})=>await n.writeFilePromise(c,s,a))}writeFileSync(r,s,a){return this.makeCallSync(r,()=>this.baseFs.writeFileSync(r,s,a),(n,{subPath:c})=>n.writeFileSync(c,s,a))}async unlinkPromise(r){return await this.makeCallPromise(r,async()=>await this.baseFs.unlinkPromise(r),async(s,{subPath:a})=>await s.unlinkPromise(a))}unlinkSync(r){return this.makeCallSync(r,()=>this.baseFs.unlinkSync(r),(s,{subPath:a})=>s.unlinkSync(a))}async utimesPromise(r,s,a){return await this.makeCallPromise(r,async()=>await this.baseFs.utimesPromise(r,s,a),async(n,{subPath:c})=>await n.utimesPromise(c,s,a))}utimesSync(r,s,a){return this.makeCallSync(r,()=>this.baseFs.utimesSync(r,s,a),(n,{subPath:c})=>n.utimesSync(c,s,a))}async lutimesPromise(r,s,a){return await this.makeCallPromise(r,async()=>await this.baseFs.lutimesPromise(r,s,a),async(n,{subPath:c})=>await n.lutimesPromise(c,s,a))}lutimesSync(r,s,a){return this.makeCallSync(r,()=>this.baseFs.lutimesSync(r,s,a),(n,{subPath:c})=>n.lutimesSync(c,s,a))}async mkdirPromise(r,s){return await this.makeCallPromise(r,async()=>await this.baseFs.mkdirPromise(r,s),async(a,{subPath:n})=>await a.mkdirPromise(n,s))}mkdirSync(r,s){return this.makeCallSync(r,()=>this.baseFs.mkdirSync(r,s),(a,{subPath:n})=>a.mkdirSync(n,s))}async rmdirPromise(r,s){return await this.makeCallPromise(r,async()=>await this.baseFs.rmdirPromise(r,s),async(a,{subPath:n})=>await a.rmdirPromise(n,s))}rmdirSync(r,s){return this.makeCallSync(r,()=>this.baseFs.rmdirSync(r,s),(a,{subPath:n})=>a.rmdirSync(n,s))}async rmPromise(r,s){return await this.makeCallPromise(r,async()=>await this.baseFs.rmPromise(r,s),async(a,{subPath:n})=>await a.rmPromise(n,s))}rmSync(r,s){return this.makeCallSync(r,()=>this.baseFs.rmSync(r,s),(a,{subPath:n})=>a.rmSync(n,s))}async linkPromise(r,s){return await this.makeCallPromise(s,async()=>await this.baseFs.linkPromise(r,s),async(a,{subPath:n})=>await a.linkPromise(r,n))}linkSync(r,s){return this.makeCallSync(s,()=>this.baseFs.linkSync(r,s),(a,{subPath:n})=>a.linkSync(r,n))}async symlinkPromise(r,s,a){return await this.makeCallPromise(s,async()=>await this.baseFs.symlinkPromise(r,s,a),async(n,{subPath:c})=>await n.symlinkPromise(r,c))}symlinkSync(r,s,a){return this.makeCallSync(s,()=>this.baseFs.symlinkSync(r,s,a),(n,{subPath:c})=>n.symlinkSync(r,c))}async readFilePromise(r,s){return this.makeCallPromise(r,async()=>await this.baseFs.readFilePromise(r,s),async(a,{subPath:n})=>await a.readFilePromise(n,s))}readFileSync(r,s){return this.makeCallSync(r,()=>this.baseFs.readFileSync(r,s),(a,{subPath:n})=>a.readFileSync(n,s))}async readdirPromise(r,s){return await this.makeCallPromise(r,async()=>await this.baseFs.readdirPromise(r,s),async(a,{subPath:n})=>await a.readdirPromise(n,s),{requireSubpath:!1})}readdirSync(r,s){return this.makeCallSync(r,()=>this.baseFs.readdirSync(r,s),(a,{subPath:n})=>a.readdirSync(n,s),{requireSubpath:!1})}async readlinkPromise(r){return await this.makeCallPromise(r,async()=>await this.baseFs.readlinkPromise(r),async(s,{subPath:a})=>await s.readlinkPromise(a))}readlinkSync(r){return this.makeCallSync(r,()=>this.baseFs.readlinkSync(r),(s,{subPath:a})=>s.readlinkSync(a))}async truncatePromise(r,s){return await this.makeCallPromise(r,async()=>await this.baseFs.truncatePromise(r,s),async(a,{subPath:n})=>await a.truncatePromise(n,s))}truncateSync(r,s){return this.makeCallSync(r,()=>this.baseFs.truncateSync(r,s),(a,{subPath:n})=>a.truncateSync(n,s))}async ftruncatePromise(r,s){if((r&tl)!==this.magic)return this.baseFs.ftruncatePromise(r,s);let a=this.fdMap.get(r);if(typeof a>\"u\")throw Mo(\"ftruncate\");let[n,c]=a;return n.ftruncatePromise(c,s)}ftruncateSync(r,s){if((r&tl)!==this.magic)return this.baseFs.ftruncateSync(r,s);let a=this.fdMap.get(r);if(typeof a>\"u\")throw Mo(\"ftruncateSync\");let[n,c]=a;return n.ftruncateSync(c,s)}watch(r,s,a){return this.makeCallSync(r,()=>this.baseFs.watch(r,s,a),(n,{subPath:c})=>n.watch(c,s,a))}watchFile(r,s,a){return this.makeCallSync(r,()=>this.baseFs.watchFile(r,s,a),()=>sE(this,r,s,a))}unwatchFile(r,s){return this.makeCallSync(r,()=>this.baseFs.unwatchFile(r,s),()=>md(this,r,s))}async makeCallPromise(r,s,a,{requireSubpath:n=!0}={}){if(typeof r!=\"string\")return await s();let c=this.resolve(r),f=this.findMount(c);return f?n&&f.subPath===\"/\"?await s():await this.getMountPromise(f.archivePath,async p=>await a(p,f)):await s()}makeCallSync(r,s,a,{requireSubpath:n=!0}={}){if(typeof r!=\"string\")return s();let c=this.resolve(r),f=this.findMount(c);return!f||n&&f.subPath===\"/\"?s():this.getMountSync(f.archivePath,p=>a(p,f))}findMount(r){if(this.filter&&!this.filter.test(r))return null;let s=\"\";for(;;){let a=r.substring(s.length),n=this.getMountPoint(a,s);if(!n)return null;if(s=this.pathUtils.join(s,n),!this.isMount.has(s)){if(this.notMount.has(s))continue;try{if(this.typeCheck!==null&&(this.baseFs.statSync(s).mode&wd.constants.S_IFMT)!==this.typeCheck){this.notMount.add(s);continue}}catch{return null}this.isMount.add(s)}return{archivePath:s,subPath:this.pathUtils.join(vt.root,r.substring(s.length))}}}limitOpenFiles(r){if(this.mountInstances===null)return;let s=Date.now(),a=s+this.maxAge,n=r===null?0:this.mountInstances.size-r;for(let[c,{childFs:f,expiresAt:p,refCount:h}]of this.mountInstances.entries())if(!(h!==0||f.hasOpenFileHandles?.())){if(s>=p){f.saveAndClose?.(),this.mountInstances.delete(c),n-=1;continue}else if(r===null||n<=0){a=p;break}f.saveAndClose?.(),this.mountInstances.delete(c),n-=1}this.limitOpenFilesTimeout===null&&(r===null&&this.mountInstances.size>0||r!==null)&&isFinite(a)&&(this.limitOpenFilesTimeout=setTimeout(()=>{this.limitOpenFilesTimeout=null,this.limitOpenFiles(null)},a-s).unref())}async getMountPromise(r,s){if(this.mountInstances){let a=this.mountInstances.get(r);if(!a){let n=await this.factoryPromise(this.baseFs,r);a=this.mountInstances.get(r),a||(a={childFs:n(),expiresAt:0,refCount:0})}this.mountInstances.delete(r),this.limitOpenFiles(this.maxOpenFiles-1),this.mountInstances.set(r,a),a.expiresAt=Date.now()+this.maxAge,a.refCount+=1;try{return await s(a.childFs)}finally{a.refCount-=1}}else{let a=(await this.factoryPromise(this.baseFs,r))();try{return await s(a)}finally{a.saveAndClose?.()}}}getMountSync(r,s){if(this.mountInstances){let a=this.mountInstances.get(r);return a||(a={childFs:this.factorySync(this.baseFs,r),expiresAt:0,refCount:0}),this.mountInstances.delete(r),this.limitOpenFiles(this.maxOpenFiles-1),this.mountInstances.set(r,a),a.expiresAt=Date.now()+this.maxAge,s(a.childFs)}else{let a=this.factorySync(this.baseFs,r);try{return s(a)}finally{a.saveAndClose?.()}}}}});var er,nx,l$=Ze(()=>{Id();el();er=()=>Object.assign(new Error(\"ENOSYS: unsupported filesystem access\"),{code:\"ENOSYS\"}),nx=class t extends mp{static{this.instance=new t}constructor(){super(J)}getExtractHint(){throw er()}getRealPath(){throw er()}resolve(){throw er()}async openPromise(){throw er()}openSync(){throw er()}async opendirPromise(){throw er()}opendirSync(){throw er()}async readPromise(){throw er()}readSync(){throw er()}async writePromise(){throw er()}writeSync(){throw er()}async closePromise(){throw er()}closeSync(){throw er()}createWriteStream(){throw er()}createReadStream(){throw er()}async realpathPromise(){throw er()}realpathSync(){throw er()}async readdirPromise(){throw er()}readdirSync(){throw er()}async existsPromise(e){throw er()}existsSync(e){throw er()}async accessPromise(){throw er()}accessSync(){throw er()}async statPromise(){throw er()}statSync(){throw er()}async fstatPromise(e){throw er()}fstatSync(e){throw er()}async lstatPromise(e){throw er()}lstatSync(e){throw er()}async fchmodPromise(){throw er()}fchmodSync(){throw er()}async chmodPromise(){throw er()}chmodSync(){throw er()}async fchownPromise(){throw er()}fchownSync(){throw er()}async chownPromise(){throw er()}chownSync(){throw er()}async mkdirPromise(){throw er()}mkdirSync(){throw er()}async rmdirPromise(){throw er()}rmdirSync(){throw er()}async rmPromise(){throw er()}rmSync(){throw er()}async linkPromise(){throw er()}linkSync(){throw er()}async symlinkPromise(){throw er()}symlinkSync(){throw er()}async renamePromise(){throw er()}renameSync(){throw er()}async copyFilePromise(){throw er()}copyFileSync(){throw er()}async appendFilePromise(){throw er()}appendFileSync(){throw er()}async writeFilePromise(){throw er()}writeFileSync(){throw er()}async unlinkPromise(){throw er()}unlinkSync(){throw er()}async utimesPromise(){throw er()}utimesSync(){throw er()}async lutimesPromise(){throw er()}lutimesSync(){throw er()}async readFilePromise(){throw er()}readFileSync(){throw er()}async readlinkPromise(){throw er()}readlinkSync(){throw er()}async truncatePromise(){throw er()}truncateSync(){throw er()}async ftruncatePromise(e,r){throw er()}ftruncateSync(e,r){throw er()}watch(){throw er()}watchFile(){throw er()}unwatchFile(){throw er()}}});var t0,c$=Ze(()=>{yp();el();t0=class extends _s{constructor(e){super(fe),this.baseFs=e}mapFromBase(e){return fe.fromPortablePath(e)}mapToBase(e){return fe.toPortablePath(e)}}});var nqe,PU,iqe,uo,u$=Ze(()=>{Cd();yp();el();nqe=/^[0-9]+$/,PU=/^(\\/(?:[^/]+\\/)*?(?:\\$\\$virtual|__virtual__))((?:\\/((?:[^/]+-)?[a-f0-9]+)(?:\\/([^/]+))?)?((?:\\/.*)?))$/,iqe=/^([^/]+-)?[a-f0-9]+$/,uo=class t extends _s{static makeVirtualPath(e,r,s){if(J.basename(e)!==\"__virtual__\")throw new Error('Assertion failed: Virtual folders must be named \"__virtual__\"');if(!J.basename(r).match(iqe))throw new Error(\"Assertion failed: Virtual components must be ended by an hexadecimal hash\");let n=J.relative(J.dirname(e),s).split(\"/\"),c=0;for(;c<n.length&&n[c]===\"..\";)c+=1;let f=n.slice(c);return J.join(e,r,String(c),...f)}static resolveVirtual(e){let r=e.match(PU);if(!r||!r[3]&&r[5])return e;let s=J.dirname(r[1]);if(!r[3]||!r[4])return s;if(!nqe.test(r[4]))return e;let n=Number(r[4]),c=\"../\".repeat(n),f=r[5]||\".\";return t.resolveVirtual(J.join(s,c,f))}constructor({baseFs:e=new Yn}={}){super(J),this.baseFs=e}getExtractHint(e){return this.baseFs.getExtractHint(e)}getRealPath(){return this.baseFs.getRealPath()}realpathSync(e){let r=e.match(PU);if(!r)return this.baseFs.realpathSync(e);if(!r[5])return e;let s=this.baseFs.realpathSync(this.mapToBase(e));return t.makeVirtualPath(r[1],r[3],s)}async realpathPromise(e){let r=e.match(PU);if(!r)return await this.baseFs.realpathPromise(e);if(!r[5])return e;let s=await this.baseFs.realpathPromise(this.mapToBase(e));return t.makeVirtualPath(r[1],r[3],s)}mapToBase(e){if(e===\"\")return e;if(this.pathUtils.isAbsolute(e))return t.resolveVirtual(e);let r=t.resolveVirtual(this.baseFs.resolve(vt.dot)),s=t.resolveVirtual(this.baseFs.resolve(e));return J.relative(r,s)||vt.dot}mapFromBase(e){return e}}});function sqe(t,e){return typeof bU.default.isUtf8<\"u\"?bU.default.isUtf8(t):Buffer.byteLength(e)===t.byteLength}var bU,f$,A$,ix,p$=Ze(()=>{bU=ut(Ie(\"buffer\")),f$=Ie(\"url\"),A$=Ie(\"util\");yp();el();ix=class extends _s{constructor(e){super(fe),this.baseFs=e}mapFromBase(e){return e}mapToBase(e){if(typeof e==\"string\")return e;if(e instanceof URL)return(0,f$.fileURLToPath)(e);if(Buffer.isBuffer(e)){let r=e.toString();if(!sqe(e,r))throw new Error(\"Non-utf8 buffers are not supported at the moment. Please upvote the following issue if you encounter this error: https://github.com/yarnpkg/berry/issues/4942\");return r}throw new Error(`Unsupported path type: ${(0,A$.inspect)(e)}`)}}});var y$,Uo,Ep,r0,sx,ox,aE,Tu,Fu,h$,g$,d$,m$,M2,E$=Ze(()=>{y$=Ie(\"readline\"),Uo=Symbol(\"kBaseFs\"),Ep=Symbol(\"kFd\"),r0=Symbol(\"kClosePromise\"),sx=Symbol(\"kCloseResolve\"),ox=Symbol(\"kCloseReject\"),aE=Symbol(\"kRefs\"),Tu=Symbol(\"kRef\"),Fu=Symbol(\"kUnref\"),M2=class{constructor(e,r){this[m$]=1;this[d$]=void 0;this[g$]=void 0;this[h$]=void 0;this[Uo]=r,this[Ep]=e}get fd(){return this[Ep]}async appendFile(e,r){try{this[Tu](this.appendFile);let s=(typeof r==\"string\"?r:r?.encoding)??void 0;return await this[Uo].appendFilePromise(this.fd,e,s?{encoding:s}:void 0)}finally{this[Fu]()}}async chown(e,r){try{return this[Tu](this.chown),await this[Uo].fchownPromise(this.fd,e,r)}finally{this[Fu]()}}async chmod(e){try{return this[Tu](this.chmod),await this[Uo].fchmodPromise(this.fd,e)}finally{this[Fu]()}}createReadStream(e){return this[Uo].createReadStream(null,{...e,fd:this.fd})}createWriteStream(e){return this[Uo].createWriteStream(null,{...e,fd:this.fd})}datasync(){throw new Error(\"Method not implemented.\")}sync(){throw new Error(\"Method not implemented.\")}async read(e,r,s,a){try{this[Tu](this.read);let n;return Buffer.isBuffer(e)?n=e:(e??={},n=e.buffer??Buffer.alloc(16384),r=e.offset||0,s=e.length??n.byteLength,a=e.position??null),r??=0,s??=0,s===0?{bytesRead:s,buffer:n}:{bytesRead:await this[Uo].readPromise(this.fd,n,r,s,a),buffer:n}}finally{this[Fu]()}}async readFile(e){try{this[Tu](this.readFile);let r=(typeof e==\"string\"?e:e?.encoding)??void 0;return await this[Uo].readFilePromise(this.fd,r)}finally{this[Fu]()}}readLines(e){return(0,y$.createInterface)({input:this.createReadStream(e),crlfDelay:1/0})}async stat(e){try{return this[Tu](this.stat),await this[Uo].fstatPromise(this.fd,e)}finally{this[Fu]()}}async truncate(e){try{return this[Tu](this.truncate),await this[Uo].ftruncatePromise(this.fd,e)}finally{this[Fu]()}}utimes(e,r){throw new Error(\"Method not implemented.\")}async writeFile(e,r){try{this[Tu](this.writeFile);let s=(typeof r==\"string\"?r:r?.encoding)??void 0;await this[Uo].writeFilePromise(this.fd,e,s)}finally{this[Fu]()}}async write(...e){try{if(this[Tu](this.write),ArrayBuffer.isView(e[0])){let[r,s,a,n]=e;return{bytesWritten:await this[Uo].writePromise(this.fd,r,s??void 0,a??void 0,n??void 0),buffer:r}}else{let[r,s,a]=e;return{bytesWritten:await this[Uo].writePromise(this.fd,r,s,a),buffer:r}}}finally{this[Fu]()}}async writev(e,r){try{this[Tu](this.writev);let s=0;if(typeof r<\"u\")for(let a of e){let n=await this.write(a,void 0,void 0,r);s+=n.bytesWritten,r+=n.bytesWritten}else for(let a of e){let n=await this.write(a);s+=n.bytesWritten}return{buffers:e,bytesWritten:s}}finally{this[Fu]()}}readv(e,r){throw new Error(\"Method not implemented.\")}close(){if(this[Ep]===-1)return Promise.resolve();if(this[r0])return this[r0];if(this[aE]--,this[aE]===0){let e=this[Ep];this[Ep]=-1,this[r0]=this[Uo].closePromise(e).finally(()=>{this[r0]=void 0})}else this[r0]=new Promise((e,r)=>{this[sx]=e,this[ox]=r}).finally(()=>{this[r0]=void 0,this[ox]=void 0,this[sx]=void 0});return this[r0]}[(Uo,Ep,m$=aE,d$=r0,g$=sx,h$=ox,Tu)](e){if(this[Ep]===-1){let r=new Error(\"file closed\");throw r.code=\"EBADF\",r.syscall=e.name,r}this[aE]++}[Fu](){if(this[aE]--,this[aE]===0){let e=this[Ep];this[Ep]=-1,this[Uo].closePromise(e).then(this[sx],this[ox])}}}});function U2(t,e){e=new ix(e);let r=(s,a,n)=>{let c=s[a];s[a]=n,typeof c?.[lE.promisify.custom]<\"u\"&&(n[lE.promisify.custom]=c[lE.promisify.custom])};{r(t,\"exists\",(s,...a)=>{let c=typeof a[a.length-1]==\"function\"?a.pop():()=>{};process.nextTick(()=>{e.existsPromise(s).then(f=>{c(f)},()=>{c(!1)})})}),r(t,\"read\",(...s)=>{let[a,n,c,f,p,h]=s;if(s.length<=3){let E={};s.length<3?h=s[1]:(E=s[1],h=s[2]),{buffer:n=Buffer.alloc(16384),offset:c=0,length:f=n.byteLength,position:p}=E}if(c==null&&(c=0),f|=0,f===0){process.nextTick(()=>{h(null,0,n)});return}p==null&&(p=-1),process.nextTick(()=>{e.readPromise(a,n,c,f,p).then(E=>{h(null,E,n)},E=>{h(E,0,n)})})});for(let s of I$){let a=s.replace(/Promise$/,\"\");if(typeof t[a]>\"u\")continue;let n=e[s];if(typeof n>\"u\")continue;r(t,a,(...f)=>{let h=typeof f[f.length-1]==\"function\"?f.pop():()=>{};process.nextTick(()=>{n.apply(e,f).then(E=>{h(null,E)},E=>{h(E)})})})}t.realpath.native=t.realpath}{r(t,\"existsSync\",s=>{try{return e.existsSync(s)}catch{return!1}}),r(t,\"readSync\",(...s)=>{let[a,n,c,f,p]=s;return s.length<=3&&({offset:c=0,length:f=n.byteLength,position:p}=s[2]||{}),c==null&&(c=0),f|=0,f===0?0:(p==null&&(p=-1),e.readSync(a,n,c,f,p))});for(let s of oqe){let a=s;if(typeof t[a]>\"u\")continue;let n=e[s];typeof n>\"u\"||r(t,a,n.bind(e))}t.realpathSync.native=t.realpathSync}{let s=t.promises;for(let a of I$){let n=a.replace(/Promise$/,\"\");if(typeof s[n]>\"u\")continue;let c=e[a];typeof c>\"u\"||a!==\"open\"&&r(s,n,(f,...p)=>f instanceof M2?f[n].apply(f,p):c.call(e,f,...p))}r(s,\"open\",async(...a)=>{let n=await e.openPromise(...a);return new M2(n,e)})}t.read[lE.promisify.custom]=async(s,a,...n)=>({bytesRead:await e.readPromise(s,a,...n),buffer:a}),t.write[lE.promisify.custom]=async(s,a,...n)=>({bytesWritten:await e.writePromise(s,a,...n),buffer:a})}function ax(t,e){let r=Object.create(t);return U2(r,e),r}var lE,oqe,I$,C$=Ze(()=>{lE=Ie(\"util\");p$();E$();oqe=new Set([\"accessSync\",\"appendFileSync\",\"createReadStream\",\"createWriteStream\",\"chmodSync\",\"fchmodSync\",\"chownSync\",\"fchownSync\",\"closeSync\",\"copyFileSync\",\"linkSync\",\"lstatSync\",\"fstatSync\",\"lutimesSync\",\"mkdirSync\",\"openSync\",\"opendirSync\",\"readlinkSync\",\"readFileSync\",\"readdirSync\",\"readlinkSync\",\"realpathSync\",\"renameSync\",\"rmdirSync\",\"rmSync\",\"statSync\",\"symlinkSync\",\"truncateSync\",\"ftruncateSync\",\"unlinkSync\",\"unwatchFile\",\"utimesSync\",\"watch\",\"watchFile\",\"writeFileSync\",\"writeSync\"]),I$=new Set([\"accessPromise\",\"appendFilePromise\",\"fchmodPromise\",\"chmodPromise\",\"fchownPromise\",\"chownPromise\",\"closePromise\",\"copyFilePromise\",\"linkPromise\",\"fstatPromise\",\"lstatPromise\",\"lutimesPromise\",\"mkdirPromise\",\"openPromise\",\"opendirPromise\",\"readdirPromise\",\"realpathPromise\",\"readFilePromise\",\"readdirPromise\",\"readlinkPromise\",\"renamePromise\",\"rmdirPromise\",\"rmPromise\",\"statPromise\",\"symlinkPromise\",\"truncatePromise\",\"ftruncatePromise\",\"unlinkPromise\",\"utimesPromise\",\"writeFilePromise\",\"writeSync\"])});function w$(t){let e=Math.ceil(Math.random()*4294967296).toString(16).padStart(8,\"0\");return`${t}${e}`}function B$(){if(xU)return xU;let t=fe.toPortablePath(v$.default.tmpdir()),e=ce.realpathSync(t);return process.once(\"exit\",()=>{ce.rmtempSync()}),xU={tmpdir:t,realTmpdir:e}}var v$,Nu,xU,ce,S$=Ze(()=>{v$=ut(Ie(\"os\"));Cd();el();Nu=new Set,xU=null;ce=Object.assign(new Yn,{detachTemp(t){Nu.delete(t)},mktempSync(t){let{tmpdir:e,realTmpdir:r}=B$();for(;;){let s=w$(\"xfs-\");try{this.mkdirSync(J.join(e,s))}catch(n){if(n.code===\"EEXIST\")continue;throw n}let a=J.join(r,s);if(Nu.add(a),typeof t>\"u\")return a;try{return t(a)}finally{if(Nu.has(a)){Nu.delete(a);try{this.removeSync(a)}catch{}}}}},async mktempPromise(t){let{tmpdir:e,realTmpdir:r}=B$();for(;;){let s=w$(\"xfs-\");try{await this.mkdirPromise(J.join(e,s))}catch(n){if(n.code===\"EEXIST\")continue;throw n}let a=J.join(r,s);if(Nu.add(a),typeof t>\"u\")return a;try{return await t(a)}finally{if(Nu.has(a)){Nu.delete(a);try{await this.removePromise(a)}catch{}}}}},async rmtempPromise(){await Promise.all(Array.from(Nu.values()).map(async t=>{try{await ce.removePromise(t,{maxRetries:0}),Nu.delete(t)}catch{}}))},rmtempSync(){for(let t of Nu)try{ce.removeSync(t),Nu.delete(t)}catch{}}})});var _2={};Vt(_2,{AliasFS:()=>_f,BasePortableFakeFS:()=>Uf,CustomDir:()=>L2,CwdFS:()=>Sn,FakeFS:()=>mp,Filename:()=>Er,JailFS:()=>Hf,LazyFS:()=>oE,MountFS:()=>e0,NoFS:()=>nx,NodeFS:()=>Yn,PortablePath:()=>vt,PosixFS:()=>t0,ProxiedFS:()=>_s,VirtualFS:()=>uo,constants:()=>fi,errors:()=>or,extendFs:()=>ax,normalizeLineEndings:()=>Ed,npath:()=>fe,opendir:()=>ex,patchFs:()=>U2,ppath:()=>J,setupCopyIndex:()=>$b,statUtils:()=>$a,unwatchAllFiles:()=>yd,unwatchFile:()=>md,watchFile:()=>sE,xfs:()=>ce});var Dt=Ze(()=>{jX();zb();wU();SU();JX();DU();Id();el();el();e$();Id();n$();s$();o$();a$();l$();Cd();c$();yp();u$();C$();S$()});var k$=_((mkt,x$)=>{x$.exports=b$;b$.sync=lqe;var D$=Ie(\"fs\");function aqe(t,e){var r=e.pathExt!==void 0?e.pathExt:process.env.PATHEXT;if(!r||(r=r.split(\";\"),r.indexOf(\"\")!==-1))return!0;for(var s=0;s<r.length;s++){var a=r[s].toLowerCase();if(a&&t.substr(-a.length).toLowerCase()===a)return!0}return!1}function P$(t,e,r){return!t.isSymbolicLink()&&!t.isFile()?!1:aqe(e,r)}function b$(t,e,r){D$.stat(t,function(s,a){r(s,s?!1:P$(a,t,e))})}function lqe(t,e){return P$(D$.statSync(t),t,e)}});var N$=_((ykt,F$)=>{F$.exports=R$;R$.sync=cqe;var Q$=Ie(\"fs\");function R$(t,e,r){Q$.stat(t,function(s,a){r(s,s?!1:T$(a,e))})}function cqe(t,e){return T$(Q$.statSync(t),e)}function T$(t,e){return t.isFile()&&uqe(t,e)}function uqe(t,e){var r=t.mode,s=t.uid,a=t.gid,n=e.uid!==void 0?e.uid:process.getuid&&process.getuid(),c=e.gid!==void 0?e.gid:process.getgid&&process.getgid(),f=parseInt(\"100\",8),p=parseInt(\"010\",8),h=parseInt(\"001\",8),E=f|p,C=r&h||r&p&&a===c||r&f&&s===n||r&E&&n===0;return C}});var L$=_((Ikt,O$)=>{var Ekt=Ie(\"fs\"),lx;process.platform===\"win32\"||global.TESTING_WINDOWS?lx=k$():lx=N$();O$.exports=kU;kU.sync=fqe;function kU(t,e,r){if(typeof e==\"function\"&&(r=e,e={}),!r){if(typeof Promise!=\"function\")throw new TypeError(\"callback not provided\");return new Promise(function(s,a){kU(t,e||{},function(n,c){n?a(n):s(c)})})}lx(t,e||{},function(s,a){s&&(s.code===\"EACCES\"||e&&e.ignoreErrors)&&(s=null,a=!1),r(s,a)})}function fqe(t,e){try{return lx.sync(t,e||{})}catch(r){if(e&&e.ignoreErrors||r.code===\"EACCES\")return!1;throw r}}});var q$=_((Ckt,G$)=>{var cE=process.platform===\"win32\"||process.env.OSTYPE===\"cygwin\"||process.env.OSTYPE===\"msys\",M$=Ie(\"path\"),Aqe=cE?\";\":\":\",U$=L$(),_$=t=>Object.assign(new Error(`not found: ${t}`),{code:\"ENOENT\"}),H$=(t,e)=>{let r=e.colon||Aqe,s=t.match(/\\//)||cE&&t.match(/\\\\/)?[\"\"]:[...cE?[process.cwd()]:[],...(e.path||process.env.PATH||\"\").split(r)],a=cE?e.pathExt||process.env.PATHEXT||\".EXE;.CMD;.BAT;.COM\":\"\",n=cE?a.split(r):[\"\"];return cE&&t.indexOf(\".\")!==-1&&n[0]!==\"\"&&n.unshift(\"\"),{pathEnv:s,pathExt:n,pathExtExe:a}},j$=(t,e,r)=>{typeof e==\"function\"&&(r=e,e={}),e||(e={});let{pathEnv:s,pathExt:a,pathExtExe:n}=H$(t,e),c=[],f=h=>new Promise((E,C)=>{if(h===s.length)return e.all&&c.length?E(c):C(_$(t));let S=s[h],b=/^\".*\"$/.test(S)?S.slice(1,-1):S,I=M$.join(b,t),T=!b&&/^\\.[\\\\\\/]/.test(t)?t.slice(0,2)+I:I;E(p(T,h,0))}),p=(h,E,C)=>new Promise((S,b)=>{if(C===a.length)return S(f(E+1));let I=a[C];U$(h+I,{pathExt:n},(T,N)=>{if(!T&&N)if(e.all)c.push(h+I);else return S(h+I);return S(p(h,E,C+1))})});return r?f(0).then(h=>r(null,h),r):f(0)},pqe=(t,e)=>{e=e||{};let{pathEnv:r,pathExt:s,pathExtExe:a}=H$(t,e),n=[];for(let c=0;c<r.length;c++){let f=r[c],p=/^\".*\"$/.test(f)?f.slice(1,-1):f,h=M$.join(p,t),E=!p&&/^\\.[\\\\\\/]/.test(t)?t.slice(0,2)+h:h;for(let C=0;C<s.length;C++){let S=E+s[C];try{if(U$.sync(S,{pathExt:a}))if(e.all)n.push(S);else return S}catch{}}}if(e.all&&n.length)return n;if(e.nothrow)return null;throw _$(t)};G$.exports=j$;j$.sync=pqe});var Y$=_((wkt,QU)=>{\"use strict\";var W$=(t={})=>{let e=t.env||process.env;return(t.platform||process.platform)!==\"win32\"?\"PATH\":Object.keys(e).reverse().find(s=>s.toUpperCase()===\"PATH\")||\"Path\"};QU.exports=W$;QU.exports.default=W$});var z$=_((Bkt,K$)=>{\"use strict\";var V$=Ie(\"path\"),hqe=q$(),gqe=Y$();function J$(t,e){let r=t.options.env||process.env,s=process.cwd(),a=t.options.cwd!=null,n=a&&process.chdir!==void 0&&!process.chdir.disabled;if(n)try{process.chdir(t.options.cwd)}catch{}let c;try{c=hqe.sync(t.command,{path:r[gqe({env:r})],pathExt:e?V$.delimiter:void 0})}catch{}finally{n&&process.chdir(s)}return c&&(c=V$.resolve(a?t.options.cwd:\"\",c)),c}function dqe(t){return J$(t)||J$(t,!0)}K$.exports=dqe});var Z$=_((vkt,TU)=>{\"use strict\";var RU=/([()\\][%!^\"`<>&|;, *?])/g;function mqe(t){return t=t.replace(RU,\"^$1\"),t}function yqe(t,e){return t=`${t}`,t=t.replace(/(?=(\\\\+?)?)\\1\"/g,'$1$1\\\\\"'),t=t.replace(/(?=(\\\\+?)?)\\1$/,\"$1$1\"),t=`\"${t}\"`,t=t.replace(RU,\"^$1\"),e&&(t=t.replace(RU,\"^$1\")),t}TU.exports.command=mqe;TU.exports.argument=yqe});var $$=_((Skt,X$)=>{\"use strict\";X$.exports=/^#!(.*)/});var tee=_((Dkt,eee)=>{\"use strict\";var Eqe=$$();eee.exports=(t=\"\")=>{let e=t.match(Eqe);if(!e)return null;let[r,s]=e[0].replace(/#! ?/,\"\").split(\" \"),a=r.split(\"/\").pop();return a===\"env\"?s:s?`${a} ${s}`:a}});var nee=_((Pkt,ree)=>{\"use strict\";var FU=Ie(\"fs\"),Iqe=tee();function Cqe(t){let r=Buffer.alloc(150),s;try{s=FU.openSync(t,\"r\"),FU.readSync(s,r,0,150,0),FU.closeSync(s)}catch{}return Iqe(r.toString())}ree.exports=Cqe});var aee=_((bkt,oee)=>{\"use strict\";var wqe=Ie(\"path\"),iee=z$(),see=Z$(),Bqe=nee(),vqe=process.platform===\"win32\",Sqe=/\\.(?:com|exe)$/i,Dqe=/node_modules[\\\\/].bin[\\\\/][^\\\\/]+\\.cmd$/i;function Pqe(t){t.file=iee(t);let e=t.file&&Bqe(t.file);return e?(t.args.unshift(t.file),t.command=e,iee(t)):t.file}function bqe(t){if(!vqe)return t;let e=Pqe(t),r=!Sqe.test(e);if(t.options.forceShell||r){let s=Dqe.test(e);t.command=wqe.normalize(t.command),t.command=see.command(t.command),t.args=t.args.map(n=>see.argument(n,s));let a=[t.command].concat(t.args).join(\" \");t.args=[\"/d\",\"/s\",\"/c\",`\"${a}\"`],t.command=process.env.comspec||\"cmd.exe\",t.options.windowsVerbatimArguments=!0}return t}function xqe(t,e,r){e&&!Array.isArray(e)&&(r=e,e=null),e=e?e.slice(0):[],r=Object.assign({},r);let s={command:t,args:e,options:r,file:void 0,original:{command:t,args:e}};return r.shell?s:bqe(s)}oee.exports=xqe});var uee=_((xkt,cee)=>{\"use strict\";var NU=process.platform===\"win32\";function OU(t,e){return Object.assign(new Error(`${e} ${t.command} ENOENT`),{code:\"ENOENT\",errno:\"ENOENT\",syscall:`${e} ${t.command}`,path:t.command,spawnargs:t.args})}function kqe(t,e){if(!NU)return;let r=t.emit;t.emit=function(s,a){if(s===\"exit\"){let n=lee(a,e);if(n)return r.call(t,\"error\",n)}return r.apply(t,arguments)}}function lee(t,e){return NU&&t===1&&!e.file?OU(e.original,\"spawn\"):null}function Qqe(t,e){return NU&&t===1&&!e.file?OU(e.original,\"spawnSync\"):null}cee.exports={hookChildProcess:kqe,verifyENOENT:lee,verifyENOENTSync:Qqe,notFoundError:OU}});var UU=_((kkt,uE)=>{\"use strict\";var fee=Ie(\"child_process\"),LU=aee(),MU=uee();function Aee(t,e,r){let s=LU(t,e,r),a=fee.spawn(s.command,s.args,s.options);return MU.hookChildProcess(a,s),a}function Rqe(t,e,r){let s=LU(t,e,r),a=fee.spawnSync(s.command,s.args,s.options);return a.error=a.error||MU.verifyENOENTSync(a.status,s),a}uE.exports=Aee;uE.exports.spawn=Aee;uE.exports.sync=Rqe;uE.exports._parse=LU;uE.exports._enoent=MU});var hee=_((Qkt,pee)=>{\"use strict\";function Tqe(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function Bd(t,e,r,s){this.message=t,this.expected=e,this.found=r,this.location=s,this.name=\"SyntaxError\",typeof Error.captureStackTrace==\"function\"&&Error.captureStackTrace(this,Bd)}Tqe(Bd,Error);Bd.buildMessage=function(t,e){var r={literal:function(h){return'\"'+a(h.text)+'\"'},class:function(h){var E=\"\",C;for(C=0;C<h.parts.length;C++)E+=h.parts[C]instanceof Array?n(h.parts[C][0])+\"-\"+n(h.parts[C][1]):n(h.parts[C]);return\"[\"+(h.inverted?\"^\":\"\")+E+\"]\"},any:function(h){return\"any character\"},end:function(h){return\"end of input\"},other:function(h){return h.description}};function s(h){return h.charCodeAt(0).toString(16).toUpperCase()}function a(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\"/g,'\\\\\"').replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(E){return\"\\\\x0\"+s(E)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(E){return\"\\\\x\"+s(E)})}function n(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\\]/g,\"\\\\]\").replace(/\\^/g,\"\\\\^\").replace(/-/g,\"\\\\-\").replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(E){return\"\\\\x0\"+s(E)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(E){return\"\\\\x\"+s(E)})}function c(h){return r[h.type](h)}function f(h){var E=new Array(h.length),C,S;for(C=0;C<h.length;C++)E[C]=c(h[C]);if(E.sort(),E.length>0){for(C=1,S=1;C<E.length;C++)E[C-1]!==E[C]&&(E[S]=E[C],S++);E.length=S}switch(E.length){case 1:return E[0];case 2:return E[0]+\" or \"+E[1];default:return E.slice(0,-1).join(\", \")+\", or \"+E[E.length-1]}}function p(h){return h?'\"'+a(h)+'\"':\"end of input\"}return\"Expected \"+f(t)+\" but \"+p(e)+\" found.\"};function Fqe(t,e){e=e!==void 0?e:{};var r={},s={Start:Wa},a=Wa,n=function(O){return O||[]},c=function(O,K,re){return[{command:O,type:K}].concat(re||[])},f=function(O,K){return[{command:O,type:K||\";\"}]},p=function(O){return O},h=\";\",E=ur(\";\",!1),C=\"&\",S=ur(\"&\",!1),b=function(O,K){return K?{chain:O,then:K}:{chain:O}},I=function(O,K){return{type:O,line:K}},T=\"&&\",N=ur(\"&&\",!1),U=\"||\",W=ur(\"||\",!1),ee=function(O,K){return K?{...O,then:K}:O},ie=function(O,K){return{type:O,chain:K}},ue=\"|&\",le=ur(\"|&\",!1),me=\"|\",pe=ur(\"|\",!1),Be=\"=\",Ce=ur(\"=\",!1),g=function(O,K){return{name:O,args:[K]}},we=function(O){return{name:O,args:[]}},ye=\"(\",Ae=ur(\"(\",!1),se=\")\",X=ur(\")\",!1),De=function(O,K){return{type:\"subshell\",subshell:O,args:K}},Te=\"{\",mt=ur(\"{\",!1),j=\"}\",rt=ur(\"}\",!1),Fe=function(O,K){return{type:\"group\",group:O,args:K}},Ne=function(O,K){return{type:\"command\",args:K,envs:O}},be=function(O){return{type:\"envs\",envs:O}},Ve=function(O){return O},ke=function(O){return O},it=/^[0-9]/,Ue=Ki([[\"0\",\"9\"]],!1,!1),x=function(O,K,re){return{type:\"redirection\",subtype:K,fd:O!==null?parseInt(O):null,args:[re]}},w=\">>\",P=ur(\">>\",!1),y=\">&\",F=ur(\">&\",!1),z=\">\",Z=ur(\">\",!1),$=\"<<<\",oe=ur(\"<<<\",!1),xe=\"<&\",Re=ur(\"<&\",!1),lt=\"<\",Ct=ur(\"<\",!1),qt=function(O){return{type:\"argument\",segments:[].concat(...O)}},ir=function(O){return O},bt=\"$'\",gn=ur(\"$'\",!1),br=\"'\",Ir=ur(\"'\",!1),Or=function(O){return[{type:\"text\",text:O}]},nn='\"\"',ai=ur('\"\"',!1),Io=function(){return{type:\"text\",text:\"\"}},ts='\"',$s=ur('\"',!1),Co=function(O){return O},Hi=function(O){return{type:\"arithmetic\",arithmetic:O,quoted:!0}},eo=function(O){return{type:\"shell\",shell:O,quoted:!0}},wo=function(O){return{type:\"variable\",...O,quoted:!0}},QA=function(O){return{type:\"text\",text:O}},Af=function(O){return{type:\"arithmetic\",arithmetic:O,quoted:!1}},dh=function(O){return{type:\"shell\",shell:O,quoted:!1}},mh=function(O){return{type:\"variable\",...O,quoted:!1}},to=function(O){return{type:\"glob\",pattern:O}},jn=/^[^']/,Rs=Ki([\"'\"],!0,!1),ro=function(O){return O.join(\"\")},ou=/^[^$\"]/,au=Ki([\"$\",'\"'],!0,!1),lu=`\\\\\n`,RA=ur(`\\\\\n`,!1),TA=function(){return\"\"},oa=\"\\\\\",aa=ur(\"\\\\\",!1),FA=/^[\\\\$\"`]/,gr=Ki([\"\\\\\",\"$\",'\"',\"`\"],!1,!1),Bo=function(O){return O},Me=\"\\\\a\",cu=ur(\"\\\\a\",!1),Cr=function(){return\"a\"},pf=\"\\\\b\",NA=ur(\"\\\\b\",!1),OA=function(){return\"\\b\"},uu=/^[Ee]/,fu=Ki([\"E\",\"e\"],!1,!1),oc=function(){return\"\\x1B\"},ve=\"\\\\f\",Nt=ur(\"\\\\f\",!1),ac=function(){return\"\\f\"},Oi=\"\\\\n\",no=ur(\"\\\\n\",!1),Tt=function(){return`\n`},xn=\"\\\\r\",la=ur(\"\\\\r\",!1),ji=function(){return\"\\r\"},Li=\"\\\\t\",Na=ur(\"\\\\t\",!1),dn=function(){return\"\t\"},Kn=\"\\\\v\",Au=ur(\"\\\\v\",!1),yh=function(){return\"\\v\"},Oa=/^[\\\\'\"?]/,La=Ki([\"\\\\\",\"'\",'\"',\"?\"],!1,!1),Ma=function(O){return String.fromCharCode(parseInt(O,16))},$e=\"\\\\x\",Ua=ur(\"\\\\x\",!1),hf=\"\\\\u\",lc=ur(\"\\\\u\",!1),wn=\"\\\\U\",ca=ur(\"\\\\U\",!1),LA=function(O){return String.fromCodePoint(parseInt(O,16))},MA=/^[0-7]/,ua=Ki([[\"0\",\"7\"]],!1,!1),Bl=/^[0-9a-fA-f]/,Mt=Ki([[\"0\",\"9\"],[\"a\",\"f\"],[\"A\",\"f\"]],!1,!1),kn=yf(),fa=\"{}\",Ha=ur(\"{}\",!1),rs=function(){return\"{}\"},cc=\"-\",pu=ur(\"-\",!1),uc=\"+\",ja=ur(\"+\",!1),Mi=\".\",Is=ur(\".\",!1),vl=function(O,K,re){return{type:\"number\",value:(O===\"-\"?-1:1)*parseFloat(K.join(\"\")+\".\"+re.join(\"\"))}},gf=function(O,K){return{type:\"number\",value:(O===\"-\"?-1:1)*parseInt(K.join(\"\"))}},fc=function(O){return{type:\"variable\",...O}},wi=function(O){return{type:\"variable\",name:O}},Qn=function(O){return O},Ac=\"*\",Ke=ur(\"*\",!1),st=\"/\",St=ur(\"/\",!1),lr=function(O,K,re){return{type:K===\"*\"?\"multiplication\":\"division\",right:re}},te=function(O,K){return K.reduce((re,de)=>({left:re,...de}),O)},Ee=function(O,K,re){return{type:K===\"+\"?\"addition\":\"subtraction\",right:re}},Oe=\"$((\",dt=ur(\"$((\",!1),Et=\"))\",Pt=ur(\"))\",!1),tr=function(O){return O},An=\"$(\",li=ur(\"$(\",!1),Gi=function(O){return O},Rn=\"${\",Ga=ur(\"${\",!1),my=\":-\",X1=ur(\":-\",!1),vo=function(O,K){return{name:O,defaultValue:K}},yy=\":-}\",Eh=ur(\":-}\",!1),$1=function(O){return{name:O,defaultValue:[]}},So=\":+\",Ih=ur(\":+\",!1),Ch=function(O,K){return{name:O,alternativeValue:K}},hu=\":+}\",wh=ur(\":+}\",!1),Fg=function(O){return{name:O,alternativeValue:[]}},Ng=function(O){return{name:O}},Og=\"$\",Ey=ur(\"$\",!1),df=function(O){return e.isGlobPattern(O)},Do=function(O){return O},Sl=/^[a-zA-Z0-9_]/,Bh=Ki([[\"a\",\"z\"],[\"A\",\"Z\"],[\"0\",\"9\"],\"_\"],!1,!1),Lg=function(){return By()},Dl=/^[$@*?#a-zA-Z0-9_\\-]/,Pl=Ki([\"$\",\"@\",\"*\",\"?\",\"#\",[\"a\",\"z\"],[\"A\",\"Z\"],[\"0\",\"9\"],\"_\",\"-\"],!1,!1),Iy=/^[()}<>$|&; \\t\"']/,UA=Ki([\"(\",\")\",\"}\",\"<\",\">\",\"$\",\"|\",\"&\",\";\",\" \",\"\t\",'\"',\"'\"],!1,!1),Cy=/^[<>&; \\t\"']/,wy=Ki([\"<\",\">\",\"&\",\";\",\" \",\"\t\",'\"',\"'\"],!1,!1),_A=/^[ \\t]/,HA=Ki([\" \",\"\t\"],!1,!1),Y=0,xt=0,jA=[{line:1,column:1}],Po=0,mf=[],yt=0,gu;if(\"startRule\"in e){if(!(e.startRule in s))throw new Error(`Can't start parsing from rule \"`+e.startRule+'\".');a=s[e.startRule]}function By(){return t.substring(xt,Y)}function Mg(){return Ef(xt,Y)}function e2(O,K){throw K=K!==void 0?K:Ef(xt,Y),GA([Ug(O)],t.substring(xt,Y),K)}function vh(O,K){throw K=K!==void 0?K:Ef(xt,Y),di(O,K)}function ur(O,K){return{type:\"literal\",text:O,ignoreCase:K}}function Ki(O,K,re){return{type:\"class\",parts:O,inverted:K,ignoreCase:re}}function yf(){return{type:\"any\"}}function qa(){return{type:\"end\"}}function Ug(O){return{type:\"other\",description:O}}function du(O){var K=jA[O],re;if(K)return K;for(re=O-1;!jA[re];)re--;for(K=jA[re],K={line:K.line,column:K.column};re<O;)t.charCodeAt(re)===10?(K.line++,K.column=1):K.column++,re++;return jA[O]=K,K}function Ef(O,K){var re=du(O),de=du(K);return{start:{offset:O,line:re.line,column:re.column},end:{offset:K,line:de.line,column:de.column}}}function wt(O){Y<Po||(Y>Po&&(Po=Y,mf=[]),mf.push(O))}function di(O,K){return new Bd(O,null,null,K)}function GA(O,K,re){return new Bd(Bd.buildMessage(O,K),O,K,re)}function Wa(){var O,K,re;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();return K!==r?(re=Aa(),re===r&&(re=null),re!==r?(xt=O,K=n(re),O=K):(Y=O,O=r)):(Y=O,O=r),O}function Aa(){var O,K,re,de,Je;if(O=Y,K=Sh(),K!==r){for(re=[],de=kt();de!==r;)re.push(de),de=kt();re!==r?(de=_g(),de!==r?(Je=Ya(),Je===r&&(Je=null),Je!==r?(xt=O,K=c(K,de,Je),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r)}else Y=O,O=r;if(O===r)if(O=Y,K=Sh(),K!==r){for(re=[],de=kt();de!==r;)re.push(de),de=kt();re!==r?(de=_g(),de===r&&(de=null),de!==r?(xt=O,K=f(K,de),O=K):(Y=O,O=r)):(Y=O,O=r)}else Y=O,O=r;return O}function Ya(){var O,K,re,de,Je;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r)if(re=Aa(),re!==r){for(de=[],Je=kt();Je!==r;)de.push(Je),Je=kt();de!==r?(xt=O,K=p(re),O=K):(Y=O,O=r)}else Y=O,O=r;else Y=O,O=r;return O}function _g(){var O;return t.charCodeAt(Y)===59?(O=h,Y++):(O=r,yt===0&&wt(E)),O===r&&(t.charCodeAt(Y)===38?(O=C,Y++):(O=r,yt===0&&wt(S))),O}function Sh(){var O,K,re;return O=Y,K=qA(),K!==r?(re=Hg(),re===r&&(re=null),re!==r?(xt=O,K=b(K,re),O=K):(Y=O,O=r)):(Y=O,O=r),O}function Hg(){var O,K,re,de,Je,At,dr;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r)if(re=vy(),re!==r){for(de=[],Je=kt();Je!==r;)de.push(Je),Je=kt();if(de!==r)if(Je=Sh(),Je!==r){for(At=[],dr=kt();dr!==r;)At.push(dr),dr=kt();At!==r?(xt=O,K=I(re,Je),O=K):(Y=O,O=r)}else Y=O,O=r;else Y=O,O=r}else Y=O,O=r;else Y=O,O=r;return O}function vy(){var O;return t.substr(Y,2)===T?(O=T,Y+=2):(O=r,yt===0&&wt(N)),O===r&&(t.substr(Y,2)===U?(O=U,Y+=2):(O=r,yt===0&&wt(W))),O}function qA(){var O,K,re;return O=Y,K=If(),K!==r?(re=jg(),re===r&&(re=null),re!==r?(xt=O,K=ee(K,re),O=K):(Y=O,O=r)):(Y=O,O=r),O}function jg(){var O,K,re,de,Je,At,dr;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r)if(re=mu(),re!==r){for(de=[],Je=kt();Je!==r;)de.push(Je),Je=kt();if(de!==r)if(Je=qA(),Je!==r){for(At=[],dr=kt();dr!==r;)At.push(dr),dr=kt();At!==r?(xt=O,K=ie(re,Je),O=K):(Y=O,O=r)}else Y=O,O=r;else Y=O,O=r}else Y=O,O=r;else Y=O,O=r;return O}function mu(){var O;return t.substr(Y,2)===ue?(O=ue,Y+=2):(O=r,yt===0&&wt(le)),O===r&&(t.charCodeAt(Y)===124?(O=me,Y++):(O=r,yt===0&&wt(pe))),O}function yu(){var O,K,re,de,Je,At;if(O=Y,K=bh(),K!==r)if(t.charCodeAt(Y)===61?(re=Be,Y++):(re=r,yt===0&&wt(Ce)),re!==r)if(de=WA(),de!==r){for(Je=[],At=kt();At!==r;)Je.push(At),At=kt();Je!==r?(xt=O,K=g(K,de),O=K):(Y=O,O=r)}else Y=O,O=r;else Y=O,O=r;else Y=O,O=r;if(O===r)if(O=Y,K=bh(),K!==r)if(t.charCodeAt(Y)===61?(re=Be,Y++):(re=r,yt===0&&wt(Ce)),re!==r){for(de=[],Je=kt();Je!==r;)de.push(Je),Je=kt();de!==r?(xt=O,K=we(K),O=K):(Y=O,O=r)}else Y=O,O=r;else Y=O,O=r;return O}function If(){var O,K,re,de,Je,At,dr,vr,Un,mi,Cs;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r)if(t.charCodeAt(Y)===40?(re=ye,Y++):(re=r,yt===0&&wt(Ae)),re!==r){for(de=[],Je=kt();Je!==r;)de.push(Je),Je=kt();if(de!==r)if(Je=Aa(),Je!==r){for(At=[],dr=kt();dr!==r;)At.push(dr),dr=kt();if(At!==r)if(t.charCodeAt(Y)===41?(dr=se,Y++):(dr=r,yt===0&&wt(X)),dr!==r){for(vr=[],Un=kt();Un!==r;)vr.push(Un),Un=kt();if(vr!==r){for(Un=[],mi=Gn();mi!==r;)Un.push(mi),mi=Gn();if(Un!==r){for(mi=[],Cs=kt();Cs!==r;)mi.push(Cs),Cs=kt();mi!==r?(xt=O,K=De(Je,Un),O=K):(Y=O,O=r)}else Y=O,O=r}else Y=O,O=r}else Y=O,O=r;else Y=O,O=r}else Y=O,O=r;else Y=O,O=r}else Y=O,O=r;else Y=O,O=r;if(O===r){for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r)if(t.charCodeAt(Y)===123?(re=Te,Y++):(re=r,yt===0&&wt(mt)),re!==r){for(de=[],Je=kt();Je!==r;)de.push(Je),Je=kt();if(de!==r)if(Je=Aa(),Je!==r){for(At=[],dr=kt();dr!==r;)At.push(dr),dr=kt();if(At!==r)if(t.charCodeAt(Y)===125?(dr=j,Y++):(dr=r,yt===0&&wt(rt)),dr!==r){for(vr=[],Un=kt();Un!==r;)vr.push(Un),Un=kt();if(vr!==r){for(Un=[],mi=Gn();mi!==r;)Un.push(mi),mi=Gn();if(Un!==r){for(mi=[],Cs=kt();Cs!==r;)mi.push(Cs),Cs=kt();mi!==r?(xt=O,K=Fe(Je,Un),O=K):(Y=O,O=r)}else Y=O,O=r}else Y=O,O=r}else Y=O,O=r;else Y=O,O=r}else Y=O,O=r;else Y=O,O=r}else Y=O,O=r;else Y=O,O=r;if(O===r){for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r){for(re=[],de=yu();de!==r;)re.push(de),de=yu();if(re!==r){for(de=[],Je=kt();Je!==r;)de.push(Je),Je=kt();if(de!==r){if(Je=[],At=Eu(),At!==r)for(;At!==r;)Je.push(At),At=Eu();else Je=r;if(Je!==r){for(At=[],dr=kt();dr!==r;)At.push(dr),dr=kt();At!==r?(xt=O,K=Ne(re,Je),O=K):(Y=O,O=r)}else Y=O,O=r}else Y=O,O=r}else Y=O,O=r}else Y=O,O=r;if(O===r){for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r){if(re=[],de=yu(),de!==r)for(;de!==r;)re.push(de),de=yu();else re=r;if(re!==r){for(de=[],Je=kt();Je!==r;)de.push(Je),Je=kt();de!==r?(xt=O,K=be(re),O=K):(Y=O,O=r)}else Y=O,O=r}else Y=O,O=r}}}return O}function Ts(){var O,K,re,de,Je;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r){if(re=[],de=bi(),de!==r)for(;de!==r;)re.push(de),de=bi();else re=r;if(re!==r){for(de=[],Je=kt();Je!==r;)de.push(Je),Je=kt();de!==r?(xt=O,K=Ve(re),O=K):(Y=O,O=r)}else Y=O,O=r}else Y=O,O=r;return O}function Eu(){var O,K,re;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();if(K!==r?(re=Gn(),re!==r?(xt=O,K=ke(re),O=K):(Y=O,O=r)):(Y=O,O=r),O===r){for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();K!==r?(re=bi(),re!==r?(xt=O,K=ke(re),O=K):(Y=O,O=r)):(Y=O,O=r)}return O}function Gn(){var O,K,re,de,Je;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();return K!==r?(it.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(Ue)),re===r&&(re=null),re!==r?(de=ns(),de!==r?(Je=bi(),Je!==r?(xt=O,K=x(re,de,Je),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r),O}function ns(){var O;return t.substr(Y,2)===w?(O=w,Y+=2):(O=r,yt===0&&wt(P)),O===r&&(t.substr(Y,2)===y?(O=y,Y+=2):(O=r,yt===0&&wt(F)),O===r&&(t.charCodeAt(Y)===62?(O=z,Y++):(O=r,yt===0&&wt(Z)),O===r&&(t.substr(Y,3)===$?(O=$,Y+=3):(O=r,yt===0&&wt(oe)),O===r&&(t.substr(Y,2)===xe?(O=xe,Y+=2):(O=r,yt===0&&wt(Re)),O===r&&(t.charCodeAt(Y)===60?(O=lt,Y++):(O=r,yt===0&&wt(Ct))))))),O}function bi(){var O,K,re;for(O=Y,K=[],re=kt();re!==r;)K.push(re),re=kt();return K!==r?(re=WA(),re!==r?(xt=O,K=ke(re),O=K):(Y=O,O=r)):(Y=O,O=r),O}function WA(){var O,K,re;if(O=Y,K=[],re=Cf(),re!==r)for(;re!==r;)K.push(re),re=Cf();else K=r;return K!==r&&(xt=O,K=qt(K)),O=K,O}function Cf(){var O,K;return O=Y,K=mn(),K!==r&&(xt=O,K=ir(K)),O=K,O===r&&(O=Y,K=Gg(),K!==r&&(xt=O,K=ir(K)),O=K,O===r&&(O=Y,K=qg(),K!==r&&(xt=O,K=ir(K)),O=K,O===r&&(O=Y,K=is(),K!==r&&(xt=O,K=ir(K)),O=K))),O}function mn(){var O,K,re,de;return O=Y,t.substr(Y,2)===bt?(K=bt,Y+=2):(K=r,yt===0&&wt(gn)),K!==r?(re=yn(),re!==r?(t.charCodeAt(Y)===39?(de=br,Y++):(de=r,yt===0&&wt(Ir)),de!==r?(xt=O,K=Or(re),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r),O}function Gg(){var O,K,re,de;return O=Y,t.charCodeAt(Y)===39?(K=br,Y++):(K=r,yt===0&&wt(Ir)),K!==r?(re=wf(),re!==r?(t.charCodeAt(Y)===39?(de=br,Y++):(de=r,yt===0&&wt(Ir)),de!==r?(xt=O,K=Or(re),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r),O}function qg(){var O,K,re,de;if(O=Y,t.substr(Y,2)===nn?(K=nn,Y+=2):(K=r,yt===0&&wt(ai)),K!==r&&(xt=O,K=Io()),O=K,O===r)if(O=Y,t.charCodeAt(Y)===34?(K=ts,Y++):(K=r,yt===0&&wt($s)),K!==r){for(re=[],de=bl();de!==r;)re.push(de),de=bl();re!==r?(t.charCodeAt(Y)===34?(de=ts,Y++):(de=r,yt===0&&wt($s)),de!==r?(xt=O,K=Co(re),O=K):(Y=O,O=r)):(Y=O,O=r)}else Y=O,O=r;return O}function is(){var O,K,re;if(O=Y,K=[],re=bo(),re!==r)for(;re!==r;)K.push(re),re=bo();else K=r;return K!==r&&(xt=O,K=Co(K)),O=K,O}function bl(){var O,K;return O=Y,K=Xr(),K!==r&&(xt=O,K=Hi(K)),O=K,O===r&&(O=Y,K=Ph(),K!==r&&(xt=O,K=eo(K)),O=K,O===r&&(O=Y,K=VA(),K!==r&&(xt=O,K=wo(K)),O=K,O===r&&(O=Y,K=Bf(),K!==r&&(xt=O,K=QA(K)),O=K))),O}function bo(){var O,K;return O=Y,K=Xr(),K!==r&&(xt=O,K=Af(K)),O=K,O===r&&(O=Y,K=Ph(),K!==r&&(xt=O,K=dh(K)),O=K,O===r&&(O=Y,K=VA(),K!==r&&(xt=O,K=mh(K)),O=K,O===r&&(O=Y,K=Sy(),K!==r&&(xt=O,K=to(K)),O=K,O===r&&(O=Y,K=Dh(),K!==r&&(xt=O,K=QA(K)),O=K)))),O}function wf(){var O,K,re;for(O=Y,K=[],jn.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(Rs));re!==r;)K.push(re),jn.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(Rs));return K!==r&&(xt=O,K=ro(K)),O=K,O}function Bf(){var O,K,re;if(O=Y,K=[],re=xl(),re===r&&(ou.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(au))),re!==r)for(;re!==r;)K.push(re),re=xl(),re===r&&(ou.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(au)));else K=r;return K!==r&&(xt=O,K=ro(K)),O=K,O}function xl(){var O,K,re;return O=Y,t.substr(Y,2)===lu?(K=lu,Y+=2):(K=r,yt===0&&wt(RA)),K!==r&&(xt=O,K=TA()),O=K,O===r&&(O=Y,t.charCodeAt(Y)===92?(K=oa,Y++):(K=r,yt===0&&wt(aa)),K!==r?(FA.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(gr)),re!==r?(xt=O,K=Bo(re),O=K):(Y=O,O=r)):(Y=O,O=r)),O}function yn(){var O,K,re;for(O=Y,K=[],re=xo(),re===r&&(jn.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(Rs)));re!==r;)K.push(re),re=xo(),re===r&&(jn.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(Rs)));return K!==r&&(xt=O,K=ro(K)),O=K,O}function xo(){var O,K,re;return O=Y,t.substr(Y,2)===Me?(K=Me,Y+=2):(K=r,yt===0&&wt(cu)),K!==r&&(xt=O,K=Cr()),O=K,O===r&&(O=Y,t.substr(Y,2)===pf?(K=pf,Y+=2):(K=r,yt===0&&wt(NA)),K!==r&&(xt=O,K=OA()),O=K,O===r&&(O=Y,t.charCodeAt(Y)===92?(K=oa,Y++):(K=r,yt===0&&wt(aa)),K!==r?(uu.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(fu)),re!==r?(xt=O,K=oc(),O=K):(Y=O,O=r)):(Y=O,O=r),O===r&&(O=Y,t.substr(Y,2)===ve?(K=ve,Y+=2):(K=r,yt===0&&wt(Nt)),K!==r&&(xt=O,K=ac()),O=K,O===r&&(O=Y,t.substr(Y,2)===Oi?(K=Oi,Y+=2):(K=r,yt===0&&wt(no)),K!==r&&(xt=O,K=Tt()),O=K,O===r&&(O=Y,t.substr(Y,2)===xn?(K=xn,Y+=2):(K=r,yt===0&&wt(la)),K!==r&&(xt=O,K=ji()),O=K,O===r&&(O=Y,t.substr(Y,2)===Li?(K=Li,Y+=2):(K=r,yt===0&&wt(Na)),K!==r&&(xt=O,K=dn()),O=K,O===r&&(O=Y,t.substr(Y,2)===Kn?(K=Kn,Y+=2):(K=r,yt===0&&wt(Au)),K!==r&&(xt=O,K=yh()),O=K,O===r&&(O=Y,t.charCodeAt(Y)===92?(K=oa,Y++):(K=r,yt===0&&wt(aa)),K!==r?(Oa.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(La)),re!==r?(xt=O,K=Bo(re),O=K):(Y=O,O=r)):(Y=O,O=r),O===r&&(O=Iu()))))))))),O}function Iu(){var O,K,re,de,Je,At,dr,vr,Un,mi,Cs,JA;return O=Y,t.charCodeAt(Y)===92?(K=oa,Y++):(K=r,yt===0&&wt(aa)),K!==r?(re=pa(),re!==r?(xt=O,K=Ma(re),O=K):(Y=O,O=r)):(Y=O,O=r),O===r&&(O=Y,t.substr(Y,2)===$e?(K=$e,Y+=2):(K=r,yt===0&&wt(Ua)),K!==r?(re=Y,de=Y,Je=pa(),Je!==r?(At=Fs(),At!==r?(Je=[Je,At],de=Je):(Y=de,de=r)):(Y=de,de=r),de===r&&(de=pa()),de!==r?re=t.substring(re,Y):re=de,re!==r?(xt=O,K=Ma(re),O=K):(Y=O,O=r)):(Y=O,O=r),O===r&&(O=Y,t.substr(Y,2)===hf?(K=hf,Y+=2):(K=r,yt===0&&wt(lc)),K!==r?(re=Y,de=Y,Je=Fs(),Je!==r?(At=Fs(),At!==r?(dr=Fs(),dr!==r?(vr=Fs(),vr!==r?(Je=[Je,At,dr,vr],de=Je):(Y=de,de=r)):(Y=de,de=r)):(Y=de,de=r)):(Y=de,de=r),de!==r?re=t.substring(re,Y):re=de,re!==r?(xt=O,K=Ma(re),O=K):(Y=O,O=r)):(Y=O,O=r),O===r&&(O=Y,t.substr(Y,2)===wn?(K=wn,Y+=2):(K=r,yt===0&&wt(ca)),K!==r?(re=Y,de=Y,Je=Fs(),Je!==r?(At=Fs(),At!==r?(dr=Fs(),dr!==r?(vr=Fs(),vr!==r?(Un=Fs(),Un!==r?(mi=Fs(),mi!==r?(Cs=Fs(),Cs!==r?(JA=Fs(),JA!==r?(Je=[Je,At,dr,vr,Un,mi,Cs,JA],de=Je):(Y=de,de=r)):(Y=de,de=r)):(Y=de,de=r)):(Y=de,de=r)):(Y=de,de=r)):(Y=de,de=r)):(Y=de,de=r)):(Y=de,de=r),de!==r?re=t.substring(re,Y):re=de,re!==r?(xt=O,K=LA(re),O=K):(Y=O,O=r)):(Y=O,O=r)))),O}function pa(){var O;return MA.test(t.charAt(Y))?(O=t.charAt(Y),Y++):(O=r,yt===0&&wt(ua)),O}function Fs(){var O;return Bl.test(t.charAt(Y))?(O=t.charAt(Y),Y++):(O=r,yt===0&&wt(Mt)),O}function Dh(){var O,K,re,de,Je;if(O=Y,K=[],re=Y,t.charCodeAt(Y)===92?(de=oa,Y++):(de=r,yt===0&&wt(aa)),de!==r?(t.length>Y?(Je=t.charAt(Y),Y++):(Je=r,yt===0&&wt(kn)),Je!==r?(xt=re,de=Bo(Je),re=de):(Y=re,re=r)):(Y=re,re=r),re===r&&(re=Y,t.substr(Y,2)===fa?(de=fa,Y+=2):(de=r,yt===0&&wt(Ha)),de!==r&&(xt=re,de=rs()),re=de,re===r&&(re=Y,de=Y,yt++,Je=Dy(),yt--,Je===r?de=void 0:(Y=de,de=r),de!==r?(t.length>Y?(Je=t.charAt(Y),Y++):(Je=r,yt===0&&wt(kn)),Je!==r?(xt=re,de=Bo(Je),re=de):(Y=re,re=r)):(Y=re,re=r))),re!==r)for(;re!==r;)K.push(re),re=Y,t.charCodeAt(Y)===92?(de=oa,Y++):(de=r,yt===0&&wt(aa)),de!==r?(t.length>Y?(Je=t.charAt(Y),Y++):(Je=r,yt===0&&wt(kn)),Je!==r?(xt=re,de=Bo(Je),re=de):(Y=re,re=r)):(Y=re,re=r),re===r&&(re=Y,t.substr(Y,2)===fa?(de=fa,Y+=2):(de=r,yt===0&&wt(Ha)),de!==r&&(xt=re,de=rs()),re=de,re===r&&(re=Y,de=Y,yt++,Je=Dy(),yt--,Je===r?de=void 0:(Y=de,de=r),de!==r?(t.length>Y?(Je=t.charAt(Y),Y++):(Je=r,yt===0&&wt(kn)),Je!==r?(xt=re,de=Bo(Je),re=de):(Y=re,re=r)):(Y=re,re=r)));else K=r;return K!==r&&(xt=O,K=ro(K)),O=K,O}function YA(){var O,K,re,de,Je,At;if(O=Y,t.charCodeAt(Y)===45?(K=cc,Y++):(K=r,yt===0&&wt(pu)),K===r&&(t.charCodeAt(Y)===43?(K=uc,Y++):(K=r,yt===0&&wt(ja))),K===r&&(K=null),K!==r){if(re=[],it.test(t.charAt(Y))?(de=t.charAt(Y),Y++):(de=r,yt===0&&wt(Ue)),de!==r)for(;de!==r;)re.push(de),it.test(t.charAt(Y))?(de=t.charAt(Y),Y++):(de=r,yt===0&&wt(Ue));else re=r;if(re!==r)if(t.charCodeAt(Y)===46?(de=Mi,Y++):(de=r,yt===0&&wt(Is)),de!==r){if(Je=[],it.test(t.charAt(Y))?(At=t.charAt(Y),Y++):(At=r,yt===0&&wt(Ue)),At!==r)for(;At!==r;)Je.push(At),it.test(t.charAt(Y))?(At=t.charAt(Y),Y++):(At=r,yt===0&&wt(Ue));else Je=r;Je!==r?(xt=O,K=vl(K,re,Je),O=K):(Y=O,O=r)}else Y=O,O=r;else Y=O,O=r}else Y=O,O=r;if(O===r){if(O=Y,t.charCodeAt(Y)===45?(K=cc,Y++):(K=r,yt===0&&wt(pu)),K===r&&(t.charCodeAt(Y)===43?(K=uc,Y++):(K=r,yt===0&&wt(ja))),K===r&&(K=null),K!==r){if(re=[],it.test(t.charAt(Y))?(de=t.charAt(Y),Y++):(de=r,yt===0&&wt(Ue)),de!==r)for(;de!==r;)re.push(de),it.test(t.charAt(Y))?(de=t.charAt(Y),Y++):(de=r,yt===0&&wt(Ue));else re=r;re!==r?(xt=O,K=gf(K,re),O=K):(Y=O,O=r)}else Y=O,O=r;if(O===r&&(O=Y,K=VA(),K!==r&&(xt=O,K=fc(K)),O=K,O===r&&(O=Y,K=pc(),K!==r&&(xt=O,K=wi(K)),O=K,O===r)))if(O=Y,t.charCodeAt(Y)===40?(K=ye,Y++):(K=r,yt===0&&wt(Ae)),K!==r){for(re=[],de=kt();de!==r;)re.push(de),de=kt();if(re!==r)if(de=io(),de!==r){for(Je=[],At=kt();At!==r;)Je.push(At),At=kt();Je!==r?(t.charCodeAt(Y)===41?(At=se,Y++):(At=r,yt===0&&wt(X)),At!==r?(xt=O,K=Qn(de),O=K):(Y=O,O=r)):(Y=O,O=r)}else Y=O,O=r;else Y=O,O=r}else Y=O,O=r}return O}function vf(){var O,K,re,de,Je,At,dr,vr;if(O=Y,K=YA(),K!==r){for(re=[],de=Y,Je=[],At=kt();At!==r;)Je.push(At),At=kt();if(Je!==r)if(t.charCodeAt(Y)===42?(At=Ac,Y++):(At=r,yt===0&&wt(Ke)),At===r&&(t.charCodeAt(Y)===47?(At=st,Y++):(At=r,yt===0&&wt(St))),At!==r){for(dr=[],vr=kt();vr!==r;)dr.push(vr),vr=kt();dr!==r?(vr=YA(),vr!==r?(xt=de,Je=lr(K,At,vr),de=Je):(Y=de,de=r)):(Y=de,de=r)}else Y=de,de=r;else Y=de,de=r;for(;de!==r;){for(re.push(de),de=Y,Je=[],At=kt();At!==r;)Je.push(At),At=kt();if(Je!==r)if(t.charCodeAt(Y)===42?(At=Ac,Y++):(At=r,yt===0&&wt(Ke)),At===r&&(t.charCodeAt(Y)===47?(At=st,Y++):(At=r,yt===0&&wt(St))),At!==r){for(dr=[],vr=kt();vr!==r;)dr.push(vr),vr=kt();dr!==r?(vr=YA(),vr!==r?(xt=de,Je=lr(K,At,vr),de=Je):(Y=de,de=r)):(Y=de,de=r)}else Y=de,de=r;else Y=de,de=r}re!==r?(xt=O,K=te(K,re),O=K):(Y=O,O=r)}else Y=O,O=r;return O}function io(){var O,K,re,de,Je,At,dr,vr;if(O=Y,K=vf(),K!==r){for(re=[],de=Y,Je=[],At=kt();At!==r;)Je.push(At),At=kt();if(Je!==r)if(t.charCodeAt(Y)===43?(At=uc,Y++):(At=r,yt===0&&wt(ja)),At===r&&(t.charCodeAt(Y)===45?(At=cc,Y++):(At=r,yt===0&&wt(pu))),At!==r){for(dr=[],vr=kt();vr!==r;)dr.push(vr),vr=kt();dr!==r?(vr=vf(),vr!==r?(xt=de,Je=Ee(K,At,vr),de=Je):(Y=de,de=r)):(Y=de,de=r)}else Y=de,de=r;else Y=de,de=r;for(;de!==r;){for(re.push(de),de=Y,Je=[],At=kt();At!==r;)Je.push(At),At=kt();if(Je!==r)if(t.charCodeAt(Y)===43?(At=uc,Y++):(At=r,yt===0&&wt(ja)),At===r&&(t.charCodeAt(Y)===45?(At=cc,Y++):(At=r,yt===0&&wt(pu))),At!==r){for(dr=[],vr=kt();vr!==r;)dr.push(vr),vr=kt();dr!==r?(vr=vf(),vr!==r?(xt=de,Je=Ee(K,At,vr),de=Je):(Y=de,de=r)):(Y=de,de=r)}else Y=de,de=r;else Y=de,de=r}re!==r?(xt=O,K=te(K,re),O=K):(Y=O,O=r)}else Y=O,O=r;return O}function Xr(){var O,K,re,de,Je,At;if(O=Y,t.substr(Y,3)===Oe?(K=Oe,Y+=3):(K=r,yt===0&&wt(dt)),K!==r){for(re=[],de=kt();de!==r;)re.push(de),de=kt();if(re!==r)if(de=io(),de!==r){for(Je=[],At=kt();At!==r;)Je.push(At),At=kt();Je!==r?(t.substr(Y,2)===Et?(At=Et,Y+=2):(At=r,yt===0&&wt(Pt)),At!==r?(xt=O,K=tr(de),O=K):(Y=O,O=r)):(Y=O,O=r)}else Y=O,O=r;else Y=O,O=r}else Y=O,O=r;return O}function Ph(){var O,K,re,de;return O=Y,t.substr(Y,2)===An?(K=An,Y+=2):(K=r,yt===0&&wt(li)),K!==r?(re=Aa(),re!==r?(t.charCodeAt(Y)===41?(de=se,Y++):(de=r,yt===0&&wt(X)),de!==r?(xt=O,K=Gi(re),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r),O}function VA(){var O,K,re,de,Je,At;return O=Y,t.substr(Y,2)===Rn?(K=Rn,Y+=2):(K=r,yt===0&&wt(Ga)),K!==r?(re=pc(),re!==r?(t.substr(Y,2)===my?(de=my,Y+=2):(de=r,yt===0&&wt(X1)),de!==r?(Je=Ts(),Je!==r?(t.charCodeAt(Y)===125?(At=j,Y++):(At=r,yt===0&&wt(rt)),At!==r?(xt=O,K=vo(re,Je),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r),O===r&&(O=Y,t.substr(Y,2)===Rn?(K=Rn,Y+=2):(K=r,yt===0&&wt(Ga)),K!==r?(re=pc(),re!==r?(t.substr(Y,3)===yy?(de=yy,Y+=3):(de=r,yt===0&&wt(Eh)),de!==r?(xt=O,K=$1(re),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r),O===r&&(O=Y,t.substr(Y,2)===Rn?(K=Rn,Y+=2):(K=r,yt===0&&wt(Ga)),K!==r?(re=pc(),re!==r?(t.substr(Y,2)===So?(de=So,Y+=2):(de=r,yt===0&&wt(Ih)),de!==r?(Je=Ts(),Je!==r?(t.charCodeAt(Y)===125?(At=j,Y++):(At=r,yt===0&&wt(rt)),At!==r?(xt=O,K=Ch(re,Je),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r),O===r&&(O=Y,t.substr(Y,2)===Rn?(K=Rn,Y+=2):(K=r,yt===0&&wt(Ga)),K!==r?(re=pc(),re!==r?(t.substr(Y,3)===hu?(de=hu,Y+=3):(de=r,yt===0&&wt(wh)),de!==r?(xt=O,K=Fg(re),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r),O===r&&(O=Y,t.substr(Y,2)===Rn?(K=Rn,Y+=2):(K=r,yt===0&&wt(Ga)),K!==r?(re=pc(),re!==r?(t.charCodeAt(Y)===125?(de=j,Y++):(de=r,yt===0&&wt(rt)),de!==r?(xt=O,K=Ng(re),O=K):(Y=O,O=r)):(Y=O,O=r)):(Y=O,O=r),O===r&&(O=Y,t.charCodeAt(Y)===36?(K=Og,Y++):(K=r,yt===0&&wt(Ey)),K!==r?(re=pc(),re!==r?(xt=O,K=Ng(re),O=K):(Y=O,O=r)):(Y=O,O=r)))))),O}function Sy(){var O,K,re;return O=Y,K=Wg(),K!==r?(xt=Y,re=df(K),re?re=void 0:re=r,re!==r?(xt=O,K=Do(K),O=K):(Y=O,O=r)):(Y=O,O=r),O}function Wg(){var O,K,re,de,Je;if(O=Y,K=[],re=Y,de=Y,yt++,Je=xh(),yt--,Je===r?de=void 0:(Y=de,de=r),de!==r?(t.length>Y?(Je=t.charAt(Y),Y++):(Je=r,yt===0&&wt(kn)),Je!==r?(xt=re,de=Bo(Je),re=de):(Y=re,re=r)):(Y=re,re=r),re!==r)for(;re!==r;)K.push(re),re=Y,de=Y,yt++,Je=xh(),yt--,Je===r?de=void 0:(Y=de,de=r),de!==r?(t.length>Y?(Je=t.charAt(Y),Y++):(Je=r,yt===0&&wt(kn)),Je!==r?(xt=re,de=Bo(Je),re=de):(Y=re,re=r)):(Y=re,re=r);else K=r;return K!==r&&(xt=O,K=ro(K)),O=K,O}function bh(){var O,K,re;if(O=Y,K=[],Sl.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(Bh)),re!==r)for(;re!==r;)K.push(re),Sl.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(Bh));else K=r;return K!==r&&(xt=O,K=Lg()),O=K,O}function pc(){var O,K,re;if(O=Y,K=[],Dl.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(Pl)),re!==r)for(;re!==r;)K.push(re),Dl.test(t.charAt(Y))?(re=t.charAt(Y),Y++):(re=r,yt===0&&wt(Pl));else K=r;return K!==r&&(xt=O,K=Lg()),O=K,O}function Dy(){var O;return Iy.test(t.charAt(Y))?(O=t.charAt(Y),Y++):(O=r,yt===0&&wt(UA)),O}function xh(){var O;return Cy.test(t.charAt(Y))?(O=t.charAt(Y),Y++):(O=r,yt===0&&wt(wy)),O}function kt(){var O,K;if(O=[],_A.test(t.charAt(Y))?(K=t.charAt(Y),Y++):(K=r,yt===0&&wt(HA)),K!==r)for(;K!==r;)O.push(K),_A.test(t.charAt(Y))?(K=t.charAt(Y),Y++):(K=r,yt===0&&wt(HA));else O=r;return O}if(gu=a(),gu!==r&&Y===t.length)return gu;throw gu!==r&&Y<t.length&&wt(qa()),GA(mf,Po<t.length?t.charAt(Po):null,Po<t.length?Ef(Po,Po+1):Ef(Po,Po))}pee.exports={SyntaxError:Bd,parse:Fqe}});function ux(t,e={isGlobPattern:()=>!1}){try{return(0,gee.parse)(t,e)}catch(r){throw r.location&&(r.message=r.message.replace(/(\\.)?$/,` (line ${r.location.start.line}, column ${r.location.start.column})$1`)),r}}function fE(t,{endSemicolon:e=!1}={}){return t.map(({command:r,type:s},a)=>`${fx(r)}${s===\";\"?a!==t.length-1||e?\";\":\"\":\" &\"}`).join(\" \")}function fx(t){return`${AE(t.chain)}${t.then?` ${_U(t.then)}`:\"\"}`}function _U(t){return`${t.type} ${fx(t.line)}`}function AE(t){return`${jU(t)}${t.then?` ${HU(t.then)}`:\"\"}`}function HU(t){return`${t.type} ${AE(t.chain)}`}function jU(t){switch(t.type){case\"command\":return`${t.envs.length>0?`${t.envs.map(e=>cx(e)).join(\" \")} `:\"\"}${t.args.map(e=>GU(e)).join(\" \")}`;case\"subshell\":return`(${fE(t.subshell)})${t.args.length>0?` ${t.args.map(e=>H2(e)).join(\" \")}`:\"\"}`;case\"group\":return`{ ${fE(t.group,{endSemicolon:!0})} }${t.args.length>0?` ${t.args.map(e=>H2(e)).join(\" \")}`:\"\"}`;case\"envs\":return t.envs.map(e=>cx(e)).join(\" \");default:throw new Error(`Unsupported command type:  \"${t.type}\"`)}}function cx(t){return`${t.name}=${t.args[0]?vd(t.args[0]):\"\"}`}function GU(t){switch(t.type){case\"redirection\":return H2(t);case\"argument\":return vd(t);default:throw new Error(`Unsupported argument type: \"${t.type}\"`)}}function H2(t){return`${t.subtype} ${t.args.map(e=>vd(e)).join(\" \")}`}function vd(t){return t.segments.map(e=>qU(e)).join(\"\")}function qU(t){let e=(s,a)=>a?`\"${s}\"`:s,r=s=>s===\"\"?\"''\":s.match(/[()}<>$|&;\"'\\n\\t ]/)?s.match(/['\\t\\p{C}]/u)?s.match(/'/)?`\"${s.replace(/[\"$\\t\\p{C}]/u,Oqe)}\"`:`$'${s.replace(/[\\t\\p{C}]/u,mee)}'`:`'${s}'`:s;switch(t.type){case\"text\":return r(t.text);case\"glob\":return t.pattern;case\"shell\":return e(`$(${fE(t.shell)})`,t.quoted);case\"variable\":return e(typeof t.defaultValue>\"u\"?typeof t.alternativeValue>\"u\"?`\\${${t.name}}`:t.alternativeValue.length===0?`\\${${t.name}:+}`:`\\${${t.name}:+${t.alternativeValue.map(s=>vd(s)).join(\" \")}}`:t.defaultValue.length===0?`\\${${t.name}:-}`:`\\${${t.name}:-${t.defaultValue.map(s=>vd(s)).join(\" \")}}`,t.quoted);case\"arithmetic\":return`$(( ${Ax(t.arithmetic)} ))`;default:throw new Error(`Unsupported argument segment type: \"${t.type}\"`)}}function Ax(t){let e=a=>{switch(a){case\"addition\":return\"+\";case\"subtraction\":return\"-\";case\"multiplication\":return\"*\";case\"division\":return\"/\";default:throw new Error(`Can't extract operator from arithmetic expression of type \"${a}\"`)}},r=(a,n)=>n?`( ${a} )`:a,s=a=>r(Ax(a),![\"number\",\"variable\"].includes(a.type));switch(t.type){case\"number\":return String(t.value);case\"variable\":return t.name;default:return`${s(t.left)} ${e(t.type)} ${s(t.right)}`}}var gee,dee,Nqe,mee,Oqe,yee=Ze(()=>{gee=ut(hee());dee=new Map([[\"\\f\",\"\\\\f\"],[`\n`,\"\\\\n\"],[\"\\r\",\"\\\\r\"],[\"\t\",\"\\\\t\"],[\"\\v\",\"\\\\v\"],[\"\\0\",\"\\\\0\"]]),Nqe=new Map([[\"\\\\\",\"\\\\\\\\\"],[\"$\",\"\\\\$\"],['\"','\\\\\"'],...Array.from(dee,([t,e])=>[t,`\"$'${e}'\"`])]),mee=t=>dee.get(t)??`\\\\x${t.charCodeAt(0).toString(16).padStart(2,\"0\")}`,Oqe=t=>Nqe.get(t)??`\"$'${mee(t)}'\"`});var Iee=_((Wkt,Eee)=>{\"use strict\";function Lqe(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function Sd(t,e,r,s){this.message=t,this.expected=e,this.found=r,this.location=s,this.name=\"SyntaxError\",typeof Error.captureStackTrace==\"function\"&&Error.captureStackTrace(this,Sd)}Lqe(Sd,Error);Sd.buildMessage=function(t,e){var r={literal:function(h){return'\"'+a(h.text)+'\"'},class:function(h){var E=\"\",C;for(C=0;C<h.parts.length;C++)E+=h.parts[C]instanceof Array?n(h.parts[C][0])+\"-\"+n(h.parts[C][1]):n(h.parts[C]);return\"[\"+(h.inverted?\"^\":\"\")+E+\"]\"},any:function(h){return\"any character\"},end:function(h){return\"end of input\"},other:function(h){return h.description}};function s(h){return h.charCodeAt(0).toString(16).toUpperCase()}function a(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\"/g,'\\\\\"').replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(E){return\"\\\\x0\"+s(E)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(E){return\"\\\\x\"+s(E)})}function n(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\\]/g,\"\\\\]\").replace(/\\^/g,\"\\\\^\").replace(/-/g,\"\\\\-\").replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(E){return\"\\\\x0\"+s(E)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(E){return\"\\\\x\"+s(E)})}function c(h){return r[h.type](h)}function f(h){var E=new Array(h.length),C,S;for(C=0;C<h.length;C++)E[C]=c(h[C]);if(E.sort(),E.length>0){for(C=1,S=1;C<E.length;C++)E[C-1]!==E[C]&&(E[S]=E[C],S++);E.length=S}switch(E.length){case 1:return E[0];case 2:return E[0]+\" or \"+E[1];default:return E.slice(0,-1).join(\", \")+\", or \"+E[E.length-1]}}function p(h){return h?'\"'+a(h)+'\"':\"end of input\"}return\"Expected \"+f(t)+\" but \"+p(e)+\" found.\"};function Mqe(t,e){e=e!==void 0?e:{};var r={},s={resolution:Ne},a=Ne,n=\"/\",c=ye(\"/\",!1),f=function(Ue,x){return{from:Ue,descriptor:x}},p=function(Ue){return{descriptor:Ue}},h=\"@\",E=ye(\"@\",!1),C=function(Ue,x){return{fullName:Ue,description:x}},S=function(Ue){return{fullName:Ue}},b=function(){return Be()},I=/^[^\\/@]/,T=Ae([\"/\",\"@\"],!0,!1),N=/^[^\\/]/,U=Ae([\"/\"],!0,!1),W=0,ee=0,ie=[{line:1,column:1}],ue=0,le=[],me=0,pe;if(\"startRule\"in e){if(!(e.startRule in s))throw new Error(`Can't start parsing from rule \"`+e.startRule+'\".');a=s[e.startRule]}function Be(){return t.substring(ee,W)}function Ce(){return mt(ee,W)}function g(Ue,x){throw x=x!==void 0?x:mt(ee,W),Fe([De(Ue)],t.substring(ee,W),x)}function we(Ue,x){throw x=x!==void 0?x:mt(ee,W),rt(Ue,x)}function ye(Ue,x){return{type:\"literal\",text:Ue,ignoreCase:x}}function Ae(Ue,x,w){return{type:\"class\",parts:Ue,inverted:x,ignoreCase:w}}function se(){return{type:\"any\"}}function X(){return{type:\"end\"}}function De(Ue){return{type:\"other\",description:Ue}}function Te(Ue){var x=ie[Ue],w;if(x)return x;for(w=Ue-1;!ie[w];)w--;for(x=ie[w],x={line:x.line,column:x.column};w<Ue;)t.charCodeAt(w)===10?(x.line++,x.column=1):x.column++,w++;return ie[Ue]=x,x}function mt(Ue,x){var w=Te(Ue),P=Te(x);return{start:{offset:Ue,line:w.line,column:w.column},end:{offset:x,line:P.line,column:P.column}}}function j(Ue){W<ue||(W>ue&&(ue=W,le=[]),le.push(Ue))}function rt(Ue,x){return new Sd(Ue,null,null,x)}function Fe(Ue,x,w){return new Sd(Sd.buildMessage(Ue,x),Ue,x,w)}function Ne(){var Ue,x,w,P;return Ue=W,x=be(),x!==r?(t.charCodeAt(W)===47?(w=n,W++):(w=r,me===0&&j(c)),w!==r?(P=be(),P!==r?(ee=Ue,x=f(x,P),Ue=x):(W=Ue,Ue=r)):(W=Ue,Ue=r)):(W=Ue,Ue=r),Ue===r&&(Ue=W,x=be(),x!==r&&(ee=Ue,x=p(x)),Ue=x),Ue}function be(){var Ue,x,w,P;return Ue=W,x=Ve(),x!==r?(t.charCodeAt(W)===64?(w=h,W++):(w=r,me===0&&j(E)),w!==r?(P=it(),P!==r?(ee=Ue,x=C(x,P),Ue=x):(W=Ue,Ue=r)):(W=Ue,Ue=r)):(W=Ue,Ue=r),Ue===r&&(Ue=W,x=Ve(),x!==r&&(ee=Ue,x=S(x)),Ue=x),Ue}function Ve(){var Ue,x,w,P,y;return Ue=W,t.charCodeAt(W)===64?(x=h,W++):(x=r,me===0&&j(E)),x!==r?(w=ke(),w!==r?(t.charCodeAt(W)===47?(P=n,W++):(P=r,me===0&&j(c)),P!==r?(y=ke(),y!==r?(ee=Ue,x=b(),Ue=x):(W=Ue,Ue=r)):(W=Ue,Ue=r)):(W=Ue,Ue=r)):(W=Ue,Ue=r),Ue===r&&(Ue=W,x=ke(),x!==r&&(ee=Ue,x=b()),Ue=x),Ue}function ke(){var Ue,x,w;if(Ue=W,x=[],I.test(t.charAt(W))?(w=t.charAt(W),W++):(w=r,me===0&&j(T)),w!==r)for(;w!==r;)x.push(w),I.test(t.charAt(W))?(w=t.charAt(W),W++):(w=r,me===0&&j(T));else x=r;return x!==r&&(ee=Ue,x=b()),Ue=x,Ue}function it(){var Ue,x,w;if(Ue=W,x=[],N.test(t.charAt(W))?(w=t.charAt(W),W++):(w=r,me===0&&j(U)),w!==r)for(;w!==r;)x.push(w),N.test(t.charAt(W))?(w=t.charAt(W),W++):(w=r,me===0&&j(U));else x=r;return x!==r&&(ee=Ue,x=b()),Ue=x,Ue}if(pe=a(),pe!==r&&W===t.length)return pe;throw pe!==r&&W<t.length&&j(X()),Fe(le,ue<t.length?t.charAt(ue):null,ue<t.length?mt(ue,ue+1):mt(ue,ue))}Eee.exports={SyntaxError:Sd,parse:Mqe}});function px(t){let e=t.match(/^\\*{1,2}\\/(.*)/);if(e)throw new Error(`The override for '${t}' includes a glob pattern. Glob patterns have been removed since their behaviours don't match what you'd expect. Set the override to '${e[1]}' instead.`);try{return(0,Cee.parse)(t)}catch(r){throw r.location&&(r.message=r.message.replace(/(\\.)?$/,` (line ${r.location.start.line}, column ${r.location.start.column})$1`)),r}}function hx(t){let e=\"\";return t.from&&(e+=t.from.fullName,t.from.description&&(e+=`@${t.from.description}`),e+=\"/\"),e+=t.descriptor.fullName,t.descriptor.description&&(e+=`@${t.descriptor.description}`),e}var Cee,wee=Ze(()=>{Cee=ut(Iee())});var Pd=_((Vkt,Dd)=>{\"use strict\";function Bee(t){return typeof t>\"u\"||t===null}function Uqe(t){return typeof t==\"object\"&&t!==null}function _qe(t){return Array.isArray(t)?t:Bee(t)?[]:[t]}function Hqe(t,e){var r,s,a,n;if(e)for(n=Object.keys(e),r=0,s=n.length;r<s;r+=1)a=n[r],t[a]=e[a];return t}function jqe(t,e){var r=\"\",s;for(s=0;s<e;s+=1)r+=t;return r}function Gqe(t){return t===0&&Number.NEGATIVE_INFINITY===1/t}Dd.exports.isNothing=Bee;Dd.exports.isObject=Uqe;Dd.exports.toArray=_qe;Dd.exports.repeat=jqe;Dd.exports.isNegativeZero=Gqe;Dd.exports.extend=Hqe});var pE=_((Jkt,vee)=>{\"use strict\";function j2(t,e){Error.call(this),this.name=\"YAMLException\",this.reason=t,this.mark=e,this.message=(this.reason||\"(unknown reason)\")+(this.mark?\" \"+this.mark.toString():\"\"),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=new Error().stack||\"\"}j2.prototype=Object.create(Error.prototype);j2.prototype.constructor=j2;j2.prototype.toString=function(e){var r=this.name+\": \";return r+=this.reason||\"(unknown reason)\",!e&&this.mark&&(r+=\" \"+this.mark.toString()),r};vee.exports=j2});var Pee=_((Kkt,Dee)=>{\"use strict\";var See=Pd();function WU(t,e,r,s,a){this.name=t,this.buffer=e,this.position=r,this.line=s,this.column=a}WU.prototype.getSnippet=function(e,r){var s,a,n,c,f;if(!this.buffer)return null;for(e=e||4,r=r||75,s=\"\",a=this.position;a>0&&`\\0\\r\n\\x85\\u2028\\u2029`.indexOf(this.buffer.charAt(a-1))===-1;)if(a-=1,this.position-a>r/2-1){s=\" ... \",a+=5;break}for(n=\"\",c=this.position;c<this.buffer.length&&`\\0\\r\n\\x85\\u2028\\u2029`.indexOf(this.buffer.charAt(c))===-1;)if(c+=1,c-this.position>r/2-1){n=\" ... \",c-=5;break}return f=this.buffer.slice(a,c),See.repeat(\" \",e)+s+f+n+`\n`+See.repeat(\" \",e+this.position-a+s.length)+\"^\"};WU.prototype.toString=function(e){var r,s=\"\";return this.name&&(s+='in \"'+this.name+'\" '),s+=\"at line \"+(this.line+1)+\", column \"+(this.column+1),e||(r=this.getSnippet(),r&&(s+=`:\n`+r)),s};Dee.exports=WU});var Ss=_((zkt,xee)=>{\"use strict\";var bee=pE(),qqe=[\"kind\",\"resolve\",\"construct\",\"instanceOf\",\"predicate\",\"represent\",\"defaultStyle\",\"styleAliases\"],Wqe=[\"scalar\",\"sequence\",\"mapping\"];function Yqe(t){var e={};return t!==null&&Object.keys(t).forEach(function(r){t[r].forEach(function(s){e[String(s)]=r})}),e}function Vqe(t,e){if(e=e||{},Object.keys(e).forEach(function(r){if(qqe.indexOf(r)===-1)throw new bee('Unknown option \"'+r+'\" is met in definition of \"'+t+'\" YAML type.')}),this.tag=t,this.kind=e.kind||null,this.resolve=e.resolve||function(){return!0},this.construct=e.construct||function(r){return r},this.instanceOf=e.instanceOf||null,this.predicate=e.predicate||null,this.represent=e.represent||null,this.defaultStyle=e.defaultStyle||null,this.styleAliases=Yqe(e.styleAliases||null),Wqe.indexOf(this.kind)===-1)throw new bee('Unknown kind \"'+this.kind+'\" is specified for \"'+t+'\" YAML type.')}xee.exports=Vqe});var bd=_((Zkt,Qee)=>{\"use strict\";var kee=Pd(),gx=pE(),Jqe=Ss();function YU(t,e,r){var s=[];return t.include.forEach(function(a){r=YU(a,e,r)}),t[e].forEach(function(a){r.forEach(function(n,c){n.tag===a.tag&&n.kind===a.kind&&s.push(c)}),r.push(a)}),r.filter(function(a,n){return s.indexOf(n)===-1})}function Kqe(){var t={scalar:{},sequence:{},mapping:{},fallback:{}},e,r;function s(a){t[a.kind][a.tag]=t.fallback[a.tag]=a}for(e=0,r=arguments.length;e<r;e+=1)arguments[e].forEach(s);return t}function hE(t){this.include=t.include||[],this.implicit=t.implicit||[],this.explicit=t.explicit||[],this.implicit.forEach(function(e){if(e.loadKind&&e.loadKind!==\"scalar\")throw new gx(\"There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.\")}),this.compiledImplicit=YU(this,\"implicit\",[]),this.compiledExplicit=YU(this,\"explicit\",[]),this.compiledTypeMap=Kqe(this.compiledImplicit,this.compiledExplicit)}hE.DEFAULT=null;hE.create=function(){var e,r;switch(arguments.length){case 1:e=hE.DEFAULT,r=arguments[0];break;case 2:e=arguments[0],r=arguments[1];break;default:throw new gx(\"Wrong number of arguments for Schema.create function\")}if(e=kee.toArray(e),r=kee.toArray(r),!e.every(function(s){return s instanceof hE}))throw new gx(\"Specified list of super schemas (or a single Schema object) contains a non-Schema object.\");if(!r.every(function(s){return s instanceof Jqe}))throw new gx(\"Specified list of YAML types (or a single Type object) contains a non-Type object.\");return new hE({include:e,explicit:r})};Qee.exports=hE});var Tee=_((Xkt,Ree)=>{\"use strict\";var zqe=Ss();Ree.exports=new zqe(\"tag:yaml.org,2002:str\",{kind:\"scalar\",construct:function(t){return t!==null?t:\"\"}})});var Nee=_(($kt,Fee)=>{\"use strict\";var Zqe=Ss();Fee.exports=new Zqe(\"tag:yaml.org,2002:seq\",{kind:\"sequence\",construct:function(t){return t!==null?t:[]}})});var Lee=_((eQt,Oee)=>{\"use strict\";var Xqe=Ss();Oee.exports=new Xqe(\"tag:yaml.org,2002:map\",{kind:\"mapping\",construct:function(t){return t!==null?t:{}}})});var dx=_((tQt,Mee)=>{\"use strict\";var $qe=bd();Mee.exports=new $qe({explicit:[Tee(),Nee(),Lee()]})});var _ee=_((rQt,Uee)=>{\"use strict\";var e5e=Ss();function t5e(t){if(t===null)return!0;var e=t.length;return e===1&&t===\"~\"||e===4&&(t===\"null\"||t===\"Null\"||t===\"NULL\")}function r5e(){return null}function n5e(t){return t===null}Uee.exports=new e5e(\"tag:yaml.org,2002:null\",{kind:\"scalar\",resolve:t5e,construct:r5e,predicate:n5e,represent:{canonical:function(){return\"~\"},lowercase:function(){return\"null\"},uppercase:function(){return\"NULL\"},camelcase:function(){return\"Null\"}},defaultStyle:\"lowercase\"})});var jee=_((nQt,Hee)=>{\"use strict\";var i5e=Ss();function s5e(t){if(t===null)return!1;var e=t.length;return e===4&&(t===\"true\"||t===\"True\"||t===\"TRUE\")||e===5&&(t===\"false\"||t===\"False\"||t===\"FALSE\")}function o5e(t){return t===\"true\"||t===\"True\"||t===\"TRUE\"}function a5e(t){return Object.prototype.toString.call(t)===\"[object Boolean]\"}Hee.exports=new i5e(\"tag:yaml.org,2002:bool\",{kind:\"scalar\",resolve:s5e,construct:o5e,predicate:a5e,represent:{lowercase:function(t){return t?\"true\":\"false\"},uppercase:function(t){return t?\"TRUE\":\"FALSE\"},camelcase:function(t){return t?\"True\":\"False\"}},defaultStyle:\"lowercase\"})});var qee=_((iQt,Gee)=>{\"use strict\";var l5e=Pd(),c5e=Ss();function u5e(t){return 48<=t&&t<=57||65<=t&&t<=70||97<=t&&t<=102}function f5e(t){return 48<=t&&t<=55}function A5e(t){return 48<=t&&t<=57}function p5e(t){if(t===null)return!1;var e=t.length,r=0,s=!1,a;if(!e)return!1;if(a=t[r],(a===\"-\"||a===\"+\")&&(a=t[++r]),a===\"0\"){if(r+1===e)return!0;if(a=t[++r],a===\"b\"){for(r++;r<e;r++)if(a=t[r],a!==\"_\"){if(a!==\"0\"&&a!==\"1\")return!1;s=!0}return s&&a!==\"_\"}if(a===\"x\"){for(r++;r<e;r++)if(a=t[r],a!==\"_\"){if(!u5e(t.charCodeAt(r)))return!1;s=!0}return s&&a!==\"_\"}for(;r<e;r++)if(a=t[r],a!==\"_\"){if(!f5e(t.charCodeAt(r)))return!1;s=!0}return s&&a!==\"_\"}if(a===\"_\")return!1;for(;r<e;r++)if(a=t[r],a!==\"_\"){if(a===\":\")break;if(!A5e(t.charCodeAt(r)))return!1;s=!0}return!s||a===\"_\"?!1:a!==\":\"?!0:/^(:[0-5]?[0-9])+$/.test(t.slice(r))}function h5e(t){var e=t,r=1,s,a,n=[];return e.indexOf(\"_\")!==-1&&(e=e.replace(/_/g,\"\")),s=e[0],(s===\"-\"||s===\"+\")&&(s===\"-\"&&(r=-1),e=e.slice(1),s=e[0]),e===\"0\"?0:s===\"0\"?e[1]===\"b\"?r*parseInt(e.slice(2),2):e[1]===\"x\"?r*parseInt(e,16):r*parseInt(e,8):e.indexOf(\":\")!==-1?(e.split(\":\").forEach(function(c){n.unshift(parseInt(c,10))}),e=0,a=1,n.forEach(function(c){e+=c*a,a*=60}),r*e):r*parseInt(e,10)}function g5e(t){return Object.prototype.toString.call(t)===\"[object Number]\"&&t%1===0&&!l5e.isNegativeZero(t)}Gee.exports=new c5e(\"tag:yaml.org,2002:int\",{kind:\"scalar\",resolve:p5e,construct:h5e,predicate:g5e,represent:{binary:function(t){return t>=0?\"0b\"+t.toString(2):\"-0b\"+t.toString(2).slice(1)},octal:function(t){return t>=0?\"0\"+t.toString(8):\"-0\"+t.toString(8).slice(1)},decimal:function(t){return t.toString(10)},hexadecimal:function(t){return t>=0?\"0x\"+t.toString(16).toUpperCase():\"-0x\"+t.toString(16).toUpperCase().slice(1)}},defaultStyle:\"decimal\",styleAliases:{binary:[2,\"bin\"],octal:[8,\"oct\"],decimal:[10,\"dec\"],hexadecimal:[16,\"hex\"]}})});var Vee=_((sQt,Yee)=>{\"use strict\";var Wee=Pd(),d5e=Ss(),m5e=new RegExp(\"^(?:[-+]?(?:0|[1-9][0-9_]*)(?:\\\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\\\.[0-9_]*|[-+]?\\\\.(?:inf|Inf|INF)|\\\\.(?:nan|NaN|NAN))$\");function y5e(t){return!(t===null||!m5e.test(t)||t[t.length-1]===\"_\")}function E5e(t){var e,r,s,a;return e=t.replace(/_/g,\"\").toLowerCase(),r=e[0]===\"-\"?-1:1,a=[],\"+-\".indexOf(e[0])>=0&&(e=e.slice(1)),e===\".inf\"?r===1?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:e===\".nan\"?NaN:e.indexOf(\":\")>=0?(e.split(\":\").forEach(function(n){a.unshift(parseFloat(n,10))}),e=0,s=1,a.forEach(function(n){e+=n*s,s*=60}),r*e):r*parseFloat(e,10)}var I5e=/^[-+]?[0-9]+e/;function C5e(t,e){var r;if(isNaN(t))switch(e){case\"lowercase\":return\".nan\";case\"uppercase\":return\".NAN\";case\"camelcase\":return\".NaN\"}else if(Number.POSITIVE_INFINITY===t)switch(e){case\"lowercase\":return\".inf\";case\"uppercase\":return\".INF\";case\"camelcase\":return\".Inf\"}else if(Number.NEGATIVE_INFINITY===t)switch(e){case\"lowercase\":return\"-.inf\";case\"uppercase\":return\"-.INF\";case\"camelcase\":return\"-.Inf\"}else if(Wee.isNegativeZero(t))return\"-0.0\";return r=t.toString(10),I5e.test(r)?r.replace(\"e\",\".e\"):r}function w5e(t){return Object.prototype.toString.call(t)===\"[object Number]\"&&(t%1!==0||Wee.isNegativeZero(t))}Yee.exports=new d5e(\"tag:yaml.org,2002:float\",{kind:\"scalar\",resolve:y5e,construct:E5e,predicate:w5e,represent:C5e,defaultStyle:\"lowercase\"})});var VU=_((oQt,Jee)=>{\"use strict\";var B5e=bd();Jee.exports=new B5e({include:[dx()],implicit:[_ee(),jee(),qee(),Vee()]})});var JU=_((aQt,Kee)=>{\"use strict\";var v5e=bd();Kee.exports=new v5e({include:[VU()]})});var $ee=_((lQt,Xee)=>{\"use strict\";var S5e=Ss(),zee=new RegExp(\"^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$\"),Zee=new RegExp(\"^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\\\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\\\.([0-9]*))?(?:[ \\\\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$\");function D5e(t){return t===null?!1:zee.exec(t)!==null||Zee.exec(t)!==null}function P5e(t){var e,r,s,a,n,c,f,p=0,h=null,E,C,S;if(e=zee.exec(t),e===null&&(e=Zee.exec(t)),e===null)throw new Error(\"Date resolve error\");if(r=+e[1],s=+e[2]-1,a=+e[3],!e[4])return new Date(Date.UTC(r,s,a));if(n=+e[4],c=+e[5],f=+e[6],e[7]){for(p=e[7].slice(0,3);p.length<3;)p+=\"0\";p=+p}return e[9]&&(E=+e[10],C=+(e[11]||0),h=(E*60+C)*6e4,e[9]===\"-\"&&(h=-h)),S=new Date(Date.UTC(r,s,a,n,c,f,p)),h&&S.setTime(S.getTime()-h),S}function b5e(t){return t.toISOString()}Xee.exports=new S5e(\"tag:yaml.org,2002:timestamp\",{kind:\"scalar\",resolve:D5e,construct:P5e,instanceOf:Date,represent:b5e})});var tte=_((cQt,ete)=>{\"use strict\";var x5e=Ss();function k5e(t){return t===\"<<\"||t===null}ete.exports=new x5e(\"tag:yaml.org,2002:merge\",{kind:\"scalar\",resolve:k5e})});var ite=_((uQt,nte)=>{\"use strict\";var xd;try{rte=Ie,xd=rte(\"buffer\").Buffer}catch{}var rte,Q5e=Ss(),KU=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\\r`;function R5e(t){if(t===null)return!1;var e,r,s=0,a=t.length,n=KU;for(r=0;r<a;r++)if(e=n.indexOf(t.charAt(r)),!(e>64)){if(e<0)return!1;s+=6}return s%8===0}function T5e(t){var e,r,s=t.replace(/[\\r\\n=]/g,\"\"),a=s.length,n=KU,c=0,f=[];for(e=0;e<a;e++)e%4===0&&e&&(f.push(c>>16&255),f.push(c>>8&255),f.push(c&255)),c=c<<6|n.indexOf(s.charAt(e));return r=a%4*6,r===0?(f.push(c>>16&255),f.push(c>>8&255),f.push(c&255)):r===18?(f.push(c>>10&255),f.push(c>>2&255)):r===12&&f.push(c>>4&255),xd?xd.from?xd.from(f):new xd(f):f}function F5e(t){var e=\"\",r=0,s,a,n=t.length,c=KU;for(s=0;s<n;s++)s%3===0&&s&&(e+=c[r>>18&63],e+=c[r>>12&63],e+=c[r>>6&63],e+=c[r&63]),r=(r<<8)+t[s];return a=n%3,a===0?(e+=c[r>>18&63],e+=c[r>>12&63],e+=c[r>>6&63],e+=c[r&63]):a===2?(e+=c[r>>10&63],e+=c[r>>4&63],e+=c[r<<2&63],e+=c[64]):a===1&&(e+=c[r>>2&63],e+=c[r<<4&63],e+=c[64],e+=c[64]),e}function N5e(t){return xd&&xd.isBuffer(t)}nte.exports=new Q5e(\"tag:yaml.org,2002:binary\",{kind:\"scalar\",resolve:R5e,construct:T5e,predicate:N5e,represent:F5e})});var ote=_((AQt,ste)=>{\"use strict\";var O5e=Ss(),L5e=Object.prototype.hasOwnProperty,M5e=Object.prototype.toString;function U5e(t){if(t===null)return!0;var e=[],r,s,a,n,c,f=t;for(r=0,s=f.length;r<s;r+=1){if(a=f[r],c=!1,M5e.call(a)!==\"[object Object]\")return!1;for(n in a)if(L5e.call(a,n))if(!c)c=!0;else return!1;if(!c)return!1;if(e.indexOf(n)===-1)e.push(n);else return!1}return!0}function _5e(t){return t!==null?t:[]}ste.exports=new O5e(\"tag:yaml.org,2002:omap\",{kind:\"sequence\",resolve:U5e,construct:_5e})});var lte=_((pQt,ate)=>{\"use strict\";var H5e=Ss(),j5e=Object.prototype.toString;function G5e(t){if(t===null)return!0;var e,r,s,a,n,c=t;for(n=new Array(c.length),e=0,r=c.length;e<r;e+=1){if(s=c[e],j5e.call(s)!==\"[object Object]\"||(a=Object.keys(s),a.length!==1))return!1;n[e]=[a[0],s[a[0]]]}return!0}function q5e(t){if(t===null)return[];var e,r,s,a,n,c=t;for(n=new Array(c.length),e=0,r=c.length;e<r;e+=1)s=c[e],a=Object.keys(s),n[e]=[a[0],s[a[0]]];return n}ate.exports=new H5e(\"tag:yaml.org,2002:pairs\",{kind:\"sequence\",resolve:G5e,construct:q5e})});var ute=_((hQt,cte)=>{\"use strict\";var W5e=Ss(),Y5e=Object.prototype.hasOwnProperty;function V5e(t){if(t===null)return!0;var e,r=t;for(e in r)if(Y5e.call(r,e)&&r[e]!==null)return!1;return!0}function J5e(t){return t!==null?t:{}}cte.exports=new W5e(\"tag:yaml.org,2002:set\",{kind:\"mapping\",resolve:V5e,construct:J5e})});var gE=_((gQt,fte)=>{\"use strict\";var K5e=bd();fte.exports=new K5e({include:[JU()],implicit:[$ee(),tte()],explicit:[ite(),ote(),lte(),ute()]})});var pte=_((dQt,Ate)=>{\"use strict\";var z5e=Ss();function Z5e(){return!0}function X5e(){}function $5e(){return\"\"}function e9e(t){return typeof t>\"u\"}Ate.exports=new z5e(\"tag:yaml.org,2002:js/undefined\",{kind:\"scalar\",resolve:Z5e,construct:X5e,predicate:e9e,represent:$5e})});var gte=_((mQt,hte)=>{\"use strict\";var t9e=Ss();function r9e(t){if(t===null||t.length===0)return!1;var e=t,r=/\\/([gim]*)$/.exec(t),s=\"\";return!(e[0]===\"/\"&&(r&&(s=r[1]),s.length>3||e[e.length-s.length-1]!==\"/\"))}function n9e(t){var e=t,r=/\\/([gim]*)$/.exec(t),s=\"\";return e[0]===\"/\"&&(r&&(s=r[1]),e=e.slice(1,e.length-s.length-1)),new RegExp(e,s)}function i9e(t){var e=\"/\"+t.source+\"/\";return t.global&&(e+=\"g\"),t.multiline&&(e+=\"m\"),t.ignoreCase&&(e+=\"i\"),e}function s9e(t){return Object.prototype.toString.call(t)===\"[object RegExp]\"}hte.exports=new t9e(\"tag:yaml.org,2002:js/regexp\",{kind:\"scalar\",resolve:r9e,construct:n9e,predicate:s9e,represent:i9e})});var yte=_((yQt,mte)=>{\"use strict\";var mx;try{dte=Ie,mx=dte(\"esprima\")}catch{typeof window<\"u\"&&(mx=window.esprima)}var dte,o9e=Ss();function a9e(t){if(t===null)return!1;try{var e=\"(\"+t+\")\",r=mx.parse(e,{range:!0});return!(r.type!==\"Program\"||r.body.length!==1||r.body[0].type!==\"ExpressionStatement\"||r.body[0].expression.type!==\"ArrowFunctionExpression\"&&r.body[0].expression.type!==\"FunctionExpression\")}catch{return!1}}function l9e(t){var e=\"(\"+t+\")\",r=mx.parse(e,{range:!0}),s=[],a;if(r.type!==\"Program\"||r.body.length!==1||r.body[0].type!==\"ExpressionStatement\"||r.body[0].expression.type!==\"ArrowFunctionExpression\"&&r.body[0].expression.type!==\"FunctionExpression\")throw new Error(\"Failed to resolve function\");return r.body[0].expression.params.forEach(function(n){s.push(n.name)}),a=r.body[0].expression.body.range,r.body[0].expression.body.type===\"BlockStatement\"?new Function(s,e.slice(a[0]+1,a[1]-1)):new Function(s,\"return \"+e.slice(a[0],a[1]))}function c9e(t){return t.toString()}function u9e(t){return Object.prototype.toString.call(t)===\"[object Function]\"}mte.exports=new o9e(\"tag:yaml.org,2002:js/function\",{kind:\"scalar\",resolve:a9e,construct:l9e,predicate:u9e,represent:c9e})});var G2=_((IQt,Ite)=>{\"use strict\";var Ete=bd();Ite.exports=Ete.DEFAULT=new Ete({include:[gE()],explicit:[pte(),gte(),yte()]})});var Ute=_((CQt,q2)=>{\"use strict\";var Ip=Pd(),Pte=pE(),f9e=Pee(),bte=gE(),A9e=G2(),i0=Object.prototype.hasOwnProperty,yx=1,xte=2,kte=3,Ex=4,zU=1,p9e=2,Cte=3,h9e=/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F-\\x84\\x86-\\x9F\\uFFFE\\uFFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]/,g9e=/[\\x85\\u2028\\u2029]/,d9e=/[,\\[\\]\\{\\}]/,Qte=/^(?:!|!!|![a-z\\-]+!)$/i,Rte=/^(?:!|[^,\\[\\]\\{\\}])(?:%[0-9a-f]{2}|[0-9a-z\\-#;\\/\\?:@&=\\+\\$,_\\.!~\\*'\\(\\)\\[\\]])*$/i;function wte(t){return Object.prototype.toString.call(t)}function jf(t){return t===10||t===13}function Qd(t){return t===9||t===32}function rl(t){return t===9||t===32||t===10||t===13}function dE(t){return t===44||t===91||t===93||t===123||t===125}function m9e(t){var e;return 48<=t&&t<=57?t-48:(e=t|32,97<=e&&e<=102?e-97+10:-1)}function y9e(t){return t===120?2:t===117?4:t===85?8:0}function E9e(t){return 48<=t&&t<=57?t-48:-1}function Bte(t){return t===48?\"\\0\":t===97?\"\\x07\":t===98?\"\\b\":t===116||t===9?\"\t\":t===110?`\n`:t===118?\"\\v\":t===102?\"\\f\":t===114?\"\\r\":t===101?\"\\x1B\":t===32?\" \":t===34?'\"':t===47?\"/\":t===92?\"\\\\\":t===78?\"\\x85\":t===95?\"\\xA0\":t===76?\"\\u2028\":t===80?\"\\u2029\":\"\"}function I9e(t){return t<=65535?String.fromCharCode(t):String.fromCharCode((t-65536>>10)+55296,(t-65536&1023)+56320)}var Tte=new Array(256),Fte=new Array(256);for(kd=0;kd<256;kd++)Tte[kd]=Bte(kd)?1:0,Fte[kd]=Bte(kd);var kd;function C9e(t,e){this.input=t,this.filename=e.filename||null,this.schema=e.schema||A9e,this.onWarning=e.onWarning||null,this.legacy=e.legacy||!1,this.json=e.json||!1,this.listener=e.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=t.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.documents=[]}function Nte(t,e){return new Pte(e,new f9e(t.filename,t.input,t.position,t.line,t.position-t.lineStart))}function Tr(t,e){throw Nte(t,e)}function Ix(t,e){t.onWarning&&t.onWarning.call(null,Nte(t,e))}var vte={YAML:function(e,r,s){var a,n,c;e.version!==null&&Tr(e,\"duplication of %YAML directive\"),s.length!==1&&Tr(e,\"YAML directive accepts exactly one argument\"),a=/^([0-9]+)\\.([0-9]+)$/.exec(s[0]),a===null&&Tr(e,\"ill-formed argument of the YAML directive\"),n=parseInt(a[1],10),c=parseInt(a[2],10),n!==1&&Tr(e,\"unacceptable YAML version of the document\"),e.version=s[0],e.checkLineBreaks=c<2,c!==1&&c!==2&&Ix(e,\"unsupported YAML version of the document\")},TAG:function(e,r,s){var a,n;s.length!==2&&Tr(e,\"TAG directive accepts exactly two arguments\"),a=s[0],n=s[1],Qte.test(a)||Tr(e,\"ill-formed tag handle (first argument) of the TAG directive\"),i0.call(e.tagMap,a)&&Tr(e,'there is a previously declared suffix for \"'+a+'\" tag handle'),Rte.test(n)||Tr(e,\"ill-formed tag prefix (second argument) of the TAG directive\"),e.tagMap[a]=n}};function n0(t,e,r,s){var a,n,c,f;if(e<r){if(f=t.input.slice(e,r),s)for(a=0,n=f.length;a<n;a+=1)c=f.charCodeAt(a),c===9||32<=c&&c<=1114111||Tr(t,\"expected valid JSON character\");else h9e.test(f)&&Tr(t,\"the stream contains non-printable characters\");t.result+=f}}function Ste(t,e,r,s){var a,n,c,f;for(Ip.isObject(r)||Tr(t,\"cannot merge mappings; the provided source object is unacceptable\"),a=Object.keys(r),c=0,f=a.length;c<f;c+=1)n=a[c],i0.call(e,n)||(e[n]=r[n],s[n]=!0)}function mE(t,e,r,s,a,n,c,f){var p,h;if(Array.isArray(a))for(a=Array.prototype.slice.call(a),p=0,h=a.length;p<h;p+=1)Array.isArray(a[p])&&Tr(t,\"nested arrays are not supported inside keys\"),typeof a==\"object\"&&wte(a[p])===\"[object Object]\"&&(a[p]=\"[object Object]\");if(typeof a==\"object\"&&wte(a)===\"[object Object]\"&&(a=\"[object Object]\"),a=String(a),e===null&&(e={}),s===\"tag:yaml.org,2002:merge\")if(Array.isArray(n))for(p=0,h=n.length;p<h;p+=1)Ste(t,e,n[p],r);else Ste(t,e,n,r);else!t.json&&!i0.call(r,a)&&i0.call(e,a)&&(t.line=c||t.line,t.position=f||t.position,Tr(t,\"duplicated mapping key\")),e[a]=n,delete r[a];return e}function ZU(t){var e;e=t.input.charCodeAt(t.position),e===10?t.position++:e===13?(t.position++,t.input.charCodeAt(t.position)===10&&t.position++):Tr(t,\"a line break is expected\"),t.line+=1,t.lineStart=t.position}function os(t,e,r){for(var s=0,a=t.input.charCodeAt(t.position);a!==0;){for(;Qd(a);)a=t.input.charCodeAt(++t.position);if(e&&a===35)do a=t.input.charCodeAt(++t.position);while(a!==10&&a!==13&&a!==0);if(jf(a))for(ZU(t),a=t.input.charCodeAt(t.position),s++,t.lineIndent=0;a===32;)t.lineIndent++,a=t.input.charCodeAt(++t.position);else break}return r!==-1&&s!==0&&t.lineIndent<r&&Ix(t,\"deficient indentation\"),s}function Cx(t){var e=t.position,r;return r=t.input.charCodeAt(e),!!((r===45||r===46)&&r===t.input.charCodeAt(e+1)&&r===t.input.charCodeAt(e+2)&&(e+=3,r=t.input.charCodeAt(e),r===0||rl(r)))}function XU(t,e){e===1?t.result+=\" \":e>1&&(t.result+=Ip.repeat(`\n`,e-1))}function w9e(t,e,r){var s,a,n,c,f,p,h,E,C=t.kind,S=t.result,b;if(b=t.input.charCodeAt(t.position),rl(b)||dE(b)||b===35||b===38||b===42||b===33||b===124||b===62||b===39||b===34||b===37||b===64||b===96||(b===63||b===45)&&(a=t.input.charCodeAt(t.position+1),rl(a)||r&&dE(a)))return!1;for(t.kind=\"scalar\",t.result=\"\",n=c=t.position,f=!1;b!==0;){if(b===58){if(a=t.input.charCodeAt(t.position+1),rl(a)||r&&dE(a))break}else if(b===35){if(s=t.input.charCodeAt(t.position-1),rl(s))break}else{if(t.position===t.lineStart&&Cx(t)||r&&dE(b))break;if(jf(b))if(p=t.line,h=t.lineStart,E=t.lineIndent,os(t,!1,-1),t.lineIndent>=e){f=!0,b=t.input.charCodeAt(t.position);continue}else{t.position=c,t.line=p,t.lineStart=h,t.lineIndent=E;break}}f&&(n0(t,n,c,!1),XU(t,t.line-p),n=c=t.position,f=!1),Qd(b)||(c=t.position+1),b=t.input.charCodeAt(++t.position)}return n0(t,n,c,!1),t.result?!0:(t.kind=C,t.result=S,!1)}function B9e(t,e){var r,s,a;if(r=t.input.charCodeAt(t.position),r!==39)return!1;for(t.kind=\"scalar\",t.result=\"\",t.position++,s=a=t.position;(r=t.input.charCodeAt(t.position))!==0;)if(r===39)if(n0(t,s,t.position,!0),r=t.input.charCodeAt(++t.position),r===39)s=t.position,t.position++,a=t.position;else return!0;else jf(r)?(n0(t,s,a,!0),XU(t,os(t,!1,e)),s=a=t.position):t.position===t.lineStart&&Cx(t)?Tr(t,\"unexpected end of the document within a single quoted scalar\"):(t.position++,a=t.position);Tr(t,\"unexpected end of the stream within a single quoted scalar\")}function v9e(t,e){var r,s,a,n,c,f;if(f=t.input.charCodeAt(t.position),f!==34)return!1;for(t.kind=\"scalar\",t.result=\"\",t.position++,r=s=t.position;(f=t.input.charCodeAt(t.position))!==0;){if(f===34)return n0(t,r,t.position,!0),t.position++,!0;if(f===92){if(n0(t,r,t.position,!0),f=t.input.charCodeAt(++t.position),jf(f))os(t,!1,e);else if(f<256&&Tte[f])t.result+=Fte[f],t.position++;else if((c=y9e(f))>0){for(a=c,n=0;a>0;a--)f=t.input.charCodeAt(++t.position),(c=m9e(f))>=0?n=(n<<4)+c:Tr(t,\"expected hexadecimal character\");t.result+=I9e(n),t.position++}else Tr(t,\"unknown escape sequence\");r=s=t.position}else jf(f)?(n0(t,r,s,!0),XU(t,os(t,!1,e)),r=s=t.position):t.position===t.lineStart&&Cx(t)?Tr(t,\"unexpected end of the document within a double quoted scalar\"):(t.position++,s=t.position)}Tr(t,\"unexpected end of the stream within a double quoted scalar\")}function S9e(t,e){var r=!0,s,a=t.tag,n,c=t.anchor,f,p,h,E,C,S={},b,I,T,N;if(N=t.input.charCodeAt(t.position),N===91)p=93,C=!1,n=[];else if(N===123)p=125,C=!0,n={};else return!1;for(t.anchor!==null&&(t.anchorMap[t.anchor]=n),N=t.input.charCodeAt(++t.position);N!==0;){if(os(t,!0,e),N=t.input.charCodeAt(t.position),N===p)return t.position++,t.tag=a,t.anchor=c,t.kind=C?\"mapping\":\"sequence\",t.result=n,!0;r||Tr(t,\"missed comma between flow collection entries\"),I=b=T=null,h=E=!1,N===63&&(f=t.input.charCodeAt(t.position+1),rl(f)&&(h=E=!0,t.position++,os(t,!0,e))),s=t.line,yE(t,e,yx,!1,!0),I=t.tag,b=t.result,os(t,!0,e),N=t.input.charCodeAt(t.position),(E||t.line===s)&&N===58&&(h=!0,N=t.input.charCodeAt(++t.position),os(t,!0,e),yE(t,e,yx,!1,!0),T=t.result),C?mE(t,n,S,I,b,T):h?n.push(mE(t,null,S,I,b,T)):n.push(b),os(t,!0,e),N=t.input.charCodeAt(t.position),N===44?(r=!0,N=t.input.charCodeAt(++t.position)):r=!1}Tr(t,\"unexpected end of the stream within a flow collection\")}function D9e(t,e){var r,s,a=zU,n=!1,c=!1,f=e,p=0,h=!1,E,C;if(C=t.input.charCodeAt(t.position),C===124)s=!1;else if(C===62)s=!0;else return!1;for(t.kind=\"scalar\",t.result=\"\";C!==0;)if(C=t.input.charCodeAt(++t.position),C===43||C===45)zU===a?a=C===43?Cte:p9e:Tr(t,\"repeat of a chomping mode identifier\");else if((E=E9e(C))>=0)E===0?Tr(t,\"bad explicit indentation width of a block scalar; it cannot be less than one\"):c?Tr(t,\"repeat of an indentation width identifier\"):(f=e+E-1,c=!0);else break;if(Qd(C)){do C=t.input.charCodeAt(++t.position);while(Qd(C));if(C===35)do C=t.input.charCodeAt(++t.position);while(!jf(C)&&C!==0)}for(;C!==0;){for(ZU(t),t.lineIndent=0,C=t.input.charCodeAt(t.position);(!c||t.lineIndent<f)&&C===32;)t.lineIndent++,C=t.input.charCodeAt(++t.position);if(!c&&t.lineIndent>f&&(f=t.lineIndent),jf(C)){p++;continue}if(t.lineIndent<f){a===Cte?t.result+=Ip.repeat(`\n`,n?1+p:p):a===zU&&n&&(t.result+=`\n`);break}for(s?Qd(C)?(h=!0,t.result+=Ip.repeat(`\n`,n?1+p:p)):h?(h=!1,t.result+=Ip.repeat(`\n`,p+1)):p===0?n&&(t.result+=\" \"):t.result+=Ip.repeat(`\n`,p):t.result+=Ip.repeat(`\n`,n?1+p:p),n=!0,c=!0,p=0,r=t.position;!jf(C)&&C!==0;)C=t.input.charCodeAt(++t.position);n0(t,r,t.position,!1)}return!0}function Dte(t,e){var r,s=t.tag,a=t.anchor,n=[],c,f=!1,p;for(t.anchor!==null&&(t.anchorMap[t.anchor]=n),p=t.input.charCodeAt(t.position);p!==0&&!(p!==45||(c=t.input.charCodeAt(t.position+1),!rl(c)));){if(f=!0,t.position++,os(t,!0,-1)&&t.lineIndent<=e){n.push(null),p=t.input.charCodeAt(t.position);continue}if(r=t.line,yE(t,e,kte,!1,!0),n.push(t.result),os(t,!0,-1),p=t.input.charCodeAt(t.position),(t.line===r||t.lineIndent>e)&&p!==0)Tr(t,\"bad indentation of a sequence entry\");else if(t.lineIndent<e)break}return f?(t.tag=s,t.anchor=a,t.kind=\"sequence\",t.result=n,!0):!1}function P9e(t,e,r){var s,a,n,c,f=t.tag,p=t.anchor,h={},E={},C=null,S=null,b=null,I=!1,T=!1,N;for(t.anchor!==null&&(t.anchorMap[t.anchor]=h),N=t.input.charCodeAt(t.position);N!==0;){if(s=t.input.charCodeAt(t.position+1),n=t.line,c=t.position,(N===63||N===58)&&rl(s))N===63?(I&&(mE(t,h,E,C,S,null),C=S=b=null),T=!0,I=!0,a=!0):I?(I=!1,a=!0):Tr(t,\"incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line\"),t.position+=1,N=s;else if(yE(t,r,xte,!1,!0))if(t.line===n){for(N=t.input.charCodeAt(t.position);Qd(N);)N=t.input.charCodeAt(++t.position);if(N===58)N=t.input.charCodeAt(++t.position),rl(N)||Tr(t,\"a whitespace character is expected after the key-value separator within a block mapping\"),I&&(mE(t,h,E,C,S,null),C=S=b=null),T=!0,I=!1,a=!1,C=t.tag,S=t.result;else if(T)Tr(t,\"can not read an implicit mapping pair; a colon is missed\");else return t.tag=f,t.anchor=p,!0}else if(T)Tr(t,\"can not read a block mapping entry; a multiline key may not be an implicit key\");else return t.tag=f,t.anchor=p,!0;else break;if((t.line===n||t.lineIndent>e)&&(yE(t,e,Ex,!0,a)&&(I?S=t.result:b=t.result),I||(mE(t,h,E,C,S,b,n,c),C=S=b=null),os(t,!0,-1),N=t.input.charCodeAt(t.position)),t.lineIndent>e&&N!==0)Tr(t,\"bad indentation of a mapping entry\");else if(t.lineIndent<e)break}return I&&mE(t,h,E,C,S,null),T&&(t.tag=f,t.anchor=p,t.kind=\"mapping\",t.result=h),T}function b9e(t){var e,r=!1,s=!1,a,n,c;if(c=t.input.charCodeAt(t.position),c!==33)return!1;if(t.tag!==null&&Tr(t,\"duplication of a tag property\"),c=t.input.charCodeAt(++t.position),c===60?(r=!0,c=t.input.charCodeAt(++t.position)):c===33?(s=!0,a=\"!!\",c=t.input.charCodeAt(++t.position)):a=\"!\",e=t.position,r){do c=t.input.charCodeAt(++t.position);while(c!==0&&c!==62);t.position<t.length?(n=t.input.slice(e,t.position),c=t.input.charCodeAt(++t.position)):Tr(t,\"unexpected end of the stream within a verbatim tag\")}else{for(;c!==0&&!rl(c);)c===33&&(s?Tr(t,\"tag suffix cannot contain exclamation marks\"):(a=t.input.slice(e-1,t.position+1),Qte.test(a)||Tr(t,\"named tag handle cannot contain such characters\"),s=!0,e=t.position+1)),c=t.input.charCodeAt(++t.position);n=t.input.slice(e,t.position),d9e.test(n)&&Tr(t,\"tag suffix cannot contain flow indicator characters\")}return n&&!Rte.test(n)&&Tr(t,\"tag name cannot contain such characters: \"+n),r?t.tag=n:i0.call(t.tagMap,a)?t.tag=t.tagMap[a]+n:a===\"!\"?t.tag=\"!\"+n:a===\"!!\"?t.tag=\"tag:yaml.org,2002:\"+n:Tr(t,'undeclared tag handle \"'+a+'\"'),!0}function x9e(t){var e,r;if(r=t.input.charCodeAt(t.position),r!==38)return!1;for(t.anchor!==null&&Tr(t,\"duplication of an anchor property\"),r=t.input.charCodeAt(++t.position),e=t.position;r!==0&&!rl(r)&&!dE(r);)r=t.input.charCodeAt(++t.position);return t.position===e&&Tr(t,\"name of an anchor node must contain at least one character\"),t.anchor=t.input.slice(e,t.position),!0}function k9e(t){var e,r,s;if(s=t.input.charCodeAt(t.position),s!==42)return!1;for(s=t.input.charCodeAt(++t.position),e=t.position;s!==0&&!rl(s)&&!dE(s);)s=t.input.charCodeAt(++t.position);return t.position===e&&Tr(t,\"name of an alias node must contain at least one character\"),r=t.input.slice(e,t.position),i0.call(t.anchorMap,r)||Tr(t,'unidentified alias \"'+r+'\"'),t.result=t.anchorMap[r],os(t,!0,-1),!0}function yE(t,e,r,s,a){var n,c,f,p=1,h=!1,E=!1,C,S,b,I,T;if(t.listener!==null&&t.listener(\"open\",t),t.tag=null,t.anchor=null,t.kind=null,t.result=null,n=c=f=Ex===r||kte===r,s&&os(t,!0,-1)&&(h=!0,t.lineIndent>e?p=1:t.lineIndent===e?p=0:t.lineIndent<e&&(p=-1)),p===1)for(;b9e(t)||x9e(t);)os(t,!0,-1)?(h=!0,f=n,t.lineIndent>e?p=1:t.lineIndent===e?p=0:t.lineIndent<e&&(p=-1)):f=!1;if(f&&(f=h||a),(p===1||Ex===r)&&(yx===r||xte===r?I=e:I=e+1,T=t.position-t.lineStart,p===1?f&&(Dte(t,T)||P9e(t,T,I))||S9e(t,I)?E=!0:(c&&D9e(t,I)||B9e(t,I)||v9e(t,I)?E=!0:k9e(t)?(E=!0,(t.tag!==null||t.anchor!==null)&&Tr(t,\"alias node should not have any properties\")):w9e(t,I,yx===r)&&(E=!0,t.tag===null&&(t.tag=\"?\")),t.anchor!==null&&(t.anchorMap[t.anchor]=t.result)):p===0&&(E=f&&Dte(t,T))),t.tag!==null&&t.tag!==\"!\")if(t.tag===\"?\"){for(t.result!==null&&t.kind!==\"scalar\"&&Tr(t,'unacceptable node kind for !<?> tag; it should be \"scalar\", not \"'+t.kind+'\"'),C=0,S=t.implicitTypes.length;C<S;C+=1)if(b=t.implicitTypes[C],b.resolve(t.result)){t.result=b.construct(t.result),t.tag=b.tag,t.anchor!==null&&(t.anchorMap[t.anchor]=t.result);break}}else i0.call(t.typeMap[t.kind||\"fallback\"],t.tag)?(b=t.typeMap[t.kind||\"fallback\"][t.tag],t.result!==null&&b.kind!==t.kind&&Tr(t,\"unacceptable node kind for !<\"+t.tag+'> tag; it should be \"'+b.kind+'\", not \"'+t.kind+'\"'),b.resolve(t.result)?(t.result=b.construct(t.result),t.anchor!==null&&(t.anchorMap[t.anchor]=t.result)):Tr(t,\"cannot resolve a node with !<\"+t.tag+\"> explicit tag\")):Tr(t,\"unknown tag !<\"+t.tag+\">\");return t.listener!==null&&t.listener(\"close\",t),t.tag!==null||t.anchor!==null||E}function Q9e(t){var e=t.position,r,s,a,n=!1,c;for(t.version=null,t.checkLineBreaks=t.legacy,t.tagMap={},t.anchorMap={};(c=t.input.charCodeAt(t.position))!==0&&(os(t,!0,-1),c=t.input.charCodeAt(t.position),!(t.lineIndent>0||c!==37));){for(n=!0,c=t.input.charCodeAt(++t.position),r=t.position;c!==0&&!rl(c);)c=t.input.charCodeAt(++t.position);for(s=t.input.slice(r,t.position),a=[],s.length<1&&Tr(t,\"directive name must not be less than one character in length\");c!==0;){for(;Qd(c);)c=t.input.charCodeAt(++t.position);if(c===35){do c=t.input.charCodeAt(++t.position);while(c!==0&&!jf(c));break}if(jf(c))break;for(r=t.position;c!==0&&!rl(c);)c=t.input.charCodeAt(++t.position);a.push(t.input.slice(r,t.position))}c!==0&&ZU(t),i0.call(vte,s)?vte[s](t,s,a):Ix(t,'unknown document directive \"'+s+'\"')}if(os(t,!0,-1),t.lineIndent===0&&t.input.charCodeAt(t.position)===45&&t.input.charCodeAt(t.position+1)===45&&t.input.charCodeAt(t.position+2)===45?(t.position+=3,os(t,!0,-1)):n&&Tr(t,\"directives end mark is expected\"),yE(t,t.lineIndent-1,Ex,!1,!0),os(t,!0,-1),t.checkLineBreaks&&g9e.test(t.input.slice(e,t.position))&&Ix(t,\"non-ASCII line breaks are interpreted as content\"),t.documents.push(t.result),t.position===t.lineStart&&Cx(t)){t.input.charCodeAt(t.position)===46&&(t.position+=3,os(t,!0,-1));return}if(t.position<t.length-1)Tr(t,\"end of the stream or a document separator is expected\");else return}function Ote(t,e){t=String(t),e=e||{},t.length!==0&&(t.charCodeAt(t.length-1)!==10&&t.charCodeAt(t.length-1)!==13&&(t+=`\n`),t.charCodeAt(0)===65279&&(t=t.slice(1)));var r=new C9e(t,e),s=t.indexOf(\"\\0\");for(s!==-1&&(r.position=s,Tr(r,\"null byte is not allowed in input\")),r.input+=\"\\0\";r.input.charCodeAt(r.position)===32;)r.lineIndent+=1,r.position+=1;for(;r.position<r.length-1;)Q9e(r);return r.documents}function Lte(t,e,r){e!==null&&typeof e==\"object\"&&typeof r>\"u\"&&(r=e,e=null);var s=Ote(t,r);if(typeof e!=\"function\")return s;for(var a=0,n=s.length;a<n;a+=1)e(s[a])}function Mte(t,e){var r=Ote(t,e);if(r.length!==0){if(r.length===1)return r[0];throw new Pte(\"expected a single document in the stream, but found more\")}}function R9e(t,e,r){return typeof e==\"object\"&&e!==null&&typeof r>\"u\"&&(r=e,e=null),Lte(t,e,Ip.extend({schema:bte},r))}function T9e(t,e){return Mte(t,Ip.extend({schema:bte},e))}q2.exports.loadAll=Lte;q2.exports.load=Mte;q2.exports.safeLoadAll=R9e;q2.exports.safeLoad=T9e});var lre=_((wQt,r_)=>{\"use strict\";var Y2=Pd(),V2=pE(),F9e=G2(),N9e=gE(),Vte=Object.prototype.toString,Jte=Object.prototype.hasOwnProperty,O9e=9,W2=10,L9e=13,M9e=32,U9e=33,_9e=34,Kte=35,H9e=37,j9e=38,G9e=39,q9e=42,zte=44,W9e=45,Zte=58,Y9e=61,V9e=62,J9e=63,K9e=64,Xte=91,$te=93,z9e=96,ere=123,Z9e=124,tre=125,_o={};_o[0]=\"\\\\0\";_o[7]=\"\\\\a\";_o[8]=\"\\\\b\";_o[9]=\"\\\\t\";_o[10]=\"\\\\n\";_o[11]=\"\\\\v\";_o[12]=\"\\\\f\";_o[13]=\"\\\\r\";_o[27]=\"\\\\e\";_o[34]='\\\\\"';_o[92]=\"\\\\\\\\\";_o[133]=\"\\\\N\";_o[160]=\"\\\\_\";_o[8232]=\"\\\\L\";_o[8233]=\"\\\\P\";var X9e=[\"y\",\"Y\",\"yes\",\"Yes\",\"YES\",\"on\",\"On\",\"ON\",\"n\",\"N\",\"no\",\"No\",\"NO\",\"off\",\"Off\",\"OFF\"];function $9e(t,e){var r,s,a,n,c,f,p;if(e===null)return{};for(r={},s=Object.keys(e),a=0,n=s.length;a<n;a+=1)c=s[a],f=String(e[c]),c.slice(0,2)===\"!!\"&&(c=\"tag:yaml.org,2002:\"+c.slice(2)),p=t.compiledTypeMap.fallback[c],p&&Jte.call(p.styleAliases,f)&&(f=p.styleAliases[f]),r[c]=f;return r}function _te(t){var e,r,s;if(e=t.toString(16).toUpperCase(),t<=255)r=\"x\",s=2;else if(t<=65535)r=\"u\",s=4;else if(t<=4294967295)r=\"U\",s=8;else throw new V2(\"code point within a string may not be greater than 0xFFFFFFFF\");return\"\\\\\"+r+Y2.repeat(\"0\",s-e.length)+e}function eWe(t){this.schema=t.schema||F9e,this.indent=Math.max(1,t.indent||2),this.noArrayIndent=t.noArrayIndent||!1,this.skipInvalid=t.skipInvalid||!1,this.flowLevel=Y2.isNothing(t.flowLevel)?-1:t.flowLevel,this.styleMap=$9e(this.schema,t.styles||null),this.sortKeys=t.sortKeys||!1,this.lineWidth=t.lineWidth||80,this.noRefs=t.noRefs||!1,this.noCompatMode=t.noCompatMode||!1,this.condenseFlow=t.condenseFlow||!1,this.implicitTypes=this.schema.compiledImplicit,this.explicitTypes=this.schema.compiledExplicit,this.tag=null,this.result=\"\",this.duplicates=[],this.usedDuplicates=null}function Hte(t,e){for(var r=Y2.repeat(\" \",e),s=0,a=-1,n=\"\",c,f=t.length;s<f;)a=t.indexOf(`\n`,s),a===-1?(c=t.slice(s),s=f):(c=t.slice(s,a+1),s=a+1),c.length&&c!==`\n`&&(n+=r),n+=c;return n}function $U(t,e){return`\n`+Y2.repeat(\" \",t.indent*e)}function tWe(t,e){var r,s,a;for(r=0,s=t.implicitTypes.length;r<s;r+=1)if(a=t.implicitTypes[r],a.resolve(e))return!0;return!1}function t_(t){return t===M9e||t===O9e}function EE(t){return 32<=t&&t<=126||161<=t&&t<=55295&&t!==8232&&t!==8233||57344<=t&&t<=65533&&t!==65279||65536<=t&&t<=1114111}function rWe(t){return EE(t)&&!t_(t)&&t!==65279&&t!==L9e&&t!==W2}function jte(t,e){return EE(t)&&t!==65279&&t!==zte&&t!==Xte&&t!==$te&&t!==ere&&t!==tre&&t!==Zte&&(t!==Kte||e&&rWe(e))}function nWe(t){return EE(t)&&t!==65279&&!t_(t)&&t!==W9e&&t!==J9e&&t!==Zte&&t!==zte&&t!==Xte&&t!==$te&&t!==ere&&t!==tre&&t!==Kte&&t!==j9e&&t!==q9e&&t!==U9e&&t!==Z9e&&t!==Y9e&&t!==V9e&&t!==G9e&&t!==_9e&&t!==H9e&&t!==K9e&&t!==z9e}function rre(t){var e=/^\\n* /;return e.test(t)}var nre=1,ire=2,sre=3,ore=4,wx=5;function iWe(t,e,r,s,a){var n,c,f,p=!1,h=!1,E=s!==-1,C=-1,S=nWe(t.charCodeAt(0))&&!t_(t.charCodeAt(t.length-1));if(e)for(n=0;n<t.length;n++){if(c=t.charCodeAt(n),!EE(c))return wx;f=n>0?t.charCodeAt(n-1):null,S=S&&jte(c,f)}else{for(n=0;n<t.length;n++){if(c=t.charCodeAt(n),c===W2)p=!0,E&&(h=h||n-C-1>s&&t[C+1]!==\" \",C=n);else if(!EE(c))return wx;f=n>0?t.charCodeAt(n-1):null,S=S&&jte(c,f)}h=h||E&&n-C-1>s&&t[C+1]!==\" \"}return!p&&!h?S&&!a(t)?nre:ire:r>9&&rre(t)?wx:h?ore:sre}function sWe(t,e,r,s){t.dump=function(){if(e.length===0)return\"''\";if(!t.noCompatMode&&X9e.indexOf(e)!==-1)return\"'\"+e+\"'\";var a=t.indent*Math.max(1,r),n=t.lineWidth===-1?-1:Math.max(Math.min(t.lineWidth,40),t.lineWidth-a),c=s||t.flowLevel>-1&&r>=t.flowLevel;function f(p){return tWe(t,p)}switch(iWe(e,c,t.indent,n,f)){case nre:return e;case ire:return\"'\"+e.replace(/'/g,\"''\")+\"'\";case sre:return\"|\"+Gte(e,t.indent)+qte(Hte(e,a));case ore:return\">\"+Gte(e,t.indent)+qte(Hte(oWe(e,n),a));case wx:return'\"'+aWe(e,n)+'\"';default:throw new V2(\"impossible error: invalid scalar style\")}}()}function Gte(t,e){var r=rre(t)?String(e):\"\",s=t[t.length-1]===`\n`,a=s&&(t[t.length-2]===`\n`||t===`\n`),n=a?\"+\":s?\"\":\"-\";return r+n+`\n`}function qte(t){return t[t.length-1]===`\n`?t.slice(0,-1):t}function oWe(t,e){for(var r=/(\\n+)([^\\n]*)/g,s=function(){var h=t.indexOf(`\n`);return h=h!==-1?h:t.length,r.lastIndex=h,Wte(t.slice(0,h),e)}(),a=t[0]===`\n`||t[0]===\" \",n,c;c=r.exec(t);){var f=c[1],p=c[2];n=p[0]===\" \",s+=f+(!a&&!n&&p!==\"\"?`\n`:\"\")+Wte(p,e),a=n}return s}function Wte(t,e){if(t===\"\"||t[0]===\" \")return t;for(var r=/ [^ ]/g,s,a=0,n,c=0,f=0,p=\"\";s=r.exec(t);)f=s.index,f-a>e&&(n=c>a?c:f,p+=`\n`+t.slice(a,n),a=n+1),c=f;return p+=`\n`,t.length-a>e&&c>a?p+=t.slice(a,c)+`\n`+t.slice(c+1):p+=t.slice(a),p.slice(1)}function aWe(t){for(var e=\"\",r,s,a,n=0;n<t.length;n++){if(r=t.charCodeAt(n),r>=55296&&r<=56319&&(s=t.charCodeAt(n+1),s>=56320&&s<=57343)){e+=_te((r-55296)*1024+s-56320+65536),n++;continue}a=_o[r],e+=!a&&EE(r)?t[n]:a||_te(r)}return e}function lWe(t,e,r){var s=\"\",a=t.tag,n,c;for(n=0,c=r.length;n<c;n+=1)Rd(t,e,r[n],!1,!1)&&(n!==0&&(s+=\",\"+(t.condenseFlow?\"\":\" \")),s+=t.dump);t.tag=a,t.dump=\"[\"+s+\"]\"}function cWe(t,e,r,s){var a=\"\",n=t.tag,c,f;for(c=0,f=r.length;c<f;c+=1)Rd(t,e+1,r[c],!0,!0)&&((!s||c!==0)&&(a+=$U(t,e)),t.dump&&W2===t.dump.charCodeAt(0)?a+=\"-\":a+=\"- \",a+=t.dump);t.tag=n,t.dump=a||\"[]\"}function uWe(t,e,r){var s=\"\",a=t.tag,n=Object.keys(r),c,f,p,h,E;for(c=0,f=n.length;c<f;c+=1)E=\"\",c!==0&&(E+=\", \"),t.condenseFlow&&(E+='\"'),p=n[c],h=r[p],Rd(t,e,p,!1,!1)&&(t.dump.length>1024&&(E+=\"? \"),E+=t.dump+(t.condenseFlow?'\"':\"\")+\":\"+(t.condenseFlow?\"\":\" \"),Rd(t,e,h,!1,!1)&&(E+=t.dump,s+=E));t.tag=a,t.dump=\"{\"+s+\"}\"}function fWe(t,e,r,s){var a=\"\",n=t.tag,c=Object.keys(r),f,p,h,E,C,S;if(t.sortKeys===!0)c.sort();else if(typeof t.sortKeys==\"function\")c.sort(t.sortKeys);else if(t.sortKeys)throw new V2(\"sortKeys must be a boolean or a function\");for(f=0,p=c.length;f<p;f+=1)S=\"\",(!s||f!==0)&&(S+=$U(t,e)),h=c[f],E=r[h],Rd(t,e+1,h,!0,!0,!0)&&(C=t.tag!==null&&t.tag!==\"?\"||t.dump&&t.dump.length>1024,C&&(t.dump&&W2===t.dump.charCodeAt(0)?S+=\"?\":S+=\"? \"),S+=t.dump,C&&(S+=$U(t,e)),Rd(t,e+1,E,!0,C)&&(t.dump&&W2===t.dump.charCodeAt(0)?S+=\":\":S+=\": \",S+=t.dump,a+=S));t.tag=n,t.dump=a||\"{}\"}function Yte(t,e,r){var s,a,n,c,f,p;for(a=r?t.explicitTypes:t.implicitTypes,n=0,c=a.length;n<c;n+=1)if(f=a[n],(f.instanceOf||f.predicate)&&(!f.instanceOf||typeof e==\"object\"&&e instanceof f.instanceOf)&&(!f.predicate||f.predicate(e))){if(t.tag=r?f.tag:\"?\",f.represent){if(p=t.styleMap[f.tag]||f.defaultStyle,Vte.call(f.represent)===\"[object Function]\")s=f.represent(e,p);else if(Jte.call(f.represent,p))s=f.represent[p](e,p);else throw new V2(\"!<\"+f.tag+'> tag resolver accepts not \"'+p+'\" style');t.dump=s}return!0}return!1}function Rd(t,e,r,s,a,n){t.tag=null,t.dump=r,Yte(t,r,!1)||Yte(t,r,!0);var c=Vte.call(t.dump);s&&(s=t.flowLevel<0||t.flowLevel>e);var f=c===\"[object Object]\"||c===\"[object Array]\",p,h;if(f&&(p=t.duplicates.indexOf(r),h=p!==-1),(t.tag!==null&&t.tag!==\"?\"||h||t.indent!==2&&e>0)&&(a=!1),h&&t.usedDuplicates[p])t.dump=\"*ref_\"+p;else{if(f&&h&&!t.usedDuplicates[p]&&(t.usedDuplicates[p]=!0),c===\"[object Object]\")s&&Object.keys(t.dump).length!==0?(fWe(t,e,t.dump,a),h&&(t.dump=\"&ref_\"+p+t.dump)):(uWe(t,e,t.dump),h&&(t.dump=\"&ref_\"+p+\" \"+t.dump));else if(c===\"[object Array]\"){var E=t.noArrayIndent&&e>0?e-1:e;s&&t.dump.length!==0?(cWe(t,E,t.dump,a),h&&(t.dump=\"&ref_\"+p+t.dump)):(lWe(t,E,t.dump),h&&(t.dump=\"&ref_\"+p+\" \"+t.dump))}else if(c===\"[object String]\")t.tag!==\"?\"&&sWe(t,t.dump,e,n);else{if(t.skipInvalid)return!1;throw new V2(\"unacceptable kind of an object to dump \"+c)}t.tag!==null&&t.tag!==\"?\"&&(t.dump=\"!<\"+t.tag+\"> \"+t.dump)}return!0}function AWe(t,e){var r=[],s=[],a,n;for(e_(t,r,s),a=0,n=s.length;a<n;a+=1)e.duplicates.push(r[s[a]]);e.usedDuplicates=new Array(n)}function e_(t,e,r){var s,a,n;if(t!==null&&typeof t==\"object\")if(a=e.indexOf(t),a!==-1)r.indexOf(a)===-1&&r.push(a);else if(e.push(t),Array.isArray(t))for(a=0,n=t.length;a<n;a+=1)e_(t[a],e,r);else for(s=Object.keys(t),a=0,n=s.length;a<n;a+=1)e_(t[s[a]],e,r)}function are(t,e){e=e||{};var r=new eWe(e);return r.noRefs||AWe(t,r),Rd(r,0,t,!0,!0)?r.dump+`\n`:\"\"}function pWe(t,e){return are(t,Y2.extend({schema:N9e},e))}r_.exports.dump=are;r_.exports.safeDump=pWe});var ure=_((BQt,qi)=>{\"use strict\";var Bx=Ute(),cre=lre();function vx(t){return function(){throw new Error(\"Function \"+t+\" is deprecated and cannot be used.\")}}qi.exports.Type=Ss();qi.exports.Schema=bd();qi.exports.FAILSAFE_SCHEMA=dx();qi.exports.JSON_SCHEMA=VU();qi.exports.CORE_SCHEMA=JU();qi.exports.DEFAULT_SAFE_SCHEMA=gE();qi.exports.DEFAULT_FULL_SCHEMA=G2();qi.exports.load=Bx.load;qi.exports.loadAll=Bx.loadAll;qi.exports.safeLoad=Bx.safeLoad;qi.exports.safeLoadAll=Bx.safeLoadAll;qi.exports.dump=cre.dump;qi.exports.safeDump=cre.safeDump;qi.exports.YAMLException=pE();qi.exports.MINIMAL_SCHEMA=dx();qi.exports.SAFE_SCHEMA=gE();qi.exports.DEFAULT_SCHEMA=G2();qi.exports.scan=vx(\"scan\");qi.exports.parse=vx(\"parse\");qi.exports.compose=vx(\"compose\");qi.exports.addConstructor=vx(\"addConstructor\")});var Are=_((vQt,fre)=>{\"use strict\";var hWe=ure();fre.exports=hWe});var hre=_((SQt,pre)=>{\"use strict\";function gWe(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function Td(t,e,r,s){this.message=t,this.expected=e,this.found=r,this.location=s,this.name=\"SyntaxError\",typeof Error.captureStackTrace==\"function\"&&Error.captureStackTrace(this,Td)}gWe(Td,Error);Td.buildMessage=function(t,e){var r={literal:function(h){return'\"'+a(h.text)+'\"'},class:function(h){var E=\"\",C;for(C=0;C<h.parts.length;C++)E+=h.parts[C]instanceof Array?n(h.parts[C][0])+\"-\"+n(h.parts[C][1]):n(h.parts[C]);return\"[\"+(h.inverted?\"^\":\"\")+E+\"]\"},any:function(h){return\"any character\"},end:function(h){return\"end of input\"},other:function(h){return h.description}};function s(h){return h.charCodeAt(0).toString(16).toUpperCase()}function a(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\"/g,'\\\\\"').replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(E){return\"\\\\x0\"+s(E)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(E){return\"\\\\x\"+s(E)})}function n(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\\]/g,\"\\\\]\").replace(/\\^/g,\"\\\\^\").replace(/-/g,\"\\\\-\").replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(E){return\"\\\\x0\"+s(E)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(E){return\"\\\\x\"+s(E)})}function c(h){return r[h.type](h)}function f(h){var E=new Array(h.length),C,S;for(C=0;C<h.length;C++)E[C]=c(h[C]);if(E.sort(),E.length>0){for(C=1,S=1;C<E.length;C++)E[C-1]!==E[C]&&(E[S]=E[C],S++);E.length=S}switch(E.length){case 1:return E[0];case 2:return E[0]+\" or \"+E[1];default:return E.slice(0,-1).join(\", \")+\", or \"+E[E.length-1]}}function p(h){return h?'\"'+a(h)+'\"':\"end of input\"}return\"Expected \"+f(t)+\" but \"+p(e)+\" found.\"};function dWe(t,e){e=e!==void 0?e:{};var r={},s={Start:lc},a=lc,n=function(te){return[].concat(...te)},c=\"-\",f=dn(\"-\",!1),p=function(te){return te},h=function(te){return Object.assign({},...te)},E=\"#\",C=dn(\"#\",!1),S=Au(),b=function(){return{}},I=\":\",T=dn(\":\",!1),N=function(te,Ee){return{[te]:Ee}},U=\",\",W=dn(\",\",!1),ee=function(te,Ee){return Ee},ie=function(te,Ee,Oe){return Object.assign({},...[te].concat(Ee).map(dt=>({[dt]:Oe})))},ue=function(te){return te},le=function(te){return te},me=Oa(\"correct indentation\"),pe=\" \",Be=dn(\" \",!1),Ce=function(te){return te.length===lr*St},g=function(te){return te.length===(lr+1)*St},we=function(){return lr++,!0},ye=function(){return lr--,!0},Ae=function(){return la()},se=Oa(\"pseudostring\"),X=/^[^\\r\\n\\t ?:,\\][{}#&*!|>'\"%@`\\-]/,De=Kn([\"\\r\",`\n`,\"\t\",\" \",\"?\",\":\",\",\",\"]\",\"[\",\"{\",\"}\",\"#\",\"&\",\"*\",\"!\",\"|\",\">\",\"'\",'\"',\"%\",\"@\",\"`\",\"-\"],!0,!1),Te=/^[^\\r\\n\\t ,\\][{}:#\"']/,mt=Kn([\"\\r\",`\n`,\"\t\",\" \",\",\",\"]\",\"[\",\"{\",\"}\",\":\",\"#\",'\"',\"'\"],!0,!1),j=function(){return la().replace(/^ *| *$/g,\"\")},rt=\"--\",Fe=dn(\"--\",!1),Ne=/^[a-zA-Z\\/0-9]/,be=Kn([[\"a\",\"z\"],[\"A\",\"Z\"],\"/\",[\"0\",\"9\"]],!1,!1),Ve=/^[^\\r\\n\\t :,]/,ke=Kn([\"\\r\",`\n`,\"\t\",\" \",\":\",\",\"],!0,!1),it=\"null\",Ue=dn(\"null\",!1),x=function(){return null},w=\"true\",P=dn(\"true\",!1),y=function(){return!0},F=\"false\",z=dn(\"false\",!1),Z=function(){return!1},$=Oa(\"string\"),oe='\"',xe=dn('\"',!1),Re=function(){return\"\"},lt=function(te){return te},Ct=function(te){return te.join(\"\")},qt=/^[^\"\\\\\\0-\\x1F\\x7F]/,ir=Kn(['\"',\"\\\\\",[\"\\0\",\"\u001f\"],\"\\x7F\"],!0,!1),bt='\\\\\"',gn=dn('\\\\\"',!1),br=function(){return'\"'},Ir=\"\\\\\\\\\",Or=dn(\"\\\\\\\\\",!1),nn=function(){return\"\\\\\"},ai=\"\\\\/\",Io=dn(\"\\\\/\",!1),ts=function(){return\"/\"},$s=\"\\\\b\",Co=dn(\"\\\\b\",!1),Hi=function(){return\"\\b\"},eo=\"\\\\f\",wo=dn(\"\\\\f\",!1),QA=function(){return\"\\f\"},Af=\"\\\\n\",dh=dn(\"\\\\n\",!1),mh=function(){return`\n`},to=\"\\\\r\",jn=dn(\"\\\\r\",!1),Rs=function(){return\"\\r\"},ro=\"\\\\t\",ou=dn(\"\\\\t\",!1),au=function(){return\"\t\"},lu=\"\\\\u\",RA=dn(\"\\\\u\",!1),TA=function(te,Ee,Oe,dt){return String.fromCharCode(parseInt(`0x${te}${Ee}${Oe}${dt}`))},oa=/^[0-9a-fA-F]/,aa=Kn([[\"0\",\"9\"],[\"a\",\"f\"],[\"A\",\"F\"]],!1,!1),FA=Oa(\"blank space\"),gr=/^[ \\t]/,Bo=Kn([\" \",\"\t\"],!1,!1),Me=Oa(\"white space\"),cu=/^[ \\t\\n\\r]/,Cr=Kn([\" \",\"\t\",`\n`,\"\\r\"],!1,!1),pf=`\\r\n`,NA=dn(`\\r\n`,!1),OA=`\n`,uu=dn(`\n`,!1),fu=\"\\r\",oc=dn(\"\\r\",!1),ve=0,Nt=0,ac=[{line:1,column:1}],Oi=0,no=[],Tt=0,xn;if(\"startRule\"in e){if(!(e.startRule in s))throw new Error(`Can't start parsing from rule \"`+e.startRule+'\".');a=s[e.startRule]}function la(){return t.substring(Nt,ve)}function ji(){return Ma(Nt,ve)}function Li(te,Ee){throw Ee=Ee!==void 0?Ee:Ma(Nt,ve),hf([Oa(te)],t.substring(Nt,ve),Ee)}function Na(te,Ee){throw Ee=Ee!==void 0?Ee:Ma(Nt,ve),Ua(te,Ee)}function dn(te,Ee){return{type:\"literal\",text:te,ignoreCase:Ee}}function Kn(te,Ee,Oe){return{type:\"class\",parts:te,inverted:Ee,ignoreCase:Oe}}function Au(){return{type:\"any\"}}function yh(){return{type:\"end\"}}function Oa(te){return{type:\"other\",description:te}}function La(te){var Ee=ac[te],Oe;if(Ee)return Ee;for(Oe=te-1;!ac[Oe];)Oe--;for(Ee=ac[Oe],Ee={line:Ee.line,column:Ee.column};Oe<te;)t.charCodeAt(Oe)===10?(Ee.line++,Ee.column=1):Ee.column++,Oe++;return ac[te]=Ee,Ee}function Ma(te,Ee){var Oe=La(te),dt=La(Ee);return{start:{offset:te,line:Oe.line,column:Oe.column},end:{offset:Ee,line:dt.line,column:dt.column}}}function $e(te){ve<Oi||(ve>Oi&&(Oi=ve,no=[]),no.push(te))}function Ua(te,Ee){return new Td(te,null,null,Ee)}function hf(te,Ee,Oe){return new Td(Td.buildMessage(te,Ee),te,Ee,Oe)}function lc(){var te;return te=LA(),te}function wn(){var te,Ee,Oe;for(te=ve,Ee=[],Oe=ca();Oe!==r;)Ee.push(Oe),Oe=ca();return Ee!==r&&(Nt=te,Ee=n(Ee)),te=Ee,te}function ca(){var te,Ee,Oe,dt,Et;return te=ve,Ee=Bl(),Ee!==r?(t.charCodeAt(ve)===45?(Oe=c,ve++):(Oe=r,Tt===0&&$e(f)),Oe!==r?(dt=Qn(),dt!==r?(Et=ua(),Et!==r?(Nt=te,Ee=p(Et),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r),te}function LA(){var te,Ee,Oe;for(te=ve,Ee=[],Oe=MA();Oe!==r;)Ee.push(Oe),Oe=MA();return Ee!==r&&(Nt=te,Ee=h(Ee)),te=Ee,te}function MA(){var te,Ee,Oe,dt,Et,Pt,tr,An,li;if(te=ve,Ee=Qn(),Ee===r&&(Ee=null),Ee!==r){if(Oe=ve,t.charCodeAt(ve)===35?(dt=E,ve++):(dt=r,Tt===0&&$e(C)),dt!==r){if(Et=[],Pt=ve,tr=ve,Tt++,An=st(),Tt--,An===r?tr=void 0:(ve=tr,tr=r),tr!==r?(t.length>ve?(An=t.charAt(ve),ve++):(An=r,Tt===0&&$e(S)),An!==r?(tr=[tr,An],Pt=tr):(ve=Pt,Pt=r)):(ve=Pt,Pt=r),Pt!==r)for(;Pt!==r;)Et.push(Pt),Pt=ve,tr=ve,Tt++,An=st(),Tt--,An===r?tr=void 0:(ve=tr,tr=r),tr!==r?(t.length>ve?(An=t.charAt(ve),ve++):(An=r,Tt===0&&$e(S)),An!==r?(tr=[tr,An],Pt=tr):(ve=Pt,Pt=r)):(ve=Pt,Pt=r);else Et=r;Et!==r?(dt=[dt,Et],Oe=dt):(ve=Oe,Oe=r)}else ve=Oe,Oe=r;if(Oe===r&&(Oe=null),Oe!==r){if(dt=[],Et=Ke(),Et!==r)for(;Et!==r;)dt.push(Et),Et=Ke();else dt=r;dt!==r?(Nt=te,Ee=b(),te=Ee):(ve=te,te=r)}else ve=te,te=r}else ve=te,te=r;if(te===r&&(te=ve,Ee=Bl(),Ee!==r?(Oe=Ha(),Oe!==r?(dt=Qn(),dt===r&&(dt=null),dt!==r?(t.charCodeAt(ve)===58?(Et=I,ve++):(Et=r,Tt===0&&$e(T)),Et!==r?(Pt=Qn(),Pt===r&&(Pt=null),Pt!==r?(tr=ua(),tr!==r?(Nt=te,Ee=N(Oe,tr),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r),te===r&&(te=ve,Ee=Bl(),Ee!==r?(Oe=rs(),Oe!==r?(dt=Qn(),dt===r&&(dt=null),dt!==r?(t.charCodeAt(ve)===58?(Et=I,ve++):(Et=r,Tt===0&&$e(T)),Et!==r?(Pt=Qn(),Pt===r&&(Pt=null),Pt!==r?(tr=ua(),tr!==r?(Nt=te,Ee=N(Oe,tr),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r),te===r))){if(te=ve,Ee=Bl(),Ee!==r)if(Oe=rs(),Oe!==r)if(dt=Qn(),dt!==r)if(Et=pu(),Et!==r){if(Pt=[],tr=Ke(),tr!==r)for(;tr!==r;)Pt.push(tr),tr=Ke();else Pt=r;Pt!==r?(Nt=te,Ee=N(Oe,Et),te=Ee):(ve=te,te=r)}else ve=te,te=r;else ve=te,te=r;else ve=te,te=r;else ve=te,te=r;if(te===r)if(te=ve,Ee=Bl(),Ee!==r)if(Oe=rs(),Oe!==r){if(dt=[],Et=ve,Pt=Qn(),Pt===r&&(Pt=null),Pt!==r?(t.charCodeAt(ve)===44?(tr=U,ve++):(tr=r,Tt===0&&$e(W)),tr!==r?(An=Qn(),An===r&&(An=null),An!==r?(li=rs(),li!==r?(Nt=Et,Pt=ee(Oe,li),Et=Pt):(ve=Et,Et=r)):(ve=Et,Et=r)):(ve=Et,Et=r)):(ve=Et,Et=r),Et!==r)for(;Et!==r;)dt.push(Et),Et=ve,Pt=Qn(),Pt===r&&(Pt=null),Pt!==r?(t.charCodeAt(ve)===44?(tr=U,ve++):(tr=r,Tt===0&&$e(W)),tr!==r?(An=Qn(),An===r&&(An=null),An!==r?(li=rs(),li!==r?(Nt=Et,Pt=ee(Oe,li),Et=Pt):(ve=Et,Et=r)):(ve=Et,Et=r)):(ve=Et,Et=r)):(ve=Et,Et=r);else dt=r;dt!==r?(Et=Qn(),Et===r&&(Et=null),Et!==r?(t.charCodeAt(ve)===58?(Pt=I,ve++):(Pt=r,Tt===0&&$e(T)),Pt!==r?(tr=Qn(),tr===r&&(tr=null),tr!==r?(An=ua(),An!==r?(Nt=te,Ee=ie(Oe,dt,An),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)}else ve=te,te=r;else ve=te,te=r}return te}function ua(){var te,Ee,Oe,dt,Et,Pt,tr;if(te=ve,Ee=ve,Tt++,Oe=ve,dt=st(),dt!==r?(Et=Mt(),Et!==r?(t.charCodeAt(ve)===45?(Pt=c,ve++):(Pt=r,Tt===0&&$e(f)),Pt!==r?(tr=Qn(),tr!==r?(dt=[dt,Et,Pt,tr],Oe=dt):(ve=Oe,Oe=r)):(ve=Oe,Oe=r)):(ve=Oe,Oe=r)):(ve=Oe,Oe=r),Tt--,Oe!==r?(ve=Ee,Ee=void 0):Ee=r,Ee!==r?(Oe=Ke(),Oe!==r?(dt=kn(),dt!==r?(Et=wn(),Et!==r?(Pt=fa(),Pt!==r?(Nt=te,Ee=ue(Et),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r),te===r&&(te=ve,Ee=st(),Ee!==r?(Oe=kn(),Oe!==r?(dt=LA(),dt!==r?(Et=fa(),Et!==r?(Nt=te,Ee=ue(dt),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r),te===r))if(te=ve,Ee=cc(),Ee!==r){if(Oe=[],dt=Ke(),dt!==r)for(;dt!==r;)Oe.push(dt),dt=Ke();else Oe=r;Oe!==r?(Nt=te,Ee=le(Ee),te=Ee):(ve=te,te=r)}else ve=te,te=r;return te}function Bl(){var te,Ee,Oe;for(Tt++,te=ve,Ee=[],t.charCodeAt(ve)===32?(Oe=pe,ve++):(Oe=r,Tt===0&&$e(Be));Oe!==r;)Ee.push(Oe),t.charCodeAt(ve)===32?(Oe=pe,ve++):(Oe=r,Tt===0&&$e(Be));return Ee!==r?(Nt=ve,Oe=Ce(Ee),Oe?Oe=void 0:Oe=r,Oe!==r?(Ee=[Ee,Oe],te=Ee):(ve=te,te=r)):(ve=te,te=r),Tt--,te===r&&(Ee=r,Tt===0&&$e(me)),te}function Mt(){var te,Ee,Oe;for(te=ve,Ee=[],t.charCodeAt(ve)===32?(Oe=pe,ve++):(Oe=r,Tt===0&&$e(Be));Oe!==r;)Ee.push(Oe),t.charCodeAt(ve)===32?(Oe=pe,ve++):(Oe=r,Tt===0&&$e(Be));return Ee!==r?(Nt=ve,Oe=g(Ee),Oe?Oe=void 0:Oe=r,Oe!==r?(Ee=[Ee,Oe],te=Ee):(ve=te,te=r)):(ve=te,te=r),te}function kn(){var te;return Nt=ve,te=we(),te?te=void 0:te=r,te}function fa(){var te;return Nt=ve,te=ye(),te?te=void 0:te=r,te}function Ha(){var te;return te=vl(),te===r&&(te=uc()),te}function rs(){var te,Ee,Oe;if(te=vl(),te===r){if(te=ve,Ee=[],Oe=ja(),Oe!==r)for(;Oe!==r;)Ee.push(Oe),Oe=ja();else Ee=r;Ee!==r&&(Nt=te,Ee=Ae()),te=Ee}return te}function cc(){var te;return te=Mi(),te===r&&(te=Is(),te===r&&(te=vl(),te===r&&(te=uc()))),te}function pu(){var te;return te=Mi(),te===r&&(te=vl(),te===r&&(te=ja())),te}function uc(){var te,Ee,Oe,dt,Et,Pt;if(Tt++,te=ve,X.test(t.charAt(ve))?(Ee=t.charAt(ve),ve++):(Ee=r,Tt===0&&$e(De)),Ee!==r){for(Oe=[],dt=ve,Et=Qn(),Et===r&&(Et=null),Et!==r?(Te.test(t.charAt(ve))?(Pt=t.charAt(ve),ve++):(Pt=r,Tt===0&&$e(mt)),Pt!==r?(Et=[Et,Pt],dt=Et):(ve=dt,dt=r)):(ve=dt,dt=r);dt!==r;)Oe.push(dt),dt=ve,Et=Qn(),Et===r&&(Et=null),Et!==r?(Te.test(t.charAt(ve))?(Pt=t.charAt(ve),ve++):(Pt=r,Tt===0&&$e(mt)),Pt!==r?(Et=[Et,Pt],dt=Et):(ve=dt,dt=r)):(ve=dt,dt=r);Oe!==r?(Nt=te,Ee=j(),te=Ee):(ve=te,te=r)}else ve=te,te=r;return Tt--,te===r&&(Ee=r,Tt===0&&$e(se)),te}function ja(){var te,Ee,Oe,dt,Et;if(te=ve,t.substr(ve,2)===rt?(Ee=rt,ve+=2):(Ee=r,Tt===0&&$e(Fe)),Ee===r&&(Ee=null),Ee!==r)if(Ne.test(t.charAt(ve))?(Oe=t.charAt(ve),ve++):(Oe=r,Tt===0&&$e(be)),Oe!==r){for(dt=[],Ve.test(t.charAt(ve))?(Et=t.charAt(ve),ve++):(Et=r,Tt===0&&$e(ke));Et!==r;)dt.push(Et),Ve.test(t.charAt(ve))?(Et=t.charAt(ve),ve++):(Et=r,Tt===0&&$e(ke));dt!==r?(Nt=te,Ee=j(),te=Ee):(ve=te,te=r)}else ve=te,te=r;else ve=te,te=r;return te}function Mi(){var te,Ee;return te=ve,t.substr(ve,4)===it?(Ee=it,ve+=4):(Ee=r,Tt===0&&$e(Ue)),Ee!==r&&(Nt=te,Ee=x()),te=Ee,te}function Is(){var te,Ee;return te=ve,t.substr(ve,4)===w?(Ee=w,ve+=4):(Ee=r,Tt===0&&$e(P)),Ee!==r&&(Nt=te,Ee=y()),te=Ee,te===r&&(te=ve,t.substr(ve,5)===F?(Ee=F,ve+=5):(Ee=r,Tt===0&&$e(z)),Ee!==r&&(Nt=te,Ee=Z()),te=Ee),te}function vl(){var te,Ee,Oe,dt;return Tt++,te=ve,t.charCodeAt(ve)===34?(Ee=oe,ve++):(Ee=r,Tt===0&&$e(xe)),Ee!==r?(t.charCodeAt(ve)===34?(Oe=oe,ve++):(Oe=r,Tt===0&&$e(xe)),Oe!==r?(Nt=te,Ee=Re(),te=Ee):(ve=te,te=r)):(ve=te,te=r),te===r&&(te=ve,t.charCodeAt(ve)===34?(Ee=oe,ve++):(Ee=r,Tt===0&&$e(xe)),Ee!==r?(Oe=gf(),Oe!==r?(t.charCodeAt(ve)===34?(dt=oe,ve++):(dt=r,Tt===0&&$e(xe)),dt!==r?(Nt=te,Ee=lt(Oe),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)),Tt--,te===r&&(Ee=r,Tt===0&&$e($)),te}function gf(){var te,Ee,Oe;if(te=ve,Ee=[],Oe=fc(),Oe!==r)for(;Oe!==r;)Ee.push(Oe),Oe=fc();else Ee=r;return Ee!==r&&(Nt=te,Ee=Ct(Ee)),te=Ee,te}function fc(){var te,Ee,Oe,dt,Et,Pt;return qt.test(t.charAt(ve))?(te=t.charAt(ve),ve++):(te=r,Tt===0&&$e(ir)),te===r&&(te=ve,t.substr(ve,2)===bt?(Ee=bt,ve+=2):(Ee=r,Tt===0&&$e(gn)),Ee!==r&&(Nt=te,Ee=br()),te=Ee,te===r&&(te=ve,t.substr(ve,2)===Ir?(Ee=Ir,ve+=2):(Ee=r,Tt===0&&$e(Or)),Ee!==r&&(Nt=te,Ee=nn()),te=Ee,te===r&&(te=ve,t.substr(ve,2)===ai?(Ee=ai,ve+=2):(Ee=r,Tt===0&&$e(Io)),Ee!==r&&(Nt=te,Ee=ts()),te=Ee,te===r&&(te=ve,t.substr(ve,2)===$s?(Ee=$s,ve+=2):(Ee=r,Tt===0&&$e(Co)),Ee!==r&&(Nt=te,Ee=Hi()),te=Ee,te===r&&(te=ve,t.substr(ve,2)===eo?(Ee=eo,ve+=2):(Ee=r,Tt===0&&$e(wo)),Ee!==r&&(Nt=te,Ee=QA()),te=Ee,te===r&&(te=ve,t.substr(ve,2)===Af?(Ee=Af,ve+=2):(Ee=r,Tt===0&&$e(dh)),Ee!==r&&(Nt=te,Ee=mh()),te=Ee,te===r&&(te=ve,t.substr(ve,2)===to?(Ee=to,ve+=2):(Ee=r,Tt===0&&$e(jn)),Ee!==r&&(Nt=te,Ee=Rs()),te=Ee,te===r&&(te=ve,t.substr(ve,2)===ro?(Ee=ro,ve+=2):(Ee=r,Tt===0&&$e(ou)),Ee!==r&&(Nt=te,Ee=au()),te=Ee,te===r&&(te=ve,t.substr(ve,2)===lu?(Ee=lu,ve+=2):(Ee=r,Tt===0&&$e(RA)),Ee!==r?(Oe=wi(),Oe!==r?(dt=wi(),dt!==r?(Et=wi(),Et!==r?(Pt=wi(),Pt!==r?(Nt=te,Ee=TA(Oe,dt,Et,Pt),te=Ee):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)):(ve=te,te=r)))))))))),te}function wi(){var te;return oa.test(t.charAt(ve))?(te=t.charAt(ve),ve++):(te=r,Tt===0&&$e(aa)),te}function Qn(){var te,Ee;if(Tt++,te=[],gr.test(t.charAt(ve))?(Ee=t.charAt(ve),ve++):(Ee=r,Tt===0&&$e(Bo)),Ee!==r)for(;Ee!==r;)te.push(Ee),gr.test(t.charAt(ve))?(Ee=t.charAt(ve),ve++):(Ee=r,Tt===0&&$e(Bo));else te=r;return Tt--,te===r&&(Ee=r,Tt===0&&$e(FA)),te}function Ac(){var te,Ee;if(Tt++,te=[],cu.test(t.charAt(ve))?(Ee=t.charAt(ve),ve++):(Ee=r,Tt===0&&$e(Cr)),Ee!==r)for(;Ee!==r;)te.push(Ee),cu.test(t.charAt(ve))?(Ee=t.charAt(ve),ve++):(Ee=r,Tt===0&&$e(Cr));else te=r;return Tt--,te===r&&(Ee=r,Tt===0&&$e(Me)),te}function Ke(){var te,Ee,Oe,dt,Et,Pt;if(te=ve,Ee=st(),Ee!==r){for(Oe=[],dt=ve,Et=Qn(),Et===r&&(Et=null),Et!==r?(Pt=st(),Pt!==r?(Et=[Et,Pt],dt=Et):(ve=dt,dt=r)):(ve=dt,dt=r);dt!==r;)Oe.push(dt),dt=ve,Et=Qn(),Et===r&&(Et=null),Et!==r?(Pt=st(),Pt!==r?(Et=[Et,Pt],dt=Et):(ve=dt,dt=r)):(ve=dt,dt=r);Oe!==r?(Ee=[Ee,Oe],te=Ee):(ve=te,te=r)}else ve=te,te=r;return te}function st(){var te;return t.substr(ve,2)===pf?(te=pf,ve+=2):(te=r,Tt===0&&$e(NA)),te===r&&(t.charCodeAt(ve)===10?(te=OA,ve++):(te=r,Tt===0&&$e(uu)),te===r&&(t.charCodeAt(ve)===13?(te=fu,ve++):(te=r,Tt===0&&$e(oc)))),te}let St=2,lr=0;if(xn=a(),xn!==r&&ve===t.length)return xn;throw xn!==r&&ve<t.length&&$e(yh()),hf(no,Oi<t.length?t.charAt(Oi):null,Oi<t.length?Ma(Oi,Oi+1):Ma(Oi,Oi))}pre.exports={SyntaxError:Td,parse:dWe}});function dre(t){return t.match(mWe)?t:JSON.stringify(t)}function yre(t){return typeof t>\"u\"?!0:typeof t==\"object\"&&t!==null&&!Array.isArray(t)?Object.keys(t).every(e=>yre(t[e])):!1}function n_(t,e,r){if(t===null)return`null\n`;if(typeof t==\"number\"||typeof t==\"boolean\")return`${t.toString()}\n`;if(typeof t==\"string\")return`${dre(t)}\n`;if(Array.isArray(t)){if(t.length===0)return`[]\n`;let s=\"  \".repeat(e);return`\n${t.map(n=>`${s}- ${n_(n,e+1,!1)}`).join(\"\")}`}if(typeof t==\"object\"&&t){let[s,a]=t instanceof Sx?[t.data,!1]:[t,!0],n=\"  \".repeat(e),c=Object.keys(s);a&&c.sort((p,h)=>{let E=gre.indexOf(p),C=gre.indexOf(h);return E===-1&&C===-1?p<h?-1:p>h?1:0:E!==-1&&C===-1?-1:E===-1&&C!==-1?1:E-C});let f=c.filter(p=>!yre(s[p])).map((p,h)=>{let E=s[p],C=dre(p),S=n_(E,e+1,!0),b=h>0||r?n:\"\",I=C.length>1024?`? ${C}\n${b}:`:`${C}:`,T=S.startsWith(`\n`)?S:` ${S}`;return`${b}${I}${T}`}).join(e===0?`\n`:\"\")||`\n`;return r?`\n${f}`:`${f}`}throw new Error(`Unsupported value type (${t})`)}function nl(t){try{let e=n_(t,0,!1);return e!==`\n`?e:\"\"}catch(e){throw e.location&&(e.message=e.message.replace(/(\\.)?$/,` (line ${e.location.start.line}, column ${e.location.start.column})$1`)),e}}function yWe(t){return t.endsWith(`\n`)||(t+=`\n`),(0,mre.parse)(t)}function IWe(t){if(EWe.test(t))return yWe(t);let e=(0,Dx.safeLoad)(t,{schema:Dx.FAILSAFE_SCHEMA,json:!0});if(e==null)return{};if(typeof e!=\"object\")throw new Error(`Expected an indexed object, got a ${typeof e} instead. Does your file follow Yaml's rules?`);if(Array.isArray(e))throw new Error(\"Expected an indexed object, got an array instead. Does your file follow Yaml's rules?\");return e}function as(t){return IWe(t)}var Dx,mre,mWe,gre,Sx,EWe,Ere=Ze(()=>{Dx=ut(Are()),mre=ut(hre()),mWe=/^(?![-?:,\\][{}#&*!|>'\"%@` \\t\\r\\n]).([ \\t]*(?![,\\][{}:# \\t\\r\\n]).)*$/,gre=[\"__metadata\",\"version\",\"resolution\",\"dependencies\",\"peerDependencies\",\"dependenciesMeta\",\"peerDependenciesMeta\",\"binaries\"],Sx=class{constructor(e){this.data=e}};nl.PreserveOrdering=Sx;EWe=/^(#.*(\\r?\\n))*?#\\s+yarn\\s+lockfile\\s+v1\\r?\\n/i});var J2={};Vt(J2,{parseResolution:()=>px,parseShell:()=>ux,parseSyml:()=>as,stringifyArgument:()=>GU,stringifyArgumentSegment:()=>qU,stringifyArithmeticExpression:()=>Ax,stringifyCommand:()=>jU,stringifyCommandChain:()=>AE,stringifyCommandChainThen:()=>HU,stringifyCommandLine:()=>fx,stringifyCommandLineThen:()=>_U,stringifyEnvSegment:()=>cx,stringifyRedirectArgument:()=>H2,stringifyResolution:()=>hx,stringifyShell:()=>fE,stringifyShellLine:()=>fE,stringifySyml:()=>nl,stringifyValueArgument:()=>vd});var wc=Ze(()=>{yee();wee();Ere()});var Cre=_((kQt,i_)=>{\"use strict\";var CWe=t=>{let e=!1,r=!1,s=!1;for(let a=0;a<t.length;a++){let n=t[a];e&&/[a-zA-Z]/.test(n)&&n.toUpperCase()===n?(t=t.slice(0,a)+\"-\"+t.slice(a),e=!1,s=r,r=!0,a++):r&&s&&/[a-zA-Z]/.test(n)&&n.toLowerCase()===n?(t=t.slice(0,a-1)+\"-\"+t.slice(a-1),s=r,r=!1,e=!0):(e=n.toLowerCase()===n&&n.toUpperCase()!==n,s=r,r=n.toUpperCase()===n&&n.toLowerCase()!==n)}return t},Ire=(t,e)=>{if(!(typeof t==\"string\"||Array.isArray(t)))throw new TypeError(\"Expected the input to be `string | string[]`\");e=Object.assign({pascalCase:!1},e);let r=a=>e.pascalCase?a.charAt(0).toUpperCase()+a.slice(1):a;return Array.isArray(t)?t=t.map(a=>a.trim()).filter(a=>a.length).join(\"-\"):t=t.trim(),t.length===0?\"\":t.length===1?e.pascalCase?t.toUpperCase():t.toLowerCase():(t!==t.toLowerCase()&&(t=CWe(t)),t=t.replace(/^[_.\\- ]+/,\"\").toLowerCase().replace(/[_.\\- ]+(\\w|$)/g,(a,n)=>n.toUpperCase()).replace(/\\d+(\\w|$)/g,a=>a.toUpperCase()),r(t))};i_.exports=Ire;i_.exports.default=Ire});var wre=_((QQt,wWe)=>{wWe.exports=[{name:\"Agola CI\",constant:\"AGOLA\",env:\"AGOLA_GIT_REF\",pr:\"AGOLA_PULL_REQUEST_ID\"},{name:\"Appcircle\",constant:\"APPCIRCLE\",env:\"AC_APPCIRCLE\"},{name:\"AppVeyor\",constant:\"APPVEYOR\",env:\"APPVEYOR\",pr:\"APPVEYOR_PULL_REQUEST_NUMBER\"},{name:\"AWS CodeBuild\",constant:\"CODEBUILD\",env:\"CODEBUILD_BUILD_ARN\"},{name:\"Azure Pipelines\",constant:\"AZURE_PIPELINES\",env:\"TF_BUILD\",pr:{BUILD_REASON:\"PullRequest\"}},{name:\"Bamboo\",constant:\"BAMBOO\",env:\"bamboo_planKey\"},{name:\"Bitbucket Pipelines\",constant:\"BITBUCKET\",env:\"BITBUCKET_COMMIT\",pr:\"BITBUCKET_PR_ID\"},{name:\"Bitrise\",constant:\"BITRISE\",env:\"BITRISE_IO\",pr:\"BITRISE_PULL_REQUEST\"},{name:\"Buddy\",constant:\"BUDDY\",env:\"BUDDY_WORKSPACE_ID\",pr:\"BUDDY_EXECUTION_PULL_REQUEST_ID\"},{name:\"Buildkite\",constant:\"BUILDKITE\",env:\"BUILDKITE\",pr:{env:\"BUILDKITE_PULL_REQUEST\",ne:\"false\"}},{name:\"CircleCI\",constant:\"CIRCLE\",env:\"CIRCLECI\",pr:\"CIRCLE_PULL_REQUEST\"},{name:\"Cirrus CI\",constant:\"CIRRUS\",env:\"CIRRUS_CI\",pr:\"CIRRUS_PR\"},{name:\"Codefresh\",constant:\"CODEFRESH\",env:\"CF_BUILD_ID\",pr:{any:[\"CF_PULL_REQUEST_NUMBER\",\"CF_PULL_REQUEST_ID\"]}},{name:\"Codemagic\",constant:\"CODEMAGIC\",env:\"CM_BUILD_ID\",pr:\"CM_PULL_REQUEST\"},{name:\"Codeship\",constant:\"CODESHIP\",env:{CI_NAME:\"codeship\"}},{name:\"Drone\",constant:\"DRONE\",env:\"DRONE\",pr:{DRONE_BUILD_EVENT:\"pull_request\"}},{name:\"dsari\",constant:\"DSARI\",env:\"DSARI\"},{name:\"Earthly\",constant:\"EARTHLY\",env:\"EARTHLY_CI\"},{name:\"Expo Application Services\",constant:\"EAS\",env:\"EAS_BUILD\"},{name:\"Gerrit\",constant:\"GERRIT\",env:\"GERRIT_PROJECT\"},{name:\"Gitea Actions\",constant:\"GITEA_ACTIONS\",env:\"GITEA_ACTIONS\"},{name:\"GitHub Actions\",constant:\"GITHUB_ACTIONS\",env:\"GITHUB_ACTIONS\",pr:{GITHUB_EVENT_NAME:\"pull_request\"}},{name:\"GitLab CI\",constant:\"GITLAB\",env:\"GITLAB_CI\",pr:\"CI_MERGE_REQUEST_ID\"},{name:\"GoCD\",constant:\"GOCD\",env:\"GO_PIPELINE_LABEL\"},{name:\"Google Cloud Build\",constant:\"GOOGLE_CLOUD_BUILD\",env:\"BUILDER_OUTPUT\"},{name:\"Harness CI\",constant:\"HARNESS\",env:\"HARNESS_BUILD_ID\"},{name:\"Heroku\",constant:\"HEROKU\",env:{env:\"NODE\",includes:\"/app/.heroku/node/bin/node\"}},{name:\"Hudson\",constant:\"HUDSON\",env:\"HUDSON_URL\"},{name:\"Jenkins\",constant:\"JENKINS\",env:[\"JENKINS_URL\",\"BUILD_ID\"],pr:{any:[\"ghprbPullId\",\"CHANGE_ID\"]}},{name:\"LayerCI\",constant:\"LAYERCI\",env:\"LAYERCI\",pr:\"LAYERCI_PULL_REQUEST\"},{name:\"Magnum CI\",constant:\"MAGNUM\",env:\"MAGNUM\"},{name:\"Netlify CI\",constant:\"NETLIFY\",env:\"NETLIFY\",pr:{env:\"PULL_REQUEST\",ne:\"false\"}},{name:\"Nevercode\",constant:\"NEVERCODE\",env:\"NEVERCODE\",pr:{env:\"NEVERCODE_PULL_REQUEST\",ne:\"false\"}},{name:\"Prow\",constant:\"PROW\",env:\"PROW_JOB_ID\"},{name:\"ReleaseHub\",constant:\"RELEASEHUB\",env:\"RELEASE_BUILD_ID\"},{name:\"Render\",constant:\"RENDER\",env:\"RENDER\",pr:{IS_PULL_REQUEST:\"true\"}},{name:\"Sail CI\",constant:\"SAIL\",env:\"SAILCI\",pr:\"SAIL_PULL_REQUEST_NUMBER\"},{name:\"Screwdriver\",constant:\"SCREWDRIVER\",env:\"SCREWDRIVER\",pr:{env:\"SD_PULL_REQUEST\",ne:\"false\"}},{name:\"Semaphore\",constant:\"SEMAPHORE\",env:\"SEMAPHORE\",pr:\"PULL_REQUEST_NUMBER\"},{name:\"Sourcehut\",constant:\"SOURCEHUT\",env:{CI_NAME:\"sourcehut\"}},{name:\"Strider CD\",constant:\"STRIDER\",env:\"STRIDER\"},{name:\"TaskCluster\",constant:\"TASKCLUSTER\",env:[\"TASK_ID\",\"RUN_ID\"]},{name:\"TeamCity\",constant:\"TEAMCITY\",env:\"TEAMCITY_VERSION\"},{name:\"Travis CI\",constant:\"TRAVIS\",env:\"TRAVIS\",pr:{env:\"TRAVIS_PULL_REQUEST\",ne:\"false\"}},{name:\"Vela\",constant:\"VELA\",env:\"VELA\",pr:{VELA_PULL_REQUEST:\"1\"}},{name:\"Vercel\",constant:\"VERCEL\",env:{any:[\"NOW_BUILDER\",\"VERCEL\"]},pr:\"VERCEL_GIT_PULL_REQUEST_ID\"},{name:\"Visual Studio App Center\",constant:\"APPCENTER\",env:\"APPCENTER_BUILD_ID\"},{name:\"Woodpecker\",constant:\"WOODPECKER\",env:{CI:\"woodpecker\"},pr:{CI_BUILD_EVENT:\"pull_request\"}},{name:\"Xcode Cloud\",constant:\"XCODE_CLOUD\",env:\"CI_XCODE_PROJECT\",pr:\"CI_PULL_REQUEST_NUMBER\"},{name:\"Xcode Server\",constant:\"XCODE_SERVER\",env:\"XCS\"}]});var Fd=_(Ml=>{\"use strict\";var vre=wre(),Ds=process.env;Object.defineProperty(Ml,\"_vendors\",{value:vre.map(function(t){return t.constant})});Ml.name=null;Ml.isPR=null;vre.forEach(function(t){let r=(Array.isArray(t.env)?t.env:[t.env]).every(function(s){return Bre(s)});if(Ml[t.constant]=r,!!r)switch(Ml.name=t.name,typeof t.pr){case\"string\":Ml.isPR=!!Ds[t.pr];break;case\"object\":\"env\"in t.pr?Ml.isPR=t.pr.env in Ds&&Ds[t.pr.env]!==t.pr.ne:\"any\"in t.pr?Ml.isPR=t.pr.any.some(function(s){return!!Ds[s]}):Ml.isPR=Bre(t.pr);break;default:Ml.isPR=null}});Ml.isCI=!!(Ds.CI!==\"false\"&&(Ds.BUILD_ID||Ds.BUILD_NUMBER||Ds.CI||Ds.CI_APP_ID||Ds.CI_BUILD_ID||Ds.CI_BUILD_NUMBER||Ds.CI_NAME||Ds.CONTINUOUS_INTEGRATION||Ds.RUN_ID||Ml.name));function Bre(t){return typeof t==\"string\"?!!Ds[t]:\"env\"in t?Ds[t.env]&&Ds[t.env].includes(t.includes):\"any\"in t?t.any.some(function(e){return!!Ds[e]}):Object.keys(t).every(function(e){return Ds[e]===t[e]})}});var ei,En,Nd,s_,Px,Sre,o_,a_,bx=Ze(()=>{(function(t){t.StartOfInput=\"\\0\",t.EndOfInput=\"\u0001\",t.EndOfPartialInput=\"\u0002\"})(ei||(ei={}));(function(t){t[t.InitialNode=0]=\"InitialNode\",t[t.SuccessNode=1]=\"SuccessNode\",t[t.ErrorNode=2]=\"ErrorNode\",t[t.CustomNode=3]=\"CustomNode\"})(En||(En={}));Nd=-1,s_=/^(-h|--help)(?:=([0-9]+))?$/,Px=/^(--[a-z]+(?:-[a-z]+)*|-[a-zA-Z]+)$/,Sre=/^-[a-zA-Z]{2,}$/,o_=/^([^=]+)=([\\s\\S]*)$/,a_=process.env.DEBUG_CLI===\"1\"});var nt,IE,xx,l_,kx=Ze(()=>{bx();nt=class extends Error{constructor(e){super(e),this.clipanion={type:\"usage\"},this.name=\"UsageError\"}},IE=class extends Error{constructor(e,r){if(super(),this.input=e,this.candidates=r,this.clipanion={type:\"none\"},this.name=\"UnknownSyntaxError\",this.candidates.length===0)this.message=\"Command not found, but we're not sure what's the alternative.\";else if(this.candidates.every(s=>s.reason!==null&&s.reason===r[0].reason)){let[{reason:s}]=this.candidates;this.message=`${s}\n\n${this.candidates.map(({usage:a})=>`$ ${a}`).join(`\n`)}`}else if(this.candidates.length===1){let[{usage:s}]=this.candidates;this.message=`Command not found; did you mean:\n\n$ ${s}\n${l_(e)}`}else this.message=`Command not found; did you mean one of:\n\n${this.candidates.map(({usage:s},a)=>`${`${a}.`.padStart(4)} ${s}`).join(`\n`)}\n\n${l_(e)}`}},xx=class extends Error{constructor(e,r){super(),this.input=e,this.usages=r,this.clipanion={type:\"none\"},this.name=\"AmbiguousSyntaxError\",this.message=`Cannot find which to pick amongst the following alternatives:\n\n${this.usages.map((s,a)=>`${`${a}.`.padStart(4)} ${s}`).join(`\n`)}\n\n${l_(e)}`}},l_=t=>`While running ${t.filter(e=>e!==ei.EndOfInput&&e!==ei.EndOfPartialInput).map(e=>{let r=JSON.stringify(e);return e.match(/\\s/)||e.length===0||r!==`\"${e}\"`?r:e}).join(\" \")}`});function BWe(t){let e=t.split(`\n`),r=e.filter(a=>a.match(/\\S/)),s=r.length>0?r.reduce((a,n)=>Math.min(a,n.length-n.trimStart().length),Number.MAX_VALUE):0;return e.map(a=>a.slice(s).trimRight()).join(`\n`)}function Ho(t,{format:e,paragraphs:r}){return t=t.replace(/\\r\\n?/g,`\n`),t=BWe(t),t=t.replace(/^\\n+|\\n+$/g,\"\"),t=t.replace(/^(\\s*)-([^\\n]*?)\\n+/gm,`$1-$2\n\n`),t=t.replace(/\\n(\\n)?\\n*/g,(s,a)=>a||\" \"),r&&(t=t.split(/\\n/).map(s=>{let a=s.match(/^\\s*[*-][\\t ]+(.*)/);if(!a)return s.match(/(.{1,80})(?: |$)/g).join(`\n`);let n=s.length-s.trimStart().length;return a[1].match(new RegExp(`(.{1,${78-n}})(?: |$)`,\"g\")).map((c,f)=>\" \".repeat(n)+(f===0?\"- \":\"  \")+c).join(`\n`)}).join(`\n\n`)),t=t.replace(/(`+)((?:.|[\\n])*?)\\1/g,(s,a,n)=>e.code(a+n+a)),t=t.replace(/(\\*\\*)((?:.|[\\n])*?)\\1/g,(s,a,n)=>e.bold(a+n+a)),t?`${t}\n`:\"\"}var c_,Dre,Pre,u_=Ze(()=>{c_=Array(80).fill(\"\\u2501\");for(let t=0;t<=24;++t)c_[c_.length-t]=`\\x1B[38;5;${232+t}m\\u2501`;Dre={header:t=>`\\x1B[1m\\u2501\\u2501\\u2501 ${t}${t.length<75?` ${c_.slice(t.length+5).join(\"\")}`:\":\"}\\x1B[0m`,bold:t=>`\\x1B[1m${t}\\x1B[22m`,error:t=>`\\x1B[31m\\x1B[1m${t}\\x1B[22m\\x1B[39m`,code:t=>`\\x1B[36m${t}\\x1B[39m`},Pre={header:t=>t,bold:t=>t,error:t=>t,code:t=>t}});function ya(t){return{...t,[K2]:!0}}function Gf(t,e){return typeof t>\"u\"?[t,e]:typeof t==\"object\"&&t!==null&&!Array.isArray(t)?[void 0,t]:[t,e]}function Qx(t,{mergeName:e=!1}={}){let r=t.match(/^([^:]+): (.*)$/m);if(!r)return\"validation failed\";let[,s,a]=r;return e&&(a=a[0].toLowerCase()+a.slice(1)),a=s!==\".\"||!e?`${s.replace(/^\\.(\\[|$)/,\"$1\")}: ${a}`:`: ${a}`,a}function z2(t,e){return e.length===1?new nt(`${t}${Qx(e[0],{mergeName:!0})}`):new nt(`${t}:\n${e.map(r=>`\n- ${Qx(r)}`).join(\"\")}`)}function Od(t,e,r){if(typeof r>\"u\")return e;let s=[],a=[],n=f=>{let p=e;return e=f,n.bind(null,p)};if(!r(e,{errors:s,coercions:a,coercion:n}))throw z2(`Invalid value for ${t}`,s);for(let[,f]of a)f();return e}var K2,Cp=Ze(()=>{kx();K2=Symbol(\"clipanion/isOption\")});var Ea={};Vt(Ea,{KeyRelationship:()=>qf,TypeAssertionError:()=>o0,applyCascade:()=>$2,as:()=>jWe,assert:()=>UWe,assertWithErrors:()=>_We,cascade:()=>Nx,fn:()=>GWe,hasAtLeastOneKey:()=>m_,hasExactLength:()=>Rre,hasForbiddenKeys:()=>lYe,hasKeyRelationship:()=>tB,hasMaxLength:()=>WWe,hasMinLength:()=>qWe,hasMutuallyExclusiveKeys:()=>cYe,hasRequiredKeys:()=>aYe,hasUniqueItems:()=>YWe,isArray:()=>Rx,isAtLeast:()=>g_,isAtMost:()=>KWe,isBase64:()=>nYe,isBoolean:()=>QWe,isDate:()=>TWe,isDict:()=>OWe,isEnum:()=>fo,isHexColor:()=>rYe,isISO8601:()=>tYe,isInExclusiveRange:()=>ZWe,isInInclusiveRange:()=>zWe,isInstanceOf:()=>MWe,isInteger:()=>d_,isJSON:()=>iYe,isLiteral:()=>xre,isLowerCase:()=>XWe,isMap:()=>NWe,isNegative:()=>VWe,isNullable:()=>oYe,isNumber:()=>p_,isObject:()=>kre,isOneOf:()=>h_,isOptional:()=>sYe,isPartial:()=>LWe,isPayload:()=>RWe,isPositive:()=>JWe,isRecord:()=>Fx,isSet:()=>FWe,isString:()=>wE,isTuple:()=>Tx,isUUID4:()=>eYe,isUnknown:()=>A_,isUpperCase:()=>$We,makeTrait:()=>Qre,makeValidator:()=>Wr,matchesRegExp:()=>X2,softAssert:()=>HWe});function ti(t){return t===null?\"null\":t===void 0?\"undefined\":t===\"\"?\"an empty string\":typeof t==\"symbol\"?`<${t.toString()}>`:Array.isArray(t)?\"an array\":JSON.stringify(t)}function CE(t,e){if(t.length===0)return\"nothing\";if(t.length===1)return ti(t[0]);let r=t.slice(0,-1),s=t[t.length-1],a=t.length>2?`, ${e} `:` ${e} `;return`${r.map(n=>ti(n)).join(\", \")}${a}${ti(s)}`}function s0(t,e){var r,s,a;return typeof e==\"number\"?`${(r=t?.p)!==null&&r!==void 0?r:\".\"}[${e}]`:vWe.test(e)?`${(s=t?.p)!==null&&s!==void 0?s:\"\"}.${e}`:`${(a=t?.p)!==null&&a!==void 0?a:\".\"}[${JSON.stringify(e)}]`}function f_(t,e,r){return t===1?e:r}function mr({errors:t,p:e}={},r){return t?.push(`${e??\".\"}: ${r}`),!1}function xWe(t,e){return r=>{t[e]=r}}function Wf(t,e){return r=>{let s=t[e];return t[e]=r,Wf(t,e).bind(null,s)}}function Z2(t,e,r){let s=()=>(t(r()),a),a=()=>(t(e),s);return s}function A_(){return Wr({test:(t,e)=>!0})}function xre(t){return Wr({test:(e,r)=>e!==t?mr(r,`Expected ${ti(t)} (got ${ti(e)})`):!0})}function wE(){return Wr({test:(t,e)=>typeof t!=\"string\"?mr(e,`Expected a string (got ${ti(t)})`):!0})}function fo(t){let e=Array.isArray(t)?t:Object.values(t),r=e.every(a=>typeof a==\"string\"||typeof a==\"number\"),s=new Set(e);return s.size===1?xre([...s][0]):Wr({test:(a,n)=>s.has(a)?!0:r?mr(n,`Expected one of ${CE(e,\"or\")} (got ${ti(a)})`):mr(n,`Expected a valid enumeration value (got ${ti(a)})`)})}function QWe(){return Wr({test:(t,e)=>{var r;if(typeof t!=\"boolean\"){if(typeof e?.coercions<\"u\"){if(typeof e?.coercion>\"u\")return mr(e,\"Unbound coercion result\");let s=kWe.get(t);if(typeof s<\"u\")return e.coercions.push([(r=e.p)!==null&&r!==void 0?r:\".\",e.coercion.bind(null,s)]),!0}return mr(e,`Expected a boolean (got ${ti(t)})`)}return!0}})}function p_(){return Wr({test:(t,e)=>{var r;if(typeof t!=\"number\"){if(typeof e?.coercions<\"u\"){if(typeof e?.coercion>\"u\")return mr(e,\"Unbound coercion result\");let s;if(typeof t==\"string\"){let a;try{a=JSON.parse(t)}catch{}if(typeof a==\"number\")if(JSON.stringify(a)===t)s=a;else return mr(e,`Received a number that can't be safely represented by the runtime (${t})`)}if(typeof s<\"u\")return e.coercions.push([(r=e.p)!==null&&r!==void 0?r:\".\",e.coercion.bind(null,s)]),!0}return mr(e,`Expected a number (got ${ti(t)})`)}return!0}})}function RWe(t){return Wr({test:(e,r)=>{var s;if(typeof r?.coercions>\"u\")return mr(r,\"The isPayload predicate can only be used with coercion enabled\");if(typeof r.coercion>\"u\")return mr(r,\"Unbound coercion result\");if(typeof e!=\"string\")return mr(r,`Expected a string (got ${ti(e)})`);let a;try{a=JSON.parse(e)}catch{return mr(r,`Expected a JSON string (got ${ti(e)})`)}let n={value:a};return t(a,Object.assign(Object.assign({},r),{coercion:Wf(n,\"value\")}))?(r.coercions.push([(s=r.p)!==null&&s!==void 0?s:\".\",r.coercion.bind(null,n.value)]),!0):!1}})}function TWe(){return Wr({test:(t,e)=>{var r;if(!(t instanceof Date)){if(typeof e?.coercions<\"u\"){if(typeof e?.coercion>\"u\")return mr(e,\"Unbound coercion result\");let s;if(typeof t==\"string\"&&bre.test(t))s=new Date(t);else{let a;if(typeof t==\"string\"){let n;try{n=JSON.parse(t)}catch{}typeof n==\"number\"&&(a=n)}else typeof t==\"number\"&&(a=t);if(typeof a<\"u\")if(Number.isSafeInteger(a)||!Number.isSafeInteger(a*1e3))s=new Date(a*1e3);else return mr(e,`Received a timestamp that can't be safely represented by the runtime (${t})`)}if(typeof s<\"u\")return e.coercions.push([(r=e.p)!==null&&r!==void 0?r:\".\",e.coercion.bind(null,s)]),!0}return mr(e,`Expected a date (got ${ti(t)})`)}return!0}})}function Rx(t,{delimiter:e}={}){return Wr({test:(r,s)=>{var a;let n=r;if(typeof r==\"string\"&&typeof e<\"u\"&&typeof s?.coercions<\"u\"){if(typeof s?.coercion>\"u\")return mr(s,\"Unbound coercion result\");r=r.split(e)}if(!Array.isArray(r))return mr(s,`Expected an array (got ${ti(r)})`);let c=!0;for(let f=0,p=r.length;f<p&&(c=t(r[f],Object.assign(Object.assign({},s),{p:s0(s,f),coercion:Wf(r,f)}))&&c,!(!c&&s?.errors==null));++f);return r!==n&&s.coercions.push([(a=s.p)!==null&&a!==void 0?a:\".\",s.coercion.bind(null,r)]),c}})}function FWe(t,{delimiter:e}={}){let r=Rx(t,{delimiter:e});return Wr({test:(s,a)=>{var n,c;if(Object.getPrototypeOf(s).toString()===\"[object Set]\")if(typeof a?.coercions<\"u\"){if(typeof a?.coercion>\"u\")return mr(a,\"Unbound coercion result\");let f=[...s],p=[...s];if(!r(p,Object.assign(Object.assign({},a),{coercion:void 0})))return!1;let h=()=>p.some((E,C)=>E!==f[C])?new Set(p):s;return a.coercions.push([(n=a.p)!==null&&n!==void 0?n:\".\",Z2(a.coercion,s,h)]),!0}else{let f=!0;for(let p of s)if(f=t(p,Object.assign({},a))&&f,!f&&a?.errors==null)break;return f}if(typeof a?.coercions<\"u\"){if(typeof a?.coercion>\"u\")return mr(a,\"Unbound coercion result\");let f={value:s};return r(s,Object.assign(Object.assign({},a),{coercion:Wf(f,\"value\")}))?(a.coercions.push([(c=a.p)!==null&&c!==void 0?c:\".\",Z2(a.coercion,s,()=>new Set(f.value))]),!0):!1}return mr(a,`Expected a set (got ${ti(s)})`)}})}function NWe(t,e){let r=Rx(Tx([t,e])),s=Fx(e,{keys:t});return Wr({test:(a,n)=>{var c,f,p;if(Object.getPrototypeOf(a).toString()===\"[object Map]\")if(typeof n?.coercions<\"u\"){if(typeof n?.coercion>\"u\")return mr(n,\"Unbound coercion result\");let h=[...a],E=[...a];if(!r(E,Object.assign(Object.assign({},n),{coercion:void 0})))return!1;let C=()=>E.some((S,b)=>S[0]!==h[b][0]||S[1]!==h[b][1])?new Map(E):a;return n.coercions.push([(c=n.p)!==null&&c!==void 0?c:\".\",Z2(n.coercion,a,C)]),!0}else{let h=!0;for(let[E,C]of a)if(h=t(E,Object.assign({},n))&&h,!h&&n?.errors==null||(h=e(C,Object.assign(Object.assign({},n),{p:s0(n,E)}))&&h,!h&&n?.errors==null))break;return h}if(typeof n?.coercions<\"u\"){if(typeof n?.coercion>\"u\")return mr(n,\"Unbound coercion result\");let h={value:a};return Array.isArray(a)?r(a,Object.assign(Object.assign({},n),{coercion:void 0}))?(n.coercions.push([(f=n.p)!==null&&f!==void 0?f:\".\",Z2(n.coercion,a,()=>new Map(h.value))]),!0):!1:s(a,Object.assign(Object.assign({},n),{coercion:Wf(h,\"value\")}))?(n.coercions.push([(p=n.p)!==null&&p!==void 0?p:\".\",Z2(n.coercion,a,()=>new Map(Object.entries(h.value)))]),!0):!1}return mr(n,`Expected a map (got ${ti(a)})`)}})}function Tx(t,{delimiter:e}={}){let r=Rre(t.length);return Wr({test:(s,a)=>{var n;if(typeof s==\"string\"&&typeof e<\"u\"&&typeof a?.coercions<\"u\"){if(typeof a?.coercion>\"u\")return mr(a,\"Unbound coercion result\");s=s.split(e),a.coercions.push([(n=a.p)!==null&&n!==void 0?n:\".\",a.coercion.bind(null,s)])}if(!Array.isArray(s))return mr(a,`Expected a tuple (got ${ti(s)})`);let c=r(s,Object.assign({},a));for(let f=0,p=s.length;f<p&&f<t.length&&(c=t[f](s[f],Object.assign(Object.assign({},a),{p:s0(a,f),coercion:Wf(s,f)}))&&c,!(!c&&a?.errors==null));++f);return c}})}function Fx(t,{keys:e=null}={}){let r=Rx(Tx([e??wE(),t]));return Wr({test:(s,a)=>{var n;if(Array.isArray(s)&&typeof a?.coercions<\"u\")return typeof a?.coercion>\"u\"?mr(a,\"Unbound coercion result\"):r(s,Object.assign(Object.assign({},a),{coercion:void 0}))?(s=Object.fromEntries(s),a.coercions.push([(n=a.p)!==null&&n!==void 0?n:\".\",a.coercion.bind(null,s)]),!0):!1;if(typeof s!=\"object\"||s===null)return mr(a,`Expected an object (got ${ti(s)})`);let c=Object.keys(s),f=!0;for(let p=0,h=c.length;p<h&&(f||a?.errors!=null);++p){let E=c[p],C=s[E];if(E===\"__proto__\"||E===\"constructor\"){f=mr(Object.assign(Object.assign({},a),{p:s0(a,E)}),\"Unsafe property name\");continue}if(e!==null&&!e(E,a)){f=!1;continue}if(!t(C,Object.assign(Object.assign({},a),{p:s0(a,E),coercion:Wf(s,E)}))){f=!1;continue}}return f}})}function OWe(t,e={}){return Fx(t,e)}function kre(t,{extra:e=null}={}){let r=Object.keys(t),s=Wr({test:(a,n)=>{if(typeof a!=\"object\"||a===null)return mr(n,`Expected an object (got ${ti(a)})`);let c=new Set([...r,...Object.keys(a)]),f={},p=!0;for(let h of c){if(h===\"constructor\"||h===\"__proto__\")p=mr(Object.assign(Object.assign({},n),{p:s0(n,h)}),\"Unsafe property name\");else{let E=Object.prototype.hasOwnProperty.call(t,h)?t[h]:void 0,C=Object.prototype.hasOwnProperty.call(a,h)?a[h]:void 0;typeof E<\"u\"?p=E(C,Object.assign(Object.assign({},n),{p:s0(n,h),coercion:Wf(a,h)}))&&p:e===null?p=mr(Object.assign(Object.assign({},n),{p:s0(n,h)}),`Extraneous property (got ${ti(C)})`):Object.defineProperty(f,h,{enumerable:!0,get:()=>C,set:xWe(a,h)})}if(!p&&n?.errors==null)break}return e!==null&&(p||n?.errors!=null)&&(p=e(f,n)&&p),p}});return Object.assign(s,{properties:t})}function LWe(t){return kre(t,{extra:Fx(A_())})}function Qre(t){return()=>t}function Wr({test:t}){return Qre(t)()}function UWe(t,e){if(!e(t))throw new o0}function _We(t,e){let r=[];if(!e(t,{errors:r}))throw new o0({errors:r})}function HWe(t,e){}function jWe(t,e,{coerce:r=!1,errors:s,throw:a}={}){let n=s?[]:void 0;if(!r){if(e(t,{errors:n}))return a?t:{value:t,errors:void 0};if(a)throw new o0({errors:n});return{value:void 0,errors:n??!0}}let c={value:t},f=Wf(c,\"value\"),p=[];if(!e(t,{errors:n,coercion:f,coercions:p})){if(a)throw new o0({errors:n});return{value:void 0,errors:n??!0}}for(let[,h]of p)h();return a?c.value:{value:c.value,errors:void 0}}function GWe(t,e){let r=Tx(t);return(...s)=>{if(!r(s))throw new o0;return e(...s)}}function qWe(t){return Wr({test:(e,r)=>e.length>=t?!0:mr(r,`Expected to have a length of at least ${t} elements (got ${e.length})`)})}function WWe(t){return Wr({test:(e,r)=>e.length<=t?!0:mr(r,`Expected to have a length of at most ${t} elements (got ${e.length})`)})}function Rre(t){return Wr({test:(e,r)=>e.length!==t?mr(r,`Expected to have a length of exactly ${t} elements (got ${e.length})`):!0})}function YWe({map:t}={}){return Wr({test:(e,r)=>{let s=new Set,a=new Set;for(let n=0,c=e.length;n<c;++n){let f=e[n],p=typeof t<\"u\"?t(f):f;if(s.has(p)){if(a.has(p))continue;mr(r,`Expected to contain unique elements; got a duplicate with ${ti(e)}`),a.add(p)}else s.add(p)}return a.size===0}})}function VWe(){return Wr({test:(t,e)=>t<=0?!0:mr(e,`Expected to be negative (got ${t})`)})}function JWe(){return Wr({test:(t,e)=>t>=0?!0:mr(e,`Expected to be positive (got ${t})`)})}function g_(t){return Wr({test:(e,r)=>e>=t?!0:mr(r,`Expected to be at least ${t} (got ${e})`)})}function KWe(t){return Wr({test:(e,r)=>e<=t?!0:mr(r,`Expected to be at most ${t} (got ${e})`)})}function zWe(t,e){return Wr({test:(r,s)=>r>=t&&r<=e?!0:mr(s,`Expected to be in the [${t}; ${e}] range (got ${r})`)})}function ZWe(t,e){return Wr({test:(r,s)=>r>=t&&r<e?!0:mr(s,`Expected to be in the [${t}; ${e}[ range (got ${r})`)})}function d_({unsafe:t=!1}={}){return Wr({test:(e,r)=>e!==Math.round(e)?mr(r,`Expected to be an integer (got ${e})`):!t&&!Number.isSafeInteger(e)?mr(r,`Expected to be a safe integer (got ${e})`):!0})}function X2(t){return Wr({test:(e,r)=>t.test(e)?!0:mr(r,`Expected to match the pattern ${t.toString()} (got ${ti(e)})`)})}function XWe(){return Wr({test:(t,e)=>t!==t.toLowerCase()?mr(e,`Expected to be all-lowercase (got ${t})`):!0})}function $We(){return Wr({test:(t,e)=>t!==t.toUpperCase()?mr(e,`Expected to be all-uppercase (got ${t})`):!0})}function eYe(){return Wr({test:(t,e)=>bWe.test(t)?!0:mr(e,`Expected to be a valid UUID v4 (got ${ti(t)})`)})}function tYe(){return Wr({test:(t,e)=>bre.test(t)?!0:mr(e,`Expected to be a valid ISO 8601 date string (got ${ti(t)})`)})}function rYe({alpha:t=!1}){return Wr({test:(e,r)=>(t?SWe.test(e):DWe.test(e))?!0:mr(r,`Expected to be a valid hexadecimal color string (got ${ti(e)})`)})}function nYe(){return Wr({test:(t,e)=>PWe.test(t)?!0:mr(e,`Expected to be a valid base 64 string (got ${ti(t)})`)})}function iYe(t=A_()){return Wr({test:(e,r)=>{let s;try{s=JSON.parse(e)}catch{return mr(r,`Expected to be a valid JSON string (got ${ti(e)})`)}return t(s,r)}})}function Nx(t,...e){let r=Array.isArray(e[0])?e[0]:e;return Wr({test:(s,a)=>{var n,c;let f={value:s},p=typeof a?.coercions<\"u\"?Wf(f,\"value\"):void 0,h=typeof a?.coercions<\"u\"?[]:void 0;if(!t(s,Object.assign(Object.assign({},a),{coercion:p,coercions:h})))return!1;let E=[];if(typeof h<\"u\")for(let[,C]of h)E.push(C());try{if(typeof a?.coercions<\"u\"){if(f.value!==s){if(typeof a?.coercion>\"u\")return mr(a,\"Unbound coercion result\");a.coercions.push([(n=a.p)!==null&&n!==void 0?n:\".\",a.coercion.bind(null,f.value)])}(c=a?.coercions)===null||c===void 0||c.push(...h)}return r.every(C=>C(f.value,a))}finally{for(let C of E)C()}}})}function $2(t,...e){let r=Array.isArray(e[0])?e[0]:e;return Nx(t,r)}function sYe(t){return Wr({test:(e,r)=>typeof e>\"u\"?!0:t(e,r)})}function oYe(t){return Wr({test:(e,r)=>e===null?!0:t(e,r)})}function aYe(t,e){var r;let s=new Set(t),a=eB[(r=e?.missingIf)!==null&&r!==void 0?r:\"missing\"];return Wr({test:(n,c)=>{let f=new Set(Object.keys(n)),p=[];for(let h of s)a(f,h,n)||p.push(h);return p.length>0?mr(c,`Missing required ${f_(p.length,\"property\",\"properties\")} ${CE(p,\"and\")}`):!0}})}function m_(t,e){var r;let s=new Set(t),a=eB[(r=e?.missingIf)!==null&&r!==void 0?r:\"missing\"];return Wr({test:(n,c)=>Object.keys(n).some(h=>a(s,h,n))?!0:mr(c,`Missing at least one property from ${CE(Array.from(s),\"or\")}`)})}function lYe(t,e){var r;let s=new Set(t),a=eB[(r=e?.missingIf)!==null&&r!==void 0?r:\"missing\"];return Wr({test:(n,c)=>{let f=new Set(Object.keys(n)),p=[];for(let h of s)a(f,h,n)&&p.push(h);return p.length>0?mr(c,`Forbidden ${f_(p.length,\"property\",\"properties\")} ${CE(p,\"and\")}`):!0}})}function cYe(t,e){var r;let s=new Set(t),a=eB[(r=e?.missingIf)!==null&&r!==void 0?r:\"missing\"];return Wr({test:(n,c)=>{let f=new Set(Object.keys(n)),p=[];for(let h of s)a(f,h,n)&&p.push(h);return p.length>1?mr(c,`Mutually exclusive properties ${CE(p,\"and\")}`):!0}})}function tB(t,e,r,s){var a,n;let c=new Set((a=s?.ignore)!==null&&a!==void 0?a:[]),f=eB[(n=s?.missingIf)!==null&&n!==void 0?n:\"missing\"],p=new Set(r),h=uYe[e],E=e===qf.Forbids?\"or\":\"and\";return Wr({test:(C,S)=>{let b=new Set(Object.keys(C));if(!f(b,t,C)||c.has(C[t]))return!0;let I=[];for(let T of p)(f(b,T,C)&&!c.has(C[T]))!==h.expect&&I.push(T);return I.length>=1?mr(S,`Property \"${t}\" ${h.message} ${f_(I.length,\"property\",\"properties\")} ${CE(I,E)}`):!0}})}var vWe,SWe,DWe,PWe,bWe,bre,kWe,MWe,h_,o0,eB,qf,uYe,Ul=Ze(()=>{vWe=/^[a-zA-Z_][a-zA-Z0-9_]*$/;SWe=/^#[0-9a-f]{6}$/i,DWe=/^#[0-9a-f]{6}([0-9a-f]{2})?$/i,PWe=/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/,bWe=/^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}$/i,bre=/^(?:[1-9]\\d{3}(-?)(?:(?:0[1-9]|1[0-2])\\1(?:0[1-9]|1\\d|2[0-8])|(?:0[13-9]|1[0-2])\\1(?:29|30)|(?:0[13578]|1[02])(?:\\1)31|00[1-9]|0[1-9]\\d|[12]\\d{2}|3(?:[0-5]\\d|6[0-5]))|(?:[1-9]\\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)(?:(-?)02(?:\\2)29|-?366))T(?:[01]\\d|2[0-3])(:?)[0-5]\\d(?:\\3[0-5]\\d)?(?:Z|[+-][01]\\d(?:\\3[0-5]\\d)?)$/;kWe=new Map([[\"true\",!0],[\"True\",!0],[\"1\",!0],[1,!0],[\"false\",!1],[\"False\",!1],[\"0\",!1],[0,!1]]);MWe=t=>Wr({test:(e,r)=>e instanceof t?!0:mr(r,`Expected an instance of ${t.name} (got ${ti(e)})`)}),h_=(t,{exclusive:e=!1}={})=>Wr({test:(r,s)=>{var a,n,c;let f=[],p=typeof s?.errors<\"u\"?[]:void 0;for(let h=0,E=t.length;h<E;++h){let C=typeof s?.errors<\"u\"?[]:void 0,S=typeof s?.coercions<\"u\"?[]:void 0;if(t[h](r,Object.assign(Object.assign({},s),{errors:C,coercions:S,p:`${(a=s?.p)!==null&&a!==void 0?a:\".\"}#${h+1}`}))){if(f.push([`#${h+1}`,S]),!e)break}else p?.push(C[0])}if(f.length===1){let[,h]=f[0];return typeof h<\"u\"&&((n=s?.coercions)===null||n===void 0||n.push(...h)),!0}return f.length>1?mr(s,`Expected to match exactly a single predicate (matched ${f.join(\", \")})`):(c=s?.errors)===null||c===void 0||c.push(...p),!1}});o0=class extends Error{constructor({errors:e}={}){let r=\"Type mismatch\";if(e&&e.length>0){r+=`\n`;for(let s of e)r+=`\n- ${s}`}super(r)}};eB={missing:(t,e)=>t.has(e),undefined:(t,e,r)=>t.has(e)&&typeof r[e]<\"u\",nil:(t,e,r)=>t.has(e)&&r[e]!=null,falsy:(t,e,r)=>t.has(e)&&!!r[e]};(function(t){t.Forbids=\"Forbids\",t.Requires=\"Requires\"})(qf||(qf={}));uYe={[qf.Forbids]:{expect:!1,message:\"forbids using\"},[qf.Requires]:{expect:!0,message:\"requires using\"}}});var ot,a0=Ze(()=>{Cp();ot=class{constructor(){this.help=!1}static Usage(e){return e}async catch(e){throw e}async validateAndExecute(){let r=this.constructor.schema;if(Array.isArray(r)){let{isDict:a,isUnknown:n,applyCascade:c}=await Promise.resolve().then(()=>(Ul(),Ea)),f=c(a(n()),r),p=[],h=[];if(!f(this,{errors:p,coercions:h}))throw z2(\"Invalid option schema\",p);for(let[,C]of h)C()}else if(r!=null)throw new Error(\"Invalid command schema\");let s=await this.execute();return typeof s<\"u\"?s:0}};ot.isOption=K2;ot.Default=[]});function il(t){a_&&console.log(t)}function Fre(){let t={nodes:[]};for(let e=0;e<En.CustomNode;++e)t.nodes.push(_l());return t}function fYe(t){let e=Fre(),r=[],s=e.nodes.length;for(let a of t){r.push(s);for(let n=0;n<a.nodes.length;++n)Ore(n)||e.nodes.push(EYe(a.nodes[n],s));s+=a.nodes.length-En.CustomNode+1}for(let a of r)BE(e,En.InitialNode,a);return e}function Ou(t,e){return t.nodes.push(e),t.nodes.length-1}function AYe(t){let e=new Set,r=s=>{if(e.has(s))return;e.add(s);let a=t.nodes[s];for(let c of Object.values(a.statics))for(let{to:f}of c)r(f);for(let[,{to:c}]of a.dynamics)r(c);for(let{to:c}of a.shortcuts)r(c);let n=new Set(a.shortcuts.map(({to:c})=>c));for(;a.shortcuts.length>0;){let{to:c}=a.shortcuts.shift(),f=t.nodes[c];for(let[p,h]of Object.entries(f.statics)){let E=Object.prototype.hasOwnProperty.call(a.statics,p)?a.statics[p]:a.statics[p]=[];for(let C of h)E.some(({to:S})=>C.to===S)||E.push(C)}for(let[p,h]of f.dynamics)a.dynamics.some(([E,{to:C}])=>p===E&&h.to===C)||a.dynamics.push([p,h]);for(let p of f.shortcuts)n.has(p.to)||(a.shortcuts.push(p),n.add(p.to))}};r(En.InitialNode)}function pYe(t,{prefix:e=\"\"}={}){if(a_){il(`${e}Nodes are:`);for(let r=0;r<t.nodes.length;++r)il(`${e}  ${r}: ${JSON.stringify(t.nodes[r])}`)}}function hYe(t,e,r=!1){il(`Running a vm on ${JSON.stringify(e)}`);let s=[{node:En.InitialNode,state:{candidateUsage:null,requiredOptions:[],errorMessage:null,ignoreOptions:!1,options:[],path:[],positionals:[],remainder:null,selectedIndex:null,partial:!1,tokens:[]}}];pYe(t,{prefix:\"  \"});let a=[ei.StartOfInput,...e];for(let n=0;n<a.length;++n){let c=a[n],f=c===ei.EndOfInput||c===ei.EndOfPartialInput,p=n-1;il(`  Processing ${JSON.stringify(c)}`);let h=[];for(let{node:E,state:C}of s){il(`    Current node is ${E}`);let S=t.nodes[E];if(E===En.ErrorNode){h.push({node:E,state:C});continue}console.assert(S.shortcuts.length===0,\"Shortcuts should have been eliminated by now\");let b=Object.prototype.hasOwnProperty.call(S.statics,c);if(!r||n<a.length-1||b)if(b){let I=S.statics[c];for(let{to:T,reducer:N}of I)h.push({node:T,state:typeof N<\"u\"?Ox(E_,N,C,c,p):C}),il(`      Static transition to ${T} found`)}else il(\"      No static transition found\");else{let I=!1;for(let T of Object.keys(S.statics))if(T.startsWith(c)){if(c===T)for(let{to:N,reducer:U}of S.statics[T])h.push({node:N,state:typeof U<\"u\"?Ox(E_,U,C,c,p):C}),il(`      Static transition to ${N} found`);else for(let{to:N}of S.statics[T])h.push({node:N,state:{...C,remainder:T.slice(c.length)}}),il(`      Static transition to ${N} found (partial match)`);I=!0}I||il(\"      No partial static transition found\")}if(!f)for(let[I,{to:T,reducer:N}]of S.dynamics)Ox(IYe,I,C,c,p)&&(h.push({node:T,state:typeof N<\"u\"?Ox(E_,N,C,c,p):C}),il(`      Dynamic transition to ${T} found (via ${I})`))}if(h.length===0&&f&&e.length===1)return[{node:En.InitialNode,state:Tre}];if(h.length===0)throw new IE(e,s.filter(({node:E})=>E!==En.ErrorNode).map(({state:E})=>({usage:E.candidateUsage,reason:null})));if(h.every(({node:E})=>E===En.ErrorNode))throw new IE(e,h.map(({state:E})=>({usage:E.candidateUsage,reason:E.errorMessage})));s=dYe(h)}if(s.length>0){il(\"  Results:\");for(let n of s)il(`    - ${n.node} -> ${JSON.stringify(n.state)}`)}else il(\"  No results\");return s}function gYe(t,e,{endToken:r=ei.EndOfInput}={}){let s=hYe(t,[...e,r]);return mYe(e,s.map(({state:a})=>a))}function dYe(t){let e=0;for(let{state:r}of t)r.path.length>e&&(e=r.path.length);return t.filter(({state:r})=>r.path.length===e)}function mYe(t,e){let r=e.filter(S=>S.selectedIndex!==null),s=r.filter(S=>!S.partial);if(s.length>0&&(r=s),r.length===0)throw new Error;let a=r.filter(S=>S.selectedIndex===Nd||S.requiredOptions.every(b=>b.some(I=>S.options.find(T=>T.name===I))));if(a.length===0)throw new IE(t,r.map(S=>({usage:S.candidateUsage,reason:null})));let n=0;for(let S of a)S.path.length>n&&(n=S.path.length);let c=a.filter(S=>S.path.length===n),f=S=>S.positionals.filter(({extra:b})=>!b).length+S.options.length,p=c.map(S=>({state:S,positionalCount:f(S)})),h=0;for(let{positionalCount:S}of p)S>h&&(h=S);let E=p.filter(({positionalCount:S})=>S===h).map(({state:S})=>S),C=yYe(E);if(C.length>1)throw new xx(t,C.map(S=>S.candidateUsage));return C[0]}function yYe(t){let e=[],r=[];for(let s of t)s.selectedIndex===Nd?r.push(s):e.push(s);return r.length>0&&e.push({...Tre,path:Nre(...r.map(s=>s.path)),options:r.reduce((s,a)=>s.concat(a.options),[])}),e}function Nre(t,e,...r){return e===void 0?Array.from(t):Nre(t.filter((s,a)=>s===e[a]),...r)}function _l(){return{dynamics:[],shortcuts:[],statics:{}}}function Ore(t){return t===En.SuccessNode||t===En.ErrorNode}function y_(t,e=0){return{to:Ore(t.to)?t.to:t.to>=En.CustomNode?t.to+e-En.CustomNode+1:t.to+e,reducer:t.reducer}}function EYe(t,e=0){let r=_l();for(let[s,a]of t.dynamics)r.dynamics.push([s,y_(a,e)]);for(let s of t.shortcuts)r.shortcuts.push(y_(s,e));for(let[s,a]of Object.entries(t.statics))r.statics[s]=a.map(n=>y_(n,e));return r}function Hs(t,e,r,s,a){t.nodes[e].dynamics.push([r,{to:s,reducer:a}])}function BE(t,e,r,s){t.nodes[e].shortcuts.push({to:r,reducer:s})}function Ia(t,e,r,s,a){(Object.prototype.hasOwnProperty.call(t.nodes[e].statics,r)?t.nodes[e].statics[r]:t.nodes[e].statics[r]=[]).push({to:s,reducer:a})}function Ox(t,e,r,s,a){if(Array.isArray(e)){let[n,...c]=e;return t[n](r,s,a,...c)}else return t[e](r,s,a)}var Tre,IYe,E_,Hl,I_,Lx,Mx=Ze(()=>{bx();kx();Tre={candidateUsage:null,requiredOptions:[],errorMessage:null,ignoreOptions:!1,path:[],positionals:[],options:[],remainder:null,selectedIndex:Nd,partial:!1,tokens:[]};IYe={always:()=>!0,isOptionLike:(t,e)=>!t.ignoreOptions&&e!==\"-\"&&e.startsWith(\"-\"),isNotOptionLike:(t,e)=>t.ignoreOptions||e===\"-\"||!e.startsWith(\"-\"),isOption:(t,e,r,s)=>!t.ignoreOptions&&e===s,isBatchOption:(t,e,r,s)=>!t.ignoreOptions&&Sre.test(e)&&[...e.slice(1)].every(a=>s.has(`-${a}`)),isBoundOption:(t,e,r,s,a)=>{let n=e.match(o_);return!t.ignoreOptions&&!!n&&Px.test(n[1])&&s.has(n[1])&&a.filter(c=>c.nameSet.includes(n[1])).every(c=>c.allowBinding)},isNegatedOption:(t,e,r,s)=>!t.ignoreOptions&&e===`--no-${s.slice(2)}`,isHelp:(t,e)=>!t.ignoreOptions&&s_.test(e),isUnsupportedOption:(t,e,r,s)=>!t.ignoreOptions&&e.startsWith(\"-\")&&Px.test(e)&&!s.has(e),isInvalidOption:(t,e)=>!t.ignoreOptions&&e.startsWith(\"-\")&&!Px.test(e)},E_={setCandidateState:(t,e,r,s)=>({...t,...s}),setSelectedIndex:(t,e,r,s)=>({...t,selectedIndex:s}),setPartialIndex:(t,e,r,s)=>({...t,selectedIndex:s,partial:!0}),pushBatch:(t,e,r,s)=>{let a=t.options.slice(),n=t.tokens.slice();for(let c=1;c<e.length;++c){let f=s.get(`-${e[c]}`),p=c===1?[0,2]:[c,c+1];a.push({name:f,value:!0}),n.push({segmentIndex:r,type:\"option\",option:f,slice:p})}return{...t,options:a,tokens:n}},pushBound:(t,e,r)=>{let[,s,a]=e.match(o_),n=t.options.concat({name:s,value:a}),c=t.tokens.concat([{segmentIndex:r,type:\"option\",slice:[0,s.length],option:s},{segmentIndex:r,type:\"assign\",slice:[s.length,s.length+1]},{segmentIndex:r,type:\"value\",slice:[s.length+1,s.length+a.length+1]}]);return{...t,options:n,tokens:c}},pushPath:(t,e,r)=>{let s=t.path.concat(e),a=t.tokens.concat({segmentIndex:r,type:\"path\"});return{...t,path:s,tokens:a}},pushPositional:(t,e,r)=>{let s=t.positionals.concat({value:e,extra:!1}),a=t.tokens.concat({segmentIndex:r,type:\"positional\"});return{...t,positionals:s,tokens:a}},pushExtra:(t,e,r)=>{let s=t.positionals.concat({value:e,extra:!0}),a=t.tokens.concat({segmentIndex:r,type:\"positional\"});return{...t,positionals:s,tokens:a}},pushExtraNoLimits:(t,e,r)=>{let s=t.positionals.concat({value:e,extra:Hl}),a=t.tokens.concat({segmentIndex:r,type:\"positional\"});return{...t,positionals:s,tokens:a}},pushTrue:(t,e,r,s)=>{let a=t.options.concat({name:s,value:!0}),n=t.tokens.concat({segmentIndex:r,type:\"option\",option:s});return{...t,options:a,tokens:n}},pushFalse:(t,e,r,s)=>{let a=t.options.concat({name:s,value:!1}),n=t.tokens.concat({segmentIndex:r,type:\"option\",option:s});return{...t,options:a,tokens:n}},pushUndefined:(t,e,r,s)=>{let a=t.options.concat({name:e,value:void 0}),n=t.tokens.concat({segmentIndex:r,type:\"option\",option:e});return{...t,options:a,tokens:n}},pushStringValue:(t,e,r)=>{var s;let a=t.options[t.options.length-1],n=t.options.slice(),c=t.tokens.concat({segmentIndex:r,type:\"value\"});return a.value=((s=a.value)!==null&&s!==void 0?s:[]).concat([e]),{...t,options:n,tokens:c}},setStringValue:(t,e,r)=>{let s=t.options[t.options.length-1],a=t.options.slice(),n=t.tokens.concat({segmentIndex:r,type:\"value\"});return s.value=e,{...t,options:a,tokens:n}},inhibateOptions:t=>({...t,ignoreOptions:!0}),useHelp:(t,e,r,s)=>{let[,,a]=e.match(s_);return typeof a<\"u\"?{...t,options:[{name:\"-c\",value:String(s)},{name:\"-i\",value:a}]}:{...t,options:[{name:\"-c\",value:String(s)}]}},setError:(t,e,r,s)=>e===ei.EndOfInput||e===ei.EndOfPartialInput?{...t,errorMessage:`${s}.`}:{...t,errorMessage:`${s} (\"${e}\").`},setOptionArityError:(t,e)=>{let r=t.options[t.options.length-1];return{...t,errorMessage:`Not enough arguments to option ${r.name}.`}}},Hl=Symbol(),I_=class{constructor(e,r){this.allOptionNames=new Map,this.arity={leading:[],trailing:[],extra:[],proxy:!1},this.options=[],this.paths=[],this.cliIndex=e,this.cliOpts=r}addPath(e){this.paths.push(e)}setArity({leading:e=this.arity.leading,trailing:r=this.arity.trailing,extra:s=this.arity.extra,proxy:a=this.arity.proxy}){Object.assign(this.arity,{leading:e,trailing:r,extra:s,proxy:a})}addPositional({name:e=\"arg\",required:r=!0}={}){if(!r&&this.arity.extra===Hl)throw new Error(\"Optional parameters cannot be declared when using .rest() or .proxy()\");if(!r&&this.arity.trailing.length>0)throw new Error(\"Optional parameters cannot be declared after the required trailing positional arguments\");!r&&this.arity.extra!==Hl?this.arity.extra.push(e):this.arity.extra!==Hl&&this.arity.extra.length===0?this.arity.leading.push(e):this.arity.trailing.push(e)}addRest({name:e=\"arg\",required:r=0}={}){if(this.arity.extra===Hl)throw new Error(\"Infinite lists cannot be declared multiple times in the same command\");if(this.arity.trailing.length>0)throw new Error(\"Infinite lists cannot be declared after the required trailing positional arguments\");for(let s=0;s<r;++s)this.addPositional({name:e});this.arity.extra=Hl}addProxy({required:e=0}={}){this.addRest({required:e}),this.arity.proxy=!0}addOption({names:e,description:r,arity:s=0,hidden:a=!1,required:n=!1,allowBinding:c=!0}){if(!c&&s>1)throw new Error(\"The arity cannot be higher than 1 when the option only supports the --arg=value syntax\");if(!Number.isInteger(s))throw new Error(`The arity must be an integer, got ${s}`);if(s<0)throw new Error(`The arity must be positive, got ${s}`);let f=e.reduce((p,h)=>h.length>p.length?h:p,\"\");for(let p of e)this.allOptionNames.set(p,f);this.options.push({preferredName:f,nameSet:e,description:r,arity:s,hidden:a,required:n,allowBinding:c})}setContext(e){this.context=e}usage({detailed:e=!0,inlineOptions:r=!0}={}){let s=[this.cliOpts.binaryName],a=[];if(this.paths.length>0&&s.push(...this.paths[0]),e){for(let{preferredName:c,nameSet:f,arity:p,hidden:h,description:E,required:C}of this.options){if(h)continue;let S=[];for(let I=0;I<p;++I)S.push(` #${I}`);let b=`${f.join(\",\")}${S.join(\"\")}`;!r&&E?a.push({preferredName:c,nameSet:f,definition:b,description:E,required:C}):s.push(C?`<${b}>`:`[${b}]`)}s.push(...this.arity.leading.map(c=>`<${c}>`)),this.arity.extra===Hl?s.push(\"...\"):s.push(...this.arity.extra.map(c=>`[${c}]`)),s.push(...this.arity.trailing.map(c=>`<${c}>`))}return{usage:s.join(\" \"),options:a}}compile(){if(typeof this.context>\"u\")throw new Error(\"Assertion failed: No context attached\");let e=Fre(),r=En.InitialNode,s=this.usage().usage,a=this.options.filter(f=>f.required).map(f=>f.nameSet);r=Ou(e,_l()),Ia(e,En.InitialNode,ei.StartOfInput,r,[\"setCandidateState\",{candidateUsage:s,requiredOptions:a}]);let n=this.arity.proxy?\"always\":\"isNotOptionLike\",c=this.paths.length>0?this.paths:[[]];for(let f of c){let p=r;if(f.length>0){let S=Ou(e,_l());BE(e,p,S),this.registerOptions(e,S),p=S}for(let S=0;S<f.length;++S){let b=Ou(e,_l());Ia(e,p,f[S],b,\"pushPath\"),p=b}if(this.arity.leading.length>0||!this.arity.proxy){let S=Ou(e,_l());Hs(e,p,\"isHelp\",S,[\"useHelp\",this.cliIndex]),Hs(e,S,\"always\",S,\"pushExtra\"),Ia(e,S,ei.EndOfInput,En.SuccessNode,[\"setSelectedIndex\",Nd]),this.registerOptions(e,p)}this.arity.leading.length>0&&(Ia(e,p,ei.EndOfInput,En.ErrorNode,[\"setError\",\"Not enough positional arguments\"]),Ia(e,p,ei.EndOfPartialInput,En.SuccessNode,[\"setPartialIndex\",this.cliIndex]));let h=p;for(let S=0;S<this.arity.leading.length;++S){let b=Ou(e,_l());(!this.arity.proxy||S+1!==this.arity.leading.length)&&this.registerOptions(e,b),(this.arity.trailing.length>0||S+1!==this.arity.leading.length)&&(Ia(e,b,ei.EndOfInput,En.ErrorNode,[\"setError\",\"Not enough positional arguments\"]),Ia(e,b,ei.EndOfPartialInput,En.SuccessNode,[\"setPartialIndex\",this.cliIndex])),Hs(e,h,\"isNotOptionLike\",b,\"pushPositional\"),h=b}let E=h;if(this.arity.extra===Hl||this.arity.extra.length>0){let S=Ou(e,_l());if(BE(e,h,S),this.arity.extra===Hl){let b=Ou(e,_l());this.arity.proxy||this.registerOptions(e,b),Hs(e,h,n,b,\"pushExtraNoLimits\"),Hs(e,b,n,b,\"pushExtraNoLimits\"),BE(e,b,S)}else for(let b=0;b<this.arity.extra.length;++b){let I=Ou(e,_l());(!this.arity.proxy||b>0)&&this.registerOptions(e,I),Hs(e,E,n,I,\"pushExtra\"),BE(e,I,S),E=I}E=S}this.arity.trailing.length>0&&(Ia(e,E,ei.EndOfInput,En.ErrorNode,[\"setError\",\"Not enough positional arguments\"]),Ia(e,E,ei.EndOfPartialInput,En.SuccessNode,[\"setPartialIndex\",this.cliIndex]));let C=E;for(let S=0;S<this.arity.trailing.length;++S){let b=Ou(e,_l());this.arity.proxy||this.registerOptions(e,b),S+1<this.arity.trailing.length&&(Ia(e,b,ei.EndOfInput,En.ErrorNode,[\"setError\",\"Not enough positional arguments\"]),Ia(e,b,ei.EndOfPartialInput,En.SuccessNode,[\"setPartialIndex\",this.cliIndex])),Hs(e,C,\"isNotOptionLike\",b,\"pushPositional\"),C=b}Hs(e,C,n,En.ErrorNode,[\"setError\",\"Extraneous positional argument\"]),Ia(e,C,ei.EndOfInput,En.SuccessNode,[\"setSelectedIndex\",this.cliIndex]),Ia(e,C,ei.EndOfPartialInput,En.SuccessNode,[\"setSelectedIndex\",this.cliIndex])}return{machine:e,context:this.context}}registerOptions(e,r){Hs(e,r,[\"isOption\",\"--\"],r,\"inhibateOptions\"),Hs(e,r,[\"isBatchOption\",this.allOptionNames],r,[\"pushBatch\",this.allOptionNames]),Hs(e,r,[\"isBoundOption\",this.allOptionNames,this.options],r,\"pushBound\"),Hs(e,r,[\"isUnsupportedOption\",this.allOptionNames],En.ErrorNode,[\"setError\",\"Unsupported option name\"]),Hs(e,r,[\"isInvalidOption\"],En.ErrorNode,[\"setError\",\"Invalid option name\"]);for(let s of this.options)if(s.arity===0)for(let a of s.nameSet)Hs(e,r,[\"isOption\",a],r,[\"pushTrue\",s.preferredName]),a.startsWith(\"--\")&&!a.startsWith(\"--no-\")&&Hs(e,r,[\"isNegatedOption\",a],r,[\"pushFalse\",s.preferredName]);else{let a=Ou(e,_l());for(let n of s.nameSet)Hs(e,r,[\"isOption\",n],a,[\"pushUndefined\",s.preferredName]);for(let n=0;n<s.arity;++n){let c=Ou(e,_l());Ia(e,a,ei.EndOfInput,En.ErrorNode,\"setOptionArityError\"),Ia(e,a,ei.EndOfPartialInput,En.ErrorNode,\"setOptionArityError\"),Hs(e,a,\"isOptionLike\",En.ErrorNode,\"setOptionArityError\");let f=s.arity===1?\"setStringValue\":\"pushStringValue\";Hs(e,a,\"isNotOptionLike\",c,f),a=c}BE(e,a,r)}}},Lx=class t{constructor({binaryName:e=\"...\"}={}){this.builders=[],this.opts={binaryName:e}}static build(e,r={}){return new t(r).commands(e).compile()}getBuilderByIndex(e){if(!(e>=0&&e<this.builders.length))throw new Error(`Assertion failed: Out-of-bound command index (${e})`);return this.builders[e]}commands(e){for(let r of e)r(this.command());return this}command(){let e=new I_(this.builders.length,this.opts);return this.builders.push(e),e}compile(){let e=[],r=[];for(let a of this.builders){let{machine:n,context:c}=a.compile();e.push(n),r.push(c)}let s=fYe(e);return AYe(s),{machine:s,contexts:r,process:(a,{partial:n}={})=>{let c=n?ei.EndOfPartialInput:ei.EndOfInput;return gYe(s,a,{endToken:c})}}}}});function Mre(){return Ux.default&&\"getColorDepth\"in Ux.default.WriteStream.prototype?Ux.default.WriteStream.prototype.getColorDepth():process.env.FORCE_COLOR===\"0\"?1:process.env.FORCE_COLOR===\"1\"||typeof process.stdout<\"u\"&&process.stdout.isTTY?8:1}function Ure(t){let e=Lre;if(typeof e>\"u\"){if(t.stdout===process.stdout&&t.stderr===process.stderr)return null;let{AsyncLocalStorage:r}=Ie(\"async_hooks\");e=Lre=new r;let s=process.stdout._write;process.stdout._write=function(n,c,f){let p=e.getStore();return typeof p>\"u\"?s.call(this,n,c,f):p.stdout.write(n,c,f)};let a=process.stderr._write;process.stderr._write=function(n,c,f){let p=e.getStore();return typeof p>\"u\"?a.call(this,n,c,f):p.stderr.write(n,c,f)}}return r=>e.run(t,r)}var Ux,Lre,_re=Ze(()=>{Ux=ut(Ie(\"tty\"),1)});var _x,Hre=Ze(()=>{a0();_x=class t extends ot{constructor(e){super(),this.contexts=e,this.commands=[]}static from(e,r){let s=new t(r);s.path=e.path;for(let a of e.options)switch(a.name){case\"-c\":s.commands.push(Number(a.value));break;case\"-i\":s.index=Number(a.value);break}return s}async execute(){let e=this.commands;if(typeof this.index<\"u\"&&this.index>=0&&this.index<e.length&&(e=[e[this.index]]),e.length===0)this.context.stdout.write(this.cli.usage());else if(e.length===1)this.context.stdout.write(this.cli.usage(this.contexts[e[0]].commandClass,{detailed:!0}));else if(e.length>1){this.context.stdout.write(`Multiple commands match your selection:\n`),this.context.stdout.write(`\n`);let r=0;for(let s of this.commands)this.context.stdout.write(this.cli.usage(this.contexts[s].commandClass,{prefix:`${r++}. `.padStart(5)}));this.context.stdout.write(`\n`),this.context.stdout.write(`Run again with -h=<index> to see the longer details of any of those commands.\n`)}}}});async function qre(...t){let{resolvedOptions:e,resolvedCommandClasses:r,resolvedArgv:s,resolvedContext:a}=Yre(t);return Ca.from(r,e).runExit(s,a)}async function Wre(...t){let{resolvedOptions:e,resolvedCommandClasses:r,resolvedArgv:s,resolvedContext:a}=Yre(t);return Ca.from(r,e).run(s,a)}function Yre(t){let e,r,s,a;switch(typeof process<\"u\"&&typeof process.argv<\"u\"&&(s=process.argv.slice(2)),t.length){case 1:r=t[0];break;case 2:t[0]&&t[0].prototype instanceof ot||Array.isArray(t[0])?(r=t[0],Array.isArray(t[1])?s=t[1]:a=t[1]):(e=t[0],r=t[1]);break;case 3:Array.isArray(t[2])?(e=t[0],r=t[1],s=t[2]):t[0]&&t[0].prototype instanceof ot||Array.isArray(t[0])?(r=t[0],s=t[1],a=t[2]):(e=t[0],r=t[1],a=t[2]);break;default:e=t[0],r=t[1],s=t[2],a=t[3];break}if(typeof s>\"u\")throw new Error(\"The argv parameter must be provided when running Clipanion outside of a Node context\");return{resolvedOptions:e,resolvedCommandClasses:r,resolvedArgv:s,resolvedContext:a}}function Gre(t){return t()}var jre,Ca,Vre=Ze(()=>{bx();Mx();u_();_re();a0();Hre();jre=Symbol(\"clipanion/errorCommand\");Ca=class t{constructor({binaryLabel:e,binaryName:r=\"...\",binaryVersion:s,enableCapture:a=!1,enableColors:n}={}){this.registrations=new Map,this.builder=new Lx({binaryName:r}),this.binaryLabel=e,this.binaryName=r,this.binaryVersion=s,this.enableCapture=a,this.enableColors=n}static from(e,r={}){let s=new t(r),a=Array.isArray(e)?e:[e];for(let n of a)s.register(n);return s}register(e){var r;let s=new Map,a=new e;for(let p in a){let h=a[p];typeof h==\"object\"&&h!==null&&h[ot.isOption]&&s.set(p,h)}let n=this.builder.command(),c=n.cliIndex,f=(r=e.paths)!==null&&r!==void 0?r:a.paths;if(typeof f<\"u\")for(let p of f)n.addPath(p);this.registrations.set(e,{specs:s,builder:n,index:c});for(let[p,{definition:h}]of s.entries())h(n,p);n.setContext({commandClass:e})}process(e,r){let{input:s,context:a,partial:n}=typeof e==\"object\"&&Array.isArray(e)?{input:e,context:r}:e,{contexts:c,process:f}=this.builder.compile(),p=f(s,{partial:n}),h={...t.defaultContext,...a};switch(p.selectedIndex){case Nd:{let E=_x.from(p,c);return E.context=h,E.tokens=p.tokens,E}default:{let{commandClass:E}=c[p.selectedIndex],C=this.registrations.get(E);if(typeof C>\"u\")throw new Error(\"Assertion failed: Expected the command class to have been registered.\");let S=new E;S.context=h,S.tokens=p.tokens,S.path=p.path;try{for(let[b,{transformer:I}]of C.specs.entries())S[b]=I(C.builder,b,p,h);return S}catch(b){throw b[jre]=S,b}}break}}async run(e,r){var s,a;let n,c={...t.defaultContext,...r},f=(s=this.enableColors)!==null&&s!==void 0?s:c.colorDepth>1;if(!Array.isArray(e))n=e;else try{n=this.process(e,c)}catch(E){return c.stdout.write(this.error(E,{colored:f})),1}if(n.help)return c.stdout.write(this.usage(n,{colored:f,detailed:!0})),0;n.context=c,n.cli={binaryLabel:this.binaryLabel,binaryName:this.binaryName,binaryVersion:this.binaryVersion,enableCapture:this.enableCapture,enableColors:this.enableColors,definitions:()=>this.definitions(),definition:E=>this.definition(E),error:(E,C)=>this.error(E,C),format:E=>this.format(E),process:(E,C)=>this.process(E,{...c,...C}),run:(E,C)=>this.run(E,{...c,...C}),usage:(E,C)=>this.usage(E,C)};let p=this.enableCapture&&(a=Ure(c))!==null&&a!==void 0?a:Gre,h;try{h=await p(()=>n.validateAndExecute().catch(E=>n.catch(E).then(()=>0)))}catch(E){return c.stdout.write(this.error(E,{colored:f,command:n})),1}return h}async runExit(e,r){process.exitCode=await this.run(e,r)}definition(e,{colored:r=!1}={}){if(!e.usage)return null;let{usage:s}=this.getUsageByRegistration(e,{detailed:!1}),{usage:a,options:n}=this.getUsageByRegistration(e,{detailed:!0,inlineOptions:!1}),c=typeof e.usage.category<\"u\"?Ho(e.usage.category,{format:this.format(r),paragraphs:!1}):void 0,f=typeof e.usage.description<\"u\"?Ho(e.usage.description,{format:this.format(r),paragraphs:!1}):void 0,p=typeof e.usage.details<\"u\"?Ho(e.usage.details,{format:this.format(r),paragraphs:!0}):void 0,h=typeof e.usage.examples<\"u\"?e.usage.examples.map(([E,C])=>[Ho(E,{format:this.format(r),paragraphs:!1}),C.replace(/\\$0/g,this.binaryName)]):void 0;return{path:s,usage:a,category:c,description:f,details:p,examples:h,options:n}}definitions({colored:e=!1}={}){let r=[];for(let s of this.registrations.keys()){let a=this.definition(s,{colored:e});a&&r.push(a)}return r}usage(e=null,{colored:r,detailed:s=!1,prefix:a=\"$ \"}={}){var n;if(e===null){for(let p of this.registrations.keys()){let h=p.paths,E=typeof p.usage<\"u\";if(!h||h.length===0||h.length===1&&h[0].length===0||((n=h?.some(b=>b.length===0))!==null&&n!==void 0?n:!1))if(e){e=null;break}else e=p;else if(E){e=null;continue}}e&&(s=!0)}let c=e!==null&&e instanceof ot?e.constructor:e,f=\"\";if(c)if(s){let{description:p=\"\",details:h=\"\",examples:E=[]}=c.usage||{};p!==\"\"&&(f+=Ho(p,{format:this.format(r),paragraphs:!1}).replace(/^./,b=>b.toUpperCase()),f+=`\n`),(h!==\"\"||E.length>0)&&(f+=`${this.format(r).header(\"Usage\")}\n`,f+=`\n`);let{usage:C,options:S}=this.getUsageByRegistration(c,{inlineOptions:!1});if(f+=`${this.format(r).bold(a)}${C}\n`,S.length>0){f+=`\n`,f+=`${this.format(r).header(\"Options\")}\n`;let b=S.reduce((I,T)=>Math.max(I,T.definition.length),0);f+=`\n`;for(let{definition:I,description:T}of S)f+=`  ${this.format(r).bold(I.padEnd(b))}    ${Ho(T,{format:this.format(r),paragraphs:!1})}`}if(h!==\"\"&&(f+=`\n`,f+=`${this.format(r).header(\"Details\")}\n`,f+=`\n`,f+=Ho(h,{format:this.format(r),paragraphs:!0})),E.length>0){f+=`\n`,f+=`${this.format(r).header(\"Examples\")}\n`;for(let[b,I]of E)f+=`\n`,f+=Ho(b,{format:this.format(r),paragraphs:!1}),f+=`${I.replace(/^/m,`  ${this.format(r).bold(a)}`).replace(/\\$0/g,this.binaryName)}\n`}}else{let{usage:p}=this.getUsageByRegistration(c);f+=`${this.format(r).bold(a)}${p}\n`}else{let p=new Map;for(let[S,{index:b}]of this.registrations.entries()){if(typeof S.usage>\"u\")continue;let I=typeof S.usage.category<\"u\"?Ho(S.usage.category,{format:this.format(r),paragraphs:!1}):null,T=p.get(I);typeof T>\"u\"&&p.set(I,T=[]);let{usage:N}=this.getUsageByIndex(b);T.push({commandClass:S,usage:N})}let h=Array.from(p.keys()).sort((S,b)=>S===null?-1:b===null?1:S.localeCompare(b,\"en\",{usage:\"sort\",caseFirst:\"upper\"})),E=typeof this.binaryLabel<\"u\",C=typeof this.binaryVersion<\"u\";E||C?(E&&C?f+=`${this.format(r).header(`${this.binaryLabel} - ${this.binaryVersion}`)}\n\n`:E?f+=`${this.format(r).header(`${this.binaryLabel}`)}\n`:f+=`${this.format(r).header(`${this.binaryVersion}`)}\n`,f+=`  ${this.format(r).bold(a)}${this.binaryName} <command>\n`):f+=`${this.format(r).bold(a)}${this.binaryName} <command>\n`;for(let S of h){let b=p.get(S).slice().sort((T,N)=>T.usage.localeCompare(N.usage,\"en\",{usage:\"sort\",caseFirst:\"upper\"})),I=S!==null?S.trim():\"General commands\";f+=`\n`,f+=`${this.format(r).header(`${I}`)}\n`;for(let{commandClass:T,usage:N}of b){let U=T.usage.description||\"undocumented\";f+=`\n`,f+=`  ${this.format(r).bold(N)}\n`,f+=`    ${Ho(U,{format:this.format(r),paragraphs:!1})}`}}f+=`\n`,f+=Ho(\"You can also print more details about any of these commands by calling them with the `-h,--help` flag right after the command name.\",{format:this.format(r),paragraphs:!0})}return f}error(e,r){var s,{colored:a,command:n=(s=e[jre])!==null&&s!==void 0?s:null}=r===void 0?{}:r;(!e||typeof e!=\"object\"||!(\"stack\"in e))&&(e=new Error(`Execution failed with a non-error rejection (rejected value: ${JSON.stringify(e)})`));let c=\"\",f=e.name.replace(/([a-z])([A-Z])/g,\"$1 $2\");f===\"Error\"&&(f=\"Internal Error\"),c+=`${this.format(a).error(f)}: ${e.message}\n`;let p=e.clipanion;return typeof p<\"u\"?p.type===\"usage\"&&(c+=`\n`,c+=this.usage(n)):e.stack&&(c+=`${e.stack.replace(/^.*\\n/,\"\")}\n`),c}format(e){var r;return((r=e??this.enableColors)!==null&&r!==void 0?r:t.defaultContext.colorDepth>1)?Dre:Pre}getUsageByRegistration(e,r){let s=this.registrations.get(e);if(typeof s>\"u\")throw new Error(\"Assertion failed: Unregistered command\");return this.getUsageByIndex(s.index,r)}getUsageByIndex(e,r){return this.builder.getBuilderByIndex(e).usage(r)}};Ca.defaultContext={env:process.env,stdin:process.stdin,stdout:process.stdout,stderr:process.stderr,colorDepth:Mre()}});var rB,Jre=Ze(()=>{a0();rB=class extends ot{async execute(){this.context.stdout.write(`${JSON.stringify(this.cli.definitions(),null,2)}\n`)}};rB.paths=[[\"--clipanion=definitions\"]]});var nB,Kre=Ze(()=>{a0();nB=class extends ot{async execute(){this.context.stdout.write(this.cli.usage())}};nB.paths=[[\"-h\"],[\"--help\"]]});function Hx(t={}){return ya({definition(e,r){var s;e.addProxy({name:(s=t.name)!==null&&s!==void 0?s:r,required:t.required})},transformer(e,r,s){return s.positionals.map(({value:a})=>a)}})}var C_=Ze(()=>{Cp()});var iB,zre=Ze(()=>{a0();C_();iB=class extends ot{constructor(){super(...arguments),this.args=Hx()}async execute(){this.context.stdout.write(`${JSON.stringify(this.cli.process(this.args).tokens,null,2)}\n`)}};iB.paths=[[\"--clipanion=tokens\"]]});var sB,Zre=Ze(()=>{a0();sB=class extends ot{async execute(){var e;this.context.stdout.write(`${(e=this.cli.binaryVersion)!==null&&e!==void 0?e:\"<unknown>\"}\n`)}};sB.paths=[[\"-v\"],[\"--version\"]]});var w_={};Vt(w_,{DefinitionsCommand:()=>rB,HelpCommand:()=>nB,TokensCommand:()=>iB,VersionCommand:()=>sB});var Xre=Ze(()=>{Jre();Kre();zre();Zre()});function $re(t,e,r){let[s,a]=Gf(e,r??{}),{arity:n=1}=a,c=t.split(\",\"),f=new Set(c);return ya({definition(p){p.addOption({names:c,arity:n,hidden:a?.hidden,description:a?.description,required:a.required})},transformer(p,h,E){let C,S=typeof s<\"u\"?[...s]:void 0;for(let{name:b,value:I}of E.options)f.has(b)&&(C=b,S=S??[],S.push(I));return typeof S<\"u\"?Od(C??h,S,a.validator):S}})}var ene=Ze(()=>{Cp()});function tne(t,e,r){let[s,a]=Gf(e,r??{}),n=t.split(\",\"),c=new Set(n);return ya({definition(f){f.addOption({names:n,allowBinding:!1,arity:0,hidden:a.hidden,description:a.description,required:a.required})},transformer(f,p,h){let E=s;for(let{name:C,value:S}of h.options)c.has(C)&&(E=S);return E}})}var rne=Ze(()=>{Cp()});function nne(t,e,r){let[s,a]=Gf(e,r??{}),n=t.split(\",\"),c=new Set(n);return ya({definition(f){f.addOption({names:n,allowBinding:!1,arity:0,hidden:a.hidden,description:a.description,required:a.required})},transformer(f,p,h){let E=s;for(let{name:C,value:S}of h.options)c.has(C)&&(E??(E=0),S?E+=1:E=0);return E}})}var ine=Ze(()=>{Cp()});function sne(t={}){return ya({definition(e,r){var s;e.addRest({name:(s=t.name)!==null&&s!==void 0?s:r,required:t.required})},transformer(e,r,s){let a=c=>{let f=s.positionals[c];return f.extra===Hl||f.extra===!1&&c<e.arity.leading.length},n=0;for(;n<s.positionals.length&&a(n);)n+=1;return s.positionals.splice(0,n).map(({value:c})=>c)}})}var one=Ze(()=>{Mx();Cp()});function CYe(t,e,r){let[s,a]=Gf(e,r??{}),{arity:n=1}=a,c=t.split(\",\"),f=new Set(c);return ya({definition(p){p.addOption({names:c,arity:a.tolerateBoolean?0:n,hidden:a.hidden,description:a.description,required:a.required})},transformer(p,h,E,C){let S,b=s;typeof a.env<\"u\"&&C.env[a.env]&&(S=a.env,b=C.env[a.env]);for(let{name:I,value:T}of E.options)f.has(I)&&(S=I,b=T);return typeof b==\"string\"?Od(S??h,b,a.validator):b}})}function wYe(t={}){let{required:e=!0}=t;return ya({definition(r,s){var a;r.addPositional({name:(a=t.name)!==null&&a!==void 0?a:s,required:t.required})},transformer(r,s,a){var n;for(let c=0;c<a.positionals.length;++c){if(a.positionals[c].extra===Hl||e&&a.positionals[c].extra===!0||!e&&a.positionals[c].extra===!1)continue;let[f]=a.positionals.splice(c,1);return Od((n=t.name)!==null&&n!==void 0?n:s,f.value,t.validator)}}})}function ane(t,...e){return typeof t==\"string\"?CYe(t,...e):wYe(t)}var lne=Ze(()=>{Mx();Cp()});var ge={};Vt(ge,{Array:()=>$re,Boolean:()=>tne,Counter:()=>nne,Proxy:()=>Hx,Rest:()=>sne,String:()=>ane,applyValidator:()=>Od,cleanValidationError:()=>Qx,formatError:()=>z2,isOptionSymbol:()=>K2,makeCommandOption:()=>ya,rerouteArguments:()=>Gf});var cne=Ze(()=>{Cp();C_();ene();rne();ine();one();lne()});var oB={};Vt(oB,{Builtins:()=>w_,Cli:()=>Ca,Command:()=>ot,Option:()=>ge,UsageError:()=>nt,formatMarkdownish:()=>Ho,run:()=>Wre,runExit:()=>qre});var Yt=Ze(()=>{kx();u_();a0();Vre();Xre();cne()});var une=_((MRt,BYe)=>{BYe.exports={name:\"dotenv\",version:\"16.3.1\",description:\"Loads environment variables from .env file\",main:\"lib/main.js\",types:\"lib/main.d.ts\",exports:{\".\":{types:\"./lib/main.d.ts\",require:\"./lib/main.js\",default:\"./lib/main.js\"},\"./config\":\"./config.js\",\"./config.js\":\"./config.js\",\"./lib/env-options\":\"./lib/env-options.js\",\"./lib/env-options.js\":\"./lib/env-options.js\",\"./lib/cli-options\":\"./lib/cli-options.js\",\"./lib/cli-options.js\":\"./lib/cli-options.js\",\"./package.json\":\"./package.json\"},scripts:{\"dts-check\":\"tsc --project tests/types/tsconfig.json\",lint:\"standard\",\"lint-readme\":\"standard-markdown\",pretest:\"npm run lint && npm run dts-check\",test:\"tap tests/*.js --100 -Rspec\",prerelease:\"npm test\",release:\"standard-version\"},repository:{type:\"git\",url:\"git://github.com/motdotla/dotenv.git\"},funding:\"https://github.com/motdotla/dotenv?sponsor=1\",keywords:[\"dotenv\",\"env\",\".env\",\"environment\",\"variables\",\"config\",\"settings\"],readmeFilename:\"README.md\",license:\"BSD-2-Clause\",devDependencies:{\"@definitelytyped/dtslint\":\"^0.0.133\",\"@types/node\":\"^18.11.3\",decache:\"^4.6.1\",sinon:\"^14.0.1\",standard:\"^17.0.0\",\"standard-markdown\":\"^7.1.0\",\"standard-version\":\"^9.5.0\",tap:\"^16.3.0\",tar:\"^6.1.11\",typescript:\"^4.8.4\"},engines:{node:\">=12\"},browser:{fs:!1}}});var hne=_((URt,wp)=>{var fne=Ie(\"fs\"),v_=Ie(\"path\"),vYe=Ie(\"os\"),SYe=Ie(\"crypto\"),DYe=une(),S_=DYe.version,PYe=/(?:^|^)\\s*(?:export\\s+)?([\\w.-]+)(?:\\s*=\\s*?|:\\s+?)(\\s*'(?:\\\\'|[^'])*'|\\s*\"(?:\\\\\"|[^\"])*\"|\\s*`(?:\\\\`|[^`])*`|[^#\\r\\n]+)?\\s*(?:#.*)?(?:$|$)/mg;function bYe(t){let e={},r=t.toString();r=r.replace(/\\r\\n?/mg,`\n`);let s;for(;(s=PYe.exec(r))!=null;){let a=s[1],n=s[2]||\"\";n=n.trim();let c=n[0];n=n.replace(/^(['\"`])([\\s\\S]*)\\1$/mg,\"$2\"),c==='\"'&&(n=n.replace(/\\\\n/g,`\n`),n=n.replace(/\\\\r/g,\"\\r\")),e[a]=n}return e}function xYe(t){let e=pne(t),r=js.configDotenv({path:e});if(!r.parsed)throw new Error(`MISSING_DATA: Cannot parse ${e} for an unknown reason`);let s=Ane(t).split(\",\"),a=s.length,n;for(let c=0;c<a;c++)try{let f=s[c].trim(),p=RYe(r,f);n=js.decrypt(p.ciphertext,p.key);break}catch(f){if(c+1>=a)throw f}return js.parse(n)}function kYe(t){console.log(`[dotenv@${S_}][INFO] ${t}`)}function QYe(t){console.log(`[dotenv@${S_}][WARN] ${t}`)}function B_(t){console.log(`[dotenv@${S_}][DEBUG] ${t}`)}function Ane(t){return t&&t.DOTENV_KEY&&t.DOTENV_KEY.length>0?t.DOTENV_KEY:process.env.DOTENV_KEY&&process.env.DOTENV_KEY.length>0?process.env.DOTENV_KEY:\"\"}function RYe(t,e){let r;try{r=new URL(e)}catch(f){throw f.code===\"ERR_INVALID_URL\"?new Error(\"INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenv.org/vault/.env.vault?environment=development\"):f}let s=r.password;if(!s)throw new Error(\"INVALID_DOTENV_KEY: Missing key part\");let a=r.searchParams.get(\"environment\");if(!a)throw new Error(\"INVALID_DOTENV_KEY: Missing environment part\");let n=`DOTENV_VAULT_${a.toUpperCase()}`,c=t.parsed[n];if(!c)throw new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${n} in your .env.vault file.`);return{ciphertext:c,key:s}}function pne(t){let e=v_.resolve(process.cwd(),\".env\");return t&&t.path&&t.path.length>0&&(e=t.path),e.endsWith(\".vault\")?e:`${e}.vault`}function TYe(t){return t[0]===\"~\"?v_.join(vYe.homedir(),t.slice(1)):t}function FYe(t){kYe(\"Loading env from encrypted .env.vault\");let e=js._parseVault(t),r=process.env;return t&&t.processEnv!=null&&(r=t.processEnv),js.populate(r,e,t),{parsed:e}}function NYe(t){let e=v_.resolve(process.cwd(),\".env\"),r=\"utf8\",s=!!(t&&t.debug);t&&(t.path!=null&&(e=TYe(t.path)),t.encoding!=null&&(r=t.encoding));try{let a=js.parse(fne.readFileSync(e,{encoding:r})),n=process.env;return t&&t.processEnv!=null&&(n=t.processEnv),js.populate(n,a,t),{parsed:a}}catch(a){return s&&B_(`Failed to load ${e} ${a.message}`),{error:a}}}function OYe(t){let e=pne(t);return Ane(t).length===0?js.configDotenv(t):fne.existsSync(e)?js._configVault(t):(QYe(`You set DOTENV_KEY but you are missing a .env.vault file at ${e}. Did you forget to build it?`),js.configDotenv(t))}function LYe(t,e){let r=Buffer.from(e.slice(-64),\"hex\"),s=Buffer.from(t,\"base64\"),a=s.slice(0,12),n=s.slice(-16);s=s.slice(12,-16);try{let c=SYe.createDecipheriv(\"aes-256-gcm\",r,a);return c.setAuthTag(n),`${c.update(s)}${c.final()}`}catch(c){let f=c instanceof RangeError,p=c.message===\"Invalid key length\",h=c.message===\"Unsupported state or unable to authenticate data\";if(f||p){let E=\"INVALID_DOTENV_KEY: It must be 64 characters long (or more)\";throw new Error(E)}else if(h){let E=\"DECRYPTION_FAILED: Please check your DOTENV_KEY\";throw new Error(E)}else throw console.error(\"Error: \",c.code),console.error(\"Error: \",c.message),c}}function MYe(t,e,r={}){let s=!!(r&&r.debug),a=!!(r&&r.override);if(typeof e!=\"object\")throw new Error(\"OBJECT_REQUIRED: Please check the processEnv argument being passed to populate\");for(let n of Object.keys(e))Object.prototype.hasOwnProperty.call(t,n)?(a===!0&&(t[n]=e[n]),s&&B_(a===!0?`\"${n}\" is already defined and WAS overwritten`:`\"${n}\" is already defined and was NOT overwritten`)):t[n]=e[n]}var js={configDotenv:NYe,_configVault:FYe,_parseVault:xYe,config:OYe,decrypt:LYe,parse:bYe,populate:MYe};wp.exports.configDotenv=js.configDotenv;wp.exports._configVault=js._configVault;wp.exports._parseVault=js._parseVault;wp.exports.config=js.config;wp.exports.decrypt=js.decrypt;wp.exports.parse=js.parse;wp.exports.populate=js.populate;wp.exports=js});var dne=_((_Rt,gne)=>{\"use strict\";gne.exports=(t,...e)=>new Promise(r=>{r(t(...e))})});var Ld=_((HRt,D_)=>{\"use strict\";var UYe=dne(),mne=t=>{if(t<1)throw new TypeError(\"Expected `concurrency` to be a number from 1 and up\");let e=[],r=0,s=()=>{r--,e.length>0&&e.shift()()},a=(f,p,...h)=>{r++;let E=UYe(f,...h);p(E),E.then(s,s)},n=(f,p,...h)=>{r<t?a(f,p,...h):e.push(a.bind(null,f,p,...h))},c=(f,...p)=>new Promise(h=>n(f,h,...p));return Object.defineProperties(c,{activeCount:{get:()=>r},pendingCount:{get:()=>e.length}}),c};D_.exports=mne;D_.exports.default=mne});function Yf(t){return`YN${t.toString(10).padStart(4,\"0\")}`}function jx(t){let e=Number(t.slice(2));if(typeof Br[e]>\"u\")throw new Error(`Unknown message name: \"${t}\"`);return e}var Br,Gx=Ze(()=>{Br=(Me=>(Me[Me.UNNAMED=0]=\"UNNAMED\",Me[Me.EXCEPTION=1]=\"EXCEPTION\",Me[Me.MISSING_PEER_DEPENDENCY=2]=\"MISSING_PEER_DEPENDENCY\",Me[Me.CYCLIC_DEPENDENCIES=3]=\"CYCLIC_DEPENDENCIES\",Me[Me.DISABLED_BUILD_SCRIPTS=4]=\"DISABLED_BUILD_SCRIPTS\",Me[Me.BUILD_DISABLED=5]=\"BUILD_DISABLED\",Me[Me.SOFT_LINK_BUILD=6]=\"SOFT_LINK_BUILD\",Me[Me.MUST_BUILD=7]=\"MUST_BUILD\",Me[Me.MUST_REBUILD=8]=\"MUST_REBUILD\",Me[Me.BUILD_FAILED=9]=\"BUILD_FAILED\",Me[Me.RESOLVER_NOT_FOUND=10]=\"RESOLVER_NOT_FOUND\",Me[Me.FETCHER_NOT_FOUND=11]=\"FETCHER_NOT_FOUND\",Me[Me.LINKER_NOT_FOUND=12]=\"LINKER_NOT_FOUND\",Me[Me.FETCH_NOT_CACHED=13]=\"FETCH_NOT_CACHED\",Me[Me.YARN_IMPORT_FAILED=14]=\"YARN_IMPORT_FAILED\",Me[Me.REMOTE_INVALID=15]=\"REMOTE_INVALID\",Me[Me.REMOTE_NOT_FOUND=16]=\"REMOTE_NOT_FOUND\",Me[Me.RESOLUTION_PACK=17]=\"RESOLUTION_PACK\",Me[Me.CACHE_CHECKSUM_MISMATCH=18]=\"CACHE_CHECKSUM_MISMATCH\",Me[Me.UNUSED_CACHE_ENTRY=19]=\"UNUSED_CACHE_ENTRY\",Me[Me.MISSING_LOCKFILE_ENTRY=20]=\"MISSING_LOCKFILE_ENTRY\",Me[Me.WORKSPACE_NOT_FOUND=21]=\"WORKSPACE_NOT_FOUND\",Me[Me.TOO_MANY_MATCHING_WORKSPACES=22]=\"TOO_MANY_MATCHING_WORKSPACES\",Me[Me.CONSTRAINTS_MISSING_DEPENDENCY=23]=\"CONSTRAINTS_MISSING_DEPENDENCY\",Me[Me.CONSTRAINTS_INCOMPATIBLE_DEPENDENCY=24]=\"CONSTRAINTS_INCOMPATIBLE_DEPENDENCY\",Me[Me.CONSTRAINTS_EXTRANEOUS_DEPENDENCY=25]=\"CONSTRAINTS_EXTRANEOUS_DEPENDENCY\",Me[Me.CONSTRAINTS_INVALID_DEPENDENCY=26]=\"CONSTRAINTS_INVALID_DEPENDENCY\",Me[Me.CANT_SUGGEST_RESOLUTIONS=27]=\"CANT_SUGGEST_RESOLUTIONS\",Me[Me.FROZEN_LOCKFILE_EXCEPTION=28]=\"FROZEN_LOCKFILE_EXCEPTION\",Me[Me.CROSS_DRIVE_VIRTUAL_LOCAL=29]=\"CROSS_DRIVE_VIRTUAL_LOCAL\",Me[Me.FETCH_FAILED=30]=\"FETCH_FAILED\",Me[Me.DANGEROUS_NODE_MODULES=31]=\"DANGEROUS_NODE_MODULES\",Me[Me.NODE_GYP_INJECTED=32]=\"NODE_GYP_INJECTED\",Me[Me.AUTHENTICATION_NOT_FOUND=33]=\"AUTHENTICATION_NOT_FOUND\",Me[Me.INVALID_CONFIGURATION_KEY=34]=\"INVALID_CONFIGURATION_KEY\",Me[Me.NETWORK_ERROR=35]=\"NETWORK_ERROR\",Me[Me.LIFECYCLE_SCRIPT=36]=\"LIFECYCLE_SCRIPT\",Me[Me.CONSTRAINTS_MISSING_FIELD=37]=\"CONSTRAINTS_MISSING_FIELD\",Me[Me.CONSTRAINTS_INCOMPATIBLE_FIELD=38]=\"CONSTRAINTS_INCOMPATIBLE_FIELD\",Me[Me.CONSTRAINTS_EXTRANEOUS_FIELD=39]=\"CONSTRAINTS_EXTRANEOUS_FIELD\",Me[Me.CONSTRAINTS_INVALID_FIELD=40]=\"CONSTRAINTS_INVALID_FIELD\",Me[Me.AUTHENTICATION_INVALID=41]=\"AUTHENTICATION_INVALID\",Me[Me.PROLOG_UNKNOWN_ERROR=42]=\"PROLOG_UNKNOWN_ERROR\",Me[Me.PROLOG_SYNTAX_ERROR=43]=\"PROLOG_SYNTAX_ERROR\",Me[Me.PROLOG_EXISTENCE_ERROR=44]=\"PROLOG_EXISTENCE_ERROR\",Me[Me.STACK_OVERFLOW_RESOLUTION=45]=\"STACK_OVERFLOW_RESOLUTION\",Me[Me.AUTOMERGE_FAILED_TO_PARSE=46]=\"AUTOMERGE_FAILED_TO_PARSE\",Me[Me.AUTOMERGE_IMMUTABLE=47]=\"AUTOMERGE_IMMUTABLE\",Me[Me.AUTOMERGE_SUCCESS=48]=\"AUTOMERGE_SUCCESS\",Me[Me.AUTOMERGE_REQUIRED=49]=\"AUTOMERGE_REQUIRED\",Me[Me.DEPRECATED_CLI_SETTINGS=50]=\"DEPRECATED_CLI_SETTINGS\",Me[Me.PLUGIN_NAME_NOT_FOUND=51]=\"PLUGIN_NAME_NOT_FOUND\",Me[Me.INVALID_PLUGIN_REFERENCE=52]=\"INVALID_PLUGIN_REFERENCE\",Me[Me.CONSTRAINTS_AMBIGUITY=53]=\"CONSTRAINTS_AMBIGUITY\",Me[Me.CACHE_OUTSIDE_PROJECT=54]=\"CACHE_OUTSIDE_PROJECT\",Me[Me.IMMUTABLE_INSTALL=55]=\"IMMUTABLE_INSTALL\",Me[Me.IMMUTABLE_CACHE=56]=\"IMMUTABLE_CACHE\",Me[Me.INVALID_MANIFEST=57]=\"INVALID_MANIFEST\",Me[Me.PACKAGE_PREPARATION_FAILED=58]=\"PACKAGE_PREPARATION_FAILED\",Me[Me.INVALID_RANGE_PEER_DEPENDENCY=59]=\"INVALID_RANGE_PEER_DEPENDENCY\",Me[Me.INCOMPATIBLE_PEER_DEPENDENCY=60]=\"INCOMPATIBLE_PEER_DEPENDENCY\",Me[Me.DEPRECATED_PACKAGE=61]=\"DEPRECATED_PACKAGE\",Me[Me.INCOMPATIBLE_OS=62]=\"INCOMPATIBLE_OS\",Me[Me.INCOMPATIBLE_CPU=63]=\"INCOMPATIBLE_CPU\",Me[Me.FROZEN_ARTIFACT_EXCEPTION=64]=\"FROZEN_ARTIFACT_EXCEPTION\",Me[Me.TELEMETRY_NOTICE=65]=\"TELEMETRY_NOTICE\",Me[Me.PATCH_HUNK_FAILED=66]=\"PATCH_HUNK_FAILED\",Me[Me.INVALID_CONFIGURATION_VALUE=67]=\"INVALID_CONFIGURATION_VALUE\",Me[Me.UNUSED_PACKAGE_EXTENSION=68]=\"UNUSED_PACKAGE_EXTENSION\",Me[Me.REDUNDANT_PACKAGE_EXTENSION=69]=\"REDUNDANT_PACKAGE_EXTENSION\",Me[Me.AUTO_NM_SUCCESS=70]=\"AUTO_NM_SUCCESS\",Me[Me.NM_CANT_INSTALL_EXTERNAL_SOFT_LINK=71]=\"NM_CANT_INSTALL_EXTERNAL_SOFT_LINK\",Me[Me.NM_PRESERVE_SYMLINKS_REQUIRED=72]=\"NM_PRESERVE_SYMLINKS_REQUIRED\",Me[Me.UPDATE_LOCKFILE_ONLY_SKIP_LINK=73]=\"UPDATE_LOCKFILE_ONLY_SKIP_LINK\",Me[Me.NM_HARDLINKS_MODE_DOWNGRADED=74]=\"NM_HARDLINKS_MODE_DOWNGRADED\",Me[Me.PROLOG_INSTANTIATION_ERROR=75]=\"PROLOG_INSTANTIATION_ERROR\",Me[Me.INCOMPATIBLE_ARCHITECTURE=76]=\"INCOMPATIBLE_ARCHITECTURE\",Me[Me.GHOST_ARCHITECTURE=77]=\"GHOST_ARCHITECTURE\",Me[Me.RESOLUTION_MISMATCH=78]=\"RESOLUTION_MISMATCH\",Me[Me.PROLOG_LIMIT_EXCEEDED=79]=\"PROLOG_LIMIT_EXCEEDED\",Me[Me.NETWORK_DISABLED=80]=\"NETWORK_DISABLED\",Me[Me.NETWORK_UNSAFE_HTTP=81]=\"NETWORK_UNSAFE_HTTP\",Me[Me.RESOLUTION_FAILED=82]=\"RESOLUTION_FAILED\",Me[Me.AUTOMERGE_GIT_ERROR=83]=\"AUTOMERGE_GIT_ERROR\",Me[Me.CONSTRAINTS_CHECK_FAILED=84]=\"CONSTRAINTS_CHECK_FAILED\",Me[Me.UPDATED_RESOLUTION_RECORD=85]=\"UPDATED_RESOLUTION_RECORD\",Me[Me.EXPLAIN_PEER_DEPENDENCIES_CTA=86]=\"EXPLAIN_PEER_DEPENDENCIES_CTA\",Me[Me.MIGRATION_SUCCESS=87]=\"MIGRATION_SUCCESS\",Me[Me.VERSION_NOTICE=88]=\"VERSION_NOTICE\",Me[Me.TIPS_NOTICE=89]=\"TIPS_NOTICE\",Me[Me.OFFLINE_MODE_ENABLED=90]=\"OFFLINE_MODE_ENABLED\",Me[Me.INVALID_PROVENANCE_ENVIRONMENT=91]=\"INVALID_PROVENANCE_ENVIRONMENT\",Me))(Br||{})});var aB=_((GRt,yne)=>{var _Ye=\"2.0.0\",HYe=Number.MAX_SAFE_INTEGER||9007199254740991,jYe=16,GYe=250,qYe=[\"major\",\"premajor\",\"minor\",\"preminor\",\"patch\",\"prepatch\",\"prerelease\"];yne.exports={MAX_LENGTH:256,MAX_SAFE_COMPONENT_LENGTH:jYe,MAX_SAFE_BUILD_LENGTH:GYe,MAX_SAFE_INTEGER:HYe,RELEASE_TYPES:qYe,SEMVER_SPEC_VERSION:_Ye,FLAG_INCLUDE_PRERELEASE:1,FLAG_LOOSE:2}});var lB=_((qRt,Ene)=>{var WYe=typeof process==\"object\"&&process.env&&process.env.NODE_DEBUG&&/\\bsemver\\b/i.test(process.env.NODE_DEBUG)?(...t)=>console.error(\"SEMVER\",...t):()=>{};Ene.exports=WYe});var vE=_((Bp,Ine)=>{var{MAX_SAFE_COMPONENT_LENGTH:P_,MAX_SAFE_BUILD_LENGTH:YYe,MAX_LENGTH:VYe}=aB(),JYe=lB();Bp=Ine.exports={};var KYe=Bp.re=[],zYe=Bp.safeRe=[],rr=Bp.src=[],nr=Bp.t={},ZYe=0,b_=\"[a-zA-Z0-9-]\",XYe=[[\"\\\\s\",1],[\"\\\\d\",VYe],[b_,YYe]],$Ye=t=>{for(let[e,r]of XYe)t=t.split(`${e}*`).join(`${e}{0,${r}}`).split(`${e}+`).join(`${e}{1,${r}}`);return t},Jr=(t,e,r)=>{let s=$Ye(e),a=ZYe++;JYe(t,a,e),nr[t]=a,rr[a]=e,KYe[a]=new RegExp(e,r?\"g\":void 0),zYe[a]=new RegExp(s,r?\"g\":void 0)};Jr(\"NUMERICIDENTIFIER\",\"0|[1-9]\\\\d*\");Jr(\"NUMERICIDENTIFIERLOOSE\",\"\\\\d+\");Jr(\"NONNUMERICIDENTIFIER\",`\\\\d*[a-zA-Z-]${b_}*`);Jr(\"MAINVERSION\",`(${rr[nr.NUMERICIDENTIFIER]})\\\\.(${rr[nr.NUMERICIDENTIFIER]})\\\\.(${rr[nr.NUMERICIDENTIFIER]})`);Jr(\"MAINVERSIONLOOSE\",`(${rr[nr.NUMERICIDENTIFIERLOOSE]})\\\\.(${rr[nr.NUMERICIDENTIFIERLOOSE]})\\\\.(${rr[nr.NUMERICIDENTIFIERLOOSE]})`);Jr(\"PRERELEASEIDENTIFIER\",`(?:${rr[nr.NUMERICIDENTIFIER]}|${rr[nr.NONNUMERICIDENTIFIER]})`);Jr(\"PRERELEASEIDENTIFIERLOOSE\",`(?:${rr[nr.NUMERICIDENTIFIERLOOSE]}|${rr[nr.NONNUMERICIDENTIFIER]})`);Jr(\"PRERELEASE\",`(?:-(${rr[nr.PRERELEASEIDENTIFIER]}(?:\\\\.${rr[nr.PRERELEASEIDENTIFIER]})*))`);Jr(\"PRERELEASELOOSE\",`(?:-?(${rr[nr.PRERELEASEIDENTIFIERLOOSE]}(?:\\\\.${rr[nr.PRERELEASEIDENTIFIERLOOSE]})*))`);Jr(\"BUILDIDENTIFIER\",`${b_}+`);Jr(\"BUILD\",`(?:\\\\+(${rr[nr.BUILDIDENTIFIER]}(?:\\\\.${rr[nr.BUILDIDENTIFIER]})*))`);Jr(\"FULLPLAIN\",`v?${rr[nr.MAINVERSION]}${rr[nr.PRERELEASE]}?${rr[nr.BUILD]}?`);Jr(\"FULL\",`^${rr[nr.FULLPLAIN]}$`);Jr(\"LOOSEPLAIN\",`[v=\\\\s]*${rr[nr.MAINVERSIONLOOSE]}${rr[nr.PRERELEASELOOSE]}?${rr[nr.BUILD]}?`);Jr(\"LOOSE\",`^${rr[nr.LOOSEPLAIN]}$`);Jr(\"GTLT\",\"((?:<|>)?=?)\");Jr(\"XRANGEIDENTIFIERLOOSE\",`${rr[nr.NUMERICIDENTIFIERLOOSE]}|x|X|\\\\*`);Jr(\"XRANGEIDENTIFIER\",`${rr[nr.NUMERICIDENTIFIER]}|x|X|\\\\*`);Jr(\"XRANGEPLAIN\",`[v=\\\\s]*(${rr[nr.XRANGEIDENTIFIER]})(?:\\\\.(${rr[nr.XRANGEIDENTIFIER]})(?:\\\\.(${rr[nr.XRANGEIDENTIFIER]})(?:${rr[nr.PRERELEASE]})?${rr[nr.BUILD]}?)?)?`);Jr(\"XRANGEPLAINLOOSE\",`[v=\\\\s]*(${rr[nr.XRANGEIDENTIFIERLOOSE]})(?:\\\\.(${rr[nr.XRANGEIDENTIFIERLOOSE]})(?:\\\\.(${rr[nr.XRANGEIDENTIFIERLOOSE]})(?:${rr[nr.PRERELEASELOOSE]})?${rr[nr.BUILD]}?)?)?`);Jr(\"XRANGE\",`^${rr[nr.GTLT]}\\\\s*${rr[nr.XRANGEPLAIN]}$`);Jr(\"XRANGELOOSE\",`^${rr[nr.GTLT]}\\\\s*${rr[nr.XRANGEPLAINLOOSE]}$`);Jr(\"COERCEPLAIN\",`(^|[^\\\\d])(\\\\d{1,${P_}})(?:\\\\.(\\\\d{1,${P_}}))?(?:\\\\.(\\\\d{1,${P_}}))?`);Jr(\"COERCE\",`${rr[nr.COERCEPLAIN]}(?:$|[^\\\\d])`);Jr(\"COERCEFULL\",rr[nr.COERCEPLAIN]+`(?:${rr[nr.PRERELEASE]})?(?:${rr[nr.BUILD]})?(?:$|[^\\\\d])`);Jr(\"COERCERTL\",rr[nr.COERCE],!0);Jr(\"COERCERTLFULL\",rr[nr.COERCEFULL],!0);Jr(\"LONETILDE\",\"(?:~>?)\");Jr(\"TILDETRIM\",`(\\\\s*)${rr[nr.LONETILDE]}\\\\s+`,!0);Bp.tildeTrimReplace=\"$1~\";Jr(\"TILDE\",`^${rr[nr.LONETILDE]}${rr[nr.XRANGEPLAIN]}$`);Jr(\"TILDELOOSE\",`^${rr[nr.LONETILDE]}${rr[nr.XRANGEPLAINLOOSE]}$`);Jr(\"LONECARET\",\"(?:\\\\^)\");Jr(\"CARETTRIM\",`(\\\\s*)${rr[nr.LONECARET]}\\\\s+`,!0);Bp.caretTrimReplace=\"$1^\";Jr(\"CARET\",`^${rr[nr.LONECARET]}${rr[nr.XRANGEPLAIN]}$`);Jr(\"CARETLOOSE\",`^${rr[nr.LONECARET]}${rr[nr.XRANGEPLAINLOOSE]}$`);Jr(\"COMPARATORLOOSE\",`^${rr[nr.GTLT]}\\\\s*(${rr[nr.LOOSEPLAIN]})$|^$`);Jr(\"COMPARATOR\",`^${rr[nr.GTLT]}\\\\s*(${rr[nr.FULLPLAIN]})$|^$`);Jr(\"COMPARATORTRIM\",`(\\\\s*)${rr[nr.GTLT]}\\\\s*(${rr[nr.LOOSEPLAIN]}|${rr[nr.XRANGEPLAIN]})`,!0);Bp.comparatorTrimReplace=\"$1$2$3\";Jr(\"HYPHENRANGE\",`^\\\\s*(${rr[nr.XRANGEPLAIN]})\\\\s+-\\\\s+(${rr[nr.XRANGEPLAIN]})\\\\s*$`);Jr(\"HYPHENRANGELOOSE\",`^\\\\s*(${rr[nr.XRANGEPLAINLOOSE]})\\\\s+-\\\\s+(${rr[nr.XRANGEPLAINLOOSE]})\\\\s*$`);Jr(\"STAR\",\"(<|>)?=?\\\\s*\\\\*\");Jr(\"GTE0\",\"^\\\\s*>=\\\\s*0\\\\.0\\\\.0\\\\s*$\");Jr(\"GTE0PRE\",\"^\\\\s*>=\\\\s*0\\\\.0\\\\.0-0\\\\s*$\")});var qx=_((WRt,Cne)=>{var eVe=Object.freeze({loose:!0}),tVe=Object.freeze({}),rVe=t=>t?typeof t!=\"object\"?eVe:t:tVe;Cne.exports=rVe});var x_=_((YRt,vne)=>{var wne=/^[0-9]+$/,Bne=(t,e)=>{let r=wne.test(t),s=wne.test(e);return r&&s&&(t=+t,e=+e),t===e?0:r&&!s?-1:s&&!r?1:t<e?-1:1},nVe=(t,e)=>Bne(e,t);vne.exports={compareIdentifiers:Bne,rcompareIdentifiers:nVe}});var jo=_((VRt,bne)=>{var Wx=lB(),{MAX_LENGTH:Sne,MAX_SAFE_INTEGER:Yx}=aB(),{safeRe:Dne,t:Pne}=vE(),iVe=qx(),{compareIdentifiers:SE}=x_(),k_=class t{constructor(e,r){if(r=iVe(r),e instanceof t){if(e.loose===!!r.loose&&e.includePrerelease===!!r.includePrerelease)return e;e=e.version}else if(typeof e!=\"string\")throw new TypeError(`Invalid version. Must be a string. Got type \"${typeof e}\".`);if(e.length>Sne)throw new TypeError(`version is longer than ${Sne} characters`);Wx(\"SemVer\",e,r),this.options=r,this.loose=!!r.loose,this.includePrerelease=!!r.includePrerelease;let s=e.trim().match(r.loose?Dne[Pne.LOOSE]:Dne[Pne.FULL]);if(!s)throw new TypeError(`Invalid Version: ${e}`);if(this.raw=e,this.major=+s[1],this.minor=+s[2],this.patch=+s[3],this.major>Yx||this.major<0)throw new TypeError(\"Invalid major version\");if(this.minor>Yx||this.minor<0)throw new TypeError(\"Invalid minor version\");if(this.patch>Yx||this.patch<0)throw new TypeError(\"Invalid patch version\");s[4]?this.prerelease=s[4].split(\".\").map(a=>{if(/^[0-9]+$/.test(a)){let n=+a;if(n>=0&&n<Yx)return n}return a}):this.prerelease=[],this.build=s[5]?s[5].split(\".\"):[],this.format()}format(){return this.version=`${this.major}.${this.minor}.${this.patch}`,this.prerelease.length&&(this.version+=`-${this.prerelease.join(\".\")}`),this.version}toString(){return this.version}compare(e){if(Wx(\"SemVer.compare\",this.version,this.options,e),!(e instanceof t)){if(typeof e==\"string\"&&e===this.version)return 0;e=new t(e,this.options)}return e.version===this.version?0:this.compareMain(e)||this.comparePre(e)}compareMain(e){return e instanceof t||(e=new t(e,this.options)),SE(this.major,e.major)||SE(this.minor,e.minor)||SE(this.patch,e.patch)}comparePre(e){if(e instanceof t||(e=new t(e,this.options)),this.prerelease.length&&!e.prerelease.length)return-1;if(!this.prerelease.length&&e.prerelease.length)return 1;if(!this.prerelease.length&&!e.prerelease.length)return 0;let r=0;do{let s=this.prerelease[r],a=e.prerelease[r];if(Wx(\"prerelease compare\",r,s,a),s===void 0&&a===void 0)return 0;if(a===void 0)return 1;if(s===void 0)return-1;if(s===a)continue;return SE(s,a)}while(++r)}compareBuild(e){e instanceof t||(e=new t(e,this.options));let r=0;do{let s=this.build[r],a=e.build[r];if(Wx(\"prerelease compare\",r,s,a),s===void 0&&a===void 0)return 0;if(a===void 0)return 1;if(s===void 0)return-1;if(s===a)continue;return SE(s,a)}while(++r)}inc(e,r,s){switch(e){case\"premajor\":this.prerelease.length=0,this.patch=0,this.minor=0,this.major++,this.inc(\"pre\",r,s);break;case\"preminor\":this.prerelease.length=0,this.patch=0,this.minor++,this.inc(\"pre\",r,s);break;case\"prepatch\":this.prerelease.length=0,this.inc(\"patch\",r,s),this.inc(\"pre\",r,s);break;case\"prerelease\":this.prerelease.length===0&&this.inc(\"patch\",r,s),this.inc(\"pre\",r,s);break;case\"major\":(this.minor!==0||this.patch!==0||this.prerelease.length===0)&&this.major++,this.minor=0,this.patch=0,this.prerelease=[];break;case\"minor\":(this.patch!==0||this.prerelease.length===0)&&this.minor++,this.patch=0,this.prerelease=[];break;case\"patch\":this.prerelease.length===0&&this.patch++,this.prerelease=[];break;case\"pre\":{let a=Number(s)?1:0;if(!r&&s===!1)throw new Error(\"invalid increment argument: identifier is empty\");if(this.prerelease.length===0)this.prerelease=[a];else{let n=this.prerelease.length;for(;--n>=0;)typeof this.prerelease[n]==\"number\"&&(this.prerelease[n]++,n=-2);if(n===-1){if(r===this.prerelease.join(\".\")&&s===!1)throw new Error(\"invalid increment argument: identifier already exists\");this.prerelease.push(a)}}if(r){let n=[r,a];s===!1&&(n=[r]),SE(this.prerelease[0],r)===0?isNaN(this.prerelease[1])&&(this.prerelease=n):this.prerelease=n}break}default:throw new Error(`invalid increment argument: ${e}`)}return this.raw=this.format(),this.build.length&&(this.raw+=`+${this.build.join(\".\")}`),this}};bne.exports=k_});var Md=_((JRt,kne)=>{var xne=jo(),sVe=(t,e,r=!1)=>{if(t instanceof xne)return t;try{return new xne(t,e)}catch(s){if(!r)return null;throw s}};kne.exports=sVe});var Rne=_((KRt,Qne)=>{var oVe=Md(),aVe=(t,e)=>{let r=oVe(t,e);return r?r.version:null};Qne.exports=aVe});var Fne=_((zRt,Tne)=>{var lVe=Md(),cVe=(t,e)=>{let r=lVe(t.trim().replace(/^[=v]+/,\"\"),e);return r?r.version:null};Tne.exports=cVe});var Lne=_((ZRt,One)=>{var Nne=jo(),uVe=(t,e,r,s,a)=>{typeof r==\"string\"&&(a=s,s=r,r=void 0);try{return new Nne(t instanceof Nne?t.version:t,r).inc(e,s,a).version}catch{return null}};One.exports=uVe});var _ne=_((XRt,Une)=>{var Mne=Md(),fVe=(t,e)=>{let r=Mne(t,null,!0),s=Mne(e,null,!0),a=r.compare(s);if(a===0)return null;let n=a>0,c=n?r:s,f=n?s:r,p=!!c.prerelease.length;if(!!f.prerelease.length&&!p)return!f.patch&&!f.minor?\"major\":c.patch?\"patch\":c.minor?\"minor\":\"major\";let E=p?\"pre\":\"\";return r.major!==s.major?E+\"major\":r.minor!==s.minor?E+\"minor\":r.patch!==s.patch?E+\"patch\":\"prerelease\"};Une.exports=fVe});var jne=_(($Rt,Hne)=>{var AVe=jo(),pVe=(t,e)=>new AVe(t,e).major;Hne.exports=pVe});var qne=_((eTt,Gne)=>{var hVe=jo(),gVe=(t,e)=>new hVe(t,e).minor;Gne.exports=gVe});var Yne=_((tTt,Wne)=>{var dVe=jo(),mVe=(t,e)=>new dVe(t,e).patch;Wne.exports=mVe});var Jne=_((rTt,Vne)=>{var yVe=Md(),EVe=(t,e)=>{let r=yVe(t,e);return r&&r.prerelease.length?r.prerelease:null};Vne.exports=EVe});var Bc=_((nTt,zne)=>{var Kne=jo(),IVe=(t,e,r)=>new Kne(t,r).compare(new Kne(e,r));zne.exports=IVe});var Xne=_((iTt,Zne)=>{var CVe=Bc(),wVe=(t,e,r)=>CVe(e,t,r);Zne.exports=wVe});var eie=_((sTt,$ne)=>{var BVe=Bc(),vVe=(t,e)=>BVe(t,e,!0);$ne.exports=vVe});var Vx=_((oTt,rie)=>{var tie=jo(),SVe=(t,e,r)=>{let s=new tie(t,r),a=new tie(e,r);return s.compare(a)||s.compareBuild(a)};rie.exports=SVe});var iie=_((aTt,nie)=>{var DVe=Vx(),PVe=(t,e)=>t.sort((r,s)=>DVe(r,s,e));nie.exports=PVe});var oie=_((lTt,sie)=>{var bVe=Vx(),xVe=(t,e)=>t.sort((r,s)=>bVe(s,r,e));sie.exports=xVe});var cB=_((cTt,aie)=>{var kVe=Bc(),QVe=(t,e,r)=>kVe(t,e,r)>0;aie.exports=QVe});var Jx=_((uTt,lie)=>{var RVe=Bc(),TVe=(t,e,r)=>RVe(t,e,r)<0;lie.exports=TVe});var Q_=_((fTt,cie)=>{var FVe=Bc(),NVe=(t,e,r)=>FVe(t,e,r)===0;cie.exports=NVe});var R_=_((ATt,uie)=>{var OVe=Bc(),LVe=(t,e,r)=>OVe(t,e,r)!==0;uie.exports=LVe});var Kx=_((pTt,fie)=>{var MVe=Bc(),UVe=(t,e,r)=>MVe(t,e,r)>=0;fie.exports=UVe});var zx=_((hTt,Aie)=>{var _Ve=Bc(),HVe=(t,e,r)=>_Ve(t,e,r)<=0;Aie.exports=HVe});var T_=_((gTt,pie)=>{var jVe=Q_(),GVe=R_(),qVe=cB(),WVe=Kx(),YVe=Jx(),VVe=zx(),JVe=(t,e,r,s)=>{switch(e){case\"===\":return typeof t==\"object\"&&(t=t.version),typeof r==\"object\"&&(r=r.version),t===r;case\"!==\":return typeof t==\"object\"&&(t=t.version),typeof r==\"object\"&&(r=r.version),t!==r;case\"\":case\"=\":case\"==\":return jVe(t,r,s);case\"!=\":return GVe(t,r,s);case\">\":return qVe(t,r,s);case\">=\":return WVe(t,r,s);case\"<\":return YVe(t,r,s);case\"<=\":return VVe(t,r,s);default:throw new TypeError(`Invalid operator: ${e}`)}};pie.exports=JVe});var gie=_((dTt,hie)=>{var KVe=jo(),zVe=Md(),{safeRe:Zx,t:Xx}=vE(),ZVe=(t,e)=>{if(t instanceof KVe)return t;if(typeof t==\"number\"&&(t=String(t)),typeof t!=\"string\")return null;e=e||{};let r=null;if(!e.rtl)r=t.match(e.includePrerelease?Zx[Xx.COERCEFULL]:Zx[Xx.COERCE]);else{let p=e.includePrerelease?Zx[Xx.COERCERTLFULL]:Zx[Xx.COERCERTL],h;for(;(h=p.exec(t))&&(!r||r.index+r[0].length!==t.length);)(!r||h.index+h[0].length!==r.index+r[0].length)&&(r=h),p.lastIndex=h.index+h[1].length+h[2].length;p.lastIndex=-1}if(r===null)return null;let s=r[2],a=r[3]||\"0\",n=r[4]||\"0\",c=e.includePrerelease&&r[5]?`-${r[5]}`:\"\",f=e.includePrerelease&&r[6]?`+${r[6]}`:\"\";return zVe(`${s}.${a}.${n}${c}${f}`,e)};hie.exports=ZVe});var mie=_((mTt,die)=>{\"use strict\";die.exports=function(t){t.prototype[Symbol.iterator]=function*(){for(let e=this.head;e;e=e.next)yield e.value}}});var $x=_((yTt,yie)=>{\"use strict\";yie.exports=Fn;Fn.Node=Ud;Fn.create=Fn;function Fn(t){var e=this;if(e instanceof Fn||(e=new Fn),e.tail=null,e.head=null,e.length=0,t&&typeof t.forEach==\"function\")t.forEach(function(a){e.push(a)});else if(arguments.length>0)for(var r=0,s=arguments.length;r<s;r++)e.push(arguments[r]);return e}Fn.prototype.removeNode=function(t){if(t.list!==this)throw new Error(\"removing node which does not belong to this list\");var e=t.next,r=t.prev;return e&&(e.prev=r),r&&(r.next=e),t===this.head&&(this.head=e),t===this.tail&&(this.tail=r),t.list.length--,t.next=null,t.prev=null,t.list=null,e};Fn.prototype.unshiftNode=function(t){if(t!==this.head){t.list&&t.list.removeNode(t);var e=this.head;t.list=this,t.next=e,e&&(e.prev=t),this.head=t,this.tail||(this.tail=t),this.length++}};Fn.prototype.pushNode=function(t){if(t!==this.tail){t.list&&t.list.removeNode(t);var e=this.tail;t.list=this,t.prev=e,e&&(e.next=t),this.tail=t,this.head||(this.head=t),this.length++}};Fn.prototype.push=function(){for(var t=0,e=arguments.length;t<e;t++)$Ve(this,arguments[t]);return this.length};Fn.prototype.unshift=function(){for(var t=0,e=arguments.length;t<e;t++)e7e(this,arguments[t]);return this.length};Fn.prototype.pop=function(){if(this.tail){var t=this.tail.value;return this.tail=this.tail.prev,this.tail?this.tail.next=null:this.head=null,this.length--,t}};Fn.prototype.shift=function(){if(this.head){var t=this.head.value;return this.head=this.head.next,this.head?this.head.prev=null:this.tail=null,this.length--,t}};Fn.prototype.forEach=function(t,e){e=e||this;for(var r=this.head,s=0;r!==null;s++)t.call(e,r.value,s,this),r=r.next};Fn.prototype.forEachReverse=function(t,e){e=e||this;for(var r=this.tail,s=this.length-1;r!==null;s--)t.call(e,r.value,s,this),r=r.prev};Fn.prototype.get=function(t){for(var e=0,r=this.head;r!==null&&e<t;e++)r=r.next;if(e===t&&r!==null)return r.value};Fn.prototype.getReverse=function(t){for(var e=0,r=this.tail;r!==null&&e<t;e++)r=r.prev;if(e===t&&r!==null)return r.value};Fn.prototype.map=function(t,e){e=e||this;for(var r=new Fn,s=this.head;s!==null;)r.push(t.call(e,s.value,this)),s=s.next;return r};Fn.prototype.mapReverse=function(t,e){e=e||this;for(var r=new Fn,s=this.tail;s!==null;)r.push(t.call(e,s.value,this)),s=s.prev;return r};Fn.prototype.reduce=function(t,e){var r,s=this.head;if(arguments.length>1)r=e;else if(this.head)s=this.head.next,r=this.head.value;else throw new TypeError(\"Reduce of empty list with no initial value\");for(var a=0;s!==null;a++)r=t(r,s.value,a),s=s.next;return r};Fn.prototype.reduceReverse=function(t,e){var r,s=this.tail;if(arguments.length>1)r=e;else if(this.tail)s=this.tail.prev,r=this.tail.value;else throw new TypeError(\"Reduce of empty list with no initial value\");for(var a=this.length-1;s!==null;a--)r=t(r,s.value,a),s=s.prev;return r};Fn.prototype.toArray=function(){for(var t=new Array(this.length),e=0,r=this.head;r!==null;e++)t[e]=r.value,r=r.next;return t};Fn.prototype.toArrayReverse=function(){for(var t=new Array(this.length),e=0,r=this.tail;r!==null;e++)t[e]=r.value,r=r.prev;return t};Fn.prototype.slice=function(t,e){e=e||this.length,e<0&&(e+=this.length),t=t||0,t<0&&(t+=this.length);var r=new Fn;if(e<t||e<0)return r;t<0&&(t=0),e>this.length&&(e=this.length);for(var s=0,a=this.head;a!==null&&s<t;s++)a=a.next;for(;a!==null&&s<e;s++,a=a.next)r.push(a.value);return r};Fn.prototype.sliceReverse=function(t,e){e=e||this.length,e<0&&(e+=this.length),t=t||0,t<0&&(t+=this.length);var r=new Fn;if(e<t||e<0)return r;t<0&&(t=0),e>this.length&&(e=this.length);for(var s=this.length,a=this.tail;a!==null&&s>e;s--)a=a.prev;for(;a!==null&&s>t;s--,a=a.prev)r.push(a.value);return r};Fn.prototype.splice=function(t,e,...r){t>this.length&&(t=this.length-1),t<0&&(t=this.length+t);for(var s=0,a=this.head;a!==null&&s<t;s++)a=a.next;for(var n=[],s=0;a&&s<e;s++)n.push(a.value),a=this.removeNode(a);a===null&&(a=this.tail),a!==this.head&&a!==this.tail&&(a=a.prev);for(var s=0;s<r.length;s++)a=XVe(this,a,r[s]);return n};Fn.prototype.reverse=function(){for(var t=this.head,e=this.tail,r=t;r!==null;r=r.prev){var s=r.prev;r.prev=r.next,r.next=s}return this.head=e,this.tail=t,this};function XVe(t,e,r){var s=e===t.head?new Ud(r,null,e,t):new Ud(r,e,e.next,t);return s.next===null&&(t.tail=s),s.prev===null&&(t.head=s),t.length++,s}function $Ve(t,e){t.tail=new Ud(e,t.tail,null,t),t.head||(t.head=t.tail),t.length++}function e7e(t,e){t.head=new Ud(e,null,t.head,t),t.tail||(t.tail=t.head),t.length++}function Ud(t,e,r,s){if(!(this instanceof Ud))return new Ud(t,e,r,s);this.list=s,this.value=t,e?(e.next=this,this.prev=e):this.prev=null,r?(r.prev=this,this.next=r):this.next=null}try{mie()(Fn)}catch{}});var Bie=_((ETt,wie)=>{\"use strict\";var t7e=$x(),_d=Symbol(\"max\"),Sp=Symbol(\"length\"),DE=Symbol(\"lengthCalculator\"),fB=Symbol(\"allowStale\"),Hd=Symbol(\"maxAge\"),vp=Symbol(\"dispose\"),Eie=Symbol(\"noDisposeOnSet\"),Gs=Symbol(\"lruList\"),Lu=Symbol(\"cache\"),Cie=Symbol(\"updateAgeOnGet\"),F_=()=>1,O_=class{constructor(e){if(typeof e==\"number\"&&(e={max:e}),e||(e={}),e.max&&(typeof e.max!=\"number\"||e.max<0))throw new TypeError(\"max must be a non-negative number\");let r=this[_d]=e.max||1/0,s=e.length||F_;if(this[DE]=typeof s!=\"function\"?F_:s,this[fB]=e.stale||!1,e.maxAge&&typeof e.maxAge!=\"number\")throw new TypeError(\"maxAge must be a number\");this[Hd]=e.maxAge||0,this[vp]=e.dispose,this[Eie]=e.noDisposeOnSet||!1,this[Cie]=e.updateAgeOnGet||!1,this.reset()}set max(e){if(typeof e!=\"number\"||e<0)throw new TypeError(\"max must be a non-negative number\");this[_d]=e||1/0,uB(this)}get max(){return this[_d]}set allowStale(e){this[fB]=!!e}get allowStale(){return this[fB]}set maxAge(e){if(typeof e!=\"number\")throw new TypeError(\"maxAge must be a non-negative number\");this[Hd]=e,uB(this)}get maxAge(){return this[Hd]}set lengthCalculator(e){typeof e!=\"function\"&&(e=F_),e!==this[DE]&&(this[DE]=e,this[Sp]=0,this[Gs].forEach(r=>{r.length=this[DE](r.value,r.key),this[Sp]+=r.length})),uB(this)}get lengthCalculator(){return this[DE]}get length(){return this[Sp]}get itemCount(){return this[Gs].length}rforEach(e,r){r=r||this;for(let s=this[Gs].tail;s!==null;){let a=s.prev;Iie(this,e,s,r),s=a}}forEach(e,r){r=r||this;for(let s=this[Gs].head;s!==null;){let a=s.next;Iie(this,e,s,r),s=a}}keys(){return this[Gs].toArray().map(e=>e.key)}values(){return this[Gs].toArray().map(e=>e.value)}reset(){this[vp]&&this[Gs]&&this[Gs].length&&this[Gs].forEach(e=>this[vp](e.key,e.value)),this[Lu]=new Map,this[Gs]=new t7e,this[Sp]=0}dump(){return this[Gs].map(e=>ek(this,e)?!1:{k:e.key,v:e.value,e:e.now+(e.maxAge||0)}).toArray().filter(e=>e)}dumpLru(){return this[Gs]}set(e,r,s){if(s=s||this[Hd],s&&typeof s!=\"number\")throw new TypeError(\"maxAge must be a number\");let a=s?Date.now():0,n=this[DE](r,e);if(this[Lu].has(e)){if(n>this[_d])return PE(this,this[Lu].get(e)),!1;let p=this[Lu].get(e).value;return this[vp]&&(this[Eie]||this[vp](e,p.value)),p.now=a,p.maxAge=s,p.value=r,this[Sp]+=n-p.length,p.length=n,this.get(e),uB(this),!0}let c=new L_(e,r,n,a,s);return c.length>this[_d]?(this[vp]&&this[vp](e,r),!1):(this[Sp]+=c.length,this[Gs].unshift(c),this[Lu].set(e,this[Gs].head),uB(this),!0)}has(e){if(!this[Lu].has(e))return!1;let r=this[Lu].get(e).value;return!ek(this,r)}get(e){return N_(this,e,!0)}peek(e){return N_(this,e,!1)}pop(){let e=this[Gs].tail;return e?(PE(this,e),e.value):null}del(e){PE(this,this[Lu].get(e))}load(e){this.reset();let r=Date.now();for(let s=e.length-1;s>=0;s--){let a=e[s],n=a.e||0;if(n===0)this.set(a.k,a.v);else{let c=n-r;c>0&&this.set(a.k,a.v,c)}}}prune(){this[Lu].forEach((e,r)=>N_(this,r,!1))}},N_=(t,e,r)=>{let s=t[Lu].get(e);if(s){let a=s.value;if(ek(t,a)){if(PE(t,s),!t[fB])return}else r&&(t[Cie]&&(s.value.now=Date.now()),t[Gs].unshiftNode(s));return a.value}},ek=(t,e)=>{if(!e||!e.maxAge&&!t[Hd])return!1;let r=Date.now()-e.now;return e.maxAge?r>e.maxAge:t[Hd]&&r>t[Hd]},uB=t=>{if(t[Sp]>t[_d])for(let e=t[Gs].tail;t[Sp]>t[_d]&&e!==null;){let r=e.prev;PE(t,e),e=r}},PE=(t,e)=>{if(e){let r=e.value;t[vp]&&t[vp](r.key,r.value),t[Sp]-=r.length,t[Lu].delete(r.key),t[Gs].removeNode(e)}},L_=class{constructor(e,r,s,a,n){this.key=e,this.value=r,this.length=s,this.now=a,this.maxAge=n||0}},Iie=(t,e,r,s)=>{let a=r.value;ek(t,a)&&(PE(t,r),t[fB]||(a=void 0)),a&&e.call(s,a.value,a.key,t)};wie.exports=O_});var vc=_((ITt,Pie)=>{var M_=class t{constructor(e,r){if(r=n7e(r),e instanceof t)return e.loose===!!r.loose&&e.includePrerelease===!!r.includePrerelease?e:new t(e.raw,r);if(e instanceof U_)return this.raw=e.value,this.set=[[e]],this.format(),this;if(this.options=r,this.loose=!!r.loose,this.includePrerelease=!!r.includePrerelease,this.raw=e.trim().split(/\\s+/).join(\" \"),this.set=this.raw.split(\"||\").map(s=>this.parseRange(s.trim())).filter(s=>s.length),!this.set.length)throw new TypeError(`Invalid SemVer Range: ${this.raw}`);if(this.set.length>1){let s=this.set[0];if(this.set=this.set.filter(a=>!Sie(a[0])),this.set.length===0)this.set=[s];else if(this.set.length>1){for(let a of this.set)if(a.length===1&&u7e(a[0])){this.set=[a];break}}}this.format()}format(){return this.range=this.set.map(e=>e.join(\" \").trim()).join(\"||\").trim(),this.range}toString(){return this.range}parseRange(e){let s=((this.options.includePrerelease&&l7e)|(this.options.loose&&c7e))+\":\"+e,a=vie.get(s);if(a)return a;let n=this.options.loose,c=n?sl[wa.HYPHENRANGELOOSE]:sl[wa.HYPHENRANGE];e=e.replace(c,I7e(this.options.includePrerelease)),vi(\"hyphen replace\",e),e=e.replace(sl[wa.COMPARATORTRIM],s7e),vi(\"comparator trim\",e),e=e.replace(sl[wa.TILDETRIM],o7e),vi(\"tilde trim\",e),e=e.replace(sl[wa.CARETTRIM],a7e),vi(\"caret trim\",e);let f=e.split(\" \").map(C=>f7e(C,this.options)).join(\" \").split(/\\s+/).map(C=>E7e(C,this.options));n&&(f=f.filter(C=>(vi(\"loose invalid filter\",C,this.options),!!C.match(sl[wa.COMPARATORLOOSE])))),vi(\"range list\",f);let p=new Map,h=f.map(C=>new U_(C,this.options));for(let C of h){if(Sie(C))return[C];p.set(C.value,C)}p.size>1&&p.has(\"\")&&p.delete(\"\");let E=[...p.values()];return vie.set(s,E),E}intersects(e,r){if(!(e instanceof t))throw new TypeError(\"a Range is required\");return this.set.some(s=>Die(s,r)&&e.set.some(a=>Die(a,r)&&s.every(n=>a.every(c=>n.intersects(c,r)))))}test(e){if(!e)return!1;if(typeof e==\"string\")try{e=new i7e(e,this.options)}catch{return!1}for(let r=0;r<this.set.length;r++)if(C7e(this.set[r],e,this.options))return!0;return!1}};Pie.exports=M_;var r7e=Bie(),vie=new r7e({max:1e3}),n7e=qx(),U_=AB(),vi=lB(),i7e=jo(),{safeRe:sl,t:wa,comparatorTrimReplace:s7e,tildeTrimReplace:o7e,caretTrimReplace:a7e}=vE(),{FLAG_INCLUDE_PRERELEASE:l7e,FLAG_LOOSE:c7e}=aB(),Sie=t=>t.value===\"<0.0.0-0\",u7e=t=>t.value===\"\",Die=(t,e)=>{let r=!0,s=t.slice(),a=s.pop();for(;r&&s.length;)r=s.every(n=>a.intersects(n,e)),a=s.pop();return r},f7e=(t,e)=>(vi(\"comp\",t,e),t=h7e(t,e),vi(\"caret\",t),t=A7e(t,e),vi(\"tildes\",t),t=d7e(t,e),vi(\"xrange\",t),t=y7e(t,e),vi(\"stars\",t),t),Ba=t=>!t||t.toLowerCase()===\"x\"||t===\"*\",A7e=(t,e)=>t.trim().split(/\\s+/).map(r=>p7e(r,e)).join(\" \"),p7e=(t,e)=>{let r=e.loose?sl[wa.TILDELOOSE]:sl[wa.TILDE];return t.replace(r,(s,a,n,c,f)=>{vi(\"tilde\",t,s,a,n,c,f);let p;return Ba(a)?p=\"\":Ba(n)?p=`>=${a}.0.0 <${+a+1}.0.0-0`:Ba(c)?p=`>=${a}.${n}.0 <${a}.${+n+1}.0-0`:f?(vi(\"replaceTilde pr\",f),p=`>=${a}.${n}.${c}-${f} <${a}.${+n+1}.0-0`):p=`>=${a}.${n}.${c} <${a}.${+n+1}.0-0`,vi(\"tilde return\",p),p})},h7e=(t,e)=>t.trim().split(/\\s+/).map(r=>g7e(r,e)).join(\" \"),g7e=(t,e)=>{vi(\"caret\",t,e);let r=e.loose?sl[wa.CARETLOOSE]:sl[wa.CARET],s=e.includePrerelease?\"-0\":\"\";return t.replace(r,(a,n,c,f,p)=>{vi(\"caret\",t,a,n,c,f,p);let h;return Ba(n)?h=\"\":Ba(c)?h=`>=${n}.0.0${s} <${+n+1}.0.0-0`:Ba(f)?n===\"0\"?h=`>=${n}.${c}.0${s} <${n}.${+c+1}.0-0`:h=`>=${n}.${c}.0${s} <${+n+1}.0.0-0`:p?(vi(\"replaceCaret pr\",p),n===\"0\"?c===\"0\"?h=`>=${n}.${c}.${f}-${p} <${n}.${c}.${+f+1}-0`:h=`>=${n}.${c}.${f}-${p} <${n}.${+c+1}.0-0`:h=`>=${n}.${c}.${f}-${p} <${+n+1}.0.0-0`):(vi(\"no pr\"),n===\"0\"?c===\"0\"?h=`>=${n}.${c}.${f}${s} <${n}.${c}.${+f+1}-0`:h=`>=${n}.${c}.${f}${s} <${n}.${+c+1}.0-0`:h=`>=${n}.${c}.${f} <${+n+1}.0.0-0`),vi(\"caret return\",h),h})},d7e=(t,e)=>(vi(\"replaceXRanges\",t,e),t.split(/\\s+/).map(r=>m7e(r,e)).join(\" \")),m7e=(t,e)=>{t=t.trim();let r=e.loose?sl[wa.XRANGELOOSE]:sl[wa.XRANGE];return t.replace(r,(s,a,n,c,f,p)=>{vi(\"xRange\",t,s,a,n,c,f,p);let h=Ba(n),E=h||Ba(c),C=E||Ba(f),S=C;return a===\"=\"&&S&&(a=\"\"),p=e.includePrerelease?\"-0\":\"\",h?a===\">\"||a===\"<\"?s=\"<0.0.0-0\":s=\"*\":a&&S?(E&&(c=0),f=0,a===\">\"?(a=\">=\",E?(n=+n+1,c=0,f=0):(c=+c+1,f=0)):a===\"<=\"&&(a=\"<\",E?n=+n+1:c=+c+1),a===\"<\"&&(p=\"-0\"),s=`${a+n}.${c}.${f}${p}`):E?s=`>=${n}.0.0${p} <${+n+1}.0.0-0`:C&&(s=`>=${n}.${c}.0${p} <${n}.${+c+1}.0-0`),vi(\"xRange return\",s),s})},y7e=(t,e)=>(vi(\"replaceStars\",t,e),t.trim().replace(sl[wa.STAR],\"\")),E7e=(t,e)=>(vi(\"replaceGTE0\",t,e),t.trim().replace(sl[e.includePrerelease?wa.GTE0PRE:wa.GTE0],\"\")),I7e=t=>(e,r,s,a,n,c,f,p,h,E,C,S,b)=>(Ba(s)?r=\"\":Ba(a)?r=`>=${s}.0.0${t?\"-0\":\"\"}`:Ba(n)?r=`>=${s}.${a}.0${t?\"-0\":\"\"}`:c?r=`>=${r}`:r=`>=${r}${t?\"-0\":\"\"}`,Ba(h)?p=\"\":Ba(E)?p=`<${+h+1}.0.0-0`:Ba(C)?p=`<${h}.${+E+1}.0-0`:S?p=`<=${h}.${E}.${C}-${S}`:t?p=`<${h}.${E}.${+C+1}-0`:p=`<=${p}`,`${r} ${p}`.trim()),C7e=(t,e,r)=>{for(let s=0;s<t.length;s++)if(!t[s].test(e))return!1;if(e.prerelease.length&&!r.includePrerelease){for(let s=0;s<t.length;s++)if(vi(t[s].semver),t[s].semver!==U_.ANY&&t[s].semver.prerelease.length>0){let a=t[s].semver;if(a.major===e.major&&a.minor===e.minor&&a.patch===e.patch)return!0}return!1}return!0}});var AB=_((CTt,Tie)=>{var pB=Symbol(\"SemVer ANY\"),j_=class t{static get ANY(){return pB}constructor(e,r){if(r=bie(r),e instanceof t){if(e.loose===!!r.loose)return e;e=e.value}e=e.trim().split(/\\s+/).join(\" \"),H_(\"comparator\",e,r),this.options=r,this.loose=!!r.loose,this.parse(e),this.semver===pB?this.value=\"\":this.value=this.operator+this.semver.version,H_(\"comp\",this)}parse(e){let r=this.options.loose?xie[kie.COMPARATORLOOSE]:xie[kie.COMPARATOR],s=e.match(r);if(!s)throw new TypeError(`Invalid comparator: ${e}`);this.operator=s[1]!==void 0?s[1]:\"\",this.operator===\"=\"&&(this.operator=\"\"),s[2]?this.semver=new Qie(s[2],this.options.loose):this.semver=pB}toString(){return this.value}test(e){if(H_(\"Comparator.test\",e,this.options.loose),this.semver===pB||e===pB)return!0;if(typeof e==\"string\")try{e=new Qie(e,this.options)}catch{return!1}return __(e,this.operator,this.semver,this.options)}intersects(e,r){if(!(e instanceof t))throw new TypeError(\"a Comparator is required\");return this.operator===\"\"?this.value===\"\"?!0:new Rie(e.value,r).test(this.value):e.operator===\"\"?e.value===\"\"?!0:new Rie(this.value,r).test(e.semver):(r=bie(r),r.includePrerelease&&(this.value===\"<0.0.0-0\"||e.value===\"<0.0.0-0\")||!r.includePrerelease&&(this.value.startsWith(\"<0.0.0\")||e.value.startsWith(\"<0.0.0\"))?!1:!!(this.operator.startsWith(\">\")&&e.operator.startsWith(\">\")||this.operator.startsWith(\"<\")&&e.operator.startsWith(\"<\")||this.semver.version===e.semver.version&&this.operator.includes(\"=\")&&e.operator.includes(\"=\")||__(this.semver,\"<\",e.semver,r)&&this.operator.startsWith(\">\")&&e.operator.startsWith(\"<\")||__(this.semver,\">\",e.semver,r)&&this.operator.startsWith(\"<\")&&e.operator.startsWith(\">\")))}};Tie.exports=j_;var bie=qx(),{safeRe:xie,t:kie}=vE(),__=T_(),H_=lB(),Qie=jo(),Rie=vc()});var hB=_((wTt,Fie)=>{var w7e=vc(),B7e=(t,e,r)=>{try{e=new w7e(e,r)}catch{return!1}return e.test(t)};Fie.exports=B7e});var Oie=_((BTt,Nie)=>{var v7e=vc(),S7e=(t,e)=>new v7e(t,e).set.map(r=>r.map(s=>s.value).join(\" \").trim().split(\" \"));Nie.exports=S7e});var Mie=_((vTt,Lie)=>{var D7e=jo(),P7e=vc(),b7e=(t,e,r)=>{let s=null,a=null,n=null;try{n=new P7e(e,r)}catch{return null}return t.forEach(c=>{n.test(c)&&(!s||a.compare(c)===-1)&&(s=c,a=new D7e(s,r))}),s};Lie.exports=b7e});var _ie=_((STt,Uie)=>{var x7e=jo(),k7e=vc(),Q7e=(t,e,r)=>{let s=null,a=null,n=null;try{n=new k7e(e,r)}catch{return null}return t.forEach(c=>{n.test(c)&&(!s||a.compare(c)===1)&&(s=c,a=new x7e(s,r))}),s};Uie.exports=Q7e});var Gie=_((DTt,jie)=>{var G_=jo(),R7e=vc(),Hie=cB(),T7e=(t,e)=>{t=new R7e(t,e);let r=new G_(\"0.0.0\");if(t.test(r)||(r=new G_(\"0.0.0-0\"),t.test(r)))return r;r=null;for(let s=0;s<t.set.length;++s){let a=t.set[s],n=null;a.forEach(c=>{let f=new G_(c.semver.version);switch(c.operator){case\">\":f.prerelease.length===0?f.patch++:f.prerelease.push(0),f.raw=f.format();case\"\":case\">=\":(!n||Hie(f,n))&&(n=f);break;case\"<\":case\"<=\":break;default:throw new Error(`Unexpected operation: ${c.operator}`)}}),n&&(!r||Hie(r,n))&&(r=n)}return r&&t.test(r)?r:null};jie.exports=T7e});var Wie=_((PTt,qie)=>{var F7e=vc(),N7e=(t,e)=>{try{return new F7e(t,e).range||\"*\"}catch{return null}};qie.exports=N7e});var tk=_((bTt,Kie)=>{var O7e=jo(),Jie=AB(),{ANY:L7e}=Jie,M7e=vc(),U7e=hB(),Yie=cB(),Vie=Jx(),_7e=zx(),H7e=Kx(),j7e=(t,e,r,s)=>{t=new O7e(t,s),e=new M7e(e,s);let a,n,c,f,p;switch(r){case\">\":a=Yie,n=_7e,c=Vie,f=\">\",p=\">=\";break;case\"<\":a=Vie,n=H7e,c=Yie,f=\"<\",p=\"<=\";break;default:throw new TypeError('Must provide a hilo val of \"<\" or \">\"')}if(U7e(t,e,s))return!1;for(let h=0;h<e.set.length;++h){let E=e.set[h],C=null,S=null;if(E.forEach(b=>{b.semver===L7e&&(b=new Jie(\">=0.0.0\")),C=C||b,S=S||b,a(b.semver,C.semver,s)?C=b:c(b.semver,S.semver,s)&&(S=b)}),C.operator===f||C.operator===p||(!S.operator||S.operator===f)&&n(t,S.semver))return!1;if(S.operator===p&&c(t,S.semver))return!1}return!0};Kie.exports=j7e});var Zie=_((xTt,zie)=>{var G7e=tk(),q7e=(t,e,r)=>G7e(t,e,\">\",r);zie.exports=q7e});var $ie=_((kTt,Xie)=>{var W7e=tk(),Y7e=(t,e,r)=>W7e(t,e,\"<\",r);Xie.exports=Y7e});var rse=_((QTt,tse)=>{var ese=vc(),V7e=(t,e,r)=>(t=new ese(t,r),e=new ese(e,r),t.intersects(e,r));tse.exports=V7e});var ise=_((RTt,nse)=>{var J7e=hB(),K7e=Bc();nse.exports=(t,e,r)=>{let s=[],a=null,n=null,c=t.sort((E,C)=>K7e(E,C,r));for(let E of c)J7e(E,e,r)?(n=E,a||(a=E)):(n&&s.push([a,n]),n=null,a=null);a&&s.push([a,null]);let f=[];for(let[E,C]of s)E===C?f.push(E):!C&&E===c[0]?f.push(\"*\"):C?E===c[0]?f.push(`<=${C}`):f.push(`${E} - ${C}`):f.push(`>=${E}`);let p=f.join(\" || \"),h=typeof e.raw==\"string\"?e.raw:String(e);return p.length<h.length?p:e}});var use=_((TTt,cse)=>{var sse=vc(),W_=AB(),{ANY:q_}=W_,gB=hB(),Y_=Bc(),z7e=(t,e,r={})=>{if(t===e)return!0;t=new sse(t,r),e=new sse(e,r);let s=!1;e:for(let a of t.set){for(let n of e.set){let c=X7e(a,n,r);if(s=s||c!==null,c)continue e}if(s)return!1}return!0},Z7e=[new W_(\">=0.0.0-0\")],ose=[new W_(\">=0.0.0\")],X7e=(t,e,r)=>{if(t===e)return!0;if(t.length===1&&t[0].semver===q_){if(e.length===1&&e[0].semver===q_)return!0;r.includePrerelease?t=Z7e:t=ose}if(e.length===1&&e[0].semver===q_){if(r.includePrerelease)return!0;e=ose}let s=new Set,a,n;for(let b of t)b.operator===\">\"||b.operator===\">=\"?a=ase(a,b,r):b.operator===\"<\"||b.operator===\"<=\"?n=lse(n,b,r):s.add(b.semver);if(s.size>1)return null;let c;if(a&&n){if(c=Y_(a.semver,n.semver,r),c>0)return null;if(c===0&&(a.operator!==\">=\"||n.operator!==\"<=\"))return null}for(let b of s){if(a&&!gB(b,String(a),r)||n&&!gB(b,String(n),r))return null;for(let I of e)if(!gB(b,String(I),r))return!1;return!0}let f,p,h,E,C=n&&!r.includePrerelease&&n.semver.prerelease.length?n.semver:!1,S=a&&!r.includePrerelease&&a.semver.prerelease.length?a.semver:!1;C&&C.prerelease.length===1&&n.operator===\"<\"&&C.prerelease[0]===0&&(C=!1);for(let b of e){if(E=E||b.operator===\">\"||b.operator===\">=\",h=h||b.operator===\"<\"||b.operator===\"<=\",a){if(S&&b.semver.prerelease&&b.semver.prerelease.length&&b.semver.major===S.major&&b.semver.minor===S.minor&&b.semver.patch===S.patch&&(S=!1),b.operator===\">\"||b.operator===\">=\"){if(f=ase(a,b,r),f===b&&f!==a)return!1}else if(a.operator===\">=\"&&!gB(a.semver,String(b),r))return!1}if(n){if(C&&b.semver.prerelease&&b.semver.prerelease.length&&b.semver.major===C.major&&b.semver.minor===C.minor&&b.semver.patch===C.patch&&(C=!1),b.operator===\"<\"||b.operator===\"<=\"){if(p=lse(n,b,r),p===b&&p!==n)return!1}else if(n.operator===\"<=\"&&!gB(n.semver,String(b),r))return!1}if(!b.operator&&(n||a)&&c!==0)return!1}return!(a&&h&&!n&&c!==0||n&&E&&!a&&c!==0||S||C)},ase=(t,e,r)=>{if(!t)return e;let s=Y_(t.semver,e.semver,r);return s>0?t:s<0||e.operator===\">\"&&t.operator===\">=\"?e:t},lse=(t,e,r)=>{if(!t)return e;let s=Y_(t.semver,e.semver,r);return s<0?t:s>0||e.operator===\"<\"&&t.operator===\"<=\"?e:t};cse.exports=z7e});var Ai=_((FTt,pse)=>{var V_=vE(),fse=aB(),$7e=jo(),Ase=x_(),eJe=Md(),tJe=Rne(),rJe=Fne(),nJe=Lne(),iJe=_ne(),sJe=jne(),oJe=qne(),aJe=Yne(),lJe=Jne(),cJe=Bc(),uJe=Xne(),fJe=eie(),AJe=Vx(),pJe=iie(),hJe=oie(),gJe=cB(),dJe=Jx(),mJe=Q_(),yJe=R_(),EJe=Kx(),IJe=zx(),CJe=T_(),wJe=gie(),BJe=AB(),vJe=vc(),SJe=hB(),DJe=Oie(),PJe=Mie(),bJe=_ie(),xJe=Gie(),kJe=Wie(),QJe=tk(),RJe=Zie(),TJe=$ie(),FJe=rse(),NJe=ise(),OJe=use();pse.exports={parse:eJe,valid:tJe,clean:rJe,inc:nJe,diff:iJe,major:sJe,minor:oJe,patch:aJe,prerelease:lJe,compare:cJe,rcompare:uJe,compareLoose:fJe,compareBuild:AJe,sort:pJe,rsort:hJe,gt:gJe,lt:dJe,eq:mJe,neq:yJe,gte:EJe,lte:IJe,cmp:CJe,coerce:wJe,Comparator:BJe,Range:vJe,satisfies:SJe,toComparators:DJe,maxSatisfying:PJe,minSatisfying:bJe,minVersion:xJe,validRange:kJe,outside:QJe,gtr:RJe,ltr:TJe,intersects:FJe,simplifyRange:NJe,subset:OJe,SemVer:$7e,re:V_.re,src:V_.src,tokens:V_.t,SEMVER_SPEC_VERSION:fse.SEMVER_SPEC_VERSION,RELEASE_TYPES:fse.RELEASE_TYPES,compareIdentifiers:Ase.compareIdentifiers,rcompareIdentifiers:Ase.rcompareIdentifiers}});var gse=_((NTt,hse)=>{\"use strict\";function LJe(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function jd(t,e,r,s){this.message=t,this.expected=e,this.found=r,this.location=s,this.name=\"SyntaxError\",typeof Error.captureStackTrace==\"function\"&&Error.captureStackTrace(this,jd)}LJe(jd,Error);jd.buildMessage=function(t,e){var r={literal:function(h){return'\"'+a(h.text)+'\"'},class:function(h){var E=\"\",C;for(C=0;C<h.parts.length;C++)E+=h.parts[C]instanceof Array?n(h.parts[C][0])+\"-\"+n(h.parts[C][1]):n(h.parts[C]);return\"[\"+(h.inverted?\"^\":\"\")+E+\"]\"},any:function(h){return\"any character\"},end:function(h){return\"end of input\"},other:function(h){return h.description}};function s(h){return h.charCodeAt(0).toString(16).toUpperCase()}function a(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\"/g,'\\\\\"').replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(E){return\"\\\\x0\"+s(E)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(E){return\"\\\\x\"+s(E)})}function n(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\\]/g,\"\\\\]\").replace(/\\^/g,\"\\\\^\").replace(/-/g,\"\\\\-\").replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(E){return\"\\\\x0\"+s(E)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(E){return\"\\\\x\"+s(E)})}function c(h){return r[h.type](h)}function f(h){var E=new Array(h.length),C,S;for(C=0;C<h.length;C++)E[C]=c(h[C]);if(E.sort(),E.length>0){for(C=1,S=1;C<E.length;C++)E[C-1]!==E[C]&&(E[S]=E[C],S++);E.length=S}switch(E.length){case 1:return E[0];case 2:return E[0]+\" or \"+E[1];default:return E.slice(0,-1).join(\", \")+\", or \"+E[E.length-1]}}function p(h){return h?'\"'+a(h)+'\"':\"end of input\"}return\"Expected \"+f(t)+\" but \"+p(e)+\" found.\"};function MJe(t,e){e=e!==void 0?e:{};var r={},s={Expression:y},a=y,n=\"|\",c=Fe(\"|\",!1),f=\"&\",p=Fe(\"&\",!1),h=\"^\",E=Fe(\"^\",!1),C=function($,oe){return!!oe.reduce((xe,Re)=>{switch(Re[1]){case\"|\":return xe|Re[3];case\"&\":return xe&Re[3];case\"^\":return xe^Re[3]}},$)},S=\"!\",b=Fe(\"!\",!1),I=function($){return!$},T=\"(\",N=Fe(\"(\",!1),U=\")\",W=Fe(\")\",!1),ee=function($){return $},ie=/^[^ \\t\\n\\r()!|&\\^]/,ue=Ne([\" \",\"\t\",`\n`,\"\\r\",\"(\",\")\",\"!\",\"|\",\"&\",\"^\"],!0,!1),le=function($){return e.queryPattern.test($)},me=function($){return e.checkFn($)},pe=ke(\"whitespace\"),Be=/^[ \\t\\n\\r]/,Ce=Ne([\" \",\"\t\",`\n`,\"\\r\"],!1,!1),g=0,we=0,ye=[{line:1,column:1}],Ae=0,se=[],X=0,De;if(\"startRule\"in e){if(!(e.startRule in s))throw new Error(`Can't start parsing from rule \"`+e.startRule+'\".');a=s[e.startRule]}function Te(){return t.substring(we,g)}function mt(){return Ue(we,g)}function j($,oe){throw oe=oe!==void 0?oe:Ue(we,g),P([ke($)],t.substring(we,g),oe)}function rt($,oe){throw oe=oe!==void 0?oe:Ue(we,g),w($,oe)}function Fe($,oe){return{type:\"literal\",text:$,ignoreCase:oe}}function Ne($,oe,xe){return{type:\"class\",parts:$,inverted:oe,ignoreCase:xe}}function be(){return{type:\"any\"}}function Ve(){return{type:\"end\"}}function ke($){return{type:\"other\",description:$}}function it($){var oe=ye[$],xe;if(oe)return oe;for(xe=$-1;!ye[xe];)xe--;for(oe=ye[xe],oe={line:oe.line,column:oe.column};xe<$;)t.charCodeAt(xe)===10?(oe.line++,oe.column=1):oe.column++,xe++;return ye[$]=oe,oe}function Ue($,oe){var xe=it($),Re=it(oe);return{start:{offset:$,line:xe.line,column:xe.column},end:{offset:oe,line:Re.line,column:Re.column}}}function x($){g<Ae||(g>Ae&&(Ae=g,se=[]),se.push($))}function w($,oe){return new jd($,null,null,oe)}function P($,oe,xe){return new jd(jd.buildMessage($,oe),$,oe,xe)}function y(){var $,oe,xe,Re,lt,Ct,qt,ir;if($=g,oe=F(),oe!==r){for(xe=[],Re=g,lt=Z(),lt!==r?(t.charCodeAt(g)===124?(Ct=n,g++):(Ct=r,X===0&&x(c)),Ct===r&&(t.charCodeAt(g)===38?(Ct=f,g++):(Ct=r,X===0&&x(p)),Ct===r&&(t.charCodeAt(g)===94?(Ct=h,g++):(Ct=r,X===0&&x(E)))),Ct!==r?(qt=Z(),qt!==r?(ir=F(),ir!==r?(lt=[lt,Ct,qt,ir],Re=lt):(g=Re,Re=r)):(g=Re,Re=r)):(g=Re,Re=r)):(g=Re,Re=r);Re!==r;)xe.push(Re),Re=g,lt=Z(),lt!==r?(t.charCodeAt(g)===124?(Ct=n,g++):(Ct=r,X===0&&x(c)),Ct===r&&(t.charCodeAt(g)===38?(Ct=f,g++):(Ct=r,X===0&&x(p)),Ct===r&&(t.charCodeAt(g)===94?(Ct=h,g++):(Ct=r,X===0&&x(E)))),Ct!==r?(qt=Z(),qt!==r?(ir=F(),ir!==r?(lt=[lt,Ct,qt,ir],Re=lt):(g=Re,Re=r)):(g=Re,Re=r)):(g=Re,Re=r)):(g=Re,Re=r);xe!==r?(we=$,oe=C(oe,xe),$=oe):(g=$,$=r)}else g=$,$=r;return $}function F(){var $,oe,xe,Re,lt,Ct;return $=g,t.charCodeAt(g)===33?(oe=S,g++):(oe=r,X===0&&x(b)),oe!==r?(xe=F(),xe!==r?(we=$,oe=I(xe),$=oe):(g=$,$=r)):(g=$,$=r),$===r&&($=g,t.charCodeAt(g)===40?(oe=T,g++):(oe=r,X===0&&x(N)),oe!==r?(xe=Z(),xe!==r?(Re=y(),Re!==r?(lt=Z(),lt!==r?(t.charCodeAt(g)===41?(Ct=U,g++):(Ct=r,X===0&&x(W)),Ct!==r?(we=$,oe=ee(Re),$=oe):(g=$,$=r)):(g=$,$=r)):(g=$,$=r)):(g=$,$=r)):(g=$,$=r),$===r&&($=z())),$}function z(){var $,oe,xe,Re,lt;if($=g,oe=Z(),oe!==r){if(xe=g,Re=[],ie.test(t.charAt(g))?(lt=t.charAt(g),g++):(lt=r,X===0&&x(ue)),lt!==r)for(;lt!==r;)Re.push(lt),ie.test(t.charAt(g))?(lt=t.charAt(g),g++):(lt=r,X===0&&x(ue));else Re=r;Re!==r?xe=t.substring(xe,g):xe=Re,xe!==r?(we=g,Re=le(xe),Re?Re=void 0:Re=r,Re!==r?(we=$,oe=me(xe),$=oe):(g=$,$=r)):(g=$,$=r)}else g=$,$=r;return $}function Z(){var $,oe;for(X++,$=[],Be.test(t.charAt(g))?(oe=t.charAt(g),g++):(oe=r,X===0&&x(Ce));oe!==r;)$.push(oe),Be.test(t.charAt(g))?(oe=t.charAt(g),g++):(oe=r,X===0&&x(Ce));return X--,$===r&&(oe=r,X===0&&x(pe)),$}if(De=a(),De!==r&&g===t.length)return De;throw De!==r&&g<t.length&&x(Ve()),P(se,Ae<t.length?t.charAt(Ae):null,Ae<t.length?Ue(Ae,Ae+1):Ue(Ae,Ae))}hse.exports={SyntaxError:jd,parse:MJe}});var dse=_(rk=>{var{parse:UJe}=gse();rk.makeParser=(t=/[a-z]+/)=>(e,r)=>UJe(e,{queryPattern:t,checkFn:r});rk.parse=rk.makeParser()});var yse=_((LTt,mse)=>{\"use strict\";mse.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}});var J_=_((MTt,Ise)=>{var dB=yse(),Ese={};for(let t of Object.keys(dB))Ese[dB[t]]=t;var hr={rgb:{channels:3,labels:\"rgb\"},hsl:{channels:3,labels:\"hsl\"},hsv:{channels:3,labels:\"hsv\"},hwb:{channels:3,labels:\"hwb\"},cmyk:{channels:4,labels:\"cmyk\"},xyz:{channels:3,labels:\"xyz\"},lab:{channels:3,labels:\"lab\"},lch:{channels:3,labels:\"lch\"},hex:{channels:1,labels:[\"hex\"]},keyword:{channels:1,labels:[\"keyword\"]},ansi16:{channels:1,labels:[\"ansi16\"]},ansi256:{channels:1,labels:[\"ansi256\"]},hcg:{channels:3,labels:[\"h\",\"c\",\"g\"]},apple:{channels:3,labels:[\"r16\",\"g16\",\"b16\"]},gray:{channels:1,labels:[\"gray\"]}};Ise.exports=hr;for(let t of Object.keys(hr)){if(!(\"channels\"in hr[t]))throw new Error(\"missing channels property: \"+t);if(!(\"labels\"in hr[t]))throw new Error(\"missing channel labels property: \"+t);if(hr[t].labels.length!==hr[t].channels)throw new Error(\"channel and label counts mismatch: \"+t);let{channels:e,labels:r}=hr[t];delete hr[t].channels,delete hr[t].labels,Object.defineProperty(hr[t],\"channels\",{value:e}),Object.defineProperty(hr[t],\"labels\",{value:r})}hr.rgb.hsl=function(t){let e=t[0]/255,r=t[1]/255,s=t[2]/255,a=Math.min(e,r,s),n=Math.max(e,r,s),c=n-a,f,p;n===a?f=0:e===n?f=(r-s)/c:r===n?f=2+(s-e)/c:s===n&&(f=4+(e-r)/c),f=Math.min(f*60,360),f<0&&(f+=360);let h=(a+n)/2;return n===a?p=0:h<=.5?p=c/(n+a):p=c/(2-n-a),[f,p*100,h*100]};hr.rgb.hsv=function(t){let e,r,s,a,n,c=t[0]/255,f=t[1]/255,p=t[2]/255,h=Math.max(c,f,p),E=h-Math.min(c,f,p),C=function(S){return(h-S)/6/E+1/2};return E===0?(a=0,n=0):(n=E/h,e=C(c),r=C(f),s=C(p),c===h?a=s-r:f===h?a=1/3+e-s:p===h&&(a=2/3+r-e),a<0?a+=1:a>1&&(a-=1)),[a*360,n*100,h*100]};hr.rgb.hwb=function(t){let e=t[0],r=t[1],s=t[2],a=hr.rgb.hsl(t)[0],n=1/255*Math.min(e,Math.min(r,s));return s=1-1/255*Math.max(e,Math.max(r,s)),[a,n*100,s*100]};hr.rgb.cmyk=function(t){let e=t[0]/255,r=t[1]/255,s=t[2]/255,a=Math.min(1-e,1-r,1-s),n=(1-e-a)/(1-a)||0,c=(1-r-a)/(1-a)||0,f=(1-s-a)/(1-a)||0;return[n*100,c*100,f*100,a*100]};function _Je(t,e){return(t[0]-e[0])**2+(t[1]-e[1])**2+(t[2]-e[2])**2}hr.rgb.keyword=function(t){let e=Ese[t];if(e)return e;let r=1/0,s;for(let a of Object.keys(dB)){let n=dB[a],c=_Je(t,n);c<r&&(r=c,s=a)}return s};hr.keyword.rgb=function(t){return dB[t]};hr.rgb.xyz=function(t){let e=t[0]/255,r=t[1]/255,s=t[2]/255;e=e>.04045?((e+.055)/1.055)**2.4:e/12.92,r=r>.04045?((r+.055)/1.055)**2.4:r/12.92,s=s>.04045?((s+.055)/1.055)**2.4:s/12.92;let a=e*.4124+r*.3576+s*.1805,n=e*.2126+r*.7152+s*.0722,c=e*.0193+r*.1192+s*.9505;return[a*100,n*100,c*100]};hr.rgb.lab=function(t){let e=hr.rgb.xyz(t),r=e[0],s=e[1],a=e[2];r/=95.047,s/=100,a/=108.883,r=r>.008856?r**(1/3):7.787*r+16/116,s=s>.008856?s**(1/3):7.787*s+16/116,a=a>.008856?a**(1/3):7.787*a+16/116;let n=116*s-16,c=500*(r-s),f=200*(s-a);return[n,c,f]};hr.hsl.rgb=function(t){let e=t[0]/360,r=t[1]/100,s=t[2]/100,a,n,c;if(r===0)return c=s*255,[c,c,c];s<.5?a=s*(1+r):a=s+r-s*r;let f=2*s-a,p=[0,0,0];for(let h=0;h<3;h++)n=e+1/3*-(h-1),n<0&&n++,n>1&&n--,6*n<1?c=f+(a-f)*6*n:2*n<1?c=a:3*n<2?c=f+(a-f)*(2/3-n)*6:c=f,p[h]=c*255;return p};hr.hsl.hsv=function(t){let e=t[0],r=t[1]/100,s=t[2]/100,a=r,n=Math.max(s,.01);s*=2,r*=s<=1?s:2-s,a*=n<=1?n:2-n;let c=(s+r)/2,f=s===0?2*a/(n+a):2*r/(s+r);return[e,f*100,c*100]};hr.hsv.rgb=function(t){let e=t[0]/60,r=t[1]/100,s=t[2]/100,a=Math.floor(e)%6,n=e-Math.floor(e),c=255*s*(1-r),f=255*s*(1-r*n),p=255*s*(1-r*(1-n));switch(s*=255,a){case 0:return[s,p,c];case 1:return[f,s,c];case 2:return[c,s,p];case 3:return[c,f,s];case 4:return[p,c,s];case 5:return[s,c,f]}};hr.hsv.hsl=function(t){let e=t[0],r=t[1]/100,s=t[2]/100,a=Math.max(s,.01),n,c;c=(2-r)*s;let f=(2-r)*a;return n=r*a,n/=f<=1?f:2-f,n=n||0,c/=2,[e,n*100,c*100]};hr.hwb.rgb=function(t){let e=t[0]/360,r=t[1]/100,s=t[2]/100,a=r+s,n;a>1&&(r/=a,s/=a);let c=Math.floor(6*e),f=1-s;n=6*e-c,c&1&&(n=1-n);let p=r+n*(f-r),h,E,C;switch(c){default:case 6:case 0:h=f,E=p,C=r;break;case 1:h=p,E=f,C=r;break;case 2:h=r,E=f,C=p;break;case 3:h=r,E=p,C=f;break;case 4:h=p,E=r,C=f;break;case 5:h=f,E=r,C=p;break}return[h*255,E*255,C*255]};hr.cmyk.rgb=function(t){let e=t[0]/100,r=t[1]/100,s=t[2]/100,a=t[3]/100,n=1-Math.min(1,e*(1-a)+a),c=1-Math.min(1,r*(1-a)+a),f=1-Math.min(1,s*(1-a)+a);return[n*255,c*255,f*255]};hr.xyz.rgb=function(t){let e=t[0]/100,r=t[1]/100,s=t[2]/100,a,n,c;return a=e*3.2406+r*-1.5372+s*-.4986,n=e*-.9689+r*1.8758+s*.0415,c=e*.0557+r*-.204+s*1.057,a=a>.0031308?1.055*a**(1/2.4)-.055:a*12.92,n=n>.0031308?1.055*n**(1/2.4)-.055:n*12.92,c=c>.0031308?1.055*c**(1/2.4)-.055:c*12.92,a=Math.min(Math.max(0,a),1),n=Math.min(Math.max(0,n),1),c=Math.min(Math.max(0,c),1),[a*255,n*255,c*255]};hr.xyz.lab=function(t){let e=t[0],r=t[1],s=t[2];e/=95.047,r/=100,s/=108.883,e=e>.008856?e**(1/3):7.787*e+16/116,r=r>.008856?r**(1/3):7.787*r+16/116,s=s>.008856?s**(1/3):7.787*s+16/116;let a=116*r-16,n=500*(e-r),c=200*(r-s);return[a,n,c]};hr.lab.xyz=function(t){let e=t[0],r=t[1],s=t[2],a,n,c;n=(e+16)/116,a=r/500+n,c=n-s/200;let f=n**3,p=a**3,h=c**3;return n=f>.008856?f:(n-16/116)/7.787,a=p>.008856?p:(a-16/116)/7.787,c=h>.008856?h:(c-16/116)/7.787,a*=95.047,n*=100,c*=108.883,[a,n,c]};hr.lab.lch=function(t){let e=t[0],r=t[1],s=t[2],a;a=Math.atan2(s,r)*360/2/Math.PI,a<0&&(a+=360);let c=Math.sqrt(r*r+s*s);return[e,c,a]};hr.lch.lab=function(t){let e=t[0],r=t[1],a=t[2]/360*2*Math.PI,n=r*Math.cos(a),c=r*Math.sin(a);return[e,n,c]};hr.rgb.ansi16=function(t,e=null){let[r,s,a]=t,n=e===null?hr.rgb.hsv(t)[2]:e;if(n=Math.round(n/50),n===0)return 30;let c=30+(Math.round(a/255)<<2|Math.round(s/255)<<1|Math.round(r/255));return n===2&&(c+=60),c};hr.hsv.ansi16=function(t){return hr.rgb.ansi16(hr.hsv.rgb(t),t[2])};hr.rgb.ansi256=function(t){let e=t[0],r=t[1],s=t[2];return e===r&&r===s?e<8?16:e>248?231:Math.round((e-8)/247*24)+232:16+36*Math.round(e/255*5)+6*Math.round(r/255*5)+Math.round(s/255*5)};hr.ansi16.rgb=function(t){let e=t%10;if(e===0||e===7)return t>50&&(e+=3.5),e=e/10.5*255,[e,e,e];let r=(~~(t>50)+1)*.5,s=(e&1)*r*255,a=(e>>1&1)*r*255,n=(e>>2&1)*r*255;return[s,a,n]};hr.ansi256.rgb=function(t){if(t>=232){let n=(t-232)*10+8;return[n,n,n]}t-=16;let e,r=Math.floor(t/36)/5*255,s=Math.floor((e=t%36)/6)/5*255,a=e%6/5*255;return[r,s,a]};hr.rgb.hex=function(t){let r=(((Math.round(t[0])&255)<<16)+((Math.round(t[1])&255)<<8)+(Math.round(t[2])&255)).toString(16).toUpperCase();return\"000000\".substring(r.length)+r};hr.hex.rgb=function(t){let e=t.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);if(!e)return[0,0,0];let r=e[0];e[0].length===3&&(r=r.split(\"\").map(f=>f+f).join(\"\"));let s=parseInt(r,16),a=s>>16&255,n=s>>8&255,c=s&255;return[a,n,c]};hr.rgb.hcg=function(t){let e=t[0]/255,r=t[1]/255,s=t[2]/255,a=Math.max(Math.max(e,r),s),n=Math.min(Math.min(e,r),s),c=a-n,f,p;return c<1?f=n/(1-c):f=0,c<=0?p=0:a===e?p=(r-s)/c%6:a===r?p=2+(s-e)/c:p=4+(e-r)/c,p/=6,p%=1,[p*360,c*100,f*100]};hr.hsl.hcg=function(t){let e=t[1]/100,r=t[2]/100,s=r<.5?2*e*r:2*e*(1-r),a=0;return s<1&&(a=(r-.5*s)/(1-s)),[t[0],s*100,a*100]};hr.hsv.hcg=function(t){let e=t[1]/100,r=t[2]/100,s=e*r,a=0;return s<1&&(a=(r-s)/(1-s)),[t[0],s*100,a*100]};hr.hcg.rgb=function(t){let e=t[0]/360,r=t[1]/100,s=t[2]/100;if(r===0)return[s*255,s*255,s*255];let a=[0,0,0],n=e%1*6,c=n%1,f=1-c,p=0;switch(Math.floor(n)){case 0:a[0]=1,a[1]=c,a[2]=0;break;case 1:a[0]=f,a[1]=1,a[2]=0;break;case 2:a[0]=0,a[1]=1,a[2]=c;break;case 3:a[0]=0,a[1]=f,a[2]=1;break;case 4:a[0]=c,a[1]=0,a[2]=1;break;default:a[0]=1,a[1]=0,a[2]=f}return p=(1-r)*s,[(r*a[0]+p)*255,(r*a[1]+p)*255,(r*a[2]+p)*255]};hr.hcg.hsv=function(t){let e=t[1]/100,r=t[2]/100,s=e+r*(1-e),a=0;return s>0&&(a=e/s),[t[0],a*100,s*100]};hr.hcg.hsl=function(t){let e=t[1]/100,s=t[2]/100*(1-e)+.5*e,a=0;return s>0&&s<.5?a=e/(2*s):s>=.5&&s<1&&(a=e/(2*(1-s))),[t[0],a*100,s*100]};hr.hcg.hwb=function(t){let e=t[1]/100,r=t[2]/100,s=e+r*(1-e);return[t[0],(s-e)*100,(1-s)*100]};hr.hwb.hcg=function(t){let e=t[1]/100,s=1-t[2]/100,a=s-e,n=0;return a<1&&(n=(s-a)/(1-a)),[t[0],a*100,n*100]};hr.apple.rgb=function(t){return[t[0]/65535*255,t[1]/65535*255,t[2]/65535*255]};hr.rgb.apple=function(t){return[t[0]/255*65535,t[1]/255*65535,t[2]/255*65535]};hr.gray.rgb=function(t){return[t[0]/100*255,t[0]/100*255,t[0]/100*255]};hr.gray.hsl=function(t){return[0,0,t[0]]};hr.gray.hsv=hr.gray.hsl;hr.gray.hwb=function(t){return[0,100,t[0]]};hr.gray.cmyk=function(t){return[0,0,0,t[0]]};hr.gray.lab=function(t){return[t[0],0,0]};hr.gray.hex=function(t){let e=Math.round(t[0]/100*255)&255,s=((e<<16)+(e<<8)+e).toString(16).toUpperCase();return\"000000\".substring(s.length)+s};hr.rgb.gray=function(t){return[(t[0]+t[1]+t[2])/3/255*100]}});var wse=_((UTt,Cse)=>{var nk=J_();function HJe(){let t={},e=Object.keys(nk);for(let r=e.length,s=0;s<r;s++)t[e[s]]={distance:-1,parent:null};return t}function jJe(t){let e=HJe(),r=[t];for(e[t].distance=0;r.length;){let s=r.pop(),a=Object.keys(nk[s]);for(let n=a.length,c=0;c<n;c++){let f=a[c],p=e[f];p.distance===-1&&(p.distance=e[s].distance+1,p.parent=s,r.unshift(f))}}return e}function GJe(t,e){return function(r){return e(t(r))}}function qJe(t,e){let r=[e[t].parent,t],s=nk[e[t].parent][t],a=e[t].parent;for(;e[a].parent;)r.unshift(e[a].parent),s=GJe(nk[e[a].parent][a],s),a=e[a].parent;return s.conversion=r,s}Cse.exports=function(t){let e=jJe(t),r={},s=Object.keys(e);for(let a=s.length,n=0;n<a;n++){let c=s[n];e[c].parent!==null&&(r[c]=qJe(c,e))}return r}});var vse=_((_Tt,Bse)=>{var K_=J_(),WJe=wse(),bE={},YJe=Object.keys(K_);function VJe(t){let e=function(...r){let s=r[0];return s==null?s:(s.length>1&&(r=s),t(r))};return\"conversion\"in t&&(e.conversion=t.conversion),e}function JJe(t){let e=function(...r){let s=r[0];if(s==null)return s;s.length>1&&(r=s);let a=t(r);if(typeof a==\"object\")for(let n=a.length,c=0;c<n;c++)a[c]=Math.round(a[c]);return a};return\"conversion\"in t&&(e.conversion=t.conversion),e}YJe.forEach(t=>{bE[t]={},Object.defineProperty(bE[t],\"channels\",{value:K_[t].channels}),Object.defineProperty(bE[t],\"labels\",{value:K_[t].labels});let e=WJe(t);Object.keys(e).forEach(s=>{let a=e[s];bE[t][s]=JJe(a),bE[t][s].raw=VJe(a)})});Bse.exports=bE});var sk=_((HTt,xse)=>{\"use strict\";var Sse=(t,e)=>(...r)=>`\\x1B[${t(...r)+e}m`,Dse=(t,e)=>(...r)=>{let s=t(...r);return`\\x1B[${38+e};5;${s}m`},Pse=(t,e)=>(...r)=>{let s=t(...r);return`\\x1B[${38+e};2;${s[0]};${s[1]};${s[2]}m`},ik=t=>t,bse=(t,e,r)=>[t,e,r],xE=(t,e,r)=>{Object.defineProperty(t,e,{get:()=>{let s=r();return Object.defineProperty(t,e,{value:s,enumerable:!0,configurable:!0}),s},enumerable:!0,configurable:!0})},z_,kE=(t,e,r,s)=>{z_===void 0&&(z_=vse());let a=s?10:0,n={};for(let[c,f]of Object.entries(z_)){let p=c===\"ansi16\"?\"ansi\":c;c===e?n[p]=t(r,a):typeof f==\"object\"&&(n[p]=t(f[e],a))}return n};function KJe(){let t=new Map,e={modifier:{reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],inverse:[7,27],hidden:[8,28],strikethrough:[9,29]},color:{black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],blackBright:[90,39],redBright:[91,39],greenBright:[92,39],yellowBright:[93,39],blueBright:[94,39],magentaBright:[95,39],cyanBright:[96,39],whiteBright:[97,39]},bgColor:{bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],bgBlackBright:[100,49],bgRedBright:[101,49],bgGreenBright:[102,49],bgYellowBright:[103,49],bgBlueBright:[104,49],bgMagentaBright:[105,49],bgCyanBright:[106,49],bgWhiteBright:[107,49]}};e.color.gray=e.color.blackBright,e.bgColor.bgGray=e.bgColor.bgBlackBright,e.color.grey=e.color.blackBright,e.bgColor.bgGrey=e.bgColor.bgBlackBright;for(let[r,s]of Object.entries(e)){for(let[a,n]of Object.entries(s))e[a]={open:`\\x1B[${n[0]}m`,close:`\\x1B[${n[1]}m`},s[a]=e[a],t.set(n[0],n[1]);Object.defineProperty(e,r,{value:s,enumerable:!1})}return Object.defineProperty(e,\"codes\",{value:t,enumerable:!1}),e.color.close=\"\\x1B[39m\",e.bgColor.close=\"\\x1B[49m\",xE(e.color,\"ansi\",()=>kE(Sse,\"ansi16\",ik,!1)),xE(e.color,\"ansi256\",()=>kE(Dse,\"ansi256\",ik,!1)),xE(e.color,\"ansi16m\",()=>kE(Pse,\"rgb\",bse,!1)),xE(e.bgColor,\"ansi\",()=>kE(Sse,\"ansi16\",ik,!0)),xE(e.bgColor,\"ansi256\",()=>kE(Dse,\"ansi256\",ik,!0)),xE(e.bgColor,\"ansi16m\",()=>kE(Pse,\"rgb\",bse,!0)),e}Object.defineProperty(xse,\"exports\",{enumerable:!0,get:KJe})});var Qse=_((jTt,kse)=>{\"use strict\";kse.exports=(t,e=process.argv)=>{let r=t.startsWith(\"-\")?\"\":t.length===1?\"-\":\"--\",s=e.indexOf(r+t),a=e.indexOf(\"--\");return s!==-1&&(a===-1||s<a)}});var Fse=_((GTt,Tse)=>{\"use strict\";var zJe=Ie(\"os\"),Rse=Ie(\"tty\"),Sc=Qse(),{env:Ps}=process,l0;Sc(\"no-color\")||Sc(\"no-colors\")||Sc(\"color=false\")||Sc(\"color=never\")?l0=0:(Sc(\"color\")||Sc(\"colors\")||Sc(\"color=true\")||Sc(\"color=always\"))&&(l0=1);\"FORCE_COLOR\"in Ps&&(Ps.FORCE_COLOR===\"true\"?l0=1:Ps.FORCE_COLOR===\"false\"?l0=0:l0=Ps.FORCE_COLOR.length===0?1:Math.min(parseInt(Ps.FORCE_COLOR,10),3));function Z_(t){return t===0?!1:{level:t,hasBasic:!0,has256:t>=2,has16m:t>=3}}function X_(t,e){if(l0===0)return 0;if(Sc(\"color=16m\")||Sc(\"color=full\")||Sc(\"color=truecolor\"))return 3;if(Sc(\"color=256\"))return 2;if(t&&!e&&l0===void 0)return 0;let r=l0||0;if(Ps.TERM===\"dumb\")return r;if(process.platform===\"win32\"){let s=zJe.release().split(\".\");return Number(s[0])>=10&&Number(s[2])>=10586?Number(s[2])>=14931?3:2:1}if(\"CI\"in Ps)return[\"TRAVIS\",\"CIRCLECI\",\"APPVEYOR\",\"GITLAB_CI\"].some(s=>s in Ps)||Ps.CI_NAME===\"codeship\"?1:r;if(\"TEAMCITY_VERSION\"in Ps)return/^(9\\.(0*[1-9]\\d*)\\.|\\d{2,}\\.)/.test(Ps.TEAMCITY_VERSION)?1:0;if(\"GITHUB_ACTIONS\"in Ps)return 1;if(Ps.COLORTERM===\"truecolor\")return 3;if(\"TERM_PROGRAM\"in Ps){let s=parseInt((Ps.TERM_PROGRAM_VERSION||\"\").split(\".\")[0],10);switch(Ps.TERM_PROGRAM){case\"iTerm.app\":return s>=3?3:2;case\"Apple_Terminal\":return 2}}return/-256(color)?$/i.test(Ps.TERM)?2:/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(Ps.TERM)||\"COLORTERM\"in Ps?1:r}function ZJe(t){let e=X_(t,t&&t.isTTY);return Z_(e)}Tse.exports={supportsColor:ZJe,stdout:Z_(X_(!0,Rse.isatty(1))),stderr:Z_(X_(!0,Rse.isatty(2)))}});var Ose=_((qTt,Nse)=>{\"use strict\";var XJe=(t,e,r)=>{let s=t.indexOf(e);if(s===-1)return t;let a=e.length,n=0,c=\"\";do c+=t.substr(n,s-n)+e+r,n=s+a,s=t.indexOf(e,n);while(s!==-1);return c+=t.substr(n),c},$Je=(t,e,r,s)=>{let a=0,n=\"\";do{let c=t[s-1]===\"\\r\";n+=t.substr(a,(c?s-1:s)-a)+e+(c?`\\r\n`:`\n`)+r,a=s+1,s=t.indexOf(`\n`,a)}while(s!==-1);return n+=t.substr(a),n};Nse.exports={stringReplaceAll:XJe,stringEncaseCRLFWithFirstIndex:$Je}});var Hse=_((WTt,_se)=>{\"use strict\";var eKe=/(?:\\\\(u(?:[a-f\\d]{4}|\\{[a-f\\d]{1,6}\\})|x[a-f\\d]{2}|.))|(?:\\{(~)?(\\w+(?:\\([^)]*\\))?(?:\\.\\w+(?:\\([^)]*\\))?)*)(?:[ \\t]|(?=\\r?\\n)))|(\\})|((?:.|[\\r\\n\\f])+?)/gi,Lse=/(?:^|\\.)(\\w+)(?:\\(([^)]*)\\))?/g,tKe=/^(['\"])((?:\\\\.|(?!\\1)[^\\\\])*)\\1$/,rKe=/\\\\(u(?:[a-f\\d]{4}|{[a-f\\d]{1,6}})|x[a-f\\d]{2}|.)|([^\\\\])/gi,nKe=new Map([[\"n\",`\n`],[\"r\",\"\\r\"],[\"t\",\"\t\"],[\"b\",\"\\b\"],[\"f\",\"\\f\"],[\"v\",\"\\v\"],[\"0\",\"\\0\"],[\"\\\\\",\"\\\\\"],[\"e\",\"\\x1B\"],[\"a\",\"\\x07\"]]);function Use(t){let e=t[0]===\"u\",r=t[1]===\"{\";return e&&!r&&t.length===5||t[0]===\"x\"&&t.length===3?String.fromCharCode(parseInt(t.slice(1),16)):e&&r?String.fromCodePoint(parseInt(t.slice(2,-1),16)):nKe.get(t)||t}function iKe(t,e){let r=[],s=e.trim().split(/\\s*,\\s*/g),a;for(let n of s){let c=Number(n);if(!Number.isNaN(c))r.push(c);else if(a=n.match(tKe))r.push(a[2].replace(rKe,(f,p,h)=>p?Use(p):h));else throw new Error(`Invalid Chalk template style argument: ${n} (in style '${t}')`)}return r}function sKe(t){Lse.lastIndex=0;let e=[],r;for(;(r=Lse.exec(t))!==null;){let s=r[1];if(r[2]){let a=iKe(s,r[2]);e.push([s].concat(a))}else e.push([s])}return e}function Mse(t,e){let r={};for(let a of e)for(let n of a.styles)r[n[0]]=a.inverse?null:n.slice(1);let s=t;for(let[a,n]of Object.entries(r))if(Array.isArray(n)){if(!(a in s))throw new Error(`Unknown Chalk style: ${a}`);s=n.length>0?s[a](...n):s[a]}return s}_se.exports=(t,e)=>{let r=[],s=[],a=[];if(e.replace(eKe,(n,c,f,p,h,E)=>{if(c)a.push(Use(c));else if(p){let C=a.join(\"\");a=[],s.push(r.length===0?C:Mse(t,r)(C)),r.push({inverse:f,styles:sKe(p)})}else if(h){if(r.length===0)throw new Error(\"Found extraneous } in Chalk template literal\");s.push(Mse(t,r)(a.join(\"\"))),a=[],r.pop()}else a.push(E)}),s.push(a.join(\"\")),r.length>0){let n=`Chalk template literal is missing ${r.length} closing bracket${r.length===1?\"\":\"s\"} (\\`}\\`)`;throw new Error(n)}return s.join(\"\")}});var RE=_((YTt,Vse)=>{\"use strict\";var mB=sk(),{stdout:e4,stderr:t4}=Fse(),{stringReplaceAll:oKe,stringEncaseCRLFWithFirstIndex:aKe}=Ose(),{isArray:ok}=Array,Gse=[\"ansi\",\"ansi\",\"ansi256\",\"ansi16m\"],QE=Object.create(null),lKe=(t,e={})=>{if(e.level&&!(Number.isInteger(e.level)&&e.level>=0&&e.level<=3))throw new Error(\"The `level` option should be an integer from 0 to 3\");let r=e4?e4.level:0;t.level=e.level===void 0?r:e.level},r4=class{constructor(e){return qse(e)}},qse=t=>{let e={};return lKe(e,t),e.template=(...r)=>Yse(e.template,...r),Object.setPrototypeOf(e,ak.prototype),Object.setPrototypeOf(e.template,e),e.template.constructor=()=>{throw new Error(\"`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.\")},e.template.Instance=r4,e.template};function ak(t){return qse(t)}for(let[t,e]of Object.entries(mB))QE[t]={get(){let r=lk(this,n4(e.open,e.close,this._styler),this._isEmpty);return Object.defineProperty(this,t,{value:r}),r}};QE.visible={get(){let t=lk(this,this._styler,!0);return Object.defineProperty(this,\"visible\",{value:t}),t}};var Wse=[\"rgb\",\"hex\",\"keyword\",\"hsl\",\"hsv\",\"hwb\",\"ansi\",\"ansi256\"];for(let t of Wse)QE[t]={get(){let{level:e}=this;return function(...r){let s=n4(mB.color[Gse[e]][t](...r),mB.color.close,this._styler);return lk(this,s,this._isEmpty)}}};for(let t of Wse){let e=\"bg\"+t[0].toUpperCase()+t.slice(1);QE[e]={get(){let{level:r}=this;return function(...s){let a=n4(mB.bgColor[Gse[r]][t](...s),mB.bgColor.close,this._styler);return lk(this,a,this._isEmpty)}}}}var cKe=Object.defineProperties(()=>{},{...QE,level:{enumerable:!0,get(){return this._generator.level},set(t){this._generator.level=t}}}),n4=(t,e,r)=>{let s,a;return r===void 0?(s=t,a=e):(s=r.openAll+t,a=e+r.closeAll),{open:t,close:e,openAll:s,closeAll:a,parent:r}},lk=(t,e,r)=>{let s=(...a)=>ok(a[0])&&ok(a[0].raw)?jse(s,Yse(s,...a)):jse(s,a.length===1?\"\"+a[0]:a.join(\" \"));return Object.setPrototypeOf(s,cKe),s._generator=t,s._styler=e,s._isEmpty=r,s},jse=(t,e)=>{if(t.level<=0||!e)return t._isEmpty?\"\":e;let r=t._styler;if(r===void 0)return e;let{openAll:s,closeAll:a}=r;if(e.indexOf(\"\\x1B\")!==-1)for(;r!==void 0;)e=oKe(e,r.close,r.open),r=r.parent;let n=e.indexOf(`\n`);return n!==-1&&(e=aKe(e,a,s,n)),s+e+a},$_,Yse=(t,...e)=>{let[r]=e;if(!ok(r)||!ok(r.raw))return e.join(\" \");let s=e.slice(1),a=[r.raw[0]];for(let n=1;n<r.length;n++)a.push(String(s[n-1]).replace(/[{}\\\\]/g,\"\\\\$&\"),String(r.raw[n]));return $_===void 0&&($_=Hse()),$_(t,a.join(\"\"))};Object.defineProperties(ak.prototype,QE);var ck=ak();ck.supportsColor=e4;ck.stderr=ak({level:t4?t4.level:0});ck.stderr.supportsColor=t4;Vse.exports=ck});var uk=_(Dc=>{\"use strict\";Dc.isInteger=t=>typeof t==\"number\"?Number.isInteger(t):typeof t==\"string\"&&t.trim()!==\"\"?Number.isInteger(Number(t)):!1;Dc.find=(t,e)=>t.nodes.find(r=>r.type===e);Dc.exceedsLimit=(t,e,r=1,s)=>s===!1||!Dc.isInteger(t)||!Dc.isInteger(e)?!1:(Number(e)-Number(t))/Number(r)>=s;Dc.escapeNode=(t,e=0,r)=>{let s=t.nodes[e];s&&(r&&s.type===r||s.type===\"open\"||s.type===\"close\")&&s.escaped!==!0&&(s.value=\"\\\\\"+s.value,s.escaped=!0)};Dc.encloseBrace=t=>t.type!==\"brace\"||t.commas>>0+t.ranges>>0?!1:(t.invalid=!0,!0);Dc.isInvalidBrace=t=>t.type!==\"brace\"?!1:t.invalid===!0||t.dollar?!0:!(t.commas>>0+t.ranges>>0)||t.open!==!0||t.close!==!0?(t.invalid=!0,!0):!1;Dc.isOpenOrClose=t=>t.type===\"open\"||t.type===\"close\"?!0:t.open===!0||t.close===!0;Dc.reduce=t=>t.reduce((e,r)=>(r.type===\"text\"&&e.push(r.value),r.type===\"range\"&&(r.type=\"text\"),e),[]);Dc.flatten=(...t)=>{let e=[],r=s=>{for(let a=0;a<s.length;a++){let n=s[a];Array.isArray(n)?r(n,e):n!==void 0&&e.push(n)}return e};return r(t),e}});var fk=_((JTt,Kse)=>{\"use strict\";var Jse=uk();Kse.exports=(t,e={})=>{let r=(s,a={})=>{let n=e.escapeInvalid&&Jse.isInvalidBrace(a),c=s.invalid===!0&&e.escapeInvalid===!0,f=\"\";if(s.value)return(n||c)&&Jse.isOpenOrClose(s)?\"\\\\\"+s.value:s.value;if(s.value)return s.value;if(s.nodes)for(let p of s.nodes)f+=r(p);return f};return r(t)}});var Zse=_((KTt,zse)=>{\"use strict\";zse.exports=function(t){return typeof t==\"number\"?t-t===0:typeof t==\"string\"&&t.trim()!==\"\"?Number.isFinite?Number.isFinite(+t):isFinite(+t):!1}});var ooe=_((zTt,soe)=>{\"use strict\";var Xse=Zse(),Gd=(t,e,r)=>{if(Xse(t)===!1)throw new TypeError(\"toRegexRange: expected the first argument to be a number\");if(e===void 0||t===e)return String(t);if(Xse(e)===!1)throw new TypeError(\"toRegexRange: expected the second argument to be a number.\");let s={relaxZeros:!0,...r};typeof s.strictZeros==\"boolean\"&&(s.relaxZeros=s.strictZeros===!1);let a=String(s.relaxZeros),n=String(s.shorthand),c=String(s.capture),f=String(s.wrap),p=t+\":\"+e+\"=\"+a+n+c+f;if(Gd.cache.hasOwnProperty(p))return Gd.cache[p].result;let h=Math.min(t,e),E=Math.max(t,e);if(Math.abs(h-E)===1){let T=t+\"|\"+e;return s.capture?`(${T})`:s.wrap===!1?T:`(?:${T})`}let C=ioe(t)||ioe(e),S={min:t,max:e,a:h,b:E},b=[],I=[];if(C&&(S.isPadded=C,S.maxLen=String(S.max).length),h<0){let T=E<0?Math.abs(E):1;I=$se(T,Math.abs(h),S,s),h=S.a=0}return E>=0&&(b=$se(h,E,S,s)),S.negatives=I,S.positives=b,S.result=uKe(I,b,s),s.capture===!0?S.result=`(${S.result})`:s.wrap!==!1&&b.length+I.length>1&&(S.result=`(?:${S.result})`),Gd.cache[p]=S,S.result};function uKe(t,e,r){let s=i4(t,e,\"-\",!1,r)||[],a=i4(e,t,\"\",!1,r)||[],n=i4(t,e,\"-?\",!0,r)||[];return s.concat(n).concat(a).join(\"|\")}function fKe(t,e){let r=1,s=1,a=toe(t,r),n=new Set([e]);for(;t<=a&&a<=e;)n.add(a),r+=1,a=toe(t,r);for(a=roe(e+1,s)-1;t<a&&a<=e;)n.add(a),s+=1,a=roe(e+1,s)-1;return n=[...n],n.sort(hKe),n}function AKe(t,e,r){if(t===e)return{pattern:t,count:[],digits:0};let s=pKe(t,e),a=s.length,n=\"\",c=0;for(let f=0;f<a;f++){let[p,h]=s[f];p===h?n+=p:p!==\"0\"||h!==\"9\"?n+=gKe(p,h,r):c++}return c&&(n+=r.shorthand===!0?\"\\\\d\":\"[0-9]\"),{pattern:n,count:[c],digits:a}}function $se(t,e,r,s){let a=fKe(t,e),n=[],c=t,f;for(let p=0;p<a.length;p++){let h=a[p],E=AKe(String(c),String(h),s),C=\"\";if(!r.isPadded&&f&&f.pattern===E.pattern){f.count.length>1&&f.count.pop(),f.count.push(E.count[0]),f.string=f.pattern+noe(f.count),c=h+1;continue}r.isPadded&&(C=dKe(h,r,s)),E.string=C+E.pattern+noe(E.count),n.push(E),c=h+1,f=E}return n}function i4(t,e,r,s,a){let n=[];for(let c of t){let{string:f}=c;!s&&!eoe(e,\"string\",f)&&n.push(r+f),s&&eoe(e,\"string\",f)&&n.push(r+f)}return n}function pKe(t,e){let r=[];for(let s=0;s<t.length;s++)r.push([t[s],e[s]]);return r}function hKe(t,e){return t>e?1:e>t?-1:0}function eoe(t,e,r){return t.some(s=>s[e]===r)}function toe(t,e){return Number(String(t).slice(0,-e)+\"9\".repeat(e))}function roe(t,e){return t-t%Math.pow(10,e)}function noe(t){let[e=0,r=\"\"]=t;return r||e>1?`{${e+(r?\",\"+r:\"\")}}`:\"\"}function gKe(t,e,r){return`[${t}${e-t===1?\"\":\"-\"}${e}]`}function ioe(t){return/^-?(0+)\\d/.test(t)}function dKe(t,e,r){if(!e.isPadded)return t;let s=Math.abs(e.maxLen-String(t).length),a=r.relaxZeros!==!1;switch(s){case 0:return\"\";case 1:return a?\"0?\":\"0\";case 2:return a?\"0{0,2}\":\"00\";default:return a?`0{0,${s}}`:`0{${s}}`}}Gd.cache={};Gd.clearCache=()=>Gd.cache={};soe.exports=Gd});var a4=_((ZTt,hoe)=>{\"use strict\";var mKe=Ie(\"util\"),coe=ooe(),aoe=t=>t!==null&&typeof t==\"object\"&&!Array.isArray(t),yKe=t=>e=>t===!0?Number(e):String(e),s4=t=>typeof t==\"number\"||typeof t==\"string\"&&t!==\"\",yB=t=>Number.isInteger(+t),o4=t=>{let e=`${t}`,r=-1;if(e[0]===\"-\"&&(e=e.slice(1)),e===\"0\")return!1;for(;e[++r]===\"0\";);return r>0},EKe=(t,e,r)=>typeof t==\"string\"||typeof e==\"string\"?!0:r.stringify===!0,IKe=(t,e,r)=>{if(e>0){let s=t[0]===\"-\"?\"-\":\"\";s&&(t=t.slice(1)),t=s+t.padStart(s?e-1:e,\"0\")}return r===!1?String(t):t},loe=(t,e)=>{let r=t[0]===\"-\"?\"-\":\"\";for(r&&(t=t.slice(1),e--);t.length<e;)t=\"0\"+t;return r?\"-\"+t:t},CKe=(t,e)=>{t.negatives.sort((c,f)=>c<f?-1:c>f?1:0),t.positives.sort((c,f)=>c<f?-1:c>f?1:0);let r=e.capture?\"\":\"?:\",s=\"\",a=\"\",n;return t.positives.length&&(s=t.positives.join(\"|\")),t.negatives.length&&(a=`-(${r}${t.negatives.join(\"|\")})`),s&&a?n=`${s}|${a}`:n=s||a,e.wrap?`(${r}${n})`:n},uoe=(t,e,r,s)=>{if(r)return coe(t,e,{wrap:!1,...s});let a=String.fromCharCode(t);if(t===e)return a;let n=String.fromCharCode(e);return`[${a}-${n}]`},foe=(t,e,r)=>{if(Array.isArray(t)){let s=r.wrap===!0,a=r.capture?\"\":\"?:\";return s?`(${a}${t.join(\"|\")})`:t.join(\"|\")}return coe(t,e,r)},Aoe=(...t)=>new RangeError(\"Invalid range arguments: \"+mKe.inspect(...t)),poe=(t,e,r)=>{if(r.strictRanges===!0)throw Aoe([t,e]);return[]},wKe=(t,e)=>{if(e.strictRanges===!0)throw new TypeError(`Expected step \"${t}\" to be a number`);return[]},BKe=(t,e,r=1,s={})=>{let a=Number(t),n=Number(e);if(!Number.isInteger(a)||!Number.isInteger(n)){if(s.strictRanges===!0)throw Aoe([t,e]);return[]}a===0&&(a=0),n===0&&(n=0);let c=a>n,f=String(t),p=String(e),h=String(r);r=Math.max(Math.abs(r),1);let E=o4(f)||o4(p)||o4(h),C=E?Math.max(f.length,p.length,h.length):0,S=E===!1&&EKe(t,e,s)===!1,b=s.transform||yKe(S);if(s.toRegex&&r===1)return uoe(loe(t,C),loe(e,C),!0,s);let I={negatives:[],positives:[]},T=W=>I[W<0?\"negatives\":\"positives\"].push(Math.abs(W)),N=[],U=0;for(;c?a>=n:a<=n;)s.toRegex===!0&&r>1?T(a):N.push(IKe(b(a,U),C,S)),a=c?a-r:a+r,U++;return s.toRegex===!0?r>1?CKe(I,s):foe(N,null,{wrap:!1,...s}):N},vKe=(t,e,r=1,s={})=>{if(!yB(t)&&t.length>1||!yB(e)&&e.length>1)return poe(t,e,s);let a=s.transform||(S=>String.fromCharCode(S)),n=`${t}`.charCodeAt(0),c=`${e}`.charCodeAt(0),f=n>c,p=Math.min(n,c),h=Math.max(n,c);if(s.toRegex&&r===1)return uoe(p,h,!1,s);let E=[],C=0;for(;f?n>=c:n<=c;)E.push(a(n,C)),n=f?n-r:n+r,C++;return s.toRegex===!0?foe(E,null,{wrap:!1,options:s}):E},Ak=(t,e,r,s={})=>{if(e==null&&s4(t))return[t];if(!s4(t)||!s4(e))return poe(t,e,s);if(typeof r==\"function\")return Ak(t,e,1,{transform:r});if(aoe(r))return Ak(t,e,0,r);let a={...s};return a.capture===!0&&(a.wrap=!0),r=r||a.step||1,yB(r)?yB(t)&&yB(e)?BKe(t,e,r,a):vKe(t,e,Math.max(Math.abs(r),1),a):r!=null&&!aoe(r)?wKe(r,a):Ak(t,e,1,r)};hoe.exports=Ak});var moe=_((XTt,doe)=>{\"use strict\";var SKe=a4(),goe=uk(),DKe=(t,e={})=>{let r=(s,a={})=>{let n=goe.isInvalidBrace(a),c=s.invalid===!0&&e.escapeInvalid===!0,f=n===!0||c===!0,p=e.escapeInvalid===!0?\"\\\\\":\"\",h=\"\";if(s.isOpen===!0||s.isClose===!0)return p+s.value;if(s.type===\"open\")return f?p+s.value:\"(\";if(s.type===\"close\")return f?p+s.value:\")\";if(s.type===\"comma\")return s.prev.type===\"comma\"?\"\":f?s.value:\"|\";if(s.value)return s.value;if(s.nodes&&s.ranges>0){let E=goe.reduce(s.nodes),C=SKe(...E,{...e,wrap:!1,toRegex:!0});if(C.length!==0)return E.length>1&&C.length>1?`(${C})`:C}if(s.nodes)for(let E of s.nodes)h+=r(E,s);return h};return r(t)};doe.exports=DKe});var Ioe=_(($Tt,Eoe)=>{\"use strict\";var PKe=a4(),yoe=fk(),TE=uk(),qd=(t=\"\",e=\"\",r=!1)=>{let s=[];if(t=[].concat(t),e=[].concat(e),!e.length)return t;if(!t.length)return r?TE.flatten(e).map(a=>`{${a}}`):e;for(let a of t)if(Array.isArray(a))for(let n of a)s.push(qd(n,e,r));else for(let n of e)r===!0&&typeof n==\"string\"&&(n=`{${n}}`),s.push(Array.isArray(n)?qd(a,n,r):a+n);return TE.flatten(s)},bKe=(t,e={})=>{let r=e.rangeLimit===void 0?1e3:e.rangeLimit,s=(a,n={})=>{a.queue=[];let c=n,f=n.queue;for(;c.type!==\"brace\"&&c.type!==\"root\"&&c.parent;)c=c.parent,f=c.queue;if(a.invalid||a.dollar){f.push(qd(f.pop(),yoe(a,e)));return}if(a.type===\"brace\"&&a.invalid!==!0&&a.nodes.length===2){f.push(qd(f.pop(),[\"{}\"]));return}if(a.nodes&&a.ranges>0){let C=TE.reduce(a.nodes);if(TE.exceedsLimit(...C,e.step,r))throw new RangeError(\"expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.\");let S=PKe(...C,e);S.length===0&&(S=yoe(a,e)),f.push(qd(f.pop(),S)),a.nodes=[];return}let p=TE.encloseBrace(a),h=a.queue,E=a;for(;E.type!==\"brace\"&&E.type!==\"root\"&&E.parent;)E=E.parent,h=E.queue;for(let C=0;C<a.nodes.length;C++){let S=a.nodes[C];if(S.type===\"comma\"&&a.type===\"brace\"){C===1&&h.push(\"\"),h.push(\"\");continue}if(S.type===\"close\"){f.push(qd(f.pop(),h,p));continue}if(S.value&&S.type!==\"open\"){h.push(qd(h.pop(),S.value));continue}S.nodes&&s(S,a)}return h};return TE.flatten(s(t))};Eoe.exports=bKe});var woe=_((eFt,Coe)=>{\"use strict\";Coe.exports={MAX_LENGTH:1024*64,CHAR_0:\"0\",CHAR_9:\"9\",CHAR_UPPERCASE_A:\"A\",CHAR_LOWERCASE_A:\"a\",CHAR_UPPERCASE_Z:\"Z\",CHAR_LOWERCASE_Z:\"z\",CHAR_LEFT_PARENTHESES:\"(\",CHAR_RIGHT_PARENTHESES:\")\",CHAR_ASTERISK:\"*\",CHAR_AMPERSAND:\"&\",CHAR_AT:\"@\",CHAR_BACKSLASH:\"\\\\\",CHAR_BACKTICK:\"`\",CHAR_CARRIAGE_RETURN:\"\\r\",CHAR_CIRCUMFLEX_ACCENT:\"^\",CHAR_COLON:\":\",CHAR_COMMA:\",\",CHAR_DOLLAR:\"$\",CHAR_DOT:\".\",CHAR_DOUBLE_QUOTE:'\"',CHAR_EQUAL:\"=\",CHAR_EXCLAMATION_MARK:\"!\",CHAR_FORM_FEED:\"\\f\",CHAR_FORWARD_SLASH:\"/\",CHAR_HASH:\"#\",CHAR_HYPHEN_MINUS:\"-\",CHAR_LEFT_ANGLE_BRACKET:\"<\",CHAR_LEFT_CURLY_BRACE:\"{\",CHAR_LEFT_SQUARE_BRACKET:\"[\",CHAR_LINE_FEED:`\n`,CHAR_NO_BREAK_SPACE:\"\\xA0\",CHAR_PERCENT:\"%\",CHAR_PLUS:\"+\",CHAR_QUESTION_MARK:\"?\",CHAR_RIGHT_ANGLE_BRACKET:\">\",CHAR_RIGHT_CURLY_BRACE:\"}\",CHAR_RIGHT_SQUARE_BRACKET:\"]\",CHAR_SEMICOLON:\";\",CHAR_SINGLE_QUOTE:\"'\",CHAR_SPACE:\" \",CHAR_TAB:\"\t\",CHAR_UNDERSCORE:\"_\",CHAR_VERTICAL_LINE:\"|\",CHAR_ZERO_WIDTH_NOBREAK_SPACE:\"\\uFEFF\"}});var Poe=_((tFt,Doe)=>{\"use strict\";var xKe=fk(),{MAX_LENGTH:Boe,CHAR_BACKSLASH:l4,CHAR_BACKTICK:kKe,CHAR_COMMA:QKe,CHAR_DOT:RKe,CHAR_LEFT_PARENTHESES:TKe,CHAR_RIGHT_PARENTHESES:FKe,CHAR_LEFT_CURLY_BRACE:NKe,CHAR_RIGHT_CURLY_BRACE:OKe,CHAR_LEFT_SQUARE_BRACKET:voe,CHAR_RIGHT_SQUARE_BRACKET:Soe,CHAR_DOUBLE_QUOTE:LKe,CHAR_SINGLE_QUOTE:MKe,CHAR_NO_BREAK_SPACE:UKe,CHAR_ZERO_WIDTH_NOBREAK_SPACE:_Ke}=woe(),HKe=(t,e={})=>{if(typeof t!=\"string\")throw new TypeError(\"Expected a string\");let r=e||{},s=typeof r.maxLength==\"number\"?Math.min(Boe,r.maxLength):Boe;if(t.length>s)throw new SyntaxError(`Input length (${t.length}), exceeds max characters (${s})`);let a={type:\"root\",input:t,nodes:[]},n=[a],c=a,f=a,p=0,h=t.length,E=0,C=0,S,b={},I=()=>t[E++],T=N=>{if(N.type===\"text\"&&f.type===\"dot\"&&(f.type=\"text\"),f&&f.type===\"text\"&&N.type===\"text\"){f.value+=N.value;return}return c.nodes.push(N),N.parent=c,N.prev=f,f=N,N};for(T({type:\"bos\"});E<h;)if(c=n[n.length-1],S=I(),!(S===_Ke||S===UKe)){if(S===l4){T({type:\"text\",value:(e.keepEscaping?S:\"\")+I()});continue}if(S===Soe){T({type:\"text\",value:\"\\\\\"+S});continue}if(S===voe){p++;let N=!0,U;for(;E<h&&(U=I());){if(S+=U,U===voe){p++;continue}if(U===l4){S+=I();continue}if(U===Soe&&(p--,p===0))break}T({type:\"text\",value:S});continue}if(S===TKe){c=T({type:\"paren\",nodes:[]}),n.push(c),T({type:\"text\",value:S});continue}if(S===FKe){if(c.type!==\"paren\"){T({type:\"text\",value:S});continue}c=n.pop(),T({type:\"text\",value:S}),c=n[n.length-1];continue}if(S===LKe||S===MKe||S===kKe){let N=S,U;for(e.keepQuotes!==!0&&(S=\"\");E<h&&(U=I());){if(U===l4){S+=U+I();continue}if(U===N){e.keepQuotes===!0&&(S+=U);break}S+=U}T({type:\"text\",value:S});continue}if(S===NKe){C++;let U={type:\"brace\",open:!0,close:!1,dollar:f.value&&f.value.slice(-1)===\"$\"||c.dollar===!0,depth:C,commas:0,ranges:0,nodes:[]};c=T(U),n.push(c),T({type:\"open\",value:S});continue}if(S===OKe){if(c.type!==\"brace\"){T({type:\"text\",value:S});continue}let N=\"close\";c=n.pop(),c.close=!0,T({type:N,value:S}),C--,c=n[n.length-1];continue}if(S===QKe&&C>0){if(c.ranges>0){c.ranges=0;let N=c.nodes.shift();c.nodes=[N,{type:\"text\",value:xKe(c)}]}T({type:\"comma\",value:S}),c.commas++;continue}if(S===RKe&&C>0&&c.commas===0){let N=c.nodes;if(C===0||N.length===0){T({type:\"text\",value:S});continue}if(f.type===\"dot\"){if(c.range=[],f.value+=S,f.type=\"range\",c.nodes.length!==3&&c.nodes.length!==5){c.invalid=!0,c.ranges=0,f.type=\"text\";continue}c.ranges++,c.args=[];continue}if(f.type===\"range\"){N.pop();let U=N[N.length-1];U.value+=f.value+S,f=U,c.ranges--;continue}T({type:\"dot\",value:S});continue}T({type:\"text\",value:S})}do if(c=n.pop(),c.type!==\"root\"){c.nodes.forEach(W=>{W.nodes||(W.type===\"open\"&&(W.isOpen=!0),W.type===\"close\"&&(W.isClose=!0),W.nodes||(W.type=\"text\"),W.invalid=!0)});let N=n[n.length-1],U=N.nodes.indexOf(c);N.nodes.splice(U,1,...c.nodes)}while(n.length>0);return T({type:\"eos\"}),a};Doe.exports=HKe});var koe=_((rFt,xoe)=>{\"use strict\";var boe=fk(),jKe=moe(),GKe=Ioe(),qKe=Poe(),jl=(t,e={})=>{let r=[];if(Array.isArray(t))for(let s of t){let a=jl.create(s,e);Array.isArray(a)?r.push(...a):r.push(a)}else r=[].concat(jl.create(t,e));return e&&e.expand===!0&&e.nodupes===!0&&(r=[...new Set(r)]),r};jl.parse=(t,e={})=>qKe(t,e);jl.stringify=(t,e={})=>boe(typeof t==\"string\"?jl.parse(t,e):t,e);jl.compile=(t,e={})=>(typeof t==\"string\"&&(t=jl.parse(t,e)),jKe(t,e));jl.expand=(t,e={})=>{typeof t==\"string\"&&(t=jl.parse(t,e));let r=GKe(t,e);return e.noempty===!0&&(r=r.filter(Boolean)),e.nodupes===!0&&(r=[...new Set(r)]),r};jl.create=(t,e={})=>t===\"\"||t.length<3?[t]:e.expand!==!0?jl.compile(t,e):jl.expand(t,e);xoe.exports=jl});var EB=_((nFt,Noe)=>{\"use strict\";var WKe=Ie(\"path\"),Vf=\"\\\\\\\\/\",Qoe=`[^${Vf}]`,Dp=\"\\\\.\",YKe=\"\\\\+\",VKe=\"\\\\?\",pk=\"\\\\/\",JKe=\"(?=.)\",Roe=\"[^/]\",c4=`(?:${pk}|$)`,Toe=`(?:^|${pk})`,u4=`${Dp}{1,2}${c4}`,KKe=`(?!${Dp})`,zKe=`(?!${Toe}${u4})`,ZKe=`(?!${Dp}{0,1}${c4})`,XKe=`(?!${u4})`,$Ke=`[^.${pk}]`,eze=`${Roe}*?`,Foe={DOT_LITERAL:Dp,PLUS_LITERAL:YKe,QMARK_LITERAL:VKe,SLASH_LITERAL:pk,ONE_CHAR:JKe,QMARK:Roe,END_ANCHOR:c4,DOTS_SLASH:u4,NO_DOT:KKe,NO_DOTS:zKe,NO_DOT_SLASH:ZKe,NO_DOTS_SLASH:XKe,QMARK_NO_DOT:$Ke,STAR:eze,START_ANCHOR:Toe},tze={...Foe,SLASH_LITERAL:`[${Vf}]`,QMARK:Qoe,STAR:`${Qoe}*?`,DOTS_SLASH:`${Dp}{1,2}(?:[${Vf}]|$)`,NO_DOT:`(?!${Dp})`,NO_DOTS:`(?!(?:^|[${Vf}])${Dp}{1,2}(?:[${Vf}]|$))`,NO_DOT_SLASH:`(?!${Dp}{0,1}(?:[${Vf}]|$))`,NO_DOTS_SLASH:`(?!${Dp}{1,2}(?:[${Vf}]|$))`,QMARK_NO_DOT:`[^.${Vf}]`,START_ANCHOR:`(?:^|[${Vf}])`,END_ANCHOR:`(?:[${Vf}]|$)`},rze={alnum:\"a-zA-Z0-9\",alpha:\"a-zA-Z\",ascii:\"\\\\x00-\\\\x7F\",blank:\" \\\\t\",cntrl:\"\\\\x00-\\\\x1F\\\\x7F\",digit:\"0-9\",graph:\"\\\\x21-\\\\x7E\",lower:\"a-z\",print:\"\\\\x20-\\\\x7E \",punct:\"\\\\-!\\\"#$%&'()\\\\*+,./:;<=>?@[\\\\]^_`{|}~\",space:\" \\\\t\\\\r\\\\n\\\\v\\\\f\",upper:\"A-Z\",word:\"A-Za-z0-9_\",xdigit:\"A-Fa-f0-9\"};Noe.exports={MAX_LENGTH:1024*64,POSIX_REGEX_SOURCE:rze,REGEX_BACKSLASH:/\\\\(?![*+?^${}(|)[\\]])/g,REGEX_NON_SPECIAL_CHARS:/^[^@![\\].,$*+?^{}()|\\\\/]+/,REGEX_SPECIAL_CHARS:/[-*+?.^${}(|)[\\]]/,REGEX_SPECIAL_CHARS_BACKREF:/(\\\\?)((\\W)(\\3*))/g,REGEX_SPECIAL_CHARS_GLOBAL:/([-*+?.^${}(|)[\\]])/g,REGEX_REMOVE_BACKSLASH:/(?:\\[.*?[^\\\\]\\]|\\\\(?=.))/g,REPLACEMENTS:{\"***\":\"*\",\"**/**\":\"**\",\"**/**/**\":\"**\"},CHAR_0:48,CHAR_9:57,CHAR_UPPERCASE_A:65,CHAR_LOWERCASE_A:97,CHAR_UPPERCASE_Z:90,CHAR_LOWERCASE_Z:122,CHAR_LEFT_PARENTHESES:40,CHAR_RIGHT_PARENTHESES:41,CHAR_ASTERISK:42,CHAR_AMPERSAND:38,CHAR_AT:64,CHAR_BACKWARD_SLASH:92,CHAR_CARRIAGE_RETURN:13,CHAR_CIRCUMFLEX_ACCENT:94,CHAR_COLON:58,CHAR_COMMA:44,CHAR_DOT:46,CHAR_DOUBLE_QUOTE:34,CHAR_EQUAL:61,CHAR_EXCLAMATION_MARK:33,CHAR_FORM_FEED:12,CHAR_FORWARD_SLASH:47,CHAR_GRAVE_ACCENT:96,CHAR_HASH:35,CHAR_HYPHEN_MINUS:45,CHAR_LEFT_ANGLE_BRACKET:60,CHAR_LEFT_CURLY_BRACE:123,CHAR_LEFT_SQUARE_BRACKET:91,CHAR_LINE_FEED:10,CHAR_NO_BREAK_SPACE:160,CHAR_PERCENT:37,CHAR_PLUS:43,CHAR_QUESTION_MARK:63,CHAR_RIGHT_ANGLE_BRACKET:62,CHAR_RIGHT_CURLY_BRACE:125,CHAR_RIGHT_SQUARE_BRACKET:93,CHAR_SEMICOLON:59,CHAR_SINGLE_QUOTE:39,CHAR_SPACE:32,CHAR_TAB:9,CHAR_UNDERSCORE:95,CHAR_VERTICAL_LINE:124,CHAR_ZERO_WIDTH_NOBREAK_SPACE:65279,SEP:WKe.sep,extglobChars(t){return{\"!\":{type:\"negate\",open:\"(?:(?!(?:\",close:`))${t.STAR})`},\"?\":{type:\"qmark\",open:\"(?:\",close:\")?\"},\"+\":{type:\"plus\",open:\"(?:\",close:\")+\"},\"*\":{type:\"star\",open:\"(?:\",close:\")*\"},\"@\":{type:\"at\",open:\"(?:\",close:\")\"}}},globChars(t){return t===!0?tze:Foe}}});var IB=_(ol=>{\"use strict\";var nze=Ie(\"path\"),ize=process.platform===\"win32\",{REGEX_BACKSLASH:sze,REGEX_REMOVE_BACKSLASH:oze,REGEX_SPECIAL_CHARS:aze,REGEX_SPECIAL_CHARS_GLOBAL:lze}=EB();ol.isObject=t=>t!==null&&typeof t==\"object\"&&!Array.isArray(t);ol.hasRegexChars=t=>aze.test(t);ol.isRegexChar=t=>t.length===1&&ol.hasRegexChars(t);ol.escapeRegex=t=>t.replace(lze,\"\\\\$1\");ol.toPosixSlashes=t=>t.replace(sze,\"/\");ol.removeBackslashes=t=>t.replace(oze,e=>e===\"\\\\\"?\"\":e);ol.supportsLookbehinds=()=>{let t=process.version.slice(1).split(\".\").map(Number);return t.length===3&&t[0]>=9||t[0]===8&&t[1]>=10};ol.isWindows=t=>t&&typeof t.windows==\"boolean\"?t.windows:ize===!0||nze.sep===\"\\\\\";ol.escapeLast=(t,e,r)=>{let s=t.lastIndexOf(e,r);return s===-1?t:t[s-1]===\"\\\\\"?ol.escapeLast(t,e,s-1):`${t.slice(0,s)}\\\\${t.slice(s)}`};ol.removePrefix=(t,e={})=>{let r=t;return r.startsWith(\"./\")&&(r=r.slice(2),e.prefix=\"./\"),r};ol.wrapOutput=(t,e={},r={})=>{let s=r.contains?\"\":\"^\",a=r.contains?\"\":\"$\",n=`${s}(?:${t})${a}`;return e.negated===!0&&(n=`(?:^(?!${n}).*$)`),n}});var Goe=_((sFt,joe)=>{\"use strict\";var Ooe=IB(),{CHAR_ASTERISK:f4,CHAR_AT:cze,CHAR_BACKWARD_SLASH:CB,CHAR_COMMA:uze,CHAR_DOT:A4,CHAR_EXCLAMATION_MARK:p4,CHAR_FORWARD_SLASH:Hoe,CHAR_LEFT_CURLY_BRACE:h4,CHAR_LEFT_PARENTHESES:g4,CHAR_LEFT_SQUARE_BRACKET:fze,CHAR_PLUS:Aze,CHAR_QUESTION_MARK:Loe,CHAR_RIGHT_CURLY_BRACE:pze,CHAR_RIGHT_PARENTHESES:Moe,CHAR_RIGHT_SQUARE_BRACKET:hze}=EB(),Uoe=t=>t===Hoe||t===CB,_oe=t=>{t.isPrefix!==!0&&(t.depth=t.isGlobstar?1/0:1)},gze=(t,e)=>{let r=e||{},s=t.length-1,a=r.parts===!0||r.scanToEnd===!0,n=[],c=[],f=[],p=t,h=-1,E=0,C=0,S=!1,b=!1,I=!1,T=!1,N=!1,U=!1,W=!1,ee=!1,ie=!1,ue=!1,le=0,me,pe,Be={value:\"\",depth:0,isGlob:!1},Ce=()=>h>=s,g=()=>p.charCodeAt(h+1),we=()=>(me=pe,p.charCodeAt(++h));for(;h<s;){pe=we();let De;if(pe===CB){W=Be.backslashes=!0,pe=we(),pe===h4&&(U=!0);continue}if(U===!0||pe===h4){for(le++;Ce()!==!0&&(pe=we());){if(pe===CB){W=Be.backslashes=!0,we();continue}if(pe===h4){le++;continue}if(U!==!0&&pe===A4&&(pe=we())===A4){if(S=Be.isBrace=!0,I=Be.isGlob=!0,ue=!0,a===!0)continue;break}if(U!==!0&&pe===uze){if(S=Be.isBrace=!0,I=Be.isGlob=!0,ue=!0,a===!0)continue;break}if(pe===pze&&(le--,le===0)){U=!1,S=Be.isBrace=!0,ue=!0;break}}if(a===!0)continue;break}if(pe===Hoe){if(n.push(h),c.push(Be),Be={value:\"\",depth:0,isGlob:!1},ue===!0)continue;if(me===A4&&h===E+1){E+=2;continue}C=h+1;continue}if(r.noext!==!0&&(pe===Aze||pe===cze||pe===f4||pe===Loe||pe===p4)===!0&&g()===g4){if(I=Be.isGlob=!0,T=Be.isExtglob=!0,ue=!0,pe===p4&&h===E&&(ie=!0),a===!0){for(;Ce()!==!0&&(pe=we());){if(pe===CB){W=Be.backslashes=!0,pe=we();continue}if(pe===Moe){I=Be.isGlob=!0,ue=!0;break}}continue}break}if(pe===f4){if(me===f4&&(N=Be.isGlobstar=!0),I=Be.isGlob=!0,ue=!0,a===!0)continue;break}if(pe===Loe){if(I=Be.isGlob=!0,ue=!0,a===!0)continue;break}if(pe===fze){for(;Ce()!==!0&&(De=we());){if(De===CB){W=Be.backslashes=!0,we();continue}if(De===hze){b=Be.isBracket=!0,I=Be.isGlob=!0,ue=!0;break}}if(a===!0)continue;break}if(r.nonegate!==!0&&pe===p4&&h===E){ee=Be.negated=!0,E++;continue}if(r.noparen!==!0&&pe===g4){if(I=Be.isGlob=!0,a===!0){for(;Ce()!==!0&&(pe=we());){if(pe===g4){W=Be.backslashes=!0,pe=we();continue}if(pe===Moe){ue=!0;break}}continue}break}if(I===!0){if(ue=!0,a===!0)continue;break}}r.noext===!0&&(T=!1,I=!1);let ye=p,Ae=\"\",se=\"\";E>0&&(Ae=p.slice(0,E),p=p.slice(E),C-=E),ye&&I===!0&&C>0?(ye=p.slice(0,C),se=p.slice(C)):I===!0?(ye=\"\",se=p):ye=p,ye&&ye!==\"\"&&ye!==\"/\"&&ye!==p&&Uoe(ye.charCodeAt(ye.length-1))&&(ye=ye.slice(0,-1)),r.unescape===!0&&(se&&(se=Ooe.removeBackslashes(se)),ye&&W===!0&&(ye=Ooe.removeBackslashes(ye)));let X={prefix:Ae,input:t,start:E,base:ye,glob:se,isBrace:S,isBracket:b,isGlob:I,isExtglob:T,isGlobstar:N,negated:ee,negatedExtglob:ie};if(r.tokens===!0&&(X.maxDepth=0,Uoe(pe)||c.push(Be),X.tokens=c),r.parts===!0||r.tokens===!0){let De;for(let Te=0;Te<n.length;Te++){let mt=De?De+1:E,j=n[Te],rt=t.slice(mt,j);r.tokens&&(Te===0&&E!==0?(c[Te].isPrefix=!0,c[Te].value=Ae):c[Te].value=rt,_oe(c[Te]),X.maxDepth+=c[Te].depth),(Te!==0||rt!==\"\")&&f.push(rt),De=j}if(De&&De+1<t.length){let Te=t.slice(De+1);f.push(Te),r.tokens&&(c[c.length-1].value=Te,_oe(c[c.length-1]),X.maxDepth+=c[c.length-1].depth)}X.slashes=n,X.parts=f}return X};joe.exports=gze});var Yoe=_((oFt,Woe)=>{\"use strict\";var hk=EB(),Gl=IB(),{MAX_LENGTH:gk,POSIX_REGEX_SOURCE:dze,REGEX_NON_SPECIAL_CHARS:mze,REGEX_SPECIAL_CHARS_BACKREF:yze,REPLACEMENTS:qoe}=hk,Eze=(t,e)=>{if(typeof e.expandRange==\"function\")return e.expandRange(...t,e);t.sort();let r=`[${t.join(\"-\")}]`;try{new RegExp(r)}catch{return t.map(a=>Gl.escapeRegex(a)).join(\"..\")}return r},FE=(t,e)=>`Missing ${t}: \"${e}\" - use \"\\\\\\\\${e}\" to match literal characters`,d4=(t,e)=>{if(typeof t!=\"string\")throw new TypeError(\"Expected a string\");t=qoe[t]||t;let r={...e},s=typeof r.maxLength==\"number\"?Math.min(gk,r.maxLength):gk,a=t.length;if(a>s)throw new SyntaxError(`Input length: ${a}, exceeds maximum allowed length: ${s}`);let n={type:\"bos\",value:\"\",output:r.prepend||\"\"},c=[n],f=r.capture?\"\":\"?:\",p=Gl.isWindows(e),h=hk.globChars(p),E=hk.extglobChars(h),{DOT_LITERAL:C,PLUS_LITERAL:S,SLASH_LITERAL:b,ONE_CHAR:I,DOTS_SLASH:T,NO_DOT:N,NO_DOT_SLASH:U,NO_DOTS_SLASH:W,QMARK:ee,QMARK_NO_DOT:ie,STAR:ue,START_ANCHOR:le}=h,me=x=>`(${f}(?:(?!${le}${x.dot?T:C}).)*?)`,pe=r.dot?\"\":N,Be=r.dot?ee:ie,Ce=r.bash===!0?me(r):ue;r.capture&&(Ce=`(${Ce})`),typeof r.noext==\"boolean\"&&(r.noextglob=r.noext);let g={input:t,index:-1,start:0,dot:r.dot===!0,consumed:\"\",output:\"\",prefix:\"\",backtrack:!1,negated:!1,brackets:0,braces:0,parens:0,quotes:0,globstar:!1,tokens:c};t=Gl.removePrefix(t,g),a=t.length;let we=[],ye=[],Ae=[],se=n,X,De=()=>g.index===a-1,Te=g.peek=(x=1)=>t[g.index+x],mt=g.advance=()=>t[++g.index]||\"\",j=()=>t.slice(g.index+1),rt=(x=\"\",w=0)=>{g.consumed+=x,g.index+=w},Fe=x=>{g.output+=x.output!=null?x.output:x.value,rt(x.value)},Ne=()=>{let x=1;for(;Te()===\"!\"&&(Te(2)!==\"(\"||Te(3)===\"?\");)mt(),g.start++,x++;return x%2===0?!1:(g.negated=!0,g.start++,!0)},be=x=>{g[x]++,Ae.push(x)},Ve=x=>{g[x]--,Ae.pop()},ke=x=>{if(se.type===\"globstar\"){let w=g.braces>0&&(x.type===\"comma\"||x.type===\"brace\"),P=x.extglob===!0||we.length&&(x.type===\"pipe\"||x.type===\"paren\");x.type!==\"slash\"&&x.type!==\"paren\"&&!w&&!P&&(g.output=g.output.slice(0,-se.output.length),se.type=\"star\",se.value=\"*\",se.output=Ce,g.output+=se.output)}if(we.length&&x.type!==\"paren\"&&(we[we.length-1].inner+=x.value),(x.value||x.output)&&Fe(x),se&&se.type===\"text\"&&x.type===\"text\"){se.value+=x.value,se.output=(se.output||\"\")+x.value;return}x.prev=se,c.push(x),se=x},it=(x,w)=>{let P={...E[w],conditions:1,inner:\"\"};P.prev=se,P.parens=g.parens,P.output=g.output;let y=(r.capture?\"(\":\"\")+P.open;be(\"parens\"),ke({type:x,value:w,output:g.output?\"\":I}),ke({type:\"paren\",extglob:!0,value:mt(),output:y}),we.push(P)},Ue=x=>{let w=x.close+(r.capture?\")\":\"\"),P;if(x.type===\"negate\"){let y=Ce;if(x.inner&&x.inner.length>1&&x.inner.includes(\"/\")&&(y=me(r)),(y!==Ce||De()||/^\\)+$/.test(j()))&&(w=x.close=`)$))${y}`),x.inner.includes(\"*\")&&(P=j())&&/^\\.[^\\\\/.]+$/.test(P)){let F=d4(P,{...e,fastpaths:!1}).output;w=x.close=`)${F})${y})`}x.prev.type===\"bos\"&&(g.negatedExtglob=!0)}ke({type:\"paren\",extglob:!0,value:X,output:w}),Ve(\"parens\")};if(r.fastpaths!==!1&&!/(^[*!]|[/()[\\]{}\"])/.test(t)){let x=!1,w=t.replace(yze,(P,y,F,z,Z,$)=>z===\"\\\\\"?(x=!0,P):z===\"?\"?y?y+z+(Z?ee.repeat(Z.length):\"\"):$===0?Be+(Z?ee.repeat(Z.length):\"\"):ee.repeat(F.length):z===\".\"?C.repeat(F.length):z===\"*\"?y?y+z+(Z?Ce:\"\"):Ce:y?P:`\\\\${P}`);return x===!0&&(r.unescape===!0?w=w.replace(/\\\\/g,\"\"):w=w.replace(/\\\\+/g,P=>P.length%2===0?\"\\\\\\\\\":P?\"\\\\\":\"\")),w===t&&r.contains===!0?(g.output=t,g):(g.output=Gl.wrapOutput(w,g,e),g)}for(;!De();){if(X=mt(),X===\"\\0\")continue;if(X===\"\\\\\"){let P=Te();if(P===\"/\"&&r.bash!==!0||P===\".\"||P===\";\")continue;if(!P){X+=\"\\\\\",ke({type:\"text\",value:X});continue}let y=/^\\\\+/.exec(j()),F=0;if(y&&y[0].length>2&&(F=y[0].length,g.index+=F,F%2!==0&&(X+=\"\\\\\")),r.unescape===!0?X=mt():X+=mt(),g.brackets===0){ke({type:\"text\",value:X});continue}}if(g.brackets>0&&(X!==\"]\"||se.value===\"[\"||se.value===\"[^\")){if(r.posix!==!1&&X===\":\"){let P=se.value.slice(1);if(P.includes(\"[\")&&(se.posix=!0,P.includes(\":\"))){let y=se.value.lastIndexOf(\"[\"),F=se.value.slice(0,y),z=se.value.slice(y+2),Z=dze[z];if(Z){se.value=F+Z,g.backtrack=!0,mt(),!n.output&&c.indexOf(se)===1&&(n.output=I);continue}}}(X===\"[\"&&Te()!==\":\"||X===\"-\"&&Te()===\"]\")&&(X=`\\\\${X}`),X===\"]\"&&(se.value===\"[\"||se.value===\"[^\")&&(X=`\\\\${X}`),r.posix===!0&&X===\"!\"&&se.value===\"[\"&&(X=\"^\"),se.value+=X,Fe({value:X});continue}if(g.quotes===1&&X!=='\"'){X=Gl.escapeRegex(X),se.value+=X,Fe({value:X});continue}if(X==='\"'){g.quotes=g.quotes===1?0:1,r.keepQuotes===!0&&ke({type:\"text\",value:X});continue}if(X===\"(\"){be(\"parens\"),ke({type:\"paren\",value:X});continue}if(X===\")\"){if(g.parens===0&&r.strictBrackets===!0)throw new SyntaxError(FE(\"opening\",\"(\"));let P=we[we.length-1];if(P&&g.parens===P.parens+1){Ue(we.pop());continue}ke({type:\"paren\",value:X,output:g.parens?\")\":\"\\\\)\"}),Ve(\"parens\");continue}if(X===\"[\"){if(r.nobracket===!0||!j().includes(\"]\")){if(r.nobracket!==!0&&r.strictBrackets===!0)throw new SyntaxError(FE(\"closing\",\"]\"));X=`\\\\${X}`}else be(\"brackets\");ke({type:\"bracket\",value:X});continue}if(X===\"]\"){if(r.nobracket===!0||se&&se.type===\"bracket\"&&se.value.length===1){ke({type:\"text\",value:X,output:`\\\\${X}`});continue}if(g.brackets===0){if(r.strictBrackets===!0)throw new SyntaxError(FE(\"opening\",\"[\"));ke({type:\"text\",value:X,output:`\\\\${X}`});continue}Ve(\"brackets\");let P=se.value.slice(1);if(se.posix!==!0&&P[0]===\"^\"&&!P.includes(\"/\")&&(X=`/${X}`),se.value+=X,Fe({value:X}),r.literalBrackets===!1||Gl.hasRegexChars(P))continue;let y=Gl.escapeRegex(se.value);if(g.output=g.output.slice(0,-se.value.length),r.literalBrackets===!0){g.output+=y,se.value=y;continue}se.value=`(${f}${y}|${se.value})`,g.output+=se.value;continue}if(X===\"{\"&&r.nobrace!==!0){be(\"braces\");let P={type:\"brace\",value:X,output:\"(\",outputIndex:g.output.length,tokensIndex:g.tokens.length};ye.push(P),ke(P);continue}if(X===\"}\"){let P=ye[ye.length-1];if(r.nobrace===!0||!P){ke({type:\"text\",value:X,output:X});continue}let y=\")\";if(P.dots===!0){let F=c.slice(),z=[];for(let Z=F.length-1;Z>=0&&(c.pop(),F[Z].type!==\"brace\");Z--)F[Z].type!==\"dots\"&&z.unshift(F[Z].value);y=Eze(z,r),g.backtrack=!0}if(P.comma!==!0&&P.dots!==!0){let F=g.output.slice(0,P.outputIndex),z=g.tokens.slice(P.tokensIndex);P.value=P.output=\"\\\\{\",X=y=\"\\\\}\",g.output=F;for(let Z of z)g.output+=Z.output||Z.value}ke({type:\"brace\",value:X,output:y}),Ve(\"braces\"),ye.pop();continue}if(X===\"|\"){we.length>0&&we[we.length-1].conditions++,ke({type:\"text\",value:X});continue}if(X===\",\"){let P=X,y=ye[ye.length-1];y&&Ae[Ae.length-1]===\"braces\"&&(y.comma=!0,P=\"|\"),ke({type:\"comma\",value:X,output:P});continue}if(X===\"/\"){if(se.type===\"dot\"&&g.index===g.start+1){g.start=g.index+1,g.consumed=\"\",g.output=\"\",c.pop(),se=n;continue}ke({type:\"slash\",value:X,output:b});continue}if(X===\".\"){if(g.braces>0&&se.type===\"dot\"){se.value===\".\"&&(se.output=C);let P=ye[ye.length-1];se.type=\"dots\",se.output+=X,se.value+=X,P.dots=!0;continue}if(g.braces+g.parens===0&&se.type!==\"bos\"&&se.type!==\"slash\"){ke({type:\"text\",value:X,output:C});continue}ke({type:\"dot\",value:X,output:C});continue}if(X===\"?\"){if(!(se&&se.value===\"(\")&&r.noextglob!==!0&&Te()===\"(\"&&Te(2)!==\"?\"){it(\"qmark\",X);continue}if(se&&se.type===\"paren\"){let y=Te(),F=X;if(y===\"<\"&&!Gl.supportsLookbehinds())throw new Error(\"Node.js v10 or higher is required for regex lookbehinds\");(se.value===\"(\"&&!/[!=<:]/.test(y)||y===\"<\"&&!/<([!=]|\\w+>)/.test(j()))&&(F=`\\\\${X}`),ke({type:\"text\",value:X,output:F});continue}if(r.dot!==!0&&(se.type===\"slash\"||se.type===\"bos\")){ke({type:\"qmark\",value:X,output:ie});continue}ke({type:\"qmark\",value:X,output:ee});continue}if(X===\"!\"){if(r.noextglob!==!0&&Te()===\"(\"&&(Te(2)!==\"?\"||!/[!=<:]/.test(Te(3)))){it(\"negate\",X);continue}if(r.nonegate!==!0&&g.index===0){Ne();continue}}if(X===\"+\"){if(r.noextglob!==!0&&Te()===\"(\"&&Te(2)!==\"?\"){it(\"plus\",X);continue}if(se&&se.value===\"(\"||r.regex===!1){ke({type:\"plus\",value:X,output:S});continue}if(se&&(se.type===\"bracket\"||se.type===\"paren\"||se.type===\"brace\")||g.parens>0){ke({type:\"plus\",value:X});continue}ke({type:\"plus\",value:S});continue}if(X===\"@\"){if(r.noextglob!==!0&&Te()===\"(\"&&Te(2)!==\"?\"){ke({type:\"at\",extglob:!0,value:X,output:\"\"});continue}ke({type:\"text\",value:X});continue}if(X!==\"*\"){(X===\"$\"||X===\"^\")&&(X=`\\\\${X}`);let P=mze.exec(j());P&&(X+=P[0],g.index+=P[0].length),ke({type:\"text\",value:X});continue}if(se&&(se.type===\"globstar\"||se.star===!0)){se.type=\"star\",se.star=!0,se.value+=X,se.output=Ce,g.backtrack=!0,g.globstar=!0,rt(X);continue}let x=j();if(r.noextglob!==!0&&/^\\([^?]/.test(x)){it(\"star\",X);continue}if(se.type===\"star\"){if(r.noglobstar===!0){rt(X);continue}let P=se.prev,y=P.prev,F=P.type===\"slash\"||P.type===\"bos\",z=y&&(y.type===\"star\"||y.type===\"globstar\");if(r.bash===!0&&(!F||x[0]&&x[0]!==\"/\")){ke({type:\"star\",value:X,output:\"\"});continue}let Z=g.braces>0&&(P.type===\"comma\"||P.type===\"brace\"),$=we.length&&(P.type===\"pipe\"||P.type===\"paren\");if(!F&&P.type!==\"paren\"&&!Z&&!$){ke({type:\"star\",value:X,output:\"\"});continue}for(;x.slice(0,3)===\"/**\";){let oe=t[g.index+4];if(oe&&oe!==\"/\")break;x=x.slice(3),rt(\"/**\",3)}if(P.type===\"bos\"&&De()){se.type=\"globstar\",se.value+=X,se.output=me(r),g.output=se.output,g.globstar=!0,rt(X);continue}if(P.type===\"slash\"&&P.prev.type!==\"bos\"&&!z&&De()){g.output=g.output.slice(0,-(P.output+se.output).length),P.output=`(?:${P.output}`,se.type=\"globstar\",se.output=me(r)+(r.strictSlashes?\")\":\"|$)\"),se.value+=X,g.globstar=!0,g.output+=P.output+se.output,rt(X);continue}if(P.type===\"slash\"&&P.prev.type!==\"bos\"&&x[0]===\"/\"){let oe=x[1]!==void 0?\"|$\":\"\";g.output=g.output.slice(0,-(P.output+se.output).length),P.output=`(?:${P.output}`,se.type=\"globstar\",se.output=`${me(r)}${b}|${b}${oe})`,se.value+=X,g.output+=P.output+se.output,g.globstar=!0,rt(X+mt()),ke({type:\"slash\",value:\"/\",output:\"\"});continue}if(P.type===\"bos\"&&x[0]===\"/\"){se.type=\"globstar\",se.value+=X,se.output=`(?:^|${b}|${me(r)}${b})`,g.output=se.output,g.globstar=!0,rt(X+mt()),ke({type:\"slash\",value:\"/\",output:\"\"});continue}g.output=g.output.slice(0,-se.output.length),se.type=\"globstar\",se.output=me(r),se.value+=X,g.output+=se.output,g.globstar=!0,rt(X);continue}let w={type:\"star\",value:X,output:Ce};if(r.bash===!0){w.output=\".*?\",(se.type===\"bos\"||se.type===\"slash\")&&(w.output=pe+w.output),ke(w);continue}if(se&&(se.type===\"bracket\"||se.type===\"paren\")&&r.regex===!0){w.output=X,ke(w);continue}(g.index===g.start||se.type===\"slash\"||se.type===\"dot\")&&(se.type===\"dot\"?(g.output+=U,se.output+=U):r.dot===!0?(g.output+=W,se.output+=W):(g.output+=pe,se.output+=pe),Te()!==\"*\"&&(g.output+=I,se.output+=I)),ke(w)}for(;g.brackets>0;){if(r.strictBrackets===!0)throw new SyntaxError(FE(\"closing\",\"]\"));g.output=Gl.escapeLast(g.output,\"[\"),Ve(\"brackets\")}for(;g.parens>0;){if(r.strictBrackets===!0)throw new SyntaxError(FE(\"closing\",\")\"));g.output=Gl.escapeLast(g.output,\"(\"),Ve(\"parens\")}for(;g.braces>0;){if(r.strictBrackets===!0)throw new SyntaxError(FE(\"closing\",\"}\"));g.output=Gl.escapeLast(g.output,\"{\"),Ve(\"braces\")}if(r.strictSlashes!==!0&&(se.type===\"star\"||se.type===\"bracket\")&&ke({type:\"maybe_slash\",value:\"\",output:`${b}?`}),g.backtrack===!0){g.output=\"\";for(let x of g.tokens)g.output+=x.output!=null?x.output:x.value,x.suffix&&(g.output+=x.suffix)}return g};d4.fastpaths=(t,e)=>{let r={...e},s=typeof r.maxLength==\"number\"?Math.min(gk,r.maxLength):gk,a=t.length;if(a>s)throw new SyntaxError(`Input length: ${a}, exceeds maximum allowed length: ${s}`);t=qoe[t]||t;let n=Gl.isWindows(e),{DOT_LITERAL:c,SLASH_LITERAL:f,ONE_CHAR:p,DOTS_SLASH:h,NO_DOT:E,NO_DOTS:C,NO_DOTS_SLASH:S,STAR:b,START_ANCHOR:I}=hk.globChars(n),T=r.dot?C:E,N=r.dot?S:E,U=r.capture?\"\":\"?:\",W={negated:!1,prefix:\"\"},ee=r.bash===!0?\".*?\":b;r.capture&&(ee=`(${ee})`);let ie=pe=>pe.noglobstar===!0?ee:`(${U}(?:(?!${I}${pe.dot?h:c}).)*?)`,ue=pe=>{switch(pe){case\"*\":return`${T}${p}${ee}`;case\".*\":return`${c}${p}${ee}`;case\"*.*\":return`${T}${ee}${c}${p}${ee}`;case\"*/*\":return`${T}${ee}${f}${p}${N}${ee}`;case\"**\":return T+ie(r);case\"**/*\":return`(?:${T}${ie(r)}${f})?${N}${p}${ee}`;case\"**/*.*\":return`(?:${T}${ie(r)}${f})?${N}${ee}${c}${p}${ee}`;case\"**/.*\":return`(?:${T}${ie(r)}${f})?${c}${p}${ee}`;default:{let Be=/^(.*?)\\.(\\w+)$/.exec(pe);if(!Be)return;let Ce=ue(Be[1]);return Ce?Ce+c+Be[2]:void 0}}},le=Gl.removePrefix(t,W),me=ue(le);return me&&r.strictSlashes!==!0&&(me+=`${f}?`),me};Woe.exports=d4});var Joe=_((aFt,Voe)=>{\"use strict\";var Ize=Ie(\"path\"),Cze=Goe(),m4=Yoe(),y4=IB(),wze=EB(),Bze=t=>t&&typeof t==\"object\"&&!Array.isArray(t),Zi=(t,e,r=!1)=>{if(Array.isArray(t)){let E=t.map(S=>Zi(S,e,r));return S=>{for(let b of E){let I=b(S);if(I)return I}return!1}}let s=Bze(t)&&t.tokens&&t.input;if(t===\"\"||typeof t!=\"string\"&&!s)throw new TypeError(\"Expected pattern to be a non-empty string\");let a=e||{},n=y4.isWindows(e),c=s?Zi.compileRe(t,e):Zi.makeRe(t,e,!1,!0),f=c.state;delete c.state;let p=()=>!1;if(a.ignore){let E={...e,ignore:null,onMatch:null,onResult:null};p=Zi(a.ignore,E,r)}let h=(E,C=!1)=>{let{isMatch:S,match:b,output:I}=Zi.test(E,c,e,{glob:t,posix:n}),T={glob:t,state:f,regex:c,posix:n,input:E,output:I,match:b,isMatch:S};return typeof a.onResult==\"function\"&&a.onResult(T),S===!1?(T.isMatch=!1,C?T:!1):p(E)?(typeof a.onIgnore==\"function\"&&a.onIgnore(T),T.isMatch=!1,C?T:!1):(typeof a.onMatch==\"function\"&&a.onMatch(T),C?T:!0)};return r&&(h.state=f),h};Zi.test=(t,e,r,{glob:s,posix:a}={})=>{if(typeof t!=\"string\")throw new TypeError(\"Expected input to be a string\");if(t===\"\")return{isMatch:!1,output:\"\"};let n=r||{},c=n.format||(a?y4.toPosixSlashes:null),f=t===s,p=f&&c?c(t):t;return f===!1&&(p=c?c(t):t,f=p===s),(f===!1||n.capture===!0)&&(n.matchBase===!0||n.basename===!0?f=Zi.matchBase(t,e,r,a):f=e.exec(p)),{isMatch:!!f,match:f,output:p}};Zi.matchBase=(t,e,r,s=y4.isWindows(r))=>(e instanceof RegExp?e:Zi.makeRe(e,r)).test(Ize.basename(t));Zi.isMatch=(t,e,r)=>Zi(e,r)(t);Zi.parse=(t,e)=>Array.isArray(t)?t.map(r=>Zi.parse(r,e)):m4(t,{...e,fastpaths:!1});Zi.scan=(t,e)=>Cze(t,e);Zi.compileRe=(t,e,r=!1,s=!1)=>{if(r===!0)return t.output;let a=e||{},n=a.contains?\"\":\"^\",c=a.contains?\"\":\"$\",f=`${n}(?:${t.output})${c}`;t&&t.negated===!0&&(f=`^(?!${f}).*$`);let p=Zi.toRegex(f,e);return s===!0&&(p.state=t),p};Zi.makeRe=(t,e={},r=!1,s=!1)=>{if(!t||typeof t!=\"string\")throw new TypeError(\"Expected a non-empty string\");let a={negated:!1,fastpaths:!0};return e.fastpaths!==!1&&(t[0]===\".\"||t[0]===\"*\")&&(a.output=m4.fastpaths(t,e)),a.output||(a=m4(t,e)),Zi.compileRe(a,e,r,s)};Zi.toRegex=(t,e)=>{try{let r=e||{};return new RegExp(t,r.flags||(r.nocase?\"i\":\"\"))}catch(r){if(e&&e.debug===!0)throw r;return/$^/}};Zi.constants=wze;Voe.exports=Zi});var zoe=_((lFt,Koe)=>{\"use strict\";Koe.exports=Joe()});var Go=_((cFt,eae)=>{\"use strict\";var Xoe=Ie(\"util\"),$oe=koe(),Jf=zoe(),E4=IB(),Zoe=t=>t===\"\"||t===\"./\",xi=(t,e,r)=>{e=[].concat(e),t=[].concat(t);let s=new Set,a=new Set,n=new Set,c=0,f=E=>{n.add(E.output),r&&r.onResult&&r.onResult(E)};for(let E=0;E<e.length;E++){let C=Jf(String(e[E]),{...r,onResult:f},!0),S=C.state.negated||C.state.negatedExtglob;S&&c++;for(let b of t){let I=C(b,!0);(S?!I.isMatch:I.isMatch)&&(S?s.add(I.output):(s.delete(I.output),a.add(I.output)))}}let h=(c===e.length?[...n]:[...a]).filter(E=>!s.has(E));if(r&&h.length===0){if(r.failglob===!0)throw new Error(`No matches found for \"${e.join(\", \")}\"`);if(r.nonull===!0||r.nullglob===!0)return r.unescape?e.map(E=>E.replace(/\\\\/g,\"\")):e}return h};xi.match=xi;xi.matcher=(t,e)=>Jf(t,e);xi.isMatch=(t,e,r)=>Jf(e,r)(t);xi.any=xi.isMatch;xi.not=(t,e,r={})=>{e=[].concat(e).map(String);let s=new Set,a=[],n=f=>{r.onResult&&r.onResult(f),a.push(f.output)},c=new Set(xi(t,e,{...r,onResult:n}));for(let f of a)c.has(f)||s.add(f);return[...s]};xi.contains=(t,e,r)=>{if(typeof t!=\"string\")throw new TypeError(`Expected a string: \"${Xoe.inspect(t)}\"`);if(Array.isArray(e))return e.some(s=>xi.contains(t,s,r));if(typeof e==\"string\"){if(Zoe(t)||Zoe(e))return!1;if(t.includes(e)||t.startsWith(\"./\")&&t.slice(2).includes(e))return!0}return xi.isMatch(t,e,{...r,contains:!0})};xi.matchKeys=(t,e,r)=>{if(!E4.isObject(t))throw new TypeError(\"Expected the first argument to be an object\");let s=xi(Object.keys(t),e,r),a={};for(let n of s)a[n]=t[n];return a};xi.some=(t,e,r)=>{let s=[].concat(t);for(let a of[].concat(e)){let n=Jf(String(a),r);if(s.some(c=>n(c)))return!0}return!1};xi.every=(t,e,r)=>{let s=[].concat(t);for(let a of[].concat(e)){let n=Jf(String(a),r);if(!s.every(c=>n(c)))return!1}return!0};xi.all=(t,e,r)=>{if(typeof t!=\"string\")throw new TypeError(`Expected a string: \"${Xoe.inspect(t)}\"`);return[].concat(e).every(s=>Jf(s,r)(t))};xi.capture=(t,e,r)=>{let s=E4.isWindows(r),n=Jf.makeRe(String(t),{...r,capture:!0}).exec(s?E4.toPosixSlashes(e):e);if(n)return n.slice(1).map(c=>c===void 0?\"\":c)};xi.makeRe=(...t)=>Jf.makeRe(...t);xi.scan=(...t)=>Jf.scan(...t);xi.parse=(t,e)=>{let r=[];for(let s of[].concat(t||[]))for(let a of $oe(String(s),e))r.push(Jf.parse(a,e));return r};xi.braces=(t,e)=>{if(typeof t!=\"string\")throw new TypeError(\"Expected a string\");return e&&e.nobrace===!0||!/\\{.*\\}/.test(t)?[t]:$oe(t,e)};xi.braceExpand=(t,e)=>{if(typeof t!=\"string\")throw new TypeError(\"Expected a string\");return xi.braces(t,{...e,expand:!0})};eae.exports=xi});var rae=_((uFt,tae)=>{\"use strict\";tae.exports=({onlyFirst:t=!1}={})=>{let e=[\"[\\\\u001B\\\\u009B][[\\\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]+)*|[a-zA-Z\\\\d]+(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]*)*)?\\\\u0007)\",\"(?:(?:\\\\d{1,4}(?:;\\\\d{0,4})*)?[\\\\dA-PR-TZcf-ntqry=><~]))\"].join(\"|\");return new RegExp(e,t?void 0:\"g\")}});var dk=_((fFt,nae)=>{\"use strict\";var vze=rae();nae.exports=t=>typeof t==\"string\"?t.replace(vze(),\"\"):t});function iae(t){return Number.isSafeInteger(t)&&t>=0}var sae=Ze(()=>{});function oae(t){return t!=null&&typeof t!=\"function\"&&iae(t.length)}var aae=Ze(()=>{sae()});function Pc(t){return t===\"__proto__\"}var wB=Ze(()=>{});function NE(t){switch(typeof t){case\"number\":case\"symbol\":return!1;case\"string\":return t.includes(\".\")||t.includes(\"[\")||t.includes(\"]\")}}var mk=Ze(()=>{});function OE(t){return typeof t==\"string\"||typeof t==\"symbol\"?t:Object.is(t?.valueOf?.(),-0)?\"-0\":String(t)}var yk=Ze(()=>{});function Mu(t){let e=[],r=t.length;if(r===0)return e;let s=0,a=\"\",n=\"\",c=!1;for(t.charCodeAt(0)===46&&(e.push(\"\"),s++);s<r;){let f=t[s];n?f===\"\\\\\"&&s+1<r?(s++,a+=t[s]):f===n?n=\"\":a+=f:c?f==='\"'||f===\"'\"?n=f:f===\"]\"?(c=!1,e.push(a),a=\"\"):a+=f:f===\"[\"?(c=!0,a&&(e.push(a),a=\"\")):f===\".\"?a&&(e.push(a),a=\"\"):a+=f,s++}return a&&e.push(a),e}var LE=Ze(()=>{});function va(t,e,r){if(t==null)return r;switch(typeof e){case\"string\":{if(Pc(e))return r;let s=t[e];return s===void 0?NE(e)?va(t,Mu(e),r):r:s}case\"number\":case\"symbol\":{typeof e==\"number\"&&(e=OE(e));let s=t[e];return s===void 0?r:s}default:{if(Array.isArray(e))return Sze(t,e,r);if(Object.is(e?.valueOf(),-0)?e=\"-0\":e=String(e),Pc(e))return r;let s=t[e];return s===void 0?r:s}}}function Sze(t,e,r){if(e.length===0)return r;let s=t;for(let a=0;a<e.length;a++){if(s==null||Pc(e[a]))return r;s=s[e[a]]}return s===void 0?r:s}var Ek=Ze(()=>{wB();mk();yk();LE()});function I4(t){return t!==null&&(typeof t==\"object\"||typeof t==\"function\")}var lae=Ze(()=>{});function ME(t){return t==null||typeof t!=\"object\"&&typeof t!=\"function\"}var Ik=Ze(()=>{});function Ck(t,e){return t===e||Number.isNaN(t)&&Number.isNaN(e)}var C4=Ze(()=>{});function Wd(t){return Object.getOwnPropertySymbols(t).filter(e=>Object.prototype.propertyIsEnumerable.call(t,e))}var wk=Ze(()=>{});function Yd(t){return t==null?t===void 0?\"[object Undefined]\":\"[object Null]\":Object.prototype.toString.call(t)}var Bk=Ze(()=>{});var vk,UE,_E,HE,Vd,Sk,Dk,Pk,bk,xk,cae,kk,jE,uae,Qk,Rk,Tk,Fk,Nk,fae,Ok,Lk,Mk,Aae,Uk,_k,Hk=Ze(()=>{vk=\"[object RegExp]\",UE=\"[object String]\",_E=\"[object Number]\",HE=\"[object Boolean]\",Vd=\"[object Arguments]\",Sk=\"[object Symbol]\",Dk=\"[object Date]\",Pk=\"[object Map]\",bk=\"[object Set]\",xk=\"[object Array]\",cae=\"[object Function]\",kk=\"[object ArrayBuffer]\",jE=\"[object Object]\",uae=\"[object Error]\",Qk=\"[object DataView]\",Rk=\"[object Uint8Array]\",Tk=\"[object Uint8ClampedArray]\",Fk=\"[object Uint16Array]\",Nk=\"[object Uint32Array]\",fae=\"[object BigUint64Array]\",Ok=\"[object Int8Array]\",Lk=\"[object Int16Array]\",Mk=\"[object Int32Array]\",Aae=\"[object BigInt64Array]\",Uk=\"[object Float32Array]\",_k=\"[object Float64Array]\"});function GE(t){return ArrayBuffer.isView(t)&&!(t instanceof DataView)}var jk=Ze(()=>{});function pae(t,e){return u0(t,void 0,t,new Map,e)}function u0(t,e,r,s=new Map,a=void 0){let n=a?.(t,e,r,s);if(n!=null)return n;if(ME(t))return t;if(s.has(t))return s.get(t);if(Array.isArray(t)){let c=new Array(t.length);s.set(t,c);for(let f=0;f<t.length;f++)c[f]=u0(t[f],f,r,s,a);return Object.hasOwn(t,\"index\")&&(c.index=t.index),Object.hasOwn(t,\"input\")&&(c.input=t.input),c}if(t instanceof Date)return new Date(t.getTime());if(t instanceof RegExp){let c=new RegExp(t.source,t.flags);return c.lastIndex=t.lastIndex,c}if(t instanceof Map){let c=new Map;s.set(t,c);for(let[f,p]of t)c.set(f,u0(p,f,r,s,a));return c}if(t instanceof Set){let c=new Set;s.set(t,c);for(let f of t)c.add(u0(f,void 0,r,s,a));return c}if(typeof Buffer<\"u\"&&Buffer.isBuffer(t))return t.subarray();if(GE(t)){let c=new(Object.getPrototypeOf(t)).constructor(t.length);s.set(t,c);for(let f=0;f<t.length;f++)c[f]=u0(t[f],f,r,s,a);return c}if(t instanceof ArrayBuffer||typeof SharedArrayBuffer<\"u\"&&t instanceof SharedArrayBuffer)return t.slice(0);if(t instanceof DataView){let c=new DataView(t.buffer.slice(0),t.byteOffset,t.byteLength);return s.set(t,c),c0(c,t,r,s,a),c}if(typeof File<\"u\"&&t instanceof File){let c=new File([t],t.name,{type:t.type});return s.set(t,c),c0(c,t,r,s,a),c}if(t instanceof Blob){let c=new Blob([t],{type:t.type});return s.set(t,c),c0(c,t,r,s,a),c}if(t instanceof Error){let c=new t.constructor;return s.set(t,c),c.message=t.message,c.name=t.name,c.stack=t.stack,c.cause=t.cause,c0(c,t,r,s,a),c}if(typeof t==\"object\"&&Dze(t)){let c=Object.create(Object.getPrototypeOf(t));return s.set(t,c),c0(c,t,r,s,a),c}return t}function c0(t,e,r=t,s,a){let n=[...Object.keys(e),...Wd(e)];for(let c=0;c<n.length;c++){let f=n[c],p=Object.getOwnPropertyDescriptor(t,f);(p==null||p.writable)&&(t[f]=u0(e[f],f,r,s,a))}}function Dze(t){switch(Yd(t)){case Vd:case xk:case kk:case Qk:case HE:case Dk:case Uk:case _k:case Ok:case Lk:case Mk:case Pk:case _E:case jE:case vk:case bk:case UE:case Sk:case Rk:case Tk:case Fk:case Nk:return!0;default:return!1}}var w4=Ze(()=>{wk();Bk();Hk();Ik();jk()});function hae(t){return u0(t,void 0,t,new Map,void 0)}var gae=Ze(()=>{w4()});function dae(t,e){return pae(t,(r,s,a,n)=>{let c=e?.(r,s,a,n);if(c!=null)return c;if(typeof t==\"object\")switch(Object.prototype.toString.call(t)){case _E:case UE:case HE:{let f=new t.constructor(t?.valueOf());return c0(f,t),f}case Vd:{let f={};return c0(f,t),f.length=t.length,f[Symbol.iterator]=t[Symbol.iterator],f}default:return}})}var mae=Ze(()=>{w4();Hk()});function f0(t){return dae(t)}var B4=Ze(()=>{mae()});function Gk(t,e=Number.MAX_SAFE_INTEGER){switch(typeof t){case\"number\":return Number.isInteger(t)&&t>=0&&t<e;case\"symbol\":return!1;case\"string\":return Pze.test(t)}}var Pze,v4=Ze(()=>{Pze=/^(?:0|[1-9]\\d*)$/});function BB(t){return t!==null&&typeof t==\"object\"&&Yd(t)===\"[object Arguments]\"}var S4=Ze(()=>{Bk()});function vB(t,e){let r;if(Array.isArray(e)?r=e:typeof e==\"string\"&&NE(e)&&t?.[e]==null?r=Mu(e):r=[e],r.length===0)return!1;let s=t;for(let a=0;a<r.length;a++){let n=r[a];if((s==null||!Object.hasOwn(s,n))&&!((Array.isArray(s)||BB(s))&&Gk(n)&&n<s.length))return!1;s=s[n]}return!0}var D4=Ze(()=>{mk();v4();S4();LE()});function P4(t){return typeof t==\"object\"&&t!==null}var yae=Ze(()=>{});function Eae(t){return typeof t==\"symbol\"||t instanceof Symbol}var Iae=Ze(()=>{});function Cae(t,e){return Array.isArray(t)?!1:typeof t==\"number\"||typeof t==\"boolean\"||t==null||Eae(t)?!0:typeof t==\"string\"&&(xze.test(t)||!bze.test(t))||e!=null&&Object.hasOwn(e,t)}var bze,xze,wae=Ze(()=>{Iae();bze=/\\.|\\[(?:[^[\\]]*|([\"'])(?:(?!\\1)[^\\\\]|\\\\.)*?\\1)\\]/,xze=/^\\w*$/});function A0(t,e){if(t==null)return!0;switch(typeof e){case\"symbol\":case\"number\":case\"object\":{if(Array.isArray(e))return Bae(t,e);if(typeof e==\"number\"?e=OE(e):typeof e==\"object\"&&(Object.is(e?.valueOf(),-0)?e=\"-0\":e=String(e)),Pc(e))return!1;if(t?.[e]===void 0)return!0;try{return delete t[e],!0}catch{return!1}}case\"string\":{if(t?.[e]===void 0&&NE(e))return Bae(t,Mu(e));if(Pc(e))return!1;try{return delete t[e],!0}catch{return!1}}}}function Bae(t,e){let r=va(t,e.slice(0,-1),t),s=e[e.length-1];if(r?.[s]===void 0)return!0;if(Pc(s))return!1;try{return delete r[s],!0}catch{return!1}}var b4=Ze(()=>{Ek();wB();mk();yk();LE()});function vae(t){return t==null}var Sae=Ze(()=>{});var Dae,Pae=Ze(()=>{C4();Dae=(t,e,r)=>{let s=t[e];(!(Object.hasOwn(t,e)&&Ck(s,r))||r===void 0&&!(e in t))&&(t[e]=r)}});function bae(t,e,r,s){if(t==null&&!I4(t))return t;let a=Cae(e,t)?[e]:Array.isArray(e)?e:typeof e==\"string\"?Mu(e):[e],n=t;for(let c=0;c<a.length&&n!=null;c++){let f=OE(a[c]);if(Pc(f))continue;let p;if(c===a.length-1)p=r(n[f]);else{let h=n[f],E=s?.(h,f,t);p=E!==void 0?E:I4(h)?h:Gk(a[c+1])?[]:{}}Dae(n,f,p),n=n[f]}return t}var xae=Ze(()=>{wB();Pae();v4();wae();yk();lae();LE()});function Jd(t,e,r){return bae(t,e,()=>r,()=>{})}var x4=Ze(()=>{xae()});function kae(t,e=0,r={}){typeof r!=\"object\"&&(r={});let s=null,a=null,n=null,c=0,f=null,p,{leading:h=!1,trailing:E=!0,maxWait:C}=r,S=\"maxWait\"in r,b=S?Math.max(Number(C)||0,e):0,I=ue=>(s!==null&&(p=t.apply(a,s)),s=a=null,c=ue,p),T=ue=>(c=ue,f=setTimeout(ee,e),h&&s!==null?I(ue):p),N=ue=>(f=null,E&&s!==null?I(ue):p),U=ue=>{if(n===null)return!0;let le=ue-n,me=le>=e||le<0,pe=S&&ue-c>=b;return me||pe},W=ue=>{let le=n===null?0:ue-n,me=e-le,pe=b-(ue-c);return S?Math.min(me,pe):me},ee=()=>{let ue=Date.now();if(U(ue))return N(ue);f=setTimeout(ee,W(ue))},ie=function(...ue){let le=Date.now(),me=U(le);if(s=ue,a=this,n=le,me){if(f===null)return T(le);if(S)return clearTimeout(f),f=setTimeout(ee,e),I(le)}return f===null&&(f=setTimeout(ee,e)),p};return ie.cancel=()=>{f!==null&&clearTimeout(f),c=0,n=s=a=f=null},ie.flush=()=>f===null?p:N(Date.now()),ie}var Qae=Ze(()=>{});function k4(t,e=0,r={}){let{leading:s=!0,trailing:a=!0}=r;return kae(t,e,{leading:s,maxWait:e,trailing:a})}var Rae=Ze(()=>{Qae()});function Q4(t){if(t==null)return\"\";if(typeof t==\"string\")return t;if(Array.isArray(t))return t.map(Q4).join(\",\");let e=String(t);return e===\"0\"&&Object.is(Number(t),-0)?\"-0\":e}var Tae=Ze(()=>{});function R4(t){if(!t||typeof t!=\"object\")return!1;let e=Object.getPrototypeOf(t);return e===null||e===Object.prototype||Object.getPrototypeOf(e)===null?Object.prototype.toString.call(t)===\"[object Object]\":!1}var Fae=Ze(()=>{});function Nae(t,e,r){return SB(t,e,void 0,void 0,void 0,void 0,r)}function SB(t,e,r,s,a,n,c){let f=c(t,e,r,s,a,n);if(f!==void 0)return f;if(typeof t==typeof e)switch(typeof t){case\"bigint\":case\"string\":case\"boolean\":case\"symbol\":case\"undefined\":return t===e;case\"number\":return t===e||Object.is(t,e);case\"function\":return t===e;case\"object\":return DB(t,e,n,c)}return DB(t,e,n,c)}function DB(t,e,r,s){if(Object.is(t,e))return!0;let a=Yd(t),n=Yd(e);if(a===Vd&&(a=jE),n===Vd&&(n=jE),a!==n)return!1;switch(a){case UE:return t.toString()===e.toString();case _E:{let p=t.valueOf(),h=e.valueOf();return Ck(p,h)}case HE:case Dk:case Sk:return Object.is(t.valueOf(),e.valueOf());case vk:return t.source===e.source&&t.flags===e.flags;case cae:return t===e}r=r??new Map;let c=r.get(t),f=r.get(e);if(c!=null&&f!=null)return c===e;r.set(t,e),r.set(e,t);try{switch(a){case Pk:{if(t.size!==e.size)return!1;for(let[p,h]of t.entries())if(!e.has(p)||!SB(h,e.get(p),p,t,e,r,s))return!1;return!0}case bk:{if(t.size!==e.size)return!1;let p=Array.from(t.values()),h=Array.from(e.values());for(let E=0;E<p.length;E++){let C=p[E],S=h.findIndex(b=>SB(C,b,void 0,t,e,r,s));if(S===-1)return!1;h.splice(S,1)}return!0}case xk:case Rk:case Tk:case Fk:case Nk:case fae:case Ok:case Lk:case Mk:case Aae:case Uk:case _k:{if(typeof Buffer<\"u\"&&Buffer.isBuffer(t)!==Buffer.isBuffer(e)||t.length!==e.length)return!1;for(let p=0;p<t.length;p++)if(!SB(t[p],e[p],p,t,e,r,s))return!1;return!0}case kk:return t.byteLength!==e.byteLength?!1:DB(new Uint8Array(t),new Uint8Array(e),r,s);case Qk:return t.byteLength!==e.byteLength||t.byteOffset!==e.byteOffset?!1:DB(new Uint8Array(t),new Uint8Array(e),r,s);case uae:return t.name===e.name&&t.message===e.message;case jE:{if(!(DB(t.constructor,e.constructor,r,s)||R4(t)&&R4(e)))return!1;let h=[...Object.keys(t),...Wd(t)],E=[...Object.keys(e),...Wd(e)];if(h.length!==E.length)return!1;for(let C=0;C<h.length;C++){let S=h[C],b=t[S];if(!Object.hasOwn(e,S))return!1;let I=e[S];if(!SB(b,I,S,t,e,r,s))return!1}return!0}default:return!1}}finally{r.delete(t),r.delete(e)}}var Oae=Ze(()=>{Fae();wk();Bk();Hk();C4()});function Lae(){}var Mae=Ze(()=>{});function T4(t,e){return Nae(t,e,Lae)}var Uae=Ze(()=>{Oae();Mae()});function _ae(t){return GE(t)}var Hae=Ze(()=>{jk()});function jae(t){if(typeof t!=\"object\"||t==null)return!1;if(Object.getPrototypeOf(t)===null)return!0;if(Object.prototype.toString.call(t)!==\"[object Object]\"){let r=t[Symbol.toStringTag];return r==null||!Object.getOwnPropertyDescriptor(t,Symbol.toStringTag)?.writable?!1:t.toString()===`[object ${r}]`}let e=t;for(;Object.getPrototypeOf(e)!==null;)e=Object.getPrototypeOf(e);return Object.getPrototypeOf(t)===e}var Gae=Ze(()=>{});function qae(t){if(ME(t))return t;if(Array.isArray(t)||GE(t)||t instanceof ArrayBuffer||typeof SharedArrayBuffer<\"u\"&&t instanceof SharedArrayBuffer)return t.slice(0);let e=Object.getPrototypeOf(t),r=e.constructor;if(t instanceof Date||t instanceof Map||t instanceof Set)return new r(t);if(t instanceof RegExp){let s=new r(t);return s.lastIndex=t.lastIndex,s}if(t instanceof DataView)return new r(t.buffer.slice(0));if(t instanceof Error){let s=new r(t.message);return s.stack=t.stack,s.name=t.name,s.cause=t.cause,s}if(typeof File<\"u\"&&t instanceof File)return new r([t],t.name,{type:t.type,lastModified:t.lastModified});if(typeof t==\"object\"){let s=Object.create(e);return Object.assign(s,t)}return t}var Wae=Ze(()=>{Ik();jk()});function F4(t,...e){let r=e.slice(0,-1),s=e[e.length-1],a=t;for(let n=0;n<r.length;n++){let c=r[n];a=qk(a,c,s,new Map)}return a}function qk(t,e,r,s){if(ME(t)&&(t=Object(t)),e==null||typeof e!=\"object\")return t;if(s.has(e))return qae(s.get(e));if(s.set(e,t),Array.isArray(e)){e=e.slice();for(let n=0;n<e.length;n++)e[n]=e[n]??void 0}let a=[...Object.keys(e),...Wd(e)];for(let n=0;n<a.length;n++){let c=a[n];if(Pc(c))continue;let f=e[c],p=t[c];if(BB(f)&&(f={...f}),BB(p)&&(p={...p}),typeof Buffer<\"u\"&&Buffer.isBuffer(f)&&(f=f0(f)),Array.isArray(f))if(typeof p==\"object\"&&p!=null){let E=[],C=Reflect.ownKeys(p);for(let S=0;S<C.length;S++){let b=C[S];E[b]=p[b]}p=E}else p=[];let h=r(p,f,c,t,e,s);h!=null?t[c]=h:Array.isArray(f)||P4(p)&&P4(f)?t[c]=qk(p,f,r,s):p==null&&jae(f)?t[c]=qk({},f,r,s):p==null&&_ae(f)?t[c]=f0(f):(p===void 0||f!==void 0)&&(t[c]=f)}return t}var Yae=Ze(()=>{B4();wB();Wae();Ik();wk();S4();yae();Gae();Hae()});function N4(t,...e){if(t==null)return{};let r=hae(t);for(let s=0;s<e.length;s++){let a=e[s];switch(typeof a){case\"object\":{Array.isArray(a)||(a=Array.from(a));for(let n=0;n<a.length;n++){let c=a[n];A0(r,c)}break}case\"string\":case\"symbol\":case\"number\":{A0(r,a);break}}}return r}var Vae=Ze(()=>{b4();gae()});function Kd(t,...e){if(vae(t))return{};let r={};for(let s=0;s<e.length;s++){let a=e[s];switch(typeof a){case\"object\":{Array.isArray(a)||(oae(a)?a=Array.from(a):a=[a]);break}case\"string\":case\"symbol\":case\"number\":{a=[a];break}}for(let n of a){let c=va(t,n);c===void 0&&!vB(t,n)||(typeof n==\"string\"&&Object.hasOwn(t,n)?r[n]=c:Jd(r,n,c))}}return r}var Jae=Ze(()=>{Ek();D4();x4();aae();Sae()});function Kae(t){return t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()}var zae=Ze(()=>{});function PB(t){return Kae(Q4(t))}var Zae=Ze(()=>{zae();Tae()});var ql=Ze(()=>{Rae();Uae();B4();Ek();D4();Yae();Vae();Jae();x4();b4();Zae();LE()});var je={};Vt(je,{AsyncActions:()=>M4,BufferStream:()=>L4,CachingStrategy:()=>ale,DefaultStream:()=>U4,allSettledSafe:()=>Uu,assertNever:()=>H4,bufferStream:()=>WE,buildIgnorePattern:()=>Oze,convertMapsToIndexableObjects:()=>Yk,dynamicRequire:()=>bp,escapeRegExp:()=>Qze,getArrayWithDefault:()=>xB,getFactoryWithDefault:()=>Yl,getMapWithDefault:()=>j4,getSetWithDefault:()=>Pp,groupBy:()=>Uze,isIndexableObject:()=>O4,isPathLike:()=>Lze,isTaggedYarnVersion:()=>kze,makeDeferred:()=>ile,mapAndFilter:()=>Wl,mapAndFind:()=>p0,mergeIntoTarget:()=>cle,overrideType:()=>Rze,parseBoolean:()=>kB,parseInt:()=>YE,parseOptionalBoolean:()=>lle,plural:()=>Wk,prettifyAsyncErrors:()=>qE,prettifySyncErrors:()=>G4,releaseAfterUseAsync:()=>Fze,replaceEnvVariables:()=>Vk,sortMap:()=>qs,toMerged:()=>Mze,tryParseOptionalBoolean:()=>q4,validateEnum:()=>Tze});function kze(t){return!!(tle.default.valid(t)&&t.match(/^[^-]+(-rc\\.[0-9]+)?$/))}function Wk(t,{one:e,more:r,zero:s=r}){return t===0?s:t===1?e:r}function Qze(t){return t.replace(/[.*+?^${}()|[\\]\\\\]/g,\"\\\\$&\")}function Rze(t){}function H4(t){throw new Error(`Assertion failed: Unexpected object '${t}'`)}function Tze(t,e){let r=Object.values(t);if(!r.includes(e))throw new nt(`Invalid value for enumeration: ${JSON.stringify(e)} (expected one of ${r.map(s=>JSON.stringify(s)).join(\", \")})`);return e}function Wl(t,e){let r=[];for(let s of t){let a=e(s);a!==rle&&r.push(a)}return r}function p0(t,e){for(let r of t){let s=e(r);if(s!==nle)return s}}function O4(t){return typeof t==\"object\"&&t!==null}async function Uu(t){let e=await Promise.allSettled(t),r=[];for(let s of e){if(s.status===\"rejected\")throw s.reason;r.push(s.value)}return r}function Yk(t){if(t instanceof Map&&(t=Object.fromEntries(t)),O4(t))for(let e of Object.keys(t)){let r=t[e];O4(r)&&(t[e]=Yk(r))}return t}function Yl(t,e,r){let s=t.get(e);return typeof s>\"u\"&&t.set(e,s=r()),s}function xB(t,e){let r=t.get(e);return typeof r>\"u\"&&t.set(e,r=[]),r}function Pp(t,e){let r=t.get(e);return typeof r>\"u\"&&t.set(e,r=new Set),r}function j4(t,e){let r=t.get(e);return typeof r>\"u\"&&t.set(e,r=new Map),r}async function Fze(t,e){if(e==null)return await t();try{return await t()}finally{await e()}}async function qE(t,e){try{return await t()}catch(r){throw r.message=e(r.message),r}}function G4(t,e){try{return t()}catch(r){throw r.message=e(r.message),r}}async function WE(t){return await new Promise((e,r)=>{let s=[];t.on(\"error\",a=>{r(a)}),t.on(\"data\",a=>{s.push(a)}),t.on(\"end\",()=>{e(Buffer.concat(s))})})}function ile(){let t,e;return{promise:new Promise((s,a)=>{t=s,e=a}),resolve:t,reject:e}}function sle(t){return bB(fe.fromPortablePath(t))}function ole(path){let physicalPath=fe.fromPortablePath(path),currentCacheEntry=bB.cache[physicalPath];delete bB.cache[physicalPath];let result;try{result=sle(physicalPath);let freshCacheEntry=bB.cache[physicalPath],dynamicModule=eval(\"module\"),freshCacheIndex=dynamicModule.children.indexOf(freshCacheEntry);freshCacheIndex!==-1&&dynamicModule.children.splice(freshCacheIndex,1)}finally{bB.cache[physicalPath]=currentCacheEntry}return result}function Nze(t){let e=Xae.get(t),r=ce.statSync(t);if(e?.mtime===r.mtimeMs)return e.instance;let s=ole(t);return Xae.set(t,{mtime:r.mtimeMs,instance:s}),s}function bp(t,{cachingStrategy:e=2}={}){switch(e){case 0:return ole(t);case 1:return Nze(t);case 2:return sle(t);default:throw new Error(\"Unsupported caching strategy\")}}function qs(t,e){let r=Array.from(t);Array.isArray(e)||(e=[e]);let s=[];for(let n of e)s.push(r.map(c=>n(c)));let a=r.map((n,c)=>c);return a.sort((n,c)=>{for(let f of s){let p=f[n]<f[c]?-1:f[n]>f[c]?1:0;if(p!==0)return p}return 0}),a.map(n=>r[n])}function Oze(t){return t.length===0?null:t.map(e=>`(${$ae.default.makeRe(e,{windows:!1,dot:!0}).source})`).join(\"|\")}function Vk(t,{env:e}){let r=/\\${(?<variableName>[\\d\\w_]+)(?<colon>:)?(?:-(?<fallback>[^}]*))?}/g;return t.replace(r,(...s)=>{let{variableName:a,colon:n,fallback:c}=s[s.length-1],f=Object.hasOwn(e,a),p=e[a];if(p||f&&!n)return p;if(c!=null)return c;throw new nt(`Environment variable not found (${a})`)})}function kB(t){switch(t){case\"true\":case\"1\":case 1:case!0:return!0;case\"false\":case\"0\":case 0:case!1:return!1;default:throw new Error(`Couldn't parse \"${t}\" as a boolean`)}}function lle(t){return typeof t>\"u\"?t:kB(t)}function q4(t){try{return lle(t)}catch{return null}}function Lze(t){return!!(fe.isAbsolute(t)||t.match(/^(\\.{1,2}|~)\\//))}function cle(t,...e){let r=c=>({value:c}),s=r(t),a=e.map(c=>r(c)),{value:n}=F4(s,...a,(c,f)=>{if(Array.isArray(c)&&Array.isArray(f)){for(let p of f)c.find(h=>T4(h,p))||c.push(p);return c}});return n}function Mze(...t){return cle({},...t)}function Uze(t,e){let r=Object.create(null);for(let s of t){let a=s[e];r[a]??=[],r[a].push(s)}return r}function YE(t){return typeof t==\"string\"?Number.parseInt(t,10):t}var $ae,ele,tle,_4,rle,nle,L4,M4,U4,bB,Xae,ale,bc=Ze(()=>{Dt();Yt();ql();$ae=ut(Go()),ele=ut(Ld()),tle=ut(Ai()),_4=Ie(\"stream\");rle=Symbol();Wl.skip=rle;nle=Symbol();p0.skip=nle;L4=class extends _4.Transform{constructor(){super(...arguments);this.chunks=[]}_transform(r,s,a){if(s!==\"buffer\"||!Buffer.isBuffer(r))throw new Error(\"Assertion failed: BufferStream only accept buffers\");this.chunks.push(r),a(null,null)}_flush(r){r(null,Buffer.concat(this.chunks))}};M4=class{constructor(e){this.deferred=new Map;this.promises=new Map;this.limit=(0,ele.default)(e)}set(e,r){let s=this.deferred.get(e);typeof s>\"u\"&&this.deferred.set(e,s=ile());let a=this.limit(()=>r());return this.promises.set(e,a),a.then(()=>{this.promises.get(e)===a&&s.resolve()},n=>{this.promises.get(e)===a&&s.reject(n)}),s.promise}reduce(e,r){let s=this.promises.get(e)??Promise.resolve();this.set(e,()=>r(s))}async wait(){await Promise.all(this.promises.values())}},U4=class extends _4.Transform{constructor(r=Buffer.alloc(0)){super();this.active=!0;this.ifEmpty=r}_transform(r,s,a){if(s!==\"buffer\"||!Buffer.isBuffer(r))throw new Error(\"Assertion failed: DefaultStream only accept buffers\");this.active=!1,a(null,r)}_flush(r){this.active&&this.ifEmpty.length>0?r(null,this.ifEmpty):r(null)}},bB=eval(\"require\");Xae=new Map;ale=(s=>(s[s.NoCache=0]=\"NoCache\",s[s.FsTime=1]=\"FsTime\",s[s.Node=2]=\"Node\",s))(ale||{})});var VE,W4,Y4,ule=Ze(()=>{VE=(r=>(r.HARD=\"HARD\",r.SOFT=\"SOFT\",r))(VE||{}),W4=(s=>(s.Dependency=\"Dependency\",s.PeerDependency=\"PeerDependency\",s.PeerDependencyMeta=\"PeerDependencyMeta\",s))(W4||{}),Y4=(s=>(s.Inactive=\"inactive\",s.Redundant=\"redundant\",s.Active=\"active\",s))(Y4||{})});var he={};Vt(he,{LogLevel:()=>$k,Style:()=>zk,Type:()=>ht,addLogFilterSupport:()=>TB,applyColor:()=>ri,applyHyperlink:()=>KE,applyStyle:()=>zd,json:()=>Zd,jsonOrPretty:()=>jze,mark:()=>Z4,pretty:()=>Ht,prettyField:()=>Kf,prettyList:()=>z4,prettyTruncatedLocatorList:()=>Xk,stripAnsi:()=>JE.default,supportsColor:()=>Zk,supportsHyperlinks:()=>K4,tuple:()=>_u});function fle(t){let e=[\"KiB\",\"MiB\",\"GiB\",\"TiB\"],r=e.length;for(;r>1&&t<1024**r;)r-=1;let s=1024**r;return`${Math.floor(t*100/s)/100} ${e[r-1]}`}function Jk(t,e){if(Array.isArray(e))return e.length===0?ri(t,\"[]\",ht.CODE):ri(t,\"[ \",ht.CODE)+e.map(r=>Jk(t,r)).join(\", \")+ri(t,\" ]\",ht.CODE);if(typeof e==\"string\")return ri(t,JSON.stringify(e),ht.STRING);if(typeof e==\"number\")return ri(t,JSON.stringify(e),ht.NUMBER);if(typeof e==\"boolean\")return ri(t,JSON.stringify(e),ht.BOOLEAN);if(e===null)return ri(t,\"null\",ht.NULL);if(typeof e==\"object\"&&Object.getPrototypeOf(e)===Object.prototype){let r=Object.entries(e);return r.length===0?ri(t,\"{}\",ht.CODE):ri(t,\"{ \",ht.CODE)+r.map(([s,a])=>`${Jk(t,s)}: ${Jk(t,a)}`).join(\", \")+ri(t,\" }\",ht.CODE)}if(typeof e>\"u\")return ri(t,\"undefined\",ht.NULL);throw new Error(\"Assertion failed: The value doesn't seem to be a valid JSON object\")}function _u(t,e){return[e,t]}function zd(t,e,r){return t.get(\"enableColors\")&&r&2&&(e=RB.default.bold(e)),e}function ri(t,e,r){if(!t.get(\"enableColors\"))return e;let s=_ze.get(r);if(s===null)return e;let a=typeof s>\"u\"?r:J4.level>=3?s[0]:s[1],n=typeof a==\"number\"?V4.ansi256(a):a.startsWith(\"#\")?V4.hex(a):V4[a];if(typeof n!=\"function\")throw new Error(`Invalid format type ${a}`);return n(e)}function KE(t,e,r){return t.get(\"enableHyperlinks\")?Hze?`\\x1B]8;;${r}\\x1B\\\\${e}\\x1B]8;;\\x1B\\\\`:`\\x1B]8;;${r}\\x07${e}\\x1B]8;;\\x07`:e}function Ht(t,e,r){if(e===null)return ri(t,\"null\",ht.NULL);if(Object.hasOwn(Kk,r))return Kk[r].pretty(t,e);if(typeof e!=\"string\")throw new Error(`Assertion failed: Expected the value to be a string, got ${typeof e}`);return ri(t,e,r)}function z4(t,e,r,{separator:s=\", \"}={}){return[...e].map(a=>Ht(t,a,r)).join(s)}function Zd(t,e){if(t===null)return null;if(Object.hasOwn(Kk,e))return Kk[e].json(t);if(typeof t!=\"string\")throw new Error(`Assertion failed: Expected the value to be a string, got ${typeof t}`);return t}function jze(t,e,[r,s]){return t?Zd(r,s):Ht(e,r,s)}function Z4(t){return{Check:ri(t,\"\\u2713\",\"green\"),Cross:ri(t,\"\\u2718\",\"red\"),Question:ri(t,\"?\",\"cyan\")}}function Kf(t,{label:e,value:[r,s]}){return`${Ht(t,e,ht.CODE)}: ${Ht(t,r,s)}`}function Xk(t,e,r){let s=[],a=[...e],n=r;for(;a.length>0;){let h=a[0],E=`${Yr(t,h)}, `,C=X4(h).length+2;if(s.length>0&&n<C)break;s.push([E,C]),n-=C,a.shift()}if(a.length===0)return s.map(([h])=>h).join(\"\").slice(0,-2);let c=\"X\".repeat(a.length.toString().length),f=`and ${c} more.`,p=a.length;for(;s.length>1&&n<f.length;)n+=s[s.length-1][1],p+=1,s.pop();return[s.map(([h])=>h).join(\"\"),f.replace(c,Ht(t,p,ht.NUMBER))].join(\"\")}function TB(t,{configuration:e}){let r=e.get(\"logFilters\"),s=new Map,a=new Map,n=[];for(let C of r){let S=C.get(\"level\");if(typeof S>\"u\")continue;let b=C.get(\"code\");typeof b<\"u\"&&s.set(b,S);let I=C.get(\"text\");typeof I<\"u\"&&a.set(I,S);let T=C.get(\"pattern\");typeof T<\"u\"&&n.push([Ale.default.matcher(T,{contains:!0}),S])}n.reverse();let c=(C,S,b)=>{if(C===null||C===0)return b;let I=a.size>0||n.length>0?(0,JE.default)(S):S;if(a.size>0){let T=a.get(I);if(typeof T<\"u\")return T??b}if(n.length>0){for(let[T,N]of n)if(T(I))return N??b}if(s.size>0){let T=s.get(Yf(C));if(typeof T<\"u\")return T??b}return b},f=t.reportInfo,p=t.reportWarning,h=t.reportError,E=function(C,S,b,I){switch(c(S,b,I)){case\"info\":f.call(C,S,b);break;case\"warning\":p.call(C,S??0,b);break;case\"error\":h.call(C,S??0,b);break}};t.reportInfo=function(...C){return E(this,...C,\"info\")},t.reportWarning=function(...C){return E(this,...C,\"warning\")},t.reportError=function(...C){return E(this,...C,\"error\")}}var RB,QB,Ale,JE,ht,zk,J4,Zk,K4,V4,_ze,qo,Kk,Hze,$k,xc=Ze(()=>{Dt();RB=ut(RE()),QB=ut(Fd());Yt();Ale=ut(Go()),JE=ut(dk());Gx();Wo();ht={NO_HINT:\"NO_HINT\",ID:\"ID\",NULL:\"NULL\",SCOPE:\"SCOPE\",NAME:\"NAME\",RANGE:\"RANGE\",REFERENCE:\"REFERENCE\",NUMBER:\"NUMBER\",STRING:\"STRING\",BOOLEAN:\"BOOLEAN\",PATH:\"PATH\",URL:\"URL\",ADDED:\"ADDED\",REMOVED:\"REMOVED\",CODE:\"CODE\",INSPECT:\"INSPECT\",DURATION:\"DURATION\",SIZE:\"SIZE\",SIZE_DIFF:\"SIZE_DIFF\",IDENT:\"IDENT\",DESCRIPTOR:\"DESCRIPTOR\",LOCATOR:\"LOCATOR\",RESOLUTION:\"RESOLUTION\",DEPENDENT:\"DEPENDENT\",PACKAGE_EXTENSION:\"PACKAGE_EXTENSION\",SETTING:\"SETTING\",MARKDOWN:\"MARKDOWN\",MARKDOWN_INLINE:\"MARKDOWN_INLINE\"},zk=(e=>(e[e.BOLD=2]=\"BOLD\",e))(zk||{}),J4=QB.default.GITHUB_ACTIONS?{level:2}:RB.default.supportsColor?{level:RB.default.supportsColor.level}:{level:0},Zk=J4.level!==0,K4=Zk&&!QB.default.GITHUB_ACTIONS&&!QB.default.CIRCLE&&!QB.default.GITLAB,V4=new RB.default.Instance(J4),_ze=new Map([[ht.NO_HINT,null],[ht.NULL,[\"#a853b5\",129]],[ht.SCOPE,[\"#d75f00\",166]],[ht.NAME,[\"#d7875f\",173]],[ht.RANGE,[\"#00afaf\",37]],[ht.REFERENCE,[\"#87afff\",111]],[ht.NUMBER,[\"#ffd700\",220]],[ht.STRING,[\"#b4bd68\",32]],[ht.BOOLEAN,[\"#faa023\",209]],[ht.PATH,[\"#d75fd7\",170]],[ht.URL,[\"#d75fd7\",170]],[ht.ADDED,[\"#5faf00\",70]],[ht.REMOVED,[\"#ff3131\",160]],[ht.CODE,[\"#87afff\",111]],[ht.SIZE,[\"#ffd700\",220]]]),qo=t=>t;Kk={[ht.ID]:qo({pretty:(t,e)=>typeof e==\"number\"?ri(t,`${e}`,ht.NUMBER):ri(t,e,ht.CODE),json:t=>t}),[ht.INSPECT]:qo({pretty:(t,e)=>Jk(t,e),json:t=>t}),[ht.NUMBER]:qo({pretty:(t,e)=>ri(t,`${e}`,ht.NUMBER),json:t=>t}),[ht.IDENT]:qo({pretty:(t,e)=>Xi(t,e),json:t=>un(t)}),[ht.LOCATOR]:qo({pretty:(t,e)=>Yr(t,e),json:t=>ll(t)}),[ht.DESCRIPTOR]:qo({pretty:(t,e)=>ni(t,e),json:t=>al(t)}),[ht.RESOLUTION]:qo({pretty:(t,{descriptor:e,locator:r})=>FB(t,e,r),json:({descriptor:t,locator:e})=>({descriptor:al(t),locator:e!==null?ll(e):null})}),[ht.DEPENDENT]:qo({pretty:(t,{locator:e,descriptor:r})=>$4(t,e,r),json:({locator:t,descriptor:e})=>({locator:ll(t),descriptor:al(e)})}),[ht.PACKAGE_EXTENSION]:qo({pretty:(t,e)=>{switch(e.type){case\"Dependency\":return`${Xi(t,e.parentDescriptor)} \\u27A4 ${ri(t,\"dependencies\",ht.CODE)} \\u27A4 ${Xi(t,e.descriptor)}`;case\"PeerDependency\":return`${Xi(t,e.parentDescriptor)} \\u27A4 ${ri(t,\"peerDependencies\",ht.CODE)} \\u27A4 ${Xi(t,e.descriptor)}`;case\"PeerDependencyMeta\":return`${Xi(t,e.parentDescriptor)} \\u27A4 ${ri(t,\"peerDependenciesMeta\",ht.CODE)} \\u27A4 ${Xi(t,Sa(e.selector))} \\u27A4 ${ri(t,e.key,ht.CODE)}`;default:throw new Error(`Assertion failed: Unsupported package extension type: ${e.type}`)}},json:t=>{switch(t.type){case\"Dependency\":return`${un(t.parentDescriptor)} > ${un(t.descriptor)}`;case\"PeerDependency\":return`${un(t.parentDescriptor)} >> ${un(t.descriptor)}`;case\"PeerDependencyMeta\":return`${un(t.parentDescriptor)} >> ${t.selector} / ${t.key}`;default:throw new Error(`Assertion failed: Unsupported package extension type: ${t.type}`)}}}),[ht.SETTING]:qo({pretty:(t,e)=>(t.get(e),KE(t,ri(t,e,ht.CODE),`https://yarnpkg.com/configuration/yarnrc#${e}`)),json:t=>t}),[ht.DURATION]:qo({pretty:(t,e)=>{if(e>1e3*60){let r=Math.floor(e/1e3/60),s=Math.ceil((e-r*60*1e3)/1e3);return s===0?`${r}m`:`${r}m ${s}s`}else{let r=Math.floor(e/1e3),s=e-r*1e3;return s===0?`${r}s`:`${r}s ${s}ms`}},json:t=>t}),[ht.SIZE]:qo({pretty:(t,e)=>ri(t,fle(e),ht.NUMBER),json:t=>t}),[ht.SIZE_DIFF]:qo({pretty:(t,e)=>{let r=e>=0?\"+\":\"-\",s=r===\"+\"?ht.REMOVED:ht.ADDED;return ri(t,`${r} ${fle(Math.max(Math.abs(e),1))}`,s)},json:t=>t}),[ht.PATH]:qo({pretty:(t,e)=>ri(t,fe.fromPortablePath(e),ht.PATH),json:t=>fe.fromPortablePath(t)}),[ht.MARKDOWN]:qo({pretty:(t,{text:e,format:r,paragraphs:s})=>Ho(e,{format:r,paragraphs:s}),json:({text:t})=>t}),[ht.MARKDOWN_INLINE]:qo({pretty:(t,e)=>(e=e.replace(/(`+)((?:.|[\\n])*?)\\1/g,(r,s,a)=>Ht(t,s+a+s,ht.CODE)),e=e.replace(/(\\*\\*)((?:.|[\\n])*?)\\1/g,(r,s,a)=>zd(t,a,2)),e),json:t=>t})};Hze=!!process.env.KONSOLE_VERSION;$k=(a=>(a.Error=\"error\",a.Warning=\"warning\",a.Info=\"info\",a.Discard=\"discard\",a))($k||{})});var ple=_(zE=>{\"use strict\";Object.defineProperty(zE,\"__esModule\",{value:!0});zE.splitWhen=zE.flatten=void 0;function Gze(t){return t.reduce((e,r)=>[].concat(e,r),[])}zE.flatten=Gze;function qze(t,e){let r=[[]],s=0;for(let a of t)e(a)?(s++,r[s]=[]):r[s].push(a);return r}zE.splitWhen=qze});var hle=_(eQ=>{\"use strict\";Object.defineProperty(eQ,\"__esModule\",{value:!0});eQ.isEnoentCodeError=void 0;function Wze(t){return t.code===\"ENOENT\"}eQ.isEnoentCodeError=Wze});var gle=_(tQ=>{\"use strict\";Object.defineProperty(tQ,\"__esModule\",{value:!0});tQ.createDirentFromStats=void 0;var e3=class{constructor(e,r){this.name=e,this.isBlockDevice=r.isBlockDevice.bind(r),this.isCharacterDevice=r.isCharacterDevice.bind(r),this.isDirectory=r.isDirectory.bind(r),this.isFIFO=r.isFIFO.bind(r),this.isFile=r.isFile.bind(r),this.isSocket=r.isSocket.bind(r),this.isSymbolicLink=r.isSymbolicLink.bind(r)}};function Yze(t,e){return new e3(t,e)}tQ.createDirentFromStats=Yze});var Ele=_(ls=>{\"use strict\";Object.defineProperty(ls,\"__esModule\",{value:!0});ls.convertPosixPathToPattern=ls.convertWindowsPathToPattern=ls.convertPathToPattern=ls.escapePosixPath=ls.escapeWindowsPath=ls.escape=ls.removeLeadingDotSegment=ls.makeAbsolute=ls.unixify=void 0;var Vze=Ie(\"os\"),Jze=Ie(\"path\"),dle=Vze.platform()===\"win32\",Kze=2,zze=/(\\\\?)([()*?[\\]{|}]|^!|[!+@](?=\\()|\\\\(?![!()*+?@[\\]{|}]))/g,Zze=/(\\\\?)([()[\\]{}]|^!|[!+@](?=\\())/g,Xze=/^\\\\\\\\([.?])/,$ze=/\\\\(?![!()+@[\\]{}])/g;function eZe(t){return t.replace(/\\\\/g,\"/\")}ls.unixify=eZe;function tZe(t,e){return Jze.resolve(t,e)}ls.makeAbsolute=tZe;function rZe(t){if(t.charAt(0)===\".\"){let e=t.charAt(1);if(e===\"/\"||e===\"\\\\\")return t.slice(Kze)}return t}ls.removeLeadingDotSegment=rZe;ls.escape=dle?t3:r3;function t3(t){return t.replace(Zze,\"\\\\$2\")}ls.escapeWindowsPath=t3;function r3(t){return t.replace(zze,\"\\\\$2\")}ls.escapePosixPath=r3;ls.convertPathToPattern=dle?mle:yle;function mle(t){return t3(t).replace(Xze,\"//$1\").replace($ze,\"/\")}ls.convertWindowsPathToPattern=mle;function yle(t){return r3(t)}ls.convertPosixPathToPattern=yle});var Cle=_((UOt,Ile)=>{Ile.exports=function(e){if(typeof e!=\"string\"||e===\"\")return!1;for(var r;r=/(\\\\).|([@?!+*]\\(.*\\))/g.exec(e);){if(r[2])return!0;e=e.slice(r.index+r[0].length)}return!1}});var vle=_((_Ot,Ble)=>{var nZe=Cle(),wle={\"{\":\"}\",\"(\":\")\",\"[\":\"]\"},iZe=function(t){if(t[0]===\"!\")return!0;for(var e=0,r=-2,s=-2,a=-2,n=-2,c=-2;e<t.length;){if(t[e]===\"*\"||t[e+1]===\"?\"&&/[\\].+)]/.test(t[e])||s!==-1&&t[e]===\"[\"&&t[e+1]!==\"]\"&&(s<e&&(s=t.indexOf(\"]\",e)),s>e&&(c===-1||c>s||(c=t.indexOf(\"\\\\\",e),c===-1||c>s)))||a!==-1&&t[e]===\"{\"&&t[e+1]!==\"}\"&&(a=t.indexOf(\"}\",e),a>e&&(c=t.indexOf(\"\\\\\",e),c===-1||c>a))||n!==-1&&t[e]===\"(\"&&t[e+1]===\"?\"&&/[:!=]/.test(t[e+2])&&t[e+3]!==\")\"&&(n=t.indexOf(\")\",e),n>e&&(c=t.indexOf(\"\\\\\",e),c===-1||c>n))||r!==-1&&t[e]===\"(\"&&t[e+1]!==\"|\"&&(r<e&&(r=t.indexOf(\"|\",e)),r!==-1&&t[r+1]!==\")\"&&(n=t.indexOf(\")\",r),n>r&&(c=t.indexOf(\"\\\\\",r),c===-1||c>n))))return!0;if(t[e]===\"\\\\\"){var f=t[e+1];e+=2;var p=wle[f];if(p){var h=t.indexOf(p,e);h!==-1&&(e=h+1)}if(t[e]===\"!\")return!0}else e++}return!1},sZe=function(t){if(t[0]===\"!\")return!0;for(var e=0;e<t.length;){if(/[*?{}()[\\]]/.test(t[e]))return!0;if(t[e]===\"\\\\\"){var r=t[e+1];e+=2;var s=wle[r];if(s){var a=t.indexOf(s,e);a!==-1&&(e=a+1)}if(t[e]===\"!\")return!0}else e++}return!1};Ble.exports=function(e,r){if(typeof e!=\"string\"||e===\"\")return!1;if(nZe(e))return!0;var s=iZe;return r&&r.strict===!1&&(s=sZe),s(e)}});var Dle=_((HOt,Sle)=>{\"use strict\";var oZe=vle(),aZe=Ie(\"path\").posix.dirname,lZe=Ie(\"os\").platform()===\"win32\",n3=\"/\",cZe=/\\\\/g,uZe=/[\\{\\[].*[\\}\\]]$/,fZe=/(^|[^\\\\])([\\{\\[]|\\([^\\)]+$)/,AZe=/\\\\([\\!\\*\\?\\|\\[\\]\\(\\)\\{\\}])/g;Sle.exports=function(e,r){var s=Object.assign({flipBackslashes:!0},r);s.flipBackslashes&&lZe&&e.indexOf(n3)<0&&(e=e.replace(cZe,n3)),uZe.test(e)&&(e+=n3),e+=\"a\";do e=aZe(e);while(oZe(e)||fZe.test(e));return e.replace(AZe,\"$1\")}});var Fle=_(jr=>{\"use strict\";Object.defineProperty(jr,\"__esModule\",{value:!0});jr.removeDuplicateSlashes=jr.matchAny=jr.convertPatternsToRe=jr.makeRe=jr.getPatternParts=jr.expandBraceExpansion=jr.expandPatternsWithBraceExpansion=jr.isAffectDepthOfReadingPattern=jr.endsWithSlashGlobStar=jr.hasGlobStar=jr.getBaseDirectory=jr.isPatternRelatedToParentDirectory=jr.getPatternsOutsideCurrentDirectory=jr.getPatternsInsideCurrentDirectory=jr.getPositivePatterns=jr.getNegativePatterns=jr.isPositivePattern=jr.isNegativePattern=jr.convertToNegativePattern=jr.convertToPositivePattern=jr.isDynamicPattern=jr.isStaticPattern=void 0;var pZe=Ie(\"path\"),hZe=Dle(),i3=Go(),Ple=\"**\",gZe=\"\\\\\",dZe=/[*?]|^!/,mZe=/\\[[^[]*]/,yZe=/(?:^|[^!*+?@])\\([^(]*\\|[^|]*\\)/,EZe=/[!*+?@]\\([^(]*\\)/,IZe=/,|\\.\\./,CZe=/(?!^)\\/{2,}/g;function ble(t,e={}){return!xle(t,e)}jr.isStaticPattern=ble;function xle(t,e={}){return t===\"\"?!1:!!(e.caseSensitiveMatch===!1||t.includes(gZe)||dZe.test(t)||mZe.test(t)||yZe.test(t)||e.extglob!==!1&&EZe.test(t)||e.braceExpansion!==!1&&wZe(t))}jr.isDynamicPattern=xle;function wZe(t){let e=t.indexOf(\"{\");if(e===-1)return!1;let r=t.indexOf(\"}\",e+1);if(r===-1)return!1;let s=t.slice(e,r);return IZe.test(s)}function BZe(t){return rQ(t)?t.slice(1):t}jr.convertToPositivePattern=BZe;function vZe(t){return\"!\"+t}jr.convertToNegativePattern=vZe;function rQ(t){return t.startsWith(\"!\")&&t[1]!==\"(\"}jr.isNegativePattern=rQ;function kle(t){return!rQ(t)}jr.isPositivePattern=kle;function SZe(t){return t.filter(rQ)}jr.getNegativePatterns=SZe;function DZe(t){return t.filter(kle)}jr.getPositivePatterns=DZe;function PZe(t){return t.filter(e=>!s3(e))}jr.getPatternsInsideCurrentDirectory=PZe;function bZe(t){return t.filter(s3)}jr.getPatternsOutsideCurrentDirectory=bZe;function s3(t){return t.startsWith(\"..\")||t.startsWith(\"./..\")}jr.isPatternRelatedToParentDirectory=s3;function xZe(t){return hZe(t,{flipBackslashes:!1})}jr.getBaseDirectory=xZe;function kZe(t){return t.includes(Ple)}jr.hasGlobStar=kZe;function Qle(t){return t.endsWith(\"/\"+Ple)}jr.endsWithSlashGlobStar=Qle;function QZe(t){let e=pZe.basename(t);return Qle(t)||ble(e)}jr.isAffectDepthOfReadingPattern=QZe;function RZe(t){return t.reduce((e,r)=>e.concat(Rle(r)),[])}jr.expandPatternsWithBraceExpansion=RZe;function Rle(t){let e=i3.braces(t,{expand:!0,nodupes:!0,keepEscaping:!0});return e.sort((r,s)=>r.length-s.length),e.filter(r=>r!==\"\")}jr.expandBraceExpansion=Rle;function TZe(t,e){let{parts:r}=i3.scan(t,Object.assign(Object.assign({},e),{parts:!0}));return r.length===0&&(r=[t]),r[0].startsWith(\"/\")&&(r[0]=r[0].slice(1),r.unshift(\"\")),r}jr.getPatternParts=TZe;function Tle(t,e){return i3.makeRe(t,e)}jr.makeRe=Tle;function FZe(t,e){return t.map(r=>Tle(r,e))}jr.convertPatternsToRe=FZe;function NZe(t,e){return e.some(r=>r.test(t))}jr.matchAny=NZe;function OZe(t){return t.replace(CZe,\"/\")}jr.removeDuplicateSlashes=OZe});var Mle=_((GOt,Lle)=>{\"use strict\";var LZe=Ie(\"stream\"),Nle=LZe.PassThrough,MZe=Array.prototype.slice;Lle.exports=UZe;function UZe(){let t=[],e=MZe.call(arguments),r=!1,s=e[e.length-1];s&&!Array.isArray(s)&&s.pipe==null?e.pop():s={};let a=s.end!==!1,n=s.pipeError===!0;s.objectMode==null&&(s.objectMode=!0),s.highWaterMark==null&&(s.highWaterMark=64*1024);let c=Nle(s);function f(){for(let E=0,C=arguments.length;E<C;E++)t.push(Ole(arguments[E],s));return p(),this}function p(){if(r)return;r=!0;let E=t.shift();if(!E){process.nextTick(h);return}Array.isArray(E)||(E=[E]);let C=E.length+1;function S(){--C>0||(r=!1,p())}function b(I){function T(){I.removeListener(\"merge2UnpipeEnd\",T),I.removeListener(\"end\",T),n&&I.removeListener(\"error\",N),S()}function N(U){c.emit(\"error\",U)}if(I._readableState.endEmitted)return S();I.on(\"merge2UnpipeEnd\",T),I.on(\"end\",T),n&&I.on(\"error\",N),I.pipe(c,{end:!1}),I.resume()}for(let I=0;I<E.length;I++)b(E[I]);S()}function h(){r=!1,c.emit(\"queueDrain\"),a&&c.end()}return c.setMaxListeners(0),c.add=f,c.on(\"unpipe\",function(E){E.emit(\"merge2UnpipeEnd\")}),e.length&&f.apply(null,e),c}function Ole(t,e){if(Array.isArray(t))for(let r=0,s=t.length;r<s;r++)t[r]=Ole(t[r],e);else{if(!t._readableState&&t.pipe&&(t=t.pipe(Nle(e))),!t._readableState||!t.pause||!t.pipe)throw new Error(\"Only readable stream can be merged.\");t.pause()}return t}});var _le=_(nQ=>{\"use strict\";Object.defineProperty(nQ,\"__esModule\",{value:!0});nQ.merge=void 0;var _Ze=Mle();function HZe(t){let e=_Ze(t);return t.forEach(r=>{r.once(\"error\",s=>e.emit(\"error\",s))}),e.once(\"close\",()=>Ule(t)),e.once(\"end\",()=>Ule(t)),e}nQ.merge=HZe;function Ule(t){t.forEach(e=>e.emit(\"close\"))}});var Hle=_(ZE=>{\"use strict\";Object.defineProperty(ZE,\"__esModule\",{value:!0});ZE.isEmpty=ZE.isString=void 0;function jZe(t){return typeof t==\"string\"}ZE.isString=jZe;function GZe(t){return t===\"\"}ZE.isEmpty=GZe});var xp=_(Yo=>{\"use strict\";Object.defineProperty(Yo,\"__esModule\",{value:!0});Yo.string=Yo.stream=Yo.pattern=Yo.path=Yo.fs=Yo.errno=Yo.array=void 0;var qZe=ple();Yo.array=qZe;var WZe=hle();Yo.errno=WZe;var YZe=gle();Yo.fs=YZe;var VZe=Ele();Yo.path=VZe;var JZe=Fle();Yo.pattern=JZe;var KZe=_le();Yo.stream=KZe;var zZe=Hle();Yo.string=zZe});var Wle=_(Vo=>{\"use strict\";Object.defineProperty(Vo,\"__esModule\",{value:!0});Vo.convertPatternGroupToTask=Vo.convertPatternGroupsToTasks=Vo.groupPatternsByBaseDirectory=Vo.getNegativePatternsAsPositive=Vo.getPositivePatterns=Vo.convertPatternsToTasks=Vo.generate=void 0;var Hu=xp();function ZZe(t,e){let r=jle(t,e),s=jle(e.ignore,e),a=Gle(r),n=qle(r,s),c=a.filter(E=>Hu.pattern.isStaticPattern(E,e)),f=a.filter(E=>Hu.pattern.isDynamicPattern(E,e)),p=o3(c,n,!1),h=o3(f,n,!0);return p.concat(h)}Vo.generate=ZZe;function jle(t,e){let r=t;return e.braceExpansion&&(r=Hu.pattern.expandPatternsWithBraceExpansion(r)),e.baseNameMatch&&(r=r.map(s=>s.includes(\"/\")?s:`**/${s}`)),r.map(s=>Hu.pattern.removeDuplicateSlashes(s))}function o3(t,e,r){let s=[],a=Hu.pattern.getPatternsOutsideCurrentDirectory(t),n=Hu.pattern.getPatternsInsideCurrentDirectory(t),c=a3(a),f=a3(n);return s.push(...l3(c,e,r)),\".\"in f?s.push(c3(\".\",n,e,r)):s.push(...l3(f,e,r)),s}Vo.convertPatternsToTasks=o3;function Gle(t){return Hu.pattern.getPositivePatterns(t)}Vo.getPositivePatterns=Gle;function qle(t,e){return Hu.pattern.getNegativePatterns(t).concat(e).map(Hu.pattern.convertToPositivePattern)}Vo.getNegativePatternsAsPositive=qle;function a3(t){let e={};return t.reduce((r,s)=>{let a=Hu.pattern.getBaseDirectory(s);return a in r?r[a].push(s):r[a]=[s],r},e)}Vo.groupPatternsByBaseDirectory=a3;function l3(t,e,r){return Object.keys(t).map(s=>c3(s,t[s],e,r))}Vo.convertPatternGroupsToTasks=l3;function c3(t,e,r,s){return{dynamic:s,positive:e,negative:r,base:t,patterns:[].concat(e,r.map(Hu.pattern.convertToNegativePattern))}}Vo.convertPatternGroupToTask=c3});var Vle=_(iQ=>{\"use strict\";Object.defineProperty(iQ,\"__esModule\",{value:!0});iQ.read=void 0;function XZe(t,e,r){e.fs.lstat(t,(s,a)=>{if(s!==null){Yle(r,s);return}if(!a.isSymbolicLink()||!e.followSymbolicLink){u3(r,a);return}e.fs.stat(t,(n,c)=>{if(n!==null){if(e.throwErrorOnBrokenSymbolicLink){Yle(r,n);return}u3(r,a);return}e.markSymbolicLink&&(c.isSymbolicLink=()=>!0),u3(r,c)})})}iQ.read=XZe;function Yle(t,e){t(e)}function u3(t,e){t(null,e)}});var Jle=_(sQ=>{\"use strict\";Object.defineProperty(sQ,\"__esModule\",{value:!0});sQ.read=void 0;function $Ze(t,e){let r=e.fs.lstatSync(t);if(!r.isSymbolicLink()||!e.followSymbolicLink)return r;try{let s=e.fs.statSync(t);return e.markSymbolicLink&&(s.isSymbolicLink=()=>!0),s}catch(s){if(!e.throwErrorOnBrokenSymbolicLink)return r;throw s}}sQ.read=$Ze});var Kle=_(h0=>{\"use strict\";Object.defineProperty(h0,\"__esModule\",{value:!0});h0.createFileSystemAdapter=h0.FILE_SYSTEM_ADAPTER=void 0;var oQ=Ie(\"fs\");h0.FILE_SYSTEM_ADAPTER={lstat:oQ.lstat,stat:oQ.stat,lstatSync:oQ.lstatSync,statSync:oQ.statSync};function eXe(t){return t===void 0?h0.FILE_SYSTEM_ADAPTER:Object.assign(Object.assign({},h0.FILE_SYSTEM_ADAPTER),t)}h0.createFileSystemAdapter=eXe});var zle=_(A3=>{\"use strict\";Object.defineProperty(A3,\"__esModule\",{value:!0});var tXe=Kle(),f3=class{constructor(e={}){this._options=e,this.followSymbolicLink=this._getValue(this._options.followSymbolicLink,!0),this.fs=tXe.createFileSystemAdapter(this._options.fs),this.markSymbolicLink=this._getValue(this._options.markSymbolicLink,!1),this.throwErrorOnBrokenSymbolicLink=this._getValue(this._options.throwErrorOnBrokenSymbolicLink,!0)}_getValue(e,r){return e??r}};A3.default=f3});var Xd=_(g0=>{\"use strict\";Object.defineProperty(g0,\"__esModule\",{value:!0});g0.statSync=g0.stat=g0.Settings=void 0;var Zle=Vle(),rXe=Jle(),p3=zle();g0.Settings=p3.default;function nXe(t,e,r){if(typeof e==\"function\"){Zle.read(t,h3(),e);return}Zle.read(t,h3(e),r)}g0.stat=nXe;function iXe(t,e){let r=h3(e);return rXe.read(t,r)}g0.statSync=iXe;function h3(t={}){return t instanceof p3.default?t:new p3.default(t)}});var ece=_(($Ot,$le)=>{var Xle;$le.exports=typeof queueMicrotask==\"function\"?queueMicrotask.bind(typeof window<\"u\"?window:global):t=>(Xle||(Xle=Promise.resolve())).then(t).catch(e=>setTimeout(()=>{throw e},0))});var rce=_((eLt,tce)=>{tce.exports=oXe;var sXe=ece();function oXe(t,e){let r,s,a,n=!0;Array.isArray(t)?(r=[],s=t.length):(a=Object.keys(t),r={},s=a.length);function c(p){function h(){e&&e(p,r),e=null}n?sXe(h):h()}function f(p,h,E){r[p]=E,(--s===0||h)&&c(h)}s?a?a.forEach(function(p){t[p](function(h,E){f(p,h,E)})}):t.forEach(function(p,h){p(function(E,C){f(h,E,C)})}):c(null),n=!1}});var g3=_(lQ=>{\"use strict\";Object.defineProperty(lQ,\"__esModule\",{value:!0});lQ.IS_SUPPORT_READDIR_WITH_FILE_TYPES=void 0;var aQ=process.versions.node.split(\".\");if(aQ[0]===void 0||aQ[1]===void 0)throw new Error(`Unexpected behavior. The 'process.versions.node' variable has invalid value: ${process.versions.node}`);var nce=Number.parseInt(aQ[0],10),aXe=Number.parseInt(aQ[1],10),ice=10,lXe=10,cXe=nce>ice,uXe=nce===ice&&aXe>=lXe;lQ.IS_SUPPORT_READDIR_WITH_FILE_TYPES=cXe||uXe});var sce=_(cQ=>{\"use strict\";Object.defineProperty(cQ,\"__esModule\",{value:!0});cQ.createDirentFromStats=void 0;var d3=class{constructor(e,r){this.name=e,this.isBlockDevice=r.isBlockDevice.bind(r),this.isCharacterDevice=r.isCharacterDevice.bind(r),this.isDirectory=r.isDirectory.bind(r),this.isFIFO=r.isFIFO.bind(r),this.isFile=r.isFile.bind(r),this.isSocket=r.isSocket.bind(r),this.isSymbolicLink=r.isSymbolicLink.bind(r)}};function fXe(t,e){return new d3(t,e)}cQ.createDirentFromStats=fXe});var m3=_(uQ=>{\"use strict\";Object.defineProperty(uQ,\"__esModule\",{value:!0});uQ.fs=void 0;var AXe=sce();uQ.fs=AXe});var y3=_(fQ=>{\"use strict\";Object.defineProperty(fQ,\"__esModule\",{value:!0});fQ.joinPathSegments=void 0;function pXe(t,e,r){return t.endsWith(r)?t+e:t+r+e}fQ.joinPathSegments=pXe});var fce=_(d0=>{\"use strict\";Object.defineProperty(d0,\"__esModule\",{value:!0});d0.readdir=d0.readdirWithFileTypes=d0.read=void 0;var hXe=Xd(),oce=rce(),gXe=g3(),ace=m3(),lce=y3();function dXe(t,e,r){if(!e.stats&&gXe.IS_SUPPORT_READDIR_WITH_FILE_TYPES){cce(t,e,r);return}uce(t,e,r)}d0.read=dXe;function cce(t,e,r){e.fs.readdir(t,{withFileTypes:!0},(s,a)=>{if(s!==null){AQ(r,s);return}let n=a.map(f=>({dirent:f,name:f.name,path:lce.joinPathSegments(t,f.name,e.pathSegmentSeparator)}));if(!e.followSymbolicLinks){E3(r,n);return}let c=n.map(f=>mXe(f,e));oce(c,(f,p)=>{if(f!==null){AQ(r,f);return}E3(r,p)})})}d0.readdirWithFileTypes=cce;function mXe(t,e){return r=>{if(!t.dirent.isSymbolicLink()){r(null,t);return}e.fs.stat(t.path,(s,a)=>{if(s!==null){if(e.throwErrorOnBrokenSymbolicLink){r(s);return}r(null,t);return}t.dirent=ace.fs.createDirentFromStats(t.name,a),r(null,t)})}}function uce(t,e,r){e.fs.readdir(t,(s,a)=>{if(s!==null){AQ(r,s);return}let n=a.map(c=>{let f=lce.joinPathSegments(t,c,e.pathSegmentSeparator);return p=>{hXe.stat(f,e.fsStatSettings,(h,E)=>{if(h!==null){p(h);return}let C={name:c,path:f,dirent:ace.fs.createDirentFromStats(c,E)};e.stats&&(C.stats=E),p(null,C)})}});oce(n,(c,f)=>{if(c!==null){AQ(r,c);return}E3(r,f)})})}d0.readdir=uce;function AQ(t,e){t(e)}function E3(t,e){t(null,e)}});var dce=_(m0=>{\"use strict\";Object.defineProperty(m0,\"__esModule\",{value:!0});m0.readdir=m0.readdirWithFileTypes=m0.read=void 0;var yXe=Xd(),EXe=g3(),Ace=m3(),pce=y3();function IXe(t,e){return!e.stats&&EXe.IS_SUPPORT_READDIR_WITH_FILE_TYPES?hce(t,e):gce(t,e)}m0.read=IXe;function hce(t,e){return e.fs.readdirSync(t,{withFileTypes:!0}).map(s=>{let a={dirent:s,name:s.name,path:pce.joinPathSegments(t,s.name,e.pathSegmentSeparator)};if(a.dirent.isSymbolicLink()&&e.followSymbolicLinks)try{let n=e.fs.statSync(a.path);a.dirent=Ace.fs.createDirentFromStats(a.name,n)}catch(n){if(e.throwErrorOnBrokenSymbolicLink)throw n}return a})}m0.readdirWithFileTypes=hce;function gce(t,e){return e.fs.readdirSync(t).map(s=>{let a=pce.joinPathSegments(t,s,e.pathSegmentSeparator),n=yXe.statSync(a,e.fsStatSettings),c={name:s,path:a,dirent:Ace.fs.createDirentFromStats(s,n)};return e.stats&&(c.stats=n),c})}m0.readdir=gce});var mce=_(y0=>{\"use strict\";Object.defineProperty(y0,\"__esModule\",{value:!0});y0.createFileSystemAdapter=y0.FILE_SYSTEM_ADAPTER=void 0;var XE=Ie(\"fs\");y0.FILE_SYSTEM_ADAPTER={lstat:XE.lstat,stat:XE.stat,lstatSync:XE.lstatSync,statSync:XE.statSync,readdir:XE.readdir,readdirSync:XE.readdirSync};function CXe(t){return t===void 0?y0.FILE_SYSTEM_ADAPTER:Object.assign(Object.assign({},y0.FILE_SYSTEM_ADAPTER),t)}y0.createFileSystemAdapter=CXe});var yce=_(C3=>{\"use strict\";Object.defineProperty(C3,\"__esModule\",{value:!0});var wXe=Ie(\"path\"),BXe=Xd(),vXe=mce(),I3=class{constructor(e={}){this._options=e,this.followSymbolicLinks=this._getValue(this._options.followSymbolicLinks,!1),this.fs=vXe.createFileSystemAdapter(this._options.fs),this.pathSegmentSeparator=this._getValue(this._options.pathSegmentSeparator,wXe.sep),this.stats=this._getValue(this._options.stats,!1),this.throwErrorOnBrokenSymbolicLink=this._getValue(this._options.throwErrorOnBrokenSymbolicLink,!0),this.fsStatSettings=new BXe.Settings({followSymbolicLink:this.followSymbolicLinks,fs:this.fs,throwErrorOnBrokenSymbolicLink:this.throwErrorOnBrokenSymbolicLink})}_getValue(e,r){return e??r}};C3.default=I3});var pQ=_(E0=>{\"use strict\";Object.defineProperty(E0,\"__esModule\",{value:!0});E0.Settings=E0.scandirSync=E0.scandir=void 0;var Ece=fce(),SXe=dce(),w3=yce();E0.Settings=w3.default;function DXe(t,e,r){if(typeof e==\"function\"){Ece.read(t,B3(),e);return}Ece.read(t,B3(e),r)}E0.scandir=DXe;function PXe(t,e){let r=B3(e);return SXe.read(t,r)}E0.scandirSync=PXe;function B3(t={}){return t instanceof w3.default?t:new w3.default(t)}});var Cce=_((uLt,Ice)=>{\"use strict\";function bXe(t){var e=new t,r=e;function s(){var n=e;return n.next?e=n.next:(e=new t,r=e),n.next=null,n}function a(n){r.next=n,r=n}return{get:s,release:a}}Ice.exports=bXe});var Bce=_((fLt,v3)=>{\"use strict\";var xXe=Cce();function wce(t,e,r){if(typeof t==\"function\"&&(r=e,e=t,t=null),!(r>=1))throw new Error(\"fastqueue concurrency must be equal to or greater than 1\");var s=xXe(kXe),a=null,n=null,c=0,f=null,p={push:T,drain:kc,saturated:kc,pause:E,paused:!1,get concurrency(){return r},set concurrency(ue){if(!(ue>=1))throw new Error(\"fastqueue concurrency must be equal to or greater than 1\");if(r=ue,!p.paused)for(;a&&c<r;)c++,U()},running:h,resume:b,idle:I,length:C,getQueue:S,unshift:N,empty:kc,kill:W,killAndDrain:ee,error:ie};return p;function h(){return c}function E(){p.paused=!0}function C(){for(var ue=a,le=0;ue;)ue=ue.next,le++;return le}function S(){for(var ue=a,le=[];ue;)le.push(ue.value),ue=ue.next;return le}function b(){if(p.paused){if(p.paused=!1,a===null){c++,U();return}for(;a&&c<r;)c++,U()}}function I(){return c===0&&p.length()===0}function T(ue,le){var me=s.get();me.context=t,me.release=U,me.value=ue,me.callback=le||kc,me.errorHandler=f,c>=r||p.paused?n?(n.next=me,n=me):(a=me,n=me,p.saturated()):(c++,e.call(t,me.value,me.worked))}function N(ue,le){var me=s.get();me.context=t,me.release=U,me.value=ue,me.callback=le||kc,me.errorHandler=f,c>=r||p.paused?a?(me.next=a,a=me):(a=me,n=me,p.saturated()):(c++,e.call(t,me.value,me.worked))}function U(ue){ue&&s.release(ue);var le=a;le&&c<=r?p.paused?c--:(n===a&&(n=null),a=le.next,le.next=null,e.call(t,le.value,le.worked),n===null&&p.empty()):--c===0&&p.drain()}function W(){a=null,n=null,p.drain=kc}function ee(){a=null,n=null,p.drain(),p.drain=kc}function ie(ue){f=ue}}function kc(){}function kXe(){this.value=null,this.callback=kc,this.next=null,this.release=kc,this.context=null,this.errorHandler=null;var t=this;this.worked=function(r,s){var a=t.callback,n=t.errorHandler,c=t.value;t.value=null,t.callback=kc,t.errorHandler&&n(r,c),a.call(t.context,r,s),t.release(t)}}function QXe(t,e,r){typeof t==\"function\"&&(r=e,e=t,t=null);function s(E,C){e.call(this,E).then(function(S){C(null,S)},C)}var a=wce(t,s,r),n=a.push,c=a.unshift;return a.push=f,a.unshift=p,a.drained=h,a;function f(E){var C=new Promise(function(S,b){n(E,function(I,T){if(I){b(I);return}S(T)})});return C.catch(kc),C}function p(E){var C=new Promise(function(S,b){c(E,function(I,T){if(I){b(I);return}S(T)})});return C.catch(kc),C}function h(){if(a.idle())return new Promise(function(S){S()});var E=a.drain,C=new Promise(function(S){a.drain=function(){E(),S()}});return C}}v3.exports=wce;v3.exports.promise=QXe});var hQ=_(zf=>{\"use strict\";Object.defineProperty(zf,\"__esModule\",{value:!0});zf.joinPathSegments=zf.replacePathSegmentSeparator=zf.isAppliedFilter=zf.isFatalError=void 0;function RXe(t,e){return t.errorFilter===null?!0:!t.errorFilter(e)}zf.isFatalError=RXe;function TXe(t,e){return t===null||t(e)}zf.isAppliedFilter=TXe;function FXe(t,e){return t.split(/[/\\\\]/).join(e)}zf.replacePathSegmentSeparator=FXe;function NXe(t,e,r){return t===\"\"?e:t.endsWith(r)?t+e:t+r+e}zf.joinPathSegments=NXe});var P3=_(D3=>{\"use strict\";Object.defineProperty(D3,\"__esModule\",{value:!0});var OXe=hQ(),S3=class{constructor(e,r){this._root=e,this._settings=r,this._root=OXe.replacePathSegmentSeparator(e,r.pathSegmentSeparator)}};D3.default=S3});var k3=_(x3=>{\"use strict\";Object.defineProperty(x3,\"__esModule\",{value:!0});var LXe=Ie(\"events\"),MXe=pQ(),UXe=Bce(),gQ=hQ(),_Xe=P3(),b3=class extends _Xe.default{constructor(e,r){super(e,r),this._settings=r,this._scandir=MXe.scandir,this._emitter=new LXe.EventEmitter,this._queue=UXe(this._worker.bind(this),this._settings.concurrency),this._isFatalError=!1,this._isDestroyed=!1,this._queue.drain=()=>{this._isFatalError||this._emitter.emit(\"end\")}}read(){return this._isFatalError=!1,this._isDestroyed=!1,setImmediate(()=>{this._pushToQueue(this._root,this._settings.basePath)}),this._emitter}get isDestroyed(){return this._isDestroyed}destroy(){if(this._isDestroyed)throw new Error(\"The reader is already destroyed\");this._isDestroyed=!0,this._queue.killAndDrain()}onEntry(e){this._emitter.on(\"entry\",e)}onError(e){this._emitter.once(\"error\",e)}onEnd(e){this._emitter.once(\"end\",e)}_pushToQueue(e,r){let s={directory:e,base:r};this._queue.push(s,a=>{a!==null&&this._handleError(a)})}_worker(e,r){this._scandir(e.directory,this._settings.fsScandirSettings,(s,a)=>{if(s!==null){r(s,void 0);return}for(let n of a)this._handleEntry(n,e.base);r(null,void 0)})}_handleError(e){this._isDestroyed||!gQ.isFatalError(this._settings,e)||(this._isFatalError=!0,this._isDestroyed=!0,this._emitter.emit(\"error\",e))}_handleEntry(e,r){if(this._isDestroyed||this._isFatalError)return;let s=e.path;r!==void 0&&(e.path=gQ.joinPathSegments(r,e.name,this._settings.pathSegmentSeparator)),gQ.isAppliedFilter(this._settings.entryFilter,e)&&this._emitEntry(e),e.dirent.isDirectory()&&gQ.isAppliedFilter(this._settings.deepFilter,e)&&this._pushToQueue(s,r===void 0?void 0:e.path)}_emitEntry(e){this._emitter.emit(\"entry\",e)}};x3.default=b3});var vce=_(R3=>{\"use strict\";Object.defineProperty(R3,\"__esModule\",{value:!0});var HXe=k3(),Q3=class{constructor(e,r){this._root=e,this._settings=r,this._reader=new HXe.default(this._root,this._settings),this._storage=[]}read(e){this._reader.onError(r=>{jXe(e,r)}),this._reader.onEntry(r=>{this._storage.push(r)}),this._reader.onEnd(()=>{GXe(e,this._storage)}),this._reader.read()}};R3.default=Q3;function jXe(t,e){t(e)}function GXe(t,e){t(null,e)}});var Sce=_(F3=>{\"use strict\";Object.defineProperty(F3,\"__esModule\",{value:!0});var qXe=Ie(\"stream\"),WXe=k3(),T3=class{constructor(e,r){this._root=e,this._settings=r,this._reader=new WXe.default(this._root,this._settings),this._stream=new qXe.Readable({objectMode:!0,read:()=>{},destroy:()=>{this._reader.isDestroyed||this._reader.destroy()}})}read(){return this._reader.onError(e=>{this._stream.emit(\"error\",e)}),this._reader.onEntry(e=>{this._stream.push(e)}),this._reader.onEnd(()=>{this._stream.push(null)}),this._reader.read(),this._stream}};F3.default=T3});var Dce=_(O3=>{\"use strict\";Object.defineProperty(O3,\"__esModule\",{value:!0});var YXe=pQ(),dQ=hQ(),VXe=P3(),N3=class extends VXe.default{constructor(){super(...arguments),this._scandir=YXe.scandirSync,this._storage=[],this._queue=new Set}read(){return this._pushToQueue(this._root,this._settings.basePath),this._handleQueue(),this._storage}_pushToQueue(e,r){this._queue.add({directory:e,base:r})}_handleQueue(){for(let e of this._queue.values())this._handleDirectory(e.directory,e.base)}_handleDirectory(e,r){try{let s=this._scandir(e,this._settings.fsScandirSettings);for(let a of s)this._handleEntry(a,r)}catch(s){this._handleError(s)}}_handleError(e){if(dQ.isFatalError(this._settings,e))throw e}_handleEntry(e,r){let s=e.path;r!==void 0&&(e.path=dQ.joinPathSegments(r,e.name,this._settings.pathSegmentSeparator)),dQ.isAppliedFilter(this._settings.entryFilter,e)&&this._pushToStorage(e),e.dirent.isDirectory()&&dQ.isAppliedFilter(this._settings.deepFilter,e)&&this._pushToQueue(s,r===void 0?void 0:e.path)}_pushToStorage(e){this._storage.push(e)}};O3.default=N3});var Pce=_(M3=>{\"use strict\";Object.defineProperty(M3,\"__esModule\",{value:!0});var JXe=Dce(),L3=class{constructor(e,r){this._root=e,this._settings=r,this._reader=new JXe.default(this._root,this._settings)}read(){return this._reader.read()}};M3.default=L3});var bce=_(_3=>{\"use strict\";Object.defineProperty(_3,\"__esModule\",{value:!0});var KXe=Ie(\"path\"),zXe=pQ(),U3=class{constructor(e={}){this._options=e,this.basePath=this._getValue(this._options.basePath,void 0),this.concurrency=this._getValue(this._options.concurrency,Number.POSITIVE_INFINITY),this.deepFilter=this._getValue(this._options.deepFilter,null),this.entryFilter=this._getValue(this._options.entryFilter,null),this.errorFilter=this._getValue(this._options.errorFilter,null),this.pathSegmentSeparator=this._getValue(this._options.pathSegmentSeparator,KXe.sep),this.fsScandirSettings=new zXe.Settings({followSymbolicLinks:this._options.followSymbolicLinks,fs:this._options.fs,pathSegmentSeparator:this._options.pathSegmentSeparator,stats:this._options.stats,throwErrorOnBrokenSymbolicLink:this._options.throwErrorOnBrokenSymbolicLink})}_getValue(e,r){return e??r}};_3.default=U3});var yQ=_(Zf=>{\"use strict\";Object.defineProperty(Zf,\"__esModule\",{value:!0});Zf.Settings=Zf.walkStream=Zf.walkSync=Zf.walk=void 0;var xce=vce(),ZXe=Sce(),XXe=Pce(),H3=bce();Zf.Settings=H3.default;function $Xe(t,e,r){if(typeof e==\"function\"){new xce.default(t,mQ()).read(e);return}new xce.default(t,mQ(e)).read(r)}Zf.walk=$Xe;function e$e(t,e){let r=mQ(e);return new XXe.default(t,r).read()}Zf.walkSync=e$e;function t$e(t,e){let r=mQ(e);return new ZXe.default(t,r).read()}Zf.walkStream=t$e;function mQ(t={}){return t instanceof H3.default?t:new H3.default(t)}});var EQ=_(G3=>{\"use strict\";Object.defineProperty(G3,\"__esModule\",{value:!0});var r$e=Ie(\"path\"),n$e=Xd(),kce=xp(),j3=class{constructor(e){this._settings=e,this._fsStatSettings=new n$e.Settings({followSymbolicLink:this._settings.followSymbolicLinks,fs:this._settings.fs,throwErrorOnBrokenSymbolicLink:this._settings.followSymbolicLinks})}_getFullEntryPath(e){return r$e.resolve(this._settings.cwd,e)}_makeEntry(e,r){let s={name:r,path:r,dirent:kce.fs.createDirentFromStats(r,e)};return this._settings.stats&&(s.stats=e),s}_isFatalError(e){return!kce.errno.isEnoentCodeError(e)&&!this._settings.suppressErrors}};G3.default=j3});var Y3=_(W3=>{\"use strict\";Object.defineProperty(W3,\"__esModule\",{value:!0});var i$e=Ie(\"stream\"),s$e=Xd(),o$e=yQ(),a$e=EQ(),q3=class extends a$e.default{constructor(){super(...arguments),this._walkStream=o$e.walkStream,this._stat=s$e.stat}dynamic(e,r){return this._walkStream(e,r)}static(e,r){let s=e.map(this._getFullEntryPath,this),a=new i$e.PassThrough({objectMode:!0});a._write=(n,c,f)=>this._getEntry(s[n],e[n],r).then(p=>{p!==null&&r.entryFilter(p)&&a.push(p),n===s.length-1&&a.end(),f()}).catch(f);for(let n=0;n<s.length;n++)a.write(n);return a}_getEntry(e,r,s){return this._getStat(e).then(a=>this._makeEntry(a,r)).catch(a=>{if(s.errorFilter(a))return null;throw a})}_getStat(e){return new Promise((r,s)=>{this._stat(e,this._fsStatSettings,(a,n)=>a===null?r(n):s(a))})}};W3.default=q3});var Qce=_(J3=>{\"use strict\";Object.defineProperty(J3,\"__esModule\",{value:!0});var l$e=yQ(),c$e=EQ(),u$e=Y3(),V3=class extends c$e.default{constructor(){super(...arguments),this._walkAsync=l$e.walk,this._readerStream=new u$e.default(this._settings)}dynamic(e,r){return new Promise((s,a)=>{this._walkAsync(e,r,(n,c)=>{n===null?s(c):a(n)})})}async static(e,r){let s=[],a=this._readerStream.static(e,r);return new Promise((n,c)=>{a.once(\"error\",c),a.on(\"data\",f=>s.push(f)),a.once(\"end\",()=>n(s))})}};J3.default=V3});var Rce=_(z3=>{\"use strict\";Object.defineProperty(z3,\"__esModule\",{value:!0});var NB=xp(),K3=class{constructor(e,r,s){this._patterns=e,this._settings=r,this._micromatchOptions=s,this._storage=[],this._fillStorage()}_fillStorage(){for(let e of this._patterns){let r=this._getPatternSegments(e),s=this._splitSegmentsIntoSections(r);this._storage.push({complete:s.length<=1,pattern:e,segments:r,sections:s})}}_getPatternSegments(e){return NB.pattern.getPatternParts(e,this._micromatchOptions).map(s=>NB.pattern.isDynamicPattern(s,this._settings)?{dynamic:!0,pattern:s,patternRe:NB.pattern.makeRe(s,this._micromatchOptions)}:{dynamic:!1,pattern:s})}_splitSegmentsIntoSections(e){return NB.array.splitWhen(e,r=>r.dynamic&&NB.pattern.hasGlobStar(r.pattern))}};z3.default=K3});var Tce=_(X3=>{\"use strict\";Object.defineProperty(X3,\"__esModule\",{value:!0});var f$e=Rce(),Z3=class extends f$e.default{match(e){let r=e.split(\"/\"),s=r.length,a=this._storage.filter(n=>!n.complete||n.segments.length>s);for(let n of a){let c=n.sections[0];if(!n.complete&&s>c.length||r.every((p,h)=>{let E=n.segments[h];return!!(E.dynamic&&E.patternRe.test(p)||!E.dynamic&&E.pattern===p)}))return!0}return!1}};X3.default=Z3});var Fce=_(e8=>{\"use strict\";Object.defineProperty(e8,\"__esModule\",{value:!0});var IQ=xp(),A$e=Tce(),$3=class{constructor(e,r){this._settings=e,this._micromatchOptions=r}getFilter(e,r,s){let a=this._getMatcher(r),n=this._getNegativePatternsRe(s);return c=>this._filter(e,c,a,n)}_getMatcher(e){return new A$e.default(e,this._settings,this._micromatchOptions)}_getNegativePatternsRe(e){let r=e.filter(IQ.pattern.isAffectDepthOfReadingPattern);return IQ.pattern.convertPatternsToRe(r,this._micromatchOptions)}_filter(e,r,s,a){if(this._isSkippedByDeep(e,r.path)||this._isSkippedSymbolicLink(r))return!1;let n=IQ.path.removeLeadingDotSegment(r.path);return this._isSkippedByPositivePatterns(n,s)?!1:this._isSkippedByNegativePatterns(n,a)}_isSkippedByDeep(e,r){return this._settings.deep===1/0?!1:this._getEntryLevel(e,r)>=this._settings.deep}_getEntryLevel(e,r){let s=r.split(\"/\").length;if(e===\"\")return s;let a=e.split(\"/\").length;return s-a}_isSkippedSymbolicLink(e){return!this._settings.followSymbolicLinks&&e.dirent.isSymbolicLink()}_isSkippedByPositivePatterns(e,r){return!this._settings.baseNameMatch&&!r.match(e)}_isSkippedByNegativePatterns(e,r){return!IQ.pattern.matchAny(e,r)}};e8.default=$3});var Nce=_(r8=>{\"use strict\";Object.defineProperty(r8,\"__esModule\",{value:!0});var $d=xp(),t8=class{constructor(e,r){this._settings=e,this._micromatchOptions=r,this.index=new Map}getFilter(e,r){let s=$d.pattern.convertPatternsToRe(e,this._micromatchOptions),a=$d.pattern.convertPatternsToRe(r,Object.assign(Object.assign({},this._micromatchOptions),{dot:!0}));return n=>this._filter(n,s,a)}_filter(e,r,s){let a=$d.path.removeLeadingDotSegment(e.path);if(this._settings.unique&&this._isDuplicateEntry(a)||this._onlyFileFilter(e)||this._onlyDirectoryFilter(e)||this._isSkippedByAbsoluteNegativePatterns(a,s))return!1;let n=e.dirent.isDirectory(),c=this._isMatchToPatterns(a,r,n)&&!this._isMatchToPatterns(a,s,n);return this._settings.unique&&c&&this._createIndexRecord(a),c}_isDuplicateEntry(e){return this.index.has(e)}_createIndexRecord(e){this.index.set(e,void 0)}_onlyFileFilter(e){return this._settings.onlyFiles&&!e.dirent.isFile()}_onlyDirectoryFilter(e){return this._settings.onlyDirectories&&!e.dirent.isDirectory()}_isSkippedByAbsoluteNegativePatterns(e,r){if(!this._settings.absolute)return!1;let s=$d.path.makeAbsolute(this._settings.cwd,e);return $d.pattern.matchAny(s,r)}_isMatchToPatterns(e,r,s){let a=$d.pattern.matchAny(e,r);return!a&&s?$d.pattern.matchAny(e+\"/\",r):a}};r8.default=t8});var Oce=_(i8=>{\"use strict\";Object.defineProperty(i8,\"__esModule\",{value:!0});var p$e=xp(),n8=class{constructor(e){this._settings=e}getFilter(){return e=>this._isNonFatalError(e)}_isNonFatalError(e){return p$e.errno.isEnoentCodeError(e)||this._settings.suppressErrors}};i8.default=n8});var Mce=_(o8=>{\"use strict\";Object.defineProperty(o8,\"__esModule\",{value:!0});var Lce=xp(),s8=class{constructor(e){this._settings=e}getTransformer(){return e=>this._transform(e)}_transform(e){let r=e.path;return this._settings.absolute&&(r=Lce.path.makeAbsolute(this._settings.cwd,r),r=Lce.path.unixify(r)),this._settings.markDirectories&&e.dirent.isDirectory()&&(r+=\"/\"),this._settings.objectMode?Object.assign(Object.assign({},e),{path:r}):r}};o8.default=s8});var CQ=_(l8=>{\"use strict\";Object.defineProperty(l8,\"__esModule\",{value:!0});var h$e=Ie(\"path\"),g$e=Fce(),d$e=Nce(),m$e=Oce(),y$e=Mce(),a8=class{constructor(e){this._settings=e,this.errorFilter=new m$e.default(this._settings),this.entryFilter=new d$e.default(this._settings,this._getMicromatchOptions()),this.deepFilter=new g$e.default(this._settings,this._getMicromatchOptions()),this.entryTransformer=new y$e.default(this._settings)}_getRootDirectory(e){return h$e.resolve(this._settings.cwd,e.base)}_getReaderOptions(e){let r=e.base===\".\"?\"\":e.base;return{basePath:r,pathSegmentSeparator:\"/\",concurrency:this._settings.concurrency,deepFilter:this.deepFilter.getFilter(r,e.positive,e.negative),entryFilter:this.entryFilter.getFilter(e.positive,e.negative),errorFilter:this.errorFilter.getFilter(),followSymbolicLinks:this._settings.followSymbolicLinks,fs:this._settings.fs,stats:this._settings.stats,throwErrorOnBrokenSymbolicLink:this._settings.throwErrorOnBrokenSymbolicLink,transform:this.entryTransformer.getTransformer()}}_getMicromatchOptions(){return{dot:this._settings.dot,matchBase:this._settings.baseNameMatch,nobrace:!this._settings.braceExpansion,nocase:!this._settings.caseSensitiveMatch,noext:!this._settings.extglob,noglobstar:!this._settings.globstar,posix:!0,strictSlashes:!1}}};l8.default=a8});var Uce=_(u8=>{\"use strict\";Object.defineProperty(u8,\"__esModule\",{value:!0});var E$e=Qce(),I$e=CQ(),c8=class extends I$e.default{constructor(){super(...arguments),this._reader=new E$e.default(this._settings)}async read(e){let r=this._getRootDirectory(e),s=this._getReaderOptions(e);return(await this.api(r,e,s)).map(n=>s.transform(n))}api(e,r,s){return r.dynamic?this._reader.dynamic(e,s):this._reader.static(r.patterns,s)}};u8.default=c8});var _ce=_(A8=>{\"use strict\";Object.defineProperty(A8,\"__esModule\",{value:!0});var C$e=Ie(\"stream\"),w$e=Y3(),B$e=CQ(),f8=class extends B$e.default{constructor(){super(...arguments),this._reader=new w$e.default(this._settings)}read(e){let r=this._getRootDirectory(e),s=this._getReaderOptions(e),a=this.api(r,e,s),n=new C$e.Readable({objectMode:!0,read:()=>{}});return a.once(\"error\",c=>n.emit(\"error\",c)).on(\"data\",c=>n.emit(\"data\",s.transform(c))).once(\"end\",()=>n.emit(\"end\")),n.once(\"close\",()=>a.destroy()),n}api(e,r,s){return r.dynamic?this._reader.dynamic(e,s):this._reader.static(r.patterns,s)}};A8.default=f8});var Hce=_(h8=>{\"use strict\";Object.defineProperty(h8,\"__esModule\",{value:!0});var v$e=Xd(),S$e=yQ(),D$e=EQ(),p8=class extends D$e.default{constructor(){super(...arguments),this._walkSync=S$e.walkSync,this._statSync=v$e.statSync}dynamic(e,r){return this._walkSync(e,r)}static(e,r){let s=[];for(let a of e){let n=this._getFullEntryPath(a),c=this._getEntry(n,a,r);c===null||!r.entryFilter(c)||s.push(c)}return s}_getEntry(e,r,s){try{let a=this._getStat(e);return this._makeEntry(a,r)}catch(a){if(s.errorFilter(a))return null;throw a}}_getStat(e){return this._statSync(e,this._fsStatSettings)}};h8.default=p8});var jce=_(d8=>{\"use strict\";Object.defineProperty(d8,\"__esModule\",{value:!0});var P$e=Hce(),b$e=CQ(),g8=class extends b$e.default{constructor(){super(...arguments),this._reader=new P$e.default(this._settings)}read(e){let r=this._getRootDirectory(e),s=this._getReaderOptions(e);return this.api(r,e,s).map(s.transform)}api(e,r,s){return r.dynamic?this._reader.dynamic(e,s):this._reader.static(r.patterns,s)}};d8.default=g8});var Gce=_(eI=>{\"use strict\";Object.defineProperty(eI,\"__esModule\",{value:!0});eI.DEFAULT_FILE_SYSTEM_ADAPTER=void 0;var $E=Ie(\"fs\"),x$e=Ie(\"os\"),k$e=Math.max(x$e.cpus().length,1);eI.DEFAULT_FILE_SYSTEM_ADAPTER={lstat:$E.lstat,lstatSync:$E.lstatSync,stat:$E.stat,statSync:$E.statSync,readdir:$E.readdir,readdirSync:$E.readdirSync};var m8=class{constructor(e={}){this._options=e,this.absolute=this._getValue(this._options.absolute,!1),this.baseNameMatch=this._getValue(this._options.baseNameMatch,!1),this.braceExpansion=this._getValue(this._options.braceExpansion,!0),this.caseSensitiveMatch=this._getValue(this._options.caseSensitiveMatch,!0),this.concurrency=this._getValue(this._options.concurrency,k$e),this.cwd=this._getValue(this._options.cwd,process.cwd()),this.deep=this._getValue(this._options.deep,1/0),this.dot=this._getValue(this._options.dot,!1),this.extglob=this._getValue(this._options.extglob,!0),this.followSymbolicLinks=this._getValue(this._options.followSymbolicLinks,!0),this.fs=this._getFileSystemMethods(this._options.fs),this.globstar=this._getValue(this._options.globstar,!0),this.ignore=this._getValue(this._options.ignore,[]),this.markDirectories=this._getValue(this._options.markDirectories,!1),this.objectMode=this._getValue(this._options.objectMode,!1),this.onlyDirectories=this._getValue(this._options.onlyDirectories,!1),this.onlyFiles=this._getValue(this._options.onlyFiles,!0),this.stats=this._getValue(this._options.stats,!1),this.suppressErrors=this._getValue(this._options.suppressErrors,!1),this.throwErrorOnBrokenSymbolicLink=this._getValue(this._options.throwErrorOnBrokenSymbolicLink,!1),this.unique=this._getValue(this._options.unique,!0),this.onlyDirectories&&(this.onlyFiles=!1),this.stats&&(this.objectMode=!0),this.ignore=[].concat(this.ignore)}_getValue(e,r){return e===void 0?r:e}_getFileSystemMethods(e={}){return Object.assign(Object.assign({},eI.DEFAULT_FILE_SYSTEM_ADAPTER),e)}};eI.default=m8});var wQ=_((OLt,Wce)=>{\"use strict\";var qce=Wle(),Q$e=Uce(),R$e=_ce(),T$e=jce(),y8=Gce(),Qc=xp();async function E8(t,e){ju(t);let r=I8(t,Q$e.default,e),s=await Promise.all(r);return Qc.array.flatten(s)}(function(t){t.glob=t,t.globSync=e,t.globStream=r,t.async=t;function e(h,E){ju(h);let C=I8(h,T$e.default,E);return Qc.array.flatten(C)}t.sync=e;function r(h,E){ju(h);let C=I8(h,R$e.default,E);return Qc.stream.merge(C)}t.stream=r;function s(h,E){ju(h);let C=[].concat(h),S=new y8.default(E);return qce.generate(C,S)}t.generateTasks=s;function a(h,E){ju(h);let C=new y8.default(E);return Qc.pattern.isDynamicPattern(h,C)}t.isDynamicPattern=a;function n(h){return ju(h),Qc.path.escape(h)}t.escapePath=n;function c(h){return ju(h),Qc.path.convertPathToPattern(h)}t.convertPathToPattern=c;let f;(function(h){function E(S){return ju(S),Qc.path.escapePosixPath(S)}h.escapePath=E;function C(S){return ju(S),Qc.path.convertPosixPathToPattern(S)}h.convertPathToPattern=C})(f=t.posix||(t.posix={}));let p;(function(h){function E(S){return ju(S),Qc.path.escapeWindowsPath(S)}h.escapePath=E;function C(S){return ju(S),Qc.path.convertWindowsPathToPattern(S)}h.convertPathToPattern=C})(p=t.win32||(t.win32={}))})(E8||(E8={}));function I8(t,e,r){let s=[].concat(t),a=new y8.default(r),n=qce.generate(s,a),c=new e(a);return n.map(c.read,c)}function ju(t){if(![].concat(t).every(s=>Qc.string.isString(s)&&!Qc.string.isEmpty(s)))throw new TypeError(\"Patterns must be a string (non empty) or an array of strings\")}Wce.exports=E8});var Nn={};Vt(Nn,{checksumFile:()=>vQ,checksumPattern:()=>SQ,makeHash:()=>cs});function cs(...t){let e=(0,BQ.createHash)(\"sha512\"),r=\"\";for(let s of t)typeof s==\"string\"?r+=s:s&&(r&&(e.update(r),r=\"\"),e.update(s));return r&&e.update(r),e.digest(\"hex\")}async function vQ(t,{baseFs:e,algorithm:r}={baseFs:ce,algorithm:\"sha512\"}){let s=await e.openPromise(t,\"r\");try{let n=Buffer.allocUnsafeSlow(65536),c=(0,BQ.createHash)(r),f=0;for(;(f=await e.readPromise(s,n,0,65536))!==0;)c.update(f===65536?n:n.slice(0,f));return c.digest(\"hex\")}finally{await e.closePromise(s)}}async function SQ(t,{cwd:e}){let s=(await(0,C8.default)(t,{cwd:fe.fromPortablePath(e),onlyDirectories:!0})).map(f=>`${f}/**/*`),a=await(0,C8.default)([t,...s],{cwd:fe.fromPortablePath(e),onlyFiles:!1});a.sort();let n=await Promise.all(a.map(async f=>{let p=[Buffer.from(f)],h=J.join(e,fe.toPortablePath(f)),E=await ce.lstatPromise(h);return E.isSymbolicLink()?p.push(Buffer.from(await ce.readlinkPromise(h))):E.isFile()&&p.push(await ce.readFilePromise(h)),p.join(\"\\0\")})),c=(0,BQ.createHash)(\"sha512\");for(let f of n)c.update(f);return c.digest(\"hex\")}var BQ,C8,I0=Ze(()=>{Dt();BQ=Ie(\"crypto\"),C8=ut(wQ())});var G={};Vt(G,{allPeerRequests:()=>qB,areDescriptorsEqual:()=>zce,areIdentsEqual:()=>UB,areLocatorsEqual:()=>_B,areVirtualPackagesEquivalent:()=>j$e,bindDescriptor:()=>_$e,bindLocator:()=>H$e,convertDescriptorToLocator:()=>DQ,convertLocatorToDescriptor:()=>B8,convertPackageToLocator:()=>L$e,convertToIdent:()=>O$e,convertToManifestRange:()=>X$e,copyPackage:()=>LB,devirtualizeDescriptor:()=>MB,devirtualizeLocator:()=>rI,ensureDevirtualizedDescriptor:()=>M$e,ensureDevirtualizedLocator:()=>U$e,getIdentVendorPath:()=>P8,isPackageCompatible:()=>QQ,isVirtualDescriptor:()=>kp,isVirtualLocator:()=>Gu,makeDescriptor:()=>On,makeIdent:()=>Da,makeLocator:()=>Ws,makeRange:()=>xQ,parseDescriptor:()=>C0,parseFileStyleRange:()=>z$e,parseIdent:()=>Sa,parseLocator:()=>Qp,parseRange:()=>em,prettyDependent:()=>$4,prettyDescriptor:()=>ni,prettyIdent:()=>Xi,prettyLocator:()=>Yr,prettyLocatorNoColors:()=>X4,prettyRange:()=>iI,prettyReference:()=>jB,prettyResolution:()=>FB,prettyWorkspace:()=>GB,renamePackage:()=>v8,slugifyIdent:()=>w8,slugifyLocator:()=>nI,sortDescriptors:()=>sI,stringifyDescriptor:()=>al,stringifyIdent:()=>un,stringifyLocator:()=>ll,tryParseDescriptor:()=>HB,tryParseIdent:()=>Zce,tryParseLocator:()=>bQ,tryParseRange:()=>K$e,unwrapIdentFromScope:()=>eet,virtualizeDescriptor:()=>S8,virtualizePackage:()=>D8,wrapIdentIntoScope:()=>$$e});function Da(t,e){if(t?.startsWith(\"@\"))throw new Error(\"Invalid scope: don't prefix it with '@'\");return{identHash:cs(t,e),scope:t,name:e}}function On(t,e){return{identHash:t.identHash,scope:t.scope,name:t.name,descriptorHash:cs(t.identHash,e),range:e}}function Ws(t,e){return{identHash:t.identHash,scope:t.scope,name:t.name,locatorHash:cs(t.identHash,e),reference:e}}function O$e(t){return{identHash:t.identHash,scope:t.scope,name:t.name}}function DQ(t){return{identHash:t.identHash,scope:t.scope,name:t.name,locatorHash:t.descriptorHash,reference:t.range}}function B8(t){return{identHash:t.identHash,scope:t.scope,name:t.name,descriptorHash:t.locatorHash,range:t.reference}}function L$e(t){return{identHash:t.identHash,scope:t.scope,name:t.name,locatorHash:t.locatorHash,reference:t.reference}}function v8(t,e){return{identHash:e.identHash,scope:e.scope,name:e.name,locatorHash:e.locatorHash,reference:e.reference,version:t.version,languageName:t.languageName,linkType:t.linkType,conditions:t.conditions,dependencies:new Map(t.dependencies),peerDependencies:new Map(t.peerDependencies),dependenciesMeta:new Map(t.dependenciesMeta),peerDependenciesMeta:new Map(t.peerDependenciesMeta),bin:new Map(t.bin)}}function LB(t){return v8(t,t)}function S8(t,e){if(e.includes(\"#\"))throw new Error(\"Invalid entropy\");return On(t,`virtual:${e}#${t.range}`)}function D8(t,e){if(e.includes(\"#\"))throw new Error(\"Invalid entropy\");return v8(t,Ws(t,`virtual:${e}#${t.reference}`))}function kp(t){return t.range.startsWith(OB)}function Gu(t){return t.reference.startsWith(OB)}function MB(t){if(!kp(t))throw new Error(\"Not a virtual descriptor\");return On(t,t.range.replace(PQ,\"\"))}function rI(t){if(!Gu(t))throw new Error(\"Not a virtual descriptor\");return Ws(t,t.reference.replace(PQ,\"\"))}function M$e(t){return kp(t)?On(t,t.range.replace(PQ,\"\")):t}function U$e(t){return Gu(t)?Ws(t,t.reference.replace(PQ,\"\")):t}function _$e(t,e){return t.range.includes(\"::\")?t:On(t,`${t.range}::${tI.default.stringify(e)}`)}function H$e(t,e){return t.reference.includes(\"::\")?t:Ws(t,`${t.reference}::${tI.default.stringify(e)}`)}function UB(t,e){return t.identHash===e.identHash}function zce(t,e){return t.descriptorHash===e.descriptorHash}function _B(t,e){return t.locatorHash===e.locatorHash}function j$e(t,e){if(!Gu(t))throw new Error(\"Invalid package type\");if(!Gu(e))throw new Error(\"Invalid package type\");if(!UB(t,e)||t.dependencies.size!==e.dependencies.size)return!1;for(let r of t.dependencies.values()){let s=e.dependencies.get(r.identHash);if(!s||!zce(r,s))return!1}return!0}function Sa(t){let e=Zce(t);if(!e)throw new Error(`Invalid ident (${t})`);return e}function Zce(t){let e=t.match(G$e);if(!e)return null;let[,r,s]=e;return Da(typeof r<\"u\"?r:null,s)}function C0(t,e=!1){let r=HB(t,e);if(!r)throw new Error(`Invalid descriptor (${t})`);return r}function HB(t,e=!1){let r=e?t.match(q$e):t.match(W$e);if(!r)return null;let[,s,a,n]=r;if(n===\"unknown\")throw new Error(`Invalid range (${t})`);let c=typeof s<\"u\"?s:null,f=typeof n<\"u\"?n:\"unknown\";return On(Da(c,a),f)}function Qp(t,e=!1){let r=bQ(t,e);if(!r)throw new Error(`Invalid locator (${t})`);return r}function bQ(t,e=!1){let r=e?t.match(Y$e):t.match(V$e);if(!r)return null;let[,s,a,n]=r;if(n===\"unknown\")throw new Error(`Invalid reference (${t})`);let c=typeof s<\"u\"?s:null,f=typeof n<\"u\"?n:\"unknown\";return Ws(Da(c,a),f)}function em(t,e){let r=t.match(J$e);if(r===null)throw new Error(`Invalid range (${t})`);let s=typeof r[1]<\"u\"?r[1]:null;if(typeof e?.requireProtocol==\"string\"&&s!==e.requireProtocol)throw new Error(`Invalid protocol (${s})`);if(e?.requireProtocol&&s===null)throw new Error(`Missing protocol (${s})`);let a=typeof r[3]<\"u\"?decodeURIComponent(r[2]):null;if(e?.requireSource&&a===null)throw new Error(`Missing source (${t})`);let n=typeof r[3]<\"u\"?decodeURIComponent(r[3]):decodeURIComponent(r[2]),c=e?.parseSelector?tI.default.parse(n):n,f=typeof r[4]<\"u\"?tI.default.parse(r[4]):null;return{protocol:s,source:a,selector:c,params:f}}function K$e(t,e){try{return em(t,e)}catch{return null}}function z$e(t,{protocol:e}){let{selector:r,params:s}=em(t,{requireProtocol:e,requireBindings:!0});if(typeof s.locator!=\"string\")throw new Error(`Assertion failed: Invalid bindings for ${t}`);return{parentLocator:Qp(s.locator,!0),path:r}}function Yce(t){return t=t.replaceAll(\"%\",\"%25\"),t=t.replaceAll(\":\",\"%3A\"),t=t.replaceAll(\"#\",\"%23\"),t}function Z$e(t){return t===null?!1:Object.entries(t).length>0}function xQ({protocol:t,source:e,selector:r,params:s}){let a=\"\";return t!==null&&(a+=`${t}`),e!==null&&(a+=`${Yce(e)}#`),a+=Yce(r),Z$e(s)&&(a+=`::${tI.default.stringify(s)}`),a}function X$e(t){let{params:e,protocol:r,source:s,selector:a}=em(t);for(let n in e)n.startsWith(\"__\")&&delete e[n];return xQ({protocol:r,source:s,params:e,selector:a})}function un(t){return t.scope?`@${t.scope}/${t.name}`:`${t.name}`}function $$e(t,e){return t.scope?Da(e,`${t.scope}__${t.name}`):Da(e,t.name)}function eet(t,e){if(t.scope!==e)return t;let r=t.name.indexOf(\"__\");if(r===-1)return Da(null,t.name);let s=t.name.slice(0,r),a=t.name.slice(r+2);return Da(s,a)}function al(t){return t.scope?`@${t.scope}/${t.name}@${t.range}`:`${t.name}@${t.range}`}function ll(t){return t.scope?`@${t.scope}/${t.name}@${t.reference}`:`${t.name}@${t.reference}`}function w8(t){return t.scope!==null?`@${t.scope}-${t.name}`:t.name}function nI(t){let{protocol:e,selector:r}=em(t.reference),s=e!==null?e.replace(tet,\"\"):\"exotic\",a=Vce.default.valid(r),n=a!==null?`${s}-${a}`:`${s}`,c=10;return t.scope?`${w8(t)}-${n}-${t.locatorHash.slice(0,c)}`:`${w8(t)}-${n}-${t.locatorHash.slice(0,c)}`}function Xi(t,e){return e.scope?`${Ht(t,`@${e.scope}/`,ht.SCOPE)}${Ht(t,e.name,ht.NAME)}`:`${Ht(t,e.name,ht.NAME)}`}function kQ(t){if(t.startsWith(OB)){let e=kQ(t.substring(t.indexOf(\"#\")+1)),r=t.substring(OB.length,OB.length+F$e);return`${e} [${r}]`}else return t.replace(ret,\"?[...]\")}function iI(t,e){return`${Ht(t,kQ(e),ht.RANGE)}`}function ni(t,e){return`${Xi(t,e)}${Ht(t,\"@\",ht.RANGE)}${iI(t,e.range)}`}function jB(t,e){return`${Ht(t,kQ(e),ht.REFERENCE)}`}function Yr(t,e){return`${Xi(t,e)}${Ht(t,\"@\",ht.REFERENCE)}${jB(t,e.reference)}`}function X4(t){return`${un(t)}@${kQ(t.reference)}`}function sI(t){return qs(t,[e=>un(e),e=>e.range])}function GB(t,e){return Xi(t,e.anchoredLocator)}function FB(t,e,r){let s=kp(e)?MB(e):e;return r===null?`${ni(t,s)} \\u2192 ${Z4(t).Cross}`:s.identHash===r.identHash?`${ni(t,s)} \\u2192 ${jB(t,r.reference)}`:`${ni(t,s)} \\u2192 ${Yr(t,r)}`}function $4(t,e,r){return r===null?`${Yr(t,e)}`:`${Yr(t,e)} (via ${iI(t,r.range)})`}function P8(t){return`node_modules/${un(t)}`}function QQ(t,e){return t.conditions?N$e(t.conditions,r=>{let[,s,a]=r.match(Kce),n=e[s];return n?n.includes(a):!0}):!0}function qB(t){let e=new Set;if(\"children\"in t)e.add(t);else for(let r of t.requests.values())e.add(r);for(let r of e)for(let s of r.children.values())e.add(s);return e}var tI,Vce,Jce,OB,F$e,Kce,N$e,PQ,G$e,q$e,W$e,Y$e,V$e,J$e,tet,ret,Wo=Ze(()=>{tI=ut(Ie(\"querystring\")),Vce=ut(Ai()),Jce=ut(dse());xc();I0();bc();Wo();OB=\"virtual:\",F$e=5,Kce=/(os|cpu|libc)=([a-z0-9_-]+)/,N$e=(0,Jce.makeParser)(Kce);PQ=/^[^#]*#/;G$e=/^(?:@([^/]+?)\\/)?([^@/]+)$/;q$e=/^(?:@([^/]+?)\\/)?([^@/]+?)(?:@(.+))$/,W$e=/^(?:@([^/]+?)\\/)?([^@/]+?)(?:@(.+))?$/;Y$e=/^(?:@([^/]+?)\\/)?([^@/]+?)(?:@(.+))$/,V$e=/^(?:@([^/]+?)\\/)?([^@/]+?)(?:@(.+))?$/;J$e=/^([^#:]*:)?((?:(?!::)[^#])*)(?:#((?:(?!::).)*))?(?:::(.*))?$/;tet=/:$/;ret=/\\?.*/});var Xce,$ce=Ze(()=>{Wo();Xce={hooks:{reduceDependency:(t,e,r,s,{resolver:a,resolveOptions:n})=>{for(let{pattern:c,reference:f}of e.topLevelWorkspace.manifest.resolutions){if(c.from&&(c.from.fullName!==un(r)||e.configuration.normalizeLocator(Ws(Sa(c.from.fullName),c.from.description??r.reference)).locatorHash!==r.locatorHash)||c.descriptor.fullName!==un(t)||e.configuration.normalizeDependency(On(Qp(c.descriptor.fullName),c.descriptor.description??t.range)).descriptorHash!==t.descriptorHash)continue;return a.bindDescriptor(e.configuration.normalizeDependency(On(t,f)),e.topLevelWorkspace.anchoredLocator,n)}return t},validateProject:async(t,e)=>{for(let r of t.workspaces){let s=GB(t.configuration,r);await t.configuration.triggerHook(a=>a.validateWorkspace,r,{reportWarning:(a,n)=>e.reportWarning(a,`${s}: ${n}`),reportError:(a,n)=>e.reportError(a,`${s}: ${n}`)})}},validateWorkspace:async(t,e)=>{let{manifest:r}=t;r.resolutions.length&&t.cwd!==t.project.cwd&&r.errors.push(new Error(\"Resolutions field will be ignored\"));for(let s of r.errors)e.reportWarning(57,s.message)}}}});var Ei,tm=Ze(()=>{Ei=class t{static{this.protocol=\"workspace:\"}supportsDescriptor(e,r){return!!(e.range.startsWith(t.protocol)||r.project.tryWorkspaceByDescriptor(e)!==null)}supportsLocator(e,r){return!!e.reference.startsWith(t.protocol)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,s){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){return[s.project.getWorkspaceByDescriptor(e).anchoredLocator]}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){let s=r.project.getWorkspaceByCwd(e.reference.slice(t.protocol.length));return{...e,version:s.manifest.version||\"0.0.0\",languageName:\"unknown\",linkType:\"SOFT\",conditions:null,dependencies:r.project.configuration.normalizeDependencyMap(new Map([...s.manifest.dependencies,...s.manifest.devDependencies])),peerDependencies:new Map([...s.manifest.peerDependencies]),dependenciesMeta:s.manifest.dependenciesMeta,peerDependenciesMeta:s.manifest.peerDependenciesMeta,bin:s.manifest.bin}}}});var Fr={};Vt(Fr,{SemVer:()=>iue.SemVer,clean:()=>iet,getComparator:()=>rue,mergeComparators:()=>b8,satisfiesWithPrereleases:()=>Xf,simplifyRanges:()=>x8,stringifyComparator:()=>nue,validRange:()=>cl});function Xf(t,e,r=!1){if(!t)return!1;let s=`${e}${r}`,a=eue.get(s);if(typeof a>\"u\")try{a=new Rp.default.Range(e,{includePrerelease:!0,loose:r})}catch{return!1}finally{eue.set(s,a||null)}else if(a===null)return!1;let n;try{n=new Rp.default.SemVer(t,a)}catch{return!1}return a.test(n)?!0:(n.prerelease&&(n.prerelease=[]),a.set.some(c=>{for(let f of c)f.semver.prerelease&&(f.semver.prerelease=[]);return c.every(f=>f.test(n))}))}function cl(t){if(t.indexOf(\":\")!==-1)return null;let e=tue.get(t);if(typeof e<\"u\")return e;try{e=new Rp.default.Range(t)}catch{e=null}return tue.set(t,e),e}function iet(t){let e=net.exec(t);return e?e[1]:null}function rue(t){if(t.semver===Rp.default.Comparator.ANY)return{gt:null,lt:null};switch(t.operator){case\"\":return{gt:[\">=\",t.semver],lt:[\"<=\",t.semver]};case\">\":case\">=\":return{gt:[t.operator,t.semver],lt:null};case\"<\":case\"<=\":return{gt:null,lt:[t.operator,t.semver]};default:throw new Error(`Assertion failed: Unexpected comparator operator (${t.operator})`)}}function b8(t){if(t.length===0)return null;let e=null,r=null;for(let s of t){if(s.gt){let a=e!==null?Rp.default.compare(s.gt[1],e[1]):null;(a===null||a>0||a===0&&s.gt[0]===\">\")&&(e=s.gt)}if(s.lt){let a=r!==null?Rp.default.compare(s.lt[1],r[1]):null;(a===null||a<0||a===0&&s.lt[0]===\"<\")&&(r=s.lt)}}if(e&&r){let s=Rp.default.compare(e[1],r[1]);if(s===0&&(e[0]===\">\"||r[0]===\"<\")||s>0)return null}return{gt:e,lt:r}}function nue(t){if(t.gt&&t.lt){if(t.gt[0]===\">=\"&&t.lt[0]===\"<=\"&&t.gt[1].version===t.lt[1].version)return t.gt[1].version;if(t.gt[0]===\">=\"&&t.lt[0]===\"<\"){if(t.lt[1].version===`${t.gt[1].major+1}.0.0-0`)return`^${t.gt[1].version}`;if(t.lt[1].version===`${t.gt[1].major}.${t.gt[1].minor+1}.0-0`)return`~${t.gt[1].version}`}}let e=[];return t.gt&&e.push(t.gt[0]+t.gt[1].version),t.lt&&e.push(t.lt[0]+t.lt[1].version),e.length?e.join(\" \"):\"*\"}function x8(t){let e=t.map(set).map(s=>cl(s).set.map(a=>a.map(n=>rue(n)))),r=e.shift().map(s=>b8(s)).filter(s=>s!==null);for(let s of e){let a=[];for(let n of r)for(let c of s){let f=b8([n,...c]);f!==null&&a.push(f)}r=a}return r.length===0?null:r.map(s=>nue(s)).join(\" || \")}function set(t){let e=t.split(\"||\");if(e.length>1){let r=new Set;for(let s of e)e.some(a=>a!==s&&Rp.default.subset(s,a))||r.add(s);if(r.size<e.length)return[...r].join(\" || \")}return t}var Rp,iue,eue,tue,net,Tp=Ze(()=>{Rp=ut(Ai()),iue=ut(Ai()),eue=new Map;tue=new Map;net=/^(?:[\\sv=]*?)((0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)(?:\\s*)$/});function sue(t){let e=t.match(/^[ \\t]+/m);return e?e[0]:\"  \"}function oue(t){return t.charCodeAt(0)===65279?t.slice(1):t}function Pa(t){return t.replace(/\\\\/g,\"/\")}function RQ(t,{yamlCompatibilityMode:e}){return e?q4(t):typeof t>\"u\"||typeof t==\"boolean\"?t:null}function aue(t,e){let r=e.search(/[^!]/);if(r===-1)return\"invalid\";let s=r%2===0?\"\":\"!\",a=e.slice(r);return`${s}${t}=${a}`}function k8(t,e){return e.length===1?aue(t,e[0]):`(${e.map(r=>aue(t,r)).join(\" | \")})`}var lue,Ut,oI=Ze(()=>{Dt();wc();lue=ut(Ai());tm();bc();Tp();Wo();Ut=class t{constructor(){this.indent=\"  \";this.name=null;this.version=null;this.os=null;this.cpu=null;this.libc=null;this.type=null;this.packageManager=null;this.private=!1;this.license=null;this.main=null;this.module=null;this.browser=null;this.languageName=null;this.bin=new Map;this.scripts=new Map;this.dependencies=new Map;this.devDependencies=new Map;this.peerDependencies=new Map;this.workspaceDefinitions=[];this.dependenciesMeta=new Map;this.peerDependenciesMeta=new Map;this.resolutions=[];this.files=null;this.publishConfig=null;this.installConfig=null;this.preferUnplugged=null;this.raw={};this.errors=[]}static{this.fileName=\"package.json\"}static{this.allDependencies=[\"dependencies\",\"devDependencies\",\"peerDependencies\"]}static{this.hardDependencies=[\"dependencies\",\"devDependencies\"]}static async tryFind(e,{baseFs:r=new Yn}={}){let s=J.join(e,\"package.json\");try{return await t.fromFile(s,{baseFs:r})}catch(a){if(a.code===\"ENOENT\")return null;throw a}}static async find(e,{baseFs:r}={}){let s=await t.tryFind(e,{baseFs:r});if(s===null)throw new Error(\"Manifest not found\");return s}static async fromFile(e,{baseFs:r=new Yn}={}){let s=new t;return await s.loadFile(e,{baseFs:r}),s}static fromText(e){let r=new t;return r.loadFromText(e),r}loadFromText(e){let r;try{r=JSON.parse(oue(e)||\"{}\")}catch(s){throw s.message+=` (when parsing ${e})`,s}this.load(r),this.indent=sue(e)}async loadFile(e,{baseFs:r=new Yn}){let s=await r.readFilePromise(e,\"utf8\"),a;try{a=JSON.parse(oue(s)||\"{}\")}catch(n){throw n.message+=` (when parsing ${e})`,n}this.load(a),this.indent=sue(s)}load(e,{yamlCompatibilityMode:r=!1}={}){if(typeof e!=\"object\"||e===null)throw new Error(`Utterly invalid manifest data (${e})`);this.raw=e;let s=[];if(this.name=null,typeof e.name==\"string\")try{this.name=Sa(e.name)}catch{s.push(new Error(\"Parsing failed for the 'name' field\"))}if(typeof e.version==\"string\"?this.version=e.version:this.version=null,Array.isArray(e.os)){let n=[];this.os=n;for(let c of e.os)typeof c!=\"string\"?s.push(new Error(\"Parsing failed for the 'os' field\")):n.push(c)}else this.os=null;if(Array.isArray(e.cpu)){let n=[];this.cpu=n;for(let c of e.cpu)typeof c!=\"string\"?s.push(new Error(\"Parsing failed for the 'cpu' field\")):n.push(c)}else this.cpu=null;if(Array.isArray(e.libc)){let n=[];this.libc=n;for(let c of e.libc)typeof c!=\"string\"?s.push(new Error(\"Parsing failed for the 'libc' field\")):n.push(c)}else this.libc=null;if(typeof e.type==\"string\"?this.type=e.type:this.type=null,typeof e.packageManager==\"string\"?this.packageManager=e.packageManager:this.packageManager=null,typeof e.private==\"boolean\"?this.private=e.private:this.private=!1,typeof e.license==\"string\"?this.license=e.license:this.license=null,typeof e.languageName==\"string\"?this.languageName=e.languageName:this.languageName=null,typeof e.main==\"string\"?this.main=Pa(e.main):this.main=null,typeof e.module==\"string\"?this.module=Pa(e.module):this.module=null,e.browser!=null)if(typeof e.browser==\"string\")this.browser=Pa(e.browser);else{this.browser=new Map;for(let[n,c]of Object.entries(e.browser))this.browser.set(Pa(n),typeof c==\"string\"?Pa(c):c)}else this.browser=null;if(this.bin=new Map,typeof e.bin==\"string\")e.bin.trim()===\"\"?s.push(new Error(\"Invalid bin field\")):this.name!==null?this.bin.set(this.name.name,Pa(e.bin)):s.push(new Error(\"String bin field, but no attached package name\"));else if(typeof e.bin==\"object\"&&e.bin!==null)for(let[n,c]of Object.entries(e.bin)){if(typeof c!=\"string\"||c.trim()===\"\"){s.push(new Error(`Invalid bin definition for '${n}'`));continue}let f=Sa(n);this.bin.set(f.name,Pa(c))}if(this.scripts=new Map,typeof e.scripts==\"object\"&&e.scripts!==null)for(let[n,c]of Object.entries(e.scripts)){if(typeof c!=\"string\"){s.push(new Error(`Invalid script definition for '${n}'`));continue}this.scripts.set(n,c)}if(this.dependencies=new Map,typeof e.dependencies==\"object\"&&e.dependencies!==null)for(let[n,c]of Object.entries(e.dependencies)){if(typeof c!=\"string\"){s.push(new Error(`Invalid dependency range for '${n}'`));continue}let f;try{f=Sa(n)}catch{s.push(new Error(`Parsing failed for the dependency name '${n}'`));continue}let p=On(f,c);this.dependencies.set(p.identHash,p)}if(this.devDependencies=new Map,typeof e.devDependencies==\"object\"&&e.devDependencies!==null)for(let[n,c]of Object.entries(e.devDependencies)){if(typeof c!=\"string\"){s.push(new Error(`Invalid dependency range for '${n}'`));continue}let f;try{f=Sa(n)}catch{s.push(new Error(`Parsing failed for the dependency name '${n}'`));continue}let p=On(f,c);this.devDependencies.set(p.identHash,p)}if(this.peerDependencies=new Map,typeof e.peerDependencies==\"object\"&&e.peerDependencies!==null)for(let[n,c]of Object.entries(e.peerDependencies)){let f;try{f=Sa(n)}catch{s.push(new Error(`Parsing failed for the dependency name '${n}'`));continue}(typeof c!=\"string\"||!c.startsWith(Ei.protocol)&&!cl(c))&&(s.push(new Error(`Invalid dependency range for '${n}'`)),c=\"*\");let p=On(f,c);this.peerDependencies.set(p.identHash,p)}typeof e.workspaces==\"object\"&&e.workspaces!==null&&e.workspaces.nohoist&&s.push(new Error(\"'nohoist' is deprecated, please use 'installConfig.hoistingLimits' instead\"));let a=Array.isArray(e.workspaces)?e.workspaces:typeof e.workspaces==\"object\"&&e.workspaces!==null&&Array.isArray(e.workspaces.packages)?e.workspaces.packages:[];this.workspaceDefinitions=[];for(let n of a){if(typeof n!=\"string\"){s.push(new Error(`Invalid workspace definition for '${n}'`));continue}this.workspaceDefinitions.push({pattern:n})}if(this.dependenciesMeta=new Map,typeof e.dependenciesMeta==\"object\"&&e.dependenciesMeta!==null)for(let[n,c]of Object.entries(e.dependenciesMeta)){if(typeof c!=\"object\"||c===null){s.push(new Error(`Invalid meta field for '${n}`));continue}let f=C0(n),p=this.ensureDependencyMeta(f),h=RQ(c.built,{yamlCompatibilityMode:r});if(h===null){s.push(new Error(`Invalid built meta field for '${n}'`));continue}let E=RQ(c.optional,{yamlCompatibilityMode:r});if(E===null){s.push(new Error(`Invalid optional meta field for '${n}'`));continue}let C=RQ(c.unplugged,{yamlCompatibilityMode:r});if(C===null){s.push(new Error(`Invalid unplugged meta field for '${n}'`));continue}Object.assign(p,{built:h,optional:E,unplugged:C})}if(this.peerDependenciesMeta=new Map,typeof e.peerDependenciesMeta==\"object\"&&e.peerDependenciesMeta!==null)for(let[n,c]of Object.entries(e.peerDependenciesMeta)){if(typeof c!=\"object\"||c===null){s.push(new Error(`Invalid meta field for '${n}'`));continue}let f=C0(n),p=this.ensurePeerDependencyMeta(f),h=RQ(c.optional,{yamlCompatibilityMode:r});if(h===null){s.push(new Error(`Invalid optional meta field for '${n}'`));continue}Object.assign(p,{optional:h})}if(this.resolutions=[],typeof e.resolutions==\"object\"&&e.resolutions!==null)for(let[n,c]of Object.entries(e.resolutions)){if(typeof c!=\"string\"){s.push(new Error(`Invalid resolution entry for '${n}'`));continue}try{this.resolutions.push({pattern:px(n),reference:c})}catch(f){s.push(f);continue}}if(Array.isArray(e.files)){this.files=new Set;for(let n of e.files){if(typeof n!=\"string\"){s.push(new Error(`Invalid files entry for '${n}'`));continue}this.files.add(n)}}else this.files=null;if(typeof e.publishConfig==\"object\"&&e.publishConfig!==null){if(this.publishConfig={},typeof e.publishConfig.access==\"string\"&&(this.publishConfig.access=e.publishConfig.access),typeof e.publishConfig.main==\"string\"&&(this.publishConfig.main=Pa(e.publishConfig.main)),typeof e.publishConfig.module==\"string\"&&(this.publishConfig.module=Pa(e.publishConfig.module)),e.publishConfig.browser!=null)if(typeof e.publishConfig.browser==\"string\")this.publishConfig.browser=Pa(e.publishConfig.browser);else{this.publishConfig.browser=new Map;for(let[n,c]of Object.entries(e.publishConfig.browser))this.publishConfig.browser.set(Pa(n),typeof c==\"string\"?Pa(c):c)}if(typeof e.publishConfig.registry==\"string\"&&(this.publishConfig.registry=e.publishConfig.registry),typeof e.publishConfig.provenance==\"boolean\"&&(this.publishConfig.provenance=e.publishConfig.provenance),typeof e.publishConfig.bin==\"string\")this.name!==null?this.publishConfig.bin=new Map([[this.name.name,Pa(e.publishConfig.bin)]]):s.push(new Error(\"String bin field, but no attached package name\"));else if(typeof e.publishConfig.bin==\"object\"&&e.publishConfig.bin!==null){this.publishConfig.bin=new Map;for(let[n,c]of Object.entries(e.publishConfig.bin)){if(typeof c!=\"string\"){s.push(new Error(`Invalid bin definition for '${n}'`));continue}this.publishConfig.bin.set(n,Pa(c))}}if(Array.isArray(e.publishConfig.executableFiles)){this.publishConfig.executableFiles=new Set;for(let n of e.publishConfig.executableFiles){if(typeof n!=\"string\"){s.push(new Error(\"Invalid executable file definition\"));continue}this.publishConfig.executableFiles.add(Pa(n))}}}else this.publishConfig=null;if(typeof e.installConfig==\"object\"&&e.installConfig!==null){this.installConfig={};for(let n of Object.keys(e.installConfig))n===\"hoistingLimits\"?typeof e.installConfig.hoistingLimits==\"string\"?this.installConfig.hoistingLimits=e.installConfig.hoistingLimits:s.push(new Error(\"Invalid hoisting limits definition\")):n==\"selfReferences\"?typeof e.installConfig.selfReferences==\"boolean\"?this.installConfig.selfReferences=e.installConfig.selfReferences:s.push(new Error(\"Invalid selfReferences definition, must be a boolean value\")):s.push(new Error(`Unrecognized installConfig key: ${n}`))}else this.installConfig=null;if(typeof e.optionalDependencies==\"object\"&&e.optionalDependencies!==null)for(let[n,c]of Object.entries(e.optionalDependencies)){if(typeof c!=\"string\"){s.push(new Error(`Invalid dependency range for '${n}'`));continue}let f;try{f=Sa(n)}catch{s.push(new Error(`Parsing failed for the dependency name '${n}'`));continue}let p=On(f,c);this.dependencies.set(p.identHash,p);let h=On(f,\"unknown\"),E=this.ensureDependencyMeta(h);Object.assign(E,{optional:!0})}typeof e.preferUnplugged==\"boolean\"?this.preferUnplugged=e.preferUnplugged:this.preferUnplugged=null,this.errors=s}getForScope(e){switch(e){case\"dependencies\":return this.dependencies;case\"devDependencies\":return this.devDependencies;case\"peerDependencies\":return this.peerDependencies;default:throw new Error(`Unsupported value (\"${e}\")`)}}hasConsumerDependency(e){return!!(this.dependencies.has(e.identHash)||this.peerDependencies.has(e.identHash))}hasHardDependency(e){return!!(this.dependencies.has(e.identHash)||this.devDependencies.has(e.identHash))}hasSoftDependency(e){return!!this.peerDependencies.has(e.identHash)}hasDependency(e){return!!(this.hasHardDependency(e)||this.hasSoftDependency(e))}getConditions(){let e=[];return this.os&&this.os.length>0&&e.push(k8(\"os\",this.os)),this.cpu&&this.cpu.length>0&&e.push(k8(\"cpu\",this.cpu)),this.libc&&this.libc.length>0&&e.push(k8(\"libc\",this.libc)),e.length>0?e.join(\" & \"):null}ensureDependencyMeta(e){if(e.range!==\"unknown\"&&!lue.default.valid(e.range))throw new Error(`Invalid meta field range for '${al(e)}'`);let r=un(e),s=e.range!==\"unknown\"?e.range:null,a=this.dependenciesMeta.get(r);a||this.dependenciesMeta.set(r,a=new Map);let n=a.get(s);return n||a.set(s,n={}),n}ensurePeerDependencyMeta(e){if(e.range!==\"unknown\")throw new Error(`Invalid meta field range for '${al(e)}'`);let r=un(e),s=this.peerDependenciesMeta.get(r);return s||this.peerDependenciesMeta.set(r,s={}),s}setRawField(e,r,{after:s=[]}={}){let a=new Set(s.filter(n=>Object.hasOwn(this.raw,n)));if(a.size===0||Object.hasOwn(this.raw,e))this.raw[e]=r;else{let n=this.raw,c=this.raw={},f=!1;for(let p of Object.keys(n))c[p]=n[p],f||(a.delete(p),a.size===0&&(c[e]=r,f=!0))}}exportTo(e,{compatibilityMode:r=!0}={}){if(Object.assign(e,this.raw),this.name!==null?e.name=un(this.name):delete e.name,this.version!==null?e.version=this.version:delete e.version,this.os!==null?e.os=this.os:delete e.os,this.cpu!==null?e.cpu=this.cpu:delete e.cpu,this.type!==null?e.type=this.type:delete e.type,this.packageManager!==null?e.packageManager=this.packageManager:delete e.packageManager,this.private?e.private=!0:delete e.private,this.license!==null?e.license=this.license:delete e.license,this.languageName!==null?e.languageName=this.languageName:delete e.languageName,this.main!==null?e.main=this.main:delete e.main,this.module!==null?e.module=this.module:delete e.module,this.browser!==null){let n=this.browser;typeof n==\"string\"?e.browser=n:n instanceof Map&&(e.browser=Object.assign({},...Array.from(n.keys()).sort().map(c=>({[c]:n.get(c)}))))}else delete e.browser;this.bin.size===1&&this.name!==null&&this.bin.has(this.name.name)?e.bin=this.bin.get(this.name.name):this.bin.size>0?e.bin=Object.assign({},...Array.from(this.bin.keys()).sort().map(n=>({[n]:this.bin.get(n)}))):delete e.bin,this.workspaceDefinitions.length>0?this.raw.workspaces&&!Array.isArray(this.raw.workspaces)?e.workspaces={...this.raw.workspaces,packages:this.workspaceDefinitions.map(({pattern:n})=>n)}:e.workspaces=this.workspaceDefinitions.map(({pattern:n})=>n):this.raw.workspaces&&!Array.isArray(this.raw.workspaces)&&Object.keys(this.raw.workspaces).length>0?e.workspaces=this.raw.workspaces:delete e.workspaces;let s=[],a=[];for(let n of this.dependencies.values()){let c=this.dependenciesMeta.get(un(n)),f=!1;if(r&&c){let p=c.get(null);p&&p.optional&&(f=!0)}f?a.push(n):s.push(n)}s.length>0?e.dependencies=Object.assign({},...sI(s).map(n=>({[un(n)]:n.range}))):delete e.dependencies,a.length>0?e.optionalDependencies=Object.assign({},...sI(a).map(n=>({[un(n)]:n.range}))):delete e.optionalDependencies,this.devDependencies.size>0?e.devDependencies=Object.assign({},...sI(this.devDependencies.values()).map(n=>({[un(n)]:n.range}))):delete e.devDependencies,this.peerDependencies.size>0?e.peerDependencies=Object.assign({},...sI(this.peerDependencies.values()).map(n=>({[un(n)]:n.range}))):delete e.peerDependencies,e.dependenciesMeta={};for(let[n,c]of qs(this.dependenciesMeta.entries(),([f,p])=>f))for(let[f,p]of qs(c.entries(),([h,E])=>h!==null?`0${h}`:\"1\")){let h=f!==null?al(On(Sa(n),f)):n,E={...p};r&&f===null&&delete E.optional,Object.keys(E).length!==0&&(e.dependenciesMeta[h]=E)}if(Object.keys(e.dependenciesMeta).length===0&&delete e.dependenciesMeta,this.peerDependenciesMeta.size>0?e.peerDependenciesMeta=Object.assign({},...qs(this.peerDependenciesMeta.entries(),([n,c])=>n).map(([n,c])=>({[n]:c}))):delete e.peerDependenciesMeta,this.resolutions.length>0?e.resolutions=Object.assign({},...this.resolutions.map(({pattern:n,reference:c})=>({[hx(n)]:c}))):delete e.resolutions,this.files!==null?e.files=Array.from(this.files):delete e.files,this.preferUnplugged!==null?e.preferUnplugged=this.preferUnplugged:delete e.preferUnplugged,this.scripts!==null&&this.scripts.size>0){e.scripts??={};for(let n of Object.keys(e.scripts))this.scripts.has(n)||delete e.scripts[n];for(let[n,c]of this.scripts.entries())e.scripts[n]=c}else delete e.scripts;return e}}});function aet(t){return typeof t.reportCode<\"u\"}var cue,uue,oet,jt,Ao,Rc=Ze(()=>{ql();cue=Ie(\"stream\"),uue=Ie(\"string_decoder\"),oet=15,jt=class extends Error{constructor(r,s,a){super(s);this.reportExtra=a;this.reportCode=r}};Ao=class{constructor(){this.cacheHits=new Set;this.cacheMisses=new Set;this.reportedInfos=new Set;this.reportedWarnings=new Set;this.reportedErrors=new Set}getRecommendedLength(){return 180}reportCacheHit(e){this.cacheHits.add(e.locatorHash)}reportCacheMiss(e,r){this.cacheMisses.add(e.locatorHash)}static progressViaCounter(e){let r=0,s,a=new Promise(p=>{s=p}),n=p=>{let h=s;a=new Promise(E=>{s=E}),r=p,h()},c=(p=0)=>{n(r+1)},f=async function*(){for(;r<e;)await a,yield{progress:r/e}}();return{[Symbol.asyncIterator](){return f},hasProgress:!0,hasTitle:!1,set:n,tick:c}}static progressViaTitle(){let e,r,s=new Promise(c=>{r=c}),a=k4(c=>{let f=r;s=new Promise(p=>{r=p}),e=c,f()},1e3/oet),n=async function*(){for(;;)await s,yield{title:e}}();return{[Symbol.asyncIterator](){return n},hasProgress:!1,hasTitle:!0,setTitle:a}}async startProgressPromise(e,r){let s=this.reportProgress(e);try{return await r(e)}finally{s.stop()}}startProgressSync(e,r){let s=this.reportProgress(e);try{return r(e)}finally{s.stop()}}reportInfoOnce(e,r,s){let a=s&&s.key?s.key:r;this.reportedInfos.has(a)||(this.reportedInfos.add(a),this.reportInfo(e,r),s?.reportExtra?.(this))}reportWarningOnce(e,r,s){let a=s&&s.key?s.key:r;this.reportedWarnings.has(a)||(this.reportedWarnings.add(a),this.reportWarning(e,r),s?.reportExtra?.(this))}reportErrorOnce(e,r,s){let a=s&&s.key?s.key:r;this.reportedErrors.has(a)||(this.reportedErrors.add(a),this.reportError(e,r),s?.reportExtra?.(this))}reportExceptionOnce(e){aet(e)?this.reportErrorOnce(e.reportCode,e.message,{key:e,reportExtra:e.reportExtra}):this.reportErrorOnce(1,e.stack||e.message,{key:e})}createStreamReporter(e=null){let r=new cue.PassThrough,s=new uue.StringDecoder,a=\"\";return r.on(\"data\",n=>{let c=s.write(n),f;do if(f=c.indexOf(`\n`),f!==-1){let p=a+c.substring(0,f);c=c.substring(f+1),a=\"\",e!==null?this.reportInfo(null,`${e} ${p}`):this.reportInfo(null,p)}while(f!==-1);a+=c}),r.on(\"end\",()=>{let n=s.end();n!==\"\"&&(e!==null?this.reportInfo(null,`${e} ${n}`):this.reportInfo(null,n))}),r}}});var aI,Q8=Ze(()=>{Rc();Wo();aI=class{constructor(e){this.fetchers=e}supports(e,r){return!!this.tryFetcher(e,r)}getLocalPath(e,r){return this.getFetcher(e,r).getLocalPath(e,r)}async fetch(e,r){return await this.getFetcher(e,r).fetch(e,r)}tryFetcher(e,r){let s=this.fetchers.find(a=>a.supports(e,r));return s||null}getFetcher(e,r){let s=this.fetchers.find(a=>a.supports(e,r));if(!s)throw new jt(11,`${Yr(r.project.configuration,e)} isn't supported by any available fetcher`);return s}}});var rm,R8=Ze(()=>{Wo();rm=class{constructor(e){this.resolvers=e.filter(r=>r)}supportsDescriptor(e,r){return!!this.tryResolverByDescriptor(e,r)}supportsLocator(e,r){return!!this.tryResolverByLocator(e,r)}shouldPersistResolution(e,r){return this.getResolverByLocator(e,r).shouldPersistResolution(e,r)}bindDescriptor(e,r,s){return this.getResolverByDescriptor(e,s).bindDescriptor(e,r,s)}getResolutionDependencies(e,r){return this.getResolverByDescriptor(e,r).getResolutionDependencies(e,r)}async getCandidates(e,r,s){return await this.getResolverByDescriptor(e,s).getCandidates(e,r,s)}async getSatisfying(e,r,s,a){return this.getResolverByDescriptor(e,a).getSatisfying(e,r,s,a)}async resolve(e,r){return await this.getResolverByLocator(e,r).resolve(e,r)}tryResolverByDescriptor(e,r){let s=this.resolvers.find(a=>a.supportsDescriptor(e,r));return s||null}getResolverByDescriptor(e,r){let s=this.resolvers.find(a=>a.supportsDescriptor(e,r));if(!s)throw new Error(`${ni(r.project.configuration,e)} isn't supported by any available resolver`);return s}tryResolverByLocator(e,r){let s=this.resolvers.find(a=>a.supportsLocator(e,r));return s||null}getResolverByLocator(e,r){let s=this.resolvers.find(a=>a.supportsLocator(e,r));if(!s)throw new Error(`${Yr(r.project.configuration,e)} isn't supported by any available resolver`);return s}}});var lI,T8=Ze(()=>{Dt();Wo();lI=class{supports(e){return!!e.reference.startsWith(\"virtual:\")}getLocalPath(e,r){let s=e.reference.indexOf(\"#\");if(s===-1)throw new Error(\"Invalid virtual package reference\");let a=e.reference.slice(s+1),n=Ws(e,a);return r.fetcher.getLocalPath(n,r)}async fetch(e,r){let s=e.reference.indexOf(\"#\");if(s===-1)throw new Error(\"Invalid virtual package reference\");let a=e.reference.slice(s+1),n=Ws(e,a),c=await r.fetcher.fetch(n,r);return await this.ensureVirtualLink(e,c,r)}getLocatorFilename(e){return nI(e)}async ensureVirtualLink(e,r,s){let a=r.packageFs.getRealPath(),n=s.project.configuration.get(\"virtualFolder\"),c=this.getLocatorFilename(e),f=uo.makeVirtualPath(n,c,a),p=new _f(f,{baseFs:r.packageFs,pathUtils:J});return{...r,packageFs:p}}}});var TQ,fue=Ze(()=>{TQ=class t{static{this.protocol=\"virtual:\"}static isVirtualDescriptor(e){return!!e.range.startsWith(t.protocol)}static isVirtualLocator(e){return!!e.reference.startsWith(t.protocol)}supportsDescriptor(e,r){return t.isVirtualDescriptor(e)}supportsLocator(e,r){return t.isVirtualLocator(e)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,s){throw new Error('Assertion failed: calling \"bindDescriptor\" on a virtual descriptor is unsupported')}getResolutionDependencies(e,r){throw new Error('Assertion failed: calling \"getResolutionDependencies\" on a virtual descriptor is unsupported')}async getCandidates(e,r,s){throw new Error('Assertion failed: calling \"getCandidates\" on a virtual descriptor is unsupported')}async getSatisfying(e,r,s,a){throw new Error('Assertion failed: calling \"getSatisfying\" on a virtual descriptor is unsupported')}async resolve(e,r){throw new Error('Assertion failed: calling \"resolve\" on a virtual locator is unsupported')}}});var cI,F8=Ze(()=>{Dt();tm();cI=class{supports(e){return!!e.reference.startsWith(Ei.protocol)}getLocalPath(e,r){return this.getWorkspace(e,r).cwd}async fetch(e,r){let s=this.getWorkspace(e,r).cwd;return{packageFs:new Sn(s),prefixPath:vt.dot,localPath:s}}getWorkspace(e,r){return r.project.getWorkspaceByCwd(e.reference.slice(Ei.protocol.length))}}});function WB(t){return typeof t==\"object\"&&t!==null&&!Array.isArray(t)}function Aue(t){return typeof t>\"u\"?3:WB(t)?0:Array.isArray(t)?1:2}function L8(t,e){return Object.hasOwn(t,e)}function uet(t){return WB(t)&&L8(t,\"onConflict\")&&typeof t.onConflict==\"string\"}function fet(t){if(typeof t>\"u\")return{onConflict:\"default\",value:t};if(!uet(t))return{onConflict:\"default\",value:t};if(L8(t,\"value\"))return t;let{onConflict:e,...r}=t;return{onConflict:e,value:r}}function pue(t,e){let r=WB(t)&&L8(t,e)?t[e]:void 0;return fet(r)}function uI(t,e){return[t,e,hue]}function M8(t){return Array.isArray(t)?t[2]===hue:!1}function N8(t,e){if(WB(t)){let r={};for(let s of Object.keys(t))r[s]=N8(t[s],e);return uI(e,r)}return Array.isArray(t)?uI(e,t.map(r=>N8(r,e))):uI(e,t)}function O8(t,e,r,s,a){let n,c=[],f=a,p=0;for(let E=a-1;E>=s;--E){let[C,S]=t[E],{onConflict:b,value:I}=pue(S,r),T=Aue(I);if(T!==3){if(n??=T,T!==n||b===\"hardReset\"){p=f;break}if(T===2)return uI(C,I);if(c.unshift([C,I]),b===\"reset\"){p=E;break}b===\"extend\"&&E===s&&(s=0),f=E}}if(typeof n>\"u\")return null;let h=c.map(([E])=>E).join(\", \");switch(n){case 1:return uI(h,new Array().concat(...c.map(([E,C])=>C.map(S=>N8(S,E)))));case 0:{let E=Object.assign({},...c.map(([,T])=>T)),C=Object.keys(E),S={},b=t.map(([T,N])=>[T,pue(N,r).value]),I=cet(b,([T,N])=>{let U=Aue(N);return U!==0&&U!==3});if(I!==-1){let T=b.slice(I+1);for(let N of C)S[N]=O8(T,e,N,0,T.length)}else for(let T of C)S[T]=O8(b,e,T,p,b.length);return uI(h,S)}default:throw new Error(\"Assertion failed: Non-extendable value type\")}}function gue(t){return O8(t.map(([e,r])=>[e,{\".\":r}]),[],\".\",0,t.length)}function YB(t){return M8(t)?t[1]:t}function FQ(t){let e=M8(t)?t[1]:t;if(Array.isArray(e))return e.map(r=>FQ(r));if(WB(e)){let r={};for(let[s,a]of Object.entries(e))r[s]=FQ(a);return r}return e}function U8(t){return M8(t)?t[0]:null}var cet,hue,due=Ze(()=>{cet=(t,e,r)=>{let s=[...t];return s.reverse(),s.findIndex(e,r)};hue=Symbol()});var NQ={};Vt(NQ,{getDefaultGlobalFolder:()=>H8,getHomeFolder:()=>fI,isFolderInside:()=>j8});function H8(){if(process.platform===\"win32\"){let t=fe.toPortablePath(process.env.LOCALAPPDATA||fe.join((0,_8.homedir)(),\"AppData\",\"Local\"));return J.resolve(t,\"Yarn/Berry\")}if(process.env.XDG_DATA_HOME){let t=fe.toPortablePath(process.env.XDG_DATA_HOME);return J.resolve(t,\"yarn/berry\")}return J.resolve(fI(),\".yarn/berry\")}function fI(){return fe.toPortablePath((0,_8.homedir)()||\"/usr/local/share\")}function j8(t,e){let r=J.relative(e,t);return r&&!r.startsWith(\"..\")&&!J.isAbsolute(r)}var _8,OQ=Ze(()=>{Dt();_8=Ie(\"os\")});var Eue=_((uMt,yue)=>{\"use strict\";var G8=Ie(\"https\"),q8=Ie(\"http\"),{URL:mue}=Ie(\"url\"),W8=class extends q8.Agent{constructor(e){let{proxy:r,proxyRequestOptions:s,...a}=e;super(a),this.proxy=typeof r==\"string\"?new mue(r):r,this.proxyRequestOptions=s||{}}createConnection(e,r){let s={...this.proxyRequestOptions,method:\"CONNECT\",host:this.proxy.hostname,port:this.proxy.port,path:`${e.host}:${e.port}`,setHost:!1,headers:{...this.proxyRequestOptions.headers,connection:this.keepAlive?\"keep-alive\":\"close\",host:`${e.host}:${e.port}`},agent:!1,timeout:e.timeout||0};if(this.proxy.username||this.proxy.password){let n=Buffer.from(`${decodeURIComponent(this.proxy.username||\"\")}:${decodeURIComponent(this.proxy.password||\"\")}`).toString(\"base64\");s.headers[\"proxy-authorization\"]=`Basic ${n}`}this.proxy.protocol===\"https:\"&&(s.servername=this.proxy.hostname);let a=(this.proxy.protocol===\"http:\"?q8:G8).request(s);a.once(\"connect\",(n,c,f)=>{a.removeAllListeners(),c.removeAllListeners(),n.statusCode===200?r(null,c):(c.destroy(),r(new Error(`Bad response: ${n.statusCode}`),null))}),a.once(\"timeout\",()=>{a.destroy(new Error(\"Proxy timeout\"))}),a.once(\"error\",n=>{a.removeAllListeners(),r(n,null)}),a.end()}},Y8=class extends G8.Agent{constructor(e){let{proxy:r,proxyRequestOptions:s,...a}=e;super(a),this.proxy=typeof r==\"string\"?new mue(r):r,this.proxyRequestOptions=s||{}}createConnection(e,r){let s={...this.proxyRequestOptions,method:\"CONNECT\",host:this.proxy.hostname,port:this.proxy.port,path:`${e.host}:${e.port}`,setHost:!1,headers:{...this.proxyRequestOptions.headers,connection:this.keepAlive?\"keep-alive\":\"close\",host:`${e.host}:${e.port}`},agent:!1,timeout:e.timeout||0};if(this.proxy.username||this.proxy.password){let n=Buffer.from(`${decodeURIComponent(this.proxy.username||\"\")}:${decodeURIComponent(this.proxy.password||\"\")}`).toString(\"base64\");s.headers[\"proxy-authorization\"]=`Basic ${n}`}this.proxy.protocol===\"https:\"&&(s.servername=this.proxy.hostname);let a=(this.proxy.protocol===\"http:\"?q8:G8).request(s);a.once(\"connect\",(n,c,f)=>{if(a.removeAllListeners(),c.removeAllListeners(),n.statusCode===200){let p=super.createConnection({...e,socket:c});r(null,p)}else c.destroy(),r(new Error(`Bad response: ${n.statusCode}`),null)}),a.once(\"timeout\",()=>{a.destroy(new Error(\"Proxy timeout\"))}),a.once(\"error\",n=>{a.removeAllListeners(),r(n,null)}),a.end()}};yue.exports={HttpProxyAgent:W8,HttpsProxyAgent:Y8}});var V8,Iue,Cue,wue=Ze(()=>{V8=ut(Eue(),1),Iue=V8.default.HttpProxyAgent,Cue=V8.default.HttpsProxyAgent});var Np=_((Fp,LQ)=>{\"use strict\";Object.defineProperty(Fp,\"__esModule\",{value:!0});var Bue=[\"Int8Array\",\"Uint8Array\",\"Uint8ClampedArray\",\"Int16Array\",\"Uint16Array\",\"Int32Array\",\"Uint32Array\",\"Float32Array\",\"Float64Array\",\"BigInt64Array\",\"BigUint64Array\"];function pet(t){return Bue.includes(t)}var het=[\"Function\",\"Generator\",\"AsyncGenerator\",\"GeneratorFunction\",\"AsyncGeneratorFunction\",\"AsyncFunction\",\"Observable\",\"Array\",\"Buffer\",\"Blob\",\"Object\",\"RegExp\",\"Date\",\"Error\",\"Map\",\"Set\",\"WeakMap\",\"WeakSet\",\"ArrayBuffer\",\"SharedArrayBuffer\",\"DataView\",\"Promise\",\"URL\",\"FormData\",\"URLSearchParams\",\"HTMLElement\",...Bue];function get(t){return het.includes(t)}var det=[\"null\",\"undefined\",\"string\",\"number\",\"bigint\",\"boolean\",\"symbol\"];function met(t){return det.includes(t)}function AI(t){return e=>typeof e===t}var{toString:vue}=Object.prototype,VB=t=>{let e=vue.call(t).slice(8,-1);if(/HTML\\w+Element/.test(e)&&Pe.domElement(t))return\"HTMLElement\";if(get(e))return e},pi=t=>e=>VB(e)===t;function Pe(t){if(t===null)return\"null\";switch(typeof t){case\"undefined\":return\"undefined\";case\"string\":return\"string\";case\"number\":return\"number\";case\"boolean\":return\"boolean\";case\"function\":return\"Function\";case\"bigint\":return\"bigint\";case\"symbol\":return\"symbol\";default:}if(Pe.observable(t))return\"Observable\";if(Pe.array(t))return\"Array\";if(Pe.buffer(t))return\"Buffer\";let e=VB(t);if(e)return e;if(t instanceof String||t instanceof Boolean||t instanceof Number)throw new TypeError(\"Please don't use object wrappers for primitive types\");return\"Object\"}Pe.undefined=AI(\"undefined\");Pe.string=AI(\"string\");var yet=AI(\"number\");Pe.number=t=>yet(t)&&!Pe.nan(t);Pe.bigint=AI(\"bigint\");Pe.function_=AI(\"function\");Pe.null_=t=>t===null;Pe.class_=t=>Pe.function_(t)&&t.toString().startsWith(\"class \");Pe.boolean=t=>t===!0||t===!1;Pe.symbol=AI(\"symbol\");Pe.numericString=t=>Pe.string(t)&&!Pe.emptyStringOrWhitespace(t)&&!Number.isNaN(Number(t));Pe.array=(t,e)=>Array.isArray(t)?Pe.function_(e)?t.every(e):!0:!1;Pe.buffer=t=>{var e,r,s,a;return(a=(s=(r=(e=t)===null||e===void 0?void 0:e.constructor)===null||r===void 0?void 0:r.isBuffer)===null||s===void 0?void 0:s.call(r,t))!==null&&a!==void 0?a:!1};Pe.blob=t=>pi(\"Blob\")(t);Pe.nullOrUndefined=t=>Pe.null_(t)||Pe.undefined(t);Pe.object=t=>!Pe.null_(t)&&(typeof t==\"object\"||Pe.function_(t));Pe.iterable=t=>{var e;return Pe.function_((e=t)===null||e===void 0?void 0:e[Symbol.iterator])};Pe.asyncIterable=t=>{var e;return Pe.function_((e=t)===null||e===void 0?void 0:e[Symbol.asyncIterator])};Pe.generator=t=>{var e,r;return Pe.iterable(t)&&Pe.function_((e=t)===null||e===void 0?void 0:e.next)&&Pe.function_((r=t)===null||r===void 0?void 0:r.throw)};Pe.asyncGenerator=t=>Pe.asyncIterable(t)&&Pe.function_(t.next)&&Pe.function_(t.throw);Pe.nativePromise=t=>pi(\"Promise\")(t);var Eet=t=>{var e,r;return Pe.function_((e=t)===null||e===void 0?void 0:e.then)&&Pe.function_((r=t)===null||r===void 0?void 0:r.catch)};Pe.promise=t=>Pe.nativePromise(t)||Eet(t);Pe.generatorFunction=pi(\"GeneratorFunction\");Pe.asyncGeneratorFunction=t=>VB(t)===\"AsyncGeneratorFunction\";Pe.asyncFunction=t=>VB(t)===\"AsyncFunction\";Pe.boundFunction=t=>Pe.function_(t)&&!t.hasOwnProperty(\"prototype\");Pe.regExp=pi(\"RegExp\");Pe.date=pi(\"Date\");Pe.error=pi(\"Error\");Pe.map=t=>pi(\"Map\")(t);Pe.set=t=>pi(\"Set\")(t);Pe.weakMap=t=>pi(\"WeakMap\")(t);Pe.weakSet=t=>pi(\"WeakSet\")(t);Pe.int8Array=pi(\"Int8Array\");Pe.uint8Array=pi(\"Uint8Array\");Pe.uint8ClampedArray=pi(\"Uint8ClampedArray\");Pe.int16Array=pi(\"Int16Array\");Pe.uint16Array=pi(\"Uint16Array\");Pe.int32Array=pi(\"Int32Array\");Pe.uint32Array=pi(\"Uint32Array\");Pe.float32Array=pi(\"Float32Array\");Pe.float64Array=pi(\"Float64Array\");Pe.bigInt64Array=pi(\"BigInt64Array\");Pe.bigUint64Array=pi(\"BigUint64Array\");Pe.arrayBuffer=pi(\"ArrayBuffer\");Pe.sharedArrayBuffer=pi(\"SharedArrayBuffer\");Pe.dataView=pi(\"DataView\");Pe.enumCase=(t,e)=>Object.values(e).includes(t);Pe.directInstanceOf=(t,e)=>Object.getPrototypeOf(t)===e.prototype;Pe.urlInstance=t=>pi(\"URL\")(t);Pe.urlString=t=>{if(!Pe.string(t))return!1;try{return new URL(t),!0}catch{return!1}};Pe.truthy=t=>!!t;Pe.falsy=t=>!t;Pe.nan=t=>Number.isNaN(t);Pe.primitive=t=>Pe.null_(t)||met(typeof t);Pe.integer=t=>Number.isInteger(t);Pe.safeInteger=t=>Number.isSafeInteger(t);Pe.plainObject=t=>{if(vue.call(t)!==\"[object Object]\")return!1;let e=Object.getPrototypeOf(t);return e===null||e===Object.getPrototypeOf({})};Pe.typedArray=t=>pet(VB(t));var Iet=t=>Pe.safeInteger(t)&&t>=0;Pe.arrayLike=t=>!Pe.nullOrUndefined(t)&&!Pe.function_(t)&&Iet(t.length);Pe.inRange=(t,e)=>{if(Pe.number(e))return t>=Math.min(0,e)&&t<=Math.max(e,0);if(Pe.array(e)&&e.length===2)return t>=Math.min(...e)&&t<=Math.max(...e);throw new TypeError(`Invalid range: ${JSON.stringify(e)}`)};var Cet=1,wet=[\"innerHTML\",\"ownerDocument\",\"style\",\"attributes\",\"nodeValue\"];Pe.domElement=t=>Pe.object(t)&&t.nodeType===Cet&&Pe.string(t.nodeName)&&!Pe.plainObject(t)&&wet.every(e=>e in t);Pe.observable=t=>{var e,r,s,a;return t?t===((r=(e=t)[Symbol.observable])===null||r===void 0?void 0:r.call(e))||t===((a=(s=t)[\"@@observable\"])===null||a===void 0?void 0:a.call(s)):!1};Pe.nodeStream=t=>Pe.object(t)&&Pe.function_(t.pipe)&&!Pe.observable(t);Pe.infinite=t=>t===1/0||t===-1/0;var Sue=t=>e=>Pe.integer(e)&&Math.abs(e%2)===t;Pe.evenInteger=Sue(0);Pe.oddInteger=Sue(1);Pe.emptyArray=t=>Pe.array(t)&&t.length===0;Pe.nonEmptyArray=t=>Pe.array(t)&&t.length>0;Pe.emptyString=t=>Pe.string(t)&&t.length===0;var Bet=t=>Pe.string(t)&&!/\\S/.test(t);Pe.emptyStringOrWhitespace=t=>Pe.emptyString(t)||Bet(t);Pe.nonEmptyString=t=>Pe.string(t)&&t.length>0;Pe.nonEmptyStringAndNotWhitespace=t=>Pe.string(t)&&!Pe.emptyStringOrWhitespace(t);Pe.emptyObject=t=>Pe.object(t)&&!Pe.map(t)&&!Pe.set(t)&&Object.keys(t).length===0;Pe.nonEmptyObject=t=>Pe.object(t)&&!Pe.map(t)&&!Pe.set(t)&&Object.keys(t).length>0;Pe.emptySet=t=>Pe.set(t)&&t.size===0;Pe.nonEmptySet=t=>Pe.set(t)&&t.size>0;Pe.emptyMap=t=>Pe.map(t)&&t.size===0;Pe.nonEmptyMap=t=>Pe.map(t)&&t.size>0;Pe.propertyKey=t=>Pe.any([Pe.string,Pe.number,Pe.symbol],t);Pe.formData=t=>pi(\"FormData\")(t);Pe.urlSearchParams=t=>pi(\"URLSearchParams\")(t);var Due=(t,e,r)=>{if(!Pe.function_(e))throw new TypeError(`Invalid predicate: ${JSON.stringify(e)}`);if(r.length===0)throw new TypeError(\"Invalid number of values\");return t.call(r,e)};Pe.any=(t,...e)=>(Pe.array(t)?t:[t]).some(s=>Due(Array.prototype.some,s,e));Pe.all=(t,...e)=>Due(Array.prototype.every,t,e);var _t=(t,e,r,s={})=>{if(!t){let{multipleValues:a}=s,n=a?`received values of types ${[...new Set(r.map(c=>`\\`${Pe(c)}\\``))].join(\", \")}`:`received value of type \\`${Pe(r)}\\``;throw new TypeError(`Expected value which is \\`${e}\\`, ${n}.`)}};Fp.assert={undefined:t=>_t(Pe.undefined(t),\"undefined\",t),string:t=>_t(Pe.string(t),\"string\",t),number:t=>_t(Pe.number(t),\"number\",t),bigint:t=>_t(Pe.bigint(t),\"bigint\",t),function_:t=>_t(Pe.function_(t),\"Function\",t),null_:t=>_t(Pe.null_(t),\"null\",t),class_:t=>_t(Pe.class_(t),\"Class\",t),boolean:t=>_t(Pe.boolean(t),\"boolean\",t),symbol:t=>_t(Pe.symbol(t),\"symbol\",t),numericString:t=>_t(Pe.numericString(t),\"string with a number\",t),array:(t,e)=>{_t(Pe.array(t),\"Array\",t),e&&t.forEach(e)},buffer:t=>_t(Pe.buffer(t),\"Buffer\",t),blob:t=>_t(Pe.blob(t),\"Blob\",t),nullOrUndefined:t=>_t(Pe.nullOrUndefined(t),\"null or undefined\",t),object:t=>_t(Pe.object(t),\"Object\",t),iterable:t=>_t(Pe.iterable(t),\"Iterable\",t),asyncIterable:t=>_t(Pe.asyncIterable(t),\"AsyncIterable\",t),generator:t=>_t(Pe.generator(t),\"Generator\",t),asyncGenerator:t=>_t(Pe.asyncGenerator(t),\"AsyncGenerator\",t),nativePromise:t=>_t(Pe.nativePromise(t),\"native Promise\",t),promise:t=>_t(Pe.promise(t),\"Promise\",t),generatorFunction:t=>_t(Pe.generatorFunction(t),\"GeneratorFunction\",t),asyncGeneratorFunction:t=>_t(Pe.asyncGeneratorFunction(t),\"AsyncGeneratorFunction\",t),asyncFunction:t=>_t(Pe.asyncFunction(t),\"AsyncFunction\",t),boundFunction:t=>_t(Pe.boundFunction(t),\"Function\",t),regExp:t=>_t(Pe.regExp(t),\"RegExp\",t),date:t=>_t(Pe.date(t),\"Date\",t),error:t=>_t(Pe.error(t),\"Error\",t),map:t=>_t(Pe.map(t),\"Map\",t),set:t=>_t(Pe.set(t),\"Set\",t),weakMap:t=>_t(Pe.weakMap(t),\"WeakMap\",t),weakSet:t=>_t(Pe.weakSet(t),\"WeakSet\",t),int8Array:t=>_t(Pe.int8Array(t),\"Int8Array\",t),uint8Array:t=>_t(Pe.uint8Array(t),\"Uint8Array\",t),uint8ClampedArray:t=>_t(Pe.uint8ClampedArray(t),\"Uint8ClampedArray\",t),int16Array:t=>_t(Pe.int16Array(t),\"Int16Array\",t),uint16Array:t=>_t(Pe.uint16Array(t),\"Uint16Array\",t),int32Array:t=>_t(Pe.int32Array(t),\"Int32Array\",t),uint32Array:t=>_t(Pe.uint32Array(t),\"Uint32Array\",t),float32Array:t=>_t(Pe.float32Array(t),\"Float32Array\",t),float64Array:t=>_t(Pe.float64Array(t),\"Float64Array\",t),bigInt64Array:t=>_t(Pe.bigInt64Array(t),\"BigInt64Array\",t),bigUint64Array:t=>_t(Pe.bigUint64Array(t),\"BigUint64Array\",t),arrayBuffer:t=>_t(Pe.arrayBuffer(t),\"ArrayBuffer\",t),sharedArrayBuffer:t=>_t(Pe.sharedArrayBuffer(t),\"SharedArrayBuffer\",t),dataView:t=>_t(Pe.dataView(t),\"DataView\",t),enumCase:(t,e)=>_t(Pe.enumCase(t,e),\"EnumCase\",t),urlInstance:t=>_t(Pe.urlInstance(t),\"URL\",t),urlString:t=>_t(Pe.urlString(t),\"string with a URL\",t),truthy:t=>_t(Pe.truthy(t),\"truthy\",t),falsy:t=>_t(Pe.falsy(t),\"falsy\",t),nan:t=>_t(Pe.nan(t),\"NaN\",t),primitive:t=>_t(Pe.primitive(t),\"primitive\",t),integer:t=>_t(Pe.integer(t),\"integer\",t),safeInteger:t=>_t(Pe.safeInteger(t),\"integer\",t),plainObject:t=>_t(Pe.plainObject(t),\"plain object\",t),typedArray:t=>_t(Pe.typedArray(t),\"TypedArray\",t),arrayLike:t=>_t(Pe.arrayLike(t),\"array-like\",t),domElement:t=>_t(Pe.domElement(t),\"HTMLElement\",t),observable:t=>_t(Pe.observable(t),\"Observable\",t),nodeStream:t=>_t(Pe.nodeStream(t),\"Node.js Stream\",t),infinite:t=>_t(Pe.infinite(t),\"infinite number\",t),emptyArray:t=>_t(Pe.emptyArray(t),\"empty array\",t),nonEmptyArray:t=>_t(Pe.nonEmptyArray(t),\"non-empty array\",t),emptyString:t=>_t(Pe.emptyString(t),\"empty string\",t),emptyStringOrWhitespace:t=>_t(Pe.emptyStringOrWhitespace(t),\"empty string or whitespace\",t),nonEmptyString:t=>_t(Pe.nonEmptyString(t),\"non-empty string\",t),nonEmptyStringAndNotWhitespace:t=>_t(Pe.nonEmptyStringAndNotWhitespace(t),\"non-empty string and not whitespace\",t),emptyObject:t=>_t(Pe.emptyObject(t),\"empty object\",t),nonEmptyObject:t=>_t(Pe.nonEmptyObject(t),\"non-empty object\",t),emptySet:t=>_t(Pe.emptySet(t),\"empty set\",t),nonEmptySet:t=>_t(Pe.nonEmptySet(t),\"non-empty set\",t),emptyMap:t=>_t(Pe.emptyMap(t),\"empty map\",t),nonEmptyMap:t=>_t(Pe.nonEmptyMap(t),\"non-empty map\",t),propertyKey:t=>_t(Pe.propertyKey(t),\"PropertyKey\",t),formData:t=>_t(Pe.formData(t),\"FormData\",t),urlSearchParams:t=>_t(Pe.urlSearchParams(t),\"URLSearchParams\",t),evenInteger:t=>_t(Pe.evenInteger(t),\"even integer\",t),oddInteger:t=>_t(Pe.oddInteger(t),\"odd integer\",t),directInstanceOf:(t,e)=>_t(Pe.directInstanceOf(t,e),\"T\",t),inRange:(t,e)=>_t(Pe.inRange(t,e),\"in range\",t),any:(t,...e)=>_t(Pe.any(t,...e),\"predicate returns truthy for any value\",e,{multipleValues:!0}),all:(t,...e)=>_t(Pe.all(t,...e),\"predicate returns truthy for all values\",e,{multipleValues:!0})};Object.defineProperties(Pe,{class:{value:Pe.class_},function:{value:Pe.function_},null:{value:Pe.null_}});Object.defineProperties(Fp.assert,{class:{value:Fp.assert.class_},function:{value:Fp.assert.function_},null:{value:Fp.assert.null_}});Fp.default=Pe;LQ.exports=Pe;LQ.exports.default=Pe;LQ.exports.assert=Fp.assert});var Pue=_((AMt,J8)=>{\"use strict\";var MQ=class extends Error{constructor(e){super(e||\"Promise was canceled\"),this.name=\"CancelError\"}get isCanceled(){return!0}},UQ=class t{static fn(e){return(...r)=>new t((s,a,n)=>{r.push(n),e(...r).then(s,a)})}constructor(e){this._cancelHandlers=[],this._isPending=!0,this._isCanceled=!1,this._rejectOnCancel=!0,this._promise=new Promise((r,s)=>{this._reject=s;let a=f=>{this._isPending=!1,r(f)},n=f=>{this._isPending=!1,s(f)},c=f=>{if(!this._isPending)throw new Error(\"The `onCancel` handler was attached after the promise settled.\");this._cancelHandlers.push(f)};return Object.defineProperties(c,{shouldReject:{get:()=>this._rejectOnCancel,set:f=>{this._rejectOnCancel=f}}}),e(a,n,c)})}then(e,r){return this._promise.then(e,r)}catch(e){return this._promise.catch(e)}finally(e){return this._promise.finally(e)}cancel(e){if(!(!this._isPending||this._isCanceled)){if(this._cancelHandlers.length>0)try{for(let r of this._cancelHandlers)r()}catch(r){this._reject(r)}this._isCanceled=!0,this._rejectOnCancel&&this._reject(new MQ(e))}}get isCanceled(){return this._isCanceled}};Object.setPrototypeOf(UQ.prototype,Promise.prototype);J8.exports=UQ;J8.exports.CancelError=MQ});var bue=_((z8,Z8)=>{\"use strict\";Object.defineProperty(z8,\"__esModule\",{value:!0});function vet(t){return t.encrypted}var K8=(t,e)=>{let r;typeof e==\"function\"?r={connect:e}:r=e;let s=typeof r.connect==\"function\",a=typeof r.secureConnect==\"function\",n=typeof r.close==\"function\",c=()=>{s&&r.connect(),vet(t)&&a&&(t.authorized?r.secureConnect():t.authorizationError||t.once(\"secureConnect\",r.secureConnect)),n&&t.once(\"close\",r.close)};t.writable&&!t.connecting?c():t.connecting?t.once(\"connect\",c):t.destroyed&&n&&r.close(t._hadError)};z8.default=K8;Z8.exports=K8;Z8.exports.default=K8});var xue=_(($8,eH)=>{\"use strict\";Object.defineProperty($8,\"__esModule\",{value:!0});var Det=bue(),Pet=Number(process.versions.node.split(\".\")[0]),X8=t=>{let e={start:Date.now(),socket:void 0,lookup:void 0,connect:void 0,secureConnect:void 0,upload:void 0,response:void 0,end:void 0,error:void 0,abort:void 0,phases:{wait:void 0,dns:void 0,tcp:void 0,tls:void 0,request:void 0,firstByte:void 0,download:void 0,total:void 0}};t.timings=e;let r=c=>{let f=c.emit.bind(c);c.emit=(p,...h)=>(p===\"error\"&&(e.error=Date.now(),e.phases.total=e.error-e.start,c.emit=f),f(p,...h))};r(t),t.prependOnceListener(\"abort\",()=>{e.abort=Date.now(),(!e.response||Pet>=13)&&(e.phases.total=Date.now()-e.start)});let s=c=>{e.socket=Date.now(),e.phases.wait=e.socket-e.start;let f=()=>{e.lookup=Date.now(),e.phases.dns=e.lookup-e.socket};c.prependOnceListener(\"lookup\",f),Det.default(c,{connect:()=>{e.connect=Date.now(),e.lookup===void 0&&(c.removeListener(\"lookup\",f),e.lookup=e.connect,e.phases.dns=e.lookup-e.socket),e.phases.tcp=e.connect-e.lookup},secureConnect:()=>{e.secureConnect=Date.now(),e.phases.tls=e.secureConnect-e.connect}})};t.socket?s(t.socket):t.prependOnceListener(\"socket\",s);let a=()=>{var c;e.upload=Date.now(),e.phases.request=e.upload-(c=e.secureConnect,c??e.connect)};return(typeof t.writableFinished==\"boolean\"?t.writableFinished:t.finished&&t.outputSize===0&&(!t.socket||t.socket.writableLength===0))?a():t.prependOnceListener(\"finish\",a),t.prependOnceListener(\"response\",c=>{e.response=Date.now(),e.phases.firstByte=e.response-e.upload,c.timings=e,r(c),c.prependOnceListener(\"end\",()=>{e.end=Date.now(),e.phases.download=e.end-e.response,e.phases.total=e.end-e.start})}),e};$8.default=X8;eH.exports=X8;eH.exports.default=X8});var Oue=_((pMt,nH)=>{\"use strict\";var{V4MAPPED:bet,ADDRCONFIG:xet,ALL:Nue,promises:{Resolver:kue},lookup:ket}=Ie(\"dns\"),{promisify:tH}=Ie(\"util\"),Qet=Ie(\"os\"),pI=Symbol(\"cacheableLookupCreateConnection\"),rH=Symbol(\"cacheableLookupInstance\"),Que=Symbol(\"expires\"),Ret=typeof Nue==\"number\",Rue=t=>{if(!(t&&typeof t.createConnection==\"function\"))throw new Error(\"Expected an Agent instance as the first argument\")},Tet=t=>{for(let e of t)e.family!==6&&(e.address=`::ffff:${e.address}`,e.family=6)},Tue=()=>{let t=!1,e=!1;for(let r of Object.values(Qet.networkInterfaces()))for(let s of r)if(!s.internal&&(s.family===\"IPv6\"?e=!0:t=!0,t&&e))return{has4:t,has6:e};return{has4:t,has6:e}},Fet=t=>Symbol.iterator in t,Fue={ttl:!0},Net={all:!0},_Q=class{constructor({cache:e=new Map,maxTtl:r=1/0,fallbackDuration:s=3600,errorTtl:a=.15,resolver:n=new kue,lookup:c=ket}={}){if(this.maxTtl=r,this.errorTtl=a,this._cache=e,this._resolver=n,this._dnsLookup=tH(c),this._resolver instanceof kue?(this._resolve4=this._resolver.resolve4.bind(this._resolver),this._resolve6=this._resolver.resolve6.bind(this._resolver)):(this._resolve4=tH(this._resolver.resolve4.bind(this._resolver)),this._resolve6=tH(this._resolver.resolve6.bind(this._resolver))),this._iface=Tue(),this._pending={},this._nextRemovalTime=!1,this._hostnamesToFallback=new Set,s<1)this._fallback=!1;else{this._fallback=!0;let f=setInterval(()=>{this._hostnamesToFallback.clear()},s*1e3);f.unref&&f.unref()}this.lookup=this.lookup.bind(this),this.lookupAsync=this.lookupAsync.bind(this)}set servers(e){this.clear(),this._resolver.setServers(e)}get servers(){return this._resolver.getServers()}lookup(e,r,s){if(typeof r==\"function\"?(s=r,r={}):typeof r==\"number\"&&(r={family:r}),!s)throw new Error(\"Callback must be a function.\");this.lookupAsync(e,r).then(a=>{r.all?s(null,a):s(null,a.address,a.family,a.expires,a.ttl)},s)}async lookupAsync(e,r={}){typeof r==\"number\"&&(r={family:r});let s=await this.query(e);if(r.family===6){let a=s.filter(n=>n.family===6);r.hints&bet&&(Ret&&r.hints&Nue||a.length===0)?Tet(s):s=a}else r.family===4&&(s=s.filter(a=>a.family===4));if(r.hints&xet){let{_iface:a}=this;s=s.filter(n=>n.family===6?a.has6:a.has4)}if(s.length===0){let a=new Error(`cacheableLookup ENOTFOUND ${e}`);throw a.code=\"ENOTFOUND\",a.hostname=e,a}return r.all?s:s[0]}async query(e){let r=await this._cache.get(e);if(!r){let s=this._pending[e];if(s)r=await s;else{let a=this.queryAndCache(e);this._pending[e]=a,r=await a}}return r=r.map(s=>({...s})),r}async _resolve(e){let r=async h=>{try{return await h}catch(E){if(E.code===\"ENODATA\"||E.code===\"ENOTFOUND\")return[];throw E}},[s,a]=await Promise.all([this._resolve4(e,Fue),this._resolve6(e,Fue)].map(h=>r(h))),n=0,c=0,f=0,p=Date.now();for(let h of s)h.family=4,h.expires=p+h.ttl*1e3,n=Math.max(n,h.ttl);for(let h of a)h.family=6,h.expires=p+h.ttl*1e3,c=Math.max(c,h.ttl);return s.length>0?a.length>0?f=Math.min(n,c):f=n:f=c,{entries:[...s,...a],cacheTtl:f}}async _lookup(e){try{return{entries:await this._dnsLookup(e,{all:!0}),cacheTtl:0}}catch{return{entries:[],cacheTtl:0}}}async _set(e,r,s){if(this.maxTtl>0&&s>0){s=Math.min(s,this.maxTtl)*1e3,r[Que]=Date.now()+s;try{await this._cache.set(e,r,s)}catch(a){this.lookupAsync=async()=>{let n=new Error(\"Cache Error. Please recreate the CacheableLookup instance.\");throw n.cause=a,n}}Fet(this._cache)&&this._tick(s)}}async queryAndCache(e){if(this._hostnamesToFallback.has(e))return this._dnsLookup(e,Net);try{let r=await this._resolve(e);r.entries.length===0&&this._fallback&&(r=await this._lookup(e),r.entries.length!==0&&this._hostnamesToFallback.add(e));let s=r.entries.length===0?this.errorTtl:r.cacheTtl;return await this._set(e,r.entries,s),delete this._pending[e],r.entries}catch(r){throw delete this._pending[e],r}}_tick(e){let r=this._nextRemovalTime;(!r||e<r)&&(clearTimeout(this._removalTimeout),this._nextRemovalTime=e,this._removalTimeout=setTimeout(()=>{this._nextRemovalTime=!1;let s=1/0,a=Date.now();for(let[n,c]of this._cache){let f=c[Que];a>=f?this._cache.delete(n):f<s&&(s=f)}s!==1/0&&this._tick(s-a)},e),this._removalTimeout.unref&&this._removalTimeout.unref())}install(e){if(Rue(e),pI in e)throw new Error(\"CacheableLookup has been already installed\");e[pI]=e.createConnection,e[rH]=this,e.createConnection=(r,s)=>(\"lookup\"in r||(r.lookup=this.lookup),e[pI](r,s))}uninstall(e){if(Rue(e),e[pI]){if(e[rH]!==this)throw new Error(\"The agent is not owned by this CacheableLookup instance\");e.createConnection=e[pI],delete e[pI],delete e[rH]}}updateInterfaceInfo(){let{_iface:e}=this;this._iface=Tue(),(e.has4&&!this._iface.has4||e.has6&&!this._iface.has6)&&this._cache.clear()}clear(e){if(e){this._cache.delete(e);return}this._cache.clear()}};nH.exports=_Q;nH.exports.default=_Q});var Uue=_((hMt,iH)=>{\"use strict\";var Oet=typeof URL>\"u\"?Ie(\"url\").URL:URL,Let=\"text/plain\",Met=\"us-ascii\",Lue=(t,e)=>e.some(r=>r instanceof RegExp?r.test(t):r===t),Uet=(t,{stripHash:e})=>{let r=t.match(/^data:([^,]*?),([^#]*?)(?:#(.*))?$/);if(!r)throw new Error(`Invalid URL: ${t}`);let s=r[1].split(\";\"),a=r[2],n=e?\"\":r[3],c=!1;s[s.length-1]===\"base64\"&&(s.pop(),c=!0);let f=(s.shift()||\"\").toLowerCase(),h=[...s.map(E=>{let[C,S=\"\"]=E.split(\"=\").map(b=>b.trim());return C===\"charset\"&&(S=S.toLowerCase(),S===Met)?\"\":`${C}${S?`=${S}`:\"\"}`}).filter(Boolean)];return c&&h.push(\"base64\"),(h.length!==0||f&&f!==Let)&&h.unshift(f),`data:${h.join(\";\")},${c?a.trim():a}${n?`#${n}`:\"\"}`},Mue=(t,e)=>{if(e={defaultProtocol:\"http:\",normalizeProtocol:!0,forceHttp:!1,forceHttps:!1,stripAuthentication:!0,stripHash:!1,stripWWW:!0,removeQueryParameters:[/^utm_\\w+/i],removeTrailingSlash:!0,removeDirectoryIndex:!1,sortQueryParameters:!0,...e},Reflect.has(e,\"normalizeHttps\"))throw new Error(\"options.normalizeHttps is renamed to options.forceHttp\");if(Reflect.has(e,\"normalizeHttp\"))throw new Error(\"options.normalizeHttp is renamed to options.forceHttps\");if(Reflect.has(e,\"stripFragment\"))throw new Error(\"options.stripFragment is renamed to options.stripHash\");if(t=t.trim(),/^data:/i.test(t))return Uet(t,e);let r=t.startsWith(\"//\");!r&&/^\\.*\\//.test(t)||(t=t.replace(/^(?!(?:\\w+:)?\\/\\/)|^\\/\\//,e.defaultProtocol));let a=new Oet(t);if(e.forceHttp&&e.forceHttps)throw new Error(\"The `forceHttp` and `forceHttps` options cannot be used together\");if(e.forceHttp&&a.protocol===\"https:\"&&(a.protocol=\"http:\"),e.forceHttps&&a.protocol===\"http:\"&&(a.protocol=\"https:\"),e.stripAuthentication&&(a.username=\"\",a.password=\"\"),e.stripHash&&(a.hash=\"\"),a.pathname&&(a.pathname=a.pathname.replace(/((?!:).|^)\\/{2,}/g,(n,c)=>/^(?!\\/)/g.test(c)?`${c}/`:\"/\")),a.pathname&&(a.pathname=decodeURI(a.pathname)),e.removeDirectoryIndex===!0&&(e.removeDirectoryIndex=[/^index\\.[a-z]+$/]),Array.isArray(e.removeDirectoryIndex)&&e.removeDirectoryIndex.length>0){let n=a.pathname.split(\"/\"),c=n[n.length-1];Lue(c,e.removeDirectoryIndex)&&(n=n.slice(0,n.length-1),a.pathname=n.slice(1).join(\"/\")+\"/\")}if(a.hostname&&(a.hostname=a.hostname.replace(/\\.$/,\"\"),e.stripWWW&&/^www\\.([a-z\\-\\d]{2,63})\\.([a-z.]{2,5})$/.test(a.hostname)&&(a.hostname=a.hostname.replace(/^www\\./,\"\"))),Array.isArray(e.removeQueryParameters))for(let n of[...a.searchParams.keys()])Lue(n,e.removeQueryParameters)&&a.searchParams.delete(n);return e.sortQueryParameters&&a.searchParams.sort(),e.removeTrailingSlash&&(a.pathname=a.pathname.replace(/\\/$/,\"\")),t=a.toString(),(e.removeTrailingSlash||a.pathname===\"/\")&&a.hash===\"\"&&(t=t.replace(/\\/$/,\"\")),r&&!e.normalizeProtocol&&(t=t.replace(/^http:\\/\\//,\"//\")),e.stripProtocol&&(t=t.replace(/^(?:https?:)?\\/\\//,\"\")),t};iH.exports=Mue;iH.exports.default=Mue});var jue=_((gMt,Hue)=>{Hue.exports=_ue;function _ue(t,e){if(t&&e)return _ue(t)(e);if(typeof t!=\"function\")throw new TypeError(\"need wrapper function\");return Object.keys(t).forEach(function(s){r[s]=t[s]}),r;function r(){for(var s=new Array(arguments.length),a=0;a<s.length;a++)s[a]=arguments[a];var n=t.apply(this,s),c=s[s.length-1];return typeof n==\"function\"&&n!==c&&Object.keys(c).forEach(function(f){n[f]=c[f]}),n}}});var oH=_((dMt,sH)=>{var Gue=jue();sH.exports=Gue(HQ);sH.exports.strict=Gue(que);HQ.proto=HQ(function(){Object.defineProperty(Function.prototype,\"once\",{value:function(){return HQ(this)},configurable:!0}),Object.defineProperty(Function.prototype,\"onceStrict\",{value:function(){return que(this)},configurable:!0})});function HQ(t){var e=function(){return e.called?e.value:(e.called=!0,e.value=t.apply(this,arguments))};return e.called=!1,e}function que(t){var e=function(){if(e.called)throw new Error(e.onceError);return e.called=!0,e.value=t.apply(this,arguments)},r=t.name||\"Function wrapped with `once`\";return e.onceError=r+\" shouldn't be called more than once\",e.called=!1,e}});var aH=_((mMt,Yue)=>{var _et=oH(),Het=function(){},jet=function(t){return t.setHeader&&typeof t.abort==\"function\"},Get=function(t){return t.stdio&&Array.isArray(t.stdio)&&t.stdio.length===3},Wue=function(t,e,r){if(typeof e==\"function\")return Wue(t,null,e);e||(e={}),r=_et(r||Het);var s=t._writableState,a=t._readableState,n=e.readable||e.readable!==!1&&t.readable,c=e.writable||e.writable!==!1&&t.writable,f=function(){t.writable||p()},p=function(){c=!1,n||r.call(t)},h=function(){n=!1,c||r.call(t)},E=function(I){r.call(t,I?new Error(\"exited with error code: \"+I):null)},C=function(I){r.call(t,I)},S=function(){if(n&&!(a&&a.ended))return r.call(t,new Error(\"premature close\"));if(c&&!(s&&s.ended))return r.call(t,new Error(\"premature close\"))},b=function(){t.req.on(\"finish\",p)};return jet(t)?(t.on(\"complete\",p),t.on(\"abort\",S),t.req?b():t.on(\"request\",b)):c&&!s&&(t.on(\"end\",f),t.on(\"close\",f)),Get(t)&&t.on(\"exit\",E),t.on(\"end\",h),t.on(\"finish\",p),e.error!==!1&&t.on(\"error\",C),t.on(\"close\",S),function(){t.removeListener(\"complete\",p),t.removeListener(\"abort\",S),t.removeListener(\"request\",b),t.req&&t.req.removeListener(\"finish\",p),t.removeListener(\"end\",f),t.removeListener(\"close\",f),t.removeListener(\"finish\",p),t.removeListener(\"exit\",E),t.removeListener(\"end\",h),t.removeListener(\"error\",C),t.removeListener(\"close\",S)}};Yue.exports=Wue});var Kue=_((yMt,Jue)=>{var qet=oH(),Wet=aH(),lH=Ie(\"fs\"),JB=function(){},Yet=/^v?\\.0/.test(process.version),jQ=function(t){return typeof t==\"function\"},Vet=function(t){return!Yet||!lH?!1:(t instanceof(lH.ReadStream||JB)||t instanceof(lH.WriteStream||JB))&&jQ(t.close)},Jet=function(t){return t.setHeader&&jQ(t.abort)},Ket=function(t,e,r,s){s=qet(s);var a=!1;t.on(\"close\",function(){a=!0}),Wet(t,{readable:e,writable:r},function(c){if(c)return s(c);a=!0,s()});var n=!1;return function(c){if(!a&&!n){if(n=!0,Vet(t))return t.close(JB);if(Jet(t))return t.abort();if(jQ(t.destroy))return t.destroy();s(c||new Error(\"stream was destroyed\"))}}},Vue=function(t){t()},zet=function(t,e){return t.pipe(e)},Zet=function(){var t=Array.prototype.slice.call(arguments),e=jQ(t[t.length-1]||JB)&&t.pop()||JB;if(Array.isArray(t[0])&&(t=t[0]),t.length<2)throw new Error(\"pump requires two streams per minimum\");var r,s=t.map(function(a,n){var c=n<t.length-1,f=n>0;return Ket(a,c,f,function(p){r||(r=p),p&&s.forEach(Vue),!c&&(s.forEach(Vue),e(r))})});return t.reduce(zet)};Jue.exports=Zet});var Zue=_((EMt,zue)=>{\"use strict\";var{PassThrough:Xet}=Ie(\"stream\");zue.exports=t=>{t={...t};let{array:e}=t,{encoding:r}=t,s=r===\"buffer\",a=!1;e?a=!(r||s):r=r||\"utf8\",s&&(r=null);let n=new Xet({objectMode:a});r&&n.setEncoding(r);let c=0,f=[];return n.on(\"data\",p=>{f.push(p),a?c=f.length:c+=p.length}),n.getBufferedValue=()=>e?f:s?Buffer.concat(f,c):f.join(\"\"),n.getBufferedLength=()=>c,n}});var Xue=_((IMt,hI)=>{\"use strict\";var $et=Kue(),ett=Zue(),GQ=class extends Error{constructor(){super(\"maxBuffer exceeded\"),this.name=\"MaxBufferError\"}};async function qQ(t,e){if(!t)return Promise.reject(new Error(\"Expected a stream\"));e={maxBuffer:1/0,...e};let{maxBuffer:r}=e,s;return await new Promise((a,n)=>{let c=f=>{f&&(f.bufferedData=s.getBufferedValue()),n(f)};s=$et(t,ett(e),f=>{if(f){c(f);return}a()}),s.on(\"data\",()=>{s.getBufferedLength()>r&&c(new GQ)})}),s.getBufferedValue()}hI.exports=qQ;hI.exports.default=qQ;hI.exports.buffer=(t,e)=>qQ(t,{...e,encoding:\"buffer\"});hI.exports.array=(t,e)=>qQ(t,{...e,array:!0});hI.exports.MaxBufferError=GQ});var efe=_((wMt,$ue)=>{\"use strict\";var ttt=new Set([200,203,204,206,300,301,308,404,405,410,414,501]),rtt=new Set([200,203,204,300,301,302,303,307,308,404,405,410,414,501]),ntt=new Set([500,502,503,504]),itt={date:!0,connection:!0,\"keep-alive\":!0,\"proxy-authenticate\":!0,\"proxy-authorization\":!0,te:!0,trailer:!0,\"transfer-encoding\":!0,upgrade:!0},stt={\"content-length\":!0,\"content-encoding\":!0,\"transfer-encoding\":!0,\"content-range\":!0};function nm(t){let e=parseInt(t,10);return isFinite(e)?e:0}function ott(t){return t?ntt.has(t.status):!0}function cH(t){let e={};if(!t)return e;let r=t.trim().split(/,/);for(let s of r){let[a,n]=s.split(/=/,2);e[a.trim()]=n===void 0?!0:n.trim().replace(/^\"|\"$/g,\"\")}return e}function att(t){let e=[];for(let r in t){let s=t[r];e.push(s===!0?r:r+\"=\"+s)}if(e.length)return e.join(\", \")}$ue.exports=class{constructor(e,r,{shared:s,cacheHeuristic:a,immutableMinTimeToLive:n,ignoreCargoCult:c,_fromObject:f}={}){if(f){this._fromObject(f);return}if(!r||!r.headers)throw Error(\"Response headers missing\");this._assertRequestHasHeaders(e),this._responseTime=this.now(),this._isShared=s!==!1,this._cacheHeuristic=a!==void 0?a:.1,this._immutableMinTtl=n!==void 0?n:24*3600*1e3,this._status=\"status\"in r?r.status:200,this._resHeaders=r.headers,this._rescc=cH(r.headers[\"cache-control\"]),this._method=\"method\"in e?e.method:\"GET\",this._url=e.url,this._host=e.headers.host,this._noAuthorization=!e.headers.authorization,this._reqHeaders=r.headers.vary?e.headers:null,this._reqcc=cH(e.headers[\"cache-control\"]),c&&\"pre-check\"in this._rescc&&\"post-check\"in this._rescc&&(delete this._rescc[\"pre-check\"],delete this._rescc[\"post-check\"],delete this._rescc[\"no-cache\"],delete this._rescc[\"no-store\"],delete this._rescc[\"must-revalidate\"],this._resHeaders=Object.assign({},this._resHeaders,{\"cache-control\":att(this._rescc)}),delete this._resHeaders.expires,delete this._resHeaders.pragma),r.headers[\"cache-control\"]==null&&/no-cache/.test(r.headers.pragma)&&(this._rescc[\"no-cache\"]=!0)}now(){return Date.now()}storable(){return!!(!this._reqcc[\"no-store\"]&&(this._method===\"GET\"||this._method===\"HEAD\"||this._method===\"POST\"&&this._hasExplicitExpiration())&&rtt.has(this._status)&&!this._rescc[\"no-store\"]&&(!this._isShared||!this._rescc.private)&&(!this._isShared||this._noAuthorization||this._allowsStoringAuthenticated())&&(this._resHeaders.expires||this._rescc[\"max-age\"]||this._isShared&&this._rescc[\"s-maxage\"]||this._rescc.public||ttt.has(this._status)))}_hasExplicitExpiration(){return this._isShared&&this._rescc[\"s-maxage\"]||this._rescc[\"max-age\"]||this._resHeaders.expires}_assertRequestHasHeaders(e){if(!e||!e.headers)throw Error(\"Request headers missing\")}satisfiesWithoutRevalidation(e){this._assertRequestHasHeaders(e);let r=cH(e.headers[\"cache-control\"]);return r[\"no-cache\"]||/no-cache/.test(e.headers.pragma)||r[\"max-age\"]&&this.age()>r[\"max-age\"]||r[\"min-fresh\"]&&this.timeToLive()<1e3*r[\"min-fresh\"]||this.stale()&&!(r[\"max-stale\"]&&!this._rescc[\"must-revalidate\"]&&(r[\"max-stale\"]===!0||r[\"max-stale\"]>this.age()-this.maxAge()))?!1:this._requestMatches(e,!1)}_requestMatches(e,r){return(!this._url||this._url===e.url)&&this._host===e.headers.host&&(!e.method||this._method===e.method||r&&e.method===\"HEAD\")&&this._varyMatches(e)}_allowsStoringAuthenticated(){return this._rescc[\"must-revalidate\"]||this._rescc.public||this._rescc[\"s-maxage\"]}_varyMatches(e){if(!this._resHeaders.vary)return!0;if(this._resHeaders.vary===\"*\")return!1;let r=this._resHeaders.vary.trim().toLowerCase().split(/\\s*,\\s*/);for(let s of r)if(e.headers[s]!==this._reqHeaders[s])return!1;return!0}_copyWithoutHopByHopHeaders(e){let r={};for(let s in e)itt[s]||(r[s]=e[s]);if(e.connection){let s=e.connection.trim().split(/\\s*,\\s*/);for(let a of s)delete r[a]}if(r.warning){let s=r.warning.split(/,/).filter(a=>!/^\\s*1[0-9][0-9]/.test(a));s.length?r.warning=s.join(\",\").trim():delete r.warning}return r}responseHeaders(){let e=this._copyWithoutHopByHopHeaders(this._resHeaders),r=this.age();return r>3600*24&&!this._hasExplicitExpiration()&&this.maxAge()>3600*24&&(e.warning=(e.warning?`${e.warning}, `:\"\")+'113 - \"rfc7234 5.5.4\"'),e.age=`${Math.round(r)}`,e.date=new Date(this.now()).toUTCString(),e}date(){let e=Date.parse(this._resHeaders.date);return isFinite(e)?e:this._responseTime}age(){let e=this._ageValue(),r=(this.now()-this._responseTime)/1e3;return e+r}_ageValue(){return nm(this._resHeaders.age)}maxAge(){if(!this.storable()||this._rescc[\"no-cache\"]||this._isShared&&this._resHeaders[\"set-cookie\"]&&!this._rescc.public&&!this._rescc.immutable||this._resHeaders.vary===\"*\")return 0;if(this._isShared){if(this._rescc[\"proxy-revalidate\"])return 0;if(this._rescc[\"s-maxage\"])return nm(this._rescc[\"s-maxage\"])}if(this._rescc[\"max-age\"])return nm(this._rescc[\"max-age\"]);let e=this._rescc.immutable?this._immutableMinTtl:0,r=this.date();if(this._resHeaders.expires){let s=Date.parse(this._resHeaders.expires);return Number.isNaN(s)||s<r?0:Math.max(e,(s-r)/1e3)}if(this._resHeaders[\"last-modified\"]){let s=Date.parse(this._resHeaders[\"last-modified\"]);if(isFinite(s)&&r>s)return Math.max(e,(r-s)/1e3*this._cacheHeuristic)}return e}timeToLive(){let e=this.maxAge()-this.age(),r=e+nm(this._rescc[\"stale-if-error\"]),s=e+nm(this._rescc[\"stale-while-revalidate\"]);return Math.max(0,e,r,s)*1e3}stale(){return this.maxAge()<=this.age()}_useStaleIfError(){return this.maxAge()+nm(this._rescc[\"stale-if-error\"])>this.age()}useStaleWhileRevalidate(){return this.maxAge()+nm(this._rescc[\"stale-while-revalidate\"])>this.age()}static fromObject(e){return new this(void 0,void 0,{_fromObject:e})}_fromObject(e){if(this._responseTime)throw Error(\"Reinitialized\");if(!e||e.v!==1)throw Error(\"Invalid serialization\");this._responseTime=e.t,this._isShared=e.sh,this._cacheHeuristic=e.ch,this._immutableMinTtl=e.imm!==void 0?e.imm:24*3600*1e3,this._status=e.st,this._resHeaders=e.resh,this._rescc=e.rescc,this._method=e.m,this._url=e.u,this._host=e.h,this._noAuthorization=e.a,this._reqHeaders=e.reqh,this._reqcc=e.reqcc}toObject(){return{v:1,t:this._responseTime,sh:this._isShared,ch:this._cacheHeuristic,imm:this._immutableMinTtl,st:this._status,resh:this._resHeaders,rescc:this._rescc,m:this._method,u:this._url,h:this._host,a:this._noAuthorization,reqh:this._reqHeaders,reqcc:this._reqcc}}revalidationHeaders(e){this._assertRequestHasHeaders(e);let r=this._copyWithoutHopByHopHeaders(e.headers);if(delete r[\"if-range\"],!this._requestMatches(e,!0)||!this.storable())return delete r[\"if-none-match\"],delete r[\"if-modified-since\"],r;if(this._resHeaders.etag&&(r[\"if-none-match\"]=r[\"if-none-match\"]?`${r[\"if-none-match\"]}, ${this._resHeaders.etag}`:this._resHeaders.etag),r[\"accept-ranges\"]||r[\"if-match\"]||r[\"if-unmodified-since\"]||this._method&&this._method!=\"GET\"){if(delete r[\"if-modified-since\"],r[\"if-none-match\"]){let a=r[\"if-none-match\"].split(/,/).filter(n=>!/^\\s*W\\//.test(n));a.length?r[\"if-none-match\"]=a.join(\",\").trim():delete r[\"if-none-match\"]}}else this._resHeaders[\"last-modified\"]&&!r[\"if-modified-since\"]&&(r[\"if-modified-since\"]=this._resHeaders[\"last-modified\"]);return r}revalidatedPolicy(e,r){if(this._assertRequestHasHeaders(e),this._useStaleIfError()&&ott(r))return{modified:!1,matches:!1,policy:this};if(!r||!r.headers)throw Error(\"Response headers missing\");let s=!1;if(r.status!==void 0&&r.status!=304?s=!1:r.headers.etag&&!/^\\s*W\\//.test(r.headers.etag)?s=this._resHeaders.etag&&this._resHeaders.etag.replace(/^\\s*W\\//,\"\")===r.headers.etag:this._resHeaders.etag&&r.headers.etag?s=this._resHeaders.etag.replace(/^\\s*W\\//,\"\")===r.headers.etag.replace(/^\\s*W\\//,\"\"):this._resHeaders[\"last-modified\"]?s=this._resHeaders[\"last-modified\"]===r.headers[\"last-modified\"]:!this._resHeaders.etag&&!this._resHeaders[\"last-modified\"]&&!r.headers.etag&&!r.headers[\"last-modified\"]&&(s=!0),!s)return{policy:new this.constructor(e,r),modified:r.status!=304,matches:!1};let a={};for(let c in this._resHeaders)a[c]=c in r.headers&&!stt[c]?r.headers[c]:this._resHeaders[c];let n=Object.assign({},r,{status:this._status,method:this._method,headers:a});return{policy:new this.constructor(e,n,{shared:this._isShared,cacheHeuristic:this._cacheHeuristic,immutableMinTimeToLive:this._immutableMinTtl}),modified:!1,matches:!0}}}});var WQ=_((BMt,tfe)=>{\"use strict\";tfe.exports=t=>{let e={};for(let[r,s]of Object.entries(t))e[r.toLowerCase()]=s;return e}});var nfe=_((vMt,rfe)=>{\"use strict\";var ltt=Ie(\"stream\").Readable,ctt=WQ(),uH=class extends ltt{constructor(e,r,s,a){if(typeof e!=\"number\")throw new TypeError(\"Argument `statusCode` should be a number\");if(typeof r!=\"object\")throw new TypeError(\"Argument `headers` should be an object\");if(!(s instanceof Buffer))throw new TypeError(\"Argument `body` should be a buffer\");if(typeof a!=\"string\")throw new TypeError(\"Argument `url` should be a string\");super(),this.statusCode=e,this.headers=ctt(r),this.body=s,this.url=a}_read(){this.push(this.body),this.push(null)}};rfe.exports=uH});var sfe=_((SMt,ife)=>{\"use strict\";var utt=[\"destroy\",\"setTimeout\",\"socket\",\"headers\",\"trailers\",\"rawHeaders\",\"statusCode\",\"httpVersion\",\"httpVersionMinor\",\"httpVersionMajor\",\"rawTrailers\",\"statusMessage\"];ife.exports=(t,e)=>{let r=new Set(Object.keys(t).concat(utt));for(let s of r)s in e||(e[s]=typeof t[s]==\"function\"?t[s].bind(t):t[s])}});var afe=_((DMt,ofe)=>{\"use strict\";var ftt=Ie(\"stream\").PassThrough,Att=sfe(),ptt=t=>{if(!(t&&t.pipe))throw new TypeError(\"Parameter `response` must be a response stream.\");let e=new ftt;return Att(t,e),t.pipe(e)};ofe.exports=ptt});var lfe=_(fH=>{fH.stringify=function t(e){if(typeof e>\"u\")return e;if(e&&Buffer.isBuffer(e))return JSON.stringify(\":base64:\"+e.toString(\"base64\"));if(e&&e.toJSON&&(e=e.toJSON()),e&&typeof e==\"object\"){var r=\"\",s=Array.isArray(e);r=s?\"[\":\"{\";var a=!0;for(var n in e){var c=typeof e[n]==\"function\"||!s&&typeof e[n]>\"u\";Object.hasOwnProperty.call(e,n)&&!c&&(a||(r+=\",\"),a=!1,s?e[n]==null?r+=\"null\":r+=t(e[n]):e[n]!==void 0&&(r+=t(n)+\":\"+t(e[n])))}return r+=s?\"]\":\"}\",r}else return typeof e==\"string\"?JSON.stringify(/^:/.test(e)?\":\"+e:e):typeof e>\"u\"?\"null\":JSON.stringify(e)};fH.parse=function(t){return JSON.parse(t,function(e,r){return typeof r==\"string\"?/^:base64:/.test(r)?Buffer.from(r.substring(8),\"base64\"):/^:/.test(r)?r.substring(1):r:r})}});var Afe=_((bMt,ffe)=>{\"use strict\";var htt=Ie(\"events\"),cfe=lfe(),gtt=t=>{let e={redis:\"@keyv/redis\",rediss:\"@keyv/redis\",mongodb:\"@keyv/mongo\",mongo:\"@keyv/mongo\",sqlite:\"@keyv/sqlite\",postgresql:\"@keyv/postgres\",postgres:\"@keyv/postgres\",mysql:\"@keyv/mysql\",etcd:\"@keyv/etcd\",offline:\"@keyv/offline\",tiered:\"@keyv/tiered\"};if(t.adapter||t.uri){let r=t.adapter||/^[^:+]*/.exec(t.uri)[0];return new(Ie(e[r]))(t)}return new Map},ufe=[\"sqlite\",\"postgres\",\"mysql\",\"mongo\",\"redis\",\"tiered\"],AH=class extends htt{constructor(e,{emitErrors:r=!0,...s}={}){if(super(),this.opts={namespace:\"keyv\",serialize:cfe.stringify,deserialize:cfe.parse,...typeof e==\"string\"?{uri:e}:e,...s},!this.opts.store){let n={...this.opts};this.opts.store=gtt(n)}if(this.opts.compression){let n=this.opts.compression;this.opts.serialize=n.serialize.bind(n),this.opts.deserialize=n.deserialize.bind(n)}typeof this.opts.store.on==\"function\"&&r&&this.opts.store.on(\"error\",n=>this.emit(\"error\",n)),this.opts.store.namespace=this.opts.namespace;let a=n=>async function*(){for await(let[c,f]of typeof n==\"function\"?n(this.opts.store.namespace):n){let p=await this.opts.deserialize(f);if(!(this.opts.store.namespace&&!c.includes(this.opts.store.namespace))){if(typeof p.expires==\"number\"&&Date.now()>p.expires){this.delete(c);continue}yield[this._getKeyUnprefix(c),p.value]}}};typeof this.opts.store[Symbol.iterator]==\"function\"&&this.opts.store instanceof Map?this.iterator=a(this.opts.store):typeof this.opts.store.iterator==\"function\"&&this.opts.store.opts&&this._checkIterableAdaptar()&&(this.iterator=a(this.opts.store.iterator.bind(this.opts.store)))}_checkIterableAdaptar(){return ufe.includes(this.opts.store.opts.dialect)||ufe.findIndex(e=>this.opts.store.opts.url.includes(e))>=0}_getKeyPrefix(e){return`${this.opts.namespace}:${e}`}_getKeyPrefixArray(e){return e.map(r=>`${this.opts.namespace}:${r}`)}_getKeyUnprefix(e){return e.split(\":\").splice(1).join(\":\")}get(e,r){let{store:s}=this.opts,a=Array.isArray(e),n=a?this._getKeyPrefixArray(e):this._getKeyPrefix(e);if(a&&s.getMany===void 0){let c=[];for(let f of n)c.push(Promise.resolve().then(()=>s.get(f)).then(p=>typeof p==\"string\"?this.opts.deserialize(p):this.opts.compression?this.opts.deserialize(p):p).then(p=>{if(p!=null)return typeof p.expires==\"number\"&&Date.now()>p.expires?this.delete(f).then(()=>{}):r&&r.raw?p:p.value}));return Promise.allSettled(c).then(f=>{let p=[];for(let h of f)p.push(h.value);return p})}return Promise.resolve().then(()=>a?s.getMany(n):s.get(n)).then(c=>typeof c==\"string\"?this.opts.deserialize(c):this.opts.compression?this.opts.deserialize(c):c).then(c=>{if(c!=null)return a?c.map((f,p)=>{if(typeof f==\"string\"&&(f=this.opts.deserialize(f)),f!=null){if(typeof f.expires==\"number\"&&Date.now()>f.expires){this.delete(e[p]).then(()=>{});return}return r&&r.raw?f:f.value}}):typeof c.expires==\"number\"&&Date.now()>c.expires?this.delete(e).then(()=>{}):r&&r.raw?c:c.value})}set(e,r,s){let a=this._getKeyPrefix(e);typeof s>\"u\"&&(s=this.opts.ttl),s===0&&(s=void 0);let{store:n}=this.opts;return Promise.resolve().then(()=>{let c=typeof s==\"number\"?Date.now()+s:null;return typeof r==\"symbol\"&&this.emit(\"error\",\"symbol cannot be serialized\"),r={value:r,expires:c},this.opts.serialize(r)}).then(c=>n.set(a,c,s)).then(()=>!0)}delete(e){let{store:r}=this.opts;if(Array.isArray(e)){let a=this._getKeyPrefixArray(e);if(r.deleteMany===void 0){let n=[];for(let c of a)n.push(r.delete(c));return Promise.allSettled(n).then(c=>c.every(f=>f.value===!0))}return Promise.resolve().then(()=>r.deleteMany(a))}let s=this._getKeyPrefix(e);return Promise.resolve().then(()=>r.delete(s))}clear(){let{store:e}=this.opts;return Promise.resolve().then(()=>e.clear())}has(e){let r=this._getKeyPrefix(e),{store:s}=this.opts;return Promise.resolve().then(async()=>typeof s.has==\"function\"?s.has(r):await s.get(r)!==void 0)}disconnect(){let{store:e}=this.opts;if(typeof e.disconnect==\"function\")return e.disconnect()}};ffe.exports=AH});var gfe=_((kMt,hfe)=>{\"use strict\";var dtt=Ie(\"events\"),YQ=Ie(\"url\"),mtt=Uue(),ytt=Xue(),pH=efe(),pfe=nfe(),Ett=WQ(),Itt=afe(),Ctt=Afe(),KB=class t{constructor(e,r){if(typeof e!=\"function\")throw new TypeError(\"Parameter `request` must be a function\");return this.cache=new Ctt({uri:typeof r==\"string\"&&r,store:typeof r!=\"string\"&&r,namespace:\"cacheable-request\"}),this.createCacheableRequest(e)}createCacheableRequest(e){return(r,s)=>{let a;if(typeof r==\"string\")a=hH(YQ.parse(r)),r={};else if(r instanceof YQ.URL)a=hH(YQ.parse(r.toString())),r={};else{let[C,...S]=(r.path||\"\").split(\"?\"),b=S.length>0?`?${S.join(\"?\")}`:\"\";a=hH({...r,pathname:C,search:b})}r={headers:{},method:\"GET\",cache:!0,strictTtl:!1,automaticFailover:!1,...r,...wtt(a)},r.headers=Ett(r.headers);let n=new dtt,c=mtt(YQ.format(a),{stripWWW:!1,removeTrailingSlash:!1,stripAuthentication:!1}),f=`${r.method}:${c}`,p=!1,h=!1,E=C=>{h=!0;let S=!1,b,I=new Promise(N=>{b=()=>{S||(S=!0,N())}}),T=N=>{if(p&&!C.forceRefresh){N.status=N.statusCode;let W=pH.fromObject(p.cachePolicy).revalidatedPolicy(C,N);if(!W.modified){let ee=W.policy.responseHeaders();N=new pfe(p.statusCode,ee,p.body,p.url),N.cachePolicy=W.policy,N.fromCache=!0}}N.fromCache||(N.cachePolicy=new pH(C,N,C),N.fromCache=!1);let U;C.cache&&N.cachePolicy.storable()?(U=Itt(N),(async()=>{try{let W=ytt.buffer(N);if(await Promise.race([I,new Promise(le=>N.once(\"end\",le))]),S)return;let ee=await W,ie={cachePolicy:N.cachePolicy.toObject(),url:N.url,statusCode:N.fromCache?p.statusCode:N.statusCode,body:ee},ue=C.strictTtl?N.cachePolicy.timeToLive():void 0;C.maxTtl&&(ue=ue?Math.min(ue,C.maxTtl):C.maxTtl),await this.cache.set(f,ie,ue)}catch(W){n.emit(\"error\",new t.CacheError(W))}})()):C.cache&&p&&(async()=>{try{await this.cache.delete(f)}catch(W){n.emit(\"error\",new t.CacheError(W))}})(),n.emit(\"response\",U||N),typeof s==\"function\"&&s(U||N)};try{let N=e(C,T);N.once(\"error\",b),N.once(\"abort\",b),n.emit(\"request\",N)}catch(N){n.emit(\"error\",new t.RequestError(N))}};return(async()=>{let C=async b=>{await Promise.resolve();let I=b.cache?await this.cache.get(f):void 0;if(typeof I>\"u\")return E(b);let T=pH.fromObject(I.cachePolicy);if(T.satisfiesWithoutRevalidation(b)&&!b.forceRefresh){let N=T.responseHeaders(),U=new pfe(I.statusCode,N,I.body,I.url);U.cachePolicy=T,U.fromCache=!0,n.emit(\"response\",U),typeof s==\"function\"&&s(U)}else p=I,b.headers=T.revalidationHeaders(b),E(b)},S=b=>n.emit(\"error\",new t.CacheError(b));this.cache.once(\"error\",S),n.on(\"response\",()=>this.cache.removeListener(\"error\",S));try{await C(r)}catch(b){r.automaticFailover&&!h&&E(r),n.emit(\"error\",new t.CacheError(b))}})(),n}}};function wtt(t){let e={...t};return e.path=`${t.pathname||\"/\"}${t.search||\"\"}`,delete e.pathname,delete e.search,e}function hH(t){return{protocol:t.protocol,auth:t.auth,hostname:t.hostname||t.host||\"localhost\",port:t.port,pathname:t.pathname,search:t.search}}KB.RequestError=class extends Error{constructor(t){super(t.message),this.name=\"RequestError\",Object.assign(this,t)}};KB.CacheError=class extends Error{constructor(t){super(t.message),this.name=\"CacheError\",Object.assign(this,t)}};hfe.exports=KB});var mfe=_((TMt,dfe)=>{\"use strict\";var Btt=[\"aborted\",\"complete\",\"headers\",\"httpVersion\",\"httpVersionMinor\",\"httpVersionMajor\",\"method\",\"rawHeaders\",\"rawTrailers\",\"setTimeout\",\"socket\",\"statusCode\",\"statusMessage\",\"trailers\",\"url\"];dfe.exports=(t,e)=>{if(e._readableState.autoDestroy)throw new Error(\"The second stream must have the `autoDestroy` option set to `false`\");let r=new Set(Object.keys(t).concat(Btt)),s={};for(let a of r)a in e||(s[a]={get(){let n=t[a];return typeof n==\"function\"?n.bind(t):n},set(n){t[a]=n},enumerable:!0,configurable:!1});return Object.defineProperties(e,s),t.once(\"aborted\",()=>{e.destroy(),e.emit(\"aborted\")}),t.once(\"close\",()=>{t.complete&&e.readable?e.once(\"end\",()=>{e.emit(\"close\")}):e.emit(\"close\")}),e}});var Efe=_((FMt,yfe)=>{\"use strict\";var{Transform:vtt,PassThrough:Stt}=Ie(\"stream\"),gH=Ie(\"zlib\"),Dtt=mfe();yfe.exports=t=>{let e=(t.headers[\"content-encoding\"]||\"\").toLowerCase();if(![\"gzip\",\"deflate\",\"br\"].includes(e))return t;let r=e===\"br\";if(r&&typeof gH.createBrotliDecompress!=\"function\")return t.destroy(new Error(\"Brotli is not supported on Node.js < 12\")),t;let s=!0,a=new vtt({transform(f,p,h){s=!1,h(null,f)},flush(f){f()}}),n=new Stt({autoDestroy:!1,destroy(f,p){t.destroy(),p(f)}}),c=r?gH.createBrotliDecompress():gH.createUnzip();return c.once(\"error\",f=>{if(s&&!t.readable){n.end();return}n.destroy(f)}),Dtt(t,n),t.pipe(a).pipe(c).pipe(n),n}});var mH=_((NMt,Ife)=>{\"use strict\";var dH=class{constructor(e={}){if(!(e.maxSize&&e.maxSize>0))throw new TypeError(\"`maxSize` must be a number greater than 0\");this.maxSize=e.maxSize,this.onEviction=e.onEviction,this.cache=new Map,this.oldCache=new Map,this._size=0}_set(e,r){if(this.cache.set(e,r),this._size++,this._size>=this.maxSize){if(this._size=0,typeof this.onEviction==\"function\")for(let[s,a]of this.oldCache.entries())this.onEviction(s,a);this.oldCache=this.cache,this.cache=new Map}}get(e){if(this.cache.has(e))return this.cache.get(e);if(this.oldCache.has(e)){let r=this.oldCache.get(e);return this.oldCache.delete(e),this._set(e,r),r}}set(e,r){return this.cache.has(e)?this.cache.set(e,r):this._set(e,r),this}has(e){return this.cache.has(e)||this.oldCache.has(e)}peek(e){if(this.cache.has(e))return this.cache.get(e);if(this.oldCache.has(e))return this.oldCache.get(e)}delete(e){let r=this.cache.delete(e);return r&&this._size--,this.oldCache.delete(e)||r}clear(){this.cache.clear(),this.oldCache.clear(),this._size=0}*keys(){for(let[e]of this)yield e}*values(){for(let[,e]of this)yield e}*[Symbol.iterator](){for(let e of this.cache)yield e;for(let e of this.oldCache){let[r]=e;this.cache.has(r)||(yield e)}}get size(){let e=0;for(let r of this.oldCache.keys())this.cache.has(r)||e++;return Math.min(this._size+e,this.maxSize)}};Ife.exports=dH});var EH=_((OMt,vfe)=>{\"use strict\";var Ptt=Ie(\"events\"),btt=Ie(\"tls\"),xtt=Ie(\"http2\"),ktt=mH(),ba=Symbol(\"currentStreamsCount\"),Cfe=Symbol(\"request\"),Tc=Symbol(\"cachedOriginSet\"),gI=Symbol(\"gracefullyClosing\"),Qtt=[\"maxDeflateDynamicTableSize\",\"maxSessionMemory\",\"maxHeaderListPairs\",\"maxOutstandingPings\",\"maxReservedRemoteStreams\",\"maxSendHeaderBlockLength\",\"paddingStrategy\",\"localAddress\",\"path\",\"rejectUnauthorized\",\"minDHSize\",\"ca\",\"cert\",\"clientCertEngine\",\"ciphers\",\"key\",\"pfx\",\"servername\",\"minVersion\",\"maxVersion\",\"secureProtocol\",\"crl\",\"honorCipherOrder\",\"ecdhCurve\",\"dhparam\",\"secureOptions\",\"sessionIdContext\"],Rtt=(t,e,r)=>{let s=0,a=t.length;for(;s<a;){let n=s+a>>>1;r(t[n],e)?s=n+1:a=n}return s},Ttt=(t,e)=>t.remoteSettings.maxConcurrentStreams>e.remoteSettings.maxConcurrentStreams,yH=(t,e)=>{for(let r of t)r[Tc].length<e[Tc].length&&r[Tc].every(s=>e[Tc].includes(s))&&r[ba]+e[ba]<=e.remoteSettings.maxConcurrentStreams&&Bfe(r)},Ftt=(t,e)=>{for(let r of t)e[Tc].length<r[Tc].length&&e[Tc].every(s=>r[Tc].includes(s))&&e[ba]+r[ba]<=r.remoteSettings.maxConcurrentStreams&&Bfe(e)},wfe=({agent:t,isFree:e})=>{let r={};for(let s in t.sessions){let n=t.sessions[s].filter(c=>{let f=c[im.kCurrentStreamsCount]<c.remoteSettings.maxConcurrentStreams;return e?f:!f});n.length!==0&&(r[s]=n)}return r},Bfe=t=>{t[gI]=!0,t[ba]===0&&t.close()},im=class t extends Ptt{constructor({timeout:e=6e4,maxSessions:r=1/0,maxFreeSessions:s=10,maxCachedTlsSessions:a=100}={}){super(),this.sessions={},this.queue={},this.timeout=e,this.maxSessions=r,this.maxFreeSessions=s,this._freeSessionsCount=0,this._sessionsCount=0,this.settings={enablePush:!1},this.tlsSessionCache=new ktt({maxSize:a})}static normalizeOrigin(e,r){return typeof e==\"string\"&&(e=new URL(e)),r&&e.hostname!==r&&(e.hostname=r),e.origin}normalizeOptions(e){let r=\"\";if(e)for(let s of Qtt)e[s]&&(r+=`:${e[s]}`);return r}_tryToCreateNewSession(e,r){if(!(e in this.queue)||!(r in this.queue[e]))return;let s=this.queue[e][r];this._sessionsCount<this.maxSessions&&!s.completed&&(s.completed=!0,s())}getSession(e,r,s){return new Promise((a,n)=>{Array.isArray(s)?(s=[...s],a()):s=[{resolve:a,reject:n}];let c=this.normalizeOptions(r),f=t.normalizeOrigin(e,r&&r.servername);if(f===void 0){for(let{reject:E}of s)E(new TypeError(\"The `origin` argument needs to be a string or an URL object\"));return}if(c in this.sessions){let E=this.sessions[c],C=-1,S=-1,b;for(let I of E){let T=I.remoteSettings.maxConcurrentStreams;if(T<C)break;if(I[Tc].includes(f)){let N=I[ba];if(N>=T||I[gI]||I.destroyed)continue;b||(C=T),N>S&&(b=I,S=N)}}if(b){if(s.length!==1){for(let{reject:I}of s){let T=new Error(`Expected the length of listeners to be 1, got ${s.length}.\nPlease report this to https://github.com/szmarczak/http2-wrapper/`);I(T)}return}s[0].resolve(b);return}}if(c in this.queue){if(f in this.queue[c]){this.queue[c][f].listeners.push(...s),this._tryToCreateNewSession(c,f);return}}else this.queue[c]={};let p=()=>{c in this.queue&&this.queue[c][f]===h&&(delete this.queue[c][f],Object.keys(this.queue[c]).length===0&&delete this.queue[c])},h=()=>{let E=`${f}:${c}`,C=!1;try{let S=xtt.connect(e,{createConnection:this.createConnection,settings:this.settings,session:this.tlsSessionCache.get(E),...r});S[ba]=0,S[gI]=!1;let b=()=>S[ba]<S.remoteSettings.maxConcurrentStreams,I=!0;S.socket.once(\"session\",N=>{this.tlsSessionCache.set(E,N)}),S.once(\"error\",N=>{for(let{reject:U}of s)U(N);this.tlsSessionCache.delete(E)}),S.setTimeout(this.timeout,()=>{S.destroy()}),S.once(\"close\",()=>{if(C){I&&this._freeSessionsCount--,this._sessionsCount--;let N=this.sessions[c];N.splice(N.indexOf(S),1),N.length===0&&delete this.sessions[c]}else{let N=new Error(\"Session closed without receiving a SETTINGS frame\");N.code=\"HTTP2WRAPPER_NOSETTINGS\";for(let{reject:U}of s)U(N);p()}this._tryToCreateNewSession(c,f)});let T=()=>{if(!(!(c in this.queue)||!b())){for(let N of S[Tc])if(N in this.queue[c]){let{listeners:U}=this.queue[c][N];for(;U.length!==0&&b();)U.shift().resolve(S);let W=this.queue[c];if(W[N].listeners.length===0&&(delete W[N],Object.keys(W).length===0)){delete this.queue[c];break}if(!b())break}}};S.on(\"origin\",()=>{S[Tc]=S.originSet,b()&&(T(),yH(this.sessions[c],S))}),S.once(\"remoteSettings\",()=>{if(S.ref(),S.unref(),this._sessionsCount++,h.destroyed){let N=new Error(\"Agent has been destroyed\");for(let U of s)U.reject(N);S.destroy();return}S[Tc]=S.originSet;{let N=this.sessions;if(c in N){let U=N[c];U.splice(Rtt(U,S,Ttt),0,S)}else N[c]=[S]}this._freeSessionsCount+=1,C=!0,this.emit(\"session\",S),T(),p(),S[ba]===0&&this._freeSessionsCount>this.maxFreeSessions&&S.close(),s.length!==0&&(this.getSession(f,r,s),s.length=0),S.on(\"remoteSettings\",()=>{T(),yH(this.sessions[c],S)})}),S[Cfe]=S.request,S.request=(N,U)=>{if(S[gI])throw new Error(\"The session is gracefully closing. No new streams are allowed.\");let W=S[Cfe](N,U);return S.ref(),++S[ba],S[ba]===S.remoteSettings.maxConcurrentStreams&&this._freeSessionsCount--,W.once(\"close\",()=>{if(I=b(),--S[ba],!S.destroyed&&!S.closed&&(Ftt(this.sessions[c],S),b()&&!S.closed)){I||(this._freeSessionsCount++,I=!0);let ee=S[ba]===0;ee&&S.unref(),ee&&(this._freeSessionsCount>this.maxFreeSessions||S[gI])?S.close():(yH(this.sessions[c],S),T())}}),W}}catch(S){for(let b of s)b.reject(S);p()}};h.listeners=s,h.completed=!1,h.destroyed=!1,this.queue[c][f]=h,this._tryToCreateNewSession(c,f)})}request(e,r,s,a){return new Promise((n,c)=>{this.getSession(e,r,[{reject:c,resolve:f=>{try{n(f.request(s,a))}catch(p){c(p)}}}])})}createConnection(e,r){return t.connect(e,r)}static connect(e,r){r.ALPNProtocols=[\"h2\"];let s=e.port||443,a=e.hostname||e.host;return typeof r.servername>\"u\"&&(r.servername=a),btt.connect(s,a,r)}closeFreeSessions(){for(let e of Object.values(this.sessions))for(let r of e)r[ba]===0&&r.close()}destroy(e){for(let r of Object.values(this.sessions))for(let s of r)s.destroy(e);for(let r of Object.values(this.queue))for(let s of Object.values(r))s.destroyed=!0;this.queue={}}get freeSessions(){return wfe({agent:this,isFree:!0})}get busySessions(){return wfe({agent:this,isFree:!1})}};im.kCurrentStreamsCount=ba;im.kGracefullyClosing=gI;vfe.exports={Agent:im,globalAgent:new im}});var CH=_((LMt,Sfe)=>{\"use strict\";var{Readable:Ntt}=Ie(\"stream\"),IH=class extends Ntt{constructor(e,r){super({highWaterMark:r,autoDestroy:!1}),this.statusCode=null,this.statusMessage=\"\",this.httpVersion=\"2.0\",this.httpVersionMajor=2,this.httpVersionMinor=0,this.headers={},this.trailers={},this.req=null,this.aborted=!1,this.complete=!1,this.upgrade=null,this.rawHeaders=[],this.rawTrailers=[],this.socket=e,this.connection=e,this._dumped=!1}_destroy(e){this.req._request.destroy(e)}setTimeout(e,r){return this.req.setTimeout(e,r),this}_dump(){this._dumped||(this._dumped=!0,this.removeAllListeners(\"data\"),this.resume())}_read(){this.req&&this.req._request.resume()}};Sfe.exports=IH});var wH=_((MMt,Dfe)=>{\"use strict\";Dfe.exports=t=>{let e={protocol:t.protocol,hostname:typeof t.hostname==\"string\"&&t.hostname.startsWith(\"[\")?t.hostname.slice(1,-1):t.hostname,host:t.host,hash:t.hash,search:t.search,pathname:t.pathname,href:t.href,path:`${t.pathname||\"\"}${t.search||\"\"}`};return typeof t.port==\"string\"&&t.port.length!==0&&(e.port=Number(t.port)),(t.username||t.password)&&(e.auth=`${t.username||\"\"}:${t.password||\"\"}`),e}});var bfe=_((UMt,Pfe)=>{\"use strict\";Pfe.exports=(t,e,r)=>{for(let s of r)t.on(s,(...a)=>e.emit(s,...a))}});var kfe=_((_Mt,xfe)=>{\"use strict\";xfe.exports=t=>{switch(t){case\":method\":case\":scheme\":case\":authority\":case\":path\":return!0;default:return!1}}});var Rfe=_((jMt,Qfe)=>{\"use strict\";var dI=(t,e,r)=>{Qfe.exports[e]=class extends t{constructor(...a){super(typeof r==\"string\"?r:r(a)),this.name=`${super.name} [${e}]`,this.code=e}}};dI(TypeError,\"ERR_INVALID_ARG_TYPE\",t=>{let e=t[0].includes(\".\")?\"property\":\"argument\",r=t[1],s=Array.isArray(r);return s&&(r=`${r.slice(0,-1).join(\", \")} or ${r.slice(-1)}`),`The \"${t[0]}\" ${e} must be ${s?\"one of\":\"of\"} type ${r}. Received ${typeof t[2]}`});dI(TypeError,\"ERR_INVALID_PROTOCOL\",t=>`Protocol \"${t[0]}\" not supported. Expected \"${t[1]}\"`);dI(Error,\"ERR_HTTP_HEADERS_SENT\",t=>`Cannot ${t[0]} headers after they are sent to the client`);dI(TypeError,\"ERR_INVALID_HTTP_TOKEN\",t=>`${t[0]} must be a valid HTTP token [${t[1]}]`);dI(TypeError,\"ERR_HTTP_INVALID_HEADER_VALUE\",t=>`Invalid value \"${t[0]} for header \"${t[1]}\"`);dI(TypeError,\"ERR_INVALID_CHAR\",t=>`Invalid character in ${t[0]} [${t[1]}]`)});var PH=_((GMt,Ufe)=>{\"use strict\";var Ott=Ie(\"http2\"),{Writable:Ltt}=Ie(\"stream\"),{Agent:Tfe,globalAgent:Mtt}=EH(),Utt=CH(),_tt=wH(),Htt=bfe(),jtt=kfe(),{ERR_INVALID_ARG_TYPE:BH,ERR_INVALID_PROTOCOL:Gtt,ERR_HTTP_HEADERS_SENT:Ffe,ERR_INVALID_HTTP_TOKEN:qtt,ERR_HTTP_INVALID_HEADER_VALUE:Wtt,ERR_INVALID_CHAR:Ytt}=Rfe(),{HTTP2_HEADER_STATUS:Nfe,HTTP2_HEADER_METHOD:Ofe,HTTP2_HEADER_PATH:Lfe,HTTP2_METHOD_CONNECT:Vtt}=Ott.constants,Jo=Symbol(\"headers\"),vH=Symbol(\"origin\"),SH=Symbol(\"session\"),Mfe=Symbol(\"options\"),VQ=Symbol(\"flushedHeaders\"),zB=Symbol(\"jobs\"),Jtt=/^[\\^`\\-\\w!#$%&*+.|~]+$/,Ktt=/[^\\t\\u0020-\\u007E\\u0080-\\u00FF]/,DH=class extends Ltt{constructor(e,r,s){super({autoDestroy:!1});let a=typeof e==\"string\"||e instanceof URL;if(a&&(e=_tt(e instanceof URL?e:new URL(e))),typeof r==\"function\"||r===void 0?(s=r,r=a?e:{...e}):r={...e,...r},r.h2session)this[SH]=r.h2session;else if(r.agent===!1)this.agent=new Tfe({maxFreeSessions:0});else if(typeof r.agent>\"u\"||r.agent===null)typeof r.createConnection==\"function\"?(this.agent=new Tfe({maxFreeSessions:0}),this.agent.createConnection=r.createConnection):this.agent=Mtt;else if(typeof r.agent.request==\"function\")this.agent=r.agent;else throw new BH(\"options.agent\",[\"Agent-like Object\",\"undefined\",\"false\"],r.agent);if(r.protocol&&r.protocol!==\"https:\")throw new Gtt(r.protocol,\"https:\");let n=r.port||r.defaultPort||this.agent&&this.agent.defaultPort||443,c=r.hostname||r.host||\"localhost\";delete r.hostname,delete r.host,delete r.port;let{timeout:f}=r;if(r.timeout=void 0,this[Jo]=Object.create(null),this[zB]=[],this.socket=null,this.connection=null,this.method=r.method||\"GET\",this.path=r.path,this.res=null,this.aborted=!1,this.reusedSocket=!1,r.headers)for(let[p,h]of Object.entries(r.headers))this.setHeader(p,h);r.auth&&!(\"authorization\"in this[Jo])&&(this[Jo].authorization=\"Basic \"+Buffer.from(r.auth).toString(\"base64\")),r.session=r.tlsSession,r.path=r.socketPath,this[Mfe]=r,n===443?(this[vH]=`https://${c}`,\":authority\"in this[Jo]||(this[Jo][\":authority\"]=c)):(this[vH]=`https://${c}:${n}`,\":authority\"in this[Jo]||(this[Jo][\":authority\"]=`${c}:${n}`)),f&&this.setTimeout(f),s&&this.once(\"response\",s),this[VQ]=!1}get method(){return this[Jo][Ofe]}set method(e){e&&(this[Jo][Ofe]=e.toUpperCase())}get path(){return this[Jo][Lfe]}set path(e){e&&(this[Jo][Lfe]=e)}get _mustNotHaveABody(){return this.method===\"GET\"||this.method===\"HEAD\"||this.method===\"DELETE\"}_write(e,r,s){if(this._mustNotHaveABody){s(new Error(\"The GET, HEAD and DELETE methods must NOT have a body\"));return}this.flushHeaders();let a=()=>this._request.write(e,r,s);this._request?a():this[zB].push(a)}_final(e){if(this.destroyed)return;this.flushHeaders();let r=()=>{if(this._mustNotHaveABody){e();return}this._request.end(e)};this._request?r():this[zB].push(r)}abort(){this.res&&this.res.complete||(this.aborted||process.nextTick(()=>this.emit(\"abort\")),this.aborted=!0,this.destroy())}_destroy(e,r){this.res&&this.res._dump(),this._request&&this._request.destroy(),r(e)}async flushHeaders(){if(this[VQ]||this.destroyed)return;this[VQ]=!0;let e=this.method===Vtt,r=s=>{if(this._request=s,this.destroyed){s.destroy();return}e||Htt(s,this,[\"timeout\",\"continue\",\"close\",\"error\"]);let a=c=>(...f)=>{!this.writable&&!this.destroyed?c(...f):this.once(\"finish\",()=>{c(...f)})};s.once(\"response\",a((c,f,p)=>{let h=new Utt(this.socket,s.readableHighWaterMark);this.res=h,h.req=this,h.statusCode=c[Nfe],h.headers=c,h.rawHeaders=p,h.once(\"end\",()=>{this.aborted?(h.aborted=!0,h.emit(\"aborted\")):(h.complete=!0,h.socket=null,h.connection=null)}),e?(h.upgrade=!0,this.emit(\"connect\",h,s,Buffer.alloc(0))?this.emit(\"close\"):s.destroy()):(s.on(\"data\",E=>{!h._dumped&&!h.push(E)&&s.pause()}),s.once(\"end\",()=>{h.push(null)}),this.emit(\"response\",h)||h._dump())})),s.once(\"headers\",a(c=>this.emit(\"information\",{statusCode:c[Nfe]}))),s.once(\"trailers\",a((c,f,p)=>{let{res:h}=this;h.trailers=c,h.rawTrailers=p}));let{socket:n}=s.session;this.socket=n,this.connection=n;for(let c of this[zB])c();this.emit(\"socket\",this.socket)};if(this[SH])try{r(this[SH].request(this[Jo]))}catch(s){this.emit(\"error\",s)}else{this.reusedSocket=!0;try{r(await this.agent.request(this[vH],this[Mfe],this[Jo]))}catch(s){this.emit(\"error\",s)}}}getHeader(e){if(typeof e!=\"string\")throw new BH(\"name\",\"string\",e);return this[Jo][e.toLowerCase()]}get headersSent(){return this[VQ]}removeHeader(e){if(typeof e!=\"string\")throw new BH(\"name\",\"string\",e);if(this.headersSent)throw new Ffe(\"remove\");delete this[Jo][e.toLowerCase()]}setHeader(e,r){if(this.headersSent)throw new Ffe(\"set\");if(typeof e!=\"string\"||!Jtt.test(e)&&!jtt(e))throw new qtt(\"Header name\",e);if(typeof r>\"u\")throw new Wtt(r,e);if(Ktt.test(r))throw new Ytt(\"header content\",e);this[Jo][e.toLowerCase()]=r}setNoDelay(){}setSocketKeepAlive(){}setTimeout(e,r){let s=()=>this._request.setTimeout(e,r);return this._request?s():this[zB].push(s),this}get maxHeadersCount(){if(!this.destroyed&&this._request)return this._request.session.localSettings.maxHeaderListSize}set maxHeadersCount(e){}};Ufe.exports=DH});var Hfe=_((qMt,_fe)=>{\"use strict\";var ztt=Ie(\"tls\");_fe.exports=(t={},e=ztt.connect)=>new Promise((r,s)=>{let a=!1,n,c=async()=>{await p,n.off(\"timeout\",f),n.off(\"error\",s),t.resolveSocket?(r({alpnProtocol:n.alpnProtocol,socket:n,timeout:a}),a&&(await Promise.resolve(),n.emit(\"timeout\"))):(n.destroy(),r({alpnProtocol:n.alpnProtocol,timeout:a}))},f=async()=>{a=!0,c()},p=(async()=>{try{n=await e(t,c),n.on(\"error\",s),n.once(\"timeout\",f)}catch(h){s(h)}})()})});var Gfe=_((WMt,jfe)=>{\"use strict\";var Ztt=Ie(\"net\");jfe.exports=t=>{let e=t.host,r=t.headers&&t.headers.host;return r&&(r.startsWith(\"[\")?r.indexOf(\"]\")===-1?e=r:e=r.slice(1,-1):e=r.split(\":\",1)[0]),Ztt.isIP(e)?\"\":e}});var Yfe=_((YMt,xH)=>{\"use strict\";var qfe=Ie(\"http\"),bH=Ie(\"https\"),Xtt=Hfe(),$tt=mH(),ert=PH(),trt=Gfe(),rrt=wH(),JQ=new $tt({maxSize:100}),ZB=new Map,Wfe=(t,e,r)=>{e._httpMessage={shouldKeepAlive:!0};let s=()=>{t.emit(\"free\",e,r)};e.on(\"free\",s);let a=()=>{t.removeSocket(e,r)};e.on(\"close\",a);let n=()=>{t.removeSocket(e,r),e.off(\"close\",a),e.off(\"free\",s),e.off(\"agentRemove\",n)};e.on(\"agentRemove\",n),t.emit(\"free\",e,r)},nrt=async t=>{let e=`${t.host}:${t.port}:${t.ALPNProtocols.sort()}`;if(!JQ.has(e)){if(ZB.has(e))return(await ZB.get(e)).alpnProtocol;let{path:r,agent:s}=t;t.path=t.socketPath;let a=Xtt(t);ZB.set(e,a);try{let{socket:n,alpnProtocol:c}=await a;if(JQ.set(e,c),t.path=r,c===\"h2\")n.destroy();else{let{globalAgent:f}=bH,p=bH.Agent.prototype.createConnection;s?s.createConnection===p?Wfe(s,n,t):n.destroy():f.createConnection===p?Wfe(f,n,t):n.destroy()}return ZB.delete(e),c}catch(n){throw ZB.delete(e),n}}return JQ.get(e)};xH.exports=async(t,e,r)=>{if((typeof t==\"string\"||t instanceof URL)&&(t=rrt(new URL(t))),typeof e==\"function\"&&(r=e,e=void 0),e={ALPNProtocols:[\"h2\",\"http/1.1\"],...t,...e,resolveSocket:!0},!Array.isArray(e.ALPNProtocols)||e.ALPNProtocols.length===0)throw new Error(\"The `ALPNProtocols` option must be an Array with at least one entry\");e.protocol=e.protocol||\"https:\";let s=e.protocol===\"https:\";e.host=e.hostname||e.host||\"localhost\",e.session=e.tlsSession,e.servername=e.servername||trt(e),e.port=e.port||(s?443:80),e._defaultAgent=s?bH.globalAgent:qfe.globalAgent;let a=e.agent;if(a){if(a.addRequest)throw new Error(\"The `options.agent` object can contain only `http`, `https` or `http2` properties\");e.agent=a[s?\"https\":\"http\"]}return s&&await nrt(e)===\"h2\"?(a&&(e.agent=a.http2),new ert(e,r)):qfe.request(e,r)};xH.exports.protocolCache=JQ});var Jfe=_((VMt,Vfe)=>{\"use strict\";var irt=Ie(\"http2\"),srt=EH(),kH=PH(),ort=CH(),art=Yfe(),lrt=(t,e,r)=>new kH(t,e,r),crt=(t,e,r)=>{let s=new kH(t,e,r);return s.end(),s};Vfe.exports={...irt,ClientRequest:kH,IncomingMessage:ort,...srt,request:lrt,get:crt,auto:art}});var RH=_(QH=>{\"use strict\";Object.defineProperty(QH,\"__esModule\",{value:!0});var Kfe=Np();QH.default=t=>Kfe.default.nodeStream(t)&&Kfe.default.function_(t.getBoundary)});var $fe=_(TH=>{\"use strict\";Object.defineProperty(TH,\"__esModule\",{value:!0});var Zfe=Ie(\"fs\"),Xfe=Ie(\"util\"),zfe=Np(),urt=RH(),frt=Xfe.promisify(Zfe.stat);TH.default=async(t,e)=>{if(e&&\"content-length\"in e)return Number(e[\"content-length\"]);if(!t)return 0;if(zfe.default.string(t))return Buffer.byteLength(t);if(zfe.default.buffer(t))return t.length;if(urt.default(t))return Xfe.promisify(t.getLength.bind(t))();if(t instanceof Zfe.ReadStream){let{size:r}=await frt(t.path);return r===0?void 0:r}}});var NH=_(FH=>{\"use strict\";Object.defineProperty(FH,\"__esModule\",{value:!0});function Art(t,e,r){let s={};for(let a of r)s[a]=(...n)=>{e.emit(a,...n)},t.on(a,s[a]);return()=>{for(let a of r)t.off(a,s[a])}}FH.default=Art});var eAe=_(OH=>{\"use strict\";Object.defineProperty(OH,\"__esModule\",{value:!0});OH.default=()=>{let t=[];return{once(e,r,s){e.once(r,s),t.push({origin:e,event:r,fn:s})},unhandleAll(){for(let e of t){let{origin:r,event:s,fn:a}=e;r.removeListener(s,a)}t.length=0}}}});var rAe=_(XB=>{\"use strict\";Object.defineProperty(XB,\"__esModule\",{value:!0});XB.TimeoutError=void 0;var prt=Ie(\"net\"),hrt=eAe(),tAe=Symbol(\"reentry\"),grt=()=>{},KQ=class extends Error{constructor(e,r){super(`Timeout awaiting '${r}' for ${e}ms`),this.event=r,this.name=\"TimeoutError\",this.code=\"ETIMEDOUT\"}};XB.TimeoutError=KQ;XB.default=(t,e,r)=>{if(tAe in t)return grt;t[tAe]=!0;let s=[],{once:a,unhandleAll:n}=hrt.default(),c=(C,S,b)=>{var I;let T=setTimeout(S,C,C,b);(I=T.unref)===null||I===void 0||I.call(T);let N=()=>{clearTimeout(T)};return s.push(N),N},{host:f,hostname:p}=r,h=(C,S)=>{t.destroy(new KQ(C,S))},E=()=>{for(let C of s)C();n()};if(t.once(\"error\",C=>{if(E(),t.listenerCount(\"error\")===0)throw C}),t.once(\"close\",E),a(t,\"response\",C=>{a(C,\"end\",E)}),typeof e.request<\"u\"&&c(e.request,h,\"request\"),typeof e.socket<\"u\"){let C=()=>{h(e.socket,\"socket\")};t.setTimeout(e.socket,C),s.push(()=>{t.removeListener(\"timeout\",C)})}return a(t,\"socket\",C=>{var S;let{socketPath:b}=t;if(C.connecting){let I=!!(b??prt.isIP((S=p??f)!==null&&S!==void 0?S:\"\")!==0);if(typeof e.lookup<\"u\"&&!I&&typeof C.address().address>\"u\"){let T=c(e.lookup,h,\"lookup\");a(C,\"lookup\",T)}if(typeof e.connect<\"u\"){let T=()=>c(e.connect,h,\"connect\");I?a(C,\"connect\",T()):a(C,\"lookup\",N=>{N===null&&a(C,\"connect\",T())})}typeof e.secureConnect<\"u\"&&r.protocol===\"https:\"&&a(C,\"connect\",()=>{let T=c(e.secureConnect,h,\"secureConnect\");a(C,\"secureConnect\",T)})}if(typeof e.send<\"u\"){let I=()=>c(e.send,h,\"send\");C.connecting?a(C,\"connect\",()=>{a(t,\"upload-complete\",I())}):a(t,\"upload-complete\",I())}}),typeof e.response<\"u\"&&a(t,\"upload-complete\",()=>{let C=c(e.response,h,\"response\");a(t,\"response\",C)}),E}});var iAe=_(LH=>{\"use strict\";Object.defineProperty(LH,\"__esModule\",{value:!0});var nAe=Np();LH.default=t=>{t=t;let e={protocol:t.protocol,hostname:nAe.default.string(t.hostname)&&t.hostname.startsWith(\"[\")?t.hostname.slice(1,-1):t.hostname,host:t.host,hash:t.hash,search:t.search,pathname:t.pathname,href:t.href,path:`${t.pathname||\"\"}${t.search||\"\"}`};return nAe.default.string(t.port)&&t.port.length>0&&(e.port=Number(t.port)),(t.username||t.password)&&(e.auth=`${t.username||\"\"}:${t.password||\"\"}`),e}});var sAe=_(MH=>{\"use strict\";Object.defineProperty(MH,\"__esModule\",{value:!0});var drt=Ie(\"url\"),mrt=[\"protocol\",\"host\",\"hostname\",\"port\",\"pathname\",\"search\"];MH.default=(t,e)=>{var r,s;if(e.path){if(e.pathname)throw new TypeError(\"Parameters `path` and `pathname` are mutually exclusive.\");if(e.search)throw new TypeError(\"Parameters `path` and `search` are mutually exclusive.\");if(e.searchParams)throw new TypeError(\"Parameters `path` and `searchParams` are mutually exclusive.\")}if(e.search&&e.searchParams)throw new TypeError(\"Parameters `search` and `searchParams` are mutually exclusive.\");if(!t){if(!e.protocol)throw new TypeError(\"No URL protocol specified\");t=`${e.protocol}//${(s=(r=e.hostname)!==null&&r!==void 0?r:e.host)!==null&&s!==void 0?s:\"\"}`}let a=new drt.URL(t);if(e.path){let n=e.path.indexOf(\"?\");n===-1?e.pathname=e.path:(e.pathname=e.path.slice(0,n),e.search=e.path.slice(n+1)),delete e.path}for(let n of mrt)e[n]&&(a[n]=e[n].toString());return a}});var oAe=_(_H=>{\"use strict\";Object.defineProperty(_H,\"__esModule\",{value:!0});var UH=class{constructor(){this.weakMap=new WeakMap,this.map=new Map}set(e,r){typeof e==\"object\"?this.weakMap.set(e,r):this.map.set(e,r)}get(e){return typeof e==\"object\"?this.weakMap.get(e):this.map.get(e)}has(e){return typeof e==\"object\"?this.weakMap.has(e):this.map.has(e)}};_H.default=UH});var jH=_(HH=>{\"use strict\";Object.defineProperty(HH,\"__esModule\",{value:!0});var yrt=async t=>{let e=[],r=0;for await(let s of t)e.push(s),r+=Buffer.byteLength(s);return Buffer.isBuffer(e[0])?Buffer.concat(e,r):Buffer.from(e.join(\"\"))};HH.default=yrt});var lAe=_(sm=>{\"use strict\";Object.defineProperty(sm,\"__esModule\",{value:!0});sm.dnsLookupIpVersionToFamily=sm.isDnsLookupIpVersion=void 0;var aAe={auto:0,ipv4:4,ipv6:6};sm.isDnsLookupIpVersion=t=>t in aAe;sm.dnsLookupIpVersionToFamily=t=>{if(sm.isDnsLookupIpVersion(t))return aAe[t];throw new Error(\"Invalid DNS lookup IP version\")}});var GH=_(zQ=>{\"use strict\";Object.defineProperty(zQ,\"__esModule\",{value:!0});zQ.isResponseOk=void 0;zQ.isResponseOk=t=>{let{statusCode:e}=t,r=t.request.options.followRedirect?299:399;return e>=200&&e<=r||e===304}});var uAe=_(qH=>{\"use strict\";Object.defineProperty(qH,\"__esModule\",{value:!0});var cAe=new Set;qH.default=t=>{cAe.has(t)||(cAe.add(t),process.emitWarning(`Got: ${t}`,{type:\"DeprecationWarning\"}))}});var fAe=_(WH=>{\"use strict\";Object.defineProperty(WH,\"__esModule\",{value:!0});var Si=Np(),Ert=(t,e)=>{if(Si.default.null_(t.encoding))throw new TypeError(\"To get a Buffer, set `options.responseType` to `buffer` instead\");Si.assert.any([Si.default.string,Si.default.undefined],t.encoding),Si.assert.any([Si.default.boolean,Si.default.undefined],t.resolveBodyOnly),Si.assert.any([Si.default.boolean,Si.default.undefined],t.methodRewriting),Si.assert.any([Si.default.boolean,Si.default.undefined],t.isStream),Si.assert.any([Si.default.string,Si.default.undefined],t.responseType),t.responseType===void 0&&(t.responseType=\"text\");let{retry:r}=t;if(e?t.retry={...e.retry}:t.retry={calculateDelay:s=>s.computedValue,limit:0,methods:[],statusCodes:[],errorCodes:[],maxRetryAfter:void 0},Si.default.object(r)?(t.retry={...t.retry,...r},t.retry.methods=[...new Set(t.retry.methods.map(s=>s.toUpperCase()))],t.retry.statusCodes=[...new Set(t.retry.statusCodes)],t.retry.errorCodes=[...new Set(t.retry.errorCodes)]):Si.default.number(r)&&(t.retry.limit=r),Si.default.undefined(t.retry.maxRetryAfter)&&(t.retry.maxRetryAfter=Math.min(...[t.timeout.request,t.timeout.connect].filter(Si.default.number))),Si.default.object(t.pagination)){e&&(t.pagination={...e.pagination,...t.pagination});let{pagination:s}=t;if(!Si.default.function_(s.transform))throw new Error(\"`options.pagination.transform` must be implemented\");if(!Si.default.function_(s.shouldContinue))throw new Error(\"`options.pagination.shouldContinue` must be implemented\");if(!Si.default.function_(s.filter))throw new TypeError(\"`options.pagination.filter` must be implemented\");if(!Si.default.function_(s.paginate))throw new Error(\"`options.pagination.paginate` must be implemented\")}return t.responseType===\"json\"&&t.headers.accept===void 0&&(t.headers.accept=\"application/json\"),t};WH.default=Ert});var AAe=_($B=>{\"use strict\";Object.defineProperty($B,\"__esModule\",{value:!0});$B.retryAfterStatusCodes=void 0;$B.retryAfterStatusCodes=new Set([413,429,503]);var Irt=({attemptCount:t,retryOptions:e,error:r,retryAfter:s})=>{if(t>e.limit)return 0;let a=e.methods.includes(r.options.method),n=e.errorCodes.includes(r.code),c=r.response&&e.statusCodes.includes(r.response.statusCode);if(!a||!n&&!c)return 0;if(r.response){if(s)return e.maxRetryAfter===void 0||s>e.maxRetryAfter?0:s;if(r.response.statusCode===413)return 0}let f=Math.random()*100;return 2**(t-1)*1e3+f};$B.default=Irt});var rv=_(Ln=>{\"use strict\";Object.defineProperty(Ln,\"__esModule\",{value:!0});Ln.UnsupportedProtocolError=Ln.ReadError=Ln.TimeoutError=Ln.UploadError=Ln.CacheError=Ln.HTTPError=Ln.MaxRedirectsError=Ln.RequestError=Ln.setNonEnumerableProperties=Ln.knownHookEvents=Ln.withoutBody=Ln.kIsNormalizedAlready=void 0;var pAe=Ie(\"util\"),hAe=Ie(\"stream\"),Crt=Ie(\"fs\"),w0=Ie(\"url\"),gAe=Ie(\"http\"),YH=Ie(\"http\"),wrt=Ie(\"https\"),Brt=xue(),vrt=Oue(),dAe=gfe(),Srt=Efe(),Drt=Jfe(),Prt=WQ(),at=Np(),brt=$fe(),mAe=RH(),xrt=NH(),yAe=rAe(),krt=iAe(),EAe=sAe(),Qrt=oAe(),Rrt=jH(),IAe=lAe(),Trt=GH(),B0=uAe(),Frt=fAe(),Nrt=AAe(),VH,po=Symbol(\"request\"),$Q=Symbol(\"response\"),mI=Symbol(\"responseSize\"),yI=Symbol(\"downloadedSize\"),EI=Symbol(\"bodySize\"),II=Symbol(\"uploadedSize\"),ZQ=Symbol(\"serverResponsesPiped\"),CAe=Symbol(\"unproxyEvents\"),wAe=Symbol(\"isFromCache\"),JH=Symbol(\"cancelTimeouts\"),BAe=Symbol(\"startedReading\"),CI=Symbol(\"stopReading\"),XQ=Symbol(\"triggerRead\"),v0=Symbol(\"body\"),ev=Symbol(\"jobs\"),vAe=Symbol(\"originalResponse\"),SAe=Symbol(\"retryTimeout\");Ln.kIsNormalizedAlready=Symbol(\"isNormalizedAlready\");var Ort=at.default.string(process.versions.brotli);Ln.withoutBody=new Set([\"GET\",\"HEAD\"]);Ln.knownHookEvents=[\"init\",\"beforeRequest\",\"beforeRedirect\",\"beforeError\",\"beforeRetry\",\"afterResponse\"];function Lrt(t){for(let e in t){let r=t[e];if(!at.default.string(r)&&!at.default.number(r)&&!at.default.boolean(r)&&!at.default.null_(r)&&!at.default.undefined(r))throw new TypeError(`The \\`searchParams\\` value '${String(r)}' must be a string, number, boolean or null`)}}function Mrt(t){return at.default.object(t)&&!(\"statusCode\"in t)}var KH=new Qrt.default,Urt=async t=>new Promise((e,r)=>{let s=a=>{r(a)};t.pending||e(),t.once(\"error\",s),t.once(\"ready\",()=>{t.off(\"error\",s),e()})}),_rt=new Set([300,301,302,303,304,307,308]),Hrt=[\"context\",\"body\",\"json\",\"form\"];Ln.setNonEnumerableProperties=(t,e)=>{let r={};for(let s of t)if(s)for(let a of Hrt)a in s&&(r[a]={writable:!0,configurable:!0,enumerable:!1,value:s[a]});Object.defineProperties(e,r)};var us=class extends Error{constructor(e,r,s){var a;if(super(e),Error.captureStackTrace(this,this.constructor),this.name=\"RequestError\",this.code=r.code,s instanceof oR?(Object.defineProperty(this,\"request\",{enumerable:!1,value:s}),Object.defineProperty(this,\"response\",{enumerable:!1,value:s[$Q]}),Object.defineProperty(this,\"options\",{enumerable:!1,value:s.options})):Object.defineProperty(this,\"options\",{enumerable:!1,value:s}),this.timings=(a=this.request)===null||a===void 0?void 0:a.timings,at.default.string(r.stack)&&at.default.string(this.stack)){let n=this.stack.indexOf(this.message)+this.message.length,c=this.stack.slice(n).split(`\n`).reverse(),f=r.stack.slice(r.stack.indexOf(r.message)+r.message.length).split(`\n`).reverse();for(;f.length!==0&&f[0]===c[0];)c.shift();this.stack=`${this.stack.slice(0,n)}${c.reverse().join(`\n`)}${f.reverse().join(`\n`)}`}}};Ln.RequestError=us;var eR=class extends us{constructor(e){super(`Redirected ${e.options.maxRedirects} times. Aborting.`,{},e),this.name=\"MaxRedirectsError\"}};Ln.MaxRedirectsError=eR;var tR=class extends us{constructor(e){super(`Response code ${e.statusCode} (${e.statusMessage})`,{},e.request),this.name=\"HTTPError\"}};Ln.HTTPError=tR;var rR=class extends us{constructor(e,r){super(e.message,e,r),this.name=\"CacheError\"}};Ln.CacheError=rR;var nR=class extends us{constructor(e,r){super(e.message,e,r),this.name=\"UploadError\"}};Ln.UploadError=nR;var iR=class extends us{constructor(e,r,s){super(e.message,e,s),this.name=\"TimeoutError\",this.event=e.event,this.timings=r}};Ln.TimeoutError=iR;var tv=class extends us{constructor(e,r){super(e.message,e,r),this.name=\"ReadError\"}};Ln.ReadError=tv;var sR=class extends us{constructor(e){super(`Unsupported protocol \"${e.url.protocol}\"`,{},e),this.name=\"UnsupportedProtocolError\"}};Ln.UnsupportedProtocolError=sR;var jrt=[\"socket\",\"connect\",\"continue\",\"information\",\"upgrade\",\"timeout\"],oR=class extends hAe.Duplex{constructor(e,r={},s){super({autoDestroy:!1,highWaterMark:0}),this[yI]=0,this[II]=0,this.requestInitialized=!1,this[ZQ]=new Set,this.redirects=[],this[CI]=!1,this[XQ]=!1,this[ev]=[],this.retryCount=0,this._progressCallbacks=[];let a=()=>this._unlockWrite(),n=()=>this._lockWrite();this.on(\"pipe\",h=>{h.prependListener(\"data\",a),h.on(\"data\",n),h.prependListener(\"end\",a),h.on(\"end\",n)}),this.on(\"unpipe\",h=>{h.off(\"data\",a),h.off(\"data\",n),h.off(\"end\",a),h.off(\"end\",n)}),this.on(\"pipe\",h=>{h instanceof YH.IncomingMessage&&(this.options.headers={...h.headers,...this.options.headers})});let{json:c,body:f,form:p}=r;if((c||f||p)&&this._lockWrite(),Ln.kIsNormalizedAlready in r)this.options=r;else try{this.options=this.constructor.normalizeArguments(e,r,s)}catch(h){at.default.nodeStream(r.body)&&r.body.destroy(),this.destroy(h);return}(async()=>{var h;try{this.options.body instanceof Crt.ReadStream&&await Urt(this.options.body);let{url:E}=this.options;if(!E)throw new TypeError(\"Missing `url` property\");if(this.requestUrl=E.toString(),decodeURI(this.requestUrl),await this._finalizeBody(),await this._makeRequest(),this.destroyed){(h=this[po])===null||h===void 0||h.destroy();return}for(let C of this[ev])C();this[ev].length=0,this.requestInitialized=!0}catch(E){if(E instanceof us){this._beforeError(E);return}this.destroyed||this.destroy(E)}})()}static normalizeArguments(e,r,s){var a,n,c,f,p;let h=r;if(at.default.object(e)&&!at.default.urlInstance(e))r={...s,...e,...r};else{if(e&&r&&r.url!==void 0)throw new TypeError(\"The `url` option is mutually exclusive with the `input` argument\");r={...s,...r},e!==void 0&&(r.url=e),at.default.urlInstance(r.url)&&(r.url=new w0.URL(r.url.toString()))}if(r.cache===!1&&(r.cache=void 0),r.dnsCache===!1&&(r.dnsCache=void 0),at.assert.any([at.default.string,at.default.undefined],r.method),at.assert.any([at.default.object,at.default.undefined],r.headers),at.assert.any([at.default.string,at.default.urlInstance,at.default.undefined],r.prefixUrl),at.assert.any([at.default.object,at.default.undefined],r.cookieJar),at.assert.any([at.default.object,at.default.string,at.default.undefined],r.searchParams),at.assert.any([at.default.object,at.default.string,at.default.undefined],r.cache),at.assert.any([at.default.object,at.default.number,at.default.undefined],r.timeout),at.assert.any([at.default.object,at.default.undefined],r.context),at.assert.any([at.default.object,at.default.undefined],r.hooks),at.assert.any([at.default.boolean,at.default.undefined],r.decompress),at.assert.any([at.default.boolean,at.default.undefined],r.ignoreInvalidCookies),at.assert.any([at.default.boolean,at.default.undefined],r.followRedirect),at.assert.any([at.default.number,at.default.undefined],r.maxRedirects),at.assert.any([at.default.boolean,at.default.undefined],r.throwHttpErrors),at.assert.any([at.default.boolean,at.default.undefined],r.http2),at.assert.any([at.default.boolean,at.default.undefined],r.allowGetBody),at.assert.any([at.default.string,at.default.undefined],r.localAddress),at.assert.any([IAe.isDnsLookupIpVersion,at.default.undefined],r.dnsLookupIpVersion),at.assert.any([at.default.object,at.default.undefined],r.https),at.assert.any([at.default.boolean,at.default.undefined],r.rejectUnauthorized),r.https&&(at.assert.any([at.default.boolean,at.default.undefined],r.https.rejectUnauthorized),at.assert.any([at.default.function_,at.default.undefined],r.https.checkServerIdentity),at.assert.any([at.default.string,at.default.object,at.default.array,at.default.undefined],r.https.certificateAuthority),at.assert.any([at.default.string,at.default.object,at.default.array,at.default.undefined],r.https.key),at.assert.any([at.default.string,at.default.object,at.default.array,at.default.undefined],r.https.certificate),at.assert.any([at.default.string,at.default.undefined],r.https.passphrase),at.assert.any([at.default.string,at.default.buffer,at.default.array,at.default.undefined],r.https.pfx)),at.assert.any([at.default.object,at.default.undefined],r.cacheOptions),at.default.string(r.method)?r.method=r.method.toUpperCase():r.method=\"GET\",r.headers===s?.headers?r.headers={...r.headers}:r.headers=Prt({...s?.headers,...r.headers}),\"slashes\"in r)throw new TypeError(\"The legacy `url.Url` has been deprecated. Use `URL` instead.\");if(\"auth\"in r)throw new TypeError(\"Parameter `auth` is deprecated. Use `username` / `password` instead.\");if(\"searchParams\"in r&&r.searchParams&&r.searchParams!==s?.searchParams){let b;if(at.default.string(r.searchParams)||r.searchParams instanceof w0.URLSearchParams)b=new w0.URLSearchParams(r.searchParams);else{Lrt(r.searchParams),b=new w0.URLSearchParams;for(let I in r.searchParams){let T=r.searchParams[I];T===null?b.append(I,\"\"):T!==void 0&&b.append(I,T)}}(a=s?.searchParams)===null||a===void 0||a.forEach((I,T)=>{b.has(T)||b.append(T,I)}),r.searchParams=b}if(r.username=(n=r.username)!==null&&n!==void 0?n:\"\",r.password=(c=r.password)!==null&&c!==void 0?c:\"\",at.default.undefined(r.prefixUrl)?r.prefixUrl=(f=s?.prefixUrl)!==null&&f!==void 0?f:\"\":(r.prefixUrl=r.prefixUrl.toString(),r.prefixUrl!==\"\"&&!r.prefixUrl.endsWith(\"/\")&&(r.prefixUrl+=\"/\")),at.default.string(r.url)){if(r.url.startsWith(\"/\"))throw new Error(\"`input` must not start with a slash when using `prefixUrl`\");r.url=EAe.default(r.prefixUrl+r.url,r)}else(at.default.undefined(r.url)&&r.prefixUrl!==\"\"||r.protocol)&&(r.url=EAe.default(r.prefixUrl,r));if(r.url){\"port\"in r&&delete r.port;let{prefixUrl:b}=r;Object.defineProperty(r,\"prefixUrl\",{set:T=>{let N=r.url;if(!N.href.startsWith(T))throw new Error(`Cannot change \\`prefixUrl\\` from ${b} to ${T}: ${N.href}`);r.url=new w0.URL(T+N.href.slice(b.length)),b=T},get:()=>b});let{protocol:I}=r.url;if(I===\"unix:\"&&(I=\"http:\",r.url=new w0.URL(`http://unix${r.url.pathname}${r.url.search}`)),r.searchParams&&(r.url.search=r.searchParams.toString()),I!==\"http:\"&&I!==\"https:\")throw new sR(r);r.username===\"\"?r.username=r.url.username:r.url.username=r.username,r.password===\"\"?r.password=r.url.password:r.url.password=r.password}let{cookieJar:E}=r;if(E){let{setCookie:b,getCookieString:I}=E;at.assert.function_(b),at.assert.function_(I),b.length===4&&I.length===0&&(b=pAe.promisify(b.bind(r.cookieJar)),I=pAe.promisify(I.bind(r.cookieJar)),r.cookieJar={setCookie:b,getCookieString:I})}let{cache:C}=r;if(C&&(KH.has(C)||KH.set(C,new dAe((b,I)=>{let T=b[po](b,I);return at.default.promise(T)&&(T.once=(N,U)=>{if(N===\"error\")T.catch(U);else if(N===\"abort\")(async()=>{try{(await T).once(\"abort\",U)}catch{}})();else throw new Error(`Unknown HTTP2 promise event: ${N}`);return T}),T},C))),r.cacheOptions={...r.cacheOptions},r.dnsCache===!0)VH||(VH=new vrt.default),r.dnsCache=VH;else if(!at.default.undefined(r.dnsCache)&&!r.dnsCache.lookup)throw new TypeError(`Parameter \\`dnsCache\\` must be a CacheableLookup instance or a boolean, got ${at.default(r.dnsCache)}`);at.default.number(r.timeout)?r.timeout={request:r.timeout}:s&&r.timeout!==s.timeout?r.timeout={...s.timeout,...r.timeout}:r.timeout={...r.timeout},r.context||(r.context={});let S=r.hooks===s?.hooks;r.hooks={...r.hooks};for(let b of Ln.knownHookEvents)if(b in r.hooks)if(at.default.array(r.hooks[b]))r.hooks[b]=[...r.hooks[b]];else throw new TypeError(`Parameter \\`${b}\\` must be an Array, got ${at.default(r.hooks[b])}`);else r.hooks[b]=[];if(s&&!S)for(let b of Ln.knownHookEvents)s.hooks[b].length>0&&(r.hooks[b]=[...s.hooks[b],...r.hooks[b]]);if(\"family\"in r&&B0.default('\"options.family\" was never documented, please use \"options.dnsLookupIpVersion\"'),s?.https&&(r.https={...s.https,...r.https}),\"rejectUnauthorized\"in r&&B0.default('\"options.rejectUnauthorized\" is now deprecated, please use \"options.https.rejectUnauthorized\"'),\"checkServerIdentity\"in r&&B0.default('\"options.checkServerIdentity\" was never documented, please use \"options.https.checkServerIdentity\"'),\"ca\"in r&&B0.default('\"options.ca\" was never documented, please use \"options.https.certificateAuthority\"'),\"key\"in r&&B0.default('\"options.key\" was never documented, please use \"options.https.key\"'),\"cert\"in r&&B0.default('\"options.cert\" was never documented, please use \"options.https.certificate\"'),\"passphrase\"in r&&B0.default('\"options.passphrase\" was never documented, please use \"options.https.passphrase\"'),\"pfx\"in r&&B0.default('\"options.pfx\" was never documented, please use \"options.https.pfx\"'),\"followRedirects\"in r)throw new TypeError(\"The `followRedirects` option does not exist. Use `followRedirect` instead.\");if(r.agent){for(let b in r.agent)if(b!==\"http\"&&b!==\"https\"&&b!==\"http2\")throw new TypeError(`Expected the \\`options.agent\\` properties to be \\`http\\`, \\`https\\` or \\`http2\\`, got \\`${b}\\``)}return r.maxRedirects=(p=r.maxRedirects)!==null&&p!==void 0?p:0,Ln.setNonEnumerableProperties([s,h],r),Frt.default(r,s)}_lockWrite(){let e=()=>{throw new TypeError(\"The payload has been already provided\")};this.write=e,this.end=e}_unlockWrite(){this.write=super.write,this.end=super.end}async _finalizeBody(){let{options:e}=this,{headers:r}=e,s=!at.default.undefined(e.form),a=!at.default.undefined(e.json),n=!at.default.undefined(e.body),c=s||a||n,f=Ln.withoutBody.has(e.method)&&!(e.method===\"GET\"&&e.allowGetBody);if(this._cannotHaveBody=f,c){if(f)throw new TypeError(`The \\`${e.method}\\` method cannot be used with a body`);if([n,s,a].filter(p=>p).length>1)throw new TypeError(\"The `body`, `json` and `form` options are mutually exclusive\");if(n&&!(e.body instanceof hAe.Readable)&&!at.default.string(e.body)&&!at.default.buffer(e.body)&&!mAe.default(e.body))throw new TypeError(\"The `body` option must be a stream.Readable, string or Buffer\");if(s&&!at.default.object(e.form))throw new TypeError(\"The `form` option must be an Object\");{let p=!at.default.string(r[\"content-type\"]);n?(mAe.default(e.body)&&p&&(r[\"content-type\"]=`multipart/form-data; boundary=${e.body.getBoundary()}`),this[v0]=e.body):s?(p&&(r[\"content-type\"]=\"application/x-www-form-urlencoded\"),this[v0]=new w0.URLSearchParams(e.form).toString()):(p&&(r[\"content-type\"]=\"application/json\"),this[v0]=e.stringifyJson(e.json));let h=await brt.default(this[v0],e.headers);at.default.undefined(r[\"content-length\"])&&at.default.undefined(r[\"transfer-encoding\"])&&!f&&!at.default.undefined(h)&&(r[\"content-length\"]=String(h))}}else f?this._lockWrite():this._unlockWrite();this[EI]=Number(r[\"content-length\"])||void 0}async _onResponseBase(e){let{options:r}=this,{url:s}=r;this[vAe]=e,r.decompress&&(e=Srt(e));let a=e.statusCode,n=e;n.statusMessage=n.statusMessage?n.statusMessage:gAe.STATUS_CODES[a],n.url=r.url.toString(),n.requestUrl=this.requestUrl,n.redirectUrls=this.redirects,n.request=this,n.isFromCache=e.fromCache||!1,n.ip=this.ip,n.retryCount=this.retryCount,this[wAe]=n.isFromCache,this[mI]=Number(e.headers[\"content-length\"])||void 0,this[$Q]=e,e.once(\"end\",()=>{this[mI]=this[yI],this.emit(\"downloadProgress\",this.downloadProgress)}),e.once(\"error\",f=>{e.destroy(),this._beforeError(new tv(f,this))}),e.once(\"aborted\",()=>{this._beforeError(new tv({name:\"Error\",message:\"The server aborted pending request\",code:\"ECONNRESET\"},this))}),this.emit(\"downloadProgress\",this.downloadProgress);let c=e.headers[\"set-cookie\"];if(at.default.object(r.cookieJar)&&c){let f=c.map(async p=>r.cookieJar.setCookie(p,s.toString()));r.ignoreInvalidCookies&&(f=f.map(async p=>p.catch(()=>{})));try{await Promise.all(f)}catch(p){this._beforeError(p);return}}if(r.followRedirect&&e.headers.location&&_rt.has(a)){if(e.resume(),this[po]&&(this[JH](),delete this[po],this[CAe]()),(a===303&&r.method!==\"GET\"&&r.method!==\"HEAD\"||!r.methodRewriting)&&(r.method=\"GET\",\"body\"in r&&delete r.body,\"json\"in r&&delete r.json,\"form\"in r&&delete r.form,this[v0]=void 0,delete r.headers[\"content-length\"]),this.redirects.length>=r.maxRedirects){this._beforeError(new eR(this));return}try{let p=Buffer.from(e.headers.location,\"binary\").toString(),h=new w0.URL(p,s),E=h.toString();decodeURI(E),h.hostname!==s.hostname||h.port!==s.port?(\"host\"in r.headers&&delete r.headers.host,\"cookie\"in r.headers&&delete r.headers.cookie,\"authorization\"in r.headers&&delete r.headers.authorization,(r.username||r.password)&&(r.username=\"\",r.password=\"\")):(h.username=r.username,h.password=r.password),this.redirects.push(E),r.url=h;for(let C of r.hooks.beforeRedirect)await C(r,n);this.emit(\"redirect\",n,r),await this._makeRequest()}catch(p){this._beforeError(p);return}return}if(r.isStream&&r.throwHttpErrors&&!Trt.isResponseOk(n)){this._beforeError(new tR(n));return}e.on(\"readable\",()=>{this[XQ]&&this._read()}),this.on(\"resume\",()=>{e.resume()}),this.on(\"pause\",()=>{e.pause()}),e.once(\"end\",()=>{this.push(null)}),this.emit(\"response\",e);for(let f of this[ZQ])if(!f.headersSent){for(let p in e.headers){let h=r.decompress?p!==\"content-encoding\":!0,E=e.headers[p];h&&f.setHeader(p,E)}f.statusCode=a}}async _onResponse(e){try{await this._onResponseBase(e)}catch(r){this._beforeError(r)}}_onRequest(e){let{options:r}=this,{timeout:s,url:a}=r;Brt.default(e),this[JH]=yAe.default(e,s,a);let n=r.cache?\"cacheableResponse\":\"response\";e.once(n,p=>{this._onResponse(p)}),e.once(\"error\",p=>{var h;e.destroy(),(h=e.res)===null||h===void 0||h.removeAllListeners(\"end\"),p=p instanceof yAe.TimeoutError?new iR(p,this.timings,this):new us(p.message,p,this),this._beforeError(p)}),this[CAe]=xrt.default(e,this,jrt),this[po]=e,this.emit(\"uploadProgress\",this.uploadProgress);let c=this[v0],f=this.redirects.length===0?this:e;at.default.nodeStream(c)?(c.pipe(f),c.once(\"error\",p=>{this._beforeError(new nR(p,this))})):(this._unlockWrite(),at.default.undefined(c)?(this._cannotHaveBody||this._noPipe)&&(f.end(),this._lockWrite()):(this._writeRequest(c,void 0,()=>{}),f.end(),this._lockWrite())),this.emit(\"request\",e)}async _createCacheableRequest(e,r){return new Promise((s,a)=>{Object.assign(r,krt.default(e)),delete r.url;let n,c=KH.get(r.cache)(r,async f=>{f._readableState.autoDestroy=!1,n&&(await n).emit(\"cacheableResponse\",f),s(f)});r.url=e,c.once(\"error\",a),c.once(\"request\",async f=>{n=f,s(n)})})}async _makeRequest(){var e,r,s,a,n;let{options:c}=this,{headers:f}=c;for(let U in f)if(at.default.undefined(f[U]))delete f[U];else if(at.default.null_(f[U]))throw new TypeError(`Use \\`undefined\\` instead of \\`null\\` to delete the \\`${U}\\` header`);if(c.decompress&&at.default.undefined(f[\"accept-encoding\"])&&(f[\"accept-encoding\"]=Ort?\"gzip, deflate, br\":\"gzip, deflate\"),c.cookieJar){let U=await c.cookieJar.getCookieString(c.url.toString());at.default.nonEmptyString(U)&&(c.headers.cookie=U)}for(let U of c.hooks.beforeRequest){let W=await U(c);if(!at.default.undefined(W)){c.request=()=>W;break}}c.body&&this[v0]!==c.body&&(this[v0]=c.body);let{agent:p,request:h,timeout:E,url:C}=c;if(c.dnsCache&&!(\"lookup\"in c)&&(c.lookup=c.dnsCache.lookup),C.hostname===\"unix\"){let U=/(?<socketPath>.+?):(?<path>.+)/.exec(`${C.pathname}${C.search}`);if(U?.groups){let{socketPath:W,path:ee}=U.groups;Object.assign(c,{socketPath:W,path:ee,host:\"\"})}}let S=C.protocol===\"https:\",b;c.http2?b=Drt.auto:b=S?wrt.request:gAe.request;let I=(e=c.request)!==null&&e!==void 0?e:b,T=c.cache?this._createCacheableRequest:I;p&&!c.http2&&(c.agent=p[S?\"https\":\"http\"]),c[po]=I,delete c.request,delete c.timeout;let N=c;if(N.shared=(r=c.cacheOptions)===null||r===void 0?void 0:r.shared,N.cacheHeuristic=(s=c.cacheOptions)===null||s===void 0?void 0:s.cacheHeuristic,N.immutableMinTimeToLive=(a=c.cacheOptions)===null||a===void 0?void 0:a.immutableMinTimeToLive,N.ignoreCargoCult=(n=c.cacheOptions)===null||n===void 0?void 0:n.ignoreCargoCult,c.dnsLookupIpVersion!==void 0)try{N.family=IAe.dnsLookupIpVersionToFamily(c.dnsLookupIpVersion)}catch{throw new Error(\"Invalid `dnsLookupIpVersion` option value\")}c.https&&(\"rejectUnauthorized\"in c.https&&(N.rejectUnauthorized=c.https.rejectUnauthorized),c.https.checkServerIdentity&&(N.checkServerIdentity=c.https.checkServerIdentity),c.https.certificateAuthority&&(N.ca=c.https.certificateAuthority),c.https.certificate&&(N.cert=c.https.certificate),c.https.key&&(N.key=c.https.key),c.https.passphrase&&(N.passphrase=c.https.passphrase),c.https.pfx&&(N.pfx=c.https.pfx));try{let U=await T(C,N);at.default.undefined(U)&&(U=b(C,N)),c.request=h,c.timeout=E,c.agent=p,c.https&&(\"rejectUnauthorized\"in c.https&&delete N.rejectUnauthorized,c.https.checkServerIdentity&&delete N.checkServerIdentity,c.https.certificateAuthority&&delete N.ca,c.https.certificate&&delete N.cert,c.https.key&&delete N.key,c.https.passphrase&&delete N.passphrase,c.https.pfx&&delete N.pfx),Mrt(U)?this._onRequest(U):this.writable?(this.once(\"finish\",()=>{this._onResponse(U)}),this._unlockWrite(),this.end(),this._lockWrite()):this._onResponse(U)}catch(U){throw U instanceof dAe.CacheError?new rR(U,this):new us(U.message,U,this)}}async _error(e){try{for(let r of this.options.hooks.beforeError)e=await r(e)}catch(r){e=new us(r.message,r,this)}this.destroy(e)}_beforeError(e){if(this[CI])return;let{options:r}=this,s=this.retryCount+1;this[CI]=!0,e instanceof us||(e=new us(e.message,e,this));let a=e,{response:n}=a;(async()=>{if(n&&!n.body){n.setEncoding(this._readableState.encoding);try{n.rawBody=await Rrt.default(n),n.body=n.rawBody.toString()}catch{}}if(this.listenerCount(\"retry\")!==0){let c;try{let f;n&&\"retry-after\"in n.headers&&(f=Number(n.headers[\"retry-after\"]),Number.isNaN(f)?(f=Date.parse(n.headers[\"retry-after\"])-Date.now(),f<=0&&(f=1)):f*=1e3),c=await r.retry.calculateDelay({attemptCount:s,retryOptions:r.retry,error:a,retryAfter:f,computedValue:Nrt.default({attemptCount:s,retryOptions:r.retry,error:a,retryAfter:f,computedValue:0})})}catch(f){this._error(new us(f.message,f,this));return}if(c){let f=async()=>{try{for(let p of this.options.hooks.beforeRetry)await p(this.options,a,s)}catch(p){this._error(new us(p.message,e,this));return}this.destroyed||(this.destroy(),this.emit(\"retry\",s,e))};this[SAe]=setTimeout(f,c);return}}this._error(a)})()}_read(){this[XQ]=!0;let e=this[$Q];if(e&&!this[CI]){e.readableLength&&(this[XQ]=!1);let r;for(;(r=e.read())!==null;){this[yI]+=r.length,this[BAe]=!0;let s=this.downloadProgress;s.percent<1&&this.emit(\"downloadProgress\",s),this.push(r)}}}_write(e,r,s){let a=()=>{this._writeRequest(e,r,s)};this.requestInitialized?a():this[ev].push(a)}_writeRequest(e,r,s){this[po].destroyed||(this._progressCallbacks.push(()=>{this[II]+=Buffer.byteLength(e,r);let a=this.uploadProgress;a.percent<1&&this.emit(\"uploadProgress\",a)}),this[po].write(e,r,a=>{!a&&this._progressCallbacks.length>0&&this._progressCallbacks.shift()(),s(a)}))}_final(e){let r=()=>{for(;this._progressCallbacks.length!==0;)this._progressCallbacks.shift()();if(!(po in this)){e();return}if(this[po].destroyed){e();return}this[po].end(s=>{s||(this[EI]=this[II],this.emit(\"uploadProgress\",this.uploadProgress),this[po].emit(\"upload-complete\")),e(s)})};this.requestInitialized?r():this[ev].push(r)}_destroy(e,r){var s;this[CI]=!0,clearTimeout(this[SAe]),po in this&&(this[JH](),!((s=this[$Q])===null||s===void 0)&&s.complete||this[po].destroy()),e!==null&&!at.default.undefined(e)&&!(e instanceof us)&&(e=new us(e.message,e,this)),r(e)}get _isAboutToError(){return this[CI]}get ip(){var e;return(e=this.socket)===null||e===void 0?void 0:e.remoteAddress}get aborted(){var e,r,s;return((r=(e=this[po])===null||e===void 0?void 0:e.destroyed)!==null&&r!==void 0?r:this.destroyed)&&!(!((s=this[vAe])===null||s===void 0)&&s.complete)}get socket(){var e,r;return(r=(e=this[po])===null||e===void 0?void 0:e.socket)!==null&&r!==void 0?r:void 0}get downloadProgress(){let e;return this[mI]?e=this[yI]/this[mI]:this[mI]===this[yI]?e=1:e=0,{percent:e,transferred:this[yI],total:this[mI]}}get uploadProgress(){let e;return this[EI]?e=this[II]/this[EI]:this[EI]===this[II]?e=1:e=0,{percent:e,transferred:this[II],total:this[EI]}}get timings(){var e;return(e=this[po])===null||e===void 0?void 0:e.timings}get isFromCache(){return this[wAe]}pipe(e,r){if(this[BAe])throw new Error(\"Failed to pipe. The response has been emitted already.\");return e instanceof YH.ServerResponse&&this[ZQ].add(e),super.pipe(e,r)}unpipe(e){return e instanceof YH.ServerResponse&&this[ZQ].delete(e),super.unpipe(e),this}};Ln.default=oR});var nv=_(qu=>{\"use strict\";var Grt=qu&&qu.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),qrt=qu&&qu.__exportStar||function(t,e){for(var r in t)r!==\"default\"&&!Object.prototype.hasOwnProperty.call(e,r)&&Grt(e,t,r)};Object.defineProperty(qu,\"__esModule\",{value:!0});qu.CancelError=qu.ParseError=void 0;var DAe=rv(),zH=class extends DAe.RequestError{constructor(e,r){let{options:s}=r.request;super(`${e.message} in \"${s.url.toString()}\"`,e,r.request),this.name=\"ParseError\"}};qu.ParseError=zH;var ZH=class extends DAe.RequestError{constructor(e){super(\"Promise was canceled\",{},e),this.name=\"CancelError\"}get isCanceled(){return!0}};qu.CancelError=ZH;qrt(rv(),qu)});var bAe=_(XH=>{\"use strict\";Object.defineProperty(XH,\"__esModule\",{value:!0});var PAe=nv(),Wrt=(t,e,r,s)=>{let{rawBody:a}=t;try{if(e===\"text\")return a.toString(s);if(e===\"json\")return a.length===0?\"\":r(a.toString());if(e===\"buffer\")return a;throw new PAe.ParseError({message:`Unknown body type '${e}'`,name:\"Error\"},t)}catch(n){throw new PAe.ParseError(n,t)}};XH.default=Wrt});var $H=_(S0=>{\"use strict\";var Yrt=S0&&S0.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),Vrt=S0&&S0.__exportStar||function(t,e){for(var r in t)r!==\"default\"&&!Object.prototype.hasOwnProperty.call(e,r)&&Yrt(e,t,r)};Object.defineProperty(S0,\"__esModule\",{value:!0});var Jrt=Ie(\"events\"),Krt=Np(),zrt=Pue(),aR=nv(),xAe=bAe(),kAe=rv(),Zrt=NH(),Xrt=jH(),QAe=GH(),$rt=[\"request\",\"response\",\"redirect\",\"uploadProgress\",\"downloadProgress\"];function RAe(t){let e,r,s=new Jrt.EventEmitter,a=new zrt((c,f,p)=>{let h=E=>{let C=new kAe.default(void 0,t);C.retryCount=E,C._noPipe=!0,p(()=>C.destroy()),p.shouldReject=!1,p(()=>f(new aR.CancelError(C))),e=C,C.once(\"response\",async I=>{var T;if(I.retryCount=E,I.request.aborted)return;let N;try{N=await Xrt.default(C),I.rawBody=N}catch{return}if(C._isAboutToError)return;let U=((T=I.headers[\"content-encoding\"])!==null&&T!==void 0?T:\"\").toLowerCase(),W=[\"gzip\",\"deflate\",\"br\"].includes(U),{options:ee}=C;if(W&&!ee.decompress)I.body=N;else try{I.body=xAe.default(I,ee.responseType,ee.parseJson,ee.encoding)}catch(ie){if(I.body=N.toString(),QAe.isResponseOk(I)){C._beforeError(ie);return}}try{for(let[ie,ue]of ee.hooks.afterResponse.entries())I=await ue(I,async le=>{let me=kAe.default.normalizeArguments(void 0,{...le,retry:{calculateDelay:()=>0},throwHttpErrors:!1,resolveBodyOnly:!1},ee);me.hooks.afterResponse=me.hooks.afterResponse.slice(0,ie);for(let Be of me.hooks.beforeRetry)await Be(me);let pe=RAe(me);return p(()=>{pe.catch(()=>{}),pe.cancel()}),pe})}catch(ie){C._beforeError(new aR.RequestError(ie.message,ie,C));return}if(!QAe.isResponseOk(I)){C._beforeError(new aR.HTTPError(I));return}r=I,c(C.options.resolveBodyOnly?I.body:I)});let S=I=>{if(a.isCanceled)return;let{options:T}=C;if(I instanceof aR.HTTPError&&!T.throwHttpErrors){let{response:N}=I;c(C.options.resolveBodyOnly?N.body:N);return}f(I)};C.once(\"error\",S);let b=C.options.body;C.once(\"retry\",(I,T)=>{var N,U;if(b===((N=T.request)===null||N===void 0?void 0:N.options.body)&&Krt.default.nodeStream((U=T.request)===null||U===void 0?void 0:U.options.body)){S(T);return}h(I)}),Zrt.default(C,s,$rt)};h(0)});a.on=(c,f)=>(s.on(c,f),a);let n=c=>{let f=(async()=>{await a;let{options:p}=r.request;return xAe.default(r,c,p.parseJson,p.encoding)})();return Object.defineProperties(f,Object.getOwnPropertyDescriptors(a)),f};return a.json=()=>{let{headers:c}=e.options;return!e.writableFinished&&c.accept===void 0&&(c.accept=\"application/json\"),n(\"json\")},a.buffer=()=>n(\"buffer\"),a.text=()=>n(\"text\"),a}S0.default=RAe;Vrt(nv(),S0)});var TAe=_(ej=>{\"use strict\";Object.defineProperty(ej,\"__esModule\",{value:!0});var ent=nv();function tnt(t,...e){let r=(async()=>{if(t instanceof ent.RequestError)try{for(let a of e)if(a)for(let n of a)t=await n(t)}catch(a){t=a}throw t})(),s=()=>r;return r.json=s,r.text=s,r.buffer=s,r.on=s,r}ej.default=tnt});var OAe=_(tj=>{\"use strict\";Object.defineProperty(tj,\"__esModule\",{value:!0});var FAe=Np();function NAe(t){for(let e of Object.values(t))(FAe.default.plainObject(e)||FAe.default.array(e))&&NAe(e);return Object.freeze(t)}tj.default=NAe});var MAe=_(LAe=>{\"use strict\";Object.defineProperty(LAe,\"__esModule\",{value:!0})});var rj=_(Nc=>{\"use strict\";var rnt=Nc&&Nc.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),nnt=Nc&&Nc.__exportStar||function(t,e){for(var r in t)r!==\"default\"&&!Object.prototype.hasOwnProperty.call(e,r)&&rnt(e,t,r)};Object.defineProperty(Nc,\"__esModule\",{value:!0});Nc.defaultHandler=void 0;var UAe=Np(),Fc=$H(),int=TAe(),cR=rv(),snt=OAe(),ont={RequestError:Fc.RequestError,CacheError:Fc.CacheError,ReadError:Fc.ReadError,HTTPError:Fc.HTTPError,MaxRedirectsError:Fc.MaxRedirectsError,TimeoutError:Fc.TimeoutError,ParseError:Fc.ParseError,CancelError:Fc.CancelError,UnsupportedProtocolError:Fc.UnsupportedProtocolError,UploadError:Fc.UploadError},ant=async t=>new Promise(e=>{setTimeout(e,t)}),{normalizeArguments:lR}=cR.default,_Ae=(...t)=>{let e;for(let r of t)e=lR(void 0,r,e);return e},lnt=t=>t.isStream?new cR.default(void 0,t):Fc.default(t),cnt=t=>\"defaults\"in t&&\"options\"in t.defaults,unt=[\"get\",\"post\",\"put\",\"patch\",\"head\",\"delete\"];Nc.defaultHandler=(t,e)=>e(t);var HAe=(t,e)=>{if(t)for(let r of t)r(e)},jAe=t=>{t._rawHandlers=t.handlers,t.handlers=t.handlers.map(s=>(a,n)=>{let c,f=s(a,p=>(c=n(p),c));if(f!==c&&!a.isStream&&c){let p=f,{then:h,catch:E,finally:C}=p;Object.setPrototypeOf(p,Object.getPrototypeOf(c)),Object.defineProperties(p,Object.getOwnPropertyDescriptors(c)),p.then=h,p.catch=E,p.finally=C}return f});let e=(s,a={},n)=>{var c,f;let p=0,h=E=>t.handlers[p++](E,p===t.handlers.length?lnt:h);if(UAe.default.plainObject(s)){let E={...s,...a};cR.setNonEnumerableProperties([s,a],E),a=E,s=void 0}try{let E;try{HAe(t.options.hooks.init,a),HAe((c=a.hooks)===null||c===void 0?void 0:c.init,a)}catch(S){E=S}let C=lR(s,a,n??t.options);if(C[cR.kIsNormalizedAlready]=!0,E)throw new Fc.RequestError(E.message,E,C);return h(C)}catch(E){if(a.isStream)throw E;return int.default(E,t.options.hooks.beforeError,(f=a.hooks)===null||f===void 0?void 0:f.beforeError)}};e.extend=(...s)=>{let a=[t.options],n=[...t._rawHandlers],c;for(let f of s)cnt(f)?(a.push(f.defaults.options),n.push(...f.defaults._rawHandlers),c=f.defaults.mutableDefaults):(a.push(f),\"handlers\"in f&&n.push(...f.handlers),c=f.mutableDefaults);return n=n.filter(f=>f!==Nc.defaultHandler),n.length===0&&n.push(Nc.defaultHandler),jAe({options:_Ae(...a),handlers:n,mutableDefaults:!!c})};let r=async function*(s,a){let n=lR(s,a,t.options);n.resolveBodyOnly=!1;let c=n.pagination;if(!UAe.default.object(c))throw new TypeError(\"`options.pagination` must be implemented\");let f=[],{countLimit:p}=c,h=0;for(;h<c.requestLimit;){h!==0&&await ant(c.backoff);let E=await e(void 0,void 0,n),C=await c.transform(E),S=[];for(let I of C)if(c.filter(I,f,S)&&(!c.shouldContinue(I,f,S)||(yield I,c.stackAllItems&&f.push(I),S.push(I),--p<=0)))return;let b=c.paginate(E,f,S);if(b===!1)return;b===E.request.options?n=E.request.options:b!==void 0&&(n=lR(void 0,b,n)),h++}};e.paginate=r,e.paginate.all=async(s,a)=>{let n=[];for await(let c of r(s,a))n.push(c);return n},e.paginate.each=r,e.stream=(s,a)=>e(s,{...a,isStream:!0});for(let s of unt)e[s]=(a,n)=>e(a,{...n,method:s}),e.stream[s]=(a,n)=>e(a,{...n,method:s,isStream:!0});return Object.assign(e,ont),Object.defineProperty(e,\"defaults\",{value:t.mutableDefaults?t:snt.default(t),writable:t.mutableDefaults,configurable:t.mutableDefaults,enumerable:!0}),e.mergeOptions=_Ae,e};Nc.default=jAe;nnt(MAe(),Nc)});var WAe=_((Op,uR)=>{\"use strict\";var fnt=Op&&Op.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),GAe=Op&&Op.__exportStar||function(t,e){for(var r in t)r!==\"default\"&&!Object.prototype.hasOwnProperty.call(e,r)&&fnt(e,t,r)};Object.defineProperty(Op,\"__esModule\",{value:!0});var Ant=Ie(\"url\"),qAe=rj(),pnt={options:{method:\"GET\",retry:{limit:2,methods:[\"GET\",\"PUT\",\"HEAD\",\"DELETE\",\"OPTIONS\",\"TRACE\"],statusCodes:[408,413,429,500,502,503,504,521,522,524],errorCodes:[\"ETIMEDOUT\",\"ECONNRESET\",\"EADDRINUSE\",\"ECONNREFUSED\",\"EPIPE\",\"ENOTFOUND\",\"ENETUNREACH\",\"EAI_AGAIN\"],maxRetryAfter:void 0,calculateDelay:({computedValue:t})=>t},timeout:{},headers:{\"user-agent\":\"got (https://github.com/sindresorhus/got)\"},hooks:{init:[],beforeRequest:[],beforeRedirect:[],beforeRetry:[],beforeError:[],afterResponse:[]},cache:void 0,dnsCache:void 0,decompress:!0,throwHttpErrors:!0,followRedirect:!0,isStream:!1,responseType:\"text\",resolveBodyOnly:!1,maxRedirects:10,prefixUrl:\"\",methodRewriting:!0,ignoreInvalidCookies:!1,context:{},http2:!1,allowGetBody:!1,https:void 0,pagination:{transform:t=>t.request.options.responseType===\"json\"?t.body:JSON.parse(t.body),paginate:t=>{if(!Reflect.has(t.headers,\"link\"))return!1;let e=t.headers.link.split(\",\"),r;for(let s of e){let a=s.split(\";\");if(a[1].includes(\"next\")){r=a[0].trimStart().trim(),r=r.slice(1,-1);break}}return r?{url:new Ant.URL(r)}:!1},filter:()=>!0,shouldContinue:()=>!0,countLimit:1/0,backoff:0,requestLimit:1e4,stackAllItems:!0},parseJson:t=>JSON.parse(t),stringifyJson:t=>JSON.stringify(t),cacheOptions:{}},handlers:[qAe.defaultHandler],mutableDefaults:!1},nj=qAe.default(pnt);Op.default=nj;uR.exports=nj;uR.exports.default=nj;uR.exports.__esModule=!0;GAe(rj(),Op);GAe($H(),Op)});var ln={};Vt(ln,{Method:()=>ZAe,del:()=>ynt,get:()=>oj,getNetworkSettings:()=>zAe,post:()=>aj,put:()=>mnt,request:()=>iv});async function ij(t){return Yl(VAe,t,()=>ce.readFilePromise(t).then(e=>(VAe.set(t,e),e)))}function dnt({statusCode:t,statusMessage:e},r){let s=Ht(r,t,ht.NUMBER),a=`https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/${t}`;return KE(r,`${s}${e?` (${e})`:\"\"}`,a)}async function fR(t,{configuration:e,customErrorMessage:r}){try{return await t}catch(s){if(s.name!==\"HTTPError\")throw s;let a=r?.(s,e)??s.response.body?.error;a==null&&(s.message.startsWith(\"Response code\")?a=\"The remote server failed to provide the requested resource\":a=s.message),s.code===\"ETIMEDOUT\"&&s.event===\"socket\"&&(a+=`(can be increased via ${Ht(e,\"httpTimeout\",ht.SETTING)})`);let n=new jt(35,a,c=>{s.response&&c.reportError(35,`  ${Kf(e,{label:\"Response Code\",value:_u(ht.NO_HINT,dnt(s.response,e))})}`),s.request&&(c.reportError(35,`  ${Kf(e,{label:\"Request Method\",value:_u(ht.NO_HINT,s.request.options.method)})}`),c.reportError(35,`  ${Kf(e,{label:\"Request URL\",value:_u(ht.URL,s.request.requestUrl)})}`)),s.request.redirects.length>0&&c.reportError(35,`  ${Kf(e,{label:\"Request Redirects\",value:_u(ht.NO_HINT,z4(e,s.request.redirects,ht.URL))})}`),s.request.retryCount===s.request.options.retry.limit&&c.reportError(35,`  ${Kf(e,{label:\"Request Retry Count\",value:_u(ht.NO_HINT,`${Ht(e,s.request.retryCount,ht.NUMBER)} (can be increased via ${Ht(e,\"httpRetry\",ht.SETTING)})`)})}`)});throw n.originalError=s,n}}function zAe(t,e){let r=[...e.configuration.get(\"networkSettings\")].sort(([c],[f])=>f.length-c.length),s={enableNetwork:void 0,httpsCaFilePath:void 0,httpProxy:void 0,httpsProxy:void 0,httpsKeyFilePath:void 0,httpsCertFilePath:void 0},a=Object.keys(s),n=typeof t==\"string\"?new URL(t):t;for(let[c,f]of r)if(sj.default.isMatch(n.hostname,c))for(let p of a){let h=f.get(p);h!==null&&typeof s[p]>\"u\"&&(s[p]=h)}for(let c of a)typeof s[c]>\"u\"&&(s[c]=e.configuration.get(c));return s}async function iv(t,e,{configuration:r,headers:s,jsonRequest:a,jsonResponse:n,method:c=\"GET\",wrapNetworkRequest:f}){let p={target:t,body:e,configuration:r,headers:s,jsonRequest:a,jsonResponse:n,method:c},h=async()=>await Ent(t,e,p),E=typeof f<\"u\"?await f(h,p):h;return await(await r.reduceHook(S=>S.wrapNetworkRequest,E,p))()}async function oj(t,{configuration:e,jsonResponse:r,customErrorMessage:s,wrapNetworkRequest:a,...n}){let c=()=>fR(iv(t,null,{configuration:e,wrapNetworkRequest:a,...n}),{configuration:e,customErrorMessage:s}).then(p=>p.body),f=await(typeof a<\"u\"?c():Yl(YAe,t,()=>c().then(p=>(YAe.set(t,p),p))));return r?JSON.parse(f.toString()):f}async function mnt(t,e,{customErrorMessage:r,...s}){return(await fR(iv(t,e,{...s,method:\"PUT\"}),{customErrorMessage:r,configuration:s.configuration})).body}async function aj(t,e,{customErrorMessage:r,...s}){return(await fR(iv(t,e,{...s,method:\"POST\"}),{customErrorMessage:r,configuration:s.configuration})).body}async function ynt(t,{customErrorMessage:e,...r}){return(await fR(iv(t,null,{...r,method:\"DELETE\"}),{customErrorMessage:e,configuration:r.configuration})).body}async function Ent(t,e,{configuration:r,headers:s,jsonRequest:a,jsonResponse:n,method:c=\"GET\"}){let f=typeof t==\"string\"?new URL(t):t,p=zAe(f,{configuration:r});if(p.enableNetwork===!1)throw new jt(80,`Request to '${f.href}' has been blocked because of your configuration settings`);if(f.protocol===\"http:\"&&!sj.default.isMatch(f.hostname,r.get(\"unsafeHttpWhitelist\")))throw new jt(81,`Unsafe http requests must be explicitly whitelisted in your configuration (${f.hostname})`);let h={headers:s,method:c};h.responseType=n?\"json\":\"buffer\",e!==null&&(Buffer.isBuffer(e)||!a&&typeof e==\"string\"?h.body=e:h.json=e);let E=r.get(\"httpTimeout\"),C=r.get(\"httpRetry\"),S=r.get(\"enableStrictSsl\"),b=p.httpsCaFilePath,I=p.httpsCertFilePath,T=p.httpsKeyFilePath,{default:N}=await Promise.resolve().then(()=>ut(WAe())),U=b?await ij(b):void 0,W=I?await ij(I):void 0,ee=T?await ij(T):void 0,ie={rejectUnauthorized:S,ca:U,cert:W,key:ee},ue={http:p.httpProxy?new Iue({proxy:p.httpProxy,proxyRequestOptions:ie}):hnt,https:p.httpsProxy?new Cue({proxy:p.httpsProxy,proxyRequestOptions:ie}):gnt},le=N.extend({timeout:{socket:E},retry:C,agent:ue,https:{rejectUnauthorized:S,certificateAuthority:U,certificate:W,key:ee},...h});return r.getLimit(\"networkConcurrency\")(()=>le(f))}var JAe,KAe,sj,YAe,VAe,hnt,gnt,ZAe,AR=Ze(()=>{Dt();wue();JAe=Ie(\"https\"),KAe=Ie(\"http\"),sj=ut(Go());Rc();xc();bc();YAe=new Map,VAe=new Map,hnt=new KAe.Agent({keepAlive:!0}),gnt=new JAe.Agent({keepAlive:!0});ZAe=(a=>(a.GET=\"GET\",a.PUT=\"PUT\",a.POST=\"POST\",a.DELETE=\"DELETE\",a))(ZAe||{})});var fs={};Vt(fs,{availableParallelism:()=>cj,getArchitecture:()=>sv,getArchitectureName:()=>vnt,getArchitectureSet:()=>lj,getCaller:()=>bnt,major:()=>Int,openUrl:()=>Cnt});function Bnt(){if(process.platform!==\"linux\")return null;let t;try{t=ce.readFileSync(wnt)}catch{}if(typeof t<\"u\"){if(t&&(t.includes(\"GLIBC\")||t.includes(\"GNU libc\")||t.includes(\"GNU C Library\")))return\"glibc\";if(t&&t.includes(\"musl\"))return\"musl\"}let r=(process.report?.getReport()??{}).sharedObjects??[],s=/\\/(?:(ld-linux-|[^/]+-linux-gnu\\/)|(libc.musl-|ld-musl-))/;return p0(r,a=>{let n=a.match(s);if(!n)return p0.skip;if(n[1])return\"glibc\";if(n[2])return\"musl\";throw new Error(\"Assertion failed: Expected the libc variant to have been detected\")})??null}function sv(){return $Ae=$Ae??{os:(process.env.YARN_IS_TEST_ENV?process.env.YARN_OS_OVERRIDE:void 0)??process.platform,cpu:(process.env.YARN_IS_TEST_ENV?process.env.YARN_CPU_OVERRIDE:void 0)??process.arch,libc:(process.env.YARN_IS_TEST_ENV?process.env.YARN_LIBC_OVERRIDE:void 0)??Bnt()}}function vnt(t=sv()){return t.libc?`${t.os}-${t.cpu}-${t.libc}`:`${t.os}-${t.cpu}`}function lj(){let t=sv();return epe=epe??{os:[t.os],cpu:[t.cpu],libc:t.libc?[t.libc]:[]}}function Pnt(t){let e=Snt.exec(t);if(!e)return null;let r=e[2]&&e[2].indexOf(\"native\")===0,s=e[2]&&e[2].indexOf(\"eval\")===0,a=Dnt.exec(e[2]);return s&&a!=null&&(e[2]=a[1],e[3]=a[2],e[4]=a[3]),{file:r?null:e[2],methodName:e[1]||\"<unknown>\",arguments:r?[e[2]]:[],line:e[3]?+e[3]:null,column:e[4]?+e[4]:null}}function bnt(){let e=new Error().stack.split(`\n`)[3];return Pnt(e)}function cj(){return typeof pR.default.availableParallelism<\"u\"?pR.default.availableParallelism():Math.max(1,pR.default.cpus().length)}var pR,Int,XAe,Cnt,wnt,$Ae,epe,Snt,Dnt,hR=Ze(()=>{Dt();pR=ut(Ie(\"os\"));gR();bc();Int=Number(process.versions.node.split(\".\")[0]),XAe=new Map([[\"darwin\",\"open\"],[\"linux\",\"xdg-open\"],[\"win32\",\"explorer.exe\"]]).get(process.platform),Cnt=typeof XAe<\"u\"?async t=>{try{return await uj(XAe,[t],{cwd:J.cwd()}),!0}catch{return!1}}:void 0,wnt=\"/usr/bin/ldd\";Snt=/^\\s*at (.*?) ?\\(((?:file|https?|blob|chrome-extension|native|eval|webpack|<anonymous>|\\/|[a-z]:\\\\|\\\\\\\\).*?)(?::(\\d+))?(?::(\\d+))?\\)?\\s*$/i,Dnt=/\\((\\S*)(?::(\\d+))(?::(\\d+))\\)/});function gj(t,e,r,s,a){let n=YB(r);if(s.isArray||s.type===\"ANY\"&&Array.isArray(n))return Array.isArray(n)?n.map((c,f)=>fj(t,`${e}[${f}]`,c,s,a)):String(n).split(/,/).map(c=>fj(t,e,c,s,a));if(Array.isArray(n))throw new Error(`Non-array configuration settings \"${e}\" cannot be an array`);return fj(t,e,r,s,a)}function fj(t,e,r,s,a){let n=YB(r);switch(s.type){case\"ANY\":return FQ(n);case\"SHAPE\":return Rnt(t,e,r,s,a);case\"MAP\":return Tnt(t,e,r,s,a)}if(n===null&&!s.isNullable&&s.default!==null)throw new Error(`Non-nullable configuration settings \"${e}\" cannot be set to null`);if(s.values?.includes(n))return n;let f=(()=>{if(s.type===\"BOOLEAN\"&&typeof n!=\"string\")return kB(n);if(typeof n!=\"string\")throw new Error(`Expected configuration setting \"${e}\" to be a string, got ${typeof n}`);let p=Vk(n,{env:t.env});switch(s.type){case\"ABSOLUTE_PATH\":{let h=a,E=U8(r);return E&&E[0]!==\"<\"&&(h=J.dirname(E)),J.resolve(h,fe.toPortablePath(p))}case\"LOCATOR_LOOSE\":return Qp(p,!1);case\"NUMBER\":return parseInt(p);case\"LOCATOR\":return Qp(p);case\"BOOLEAN\":return kB(p);default:return p}})();if(s.values&&!s.values.includes(f))throw new Error(`Invalid value, expected one of ${s.values.join(\", \")}`);return f}function Rnt(t,e,r,s,a){let n=YB(r);if(typeof n!=\"object\"||Array.isArray(n))throw new nt(`Object configuration settings \"${e}\" must be an object`);let c=dj(t,s,{ignoreArrays:!0});if(n===null)return c;for(let[f,p]of Object.entries(n)){let h=`${e}.${f}`;if(!s.properties[f])throw new nt(`Unrecognized configuration settings found: ${e}.${f} - run \"yarn config\" to see the list of settings supported in Yarn`);c.set(f,gj(t,h,p,s.properties[f],a))}return c}function Tnt(t,e,r,s,a){let n=YB(r),c=new Map;if(typeof n!=\"object\"||Array.isArray(n))throw new nt(`Map configuration settings \"${e}\" must be an object`);if(n===null)return c;for(let[f,p]of Object.entries(n)){let h=s.normalizeKeys?s.normalizeKeys(f):f,E=`${e}['${h}']`,C=s.valueDefinition;c.set(h,gj(t,E,p,C,a))}return c}function dj(t,e,{ignoreArrays:r=!1}={}){switch(e.type){case\"SHAPE\":{if(e.isArray&&!r)return[];let s=new Map;for(let[a,n]of Object.entries(e.properties))s.set(a,dj(t,n));return s}case\"MAP\":return e.isArray&&!r?[]:new Map;case\"ABSOLUTE_PATH\":return e.default===null?null:t.projectCwd===null?Array.isArray(e.default)?e.default.map(s=>J.normalize(s)):J.isAbsolute(e.default)?J.normalize(e.default):e.isNullable?null:void 0:Array.isArray(e.default)?e.default.map(s=>J.resolve(t.projectCwd,s)):J.resolve(t.projectCwd,e.default);default:return e.default}}function mR(t,e,r){if(e.type===\"SECRET\"&&typeof t==\"string\"&&r.hideSecrets)return Qnt;if(e.type===\"ABSOLUTE_PATH\"&&typeof t==\"string\"&&r.getNativePaths)return fe.fromPortablePath(t);if(e.isArray&&Array.isArray(t)){let s=[];for(let a of t)s.push(mR(a,e,r));return s}if(e.type===\"MAP\"&&t instanceof Map){if(t.size===0)return;let s=new Map;for(let[a,n]of t.entries()){let c=mR(n,e.valueDefinition,r);typeof c<\"u\"&&s.set(a,c)}return s}if(e.type===\"SHAPE\"&&t instanceof Map){if(t.size===0)return;let s=new Map;for(let[a,n]of t.entries()){let c=e.properties[a],f=mR(n,c,r);typeof f<\"u\"&&s.set(a,f)}return s}return t}function Fnt(){let t={};for(let[e,r]of Object.entries(process.env))e=e.toLowerCase(),e.startsWith(yR)&&(e=(0,rpe.default)(e.slice(yR.length)),t[e]=r);return t}function pj(){let t=`${yR}rc_filename`;for(let[e,r]of Object.entries(process.env))if(e.toLowerCase()===t&&typeof r==\"string\")return r;return hj}async function tpe(t){try{return await ce.readFilePromise(t)}catch{return Buffer.of()}}async function Nnt(t,e){return Buffer.compare(...await Promise.all([tpe(t),tpe(e)]))===0}async function Ont(t,e){let[r,s]=await Promise.all([ce.statPromise(t),ce.statPromise(e)]);return r.dev===s.dev&&r.ino===s.ino}async function Mnt({configuration:t,selfPath:e}){let r=t.get(\"yarnPath\");return t.get(\"ignorePath\")||r===null||r===e||await Lnt(r,e)?null:r}var rpe,Lp,npe,ipe,spe,Aj,xnt,ov,knt,Mp,yR,hj,Qnt,wI,ope,ER,dR,Lnt,ze,av=Ze(()=>{Dt();wc();rpe=ut(Cre()),Lp=ut(Fd());Yt();npe=ut(hne()),ipe=Ie(\"module\"),spe=ut(Ld()),Aj=Ie(\"stream\");$ce();oI();Q8();R8();T8();fue();F8();tm();due();OQ();xc();I0();AR();bc();hR();Tp();Wo();xnt=function(){if(!Lp.GITHUB_ACTIONS||!process.env.GITHUB_EVENT_PATH)return!1;let t=fe.toPortablePath(process.env.GITHUB_EVENT_PATH),e;try{e=ce.readJsonSync(t)}catch{return!1}return!(!(\"repository\"in e)||!e.repository||(e.repository.private??!0))}(),ov=new Set([\"@yarnpkg/plugin-constraints\",\"@yarnpkg/plugin-exec\",\"@yarnpkg/plugin-interactive-tools\",\"@yarnpkg/plugin-stage\",\"@yarnpkg/plugin-typescript\",\"@yarnpkg/plugin-version\",\"@yarnpkg/plugin-workspace-tools\"]),knt=new Set([\"isTestEnv\",\"injectNpmUser\",\"injectNpmPassword\",\"injectNpm2FaToken\",\"zipDataEpilogue\",\"cacheCheckpointOverride\",\"cacheVersionOverride\",\"lockfileVersionOverride\",\"osOverride\",\"cpuOverride\",\"libcOverride\",\"binFolder\",\"version\",\"flags\",\"profile\",\"gpg\",\"ignoreNode\",\"wrapOutput\",\"home\",\"confDir\",\"registry\",\"ignoreCwd\"]),Mp=/^(?!v)[a-z0-9._-]+$/i,yR=\"yarn_\",hj=\".yarnrc.yml\",Qnt=\"********\",wI=(E=>(E.ANY=\"ANY\",E.BOOLEAN=\"BOOLEAN\",E.ABSOLUTE_PATH=\"ABSOLUTE_PATH\",E.LOCATOR=\"LOCATOR\",E.LOCATOR_LOOSE=\"LOCATOR_LOOSE\",E.NUMBER=\"NUMBER\",E.STRING=\"STRING\",E.SECRET=\"SECRET\",E.SHAPE=\"SHAPE\",E.MAP=\"MAP\",E))(wI||{}),ope=ht,ER=(r=>(r.JUNCTIONS=\"junctions\",r.SYMLINKS=\"symlinks\",r))(ER||{}),dR={lastUpdateCheck:{description:\"Last timestamp we checked whether new Yarn versions were available\",type:\"STRING\",default:null},yarnPath:{description:\"Path to the local executable that must be used over the global one\",type:\"ABSOLUTE_PATH\",default:null},ignorePath:{description:\"If true, the local executable will be ignored when using the global one\",type:\"BOOLEAN\",default:!1},globalFolder:{description:\"Folder where all system-global files are stored\",type:\"ABSOLUTE_PATH\",default:H8()},cacheFolder:{description:\"Folder where the cache files must be written\",type:\"ABSOLUTE_PATH\",default:\"./.yarn/cache\"},compressionLevel:{description:\"Zip files compression level, from 0 to 9 or mixed (a variant of 9, which stores some files uncompressed, when compression doesn't yield good results)\",type:\"NUMBER\",values:[\"mixed\",0,1,2,3,4,5,6,7,8,9],default:0},virtualFolder:{description:\"Folder where the virtual packages (cf doc) will be mapped on the disk (must be named __virtual__)\",type:\"ABSOLUTE_PATH\",default:\"./.yarn/__virtual__\"},installStatePath:{description:\"Path of the file where the install state will be persisted\",type:\"ABSOLUTE_PATH\",default:\"./.yarn/install-state.gz\"},immutablePatterns:{description:\"Array of glob patterns; files matching them won't be allowed to change during immutable installs\",type:\"STRING\",default:[],isArray:!0},rcFilename:{description:\"Name of the files where the configuration can be found\",type:\"STRING\",default:pj()},enableGlobalCache:{description:\"If true, the system-wide cache folder will be used regardless of `cache-folder`\",type:\"BOOLEAN\",default:!0},cacheMigrationMode:{description:\"Defines the conditions under which Yarn upgrades should cause the cache archives to be regenerated.\",type:\"STRING\",values:[\"always\",\"match-spec\",\"required-only\"],default:\"always\"},enableColors:{description:\"If true, the CLI is allowed to use colors in its output\",type:\"BOOLEAN\",default:Zk,defaultText:\"<dynamic>\"},enableHyperlinks:{description:\"If true, the CLI is allowed to use hyperlinks in its output\",type:\"BOOLEAN\",default:K4,defaultText:\"<dynamic>\"},enableInlineBuilds:{description:\"If true, the CLI will print the build output on the command line\",type:\"BOOLEAN\",default:Lp.isCI,defaultText:\"<dynamic>\"},enableMessageNames:{description:\"If true, the CLI will prefix most messages with codes suitable for search engines\",type:\"BOOLEAN\",default:!0},enableProgressBars:{description:\"If true, the CLI is allowed to show a progress bar for long-running events\",type:\"BOOLEAN\",default:!Lp.isCI,defaultText:\"<dynamic>\"},enableTimers:{description:\"If true, the CLI is allowed to print the time spent executing commands\",type:\"BOOLEAN\",default:!0},enableTips:{description:\"If true, installs will print a helpful message every day of the week\",type:\"BOOLEAN\",default:!Lp.isCI,defaultText:\"<dynamic>\"},preferInteractive:{description:\"If true, the CLI will automatically use the interactive mode when called from a TTY\",type:\"BOOLEAN\",default:!1},preferTruncatedLines:{description:\"If true, the CLI will truncate lines that would go beyond the size of the terminal\",type:\"BOOLEAN\",default:!1},progressBarStyle:{description:\"Which style of progress bar should be used (only when progress bars are enabled)\",type:\"STRING\",default:void 0,defaultText:\"<dynamic>\"},defaultLanguageName:{description:\"Default language mode that should be used when a package doesn't offer any insight\",type:\"STRING\",default:\"node\"},defaultProtocol:{description:\"Default resolution protocol used when resolving pure semver and tag ranges\",type:\"STRING\",default:\"npm:\"},enableTransparentWorkspaces:{description:\"If false, Yarn won't automatically resolve workspace dependencies unless they use the `workspace:` protocol\",type:\"BOOLEAN\",default:!0},supportedArchitectures:{description:\"Architectures that Yarn will fetch and inject into the resolver\",type:\"SHAPE\",properties:{os:{description:\"Array of supported process.platform strings, or null to target them all\",type:\"STRING\",isArray:!0,isNullable:!0,default:[\"current\"]},cpu:{description:\"Array of supported process.arch strings, or null to target them all\",type:\"STRING\",isArray:!0,isNullable:!0,default:[\"current\"]},libc:{description:\"Array of supported libc libraries, or null to target them all\",type:\"STRING\",isArray:!0,isNullable:!0,default:[\"current\"]}}},enableMirror:{description:\"If true, the downloaded packages will be retrieved and stored in both the local and global folders\",type:\"BOOLEAN\",default:!0},enableNetwork:{description:\"If false, Yarn will refuse to use the network if required to\",type:\"BOOLEAN\",default:!0},enableOfflineMode:{description:\"If true, Yarn will attempt to retrieve files and metadata from the global cache rather than the network\",type:\"BOOLEAN\",default:!1},httpProxy:{description:\"URL of the http proxy that must be used for outgoing http requests\",type:\"STRING\",default:null},httpsProxy:{description:\"URL of the http proxy that must be used for outgoing https requests\",type:\"STRING\",default:null},unsafeHttpWhitelist:{description:\"List of the hostnames for which http queries are allowed (glob patterns are supported)\",type:\"STRING\",default:[],isArray:!0},httpTimeout:{description:\"Timeout of each http request in milliseconds\",type:\"NUMBER\",default:6e4},httpRetry:{description:\"Retry times on http failure\",type:\"NUMBER\",default:3},networkConcurrency:{description:\"Maximal number of concurrent requests\",type:\"NUMBER\",default:50},taskPoolConcurrency:{description:\"Maximal amount of concurrent heavy task processing\",type:\"NUMBER\",default:cj()},taskPoolMode:{description:\"Execution strategy for heavy tasks\",type:\"STRING\",values:[\"async\",\"workers\"],default:\"workers\"},networkSettings:{description:\"Network settings per hostname (glob patterns are supported)\",type:\"MAP\",valueDefinition:{description:\"\",type:\"SHAPE\",properties:{httpsCaFilePath:{description:\"Path to file containing one or multiple Certificate Authority signing certificates\",type:\"ABSOLUTE_PATH\",default:null},enableNetwork:{description:\"If false, the package manager will refuse to use the network if required to\",type:\"BOOLEAN\",default:null},httpProxy:{description:\"URL of the http proxy that must be used for outgoing http requests\",type:\"STRING\",default:null},httpsProxy:{description:\"URL of the http proxy that must be used for outgoing https requests\",type:\"STRING\",default:null},httpsKeyFilePath:{description:\"Path to file containing private key in PEM format\",type:\"ABSOLUTE_PATH\",default:null},httpsCertFilePath:{description:\"Path to file containing certificate chain in PEM format\",type:\"ABSOLUTE_PATH\",default:null}}}},httpsCaFilePath:{description:\"A path to a file containing one or multiple Certificate Authority signing certificates\",type:\"ABSOLUTE_PATH\",default:null},httpsKeyFilePath:{description:\"Path to file containing private key in PEM format\",type:\"ABSOLUTE_PATH\",default:null},httpsCertFilePath:{description:\"Path to file containing certificate chain in PEM format\",type:\"ABSOLUTE_PATH\",default:null},enableStrictSsl:{description:\"If false, SSL certificate errors will be ignored\",type:\"BOOLEAN\",default:!0},logFilters:{description:\"Overrides for log levels\",type:\"SHAPE\",isArray:!0,concatenateValues:!0,properties:{code:{description:\"Code of the messages covered by this override\",type:\"STRING\",default:void 0},text:{description:\"Code of the texts covered by this override\",type:\"STRING\",default:void 0},pattern:{description:\"Code of the patterns covered by this override\",type:\"STRING\",default:void 0},level:{description:\"Log level override, set to null to remove override\",type:\"STRING\",values:Object.values($k),isNullable:!0,default:void 0}}},enableTelemetry:{description:\"If true, telemetry will be periodically sent, following the rules in https://yarnpkg.com/advanced/telemetry\",type:\"BOOLEAN\",default:!0},telemetryInterval:{description:\"Minimal amount of time between two telemetry uploads, in days\",type:\"NUMBER\",default:7},telemetryUserId:{description:\"If you desire to tell us which project you are, you can set this field. Completely optional and opt-in.\",type:\"STRING\",default:null},enableHardenedMode:{description:\"If true, automatically enable --check-resolutions --refresh-lockfile on installs\",type:\"BOOLEAN\",default:Lp.isPR&&xnt,defaultText:\"<true on public PRs>\"},enableScripts:{description:\"If true, packages are allowed to have install scripts by default\",type:\"BOOLEAN\",default:!0},enableStrictSettings:{description:\"If true, unknown settings will cause Yarn to abort\",type:\"BOOLEAN\",default:!0},enableImmutableCache:{description:\"If true, the cache is reputed immutable and actions that would modify it will throw\",type:\"BOOLEAN\",default:!1},enableCacheClean:{description:\"If false, disallows the `cache clean` command\",type:\"BOOLEAN\",default:!0},checksumBehavior:{description:\"Enumeration defining what to do when a checksum doesn't match expectations\",type:\"STRING\",default:\"throw\"},injectEnvironmentFiles:{description:\"List of all the environment files that Yarn should inject inside the process when it starts\",type:\"ABSOLUTE_PATH\",default:[\".env.yarn?\"],isArray:!0},packageExtensions:{description:\"Map of package corrections to apply on the dependency tree\",type:\"MAP\",valueDefinition:{description:\"The extension that will be applied to any package whose version matches the specified range\",type:\"SHAPE\",properties:{dependencies:{description:\"The set of dependencies that must be made available to the current package in order for it to work properly\",type:\"MAP\",valueDefinition:{description:\"A range\",type:\"STRING\"}},peerDependencies:{description:\"Inherited dependencies - the consumer of the package will be tasked to provide them\",type:\"MAP\",valueDefinition:{description:\"A semver range\",type:\"STRING\"}},peerDependenciesMeta:{description:\"Extra information related to the dependencies listed in the peerDependencies field\",type:\"MAP\",valueDefinition:{description:\"The peerDependency meta\",type:\"SHAPE\",properties:{optional:{description:\"If true, the selected peer dependency will be marked as optional by the package manager and the consumer omitting it won't be reported as an error\",type:\"BOOLEAN\",default:!1}}}}}}}};Lnt=process.platform===\"win32\"?Nnt:Ont;ze=class t{constructor(e){this.isCI=Lp.isCI;this.projectCwd=null;this.plugins=new Map;this.settings=new Map;this.values=new Map;this.sources=new Map;this.invalid=new Map;this.env={};this.limits=new Map;this.packageExtensions=null;this.startingCwd=e}static{this.deleteProperty=Symbol()}static{this.telemetry=null}static create(e,r,s){let a=new t(e);typeof r<\"u\"&&!(r instanceof Map)&&(a.projectCwd=r),a.importSettings(dR);let n=typeof s<\"u\"?s:r instanceof Map?r:new Map;for(let[c,f]of n)a.activatePlugin(c,f);return a}static async find(e,r,{strict:s=!0,usePathCheck:a=null,useRc:n=!0}={}){let c=Fnt();delete c.rcFilename;let f=new t(e),p=await t.findRcFiles(e),h=await t.findFolderRcFile(fI());h&&(p.find(me=>me.path===h.path)||p.unshift(h));let E=gue(p.map(le=>[le.path,le.data])),C=vt.dot,S=new Set(Object.keys(dR)),b=({yarnPath:le,ignorePath:me,injectEnvironmentFiles:pe})=>({yarnPath:le,ignorePath:me,injectEnvironmentFiles:pe}),I=({yarnPath:le,ignorePath:me,injectEnvironmentFiles:pe,...Be})=>{let Ce={};for(let[g,we]of Object.entries(Be))S.has(g)&&(Ce[g]=we);return Ce},T=({yarnPath:le,ignorePath:me,...pe})=>{let Be={};for(let[Ce,g]of Object.entries(pe))S.has(Ce)||(Be[Ce]=g);return Be};if(f.importSettings(b(dR)),f.useWithSource(\"<environment>\",b(c),e,{strict:!1}),E){let[le,me]=E;f.useWithSource(le,b(me),C,{strict:!1})}if(a){if(await Mnt({configuration:f,selfPath:a})!==null)return f;f.useWithSource(\"<override>\",{ignorePath:!0},e,{strict:!1,overwrite:!0})}let N=await t.findProjectCwd(e);f.startingCwd=e,f.projectCwd=N;let U=Object.assign(Object.create(null),process.env);f.env=U;let W=await Promise.all(f.get(\"injectEnvironmentFiles\").map(async le=>{let me=le.endsWith(\"?\")?await ce.readFilePromise(le.slice(0,-1),\"utf8\").catch(()=>\"\"):await ce.readFilePromise(le,\"utf8\");return(0,npe.parse)(me)}));for(let le of W)for(let[me,pe]of Object.entries(le))f.env[me]=Vk(pe,{env:U});if(f.importSettings(I(dR)),f.useWithSource(\"<environment>\",I(c),e,{strict:s}),E){let[le,me]=E;f.useWithSource(le,I(me),C,{strict:s})}let ee=le=>\"default\"in le?le.default:le,ie=new Map([[\"@@core\",Xce]]);if(r!==null)for(let le of r.plugins.keys())ie.set(le,ee(r.modules.get(le)));for(let[le,me]of ie)f.activatePlugin(le,me);let ue=new Map([]);if(r!==null){let le=new Map;for(let[Be,Ce]of r.modules)le.set(Be,()=>Ce);let me=new Set,pe=async(Be,Ce)=>{let{factory:g,name:we}=bp(Be);if(!g||me.has(we))return;let ye=new Map(le),Ae=X=>{if((0,ipe.isBuiltin)(X))return bp(X);if(ye.has(X))return ye.get(X)();throw new nt(`This plugin cannot access the package referenced via ${X} which is neither a builtin, nor an exposed entry`)},se=await qE(async()=>ee(await g(Ae)),X=>`${X} (when initializing ${we}, defined in ${Ce})`);le.set(we,()=>se),me.add(we),ue.set(we,se)};if(c.plugins)for(let Be of c.plugins.split(\";\")){let Ce=J.resolve(e,fe.toPortablePath(Be));await pe(Ce,\"<environment>\")}for(let{path:Be,cwd:Ce,data:g}of p)if(n&&Array.isArray(g.plugins))for(let we of g.plugins){let ye=typeof we!=\"string\"?we.path:we,Ae=we?.spec??\"\",se=we?.checksum??\"\";if(ov.has(Ae))continue;let X=J.resolve(Ce,fe.toPortablePath(ye));if(!await ce.existsPromise(X)){if(!Ae){let mt=Ht(f,J.basename(X,\".cjs\"),ht.NAME),j=Ht(f,\".gitignore\",ht.NAME),rt=Ht(f,f.values.get(\"rcFilename\"),ht.NAME),Fe=Ht(f,\"https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored\",ht.URL);throw new nt(`Missing source for the ${mt} plugin - please try to remove the plugin from ${rt} then reinstall it manually. This error usually occurs because ${j} is incorrect, check ${Fe} to make sure your plugin folder isn't gitignored.`)}if(!Ae.match(/^https?:/)){let mt=Ht(f,J.basename(X,\".cjs\"),ht.NAME),j=Ht(f,f.values.get(\"rcFilename\"),ht.NAME);throw new nt(`Failed to recognize the source for the ${mt} plugin - please try to delete the plugin from ${j} then reinstall it manually.`)}let De=await oj(Ae,{configuration:f}),Te=cs(De);if(se&&se!==Te){let mt=Ht(f,J.basename(X,\".cjs\"),ht.NAME),j=Ht(f,f.values.get(\"rcFilename\"),ht.NAME),rt=Ht(f,`yarn plugin import ${Ae}`,ht.CODE);throw new nt(`Failed to fetch the ${mt} plugin from its remote location: its checksum seems to have changed. If this is expected, please remove the plugin from ${j} then run ${rt} to reimport it.`)}await ce.mkdirPromise(J.dirname(X),{recursive:!0}),await ce.writeFilePromise(X,De)}await pe(X,Be)}}for(let[le,me]of ue)f.activatePlugin(le,me);if(f.useWithSource(\"<environment>\",T(c),e,{strict:s}),E){let[le,me]=E;f.useWithSource(le,T(me),C,{strict:s})}return f.get(\"enableGlobalCache\")&&(f.values.set(\"cacheFolder\",`${f.get(\"globalFolder\")}/cache`),f.sources.set(\"cacheFolder\",\"<internal>\")),f}static async findRcFiles(e){let r=pj(),s=[],a=e,n=null;for(;a!==n;){n=a;let c=J.join(n,r);if(ce.existsSync(c)){let f,p;try{p=await ce.readFilePromise(c,\"utf8\"),f=as(p)}catch{let h=\"\";throw p?.match(/^\\s+(?!-)[^:]+\\s+\\S+/m)&&(h=\" (in particular, make sure you list the colons after each key name)\"),new nt(`Parse error when loading ${c}; please check it's proper Yaml${h}`)}s.unshift({path:c,cwd:n,data:f})}a=J.dirname(n)}return s}static async findFolderRcFile(e){let r=J.join(e,Er.rc),s;try{s=await ce.readFilePromise(r,\"utf8\")}catch(n){if(n.code===\"ENOENT\")return null;throw n}let a=as(s);return{path:r,cwd:e,data:a}}static async findProjectCwd(e){let r=null,s=e,a=null;for(;s!==a;){if(a=s,ce.existsSync(J.join(a,Er.lockfile)))return a;ce.existsSync(J.join(a,Er.manifest))&&(r=a),s=J.dirname(a)}return r}static async updateConfiguration(e,r,s={}){let a=pj(),n=J.join(e,a),c=ce.existsSync(n)?as(await ce.readFilePromise(n,\"utf8\")):{},f=!1,p;if(typeof r==\"function\"){try{p=r(c)}catch{p=r({})}if(p===c)return!1}else{p=c;for(let h of Object.keys(r)){let E=c[h],C=r[h],S;if(typeof C==\"function\")try{S=C(E)}catch{S=C(void 0)}else S=C;E!==S&&(S===t.deleteProperty?delete p[h]:p[h]=S,f=!0)}if(!f)return!1}return await ce.changeFilePromise(n,nl(p),{automaticNewlines:!0}),!0}static async addPlugin(e,r){r.length!==0&&await t.updateConfiguration(e,s=>{let a=s.plugins??[];if(a.length===0)return{...s,plugins:r};let n=[],c=[...r];for(let f of a){let p=typeof f!=\"string\"?f.path:f,h=c.find(E=>E.path===p);h?(n.push(h),c=c.filter(E=>E!==h)):n.push(f)}return n.push(...c),{...s,plugins:n}})}static async updateHomeConfiguration(e){let r=fI();return await t.updateConfiguration(r,e)}activatePlugin(e,r){this.plugins.set(e,r),typeof r.configuration<\"u\"&&this.importSettings(r.configuration)}importSettings(e){for(let[r,s]of Object.entries(e))if(s!=null){if(this.settings.has(r))throw new Error(`Cannot redefine settings \"${r}\"`);this.settings.set(r,s),this.values.set(r,dj(this,s))}}useWithSource(e,r,s,a){try{this.use(e,r,s,a)}catch(n){throw n.message+=` (in ${Ht(this,e,ht.PATH)})`,n}}use(e,r,s,{strict:a=!0,overwrite:n=!1}={}){a=a&&this.get(\"enableStrictSettings\");for(let c of[\"enableStrictSettings\",...Object.keys(r)]){let f=r[c],p=U8(f);if(p&&(e=p),typeof f>\"u\"||c===\"plugins\"||e===\"<environment>\"&&knt.has(c))continue;if(c===\"rcFilename\")throw new nt(`The rcFilename settings can only be set via ${`${yR}RC_FILENAME`.toUpperCase()}, not via a rc file`);let h=this.settings.get(c);if(!h){let C=fI(),S=e[0]!==\"<\"?J.dirname(e):null;if(a&&!(S!==null?C===S:!1))throw new nt(`Unrecognized or legacy configuration settings found: ${c} - run \"yarn config\" to see the list of settings supported in Yarn`);this.invalid.set(c,e);continue}if(this.sources.has(c)&&!(n||h.type===\"MAP\"||h.isArray&&h.concatenateValues))continue;let E;try{E=gj(this,c,f,h,s)}catch(C){throw C.message+=` in ${Ht(this,e,ht.PATH)}`,C}if(c===\"enableStrictSettings\"&&e!==\"<environment>\"){a=E;continue}if(h.type===\"MAP\"){let C=this.values.get(c);this.values.set(c,new Map(n?[...C,...E]:[...E,...C])),this.sources.set(c,`${this.sources.get(c)}, ${e}`)}else if(h.isArray&&h.concatenateValues){let C=this.values.get(c);this.values.set(c,n?[...C,...E]:[...E,...C]),this.sources.set(c,`${this.sources.get(c)}, ${e}`)}else this.values.set(c,E),this.sources.set(c,e)}}get(e){if(!this.values.has(e))throw new Error(`Invalid configuration key \"${e}\"`);return this.values.get(e)}getSpecial(e,{hideSecrets:r=!1,getNativePaths:s=!1}){let a=this.get(e),n=this.settings.get(e);if(typeof n>\"u\")throw new nt(`Couldn't find a configuration settings named \"${e}\"`);return mR(a,n,{hideSecrets:r,getNativePaths:s})}getSubprocessStreams(e,{header:r,prefix:s,report:a}){let n,c,f=ce.createWriteStream(e);if(this.get(\"enableInlineBuilds\")){let p=a.createStreamReporter(`${s} ${Ht(this,\"STDOUT\",\"green\")}`),h=a.createStreamReporter(`${s} ${Ht(this,\"STDERR\",\"red\")}`);n=new Aj.PassThrough,n.pipe(p),n.pipe(f),c=new Aj.PassThrough,c.pipe(h),c.pipe(f)}else n=f,c=f,typeof r<\"u\"&&n.write(`${r}\n`);return{stdout:n,stderr:c}}makeResolver(){let e=[];for(let r of this.plugins.values())for(let s of r.resolvers||[])e.push(new s);return new rm([new TQ,new Ei,...e])}makeFetcher(){let e=[];for(let r of this.plugins.values())for(let s of r.fetchers||[])e.push(new s);return new aI([new lI,new cI,...e])}getLinkers(){let e=[];for(let r of this.plugins.values())for(let s of r.linkers||[])e.push(new s);return e}getSupportedArchitectures(){let e=sv(),r=this.get(\"supportedArchitectures\"),s=r.get(\"os\");s!==null&&(s=s.map(c=>c===\"current\"?e.os:c));let a=r.get(\"cpu\");a!==null&&(a=a.map(c=>c===\"current\"?e.cpu:c));let n=r.get(\"libc\");return n!==null&&(n=Wl(n,c=>c===\"current\"?e.libc??Wl.skip:c)),{os:s,cpu:a,libc:n}}isInteractive({interactive:e,stdout:r}){return r.isTTY?e??this.get(\"preferInteractive\"):!1}async getPackageExtensions(){if(this.packageExtensions!==null)return this.packageExtensions;this.packageExtensions=new Map;let e=this.packageExtensions,r=(s,a,{userProvided:n=!1}={})=>{if(!cl(s.range))throw new Error(\"Only semver ranges are allowed as keys for the packageExtensions setting\");let c=new Ut;c.load(a,{yamlCompatibilityMode:!0});let f=xB(e,s.identHash),p=[];f.push([s.range,p]);let h={status:\"inactive\",userProvided:n,parentDescriptor:s};for(let E of c.dependencies.values())p.push({...h,type:\"Dependency\",descriptor:E});for(let E of c.peerDependencies.values())p.push({...h,type:\"PeerDependency\",descriptor:E});for(let[E,C]of c.peerDependenciesMeta)for(let[S,b]of Object.entries(C))p.push({...h,type:\"PeerDependencyMeta\",selector:E,key:S,value:b})};await this.triggerHook(s=>s.registerPackageExtensions,this,r);for(let[s,a]of this.get(\"packageExtensions\"))r(C0(s,!0),Yk(a),{userProvided:!0});return e}normalizeLocator(e){return cl(e.reference)?Ws(e,`${this.get(\"defaultProtocol\")}${e.reference}`):Mp.test(e.reference)?Ws(e,`${this.get(\"defaultProtocol\")}${e.reference}`):e}normalizeDependency(e){return cl(e.range)?On(e,`${this.get(\"defaultProtocol\")}${e.range}`):Mp.test(e.range)?On(e,`${this.get(\"defaultProtocol\")}${e.range}`):e}normalizeDependencyMap(e){return new Map([...e].map(([r,s])=>[r,this.normalizeDependency(s)]))}normalizePackage(e,{packageExtensions:r}){let s=LB(e),a=r.get(e.identHash);if(typeof a<\"u\"){let c=e.version;if(c!==null){for(let[f,p]of a)if(Xf(c,f))for(let h of p)switch(h.status===\"inactive\"&&(h.status=\"redundant\"),h.type){case\"Dependency\":typeof s.dependencies.get(h.descriptor.identHash)>\"u\"&&(h.status=\"active\",s.dependencies.set(h.descriptor.identHash,this.normalizeDependency(h.descriptor)));break;case\"PeerDependency\":typeof s.peerDependencies.get(h.descriptor.identHash)>\"u\"&&(h.status=\"active\",s.peerDependencies.set(h.descriptor.identHash,h.descriptor));break;case\"PeerDependencyMeta\":{let E=s.peerDependenciesMeta.get(h.selector);(typeof E>\"u\"||!Object.hasOwn(E,h.key)||E[h.key]!==h.value)&&(h.status=\"active\",Yl(s.peerDependenciesMeta,h.selector,()=>({}))[h.key]=h.value)}break;default:H4(h)}}}let n=c=>c.scope?`${c.scope}__${c.name}`:`${c.name}`;for(let c of s.peerDependenciesMeta.keys()){let f=Sa(c);s.peerDependencies.has(f.identHash)||s.peerDependencies.set(f.identHash,On(f,\"*\"))}for(let c of s.peerDependencies.values()){if(c.scope===\"types\")continue;let f=n(c),p=Da(\"types\",f),h=un(p);s.peerDependencies.has(p.identHash)||s.peerDependenciesMeta.has(h)||s.dependencies.has(p.identHash)||(s.peerDependencies.set(p.identHash,On(p,\"*\")),s.peerDependenciesMeta.set(h,{optional:!0}))}return s.dependencies=new Map(qs(s.dependencies,([,c])=>al(c))),s.peerDependencies=new Map(qs(s.peerDependencies,([,c])=>al(c))),s}getLimit(e){return Yl(this.limits,e,()=>(0,spe.default)(this.get(e)))}async triggerHook(e,...r){for(let s of this.plugins.values()){let a=s.hooks;if(!a)continue;let n=e(a);n&&await n(...r)}}async triggerMultipleHooks(e,r){for(let s of r)await this.triggerHook(e,...s)}async reduceHook(e,r,...s){let a=r;for(let n of this.plugins.values()){let c=n.hooks;if(!c)continue;let f=e(c);f&&(a=await f(a,...s))}return a}async firstHook(e,...r){for(let s of this.plugins.values()){let a=s.hooks;if(!a)continue;let n=e(a);if(!n)continue;let c=await n(...r);if(typeof c<\"u\")return c}return null}}});var qr={};Vt(qr,{EndStrategy:()=>Ij,ExecError:()=>IR,PipeError:()=>lv,execvp:()=>uj,pipevp:()=>Wu});function om(t){return t!==null&&typeof t.fd==\"number\"}function mj(){}function yj(){for(let t of am)t.kill()}async function Wu(t,e,{cwd:r,env:s=process.env,strict:a=!1,stdin:n=null,stdout:c,stderr:f,end:p=2}){let h=[\"pipe\",\"pipe\",\"pipe\"];n===null?h[0]=\"ignore\":om(n)&&(h[0]=n),om(c)&&(h[1]=c),om(f)&&(h[2]=f);let E=(0,Ej.default)(t,e,{cwd:fe.fromPortablePath(r),env:{...s,PWD:fe.fromPortablePath(r)},stdio:h});am.add(E),am.size===1&&(process.on(\"SIGINT\",mj),process.on(\"SIGTERM\",yj)),!om(n)&&n!==null&&n.pipe(E.stdin),om(c)||E.stdout.pipe(c,{end:!1}),om(f)||E.stderr.pipe(f,{end:!1});let C=()=>{for(let S of new Set([c,f]))om(S)||S.end()};return new Promise((S,b)=>{E.on(\"error\",I=>{am.delete(E),am.size===0&&(process.off(\"SIGINT\",mj),process.off(\"SIGTERM\",yj)),(p===2||p===1)&&C(),b(I)}),E.on(\"close\",(I,T)=>{am.delete(E),am.size===0&&(process.off(\"SIGINT\",mj),process.off(\"SIGTERM\",yj)),(p===2||p===1&&I!==0)&&C(),I===0||!a?S({code:Cj(I,T)}):b(new lv({fileName:t,code:I,signal:T}))})})}async function uj(t,e,{cwd:r,env:s=process.env,encoding:a=\"utf8\",strict:n=!1}){let c=[\"ignore\",\"pipe\",\"pipe\"],f=[],p=[],h=fe.fromPortablePath(r);typeof s.PWD<\"u\"&&(s={...s,PWD:h});let E=(0,Ej.default)(t,e,{cwd:h,env:s,stdio:c});return E.stdout.on(\"data\",C=>{f.push(C)}),E.stderr.on(\"data\",C=>{p.push(C)}),await new Promise((C,S)=>{E.on(\"error\",b=>{let I=ze.create(r),T=Ht(I,t,ht.PATH);S(new jt(1,`Process ${T} failed to spawn`,N=>{N.reportError(1,`  ${Kf(I,{label:\"Thrown Error\",value:_u(ht.NO_HINT,b.message)})}`)}))}),E.on(\"close\",(b,I)=>{let T=a===\"buffer\"?Buffer.concat(f):Buffer.concat(f).toString(a),N=a===\"buffer\"?Buffer.concat(p):Buffer.concat(p).toString(a);b===0||!n?C({code:Cj(b,I),stdout:T,stderr:N}):S(new IR({fileName:t,code:b,signal:I,stdout:T,stderr:N}))})})}function Cj(t,e){let r=Unt.get(e);return typeof r<\"u\"?128+r:t??1}function _nt(t,e,{configuration:r,report:s}){s.reportError(1,`  ${Kf(r,t!==null?{label:\"Exit Code\",value:_u(ht.NUMBER,t)}:{label:\"Exit Signal\",value:_u(ht.CODE,e)})}`)}var Ej,Ij,lv,IR,am,Unt,gR=Ze(()=>{Dt();Ej=ut(UU());av();Rc();xc();Ij=(s=>(s[s.Never=0]=\"Never\",s[s.ErrorCode=1]=\"ErrorCode\",s[s.Always=2]=\"Always\",s))(Ij||{}),lv=class extends jt{constructor({fileName:e,code:r,signal:s}){let a=ze.create(J.cwd()),n=Ht(a,e,ht.PATH);super(1,`Child ${n} reported an error`,c=>{_nt(r,s,{configuration:a,report:c})}),this.code=Cj(r,s)}},IR=class extends lv{constructor({fileName:e,code:r,signal:s,stdout:a,stderr:n}){super({fileName:e,code:r,signal:s}),this.stdout=a,this.stderr=n}};am=new Set;Unt=new Map([[\"SIGINT\",2],[\"SIGQUIT\",3],[\"SIGKILL\",9],[\"SIGTERM\",15]])});function lpe(t){ape=t}function cv(){return typeof wj>\"u\"&&(wj=ape()),wj}var wj,ape,Bj=Ze(()=>{ape=()=>{throw new Error(\"Assertion failed: No libzip instance is available, and no factory was configured\")}});var cpe=_((CR,Sj)=>{var Hnt=Object.assign({},Ie(\"fs\")),vj=function(){var t=typeof document<\"u\"&&document.currentScript?document.currentScript.src:void 0;return typeof __filename<\"u\"&&(t=t||__filename),function(e){e=e||{};var r=typeof e<\"u\"?e:{},s,a;r.ready=new Promise(function(Ke,st){s=Ke,a=st});var n={},c;for(c in r)r.hasOwnProperty(c)&&(n[c]=r[c]);var f=[],p=\"./this.program\",h=function(Ke,st){throw st},E=!1,C=!0,S=\"\";function b(Ke){return r.locateFile?r.locateFile(Ke,S):S+Ke}var I,T,N,U;C&&(E?S=Ie(\"path\").dirname(S)+\"/\":S=__dirname+\"/\",I=function(st,St){var lr=Me(st);return lr?St?lr:lr.toString():(N||(N=Hnt),U||(U=Ie(\"path\")),st=U.normalize(st),N.readFileSync(st,St?null:\"utf8\"))},T=function(st){var St=I(st,!0);return St.buffer||(St=new Uint8Array(St)),we(St.buffer),St},process.argv.length>1&&(p=process.argv[1].replace(/\\\\/g,\"/\")),f=process.argv.slice(2),h=function(Ke){process.exit(Ke)},r.inspect=function(){return\"[Emscripten Module object]\"});var W=r.print||console.log.bind(console),ee=r.printErr||console.warn.bind(console);for(c in n)n.hasOwnProperty(c)&&(r[c]=n[c]);n=null,r.arguments&&(f=r.arguments),r.thisProgram&&(p=r.thisProgram),r.quit&&(h=r.quit);var ie=0,ue=function(Ke){ie=Ke},le;r.wasmBinary&&(le=r.wasmBinary);var me=r.noExitRuntime||!0;typeof WebAssembly!=\"object\"&&ts(\"no native wasm support detected\");function pe(Ke,st,St){switch(st=st||\"i8\",st.charAt(st.length-1)===\"*\"&&(st=\"i32\"),st){case\"i1\":return Ve[Ke>>0];case\"i8\":return Ve[Ke>>0];case\"i16\":return mh((Ke>>1)*2);case\"i32\":return to((Ke>>2)*4);case\"i64\":return to((Ke>>2)*4);case\"float\":return Af((Ke>>2)*4);case\"double\":return dh((Ke>>3)*8);default:ts(\"invalid type for getValue: \"+st)}return null}var Be,Ce=!1,g;function we(Ke,st){Ke||ts(\"Assertion failed: \"+st)}function ye(Ke){var st=r[\"_\"+Ke];return we(st,\"Cannot call unknown function \"+Ke+\", make sure it is exported\"),st}function Ae(Ke,st,St,lr,te){var Ee={string:function(Gi){var Rn=0;if(Gi!=null&&Gi!==0){var Ga=(Gi.length<<2)+1;Rn=wi(Ga),mt(Gi,Rn,Ga)}return Rn},array:function(Gi){var Rn=wi(Gi.length);return Fe(Gi,Rn),Rn}};function Oe(Gi){return st===\"string\"?De(Gi):st===\"boolean\"?!!Gi:Gi}var dt=ye(Ke),Et=[],Pt=0;if(lr)for(var tr=0;tr<lr.length;tr++){var An=Ee[St[tr]];An?(Pt===0&&(Pt=gf()),Et[tr]=An(lr[tr])):Et[tr]=lr[tr]}var li=dt.apply(null,Et);return li=Oe(li),Pt!==0&&fc(Pt),li}function se(Ke,st,St,lr){St=St||[];var te=St.every(function(Oe){return Oe===\"number\"}),Ee=st!==\"string\";return Ee&&te&&!lr?ye(Ke):function(){return Ae(Ke,st,St,arguments,lr)}}var X=new TextDecoder(\"utf8\");function De(Ke,st){if(!Ke)return\"\";for(var St=Ke+st,lr=Ke;!(lr>=St)&&ke[lr];)++lr;return X.decode(ke.subarray(Ke,lr))}function Te(Ke,st,St,lr){if(!(lr>0))return 0;for(var te=St,Ee=St+lr-1,Oe=0;Oe<Ke.length;++Oe){var dt=Ke.charCodeAt(Oe);if(dt>=55296&&dt<=57343){var Et=Ke.charCodeAt(++Oe);dt=65536+((dt&1023)<<10)|Et&1023}if(dt<=127){if(St>=Ee)break;st[St++]=dt}else if(dt<=2047){if(St+1>=Ee)break;st[St++]=192|dt>>6,st[St++]=128|dt&63}else if(dt<=65535){if(St+2>=Ee)break;st[St++]=224|dt>>12,st[St++]=128|dt>>6&63,st[St++]=128|dt&63}else{if(St+3>=Ee)break;st[St++]=240|dt>>18,st[St++]=128|dt>>12&63,st[St++]=128|dt>>6&63,st[St++]=128|dt&63}}return st[St]=0,St-te}function mt(Ke,st,St){return Te(Ke,ke,st,St)}function j(Ke){for(var st=0,St=0;St<Ke.length;++St){var lr=Ke.charCodeAt(St);lr>=55296&&lr<=57343&&(lr=65536+((lr&1023)<<10)|Ke.charCodeAt(++St)&1023),lr<=127?++st:lr<=2047?st+=2:lr<=65535?st+=3:st+=4}return st}function rt(Ke){var st=j(Ke)+1,St=La(st);return St&&Te(Ke,Ve,St,st),St}function Fe(Ke,st){Ve.set(Ke,st)}function Ne(Ke,st){return Ke%st>0&&(Ke+=st-Ke%st),Ke}var be,Ve,ke,it,Ue,x,w,P,y,F;function z(Ke){be=Ke,r.HEAP_DATA_VIEW=F=new DataView(Ke),r.HEAP8=Ve=new Int8Array(Ke),r.HEAP16=it=new Int16Array(Ke),r.HEAP32=x=new Int32Array(Ke),r.HEAPU8=ke=new Uint8Array(Ke),r.HEAPU16=Ue=new Uint16Array(Ke),r.HEAPU32=w=new Uint32Array(Ke),r.HEAPF32=P=new Float32Array(Ke),r.HEAPF64=y=new Float64Array(Ke)}var Z=r.INITIAL_MEMORY||16777216,$,oe=[],xe=[],Re=[],lt=!1;function Ct(){if(r.preRun)for(typeof r.preRun==\"function\"&&(r.preRun=[r.preRun]);r.preRun.length;)bt(r.preRun.shift());Rs(oe)}function qt(){lt=!0,Rs(xe)}function ir(){if(r.postRun)for(typeof r.postRun==\"function\"&&(r.postRun=[r.postRun]);r.postRun.length;)br(r.postRun.shift());Rs(Re)}function bt(Ke){oe.unshift(Ke)}function gn(Ke){xe.unshift(Ke)}function br(Ke){Re.unshift(Ke)}var Ir=0,Or=null,nn=null;function ai(Ke){Ir++,r.monitorRunDependencies&&r.monitorRunDependencies(Ir)}function Io(Ke){if(Ir--,r.monitorRunDependencies&&r.monitorRunDependencies(Ir),Ir==0&&(Or!==null&&(clearInterval(Or),Or=null),nn)){var st=nn;nn=null,st()}}r.preloadedImages={},r.preloadedAudios={};function ts(Ke){r.onAbort&&r.onAbort(Ke),Ke+=\"\",ee(Ke),Ce=!0,g=1,Ke=\"abort(\"+Ke+\"). Build with -s ASSERTIONS=1 for more info.\";var st=new WebAssembly.RuntimeError(Ke);throw a(st),st}var $s=\"data:application/octet-stream;base64,\";function Co(Ke){return Ke.startsWith($s)}var Hi=\"data:application/octet-stream;base64,AGFzbQEAAAAB/wEkYAN/f38Bf2ABfwF/YAJ/fwF/YAF/AGAEf39/fwF/YAN/f38AYAV/f39/fwF/YAJ/fwBgBH9/f38AYAABf2AFf39/fn8BfmAEf35/fwF/YAR/f35/AX5gAn9+AX9gA398fwBgA39/fgF/YAF/AX5gBn9/f39/fwF/YAN/fn8Bf2AEf39/fwF+YAV/f35/fwF/YAR/f35/AX9gA39/fgF+YAJ/fgBgAn9/AX5gBX9/f39/AGADf35/AX5gBX5+f35/AX5gA39/fwF+YAZ/fH9/f38Bf2AAAGAHf35/f39+fwF/YAV/fn9/fwF/YAV/f39/fwF+YAJ+fwF/YAJ/fAACJQYBYQFhAAMBYQFiAAEBYQFjAAABYQFkAAEBYQFlAAIBYQFmAAED5wHlAQMAAwEDAwEHDAgDFgcNEgEDDRcFAQ8DEAUQAwIBAhgECxkEAQMBBQsFAwMDARACBAMAAggLBwEAAwADGgQDGwYGABwBBgMTFBEHBwcVCx4ABAgHBAICAgAfAQICAgIGFSAAIQAiAAIBBgIHAg0LEw0FAQUCACMDAQAUAAAGBQECBQUDCwsSAgEDBQIHAQEICAACCQQEAQABCAEBCQoBAwkBAQEBBgEGBgYABAIEBAQGEQQEAAARAAEDCQEJAQAJCQkBAQECCgoAAAMPAQEBAwACAgICBQIABwAKBgwHAAADAgICBQEEBQFwAT8/BQcBAYACgIACBgkBfwFBgInBAgsH+gEzAWcCAAFoAFQBaQDqAQFqALsBAWsAwQEBbACpAQFtAKgBAW4ApwEBbwClAQFwAKMBAXEAoAEBcgCbAQFzAMABAXQAugEBdQC5AQF2AEsBdwDiAQF4AMgBAXkAxwEBegDCAQFBAMkBAUIAuAEBQwAGAUQACQFFAKYBAUYAtwEBRwC2AQFIALUBAUkAtAEBSgCzAQFLALIBAUwAsQEBTQCwAQFOAK8BAU8AvAEBUACuAQFRAK0BAVIArAEBUwAaAVQACwFVAKQBAVYAMgFXAQABWACrAQFZAKoBAVoAxgEBXwDFAQEkAMQBAmFhAL8BAmJhAL4BAmNhAL0BCXgBAEEBCz6iAeMBjgGQAVpbjwFYnwGdAVeeAV1coQFZVlWcAZoBmQGYAZcBlgGVAZQBkwGSAZEB6QHoAecB5gHlAeQB4QHfAeAB3gHdAdwB2gHbAYUB2QHYAdcB1gHVAdQB0wHSAdEB0AHPAc4BzQHMAcsBygE4wwEK1N8G5QHMDAEHfwJAIABFDQAgAEEIayIDIABBBGsoAgAiAUF4cSIAaiEFAkAgAUEBcQ0AIAFBA3FFDQEgAyADKAIAIgFrIgNBxIQBKAIASQ0BIAAgAWohACADQciEASgCAEcEQCABQf8BTQRAIAMoAggiAiABQQN2IgRBA3RB3IQBakYaIAIgAygCDCIBRgRAQbSEAUG0hAEoAgBBfiAEd3E2AgAMAwsgAiABNgIMIAEgAjYCCAwCCyADKAIYIQYCQCADIAMoAgwiAUcEQCADKAIIIgIgATYCDCABIAI2AggMAQsCQCADQRRqIgIoAgAiBA0AIANBEGoiAigCACIEDQBBACEBDAELA0AgAiEHIAQiAUEUaiICKAIAIgQNACABQRBqIQIgASgCECIEDQALIAdBADYCAAsgBkUNAQJAIAMgAygCHCICQQJ0QeSGAWoiBCgCAEYEQCAEIAE2AgAgAQ0BQbiEAUG4hAEoAgBBfiACd3E2AgAMAwsgBkEQQRQgBigCECADRhtqIAE2AgAgAUUNAgsgASAGNgIYIAMoAhAiAgRAIAEgAjYCECACIAE2AhgLIAMoAhQiAkUNASABIAI2AhQgAiABNgIYDAELIAUoAgQiAUEDcUEDRw0AQbyEASAANgIAIAUgAUF+cTYCBCADIABBAXI2AgQgACADaiAANgIADwsgAyAFTw0AIAUoAgQiAUEBcUUNAAJAIAFBAnFFBEAgBUHMhAEoAgBGBEBBzIQBIAM2AgBBwIQBQcCEASgCACAAaiIANgIAIAMgAEEBcjYCBCADQciEASgCAEcNA0G8hAFBADYCAEHIhAFBADYCAA8LIAVByIQBKAIARgRAQciEASADNgIAQbyEAUG8hAEoAgAgAGoiADYCACADIABBAXI2AgQgACADaiAANgIADwsgAUF4cSAAaiEAAkAgAUH/AU0EQCAFKAIIIgIgAUEDdiIEQQN0QdyEAWpGGiACIAUoAgwiAUYEQEG0hAFBtIQBKAIAQX4gBHdxNgIADAILIAIgATYCDCABIAI2AggMAQsgBSgCGCEGAkAgBSAFKAIMIgFHBEAgBSgCCCICQcSEASgCAEkaIAIgATYCDCABIAI2AggMAQsCQCAFQRRqIgIoAgAiBA0AIAVBEGoiAigCACIEDQBBACEBDAELA0AgAiEHIAQiAUEUaiICKAIAIgQNACABQRBqIQIgASgCECIEDQALIAdBADYCAAsgBkUNAAJAIAUgBSgCHCICQQJ0QeSGAWoiBCgCAEYEQCAEIAE2AgAgAQ0BQbiEAUG4hAEoAgBBfiACd3E2AgAMAgsgBkEQQRQgBigCECAFRhtqIAE2AgAgAUUNAQsgASAGNgIYIAUoAhAiAgRAIAEgAjYCECACIAE2AhgLIAUoAhQiAkUNACABIAI2AhQgAiABNgIYCyADIABBAXI2AgQgACADaiAANgIAIANByIQBKAIARw0BQbyEASAANgIADwsgBSABQX5xNgIEIAMgAEEBcjYCBCAAIANqIAA2AgALIABB/wFNBEAgAEEDdiIBQQN0QdyEAWohAAJ/QbSEASgCACICQQEgAXQiAXFFBEBBtIQBIAEgAnI2AgAgAAwBCyAAKAIICyECIAAgAzYCCCACIAM2AgwgAyAANgIMIAMgAjYCCA8LQR8hAiADQgA3AhAgAEH///8HTQRAIABBCHYiASABQYD+P2pBEHZBCHEiAXQiAiACQYDgH2pBEHZBBHEiAnQiBCAEQYCAD2pBEHZBAnEiBHRBD3YgASACciAEcmsiAUEBdCAAIAFBFWp2QQFxckEcaiECCyADIAI2AhwgAkECdEHkhgFqIQECQAJAAkBBuIQBKAIAIgRBASACdCIHcUUEQEG4hAEgBCAHcjYCACABIAM2AgAgAyABNgIYDAELIABBAEEZIAJBAXZrIAJBH0YbdCECIAEoAgAhAQNAIAEiBCgCBEF4cSAARg0CIAJBHXYhASACQQF0IQIgBCABQQRxaiIHQRBqKAIAIgENAAsgByADNgIQIAMgBDYCGAsgAyADNgIMIAMgAzYCCAwBCyAEKAIIIgAgAzYCDCAEIAM2AgggA0EANgIYIAMgBDYCDCADIAA2AggLQdSEAUHUhAEoAgBBAWsiAEF/IAAbNgIACwuDBAEDfyACQYAETwRAIAAgASACEAIaIAAPCyAAIAJqIQMCQCAAIAFzQQNxRQRAAkAgAEEDcUUEQCAAIQIMAQsgAkEBSARAIAAhAgwBCyAAIQIDQCACIAEtAAA6AAAgAUEBaiEBIAJBAWoiAkEDcUUNASACIANJDQALCwJAIANBfHEiBEHAAEkNACACIARBQGoiBUsNAANAIAIgASgCADYCACACIAEoAgQ2AgQgAiABKAIINgIIIAIgASgCDDYCDCACIAEoAhA2AhAgAiABKAIUNgIUIAIgASgCGDYCGCACIAEoAhw2AhwgAiABKAIgNgIgIAIgASgCJDYCJCACIAEoAig2AiggAiABKAIsNgIsIAIgASgCMDYCMCACIAEoAjQ2AjQgAiABKAI4NgI4IAIgASgCPDYCPCABQUBrIQEgAkFAayICIAVNDQALCyACIARPDQEDQCACIAEoAgA2AgAgAUEEaiEBIAJBBGoiAiAESQ0ACwwBCyADQQRJBEAgACECDAELIAAgA0EEayIESwRAIAAhAgwBCyAAIQIDQCACIAEtAAA6AAAgAiABLQABOgABIAIgAS0AAjoAAiACIAEtAAM6AAMgAUEEaiEBIAJBBGoiAiAETQ0ACwsgAiADSQRAA0AgAiABLQAAOgAAIAFBAWohASACQQFqIgIgA0cNAAsLIAALGgAgAARAIAAtAAEEQCAAKAIEEAYLIAAQBgsLoi4BDH8jAEEQayIMJAACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAEH0AU0EQEG0hAEoAgAiBUEQIABBC2pBeHEgAEELSRsiCEEDdiICdiIBQQNxBEAgAUF/c0EBcSACaiIDQQN0IgFB5IQBaigCACIEQQhqIQACQCAEKAIIIgIgAUHchAFqIgFGBEBBtIQBIAVBfiADd3E2AgAMAQsgAiABNgIMIAEgAjYCCAsgBCADQQN0IgFBA3I2AgQgASAEaiIBIAEoAgRBAXI2AgQMDQsgCEG8hAEoAgAiCk0NASABBEACQEECIAJ0IgBBACAAa3IgASACdHEiAEEAIABrcUEBayIAIABBDHZBEHEiAnYiAUEFdkEIcSIAIAJyIAEgAHYiAUECdkEEcSIAciABIAB2IgFBAXZBAnEiAHIgASAAdiIBQQF2QQFxIgByIAEgAHZqIgNBA3QiAEHkhAFqKAIAIgQoAggiASAAQdyEAWoiAEYEQEG0hAEgBUF+IAN3cSIFNgIADAELIAEgADYCDCAAIAE2AggLIARBCGohACAEIAhBA3I2AgQgBCAIaiICIANBA3QiASAIayIDQQFyNgIEIAEgBGogAzYCACAKBEAgCkEDdiIBQQN0QdyEAWohB0HIhAEoAgAhBAJ/IAVBASABdCIBcUUEQEG0hAEgASAFcjYCACAHDAELIAcoAggLIQEgByAENgIIIAEgBDYCDCAEIAc2AgwgBCABNgIIC0HIhAEgAjYCAEG8hAEgAzYCAAwNC0G4hAEoAgAiBkUNASAGQQAgBmtxQQFrIgAgAEEMdkEQcSICdiIBQQV2QQhxIgAgAnIgASAAdiIBQQJ2QQRxIgByIAEgAHYiAUEBdkECcSIAciABIAB2IgFBAXZBAXEiAHIgASAAdmpBAnRB5IYBaigCACIBKAIEQXhxIAhrIQMgASECA0ACQCACKAIQIgBFBEAgAigCFCIARQ0BCyAAKAIEQXhxIAhrIgIgAyACIANJIgIbIQMgACABIAIbIQEgACECDAELCyABIAhqIgkgAU0NAiABKAIYIQsgASABKAIMIgRHBEAgASgCCCIAQcSEASgCAEkaIAAgBDYCDCAEIAA2AggMDAsgAUEUaiICKAIAIgBFBEAgASgCECIARQ0EIAFBEGohAgsDQCACIQcgACIEQRRqIgIoAgAiAA0AIARBEGohAiAEKAIQIgANAAsgB0EANgIADAsLQX8hCCAAQb9/Sw0AIABBC2oiAEF4cSEIQbiEASgCACIJRQ0AQQAgCGshAwJAAkACQAJ/QQAgCEGAAkkNABpBHyAIQf///wdLDQAaIABBCHYiACAAQYD+P2pBEHZBCHEiAnQiACAAQYDgH2pBEHZBBHEiAXQiACAAQYCAD2pBEHZBAnEiAHRBD3YgASACciAAcmsiAEEBdCAIIABBFWp2QQFxckEcagsiBUECdEHkhgFqKAIAIgJFBEBBACEADAELQQAhACAIQQBBGSAFQQF2ayAFQR9GG3QhAQNAAkAgAigCBEF4cSAIayIHIANPDQAgAiEEIAciAw0AQQAhAyACIQAMAwsgACACKAIUIgcgByACIAFBHXZBBHFqKAIQIgJGGyAAIAcbIQAgAUEBdCEBIAINAAsLIAAgBHJFBEBBAiAFdCIAQQAgAGtyIAlxIgBFDQMgAEEAIABrcUEBayIAIABBDHZBEHEiAnYiAUEFdkEIcSIAIAJyIAEgAHYiAUECdkEEcSIAciABIAB2IgFBAXZBAnEiAHIgASAAdiIBQQF2QQFxIgByIAEgAHZqQQJ0QeSGAWooAgAhAAsgAEUNAQsDQCAAKAIEQXhxIAhrIgEgA0khAiABIAMgAhshAyAAIAQgAhshBCAAKAIQIgEEfyABBSAAKAIUCyIADQALCyAERQ0AIANBvIQBKAIAIAhrTw0AIAQgCGoiBiAETQ0BIAQoAhghBSAEIAQoAgwiAUcEQCAEKAIIIgBBxIQBKAIASRogACABNgIMIAEgADYCCAwKCyAEQRRqIgIoAgAiAEUEQCAEKAIQIgBFDQQgBEEQaiECCwNAIAIhByAAIgFBFGoiAigCACIADQAgAUEQaiECIAEoAhAiAA0ACyAHQQA2AgAMCQsgCEG8hAEoAgAiAk0EQEHIhAEoAgAhAwJAIAIgCGsiAUEQTwRAQbyEASABNgIAQciEASADIAhqIgA2AgAgACABQQFyNgIEIAIgA2ogATYCACADIAhBA3I2AgQMAQtByIQBQQA2AgBBvIQBQQA2AgAgAyACQQNyNgIEIAIgA2oiACAAKAIEQQFyNgIECyADQQhqIQAMCwsgCEHAhAEoAgAiBkkEQEHAhAEgBiAIayIBNgIAQcyEAUHMhAEoAgAiAiAIaiIANgIAIAAgAUEBcjYCBCACIAhBA3I2AgQgAkEIaiEADAsLQQAhACAIQS9qIgkCf0GMiAEoAgAEQEGUiAEoAgAMAQtBmIgBQn83AgBBkIgBQoCggICAgAQ3AgBBjIgBIAxBDGpBcHFB2KrVqgVzNgIAQaCIAUEANgIAQfCHAUEANgIAQYAgCyIBaiIFQQAgAWsiB3EiAiAITQ0KQeyHASgCACIEBEBB5IcBKAIAIgMgAmoiASADTQ0LIAEgBEsNCwtB8IcBLQAAQQRxDQUCQAJAQcyEASgCACIDBEBB9IcBIQADQCADIAAoAgAiAU8EQCABIAAoAgRqIANLDQMLIAAoAggiAA0ACwtBABApIgFBf0YNBiACIQVBkIgBKAIAIgNBAWsiACABcQRAIAIgAWsgACABakEAIANrcWohBQsgBSAITQ0GIAVB/v///wdLDQZB7IcBKAIAIgQEQEHkhwEoAgAiAyAFaiIAIANNDQcgACAESw0HCyAFECkiACABRw0BDAgLIAUgBmsgB3EiBUH+////B0sNBSAFECkiASAAKAIAIAAoAgRqRg0EIAEhAAsCQCAAQX9GDQAgCEEwaiAFTQ0AQZSIASgCACIBIAkgBWtqQQAgAWtxIgFB/v///wdLBEAgACEBDAgLIAEQKUF/RwRAIAEgBWohBSAAIQEMCAtBACAFaxApGgwFCyAAIgFBf0cNBgwECwALQQAhBAwHC0EAIQEMBQsgAUF/Rw0CC0HwhwFB8IcBKAIAQQRyNgIACyACQf7///8HSw0BIAIQKSEBQQAQKSEAIAFBf0YNASAAQX9GDQEgACABTQ0BIAAgAWsiBSAIQShqTQ0BC0HkhwFB5IcBKAIAIAVqIgA2AgBB6IcBKAIAIABJBEBB6IcBIAA2AgALAkACQAJAQcyEASgCACIHBEBB9IcBIQADQCABIAAoAgAiAyAAKAIEIgJqRg0CIAAoAggiAA0ACwwCC0HEhAEoAgAiAEEAIAAgAU0bRQRAQcSEASABNgIAC0EAIQBB+IcBIAU2AgBB9IcBIAE2AgBB1IQBQX82AgBB2IQBQYyIASgCADYCAEGAiAFBADYCAANAIABBA3QiA0HkhAFqIANB3IQBaiICNgIAIANB6IQBaiACNgIAIABBAWoiAEEgRw0AC0HAhAEgBUEoayIDQXggAWtBB3FBACABQQhqQQdxGyIAayICNgIAQcyEASAAIAFqIgA2AgAgACACQQFyNgIEIAEgA2pBKDYCBEHQhAFBnIgBKAIANgIADAILIAAtAAxBCHENACADIAdLDQAgASAHTQ0AIAAgAiAFajYCBEHMhAEgB0F4IAdrQQdxQQAgB0EIakEHcRsiAGoiAjYCAEHAhAFBwIQBKAIAIAVqIgEgAGsiADYCACACIABBAXI2AgQgASAHakEoNgIEQdCEAUGciAEoAgA2AgAMAQtBxIQBKAIAIAFLBEBBxIQBIAE2AgALIAEgBWohAkH0hwEhAAJAAkACQAJAAkACQANAIAIgACgCAEcEQCAAKAIIIgANAQwCCwsgAC0ADEEIcUUNAQtB9IcBIQADQCAHIAAoAgAiAk8EQCACIAAoAgRqIgQgB0sNAwsgACgCCCEADAALAAsgACABNgIAIAAgACgCBCAFajYCBCABQXggAWtBB3FBACABQQhqQQdxG2oiCSAIQQNyNgIEIAJBeCACa0EHcUEAIAJBCGpBB3EbaiIFIAggCWoiBmshAiAFIAdGBEBBzIQBIAY2AgBBwIQBQcCEASgCACACaiIANgIAIAYgAEEBcjYCBAwDCyAFQciEASgCAEYEQEHIhAEgBjYCAEG8hAFBvIQBKAIAIAJqIgA2AgAgBiAAQQFyNgIEIAAgBmogADYCAAwDCyAFKAIEIgBBA3FBAUYEQCAAQXhxIQcCQCAAQf8BTQRAIAUoAggiAyAAQQN2IgBBA3RB3IQBakYaIAMgBSgCDCIBRgRAQbSEAUG0hAEoAgBBfiAAd3E2AgAMAgsgAyABNgIMIAEgAzYCCAwBCyAFKAIYIQgCQCAFIAUoAgwiAUcEQCAFKAIIIgAgATYCDCABIAA2AggMAQsCQCAFQRRqIgAoAgAiAw0AIAVBEGoiACgCACIDDQBBACEBDAELA0AgACEEIAMiAUEUaiIAKAIAIgMNACABQRBqIQAgASgCECIDDQALIARBADYCAAsgCEUNAAJAIAUgBSgCHCIDQQJ0QeSGAWoiACgCAEYEQCAAIAE2AgAgAQ0BQbiEAUG4hAEoAgBBfiADd3E2AgAMAgsgCEEQQRQgCCgCECAFRhtqIAE2AgAgAUUNAQsgASAINgIYIAUoAhAiAARAIAEgADYCECAAIAE2AhgLIAUoAhQiAEUNACABIAA2AhQgACABNgIYCyAFIAdqIQUgAiAHaiECCyAFIAUoAgRBfnE2AgQgBiACQQFyNgIEIAIgBmogAjYCACACQf8BTQRAIAJBA3YiAEEDdEHchAFqIQICf0G0hAEoAgAiAUEBIAB0IgBxRQRAQbSEASAAIAFyNgIAIAIMAQsgAigCCAshACACIAY2AgggACAGNgIMIAYgAjYCDCAGIAA2AggMAwtBHyEAIAJB////B00EQCACQQh2IgAgAEGA/j9qQRB2QQhxIgN0IgAgAEGA4B9qQRB2QQRxIgF0IgAgAEGAgA9qQRB2QQJxIgB0QQ92IAEgA3IgAHJrIgBBAXQgAiAAQRVqdkEBcXJBHGohAAsgBiAANgIcIAZCADcCECAAQQJ0QeSGAWohBAJAQbiEASgCACIDQQEgAHQiAXFFBEBBuIQBIAEgA3I2AgAgBCAGNgIAIAYgBDYCGAwBCyACQQBBGSAAQQF2ayAAQR9GG3QhACAEKAIAIQEDQCABIgMoAgRBeHEgAkYNAyAAQR12IQEgAEEBdCEAIAMgAUEEcWoiBCgCECIBDQALIAQgBjYCECAGIAM2AhgLIAYgBjYCDCAGIAY2AggMAgtBwIQBIAVBKGsiA0F4IAFrQQdxQQAgAUEIakEHcRsiAGsiAjYCAEHMhAEgACABaiIANgIAIAAgAkEBcjYCBCABIANqQSg2AgRB0IQBQZyIASgCADYCACAHIARBJyAEa0EHcUEAIARBJ2tBB3EbakEvayIAIAAgB0EQakkbIgJBGzYCBCACQfyHASkCADcCECACQfSHASkCADcCCEH8hwEgAkEIajYCAEH4hwEgBTYCAEH0hwEgATYCAEGAiAFBADYCACACQRhqIQADQCAAQQc2AgQgAEEIaiEBIABBBGohACABIARJDQALIAIgB0YNAyACIAIoAgRBfnE2AgQgByACIAdrIgRBAXI2AgQgAiAENgIAIARB/wFNBEAgBEEDdiIAQQN0QdyEAWohAgJ/QbSEASgCACIBQQEgAHQiAHFFBEBBtIQBIAAgAXI2AgAgAgwBCyACKAIICyEAIAIgBzYCCCAAIAc2AgwgByACNgIMIAcgADYCCAwEC0EfIQAgB0IANwIQIARB////B00EQCAEQQh2IgAgAEGA/j9qQRB2QQhxIgJ0IgAgAEGA4B9qQRB2QQRxIgF0IgAgAEGAgA9qQRB2QQJxIgB0QQ92IAEgAnIgAHJrIgBBAXQgBCAAQRVqdkEBcXJBHGohAAsgByAANgIcIABBAnRB5IYBaiEDAkBBuIQBKAIAIgJBASAAdCIBcUUEQEG4hAEgASACcjYCACADIAc2AgAgByADNgIYDAELIARBAEEZIABBAXZrIABBH0YbdCEAIAMoAgAhAQNAIAEiAigCBEF4cSAERg0EIABBHXYhASAAQQF0IQAgAiABQQRxaiIDKAIQIgENAAsgAyAHNgIQIAcgAjYCGAsgByAHNgIMIAcgBzYCCAwDCyADKAIIIgAgBjYCDCADIAY2AgggBkEANgIYIAYgAzYCDCAGIAA2AggLIAlBCGohAAwFCyACKAIIIgAgBzYCDCACIAc2AgggB0EANgIYIAcgAjYCDCAHIAA2AggLQcCEASgCACIAIAhNDQBBwIQBIAAgCGsiATYCAEHMhAFBzIQBKAIAIgIgCGoiADYCACAAIAFBAXI2AgQgAiAIQQNyNgIEIAJBCGohAAwDC0GEhAFBMDYCAEEAIQAMAgsCQCAFRQ0AAkAgBCgCHCICQQJ0QeSGAWoiACgCACAERgRAIAAgATYCACABDQFBuIQBIAlBfiACd3EiCTYCAAwCCyAFQRBBFCAFKAIQIARGG2ogATYCACABRQ0BCyABIAU2AhggBCgCECIABEAgASAANgIQIAAgATYCGAsgBCgCFCIARQ0AIAEgADYCFCAAIAE2AhgLAkAgA0EPTQRAIAQgAyAIaiIAQQNyNgIEIAAgBGoiACAAKAIEQQFyNgIEDAELIAQgCEEDcjYCBCAGIANBAXI2AgQgAyAGaiADNgIAIANB/wFNBEAgA0EDdiIAQQN0QdyEAWohAgJ/QbSEASgCACIBQQEgAHQiAHFFBEBBtIQBIAAgAXI2AgAgAgwBCyACKAIICyEAIAIgBjYCCCAAIAY2AgwgBiACNgIMIAYgADYCCAwBC0EfIQAgA0H///8HTQRAIANBCHYiACAAQYD+P2pBEHZBCHEiAnQiACAAQYDgH2pBEHZBBHEiAXQiACAAQYCAD2pBEHZBAnEiAHRBD3YgASACciAAcmsiAEEBdCADIABBFWp2QQFxckEcaiEACyAGIAA2AhwgBkIANwIQIABBAnRB5IYBaiECAkACQCAJQQEgAHQiAXFFBEBBuIQBIAEgCXI2AgAgAiAGNgIAIAYgAjYCGAwBCyADQQBBGSAAQQF2ayAAQR9GG3QhACACKAIAIQgDQCAIIgEoAgRBeHEgA0YNAiAAQR12IQIgAEEBdCEAIAEgAkEEcWoiAigCECIIDQALIAIgBjYCECAGIAE2AhgLIAYgBjYCDCAGIAY2AggMAQsgASgCCCIAIAY2AgwgASAGNgIIIAZBADYCGCAGIAE2AgwgBiAANgIICyAEQQhqIQAMAQsCQCALRQ0AAkAgASgCHCICQQJ0QeSGAWoiACgCACABRgRAIAAgBDYCACAEDQFBuIQBIAZBfiACd3E2AgAMAgsgC0EQQRQgCygCECABRhtqIAQ2AgAgBEUNAQsgBCALNgIYIAEoAhAiAARAIAQgADYCECAAIAQ2AhgLIAEoAhQiAEUNACAEIAA2AhQgACAENgIYCwJAIANBD00EQCABIAMgCGoiAEEDcjYCBCAAIAFqIgAgACgCBEEBcjYCBAwBCyABIAhBA3I2AgQgCSADQQFyNgIEIAMgCWogAzYCACAKBEAgCkEDdiIAQQN0QdyEAWohBEHIhAEoAgAhAgJ/QQEgAHQiACAFcUUEQEG0hAEgACAFcjYCACAEDAELIAQoAggLIQAgBCACNgIIIAAgAjYCDCACIAQ2AgwgAiAANgIIC0HIhAEgCTYCAEG8hAEgAzYCAAsgAUEIaiEACyAMQRBqJAAgAAuJAQEDfyAAKAIcIgEQMAJAIAAoAhAiAiABKAIQIgMgAiADSRsiAkUNACAAKAIMIAEoAgggAhAHGiAAIAAoAgwgAmo2AgwgASABKAIIIAJqNgIIIAAgACgCFCACajYCFCAAIAAoAhAgAms2AhAgASABKAIQIAJrIgA2AhAgAA0AIAEgASgCBDYCCAsLzgEBBX8CQCAARQ0AIAAoAjAiAQRAIAAgAUEBayIBNgIwIAENAQsgACgCIARAIABBATYCICAAEBoaCyAAKAIkQQFGBEAgABBDCwJAIAAoAiwiAUUNACAALQAoDQACQCABKAJEIgNFDQAgASgCTCEEA0AgACAEIAJBAnRqIgUoAgBHBEAgAyACQQFqIgJHDQEMAgsLIAUgBCADQQFrIgJBAnRqKAIANgIAIAEgAjYCRAsLIABBAEIAQQUQDhogACgCACIBBEAgARALCyAAEAYLC1oCAn4BfwJ/AkACQCAALQAARQ0AIAApAxAiAUJ9Vg0AIAFCAnwiAiAAKQMIWA0BCyAAQQA6AABBAAwBC0EAIAAoAgQiA0UNABogACACNwMQIAMgAadqLwAACwthAgJ+AX8CQAJAIAAtAABFDQAgACkDECICQn1WDQAgAkICfCIDIAApAwhYDQELIABBADoAAA8LIAAoAgQiBEUEQA8LIAAgAzcDECAEIAKnaiIAIAFBCHY6AAEgACABOgAAC8wCAQJ/IwBBEGsiBCQAAkAgACkDGCADrYinQQFxRQRAIABBDGoiAARAIABBADYCBCAAQRw2AgALQn8hAgwBCwJ+IAAoAgAiBUUEQCAAKAIIIAEgAiADIAAoAgQRDAAMAQsgBSAAKAIIIAEgAiADIAAoAgQRCgALIgJCf1UNAAJAIANBBGsOCwEAAAAAAAAAAAABAAsCQAJAIAAtABhBEHFFBEAgAEEMaiIBBEAgAUEANgIEIAFBHDYCAAsMAQsCfiAAKAIAIgFFBEAgACgCCCAEQQhqQghBBCAAKAIEEQwADAELIAEgACgCCCAEQQhqQghBBCAAKAIEEQoAC0J/VQ0BCyAAQQxqIgAEQCAAQQA2AgQgAEEUNgIACwwBCyAEKAIIIQEgBCgCDCEDIABBDGoiAARAIAAgAzYCBCAAIAE2AgALCyAEQRBqJAAgAguTFQIOfwN+AkACQAJAAkACQAJAAkACQAJAAkACQCAAKALwLQRAIAAoAogBQQFIDQEgACgCACIEKAIsQQJHDQQgAC8B5AENAyAALwHoAQ0DIAAvAewBDQMgAC8B8AENAyAALwH0AQ0DIAAvAfgBDQMgAC8B/AENAyAALwGcAg0DIAAvAaACDQMgAC8BpAINAyAALwGoAg0DIAAvAawCDQMgAC8BsAINAyAALwG0Ag0DIAAvAbgCDQMgAC8BvAINAyAALwHAAg0DIAAvAcQCDQMgAC8ByAINAyAALwHUAg0DIAAvAdgCDQMgAC8B3AINAyAALwHgAg0DIAAvAYgCDQIgAC8BjAINAiAALwGYAg0CQSAhBgNAIAAgBkECdCIFai8B5AENAyAAIAVBBHJqLwHkAQ0DIAAgBUEIcmovAeQBDQMgACAFQQxyai8B5AENAyAGQQRqIgZBgAJHDQALDAMLIABBBzYC/C0gAkF8Rw0FIAFFDQUMBgsgAkEFaiIEIQcMAwtBASEHCyAEIAc2AiwLIAAgAEHoFmoQUSAAIABB9BZqEFEgAC8B5gEhBCAAIABB7BZqKAIAIgxBAnRqQf//AzsB6gEgAEGQFmohECAAQZQWaiERIABBjBZqIQdBACEGIAxBAE4EQEEHQYoBIAQbIQ1BBEEDIAQbIQpBfyEJA0AgBCEIIAAgCyIOQQFqIgtBAnRqLwHmASEEAkACQCAGQQFqIgVB//8DcSIPIA1B//8DcU8NACAEIAhHDQAgBSEGDAELAn8gACAIQQJ0akHMFWogCkH//wNxIA9LDQAaIAgEQEEBIQUgByAIIAlGDQEaIAAgCEECdGpBzBVqIgYgBi8BAEEBajsBACAHDAELQQEhBSAQIBEgBkH//wNxQQpJGwsiBiAGLwEAIAVqOwEAQQAhBgJ/IARFBEBBAyEKQYoBDAELQQNBBCAEIAhGIgUbIQpBBkEHIAUbCyENIAghCQsgDCAORw0ACwsgAEHaE2ovAQAhBCAAIABB+BZqKAIAIgxBAnRqQd4TakH//wM7AQBBACEGIAxBAE4EQEEHQYoBIAQbIQ1BBEEDIAQbIQpBfyEJQQAhCwNAIAQhCCAAIAsiDkEBaiILQQJ0akHaE2ovAQAhBAJAAkAgBkEBaiIFQf//A3EiDyANQf//A3FPDQAgBCAIRw0AIAUhBgwBCwJ/IAAgCEECdGpBzBVqIApB//8DcSAPSw0AGiAIBEBBASEFIAcgCCAJRg0BGiAAIAhBAnRqQcwVaiIGIAYvAQBBAWo7AQAgBwwBC0EBIQUgECARIAZB//8DcUEKSRsLIgYgBi8BACAFajsBAEEAIQYCfyAERQRAQQMhCkGKAQwBC0EDQQQgBCAIRiIFGyEKQQZBByAFGwshDSAIIQkLIAwgDkcNAAsLIAAgAEGAF2oQUSAAIAAoAvgtAn9BEiAAQYoWai8BAA0AGkERIABB0hVqLwEADQAaQRAgAEGGFmovAQANABpBDyAAQdYVai8BAA0AGkEOIABBghZqLwEADQAaQQ0gAEHaFWovAQANABpBDCAAQf4Vai8BAA0AGkELIABB3hVqLwEADQAaQQogAEH6FWovAQANABpBCSAAQeIVai8BAA0AGkEIIABB9hVqLwEADQAaQQcgAEHmFWovAQANABpBBiAAQfIVai8BAA0AGkEFIABB6hVqLwEADQAaQQQgAEHuFWovAQANABpBA0ECIABBzhVqLwEAGwsiBkEDbGoiBEERajYC+C0gACgC/C1BCmpBA3YiByAEQRtqQQN2IgRNBEAgByEEDAELIAAoAowBQQRHDQAgByEECyAEIAJBBGpPQQAgARsNASAEIAdHDQQLIANBAmqtIRIgACkDmC4hFCAAKAKgLiIBQQNqIgdBP0sNASASIAGthiAUhCESDAILIAAgASACIAMQOQwDCyABQcAARgRAIAAoAgQgACgCEGogFDcAACAAIAAoAhBBCGo2AhBBAyEHDAELIAAoAgQgACgCEGogEiABrYYgFIQ3AAAgACAAKAIQQQhqNgIQIAFBPWshByASQcAAIAFrrYghEgsgACASNwOYLiAAIAc2AqAuIABBgMEAQYDKABCHAQwBCyADQQRqrSESIAApA5guIRQCQCAAKAKgLiIBQQNqIgRBP00EQCASIAGthiAUhCESDAELIAFBwABGBEAgACgCBCAAKAIQaiAUNwAAIAAgACgCEEEIajYCEEEDIQQMAQsgACgCBCAAKAIQaiASIAGthiAUhDcAACAAIAAoAhBBCGo2AhAgAUE9ayEEIBJBwAAgAWutiCESCyAAIBI3A5guIAAgBDYCoC4gAEHsFmooAgAiC6xCgAJ9IRMgAEH4FmooAgAhCQJAAkACfwJ+AkACfwJ/IARBOk0EQCATIASthiAShCETIARBBWoMAQsgBEHAAEYEQCAAKAIEIAAoAhBqIBI3AAAgACAAKAIQQQhqNgIQIAmsIRJCBSEUQQoMAgsgACgCBCAAKAIQaiATIASthiAShDcAACAAIAAoAhBBCGo2AhAgE0HAACAEa62IIRMgBEE7awshBSAJrCESIAVBOksNASAFrSEUIAVBBWoLIQcgEiAUhiAThAwBCyAFQcAARgRAIAAoAgQgACgCEGogEzcAACAAIAAoAhBBCGo2AhAgBq1CA30hE0IFIRRBCQwCCyAAKAIEIAAoAhBqIBIgBa2GIBOENwAAIAAgACgCEEEIajYCECAFQTtrIQcgEkHAACAFa62ICyESIAatQgN9IRMgB0E7Sw0BIAetIRQgB0EEagshBCATIBSGIBKEIRMMAQsgB0HAAEYEQCAAKAIEIAAoAhBqIBI3AAAgACAAKAIQQQhqNgIQQQQhBAwBCyAAKAIEIAAoAhBqIBMgB62GIBKENwAAIAAgACgCEEEIajYCECAHQTxrIQQgE0HAACAHa62IIRMLQQAhBQNAIAAgBSIBQZDWAGotAABBAnRqQc4VajMBACEUAn8gBEE8TQRAIBQgBK2GIBOEIRMgBEEDagwBCyAEQcAARgRAIAAoAgQgACgCEGogEzcAACAAIAAoAhBBCGo2AhAgFCETQQMMAQsgACgCBCAAKAIQaiAUIASthiAThDcAACAAIAAoAhBBCGo2AhAgFEHAACAEa62IIRMgBEE9awshBCABQQFqIQUgASAGRw0ACyAAIAQ2AqAuIAAgEzcDmC4gACAAQeQBaiICIAsQhgEgACAAQdgTaiIBIAkQhgEgACACIAEQhwELIAAQiAEgAwRAAkAgACgCoC4iBEE5TgRAIAAoAgQgACgCEGogACkDmC43AAAgACAAKAIQQQhqNgIQDAELIARBGU4EQCAAKAIEIAAoAhBqIAApA5guPgAAIAAgAEGcLmo1AgA3A5guIAAgACgCEEEEajYCECAAIAAoAqAuQSBrIgQ2AqAuCyAEQQlOBH8gACgCBCAAKAIQaiAAKQOYLj0AACAAIAAoAhBBAmo2AhAgACAAKQOYLkIQiDcDmC4gACgCoC5BEGsFIAQLQQFIDQAgACAAKAIQIgFBAWo2AhAgASAAKAIEaiAAKQOYLjwAAAsgAEEANgKgLiAAQgA3A5guCwsZACAABEAgACgCABAGIAAoAgwQBiAAEAYLC6wBAQJ+Qn8hAwJAIAAtACgNAAJAAkAgACgCIEUNACACQgBTDQAgAlANASABDQELIABBDGoiAARAIABBADYCBCAAQRI2AgALQn8PCyAALQA1DQBCACEDIAAtADQNACACUA0AA0AgACABIAOnaiACIAN9QQEQDiIEQn9XBEAgAEEBOgA1Qn8gAyADUBsPCyAEUEUEQCADIAR8IgMgAloNAgwBCwsgAEEBOgA0CyADC3UCAn4BfwJAAkAgAC0AAEUNACAAKQMQIgJCe1YNACACQgR8IgMgACkDCFgNAQsgAEEAOgAADwsgACgCBCIERQRADwsgACADNwMQIAQgAqdqIgAgAUEYdjoAAyAAIAFBEHY6AAIgACABQQh2OgABIAAgAToAAAtUAgF+AX8CQAJAIAAtAABFDQAgASAAKQMQIgF8IgIgAVQNACACIAApAwhYDQELIABBADoAAEEADwsgACgCBCIDRQRAQQAPCyAAIAI3AxAgAyABp2oLdwECfyMAQRBrIgMkAEF/IQQCQCAALQAoDQAgACgCIEEAIAJBA0kbRQRAIABBDGoiAARAIABBADYCBCAAQRI2AgALDAELIAMgAjYCCCADIAE3AwAgACADQhBBBhAOQgBTDQBBACEEIABBADoANAsgA0EQaiQAIAQLVwICfgF/AkACQCAALQAARQ0AIAApAxAiAUJ7Vg0AIAFCBHwiAiAAKQMIWA0BCyAAQQA6AABBAA8LIAAoAgQiA0UEQEEADwsgACACNwMQIAMgAadqKAAAC1UCAX4BfyAABEACQCAAKQMIUA0AQgEhAQNAIAAoAgAgAkEEdGoQPiABIAApAwhaDQEgAachAiABQgF8IQEMAAsACyAAKAIAEAYgACgCKBAQIAAQBgsLZAECfwJAAkACQCAARQRAIAGnEAkiA0UNAkEYEAkiAkUNAQwDCyAAIQNBGBAJIgINAkEADwsgAxAGC0EADwsgAkIANwMQIAIgATcDCCACIAM2AgQgAkEBOgAAIAIgAEU6AAEgAgudAQICfgF/AkACQCAALQAARQ0AIAApAxAiAkJ3Vg0AIAJCCHwiAyAAKQMIWA0BCyAAQQA6AAAPCyAAKAIEIgRFBEAPCyAAIAM3AxAgBCACp2oiACABQjiIPAAHIAAgAUIwiDwABiAAIAFCKIg8AAUgACABQiCIPAAEIAAgAUIYiDwAAyAAIAFCEIg8AAIgACABQgiIPAABIAAgATwAAAvwAgICfwF+AkAgAkUNACAAIAJqIgNBAWsgAToAACAAIAE6AAAgAkEDSQ0AIANBAmsgAToAACAAIAE6AAEgA0EDayABOgAAIAAgAToAAiACQQdJDQAgA0EEayABOgAAIAAgAToAAyACQQlJDQAgAEEAIABrQQNxIgRqIgMgAUH/AXFBgYKECGwiADYCACADIAIgBGtBfHEiAmoiAUEEayAANgIAIAJBCUkNACADIAA2AgggAyAANgIEIAFBCGsgADYCACABQQxrIAA2AgAgAkEZSQ0AIAMgADYCGCADIAA2AhQgAyAANgIQIAMgADYCDCABQRBrIAA2AgAgAUEUayAANgIAIAFBGGsgADYCACABQRxrIAA2AgAgAiADQQRxQRhyIgFrIgJBIEkNACAArUKBgICAEH4hBSABIANqIQEDQCABIAU3AxggASAFNwMQIAEgBTcDCCABIAU3AwAgAUEgaiEBIAJBIGsiAkEfSw0ACwsLbwEDfyAAQQxqIQICQAJ/IAAoAiAiAUUEQEF/IQFBEgwBCyAAIAFBAWsiAzYCIEEAIQEgAw0BIABBAEIAQQIQDhogACgCACIARQ0BIAAQGkF/Sg0BQRQLIQAgAgRAIAJBADYCBCACIAA2AgALCyABC58BAgF/AX4CfwJAAn4gACgCACIDKAIkQQFGQQAgAkJ/VRtFBEAgA0EMaiIBBEAgAUEANgIEIAFBEjYCAAtCfwwBCyADIAEgAkELEA4LIgRCf1cEQCAAKAIAIQEgAEEIaiIABEAgACABKAIMNgIAIAAgASgCEDYCBAsMAQtBACACIARRDQEaIABBCGoEQCAAQRs2AgwgAEEGNgIICwtBfwsLJAEBfyAABEADQCAAKAIAIQEgACgCDBAGIAAQBiABIgANAAsLC5gBAgJ+AX8CQAJAIAAtAABFDQAgACkDECIBQndWDQAgAUIIfCICIAApAwhYDQELIABBADoAAEIADwsgACgCBCIDRQRAQgAPCyAAIAI3AxAgAyABp2oiADEABkIwhiAAMQAHQjiGhCAAMQAFQiiGhCAAMQAEQiCGhCAAMQADQhiGhCAAMQACQhCGhCAAMQABQgiGhCAAMQAAfAsjACAAQShGBEAgAhAGDwsgAgRAIAEgAkEEaygCACAAEQcACwsyACAAKAIkQQFHBEAgAEEMaiIABEAgAEEANgIEIABBEjYCAAtCfw8LIABBAEIAQQ0QDgsPACAABEAgABA2IAAQBgsLgAEBAX8gAC0AKAR/QX8FIAFFBEAgAEEMagRAIABBADYCECAAQRI2AgwLQX8PCyABECoCQCAAKAIAIgJFDQAgAiABECFBf0oNACAAKAIAIQEgAEEMaiIABEAgACABKAIMNgIAIAAgASgCEDYCBAtBfw8LIAAgAUI4QQMQDkI/h6cLC38BA38gACEBAkAgAEEDcQRAA0AgAS0AAEUNAiABQQFqIgFBA3ENAAsLA0AgASICQQRqIQEgAigCACIDQX9zIANBgYKECGtxQYCBgoR4cUUNAAsgA0H/AXFFBEAgAiAAaw8LA0AgAi0AASEDIAJBAWoiASECIAMNAAsLIAEgAGsL3wIBCH8gAEUEQEEBDwsCQCAAKAIIIgINAEEBIQQgAC8BBCIHRQRAQQEhAgwBCyAAKAIAIQgDQAJAIAMgCGoiBS0AACICQSBPBEAgAkEYdEEYdUF/Sg0BCyACQQ1NQQBBASACdEGAzABxGw0AAn8CfyACQeABcUHAAUYEQEEBIQYgA0EBagwBCyACQfABcUHgAUYEQCADQQJqIQNBACEGQQEMAgsgAkH4AXFB8AFHBEBBBCECDAULQQAhBiADQQNqCyEDQQALIQlBBCECIAMgB08NAiAFLQABQcABcUGAAUcNAkEDIQQgBg0AIAUtAAJBwAFxQYABRw0CIAkNACAFLQADQcABcUGAAUcNAgsgBCECIANBAWoiAyAHSQ0ACwsgACACNgIIAn8CQCABRQ0AAkAgAUECRw0AIAJBA0cNAEECIQIgAEECNgIICyABIAJGDQBBBSACQQFHDQEaCyACCwtIAgJ+An8jAEEQayIEIAE2AgxCASAArYYhAgNAIAQgAUEEaiIANgIMIAIiA0IBIAEoAgAiBa2GhCECIAAhASAFQX9KDQALIAMLhwUBB38CQAJAIABFBEBBxRQhAiABRQ0BIAFBADYCAEHFFA8LIAJBwABxDQEgACgCCEUEQCAAQQAQIxoLIAAoAgghBAJAIAJBgAFxBEAgBEEBa0ECTw0BDAMLIARBBEcNAgsCQCAAKAIMIgINACAAAn8gACgCACEIIABBEGohCUEAIQICQAJAAkACQCAALwEEIgUEQEEBIQQgBUEBcSEHIAVBAUcNAQwCCyAJRQ0CIAlBADYCAEEADAQLIAVBfnEhBgNAIARBAUECQQMgAiAIai0AAEEBdEHQFGovAQAiCkGAEEkbIApBgAFJG2pBAUECQQMgCCACQQFyai0AAEEBdEHQFGovAQAiBEGAEEkbIARBgAFJG2ohBCACQQJqIQIgBkECayIGDQALCwJ/IAcEQCAEQQFBAkEDIAIgCGotAABBAXRB0BRqLwEAIgJBgBBJGyACQYABSRtqIQQLIAQLEAkiB0UNASAFQQEgBUEBSxshCkEAIQVBACEGA0AgBSAHaiEDAn8gBiAIai0AAEEBdEHQFGovAQAiAkH/AE0EQCADIAI6AAAgBUEBagwBCyACQf8PTQRAIAMgAkE/cUGAAXI6AAEgAyACQQZ2QcABcjoAACAFQQJqDAELIAMgAkE/cUGAAXI6AAIgAyACQQx2QeABcjoAACADIAJBBnZBP3FBgAFyOgABIAVBA2oLIQUgBkEBaiIGIApHDQALIAcgBEEBayICakEAOgAAIAlFDQAgCSACNgIACyAHDAELIAMEQCADQQA2AgQgA0EONgIAC0EACyICNgIMIAINAEEADwsgAUUNACABIAAoAhA2AgALIAIPCyABBEAgASAALwEENgIACyAAKAIAC4MBAQR/QRIhBQJAAkAgACkDMCABWA0AIAGnIQYgACgCQCEEIAJBCHEiB0UEQCAEIAZBBHRqKAIEIgINAgsgBCAGQQR0aiIEKAIAIgJFDQAgBC0ADEUNAUEXIQUgBw0BC0EAIQIgAyAAQQhqIAMbIgAEQCAAQQA2AgQgACAFNgIACwsgAgtuAQF/IwBBgAJrIgUkAAJAIARBgMAEcQ0AIAIgA0wNACAFIAFB/wFxIAIgA2siAkGAAiACQYACSSIBGxAZIAFFBEADQCAAIAVBgAIQLiACQYACayICQf8BSw0ACwsgACAFIAIQLgsgBUGAAmokAAuBAQEBfyMAQRBrIgQkACACIANsIQICQCAAQSdGBEAgBEEMaiACEIwBIQBBACAEKAIMIAAbIQAMAQsgAUEBIAJBxABqIAARAAAiAUUEQEEAIQAMAQtBwAAgAUE/cWsiACABakHAAEEAIABBBEkbaiIAQQRrIAE2AAALIARBEGokACAAC1IBAn9BhIEBKAIAIgEgAEEDakF8cSICaiEAAkAgAkEAIAAgAU0bDQAgAD8AQRB0SwRAIAAQA0UNAQtBhIEBIAA2AgAgAQ8LQYSEAUEwNgIAQX8LNwAgAEJ/NwMQIABBADYCCCAAQgA3AwAgAEEANgIwIABC/////w83AyggAEIANwMYIABCADcDIAulAQEBf0HYABAJIgFFBEBBAA8LAkAgAARAIAEgAEHYABAHGgwBCyABQgA3AyAgAUEANgIYIAFC/////w83AxAgAUEAOwEMIAFBv4YoNgIIIAFBAToABiABQQA6AAQgAUIANwNIIAFBgIDYjXg2AkQgAUIANwMoIAFCADcDMCABQgA3AzggAUFAa0EAOwEAIAFCADcDUAsgAUEBOgAFIAFBADYCACABC1gCAn4BfwJAAkAgAC0AAEUNACAAKQMQIgMgAq18IgQgA1QNACAEIAApAwhYDQELIABBADoAAA8LIAAoAgQiBUUEQA8LIAAgBDcDECAFIAOnaiABIAIQBxoLlgEBAn8CQAJAIAJFBEAgAacQCSIFRQ0BQRgQCSIEDQIgBRAGDAELIAIhBUEYEAkiBA0BCyADBEAgA0EANgIEIANBDjYCAAtBAA8LIARCADcDECAEIAE3AwggBCAFNgIEIARBAToAACAEIAJFOgABIAAgBSABIAMQZUEASAR/IAQtAAEEQCAEKAIEEAYLIAQQBkEABSAECwubAgEDfyAALQAAQSBxRQRAAkAgASEDAkAgAiAAIgEoAhAiAAR/IAAFAn8gASABLQBKIgBBAWsgAHI6AEogASgCACIAQQhxBEAgASAAQSByNgIAQX8MAQsgAUIANwIEIAEgASgCLCIANgIcIAEgADYCFCABIAAgASgCMGo2AhBBAAsNASABKAIQCyABKAIUIgVrSwRAIAEgAyACIAEoAiQRAAAaDAILAn8gASwAS0F/SgRAIAIhAANAIAIgACIERQ0CGiADIARBAWsiAGotAABBCkcNAAsgASADIAQgASgCJBEAACAESQ0CIAMgBGohAyABKAIUIQUgAiAEawwBCyACCyEAIAUgAyAAEAcaIAEgASgCFCAAajYCFAsLCwvNBQEGfyAAKAIwIgNBhgJrIQYgACgCPCECIAMhAQNAIAAoAkQgAiAAKAJoIgRqayECIAEgBmogBE0EQCAAKAJIIgEgASADaiADEAcaAkAgAyAAKAJsIgFNBEAgACABIANrNgJsDAELIABCADcCbAsgACAAKAJoIANrIgE2AmggACAAKAJYIANrNgJYIAEgACgChC5JBEAgACABNgKELgsgAEH8gAEoAgARAwAgAiADaiECCwJAIAAoAgAiASgCBCIERQ0AIAAoAjwhBSAAIAIgBCACIARJGyICBH8gACgCSCAAKAJoaiAFaiEFIAEgBCACazYCBAJAAkACQAJAIAEoAhwiBCgCFEEBaw4CAQACCyAEQaABaiAFIAEoAgAgAkHcgAEoAgARCAAMAgsgASABKAIwIAUgASgCACACQcSAASgCABEEADYCMAwBCyAFIAEoAgAgAhAHGgsgASABKAIAIAJqNgIAIAEgASgCCCACajYCCCAAKAI8BSAFCyACaiICNgI8AkAgACgChC4iASACakEDSQ0AIAAoAmggAWshAQJAIAAoAnRBgQhPBEAgACAAIAAoAkggAWoiAi0AACACLQABIAAoAnwRAAA2AlQMAQsgAUUNACAAIAFBAWsgACgChAERAgAaCyAAKAKELiAAKAI8IgJBAUZrIgRFDQAgACABIAQgACgCgAERBQAgACAAKAKELiAEazYChC4gACgCPCECCyACQYUCSw0AIAAoAgAoAgRFDQAgACgCMCEBDAELCwJAIAAoAkQiAiAAKAJAIgNNDQAgAAJ/IAAoAjwgACgCaGoiASADSwRAIAAoAkggAWpBACACIAFrIgNBggIgA0GCAkkbIgMQGSABIANqDAELIAFBggJqIgEgA00NASAAKAJIIANqQQAgAiADayICIAEgA2siAyACIANJGyIDEBkgACgCQCADags2AkALC50CAQF/AkAgAAJ/IAAoAqAuIgFBwABGBEAgACgCBCAAKAIQaiAAKQOYLjcAACAAQgA3A5guIAAgACgCEEEIajYCEEEADAELIAFBIE4EQCAAKAIEIAAoAhBqIAApA5guPgAAIAAgAEGcLmo1AgA3A5guIAAgACgCEEEEajYCECAAIAAoAqAuQSBrIgE2AqAuCyABQRBOBEAgACgCBCAAKAIQaiAAKQOYLj0AACAAIAAoAhBBAmo2AhAgACAAKQOYLkIQiDcDmC4gACAAKAKgLkEQayIBNgKgLgsgAUEISA0BIAAgACgCECIBQQFqNgIQIAEgACgCBGogACkDmC48AAAgACAAKQOYLkIIiDcDmC4gACgCoC5BCGsLNgKgLgsLEAAgACgCCBAGIABBADYCCAvwAQECf0F/IQECQCAALQAoDQAgACgCJEEDRgRAIABBDGoEQCAAQQA2AhAgAEEXNgIMC0F/DwsCQCAAKAIgBEAgACkDGELAAINCAFINASAAQQxqBEAgAEEANgIQIABBHTYCDAtBfw8LAkAgACgCACICRQ0AIAIQMkF/Sg0AIAAoAgAhASAAQQxqIgAEQCAAIAEoAgw2AgAgACABKAIQNgIEC0F/DwsgAEEAQgBBABAOQn9VDQAgACgCACIARQ0BIAAQGhpBfw8LQQAhASAAQQA7ATQgAEEMagRAIABCADcCDAsgACAAKAIgQQFqNgIgCyABCzsAIAAtACgEfkJ/BSAAKAIgRQRAIABBDGoiAARAIABBADYCBCAAQRI2AgALQn8PCyAAQQBCAEEHEA4LC5oIAQt/IABFBEAgARAJDwsgAUFATwRAQYSEAUEwNgIAQQAPCwJ/QRAgAUELakF4cSABQQtJGyEGIABBCGsiBSgCBCIJQXhxIQQCQCAJQQNxRQRAQQAgBkGAAkkNAhogBkEEaiAETQRAIAUhAiAEIAZrQZSIASgCAEEBdE0NAgtBAAwCCyAEIAVqIQcCQCAEIAZPBEAgBCAGayIDQRBJDQEgBSAJQQFxIAZyQQJyNgIEIAUgBmoiAiADQQNyNgIEIAcgBygCBEEBcjYCBCACIAMQOwwBCyAHQcyEASgCAEYEQEHAhAEoAgAgBGoiBCAGTQ0CIAUgCUEBcSAGckECcjYCBCAFIAZqIgMgBCAGayICQQFyNgIEQcCEASACNgIAQcyEASADNgIADAELIAdByIQBKAIARgRAQbyEASgCACAEaiIDIAZJDQICQCADIAZrIgJBEE8EQCAFIAlBAXEgBnJBAnI2AgQgBSAGaiIEIAJBAXI2AgQgAyAFaiIDIAI2AgAgAyADKAIEQX5xNgIEDAELIAUgCUEBcSADckECcjYCBCADIAVqIgIgAigCBEEBcjYCBEEAIQJBACEEC0HIhAEgBDYCAEG8hAEgAjYCAAwBCyAHKAIEIgNBAnENASADQXhxIARqIgogBkkNASAKIAZrIQwCQCADQf8BTQRAIAcoAggiBCADQQN2IgJBA3RB3IQBakYaIAQgBygCDCIDRgRAQbSEAUG0hAEoAgBBfiACd3E2AgAMAgsgBCADNgIMIAMgBDYCCAwBCyAHKAIYIQsCQCAHIAcoAgwiCEcEQCAHKAIIIgJBxIQBKAIASRogAiAINgIMIAggAjYCCAwBCwJAIAdBFGoiBCgCACICDQAgB0EQaiIEKAIAIgINAEEAIQgMAQsDQCAEIQMgAiIIQRRqIgQoAgAiAg0AIAhBEGohBCAIKAIQIgINAAsgA0EANgIACyALRQ0AAkAgByAHKAIcIgNBAnRB5IYBaiICKAIARgRAIAIgCDYCACAIDQFBuIQBQbiEASgCAEF+IAN3cTYCAAwCCyALQRBBFCALKAIQIAdGG2ogCDYCACAIRQ0BCyAIIAs2AhggBygCECICBEAgCCACNgIQIAIgCDYCGAsgBygCFCICRQ0AIAggAjYCFCACIAg2AhgLIAxBD00EQCAFIAlBAXEgCnJBAnI2AgQgBSAKaiICIAIoAgRBAXI2AgQMAQsgBSAJQQFxIAZyQQJyNgIEIAUgBmoiAyAMQQNyNgIEIAUgCmoiAiACKAIEQQFyNgIEIAMgDBA7CyAFIQILIAILIgIEQCACQQhqDwsgARAJIgVFBEBBAA8LIAUgAEF8QXggAEEEaygCACICQQNxGyACQXhxaiICIAEgASACSxsQBxogABAGIAUL6QEBA38CQCABRQ0AIAJBgDBxIgIEfwJ/IAJBgCBHBEBBAiACQYAQRg0BGiADBEAgA0EANgIEIANBEjYCAAtBAA8LQQQLIQJBAAVBAQshBkEUEAkiBEUEQCADBEAgA0EANgIEIANBDjYCAAtBAA8LIAQgAUEBahAJIgU2AgAgBUUEQCAEEAZBAA8LIAUgACABEAcgAWpBADoAACAEQQA2AhAgBEIANwMIIAQgATsBBCAGDQAgBCACECNBBUcNACAEKAIAEAYgBCgCDBAGIAQQBkEAIQQgAwRAIANBADYCBCADQRI2AgALCyAEC7UBAQJ/AkACQAJAAkACQAJAAkAgAC0ABQRAIAAtAABBAnFFDQELIAAoAjAQECAAQQA2AjAgAC0ABUUNAQsgAC0AAEEIcUUNAQsgACgCNBAcIABBADYCNCAALQAFRQ0BCyAALQAAQQRxRQ0BCyAAKAI4EBAgAEEANgI4IAAtAAVFDQELIAAtAABBgAFxRQ0BCyAAKAJUIgEEfyABQQAgARAiEBkgACgCVAVBAAsQBiAAQQA2AlQLC9wMAgl/AX4jAEFAaiIGJAACQAJAAkACQAJAIAEoAjBBABAjIgVBAkZBACABKAI4QQAQIyIEQQFGGw0AIAVBAUZBACAEQQJGGw0AIAVBAkciAw0BIARBAkcNAQsgASABLwEMQYAQcjsBDEEAIQMMAQsgASABLwEMQf/vA3E7AQxBACEFIANFBEBB9eABIAEoAjAgAEEIahBpIgVFDQILIAJBgAJxBEAgBSEDDAELIARBAkcEQCAFIQMMAQtB9cYBIAEoAjggAEEIahBpIgNFBEAgBRAcDAILIAMgBTYCAAsgASABLwEMQf7/A3EgAS8BUiIFQQBHcjsBDAJAAkACQAJAAn8CQAJAIAEpAyhC/v///w9WDQAgASkDIEL+////D1YNACACQYAEcUUNASABKQNIQv////8PVA0BCyAFQYECa0H//wNxQQNJIQdBAQwBCyAFQYECa0H//wNxIQQgAkGACnFBgApHDQEgBEEDSSEHQQALIQkgBkIcEBciBEUEQCAAQQhqIgAEQCAAQQA2AgQgAEEONgIACyADEBwMBQsgAkGACHEhBQJAAkAgAkGAAnEEQAJAIAUNACABKQMgQv////8PVg0AIAEpAyhCgICAgBBUDQMLIAQgASkDKBAYIAEpAyAhDAwBCwJAAkACQCAFDQAgASkDIEL/////D1YNACABKQMoIgxC/////w9WDQEgASkDSEKAgICAEFQNBAsgASkDKCIMQv////8PVA0BCyAEIAwQGAsgASkDICIMQv////8PWgRAIAQgDBAYCyABKQNIIgxC/////w9UDQELIAQgDBAYCyAELQAARQRAIABBCGoiAARAIABBADYCBCAAQRQ2AgALIAQQCCADEBwMBQtBASEKQQEgBC0AAAR+IAQpAxAFQgALp0H//wNxIAYQRyEFIAQQCCAFIAM2AgAgBw0BDAILIAMhBSAEQQJLDQELIAZCBxAXIgRFBEAgAEEIaiIABEAgAEEANgIEIABBDjYCAAsgBRAcDAMLIARBAhANIARBhxJBAhAsIAQgAS0AUhBwIAQgAS8BEBANIAQtAABFBEAgAEEIaiIABEAgAEEANgIEIABBFDYCAAsgBBAIDAILQYGyAkEHIAYQRyEDIAQQCCADIAU2AgBBASELIAMhBQsgBkIuEBciA0UEQCAAQQhqIgAEQCAAQQA2AgQgAEEONgIACyAFEBwMAgsgA0GjEkGoEiACQYACcSIHG0EEECwgB0UEQCADIAkEf0EtBSABLwEIC0H//wNxEA0LIAMgCQR/QS0FIAEvAQoLQf//A3EQDSADIAEvAQwQDSADIAsEf0HjAAUgASgCEAtB//8DcRANIAYgASgCFDYCPAJ/IAZBPGoQjQEiCEUEQEEAIQlBIQwBCwJ/IAgoAhQiBEHQAE4EQCAEQQl0DAELIAhB0AA2AhRBgMACCyEEIAgoAgRBBXQgCCgCCEELdGogCCgCAEEBdmohCSAIKAIMIAQgCCgCEEEFdGpqQaDAAWoLIQQgAyAJQf//A3EQDSADIARB//8DcRANIAMCfyALBEBBACABKQMoQhRUDQEaCyABKAIYCxASIAEpAyAhDCADAn8gAwJ/AkAgBwRAIAxC/v///w9YBEAgASkDKEL/////D1QNAgsgA0F/EBJBfwwDC0F/IAxC/v///w9WDQEaCyAMpwsQEiABKQMoIgxC/////w8gDEL/////D1QbpwsQEiADIAEoAjAiBAR/IAQvAQQFQQALQf//A3EQDSADIAEoAjQgAhBsIAVBgAYQbGpB//8DcRANIAdFBEAgAyABKAI4IgQEfyAELwEEBUEAC0H//wNxEA0gAyABLwE8EA0gAyABLwFAEA0gAyABKAJEEBIgAyABKQNIIgxC/////w8gDEL/////D1QbpxASCyADLQAARQRAIABBCGoiAARAIABBADYCBCAAQRQ2AgALIAMQCCAFEBwMAgsgACAGIAMtAAAEfiADKQMQBUIACxAbIQQgAxAIIARBf0wNACABKAIwIgMEQCAAIAMQYUF/TA0BCyAFBEAgACAFQYAGEGtBf0wNAQsgBRAcIAEoAjQiBQRAIAAgBSACEGtBAEgNAgsgBw0CIAEoAjgiAUUNAiAAIAEQYUEATg0CDAELIAUQHAtBfyEKCyAGQUBrJAAgCgtNAQJ/IAEtAAAhAgJAIAAtAAAiA0UNACACIANHDQADQCABLQABIQIgAC0AASIDRQ0BIAFBAWohASAAQQFqIQAgAiADRg0ACwsgAyACawvcAwICfgF/IAOtIQQgACkDmC4hBQJAIAACfyAAAn4gACgCoC4iBkEDaiIDQT9NBEAgBCAGrYYgBYQMAQsgBkHAAEYEQCAAKAIEIAAoAhBqIAU3AAAgACgCEEEIagwCCyAAKAIEIAAoAhBqIAQgBq2GIAWENwAAIAAgACgCEEEIajYCECAGQT1rIQMgBEHAACAGa62ICyIENwOYLiAAIAM2AqAuIANBOU4EQCAAKAIEIAAoAhBqIAQ3AAAgACAAKAIQQQhqNgIQDAILIANBGU4EQCAAKAIEIAAoAhBqIAQ+AAAgACAAKAIQQQRqNgIQIAAgACkDmC5CIIgiBDcDmC4gACAAKAKgLkEgayIDNgKgLgsgA0EJTgR/IAAoAgQgACgCEGogBD0AACAAIAAoAhBBAmo2AhAgACkDmC5CEIghBCAAKAKgLkEQawUgAwtBAUgNASAAKAIQCyIDQQFqNgIQIAAoAgQgA2ogBDwAAAsgAEEANgKgLiAAQgA3A5guIAAoAgQgACgCEGogAjsAACAAIAAoAhBBAmoiAzYCECAAKAIEIANqIAJBf3M7AAAgACAAKAIQQQJqIgM2AhAgAgRAIAAoAgQgA2ogASACEAcaIAAgACgCECACajYCEAsLrAQCAX8BfgJAIAANACABUA0AIAMEQCADQQA2AgQgA0ESNgIAC0EADwsCQAJAIAAgASACIAMQiQEiBEUNAEEYEAkiAkUEQCADBEAgA0EANgIEIANBDjYCAAsCQCAEKAIoIgBFBEAgBCkDGCEBDAELIABBADYCKCAEKAIoQgA3AyAgBCAEKQMYIgUgBCkDICIBIAEgBVQbIgE3AxgLIAQpAwggAVYEQANAIAQoAgAgAadBBHRqKAIAEAYgAUIBfCIBIAQpAwhUDQALCyAEKAIAEAYgBCgCBBAGIAQQBgwBCyACQQA2AhQgAiAENgIQIAJBABABNgIMIAJBADYCCCACQgA3AgACf0E4EAkiAEUEQCADBEAgA0EANgIEIANBDjYCAAtBAAwBCyAAQQA2AgggAEIANwMAIABCADcDICAAQoCAgIAQNwIsIABBADoAKCAAQQA2AhQgAEIANwIMIABBADsBNCAAIAI2AgggAEEkNgIEIABCPyACQQBCAEEOQSQRDAAiASABQgBTGzcDGCAACyIADQEgAigCECIDBEACQCADKAIoIgBFBEAgAykDGCEBDAELIABBADYCKCADKAIoQgA3AyAgAyADKQMYIgUgAykDICIBIAEgBVQbIgE3AxgLIAMpAwggAVYEQANAIAMoAgAgAadBBHRqKAIAEAYgAUIBfCIBIAMpAwhUDQALCyADKAIAEAYgAygCBBAGIAMQBgsgAhAGC0EAIQALIAALiwwBBn8gACABaiEFAkACQCAAKAIEIgJBAXENACACQQNxRQ0BIAAoAgAiAiABaiEBAkAgACACayIAQciEASgCAEcEQCACQf8BTQRAIAAoAggiBCACQQN2IgJBA3RB3IQBakYaIAAoAgwiAyAERw0CQbSEAUG0hAEoAgBBfiACd3E2AgAMAwsgACgCGCEGAkAgACAAKAIMIgNHBEAgACgCCCICQcSEASgCAEkaIAIgAzYCDCADIAI2AggMAQsCQCAAQRRqIgIoAgAiBA0AIABBEGoiAigCACIEDQBBACEDDAELA0AgAiEHIAQiA0EUaiICKAIAIgQNACADQRBqIQIgAygCECIEDQALIAdBADYCAAsgBkUNAgJAIAAgACgCHCIEQQJ0QeSGAWoiAigCAEYEQCACIAM2AgAgAw0BQbiEAUG4hAEoAgBBfiAEd3E2AgAMBAsgBkEQQRQgBigCECAARhtqIAM2AgAgA0UNAwsgAyAGNgIYIAAoAhAiAgRAIAMgAjYCECACIAM2AhgLIAAoAhQiAkUNAiADIAI2AhQgAiADNgIYDAILIAUoAgQiAkEDcUEDRw0BQbyEASABNgIAIAUgAkF+cTYCBCAAIAFBAXI2AgQgBSABNgIADwsgBCADNgIMIAMgBDYCCAsCQCAFKAIEIgJBAnFFBEAgBUHMhAEoAgBGBEBBzIQBIAA2AgBBwIQBQcCEASgCACABaiIBNgIAIAAgAUEBcjYCBCAAQciEASgCAEcNA0G8hAFBADYCAEHIhAFBADYCAA8LIAVByIQBKAIARgRAQciEASAANgIAQbyEAUG8hAEoAgAgAWoiATYCACAAIAFBAXI2AgQgACABaiABNgIADwsgAkF4cSABaiEBAkAgAkH/AU0EQCAFKAIIIgQgAkEDdiICQQN0QdyEAWpGGiAEIAUoAgwiA0YEQEG0hAFBtIQBKAIAQX4gAndxNgIADAILIAQgAzYCDCADIAQ2AggMAQsgBSgCGCEGAkAgBSAFKAIMIgNHBEAgBSgCCCICQcSEASgCAEkaIAIgAzYCDCADIAI2AggMAQsCQCAFQRRqIgQoAgAiAg0AIAVBEGoiBCgCACICDQBBACEDDAELA0AgBCEHIAIiA0EUaiIEKAIAIgINACADQRBqIQQgAygCECICDQALIAdBADYCAAsgBkUNAAJAIAUgBSgCHCIEQQJ0QeSGAWoiAigCAEYEQCACIAM2AgAgAw0BQbiEAUG4hAEoAgBBfiAEd3E2AgAMAgsgBkEQQRQgBigCECAFRhtqIAM2AgAgA0UNAQsgAyAGNgIYIAUoAhAiAgRAIAMgAjYCECACIAM2AhgLIAUoAhQiAkUNACADIAI2AhQgAiADNgIYCyAAIAFBAXI2AgQgACABaiABNgIAIABByIQBKAIARw0BQbyEASABNgIADwsgBSACQX5xNgIEIAAgAUEBcjYCBCAAIAFqIAE2AgALIAFB/wFNBEAgAUEDdiICQQN0QdyEAWohAQJ/QbSEASgCACIDQQEgAnQiAnFFBEBBtIQBIAIgA3I2AgAgAQwBCyABKAIICyECIAEgADYCCCACIAA2AgwgACABNgIMIAAgAjYCCA8LQR8hAiAAQgA3AhAgAUH///8HTQRAIAFBCHYiAiACQYD+P2pBEHZBCHEiBHQiAiACQYDgH2pBEHZBBHEiA3QiAiACQYCAD2pBEHZBAnEiAnRBD3YgAyAEciACcmsiAkEBdCABIAJBFWp2QQFxckEcaiECCyAAIAI2AhwgAkECdEHkhgFqIQcCQAJAQbiEASgCACIEQQEgAnQiA3FFBEBBuIQBIAMgBHI2AgAgByAANgIAIAAgBzYCGAwBCyABQQBBGSACQQF2ayACQR9GG3QhAiAHKAIAIQMDQCADIgQoAgRBeHEgAUYNAiACQR12IQMgAkEBdCECIAQgA0EEcWoiB0EQaigCACIDDQALIAcgADYCECAAIAQ2AhgLIAAgADYCDCAAIAA2AggPCyAEKAIIIgEgADYCDCAEIAA2AgggAEEANgIYIAAgBDYCDCAAIAE2AggLC1gCAX8BfgJAAn9BACAARQ0AGiAArUIChiICpyIBIABBBHJBgIAESQ0AGkF/IAEgAkIgiKcbCyIBEAkiAEUNACAAQQRrLQAAQQNxRQ0AIABBACABEBkLIAALQwEDfwJAIAJFDQADQCAALQAAIgQgAS0AACIFRgRAIAFBAWohASAAQQFqIQAgAkEBayICDQEMAgsLIAQgBWshAwsgAwsUACAAEEAgACgCABAgIAAoAgQQIAutBAIBfgV/IwBBEGsiBCQAIAAgAWshBgJAAkAgAUEBRgRAIAAgBi0AACACEBkMAQsgAUEJTwRAIAAgBikAADcAACAAIAJBAWtBB3FBAWoiBWohACACIAVrIgFFDQIgBSAGaiECA0AgACACKQAANwAAIAJBCGohAiAAQQhqIQAgAUEIayIBDQALDAILAkACQAJAAkAgAUEEaw4FAAICAgECCyAEIAYoAAAiATYCBCAEIAE2AgAMAgsgBCAGKQAANwMADAELQQghByAEQQhqIQgDQCAIIAYgByABIAEgB0sbIgUQByAFaiEIIAcgBWsiBw0ACyAEIAQpAwg3AwALAkAgBQ0AIAJBEEkNACAEKQMAIQMgAkEQayIGQQR2QQFqQQdxIgEEQANAIAAgAzcACCAAIAM3AAAgAkEQayECIABBEGohACABQQFrIgENAAsLIAZB8ABJDQADQCAAIAM3AHggACADNwBwIAAgAzcAaCAAIAM3AGAgACADNwBYIAAgAzcAUCAAIAM3AEggACADNwBAIAAgAzcAOCAAIAM3ADAgACADNwAoIAAgAzcAICAAIAM3ABggACADNwAQIAAgAzcACCAAIAM3AAAgAEGAAWohACACQYABayICQQ9LDQALCyACQQhPBEBBCCAFayEBA0AgACAEKQMANwAAIAAgAWohACACIAFrIgJBB0sNAAsLIAJFDQEgACAEIAIQBxoLIAAgAmohAAsgBEEQaiQAIAALXwECfyAAKAIIIgEEQCABEAsgAEEANgIICwJAIAAoAgQiAUUNACABKAIAIgJBAXFFDQAgASgCEEF+Rw0AIAEgAkF+cSICNgIAIAINACABECAgAEEANgIECyAAQQA6AAwL1wICBH8BfgJAAkAgACgCQCABp0EEdGooAgAiA0UEQCACBEAgAkEANgIEIAJBFDYCAAsMAQsgACgCACADKQNIIgdBABAUIQMgACgCACEAIANBf0wEQCACBEAgAiAAKAIMNgIAIAIgACgCEDYCBAsMAQtCACEBIwBBEGsiBiQAQX8hAwJAIABCGkEBEBRBf0wEQCACBEAgAiAAKAIMNgIAIAIgACgCEDYCBAsMAQsgAEIEIAZBCmogAhAtIgRFDQBBHiEAQQEhBQNAIAQQDCAAaiEAIAVBAkcEQCAFQQFqIQUMAQsLIAQtAAAEfyAEKQMQIAQpAwhRBUEAC0UEQCACBEAgAkEANgIEIAJBFDYCAAsgBBAIDAELIAQQCCAAIQMLIAZBEGokACADIgBBAEgNASAHIACtfCIBQn9VDQEgAgRAIAJBFjYCBCACQQQ2AgALC0IAIQELIAELYAIBfgF/AkAgAEUNACAAQQhqEF8iAEUNACABIAEoAjBBAWo2AjAgACADNgIIIAAgAjYCBCAAIAE2AgAgAEI/IAEgA0EAQgBBDiACEQoAIgQgBEIAUxs3AxggACEFCyAFCyIAIAAoAiRBAWtBAU0EQCAAQQBCAEEKEA4aIABBADYCJAsLbgACQAJAAkAgA0IQVA0AIAJFDQECfgJAAkACQCACKAIIDgMCAAEECyACKQMAIAB8DAILIAIpAwAgAXwMAQsgAikDAAsiA0IAUw0AIAEgA1oNAgsgBARAIARBADYCBCAEQRI2AgALC0J/IQMLIAMLggICAX8CfgJAQQEgAiADGwRAIAIgA2oQCSIFRQRAIAQEQCAEQQA2AgQgBEEONgIAC0EADwsgAq0hBgJAAkAgAARAIAAgBhATIgBFBEAgBARAIARBADYCBCAEQQ42AgALDAULIAUgACACEAcaIAMNAQwCCyABIAUgBhARIgdCf1cEQCAEBEAgBCABKAIMNgIAIAQgASgCEDYCBAsMBAsgBiAHVQRAIAQEQCAEQQA2AgQgBEERNgIACwwECyADRQ0BCyACIAVqIgBBADoAACACQQFIDQAgBSECA0AgAi0AAEUEQCACQSA6AAALIAJBAWoiAiAASQ0ACwsLIAUPCyAFEAZBAAuBAQEBfwJAIAAEQCADQYAGcSEFQQAhAwNAAkAgAC8BCCACRw0AIAUgACgCBHFFDQAgA0EATg0DIANBAWohAwsgACgCACIADQALCyAEBEAgBEEANgIEIARBCTYCAAtBAA8LIAEEQCABIAAvAQo7AQALIAAvAQpFBEBBwBQPCyAAKAIMC1cBAX9BEBAJIgNFBEBBAA8LIAMgATsBCiADIAA7AQggA0GABjYCBCADQQA2AgACQCABBEAgAyACIAEQYyIANgIMIAANASADEAZBAA8LIANBADYCDAsgAwvuBQIEfwV+IwBB4ABrIgQkACAEQQhqIgNCADcDICADQQA2AhggA0L/////DzcDECADQQA7AQwgA0G/hig2AgggA0EBOgAGIANBADsBBCADQQA2AgAgA0IANwNIIANBgIDYjXg2AkQgA0IANwMoIANCADcDMCADQgA3AzggA0FAa0EAOwEAIANCADcDUCABKQMIUCIDRQRAIAEoAgAoAgApA0ghBwsCfgJAIAMEQCAHIQkMAQsgByEJA0AgCqdBBHQiBSABKAIAaigCACIDKQNIIgggCSAIIAlUGyIJIAEpAyBWBEAgAgRAIAJBADYCBCACQRM2AgALQn8MAwsgAygCMCIGBH8gBi8BBAVBAAtB//8Dca0gCCADKQMgfHxCHnwiCCAHIAcgCFQbIgcgASkDIFYEQCACBEAgAkEANgIEIAJBEzYCAAtCfwwDCyAAKAIAIAEoAgAgBWooAgApA0hBABAUIQYgACgCACEDIAZBf0wEQCACBEAgAiADKAIMNgIAIAIgAygCEDYCBAtCfwwDCyAEQQhqIANBAEEBIAIQaEJ/UQRAIARBCGoQNkJ/DAMLAkACQCABKAIAIAVqKAIAIgMvAQogBC8BEkkNACADKAIQIAQoAhhHDQAgAygCFCAEKAIcRw0AIAMoAjAgBCgCOBBiRQ0AAkAgBCgCICIGIAMoAhhHBEAgBCkDKCEIDAELIAMpAyAiCyAEKQMoIghSDQAgCyEIIAMpAyggBCkDMFENAgsgBC0AFEEIcUUNACAGDQAgCEIAUg0AIAQpAzBQDQELIAIEQCACQQA2AgQgAkEVNgIACyAEQQhqEDZCfwwDCyABKAIAIAVqKAIAKAI0IAQoAjwQbyEDIAEoAgAgBWooAgAiBUEBOgAEIAUgAzYCNCAEQQA2AjwgBEEIahA2IApCAXwiCiABKQMIVA0ACwsgByAJfSIHQv///////////wAgB0L///////////8AVBsLIQcgBEHgAGokACAHC8YBAQJ/QdgAEAkiAUUEQCAABEAgAEEANgIEIABBDjYCAAtBAA8LIAECf0EYEAkiAkUEQCAABEAgAEEANgIEIABBDjYCAAtBAAwBCyACQQA2AhAgAkIANwMIIAJBADYCACACCyIANgJQIABFBEAgARAGQQAPCyABQgA3AwAgAUEANgIQIAFCADcCCCABQgA3AhQgAUEANgJUIAFCADcCHCABQgA3ACEgAUIANwMwIAFCADcDOCABQUBrQgA3AwAgAUIANwNIIAELgBMCD38CfiMAQdAAayIFJAAgBSABNgJMIAVBN2ohEyAFQThqIRBBACEBA0ACQCAOQQBIDQBB/////wcgDmsgAUgEQEGEhAFBPTYCAEF/IQ4MAQsgASAOaiEOCyAFKAJMIgchAQJAAkACQAJAAkACQAJAAkAgBQJ/AkAgBy0AACIGBEADQAJAAkAgBkH/AXEiBkUEQCABIQYMAQsgBkElRw0BIAEhBgNAIAEtAAFBJUcNASAFIAFBAmoiCDYCTCAGQQFqIQYgAS0AAiEMIAghASAMQSVGDQALCyAGIAdrIQEgAARAIAAgByABEC4LIAENDSAFKAJMIQEgBSgCTCwAAUEwa0EKTw0DIAEtAAJBJEcNAyABLAABQTBrIQ9BASERIAFBA2oMBAsgBSABQQFqIgg2AkwgAS0AASEGIAghAQwACwALIA4hDSAADQggEUUNAkEBIQEDQCAEIAFBAnRqKAIAIgAEQCADIAFBA3RqIAAgAhB4QQEhDSABQQFqIgFBCkcNAQwKCwtBASENIAFBCk8NCANAIAQgAUECdGooAgANCCABQQFqIgFBCkcNAAsMCAtBfyEPIAFBAWoLIgE2AkxBACEIAkAgASwAACIKQSBrIgZBH0sNAEEBIAZ0IgZBidEEcUUNAANAAkAgBSABQQFqIgg2AkwgASwAASIKQSBrIgFBIE8NAEEBIAF0IgFBidEEcUUNACABIAZyIQYgCCEBDAELCyAIIQEgBiEICwJAIApBKkYEQCAFAn8CQCABLAABQTBrQQpPDQAgBSgCTCIBLQACQSRHDQAgASwAAUECdCAEakHAAWtBCjYCACABLAABQQN0IANqQYADaygCACELQQEhESABQQNqDAELIBENCEEAIRFBACELIAAEQCACIAIoAgAiAUEEajYCACABKAIAIQsLIAUoAkxBAWoLIgE2AkwgC0F/Sg0BQQAgC2shCyAIQYDAAHIhCAwBCyAFQcwAahB3IgtBAEgNBiAFKAJMIQELQX8hCQJAIAEtAABBLkcNACABLQABQSpGBEACQCABLAACQTBrQQpPDQAgBSgCTCIBLQADQSRHDQAgASwAAkECdCAEakHAAWtBCjYCACABLAACQQN0IANqQYADaygCACEJIAUgAUEEaiIBNgJMDAILIBENByAABH8gAiACKAIAIgFBBGo2AgAgASgCAAVBAAshCSAFIAUoAkxBAmoiATYCTAwBCyAFIAFBAWo2AkwgBUHMAGoQdyEJIAUoAkwhAQtBACEGA0AgBiESQX8hDSABLAAAQcEAa0E5Sw0HIAUgAUEBaiIKNgJMIAEsAAAhBiAKIQEgBiASQTpsakGf7ABqLQAAIgZBAWtBCEkNAAsgBkETRg0CIAZFDQYgD0EATgRAIAQgD0ECdGogBjYCACAFIAMgD0EDdGopAwA3A0AMBAsgAA0BC0EAIQ0MBQsgBUFAayAGIAIQeCAFKAJMIQoMAgsgD0F/Sg0DC0EAIQEgAEUNBAsgCEH//3txIgwgCCAIQYDAAHEbIQZBACENQaQIIQ8gECEIAkACQAJAAn8CQAJAAkACQAJ/AkACQAJAAkACQAJAAkAgCkEBaywAACIBQV9xIAEgAUEPcUEDRhsgASASGyIBQdgAaw4hBBISEhISEhISDhIPBg4ODhIGEhISEgIFAxISCRIBEhIEAAsCQCABQcEAaw4HDhILEg4ODgALIAFB0wBGDQkMEQsgBSkDQCEUQaQIDAULQQAhAQJAAkACQAJAAkACQAJAIBJB/wFxDggAAQIDBBcFBhcLIAUoAkAgDjYCAAwWCyAFKAJAIA42AgAMFQsgBSgCQCAOrDcDAAwUCyAFKAJAIA47AQAMEwsgBSgCQCAOOgAADBILIAUoAkAgDjYCAAwRCyAFKAJAIA6sNwMADBALIAlBCCAJQQhLGyEJIAZBCHIhBkH4ACEBCyAQIQcgAUEgcSEMIAUpA0AiFFBFBEADQCAHQQFrIgcgFKdBD3FBsPAAai0AACAMcjoAACAUQg9WIQogFEIEiCEUIAoNAAsLIAUpA0BQDQMgBkEIcUUNAyABQQR2QaQIaiEPQQIhDQwDCyAQIQEgBSkDQCIUUEUEQANAIAFBAWsiASAUp0EHcUEwcjoAACAUQgdWIQcgFEIDiCEUIAcNAAsLIAEhByAGQQhxRQ0CIAkgECAHayIBQQFqIAEgCUgbIQkMAgsgBSkDQCIUQn9XBEAgBUIAIBR9IhQ3A0BBASENQaQIDAELIAZBgBBxBEBBASENQaUIDAELQaYIQaQIIAZBAXEiDRsLIQ8gECEBAkAgFEKAgICAEFQEQCAUIRUMAQsDQCABQQFrIgEgFCAUQgqAIhVCCn59p0EwcjoAACAUQv////+fAVYhByAVIRQgBw0ACwsgFaciBwRAA0AgAUEBayIBIAcgB0EKbiIMQQpsa0EwcjoAACAHQQlLIQogDCEHIAoNAAsLIAEhBwsgBkH//3txIAYgCUF/ShshBgJAIAUpA0AiFEIAUg0AIAkNAEEAIQkgECEHDAoLIAkgFFAgECAHa2oiASABIAlIGyEJDAkLIAUoAkAiAUGKEiABGyIHQQAgCRB6IgEgByAJaiABGyEIIAwhBiABIAdrIAkgARshCQwICyAJBEAgBSgCQAwCC0EAIQEgAEEgIAtBACAGECcMAgsgBUEANgIMIAUgBSkDQD4CCCAFIAVBCGo2AkBBfyEJIAVBCGoLIQhBACEBAkADQCAIKAIAIgdFDQECQCAFQQRqIAcQeSIHQQBIIgwNACAHIAkgAWtLDQAgCEEEaiEIIAkgASAHaiIBSw0BDAILC0F/IQ0gDA0FCyAAQSAgCyABIAYQJyABRQRAQQAhAQwBC0EAIQggBSgCQCEKA0AgCigCACIHRQ0BIAVBBGogBxB5IgcgCGoiCCABSg0BIAAgBUEEaiAHEC4gCkEEaiEKIAEgCEsNAAsLIABBICALIAEgBkGAwABzECcgCyABIAEgC0gbIQEMBQsgACAFKwNAIAsgCSAGIAFBABEdACEBDAQLIAUgBSkDQDwAN0EBIQkgEyEHIAwhBgwCC0F/IQ0LIAVB0ABqJAAgDQ8LIABBICANIAggB2siDCAJIAkgDEgbIgpqIgggCyAIIAtKGyIBIAggBhAnIAAgDyANEC4gAEEwIAEgCCAGQYCABHMQJyAAQTAgCiAMQQAQJyAAIAcgDBAuIABBICABIAggBkGAwABzECcMAAsAC54DAgR/AX4gAARAIAAoAgAiAQRAIAEQGhogACgCABALCyAAKAIcEAYgACgCIBAQIAAoAiQQECAAKAJQIgMEQCADKAIQIgIEQCADKAIAIgEEfwNAIAIgBEECdGooAgAiAgRAA0AgAigCGCEBIAIQBiABIgINAAsgAygCACEBCyABIARBAWoiBEsEQCADKAIQIQIMAQsLIAMoAhAFIAILEAYLIAMQBgsgACgCQCIBBEAgACkDMFAEfyABBSABED5CAiEFAkAgACkDMEICVA0AQQEhAgNAIAAoAkAgAkEEdGoQPiAFIAApAzBaDQEgBachAiAFQgF8IQUMAAsACyAAKAJACxAGCwJAIAAoAkRFDQBBACECQgEhBQNAIAAoAkwgAkECdGooAgAiAUEBOgAoIAFBDGoiASgCAEUEQCABBEAgAUEANgIEIAFBCDYCAAsLIAUgADUCRFoNASAFpyECIAVCAXwhBQwACwALIAAoAkwQBiAAKAJUIgIEQCACKAIIIgEEQCACKAIMIAERAwALIAIQBgsgAEEIahAxIAAQBgsL6gMCAX4EfwJAIAAEfiABRQRAIAMEQCADQQA2AgQgA0ESNgIAC0J/DwsgAkGDIHEEQAJAIAApAzBQDQBBPEE9IAJBAXEbIQcgAkECcUUEQANAIAAgBCACIAMQUyIFBEAgASAFIAcRAgBFDQYLIARCAXwiBCAAKQMwVA0ADAILAAsDQCAAIAQgAiADEFMiBQRAIAECfyAFECJBAWohBgNAQQAgBkUNARogBSAGQQFrIgZqIggtAABBL0cNAAsgCAsiBkEBaiAFIAYbIAcRAgBFDQULIARCAXwiBCAAKQMwVA0ACwsgAwRAIANBADYCBCADQQk2AgALQn8PC0ESIQYCQAJAIAAoAlAiBUUNACABRQ0AQQkhBiAFKQMIUA0AIAUoAhAgAS0AACIHBH9CpesKIQQgASEAA0AgBCAHrUL/AYN8IQQgAC0AASIHBEAgAEEBaiEAIARC/////w+DQiF+IQQMAQsLIASnBUGFKgsgBSgCAHBBAnRqKAIAIgBFDQADQCABIAAoAgAQOEUEQCACQQhxBEAgACkDCCIEQn9RDQMMBAsgACkDECIEQn9RDQIMAwsgACgCGCIADQALCyADBEAgA0EANgIEIAMgBjYCAAtCfyEECyAEBUJ/Cw8LIAMEQCADQgA3AgALIAQL3AQCB38BfgJAAkAgAEUNACABRQ0AIAJCf1UNAQsgBARAIARBADYCBCAEQRI2AgALQQAPCwJAIAAoAgAiB0UEQEGAAiEHQYACEDwiBkUNASAAKAIQEAYgAEGAAjYCACAAIAY2AhALAkACQCAAKAIQIAEtAAAiBQR/QqXrCiEMIAEhBgNAIAwgBa1C/wGDfCEMIAYtAAEiBQRAIAZBAWohBiAMQv////8Pg0IhfiEMDAELCyAMpwVBhSoLIgYgB3BBAnRqIggoAgAiBQRAA0ACQCAFKAIcIAZHDQAgASAFKAIAEDgNAAJAIANBCHEEQCAFKQMIQn9SDQELIAUpAxBCf1ENBAsgBARAIARBADYCBCAEQQo2AgALQQAPCyAFKAIYIgUNAAsLQSAQCSIFRQ0CIAUgATYCACAFIAgoAgA2AhggCCAFNgIAIAVCfzcDCCAFIAY2AhwgACAAKQMIQgF8Igw3AwggDLogB7hEAAAAAAAA6D+iZEUNACAHQQBIDQAgByAHQQF0IghGDQAgCBA8IgpFDQECQCAMQgAgBxtQBEAgACgCECEJDAELIAAoAhAhCUEAIQQDQCAJIARBAnRqKAIAIgYEQANAIAYoAhghASAGIAogBigCHCAIcEECdGoiCygCADYCGCALIAY2AgAgASIGDQALCyAEQQFqIgQgB0cNAAsLIAkQBiAAIAg2AgAgACAKNgIQCyADQQhxBEAgBSACNwMICyAFIAI3AxBBAQ8LIAQEQCAEQQA2AgQgBEEONgIAC0EADwsgBARAIARBADYCBCAEQQ42AgALQQAL3Q8BF38jAEFAaiIHQgA3AzAgB0IANwM4IAdCADcDICAHQgA3AygCQAJAAkACQAJAIAIEQCACQQNxIQggAkEBa0EDTwRAIAJBfHEhBgNAIAdBIGogASAJQQF0IgxqLwEAQQF0aiIKIAovAQBBAWo7AQAgB0EgaiABIAxBAnJqLwEAQQF0aiIKIAovAQBBAWo7AQAgB0EgaiABIAxBBHJqLwEAQQF0aiIKIAovAQBBAWo7AQAgB0EgaiABIAxBBnJqLwEAQQF0aiIKIAovAQBBAWo7AQAgCUEEaiEJIAZBBGsiBg0ACwsgCARAA0AgB0EgaiABIAlBAXRqLwEAQQF0aiIGIAYvAQBBAWo7AQAgCUEBaiEJIAhBAWsiCA0ACwsgBCgCACEJQQ8hCyAHLwE+IhENAgwBCyAEKAIAIQkLQQ4hC0EAIREgBy8BPA0AQQ0hCyAHLwE6DQBBDCELIAcvATgNAEELIQsgBy8BNg0AQQohCyAHLwE0DQBBCSELIAcvATINAEEIIQsgBy8BMA0AQQchCyAHLwEuDQBBBiELIAcvASwNAEEFIQsgBy8BKg0AQQQhCyAHLwEoDQBBAyELIAcvASYNAEECIQsgBy8BJA0AIAcvASJFBEAgAyADKAIAIgBBBGo2AgAgAEHAAjYBACADIAMoAgAiAEEEajYCACAAQcACNgEAQQEhDQwDCyAJQQBHIRtBASELQQEhCQwBCyALIAkgCSALSxshG0EBIQ5BASEJA0AgB0EgaiAJQQF0ai8BAA0BIAlBAWoiCSALRw0ACyALIQkLQX8hCCAHLwEiIg9BAksNAUEEIAcvASQiECAPQQF0amsiBkEASA0BIAZBAXQgBy8BJiISayIGQQBIDQEgBkEBdCAHLwEoIhNrIgZBAEgNASAGQQF0IAcvASoiFGsiBkEASA0BIAZBAXQgBy8BLCIVayIGQQBIDQEgBkEBdCAHLwEuIhZrIgZBAEgNASAGQQF0IAcvATAiF2siBkEASA0BIAZBAXQgBy8BMiIZayIGQQBIDQEgBkEBdCAHLwE0IhxrIgZBAEgNASAGQQF0IAcvATYiDWsiBkEASA0BIAZBAXQgBy8BOCIYayIGQQBIDQEgBkEBdCAHLwE6IgxrIgZBAEgNASAGQQF0IAcvATwiCmsiBkEASA0BIAZBAXQgEWsiBkEASA0BIAZBACAARSAOchsNASAJIBtLIRpBACEIIAdBADsBAiAHIA87AQQgByAPIBBqIgY7AQYgByAGIBJqIgY7AQggByAGIBNqIgY7AQogByAGIBRqIgY7AQwgByAGIBVqIgY7AQ4gByAGIBZqIgY7ARAgByAGIBdqIgY7ARIgByAGIBlqIgY7ARQgByAGIBxqIgY7ARYgByAGIA1qIgY7ARggByAGIBhqIgY7ARogByAGIAxqIgY7ARwgByAGIApqOwEeAkAgAkUNACACQQFHBEAgAkF+cSEGA0AgASAIQQF0ai8BACIKBEAgByAKQQF0aiIKIAovAQAiCkEBajsBACAFIApBAXRqIAg7AQALIAEgCEEBciIMQQF0ai8BACIKBEAgByAKQQF0aiIKIAovAQAiCkEBajsBACAFIApBAXRqIAw7AQALIAhBAmohCCAGQQJrIgYNAAsLIAJBAXFFDQAgASAIQQF0ai8BACICRQ0AIAcgAkEBdGoiAiACLwEAIgJBAWo7AQAgBSACQQF0aiAIOwEACyAJIBsgGhshDUEUIRBBACEWIAUiCiEYQQAhEgJAAkACQCAADgICAAELQQEhCCANQQpLDQNBgQIhEEHw2QAhGEGw2QAhCkEBIRIMAQsgAEECRiEWQQAhEEHw2gAhGEGw2gAhCiAAQQJHBEAMAQtBASEIIA1BCUsNAgtBASANdCITQQFrIRwgAygCACEUQQAhFSANIQZBACEPQQAhDkF/IQIDQEEBIAZ0IRoCQANAIAkgD2shFwJAIAUgFUEBdGovAQAiCCAQTwRAIAogCCAQa0EBdCIAai8BACERIAAgGGotAAAhAAwBC0EAQeAAIAhBAWogEEkiBhshACAIQQAgBhshEQsgDiAPdiEMQX8gF3QhBiAaIQgDQCAUIAYgCGoiCCAMakECdGoiGSAROwECIBkgFzoAASAZIAA6AAAgCA0AC0EBIAlBAWt0IQYDQCAGIgBBAXYhBiAAIA5xDQALIAdBIGogCUEBdGoiBiAGLwEAQQFrIgY7AQAgAEEBayAOcSAAakEAIAAbIQ4gFUEBaiEVIAZB//8DcUUEQCAJIAtGDQIgASAFIBVBAXRqLwEAQQF0ai8BACEJCyAJIA1NDQAgDiAccSIAIAJGDQALQQEgCSAPIA0gDxsiD2siBnQhAiAJIAtJBEAgCyAPayEMIAkhCAJAA0AgAiAHQSBqIAhBAXRqLwEAayICQQFIDQEgAkEBdCECIAZBAWoiBiAPaiIIIAtJDQALIAwhBgtBASAGdCECC0EBIQggEiACIBNqIhNBtApLcQ0DIBYgE0HQBEtxDQMgAygCACICIABBAnRqIgggDToAASAIIAY6AAAgCCAUIBpBAnRqIhQgAmtBAnY7AQIgACECDAELCyAOBEAgFCAOQQJ0aiIAQQA7AQIgACAXOgABIABBwAA6AAALIAMgAygCACATQQJ0ajYCAAsgBCANNgIAQQAhCAsgCAusAQICfgF/IAFBAmqtIQIgACkDmC4hAwJAIAAoAqAuIgFBA2oiBEE/TQRAIAIgAa2GIAOEIQIMAQsgAUHAAEYEQCAAKAIEIAAoAhBqIAM3AAAgACAAKAIQQQhqNgIQQQMhBAwBCyAAKAIEIAAoAhBqIAIgAa2GIAOENwAAIAAgACgCEEEIajYCECABQT1rIQQgAkHAACABa62IIQILIAAgAjcDmC4gACAENgKgLguXAwICfgN/QYDJADMBACECIAApA5guIQMCQCAAKAKgLiIFQYLJAC8BACIGaiIEQT9NBEAgAiAFrYYgA4QhAgwBCyAFQcAARgRAIAAoAgQgACgCEGogAzcAACAAIAAoAhBBCGo2AhAgBiEEDAELIAAoAgQgACgCEGogAiAFrYYgA4Q3AAAgACAAKAIQQQhqNgIQIARBQGohBCACQcAAIAVrrYghAgsgACACNwOYLiAAIAQ2AqAuIAEEQAJAIARBOU4EQCAAKAIEIAAoAhBqIAI3AAAgACAAKAIQQQhqNgIQDAELIARBGU4EQCAAKAIEIAAoAhBqIAI+AAAgACAAKAIQQQRqNgIQIAAgACkDmC5CIIgiAjcDmC4gACAAKAKgLkEgayIENgKgLgsgBEEJTgR/IAAoAgQgACgCEGogAj0AACAAIAAoAhBBAmo2AhAgACkDmC5CEIghAiAAKAKgLkEQawUgBAtBAUgNACAAIAAoAhAiAUEBajYCECABIAAoAgRqIAI8AAALIABBADYCoC4gAEIANwOYLgsL8hQBEn8gASgCCCICKAIAIQUgAigCDCEHIAEoAgAhCCAAQoCAgIDQxwA3A6ApQQAhAgJAAkAgB0EASgRAQX8hDANAAkAgCCACQQJ0aiIDLwEABEAgACAAKAKgKUEBaiIDNgKgKSAAIANBAnRqQawXaiACNgIAIAAgAmpBqClqQQA6AAAgAiEMDAELIANBADsBAgsgAkEBaiICIAdHDQALIABB/C1qIQ8gAEH4LWohESAAKAKgKSIEQQFKDQIMAQsgAEH8LWohDyAAQfgtaiERQX8hDAsDQCAAIARBAWoiAjYCoCkgACACQQJ0akGsF2ogDEEBaiIDQQAgDEECSCIGGyICNgIAIAggAkECdCIEakEBOwEAIAAgAmpBqClqQQA6AAAgACAAKAL4LUEBazYC+C0gBQRAIA8gDygCACAEIAVqLwECazYCAAsgAyAMIAYbIQwgACgCoCkiBEECSA0ACwsgASAMNgIEIARBAXYhBgNAIAAgBkECdGpBrBdqKAIAIQkCQCAGIgJBAXQiAyAESg0AIAggCUECdGohCiAAIAlqQagpaiENIAYhBQNAAkAgAyAETgRAIAMhAgwBCyAIIABBrBdqIgIgA0EBciIEQQJ0aigCACILQQJ0ai8BACIOIAggAiADQQJ0aigCACIQQQJ0ai8BACICTwRAIAIgDkcEQCADIQIMAgsgAyECIABBqClqIgMgC2otAAAgAyAQai0AAEsNAQsgBCECCyAKLwEAIgQgCCAAIAJBAnRqQawXaigCACIDQQJ0ai8BACILSQRAIAUhAgwCCwJAIAQgC0cNACANLQAAIAAgA2pBqClqLQAASw0AIAUhAgwCCyAAIAVBAnRqQawXaiADNgIAIAIhBSACQQF0IgMgACgCoCkiBEwNAAsLIAAgAkECdGpBrBdqIAk2AgAgBkECTgRAIAZBAWshBiAAKAKgKSEEDAELCyAAKAKgKSEDA0AgByEGIAAgA0EBayIENgKgKSAAKAKwFyEKIAAgACADQQJ0akGsF2ooAgAiCTYCsBdBASECAkAgA0EDSA0AIAggCUECdGohDSAAIAlqQagpaiELQQIhA0EBIQUDQAJAIAMgBE4EQCADIQIMAQsgCCAAQawXaiICIANBAXIiB0ECdGooAgAiBEECdGovAQAiDiAIIAIgA0ECdGooAgAiEEECdGovAQAiAk8EQCACIA5HBEAgAyECDAILIAMhAiAAQagpaiIDIARqLQAAIAMgEGotAABLDQELIAchAgsgDS8BACIHIAggACACQQJ0akGsF2ooAgAiA0ECdGovAQAiBEkEQCAFIQIMAgsCQCAEIAdHDQAgCy0AACAAIANqQagpai0AAEsNACAFIQIMAgsgACAFQQJ0akGsF2ogAzYCACACIQUgAkEBdCIDIAAoAqApIgRMDQALC0ECIQMgAEGsF2oiByACQQJ0aiAJNgIAIAAgACgCpClBAWsiBTYCpCkgACgCsBchAiAHIAVBAnRqIAo2AgAgACAAKAKkKUEBayIFNgKkKSAHIAVBAnRqIAI2AgAgCCAGQQJ0aiINIAggAkECdGoiBS8BACAIIApBAnRqIgQvAQBqOwEAIABBqClqIgkgBmoiCyACIAlqLQAAIgIgCSAKai0AACIKIAIgCksbQQFqOgAAIAUgBjsBAiAEIAY7AQIgACAGNgKwF0EBIQVBASECAkAgACgCoCkiBEECSA0AA0AgDS8BACIKIAggAAJ/IAMgAyAETg0AGiAIIAcgA0EBciICQQJ0aigCACIEQQJ0ai8BACIOIAggByADQQJ0aigCACIQQQJ0ai8BACISTwRAIAMgDiASRw0BGiADIAQgCWotAAAgCSAQai0AAEsNARoLIAILIgJBAnRqQawXaigCACIDQQJ0ai8BACIESQRAIAUhAgwCCwJAIAQgCkcNACALLQAAIAAgA2pBqClqLQAASw0AIAUhAgwCCyAAIAVBAnRqQawXaiADNgIAIAIhBSACQQF0IgMgACgCoCkiBEwNAAsLIAZBAWohByAAIAJBAnRqQawXaiAGNgIAIAAoAqApIgNBAUoNAAsgACAAKAKkKUEBayICNgKkKSAAQawXaiIDIAJBAnRqIAAoArAXNgIAIAEoAgQhCSABKAIIIgIoAhAhBiACKAIIIQogAigCBCEQIAIoAgAhDSABKAIAIQcgAEGkF2pCADcBACAAQZwXakIANwEAIABBlBdqQgA3AQAgAEGMF2oiAUIANwEAQQAhBSAHIAMgACgCpClBAnRqKAIAQQJ0akEAOwECAkAgACgCpCkiAkG7BEoNACACQQFqIQIDQCAHIAAgAkECdGpBrBdqKAIAIgRBAnQiEmoiCyAHIAsvAQJBAnRqLwECIgNBAWogBiADIAZJGyIOOwECIAMgBk8hEwJAIAQgCUoNACAAIA5BAXRqQYwXaiIDIAMvAQBBAWo7AQBBACEDIAQgCk4EQCAQIAQgCmtBAnRqKAIAIQMLIBEgESgCACALLwEAIgQgAyAOamxqNgIAIA1FDQAgDyAPKAIAIAMgDSASai8BAmogBGxqNgIACyAFIBNqIQUgAkEBaiICQb0ERw0ACyAFRQ0AIAAgBkEBdGpBjBdqIQQDQCAGIQIDQCAAIAIiA0EBayICQQF0akGMF2oiDy8BACIKRQ0ACyAPIApBAWs7AQAgACADQQF0akGMF2oiAiACLwEAQQJqOwEAIAQgBC8BAEEBayIDOwEAIAVBAkohAiAFQQJrIQUgAg0ACyAGRQ0AQb0EIQIDQCADQf//A3EiBQRAA0AgACACQQFrIgJBAnRqQawXaigCACIDIAlKDQAgByADQQJ0aiIDLwECIAZHBEAgESARKAIAIAYgAy8BAGxqIgQ2AgAgESAEIAMvAQAgAy8BAmxrNgIAIAMgBjsBAgsgBUEBayIFDQALCyAGQQFrIgZFDQEgACAGQQF0akGMF2ovAQAhAwwACwALIwBBIGsiAiABIgAvAQBBAXQiATsBAiACIAEgAC8BAmpBAXQiATsBBCACIAEgAC8BBGpBAXQiATsBBiACIAEgAC8BBmpBAXQiATsBCCACIAEgAC8BCGpBAXQiATsBCiACIAEgAC8BCmpBAXQiATsBDCACIAEgAC8BDGpBAXQiATsBDiACIAEgAC8BDmpBAXQiATsBECACIAEgAC8BEGpBAXQiATsBEiACIAEgAC8BEmpBAXQiATsBFCACIAEgAC8BFGpBAXQiATsBFiACIAEgAC8BFmpBAXQiATsBGCACIAEgAC8BGGpBAXQiATsBGiACIAEgAC8BGmpBAXQiATsBHCACIAAvARwgAWpBAXQ7AR5BACEAIAxBAE4EQANAIAggAEECdGoiAy8BAiIBBEAgAiABQQF0aiIFIAUvAQAiBUEBajsBACADIAWtQoD+A4NCCIhCgpCAgQh+QpDCiKKIAYNCgYKEiBB+QiCIp0H/AXEgBUH/AXGtQoKQgIEIfkKQwoiiiAGDQoGChIgQfkIYiKdBgP4DcXJBECABa3Y7AQALIAAgDEchASAAQQFqIQAgAQ0ACwsLcgEBfyMAQRBrIgQkAAJ/QQAgAEUNABogAEEIaiEAIAFFBEAgAlBFBEAgAARAIABBADYCBCAAQRI2AgALQQAMAgtBAEIAIAMgABA6DAELIAQgAjcDCCAEIAE2AgAgBEIBIAMgABA6CyEAIARBEGokACAACyIAIAAgASACIAMQJiIARQRAQQAPCyAAKAIwQQAgAiADECULAwABC8gFAQR/IABB//8DcSEDIABBEHYhBEEBIQAgAkEBRgRAIAMgAS0AAGpB8f8DcCIAIARqQfH/A3BBEHQgAHIPCwJAIAEEfyACQRBJDQECQCACQa8rSwRAA0AgAkGwK2shAkG1BSEFIAEhAANAIAMgAC0AAGoiAyAEaiADIAAtAAFqIgNqIAMgAC0AAmoiA2ogAyAALQADaiIDaiADIAAtAARqIgNqIAMgAC0ABWoiA2ogAyAALQAGaiIDaiADIAAtAAdqIgNqIQQgBQRAIABBCGohACAFQQFrIQUMAQsLIARB8f8DcCEEIANB8f8DcCEDIAFBsCtqIQEgAkGvK0sNAAsgAkEISQ0BCwNAIAMgAS0AAGoiACAEaiAAIAEtAAFqIgBqIAAgAS0AAmoiAGogACABLQADaiIAaiAAIAEtAARqIgBqIAAgAS0ABWoiAGogACABLQAGaiIAaiAAIAEtAAdqIgNqIQQgAUEIaiEBIAJBCGsiAkEHSw0ACwsCQCACRQ0AIAJBAWshBiACQQNxIgUEQCABIQADQCACQQFrIQIgAyAALQAAaiIDIARqIQQgAEEBaiIBIQAgBUEBayIFDQALCyAGQQNJDQADQCADIAEtAABqIgAgAS0AAWoiBSABLQACaiIGIAEtAANqIgMgBiAFIAAgBGpqamohBCABQQRqIQEgAkEEayICDQALCyADQfH/A3AgBEHx/wNwQRB0cgVBAQsPCwJAIAJFDQAgAkEBayEGIAJBA3EiBQRAIAEhAANAIAJBAWshAiADIAAtAABqIgMgBGohBCAAQQFqIgEhACAFQQFrIgUNAAsLIAZBA0kNAANAIAMgAS0AAGoiACABLQABaiIFIAEtAAJqIgYgAS0AA2oiAyAGIAUgACAEampqaiEEIAFBBGohASACQQRrIgINAAsLIANB8f8DcCAEQfH/A3BBEHRyCx8AIAAgAiADQcCAASgCABEAACEAIAEgAiADEAcaIAALIwAgACAAKAJAIAIgA0HUgAEoAgARAAA2AkAgASACIAMQBxoLzSoCGH8HfiAAKAIMIgIgACgCECIDaiEQIAMgAWshASAAKAIAIgUgACgCBGohA0F/IAAoAhwiBygCpAF0IQRBfyAHKAKgAXQhCyAHKAI4IQwCf0EAIAcoAiwiEUUNABpBACACIAxJDQAaIAJBhAJqIAwgEWpNCyEWIBBBgwJrIRMgASACaiEXIANBDmshFCAEQX9zIRggC0F/cyESIAcoApwBIRUgBygCmAEhDSAHKAKIASEIIAc1AoQBIR0gBygCNCEOIAcoAjAhGSAQQQFqIQ8DQCAIQThyIQYgBSAIQQN2QQdxayELAn8gAiANIAUpAAAgCK2GIB2EIh2nIBJxQQJ0IgFqIgMtAAAiBA0AGiACIAEgDWoiAS0AAjoAACAGIAEtAAEiAWshBiACQQFqIA0gHSABrYgiHacgEnFBAnQiAWoiAy0AACIEDQAaIAIgASANaiIDLQACOgABIAYgAy0AASIDayEGIA0gHSADrYgiHacgEnFBAnRqIgMtAAAhBCACQQJqCyEBIAtBB2ohBSAGIAMtAAEiAmshCCAdIAKtiCEdAkACQAJAIARB/wFxRQ0AAkACQAJAAkACQANAIARBEHEEQCAVIB0gBK1CD4OIIhqnIBhxQQJ0aiECAn8gCCAEQQ9xIgZrIgRBG0sEQCAEIQggBQwBCyAEQThyIQggBSkAACAErYYgGoQhGiAFIARBA3ZrQQdqCyELIAMzAQIhGyAIIAItAAEiA2shCCAaIAOtiCEaIAItAAAiBEEQcQ0CA0AgBEHAAHFFBEAgCCAVIAIvAQJBAnRqIBqnQX8gBHRBf3NxQQJ0aiICLQABIgNrIQggGiADrYghGiACLQAAIgRBEHFFDQEMBAsLIAdB0f4ANgIEIABB7A42AhggGiEdDAMLIARB/wFxIgJBwABxRQRAIAggDSADLwECQQJ0aiAdp0F/IAJ0QX9zcUECdGoiAy0AASICayEIIB0gAq2IIR0gAy0AACIERQ0HDAELCyAEQSBxBEAgB0G//gA2AgQgASECDAgLIAdB0f4ANgIEIABB0A42AhggASECDAcLIB1BfyAGdEF/c62DIBt8IhunIQUgCCAEQQ9xIgNrIQggGiAErUIPg4ghHSABIBdrIgYgAjMBAiAaQX8gA3RBf3Otg3ynIgRPDQIgBCAGayIGIBlNDQEgBygCjEdFDQEgB0HR/gA2AgQgAEG5DDYCGAsgASECIAshBQwFCwJAIA5FBEAgDCARIAZraiEDDAELIAYgDk0EQCAMIA4gBmtqIQMMAQsgDCARIAYgDmsiBmtqIQMgBSAGTQ0AIAUgBmshBQJAAkAgASADTSABIA8gAWusIhogBq0iGyAaIBtUGyIapyIGaiICIANLcQ0AIAMgBmogAUsgASADT3ENACABIAMgBhAHGiACIQEMAQsgASADIAMgAWsiASABQR91IgFqIAFzIgIQByACaiEBIBogAq0iHn0iHFANACACIANqIQIDQAJAIBwgHiAcIB5UGyIbQiBUBEAgGyEaDAELIBsiGkIgfSIgQgWIQgF8QgODIh9QRQRAA0AgASACKQAANwAAIAEgAikAGDcAGCABIAIpABA3ABAgASACKQAINwAIIBpCIH0hGiACQSBqIQIgAUEgaiEBIB9CAX0iH0IAUg0ACwsgIELgAFQNAANAIAEgAikAADcAACABIAIpABg3ABggASACKQAQNwAQIAEgAikACDcACCABIAIpADg3ADggASACKQAwNwAwIAEgAikAKDcAKCABIAIpACA3ACAgASACKQBYNwBYIAEgAikAUDcAUCABIAIpAEg3AEggASACKQBANwBAIAEgAikAYDcAYCABIAIpAGg3AGggASACKQBwNwBwIAEgAikAeDcAeCACQYABaiECIAFBgAFqIQEgGkKAAX0iGkIfVg0ACwsgGkIQWgRAIAEgAikAADcAACABIAIpAAg3AAggGkIQfSEaIAJBEGohAiABQRBqIQELIBpCCFoEQCABIAIpAAA3AAAgGkIIfSEaIAJBCGohAiABQQhqIQELIBpCBFoEQCABIAIoAAA2AAAgGkIEfSEaIAJBBGohAiABQQRqIQELIBpCAloEQCABIAIvAAA7AAAgGkICfSEaIAJBAmohAiABQQJqIQELIBwgG30hHCAaUEUEQCABIAItAAA6AAAgAkEBaiECIAFBAWohAQsgHEIAUg0ACwsgDiEGIAwhAwsgBSAGSwRAAkACQCABIANNIAEgDyABa6wiGiAGrSIbIBogG1QbIhqnIglqIgIgA0txDQAgAyAJaiABSyABIANPcQ0AIAEgAyAJEAcaDAELIAEgAyADIAFrIgEgAUEfdSIBaiABcyIBEAcgAWohAiAaIAGtIh59IhxQDQAgASADaiEBA0ACQCAcIB4gHCAeVBsiG0IgVARAIBshGgwBCyAbIhpCIH0iIEIFiEIBfEIDgyIfUEUEQANAIAIgASkAADcAACACIAEpABg3ABggAiABKQAQNwAQIAIgASkACDcACCAaQiB9IRogAUEgaiEBIAJBIGohAiAfQgF9Ih9CAFINAAsLICBC4ABUDQADQCACIAEpAAA3AAAgAiABKQAYNwAYIAIgASkAEDcAECACIAEpAAg3AAggAiABKQA4NwA4IAIgASkAMDcAMCACIAEpACg3ACggAiABKQAgNwAgIAIgASkAWDcAWCACIAEpAFA3AFAgAiABKQBINwBIIAIgASkAQDcAQCACIAEpAGA3AGAgAiABKQBoNwBoIAIgASkAcDcAcCACIAEpAHg3AHggAUGAAWohASACQYABaiECIBpCgAF9IhpCH1YNAAsLIBpCEFoEQCACIAEpAAA3AAAgAiABKQAINwAIIBpCEH0hGiACQRBqIQIgAUEQaiEBCyAaQghaBEAgAiABKQAANwAAIBpCCH0hGiACQQhqIQIgAUEIaiEBCyAaQgRaBEAgAiABKAAANgAAIBpCBH0hGiACQQRqIQIgAUEEaiEBCyAaQgJaBEAgAiABLwAAOwAAIBpCAn0hGiACQQJqIQIgAUECaiEBCyAcIBt9IRwgGlBFBEAgAiABLQAAOgAAIAJBAWohAiABQQFqIQELIBxCAFINAAsLIAUgBmshAUEAIARrIQUCQCAEQQdLBEAgBCEDDAELIAEgBE0EQCAEIQMMAQsgAiAEayEFA0ACQCACIAUpAAA3AAAgBEEBdCEDIAEgBGshASACIARqIQIgBEEDSw0AIAMhBCABIANLDQELC0EAIANrIQULIAIgBWohBAJAIAUgDyACa6wiGiABrSIbIBogG1QbIhqnIgFIIAVBf0pxDQAgBUEBSCABIARqIAJLcQ0AIAIgBCABEAcgAWohAgwDCyACIAQgAyADQR91IgFqIAFzIgEQByABaiECIBogAa0iHn0iHFANAiABIARqIQEDQAJAIBwgHiAcIB5UGyIbQiBUBEAgGyEaDAELIBsiGkIgfSIgQgWIQgF8QgODIh9QRQRAA0AgAiABKQAANwAAIAIgASkAGDcAGCACIAEpABA3ABAgAiABKQAINwAIIBpCIH0hGiABQSBqIQEgAkEgaiECIB9CAX0iH0IAUg0ACwsgIELgAFQNAANAIAIgASkAADcAACACIAEpABg3ABggAiABKQAQNwAQIAIgASkACDcACCACIAEpADg3ADggAiABKQAwNwAwIAIgASkAKDcAKCACIAEpACA3ACAgAiABKQBYNwBYIAIgASkAUDcAUCACIAEpAEg3AEggAiABKQBANwBAIAIgASkAYDcAYCACIAEpAGg3AGggAiABKQBwNwBwIAIgASkAeDcAeCABQYABaiEBIAJBgAFqIQIgGkKAAX0iGkIfVg0ACwsgGkIQWgRAIAIgASkAADcAACACIAEpAAg3AAggGkIQfSEaIAJBEGohAiABQRBqIQELIBpCCFoEQCACIAEpAAA3AAAgGkIIfSEaIAJBCGohAiABQQhqIQELIBpCBFoEQCACIAEoAAA2AAAgGkIEfSEaIAJBBGohAiABQQRqIQELIBpCAloEQCACIAEvAAA7AAAgGkICfSEaIAJBAmohAiABQQJqIQELIBwgG30hHCAaUEUEQCACIAEtAAA6AAAgAkEBaiECIAFBAWohAQsgHFBFDQALDAILAkAgASADTSABIA8gAWusIhogBa0iGyAaIBtUGyIapyIEaiICIANLcQ0AIAMgBGogAUsgASADT3ENACABIAMgBBAHGgwCCyABIAMgAyABayIBIAFBH3UiAWogAXMiARAHIAFqIQIgGiABrSIefSIcUA0BIAEgA2ohAQNAAkAgHCAeIBwgHlQbIhtCIFQEQCAbIRoMAQsgGyIaQiB9IiBCBYhCAXxCA4MiH1BFBEADQCACIAEpAAA3AAAgAiABKQAYNwAYIAIgASkAEDcAECACIAEpAAg3AAggGkIgfSEaIAFBIGohASACQSBqIQIgH0IBfSIfQgBSDQALCyAgQuAAVA0AA0AgAiABKQAANwAAIAIgASkAGDcAGCACIAEpABA3ABAgAiABKQAINwAIIAIgASkAODcAOCACIAEpADA3ADAgAiABKQAoNwAoIAIgASkAIDcAICACIAEpAFg3AFggAiABKQBQNwBQIAIgASkASDcASCACIAEpAEA3AEAgAiABKQBgNwBgIAIgASkAaDcAaCACIAEpAHA3AHAgAiABKQB4NwB4IAFBgAFqIQEgAkGAAWohAiAaQoABfSIaQh9WDQALCyAaQhBaBEAgAiABKQAANwAAIAIgASkACDcACCAaQhB9IRogAkEQaiECIAFBEGohAQsgGkIIWgRAIAIgASkAADcAACAaQgh9IRogAkEIaiECIAFBCGohAQsgGkIEWgRAIAIgASgAADYAACAaQgR9IRogAkEEaiECIAFBBGohAQsgGkICWgRAIAIgAS8AADsAACAaQgJ9IRogAkECaiECIAFBAmohAQsgHCAbfSEcIBpQRQRAIAIgAS0AADoAACACQQFqIQIgAUEBaiEBCyAcUEUNAAsMAQsCQAJAIBYEQAJAIAQgBUkEQCAHKAKYRyAESw0BCyABIARrIQMCQEEAIARrIgVBf0ogDyABa6wiGiAbIBogG1QbIhqnIgIgBUpxDQAgBUEBSCACIANqIAFLcQ0AIAEgAyACEAcgAmohAgwFCyABIAMgBCAEQR91IgFqIAFzIgEQByABaiECIBogAa0iHn0iHFANBCABIANqIQEDQAJAIBwgHiAcIB5UGyIbQiBUBEAgGyEaDAELIBsiGkIgfSIgQgWIQgF8QgODIh9QRQRAA0AgAiABKQAANwAAIAIgASkAGDcAGCACIAEpABA3ABAgAiABKQAINwAIIBpCIH0hGiABQSBqIQEgAkEgaiECIB9CAX0iH0IAUg0ACwsgIELgAFQNAANAIAIgASkAADcAACACIAEpABg3ABggAiABKQAQNwAQIAIgASkACDcACCACIAEpADg3ADggAiABKQAwNwAwIAIgASkAKDcAKCACIAEpACA3ACAgAiABKQBYNwBYIAIgASkAUDcAUCACIAEpAEg3AEggAiABKQBANwBAIAIgASkAYDcAYCACIAEpAGg3AGggAiABKQBwNwBwIAIgASkAeDcAeCABQYABaiEBIAJBgAFqIQIgGkKAAX0iGkIfVg0ACwsgGkIQWgRAIAIgASkAADcAACACIAEpAAg3AAggGkIQfSEaIAJBEGohAiABQRBqIQELIBpCCFoEQCACIAEpAAA3AAAgGkIIfSEaIAJBCGohAiABQQhqIQELIBpCBFoEQCACIAEoAAA2AAAgGkIEfSEaIAJBBGohAiABQQRqIQELIBpCAloEQCACIAEvAAA7AAAgGkICfSEaIAJBAmohAiABQQJqIQELIBwgG30hHCAaUEUEQCACIAEtAAA6AAAgAkEBaiECIAFBAWohAQsgHFBFDQALDAQLIBAgAWsiCUEBaiIGIAUgBSAGSxshAyABIARrIQIgAUEHcUUNAiADRQ0CIAEgAi0AADoAACACQQFqIQIgAUEBaiIGQQdxQQAgA0EBayIFGw0BIAYhASAFIQMgCSEGDAILAkAgBCAFSQRAIAcoAphHIARLDQELIAEgASAEayIGKQAANwAAIAEgBUEBa0EHcUEBaiIDaiECIAUgA2siBEUNAyADIAZqIQEDQCACIAEpAAA3AAAgAUEIaiEBIAJBCGohAiAEQQhrIgQNAAsMAwsgASAEIAUQPyECDAILIAEgAi0AADoAASAJQQFrIQYgA0ECayEFIAJBAWohAgJAIAFBAmoiCkEHcUUNACAFRQ0AIAEgAi0AADoAAiAJQQJrIQYgA0EDayEFIAJBAWohAgJAIAFBA2oiCkEHcUUNACAFRQ0AIAEgAi0AADoAAyAJQQNrIQYgA0EEayEFIAJBAWohAgJAIAFBBGoiCkEHcUUNACAFRQ0AIAEgAi0AADoABCAJQQRrIQYgA0EFayEFIAJBAWohAgJAIAFBBWoiCkEHcUUNACAFRQ0AIAEgAi0AADoABSAJQQVrIQYgA0EGayEFIAJBAWohAgJAIAFBBmoiCkEHcUUNACAFRQ0AIAEgAi0AADoABiAJQQZrIQYgA0EHayEFIAJBAWohAgJAIAFBB2oiCkEHcUUNACAFRQ0AIAEgAi0AADoAByAJQQdrIQYgA0EIayEDIAFBCGohASACQQFqIQIMBgsgCiEBIAUhAwwFCyAKIQEgBSEDDAQLIAohASAFIQMMAwsgCiEBIAUhAwwCCyAKIQEgBSEDDAELIAohASAFIQMLAkACQCAGQRdNBEAgA0UNASADQQFrIQUgA0EHcSIEBEADQCABIAItAAA6AAAgA0EBayEDIAFBAWohASACQQFqIQIgBEEBayIEDQALCyAFQQdJDQEDQCABIAItAAA6AAAgASACLQABOgABIAEgAi0AAjoAAiABIAItAAM6AAMgASACLQAEOgAEIAEgAi0ABToABSABIAItAAY6AAYgASACLQAHOgAHIAFBCGohASACQQhqIQIgA0EIayIDDQALDAELIAMNAQsgASECDAELIAEgBCADED8hAgsgCyEFDAELIAEgAy0AAjoAACABQQFqIQILIAUgFE8NACACIBNJDQELCyAAIAI2AgwgACAFIAhBA3ZrIgE2AgAgACATIAJrQYMCajYCECAAIBQgAWtBDmo2AgQgByAIQQdxIgA2AogBIAcgHUJ/IACthkJ/hYM+AoQBC+cFAQR/IAMgAiACIANLGyEEIAAgAWshAgJAIABBB3FFDQAgBEUNACAAIAItAAA6AAAgA0EBayEGIAJBAWohAiAAQQFqIgdBB3FBACAEQQFrIgUbRQRAIAchACAFIQQgBiEDDAELIAAgAi0AADoAASADQQJrIQYgBEECayEFIAJBAWohAgJAIABBAmoiB0EHcUUNACAFRQ0AIAAgAi0AADoAAiADQQNrIQYgBEEDayEFIAJBAWohAgJAIABBA2oiB0EHcUUNACAFRQ0AIAAgAi0AADoAAyADQQRrIQYgBEEEayEFIAJBAWohAgJAIABBBGoiB0EHcUUNACAFRQ0AIAAgAi0AADoABCADQQVrIQYgBEEFayEFIAJBAWohAgJAIABBBWoiB0EHcUUNACAFRQ0AIAAgAi0AADoABSADQQZrIQYgBEEGayEFIAJBAWohAgJAIABBBmoiB0EHcUUNACAFRQ0AIAAgAi0AADoABiADQQdrIQYgBEEHayEFIAJBAWohAgJAIABBB2oiB0EHcUUNACAFRQ0AIAAgAi0AADoAByADQQhrIQMgBEEIayEEIABBCGohACACQQFqIQIMBgsgByEAIAUhBCAGIQMMBQsgByEAIAUhBCAGIQMMBAsgByEAIAUhBCAGIQMMAwsgByEAIAUhBCAGIQMMAgsgByEAIAUhBCAGIQMMAQsgByEAIAUhBCAGIQMLAkAgA0EXTQRAIARFDQEgBEEBayEBIARBB3EiAwRAA0AgACACLQAAOgAAIARBAWshBCAAQQFqIQAgAkEBaiECIANBAWsiAw0ACwsgAUEHSQ0BA0AgACACLQAAOgAAIAAgAi0AAToAASAAIAItAAI6AAIgACACLQADOgADIAAgAi0ABDoABCAAIAItAAU6AAUgACACLQAGOgAGIAAgAi0ABzoAByAAQQhqIQAgAkEIaiECIARBCGsiBA0ACwwBCyAERQ0AIAAgASAEED8hAAsgAAvyCAEXfyAAKAJoIgwgACgCMEGGAmsiBWtBACAFIAxJGyENIAAoAnQhAiAAKAKQASEPIAAoAkgiDiAMaiIJIAAoAnAiBUECIAUbIgVBAWsiBmoiAy0AASESIAMtAAAhEyAGIA5qIQZBAyEDIAAoApQBIRYgACgCPCEUIAAoAkwhECAAKAI4IRECQAJ/IAVBA0kEQCANIQggDgwBCyAAIABBACAJLQABIAAoAnwRAAAgCS0AAiAAKAJ8EQAAIQoDQCAAIAogAyAJai0AACAAKAJ8EQAAIQogACgCUCAKQQF0ai8BACIIIAEgCCABQf//A3FJIggbIQEgA0ECayAHIAgbIQcgA0EBaiIDIAVNDQALIAFB//8DcSAHIA1qIghB//8DcU0NASAGIAdB//8DcSIDayEGIA4gA2sLIQMCQAJAIAwgAUH//wNxTQ0AIAIgAkECdiAFIA9JGyEKIA1B//8DcSEVIAlBAmohDyAJQQRrIRcDQAJAAkAgBiABQf//A3EiC2otAAAgE0cNACAGIAtBAWoiAWotAAAgEkcNACADIAtqIgItAAAgCS0AAEcNACABIANqLQAAIAktAAFGDQELIApBAWsiCkUNAiAQIAsgEXFBAXRqLwEAIgEgCEH//wNxSw0BDAILIAJBAmohAUEAIQQgDyECAkADQCACLQAAIAEtAABHDQEgAi0AASABLQABRwRAIARBAXIhBAwCCyACLQACIAEtAAJHBEAgBEECciEEDAILIAItAAMgAS0AA0cEQCAEQQNyIQQMAgsgAi0ABCABLQAERwRAIARBBHIhBAwCCyACLQAFIAEtAAVHBEAgBEEFciEEDAILIAItAAYgAS0ABkcEQCAEQQZyIQQMAgsgAi0AByABLQAHRwRAIARBB3IhBAwCCyABQQhqIQEgAkEIaiECIARB+AFJIRggBEEIaiEEIBgNAAtBgAIhBAsCQAJAIAUgBEECaiICSQRAIAAgCyAHQf//A3FrIgY2AmwgAiAUSwRAIBQPCyACIBZPBEAgAg8LIAkgBEEBaiIFaiIBLQABIRIgAS0AACETAkAgAkEESQ0AIAIgBmogDE8NACAGQf//A3EhCCAEQQFrIQtBACEDQQAhBwNAIBAgAyAIaiARcUEBdGovAQAiASAGQf//A3FJBEAgAyAVaiABTw0IIAMhByABIQYLIANBAWoiAyALTQ0ACyAAIAAgAEEAIAIgF2oiAS0AACAAKAJ8EQAAIAEtAAEgACgCfBEAACABLQACIAAoAnwRAAAhASAAKAJQIAFBAXRqLwEAIgEgBkH//wNxTwRAIAdB//8DcSEDIAYhAQwDCyAEQQJrIgdB//8DcSIDIBVqIAFPDQYMAgsgAyAFaiEGIAIhBQsgCkEBayIKRQ0DIBAgCyARcUEBdGovAQAiASAIQf//A3FNDQMMAQsgByANaiEIIA4gA2siAyAFaiEGIAIhBQsgDCABQf//A3FLDQALCyAFDwsgAiEFCyAFIAAoAjwiACAAIAVLGwuGBQETfyAAKAJ0IgMgA0ECdiAAKAJwIgNBAiADGyIDIAAoApABSRshByAAKAJoIgogACgCMEGGAmsiBWtB//8DcUEAIAUgCkkbIQwgACgCSCIIIApqIgkgA0EBayICaiIFLQABIQ0gBS0AACEOIAlBAmohBSACIAhqIQsgACgClAEhEiAAKAI8IQ8gACgCTCEQIAAoAjghESAAKAKIAUEFSCETA0ACQCAKIAFB//8DcU0NAANAAkACQCALIAFB//8DcSIGai0AACAORw0AIAsgBkEBaiIBai0AACANRw0AIAYgCGoiAi0AACAJLQAARw0AIAEgCGotAAAgCS0AAUYNAQsgB0EBayIHRQ0CIAwgECAGIBFxQQF0ai8BACIBSQ0BDAILCyACQQJqIQRBACECIAUhAQJAA0AgAS0AACAELQAARw0BIAEtAAEgBC0AAUcEQCACQQFyIQIMAgsgAS0AAiAELQACRwRAIAJBAnIhAgwCCyABLQADIAQtAANHBEAgAkEDciECDAILIAEtAAQgBC0ABEcEQCACQQRyIQIMAgsgAS0ABSAELQAFRwRAIAJBBXIhAgwCCyABLQAGIAQtAAZHBEAgAkEGciECDAILIAEtAAcgBC0AB0cEQCACQQdyIQIMAgsgBEEIaiEEIAFBCGohASACQfgBSSEUIAJBCGohAiAUDQALQYACIQILAkAgAyACQQJqIgFJBEAgACAGNgJsIAEgD0sEQCAPDwsgASASTwRAIAEPCyAIIAJBAWoiA2ohCyADIAlqIgMtAAEhDSADLQAAIQ4gASEDDAELIBMNAQsgB0EBayIHRQ0AIAwgECAGIBFxQQF0ai8BACIBSQ0BCwsgAwvLAQECfwJAA0AgAC0AACABLQAARw0BIAAtAAEgAS0AAUcEQCACQQFyDwsgAC0AAiABLQACRwRAIAJBAnIPCyAALQADIAEtAANHBEAgAkEDcg8LIAAtAAQgAS0ABEcEQCACQQRyDwsgAC0ABSABLQAFRwRAIAJBBXIPCyAALQAGIAEtAAZHBEAgAkEGcg8LIAAtAAcgAS0AB0cEQCACQQdyDwsgAUEIaiEBIABBCGohACACQfgBSSEDIAJBCGohAiADDQALQYACIQILIAIL5wwBB38gAEF/cyEAIAJBF08EQAJAIAFBA3FFDQAgAS0AACAAQf8BcXNBAnRB0BhqKAIAIABBCHZzIQAgAkEBayIEQQAgAUEBaiIDQQNxG0UEQCAEIQIgAyEBDAELIAEtAAEgAEH/AXFzQQJ0QdAYaigCACAAQQh2cyEAIAFBAmohAwJAIAJBAmsiBEUNACADQQNxRQ0AIAEtAAIgAEH/AXFzQQJ0QdAYaigCACAAQQh2cyEAIAFBA2ohAwJAIAJBA2siBEUNACADQQNxRQ0AIAEtAAMgAEH/AXFzQQJ0QdAYaigCACAAQQh2cyEAIAFBBGohASACQQRrIQIMAgsgBCECIAMhAQwBCyAEIQIgAyEBCyACQRRuIgNBbGwhCQJAIANBAWsiCEUEQEEAIQQMAQsgA0EUbCABakEUayEDQQAhBANAIAEoAhAgB3MiB0EWdkH8B3FB0DhqKAIAIAdBDnZB/AdxQdAwaigCACAHQQZ2QfwHcUHQKGooAgAgB0H/AXFBAnRB0CBqKAIAc3NzIQcgASgCDCAGcyIGQRZ2QfwHcUHQOGooAgAgBkEOdkH8B3FB0DBqKAIAIAZBBnZB/AdxQdAoaigCACAGQf8BcUECdEHQIGooAgBzc3MhBiABKAIIIAVzIgVBFnZB/AdxQdA4aigCACAFQQ52QfwHcUHQMGooAgAgBUEGdkH8B3FB0ChqKAIAIAVB/wFxQQJ0QdAgaigCAHNzcyEFIAEoAgQgBHMiBEEWdkH8B3FB0DhqKAIAIARBDnZB/AdxQdAwaigCACAEQQZ2QfwHcUHQKGooAgAgBEH/AXFBAnRB0CBqKAIAc3NzIQQgASgCACAAcyIAQRZ2QfwHcUHQOGooAgAgAEEOdkH8B3FB0DBqKAIAIABBBnZB/AdxQdAoaigCACAAQf8BcUECdEHQIGooAgBzc3MhACABQRRqIQEgCEEBayIIDQALIAMhAQsgAiAJaiECIAEoAhAgASgCDCABKAIIIAEoAgQgASgCACAAcyIAQQh2IABB/wFxQQJ0QdAYaigCAHMiAEEIdiAAQf8BcUECdEHQGGooAgBzIgBBCHYgAEH/AXFBAnRB0BhqKAIAcyIAQf8BcUECdEHQGGooAgAgBHNzIABBCHZzIgBBCHYgAEH/AXFBAnRB0BhqKAIAcyIAQQh2IABB/wFxQQJ0QdAYaigCAHMiAEEIdiAAQf8BcUECdEHQGGooAgBzIgBB/wFxQQJ0QdAYaigCACAFc3MgAEEIdnMiAEEIdiAAQf8BcUECdEHQGGooAgBzIgBBCHYgAEH/AXFBAnRB0BhqKAIAcyIAQQh2IABB/wFxQQJ0QdAYaigCAHMiAEH/AXFBAnRB0BhqKAIAIAZzcyAAQQh2cyIAQQh2IABB/wFxQQJ0QdAYaigCAHMiAEEIdiAAQf8BcUECdEHQGGooAgBzIgBBCHYgAEH/AXFBAnRB0BhqKAIAcyIAQf8BcUECdEHQGGooAgAgB3NzIABBCHZzIgBBCHYgAEH/AXFBAnRB0BhqKAIAcyIAQQh2IABB/wFxQQJ0QdAYaigCAHMiAEEIdiAAQf8BcUECdEHQGGooAgBzIgBBCHYgAEH/AXFBAnRB0BhqKAIAcyEAIAFBFGohAQsgAkEHSwRAA0AgAS0AByABLQAGIAEtAAUgAS0ABCABLQADIAEtAAIgAS0AASABLQAAIABB/wFxc0ECdEHQGGooAgAgAEEIdnMiAEH/AXFzQQJ0QdAYaigCACAAQQh2cyIAQf8BcXNBAnRB0BhqKAIAIABBCHZzIgBB/wFxc0ECdEHQGGooAgAgAEEIdnMiAEH/AXFzQQJ0QdAYaigCACAAQQh2cyIAQf8BcXNBAnRB0BhqKAIAIABBCHZzIgBB/wFxc0ECdEHQGGooAgAgAEEIdnMiAEH/AXFzQQJ0QdAYaigCACAAQQh2cyEAIAFBCGohASACQQhrIgJBB0sNAAsLAkAgAkUNACACQQFxBH8gAS0AACAAQf8BcXNBAnRB0BhqKAIAIABBCHZzIQAgAUEBaiEBIAJBAWsFIAILIQMgAkEBRg0AA0AgAS0AASABLQAAIABB/wFxc0ECdEHQGGooAgAgAEEIdnMiAEH/AXFzQQJ0QdAYaigCACAAQQh2cyEAIAFBAmohASADQQJrIgMNAAsLIABBf3MLwgIBA38jAEEQayIIJAACfwJAIAAEQCAEDQEgBVANAQsgBgRAIAZBADYCBCAGQRI2AgALQQAMAQtBgAEQCSIHRQRAIAYEQCAGQQA2AgQgBkEONgIAC0EADAELIAcgATcDCCAHQgA3AwAgB0EoaiIJECogByAFNwMYIAcgBDYCECAHIAM6AGAgB0EANgJsIAdCADcCZCAAKQMYIQEgCEF/NgIIIAhCjoCAgPAANwMAIAdBECAIECQgAUL/gQGDhCIBNwNwIAcgAadBBnZBAXE6AHgCQCACRQ0AIAkgAhBgQX9KDQAgBxAGQQAMAQsgBhBfIgIEQCAAIAAoAjBBAWo2AjAgAiAHNgIIIAJBATYCBCACIAA2AgAgAkI/IAAgB0EAQgBBDkEBEQoAIgEgAUIAUxs3AxgLIAILIQAgCEEQaiQAIAALYgEBf0E4EAkiAUUEQCAABEAgAEEANgIEIABBDjYCAAtBAA8LIAFBADYCCCABQgA3AwAgAUIANwMgIAFCgICAgBA3AiwgAUEAOgAoIAFBADYCFCABQgA3AgwgAUEAOwE0IAELuwEBAX4gASkDACICQgKDUEUEQCAAIAEpAxA3AxALIAJCBINQRQRAIAAgASkDGDcDGAsgAkIIg1BFBEAgACABKQMgNwMgCyACQhCDUEUEQCAAIAEoAig2AigLIAJCIINQRQRAIAAgASgCLDYCLAsgAkLAAINQRQRAIAAgAS8BMDsBMAsgAkKAAYNQRQRAIAAgAS8BMjsBMgsgAkKAAoNQRQRAIAAgASgCNDYCNAsgACAAKQMAIAKENwMAQQALGQAgAUUEQEEADwsgACABKAIAIAEzAQQQGws3AQJ/IABBACABG0UEQCAAIAFGDwsgAC8BBCIDIAEvAQRGBH8gACgCACABKAIAIAMQPQVBAQtFCyIBAX8gAUUEQEEADwsgARAJIgJFBEBBAA8LIAIgACABEAcLKQAgACABIAIgAyAEEEUiAEUEQEEADwsgACACQQAgBBA1IQEgABAGIAELcQEBfgJ/AkAgAkJ/VwRAIAMEQCADQQA2AgQgA0EUNgIACwwBCyAAIAEgAhARIgRCf1cEQCADBEAgAyAAKAIMNgIAIAMgACgCEDYCBAsMAQtBACACIARXDQEaIAMEQCADQQA2AgQgA0ERNgIACwtBfwsLNQAgACABIAJBABAmIgBFBEBBfw8LIAMEQCADIAAtAAk6AAALIAQEQCAEIAAoAkQ2AgALQQAL/AECAn8BfiMAQRBrIgMkAAJAIAAgA0EOaiABQYAGQQAQRiIARQRAIAIhAAwBCyADLwEOIgFBBUkEQCACIQAMAQsgAC0AAEEBRwRAIAIhAAwBCyAAIAGtQv//A4MQFyIBRQRAIAIhAAwBCyABEH0aAkAgARAVIAIEfwJ/IAIvAQQhAEEAIAIoAgAiBEUNABpBACAEIABB1IABKAIAEQAACwVBAAtHBEAgAiEADAELIAEgAS0AAAR+IAEpAwggASkDEH0FQgALIgVC//8DgxATIAWnQf//A3FBgBBBABA1IgBFBEAgAiEADAELIAIQEAsgARAICyADQRBqJAAgAAvmDwIIfwJ+IwBB4ABrIgckAEEeQS4gAxshCwJAAkAgAgRAIAIiBSIGLQAABH4gBikDCCAGKQMQfQVCAAsgC61aDQEgBARAIARBADYCBCAEQRM2AgALQn8hDQwCCyABIAutIAcgBBAtIgUNAEJ/IQ0MAQsgBUIEEBMoAABBoxJBqBIgAxsoAABHBEAgBARAIARBADYCBCAEQRM2AgALQn8hDSACDQEgBRAIDAELIABCADcDICAAQQA2AhggAEL/////DzcDECAAQQA7AQwgAEG/hig2AgggAEEBOgAGIABBADsBBCAAQQA2AgAgAEIANwNIIABBgIDYjXg2AkQgAEIANwMoIABCADcDMCAAQgA3AzggAEFAa0EAOwEAIABCADcDUCAAIAMEf0EABSAFEAwLOwEIIAAgBRAMOwEKIAAgBRAMOwEMIAAgBRAMNgIQIAUQDCEGIAUQDCEJIAdBADYCWCAHQgA3A1AgB0IANwNIIAcgCUEfcTYCPCAHIAZBC3Y2AjggByAGQQV2QT9xNgI0IAcgBkEBdEE+cTYCMCAHIAlBCXZB0ABqNgJEIAcgCUEFdkEPcUEBazYCQCAAIAdBMGoQBTYCFCAAIAUQFTYCGCAAIAUQFa03AyAgACAFEBWtNwMoIAUQDCEIIAUQDCEGIAACfiADBEBBACEJIABBADYCRCAAQQA7AUAgAEEANgI8QgAMAQsgBRAMIQkgACAFEAw2AjwgACAFEAw7AUAgACAFEBU2AkQgBRAVrQs3A0ggBS0AAEUEQCAEBEAgBEEANgIEIARBFDYCAAtCfyENIAINASAFEAgMAQsCQCAALwEMIgpBAXEEQCAKQcAAcQRAIABB//8DOwFSDAILIABBATsBUgwBCyAAQQA7AVILIABBADYCOCAAQgA3AzAgBiAIaiAJaiEKAkAgAgRAIAUtAAAEfiAFKQMIIAUpAxB9BUIACyAKrVoNASAEBEAgBEEANgIEIARBFTYCAAtCfyENDAILIAUQCCABIAqtQQAgBBAtIgUNAEJ/IQ0MAQsCQCAIRQ0AIAAgBSABIAhBASAEEGQiCDYCMCAIRQRAIAQoAgBBEUYEQCAEBEAgBEEANgIEIARBFTYCAAsLQn8hDSACDQIgBRAIDAILIAAtAA1BCHFFDQAgCEECECNBBUcNACAEBEAgBEEANgIEIARBFTYCAAtCfyENIAINASAFEAgMAQsgAEE0aiEIAkAgBkUNACAFIAEgBkEAIAQQRSIMRQRAQn8hDSACDQIgBRAIDAILIAwgBkGAAkGABCADGyAIIAQQbiEGIAwQBiAGRQRAQn8hDSACDQIgBRAIDAILIANFDQAgAEEBOgAECwJAIAlFDQAgACAFIAEgCUEAIAQQZCIBNgI4IAFFBEBCfyENIAINAiAFEAgMAgsgAC0ADUEIcUUNACABQQIQI0EFRw0AIAQEQCAEQQA2AgQgBEEVNgIAC0J/IQ0gAg0BIAUQCAwBCyAAIAAoAjRB9eABIAAoAjAQZzYCMCAAIAAoAjRB9cYBIAAoAjgQZzYCOAJAAkAgACkDKEL/////D1ENACAAKQMgQv////8PUQ0AIAApA0hC/////w9SDQELAkACQAJAIAgoAgAgB0EwakEBQYACQYAEIAMbIAQQRiIBRQRAIAJFDQEMAgsgASAHMwEwEBciAUUEQCAEBEAgBEEANgIEIARBDjYCAAsgAkUNAQwCCwJAIAApAyhC/////w9RBEAgACABEB03AygMAQsgA0UNAEEAIQYCQCABKQMQIg5CCHwiDSAOVA0AIAEpAwggDVQNACABIA03AxBBASEGCyABIAY6AAALIAApAyBC/////w9RBEAgACABEB03AyALAkAgAw0AIAApA0hC/////w9RBEAgACABEB03A0gLIAAoAjxB//8DRw0AIAAgARAVNgI8CyABLQAABH8gASkDECABKQMIUQVBAAsNAiAEBEAgBEEANgIEIARBFTYCAAsgARAIIAINAQsgBRAIC0J/IQ0MAgsgARAICyAFLQAARQRAIAQEQCAEQQA2AgQgBEEUNgIAC0J/IQ0gAg0BIAUQCAwBCyACRQRAIAUQCAtCfyENIAApA0hCf1cEQCAEBEAgBEEWNgIEIARBBDYCAAsMAQsjAEEQayIDJABBASEBAkAgACgCEEHjAEcNAEEAIQECQCAAKAI0IANBDmpBgbICQYAGQQAQRiICBEAgAy8BDiIFQQZLDQELIAQEQCAEQQA2AgQgBEEVNgIACwwBCyACIAWtQv//A4MQFyICRQRAIAQEQCAEQQA2AgQgBEEUNgIACwwBC0EBIQECQAJAAkAgAhAMQQFrDgICAQALQQAhASAEBEAgBEEANgIEIARBGDYCAAsgAhAIDAILIAApAyhCE1YhAQsgAkICEBMvAABBwYoBRwRAQQAhASAEBEAgBEEANgIEIARBGDYCAAsgAhAIDAELIAIQfUEBayIFQf8BcUEDTwRAQQAhASAEBEAgBEEANgIEIARBGDYCAAsgAhAIDAELIAMvAQ5BB0cEQEEAIQEgBARAIARBADYCBCAEQRU2AgALIAIQCAwBCyAAIAE6AAYgACAFQf8BcUGBAmo7AVIgACACEAw2AhAgAhAIQQEhAQsgA0EQaiQAIAFFDQAgCCAIKAIAEG02AgAgCiALaq0hDQsgB0HgAGokACANC4ECAQR/IwBBEGsiBCQAAkAgASAEQQxqQcAAQQAQJSIGRQ0AIAQoAgxBBWoiA0GAgARPBEAgAgRAIAJBADYCBCACQRI2AgALDAELQQAgA60QFyIDRQRAIAIEQCACQQA2AgQgAkEONgIACwwBCyADQQEQcCADIAEEfwJ/IAEvAQQhBUEAIAEoAgAiAUUNABpBACABIAVB1IABKAIAEQAACwVBAAsQEiADIAYgBCgCDBAsAn8gAy0AAEUEQCACBEAgAkEANgIEIAJBFDYCAAtBAAwBCyAAIAMtAAAEfiADKQMQBUIAC6dB//8DcSADKAIEEEcLIQUgAxAICyAEQRBqJAAgBQvgAQICfwF+QTAQCSICRQRAIAEEQCABQQA2AgQgAUEONgIAC0EADwsgAkIANwMIIAJBADYCACACQgA3AxAgAkIANwMYIAJCADcDICACQgA3ACUgAFAEQCACDwsCQCAAQv////8AVg0AIACnQQR0EAkiA0UNACACIAM2AgBBACEBQgEhBANAIAMgAUEEdGoiAUIANwIAIAFCADcABSAAIARSBEAgBKchASAEQgF8IQQMAQsLIAIgADcDCCACIAA3AxAgAg8LIAEEQCABQQA2AgQgAUEONgIAC0EAEBAgAhAGQQAL7gECA38BfiMAQRBrIgQkAAJAIARBDGpCBBAXIgNFBEBBfyECDAELAkAgAQRAIAJBgAZxIQUDQAJAIAUgASgCBHFFDQACQCADKQMIQgBUBEAgA0EAOgAADAELIANCADcDECADQQE6AAALIAMgAS8BCBANIAMgAS8BChANIAMtAABFBEAgAEEIaiIABEAgAEEANgIEIABBFDYCAAtBfyECDAQLQX8hAiAAIARBDGpCBBAbQQBIDQMgATMBCiIGUA0AIAAgASgCDCAGEBtBAEgNAwsgASgCACIBDQALC0EAIQILIAMQCAsgBEEQaiQAIAILPAEBfyAABEAgAUGABnEhAQNAIAEgACgCBHEEQCACIAAvAQpqQQRqIQILIAAoAgAiAA0ACwsgAkH//wNxC5wBAQN/IABFBEBBAA8LIAAhAwNAAn8CQAJAIAAvAQgiAUH04AFNBEAgAUEBRg0BIAFB9cYBRg0BDAILIAFBgbICRg0AIAFB9eABRw0BCyAAKAIAIQEgAEEANgIAIAAoAgwQBiAAEAYgASADIAAgA0YbIQMCQCACRQRAQQAhAgwBCyACIAE2AgALIAEMAQsgACICKAIACyIADQALIAMLsgQCBX8BfgJAAkACQCAAIAGtEBciAQRAIAEtAAANAUEAIQAMAgsgBARAIARBADYCBCAEQQ42AgALQQAPC0EAIQADQCABLQAABH4gASkDCCABKQMQfQVCAAtCBFQNASABEAwhByABIAEQDCIGrRATIghFBEBBACECIAQEQCAEQQA2AgQgBEEVNgIACyABEAggAEUNAwNAIAAoAgAhASAAKAIMEAYgABAGIAEiAA0ACwwDCwJAAkBBEBAJIgUEQCAFIAY7AQogBSAHOwEIIAUgAjYCBCAFQQA2AgAgBkUNASAFIAggBhBjIgY2AgwgBg0CIAUQBgtBACECIAQEQCAEQQA2AgQgBEEONgIACyABEAggAEUNBANAIAAoAgAhASAAKAIMEAYgABAGIAEiAA0ACwwECyAFQQA2AgwLAkAgAEUEQCAFIQAMAQsgCSAFNgIACyAFIQkgAS0AAA0ACwsCQCABLQAABH8gASkDECABKQMIUQVBAAsNACABIAEtAAAEfiABKQMIIAEpAxB9BUIACyIKQv////8PgxATIQICQCAKpyIFQQNLDQAgAkUNACACQcEUIAUQPUUNAQtBACECIAQEQCAEQQA2AgQgBEEVNgIACyABEAggAEUNAQNAIAAoAgAhASAAKAIMEAYgABAGIAEiAA0ACwwBCyABEAggAwRAIAMgADYCAEEBDwtBASECIABFDQADQCAAKAIAIQEgACgCDBAGIAAQBiABIgANAAsLIAILvgEBBX8gAAR/IAAhAgNAIAIiBCgCACICDQALIAEEQANAIAEiAy8BCCEGIAMoAgAhASAAIQICQAJAA0ACQCACLwEIIAZHDQAgAi8BCiIFIAMvAQpHDQAgBUUNAiACKAIMIAMoAgwgBRA9RQ0CCyACKAIAIgINAAsgA0EANgIAIAQgAzYCACADIQQMAQsgAiACKAIEIAMoAgRBgAZxcjYCBCADQQA2AgAgAygCDBAGIAMQBgsgAQ0ACwsgAAUgAQsLVQICfgF/AkACQCAALQAARQ0AIAApAxAiAkIBfCIDIAJUDQAgAyAAKQMIWA0BCyAAQQA6AAAPCyAAKAIEIgRFBEAPCyAAIAM3AxAgBCACp2ogAToAAAt9AQN/IwBBEGsiAiQAIAIgATYCDEF/IQMCQCAALQAoDQACQCAAKAIAIgRFDQAgBCABEHFBf0oNACAAKAIAIQEgAEEMaiIABEAgACABKAIMNgIAIAAgASgCEDYCBAsMAQsgACACQQxqQgRBExAOQj+HpyEDCyACQRBqJAAgAwvdAQEDfyABIAApAzBaBEAgAEEIagRAIABBADYCDCAAQRI2AggLQX8PCyAAQQhqIQIgAC0AGEECcQRAIAIEQCACQQA2AgQgAkEZNgIAC0F/DwtBfyEDAkAgACABQQAgAhBTIgRFDQAgACgCUCAEIAIQfkUNAAJ/IAEgACkDMFoEQCAAQQhqBEAgAEEANgIMIABBEjYCCAtBfwwBCyABp0EEdCICIAAoAkBqKAIEECAgACgCQCACaiICQQA2AgQgAhBAQQALDQAgACgCQCABp0EEdGpBAToADEEAIQMLIAMLpgIBBX9BfyEFAkAgACABQQBBABAmRQ0AIAAtABhBAnEEQCAAQQhqIgAEQCAAQQA2AgQgAEEZNgIAC0F/DwsCfyAAKAJAIgQgAaciBkEEdGooAgAiBUUEQCADQYCA2I14RyEHQQMMAQsgBSgCRCADRyEHIAUtAAkLIQggBCAGQQR0aiIEIQYgBCgCBCEEQQAgAiAIRiAHG0UEQAJAIAQNACAGIAUQKyIENgIEIAQNACAAQQhqIgAEQCAAQQA2AgQgAEEONgIAC0F/DwsgBCADNgJEIAQgAjoACSAEIAQoAgBBEHI2AgBBAA8LQQAhBSAERQ0AIAQgBCgCAEFvcSIANgIAIABFBEAgBBAgIAZBADYCBEEADwsgBCADNgJEIAQgCDoACQsgBQvjCAIFfwR+IAAtABhBAnEEQCAAQQhqBEAgAEEANgIMIABBGTYCCAtCfw8LIAApAzAhCwJAIANBgMAAcQRAIAAgASADQQAQTCIJQn9SDQELAn4CQAJAIAApAzAiCUIBfCIMIAApAzgiClQEQCAAKAJAIQQMAQsgCkIBhiIJQoAIIAlCgAhUGyIJQhAgCUIQVhsgCnwiCadBBHQiBK0gCkIEhkLw////D4NUDQEgACgCQCAEEDQiBEUNASAAIAk3AzggACAENgJAIAApAzAiCUIBfCEMCyAAIAw3AzAgBCAJp0EEdGoiBEIANwIAIARCADcABSAJDAELIABBCGoEQCAAQQA2AgwgAEEONgIIC0J/CyIJQgBZDQBCfw8LAkAgAUUNAAJ/QQAhBCAJIAApAzBaBEAgAEEIagRAIABBADYCDCAAQRI2AggLQX8MAQsgAC0AGEECcQRAIABBCGoEQCAAQQA2AgwgAEEZNgIIC0F/DAELAkAgAUUNACABLQAARQ0AQX8gASABECJB//8DcSADIABBCGoQNSIERQ0BGiADQYAwcQ0AIARBABAjQQNHDQAgBEECNgIICwJAIAAgAUEAQQAQTCIKQgBTIgENACAJIApRDQAgBBAQIABBCGoEQCAAQQA2AgwgAEEKNgIIC0F/DAELAkAgAUEBIAkgClEbRQ0AAkACfwJAIAAoAkAiASAJpyIFQQR0aiIGKAIAIgMEQCADKAIwIAQQYg0BCyAEIAYoAgQNARogBiAGKAIAECsiAzYCBCAEIAMNARogAEEIagRAIABBADYCDCAAQQ42AggLDAILQQEhByAGKAIAKAIwC0EAQQAgAEEIaiIDECUiCEUNAAJAAkAgASAFQQR0aiIFKAIEIgENACAGKAIAIgENAEEAIQEMAQsgASgCMCIBRQRAQQAhAQwBCyABQQBBACADECUiAUUNAQsgACgCUCAIIAlBACADEE1FDQAgAQRAIAAoAlAgAUEAEH4aCyAFKAIEIQMgBwRAIANFDQIgAy0AAEECcUUNAiADKAIwEBAgBSgCBCIBIAEoAgBBfXEiAzYCACADRQRAIAEQICAFQQA2AgQgBBAQQQAMBAsgASAGKAIAKAIwNgIwIAQQEEEADAMLIAMoAgAiAUECcQRAIAMoAjAQECAFKAIEIgMoAgAhAQsgAyAENgIwIAMgAUECcjYCAEEADAILIAQQEEF/DAELIAQQEEEAC0UNACALIAApAzBRBEBCfw8LIAAoAkAgCadBBHRqED4gACALNwMwQn8PCyAJpyIGQQR0IgEgACgCQGoQQAJAAkAgACgCQCIEIAFqIgMoAgAiBUUNAAJAIAMoAgQiAwRAIAMoAgAiAEEBcUUNAQwCCyAFECshAyAAKAJAIgQgBkEEdGogAzYCBCADRQ0CIAMoAgAhAAsgA0F+NgIQIAMgAEEBcjYCAAsgASAEaiACNgIIIAkPCyAAQQhqBEAgAEEANgIMIABBDjYCCAtCfwteAQF/IwBBEGsiAiQAAn8gACgCJEEBRwRAIABBDGoiAARAIABBADYCBCAAQRI2AgALQX8MAQsgAkEANgIIIAIgATcDACAAIAJCEEEMEA5CP4enCyEAIAJBEGokACAAC9oDAQZ/IwBBEGsiBSQAIAUgAjYCDCMAQaABayIEJAAgBEEIakHA8ABBkAEQBxogBCAANgI0IAQgADYCHCAEQX4gAGsiA0H/////ByADQf////8HSRsiBjYCOCAEIAAgBmoiADYCJCAEIAA2AhggBEEIaiEAIwBB0AFrIgMkACADIAI2AswBIANBoAFqQQBBKBAZIAMgAygCzAE2AsgBAkBBACABIANByAFqIANB0ABqIANBoAFqEEpBAEgNACAAKAJMQQBOIQcgACgCACECIAAsAEpBAEwEQCAAIAJBX3E2AgALIAJBIHEhCAJ/IAAoAjAEQCAAIAEgA0HIAWogA0HQAGogA0GgAWoQSgwBCyAAQdAANgIwIAAgA0HQAGo2AhAgACADNgIcIAAgAzYCFCAAKAIsIQIgACADNgIsIAAgASADQcgBaiADQdAAaiADQaABahBKIAJFDQAaIABBAEEAIAAoAiQRAAAaIABBADYCMCAAIAI2AiwgAEEANgIcIABBADYCECAAKAIUGiAAQQA2AhRBAAsaIAAgACgCACAIcjYCACAHRQ0ACyADQdABaiQAIAYEQCAEKAIcIgAgACAEKAIYRmtBADoAAAsgBEGgAWokACAFQRBqJAALUwEDfwJAIAAoAgAsAABBMGtBCk8NAANAIAAoAgAiAiwAACEDIAAgAkEBajYCACABIANqQTBrIQEgAiwAAUEwa0EKTw0BIAFBCmwhAQwACwALIAELuwIAAkAgAUEUSw0AAkACQAJAAkACQAJAAkACQAJAAkAgAUEJaw4KAAECAwQFBgcICQoLIAIgAigCACIBQQRqNgIAIAAgASgCADYCAA8LIAIgAigCACIBQQRqNgIAIAAgATQCADcDAA8LIAIgAigCACIBQQRqNgIAIAAgATUCADcDAA8LIAIgAigCAEEHakF4cSIBQQhqNgIAIAAgASkDADcDAA8LIAIgAigCACIBQQRqNgIAIAAgATIBADcDAA8LIAIgAigCACIBQQRqNgIAIAAgATMBADcDAA8LIAIgAigCACIBQQRqNgIAIAAgATAAADcDAA8LIAIgAigCACIBQQRqNgIAIAAgATEAADcDAA8LIAIgAigCAEEHakF4cSIBQQhqNgIAIAAgASsDADkDAA8LIAAgAkEAEQcACwubAgAgAEUEQEEADwsCfwJAIAAEfyABQf8ATQ0BAkBB9IIBKAIAKAIARQRAIAFBgH9xQYC/A0YNAwwBCyABQf8PTQRAIAAgAUE/cUGAAXI6AAEgACABQQZ2QcABcjoAAEECDAQLIAFBgLADT0EAIAFBgEBxQYDAA0cbRQRAIAAgAUE/cUGAAXI6AAIgACABQQx2QeABcjoAACAAIAFBBnZBP3FBgAFyOgABQQMMBAsgAUGAgARrQf//P00EQCAAIAFBP3FBgAFyOgADIAAgAUESdkHwAXI6AAAgACABQQZ2QT9xQYABcjoAAiAAIAFBDHZBP3FBgAFyOgABQQQMBAsLQYSEAUEZNgIAQX8FQQELDAELIAAgAToAAEEBCwvjAQECfyACQQBHIQMCQAJAAkAgAEEDcUUNACACRQ0AIAFB/wFxIQQDQCAALQAAIARGDQIgAkEBayICQQBHIQMgAEEBaiIAQQNxRQ0BIAINAAsLIANFDQELAkAgAC0AACABQf8BcUYNACACQQRJDQAgAUH/AXFBgYKECGwhAwNAIAAoAgAgA3MiBEF/cyAEQYGChAhrcUGAgYKEeHENASAAQQRqIQAgAkEEayICQQNLDQALCyACRQ0AIAFB/wFxIQEDQCABIAAtAABGBEAgAA8LIABBAWohACACQQFrIgINAAsLQQALeQEBfAJAIABFDQAgACsDECAAKwMgIgIgAUQAAAAAAAAAACABRAAAAAAAAAAAZBsiAUQAAAAAAADwPyABRAAAAAAAAPA/YxsgACsDKCACoaKgIgEgACsDGKFjRQ0AIAAoAgAgASAAKAIMIAAoAgQRDgAgACABOQMYCwtIAQF8AkAgAEUNACAAKwMQIAArAyAiASAAKwMoIAGhoCIBIAArAxihY0UNACAAKAIAIAEgACgCDCAAKAIEEQ4AIAAgATkDGAsLWgICfgF/An8CQAJAIAAtAABFDQAgACkDECIBQgF8IgIgAVQNACACIAApAwhYDQELIABBADoAAEEADAELQQAgACgCBCIDRQ0AGiAAIAI3AxAgAyABp2otAAALC4IEAgZ/AX4gAEEAIAEbRQRAIAIEQCACQQA2AgQgAkESNgIAC0EADwsCQAJAIAApAwhQDQAgACgCECABLQAAIgQEf0Kl6wohCSABIQMDQCAJIAStQv8Bg3whCSADLQABIgQEQCADQQFqIQMgCUL/////D4NCIX4hCQwBCwsgCacFQYUqCyIEIAAoAgBwQQJ0aiIGKAIAIgNFDQADQAJAIAMoAhwgBEcNACABIAMoAgAQOA0AAkAgAykDCEJ/UQRAIAMoAhghAQJAIAUEQCAFIAE2AhgMAQsgBiABNgIACyADEAYgACAAKQMIQgF9Igk3AwggCbogACgCACIBuER7FK5H4XqEP6JjRQ0BIAFBgQJJDQECf0EAIQMgACgCACIGIAFBAXYiBUcEQCAFEDwiB0UEQCACBEAgAkEANgIEIAJBDjYCAAtBAAwCCwJAIAApAwhCACAGG1AEQCAAKAIQIQQMAQsgACgCECEEA0AgBCADQQJ0aigCACIBBEADQCABKAIYIQIgASAHIAEoAhwgBXBBAnRqIggoAgA2AhggCCABNgIAIAIiAQ0ACwsgA0EBaiIDIAZHDQALCyAEEAYgACAFNgIAIAAgBzYCEAtBAQsNAQwFCyADQn83AxALQQEPCyADIgUoAhgiAw0ACwsgAgRAIAJBADYCBCACQQk2AgALC0EAC6UGAgl/AX4jAEHwAGsiBSQAAkACQCAARQ0AAkAgAQRAIAEpAzAgAlYNAQtBACEDIABBCGoEQCAAQQA2AgwgAEESNgIICwwCCwJAIANBCHENACABKAJAIAKnQQR0aiIGKAIIRQRAIAYtAAxFDQELQQAhAyAAQQhqBEAgAEEANgIMIABBDzYCCAsMAgsgASACIANBCHIgBUE4ahCKAUF/TARAQQAhAyAAQQhqBEAgAEEANgIMIABBFDYCCAsMAgsgA0EDdkEEcSADciIGQQRxIQcgBSkDUCEOIAUvAWghCQJAIANBIHFFIAUvAWpBAEdxIgtFDQAgBA0AIAAoAhwiBA0AQQAhAyAAQQhqBEAgAEEANgIMIABBGjYCCAsMAgsgBSkDWFAEQCAAQQBCAEEAEFIhAwwCCwJAIAdFIgwgCUEAR3EiDUEBckUEQEEAIQMgBUEAOwEwIAUgDjcDICAFIA43AxggBSAFKAJgNgIoIAVC3AA3AwAgASgCACAOIAVBACABIAIgAEEIahBeIgYNAQwDC0EAIQMgASACIAYgAEEIaiIGECYiB0UNAiABKAIAIAUpA1ggBUE4aiAHLwEMQQF2QQNxIAEgAiAGEF4iBkUNAgsCfyAGIAE2AiwCQCABKAJEIghBAWoiCiABKAJIIgdJBEAgASgCTCEHDAELIAEoAkwgB0EKaiIIQQJ0EDQiB0UEQCABQQhqBEAgAUEANgIMIAFBDjYCCAtBfwwCCyABIAc2AkwgASAINgJIIAEoAkQiCEEBaiEKCyABIAo2AkQgByAIQQJ0aiAGNgIAQQALQX9MBEAgBhALDAELAkAgC0UEQCAGIQEMAQtBJkEAIAUvAWpBAUYbIgFFBEAgAEEIagRAIABBADYCDCAAQRg2AggLDAMLIAAgBiAFLwFqQQAgBCABEQYAIQEgBhALIAFFDQILAkAgDUUEQCABIQMMAQsgACABIAUvAWgQgQEhAyABEAsgA0UNAQsCQCAJRSAMckUEQCADIQEMAQsgACADQQEQgAEhASADEAsgAUUNAQsgASEDDAELQQAhAwsgBUHwAGokACADC4UBAQF/IAFFBEAgAEEIaiIABEAgAEEANgIEIABBEjYCAAtBAA8LQTgQCSIDRQRAIABBCGoiAARAIABBADYCBCAAQQ42AgALQQAPCyADQQA2AhAgA0IANwIIIANCADcDKCADQQA2AgQgAyACNgIAIANCADcDGCADQQA2AjAgACABQTsgAxBCCw8AIAAgASACQQBBABCCAQusAgECfyABRQRAIABBCGoiAARAIABBADYCBCAAQRI2AgALQQAPCwJAIAJBfUsNACACQf//A3FBCEYNACAAQQhqIgAEQCAAQQA2AgQgAEEQNgIAC0EADwsCQEGwwAAQCSIFBEAgBUEANgIIIAVCADcCACAFQYiBAUGogQEgAxs2AqhAIAUgAjYCFCAFIAM6ABAgBUEAOgAPIAVBADsBDCAFIAMgAkF9SyIGcToADiAFQQggAiAGG0H//wNxIAQgBUGIgQFBqIEBIAMbKAIAEQAAIgI2AqxAIAINASAFEDEgBRAGCyAAQQhqIgAEQCAAQQA2AgQgAEEONgIAC0EADwsgACABQTogBRBCIgAEfyAABSAFKAKsQCAFKAKoQCgCBBEDACAFEDEgBRAGQQALC6ABAQF/IAIgACgCBCIDIAIgA0kbIgIEQCAAIAMgAms2AgQCQAJAAkACQCAAKAIcIgMoAhRBAWsOAgEAAgsgA0GgAWogASAAKAIAIAJB3IABKAIAEQgADAILIAAgACgCMCABIAAoAgAgAkHEgAEoAgARBAA2AjAMAQsgASAAKAIAIAIQBxoLIAAgACgCACACajYCACAAIAAoAgggAmo2AggLC7cCAQR/QX4hAgJAIABFDQAgACgCIEUNACAAKAIkIgRFDQAgACgCHCIBRQ0AIAEoAgAgAEcNAAJAAkAgASgCICIDQTlrDjkBAgICAgICAgICAgIBAgICAQICAgICAgICAgICAgICAgICAQICAgICAgICAgICAQICAgICAgICAgEACyADQZoFRg0AIANBKkcNAQsCfwJ/An8gASgCBCICBEAgBCAAKAIoIAIQHiAAKAIcIQELIAEoAlAiAgsEQCAAKAIkIAAoAiggAhAeIAAoAhwhAQsgASgCTCICCwRAIAAoAiQgACgCKCACEB4gACgCHCEBCyABKAJIIgILBEAgACgCJCAAKAIoIAIQHiAAKAIcIQELIAAoAiQgACgCKCABEB4gAEEANgIcQX1BACADQfEARhshAgsgAgvrCQEIfyAAKAIwIgMgACgCDEEFayICIAIgA0sbIQggACgCACIEKAIEIQkgAUEERiEHAkADQCAEKAIQIgMgACgCoC5BKmpBA3UiAkkEQEEBIQYMAgsgCCADIAJrIgMgACgCaCAAKAJYayICIAQoAgRqIgVB//8DIAVB//8DSRsiBiADIAZJGyIDSwRAQQEhBiADQQBHIAdyRQ0CIAFFDQIgAyAFRw0CCyAAQQBBACAHIAMgBUZxIgUQOSAAIAAoAhBBBGsiBDYCECAAKAIEIARqIAM7AAAgACAAKAIQQQJqIgQ2AhAgACgCBCAEaiADQX9zOwAAIAAgACgCEEECajYCECAAKAIAEAoCfyACBEAgACgCACgCDCAAKAJIIAAoAlhqIAMgAiACIANLGyICEAcaIAAoAgAiBCAEKAIMIAJqNgIMIAQgBCgCECACazYCECAEIAQoAhQgAmo2AhQgACAAKAJYIAJqNgJYIAMgAmshAwsgAwsEQCAAKAIAIgIgAigCDCADEIMBIAAoAgAiAiACKAIMIANqNgIMIAIgAigCECADazYCECACIAIoAhQgA2o2AhQLIAAoAgAhBCAFRQ0AC0EAIQYLAkAgCSAEKAIEayICRQRAIAAoAmghAwwBCwJAIAAoAjAiAyACTQRAIABBAjYCgC4gACgCSCAEKAIAIANrIAMQBxogACAAKAIwIgM2AoQuIAAgAzYCaAwBCyACIAAoAkQgACgCaCIFa08EQCAAIAUgA2siBDYCaCAAKAJIIgUgAyAFaiAEEAcaIAAoAoAuIgNBAU0EQCAAIANBAWo2AoAuCyAAIAAoAmgiBSAAKAKELiIDIAMgBUsbNgKELiAAKAIAIQQLIAAoAkggBWogBCgCACACayACEAcaIAAgACgCaCACaiIDNgJoIAAgACgCMCAAKAKELiIEayIFIAIgAiAFSxsgBGo2AoQuCyAAIAM2AlgLIAAgAyAAKAJAIgIgAiADSRs2AkBBAyECAkAgBkUNACAAKAIAIgUoAgQhAgJAAkAgAUF7cUUNACACDQBBASECIAMgACgCWEYNAiAAKAJEIANrIQRBACECDAELIAIgACgCRCADayIETQ0AIAAoAlgiByAAKAIwIgZIDQAgACADIAZrIgM2AmggACAHIAZrNgJYIAAoAkgiAiACIAZqIAMQBxogACgCgC4iA0EBTQRAIAAgA0EBajYCgC4LIAAgACgCaCIDIAAoAoQuIgIgAiADSxs2AoQuIAAoAjAgBGohBCAAKAIAIgUoAgQhAgsCQCACIAQgAiAESRsiAkUEQCAAKAIwIQUMAQsgBSAAKAJIIANqIAIQgwEgACAAKAJoIAJqIgM2AmggACAAKAIwIgUgACgChC4iBGsiBiACIAIgBksbIARqNgKELgsgACADIAAoAkAiAiACIANJGzYCQCADIAAoAlgiBmsiAyAFIAAoAgwgACgCoC5BKmpBA3VrIgJB//8DIAJB//8DSRsiBCAEIAVLG0kEQEEAIQIgAUEERiADQQBHckUNASABRQ0BIAAoAgAoAgQNASADIARLDQELQQAhAiABQQRGBEAgACgCACgCBEUgAyAETXEhAgsgACAAKAJIIAZqIAQgAyADIARLGyIBIAIQOSAAIAAoAlggAWo2AlggACgCABAKQQJBACACGw8LIAIL/woCCn8DfiAAKQOYLiENIAAoAqAuIQQgAkEATgRAQQRBAyABLwECIggbIQlBB0GKASAIGyEFQX8hCgNAIAghByABIAsiDEEBaiILQQJ0ai8BAiEIAkACQCAGQQFqIgMgBU4NACAHIAhHDQAgAyEGDAELAkAgAyAJSARAIAAgB0ECdGoiBkHOFWohCSAGQcwVaiEKA0AgCjMBACEPAn8gBCAJLwEAIgZqIgVBP00EQCAPIASthiANhCENIAUMAQsgBEHAAEYEQCAAKAIEIAAoAhBqIA03AAAgACAAKAIQQQhqNgIQIA8hDSAGDAELIAAoAgQgACgCEGogDyAErYYgDYQ3AAAgACAAKAIQQQhqNgIQIA9BwAAgBGutiCENIAVBQGoLIQQgA0EBayIDDQALDAELIAcEQAJAIAcgCkYEQCANIQ8gBCEFIAMhBgwBCyAAIAdBAnRqIgNBzBVqMwEAIQ8gBCADQc4Vai8BACIDaiIFQT9NBEAgDyAErYYgDYQhDwwBCyAEQcAARgRAIAAoAgQgACgCEGogDTcAACAAIAAoAhBBCGo2AhAgAyEFDAELIAAoAgQgACgCEGogDyAErYYgDYQ3AAAgACAAKAIQQQhqNgIQIAVBQGohBSAPQcAAIARrrYghDwsgADMBjBYhDgJAIAUgAC8BjhYiBGoiA0E/TQRAIA4gBa2GIA+EIQ4MAQsgBUHAAEYEQCAAKAIEIAAoAhBqIA83AAAgACAAKAIQQQhqNgIQIAQhAwwBCyAAKAIEIAAoAhBqIA4gBa2GIA+ENwAAIAAgACgCEEEIajYCECADQUBqIQMgDkHAACAFa62IIQ4LIAasQgN9IQ0gA0E9TQRAIANBAmohBCANIAOthiAOhCENDAILIANBwABGBEAgACgCBCAAKAIQaiAONwAAIAAgACgCEEEIajYCEEECIQQMAgsgACgCBCAAKAIQaiANIAOthiAOhDcAACAAIAAoAhBBCGo2AhAgA0E+ayEEIA1BwAAgA2utiCENDAELIAZBCUwEQCAAMwGQFiEOAkAgBCAALwGSFiIFaiIDQT9NBEAgDiAErYYgDYQhDgwBCyAEQcAARgRAIAAoAgQgACgCEGogDTcAACAAIAAoAhBBCGo2AhAgBSEDDAELIAAoAgQgACgCEGogDiAErYYgDYQ3AAAgACAAKAIQQQhqNgIQIANBQGohAyAOQcAAIARrrYghDgsgBqxCAn0hDSADQTxNBEAgA0EDaiEEIA0gA62GIA6EIQ0MAgsgA0HAAEYEQCAAKAIEIAAoAhBqIA43AAAgACAAKAIQQQhqNgIQQQMhBAwCCyAAKAIEIAAoAhBqIA0gA62GIA6ENwAAIAAgACgCEEEIajYCECADQT1rIQQgDUHAACADa62IIQ0MAQsgADMBlBYhDgJAIAQgAC8BlhYiBWoiA0E/TQRAIA4gBK2GIA2EIQ4MAQsgBEHAAEYEQCAAKAIEIAAoAhBqIA03AAAgACAAKAIQQQhqNgIQIAUhAwwBCyAAKAIEIAAoAhBqIA4gBK2GIA2ENwAAIAAgACgCEEEIajYCECADQUBqIQMgDkHAACAEa62IIQ4LIAatQgp9IQ0gA0E4TQRAIANBB2ohBCANIAOthiAOhCENDAELIANBwABGBEAgACgCBCAAKAIQaiAONwAAIAAgACgCEEEIajYCEEEHIQQMAQsgACgCBCAAKAIQaiANIAOthiAOhDcAACAAIAAoAhBBCGo2AhAgA0E5ayEEIA1BwAAgA2utiCENC0EAIQYCfyAIRQRAQYoBIQVBAwwBC0EGQQcgByAIRiIDGyEFQQNBBCADGwshCSAHIQoLIAIgDEcNAAsLIAAgBDYCoC4gACANNwOYLgv5BQIIfwJ+AkAgACgC8C1FBEAgACkDmC4hCyAAKAKgLiEDDAELA0AgCSIDQQNqIQkgAyAAKALsLWoiAy0AAiEFIAApA5guIQwgACgCoC4hBAJAIAMvAAAiB0UEQCABIAVBAnRqIgMzAQAhCyAEIAMvAQIiBWoiA0E/TQRAIAsgBK2GIAyEIQsMAgsgBEHAAEYEQCAAKAIEIAAoAhBqIAw3AAAgACAAKAIQQQhqNgIQIAUhAwwCCyAAKAIEIAAoAhBqIAsgBK2GIAyENwAAIAAgACgCEEEIajYCECADQUBqIQMgC0HAACAEa62IIQsMAQsgBUGAzwBqLQAAIghBAnQiBiABaiIDQYQIajMBACELIANBhghqLwEAIQMgCEEIa0ETTQRAIAUgBkGA0QBqKAIAa60gA62GIAuEIQsgBkHA0wBqKAIAIANqIQMLIAMgAiAHQQFrIgcgB0EHdkGAAmogB0GAAkkbQYDLAGotAAAiBUECdCIIaiIKLwECaiEGIAozAQAgA62GIAuEIQsgBCAFQQRJBH8gBgUgByAIQYDSAGooAgBrrSAGrYYgC4QhCyAIQcDUAGooAgAgBmoLIgVqIgNBP00EQCALIASthiAMhCELDAELIARBwABGBEAgACgCBCAAKAIQaiAMNwAAIAAgACgCEEEIajYCECAFIQMMAQsgACgCBCAAKAIQaiALIASthiAMhDcAACAAIAAoAhBBCGo2AhAgA0FAaiEDIAtBwAAgBGutiCELCyAAIAs3A5guIAAgAzYCoC4gCSAAKALwLUkNAAsLIAFBgAhqMwEAIQwCQCADIAFBgghqLwEAIgJqIgFBP00EQCAMIAOthiALhCEMDAELIANBwABGBEAgACgCBCAAKAIQaiALNwAAIAAgACgCEEEIajYCECACIQEMAQsgACgCBCAAKAIQaiAMIAOthiALhDcAACAAIAAoAhBBCGo2AhAgAUFAaiEBIAxBwAAgA2utiCEMCyAAIAw3A5guIAAgATYCoC4L8AQBA38gAEHkAWohAgNAIAIgAUECdCIDakEAOwEAIAIgA0EEcmpBADsBACABQQJqIgFBngJHDQALIABBADsBzBUgAEEAOwHYEyAAQZQWakEAOwEAIABBkBZqQQA7AQAgAEGMFmpBADsBACAAQYgWakEAOwEAIABBhBZqQQA7AQAgAEGAFmpBADsBACAAQfwVakEAOwEAIABB+BVqQQA7AQAgAEH0FWpBADsBACAAQfAVakEAOwEAIABB7BVqQQA7AQAgAEHoFWpBADsBACAAQeQVakEAOwEAIABB4BVqQQA7AQAgAEHcFWpBADsBACAAQdgVakEAOwEAIABB1BVqQQA7AQAgAEHQFWpBADsBACAAQcwUakEAOwEAIABByBRqQQA7AQAgAEHEFGpBADsBACAAQcAUakEAOwEAIABBvBRqQQA7AQAgAEG4FGpBADsBACAAQbQUakEAOwEAIABBsBRqQQA7AQAgAEGsFGpBADsBACAAQagUakEAOwEAIABBpBRqQQA7AQAgAEGgFGpBADsBACAAQZwUakEAOwEAIABBmBRqQQA7AQAgAEGUFGpBADsBACAAQZAUakEAOwEAIABBjBRqQQA7AQAgAEGIFGpBADsBACAAQYQUakEAOwEAIABBgBRqQQA7AQAgAEH8E2pBADsBACAAQfgTakEAOwEAIABB9BNqQQA7AQAgAEHwE2pBADsBACAAQewTakEAOwEAIABB6BNqQQA7AQAgAEHkE2pBADsBACAAQeATakEAOwEAIABB3BNqQQA7AQAgAEIANwL8LSAAQeQJakEBOwEAIABBADYC+C0gAEEANgLwLQuKAwIGfwR+QcgAEAkiBEUEQEEADwsgBEIANwMAIARCADcDMCAEQQA2AiggBEIANwMgIARCADcDGCAEQgA3AxAgBEIANwMIIARCADcDOCABUARAIARBCBAJIgA2AgQgAEUEQCAEEAYgAwRAIANBADYCBCADQQ42AgALQQAPCyAAQgA3AwAgBA8LAkAgAaciBUEEdBAJIgZFDQAgBCAGNgIAIAVBA3RBCGoQCSIFRQ0AIAQgATcDECAEIAU2AgQDQCAAIAynIghBBHRqIgcpAwgiDVBFBEAgBygCACIHRQRAIAMEQCADQQA2AgQgA0ESNgIACyAGEAYgBRAGIAQQBkEADwsgBiAKp0EEdGoiCSANNwMIIAkgBzYCACAFIAhBA3RqIAs3AwAgCyANfCELIApCAXwhCgsgDEIBfCIMIAFSDQALIAQgCjcDCCAEQgAgCiACGzcDGCAFIAqnQQN0aiALNwMAIAQgCzcDMCAEDwsgAwRAIANBADYCBCADQQ42AgALIAYQBiAEEAZBAAvlAQIDfwF+QX8hBQJAIAAgASACQQAQJiIERQ0AIAAgASACEIsBIgZFDQACfgJAIAJBCHENACAAKAJAIAGnQQR0aigCCCICRQ0AIAIgAxAhQQBOBEAgAykDAAwCCyAAQQhqIgAEQCAAQQA2AgQgAEEPNgIAC0F/DwsgAxAqIAMgBCgCGDYCLCADIAQpAyg3AxggAyAEKAIUNgIoIAMgBCkDIDcDICADIAQoAhA7ATAgAyAELwFSOwEyQvwBQtwBIAQtAAYbCyEHIAMgBjYCCCADIAE3AxAgAyAHQgOENwMAQQAhBQsgBQspAQF/IAAgASACIABBCGoiABAmIgNFBEBBAA8LIAMoAjBBACACIAAQJQuAAwEGfwJ/An9BMCABQYB/Sw0BGgJ/IAFBgH9PBEBBhIQBQTA2AgBBAAwBC0EAQRAgAUELakF4cSABQQtJGyIFQcwAahAJIgFFDQAaIAFBCGshAgJAIAFBP3FFBEAgAiEBDAELIAFBBGsiBigCACIHQXhxIAFBP2pBQHFBCGsiASABQUBrIAEgAmtBD0sbIgEgAmsiA2shBCAHQQNxRQRAIAIoAgAhAiABIAQ2AgQgASACIANqNgIADAELIAEgBCABKAIEQQFxckECcjYCBCABIARqIgQgBCgCBEEBcjYCBCAGIAMgBigCAEEBcXJBAnI2AgAgAiADaiIEIAQoAgRBAXI2AgQgAiADEDsLAkAgASgCBCICQQNxRQ0AIAJBeHEiAyAFQRBqTQ0AIAEgBSACQQFxckECcjYCBCABIAVqIgIgAyAFayIFQQNyNgIEIAEgA2oiAyADKAIEQQFyNgIEIAIgBRA7CyABQQhqCyIBRQsEQEEwDwsgACABNgIAQQALCwoAIABBiIQBEAQL6AIBBX8gACgCUCEBIAAvATAhBEEEIQUDQCABQQAgAS8BACICIARrIgMgAiADSRs7AQAgAUEAIAEvAQIiAiAEayIDIAIgA0kbOwECIAFBACABLwEEIgIgBGsiAyACIANJGzsBBCABQQAgAS8BBiICIARrIgMgAiADSRs7AQYgBUGAgARGRQRAIAFBCGohASAFQQRqIQUMAQsLAkAgBEUNACAEQQNxIQUgACgCTCEBIARBAWtBA08EQCAEIAVrIQADQCABQQAgAS8BACICIARrIgMgAiADSRs7AQAgAUEAIAEvAQIiAiAEayIDIAIgA0kbOwECIAFBACABLwEEIgIgBGsiAyACIANJGzsBBCABQQAgAS8BBiICIARrIgMgAiADSRs7AQYgAUEIaiEBIABBBGsiAA0ACwsgBUUNAANAIAFBACABLwEAIgAgBGsiAiAAIAJJGzsBACABQQJqIQEgBUEBayIFDQALCwuDAQEEfyACQQFOBEAgAiAAKAJIIAFqIgJqIQMgACgCUCEEA0AgBCACKAAAQbHz3fF5bEEPdkH+/wdxaiIFLwEAIgYgAUH//wNxRwRAIAAoAkwgASAAKAI4cUH//wNxQQF0aiAGOwEAIAUgATsBAAsgAUEBaiEBIAJBAWoiAiADSQ0ACwsLUAECfyABIAAoAlAgACgCSCABaigAAEGx893xeWxBD3ZB/v8HcWoiAy8BACICRwRAIAAoAkwgACgCOCABcUEBdGogAjsBACADIAE7AQALIAILugEBAX8jAEEQayICJAAgAkEAOgAIQYCBAUECNgIAQfyAAUEDNgIAQfiAAUEENgIAQfSAAUEFNgIAQfCAAUEGNgIAQeyAAUEHNgIAQeiAAUEINgIAQeSAAUEJNgIAQeCAAUEKNgIAQdyAAUELNgIAQdiAAUEMNgIAQdSAAUENNgIAQdCAAUEONgIAQcyAAUEPNgIAQciAAUEQNgIAQcSAAUERNgIAQcCAAUESNgIAIAAgARBYIAJBEGokAAu9AQEBfyMAQRBrIgEkACABQQA6AAhBgIEBQQI2AgBB/IABQQM2AgBB+IABQQQ2AgBB9IABQQU2AgBB8IABQQY2AgBB7IABQQc2AgBB6IABQQg2AgBB5IABQQk2AgBB4IABQQo2AgBB3IABQQs2AgBB2IABQQw2AgBB1IABQQ02AgBB0IABQQ42AgBBzIABQQ82AgBByIABQRA2AgBBxIABQRE2AgBBwIABQRI2AgAgAEEANgJAIAFBEGokAEEAC70BAQF/IwBBEGsiASQAIAFBADoACEGAgQFBAjYCAEH8gAFBAzYCAEH4gAFBBDYCAEH0gAFBBTYCAEHwgAFBBjYCAEHsgAFBBzYCAEHogAFBCDYCAEHkgAFBCTYCAEHggAFBCjYCAEHcgAFBCzYCAEHYgAFBDDYCAEHUgAFBDTYCAEHQgAFBDjYCAEHMgAFBDzYCAEHIgAFBEDYCAEHEgAFBETYCAEHAgAFBEjYCACAAKAJAIQAgAUEQaiQAIAALvgEBAX8jAEEQayIEJAAgBEEAOgAIQYCBAUECNgIAQfyAAUEDNgIAQfiAAUEENgIAQfSAAUEFNgIAQfCAAUEGNgIAQeyAAUEHNgIAQeiAAUEINgIAQeSAAUEJNgIAQeCAAUEKNgIAQdyAAUELNgIAQdiAAUEMNgIAQdSAAUENNgIAQdCAAUEONgIAQcyAAUEPNgIAQciAAUEQNgIAQcSAAUERNgIAQcCAAUESNgIAIAAgASACIAMQVyAEQRBqJAALygEAIwBBEGsiAyQAIANBADoACEGAgQFBAjYCAEH8gAFBAzYCAEH4gAFBBDYCAEH0gAFBBTYCAEHwgAFBBjYCAEHsgAFBBzYCAEHogAFBCDYCAEHkgAFBCTYCAEHggAFBCjYCAEHcgAFBCzYCAEHYgAFBDDYCAEHUgAFBDTYCAEHQgAFBDjYCAEHMgAFBDzYCAEHIgAFBEDYCAEHEgAFBETYCAEHAgAFBEjYCACAAIAAoAkAgASACQdSAASgCABEAADYCQCADQRBqJAALwAEBAX8jAEEQayIDJAAgA0EAOgAIQYCBAUECNgIAQfyAAUEDNgIAQfiAAUEENgIAQfSAAUEFNgIAQfCAAUEGNgIAQeyAAUEHNgIAQeiAAUEINgIAQeSAAUEJNgIAQeCAAUEKNgIAQdyAAUELNgIAQdiAAUEMNgIAQdSAAUENNgIAQdCAAUEONgIAQcyAAUEPNgIAQciAAUEQNgIAQcSAAUERNgIAQcCAAUESNgIAIAAgASACEF0hACADQRBqJAAgAAu+AQEBfyMAQRBrIgIkACACQQA6AAhBgIEBQQI2AgBB/IABQQM2AgBB+IABQQQ2AgBB9IABQQU2AgBB8IABQQY2AgBB7IABQQc2AgBB6IABQQg2AgBB5IABQQk2AgBB4IABQQo2AgBB3IABQQs2AgBB2IABQQw2AgBB1IABQQ02AgBB0IABQQ42AgBBzIABQQ82AgBByIABQRA2AgBBxIABQRE2AgBBwIABQRI2AgAgACABEFwhACACQRBqJAAgAAu2AQEBfyMAQRBrIgAkACAAQQA6AAhBgIEBQQI2AgBB/IABQQM2AgBB+IABQQQ2AgBB9IABQQU2AgBB8IABQQY2AgBB7IABQQc2AgBB6IABQQg2AgBB5IABQQk2AgBB4IABQQo2AgBB3IABQQs2AgBB2IABQQw2AgBB1IABQQ02AgBB0IABQQ42AgBBzIABQQ82AgBByIABQRA2AgBBxIABQRE2AgBBwIABQRI2AgAgAEEQaiQAQQgLwgEBAX8jAEEQayIEJAAgBEEAOgAIQYCBAUECNgIAQfyAAUEDNgIAQfiAAUEENgIAQfSAAUEFNgIAQfCAAUEGNgIAQeyAAUEHNgIAQeiAAUEINgIAQeSAAUEJNgIAQeCAAUEKNgIAQdyAAUELNgIAQdiAAUEMNgIAQdSAAUENNgIAQdCAAUEONgIAQcyAAUEPNgIAQciAAUEQNgIAQcSAAUERNgIAQcCAAUESNgIAIAAgASACIAMQWSEAIARBEGokACAAC8IBAQF/IwBBEGsiBCQAIARBADoACEGAgQFBAjYCAEH8gAFBAzYCAEH4gAFBBDYCAEH0gAFBBTYCAEHwgAFBBjYCAEHsgAFBBzYCAEHogAFBCDYCAEHkgAFBCTYCAEHggAFBCjYCAEHcgAFBCzYCAEHYgAFBDDYCAEHUgAFBDTYCAEHQgAFBDjYCAEHMgAFBDzYCAEHIgAFBEDYCAEHEgAFBETYCAEHAgAFBEjYCACAAIAEgAiADEFYhACAEQRBqJAAgAAsHACAALwEwC8ABAQF/IwBBEGsiAyQAIANBADoACEGAgQFBAjYCAEH8gAFBAzYCAEH4gAFBBDYCAEH0gAFBBTYCAEHwgAFBBjYCAEHsgAFBBzYCAEHogAFBCDYCAEHkgAFBCTYCAEHggAFBCjYCAEHcgAFBCzYCAEHYgAFBDDYCAEHUgAFBDTYCAEHQgAFBDjYCAEHMgAFBDzYCAEHIgAFBEDYCAEHEgAFBETYCAEHAgAFBEjYCACAAIAEgAhBVIQAgA0EQaiQAIAALBwAgACgCQAsaACAAIAAoAkAgASACQdSAASgCABEAADYCQAsLACAAQQA2AkBBAAsHACAAKAIgCwQAQQgLzgUCA34BfyMAQYBAaiIIJAACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCAEDhECAwwFAAEECAkJCQkJCQcJBgkLIANCCFoEfiACIAEoAmQ2AgAgAiABKAJoNgIEQggFQn8LIQYMCwsgARAGDAoLIAEoAhAiAgRAIAIgASkDGCABQeQAaiICEEEiA1ANCCABKQMIIgVCf4UgA1QEQCACBEAgAkEANgIEIAJBFTYCAAsMCQsgAUEANgIQIAEgAyAFfDcDCCABIAEpAwAgA3w3AwALIAEtAHgEQCABKQMAIQUMCQtCACEDIAEpAwAiBVAEQCABQgA3AyAMCgsDQCAAIAggBSADfSIFQoDAACAFQoDAAFQbEBEiB0J/VwRAIAFB5ABqIgEEQCABIAAoAgw2AgAgASAAKAIQNgIECwwJCyAHUEUEQCABKQMAIgUgAyAHfCIDWA0KDAELCyABQeQAagRAIAFBADYCaCABQRE2AmQLDAcLIAEpAwggASkDICIFfSIHIAMgAyAHVhsiA1ANCAJAIAEtAHhFDQAgACAFQQAQFEF/Sg0AIAFB5ABqIgEEQCABIAAoAgw2AgAgASAAKAIQNgIECwwHCyAAIAIgAxARIgZCf1cEQCABQeQAagRAIAFBADYCaCABQRE2AmQLDAcLIAEgASkDICAGfCIDNwMgIAZCAFINCEIAIQYgAyABKQMIWg0IIAFB5ABqBEAgAUEANgJoIAFBETYCZAsMBgsgASkDICABKQMAIgV9IAEpAwggBX0gAiADIAFB5ABqEEQiA0IAUw0FIAEgASkDACADfDcDIAwHCyACIAFBKGoQYEEfdawhBgwGCyABMABgIQYMBQsgASkDcCEGDAQLIAEpAyAgASkDAH0hBgwDCyABQeQAagRAIAFBADYCaCABQRw2AmQLC0J/IQYMAQsgASAFNwMgCyAIQYBAayQAIAYLBwAgACgCAAsPACAAIAAoAjBBAWo2AjALGABB+IMBQgA3AgBBgIQBQQA2AgBB+IMBCwcAIABBDGoLBwAgACgCLAsHACAAKAIoCwcAIAAoAhgLFQAgACABrSACrUIghoQgAyAEEIoBCxMBAX4gABAzIgFCIIinEAAgAacLbwEBfiABrSACrUIghoQhBSMAQRBrIgEkAAJ/IABFBEAgBVBFBEAgBARAIARBADYCBCAEQRI2AgALQQAMAgtBAEIAIAMgBBA6DAELIAEgBTcDCCABIAA2AgAgAUIBIAMgBBA6CyEAIAFBEGokACAACxQAIAAgASACrSADrUIghoQgBBBSC9oCAgJ/AX4CfyABrSACrUIghoQiByAAKQMwVEEAIARBCkkbRQRAIABBCGoEQCAAQQA2AgwgAEESNgIIC0F/DAELIAAtABhBAnEEQCAAQQhqBEAgAEEANgIMIABBGTYCCAtBfwwBCyADBH8gA0H//wNxQQhGIANBfUtyBUEBC0UEQCAAQQhqBEAgAEEANgIMIABBEDYCCAtBfwwBCyAAKAJAIgEgB6ciBUEEdGooAgAiAgR/IAIoAhAgA0YFIANBf0YLIQYgASAFQQR0aiIBIQUgASgCBCEBAkAgBgRAIAFFDQEgAUEAOwFQIAEgASgCAEF+cSIANgIAIAANASABECAgBUEANgIEQQAMAgsCQCABDQAgBSACECsiATYCBCABDQAgAEEIagRAIABBADYCDCAAQQ42AggLQX8MAgsgASAEOwFQIAEgAzYCECABIAEoAgBBAXI2AgALQQALCxwBAX4gACABIAIgAEEIahBMIgNCIIinEAAgA6cLHwEBfiAAIAEgAq0gA61CIIaEEBEiBEIgiKcQACAEpwteAQF+An5CfyAARQ0AGiAAKQMwIgIgAUEIcUUNABpCACACUA0AGiAAKAJAIQADQCACIAKnQQR0IABqQRBrKAIADQEaIAJCAX0iAkIAUg0AC0IACyICQiCIpxAAIAKnCxMAIAAgAa0gAq1CIIaEIAMQiwELnwEBAn4CfiACrSADrUIghoQhBUJ/IQQCQCAARQ0AIAAoAgQNACAAQQRqIQIgBUJ/VwRAIAIEQCACQQA2AgQgAkESNgIAC0J/DAILQgAhBCAALQAQDQAgBVANACAAKAIUIAEgBRARIgRCf1UNACAAKAIUIQAgAgRAIAIgACgCDDYCACACIAAoAhA2AgQLQn8hBAsgBAsiBEIgiKcQACAEpwueAQEBfwJ/IAAgACABrSACrUIghoQgAyAAKAIcEH8iAQRAIAEQMkF/TARAIABBCGoEQCAAIAEoAgw2AgggACABKAIQNgIMCyABEAtBAAwCC0EYEAkiBEUEQCAAQQhqBEAgAEEANgIMIABBDjYCCAsgARALQQAMAgsgBCAANgIAIARBADYCDCAEQgA3AgQgBCABNgIUIARBADoAEAsgBAsLsQICAX8BfgJ/QX8hBAJAIAAgAa0gAq1CIIaEIgZBAEEAECZFDQAgAC0AGEECcQRAIABBCGoEQCAAQQA2AgwgAEEZNgIIC0F/DAILIAAoAkAiASAGpyICQQR0aiIEKAIIIgUEQEEAIQQgBSADEHFBf0oNASAAQQhqBEAgAEEANgIMIABBDzYCCAtBfwwCCwJAIAQoAgAiBQRAIAUoAhQgA0YNAQsCQCABIAJBBHRqIgEoAgQiBA0AIAEgBRArIgQ2AgQgBA0AIABBCGoEQCAAQQA2AgwgAEEONgIIC0F/DAMLIAQgAzYCFCAEIAQoAgBBIHI2AgBBAAwCC0EAIQQgASACQQR0aiIBKAIEIgBFDQAgACAAKAIAQV9xIgI2AgAgAg0AIAAQICABQQA2AgQLIAQLCxQAIAAgAa0gAq1CIIaEIAQgBRBzCxIAIAAgAa0gAq1CIIaEIAMQFAtBAQF+An4gAUEAIAIbRQRAIABBCGoEQCAAQQA2AgwgAEESNgIIC0J/DAELIAAgASACIAMQdAsiBEIgiKcQACAEpwvGAwIFfwF+An4CQAJAIAAiBC0AGEECcQRAIARBCGoEQCAEQQA2AgwgBEEZNgIICwwBCyABRQRAIARBCGoEQCAEQQA2AgwgBEESNgIICwwBCyABECIiByABakEBay0AAEEvRwRAIAdBAmoQCSIARQRAIARBCGoEQCAEQQA2AgwgBEEONgIICwwCCwJAAkAgACIGIAEiBXNBA3ENACAFQQNxBEADQCAGIAUtAAAiAzoAACADRQ0DIAZBAWohBiAFQQFqIgVBA3ENAAsLIAUoAgAiA0F/cyADQYGChAhrcUGAgYKEeHENAANAIAYgAzYCACAFKAIEIQMgBkEEaiEGIAVBBGohBSADQYGChAhrIANBf3NxQYCBgoR4cUUNAAsLIAYgBS0AACIDOgAAIANFDQADQCAGIAUtAAEiAzoAASAGQQFqIQYgBUEBaiEFIAMNAAsLIAcgACIDakEvOwAACyAEQQBCAEEAEFIiAEUEQCADEAYMAQsgBCADIAEgAxsgACACEHQhCCADEAYgCEJ/VwRAIAAQCyAIDAMLIAQgCEEDQYCA/I8EEHNBf0oNASAEIAgQchoLQn8hCAsgCAsiCEIgiKcQACAIpwsQACAAIAGtIAKtQiCGhBByCxYAIAAgAa0gAq1CIIaEIAMgBCAFEGYL3iMDD38IfgF8IwBB8ABrIgkkAAJAIAFBAE5BACAAG0UEQCACBEAgAkEANgIEIAJBEjYCAAsMAQsgACkDGCISAn5BsIMBKQMAIhNCf1EEQCAJQoOAgIBwNwMwIAlChoCAgPAANwMoIAlCgYCAgCA3AyBBsIMBQQAgCUEgahAkNwMAIAlCj4CAgHA3AxAgCUKJgICAoAE3AwAgCUKMgICA0AE3AwhBuIMBQQggCRAkNwMAQbCDASkDACETCyATC4MgE1IEQCACBEAgAkEANgIEIAJBHDYCAAsMAQsgASABQRByQbiDASkDACITIBKDIBNRGyIKQRhxQRhGBEAgAgRAIAJBADYCBCACQRk2AgALDAELIAlBOGoQKgJAIAAgCUE4ahAhBEACQCAAKAIMQQVGBEAgACgCEEEsRg0BCyACBEAgAiAAKAIMNgIAIAIgACgCEDYCBAsMAgsgCkEBcUUEQCACBEAgAkEANgIEIAJBCTYCAAsMAwsgAhBJIgVFDQEgBSAKNgIEIAUgADYCACAKQRBxRQ0CIAUgBSgCFEECcjYCFCAFIAUoAhhBAnI2AhgMAgsgCkECcQRAIAIEQCACQQA2AgQgAkEKNgIACwwCCyAAEDJBf0wEQCACBEAgAiAAKAIMNgIAIAIgACgCEDYCBAsMAQsCfyAKQQhxBEACQCACEEkiAUUNACABIAo2AgQgASAANgIAIApBEHFFDQAgASABKAIUQQJyNgIUIAEgASgCGEECcjYCGAsgAQwBCyMAQUBqIg4kACAOQQhqECoCQCAAIA5BCGoQIUF/TARAIAIEQCACIAAoAgw2AgAgAiAAKAIQNgIECwwBCyAOLQAIQQRxRQRAIAIEQCACQYoBNgIEIAJBBDYCAAsMAQsgDikDICETIAIQSSIFRQRAQQAhBQwBCyAFIAo2AgQgBSAANgIAIApBEHEEQCAFIAUoAhRBAnI2AhQgBSAFKAIYQQJyNgIYCwJAAkACQCATUARAAn8gACEBAkADQCABKQMYQoCAEINCAFINASABKAIAIgENAAtBAQwBCyABQQBCAEESEA6nCw0EIAVBCGoEQCAFQQA2AgwgBUETNgIICwwBCyMAQdAAayIBJAACQCATQhVYBEAgBUEIagRAIAVBADYCDCAFQRM2AggLDAELAkACQCAFKAIAQgAgE0KqgAQgE0KqgARUGyISfUECEBRBf0oNACAFKAIAIgMoAgxBBEYEQCADKAIQQRZGDQELIAVBCGoEQCAFIAMoAgw2AgggBSADKAIQNgIMCwwBCyAFKAIAEDMiE0J/VwRAIAUoAgAhAyAFQQhqIggEQCAIIAMoAgw2AgAgCCADKAIQNgIECwwBCyAFKAIAIBJBACAFQQhqIg8QLSIERQ0BIBJCqoAEWgRAAkAgBCkDCEIUVARAIARBADoAAAwBCyAEQhQ3AxAgBEEBOgAACwsgAQRAIAFBADYCBCABQRM2AgALIARCABATIQwCQCAELQAABH4gBCkDCCAEKQMQfQVCAAunIgdBEmtBA0sEQEJ/IRcDQCAMQQFrIQMgByAMakEVayEGAkADQCADQQFqIgNB0AAgBiADaxB6IgNFDQEgA0EBaiIMQZ8SQQMQPQ0ACwJAIAMgBCgCBGusIhIgBCkDCFYEQCAEQQA6AAAMAQsgBCASNwMQIARBAToAAAsgBC0AAAR+IAQpAxAFQgALIRICQCAELQAABH4gBCkDCCAEKQMQfQVCAAtCFVgEQCABBEAgAUEANgIEIAFBEzYCAAsMAQsgBEIEEBMoAABB0JaVMEcEQCABBEAgAUEANgIEIAFBEzYCAAsMAQsCQAJAAkAgEkIUVA0AIAQoAgQgEqdqQRRrKAAAQdCWmThHDQACQCASQhR9IhQgBCIDKQMIVgRAIANBADoAAAwBCyADIBQ3AxAgA0EBOgAACyAFKAIUIRAgBSgCACEGIAMtAAAEfiAEKQMQBUIACyEWIARCBBATGiAEEAwhCyAEEAwhDSAEEB0iFEJ/VwRAIAEEQCABQRY2AgQgAUEENgIACwwECyAUQjh8IhUgEyAWfCIWVgRAIAEEQCABQQA2AgQgAUEVNgIACwwECwJAAkAgEyAUVg0AIBUgEyAEKQMIfFYNAAJAIBQgE30iFSAEKQMIVgRAIANBADoAAAwBCyADIBU3AxAgA0EBOgAAC0EAIQcMAQsgBiAUQQAQFEF/TARAIAEEQCABIAYoAgw2AgAgASAGKAIQNgIECwwFC0EBIQcgBkI4IAFBEGogARAtIgNFDQQLIANCBBATKAAAQdCWmTBHBEAgAQRAIAFBADYCBCABQRU2AgALIAdFDQQgAxAIDAQLIAMQHSEVAkAgEEEEcSIGRQ0AIBQgFXxCDHwgFlENACABBEAgAUEANgIEIAFBFTYCAAsgB0UNBCADEAgMBAsgA0IEEBMaIAMQFSIQIAsgC0H//wNGGyELIAMQFSIRIA0gDUH//wNGGyENAkAgBkUNACANIBFGQQAgCyAQRhsNACABBEAgAUEANgIEIAFBFTYCAAsgB0UNBCADEAgMBAsgCyANcgRAIAEEQCABQQA2AgQgAUEBNgIACyAHRQ0EIAMQCAwECyADEB0iGCADEB1SBEAgAQRAIAFBADYCBCABQQE2AgALIAdFDQQgAxAIDAQLIAMQHSEVIAMQHSEWIAMtAABFBEAgAQRAIAFBADYCBCABQRQ2AgALIAdFDQQgAxAIDAQLIAcEQCADEAgLAkAgFkIAWQRAIBUgFnwiGSAWWg0BCyABBEAgAUEWNgIEIAFBBDYCAAsMBAsgEyAUfCIUIBlUBEAgAQRAIAFBADYCBCABQRU2AgALDAQLAkAgBkUNACAUIBlRDQAgAQRAIAFBADYCBCABQRU2AgALDAQLIBggFUIugFgNASABBEAgAUEANgIEIAFBFTYCAAsMAwsCQCASIAQpAwhWBEAgBEEAOgAADAELIAQgEjcDECAEQQE6AAALIAUoAhQhAyAELQAABH4gBCkDCCAEKQMQfQVCAAtCFVgEQCABBEAgAUEANgIEIAFBFTYCAAsMAwsgBC0AAAR+IAQpAxAFQgALIRQgBEIEEBMaIAQQFQRAIAEEQCABQQA2AgQgAUEBNgIACwwDCyAEEAwgBBAMIgZHBEAgAQRAIAFBADYCBCABQRM2AgALDAMLIAQQFSEHIAQQFa0iFiAHrSIVfCIYIBMgFHwiFFYEQCABBEAgAUEANgIEIAFBFTYCAAsMAwsCQCADQQRxRQ0AIBQgGFENACABBEAgAUEANgIEIAFBFTYCAAsMAwsgBq0gARBqIgNFDQIgAyAWNwMgIAMgFTcDGCADQQA6ACwMAQsgGCABEGoiA0UNASADIBY3AyAgAyAVNwMYIANBAToALAsCQCASQhR8IhQgBCkDCFYEQCAEQQA6AAAMAQsgBCAUNwMQIARBAToAAAsgBBAMIQYCQCADKQMYIAMpAyB8IBIgE3xWDQACQCAGRQRAIAUtAARBBHFFDQELAkAgEkIWfCISIAQpAwhWBEAgBEEAOgAADAELIAQgEjcDECAEQQE6AAALIAQtAAAEfiAEKQMIIAQpAxB9BUIACyIUIAatIhJUDQEgBS0ABEEEcUEAIBIgFFIbDQEgBkUNACADIAQgEhATIAZBACABEDUiBjYCKCAGDQAgAxAWDAILAkAgEyADKQMgIhJYBEACQCASIBN9IhIgBCkDCFYEQCAEQQA6AAAMAQsgBCASNwMQIARBAToAAAsgBCADKQMYEBMiBkUNAiAGIAMpAxgQFyIHDQEgAQRAIAFBADYCBCABQQ42AgALIAMQFgwDCyAFKAIAIBJBABAUIQcgBSgCACEGIAdBf0wEQCABBEAgASAGKAIMNgIAIAEgBigCEDYCBAsgAxAWDAMLQQAhByAGEDMgAykDIFENACABBEAgAUEANgIEIAFBEzYCAAsgAxAWDAILQgAhFAJAAkAgAykDGCIWUEUEQANAIBQgAykDCFIiC0UEQCADLQAsDQMgFkIuVA0DAn8CQCADKQMQIhVCgIAEfCISIBVaQQAgEkKAgICAAVQbRQ0AIAMoAgAgEqdBBHQQNCIGRQ0AIAMgBjYCAAJAIAMpAwgiFSASWg0AIAYgFadBBHRqIgZCADcCACAGQgA3AAUgFUIBfCIVIBJRDQADQCADKAIAIBWnQQR0aiIGQgA3AgAgBkIANwAFIBVCAXwiFSASUg0ACwsgAyASNwMIIAMgEjcDEEEBDAELIAEEQCABQQA2AgQgAUEONgIAC0EAC0UNBAtB2AAQCSIGBH8gBkIANwMgIAZBADYCGCAGQv////8PNwMQIAZBADsBDCAGQb+GKDYCCCAGQQE6AAYgBkEAOwEEIAZBADYCACAGQgA3A0ggBkGAgNiNeDYCRCAGQgA3AyggBkIANwMwIAZCADcDOCAGQUBrQQA7AQAgBkIANwNQIAYFQQALIQYgAygCACAUp0EEdGogBjYCAAJAIAYEQCAGIAUoAgAgB0EAIAEQaCISQn9VDQELIAsNBCABKAIAQRNHDQQgAQRAIAFBADYCBCABQRU2AgALDAQLIBRCAXwhFCAWIBJ9IhZCAFINAAsLIBQgAykDCFINAAJAIAUtAARBBHFFDQAgBwRAIActAAAEfyAHKQMQIAcpAwhRBUEAC0UNAgwBCyAFKAIAEDMiEkJ/VwRAIAUoAgAhBiABBEAgASAGKAIMNgIAIAEgBigCEDYCBAsgAxAWDAULIBIgAykDGCADKQMgfFINAQsgBxAIAn4gCARAAn8gF0IAVwRAIAUgCCABEEghFwsgBSADIAEQSCISIBdVCwRAIAgQFiASDAILIAMQFgwFC0IAIAUtAARBBHFFDQAaIAUgAyABEEgLIRcgAyEIDAMLIAEEQCABQQA2AgQgAUEVNgIACyAHEAggAxAWDAILIAMQFiAHEAgMAQsgAQRAIAFBADYCBCABQRU2AgALIAMQFgsCQCAMIAQoAgRrrCISIAQpAwhWBEAgBEEAOgAADAELIAQgEjcDECAEQQE6AAALIAQtAAAEfiAEKQMIIAQpAxB9BUIAC6ciB0ESa0EDSw0BCwsgBBAIIBdCf1UNAwwBCyAEEAgLIA8iAwRAIAMgASgCADYCACADIAEoAgQ2AgQLIAgQFgtBACEICyABQdAAaiQAIAgNAQsgAgRAIAIgBSgCCDYCACACIAUoAgw2AgQLDAELIAUgCCgCADYCQCAFIAgpAwg3AzAgBSAIKQMQNwM4IAUgCCgCKDYCICAIEAYgBSgCUCEIIAVBCGoiBCEBQQAhBwJAIAUpAzAiE1ANAEGAgICAeCEGAn8gE7pEAAAAAAAA6D+jRAAA4P///+9BpCIaRAAAAAAAAPBBYyAaRAAAAAAAAAAAZnEEQCAaqwwBC0EACyIDQYCAgIB4TQRAIANBAWsiA0EBdiADciIDQQJ2IANyIgNBBHYgA3IiA0EIdiADciIDQRB2IANyQQFqIQYLIAYgCCgCACIMTQ0AIAYQPCILRQRAIAEEQCABQQA2AgQgAUEONgIACwwBCwJAIAgpAwhCACAMG1AEQCAIKAIQIQ8MAQsgCCgCECEPA0AgDyAHQQJ0aigCACIBBEADQCABKAIYIQMgASALIAEoAhwgBnBBAnRqIg0oAgA2AhggDSABNgIAIAMiAQ0ACwsgB0EBaiIHIAxHDQALCyAPEAYgCCAGNgIAIAggCzYCEAsCQCAFKQMwUA0AQgAhEwJAIApBBHFFBEADQCAFKAJAIBOnQQR0aigCACgCMEEAQQAgAhAlIgFFDQQgBSgCUCABIBNBCCAEEE1FBEAgBCgCAEEKRw0DCyATQgF8IhMgBSkDMFQNAAwDCwALA0AgBSgCQCATp0EEdGooAgAoAjBBAEEAIAIQJSIBRQ0DIAUoAlAgASATQQggBBBNRQ0BIBNCAXwiEyAFKQMwVA0ACwwBCyACBEAgAiAEKAIANgIAIAIgBCgCBDYCBAsMAQsgBSAFKAIUNgIYDAELIAAgACgCMEEBajYCMCAFEEtBACEFCyAOQUBrJAAgBQsiBQ0BIAAQGhoLQQAhBQsgCUHwAGokACAFCxAAIwAgAGtBcHEiACQAIAALBgAgACQACwQAIwAL4CoDEX8IfgN8IwBBwMAAayIHJABBfyECAkAgAEUNAAJ/IAAtAChFBEBBACAAKAIYIAAoAhRGDQEaC0EBCyEBAkACQCAAKQMwIhRQRQRAIAAoAkAhCgNAIAogEqdBBHRqIgMtAAwhCwJAAkAgAygCCA0AIAsNACADKAIEIgNFDQEgAygCAEUNAQtBASEBCyAXIAtBAXOtQv8Bg3whFyASQgF8IhIgFFINAAsgF0IAUg0BCyAAKAIEQQhxIAFyRQ0BAn8gACgCACIDKAIkIgFBA0cEQCADKAIgBH9BfyADEBpBAEgNAhogAygCJAUgAQsEQCADEEMLQX8gA0EAQgBBDxAOQgBTDQEaIANBAzYCJAtBAAtBf0oNASAAKAIAKAIMQRZGBEAgACgCACgCEEEsRg0CCyAAKAIAIQEgAEEIagRAIAAgASgCDDYCCCAAIAEoAhA2AgwLDAILIAFFDQAgFCAXVARAIABBCGoEQCAAQQA2AgwgAEEUNgIICwwCCyAXp0EDdBAJIgtFDQFCfyEWQgAhEgNAAkAgCiASp0EEdGoiBigCACIDRQ0AAkAgBigCCA0AIAYtAAwNACAGKAIEIgFFDQEgASgCAEUNAQsgFiADKQNIIhMgEyAWVhshFgsgBi0ADEUEQCAXIBlYBEAgCxAGIABBCGoEQCAAQQA2AgwgAEEUNgIICwwECyALIBmnQQN0aiASNwMAIBlCAXwhGQsgEkIBfCISIBRSDQALIBcgGVYEQCALEAYgAEEIagRAIABBADYCDCAAQRQ2AggLDAILAkACQCAAKAIAKQMYQoCACINQDQACQAJAIBZCf1INACAAKQMwIhNQDQIgE0IBgyEVIAAoAkAhAwJAIBNCAVEEQEJ/IRRCACESQgAhFgwBCyATQn6DIRlCfyEUQgAhEkIAIRYDQCADIBKnQQR0aigCACIBBEAgFiABKQNIIhMgEyAWVCIBGyEWIBQgEiABGyEUCyADIBJCAYQiGKdBBHRqKAIAIgEEQCAWIAEpA0giEyATIBZUIgEbIRYgFCAYIAEbIRQLIBJCAnwhEiAZQgJ9IhlQRQ0ACwsCQCAVUA0AIAMgEqdBBHRqKAIAIgFFDQAgFiABKQNIIhMgEyAWVCIBGyEWIBQgEiABGyEUCyAUQn9RDQBCACETIwBBEGsiBiQAAkAgACAUIABBCGoiCBBBIhVQDQAgFSAAKAJAIBSnQQR0aigCACIKKQMgIhh8IhQgGFpBACAUQn9VG0UEQCAIBEAgCEEWNgIEIAhBBDYCAAsMAQsgCi0ADEEIcUUEQCAUIRMMAQsgACgCACAUQQAQFCEBIAAoAgAhAyABQX9MBEAgCARAIAggAygCDDYCACAIIAMoAhA2AgQLDAELIAMgBkEMakIEEBFCBFIEQCAAKAIAIQEgCARAIAggASgCDDYCACAIIAEoAhA2AgQLDAELIBRCBHwgFCAGKAAMQdCWncAARhtCFEIMAn9BASEBAkAgCikDKEL+////D1YNACAKKQMgQv7///8PVg0AQQAhAQsgAQsbfCIUQn9XBEAgCARAIAhBFjYCBCAIQQQ2AgALDAELIBQhEwsgBkEQaiQAIBMiFkIAUg0BIAsQBgwFCyAWUA0BCwJ/IAAoAgAiASgCJEEBRgRAIAFBDGoEQCABQQA2AhAgAUESNgIMC0F/DAELQX8gAUEAIBZBERAOQgBTDQAaIAFBATYCJEEAC0F/Sg0BC0IAIRYCfyAAKAIAIgEoAiRBAUYEQCABQQxqBEAgAUEANgIQIAFBEjYCDAtBfwwBC0F/IAFBAEIAQQgQDkIAUw0AGiABQQE2AiRBAAtBf0oNACAAKAIAIQEgAEEIagRAIAAgASgCDDYCCCAAIAEoAhA2AgwLIAsQBgwCCyAAKAJUIgIEQCACQgA3AxggAigCAEQAAAAAAAAAACACKAIMIAIoAgQRDgALIABBCGohBCAXuiEcQgAhFAJAAkACQANAIBcgFCITUgRAIBO6IByjIRsgE0IBfCIUuiAcoyEaAkAgACgCVCICRQ0AIAIgGjkDKCACIBs5AyAgAisDECAaIBuhRAAAAAAAAAAAoiAboCIaIAIrAxihY0UNACACKAIAIBogAigCDCACKAIEEQ4AIAIgGjkDGAsCfwJAIAAoAkAgCyATp0EDdGopAwAiE6dBBHRqIg0oAgAiAQRAIAEpA0ggFlQNAQsgDSgCBCEFAkACfwJAIA0oAggiAkUEQCAFRQ0BQQEgBSgCACICQQFxDQIaIAJBwABxQQZ2DAILQQEgBQ0BGgsgDSABECsiBTYCBCAFRQ0BIAJBAEcLIQZBACEJIwBBEGsiDCQAAkAgEyAAKQMwWgRAIABBCGoEQCAAQQA2AgwgAEESNgIIC0F/IQkMAQsgACgCQCIKIBOnIgNBBHRqIg8oAgAiAkUNACACLQAEDQACQCACKQNIQhp8IhhCf1cEQCAAQQhqBEAgAEEWNgIMIABBBDYCCAsMAQtBfyEJIAAoAgAgGEEAEBRBf0wEQCAAKAIAIQIgAEEIagRAIAAgAigCDDYCCCAAIAIoAhA2AgwLDAILIAAoAgBCBCAMQQxqIABBCGoiDhAtIhBFDQEgEBAMIQEgEBAMIQggEC0AAAR/IBApAxAgECkDCFEFQQALIQIgEBAIIAJFBEAgDgRAIA5BADYCBCAOQRQ2AgALDAILAkAgCEUNACAAKAIAIAGtQQEQFEF/TARAQYSEASgCACECIA4EQCAOIAI2AgQgDkEENgIACwwDC0EAIAAoAgAgCEEAIA4QRSIBRQ0BIAEgCEGAAiAMQQhqIA4QbiECIAEQBiACRQ0BIAwoAggiAkUNACAMIAIQbSICNgIIIA8oAgAoAjQgAhBvIQIgDygCACACNgI0CyAPKAIAIgJBAToABEEAIQkgCiADQQR0aigCBCIBRQ0BIAEtAAQNASACKAI0IQIgAUEBOgAEIAEgAjYCNAwBC0F/IQkLIAxBEGokACAJQQBIDQUgACgCABAfIhhCAFMNBSAFIBg3A0ggBgRAQQAhDCANKAIIIg0hASANRQRAIAAgACATQQhBABB/IgwhASAMRQ0HCwJAAkAgASAHQQhqECFBf0wEQCAEBEAgBCABKAIMNgIAIAQgASgCEDYCBAsMAQsgBykDCCISQsAAg1AEQCAHQQA7ATggByASQsAAhCISNwMICwJAAkAgBSgCECICQX5PBEAgBy8BOCIDRQ0BIAUgAzYCECADIQIMAgsgAg0AIBJCBINQDQAgByAHKQMgNwMoIAcgEkIIhCISNwMIQQAhAgwBCyAHIBJC9////w+DIhI3AwgLIBJCgAGDUARAIAdBADsBOiAHIBJCgAGEIhI3AwgLAn8gEkIEg1AEQEJ/IRVBgAoMAQsgBSAHKQMgIhU3AyggEkIIg1AEQAJAAkACQAJAQQggAiACQX1LG0H//wNxDg0CAwMDAwMDAwEDAwMAAwtBgApBgAIgFUKUwuTzD1YbDAQLQYAKQYACIBVCg4Ow/w9WGwwDC0GACkGAAiAVQv////8PVhsMAgtBgApBgAIgFUIAUhsMAQsgBSAHKQMoNwMgQYACCyEPIAAoAgAQHyITQn9XBEAgACgCACECIAQEQCAEIAIoAgw2AgAgBCACKAIQNgIECwwBCyAFIAUvAQxB9/8DcTsBDCAAIAUgDxA3IgpBAEgNACAHLwE4IghBCCAFKAIQIgMgA0F9SxtB//8DcSICRyEGAkACQAJAAkACQAJAAkAgAiAIRwRAIANBAEchAwwBC0EAIQMgBS0AAEGAAXFFDQELIAUvAVIhCSAHLwE6IQIMAQsgBS8BUiIJIAcvAToiAkYNAQsgASABKAIwQQFqNgIwIAJB//8DcQ0BIAEhAgwCCyABIAEoAjBBAWo2AjBBACEJDAILQSZBACAHLwE6QQFGGyICRQRAIAQEQCAEQQA2AgQgBEEYNgIACyABEAsMAwsgACABIAcvATpBACAAKAIcIAIRBgAhAiABEAsgAkUNAgsgCUEARyEJIAhBAEcgBnFFBEAgAiEBDAELIAAgAiAHLwE4EIEBIQEgAhALIAFFDQELAkAgCEUgBnJFBEAgASECDAELIAAgAUEAEIABIQIgARALIAJFDQELAkAgA0UEQCACIQMMAQsgACACIAUoAhBBASAFLwFQEIIBIQMgAhALIANFDQELAkAgCUUEQCADIQEMAQsgBSgCVCIBRQRAIAAoAhwhAQsCfyAFLwFSGkEBCwRAIAQEQCAEQQA2AgQgBEEYNgIACyADEAsMAgsgACADIAUvAVJBASABQQARBgAhASADEAsgAUUNAQsgACgCABAfIhhCf1cEQCAAKAIAIQIgBARAIAQgAigCDDYCACAEIAIoAhA2AgQLDAELAkAgARAyQQBOBEACfwJAAkAgASAHQUBrQoDAABARIhJCAVMNAEIAIRkgFUIAVQRAIBW5IRoDQCAAIAdBQGsgEhAbQQBIDQMCQCASQoDAAFINACAAKAJUIgJFDQAgAiAZQoBAfSIZuSAaoxB7CyABIAdBQGtCgMAAEBEiEkIAVQ0ACwwBCwNAIAAgB0FAayASEBtBAEgNAiABIAdBQGtCgMAAEBEiEkIAVQ0ACwtBACASQn9VDQEaIAQEQCAEIAEoAgw2AgAgBCABKAIQNgIECwtBfwshAiABEBoaDAELIAQEQCAEIAEoAgw2AgAgBCABKAIQNgIEC0F/IQILIAEgB0EIahAhQX9MBEAgBARAIAQgASgCDDYCACAEIAEoAhA2AgQLQX8hAgsCf0EAIQkCQCABIgNFDQADQCADLQAaQQFxBEBB/wEhCSADQQBCAEEQEA4iFUIAUw0CIBVCBFkEQCADQQxqBEAgA0EANgIQIANBFDYCDAsMAwsgFachCQwCCyADKAIAIgMNAAsLIAlBGHRBGHUiA0F/TAsEQCAEBEAgBCABKAIMNgIAIAQgASgCEDYCBAsgARALDAELIAEQCyACQQBIDQAgACgCABAfIRUgACgCACECIBVCf1cEQCAEBEAgBCACKAIMNgIAIAQgAigCEDYCBAsMAQsgAiATEHVBf0wEQCAAKAIAIQIgBARAIAQgAigCDDYCACAEIAIoAhA2AgQLDAELIAcpAwgiE0LkAINC5ABSBEAgBARAIARBADYCBCAEQRQ2AgALDAELAkAgBS0AAEEgcQ0AIBNCEINQRQRAIAUgBygCMDYCFAwBCyAFQRRqEAEaCyAFIAcvATg2AhAgBSAHKAI0NgIYIAcpAyAhEyAFIBUgGH03AyAgBSATNwMoIAUgBS8BDEH5/wNxIANB/wFxQQF0cjsBDCAPQQp2IQNBPyEBAkACQAJAAkAgBSgCECICQQxrDgMAAQIBCyAFQS47AQoMAgtBLSEBIAMNACAFKQMoQv7///8PVg0AIAUpAyBC/v///w9WDQBBFCEBIAJBCEYNACAFLwFSQQFGDQAgBSgCMCICBH8gAi8BBAVBAAtB//8DcSICBEAgAiAFKAIwKAIAakEBay0AAEEvRg0BC0EKIQELIAUgATsBCgsgACAFIA8QNyICQQBIDQAgAiAKRwRAIAQEQCAEQQA2AgQgBEEUNgIACwwBCyAAKAIAIBUQdUF/Sg0BIAAoAgAhAiAEBEAgBCACKAIMNgIAIAQgAigCEDYCBAsLIA0NByAMEAsMBwsgDQ0CIAwQCwwCCyAFIAUvAQxB9/8DcTsBDCAAIAVBgAIQN0EASA0FIAAgEyAEEEEiE1ANBSAAKAIAIBNBABAUQX9MBEAgACgCACECIAQEQCAEIAIoAgw2AgAgBCACKAIQNgIECwwGCyAFKQMgIRIjAEGAQGoiAyQAAkAgElBFBEAgAEEIaiECIBK6IRoDQEF/IQEgACgCACADIBJCgMAAIBJCgMAAVBsiEyACEGVBAEgNAiAAIAMgExAbQQBIDQIgACgCVCAaIBIgE30iErqhIBqjEHsgEkIAUg0ACwtBACEBCyADQYBAayQAIAFBf0oNAUEBIREgAUEcdkEIcUEIRgwCCyAEBEAgBEEANgIEIARBDjYCAAsMBAtBAAtFDQELCyARDQBBfyECAkAgACgCABAfQgBTDQAgFyEUQQAhCkIAIRcjAEHwAGsiESQAAkAgACgCABAfIhVCAFkEQCAUUEUEQANAIAAgACgCQCALIBenQQN0aigCAEEEdGoiAygCBCIBBH8gAQUgAygCAAtBgAQQNyIBQQBIBEBCfyEXDAQLIAFBAEcgCnIhCiAXQgF8IhcgFFINAAsLQn8hFyAAKAIAEB8iGEJ/VwRAIAAoAgAhASAAQQhqBEAgACABKAIMNgIIIAAgASgCEDYCDAsMAgsgEULiABAXIgZFBEAgAEEIagRAIABBADYCDCAAQQ42AggLDAILIBggFX0hEyAVQv////8PViAUQv//A1ZyIApyQQFxBEAgBkGZEkEEECwgBkIsEBggBkEtEA0gBkEtEA0gBkEAEBIgBkEAEBIgBiAUEBggBiAUEBggBiATEBggBiAVEBggBkGUEkEEECwgBkEAEBIgBiAYEBggBkEBEBILIAZBnhJBBBAsIAZBABASIAYgFEL//wMgFEL//wNUG6dB//8DcSIBEA0gBiABEA0gBkF/IBOnIBNC/v///w9WGxASIAZBfyAVpyAVQv7///8PVhsQEiAGIABBJEEgIAAtACgbaigCACIDBH8gAy8BBAVBAAtB//8DcRANIAYtAABFBEAgAEEIagRAIABBADYCDCAAQRQ2AggLIAYQCAwCCyAAIAYoAgQgBi0AAAR+IAYpAxAFQgALEBshASAGEAggAUEASA0BIAMEQCAAIAMoAgAgAzMBBBAbQQBIDQILIBMhFwwBCyAAKAIAIQEgAEEIagRAIAAgASgCDDYCCCAAIAEoAhA2AgwLQn8hFwsgEUHwAGokACAXQgBTDQAgACgCABAfQj+HpyECCyALEAYgAkEASA0BAn8gACgCACIBKAIkQQFHBEAgAUEMagRAIAFBADYCECABQRI2AgwLQX8MAQsgASgCICICQQJPBEAgAUEMagRAIAFBADYCECABQR02AgwLQX8MAQsCQCACQQFHDQAgARAaQQBODQBBfwwBCyABQQBCAEEJEA5Cf1cEQCABQQI2AiRBfwwBCyABQQA2AiRBAAtFDQIgACgCACECIAQEQCAEIAIoAgw2AgAgBCACKAIQNgIECwwBCyALEAYLIAAoAlQQfCAAKAIAEENBfyECDAILIAAoAlQQfAsgABBLQQAhAgsgB0HAwABqJAAgAgtFAEHwgwFCADcDAEHogwFCADcDAEHggwFCADcDAEHYgwFCADcDAEHQgwFCADcDAEHIgwFCADcDAEHAgwFCADcDAEHAgwELoQMBCH8jAEGgAWsiAiQAIAAQMQJAAn8CQCAAKAIAIgFBAE4EQCABQbATKAIASA0BCyACIAE2AhAgAkEgakH2ESACQRBqEHZBASEGIAJBIGohBCACQSBqECIhA0EADAELIAFBAnQiAUGwEmooAgAhBQJ/AkACQCABQcATaigCAEEBaw4CAAEECyAAKAIEIQNB9IIBKAIAIQdBACEBAkACQANAIAMgAUHQ8QBqLQAARwRAQdcAIQQgAUEBaiIBQdcARw0BDAILCyABIgQNAEGw8gAhAwwBC0Gw8gAhAQNAIAEtAAAhCCABQQFqIgMhASAIDQAgAyEBIARBAWsiBA0ACwsgBygCFBogAwwBC0EAIAAoAgRrQQJ0QdjAAGooAgALIgRFDQEgBBAiIQMgBUUEQEEAIQVBASEGQQAMAQsgBRAiQQJqCyEBIAEgA2pBAWoQCSIBRQRAQegSKAIAIQUMAQsgAiAENgIIIAJBrBJBkRIgBhs2AgQgAkGsEiAFIAYbNgIAIAFBqwogAhB2IAAgATYCCCABIQULIAJBoAFqJAAgBQszAQF/IAAoAhQiAyABIAIgACgCECADayIBIAEgAksbIgEQBxogACAAKAIUIAFqNgIUIAILBgBBsIgBCwYAQayIAQsGAEGkiAELBwAgAEEEagsHACAAQQhqCyYBAX8gACgCFCIBBEAgARALCyAAKAIEIQEgAEEEahAxIAAQBiABC6kBAQN/AkAgAC0AACICRQ0AA0AgAS0AACIERQRAIAIhAwwCCwJAIAIgBEYNACACQSByIAIgAkHBAGtBGkkbIAEtAAAiAkEgciACIAJBwQBrQRpJG0YNACAALQAAIQMMAgsgAUEBaiEBIAAtAAEhAiAAQQFqIQAgAg0ACwsgA0H/AXEiAEEgciAAIABBwQBrQRpJGyABLQAAIgBBIHIgACAAQcEAa0EaSRtrC8sGAgJ+An8jAEHgAGsiByQAAkACQAJAAkACQAJAAkACQAJAAkACQCAEDg8AAQoCAwQGBwgICAgICAUICyABQgA3AyAMCQsgACACIAMQESIFQn9XBEAgAUEIaiIBBEAgASAAKAIMNgIAIAEgACgCEDYCBAsMCAsCQCAFUARAIAEpAygiAyABKQMgUg0BIAEgAzcDGCABQQE2AgQgASgCAEUNASAAIAdBKGoQIUF/TARAIAFBCGoiAQRAIAEgACgCDDYCACABIAAoAhA2AgQLDAoLAkAgBykDKCIDQiCDUA0AIAcoAlQgASgCMEYNACABQQhqBEAgAUEANgIMIAFBBzYCCAsMCgsgA0IEg1ANASAHKQNAIAEpAxhRDQEgAUEIagRAIAFBADYCDCABQRU2AggLDAkLIAEoAgQNACABKQMoIgMgASkDICIGVA0AIAUgAyAGfSIDWA0AIAEoAjAhBANAIAECfyAFIAN9IgZC/////w8gBkL/////D1QbIganIQBBACACIAOnaiIIRQ0AGiAEIAggAEHUgAEoAgARAAALIgQ2AjAgASABKQMoIAZ8NwMoIAUgAyAGfCIDVg0ACwsgASABKQMgIAV8NwMgDAgLIAEoAgRFDQcgAiABKQMYIgM3AxggASgCMCEAIAJBADYCMCACIAM3AyAgAiAANgIsIAIgAikDAELsAYQ3AwAMBwsgA0IIWgR+IAIgASgCCDYCACACIAEoAgw2AgRCCAVCfwshBQwGCyABEAYMBQtCfyEFIAApAxgiA0J/VwRAIAFBCGoiAQRAIAEgACgCDDYCACABIAAoAhA2AgQLDAULIAdBfzYCGCAHQo+AgICAAjcDECAHQoyAgIDQATcDCCAHQomAgICgATcDACADQQggBxAkQn+FgyEFDAQLIANCD1gEQCABQQhqBEAgAUEANgIMIAFBEjYCCAsMAwsgAkUNAgJAIAAgAikDACACKAIIEBRBAE4EQCAAEDMiA0J/VQ0BCyABQQhqIgEEQCABIAAoAgw2AgAgASAAKAIQNgIECwwDCyABIAM3AyAMAwsgASkDICEFDAILIAFBCGoEQCABQQA2AgwgAUEcNgIICwtCfyEFCyAHQeAAaiQAIAULjAcCAn4CfyMAQRBrIgckAAJAAkACQAJAAkACQAJAAkACQAJAIAQOEQABAgMFBggICAgICAgIBwgECAsgAUJ/NwMgIAFBADoADyABQQA7AQwgAUIANwMYIAEoAqxAIAEoAqhAKAIMEQEArUIBfSEFDAgLQn8hBSABKAIADQdCACEFIANQDQcgAS0ADQ0HIAFBKGohBAJAA0ACQCAHIAMgBX03AwggASgCrEAgAiAFp2ogB0EIaiABKAKoQCgCHBEAACEIQgAgBykDCCAIQQJGGyAFfCEFAkACQAJAIAhBAWsOAwADAQILIAFBAToADSABKQMgIgNCf1cEQCABBEAgAUEANgIEIAFBFDYCAAsMBQsgAS0ADkUNBCADIAVWDQQgASADNwMYIAFBAToADyACIAQgA6cQBxogASkDGCEFDAwLIAEtAAwNAyAAIARCgMAAEBEiBkJ/VwRAIAEEQCABIAAoAgw2AgAgASAAKAIQNgIECwwECyAGUARAIAFBAToADCABKAKsQCABKAKoQCgCGBEDACABKQMgQn9VDQEgAUIANwMgDAELAkAgASkDIEIAWQRAIAFBADoADgwBCyABIAY3AyALIAEoAqxAIAQgBiABKAKoQCgCFBEPABoLIAMgBVYNAQwCCwsgASgCAA0AIAEEQCABQQA2AgQgAUEUNgIACwsgBVBFBEAgAUEAOgAOIAEgASkDGCAFfDcDGAwIC0J/QgAgASgCABshBQwHCyABKAKsQCABKAKoQCgCEBEBAK1CAX0hBQwGCyABLQAQBEAgAS0ADQRAIAIgAS0ADwR/QQAFQQggASgCFCIAIABBfUsbCzsBMCACIAEpAxg3AyAgAiACKQMAQsgAhDcDAAwHCyACIAIpAwBCt////w+DNwMADAYLIAJBADsBMCACKQMAIQMgAS0ADQRAIAEpAxghBSACIANCxACENwMAIAIgBTcDGEIAIQUMBgsgAiADQrv///8Pg0LAAIQ3AwAMBQsgAS0ADw0EIAEoAqxAIAEoAqhAKAIIEQEArCEFDAQLIANCCFoEfiACIAEoAgA2AgAgAiABKAIENgIEQggFQn8LIQUMAwsgAUUNAiABKAKsQCABKAKoQCgCBBEDACABEDEgARAGDAILIAdBfzYCAEEQIAcQJEI/hCEFDAELIAEEQCABQQA2AgQgAUEUNgIAC0J/IQULIAdBEGokACAFC2MAQcgAEAkiAEUEQEGEhAEoAgAhASACBEAgAiABNgIEIAJBATYCAAsgAA8LIABBADoADCAAQQA6AAQgACACNgIAIABBADYCOCAAQgA3AzAgACABQQkgAUEBa0EJSRs2AgggAAu3fAIefwZ+IAIpAwAhIiAAIAE2AhwgACAiQv////8PICJC/////w9UGz4CICAAQRBqIQECfyAALQAEBEACfyAALQAMQQJ0IQpBfiEEAkACQAJAIAEiBUUNACAFKAIgRQ0AIAUoAiRFDQAgBSgCHCIDRQ0AIAMoAgAgBUcNAAJAAkAgAygCICIGQTlrDjkBAgICAgICAgICAgIBAgICAQICAgICAgICAgICAgICAgICAQICAgICAgICAgICAQICAgICAgICAgEACyAGQZoFRg0AIAZBKkcNAQsgCkEFSw0AAkACQCAFKAIMRQ0AIAUoAgQiAQRAIAUoAgBFDQELIAZBmgVHDQEgCkEERg0BCyAFQeDAACgCADYCGEF+DAQLIAUoAhBFDQEgAygCJCEEIAMgCjYCJAJAIAMoAhAEQCADEDACQCAFKAIQIgYgAygCECIIIAYgCEkbIgFFDQAgBSgCDCADKAIIIAEQBxogBSAFKAIMIAFqNgIMIAMgAygCCCABajYCCCAFIAUoAhQgAWo2AhQgBSAFKAIQIAFrIgY2AhAgAyADKAIQIAFrIgg2AhAgCA0AIAMgAygCBDYCCEEAIQgLIAYEQCADKAIgIQYMAgsMBAsgAQ0AIApBAXRBd0EAIApBBEsbaiAEQQF0QXdBACAEQQRKG2pKDQAgCkEERg0ADAILAkACQAJAAkACQCAGQSpHBEAgBkGaBUcNASAFKAIERQ0DDAcLIAMoAhRFBEAgA0HxADYCIAwCCyADKAI0QQx0QYDwAWshBAJAIAMoAowBQQJODQAgAygCiAEiAUEBTA0AIAFBBUwEQCAEQcAAciEEDAELQYABQcABIAFBBkYbIARyIQQLIAMoAgQgCGogBEEgciAEIAMoAmgbIgFBH3AgAXJBH3NBCHQgAUGA/gNxQQh2cjsAACADIAMoAhBBAmoiATYCECADKAJoBEAgAygCBCABaiAFKAIwIgFBGHQgAUEIdEGAgPwHcXIgAUEIdkGA/gNxIAFBGHZycjYAACADIAMoAhBBBGo2AhALIAVBATYCMCADQfEANgIgIAUQCiADKAIQDQcgAygCICEGCwJAAkACQAJAIAZBOUYEfyADQaABakHkgAEoAgARAQAaIAMgAygCECIBQQFqNgIQIAEgAygCBGpBHzoAACADIAMoAhAiAUEBajYCECABIAMoAgRqQYsBOgAAIAMgAygCECIBQQFqNgIQIAEgAygCBGpBCDoAAAJAIAMoAhwiAUUEQCADKAIEIAMoAhBqQQA2AAAgAyADKAIQIgFBBWo2AhAgASADKAIEakEAOgAEQQIhBCADKAKIASIBQQlHBEBBBCABQQJIQQJ0IAMoAowBQQFKGyEECyADIAMoAhAiAUEBajYCECABIAMoAgRqIAQ6AAAgAyADKAIQIgFBAWo2AhAgASADKAIEakEDOgAAIANB8QA2AiAgBRAKIAMoAhBFDQEMDQsgASgCJCELIAEoAhwhCSABKAIQIQggASgCLCENIAEoAgAhBiADIAMoAhAiAUEBajYCEEECIQQgASADKAIEaiANQQBHQQF0IAZBAEdyIAhBAEdBAnRyIAlBAEdBA3RyIAtBAEdBBHRyOgAAIAMoAgQgAygCEGogAygCHCgCBDYAACADIAMoAhAiDUEEaiIGNgIQIAMoAogBIgFBCUcEQEEEIAFBAkhBAnQgAygCjAFBAUobIQQLIAMgDUEFajYCECADKAIEIAZqIAQ6AAAgAygCHCgCDCEEIAMgAygCECIBQQFqNgIQIAEgAygCBGogBDoAACADKAIcIgEoAhAEfyADKAIEIAMoAhBqIAEoAhQ7AAAgAyADKAIQQQJqNgIQIAMoAhwFIAELKAIsBEAgBQJ/IAUoAjAhBiADKAIQIQRBACADKAIEIgFFDQAaIAYgASAEQdSAASgCABEAAAs2AjALIANBxQA2AiAgA0EANgIYDAILIAMoAiAFIAYLQcUAaw4jAAQEBAEEBAQEBAQEBAQEBAQEBAQEBAIEBAQEBAQEBAQEBAMECyADKAIcIgEoAhAiBgRAIAMoAgwiCCADKAIQIgQgAS8BFCADKAIYIg1rIglqSQRAA0AgAygCBCAEaiAGIA1qIAggBGsiCBAHGiADIAMoAgwiDTYCEAJAIAMoAhwoAixFDQAgBCANTw0AIAUCfyAFKAIwIQZBACADKAIEIARqIgFFDQAaIAYgASANIARrQdSAASgCABEAAAs2AjALIAMgAygCGCAIajYCGCAFKAIcIgYQMAJAIAUoAhAiBCAGKAIQIgEgASAESxsiAUUNACAFKAIMIAYoAgggARAHGiAFIAUoAgwgAWo2AgwgBiAGKAIIIAFqNgIIIAUgBSgCFCABajYCFCAFIAUoAhAgAWs2AhAgBiAGKAIQIAFrIgE2AhAgAQ0AIAYgBigCBDYCCAsgAygCEA0MIAMoAhghDSADKAIcKAIQIQZBACEEIAkgCGsiCSADKAIMIghLDQALCyADKAIEIARqIAYgDWogCRAHGiADIAMoAhAgCWoiDTYCEAJAIAMoAhwoAixFDQAgBCANTw0AIAUCfyAFKAIwIQZBACADKAIEIARqIgFFDQAaIAYgASANIARrQdSAASgCABEAAAs2AjALIANBADYCGAsgA0HJADYCIAsgAygCHCgCHARAIAMoAhAiBCEJA0ACQCAEIAMoAgxHDQACQCADKAIcKAIsRQ0AIAQgCU0NACAFAn8gBSgCMCEGQQAgAygCBCAJaiIBRQ0AGiAGIAEgBCAJa0HUgAEoAgARAAALNgIwCyAFKAIcIgYQMAJAIAUoAhAiBCAGKAIQIgEgASAESxsiAUUNACAFKAIMIAYoAgggARAHGiAFIAUoAgwgAWo2AgwgBiAGKAIIIAFqNgIIIAUgBSgCFCABajYCFCAFIAUoAhAgAWs2AhAgBiAGKAIQIAFrIgE2AhAgAQ0AIAYgBigCBDYCCAtBACEEQQAhCSADKAIQRQ0ADAsLIAMoAhwoAhwhBiADIAMoAhgiAUEBajYCGCABIAZqLQAAIQEgAyAEQQFqNgIQIAMoAgQgBGogAToAACABBEAgAygCECEEDAELCwJAIAMoAhwoAixFDQAgAygCECIGIAlNDQAgBQJ/IAUoAjAhBEEAIAMoAgQgCWoiAUUNABogBCABIAYgCWtB1IABKAIAEQAACzYCMAsgA0EANgIYCyADQdsANgIgCwJAIAMoAhwoAiRFDQAgAygCECIEIQkDQAJAIAQgAygCDEcNAAJAIAMoAhwoAixFDQAgBCAJTQ0AIAUCfyAFKAIwIQZBACADKAIEIAlqIgFFDQAaIAYgASAEIAlrQdSAASgCABEAAAs2AjALIAUoAhwiBhAwAkAgBSgCECIEIAYoAhAiASABIARLGyIBRQ0AIAUoAgwgBigCCCABEAcaIAUgBSgCDCABajYCDCAGIAYoAgggAWo2AgggBSAFKAIUIAFqNgIUIAUgBSgCECABazYCECAGIAYoAhAgAWsiATYCECABDQAgBiAGKAIENgIIC0EAIQRBACEJIAMoAhBFDQAMCgsgAygCHCgCJCEGIAMgAygCGCIBQQFqNgIYIAEgBmotAAAhASADIARBAWo2AhAgAygCBCAEaiABOgAAIAEEQCADKAIQIQQMAQsLIAMoAhwoAixFDQAgAygCECIGIAlNDQAgBQJ/IAUoAjAhBEEAIAMoAgQgCWoiAUUNABogBCABIAYgCWtB1IABKAIAEQAACzYCMAsgA0HnADYCIAsCQCADKAIcKAIsBEAgAygCDCADKAIQIgFBAmpJBH8gBRAKIAMoAhANAkEABSABCyADKAIEaiAFKAIwOwAAIAMgAygCEEECajYCECADQaABakHkgAEoAgARAQAaCyADQfEANgIgIAUQCiADKAIQRQ0BDAcLDAYLIAUoAgQNAQsgAygCPA0AIApFDQEgAygCIEGaBUYNAQsCfyADKAKIASIBRQRAIAMgChCFAQwBCwJAAkACQCADKAKMAUECaw4CAAECCwJ/AkADQAJAAkAgAygCPA0AIAMQLyADKAI8DQAgCg0BQQAMBAsgAygCSCADKAJoai0AACEEIAMgAygC8C0iAUEBajYC8C0gASADKALsLWpBADoAACADIAMoAvAtIgFBAWo2AvAtIAEgAygC7C1qQQA6AAAgAyADKALwLSIBQQFqNgLwLSABIAMoAuwtaiAEOgAAIAMgBEECdGoiASABLwHkAUEBajsB5AEgAyADKAI8QQFrNgI8IAMgAygCaEEBaiIBNgJoIAMoAvAtIAMoAvQtRw0BQQAhBCADIAMoAlgiBkEATgR/IAMoAkggBmoFQQALIAEgBmtBABAPIAMgAygCaDYCWCADKAIAEAogAygCACgCEA0BDAILCyADQQA2AoQuIApBBEYEQCADIAMoAlgiAUEATgR/IAMoAkggAWoFQQALIAMoAmggAWtBARAPIAMgAygCaDYCWCADKAIAEApBA0ECIAMoAgAoAhAbDAILIAMoAvAtBEBBACEEIAMgAygCWCIBQQBOBH8gAygCSCABagVBAAsgAygCaCABa0EAEA8gAyADKAJoNgJYIAMoAgAQCiADKAIAKAIQRQ0BC0EBIQQLIAQLDAILAn8CQANAAkACQAJAAkACQCADKAI8Ig1BggJLDQAgAxAvAkAgAygCPCINQYICSw0AIAoNAEEADAgLIA1FDQQgDUECSw0AIAMoAmghCAwBCyADKAJoIghFBEBBACEIDAELIAMoAkggCGoiAUEBayIELQAAIgYgAS0AAEcNACAGIAQtAAJHDQAgBEEDaiEEQQAhCQJAA0AgBiAELQAARw0BIAQtAAEgBkcEQCAJQQFyIQkMAgsgBC0AAiAGRwRAIAlBAnIhCQwCCyAELQADIAZHBEAgCUEDciEJDAILIAQtAAQgBkcEQCAJQQRyIQkMAgsgBC0ABSAGRwRAIAlBBXIhCQwCCyAELQAGIAZHBEAgCUEGciEJDAILIAQtAAcgBkcEQCAJQQdyIQkMAgsgBEEIaiEEIAlB+AFJIQEgCUEIaiEJIAENAAtBgAIhCQtBggIhBCANIAlBAmoiASABIA1LGyIBQYECSw0BIAEiBEECSw0BCyADKAJIIAhqLQAAIQQgAyADKALwLSIBQQFqNgLwLSABIAMoAuwtakEAOgAAIAMgAygC8C0iAUEBajYC8C0gASADKALsLWpBADoAACADIAMoAvAtIgFBAWo2AvAtIAEgAygC7C1qIAQ6AAAgAyAEQQJ0aiIBIAEvAeQBQQFqOwHkASADIAMoAjxBAWs2AjwgAyADKAJoQQFqIgQ2AmgMAQsgAyADKALwLSIBQQFqNgLwLSABIAMoAuwtakEBOgAAIAMgAygC8C0iAUEBajYC8C0gASADKALsLWpBADoAACADIAMoAvAtIgFBAWo2AvAtIAEgAygC7C1qIARBA2s6AAAgAyADKAKALkEBajYCgC4gBEH9zgBqLQAAQQJ0IANqQegJaiIBIAEvAQBBAWo7AQAgA0GAywAtAABBAnRqQdgTaiIBIAEvAQBBAWo7AQAgAyADKAI8IARrNgI8IAMgAygCaCAEaiIENgJoCyADKALwLSADKAL0LUcNAUEAIQggAyADKAJYIgFBAE4EfyADKAJIIAFqBUEACyAEIAFrQQAQDyADIAMoAmg2AlggAygCABAKIAMoAgAoAhANAQwCCwsgA0EANgKELiAKQQRGBEAgAyADKAJYIgFBAE4EfyADKAJIIAFqBUEACyADKAJoIAFrQQEQDyADIAMoAmg2AlggAygCABAKQQNBAiADKAIAKAIQGwwCCyADKALwLQRAQQAhCCADIAMoAlgiAUEATgR/IAMoAkggAWoFQQALIAMoAmggAWtBABAPIAMgAygCaDYCWCADKAIAEAogAygCACgCEEUNAQtBASEICyAICwwBCyADIAogAUEMbEG42ABqKAIAEQIACyIBQX5xQQJGBEAgA0GaBTYCIAsgAUF9cUUEQEEAIQQgBSgCEA0CDAQLIAFBAUcNAAJAAkACQCAKQQFrDgUAAQEBAgELIAMpA5guISICfwJ+IAMoAqAuIgFBA2oiCUE/TQRAQgIgAa2GICKEDAELIAFBwABGBEAgAygCBCADKAIQaiAiNwAAIAMgAygCEEEIajYCEEICISJBCgwCCyADKAIEIAMoAhBqQgIgAa2GICKENwAAIAMgAygCEEEIajYCECABQT1rIQlCAkHAACABa62ICyEiIAlBB2ogCUE5SQ0AGiADKAIEIAMoAhBqICI3AAAgAyADKAIQQQhqNgIQQgAhIiAJQTlrCyEBIAMgIjcDmC4gAyABNgKgLiADEDAMAQsgA0EAQQBBABA5IApBA0cNACADKAJQQQBBgIAIEBkgAygCPA0AIANBADYChC4gA0EANgJYIANBADYCaAsgBRAKIAUoAhANAAwDC0EAIQQgCkEERw0AAkACfwJAAkAgAygCFEEBaw4CAQADCyAFIANBoAFqQeCAASgCABEBACIBNgIwIAMoAgQgAygCEGogATYAACADIAMoAhBBBGoiATYCECADKAIEIAFqIQQgBSgCCAwBCyADKAIEIAMoAhBqIQQgBSgCMCIBQRh0IAFBCHRBgID8B3FyIAFBCHZBgP4DcSABQRh2cnILIQEgBCABNgAAIAMgAygCEEEEajYCEAsgBRAKIAMoAhQiAUEBTgRAIANBACABazYCFAsgAygCEEUhBAsgBAwCCyAFQezAACgCADYCGEF7DAELIANBfzYCJEEACwwBCyMAQRBrIhQkAEF+IRcCQCABIgxFDQAgDCgCIEUNACAMKAIkRQ0AIAwoAhwiB0UNACAHKAIAIAxHDQAgBygCBCIIQbT+AGtBH0sNACAMKAIMIhBFDQAgDCgCACIBRQRAIAwoAgQNAQsgCEG//gBGBEAgB0HA/gA2AgRBwP4AIQgLIAdBpAFqIR8gB0G8BmohGSAHQbwBaiEcIAdBoAFqIR0gB0G4AWohGiAHQfwKaiEYIAdBQGshHiAHKAKIASEFIAwoAgQiICEGIAcoAoQBIQogDCgCECIPIRYCfwJAAkACQANAAkBBfSEEQQEhCQJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIAhBtP4Aaw4fBwYICQolJicoBSwtLQsZGgQMAjIzATUANw0OAzlISUwLIAcoApQBIQMgASEEIAYhCAw1CyAHKAKUASEDIAEhBCAGIQgMMgsgBygCtAEhCAwuCyAHKAIMIQgMQQsgBUEOTw0pIAZFDUEgBUEIaiEIIAFBAWohBCAGQQFrIQkgAS0AACAFdCAKaiEKIAVBBkkNDCAEIQEgCSEGIAghBQwpCyAFQSBPDSUgBkUNQCABQQFqIQQgBkEBayEIIAEtAAAgBXQgCmohCiAFQRhJDQ0gBCEBIAghBgwlCyAFQRBPDRUgBkUNPyAFQQhqIQggAUEBaiEEIAZBAWshCSABLQAAIAV0IApqIQogBUEISQ0NIAQhASAJIQYgCCEFDBULIAcoAgwiC0UNByAFQRBPDSIgBkUNPiAFQQhqIQggAUEBaiEEIAZBAWshCSABLQAAIAV0IApqIQogBUEISQ0NIAQhASAJIQYgCCEFDCILIAVBH0sNFQwUCyAFQQ9LDRYMFQsgBygCFCIEQYAIcUUEQCAFIQgMFwsgCiEIIAVBD0sNGAwXCyAKIAVBB3F2IQogBUF4cSIFQR9LDQwgBkUNOiAFQQhqIQggAUEBaiEEIAZBAWshCSABLQAAIAV0IApqIQogBUEYSQ0GIAQhASAJIQYgCCEFDAwLIAcoArQBIgggBygCqAEiC08NIwwiCyAPRQ0qIBAgBygCjAE6AAAgB0HI/gA2AgQgD0EBayEPIBBBAWohECAHKAIEIQgMOQsgBygCDCIDRQRAQQAhCAwJCyAFQR9LDQcgBkUNNyAFQQhqIQggAUEBaiEEIAZBAWshCSABLQAAIAV0IApqIQogBUEYSQ0BIAQhASAJIQYgCCEFDAcLIAdBwP4ANgIEDCoLIAlFBEAgBCEBQQAhBiAIIQUgDSEEDDgLIAVBEGohCSABQQJqIQQgBkECayELIAEtAAEgCHQgCmohCiAFQQ9LBEAgBCEBIAshBiAJIQUMBgsgC0UEQCAEIQFBACEGIAkhBSANIQQMOAsgBUEYaiEIIAFBA2ohBCAGQQNrIQsgAS0AAiAJdCAKaiEKIAVBB0sEQCAEIQEgCyEGIAghBQwGCyALRQRAIAQhAUEAIQYgCCEFIA0hBAw4CyAFQSBqIQUgBkEEayEGIAEtAAMgCHQgCmohCiABQQRqIQEMBQsgCUUEQCAEIQFBACEGIAghBSANIQQMNwsgBUEQaiEFIAZBAmshBiABLQABIAh0IApqIQogAUECaiEBDBwLIAlFBEAgBCEBQQAhBiAIIQUgDSEEDDYLIAVBEGohCSABQQJqIQQgBkECayELIAEtAAEgCHQgCmohCiAFQQ9LBEAgBCEBIAshBiAJIQUMBgsgC0UEQCAEIQFBACEGIAkhBSANIQQMNgsgBUEYaiEIIAFBA2ohBCAGQQNrIQsgAS0AAiAJdCAKaiEKIAUEQCAEIQEgCyEGIAghBQwGCyALRQRAIAQhAUEAIQYgCCEFIA0hBAw2CyAFQSBqIQUgBkEEayEGIAEtAAMgCHQgCmohCiABQQRqIQEMBQsgBUEIaiEJIAhFBEAgBCEBQQAhBiAJIQUgDSEEDDULIAFBAmohBCAGQQJrIQggAS0AASAJdCAKaiEKIAVBD0sEQCAEIQEgCCEGDBgLIAVBEGohCSAIRQRAIAQhAUEAIQYgCSEFIA0hBAw1CyABQQNqIQQgBkEDayEIIAEtAAIgCXQgCmohCiAFQQdLBEAgBCEBIAghBgwYCyAFQRhqIQUgCEUEQCAEIQFBACEGIA0hBAw1CyAGQQRrIQYgAS0AAyAFdCAKaiEKIAFBBGohAQwXCyAJDQYgBCEBQQAhBiAIIQUgDSEEDDMLIAlFBEAgBCEBQQAhBiAIIQUgDSEEDDMLIAVBEGohBSAGQQJrIQYgAS0AASAIdCAKaiEKIAFBAmohAQwUCyAMIBYgD2siCSAMKAIUajYCFCAHIAcoAiAgCWo2AiACQCADQQRxRQ0AIAkEQAJAIBAgCWshBCAMKAIcIggoAhQEQCAIQUBrIAQgCUEAQdiAASgCABEIAAwBCyAIIAgoAhwgBCAJQcCAASgCABEAACIENgIcIAwgBDYCMAsLIAcoAhRFDQAgByAeQeCAASgCABEBACIENgIcIAwgBDYCMAsCQCAHKAIMIghBBHFFDQAgBygCHCAKIApBCHRBgID8B3EgCkEYdHIgCkEIdkGA/gNxIApBGHZyciAHKAIUG0YNACAHQdH+ADYCBCAMQaQMNgIYIA8hFiAHKAIEIQgMMQtBACEKQQAhBSAPIRYLIAdBz/4ANgIEDC0LIApB//8DcSIEIApBf3NBEHZHBEAgB0HR/gA2AgQgDEGOCjYCGCAHKAIEIQgMLwsgB0HC/gA2AgQgByAENgKMAUEAIQpBACEFCyAHQcP+ADYCBAsgBygCjAEiBARAIA8gBiAEIAQgBksbIgQgBCAPSxsiCEUNHiAQIAEgCBAHIQQgByAHKAKMASAIazYCjAEgBCAIaiEQIA8gCGshDyABIAhqIQEgBiAIayEGIAcoAgQhCAwtCyAHQb/+ADYCBCAHKAIEIQgMLAsgBUEQaiEFIAZBAmshBiABLQABIAh0IApqIQogAUECaiEBCyAHIAo2AhQgCkH/AXFBCEcEQCAHQdH+ADYCBCAMQYIPNgIYIAcoAgQhCAwrCyAKQYDAA3EEQCAHQdH+ADYCBCAMQY0JNgIYIAcoAgQhCAwrCyAHKAIkIgQEQCAEIApBCHZBAXE2AgALAkAgCkGABHFFDQAgBy0ADEEEcUUNACAUIAo7AAwgBwJ/IAcoAhwhBUEAIBRBDGoiBEUNABogBSAEQQJB1IABKAIAEQAACzYCHAsgB0G2/gA2AgRBACEFQQAhCgsgBkUNKCABQQFqIQQgBkEBayEIIAEtAAAgBXQgCmohCiAFQRhPBEAgBCEBIAghBgwBCyAFQQhqIQkgCEUEQCAEIQFBACEGIAkhBSANIQQMKwsgAUECaiEEIAZBAmshCCABLQABIAl0IApqIQogBUEPSwRAIAQhASAIIQYMAQsgBUEQaiEJIAhFBEAgBCEBQQAhBiAJIQUgDSEEDCsLIAFBA2ohBCAGQQNrIQggAS0AAiAJdCAKaiEKIAVBB0sEQCAEIQEgCCEGDAELIAVBGGohBSAIRQRAIAQhAUEAIQYgDSEEDCsLIAZBBGshBiABLQADIAV0IApqIQogAUEEaiEBCyAHKAIkIgQEQCAEIAo2AgQLAkAgBy0AFUECcUUNACAHLQAMQQRxRQ0AIBQgCjYADCAHAn8gBygCHCEFQQAgFEEMaiIERQ0AGiAFIARBBEHUgAEoAgARAAALNgIcCyAHQbf+ADYCBEEAIQVBACEKCyAGRQ0mIAFBAWohBCAGQQFrIQggAS0AACAFdCAKaiEKIAVBCE8EQCAEIQEgCCEGDAELIAVBCGohBSAIRQRAIAQhAUEAIQYgDSEEDCkLIAZBAmshBiABLQABIAV0IApqIQogAUECaiEBCyAHKAIkIgQEQCAEIApBCHY2AgwgBCAKQf8BcTYCCAsCQCAHLQAVQQJxRQ0AIActAAxBBHFFDQAgFCAKOwAMIAcCfyAHKAIcIQVBACAUQQxqIgRFDQAaIAUgBEECQdSAASgCABEAAAs2AhwLIAdBuP4ANgIEQQAhCEEAIQVBACEKIAcoAhQiBEGACHENAQsgBygCJCIEBEAgBEEANgIQCyAIIQUMAgsgBkUEQEEAIQYgCCEKIA0hBAwmCyABQQFqIQkgBkEBayELIAEtAAAgBXQgCGohCiAFQQhPBEAgCSEBIAshBgwBCyAFQQhqIQUgC0UEQCAJIQFBACEGIA0hBAwmCyAGQQJrIQYgAS0AASAFdCAKaiEKIAFBAmohAQsgByAKQf//A3EiCDYCjAEgBygCJCIFBEAgBSAINgIUC0EAIQUCQCAEQYAEcUUNACAHLQAMQQRxRQ0AIBQgCjsADCAHAn8gBygCHCEIQQAgFEEMaiIERQ0AGiAIIARBAkHUgAEoAgARAAALNgIcC0EAIQoLIAdBuf4ANgIECyAHKAIUIglBgAhxBEAgBiAHKAKMASIIIAYgCEkbIg4EQAJAIAcoAiQiA0UNACADKAIQIgRFDQAgAygCGCILIAMoAhQgCGsiCE0NACAEIAhqIAEgCyAIayAOIAggDmogC0sbEAcaIAcoAhQhCQsCQCAJQYAEcUUNACAHLQAMQQRxRQ0AIAcCfyAHKAIcIQRBACABRQ0AGiAEIAEgDkHUgAEoAgARAAALNgIcCyAHIAcoAowBIA5rIgg2AowBIAYgDmshBiABIA5qIQELIAgNEwsgB0G6/gA2AgQgB0EANgKMAQsCQCAHLQAVQQhxBEBBACEIIAZFDQQDQCABIAhqLQAAIQMCQCAHKAIkIgtFDQAgCygCHCIERQ0AIAcoAowBIgkgCygCIE8NACAHIAlBAWo2AowBIAQgCWogAzoAAAsgA0EAIAYgCEEBaiIISxsNAAsCQCAHLQAVQQJxRQ0AIActAAxBBHFFDQAgBwJ/IAcoAhwhBEEAIAFFDQAaIAQgASAIQdSAASgCABEAAAs2AhwLIAEgCGohASAGIAhrIQYgA0UNAQwTCyAHKAIkIgRFDQAgBEEANgIcCyAHQbv+ADYCBCAHQQA2AowBCwJAIActABVBEHEEQEEAIQggBkUNAwNAIAEgCGotAAAhAwJAIAcoAiQiC0UNACALKAIkIgRFDQAgBygCjAEiCSALKAIoTw0AIAcgCUEBajYCjAEgBCAJaiADOgAACyADQQAgBiAIQQFqIghLGw0ACwJAIActABVBAnFFDQAgBy0ADEEEcUUNACAHAn8gBygCHCEEQQAgAUUNABogBCABIAhB1IABKAIAEQAACzYCHAsgASAIaiEBIAYgCGshBiADRQ0BDBILIAcoAiQiBEUNACAEQQA2AiQLIAdBvP4ANgIECyAHKAIUIgtBgARxBEACQCAFQQ9LDQAgBkUNHyAFQQhqIQggAUEBaiEEIAZBAWshCSABLQAAIAV0IApqIQogBUEITwRAIAQhASAJIQYgCCEFDAELIAlFBEAgBCEBQQAhBiAIIQUgDSEEDCILIAVBEGohBSAGQQJrIQYgAS0AASAIdCAKaiEKIAFBAmohAQsCQCAHLQAMQQRxRQ0AIAogBy8BHEYNACAHQdH+ADYCBCAMQdcMNgIYIAcoAgQhCAwgC0EAIQpBACEFCyAHKAIkIgQEQCAEQQE2AjAgBCALQQl2QQFxNgIsCwJAIActAAxBBHFFDQAgC0UNACAHIB5B5IABKAIAEQEAIgQ2AhwgDCAENgIwCyAHQb/+ADYCBCAHKAIEIQgMHgtBACEGDA4LAkAgC0ECcUUNACAKQZ+WAkcNACAHKAIoRQRAIAdBDzYCKAtBACEKIAdBADYCHCAUQZ+WAjsADCAHIBRBDGoiBAR/QQAgBEECQdSAASgCABEAAAVBAAs2AhwgB0G1/gA2AgRBACEFIAcoAgQhCAwdCyAHKAIkIgQEQCAEQX82AjALAkAgC0EBcQRAIApBCHRBgP4DcSAKQQh2akEfcEUNAQsgB0HR/gA2AgQgDEH2CzYCGCAHKAIEIQgMHQsgCkEPcUEIRwRAIAdB0f4ANgIEIAxBgg82AhggBygCBCEIDB0LIApBBHYiBEEPcSIJQQhqIQsgCUEHTUEAIAcoAigiCAR/IAgFIAcgCzYCKCALCyALTxtFBEAgBUEEayEFIAdB0f4ANgIEIAxB+gw2AhggBCEKIAcoAgQhCAwdCyAHQQE2AhxBACEFIAdBADYCFCAHQYACIAl0NgIYIAxBATYCMCAHQb3+AEG//gAgCkGAwABxGzYCBEEAIQogBygCBCEIDBwLIAcgCkEIdEGAgPwHcSAKQRh0ciAKQQh2QYD+A3EgCkEYdnJyIgQ2AhwgDCAENgIwIAdBvv4ANgIEQQAhCkEAIQULIAcoAhBFBEAgDCAPNgIQIAwgEDYCDCAMIAY2AgQgDCABNgIAIAcgBTYCiAEgByAKNgKEAUECIRcMIAsgB0EBNgIcIAxBATYCMCAHQb/+ADYCBAsCfwJAIAcoAghFBEAgBUEDSQ0BIAUMAgsgB0HO/gA2AgQgCiAFQQdxdiEKIAVBeHEhBSAHKAIEIQgMGwsgBkUNGSAGQQFrIQYgAS0AACAFdCAKaiEKIAFBAWohASAFQQhqCyEEIAcgCkEBcTYCCAJAAkACQAJAAkAgCkEBdkEDcUEBaw4DAQIDAAsgB0HB/gA2AgQMAwsgB0Gw2wA2ApgBIAdCiYCAgNAANwOgASAHQbDrADYCnAEgB0HH/gA2AgQMAgsgB0HE/gA2AgQMAQsgB0HR/gA2AgQgDEHXDTYCGAsgBEEDayEFIApBA3YhCiAHKAIEIQgMGQsgByAKQR9xIghBgQJqNgKsASAHIApBBXZBH3EiBEEBajYCsAEgByAKQQp2QQ9xQQRqIgs2AqgBIAVBDmshBSAKQQ52IQogCEEdTUEAIARBHkkbRQRAIAdB0f4ANgIEIAxB6gk2AhggBygCBCEIDBkLIAdBxf4ANgIEQQAhCCAHQQA2ArQBCyAIIQQDQCAFQQJNBEAgBkUNGCAGQQFrIQYgAS0AACAFdCAKaiEKIAVBCGohBSABQQFqIQELIAcgBEEBaiIINgK0ASAHIARBAXRBsOwAai8BAEEBdGogCkEHcTsBvAEgBUEDayEFIApBA3YhCiALIAgiBEsNAAsLIAhBEk0EQEESIAhrIQ1BAyAIa0EDcSIEBEADQCAHIAhBAXRBsOwAai8BAEEBdGpBADsBvAEgCEEBaiEIIARBAWsiBA0ACwsgDUEDTwRAA0AgB0G8AWoiDSAIQQF0IgRBsOwAai8BAEEBdGpBADsBACANIARBsuwAai8BAEEBdGpBADsBACANIARBtOwAai8BAEEBdGpBADsBACANIARBtuwAai8BAEEBdGpBADsBACAIQQRqIghBE0cNAAsLIAdBEzYCtAELIAdBBzYCoAEgByAYNgKYASAHIBg2ArgBQQAhCEEAIBxBEyAaIB0gGRBOIg0EQCAHQdH+ADYCBCAMQfQINgIYIAcoAgQhCAwXCyAHQcb+ADYCBCAHQQA2ArQBQQAhDQsgBygCrAEiFSAHKAKwAWoiESAISwRAQX8gBygCoAF0QX9zIRIgBygCmAEhGwNAIAYhCSABIQsCQCAFIgMgGyAKIBJxIhNBAnRqLQABIg5PBEAgBSEEDAELA0AgCUUNDSALLQAAIAN0IQ4gC0EBaiELIAlBAWshCSADQQhqIgQhAyAEIBsgCiAOaiIKIBJxIhNBAnRqLQABIg5JDQALIAshASAJIQYLAkAgGyATQQJ0ai8BAiIFQQ9NBEAgByAIQQFqIgk2ArQBIAcgCEEBdGogBTsBvAEgBCAOayEFIAogDnYhCiAJIQgMAQsCfwJ/AkACQAJAIAVBEGsOAgABAgsgDkECaiIFIARLBEADQCAGRQ0bIAZBAWshBiABLQAAIAR0IApqIQogAUEBaiEBIARBCGoiBCAFSQ0ACwsgBCAOayEFIAogDnYhBCAIRQRAIAdB0f4ANgIEIAxBvAk2AhggBCEKIAcoAgQhCAwdCyAFQQJrIQUgBEECdiEKIARBA3FBA2ohCSAIQQF0IAdqLwG6AQwDCyAOQQNqIgUgBEsEQANAIAZFDRogBkEBayEGIAEtAAAgBHQgCmohCiABQQFqIQEgBEEIaiIEIAVJDQALCyAEIA5rQQNrIQUgCiAOdiIEQQN2IQogBEEHcUEDagwBCyAOQQdqIgUgBEsEQANAIAZFDRkgBkEBayEGIAEtAAAgBHQgCmohCiABQQFqIQEgBEEIaiIEIAVJDQALCyAEIA5rQQdrIQUgCiAOdiIEQQd2IQogBEH/AHFBC2oLIQlBAAshAyAIIAlqIBFLDRMgCUEBayEEIAlBA3EiCwRAA0AgByAIQQF0aiADOwG8ASAIQQFqIQggCUEBayEJIAtBAWsiCw0ACwsgBEEDTwRAA0AgByAIQQF0aiIEIAM7Ab4BIAQgAzsBvAEgBCADOwHAASAEIAM7AcIBIAhBBGohCCAJQQRrIgkNAAsLIAcgCDYCtAELIAggEUkNAAsLIAcvAbwFRQRAIAdB0f4ANgIEIAxB0Qs2AhggBygCBCEIDBYLIAdBCjYCoAEgByAYNgKYASAHIBg2ArgBQQEgHCAVIBogHSAZEE4iDQRAIAdB0f4ANgIEIAxB2Ag2AhggBygCBCEIDBYLIAdBCTYCpAEgByAHKAK4ATYCnAFBAiAHIAcoAqwBQQF0akG8AWogBygCsAEgGiAfIBkQTiINBEAgB0HR/gA2AgQgDEGmCTYCGCAHKAIEIQgMFgsgB0HH/gA2AgRBACENCyAHQcj+ADYCBAsCQCAGQQ9JDQAgD0GEAkkNACAMIA82AhAgDCAQNgIMIAwgBjYCBCAMIAE2AgAgByAFNgKIASAHIAo2AoQBIAwgFkHogAEoAgARBwAgBygCiAEhBSAHKAKEASEKIAwoAgQhBiAMKAIAIQEgDCgCECEPIAwoAgwhECAHKAIEQb/+AEcNByAHQX82ApBHIAcoAgQhCAwUCyAHQQA2ApBHIAUhCSAGIQggASEEAkAgBygCmAEiEiAKQX8gBygCoAF0QX9zIhVxIg5BAnRqLQABIgsgBU0EQCAFIQMMAQsDQCAIRQ0PIAQtAAAgCXQhCyAEQQFqIQQgCEEBayEIIAlBCGoiAyEJIAMgEiAKIAtqIgogFXEiDkECdGotAAEiC0kNAAsLIBIgDkECdGoiAS8BAiETAkBBACABLQAAIhEgEUHwAXEbRQRAIAshBgwBCyAIIQYgBCEBAkAgAyIFIAsgEiAKQX8gCyARanRBf3MiFXEgC3YgE2oiEUECdGotAAEiDmpPBEAgAyEJDAELA0AgBkUNDyABLQAAIAV0IQ4gAUEBaiEBIAZBAWshBiAFQQhqIgkhBSALIBIgCiAOaiIKIBVxIAt2IBNqIhFBAnRqLQABIg5qIAlLDQALIAEhBCAGIQgLIBIgEUECdGoiAS0AACERIAEvAQIhEyAHIAs2ApBHIAsgDmohBiAJIAtrIQMgCiALdiEKIA4hCwsgByAGNgKQRyAHIBNB//8DcTYCjAEgAyALayEFIAogC3YhCiARRQRAIAdBzf4ANgIEDBALIBFBIHEEQCAHQb/+ADYCBCAHQX82ApBHDBALIBFBwABxBEAgB0HR/gA2AgQgDEHQDjYCGAwQCyAHQcn+ADYCBCAHIBFBD3EiAzYClAELAkAgA0UEQCAHKAKMASELIAQhASAIIQYMAQsgBSEJIAghBiAEIQsCQCADIAVNBEAgBCEBDAELA0AgBkUNDSAGQQFrIQYgCy0AACAJdCAKaiEKIAtBAWoiASELIAlBCGoiCSADSQ0ACwsgByAHKAKQRyADajYCkEcgByAHKAKMASAKQX8gA3RBf3NxaiILNgKMASAJIANrIQUgCiADdiEKCyAHQcr+ADYCBCAHIAs2ApRHCyAFIQkgBiEIIAEhBAJAIAcoApwBIhIgCkF/IAcoAqQBdEF/cyIVcSIOQQJ0ai0AASIDIAVNBEAgBSELDAELA0AgCEUNCiAELQAAIAl0IQMgBEEBaiEEIAhBAWshCCAJQQhqIgshCSALIBIgAyAKaiIKIBVxIg5BAnRqLQABIgNJDQALCyASIA5BAnRqIgEvAQIhEwJAIAEtAAAiEUHwAXEEQCAHKAKQRyEGIAMhCQwBCyAIIQYgBCEBAkAgCyIFIAMgEiAKQX8gAyARanRBf3MiFXEgA3YgE2oiEUECdGotAAEiCWpPBEAgCyEODAELA0AgBkUNCiABLQAAIAV0IQkgAUEBaiEBIAZBAWshBiAFQQhqIg4hBSADIBIgCSAKaiIKIBVxIAN2IBNqIhFBAnRqLQABIglqIA5LDQALIAEhBCAGIQgLIBIgEUECdGoiAS0AACERIAEvAQIhEyAHIAcoApBHIANqIgY2ApBHIA4gA2shCyAKIAN2IQoLIAcgBiAJajYCkEcgCyAJayEFIAogCXYhCiARQcAAcQRAIAdB0f4ANgIEIAxB7A42AhggBCEBIAghBiAHKAIEIQgMEgsgB0HL/gA2AgQgByARQQ9xIgM2ApQBIAcgE0H//wNxNgKQAQsCQCADRQRAIAQhASAIIQYMAQsgBSEJIAghBiAEIQsCQCADIAVNBEAgBCEBDAELA0AgBkUNCCAGQQFrIQYgCy0AACAJdCAKaiEKIAtBAWoiASELIAlBCGoiCSADSQ0ACwsgByAHKAKQRyADajYCkEcgByAHKAKQASAKQX8gA3RBf3NxajYCkAEgCSADayEFIAogA3YhCgsgB0HM/gA2AgQLIA9FDQACfyAHKAKQASIIIBYgD2siBEsEQAJAIAggBGsiCCAHKAIwTQ0AIAcoAoxHRQ0AIAdB0f4ANgIEIAxBuQw2AhggBygCBCEIDBILAn8CQAJ/IAcoAjQiBCAISQRAIAcoAjggBygCLCAIIARrIghragwBCyAHKAI4IAQgCGtqCyILIBAgDyAQaiAQa0EBaqwiISAPIAcoAowBIgQgCCAEIAhJGyIEIAQgD0sbIgitIiIgISAiVBsiIqciCWoiBEkgCyAQT3ENACALIBBNIAkgC2ogEEtxDQAgECALIAkQBxogBAwBCyAQIAsgCyAQayIEIARBH3UiBGogBHMiCRAHIAlqIQQgIiAJrSIkfSIjUEUEQCAJIAtqIQkDQAJAICMgJCAjICRUGyIiQiBUBEAgIiEhDAELICIiIUIgfSImQgWIQgF8QgODIiVQRQRAA0AgBCAJKQAANwAAIAQgCSkAGDcAGCAEIAkpABA3ABAgBCAJKQAINwAIICFCIH0hISAJQSBqIQkgBEEgaiEEICVCAX0iJUIAUg0ACwsgJkLgAFQNAANAIAQgCSkAADcAACAEIAkpABg3ABggBCAJKQAQNwAQIAQgCSkACDcACCAEIAkpADg3ADggBCAJKQAwNwAwIAQgCSkAKDcAKCAEIAkpACA3ACAgBCAJKQBYNwBYIAQgCSkAUDcAUCAEIAkpAEg3AEggBCAJKQBANwBAIAQgCSkAYDcAYCAEIAkpAGg3AGggBCAJKQBwNwBwIAQgCSkAeDcAeCAJQYABaiEJIARBgAFqIQQgIUKAAX0iIUIfVg0ACwsgIUIQWgRAIAQgCSkAADcAACAEIAkpAAg3AAggIUIQfSEhIAlBEGohCSAEQRBqIQQLICFCCFoEQCAEIAkpAAA3AAAgIUIIfSEhIAlBCGohCSAEQQhqIQQLICFCBFoEQCAEIAkoAAA2AAAgIUIEfSEhIAlBBGohCSAEQQRqIQQLICFCAloEQCAEIAkvAAA7AAAgIUICfSEhIAlBAmohCSAEQQJqIQQLICMgIn0hIyAhUEUEQCAEIAktAAA6AAAgCUEBaiEJIARBAWohBAsgI0IAUg0ACwsgBAsMAQsgECAIIA8gBygCjAEiBCAEIA9LGyIIIA9ByIABKAIAEQQACyEQIAcgBygCjAEgCGsiBDYCjAEgDyAIayEPIAQNAiAHQcj+ADYCBCAHKAIEIQgMDwsgDSEJCyAJIQQMDgsgBygCBCEIDAwLIAEgBmohASAFIAZBA3RqIQUMCgsgBCAIaiEBIAUgCEEDdGohBQwJCyAEIAhqIQEgCyAIQQN0aiEFDAgLIAEgBmohASAFIAZBA3RqIQUMBwsgBCAIaiEBIAUgCEEDdGohBQwGCyAEIAhqIQEgAyAIQQN0aiEFDAULIAEgBmohASAFIAZBA3RqIQUMBAsgB0HR/gA2AgQgDEG8CTYCGCAHKAIEIQgMBAsgBCEBIAghBiAHKAIEIQgMAwtBACEGIAQhBSANIQQMAwsCQAJAIAhFBEAgCiEJDAELIAcoAhRFBEAgCiEJDAELAkAgBUEfSw0AIAZFDQMgBUEIaiEJIAFBAWohBCAGQQFrIQsgAS0AACAFdCAKaiEKIAVBGE8EQCAEIQEgCyEGIAkhBQwBCyALRQRAIAQhAUEAIQYgCSEFIA0hBAwGCyAFQRBqIQsgAUECaiEEIAZBAmshAyABLQABIAl0IApqIQogBUEPSwRAIAQhASADIQYgCyEFDAELIANFBEAgBCEBQQAhBiALIQUgDSEEDAYLIAVBGGohCSABQQNqIQQgBkEDayEDIAEtAAIgC3QgCmohCiAFQQdLBEAgBCEBIAMhBiAJIQUMAQsgA0UEQCAEIQFBACEGIAkhBSANIQQMBgsgBUEgaiEFIAZBBGshBiABLQADIAl0IApqIQogAUEEaiEBC0EAIQkgCEEEcQRAIAogBygCIEcNAgtBACEFCyAHQdD+ADYCBEEBIQQgCSEKDAMLIAdB0f4ANgIEIAxBjQw2AhggBygCBCEIDAELC0EAIQYgDSEECyAMIA82AhAgDCAQNgIMIAwgBjYCBCAMIAE2AgAgByAFNgKIASAHIAo2AoQBAkAgBygCLA0AIA8gFkYNAiAHKAIEIgFB0P4ASw0CIAFBzv4ASQ0ACwJ/IBYgD2shCiAHKAIMQQRxIQkCQAJAAkAgDCgCHCIDKAI4Ig1FBEBBASEIIAMgAygCACIBKAIgIAEoAiggAygCmEdBASADKAIodGpBARAoIg02AjggDUUNAQsgAygCLCIGRQRAIANCADcDMCADQQEgAygCKHQiBjYCLAsgBiAKTQRAAkAgCQRAAkAgBiAKTw0AIAogBmshBSAQIAprIQEgDCgCHCIGKAIUBEAgBkFAayABIAVBAEHYgAEoAgARCAAMAQsgBiAGKAIcIAEgBUHAgAEoAgARAAAiATYCHCAMIAE2AjALIAMoAiwiDUUNASAQIA1rIQUgAygCOCEBIAwoAhwiBigCFARAIAZBQGsgASAFIA1B3IABKAIAEQgADAILIAYgBigCHCABIAUgDUHEgAEoAgARBAAiATYCHCAMIAE2AjAMAQsgDSAQIAZrIAYQBxoLIANBADYCNCADIAMoAiw2AjBBAAwECyAKIAYgAygCNCIFayIBIAEgCksbIQsgECAKayEGIAUgDWohBQJAIAkEQAJAIAtFDQAgDCgCHCIBKAIUBEAgAUFAayAFIAYgC0HcgAEoAgARCAAMAQsgASABKAIcIAUgBiALQcSAASgCABEEACIBNgIcIAwgATYCMAsgCiALayIFRQ0BIBAgBWshBiADKAI4IQEgDCgCHCINKAIUBEAgDUFAayABIAYgBUHcgAEoAgARCAAMBQsgDSANKAIcIAEgBiAFQcSAASgCABEEACIBNgIcIAwgATYCMAwECyAFIAYgCxAHGiAKIAtrIgUNAgtBACEIIANBACADKAI0IAtqIgUgBSADKAIsIgFGGzYCNCABIAMoAjAiAU0NACADIAEgC2o2AjALIAgMAgsgAygCOCAQIAVrIAUQBxoLIAMgBTYCNCADIAMoAiw2AjBBAAtFBEAgDCgCECEPIAwoAgQhFyAHKAKIAQwDCyAHQdL+ADYCBAtBfCEXDAILIAYhFyAFCyEFIAwgICAXayIBIAwoAghqNgIIIAwgFiAPayIGIAwoAhRqNgIUIAcgBygCICAGajYCICAMIAcoAghBAEdBBnQgBWogBygCBCIFQb/+AEZBB3RqQYACIAVBwv4ARkEIdCAFQcf+AEYbajYCLCAEIARBeyAEGyABIAZyGyEXCyAUQRBqJAAgFwshASACIAIpAwAgADUCIH03AwACQAJAAkACQCABQQVqDgcBAgICAgMAAgtBAQ8LIAAoAhQNAEEDDwsgACgCACIABEAgACABNgIEIABBDTYCAAtBAiEBCyABCwkAIABBAToADAtEAAJAIAJC/////w9YBEAgACgCFEUNAQsgACgCACIABEAgAEEANgIEIABBEjYCAAtBAA8LIAAgATYCECAAIAI+AhRBAQu5AQEEfyAAQRBqIQECfyAALQAEBEAgARCEAQwBC0F+IQMCQCABRQ0AIAEoAiBFDQAgASgCJCIERQ0AIAEoAhwiAkUNACACKAIAIAFHDQAgAigCBEG0/gBrQR9LDQAgAigCOCIDBEAgBCABKAIoIAMQHiABKAIkIQQgASgCHCECCyAEIAEoAiggAhAeQQAhAyABQQA2AhwLIAMLIgEEQCAAKAIAIgAEQCAAIAE2AgQgAEENNgIACwsgAUUL0gwBBn8gAEIANwIQIABCADcCHCAAQRBqIQICfyAALQAEBEAgACgCCCEBQesMLQAAQTFGBH8Cf0F+IQMCQCACRQ0AIAJBADYCGCACKAIgIgRFBEAgAkEANgIoIAJBJzYCIEEnIQQLIAIoAiRFBEAgAkEoNgIkC0EGIAEgAUF/RhsiBUEASA0AIAVBCUoNAEF8IQMgBCACKAIoQQFB0C4QKCIBRQ0AIAIgATYCHCABIAI2AgAgAUEPNgI0IAFCgICAgKAFNwIcIAFBADYCFCABQYCAAjYCMCABQf//ATYCOCABIAIoAiAgAigCKEGAgAJBAhAoNgJIIAEgAigCICACKAIoIAEoAjBBAhAoIgM2AkwgA0EAIAEoAjBBAXQQGSACKAIgIAIoAihBgIAEQQIQKCEDIAFBgIACNgLoLSABQQA2AkAgASADNgJQIAEgAigCICACKAIoQYCAAkEEECgiAzYCBCABIAEoAugtIgRBAnQ2AgwCQAJAIAEoAkhFDQAgASgCTEUNACABKAJQRQ0AIAMNAQsgAUGaBTYCICACQejAACgCADYCGCACEIQBGkF8DAILIAFBADYCjAEgASAFNgKIASABQgA3AyggASADIARqNgLsLSABIARBA2xBA2s2AvQtQX4hAwJAIAJFDQAgAigCIEUNACACKAIkRQ0AIAIoAhwiAUUNACABKAIAIAJHDQACQAJAIAEoAiAiBEE5aw45AQICAgICAgICAgICAQICAgECAgICAgICAgICAgICAgICAgECAgICAgICAgICAgECAgICAgICAgIBAAsgBEGaBUYNACAEQSpHDQELIAJBAjYCLCACQQA2AgggAkIANwIUIAFBADYCECABIAEoAgQ2AgggASgCFCIDQX9MBEAgAUEAIANrIgM2AhQLIAFBOUEqIANBAkYbNgIgIAIgA0ECRgR/IAFBoAFqQeSAASgCABEBAAVBAQs2AjAgAUF+NgIkIAFBADYCoC4gAUIANwOYLiABQYgXakGg0wA2AgAgASABQcwVajYCgBcgAUH8FmpBjNMANgIAIAEgAUHYE2o2AvQWIAFB8BZqQfjSADYCACABIAFB5AFqNgLoFiABEIgBQQAhAwsgAw0AIAIoAhwiAiACKAIwQQF0NgJEQQAhAyACKAJQQQBBgIAIEBkgAiACKAKIASIEQQxsIgFBtNgAai8BADYClAEgAiABQbDYAGovAQA2ApABIAIgAUGy2ABqLwEANgJ4IAIgAUG22ABqLwEANgJ0QfiAASgCACEFQeyAASgCACEGQYCBASgCACEBIAJCADcCbCACQgA3AmQgAkEANgI8IAJBADYChC4gAkIANwJUIAJBKSABIARBCUYiARs2AnwgAkEqIAYgARs2AoABIAJBKyAFIAEbNgKEAQsgAwsFQXoLDAELAn9BekHrDC0AAEExRw0AGkF+IAJFDQAaIAJBADYCGCACKAIgIgNFBEAgAkEANgIoIAJBJzYCIEEnIQMLIAIoAiRFBEAgAkEoNgIkC0F8IAMgAigCKEEBQaDHABAoIgRFDQAaIAIgBDYCHCAEQQA2AjggBCACNgIAIARBtP4ANgIEIARBzIABKAIAEQkANgKYR0F+IQMCQCACRQ0AIAIoAiBFDQAgAigCJCIFRQ0AIAIoAhwiAUUNACABKAIAIAJHDQAgASgCBEG0/gBrQR9LDQACQAJAIAEoAjgiBgRAIAEoAihBD0cNAQsgAUEPNgIoIAFBADYCDAwBCyAFIAIoAiggBhAeIAFBADYCOCACKAIgIQUgAUEPNgIoIAFBADYCDCAFRQ0BCyACKAIkRQ0AIAIoAhwiAUUNACABKAIAIAJHDQAgASgCBEG0/gBrQR9LDQBBACEDIAFBADYCNCABQgA3AiwgAUEANgIgIAJBADYCCCACQgA3AhQgASgCDCIFBEAgAiAFQQFxNgIwCyABQrT+ADcCBCABQgA3AoQBIAFBADYCJCABQoCAgoAQNwMYIAFCgICAgHA3AxAgAUKBgICAcDcCjEcgASABQfwKaiIFNgK4ASABIAU2ApwBIAEgBTYCmAELQQAgA0UNABogAigCJCACKAIoIAQQHiACQQA2AhwgAwsLIgIEQCAAKAIAIgAEQCAAIAI2AgQgAEENNgIACwsgAkULKQEBfyAALQAERQRAQQAPC0ECIQEgACgCCCIAQQNOBH8gAEEHSgVBAgsLBgAgABAGC2MAQcgAEAkiAEUEQEGEhAEoAgAhASACBEAgAiABNgIEIAJBATYCAAsgAA8LIABBADoADCAAQQE6AAQgACACNgIAIABBADYCOCAAQgA3AzAgACABQQkgAUEBa0EJSRs2AgggAAukCgIIfwF+QfCAAUH0gAEgACgCdEGBCEkbIQYCQANAAkACfwJAIAAoAjxBhQJLDQAgABAvAkAgACgCPCICQYUCSw0AIAENAEEADwsgAkUNAiACQQRPDQBBAAwBCyAAIAAoAmggACgChAERAgALIQMgACAAKAJsOwFgQQIhAgJAIAA1AmggA619IgpCAVMNACAKIAAoAjBBhgJrrVUNACAAKAJwIAAoAnhPDQAgA0UNACAAIAMgBigCABECACICQQVLDQBBAiACIAAoAowBQQFGGyECCwJAIAAoAnAiA0EDSQ0AIAIgA0sNACAAIAAoAvAtIgJBAWo2AvAtIAAoAjwhBCACIAAoAuwtaiAAKAJoIgcgAC8BYEF/c2oiAjoAACAAIAAoAvAtIgVBAWo2AvAtIAUgACgC7C1qIAJBCHY6AAAgACAAKALwLSIFQQFqNgLwLSAFIAAoAuwtaiADQQNrOgAAIAAgACgCgC5BAWo2AoAuIANB/c4Aai0AAEECdCAAakHoCWoiAyADLwEAQQFqOwEAIAAgAkEBayICIAJBB3ZBgAJqIAJBgAJJG0GAywBqLQAAQQJ0akHYE2oiAiACLwEAQQFqOwEAIAAgACgCcCIFQQFrIgM2AnAgACAAKAI8IANrNgI8IAAoAvQtIQggACgC8C0hCSAEIAdqQQNrIgQgACgCaCICSwRAIAAgAkEBaiAEIAJrIgIgBUECayIEIAIgBEkbIAAoAoABEQUAIAAoAmghAgsgAEEANgJkIABBADYCcCAAIAIgA2oiBDYCaCAIIAlHDQJBACECIAAgACgCWCIDQQBOBH8gACgCSCADagVBAAsgBCADa0EAEA8gACAAKAJoNgJYIAAoAgAQCiAAKAIAKAIQDQIMAwsgACgCZARAIAAoAmggACgCSGpBAWstAAAhAyAAIAAoAvAtIgRBAWo2AvAtIAQgACgC7C1qQQA6AAAgACAAKALwLSIEQQFqNgLwLSAEIAAoAuwtakEAOgAAIAAgACgC8C0iBEEBajYC8C0gBCAAKALsLWogAzoAACAAIANBAnRqIgMgAy8B5AFBAWo7AeQBIAAoAvAtIAAoAvQtRgRAIAAgACgCWCIDQQBOBH8gACgCSCADagVBAAsgACgCaCADa0EAEA8gACAAKAJoNgJYIAAoAgAQCgsgACACNgJwIAAgACgCaEEBajYCaCAAIAAoAjxBAWs2AjwgACgCACgCEA0CQQAPBSAAQQE2AmQgACACNgJwIAAgACgCaEEBajYCaCAAIAAoAjxBAWs2AjwMAgsACwsgACgCZARAIAAoAmggACgCSGpBAWstAAAhAiAAIAAoAvAtIgNBAWo2AvAtIAMgACgC7C1qQQA6AAAgACAAKALwLSIDQQFqNgLwLSADIAAoAuwtakEAOgAAIAAgACgC8C0iA0EBajYC8C0gAyAAKALsLWogAjoAACAAIAJBAnRqIgIgAi8B5AFBAWo7AeQBIAAoAvAtIAAoAvQtRhogAEEANgJkCyAAIAAoAmgiA0ECIANBAkkbNgKELiABQQRGBEAgACAAKAJYIgFBAE4EfyAAKAJIIAFqBUEACyADIAFrQQEQDyAAIAAoAmg2AlggACgCABAKQQNBAiAAKAIAKAIQGw8LIAAoAvAtBEBBACECIAAgACgCWCIBQQBOBH8gACgCSCABagVBAAsgAyABa0EAEA8gACAAKAJoNgJYIAAoAgAQCiAAKAIAKAIQRQ0BC0EBIQILIAIL2BACEH8BfiAAKAKIAUEFSCEOA0ACQAJ/AkACQAJAAn8CQAJAIAAoAjxBhQJNBEAgABAvIAAoAjwiA0GFAksNASABDQFBAA8LIA4NASAIIQMgBSEHIAohDSAGQf//A3FFDQEMAwsgA0UNA0EAIANBBEkNARoLIAAgACgCaEH4gAEoAgARAgALIQZBASECQQAhDSAAKAJoIgOtIAatfSISQgFTDQIgEiAAKAIwQYYCa61VDQIgBkUNAiAAIAZB8IABKAIAEQIAIgZBASAGQfz/A3EbQQEgACgCbCINQf//A3EgA0H//wNxSRshBiADIQcLAkAgACgCPCIEIAZB//8DcSICQQRqTQ0AIAZB//8DcUEDTQRAQQEgBkEBa0H//wNxIglFDQQaIANB//8DcSIEIAdBAWpB//8DcSIDSw0BIAAgAyAJIAQgA2tBAWogAyAJaiAESxtB7IABKAIAEQUADAELAkAgACgCeEEEdCACSQ0AIARBBEkNACAGQQFrQf//A3EiDCAHQQFqQf//A3EiBGohCSAEIANB//8DcSIDTwRAQeyAASgCACELIAMgCUkEQCAAIAQgDCALEQUADAMLIAAgBCADIARrQQFqIAsRBQAMAgsgAyAJTw0BIAAgAyAJIANrQeyAASgCABEFAAwBCyAGIAdqQf//A3EiA0UNACAAIANBAWtB+IABKAIAEQIAGgsgBgwCCyAAIAAoAmgiBUECIAVBAkkbNgKELiABQQRGBEBBACEDIAAgACgCWCIBQQBOBH8gACgCSCABagVBAAsgBSABa0EBEA8gACAAKAJoNgJYIAAoAgAQCkEDQQIgACgCACgCEBsPCyAAKALwLQRAQQAhAkEAIQMgACAAKAJYIgFBAE4EfyAAKAJIIAFqBUEACyAFIAFrQQAQDyAAIAAoAmg2AlggACgCABAKIAAoAgAoAhBFDQMLQQEhAgwCCyADIQdBAQshBEEAIQYCQCAODQAgACgCPEGHAkkNACACIAdB//8DcSIQaiIDIAAoAkRBhgJrTw0AIAAgAzYCaEEAIQogACADQfiAASgCABECACEFAn8CQCAAKAJoIgitIAWtfSISQgFTDQAgEiAAKAIwQYYCa61VDQAgBUUNACAAIAVB8IABKAIAEQIAIQYgAC8BbCIKIAhB//8DcSIFTw0AIAZB//8DcSIDQQRJDQAgCCAEQf//A3FBAkkNARogCCACIApBAWpLDQEaIAggAiAFQQFqSw0BGiAIIAAoAkgiCSACa0EBaiICIApqLQAAIAIgBWotAABHDQEaIAggCUEBayICIApqIgwtAAAgAiAFaiIPLQAARw0BGiAIIAUgCCAAKAIwQYYCayICa0H//wNxQQAgAiAFSRsiEU0NARogCCADQf8BSw0BGiAGIQUgCCECIAQhAyAIIAoiCUECSQ0BGgNAAkAgA0EBayEDIAVBAWohCyAJQQFrIQkgAkEBayECIAxBAWsiDC0AACAPQQFrIg8tAABHDQAgA0H//wNxRQ0AIBEgAkH//wNxTw0AIAVB//8DcUH+AUsNACALIQUgCUH//wNxQQFLDQELCyAIIANB//8DcUEBSw0BGiAIIAtB//8DcUECRg0BGiAIQQFqIQggAyEEIAshBiAJIQogAgwBC0EBIQYgCAshBSAAIBA2AmgLAn8gBEH//wNxIgNBA00EQCAEQf//A3EiA0UNAyAAKAJIIAdB//8DcWotAAAhBCAAIAAoAvAtIgJBAWo2AvAtIAIgACgC7C1qQQA6AAAgACAAKALwLSICQQFqNgLwLSACIAAoAuwtakEAOgAAIAAgACgC8C0iAkEBajYC8C0gAiAAKALsLWogBDoAACAAIARBAnRqIgRB5AFqIAQvAeQBQQFqOwEAIAAgACgCPEEBazYCPCAAKALwLSICIAAoAvQtRiIEIANBAUYNARogACgCSCAHQQFqQf//A3FqLQAAIQkgACACQQFqNgLwLSAAKALsLSACakEAOgAAIAAgACgC8C0iAkEBajYC8C0gAiAAKALsLWpBADoAACAAIAAoAvAtIgJBAWo2AvAtIAIgACgC7C1qIAk6AAAgACAJQQJ0aiICQeQBaiACLwHkAUEBajsBACAAIAAoAjxBAWs2AjwgBCAAKALwLSICIAAoAvQtRmoiBCADQQJGDQEaIAAoAkggB0ECakH//wNxai0AACEHIAAgAkEBajYC8C0gACgC7C0gAmpBADoAACAAIAAoAvAtIgJBAWo2AvAtIAIgACgC7C1qQQA6AAAgACAAKALwLSICQQFqNgLwLSACIAAoAuwtaiAHOgAAIAAgB0ECdGoiB0HkAWogBy8B5AFBAWo7AQAgACAAKAI8QQFrNgI8IAQgACgC8C0gACgC9C1GagwBCyAAIAAoAvAtIgJBAWo2AvAtIAIgACgC7C1qIAdB//8DcSANQf//A3FrIgc6AAAgACAAKALwLSICQQFqNgLwLSACIAAoAuwtaiAHQQh2OgAAIAAgACgC8C0iAkEBajYC8C0gAiAAKALsLWogBEEDazoAACAAIAAoAoAuQQFqNgKALiADQf3OAGotAABBAnQgAGpB6AlqIgQgBC8BAEEBajsBACAAIAdBAWsiBCAEQQd2QYACaiAEQYACSRtBgMsAai0AAEECdGpB2BNqIgQgBC8BAEEBajsBACAAIAAoAjwgA2s2AjwgACgC8C0gACgC9C1GCyEEIAAgACgCaCADaiIHNgJoIARFDQFBACECQQAhBCAAIAAoAlgiA0EATgR/IAAoAkggA2oFQQALIAcgA2tBABAPIAAgACgCaDYCWCAAKAIAEAogACgCACgCEA0BCwsgAgu0BwIEfwF+AkADQAJAAkACQAJAIAAoAjxBhQJNBEAgABAvAkAgACgCPCICQYUCSw0AIAENAEEADwsgAkUNBCACQQRJDQELIAAgACgCaEH4gAEoAgARAgAhAiAANQJoIAKtfSIGQgFTDQAgBiAAKAIwQYYCa61VDQAgAkUNACAAIAJB8IABKAIAEQIAIgJBBEkNACAAIAAoAvAtIgNBAWo2AvAtIAMgACgC7C1qIAAoAmggACgCbGsiAzoAACAAIAAoAvAtIgRBAWo2AvAtIAQgACgC7C1qIANBCHY6AAAgACAAKALwLSIEQQFqNgLwLSAEIAAoAuwtaiACQQNrOgAAIAAgACgCgC5BAWo2AoAuIAJB/c4Aai0AAEECdCAAakHoCWoiBCAELwEAQQFqOwEAIAAgA0EBayIDIANBB3ZBgAJqIANBgAJJG0GAywBqLQAAQQJ0akHYE2oiAyADLwEAQQFqOwEAIAAgACgCPCACayIFNgI8IAAoAvQtIQMgACgC8C0hBCAAKAJ4IAJPQQAgBUEDSxsNASAAIAAoAmggAmoiAjYCaCAAIAJBAWtB+IABKAIAEQIAGiADIARHDQQMAgsgACgCSCAAKAJoai0AACECIAAgACgC8C0iA0EBajYC8C0gAyAAKALsLWpBADoAACAAIAAoAvAtIgNBAWo2AvAtIAMgACgC7C1qQQA6AAAgACAAKALwLSIDQQFqNgLwLSADIAAoAuwtaiACOgAAIAAgAkECdGoiAkHkAWogAi8B5AFBAWo7AQAgACAAKAI8QQFrNgI8IAAgACgCaEEBajYCaCAAKALwLSAAKAL0LUcNAwwBCyAAIAAoAmhBAWoiBTYCaCAAIAUgAkEBayICQeyAASgCABEFACAAIAAoAmggAmo2AmggAyAERw0CC0EAIQNBACECIAAgACgCWCIEQQBOBH8gACgCSCAEagVBAAsgACgCaCAEa0EAEA8gACAAKAJoNgJYIAAoAgAQCiAAKAIAKAIQDQEMAgsLIAAgACgCaCIEQQIgBEECSRs2AoQuIAFBBEYEQEEAIQIgACAAKAJYIgFBAE4EfyAAKAJIIAFqBUEACyAEIAFrQQEQDyAAIAAoAmg2AlggACgCABAKQQNBAiAAKAIAKAIQGw8LIAAoAvAtBEBBACEDQQAhAiAAIAAoAlgiAUEATgR/IAAoAkggAWoFQQALIAQgAWtBABAPIAAgACgCaDYCWCAAKAIAEAogACgCACgCEEUNAQtBASEDCyADC80JAgl/An4gAUEERiEGIAAoAiwhAgJAAkACQCABQQRGBEAgAkECRg0CIAIEQCAAQQAQUCAAQQA2AiwgACAAKAJoNgJYIAAoAgAQCiAAKAIAKAIQRQ0ECyAAIAYQTyAAQQI2AiwMAQsgAg0BIAAoAjxFDQEgACAGEE8gAEEBNgIsCyAAIAAoAmg2AlgLQQJBASABQQRGGyEKA0ACQCAAKAIMIAAoAhBBCGpLDQAgACgCABAKIAAoAgAiAigCEA0AQQAhAyABQQRHDQIgAigCBA0CIAAoAqAuDQIgACgCLEVBAXQPCwJAAkAgACgCPEGFAk0EQCAAEC8CQCAAKAI8IgNBhQJLDQAgAQ0AQQAPCyADRQ0CIAAoAiwEfyADBSAAIAYQTyAAIAo2AiwgACAAKAJoNgJYIAAoAjwLQQRJDQELIAAgACgCaEH4gAEoAgARAgAhBCAAKAJoIgKtIAStfSILQgFTDQAgCyAAKAIwQYYCa61VDQAgAiAAKAJIIgJqIgMvAAAgAiAEaiICLwAARw0AIANBAmogAkECakHQgAEoAgARAgBBAmoiA0EESQ0AIAAoAjwiAiADIAIgA0kbIgJBggIgAkGCAkkbIgdB/c4Aai0AACICQQJ0IgRBhMkAajMBACEMIARBhskAai8BACEDIAJBCGtBE00EQCAHQQNrIARBgNEAaigCAGutIAOthiAMhCEMIARBsNYAaigCACADaiEDCyAAKAKgLiEFIAMgC6dBAWsiCCAIQQd2QYACaiAIQYACSRtBgMsAai0AACICQQJ0IglBgsoAai8BAGohBCAJQYDKAGozAQAgA62GIAyEIQsgACkDmC4hDAJAIAUgAkEESQR/IAQFIAggCUGA0gBqKAIAa60gBK2GIAuEIQsgCUGw1wBqKAIAIARqCyICaiIDQT9NBEAgCyAFrYYgDIQhCwwBCyAFQcAARgRAIAAoAgQgACgCEGogDDcAACAAIAAoAhBBCGo2AhAgAiEDDAELIAAoAgQgACgCEGogCyAFrYYgDIQ3AAAgACAAKAIQQQhqNgIQIANBQGohAyALQcAAIAVrrYghCwsgACALNwOYLiAAIAM2AqAuIAAgACgCPCAHazYCPCAAIAAoAmggB2o2AmgMAgsgACgCSCAAKAJoai0AAEECdCICQYDBAGozAQAhCyAAKQOYLiEMAkAgACgCoC4iBCACQYLBAGovAQAiAmoiA0E/TQRAIAsgBK2GIAyEIQsMAQsgBEHAAEYEQCAAKAIEIAAoAhBqIAw3AAAgACAAKAIQQQhqNgIQIAIhAwwBCyAAKAIEIAAoAhBqIAsgBK2GIAyENwAAIAAgACgCEEEIajYCECADQUBqIQMgC0HAACAEa62IIQsLIAAgCzcDmC4gACADNgKgLiAAIAAoAmhBAWo2AmggACAAKAI8QQFrNgI8DAELCyAAIAAoAmgiAkECIAJBAkkbNgKELiAAKAIsIQIgAUEERgRAAkAgAkUNACAAQQEQUCAAQQA2AiwgACAAKAJoNgJYIAAoAgAQCiAAKAIAKAIQDQBBAg8LQQMPCyACBEBBACEDIABBABBQIABBADYCLCAAIAAoAmg2AlggACgCABAKIAAoAgAoAhBFDQELQQEhAwsgAwucAQEFfyACQQFOBEAgAiAAKAJIIAFqIgNqQQJqIQQgA0ECaiECIAAoAlQhAyAAKAJQIQUDQCAAIAItAAAgA0EFdEHg/wFxcyIDNgJUIAUgA0EBdGoiBi8BACIHIAFB//8DcUcEQCAAKAJMIAEgACgCOHFB//8DcUEBdGogBzsBACAGIAE7AQALIAFBAWohASACQQFqIgIgBEkNAAsLC1sBAn8gACAAKAJIIAFqLQACIAAoAlRBBXRB4P8BcXMiAjYCVCABIAAoAlAgAkEBdGoiAy8BACICRwRAIAAoAkwgACgCOCABcUEBdGogAjsBACADIAE7AQALIAILEwAgAUEFdEHg/wFxIAJB/wFxcwsGACABEAYLLwAjAEEQayIAJAAgAEEMaiABIAJsEIwBIQEgACgCDCECIABBEGokAEEAIAIgARsLjAoCAX4CfyMAQfAAayIGJAACQAJAAkACQAJAAkACQAJAIAQODwABBwIEBQYGBgYGBgYGAwYLQn8hBQJAIAAgBkHkAGpCDBARIgNCf1cEQCABBEAgASAAKAIMNgIAIAEgACgCEDYCBAsMAQsCQCADQgxSBEAgAQRAIAFBADYCBCABQRE2AgALDAELIAEoAhQhBEEAIQJCASEFA0AgBkHkAGogAmoiAiACLQAAIARB/f8DcSICQQJyIAJBA3NsQQh2cyICOgAAIAYgAjoAKCABAn8gASgCDEF/cyECQQAgBkEoaiIERQ0AGiACIARBAUHUgAEoAgARAAALQX9zIgI2AgwgASABKAIQIAJB/wFxakGFiKLAAGxBAWoiAjYCECAGIAJBGHY6ACggAQJ/IAEoAhRBf3MhAkEAIAZBKGoiBEUNABogAiAEQQFB1IABKAIAEQAAC0F/cyIENgIUIAVCDFIEQCAFpyECIAVCAXwhBQwBCwtCACEFIAAgBkEoahAhQQBIDQEgBigCUCEAIwBBEGsiAiQAIAIgADYCDCAGAn8gAkEMahCNASIARQRAIAZBITsBJEEADAELAn8gACgCFCIEQdAATgRAIARBCXQMAQsgAEHQADYCFEGAwAILIQQgBiAAKAIMIAQgACgCEEEFdGpqQaDAAWo7ASQgACgCBEEFdCAAKAIIQQt0aiAAKAIAQQF2ags7ASYgAkEQaiQAIAYtAG8iACAGLQBXRg0BIAYtACcgAEYNASABBEAgAUEANgIEIAFBGzYCAAsLQn8hBQsgBkHwAGokACAFDwtCfyEFIAAgAiADEBEiA0J/VwRAIAEEQCABIAAoAgw2AgAgASAAKAIQNgIECwwGCyMAQRBrIgAkAAJAIANQDQAgASgCFCEEIAJFBEBCASEFA0AgACACIAdqLQAAIARB/f8DcSIEQQJyIARBA3NsQQh2czoADyABAn8gASgCDEF/cyEEQQAgAEEPaiIHRQ0AGiAEIAdBAUHUgAEoAgARAAALQX9zIgQ2AgwgASABKAIQIARB/wFxakGFiKLAAGxBAWoiBDYCECAAIARBGHY6AA8gAQJ/IAEoAhRBf3MhBEEAIABBD2oiB0UNABogBCAHQQFB1IABKAIAEQAAC0F/cyIENgIUIAMgBVENAiAFpyEHIAVCAXwhBQwACwALQgEhBQNAIAAgAiAHai0AACAEQf3/A3EiBEECciAEQQNzbEEIdnMiBDoADyACIAdqIAQ6AAAgAQJ/IAEoAgxBf3MhBEEAIABBD2oiB0UNABogBCAHQQFB1IABKAIAEQAAC0F/cyIENgIMIAEgASgCECAEQf8BcWpBhYiiwABsQQFqIgQ2AhAgACAEQRh2OgAPIAECfyABKAIUQX9zIQRBACAAQQ9qIgdFDQAaIAQgB0EBQdSAASgCABEAAAtBf3MiBDYCFCADIAVRDQEgBachByAFQgF8IQUMAAsACyAAQRBqJAAgAyEFDAULIAJBADsBMiACIAIpAwAiA0KAAYQ3AwAgA0IIg1ANBCACIAIpAyBCDH03AyAMBAsgBkKFgICAcDcDECAGQoOAgIDAADcDCCAGQoGAgIAgNwMAQQAgBhAkIQUMAwsgA0IIWgR+IAIgASgCADYCACACIAEoAgQ2AgRCCAVCfwshBQwCCyABEAYMAQsgAQRAIAFBADYCBCABQRI2AgALQn8hBQsgBkHwAGokACAFC60DAgJ/An4jAEEQayIGJAACQAJAAkAgBEUNACABRQ0AIAJBAUYNAQtBACEDIABBCGoiAARAIABBADYCBCAAQRI2AgALDAELIANBAXEEQEEAIQMgAEEIaiIABEAgAEEANgIEIABBGDYCAAsMAQtBGBAJIgVFBEBBACEDIABBCGoiAARAIABBADYCBCAAQQ42AgALDAELIAVBADYCCCAFQgA3AgAgBUGQ8dmiAzYCFCAFQvis0ZGR8dmiIzcCDAJAIAQQIiICRQ0AIAKtIQhBACEDQYfTru5+IQJCASEHA0AgBiADIARqLQAAOgAPIAUgBkEPaiIDBH8gAiADQQFB1IABKAIAEQAABUEAC0F/cyICNgIMIAUgBSgCECACQf8BcWpBhYiiwABsQQFqIgI2AhAgBiACQRh2OgAPIAUCfyAFKAIUQX9zIQJBACAGQQ9qIgNFDQAaIAIgA0EBQdSAASgCABEAAAtBf3M2AhQgByAIUQ0BIAUoAgxBf3MhAiAHpyEDIAdCAXwhBwwACwALIAAgAUElIAUQQiIDDQAgBRAGQQAhAwsgBkEQaiQAIAMLnRoCBn4FfyMAQdAAayILJAACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCADDhQFBhULAwQJDgACCBAKDw0HEQERDBELAkBByAAQCSIBBEAgAUIANwMAIAFCADcDMCABQQA2AiggAUIANwMgIAFCADcDGCABQgA3AxAgAUIANwMIIAFCADcDOCABQQgQCSIDNgIEIAMNASABEAYgAARAIABBADYCBCAAQQ42AgALCyAAQQA2AhQMFAsgA0IANwMAIAAgATYCFCABQUBrQgA3AwAgAUIANwM4DBQLAkACQCACUARAQcgAEAkiA0UNFCADQgA3AwAgA0IANwMwIANBADYCKCADQgA3AyAgA0IANwMYIANCADcDECADQgA3AwggA0IANwM4IANBCBAJIgE2AgQgAQ0BIAMQBiAABEAgAEEANgIEIABBDjYCAAsMFAsgAiAAKAIQIgEpAzBWBEAgAARAIABBADYCBCAAQRI2AgALDBQLIAEoAigEQCAABEAgAEEANgIEIABBHTYCAAsMFAsgASgCBCEDAkAgASkDCCIGQgF9IgdQDQADQAJAIAIgAyAHIAR9QgGIIAR8IgWnQQN0aikDAFQEQCAFQgF9IQcMAQsgBSAGUQRAIAYhBQwDCyADIAVCAXwiBKdBA3RqKQMAIAJWDQILIAQhBSAEIAdUDQALCwJAIAIgAyAFpyIKQQN0aikDAH0iBFBFBEAgASgCACIDIApBBHRqKQMIIQcMAQsgASgCACIDIAVCAX0iBadBBHRqKQMIIgchBAsgAiAHIAR9VARAIAAEQCAAQQA2AgQgAEEcNgIACwwUCyADIAVCAXwiBUEAIAAQiQEiA0UNEyADKAIAIAMoAggiCkEEdGpBCGsgBDcDACADKAIEIApBA3RqIAI3AwAgAyACNwMwIAMgASkDGCIGIAMpAwgiBEIBfSIHIAYgB1QbNwMYIAEgAzYCKCADIAE2AiggASAENwMgIAMgBTcDIAwBCyABQgA3AwALIAAgAzYCFCADIAQ3A0AgAyACNwM4QgAhBAwTCyAAKAIQIgEEQAJAIAEoAigiA0UEQCABKQMYIQIMAQsgA0EANgIoIAEoAihCADcDICABIAEpAxgiAiABKQMgIgUgAiAFVhsiAjcDGAsgASkDCCACVgRAA0AgASgCACACp0EEdGooAgAQBiACQgF8IgIgASkDCFQNAAsLIAEoAgAQBiABKAIEEAYgARAGCyAAKAIUIQEgAEEANgIUIAAgATYCEAwSCyACQghaBH4gASAAKAIANgIAIAEgACgCBDYCBEIIBUJ/CyEEDBELIAAoAhAiAQRAAkAgASgCKCIDRQRAIAEpAxghAgwBCyADQQA2AiggASgCKEIANwMgIAEgASkDGCICIAEpAyAiBSACIAVWGyICNwMYCyABKQMIIAJWBEADQCABKAIAIAKnQQR0aigCABAGIAJCAXwiAiABKQMIVA0ACwsgASgCABAGIAEoAgQQBiABEAYLIAAoAhQiAQRAAkAgASgCKCIDRQRAIAEpAxghAgwBCyADQQA2AiggASgCKEIANwMgIAEgASkDGCICIAEpAyAiBSACIAVWGyICNwMYCyABKQMIIAJWBEADQCABKAIAIAKnQQR0aigCABAGIAJCAXwiAiABKQMIVA0ACwsgASgCABAGIAEoAgQQBiABEAYLIAAQBgwQCyAAKAIQIgBCADcDOCAAQUBrQgA3AwAMDwsgAkJ/VwRAIAAEQCAAQQA2AgQgAEESNgIACwwOCyACIAAoAhAiAykDMCADKQM4IgZ9IgUgAiAFVBsiBVANDiABIAMpA0AiB6ciAEEEdCIBIAMoAgBqIgooAgAgBiADKAIEIABBA3RqKQMAfSICp2ogBSAKKQMIIAJ9IgYgBSAGVBsiBKcQByEKIAcgBCADKAIAIgAgAWopAwggAn1RrXwhAiAFIAZWBEADQCAKIASnaiAAIAKnQQR0IgFqIgAoAgAgBSAEfSIGIAApAwgiByAGIAdUGyIGpxAHGiACIAYgAygCACIAIAFqKQMIUa18IQIgBSAEIAZ8IgRWDQALCyADIAI3A0AgAyADKQM4IAR8NwM4DA4LQn8hBEHIABAJIgNFDQ0gA0IANwMAIANCADcDMCADQQA2AiggA0IANwMgIANCADcDGCADQgA3AxAgA0IANwMIIANCADcDOCADQQgQCSIBNgIEIAFFBEAgAxAGIAAEQCAAQQA2AgQgAEEONgIACwwOCyABQgA3AwAgACgCECIBBEACQCABKAIoIgpFBEAgASkDGCEEDAELIApBADYCKCABKAIoQgA3AyAgASABKQMYIgIgASkDICIFIAIgBVYbIgQ3AxgLIAEpAwggBFYEQANAIAEoAgAgBKdBBHRqKAIAEAYgBEIBfCIEIAEpAwhUDQALCyABKAIAEAYgASgCBBAGIAEQBgsgACADNgIQQgAhBAwNCyAAKAIUIgEEQAJAIAEoAigiA0UEQCABKQMYIQIMAQsgA0EANgIoIAEoAihCADcDICABIAEpAxgiAiABKQMgIgUgAiAFVhsiAjcDGAsgASkDCCACVgRAA0AgASgCACACp0EEdGooAgAQBiACQgF8IgIgASkDCFQNAAsLIAEoAgAQBiABKAIEEAYgARAGCyAAQQA2AhQMDAsgACgCECIDKQM4IAMpAzAgASACIAAQRCIHQgBTDQogAyAHNwM4AkAgAykDCCIGQgF9IgJQDQAgAygCBCEAA0ACQCAHIAAgAiAEfUIBiCAEfCIFp0EDdGopAwBUBEAgBUIBfSECDAELIAUgBlEEQCAGIQUMAwsgACAFQgF8IgSnQQN0aikDACAHVg0CCyAEIQUgAiAEVg0ACwsgAyAFNwNAQgAhBAwLCyAAKAIUIgMpAzggAykDMCABIAIgABBEIgdCAFMNCSADIAc3AzgCQCADKQMIIgZCAX0iAlANACADKAIEIQADQAJAIAcgACACIAR9QgGIIAR8IgWnQQN0aikDAFQEQCAFQgF9IQIMAQsgBSAGUQRAIAYhBQwDCyAAIAVCAXwiBKdBA3RqKQMAIAdWDQILIAQhBSACIARWDQALCyADIAU3A0BCACEEDAoLIAJCN1gEQCAABEAgAEEANgIEIABBEjYCAAsMCQsgARAqIAEgACgCDDYCKCAAKAIQKQMwIQIgAUEANgIwIAEgAjcDICABIAI3AxggAULcATcDAEI4IQQMCQsgACABKAIANgIMDAgLIAtBQGtBfzYCACALQouAgICwAjcDOCALQoyAgIDQATcDMCALQo+AgICgATcDKCALQpGAgICQATcDICALQoeAgICAATcDGCALQoWAgIDgADcDECALQoOAgIDAADcDCCALQoGAgIAgNwMAQQAgCxAkIQQMBwsgACgCECkDOCIEQn9VDQYgAARAIABBPTYCBCAAQR42AgALDAULIAAoAhQpAzgiBEJ/VQ0FIAAEQCAAQT02AgQgAEEeNgIACwwEC0J/IQQgAkJ/VwRAIAAEQCAAQQA2AgQgAEESNgIACwwFCyACIAAoAhQiAykDOCACfCIFQv//A3wiBFYEQCAABEAgAEEANgIEIABBEjYCAAsMBAsCQCAFIAMoAgQiCiADKQMIIganQQN0aikDACIHWA0AAkAgBCAHfUIQiCAGfCIIIAMpAxAiCVgNAEIQIAkgCVAbIQUDQCAFIgRCAYYhBSAEIAhUDQALIAQgCVQNACADKAIAIASnIgpBBHQQNCIMRQ0DIAMgDDYCACADKAIEIApBA3RBCGoQNCIKRQ0DIAMgBDcDECADIAo2AgQgAykDCCEGCyAGIAhaDQAgAygCACEMA0AgDCAGp0EEdGoiDUGAgAQQCSIONgIAIA5FBEAgAARAIABBADYCBCAAQQ42AgALDAYLIA1CgIAENwMIIAMgBkIBfCIFNwMIIAogBadBA3RqIAdCgIAEfCIHNwMAIAMpAwgiBiAIVA0ACwsgAykDQCEFIAMpAzghBwJAIAJQBEBCACEEDAELIAWnIgBBBHQiDCADKAIAaiINKAIAIAcgCiAAQQN0aikDAH0iBqdqIAEgAiANKQMIIAZ9IgcgAiAHVBsiBKcQBxogBSAEIAMoAgAiACAMaikDCCAGfVGtfCEFIAIgB1YEQANAIAAgBadBBHQiCmoiACgCACABIASnaiACIAR9IgYgACkDCCIHIAYgB1QbIganEAcaIAUgBiADKAIAIgAgCmopAwhRrXwhBSAEIAZ8IgQgAlQNAAsLIAMpAzghBwsgAyAFNwNAIAMgBCAHfCICNwM4IAIgAykDMFgNBCADIAI3AzAMBAsgAARAIABBADYCBCAAQRw2AgALDAILIAAEQCAAQQA2AgQgAEEONgIACyAABEAgAEEANgIEIABBDjYCAAsMAQsgAEEANgIUC0J/IQQLIAtB0ABqJAAgBAtIAQF/IABCADcCBCAAIAE2AgACQCABQQBIDQBBsBMoAgAgAUwNACABQQJ0QcATaigCAEEBRw0AQYSEASgCACECCyAAIAI2AgQLDgAgAkGx893xeWxBEHYLvgEAIwBBEGsiACQAIABBADoACEGAgQFBAjYCAEH8gAFBAzYCAEH4gAFBBDYCAEH0gAFBBTYCAEHwgAFBBjYCAEHsgAFBBzYCAEHogAFBCDYCAEHkgAFBCTYCAEHggAFBCjYCAEHcgAFBCzYCAEHYgAFBDDYCAEHUgAFBDTYCAEHQgAFBDjYCAEHMgAFBDzYCAEHIgAFBEDYCAEHEgAFBETYCAEHAgAFBEjYCACAAQRBqJAAgAkGx893xeWxBEHYLuQEBAX8jAEEQayIBJAAgAUEAOgAIQYCBAUECNgIAQfyAAUEDNgIAQfiAAUEENgIAQfSAAUEFNgIAQfCAAUEGNgIAQeyAAUEHNgIAQeiAAUEINgIAQeSAAUEJNgIAQeCAAUEKNgIAQdyAAUELNgIAQdiAAUEMNgIAQdSAAUENNgIAQdCAAUEONgIAQcyAAUEPNgIAQciAAUEQNgIAQcSAAUERNgIAQcCAAUESNgIAIAAQjgEgAUEQaiQAC78BAQF/IwBBEGsiAiQAIAJBADoACEGAgQFBAjYCAEH8gAFBAzYCAEH4gAFBBDYCAEH0gAFBBTYCAEHwgAFBBjYCAEHsgAFBBzYCAEHogAFBCDYCAEHkgAFBCTYCAEHggAFBCjYCAEHcgAFBCzYCAEHYgAFBDDYCAEHUgAFBDTYCAEHQgAFBDjYCAEHMgAFBDzYCAEHIgAFBEDYCAEHEgAFBETYCAEHAgAFBEjYCACAAIAEQkAEhACACQRBqJAAgAAu+AQEBfyMAQRBrIgIkACACQQA6AAhBgIEBQQI2AgBB/IABQQM2AgBB+IABQQQ2AgBB9IABQQU2AgBB8IABQQY2AgBB7IABQQc2AgBB6IABQQg2AgBB5IABQQk2AgBB4IABQQo2AgBB3IABQQs2AgBB2IABQQw2AgBB1IABQQ02AgBB0IABQQ42AgBBzIABQQ82AgBByIABQRA2AgBBxIABQRE2AgBBwIABQRI2AgAgACABEFohACACQRBqJAAgAAu+AQEBfyMAQRBrIgIkACACQQA6AAhBgIEBQQI2AgBB/IABQQM2AgBB+IABQQQ2AgBB9IABQQU2AgBB8IABQQY2AgBB7IABQQc2AgBB6IABQQg2AgBB5IABQQk2AgBB4IABQQo2AgBB3IABQQs2AgBB2IABQQw2AgBB1IABQQ02AgBB0IABQQ42AgBBzIABQQ82AgBByIABQRA2AgBBxIABQRE2AgBBwIABQRI2AgAgACABEFshACACQRBqJAAgAAu9AQEBfyMAQRBrIgMkACADQQA6AAhBgIEBQQI2AgBB/IABQQM2AgBB+IABQQQ2AgBB9IABQQU2AgBB8IABQQY2AgBB7IABQQc2AgBB6IABQQg2AgBB5IABQQk2AgBB4IABQQo2AgBB3IABQQs2AgBB2IABQQw2AgBB1IABQQ02AgBB0IABQQ42AgBBzIABQQ82AgBByIABQRA2AgBBxIABQRE2AgBBwIABQRI2AgAgACABIAIQjwEgA0EQaiQAC4UBAgR/AX4jAEEQayIBJAACQCAAKQMwUARADAELA0ACQCAAIAVBACABQQ9qIAFBCGoQZiIEQX9GDQAgAS0AD0EDRw0AIAIgASgCCEGAgICAf3FBgICAgHpGaiECC0F/IQMgBEF/Rg0BIAIhAyAFQgF8IgUgACkDMFQNAAsLIAFBEGokACADCwuMdSUAQYAIC7ELaW5zdWZmaWNpZW50IG1lbW9yeQBuZWVkIGRpY3Rpb25hcnkALSsgICAwWDB4AFppcCBhcmNoaXZlIGluY29uc2lzdGVudABJbnZhbGlkIGFyZ3VtZW50AGludmFsaWQgbGl0ZXJhbC9sZW5ndGhzIHNldABpbnZhbGlkIGNvZGUgbGVuZ3RocyBzZXQAdW5rbm93biBoZWFkZXIgZmxhZ3Mgc2V0AGludmFsaWQgZGlzdGFuY2VzIHNldABpbnZhbGlkIGJpdCBsZW5ndGggcmVwZWF0AEZpbGUgYWxyZWFkeSBleGlzdHMAdG9vIG1hbnkgbGVuZ3RoIG9yIGRpc3RhbmNlIHN5bWJvbHMAaW52YWxpZCBzdG9yZWQgYmxvY2sgbGVuZ3RocwAlcyVzJXMAYnVmZmVyIGVycm9yAE5vIGVycm9yAHN0cmVhbSBlcnJvcgBUZWxsIGVycm9yAEludGVybmFsIGVycm9yAFNlZWsgZXJyb3IAV3JpdGUgZXJyb3IAZmlsZSBlcnJvcgBSZWFkIGVycm9yAFpsaWIgZXJyb3IAZGF0YSBlcnJvcgBDUkMgZXJyb3IAaW5jb21wYXRpYmxlIHZlcnNpb24AaW52YWxpZCBjb2RlIC0tIG1pc3NpbmcgZW5kLW9mLWJsb2NrAGluY29ycmVjdCBoZWFkZXIgY2hlY2sAaW5jb3JyZWN0IGxlbmd0aCBjaGVjawBpbmNvcnJlY3QgZGF0YSBjaGVjawBpbnZhbGlkIGRpc3RhbmNlIHRvbyBmYXIgYmFjawBoZWFkZXIgY3JjIG1pc21hdGNoADEuMi4xMy56bGliLW5nAGludmFsaWQgd2luZG93IHNpemUAUmVhZC1vbmx5IGFyY2hpdmUATm90IGEgemlwIGFyY2hpdmUAUmVzb3VyY2Ugc3RpbGwgaW4gdXNlAE1hbGxvYyBmYWlsdXJlAGludmFsaWQgYmxvY2sgdHlwZQBGYWlsdXJlIHRvIGNyZWF0ZSB0ZW1wb3JhcnkgZmlsZQBDYW4ndCBvcGVuIGZpbGUATm8gc3VjaCBmaWxlAFByZW1hdHVyZSBlbmQgb2YgZmlsZQBDYW4ndCByZW1vdmUgZmlsZQBpbnZhbGlkIGxpdGVyYWwvbGVuZ3RoIGNvZGUAaW52YWxpZCBkaXN0YW5jZSBjb2RlAHVua25vd24gY29tcHJlc3Npb24gbWV0aG9kAHN0cmVhbSBlbmQAQ29tcHJlc3NlZCBkYXRhIGludmFsaWQATXVsdGktZGlzayB6aXAgYXJjaGl2ZXMgbm90IHN1cHBvcnRlZABPcGVyYXRpb24gbm90IHN1cHBvcnRlZABFbmNyeXB0aW9uIG1ldGhvZCBub3Qgc3VwcG9ydGVkAENvbXByZXNzaW9uIG1ldGhvZCBub3Qgc3VwcG9ydGVkAEVudHJ5IGhhcyBiZWVuIGRlbGV0ZWQAQ29udGFpbmluZyB6aXAgYXJjaGl2ZSB3YXMgY2xvc2VkAENsb3NpbmcgemlwIGFyY2hpdmUgZmFpbGVkAFJlbmFtaW5nIHRlbXBvcmFyeSBmaWxlIGZhaWxlZABFbnRyeSBoYXMgYmVlbiBjaGFuZ2VkAE5vIHBhc3N3b3JkIHByb3ZpZGVkAFdyb25nIHBhc3N3b3JkIHByb3ZpZGVkAFVua25vd24gZXJyb3IgJWQAQUUAKG51bGwpADogAFBLBgcAUEsGBgBQSwUGAFBLAwQAUEsBAgAAAAA/BQAAwAcAAJMIAAB4CAAAbwUAAJEFAAB6BQAAsgUAAFYIAAAbBwAA1gQAAAsHAADqBgAAnAUAAMgGAACyCAAAHggAACgHAABHBAAAoAYAAGAFAAAuBAAAPgcAAD8IAAD+BwAAjgYAAMkIAADeCAAA5gcAALIGAABVBQAAqAcAACAAQcgTCxEBAAAAAQAAAAEAAAABAAAAAQBB7BMLCQEAAAABAAAAAgBBmBQLAQEAQbgUCwEBAEHSFAukLDomOyZlJmYmYyZgJiIg2CXLJdklQiZAJmomayY8JrolxCWVITwgtgCnAKwlqCGRIZMhkiGQIR8ilCGyJbwlIAAhACIAIwAkACUAJgAnACgAKQAqACsALAAtAC4ALwAwADEAMgAzADQANQA2ADcAOAA5ADoAOwA8AD0APgA/AEAAQQBCAEMARABFAEYARwBIAEkASgBLAEwATQBOAE8AUABRAFIAUwBUAFUAVgBXAFgAWQBaAFsAXABdAF4AXwBgAGEAYgBjAGQAZQBmAGcAaABpAGoAawBsAG0AbgBvAHAAcQByAHMAdAB1AHYAdwB4AHkAegB7AHwAfQB+AAIjxwD8AOkA4gDkAOAA5QDnAOoA6wDoAO8A7gDsAMQAxQDJAOYAxgD0APYA8gD7APkA/wDWANwAogCjAKUApyCSAeEA7QDzAPoA8QDRAKoAugC/ABAjrAC9ALwAoQCrALsAkSWSJZMlAiUkJWElYiVWJVUlYyVRJVclXSVcJVslECUUJTQlLCUcJQAlPCVeJV8lWiVUJWklZiVgJVAlbCVnJWglZCVlJVklWCVSJVMlayVqJRglDCWIJYQljCWQJYAlsQPfAJMDwAOjA8MDtQDEA6YDmAOpA7QDHiLGA7UDKSJhIrEAZSJkIiAjISP3AEgisAAZIrcAGiJ/ILIAoCWgAAAAAACWMAd3LGEO7rpRCZkZxG0Hj/RqcDWlY+mjlWSeMojbDqS43Hke6dXgiNnSlytMtgm9fLF+By2455Edv5BkELcd8iCwakhxufPeQb6EfdTaGuvk3W1RtdT0x4XTg1aYbBPAqGtkevli/ezJZYpPXAEU2WwGY2M9D/r1DQiNyCBuO14QaUzkQWDVcnFnotHkAzxH1ARL/YUN0mu1CqX6qLU1bJiyQtbJu9tA+bys42zYMnVc30XPDdbcWT3Rq6ww2SY6AN5RgFHXyBZh0L+19LQhI8SzVpmVus8Ppb24nrgCKAiIBV+y2QzGJOkLsYd8by8RTGhYqx1hwT0tZraQQdx2BnHbAbwg0pgqENXviYWxcR+1tgal5L+fM9S46KLJB3g0+QAPjqgJlhiYDuG7DWp/LT1tCJdsZJEBXGPm9FFra2JhbBzYMGWFTgBi8u2VBmx7pQEbwfQIglfED/XG2bBlUOm3Euq4vot8iLn83x3dYkkt2hXzfNOMZUzU+1hhsk3OUbU6dAC8o+Iwu9RBpd9K15XYPW3E0aT79NbTaulpQ/zZbjRGiGet0Lhg2nMtBETlHQMzX0wKqsl8Dd08cQVQqkECJxAQC76GIAzJJbVoV7OFbyAJ1Ga5n+Rhzg753l6YydkpIpjQsLSo18cXPbNZgQ20LjtcvbetbLrAIIO47bazv5oM4rYDmtKxdDlH1eqvd9KdFSbbBIMW3HMSC2PjhDtklD5qbQ2oWmp6C88O5J3/CZMnrgAKsZ4HfUSTD/DSowiHaPIBHv7CBmldV2L3y2dlgHE2bBnnBmtudhvU/uAr04laetoQzErdZ2/fufn5776OQ763F9WOsGDoo9bWfpPRocTC2DhS8t9P8We70WdXvKbdBrU/SzaySNorDdhMGwqv9koDNmB6BEHD72DfVd9nqO+ObjF5vmlGjLNhyxqDZryg0m8lNuJoUpV3DMwDRwu7uRYCIi8mBVW+O7rFKAu9spJatCsEarNcp//XwjHP0LWLntksHa7eW7DCZJsm8mPsnKNqdQqTbQKpBgmcPzYO64VnB3ITVwAFgkq/lRR6uOKuK7F7OBu2DJuO0pINvtXlt+/cfCHf2wvU0tOGQuLU8fiz3Whug9ofzRa+gVsmufbhd7Bvd0e3GOZaCIhwag//yjsGZlwLARH/nmWPaa5i+NP/a2FFz2wWeOIKoO7SDddUgwROwrMDOWEmZ6f3FmDQTUdpSdt3bj5KatGu3FrW2WYL30DwO9g3U668qcWeu95/z7JH6f+1MBzyvb2KwrrKMJOzU6ajtCQFNtC6kwbXzSlX3lS/Z9kjLnpms7hKYcQCG2hdlCtvKje+C7ShjgzDG98FWo3vAi0AAAAARjtnZYx2zsrKTamvWevtTh/QiivVnSOEk6ZE4bLW25307bz4PqAVV3ibcjLrPTbTrQZRtmdL+BkhcJ98JavG4GOQoYWp3Qgq7+ZvT3xAK646e0zL8DblZLYNggGXfR190UZ6GBsL07ddMLTSzpbwM4itl1ZC4D75BNtZnAtQ/BpNa5t/hyYy0MEdVbVSuxFUFIB2Md7N356Y9rj7uYYnh/+9QOI18OlNc8uOKOBtysmmVq2sbBsEAyogY2Yu+zr6aMBdn6KN9DDktpNVdxDXtDErsNH7Zhl+vV1+G5wt4WfaFoYCEFsvrVZgSMjFxgwpg/1rTEmwwuMPi6WGFqD4NVCbn1Ca1jb/3O1Rmk9LFXsJcHIewz3bsYUGvNSkdiOo4k1EzSgA7WJuO4oH/Z3O5rumqYNx6wAsN9BnSTMLPtV1MFmwv33wH/lGl3pq4NObLNu0/uaWHVGgrXo0gd3lSMfmgi0NqyuCS5BM59g2CAaeDW9jVEDGzBJ7oakd8AQvW8tjSpGGyuXXva2ARBvpYQIgjgTIbSerjlZAzq8m37LpHbjXI1AReGVrdh32zTL8sPZVmXq7/DY8gJtTOFvCz35gpaq0LQwF8hZrYGGwL4Eni0jk7cbhS6v9hi6KjRlSzLZ+Nwb715hAwLD902b0HJVdk3lfEDrWGStdsyxA8Wtqe5YOoDY/oeYNWMR1qxwlM5B7QPnd0u+/5rWKnpYq9titTZMS4OQ8VNuDWcd9x7iBRqDdSwsJcg0wbhcJ6zeLT9BQ7oWd+UHDpp4kUADaxRY7vaDcdhQPmk1zars97Bb9BotzN0si3HFwRbni1gFYpO1mPW6gz5Iom6j3JxANcWErahSrZsO77V2k3n774D84wIda8o0u9bS2SZCVxtbs0/2xiRmwGCZfi39DzC07oooWXMdAW/VoBmCSDQK7y5FEgKz0js0FW8j2Yj5bUCbfHWtButcm6BWRHY9wsG0QDPZWd2k8G97GeiC5o+mG/UKvvZonZfAziCPLVO064AlefNtuO7aWx5TwraDxYwvkECUwg3XvfSraqUZNv4g20sPODbWmBEAcCUJ7e2zR3T+Nl+ZY6F2r8UcbkJYiH0vPvllwqNuTPQF01QZmEUagIvAAm0WVytbsOozti1+tnRQj66ZzRiHr2uln0L2M9Hb5bbJNngh4ADenPjtQwjGw9UR3i5IhvcY7jvv9XOtoWxgKLmB/b+Qt1sCiFrGlg2Yu2cVdSbwPEOATSSuHdtqNw5ectqTyVvsNXRDAajgUGzOkUiBUwZht/W7eVpoLTfDe6gvLuY/BhhAgh713RabN6Dng9o9cKrsm82yAQZb/JgV3uR1iEnNQy701a6zYAAAAAFiA4tfxBrR0qYZWo+INaOm6jYo+EwvcnUuLPkqFHaEJ3Z1D3nQbFX0sm/eqZxDJ4D+QKzeWFn2UzpafQwo7QhNSu6DE+z32Z6O9FLDoNir6sLbILRkwno5BsHxZjybjGtemAc1+IFduJqC1uW0ri/M1q2kknC0/h8St3VAUdoQmTPZm8eVwMFK98NKF9nvsz677DhgHfVi7X/26bJFrJS/J68f4YG2RWzjtc4xzZk3GK+avEYJg+bLa4BtlHk3GNUbNJOLvS3JBt8uQlvxArtykwEwLDUYaqFXG+H+bUGc8w9CF62pW00gy1jGfeV0P1SHd7QKIW7uh0NtZdijsCE1wbOqa2eq8OYFqXu7K4WCkkmGCczvn1NBjZzYHrfGpRPVxS5Nc9x0wBHf/50/8wa0XfCN6vvp12eZ6lw4i10peeleoidPR/iqLURz9wNoit5hawGAx3JbDaVx0FKfK61f/SgmAVsxfIw5MvfRFx4O+HUdhabTBN8rsQdUdPJqMa2QabrzNnDgflRzayN6X5IKGFwZVL5FQ9ncRsiG5hy1i4QfPtUiBmRYQAXvBW4pFiwMKp1yqjPH/8gwTKDahznhuISyvx6d6DJ8nmNvUrKaRjCxERiWqEuV9KvAys7xvces8jaZCutsFGjo50lGxB5gJMeVPoLez7Pg3UTtQ2BGaCFjzTaHepe75Xkc5stV5c+pVm6RD080HG1Mv0NXFsJONRVJEJMME53xD5jA3yNh6b0g6rcbObA6eTo7ZWuNTiQJjsV6r5ef982UFKrjuO2Dgbtm3SeiPFBFobcPf/vKAh34QVy74RvR2eKQjPfOaaWVzeL7M9S4dlHXMykSulbwcLndrtaghyO0owx+mo/1V/iMfglelSSEPJav2wbM0tZkz1mIwtYDBaDViFiO+XFx7Pr6L0rjoKIo4Cv9OldevFhU1eL+TY9vnE4EMrJi/RvQYXZFdngsyBR7p5cuIdqaTCJRxOo7C0mIOIAUphR5PcQX8mNiDqjuAA0jseDQZ1yC0+wCJMq2j0bJPdJo5cT7CuZPpaz/FSjO/J539KbjepalaCQwvDKpUr+59HyTQN0ekMuDuImRDtqKGlHIPW8Qqj7kTgwnvsNuJDWeQAjMtyILR+mEEh1k5hGWO9xL6za+SGBoGFE65XpSsbhUfkiRNn3Dz5BkmULyZxIdsQp3xNMJ/Jp1EKYXFxMtSjk/1GNbPF89/SUFsJ8mju+lfPPix394vGFmIjEDZalsLUlQRU9K2xvpU4GWi1AKyZnnf4j75PTWXf2uWz/+JQYR0twvc9FXcdXIDfy3y4ajjZH7ru+ScPBJiyp9K4ihIAWkWAlnp9NXwb6J2qO9AoQAAAADhtlLvg2vUBWLdhuoG16gL52H65IW8fA5kCi7hDK5RF+0YA/iPxYUSbnPX/Qp5+Rzrz6vziRItGWikf/YYXKMu+erxwZs3dyt6gSXEHosLJf89Wcqd4N8gfFaNzxTy8jn1RKDWl5kmPHYvdNMSJVoy85MI3ZFOjjdw+NzYMLhGXdEOFLKz05JYUmXAtzZv7lbX2by5tQQ6U1SyaLw8FhdK3aBFpb99w09ey5GgOsG/Qdt37a65qmtEWBw5qyjk5XPJUrecq48xdko5Y5kuM014z4Ufl61YmX1M7suSJEq0ZMX85ounIWBhRpcyjiKdHG/DK06AofbIakBAmoVgcI26gcbfVeMbWb8CrQtQZqclsYcRd17lzPG0BHqjW2ze3K2NaI5C77UIqA4DWkdqCXSmi78mSelioKMI1PJMeCwulJmafHv7R/qRGvGofn77hp+fTdRw/ZBSmhwmAHV0gn+DlTQtbPfpq4YWX/lpclXXiJPjhWfxPgONEIhRYlDIy+exfpkI06Mf4jIVTQ1WH2Pst6kxA9V0t+k0wuUGXGaa8L3QyB/fDU71PrscGlqxMvu7B2AU2drm/jhstBFIlGjJqSI6Jsv/vMwqSe4jTkPAwq/1ki3NKBTHLJ5GKEQ6Od6ljGsxx1Ht2ybnvzRC7ZHVo1vDOsGGRdAgMBc/geZrrmBQOUECjb+r4zvtRIcxw6Vmh5FKBFoXoOXsRU+NSDq5bP5oVg4j7rzvlbxTi5+SsmopwF0I9Ea36UIUWJm6yIB4DJpvGtEchftnTmqfbWCLftsyZBwGtI79sOZhlRSZl3Siy3gWf02S98kffZPDMZxydWNzEKjlmfEet3axXi3zUOh/HDI1+fbTg6sZt4mF+FY/1xc04lH91VQDEr3wfORcRi4LPpuo4d8t+g67J9TvWpGGADhMAOrZ+lIFqQKO3Ui03DIqaVrYy98IN6/VJtZOY3Q5LL7y080IoDylrN/KRBqNJSbHC8/HcVkgo3t3wULNJS4gEKPEwabxK+GW5hQAILT7Yv0yEYNLYP7nQU4fBvcc8GQqmhqFnMj17Ti3AwyO5exuU2MGj+Ux6evvHwgKWU3naITLDYkymeL5ykU6GHwX1XqhkT+bF8PQ/x3tMR6rv958djk0ncBr2/VkFC0U0kbCdg/AKJe5ksfzs7wmEgXuyXDYaCORbjrM0S6gSTCY8qZSRXRMs/Mmo9f5CEI2T1qtVJLcR7UkjqjdgPFePDajsV7rJVu/XXe021dZVTrhC7pYPI1QuYrfv8lyA2coxFGIShnXYquvhY3PpatsLhP5g0zOf2mteC2GxdxScCRqAJ9Gt4Z1pwHUmsML+nsivaiUQGAufqHWfJEAAAAAQ8umh8eQPNSEW5pTzycIc4zsrvQItzSnS3ySIJ5PEObdhLZhWd8sMhoUirVRaBiVEqO+Epb4JEHVM4LGfZlRFz5S95C6CW3D+cLLRLK+WWTxdf/jdS5lsDblwzfj1kHxoB3ndiRGfSVnjduiLPFJgm867wXrYXVWqKrT0foyoy65+QWpPaKf+n5pOX01Fatddt4N2vKFl4mxTjEOZH2zyCe2FU+j7Y8c4CYpm6tau7vokR08bMqHby8BIeiHq/I5xGBUvkA7zu0D8GhqSIz6SgtHXM2PHMaezNdgGRnk4t9aL0RY3nTeC52/eIzWw+qslQhMKxFT1nhSmHD/9GVGXbeu4Noz9XqJcD7cDjtCTi54ieip/NJy+r8Z1H1qKla7KeHwPK26am/ucczopQ1eyObG+E9inWIcIVbEm4n8F0rKN7HNTmwrng2njRlG2x85BRC5voFLI+3CgIVqF7MHrFR4oSvQIzt4k+id/9iUD9+bX6lYHwQzC1zPlYwOV+VzTZxD9MnH2aeKDH8gwXDtAIK7S4cG4NHURSt3U5AY9ZXT01MSV4jJQRRDb8ZfP/3mHPRbYZivwTLbZGe1c860ZDAFEuO0Xoiw95UuN7zpvBf/IhqQe3mAwziyJkTtgaSCrkoCBSoRmFZp2j7RIqas8WFtCnblNpAlpv02oujLjLqrACo9L1uwbmyQFukn7ITJZCciTuB8uB2jtx6adoScXDVPOtuxFKCI8t8GD7mjlC/6aDKofjOo+z34DnyVUt2t1pl7KlLC4XkRCUf+WnXV3hm+c1md5ekK3i5PjQsdzUtI1mvMzI3xn49GVxjEOsU4h/FjvwOq+exAYV9rEvkvlFEyiRPVaRNAlqK1x93eJ+eeFYFgGk4bM1mFvbSMtj9yz32Z9UsmA6YI7aUhQ5E3AQBakYaEAQvVx8qtUm9gfoMsq9gEqPBCV+s75NCgR3bw44zQd2fXSiQkHOyj8S9uZbLkyOI2v1KxdXT0Nj4IZhZ9w8CR+ZhawrpT/EUcrsrnX2VsYNs+9jOY9VC004nClJBCZBMUGf5AV9JYx4Lh2gHBKnyGRXHm1Qa6QFJNxtJyDg109YpW7qbJnUghYTeb8CL8PXemp6ck5WwBo64Qk4Pt2zUEaYCvVypLCdD/eIsWvLMtkTjot8J7IxFFMF+DZXOUJeL3z7+xtAQZNuacacmlV89OIQxVHWLH85opu2G6anDHPe4rXW6t4PvpeNN5LzsY36i/Q0X7/IjjfLf0cVz0P9fbcGRNiDOv6w+bBTje2M6eWVyVBAofXqKNVCIwrRfpliqTsgx50Hmq/gVKKDhGgY6/wtoU7IERsmvKbSBLiaaGzA39HJ9ONroYFAQAAJ0HAAAsCQAAhgUAAEgFAACnBQAAAAQAADIFAAC8BQAALAkAQYDBAAv3CQwACACMAAgATAAIAMwACAAsAAgArAAIAGwACADsAAgAHAAIAJwACABcAAgA3AAIADwACAC8AAgAfAAIAPwACAACAAgAggAIAEIACADCAAgAIgAIAKIACABiAAgA4gAIABIACACSAAgAUgAIANIACAAyAAgAsgAIAHIACADyAAgACgAIAIoACABKAAgAygAIACoACACqAAgAagAIAOoACAAaAAgAmgAIAFoACADaAAgAOgAIALoACAB6AAgA+gAIAAYACACGAAgARgAIAMYACAAmAAgApgAIAGYACADmAAgAFgAIAJYACABWAAgA1gAIADYACAC2AAgAdgAIAPYACAAOAAgAjgAIAE4ACADOAAgALgAIAK4ACABuAAgA7gAIAB4ACACeAAgAXgAIAN4ACAA+AAgAvgAIAH4ACAD+AAgAAQAIAIEACABBAAgAwQAIACEACAChAAgAYQAIAOEACAARAAgAkQAIAFEACADRAAgAMQAIALEACABxAAgA8QAIAAkACACJAAgASQAIAMkACAApAAgAqQAIAGkACADpAAgAGQAIAJkACABZAAgA2QAIADkACAC5AAgAeQAIAPkACAAFAAgAhQAIAEUACADFAAgAJQAIAKUACABlAAgA5QAIABUACACVAAgAVQAIANUACAA1AAgAtQAIAHUACAD1AAgADQAIAI0ACABNAAgAzQAIAC0ACACtAAgAbQAIAO0ACAAdAAgAnQAIAF0ACADdAAgAPQAIAL0ACAB9AAgA/QAIABMACQATAQkAkwAJAJMBCQBTAAkAUwEJANMACQDTAQkAMwAJADMBCQCzAAkAswEJAHMACQBzAQkA8wAJAPMBCQALAAkACwEJAIsACQCLAQkASwAJAEsBCQDLAAkAywEJACsACQArAQkAqwAJAKsBCQBrAAkAawEJAOsACQDrAQkAGwAJABsBCQCbAAkAmwEJAFsACQBbAQkA2wAJANsBCQA7AAkAOwEJALsACQC7AQkAewAJAHsBCQD7AAkA+wEJAAcACQAHAQkAhwAJAIcBCQBHAAkARwEJAMcACQDHAQkAJwAJACcBCQCnAAkApwEJAGcACQBnAQkA5wAJAOcBCQAXAAkAFwEJAJcACQCXAQkAVwAJAFcBCQDXAAkA1wEJADcACQA3AQkAtwAJALcBCQB3AAkAdwEJAPcACQD3AQkADwAJAA8BCQCPAAkAjwEJAE8ACQBPAQkAzwAJAM8BCQAvAAkALwEJAK8ACQCvAQkAbwAJAG8BCQDvAAkA7wEJAB8ACQAfAQkAnwAJAJ8BCQBfAAkAXwEJAN8ACQDfAQkAPwAJAD8BCQC/AAkAvwEJAH8ACQB/AQkA/wAJAP8BCQAAAAcAQAAHACAABwBgAAcAEAAHAFAABwAwAAcAcAAHAAgABwBIAAcAKAAHAGgABwAYAAcAWAAHADgABwB4AAcABAAHAEQABwAkAAcAZAAHABQABwBUAAcANAAHAHQABwADAAgAgwAIAEMACADDAAgAIwAIAKMACABjAAgA4wAIAAAABQAQAAUACAAFABgABQAEAAUAFAAFAAwABQAcAAUAAgAFABIABQAKAAUAGgAFAAYABQAWAAUADgAFAB4ABQABAAUAEQAFAAkABQAZAAUABQAFABUABQANAAUAHQAFAAMABQATAAUACwAFABsABQAHAAUAFwAFAEGBywAL7AYBAgMEBAUFBgYGBgcHBwcICAgICAgICAkJCQkJCQkJCgoKCgoKCgoKCgoKCgoKCgsLCwsLCwsLCwsLCwsLCwsMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8AABAREhITExQUFBQVFRUVFhYWFhYWFhYXFxcXFxcXFxgYGBgYGBgYGBgYGBgYGBgZGRkZGRkZGRkZGRkZGRkZGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhobGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwdHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dAAECAwQFBgcICAkJCgoLCwwMDAwNDQ0NDg4ODg8PDw8QEBAQEBAQEBEREREREREREhISEhISEhITExMTExMTExQUFBQUFBQUFBQUFBQUFBQVFRUVFRUVFRUVFRUVFRUVFhYWFhYWFhYWFhYWFhYWFhcXFxcXFxcXFxcXFxcXFxcYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGRkZGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhobGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbHAAAAAABAAAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAoAAAAMAAAADgAAABAAAAAUAAAAGAAAABwAAAAgAAAAKAAAADAAAAA4AAAAQAAAAFAAAABgAAAAcAAAAIAAAACgAAAAwAAAAOAAQYTSAAutAQEAAAACAAAAAwAAAAQAAAAGAAAACAAAAAwAAAAQAAAAGAAAACAAAAAwAAAAQAAAAGAAAACAAAAAwAAAAAABAACAAQAAAAIAAAADAAAABAAAAAYAAAAIAAAADAAAABAAAAAYAAAAIAAAADAAAABAAAAAYAAAgCAAAMApAAABAQAAHgEAAA8AAAAAJQAAQCoAAAAAAAAeAAAADwAAAAAAAADAKgAAAAAAABMAAAAHAEHg0wALTQEAAAABAAAAAQAAAAEAAAACAAAAAgAAAAIAAAACAAAAAwAAAAMAAAADAAAAAwAAAAQAAAAEAAAABAAAAAQAAAAFAAAABQAAAAUAAAAFAEHQ1AALZQEAAAABAAAAAgAAAAIAAAADAAAAAwAAAAQAAAAEAAAABQAAAAUAAAAGAAAABgAAAAcAAAAHAAAACAAAAAgAAAAJAAAACQAAAAoAAAAKAAAACwAAAAsAAAAMAAAADAAAAA0AAAANAEGA1gALIwIAAAADAAAABwAAAAAAAAAQERIACAcJBgoFCwQMAw0CDgEPAEHQ1gALTQEAAAABAAAAAQAAAAEAAAACAAAAAgAAAAIAAAACAAAAAwAAAAMAAAADAAAAAwAAAAQAAAAEAAAABAAAAAQAAAAFAAAABQAAAAUAAAAFAEHA1wALZQEAAAABAAAAAgAAAAIAAAADAAAAAwAAAAQAAAAEAAAABQAAAAUAAAAGAAAABgAAAAcAAAAHAAAACAAAAAgAAAAJAAAACQAAAAoAAAAKAAAACwAAAAsAAAAMAAAADAAAAA0AAAANAEG42AALASwAQcTYAAthLQAAAAQABAAIAAQALgAAAAQABgAQAAYALwAAAAQADAAgABgALwAAAAgAEAAgACAALwAAAAgAEACAAIAALwAAAAgAIACAAAABMAAAACAAgAACAQAEMAAAACAAAgECAQAQMABBsNkAC6UTAwAEAAUABgAHAAgACQAKAAsADQAPABEAEwAXABsAHwAjACsAMwA7AEMAUwBjAHMAgwCjAMMA4wACAQAAAAAAABAAEAAQABAAEAAQABAAEAARABEAEQARABIAEgASABIAEwATABMAEwAUABQAFAAUABUAFQAVABUAEABNAMoAAAABAAIAAwAEAAUABwAJAA0AEQAZACEAMQBBAGEAgQDBAAEBgQEBAgEDAQQBBgEIAQwBEAEYASABMAFAAWAAAAAAEAAQABAAEAARABEAEgASABMAEwAUABQAFQAVABYAFgAXABcAGAAYABkAGQAaABoAGwAbABwAHAAdAB0AQABAAGAHAAAACFAAAAgQABQIcwASBx8AAAhwAAAIMAAACcAAEAcKAAAIYAAACCAAAAmgAAAIAAAACIAAAAhAAAAJ4AAQBwYAAAhYAAAIGAAACZAAEwc7AAAIeAAACDgAAAnQABEHEQAACGgAAAgoAAAJsAAACAgAAAiIAAAISAAACfAAEAcEAAAIVAAACBQAFQjjABMHKwAACHQAAAg0AAAJyAARBw0AAAhkAAAIJAAACagAAAgEAAAIhAAACEQAAAnoABAHCAAACFwAAAgcAAAJmAAUB1MAAAh8AAAIPAAACdgAEgcXAAAIbAAACCwAAAm4AAAIDAAACIwAAAhMAAAJ+AAQBwMAAAhSAAAIEgAVCKMAEwcjAAAIcgAACDIAAAnEABEHCwAACGIAAAgiAAAJpAAACAIAAAiCAAAIQgAACeQAEAcHAAAIWgAACBoAAAmUABQHQwAACHoAAAg6AAAJ1AASBxMAAAhqAAAIKgAACbQAAAgKAAAIigAACEoAAAn0ABAHBQAACFYAAAgWAEAIAAATBzMAAAh2AAAINgAACcwAEQcPAAAIZgAACCYAAAmsAAAIBgAACIYAAAhGAAAJ7AAQBwkAAAheAAAIHgAACZwAFAdjAAAIfgAACD4AAAncABIHGwAACG4AAAguAAAJvAAACA4AAAiOAAAITgAACfwAYAcAAAAIUQAACBEAFQiDABIHHwAACHEAAAgxAAAJwgAQBwoAAAhhAAAIIQAACaIAAAgBAAAIgQAACEEAAAniABAHBgAACFkAAAgZAAAJkgATBzsAAAh5AAAIOQAACdIAEQcRAAAIaQAACCkAAAmyAAAICQAACIkAAAhJAAAJ8gAQBwQAAAhVAAAIFQAQCAIBEwcrAAAIdQAACDUAAAnKABEHDQAACGUAAAglAAAJqgAACAUAAAiFAAAIRQAACeoAEAcIAAAIXQAACB0AAAmaABQHUwAACH0AAAg9AAAJ2gASBxcAAAhtAAAILQAACboAAAgNAAAIjQAACE0AAAn6ABAHAwAACFMAAAgTABUIwwATByMAAAhzAAAIMwAACcYAEQcLAAAIYwAACCMAAAmmAAAIAwAACIMAAAhDAAAJ5gAQBwcAAAhbAAAIGwAACZYAFAdDAAAIewAACDsAAAnWABIHEwAACGsAAAgrAAAJtgAACAsAAAiLAAAISwAACfYAEAcFAAAIVwAACBcAQAgAABMHMwAACHcAAAg3AAAJzgARBw8AAAhnAAAIJwAACa4AAAgHAAAIhwAACEcAAAnuABAHCQAACF8AAAgfAAAJngAUB2MAAAh/AAAIPwAACd4AEgcbAAAIbwAACC8AAAm+AAAIDwAACI8AAAhPAAAJ/gBgBwAAAAhQAAAIEAAUCHMAEgcfAAAIcAAACDAAAAnBABAHCgAACGAAAAggAAAJoQAACAAAAAiAAAAIQAAACeEAEAcGAAAIWAAACBgAAAmRABMHOwAACHgAAAg4AAAJ0QARBxEAAAhoAAAIKAAACbEAAAgIAAAIiAAACEgAAAnxABAHBAAACFQAAAgUABUI4wATBysAAAh0AAAINAAACckAEQcNAAAIZAAACCQAAAmpAAAIBAAACIQAAAhEAAAJ6QAQBwgAAAhcAAAIHAAACZkAFAdTAAAIfAAACDwAAAnZABIHFwAACGwAAAgsAAAJuQAACAwAAAiMAAAITAAACfkAEAcDAAAIUgAACBIAFQijABMHIwAACHIAAAgyAAAJxQARBwsAAAhiAAAIIgAACaUAAAgCAAAIggAACEIAAAnlABAHBwAACFoAAAgaAAAJlQAUB0MAAAh6AAAIOgAACdUAEgcTAAAIagAACCoAAAm1AAAICgAACIoAAAhKAAAJ9QAQBwUAAAhWAAAIFgBACAAAEwczAAAIdgAACDYAAAnNABEHDwAACGYAAAgmAAAJrQAACAYAAAiGAAAIRgAACe0AEAcJAAAIXgAACB4AAAmdABQHYwAACH4AAAg+AAAJ3QASBxsAAAhuAAAILgAACb0AAAgOAAAIjgAACE4AAAn9AGAHAAAACFEAAAgRABUIgwASBx8AAAhxAAAIMQAACcMAEAcKAAAIYQAACCEAAAmjAAAIAQAACIEAAAhBAAAJ4wAQBwYAAAhZAAAIGQAACZMAEwc7AAAIeQAACDkAAAnTABEHEQAACGkAAAgpAAAJswAACAkAAAiJAAAISQAACfMAEAcEAAAIVQAACBUAEAgCARMHKwAACHUAAAg1AAAJywARBw0AAAhlAAAIJQAACasAAAgFAAAIhQAACEUAAAnrABAHCAAACF0AAAgdAAAJmwAUB1MAAAh9AAAIPQAACdsAEgcXAAAIbQAACC0AAAm7AAAIDQAACI0AAAhNAAAJ+wAQBwMAAAhTAAAIEwAVCMMAEwcjAAAIcwAACDMAAAnHABEHCwAACGMAAAgjAAAJpwAACAMAAAiDAAAIQwAACecAEAcHAAAIWwAACBsAAAmXABQHQwAACHsAAAg7AAAJ1wASBxMAAAhrAAAIKwAACbcAAAgLAAAIiwAACEsAAAn3ABAHBQAACFcAAAgXAEAIAAATBzMAAAh3AAAINwAACc8AEQcPAAAIZwAACCcAAAmvAAAIBwAACIcAAAhHAAAJ7wAQBwkAAAhfAAAIHwAACZ8AFAdjAAAIfwAACD8AAAnfABIHGwAACG8AAAgvAAAJvwAACA8AAAiPAAAITwAACf8AEAUBABcFAQETBREAGwUBEBEFBQAZBQEEFQVBAB0FAUAQBQMAGAUBAhQFIQAcBQEgEgUJABoFAQgWBYEAQAUAABAFAgAXBYEBEwUZABsFARgRBQcAGQUBBhUFYQAdBQFgEAUEABgFAQMUBTEAHAUBMBIFDQAaBQEMFgXBAEAFAAAQABEAEgAAAAgABwAJAAYACgAFAAsABAAMAAMADQACAA4AAQAPAEHg7AALQREACgAREREAAAAABQAAAAAAAAkAAAAACwAAAAAAAAAAEQAPChEREQMKBwABAAkLCwAACQYLAAALAAYRAAAAERERAEGx7QALIQsAAAAAAAAAABEACgoREREACgAAAgAJCwAAAAkACwAACwBB6+0ACwEMAEH37QALFQwAAAAADAAAAAAJDAAAAAAADAAADABBpe4ACwEOAEGx7gALFQ0AAAAEDQAAAAAJDgAAAAAADgAADgBB3+4ACwEQAEHr7gALHg8AAAAADwAAAAAJEAAAAAAAEAAAEAAAEgAAABISEgBBou8ACw4SAAAAEhISAAAAAAAACQBB0+8ACwELAEHf7wALFQoAAAAACgAAAAAJCwAAAAAACwAACwBBjfAACwEMAEGZ8AALJwwAAAAADAAAAAAJDAAAAAAADAAADAAAMDEyMzQ1Njc4OUFCQ0RFRgBB5PAACwE+AEGL8QALBf//////AEHQ8QALVxkSRDsCPyxHFD0zMAobBkZLRTcPSQ6OFwNAHTxpKzYfSi0cASAlKSEIDBUWIi4QOD4LNDEYZHR1di9BCX85ESNDMkKJiosFBCYoJw0qHjWMBxpIkxOUlQBBsPIAC4oOSWxsZWdhbCBieXRlIHNlcXVlbmNlAERvbWFpbiBlcnJvcgBSZXN1bHQgbm90IHJlcHJlc2VudGFibGUATm90IGEgdHR5AFBlcm1pc3Npb24gZGVuaWVkAE9wZXJhdGlvbiBub3QgcGVybWl0dGVkAE5vIHN1Y2ggZmlsZSBvciBkaXJlY3RvcnkATm8gc3VjaCBwcm9jZXNzAEZpbGUgZXhpc3RzAFZhbHVlIHRvbyBsYXJnZSBmb3IgZGF0YSB0eXBlAE5vIHNwYWNlIGxlZnQgb24gZGV2aWNlAE91dCBvZiBtZW1vcnkAUmVzb3VyY2UgYnVzeQBJbnRlcnJ1cHRlZCBzeXN0ZW0gY2FsbABSZXNvdXJjZSB0ZW1wb3JhcmlseSB1bmF2YWlsYWJsZQBJbnZhbGlkIHNlZWsAQ3Jvc3MtZGV2aWNlIGxpbmsAUmVhZC1vbmx5IGZpbGUgc3lzdGVtAERpcmVjdG9yeSBub3QgZW1wdHkAQ29ubmVjdGlvbiByZXNldCBieSBwZWVyAE9wZXJhdGlvbiB0aW1lZCBvdXQAQ29ubmVjdGlvbiByZWZ1c2VkAEhvc3QgaXMgZG93bgBIb3N0IGlzIHVucmVhY2hhYmxlAEFkZHJlc3MgaW4gdXNlAEJyb2tlbiBwaXBlAEkvTyBlcnJvcgBObyBzdWNoIGRldmljZSBvciBhZGRyZXNzAEJsb2NrIGRldmljZSByZXF1aXJlZABObyBzdWNoIGRldmljZQBOb3QgYSBkaXJlY3RvcnkASXMgYSBkaXJlY3RvcnkAVGV4dCBmaWxlIGJ1c3kARXhlYyBmb3JtYXQgZXJyb3IASW52YWxpZCBhcmd1bWVudABBcmd1bWVudCBsaXN0IHRvbyBsb25nAFN5bWJvbGljIGxpbmsgbG9vcABGaWxlbmFtZSB0b28gbG9uZwBUb28gbWFueSBvcGVuIGZpbGVzIGluIHN5c3RlbQBObyBmaWxlIGRlc2NyaXB0b3JzIGF2YWlsYWJsZQBCYWQgZmlsZSBkZXNjcmlwdG9yAE5vIGNoaWxkIHByb2Nlc3MAQmFkIGFkZHJlc3MARmlsZSB0b28gbGFyZ2UAVG9vIG1hbnkgbGlua3MATm8gbG9ja3MgYXZhaWxhYmxlAFJlc291cmNlIGRlYWRsb2NrIHdvdWxkIG9jY3VyAFN0YXRlIG5vdCByZWNvdmVyYWJsZQBQcmV2aW91cyBvd25lciBkaWVkAE9wZXJhdGlvbiBjYW5jZWxlZABGdW5jdGlvbiBub3QgaW1wbGVtZW50ZWQATm8gbWVzc2FnZSBvZiBkZXNpcmVkIHR5cGUASWRlbnRpZmllciByZW1vdmVkAERldmljZSBub3QgYSBzdHJlYW0ATm8gZGF0YSBhdmFpbGFibGUARGV2aWNlIHRpbWVvdXQAT3V0IG9mIHN0cmVhbXMgcmVzb3VyY2VzAExpbmsgaGFzIGJlZW4gc2V2ZXJlZABQcm90b2NvbCBlcnJvcgBCYWQgbWVzc2FnZQBGaWxlIGRlc2NyaXB0b3IgaW4gYmFkIHN0YXRlAE5vdCBhIHNvY2tldABEZXN0aW5hdGlvbiBhZGRyZXNzIHJlcXVpcmVkAE1lc3NhZ2UgdG9vIGxhcmdlAFByb3RvY29sIHdyb25nIHR5cGUgZm9yIHNvY2tldABQcm90b2NvbCBub3QgYXZhaWxhYmxlAFByb3RvY29sIG5vdCBzdXBwb3J0ZWQAU29ja2V0IHR5cGUgbm90IHN1cHBvcnRlZABOb3Qgc3VwcG9ydGVkAFByb3RvY29sIGZhbWlseSBub3Qgc3VwcG9ydGVkAEFkZHJlc3MgZmFtaWx5IG5vdCBzdXBwb3J0ZWQgYnkgcHJvdG9jb2wAQWRkcmVzcyBub3QgYXZhaWxhYmxlAE5ldHdvcmsgaXMgZG93bgBOZXR3b3JrIHVucmVhY2hhYmxlAENvbm5lY3Rpb24gcmVzZXQgYnkgbmV0d29yawBDb25uZWN0aW9uIGFib3J0ZWQATm8gYnVmZmVyIHNwYWNlIGF2YWlsYWJsZQBTb2NrZXQgaXMgY29ubmVjdGVkAFNvY2tldCBub3QgY29ubmVjdGVkAENhbm5vdCBzZW5kIGFmdGVyIHNvY2tldCBzaHV0ZG93bgBPcGVyYXRpb24gYWxyZWFkeSBpbiBwcm9ncmVzcwBPcGVyYXRpb24gaW4gcHJvZ3Jlc3MAU3RhbGUgZmlsZSBoYW5kbGUAUmVtb3RlIEkvTyBlcnJvcgBRdW90YSBleGNlZWRlZABObyBtZWRpdW0gZm91bmQAV3JvbmcgbWVkaXVtIHR5cGUATm8gZXJyb3IgaW5mb3JtYXRpb24AQcCAAQuFARMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAgERQADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADIAAAAzAAAANAAAADUAAAA2AAAANwAAADgAQfSCAQsCXEQAQbCDAQsQ/////////////////////w==\";Co(Hi)||(Hi=b(Hi));function eo(Ke){try{if(Ke==Hi&&le)return new Uint8Array(le);var st=Me(Ke);if(st)return st;if(T)return T(Ke);throw\"sync fetching of the wasm failed: you can preload it to Module['wasmBinary'] manually, or emcc.py will do that for you when generating HTML (but not JS)\"}catch(St){ts(St)}}function wo(Ke,st){var St,lr,te;try{te=eo(Ke),lr=new WebAssembly.Module(te),St=new WebAssembly.Instance(lr,st)}catch(Oe){var Ee=Oe.toString();throw ee(\"failed to compile wasm module: \"+Ee),(Ee.includes(\"imported Memory\")||Ee.includes(\"memory import\"))&&ee(\"Memory size incompatibility issues may be due to changing INITIAL_MEMORY at runtime to something too large. Use ALLOW_MEMORY_GROWTH to allow any size memory (and also make sure not to set INITIAL_MEMORY at runtime to something smaller than it was at compile time).\"),Oe}return[St,lr]}function QA(){var Ke={a:cu};function st(te,Ee){var Oe=te.exports;r.asm=Oe,Be=r.asm.g,z(Be.buffer),$=r.asm.W,gn(r.asm.h),Io(\"wasm-instantiate\")}if(ai(\"wasm-instantiate\"),r.instantiateWasm)try{var St=r.instantiateWasm(Ke,st);return St}catch(te){return ee(\"Module.instantiateWasm callback failed with error: \"+te),!1}var lr=wo(Hi,Ke);return st(lr[0]),r.asm}function Af(Ke){return F.getFloat32(Ke,!0)}function dh(Ke){return F.getFloat64(Ke,!0)}function mh(Ke){return F.getInt16(Ke,!0)}function to(Ke){return F.getInt32(Ke,!0)}function jn(Ke,st){F.setInt32(Ke,st,!0)}function Rs(Ke){for(;Ke.length>0;){var st=Ke.shift();if(typeof st==\"function\"){st(r);continue}var St=st.func;typeof St==\"number\"?st.arg===void 0?$.get(St)():$.get(St)(st.arg):St(st.arg===void 0?null:st.arg)}}function ro(Ke,st){var St=new Date(to((Ke>>2)*4)*1e3);jn((st>>2)*4,St.getUTCSeconds()),jn((st+4>>2)*4,St.getUTCMinutes()),jn((st+8>>2)*4,St.getUTCHours()),jn((st+12>>2)*4,St.getUTCDate()),jn((st+16>>2)*4,St.getUTCMonth()),jn((st+20>>2)*4,St.getUTCFullYear()-1900),jn((st+24>>2)*4,St.getUTCDay()),jn((st+36>>2)*4,0),jn((st+32>>2)*4,0);var lr=Date.UTC(St.getUTCFullYear(),0,1,0,0,0,0),te=(St.getTime()-lr)/(1e3*60*60*24)|0;return jn((st+28>>2)*4,te),ro.GMTString||(ro.GMTString=rt(\"GMT\")),jn((st+40>>2)*4,ro.GMTString),st}function ou(Ke,st){return ro(Ke,st)}function au(Ke,st,St){ke.copyWithin(Ke,st,st+St)}function lu(Ke){try{return Be.grow(Ke-be.byteLength+65535>>>16),z(Be.buffer),1}catch{}}function RA(Ke){var st=ke.length;Ke=Ke>>>0;var St=2147483648;if(Ke>St)return!1;for(var lr=1;lr<=4;lr*=2){var te=st*(1+.2/lr);te=Math.min(te,Ke+100663296);var Ee=Math.min(St,Ne(Math.max(Ke,te),65536)),Oe=lu(Ee);if(Oe)return!0}return!1}function TA(Ke){ue(Ke)}function oa(Ke){var st=Date.now()/1e3|0;return Ke&&jn((Ke>>2)*4,st),st}function aa(){if(aa.called)return;aa.called=!0;var Ke=new Date().getFullYear(),st=new Date(Ke,0,1),St=new Date(Ke,6,1),lr=st.getTimezoneOffset(),te=St.getTimezoneOffset(),Ee=Math.max(lr,te);jn((vl()>>2)*4,Ee*60),jn((Is()>>2)*4,+(lr!=te));function Oe(An){var li=An.toTimeString().match(/\\(([A-Za-z ]+)\\)$/);return li?li[1]:\"GMT\"}var dt=Oe(st),Et=Oe(St),Pt=rt(dt),tr=rt(Et);te<lr?(jn((Mi()>>2)*4,Pt),jn((Mi()+4>>2)*4,tr)):(jn((Mi()>>2)*4,tr),jn((Mi()+4>>2)*4,Pt))}function FA(Ke){aa();var st=Date.UTC(to((Ke+20>>2)*4)+1900,to((Ke+16>>2)*4),to((Ke+12>>2)*4),to((Ke+8>>2)*4),to((Ke+4>>2)*4),to((Ke>>2)*4),0),St=new Date(st);jn((Ke+24>>2)*4,St.getUTCDay());var lr=Date.UTC(St.getUTCFullYear(),0,1,0,0,0,0),te=(St.getTime()-lr)/(1e3*60*60*24)|0;return jn((Ke+28>>2)*4,te),St.getTime()/1e3|0}var gr=typeof atob==\"function\"?atob:function(Ke){var st=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\",St=\"\",lr,te,Ee,Oe,dt,Et,Pt,tr=0;Ke=Ke.replace(/[^A-Za-z0-9\\+\\/\\=]/g,\"\");do Oe=st.indexOf(Ke.charAt(tr++)),dt=st.indexOf(Ke.charAt(tr++)),Et=st.indexOf(Ke.charAt(tr++)),Pt=st.indexOf(Ke.charAt(tr++)),lr=Oe<<2|dt>>4,te=(dt&15)<<4|Et>>2,Ee=(Et&3)<<6|Pt,St=St+String.fromCharCode(lr),Et!==64&&(St=St+String.fromCharCode(te)),Pt!==64&&(St=St+String.fromCharCode(Ee));while(tr<Ke.length);return St};function Bo(Ke){if(typeof C==\"boolean\"&&C){var st;try{st=Buffer.from(Ke,\"base64\")}catch{st=new Buffer(Ke,\"base64\")}return new Uint8Array(st.buffer,st.byteOffset,st.byteLength)}try{for(var St=gr(Ke),lr=new Uint8Array(St.length),te=0;te<St.length;++te)lr[te]=St.charCodeAt(te);return lr}catch{throw new Error(\"Converting base64 string to bytes failed.\")}}function Me(Ke){if(Co(Ke))return Bo(Ke.slice($s.length))}var cu={e:ou,c:au,d:RA,a:TA,b:oa,f:FA},Cr=QA(),pf=r.___wasm_call_ctors=Cr.h,NA=r._zip_ext_count_symlinks=Cr.i,OA=r._zip_file_get_external_attributes=Cr.j,uu=r._zipstruct_statS=Cr.k,fu=r._zipstruct_stat_size=Cr.l,oc=r._zipstruct_stat_mtime=Cr.m,ve=r._zipstruct_stat_crc=Cr.n,Nt=r._zipstruct_errorS=Cr.o,ac=r._zipstruct_error_code_zip=Cr.p,Oi=r._zipstruct_stat_comp_size=Cr.q,no=r._zipstruct_stat_comp_method=Cr.r,Tt=r._zip_close=Cr.s,xn=r._zip_delete=Cr.t,la=r._zip_dir_add=Cr.u,ji=r._zip_discard=Cr.v,Li=r._zip_error_init_with_code=Cr.w,Na=r._zip_get_error=Cr.x,dn=r._zip_file_get_error=Cr.y,Kn=r._zip_error_strerror=Cr.z,Au=r._zip_fclose=Cr.A,yh=r._zip_file_add=Cr.B,Oa=r._free=Cr.C,La=r._malloc=Cr.D,Ma=r._zip_source_error=Cr.E,$e=r._zip_source_seek=Cr.F,Ua=r._zip_file_set_external_attributes=Cr.G,hf=r._zip_file_set_mtime=Cr.H,lc=r._zip_fopen_index=Cr.I,wn=r._zip_fread=Cr.J,ca=r._zip_get_name=Cr.K,LA=r._zip_get_num_entries=Cr.L,MA=r._zip_source_read=Cr.M,ua=r._zip_name_locate=Cr.N,Bl=r._zip_open_from_source=Cr.O,Mt=r._zip_set_file_compression=Cr.P,kn=r._zip_source_buffer=Cr.Q,fa=r._zip_source_buffer_create=Cr.R,Ha=r._zip_source_close=Cr.S,rs=r._zip_source_free=Cr.T,cc=r._zip_source_keep=Cr.U,pu=r._zip_source_open=Cr.V,uc=r._zip_source_tell=Cr.X,ja=r._zip_stat_index=Cr.Y,Mi=r.__get_tzname=Cr.Z,Is=r.__get_daylight=Cr._,vl=r.__get_timezone=Cr.$,gf=r.stackSave=Cr.aa,fc=r.stackRestore=Cr.ba,wi=r.stackAlloc=Cr.ca;r.cwrap=se,r.getValue=pe;var Qn;nn=function Ke(){Qn||Ac(),Qn||(nn=Ke)};function Ac(Ke){if(Ke=Ke||f,Ir>0||(Ct(),Ir>0))return;function st(){Qn||(Qn=!0,r.calledRun=!0,!Ce&&(qt(),s(r),r.onRuntimeInitialized&&r.onRuntimeInitialized(),ir()))}r.setStatus?(r.setStatus(\"Running...\"),setTimeout(function(){setTimeout(function(){r.setStatus(\"\")},1),st()},1)):st()}if(r.run=Ac,r.preInit)for(typeof r.preInit==\"function\"&&(r.preInit=[r.preInit]);r.preInit.length>0;)r.preInit.pop()();return Ac(),e}}();typeof CR==\"object\"&&typeof Sj==\"object\"?Sj.exports=vj:typeof define==\"function\"&&define.amd?define([],function(){return vj}):typeof CR==\"object\"&&(CR.createModule=vj)});var Up,upe,fpe,Ape=Ze(()=>{Up=[\"number\",\"number\"],upe=(X=>(X[X.ZIP_ER_OK=0]=\"ZIP_ER_OK\",X[X.ZIP_ER_MULTIDISK=1]=\"ZIP_ER_MULTIDISK\",X[X.ZIP_ER_RENAME=2]=\"ZIP_ER_RENAME\",X[X.ZIP_ER_CLOSE=3]=\"ZIP_ER_CLOSE\",X[X.ZIP_ER_SEEK=4]=\"ZIP_ER_SEEK\",X[X.ZIP_ER_READ=5]=\"ZIP_ER_READ\",X[X.ZIP_ER_WRITE=6]=\"ZIP_ER_WRITE\",X[X.ZIP_ER_CRC=7]=\"ZIP_ER_CRC\",X[X.ZIP_ER_ZIPCLOSED=8]=\"ZIP_ER_ZIPCLOSED\",X[X.ZIP_ER_NOENT=9]=\"ZIP_ER_NOENT\",X[X.ZIP_ER_EXISTS=10]=\"ZIP_ER_EXISTS\",X[X.ZIP_ER_OPEN=11]=\"ZIP_ER_OPEN\",X[X.ZIP_ER_TMPOPEN=12]=\"ZIP_ER_TMPOPEN\",X[X.ZIP_ER_ZLIB=13]=\"ZIP_ER_ZLIB\",X[X.ZIP_ER_MEMORY=14]=\"ZIP_ER_MEMORY\",X[X.ZIP_ER_CHANGED=15]=\"ZIP_ER_CHANGED\",X[X.ZIP_ER_COMPNOTSUPP=16]=\"ZIP_ER_COMPNOTSUPP\",X[X.ZIP_ER_EOF=17]=\"ZIP_ER_EOF\",X[X.ZIP_ER_INVAL=18]=\"ZIP_ER_INVAL\",X[X.ZIP_ER_NOZIP=19]=\"ZIP_ER_NOZIP\",X[X.ZIP_ER_INTERNAL=20]=\"ZIP_ER_INTERNAL\",X[X.ZIP_ER_INCONS=21]=\"ZIP_ER_INCONS\",X[X.ZIP_ER_REMOVE=22]=\"ZIP_ER_REMOVE\",X[X.ZIP_ER_DELETED=23]=\"ZIP_ER_DELETED\",X[X.ZIP_ER_ENCRNOTSUPP=24]=\"ZIP_ER_ENCRNOTSUPP\",X[X.ZIP_ER_RDONLY=25]=\"ZIP_ER_RDONLY\",X[X.ZIP_ER_NOPASSWD=26]=\"ZIP_ER_NOPASSWD\",X[X.ZIP_ER_WRONGPASSWD=27]=\"ZIP_ER_WRONGPASSWD\",X[X.ZIP_ER_OPNOTSUPP=28]=\"ZIP_ER_OPNOTSUPP\",X[X.ZIP_ER_INUSE=29]=\"ZIP_ER_INUSE\",X[X.ZIP_ER_TELL=30]=\"ZIP_ER_TELL\",X[X.ZIP_ER_COMPRESSED_DATA=31]=\"ZIP_ER_COMPRESSED_DATA\",X))(upe||{}),fpe=t=>({get HEAPU8(){return t.HEAPU8},errors:upe,SEEK_SET:0,SEEK_CUR:1,SEEK_END:2,ZIP_CHECKCONS:4,ZIP_EXCL:2,ZIP_RDONLY:16,ZIP_FL_OVERWRITE:8192,ZIP_FL_COMPRESSED:4,ZIP_OPSYS_DOS:0,ZIP_OPSYS_AMIGA:1,ZIP_OPSYS_OPENVMS:2,ZIP_OPSYS_UNIX:3,ZIP_OPSYS_VM_CMS:4,ZIP_OPSYS_ATARI_ST:5,ZIP_OPSYS_OS_2:6,ZIP_OPSYS_MACINTOSH:7,ZIP_OPSYS_Z_SYSTEM:8,ZIP_OPSYS_CPM:9,ZIP_OPSYS_WINDOWS_NTFS:10,ZIP_OPSYS_MVS:11,ZIP_OPSYS_VSE:12,ZIP_OPSYS_ACORN_RISC:13,ZIP_OPSYS_VFAT:14,ZIP_OPSYS_ALTERNATE_MVS:15,ZIP_OPSYS_BEOS:16,ZIP_OPSYS_TANDEM:17,ZIP_OPSYS_OS_400:18,ZIP_OPSYS_OS_X:19,ZIP_CM_DEFAULT:-1,ZIP_CM_STORE:0,ZIP_CM_DEFLATE:8,uint08S:t._malloc(1),uint32S:t._malloc(4),malloc:t._malloc,free:t._free,getValue:t.getValue,openFromSource:t.cwrap(\"zip_open_from_source\",\"number\",[\"number\",\"number\",\"number\"]),close:t.cwrap(\"zip_close\",\"number\",[\"number\"]),discard:t.cwrap(\"zip_discard\",null,[\"number\"]),getError:t.cwrap(\"zip_get_error\",\"number\",[\"number\"]),getName:t.cwrap(\"zip_get_name\",\"string\",[\"number\",\"number\",\"number\"]),getNumEntries:t.cwrap(\"zip_get_num_entries\",\"number\",[\"number\",\"number\"]),delete:t.cwrap(\"zip_delete\",\"number\",[\"number\",\"number\"]),statIndex:t.cwrap(\"zip_stat_index\",\"number\",[\"number\",...Up,\"number\",\"number\"]),fopenIndex:t.cwrap(\"zip_fopen_index\",\"number\",[\"number\",...Up,\"number\"]),fread:t.cwrap(\"zip_fread\",\"number\",[\"number\",\"number\",\"number\",\"number\"]),fclose:t.cwrap(\"zip_fclose\",\"number\",[\"number\"]),dir:{add:t.cwrap(\"zip_dir_add\",\"number\",[\"number\",\"string\"])},file:{add:t.cwrap(\"zip_file_add\",\"number\",[\"number\",\"string\",\"number\",\"number\"]),getError:t.cwrap(\"zip_file_get_error\",\"number\",[\"number\"]),getExternalAttributes:t.cwrap(\"zip_file_get_external_attributes\",\"number\",[\"number\",...Up,\"number\",\"number\",\"number\"]),setExternalAttributes:t.cwrap(\"zip_file_set_external_attributes\",\"number\",[\"number\",...Up,\"number\",\"number\",\"number\"]),setMtime:t.cwrap(\"zip_file_set_mtime\",\"number\",[\"number\",...Up,\"number\",\"number\"]),setCompression:t.cwrap(\"zip_set_file_compression\",\"number\",[\"number\",...Up,\"number\",\"number\"])},ext:{countSymlinks:t.cwrap(\"zip_ext_count_symlinks\",\"number\",[\"number\"])},error:{initWithCode:t.cwrap(\"zip_error_init_with_code\",null,[\"number\",\"number\"]),strerror:t.cwrap(\"zip_error_strerror\",\"string\",[\"number\"])},name:{locate:t.cwrap(\"zip_name_locate\",\"number\",[\"number\",\"string\",\"number\"])},source:{fromUnattachedBuffer:t.cwrap(\"zip_source_buffer_create\",\"number\",[\"number\",...Up,\"number\",\"number\"]),fromBuffer:t.cwrap(\"zip_source_buffer\",\"number\",[\"number\",\"number\",...Up,\"number\"]),free:t.cwrap(\"zip_source_free\",null,[\"number\"]),keep:t.cwrap(\"zip_source_keep\",null,[\"number\"]),open:t.cwrap(\"zip_source_open\",\"number\",[\"number\"]),close:t.cwrap(\"zip_source_close\",\"number\",[\"number\"]),seek:t.cwrap(\"zip_source_seek\",\"number\",[\"number\",...Up,\"number\"]),tell:t.cwrap(\"zip_source_tell\",\"number\",[\"number\"]),read:t.cwrap(\"zip_source_read\",\"number\",[\"number\",\"number\",\"number\"]),error:t.cwrap(\"zip_source_error\",\"number\",[\"number\"])},struct:{statS:t.cwrap(\"zipstruct_statS\",\"number\",[]),statSize:t.cwrap(\"zipstruct_stat_size\",\"number\",[\"number\"]),statCompSize:t.cwrap(\"zipstruct_stat_comp_size\",\"number\",[\"number\"]),statCompMethod:t.cwrap(\"zipstruct_stat_comp_method\",\"number\",[\"number\"]),statMtime:t.cwrap(\"zipstruct_stat_mtime\",\"number\",[\"number\"]),statCrc:t.cwrap(\"zipstruct_stat_crc\",\"number\",[\"number\"]),errorS:t.cwrap(\"zipstruct_errorS\",\"number\",[]),errorCodeZip:t.cwrap(\"zipstruct_error_code_zip\",\"number\",[\"number\"])}})});function Dj(t,e){let r=t.indexOf(e);if(r<=0)return null;let s=r;for(;r>=0&&(s=r+e.length,t[s]!==J.sep);){if(t[r-1]===J.sep)return null;r=t.indexOf(e,s)}return t.length>s&&t[s]!==J.sep?null:t.slice(0,s)}var $f,ppe=Ze(()=>{Dt();Dt();eA();$f=class t extends e0{static async openPromise(e,r){let s=new t(r);try{return await e(s)}finally{s.saveAndClose()}}constructor(e={}){let r=e.fileExtensions,s=e.readOnlyArchives,a=typeof r>\"u\"?f=>Dj(f,\".zip\"):f=>{for(let p of r){let h=Dj(f,p);if(h)return h}return null},n=(f,p)=>new As(p,{baseFs:f,readOnly:s,stats:f.statSync(p),customZipImplementation:e.customZipImplementation}),c=async(f,p)=>{let h={baseFs:f,readOnly:s,stats:await f.statPromise(p),customZipImplementation:e.customZipImplementation};return()=>new As(p,h)};super({...e,factorySync:n,factoryPromise:c,getMountPoint:a})}}});var Pj,BI,bj=Ze(()=>{Bj();Pj=class extends Error{constructor(e,r){super(e),this.name=\"Libzip Error\",this.code=r}},BI=class{constructor(e){this.filesShouldBeCached=!0;let r=\"buffer\"in e?e.buffer:e.baseFs.readFileSync(e.path);this.libzip=cv();let s=this.libzip.malloc(4);try{let c=0;e.readOnly&&(c|=this.libzip.ZIP_RDONLY);let f=this.allocateUnattachedSource(r);try{this.zip=this.libzip.openFromSource(f,c,s),this.lzSource=f}catch(p){throw this.libzip.source.free(f),p}if(this.zip===0){let p=this.libzip.struct.errorS();throw this.libzip.error.initWithCode(p,this.libzip.getValue(s,\"i32\")),this.makeLibzipError(p)}}finally{this.libzip.free(s)}let a=this.libzip.getNumEntries(this.zip,0),n=new Array(a);for(let c=0;c<a;++c)n[c]=this.libzip.getName(this.zip,c,0);if(this.listings=n,this.symlinkCount=this.libzip.ext.countSymlinks(this.zip),this.symlinkCount===-1)throw this.makeLibzipError(this.libzip.getError(this.zip))}getSymlinkCount(){return this.symlinkCount}getListings(){return this.listings}stat(e){let r=this.libzip.struct.statS();if(this.libzip.statIndex(this.zip,e,0,0,r)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));let a=this.libzip.struct.statSize(r)>>>0,n=this.libzip.struct.statMtime(r)>>>0,c=this.libzip.struct.statCrc(r)>>>0;return{size:a,mtime:n,crc:c}}makeLibzipError(e){let r=this.libzip.struct.errorCodeZip(e),s=this.libzip.error.strerror(e),a=new Pj(s,this.libzip.errors[r]);if(r===this.libzip.errors.ZIP_ER_CHANGED)throw new Error(`Assertion failed: Unexpected libzip error: ${a.message}`);return a}setFileSource(e,r,s){let a=this.allocateSource(s);try{let n=this.libzip.file.add(this.zip,e,a,this.libzip.ZIP_FL_OVERWRITE);if(n===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));if(r!==null&&this.libzip.file.setCompression(this.zip,n,0,r[0],r[1])===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));return n}catch(n){throw this.libzip.source.free(a),n}}setMtime(e,r){if(this.libzip.file.setMtime(this.zip,e,0,r,0)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip))}getExternalAttributes(e){if(this.libzip.file.getExternalAttributes(this.zip,e,0,0,this.libzip.uint08S,this.libzip.uint32S)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));let s=this.libzip.getValue(this.libzip.uint08S,\"i8\")>>>0,a=this.libzip.getValue(this.libzip.uint32S,\"i32\")>>>0;return[s,a]}setExternalAttributes(e,r,s){if(this.libzip.file.setExternalAttributes(this.zip,e,0,0,r,s)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip))}locate(e){return this.libzip.name.locate(this.zip,e,0)}getFileSource(e){let r=this.libzip.struct.statS();if(this.libzip.statIndex(this.zip,e,0,0,r)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));let a=this.libzip.struct.statCompSize(r),n=this.libzip.struct.statCompMethod(r),c=this.libzip.malloc(a);try{let f=this.libzip.fopenIndex(this.zip,e,0,this.libzip.ZIP_FL_COMPRESSED);if(f===0)throw this.makeLibzipError(this.libzip.getError(this.zip));try{let p=this.libzip.fread(f,c,a,0);if(p===-1)throw this.makeLibzipError(this.libzip.file.getError(f));if(p<a)throw new Error(\"Incomplete read\");if(p>a)throw new Error(\"Overread\");let h=this.libzip.HEAPU8.subarray(c,c+a);return{data:Buffer.from(h),compressionMethod:n}}finally{this.libzip.fclose(f)}}finally{this.libzip.free(c)}}deleteEntry(e){if(this.libzip.delete(this.zip,e)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip))}addDirectory(e){let r=this.libzip.dir.add(this.zip,e);if(r===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));return r}getBufferAndClose(){try{if(this.libzip.source.keep(this.lzSource),this.libzip.close(this.zip)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));if(this.libzip.source.open(this.lzSource)===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));if(this.libzip.source.seek(this.lzSource,0,0,this.libzip.SEEK_END)===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));let e=this.libzip.source.tell(this.lzSource);if(e===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));if(this.libzip.source.seek(this.lzSource,0,0,this.libzip.SEEK_SET)===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));let r=this.libzip.malloc(e);if(!r)throw new Error(\"Couldn't allocate enough memory\");try{let s=this.libzip.source.read(this.lzSource,r,e);if(s===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));if(s<e)throw new Error(\"Incomplete read\");if(s>e)throw new Error(\"Overread\");let a=Buffer.from(this.libzip.HEAPU8.subarray(r,r+e));return process.env.YARN_IS_TEST_ENV&&process.env.YARN_ZIP_DATA_EPILOGUE&&(a=Buffer.concat([a,Buffer.from(process.env.YARN_ZIP_DATA_EPILOGUE)])),a}finally{this.libzip.free(r)}}finally{this.libzip.source.close(this.lzSource),this.libzip.source.free(this.lzSource)}}allocateBuffer(e){Buffer.isBuffer(e)||(e=Buffer.from(e));let r=this.libzip.malloc(e.byteLength);if(!r)throw new Error(\"Couldn't allocate enough memory\");return new Uint8Array(this.libzip.HEAPU8.buffer,r,e.byteLength).set(e),{buffer:r,byteLength:e.byteLength}}allocateUnattachedSource(e){let r=this.libzip.struct.errorS(),{buffer:s,byteLength:a}=this.allocateBuffer(e),n=this.libzip.source.fromUnattachedBuffer(s,a,0,1,r);if(n===0)throw this.libzip.free(r),this.makeLibzipError(r);return n}allocateSource(e){let{buffer:r,byteLength:s}=this.allocateBuffer(e),a=this.libzip.source.fromBuffer(this.zip,r,s,0,1);if(a===0)throw this.libzip.free(r),this.makeLibzipError(this.libzip.getError(this.zip));return a}discard(){this.libzip.discard(this.zip)}}});function jnt(t){if(typeof t==\"string\"&&String(+t)===t)return+t;if(typeof t==\"number\"&&Number.isFinite(t))return t<0?Date.now()/1e3:t;if(hpe.types.isDate(t))return t.getTime()/1e3;throw new Error(\"Invalid time\")}function wR(){return Buffer.from([80,75,5,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0])}var xa,xj,hpe,kj,lm,Qj,Rj,gpe,As,BR=Ze(()=>{Dt();Dt();Dt();Dt();Dt();Dt();xa=Ie(\"fs\"),xj=Ie(\"stream\"),hpe=Ie(\"util\"),kj=ut(Ie(\"zlib\"));bj();lm=3,Qj=0,Rj=8,gpe=\"mixed\";As=class extends Uf{constructor(r,s={}){super();this.listings=new Map;this.entries=new Map;this.fileSources=new Map;this.fds=new Map;this.nextFd=0;this.ready=!1;this.readOnly=!1;s.readOnly&&(this.readOnly=!0);let a=s;this.level=typeof a.level<\"u\"?a.level:gpe;let n=s.customZipImplementation??BI;if(typeof r==\"string\"){let{baseFs:f=new Yn}=a;this.baseFs=f,this.path=r}else this.path=null,this.baseFs=null;if(s.stats)this.stats=s.stats;else if(typeof r==\"string\")try{this.stats=this.baseFs.statSync(r)}catch(f){if(f.code===\"ENOENT\"&&a.create)this.stats=$a.makeDefaultStats();else throw f}else this.stats=$a.makeDefaultStats();typeof r==\"string\"?s.create?this.zipImpl=new n({buffer:wR(),readOnly:this.readOnly}):this.zipImpl=new n({path:r,baseFs:this.baseFs,readOnly:this.readOnly,size:this.stats.size}):this.zipImpl=new n({buffer:r??wR(),readOnly:this.readOnly}),this.listings.set(vt.root,new Set);let c=this.zipImpl.getListings();for(let f=0;f<c.length;f++){let p=c[f];if(J.isAbsolute(p))continue;let h=J.resolve(vt.root,p);this.registerEntry(h,f),p.endsWith(\"/\")&&this.registerListing(h)}this.symlinkCount=this.zipImpl.getSymlinkCount(),this.ready=!0}getExtractHint(r){for(let s of this.entries.keys()){let a=this.pathUtils.extname(s);if(r.relevantExtensions.has(a))return!0}return!1}getAllFiles(){return Array.from(this.entries.keys())}getRealPath(){if(!this.path)throw new Error(\"ZipFS don't have real paths when loaded from a buffer\");return this.path}prepareClose(){if(!this.ready)throw or.EBUSY(\"archive closed, close\");yd(this)}getBufferAndClose(){if(this.prepareClose(),this.entries.size===0)return this.discardAndClose(),wR();try{return this.zipImpl.getBufferAndClose()}finally{this.ready=!1}}discardAndClose(){this.prepareClose(),this.zipImpl.discard(),this.ready=!1}saveAndClose(){if(!this.path||!this.baseFs)throw new Error(\"ZipFS cannot be saved and must be discarded when loaded from a buffer\");if(this.readOnly){this.discardAndClose();return}let r=this.baseFs.existsSync(this.path)||this.stats.mode===$a.DEFAULT_MODE?void 0:this.stats.mode;this.baseFs.writeFileSync(this.path,this.getBufferAndClose(),{mode:r}),this.ready=!1}resolve(r){return J.resolve(vt.root,r)}async openPromise(r,s,a){return this.openSync(r,s,a)}openSync(r,s,a){let n=this.nextFd++;return this.fds.set(n,{cursor:0,p:r}),n}hasOpenFileHandles(){return!!this.fds.size}async opendirPromise(r,s){return this.opendirSync(r,s)}opendirSync(r,s={}){let a=this.resolveFilename(`opendir '${r}'`,r);if(!this.entries.has(a)&&!this.listings.has(a))throw or.ENOENT(`opendir '${r}'`);let n=this.listings.get(a);if(!n)throw or.ENOTDIR(`opendir '${r}'`);let c=[...n],f=this.openSync(a,\"r\");return ex(this,a,c,{onClose:()=>{this.closeSync(f)}})}async readPromise(r,s,a,n,c){return this.readSync(r,s,a,n,c)}readSync(r,s,a=0,n=s.byteLength,c=-1){let f=this.fds.get(r);if(typeof f>\"u\")throw or.EBADF(\"read\");let p=c===-1||c===null?f.cursor:c,h=this.readFileSync(f.p);h.copy(s,a,p,p+n);let E=Math.max(0,Math.min(h.length-p,n));return(c===-1||c===null)&&(f.cursor+=E),E}async writePromise(r,s,a,n,c){return typeof s==\"string\"?this.writeSync(r,s,c):this.writeSync(r,s,a,n,c)}writeSync(r,s,a,n,c){throw typeof this.fds.get(r)>\"u\"?or.EBADF(\"read\"):new Error(\"Unimplemented\")}async closePromise(r){return this.closeSync(r)}closeSync(r){if(typeof this.fds.get(r)>\"u\")throw or.EBADF(\"read\");this.fds.delete(r)}createReadStream(r,{encoding:s}={}){if(r===null)throw new Error(\"Unimplemented\");let a=this.openSync(r,\"r\"),n=Object.assign(new xj.PassThrough({emitClose:!0,autoDestroy:!0,destroy:(f,p)=>{clearImmediate(c),this.closeSync(a),p(f)}}),{close(){n.destroy()},bytesRead:0,path:r,pending:!1}),c=setImmediate(async()=>{try{let f=await this.readFilePromise(r,s);n.bytesRead=f.length,n.end(f)}catch(f){n.destroy(f)}});return n}createWriteStream(r,{encoding:s}={}){if(this.readOnly)throw or.EROFS(`open '${r}'`);if(r===null)throw new Error(\"Unimplemented\");let a=[],n=this.openSync(r,\"w\"),c=Object.assign(new xj.PassThrough({autoDestroy:!0,emitClose:!0,destroy:(f,p)=>{try{f?p(f):(this.writeFileSync(r,Buffer.concat(a),s),p(null))}catch(h){p(h)}finally{this.closeSync(n)}}}),{close(){c.destroy()},bytesWritten:0,path:r,pending:!1});return c.on(\"data\",f=>{let p=Buffer.from(f);c.bytesWritten+=p.length,a.push(p)}),c}async realpathPromise(r){return this.realpathSync(r)}realpathSync(r){let s=this.resolveFilename(`lstat '${r}'`,r);if(!this.entries.has(s)&&!this.listings.has(s))throw or.ENOENT(`lstat '${r}'`);return s}async existsPromise(r){return this.existsSync(r)}existsSync(r){if(!this.ready)throw or.EBUSY(`archive closed, existsSync '${r}'`);if(this.symlinkCount===0){let a=J.resolve(vt.root,r);return this.entries.has(a)||this.listings.has(a)}let s;try{s=this.resolveFilename(`stat '${r}'`,r,void 0,!1)}catch{return!1}return s===void 0?!1:this.entries.has(s)||this.listings.has(s)}async accessPromise(r,s){return this.accessSync(r,s)}accessSync(r,s=xa.constants.F_OK){let a=this.resolveFilename(`access '${r}'`,r);if(!this.entries.has(a)&&!this.listings.has(a))throw or.ENOENT(`access '${r}'`);if(this.readOnly&&s&xa.constants.W_OK)throw or.EROFS(`access '${r}'`)}async statPromise(r,s={bigint:!1}){return s.bigint?this.statSync(r,{bigint:!0}):this.statSync(r)}statSync(r,s={bigint:!1,throwIfNoEntry:!0}){let a=this.resolveFilename(`stat '${r}'`,r,void 0,s.throwIfNoEntry);if(a!==void 0){if(!this.entries.has(a)&&!this.listings.has(a)){if(s.throwIfNoEntry===!1)return;throw or.ENOENT(`stat '${r}'`)}if(r[r.length-1]===\"/\"&&!this.listings.has(a))throw or.ENOTDIR(`stat '${r}'`);return this.statImpl(`stat '${r}'`,a,s)}}async fstatPromise(r,s){return this.fstatSync(r,s)}fstatSync(r,s){let a=this.fds.get(r);if(typeof a>\"u\")throw or.EBADF(\"fstatSync\");let{p:n}=a,c=this.resolveFilename(`stat '${n}'`,n);if(!this.entries.has(c)&&!this.listings.has(c))throw or.ENOENT(`stat '${n}'`);if(n[n.length-1]===\"/\"&&!this.listings.has(c))throw or.ENOTDIR(`stat '${n}'`);return this.statImpl(`fstat '${n}'`,c,s)}async lstatPromise(r,s={bigint:!1}){return s.bigint?this.lstatSync(r,{bigint:!0}):this.lstatSync(r)}lstatSync(r,s={bigint:!1,throwIfNoEntry:!0}){let a=this.resolveFilename(`lstat '${r}'`,r,!1,s.throwIfNoEntry);if(a!==void 0){if(!this.entries.has(a)&&!this.listings.has(a)){if(s.throwIfNoEntry===!1)return;throw or.ENOENT(`lstat '${r}'`)}if(r[r.length-1]===\"/\"&&!this.listings.has(a))throw or.ENOTDIR(`lstat '${r}'`);return this.statImpl(`lstat '${r}'`,a,s)}}statImpl(r,s,a={}){let n=this.entries.get(s);if(typeof n<\"u\"){let c=this.zipImpl.stat(n),f=c.crc,p=c.size,h=c.mtime*1e3,E=this.stats.uid,C=this.stats.gid,S=512,b=Math.ceil(c.size/S),I=h,T=h,N=h,U=new Date(I),W=new Date(T),ee=new Date(N),ie=new Date(h),ue=this.listings.has(s)?xa.constants.S_IFDIR:this.isSymbolicLink(n)?xa.constants.S_IFLNK:xa.constants.S_IFREG,le=ue===xa.constants.S_IFDIR?493:420,me=ue|this.getUnixMode(n,le)&511,pe=Object.assign(new $a.StatEntry,{uid:E,gid:C,size:p,blksize:S,blocks:b,atime:U,birthtime:W,ctime:ee,mtime:ie,atimeMs:I,birthtimeMs:T,ctimeMs:N,mtimeMs:h,mode:me,crc:f});return a.bigint===!0?$a.convertToBigIntStats(pe):pe}if(this.listings.has(s)){let c=this.stats.uid,f=this.stats.gid,p=0,h=512,E=0,C=this.stats.mtimeMs,S=this.stats.mtimeMs,b=this.stats.mtimeMs,I=this.stats.mtimeMs,T=new Date(C),N=new Date(S),U=new Date(b),W=new Date(I),ee=xa.constants.S_IFDIR|493,ue=Object.assign(new $a.StatEntry,{uid:c,gid:f,size:p,blksize:h,blocks:E,atime:T,birthtime:N,ctime:U,mtime:W,atimeMs:C,birthtimeMs:S,ctimeMs:b,mtimeMs:I,mode:ee,crc:0});return a.bigint===!0?$a.convertToBigIntStats(ue):ue}throw new Error(\"Unreachable\")}getUnixMode(r,s){let[a,n]=this.zipImpl.getExternalAttributes(r);return a!==lm?s:n>>>16}registerListing(r){let s=this.listings.get(r);if(s)return s;this.registerListing(J.dirname(r)).add(J.basename(r));let n=new Set;return this.listings.set(r,n),n}registerEntry(r,s){this.registerListing(J.dirname(r)).add(J.basename(r)),this.entries.set(r,s)}unregisterListing(r){this.listings.delete(r),this.listings.get(J.dirname(r))?.delete(J.basename(r))}unregisterEntry(r){this.unregisterListing(r);let s=this.entries.get(r);this.entries.delete(r),!(typeof s>\"u\")&&(this.fileSources.delete(s),this.isSymbolicLink(s)&&this.symlinkCount--)}deleteEntry(r,s){this.unregisterEntry(r),this.zipImpl.deleteEntry(s)}resolveFilename(r,s,a=!0,n=!0){if(!this.ready)throw or.EBUSY(`archive closed, ${r}`);let c=J.resolve(vt.root,s);if(c===\"/\")return vt.root;let f=this.entries.get(c);if(a&&f!==void 0)if(this.symlinkCount!==0&&this.isSymbolicLink(f)){let p=this.getFileSource(f).toString();return this.resolveFilename(r,J.resolve(J.dirname(c),p),!0,n)}else return c;for(;;){let p=this.resolveFilename(r,J.dirname(c),!0,n);if(p===void 0)return p;let h=this.listings.has(p),E=this.entries.has(p);if(!h&&!E){if(n===!1)return;throw or.ENOENT(r)}if(!h)throw or.ENOTDIR(r);if(c=J.resolve(p,J.basename(c)),!a||this.symlinkCount===0)break;let C=this.zipImpl.locate(c.slice(1));if(C===-1)break;if(this.isSymbolicLink(C)){let S=this.getFileSource(C).toString();c=J.resolve(J.dirname(c),S)}else break}return c}setFileSource(r,s){let a=Buffer.isBuffer(s)?s:Buffer.from(s),n=J.relative(vt.root,r),c=null;this.level!==\"mixed\"&&(c=[this.level===0?Qj:Rj,this.level]);let f=this.zipImpl.setFileSource(n,c,a);return this.fileSources.set(f,a),f}isSymbolicLink(r){if(this.symlinkCount===0)return!1;let[s,a]=this.zipImpl.getExternalAttributes(r);return s!==lm?!1:(a>>>16&xa.constants.S_IFMT)===xa.constants.S_IFLNK}getFileSource(r,s={asyncDecompress:!1}){let a=this.fileSources.get(r);if(typeof a<\"u\")return a;let{data:n,compressionMethod:c}=this.zipImpl.getFileSource(r);if(c===Qj)return this.zipImpl.filesShouldBeCached&&this.fileSources.set(r,n),n;if(c===Rj){if(s.asyncDecompress)return new Promise((f,p)=>{kj.default.inflateRaw(n,(h,E)=>{h?p(h):(this.zipImpl.filesShouldBeCached&&this.fileSources.set(r,E),f(E))})});{let f=kj.default.inflateRawSync(n);return this.zipImpl.filesShouldBeCached&&this.fileSources.set(r,f),f}}else throw new Error(`Unsupported compression method: ${c}`)}async fchmodPromise(r,s){return this.chmodPromise(this.fdToPath(r,\"fchmod\"),s)}fchmodSync(r,s){return this.chmodSync(this.fdToPath(r,\"fchmodSync\"),s)}async chmodPromise(r,s){return this.chmodSync(r,s)}chmodSync(r,s){if(this.readOnly)throw or.EROFS(`chmod '${r}'`);s&=493;let a=this.resolveFilename(`chmod '${r}'`,r,!1),n=this.entries.get(a);if(typeof n>\"u\")throw new Error(`Assertion failed: The entry should have been registered (${a})`);let f=this.getUnixMode(n,xa.constants.S_IFREG|0)&-512|s;this.zipImpl.setExternalAttributes(n,lm,f<<16)}async fchownPromise(r,s,a){return this.chownPromise(this.fdToPath(r,\"fchown\"),s,a)}fchownSync(r,s,a){return this.chownSync(this.fdToPath(r,\"fchownSync\"),s,a)}async chownPromise(r,s,a){return this.chownSync(r,s,a)}chownSync(r,s,a){throw new Error(\"Unimplemented\")}async renamePromise(r,s){return this.renameSync(r,s)}renameSync(r,s){throw new Error(\"Unimplemented\")}async copyFilePromise(r,s,a){let{indexSource:n,indexDest:c,resolvedDestP:f}=this.prepareCopyFile(r,s,a),p=await this.getFileSource(n,{asyncDecompress:!0}),h=this.setFileSource(f,p);h!==c&&this.registerEntry(f,h)}copyFileSync(r,s,a=0){let{indexSource:n,indexDest:c,resolvedDestP:f}=this.prepareCopyFile(r,s,a),p=this.getFileSource(n),h=this.setFileSource(f,p);h!==c&&this.registerEntry(f,h)}prepareCopyFile(r,s,a=0){if(this.readOnly)throw or.EROFS(`copyfile '${r} -> '${s}'`);if(a&xa.constants.COPYFILE_FICLONE_FORCE)throw or.ENOSYS(\"unsupported clone operation\",`copyfile '${r}' -> ${s}'`);let n=this.resolveFilename(`copyfile '${r} -> ${s}'`,r),c=this.entries.get(n);if(typeof c>\"u\")throw or.EINVAL(`copyfile '${r}' -> '${s}'`);let f=this.resolveFilename(`copyfile '${r}' -> ${s}'`,s),p=this.entries.get(f);if(a&(xa.constants.COPYFILE_EXCL|xa.constants.COPYFILE_FICLONE_FORCE)&&typeof p<\"u\")throw or.EEXIST(`copyfile '${r}' -> '${s}'`);return{indexSource:c,resolvedDestP:f,indexDest:p}}async appendFilePromise(r,s,a){if(this.readOnly)throw or.EROFS(`open '${r}'`);return typeof a>\"u\"?a={flag:\"a\"}:typeof a==\"string\"?a={flag:\"a\",encoding:a}:typeof a.flag>\"u\"&&(a={flag:\"a\",...a}),this.writeFilePromise(r,s,a)}appendFileSync(r,s,a={}){if(this.readOnly)throw or.EROFS(`open '${r}'`);return typeof a>\"u\"?a={flag:\"a\"}:typeof a==\"string\"?a={flag:\"a\",encoding:a}:typeof a.flag>\"u\"&&(a={flag:\"a\",...a}),this.writeFileSync(r,s,a)}fdToPath(r,s){let a=this.fds.get(r)?.p;if(typeof a>\"u\")throw or.EBADF(s);return a}async writeFilePromise(r,s,a){let{encoding:n,mode:c,index:f,resolvedP:p}=this.prepareWriteFile(r,a);f!==void 0&&typeof a==\"object\"&&a.flag&&a.flag.includes(\"a\")&&(s=Buffer.concat([await this.getFileSource(f,{asyncDecompress:!0}),Buffer.from(s)])),n!==null&&(s=s.toString(n));let h=this.setFileSource(p,s);h!==f&&this.registerEntry(p,h),c!==null&&await this.chmodPromise(p,c)}writeFileSync(r,s,a){let{encoding:n,mode:c,index:f,resolvedP:p}=this.prepareWriteFile(r,a);f!==void 0&&typeof a==\"object\"&&a.flag&&a.flag.includes(\"a\")&&(s=Buffer.concat([this.getFileSource(f),Buffer.from(s)])),n!==null&&(s=s.toString(n));let h=this.setFileSource(p,s);h!==f&&this.registerEntry(p,h),c!==null&&this.chmodSync(p,c)}prepareWriteFile(r,s){if(typeof r==\"number\"&&(r=this.fdToPath(r,\"read\")),this.readOnly)throw or.EROFS(`open '${r}'`);let a=this.resolveFilename(`open '${r}'`,r);if(this.listings.has(a))throw or.EISDIR(`open '${r}'`);let n=null,c=null;typeof s==\"string\"?n=s:typeof s==\"object\"&&({encoding:n=null,mode:c=null}=s);let f=this.entries.get(a);return{encoding:n,mode:c,resolvedP:a,index:f}}async unlinkPromise(r){return this.unlinkSync(r)}unlinkSync(r){if(this.readOnly)throw or.EROFS(`unlink '${r}'`);let s=this.resolveFilename(`unlink '${r}'`,r);if(this.listings.has(s))throw or.EISDIR(`unlink '${r}'`);let a=this.entries.get(s);if(typeof a>\"u\")throw or.EINVAL(`unlink '${r}'`);this.deleteEntry(s,a)}async utimesPromise(r,s,a){return this.utimesSync(r,s,a)}utimesSync(r,s,a){if(this.readOnly)throw or.EROFS(`utimes '${r}'`);let n=this.resolveFilename(`utimes '${r}'`,r);this.utimesImpl(n,a)}async lutimesPromise(r,s,a){return this.lutimesSync(r,s,a)}lutimesSync(r,s,a){if(this.readOnly)throw or.EROFS(`lutimes '${r}'`);let n=this.resolveFilename(`utimes '${r}'`,r,!1);this.utimesImpl(n,a)}utimesImpl(r,s){this.listings.has(r)&&(this.entries.has(r)||this.hydrateDirectory(r));let a=this.entries.get(r);if(a===void 0)throw new Error(\"Unreachable\");this.zipImpl.setMtime(a,jnt(s))}async mkdirPromise(r,s){return this.mkdirSync(r,s)}mkdirSync(r,{mode:s=493,recursive:a=!1}={}){if(a)return this.mkdirpSync(r,{chmod:s});if(this.readOnly)throw or.EROFS(`mkdir '${r}'`);let n=this.resolveFilename(`mkdir '${r}'`,r);if(this.entries.has(n)||this.listings.has(n))throw or.EEXIST(`mkdir '${r}'`);this.hydrateDirectory(n),this.chmodSync(n,s)}async rmdirPromise(r,s){return this.rmdirSync(r,s)}rmdirSync(r,{recursive:s=!1}={}){if(this.readOnly)throw or.EROFS(`rmdir '${r}'`);if(s){this.removeSync(r);return}let a=this.resolveFilename(`rmdir '${r}'`,r),n=this.listings.get(a);if(!n)throw or.ENOTDIR(`rmdir '${r}'`);if(n.size>0)throw or.ENOTEMPTY(`rmdir '${r}'`);let c=this.entries.get(a);if(typeof c>\"u\")throw or.EINVAL(`rmdir '${r}'`);this.deleteEntry(r,c)}async rmPromise(r,s){return this.rmSync(r,s)}rmSync(r,{recursive:s=!1}={}){if(this.readOnly)throw or.EROFS(`rm '${r}'`);if(s){this.removeSync(r);return}let a=this.resolveFilename(`rm '${r}'`,r),n=this.listings.get(a);if(!n)throw or.ENOTDIR(`rm '${r}'`);if(n.size>0)throw or.ENOTEMPTY(`rm '${r}'`);let c=this.entries.get(a);if(typeof c>\"u\")throw or.EINVAL(`rm '${r}'`);this.deleteEntry(r,c)}hydrateDirectory(r){let s=this.zipImpl.addDirectory(J.relative(vt.root,r));return this.registerListing(r),this.registerEntry(r,s),s}async linkPromise(r,s){return this.linkSync(r,s)}linkSync(r,s){throw or.EOPNOTSUPP(`link '${r}' -> '${s}'`)}async symlinkPromise(r,s){return this.symlinkSync(r,s)}symlinkSync(r,s){if(this.readOnly)throw or.EROFS(`symlink '${r}' -> '${s}'`);let a=this.resolveFilename(`symlink '${r}' -> '${s}'`,s);if(this.listings.has(a))throw or.EISDIR(`symlink '${r}' -> '${s}'`);if(this.entries.has(a))throw or.EEXIST(`symlink '${r}' -> '${s}'`);let n=this.setFileSource(a,r);this.registerEntry(a,n),this.zipImpl.setExternalAttributes(n,lm,(xa.constants.S_IFLNK|511)<<16),this.symlinkCount+=1}async readFilePromise(r,s){typeof s==\"object\"&&(s=s?s.encoding:void 0);let a=await this.readFileBuffer(r,{asyncDecompress:!0});return s?a.toString(s):a}readFileSync(r,s){typeof s==\"object\"&&(s=s?s.encoding:void 0);let a=this.readFileBuffer(r);return s?a.toString(s):a}readFileBuffer(r,s={asyncDecompress:!1}){typeof r==\"number\"&&(r=this.fdToPath(r,\"read\"));let a=this.resolveFilename(`open '${r}'`,r);if(!this.entries.has(a)&&!this.listings.has(a))throw or.ENOENT(`open '${r}'`);if(r[r.length-1]===\"/\"&&!this.listings.has(a))throw or.ENOTDIR(`open '${r}'`);if(this.listings.has(a))throw or.EISDIR(\"read\");let n=this.entries.get(a);if(n===void 0)throw new Error(\"Unreachable\");return this.getFileSource(n,s)}async readdirPromise(r,s){return this.readdirSync(r,s)}readdirSync(r,s){let a=this.resolveFilename(`scandir '${r}'`,r);if(!this.entries.has(a)&&!this.listings.has(a))throw or.ENOENT(`scandir '${r}'`);let n=this.listings.get(a);if(!n)throw or.ENOTDIR(`scandir '${r}'`);if(s?.recursive)if(s?.withFileTypes){let c=Array.from(n,f=>Object.assign(this.statImpl(\"lstat\",J.join(r,f)),{name:f,path:vt.dot,parentPath:vt.dot}));for(let f of c){if(!f.isDirectory())continue;let p=J.join(f.path,f.name),h=this.listings.get(J.join(a,p));for(let E of h)c.push(Object.assign(this.statImpl(\"lstat\",J.join(r,p,E)),{name:E,path:p,parentPath:p}))}return c}else{let c=[...n];for(let f of c){let p=this.listings.get(J.join(a,f));if(!(typeof p>\"u\"))for(let h of p)c.push(J.join(f,h))}return c}else return s?.withFileTypes?Array.from(n,c=>Object.assign(this.statImpl(\"lstat\",J.join(r,c)),{name:c,path:void 0,parentPath:void 0})):[...n]}async readlinkPromise(r){let s=this.prepareReadlink(r);return(await this.getFileSource(s,{asyncDecompress:!0})).toString()}readlinkSync(r){let s=this.prepareReadlink(r);return this.getFileSource(s).toString()}prepareReadlink(r){let s=this.resolveFilename(`readlink '${r}'`,r,!1);if(!this.entries.has(s)&&!this.listings.has(s))throw or.ENOENT(`readlink '${r}'`);if(r[r.length-1]===\"/\"&&!this.listings.has(s))throw or.ENOTDIR(`open '${r}'`);if(this.listings.has(s))throw or.EINVAL(`readlink '${r}'`);let a=this.entries.get(s);if(a===void 0)throw new Error(\"Unreachable\");if(!this.isSymbolicLink(a))throw or.EINVAL(`readlink '${r}'`);return a}async truncatePromise(r,s=0){let a=this.resolveFilename(`open '${r}'`,r),n=this.entries.get(a);if(typeof n>\"u\")throw or.EINVAL(`open '${r}'`);let c=await this.getFileSource(n,{asyncDecompress:!0}),f=Buffer.alloc(s,0);return c.copy(f),await this.writeFilePromise(r,f)}truncateSync(r,s=0){let a=this.resolveFilename(`open '${r}'`,r),n=this.entries.get(a);if(typeof n>\"u\")throw or.EINVAL(`open '${r}'`);let c=this.getFileSource(n),f=Buffer.alloc(s,0);return c.copy(f),this.writeFileSync(r,f)}async ftruncatePromise(r,s){return this.truncatePromise(this.fdToPath(r,\"ftruncate\"),s)}ftruncateSync(r,s){return this.truncateSync(this.fdToPath(r,\"ftruncateSync\"),s)}watch(r,s,a){let n;switch(typeof s){case\"function\":case\"string\":case\"undefined\":n=!0;break;default:({persistent:n=!0}=s);break}if(!n)return{on:()=>{},close:()=>{}};let c=setInterval(()=>{},24*60*60*1e3);return{on:()=>{},close:()=>{clearInterval(c)}}}watchFile(r,s,a){let n=J.resolve(vt.root,r);return sE(this,n,s,a)}unwatchFile(r,s){let a=J.resolve(vt.root,r);return md(this,a,s)}}});function mpe(t,e,r=Buffer.alloc(0),s){let a=new As(r),n=C=>C===e||C.startsWith(`${e}/`)?C.slice(0,e.length):null,c=async(C,S)=>()=>a,f=(C,S)=>a,p={...t},h=new Yn(p),E=new e0({baseFs:h,getMountPoint:n,factoryPromise:c,factorySync:f,magicByte:21,maxAge:1/0,typeCheck:s?.typeCheck});return U2(dpe.default,new t0(E)),a}var dpe,ype=Ze(()=>{Dt();dpe=ut(Ie(\"fs\"));BR()});var Epe=Ze(()=>{ppe();BR();ype()});var Tj,uv,vR,Ipe=Ze(()=>{Dt();BR();Tj={CENTRAL_DIRECTORY:33639248,END_OF_CENTRAL_DIRECTORY:101010256},uv=22,vR=class t{constructor(e){this.filesShouldBeCached=!1;if(\"buffer\"in e)throw new Error(\"Buffer based zip archives are not supported\");if(!e.readOnly)throw new Error(\"Writable zip archives are not supported\");this.baseFs=e.baseFs,this.fd=this.baseFs.openSync(e.path,\"r\");try{this.entries=t.readZipSync(this.fd,this.baseFs,e.size)}catch(r){throw this.baseFs.closeSync(this.fd),this.fd=\"closed\",r}}static readZipSync(e,r,s){if(s<uv)throw new Error(\"Invalid ZIP file: EOCD not found\");let a=-1,n=Buffer.alloc(uv);if(r.readSync(e,n,0,uv,s-uv),n.readUInt32LE(0)===Tj.END_OF_CENTRAL_DIRECTORY)a=0;else{let T=Math.min(65557,s);n=Buffer.alloc(T),r.readSync(e,n,0,T,Math.max(0,s-T));for(let N=n.length-4;N>=0;N--)if(n.readUInt32LE(N)===Tj.END_OF_CENTRAL_DIRECTORY){a=N;break}if(a===-1)throw new Error(\"Not a zip archive\")}let c=n.readUInt16LE(a+10),f=n.readUInt32LE(a+12),p=n.readUInt32LE(a+16),h=n.readUInt16LE(a+20);if(a+h+uv>n.length)throw new Error(\"Zip archive inconsistent\");if(c==65535||f==4294967295||p==4294967295)throw new Error(\"Zip 64 is not supported\");if(f>s)throw new Error(\"Zip archive inconsistent\");if(c>f/46)throw new Error(\"Zip archive inconsistent\");let E=Buffer.alloc(f);if(r.readSync(e,E,0,E.length,p)!==E.length)throw new Error(\"Zip archive inconsistent\");let C=[],S=0,b=0,I=0;for(;b<c;){if(S+46>E.length)throw new Error(\"Zip archive inconsistent\");if(E.readUInt32LE(S)!==Tj.CENTRAL_DIRECTORY)throw new Error(\"Zip archive inconsistent\");let N=E.readUInt16LE(S+4)>>>8;if(E.readUInt16LE(S+8)&1)throw new Error(\"Encrypted zip files are not supported\");let W=E.readUInt16LE(S+10),ee=E.readUInt32LE(S+16),ie=E.readUInt16LE(S+28),ue=E.readUInt16LE(S+30),le=E.readUInt16LE(S+32),me=E.readUInt32LE(S+42),pe=E.toString(\"utf8\",S+46,S+46+ie).replaceAll(\"\\0\",\" \");if(pe.includes(\"\\0\"))throw new Error(\"Invalid ZIP file\");let Be=E.readUInt32LE(S+20),Ce=E.readUInt32LE(S+38);C.push({name:pe,os:N,mtime:fi.SAFE_TIME,crc:ee,compressionMethod:W,isSymbolicLink:N===lm&&(Ce>>>16&fi.S_IFMT)===fi.S_IFLNK,size:E.readUInt32LE(S+24),compressedSize:Be,externalAttributes:Ce,localHeaderOffset:me}),I+=Be,b+=1,S+=46+ie+ue+le}if(I>s)throw new Error(\"Zip archive inconsistent\");if(S!==E.length)throw new Error(\"Zip archive inconsistent\");return C}getExternalAttributes(e){let r=this.entries[e];return[r.os,r.externalAttributes]}getListings(){return this.entries.map(e=>e.name)}getSymlinkCount(){let e=0;for(let r of this.entries)r.isSymbolicLink&&(e+=1);return e}stat(e){let r=this.entries[e];return{crc:r.crc,mtime:r.mtime,size:r.size}}locate(e){for(let r=0;r<this.entries.length;r++)if(this.entries[r].name===e)return r;return-1}getFileSource(e){if(this.fd===\"closed\")throw new Error(\"ZIP file is closed\");let r=this.entries[e],s=Buffer.alloc(30);this.baseFs.readSync(this.fd,s,0,s.length,r.localHeaderOffset);let a=s.readUInt16LE(26),n=s.readUInt16LE(28),c=Buffer.alloc(r.compressedSize);if(this.baseFs.readSync(this.fd,c,0,r.compressedSize,r.localHeaderOffset+30+a+n)!==r.compressedSize)throw new Error(\"Invalid ZIP file\");return{data:c,compressionMethod:r.compressionMethod}}discard(){this.fd!==\"closed\"&&(this.baseFs.closeSync(this.fd),this.fd=\"closed\")}addDirectory(e){throw new Error(\"Not implemented\")}deleteEntry(e){throw new Error(\"Not implemented\")}setMtime(e,r){throw new Error(\"Not implemented\")}getBufferAndClose(){throw new Error(\"Not implemented\")}setFileSource(e,r,s){throw new Error(\"Not implemented\")}setExternalAttributes(e,r,s){throw new Error(\"Not implemented\")}}});var fv={};Vt(fv,{DEFAULT_COMPRESSION_LEVEL:()=>gpe,DEFLATE:()=>Rj,JsZipImpl:()=>vR,LibZipImpl:()=>BI,STORE:()=>Qj,ZIP_UNIX:()=>lm,ZipFS:()=>As,ZipOpenFS:()=>$f,getArchivePart:()=>Dj,getLibzipPromise:()=>qnt,getLibzipSync:()=>Gnt,makeEmptyArchive:()=>wR,mountMemoryDrive:()=>mpe});function Gnt(){return cv()}async function qnt(){return cv()}var Cpe,eA=Ze(()=>{Bj();Cpe=ut(cpe());Ape();Epe();Ipe();bj();lpe(()=>{let t=(0,Cpe.default)();return fpe(t)})});var Av,wpe=Ze(()=>{Dt();Yt();pv();Av=class extends ot{constructor(){super(...arguments);this.cwd=ge.String(\"--cwd\",process.cwd(),{description:\"The directory to run the command in\"});this.commandName=ge.String();this.args=ge.Proxy()}static{this.usage={description:\"run a command using yarn's portable shell\",details:`\n      This command will run a command using Yarn's portable shell.\n\n      Make sure to escape glob patterns, redirections, and other features that might be expanded by your own shell.\n\n      Note: To escape something from Yarn's shell, you might have to escape it twice, the first time from your own shell.\n\n      Note: Don't use this command in Yarn scripts, as Yarn's shell is automatically used.\n\n      For a list of features, visit: https://github.com/yarnpkg/berry/blob/master/packages/yarnpkg-shell/README.md.\n    `,examples:[[\"Run a simple command\",\"$0 echo Hello\"],[\"Run a command with a glob pattern\",\"$0 echo '*.js'\"],[\"Run a command with a redirection\",\"$0 echo Hello World '>' hello.txt\"],[\"Run a command with an escaped glob pattern (The double escape is needed in Unix shells)\",`$0 echo '\"*.js\"'`],[\"Run a command with a variable (Double quotes are needed in Unix shells, to prevent them from expanding the variable)\",'$0 \"GREETING=Hello echo $GREETING World\"']]}}async execute(){let r=this.args.length>0?`${this.commandName} ${this.args.join(\" \")}`:this.commandName;return await vI(r,[],{cwd:fe.toPortablePath(this.cwd),stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr})}}});var Vl,Bpe=Ze(()=>{Vl=class extends Error{constructor(e){super(e),this.name=\"ShellError\"}}});var PR={};Vt(PR,{fastGlobOptions:()=>Dpe,isBraceExpansion:()=>Fj,isGlobPattern:()=>Wnt,match:()=>Ynt,micromatchOptions:()=>DR});function Wnt(t){if(!SR.default.scan(t,DR).isGlob)return!1;try{SR.default.parse(t,DR)}catch{return!1}return!0}function Ynt(t,{cwd:e,baseFs:r}){return(0,vpe.default)(t,{...Dpe,cwd:fe.fromPortablePath(e),fs:ax(Spe.default,new t0(r))})}function Fj(t){return SR.default.scan(t,DR).isBrace}var vpe,Spe,SR,DR,Dpe,Ppe=Ze(()=>{Dt();vpe=ut(wQ()),Spe=ut(Ie(\"fs\")),SR=ut(Go()),DR={strictBrackets:!0},Dpe={onlyDirectories:!1,onlyFiles:!1}});function Nj(){}function Oj(){for(let t of cm)t.kill()}function Qpe(t,e,r,s){return a=>{let n=a[0]instanceof tA.Transform?\"pipe\":a[0],c=a[1]instanceof tA.Transform?\"pipe\":a[1],f=a[2]instanceof tA.Transform?\"pipe\":a[2],p=(0,xpe.default)(t,e,{...s,stdio:[n,c,f]});return cm.add(p),cm.size===1&&(process.on(\"SIGINT\",Nj),process.on(\"SIGTERM\",Oj)),a[0]instanceof tA.Transform&&a[0].pipe(p.stdin),a[1]instanceof tA.Transform&&p.stdout.pipe(a[1],{end:!1}),a[2]instanceof tA.Transform&&p.stderr.pipe(a[2],{end:!1}),{stdin:p.stdin,promise:new Promise(h=>{p.on(\"error\",E=>{switch(cm.delete(p),cm.size===0&&(process.off(\"SIGINT\",Nj),process.off(\"SIGTERM\",Oj)),E.code){case\"ENOENT\":a[2].write(`command not found: ${t}\n`),h(127);break;case\"EACCES\":a[2].write(`permission denied: ${t}\n`),h(128);break;default:a[2].write(`uncaught error: ${E.message}\n`),h(1);break}}),p.on(\"close\",E=>{cm.delete(p),cm.size===0&&(process.off(\"SIGINT\",Nj),process.off(\"SIGTERM\",Oj)),h(E!==null?E:129)})})}}}function Rpe(t){return e=>{let r=e[0]===\"pipe\"?new tA.PassThrough:e[0];return{stdin:r,promise:Promise.resolve().then(()=>t({stdin:r,stdout:e[1],stderr:e[2]}))}}}function bR(t,e){return Mj.start(t,e)}function bpe(t,e=null){let r=new tA.PassThrough,s=new kpe.StringDecoder,a=\"\";return r.on(\"data\",n=>{let c=s.write(n),f;do if(f=c.indexOf(`\n`),f!==-1){let p=a+c.substring(0,f);c=c.substring(f+1),a=\"\",t(e!==null?`${e} ${p}`:p)}while(f!==-1);a+=c}),r.on(\"end\",()=>{let n=s.end();n!==\"\"&&t(e!==null?`${e} ${n}`:n)}),r}function Tpe(t,{prefix:e}){return{stdout:bpe(r=>t.stdout.write(`${r}\n`),t.stdout.isTTY?e:null),stderr:bpe(r=>t.stderr.write(`${r}\n`),t.stderr.isTTY?e:null)}}var xpe,tA,kpe,cm,Oc,Lj,Mj,Uj=Ze(()=>{xpe=ut(UU()),tA=Ie(\"stream\"),kpe=Ie(\"string_decoder\"),cm=new Set;Oc=class{constructor(e){this.stream=e}close(){}get(){return this.stream}},Lj=class{constructor(){this.stream=null}close(){if(this.stream===null)throw new Error(\"Assertion failed: No stream attached\");this.stream.end()}attach(e){this.stream=e}get(){if(this.stream===null)throw new Error(\"Assertion failed: No stream attached\");return this.stream}},Mj=class t{constructor(e,r){this.stdin=null;this.stdout=null;this.stderr=null;this.pipe=null;this.ancestor=e,this.implementation=r}static start(e,{stdin:r,stdout:s,stderr:a}){let n=new t(null,e);return n.stdin=r,n.stdout=s,n.stderr=a,n}pipeTo(e,r=1){let s=new t(this,e),a=new Lj;return s.pipe=a,s.stdout=this.stdout,s.stderr=this.stderr,(r&1)===1?this.stdout=a:this.ancestor!==null&&(this.stderr=this.ancestor.stdout),(r&2)===2?this.stderr=a:this.ancestor!==null&&(this.stderr=this.ancestor.stderr),s}async exec(){let e=[\"ignore\",\"ignore\",\"ignore\"];if(this.pipe)e[0]=\"pipe\";else{if(this.stdin===null)throw new Error(\"Assertion failed: No input stream registered\");e[0]=this.stdin.get()}let r;if(this.stdout===null)throw new Error(\"Assertion failed: No output stream registered\");r=this.stdout,e[1]=r.get();let s;if(this.stderr===null)throw new Error(\"Assertion failed: No error stream registered\");s=this.stderr,e[2]=s.get();let a=this.implementation(e);return this.pipe&&this.pipe.attach(a.stdin),await a.promise.then(n=>(r.close(),s.close(),n))}async run(){let e=[];for(let s=this;s;s=s.ancestor)e.push(s.exec());return(await Promise.all(e))[0]}}});var mv={};Vt(mv,{EntryCommand:()=>Av,ShellError:()=>Vl,execute:()=>vI,globUtils:()=>PR});function Fpe(t,e,r){let s=new Jl.PassThrough({autoDestroy:!0});switch(t){case 0:(e&1)===1&&r.stdin.pipe(s,{end:!1}),(e&2)===2&&r.stdin instanceof Jl.Writable&&s.pipe(r.stdin,{end:!1});break;case 1:(e&1)===1&&r.stdout.pipe(s,{end:!1}),(e&2)===2&&s.pipe(r.stdout,{end:!1});break;case 2:(e&1)===1&&r.stderr.pipe(s,{end:!1}),(e&2)===2&&s.pipe(r.stderr,{end:!1});break;default:throw new Vl(`Bad file descriptor: \"${t}\"`)}return s}function kR(t,e={}){let r={...t,...e};return r.environment={...t.environment,...e.environment},r.variables={...t.variables,...e.variables},r}async function Jnt(t,e,r){let s=[],a=new Jl.PassThrough;return a.on(\"data\",n=>s.push(n)),await QR(t,e,kR(r,{stdout:a})),Buffer.concat(s).toString().replace(/[\\r\\n]+$/,\"\")}async function Npe(t,e,r){let s=t.map(async n=>{let c=await um(n.args,e,r);return{name:n.name,value:c.join(\" \")}});return(await Promise.all(s)).reduce((n,c)=>(n[c.name]=c.value,n),{})}function xR(t){return t.match(/[^ \\r\\n\\t]+/g)||[]}async function Hpe(t,e,r,s,a=s){switch(t.name){case\"$\":s(String(process.pid));break;case\"#\":s(String(e.args.length));break;case\"@\":if(t.quoted)for(let n of e.args)a(n);else for(let n of e.args){let c=xR(n);for(let f=0;f<c.length-1;++f)a(c[f]);s(c[c.length-1])}break;case\"*\":{let n=e.args.join(\" \");if(t.quoted)s(n);else for(let c of xR(n))a(c)}break;case\"PPID\":s(String(process.ppid));break;case\"RANDOM\":s(String(Math.floor(Math.random()*32768)));break;default:{let n=parseInt(t.name,10),c,f=Number.isFinite(n);if(f?n>=0&&n<e.args.length&&(c=e.args[n]):Object.hasOwn(r.variables,t.name)?c=r.variables[t.name]:Object.hasOwn(r.environment,t.name)&&(c=r.environment[t.name]),typeof c<\"u\"&&t.alternativeValue?c=(await um(t.alternativeValue,e,r)).join(\" \"):typeof c>\"u\"&&(t.defaultValue?c=(await um(t.defaultValue,e,r)).join(\" \"):t.alternativeValue&&(c=\"\")),typeof c>\"u\")throw f?new Vl(`Unbound argument #${n}`):new Vl(`Unbound variable \"${t.name}\"`);if(t.quoted)s(c);else{let p=xR(c);for(let E=0;E<p.length-1;++E)a(p[E]);let h=p[p.length-1];typeof h<\"u\"&&s(h)}}break}}async function hv(t,e,r){if(t.type===\"number\"){if(Number.isInteger(t.value))return t.value;throw new Error(`Invalid number: \"${t.value}\", only integers are allowed`)}else if(t.type===\"variable\"){let s=[];await Hpe({...t,quoted:!0},e,r,n=>s.push(n));let a=Number(s.join(\" \"));return Number.isNaN(a)?hv({type:\"variable\",name:s.join(\" \")},e,r):hv({type:\"number\",value:a},e,r)}else return Knt[t.type](await hv(t.left,e,r),await hv(t.right,e,r))}async function um(t,e,r){let s=new Map,a=[],n=[],c=E=>{n.push(E)},f=()=>{n.length>0&&a.push(n.join(\"\")),n=[]},p=E=>{c(E),f()},h=(E,C,S)=>{let b=JSON.stringify({type:E,fd:C}),I=s.get(b);typeof I>\"u\"&&s.set(b,I=[]),I.push(S)};for(let E of t){let C=!1;switch(E.type){case\"redirection\":{let S=await um(E.args,e,r);for(let b of S)h(E.subtype,E.fd,b)}break;case\"argument\":for(let S of E.segments)switch(S.type){case\"text\":c(S.text);break;case\"glob\":c(S.pattern),C=!0;break;case\"shell\":{let b=await Jnt(S.shell,e,r);if(S.quoted)c(b);else{let I=xR(b);for(let T=0;T<I.length-1;++T)p(I[T]);c(I[I.length-1])}}break;case\"variable\":await Hpe(S,e,r,c,p);break;case\"arithmetic\":c(String(await hv(S.arithmetic,e,r)));break}break}if(f(),C){let S=a.pop();if(typeof S>\"u\")throw new Error(\"Assertion failed: Expected a glob pattern to have been set\");let b=await e.glob.match(S,{cwd:r.cwd,baseFs:e.baseFs});if(b.length===0){let I=Fj(S)?\". Note: Brace expansion of arbitrary strings isn't currently supported. For more details, please read this issue: https://github.com/yarnpkg/berry/issues/22\":\"\";throw new Vl(`No matches found: \"${S}\"${I}`)}for(let I of b.sort())p(I)}}if(s.size>0){let E=[];for(let[C,S]of s.entries())E.splice(E.length,0,C,String(S.length),...S);a.splice(0,0,\"__ysh_set_redirects\",...E,\"--\")}return a}function gv(t,e,r){e.builtins.has(t[0])||(t=[\"command\",...t]);let s=fe.fromPortablePath(r.cwd),a=r.environment;typeof a.PWD<\"u\"&&(a={...a,PWD:s});let[n,...c]=t;if(n===\"command\")return Qpe(c[0],c.slice(1),e,{cwd:s,env:a});let f=e.builtins.get(n);if(typeof f>\"u\")throw new Error(`Assertion failed: A builtin should exist for \"${n}\"`);return Rpe(async({stdin:p,stdout:h,stderr:E})=>{let{stdin:C,stdout:S,stderr:b}=r;r.stdin=p,r.stdout=h,r.stderr=E;try{return await f(c,e,r)}finally{r.stdin=C,r.stdout=S,r.stderr=b}})}function znt(t,e,r){return s=>{let a=new Jl.PassThrough,n=QR(t,e,kR(r,{stdin:a}));return{stdin:a,promise:n}}}function Znt(t,e,r){return s=>{let a=new Jl.PassThrough,n=QR(t,e,r);return{stdin:a,promise:n}}}function Ope(t,e,r,s){if(e.length===0)return t;{let a;do a=String(Math.random());while(Object.hasOwn(s.procedures,a));return s.procedures={...s.procedures},s.procedures[a]=t,gv([...e,\"__ysh_run_procedure\",a],r,s)}}async function Lpe(t,e,r){let s=t,a=null,n=null;for(;s;){let c=s.then?{...r}:r,f;switch(s.type){case\"command\":{let p=await um(s.args,e,r),h=await Npe(s.envs,e,r);f=s.envs.length?gv(p,e,kR(c,{environment:h})):gv(p,e,c)}break;case\"subshell\":{let p=await um(s.args,e,r),h=znt(s.subshell,e,c);f=Ope(h,p,e,c)}break;case\"group\":{let p=await um(s.args,e,r),h=Znt(s.group,e,c);f=Ope(h,p,e,c)}break;case\"envs\":{let p=await Npe(s.envs,e,r);c.environment={...c.environment,...p},f=gv([\"true\"],e,c)}break}if(typeof f>\"u\")throw new Error(\"Assertion failed: An action should have been generated\");if(a===null)n=bR(f,{stdin:new Oc(c.stdin),stdout:new Oc(c.stdout),stderr:new Oc(c.stderr)});else{if(n===null)throw new Error(\"Assertion failed: The execution pipeline should have been setup\");switch(a){case\"|\":n=n.pipeTo(f,1);break;case\"|&\":n=n.pipeTo(f,3);break}}s.then?(a=s.then.type,s=s.then.chain):s=null}if(n===null)throw new Error(\"Assertion failed: The execution pipeline should have been setup\");return await n.run()}async function Xnt(t,e,r,{background:s=!1}={}){function a(n){let c=[\"#2E86AB\",\"#A23B72\",\"#F18F01\",\"#C73E1D\",\"#CCE2A3\"],f=c[n%c.length];return Mpe.default.hex(f)}if(s){let n=r.nextBackgroundJobIndex++,c=a(n),f=`[${n}]`,p=c(f),{stdout:h,stderr:E}=Tpe(r,{prefix:p});return r.backgroundJobs.push(Lpe(t,e,kR(r,{stdout:h,stderr:E})).catch(C=>E.write(`${C.message}\n`)).finally(()=>{r.stdout.isTTY&&r.stdout.write(`Job ${p}, '${c(AE(t))}' has ended\n`)})),0}return await Lpe(t,e,r)}async function $nt(t,e,r,{background:s=!1}={}){let a,n=f=>{a=f,r.variables[\"?\"]=String(f)},c=async f=>{try{return await Xnt(f.chain,e,r,{background:s&&typeof f.then>\"u\"})}catch(p){if(!(p instanceof Vl))throw p;return r.stderr.write(`${p.message}\n`),1}};for(n(await c(t));t.then;){if(r.exitCode!==null)return r.exitCode;switch(t.then.type){case\"&&\":a===0&&n(await c(t.then.line));break;case\"||\":a!==0&&n(await c(t.then.line));break;default:throw new Error(`Assertion failed: Unsupported command type: \"${t.then.type}\"`)}t=t.then.line}return a}async function QR(t,e,r){let s=r.backgroundJobs;r.backgroundJobs=[];let a=0;for(let{command:n,type:c}of t){if(a=await $nt(n,e,r,{background:c===\"&\"}),r.exitCode!==null)return r.exitCode;r.variables[\"?\"]=String(a)}return await Promise.all(r.backgroundJobs),r.backgroundJobs=s,a}function jpe(t){switch(t.type){case\"variable\":return t.name===\"@\"||t.name===\"#\"||t.name===\"*\"||Number.isFinite(parseInt(t.name,10))||\"defaultValue\"in t&&!!t.defaultValue&&t.defaultValue.some(e=>dv(e))||\"alternativeValue\"in t&&!!t.alternativeValue&&t.alternativeValue.some(e=>dv(e));case\"arithmetic\":return _j(t.arithmetic);case\"shell\":return Hj(t.shell);default:return!1}}function dv(t){switch(t.type){case\"redirection\":return t.args.some(e=>dv(e));case\"argument\":return t.segments.some(e=>jpe(e));default:throw new Error(`Assertion failed: Unsupported argument type: \"${t.type}\"`)}}function _j(t){switch(t.type){case\"variable\":return jpe(t);case\"number\":return!1;default:return _j(t.left)||_j(t.right)}}function Hj(t){return t.some(({command:e})=>{for(;e;){let r=e.chain;for(;r;){let s;switch(r.type){case\"subshell\":s=Hj(r.subshell);break;case\"command\":s=r.envs.some(a=>a.args.some(n=>dv(n)))||r.args.some(a=>dv(a));break}if(s)return!0;if(!r.then)break;r=r.then.chain}if(!e.then)break;e=e.then.line}return!1})}async function vI(t,e=[],{baseFs:r=new Yn,builtins:s={},cwd:a=fe.toPortablePath(process.cwd()),env:n=process.env,stdin:c=process.stdin,stdout:f=process.stdout,stderr:p=process.stderr,variables:h={},glob:E=PR}={}){let C={};for(let[I,T]of Object.entries(n))typeof T<\"u\"&&(C[I]=T);let S=new Map(Vnt);for(let[I,T]of Object.entries(s))S.set(I,T);c===null&&(c=new Jl.PassThrough,c.end());let b=ux(t,E);if(!Hj(b)&&b.length>0&&e.length>0){let{command:I}=b[b.length-1];for(;I.then;)I=I.then.line;let T=I.chain;for(;T.then;)T=T.then.chain;T.type===\"command\"&&(T.args=T.args.concat(e.map(N=>({type:\"argument\",segments:[{type:\"text\",text:N}]}))))}return await QR(b,{args:e,baseFs:r,builtins:S,initialStdin:c,initialStdout:f,initialStderr:p,glob:E},{cwd:a,environment:C,exitCode:null,procedures:{},stdin:c,stdout:f,stderr:p,variables:Object.assign({},h,{\"?\":0}),nextBackgroundJobIndex:1,backgroundJobs:[]})}var Mpe,Upe,Jl,_pe,Vnt,Knt,pv=Ze(()=>{Dt();wc();Mpe=ut(RE()),Upe=Ie(\"os\"),Jl=Ie(\"stream\"),_pe=Ie(\"timers/promises\");wpe();Bpe();Ppe();Uj();Uj();Vnt=new Map([[\"cd\",async([t=(0,Upe.homedir)(),...e],r,s)=>{let a=J.resolve(s.cwd,fe.toPortablePath(t));if(!(await r.baseFs.statPromise(a).catch(c=>{throw c.code===\"ENOENT\"?new Vl(`cd: no such file or directory: ${t}`):c})).isDirectory())throw new Vl(`cd: not a directory: ${t}`);return s.cwd=a,0}],[\"pwd\",async(t,e,r)=>(r.stdout.write(`${fe.fromPortablePath(r.cwd)}\n`),0)],[\":\",async(t,e,r)=>0],[\"true\",async(t,e,r)=>0],[\"false\",async(t,e,r)=>1],[\"exit\",async([t,...e],r,s)=>s.exitCode=parseInt(t??s.variables[\"?\"],10)],[\"echo\",async(t,e,r)=>(r.stdout.write(`${t.join(\" \")}\n`),0)],[\"sleep\",async([t],e,r)=>{if(typeof t>\"u\")throw new Vl(\"sleep: missing operand\");let s=Number(t);if(Number.isNaN(s))throw new Vl(`sleep: invalid time interval '${t}'`);return await(0,_pe.setTimeout)(1e3*s,0)}],[\"unset\",async(t,e,r)=>{for(let s of t)delete r.environment[s],delete r.variables[s];return 0}],[\"__ysh_run_procedure\",async(t,e,r)=>{let s=r.procedures[t[0]];return await bR(s,{stdin:new Oc(r.stdin),stdout:new Oc(r.stdout),stderr:new Oc(r.stderr)}).run()}],[\"__ysh_set_redirects\",async(t,e,r)=>{let s=r.stdin,a=r.stdout,n=r.stderr,c=[],f=[],p=[],h=0;for(;t[h]!==\"--\";){let C=t[h++],{type:S,fd:b}=JSON.parse(C),I=W=>{switch(b){case null:case 0:c.push(W);break;default:throw new Error(`Unsupported file descriptor: \"${b}\"`)}},T=W=>{switch(b){case null:case 1:f.push(W);break;case 2:p.push(W);break;default:throw new Error(`Unsupported file descriptor: \"${b}\"`)}},N=Number(t[h++]),U=h+N;for(let W=h;W<U;++h,++W)switch(S){case\"<\":I(()=>e.baseFs.createReadStream(J.resolve(r.cwd,fe.toPortablePath(t[W]))));break;case\"<<<\":I(()=>{let ee=new Jl.PassThrough;return process.nextTick(()=>{ee.write(`${t[W]}\n`),ee.end()}),ee});break;case\"<&\":I(()=>Fpe(Number(t[W]),1,r));break;case\">\":case\">>\":{let ee=J.resolve(r.cwd,fe.toPortablePath(t[W]));T(ee===\"/dev/null\"?new Jl.Writable({autoDestroy:!0,emitClose:!0,write(ie,ue,le){setImmediate(le)}}):e.baseFs.createWriteStream(ee,S===\">>\"?{flags:\"a\"}:void 0))}break;case\">&\":T(Fpe(Number(t[W]),2,r));break;default:throw new Error(`Assertion failed: Unsupported redirection type: \"${S}\"`)}}if(c.length>0){let C=new Jl.PassThrough;s=C;let S=b=>{if(b===c.length)C.end();else{let I=c[b]();I.pipe(C,{end:!1}),I.on(\"end\",()=>{S(b+1)})}};S(0)}if(f.length>0){let C=new Jl.PassThrough;a=C;for(let S of f)C.pipe(S)}if(p.length>0){let C=new Jl.PassThrough;n=C;for(let S of p)C.pipe(S)}let E=await bR(gv(t.slice(h+1),e,r),{stdin:new Oc(s),stdout:new Oc(a),stderr:new Oc(n)}).run();return await Promise.all(f.map(C=>new Promise((S,b)=>{C.on(\"error\",I=>{b(I)}),C.on(\"close\",()=>{S()}),C.end()}))),await Promise.all(p.map(C=>new Promise((S,b)=>{C.on(\"error\",I=>{b(I)}),C.on(\"close\",()=>{S()}),C.end()}))),E}]]);Knt={addition:(t,e)=>t+e,subtraction:(t,e)=>t-e,multiplication:(t,e)=>t*e,division:(t,e)=>Math.trunc(t/e)}});var Gpe=_((d4t,RR)=>{function eit(){var t=0,e=1,r=2,s=3,a=4,n=5,c=6,f=7,p=8,h=9,E=10,C=11,S=12,b=13,I=14,T=15,N=16,U=17,W=0,ee=1,ie=2,ue=3,le=4;function me(g,we){return 55296<=g.charCodeAt(we)&&g.charCodeAt(we)<=56319&&56320<=g.charCodeAt(we+1)&&g.charCodeAt(we+1)<=57343}function pe(g,we){we===void 0&&(we=0);var ye=g.charCodeAt(we);if(55296<=ye&&ye<=56319&&we<g.length-1){var Ae=ye,se=g.charCodeAt(we+1);return 56320<=se&&se<=57343?(Ae-55296)*1024+(se-56320)+65536:Ae}if(56320<=ye&&ye<=57343&&we>=1){var Ae=g.charCodeAt(we-1),se=ye;return 55296<=Ae&&Ae<=56319?(Ae-55296)*1024+(se-56320)+65536:se}return ye}function Be(g,we,ye){var Ae=[g].concat(we).concat([ye]),se=Ae[Ae.length-2],X=ye,De=Ae.lastIndexOf(I);if(De>1&&Ae.slice(1,De).every(function(j){return j==s})&&[s,b,U].indexOf(g)==-1)return ie;var Te=Ae.lastIndexOf(a);if(Te>0&&Ae.slice(1,Te).every(function(j){return j==a})&&[S,a].indexOf(se)==-1)return Ae.filter(function(j){return j==a}).length%2==1?ue:le;if(se==t&&X==e)return W;if(se==r||se==t||se==e)return X==I&&we.every(function(j){return j==s})?ie:ee;if(X==r||X==t||X==e)return ee;if(se==c&&(X==c||X==f||X==h||X==E))return W;if((se==h||se==f)&&(X==f||X==p))return W;if((se==E||se==p)&&X==p)return W;if(X==s||X==T)return W;if(X==n)return W;if(se==S)return W;var mt=Ae.indexOf(s)!=-1?Ae.lastIndexOf(s)-1:Ae.length-2;return[b,U].indexOf(Ae[mt])!=-1&&Ae.slice(mt+1,-1).every(function(j){return j==s})&&X==I||se==T&&[N,U].indexOf(X)!=-1?W:we.indexOf(a)!=-1?ie:se==a&&X==a?W:ee}this.nextBreak=function(g,we){if(we===void 0&&(we=0),we<0)return 0;if(we>=g.length-1)return g.length;for(var ye=Ce(pe(g,we)),Ae=[],se=we+1;se<g.length;se++)if(!me(g,se-1)){var X=Ce(pe(g,se));if(Be(ye,Ae,X))return se;Ae.push(X)}return g.length},this.splitGraphemes=function(g){for(var we=[],ye=0,Ae;(Ae=this.nextBreak(g,ye))<g.length;)we.push(g.slice(ye,Ae)),ye=Ae;return ye<g.length&&we.push(g.slice(ye)),we},this.iterateGraphemes=function(g){var we=0,ye={next:function(){var Ae,se;return(se=this.nextBreak(g,we))<g.length?(Ae=g.slice(we,se),we=se,{value:Ae,done:!1}):we<g.length?(Ae=g.slice(we),we=g.length,{value:Ae,done:!1}):{value:void 0,done:!0}}.bind(this)};return typeof Symbol<\"u\"&&Symbol.iterator&&(ye[Symbol.iterator]=function(){return ye}),ye},this.countGraphemes=function(g){for(var we=0,ye=0,Ae;(Ae=this.nextBreak(g,ye))<g.length;)ye=Ae,we++;return ye<g.length&&we++,we};function Ce(g){return 1536<=g&&g<=1541||g==1757||g==1807||g==2274||g==3406||g==69821||70082<=g&&g<=70083||g==72250||72326<=g&&g<=72329||g==73030?S:g==13?t:g==10?e:0<=g&&g<=9||11<=g&&g<=12||14<=g&&g<=31||127<=g&&g<=159||g==173||g==1564||g==6158||g==8203||8206<=g&&g<=8207||g==8232||g==8233||8234<=g&&g<=8238||8288<=g&&g<=8292||g==8293||8294<=g&&g<=8303||55296<=g&&g<=57343||g==65279||65520<=g&&g<=65528||65529<=g&&g<=65531||113824<=g&&g<=113827||119155<=g&&g<=119162||g==917504||g==917505||917506<=g&&g<=917535||917632<=g&&g<=917759||918e3<=g&&g<=921599?r:768<=g&&g<=879||1155<=g&&g<=1159||1160<=g&&g<=1161||1425<=g&&g<=1469||g==1471||1473<=g&&g<=1474||1476<=g&&g<=1477||g==1479||1552<=g&&g<=1562||1611<=g&&g<=1631||g==1648||1750<=g&&g<=1756||1759<=g&&g<=1764||1767<=g&&g<=1768||1770<=g&&g<=1773||g==1809||1840<=g&&g<=1866||1958<=g&&g<=1968||2027<=g&&g<=2035||2070<=g&&g<=2073||2075<=g&&g<=2083||2085<=g&&g<=2087||2089<=g&&g<=2093||2137<=g&&g<=2139||2260<=g&&g<=2273||2275<=g&&g<=2306||g==2362||g==2364||2369<=g&&g<=2376||g==2381||2385<=g&&g<=2391||2402<=g&&g<=2403||g==2433||g==2492||g==2494||2497<=g&&g<=2500||g==2509||g==2519||2530<=g&&g<=2531||2561<=g&&g<=2562||g==2620||2625<=g&&g<=2626||2631<=g&&g<=2632||2635<=g&&g<=2637||g==2641||2672<=g&&g<=2673||g==2677||2689<=g&&g<=2690||g==2748||2753<=g&&g<=2757||2759<=g&&g<=2760||g==2765||2786<=g&&g<=2787||2810<=g&&g<=2815||g==2817||g==2876||g==2878||g==2879||2881<=g&&g<=2884||g==2893||g==2902||g==2903||2914<=g&&g<=2915||g==2946||g==3006||g==3008||g==3021||g==3031||g==3072||3134<=g&&g<=3136||3142<=g&&g<=3144||3146<=g&&g<=3149||3157<=g&&g<=3158||3170<=g&&g<=3171||g==3201||g==3260||g==3263||g==3266||g==3270||3276<=g&&g<=3277||3285<=g&&g<=3286||3298<=g&&g<=3299||3328<=g&&g<=3329||3387<=g&&g<=3388||g==3390||3393<=g&&g<=3396||g==3405||g==3415||3426<=g&&g<=3427||g==3530||g==3535||3538<=g&&g<=3540||g==3542||g==3551||g==3633||3636<=g&&g<=3642||3655<=g&&g<=3662||g==3761||3764<=g&&g<=3769||3771<=g&&g<=3772||3784<=g&&g<=3789||3864<=g&&g<=3865||g==3893||g==3895||g==3897||3953<=g&&g<=3966||3968<=g&&g<=3972||3974<=g&&g<=3975||3981<=g&&g<=3991||3993<=g&&g<=4028||g==4038||4141<=g&&g<=4144||4146<=g&&g<=4151||4153<=g&&g<=4154||4157<=g&&g<=4158||4184<=g&&g<=4185||4190<=g&&g<=4192||4209<=g&&g<=4212||g==4226||4229<=g&&g<=4230||g==4237||g==4253||4957<=g&&g<=4959||5906<=g&&g<=5908||5938<=g&&g<=5940||5970<=g&&g<=5971||6002<=g&&g<=6003||6068<=g&&g<=6069||6071<=g&&g<=6077||g==6086||6089<=g&&g<=6099||g==6109||6155<=g&&g<=6157||6277<=g&&g<=6278||g==6313||6432<=g&&g<=6434||6439<=g&&g<=6440||g==6450||6457<=g&&g<=6459||6679<=g&&g<=6680||g==6683||g==6742||6744<=g&&g<=6750||g==6752||g==6754||6757<=g&&g<=6764||6771<=g&&g<=6780||g==6783||6832<=g&&g<=6845||g==6846||6912<=g&&g<=6915||g==6964||6966<=g&&g<=6970||g==6972||g==6978||7019<=g&&g<=7027||7040<=g&&g<=7041||7074<=g&&g<=7077||7080<=g&&g<=7081||7083<=g&&g<=7085||g==7142||7144<=g&&g<=7145||g==7149||7151<=g&&g<=7153||7212<=g&&g<=7219||7222<=g&&g<=7223||7376<=g&&g<=7378||7380<=g&&g<=7392||7394<=g&&g<=7400||g==7405||g==7412||7416<=g&&g<=7417||7616<=g&&g<=7673||7675<=g&&g<=7679||g==8204||8400<=g&&g<=8412||8413<=g&&g<=8416||g==8417||8418<=g&&g<=8420||8421<=g&&g<=8432||11503<=g&&g<=11505||g==11647||11744<=g&&g<=11775||12330<=g&&g<=12333||12334<=g&&g<=12335||12441<=g&&g<=12442||g==42607||42608<=g&&g<=42610||42612<=g&&g<=42621||42654<=g&&g<=42655||42736<=g&&g<=42737||g==43010||g==43014||g==43019||43045<=g&&g<=43046||43204<=g&&g<=43205||43232<=g&&g<=43249||43302<=g&&g<=43309||43335<=g&&g<=43345||43392<=g&&g<=43394||g==43443||43446<=g&&g<=43449||g==43452||g==43493||43561<=g&&g<=43566||43569<=g&&g<=43570||43573<=g&&g<=43574||g==43587||g==43596||g==43644||g==43696||43698<=g&&g<=43700||43703<=g&&g<=43704||43710<=g&&g<=43711||g==43713||43756<=g&&g<=43757||g==43766||g==44005||g==44008||g==44013||g==64286||65024<=g&&g<=65039||65056<=g&&g<=65071||65438<=g&&g<=65439||g==66045||g==66272||66422<=g&&g<=66426||68097<=g&&g<=68099||68101<=g&&g<=68102||68108<=g&&g<=68111||68152<=g&&g<=68154||g==68159||68325<=g&&g<=68326||g==69633||69688<=g&&g<=69702||69759<=g&&g<=69761||69811<=g&&g<=69814||69817<=g&&g<=69818||69888<=g&&g<=69890||69927<=g&&g<=69931||69933<=g&&g<=69940||g==70003||70016<=g&&g<=70017||70070<=g&&g<=70078||70090<=g&&g<=70092||70191<=g&&g<=70193||g==70196||70198<=g&&g<=70199||g==70206||g==70367||70371<=g&&g<=70378||70400<=g&&g<=70401||g==70460||g==70462||g==70464||g==70487||70502<=g&&g<=70508||70512<=g&&g<=70516||70712<=g&&g<=70719||70722<=g&&g<=70724||g==70726||g==70832||70835<=g&&g<=70840||g==70842||g==70845||70847<=g&&g<=70848||70850<=g&&g<=70851||g==71087||71090<=g&&g<=71093||71100<=g&&g<=71101||71103<=g&&g<=71104||71132<=g&&g<=71133||71219<=g&&g<=71226||g==71229||71231<=g&&g<=71232||g==71339||g==71341||71344<=g&&g<=71349||g==71351||71453<=g&&g<=71455||71458<=g&&g<=71461||71463<=g&&g<=71467||72193<=g&&g<=72198||72201<=g&&g<=72202||72243<=g&&g<=72248||72251<=g&&g<=72254||g==72263||72273<=g&&g<=72278||72281<=g&&g<=72283||72330<=g&&g<=72342||72344<=g&&g<=72345||72752<=g&&g<=72758||72760<=g&&g<=72765||g==72767||72850<=g&&g<=72871||72874<=g&&g<=72880||72882<=g&&g<=72883||72885<=g&&g<=72886||73009<=g&&g<=73014||g==73018||73020<=g&&g<=73021||73023<=g&&g<=73029||g==73031||92912<=g&&g<=92916||92976<=g&&g<=92982||94095<=g&&g<=94098||113821<=g&&g<=113822||g==119141||119143<=g&&g<=119145||119150<=g&&g<=119154||119163<=g&&g<=119170||119173<=g&&g<=119179||119210<=g&&g<=119213||119362<=g&&g<=119364||121344<=g&&g<=121398||121403<=g&&g<=121452||g==121461||g==121476||121499<=g&&g<=121503||121505<=g&&g<=121519||122880<=g&&g<=122886||122888<=g&&g<=122904||122907<=g&&g<=122913||122915<=g&&g<=122916||122918<=g&&g<=122922||125136<=g&&g<=125142||125252<=g&&g<=125258||917536<=g&&g<=917631||917760<=g&&g<=917999?s:127462<=g&&g<=127487?a:g==2307||g==2363||2366<=g&&g<=2368||2377<=g&&g<=2380||2382<=g&&g<=2383||2434<=g&&g<=2435||2495<=g&&g<=2496||2503<=g&&g<=2504||2507<=g&&g<=2508||g==2563||2622<=g&&g<=2624||g==2691||2750<=g&&g<=2752||g==2761||2763<=g&&g<=2764||2818<=g&&g<=2819||g==2880||2887<=g&&g<=2888||2891<=g&&g<=2892||g==3007||3009<=g&&g<=3010||3014<=g&&g<=3016||3018<=g&&g<=3020||3073<=g&&g<=3075||3137<=g&&g<=3140||3202<=g&&g<=3203||g==3262||3264<=g&&g<=3265||3267<=g&&g<=3268||3271<=g&&g<=3272||3274<=g&&g<=3275||3330<=g&&g<=3331||3391<=g&&g<=3392||3398<=g&&g<=3400||3402<=g&&g<=3404||3458<=g&&g<=3459||3536<=g&&g<=3537||3544<=g&&g<=3550||3570<=g&&g<=3571||g==3635||g==3763||3902<=g&&g<=3903||g==3967||g==4145||4155<=g&&g<=4156||4182<=g&&g<=4183||g==4228||g==6070||6078<=g&&g<=6085||6087<=g&&g<=6088||6435<=g&&g<=6438||6441<=g&&g<=6443||6448<=g&&g<=6449||6451<=g&&g<=6456||6681<=g&&g<=6682||g==6741||g==6743||6765<=g&&g<=6770||g==6916||g==6965||g==6971||6973<=g&&g<=6977||6979<=g&&g<=6980||g==7042||g==7073||7078<=g&&g<=7079||g==7082||g==7143||7146<=g&&g<=7148||g==7150||7154<=g&&g<=7155||7204<=g&&g<=7211||7220<=g&&g<=7221||g==7393||7410<=g&&g<=7411||g==7415||43043<=g&&g<=43044||g==43047||43136<=g&&g<=43137||43188<=g&&g<=43203||43346<=g&&g<=43347||g==43395||43444<=g&&g<=43445||43450<=g&&g<=43451||43453<=g&&g<=43456||43567<=g&&g<=43568||43571<=g&&g<=43572||g==43597||g==43755||43758<=g&&g<=43759||g==43765||44003<=g&&g<=44004||44006<=g&&g<=44007||44009<=g&&g<=44010||g==44012||g==69632||g==69634||g==69762||69808<=g&&g<=69810||69815<=g&&g<=69816||g==69932||g==70018||70067<=g&&g<=70069||70079<=g&&g<=70080||70188<=g&&g<=70190||70194<=g&&g<=70195||g==70197||70368<=g&&g<=70370||70402<=g&&g<=70403||g==70463||70465<=g&&g<=70468||70471<=g&&g<=70472||70475<=g&&g<=70477||70498<=g&&g<=70499||70709<=g&&g<=70711||70720<=g&&g<=70721||g==70725||70833<=g&&g<=70834||g==70841||70843<=g&&g<=70844||g==70846||g==70849||71088<=g&&g<=71089||71096<=g&&g<=71099||g==71102||71216<=g&&g<=71218||71227<=g&&g<=71228||g==71230||g==71340||71342<=g&&g<=71343||g==71350||71456<=g&&g<=71457||g==71462||72199<=g&&g<=72200||g==72249||72279<=g&&g<=72280||g==72343||g==72751||g==72766||g==72873||g==72881||g==72884||94033<=g&&g<=94078||g==119142||g==119149?n:4352<=g&&g<=4447||43360<=g&&g<=43388?c:4448<=g&&g<=4519||55216<=g&&g<=55238?f:4520<=g&&g<=4607||55243<=g&&g<=55291?p:g==44032||g==44060||g==44088||g==44116||g==44144||g==44172||g==44200||g==44228||g==44256||g==44284||g==44312||g==44340||g==44368||g==44396||g==44424||g==44452||g==44480||g==44508||g==44536||g==44564||g==44592||g==44620||g==44648||g==44676||g==44704||g==44732||g==44760||g==44788||g==44816||g==44844||g==44872||g==44900||g==44928||g==44956||g==44984||g==45012||g==45040||g==45068||g==45096||g==45124||g==45152||g==45180||g==45208||g==45236||g==45264||g==45292||g==45320||g==45348||g==45376||g==45404||g==45432||g==45460||g==45488||g==45516||g==45544||g==45572||g==45600||g==45628||g==45656||g==45684||g==45712||g==45740||g==45768||g==45796||g==45824||g==45852||g==45880||g==45908||g==45936||g==45964||g==45992||g==46020||g==46048||g==46076||g==46104||g==46132||g==46160||g==46188||g==46216||g==46244||g==46272||g==46300||g==46328||g==46356||g==46384||g==46412||g==46440||g==46468||g==46496||g==46524||g==46552||g==46580||g==46608||g==46636||g==46664||g==46692||g==46720||g==46748||g==46776||g==46804||g==46832||g==46860||g==46888||g==46916||g==46944||g==46972||g==47e3||g==47028||g==47056||g==47084||g==47112||g==47140||g==47168||g==47196||g==47224||g==47252||g==47280||g==47308||g==47336||g==47364||g==47392||g==47420||g==47448||g==47476||g==47504||g==47532||g==47560||g==47588||g==47616||g==47644||g==47672||g==47700||g==47728||g==47756||g==47784||g==47812||g==47840||g==47868||g==47896||g==47924||g==47952||g==47980||g==48008||g==48036||g==48064||g==48092||g==48120||g==48148||g==48176||g==48204||g==48232||g==48260||g==48288||g==48316||g==48344||g==48372||g==48400||g==48428||g==48456||g==48484||g==48512||g==48540||g==48568||g==48596||g==48624||g==48652||g==48680||g==48708||g==48736||g==48764||g==48792||g==48820||g==48848||g==48876||g==48904||g==48932||g==48960||g==48988||g==49016||g==49044||g==49072||g==49100||g==49128||g==49156||g==49184||g==49212||g==49240||g==49268||g==49296||g==49324||g==49352||g==49380||g==49408||g==49436||g==49464||g==49492||g==49520||g==49548||g==49576||g==49604||g==49632||g==49660||g==49688||g==49716||g==49744||g==49772||g==49800||g==49828||g==49856||g==49884||g==49912||g==49940||g==49968||g==49996||g==50024||g==50052||g==50080||g==50108||g==50136||g==50164||g==50192||g==50220||g==50248||g==50276||g==50304||g==50332||g==50360||g==50388||g==50416||g==50444||g==50472||g==50500||g==50528||g==50556||g==50584||g==50612||g==50640||g==50668||g==50696||g==50724||g==50752||g==50780||g==50808||g==50836||g==50864||g==50892||g==50920||g==50948||g==50976||g==51004||g==51032||g==51060||g==51088||g==51116||g==51144||g==51172||g==51200||g==51228||g==51256||g==51284||g==51312||g==51340||g==51368||g==51396||g==51424||g==51452||g==51480||g==51508||g==51536||g==51564||g==51592||g==51620||g==51648||g==51676||g==51704||g==51732||g==51760||g==51788||g==51816||g==51844||g==51872||g==51900||g==51928||g==51956||g==51984||g==52012||g==52040||g==52068||g==52096||g==52124||g==52152||g==52180||g==52208||g==52236||g==52264||g==52292||g==52320||g==52348||g==52376||g==52404||g==52432||g==52460||g==52488||g==52516||g==52544||g==52572||g==52600||g==52628||g==52656||g==52684||g==52712||g==52740||g==52768||g==52796||g==52824||g==52852||g==52880||g==52908||g==52936||g==52964||g==52992||g==53020||g==53048||g==53076||g==53104||g==53132||g==53160||g==53188||g==53216||g==53244||g==53272||g==53300||g==53328||g==53356||g==53384||g==53412||g==53440||g==53468||g==53496||g==53524||g==53552||g==53580||g==53608||g==53636||g==53664||g==53692||g==53720||g==53748||g==53776||g==53804||g==53832||g==53860||g==53888||g==53916||g==53944||g==53972||g==54e3||g==54028||g==54056||g==54084||g==54112||g==54140||g==54168||g==54196||g==54224||g==54252||g==54280||g==54308||g==54336||g==54364||g==54392||g==54420||g==54448||g==54476||g==54504||g==54532||g==54560||g==54588||g==54616||g==54644||g==54672||g==54700||g==54728||g==54756||g==54784||g==54812||g==54840||g==54868||g==54896||g==54924||g==54952||g==54980||g==55008||g==55036||g==55064||g==55092||g==55120||g==55148||g==55176?h:44033<=g&&g<=44059||44061<=g&&g<=44087||44089<=g&&g<=44115||44117<=g&&g<=44143||44145<=g&&g<=44171||44173<=g&&g<=44199||44201<=g&&g<=44227||44229<=g&&g<=44255||44257<=g&&g<=44283||44285<=g&&g<=44311||44313<=g&&g<=44339||44341<=g&&g<=44367||44369<=g&&g<=44395||44397<=g&&g<=44423||44425<=g&&g<=44451||44453<=g&&g<=44479||44481<=g&&g<=44507||44509<=g&&g<=44535||44537<=g&&g<=44563||44565<=g&&g<=44591||44593<=g&&g<=44619||44621<=g&&g<=44647||44649<=g&&g<=44675||44677<=g&&g<=44703||44705<=g&&g<=44731||44733<=g&&g<=44759||44761<=g&&g<=44787||44789<=g&&g<=44815||44817<=g&&g<=44843||44845<=g&&g<=44871||44873<=g&&g<=44899||44901<=g&&g<=44927||44929<=g&&g<=44955||44957<=g&&g<=44983||44985<=g&&g<=45011||45013<=g&&g<=45039||45041<=g&&g<=45067||45069<=g&&g<=45095||45097<=g&&g<=45123||45125<=g&&g<=45151||45153<=g&&g<=45179||45181<=g&&g<=45207||45209<=g&&g<=45235||45237<=g&&g<=45263||45265<=g&&g<=45291||45293<=g&&g<=45319||45321<=g&&g<=45347||45349<=g&&g<=45375||45377<=g&&g<=45403||45405<=g&&g<=45431||45433<=g&&g<=45459||45461<=g&&g<=45487||45489<=g&&g<=45515||45517<=g&&g<=45543||45545<=g&&g<=45571||45573<=g&&g<=45599||45601<=g&&g<=45627||45629<=g&&g<=45655||45657<=g&&g<=45683||45685<=g&&g<=45711||45713<=g&&g<=45739||45741<=g&&g<=45767||45769<=g&&g<=45795||45797<=g&&g<=45823||45825<=g&&g<=45851||45853<=g&&g<=45879||45881<=g&&g<=45907||45909<=g&&g<=45935||45937<=g&&g<=45963||45965<=g&&g<=45991||45993<=g&&g<=46019||46021<=g&&g<=46047||46049<=g&&g<=46075||46077<=g&&g<=46103||46105<=g&&g<=46131||46133<=g&&g<=46159||46161<=g&&g<=46187||46189<=g&&g<=46215||46217<=g&&g<=46243||46245<=g&&g<=46271||46273<=g&&g<=46299||46301<=g&&g<=46327||46329<=g&&g<=46355||46357<=g&&g<=46383||46385<=g&&g<=46411||46413<=g&&g<=46439||46441<=g&&g<=46467||46469<=g&&g<=46495||46497<=g&&g<=46523||46525<=g&&g<=46551||46553<=g&&g<=46579||46581<=g&&g<=46607||46609<=g&&g<=46635||46637<=g&&g<=46663||46665<=g&&g<=46691||46693<=g&&g<=46719||46721<=g&&g<=46747||46749<=g&&g<=46775||46777<=g&&g<=46803||46805<=g&&g<=46831||46833<=g&&g<=46859||46861<=g&&g<=46887||46889<=g&&g<=46915||46917<=g&&g<=46943||46945<=g&&g<=46971||46973<=g&&g<=46999||47001<=g&&g<=47027||47029<=g&&g<=47055||47057<=g&&g<=47083||47085<=g&&g<=47111||47113<=g&&g<=47139||47141<=g&&g<=47167||47169<=g&&g<=47195||47197<=g&&g<=47223||47225<=g&&g<=47251||47253<=g&&g<=47279||47281<=g&&g<=47307||47309<=g&&g<=47335||47337<=g&&g<=47363||47365<=g&&g<=47391||47393<=g&&g<=47419||47421<=g&&g<=47447||47449<=g&&g<=47475||47477<=g&&g<=47503||47505<=g&&g<=47531||47533<=g&&g<=47559||47561<=g&&g<=47587||47589<=g&&g<=47615||47617<=g&&g<=47643||47645<=g&&g<=47671||47673<=g&&g<=47699||47701<=g&&g<=47727||47729<=g&&g<=47755||47757<=g&&g<=47783||47785<=g&&g<=47811||47813<=g&&g<=47839||47841<=g&&g<=47867||47869<=g&&g<=47895||47897<=g&&g<=47923||47925<=g&&g<=47951||47953<=g&&g<=47979||47981<=g&&g<=48007||48009<=g&&g<=48035||48037<=g&&g<=48063||48065<=g&&g<=48091||48093<=g&&g<=48119||48121<=g&&g<=48147||48149<=g&&g<=48175||48177<=g&&g<=48203||48205<=g&&g<=48231||48233<=g&&g<=48259||48261<=g&&g<=48287||48289<=g&&g<=48315||48317<=g&&g<=48343||48345<=g&&g<=48371||48373<=g&&g<=48399||48401<=g&&g<=48427||48429<=g&&g<=48455||48457<=g&&g<=48483||48485<=g&&g<=48511||48513<=g&&g<=48539||48541<=g&&g<=48567||48569<=g&&g<=48595||48597<=g&&g<=48623||48625<=g&&g<=48651||48653<=g&&g<=48679||48681<=g&&g<=48707||48709<=g&&g<=48735||48737<=g&&g<=48763||48765<=g&&g<=48791||48793<=g&&g<=48819||48821<=g&&g<=48847||48849<=g&&g<=48875||48877<=g&&g<=48903||48905<=g&&g<=48931||48933<=g&&g<=48959||48961<=g&&g<=48987||48989<=g&&g<=49015||49017<=g&&g<=49043||49045<=g&&g<=49071||49073<=g&&g<=49099||49101<=g&&g<=49127||49129<=g&&g<=49155||49157<=g&&g<=49183||49185<=g&&g<=49211||49213<=g&&g<=49239||49241<=g&&g<=49267||49269<=g&&g<=49295||49297<=g&&g<=49323||49325<=g&&g<=49351||49353<=g&&g<=49379||49381<=g&&g<=49407||49409<=g&&g<=49435||49437<=g&&g<=49463||49465<=g&&g<=49491||49493<=g&&g<=49519||49521<=g&&g<=49547||49549<=g&&g<=49575||49577<=g&&g<=49603||49605<=g&&g<=49631||49633<=g&&g<=49659||49661<=g&&g<=49687||49689<=g&&g<=49715||49717<=g&&g<=49743||49745<=g&&g<=49771||49773<=g&&g<=49799||49801<=g&&g<=49827||49829<=g&&g<=49855||49857<=g&&g<=49883||49885<=g&&g<=49911||49913<=g&&g<=49939||49941<=g&&g<=49967||49969<=g&&g<=49995||49997<=g&&g<=50023||50025<=g&&g<=50051||50053<=g&&g<=50079||50081<=g&&g<=50107||50109<=g&&g<=50135||50137<=g&&g<=50163||50165<=g&&g<=50191||50193<=g&&g<=50219||50221<=g&&g<=50247||50249<=g&&g<=50275||50277<=g&&g<=50303||50305<=g&&g<=50331||50333<=g&&g<=50359||50361<=g&&g<=50387||50389<=g&&g<=50415||50417<=g&&g<=50443||50445<=g&&g<=50471||50473<=g&&g<=50499||50501<=g&&g<=50527||50529<=g&&g<=50555||50557<=g&&g<=50583||50585<=g&&g<=50611||50613<=g&&g<=50639||50641<=g&&g<=50667||50669<=g&&g<=50695||50697<=g&&g<=50723||50725<=g&&g<=50751||50753<=g&&g<=50779||50781<=g&&g<=50807||50809<=g&&g<=50835||50837<=g&&g<=50863||50865<=g&&g<=50891||50893<=g&&g<=50919||50921<=g&&g<=50947||50949<=g&&g<=50975||50977<=g&&g<=51003||51005<=g&&g<=51031||51033<=g&&g<=51059||51061<=g&&g<=51087||51089<=g&&g<=51115||51117<=g&&g<=51143||51145<=g&&g<=51171||51173<=g&&g<=51199||51201<=g&&g<=51227||51229<=g&&g<=51255||51257<=g&&g<=51283||51285<=g&&g<=51311||51313<=g&&g<=51339||51341<=g&&g<=51367||51369<=g&&g<=51395||51397<=g&&g<=51423||51425<=g&&g<=51451||51453<=g&&g<=51479||51481<=g&&g<=51507||51509<=g&&g<=51535||51537<=g&&g<=51563||51565<=g&&g<=51591||51593<=g&&g<=51619||51621<=g&&g<=51647||51649<=g&&g<=51675||51677<=g&&g<=51703||51705<=g&&g<=51731||51733<=g&&g<=51759||51761<=g&&g<=51787||51789<=g&&g<=51815||51817<=g&&g<=51843||51845<=g&&g<=51871||51873<=g&&g<=51899||51901<=g&&g<=51927||51929<=g&&g<=51955||51957<=g&&g<=51983||51985<=g&&g<=52011||52013<=g&&g<=52039||52041<=g&&g<=52067||52069<=g&&g<=52095||52097<=g&&g<=52123||52125<=g&&g<=52151||52153<=g&&g<=52179||52181<=g&&g<=52207||52209<=g&&g<=52235||52237<=g&&g<=52263||52265<=g&&g<=52291||52293<=g&&g<=52319||52321<=g&&g<=52347||52349<=g&&g<=52375||52377<=g&&g<=52403||52405<=g&&g<=52431||52433<=g&&g<=52459||52461<=g&&g<=52487||52489<=g&&g<=52515||52517<=g&&g<=52543||52545<=g&&g<=52571||52573<=g&&g<=52599||52601<=g&&g<=52627||52629<=g&&g<=52655||52657<=g&&g<=52683||52685<=g&&g<=52711||52713<=g&&g<=52739||52741<=g&&g<=52767||52769<=g&&g<=52795||52797<=g&&g<=52823||52825<=g&&g<=52851||52853<=g&&g<=52879||52881<=g&&g<=52907||52909<=g&&g<=52935||52937<=g&&g<=52963||52965<=g&&g<=52991||52993<=g&&g<=53019||53021<=g&&g<=53047||53049<=g&&g<=53075||53077<=g&&g<=53103||53105<=g&&g<=53131||53133<=g&&g<=53159||53161<=g&&g<=53187||53189<=g&&g<=53215||53217<=g&&g<=53243||53245<=g&&g<=53271||53273<=g&&g<=53299||53301<=g&&g<=53327||53329<=g&&g<=53355||53357<=g&&g<=53383||53385<=g&&g<=53411||53413<=g&&g<=53439||53441<=g&&g<=53467||53469<=g&&g<=53495||53497<=g&&g<=53523||53525<=g&&g<=53551||53553<=g&&g<=53579||53581<=g&&g<=53607||53609<=g&&g<=53635||53637<=g&&g<=53663||53665<=g&&g<=53691||53693<=g&&g<=53719||53721<=g&&g<=53747||53749<=g&&g<=53775||53777<=g&&g<=53803||53805<=g&&g<=53831||53833<=g&&g<=53859||53861<=g&&g<=53887||53889<=g&&g<=53915||53917<=g&&g<=53943||53945<=g&&g<=53971||53973<=g&&g<=53999||54001<=g&&g<=54027||54029<=g&&g<=54055||54057<=g&&g<=54083||54085<=g&&g<=54111||54113<=g&&g<=54139||54141<=g&&g<=54167||54169<=g&&g<=54195||54197<=g&&g<=54223||54225<=g&&g<=54251||54253<=g&&g<=54279||54281<=g&&g<=54307||54309<=g&&g<=54335||54337<=g&&g<=54363||54365<=g&&g<=54391||54393<=g&&g<=54419||54421<=g&&g<=54447||54449<=g&&g<=54475||54477<=g&&g<=54503||54505<=g&&g<=54531||54533<=g&&g<=54559||54561<=g&&g<=54587||54589<=g&&g<=54615||54617<=g&&g<=54643||54645<=g&&g<=54671||54673<=g&&g<=54699||54701<=g&&g<=54727||54729<=g&&g<=54755||54757<=g&&g<=54783||54785<=g&&g<=54811||54813<=g&&g<=54839||54841<=g&&g<=54867||54869<=g&&g<=54895||54897<=g&&g<=54923||54925<=g&&g<=54951||54953<=g&&g<=54979||54981<=g&&g<=55007||55009<=g&&g<=55035||55037<=g&&g<=55063||55065<=g&&g<=55091||55093<=g&&g<=55119||55121<=g&&g<=55147||55149<=g&&g<=55175||55177<=g&&g<=55203?E:g==9757||g==9977||9994<=g&&g<=9997||g==127877||127938<=g&&g<=127940||g==127943||127946<=g&&g<=127948||128066<=g&&g<=128067||128070<=g&&g<=128080||g==128110||128112<=g&&g<=128120||g==128124||128129<=g&&g<=128131||128133<=g&&g<=128135||g==128170||128372<=g&&g<=128373||g==128378||g==128400||128405<=g&&g<=128406||128581<=g&&g<=128583||128587<=g&&g<=128591||g==128675||128692<=g&&g<=128694||g==128704||g==128716||129304<=g&&g<=129308||129310<=g&&g<=129311||g==129318||129328<=g&&g<=129337||129341<=g&&g<=129342||129489<=g&&g<=129501?b:127995<=g&&g<=127999?I:g==8205?T:g==9792||g==9794||9877<=g&&g<=9878||g==9992||g==10084||g==127752||g==127806||g==127859||g==127891||g==127908||g==127912||g==127979||g==127981||g==128139||128187<=g&&g<=128188||g==128295||g==128300||g==128488||g==128640||g==128658?N:128102<=g&&g<=128105?U:C}return this}typeof RR<\"u\"&&RR.exports&&(RR.exports=eit)});var Wpe=_((m4t,qpe)=>{var tit=/^(.*?)(\\x1b\\[[^m]+m|\\x1b\\]8;;.*?(\\x1b\\\\|\\u0007))/,TR;function rit(){if(TR)return TR;if(typeof Intl.Segmenter<\"u\"){let t=new Intl.Segmenter(\"en\",{granularity:\"grapheme\"});return TR=e=>Array.from(t.segment(e),({segment:r})=>r)}else{let t=Gpe(),e=new t;return TR=r=>e.splitGraphemes(r)}}qpe.exports=(t,e=0,r=t.length)=>{if(e<0||r<0)throw new RangeError(\"Negative indices aren't supported by this implementation\");let s=r-e,a=\"\",n=0,c=0;for(;t.length>0;){let f=t.match(tit)||[t,t,void 0],p=rit()(f[1]),h=Math.min(e-n,p.length);p=p.slice(h);let E=Math.min(s-c,p.length);a+=p.slice(0,E).join(\"\"),n+=h,c+=E,typeof f[2]<\"u\"&&(a+=f[2]),t=t.slice(f[0].length)}return a}});var fn,yv=Ze(()=>{fn=process.env.YARN_IS_TEST_ENV?\"0.0.0\":\"4.10.3\"});function Zpe(t,{configuration:e,json:r}){if(!e.get(\"enableMessageNames\"))return\"\";let a=Yf(t===null?0:t);return!r&&t===null?Ht(e,a,\"grey\"):a}function jj(t,{configuration:e,json:r}){let s=Zpe(t,{configuration:e,json:r});if(!s||t===null||t===0)return s;let a=Br[t],n=`https://yarnpkg.com/advanced/error-codes#${s}---${a}`.toLowerCase();return KE(e,s,n)}async function SI({configuration:t,stdout:e,forceError:r},s){let a=await Ot.start({configuration:t,stdout:e,includeFooter:!1},async n=>{let c=!1,f=!1;for(let p of s)typeof p.option<\"u\"&&(p.error||r?(f=!0,n.reportError(50,p.message)):(c=!0,n.reportWarning(50,p.message)),p.callback?.());c&&!f&&n.reportSeparator()});return a.hasErrors()?a.exitCode():null}var Kpe,FR,nit,Ype,Vpe,D0,zpe,Jpe,iit,sit,NR,oit,Ot,Ev=Ze(()=>{Kpe=ut(Wpe()),FR=ut(Fd());Gx();Rc();yv();xc();nit=\"\\xB7\",Ype=[\"\\u280B\",\"\\u2819\",\"\\u2839\",\"\\u2838\",\"\\u283C\",\"\\u2834\",\"\\u2826\",\"\\u2827\",\"\\u2807\",\"\\u280F\"],Vpe=80,D0=FR.default.GITHUB_ACTIONS?{start:t=>`::group::${t}\n`,end:t=>`::endgroup::\n`}:FR.default.TRAVIS?{start:t=>`travis_fold:start:${t}\n`,end:t=>`travis_fold:end:${t}\n`}:FR.default.GITLAB?{start:t=>`section_start:${Math.floor(Date.now()/1e3)}:${t.toLowerCase().replace(/\\W+/g,\"_\")}[collapsed=true]\\r\\x1B[0K${t}\n`,end:t=>`section_end:${Math.floor(Date.now()/1e3)}:${t.toLowerCase().replace(/\\W+/g,\"_\")}\\r\\x1B[0K`}:null,zpe=D0!==null,Jpe=new Date,iit=[\"iTerm.app\",\"Apple_Terminal\",\"WarpTerminal\",\"vscode\"].includes(process.env.TERM_PROGRAM)||!!process.env.WT_SESSION,sit=t=>t,NR=sit({patrick:{date:[17,3],chars:[\"\\u{1F340}\",\"\\u{1F331}\"],size:40},simba:{date:[19,7],chars:[\"\\u{1F981}\",\"\\u{1F334}\"],size:40},jack:{date:[31,10],chars:[\"\\u{1F383}\",\"\\u{1F987}\"],size:40},hogsfather:{date:[31,12],chars:[\"\\u{1F389}\",\"\\u{1F384}\"],size:40},default:{chars:[\"=\",\"-\"],size:80}}),oit=iit&&Object.keys(NR).find(t=>{let e=NR[t];return!(e.date&&(e.date[0]!==Jpe.getDate()||e.date[1]!==Jpe.getMonth()+1))})||\"default\";Ot=class extends Ao{constructor({configuration:r,stdout:s,json:a=!1,forceSectionAlignment:n=!1,includeNames:c=!0,includePrefix:f=!0,includeFooter:p=!0,includeLogs:h=!a,includeInfos:E=h,includeWarnings:C=h}){super();this.uncommitted=new Set;this.warningCount=0;this.errorCount=0;this.timerFooter=[];this.startTime=Date.now();this.indent=0;this.level=0;this.progress=new Map;this.progressTime=0;this.progressFrame=0;this.progressTimeout=null;this.progressStyle=null;this.progressMaxScaledSize=null;if(TB(this,{configuration:r}),this.configuration=r,this.forceSectionAlignment=n,this.includeNames=c,this.includePrefix=f,this.includeFooter=p,this.includeInfos=E,this.includeWarnings=C,this.json=a,this.stdout=s,r.get(\"enableProgressBars\")&&!a&&s.isTTY&&s.columns>22){let S=r.get(\"progressBarStyle\")||oit;if(!Object.hasOwn(NR,S))throw new Error(\"Assertion failed: Invalid progress bar style\");this.progressStyle=NR[S];let b=Math.min(this.getRecommendedLength(),80);this.progressMaxScaledSize=Math.floor(this.progressStyle.size*b/80)}}static async start(r,s){let a=new this(r),n=process.emitWarning;process.emitWarning=(c,f)=>{if(typeof c!=\"string\"){let h=c;c=h.message,f=f??h.name}let p=typeof f<\"u\"?`${f}: ${c}`:c;a.reportWarning(0,p)},r.includeVersion&&a.reportInfo(0,zd(r.configuration,`Yarn ${fn}`,2));try{await s(a)}catch(c){a.reportExceptionOnce(c)}finally{await a.finalize(),process.emitWarning=n}return a}hasErrors(){return this.errorCount>0}exitCode(){return this.hasErrors()?1:0}getRecommendedLength(){let s=this.progressStyle!==null?this.stdout.columns-1:super.getRecommendedLength();return Math.max(40,s-12-this.indent*2)}startSectionSync({reportHeader:r,reportFooter:s,skipIfEmpty:a},n){let c={committed:!1,action:()=>{r?.()}};a?this.uncommitted.add(c):(c.action(),c.committed=!0);let f=Date.now();try{return n()}catch(p){throw this.reportExceptionOnce(p),p}finally{let p=Date.now();this.uncommitted.delete(c),c.committed&&s?.(p-f)}}async startSectionPromise({reportHeader:r,reportFooter:s,skipIfEmpty:a},n){let c={committed:!1,action:()=>{r?.()}};a?this.uncommitted.add(c):(c.action(),c.committed=!0);let f=Date.now();try{return await n()}catch(p){throw this.reportExceptionOnce(p),p}finally{let p=Date.now();this.uncommitted.delete(c),c.committed&&s?.(p-f)}}startTimerImpl(r,s,a){return{cb:typeof s==\"function\"?s:a,reportHeader:()=>{this.level+=1,this.reportInfo(null,`\\u250C ${r}`),this.indent+=1,D0!==null&&!this.json&&this.includeInfos&&this.stdout.write(D0.start(r))},reportFooter:f=>{if(this.indent-=1,D0!==null&&!this.json&&this.includeInfos){this.stdout.write(D0.end(r));for(let p of this.timerFooter)p()}this.configuration.get(\"enableTimers\")&&f>200?this.reportInfo(null,`\\u2514 Completed in ${Ht(this.configuration,f,ht.DURATION)}`):this.reportInfo(null,\"\\u2514 Completed\"),this.level-=1},skipIfEmpty:(typeof s==\"function\"?{}:s).skipIfEmpty}}startTimerSync(r,s,a){let{cb:n,...c}=this.startTimerImpl(r,s,a);return this.startSectionSync(c,n)}async startTimerPromise(r,s,a){let{cb:n,...c}=this.startTimerImpl(r,s,a);return this.startSectionPromise(c,n)}reportSeparator(){this.indent===0?this.writeLine(\"\"):this.reportInfo(null,\"\")}reportInfo(r,s){if(!this.includeInfos)return;this.commit();let a=this.formatNameWithHyperlink(r),n=a?`${a}: `:\"\",c=`${this.formatPrefix(n,\"blueBright\")}${s}`;this.json?this.reportJson({type:\"info\",name:r,displayName:this.formatName(r),indent:this.formatIndent(),data:s}):this.writeLine(c)}reportWarning(r,s){if(this.warningCount+=1,!this.includeWarnings)return;this.commit();let a=this.formatNameWithHyperlink(r),n=a?`${a}: `:\"\";this.json?this.reportJson({type:\"warning\",name:r,displayName:this.formatName(r),indent:this.formatIndent(),data:s}):this.writeLine(`${this.formatPrefix(n,\"yellowBright\")}${s}`)}reportError(r,s){this.errorCount+=1,this.timerFooter.push(()=>this.reportErrorImpl(r,s)),this.reportErrorImpl(r,s)}reportErrorImpl(r,s){this.commit();let a=this.formatNameWithHyperlink(r),n=a?`${a}: `:\"\";this.json?this.reportJson({type:\"error\",name:r,displayName:this.formatName(r),indent:this.formatIndent(),data:s}):this.writeLine(`${this.formatPrefix(n,\"redBright\")}${s}`,{truncate:!1})}reportFold(r,s){if(!D0)return;let a=`${D0.start(r)}${s}${D0.end(r)}`;this.timerFooter.push(()=>this.stdout.write(a))}reportProgress(r){if(this.progressStyle===null)return{...Promise.resolve(),stop:()=>{}};if(r.hasProgress&&r.hasTitle)throw new Error(\"Unimplemented: Progress bars can't have both progress and titles.\");let s=!1,a=Promise.resolve().then(async()=>{let c={progress:r.hasProgress?0:void 0,title:r.hasTitle?\"\":void 0};this.progress.set(r,{definition:c,lastScaledSize:r.hasProgress?-1:void 0,lastTitle:void 0}),this.refreshProgress({delta:-1});for await(let{progress:f,title:p}of r)s||c.progress===f&&c.title===p||(c.progress=f,c.title=p,this.refreshProgress());n()}),n=()=>{s||(s=!0,this.progress.delete(r),this.refreshProgress({delta:1}))};return{...a,stop:n}}reportJson(r){this.json&&this.writeLine(`${JSON.stringify(r)}`)}async finalize(){if(!this.includeFooter)return;let r=\"\";this.errorCount>0?r=\"Failed with errors\":this.warningCount>0?r=\"Done with warnings\":r=\"Done\";let s=Ht(this.configuration,Date.now()-this.startTime,ht.DURATION),a=this.configuration.get(\"enableTimers\")?`${r} in ${s}`:r;this.errorCount>0?this.reportError(0,a):this.warningCount>0?this.reportWarning(0,a):this.reportInfo(0,a)}writeLine(r,{truncate:s}={}){this.clearProgress({clear:!0}),this.stdout.write(`${this.truncate(r,{truncate:s})}\n`),this.writeProgress()}writeLines(r,{truncate:s}={}){this.clearProgress({delta:r.length});for(let a of r)this.stdout.write(`${this.truncate(a,{truncate:s})}\n`);this.writeProgress()}commit(){let r=this.uncommitted;this.uncommitted=new Set;for(let s of r)s.committed=!0,s.action()}clearProgress({delta:r=0,clear:s=!1}){this.progressStyle!==null&&this.progress.size+r>0&&(this.stdout.write(`\\x1B[${this.progress.size+r}A`),(r>0||s)&&this.stdout.write(\"\\x1B[0J\"))}writeProgress(){if(this.progressStyle===null||(this.progressTimeout!==null&&clearTimeout(this.progressTimeout),this.progressTimeout=null,this.progress.size===0))return;let r=Date.now();r-this.progressTime>Vpe&&(this.progressFrame=(this.progressFrame+1)%Ype.length,this.progressTime=r);let s=Ype[this.progressFrame];for(let a of this.progress.values()){let n=\"\";if(typeof a.lastScaledSize<\"u\"){let h=this.progressStyle.chars[0].repeat(a.lastScaledSize),E=this.progressStyle.chars[1].repeat(this.progressMaxScaledSize-a.lastScaledSize);n=` ${h}${E}`}let c=this.formatName(null),f=c?`${c}: `:\"\",p=a.definition.title?` ${a.definition.title}`:\"\";this.stdout.write(`${Ht(this.configuration,\"\\u27A4\",\"blueBright\")} ${f}${s}${n}${p}\n`)}this.progressTimeout=setTimeout(()=>{this.refreshProgress({force:!0})},Vpe)}refreshProgress({delta:r=0,force:s=!1}={}){let a=!1,n=!1;if(s||this.progress.size===0)a=!0;else for(let c of this.progress.values()){let f=typeof c.definition.progress<\"u\"?Math.trunc(this.progressMaxScaledSize*c.definition.progress):void 0,p=c.lastScaledSize;c.lastScaledSize=f;let h=c.lastTitle;if(c.lastTitle=c.definition.title,f!==p||(n=h!==c.definition.title)){a=!0;break}}a&&(this.clearProgress({delta:r,clear:n}),this.writeProgress())}truncate(r,{truncate:s}={}){return this.progressStyle===null&&(s=!1),typeof s>\"u\"&&(s=this.configuration.get(\"preferTruncatedLines\")),s&&(r=(0,Kpe.default)(r,0,this.stdout.columns-1)),r}formatName(r){return this.includeNames?Zpe(r,{configuration:this.configuration,json:this.json}):\"\"}formatPrefix(r,s){return this.includePrefix?`${Ht(this.configuration,\"\\u27A4\",s)} ${r}${this.formatIndent()}`:\"\"}formatNameWithHyperlink(r){return this.includeNames?jj(r,{configuration:this.configuration,json:this.json}):\"\"}formatIndent(){return this.level>0||!this.forceSectionAlignment?\"\\u2502 \".repeat(this.indent):`${nit} `}}});var In={};Vt(In,{PackageManager:()=>$pe,detectPackageManager:()=>ehe,executePackageAccessibleBinary:()=>she,executePackageScript:()=>OR,executePackageShellcode:()=>Gj,executeWorkspaceAccessibleBinary:()=>pit,executeWorkspaceLifecycleScript:()=>nhe,executeWorkspaceScript:()=>rhe,getPackageAccessibleBinaries:()=>LR,getWorkspaceAccessibleBinaries:()=>ihe,hasPackageScript:()=>uit,hasWorkspaceScript:()=>qj,isNodeScript:()=>Wj,makeScriptEnv:()=>Iv,maybeExecuteWorkspaceLifecycleScript:()=>Ait,prepareExternalProject:()=>cit});async function P0(t,e,r,s=[]){if(process.platform===\"win32\"){let a=`@goto #_undefined_# 2>NUL || @title %COMSPEC% & @setlocal & @\"${r}\" ${s.map(n=>`\"${n.replace('\"','\"\"')}\"`).join(\" \")} %*`;await ce.writeFilePromise(J.format({dir:t,name:e,ext:\".cmd\"}),a)}await ce.writeFilePromise(J.join(t,e),`#!/bin/sh\nexec \"${r}\" ${s.map(a=>`'${a.replace(/'/g,`'\"'\"'`)}'`).join(\" \")} \"$@\"\n`,{mode:493})}async function ehe(t){let e=await Ut.tryFind(t);if(e?.packageManager){let s=bQ(e.packageManager);if(s?.name){let a=`found ${JSON.stringify({packageManager:e.packageManager})} in manifest`,[n]=s.reference.split(\".\");switch(s.name){case\"yarn\":return{packageManagerField:!0,packageManager:Number(n)===1?\"Yarn Classic\":\"Yarn\",reason:a};case\"npm\":return{packageManagerField:!0,packageManager:\"npm\",reason:a};case\"pnpm\":return{packageManagerField:!0,packageManager:\"pnpm\",reason:a}}}}let r;try{r=await ce.readFilePromise(J.join(t,Er.lockfile),\"utf8\")}catch{}return r!==void 0?r.match(/^__metadata:$/m)?{packageManager:\"Yarn\",reason:'\"__metadata\" key found in yarn.lock'}:{packageManager:\"Yarn Classic\",reason:'\"__metadata\" key not found in yarn.lock, must be a Yarn classic lockfile'}:ce.existsSync(J.join(t,\"package-lock.json\"))?{packageManager:\"npm\",reason:`found npm's \"package-lock.json\" lockfile`}:ce.existsSync(J.join(t,\"pnpm-lock.yaml\"))?{packageManager:\"pnpm\",reason:`found pnpm's \"pnpm-lock.yaml\" lockfile`}:null}async function Iv({project:t,locator:e,binFolder:r,ignoreCorepack:s,lifecycleScript:a,baseEnv:n=t?.configuration.env??process.env}){let c={};for(let[E,C]of Object.entries(n))typeof C<\"u\"&&(c[E.toLowerCase()!==\"path\"?E:\"PATH\"]=C);let f=fe.fromPortablePath(r);c.BERRY_BIN_FOLDER=fe.fromPortablePath(f);let p=process.env.COREPACK_ROOT&&!s?fe.join(process.env.COREPACK_ROOT,\"dist/yarn.js\"):process.argv[1];if(await Promise.all([P0(r,\"node\",process.execPath),...fn!==null?[P0(r,\"run\",process.execPath,[p,\"run\"]),P0(r,\"yarn\",process.execPath,[p]),P0(r,\"yarnpkg\",process.execPath,[p]),P0(r,\"node-gyp\",process.execPath,[p,\"run\",\"--top-level\",\"node-gyp\"])]:[]]),t&&(c.INIT_CWD=fe.fromPortablePath(t.configuration.startingCwd),c.PROJECT_CWD=fe.fromPortablePath(t.cwd)),c.PATH=c.PATH?`${f}${fe.delimiter}${c.PATH}`:`${f}`,c.npm_execpath=`${f}${fe.sep}yarn`,c.npm_node_execpath=`${f}${fe.sep}node`,e){if(!t)throw new Error(\"Assertion failed: Missing project\");let E=t.tryWorkspaceByLocator(e),C=E?E.manifest.version??\"\":t.storedPackages.get(e.locatorHash).version??\"\";c.npm_package_name=un(e),c.npm_package_version=C;let S;if(E)S=E.cwd;else{let b=t.storedPackages.get(e.locatorHash);if(!b)throw new Error(`Package for ${Yr(t.configuration,e)} not found in the project`);let I=t.configuration.getLinkers(),T={project:t,report:new Ot({stdout:new b0.PassThrough,configuration:t.configuration})},N=I.find(U=>U.supportsPackage(b,T));if(!N)throw new Error(`The package ${Yr(t.configuration,b)} isn't supported by any of the available linkers`);S=await N.findPackageLocation(b,T)}c.npm_package_json=fe.fromPortablePath(J.join(S,Er.manifest))}let h=fn!==null?`yarn/${fn}`:`yarn/${bp(\"@yarnpkg/core\").version}-core`;return c.npm_config_user_agent=`${h} npm/? node/${process.version} ${process.platform} ${process.arch}`,a&&(c.npm_lifecycle_event=a),t&&await t.configuration.triggerHook(E=>E.setupScriptEnvironment,t,c,async(E,C,S)=>await P0(r,E,C,S)),c}async function cit(t,e,{configuration:r,report:s,workspace:a=null,locator:n=null}){await lit(async()=>{await ce.mktempPromise(async c=>{let f=J.join(c,\"pack.log\"),p=null,{stdout:h,stderr:E}=r.getSubprocessStreams(f,{prefix:fe.fromPortablePath(t),report:s}),C=n&&Gu(n)?rI(n):n,S=C?ll(C):\"an external project\";h.write(`Packing ${S} from sources\n`);let b=await ehe(t),I;b!==null?(h.write(`Using ${b.packageManager} for bootstrap. Reason: ${b.reason}\n\n`),I=b.packageManager):(h.write(`No package manager configuration detected; defaulting to Yarn\n\n`),I=\"Yarn\");let T=I===\"Yarn\"&&!b?.packageManagerField;await ce.mktempPromise(async N=>{let U=await Iv({binFolder:N,ignoreCorepack:T,baseEnv:{...process.env,COREPACK_ENABLE_AUTO_PIN:\"0\"}}),ee=new Map([[\"Yarn Classic\",async()=>{let ue=a!==null?[\"workspace\",a]:[],le=J.join(t,Er.manifest),me=await ce.readFilePromise(le),pe=await Wu(process.execPath,[process.argv[1],\"set\",\"version\",\"classic\",\"--only-if-needed\",\"--yarn-path\"],{cwd:t,env:U,stdin:p,stdout:h,stderr:E,end:1});if(pe.code!==0)return pe.code;await ce.writeFilePromise(le,me),await ce.appendFilePromise(J.join(t,\".npmignore\"),`/.yarn\n`),h.write(`\n`),delete U.NODE_ENV;let Be=await Wu(\"yarn\",[\"install\"],{cwd:t,env:U,stdin:p,stdout:h,stderr:E,end:1});if(Be.code!==0)return Be.code;h.write(`\n`);let Ce=await Wu(\"yarn\",[...ue,\"pack\",\"--filename\",fe.fromPortablePath(e)],{cwd:t,env:U,stdin:p,stdout:h,stderr:E});return Ce.code!==0?Ce.code:0}],[\"Yarn\",async()=>{let ue=a!==null?[\"workspace\",a]:[];U.YARN_ENABLE_INLINE_BUILDS=\"1\";let le=J.join(t,Er.lockfile);await ce.existsPromise(le)||await ce.writeFilePromise(le,\"\");let me=await Wu(\"yarn\",[...ue,\"pack\",\"--install-if-needed\",\"--filename\",fe.fromPortablePath(e)],{cwd:t,env:U,stdin:p,stdout:h,stderr:E});return me.code!==0?me.code:0}],[\"npm\",async()=>{if(a!==null){let we=new b0.PassThrough,ye=WE(we);we.pipe(h,{end:!1});let Ae=await Wu(\"npm\",[\"--version\"],{cwd:t,env:U,stdin:p,stdout:we,stderr:E,end:0});if(we.end(),Ae.code!==0)return h.end(),E.end(),Ae.code;let se=(await ye).toString().trim();if(!Xf(se,\">=7.x\")){let X=Da(null,\"npm\"),De=On(X,se),Te=On(X,\">=7.x\");throw new Error(`Workspaces aren't supported by ${ni(r,De)}; please upgrade to ${ni(r,Te)} (npm has been detected as the primary package manager for ${Ht(r,t,ht.PATH)})`)}}let ue=a!==null?[\"--workspace\",a]:[];delete U.npm_config_user_agent,delete U.npm_config_production,delete U.NPM_CONFIG_PRODUCTION,delete U.NODE_ENV;let le=await Wu(\"npm\",[\"install\",\"--legacy-peer-deps\"],{cwd:t,env:U,stdin:p,stdout:h,stderr:E,end:1});if(le.code!==0)return le.code;let me=new b0.PassThrough,pe=WE(me);me.pipe(h);let Be=await Wu(\"npm\",[\"pack\",\"--silent\",...ue],{cwd:t,env:U,stdin:p,stdout:me,stderr:E});if(Be.code!==0)return Be.code;let Ce=(await pe).toString().trim().replace(/^.*\\n/s,\"\"),g=J.resolve(t,fe.toPortablePath(Ce));return await ce.renamePromise(g,e),0}]]).get(I);if(typeof ee>\"u\")throw new Error(\"Assertion failed: Unsupported workflow\");let ie=await ee();if(!(ie===0||typeof ie>\"u\"))throw ce.detachTemp(c),new jt(58,`Packing the package failed (exit code ${ie}, logs can be found here: ${Ht(r,f,ht.PATH)})`)})})})}async function uit(t,e,{project:r}){let s=r.tryWorkspaceByLocator(t);if(s!==null)return qj(s,e);let a=r.storedPackages.get(t.locatorHash);if(!a)throw new Error(`Package for ${Yr(r.configuration,t)} not found in the project`);return await $f.openPromise(async n=>{let c=r.configuration,f=r.configuration.getLinkers(),p={project:r,report:new Ot({stdout:new b0.PassThrough,configuration:c})},h=f.find(b=>b.supportsPackage(a,p));if(!h)throw new Error(`The package ${Yr(r.configuration,a)} isn't supported by any of the available linkers`);let E=await h.findPackageLocation(a,p),C=new Sn(E,{baseFs:n});return(await Ut.find(vt.dot,{baseFs:C})).scripts.has(e)})}async function OR(t,e,r,{cwd:s,project:a,stdin:n,stdout:c,stderr:f}){return await ce.mktempPromise(async p=>{let{manifest:h,env:E,cwd:C}=await the(t,{project:a,binFolder:p,cwd:s,lifecycleScript:e}),S=h.scripts.get(e);if(typeof S>\"u\")return 1;let b=async()=>await vI(S,r,{cwd:C,env:E,stdin:n,stdout:c,stderr:f});return await(await a.configuration.reduceHook(T=>T.wrapScriptExecution,b,a,t,e,{script:S,args:r,cwd:C,env:E,stdin:n,stdout:c,stderr:f}))()})}async function Gj(t,e,r,{cwd:s,project:a,stdin:n,stdout:c,stderr:f}){return await ce.mktempPromise(async p=>{let{env:h,cwd:E}=await the(t,{project:a,binFolder:p,cwd:s});return await vI(e,r,{cwd:E,env:h,stdin:n,stdout:c,stderr:f})})}async function fit(t,{binFolder:e,cwd:r,lifecycleScript:s}){let a=await Iv({project:t.project,locator:t.anchoredLocator,binFolder:e,lifecycleScript:s});return await Yj(e,await ihe(t)),typeof r>\"u\"&&(r=J.dirname(await ce.realpathPromise(J.join(t.cwd,\"package.json\")))),{manifest:t.manifest,binFolder:e,env:a,cwd:r}}async function the(t,{project:e,binFolder:r,cwd:s,lifecycleScript:a}){let n=e.tryWorkspaceByLocator(t);if(n!==null)return fit(n,{binFolder:r,cwd:s,lifecycleScript:a});let c=e.storedPackages.get(t.locatorHash);if(!c)throw new Error(`Package for ${Yr(e.configuration,t)} not found in the project`);return await $f.openPromise(async f=>{let p=e.configuration,h=e.configuration.getLinkers(),E={project:e,report:new Ot({stdout:new b0.PassThrough,configuration:p})},C=h.find(N=>N.supportsPackage(c,E));if(!C)throw new Error(`The package ${Yr(e.configuration,c)} isn't supported by any of the available linkers`);let S=await Iv({project:e,locator:t,binFolder:r,lifecycleScript:a});await Yj(r,await LR(t,{project:e}));let b=await C.findPackageLocation(c,E),I=new Sn(b,{baseFs:f}),T=await Ut.find(vt.dot,{baseFs:I});return typeof s>\"u\"&&(s=b),{manifest:T,binFolder:r,env:S,cwd:s}})}async function rhe(t,e,r,{cwd:s,stdin:a,stdout:n,stderr:c}){return await OR(t.anchoredLocator,e,r,{cwd:s,project:t.project,stdin:a,stdout:n,stderr:c})}function qj(t,e){return t.manifest.scripts.has(e)}async function nhe(t,e,{cwd:r,report:s}){let{configuration:a}=t.project,n=null;await ce.mktempPromise(async c=>{let f=J.join(c,`${e}.log`),p=`# This file contains the result of Yarn calling the \"${e}\" lifecycle script inside a workspace (\"${fe.fromPortablePath(t.cwd)}\")\n`,{stdout:h,stderr:E}=a.getSubprocessStreams(f,{report:s,prefix:Yr(a,t.anchoredLocator),header:p});s.reportInfo(36,`Calling the \"${e}\" lifecycle script`);let C=await rhe(t,e,[],{cwd:r,stdin:n,stdout:h,stderr:E});if(h.end(),E.end(),C!==0)throw ce.detachTemp(c),new jt(36,`${PB(e)} script failed (exit code ${Ht(a,C,ht.NUMBER)}, logs can be found here: ${Ht(a,f,ht.PATH)}); run ${Ht(a,`yarn ${e}`,ht.CODE)} to investigate`)})}async function Ait(t,e,r){qj(t,e)&&await nhe(t,e,r)}function Wj(t){let e=J.extname(t);if(e.match(/\\.[cm]?[jt]sx?$/))return!0;if(e===\".exe\"||e===\".bin\")return!1;let r=Buffer.alloc(4),s;try{s=ce.openSync(t,\"r\")}catch{return!0}try{ce.readSync(s,r,0,r.length,0)}finally{ce.closeSync(s)}let a=r.readUint32BE();return!(a===3405691582||a===3489328638||a===2135247942||(a&4294901760)===1297743872)}async function LR(t,{project:e}){let r=e.configuration,s=new Map,a=e.storedPackages.get(t.locatorHash);if(!a)throw new Error(`Package for ${Yr(r,t)} not found in the project`);let n=new b0.Writable,c=r.getLinkers(),f={project:e,report:new Ot({configuration:r,stdout:n})},p=new Set([t.locatorHash]);for(let E of a.dependencies.values()){let C=e.storedResolutions.get(E.descriptorHash);if(!C)throw new Error(`Assertion failed: The resolution (${ni(r,E)}) should have been registered`);p.add(C)}let h=await Promise.all(Array.from(p,async E=>{let C=e.storedPackages.get(E);if(!C)throw new Error(`Assertion failed: The package (${E}) should have been registered`);if(C.bin.size===0)return Wl.skip;let S=c.find(I=>I.supportsPackage(C,f));if(!S)return Wl.skip;let b=null;try{b=await S.findPackageLocation(C,f)}catch(I){if(I.code===\"LOCATOR_NOT_INSTALLED\")return Wl.skip;throw I}return{dependency:C,packageLocation:b}}));for(let E of h){if(E===Wl.skip)continue;let{dependency:C,packageLocation:S}=E;for(let[b,I]of C.bin){let T=J.resolve(S,I);s.set(b,[C,fe.fromPortablePath(T),Wj(T)])}}return s}async function ihe(t){return await LR(t.anchoredLocator,{project:t.project})}async function Yj(t,e){await Promise.all(Array.from(e,([r,[,s,a]])=>a?P0(t,r,process.execPath,[s]):P0(t,r,s,[])))}async function she(t,e,r,{cwd:s,project:a,stdin:n,stdout:c,stderr:f,nodeArgs:p=[],packageAccessibleBinaries:h}){h??=await LR(t,{project:a});let E=h.get(e);if(!E)throw new Error(`Binary not found (${e}) for ${Yr(a.configuration,t)}`);return await ce.mktempPromise(async C=>{let[,S]=E,b=await Iv({project:a,locator:t,binFolder:C});await Yj(b.BERRY_BIN_FOLDER,h);let I=Wj(fe.toPortablePath(S))?Wu(process.execPath,[...p,S,...r],{cwd:s,env:b,stdin:n,stdout:c,stderr:f}):Wu(S,r,{cwd:s,env:b,stdin:n,stdout:c,stderr:f}),T;try{T=await I}finally{await ce.removePromise(b.BERRY_BIN_FOLDER)}return T.code})}async function pit(t,e,r,{cwd:s,stdin:a,stdout:n,stderr:c,packageAccessibleBinaries:f}){return await she(t.anchoredLocator,e,r,{project:t.project,cwd:s,stdin:a,stdout:n,stderr:c,packageAccessibleBinaries:f})}var Xpe,b0,$pe,ait,lit,Vj=Ze(()=>{Dt();Dt();eA();pv();ql();Xpe=ut(Ld()),b0=Ie(\"stream\");oI();Rc();Ev();yv();gR();xc();bc();Tp();Wo();$pe=(a=>(a.Yarn1=\"Yarn Classic\",a.Yarn2=\"Yarn\",a.Npm=\"npm\",a.Pnpm=\"pnpm\",a))($pe||{});ait=2,lit=(0,Xpe.default)(ait)});var DI=_((U4t,ahe)=>{\"use strict\";var ohe=new Map([[\"C\",\"cwd\"],[\"f\",\"file\"],[\"z\",\"gzip\"],[\"P\",\"preservePaths\"],[\"U\",\"unlink\"],[\"strip-components\",\"strip\"],[\"stripComponents\",\"strip\"],[\"keep-newer\",\"newer\"],[\"keepNewer\",\"newer\"],[\"keep-newer-files\",\"newer\"],[\"keepNewerFiles\",\"newer\"],[\"k\",\"keep\"],[\"keep-existing\",\"keep\"],[\"keepExisting\",\"keep\"],[\"m\",\"noMtime\"],[\"no-mtime\",\"noMtime\"],[\"p\",\"preserveOwner\"],[\"L\",\"follow\"],[\"h\",\"follow\"]]);ahe.exports=t=>t?Object.keys(t).map(e=>[ohe.has(e)?ohe.get(e):e,t[e]]).reduce((e,r)=>(e[r[0]]=r[1],e),Object.create(null)):{}});var bI=_((_4t,dhe)=>{\"use strict\";var lhe=typeof process==\"object\"&&process?process:{stdout:null,stderr:null},hit=Ie(\"events\"),che=Ie(\"stream\"),uhe=Ie(\"string_decoder\").StringDecoder,_p=Symbol(\"EOF\"),Hp=Symbol(\"maybeEmitEnd\"),x0=Symbol(\"emittedEnd\"),MR=Symbol(\"emittingEnd\"),Cv=Symbol(\"emittedError\"),UR=Symbol(\"closed\"),fhe=Symbol(\"read\"),_R=Symbol(\"flush\"),Ahe=Symbol(\"flushChunk\"),ul=Symbol(\"encoding\"),jp=Symbol(\"decoder\"),HR=Symbol(\"flowing\"),wv=Symbol(\"paused\"),PI=Symbol(\"resume\"),Ys=Symbol(\"bufferLength\"),Jj=Symbol(\"bufferPush\"),Kj=Symbol(\"bufferShift\"),Ko=Symbol(\"objectMode\"),zo=Symbol(\"destroyed\"),zj=Symbol(\"emitData\"),phe=Symbol(\"emitEnd\"),Zj=Symbol(\"emitEnd2\"),Gp=Symbol(\"async\"),Bv=t=>Promise.resolve().then(t),hhe=global._MP_NO_ITERATOR_SYMBOLS_!==\"1\",git=hhe&&Symbol.asyncIterator||Symbol(\"asyncIterator not implemented\"),dit=hhe&&Symbol.iterator||Symbol(\"iterator not implemented\"),mit=t=>t===\"end\"||t===\"finish\"||t===\"prefinish\",yit=t=>t instanceof ArrayBuffer||typeof t==\"object\"&&t.constructor&&t.constructor.name===\"ArrayBuffer\"&&t.byteLength>=0,Eit=t=>!Buffer.isBuffer(t)&&ArrayBuffer.isView(t),jR=class{constructor(e,r,s){this.src=e,this.dest=r,this.opts=s,this.ondrain=()=>e[PI](),r.on(\"drain\",this.ondrain)}unpipe(){this.dest.removeListener(\"drain\",this.ondrain)}proxyErrors(){}end(){this.unpipe(),this.opts.end&&this.dest.end()}},Xj=class extends jR{unpipe(){this.src.removeListener(\"error\",this.proxyErrors),super.unpipe()}constructor(e,r,s){super(e,r,s),this.proxyErrors=a=>r.emit(\"error\",a),e.on(\"error\",this.proxyErrors)}};dhe.exports=class ghe extends che{constructor(e){super(),this[HR]=!1,this[wv]=!1,this.pipes=[],this.buffer=[],this[Ko]=e&&e.objectMode||!1,this[Ko]?this[ul]=null:this[ul]=e&&e.encoding||null,this[ul]===\"buffer\"&&(this[ul]=null),this[Gp]=e&&!!e.async||!1,this[jp]=this[ul]?new uhe(this[ul]):null,this[_p]=!1,this[x0]=!1,this[MR]=!1,this[UR]=!1,this[Cv]=null,this.writable=!0,this.readable=!0,this[Ys]=0,this[zo]=!1}get bufferLength(){return this[Ys]}get encoding(){return this[ul]}set encoding(e){if(this[Ko])throw new Error(\"cannot set encoding in objectMode\");if(this[ul]&&e!==this[ul]&&(this[jp]&&this[jp].lastNeed||this[Ys]))throw new Error(\"cannot change encoding\");this[ul]!==e&&(this[jp]=e?new uhe(e):null,this.buffer.length&&(this.buffer=this.buffer.map(r=>this[jp].write(r)))),this[ul]=e}setEncoding(e){this.encoding=e}get objectMode(){return this[Ko]}set objectMode(e){this[Ko]=this[Ko]||!!e}get async(){return this[Gp]}set async(e){this[Gp]=this[Gp]||!!e}write(e,r,s){if(this[_p])throw new Error(\"write after end\");if(this[zo])return this.emit(\"error\",Object.assign(new Error(\"Cannot call write after a stream was destroyed\"),{code:\"ERR_STREAM_DESTROYED\"})),!0;typeof r==\"function\"&&(s=r,r=\"utf8\"),r||(r=\"utf8\");let a=this[Gp]?Bv:n=>n();return!this[Ko]&&!Buffer.isBuffer(e)&&(Eit(e)?e=Buffer.from(e.buffer,e.byteOffset,e.byteLength):yit(e)?e=Buffer.from(e):typeof e!=\"string\"&&(this.objectMode=!0)),this[Ko]?(this.flowing&&this[Ys]!==0&&this[_R](!0),this.flowing?this.emit(\"data\",e):this[Jj](e),this[Ys]!==0&&this.emit(\"readable\"),s&&a(s),this.flowing):e.length?(typeof e==\"string\"&&!(r===this[ul]&&!this[jp].lastNeed)&&(e=Buffer.from(e,r)),Buffer.isBuffer(e)&&this[ul]&&(e=this[jp].write(e)),this.flowing&&this[Ys]!==0&&this[_R](!0),this.flowing?this.emit(\"data\",e):this[Jj](e),this[Ys]!==0&&this.emit(\"readable\"),s&&a(s),this.flowing):(this[Ys]!==0&&this.emit(\"readable\"),s&&a(s),this.flowing)}read(e){if(this[zo])return null;if(this[Ys]===0||e===0||e>this[Ys])return this[Hp](),null;this[Ko]&&(e=null),this.buffer.length>1&&!this[Ko]&&(this.encoding?this.buffer=[this.buffer.join(\"\")]:this.buffer=[Buffer.concat(this.buffer,this[Ys])]);let r=this[fhe](e||null,this.buffer[0]);return this[Hp](),r}[fhe](e,r){return e===r.length||e===null?this[Kj]():(this.buffer[0]=r.slice(e),r=r.slice(0,e),this[Ys]-=e),this.emit(\"data\",r),!this.buffer.length&&!this[_p]&&this.emit(\"drain\"),r}end(e,r,s){return typeof e==\"function\"&&(s=e,e=null),typeof r==\"function\"&&(s=r,r=\"utf8\"),e&&this.write(e,r),s&&this.once(\"end\",s),this[_p]=!0,this.writable=!1,(this.flowing||!this[wv])&&this[Hp](),this}[PI](){this[zo]||(this[wv]=!1,this[HR]=!0,this.emit(\"resume\"),this.buffer.length?this[_R]():this[_p]?this[Hp]():this.emit(\"drain\"))}resume(){return this[PI]()}pause(){this[HR]=!1,this[wv]=!0}get destroyed(){return this[zo]}get flowing(){return this[HR]}get paused(){return this[wv]}[Jj](e){this[Ko]?this[Ys]+=1:this[Ys]+=e.length,this.buffer.push(e)}[Kj](){return this.buffer.length&&(this[Ko]?this[Ys]-=1:this[Ys]-=this.buffer[0].length),this.buffer.shift()}[_R](e){do;while(this[Ahe](this[Kj]()));!e&&!this.buffer.length&&!this[_p]&&this.emit(\"drain\")}[Ahe](e){return e?(this.emit(\"data\",e),this.flowing):!1}pipe(e,r){if(this[zo])return;let s=this[x0];return r=r||{},e===lhe.stdout||e===lhe.stderr?r.end=!1:r.end=r.end!==!1,r.proxyErrors=!!r.proxyErrors,s?r.end&&e.end():(this.pipes.push(r.proxyErrors?new Xj(this,e,r):new jR(this,e,r)),this[Gp]?Bv(()=>this[PI]()):this[PI]()),e}unpipe(e){let r=this.pipes.find(s=>s.dest===e);r&&(this.pipes.splice(this.pipes.indexOf(r),1),r.unpipe())}addListener(e,r){return this.on(e,r)}on(e,r){let s=super.on(e,r);return e===\"data\"&&!this.pipes.length&&!this.flowing?this[PI]():e===\"readable\"&&this[Ys]!==0?super.emit(\"readable\"):mit(e)&&this[x0]?(super.emit(e),this.removeAllListeners(e)):e===\"error\"&&this[Cv]&&(this[Gp]?Bv(()=>r.call(this,this[Cv])):r.call(this,this[Cv])),s}get emittedEnd(){return this[x0]}[Hp](){!this[MR]&&!this[x0]&&!this[zo]&&this.buffer.length===0&&this[_p]&&(this[MR]=!0,this.emit(\"end\"),this.emit(\"prefinish\"),this.emit(\"finish\"),this[UR]&&this.emit(\"close\"),this[MR]=!1)}emit(e,r,...s){if(e!==\"error\"&&e!==\"close\"&&e!==zo&&this[zo])return;if(e===\"data\")return r?this[Gp]?Bv(()=>this[zj](r)):this[zj](r):!1;if(e===\"end\")return this[phe]();if(e===\"close\"){if(this[UR]=!0,!this[x0]&&!this[zo])return;let n=super.emit(\"close\");return this.removeAllListeners(\"close\"),n}else if(e===\"error\"){this[Cv]=r;let n=super.emit(\"error\",r);return this[Hp](),n}else if(e===\"resume\"){let n=super.emit(\"resume\");return this[Hp](),n}else if(e===\"finish\"||e===\"prefinish\"){let n=super.emit(e);return this.removeAllListeners(e),n}let a=super.emit(e,r,...s);return this[Hp](),a}[zj](e){for(let s of this.pipes)s.dest.write(e)===!1&&this.pause();let r=super.emit(\"data\",e);return this[Hp](),r}[phe](){this[x0]||(this[x0]=!0,this.readable=!1,this[Gp]?Bv(()=>this[Zj]()):this[Zj]())}[Zj](){if(this[jp]){let r=this[jp].end();if(r){for(let s of this.pipes)s.dest.write(r);super.emit(\"data\",r)}}for(let r of this.pipes)r.end();let e=super.emit(\"end\");return this.removeAllListeners(\"end\"),e}collect(){let e=[];this[Ko]||(e.dataLength=0);let r=this.promise();return this.on(\"data\",s=>{e.push(s),this[Ko]||(e.dataLength+=s.length)}),r.then(()=>e)}concat(){return this[Ko]?Promise.reject(new Error(\"cannot concat in objectMode\")):this.collect().then(e=>this[Ko]?Promise.reject(new Error(\"cannot concat in objectMode\")):this[ul]?e.join(\"\"):Buffer.concat(e,e.dataLength))}promise(){return new Promise((e,r)=>{this.on(zo,()=>r(new Error(\"stream destroyed\"))),this.on(\"error\",s=>r(s)),this.on(\"end\",()=>e())})}[git](){return{next:()=>{let r=this.read();if(r!==null)return Promise.resolve({done:!1,value:r});if(this[_p])return Promise.resolve({done:!0});let s=null,a=null,n=h=>{this.removeListener(\"data\",c),this.removeListener(\"end\",f),a(h)},c=h=>{this.removeListener(\"error\",n),this.removeListener(\"end\",f),this.pause(),s({value:h,done:!!this[_p]})},f=()=>{this.removeListener(\"error\",n),this.removeListener(\"data\",c),s({done:!0})},p=()=>n(new Error(\"stream destroyed\"));return new Promise((h,E)=>{a=E,s=h,this.once(zo,p),this.once(\"error\",n),this.once(\"end\",f),this.once(\"data\",c)})}}}[dit](){return{next:()=>{let r=this.read();return{value:r,done:r===null}}}}destroy(e){return this[zo]?(e?this.emit(\"error\",e):this.emit(zo),this):(this[zo]=!0,this.buffer.length=0,this[Ys]=0,typeof this.close==\"function\"&&!this[UR]&&this.close(),e?this.emit(\"error\",e):this.emit(zo),this)}static isStream(e){return!!e&&(e instanceof ghe||e instanceof che||e instanceof hit&&(typeof e.pipe==\"function\"||typeof e.write==\"function\"&&typeof e.end==\"function\"))}}});var yhe=_((H4t,mhe)=>{var Iit=Ie(\"zlib\").constants||{ZLIB_VERNUM:4736};mhe.exports=Object.freeze(Object.assign(Object.create(null),{Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_MEM_ERROR:-4,Z_BUF_ERROR:-5,Z_VERSION_ERROR:-6,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,DEFLATE:1,INFLATE:2,GZIP:3,GUNZIP:4,DEFLATERAW:5,INFLATERAW:6,UNZIP:7,BROTLI_DECODE:8,BROTLI_ENCODE:9,Z_MIN_WINDOWBITS:8,Z_MAX_WINDOWBITS:15,Z_DEFAULT_WINDOWBITS:15,Z_MIN_CHUNK:64,Z_MAX_CHUNK:1/0,Z_DEFAULT_CHUNK:16384,Z_MIN_MEMLEVEL:1,Z_MAX_MEMLEVEL:9,Z_DEFAULT_MEMLEVEL:8,Z_MIN_LEVEL:-1,Z_MAX_LEVEL:9,Z_DEFAULT_LEVEL:-1,BROTLI_OPERATION_PROCESS:0,BROTLI_OPERATION_FLUSH:1,BROTLI_OPERATION_FINISH:2,BROTLI_OPERATION_EMIT_METADATA:3,BROTLI_MODE_GENERIC:0,BROTLI_MODE_TEXT:1,BROTLI_MODE_FONT:2,BROTLI_DEFAULT_MODE:0,BROTLI_MIN_QUALITY:0,BROTLI_MAX_QUALITY:11,BROTLI_DEFAULT_QUALITY:11,BROTLI_MIN_WINDOW_BITS:10,BROTLI_MAX_WINDOW_BITS:24,BROTLI_LARGE_MAX_WINDOW_BITS:30,BROTLI_DEFAULT_WINDOW:22,BROTLI_MIN_INPUT_BLOCK_BITS:16,BROTLI_MAX_INPUT_BLOCK_BITS:24,BROTLI_PARAM_MODE:0,BROTLI_PARAM_QUALITY:1,BROTLI_PARAM_LGWIN:2,BROTLI_PARAM_LGBLOCK:3,BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING:4,BROTLI_PARAM_SIZE_HINT:5,BROTLI_PARAM_LARGE_WINDOW:6,BROTLI_PARAM_NPOSTFIX:7,BROTLI_PARAM_NDIRECT:8,BROTLI_DECODER_RESULT_ERROR:0,BROTLI_DECODER_RESULT_SUCCESS:1,BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:2,BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:3,BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION:0,BROTLI_DECODER_PARAM_LARGE_WINDOW:1,BROTLI_DECODER_NO_ERROR:0,BROTLI_DECODER_SUCCESS:1,BROTLI_DECODER_NEEDS_MORE_INPUT:2,BROTLI_DECODER_NEEDS_MORE_OUTPUT:3,BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE:-1,BROTLI_DECODER_ERROR_FORMAT_RESERVED:-2,BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE:-3,BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET:-4,BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME:-5,BROTLI_DECODER_ERROR_FORMAT_CL_SPACE:-6,BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE:-7,BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT:-8,BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1:-9,BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2:-10,BROTLI_DECODER_ERROR_FORMAT_TRANSFORM:-11,BROTLI_DECODER_ERROR_FORMAT_DICTIONARY:-12,BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS:-13,BROTLI_DECODER_ERROR_FORMAT_PADDING_1:-14,BROTLI_DECODER_ERROR_FORMAT_PADDING_2:-15,BROTLI_DECODER_ERROR_FORMAT_DISTANCE:-16,BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET:-19,BROTLI_DECODER_ERROR_INVALID_ARGUMENTS:-20,BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES:-21,BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS:-22,BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP:-25,BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1:-26,BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2:-27,BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES:-30,BROTLI_DECODER_ERROR_UNREACHABLE:-31},Iit))});var h6=_(Kl=>{\"use strict\";var n6=Ie(\"assert\"),k0=Ie(\"buffer\").Buffer,Che=Ie(\"zlib\"),fm=Kl.constants=yhe(),Cit=bI(),Ehe=k0.concat,Am=Symbol(\"_superWrite\"),kI=class extends Error{constructor(e){super(\"zlib: \"+e.message),this.code=e.code,this.errno=e.errno,this.code||(this.code=\"ZLIB_ERROR\"),this.message=\"zlib: \"+e.message,Error.captureStackTrace(this,this.constructor)}get name(){return\"ZlibError\"}},wit=Symbol(\"opts\"),vv=Symbol(\"flushFlag\"),Ihe=Symbol(\"finishFlushFlag\"),p6=Symbol(\"fullFlushFlag\"),Ii=Symbol(\"handle\"),GR=Symbol(\"onError\"),xI=Symbol(\"sawError\"),$j=Symbol(\"level\"),e6=Symbol(\"strategy\"),t6=Symbol(\"ended\"),j4t=Symbol(\"_defaultFullFlush\"),qR=class extends Cit{constructor(e,r){if(!e||typeof e!=\"object\")throw new TypeError(\"invalid options for ZlibBase constructor\");super(e),this[xI]=!1,this[t6]=!1,this[wit]=e,this[vv]=e.flush,this[Ihe]=e.finishFlush;try{this[Ii]=new Che[r](e)}catch(s){throw new kI(s)}this[GR]=s=>{this[xI]||(this[xI]=!0,this.close(),this.emit(\"error\",s))},this[Ii].on(\"error\",s=>this[GR](new kI(s))),this.once(\"end\",()=>this.close)}close(){this[Ii]&&(this[Ii].close(),this[Ii]=null,this.emit(\"close\"))}reset(){if(!this[xI])return n6(this[Ii],\"zlib binding closed\"),this[Ii].reset()}flush(e){this.ended||(typeof e!=\"number\"&&(e=this[p6]),this.write(Object.assign(k0.alloc(0),{[vv]:e})))}end(e,r,s){return e&&this.write(e,r),this.flush(this[Ihe]),this[t6]=!0,super.end(null,null,s)}get ended(){return this[t6]}write(e,r,s){if(typeof r==\"function\"&&(s=r,r=\"utf8\"),typeof e==\"string\"&&(e=k0.from(e,r)),this[xI])return;n6(this[Ii],\"zlib binding closed\");let a=this[Ii]._handle,n=a.close;a.close=()=>{};let c=this[Ii].close;this[Ii].close=()=>{},k0.concat=h=>h;let f;try{let h=typeof e[vv]==\"number\"?e[vv]:this[vv];f=this[Ii]._processChunk(e,h),k0.concat=Ehe}catch(h){k0.concat=Ehe,this[GR](new kI(h))}finally{this[Ii]&&(this[Ii]._handle=a,a.close=n,this[Ii].close=c,this[Ii].removeAllListeners(\"error\"))}this[Ii]&&this[Ii].on(\"error\",h=>this[GR](new kI(h)));let p;if(f)if(Array.isArray(f)&&f.length>0){p=this[Am](k0.from(f[0]));for(let h=1;h<f.length;h++)p=this[Am](f[h])}else p=this[Am](k0.from(f));return s&&s(),p}[Am](e){return super.write(e)}},qp=class extends qR{constructor(e,r){e=e||{},e.flush=e.flush||fm.Z_NO_FLUSH,e.finishFlush=e.finishFlush||fm.Z_FINISH,super(e,r),this[p6]=fm.Z_FULL_FLUSH,this[$j]=e.level,this[e6]=e.strategy}params(e,r){if(!this[xI]){if(!this[Ii])throw new Error(\"cannot switch params when binding is closed\");if(!this[Ii].params)throw new Error(\"not supported in this implementation\");if(this[$j]!==e||this[e6]!==r){this.flush(fm.Z_SYNC_FLUSH),n6(this[Ii],\"zlib binding closed\");let s=this[Ii].flush;this[Ii].flush=(a,n)=>{this.flush(a),n()};try{this[Ii].params(e,r)}finally{this[Ii].flush=s}this[Ii]&&(this[$j]=e,this[e6]=r)}}}},i6=class extends qp{constructor(e){super(e,\"Deflate\")}},s6=class extends qp{constructor(e){super(e,\"Inflate\")}},r6=Symbol(\"_portable\"),o6=class extends qp{constructor(e){super(e,\"Gzip\"),this[r6]=e&&!!e.portable}[Am](e){return this[r6]?(this[r6]=!1,e[9]=255,super[Am](e)):super[Am](e)}},a6=class extends qp{constructor(e){super(e,\"Gunzip\")}},l6=class extends qp{constructor(e){super(e,\"DeflateRaw\")}},c6=class extends qp{constructor(e){super(e,\"InflateRaw\")}},u6=class extends qp{constructor(e){super(e,\"Unzip\")}},WR=class extends qR{constructor(e,r){e=e||{},e.flush=e.flush||fm.BROTLI_OPERATION_PROCESS,e.finishFlush=e.finishFlush||fm.BROTLI_OPERATION_FINISH,super(e,r),this[p6]=fm.BROTLI_OPERATION_FLUSH}},f6=class extends WR{constructor(e){super(e,\"BrotliCompress\")}},A6=class extends WR{constructor(e){super(e,\"BrotliDecompress\")}};Kl.Deflate=i6;Kl.Inflate=s6;Kl.Gzip=o6;Kl.Gunzip=a6;Kl.DeflateRaw=l6;Kl.InflateRaw=c6;Kl.Unzip=u6;typeof Che.BrotliCompress==\"function\"?(Kl.BrotliCompress=f6,Kl.BrotliDecompress=A6):Kl.BrotliCompress=Kl.BrotliDecompress=class{constructor(){throw new Error(\"Brotli is not supported in this version of Node.js\")}}});var QI=_((W4t,whe)=>{var Bit=process.env.TESTING_TAR_FAKE_PLATFORM||process.platform;whe.exports=Bit!==\"win32\"?t=>t:t=>t&&t.replace(/\\\\/g,\"/\")});var YR=_((V4t,Bhe)=>{\"use strict\";var vit=bI(),g6=QI(),d6=Symbol(\"slurp\");Bhe.exports=class extends vit{constructor(e,r,s){switch(super(),this.pause(),this.extended=r,this.globalExtended=s,this.header=e,this.startBlockSize=512*Math.ceil(e.size/512),this.blockRemain=this.startBlockSize,this.remain=e.size,this.type=e.type,this.meta=!1,this.ignore=!1,this.type){case\"File\":case\"OldFile\":case\"Link\":case\"SymbolicLink\":case\"CharacterDevice\":case\"BlockDevice\":case\"Directory\":case\"FIFO\":case\"ContiguousFile\":case\"GNUDumpDir\":break;case\"NextFileHasLongLinkpath\":case\"NextFileHasLongPath\":case\"OldGnuLongPath\":case\"GlobalExtendedHeader\":case\"ExtendedHeader\":case\"OldExtendedHeader\":this.meta=!0;break;default:this.ignore=!0}this.path=g6(e.path),this.mode=e.mode,this.mode&&(this.mode=this.mode&4095),this.uid=e.uid,this.gid=e.gid,this.uname=e.uname,this.gname=e.gname,this.size=e.size,this.mtime=e.mtime,this.atime=e.atime,this.ctime=e.ctime,this.linkpath=g6(e.linkpath),this.uname=e.uname,this.gname=e.gname,r&&this[d6](r),s&&this[d6](s,!0)}write(e){let r=e.length;if(r>this.blockRemain)throw new Error(\"writing more to entry than is appropriate\");let s=this.remain,a=this.blockRemain;return this.remain=Math.max(0,s-r),this.blockRemain=Math.max(0,a-r),this.ignore?!0:s>=r?super.write(e):super.write(e.slice(0,s))}[d6](e,r){for(let s in e)e[s]!==null&&e[s]!==void 0&&!(r&&s===\"path\")&&(this[s]=s===\"path\"||s===\"linkpath\"?g6(e[s]):e[s])}}});var m6=_(VR=>{\"use strict\";VR.name=new Map([[\"0\",\"File\"],[\"\",\"OldFile\"],[\"1\",\"Link\"],[\"2\",\"SymbolicLink\"],[\"3\",\"CharacterDevice\"],[\"4\",\"BlockDevice\"],[\"5\",\"Directory\"],[\"6\",\"FIFO\"],[\"7\",\"ContiguousFile\"],[\"g\",\"GlobalExtendedHeader\"],[\"x\",\"ExtendedHeader\"],[\"A\",\"SolarisACL\"],[\"D\",\"GNUDumpDir\"],[\"I\",\"Inode\"],[\"K\",\"NextFileHasLongLinkpath\"],[\"L\",\"NextFileHasLongPath\"],[\"M\",\"ContinuationFile\"],[\"N\",\"OldGnuLongPath\"],[\"S\",\"SparseFile\"],[\"V\",\"TapeVolumeHeader\"],[\"X\",\"OldExtendedHeader\"]]);VR.code=new Map(Array.from(VR.name).map(t=>[t[1],t[0]]))});var Phe=_((K4t,Dhe)=>{\"use strict\";var Sit=(t,e)=>{if(Number.isSafeInteger(t))t<0?Pit(t,e):Dit(t,e);else throw Error(\"cannot encode number outside of javascript safe integer range\");return e},Dit=(t,e)=>{e[0]=128;for(var r=e.length;r>1;r--)e[r-1]=t&255,t=Math.floor(t/256)},Pit=(t,e)=>{e[0]=255;var r=!1;t=t*-1;for(var s=e.length;s>1;s--){var a=t&255;t=Math.floor(t/256),r?e[s-1]=vhe(a):a===0?e[s-1]=0:(r=!0,e[s-1]=She(a))}},bit=t=>{let e=t[0],r=e===128?kit(t.slice(1,t.length)):e===255?xit(t):null;if(r===null)throw Error(\"invalid base256 encoding\");if(!Number.isSafeInteger(r))throw Error(\"parsed number outside of javascript safe integer range\");return r},xit=t=>{for(var e=t.length,r=0,s=!1,a=e-1;a>-1;a--){var n=t[a],c;s?c=vhe(n):n===0?c=n:(s=!0,c=She(n)),c!==0&&(r-=c*Math.pow(256,e-a-1))}return r},kit=t=>{for(var e=t.length,r=0,s=e-1;s>-1;s--){var a=t[s];a!==0&&(r+=a*Math.pow(256,e-s-1))}return r},vhe=t=>(255^t)&255,She=t=>(255^t)+1&255;Dhe.exports={encode:Sit,parse:bit}});var TI=_((z4t,xhe)=>{\"use strict\";var y6=m6(),RI=Ie(\"path\").posix,bhe=Phe(),E6=Symbol(\"slurp\"),zl=Symbol(\"type\"),w6=class{constructor(e,r,s,a){this.cksumValid=!1,this.needPax=!1,this.nullBlock=!1,this.block=null,this.path=null,this.mode=null,this.uid=null,this.gid=null,this.size=null,this.mtime=null,this.cksum=null,this[zl]=\"0\",this.linkpath=null,this.uname=null,this.gname=null,this.devmaj=0,this.devmin=0,this.atime=null,this.ctime=null,Buffer.isBuffer(e)?this.decode(e,r||0,s,a):e&&this.set(e)}decode(e,r,s,a){if(r||(r=0),!e||!(e.length>=r+512))throw new Error(\"need 512 bytes for header\");if(this.path=pm(e,r,100),this.mode=Q0(e,r+100,8),this.uid=Q0(e,r+108,8),this.gid=Q0(e,r+116,8),this.size=Q0(e,r+124,12),this.mtime=I6(e,r+136,12),this.cksum=Q0(e,r+148,12),this[E6](s),this[E6](a,!0),this[zl]=pm(e,r+156,1),this[zl]===\"\"&&(this[zl]=\"0\"),this[zl]===\"0\"&&this.path.substr(-1)===\"/\"&&(this[zl]=\"5\"),this[zl]===\"5\"&&(this.size=0),this.linkpath=pm(e,r+157,100),e.slice(r+257,r+265).toString()===\"ustar\\x0000\")if(this.uname=pm(e,r+265,32),this.gname=pm(e,r+297,32),this.devmaj=Q0(e,r+329,8),this.devmin=Q0(e,r+337,8),e[r+475]!==0){let c=pm(e,r+345,155);this.path=c+\"/\"+this.path}else{let c=pm(e,r+345,130);c&&(this.path=c+\"/\"+this.path),this.atime=I6(e,r+476,12),this.ctime=I6(e,r+488,12)}let n=8*32;for(let c=r;c<r+148;c++)n+=e[c];for(let c=r+156;c<r+512;c++)n+=e[c];this.cksumValid=n===this.cksum,this.cksum===null&&n===8*32&&(this.nullBlock=!0)}[E6](e,r){for(let s in e)e[s]!==null&&e[s]!==void 0&&!(r&&s===\"path\")&&(this[s]=e[s])}encode(e,r){if(e||(e=this.block=Buffer.alloc(512),r=0),r||(r=0),!(e.length>=r+512))throw new Error(\"need 512 bytes for header\");let s=this.ctime||this.atime?130:155,a=Qit(this.path||\"\",s),n=a[0],c=a[1];this.needPax=a[2],this.needPax=hm(e,r,100,n)||this.needPax,this.needPax=R0(e,r+100,8,this.mode)||this.needPax,this.needPax=R0(e,r+108,8,this.uid)||this.needPax,this.needPax=R0(e,r+116,8,this.gid)||this.needPax,this.needPax=R0(e,r+124,12,this.size)||this.needPax,this.needPax=C6(e,r+136,12,this.mtime)||this.needPax,e[r+156]=this[zl].charCodeAt(0),this.needPax=hm(e,r+157,100,this.linkpath)||this.needPax,e.write(\"ustar\\x0000\",r+257,8),this.needPax=hm(e,r+265,32,this.uname)||this.needPax,this.needPax=hm(e,r+297,32,this.gname)||this.needPax,this.needPax=R0(e,r+329,8,this.devmaj)||this.needPax,this.needPax=R0(e,r+337,8,this.devmin)||this.needPax,this.needPax=hm(e,r+345,s,c)||this.needPax,e[r+475]!==0?this.needPax=hm(e,r+345,155,c)||this.needPax:(this.needPax=hm(e,r+345,130,c)||this.needPax,this.needPax=C6(e,r+476,12,this.atime)||this.needPax,this.needPax=C6(e,r+488,12,this.ctime)||this.needPax);let f=8*32;for(let p=r;p<r+148;p++)f+=e[p];for(let p=r+156;p<r+512;p++)f+=e[p];return this.cksum=f,R0(e,r+148,8,this.cksum),this.cksumValid=!0,this.needPax}set(e){for(let r in e)e[r]!==null&&e[r]!==void 0&&(this[r]=e[r])}get type(){return y6.name.get(this[zl])||this[zl]}get typeKey(){return this[zl]}set type(e){y6.code.has(e)?this[zl]=y6.code.get(e):this[zl]=e}},Qit=(t,e)=>{let s=t,a=\"\",n,c=RI.parse(t).root||\".\";if(Buffer.byteLength(s)<100)n=[s,a,!1];else{a=RI.dirname(s),s=RI.basename(s);do Buffer.byteLength(s)<=100&&Buffer.byteLength(a)<=e?n=[s,a,!1]:Buffer.byteLength(s)>100&&Buffer.byteLength(a)<=e?n=[s.substr(0,99),a,!0]:(s=RI.join(RI.basename(a),s),a=RI.dirname(a));while(a!==c&&!n);n||(n=[t.substr(0,99),\"\",!0])}return n},pm=(t,e,r)=>t.slice(e,e+r).toString(\"utf8\").replace(/\\0.*/,\"\"),I6=(t,e,r)=>Rit(Q0(t,e,r)),Rit=t=>t===null?null:new Date(t*1e3),Q0=(t,e,r)=>t[e]&128?bhe.parse(t.slice(e,e+r)):Fit(t,e,r),Tit=t=>isNaN(t)?null:t,Fit=(t,e,r)=>Tit(parseInt(t.slice(e,e+r).toString(\"utf8\").replace(/\\0.*$/,\"\").trim(),8)),Nit={12:8589934591,8:2097151},R0=(t,e,r,s)=>s===null?!1:s>Nit[r]||s<0?(bhe.encode(s,t.slice(e,e+r)),!0):(Oit(t,e,r,s),!1),Oit=(t,e,r,s)=>t.write(Lit(s,r),e,r,\"ascii\"),Lit=(t,e)=>Mit(Math.floor(t).toString(8),e),Mit=(t,e)=>(t.length===e-1?t:new Array(e-t.length-1).join(\"0\")+t+\" \")+\"\\0\",C6=(t,e,r,s)=>s===null?!1:R0(t,e,r,s.getTime()/1e3),Uit=new Array(156).join(\"\\0\"),hm=(t,e,r,s)=>s===null?!1:(t.write(s+Uit,e,r,\"utf8\"),s.length!==Buffer.byteLength(s)||s.length>r);xhe.exports=w6});var JR=_((Z4t,khe)=>{\"use strict\";var _it=TI(),Hit=Ie(\"path\"),Sv=class{constructor(e,r){this.atime=e.atime||null,this.charset=e.charset||null,this.comment=e.comment||null,this.ctime=e.ctime||null,this.gid=e.gid||null,this.gname=e.gname||null,this.linkpath=e.linkpath||null,this.mtime=e.mtime||null,this.path=e.path||null,this.size=e.size||null,this.uid=e.uid||null,this.uname=e.uname||null,this.dev=e.dev||null,this.ino=e.ino||null,this.nlink=e.nlink||null,this.global=r||!1}encode(){let e=this.encodeBody();if(e===\"\")return null;let r=Buffer.byteLength(e),s=512*Math.ceil(1+r/512),a=Buffer.allocUnsafe(s);for(let n=0;n<512;n++)a[n]=0;new _it({path:(\"PaxHeader/\"+Hit.basename(this.path)).slice(0,99),mode:this.mode||420,uid:this.uid||null,gid:this.gid||null,size:r,mtime:this.mtime||null,type:this.global?\"GlobalExtendedHeader\":\"ExtendedHeader\",linkpath:\"\",uname:this.uname||\"\",gname:this.gname||\"\",devmaj:0,devmin:0,atime:this.atime||null,ctime:this.ctime||null}).encode(a),a.write(e,512,r,\"utf8\");for(let n=r+512;n<a.length;n++)a[n]=0;return a}encodeBody(){return this.encodeField(\"path\")+this.encodeField(\"ctime\")+this.encodeField(\"atime\")+this.encodeField(\"dev\")+this.encodeField(\"ino\")+this.encodeField(\"nlink\")+this.encodeField(\"charset\")+this.encodeField(\"comment\")+this.encodeField(\"gid\")+this.encodeField(\"gname\")+this.encodeField(\"linkpath\")+this.encodeField(\"mtime\")+this.encodeField(\"size\")+this.encodeField(\"uid\")+this.encodeField(\"uname\")}encodeField(e){if(this[e]===null||this[e]===void 0)return\"\";let r=this[e]instanceof Date?this[e].getTime()/1e3:this[e],s=\" \"+(e===\"dev\"||e===\"ino\"||e===\"nlink\"?\"SCHILY.\":\"\")+e+\"=\"+r+`\n`,a=Buffer.byteLength(s),n=Math.floor(Math.log(a)/Math.log(10))+1;return a+n>=Math.pow(10,n)&&(n+=1),n+a+s}};Sv.parse=(t,e,r)=>new Sv(jit(Git(t),e),r);var jit=(t,e)=>e?Object.keys(t).reduce((r,s)=>(r[s]=t[s],r),e):t,Git=t=>t.replace(/\\n$/,\"\").split(`\n`).reduce(qit,Object.create(null)),qit=(t,e)=>{let r=parseInt(e,10);if(r!==Buffer.byteLength(e)+1)return t;e=e.substr((r+\" \").length);let s=e.split(\"=\"),a=s.shift().replace(/^SCHILY\\.(dev|ino|nlink)/,\"$1\");if(!a)return t;let n=s.join(\"=\");return t[a]=/^([A-Z]+\\.)?([mac]|birth|creation)time$/.test(a)?new Date(n*1e3):/^[0-9]+$/.test(n)?+n:n,t};khe.exports=Sv});var FI=_((X4t,Qhe)=>{Qhe.exports=t=>{let e=t.length-1,r=-1;for(;e>-1&&t.charAt(e)===\"/\";)r=e,e--;return r===-1?t:t.slice(0,r)}});var KR=_(($4t,Rhe)=>{\"use strict\";Rhe.exports=t=>class extends t{warn(e,r,s={}){this.file&&(s.file=this.file),this.cwd&&(s.cwd=this.cwd),s.code=r instanceof Error&&r.code||e,s.tarCode=e,!this.strict&&s.recoverable!==!1?(r instanceof Error&&(s=Object.assign(r,s),r=r.message),this.emit(\"warn\",s.tarCode,r,s)):r instanceof Error?this.emit(\"error\",Object.assign(r,s)):this.emit(\"error\",Object.assign(new Error(`${e}: ${r}`),s))}}});var v6=_((t3t,The)=>{\"use strict\";var zR=[\"|\",\"<\",\">\",\"?\",\":\"],B6=zR.map(t=>String.fromCharCode(61440+t.charCodeAt(0))),Wit=new Map(zR.map((t,e)=>[t,B6[e]])),Yit=new Map(B6.map((t,e)=>[t,zR[e]]));The.exports={encode:t=>zR.reduce((e,r)=>e.split(r).join(Wit.get(r)),t),decode:t=>B6.reduce((e,r)=>e.split(r).join(Yit.get(r)),t)}});var S6=_((r3t,Nhe)=>{var{isAbsolute:Vit,parse:Fhe}=Ie(\"path\").win32;Nhe.exports=t=>{let e=\"\",r=Fhe(t);for(;Vit(t)||r.root;){let s=t.charAt(0)===\"/\"&&t.slice(0,4)!==\"//?/\"?\"/\":r.root;t=t.substr(s.length),e+=s,r=Fhe(t)}return[e,t]}});var Lhe=_((n3t,Ohe)=>{\"use strict\";Ohe.exports=(t,e,r)=>(t&=4095,r&&(t=(t|384)&-19),e&&(t&256&&(t|=64),t&32&&(t|=8),t&4&&(t|=1)),t)});var N6=_((o3t,Zhe)=>{\"use strict\";var qhe=bI(),Whe=JR(),Yhe=TI(),nA=Ie(\"fs\"),Mhe=Ie(\"path\"),rA=QI(),Jit=FI(),Vhe=(t,e)=>e?(t=rA(t).replace(/^\\.(\\/|$)/,\"\"),Jit(e)+\"/\"+t):rA(t),Kit=16*1024*1024,Uhe=Symbol(\"process\"),_he=Symbol(\"file\"),Hhe=Symbol(\"directory\"),P6=Symbol(\"symlink\"),jhe=Symbol(\"hardlink\"),Dv=Symbol(\"header\"),ZR=Symbol(\"read\"),b6=Symbol(\"lstat\"),XR=Symbol(\"onlstat\"),x6=Symbol(\"onread\"),k6=Symbol(\"onreadlink\"),Q6=Symbol(\"openfile\"),R6=Symbol(\"onopenfile\"),T0=Symbol(\"close\"),$R=Symbol(\"mode\"),T6=Symbol(\"awaitDrain\"),D6=Symbol(\"ondrain\"),iA=Symbol(\"prefix\"),Ghe=Symbol(\"hadError\"),Jhe=KR(),zit=v6(),Khe=S6(),zhe=Lhe(),eT=Jhe(class extends qhe{constructor(e,r){if(r=r||{},super(r),typeof e!=\"string\")throw new TypeError(\"path is required\");this.path=rA(e),this.portable=!!r.portable,this.myuid=process.getuid&&process.getuid()||0,this.myuser=process.env.USER||\"\",this.maxReadSize=r.maxReadSize||Kit,this.linkCache=r.linkCache||new Map,this.statCache=r.statCache||new Map,this.preservePaths=!!r.preservePaths,this.cwd=rA(r.cwd||process.cwd()),this.strict=!!r.strict,this.noPax=!!r.noPax,this.noMtime=!!r.noMtime,this.mtime=r.mtime||null,this.prefix=r.prefix?rA(r.prefix):null,this.fd=null,this.blockLen=null,this.blockRemain=null,this.buf=null,this.offset=null,this.length=null,this.pos=null,this.remain=null,typeof r.onwarn==\"function\"&&this.on(\"warn\",r.onwarn);let s=!1;if(!this.preservePaths){let[a,n]=Khe(this.path);a&&(this.path=n,s=a)}this.win32=!!r.win32||process.platform===\"win32\",this.win32&&(this.path=zit.decode(this.path.replace(/\\\\/g,\"/\")),e=e.replace(/\\\\/g,\"/\")),this.absolute=rA(r.absolute||Mhe.resolve(this.cwd,e)),this.path===\"\"&&(this.path=\"./\"),s&&this.warn(\"TAR_ENTRY_INFO\",`stripping ${s} from absolute path`,{entry:this,path:s+this.path}),this.statCache.has(this.absolute)?this[XR](this.statCache.get(this.absolute)):this[b6]()}emit(e,...r){return e===\"error\"&&(this[Ghe]=!0),super.emit(e,...r)}[b6](){nA.lstat(this.absolute,(e,r)=>{if(e)return this.emit(\"error\",e);this[XR](r)})}[XR](e){this.statCache.set(this.absolute,e),this.stat=e,e.isFile()||(e.size=0),this.type=Xit(e),this.emit(\"stat\",e),this[Uhe]()}[Uhe](){switch(this.type){case\"File\":return this[_he]();case\"Directory\":return this[Hhe]();case\"SymbolicLink\":return this[P6]();default:return this.end()}}[$R](e){return zhe(e,this.type===\"Directory\",this.portable)}[iA](e){return Vhe(e,this.prefix)}[Dv](){this.type===\"Directory\"&&this.portable&&(this.noMtime=!0),this.header=new Yhe({path:this[iA](this.path),linkpath:this.type===\"Link\"?this[iA](this.linkpath):this.linkpath,mode:this[$R](this.stat.mode),uid:this.portable?null:this.stat.uid,gid:this.portable?null:this.stat.gid,size:this.stat.size,mtime:this.noMtime?null:this.mtime||this.stat.mtime,type:this.type,uname:this.portable?null:this.stat.uid===this.myuid?this.myuser:\"\",atime:this.portable?null:this.stat.atime,ctime:this.portable?null:this.stat.ctime}),this.header.encode()&&!this.noPax&&super.write(new Whe({atime:this.portable?null:this.header.atime,ctime:this.portable?null:this.header.ctime,gid:this.portable?null:this.header.gid,mtime:this.noMtime?null:this.mtime||this.header.mtime,path:this[iA](this.path),linkpath:this.type===\"Link\"?this[iA](this.linkpath):this.linkpath,size:this.header.size,uid:this.portable?null:this.header.uid,uname:this.portable?null:this.header.uname,dev:this.portable?null:this.stat.dev,ino:this.portable?null:this.stat.ino,nlink:this.portable?null:this.stat.nlink}).encode()),super.write(this.header.block)}[Hhe](){this.path.substr(-1)!==\"/\"&&(this.path+=\"/\"),this.stat.size=0,this[Dv](),this.end()}[P6](){nA.readlink(this.absolute,(e,r)=>{if(e)return this.emit(\"error\",e);this[k6](r)})}[k6](e){this.linkpath=rA(e),this[Dv](),this.end()}[jhe](e){this.type=\"Link\",this.linkpath=rA(Mhe.relative(this.cwd,e)),this.stat.size=0,this[Dv](),this.end()}[_he](){if(this.stat.nlink>1){let e=this.stat.dev+\":\"+this.stat.ino;if(this.linkCache.has(e)){let r=this.linkCache.get(e);if(r.indexOf(this.cwd)===0)return this[jhe](r)}this.linkCache.set(e,this.absolute)}if(this[Dv](),this.stat.size===0)return this.end();this[Q6]()}[Q6](){nA.open(this.absolute,\"r\",(e,r)=>{if(e)return this.emit(\"error\",e);this[R6](r)})}[R6](e){if(this.fd=e,this[Ghe])return this[T0]();this.blockLen=512*Math.ceil(this.stat.size/512),this.blockRemain=this.blockLen;let r=Math.min(this.blockLen,this.maxReadSize);this.buf=Buffer.allocUnsafe(r),this.offset=0,this.pos=0,this.remain=this.stat.size,this.length=this.buf.length,this[ZR]()}[ZR](){let{fd:e,buf:r,offset:s,length:a,pos:n}=this;nA.read(e,r,s,a,n,(c,f)=>{if(c)return this[T0](()=>this.emit(\"error\",c));this[x6](f)})}[T0](e){nA.close(this.fd,e)}[x6](e){if(e<=0&&this.remain>0){let a=new Error(\"encountered unexpected EOF\");return a.path=this.absolute,a.syscall=\"read\",a.code=\"EOF\",this[T0](()=>this.emit(\"error\",a))}if(e>this.remain){let a=new Error(\"did not encounter expected EOF\");return a.path=this.absolute,a.syscall=\"read\",a.code=\"EOF\",this[T0](()=>this.emit(\"error\",a))}if(e===this.remain)for(let a=e;a<this.length&&e<this.blockRemain;a++)this.buf[a+this.offset]=0,e++,this.remain++;let r=this.offset===0&&e===this.buf.length?this.buf:this.buf.slice(this.offset,this.offset+e);this.write(r)?this[D6]():this[T6](()=>this[D6]())}[T6](e){this.once(\"drain\",e)}write(e){if(this.blockRemain<e.length){let r=new Error(\"writing more data than expected\");return r.path=this.absolute,this.emit(\"error\",r)}return this.remain-=e.length,this.blockRemain-=e.length,this.pos+=e.length,this.offset+=e.length,super.write(e)}[D6](){if(!this.remain)return this.blockRemain&&super.write(Buffer.alloc(this.blockRemain)),this[T0](e=>e?this.emit(\"error\",e):this.end());this.offset>=this.length&&(this.buf=Buffer.allocUnsafe(Math.min(this.blockRemain,this.buf.length)),this.offset=0),this.length=this.buf.length-this.offset,this[ZR]()}}),F6=class extends eT{[b6](){this[XR](nA.lstatSync(this.absolute))}[P6](){this[k6](nA.readlinkSync(this.absolute))}[Q6](){this[R6](nA.openSync(this.absolute,\"r\"))}[ZR](){let e=!0;try{let{fd:r,buf:s,offset:a,length:n,pos:c}=this,f=nA.readSync(r,s,a,n,c);this[x6](f),e=!1}finally{if(e)try{this[T0](()=>{})}catch{}}}[T6](e){e()}[T0](e){nA.closeSync(this.fd),e()}},Zit=Jhe(class extends qhe{constructor(e,r){r=r||{},super(r),this.preservePaths=!!r.preservePaths,this.portable=!!r.portable,this.strict=!!r.strict,this.noPax=!!r.noPax,this.noMtime=!!r.noMtime,this.readEntry=e,this.type=e.type,this.type===\"Directory\"&&this.portable&&(this.noMtime=!0),this.prefix=r.prefix||null,this.path=rA(e.path),this.mode=this[$R](e.mode),this.uid=this.portable?null:e.uid,this.gid=this.portable?null:e.gid,this.uname=this.portable?null:e.uname,this.gname=this.portable?null:e.gname,this.size=e.size,this.mtime=this.noMtime?null:r.mtime||e.mtime,this.atime=this.portable?null:e.atime,this.ctime=this.portable?null:e.ctime,this.linkpath=rA(e.linkpath),typeof r.onwarn==\"function\"&&this.on(\"warn\",r.onwarn);let s=!1;if(!this.preservePaths){let[a,n]=Khe(this.path);a&&(this.path=n,s=a)}this.remain=e.size,this.blockRemain=e.startBlockSize,this.header=new Yhe({path:this[iA](this.path),linkpath:this.type===\"Link\"?this[iA](this.linkpath):this.linkpath,mode:this.mode,uid:this.portable?null:this.uid,gid:this.portable?null:this.gid,size:this.size,mtime:this.noMtime?null:this.mtime,type:this.type,uname:this.portable?null:this.uname,atime:this.portable?null:this.atime,ctime:this.portable?null:this.ctime}),s&&this.warn(\"TAR_ENTRY_INFO\",`stripping ${s} from absolute path`,{entry:this,path:s+this.path}),this.header.encode()&&!this.noPax&&super.write(new Whe({atime:this.portable?null:this.atime,ctime:this.portable?null:this.ctime,gid:this.portable?null:this.gid,mtime:this.noMtime?null:this.mtime,path:this[iA](this.path),linkpath:this.type===\"Link\"?this[iA](this.linkpath):this.linkpath,size:this.size,uid:this.portable?null:this.uid,uname:this.portable?null:this.uname,dev:this.portable?null:this.readEntry.dev,ino:this.portable?null:this.readEntry.ino,nlink:this.portable?null:this.readEntry.nlink}).encode()),super.write(this.header.block),e.pipe(this)}[iA](e){return Vhe(e,this.prefix)}[$R](e){return zhe(e,this.type===\"Directory\",this.portable)}write(e){let r=e.length;if(r>this.blockRemain)throw new Error(\"writing more to entry than is appropriate\");return this.blockRemain-=r,super.write(e)}end(){return this.blockRemain&&super.write(Buffer.alloc(this.blockRemain)),super.end()}});eT.Sync=F6;eT.Tar=Zit;var Xit=t=>t.isFile()?\"File\":t.isDirectory()?\"Directory\":t.isSymbolicLink()?\"SymbolicLink\":\"Unsupported\";Zhe.exports=eT});var cT=_((l3t,i0e)=>{\"use strict\";var aT=class{constructor(e,r){this.path=e||\"./\",this.absolute=r,this.entry=null,this.stat=null,this.readdir=null,this.pending=!1,this.ignore=!1,this.piped=!1}},$it=bI(),est=h6(),tst=YR(),q6=N6(),rst=q6.Sync,nst=q6.Tar,ist=$x(),Xhe=Buffer.alloc(1024),nT=Symbol(\"onStat\"),tT=Symbol(\"ended\"),sA=Symbol(\"queue\"),NI=Symbol(\"current\"),gm=Symbol(\"process\"),rT=Symbol(\"processing\"),$he=Symbol(\"processJob\"),oA=Symbol(\"jobs\"),O6=Symbol(\"jobDone\"),iT=Symbol(\"addFSEntry\"),e0e=Symbol(\"addTarEntry\"),_6=Symbol(\"stat\"),H6=Symbol(\"readdir\"),sT=Symbol(\"onreaddir\"),oT=Symbol(\"pipe\"),t0e=Symbol(\"entry\"),L6=Symbol(\"entryOpt\"),j6=Symbol(\"writeEntryClass\"),n0e=Symbol(\"write\"),M6=Symbol(\"ondrain\"),lT=Ie(\"fs\"),r0e=Ie(\"path\"),sst=KR(),U6=QI(),W6=sst(class extends $it{constructor(e){super(e),e=e||Object.create(null),this.opt=e,this.file=e.file||\"\",this.cwd=e.cwd||process.cwd(),this.maxReadSize=e.maxReadSize,this.preservePaths=!!e.preservePaths,this.strict=!!e.strict,this.noPax=!!e.noPax,this.prefix=U6(e.prefix||\"\"),this.linkCache=e.linkCache||new Map,this.statCache=e.statCache||new Map,this.readdirCache=e.readdirCache||new Map,this[j6]=q6,typeof e.onwarn==\"function\"&&this.on(\"warn\",e.onwarn),this.portable=!!e.portable,this.zip=null,e.gzip?(typeof e.gzip!=\"object\"&&(e.gzip={}),this.portable&&(e.gzip.portable=!0),this.zip=new est.Gzip(e.gzip),this.zip.on(\"data\",r=>super.write(r)),this.zip.on(\"end\",r=>super.end()),this.zip.on(\"drain\",r=>this[M6]()),this.on(\"resume\",r=>this.zip.resume())):this.on(\"drain\",this[M6]),this.noDirRecurse=!!e.noDirRecurse,this.follow=!!e.follow,this.noMtime=!!e.noMtime,this.mtime=e.mtime||null,this.filter=typeof e.filter==\"function\"?e.filter:r=>!0,this[sA]=new ist,this[oA]=0,this.jobs=+e.jobs||4,this[rT]=!1,this[tT]=!1}[n0e](e){return super.write(e)}add(e){return this.write(e),this}end(e){return e&&this.write(e),this[tT]=!0,this[gm](),this}write(e){if(this[tT])throw new Error(\"write after end\");return e instanceof tst?this[e0e](e):this[iT](e),this.flowing}[e0e](e){let r=U6(r0e.resolve(this.cwd,e.path));if(!this.filter(e.path,e))e.resume();else{let s=new aT(e.path,r,!1);s.entry=new nst(e,this[L6](s)),s.entry.on(\"end\",a=>this[O6](s)),this[oA]+=1,this[sA].push(s)}this[gm]()}[iT](e){let r=U6(r0e.resolve(this.cwd,e));this[sA].push(new aT(e,r)),this[gm]()}[_6](e){e.pending=!0,this[oA]+=1;let r=this.follow?\"stat\":\"lstat\";lT[r](e.absolute,(s,a)=>{e.pending=!1,this[oA]-=1,s?this.emit(\"error\",s):this[nT](e,a)})}[nT](e,r){this.statCache.set(e.absolute,r),e.stat=r,this.filter(e.path,r)||(e.ignore=!0),this[gm]()}[H6](e){e.pending=!0,this[oA]+=1,lT.readdir(e.absolute,(r,s)=>{if(e.pending=!1,this[oA]-=1,r)return this.emit(\"error\",r);this[sT](e,s)})}[sT](e,r){this.readdirCache.set(e.absolute,r),e.readdir=r,this[gm]()}[gm](){if(!this[rT]){this[rT]=!0;for(let e=this[sA].head;e!==null&&this[oA]<this.jobs;e=e.next)if(this[$he](e.value),e.value.ignore){let r=e.next;this[sA].removeNode(e),e.next=r}this[rT]=!1,this[tT]&&!this[sA].length&&this[oA]===0&&(this.zip?this.zip.end(Xhe):(super.write(Xhe),super.end()))}}get[NI](){return this[sA]&&this[sA].head&&this[sA].head.value}[O6](e){this[sA].shift(),this[oA]-=1,this[gm]()}[$he](e){if(!e.pending){if(e.entry){e===this[NI]&&!e.piped&&this[oT](e);return}if(e.stat||(this.statCache.has(e.absolute)?this[nT](e,this.statCache.get(e.absolute)):this[_6](e)),!!e.stat&&!e.ignore&&!(!this.noDirRecurse&&e.stat.isDirectory()&&!e.readdir&&(this.readdirCache.has(e.absolute)?this[sT](e,this.readdirCache.get(e.absolute)):this[H6](e),!e.readdir))){if(e.entry=this[t0e](e),!e.entry){e.ignore=!0;return}e===this[NI]&&!e.piped&&this[oT](e)}}}[L6](e){return{onwarn:(r,s,a)=>this.warn(r,s,a),noPax:this.noPax,cwd:this.cwd,absolute:e.absolute,preservePaths:this.preservePaths,maxReadSize:this.maxReadSize,strict:this.strict,portable:this.portable,linkCache:this.linkCache,statCache:this.statCache,noMtime:this.noMtime,mtime:this.mtime,prefix:this.prefix}}[t0e](e){this[oA]+=1;try{return new this[j6](e.path,this[L6](e)).on(\"end\",()=>this[O6](e)).on(\"error\",r=>this.emit(\"error\",r))}catch(r){this.emit(\"error\",r)}}[M6](){this[NI]&&this[NI].entry&&this[NI].entry.resume()}[oT](e){e.piped=!0,e.readdir&&e.readdir.forEach(a=>{let n=e.path,c=n===\"./\"?\"\":n.replace(/\\/*$/,\"/\");this[iT](c+a)});let r=e.entry,s=this.zip;s?r.on(\"data\",a=>{s.write(a)||r.pause()}):r.on(\"data\",a=>{super.write(a)||r.pause()})}pause(){return this.zip&&this.zip.pause(),super.pause()}}),G6=class extends W6{constructor(e){super(e),this[j6]=rst}pause(){}resume(){}[_6](e){let r=this.follow?\"statSync\":\"lstatSync\";this[nT](e,lT[r](e.absolute))}[H6](e,r){this[sT](e,lT.readdirSync(e.absolute))}[oT](e){let r=e.entry,s=this.zip;e.readdir&&e.readdir.forEach(a=>{let n=e.path,c=n===\"./\"?\"\":n.replace(/\\/*$/,\"/\");this[iT](c+a)}),s?r.on(\"data\",a=>{s.write(a)}):r.on(\"data\",a=>{super[n0e](a)})}};W6.Sync=G6;i0e.exports=W6});var GI=_(bv=>{\"use strict\";var ost=bI(),ast=Ie(\"events\").EventEmitter,fl=Ie(\"fs\"),J6=fl.writev;if(!J6){let t=process.binding(\"fs\"),e=t.FSReqWrap||t.FSReqCallback;J6=(r,s,a,n)=>{let c=(p,h)=>n(p,h,s),f=new e;f.oncomplete=c,t.writeBuffers(r,s,a,f)}}var HI=Symbol(\"_autoClose\"),Yu=Symbol(\"_close\"),Pv=Symbol(\"_ended\"),ii=Symbol(\"_fd\"),s0e=Symbol(\"_finished\"),N0=Symbol(\"_flags\"),Y6=Symbol(\"_flush\"),K6=Symbol(\"_handleChunk\"),z6=Symbol(\"_makeBuf\"),hT=Symbol(\"_mode\"),uT=Symbol(\"_needDrain\"),UI=Symbol(\"_onerror\"),jI=Symbol(\"_onopen\"),V6=Symbol(\"_onread\"),LI=Symbol(\"_onwrite\"),O0=Symbol(\"_open\"),Wp=Symbol(\"_path\"),dm=Symbol(\"_pos\"),aA=Symbol(\"_queue\"),MI=Symbol(\"_read\"),o0e=Symbol(\"_readSize\"),F0=Symbol(\"_reading\"),fT=Symbol(\"_remain\"),a0e=Symbol(\"_size\"),AT=Symbol(\"_write\"),OI=Symbol(\"_writing\"),pT=Symbol(\"_defaultFlag\"),_I=Symbol(\"_errored\"),gT=class extends ost{constructor(e,r){if(r=r||{},super(r),this.readable=!0,this.writable=!1,typeof e!=\"string\")throw new TypeError(\"path must be a string\");this[_I]=!1,this[ii]=typeof r.fd==\"number\"?r.fd:null,this[Wp]=e,this[o0e]=r.readSize||16*1024*1024,this[F0]=!1,this[a0e]=typeof r.size==\"number\"?r.size:1/0,this[fT]=this[a0e],this[HI]=typeof r.autoClose==\"boolean\"?r.autoClose:!0,typeof this[ii]==\"number\"?this[MI]():this[O0]()}get fd(){return this[ii]}get path(){return this[Wp]}write(){throw new TypeError(\"this is a readable stream\")}end(){throw new TypeError(\"this is a readable stream\")}[O0](){fl.open(this[Wp],\"r\",(e,r)=>this[jI](e,r))}[jI](e,r){e?this[UI](e):(this[ii]=r,this.emit(\"open\",r),this[MI]())}[z6](){return Buffer.allocUnsafe(Math.min(this[o0e],this[fT]))}[MI](){if(!this[F0]){this[F0]=!0;let e=this[z6]();if(e.length===0)return process.nextTick(()=>this[V6](null,0,e));fl.read(this[ii],e,0,e.length,null,(r,s,a)=>this[V6](r,s,a))}}[V6](e,r,s){this[F0]=!1,e?this[UI](e):this[K6](r,s)&&this[MI]()}[Yu](){if(this[HI]&&typeof this[ii]==\"number\"){let e=this[ii];this[ii]=null,fl.close(e,r=>r?this.emit(\"error\",r):this.emit(\"close\"))}}[UI](e){this[F0]=!0,this[Yu](),this.emit(\"error\",e)}[K6](e,r){let s=!1;return this[fT]-=e,e>0&&(s=super.write(e<r.length?r.slice(0,e):r)),(e===0||this[fT]<=0)&&(s=!1,this[Yu](),super.end()),s}emit(e,r){switch(e){case\"prefinish\":case\"finish\":break;case\"drain\":typeof this[ii]==\"number\"&&this[MI]();break;case\"error\":return this[_I]?void 0:(this[_I]=!0,super.emit(e,r));default:return super.emit(e,r)}}},Z6=class extends gT{[O0](){let e=!0;try{this[jI](null,fl.openSync(this[Wp],\"r\")),e=!1}finally{e&&this[Yu]()}}[MI](){let e=!0;try{if(!this[F0]){this[F0]=!0;do{let r=this[z6](),s=r.length===0?0:fl.readSync(this[ii],r,0,r.length,null);if(!this[K6](s,r))break}while(!0);this[F0]=!1}e=!1}finally{e&&this[Yu]()}}[Yu](){if(this[HI]&&typeof this[ii]==\"number\"){let e=this[ii];this[ii]=null,fl.closeSync(e),this.emit(\"close\")}}},dT=class extends ast{constructor(e,r){r=r||{},super(r),this.readable=!1,this.writable=!0,this[_I]=!1,this[OI]=!1,this[Pv]=!1,this[uT]=!1,this[aA]=[],this[Wp]=e,this[ii]=typeof r.fd==\"number\"?r.fd:null,this[hT]=r.mode===void 0?438:r.mode,this[dm]=typeof r.start==\"number\"?r.start:null,this[HI]=typeof r.autoClose==\"boolean\"?r.autoClose:!0;let s=this[dm]!==null?\"r+\":\"w\";this[pT]=r.flags===void 0,this[N0]=this[pT]?s:r.flags,this[ii]===null&&this[O0]()}emit(e,r){if(e===\"error\"){if(this[_I])return;this[_I]=!0}return super.emit(e,r)}get fd(){return this[ii]}get path(){return this[Wp]}[UI](e){this[Yu](),this[OI]=!0,this.emit(\"error\",e)}[O0](){fl.open(this[Wp],this[N0],this[hT],(e,r)=>this[jI](e,r))}[jI](e,r){this[pT]&&this[N0]===\"r+\"&&e&&e.code===\"ENOENT\"?(this[N0]=\"w\",this[O0]()):e?this[UI](e):(this[ii]=r,this.emit(\"open\",r),this[Y6]())}end(e,r){return e&&this.write(e,r),this[Pv]=!0,!this[OI]&&!this[aA].length&&typeof this[ii]==\"number\"&&this[LI](null,0),this}write(e,r){return typeof e==\"string\"&&(e=Buffer.from(e,r)),this[Pv]?(this.emit(\"error\",new Error(\"write() after end()\")),!1):this[ii]===null||this[OI]||this[aA].length?(this[aA].push(e),this[uT]=!0,!1):(this[OI]=!0,this[AT](e),!0)}[AT](e){fl.write(this[ii],e,0,e.length,this[dm],(r,s)=>this[LI](r,s))}[LI](e,r){e?this[UI](e):(this[dm]!==null&&(this[dm]+=r),this[aA].length?this[Y6]():(this[OI]=!1,this[Pv]&&!this[s0e]?(this[s0e]=!0,this[Yu](),this.emit(\"finish\")):this[uT]&&(this[uT]=!1,this.emit(\"drain\"))))}[Y6](){if(this[aA].length===0)this[Pv]&&this[LI](null,0);else if(this[aA].length===1)this[AT](this[aA].pop());else{let e=this[aA];this[aA]=[],J6(this[ii],e,this[dm],(r,s)=>this[LI](r,s))}}[Yu](){if(this[HI]&&typeof this[ii]==\"number\"){let e=this[ii];this[ii]=null,fl.close(e,r=>r?this.emit(\"error\",r):this.emit(\"close\"))}}},X6=class extends dT{[O0](){let e;if(this[pT]&&this[N0]===\"r+\")try{e=fl.openSync(this[Wp],this[N0],this[hT])}catch(r){if(r.code===\"ENOENT\")return this[N0]=\"w\",this[O0]();throw r}else e=fl.openSync(this[Wp],this[N0],this[hT]);this[jI](null,e)}[Yu](){if(this[HI]&&typeof this[ii]==\"number\"){let e=this[ii];this[ii]=null,fl.closeSync(e),this.emit(\"close\")}}[AT](e){let r=!0;try{this[LI](null,fl.writeSync(this[ii],e,0,e.length,this[dm])),r=!1}finally{if(r)try{this[Yu]()}catch{}}}};bv.ReadStream=gT;bv.ReadStreamSync=Z6;bv.WriteStream=dT;bv.WriteStreamSync=X6});var BT=_((f3t,h0e)=>{\"use strict\";var lst=KR(),cst=TI(),ust=Ie(\"events\"),fst=$x(),Ast=1024*1024,pst=YR(),l0e=JR(),hst=h6(),$6=Buffer.from([31,139]),Lc=Symbol(\"state\"),mm=Symbol(\"writeEntry\"),Yp=Symbol(\"readEntry\"),eG=Symbol(\"nextEntry\"),c0e=Symbol(\"processEntry\"),Mc=Symbol(\"extendedHeader\"),xv=Symbol(\"globalExtendedHeader\"),L0=Symbol(\"meta\"),u0e=Symbol(\"emitMeta\"),Di=Symbol(\"buffer\"),Vp=Symbol(\"queue\"),ym=Symbol(\"ended\"),f0e=Symbol(\"emittedEnd\"),Em=Symbol(\"emit\"),Al=Symbol(\"unzip\"),mT=Symbol(\"consumeChunk\"),yT=Symbol(\"consumeChunkSub\"),tG=Symbol(\"consumeBody\"),A0e=Symbol(\"consumeMeta\"),p0e=Symbol(\"consumeHeader\"),ET=Symbol(\"consuming\"),rG=Symbol(\"bufferConcat\"),nG=Symbol(\"maybeEnd\"),kv=Symbol(\"writing\"),M0=Symbol(\"aborted\"),IT=Symbol(\"onDone\"),Im=Symbol(\"sawValidEntry\"),CT=Symbol(\"sawNullBlock\"),wT=Symbol(\"sawEOF\"),gst=t=>!0;h0e.exports=lst(class extends ust{constructor(e){e=e||{},super(e),this.file=e.file||\"\",this[Im]=null,this.on(IT,r=>{(this[Lc]===\"begin\"||this[Im]===!1)&&this.warn(\"TAR_BAD_ARCHIVE\",\"Unrecognized archive format\")}),e.ondone?this.on(IT,e.ondone):this.on(IT,r=>{this.emit(\"prefinish\"),this.emit(\"finish\"),this.emit(\"end\"),this.emit(\"close\")}),this.strict=!!e.strict,this.maxMetaEntrySize=e.maxMetaEntrySize||Ast,this.filter=typeof e.filter==\"function\"?e.filter:gst,this.writable=!0,this.readable=!1,this[Vp]=new fst,this[Di]=null,this[Yp]=null,this[mm]=null,this[Lc]=\"begin\",this[L0]=\"\",this[Mc]=null,this[xv]=null,this[ym]=!1,this[Al]=null,this[M0]=!1,this[CT]=!1,this[wT]=!1,typeof e.onwarn==\"function\"&&this.on(\"warn\",e.onwarn),typeof e.onentry==\"function\"&&this.on(\"entry\",e.onentry)}[p0e](e,r){this[Im]===null&&(this[Im]=!1);let s;try{s=new cst(e,r,this[Mc],this[xv])}catch(a){return this.warn(\"TAR_ENTRY_INVALID\",a)}if(s.nullBlock)this[CT]?(this[wT]=!0,this[Lc]===\"begin\"&&(this[Lc]=\"header\"),this[Em](\"eof\")):(this[CT]=!0,this[Em](\"nullBlock\"));else if(this[CT]=!1,!s.cksumValid)this.warn(\"TAR_ENTRY_INVALID\",\"checksum failure\",{header:s});else if(!s.path)this.warn(\"TAR_ENTRY_INVALID\",\"path is required\",{header:s});else{let a=s.type;if(/^(Symbolic)?Link$/.test(a)&&!s.linkpath)this.warn(\"TAR_ENTRY_INVALID\",\"linkpath required\",{header:s});else if(!/^(Symbolic)?Link$/.test(a)&&s.linkpath)this.warn(\"TAR_ENTRY_INVALID\",\"linkpath forbidden\",{header:s});else{let n=this[mm]=new pst(s,this[Mc],this[xv]);if(!this[Im])if(n.remain){let c=()=>{n.invalid||(this[Im]=!0)};n.on(\"end\",c)}else this[Im]=!0;n.meta?n.size>this.maxMetaEntrySize?(n.ignore=!0,this[Em](\"ignoredEntry\",n),this[Lc]=\"ignore\",n.resume()):n.size>0&&(this[L0]=\"\",n.on(\"data\",c=>this[L0]+=c),this[Lc]=\"meta\"):(this[Mc]=null,n.ignore=n.ignore||!this.filter(n.path,n),n.ignore?(this[Em](\"ignoredEntry\",n),this[Lc]=n.remain?\"ignore\":\"header\",n.resume()):(n.remain?this[Lc]=\"body\":(this[Lc]=\"header\",n.end()),this[Yp]?this[Vp].push(n):(this[Vp].push(n),this[eG]())))}}}[c0e](e){let r=!0;return e?Array.isArray(e)?this.emit.apply(this,e):(this[Yp]=e,this.emit(\"entry\",e),e.emittedEnd||(e.on(\"end\",s=>this[eG]()),r=!1)):(this[Yp]=null,r=!1),r}[eG](){do;while(this[c0e](this[Vp].shift()));if(!this[Vp].length){let e=this[Yp];!e||e.flowing||e.size===e.remain?this[kv]||this.emit(\"drain\"):e.once(\"drain\",s=>this.emit(\"drain\"))}}[tG](e,r){let s=this[mm],a=s.blockRemain,n=a>=e.length&&r===0?e:e.slice(r,r+a);return s.write(n),s.blockRemain||(this[Lc]=\"header\",this[mm]=null,s.end()),n.length}[A0e](e,r){let s=this[mm],a=this[tG](e,r);return this[mm]||this[u0e](s),a}[Em](e,r,s){!this[Vp].length&&!this[Yp]?this.emit(e,r,s):this[Vp].push([e,r,s])}[u0e](e){switch(this[Em](\"meta\",this[L0]),e.type){case\"ExtendedHeader\":case\"OldExtendedHeader\":this[Mc]=l0e.parse(this[L0],this[Mc],!1);break;case\"GlobalExtendedHeader\":this[xv]=l0e.parse(this[L0],this[xv],!0);break;case\"NextFileHasLongPath\":case\"OldGnuLongPath\":this[Mc]=this[Mc]||Object.create(null),this[Mc].path=this[L0].replace(/\\0.*/,\"\");break;case\"NextFileHasLongLinkpath\":this[Mc]=this[Mc]||Object.create(null),this[Mc].linkpath=this[L0].replace(/\\0.*/,\"\");break;default:throw new Error(\"unknown meta: \"+e.type)}}abort(e){this[M0]=!0,this.emit(\"abort\",e),this.warn(\"TAR_ABORT\",e,{recoverable:!1})}write(e){if(this[M0])return;if(this[Al]===null&&e){if(this[Di]&&(e=Buffer.concat([this[Di],e]),this[Di]=null),e.length<$6.length)return this[Di]=e,!0;for(let s=0;this[Al]===null&&s<$6.length;s++)e[s]!==$6[s]&&(this[Al]=!1);if(this[Al]===null){let s=this[ym];this[ym]=!1,this[Al]=new hst.Unzip,this[Al].on(\"data\",n=>this[mT](n)),this[Al].on(\"error\",n=>this.abort(n)),this[Al].on(\"end\",n=>{this[ym]=!0,this[mT]()}),this[kv]=!0;let a=this[Al][s?\"end\":\"write\"](e);return this[kv]=!1,a}}this[kv]=!0,this[Al]?this[Al].write(e):this[mT](e),this[kv]=!1;let r=this[Vp].length?!1:this[Yp]?this[Yp].flowing:!0;return!r&&!this[Vp].length&&this[Yp].once(\"drain\",s=>this.emit(\"drain\")),r}[rG](e){e&&!this[M0]&&(this[Di]=this[Di]?Buffer.concat([this[Di],e]):e)}[nG](){if(this[ym]&&!this[f0e]&&!this[M0]&&!this[ET]){this[f0e]=!0;let e=this[mm];if(e&&e.blockRemain){let r=this[Di]?this[Di].length:0;this.warn(\"TAR_BAD_ARCHIVE\",`Truncated input (needed ${e.blockRemain} more bytes, only ${r} available)`,{entry:e}),this[Di]&&e.write(this[Di]),e.end()}this[Em](IT)}}[mT](e){if(this[ET])this[rG](e);else if(!e&&!this[Di])this[nG]();else{if(this[ET]=!0,this[Di]){this[rG](e);let r=this[Di];this[Di]=null,this[yT](r)}else this[yT](e);for(;this[Di]&&this[Di].length>=512&&!this[M0]&&!this[wT];){let r=this[Di];this[Di]=null,this[yT](r)}this[ET]=!1}(!this[Di]||this[ym])&&this[nG]()}[yT](e){let r=0,s=e.length;for(;r+512<=s&&!this[M0]&&!this[wT];)switch(this[Lc]){case\"begin\":case\"header\":this[p0e](e,r),r+=512;break;case\"ignore\":case\"body\":r+=this[tG](e,r);break;case\"meta\":r+=this[A0e](e,r);break;default:throw new Error(\"invalid state: \"+this[Lc])}r<s&&(this[Di]?this[Di]=Buffer.concat([e.slice(r),this[Di]]):this[Di]=e.slice(r))}end(e){this[M0]||(this[Al]?this[Al].end(e):(this[ym]=!0,this.write(e)))}})});var vT=_((A3t,y0e)=>{\"use strict\";var dst=DI(),d0e=BT(),qI=Ie(\"fs\"),mst=GI(),g0e=Ie(\"path\"),iG=FI();y0e.exports=(t,e,r)=>{typeof t==\"function\"?(r=t,e=null,t={}):Array.isArray(t)&&(e=t,t={}),typeof e==\"function\"&&(r=e,e=null),e?e=Array.from(e):e=[];let s=dst(t);if(s.sync&&typeof r==\"function\")throw new TypeError(\"callback not supported for sync tar functions\");if(!s.file&&typeof r==\"function\")throw new TypeError(\"callback only supported with file option\");return e.length&&Est(s,e),s.noResume||yst(s),s.file&&s.sync?Ist(s):s.file?Cst(s,r):m0e(s)};var yst=t=>{let e=t.onentry;t.onentry=e?r=>{e(r),r.resume()}:r=>r.resume()},Est=(t,e)=>{let r=new Map(e.map(n=>[iG(n),!0])),s=t.filter,a=(n,c)=>{let f=c||g0e.parse(n).root||\".\",p=n===f?!1:r.has(n)?r.get(n):a(g0e.dirname(n),f);return r.set(n,p),p};t.filter=s?(n,c)=>s(n,c)&&a(iG(n)):n=>a(iG(n))},Ist=t=>{let e=m0e(t),r=t.file,s=!0,a;try{let n=qI.statSync(r),c=t.maxReadSize||16*1024*1024;if(n.size<c)e.end(qI.readFileSync(r));else{let f=0,p=Buffer.allocUnsafe(c);for(a=qI.openSync(r,\"r\");f<n.size;){let h=qI.readSync(a,p,0,c,f);f+=h,e.write(p.slice(0,h))}e.end()}s=!1}finally{if(s&&a)try{qI.closeSync(a)}catch{}}},Cst=(t,e)=>{let r=new d0e(t),s=t.maxReadSize||16*1024*1024,a=t.file,n=new Promise((c,f)=>{r.on(\"error\",f),r.on(\"end\",c),qI.stat(a,(p,h)=>{if(p)f(p);else{let E=new mst.ReadStream(a,{readSize:s,size:h.size});E.on(\"error\",f),E.pipe(r)}})});return e?n.then(e,e):n},m0e=t=>new d0e(t)});var v0e=_((p3t,B0e)=>{\"use strict\";var wst=DI(),ST=cT(),E0e=GI(),I0e=vT(),C0e=Ie(\"path\");B0e.exports=(t,e,r)=>{if(typeof e==\"function\"&&(r=e),Array.isArray(t)&&(e=t,t={}),!e||!Array.isArray(e)||!e.length)throw new TypeError(\"no files or directories specified\");e=Array.from(e);let s=wst(t);if(s.sync&&typeof r==\"function\")throw new TypeError(\"callback not supported for sync tar functions\");if(!s.file&&typeof r==\"function\")throw new TypeError(\"callback only supported with file option\");return s.file&&s.sync?Bst(s,e):s.file?vst(s,e,r):s.sync?Sst(s,e):Dst(s,e)};var Bst=(t,e)=>{let r=new ST.Sync(t),s=new E0e.WriteStreamSync(t.file,{mode:t.mode||438});r.pipe(s),w0e(r,e)},vst=(t,e,r)=>{let s=new ST(t),a=new E0e.WriteStream(t.file,{mode:t.mode||438});s.pipe(a);let n=new Promise((c,f)=>{a.on(\"error\",f),a.on(\"close\",c),s.on(\"error\",f)});return sG(s,e),r?n.then(r,r):n},w0e=(t,e)=>{e.forEach(r=>{r.charAt(0)===\"@\"?I0e({file:C0e.resolve(t.cwd,r.substr(1)),sync:!0,noResume:!0,onentry:s=>t.add(s)}):t.add(r)}),t.end()},sG=(t,e)=>{for(;e.length;){let r=e.shift();if(r.charAt(0)===\"@\")return I0e({file:C0e.resolve(t.cwd,r.substr(1)),noResume:!0,onentry:s=>t.add(s)}).then(s=>sG(t,e));t.add(r)}t.end()},Sst=(t,e)=>{let r=new ST.Sync(t);return w0e(r,e),r},Dst=(t,e)=>{let r=new ST(t);return sG(r,e),r}});var oG=_((h3t,Q0e)=>{\"use strict\";var Pst=DI(),S0e=cT(),Zl=Ie(\"fs\"),D0e=GI(),P0e=vT(),b0e=Ie(\"path\"),x0e=TI();Q0e.exports=(t,e,r)=>{let s=Pst(t);if(!s.file)throw new TypeError(\"file is required\");if(s.gzip)throw new TypeError(\"cannot append to compressed archives\");if(!e||!Array.isArray(e)||!e.length)throw new TypeError(\"no files or directories specified\");return e=Array.from(e),s.sync?bst(s,e):kst(s,e,r)};var bst=(t,e)=>{let r=new S0e.Sync(t),s=!0,a,n;try{try{a=Zl.openSync(t.file,\"r+\")}catch(p){if(p.code===\"ENOENT\")a=Zl.openSync(t.file,\"w+\");else throw p}let c=Zl.fstatSync(a),f=Buffer.alloc(512);e:for(n=0;n<c.size;n+=512){for(let E=0,C=0;E<512;E+=C){if(C=Zl.readSync(a,f,E,f.length-E,n+E),n===0&&f[0]===31&&f[1]===139)throw new Error(\"cannot append to compressed archives\");if(!C)break e}let p=new x0e(f);if(!p.cksumValid)break;let h=512*Math.ceil(p.size/512);if(n+h+512>c.size)break;n+=h,t.mtimeCache&&t.mtimeCache.set(p.path,p.mtime)}s=!1,xst(t,r,n,a,e)}finally{if(s)try{Zl.closeSync(a)}catch{}}},xst=(t,e,r,s,a)=>{let n=new D0e.WriteStreamSync(t.file,{fd:s,start:r});e.pipe(n),Qst(e,a)},kst=(t,e,r)=>{e=Array.from(e);let s=new S0e(t),a=(c,f,p)=>{let h=(I,T)=>{I?Zl.close(c,N=>p(I)):p(null,T)},E=0;if(f===0)return h(null,0);let C=0,S=Buffer.alloc(512),b=(I,T)=>{if(I)return h(I);if(C+=T,C<512&&T)return Zl.read(c,S,C,S.length-C,E+C,b);if(E===0&&S[0]===31&&S[1]===139)return h(new Error(\"cannot append to compressed archives\"));if(C<512)return h(null,E);let N=new x0e(S);if(!N.cksumValid)return h(null,E);let U=512*Math.ceil(N.size/512);if(E+U+512>f||(E+=U+512,E>=f))return h(null,E);t.mtimeCache&&t.mtimeCache.set(N.path,N.mtime),C=0,Zl.read(c,S,0,512,E,b)};Zl.read(c,S,0,512,E,b)},n=new Promise((c,f)=>{s.on(\"error\",f);let p=\"r+\",h=(E,C)=>{if(E&&E.code===\"ENOENT\"&&p===\"r+\")return p=\"w+\",Zl.open(t.file,p,h);if(E)return f(E);Zl.fstat(C,(S,b)=>{if(S)return Zl.close(C,()=>f(S));a(C,b.size,(I,T)=>{if(I)return f(I);let N=new D0e.WriteStream(t.file,{fd:C,start:T});s.pipe(N),N.on(\"error\",f),N.on(\"close\",c),k0e(s,e)})})};Zl.open(t.file,p,h)});return r?n.then(r,r):n},Qst=(t,e)=>{e.forEach(r=>{r.charAt(0)===\"@\"?P0e({file:b0e.resolve(t.cwd,r.substr(1)),sync:!0,noResume:!0,onentry:s=>t.add(s)}):t.add(r)}),t.end()},k0e=(t,e)=>{for(;e.length;){let r=e.shift();if(r.charAt(0)===\"@\")return P0e({file:b0e.resolve(t.cwd,r.substr(1)),noResume:!0,onentry:s=>t.add(s)}).then(s=>k0e(t,e));t.add(r)}t.end()}});var T0e=_((g3t,R0e)=>{\"use strict\";var Rst=DI(),Tst=oG();R0e.exports=(t,e,r)=>{let s=Rst(t);if(!s.file)throw new TypeError(\"file is required\");if(s.gzip)throw new TypeError(\"cannot append to compressed archives\");if(!e||!Array.isArray(e)||!e.length)throw new TypeError(\"no files or directories specified\");return e=Array.from(e),Fst(s),Tst(s,e,r)};var Fst=t=>{let e=t.filter;t.mtimeCache||(t.mtimeCache=new Map),t.filter=e?(r,s)=>e(r,s)&&!(t.mtimeCache.get(r)>s.mtime):(r,s)=>!(t.mtimeCache.get(r)>s.mtime)}});var O0e=_((d3t,N0e)=>{var{promisify:F0e}=Ie(\"util\"),U0=Ie(\"fs\"),Nst=t=>{if(!t)t={mode:511,fs:U0};else if(typeof t==\"object\")t={mode:511,fs:U0,...t};else if(typeof t==\"number\")t={mode:t,fs:U0};else if(typeof t==\"string\")t={mode:parseInt(t,8),fs:U0};else throw new TypeError(\"invalid options argument\");return t.mkdir=t.mkdir||t.fs.mkdir||U0.mkdir,t.mkdirAsync=F0e(t.mkdir),t.stat=t.stat||t.fs.stat||U0.stat,t.statAsync=F0e(t.stat),t.statSync=t.statSync||t.fs.statSync||U0.statSync,t.mkdirSync=t.mkdirSync||t.fs.mkdirSync||U0.mkdirSync,t};N0e.exports=Nst});var M0e=_((m3t,L0e)=>{var Ost=process.platform,{resolve:Lst,parse:Mst}=Ie(\"path\"),Ust=t=>{if(/\\0/.test(t))throw Object.assign(new TypeError(\"path must be a string without null bytes\"),{path:t,code:\"ERR_INVALID_ARG_VALUE\"});if(t=Lst(t),Ost===\"win32\"){let e=/[*|\"<>?:]/,{root:r}=Mst(t);if(e.test(t.substr(r.length)))throw Object.assign(new Error(\"Illegal characters in path.\"),{path:t,code:\"EINVAL\"})}return t};L0e.exports=Ust});var G0e=_((y3t,j0e)=>{var{dirname:U0e}=Ie(\"path\"),_0e=(t,e,r=void 0)=>r===e?Promise.resolve():t.statAsync(e).then(s=>s.isDirectory()?r:void 0,s=>s.code===\"ENOENT\"?_0e(t,U0e(e),e):void 0),H0e=(t,e,r=void 0)=>{if(r!==e)try{return t.statSync(e).isDirectory()?r:void 0}catch(s){return s.code===\"ENOENT\"?H0e(t,U0e(e),e):void 0}};j0e.exports={findMade:_0e,findMadeSync:H0e}});var cG=_((E3t,W0e)=>{var{dirname:q0e}=Ie(\"path\"),aG=(t,e,r)=>{e.recursive=!1;let s=q0e(t);return s===t?e.mkdirAsync(t,e).catch(a=>{if(a.code!==\"EISDIR\")throw a}):e.mkdirAsync(t,e).then(()=>r||t,a=>{if(a.code===\"ENOENT\")return aG(s,e).then(n=>aG(t,e,n));if(a.code!==\"EEXIST\"&&a.code!==\"EROFS\")throw a;return e.statAsync(t).then(n=>{if(n.isDirectory())return r;throw a},()=>{throw a})})},lG=(t,e,r)=>{let s=q0e(t);if(e.recursive=!1,s===t)try{return e.mkdirSync(t,e)}catch(a){if(a.code!==\"EISDIR\")throw a;return}try{return e.mkdirSync(t,e),r||t}catch(a){if(a.code===\"ENOENT\")return lG(t,e,lG(s,e,r));if(a.code!==\"EEXIST\"&&a.code!==\"EROFS\")throw a;try{if(!e.statSync(t).isDirectory())throw a}catch{throw a}}};W0e.exports={mkdirpManual:aG,mkdirpManualSync:lG}});var J0e=_((I3t,V0e)=>{var{dirname:Y0e}=Ie(\"path\"),{findMade:_st,findMadeSync:Hst}=G0e(),{mkdirpManual:jst,mkdirpManualSync:Gst}=cG(),qst=(t,e)=>(e.recursive=!0,Y0e(t)===t?e.mkdirAsync(t,e):_st(e,t).then(s=>e.mkdirAsync(t,e).then(()=>s).catch(a=>{if(a.code===\"ENOENT\")return jst(t,e);throw a}))),Wst=(t,e)=>{if(e.recursive=!0,Y0e(t)===t)return e.mkdirSync(t,e);let s=Hst(e,t);try{return e.mkdirSync(t,e),s}catch(a){if(a.code===\"ENOENT\")return Gst(t,e);throw a}};V0e.exports={mkdirpNative:qst,mkdirpNativeSync:Wst}});var X0e=_((C3t,Z0e)=>{var K0e=Ie(\"fs\"),Yst=process.version,uG=Yst.replace(/^v/,\"\").split(\".\"),z0e=+uG[0]>10||+uG[0]==10&&+uG[1]>=12,Vst=z0e?t=>t.mkdir===K0e.mkdir:()=>!1,Jst=z0e?t=>t.mkdirSync===K0e.mkdirSync:()=>!1;Z0e.exports={useNative:Vst,useNativeSync:Jst}});var ige=_((w3t,nge)=>{var WI=O0e(),YI=M0e(),{mkdirpNative:$0e,mkdirpNativeSync:ege}=J0e(),{mkdirpManual:tge,mkdirpManualSync:rge}=cG(),{useNative:Kst,useNativeSync:zst}=X0e(),VI=(t,e)=>(t=YI(t),e=WI(e),Kst(e)?$0e(t,e):tge(t,e)),Zst=(t,e)=>(t=YI(t),e=WI(e),zst(e)?ege(t,e):rge(t,e));VI.sync=Zst;VI.native=(t,e)=>$0e(YI(t),WI(e));VI.manual=(t,e)=>tge(YI(t),WI(e));VI.nativeSync=(t,e)=>ege(YI(t),WI(e));VI.manualSync=(t,e)=>rge(YI(t),WI(e));nge.exports=VI});var fge=_((B3t,uge)=>{\"use strict\";var Uc=Ie(\"fs\"),Cm=Ie(\"path\"),Xst=Uc.lchown?\"lchown\":\"chown\",$st=Uc.lchownSync?\"lchownSync\":\"chownSync\",oge=Uc.lchown&&!process.version.match(/v1[1-9]+\\./)&&!process.version.match(/v10\\.[6-9]/),sge=(t,e,r)=>{try{return Uc[$st](t,e,r)}catch(s){if(s.code!==\"ENOENT\")throw s}},eot=(t,e,r)=>{try{return Uc.chownSync(t,e,r)}catch(s){if(s.code!==\"ENOENT\")throw s}},tot=oge?(t,e,r,s)=>a=>{!a||a.code!==\"EISDIR\"?s(a):Uc.chown(t,e,r,s)}:(t,e,r,s)=>s,fG=oge?(t,e,r)=>{try{return sge(t,e,r)}catch(s){if(s.code!==\"EISDIR\")throw s;eot(t,e,r)}}:(t,e,r)=>sge(t,e,r),rot=process.version,age=(t,e,r)=>Uc.readdir(t,e,r),not=(t,e)=>Uc.readdirSync(t,e);/^v4\\./.test(rot)&&(age=(t,e,r)=>Uc.readdir(t,r));var DT=(t,e,r,s)=>{Uc[Xst](t,e,r,tot(t,e,r,a=>{s(a&&a.code!==\"ENOENT\"?a:null)}))},lge=(t,e,r,s,a)=>{if(typeof e==\"string\")return Uc.lstat(Cm.resolve(t,e),(n,c)=>{if(n)return a(n.code!==\"ENOENT\"?n:null);c.name=e,lge(t,c,r,s,a)});if(e.isDirectory())AG(Cm.resolve(t,e.name),r,s,n=>{if(n)return a(n);let c=Cm.resolve(t,e.name);DT(c,r,s,a)});else{let n=Cm.resolve(t,e.name);DT(n,r,s,a)}},AG=(t,e,r,s)=>{age(t,{withFileTypes:!0},(a,n)=>{if(a){if(a.code===\"ENOENT\")return s();if(a.code!==\"ENOTDIR\"&&a.code!==\"ENOTSUP\")return s(a)}if(a||!n.length)return DT(t,e,r,s);let c=n.length,f=null,p=h=>{if(!f){if(h)return s(f=h);if(--c===0)return DT(t,e,r,s)}};n.forEach(h=>lge(t,h,e,r,p))})},iot=(t,e,r,s)=>{if(typeof e==\"string\")try{let a=Uc.lstatSync(Cm.resolve(t,e));a.name=e,e=a}catch(a){if(a.code===\"ENOENT\")return;throw a}e.isDirectory()&&cge(Cm.resolve(t,e.name),r,s),fG(Cm.resolve(t,e.name),r,s)},cge=(t,e,r)=>{let s;try{s=not(t,{withFileTypes:!0})}catch(a){if(a.code===\"ENOENT\")return;if(a.code===\"ENOTDIR\"||a.code===\"ENOTSUP\")return fG(t,e,r);throw a}return s&&s.length&&s.forEach(a=>iot(t,a,e,r)),fG(t,e,r)};uge.exports=AG;AG.sync=cge});var gge=_((v3t,pG)=>{\"use strict\";var Age=ige(),_c=Ie(\"fs\"),PT=Ie(\"path\"),pge=fge(),Vu=QI(),bT=class extends Error{constructor(e,r){super(\"Cannot extract through symbolic link\"),this.path=r,this.symlink=e}get name(){return\"SylinkError\"}},xT=class extends Error{constructor(e,r){super(r+\": Cannot cd into '\"+e+\"'\"),this.path=e,this.code=r}get name(){return\"CwdError\"}},kT=(t,e)=>t.get(Vu(e)),Qv=(t,e,r)=>t.set(Vu(e),r),sot=(t,e)=>{_c.stat(t,(r,s)=>{(r||!s.isDirectory())&&(r=new xT(t,r&&r.code||\"ENOTDIR\")),e(r)})};pG.exports=(t,e,r)=>{t=Vu(t);let s=e.umask,a=e.mode|448,n=(a&s)!==0,c=e.uid,f=e.gid,p=typeof c==\"number\"&&typeof f==\"number\"&&(c!==e.processUid||f!==e.processGid),h=e.preserve,E=e.unlink,C=e.cache,S=Vu(e.cwd),b=(N,U)=>{N?r(N):(Qv(C,t,!0),U&&p?pge(U,c,f,W=>b(W)):n?_c.chmod(t,a,r):r())};if(C&&kT(C,t)===!0)return b();if(t===S)return sot(t,b);if(h)return Age(t,{mode:a}).then(N=>b(null,N),b);let T=Vu(PT.relative(S,t)).split(\"/\");QT(S,T,a,C,E,S,null,b)};var QT=(t,e,r,s,a,n,c,f)=>{if(!e.length)return f(null,c);let p=e.shift(),h=Vu(PT.resolve(t+\"/\"+p));if(kT(s,h))return QT(h,e,r,s,a,n,c,f);_c.mkdir(h,r,hge(h,e,r,s,a,n,c,f))},hge=(t,e,r,s,a,n,c,f)=>p=>{p?_c.lstat(t,(h,E)=>{if(h)h.path=h.path&&Vu(h.path),f(h);else if(E.isDirectory())QT(t,e,r,s,a,n,c,f);else if(a)_c.unlink(t,C=>{if(C)return f(C);_c.mkdir(t,r,hge(t,e,r,s,a,n,c,f))});else{if(E.isSymbolicLink())return f(new bT(t,t+\"/\"+e.join(\"/\")));f(p)}}):(c=c||t,QT(t,e,r,s,a,n,c,f))},oot=t=>{let e=!1,r=\"ENOTDIR\";try{e=_c.statSync(t).isDirectory()}catch(s){r=s.code}finally{if(!e)throw new xT(t,r)}};pG.exports.sync=(t,e)=>{t=Vu(t);let r=e.umask,s=e.mode|448,a=(s&r)!==0,n=e.uid,c=e.gid,f=typeof n==\"number\"&&typeof c==\"number\"&&(n!==e.processUid||c!==e.processGid),p=e.preserve,h=e.unlink,E=e.cache,C=Vu(e.cwd),S=N=>{Qv(E,t,!0),N&&f&&pge.sync(N,n,c),a&&_c.chmodSync(t,s)};if(E&&kT(E,t)===!0)return S();if(t===C)return oot(C),S();if(p)return S(Age.sync(t,s));let I=Vu(PT.relative(C,t)).split(\"/\"),T=null;for(let N=I.shift(),U=C;N&&(U+=\"/\"+N);N=I.shift())if(U=Vu(PT.resolve(U)),!kT(E,U))try{_c.mkdirSync(U,s),T=T||U,Qv(E,U,!0)}catch{let ee=_c.lstatSync(U);if(ee.isDirectory()){Qv(E,U,!0);continue}else if(h){_c.unlinkSync(U),_c.mkdirSync(U,s),T=T||U,Qv(E,U,!0);continue}else if(ee.isSymbolicLink())return new bT(U,U+\"/\"+I.join(\"/\"))}return S(T)}});var gG=_((S3t,dge)=>{var hG=Object.create(null),{hasOwnProperty:aot}=Object.prototype;dge.exports=t=>(aot.call(hG,t)||(hG[t]=t.normalize(\"NFKD\")),hG[t])});var Ige=_((D3t,Ege)=>{var mge=Ie(\"assert\"),lot=gG(),cot=FI(),{join:yge}=Ie(\"path\"),uot=process.env.TESTING_TAR_FAKE_PLATFORM||process.platform,fot=uot===\"win32\";Ege.exports=()=>{let t=new Map,e=new Map,r=h=>h.split(\"/\").slice(0,-1).reduce((C,S)=>(C.length&&(S=yge(C[C.length-1],S)),C.push(S||\"/\"),C),[]),s=new Set,a=h=>{let E=e.get(h);if(!E)throw new Error(\"function does not have any path reservations\");return{paths:E.paths.map(C=>t.get(C)),dirs:[...E.dirs].map(C=>t.get(C))}},n=h=>{let{paths:E,dirs:C}=a(h);return E.every(S=>S[0]===h)&&C.every(S=>S[0]instanceof Set&&S[0].has(h))},c=h=>s.has(h)||!n(h)?!1:(s.add(h),h(()=>f(h)),!0),f=h=>{if(!s.has(h))return!1;let{paths:E,dirs:C}=e.get(h),S=new Set;return E.forEach(b=>{let I=t.get(b);mge.equal(I[0],h),I.length===1?t.delete(b):(I.shift(),typeof I[0]==\"function\"?S.add(I[0]):I[0].forEach(T=>S.add(T)))}),C.forEach(b=>{let I=t.get(b);mge(I[0]instanceof Set),I[0].size===1&&I.length===1?t.delete(b):I[0].size===1?(I.shift(),S.add(I[0])):I[0].delete(h)}),s.delete(h),S.forEach(b=>c(b)),!0};return{check:n,reserve:(h,E)=>{h=fot?[\"win32 parallelization disabled\"]:h.map(S=>lot(cot(yge(S))).toLowerCase());let C=new Set(h.map(S=>r(S)).reduce((S,b)=>S.concat(b)));return e.set(E,{dirs:C,paths:h}),h.forEach(S=>{let b=t.get(S);b?b.push(E):t.set(S,[E])}),C.forEach(S=>{let b=t.get(S);b?b[b.length-1]instanceof Set?b[b.length-1].add(E):b.push(new Set([E])):t.set(S,[new Set([E])])}),c(E)}}}});var Bge=_((P3t,wge)=>{var Aot=process.platform,pot=Aot===\"win32\",hot=global.__FAKE_TESTING_FS__||Ie(\"fs\"),{O_CREAT:got,O_TRUNC:dot,O_WRONLY:mot,UV_FS_O_FILEMAP:Cge=0}=hot.constants,yot=pot&&!!Cge,Eot=512*1024,Iot=Cge|dot|got|mot;wge.exports=yot?t=>t<Eot?Iot:\"w\":()=>\"w\"});var vG=_((b3t,Lge)=>{\"use strict\";var Cot=Ie(\"assert\"),wot=BT(),Mn=Ie(\"fs\"),Bot=GI(),Jp=Ie(\"path\"),Fge=gge(),vge=v6(),vot=Ige(),Sot=S6(),Xl=QI(),Dot=FI(),Pot=gG(),Sge=Symbol(\"onEntry\"),yG=Symbol(\"checkFs\"),Dge=Symbol(\"checkFs2\"),FT=Symbol(\"pruneCache\"),EG=Symbol(\"isReusable\"),Hc=Symbol(\"makeFs\"),IG=Symbol(\"file\"),CG=Symbol(\"directory\"),NT=Symbol(\"link\"),Pge=Symbol(\"symlink\"),bge=Symbol(\"hardlink\"),xge=Symbol(\"unsupported\"),kge=Symbol(\"checkPath\"),_0=Symbol(\"mkdir\"),Zo=Symbol(\"onError\"),RT=Symbol(\"pending\"),Qge=Symbol(\"pend\"),JI=Symbol(\"unpend\"),dG=Symbol(\"ended\"),mG=Symbol(\"maybeClose\"),wG=Symbol(\"skip\"),Rv=Symbol(\"doChown\"),Tv=Symbol(\"uid\"),Fv=Symbol(\"gid\"),Nv=Symbol(\"checkedCwd\"),Nge=Ie(\"crypto\"),Oge=Bge(),bot=process.env.TESTING_TAR_FAKE_PLATFORM||process.platform,Ov=bot===\"win32\",xot=(t,e)=>{if(!Ov)return Mn.unlink(t,e);let r=t+\".DELETE.\"+Nge.randomBytes(16).toString(\"hex\");Mn.rename(t,r,s=>{if(s)return e(s);Mn.unlink(r,e)})},kot=t=>{if(!Ov)return Mn.unlinkSync(t);let e=t+\".DELETE.\"+Nge.randomBytes(16).toString(\"hex\");Mn.renameSync(t,e),Mn.unlinkSync(e)},Rge=(t,e,r)=>t===t>>>0?t:e===e>>>0?e:r,Tge=t=>Pot(Dot(Xl(t))).toLowerCase(),Qot=(t,e)=>{e=Tge(e);for(let r of t.keys()){let s=Tge(r);(s===e||s.indexOf(e+\"/\")===0)&&t.delete(r)}},Rot=t=>{for(let e of t.keys())t.delete(e)},Lv=class extends wot{constructor(e){if(e||(e={}),e.ondone=r=>{this[dG]=!0,this[mG]()},super(e),this[Nv]=!1,this.reservations=vot(),this.transform=typeof e.transform==\"function\"?e.transform:null,this.writable=!0,this.readable=!1,this[RT]=0,this[dG]=!1,this.dirCache=e.dirCache||new Map,typeof e.uid==\"number\"||typeof e.gid==\"number\"){if(typeof e.uid!=\"number\"||typeof e.gid!=\"number\")throw new TypeError(\"cannot set owner without number uid and gid\");if(e.preserveOwner)throw new TypeError(\"cannot preserve owner in archive and also set owner explicitly\");this.uid=e.uid,this.gid=e.gid,this.setOwner=!0}else this.uid=null,this.gid=null,this.setOwner=!1;e.preserveOwner===void 0&&typeof e.uid!=\"number\"?this.preserveOwner=process.getuid&&process.getuid()===0:this.preserveOwner=!!e.preserveOwner,this.processUid=(this.preserveOwner||this.setOwner)&&process.getuid?process.getuid():null,this.processGid=(this.preserveOwner||this.setOwner)&&process.getgid?process.getgid():null,this.forceChown=e.forceChown===!0,this.win32=!!e.win32||Ov,this.newer=!!e.newer,this.keep=!!e.keep,this.noMtime=!!e.noMtime,this.preservePaths=!!e.preservePaths,this.unlink=!!e.unlink,this.cwd=Xl(Jp.resolve(e.cwd||process.cwd())),this.strip=+e.strip||0,this.processUmask=e.noChmod?0:process.umask(),this.umask=typeof e.umask==\"number\"?e.umask:this.processUmask,this.dmode=e.dmode||511&~this.umask,this.fmode=e.fmode||438&~this.umask,this.on(\"entry\",r=>this[Sge](r))}warn(e,r,s={}){return(e===\"TAR_BAD_ARCHIVE\"||e===\"TAR_ABORT\")&&(s.recoverable=!1),super.warn(e,r,s)}[mG](){this[dG]&&this[RT]===0&&(this.emit(\"prefinish\"),this.emit(\"finish\"),this.emit(\"end\"),this.emit(\"close\"))}[kge](e){if(this.strip){let r=Xl(e.path).split(\"/\");if(r.length<this.strip)return!1;if(e.path=r.slice(this.strip).join(\"/\"),e.type===\"Link\"){let s=Xl(e.linkpath).split(\"/\");if(s.length>=this.strip)e.linkpath=s.slice(this.strip).join(\"/\");else return!1}}if(!this.preservePaths){let r=Xl(e.path),s=r.split(\"/\");if(s.includes(\"..\")||Ov&&/^[a-z]:\\.\\.$/i.test(s[0]))return this.warn(\"TAR_ENTRY_ERROR\",\"path contains '..'\",{entry:e,path:r}),!1;let[a,n]=Sot(r);a&&(e.path=n,this.warn(\"TAR_ENTRY_INFO\",`stripping ${a} from absolute path`,{entry:e,path:r}))}if(Jp.isAbsolute(e.path)?e.absolute=Xl(Jp.resolve(e.path)):e.absolute=Xl(Jp.resolve(this.cwd,e.path)),!this.preservePaths&&e.absolute.indexOf(this.cwd+\"/\")!==0&&e.absolute!==this.cwd)return this.warn(\"TAR_ENTRY_ERROR\",\"path escaped extraction target\",{entry:e,path:Xl(e.path),resolvedPath:e.absolute,cwd:this.cwd}),!1;if(e.absolute===this.cwd&&e.type!==\"Directory\"&&e.type!==\"GNUDumpDir\")return!1;if(this.win32){let{root:r}=Jp.win32.parse(e.absolute);e.absolute=r+vge.encode(e.absolute.substr(r.length));let{root:s}=Jp.win32.parse(e.path);e.path=s+vge.encode(e.path.substr(s.length))}return!0}[Sge](e){if(!this[kge](e))return e.resume();switch(Cot.equal(typeof e.absolute,\"string\"),e.type){case\"Directory\":case\"GNUDumpDir\":e.mode&&(e.mode=e.mode|448);case\"File\":case\"OldFile\":case\"ContiguousFile\":case\"Link\":case\"SymbolicLink\":return this[yG](e);case\"CharacterDevice\":case\"BlockDevice\":case\"FIFO\":default:return this[xge](e)}}[Zo](e,r){e.name===\"CwdError\"?this.emit(\"error\",e):(this.warn(\"TAR_ENTRY_ERROR\",e,{entry:r}),this[JI](),r.resume())}[_0](e,r,s){Fge(Xl(e),{uid:this.uid,gid:this.gid,processUid:this.processUid,processGid:this.processGid,umask:this.processUmask,preserve:this.preservePaths,unlink:this.unlink,cache:this.dirCache,cwd:this.cwd,mode:r,noChmod:this.noChmod},s)}[Rv](e){return this.forceChown||this.preserveOwner&&(typeof e.uid==\"number\"&&e.uid!==this.processUid||typeof e.gid==\"number\"&&e.gid!==this.processGid)||typeof this.uid==\"number\"&&this.uid!==this.processUid||typeof this.gid==\"number\"&&this.gid!==this.processGid}[Tv](e){return Rge(this.uid,e.uid,this.processUid)}[Fv](e){return Rge(this.gid,e.gid,this.processGid)}[IG](e,r){let s=e.mode&4095||this.fmode,a=new Bot.WriteStream(e.absolute,{flags:Oge(e.size),mode:s,autoClose:!1});a.on(\"error\",p=>{a.fd&&Mn.close(a.fd,()=>{}),a.write=()=>!0,this[Zo](p,e),r()});let n=1,c=p=>{if(p){a.fd&&Mn.close(a.fd,()=>{}),this[Zo](p,e),r();return}--n===0&&Mn.close(a.fd,h=>{h?this[Zo](h,e):this[JI](),r()})};a.on(\"finish\",p=>{let h=e.absolute,E=a.fd;if(e.mtime&&!this.noMtime){n++;let C=e.atime||new Date,S=e.mtime;Mn.futimes(E,C,S,b=>b?Mn.utimes(h,C,S,I=>c(I&&b)):c())}if(this[Rv](e)){n++;let C=this[Tv](e),S=this[Fv](e);Mn.fchown(E,C,S,b=>b?Mn.chown(h,C,S,I=>c(I&&b)):c())}c()});let f=this.transform&&this.transform(e)||e;f!==e&&(f.on(\"error\",p=>{this[Zo](p,e),r()}),e.pipe(f)),f.pipe(a)}[CG](e,r){let s=e.mode&4095||this.dmode;this[_0](e.absolute,s,a=>{if(a){this[Zo](a,e),r();return}let n=1,c=f=>{--n===0&&(r(),this[JI](),e.resume())};e.mtime&&!this.noMtime&&(n++,Mn.utimes(e.absolute,e.atime||new Date,e.mtime,c)),this[Rv](e)&&(n++,Mn.chown(e.absolute,this[Tv](e),this[Fv](e),c)),c()})}[xge](e){e.unsupported=!0,this.warn(\"TAR_ENTRY_UNSUPPORTED\",`unsupported entry type: ${e.type}`,{entry:e}),e.resume()}[Pge](e,r){this[NT](e,e.linkpath,\"symlink\",r)}[bge](e,r){let s=Xl(Jp.resolve(this.cwd,e.linkpath));this[NT](e,s,\"link\",r)}[Qge](){this[RT]++}[JI](){this[RT]--,this[mG]()}[wG](e){this[JI](),e.resume()}[EG](e,r){return e.type===\"File\"&&!this.unlink&&r.isFile()&&r.nlink<=1&&!Ov}[yG](e){this[Qge]();let r=[e.path];e.linkpath&&r.push(e.linkpath),this.reservations.reserve(r,s=>this[Dge](e,s))}[FT](e){e.type===\"SymbolicLink\"?Rot(this.dirCache):e.type!==\"Directory\"&&Qot(this.dirCache,e.absolute)}[Dge](e,r){this[FT](e);let s=f=>{this[FT](e),r(f)},a=()=>{this[_0](this.cwd,this.dmode,f=>{if(f){this[Zo](f,e),s();return}this[Nv]=!0,n()})},n=()=>{if(e.absolute!==this.cwd){let f=Xl(Jp.dirname(e.absolute));if(f!==this.cwd)return this[_0](f,this.dmode,p=>{if(p){this[Zo](p,e),s();return}c()})}c()},c=()=>{Mn.lstat(e.absolute,(f,p)=>{if(p&&(this.keep||this.newer&&p.mtime>e.mtime)){this[wG](e),s();return}if(f||this[EG](e,p))return this[Hc](null,e,s);if(p.isDirectory()){if(e.type===\"Directory\"){let h=!this.noChmod&&e.mode&&(p.mode&4095)!==e.mode,E=C=>this[Hc](C,e,s);return h?Mn.chmod(e.absolute,e.mode,E):E()}if(e.absolute!==this.cwd)return Mn.rmdir(e.absolute,h=>this[Hc](h,e,s))}if(e.absolute===this.cwd)return this[Hc](null,e,s);xot(e.absolute,h=>this[Hc](h,e,s))})};this[Nv]?n():a()}[Hc](e,r,s){if(e){this[Zo](e,r),s();return}switch(r.type){case\"File\":case\"OldFile\":case\"ContiguousFile\":return this[IG](r,s);case\"Link\":return this[bge](r,s);case\"SymbolicLink\":return this[Pge](r,s);case\"Directory\":case\"GNUDumpDir\":return this[CG](r,s)}}[NT](e,r,s,a){Mn[s](r,e.absolute,n=>{n?this[Zo](n,e):(this[JI](),e.resume()),a()})}},TT=t=>{try{return[null,t()]}catch(e){return[e,null]}},BG=class extends Lv{[Hc](e,r){return super[Hc](e,r,()=>{})}[yG](e){if(this[FT](e),!this[Nv]){let n=this[_0](this.cwd,this.dmode);if(n)return this[Zo](n,e);this[Nv]=!0}if(e.absolute!==this.cwd){let n=Xl(Jp.dirname(e.absolute));if(n!==this.cwd){let c=this[_0](n,this.dmode);if(c)return this[Zo](c,e)}}let[r,s]=TT(()=>Mn.lstatSync(e.absolute));if(s&&(this.keep||this.newer&&s.mtime>e.mtime))return this[wG](e);if(r||this[EG](e,s))return this[Hc](null,e);if(s.isDirectory()){if(e.type===\"Directory\"){let c=!this.noChmod&&e.mode&&(s.mode&4095)!==e.mode,[f]=c?TT(()=>{Mn.chmodSync(e.absolute,e.mode)}):[];return this[Hc](f,e)}let[n]=TT(()=>Mn.rmdirSync(e.absolute));this[Hc](n,e)}let[a]=e.absolute===this.cwd?[]:TT(()=>kot(e.absolute));this[Hc](a,e)}[IG](e,r){let s=e.mode&4095||this.fmode,a=f=>{let p;try{Mn.closeSync(n)}catch(h){p=h}(f||p)&&this[Zo](f||p,e),r()},n;try{n=Mn.openSync(e.absolute,Oge(e.size),s)}catch(f){return a(f)}let c=this.transform&&this.transform(e)||e;c!==e&&(c.on(\"error\",f=>this[Zo](f,e)),e.pipe(c)),c.on(\"data\",f=>{try{Mn.writeSync(n,f,0,f.length)}catch(p){a(p)}}),c.on(\"end\",f=>{let p=null;if(e.mtime&&!this.noMtime){let h=e.atime||new Date,E=e.mtime;try{Mn.futimesSync(n,h,E)}catch(C){try{Mn.utimesSync(e.absolute,h,E)}catch{p=C}}}if(this[Rv](e)){let h=this[Tv](e),E=this[Fv](e);try{Mn.fchownSync(n,h,E)}catch(C){try{Mn.chownSync(e.absolute,h,E)}catch{p=p||C}}}a(p)})}[CG](e,r){let s=e.mode&4095||this.dmode,a=this[_0](e.absolute,s);if(a){this[Zo](a,e),r();return}if(e.mtime&&!this.noMtime)try{Mn.utimesSync(e.absolute,e.atime||new Date,e.mtime)}catch{}if(this[Rv](e))try{Mn.chownSync(e.absolute,this[Tv](e),this[Fv](e))}catch{}r(),e.resume()}[_0](e,r){try{return Fge.sync(Xl(e),{uid:this.uid,gid:this.gid,processUid:this.processUid,processGid:this.processGid,umask:this.processUmask,preserve:this.preservePaths,unlink:this.unlink,cache:this.dirCache,cwd:this.cwd,mode:r})}catch(s){return s}}[NT](e,r,s,a){try{Mn[s+\"Sync\"](r,e.absolute),a(),e.resume()}catch(n){return this[Zo](n,e)}}};Lv.Sync=BG;Lge.exports=Lv});var jge=_((x3t,Hge)=>{\"use strict\";var Tot=DI(),OT=vG(),Uge=Ie(\"fs\"),_ge=GI(),Mge=Ie(\"path\"),SG=FI();Hge.exports=(t,e,r)=>{typeof t==\"function\"?(r=t,e=null,t={}):Array.isArray(t)&&(e=t,t={}),typeof e==\"function\"&&(r=e,e=null),e?e=Array.from(e):e=[];let s=Tot(t);if(s.sync&&typeof r==\"function\")throw new TypeError(\"callback not supported for sync tar functions\");if(!s.file&&typeof r==\"function\")throw new TypeError(\"callback only supported with file option\");return e.length&&Fot(s,e),s.file&&s.sync?Not(s):s.file?Oot(s,r):s.sync?Lot(s):Mot(s)};var Fot=(t,e)=>{let r=new Map(e.map(n=>[SG(n),!0])),s=t.filter,a=(n,c)=>{let f=c||Mge.parse(n).root||\".\",p=n===f?!1:r.has(n)?r.get(n):a(Mge.dirname(n),f);return r.set(n,p),p};t.filter=s?(n,c)=>s(n,c)&&a(SG(n)):n=>a(SG(n))},Not=t=>{let e=new OT.Sync(t),r=t.file,s=Uge.statSync(r),a=t.maxReadSize||16*1024*1024;new _ge.ReadStreamSync(r,{readSize:a,size:s.size}).pipe(e)},Oot=(t,e)=>{let r=new OT(t),s=t.maxReadSize||16*1024*1024,a=t.file,n=new Promise((c,f)=>{r.on(\"error\",f),r.on(\"close\",c),Uge.stat(a,(p,h)=>{if(p)f(p);else{let E=new _ge.ReadStream(a,{readSize:s,size:h.size});E.on(\"error\",f),E.pipe(r)}})});return e?n.then(e,e):n},Lot=t=>new OT.Sync(t),Mot=t=>new OT(t)});var Gge=_(bs=>{\"use strict\";bs.c=bs.create=v0e();bs.r=bs.replace=oG();bs.t=bs.list=vT();bs.u=bs.update=T0e();bs.x=bs.extract=jge();bs.Pack=cT();bs.Unpack=vG();bs.Parse=BT();bs.ReadEntry=YR();bs.WriteEntry=N6();bs.Header=TI();bs.Pax=JR();bs.types=m6()});var DG,qge,H0,Mv,Uv,Wge=Ze(()=>{DG=ut(Ld()),qge=Ie(\"worker_threads\"),H0=Symbol(\"kTaskInfo\"),Mv=class{constructor(e,r){this.fn=e;this.limit=(0,DG.default)(r.poolSize)}run(e){return this.limit(()=>this.fn(e))}},Uv=class{constructor(e,r){this.source=e;this.workers=[];this.limit=(0,DG.default)(r.poolSize),this.cleanupInterval=setInterval(()=>{if(this.limit.pendingCount===0&&this.limit.activeCount===0){let s=this.workers.pop();s?s.terminate():clearInterval(this.cleanupInterval)}},5e3).unref()}createWorker(){this.cleanupInterval.refresh();let e=new qge.Worker(this.source,{eval:!0,execArgv:[...process.execArgv,\"--unhandled-rejections=strict\"]});return e.on(\"message\",r=>{if(!e[H0])throw new Error(\"Assertion failed: Worker sent a result without having a task assigned\");e[H0].resolve(r),e[H0]=null,e.unref(),this.workers.push(e)}),e.on(\"error\",r=>{e[H0]?.reject(r),e[H0]=null}),e.on(\"exit\",r=>{r!==0&&e[H0]?.reject(new Error(`Worker exited with code ${r}`)),e[H0]=null}),e}run(e){return this.limit(()=>{let r=this.workers.pop()??this.createWorker();return r.ref(),new Promise((s,a)=>{r[H0]={resolve:s,reject:a},r.postMessage(e)})})}}});var Vge=_((T3t,Yge)=>{var PG;Yge.exports.getContent=()=>(typeof PG>\"u\"&&(PG=Ie(\"zlib\").brotliDecompressSync(Buffer.from(\"W2xFdgBPZrjSneDvVbLecg9fIhuy4cX6GuF9CJQpmu4RdNt2tSIi3YZAPJzO1Ju/O0dV1bTkYsgCLThVdbatry9HdhTU1geV2ROjsMltUFBZJKzSZoSLXaDMA7MJtfXUZJlq3aQXKbUKncLmJdo5ByJUTvhIXveNwEBNvBd2oxvnpn4bPkVdGHlvHIlNFxsdCpFJELoRwnbMYlM4po2Z06KXwCi1p2pjs9id3NE2aovZB2yHbSj773jMlfchfy8YwvdDUZ/vn38/MrcgKXdhPVyCRIJINOTc+nvG10A05G5fDWBJlRYRLcZ2SJ9KXzV9P+t4bZ/4ta/XzPq/ny+h1gFHGaDHLBUStJHA1I6ePGRc71wTQyYfc9XD5lW9lkNwtRR9fQNnHnpZTidToeBJ1Jm1RF0pyQsV2LW+fcW218zX0zX/IxA45ZhdTxJH79h9EQSUiPkborYYSHZWctm7f//rd+ZPtVfMU6BpdkJgCVQmfvqm+fVbEgYxqmR7xsfeTPDsKih7u8clJ/eEIKB1UIl7ilvT1LKqXzCI9eUZcoOKhSFnla7zhX1BzrDkzGO57PXtznEtQ5DI6RoVcQbKVsRC1v/6verXL2YYcm90hZP2vehoS2TLcW3ZHklOOlVVgmElU0lA2ZUfMcB//6lpq63QR6LxhEs0eyZXsfAPJnM1aQnRmWpTsunAngg8P3/llEf/LfOOuZqsQdCgcRCUxFQtq9rYCAxxd6DQ1POB53uacqH73VQR/fjG1vHQQUpr8fjmM+CgUANS0Y0wBrINE3e/ZGGx+Xz4MEVr7XN2s8kFODQXAtIf2roXIqLa9ogq2qqyBS5z7CeYnNVZchZhFsDSTev96F0FZpBgFPCIpvrj8NtZ6eMDCElwZ9JHVxBmuu6Hpnl4+nDr+/x4u6vOw5XfU7e701UkJJXQQvzDoBWIBB0ce3RguzkawgT8AMPzlHgdDw5idYnj+5NJM9XBL7HSG0M/wsbK7v5iUUOt5+PuLthWduVnVU8PNAbsQUGJ/JPlTUOUBMvIGWn96Efznz4/dnfvRE2e+TxVXd0UA2iBjTJ/E+ZaENTxhknQ/K5h3/EKWn6Wo8yMRhKZla5AvalupPqw5Kso3q/5ebzuH7bEI/DiYAraB7m1PH5xtjTj/2+m9u366oab8TLrfeSCpGGktTbc8Adh1zXvEuWaaAeyuwEMAYLUgJQ4BCGNce++V01VVUOaBsDZA0DaORiOMSZa+fUuC5wNNwyMTcL9/3vTrLb3/R8IBAgmBTJZEqgsk1WebctvO2CkSqmMPX3Uzq16sRHevfe/k/+990OK/yPQiv8j0EJEAEeIAHkKEQCrCYD5fwBkBUBmDpiZVYOkpDqUqTOUqTkse7KqfRKkZpSZ0jmVmVKbVHvVGONSY6xdOXf2bfxYs+r97Gaz7/VidrNczmo5i+X4/79WaRtnVo6UQAk7u1v/33o7HGQdPSpQj/7rqqYgCstG5MTLOF+dsIv//2aWtasTQFXXSGVKy0Ch0FwtLAv5xL+sjMzIJeSZkqQ+090j9RMRiYjIRDMBVHEBdLMPuzhK9ArtKWmta6w91npmkeMIbXl7nz+t0qqu7mqNZH8NgWcOML8gqf5fsvkoWoqCW/Uv9a31Jb231iAdAFq2b0f2AXJIgEFCSX5xeJctKHDjpJQ3m3Urk0iC5/t7U/875277i6mGdxYoptsKpVKptp46HgxpRCOeWYxBRAIkEfH8P2f4vnxABfSq3okFhW7Sh7EOU6Zknm9b/2dQZl1CfrShJVuQKkmDUKRlwEAYpohyd7/uuRO4vjhiW92oa7DifsWphJQsLIonVqN9+X6G95E9gJv1/aVCu6Vysu/NbAvVQJAIkgSLIIEgCcE1iBZvi3Talbv/B95N+2tvY1Qof7OKQVArLUEjJSQhhBgSgWJaCGz+exJ5As24WxMMguChXfbB3r3z09qdsMUgWww4SIpBUgwSMGCKKVKkSDFoiimmuGKFLRY8P+/j/1z/z8vcC0/38z9ixBEjRoTHiLRERESEEhFKHk1poFts2iWWWCLiyP783Pr/f3p9jjDzv+KKLbZo0QLRAoEgGQSZIMgEgSCZEogSJUqUWJmUwG/uv3/60+facZ/fES1atGixxRZhCENEGEpElAhMifCIiMh7RNRARD0osUTmQzS53d7gIWweY/AMx+gtFBHZ+QKBsEAgEAiEnXyTePKGdLaKJm1heyFaU3uzbTmJnADDv5s+/2iBsQLt8213mBZIEC+iwULwYIFUkDqt7977a5EjE/PA5Kn3lAZJ2jN6FtU6hpJswxeRU8EDzmheRavGU+8SAXcv9hs2VHFHpGFd2uSqhHfl+2vjalI8eXtMfadrWGGNgIrP+vNSPghBQhnaYRowg/SWg6qitd+w5dduV3M/w+v7ZmNa2EHT7PCw7b26WSDoIaI+BqiP5p2zrxStV+M2GSTNwLZe7+NuQ2yBmwrOzjTUkFHwTV/eBa16T3gA4/213h/1KeX+30V2dZfwJfquaEB6xymhDz3/VMrY5GD9qnZSnAOdHwOrSiaW52B2t2N16zP70evD5mkQyIw0SkzGfUSC0v6MnmPjA/zDgnWuNgwjo7uqtquP5iVWyxtfYeRFHYCX8Ri+J5QLlWqdxq/rU5NcBfWU0gwJLQozOPn8AKW8O8tlag5jTBhcLinjQ3x+ROz+sC1XeAEFjsiL/RBz5ZaHIRt1Zbw7BI/oqy9GqIvPir/AVOOYmyvYsW4S+OjA6lAao99TaXVi1/zOSY7OsRX/YRjJGmdyzupZMt8/DVsorPED2dvEHJaq3K/NE3bKc+Ilrb/azbMvPOIR2+6+xdd8ma/RzeYh23z26tLr9RU6lUdspWd2NAZvk1KsuWtCCp0djmdRFF8HywmTO5KH5Q7JmWezwwKTluDzWDDEEErDdtCCr0a3/GLiI1+HFJKGSB6KtqRHbbS4nsotDPyRz6MFVsQZEL/84gHTA3INdbmG+IoQeUnuY9jGbwRzWSQPASvKFzPQ8sMX+Ty0xAooDSUYEg2rB2Asi8sg++mGqyPPdcZaQiV7O4lZKh/GtbLxz6f2bTsRiLCS7YyUlJjXyQfUAqv97xnph6+1be14kuOkiiW9yBJa3qGJc/jQpCNb/vnTbiO8xEL8sWjHbz2Bnbw/6u0defDAf0FGLaQbLe/+iCD19fZdW4gLDjOLrMbQ2T9vzdtlMqbVl3aCRT/5cB8G8CCpn5B9Lf3jpPZHybpehwzVihnKVbsZkH26pXEqhZl3TmBX61DuBRGWyjOcuBvMT14I2t2ppPMw9ZDpZixooFP9mAgeVVq/i0VyO1POaBTOdukyymNgYmnefdg99y0VvJTipQXLHiIB+GYJk6iLBUtXC5Eut2DpuKRTvuBkW3pv6b3l9xr3/tvyL7GOfiZJ5G+M1aBLJ8TSrpD/ib7xQ9H4b9AfOQ/uEcDmZB6cL2xC41vkwfpiTmh85keSHMtuqSwHp3CQjy0hCN4mosrShflH0n4J1MoTLAROsfy6R7DbEVIUplDwMc4bwsJzphym5GmaVt3+FVff00PZlpU7E5+eHCn5OBo5v0P3QHYrsHNk0PZ7klsowDlcZtJdJgvEbmwvROEM44XY0SuLhahpubgq3SzjsieuutCgAA3qM4rw/MfmzN6HiA++fyU4Rojl44Jb3lXXiQdVSyENix+uraEeD7BibuDCZyFx7aSSW3MA55ymmgAwipqWKus8ykE9HSnJ7CAcn4q4rnO13Ll54POTEjqOxF+FpSAggq+iW01ABNH0JIpBemwUz1pq6GW5MeY0mCE5NtDFSzPrukTra4iNQgyYuZRHSsz72UwNvCA042mO1PKJUG7b896RNyXM88mIr7W1lyhCT8uigfq1LwQ1zXpPQsUrUocxVC+No06fCYUsGWWUjl0/D4tExtJmp4w1SYeaLpnQJ7CNbVODe+nUys2PIKLyxnBq0kHPfRWcq+THl5c2JS2fQeZBVxYtIn74wmnVXuTeFKjE4apGeJAQWnr5Jum5VD/KXuOoyZRPRtrgkZfqvDIhmlbcO6TcjEIhK7mkfR/ad7WeqFjihp7L40OITvp037LNCGX/L6y51MCmkxcpjKCpzBA0noqXTJW2WtDBHUAiBTBi4eBW4rLSC2L+o208CmJ/sxGolgvDgv6hwNsfmxveCnGodx1iKVgEsUO1vE1JKVnT4SgRTO2dgh9K+H599CAmLZE8YvfNp3nhge3MhwAfna99yEZihxv/XwtnAneD0/eEOhyhBTIjd37wBrwuGTKcNBm0/Mx8mIj73As7n47h25bDP3X6UH6TyhtoUa+4M/rKf5ClWLs9Y21CYGxQE809XrP2Jk3orKEJ6hOiL28/33rVJeS5dVpluNegSJcPZfWrG3wDPe1BG6B5cHPnHbNBlhNozcJdZMyFTFG7UPzgl+oUCXRn+ISQ1WnXACLe4kbKtvvthKJhtUPPc2w70asPUj6hAjfITl0GnlA+vRox2VZA9LnskDs68Tk16hXuKd1zfFgC7b6qnLKaoEVXr+2g/BhWXIgw+GVBoqgnDnVuAp2qiUC6qOG4x6GNRVF5WUi7Odw/iUrK/gQUFTBttWGE+ceQumw2t+2dqUrzOrsHSaolipYpBpeLVPvA+1LureB631Tl56A1Wd0ryu96SzibapY3Nz1TXxbMfhInq7WkbUrgGfVaH2vd/tsicD5w5CYV+eISjPH/omyb0wzec5XMokuSw+38AZ2b9rNMawsYSIHvehmbPWUWUuFHVW7var3Am1LM8YFd+G9VDZuKFOvxqm68LDL8bNbjxFevGsFlTyXE1FAbwNZcd6k29dl6ub5BZ6V/O5cTFBmJtgRrraPr7PoqJUnMj6QIpMIodZLDE57k2i6TROku8ZdH3m6Y1vYJFSWTeioWMDaeNqyKHeN8tlp4nDWkSQxHMqbaON4f71KnQF1IwiOkHHPCMrVw/D5W089eWX3/j60UkkuvoRPJTsumkpFd6wW09GwYBwLMgvEZcBgHED3tGu6bESdiXTBcD8W+EIsfaJeutJZ5THXopIx6YVJDbcsMGmYsZtIXb8bsVjewXzc88FcTZ5lYYoFhIrBcO6ljLt5+dp5HmzXv1Kg2MwCJDrRr7qVlXdraGTP828XfilNRkEJ1GwtTE3I1t/aITjVWiTHgXNljdnMXh5wdZpZcKzszsONMKEJhMh0NK+bDGn+rAJDC3mgiOZxq1OUUXNsxkQWhYW1GFtRiWFZNcNDeLLlIQll0jLYPjE2ynxKXI4lcBwCNsxFW85dwAN0PW2KmOMcI6cTvka8d0LYiqm5TNUQfQJPIoralnyMJ4bt6oiIaYBwZu+k4MkkXTQfL1e90rIWXSgjgUBMgCXkoTn9Rr9HCuegYSj1NaIXnzEQUfbtnz7/FkaUwrNSQpHIL+Jj0VvXs5zg6Gn4hCOMevrvMmTvdBdt6DOzxoF88Zp3bG+juT/Zl9hHsXlZY/IeRVTezaepfT0+FNz8u+rCFX+1LykI9/PPmJIfH8/IRAejJVADY7rGj+r8PWPt4mhxDEd6+n9rB/NPcTe2dTs3pXtOjtNyFndrtwLPSz6s+d+vOkWnztCqcbmMfyfd0LcFRcVF8kjkoWIncdj9IKIfZhh+PP+DeY7TVAGAK++IgvZUF6PTLIJT9EhxpprSPCoWuxThGwP8vmEbDs6kDehX0zWXz47U9+/Hqajad+simdjof8lRabLnIvfxoaVOQL907ZBofU7FPER91ifRhlz9nXfSHyGA+c9sQnfOh/SDUqx+vRyM4oJLJXEyfaISzIFoC6MDWR2JB9vBLhhchIiznCQbr7n4zxaEcvphNcZfivwbIKk4C7kb+IcPA8u66nd2Gb/vUiilkp7G6ydQXj82jFjlebJ0yyezuSSbikTcg/iPlGxcWL0JnPmnSbXtHfKBGopIcI3lir17wt8hz8Tw0UHbloVh1oDnNdFBZVkteweiH42CzircC5ZTif9eeYhieGEnmUuVH7ai/JO7HRhjYEPIibvKkVqM3z0jfZE3TOv0ECUC8NkRhCWEHvAOZQ2Di9cpB1UFmdoTca81BmGHQHV52E9WYKITgpIkjtau2nj2g+/51uj2O1NqXpe7/et2u+ywiRJcxClnpB8zPWr8KpuDNG1On7P5XzL7w4LaThoWCyw51tg67gUiQxAvac5QMfVAg7A9hcPddIYKqXNqHKVTRL1cI18UOJxu71LHOStvahBLKaojwKBgRA37Txbt+RZS2SV8fnhjPK3JtIrQYXS/KbLS+FL65SGQrNoZCPoQ3jPPJ5oGmhVQ7p1HPtUJWZUSK9u52UhHSn7Fz4LaB7f232yKKRJk07LL/FidQB0163aXVWAUV+9Uo0KWhJRPowfH1uqYdJztTXYWif3SQ2veJvBWruwtw9FsVjhQC7panWsvhWmb/auexdM60b7dpZ6YWOyOJa0qT+G9zC+cUTlJul16NOjStrdI5+HmW42OyTZigq9e6wSExmEs9irgKnyuV2XcQjptcAhXGxzo0uId2qEuEZLPpPSpkxKQDdnY2nESOYlFBYmNWyWgXWU1cgMEOrISgwBaXV58jMLxLhTFsomEXb26Cnyiq2J2giU9Fm2absgPt4Rbymjjkcd7KgXAtHaXNVLic47oHHBk8ARny/M5iBziv+H09TI7cjX/4l1dt0YkbjOG67cwvyDnwimukP5zYBXBFF7hxXAov2L5b2RfPdccCG3yiboYvK/mEAdstGcwwoUpM2weBoiRPCYEpRZxbEcXZdI3lGC5+PAl0a9AOvplhycISXApYj/Cb6zYy1K01G+osg1+ehGE0m/zhJpyLJ7Z57DmuoP90ZNkReZoycA3m5rCOFZTV8N6IbLjf5BqGMUl4znKQZT8ehgTTt5IvwXbnJLz/7W2WXCWlXpiwfXydTi/zOvfh/iZZU5gT/fCx3nc4PpiXjU8MdqGAs84cdBbTDHTs/YbHBvUVFzcLVURv20/zNCLGxwIchrqFeEBiuug3jSpTTTU7nE2FRDhL0LYczn6cZASeq3qNqi1zQVYub8kofKMm6437UYd5b3/SO7CKivw4FWFPLCLc4Z8CBcULyQE9K8kclUkMZwxwWqSVYIrnqhl3jFaMYj9xzk4XxZQBOZeTHSYKTGcyN0fb56s9a6UvmqOL8RLP5maDP0skmaEs2VciXWCWkS8gbAyh6gHDIsnXCmDhDERh10JM1UdBGKpt3XYeJrw/+Ox5PFGyCLErC+uRMXw76JlFhorQtT6lEItxakSkm2joAbmHfVOulpr1LyuY5qrCVm7ZV8y6SBu2UYc1R9GKlgLZ0FCB7GyxzUfoiunzAJUkS4CwDLnKYZlJE5rs6JF008a55Dco1ZmpojV5KSQyO3RGmuIu6MJqCkKcv/VWPC5Cmzr77J8L2amlHANFA8v4MLWPFTxCuY9+llLIkHb9KqC6drvO76U/HhzYd4TCrtX3hIMtbCl4wpA/crGvRH0eb0k3lkNxfNADxb3kdLBtYQIKSVtpVDXnukN6/Jdmoy9bYx2lx/ziK38opmSgnSmwC8vM2i8fKZ8MSMatN+ll9Va3rQptqQeOiUWdB5P8j67+kp4MWQFGUJgq/jA2SU0WLYbL3FznrYOcZUA2pFzq8l+c26QbiCbAl8Ch0La9zRiLDPy2srfCpXRVcMOatjv3XJEqv6lQBhL4ygI3GKN8DSMNoacSezvDfw84MD+EGYUFiyxXhVwAcjhmct3ea/nmTEyFPJL03efr5cMR1jXApiV6KATnd6csvUBQIDUUE/gF87lpIhcASzc3FNkongQzQBhyilusxM5JCHhq1vsAHUSGlgfPu3T1LMf8fUvu+nWo1UBLM6eduqghd2CF8y4g+jxwScriC7to9zCH1oCqa+AO4eXSC2V6Ayu3vW127r3ABmlmG7suJd51EhqnAydEaetoL5Z+Ih9DtWAiYG1DSpjkcYPAD5smccfdVDpabrJdAdk1Bwhk2f/0XFt+gZ89z9cWBxBadW17CYPkcnfxboTMe+1Gm9uLOdI72/ZEW8/y0dSUqGtJdXZHqbBgpaZqxg9gdyvqrqrbu6pWaCOvqGZ9bS2aNQDDcttEfa7PXefhfw+AEl08ngtUlua0VZbiX43A5T84leaUEbC5JWu0ClotsUtMv9U9Ma8XonMcneCouY74ROyoXJb2qJ3JxdQ0t2Q4GJsnrM6NKuEQsucEeknJx9Kow/RNlZAi5gmhVfd9kZGBWxrcGjGGclP8Dlyf/begmrKtRtKZ5yBT8yKmq5BbFMBNJ3ipr7VHfJAIAEVxbHyfCVVxhN4Ea+KJOX1kmZaTU/zPKeIuHT9RFhcximF6rOEch4CCeVy0QojIiYrbkxQjbaoz5+dTT2lV8Rvem+gxY85I+O944aZIxHzaH3mJ0YT77dfahgwJEN+Ecac7wiCCIbmkaWV98mdvPxjT8bb5DRzhJR3z2dolyrlyaNktNUvWxPOjxcke/OgOG/FwhyIXgS9DOAEITNdNLXNtuKDHc8plFH43V4UF92UVd917U4OC+UYmM9htdQeQb5I/FQp+3cw6YsWkTBNupvHaX4FOeZk90YqUGUsSz1gWzC1geFSSiYQeEdS0CY6LXPM4KVsvR61UCB4pu70JHkvpAE4e0B7PIba/7aQvUbAr9ZlScVQ3ZXzHatAGkBg+fO4eawSGac8km+CpXbCs+fb7FJ8xW/0Fy3TDoZwOwb6pW+BIv8uCG5EDbNrUSRJ/WUcQn4nnt35rFYyt6GLoroOfLw+6Gcj0pO2fsa+AtutLPb9/jmtx+rXd6t3Ls22SglWOFNbJHGG8r7Q9xIThX+tITsfORZ/N/tf/jGqe2ikQDYq2celmNH7OnXLzSvuO9YNSrDOoTSTs3LlGKochkEZlMW/XAAMt7Yp/jbjIlVq2TSg8sewqPiwvBC23Zm/dTcmPDerVVzsUQcHhB+nzht1kaCTCdTNhdvoWKwvYZ4oSsaqOGGcbb5Fl+rid+q6arHmMR20GI6+uWKihVOIb707/PrT1cPyirhOh3NZKdbTbl0cuJuRSqmEV3BOkAGkr3zd0DUr+L5QTewxGAetWpDipU3AdliEJHg0sdyYLdHyNYQueZGb6g0jlOWQQ5J5v3aM199JVy3Uf/1Ge3bkUt13caf0uBvT8mPeOg705fTxlxlV8YqKpH3Ky0eqPaZDkVLcckyXL+x/Se8g56COoCA+vP5ov6o+Gq0F+INLDEJbG6H7QTc1uS8BzgI5xdRrVjdzNfNl7xrtUcdNhwEyTmciqsCw9t2xIe+RMCZTaG6rH0HSa8IzUrSafJqsbmtZwLNfIT+ipGbS6EDg/AOjP2S0Q7NpnkskF6On9uZfJBNMc/vRuPPO+CgdQfjClqSgsCSMKIdCVJSvc5lo7XijOtAu1+cAnisoJqanxLtNhMiZquTYxAg0RznpnCrQ1N8m5SKv/9Ka54quCMo1bPbNcYTa/iO3IWD+FCky5gplE7yvElfoQPOiy3GB0tsPgZH0HbIeEcx5cI6QO00aSWe8+aiLcg8lMxFwL5rRyH2XFwnT+ZpIDbUYiKNB/G0P3n75pLoHkRmfle8JmO5BO2juC2oc1qe6HJ/TC45AjhJ6czzOtLg0Q99Zri3cs+gIfZMwKN+ZARqPe540Aj0bGZso2NHB1O1t5/RkeDdikWUxkEFPKEMbII7WtZuIc1sFeyNo0fo+No1AljZ40n68sAS64VLmvZ4P5++PAqbMkRjyKYh3PXfxynQI1lAg/kz1Ky+RNG2hK0Lu+tIqLD7o9+gSk4ACGxLoKeLU1+YaI1HXJtoNRuw1pMGcuWfZTpIvUyIatl1l45Elm6xNdbDS02RGC7HxTMmZULCwdGyYXsYp4/RJgdqBWINVf7FKIaio4QYm6H5aZIpV+2XsVIn2ATFIBBq739vS8O10e1CI9Zros+/6UQ2nmCDXg6z3adf3sV9bEp8t+e7piPl0Vn6K+O0ZwZDjsWLVv1mgXeNI1bBh6kk8iojUn7nRitqTJ7o+xfs6NZTQfilDoypCeK/kaNg0+yScxuUa3HXBSpNCIkv8gbspwrErL08UpBDJieyBraCuOA1hAPfmkPFJZ9wWq4uR4fB3I6YYRqJERQ5cGX7At+5Np41bUzSNyjseRMm+HeG/Y4AOTh4sFQ6eZrtDMr6g0N5x4Qj/WEqGJ53g3lPIgwX/BjbkvAN63C4acLsxgdIE6mJCCXUZhvDTnr7Nxa6EAYH4AlflhCVNGE6TM10ypmFEoUVr30VFr5dMlvj1dIZ+iXWpUQpswhGTZ0rUdIE1uAB2ho3IZCUkoAETlgWTYTpeHTq+R59HnIeee8yLnEKghPA6gPynJCqv9EmBxl5DHixNZwGIC+ISIP596tmySz1lKWOfJSzCNvSCsphu1WSjnZ5BhOFZrKuj4Q5BJTEAqjd5FcdDoy7EPgtGmeNT6dAtdPT5oKKNBnrUNt1bmp3X8dGpblRXKqVL6+ReHnjdSY3QaLY1HU/FmqVXaPTFvxYHJxUlqTNMfb/OJaIMHrSXQ6d5QHmVpnSy8xGXfAcd6FdokA1MKAzBqB+j85xb7scozV4FTownJXNbX9hsG6i8VjLYfYfFVwvqdoWg8d49fazKaITx5BOo3bIcHKBdMaTC3DrBju3cwmjGERPEz67R4I+AEDzJIO3z0q/ZjUo9uI6WejbnyrEJp+V/2TkToGvLmdDxPqLdErgttfHueQZ4wRk42tDr1WI8ZUpkTvHvSi0wss9WMPTuTccFYOp7Vc+65+JKgOZUryMKe4H6cmOM0m3GsQxeaOPGNKY9TnaotMkhqAptsqyevZ4uGBuo0ZWacIsUxWpCQz+DT7IwKbQRnd1CSfDDOh1mmV0VZj9xygoOSlrf3TxLf8QylmirPfJRzz0bzs5Rn15+jMml2WhWeddU8AM4eATCKiVf/80RzQzE/HS7HcZBCA7w7y8fl0m+8fuf2BIEPdXRYvXUac2yxwkuOKA77mLoxfFbWKQndw7U8GDJShjJxBIgNBGN+UU14ox0YgJ+IM7vYX5ObmNF8NKUC4CN00gHk+OEuqpI3rCNei6d1kR6KzxyHsQ2bruIRx1VHoFq+zW9Ig0WemXUnkWLSlgPd0Dm+ARifyFS0uujurMDt1a8HpqbYz911nQb4TwHyRqdLsFgm3PLoUmOnDL4udj7Z/97w1eaPfyMtBP0ewBq4l/Xnypqpl4el6OnUYFt4SecDUJjh5B0Hg3uQayutsdsj6iRMwO2hMuVSyPagTWUEh5No3x8CE/QRkQHzxmWErQwksxqj7aIQyRA0obK2FRuX67Fs04IxIWOrytjmMZpyMlZdOQowSjQ2jstNQt9dyGFTjTwsdzQsyj4OQ1SOojVrNBLDUtOyjB36Q88MyXlKDihQT1mhoAElDZhpRAJ1KJkLj2EwzWYaI+3SN/5dVpV5LZftFyzcztT2sLCjuGuAKPgaNxY7Nc2bn2UgA3xIlzlUPE0x5wMiNMa7b4KpKq1kS2RcZXz1l0RJajkZzj5iiSqvqYNE0wvIytCMEQBK8fuOzqNBwV/CBCcfhfuwuq64o6mT4miwYCeoAblNBALa6rhaPPQTiijH4KaYg2bD9IUkWwtoDFhpw2/q+paPxEU3jCQGs/LnZKbNxJoqZecAyVC18y6st4me59Qnfco59MewM7GFrp8eZChAKRvXk1tLx+HFdBacQZHR0oXoXdscR+45nbBRMdY0Jt1QH04iAHUwDO7Iku+pHtupJ/XuNcuDeCgbKlpbAd1u91zwSjAOoE80NFnZX8q1YRnYpbffDudICa6eWt5NSVcKLfl+cbdk+sUIOibTNqBNJjyYHkBbLOfADZHkSI8CCggwbr9goMPQZcvj6cKiR+uOQ4/HK/GAOIzNcVLj8a5bVHwJIbNgV+IosU8kQnt/O6JN4z08ORoYvyN5iOfg4xJgMRceOc3anQf65YOrZTSP0Zq+Rcsyms8Itz+PxKCKxZkYMeVFOKfGYbISW3i7P5Iax0nQH+BW/QAjDik9AJDdDqTFQb1zfgQv2wJ/FO2jTAh2jL6lLnM2dnbL/7BygCU0AWKvBHJbwu+CED04ZVad3yNuNpb93gn+XsopRH5LteJEwkqG+Ekrqy7OJlRyn5UJ4BnpxLRCksfT+YhG57Ay0Ivh6rmqT+9J7yZXr58Eus52M4TYBYndTj3HkRS7OBJ7dUkfcRDKiLrgSRcxZxD1MikpUfnjLYoBgonb3gcE2R/otu25r2+sl8+C/eTRvq4+dTSetKZnL4qG/6D/Im0MDe3VQRr+lkROZBeXPhUhu7hVT5NL512dVCWx71GZo3MherjBXD2vePP+q3poRAc6+bB6IvVW+xcbAVAujruIz8OE3RbaOl1Ugqs/uDJjqJRpZPQ0SlQ9Ivo1WkaqU6R68Mvrt3lPeOvET1iGUQXgTMyshouibO3A/wuZoOjc2hD3B/OdIjSXYkhPII7JCPu3QKMV80nSyM/n4VKY7pdIb6qZhR2JvplYrasbD6F/cIKnNGHvZkbINmSUNy0sdlwHbCEExifPCp+l5HM/2kKUEJzMZluCjiXCNENLG7iyYGLvnhldiknwSxYHZN3NzDk9D8kbcCT2woGofSJem943nDYcmMtyZCpzEMdwsO/loCxz+grJ4MZitO6rDKDHIacWBxibAWoc9BWWwTyoy/kNdOVEloQkyII9AVU18e871tLqGS3CaI3folUwms9IXwEaXE/cqv9yRW4ESOkBgOxmgJYM/6tyrZOHVK8w4pDSA+DB6ZW0ZOhTtGRUjoZEfVEetd9rNOYClETrOvfURb1BWPYd9e9lMmN9edm6qA3CfC/S4BpRLTvrhQw5kfcdLVg/ig29gUiTiPdeo+VHCmwWnCxcl0ZNLYmYOGTBPoLkfUd5/fRqQQVr2ToqcEtoKAc1mT1AXDno0x4vt+vn5WzkXyHLXjI38zzj4ty/MLhuiLqYb0FXHHmQRABZsAOpKkB3CYy8rp6YggkRGyElTkgUR4gqkhCxE57jta3ILH4Gn+nru/dQmojvt1k+R06Ba4lIkp9IDHJ5VWdBdyIFINaQgHe9u1B7PKcdQhGKWcg4sJTW6K90F0JTZChHDNkce5itjJb5yr8O89zqdb632zyIPe0df+TBW2qNtJQt+7585WbdQ2dOlTAnHsQSz002FRKZvcPR8/Qc/fK4lhzqXcgkRtdPoTN7kXOMGRXItT0fr4Zi1GSJvOeB9SzIa1APrT+tTPeDxfHZpd1itV1vgdSXkiUlzxzTS+hJfUoD2UoZphAnfXB5uXoUI8EF2hcXj820hev769o1gsGYtEa1tFPgATELWqPyeV2ZYIzyAl7J+Qo4F/a1N3LqV/OjrnJGpoZo0uI4Y1DW1jf3DRqEzWv7RRdVv5yG4Lnyh7agT/tf+tktBzkd0sPdHFLfP3ZBpI74T8AdJc1Tf2g4TN06i6ziXBnwpqSoypI3u7D/aPNAz/D6tI4YyGUT+cOzJ71ReWL1AerHHOeqeO7CeqEBneqw3DHPhYutpNg4VQ+NMwDTWTzmnjE/97qTUKzdmxox9WPjwyr8/58Bdi4dU5JylYkp9ubriWgYgJYJBF9Qw//H4tSwBgDEJRALURops49OS5z6RZtluLDJ0x9lA799/c34tDHsfWLhDLX8IklPe7Wtp/V4NO89nFMo7i9+6RC8gWUx0FyZIMGGOR/WjiMQ9paDOkxFdRTBSfaVVDA2Gsr0lxDsbwrR863VdxY6i6KQQBLJJV2nGQjU/Mjtwp7+AekN3fW3A/7Dexq8poXDXB3kGW19YXa47n+n9gMpu//ZPwFzWR62lY6J/Tm8pVlB305Smnkl6In+9yEVNsbk1wRrxY7077fU9sjDB6ntBtBpgd2hEdKrv+kraxOWGwjTjOhRX6IQXE17xq3LixEEvQkMM+Ye0BFpOg5jWMCwStz5yGye48bVSa3WvB19O1p7nRv6tXlp9IpT58bvHtjrXsWLLe4QSmL14mnfcL2GmS7BYK/vjDkt4lm8AN3zWxix275LeB7nitYSH3boqqh84JEUlRdUCSqMLxf5cfwC+0KEBfU01o0U2ddbRNFuQICKoT+p8MeYhwZi35FzW5c3BatsW/X09ZfOw2K/XY8NNZ7bW3hPd09j+DhJoFopL2Td1KTEJV199pnPzC1Mv7csySdSqxt52wPq1/vxEY94I+PF/p4w7nn2/maWKq4ij//uPUbPPtz7Iet8uu9+34heqvtT6XaMBcCQA5dmE6YdznFrpM1jhceli/E/VkZsWyo9dL+wWwvPYJeLud2MkvsCQBaTjuwjPqTReNJIMrJAKcvsIuCR1x45zt00mwAMdDhr0uwmz5o/E672l6mxa5uSvi7g6dVUyiyjl+Ki4M8PdC8vnIdK695dhKM/IU1YflL554i+KIFsmpa+vhg1dPxi4pPRf47NVb4nh/b+1BZZyXt8m1BEkHM6OzTEEb7jhtlIZMb1tOgRe12nWf0kp1iu7Y3Zjwtxxi9cscph6+Wpdek9k2NZe6t15LBAOMAA9bM02pYzOjsovPhIrf7cfs7Pa1Or4UaRtUAbKlhl5F/unfqvPMiBnAOil/djhSc4rS0c3Ji1evkgvKI4lyivNmGl70MPpN63Gk1Mix9dtf7pivhKe1Ib1LmcwTNoFNQS2XxhhNIA1gDKgwua/CzrXHScGUBOTb361NcszobHMitEj7TzDDB2266FC1hc0XliJvE0ltDflTsPLq32TMqeA0njyEngPyfkyRXqv39HpwJQZsRBHPrD0Fx2UhF7UTSH675ZD1i9ETygY3cFWcZM6IUJ+J3v5jc0jwzjp0Yr1DTOT4vezCVrqO3TJVoEswD42nl73LYLP03itFGb20YFwZ7zi3SiVmeqwt45dMeut02k0c0o0Lot9LMq64I1WzlSzuXGc45veEqE3SHDeM2WZ1kQRmnpGBpUi9bv+8NbQo7Th+8W2d63Fw42nFzatdTjhWEak2mQF8tkhmhwJYuzf2v33iN68SJPVkzcqiR3znKD1ZXD/ydzLbUdwLltd1Mfbc9w/P9S+4qyDsQ20e/3mfbvRAtCzNLQRm4cN4p2KGwDTxGdnkbSnUOI7uM1LiKXvqWXrOoKc+rxbDC09VyntHsFxIEmCUlRhHU/YTOyP74+KouFO1OF1LfmUzwkF/i1U4/8yTtIqbJKPRltRFFLn7Ld4PjOGFYGNAmd+EGG2P5pFEtTglQu9qPaQg8ZtHIFXQAukCgCpPde4xQoIzaxP+yPQxTA5riD/0FwJ4hED9uhk0W6/Wchrrgw82nl/xaCX8uKIUgLKoacHY+ZmBtbX4JSrV/vUalha6YBUOAH1tMAG7W4VAmCoWNQDLkBMzH49fMDlIO/b6jYig6JCXyhfTiyFGjymkPiyM3p5hvXg0mpQTJsYPtjTjqu1mbeYSWrYh80f90OJHOHOHJahZCL1EEuhUSUR9FiUXNaRpX89llNu8DXdA4xj7doINu8Q6kXN3lvp3fost3vHV7KMdYhtGIpvpx1pVimIu2Gm39hPpK/m6KMKVvhT91EOxJSgQ1TxNtzmt8WV+IfeiutIrRxznlCMrRB9aYamZ0sdMVm2pbCCBeLeArNOWnRQ8r44uYvXqV0MMHl6r8fCp/XFpGYVC6/gNOBclOa1pZkwbmU87FR0wh3DFIvsMqzO8g86q92AVgXKlCDBtZOfX+3SW0vXa/92dBx5L3PMRjFFkbhJRAXzIDOLgv3CZuOiQqD10pHQb7FoqtUS4xfsVCxKgAnW+72X+7PkgNFjPE8WgUgh8eX6W1gvY/UcjnbfPzAd5vjl6DB/TISaX1DFWUWFEkzvM3jer1BwAtKx0B2AOPYGL2DtxvhiW/TuwocAXO/UKtnTvGLWPJCWbwN0f5yTlkUIGNIo707TNY/KbbRWsvKVjYTm2CO/BAtV0XWnW15YA7T+B92yN5IUvGvXl94bN5x49vD5JKuS4yjdcrx+g6JyTxZL1NTFHTkOfIfWUseh69la1YBzdgi7a9WXyzxQrEVDzC1YWqh8rN39vtEbeIBDVEHgH56nsgYq/fauFgbD6u+q1RzO6zaA6D2RAxNGAePqVW0nDzqiZtPCGp8P/GPmID82P9wS/UHKxXbJxfAWsYCENQGbsfydLYzy8vhkTksn3XgNShDELREsxG2VjPi6AJZOwyV8xOO+EqHDmtt/jw/hCIg3XsVvgXPPsTybLbfbbzS0EZ/2+b9zj+1PA87FNYgYrlvvx/V3lMqQ8Hz+s8bnDiSUu2vIL00oMn81NaO1WxIIixPWxlo9WvX8dsw7aNR7kDgCsJppKHso1VBGmvmHqAhiana1+i3yYFETyE1vtPpc6J1QXLUwboWe5/R7cJkOisw6fCPiJBghYzyKL6zc9nahDl+l/xFNCfSJimbUCCP7wp+vDzeCuQ7S4VAPoD9S1dwJHZp3fng8+GCfP7vBIMn7GbdIQRpHv05T2a9+2kp84hZ1Nn6Tc18ueBdXfHcV0C9lPxtPc08HucFChZoyXjCIAsErejHgtEusvRrFk3HA7jXY6EZEL/S29ZFrZ6Km/CGs+fj3M8qkWzMJFb5HyWNCtfBCryU7wQnVm3bIYK3jqBPkkt9nF3sY+f1wTYtgvRA58uqvY1pf8TLanzsaDA3IEhQM12NiVlqFuNwizzh7/6bwIxnzOza9VAeILoQDrVZzVG0+IDA8jNTJ9fKJuwx99dq9p37ZhlqHJeZeMXo8yFEfdE2jZCaou76IAWa9H4dhts7MWKZZ74O0z/f7BoanEpX/aIq/EEKHvPDlKHLSXo145vg7QBkxFSvXmpf+lO/M09T9aPbfIgziu7rnKrRj+4d6kb1zorI6B0nJ8qhMc7+7M7zSh3XSAuQLtWWUSsLXGoSkGMWK3VgT3BOy3F02Gg/9wMw1p9wa6SwkrafkmrpfgN7L2GJbR72nAClVbtye8V8a4DPyQIu0EhmSgo1Oltrp4RVWpS0Xx/UqzodyprcKVDqpERN9RliKi608b1uKy1UyO8G54ZoWIoP3OTJzFh5aCU3ZceHeqFTMzja5JbLsh51q1IIq4MQFyaT1Hq9aojBzuMDlvwwJD6TKp6+rWlSfKUNWYVIQmBkGlgo+CFyfygBgmKKuzxTIxSJdsZf1+FqPFugGUHKZjm8ZP72tG55AIUZpcWdiQ/iE8lKqIKrajmMvGXyzTO3bjaQCZ3rMJaJaap54V9QPftcmAkl2lZfLmS9tbn5mBnkCIRY8tvSowaesopFhUnUOclWirztsmmtqu93W0fRf41ucwSLGiMtgStPNm3WNxtMSHLsMeq8jaFSHZ9kOvZJ6wuT7FEyLD8Yv+uzisUw68n3H5TQQsaL/tjUTwYIkkBML99VKpPdISLwCENHAOANUmcwqI0g+IMUjpy+Nn9Fx1Yr2b0mvqZSEdEm4lBwNgdeuPyhlGru8p5SvbNUDA6YP2MF/TB7xkwIeDIEzqYH5UKymipf76wlfWXxhDxYSjrdnuAGg30N6qzifM8DvBdcRryjmrU+CDMJtLhGuoKZVMBSscgJk9Y/l5ZctkwNwPmKJtRcd4lIq5g1qIu+sefQmeuUmleU0WG3YXalHaQqxdlY80WdMzsp0FtN2Q2UlDsLV1i6fhnTUre7pq0kcQ7hmtpU8VJUsxEMOngMNVuEibhaNZLMr8x11LZoeJ0dpEIvtywIwo4YvPktiRepoD8PLoi0IDzu7ubGEvms6twDJy3JnenAR24eKHclGnNwXEbn8uyxfgTABY3pz+GPQbaWgDyWTY++zP/jg3fRHy7Kxrh6TxvZsC2K0T071qArULYam2hKmhnOCoWJGXXxi9VPOadzx5lj43GN/7fYAFRFNDubI4Eh9vxm01VOZFEI0fHJzHHmuHl9bVjDr6rk/P8cb9c4JhW6vBtXLFJDy/GMplr8MaHAyknKnf2/1CFf6Jo1kW9+iFXItI6Dcw0u8hKZqJWt6QiY6riwjCKlNbBwDI6uYwtYdJTCRt5GE/PO/XBaI6fZHr2+NuiZDiFbkXMCWUwsVe3gDJeyZ66raXNpnzff0JBDH+dQnV5JpeTYqz7nQFDpUdkP9YAM6ZCby+tO3fZDHLobrKhJqsaj5tvBnDDiRXEsLzX6IK2djp9wKKH3vbjd5OZ5wxTRYFWmnCmAHmN8+2zO7mWQANUwBvDpxx44kS2x2d461wJgzA+hnt+VYujuO9J8ab1bz7g08J+XxtrdHMU2Q11sWGtb1ajdvRX7Ycf13NOJlfWdUBpxoN4kfMEmgC4l/4py7Xm9nnkuaWf2o9CJOVLNTWS/X/aOtXoph3sNY27ym0FqAug2/kj7jZJ28dOPYrD5RrnfdXjbU+pSi3VZyj8LJLzZCqYtRB1bOo1Sue/XF3F3pc2dVBq+FHZuod0Rivt3zsE98h99arUCUaYEBPvjmCZqeXtTGQiT0Yeh0iLEnGAfH0dUht9WKOViaxVrqsh+izP6oFdT0ouFvQjVQDFcl+mpeEcUdOpFoHg0JJy3c11gAvurWC8gzBPdtiSewge+BiFZA4AJUlAyZdkO7YFtBxiLmN4l6oTbCAJdv3OspEXBV8vYxoFEjJyMWACi5XM8QmQIoC3oqf+IkHD8SdUhWI1jcxhqk27jbLYY4yox5OIp8XavBwDYAr2Rb6Wc884TqFDh3qYjC3El2lk/AqyCRRnh7siTEuH3VB7Kaqyt8GQ/lzeN5SViIgrDCtM8hvbhCmFPpSH99dE1IS62QU3eflbvuA1SEeClfhqvC/i7YQgOFc7GRfmRyzsgTUAXLPcD8ND34Km5UzfowwTQMWAiu5h1CZ7aN6DhlIDy4iqkSoPlppfyXq5UWgl/baz8ATbywzL5mEAJ6JnGJ6xaCFwnFNkAnDzFnQZqIAPICL9OKyHzSsOEUrYHGHjQelWQEjGojkIZ8ji9sIB7w7xlMd3APfhNODKB51feEbINNvfm7b9oUONTI1dybZxzm9n2kmJgvcw5sF8kJhN3kemSjhZibMxV27jV75hATdrH15J6CroCWB+DOkVH+EOiCdyb6yMTbufK9guzqSbeuJK4hLOmnKIwcTQspZUClg2K7Mf0JtGTeQ/HqZpC7PNYxCzeU0mt5tbrlti1J0MdOQZ33QVJf/n7PbOsAbCO2d06CNQbtAyAdSQrNMXC0NWpnPmSCRoUFFlRJaeZ+Z4SOR6gQAqo/U4DoE5Sbb3AZx4vgZhyrFy6PbzhlkTxWCgrhcDezEZKldMgzVOrPSAsbAHowadGZDEuniZpVvfnPdGL+KZ00NGg1Vs1N40WVs1va07fSuDovh6mAjuCGmXjqCIULnVPsStWPWUq456n6IMmHXOn9vTIb0AV+ERrADpOHYglvFGNj3JJ8hVKSynUPqAclHrQNnkCyX6WtXTJ/GdiBA2HcX4/UA3GpNF70urARZWnYBv1wuaAUqU54MFwvl3KsEPVH8rq9rFPKR0dqm3aLUbZSRhkCUxKCYBicPVYuqQo0V93Aoqo+mkUJzRgqj6RqIVWw+n2kXts59IRMd/wVOYTaEhD1DnfGOmTGNus1E5edrHH/Y+UaerZUTEuEgoFEyTSAAD3IAwNUZ/nm/tKwfIr/2bG1XjYK1a4YhFg+BbjYpXxfvEHngADkXfSAeOQXULQGVY8O4nRqnxFYPZHtdm0DBPlLu/H96SoJ2wT05u1ye8xkVRGQmnwLzNiUdb7UC7sc0oQO1No54IgN2tFG0ZMmOoYlhgmV8+xFl0cL6eCq1lcSntZAd6Q+kZk0ls0fVD08fDVu8Kzem7zfET94w8YcJK41b5/DKVDevEFJPsliIBqUMj+mpnH5Ht6ccyltm8CnB/ZJWECv5StR6y2FqniG7V/26IMzRPd0+UMruS+naD0z7DCdStVfdu+wN7YKxb7YCtilZrWSNJKZG9fjkNx77fRbomr0j7W4w6Z/IVl9Icc8IPfApB+OF2PG66NK731jLUGYWb9HgEazE6l8b5tzCqZ7Z2heyMdgOE8V5pvT99gHP8y++9t0IoYnMJASKHDGM13KGwG8dhLjno6k4A1mXpfQO+N+1oNP1wCZqTLpJ61+jy5jCJb8sGP3NPC5dp2Wc09GKpX/WBq1CWj8906tTk+lB9ytk+A5ZHFhabqGin1lQRN4wmxNEd1CSuiy0k+hg5RORQJF4f8CMXsXxR3E1Dm6F+40ajj8hkCx2ARwO9rw1rnp/kspFw9Y6H71m8FsW9fbNsYt3bCM/g9P+cvNwcSHdwwa3yCAz3t9lUag/6sKdbcBqaqLy9BExuvW8eOcyv7uKMJFlKycAGdjCNCC0h1+mcJqbaf5lrIHJEhTOR5+scW2FzN9kZQZaMsgAbpmEiYy6pej/RnhPesKTP61hCKcR5ERR2f0xWT/JbZev3QBAZ7Z4DjWzlvxIVMVvqTS71FWaobdBnVmW+ZeFXiUUYJ+wJlf2hEGySkL6qtk0yNG8CL/AC9704eCnBepEB9scj9OrJX3kfdaChUHK2UV7F2dOeQuB9I5i9vANRw457YlljMHIeJaDbWe+TiaJ26riL3f1329f3Q2FucOurSIWWQ2jCJ52j6ZSSn/+sYAtocRfTp50EQ8tDUZjFOrVF8OEPWv5xrPf6G4kFNhxzFco+09JikmOpFjTjKWh27NQZiGqlrf5jvkkN+2szHUX8DgE3XbY7OTf5ldJP3zFOGogsH4rsJSstLjxZnSazmsMNQQsm0sjinT+eaNm7PG0j0NSNlGeQ4qPjasFM8y+RnBwGKcbSiNFr2PzsE6I8fFdYJ4IWnjWotZtBZtDqukcucDohIqXMoWhJF4eJcU6Ff9iDCw176pIzLKfh+WyJr7fZm5/tJvyC6nSPyxBT+dgdgUMOnMaz/fH7IZqehJvh2a2T6ZEhnNrqFRny3DkgMal0Z7sGS3Jw58rf1Tf1Uhsk31rItwgsotYpCHuucOO3f4TxC9gMEg9X6GM0AxUBhUa3l+hCXvXDSCSNTOiHxnUH2/MN+rNIWygUiPlmORqhYZ0tvGhJavnaPJTCCxggvqEsul7zhE/JVNAn9C7IVRwkvI/PFAYY7lEAGxpdeDQ+EHWlrM/glBLgb8+VTQmsDrkDsGcKUDFHUpOxbqlg3kJ6ej+y234ABf4gpjGJTr/NtpjBhmC3MarGDlAxpakIsaeoPBZiATv/rhJY6gyIneE80q0E0D3gXlbtZKVcXaYS9rQgRU8B5HIlYFqUfQsbm3oeAkUDBE++iIe0zqrQEPhCA86AsBvWFdEMgzgV0nBnV0bARuDOZhbZa59eN0Ar7ZzsrpNoV8gd9ZJlv5TwyuSu6DMJxAu8nZno/XBFGEm2e+MWiJZYFYfmg4XE/5rMzFLbZ9XiIYp92cBmdYmkwDJN8Pq+TU3T00JmGEbcduvzw+P/a4tY8VM65gdFAIpPNMcLoq6HbY+03j2qA+r+psSEyIUWU3Hv/We8dR3+seisFnkWi0cfgp1NXhh7Aa3QLpIz0wjlGSqdxQIRMioFv7uduNcltFYnu0HLS4MQTTgg2qXkRoc/PQZ5PaZYXQiJlS2H/1EaLUD4oPVGPNTex/ED6/k32yHB+SB6Dwdj80C+uhfT60+lI5NXc8moC9WB7oR5LAfcZRIi1cxTimeIpdJ98kJQF0PjHQhAQ5clWTFamAOqVG8wzCu7RadNvQqM1Mu5rTRqsSgMwVJJnx6RWra+kuT3YIIsALStrOFb9MFInjnh+ZOQGyi8Y7979auPp/EF+x0KKmAaIByCjiQePNoeo4IvljmG6Th6MrmVjtiBgC7RyKnHCNcLKw7x5UeLzcZDhSGcE8NhqXgCfC8DvAZchyih6JxiQLAHp7plvSyAdNQkcJhIm3PLAiHLiqDOuGLpbPaHIGzJfN2k7zgfWBo2R1fX6FHEQSDebBhhMqNVbH8/atmoReisrOgCuVeLgc4ZLesQ5obNElBQbQFBQRpYTFADoNRmwgMF4zGesJb+Skf5bqYg6KOomQZcNLWbnNBpFtrrdwwJKf4tC8133rLcwPbmheDZHfjnJIOz96sr8FKcIR35n5yA++nosoJR2U77fRxwfKlSEtiUxgzh/rhVEk813AY57CS4w/5l4iBxyUQFpWP+ILPgWOHpMiSWTZ5M6rg3WuWIKqG2GBAFIAa81WmDiCRd6g2P/NAAaPEySnz2AffbGZ/PuMlKx+CYQDs/iV3US5w73T8PFVWLcMMWjBY12DM/L2GaGGdxNQXVLmMEhVKi5oyW3eHF1ZzjMlozYk6g7Jk2TEAP5h72HUe+/H4cP+sKY8IJJL2pQT7T/kmIA5UoLZraDBPXY8oFEnRTy01TbC0PYGV++2L0oceQypwwEquHXJSUNPuU+KeChw3qQUIwmbCTULskc+m1FtHQDJxC7Rw5l/Jf/cirjF7/nAHAr91yKyD6ECzge6PiL3fd0aMW+UF0fdMxqd5h5Xyauxv7+rKpEq8oQKlQyouG6u5XKaGg66ZRUgnokQtJKJm8G2/aDkg23ZBXSwV70MAONVIExLPZGWV/d1TW4OatRa4FjL7/F9+2L7GH+N/4NusigrwXcoEqYqCVSTLlxi6LBtvew+9YrLNxfo773YTuhCh1eSGemgpjQVEGN6mq8SvDpffNaNuQHRIMA7oAPuTO/b0v6RgHy6AEG3ZQ2uyF3F/f7B97cPwNLZyFNoOVovg1sUQuM9/uJ2HWiYJsKc6vAyJgo50PFK41+5MXKQYrNCATVspR+lMxyOI6coxpqbLaoRVF4deS3rVy7bTxVxUm7qriOr2jiExdDj3/htp0zKpaQEeTZrIWtJ6p3QBihnzvMMLRbWSHr5CpDNUDeiFJ9kXeSJ7lEo/2R3XBlxSBzv5SoSTKlFAH2MWNofhf4L5qwD+rGgp2FI7/SquPiw2+x9fi8ofZeKbbKjnXuNLejn6mlDlDb4L1VKIea5lxExFFlj2Fo1b4Huozuk1mTiQ9WEYKTNYoE8A+qXFekEXF0Ho300UnSta4RBoO1swiEekYYNJf689Z4eruKWefoYM5mc2OIpqYb1shI+Eb5b82V4h6iDGI+JFb3XooGueQA5Mk9wrjKwSD+k0KbF7aA5L/wejFYxcMvZ3DH1urC+xog3W/1/2oyySIrT6iPRqFMFRtbwhgVc8rAUVkvgQUC6e26yaroEXGhIS5/edUT17dmc2sTePHCnsxLlhfx7KHzu7VXq0zH02j6PVqk5OW172tQJ72Lg4BDXZeKr8mlDAgLIKoGw+RdarEVEYMUqcASNY0vZsJmnXeazGFbJuXSkjEsEf+B5lHhYopRgSFYVD7l2/rmh+sLB+GxSXG8tBobHAjncV5gjGn6o6l4dBe6/85SkRIBBKRQtmCi/kHgh+uzVQczrsAMjd5OVdq2E3r6+cbfA88Oyqp8Q0Qv0Cq9nQptRq4xmfUoy1zr88LmKmH0HFUWdV+HL0aby3yD6BHAanRufB2bz0puq+G56TtfHBiWIVdt/Ggs1oQrLFV5pVJIIheyapbxVMeL6cHg7fGHR7bYJDfaKdZHVuEWasDvkFRR7KY1g4RXDzDOg57exUYPVTnRjk6DvmG3L4Y+ory30leorypJmM4Wf6EUAB7wWOX34s1VcCtB6L6UuDzRSD9hLAWUFdBMUzZywBu3jEuHqVyVXBaov6qr2vfYRN8Xdk91XrcUnOlRqCi6tSA7HLqrAG8izlmvOsogVF8i2kaSTJDAnuo8rVTq8G4K/ZjxwAkYmtw/eYBtI7WjJYzq6921FWhIhV7TUmuOxmgezAAkpGPAWfFofuSTQMgCx/1m2GUaU+WSlbPwP+fLJiVeVrwLaUpzTJWeeekRBvK7JIc5T854+ZEQQP8pr2I1VVkqPHHKX/lDHSD1MCeoWIpoj1gnTqFYwFk6OR85WMSqvGK1uT6ppX7rxo6eZHb2gspPWQ+kIfNGPSnDGNdmC2wYJ8oyhVzNaNOCx1RUxpTteGoGnC50456n3aC7xs+ugeGJpLR5QaofOCf2qjAKzmZYnDnvF/1WWW0nKZMFo1Lf3MT+PeO8zirLRZMzOyu8/VPQ7WYzpzEUrLYHmUvPFBkmrIaHkIQxxR4xJ1oOahd5jLZ9kOoHThbs5z66lR7WUp1ocp8cpPculdPKkRdYgrMRRqaaIVCDp4Cw+JbjbjaEj8yIQEIcjKHN0Tp2muBYroVGXXji14U5Zt8FTzbkqHMp4byJRc0FcF2L+rjRslgumUaNi1PMZ7xVJi3c8IhbyTT2sS9X1NdtwuPjX3EcXeiJhrIZLW3yN6NhyYhVsOch4AuRG6yJMjZlHW46PULXjuPtgYnsjAK5wMzlIU7CIapAZuNGaCWbXgseFqngcRjFa6ZbHnHR4pMgVVyjheGcYeqZ7lv+yjVhKusjsYgGsfEg91ioNKbsFNQCJ7/Pw06iSqz92tvwwxUyr2fECoqDSLUmJgUV/TSeWw00hlsD5hD73UzkL3ACWJ0tsKT0QnhP8WgCmUGVbAUK9wvhN9smcoZwEbCGCkHQzor941LOpfkJdM32c3EuzozmR/lHP4v/MfcO/2lSbN+Vfe0xUMN9JcU0BO32/PCOJ5C2mYgsKKqawVF2UMFgPp8fn6GzMTOtyzIhWeXcJUMXVBLpFaJq6lEI9cYltaBcMtjtgQsO/26ZZOjLdPVjhLYDxvp8YYFofLgAkjmbQhsQcDa38qBcSli22uYA0iTlg+4Pws5FB2vKDFgK3r4Bv2YpwaBwQ5wIk3TxH5JhMw9SPqUAXGpjQ9GG6hC4eGTGR/3Woh4Xwkas4DiLhdHMEQEtUuZo5e4USnZj1k6dFsu8X2cRtbX2aK7Wo7BXpvCN5YdLFAIykmyBw0YiRus7lUx6lR/mafZ1ekJal9iThy7Q0H1SdCIJqthItA4aedoB45I2UJ4NpV2YGOECTc8Iz9CcYZ8g4H62rryPso2tKbEfAxkIZ27Lno2U9jcONseDH+vSz6Y26JbBsIwyYL8KVSg/OefVfOQJVqgWcTyd3su2ZG1quF1SpdWE+eNlMKaN9b9SVQJidb1OS7TSH82J9mf/GNn92SxUnLEkdFJRRPwwGdzRgBa+V4tw7rqmVWXWJdUnyj8vgxkgJ0Xa0Y/jMB72C2aF3LveEPOJpIPQn3bMgqwBGc3CslNoSDEdqgt8n3Y+4ACfZEnZDTrOBEB+8cadmvk8Ci6xW4ek/KrOMHIaQIWyNVMyx7m7RSbIYuokoTetUAtcUpWnTMrNFLntX6FAXlBvJhPls8gi5DgKtmMC5rgECl0X4tyjhC7U9FVkogMpBH1/pEcd+l334uTDgqAGzK13yVFn0gHaXbrGWU+0Shi2K/kx7sTmXEzNjg0usmC9Kvj0nSWuqf+E4HBunQ8wIF0OW/gE9glOykYo3rfStrcYRlcfSs5FRpUap9CcIiCikzNLd4k4LOR69veGmSOds+ZFNz4ShbftUfnw8wvM27bPzeV6H8zE+pIqO1Gz8mzFcqhw6DANr8VL6Lh67tI8lAPMlmNOnI5lOpCUYXpvI/FarqxN2bHMsQdgG6/JjL1Py+D7js6M5WdrrkZ2ovqIHEQvqUlpa6XLumFpayUgXScAr+V5jFa7L4vzEitaOTIO8QR5lKyzNrATn9AsmkC0bRKP1j5YB7a9SP66YtWJL4dbDrdsL+PF57kAZooIyheTMhwOcMBayIGj+bsaNOW87s0DZlzqrslkFa2c7fPaAMtV3ncWpztjTzi97c8Odfa12wtx3UyzMicoZiUxt7DF5tD7bxkfLoyKfdCapQNk4EzvbN0FVO0JGePRaN5/dODIBVJmGhN8qHDlDBRfG2mXefC4eahBFojRskKPUpXa1ArYqHIdaHN5QO4KQ4BDzQwGVk0KmDKAMAYQsTDclQTjfyTIAHhIDWog8s5SUVLHHY0Wo4AzqwTpgyHxABhQP1QAvoNG2+BFjhDhAMxGoXRg9/1WpwEgjvJfjMPYC9gyA9cXzGD1XGtPA0AnONL9jhWI5VlnHYsGdTN2Feq5HXXWZYhQsCslwhLAVDhVU5bdUMXjFUnNjeOpGB530QdqbdDaj6UlPExmeBQkc40IPwlwkg5SKz4HH4qyc8b2nF0qyXuSn5SKVqPxWFFJfkKEqkurmKBsTI2woYiISrv3SGZL4+MU8mZvI6LjzzfBvtjuYXQ67SdRSyU8RnrHS01sKyR2fITg1knC+II82444iVk9UeGDxiTJz1XAfCh8bG0Hw9vcmMJi2MPVs1jq6LqdLPocnn06PYd19D65mB2a7LhTxN6V6eMZwKFoyQm0UY3wXijyjoifO/BlIKxK6GiFqjpVeEfAKAeR/WwkoaZH4ZzeO0SUMEtcxM5gswrFAOIIh9CVDlRaAoaHqWTZLt7g9j5pa6v2w8MfYMUMIAk3v4jSATueDk9U3MLdUH0/qjh1ywHEOLOUohk+FuS9js5qHTsIyRcsODsq7X8kovdbHWzgbBOftCoVdMkxnZN1uied4oK7Brc60QzHQuMlIeq2eazCgCDmSTcx8NGdVO+0+7T1jxQbMkWp5CNjT2PqgaQ0JfQzgeG24P7p/asg0Lp8anDZYjPJ88ddRxe7ExgNs7YI3B34Fhat+fdW2KHjB7SaW81dKXZAhRs3rOaCAlc2jJvuKnTBETKpGW67xwbbnLt09ipyNfzAYlsJ6yGQNnnHgHpvtfx2J7rAaqi/2uMc5XRptsyNFJOhgQb5VebV/SD7io2MejwNLCJRQGBgmc1vNHVAdcBtL6Du13XggvEgZ34I9veqmrgVYWg09zw2hlHuIKbSeGxIZ7Fwz6qjmsx2BiwVJ9rJiopl7cfnE6iFIUBY0dKR6WVaTxUB8QOaLbIu2GINk27++FwOtgVap0bMzCVI8KJK7eTkTBmwL0Jfeby1y1vrpfKF2UeqI0S7ocPrHO4m3kWgtu/YFGYnGIdoOjicp52CNi7P7EzZMjMmG3bjynaGg7xz4MrxKZlQAm5GJRxUlHqE9LFsNQkCByxqxGEG+j2y+aHBnyAI8qQDw4uBJrm4aCWQ33C5no5vsfgzdiYCCsoR7gLwHScxgLAmPxOTJlDSQail9rcC+0n14FIdo0qrSmoyPNBOox7Wv+zIS7qL6DNn9dz5e7Hjn3bjchqBH/sKnNy7dg/WKy40/rrTKywLwjbftwovOqUgClosgqFpHeCAOQlillefGI+/Sf6XUi2CH+ynjHFUf+8ik9q0O93ebMcdkQ9HsU7NEOQ+9xFhvzPRM9E90fvwHPhH2IiTk2BvOvH2ys/qW9z6fwTy06bwMJitnR8HXp3V4pJ2GcbDzmRWuT6J/sgHV98j4v8ATmQ2sLrhCR15j+YCfLhaJIU7YkyRrJn6ZcGF8aZ3oCXTG+IeJiIzCyjFiHOZrDkVLOoc/BiLdUUpskucvq5Fzmlv6qkS6I3HhL6vryG6XViEfsyvqsxA+Mq208JOGGbbk09+0OkFR/YvAeCpChuIC95zYVW+ExMRJLF2Ix0U2W6A2Lun5+Rnf/PMxl82gO8r/y2EyvTXpHLefzU/7wYbCuogUYtisx9L7PoDVapgg/emvB7EOXwXrI2U67GzXF/I27qKEkCF7mCDMsKGap9Rwwxh12yrR1XGlexnIlsHSPYXyOp7jokuht6TNDnijSUVgZykbs4IluMUUnWd7vQlkf3yBCqgTP30Q8cEVQ58PuubMGPjIjaDW23AR4xFs0WiAGByugzWDXx+VTxRIdm5f1B2XEmPUPD0lll6BWeN/4NGWRPZouiP1KBC+oW+a7reSgAqRL9MWWV436LOQh67IXPTTYsSHq1uljwXMkFIB1fUaX5ym0Kc1YUfOtUaCUr6gbvIBcqduJicG89qt1Lm1pzdC5Vl7TAWUAlSOdxtuIAQf5gD+BMm6MES83MeAB8Bl8z6yo1U4vd84IxJaZTXqWTv+aYN9lrBxjyklm0PwML/ulXg7Zv0WWvVwJN9WzqxagM6Kk12OTA+OYJIrXOHYtxOklzBtrqq1AoH4qvokdysJ60/+v/zAMmJGLqWuFn3wgB2G9V/Uh/m32M3XT9Qf7vwx8nZiyJ+WNqcsi8VbsotHVSENJC1DaY4XgL2U8ddj+8H2PGq9v319qaup+9XmUHbblm0paZJ82T+AsJhY4fwjpUtmTmUouTJFm/kl/il2ht9wIFCI7z6EHNX3Gia5/BQK0yRimbJujfZeUDzQusaqDMggRTo5DKIjsZDh3HqK8K5eHwCMK2ee1FdxNnbZxLjbT3/FVj5suDMPhoLGSg+PaeRqmAn6ifao66xcxTxUQG9nCAvmuFTxcL+2dNBwJ6yaBUZPMy0tePe9scNtOIRrj6RquPqJ7W5v+1U76/yQkEF7teG4cDGOj5sWbOdq4OHWlfX2kr+q8dq6T9GquFSFbZbzBBvmArbfp+gn5l6T7Ai/9bOAITxxhn8b1jTQPgdFtvLbKcIhLuIUvkt7pHNFZNLlmrI1j//4iP0TYSomqi/PZ4EIXlvLa99PTKWZ+FkhPFup80IFmpoEybwX0AEfTYho5gmbmIt40QOkxA8fJD+tVl13N4O98sgaH3eZInMJMmI5U+UJ8b0/z5Zo5gtnGpHdl9SQK1xKg5CpBISxYgbnC+02vb4D2VRICQ+rV2l56BFRWQl2jNqYZG/xAH2RYPQmp3F6sM2OO1fnwISvKa1DEhrVfH82JyhEFfAkjLuHVWFjmWba6O7EewTCA35G1Lk+QEsTUmk7hO/9IsYhVSmV9Ri+JwmhAuNVWqaq0YRe+4RoXN9iEuHs0jCWpmm6IM4EO/Mo3So5iM6uGxTDds5WLEEfa76zFyEcr6Iqx4mV9VVO+h568MkU9CXoOLE8YnhF30GY0sdKCoczpvQxCsKTgUQ6qPx8EgWNJIZbFxXizVNcVTTKbqovZFfW0FvdLmniEVM4/5/QrpYXAFbVCEEu0J0pfCGk1vK4jHal8pCM82+shClbWhRbP4ziOiGl66/I4jV3uJJEeu6IK/Df9ygqOtovnmMaSaICNfWeKMgEiKtYKJZ2WZZQZgQVYEdObRP9sEmz1UVBt48Wqv6AJYHqDIvJYk8v1OEXhvJlKo2i+ZfT71l+S4TiDJLNhydJURrLQQlwHNZMKakMwxVi24V61JyvW0p+037zm2yCCPGqJU8NK6NFAKy+enGJpLDC4DHCWAMEEBiApYIRmtgbc7cK8t0LZP10wjlQRqlZrvj+NMJMSUHMwu41YQUAVUX+H4KGj9ZLutUKP9yWk5PIlkc8nRQrOt3jrX5zi6KDcVEv32++o6D0QQwCEsn68NEum5DvwR8kvgHXTlcZdDCkBCwWRPZA5PdXnDG1Y6dT98lu+O+Z4NejVSMWhI54GOCZT7vw3EBjKXl8Q2p7w6g7SX8ZnDMrp8IzRDcQGNxGkzP14FRvxVJnDamGL0a1sEIFsdieRLPQU++q7RwICGpdvYG/fEDWDmeCbCSJGjmmtis6Ma409c+kJGwiCKOLsL12hOX6b3EaU9Z6C32lk8GdFj2YjQuJVKrk3Uam+HDBVous5xZJYhciFGWG/R10+oxfEHerfWDLGFXg2TfPQl9DhYbzpvnyjl4nWxiBMpipIyJackA5h8VPqkiuEJZf0woD/qeFnJ7k6DGDJAhcNwIsy2SSiDOsrHJya8HOZJIYVFNpY15i4yiNMxvqLnFE1ppEEJPAoFfhPnTpmS15GYqqf4Yq47WHhRB3Yi+wfpBTCexINpsDWc9Vwj4E4VN1y3UVz7s9cvrWfSVepMo+hgj/UDHVLTw1qPcE+OUU+1IvUWMNl5bZUE2xGtyLl8ZWxE9hQC8ssihqH0uwUFC7/vTzqBkbfjx6fYrpdfn14cfj3SnnpubC3bNQXsJeot4YUO9urxJdrfQ/CrMaA8Zd+e97v8W6y/DRQlY4FOh3OHumblV29Hm+IZ7pZV7GeXh6fO10N0kIh9e95w/E/9kYKQKRHlCPNvqaBXFTJ3c4TcVyh2EjwTHxmABGNDfkEjrU9lpSUHUYiJP2Nt6fNKvG3X7ppsODhgcQfRW1TmQigS0EgYb+iIG6z/NPL4COclYWIDVRXDFEWpgaYECwggrpC2KgnAdaslISl5KLZa+vdp73X+OV7OFqM+pjueu9XG7fIyh3/XSPidzk1L3r44R6NK7wcJ+XJdmYfr1kvLLQSdNC8XvK79vgAU40yCLy1IFyY9v4qgETv0qlP61A6vIs5yY1ahNFp2wfDFwAlLxntFWt6qCD+RRnNO/fGHnSN32HfVSr4o1Z1dTID4oz+7r5XpgOUYB2T4oWHFUxfZYxc11uRCORyixMI7vKR/UyTM0AIglNvYAzQKb+HQW76Z2yYPnMd4kCowCuxjpQHcfpnmL52IAx95ytVEv5//LlV9OjYMtvXmFOOCmBFisc9xRdAulCODb8T0/z3JgqnnqtHwAaU/7bD0eKoBuQzei1OyXfB81j+4wOi/egyoHoRunYwD6A3jnVaFBOfo0Ds3yph7JwHVP9/bwku0xxwqsXZgRWNogv6r5vKOdS916kmgc6LDQ+mBYuTKuQxAwyHtQz6SAGTtwIk2Qc/tz+qBUxI9Jr/taZPYR4yxNmXGy6YXU2XLh5+68Uw7o0rhKjxfD4V1ROLxL2lC+MbRTCXZ1dEoLiSzllw+ghs2HBSVthh8hNXeCc+3ZEnvuTrtPf5ufwdR+AXnzq3UeOyy03jhcHKsmzWGiP2rONY0VgUNaVEvG/N0bhIvv1bgPiKVQO3Ls0usuYCOtB1WUSsAchHQQTk2I7UoYsuGploBQeKIWmhXG1WJFMc24fONjOn85KxjFlLh80dgtBhv0QiK56iDnJyCdnlcSYGb6UWJImqbQWuGO1W2Z4XZSAkLRtd83wZvfpKYBGUJ3AGJ7spEbwPO2sFnjMqlUhHp9FZMPic7lgJ72/sWbOATLXUb8wVWYJw4XZV5M1DbskjvUdu+qIluO/qdsk+TrbF16zc69gWWf6/hABsERZndhgw6eACxIGTycQS7a9Ew5jOAHGHzQYcuWj+8u9/cjMfqhf46hisR2xqoeLO1CZV1VY+LDSaLojJc5yXwVbvMYMcA8CIscca+CYTmvvXyFvrTX6u7iLjD5VUClfgq8Al8ubHV3ceePWyhiIW2UquAPImGK22ZmHbe7h/iWMHo46hLC2JrXh9kDCH5BRBwS74y8tycMd+zvCVMci16R3kKfF96zzx+9vAIcJiVCPKBCDr7Uc3eDqwHkxgagAz33NAC6hgyCvmjuwJAV8ztii3O5AYZfX/JZoisZ/qF4td8ub+R2zI0kbdIS1GvejepoScGs7V5P1RD1ZJU0JERoi/nrweld1YfaAP8IF/Up3y/v5eGbt9Se/PHuTYOPnthgU5xd46ejr1PYWrLO4VSelbBjVeQxB5vyh9zn8FKO5Gi+0OhDyeSbC3fdsFGPo+ywqW3Ww4kDv3VCom3Y18plV11sZsu0dPuGswyoDQF4nKFm0Cy53tv2+ndXcb/JZ9CINPy04x+uyeGuB+2lVP8OJFsg8h4FRKvYHYHl0hpYD0VFegsd3nYNL7Ulzrc5m8kPrkhVTUE5C/8yQXTuZWBICE6Fbp8g6r4iR0yuB6K9zr5vrwReYOoCaVLWTp86KG4aWOFEdo7hO93sCIfJla7vrIC8wBQRrd5mwFag47us79GwAgrPfTwdmMNFeUfQeH5So1Vgk0M5DAsGoSk0FLhsJ/XF0lcX7447xSN5+Pn00s4PBD/Sl2pbFznqL0Y166wybWbKy1+s7zs1I6+oRvTf0tBxpWZzkn4cGLNezhTnGLJnJ2iogZ1qHA7e3uTf2sMlWwfHh784XJRXsu/jMfEx7tx7ViCeU3GzrjL0AFazslaqRo/Qatkb8IHiPfHu47Ad3wiqvI494lke8TAH0lWkfC9ytdV6PfpnVJJ6ktD9JLsH845XQGX24sUmXyj6gSFc9kwikQ6V+vhfr949YvKgdEKCZZTWAzIjLGZNToY3lnTZJWzmV32SYlP82haTbsU5xSZF1nac+RCmvTwP3qDb6hGOOQrFaQ7cBmFm7FDnGFl2ACmLX0j6QSfWD47WsG0KQubHAt9JvrsJKDag+gPRsQpFYq4QucRAA6mP95Sf9RfTqXA7VrSeBg/cfzEfd/weIl45yeqmVjNVUAY+ENiUyhpbEppm9YbVF6ljKQkSbKOUfdxPCqR0vwG5amMMN9XscvyKb3LRSxE8VN+kjmH62/s/GplOfxCVmpRhFDemyqTuJtkvmhDZmr2QjIV8W8sX/Ci1Jelsr6j9RX6JEihAxROfuG9zm7jgY0YkajA8ANj48JkdZ4QQ/EV//JcdmlsgWCF0fHFU1eHuGSGTw8fxzubYySuRo637fJmpId6imVh4Dul0Xxkw+XRWo5FNLzpbw7TipeuS/iV/iVqzcUJrKcVNHK10tufaJ9do5m5+RvRWfUR0fok5Hha50OBURRedWObHT6qw1BjqnJQIlYu5MhvFQeAY23jMIx4HSzzmgOOgxjWr3ilj8ODrS9D7g6HxgnvJ2hGBteRTbH/7sVYpKnx1EcA+DmwJfe8zzyvlPI8fOLhMvM7fykrCAXXCATmd5cr5zymxK9t3zm0T2LopDGkPI71130tCDoAe018dbCUzpV8m290WI67TwnrfpaBGFUwwFAkyT7H3xG7WEQobVs/lMsbMzz3aoukkFOgemQIVKTqGGOba7EF6fjEHwQoTOU6PvYNc4vxw6lLcdweccmHD/EKxIiPKj8J06UwybFTQ1ltvqx2CqMj06uxuW82a8ViKUfJB31csKMOCq2SjDJ/Z5EHsLs+2bN+k5+pMvn7FedIwOAYoJzXV+/7U/NSwlchc1RiNREtHNOOF3D8uyk+wVKTpvM36vOrq0PUlv/SRmbcy5KIY3/drDL5JUJWvn33LVXbL40mFjIwivr2FaKHDlZFY1apOb+GIMfjmt7tZCoiOCjufSx9uZU/zIbDfe/LO6lLu9d0judEFDsooN2jb0437G6WHd0tCy1hwvnMStPzeWtaHxSCIvgjT40S3/BML47tivCg3anAOFE5WakeID9iCgrGBBlTksuMSm6LTp4icidpU4ZBpnhqYrVzIsLUzua0lBUzzExgDImsy0qKF2oiUuw6MbcOwWnKb+tZh/uKWjqga6EJv59C1DcO04Dauf2MK+lscYbwn1FTqyqDbMAiUqtBChYe7hT2iLwmt3s5hAKwk5OWOy+hvQV1F9/SW8Kejk9+MxQTorcuH3gXI1lmFZJx8Ac4X0u6F6QMhXqnEQekVviAWK3wBaykqAEEdw1SuugAdYuCEHJRqYxbVZPNUE9g8IRekR8z0mlySHqmTSOOwt21ex8D38HBgvH5l84zv2aLnhNY7st55Ch10borHIJZOuuYg1gTnQCPUsUlMQq004Qu2owdInYCvrtnh2GvUJ6zZeDJV9igdXCVh3Bp5A9QbaL1Gnutdgh0VY7S4G1B7EjNyycpOdGqGmbbNPeGVsmxcS8kq1q6BxWukRwBTFiWg+hjgyjX+mB4BTOmTHBummeG6JBWKaMQJHP9xdJQtzLPSMIK2eoFRsxKAH4N+eyT5skyuIMt8AQdbXOcgrA9xugiqLyi8VMlH3ItsZa0rArKdLHi7lEO0g5cq6x7cdiIx+ComcliJA3E4iSzreVhxFtloGDYchPqFVJ3UbXlH8vV3zIJujcFiX7Otw5RWJMMTh9f4+CVbuVWHxIye1lqoqR6muCK0bglwMPhJW03aB6XRNC9Caj961DJt2syzZbIj+RP9+yTX2jsneeA1B7r/UFFd0Nq4qMOiP2QF+t/b+VJWyoZRZV0d8OfiCI/bEMgcgIZAx7G81nq3kt/V53NoO8BhdwVEqLbL92pyforF3ahaX5bh3pv2dFgf25ypJ0dWQKMsM0sfCLq/U13ER21xsdBcLzhtPaBs9P+QNJjfscNTJ8gDo2qQwzbUbLhmwza+cjXQCUlrGIsVII60OtOmbsq1YXrxBFJrotDiJbDJMKBivZFTXHHN+YeL2HSzffjnMccpHJT4whVizD9hIbwagSPzxT4Nyn/IHUMSUQ/sCoo0ieaMNcOH0ulIm5f7eBTgFoG5C3PMgIw7hhy5dkL1n7uBgyRkcW2sBBfcx2z4UeJE/Za+zhz3EiRIrLkID+4hTSHSQYFuHVyDYg3HOjCNjNOI4wzhPdijRkGtFNkoPWcLgqUANyM2OA2Pbjt5co05nA0ATReWW1IC085Dj6+L7i9xzxeUP1yVbhKQhBAn6bOFuHmOXe8cKev+jDY9Bo7byXfHiKwdhC1QXoQ6LqiFjV87Ic/3CljDWoEteGuzPC/6AmbIbQ7KK7ynejfyTokUJjeVKNAL6Uy14lXQKJop7tYdySAu7wML0EdWA7fzGP5mic5TNFTjmrsAGTaOVadL74fdFB1TCUh2y/To5BTJQzuWTvTdFKhJtmCZVhBlpUOjQGs1fZCw4IWBGhmlvKWsUL7yD5wkp9h/clGdYN592+M97VoiZ+H1YOE62Vy7ZEhFM4BJrZjDqjgje29swXPd2VDlejd3CUeCpmNdi8wQNVNcFxjD64ofaTzZVPRh82yyBi53cS+4NLJq7OGpU4ZUixVBzIzAj7VsS+b5cZOn98ftPC71c+Kx9pUqzp/3OMaain4tFxcv+/33qM19LPkMfv/OTBDDO/uDAH9ARZpeJKwReUBxwPYXx3ofbR5NGkAFt976AKs9Wbiy9uRSMnjyEbK2Zynapfke4GVV5RcFsh0Odg8qLv2xXV385xV9Qefhu8DcTnEXmimI1o4ZPvvydergaWdWcW1tzpUeRMlCv01dCEmDiYaxj1tQvYKJCok6IdBctLa5XL10+A+gQr5/OO2KTgvHJ+F3w/JL9Qu0a1njElxJVXgzK1orXSes0rhakFHP8oK2C261nDsTiALuCLo4avykuBkMx4QzpGlgtIjzCFMXhWxI1PBhT/KcaT5LwFz9YqTK9tbnuB2U1FaY/nJ1dg0UThFmfJLUkG3SyxVoUAjrL5RmA4zElppDiDV9Q2Co0OSM6K23ffGYIfhaEGrZa+iTY9KN/xQYGvUq1jKdX7eoblJtBTP2KKFp0o6d2cNJd5fzsvcQdjQV9/GLZ4zCdwuPyaoU32LBWTQhTRZ8+iuGoAzKhVM1tw2MoD5zf4x5ql0E3J6aULhC8NQ/GZooz4R6fA5PpcfsrxByGKc2nVMXUwHUmAvhs0kr7kGU6QT2lRP2r8JNI/pAMJsDw81XNJqQOZRI0V4H5Fjcc4zLTVZtytMfF6bChVg3kILIyJakQr06XrdwYqyfpFBrvTHrsAIDh8ELs6mZTvNNFfxRAvnz+HDqRucTB6YyylRLVYgFDjOt0NMIllIi5UyEEIWP5xW/j7RiH+qZjFNEWvoCiyA2w9lIseiMzisyObBH2ppURL9auW0hmmYFgzinZdiGeNjT4BkmMkywLE0tv0Qu96KQPVqZU7Giir3K8iaVejG/CpZOkGIYNs8hoy4aRT9+c0TDQvmQLzPjMTcy9PtAywWPRCX9lcML3J5uBll6JzvXzZpW+ARXnmFvMg5JLVBqFx+ksEOCS3rEKaWdGUzYc7lzYnqpzb4wD+bsLZPCiMEi9ey1VgfZ7twhZt/aje2NNiRSiWyjy4QBFWktrYr85JFwdPyY4oEWliUDDEknpVn7iAPOAs7+sWUlW3Eu5R+5CirwejT6kiO3cXCGn3agkTHzc1SP25yEp0ZPCJbuDLcFaHE1kzgVLeFDK0AmaSlEsLBHGHEYLOnqYrGd6/B2A5jvkz9GvcmcMOlY5q+bT6YcNj0OBwKrQfB1fHzb/j8RseMumdWe/dsdihuynyzeLJBSAPwMj73b6g3W+uRP6IeXUGAThGvUKWPV9dek/Stzg9jBpoOUu3NR61T4VU09HOCVyPQKwhatlIjGibdAG64yeLdAvNv7KkGzlugUFEelerd5VkX6LzKHEb7WKbykFMLz4v9LAkchdMQkVrQgChs6I4QAJqa3mZGC7CgazReEMF8dKlT601GcMB3ElEKyjJ40Xlf2F46IzW4qiBjTRbPjKIbCaqk9kAxasHslTKnhRVsbwFcgbk0iINOhoVwjlkbEUV6R0DLimAkOEitBcAtMEopViSEXGldzHuf7K4zSYLM3TGJVuIBILtiiOOH9sIZPVx4DWxqqwm3tZ9lOgWJ43fVWnpN//s4mn+wWbD9vHJiQebYDCpSY4Wyaz7js+GRCkE9yWg0EaxxBym+lo1WPRDHv1b943jn0JCMcNeZMdQdtKkEpK8NiZ7yqRKcLlvNbzlCTD++/2bhbwainlm9jHBYT/7oARrT4oHxckgA9hTYKTCYX3L9Vadg1t8LfV6N19vsKDodSgZ8+if579G12SwnMij0CqIjtZQcMKbUSipj7aPYv47+zPf+pNtErza0vs8Z/LQA0gbz7Y0VuJXdrWqrR/7JOb/GW1EfH8vC9bKpZ1Z+MDv9pZ/BniKZviEWxFi7oRvXj6mVHAHmCk6wy9mXasMKKxSVNo6kF87c5VKuBHpby6oBC7iP74aEPjte4fJaqbe2BFhhj7Fs0vL9/FrVX3t0NuHW4fyz73UiiMeWnmqsfy3S+weHtGSX9Ahwx3hPo3obYHtNujr4iMNtOCTRkYXHOvDaDjnPgBgoKEIfnmU6laDHJA91VF1/LHmRQFoIF+z+xu+BwfRjz0eCzHJ2Yq2a+9MlQE9/GWlvH2Pr21+6inbtCMySmwmL+T3Z0GjX9ojoBque9MaEvlUJ7zI0r9PLJMiW5EkuqOLlJGBthHY3YbSL/ZE4T1GhnzLhwA37aPonY4Ek9g7cc8nxTIId+eYUArHKwbZs40512ve4v+btfh6xrqj9tmPTUCLXap/EVVv3O30Z/xHW7dQOsSr72rFVO3EvHqXNtf+M/6TjXqXDFn7ziXreZmtb1LhTH3EM0pt/5W+KFC/zW1OGwb0z28Ik6vONc3UoVWPCBUs+n0s0ZHvS2+x2MN3/I7ffjHYbyx9Ll6IseAir+tpPDm+zWZ8JvUXPmTk1egQLl58RW/pB00e5dMEVH4RhYvp0tKbUDrPcSGqsKk39aW/hEpfytKQVGmGkP9tfqhs/uJ39ZFyhmkED161KVXhT5qbEh3cbV8QTcYl+CT1NcZwhq68Oz3fDF0Yc7kmKcwlq9eSXnWha4v12YXy1jzU6QqZzZbTESuFWYrZCww2Klx2+r34yjowqskqTv8K2DyNYtNTaszvP1ebTgx2h+RSaXvz21xDKv+1OTptqS6OfoezVb12oiDc3FTIACpfjTC9eqKX7kyFYm8eqi1WFl+44ZmQPTU2/zdnYQRQcY1Nn7siFNlUmM3qVlbnRDnbB334QvZdem8y5rIPWoav/L3C8ckxHBafJYBR7vLNJvzov+rhyMV0e81h/8jWe+kQe+kT6wc/DxmQm9lkSZ5ZfLN+9eBDacOtCHktpvsAHvMdXxc93Vl/WjRtRfZeN5hAOW39dOkjdJ4Rt86u8hT/UsScuHa4/jsxJiqODB6ef+mk9qB5ZwtDp+ODBtKhoLYB+KvA2UaMMcpRVzeQeyR8Zcwm8vK88VD7m+4xhpzcf3iFw6NFntNP0KaT+I1PUsHDTomU14ep7aSTz4JAjtvvPjWYgR3Qw6Hrm4knXGl0W8STZn4fOdP3Aap4HgdqLt9l2+8Mt+U52Yy9NIhIoWpWk02ySyq61XXWtwqOqo9rXqavKbrnV/OnUs9tAwpM8+DfHf29GWSdWOzwk+VV1n7Z+q+Q/mzTcy4WYBG9qJ6ex+czepnguyWvy1fhCr1bQpXH2fA29+Dwqc+CBv7Ee+Z/9a323nszyzPtHp38h0hMHB2ETgew0Pxg/5Mp74xWD+HYQY+3uF4LbLPyo4/b0DZ6ez+Iexu6NNzQQPn34ArI9cJGmTulBOSVub8gqfveI1v39ztNk4C2L0UdwUvh5/hX18T5aL3tdHTa2k88+9z+rk7UvMLnzw/2oXmImFbRRXU76hgmnzm1j+FIZvb5tBn56QPtmhnPko/Qi/GrMw6q6nVXza8+eXGuz95pwpwyW/5sf5nMO/GsOH7FmvGM7MzWTvcpRXAu0fkPcLewAk8e9LEgCghee6Q7Polmt2t6Aux8sa5WJfYq+tcYEE8nx3n1B2FQP6Rcr5VSq79dEHSMfMyvea3S/AyGdo5/xR8XrveL3/D17Xjqv79TaGK221mAGma0wDK93imAuMgeBgDdIXaGAFvCIw99BEgpDHdP7+P0gKDAdsg5UPY4hCls1/6qCXeN6uirbMQPlRAE61plrjHqhfMDgCnw7sMYEvR8XfyXCfq/8vnTEDNrXYtIvgwdmhE1cbFW2EhYGRDZsRJle+HhWWEekUsbUWLZhQA+4NeQU22MSSTfzOgzzJ2nVMXJA/bPm6AsErgjIcz4jCcPNxCahhBkpk1sGLhrciwioGZxEMGUAiZSatgvPLBq6WVAoYKwPsVBkGchByOgq2I2FMZOrJdiCoECxhUwbQAhKccglD6fRIGLOzGaB+gjFhA8ONSQXksSDLFYAANyZlIY091uEn0pYYwGZgsiOfcySzV8KX6sL4C9tWgDjilJpqfxDjHywn4nHClITewSfE+IKFEY8rvGel9ywviLHHIiM8Mc4ItS6PiPEvehCeFL9D6ZD4HhbfQVb+zqEQ4xVqI56OOGeljwgMiwn1kciK3wiph0c2sMYx9jUhD7hkpcLLDBYLqoqQF/yFUGnyhRjvUAkhb/hMQnt1HjF+xD4k8i3+QKgC/yPGBfYB0Qt+QajasGejYB832Cuhr1FbfICBXsBnxPgN+1HQj5xd6dUHB+MFvRJe44hlSLzWI5Yr4rUbsQzoXo0QIff718SfM/r0MqI/vfzIcfedy9/YfNyxuT3M1b09f319wq9RjsnXOLR88XKDg9IxlwkHpoe0Gflzw+9eveBPpVXadPgDLb36jd+ZM68esavoLm1qnA785tUGp0RBrhJOSgGKJ4wr/qYuw7iwuV7nrIvbLizv0yaLIEWXaygojhQOET1OswIiSqYZRSHH1WETcExzWKDIQm0yUETCdYwjZUeD3UKhHj9MO7papC0UnQYUwLEdGxhB28nQmUBGjQ6k3Zp7LaCoR9QnCqSa35n3hOuelmbU9N3eoY7mYp1QYT3sfSPIKRghZ5TUTcjpTq/g6LEtjgLlZr1AHIcdO2zCM+wWOojVTh2CoB7RPJFHjQ5hC1V1U6xrFzmQQK/g3sImiQ5Bi+LH1E4oimAHRUOcxqSEgEWCEoGZIkiFHRzFOoENZMnHdN5CoZ5WYJAW9GNRHMlEWCQoKsGJCLUDVmcdVrAUitrQXDonrJoG6eOdx+OYwiaQgc1BFHIFhyIG1PfJkNOKzBT+pFg1aqHGEiKMUPTnE+DZcm7giyMh5WY7QoURDe1BsskMLiSTNxlIEtd2xKpTol/YRXMEWeh/kmYJ7SCh8AXs/arogMYMiuzI8abd7xw5BAERnuQKnhSM0CRozBD84mhwe18ACtTNDVDKCG/biOHMRUbgRXtiol+LJKjv4CRvkbQVCdcxcExHgfoLRKj9kRV1S4ddGY5wfBakkH0bbhtBT7PsKCYWVxBys6aSRy6sQSGLfF7OkzrnIIeVYoFqx7sUJX2xWcJhcjHNg3S4Kh5PpR9gOiIvDmzckbqjC+Ime105u8Ol6kNDK4Hsz+ZMJt5xwgJlqoW6EztiHNezE9Z2Q+j9W/aO3swQ/yTuv3CgM+p3/za9Tx+n2OuSi/IM/CTdLMchRSNb3RfskhJnLRNIX+8Z7ydCy/LijwHYz7YUEC18vCKGQ0TKE6r6Z0C50PcNUryIHQ868NAxTUJhu+jVni8HG3kG9lDlWVkAx9eOnQN3ry87GqDkkfpl3DZahCMKVg1XmKCQYrE4rEcjPEjkNrVIz1ZHN093b5TijdyGZ5y3Fbjus8oheJ0UhnyWQyjg7Q+4dAVFy50hgdsJGX8tE1noIIAiUvxyuk0aXw9HfdqnMQfJBvJLrsoH7Y6jx3eLzIoSWEj/WKCp7tyBDxKKdshiLNKKk1HQB7B+3gOKpsY/4EQQOQhKwtPb2VDSJti9v4qwQM4oRsQcCpmFTYi10GytkPzLfa17JLBqHJiJk0GqxXWf3mlBP3ihrrqhm5L8SL9A+3CSOYieeBFHR2J1PFqRg+CDnzIKguARgoNaEw82PlFUf53F4zQhcSHAj04N7D8KQUJ3BWsNefA9FHAkMEOPDty7GVCUPxYzpw5QxN8U82sfC2CBQiQQlo/QRFU9qEolYLUJ2gCfUdDO9V8AfAOcpdmkEe3O45hUmLQWcG+TRorKedCnsaGuklmkAGTpwGBBS5qMKXntgAYKdSQTlTMvk7azC7SFahCyR0fLUW1ENgEzZ/Q+wcwZnRXnnNZKZHPgyp/Yc1Y7pOxnwhu+xnt4+t1IKzpbZEeNOE5jQZ+T6c0UXuwpUg7aGBHJsrjZMUo2F6TTAOx5HG1Vi5QYDmaW3odIP3pynCadZ4fIX22noEcHXRIAP2cwZ0V99RrFfZhcHAXKBWAHFAD4UQavR9JS/0WSwhw6YG0CUCUGBVoocAFEzAF7qAiGnQBGtjSnfM5oE/6AiDXT+hRgRQksL9ScDmwesL/2oEgWU97cH/1nLw6RqiymSfVsWdH6SvNTynHRBkrtBtykW9U8MI90b0aNVV+RaX+yCFYHcYbFoh3R9ED0Gvd7243aq5o7n1+djKoKrs00kSCRkxBBb6wL+0gnF/GeZtFa+OFfR4nBysKCMjAngYHjM3Mk8KGSGREo6HwYhJppUBBFmzfigmded4Us8XDUMG4CFOVsEEd3EOzI5DhBId2hmif9h3Q1BhR1rPq6KQHP9PZj2hGu04DmAewcNEbqCbDiUiIDt6OdOd4ImuVhE6JPCQFxLcARv9EHuLBBpaWJ3hkyFJjrw4TR1VKNZ3t3xOlHDQN+OHtiuFRTt2kqIb0yEuWC6TZ0oIMEspETfA4Soilww3FGLBvbQQgEIZ72xaizVeTRcBUKYcCX8C7E1nFQrkSmIfC7klThPJ4vKcZnUyhE6sNRY7uRuef5Lml/Oe55ZSTS0YIZC5qZi5/u8euNeOvp3oYuSN192sVe+4thereYGRIzdmB14C3UxOmI4SghzglaDVwmXSyomWaKprg9gtDqci+x3t7uZtCAExzredfpNhrEDw15tNvnMA2GwUBjew+L1V1YIUPKia8qG+MU6aLQH8xaB4u4t4vTQouQ9gZ+QGZ/cQhYm/gajsKAvd9/Kn0BLcVz4h/nRO198sKPVxYawBQufhoxaU4v0t8dScBy7EAndjOCdZ8Wh35orOLodt82A+L122YAHoBpMQ0uXAGdhm6JZZLsc0RU1DhAHLxDFRN2wfRMUiLe8W4/4bRYl8kyOdnPhAWKQt3t7QTNU6TjBQRGPdHRkzjWggRJB7l2cB5WEGnz2hBxhIU+8aDC+ELecuwggVqp7uyQz55xBwn4v5cOf7kaXi6mdJFmptL00CJ/7WB1yDi6YYiuV6BNcxxR1VsbxmVEe217gUxUJlSeY6IyWc08G7wkkVYDjP3v4hJMcaBmJs5GHnBnCmxk9JEJsqeCT06GGKtuLcYAG1BbN3Yesp2qSgYYIz+hRm3j4aTvsDKxAQSH4rELQLaYZSfEfvbyjE4VFt7PGRQ4pMaq13BVX7vnTzDp0zwEBakAQTpCKLZK2UV+D2a93oaDmZo97DIwCUeTLqOhBp+imkOqCVuGk/ehf9Rq55ucKHBK6lEgdpbuMDJcVbCpoXBUUQYwmvewRU+iquxu0Vou1wruk+eizAagtKCtdmw4cTQ99b2+849bc1T13/XrmIrPFxTwQZuc+FQ5uns4b999+4U70WgIBc/XdNK9wBouzahJd6pwbKdJrrTNtgcNHvRjVurcJsRE9zaOxz+wreI4Jwlhr0EjEKesHfszb23kUgHT4hpixYqSFoGcINatYAgxU0DAuTWUHNG/G5pdpNku0S6crHipILybRuqKXU4DLPZMR1M00424Hga1aXjOheMnm6615nxwEIxF2HJjKehp8V/1C2/0Z6slMe3azPhUg+somjyy1V8hkM4XlZvhmI8TDCp8wQjeBGTncXFe6Sy5uFkcHh5KsHRU5kkNAdp+2notVCETsEp0gL2uy0jhIrLtE7fXAPZWCsWtJFic28uJ2/nLxTS24OHCKFvEtlVcFD7q+Gz/chKgxrXDhWDE5hFvpebIM0AWDj2WlT0E7SW2igMtSXIawM2FuKDyY47MTy2gsk8CTdbu7yAyWfqCF6ttSyZVvBIo+FXRNdXMiLTHEp6doFb2pxpdwGEoyldBr4gF0kPaopQ48WLRDbFAvumKUWJ/qqnXPPYR6fzctsRdr4h0fHH30sdw6mwcIlIx0Q2KyFwZQvaf/taM9DV07qJ65oqB9jUJc6GBIc82xvETQzMrNNI5qumHZISIyPm3ifdTAQ60dTLLedHqq8kyQVqSWjf3pxQPl7LZcFZak4Jch6jhIhYy+cZFtJ240B6OvvuXirNH4AJ8kDfcqBodasWRUIhsdCDHrnmA6AxzrYkrw+kdCT38Tkb12LVr+88pPosDavhWR96iCOdU4ac4PZXPTiiarqcHxQ4ijdROEYC1WjrDOnFHTAkH0mDZmZ84amXGrCOGMUeVEs9CFhGqs4J5GfG9HCCwaLS5zi7yjRa6qm+Ua5pUFxqA2IQ97xwqYLU8QONYIUfyXXMgxrebzakJasF/85f0oeBm0aIdBIqSXHIiLfXHPt0J3GU7phyXEQUnOM0RMw5FXDTUsAU9qkkCh+h4IWqQDTsXKpXSvQkLOBvO4xywgFJfayS0DfNAHz0tjq3sap7DsXl/A/J412tj8kD3bSw+Vm4zBjHINkoEsJFQZ7I9cX7YzSxcW8iWYYNv37LI1BAEQTsI7JTI8oVDdSCbDxYLZt4o5faTxcpR6MI3k+/21P3WWLGnqMuoRBQThliQh0uFu2FOsBqaylFcTEUuQFAnMOdZ+e57DAVcgANUXwhjHVVkhvicMJIwMOjDNpL6W2xndnMHyRH84vmFrNrf3kUS/vlcn9JA0aHamcP4DXkrxe2EQ6T/CUmTdH1rEMeVObr0bErCkxoKsOL55/Wo1H6b0yYZG7A6C2jMngwHh9CKMCCIjDXDGNM6TCxFXf5f7sqQgAAHfOyM5aE6glHQOGlBjQ095q3p42Kz7lbI993emrEP5rpAQ6oepzIUP0eJGWesB5KgRhTFIjeA2ykq+luboI1G4xsg5yfIyF2y3j9agT6/+UnJnranwIz0zfZogA0tpTNExZhEd+ct6fp/BKMNwTYdX0xrSn7hNdbOzc2REyajm37mIhyzDg3C9VePkOvdCQSyziEh9aI/2akF09aiiYgGaodM62TUpoRBteHyXlig/cOU6p7TuyUjXygIqWE741mGCJUIu6ADuAdSx4D96gTQCLQ8GMfxz1YO9NkinMbQeIto67rYosxRnfO6HDK3SYqDb8HshGdqREDHkcAQaAQK61pHTICwblJQQJksHgBHucf+wOY7gO1mRscBaLv9oxMDW+2nCxecdYsK9V9lpJ7CSw/jZciQMgtcjRsbGOnABZmUx2CIaXdWSQen4BKs+77g6Jf8IVNZRACK4t7iWh7iSuCgZIiflQoiXUMNdwAZhHqwQMlGnp7PYkhrPXmEQD3SWLfBy+wfz7p2JEc6WhDF/oFiH0iScGIpFtNAqU/u2jQItBHADTCyLnFkVsYujiV+C0bvjdoyQwshKRITcA6OLiTjhJnYoE2RmCaCwEdYbbDzzf0R5gs+2IELD8w3g5n8/+ebMGzD+IYATzjFqrJxbQDH6eB1Km09JQ/zUJo4tGotGwMVioZnKSC2NihWpbYop2yaIRIrXbBAuPdAWz+BKEfEkwLPmBe77j2ourc8JKYGrRA6jHuwM9QskU1RZsiopEhzFogUEp39q8hWN0hQayn1KY34ciiuG2XIbRQk31USJrw7r022IYTUoEmud2fEzbMVZ4D9DB5AzcA20Lb9PCjgjcmaJiarPfD74TNWYwt+H8M4dEEHxrM0ZihBxJMCWcq0E3u1mBZNGlMXtvL9m2aXDBQRqXqcZTtFW8yXP/hn2MRJ36rErjQ2ApYTE4S1zqZILXTaTCakl7uvzZcr0Wso6qDbR+LMAYVYBGWOz83JIELJeh0kmiTCg5C20Hg1B3aWFONEm6tEkfMkCmWY3LpbKc5lcgcqlFzvXDQgW2vHMjgFFkvC21AVg+EcGLQFwlequ0i5hts8uxfiM5W8OMTTfIELXhEdqTCtLOrnAKsbwXqYSp4fgmHnbmfF24pdri9VtoBKCZ18x3kll+utJS83OrzliQL2mskjdnQzYIpvABEUThQKmoTxqf53BJz7Ngpqw/721EwA+/MIrS/AhASqXrA0vhMfg7Cwft98TSarcacDUt807qxywySMLC2psiOSxRK5Urr/ECTaf0dlP1qk8oBR8TIeHeAwCyxdiCdxmiZhBRaEi7xDOO/KdxvYfnU2ESWjJwME8kvtY1ai3+vFSuLrCySAyCS+UOwE47aHCFhU7iJzD2dYitfc3QQFv1ld3/rIXvHtTQSsBJvUU4xM03rUJHOeI7RMixQqZP398jwlUC9RDCOVn0s6kpYtVfNLht3mLhnhoF48qxT+VY9Gxk4eJq++0ouys4ydbNdxoEwcabtfIbKkVPT3Vv1471TunnN3saoxzCCpfNPze545BaPGEpR7IVFqa4o9Q/nb1cAh7yENPoHKVydiEAT4gz+DVrOMCL1pPrtfHC+foAf38METgjj5ISZvmo/u/zcrNJ+SmH1u/nax9Gp2JObTzLvKHcUtoiUmamdquXo8LyE2SQqD2jbapD/NVFUid3Vm0fHX/Ad/KpnbIqper8WaV1Xe4jMZ6HdQRai7LQfGp3nhAkeNt70voiDGkVY12eKo6pp0UWtbbGei48LNy5RoHv1/kVKM2+NccwcoiNZ8+1HHfLuuI/kg/lAH9EWlco3w1xt+F964KiRp/HduyoC96UuTNgiIPvnrx+KBYE6CD0Ju1FgKrUcJsHeLtySWsL/IE5+vOscOTmZVwKXZndb9c62ktnpEYpHVpOPRW1os6q7dhHvBl70y3LqKP9HqOBOnYDn2ti5D/erBfa/6+K4htbpceH42fF9W+I75U09ilbMhKF5Kq3x0wEWED+Ubv7j5Md0py2tChJqHhaugu6vyxAQTYif82VI81d4vkxT8zutc8LIeJ4UpJmp9KWhjYiJ86kLrUUBJTtSiWQYfCH0KdNROkH9I05XAR4mTB8Zd61d6H0GKxmbzH0Swm/am+Xv1pUH78y/7ASM+Epmm+TPWCx+FdSpVqUlfUk0j8FLPMKOdMP1LnUvDag/jE58WQ9v3CNFEK+x/SbuCd85/YHBf+gJpIBAToeMoGF0YZWEFkwEopqZrnvJ2n+7r+v+2+Di+QqVUqgkYTyqjtQdpLpB9WUwN21OMSAM5rl23lrhjAdOsl1ouYKBWUNUWpq4N7hKGf7y+Ec1wiV/GkKBqxyZg81BXkWWUORXvevd34cx/P+P1njwDq8dP+3xNYId07NLvGIzb92ZSBMWxDnBISuK/pOM6COynwg67TdHcPZaNz7ticNui2W7RLehWZvnYy3FrxuBhF5cLPtyEcG3a4O8uGsLOuPDBaPDvGnbKWfcb+3Stqn1fqLiZmkjru/GNCyzVe+lu6f6+hXQtFqxcTm+hKPJFTf0fDSdGodjQAfWI69e/zE9PUeEYpg4dRHGqrOpO0BBeT2cbxMHHcJTrMTKwx96a4qSa/5i+8j4oQneXdBkn8iTSzZHG19LNWh8tNl1C2gKt9S6ILR4paYxoW8DhP5/kkhE1gaoZWHh+LdB5t7MYbAnAsf6R/kER5dMS6ellGtmQtAUU8fy+01F1cTC63D/udkOkjP/DP4E+ciuwOtqC3Aa2Ru78vG+kc8yf8Hf/8EGdUhD9z7dQc0I2RPKgxKMsoV7YJLnxmBPPiIjKVyuI6djOFtLwnWmhz01+3099oZSSBxzbf+uk0rkZUJLrBjyoa6Nei9ea4nFe3D7DzUUU87W12WFklYwSfanV5frihQqP6XFpDA9OJ5L/cIjpZcSnNXxpWEAzrn5H2ZnZP+yviw2po5Kz6XgGJ6DqdrX9DUNNBTDk+PLWtM2MIv/bj2VkQnkW6QQ9PS5Lhw7xvJGs6IlextNgrWshTxPrflbclahfr3790x7K9xvBdTGqsShtQU698Nz+19+535RCj8K/lxF1f3lH0rWNE8s84/cc16Tdz2ZgaN3xln/XcDSWYyzgjnwQKhOhLWubsXg9Gvkdh4pBhcXMeIM/qy0U4grqGluwoCWLjZ74PElI36IXpHEFyF6wWvvQEpiztzQpchv3uqTGBTFmmoQmBsIVZfTDjcwPqlm3IDvdrNaPH0Us9zst5GgOjROSm9AikbXiA0mqc8wR2ceCpF+wptE1PXnwL0D5ZQ5AdNbepA1IZerHp2/dlRZ4oq9f2rOmd2brzQ83TqobGTy9VS71eRdJbXOcj+DQhuI9IlgvW/bVRGfTxhT6PujXI21Cyj8u9vo47D4LwsfxWgFnOkeLQyHGbf3v47sbA2w3zFLNQvG3GF7kERiSKsgXY3WIoDFV14G1mdRpea4CSm6DkEJTPdEQPnofMmHpzXC304AO2ca2x8KEONhhNa7Rwhc4OZMFNhC7MQJ5Qbp0x0rxJSg5MIcnodXQdoUd7A/QS7x72ycsaNZJ2aLBxb7vvy35j0qPjm/pe+1osBVNwZFkaPpgELRhX6t4mc8NRLDc+WbcGm45GB5Odn8AoMXZpuI1fxztknLYV+Vj4Ng6mEADwbdKy2ykU4RgdsDg3Rj96Q6HHzPLMI7E1sVV6fyI7AAK6/FHAJcBHi1QkCJuibfmpthkt/PXdSJfTqia0rGWXuOD2P2Lc7qdT39n5e7awgo6m7YVEhei6tTWcfkEB2Lsjgjtsgqn9jFhxGI6co0NOW3RnkQ97qqECyWQ+P9svcLqMGpNVihs9+yNO482Lv/nG0ibjBkbw3BOA7/GHnD07cB4WrG7AsSPZSjkFszUV2IYOviz5VSe6v1AZYj9XLX2ZkSBtLD1xjWwYmBk4zDXpQXBiFTrF4RrSQ8p5276VizmMF509xKVpuUzQi2nhFCK2wUlWj3Du+A7qYZ0oIfWbWCmkHRthcZ7JNkE/kD04xYx89O1vjpVOjdjm8f9mPq+fL36ufUZMlhnC376z8nvgWJz1m0qE2hoy1dzW/E1kMuDXo6IMxzHp8s5HbPJa5XwhT+5bKyrYOPZvkujzngX20fnpnwDSu3aUgOsgYEXIGDqzUSGBgfin5VDbRXH9OJ8Ol+KHkiqpg3gmZauv8LXmGy3YE48f++o01+4JQJoncPZcN+uJFctHYipbLaym22XTB7UJdXr+xUmzP3S9UWQBJyYUhDf/ej+IQU1suQI8smUpLjQZUn0X9PQX03tfCgStx+/hgWZ/UuRiAmuKIDTg3yND6dYVN/T4qR3vcUInDFOSJq+sOrzZtrQPGa1nXENo1Ab8hAOoVjHNWJiThkhAu7oa9dztzN2TAWdwRSRbRB8KZYc42VpBbXQnRgciruCAPADWNo15O7XRKui11XLq2+rwCB4kzHV9bW+fC4u0TvvbKyP8c/6RZ7pKDvOj7Rk3DTiPXc3MJTSIKixPv7Eq6g8OnyJjAY8uRB/SlPYMJyDGJZYMfmoUMR93ov9mc95aeaQnoTZHp7eYBM7M55pNECE6vNp+N7pOYDs656supWBK9Bi+10Ty6CjTeMEakWhn9NulNehqAMI64mg/QTMcoLUJmV7Fp7x+QOJlf3SjUf4WPPae+fe43QB46f3C9gvV7AnG954CRd5GaaSh9fuCoIFW56mXINwNR6gTcJTOGd692gX+hpaYvVkKEZ6lP3M2GRu54l51AIjrwuZKJCE8zAPqNTrWEcXxv8ycGS9geyTOdpl/3BoeLkmrtcOZuLqHju2aY6ZeWUQo9VaH7oIhS25jGILCFz3uv7X0HTnHS6XtHNk89trAI1zAruV+WIXHMc6bGNZgI4DdZ/TwLY2eCB39lNzlY3cJnTIZBDkZQW63lYQIfEkLXJSTK0SU22FFRoo4cx9SSl93heU9ET8dt0d9G6GTiGs2L3tVElL+Kjq8Rd0LacCeFtLd9H/AbVDB7lExoC6bpSWYszafbuGflRqATo3wUbd6YqjVteDUw5Rx61E5Jgj5OWK/X3n/EeaWlVUYl8XMsVHoVl3mHE7BWn7qODRHDssFud31qgFFPkClOThrmkHKnwhgqUD304JMg6Fm6aIpYauJOns7EO8eWqHWFU6xYWHUlL0ugijD7whcNBfJpESEVv3N70m82k6f7YeKn1zdBZOnv8i6IBfu10P7aAwLm9d41jSGcO4yyhWQ/fRj8CEhKiv6wdYckm96/NAtOy5kGLo39/HHgUaECXkhHE8TWVeVbp6uAZzdoVLJh8zSULjLq/bBnfFjD3ULMp7BiTqZkvEuXpVdesyoz48OmhykbjWJMsPWT/YV3kV9cpjoZKV9W6kEPRUGFkeyVrbInhJ8vmCAPN7kMl+bLIl5JZqZlQtXIByOtppnJjfT2rWWkJkeTG8U+HS5O7tzgoD2fH2hMhI2zc3MrjqWrxcu5nmtQq4tCOwDGOq6hLUxcb0PBUUsLDOW9VrMlKa6Bv/BQiVxeVkUXcC2zGWSczQoENUZWcWKq/LKFWh9kxgTtjBmVA0aRZva2fy9dTqErxbrFpn53XMDbZr3AZ1XPWyLf7TpRUEEb7dtUguyxojJleLK3szonAd/cDeW0vfz/S0jBmaeYUu9oQrMxhUTqfrBe9Vrc1Yt/5p3HTFtNUvQ9GWBGZYtouByZTnvt/o3USgqBi3qdSs1FJG93D21B2tw4SHSbXEEO7Vj8erlmDFQguZGFOkAH2TXrBbTpHFlZVExzCyvOECWTSSKA6hSEGUewgdrB/41MwQapKantwgy1M+yVSQXWG+Gsjrxqjf/f5pRty8OPT8QYxhhTaUEw8VbYY2aSFCXEcdJvdkTRDxoTnzUVg6tQTmWm7nshRKrvg18ElQ55y7hmC7K1l/JAc8i7WHyguZVNbjlbzOHfgtMKb1D0mzddFTL+C8cQ+ao38XmHVjMCI0v1oL8AO4JY48ycMr7FqjBSZ3JLgyF0O/mOWf9guJZKXCGuoS8fKCOMPi3Ml1oKL4MtrR4FsjvN2zN6GCtM6HRzQ93h42gQWwocrlcMqstyGsoEBRiQ07GoVBaq28nBg2WpeMLFunBnsNm9xDIeVihdB8clxkOGiyiansFj97i4c19um4umE3SQ6hGfD7a9b9RVWDUOISMhIY2WMpWi6iIukBTY/Ep5thVxTNx9uZu037Lv1f7UYcdkQkPIzQAC3xRTPkSLp7v4eZrT+/6S2Wt7H2hFErvXs69tebEcflQYCLKKPk6NEr6q2+d8fdulE7ulW836zNk+Jb8vaXBZeK8jitjVYQ6J5qdJ1PX1wJbyMrSh/WZSVxKfGoaWGvrRJUnANSP7V0YjYpRoyFtWuL5/fphqJTBJLWIYIRgzXhThOvKy2ZAV++PZNHi/betb5Vgg7tQmAqTpGAHX1UUAlh/3ENXa3ImA+UJDlBwt+eL0AdcMIiRBz0LQm0U9qKJHWpo5NvkHMAc8kHqEcx2M715sYi3g0EBdaXTgiAAtcBzfqgd5MNrB0ulDUlpSHafrQLx4m1JfnH6MOxQKuoix4pmLjycl4nHQrt6dZAkgEraJc4D7NxPt040TcmOh1BDDCk02COSuzOUZhnRXJcxoaRtc49vSQY90mbzgFwUi7S9f5PR8oJb8K2oaPe64/xgHv5SBk/bI5frgvluNi/7+eFFuqlOej4DqI1usTk8jmWqNs7TIzKiex0zp3Wn/WkzojkkV3iE3mx0VRnePWzre+CHT5bGuV7HbiY24P0fAj5m0v/GcWAzcaQuAC1x0BtstcKfppMtVtQpwk4lyazsdtw01g5bnJNmhPIpd+gtDQyY5ULadSn4lioGSuBgd0MsQZqEicQe1qtnqJGDqiZK9beDLnKPgRFFzViqafJfJ0KQjyburfAsgFKt3wYN4u337JEdDOYNrdvsSDPC68nErgxgAWcwVe304iY3/rXniyNT7lzNcARmKPv6fJOQdf3zD2AK7ykHjZ3lHWip+sgLRyAtrXnaoiJmPXSfDib9i7Symi7E6rprI6H5YeQCVR1tZux5youfVH6/ImwuklPPKkWWO+RAgi71WUd5aIeeBftdwIDNl4ltydzRJqtNh0sLh0IWb2NieHzYEBiXjNqbbQrbIy8iFKsKolqRqYPHn5TxQcs0xHis4UmllssWLr7QmC2WsVFDzmsAGFnL+cclCPbCSQEiPzfORF/mNdJ0oK+uRkMNHRdtbIPXL0wi3bYMRZyFRsDBCOPUy4V1tkH+wY/Cc424ZVGQpeZkGaSNO6FyH5hWvdnlwTzhVCYQ0rN5rMnKESe3tq787RtqTsFIR/NFaCNQ5QGneVN2zMnFjZ7iBx6zW6BhbsuVsvMrWpFMAZ5E556BRGzZ7iEWYmFz+5pRgLhzr7vt8mydjjs3yJUVR+cx//woDbO6/tRW1EvRasxrv4uDrZfn4/1JZVX7N4u37W+ZFNyECkYN427nx12+SSgGLzbUs/VUHEy87emuF/NoRYzM66azvG2kuql9rN6M5xMkwyIKRm8o0GpUBZMK6yyVXmaFyVIBSHy8YSywoKzMEILeZ3p4GeSMl8AJfF6vMbOBeokS9ypoDRSdiaUutI6HOYUU1Li50GOEovFZxiHG0uxDmjRXLip0/YqBiiJhxgZSJj2kyPOLjZkHVJ7VA6CqA8Oh+MpAk7Ubw+Ui6Eg4O1zkpCr71fZQEifFRzSaIXJF/qTDsut2sMHX4gnXn2tCW9K3smEBLKn5GzGhWE1PHU8EPWWoqhUxQGC6G82RckNl9yGlMAsTOahtM6BMqVlvaYjvOkqOdbEh+uSdfCPZ71PFkafMsXj9agn0J0RRsirwai1EgJ+E7Lc2qStusNMUNDYULHFDrV0tb8QwOlQcTh7J7WqIWy4RpMsQmmJASet1b3WRI3YyIPCYJNRMz21kaHnZKUP78N+JEJWMUVvzDnRu5POlYo/vpKFNlBClhh9X0TGdXzTLW1lTilADwh2pWb4mDA4PtSDmmVwOgCTRzHqzYOizjmCe+DtqmUCXoPG72no09mI64oLXPs0N2sGwv/mozbVe6kSNwVBn3rRH1b66FaGNSEx1E4C8Tpl4b5bLBu43hiZKXStvC4L1QSyeUSuHhITrg02GdxaoOtjCQvxFApZeLY81qDz4HVazE1V3TXyTugJNo2smpftr5JkMWeMd/ktrRnIoMl2TIhK3scgxjjzTFi73lgbmg4dwtavJ5JDwt73ZuacqBo7MAQ8BPSCvH7RneCUDJoRy4e/x90M4T8DwdKFDNvkANQZFqAOtxVsRdiqkWeF/XlNIgi+StBxaIIvrQjjkJp8rthY+wCqWFq7XLhRmhzmOoLpn3OcwwZ3Uy0rmY+wcRXzlPU3xa1iTTTEfYaXtHTr3MJ/uuKf6A9IxDHdS7mkFOME2f7TdEtYnmmq6BtnoD8rX0kS2SVEvrhJTNNzshwmzw2tXNqurdDOa1/BTvtjoe0uyDLvL6D79B9X+j/YlWCOgqYprfU/UDTexVhpfDPNBgSdhZgj03ACP8YeoCerF/487EKKPezc7cSAUaipVYk9iDX296ceRwpZqXIhbRJkaqNMUZ+8o40il5m1a+5JxxCkEtOCBn7Va4h6vYa2movddA7rzTOK3ei0Zm4W+hHmKYF5fPPvWPNNtQR/RzKbrhl0tsqSC7e2/eis9qTUNpeN8g5UzL07YoZl8i3pFFzdsAHHUwtvKknl0pTxX5XZvBUZbFFjOKnS7rTl0FoQhos6xjBw7IWGY1b5BT94cHS9iJepy4uJ93jSL1Fzwvp1Iyd1lutEsSV/URz0y4j51tcwUAnpR2IYri7OSaXAPJ7ZubpBYOpcjsil9N7nfEIcAGhvBHbCGU4Ny1OJ6zFoMau7t1GoRxfAtYx7poaZXbR1B0dXPMAnqvNOnt+NzFpv9neLmLD6ba2/1C/zWU5fgDxxOs4KyYTm/b8A9OC+OKoRNOo2rZMZVbtEIzYIalyCjtOU41RL5983HuO4Mfg2U35qLU/mIo5uN6FIAhVh7ww7IggWfS70wgZXAmcdK3YN98Xt3K0MokD+II6nrKhrUYlwtv61ftXnovqEKUoEF+bT06MRDN8yB/1kBu55oKdkrIcks4qXWPpiMI6knb93RQrF4u+K6VfRV/FEg6PQ10izCKJ9nkT0KlD1Mkt1KE8vwFY6/JqbJKgnoSsQiL1vp7QvAMDHmb7PPOFwm8KvfT8qcV7bWnXss8smMXnZXZFaGzK8owFdDpXjGnz03ekdMSxyC0hY2m8tLphS6nIOrNN39uuzH2p/ykuSufGHQg9h9v3K2iGIitjvp/2PqLEqivS++5Ji5Ke/unWn7+VbenOqNyVdvDFPI/r0UnkVqgS1was5a+j2dSLi7C1KFpJMj+wU/8ELkpuvUJeIOl19Ep/+AFwAyPOE3WqmVCn4ikeLajgjKFrqHJ8h22xb47C+1rqKi/24sFncErVG4nS5M9YVnJ0t82fFmcBXExAXfnoqxDi5h/muCrG6EjxYIavvp8o2uPD5qgs3w2tF5xpw0XMHSxcCuQCYoEDLAKCSH6xsIskSLWdkMquSToL9UFsBLtjqVQpzkdK6tsefA1DvhYK7i0WlViHjU1l9RnKM/+OqVvBv7NedCZAUqsLdMriWSj7GkZXdu1oQlQJMvH+D8AhJ3D6QGSWXDpiQqpH6nTf0yA2uxYiCUNHsfDfNjVvUBcjsh/NdRH0SAyh01P5QjZZ76y/pxBPT2kUVDnzdSKsYj0GJcSW7uU3UnMTP0fiBPwvfJUcYGOXbxGFBjGk5E9rj+SGU1N21fw5pkk0b+7D2iMB7Kc5Ij9gBHM1Ymw9Eh6eQXcWxke+rwg5wId/NB68KKN7XHKrMykogMHvXyytYNybgTMPt02iyhfd6xm6vPP/r89SjWS0+3Ogg8YJ8mjb6bqpX+PAmwE6Y3LGp2dBAYSMKxf4WOTA4789KnQT6royDDp5daHnyIIpVFHy6IEslgUTKoPTiLvc6uCv0Jo/LW6H4wEXJvfkonosBGxVusNzbZ0aFEb67b0oyiqCJias2FBpYkWUKAZ/pnmawDf0H76zUIgJmEkiN6+T3ELwDeDYEVIii6H9bKGxptCCcQINdFlpe3U4d1GwzNKxBegGoBFM0dlm6w8gkDi9VppxT6rA0L9jrZG2HAplYlxtBsYIxiRA7YYtQ8ADGrpDLi8gEVgUBbv0btjcB76nNgAHqlgOmr7xQgELKD/nGh1ab8WNwcCBNCrCtiyeWxQkWtkaDGzcJWbta4LFnrLHvEkE3CH119OQrwMc+r95q8Oa1lOdS/ba+P1gIJEsAn+cSxcAtrQFBRPJEFYkot0KimsdeWjAL8DppVX997Gi9S0GbH5TmoQ1hxxzqZFAyVozZAEqtHb71jdn82PAIrJ08fowfemxej/IoJEmCAUHG6EREyiGHkQK+Bq+g7oqiIBC2FvsZlAuPINv4eAu8HOmqq7cNj2le9zQIMVWgwrIFYDsuBw8ln21Xx/Ha2O1vAMB/OXLseX+hMxkEkTDvn2HIqAKDWVO6orI4RbabqXyT2MoymHjaHgRla8HCAJBc5lufvnqjhJQW6ttfIWkAv4bA/eR8uhoJiGiTkhmk0wDpGC8F4qim08nTizSjmVdogGCTTLmT02LuYRDTcYq01KvdTXbKILBC7EfiEH7s5J3Xo6noOKW9gUmMI/v3aaZlAAPCmnP+maco+L0SSp1vNTPee6iP1K8DWcRFxjsNpiNobZR7/w5dUfn5ktR7WaSMjQ3a3p9No4tUnCxuaB1zJAqsSxZabbFqnvZspiAt+z7rOp4nixzHKgLKcHXjnWEEGCggkKzzNOmZbXea6jZSolRqZh8GY8M0HTNLPETyxQUL/phxNAnrt7IuFu+wIVpF6bDkX7EN1olFxf0I7muqRUNxByAx1YlL+lwd7AgogG6qyhSBiCLEFVWC03egEJRWhm8rhRHrKqfQ/B4Sv+d3+XxCPI/83X0BJ3DKhxNkV48p2pKA8ltag/x/dd1sQWpFYhNEbjU2U6kOICPZAhz1ISKZULBkgG3RfOOBVzzsUWsOhEg/iOrVK2/KYu7LDsTr+4AF9BckhTGlOc8/xfpiSyTesBojMy8odz+03h1gNswp6rtta75lY9p0S3UB0orpVNDopR8oTLJl8hRAK2ZLrYQKgAmmbvsrQchq2ZvhzdEDRQ4yZSFwTPAsZ8Q/z6r9UKr2Khv8pkUuOSoxFYEyU610YIv7OwdG/IV524k2g8GUtY+WaeT2qBcUvediMSOuYT1GpvDUFcKL3PRmc/dZsc0PxGXI9mFbGMm3gjht4FEdCgFfvksgpFRiono8/jytqiuBQS00lqruTQZ1quPP9yd14T6CcpCVx9GxXoegqu6hLYdIdDyMQVMvJhpgtpHgSSmK/LFw35fKHN0M52aDAmfKW8LjhXPaw0xiH+zX91tTkGHvy/XG7Bk7tMdwJdWGYVODtX9hFHjG7qqDwm3vbe+YoHjwuwoTPWDDhDHkRkTfZsMqjfAJtCCuSOmRylipd+Y2tI5EpoplO/E9tsAYqMuTMdfAxulNKXJ3k+O9GCqLIWqMWBuJwXHGddWIkP09W7CgZluLJMghMASvVFhLWJZyFptZl+j7UeieY9tWsBRqrfs2DIgCogHgSixKX4n5pZG6P0JLfANQUcx6AQRQJtH3jmkBByIr1Glk656nRmo3ElUxYeo6aCKksyzOEXC0m67TxoTbwA3nzrzuUXt5lIlyae/RktvDiUA2w+I/iNqcqV76NCsbnlE+uEPtbg/E05rMPka7WFCDCcO66RH/g5nDlKD2sIHE6gak3qLFD2aKqIGqFNRgQIGY8GNPfz4kijzn7YV40gq0h2dARTvDxo/86Tm7ECnE4puM5filRT/EprX8Nv7ZwYlRGwpDTKZp8ibfjIYpJteQ56pIJt2Mu+UvN73B+MhpaRWb2qQQm2qWomRZ3g1aXQdB4DyveVCa7pKkx+7gZ5t7s/fBLTHdb2iRQUqyUtB6eyeJNqEaeI7QE3xjZ7+4sPU7wr5XZ+m+86SorObiDnPw208c626f57+cvxTIMFsIIKe34xjmawjTHqbafFPhWAEs8PlESKDW2HxRaYHt3e11dawvI9S73lSbV7z3IyvfG+SQvMw/+dDYZiQKnPjUOINtxvbpGoT8OGSTO6JhdwCCNJd479lwWOR0TX1CQ4lNzrE8bh60pGl4135T72Ome40AEfUwQtLyz8DCAuOafDG6ea2HMvz3V91wPnW1b3ll08tSYAdWPuS/y+9nC4qKsCj5Y9GuBHlHHvuZn0uPDTPDu+DJT1pqHvVwYsDuvNuEAj7wz1oOZSv56NR6msS2LqUwjH2ncOGODEB8cCwyAlw7QYNshzW4K5zFZd1kPEAATSYIbRHQrpcO1hEW6wSIPcI2uolIezHWvd83pRN1zndjzPjQTkcl3G2vp4K97nnpUhl7Fy3X0k1nsANwnOZSwEqW636OnZXfzU1bYd+bYeOKN4633pmSBCUq4OLWw3FxZDdzDvtPI4BySLACUd27Y9rdFtdvgDITP4yIO+YVRiev29o9n4gR3gu1ar3yLGW0Sax2mrG+9EDL49Sb5QJESquRIMeC6MoKaoO9khvFelE/32y9wEck1Fo+J8Om/T7OgchzAuWHbatGIE1UJmkaOyX25/BAlm2/6H7vixABSmD07C8SIN3T2eKa6LgVRMLVPBeCpDfIITA51v0dp08lerDHUnAzhgQENdecGyxKAgxIKSrujE50OMP1RzbAMfI6KU/hkYlcrGX+gQXkWiP4Xl53DpTf8hq50cq52xbWlp24vbcQ+pRo6AW5GaV4fR5g2fON7jNtgkV/qOEQnJLhVsGYwQzZIQfhvYAvjiRyK2JRLDNC/bnMQIhOPCMUUym25prvXBwHxUYZQRWSpHgSd7HETUI7BWupn2IMzCIWCL1dfLyQ2+4FxJoHFCfZISBXko61pmHC80zEjWOBtjFd8BRjrGugE3Eo2TGccfqcp8q2nV2MnrNW4TJbxpSPtDoCCplEo9ySsW+8MgcO8zTUlPa3KzFtxiTR7ohJhG4oTyUxspkNTw2zW2bipVKQdQjsmDiC5tOkGSBz9QJL8v1EybiBr2zEuoC2JMRssMljrDk511BmhY6khjT+g6+Z39ySR8SLNlArlvIIQ4p7d1irOC76deOLKqYgZ3GkQFYAEwuLSj0HSfenZd/L579BP1YufKYMpOEhB2XW+6S9hzjS2sKEZpynTatoW5FgnDyLIBfV2VfYoSYEIPM6gIs+eTF2UlvtQ0tl/dSEaphwo3mFyhBfPrtx6fHPi2l24br805R/WHwjMDfa1KAWujIr+uTTzpBYi2HEdt+Z9Hl9MYgjy73/0n3Xv5gumY304NiP1UiSjqdfQvSOe7LV46j9+fncHD4suUKIJxPvv0ja6v2aKuptyTds9jcHmT7SYysuZ+IYop+TsMKy86DESqkM8HxBHTAJRG2k/tCyCDrele3rMMVQrMKwj59oG7un/RWeArANVxN/wx7CGwqHj0sSXNSH3xbLGBF2sZD/xH3jqyrtf00mCjO/i8zkZkSx1pHFDxupBfkdBvPWkWBgCvv3XAePiwPtMtL0BByNrK3ViheVze6/io0RRWVWyYqzLcPAbdRIM2Odgmjuy8VdppPHtPtEpqDmQbSceShZjTyARgFrJeT3fbyh7bF4ddpcGBl9savCS/MNMrG4topmWv/3QlyyvywVcO+pJ1k+G7NCqVjblK6w43BRBbRYnQ1GulLe3A9Nbb6Euht86KBdhqmpvqADGuHtNjaHrG1FT5RhDTWmekUnhGnL7vvz/VuRlqboysEOmzqd3ki7rEi8gri/mWTqgd02DBrjexrdv0/eq56WfRiW+sq+mmBjBOZCcM4NP9bDjS5gkPKR6a28qoea8HYhNDJfqWKLc3fx6JC33pDUFRK8WP0aEZba/k4WctryDCWzdapwGejBXJUN8+btDhoU28gCzaMClnsN0yjRG8+Ye9SbIjbppETcdqxbibktliYu9CaXnEQrgcKm13TDhbI+n/pOg/VEYWjkaSj0q7UiWwjFCsb05130O5Co5w6MImJ9e2l2ukFCC2cUZ+pOJUhGxPmpaOABu+hmwEq4NJBg0HQGEb32hOi72VrzQ94vaVrOfmFzZGygTcEzv5sfBKs7K4NKKyiAcwQ30TGvXGosvah+ICa7TSS8bXxELbGBfpXbSPJywfjLzrccg38xfAfF6pKQBJFAfAIzRbBdxj0eq0CpFtCwxLpmSY6uPwqwi9IIMYwBDfjfUWbLVBilYPEg/mL6djJ1l4aguDz42UjgzhGvBnhoWDGvHCKbQVwYSWsH2mSazoDt4VLoVWHpDChGD4Tf30BTnBTQNferAO+ZhzfHaT6R9ahaog22CZXblfLE0FzoO1NqZJK/pOLth5yEeS9AR+U5dz/MUyZwvaAtPquEeMdWlT7HIsfMMVSSaT3XvKxP+EMx/KGlPjiBVqoF1CyYB3FbCZd6gI8p9BGHewFGovd1rPyMnZrmKQtZVdV141/MMeeKq9uU4Cs8Zyc7/9OBmdX4jVyxyoPWO5xMZLX1ZGImB8uLBRfx4Gxy2IqLeFxj+uSy1vcOT37kwuFnSaKBAXExgoV6r55aIC1ujOZHxiA4y36TN95ydaXWM3qeGrxLrFioF8hDClYmxMAZQuwjemL5zkTlfNJtHtV2GMEqnMYm1actepyqdx57OF2k9U7QmowzwoDj0VtWsLo6AhJ1jhlSRj8VO2a7i2s2MQUACdvRldIwSUZrfM6LQPaAxgYEixEHhvcoM1U0UoNJ2QE9sug40O4zWxY1ab+gyOqiD3r4xzEInPTLQMTz1M9d0GYtp38OD8HUkBgI5t4ozsNygToPzRRDe7oj0KpB0aLz7TeRDtsLUW3Qlu6bOcVbm16HUNDyxaTZDwNU46Mxb2h/aVfITsZu9pFmc1ueR2VIUJ0y3ANR5unaWJHnfYwLqSoXzq8lL8adqKDddglztPR9Q5JhRbHPdY3mSpiXq95DFvI8nIDZOq3BHPzHWLD7XJMXMqa3lVmdYCkFrIF1WbmnW+jPtw8p1puTl7Y590ey8IntRGrBcAGknuZQy/kCPdpmhU3fJ+uX95b+lLfUb06bMZUrbtIJx4dtYAfYhhvWvCjxtAwJtlXmuzYaV69++77fRMrT9dfvTO5utCHk9iod1eZ76MOwJrGES2KazlgNIsZDs29EKgL09q779xD4wgxYhkVr7NLQs2y0PSzH4I9R8bPut3AzoGCcIrShgnMdgnAsvzYQbs3f5sultRqU53MCm8vCXG6ZVEaIg75WG8rhtvIehtXDB0QAkPQZckEX6Thgq6nNRSw21R6nQCCWy4h1WUjKzwnppYcbChcdJva58ec7mCWiAO6HnEmPjUmYDrt2dDsWll9dUi1TyHi5Zpymcx/e9nOhvQ5OLobeH+fTl56y1ZIRCkPpEQL5impXVbx5Ykjg3ZTF6ItkKF9y+d9AcN5G8o2cLJBbUY9Nff1NRZvX4dvIB5RgLg71aRIeEgoapcKIh+8pDvDTDjnS04KLFAehRblnBeHdGrqd1wvpdSWz5qTn2ERdjTO40PI92ppP2ME0uHvBN0GJIseVYPyDtXUQqcSma5h6bjwak7nSCGs9A7fm3zQN9eQ51rfGak4ZPk3NTLaQgt5YQFMfyxuieSpL0aFA3ifuACUxdf2wFpwbYuCVfNRclTbSXojOAhqBg7i+FiWhki91OcP9+6uhsjiqIu8/yRJxQso72gpB9sqf58GEk8X1vn9ZOmSRND06GOM+SH+bAV102HH1Gk0eD57AEXYTMAI7yqzmYzcpPAjhpyAKfj/G3PrAX5idkx7+zeK5sMYsZr8w2eC/wMzm8gtRD2X7C/PIMnyHbsx/AX7S4776ZDMDbYm7cdTdji6FLk1oTwSzot1Pz0TMdILbv2FqbLgXoh/T3Q9YbWzwQumJiDOXu9EVzrtnt7Jv0y3cwYn7cuqutp7Gl24E27t2gBvnV9/3+Sb/bAL0WeVW/FQa1icjQSv9dJY9ccTJRb+pZJs2Aq9HwXt3XTQ4EHh+cRGh1pLckjC3nZsIXhq9T0cS7e+GLmGuDWOrxFGNCLX88NeAtdvU4U9Ylv9Awt2m4BlzocnLcRlDluzM/otHQZ612E4VkwIbDusRzBjoi98JRqN6aqzmZClMKoW/TZhKSb+VCevSCqraKlwMtlXF5YgLP7IA03RDjBpce4sqvtBVqxTU26E5SHhYENXBL1c/h7ViQmOHpf0DSMS6pBLU21Ta0f8VMCVbFg+zZYwTjx7GnBMVkTBscOXb3jOwZkkkINtebgXwUldYxWT6bdkHGKPtY6gsk4wLkqkM31+yxslD4f4wWa+vocer1LOw5zNF9ihLVDdL9dOSu4T2cVMWOnr8mkGHgwDfALhgBw60a1cuhVkNMgl74NfwS6H4egkR1VwwklKZKjFDbCOvlnjiDlQInRSvycrj0A5tTIpRlhnXvZRWZSleT8+DzVnpsk4hvijl2qHwhGnC2fbRVdkl4V6w83BepqLUzmsaUcKRwj2fNNw3U3vBMgpKevFIOi3pxzC9Zf0SdqSLivDMF7ly36QHKOWRbCNrBCkStkWCxQXurxc/dnTBW/OUTBCqTU2lxJdLiMBIgXnBIog9rIsBzQ2SZ0Snm4vHpDieiTfKewTBheo3HTfoKA30txZ3EZ6UoktEHoyU9z7Ew4OnEKgzGnVXOMlyXvp9QBRsTbQZEvMxcpBjqrzDuJrzkvyzxwt1rrUBEhzvdcpy7etS29SKs7HwrVxAdNtAJeqbVXF4EF0rkVt/5sdnbMadd5daRynC75CthQti9kRHsOtxL0ZdVlcmPoqC+wLgOvVQE15LeG/FxNg4Fr6V60JLqn2q+KLeQrCzLtV5XVrR+A2tJrTXX6+lObAsg7JCHBZBmSbSY0nryqqMgZ0epLcAHH6BCIbHUJHdPWxpbsdE/LYGHGj+Da2in2CDAo9YEuH0+axeM67wDe8pYgLp2ESj6KzH3so7f1sY3FzfKmiBGPmYh+3Vt1v/QwIUjfXv0H58wxMdCcfxje/yckqx0y3og8faGRieBRk2lDJI8ix3e7IYbitWzcvYNL3WSf8TbaP2yowToj12ovNzZEMKJnZMeMsc6EH1Um3t5WeczREkSU0V+zYunaRktgTguJ2L8CGVHjdNxbmcqlaNebK4EoFJbj10WiwK66vPGYZ86J76VaLXAECVCB7pqyfUjCYNXcbGvb584wd/n1aekUEUtVYRlfSPvptQME6NF6F4OaV9vO3TVoKhZyxZFmjzDup+aAYFvSAEIU47EJGOhZjqL3aNvsvpcMHeFJvhiZGoB1Zch94VTnIEZnkH01ZlNq9AJBONAmYlbaR6NYtJlyQVQUXVjd8Wh2pVahgrmpXATTMxDIVoqMTcDJqb0PnigezmmTrnbFWnGSmRU6UNbUbkdDmhgcxiYdW90TgxeVWOWEZSfeiwMutNPYzRIWoY3r3Fx3YXhxmhxs0fKKAi2yb+JjpmPMgNQokqvGFIfUtVmWCRVgaXQ5SbosBawkAWFWdIyMIsZmPA2nqTMikF6GT6ZtQyKCf7FbtQVVYMtVBAtI5bQVuMRDKqy2b1kB6HIwyp6PdaCLzRLGOk3p4SWUysHmkKuGsaLq27bZMLV0890G6XeqEQF20Wq2ZYJYS5AW+LfR/pWn5MOTbIUyOldel1zKFR8Zu8UB158is+Sf0MP7kBBV0NIwPl4O51jyenOaiZW1dBbOrtYNVhOIcxtwKUZ1tZU2hCg3uqifqoGiTGndqxSd1UEvb5/K6z7AXqUpeXFOOfRwUU2XlYiBlRTMBepNwepliv4LmWg7uugR3KFHtWHNu6l8iQ3lCMPVTM08o3jC3XQd0tpMKrB7EXzLZ3Hiqp0o7axN33zMzi1j8pq38U0ceAKaXrVRVXOkI+lwZWJ8eq1YENwuf4Aw8XzgZIHswjdKPbFZaNL7RxYgCBuWrC/SLUWvHh+FLeBKElGLA3/23fDU3dml/8faLCZcMTsmhO3pUxAVjtoG6JoujUROTqVaXE20Zq+YN8phz2Bw+6b9HLCujaekvFqg5dc/2DmAMONBkTZZjXaGoXk9nuKrEfl+p61LJ1/pHjExdaNe0yHaoJLgvlVA/sVm1/q8dzKhKcWsSuGoCgGrr1aLg7frto3vUX8tEMDfdPUmZIWEd5mt/4W+n2uO7mYzWr2vpeKJmUc4o3IxwSB94rbMoNUNF5fIiYmF5QVFpTJUQOVuyS6HFa1YcZ4V4RmLpp2jHa2PoQEuzbJ8ljr50bylh6jh0a7vsaic6xbFBreZuU9aKvem5pW/DysOUM2/nq83z1IDFcoWWQjWzlp3DWTDP4t5ECDa7G6+UdgxzxMFctO5g2GbXvejLjcMpCguoTps082mhyJFsg1gQnm173J7AEyFqCw7eveeTmUyKH9Q+SpZMsnbQyklZGUiRLkSydjKWTsfQykV4m1D0K/mDwju2r/0F7TzADAzFCM+V1Y4vFdq2TFwtEJ8FRbkqG8E97vKRTucCqc04m0TeBp/E/ego8nCwEQ+5st+BZ6EYHDe9FtcArO/PrP5Nc0ukkmok+Hx+inzMTH+m44940PR9tN5z8pj5dh/bbnJhBzbMdBf0M8CCjKK7C2Ft6cqORIjtHEHiL4rKGsCOOXvhnSzr1NQXWawSp+k0QvgmYkUhMMo75SRSluw+XWWEvevPZ9FEflg4OKzMi7IPNgPBRmKsKG8iFHmGD2hKMgkAol3BR9xQhQd4UC4VYhXekE2+/84oEKG74gMpfllbV0Mn+jkpayxp1zVvjUvP6fcP3vchaTg+zZUQtv7HkKJAJaN4IxqrIU+WCGBegf+a79xvxKn2QFLqobkvdo4ftQnrJSfb0IVGNWr5Rg1Arzv02dU1k0PyN0sDuSf7eG7nVjf8PZhn9V64aOg3o/OUSMcAJEuAS+gMMmsB92C6kF5nGrychi1psrXOdhLAU5ip4GfEeHKgo0kDQrq9GydBiIdALWu8yv1M3B7lcz3KHnHQogUAoKb5g429Ek7RKJmub059O+28zBkAUnvG0YvzG2Pp9onBKcf3k8ykNFBx8S7DpiZUQSvMQqk/LQ8a1UxmUUAtDUZCacQccUP09oMMc/KC7YweUjMkE5Zwoze4SV7gPhdnrsPnb22mfJgqOn/HDY8WZ3qi6HYA0bUsxy3kNRZsb2oq5xqB7tXyxnm6pkg1mHzbAzVeVuec8cIWlN1ADsP1rc1K/CatOVgdh1kJ2J7SYVhLT6QbgDnLT0Hsa2HmgbX6DC8wK6nTy6/aGB+31+HDz03l5LhRQUNIJyPQSfdSIllpJPcEXiM11e+p41q0QkeX6w4Ys+tz5D6Q+P/q7jBFtreFgAkiznTW9WPuWGdrKscIjxB6JZGTzecd4g3MFN2iuHN899R8wlgk2ADpkaWPb9+KMITzRvztDUdlPEExcWDE3TcAF1wB3a6fb30bp1YVq5lEsYoka2GFU/dBnD9J8mpGqMrcSI7wA7LxKoPNOp/3+xvU1zmifsmgJi2SGW4luZle/gh8dNLVIoYktoLBpQtDHU5bLi6UpCS6ky5fIy5g6GhzvKYyTYX+ZVE5MCQPo5FJ9J1Bk0hIzSi+uFwqci1uJVo+q0+m3UX+ZimVjkgQdaq4vpmaiRUqCpTgpakacgJEihK05AgwJ4J3yVMeyPy5uCdfP5xQPLWDZW/8iylSSNaOXO4Ojc2eOX0hTeq1NRrDrlQoAO/IFfR66VN5idHJeW8+uoO6uS2DcylTz7gMvLEvOEkseAJICauTDmtp9/kTzfSVF+n/eUvhTMbLfumbKNDI1txKX2XEPCZOa3sb8fmtduQzEjw7DzOLCBU8EpUW835rgXl3arQYV/WqJlcQprTPlYmFAZn5w5ggeMxfwDYxluu33J+UP6hbtw20Quqxt+vhusSoyncnF8msI97byUeam0OG9G9ceWsLMnugxXF30ePG762/TO7cDsZ7Iib7ZWeWWNg/6O/5dMFURuyXpPhgiMOIWwToy+jgE+muREKBdOpz3qYn/gsFCLbbXghvn8XxS0uM93tSPy/QVG5OpxQLCqtToCIaVrT5V3Dq2/w42zsH3Yto17J0ug59t//NqnuKFuzZE1N05kNeA3qU2YNAXQb00ow6M3XD3iqlDWqxvOmUz4q+pRZq78GOS0Bh4L6b9azHtHZS6uMhJ7rnYe1V4MrrHuvNjKpKJ4WXTfSa/WzRNu2r6fRM86ddgFm+TPVqZ7lNh0M7ohj5pcZQOH7XwDiTQdxCuQbdCNwWlk4QiaENFS9VhksVjn1kLntrGkFmtfpPK4HRcnVzfIDzQ2NAG8RaZGa0PuPGEC17UGNOMGtUZd5g518QzcQQDd7xD7xN6nvDP4I/S53waG8tqcBCvlfUBNB62q/a8vdtV1NVvlgUC0Mmd7zYymIqKVjRnh+uLn4Tj0eITwoADu6b2gvDsrlg8+aKJF/zj/sec4dWlj+y9vCrG6knHD5Kf8dJFMqScSh3dh0xeSVVeMRTzgm2E8m6UStBJxUFrTT6wv2sDNS/ztCv48yb8MBqj/Jbex+ek/txZOtM7QMWdtXIOqJ6a2pOvC4yxJeXHBSuQnV4GWZ5fN4GKF9ur2Uxi0l+4d6SLjZ/vbbokqzA2Jin8u4xGK68Y/37sHphX2qKF0jQaWs8/2ticnz25aBwsUKch2NWe80r4+bIWeqV2xCtdoD59Vcda5Ke1I3Ihxn7gc9L48+a9IM7QF2ZyK1A155FTjfQNDrxDGcotOjve8DX23CN7RmfFLW9rDtMRNZKMASNH9D7hyCd84qdRZ9qvflZtTaZm7qaTdGg85E26210nraQZm2aR+o7FF8Z+hJuxrzruRZ4QBsyZ9kJFj7DmiQshvq7t/NTdluGNU8c/5Mnocm+t95JajAPtsew22MXDa1W6o1gB/dkZzxXzzSXeGAjBSNdk2pexLa2qLzjVYQfO1+eKyEITztNPJY0EiaPppFSBjHq2Pm5VJYhutcEoEYaKPD2nyEpwXEBrMRjm14q3KxrYzzvQywsodz9xlqxrek+Z1j4jIXew42wUiVju+3Pw/STy9VgFAvUJmEVvN74sAVNtnW9NB+mP/uilF6hPwCx66aWXXsBe9EIw9AJm0UsvvfRyBOTKlmXTLO7TC3hWBXhWBXhOBLgNueQo1kxubRrn7/OlFV/ay43oVqmS8NMibZbDIP4BgYdsYEAhxWnTX/Hf+00YB+xofh3MePg4wLF9qy8auHCWIDbDDzOuOmYczJ89C1PdC56ugpt22H/ryVsyih36Vqs4vhNpHv/Ayhh1m/CclIl2fQtp+gd67Jqut3jHd2h9wDOfMAzD8KKxoXLExAnFCxor7v0ekS5cbbuewk9CLTGjztUTNB52rOP917u9M0d045lDY0dUjg1OsWEbN7dTynTkIJwQNFdzzyJIMIZu4pp5Cq+/pGL8+L6R0eiUBn3GIKnuusPN9KRBcgNMpEBjYmuO7wvMmBcomvu6mHHngoZGGjLLg+2r+fbMk3nQOM5pbx5GYNE4UdnZ8XKPELm53ycMuXjI/1ika9J2QiiSBRnAYfJ6bV+XEc3khkdFa1gyVsIEuabSBZF72LNi1z4xl/iCgqFHQhTLTBKnYT5HRixtuD1vYxXQTmc2jPoS3NKUBxtPoGd8Z2zCTnbMFkMNLWJzaO2AQczuUFyaEDmfUm8Rb7lOFNmemLRMWhYP7Rkg4/NQUGtkQWuoymzNjMoeRgyxOkM4LQ7tXJlPzgtlBZTUyXFRHNt5MSU/F6d2/pqB34qLdu7MzAfUoR3MYapoBGT2pALX84RpFG4uxNjUiTY41zTWYf19jgQy3OEtR8WBsy/hLFWoi6m++qLdBCFGIEtgupEX4rGLUOnL3KgcuGpnDumU1vnQgPgC5FVvUVhqtM+oxIEHLHbosjS95myaVP6ssWSr6jzzsu5hBA4hp3mTNHXEiuMBc1Jc7EmUW0pcprxlqbIdgJMcpqc9pWGqHOQjHwTlOe0yhw4ISYH2Dft3RnL7Yft0mGKGczBg9CqXCwFfxmN92df9DcZK7qblD5LaAHGT551AsCO5ikBmKZ2FlOtqKHLY0wkXVX0F41vZbRmUFo5jsmVT4w6wB32DC4HSJSlEi4oJAHaQhxSHdq7MJxeFsgJK6uT4uTi282JKfitO7fw1Ax+Ki3buzIy9yVBBKrpy+Cib4hoZSStvjfSzAEthK/J862Kx7VPV7lM9qSfQWkv+GR13Jn7OULWNVhxL5HITQr0vhNngSfDCUgOGICsRxAJqQ1AHeouBbUX10AszZ0ze936zR3Sj2fA8TYszKMEtqSSFxQnSQYAHgT9XaTx1V8wIiRYrPacEs1plexFQ/Y+7D8wKsxEkUaej6Pj+c7L6VDp9kz6/4BVkCwvyD9Mtwx0cd88Wd4ItWytrEX49SZrY94/AmbdE0sJLbNbonBqVN+qNtczq7lPeHbcLGjHzADkDuhGjxHd0XVKA6NvLUA1QG3lOe94V5mAqY4ybM2Mv0lpVQFmCrcapuL6Kp08BnUxES1PM84JqCCJs1RSishk/ksF0qgtzuhQH4N/4W7sJlu33rc2Rjae0cRpld3FT978zgkXwhRODXr8s1kpok+bA0Cpng5KgqrNUYlT+aCXBRQay2y+3iiCnmNLfPLX8ANlGROhbzkBMZqp+L92oZQzi+dX1IZY0+9RVRdJ4yjJFuEgPsmqhKevRDL8QUqANDznxSV0qfA8BCAQhA/iQYxSHcSha7WTyqqEX8EDBDgTVyWeL2icSbtwgx7KQNjZynxNpyOiY80azL3hpB0UQs03uv0GcSmu9KvJisg64UFH0jJR+zgBHzqsBhVnb1RTOK7sZXvNWzl01KeoTFgJVrIWuG8ECESRvhsB8K9KSjQbzg5LLdPXDbdyEeWJTnaqTjDnpSXVg1ddNHZSAcz/M0MrVUnyvSayu2LxpEtr7wjYD0Q5bvUOBjS331HQP0BerRwVgtsFcGS0t7nmmAHwNcy/YCZ4COqCex1lJihg+sZeVoUcXGhHvU61FnYGPW3dNXTbZdMCv6sQ4aUaRD/cDEZCBeYzofB6NmFwKVSz0wb5T6FDoomA3h1H9ZYpJg9EuMKFMsX2X+I8dKT90PgSmFZGoGxG+g6aKymx9fCGoLKaRAzH9zKBerOGC1KOsp1Nf6ndhxuPlpVxYrc+2wBncdZXmbiQmPQWce4FMiqAJLfxsrR1bqsBlx+2CLLF0/LBNwX4odmsFzd6c6eAopL4nTHFBwdAtS19uwxK+5hMHxeDXkVQXRnmQ8Cil6UjAK9xcGUkovo5HnUrVMwbzvjdZEBjXlIlSO1fZysuAV4scwO2DQGQsX9GDOwPbXnqxJtEQq0q2GTICotXRTCuewo3JMuKwaFDJcSG92sSHHG9HDviApDotu6Ru3zlTyZlEyFn7ZKW1tc3Cy89ob5BIFdafLAGxaNF9RCxYavJFd0Ewi8hpgcCE9oWpC2VitnD0YeUt2celrNhZI3TevPFgA2PmMlGJBREWQYqRe1xkHnXweyhxEUjs7R4KXIikgbG8HEoXpbHi0mVHDuwhUSJLQy5MhsA+TaDV/QVaXHLUwntilCQO1vRb+XBy9dmhJWq/gUbigL0AhG8Pb95+bXBLYgqypi3Cg1FnxEKTNl2NgBb8n/61SyYH7EQYnM7mNhbT/WSqMUWYmgErox2GvR60+GpWV69zneWOVXsUSApnr0qN3VIrin8qT97LSY9OK0WBBxSwuGU0//BTqufjHGsAOwJ8IsqrdhCjj4djdctlpCCU8Twn2u9nWuBwSb8xxdYFRm5Ll6unodOt2BorTUIqc1yoOd51vxMZ/WeeBqm9mtfiOf94qOrd+xH6FgeikZNOtSFXsVDl5xJ+He7angXNf7v+13RL8fPI9XJUvf/JZ6/Jku6TXve8J5flam+R/x6u6nIraBLdjDJjO7PMSlwFCMyIrxcyI80KBPgknv+MiJATqHLIggzPfby4SMqas8hExTo/xUD55XY/gWxARE9TnJEkNPVeK7O0xHWCBMdPPwDKLv/ti8YBpxst/v2+jNjetfa4+u/f0/tNfz+oOPz+Fj63Mv9zdHX6v9qTs3jPFXnGIDLnNFM2ZJo/t9ytsKVfjK5GxAsORVIU27yzz2Dj9duShl+koNneQhnp0X6WruzCsfYemdWkiS4m3MPCWInTLiAeclBiEQOFfPp0O8KFO+9GuAZf3hpKgE1yWqhgtMH0YyUFy4BTE5ivP2RK7GdNMQBKSRNaVNkf0YP3BoW5aJFGz8FsC/MYbHBYQD0ae4GhaNYPSLcGExd1oZH80raauqOjuLAubp/kMCv8CYCCl3eiMFRYDblamPqol0C57ybDiAzQ3/aAm7+hMNFs3eIYqYjN2HlORWu0PvJZYf1eoID98XShe6AkPADn4NRXw3n6qPR5qsimqcdhuFhNl2tTwiRcvtkqiBgFl6obDFJCGTwzV2PziATab3rKx9a/JzY1PVL9G0qa9rulYwALqz3YXVlA3gozcYWP9YLSkTRMiMZDx0dt8LJhYsF5pMBBNhILJ9vBXgKVoyheRYKXWOrd9dQG+P7pQ2bRxB4ephvE54jtcw4VKyenaq1AsWeJOqaokhZnkMw49AJb/yKqJn65w4KQ7bmaBEmimDwgiJXBLtUiQeSlgo6u9UmfCXaJPBte1nupEE7FdaAYpflmgaED/fEbRCTPSNy7siqchC9mDHGakKqVp6vhkqG9V/Uq9ayTBe2qaMzM9054EzQA6qszpNd93eGN2zKit7RKtLkkEF5NmXy403DTQju//AVATcxoO6UdDheQtA6zmzDXHlpjs9G7Y0JaNzuyQkBmjKFsi+JS9049EpfEPo4pNNNTqfAPK1Cky+nsGqv2NxP7UWCLuAjgg90BvQA7RaJWRXuCx5ocJReCtIhurSZniQHsI1zWalB6FSRIYB+QcPLWxVIEcJ9F8S0Hn212wVrw+E3KFslIhN0v2cCmGqN2vpJQTh1fFn9+hcnCcG3ThMNFIv/WtHLcf+qhJ7Wm/3esWZKknQK0WTlLD+yQtppplzYOWF1ubvYlsiJdWSfnx2BrDX+vwxATLmJrn5QL0aCX/zUiqwhlIyAaH2v6YXCclxnQhhgv4gSOYQabcAbdoaygU+UwHlJYmDxYcoiFySMQptjS7/hcKKhEZGwNQHguOAfUlgvudSZS2K3LFjlOf4ISoBC8jLHzxYu6ZnTJ8nzbBDxB8eCB3HJnfipl0cO0vF/fbADGjJqQmsr/KbgZvISvb+aRVqe1BKI/ZuW+VZ9RR15yYp+MlfbuNm/LFjufRM0CCelnRKaXS16YYEgT3QncTVhiIiRzKSiKKuWhjG+TtRhzScSOwSE2OyX/xQd6qauSPgYH9Of0eYedO5Opdwcz7nwcmQP0yhKOBaUAHn7F5BPxN+KJxRz22gJjGqA0qD9u0ZmhnwgPE/OWRykavVTJSo81MQDV0hIdWjQvyPAe4ayo9f+R+slKwTMW5+3pHF2Coj1FibLJaR/8v3OKaB4nC3RTBZLXUE8HkaQ2Rp3d2ALhkpAYYLyb98NrI3OifAbFFyJkh0QEVLZz2O6K2OoQ2e3Tgm2SNnyy8Rj9f2islVIj7yKK3RB/uvwfkiTdxPRd7PowEw34Z93E555YFvY1GNeLcVxy680JYcoQ5pBKMjJb9xocqXx+9onJTiOZH6zqz/VYXMehBculYeIZa3u0mIM4vv2Wl/q+77BzvfQIT8sAmkCfwgCy61hlADCM1XI2KRHbOiHbotu+K2mNDUNAbhlmZkGexZxp/N/jKDKvk1I7kduoMFmMg9eSuUQZbUE/Q8tMmuGKNMzQ+I8YnahNFf8Me7+kJNz12GFkTQDnA5mdJaHecTJL4TShl7OhwaIcmjLa+TbZeZO9vvQEFUwzQipNVtLAmnD0PWv0myXoXekwN4QHHi/qRKsVgVaNv+/gu7GzX2uuleYn/KAmckqejSpW/nGI4APeKgWLuQak73qbSNF2LMhhthHrRj10s74YTzrD03TrmtHgTvWNG925HWriAu95nHHXzumVV8sQW/drI/rp9ysFNYah2rFvK0lUAox4cT3r8mVHcO5szJT9B4j87jQ3Lz+MJ5ztFCdMkr63wj6AtFbhPbcPynunCeVWhwXaJUb4wArjte8jhLSXTDUPrZ5ygmA4qXIb4H5nA1wiKVAUbiosm1/FGDYoZXt+sHEr5asUbk4vMUFMr6f0BJjC0lJSocEA6QtH9hsAU8IxPNnOXWGn30XHTSGCa3cwZrt3ylk7YWsVMjzvXTnG7MqryEAz9R4aTAEBwxVuD2p67IhhyCKSdoZ3BQ8bPaEnY5ERNv0eOCN4M/Ux/ndEP4ANuoe5sgWO5Ol6ZPvLzjbsUI0IeN9ix9OarwJXoUMqDzfKw3FKbxfwd4pF4Hyg8DNkq0aTGcDzT6yeSjVgYEhjA8Bt2Ja1DxdtA9Dyo6xTS+qwLggcGTfAXSYOhWoM/sdB9ceVcb0yR5Lfnkk7J0R4wg7ojhk30v0mVm/Z8OuqVEUyq3AGBG6a1EzMzcZAs+kqNM4DCgyxEv3CFNIRmr9ufyVwdPYSU5uR5CkoJDE/bBvyXgORRe6tYCVsWBUmeBlsngceK04BRpBoWazHIa2ewPwoNjfoW90HGaqARVhGJdiTPFyqLIGeAplZlbXyPROWh5g0LWEMAxtwKewRNpGLYAVMTkjFiOk4d+RO3azjsMyFxnfhH8CnMPMBZ7kfHEJYhQGom927fr3EtslAB0e5rtIEYS33Es8GPHt38sQElWGOg2gDTiBq58YLgAbZa3D3NiZzXwix5t46H0cqoqMvQrHm6ECMjUH6GBCLnKRzjwfx0X/62nhU9fzflnRzB7cOGEu0qMEYaBQXGeVAECyREHZAcbI5JUko1m6QYR0mvuU573TgqyMPpg6BWo1g75eRneNOe/eNJzSU5wgmt9pKZCZFy5IQVZsVO1IapTS7jOmmOXOvyw0tuWKp2mJmI9khHOsr3Z+u5lTzXaR7RdxqFlbYgfbKlPa6W4lPrM5lAH1EkX3e8jkQl+/EILVg/nvYWYddswlzj6JSqaNpp0dNo3YkoFTHVYh7dye4FIx0D5dxcnAntYKfhvKSzy0p6C7ZOeB7r4F4Ku4LgKqHkBJQPAGF5ET3Hb/PAbJBR0RkoGI29thvNGRHnJqNc8hZRp2EoKtE302X59myfA/L51SBok5ZQOTBngwtnHZjcPsx8tdJYdbsgHG6fTLaE3/gzj7/szld1boZTCDr059Xt8CALKhq1NJOD6NR3ksQU34DcIDEwu2kc38hbBjH0Nj1wVjRxsh1amaitcxtwlvBworhtTQiIdNDG/QuE77bsDmMwkkkML1GViER4Rcmev2mIoYj9wiIBqFyym9kuWRZgG6B0yLR67pFkdNE1LFO7IP3ruJNQZOZTObkXEXZnxT7m0mstBmXvY8btHa4si+rftZONUN5LQ4OISU69YFLE8yA+RU1cF3dsag/LwntQJcEgxzMXHacbau6j0w+dxd/9E4BzKJaVKWTM1wqKoXgKZoLrJS2show1npI/H/YhNYzNmaC4LnDDVnwZkxsWSenfvCHQOPj9Re571yRsWTPrhtU8ypG18jz1gLjZoWdst72Tkr9pirjbyt+jIqC6Uz9AV59SSBzxT+9EKlG/eRzHQmKF1GMIJSXoD1Ustpzv7i85kn3mJTyIih1ZDo2E/XZsOqqoFzJlkjQDQOnt1lINhpqBkaLpO4k2Ny/SXkqZvwJkXzL1kxk7tJF5zPSC9+hX2j8FSk57LTJ7ZRsZc2V6g7MaEBn7BzBOWDVDkDeNhjU3aiLuyCBmNMVxmH9dVWKtKqZb2mNTU7f2hIIP1PMx+mwCMOVcJfl8mt7NS3FukK68L1/eFcIFneGfShkMWy86KMOsdRZo/tQSChnBTbV+O5Xhu1HbgbT2gpCrCJNJuOwcN8WniZPQxBdf++c/biuEgv1yTMtQNaEYhJ762XVMlezR7O3+r2IwlnJhOMGSoyUuyj0Geu7Qo3FYIQPg+ENMzeDvo2o1QNA/8xLGctSrPZO1JFl0FAkvlaWeyQsR1NubSU4FrtKAndrfJN5TvDiLpjk4zoSTBUQMZTyiTotgYDm2P9MGrzaBjUAmPOhmcTwNyF2WtDkrItBoBhKVfFeGF7htmoRDNQ0rktFBWy4qHblWXmvCuG7sUaOr5j3xQckY40AUjVFFNpRHhQqmBJBwlyVrVNTprQN3tYxTyPGiYfJRvVYSOfkAidNvHHj/SJE2VqxEUHwF/Sde/pE9PkB53+I8XRSXiFmvhFfJk6cu4aJThDclACA5ygdi9SMr/K0+ue7RruovGA9F9hbhIIkbx31Ri6DNTDCSQlw5nfoFW5BdISAnGtk1AbGfxU2WqB9sk1oqv8jHcms1EeX+E4xTXLYoDwncCdLqR+rknN8YMUB4u6usHifyJoZ0NCI+0mRaEs4WNze9gWBzU4sJDBuxSxfEwGIHxOVd8pAQ3ZJpkqPai0ECDjGiruTm0bQBr0uV/aFJUnBkyDuLX4uFoepBI/j65QivbW0qNa0wyUHoC0B7hY2mLBX7hN8mXgCwxrId+lzsNe2zn1iYfKFBdUbF+pnezx1A1CCM4JXG5GNKarzqGPw9G34bSOnYbM+3xOwYj8BgR74QEYGjAEUVGbLCJ47geJveyj+nj0kmqtT8pAsbZzjlapCzPFC3PQJEGXJBRnjQOEpNwyAObhZiyYPuz4NY2/B1QDPR3J/M46G+KOKYbC+H7nzxUkWvwtZymasHgBhbMmRHYx1PA1QTx7UTWXWCKMYd3k3ttZvRBtmqOQ7YvyR+XyPq/8yA7+HQneva/aNBICvTHwxuUcutguxFu4WAfyAHCiogb6e9QLQQcvba1MaMd6Yni+SVT8vaecWCHY5FlLK/QUwXf7WDDJCLzGsr0HYBxo8plSI8M4PL/01olkvGMD0MVBYgM47gn/WI3of0kPm3tpXX9QdjtU0hNj+vi2/y81vNNo4OtPGxWTusBNVeaOg4jD5Djn/53/1SYc7TTeyrDo/pNeAbxSflqmo+MDnoE0iFanEhBhtfgEoUtG9p/GWK3IP7T4Mxo7VUdzp8VUcSWBb8bYCZZhXgViduB7jOxfIb/y7F6eBrBC6E4mW5oKfK41oLwIY14UUvlCtR/FedPUp1I8cFdVHFeowhzpXiekrAnvfqqnNG/7ll2JQgZsONE03bxr8U+u5xz/1dQmExRker060frT8Nv6MzjkwWVPet8Zq8hEfLaudPxssDmEJFO9OUYBfaCikDzj1pH7WQF+r56ntzP08lKSXrIetXTV+2zF4rM3WaNO1fjtoXQnHOrWbKQ8tVMcP/D1yBVC5lQn8Gf0xJvJk5MfONhidyxEg0TsrawtRzJ3i4euvjI22BJF8xlLQXdL/Ne0uH0xQn9vEIepYl92WXC0Wbb+Tp9Uo0ZXvy8n+Jsa6+i8yKelWTimma8h0dNObq8tjdgrhpoZKVLCzJybHwMgwvrfu0UHkmL2riZosFAg4fh0GoAL8dI8H5NHb+GP+s+FP3N5Xq28/ev9Qf+KT+y3N00jZXlC17MEk0bdeD3KQAEIjdoHtS7PFaZYCpvVgpOQWVOGEGpbC7srAjGktIMUNOQe8VhzJSHbBg0E4i3bI0bzOpFQpBaqHDXSBc9oTwZo+Y5dtGgoiNq1+rxnlRVW+T2riAwelrRi8B4/rUcp3Ez8MCSKfFB6TW20yvJ6tXjJ0LCledsT9WsIid7vAZxs0hy0YMmAc3H8vb6uMffMCfPQvLthdrRTnN1iZGcPhdxJnlpt9kwWA1U+6RchD4ygxGg7eKCDgmmteLbYAGZ3l5fP5D7Ym2rWkiONP6ePyxI450+IF7GDdePLYRXhV8omvnrKNgR+8ABJlQn7hKWKY7p0F7VLnkoXao+iXZEaWHaZm9nDYoSej4Kby4VDYI0vr1E6O3i3BzLO81b5T9KskUIg9/DE770BqFuccDJQCvF93yjtyhCA/0TcvQCdUwPRHeEBOFpSW57jCfminreRQfnAebthmxCPo8gGy9FoTu2J7jqwgYc0IIWggnEsDDdruEmWdz0FctECPtbUj0qsP2lgdQpNUFHBiFnfi7CmUqmlgFSybjtp7rFtiOEcsSZORCCaRmAsunB8VFZnIw/uTjI7KuUaEQ8O6c27n43vaH3qshhq/JJZEy9vxkEukbk4YdB1pSZNMaCAG98U847qyKFG3cGlFjWhnb5pBhBp8crOSpBNVqN3rufCcCoTCQBA/ecT9PeuxoPeeRtcc0OXZPTeY4YIePBCM+QCxUEN6qoG977y3P2fpR9hPjjPZ+bWZizaDTc7B/h2g8/LaKdpg1Eq3pG74nITMnb/Ljgdqv9fGfpKTz5II44g9SuL3LYyg0D/+IMhpjCSO83KL/0YK0owdojwkiCQXuBd9MtF+vyBDjT83s/n2ywk74FStjaUEu/8JmDEn8eTox4QE9Tuz8wh1m+G/CzhTHTjydy25OWHxHWc/OQaHUHwlGfRRcz8l/gPj05gQcQC/kD2ruwfUq6STC/8eMscXOcnUDuzXe3Jao7UvHQSVTpc8whXwhXp4sxQLLC0ZJWtkkH15aG573kJ5CQm1wuaoIAU2VUTiODcGIdb93jve8J8D29XQ15VyS21u80Gm7Z5li2t3Tkgmp0gHZaTDiCt85UH3X+/hcCTc+N/pw7Udrmu2yyhJSd7GLR+SNLR1h0A/XgvLuiAGZQqsPzvUNkMJNnb2thcUdNGYDnMRpT7iz1gGI72G9QQ7T3emenOuc2CmVR5LTG4eiHFbAl/bPEI2SJAiTBPp4RaNml1F2y8W/tvpn3eJrI5QNCu11bZFxjWE5bpo/uRaGIj1WaQdrNMZWfHAVy49euuwfG6YqUePP/L6J0e34Hxv9+5P9BKRwcqJOxL8QVqZsrImtvQugjLFdZvgdCXDNpJ6H+tpI+1NiCAefiRjPlxNh/jYGfsJ6bLHgtxFuyPG3UncUKTL6Ge4zyP2AFiFNSE4r3ivuNR6i0rZHR5nPGkIA4O9EzlnFzV2fgr6HdOKm1SFefsMx9Q6/MOZ0pN8YHcwKlhVM4ADzSXWIbDW9DbFTtjmolshfAHn1J3Z5XNlpEKPppSp54JOKSpyZHDZO0r6nkPl5d9o4LOPpPIjkxaYlAOg0pxNcXNSlT03w7n+I7a2YZZZHuOKdUJslnVypY592LJXRMUHrdE8kn94QjfBQFe+yuPm0NCGFI1JkqNU5LZii+tLpwnnbC2fcvVLEFieg30m4F7sCVRwsD71ModjfsYVcRGuvC5OjzNSu/UdXryT1XYS2BkDCDQDlFiSUBVADLlCICwhxz9kqR4p8T7UUn9rej2Hay6CFT/MKOOdPwiyNE0eiMjyi0/SLebZ9Vc5/wSt95dfJFhVygoriEpfVbZvMqCZmCrC+k2qyVCTYxRCeVC9DOCKH1QzNisO/CUjJeOurBxYcFzMbibOg06fq40GNcvaNmdUqVQ9S4N3F/ZMWOjUAqvclM9YwgjpR5A0aSJUlUKW5qjJYi5xUM/qrdhOnVlUxgzRY+mggwFGept707ZHXaVx9LT5kqtFsFulrK3ek/RYQpxN7fErT7/cJirOtyOGEDhtSDs3fnFvkn0ZlDsS9qopgcHJ/ngvrRZ+VP5eh84TqzHYCvRBeA5CGrZNC/KjMKwrfJYvUlBu0UHTrA7hg7yZduYRXd9HhTRHN5gtuNjLHpsbkBy714+jeZqmZF6ihkCy63dqdRdfKJVJzu4MjSP/afc+YZQaNv08bkyZ7b2ndG3VS8tHkT27vyHYoaB01QT0eG1okG9Q2G36Tg84vVf4w82FpIg7oy3Lan/tyO+sji51p6iU7UKOWjulqrQn8qM79/lWOylu5WzGru5o9Ky4Q4pkosZ9mK5ZyTcgrP88QFOXg+mv0wn3bjsWpi02o0/u+oD3o7MEauOunMAFGJVy/41T/B93NTvOfPurKbAekwrf1dUMWhH1NOHKRbEKjwe/8EkLHMH3Yy0MzLaLjeBOPueOpbZdeaVdy53XusvTuwrf3XW/0f9zHF/cWdDgECNXbb7bal/GeLA7dXwfKl+mWOVYsvU5UVnmQO+ciUNbhZrbo+EO9JH5fhG8FS+WEHR/PVqj1MNd2zlu2J7+ppLWlrzOl4Mbk+XKWPhWLgh02wjZhBilstr7LzLzlbc1C7q6Bd312vM1Fn5fXFJg5Te+WZLuZl2omH0r/HraBecMUBjVI5yit12QoKWGFhzkex0CCBQ4glqxTtYHP2E0WJjWn89U2d/jdC68ldtIDDhPVRomJ+VBEEsSV1pcfHjTqKbG/HtoNofR8WaJvbadyfduJZBKBdXw9SKujzrGFuwn1RpZxSdMs/ZZbzOICr+86w3E2KnXlxL+ZkgqjH1vqUhB1ZfUKr7zVKu491G7imGyIln0ISHkbi2xSxqzN8trq/+78VxDlcs4NYkBPmQoiNAeGi0OR8/Rf9sJmhJYji9pF+2QxhXALFn4IEGP6YudV27SvOD8hIh3hLHUKfy5pYMSKRuVUFQlH+8bD5lErhNgNmlD/kZeSJ6iwJHnOTNSiZ4nwzW17Zq5n2DEGTMVvsvry0Qc0+zwZdJ4VoGh1VvQfDWjIukkikpeWrMayTDOlZNeIn6C03QTdT5C7dyJ5aOpu2Tm5QSDZ2QVvrtL57RAez4uU19Fm7vubUIY4RrTUzjCEzAiR1VsQHXQZ49RGX+9UVVAQqrJG99e43zwe80Xs0OK7WrHn4dJqKA+oiN//Wg1GPmhQuf447c26Ynp8vZ+Q8+vIogvhPzh2I8qK7Y9uNxSp83DzByGY0Lwf9Oq70kmTm1CTrS+efkrFSGflNZKexahXk3nX2bNnL4fQx7kSK7lp3D5m9umrMMxP0kKIQLiiMmp/FdyrPl3gs386n9ZW4eHnCcKKL8btw16Eas6x3dehWeR1rvyAe7qVAEsjsKctzV47nJXGwCY2f2oBA0b+9ei2CGyBCJUJHMgT6snXOPIGdsIEOY5wfoZgW0C8iq6HpngmunhZAJMLE/YBmrdNdyzNsM3qHJwpOP8GoWFKNDShCYTvWz+KQuM39sbk22ThlUnUoHDN46iiwcRI6qxPKnHCl7DmHRu2YVnaxT89zvFPOjmsMU9fIleIu0q4w2CQWnwx1vz5yeihHfVMjIcYHQnQkn95OCiPtusK/Nn4HtQsgE5jCRCXNEz6MYzxhTp0c/n/QU22aOG7wUZ+USyHJHPZIMdhI6d0Hwn/0pokD000239GAKcnohyBz/wgJ+XU/mYHjdt6X9mvGQG2AUY3qUpVc8cIEBs0FKn9qhbI+eyJE5vGxflonbHGxFe8fio4GM2aaul+g9s6neYl3DPzIG0pkXpCyZWX7KG6CKxvrdIuof8w2C5nT0vreGrC5ibyOuSTz7SUGb/PI1WjqJIFI/qjs6PMtu5e2PcPNcn0nFuAs3jmdY/Q+56QR8Ag8Ih04PzFFAaAjvXyTJ1H4ZVyZLj4fDVYRJItG+alEyeXtpiyjT45p14FhQFCzLF8CvkoMNUG1dK57ylpI+9zDRWmMiuEUzf4EiiN0bSJWHlqnhGHLNvo8FOqnPw7BBaFGsbJo0s257qMQgvxPmZAKLBIzFs9wAVSknoMOwr0LvGRBGR7z3Bj3BJwAfb8zkxNACkccAFQgbo1OZK4J9mJDBdBLnZlN7X9ebfhfTm66UhqY1cqUkKVypSiKXCl2Iei13KCIYzqIwAQOwJQfsFiLyo9KcFJMyq0zHAw2kyFD39BpDDRAFuCfCMv1nAifwX4T0AY4k07sCgEGaIvpZsVgHFpr083gKw9+rr7nv8/qJyfzhWFws/XPbpLkZpZ5op9Y63Qd62KzeHb4YiOp7wqR98IrAeh4d5MMwmymAqlEhE29XceKEBSLqu7+8u/3w60y6fafE/rNoVTQWm4tCPdAE2aMwHMDpWcDiP0OpfKOFJ9/qvUPjI4S0+/D8Ja0IWPiWsc8Uq/GUKYRMRMdUfMwoylHdRou7rwzUqpqjZRIN4V7fXuGcKYxMtUrqxGumYaklm6PTd403RiQv2q4lqQqry5/5CQMvsrzeqaytDa//Y+qB579GVo0sn7/TeGhi48teQuVvAq6wvMmaKxmM0TP+xCPhPQUGpSiPN68sR5gRPbjsd+THfOsLfv6y6FBm4148emIIYw3EMh4WjDUcdEVVEaERkESHBcDAorH+paURdprS5e/5XX4lQfyRyMYpm6Fnnc76aXVG+0/5LR/MP9yFP6tLBjdrBkjqETK73qIRj/0cKzD+3cAxGZPBBHPj9Vyc69l8++J9fw6BzfDFPs3HwXz7wD2uW/s+WqTVTFz7eSwnOuj60MTwm/F8+2n8Uqqkc6w4USbJWUNG2JrlFJn9kMxB8xSM3E6HIVMjL5+8e1v2Q1LE2fUGMFOfZt4e6TE3r//KBcb3qmFpNWOBf7qmLf4WwOkjolbHlCIgwlpr1WLO2NdmxCWici0d7nmCBnDmmlY6sJ53rttY8xu91s5osOK/h+C/Ow+L1ZlTHv8aB9KMiHsEsMvMNjbv+XiHqW+5Wg+Nb0g2avaoTOO2yomXJV7pwSsf9kPfWVb6DwNt3QWca3/gYs8Y5Sdlw3yyywQ27IzZ6ZyBPFDSODN0mRB0LwPhzadR3JZ7FqOvjSPcYLuUklPIWf00C3uZzfctdJTkSM31bu05CeMHuAZvEOZkIN2AAqW/j17QEJaV164uBJX5chqEXre65X7JNUCKDUq/77VOFxexdfqWii4pJnzzBn3++7Kgcs4zUkggzHI6O0jhWqNWGVoH2oxUWKy2K1OuTt6v/DWtLtgSqDKvbn3nEfAj6xwtpqJg7VBCjAPwgSxiQCvhlR9omY92xPL/ux0jNJc+gDGQW64z0Zf+TSIpg2Y831FAEhWsMhblenoiRMBcVROuEDk3F/isNnQCAp8F2j9oygQ9AdspwddIsCtBXw/mD8kGFDS27wpxvvhLOjN44ffGg8wZ8HoKPc1U0iOhZ+NqaNv6pJ/w1jSw6f1fAsb9pHrNSNz0eHpkW7jxKr/UnwY0b1a4wd3lmDybRuI4jj7Iovuqals4bhERHkah061nh9dEje6/R60UaVt/IWMurmdfYq3amdFdIp6R0W9rq9pSn8j/6+jKgoW74e2UWcsEQ9FAOipltqfJmL0m7JJhL1hkQm138olzstJzR1NRJTPXJnhp1aq/AtWxcGYsxcD/xlH7KQMlYYhnmgNiJZRWK4NKo3RFr/tylcodVR8IXEuQ1cdtKTzOPp8q0KnfN9RwgxEE/1FUVbtyOx/dlvReOmxsRPZoQzyLq08lTAkPeNSqLN/j+LAg7+FE1+KjUSEdtrpA6V7hpoAT6zhMlFw3004XWAxSmEV2CcO6j6kCdqBlfWLsAxUTObX27+8XxHhN9Vj/zocvvrIS3lXRTtZdH5vIQmpTM7enIGPtj8jDtUmgO64XuqGAgCR9/0LrESg9sYjDYVoaGrwWDD7rhk0Bd5BB6UukTon+/NXPxETEpinfsIXasmO9CB4soO8qiqpnZUwCmuOl1kCwLs1vTuMhudTo4WbiTgkVNo3pLRNS7fjoKyuVkRFIuNZ8p+Bzqy50NMLBYQqG3BMLb5hXUex3USosl0ggLAVVWSZwsSol4bZ2gy72iQKjKo4BdK6VGPDGxTYJyTzV6CEUdO1QEftEmRJ87Jym6E3VguhqlwcsJF0e/AC+lIJCDdOf7aDjiWF2cOGcOwUSbLKtKu3HINuzX34wD/crZ2teKcWEv2NU28Wh1GPK1WoH7H+r/Zf6U2MxhuKcTuH6WKuTbvOTJWpJrLG6ndD3MMksziwKtLwCRP71JO8Trjn6tCBu5C8SqQ+J+v8zykBOgQTYeO4ooUzZ/9M18zUB9NRy8Hqw7DgufGUHFAF7UcMxsyUOBVadpzRkBcsC7/QGmABy+x73rjmfxGxCfvdIOjw5NWiZ+ToY6hyvDHQWcrUOS0cEhwX8LXzElhCvX3grDHYv2kNCh5OgHc6G93DRMpKc3wNyM0I5YRFSWG/+RUKXIm7xJFJ6exrlfhQgpUtD6kqBnbhr2lwNlfpikWc67qiNT97vGqd4tpzMbLdf27PHWNlIIOpsejzAD/waRrwQDSdHgsFKpyoG3VTq8feZk/UQvT92nKmR5a6njBdzIu4QdepHRluefkjHd+TLCNAOMeiW8w/cNlRyMHVai8j+O/fvUjHE+M0gmTubu4pH/QsDMENCyd7Er4O95fnAz1m7Vmn6zZA/ZRATJW6U5PU6//ywhD0LbSCgvktkWWvSXNPSl1n/0uFnwwrs01sVegunEzfJIwUEsC6rPbF5HRNZecXi5XozgoVQ93c6J7nN7sYUjTxXg0xbM/i7Ix/HA3pBHETvB+k5RLDXTQJhxr69M/np3Wlt3wYzr95mE1PNReplduGH4XLqJZZkOSjHnN+qMX/uORlSHu9l8SkGQJ631SeoJVv/WsAVHu1ZXRzDubOmdbxMrvvJGJugqVLrsSp5aBDt3lUJPCshk0qhHKWKYqvUxQ+khMD8I1MpSohoyx8ClnMoFFvsd6YPknGuH1MM7Z/z2Q4VWD6hch2Q/b1PrqJADJ4boeNuDF+opP6aDSMf49lumQhX9YIzGQ1kexkd5vwFRhLb2251Ez2sg3z8QtchIWlIOJ3eFGVTNw48j/vGH87CXpG4QZiqUz26MvDVsEHstQsu0eENQpCPXBXV5RHb4yvWeK0o9G+yHR6o7osGxTI4PadDnQYWnyAallMCP9XXa6Vbnqul+ZoBUJIrI0zxnNPfgaVkBxJCoT/wdmZtIFePEfDSUoYGHTZ3wwASXxHzncpG86N/fTV8pr2dit2jkciFFG6Kzx+DA6uY8sLpppvrKmDDgz9FRADgLtnnkjYIoYC3O0b2+hRvVTJ80wLQkrqtMyU1jxuKYWPvHqnBvKE137AqfePLEWE8AeHeklXQf+iLu2ZyBxvkvvRwSY9+PVlA3H3sen5TSrKyVl2d1eYlJ9f31lIbi/ADADrL9+2WsVOVxp71TVkfJElwDA2P2VMmnrdBxGK5QM2uL/n0KmH3mR6U265a7oMVkQC4lgOCfsZDaFEzbmaGMIieKelhcMf+ZnO1zXNs0qDZsOwmPz2ZdKfVP1udRaBCm6VniteQ57vSpf28kNb0qpm2CpJ9a0fwPWg2VzbSSO9ijlFOG4mSiEWld66x2TYk6gQGXqtKZZJhZqiwyNO7QqpGqforWGZ/oX0+tm5L79EsiMhp+/hEhtfhwFbvxHl90hTop85U8zdNPDoHhOj9t6qib9bG+FBOs7tS/6pNZl1/Qft7OQx5eCdJJI3RY0o89aYhFv0T4MKRh1Rbukp7VnUYNKuQWKuXyd5B3TrebDL/hyvyn9GiH2bmE2WgyavxFJq03VsOjFjXcHF/ztEt4fJlNKof8oze+BYKUd/JZQn7SX0MNZG06b1n4he+t4h9BIfOY9XdE7dCVoeYYdgV7x5qvdqyMaee1Zno4AcFRGhvTle7C7Ptd9eySGqWWYNeq9aj7HHrnN4iTUIs/N8rNeOV0NC65+POCm2XaFrrzJvSdhEEos9j5aTsSl5UdHRrlNfAHVDpukFjGwPJAJvPUG2a7SbRqi2s1EQ7TOHsoyVOdwVQNodot3mysUroZLFh6nS9udz100+c6oTb+iWBqr8678NZIXK8uX8eE2cw4XwChoYMteJCktq9kjfbYoLyHKMzusjUrjquNdV4ItQCku9ogwJqMTn4E3AgdXtRHrP1lmsShUjWbrf+n7C5sjcbVLWW/2VjviEdyQii/ovOA82oyZUOUeMZn13f25GbD6QzuJXeFnXrYcphq7HQ63A5ucLpc+hYJ6XPFWeyakA9G62vwHDLffFXJnWcFP4KCmTgv8Fr2Th7RoiHpZ5tjmXeCTyjsFGuImcVq/z5iF/C2rs9mlWnLZpBKrNBzU6Mg5KEXo1fNvue4f0zf26q5GzHln1Up4cUv7Z10L4ZwsVGx3jB9VmDpREZbyB5tD+d6obSATFO+wYtGkO4rjpMi0VEFnPZvStUhCVg2BFPX1gjTvmsjms9Ga+HCma4L7eb05rpWD4H0jEVzlYunJtq3v/8n2ZLjjFoEDUWcQAJUWrNziHuHd+X8T+UL55MdSU/g4CSWePim0MVoiM/GCGqHFJulknQBlYHJlGco3Q6FWKOhc0herQRrx9zXYMW1hkejo4SeZoUxPuJRKF3b9AwSTVeN5lu2a7zzIoLRlTnXTRnnbtCKmqZ+r7C0aTVXQtIG9rm10RQKZxlmrSzadjSGN0e4MIjFxwic9QMxUXaEDlu+u9STG0gRtAfea+TA0vpH2Djalia0raMpndvVJO6Z0TE8vgrXwyd22G5K4Rg4HLYWHf478/He5XIi7BjtmgV+ikrZfhJU6bDpsLpio8CbgFvLQeYg6uKglxmSyUwrGUgOAM+ivRxvFyowjTLkcc3q4BbDL0Ah+q4asrDUElQsdPLiW7EAaapgCG5nZl303RRmgi2xqyJ89do3NJDUeYv/qiRJnqI/3jzK1n4WAG6e/rTG25ylk4SjOvkHJapn7FXLtPFGx19yu7Qj0tm6G8n6DA/rGKXDpCcF+9HTO0Mzm3ZEm9pwZZlRHS+IKTOS6TPCJqaWVn7EB31yUpkvlY4qcB3uoVxtlUIr5v4uhobOZL7iV19kIfnaEjr+MPcgNu1zF8+ayirObcaftmbhp6Dfm0dx2Gdznh4FM0IuRQIDVgEvIlqtw4MgobzrICJ6ADIm/dTIvvBFcDPWavHWplaZjqGPNQe2wB5L7ODXOfTgRk7MBWMI5PVWQRAg65fu2vqgak6inOTofMBusgbnvbcn01oheQjmCYyJ3VA+5TSCJyZdVE/mEFkaJ2JwdwzGecZpkmNzqvOptDYk+s+XEt0V0A0Kf+FTJTPMnTm2omCfMmuXKxmLPMV/twt9S+6gI2Oo0n+TtaJxAZsX5xTg5ATdn7W4RY2Sm5UoHu/oC2MfNWqVCsWRPc8PD1I+tMEN1jYXxg52A4hghTLhN8Yh/yhJ+hEPggvx9KjYbsWGVHpiGscNR+Jg9nOkHS3HmaNUROb4swtMI2F3qHvN2V0xa8MymT/CaY5i5rY8vK2x1EuGlFd5cD1SrsNHR8Mv+ilqBZc9B6MQ7X9V8ZYm/iCDDkMbCiiGsIHbwc1ogKThobH+EYuMp2dslk5mIt99OBUaZFtx9uNr2XrbTqtePQuFZMYyJSvlDh2UsvyBo2SWS7mYT+3JY3GJD6eWMh393C9j1MVZFoTdbOVJ6Gv3+P7IGT6+0KWl0F851k0hfU2cWhmnUeRSRIVk26HWy82sen8qxqD6HdE96jQYgJQDNzRS91e5gFuwBlWXx3uIqzGyq24q38RUoysqPZPWnsKBuZv9NJkuWuv3X0HaL/pu7qsGbWsfgIA03Kq3Jc2p1HRCCfZ+RU0Lu8l07WlSh0GH3eLICmb94PF3SN5hfLKGtdBbpa6PNtQWGYPgKZ1xMnV4+2m08Ett+Wca1CBq+5M2uM38Asu/MjFNdmP0icqeBz98tgYGWbzdpEQk0zaGJwkYiuIykv2y1OMC7yndieAXdrtdOloS6/uUacGlnDTMrq5Oxs1kEknyprcJBKSa1tK2ZXc0HgZ0tKZ+x936M+6bbiIUO4rlFDgVMiVNI4tUOAqM2LQy6oD58b4PQNufxbHWeLs31n8QKT0sTpQxexiB+3f0bPpzmqiN6eW7C61KFExu+nmlGHXt9Yh7nH9dyoZt7diuYE0EmW1tK+yOXFHnRrGVyjEnpqbNsQmisz1jR50K+WdReiNuBSCKhwYLvJVDFzTGO11AgJz1K3l4s+eqHXei4FzkEyRTOvUNTDbCwyuZZB6Y3/b3Y8jdzLmAZN1D2U5u3XSTNX2wzjRQI0ewhH4BO0//0p76I+MM8G96aj2yPFTeQ+nxm9H8w4bJ1Rh1EvLv5GmeuqdCwSYbaT8uD0dLyD8lQtNnfEJRDkEYR6d/bQp/JufkcdZwdKjlw+UCjW7JM4XjlTH6+aq8oZOXcqPYzRQoFd6t3E9Njy9pPEzgFUXkMJkPXHtJ53JVlOmNFtl7KUQ5nrgmL96w2W+tMwZMDFoGLRUd4RBZaEPGxlUuKDvpeGGrzOj38KtyouxD79nl/L3X1k27tO7aMyS3dwqhfD5rc4P1b2ubsApZhiv/GJAdoWIXn10fj/NaiuBIA1XXaWRKGVXFma1VMjnU3fE6eLKM+Ks57OeVUMsfMKLIr10IIVQleZYphy/ZQA8B0yFG8HUNw52rHiEcEs02gWbmI29AaCIiQgeMjjpwR2qAaqibFlsROBMhXcVNKuY80MjB47WZnqw8mndEV9dogO/sVjGMU6glsvfzFSBged5ZMkv/LYo3l8xUjXjvhF7TSku+xEtSsGMF5MXpvQCWo2uO3hWl/OXpwCWRc6WWmoAP7tmUNvyg0pL6z8LEiNm52ImQkSqjPEErMBpOcEMxIqGxUJG73MU9QbQQy0eo54NqjicJBRNh4kpd7jkFYzAZkrY46XQCfJWa4nApxLvgVzxJIH38DtvryIbX+ydieDaakJXJXHDGyQt3R4IeeS6kjDn6TifH6CrvTdp473clu/Z/7ZXJrrD51LnE4KMKLRwbxR1/BXyLNCGuJqlwzq0+k+G05ijCT2/jcIVPx9u0bMN6/3Osr7eN4n9L0EKwtfbfhRZafP6ZirffX8Fj3lfbx/uv8G33HmA7rbHXGiz07Gz1uH3y669J7Zsl+Fjt0ubUnw/olxYeVlPkNBXZHyOpBLbdrPetORc3s63ngDIbKuRQSffXNyGDMWN206ld+fPSLHn7ECR+9Ywr8xVFrpRwfcFIdogq9g0mrjfXMw7xQ3MxqzfsLRVCq76JZNQykgmFgTStBDxtJBhpdSOTJD/LyCQDOqfIzN0swzGPZR6ys8P4RBmYTBmJGsvgwoGnOxD8BkfGL+1B7/D0o10iPtyBLCDeyeqGIgWnhQ1jXVtSrwQMSol8Mc3Y2bX0g8rofFXAyJ2ybqoKTRZlKAm4b+dmrn5NYl7NAtEzcfyhNFp6x1GkrSaCySVPd2aUbZFVSSx7WdTszWYTbL3d2HCVaQC5Lwz6kU/JUcn5/FzrugllT6SEFqkiu4HGFNWZamDVSIbEOzWQgCIRiXOoD/hUHR3kri+R9v/UnApAaGWqGX2WQxTaHj1mRa8FlF7urQWvPuLEmEyuI24CNzEMqUZRLg1XBxA+6y8dBc+bcPj3Dscfj1TSUNAzXkRbQIhnq3VMoyq+0z+j53spISmueX48dyYYW8PQsf1TJE8Mp6KaRjQC/C/niUZNiJGjvxsN46JSRUxJoyIX9mgpqhbqlBeQCY03Mn0Est1NiBaeR0kIHBtYeDN1YbgVPRpTfKylWgl5c6ahOOJ2tuP+ZjxTVNghgNY2v9BvCko2Fcv8bu+xDiU2i7etrrkZXIEhVPTAUPXv49LzORRTuagUYIDWmovn0b6SFadd5x8FPplpjgiNuweVEper3Aru3lDcIL5MuWMUGbnkPNxPE3M/eGzLokKOO7vcstYYfXfs7qhnPNHI19xXpcrLLrjDp31AOGGPtyIu7k05tgHthXFwNhQ6y2483Zrl9EQl98PcOEKv70FbwCSaX368Xo+j2VyWTNw3UevhcTnT3nCw8ZSjiIgO2NIwRB0mDeCdHAA9Hfc28LCI6ibQYuEmtgdkmX2tvv6wr3Kl9zHceRBvuU35bPX5gRQWhQfj2PmnQZUdnKioxqMrFbu4Cdh1NKNXb4G8CchSk4jizhNAneEX5oHnLERcU00Rkc2mSmUsnW/x3AVXbH44JU6wTYP8hCSY2w0vtz0v+JQeY6HtQw8jLsLyKyJm8lfC+yM/GrLRGpjTc28S8QrOna3lGTZw1MK7HW0fp9Ho54d2kysZ4U41jLRRwicLOp0sJK14p8dj81uDaDszdoVKilqiyTYitBeGSGm96hDvEFI/RkVQV0qtPTBn6UFMtow+THv4K+hDuxL6oK2tEAgRLtCANFW7FitP5FZTRDEdYkBU8GDGPRIyurzaKIUHUp8/oNhgY0VXhcJpxy+qKyMzpfoVwihsNAk6mqsB/Ix4flSw/hOzdetDMGqb0GZw8N/C7fNseL+OCh6pVv/Fy4lS/xCqfSqZs+pfxe7Pm0BIJgp5io2sxUZC8zn95O4mqpIW1fxF32NNRFj3JggdmyFvoKp49mchzwnbEwaKExV+4hovScQ85f21mFyRYJ3uis0pfe7vbr8kmUl8O2Xx89uCF3c5LD1ofZY9ekoxfbum7KsBgzpFJMMNGsrCo40ONaaJ/cbEcEf2JPbrh2JZJvDVlqiVfZVQ1se+u2K0jip407S4bmn2qUmqKQwDAeYtwdRY6S1pLznrgWJCzqzCXVbYl8oKAcKHyarp06cpQUOiQ5REIXWOk0GJsrN9KIe+LvVDlT4z9U7jiXjy2Enb4wSoM1p9SbGT4laksfgZ0td+fDqIdk2cMGirG5CUw3NUeJiMijEHw+NPsRXXxVos06BXl2PtyZ0csZQMW7uUNixTkAYOjsPfMblZIX3HOpVslSVPNMH1pNurmXZaH0TSaXScnHAispfGeWWZYBzJ/lntnLxi5gKdBd6DlrjKMH91iJALUsq3yhn0WNNHZZ3UKjRMinc0tKofDnBZAyo7JfODNx2+K4mnFST5taM1808j5kCmSmFc+G33SCyCpnf0TMYZlW2BxmjfITBhISPMyg+o1+tLccPzmDA3dLZKZNfKlNVkY8Ds0sXA+PJRr1zaUtQ+YvNgFaUH4OSEu505p2MfnOOyOqqXn+qp76GYTvzkuTFyphqXTcl5RpdmBzys23+1r3JhK0qJVkm0F0XhdFWlZra94qzoDCC/PK3ISJMp2e9gzTTYVELScULUDF8kIscgnWh9R1CE7nEA1ooEzZ8UREDPALmHo2mS2kDnXj9lrhyJCHhmpzZWp6AiqXqOd7daEdKF/nh8ocCfRW8eJrhD35zonIZT7YOPPmQj2/eMYvIsXACZUmbu3qSPPAPjGbkKKCK2RzO6AF5wMJjF9uO74fIut0sJwyndxbGCtMvT2US2/n/IPbclT/6fTbw5K8+KF9VfrKuVO4mdF2tCA5+qFSO7TvMAlSoVBot680ljUrCBSCGNM8/hh9Igbrr2X1qsy5Ry1RtAMsv6KZREODcu3QDPukEHtUNsa5x5uWP6nHfe27W0zeywNn1m2KAPNHmU+nnsVRB7tIbcyFbCBAtNw9LoaEGrojFpHePnLfbdRmtj0Jkps2HseS4UNGvzZwCwh7C2TfffYSsNQ0NWPOgZjDgyZt3sWpV42pO1KVCCQ9gUOQgIu+h478CcvqUBHgl51Wwd5U2rFm9HOmxwJV51mowcmoIvFHBcyLOWHiDVhJ0usaGnAqA/i3uRncaNyJqeHXoXUCJG9UwPY8hIzeVc1zr7xCLtSpES5mrGrP+dv96h0PEvmDEwIZSJmJNW8eCy+HaMDaDD1GnTGTW9/ie2rSphH17jolvfcnaZ+8wUwBQlQwKxpEJF1eJMtATINl29XBWRCJYywHtEnsQEpYTSszknixECpYpG7sHHfLEnV594EtWGUvPBYbfarH+QCnsUA8FbR/ZPuk54V6lGRMoMVHe6bGeQsWWQbdT65Mz7BX/UI2uei43xawjUbSRGcI0GrzLbQQ8CPKeV0vUpQNCg0hdVG22jvO3Q7kNwh41e+9ExJKfbuW9rJLTvCx1gldUMw00IhamTJ7UOicTYZtrr7WywsKTJ+sgrU6SdaO64wMhFBVIMbo4LpK6gf4lUDyakwlc9R6jw5lCzkrHrxWZkboTNodT2lyWZG18eQUKNZzffrDvQ7nGeXE/xuAv18rPaexF5RtZHKu/AcNVxKTK0zPqwGZMH17oHjdOQ6qY+C4Fq4gmxm37mcrColTxzWrizkhJp0GKPTUmRqOGiJr5AtUNUkEcQ9reCp4BB/TuFESOvtFfPlwu+v1RFJLI+rnMCBVE3fL7I10JHMXEe+0QBpn+w+aOXK+XWen3HRL4McYSjFA07xtIlhkxSIfgy28mvadwVzEWUGvl2x7AcjpO1rZ7/ADK0GkCZrAh8Z77QArpqhHeDtXcPVbwRlVNVDbLsGZyyJZrqHFiNV1I+3xkiJhjTnPWf/v6Oa4eM7SKxPZCpZ+Ouxc6Hy3xilPdSmqKq9fk4HpSdBlKrNKSBAb9eFbafGqHMUfyai5YlQi74Ufj97DvCv/f5+SLfBKPplzzchmDuVRaEUzS8bel3JcKA45VlcM8lIcaPXw8KhPA+NJnwKBAoChMRHhmHwpRd7nGmXHDrhzK77U/G9FXk84fzLlWdOQwFH60jTZWOP5rdniz/tH9920XKVjQQ65x+FGBCv5hwvJEVP7ojzVM/omNR1CaHHadmGAZz1VII0DTx3YdJYVEYfLneXoopBvZUIs/Yx6Tg3HaC3p4nZofJsnBKH3TddtQS1E3gv2AnFAX17PqSYIeLOG/BlohdkZrj8iY3rWbrMQDGQJMOhf48H/H6sk/ENA7S68Fp5dJim9y9PVhFknuAOqX2VOvlqer39J4WDI6LfRM0hrhZT+ytmerKYF4wCG3eJb0WqY68owilztDdY+kjRosL8j8Aoz3Ui4Z2I7WYuLKzfKh1L6DpzRHH3aOhnS1qAK3nkETBNqXluXx0bhO0Wb4ND+l4x47cRg054R9TzUW3B9A3CEW1u4bQLUcRJC9Z8hAhoTq5dLToST38aaqevoUnc7xeNuQ+8G0+/NjdMLT9heoFWSWyUDshAG1lc8N3PdK2jO/ByXnB2nagxzzw89VSaKFXVfYbhiMpg+E0nXbuxO53DrSTq7xbx2k3Lc4v69oYR6pEiGbvEWkl8uR7ihgG2Td5JEKhdgNtHmwVU5nICE6lstZ+Ye/6kEUL8xQ9SbxNEDh2H+e9GuwhwAzwtEdlCpFhbnPAPgbarR6LFBniLUE8r+qKSe1PLh03VhZdA4OpndXU7b5kpUpIGf04EOR0nS3g7u6czr041+6lQBvOh/ZN3YZ/NN2KIpuxKfA34COL6b3oYPBIrho1sogiEpaReLvmH5J6Pl8Xq2MhSwyvsg0Oqaq73w/rWGg5NQbpih1xWJHizC9K9rr0I7M3v5vSu7Ec+6stdKVgBSWC3J65OLRnzpfVJhBqHveKOjjEqg6V3N0rD9wKlw1q6sr+GbXTdsBxrH4AxgQRgv12P316z5p5jtwuon12S3lSJpKgDE38BEP55v0zkXRsj+IPCMNBhPD9lUuUUCQD9qJftJUq49JMedwIs82xTtgt0A760FtKN0L7k9SHbgTtOS3OedE7qBSQmBjR7k4EgKQ8I4wE+qAE6a6UbbQDDeBsttsZFjzFpFq6jQM15YO25adUnaR1RGksD8byTZQ2sGstb6KQcsLPNG89SxSLi9HXpVp8NBtSqUlwJ2zHkBiqcG9RuT/48/C2zcIEXaKf7iCqlGc6tOBMKlw2YCPE2IuGRcUP1s24ruRdB6whHuexi/ZIhLLi1DeBD8Wf91k6p/+LmptN0ujQl/zbppiy963pcsDaZHlwzGwfdZNAGNGeLIpmFcJBj9VyG8c6IKmIhMXm8Z2nhd/8hCQJXjqrvKuL4DISR+ay94/Bh4ft3ou9rHxnCJliHFmG+cu+j96f8nZV1I6h18Fn2iXemezvcLnXaV9AZvNisoHO4RHTJMUItskYSkA2AqolIBkk20uMcU/FiIXIJrKYpJIvDPmRz47Ak+VP/PCkcIEiJcrIpL2iMGgYKoXhJtTOynjT3HHip6pIZxfxiHLBpgYsJ1n2G3oMC2qNq39wU0N8GfnOMsOj+KB1YhW9vm0QK3lKsAIcb0D89CSaTDugntp2ltrH1SbJqqDAaGw6EmyLsKLkw3u0INX8ykHGCww0o1SSyVuXP5jJKA4GiYnvVjNk4fHxYbbFpXJUSt1Kat1F1Ldtqq4FjQDx26Y2Qe42KVlq3ErAEbmzGC5UUwMYyrxp/MdfccUfFqvaD7l17KJvS5VvEmHyySK88d847xOReoY+wDLh6QPsyt74DhEvuB2Lz8Ft2PbehACZglMo+mMz/e2nyNHEwGQ5QWYP+vKpXF10XD0Q9RecCcL9dTJdZyxC94yDUgkDbduqwv4ieFfZqXtvhHwcW3xyju/XhWhvEuY+9yFSWv+x1ov5HhSi3PS2wIYA3SnfLdTEloD1ukxWFoUgQ9mjEQfd8OgNQDBpuUjJywDBOGIPaOGUyzbzG5rXS3VM6T+F65w0WguerjljNSfwBhsANMrySokQWhSHS9vikmE0p4hDCm35FaSizT3lVOU59QSlBWU9NFmf7AgE/WYsfkBk6hsFJcZ0rJFvYMbP83ovXkANiVZKbdKaZCcgO7eWLobFPCoX0qtMOUmO9uBsWQcg8+I59YXGLvnz5gJ5q8QRvE1G44vEdeV+CbXOAdiSWeSHH21RTPLwKLXIp7viDw6OZFqyFYOyTSSQP/hTQ/iPmrDpUny4UKzmf2bCZQ5HRvOq9bjcGH+S0detLeFq4eEcLx3NUjY5pVj/60xatkTLwfqfqONmoWZuB1PiMwM//53/9i9vmZffhqE9qRBHSpoG/rEdNNVogxxYgkE9sSk9E7Eaf5gFNW9jPKcIi7qO6OjGJbmWZldqKKkbhbmMXdieXOY9zpNuzo5vVc0JHFtOfJaYrGh9LIXPl18HKb2B0PnAoOhwPipL/a5+dQv6ERiQcLbDzJIU0wRWTdnIuiV9QI7rw6CFx7opyRRTdeLka0XW6IUBTSY4J8mUIU7Czg3XowYqOa75PrMb85aPJnDbSMgVqKe0LcrSpeQs5Uxfkrm+82cFVPIGX9LkWQsb9R2uSvR10+ay19+LsVz3MG4fqo0X/nweoDlSozaDFqk3EJ7mkuUAfyMLs93WV8M7fjjJkK+HC82gQkeR8lptvZdriqv17rne8CmWuRzA8Mxofx14Q1YlZxnQZRFKznCz9Md1H4gPAxnYqe277m4z3TAbkTI9XKmZFNXrlt4JadEX8IhHFGRmQy7j/GTe0BDKG+S23R5+21KMtxSyubqiUhC1SZ25pw7l5lKPsX6yeWci2mQcmfIEf4ToZmiDlCfwPPIXxrRO4o0U7YLEuRzwYHrl1OybRY1NmxdRWChvIucM+p5q718ukFzYBcvn5VomXi1h6VTaJL4s8ol4KkuLpoKf+2pP/ul6/Kid+MahMIQ/GVOG/Du3MqHQ98x92lPGPTnByRUeRTnZ5Qe7WxgtjFVx+LcxQFi8sW0eZ06VxMaQIEv30taEsaQtkrqN+wj2Xv4w+8e/zBQT/z5d4zhW3zntAuv4tS43syR/buL07C31+GlfWFdofPGIvz8tVVuTErzRGL3Cohj8Em4wVVFBsOK32LK2t3lk7S8km/soa30ci9qb5e7BF2+AY61KnKIFAWsfL0kdK2PvNYx4EDCFxfP1RMdjZx1EjV0Q14DmbcHSoaeorNSMNCBzgQn0wIaJ3wt3PqjJcW5ScFr0tdXAyUzX7tf8UxS5InjSX1ejzf4CASIpiTNQ2AeecWEcY012GnTrrEdCiad2LkZUVbjDqO3zbh0vBYaf82NOdF/GplM/RJrQdbNcZ7GCCC+J1VB++JGRcU6lfiiL6IzH9o2ST5bx7i4aiW6KWqybSH3w1/OjGKYvLYgTH6F70O/6DpnVrDt5MW25LzQ4GcHt/6eBfAOQFxM8Px+4FyKjzPKlob2LP2QPKJCSipojue03fT7PQDHqE9MQOHnMjfplRFX6tucrBLXKQ2IJkTXImXiroZoSLDi3/Dxx6TBb7+IpwRrMpyAlcVGz8eEed15GJjRimj1iDa7Kl78SeW761jPzzw0WjaNNlKhrwwRenQXbBLuR2FblPPVjER1FjY9TXCsHbVPrvAaGH/Xx3AvzHZsCXsdZyALxlHzV35+IfPL/H/XXozW3N3hOfdZvh2y9O05piTlW98SqGxxTazt0xAQR8JtHRPjOGsEnvHkSqeZZoLUBNHjwB2W43fX6+G9RJI90o++9Wcvwhz7hkpd1ZODHMo+0Juf1ycjyGVDT4tqrJlqB18/fC9UWZuMU1v08ekABI5RVGcdvYUYBPcJie1UjlJ6oVT3O6GIIydsVc1DbCW3r+YYdJkFuKABJI/M69/0DoCgiEePhk5tTZ4OJGHly9JSGP8K90wecZvLQltKqYn9+K/aCd3HGyc/i7lCFV3pukXvX0yWbJ/mrhR6qi1Vut9am9r37TbdjLOw3vQWo3dulS89DNp/4+iSC4H015sve93zXERddUgaOAcLJR/5MV0tt6Zdc3tEpc9FDT3ZwUhi2Om2fwlaxVlgyC+Bx+lkQhdmm0daafz+dFVTizcDQ3hRCUQiSL8jeCv1HIEF8Sl3ZIuyc+GkMh8YF8bAzFt6yJuvpc6Dj758ycR5D8FWCIsHcKZJqm+vBVWfzOV3LvQoh3vXCDPiJrvXD1xPUGNQu9rBGyEF/MO/ssFtUagnCUGsm5FiDRZxfQUoC2KexT3IKqbDEtoIywnjGg8cSsWnTlHdNBbNFiTAKiPoYbaVzvyduuXQ0f9y5Qgpbz+kHktEJ4dEX4Op96XtIidAoA+dfNyu4aXA95S37mJbGISKZgeoGYWspuiBM6fOSyZz3gHgBsq5ArITzNcVcUunw5fqvg+BQjNzQoHOiiV4EvmQ9AIzHJx63zVNBct9LDOpv9+AtV/nVWGa2d+74NqHZOzgOLt8M/c6FYPeKmLE3QrZfsGMpJeidlHXWpQ8eHx0Z+8cNvWCU58tmjB0hY5SXej30e6cID7vhlLl6/N8lFiOdHBWuJxWRBJsalnGYZ5beOlZRy6oapVoQY7kZ2cMvr2j549TliM/pMUnTrVC5ZrRUNwbX9bSRIsxj4a9rLIs5lhtPJuj5zIECOOFdrCHUTrvMpE74erDQLTNmkbtnSiC3f1IBTBaUCslMX81KIFAy+BgiNfymZgPgTfUwaUJTll1WS90Ajkkr4O4I93CcQ8zyMtgjAZVRTF93l0SWQKcYouXT+yEealmpz4ER4eusFn/qg4USkd+xFCX2Tir7VeXD/Uaxx4pS7S+jGfYVZGs9RENOkElNsNj1asmNslKBQj++xEFu4zJAGAe0djRTdcZtAzOhIfZHNXTXpUN5s5UmJMAUw7GralnZH5Zh0/REO+beMP+FLV72EpriYumPNNBgi4M6hVpHz8QFl1ZbLT4FW+cqe2jCRFlOh6t7SoxCTS/mPKeqjy7jEcsOlJpJJw/HKDk0Uv0gY+N9gVBPiDchyBbNkQGTiatPAhAiiRbSNS5e25lCg6SKNiairKJ0LeQb/f8kzs5QZ3UdDUPUPdabzunn/+B7fA8gDeWb0gnTmC2sPuvqnmjDQj52OGQl7qkuRoqzFRab8oqxl4xK9QvWtt2pfeaZpZ7puaAQuud9VhHD+rSVPbBfwa5Et9PZmahke2NIrGTikr2+3bxgOfTd5lzT+rQbDFuqNPZ3g43OH5jfSiY11kI71WWlpxLK55TbdFL7v6Zz7DX0wtKxe9yceGCY2Kuu7rs+H7TTA5rLz6e4k99Cp0ac4FgplwE8+YIPqq+552+xBmpK34k29SByGm9CSaoETWYp9lxuCPSHCT2WV5LTbl7ZXu6vZ5tgdlUfdPf0hXlMeUAiSEg0XdLiDCBGqDvpv0Sb/ZjdS/ZwhyMDNYMNG+hafgnd8BgNvEQdqnN/TLRb9MVhSlb+K3kDtNMb/q4baVjy4T/y41RbNeWAoChyBEFMNtdVsVxDUkbKtFuPoOTxgAiGnHm3IgtL27bh8EVBe56iKsKVbhbGqo5Jm9BPslQ1TPVIBXcolcurrNY+9qICRUjkfbOpJqXkzlQrL34T1/wVlTRZPncAjtQHzGMc7iA0JQDBRijqUdEn/W1+Qe/OgJOULwzvgMY/KkagcvhoXfuGlPMbjhnw005FOPka7Q9ida7H44YO91Lie4LnF1e245E6Uy8/fNZjCba+vtFmqbNINcFEH2p6uv1XtmC35utNzAVn2JOIYEn1fZfeEpFTYZKWNuYFgwv4bd34EY5zlTgr0rwqTn4lkudIo0rppjkxMpy1U21EQX0ghSwhrcYeTGzdro2S6XECRzNivIToA50vn/yPMWdgohcsBT4JvuIRE2Up1Fg66ajdEs54eNGALwDF1aZ7rTci3GIT7n2DlsMG17IYOwyGPpbajM/2JMwvasx55uxZflzr5eMsLkYJWBgp8Hv6tH0VXyA/gsxITWeX28Mu5QvJbvHL2Z7+GUBXyif2ToGXAz2qF13Jt9WlYL71TbmXFCF42Ybm1f2AzFvYHN+TEhZ2HhQMv1snXICjUxIIHV3KnB3s7kkB8RzirZYNC6H0aiMqGBnes8p2IbHYSZ7LuYlKcKlOE5it6ixsUlQ8wTFhCU8bf39PKk0uhbtj+h3GUwtW8ZGGlEiltTGsvFs1p0CWRH1MBFnFJAek+DTj7rXnCK8SXLXWLNrjGYmTvN/6GKgVqjLiT9TuSMauIHgRtxMs+TatELHtpk8F0VBrcJD3SYZyYvw/dqxMBfXUoghzvtUSrrudQIrh4//7q1Le+KTDXSH/kSWzatDk+KkWY9Me9dkRwYl5Sidc99nQvEl89XMUzJJPj0UOAgtFi2cS0f2ZDl+Xx+kO7gH9lmGj3cEgd/gisI5oCFP2zRTvoiIzybflptnyPb7UG4J1GNh2eYuOrGq0TzDXFz4d1+kEJXMhdDGXTn6saIXgUSjBYxXozdhoeholAkGBmNfjJn9VLFuW3TW/fMg/eMyRmhuZNFWLWz9p/uTSP5PYK0YvNEaVcGC5mcr178AMDnv3hNx56wqbdd9whLm9wzumoju78cI/Yp8QLwvPRse0HnzVx38bf2U97mx4I9amYWLuRwWrPbC/FmWbB1MylqPqXDovipowpy/w4JIQzE/+O7/GA+SQF/WCzWOtThbmxjdZKCxU6/aMjvfzEwRe9NRsNmxU0WspD9YodTUeO2Io/4ff2RVcDNBZvOhsM0w9JC7FPW5/8NkKC67fZtyeTT+zFEfJ4R1+fmUKbpnwpK10RjCOAum4T4iYFyULUl+urZKABvrniA88F9CwcMWQz3TWSfwlTpLVMazbJDAno0k1dMGDl4Tq7ypBxzjZ8muhmROsvlYahuZ7/8HifzDD9oFdrnamszkth4jL8a2aJLL3GGM9PYPcXvE5xXDjvrGPxxipb3hOcLmFutsTK6p5Mrwsy9IzGfzMoRgLoMKt/V00KXIXZ+uvEY36+RCXbXLpVcTz6GZUkSHeWDkWxYjyEct86UqW0LCsESNCFgyPka9yoDZJTLKrn2nLijzvnRxQO5TwTKHRZ4ItFS33G9swxGbpVnT9FxTa3EE+PlcDhZ9E8r21FclAuASvx8jmlm4m49KKSudi8g5ROq/JAI9ZhMn51uGfctSnYW1oD0zkdzfpxcvcXhZKQZ2BjWwRO//O+VX7zjtOU1StrOIZl6l/MpUaL9kXJzp4mKzapt0EeD0CWFLRX524Koi03IDQKl4eyIwC4k6fLYxyTvPj89CwyJY/6CpTJN69YxobUw0tGheyIeaSw8XTO+klFtOV0Xo6zITjugWZcvcGbpjt0Vm54Vsk7GdqxM/X99fj44yYiFgOBjEw41QKxYYaVKMwJwukNC9i7gG1BztUqIJdUuNgupUaqbfh3dBsBjSlVjvDu9Ba3VaQWrAoEJX+u6lo/91z7mtaxTc1iAO8xMZwRdFHstZS8N3OU12qis4mSB6h9FbUVKnz25de3n+85j44+Rv9q5O4eEsd7tdrh1Q8XHT0RO9bSwe1bYzGd5FlsKp/M8BM/OUkzZZC8NAQmyQ2i1LzK0+ecD8SQKIRRd672RWFmY3mC5lWK66WMH+kafL3w6T4pXJWqCBi13QqIcoXzd3ZHCo4Rb4eIizqEo1gtK0vUfCObhFsCuIL7FwVLxNqJuZiWfg5CKxh6bQW3cyZ1YyfxkYSQUF2YXPMio0PYZk9h6/N+eNtyCgfy0xAeFH3qmpwPGMJ5bGjU46J8vO849ysa9ogPNDIEg2yZaWUUkpFSimlFIKQlJRSSrkS5q6dUbM8z3PD8qYnkoZlmOhlRhIENONYJ0AdYGVuai8oUiyefNHES6SYM7y69Epm9uq4NYwgvHhQpr9s6laBOGDmIKvibQdobfPQLc7Bb/8777ogKL5zdg1NBc9ylXeNPtSKB26GhoBQz8NyzOsj6yB8a6xs+vdofItpgKn+MXB04zwSxDHXnxDFPgzYQ0HWsicmUSDU7GJzkcRy0vR2FfgNIz+lnIpZZsCglTZdSFc7DVwd29nFlwy8ANi4kNGOpEx3BmjZMy4fk//vpcjbljLUuAPYmHkaTRhcHsMyM0eTWzrFDkDnG4cmQvrfYWXfxtuNLscxiARkIJIctbO6KtVYtQCbLXIk/CoO7MzwYoO9r0kRGckPov+G8YCfIVz1EGAN0KSaJNoYHzDK0x5ugVQugDJ/LvG82r2VLH/Ska0/F+tuhTq+GI8UPK3Q+UIEkX7/rDBpKvXl1PB8AbrQBYtHxxEF1tdwBkR+Q2+hI+qjhHTrd4ZxrMfn9lF/Uxmkzz1yT4uza+H7HYTtHpQNIxYMGcBsXr8vLjY6NI92sDS2+8N2jPyRnq0fbGmMeNAE7+8BhxYJq1zzROYxkCb1eOYQGzDWI5gR+6Za4I2HwA4bUXtKGQQ7cwrehS+8l7B8x0zrom4JcYAOaGkyOVuu9sWBJRgQVpFZB0P2XxkcgALrcBsOZQxOpNQq8mfJAWnHKsGmIq+H76WVk6i9doRqwt/HSLwvlXIgpvNbVMkrCgJKdBzZd+D3KqZqH5+NBIL81MLyXJwGC81px7EmL+No2m5ji+BsQkRdKtN8czxkifBGmAVByDWOzN5hShyndUaXdD7wHgwlN7pWw0Bm1wcFg21O32oafYKSbcmPMCooaXRIujKbyUGzIiZFPqCvIGf4C6yNaxqXB/RqSRpjU+gKzAcG5Zr1uPBZ5IksmfWdhmXbpjGe8scruI70w+FMLNy7/tjYB1kEFgMjjZi2MOoRlpRe7e+k7DVb5CT2e30HomX/M17/JHvyf1ZojxpOgqjt9/+Ah3cY7FDWOx8TknK8x2Eumz64GdksMooTdJWCQy/bypWfeodNMbCNVJ9/gh6Uj2GLzKoWHjFw2xVEQgRQ7m2NKOCCkT3ND7eQ80cEkEa2iYuiBEpxGex2bIybJKjLu3Yw8hT1hvc54f/09QT798IweEddJv59jhm2FWlvplkpJ52gnNVGc0P1Mj/mDVJaNLpxDKWfU/DJ6GMVRM/yGqPatUKXG6cWBIvVAzU9EPuSOOSwYxWQxfTq1nonrl4vyoPQM8N2G1Kq1qvAT1MoybGdDNPtpTFV+CzbfxJIPw7tUgHbxwltQunSEax03iLBSjqsvTOmck4mPaDMvOkrlvVMeSdOcRUzytAZvq1+mWSjBMcxBDeMJYYdFd2RZwQuoEBWaesMVFFndkAgjmwcWjJICj/4A2Lu7QlHQf7KoCEAoaNIiHikkJTZyoITvGV9wsmjCl9sCMMbhvgmcW2dqxaM4qX7pJqU6dBleaPqGKRiW8w9+Ytal1tzOk0ZM2LVe82tjjcxNG7cBObkqele/V+ckRPlcjd1qMp8HcltrDl7iVnVulKhbF6834bB+vGw/n0OB2Y1So7xNkAf3E7mkWQoIHMPVhPJMw65z2dpCVcX4mq5xZ/01wfJmXLlaHGY86RSuTlHTpmK9feGQhGRr/ux+qySdXWH316zPqGaJaD+p8aQc6akkU1KAkdLfOyEU6+zvC+TsrxQaudS2OEyGQcMKQmnlGbymAUuXS8bG4EiWupCg2DjAn30HR8iQ4p+nf03oQ5FINCR7A9yX2rf9r3UIkPf7dMnVVBz8Xx8cuQijH/feOh6bDPIdLHmq5mXvwX74Y3+7ecfG6jxyQYTNR0Tp21ZYnU6cx3ElF+9wPufEFRq4de+vOant1Kio0VMr4tppEunUwgd+n6Z6yN9DzugwtSv8L4n0pPTfAvyNIDGXj8X362a1E1sHS9F/Zg/X5y0dmTJZ/yEPFZfE7/ErdIMUOairpe0pfssVw0DQ/ktl1D1h0/xGXqLgqPFDQiL1jctMb6OPfyWt3t+9OojIDTAx1sLVMGFR+YObJ1tN5usEENbs+zLCWlTOlBqhg9K80OGXQdX6up6S5dfci/9CnT5iFl3/6IKhrQm3XKtsdD0mDZljqCxrsHUws3IBgpoZnvptKmhcMG11qWg9xo8pvcEsfoYuDNsmD9XNiwjT/JFyA+RGsQFFXrQkRx22uPkab+BzZ+9TkzPkJ6/QOtda5wr3XBSeefdyZlod9WmDO4ADvWP4UkO+lR4VBj4rmrnuinIV8NRCBFf+9f1kM8bpexUtfnmJpaF44xjWmayGRTq0laZhEKBMDYC5a3AfnYC01yP9f+EiBSlbQm+NGRQEJKS/euMH+yiFqJ4YUzcKgJHhOZv9bR4mIi126dx7l09XDgm/dYIuQw8UuXE2/nAtMPiiazD2OgblTlTamkplnkXXTI9TlFTlENT9Jf3fTc39+Zvu7kJYx8IuN7rj/dtbj5r/xK/jk8hjXkoi/wKsQGAeSZ9YoYD6JRFog63GuNVm3mohTcYX7PQMI3W6owrwxdZN8cQO+JQC1nPmMndnHBQmUvF26XsYJ2TLc8+dWChkyqOEHNgJCcFmHQBm6h8d7zC/dOkXQEFFOHUBaKTQv0Yi5s5EqdOfJAYvbR8JsM8UMcwTxM1VEojFe57vWI9Dr7UYZMnCU2CELzFkRYyjTIKk4BUiebxooP+Wi6vcBpVUu8tw50gBzyZiDlDikXCo01NnfJirrdAbJWfV1UXC/WglgVa7+QBz6Hr3qp4qaymBGaOAdtSUN65nA8+d0939y0YyCOPDPD0U3+hLUKYEogjWoHsaYQU96N2wxRBR7GMitKlAXL8EJHPJgO8tGE/MPabwR3H5B5R+dX4t1IwL7vvb689kuIcLyctD9FWW5HpE4fVzfc+0K+VWJP45UUV91QCwN9rr+mSDCnfY3A2U0pxN+u6OMw6PATzULT8YaQEe13K/DgTn+aurDEs5+bodpb14Xo8QJE2LdJ6NEARpnIRuENRKslssaZS9vE9Bz2yGkkhn7FWdwRzEbKb4InEXRYWngfsTL2dzokVyNE6U8ZYltMkbdzD+DeJUaMAxFI/0AKQEkFQwIYVRHh6LSJeMFYVkZVu1TVyBeJe5CKrAsb18WIe/xqO6/dN6NTiOlJxjX7xlna1a17ebFM2HMN+uBQKrREcegwm/q3rjyQp8GiasCU1Do42Q096s1jbVHtJAIn5yD+aCvCzXJSDJqY8Q+Vrr9T0Z7SqjaPRBpw7EY+nhwkqSHIQQ7bp2VTCQyP05daD0o845ysESLAtf0zkJOB6Nm26PFypQ1MJKT74efKG1HQonJymG5SMTw+Y5EU+WoFR3We3S81dgH8GrzesPSl62Kdivo8035y/68RRfMCXToFSciJVcvjCi+zayRa3QlHFPSZ5+p5L9TqHcabZ0W2OalWFrXTU5R6oDTWWO48640XOzQ58m5XR8kY2ZdBg7EFLh6aR2Bn1u6Bk1jltZqnDjHG1ak26xURHMaRBh136eNXUBiM0aBbCgFH+uXRiKn6cCQCRHZ6mD60Wvo3vEvaCKZyJYVSZguAg3BaGsCMmLJyQqWGYq+jUGBYE3qqinw34bBD88gqaTGNZJUsoZow0iAhXfIGn1/TunGk+42DxWvp9ybaX2ZRMRZZPr9hRig/5GbvE8i4sn8HFwbSf/yHnrU3GUQcp+xoxsUZKg6G5vZz5WWvG8ikUK1pPXULMuH9T0XWsAOzidXiJgR0o6VzfGrobOH7qKljKiYNgC0/OCPz+gFC6weX5NBfmTdhvQlNRGi2NAUXWqNUmh60JUMIVXo1AqhQu1jvCadRZDnBxFMmY3buGiW3jmlU2inn2XFyLygnakVb3/VjDYDrcrOBH94ylMvwUQklIWJy5MfJACzEpw2Yb1+L+8ZEOz4G+jxL4warcy03u1YYlKLE56fTS62Ad+NUgnVdl1PpxTpdgNN3ick46jTKZrD6HApCKQKHkwx6//6DJ/tVJp/z+Jk11xHVBsbd2Las9BwP2QrZ+ym054bvchBWXD6CB7XpsDqHlm9IrQSytFIeekpM/ii7P+fxBTwfuHk9c7U0Kf+LNHoNCvE3nbU6LuZCxhLko1eAmkdftyuJCbT9b9G3LN86YXxpIzQPZMRucJK1AlSulCLkuaeNoamJZJ/8AFDiBcXECs88dHTPAKI+iiMklec3HQm8SgNI6/13J8OV3PePkIL0WllxqUOVGm/p7w+bTTDyBOk1Z8Vr4LrONZZpc/bH8NI++zHbNZ11fgYb9biTcv8yu/PkLQ1wDtriZbbNzj8OZ+TD4Pq5rGc0MpWf9ylA+qa6h9bXtqBaMGnfVnPcvZZWPADy4idwJ3aT2Hh4dt1z1+IOlYb8mYVsfpvLvG4GyY2/ACvNR7Nn6THJfrso6qVLu0bJNYC8nqzd/5KONaLq1b96Qp5P9pFN5jKR/Aj7gSznxOh0NUC0Lr9BzkYgHv87Llvw/p6UTOBxU+5WsMn06PGz6snmX1aWL0LEuLGpH7ur3yvVW+1/LZYyAC0n3IbrK37II9NjLoLK5gvlyewmr9hI13c9FR2jSVNeCrFXQwiHLYKBJ6TEgzUYT1VrHLyL1oQV2Ntgpnzo5FvZFu6IDvVMu23ysMB9F18BOXETxGXjLknvCkz7twKjGBXFcqP1GWTHA7VA3COh4x96fymIlXdTsH6AyiXdBcU7w3TrkpkJKbGniweny1dcjTXk2jXkdtf9bzxhyP++855AZB6qsDcWbvIVpDKSb6oQOFlyWTX2eYL4OvfKejC1wWd/u2wqfQqihrS5HlHQGGUsulHbgFzaRuZPWyboQpH+rQ1+l7y8kU7d7RXk4aNZ1EZdFkdyIDGixTh9UyO5P6jKHIlMJXR5MvCd5Fjqfyq+xEVCyriad9jWyuGnelLBzH8RXcSGP8/7m4bfvP/aw++YD0uAgjMs0OzcL+/WjZK5f1iO3dHvqhp8A1XFcqmZt0YAU38c520UlguiDSPkRbfaHVG6we/sDfdEMvLEjwMNd69Et8vVujrr8ugeWd0jOBDZhEyFTlZjO4NqV3LJdtVOLSwXXQAw/bD3AswCPHTMaB8BX4utGNXtyM7hL20AEIh2JYHe5/ZXDPBn5Efy4QeTo+1Xt3hXKYzD1NDYh8ZAojHqfKZxDme3Eg3YGroVHgdH/yVOFgYFnQG4FKueZS1XLzAKhele8stKBnMWC5OK1438ZifspS51vF4OVVJR6ExH8zj3Ra0Grp5Dtt14W4dnQqwVi/XeTH5jhQ1pUAlIKTOJj5KUEgxjDbufhDyTAsCc4Vzk/adgIuoJyVSIHLWT59mFqDjgpngwPdGe4CX6XdgeF4I8gb0JaJ2S/vQ223VK//fl8+ubt/UksobUfuDxzjHHYhxHULhtT5hH2dnht6kkvSR06jtjdN6O8e2C+gOqi6/KjdMY7rnQTWhjLsh7GJlgE5AhuLAZcjVXBB/WkWnR5mowL+uvUjlAPLLej9r10w8kSSNdVpDrzvVZSMrgKbElMF9FwEYudM26lpxW0x1Cmif0ANTKZHCe9iwwaB549AbRnUwaOtNAwIv3rYhC7P6BZhI0dUipvXtAvyAp+DK/gQPIwcc6CM7t5Q2D1ADyYQ0P1VYHXfQXeK+aEDaES0wZs6hY6+Hi45BW6F4eInaDJpdh/pNPl3xpLFGrPvPGFYLjAhxOMtFN6Lazg8w+bW4cM1tnjyS+TjP6myhjVRnYUHpTyjxkmnjFWDVB69hQuyFRCQNKKWAwAS0Qx9/v7nejNSVFr/jWoGESsI2cgcj/SgczmNF2auR0XC8i1bxy3xyhniKK7nPmFJqMgywdgPT+KO0AVy0M0OH3diQR2ye4doRmuR0zz3xeAs6pYU4rSad9Mhf1m0QtVCiQtAf7Br9l+feO4KzlAU4qxV3oTYkWXZ+6NTvCizoknsaDaPr8+mb7qOH8+NEr+BRWTN/ECOyhO5fh62JRLlGkrPGUMURrm/1+pYB6AQdG+ZJ3foCH3ptXIkUkYnzlWeXDzs24QRvKTeJsFNi6LXQXuBtlxjqiBdjI7mYppU152YYTsyo7FXOseigCvhy3XYLa+Hkd5+MWNCRl9YfeHMMutgSeGStgdEkEpsSVdvtDTIYuXceuhugr6WaEb0cphXdLw9dfkg3Jx1P/ToXhOirTlXwdpIUumMhtrdvYXi/3dbVp3Xz4+XvynGt1ivoDxTmQ2s7Nygoylbliw9DeokgLkWO3kXgM/XHsTFtjJRc5Jc2mk+w6og0wZWg0hqwpVgWMUEHISwYkZ7uRZ+t3zxZBNB7eRAmbgugl2pndCvfvuT0rfqyg/7qFoeaX/+Gl2CFGfHPXDEluaRwZ2hH3ki4qN24i4wkKaAXOl1JDnnJqPeTqBnI95OoE8GiNVoAQi09ZARE9qMPrmSA7N1McoLoXhpc3V4xOD1rXXgXQXeYkrtLNOHPXkT6Q+uCaYVnXB9nX0s7TDUlIf8y6u2Z81p0jBh1UrDRxUSFFK5b+ZxYf9hi9u0cRlG17l7Az3Nr/ZX/bckERglKNIEvrFgdcEjfHS1NHQCdp1sjIo2tD8qyFapwdElTP86PkctBJSBUghlSiCtVXYnGRxWFATeltf+RKpVCtorHUzeFZ6t6VF521x75YimMT919IAmKBpxYuBBOBXvgsB7NW7lh9GpoqxyJ54sLOqOz7V5yE8LiRasKEOvoZ38lx01SetQD4xJ9NxsqnNcPvuCusqwDBJZFIkvGfh/nYRJfCLrcVv6Z0qcmWCrQhUptMJMlkb1wcDjqslduAnN162JXa3F6+T4S03fFFklWTWDoWW0mxGNG+yf4i/8F3QcKUs2brYyaQITA/TAvQSMweIOaLrEvCz9cAuv4NgG+vVSAOM/0EfqrGeVuO9sXTgLJq1cPjhjOIU5KIfydg2PIPVxj04E77fg5bmUMyqh5vUZhWdqbML1AG0dZPFhhZH9exCreUavQuYbYFkCgxSaMBBdE3/kszGPK3zH5Pyp6280wAb3kHguqRuP05ripDeUDJuqjOG8H9aTl+3GFlORAasgWEwG1USjEe3Y2lHOvEYcJ7ytvhcf35l/vyTUKBNskETDVD5agbzJ7vGkEQClbrJd9NfoF6ZS8Sw5vMmsGlRPWGfTHNtvmMg3ugs2kSzrhL/WpgWHVxHPm/P83rTn79NIwpOcEgV/5ejpe99kiwDiRsEqSXI5JoIwAyao8nzNJE/rZQDXnUDmlBE9jXz8Wj9t4us3XAIzfutBQQIM4KTitGG1RjhRlT7pRAQSsEZDqpVrfMVVfyaV+FVzedNvhkJOWKz0Xd2hs84f5dmnTrV1TsdiU4DzL25KSf596l0OoHA3ARRqKhHkisn6Fx5I1yMU0CmyCjlkyuMdmMjk0e6Px3nLyVfEHnZMFGmRiqheUjXCieFbZ8e5ULKRprDjIRArUwtSmw8xc35LHkeAg03PUuIlsmkZzI0qwrYQj/hizoWeI3OcuM84BuRaTGKZxvzQM7sHepdFcBVOmRV1Mhm4MgZXv31ELH6q6EvuMkgGOf/OrBXrP4sJYd4gfW6ki0Yfy4weFYyC0w5AWcYIHJMh7KI8/tRuvxWII/zzzHWpwz4z0zMbkcJtCSvRumk9PSOIEweIIE2kavWQKxP9MZML9YZVNWmV/l0L4zJxZ4J6rsxKh3/R409DO62VWZjvf5p+NdjdbHVT6VRE+rjnQF5/HTYGizJeC+QW9XlvFszciomvO8Y7ljEGivVTO572ueKRoRc0VKYeBIxIStFzp3YByP/GjWAetRaeUXRTXDnczfQaDJe5oldu83TkuGcB2BU1ULr8L4gS1K84ESwfhTdEGzwPDTq4/ESUHRjHURNsLhs8GP82BbFe8ZQS747vU1gsUBL4MN6DdM3Tw1RO6EQ7CCRlgFC5vJ7y8bFu1nMkojTVLs67R8AURc8BMl0fm3JCY5oIXEHcL/usuMQQ/OLmAm4G8hA3sQnOJt98RqGk6OH1FwJkl8tSBGGhWgiJ607LiyVSlxIISuP36akUxlKYq1j+iq5H3R0KaAlRe+vxUwKKzERB31oPepBlk8lgU6qMWqAz1z7tv7yXaQKg2+156MZhjigx/8yDywrwLqVnzIYkmowUiJlMTJUJOiYHPUoQCkpaSXFS9WoRNIMxrRPMgrBcG2Uv6uxdeRExvzt/HZoyDk/Bt3VmaK7bOIFmNc0uJzIKO/spBZxMaNElNfMEXMoJt7JYZWJJpv1vHWe0XsCM8inFr6w307BA9fSMioOVWfnD5Ci3v1373X4v2zQl+qEBydw/b/qHOvQ//hA/lq2T1fv5Bvwn7VXq1P+S0n5Jf+Iv3Ls/SMwx+D/MjcmMO00zRun/S8l4etCgdpnVq9cBL+hI6sy/FM+HjJkk9qYnj1YHhwqyJyxW38NLv8lT9gA0AT/7XmUwST7tbSe7yKpHPTbsYpyRiEddxQXY/SSTmityg4waV6VK3/Tv/UH5z/Ofm8yrIbyH61gtK6SO6l1QcJDE1QiBhKNrWcHtFqs0nsqPYFYPd/k/dyGzc72+s0eWe1XSTMrtp9wLVhhvyb0EMA5ozpSDu8X3hJh2jSPSNX+DCUPZ/jrZK63oHrqr3jRGm6p6fbrron23ChgF/l/d4qAoilEdSCVHx3qhqmzXMlfcpX2Y/WBzheYssAdzz6tJoESlVFofaj88EQJVrlPzRR+ktMw8XJC5yj76T2xKa6v0+JKGxm0ro9jqiy/02DFls83tUUrjcZAfyGWbMEUpK88cLw9VJL8O1b+i937FUXoenJ3/F6Tbdjv7i5/Hcv9xVTZunYOrotWFcVVLDyE/X+yFGiYL5YjAz3/Ciqq8fratk9u+3yIXB//JCMAeht6wyNFKZeU+8Tm2C3ezT58p/8cnLr7Fr8NVLbfpMjRa/m7uX0//y9FqGQm4NON9O6OW2MLerae8LAwR79VCbbRbsVeAiY5Ff/ll2+aum+ab4n4W4K6XRQvc2rP/Z7Y2Zpssi8veIQWqMRPKXK+657ZHKjm2JUn26DnX+BpPWmr88p/1tlaGXgo55Kye2umpHHKZ91/KQDbRPEp18/X9/fN9T3e/unfYfxHkzW4v0oSYO8LmpZG+Mbzmrmz+MKB/P+hxDx6YleZ5zW5R1TiT2m87efojrffFCpqTVGCPyk8h4EeUzoBhZMlXv2qe3sN2+w4yFVYl2QDB1+zoiUH1qwi5gJqL0KtxicFT9svAcwxfD/jY03NglAd1gSk5r89PUwSag7NXNA1k2ERGts0KuLJgNxPhFcPttoheT6XsV6+VoEuuz77fCjzTCRHLeEEemky4xnMCyqqI4CEhMfkCd1lOMQzF48gKdS90yUPUjuQ9U0fem9xI63ZujibjNoSl10hft+FQ/3pPrPihs+BcNWaaiJXqDQCDx8s6HkAZOrfQT8yUrxD45nzfm5jcwx1lR5F/TKJtvdfNYra5D83nkIaE9VSsIGORRhxt+f0zIaTEu0oHeoN7aggoalQq4f+3Xgk5p68ffkhd36y9GWqyZOrTyCONmaXDY981d48hb82HOgvtweR1ZRbHQviOrYxgsWmrd3GweXFcE5/JCuuA15Sq+UHZLJcL0hmJUTaX/PFZJGi9VheHE8RBLtqKOdeYcrly9g7N7P8XRDcv58r+lj3gvzR12LF1L8uk0m99n5x/BSz/lmFaMAbUcwcUHIiLQJ89okSB6QTUbzaxDAkfJYZ70zx2tH9kYYzEytbEl8BoxlhHakTeGGPBQP8I9hYoasT3YE4nmzPakx0TwHvrbBMC6RbUfzggEAtdhP7mIAKejj2tCKnktdBQw/QPv9d6po/66wPNoXHRD9et/wzLrvpff17+231PDwPv7dt9Zjaj7hbrx7Hb/Vxq7xP7/df+8vV5/T2b9zephu3ny3OXPnbj1hs0qf8PD4ua9rWL2+x+Fp99m+ZI5HkmRPRK8aZMK6UH8TMEj+JBUtnpotWxh865Vr5i66w5j3dxHrmkq5iY7whUlUC/YotqaXfs3XJ+hM7kyX9zI3Kpf6SSdowJNMsk6H30eSOwbhVuWeYuSM9Miy4c2kfLgU8TSif/n9/xTuLwj3pg8XEvadXFhWfLf1ixEHTF2PmgXTEOPDg6YJx5IulD4zOV00HkJ/2c3fJ+sSFNSfWvNfmN+sX/t+bF9aXfLDmlZXyr3Yr1nv+te4tm4FLaz6wGXnj5ZZr58Xiiave96/Y8SX6oM03m4lLbTZcTfxj8QaBB6r9znA0oz/M4nA7ox/M4EWemhoj0wWDGglj0oWRGgZj8oWuGhZj7IWFGh6jwAWB6jujzgWF6jCjzYWVGlJj1IWBGg1j2oWNGjJjzoWzGjVjyoWjGg5jxIWeGhpj9oWb6jYjz0WKmjhjz0WOmjDj4dg1oxr8w1g9Qxn86fACQyT8xFgrQzq83OkSQwa85qmtsgtM6qmD0jG94tkoIzTdwTCpsheM1KmgoivMwkUNwzAMw3CRwZSoLgkWua8ulw7pK0FyD7pbwUdjAkz9GHmVsfQ5v3kYKg8VUcZNZ87e+J3G2Ux0rYsA+yEYjgvljbODoBcl1XFPNrTvVduVkxNCXfqZdN0DGsHuWfrQi8V+A2dJztrMJp1DdY8dWP1qmqx2zAgBEj1Sghg0D+4w73Tmx7GXBWNOFvyDE/FhMYvzcsoD878yzLg6mAQmNF0wt8XEpgdwrnafc+bqRZ8MkH8HhvyJMYcFCsU2X+ZF5KPuRjwP4iUEY+JuI8rxx6YtpAMwrTutQnl/uE7hdVD2miPYvDecxnQKGwIf4vySag36kZRU/lGuL7XJ9sLt40NnumeOU74IO8s5kz8NtDabYMZ3l0Rv4QLw2WQjrgO1QXsYoekqizYQ4DB2vzXq2HYJf0kkH62g7sMnp5ZHqgpsLNkTLYp7hqhtzv6JIUWi37AddSEhO73k6gj5UztKM9YCD8YSkrNjYE2ocG3YvZxUp88U+qJlMgwn0sZ/bVpGGvwBALftMaBWkAdEyXDUAijPRbvsWtIajMeJHaEClPkkbeZ+do2rA/5p3rtSJ1UnpLcNMhsnK/ij7Bh/DD3adowUX0JU4YTONgic+jIORxKSwvyqmodLSFpi/jEqLGX4DLjt35A4OhLJVw6rsvbOoXsLTBWxnZtp4yCQ3p/FnVdnru+MolgYmWf/jS8Gtif8dGpvyY8yXG13SWul6OU5qxgRKhseh9h9y5/DyONb7iBLNK0ER1EWrqIglxrz3jDakWJyHXg+D/Le8nRyZiusfJMcO41liOjoh5RjIwtIzs4zO51X2d4BeDE7hI1ZdS7OL+xlioD1Vc84SRKWQxKoSEfWIfHLQudRvdruUvgcwrceddI2FVUkFJXxreUluweg92efZy47X7aG9Gw3PSy8ObEEK8g8ifB1WNLzZgFW3ov4PY1Sr5vt9258un8NNFGjealLsIYobzy8+1zk5Sac0lETG0aARe6ixlz0sarZyR1CtpvFCoLm6WUb0iN9PodDzsgqInkuVY+Jmuxj1sytdDY/d7SVbabC/hOLwMKZRRU/fBixGTZwdF3isrRLI0XSYi+EVy8LWhXzPuPxBMCh5uQaee4AOi3JufSAqrsfjdqroZf6dzOgCY/pqvO2JNm7hCpUstKMU9ona0Aw9oeUjo/OuDI4T5GdZXgHmDaYIaL4I09UWYq2WKTHl2XQPK717AZvRcKUEjUqTrzjB+XqlSea97iWndKFinuERImOQvxj0Q0aEAS1FVF10Tj4k6pM1ABssP9354j27LtmqNYfEFl/co5onhwxPHn8e2OMjh6Y0kOvz+t0kK2WFA4nIW05cuet9RXAkV7bNz8v0ZQYLejNdBDDMAzj9uecJi/yH7vmZ9MdVffpt6DTdXc4e5YwEKmA5XqE4ChE5j9mb0wYol1e9Ppu+7m/O6l7TqUOsENbqDSlZreESZazJNGKOs1GAuntoy+jERhRQb9O8fmY6onZNFJcuzANBSkhsYcOkWVp6L73r/ljYN05wimH8STOmmc6M6cDsquZ4SfYfskHGUIZ5qF3vWIgKixilKSJ4kRC7z15JcncggB1LAWmrNEsqMvSLPb8jmkKN+TI2UNgvqVJkOQC/p3IDLacCc2keX44VzMsXz4+eWE/TJlM2xG4QxiQ8OfEojoTl4QTxOPew7TxjF58m2dtQHj3hel5LsPuiEgSNx4zQy6fYS6D+xxELdidBloX40MtZKV6fjQ/kkC6TW8oO2vBBlj4vYYhI/WysEUGU9TC92vaEvMlHuYwaXb2fEO3zxA2xOm5UfSRwVEa0XXDTCvXzQsCryySQ6nZ4wVqSnT0jHpqOsjcvovzcNbA6QbhmKziI7oPBV76WZVcsqGkGOeOqLP3Vkn6rji+M4Rx2XtNHKXpG1/JvWrvx5T5N2pCSX2V8z5WYMatpHAvWxT5fZ067DSc4o0E+YRq1NO3xJv7UbxZsw3SnUek2nRPJOnRMWHuoH4gi7z1iJtuO0Lr3dH79RQwn5yE8ZZ5dJ6GkByS1bAc0LEW+D2SvLM8vpehonOr8MRa+ARcqsSMDBfe3mc0cJZ07LmELgAke6TNa7LRZ3f6qeFhlkOF5sVHRUm/ZMe6G196z6EWDfTkbaESf6X7NOuQS1QCgcyvKzYEDJ+9bkLeGV+UrWNPA/xn+0GTbE6zy/mb0NGhsvi4+dzBjZisFjzZEdH8uLJMRI+qL2MWkbBnrbenh0WSITKgM0liPIU9SplRC3TRuYd4KRe+Z35AIPJ27vRIXFp3KM3/HEQuyxLFRslEYLiwE+fxjkZ+uCg02g/1ByRGVI8kPZ4HXF7L0cleZzERbOTKCf0cEuTwdhqVyEBJNClVHYcvwCSBgXbf6TKnNfN3nK2HFkRgzFjV5nlZZBa9uP/sGf8mzz0IXPA0aHzX3p5tQWreWINAh23xeTSxAlNwgUpWyO+iPmCOQJoQIrJTQZEPatLJ0G3f4/hs5uXbjgjBTjoJQdYoN8NMUBR+Z35Yy392MHDOrtMTRPq7nbwj1zhDOmLQco7nuWrOTYsxfDXb/ek8vfTQgYt2uNLeRUL2903H1rlEb6PpEwvmgHPCB9eJuzQ2SHIhRVh6+WMLFuN73iWX52Y+eFWcm/+F92HGLs9kfRNIvzUEHRs8aXuCEVmF66L7NV8Rza1fCci2LdO0JIy6WW4S/NzQC11o+zFRyMc4aQ6qTYheLtwJs+l8JARnxJ8wDMMwYsdgZ/2yuwttSRotgGJm1kT0yQIIz13MwaXbwybKmaCiKcyjs5OLMXRMYLWlL69iPOBofxWJMxL8a1Y7z0I6reldBC8AP4qkhEWLOr+Y3U4ceq7o7vDMC84e8pv2X95LZzUxBQwoYnmpGwdfEbR3oAFvyDDMHAS2lHeiIROUizP5djpRVfgYokZTpibS8338BEnybSPXYUfGIELkqrirHqgSVI0lEuJGf38W2PunAyppQHYLidoAuZ5h7DnKAyqZQW6qln57qMqe1OWM98vs5zc8wqPzQZJtYiwBMpAHUkE9NCcSyBpBUPPBvVRXIWTDnlySjqZE5NVC5pmWXX9wAvzk1pYh1UZZibjFF6lhETcMk8QV/z3DJtunfyLvtbS6dvh6uFnQL/Swcg3iEEg9GRTXnEnc9wojVUqMD9bB0FpVY7V0pe2C3aYH7k8/5tKdeJs9EvOias5n4QuJWq0RcA16zcSEx1srD27ctSu+mAXIQdlmuc+a1H44ZVDa6mZkiJPl+2/OfFOP7p99JhHjiiaJTxrquOjQc+EenYS3H9xhTm2fQcdObuIw8c1G2Cp2j6Gt8Lf1tgxSzeNrfNb+c3sp3ne/REnwKjVP5h3sWub23Cu4XbQJV0hrN/Md5HsX1UH1Wcpd5yFK/YJDo/SyeKMaVWgvevWTdoMG/ukgrJRxYv/7mVytFYnHQ4EfZ4gXwBpOhMtDFCRLsHFDZiweqmW6oSqohiHg6MvjPYN+ZkvkUEPsRW7lDFH5C5lGl+l3jtofIbHjVU1TSCBqe39ZCN/k54R6VWeLrLjkhV2Dt8a0KOaEH4m5t4tUmtPbtZVlUfhXOmnQHlaOcmx8g3eN+VPoc7mfWdN+FrQ8LzAtIByCnVE3YzV6nmCr2Y08uQGd6fDDk/KcCc9mfNiJnQXE4kvaO6FDe79oyoJxN22NZXWLbQBXOuAn9D0LmGDsage6t5PEqVjOzfGxLrnixaWUW+ZzqvtaC8lBk2IpTLC2Lm4XTkxNZsdv/cUwUH9UvJPCHwcBD6caG9JDuWqX6oIXPsldqb1mPyh6vQWqOEpreV+t2ZhxznPz2hrsAE7Ln++YUDUYF38pk8ufmyaNsmJHlLP15OA3z3wf5qXyUeUwvXF+iu4CkyC08IC3UmTRr078GeBJ7CKJAoHHq3fkbVAPnWvOKP/j7DAF+pe+Snk4K/qahgqqKyxoSSy+xun1AwhLZm6LFA16gXio1NRfwFjbdveiNHZL4qT0Ap9m46EHo+MGtIa89xpgUtTBjPal81xjPYnbfhTXyBX9IMCdxIXO5y5oMS7KWOHrD/2wrO9TmdwvwCtsVu2+ldawrlWYaIiYcV5pM35yQkU2i2YWh2EYhm/PUb8b5A7YSC/ba5FgotFxRCZwJaJqBh+4jmx5DXdFAEoYsLPfJPDy2Y5BZ8UB999/4v47VzmlqBtqMElizbiAan+f9EDL7yQaLxbk5dDVmqKjYisxk2pqMTP/1/+ofoZdjY9GfJhsOblL0/DUcPko3FDQVLT6vnwA808MvZXiUrBEXfshXE2CKWbOP73JMY+R/MNPxyEC2Psy/aHEttTQjBXXnKYfiK4+XGqsQwKd8kTJjMC36RQi9sG3rx/w2FaDvSo2jHrLYcETfLgMCMZ+LKhHAk6mGDbI4/JUYYNSI6bw5ZqViG3dtfj6TitlCeQ1iGCWOleygWWmJWwKBSGaIq/DysijnOJ253TSrRiPpHBLmBx/W4JYeesj5K9QDTEzBedIMlA2BuOjody42Js6kpq8auwWzVBgWzUq7rlGdcpq+SZdcHOlW1rqmSTbFaj90n3AlPWm9pkYOYSaGeBH3zlzu143LIlicFyLMY471e7bqH7txjIFpXWTkVc+oHrrdVAgwqixXgl9B45kxD5OYngZOoROYICeK5BiKcsoHXU+Fqz5gITt/SikcXuN+yJZhAmQcp/Avj1OVlRGqVc3TyHU4wZv49m8Cuv9wWaeDYSHDjU11pd1FZc0wSGskhh76XhfWD6RL5/v3+XIVA4X+OatQ5LckmkMtgCbKt33iXWsQOD6HNix/z5dpXgfIpxaXNRYcYkXKz7cADA9fsNzG1/CBuvJ/b/H/PU7HPCOaVkfEVJoIUOJQAkidSI+hcV4db2lUyja+pz9aavziNPr8/hS9pFOhaQPK21H10tH1Os+tIlqCPFoaqjr1OaN9P3KyPwFrR+nWqhONHvjDv0DqwVlXoGBOvcb4khPbBIBMQHht4CwUabh0OGFHX1qyy3cDtPt9VqwkjqBhiBV2r+jVZIYvjUYa0+BURE3R7PQoINQXtmycE8+mlJMAgzVM7US1MF1nfwgClIW/ht3E9RcdjNVL5c5CpSLcGgW9ESfQDdVD2sEzRaeLH81QIrw1mEU3SeTG/qExNQTm5ydAKvZuygoydmmdhNno4dJv0OZ57Pw6r0CxJB6IHiJ6r7lp9GiAJ0zxdf5ZPimSse/ISAk+YnheGsHH8hFynbAFz0Nl9hvGqfKfoDmgt0RMBxEDgqgIefKBmQ0tcKHo/4P8pmEJr6+mE8yznLzfjcgj2g8n0uoLfXc2DUO0JgWusY5QUF8eDtDVS9cMhj6rS8bW6xsPuuPkNzV8ALjuIIQuExDf285ck1sBXauZK9vavwYpFheUVK8do6T7brbBLXX7Dz01sYb6LdqZDorDpHe8vUKzt0YlZZOLIXXRw6mw9CB+ejurAscibnqTY5qVWAYhmEc6ppaqnJs0xMifPX/r1AK7D/221HO35s99PMUFbcFKy9bPW2jkjqMdgm6PXQztguFzQKENcdUQQ4NTJfqdHTFH/donCO4COWBQtddXQOiyH/LGuxLDx8PPh+fv+7hQX4XFp3LzpVqL5z78up0W1SbiSLIJ96TOIw2bfehevmWj8ABJ1rtTKuBGV+tGILF7CzLEzORWxNHbHr9XrBSGfk/rkLEAOjJhCowLlkn4swu8l4GF6JyY5Pzj2KVqpM3UMFfiQ3ugSH/C+Ipqd085Se85pRjA7FlI6t+s2wkdx6wk850yE3Q2a84HAEr5Y8eYDtGpzW0V/ThufUmmQdpKZTivLowc/npeFMLniz4/uT8Dse6qltBU/2AnUphGd60MSO1Sn5sDSGyCbyK4l9WB64+K5cAge7mSCmUMBcmbKZEaNdMUjb96dnnBpl7d5SQl8JZl8PvRdQVAOUaJdxE0pB30cUW73aU/8QGoCtBugt4GshjYkzkx/k5+LfH5LFCIPz99OVpY5aRrNJ4mWqemD8ZRSM9rJAwUw5c70QDnEnoNPYh2PBCrFcd1+VzKq1tEJ1k282TtLsfX89TqYILioBSnhGFy4LipXtoPLhM8l9vtgaVdnMqdGKev/vUwT+bzOP2YeFYb3EnMV2RnnSVLTuoSDy5OR/NlRnXG0KWq9d7fdsZbqF1+Hry6XPEa5hJxVdTruj8i6UuFunPl8jKxStiPrSt83pFjVOok5J4cupHDiQyXlvq3lqAH8X4+QuDEznhdSS1UeeweHC5oAaiOQ7RdgIKeCrxatDQDrd75yj/4FTg6TZ+BX1njJbCtxesI8BaUOzvx9qA6mWSkN6Fe7hHUfg61w4z12TGTYNfGq1UoKrERGykAcsNeBLv3DPOnv5+FEnp4JgYIlHILGgdXEAZh82GJBMY5w5fajuDiW7qxTg2uhE2m+VC4CBxk2tcNH8w7HdKpI69zhlk6+spj77SXB8+S0FuWHvL2IfMHlPSNqUfinOBtM2effVBISj2Y59jJDwS8wDo3krokIMgbOZGleVS1gikGmdCWk1eTG+RRma1+ZPcWJ5gJyMcUTXfU/34BoboZI3ILVfnoGkTv8opTqfsuJpWohjw6GEXAnMGzD6RPxCyhLvDb9W5kgcr5Yhu3TgHv19OSiWVVxQNEeDT2ArUSkd/EnhPxknNKyuyYhpDirYU5w3lSJcpfFkvRCKymZftCtvjiDgx+14r08T1/0hQogMdKCZBpe9rvYaK8Idsus4LyTU73rqJB8hZv68Qg6ii8AtZZqnjTTNDTnl2t17HbvOP5sUhedrAJtQ0vpWahACfcwlIRXCP6dZyj9W7LJN+BqVllbbMfUn0KGSgolQdvIaKo030rSV+SwUVXRoQtSiWnKhDI/h1HOoEkdG4QbZyAq9o/I1s4QTdjMaIrDhBKmj8F1nnBFGj8RXZxgkEGs1kfRZ0AY3cyK6SIL2gcWFkKQniGo2pkV0ngd9ovJpsTILuC40wsvxCkM7R+G2ymAjiDxr3Jlu/ELhH49lkw0TQ3aOxbmTLiSCdoPEfI7MniCUaWyNbDQSe0fhussVA0L2jMRhZGQjSLzTeGVk3EMQPNB5MthkIrGk8may/IOguaSyN7GpBkP6h8cHI0oIgntC4M7LrBYH/QOOXycYFQXcADZUs94IkaMwqiyiIZzT2SrbuBbZonFQ2REG3QWOlZMsoSHs0LpXMiSBWaOyUbDUS+I7GD5UtRoLuA42FkpWRIG3R+EvJupEgfqLxRWWbkcCAxlFl/SToWjSKkl31gvSGxnslS70gbtH4qGTXvcA7NH6qbOwF3REanZLltwTpAo0/KouKIP6i8Vll67cEHtA4q2yoCLpHNDZKtqwI0hkab5QsZUK5oY6cXKFkCSo3ODHNsXCdCW1uqCMrp9BlCRq+ceLV+8KYCZVv6silU9hkCcoSJ8JjIb8SGtbUkZ1T6F8ltFnjxG/vCzETyt/UkR+ucDVLqHzixL33hfUroc0ndWThFNIsoeEBJ569LwwzofJAHfnLKVzPEsoHnFjPsbCcCQ2n1JEvrjDOEtqc4sR/3AoOhDJSR46ukA8SKh1ObD0WVoXQpqOOFKcQRULDb5z47n1hUQiV39SR905hfZBQ7nBi8FgohdBwRx356BSGIqHNHU6881joCqH8lzry0xWWRULlGCcevC9sCqHNMXWkcwouJWi4wokn7wv9JaFyRR354wqrWoLyCyeWHgtXNaHhP3Xksyssagna/MeJDx4LqSaUr9SRsyuUWoLKDifuPBaua0KbHXVk4xS6WoKGQzjxy/vCWBMqh+jIG6ewqSUoOFAxEkguDQd6RgYkZ8aBA0Y0kkvmwBVGFkZy9jhwi5HOSC4XOJAw0leSc8KBTxhJSnKZOHCNkVFJTodGc1m/IugaNPJMdpUJ0isaF06GpFRMAgPJSErPZMCAmaQcMNEYSElSrjBZGAP2JOUWk84YSAuSkjDpKwNOJOUTJkkZSL2kXGMyKgNWJOUGk3AG0kxSRkwGZ6BfyJdbnrIXWu4T0yA2LMTKmLw8PiZ9cjV0+Nux6fznPy/Df3GsOuZfHG8vGv3fmC3Wa39m1ZvG1146iW08ppv4r06D6G276T+2z8Pt2ufctfuCNT8QfgHbxWb8ufE83f/ieFj8O2tv9T+Y4M+sx3FbrWU//VeNT9bW4cnInYuwXWpfV8VJ3B7UbzVYuqbKh6WLHKDLPKALYyhd6UGgPSwdu9s6f2j4wOGROxjKg6HVzREd9feAM+rIOPoy35mxMzmL+eTWnCunO+bCqc5wLJlzcLITGsD6TnW4ucY/f9WYwUVZeewXAlVVG0En6w5crlxwrIVTK77jZsk39x67pFD0VA2ToL/YQI7o6lfGBpncvJf0o1Uzy5s7e6pSFPVO25NLpTpiUNkHUg0N3WmmtKftRz3CcutSudiZMcuw36Id9xsL6hZHnRd9RRzf77Xgzlt8d/m3eWcs0+yBm6gkLzhuk+CwSja14bpirqKxuIn9qWNN938cvPO1icUPnoOdU8vNHj+flzUIyc+sytLSvoxRsXeddmcqyeBUo39o8CaBDFn1WzonOimoXuCUFqEemWS+OBEn/Q3zkqeZjDEPXOL8VfdKp2xIUT9zR5oZnSdiZuV8oF8xzfLEmGkeT6wyF05QGcVOP+C43jL6FaAH2UGYmLlxMu8qAdmbGFSy1vfSBavJ8nzmMS6J/bdm/vvJJyJaqQiLqGkn6JNpn2ixo6qIxay69Po9O1JmwC3wkDxTHv3Ljj358oHBuCMVFtiTRhbKPWli4XwmOSMeSBWVhIXv2PbXG9Z0cDvZ1zg68gqioHc4R95DBPBsQ4LEsV0WN1V82C/DYV6oqbY3/Vw+AHwZTvn/QDurFMdYEUuDNkGZIWjwmJB3EDv0DhH5I4Qog76+Srk7d0Sn0CqUL2zFKxxH5AJxb2gR+QgRK5wnEmOAaB1aQXnHlI4yHGvkDcSj6Vu5Q/4MERyeF8gdRJrhmFEOoIpnHK+R+8bHcJ7p5/KEfDCiSThHKY7BEcuE9gLlA4KMx4BcDfGkeocO+dYQMsFzL2mnjugmaCcoR9jJPuP4B/nKEA+Kdo78aER8gXMlMYoi2gHaL72MG/nOOP5AvjZEcX0tV8ifDBEGeJ6RkyHSHo5LlFNU8RHHJ8ijIbbOwMMr8lcjmgWci5TGpSOWC2j/oPyH4AIeL5FvDLFzew4gTxUh0aAvjZTGzhFdRNujuKniExyfkXNF3Cc0QW5KxB7nFxKjGKIdoW1RRnMj3zOOP5HXFfGY9LVskO+VCCM8fyGHItIJjiuU2qjiiuMt8qDUQE5xLn8jPyjR9DifS3FsFLHs0d5Q/hjBhMcWeauIp4neISHfKUIqeL4nadfPiK6Cdobyw9jJvuD4F3mpiIcJ2gXykxLxLZxPJEZmRJuh3Uh9nt2NfGUcv5FXjiiDvpY18t4RIcPzO7IZkVZwbFB+GlW84PiAvHDEdmDgoUH+4kQzw/mXlMY4I5YztE+Uv0bwCo9r5J0jdoPeoUX+6AgpVBpS7rIjugLtGOXbbMVrHH8jF0fcL9A65KMT8QDnfyTGoIi2hrZD+W2m9CPD8RDyxhGPC30rn5E/OxFqeD6A3DkiXcLxCuXQpMkMjorcM0WX6Vv5inyAaMBZJMZgiCVohjIpATyCXCGeot5hiXwLIQbPGyl3lzOiM2gLlErZyj7iOEG+gniIaAn5ESI2OO8lRoFoFVov9fnCuZGvGccK+RqijPpaLpA/QQSF5w/kBJEqHCPKiVLFDceCPEJsRwYebpC/QjQO562UxtYRS4c2o/xTghkeM/INxG7UOzTIU0NIMujLq5S7NCO6hPaFsldb8RnHF8i5Ie57tIDcjIgZ5zeJURzRTtDuobypKVUZjifI64Z47PWt3CDfGxEmeD5CDkOkFzieo5wpVbzH8RfyYCKgn8sf5AcjmgHOF1IcG0csB2jvKJ9KsIfHJfLWEE+V3mGFfGcIWcDzo6Td4IhuAe0AyrGyk/2M4z/IS0M8VGiXyE9GxAs4ny0BiNXmQJ+bezRllOgrlV5puVs0ZZQx3TD6gXNyhaaMHvc+CoEJ0HvUct9QZluUKX1S+dhyz9A0o1Seorz1ouXelDlnnJw6sq84Kxs8FZw53TF72nI/cYprnNd0TOl15zGeapzif5yDXcvd4anGqdOO2v84l17hf2ytNyVSadV4I5to4X2KKQ6ifBKN/aC3QqpaJlU0s2BKHHVIlYPU2GLrC2lqVfuVhqgykRho3MkQU5z7T6S5tbVN0sJC+yTP/TAoD1Jbi6ZeslbNfbqJRqaUJQ2Nci81rlq7S/QGqEv0e7QLAN+wJ4wBrySssKJTAheobOhHO2WpmyiMbdxGF/iG3LsTF+Dwa/SVTXiO21jzuTgJp3U4Qoc1LLHfgH4bt/SL/WllmepMs0j2MY0uNVk3SnCowz+RdHJQCY8r+vHYjK1Wne6cchyir+1I8vG00KPXLv0GONVn9Z2OmDCw8eMDqMfGz6SzWsM4BLG63mFpxttT2sXzk9O/OlzsNMJjOk4XeldEqoPabLGs7U5ntzgTVTVv1Ge97kwutjXf4JX/TrFq4u/8R99dvJaL9TQErTbtxiT9vGIS/5lY1xrL7pD4K/L3BXns/yXf7sfdtpnD5ms/Dk31nb08pNN2ubkpVzs9uRz8wniz/7j6M3y9fqwO7Ph2vou5k/42PS7qZbdYXzRxv+02R48vZync1T/j7qLJ43l5meYhhWFazdWP7unXSvYf+bRfT980yXyVxWK63H260NfW63EUNXs3J8EUIKeAbKEwBFLueaEO64zA/Uf91nqNg9bLoN4cP/QmMoLvlEaSrJ4NPvk37L8sCnUEqRrVCTvWJUIfL2+qSzZRI7hYpDe+1wn8SqYhlagFXd7ml4jhA2TQ8w0KrJzian4D3mMbNRgLGS65S1pLoygDbJfyFU/mKErmsIr+/2QgXDldCyAQbb/+npQhGRPgY2jQi/fTDo0VMlxhja/d3XpU4g+mVvDwIYF0TDYnEKBOkm+U9j4wpOMzTvgnl7ePfyPD/bxOXhq2q+YbanqipRtby0l5kKh2LVR9b6vIHxSCDIQSPKWzFwaPL7pIYxtNS3GcZnnb3+d58iCBQBkygh/ayE5oFT0toq7iUe8jpKvvTnSLKcDv73OfRD2FqyYUNO2HqozXApUI50Z1iBfriR2t7rhJ6gVUYbiiFCu/ImF/+z88w83yrZ9ifBf/xpO6k8SHFrSTt2sYXYtCxgCIfqQbc1XOcThPhKyjVrNfK4/jz7hu/Jrq+IavUI/xGRc8I8fD9VIeY2drDOo8393UwGRoBBS9VpxPfUU2JbZf02zDFF6YEhhUStBLHWHi9+ISkQbJKaQSKchwav3VP+c6B86nZv8DKD/ayDZ+jbrtxX4tGa4lsB9O6nLxywlEDMfQwxyz0S19vXSd3L0WGDGLtz0jjumKT9DFFcog3NWy3oEX5bKcDXcrzR88j0gauZCbt8E+YDi5EQ/Pjic3BIKi8FOTDsXD3OomrqXTRcc+y+dWzVOFaMroVaukJJAQId5cPKRWD/NM7kDxcFIhgUA9diiPnjEIAYq3FqMzRfIjUYNsKGl1rb2W1C3I12WAtCQT+0QXU5LhvZGjlsDnwcPNtnThJVKsgrRHcCfvNKFG3Vyj0CbOoJIGQ+oFZUgqvUunVKESqTNQsuyqSSVqqbsQzrMHzG8rB+jHJFBJm4A0c0mF+isRqLMi72rYO6lZEYouE/Xdt9H8eGHCmh/Lk32W5fx4I1BXiV2VJc5E6JSpWuFEVLoWSVP40ahGVyLIYF6HQgZP6GZCD7Z6p8A9RpEeQTZVQLqL4ti+07HSosdPmIHOAQr1+/BK9S9N0b07rSUVu/JoqqLFoCcnXbcaf3eTr9OSDA+JdCac5Wi5eDxJx6B/CR4gzdgn/qjq9q83Ep1M+Lu4ZwP5oVo4udDdZJL+g0Re0HhFY+zqu78iB7TgMt38rUeRC42SSdSViP5LEnpBKfUpIFPsid3o87exlmxjAE2qsepK3MLibhiFBiqOo3AWvIrA3MersfLehEjRbBdpjaIZMvWxKdrexzVZ0vptZ+52CumYlx05Vgqp2g0nN5OTsbp72yehELdxP+/p1XYgp2yeXsKpPSa0xxPwk9olRrMw0hsByAf98ZYN1R82dV3zeuP+wGFZhmOcnOTaoG3UtLNcf2jnaVMtbpUuwm+wcugUvAPXBl35v/RwXe13F4k/9TX0/oX/VKPuroM6h7tYqQ+ho8765rc2ctFNOBqT7a9pxHp2MSpB0NCyBDnZ9cbXPjh3K0Dv9mgFPyyBt1NBmjeibL5YEKBMfMCFPju7/LGstqRPBPjcFIxtMlu7JA/U9BLL9MMJ1pxTq39AgrP77kxuQ4P9q5i6yH4e8jzK70jiZXBTPerpgnyBa1oMRzcCBbWkjuleTn/y64R/9tXvHm+3j0eopqSmoCVquGMFi6BlGQEfoXWzCDB70nDc9O5dYvMWm5NTfz4R0/2PfWuXRdC6FbMQr//Tv+zMGW0lCXHvCyX8GF/auZNLyZGdXH6WZvkVor8Zi9i0mGC5DB/AOHBneetJcl5BdSW6HSw01Kk1tU4O+91QijXnSoz0t8MOiQamt1aN4eamLWV8TdkaCp0wLVjOX4jsGqH4DcbiLq311fUtpDvIIzDwokRLyW55RygeQUGOjkBMYBL8P62Eyccbp+lqsAr6s7+CMvPIB6DMCForJYS85p8lsPSNxjhe1iixkLp6e4SfttoAXu8E+i7uUf8QjnCpCe+g6GZSZICFXHDzi1+eCg5u/Pir/E5PH4Rp+hlJ+bGkzjZR7cb9if+LK2t6Zjk6mJ84LUqlWFyABH+U6yjECy1RrsUZqeLHdv3+ZCB7HyB35Ha3tx10K2lVrKU4e2a10EtnhY48ZvGEsDjhVVXX6DHc0SdI1zRlz1TKSOzj8fexT3p8keP9y2Liy3F91vaK052T7BpuXcLibpCpq3YqjRfQ4CsNBvnoRBq0p7H/hNLgeADUzUtfLh/8lIl/0wm8ooVhD7PnSfdTByfP5Humb+3zepcCtrsno3h0xh6YApdVhGGiE1Tk9eebKvYPkIEL/ZeXkTH8eWNaDnjXXRK2PIffU+fffc6POGDpn0q2/oob6qpZml5XE+SJm0MQv67o1tXa/FFZaUe1UMLcD5sFqHiRP2RmRaql56BYo5hN58IMoVvmbBAWQRhRu7f+hk969spX76rXy6U0pG7GbAPLwR6f4ScO3uJLjOKaOFIjXvMZyYoBiBB0BBLKNYs7Iy7QeFFSnSjHU0DKuXNECIThIhfaJrtHN3HhtW25Dv5MB8TPlg8vHWKw0MzpX18xJTZa8oYEFo5lAPeHSfzav2pjgOWVTrSHmusR46LxGS/FRCNUqL7KYXUf5gbTooWzTZK9yu6MJdaQYz3G4VT8LqbqaTqZ0gqd+683DI/j0+Ef1V2BH1+lt2F4LkqOSEjrEkZ29fhbYRDmnIO0THxF+i8z2pYr/WNAhd5QYPWzqYwBl906tTcBwwTyWc/OUdbOnfvI685qU7H6ske5f1oIed3auW8fAG140BzltoT+p/QkKEcjXRp8Grc1HL4p1O+ULIrFUn7hWbQhX7nfP1Ku/ck40Z+/A/uJQWLMsF0w8/uKpv79dqhtjV/78/diWhZX+teIbYT7AeLf1J5KshUhjuX0QblxLnG31fMLA8oKwmWBctEvZnDGLBL7X9a8ylnIpipMlZfGhqLv0C+WGXXjl0F+XBkbn8efW/Fc1D8atzuX8UfDb1Nj9NgfX2bOfAU78FnljoPD5TFAmK5LT+LOLIYYaohDexGQrfA8HcA2K5v99BMdGojWlLFfAUDYezbeX18/hUdpcZ30avoe134PPc2Dn0uTtv86FpBJU7vyhQTz9In3ZW/SKbuURmKqU34AgpRzHwkAvnFqPbThYZlFlD4mh8flGLhtAcTl4tXrnrMlBEcAypuUYvbSay1MIIxMyoXCY7Rp0KE+uYl7Y0I+p4B23shmy0yKAM0FcaHslTY9f51xvpKFtYNybuC67s230qVjCk2GgubH3pTbE6rKaSZEXzEXubncWmfrcy7T7HJTEDWyvjR43E2KeHlvWft/LQ2dhsGg91biXEQnMlJzfdWOubZks8PyWjWHW+ZN5XpKmQOtDf2t2pgqtZe+sFvYHOwmq39pa6Q6X1Pu8rZ6435IzZ82JFU7LeaC5naxkDi9kiG/+T1sBTxVUE6InduHhlMXbJaaCXnVQWV01IVq8qGWUBsL+VccpZDFVnUcwxNWdSL88k/ZNEucYidCWOrsl695v5+7wGUvfR5fzofBf/mDH/u0t74f5q0r+VMzvKVXOpkJ+an75vvU9EgL4UefNT8TAtbbMMhvwBfyo5dJ/ypsgraP2Zsmy2/apeslSg5KUfwNwnXrf5vTf9Uw7Hl9MK/iXL2zbv2VvmC+Z9y2Md3m79YWwxi9jCIUV5HOHPRExrFzoTviJyAffGgl3lQoadaxv99aK71i30/rc6nNh/M6n116Cc74V0f+lT5j953kj6ZtUk3Ne9DdeCgFCXBPAgkkkFsLpBRh2a/rX8f40OJTmN06SloyojQX29GHnxO2Dd2qjuSJ0iUBB1DgR1XiboeKGBYchHPcm9Y+6zSQjR9tQ5vdKxlTlMT3gef8q42wBLh6Ap9vHMwH9M5nB4WTSxD4ump85W5hI7z6JZMDlL1kuFBktXC3bPmbXTBUvZAUouG9wQvwvkrlz2X3kDXeXL4+UboNfsPN+LjfFkzTYWa8VtYOhd0j5uYT8fXnV3zMTpQGSuci138VvfZLKSVF9JBLEt+bDVYQTRPK1yVnKcRVgeN73/NLnLkMfi6WglP4zgQlgbzPTJ/D05CxlQJlXQU3ez7H8TGLVR1r7NHngCZtv94rcH63DfBQyLW1JB6J9AdFEkgkt/2jTNRk7hCW4U5hfY7AEA8PzAJmrdDGCl4V9IRYQBKTNpH5fOOXqPtVnXFL1i5LZK4Vw7axXhsLRiD98GakVo70TiKy6R1xkGwdrwSusTpcGp28o8SAjykDIlcR4vuQrpMgUi0ATT22nT2icpa3g8GlT1w6hEzt+F5XJDpasq3etU8UOhQOWL9TwU1c0ejkSPoZXbdJRaqTETGc9x2GWpQ6IRC0Y5ORW6Q60ajlLVinqN2/3ndLvFQzEqmO0FfnpqpbKXWYieq8Seup1Q6xXzJZyzTj9XLHOEbkcol1vUWlI2jf1k1RH1vuGvrw1XMQxa2dhqYfpxz9onElfp8vUlkdSqlDZOcZTahTubWT+AL9UqB1abVjIDbF68C9l1Yxjgb8ulAkXeuplNp5t5QNaz3ThRKNFpFDIU2aertjXCtUGrwwonMO/pVeqa6vLdcRoJLIrtPkiNS5spjo1RElsc1EHf7Y8HQ0yR1yiAld3juFN0GyjTU/3a4vWDwUxFpneRdBPvzn92ISVVgkpw/YsloX4v43+a6AfSQBeBqEtA0Jc2YIPoGNi0/RNE5DQIUGMRkZQ+KB9AwMlhGrTVzMv2jZ6rVaKBVC9e0x84oAP2z/y6fsbSTwleQ0yPO+UzaPuvB/CWyobLVB5vnl1fbPCgwyet6NvFgP0OHuzWgkfRrGf9lvm4YV8mf5TtJiBUTeq6d5Ix45VWrkvzT6omLK1QN68hURG8AjvBpJBTfm1YXKsrE+oKEEyryiu33l8whYYi5dyMxu+GzENbMJF5zI3JE0PhyvnXBcETPuz3yYbxgyvEPfooE4h9vSnGb0VO6MwBYtQQq6mYsfvFiaOVhJlqQPAkYT+VEzmGL0u0fSearp/ocYD/ihwUxC+eHJsWngD45RPkagFwvFqxF3DKWFm1LgA/yLOCh4JRwIDZUME2EQIseGqUNAezNF5C9HLl4ecHFJA5MFnoCImLfyTtPqyaXS+eEm27k/T97VejSXp44XRjLCbLcYLQjygkoQGJsuoBb5vaxKneFe9Qtbta1nFfhnqS9UgA+fZbgvGQGyaaW19o0pFiRb19oCrk3zhNOVk8qXxBZcEzylLSIKvxmX/7g+K2WTjfl6iwwF/lvwd/KHOe9t0UGxLMo8dGrjfM8WShdayhcPdQiMqWeyLeje/4r3J+iJ5Qu+oJ1pJig3Nw1I7V219lEiZrnXCkfTkfALne0aCQhyzzJW1M9cdC84VSXnUn0YOXdz8RRA4bULJg+8Ld1bbsiSZdaT0cJq7oP2MwUx4lxB+1msMRDnHht3oLTonu+R5cIGAVoOzv2j/SZRQN8RKlp3IThENY+1RZfXOTlTsydI21sQ8Beg3IH2yQSdUE4Zn55KQxXfzJAak+CD1n4Jmos1/YBzT031cdsbn05rHpdn1DwBl+25dxRZmuei8NpyDNHDC/6mRpSfqmtS3uctAVSoE1GAPlSnVzk1MVh4paLednMce+HCPBQE0pAFw06kjn/NNwGb+15aOz8+HAlmhDCf/b2xxAmzLD1hH3qHIlmAVXI3XgcJXFaszSGYJ7WQr+TBz2UWExyAvgFA4KDI+lYGfgQe0CvW8jOZy15RCJl3CVIHcJRxbnrEAQ0acM13scEshB+dEEVKy+VdVqS/t+mLdVZm+ykq7A8o7MEVF0xMkPGxQ7EBt9cv7yoWGpDE1PQnUNoAAlHFWUPZAhwFOQYTf6CiRYzXTuKlL7Qg4AAS7+7+LZqbEswEdZ9IF7SlcQmTyhMg0AHjkEeEPTwWCzMr+0mXYDA7c3853ARWVMAA79UgJrK6OusHXgA1jtCtMhDkTchGDyQm2mzHegGO/bXBZtIOyKLHjcO9HO892GQy2PlbbIZk03JnNiCY02GYntKqYhRuFdh3318y/plw/Tt8jr6edbH6jLvOsUBTZCMWvvXhWK6+pAqqZHoJ9ggLGTl26luSH1egvbG3QHYEWeKfxjVMcIKFa9Yktjo8vucEVDGwB9UxcgwBYxF0cgszar7izZgrSzuZVLsXxrdnCxgJ+zyoWoAJRmo3f41ywOAAixMEM8hMHSfQiqyXGM70p9VU5f4lZti5L+olVGalHaU+dgklCe96VEzoiLCpBcxcZKWwMeSRnPMCIbzmRrxv2V5+m8G0iok0FEUv6836f6YIPkxe6Z50bv5B1YEuH5ZsgvQ7OKmGrsQfqWA9/IVBO+nMh7M64llJbzI6spBEzkn/6TRYv3kzfE/JUlN7BrkEIUeFJaVLdLGvGLIfPgSUKOD4XsmcmaMI1dOFa5QIpd3FOeCs/QByGtWYS127EFGo350/MmQleE2e+Jk8yACshFi6tj7ClmY0jYZOXDQRabHtRRPKawQ6gihuHIqniS0GM1gmRlUN3b4lIbF+LNhc2hE6856JULb+PdV7Sd2Gf57bVtOJX5We0Ltkg3uG2iV9EtFFP+PHQ7Dv9UPIznHCrA2G48GqI0vBlFUfwK/CWAz+84MA2JlTJZGG8Y6n11lDbFOha67t9OkYt/1oKQFJOmAkNiYmoK06L7gog8QC/uKEuIO+kC2APKtR8dzQnPuuJap5ZYnBXCnkYzhMbyRDRLUE7DJxEl1QTOAsJP5XhDaIQybEymbHJ7NaMAhiJd15mYBkIYVVFOkfgS4tYJ8DSeKmEqXeXCcUNQC+EMNgkSWNZbEqmaIDsFbA8IS3lMtBmhCPZwtyOQJiFWfZNI0g9s8V/UMe3KUn1FMj9wQ6VAJ52kerxy9BfiHwWY/fRjIH0LBBXaJVzBk6TBlTFsBTLuhzkKLTAqdJ2LEAyxYkdB/0jDYTuQJE5kF8Y1RcWEJ3USTbO+mcCZGZPVNHszTuOU2mmZ1WHYWM1Sbx4T4nUrQPDYFIi4q0zcOl5aBAwWNe57yc0XwJEoMBL1HQglKgMPH/rY/MkFO+L41iGYdVTQGgBag+oiyNAAuk4A6laNB2xYnh5hul9SqJ7Hkp8votIiINBk2ieClQnN9rJlDSEle6PONmby4hcmHe/I1R02UtFvg/nHxa/zrWmqOKcbVGtRnJ6cULJ0c3/puL/jG0cSprp6Wg4G+S+5q4Zy9GqSWZf47TWUKs1ohwkOQyOh+nWIWhZu6yTNeWGYQ4ZEzXk1dvoGMhUbdMFPZONE0xY/QmAxWAsYnxxqtIP6PG4NlNMXBpx44JRY//GrrzfsIxIkSzEb7LYNokgCt0Hh4diSD2I4HTFWMxwgd5yc1sMFSsORkhyvIciUWaj3DbgrMIhxMhicOQzbCs5aHZIUJjh8qqbxI3/Dx72OPhJC5RFybyDokUiwYgvXs7MHJAnD18NwzZ0OHTixcddIoHs2+zK28FrWlmDe314w0Zyqmon2MmpDZaqWVuHpMMps3wLZcrS3jTFAjA5qiRtjKZCvxFrlZc5XU1mMZuGoAKS+PHaNyQvEbkbNtoC4qxtAAuB5/pOayIwNxgoIi7+VHRUCQCa4Y308KVwyOvSqZ9RDC86Mtji6GavZUxA6fJ9/OQkfnfwp+i/J2V1c8EO+WGwpMeVxvWeWX104XqQkQe1CDgi/etLaEfDKoMC+bA4tAeqERCaGu40RBW7ZC3AXkY5m+epTEDXr/fkEquCYg1+IrgoUrEGSw2SnAn62WaQJ9IvaHN7JzCwq4V4XmAEwLPMWo1W4j/UcWJlENYpQ/4A1O//2be2HgtXXMinNF5fHc1HsiRyezmN5wCIHHyALCl32Qg/x4GSPZ3WmzXA6d+x2g96EwzmtjMOFQ9jN3UEARxlrP5H4JpzC6UEDR6NO0tAA2FRtfzEJH5uzmfaNHDYycKYifxNtPqFEka8mLzg7OUnKBOktA9o1l8EX+W7hUq5Y3n951FRYti93tPjJ7T/85m0RmiBScUP2zkQn8IPIldzt37/vDDvwCzHHwl2dkU6+PyjyiqQfvrO5eci66Hp8sSHNn54O84X0XyR0Co5PkwJG6Q8lYXpb2IzJCIBgMzo3hCO90uuCN9gMiZsxDEGRLAd+nZqPlyyI5Xxrun9uX9wh8yqN3wDknK8ufSrSg/4W+z2w2hQQEEyik79bfLRiRUzgHBzZtCiWmLHg3sVVwYVi8wawTbFT+jtfTnb1lACexlOAgJJvOSZwtFQuIn5zF2jDHyswmsNMyEYTbU4pFxNaEUBzMSzS94GPFQOHDY0OBJzwATOwc3iTPOfiBnF1aJLmAIzI4ABUSeFpj/4oNGhqH/QNQZV0A+asyxF9mgf4oFN9OtMsML2fScoSBPGV6AgnyYBOU2xksS+MNODLV7E+Q8RlgLR4+Gb3x7GNWfh1aAm1pFjWIXtqPBT9Yh4/9OtGh3tlv1H5Pg4LBhwS1ndVb1WPWb5FvVUK/6I93I4W+WXnXmXrWsV8EJpJYNHAmbeuBHhMuk1XWOlYtvhVecYWzON6ceK/GEP2ng/2NObzlGv6CWQtyQag0PVxNM/9DtbzRN0wFZ21Mwp31Vl8s91Y+fgRn3LptE/sjGQNaiGByuyXKvrYXT3WUuTMy9UbA03AVrw3Uwn3jUAH+Y1uUxcjJRY3KBxczh5fULSXIEmM5ov8AEYozQ/+bfbVroT4Xxh/oWz/PgxMH6KADu9++T+IL5rRjaE235J3GeYAhI8fw9y3YuhTJ6KZSzlu9GVb6+7L4EGYFpaaQKkbNo/UQ8T9pR97zWp3cgWpRcu9udmZo+kFG86OHLL175Jphh4fCD/+D1nqvf5gEkXVCmg/PDINP2GXFu4N7ClGbkrLhLkSBwBWolCTGicsHxPFGyxbJl2bkwVb6gFhajIDesQSmfqPQHcK9NC6tm/ADnOzGui/ZAgqUXm3M5ucWt/hRWn3ML3c/aHVy3xVx23efSjHRVhAd763LNF1YjpYkEYX35dSymjdyC86qXvHlzPTitThS9R77iJU0A3Q6BGd7AlrLgsshP5zsdA0UKdFUN3z9wyFaE+BluzPuN7xWbbymR6Z8FxhsSZTix4tMKRYtlEN2Cg+yxETsBuu/3dS5S4qcXjT4DsATXIbz3+IzxUQux2yLPsDgmj5PmOUsMQkYaVZ3GCPvxMGIEb47oLmGmi42Txu2IWffGHIt4tv/R4b7ysWGZJOnJxykaKQ4/aWxag2ZJVSSov42hxwK5HiqXiLIlsO0GLIwta2scsUsttnv4zKCBYS6FVHmM6UuY72NvWkLnHXWXSc+nBTwOuDsYu7qW5JtPcUTFlS0FUrZ2ALY4gIYAJKApaQSmGj8BNIwFGZYO6KV79pwame2xONGZecJyTQweAnYfjfGlloYlfhHZWEc2QY6Scw6Y/E3Jawr6ubaTH7Ibpq30cxPirDX6ZjLLhCimaZGPsjjC8CYr97vz85jK9grgUi2bM2SZlehRBO42IlmDA+DDtlkXYi+sndYKkfxeptmGCuxs2mfw0sk/ApuLkTLqnnL+jL033KK2N970inDuikN1X3E2X4ptd0mvSVRk8JkNHU/VqyU7k60ZTbbNjstxgUcpzLNptUjDriSubCe/z0gB1LvVqY2wrqu/twi/DJVhFc66jhWaolCr2TRFVwyUXJSRfYLGT8yO0ojEzcz7xmaGO2m4TWSnuHZPr6iRgUUvYTAV+hyrXU+T9PeGiC1xm4jVPo6/g5udg6H3JkuMTimV6Jdi9gbDyDcFq903LYIuKvLa7NQHbiP8+W0KQrF8maYfoajtvek0F2mDvgSjarG40n/0gcLP5CXU47NwEz3zTNEJhJSSYntQIk2np70Ut4U/58pjhMt5BYqeVnOHuFyX9Etr172ircnErTqi1Dl38e4/aPtP8RIBxGsHyebQd7HSWKozKzLfUsVaWss7oWhrQf+2NZ8wMmy8/ZNW+7x7BGV0Nc859xyOTm5UpuWmroj6i89cCA48wG3V0SfAIeMPNXMYqRCmUg5k6F+1ShuNkTGbXPm/5zm4tAqHL0B8GgWZxhFX4SU/usm08c1Ao9oKy2EyTAPSM1ZHy4SGUQDAjAzZMnxAsM0OoRVCErO2SnNxzZu0WqnCHox2n8OC4hnGxRz4guIy4oLF9thU26tfDn5/hItBQacxg7d3BljGZi2a66Cz+6zz7Sn87ufoF2f9bU6b9s2vwrYp7//+lZotfjhkZt4W8WKEMNykFRMgmJGiW0YeWJPKCXslpjFsrfQrcONotN6+1xy4MXIo6AnM2oXUHP0tVF293fJAdyE7EI1obdVjZWwlk8LkF9796b02nytZ9fMcdQObG58Q1Sa6EePigvfw/ZwVmTdyZlf6vQ1nhsuKlytNaXJOK9FRRDhqxcwUPCrkSA82+UlMKLBQLPFaT0dwBxLArwDGHA4RBz0c4orpnKF6z0aJeWTAWHfQbVPM8sriQl+cdrfuvUM74j1q1/P2zAG7LN7MexHYpc+6ppTvH9tCIW2Dr+JxtbZV/jlqh8yKxW30jCEe5LWwVRMyIn+WlD1aFP+8mzmrTK9EDyKTsEfceeOchVdZrqJohCwVIaxWYJPB58tkuYEDXVLjdUNvty0eP3Y4knRr3Jt1+EjBVBcqp0Y5J8r3b7j7s9LI+qu/cvcWw7u/dBBBDpfc0E/uiX+H2eNt0KMrtJp1H7txv3jFN2sVUYbmMCz8DM01f8zp99dU8t4+qiC+oqGAUV3X/aOEP69le5rfn5s5G7D8kqVZTqxM+VqOR3cyD/3UCKbQ8vqjSNN0E5XgRFgYSiwVnMviy01ePEvHYh6xS1VJyAg1KTAXgRYkFc5WtFlUvmxqcwbj3kUKNUjOqBUDFvdhlt+b0LfS78BGIa0ea89AV8FyJKSYhDv7i9kCAPKioVYcOW1o3CoDxUeo2I2gg8LGhTfmdZSCsx1VS1j1pn6r+qT0KszHmxwZM6ETSS25FNjm/greq39XtJkzoHD0rADl7Izm23WaT8VlYx8m3xsR7vb1c03Qz7Zz8L3AITsx00xnIje1TshB6QBIlUaxKVLwnkuXo0zSp9GVVYS9LkAHD759iEt4U54axMqPuePg80pB876omzqrgKBGktC/5i5MYmBa2pRWdYkJQIeNSRjLxnBP1GJQg7/Qvmlc/ur9cLJaWR+cA17IoPeFnE0Edx2eUE6br4BWNk01TnNqmpdIc0qaxWhOXdNKk9HVfA3BDb60Z4bbnoI2+78puCExWW+2jGGrLMY3xWwMkCQHpobByHDsHEyWTa7cJBP+DBQx8shk3x5Fhq2qsRyTRqN5hW3q+VPQcHTcOPKcrg8E826b+KWam7ydIO4f9odUWDYnpN06wzql+0mdFtY9LCoViIxojBwZ+Txjn8JmGkwjiqjqN7xBGati8sm6fRi0kY0PRk4vjxkZpxStPD6tQobrphfNFzjVbD2BfHluXWE0p3eZjyfWvv5Gt3tY+AUyzyajvFKOe3tkuAEVeHYrMmx3HeQflhfZ7UVA8rQUIOLHGR3DTZtDXg09QNqY/tbeoW5fBCKh4EqJ4FKurTTz+2FgjlQB5qtb9L3yC3x1vXiRbkriNtCgWlR8l8dNK6FNdXudfQU91nD4fLJergct5M2oXbZvFpvUp8b4cCuuWpf4gGBTm+zokshHqDo6k+I+YnS5W5SUrxbP7thrZACjWfkSlvxvNl3kEl0q52mkvyFWbGieeB7mbO7SMOTVaKF3F3Rbej0ObCwo0jxETzo6vuVuByU6foHiFO96ALKLZ+zvc27SDe9JsXj+WXtOSL62+2yRCBRlQ0zewIXfhXTB7bd1+ITlvOI32c54DzhiN3X5GP+p3f3o03GATk4B6m98DmdCmv5FpLQBXje1Bz8cPt47yjeIqHZijtpBHI5z0pQctjAFWLvBS/tFFF+VZSxP98XTZqswkSV/1RkcvqbLdiLpee224HXFbojP3zOsaDx+O21oPCEPnFGD2oWUwWvWw0fxRgjPjEnEY0MWv3hJM8TfiIB0o9XVQ61QGgd2C/JXLjuHDLZEKKLlHrKLq4GCx0g+VIMA4WE5FaklP25a2+0BdnGekfb7NPFJ+ZvCRwWKhzdaThBRK74/sH1fNuKOYYMJo6utlbinMwvSBCvDgWYI+JcTOMHUcnCIiRLuf3tpeHj02bT4SRQTbpTiIRom9hD2uAlT23ABLiy/DPDMOS0nnSujA7m4LnGjfqeqwy8GDptik1cbt2MVfu2aIE8OFcVHE5LUFsBFP0Q/wtFtdrjmQEMeuv3yOoCBVslSjOYKdzLiXmwQpKQPnX+WxKwztC4vPUecNwO+0ySgNq6voBS8Y+mYIF2R6k/wjKPrRX100I0T6sdN237PPXVfpWd7tGCaZyK7dvkdNmghOFr40agJUuhZFFNuymqJYkK4RnaB0pq+/7qQUea7rraCA4T/sLtXI5Vz8V5wc7ZR+JgEjECxdeezrCqoMQ4yCG/Lzg84nggVPaNZnBgYd7vDEWFIvJmbfhBrqdeDxTMdH+1R9VX8ocvR9v2TvsouYjCSWdRm0SGUb1+hAsXRApI5/lE4sYl269HXmQPsif4lGeqvrT0Tw3NpyL+rpR4jqTiu0w1JdDmSuDt361V96q6aGhGT2aVCFMXvip8eErgLqiio5g5mycdEEJJZNAKamlRgsEuuLisAH3yy1yXNlCLWlXvV6g8UgZxZNIjqmohmZyQFpG5E/CIUyFhF6GraLLRtf7i6xyWYiIN0d5NWyyE3ktbh1L6PShIL0dgkqtsROTEUcAI70nmiZB/f9EivsTwUBKspsEOWfn2EjnMpSvt40ihVNYSyHIlF+2AyAmZpH4VJWwagwLsWVGHbPiw7aZRTSLlOh2I9YQTKBU7O4TjrxrhzxtXHAqRbBWIyobtxMsyTW7aEoz5B/o0BrxE9guxthPju+p4DSqiODnQK468Ht6LNygqAQ0ct7NboO3gnPbRvXfd95zQEIZBI50jE/xhYu3KfLG6E8iDp8Qd8/PGyFWRKoCaOtCvjWijBsIc1+6Q7d37iwUGcH4UcsiGOYtc8h8gm6oB5dA+itMxZy87UIPaHyrC6AKYXIqkh7jeNIj2yhXv3+5VNZi1OcI5USbcVlHEAek+zFS0lESQTQ+k8cTCJUtSxQPMglV5NOiumdjCKsqETiXMPHVbNsDD8zhAlfpgrqdINyH1sn0p6aB2BF1lhEBLVk2Omw/4+MgadjImZDixDY79q94cYOgtY5KtcFDxomzyz3XFkMU4HWulPjZkfgCX2mJ3xcJtuKQAuqzPsrXotiDm7diMSDssLuxvE3FEYCHso+R45Rkac890hNh35Qk44EnrLcvJdkBATlUWXKcKSvQwPpe0Kb7zxSpbuS8L4xEs6P8GVlDDB8T8z7BjIkOkBUmHox4WqMkflQOvwALSAemO/QmCIPdmC8E4iz9xhs6Dc754rSYNWIpAVZbPVFaIvIdEbx6SPW3JoOBZTEwo3IhsEWpmQ5kMlijpov4p/cqJu4xJaVVJQ7IERmo/6Z1CLre1+HYxnoI2wosUL2o0LZ7riR6RH5j+A/gsDHZ38xKTMLQHTHfyTrTDEi2xCPecRJXI1FdJ4JUb+VA7yqWos2IbqzHPmpFjyeyTEowLavBztmqC1MJBDLMdenOdQx0Sc6Lfe6UqVN9QlIKUWDwDiUkfrQDuHqMFq4+apw/7on3XmvHZ1Ycu9eq8C4Ve17b9NgCBAonSslY94AzckF+HNWYz4LtEh6W+1FR2QVjBtU3wPC+H7p2O2mPE9C8QsfjslSz/ZrV9AGbOsPYgFTTcNUe6n8kuhFczdhWt2wXScWFsOPKrYUkxgPcDojQT3LDPefDve1+Mra6Ai9Ptun8/hKthQbm2XSboGzht+p6vp++PZY4hlCbB4KrXIhRN2f2Jh7oRE43tY3OmuZse/yOi7aIOtS34+iaMIA9o5MkvS0d7beKrtM/sRE9u/iIF41BkGpYfmBn5RNWvLt3AMlnN7ej9DrUaPx1VaJzVHuZHfoQsCbOUgs4A3CJpm7th0OamslMim00/IemtTYZ9LaLTvZwMdzmUslKSKnm5f1rs4mRVa/JZEURzKwURjC6Rg4gUcctJmxlIxm4Ku2xH0WcAuNU+9DkGIjsMOCCHEIdPI4XWgS6rvZx380K1KL+NyGNJeFDQfJCZnOdsmYnOfWQX1Uon6Qi+vsFT5UJL+6Ka+wd2EhG84fZeNvul/REpU24U21Z4Dd3I1iZGH78HCPoOn5G8XpB4XW+NJXekMFToVjoAQm06jpeS9LTTCT+YVU4TYaXX//HDz44fzwvn+eWPMDiW8y+y3KmglJuBSJbwPnoNEvAyDpSh1ODGmF4uhppyvCercTVIYHgOujT8/L4mDpN6OWF0WW8YwQpV0EQ5V8kWdMR7zzu8iNefCybqM5mbZg4xm2/OLBraNRbL8olZacFIpqq6/N6Gj6vmhkBl5UDIajaaqFlY8VqljEREjOF+L1hsdG8AC15WE9+hR9jFAMX2RqGR8AsnZtCxFMv6k0DPPVLxtXMXlf0DQQ5xZcDQxTOoSd/ZL1sUQyXp4hmnQQ2kBxB1F36iGKYyw++JJozMEHzewgcZxavy4VJ/O2YC/s092CPAX4I5Gy3KrEwJqcB8DkixBZXSJiDAFc4sqdG9Tmzblcp5gT82p8uZEmnMGB648peTIncRa9JQmkzmS0cNNScpQt2HnOkMzdXnqRpt5o0Den6Dnq0Yt5aEtZ2Ti9Tng2FYiwZBHtAlBOGp/0Pg8AsK4i2dDvkzAuor37QIFtoremjpVpE/1Bb2s+K6W0rZj2qkNQ9myJZkK9MWtEnKLYBYxYxgmRbYgurr0beUUGPSBaddGoHRMtQ0FeBvqo6WuNM/AKO+WZjat2SR2grICebUe79u1HnFKOv2ZOMMJkexBJYtKDwghYSpkdgM8a9SfoUcftntY0gZrPPzoLIRhHpikYAJHpxel7GhnYpnaNuRkdtrZycl/qUs4uxJIuNSsUxBkisHRpZcmFH9KYY5J/EDM2s+BmULvX4dcXr7eP+urQJa8R0c7nUcALp7Cx7Q8TCwrhyInRdQJWy9UUvuzSxS1En/h1sxDJm8wme5X/FjIeINIMdmBJryg/JnbTa1kDavGjYoY5Nt4PmbDDQ1ZyHCCGT2SZlh8Dk8q7VsacCLZcN/byr3GXCNCyMqzSOsY5lPoYHNL0uFGNVODK8onowsWaTN5RIFu1bNcKWSVpLqt/EPVkgI5GLYCrlfYIJ5Oh+yADonlGvbO2otGHfr8hCxWji94Al8jPsBnaQQ7Z9DDEgU8SOx1UgYy6JGikeoquECXvcExuS1yLuyGWWIk1u8sdcR25rdbOZJ9zqDMozCKBFxDFE62M5PjIgvaHDVOp9wv7rMu7dxWusBcOrB4vksVgKVJmnbrw9Y/9vi4vNVg+nuZTW7SyrObXyo38H5q8EJ2IDG4P6X0DG6VwPNWAaJDHKeHfKvMBnw6XMuC3Ad4M7HUfipx2LgGYIx8WONm7MlJTdciC081I5h4r0FipxzJ8VmkIUk4bAu9dNuAfTuA8ewdKXDBLY1wm8saYeRmdDWtZ3KBofV7PAjSCBmyMQ0KTsp+OxCMUbQ83RsR0RsUZKLc1db3ZiEUT/oetOHjP+rQY8wo9o5uEOcNTZQhyeVN3MQ/AwzfmxDnfc92cL7kS1i+9rrxhoNXl8+Z3d1WPEN+JINuHWcf2+dDS0tsI7U+jNk7SPAkNjLLW7QBEn63YUx/P7xMI2Op7ZgALkNtQPl4MjmN93fHkjkiHCF5hHLC1zDpAo7lDUOfvbCYzb5o6kuVaOBI0wto+p7Zj9PNxRC2oOBYpzV2mFoZun84U8MKeAxyRGOlmf3k4khosCJs/JZIcEjAAW6CcA8Eh29Ouf5g31iLL8fLhYA/sbUt6qmVnwvM738ZLRJlGbqp5T2iimtABsnIAC6tXEPdXs5FGDaDVjjywZkjbcHRB9LaIythIR3MgPQfDFyR1ySuwzP7icPhMH+xxLJCXL5b5RvZgfyNDVIzSNM/UPYTAcLEXyzyBdpOfkFyTFPUCdTUfjZxlC6tEk70FxUHWRDqGWXC37BclLIY2dLU8YPSm2onRRk20YUd6r2ZzDEmhAiP45vmTxznZ5GS3GapbJm+ticlQU/tZyzn/97o0hdSlGbCy5KIbuQ+CqKF04DTmrQwBwRBceWi7+AcGSgQaMSvLNSKT5rfVzFTaeXZ8UkugMPoykvIkoeVt7SiEW72/aLTzK18qOUz0Bxcep95kjbYPzhCJXglHvpXDgtqxUO6Yqp2MBQrF/+i8UDyPn1YV9uvPA0Ui4e4fNlJapvIdxnUoMnIXH7PzS0OBuHizfAfAgMbvGaU4GHFAPQfjw0OxmF/pVTUE8JKU9Oi1ffqSanafqVNNQylSxriDyf4h6DodAH38QRb9fkwVxtDc+WGm+4FjOmaXD9xxyAFjNVrdcLSiyME12Dof0dqTB46kakd8x/j802xszefa4FWRgmumizF1IibLs0cyIHXxne+w+p4aw6poad4pi81la+3naSE8mtllzet6fJrTFX4fzH8/uGntqoBrXEnHFH1MUkTHikrPStRAl6C4CqJm/6cMrAstx0vFUAHSjCItyDXAl+5iC0RSG3tv0DX5LDKGllEBiTBiHxDB8G1J6xhTC6E+z08dQg76/qt7vu9Wq2gE2hBhBsxIcuDp1uCoVUz0t4wpmeVGIqWnwmCQzaiw4JhjdgrhnTECNVor4RhM19V6HW0cFCqZnAEofHCzQKt4JsBb+yr8BSPEG0QwLWpsqIGuWDWUZSkGGMuZiApgynd8boaDYolChAurClWoH1CzValJeZqoZTz6yuet21lnhRIRy40XtNb3CGTsw+jZcQ/3hZDjpJarsvEMZSPBuEP9vG7RBJ1SecD/nzMcjx8VhRFLq4hqf6WiDZjRSQ0EoOgTZR+lZqCMAfhVeAJ1duXmMzlHcKAOnBh2x7HVdGTMTEvDqaXYoC93fVU41DqUqpeGE+2c2yoRm3C56U+WnKaDaxiq6S2AWwOC9GPGF0qxQzNSHYLCWTASAEB33Ef5rY9wpqp6oWMsENCG5To+y6GHDwoWf3IRm6AgWfxB2l7nj/O5p1BKLe3kwG0i+8jiAHqU5keal+fcgkxs48r9X67NBjk58Ksj6STOnkaIYMwTkRK9w3eae3hTEIIsAZIi3KuH59A5PqlRnYO+a1cuSdUC7voshGfKl77RSqu7+kfX7mqWsvA/PX2z3JRGMbognUPzZPak9TtV2xjKMGwUcZIT/hY9tzWNpo+tE7IL3Qd2T6s9J9vQRmLHePR86PHqD0T2ox/hzUhMqUO3FubecRMe3F/poGeInpPRUQshEiQN61C++UNMmZxLRwL0V3+KDfAsJC9nE97LSLJMaX1Bm4AeZqN5REDmMmBinpcIEBrskexv9PRUxIyWaEDZMlrYFYvxV+XdvTssmd04yq10gSThU5k/ymfwKk7hESyLL7eR2dtqUf5KzEkTFF3LB4Qk9Tvy6NXMYCEGAFoboaC7gcv8tpH3t6gsfIYJDdzv7x8quwWwJdf3lRgKDpvElwyLoNTrl7uR611FOS88CwIlgmr/Mr6ZvNBZHpBowDvBv84LO/P2qU0RENrlyokaK535uVdqkPqiR+11TsxhzEGk4iApT2J4U36rhID96H/D0x77fblzNroqo22i2zOsOB5t8GNJ0F1y9NMotoiaVZrgWFYf+/sWXCMMAWPi0e0l8xwfC7CL9m8CVigNDbBgUmVvlrhmJWYHtjBKZcLVBCwUJ2y8tFsnwqcSxyIGuxEB5pAOIAU4ypsoEGsfyYOuw1ZuN18u2RPBSWGdF9MN3P6WxxWYhXRPhhMLnD3oCIe1dcC09cl018Ko/+M/Z6oXSRHMjhqP74Xl8U7nwOHQMupiE07qEbc6BASvVvq4RzyN53iVaLEjTkYG3drgXLWKBIi/ZaBaZjvKd9cd914JN9oL8e24QTSig6+B6xeu65qG5HL6ujPPZBm4LfYqIEQmhswvxAQ2KnPrW6FIKzlOoDrfgwxjYxLqZ94dsrjLTEU2xjvnxrlqghyLDiquwwExOFU3YgfBqS3VBLJC+/uxGU32iuUHMOEnOqtrOg2Qbpr1dW/flsY0b3c9NDc3Q2mEfY16hHH1RvjdpGqI1RrLERo58ifvz3WRxvy9/zzTQ//x6ZYBJufFQSbqPLKYq/ZdZJtdBgq3JaGE6ogJl03XcjRov/nghNwuVTbaA9+hUfI5mR3L5vndGjfWxQUXQAITgtLuLWbEYY6FBMH3/WUWzrUeuxr9VoA/6fVkU1ewaq+3uoUn9SZmt5BpiBfleTPOpnik5jehm1w22053B87Tims3gyO2oxTTW3c1dzwGZpX8ftGlHnX4Ip4GAJ9MGFranAFOI3HCXpz5TmOhO/1Fn8vPauOOnijqCLB1NE4dS84dnOcWiv3jja11phKxPz5F8zFNtPshwmua2QUCEBOyZAoxkvIsp7tyRKrKGjChDZUccO6X13hfl6LtSxmtlTFrGtFTmQOFP/3wKadEelg76dQb1e47Yy7/ZpQwQeiRaDt+qJlffCR9KAIfhC9WAQ/OvV4FPwkemNe+1n0qAt+IT0YBL+69GgTbP3tBjqovfj2aslrLGrO2tImy8k0OFM0DhS1y+uXt7qIKLjKxejkFmpuPdtns/h3quPEVvTBjd0Jio/aIl5INLw4r30BDGUl9Ou1Tyb5i4gzpaOzOMUk5WnvVEtFzXdsqyHGjmtw/zWoqGlfRbh+0Q4ZDvyhkJcYBlxgtYSsnZuy5h0QAULMcAvKNS3k7NyoaQMA5SRK69PKtyImMga/VzE2SZgbnGA1zwqo4EhiPuTSS0+dLZN3GZnSMOYnYKuIL68oDdPALz8ACpLAnoXHVcoUhCREKfBYupshyvl+6a3IGhYUWU2B+I9qIcVyCVcGthfFCdBOE8an8A5l+GwIYznse/vWGWyyGW9qt9DMsQYR+thYtBjlLhByAt8reut7tXSqMIik5i3FLiVHQNTsdGK/c9pcuE5LwZtLnPkh5R1V8tWWpQJj/CkqKsogOgeYYs56u+vhN+6LG+Gs3dtj2PS/pij2nFWQHMRTalOWz9bVut2uY6vMLng+BzXluXC3KU7Vx43/Qbk+0y5lcD/uheQovpAHJcatrnmxeLdDSHX7E/pqS80mCRAeVK8wuJ1+Qrkjdr2npzrdVVr6g/yoqEYWG5UTBaWqIpkpCtKHFAwCd6vmP6FFRbWDcchKguohPJkkhOoJ2xRgQeGBXySd26WBgW+FqhmSARmAXDGk/qGSTXEHkxnVYu5/2BgDPs67ubdYxtDOmoylPbiDGLbJPnSqRQyNYrJK7/6oftYP1VyQ0icbfWT2r/H56ZD9h179ZWU1CDHAXnb3kVnzZ5a/3c7DzTln1wM4fXEFsjNIDJ/sbEPokCfQuakXDB4Uh5lTMrojLPYcHxm0xeQctkzLpMMwpfDoJud3zeQwrw7Mo3JyIDWJFBvDGi5H37H2Tr0HftGZUYih9qFEzABRrORIXsCbdF8eshRySOLLYxUWcI/1w0R+jyBHFUi9BFKlP3pPkCoBDokp+Io09g1+UMntzJGrit1FL6J3hAhs/rzjzx3KGI0mKmp8NC3FtJ+O02KSn/aKY1QGmL3QBsfPczndCp5OPZnq7vwW90/wRAovdfRFrbjWEBXBI5VWwGgioaMvCoXa2h+KhYOVdAXgUIT4r9OYMKRESaWTEFLC+cCML2I1DuALA2ve5oFofIehpv0FVhIXk6qT99ajkUU34zTBJqkmMrIzHJyGOYVzQ9WM3FG99YqwU51ZDRFzPn/udd8YyiplGbAimlvzFOilUcucRvotnOoSlP+wzN3fGZ35OVyjHf06PU0pdFM+a52X5P9UI3AfUoKqvtqXTjjMDRWQoFkLCruwABrvuz70c/CqBSUMML6It86R8eDAuQp9xAzT0NTW3p0OHW17z9AVxfsI0QGDQbeKctg+m4479n6Apfp3J9NzsgsoB458dhDQxjgUXQjwe1OY4YqXYYD5maFAu7THbaPmd1vfcYfpOtS2e56ZOmbbZi9sI28KujfPmFdrBMCcY/1zqdbjFwVuTVWgxZZJt/WOQyju5eSa1tVr+/0q73AHfhdGJi+s5O1D95J1uZgZRd/NAtwejn5v4+YJnaIWBUykvd7kBg+f80QC26zYSF72Xx6JgeaomSQG8HzlKswfrZvbd4qmEKV+oUiotB3twIFEeBUKRY3z15Zex3BV8XBgLrD/gsQKuJL/9rVmWgSMfaDnJRB3rooEFFZ6I3vfxf8NmY6Ba+0NZwNvll0PzL08U9fs3KtCEXbi5MRJiFwTyw1fYwt6afg+y6Qs48nXerzfiNSIe2005Rr4NNr7jkuW46SKbYFRnAN/gIqC101SClkXLtgj3P3kqzADHgnDLoOCAmBB+dt7muGnbtCzZ70esX8DTjXKWhkyr9/uh2VqzGAf1f7LRZEr+A3IH6Xh/zTapxB+mMA//CT1qB+TNjdGrfHx3lekjN6Sxof+7dyn6uYb6VAg2uYQUqwDTz5E1c8JMUcXl0GTmQpotXFwSdhS8v9GenbbIP0y1dZCTO3EZd9xK2c6je44GFWwT7Y/1ESE2TwWb3XJCx3TXSSOWEZEr7W8pRGBMxR89HHgIy6D8Runr1y2Ty4/y5odVUk09K/64rDU/w//kIpbqx7x6WyWVZcvK1acFq9gK/cx8ncUrzr027B29g+XKpDhMPpA0nR43xv27T9DBelCGmQfMrcogz//Yp9An/616kJ9PKQcHAUhOYWkZsVTMuxAQ2A8MFUFqrUjSg4TFxA8BnS5aDZmEAr6zLU04GiOqWKHqiq4TumZg74+qQxd/8I0BWQr6NvE3DCXMTmnrXHqLlDmU73pBPCAmrqjQ6cepMJWMyeNJ+c5zqAibN9z0qrP6/Gdg56Htkcvpe7aqTLFoJwAtDsE7AOHjiUk5nOKY0ijnb3CR9/Lk1g0CUaRIaZ5q4NM+Y9Q2cE7ljFJUQ1m9Fz+cHju5aRR8UKK2TJQ6WgDH7ouOM8pU5TEd+A2hHtvtOkum/Rw/dFpN0BFQ7FM83wmgiQ0iDdoRzNqD2mrlA/P1+KqLYTaD15B2Q+jmv1Lue8Knv+RoG3urqKV4qFyqwaxSINNcHFLQFrwY2Ob30Fh9Q9U//ELy6qzpmw7dK7vbHMnvQg2EYcySJ52Njkj0XD5IszqHH+vka5wUJcDaiJuTyNj04tbtKLpkuEmJzA/2V321kV+svyty1vNFSE/VBKT2/Q4P3jrbSnucWHltlLiuX21w+MSDOYnqxwTcevY843YgD+trdB2g8vmL2ESEwHkNfR2Gch5aTTMZPpMucr/pvivs5gcOF3fPFGJNq6iyH7by5MAlUz1HUctmPZjoKjBaVIQl4xbw7BpO37+YK5bCjy+fdOBSYOM8PNUL2BCg7SIwx0NdSDkvWew+mZTKWLoHOYKB2923Jt/r00E6F6dGbs3S6OHoQPDR1ReXrElG2ZRqK3+H7k2LEBIGwFCBt5QDemKThycmHIPyBgJkD2Bjg/0b7hVxJFbIBJ+EtqiMtKUPl6QHzuIJj2N9Z09DWPfaYMFEkWk+U+oBqVjNBOt1ig7BCmDHxe8FgOqhXDU5se/UHN++VgZYt1wiRcqQIEICkD85YJoJ2heczgusNH+TcrX2yuHZh1KptbZ4HnQWVMb5p8bEYgf9ImOVsfRCQDf6bygGsR4qhxiIu/pstrK9z7BSKeNuSR9xJnkzgcUQWh+OKl8w9Ghsrvm6Mh+L9D6nxU2xOqTVzO/pbaa0VRWYTk23bWxOrDf50beiQum8Pi5BVPDKWi/KRzApwyG4ZFWHah7CNECalOkejPrKpxJWWSztuBtt2XuxhAQe/4xZ4Ft2RN0YC9IP+wBp2YTwun4IHGKvie2J3A+hSKiu5bbV/ZKpJCpBT+1NFuUTZ6ALRI7+9RZFH1YS+N7TX+YSmt+KxU8sjWD2HTctpFOeJMx4enp0Se4lXRZ4s36lWTNhxDietteEAI8eY/c/9I5jKHpVISfwAqk3tAHEeK6IeoLYNMoROJ6jF86N9yUUw6MGj37DyKmqTATgLDHUWBClYLzsfD2TWb06eoHp52Nxi2wmCxshIYIrpMqsh5GqdfgQEcO2rPCpdcYAe6OArAUV/Ns99RgLy/Pm/qJqZNXn1JzpyqAFpCNap2kAQm51Akwf4r+IwQ49jxnShOaQsS7lYiI3DR/NdQ70g56UuOCREN+/y7lA+ITsfnnkXgiRjcuiafqeMhk55bfBra/yoLefUgvMobOOHv7Am6P4AK3hDTFW3GxthSvQLHcoM0EZ14mmojI/IMHqxc9FVD+o14GEAAopZ1lmVW9ow5j6Khzc2eh8IPQCbIDxXrhjx9yKUXOjGsU7M3OjBH4bfEqUrYldKJhJ9/JBLatwLf0nuju8TX/JBHYH/kVE0L5sA3UoAJkZDX7RwgfmqiWpJD0sY2h+lt3asOGx5O/QOyL3VqSDxIQDkQvB5yoyF4V9Lt1Ul4YJw+zET35xp5RQK+PofRKsvLPUpzGxyj+F5ozcguKLCp+qHN1djd5Co0drD97fzArDuTXqwsaqUmc33hIJg7wgExq67khoIutB0k6yg7o5hIwm8ugDKi07DlaeIXrjBRwTmoNcRW3an4pdxaQzfLA/pw3Acw+kvmVh9AMd9E7aBRip1dSyf3t1UBs9+M7voTWC2Lm49UFoagIekLmfMx1a9qbH+gXuoBmq+LINcKeGq13rjR8F5HG8Ll+HUd14DM4canu8DVU+KcKy0k6Y4yLXO5MqLigc/wddaMeJiW/ic1rUu9gUsoXOdBH94pevjqu0b1UzlzM9HNfJ0rM3cPL6m4LE86Z33AdxBQrov1jY6yRiBN0jAU21vBqrna/qwTzu0Tup43i8dyUMqoqlgXNLhTcHZJyWuMVAieyOtcFZ+d8YkMGDYX17hPCMlD2y5dnXQXMCIwnT1A7AqyvgnWKDKOfHQg64cdoKnxFg9Vh570sbpdbauVjATYPIXIfS0WXAc1vng1M0pVG/At7MLEf2K4DrnLxI01ZbVFvUX+vGA194ikffttt38sVpBb6YCsL3RgYM6DKJi/mfNr0JZ1SoItG7+Nvhtnpizs9LkvxkwWLnvpVFSp6C7xO80HM6K3zPnegk5W1ERXmg+jPSavJeRquQ3cdyKdSw3Rort0ErI+6o60Lsu9dAGHUQgfQP6v8axFXy65QL5QwFcfKSuBZKOfcJYyzajAWyXW8Uq3N3oZyKpF3Cl4HwNGYJW9X1kdOlTV0jsp6rpOFA3DTe5VuXiEwPlT0eBRfU1FeC9V3oRj+8RwBn44TwldRFjWJQp4hnAjEofrmMzf6zEqhb5MAEDeDo6xcl7PMhb1E+yoeznNcMdJqBR/gSvoAQXKNdEhnIgBF9fpWpxtIUGmv0hXIugEW51lpGLzJRdsWTp8g0W6RTAWRcB1dzVGQWByi7YbBMNBzyrVjPuj3eVtE4ax6Bmr0vZmbDlSkgG8XbksQgoWtJbDYGhYTHLOtdb44X2J72VEVMKSRi+2M57SNanM0gWN2SN0dLfJ57PoZiLb6zzFUInZsAchApqtk1Dm0sHEUbuscm3Ay7mEpQpNhvLgzGbRDWIrh/g7nDRHrUpWaKhc1XhHcTtOOFqG14yrsFF4iVDSOt2n+SkCo+QT2ViNo4Y+wzSl3ssBsA+2j7IhKOTR4LEAm1qArHnXoDHEGW+RNRFMAYNVg4y2MYxMtiGBd0bjMokKIQtu0gLHErEL2ySm8IHeGmSJrvmsznngKXABkUYM+gqp3OLWPh8Z/HOCqNzdeLzoDZPkQA5bbJz7Dt3qijmakv9U4cPgDRRe+KZMHiJuwJQWX3jcvss8TrasOt6T6bA1S6ptgJQq9NpdVQLmk9KPulHFy+20NvvL1fSORPlJBr/tKI5geKushVnGxZnqYEcWZZjdmyItn4/NkA4WrXmeAI5b8lDw+EVQppej3Eb+ErAXN2viAjXYYtzUDtkYL617Nf40vg6RpFLHiHw72zv7HISTfyXeGJTnJ+5tAehnL1jEnNLcUo2yL1P7W81IqlR82o9c9NuDNW86FiJghZqJHIfDqih6V76/pNfgajmF8tsrWwOEG2tfJwXKtr83VTZGvW/eu/MwGeETrXAibRSSIzUuNDBEgClzSmTslCMRckNi7Qo3p7yBKPnfwL/fqISAf+U7rpfCod8BBGxhIi3SJR753hpMPfQL9XZCc3uAqQGvt0TJrFmxYqBLRo3qIzgJe2RHEOBMvYKHy+4FN1kpBTSWEBqk/Py4UXpkIMch5mJQhQcwhJtkrEzHuDoEDwlx7uiPkv/wFfE8CtPu6tuHOZ5tFIG4w0gsKIBKfhOxfzLd5bjD3x1P6mEaj5ve+Uft3RYGkb9CB4QXSUBvli8jBIrN+WarerU0Kr7Z1eb1yswLIyDJrmVJVMTbPaJ8+/J8EXcb4DwBHobgKQy8z+ArIzSL7GpagknzB6hdL+0Tz8VLoxkw+czDTTZy0RBZls3ZuicHX5mxpSjs6sSyLdiYt1KKdifO3qK7kpVN0m3uJF6VxfkWrvPiLHpY8J4zu1DNLzB793ZLU8zmXFD69C4s0bbo0juDVLN/wtb1xmZtT2lZcvJacOKRnblEVtZv1uKshUiwX/6CuQrMX06aJ23xSNqd8zdu2RrUFideczknC5rSVlbM9Bjavy7cLdgjEKiA2aXEsxFVh9jvJvOd99cQz6fnXCPOsC1vruNaJPxsEi9sH0ItOMgXvpM1E7eDiHq7oDJu1LqpIp9P2mmIqMae0Q00Z1U2atnPq93xDMnpIIsai/JI67nZ/pvYdxm7s3+8drFEXbmmpsf8E0aYdElcwQNwarUAXLNhk1EBO0pWfuWoExbUNNLClStDZiRwV45CebHjU8AUvE0UhR6nlBHsUmWD0QHOQQyBatg6fjIhsAROUTtT9aLrY5W/BxYXP9vA2fgGHnXoXK6bb18TWrdwN+yDp17WgtWIQso6oLEMdyqHmb/p9Wb7yz9SOTWMykZxfkaTv14X7+eAsiTNfb0KI9e4Hwevgi+mxz4mamxsq+8kSlO39a2ogVXmeBlZAk5FAaUERHPCvHPDm0PEfifYD+znGFpkbytZ+7t9mJ/AcUtg35+iqT5jLBpbYAJur88CFGaKVWGiA4as+7161ZG18dTFgC/zuCux3SJV8bBfPjVptO8B+kXle7jgbVo8tS2njSfpaV7DqYCc5vAwYSJT0hroLDRqJ9wSagvfGNqBRZnLtyOE6JXqQ+129WuwOCqEKiCuJfWiFeN1BgFLBZVd4BXHreSc8+VwazaV0H/XFOqzeIzdpYC1/pL71QcC4a2NaY4qC0ik4m5dmVjfGUfRNNYPavC+XTDJxrLQ5PmNsE5uTfLIFrwnXPRAIIIKQG+RYGE0Xog+tFoR95Ix0vptSAbG7KECieh47kM9he8QdNB5BCY17mKOC3K/1RzGcF5JopS6Bif25BcL3Yykx0OFD1PhwvfPNABuvrorSMbo4NaRt+qqKm744F7PX4z4HKJvjNNoYZxCR9jlppVMzFFXDU3t1nFITpAWWQloith6bj4UWmPrhulfZZKj3BB7ZkR2p6rOebtJAwiximrcqH7ouwC+7UBi4AjDlVseFL2NHnqkpGuan1IC0hNeYipcAy9il1v183BXs3DD4AcX0r2JcX38yBzYNZb7VzrmFg0fawMOwPSiwBpGPFT3VOuA/B/iR0HljMXeqOZJZ9CqfZA3OG36ZtuAyhc0Fvl1G+8vAtv0Rlaho6o4YncG4uJTD6lzs72c3hfUyJbxM2bsOs0RnOaPcVBs7sy6FeqUZQBWvsb1ht/gdIjkAB647uyakoV0dqd2nGedQ6HgiJ5EE1V6XR/165PPaX0hJl6R7fiSpRzH0lFPNVZPhvmGSh2D6gDS/UC7UdwT3Xo82Qdc3na0TbBUfwT+8NGJlJR6giCeJISgfmda+Z/4xTtESeL7cpy5mTbU2WzVbop3+IHzNLp+TyXWYYCUQIUJS77SMpQwgLi145LpHdH5GqoDrsVW3kvo9m0Ur2IobNS2Y+KvOgR2fZ32Bh2FFZc5OBmEFoSqYzdwVFuiO2Y4v6JxdBm0Gez2eBfVYrjRNrK9szto4xcabff5Ek+dqHWTqG3G42Bx3JIzgzFKvGqfTN5Z3rqaRQTarlyu4/02lDYFPXL8pFG0pj9ZV5MQLGQLsr7oxVALgGi4ihMg9Oa+FQQ7EgLUIF3oPV2pBFzsIVW7efF9ntngJBp1AJpflfNbnHls9iQ91SFbeGlHKErIQI3i1O0LOYQPJKm75YA0oLPOX/1DIk8Wjj+AQXBEky2+AMZkbymYr6o1bg8R7DJ9h2Fu84fzU3Kg07kDMQs41X4URlxx9LZuOxNzigXzvIHAcWimeSKjKfVEc1hpGJ2tYH29FVwuhoIbDOch05mHmz54n5yZe+aRuFL/D+7olLSRJGcQHIltoJDpo17Kl0JAwo0aXZduacWbkXbgzPR/Kajdh2QiPJHyFx4Ge36GgoyAAPU1L8HMHmlYGZpoiCZpvsoMRKUmRape81sn+j/IdTp7i9tiQ+qLpcYItLKSG7KsQb/BmCexn6OVirIBlTvHW/hO0TP05d8YKZ5ipfYfCwVOqkUxR9Z9aW+jvn75q1nQuVKgy5Cw2v0uUl8fR3J99xo0BOn8xDB4xe2YmMGV4TGkInlmDOhV9HE0z/DMmXFsuxHm85/69oohhbGaAwiKFzuPeWBvE1E6DiorgE5dsa3+KGNBdgyUsg5Sa4ZJCiZMidQ/ept1lQ00RZsW1WniJRYhDwy/yS6yQN+KC8vpuIzzhyru04KmEyFIqA6A7AnDYgFuEmeuNLCBlRvBYhGU6NfhIiHjcQA9AxAgI3FPA2VAxABeiqoRiKzhFWDi9g6+xhOz3RzNno3mRpwFqR1sgq/ZoJvNjlUNKORwaPjmKMEa0N1O4j5uVW7/Q6wliSieQt8A3fofe0OWykocWl1sk4fcfZzFc39cYdWd9YAkm5SQBJJUIxzGw4+XNXbxLLxdqeBobObRyPklP9RETYyI6JMr3lDVAZZGN7PX4d9rudCZCxXrnQsNiOXyi05yNnqScOsYLITbPdqpCK8uS7zg+fEya5sbHPLx0e+0poa+4a9Z+K+5idYqzFWL/lR5u8jz15HT7oVZmuO2Ci0crQKPESBqBBnX8QFXyCjUOkZkUrBJHKxS36KPpESyABg5Rg4ccA6imp7jGp24ih00NpmCgJ2/wy0lw+wL9N5223rYgk9i5bEz7Ye8MbrpjMmcfONCQK3HTbwU0BKa3iAkJT5esWJQWibyxFKpay6XO7VxR0BuuWTXrQix6xp17Pgx7gavz/CQKFMoGmAHSNn15/Ur4eHg8UXymxACP0KB/dAAG9wvoGOPB66Hp9b0H8UvqnQ81GuZRs9g4NSar0Hp4uudM7x/9pDp8BjKHxDr50AmhYlyqRciEZdGV8OSCX5lPXsKsGAUVlXg3fQuo6ih61AMK9cgi58CusI+khxN5IwC8qtjQQyssuTudN1Llhw0HRAnwhQHIITkbUo/gIopEIXSMM3xkOfEgWWdCQDAzUGK/BvXmqT51cmATnJMEmdUsx94aBnUgJgFntAd++St5MdCpSZkGEtifRwFn1DBKuKEW1h3lmRi8jDJ14Y4orAUMt73O/z0EYCfM4HMWyh99w9taGPvzO9LFN7SF2j+XKC6tNlDp2zrTHxDyqbA6Q7ERMzWxP2i2HcU4e5YWOFbXp4EbSZoMPr9kXe6etDw6xwySniAB0y35C/cA2IwwxSRpuZGe0+HPUtqDChSj1VI+bMdzeTA6eFkcI5aAf3/nSlIyHTGw+SqINS3teR0K8t3p+ZHi+cek4PNEaOYTVfOiucU/m0Oczee28lxit5CxqhqIn7orgm3hy5xS3CWq+e4tIguSKhkYFHzYnb5G3buPUvfAmtAJzwUS3PaRJUrc0P2jZgSs4liWtZCKE5L8ial0stcEVvm4UQ2F6iJBUwkKJ7jctLkQ4yFil3DhZPCIEeSEhzH3sCmRR+cepD5Scu5iC05SAKH6n8luJDmuP+It0I45Eo1v/Js93QAnPkdjY/a8Vh/8UrfOkfyIdom2pMXhYNZ9Iv5zCLEgNPh81bDw7EjMkuJeeiJDT9pXu2pWgTyr2p4KLMA43p7Bq76hVc4YYRaflGXJd/9RB9hJT7pkzLLy7ynWoGqTYNtVb7ScZjSRcBuRAX4KYccKgE5EUWumg8/LxRErFYIrzrFFxS7OMyD4GV1Tlk96t9pesToZqsbsns8h9FKiDO+G5fse12nGyLqqBMcDZf7ThSe7Tk9zGlCUQO6VbkCCdBR3+Fvtj3MVDrR/PZ/7xO6b3scZ5LF2j4YK8AvnHyJ0adSQIwC6f0Pg+EVwQhegHwbmH9vdlQ2CBAJVhEsZuCeRM3soCuBS4GLGEdF0I0qf+AAEBP3O7xXH0uaLyPCy4y3j3QeuYrLxYSBZLoI7brDIi8IA3vWHV/fWtS8/ryxq+5Mo/nXEYaQARhkCyAIsAIABUT1fgh589PqHMuGIX49j1zy24MYEccqcPZLpehyJj5lqPvaF9x7NUrSRxmNo/4nn/RsDR0l2P3qMZ5vMWBAXHxqM8LqEK2oJYYtg/OVU1jeIGJVzjUpUIYsPeV1SyoCENcxGDa8tR+Dlq9SGDQw/GkK2D42kVx6SbB79jMkfpNW1SuS5v5QH+fofC8atOTfsoq28X/iPdslR/0+fQViLGGqArZT+W7b8Efxr7RNBmT3tHshcwuHKBRIYnBMnDIG4ozFkfly4DkP8ws53F9wXmhJCu9kouO6svqe0w4PTRu58lQ87KRTc4JrwnlUSEEnK7ONWRc7lv/QMvORqgWfK/Zx1OWWaAQ0QpB6rIOmFhRf/PkEjrdrjBlyWYK7IX2cvXmFkzImo1WRv5ZUAAkh0j9Khv92Vm/Q8QdDIVgPS5LcUbTJ2l6Nh0QZxfWbN16WctRc1soxYSnmoKnmfUEH4EaeG8/cafTJ1I4Ct0JZgn113KgJomkrN8t+ugzhhl9K/3HCpPK2zinW8XE2TCPe5vTOGXo6amGb6bYsMrJNLM+fyIdtTX1HR4716E+OC31D1Vz2Yz+3kEGmOMRV64OpSCuiBnDqGQ8rNIcx+pDvIgpm3eabOYZgMI581fQAzDppv5GHMiJc61MOXcsxJaE8P9PYoI7eUtl4HIE3qZGyZ8S/TiEm6hxzJivU5gHHyosEDgQv3p2gN3IaEmoGty80kBziX5619mkqh1PrR6sA4/4Tz1mVApIknkxTjOoKAIiugAZ1GPSCx0mD8DXUPBp2khjBBv22QPF7A3J+2DqRod2DVPvT+AAOkJX6+wQldfRVqkRgji9B/LH66VsvTuzqyD4YBRbeGwKHzQGw/+iTOMG2yopqMqLA4uAa723hn9/5JbV5hKHmtco/b8QJXUQImudu9GiN/6LOYo5CBEcmUhc63hn8+sOgWcsA7FXmTFSj6Q3X4mLjRtlGclTYduj4XBv2T3rFyr6W0mlZBxaTXDQQEohaUkUYcUKk0M4saD8Fko9WBXA0fG6mMjt223CWKeagJjiEFSf6Kx+bPdbX3o7uK2jTIrsPsY8ZpjVjIoOX6ngosRb2oPeCAiD7+KpvWVjWhmrrrXCOKb2y0l4V2hpdvq5dv7/ACVd9BgsvHfNowkq6LvyEZ2Sa2Z8n9+Sw8ajAZzaNvZeyf62TaAqiwJ+pMSvjAbggTYjg+PexKY4eoySweZx9jc53bKlL8nTKj0Y4I3W+7Hnw1WgwnO+cJLRp0AQVf6RouXgxWCUHWkKZ1RjKuqBeRd/tusGEzepQmcIn6Ca05dqXzowN9FTd8S2sgf2rDm/nG1OrZsqLSNepdubsp/+NkQTLewXnKxz4IdOTAoIFDazI3OYwQjWzUMGa4Vy9y4uFCC34WMxRQfGNCinFjF3aH6lLabedml0BZAodhMRMsMyrLOpYtIMYxeS41LR5gRqAWRL19Dcv8g5OTyfgQVa6hkinyAb3dhbM0bJpEx0KRssFmS7qEaaSZS0YKuia3MW7R+eKDRkLPLM0BuKPswJQgTe6CZu/bVv2QSx1d/f4VB6tCy5RPW3NZfv6vdbhVv9iPqB9BWmefVq0zJtNgzrNjXYBOhCj5AnvuVi0OvWMKzLIt8E0GMZH1Lhf5IIQBNFdlyBsiTANBWYGrBsGm4F4l5UyRnPlk9E3F1AlWdwuyzF3C1jDGLIMuL9FwPb8WntoR4mzqyCO4ihAlum8qhWS/87LEYaLRYkhgHwbSjjfqZRUCWqUdjBxYXeHXRLqjbE/3G34qFW89gD6XLeeCFilfEGHzWejZXOtT2EgAhxx0Kw4F+xni7iXiUdzDVTaYxqtR2Q/5A7QWgkqp7DE8AlB6xsR8kAgSOVURL5dHSwNBc6g5VLBp/+5iPDvclzmsxIDZU8efSv2pe/QMZYTROES7lDOdjjIPz66TW2dvOVfxE5WE3lWsS3U6UypHrdpX89liJb+v41AI3fLt+ys4aP7dfcQvXtHTfZ/XCTVvB1arZdAdO3zV6+vvqnx/8230VFj5b4gQ/+dZUHD0/SehYeB1/doqdZ0sPCKhEvifVYX8VLVxOz5HAH6CAGhBtcqJhkeiFb0fSp2LgY46l0zDAD88EUihgGSiC84Yc8tDBADusLoFk7g0dpSxcFHAXl0pSMPn8afxD0TOdBo/JqbeD8Ne6fM44YbF2PS0wy1wOcSUXlC8Seqx1C1ykVhQEw0+FajP9nrxMXFhJwXz2IZG2XLGkTmf+Ll2WIO8hiY7pXJDlVji8bVINrsaQoqLgkv4RFmR3Dpn8seDmWzMeGonHfa1ocMm5GDfhROsxhK9CuqCU34UD6Fu5RKdj4wqLtUT+xEYj0mVw8vQGVChpTYHd13NCxoHFf6WaweIYTpNAgabIOL/lsYelUDC+yDbaty+3I58YYeGTj08yGx/sJ395mM5CQZ5IJNzZCvklYu6Uc4dwYrhbYjry1+4lhFRFCMAPQXIpymtx3DH6wtj5pebZ/Jt+5yMi9WWa/IrHbFVwMs/pLCPHrNn8g9cZo+OqHXF4n16D8OzhlAuBAUR00Gtgw7cznKQ7+qWu/R+7IUuCJ3ZdWQqIiIMb2u+Zd9nB/SDTW1Y4KyiPiFqqje/2JwoMD5ymnP8frnCf9UN71ZSdY63/s5C/4iohhSUsZ2Q78zdYlBtnS/rQ67ROeqVIOi8UgrCzb3eEMazMagDp2aEmfob45XtPny/UE0Zz8PrAuuZwE3tYqaiV2U7pCQ1wHc4pXjswhrH4ZZqQ5smVcdOtmk64IBsfblwGF2eapLkfGEL6qjkXxWMKP3I8AFO3T9Mf5hpHqyOvd/yrMv0gFOF1Zi7qoIVuwKg11JTPOiHZSsMCZ2rbV+x9lfDFrmm+GyauEM8DFIpDR3FYmeIxtxvLy+J3xaQ2LV4iO3RMv76bWRGEYJetQ+eAI8CacPz0BbOUaohqvJxsTUNKQvmfGJvGbffg8XyvEFuUPRJ+L1l16Y9F9XCtYCKpv2Jw7FbRNXXgMjRba9I1CqZxKupJ+x5UH4oD5qduewd1fQ6Urz7UtYryK+IvszAo5I59kQualULXKq3mp8VS+Ecj+nvRBsiU8EXrg34lAZEwwgXh7/V5xb18Z+JcTCbzzrbhADhxzuT3wklVvlLta4T/eCejyxWvrGydgdjArNGWAf3jDL1SawYieMqP5EJ/gJ+P26geYB+12PV+jdVYiP381BCO/ffbXLRiCJT+448PHSXfXiOKLtyvVbcr8IU7p1lzvXM2P0D87mtZ/olU8QzZU0deo6ZF086CeUSNFKYzpdXDGcxz2DXrZSTf1JBQjDHUddu3WW2AUVGvc/ROsYZzej14e1Z7zEftk7hL7XlgNNqNttTMLJbllA04coA+6izvfGf3TRPUWvTvmIE99gh1Icos4T7f5x2tZUxWeDb3EJ29DwXDChPJ4Zh+DuyBZdNq4T58wkVGp9hAbniA2NnZ+P6wck5ZRlu9SQQZQVb1mEeR6zY8hy3T0JOZXZ9ROj9szrCrW1UCjvbqBJFVjF/IEUkzsnuKJBKUPp9q6+z1Ch/rfcOgJGs/SU6FRvfa6H7heUn7GlUIRHRYu38luMVPXDt0LJsqqDbd418Di3Yun1Sbw/dv8LYkxfz4/Vo3ddb74bPddQGi29NtybRsl2AKpPFBz1C32cRI66U99+w+kJC0gANCe4AC3k5dmX4dtmotzTK/VzG5Bq42VE49kTqN22hpmXJsbtXw0bGdgdblMVZfkvYH20s99Q91PwBPuk6DSx3JNzjDjgpYuKYoxNz79bk7HdW+IMrrbRzEtMzVBg4CxCJVVUz2TqCwL3JzBWYDOs50seRCq2YXD5Q/1bvSb/F/tF0JSezmOM2czri1osaoD35fUQi3UtZfn49rmE/e7l57RsP2+PzBEnAoC81wToWBeZLjYajJl/P+pFmtbb3n53dIBMVPOteyXlXbmIaW+K2hkU8eE2duUiGoWldlO+VxbHSCkO02VNeknXSQZi5vGOoItmnZzhm6Lv6OCflAsyEJ1kLQmBGchg2WY7EKDkTDgGqLjRFZAqHs1ZzJsZBTIwEUJymGnHuPGJ1QqJg3aOhP0qRCEJcu+/W4/vrHz/kx6vAugF7ZsI6lK2gVDxk8tjqUVS4ZEjdpgDBnVPb0tbDdBWK2k/3fukhQAsW1mVuxNyF3XxoKtu+PmXBbesQidi0GE7Ajwy0w3902f1vsaOP2qtXjw29PD+M/sxQC+AZPVRuGaCRGA29qN7T75qA2VYjGNl54iEw6lKN5RrZdKEAcgpg9vasZaaO2xCJUwkF21wDz/QDdZgLeqeZoUDj2bF3I+mvE6eXF6IkmmcqQEl3SPsYsBUdbfsY4WLK9Y8J3XM5kmJ75tDZiodTj5/MwC/JcROn4Zd9UI25G2F9U3dOe7gULWNRT+cd5U1/JQPK9FUs8l4FZBlcZBu7cMwpsLtSPF7TtepEMNnRtCAmQKurOaIwOC3xIWXsi2BE7wndGL9ZCgPsLAcp//w4aM0kBHLf3uIOPEP3eFuxii4Ao8EKSOlzbY+WQpfeVRTOnVsRw8bgW4BXg1jsaP2WmFObwqxCgovePjQ4XF2IZGHA7g9CqkJouGSsARuSZuhNNAwV9eqqvWETQkaN3LS2Alwe72ZyU4XNIncx0lRHU+1OKOpNEBRhSX3eoZQCncSAikGx85co70QpskU6xPXu0/haX1nCqnDTqwQVAv4yiz4wYhaO1jDl490M0/beILUjN/pMIpHymqfsOQqI4Ujdu4wKPE1Ro6AHbech5PO5pyhxBTurIJajQdBFC1/h6pk2dG/H2H2EXkPMBKAAJAZUOMaB4NX42wQ1WJwlPgLojAtaVPSIFmNi3ny2sqcGsEEfS7SFhJ1EVP89YW1UbDm+S8wBaFbrJCqo9AVPfE1YJY93TkgYotJ3Cc6HScowibq+lLL8vh89LUIHqiV7U6oRgZNrJvliAITVEI4iMUj3IdRRjorsgmwUKlrcnqP8XUq/XDETUR8DtotmGY4VZhtxLhHnCcYDm2LNhgBZh0lhxz0cKbPR1iug4g10jme95j7JNhxf6jrUAmK15XuHOlsgGdsE/rHySriDpwPL5yLdF3zV/RVYVxmwI91VtBKAdUYLAFa7QAi9tggnhKYgGBoCNtt5kkLNNLnGmQ2d4O71e382OZSzOAMPPK9B2KHujr/Gj6TqaPExTi25XdTLuehRYEIPcCnP6JfTw+kWuojjCqbyW6Dsv/+UTt8Q/nrPbCql789dH3DP+yuPFc6wlTN7RyC7Oy9v6Eth6TBEOfVEPys2zL26hfJkCEzxrWEXbF1N1CiVtt9vXakggtXRjoCW9w45g8OI7tU6KTQzK/MrXOV4dYMqs96lixXrLG4as9hcpiE0/S/3OIQ8t8EUxE4whT2uMsUgFUN0OZW+LPED3rt6/wUt6i6s7dRjqpV184DhwZfiqSqYTWya0Hwoq7g8mHTdiIV3utlAd925FMWWvKC9It+JmK/e+Do5SepknyQP8DSgu1HHhnXOLb81zXL9wjvqpDHerlM/HITMJl5UXxbAGWxkxSY8Y+ttLM9UpVtiV4ec4fsGnsn1vuLHxqk+Ek1o97clkqHpyH6CtrV+iW0esqZqrQDNuPdPTbJ6Q+BDI6ddMp9pKlfwbp2/zkunZLnwnOS54x4VVc1PmjZw32jJZc294N3vzEczEk0ea+ktRCO5cOeqoHSg+cTp27kb8t2a6Jl4SgakcfWJMuLeO0hlRuodJcfDnWM723J+D7lkSx0IhuD24Cn8tyt40iSF/DT03F3yCQkXHHcOQBJAfDniRA2kuQhNNkwFjk7z8FcTCtk2XQXTpXokWp+k0OurHidStDO+JrFVyzcKVukrG2fWcs3uKTbVcJJBj3xvKBIL3aDvdnMixNDN2IAHpcD9+mUmmNXhTWYe5oAx6TOfmm2XAdMV3P/nqzz47Lp3an4uXPYd9J16C9i/Pv89BlT/IHEc/XcO6mED2rN9sVr25Z7X+ZIyvlXzszDjv0IJQgzTX2NVOxrdqHlEiqeTsagRoJCXrt8b0JyEadRNCN9OqHgZAuSAgIuDpgmkkwcSkN20Kw8WhhSG2oxqJtMoTXemo3l+8w3rNbM7MW1iXUNYv66LN9/akEAlAfRdyfSg/gQpg1pPqh+JhDWlJopFzyWc6H6UmFIrGlxcYGZMgGRXJuhmia3JMuH3xrK0Oj4hwaI3TyIyQ2V45ydqI+M6LQJG+zgaZMj145Y+idKoX8n33WE6bqFgqCx0YPRbmrzdmS6UTKt7/aWJUn+anO5wq7CzVdKEb4jxSUnFXL8i68GVWQs7uYSH3twUp4go3V8lXfcW3lOnVoKo1uCUQno1tV7jnsZFJllpauvUmkzKKiu1VhcalOe62ybZVVl1UaF0QTiJ2XVyk0B8K5OhUoSB9kvFmV1aNbsjzgjAC0LcCZ62c7favizvvZLop/ILhWeLM9Njs0wYHsnvUz4dTYdyKSR+lcle6SCumkp1fAlLQfR0DPZTnAVuUiwvlGAtF+82YklI0Y6c46Qs32IqCOyCG4yjaDD0ajI4HUhpf+RWDa9HPlFjczDDuROVaywiSt9uRHIYXkphybr89dt2vTaXVKQPoVrFTWeWdjyca7Wi/jE5BQuxSDP2iIZ1zufqMnk5r9WlfelxUWmYF6bllvaqPkiYXc1NAbO22Iaej6mrE1L6PMmppFJC+4umxqlhXWohUzYWRl2h6KP8ChxA9hifPvQpX1pqIar57qAiaVuop6zkNnWI8ScW0eRMW6mEKS1qzpwGb7dp4+GAkCStjMW14rE28na3uTKI65SEqcrjjfqSRNIicmWORapTMW8h2zXDl32hOMlt3OHiWneDj5NsfGo5Clv3Wb9U9qhPkH+O3A4aTjKhp9Q6ehZivOUTQOFQ0WundUlwWNsWlFsckmdXWMm1/V66mR5DqcWt0jU92ScCMSPsnW62X1n+gxvbli0wx2gVk94UnxLO6cw7pBYqaUWTsc36aczZB6KaFyZ1Rk3u/CzaC9EMc55iI2Rp5KiinLtcPLBKnftM9Nm5Nl589UtnFXdvxwtk/stO8HCtXt247hU2ergVW6twjGUEms+4/7J7ZCOkJuFsyVod3assY4lxjN6OZj3EPZTpxdlIwdPgx1lhOma6qVhlGvh19x4v9eqbJZLVJMx09aMAaAesnouGnCU/dqUKkuh1lDPNBfItH1X2W3l9IVqd2pUcBap4vc64zn/RiVXQryMhN/F1IEboDJstO+5QmKYv+wkNQCPP0dm+4tA4Y4TZH72uzIztzaguvNhFcItDSYF7Dj9bKO72arvaE9a5ylaNUw31AzFS7TxSn0KstnjI97jHSrwhzxWDWe4q8x1eHbv79teDVbZJg7JNqCjZTWKLbO7Sc9lJRTkwOSKgvHcDep2Psn1jYL/vyWlvm3iX+bJ3ZDONHBU9FJvdhlZxe5Wu3AE9DNanFArMMbrHSq4NTZ/Og1xI+jNaypqmc+w+dCZ1XoXDNrHlJIx0yRwEjHqd3GuNyjO6/rUlPOYTWqSovY9nYWEJatq3djs5ccXEElUyTb+7MSDntCDfWzXn3xNcnzPMTRUSw8ttYz9Wfos6nx/+5cK8ErZ5/KamXfzBWT8lwv7pyZBJmb/9j6KMm2Mre81Cmr9Dul3I38WULtxMU62MDGDVwoTFvs9WotQqzOOiRspnd7fM7m6r724qlG2HXwdg7dYF3IE9/9aiWltByKi483o8+jt+G1BeRHejnLxa7IzdQ542oyeSazI6vJDDG/YQhHPckXOwVHjbYU29C0BnUga6YF8GnD9OMtQ8/0E3J7HKch66NjVgcM+ufkSlcEMXIguITOkDZ8uUAfH1zarU5+MONa+RzUPNYgn4zF08ksWEVI85lMyaEVidg7QHkPeAdXVTMAVPTmUL+4LArutl8Rei2PoBlyJoLBgCxXirXmDso0RHg1c404Ot7BZcxcxBZf0eO1E4cJzwBS5ECAoyA+BcbfgF7jZ9rcAAfsQWZUZYIM/C4df7aflRlOzv8t6E9rrropsowfNPQcH8Ofz4sPGT8SL5Qh2YNHcPNcj60DMaZpeVoOh9ymAGTqXqdtGUKLIg9NlOxRqNO74n1kfhbfSfIKfDJ4OrVOZmP/kExX2VhjzFECGx7FUaqOQuu0abqMO5kntiO1tn8RaUdTMaaVoBEfNJPlW+6VcW2vOY8GfdsfXg1FJFa0H7oQsj9RYf6RjMtuUTV2G+yblcaatHeR7q0bPKVoeCB+F4MWVBQHfSN2MIn7thmbSOYqq1TxZyXlawNeUq+FPeShGXaq/e4GavG+cEf+JInzZC34h1zta1al7Qh0DucBlZVATZUwQyiwEMmmlAUwgQbwCsFGyaNXDNVtY72ZS049ualMOhMCq6+hxwLVsjotCCUQjzgdfgUItNUoJJUtyEp3MoyRRGGNLZxFzX3V3zd8we1uy+4hZ4m0PMeeSdy993YNwVCi3nl+2rudFFuZp+ogrlCT6jnrHcfDNhnlc5f81xnp1BCDa5NrvlzOigrSNUnia6opwpLYKQY686xiidTAyxSl8SeoEJFUQFMA21l4C0nu/8KgZ58urD2npcPhp8F238DtsdtrxtLfENt0JTbheifcFg/BUg2y9Te5o+B4qcitSHF9k0u3zSBvOm9lhmSWHPgJwlk2WX+to7WArs2S37ow1qnBTM4RGO1KDP9YUfmPTysT51aantlzxJhbJpiYv0TB8PK+M1S5EFocpO1a2L+Ox/k6HudjfvRu1JACB+8bhXYVyBmyTPzULu1PFAsoJPjxkFm4Qp38dsKjS3BFF8MPoCONt3dwVJWT6Lpaavlwfl0VN5KSNjpFmEdYLpko534TsNqO6/DLBt9PtVMhat2Fwiq9Q0hs/BqLDCXuoA8ENHzJsf6+NiGzZ0t+E+q00oZR4YLyKkTurGMpTS70VmU/+HQ1leUX7XD67xn8W1ZgwJVprRGsP74ScSRa1Rtg+J7/pH0GP+yMOCu+IRO+VTBOnEjauu/MzkeJCo+ZQE4gW5S3lHcJcwzVrc1C0k0DqNOJUm+RBUP6+CHROhtYxwlCIhjEwIeOYi4trOKRsXiuKCIkeZwpr0r+GKlm5tXJFfxUlJPTQppKzH/aR/OHLluoLfGKeuhzLhwk5HdtbczFoh51OpuWNpbJd3TEeUwBbFMtgm7F/ndMvH1f9+gQMk5DD0gmFSt920ZDehEw5VRAswvMgnL7ka+irncnFgDeBzOqQ2DFsKEnYndVlao48bEyKj9BGMkGLA57NZGtdYrLCc8LPuLTwH5wyT8ykgg98Yk3ttBtqTy8HurppNiMWTFOKYrAhOAEUlOTI9QTZA4rtymyFmiPWcLand9bYCOfB/ug1SIwwQnjDgnh5lKdtjgky5RIyKo0pCAvI7XWxcNCpilAIjnTiTlJ9EVs7labivqjg+xQq2qYdkZUgVVKjq7/9ag+MmIheVL6WYGlbUV6DHpj2zfOsN/NU1qk6Jpp1xdLGM2SUcZIT29pZB5x3MbfwF/fLd18EvpFZi7kLeVocM7/1c3OXLLdwJty6o1jJA5iPTiC4feTSlSDs85V0wudwYGE7zTDWF6bwQyhS15kTBLL90gx+mSl5YfBi6M6TIDEM+kXAtGBFjVlcTsEpdATLsUXCK+7VWMN0yPEd9G73keW0sS43n6iIVkAyBPRyMEE9cErbfj+u+uLNyEKCSOkSrEgJ1v8oK+9VEkIHvUR26yqtNWhuLTdMZIVHYqV5pBpt15AD8A5VHRUvOPN29FSO+8ew4SA/DNddt8oG7XgP7WYnGYUUAVeKm2i9Q6zFH5Bpyqmdfw6sFQV2OpihI8PPxx5jqiqkN15jWKO7gg8L363Sr9jQB/nZpZdNzzQWycxOVNwbbuNgwrkk8vqMt4/g3SjcT3Z1kO1bI+MILxFrfNmHu3JjEHwUPxVKFD3+Yhwi0HB8bHMgWcTg1DAjp79UVQWEBEVtYqxqPZJhnrSfdeyyRW9FYe/Sp269H4nIJ+85225Qo14yQNJfOl3W47f8AGtry4/D3OiujuxJMUWhx9teW7v5Qgyu/e+l+LiudLN0jnKkJnAAEpovL/3piwoah5ckoBEq/15r/RhbonG/sj0aFLFp1857pQjzEYrVErvCu3XVLFDoBzmZW0q6rF8oygI7D6+z39WCUe5yMgDtE+uZa3N0nxuUZOJoOkNNHProiBAw5QZoF3oaOF+Aj70L7vn8MiZQ5eTOsIN/OxCR8eJXezKkQ56qqLkVKe3CLu+AdboSWaXp/iCWdcYP0Y462m3hbVI1BzIevHzp55ul0/q7D8fzBiwOA3EgCP534E6H1gDzLC1vZbwE0Vl5qcPMtCmQyGEU9BDmlVRtdjrU9CaXJw9RiK1WMVnSqtR8BO1CJg0OhBvttBAVeUbYnwl09NkjokELchjbZZV7atY5KGJxYUfNGS64LNsvBX0nG6UBhHB7Rj6lgc0NIovm5PJYiZHaEAzSFa8LBwoTU+PvJcDnTk1hQRd0Cp62/mwzcNG94e++Om5EJvUKNMPmPsXf/FU58fsvIlDgvnjFaRkRPMfVIdUrweWB88nQFaTe67rzJ9+EK2oSv725Gv309dDz2Pks52Mmqu214fJBrtPcmBxfTwJepCtrA8XNwwnAOub8ZjeSDV4ltSHBzxlRKUfWZbl35KYNNDbmP99onATfE9686N6zidx1sed9Gczy+Q+ZhgTcULUc6K2H3JyDuVCloPac09RPltr6JLSD22UFkR0Aj5bYX6NevIgpD5FsdbGqBooN+nlRrms580rOlFl4Teh+6IF8sQES+UYQ1EfA5tH3TO8zM7rI8lEJ0IyaM1x4BYoLWguVtv9tHTLDcNCk3fNh3eKjgkHYNOfC7PXFZw+2TEhDWGt2gM6mmDSUEraUDmiQcqm0cKikZGWx448Du3GxgokXAcrlBa5mBxIbDFikCUOPjh7n5kUwsXWzTXuKZ24SfbFCF9iTYNy2oLHfbC+h2Anqe4UkutRfWXdD9C3V3cmopBjc5UqZd/UZBbL2kk45hcE6Axw+/wneWAZ+NYobI5SLIAulEo1ICQXlrCUcnKS8iIOqyOnNrqDNjKgbg9DuVo3eC/KQlGHYzXgQSxYagtAF+/hH8BggsoEd5pWFjuABVVrgAoa1oETGHQtHaukBUh4sETwF8WcAUFBDBlwg4ECRNcqp26A4nAmPGwzbcnWknjIWbJ/os7LxbdltSEhmgC5NwAvDSwQjkCp/yF8l6mUH4TQm1LKpUWVGCgAoZMBE+58lHrih//Zv1ML8rxYO4NkE/Fu8Z/31XwU+cyDn2sZJNAp/k4W12bz3O4Nv41HnyAiyNezA76pU/JS/73eBuEPXX18LqPLp1t9weEcW4VmdNkx6b32eZXlX6YsmjT8x3A+yBUb3PpEdL8AVcB5Q77kcHip+GhH7XI7OkccRp+pmPGLEO+rClBNSOQPKAmqk3EnybUKU6B1VM1LLAiRDVdCYIuyWo/PLZObqTL99ogi6f8w/Zt+JAFgZSFW387WeqEM8p9GYlrcIyd82D0RMLeqwesdS7U98qUCoouJPlQdsbny6XsU5z7U7JayX135INNTzZCpTbjWP0QNh0G/3skJvN+cYv34bpM58zg/SZQzI5gnoxf2C4WovXcFlo4byite4FpF0/bz7zESslMfq4NsJ1gEGbwG3/8ay+/Wc4yOtz9x9xwHyQSqsGZY4GPWJ6XBfz/sNdaZR1lcxpjc3Ll2oC3/WJ+Xz6rmHxcdxZHpClKgqiWbmZEYBPnjRhytlL4kos67A6SfIUz6COPvWOS4hrSF8Wl/u19O54W+AkK56NnWmW5pmqY5TbHTgdClLDAg92AslKZcu4X3qsiluFx62lA5XZqgqDRo5YYWsqdyk9Vn0Y+5BFggcC5MZ4D5FEs0V4sEK8EA/wPcpDFlWMyvg8WKeNgWb7EbHbqR1d92dlSn0E8nRsdOo+z3J7tbSAC3f9e3SzDJB5xVXbt+Zq3ayiGJzf4KV4Mfkf\",\"base64\")).toString()),PG)});var ps={};Vt(ps,{convertToZip:()=>jot,convertToZipWorker:()=>kG,extractArchiveTo:()=>Xge,getDefaultTaskPool:()=>zge,getTaskPoolForConfiguration:()=>Zge,makeArchiveFromDirectory:()=>Hot});function Uot(t,e){switch(t){case\"async\":return new Mv(kG,{poolSize:e});case\"workers\":return new Uv((0,xG.getContent)(),{poolSize:e});default:throw new Error(`Assertion failed: Unknown value ${t} for taskPoolMode`)}}function zge(){return typeof bG>\"u\"&&(bG=Uot(\"workers\",fs.availableParallelism())),bG}function Zge(t){return typeof t>\"u\"?zge():Yl(_ot,t,()=>{let e=t.get(\"taskPoolMode\"),r=t.get(\"taskPoolConcurrency\");switch(e){case\"async\":return new Mv(kG,{poolSize:r});case\"workers\":return new Uv((0,xG.getContent)(),{poolSize:r});default:throw new Error(`Assertion failed: Unknown value ${e} for taskPoolMode`)}})}async function kG(t){let{tmpFile:e,tgz:r,compressionLevel:s,extractBufferOpts:a}=t,n=new As(e,{create:!0,level:s,stats:$a.makeDefaultStats()}),c=Buffer.from(r.buffer,r.byteOffset,r.byteLength);return await Xge(c,n,a),n.saveAndClose(),e}async function Hot(t,{baseFs:e=new Yn,prefixPath:r=vt.root,compressionLevel:s,inMemory:a=!1}={}){let n;if(a)n=new As(null,{level:s});else{let f=await ce.mktempPromise(),p=J.join(f,\"archive.zip\");n=new As(p,{create:!0,level:s})}let c=J.resolve(vt.root,r);return await n.copyPromise(c,t,{baseFs:e,stableTime:!0,stableSort:!0}),n}async function jot(t,e={}){let r=await ce.mktempPromise(),s=J.join(r,\"archive.zip\"),a=e.compressionLevel??e.configuration?.get(\"compressionLevel\")??\"mixed\",n={prefixPath:e.prefixPath,stripComponents:e.stripComponents};return await(e.taskPool??Zge(e.configuration)).run({tmpFile:s,tgz:t,compressionLevel:a,extractBufferOpts:n}),new As(s,{level:e.compressionLevel})}async function*Got(t){let e=new Kge.default.Parse,r=new Jge.PassThrough({objectMode:!0,autoDestroy:!0,emitClose:!0});e.on(\"entry\",s=>{r.write(s)}),e.on(\"error\",s=>{r.destroy(s)}),e.on(\"close\",()=>{r.destroyed||r.end()}),e.end(t);for await(let s of r){let a=s;yield a,a.resume()}}async function Xge(t,e,{stripComponents:r=0,prefixPath:s=vt.dot}={}){function a(n){if(n.path[0]===\"/\")return!0;let c=n.path.split(/\\//g);return!!(c.some(f=>f===\"..\")||c.length<=r)}for await(let n of Got(t)){if(a(n))continue;let c=J.normalize(fe.toPortablePath(n.path)).replace(/\\/$/,\"\").split(/\\//g);if(c.length<=r)continue;let f=c.slice(r).join(\"/\"),p=J.join(s,f),h=420;switch((n.type===\"Directory\"||(n.mode??0)&73)&&(h|=73),n.type){case\"Directory\":e.mkdirpSync(J.dirname(p),{chmod:493,utimes:[fi.SAFE_TIME,fi.SAFE_TIME]}),e.mkdirSync(p,{mode:h}),e.utimesSync(p,fi.SAFE_TIME,fi.SAFE_TIME);break;case\"OldFile\":case\"File\":e.mkdirpSync(J.dirname(p),{chmod:493,utimes:[fi.SAFE_TIME,fi.SAFE_TIME]}),e.writeFileSync(p,await WE(n),{mode:h}),e.utimesSync(p,fi.SAFE_TIME,fi.SAFE_TIME);break;case\"SymbolicLink\":e.mkdirpSync(J.dirname(p),{chmod:493,utimes:[fi.SAFE_TIME,fi.SAFE_TIME]}),e.symlinkSync(n.linkpath,p),e.lutimesSync(p,fi.SAFE_TIME,fi.SAFE_TIME);break}}return e}var Jge,Kge,xG,bG,_ot,$ge=Ze(()=>{Ge();Dt();eA();Jge=Ie(\"stream\"),Kge=ut(Gge());Wge();bc();xG=ut(Vge());_ot=new WeakMap});var tde=_((QG,ede)=>{(function(t,e){typeof QG==\"object\"?ede.exports=e():typeof define==\"function\"&&define.amd?define(e):t.treeify=e()})(QG,function(){function t(a,n){var c=n?\"\\u2514\":\"\\u251C\";return a?c+=\"\\u2500 \":c+=\"\\u2500\\u2500\\u2510\",c}function e(a,n){var c=[];for(var f in a)a.hasOwnProperty(f)&&(n&&typeof a[f]==\"function\"||c.push(f));return c}function r(a,n,c,f,p,h,E){var C=\"\",S=0,b,I,T=f.slice(0);if(T.push([n,c])&&f.length>0&&(f.forEach(function(U,W){W>0&&(C+=(U[1]?\" \":\"\\u2502\")+\"  \"),!I&&U[0]===n&&(I=!0)}),C+=t(a,c)+a,p&&(typeof n!=\"object\"||n instanceof Date)&&(C+=\": \"+n),I&&(C+=\" (circular ref.)\"),E(C)),!I&&typeof n==\"object\"){var N=e(n,h);N.forEach(function(U){b=++S===N.length,r(U,n[U],b,T,p,h,E)})}}var s={};return s.asLines=function(a,n,c,f){var p=typeof c!=\"function\"?c:!1;r(\".\",a,!1,[],n,p,f||c)},s.asTree=function(a,n,c){var f=\"\";return r(\".\",a,!1,[],n,c,function(p){f+=p+`\n`}),f},s})});var xs={};Vt(xs,{emitList:()=>qot,emitTree:()=>sde,treeNodeToJson:()=>ide,treeNodeToTreeify:()=>nde});function nde(t,{configuration:e}){let r={},s=0,a=(n,c)=>{let f=Array.isArray(n)?n.entries():Object.entries(n);for(let[p,h]of f){if(!h)continue;let{label:E,value:C,children:S}=h,b=[];typeof E<\"u\"&&b.push(zd(e,E,2)),typeof C<\"u\"&&b.push(Ht(e,C[0],C[1])),b.length===0&&b.push(zd(e,`${p}`,2));let I=b.join(\": \").trim(),T=`\\0${s++}\\0`,N=c[`${T}${I}`]={};typeof S<\"u\"&&a(S,N)}};if(typeof t.children>\"u\")throw new Error(\"The root node must only contain children\");return a(t.children,r),r}function ide(t){let e=r=>{if(typeof r.children>\"u\"){if(typeof r.value>\"u\")throw new Error(\"Assertion failed: Expected a value to be set if the children are missing\");return Zd(r.value[0],r.value[1])}let s=Array.isArray(r.children)?r.children.entries():Object.entries(r.children??{}),a=Array.isArray(r.children)?[]:{};for(let[n,c]of s)c&&(a[Wot(n)]=e(c));return typeof r.value>\"u\"?a:{value:Zd(r.value[0],r.value[1]),children:a}};return e(t)}function qot(t,{configuration:e,stdout:r,json:s}){let a=t.map(n=>({value:n}));sde({children:a},{configuration:e,stdout:r,json:s})}function sde(t,{configuration:e,stdout:r,json:s,separators:a=0}){if(s){let c=Array.isArray(t.children)?t.children.values():Object.values(t.children??{});for(let f of c)f&&r.write(`${JSON.stringify(ide(f))}\n`);return}let n=(0,rde.asTree)(nde(t,{configuration:e}),!1,!1);if(n=n.replace(/\\0[0-9]+\\0/g,\"\"),a>=1&&(n=n.replace(/^([├└]─)/gm,`\\u2502\n$1`).replace(/^│\\n/,\"\")),a>=2)for(let c=0;c<2;++c)n=n.replace(/^([│ ].{2}[├│ ].{2}[^\\n]+\\n)(([│ ]).{2}[├└].{2}[^\\n]*\\n[│ ].{2}[│ ].{2}[├└]─)/gm,`$1$3  \\u2502 \n$2`).replace(/^│\\n/,\"\");if(a>=3)throw new Error(\"Only the first two levels are accepted by treeUtils.emitTree\");r.write(n)}function Wot(t){return typeof t==\"string\"?t.replace(/^\\0[0-9]+\\0/,\"\"):t}var rde,ode=Ze(()=>{rde=ut(tde());xc()});var LT,ade=Ze(()=>{LT=class{constructor(e){this.releaseFunction=e;this.map=new Map}addOrCreate(e,r){let s=this.map.get(e);if(typeof s<\"u\"){if(s.refCount<=0)throw new Error(`Race condition in RefCountedMap. While adding a new key the refCount is: ${s.refCount} for ${JSON.stringify(e)}`);return s.refCount++,{value:s.value,release:()=>this.release(e)}}else{let a=r();return this.map.set(e,{refCount:1,value:a}),{value:a,release:()=>this.release(e)}}}release(e){let r=this.map.get(e);if(!r)throw new Error(`Unbalanced calls to release. No known instances of: ${JSON.stringify(e)}`);let s=r.refCount;if(s<=0)throw new Error(`Unbalanced calls to release. Too many release vs alloc refcount would become: ${s-1} of ${JSON.stringify(e)}`);s==1?(this.map.delete(e),this.releaseFunction(r.value)):r.refCount--}}});function _v(t){let e=t.match(Yot);if(!e?.groups)throw new Error(\"Assertion failed: Expected the checksum to match the requested pattern\");let r=e.groups.cacheVersion?parseInt(e.groups.cacheVersion):null;return{cacheKey:e.groups.cacheKey??null,cacheVersion:r,cacheSpec:e.groups.cacheSpec??null,hash:e.groups.hash}}var lde,RG,TG,MT,Kr,Yot,FG=Ze(()=>{Ge();Dt();Dt();eA();lde=Ie(\"crypto\"),RG=ut(Ie(\"fs\"));ade();Rc();I0();bc();Wo();TG=YE(process.env.YARN_CACHE_CHECKPOINT_OVERRIDE??process.env.YARN_CACHE_VERSION_OVERRIDE??9),MT=YE(process.env.YARN_CACHE_VERSION_OVERRIDE??10),Kr=class t{constructor(e,{configuration:r,immutable:s=r.get(\"enableImmutableCache\"),check:a=!1}){this.markedFiles=new Set;this.mutexes=new Map;this.refCountedZipFsCache=new LT(e=>{e.discardAndClose()});this.cacheId=`-${(0,lde.randomBytes)(8).toString(\"hex\")}.tmp`;this.configuration=r,this.cwd=e,this.immutable=s,this.check=a;let{cacheSpec:n,cacheKey:c}=t.getCacheKey(r);this.cacheSpec=n,this.cacheKey=c}static async find(e,{immutable:r,check:s}={}){let a=new t(e.get(\"cacheFolder\"),{configuration:e,immutable:r,check:s});return await a.setup(),a}static getCacheKey(e){let r=e.get(\"compressionLevel\"),s=r!==\"mixed\"?`c${r}`:\"\";return{cacheKey:[MT,s].join(\"\"),cacheSpec:s}}get mirrorCwd(){if(!this.configuration.get(\"enableMirror\"))return null;let e=`${this.configuration.get(\"globalFolder\")}/cache`;return e!==this.cwd?e:null}getVersionFilename(e){return`${nI(e)}-${this.cacheKey}.zip`}getChecksumFilename(e,r){let a=_v(r).hash.slice(0,10);return`${nI(e)}-${a}.zip`}isChecksumCompatible(e){if(e===null)return!1;let{cacheVersion:r,cacheSpec:s}=_v(e);if(r===null||r<TG)return!1;let a=this.configuration.get(\"cacheMigrationMode\");return!(r<MT&&a===\"always\"||s!==this.cacheSpec&&a!==\"required-only\")}getLocatorPath(e,r){return this.mirrorCwd===null?J.resolve(this.cwd,this.getVersionFilename(e)):r===null?J.resolve(this.cwd,this.getVersionFilename(e)):J.resolve(this.cwd,this.getChecksumFilename(e,r))}getLocatorMirrorPath(e){let r=this.mirrorCwd;return r!==null?J.resolve(r,this.getVersionFilename(e)):null}async setup(){if(!this.configuration.get(\"enableGlobalCache\"))if(this.immutable){if(!await ce.existsPromise(this.cwd))throw new jt(56,\"Cache path does not exist.\")}else{await ce.mkdirPromise(this.cwd,{recursive:!0});let e=J.resolve(this.cwd,\".gitignore\");await ce.changeFilePromise(e,`/.gitignore\n*.flock\n*.tmp\n`)}(this.mirrorCwd||!this.immutable)&&await ce.mkdirPromise(this.mirrorCwd||this.cwd,{recursive:!0})}async fetchPackageFromCache(e,r,{onHit:s,onMiss:a,loader:n,...c}){let f=this.getLocatorMirrorPath(e),p=new Yn,h=()=>{let pe=new As,Be=J.join(vt.root,P8(e));return pe.mkdirSync(Be,{recursive:!0}),pe.writeJsonSync(J.join(Be,Er.manifest),{name:un(e),mocked:!0}),pe},E=async(pe,{isColdHit:Be,controlPath:Ce=null})=>{if(Ce===null&&c.unstablePackages?.has(e.locatorHash))return{isValid:!0,hash:null};let g=r&&!Be?_v(r).cacheKey:this.cacheKey,we=!c.skipIntegrityCheck||!r?`${g}/${await vQ(pe)}`:r;if(Ce!==null){let Ae=!c.skipIntegrityCheck||!r?`${this.cacheKey}/${await vQ(Ce)}`:r;if(we!==Ae)throw new jt(18,\"The remote archive doesn't match the local checksum - has the local cache been corrupted?\")}let ye=null;switch(r!==null&&we!==r&&(this.check?ye=\"throw\":_v(r).cacheKey!==_v(we).cacheKey?ye=\"update\":ye=this.configuration.get(\"checksumBehavior\")),ye){case null:case\"update\":return{isValid:!0,hash:we};case\"ignore\":return{isValid:!0,hash:r};case\"reset\":return{isValid:!1,hash:r};default:case\"throw\":throw new jt(18,\"The remote archive doesn't match the expected checksum\")}},C=async pe=>{if(!n)throw new Error(`Cache check required but no loader configured for ${Yr(this.configuration,e)}`);let Be=await n(),Ce=Be.getRealPath();Be.saveAndClose(),await ce.chmodPromise(Ce,420);let g=await E(pe,{controlPath:Ce,isColdHit:!1});if(!g.isValid)throw new Error(\"Assertion failed: Expected a valid checksum\");return g.hash},S=async()=>{if(f===null||!await ce.existsPromise(f)){let pe=await n(),Be=pe.getRealPath();return pe.saveAndClose(),{source:\"loader\",path:Be}}return{source:\"mirror\",path:f}},b=async()=>{if(!n)throw new Error(`Cache entry required but missing for ${Yr(this.configuration,e)}`);if(this.immutable)throw new jt(56,`Cache entry required but missing for ${Yr(this.configuration,e)}`);let{path:pe,source:Be}=await S(),{hash:Ce}=await E(pe,{isColdHit:!0}),g=this.getLocatorPath(e,Ce),we=[];Be!==\"mirror\"&&f!==null&&we.push(async()=>{let Ae=`${f}${this.cacheId}`;await ce.copyFilePromise(pe,Ae,RG.default.constants.COPYFILE_FICLONE),await ce.chmodPromise(Ae,420),await ce.renamePromise(Ae,f)}),(!c.mirrorWriteOnly||f===null)&&we.push(async()=>{let Ae=`${g}${this.cacheId}`;await ce.copyFilePromise(pe,Ae,RG.default.constants.COPYFILE_FICLONE),await ce.chmodPromise(Ae,420),await ce.renamePromise(Ae,g)});let ye=c.mirrorWriteOnly?f??g:g;return await Promise.all(we.map(Ae=>Ae())),[!1,ye,Ce]},I=async()=>{let Be=(async()=>{let Ce=c.unstablePackages?.has(e.locatorHash),g=Ce||!r||this.isChecksumCompatible(r)?this.getLocatorPath(e,r):null,we=g!==null?this.markedFiles.has(g)||await p.existsPromise(g):!1,ye=!!c.mockedPackages?.has(e.locatorHash)&&(!this.check||!we),Ae=ye||we,se=Ae?s:a;if(se&&se(),Ae){let X=null,De=g;if(!ye)if(this.check)X=await C(De);else{let Te=await E(De,{isColdHit:!1});if(Te.isValid)X=Te.hash;else return b()}return[ye,De,X]}else{if(this.immutable&&Ce)throw new jt(56,`Cache entry required but missing for ${Yr(this.configuration,e)}; consider defining ${he.pretty(this.configuration,\"supportedArchitectures\",he.Type.CODE)} to cache packages for multiple systems`);return b()}})();this.mutexes.set(e.locatorHash,Be);try{return await Be}finally{this.mutexes.delete(e.locatorHash)}};for(let pe;pe=this.mutexes.get(e.locatorHash);)await pe;let[T,N,U]=await I();T||this.markedFiles.add(N);let W=()=>this.refCountedZipFsCache.addOrCreate(N,()=>T?h():new As(N,{baseFs:p,readOnly:!0})),ee,ie=new oE(()=>G4(()=>(ee=W(),ee.value),pe=>`Failed to open the cache entry for ${Yr(this.configuration,e)}: ${pe}`),J),ue=new _f(N,{baseFs:ie,pathUtils:J}),le=()=>{ee?.release()},me=c.unstablePackages?.has(e.locatorHash)?null:U;return[ue,le,me]}},Yot=/^(?:(?<cacheKey>(?<cacheVersion>[0-9]+)(?<cacheSpec>.*))\\/)?(?<hash>.*)$/});var UT,cde=Ze(()=>{UT=(r=>(r[r.SCRIPT=0]=\"SCRIPT\",r[r.SHELLCODE=1]=\"SHELLCODE\",r))(UT||{})});var Vot,KI,NG=Ze(()=>{Dt();wc();Tp();Wo();Vot=[[/^(git(?:\\+(?:https|ssh))?:\\/\\/.*(?:\\.git)?)#(.*)$/,(t,e,r,s)=>`${r}#commit=${s}`],[/^https:\\/\\/((?:[^/]+?)@)?codeload\\.github\\.com\\/([^/]+\\/[^/]+)\\/tar\\.gz\\/([0-9a-f]+)$/,(t,e,r=\"\",s,a)=>`https://${r}github.com/${s}.git#commit=${a}`],[/^https:\\/\\/((?:[^/]+?)@)?github\\.com\\/([^/]+\\/[^/]+?)(?:\\.git)?#([0-9a-f]+)$/,(t,e,r=\"\",s,a)=>`https://${r}github.com/${s}.git#commit=${a}`],[/^https?:\\/\\/[^/]+\\/(?:[^/]+\\/)*(?:@.+(?:\\/|(?:%2f)))?([^/]+)\\/(?:-|download)\\/\\1-[^/]+\\.tgz(?:#|$)/,t=>`npm:${t}`],[/^https:\\/\\/npm\\.pkg\\.github\\.com\\/download\\/(?:@[^/]+)\\/(?:[^/]+)\\/(?:[^/]+)\\/(?:[0-9a-f]+)(?:#|$)/,t=>`npm:${t}`],[/^https:\\/\\/npm\\.fontawesome\\.com\\/(?:@[^/]+)\\/([^/]+)\\/-\\/([^/]+)\\/\\1-\\2.tgz(?:#|$)/,t=>`npm:${t}`],[/^https?:\\/\\/[^/]+\\/.*\\/(@[^/]+)\\/([^/]+)\\/-\\/\\1\\/\\2-(?:[.\\d\\w-]+)\\.tgz(?:#|$)/,(t,e)=>xQ({protocol:\"npm:\",source:null,selector:t,params:{__archiveUrl:e}})],[/^[^/]+\\.tgz#[0-9a-f]+$/,t=>`npm:${t}`]],KI=class{constructor(e){this.resolver=e;this.resolutions=null}async setup(e,{report:r}){let s=J.join(e.cwd,Er.lockfile);if(!ce.existsSync(s))return;let a=await ce.readFilePromise(s,\"utf8\"),n=as(a);if(Object.hasOwn(n,\"__metadata\"))return;let c=this.resolutions=new Map;for(let f of Object.keys(n)){let p=HB(f);if(!p){r.reportWarning(14,`Failed to parse the string \"${f}\" into a proper descriptor`);continue}let h=cl(p.range)?On(p,`npm:${p.range}`):p,{version:E,resolved:C}=n[f];if(!C)continue;let S;for(let[I,T]of Vot){let N=C.match(I);if(N){S=T(E,...N);break}}if(!S){r.reportWarning(14,`${ni(e.configuration,h)}: Only some patterns can be imported from legacy lockfiles (not \"${C}\")`);continue}let b=h;try{let I=em(h.range),T=HB(I.selector,!0);T&&(b=T)}catch{}c.set(h.descriptorHash,Ws(b,S))}}supportsDescriptor(e,r){return this.resolutions?this.resolutions.has(e.descriptorHash):!1}supportsLocator(e,r){return!1}shouldPersistResolution(e,r){throw new Error(\"Assertion failed: This resolver doesn't support resolving locators to packages\")}bindDescriptor(e,r,s){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){if(!this.resolutions)throw new Error(\"Assertion failed: The resolution store should have been setup\");let a=this.resolutions.get(e.descriptorHash);if(!a)throw new Error(\"Assertion failed: The resolution should have been registered\");let n=B8(a),c=s.project.configuration.normalizeDependency(n);return await this.resolver.getCandidates(c,r,s)}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){throw new Error(\"Assertion failed: This resolver doesn't support resolving locators to packages\")}}});var lA,ude=Ze(()=>{Rc();Ev();xc();lA=class extends Ao{constructor({configuration:r,stdout:s,suggestInstall:a=!0}){super();this.errorCount=0;TB(this,{configuration:r}),this.configuration=r,this.stdout=s,this.suggestInstall=a}static async start(r,s){let a=new this(r);try{await s(a)}catch(n){a.reportExceptionOnce(n)}finally{await a.finalize()}return a}hasErrors(){return this.errorCount>0}exitCode(){return this.hasErrors()?1:0}reportCacheHit(r){}reportCacheMiss(r){}startSectionSync(r,s){return s()}async startSectionPromise(r,s){return await s()}startTimerSync(r,s,a){return(typeof s==\"function\"?s:a)()}async startTimerPromise(r,s,a){return await(typeof s==\"function\"?s:a)()}reportSeparator(){}reportInfo(r,s){}reportWarning(r,s){}reportError(r,s){this.errorCount+=1,this.stdout.write(`${Ht(this.configuration,\"\\u27A4\",\"redBright\")} ${this.formatNameWithHyperlink(r)}: ${s}\n`)}reportProgress(r){return{...Promise.resolve().then(async()=>{for await(let{}of r);}),stop:()=>{}}}reportJson(r){}reportFold(r,s){}async finalize(){this.errorCount>0&&(this.stdout.write(`\n`),this.stdout.write(`${Ht(this.configuration,\"\\u27A4\",\"redBright\")} Errors happened when preparing the environment required to run this command.\n`),this.suggestInstall&&this.stdout.write(`${Ht(this.configuration,\"\\u27A4\",\"redBright\")} This might be caused by packages being missing from the lockfile, in which case running \"yarn install\" might help.\n`))}formatNameWithHyperlink(r){return jj(r,{configuration:this.configuration,json:!1})}}});var zI,OG=Ze(()=>{Wo();zI=class{constructor(e){this.resolver=e}supportsDescriptor(e,r){return!!(r.project.storedResolutions.get(e.descriptorHash)||r.project.originalPackages.has(DQ(e).locatorHash))}supportsLocator(e,r){return!!(r.project.originalPackages.has(e.locatorHash)&&!r.project.lockfileNeedsRefresh)}shouldPersistResolution(e,r){throw new Error(\"The shouldPersistResolution method shouldn't be called on the lockfile resolver, which would always answer yes\")}bindDescriptor(e,r,s){return e}getResolutionDependencies(e,r){return this.resolver.getResolutionDependencies(e,r)}async getCandidates(e,r,s){let a=s.project.storedResolutions.get(e.descriptorHash);if(a){let c=s.project.originalPackages.get(a);if(c)return[c]}let n=s.project.originalPackages.get(DQ(e).locatorHash);if(n)return[n];throw new Error(\"Resolution expected from the lockfile data\")}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){let s=r.project.originalPackages.get(e.locatorHash);if(!s)throw new Error(\"The lockfile resolver isn't meant to resolve packages - they should already have been stored into a cache\");return s}}});function Kp(){}function Jot(t,e,r,s,a){for(var n=0,c=e.length,f=0,p=0;n<c;n++){var h=e[n];if(h.removed){if(h.value=t.join(s.slice(p,p+h.count)),p+=h.count,n&&e[n-1].added){var C=e[n-1];e[n-1]=e[n],e[n]=C}}else{if(!h.added&&a){var E=r.slice(f,f+h.count);E=E.map(function(b,I){var T=s[p+I];return T.length>b.length?T:b}),h.value=t.join(E)}else h.value=t.join(r.slice(f,f+h.count));f+=h.count,h.added||(p+=h.count)}}var S=e[c-1];return c>1&&typeof S.value==\"string\"&&(S.added||S.removed)&&t.equals(\"\",S.value)&&(e[c-2].value+=S.value,e.pop()),e}function Kot(t){return{newPos:t.newPos,components:t.components.slice(0)}}function zot(t,e){if(typeof t==\"function\")e.callback=t;else if(t)for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r]);return e}function pde(t,e,r){return r=zot(r,{ignoreWhitespace:!0}),HG.diff(t,e,r)}function Zot(t,e,r){return jG.diff(t,e,r)}function _T(t){\"@babel/helpers - typeof\";return typeof Symbol==\"function\"&&typeof Symbol.iterator==\"symbol\"?_T=function(e){return typeof e}:_T=function(e){return e&&typeof Symbol==\"function\"&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},_T(t)}function LG(t){return eat(t)||tat(t)||rat(t)||nat()}function eat(t){if(Array.isArray(t))return MG(t)}function tat(t){if(typeof Symbol<\"u\"&&Symbol.iterator in Object(t))return Array.from(t)}function rat(t,e){if(t){if(typeof t==\"string\")return MG(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);if(r===\"Object\"&&t.constructor&&(r=t.constructor.name),r===\"Map\"||r===\"Set\")return Array.from(t);if(r===\"Arguments\"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return MG(t,e)}}function MG(t,e){(e==null||e>t.length)&&(e=t.length);for(var r=0,s=new Array(e);r<e;r++)s[r]=t[r];return s}function nat(){throw new TypeError(`Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function UG(t,e,r,s,a){e=e||[],r=r||[],s&&(t=s(a,t));var n;for(n=0;n<e.length;n+=1)if(e[n]===t)return r[n];var c;if(iat.call(t)===\"[object Array]\"){for(e.push(t),c=new Array(t.length),r.push(c),n=0;n<t.length;n+=1)c[n]=UG(t[n],e,r,s,a);return e.pop(),r.pop(),c}if(t&&t.toJSON&&(t=t.toJSON()),_T(t)===\"object\"&&t!==null){e.push(t),c={},r.push(c);var f=[],p;for(p in t)t.hasOwnProperty(p)&&f.push(p);for(f.sort(),n=0;n<f.length;n+=1)p=f[n],c[p]=UG(t[p],e,r,s,p);e.pop(),r.pop()}else c=t;return c}function hde(t,e,r,s,a,n,c){c||(c={}),typeof c.context>\"u\"&&(c.context=4);var f=Zot(r,s,c);if(!f)return;f.push({value:\"\",lines:[]});function p(U){return U.map(function(W){return\" \"+W})}for(var h=[],E=0,C=0,S=[],b=1,I=1,T=function(W){var ee=f[W],ie=ee.lines||ee.value.replace(/\\n$/,\"\").split(`\n`);if(ee.lines=ie,ee.added||ee.removed){var ue;if(!E){var le=f[W-1];E=b,C=I,le&&(S=c.context>0?p(le.lines.slice(-c.context)):[],E-=S.length,C-=S.length)}(ue=S).push.apply(ue,LG(ie.map(function(Ae){return(ee.added?\"+\":\"-\")+Ae}))),ee.added?I+=ie.length:b+=ie.length}else{if(E)if(ie.length<=c.context*2&&W<f.length-2){var me;(me=S).push.apply(me,LG(p(ie)))}else{var pe,Be=Math.min(ie.length,c.context);(pe=S).push.apply(pe,LG(p(ie.slice(0,Be))));var Ce={oldStart:E,oldLines:b-E+Be,newStart:C,newLines:I-C+Be,lines:S};if(W>=f.length-2&&ie.length<=c.context){var g=/\\n$/.test(r),we=/\\n$/.test(s),ye=ie.length==0&&S.length>Ce.oldLines;!g&&ye&&r.length>0&&S.splice(Ce.oldLines,0,\"\\\\ No newline at end of file\"),(!g&&!ye||!we)&&S.push(\"\\\\ No newline at end of file\")}h.push(Ce),E=0,C=0,S=[]}b+=ie.length,I+=ie.length}},N=0;N<f.length;N++)T(N);return{oldFileName:t,newFileName:e,oldHeader:a,newHeader:n,hunks:h}}var c8t,fde,Ade,HG,jG,Xot,$ot,iat,Hv,_G,GG=Ze(()=>{Kp.prototype={diff:function(e,r){var s=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},a=s.callback;typeof s==\"function\"&&(a=s,s={}),this.options=s;var n=this;function c(T){return a?(setTimeout(function(){a(void 0,T)},0),!0):T}e=this.castInput(e),r=this.castInput(r),e=this.removeEmpty(this.tokenize(e)),r=this.removeEmpty(this.tokenize(r));var f=r.length,p=e.length,h=1,E=f+p;s.maxEditLength&&(E=Math.min(E,s.maxEditLength));var C=[{newPos:-1,components:[]}],S=this.extractCommon(C[0],r,e,0);if(C[0].newPos+1>=f&&S+1>=p)return c([{value:this.join(r),count:r.length}]);function b(){for(var T=-1*h;T<=h;T+=2){var N=void 0,U=C[T-1],W=C[T+1],ee=(W?W.newPos:0)-T;U&&(C[T-1]=void 0);var ie=U&&U.newPos+1<f,ue=W&&0<=ee&&ee<p;if(!ie&&!ue){C[T]=void 0;continue}if(!ie||ue&&U.newPos<W.newPos?(N=Kot(W),n.pushComponent(N.components,void 0,!0)):(N=U,N.newPos++,n.pushComponent(N.components,!0,void 0)),ee=n.extractCommon(N,r,e,T),N.newPos+1>=f&&ee+1>=p)return c(Jot(n,N.components,r,e,n.useLongestToken));C[T]=N}h++}if(a)(function T(){setTimeout(function(){if(h>E)return a();b()||T()},0)})();else for(;h<=E;){var I=b();if(I)return I}},pushComponent:function(e,r,s){var a=e[e.length-1];a&&a.added===r&&a.removed===s?e[e.length-1]={count:a.count+1,added:r,removed:s}:e.push({count:1,added:r,removed:s})},extractCommon:function(e,r,s,a){for(var n=r.length,c=s.length,f=e.newPos,p=f-a,h=0;f+1<n&&p+1<c&&this.equals(r[f+1],s[p+1]);)f++,p++,h++;return h&&e.components.push({count:h}),e.newPos=f,p},equals:function(e,r){return this.options.comparator?this.options.comparator(e,r):e===r||this.options.ignoreCase&&e.toLowerCase()===r.toLowerCase()},removeEmpty:function(e){for(var r=[],s=0;s<e.length;s++)e[s]&&r.push(e[s]);return r},castInput:function(e){return e},tokenize:function(e){return e.split(\"\")},join:function(e){return e.join(\"\")}};c8t=new Kp;fde=/^[A-Za-z\\xC0-\\u02C6\\u02C8-\\u02D7\\u02DE-\\u02FF\\u1E00-\\u1EFF]+$/,Ade=/\\S/,HG=new Kp;HG.equals=function(t,e){return this.options.ignoreCase&&(t=t.toLowerCase(),e=e.toLowerCase()),t===e||this.options.ignoreWhitespace&&!Ade.test(t)&&!Ade.test(e)};HG.tokenize=function(t){for(var e=t.split(/([^\\S\\r\\n]+|[()[\\]{}'\"\\r\\n]|\\b)/),r=0;r<e.length-1;r++)!e[r+1]&&e[r+2]&&fde.test(e[r])&&fde.test(e[r+2])&&(e[r]+=e[r+2],e.splice(r+1,2),r--);return e};jG=new Kp;jG.tokenize=function(t){var e=[],r=t.split(/(\\n|\\r\\n)/);r[r.length-1]||r.pop();for(var s=0;s<r.length;s++){var a=r[s];s%2&&!this.options.newlineIsToken?e[e.length-1]+=a:(this.options.ignoreWhitespace&&(a=a.trim()),e.push(a))}return e};Xot=new Kp;Xot.tokenize=function(t){return t.split(/(\\S.+?[.!?])(?=\\s+|$)/)};$ot=new Kp;$ot.tokenize=function(t){return t.split(/([{}:;,]|\\s+)/)};iat=Object.prototype.toString,Hv=new Kp;Hv.useLongestToken=!0;Hv.tokenize=jG.tokenize;Hv.castInput=function(t){var e=this.options,r=e.undefinedReplacement,s=e.stringifyReplacer,a=s===void 0?function(n,c){return typeof c>\"u\"?r:c}:s;return typeof t==\"string\"?t:JSON.stringify(UG(t,null,null,a),a,\"  \")};Hv.equals=function(t,e){return Kp.prototype.equals.call(Hv,t.replace(/,([\\r\\n])/g,\"$1\"),e.replace(/,([\\r\\n])/g,\"$1\"))};_G=new Kp;_G.tokenize=function(t){return t.slice()};_G.join=_G.removeEmpty=function(t){return t}});var HT,gde=Ze(()=>{Rc();HT=class{constructor(e){this.resolver=e}supportsDescriptor(e,r){return this.resolver.supportsDescriptor(e,r)}supportsLocator(e,r){return this.resolver.supportsLocator(e,r)}shouldPersistResolution(e,r){return this.resolver.shouldPersistResolution(e,r)}bindDescriptor(e,r,s){return this.resolver.bindDescriptor(e,r,s)}getResolutionDependencies(e,r){return this.resolver.getResolutionDependencies(e,r)}async getCandidates(e,r,s){throw new jt(20,`This package doesn't seem to be present in your lockfile; run \"yarn install\" to update the lockfile`)}async getSatisfying(e,r,s,a){throw new jt(20,`This package doesn't seem to be present in your lockfile; run \"yarn install\" to update the lockfile`)}async resolve(e,r){throw new jt(20,`This package doesn't seem to be present in your lockfile; run \"yarn install\" to update the lockfile`)}}});var ki,qG=Ze(()=>{Rc();ki=class extends Ao{reportCacheHit(e){}reportCacheMiss(e){}startSectionSync(e,r){return r()}async startSectionPromise(e,r){return await r()}startTimerSync(e,r,s){return(typeof r==\"function\"?r:s)()}async startTimerPromise(e,r,s){return await(typeof r==\"function\"?r:s)()}reportSeparator(){}reportInfo(e,r){}reportWarning(e,r){}reportError(e,r){}reportProgress(e){return{...Promise.resolve().then(async()=>{for await(let{}of e);}),stop:()=>{}}}reportJson(e){}reportFold(e,r){}async finalize(){}}});var dde,ZI,WG=Ze(()=>{Dt();dde=ut(wQ());oI();tm();xc();I0();Tp();Wo();ZI=class{constructor(e,{project:r}){this.workspacesCwds=new Set;this.project=r,this.cwd=e}async setup(){this.manifest=await Ut.tryFind(this.cwd)??new Ut,this.relativeCwd=J.relative(this.project.cwd,this.cwd)||vt.dot;let e=this.manifest.name?this.manifest.name:Da(null,`${this.computeCandidateName()}-${cs(this.relativeCwd).substring(0,6)}`);this.anchoredDescriptor=On(e,`${Ei.protocol}${this.relativeCwd}`),this.anchoredLocator=Ws(e,`${Ei.protocol}${this.relativeCwd}`);let r=this.manifest.workspaceDefinitions.map(({pattern:a})=>a);if(r.length===0)return;let s=await(0,dde.default)(r,{cwd:fe.fromPortablePath(this.cwd),onlyDirectories:!0,ignore:[\"**/node_modules\",\"**/.git\",\"**/.yarn\"]});s.sort(),await s.reduce(async(a,n)=>{let c=J.resolve(this.cwd,fe.toPortablePath(n)),f=await ce.existsPromise(J.join(c,\"package.json\"));await a,f&&this.workspacesCwds.add(c)},Promise.resolve())}get anchoredPackage(){let e=this.project.storedPackages.get(this.anchoredLocator.locatorHash);if(!e)throw new Error(`Assertion failed: Expected workspace ${GB(this.project.configuration,this)} (${Ht(this.project.configuration,J.join(this.cwd,Er.manifest),ht.PATH)}) to have been resolved. Run \"yarn install\" to update the lockfile`);return e}accepts(e){let r=e.indexOf(\":\"),s=r!==-1?e.slice(0,r+1):null,a=r!==-1?e.slice(r+1):e;if(s===Ei.protocol&&J.normalize(a)===this.relativeCwd||s===Ei.protocol&&(a===\"*\"||a===\"^\"||a===\"~\"))return!0;let n=cl(a);return n?s===Ei.protocol?n.test(this.manifest.version??\"0.0.0\"):this.project.configuration.get(\"enableTransparentWorkspaces\")&&this.manifest.version!==null?n.test(this.manifest.version):!1:!1}computeCandidateName(){return this.cwd===this.project.cwd?\"root-workspace\":`${J.basename(this.cwd)}`||\"unnamed-workspace\"}getRecursiveWorkspaceDependencies({dependencies:e=Ut.hardDependencies}={}){let r=new Set,s=a=>{for(let n of e)for(let c of a.manifest[n].values()){let f=this.project.tryWorkspaceByDescriptor(c);f===null||r.has(f)||(r.add(f),s(f))}};return s(this),r}getRecursiveWorkspaceDependents({dependencies:e=Ut.hardDependencies}={}){let r=new Set,s=a=>{for(let n of this.project.workspaces)e.some(f=>[...n.manifest[f].values()].some(p=>{let h=this.project.tryWorkspaceByDescriptor(p);return h!==null&&_B(h.anchoredLocator,a.anchoredLocator)}))&&!r.has(n)&&(r.add(n),s(n))};return s(this),r}getRecursiveWorkspaceChildren(){let e=new Set([this]);for(let r of e)for(let s of r.workspacesCwds){let a=this.project.workspacesByCwd.get(s);a&&e.add(a)}return e.delete(this),Array.from(e)}async persistManifest(){let e={};this.manifest.exportTo(e);let r=J.join(this.cwd,Ut.fileName),s=`${JSON.stringify(e,null,this.manifest.indent)}\n`;await ce.changeFilePromise(r,s,{automaticNewlines:!0}),this.manifest.raw=e}}});function uat({project:t,allDescriptors:e,allResolutions:r,allPackages:s,accessibleLocators:a=new Set,optionalBuilds:n=new Set,peerRequirements:c=new Map,peerWarnings:f=[],peerRequirementNodes:p=new Map,volatileDescriptors:h=new Set}){let E=new Map,C=[],S=new Map,b=new Map,I=new Map,T=new Map,N=new Map,U=new Map(t.workspaces.map(le=>{let me=le.anchoredLocator.locatorHash,pe=s.get(me);if(typeof pe>\"u\")throw new Error(\"Assertion failed: The workspace should have an associated package\");return[me,LB(pe)]})),W=()=>{let le=ce.mktempSync(),me=J.join(le,\"stacktrace.log\"),pe=String(C.length+1).length,Be=C.map((Ce,g)=>`${`${g+1}.`.padStart(pe,\" \")} ${ll(Ce)}\n`).join(\"\");throw ce.writeFileSync(me,Be),ce.detachTemp(le),new jt(45,`Encountered a stack overflow when resolving peer dependencies; cf ${fe.fromPortablePath(me)}`)},ee=le=>{let me=r.get(le.descriptorHash);if(typeof me>\"u\")throw new Error(\"Assertion failed: The resolution should have been registered\");let pe=s.get(me);if(!pe)throw new Error(\"Assertion failed: The package could not be found\");return pe},ie=(le,me,pe,{top:Be,optional:Ce})=>{C.length>1e3&&W(),C.push(me);let g=ue(le,me,pe,{top:Be,optional:Ce});return C.pop(),g},ue=(le,me,pe,{top:Be,optional:Ce})=>{if(Ce||n.delete(me.locatorHash),a.has(me.locatorHash))return;a.add(me.locatorHash);let g=s.get(me.locatorHash);if(!g)throw new Error(`Assertion failed: The package (${Yr(t.configuration,me)}) should have been registered`);let we=new Set,ye=new Map,Ae=[],se=[],X=[],De=[];for(let Te of Array.from(g.dependencies.values())){if(g.peerDependencies.has(Te.identHash)&&g.locatorHash!==Be)continue;if(kp(Te))throw new Error(\"Assertion failed: Virtual packages shouldn't be encountered when virtualizing a branch\");h.delete(Te.descriptorHash);let mt=Ce;if(!mt){let ke=g.dependenciesMeta.get(un(Te));if(typeof ke<\"u\"){let it=ke.get(null);typeof it<\"u\"&&it.optional&&(mt=!0)}}let j=r.get(Te.descriptorHash);if(!j)throw new Error(`Assertion failed: The resolution (${ni(t.configuration,Te)}) should have been registered`);let rt=U.get(j)||s.get(j);if(!rt)throw new Error(`Assertion failed: The package (${j}, resolved from ${ni(t.configuration,Te)}) should have been registered`);if(rt.peerDependencies.size===0){ie(Te,rt,new Map,{top:Be,optional:mt});continue}let Fe,Ne,be=new Set,Ve=new Map;Ae.push(()=>{Fe=S8(Te,me.locatorHash),Ne=D8(rt,me.locatorHash),g.dependencies.set(Te.identHash,Fe),r.set(Fe.descriptorHash,Ne.locatorHash),e.set(Fe.descriptorHash,Fe),s.set(Ne.locatorHash,Ne),Pp(T,Ne.locatorHash).add(Fe.descriptorHash),we.add(Ne.locatorHash)}),se.push(()=>{N.set(Ne.locatorHash,Ve);for(let ke of Ne.peerDependencies.values()){let Ue=Yl(ye,ke.identHash,()=>{let x=pe.get(ke.identHash)??null,w=g.dependencies.get(ke.identHash);return!w&&UB(me,ke)&&(le.identHash===me.identHash?w=le:(w=On(me,le.range),e.set(w.descriptorHash,w),r.set(w.descriptorHash,me.locatorHash),h.delete(w.descriptorHash),x=null)),w||(w=On(ke,\"missing:\")),{subject:me,ident:ke,provided:w,root:!x,requests:new Map,hash:`p${cs(me.locatorHash,ke.identHash).slice(0,6)}`}}).provided;if(Ue.range===\"missing:\"&&Ne.dependencies.has(ke.identHash)){Ne.peerDependencies.delete(ke.identHash);continue}if(Ve.set(ke.identHash,{requester:Ne,descriptor:ke,meta:Ne.peerDependenciesMeta.get(un(ke)),children:new Map}),Ne.dependencies.set(ke.identHash,Ue),kp(Ue)){let x=r.get(Ue.descriptorHash);Pp(I,x).add(Ne.locatorHash)}S.set(Ue.identHash,Ue),Ue.range===\"missing:\"&&be.add(Ue.identHash)}Ne.dependencies=new Map(qs(Ne.dependencies,([ke,it])=>un(it)))}),X.push(()=>{if(!s.has(Ne.locatorHash))return;let ke=E.get(rt.locatorHash);typeof ke==\"number\"&&ke>=2&&W();let it=E.get(rt.locatorHash),Ue=typeof it<\"u\"?it+1:1;E.set(rt.locatorHash,Ue),ie(Fe,Ne,Ve,{top:Be,optional:mt}),E.set(rt.locatorHash,Ue-1)}),De.push(()=>{let ke=r.get(Fe.descriptorHash);if(typeof ke>\"u\")throw new Error(\"Assertion failed: Expected the descriptor to be registered\");let it=N.get(ke);if(typeof it>\"u\")throw new Error(\"Assertion failed: Expected the peer requests to be registered\");for(let Ue of ye.values()){let x=it.get(Ue.ident.identHash);x&&(Ue.requests.set(Fe.descriptorHash,x),p.set(Ue.hash,Ue),Ue.root||pe.get(Ue.ident.identHash)?.children.set(Fe.descriptorHash,x))}if(s.has(Ne.locatorHash))for(let Ue of be)Ne.dependencies.delete(Ue)})}for(let Te of[...Ae,...se])Te();for(let Te of we){we.delete(Te);let mt=s.get(Te),j=cs(rI(mt).locatorHash,...Array.from(mt.dependencies.values(),be=>{let Ve=be.range!==\"missing:\"?r.get(be.descriptorHash):\"missing:\";if(typeof Ve>\"u\")throw new Error(`Assertion failed: Expected the resolution for ${ni(t.configuration,be)} to have been registered`);return Ve===Be?`${Ve} (top)`:Ve})),rt=b.get(j);if(typeof rt>\"u\"){b.set(j,mt);continue}let Fe=Pp(T,rt.locatorHash);for(let be of T.get(mt.locatorHash)??[])r.set(be,rt.locatorHash),Fe.add(be);s.delete(mt.locatorHash),a.delete(mt.locatorHash),we.delete(mt.locatorHash);let Ne=I.get(mt.locatorHash);if(Ne!==void 0){let be=Pp(I,rt.locatorHash);for(let Ve of Ne)be.add(Ve),we.add(Ve)}}for(let Te of[...X,...De])Te()};for(let le of t.workspaces){let me=le.anchoredLocator;h.delete(le.anchoredDescriptor.descriptorHash),ie(le.anchoredDescriptor,me,new Map,{top:me.locatorHash,optional:!1})}for(let le of p.values()){if(!le.root)continue;let me=s.get(le.subject.locatorHash);if(typeof me>\"u\")continue;for(let Be of le.requests.values()){let Ce=`p${cs(le.subject.locatorHash,un(le.ident),Be.requester.locatorHash).slice(0,6)}`;c.set(Ce,{subject:le.subject.locatorHash,requested:le.ident,rootRequester:Be.requester.locatorHash,allRequesters:Array.from(qB(Be),g=>g.requester.locatorHash)})}let pe=[...qB(le)];if(le.provided.range!==\"missing:\"){let Be=ee(le.provided),Ce=Be.version??\"0.0.0\",g=ye=>{if(ye.startsWith(Ei.protocol)){if(!t.tryWorkspaceByLocator(Be))return null;ye=ye.slice(Ei.protocol.length),(ye===\"^\"||ye===\"~\")&&(ye=\"*\")}return ye},we=!0;for(let ye of pe){let Ae=g(ye.descriptor.range);if(Ae===null){we=!1;continue}if(!Xf(Ce,Ae)){we=!1;let se=`p${cs(le.subject.locatorHash,un(le.ident),ye.requester.locatorHash).slice(0,6)}`;f.push({type:1,subject:me,requested:le.ident,requester:ye.requester,version:Ce,hash:se,requirementCount:pe.length})}}if(!we){let ye=pe.map(Ae=>g(Ae.descriptor.range));f.push({type:3,node:le,range:ye.includes(null)?null:x8(ye),hash:le.hash})}}else{let Be=!0;for(let Ce of pe)if(!Ce.meta?.optional){Be=!1;let g=`p${cs(le.subject.locatorHash,un(le.ident),Ce.requester.locatorHash).slice(0,6)}`;f.push({type:0,subject:me,requested:le.ident,requester:Ce.requester,hash:g})}Be||f.push({type:2,node:le,hash:le.hash})}}}function*fat(t){let e=new Map;if(\"children\"in t)e.set(t,t);else for(let r of t.requests.values())e.set(r,r);for(let[r,s]of e){yield{request:r,root:s};for(let a of r.children.values())e.has(a)||e.set(a,s)}}function Aat(t,e){let r=[],s=[],a=!1;for(let n of t.peerWarnings)if(!(n.type===1||n.type===0)){if(!t.tryWorkspaceByLocator(n.node.subject)){a=!0;continue}if(n.type===3){let c=t.storedResolutions.get(n.node.provided.descriptorHash);if(typeof c>\"u\")throw new Error(\"Assertion failed: Expected the descriptor to be registered\");let f=t.storedPackages.get(c);if(typeof f>\"u\")throw new Error(\"Assertion failed: Expected the package to be registered\");let p=p0(fat(n.node),({request:C,root:S})=>Xf(f.version??\"0.0.0\",C.descriptor.range)?p0.skip:C===S?Xi(t.configuration,C.requester):`${Xi(t.configuration,C.requester)} (via ${Xi(t.configuration,S.requester)})`),h=[...qB(n.node)].length>1?\"and other dependencies request\":\"requests\",E=n.range?iI(t.configuration,n.range):Ht(t.configuration,\"but they have non-overlapping ranges!\",\"redBright\");r.push(`${Xi(t.configuration,n.node.ident)} is listed by your project with version ${jB(t.configuration,f.version??\"0.0.0\")} (${Ht(t.configuration,n.hash,ht.CODE)}), which doesn't satisfy what ${p} ${h} (${E}).`)}if(n.type===2){let c=n.node.requests.size>1?\" and other dependencies\":\"\";s.push(`${Yr(t.configuration,n.node.subject)} doesn't provide ${Xi(t.configuration,n.node.ident)} (${Ht(t.configuration,n.hash,ht.CODE)}), requested by ${Xi(t.configuration,n.node.requests.values().next().value.requester)}${c}.`)}}e.startSectionSync({reportFooter:()=>{e.reportWarning(86,`Some peer dependencies are incorrectly met by your project; run ${Ht(t.configuration,\"yarn explain peer-requirements <hash>\",ht.CODE)} for details, where ${Ht(t.configuration,\"<hash>\",ht.CODE)} is the six-letter p-prefixed code.`)},skipIfEmpty:!0},()=>{for(let n of qs(r,c=>JE.default(c)))e.reportWarning(60,n);for(let n of qs(s,c=>JE.default(c)))e.reportWarning(2,n)}),a&&e.reportWarning(86,`Some peer dependencies are incorrectly met by dependencies; run ${Ht(t.configuration,\"yarn explain peer-requirements\",ht.CODE)} for details.`)}var jT,GT,Ede,JG,VG,KG,qT,sat,oat,mde,aat,lat,cat,$l,YG,WT,yde,Rt,Ide=Ze(()=>{Dt();Dt();wc();Yt();jT=Ie(\"crypto\");GG();ql();GT=ut(Ld()),Ede=ut(Ai()),JG=Ie(\"util\"),VG=ut(Ie(\"v8\")),KG=ut(Ie(\"zlib\"));FG();av();NG();OG();oI();R8();Rc();gde();Ev();qG();tm();WG();OQ();xc();I0();bc();hR();Vj();Tp();Wo();qT=YE(process.env.YARN_LOCKFILE_VERSION_OVERRIDE??8),sat=3,oat=/ *, */g,mde=/\\/$/,aat=32,lat=(0,JG.promisify)(KG.default.gzip),cat=(0,JG.promisify)(KG.default.gunzip),$l=(r=>(r.UpdateLockfile=\"update-lockfile\",r.SkipBuild=\"skip-build\",r))($l||{}),YG={restoreLinkersCustomData:[\"linkersCustomData\"],restoreResolutions:[\"accessibleLocators\",\"conditionalLocators\",\"disabledLocators\",\"optionalBuilds\",\"storedDescriptors\",\"storedResolutions\",\"storedPackages\",\"lockFileChecksum\"],restoreBuildState:[\"skippedBuilds\",\"storedBuildState\"]},WT=(a=>(a[a.NotProvided=0]=\"NotProvided\",a[a.NotCompatible=1]=\"NotCompatible\",a[a.NodeNotProvided=2]=\"NodeNotProvided\",a[a.NodeNotCompatible=3]=\"NodeNotCompatible\",a))(WT||{}),yde=t=>cs(`${sat}`,t),Rt=class t{constructor(e,{configuration:r}){this.resolutionAliases=new Map;this.workspaces=[];this.workspacesByCwd=new Map;this.workspacesByIdent=new Map;this.storedResolutions=new Map;this.storedDescriptors=new Map;this.storedPackages=new Map;this.storedChecksums=new Map;this.storedBuildState=new Map;this.accessibleLocators=new Set;this.conditionalLocators=new Set;this.disabledLocators=new Set;this.originalPackages=new Map;this.optionalBuilds=new Set;this.skippedBuilds=new Set;this.lockfileLastVersion=null;this.lockfileNeedsRefresh=!1;this.peerRequirements=new Map;this.peerWarnings=[];this.peerRequirementNodes=new Map;this.linkersCustomData=new Map;this.lockFileChecksum=null;this.installStateChecksum=null;this.configuration=r,this.cwd=e}static async find(e,r){if(!e.projectCwd)throw new nt(`No project found in ${r}`);let s=e.projectCwd,a=r,n=null;for(;n!==e.projectCwd;){if(n=a,ce.existsSync(J.join(n,Er.manifest))){s=n;break}a=J.dirname(n)}let c=new t(e.projectCwd,{configuration:e});ze.telemetry?.reportProject(c.cwd),await c.setupResolutions(),await c.setupWorkspaces(),ze.telemetry?.reportWorkspaceCount(c.workspaces.length),ze.telemetry?.reportDependencyCount(c.workspaces.reduce((I,T)=>I+T.manifest.dependencies.size+T.manifest.devDependencies.size,0));let f=c.tryWorkspaceByCwd(s);if(f)return{project:c,workspace:f,locator:f.anchoredLocator};let p=await c.findLocatorForLocation(`${s}/`,{strict:!0});if(p)return{project:c,locator:p,workspace:null};let h=Ht(e,c.cwd,ht.PATH),E=Ht(e,J.relative(c.cwd,s),ht.PATH),C=`- If ${h} isn't intended to be a project, remove any yarn.lock and/or package.json file there.`,S=`- If ${h} is intended to be a project, it might be that you forgot to list ${E} in its workspace configuration.`,b=`- Finally, if ${h} is fine and you intend ${E} to be treated as a completely separate project (not even a workspace), create an empty yarn.lock file in it.`;throw new nt(`The nearest package directory (${Ht(e,s,ht.PATH)}) doesn't seem to be part of the project declared in ${Ht(e,c.cwd,ht.PATH)}.\n\n${[C,S,b].join(`\n`)}`)}async setupResolutions(){this.storedResolutions=new Map,this.storedDescriptors=new Map,this.storedPackages=new Map,this.lockFileChecksum=null;let e=J.join(this.cwd,Er.lockfile),r=this.configuration.get(\"defaultLanguageName\");if(ce.existsSync(e)){let s=await ce.readFilePromise(e,\"utf8\");this.lockFileChecksum=yde(s);let a=as(s);if(a.__metadata){let n=a.__metadata.version,c=a.__metadata.cacheKey;this.lockfileLastVersion=n,this.lockfileNeedsRefresh=n<qT;for(let f of Object.keys(a)){if(f===\"__metadata\")continue;let p=a[f];if(typeof p.resolution>\"u\")throw new Error(`Assertion failed: Expected the lockfile entry to have a resolution field (${f})`);let h=Qp(p.resolution,!0),E=new Ut;E.load(p,{yamlCompatibilityMode:!0});let C=E.version,S=E.languageName||r,b=p.linkType.toUpperCase(),I=p.conditions??null,T=E.dependencies,N=E.peerDependencies,U=E.dependenciesMeta,W=E.peerDependenciesMeta,ee=E.bin;if(p.checksum!=null){let ue=typeof c<\"u\"&&!p.checksum.includes(\"/\")?`${c}/${p.checksum}`:p.checksum;this.storedChecksums.set(h.locatorHash,ue)}let ie={...h,version:C,languageName:S,linkType:b,conditions:I,dependencies:T,peerDependencies:N,dependenciesMeta:U,peerDependenciesMeta:W,bin:ee};this.originalPackages.set(ie.locatorHash,ie);for(let ue of f.split(oat)){let le=C0(ue);n<=6&&(le=this.configuration.normalizeDependency(le),le=On(le,le.range.replace(/^patch:[^@]+@(?!npm(:|%3A))/,\"$1npm%3A\"))),this.storedDescriptors.set(le.descriptorHash,le),this.storedResolutions.set(le.descriptorHash,h.locatorHash)}}}else s.includes(\"yarn lockfile v1\")&&(this.lockfileLastVersion=-1)}}async setupWorkspaces(){this.workspaces=[],this.workspacesByCwd=new Map,this.workspacesByIdent=new Map;let e=new Set,r=(0,GT.default)(4),s=async(a,n)=>{if(e.has(n))return a;e.add(n);let c=new ZI(n,{project:this});await r(()=>c.setup());let f=a.then(()=>{this.addWorkspace(c)});return Array.from(c.workspacesCwds).reduce(s,f)};await s(Promise.resolve(),this.cwd)}addWorkspace(e){let r=this.workspacesByIdent.get(e.anchoredLocator.identHash);if(typeof r<\"u\")throw new Error(`Duplicate workspace name ${Xi(this.configuration,e.anchoredLocator)}: ${fe.fromPortablePath(e.cwd)} conflicts with ${fe.fromPortablePath(r.cwd)}`);this.workspaces.push(e),this.workspacesByCwd.set(e.cwd,e),this.workspacesByIdent.set(e.anchoredLocator.identHash,e)}get topLevelWorkspace(){return this.getWorkspaceByCwd(this.cwd)}tryWorkspaceByCwd(e){J.isAbsolute(e)||(e=J.resolve(this.cwd,e)),e=J.normalize(e).replace(/\\/+$/,\"\");let r=this.workspacesByCwd.get(e);return r||null}getWorkspaceByCwd(e){let r=this.tryWorkspaceByCwd(e);if(!r)throw new Error(`Workspace not found (${e})`);return r}tryWorkspaceByFilePath(e){let r=null;for(let s of this.workspaces)J.relative(s.cwd,e).startsWith(\"../\")||r&&r.cwd.length>=s.cwd.length||(r=s);return r||null}getWorkspaceByFilePath(e){let r=this.tryWorkspaceByFilePath(e);if(!r)throw new Error(`Workspace not found (${e})`);return r}tryWorkspaceByIdent(e){let r=this.workspacesByIdent.get(e.identHash);return typeof r>\"u\"?null:r}getWorkspaceByIdent(e){let r=this.tryWorkspaceByIdent(e);if(!r)throw new Error(`Workspace not found (${Xi(this.configuration,e)})`);return r}tryWorkspaceByDescriptor(e){if(e.range.startsWith(Ei.protocol)){let s=e.range.slice(Ei.protocol.length);if(s!==\"^\"&&s!==\"~\"&&s!==\"*\"&&!cl(s))return this.tryWorkspaceByCwd(s)}let r=this.tryWorkspaceByIdent(e);return r===null||(kp(e)&&(e=MB(e)),!r.accepts(e.range))?null:r}getWorkspaceByDescriptor(e){let r=this.tryWorkspaceByDescriptor(e);if(r===null)throw new Error(`Workspace not found (${ni(this.configuration,e)})`);return r}tryWorkspaceByLocator(e){let r=this.tryWorkspaceByIdent(e);return r===null||(Gu(e)&&(e=rI(e)),r.anchoredLocator.locatorHash!==e.locatorHash)?null:r}getWorkspaceByLocator(e){let r=this.tryWorkspaceByLocator(e);if(!r)throw new Error(`Workspace not found (${Yr(this.configuration,e)})`);return r}deleteDescriptor(e){this.storedResolutions.delete(e),this.storedDescriptors.delete(e)}deleteLocator(e){this.originalPackages.delete(e),this.storedPackages.delete(e),this.accessibleLocators.delete(e)}forgetResolution(e){if(\"descriptorHash\"in e){let r=this.storedResolutions.get(e.descriptorHash);this.deleteDescriptor(e.descriptorHash);let s=new Set(this.storedResolutions.values());typeof r<\"u\"&&!s.has(r)&&this.deleteLocator(r)}if(\"locatorHash\"in e){this.deleteLocator(e.locatorHash);for(let[r,s]of this.storedResolutions)s===e.locatorHash&&this.deleteDescriptor(r)}}forgetTransientResolutions(){let e=this.configuration.makeResolver(),r=new Map;for(let[s,a]of this.storedResolutions.entries()){let n=r.get(a);n||r.set(a,n=new Set),n.add(s)}for(let s of this.originalPackages.values()){let a;try{a=e.shouldPersistResolution(s,{project:this,resolver:e})}catch{a=!1}if(!a){this.deleteLocator(s.locatorHash);let n=r.get(s.locatorHash);if(n){r.delete(s.locatorHash);for(let c of n)this.deleteDescriptor(c)}}}}forgetVirtualResolutions(){for(let e of this.storedPackages.values())for(let[r,s]of e.dependencies)kp(s)&&e.dependencies.set(r,MB(s))}getDependencyMeta(e,r){let s={},n=this.topLevelWorkspace.manifest.dependenciesMeta.get(un(e));if(!n)return s;let c=n.get(null);if(c&&Object.assign(s,c),r===null||!Ede.default.valid(r))return s;for(let[f,p]of n)f!==null&&f===r&&Object.assign(s,p);return s}async findLocatorForLocation(e,{strict:r=!1}={}){let s=new ki,a=this.configuration.getLinkers(),n={project:this,report:s};for(let c of a){let f=await c.findPackageLocator(e,n);if(f){if(r&&(await c.findPackageLocation(f,n)).replace(mde,\"\")!==e.replace(mde,\"\"))continue;return f}}return null}async loadUserConfig(){let e=J.join(this.cwd,\".pnp.cjs\");await ce.existsPromise(e)&&bp(e).setup();let r=J.join(this.cwd,\"yarn.config.cjs\");return await ce.existsPromise(r)?bp(r):null}async preparePackage(e,{resolver:r,resolveOptions:s}){let a=await this.configuration.getPackageExtensions(),n=this.configuration.normalizePackage(e,{packageExtensions:a});for(let[c,f]of n.dependencies){let p=await this.configuration.reduceHook(E=>E.reduceDependency,f,this,n,f,{resolver:r,resolveOptions:s});if(!UB(f,p))throw new Error(\"Assertion failed: The descriptor ident cannot be changed through aliases\");let h=r.bindDescriptor(p,n,s);n.dependencies.set(c,h)}return n}async resolveEverything(e){if(!this.workspacesByCwd||!this.workspacesByIdent)throw new Error(\"Workspaces must have been setup before calling this function\");this.forgetVirtualResolutions();let r=new Map(this.originalPackages),s=[];e.lockfileOnly||this.forgetTransientResolutions();let a=e.resolver||this.configuration.makeResolver(),n=new KI(a);await n.setup(this,{report:e.report});let c=e.lockfileOnly?[new HT(a)]:[n,a],f=new rm([new zI(a),...c]),p=new rm([...c]),h=this.configuration.makeFetcher(),E=e.lockfileOnly?{project:this,report:e.report,resolver:f}:{project:this,report:e.report,resolver:f,fetchOptions:{project:this,cache:e.cache,checksums:this.storedChecksums,report:e.report,fetcher:h,cacheOptions:{mirrorWriteOnly:!0}}},C=new Map,S=new Map,b=new Map,I=new Map,T=new Map,N=new Map,U=this.topLevelWorkspace.anchoredLocator,W=new Set,ee=[],ie=lj(),ue=this.configuration.getSupportedArchitectures();await e.report.startProgressPromise(Ao.progressViaTitle(),async se=>{let X=async rt=>{let Fe=await qE(async()=>await f.resolve(rt,E),ke=>`${Yr(this.configuration,rt)}: ${ke}`);if(!_B(rt,Fe))throw new Error(`Assertion failed: The locator cannot be changed by the resolver (went from ${Yr(this.configuration,rt)} to ${Yr(this.configuration,Fe)})`);I.set(Fe.locatorHash,Fe),!r.delete(Fe.locatorHash)&&!this.tryWorkspaceByLocator(Fe)&&s.push(Fe);let be=await this.preparePackage(Fe,{resolver:f,resolveOptions:E}),Ve=Uu([...be.dependencies.values()].map(ke=>j(ke)));return ee.push(Ve),Ve.catch(()=>{}),S.set(be.locatorHash,be),be},De=async rt=>{let Fe=T.get(rt.locatorHash);if(typeof Fe<\"u\")return Fe;let Ne=Promise.resolve().then(()=>X(rt));return T.set(rt.locatorHash,Ne),Ne},Te=async(rt,Fe)=>{let Ne=await j(Fe);return C.set(rt.descriptorHash,rt),b.set(rt.descriptorHash,Ne.locatorHash),Ne},mt=async rt=>{se.setTitle(ni(this.configuration,rt));let Fe=this.resolutionAliases.get(rt.descriptorHash);if(typeof Fe<\"u\")return Te(rt,this.storedDescriptors.get(Fe));let Ne=f.getResolutionDependencies(rt,E),be=Object.fromEntries(await Uu(Object.entries(Ne).map(async([it,Ue])=>{let x=f.bindDescriptor(Ue,U,E),w=await j(x);return W.add(w.locatorHash),[it,w]}))),ke=(await qE(async()=>await f.getCandidates(rt,be,E),it=>`${ni(this.configuration,rt)}: ${it}`))[0];if(typeof ke>\"u\")throw new jt(82,`${ni(this.configuration,rt)}: No candidates found`);if(e.checkResolutions){let{locators:it}=await p.getSatisfying(rt,be,[ke],{...E,resolver:p});if(!it.find(Ue=>Ue.locatorHash===ke.locatorHash))throw new jt(78,`Invalid resolution ${FB(this.configuration,rt,ke)}`)}return C.set(rt.descriptorHash,rt),b.set(rt.descriptorHash,ke.locatorHash),De(ke)},j=rt=>{let Fe=N.get(rt.descriptorHash);if(typeof Fe<\"u\")return Fe;C.set(rt.descriptorHash,rt);let Ne=Promise.resolve().then(()=>mt(rt));return N.set(rt.descriptorHash,Ne),Ne};for(let rt of this.workspaces){let Fe=rt.anchoredDescriptor;ee.push(j(Fe))}for(;ee.length>0;){let rt=[...ee];ee.length=0,await Uu(rt)}});let le=Wl(r.values(),se=>this.tryWorkspaceByLocator(se)?Wl.skip:se);if(s.length>0||le.length>0){let se=new Set(this.workspaces.flatMap(rt=>{let Fe=S.get(rt.anchoredLocator.locatorHash);if(!Fe)throw new Error(\"Assertion failed: The workspace should have been resolved\");return Array.from(Fe.dependencies.values(),Ne=>{let be=b.get(Ne.descriptorHash);if(!be)throw new Error(\"Assertion failed: The resolution should have been registered\");return be})})),X=rt=>se.has(rt.locatorHash)?\"0\":\"1\",De=rt=>ll(rt),Te=qs(s,[X,De]),mt=qs(le,[X,De]),j=e.report.getRecommendedLength();Te.length>0&&e.report.reportInfo(85,`${Ht(this.configuration,\"+\",ht.ADDED)} ${Xk(this.configuration,Te,j)}`),mt.length>0&&e.report.reportInfo(85,`${Ht(this.configuration,\"-\",ht.REMOVED)} ${Xk(this.configuration,mt,j)}`)}let me=new Set(this.resolutionAliases.values()),pe=new Set(S.keys()),Be=new Set,Ce=new Map,g=[],we=new Map;uat({project:this,accessibleLocators:Be,volatileDescriptors:me,optionalBuilds:pe,peerRequirements:Ce,peerWarnings:g,peerRequirementNodes:we,allDescriptors:C,allResolutions:b,allPackages:S});for(let se of W)pe.delete(se);for(let se of me)C.delete(se),b.delete(se);let ye=new Set,Ae=new Set;for(let se of S.values())se.conditions!=null&&pe.has(se.locatorHash)&&(QQ(se,ue)||(QQ(se,ie)&&e.report.reportWarningOnce(77,`${Yr(this.configuration,se)}: Your current architecture (${process.platform}-${process.arch}) is supported by this package, but is missing from the ${Ht(this.configuration,\"supportedArchitectures\",ht.SETTING)} setting`),Ae.add(se.locatorHash)),ye.add(se.locatorHash));this.storedResolutions=b,this.storedDescriptors=C,this.storedPackages=S,this.accessibleLocators=Be,this.conditionalLocators=ye,this.disabledLocators=Ae,this.originalPackages=I,this.optionalBuilds=pe,this.peerRequirements=Ce,this.peerWarnings=g,this.peerRequirementNodes=we}async fetchEverything({cache:e,report:r,fetcher:s,mode:a,persistProject:n=!0}){let c={mockedPackages:this.disabledLocators,unstablePackages:this.conditionalLocators},f=s||this.configuration.makeFetcher(),p={checksums:this.storedChecksums,project:this,cache:e,fetcher:f,report:r,cacheOptions:c},h=Array.from(new Set(qs(this.storedResolutions.values(),[I=>{let T=this.storedPackages.get(I);if(!T)throw new Error(\"Assertion failed: The locator should have been registered\");return ll(T)}])));a===\"update-lockfile\"&&(h=h.filter(I=>!this.storedChecksums.has(I)));let E=!1,C=Ao.progressViaCounter(h.length);await r.reportProgress(C);let S=(0,GT.default)(aat);if(await Uu(h.map(I=>S(async()=>{let T=this.storedPackages.get(I);if(!T)throw new Error(\"Assertion failed: The locator should have been registered\");if(Gu(T))return;let N;try{N=await f.fetch(T,p)}catch(U){U.message=`${Yr(this.configuration,T)}: ${U.message}`,r.reportExceptionOnce(U),E=U;return}N.checksum!=null?this.storedChecksums.set(T.locatorHash,N.checksum):this.storedChecksums.delete(T.locatorHash),N.releaseFs&&N.releaseFs()}).finally(()=>{C.tick()}))),E)throw E;let b=n&&a!==\"update-lockfile\"?await this.cacheCleanup({cache:e,report:r}):null;if(r.cacheMisses.size>0||b){let T=(await Promise.all([...r.cacheMisses].map(async le=>{let me=this.storedPackages.get(le),pe=this.storedChecksums.get(le)??null,Be=e.getLocatorPath(me,pe);return(await ce.statPromise(Be)).size}))).reduce((le,me)=>le+me,0)-(b?.size??0),N=r.cacheMisses.size,U=b?.count??0,W=`${Wk(N,{zero:\"No new packages\",one:\"A package was\",more:`${Ht(this.configuration,N,ht.NUMBER)} packages were`})} added to the project`,ee=`${Wk(U,{zero:\"none were\",one:\"one was\",more:`${Ht(this.configuration,U,ht.NUMBER)} were`})} removed`,ie=T!==0?` (${Ht(this.configuration,T,ht.SIZE_DIFF)})`:\"\",ue=U>0?N>0?`${W}, and ${ee}${ie}.`:`${W}, but ${ee}${ie}.`:`${W}${ie}.`;r.reportInfo(13,ue)}}async linkEverything({cache:e,report:r,fetcher:s,mode:a}){let n={mockedPackages:this.disabledLocators,unstablePackages:this.conditionalLocators,skipIntegrityCheck:!0},c=s||this.configuration.makeFetcher(),f={checksums:this.storedChecksums,project:this,cache:e,fetcher:c,report:r,cacheOptions:n},p=this.configuration.getLinkers(),h={project:this,report:r},E=new Map(p.map(ye=>{let Ae=ye.makeInstaller(h),se=ye.getCustomDataKey(),X=this.linkersCustomData.get(se);return typeof X<\"u\"&&Ae.attachCustomData(X),[ye,Ae]})),C=new Map,S=new Map,b=new Map,I=new Map(await Uu([...this.accessibleLocators].map(async ye=>{let Ae=this.storedPackages.get(ye);if(!Ae)throw new Error(\"Assertion failed: The locator should have been registered\");return[ye,await c.fetch(Ae,f)]}))),T=[],N=new Set,U=[];for(let ye of this.accessibleLocators){let Ae=this.storedPackages.get(ye);if(typeof Ae>\"u\")throw new Error(\"Assertion failed: The locator should have been registered\");let se=I.get(Ae.locatorHash);if(typeof se>\"u\")throw new Error(\"Assertion failed: The fetch result should have been registered\");let X=[],De=mt=>{X.push(mt)},Te=this.tryWorkspaceByLocator(Ae);if(Te!==null){let mt=[],{scripts:j}=Te.manifest;for(let Fe of[\"preinstall\",\"install\",\"postinstall\"])j.has(Fe)&&mt.push({type:0,script:Fe});try{for(let[Fe,Ne]of E)if(Fe.supportsPackage(Ae,h)&&(await Ne.installPackage(Ae,se,{holdFetchResult:De})).buildRequest!==null)throw new Error(\"Assertion failed: Linkers can't return build directives for workspaces; this responsibility befalls to the Yarn core\")}finally{X.length===0?se.releaseFs?.():T.push(Uu(X).catch(()=>{}).then(()=>{se.releaseFs?.()}))}let rt=J.join(se.packageFs.getRealPath(),se.prefixPath);S.set(Ae.locatorHash,rt),!Gu(Ae)&&mt.length>0&&b.set(Ae.locatorHash,{buildDirectives:mt,buildLocations:[rt]})}else{let mt=p.find(Fe=>Fe.supportsPackage(Ae,h));if(!mt)throw new jt(12,`${Yr(this.configuration,Ae)} isn't supported by any available linker`);let j=E.get(mt);if(!j)throw new Error(\"Assertion failed: The installer should have been registered\");let rt;try{rt=await j.installPackage(Ae,se,{holdFetchResult:De})}finally{X.length===0?se.releaseFs?.():T.push(Uu(X).then(()=>{}).then(()=>{se.releaseFs?.()}))}C.set(Ae.locatorHash,mt),S.set(Ae.locatorHash,rt.packageLocation),rt.buildRequest&&rt.packageLocation&&(rt.buildRequest.skipped?(N.add(Ae.locatorHash),this.skippedBuilds.has(Ae.locatorHash)||U.push([Ae,rt.buildRequest.explain])):b.set(Ae.locatorHash,{buildDirectives:rt.buildRequest.directives,buildLocations:[rt.packageLocation]}))}}let W=new Map;for(let ye of this.accessibleLocators){let Ae=this.storedPackages.get(ye);if(!Ae)throw new Error(\"Assertion failed: The locator should have been registered\");let se=this.tryWorkspaceByLocator(Ae)!==null,X=async(De,Te)=>{let mt=S.get(Ae.locatorHash);if(typeof mt>\"u\")throw new Error(`Assertion failed: The package (${Yr(this.configuration,Ae)}) should have been registered`);let j=[];for(let rt of Ae.dependencies.values()){let Fe=this.storedResolutions.get(rt.descriptorHash);if(typeof Fe>\"u\")throw new Error(`Assertion failed: The resolution (${ni(this.configuration,rt)}, from ${Yr(this.configuration,Ae)})should have been registered`);let Ne=this.storedPackages.get(Fe);if(typeof Ne>\"u\")throw new Error(`Assertion failed: The package (${Fe}, resolved from ${ni(this.configuration,rt)}) should have been registered`);let be=this.tryWorkspaceByLocator(Ne)===null?C.get(Fe):null;if(typeof be>\"u\")throw new Error(`Assertion failed: The package (${Fe}, resolved from ${ni(this.configuration,rt)}) should have been registered`);be===De||be===null?S.get(Ne.locatorHash)!==null&&j.push([rt,Ne]):!se&&mt!==null&&xB(W,Fe).push(mt)}mt!==null&&await Te.attachInternalDependencies(Ae,j)};if(se)for(let[De,Te]of E)De.supportsPackage(Ae,h)&&await X(De,Te);else{let De=C.get(Ae.locatorHash);if(!De)throw new Error(\"Assertion failed: The linker should have been found\");let Te=E.get(De);if(!Te)throw new Error(\"Assertion failed: The installer should have been registered\");await X(De,Te)}}for(let[ye,Ae]of W){let se=this.storedPackages.get(ye);if(!se)throw new Error(\"Assertion failed: The package should have been registered\");let X=C.get(se.locatorHash);if(!X)throw new Error(\"Assertion failed: The linker should have been found\");let De=E.get(X);if(!De)throw new Error(\"Assertion failed: The installer should have been registered\");await De.attachExternalDependents(se,Ae)}let ee=new Map;for(let[ye,Ae]of E){let se=await Ae.finalizeInstall();for(let X of se?.records??[])X.buildRequest.skipped?(N.add(X.locator.locatorHash),this.skippedBuilds.has(X.locator.locatorHash)||U.push([X.locator,X.buildRequest.explain])):b.set(X.locator.locatorHash,{buildDirectives:X.buildRequest.directives,buildLocations:X.buildLocations});typeof se?.customData<\"u\"&&ee.set(ye.getCustomDataKey(),se.customData)}if(this.linkersCustomData=ee,await Uu(T),a===\"skip-build\")return;for(let[,ye]of qs(U,([Ae])=>ll(Ae)))ye(r);let ie=new Set(b.keys()),ue=(0,jT.createHash)(\"sha512\");ue.update(process.versions.node),await this.configuration.triggerHook(ye=>ye.globalHashGeneration,this,ye=>{ue.update(\"\\0\"),ue.update(ye)});let le=ue.digest(\"hex\"),me=new Map,pe=ye=>{let Ae=me.get(ye.locatorHash);if(typeof Ae<\"u\")return Ae;let se=this.storedPackages.get(ye.locatorHash);if(typeof se>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");let X=(0,jT.createHash)(\"sha512\");X.update(ye.locatorHash),me.set(ye.locatorHash,\"<recursive>\");for(let De of se.dependencies.values()){let Te=this.storedResolutions.get(De.descriptorHash);if(typeof Te>\"u\")throw new Error(`Assertion failed: The resolution (${ni(this.configuration,De)}) should have been registered`);let mt=this.storedPackages.get(Te);if(typeof mt>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");X.update(pe(mt))}return Ae=X.digest(\"hex\"),me.set(ye.locatorHash,Ae),Ae},Be=(ye,Ae)=>{let se=(0,jT.createHash)(\"sha512\");se.update(le),se.update(pe(ye));for(let X of Ae)se.update(X);return se.digest(\"hex\")},Ce=new Map,g=!1,we=ye=>{let Ae=new Set([ye.locatorHash]);for(let se of Ae){let X=this.storedPackages.get(se);if(!X)throw new Error(\"Assertion failed: The package should have been registered\");for(let De of X.dependencies.values()){let Te=this.storedResolutions.get(De.descriptorHash);if(!Te)throw new Error(`Assertion failed: The resolution (${ni(this.configuration,De)}) should have been registered`);if(Te!==ye.locatorHash&&ie.has(Te))return!1;let mt=this.storedPackages.get(Te);if(!mt)throw new Error(\"Assertion failed: The package should have been registered\");let j=this.tryWorkspaceByLocator(mt);if(j){if(j.anchoredLocator.locatorHash!==ye.locatorHash&&ie.has(j.anchoredLocator.locatorHash))return!1;Ae.add(j.anchoredLocator.locatorHash)}Ae.add(Te)}}return!0};for(;ie.size>0;){let ye=ie.size,Ae=[];for(let se of ie){let X=this.storedPackages.get(se);if(!X)throw new Error(\"Assertion failed: The package should have been registered\");if(!we(X))continue;let De=b.get(X.locatorHash);if(!De)throw new Error(\"Assertion failed: The build directive should have been registered\");let Te=Be(X,De.buildLocations);if(this.storedBuildState.get(X.locatorHash)===Te){Ce.set(X.locatorHash,Te),ie.delete(se);continue}g||(await this.persistInstallStateFile(),g=!0),this.storedBuildState.has(X.locatorHash)?r.reportInfo(8,`${Yr(this.configuration,X)} must be rebuilt because its dependency tree changed`):r.reportInfo(7,`${Yr(this.configuration,X)} must be built because it never has been before or the last one failed`);let mt=De.buildLocations.map(async j=>{if(!J.isAbsolute(j))throw new Error(`Assertion failed: Expected the build location to be absolute (not ${j})`);for(let rt of De.buildDirectives){let Fe=`# This file contains the result of Yarn building a package (${ll(X)})\n`;switch(rt.type){case 0:Fe+=`# Script name: ${rt.script}\n`;break;case 1:Fe+=`# Script code: ${rt.script}\n`;break}let Ne=null;if(!await ce.mktempPromise(async Ve=>{let ke=J.join(Ve,\"build.log\"),{stdout:it,stderr:Ue}=this.configuration.getSubprocessStreams(ke,{header:Fe,prefix:Yr(this.configuration,X),report:r}),x;try{switch(rt.type){case 0:x=await OR(X,rt.script,[],{cwd:j,project:this,stdin:Ne,stdout:it,stderr:Ue});break;case 1:x=await Gj(X,rt.script,[],{cwd:j,project:this,stdin:Ne,stdout:it,stderr:Ue});break}}catch(y){Ue.write(y.stack),x=1}if(it.end(),Ue.end(),x===0)return!0;ce.detachTemp(Ve);let w=`${Yr(this.configuration,X)} couldn't be built successfully (exit code ${Ht(this.configuration,x,ht.NUMBER)}, logs can be found here: ${Ht(this.configuration,ke,ht.PATH)})`,P=this.optionalBuilds.has(X.locatorHash);return P?r.reportInfo(9,w):r.reportError(9,w),zpe&&r.reportFold(fe.fromPortablePath(ke),ce.readFileSync(ke,\"utf8\")),P}))return!1}return!0});Ae.push(...mt,Promise.allSettled(mt).then(j=>{ie.delete(se),j.every(rt=>rt.status===\"fulfilled\"&&rt.value===!0)&&Ce.set(X.locatorHash,Te)}))}if(await Uu(Ae),ye===ie.size){let se=Array.from(ie).map(X=>{let De=this.storedPackages.get(X);if(!De)throw new Error(\"Assertion failed: The package should have been registered\");return Yr(this.configuration,De)}).join(\", \");r.reportError(3,`Some packages have circular dependencies that make their build order unsatisfiable - as a result they won't be built (affected packages are: ${se})`);break}}this.storedBuildState=Ce,this.skippedBuilds=N}async installWithNewReport(e,r){return(await Ot.start({configuration:this.configuration,json:e.json,stdout:e.stdout,forceSectionAlignment:!0,includeLogs:!e.json&&!e.quiet,includeVersion:!0},async a=>{await this.install({...r,report:a})})).exitCode()}async install(e){let r=this.configuration.get(\"nodeLinker\");ze.telemetry?.reportInstall(r);let s=!1;if(await e.report.startTimerPromise(\"Project validation\",{skipIfEmpty:!0},async()=>{this.configuration.get(\"enableOfflineMode\")&&e.report.reportWarning(90,\"Offline work is enabled; Yarn won't fetch packages from the remote registry if it can avoid it\"),await this.configuration.triggerHook(E=>E.validateProject,this,{reportWarning:(E,C)=>{e.report.reportWarning(E,C)},reportError:(E,C)=>{e.report.reportError(E,C),s=!0}})}),s)return;let a=await this.configuration.getPackageExtensions();for(let E of a.values())for(let[,C]of E)for(let S of C)S.status=\"inactive\";let n=J.join(this.cwd,Er.lockfile),c=null;if(e.immutable)try{c=await ce.readFilePromise(n,\"utf8\")}catch(E){throw E.code===\"ENOENT\"?new jt(28,\"The lockfile would have been created by this install, which is explicitly forbidden.\"):E}await e.report.startTimerPromise(\"Resolution step\",async()=>{await this.resolveEverything(e)}),await e.report.startTimerPromise(\"Post-resolution validation\",{skipIfEmpty:!0},async()=>{Aat(this,e.report);for(let[,E]of a)for(let[,C]of E)for(let S of C)if(S.userProvided){let b=Ht(this.configuration,S,ht.PACKAGE_EXTENSION);switch(S.status){case\"inactive\":e.report.reportWarning(68,`${b}: No matching package in the dependency tree; you may not need this rule anymore.`);break;case\"redundant\":e.report.reportWarning(69,`${b}: This rule seems redundant when applied on the original package; the extension may have been applied upstream.`);break}}if(c!==null){let E=Ed(c,this.generateLockfile());if(E!==c){let C=hde(n,n,c,E,void 0,void 0,{maxEditLength:100});if(C){e.report.reportSeparator();for(let S of C.hunks){e.report.reportInfo(null,`@@ -${S.oldStart},${S.oldLines} +${S.newStart},${S.newLines} @@`);for(let b of S.lines)b.startsWith(\"+\")?e.report.reportError(28,Ht(this.configuration,b,ht.ADDED)):b.startsWith(\"-\")?e.report.reportError(28,Ht(this.configuration,b,ht.REMOVED)):e.report.reportInfo(null,Ht(this.configuration,b,\"grey\"))}e.report.reportSeparator()}throw new jt(28,\"The lockfile would have been modified by this install, which is explicitly forbidden.\")}}});for(let E of a.values())for(let[,C]of E)for(let S of C)S.userProvided&&S.status===\"active\"&&ze.telemetry?.reportPackageExtension(Zd(S,ht.PACKAGE_EXTENSION));await e.report.startTimerPromise(\"Fetch step\",async()=>{await this.fetchEverything(e)});let f=e.immutable?[...new Set(this.configuration.get(\"immutablePatterns\"))].sort():[],p=await Promise.all(f.map(async E=>SQ(E,{cwd:this.cwd})));(typeof e.persistProject>\"u\"||e.persistProject)&&await this.persist(),await e.report.startTimerPromise(\"Link step\",async()=>{if(e.mode===\"update-lockfile\"){e.report.reportWarning(73,`Skipped due to ${Ht(this.configuration,\"mode=update-lockfile\",ht.CODE)}`);return}await this.linkEverything(e);let E=await Promise.all(f.map(async C=>SQ(C,{cwd:this.cwd})));for(let C=0;C<f.length;++C)p[C]!==E[C]&&e.report.reportError(64,`The checksum for ${f[C]} has been modified by this install, which is explicitly forbidden.`)}),await this.persistInstallStateFile();let h=!1;await e.report.startTimerPromise(\"Post-install validation\",{skipIfEmpty:!0},async()=>{await this.configuration.triggerHook(E=>E.validateProjectAfterInstall,this,{reportWarning:(E,C)=>{e.report.reportWarning(E,C)},reportError:(E,C)=>{e.report.reportError(E,C),h=!0}})}),!h&&await this.configuration.triggerHook(E=>E.afterAllInstalled,this,e)}generateLockfile(){let e=new Map;for(let[n,c]of this.storedResolutions.entries()){let f=e.get(c);f||e.set(c,f=new Set),f.add(n)}let r={},{cacheKey:s}=Kr.getCacheKey(this.configuration);r.__metadata={version:qT,cacheKey:s};for(let[n,c]of e.entries()){let f=this.originalPackages.get(n);if(!f)continue;let p=[];for(let C of c){let S=this.storedDescriptors.get(C);if(!S)throw new Error(\"Assertion failed: The descriptor should have been registered\");p.push(S)}let h=p.map(C=>al(C)).sort().join(\", \"),E=new Ut;E.version=f.linkType===\"HARD\"?f.version:\"0.0.0-use.local\",E.languageName=f.languageName,E.dependencies=new Map(f.dependencies),E.peerDependencies=new Map(f.peerDependencies),E.dependenciesMeta=new Map(f.dependenciesMeta),E.peerDependenciesMeta=new Map(f.peerDependenciesMeta),E.bin=new Map(f.bin),r[h]={...E.exportTo({},{compatibilityMode:!1}),linkType:f.linkType.toLowerCase(),resolution:ll(f),checksum:this.storedChecksums.get(f.locatorHash),conditions:f.conditions||void 0}}return`${[`# This file is generated by running \"yarn install\" inside your project.\n`,`# Manual changes might be lost - proceed with caution!\n`].join(\"\")}\n`+nl(r)}async persistLockfile(){let e=J.join(this.cwd,Er.lockfile),r=\"\";try{r=await ce.readFilePromise(e,\"utf8\")}catch{}let s=this.generateLockfile(),a=Ed(r,s);a!==r&&(await ce.writeFilePromise(e,a),this.lockFileChecksum=yde(a),this.lockfileNeedsRefresh=!1)}async persistInstallStateFile(){let e=[];for(let c of Object.values(YG))e.push(...c);let r=Kd(this,e),s=VG.default.serialize(r),a=cs(s);if(this.installStateChecksum===a)return;let n=this.configuration.get(\"installStatePath\");await ce.mkdirPromise(J.dirname(n),{recursive:!0}),await ce.writeFilePromise(n,await lat(s)),this.installStateChecksum=a}async restoreInstallState({restoreLinkersCustomData:e=!0,restoreResolutions:r=!0,restoreBuildState:s=!0}={}){let a=this.configuration.get(\"installStatePath\"),n;try{let c=await cat(await ce.readFilePromise(a));n=VG.default.deserialize(c),this.installStateChecksum=cs(c)}catch{r&&await this.applyLightResolution();return}e&&typeof n.linkersCustomData<\"u\"&&(this.linkersCustomData=n.linkersCustomData),s&&Object.assign(this,Kd(n,YG.restoreBuildState)),r&&(n.lockFileChecksum===this.lockFileChecksum?Object.assign(this,Kd(n,YG.restoreResolutions)):await this.applyLightResolution())}async applyLightResolution(){await this.resolveEverything({lockfileOnly:!0,report:new ki}),await this.persistInstallStateFile()}async persist(){let e=(0,GT.default)(4);await Promise.all([this.persistLockfile(),...this.workspaces.map(r=>e(()=>r.persistManifest()))])}async cacheCleanup({cache:e,report:r}){if(this.configuration.get(\"enableGlobalCache\"))return null;let s=new Set([\".gitignore\"]);if(!j8(e.cwd,this.cwd)||!await ce.existsPromise(e.cwd))return null;let a=[];for(let c of await ce.readdirPromise(e.cwd)){if(s.has(c))continue;let f=J.resolve(e.cwd,c);e.markedFiles.has(f)||(e.immutable?r.reportError(56,`${Ht(this.configuration,J.basename(f),\"magenta\")} appears to be unused and would be marked for deletion, but the cache is immutable`):a.push(ce.lstatPromise(f).then(async p=>(await ce.removePromise(f),p.size))))}if(a.length===0)return null;let n=await Promise.all(a);return{count:a.length,size:n.reduce((c,f)=>c+f,0)}}}});function pat(t){let s=Math.floor(t.timeNow/864e5),a=t.updateInterval*864e5,n=t.state.lastUpdate??t.timeNow+a+Math.floor(a*t.randomInitialInterval),c=n+a,f=t.state.lastTips??s*864e5,p=f+864e5+8*36e5-t.timeZone,h=c<=t.timeNow,E=p<=t.timeNow,C=null;return(h||E||!t.state.lastUpdate||!t.state.lastTips)&&(C={},C.lastUpdate=h?t.timeNow:n,C.lastTips=f,C.blocks=h?{}:t.state.blocks,C.displayedTips=t.state.displayedTips),{nextState:C,triggerUpdate:h,triggerTips:E,nextTips:E?s*864e5:f}}var XI,Cde=Ze(()=>{Dt();yv();I0();AR();bc();Tp();XI=class{constructor(e,r){this.values=new Map;this.hits=new Map;this.enumerators=new Map;this.nextTips=0;this.displayedTips=[];this.shouldCommitTips=!1;this.configuration=e;let s=this.getRegistryPath();this.isNew=!ce.existsSync(s),this.shouldShowTips=!1,this.sendReport(r),this.startBuffer()}commitTips(){this.shouldShowTips&&(this.shouldCommitTips=!0)}selectTip(e){let r=new Set(this.displayedTips),s=f=>f&&fn?Xf(fn,f):!1,a=e.map((f,p)=>p).filter(f=>e[f]&&s(e[f]?.selector));if(a.length===0)return null;let n=a.filter(f=>!r.has(f));if(n.length===0){let f=Math.floor(a.length*.2);this.displayedTips=f>0?this.displayedTips.slice(-f):[],n=a.filter(p=>!r.has(p))}let c=n[Math.floor(Math.random()*n.length)];return this.displayedTips.push(c),this.commitTips(),e[c]}reportVersion(e){this.reportValue(\"version\",e.replace(/-git\\..*/,\"-git\"))}reportCommandName(e){this.reportValue(\"commandName\",e||\"<none>\")}reportPluginName(e){this.reportValue(\"pluginName\",e)}reportProject(e){this.reportEnumerator(\"projectCount\",e)}reportInstall(e){this.reportHit(\"installCount\",e)}reportPackageExtension(e){this.reportValue(\"packageExtension\",e)}reportWorkspaceCount(e){this.reportValue(\"workspaceCount\",String(e))}reportDependencyCount(e){this.reportValue(\"dependencyCount\",String(e))}reportValue(e,r){Pp(this.values,e).add(r)}reportEnumerator(e,r){Pp(this.enumerators,e).add(cs(r))}reportHit(e,r=\"*\"){let s=j4(this.hits,e),a=Yl(s,r,()=>0);s.set(r,a+1)}getRegistryPath(){let e=this.configuration.get(\"globalFolder\");return J.join(e,\"telemetry.json\")}sendReport(e){let r=this.getRegistryPath(),s;try{s=ce.readJsonSync(r)}catch{s={}}let{nextState:a,triggerUpdate:n,triggerTips:c,nextTips:f}=pat({state:s,timeNow:Date.now(),timeZone:new Date().getTimezoneOffset()*60*1e3,randomInitialInterval:Math.random(),updateInterval:this.configuration.get(\"telemetryInterval\")});if(this.nextTips=f,this.displayedTips=s.displayedTips??[],a!==null)try{ce.mkdirSync(J.dirname(r),{recursive:!0}),ce.writeJsonSync(r,a)}catch{return!1}if(c&&this.configuration.get(\"enableTips\")&&(this.shouldShowTips=!0),n){let p=s.blocks??{};if(Object.keys(p).length===0){let h=`https://browser-http-intake.logs.datadoghq.eu/v1/input/${e}?ddsource=yarn`,E=C=>aj(h,C,{configuration:this.configuration}).catch(()=>{});for(let[C,S]of Object.entries(s.blocks??{})){if(Object.keys(S).length===0)continue;let b=S;b.userId=C,b.reportType=\"primary\";for(let N of Object.keys(b.enumerators??{}))b.enumerators[N]=b.enumerators[N].length;E(b);let I=new Map,T=20;for(let[N,U]of Object.entries(b.values))U.length>0&&I.set(N,U.slice(0,T));for(;I.size>0;){let N={};N.userId=C,N.reportType=\"secondary\",N.metrics={};for(let[U,W]of I)N.metrics[U]=W.shift(),W.length===0&&I.delete(U);E(N)}}}}return!0}applyChanges(){let e=this.getRegistryPath(),r;try{r=ce.readJsonSync(e)}catch{r={}}let s=this.configuration.get(\"telemetryUserId\")??\"*\",a=r.blocks=r.blocks??{},n=a[s]=a[s]??{};for(let c of this.hits.keys()){let f=n.hits=n.hits??{},p=f[c]=f[c]??{};for(let[h,E]of this.hits.get(c))p[h]=(p[h]??0)+E}for(let c of[\"values\",\"enumerators\"])for(let f of this[c].keys()){let p=n[c]=n[c]??{};p[f]=[...new Set([...p[f]??[],...this[c].get(f)??[]])]}this.shouldCommitTips&&(r.lastTips=this.nextTips,r.displayedTips=this.displayedTips),ce.mkdirSync(J.dirname(e),{recursive:!0}),ce.writeJsonSync(e,r)}startBuffer(){process.on(\"exit\",()=>{try{this.applyChanges()}catch{}})}}});var jv={};Vt(jv,{BuildDirectiveType:()=>UT,CACHE_CHECKPOINT:()=>TG,CACHE_VERSION:()=>MT,Cache:()=>Kr,Configuration:()=>ze,DEFAULT_RC_FILENAME:()=>hj,FormatType:()=>ope,InstallMode:()=>$l,LEGACY_PLUGINS:()=>ov,LOCKFILE_VERSION:()=>qT,LegacyMigrationResolver:()=>KI,LightReport:()=>lA,LinkType:()=>VE,LockfileResolver:()=>zI,Manifest:()=>Ut,MessageName:()=>Br,MultiFetcher:()=>aI,PackageExtensionStatus:()=>Y4,PackageExtensionType:()=>W4,PeerWarningType:()=>WT,Project:()=>Rt,Report:()=>Ao,ReportError:()=>jt,SettingsType:()=>wI,StreamReport:()=>Ot,TAG_REGEXP:()=>Mp,TelemetryManager:()=>XI,ThrowReport:()=>ki,VirtualFetcher:()=>lI,WindowsLinkType:()=>ER,Workspace:()=>ZI,WorkspaceFetcher:()=>cI,WorkspaceResolver:()=>Ei,YarnVersion:()=>fn,execUtils:()=>qr,folderUtils:()=>NQ,formatUtils:()=>he,hashUtils:()=>Nn,httpUtils:()=>ln,miscUtils:()=>je,nodeUtils:()=>fs,parseMessageName:()=>jx,reportOptionDeprecations:()=>SI,scriptUtils:()=>In,semverUtils:()=>Fr,stringifyMessageName:()=>Yf,structUtils:()=>G,tgzUtils:()=>ps,treeUtils:()=>xs});var Ge=Ze(()=>{gR();OQ();xc();I0();AR();bc();hR();Vj();Tp();Wo();$ge();ode();FG();av();av();cde();NG();ude();OG();oI();Gx();Q8();Ide();Rc();Ev();Cde();qG();T8();F8();tm();WG();yv();ule()});var Pde=_((OHt,qv)=>{\"use strict\";var gat=process.env.TERM_PROGRAM===\"Hyper\",dat=process.platform===\"win32\",vde=process.platform===\"linux\",zG={ballotDisabled:\"\\u2612\",ballotOff:\"\\u2610\",ballotOn:\"\\u2611\",bullet:\"\\u2022\",bulletWhite:\"\\u25E6\",fullBlock:\"\\u2588\",heart:\"\\u2764\",identicalTo:\"\\u2261\",line:\"\\u2500\",mark:\"\\u203B\",middot:\"\\xB7\",minus:\"\\uFF0D\",multiplication:\"\\xD7\",obelus:\"\\xF7\",pencilDownRight:\"\\u270E\",pencilRight:\"\\u270F\",pencilUpRight:\"\\u2710\",percent:\"%\",pilcrow2:\"\\u2761\",pilcrow:\"\\xB6\",plusMinus:\"\\xB1\",section:\"\\xA7\",starsOff:\"\\u2606\",starsOn:\"\\u2605\",upDownArrow:\"\\u2195\"},Sde=Object.assign({},zG,{check:\"\\u221A\",cross:\"\\xD7\",ellipsisLarge:\"...\",ellipsis:\"...\",info:\"i\",question:\"?\",questionSmall:\"?\",pointer:\">\",pointerSmall:\"\\xBB\",radioOff:\"( )\",radioOn:\"(*)\",warning:\"\\u203C\"}),Dde=Object.assign({},zG,{ballotCross:\"\\u2718\",check:\"\\u2714\",cross:\"\\u2716\",ellipsisLarge:\"\\u22EF\",ellipsis:\"\\u2026\",info:\"\\u2139\",question:\"?\",questionFull:\"\\uFF1F\",questionSmall:\"\\uFE56\",pointer:vde?\"\\u25B8\":\"\\u276F\",pointerSmall:vde?\"\\u2023\":\"\\u203A\",radioOff:\"\\u25EF\",radioOn:\"\\u25C9\",warning:\"\\u26A0\"});qv.exports=dat&&!gat?Sde:Dde;Reflect.defineProperty(qv.exports,\"common\",{enumerable:!1,value:zG});Reflect.defineProperty(qv.exports,\"windows\",{enumerable:!1,value:Sde});Reflect.defineProperty(qv.exports,\"other\",{enumerable:!1,value:Dde})});var Ju=_((LHt,ZG)=>{\"use strict\";var mat=t=>t!==null&&typeof t==\"object\"&&!Array.isArray(t),yat=/[\\u001b\\u009b][[\\]#;?()]*(?:(?:(?:[^\\W_]*;?[^\\W_]*)\\u0007)|(?:(?:[0-9]{1,4}(;[0-9]{0,4})*)?[~0-9=<>cf-nqrtyA-PRZ]))/g,bde=()=>{let t={enabled:!0,visible:!0,styles:{},keys:{}};\"FORCE_COLOR\"in process.env&&(t.enabled=process.env.FORCE_COLOR!==\"0\");let e=n=>{let c=n.open=`\\x1B[${n.codes[0]}m`,f=n.close=`\\x1B[${n.codes[1]}m`,p=n.regex=new RegExp(`\\\\u001b\\\\[${n.codes[1]}m`,\"g\");return n.wrap=(h,E)=>{h.includes(f)&&(h=h.replace(p,f+c));let C=c+h+f;return E?C.replace(/\\r*\\n/g,`${f}$&${c}`):C},n},r=(n,c,f)=>typeof n==\"function\"?n(c):n.wrap(c,f),s=(n,c)=>{if(n===\"\"||n==null)return\"\";if(t.enabled===!1)return n;if(t.visible===!1)return\"\";let f=\"\"+n,p=f.includes(`\n`),h=c.length;for(h>0&&c.includes(\"unstyle\")&&(c=[...new Set([\"unstyle\",...c])].reverse());h-- >0;)f=r(t.styles[c[h]],f,p);return f},a=(n,c,f)=>{t.styles[n]=e({name:n,codes:c}),(t.keys[f]||(t.keys[f]=[])).push(n),Reflect.defineProperty(t,n,{configurable:!0,enumerable:!0,set(h){t.alias(n,h)},get(){let h=E=>s(E,h.stack);return Reflect.setPrototypeOf(h,t),h.stack=this.stack?this.stack.concat(n):[n],h}})};return a(\"reset\",[0,0],\"modifier\"),a(\"bold\",[1,22],\"modifier\"),a(\"dim\",[2,22],\"modifier\"),a(\"italic\",[3,23],\"modifier\"),a(\"underline\",[4,24],\"modifier\"),a(\"inverse\",[7,27],\"modifier\"),a(\"hidden\",[8,28],\"modifier\"),a(\"strikethrough\",[9,29],\"modifier\"),a(\"black\",[30,39],\"color\"),a(\"red\",[31,39],\"color\"),a(\"green\",[32,39],\"color\"),a(\"yellow\",[33,39],\"color\"),a(\"blue\",[34,39],\"color\"),a(\"magenta\",[35,39],\"color\"),a(\"cyan\",[36,39],\"color\"),a(\"white\",[37,39],\"color\"),a(\"gray\",[90,39],\"color\"),a(\"grey\",[90,39],\"color\"),a(\"bgBlack\",[40,49],\"bg\"),a(\"bgRed\",[41,49],\"bg\"),a(\"bgGreen\",[42,49],\"bg\"),a(\"bgYellow\",[43,49],\"bg\"),a(\"bgBlue\",[44,49],\"bg\"),a(\"bgMagenta\",[45,49],\"bg\"),a(\"bgCyan\",[46,49],\"bg\"),a(\"bgWhite\",[47,49],\"bg\"),a(\"blackBright\",[90,39],\"bright\"),a(\"redBright\",[91,39],\"bright\"),a(\"greenBright\",[92,39],\"bright\"),a(\"yellowBright\",[93,39],\"bright\"),a(\"blueBright\",[94,39],\"bright\"),a(\"magentaBright\",[95,39],\"bright\"),a(\"cyanBright\",[96,39],\"bright\"),a(\"whiteBright\",[97,39],\"bright\"),a(\"bgBlackBright\",[100,49],\"bgBright\"),a(\"bgRedBright\",[101,49],\"bgBright\"),a(\"bgGreenBright\",[102,49],\"bgBright\"),a(\"bgYellowBright\",[103,49],\"bgBright\"),a(\"bgBlueBright\",[104,49],\"bgBright\"),a(\"bgMagentaBright\",[105,49],\"bgBright\"),a(\"bgCyanBright\",[106,49],\"bgBright\"),a(\"bgWhiteBright\",[107,49],\"bgBright\"),t.ansiRegex=yat,t.hasColor=t.hasAnsi=n=>(t.ansiRegex.lastIndex=0,typeof n==\"string\"&&n!==\"\"&&t.ansiRegex.test(n)),t.alias=(n,c)=>{let f=typeof c==\"string\"?t[c]:c;if(typeof f!=\"function\")throw new TypeError(\"Expected alias to be the name of an existing color (string) or a function\");f.stack||(Reflect.defineProperty(f,\"name\",{value:n}),t.styles[n]=f,f.stack=[n]),Reflect.defineProperty(t,n,{configurable:!0,enumerable:!0,set(p){t.alias(n,p)},get(){let p=h=>s(h,p.stack);return Reflect.setPrototypeOf(p,t),p.stack=this.stack?this.stack.concat(f.stack):f.stack,p}})},t.theme=n=>{if(!mat(n))throw new TypeError(\"Expected theme to be an object\");for(let c of Object.keys(n))t.alias(c,n[c]);return t},t.alias(\"unstyle\",n=>typeof n==\"string\"&&n!==\"\"?(t.ansiRegex.lastIndex=0,n.replace(t.ansiRegex,\"\")):\"\"),t.alias(\"noop\",n=>n),t.none=t.clear=t.noop,t.stripColor=t.unstyle,t.symbols=Pde(),t.define=a,t};ZG.exports=bde();ZG.exports.create=bde});var Xo=_(pn=>{\"use strict\";var Eat=Object.prototype.toString,jc=Ju(),xde=!1,XG=[],kde={yellow:\"blue\",cyan:\"red\",green:\"magenta\",black:\"white\",blue:\"yellow\",red:\"cyan\",magenta:\"green\",white:\"black\"};pn.longest=(t,e)=>t.reduce((r,s)=>Math.max(r,e?s[e].length:s.length),0);pn.hasColor=t=>!!t&&jc.hasColor(t);var VT=pn.isObject=t=>t!==null&&typeof t==\"object\"&&!Array.isArray(t);pn.nativeType=t=>Eat.call(t).slice(8,-1).toLowerCase().replace(/\\s/g,\"\");pn.isAsyncFn=t=>pn.nativeType(t)===\"asyncfunction\";pn.isPrimitive=t=>t!=null&&typeof t!=\"object\"&&typeof t!=\"function\";pn.resolve=(t,e,...r)=>typeof e==\"function\"?e.call(t,...r):e;pn.scrollDown=(t=[])=>[...t.slice(1),t[0]];pn.scrollUp=(t=[])=>[t.pop(),...t];pn.reorder=(t=[])=>{let e=t.slice();return e.sort((r,s)=>r.index>s.index?1:r.index<s.index?-1:0),e};pn.swap=(t,e,r)=>{let s=t.length,a=r===s?0:r<0?s-1:r,n=t[e];t[e]=t[a],t[a]=n};pn.width=(t,e=80)=>{let r=t&&t.columns?t.columns:e;return t&&typeof t.getWindowSize==\"function\"&&(r=t.getWindowSize()[0]),process.platform===\"win32\"?r-1:r};pn.height=(t,e=20)=>{let r=t&&t.rows?t.rows:e;return t&&typeof t.getWindowSize==\"function\"&&(r=t.getWindowSize()[1]),r};pn.wordWrap=(t,e={})=>{if(!t)return t;typeof e==\"number\"&&(e={width:e});let{indent:r=\"\",newline:s=`\n`+r,width:a=80}=e,n=(s+r).match(/[^\\S\\n]/g)||[];a-=n.length;let c=`.{1,${a}}([\\\\s\\\\u200B]+|$)|[^\\\\s\\\\u200B]+?([\\\\s\\\\u200B]+|$)`,f=t.trim(),p=new RegExp(c,\"g\"),h=f.match(p)||[];return h=h.map(E=>E.replace(/\\n$/,\"\")),e.padEnd&&(h=h.map(E=>E.padEnd(a,\" \"))),e.padStart&&(h=h.map(E=>E.padStart(a,\" \"))),r+h.join(s)};pn.unmute=t=>{let e=t.stack.find(s=>jc.keys.color.includes(s));return e?jc[e]:t.stack.find(s=>s.slice(2)===\"bg\")?jc[e.slice(2)]:s=>s};pn.pascal=t=>t?t[0].toUpperCase()+t.slice(1):\"\";pn.inverse=t=>{if(!t||!t.stack)return t;let e=t.stack.find(s=>jc.keys.color.includes(s));if(e){let s=jc[\"bg\"+pn.pascal(e)];return s?s.black:t}let r=t.stack.find(s=>s.slice(0,2)===\"bg\");return r?jc[r.slice(2).toLowerCase()]||t:jc.none};pn.complement=t=>{if(!t||!t.stack)return t;let e=t.stack.find(s=>jc.keys.color.includes(s)),r=t.stack.find(s=>s.slice(0,2)===\"bg\");if(e&&!r)return jc[kde[e]||e];if(r){let s=r.slice(2).toLowerCase(),a=kde[s];return a&&jc[\"bg\"+pn.pascal(a)]||t}return jc.none};pn.meridiem=t=>{let e=t.getHours(),r=t.getMinutes(),s=e>=12?\"pm\":\"am\";e=e%12;let a=e===0?12:e,n=r<10?\"0\"+r:r;return a+\":\"+n+\" \"+s};pn.set=(t={},e=\"\",r)=>e.split(\".\").reduce((s,a,n,c)=>{let f=c.length-1>n?s[a]||{}:r;return!pn.isObject(f)&&n<c.length-1&&(f={}),s[a]=f},t);pn.get=(t={},e=\"\",r)=>{let s=t[e]==null?e.split(\".\").reduce((a,n)=>a&&a[n],t):t[e];return s??r};pn.mixin=(t,e)=>{if(!VT(t))return e;if(!VT(e))return t;for(let r of Object.keys(e)){let s=Object.getOwnPropertyDescriptor(e,r);if(s.hasOwnProperty(\"value\"))if(t.hasOwnProperty(r)&&VT(s.value)){let a=Object.getOwnPropertyDescriptor(t,r);VT(a.value)?t[r]=pn.merge({},t[r],e[r]):Reflect.defineProperty(t,r,s)}else Reflect.defineProperty(t,r,s);else Reflect.defineProperty(t,r,s)}return t};pn.merge=(...t)=>{let e={};for(let r of t)pn.mixin(e,r);return e};pn.mixinEmitter=(t,e)=>{let r=e.constructor.prototype;for(let s of Object.keys(r)){let a=r[s];typeof a==\"function\"?pn.define(t,s,a.bind(e)):pn.define(t,s,a)}};pn.onExit=t=>{let e=(r,s)=>{xde||(xde=!0,XG.forEach(a=>a()),r===!0&&process.exit(128+s))};XG.length===0&&(process.once(\"SIGTERM\",e.bind(null,!0,15)),process.once(\"SIGINT\",e.bind(null,!0,2)),process.once(\"exit\",e)),XG.push(t)};pn.define=(t,e,r)=>{Reflect.defineProperty(t,e,{value:r})};pn.defineExport=(t,e,r)=>{let s;Reflect.defineProperty(t,e,{enumerable:!0,configurable:!0,set(a){s=a},get(){return s?s():r()}})}});var Qde=_(rC=>{\"use strict\";rC.ctrl={a:\"first\",b:\"backward\",c:\"cancel\",d:\"deleteForward\",e:\"last\",f:\"forward\",g:\"reset\",i:\"tab\",k:\"cutForward\",l:\"reset\",n:\"newItem\",m:\"cancel\",j:\"submit\",p:\"search\",r:\"remove\",s:\"save\",u:\"undo\",w:\"cutLeft\",x:\"toggleCursor\",v:\"paste\"};rC.shift={up:\"shiftUp\",down:\"shiftDown\",left:\"shiftLeft\",right:\"shiftRight\",tab:\"prev\"};rC.fn={up:\"pageUp\",down:\"pageDown\",left:\"pageLeft\",right:\"pageRight\",delete:\"deleteForward\"};rC.option={b:\"backward\",f:\"forward\",d:\"cutRight\",left:\"cutLeft\",up:\"altUp\",down:\"altDown\"};rC.keys={pageup:\"pageUp\",pagedown:\"pageDown\",home:\"home\",end:\"end\",cancel:\"cancel\",delete:\"deleteForward\",backspace:\"delete\",down:\"down\",enter:\"submit\",escape:\"cancel\",left:\"left\",space:\"space\",number:\"number\",return:\"submit\",right:\"right\",tab:\"next\",up:\"up\"}});var Fde=_((_Ht,Tde)=>{\"use strict\";var Rde=Ie(\"readline\"),Iat=Qde(),Cat=/^(?:\\x1b)([a-zA-Z0-9])$/,wat=/^(?:\\x1b+)(O|N|\\[|\\[\\[)(?:(\\d+)(?:;(\\d+))?([~^$])|(?:1;)?(\\d+)?([a-zA-Z]))/,Bat={OP:\"f1\",OQ:\"f2\",OR:\"f3\",OS:\"f4\",\"[11~\":\"f1\",\"[12~\":\"f2\",\"[13~\":\"f3\",\"[14~\":\"f4\",\"[[A\":\"f1\",\"[[B\":\"f2\",\"[[C\":\"f3\",\"[[D\":\"f4\",\"[[E\":\"f5\",\"[15~\":\"f5\",\"[17~\":\"f6\",\"[18~\":\"f7\",\"[19~\":\"f8\",\"[20~\":\"f9\",\"[21~\":\"f10\",\"[23~\":\"f11\",\"[24~\":\"f12\",\"[A\":\"up\",\"[B\":\"down\",\"[C\":\"right\",\"[D\":\"left\",\"[E\":\"clear\",\"[F\":\"end\",\"[H\":\"home\",OA:\"up\",OB:\"down\",OC:\"right\",OD:\"left\",OE:\"clear\",OF:\"end\",OH:\"home\",\"[1~\":\"home\",\"[2~\":\"insert\",\"[3~\":\"delete\",\"[4~\":\"end\",\"[5~\":\"pageup\",\"[6~\":\"pagedown\",\"[[5~\":\"pageup\",\"[[6~\":\"pagedown\",\"[7~\":\"home\",\"[8~\":\"end\",\"[a\":\"up\",\"[b\":\"down\",\"[c\":\"right\",\"[d\":\"left\",\"[e\":\"clear\",\"[2$\":\"insert\",\"[3$\":\"delete\",\"[5$\":\"pageup\",\"[6$\":\"pagedown\",\"[7$\":\"home\",\"[8$\":\"end\",Oa:\"up\",Ob:\"down\",Oc:\"right\",Od:\"left\",Oe:\"clear\",\"[2^\":\"insert\",\"[3^\":\"delete\",\"[5^\":\"pageup\",\"[6^\":\"pagedown\",\"[7^\":\"home\",\"[8^\":\"end\",\"[Z\":\"tab\"};function vat(t){return[\"[a\",\"[b\",\"[c\",\"[d\",\"[e\",\"[2$\",\"[3$\",\"[5$\",\"[6$\",\"[7$\",\"[8$\",\"[Z\"].includes(t)}function Sat(t){return[\"Oa\",\"Ob\",\"Oc\",\"Od\",\"Oe\",\"[2^\",\"[3^\",\"[5^\",\"[6^\",\"[7^\",\"[8^\"].includes(t)}var JT=(t=\"\",e={})=>{let r,s={name:e.name,ctrl:!1,meta:!1,shift:!1,option:!1,sequence:t,raw:t,...e};if(Buffer.isBuffer(t)?t[0]>127&&t[1]===void 0?(t[0]-=128,t=\"\\x1B\"+String(t)):t=String(t):t!==void 0&&typeof t!=\"string\"?t=String(t):t||(t=s.sequence||\"\"),s.sequence=s.sequence||t||s.name,t===\"\\r\")s.raw=void 0,s.name=\"return\";else if(t===`\n`)s.name=\"enter\";else if(t===\"\t\")s.name=\"tab\";else if(t===\"\\b\"||t===\"\\x7F\"||t===\"\\x1B\\x7F\"||t===\"\\x1B\\b\")s.name=\"backspace\",s.meta=t.charAt(0)===\"\\x1B\";else if(t===\"\\x1B\"||t===\"\\x1B\\x1B\")s.name=\"escape\",s.meta=t.length===2;else if(t===\" \"||t===\"\\x1B \")s.name=\"space\",s.meta=t.length===2;else if(t<=\"\u001a\")s.name=String.fromCharCode(t.charCodeAt(0)+97-1),s.ctrl=!0;else if(t.length===1&&t>=\"0\"&&t<=\"9\")s.name=\"number\";else if(t.length===1&&t>=\"a\"&&t<=\"z\")s.name=t;else if(t.length===1&&t>=\"A\"&&t<=\"Z\")s.name=t.toLowerCase(),s.shift=!0;else if(r=Cat.exec(t))s.meta=!0,s.shift=/^[A-Z]$/.test(r[1]);else if(r=wat.exec(t)){let a=[...t];a[0]===\"\\x1B\"&&a[1]===\"\\x1B\"&&(s.option=!0);let n=[r[1],r[2],r[4],r[6]].filter(Boolean).join(\"\"),c=(r[3]||r[5]||1)-1;s.ctrl=!!(c&4),s.meta=!!(c&10),s.shift=!!(c&1),s.code=n,s.name=Bat[n],s.shift=vat(n)||s.shift,s.ctrl=Sat(n)||s.ctrl}return s};JT.listen=(t={},e)=>{let{stdin:r}=t;if(!r||r!==process.stdin&&!r.isTTY)throw new Error(\"Invalid stream passed\");let s=Rde.createInterface({terminal:!0,input:r});Rde.emitKeypressEvents(r,s);let a=(f,p)=>e(f,JT(f,p),s),n=r.isRaw;return r.isTTY&&r.setRawMode(!0),r.on(\"keypress\",a),s.resume(),()=>{r.isTTY&&r.setRawMode(n),r.removeListener(\"keypress\",a),s.pause(),s.close()}};JT.action=(t,e,r)=>{let s={...Iat,...r};return e.ctrl?(e.action=s.ctrl[e.name],e):e.option&&s.option?(e.action=s.option[e.name],e):e.shift?(e.action=s.shift[e.name],e):(e.action=s.keys[e.name],e)};Tde.exports=JT});var Ode=_((HHt,Nde)=>{\"use strict\";Nde.exports=t=>{t.timers=t.timers||{};let e=t.options.timers;if(e)for(let r of Object.keys(e)){let s=e[r];typeof s==\"number\"&&(s={interval:s}),Dat(t,r,s)}};function Dat(t,e,r={}){let s=t.timers[e]={name:e,start:Date.now(),ms:0,tick:0},a=r.interval||120;s.frames=r.frames||[],s.loading=!0;let n=setInterval(()=>{s.ms=Date.now()-s.start,s.tick++,t.render()},a);return s.stop=()=>{s.loading=!1,clearInterval(n)},Reflect.defineProperty(s,\"interval\",{value:n}),t.once(\"close\",()=>s.stop()),s.stop}});var Mde=_((jHt,Lde)=>{\"use strict\";var{define:Pat,width:bat}=Xo(),$G=class{constructor(e){let r=e.options;Pat(this,\"_prompt\",e),this.type=e.type,this.name=e.name,this.message=\"\",this.header=\"\",this.footer=\"\",this.error=\"\",this.hint=\"\",this.input=\"\",this.cursor=0,this.index=0,this.lines=0,this.tick=0,this.prompt=\"\",this.buffer=\"\",this.width=bat(r.stdout||process.stdout),Object.assign(this,r),this.name=this.name||this.message,this.message=this.message||this.name,this.symbols=e.symbols,this.styles=e.styles,this.required=new Set,this.cancelled=!1,this.submitted=!1}clone(){let e={...this};return e.status=this.status,e.buffer=Buffer.from(e.buffer),delete e.clone,e}set color(e){this._color=e}get color(){let e=this.prompt.styles;if(this.cancelled)return e.cancelled;if(this.submitted)return e.submitted;let r=this._color||e[this.status];return typeof r==\"function\"?r:e.pending}set loading(e){this._loading=e}get loading(){return typeof this._loading==\"boolean\"?this._loading:this.loadingChoices?\"choices\":!1}get status(){return this.cancelled?\"cancelled\":this.submitted?\"submitted\":\"pending\"}};Lde.exports=$G});var _de=_((GHt,Ude)=>{\"use strict\";var eq=Xo(),ho=Ju(),tq={default:ho.noop,noop:ho.noop,set inverse(t){this._inverse=t},get inverse(){return this._inverse||eq.inverse(this.primary)},set complement(t){this._complement=t},get complement(){return this._complement||eq.complement(this.primary)},primary:ho.cyan,success:ho.green,danger:ho.magenta,strong:ho.bold,warning:ho.yellow,muted:ho.dim,disabled:ho.gray,dark:ho.dim.gray,underline:ho.underline,set info(t){this._info=t},get info(){return this._info||this.primary},set em(t){this._em=t},get em(){return this._em||this.primary.underline},set heading(t){this._heading=t},get heading(){return this._heading||this.muted.underline},set pending(t){this._pending=t},get pending(){return this._pending||this.primary},set submitted(t){this._submitted=t},get submitted(){return this._submitted||this.success},set cancelled(t){this._cancelled=t},get cancelled(){return this._cancelled||this.danger},set typing(t){this._typing=t},get typing(){return this._typing||this.dim},set placeholder(t){this._placeholder=t},get placeholder(){return this._placeholder||this.primary.dim},set highlight(t){this._highlight=t},get highlight(){return this._highlight||this.inverse}};tq.merge=(t={})=>{t.styles&&typeof t.styles.enabled==\"boolean\"&&(ho.enabled=t.styles.enabled),t.styles&&typeof t.styles.visible==\"boolean\"&&(ho.visible=t.styles.visible);let e=eq.merge({},tq,t.styles);delete e.merge;for(let r of Object.keys(ho))e.hasOwnProperty(r)||Reflect.defineProperty(e,r,{get:()=>ho[r]});for(let r of Object.keys(ho.styles))e.hasOwnProperty(r)||Reflect.defineProperty(e,r,{get:()=>ho[r]});return e};Ude.exports=tq});var jde=_((qHt,Hde)=>{\"use strict\";var rq=process.platform===\"win32\",zp=Ju(),xat=Xo(),nq={...zp.symbols,upDownDoubleArrow:\"\\u21D5\",upDownDoubleArrow2:\"\\u2B0D\",upDownArrow:\"\\u2195\",asterisk:\"*\",asterism:\"\\u2042\",bulletWhite:\"\\u25E6\",electricArrow:\"\\u2301\",ellipsisLarge:\"\\u22EF\",ellipsisSmall:\"\\u2026\",fullBlock:\"\\u2588\",identicalTo:\"\\u2261\",indicator:zp.symbols.check,leftAngle:\"\\u2039\",mark:\"\\u203B\",minus:\"\\u2212\",multiplication:\"\\xD7\",obelus:\"\\xF7\",percent:\"%\",pilcrow:\"\\xB6\",pilcrow2:\"\\u2761\",pencilUpRight:\"\\u2710\",pencilDownRight:\"\\u270E\",pencilRight:\"\\u270F\",plus:\"+\",plusMinus:\"\\xB1\",pointRight:\"\\u261E\",rightAngle:\"\\u203A\",section:\"\\xA7\",hexagon:{off:\"\\u2B21\",on:\"\\u2B22\",disabled:\"\\u2B22\"},ballot:{on:\"\\u2611\",off:\"\\u2610\",disabled:\"\\u2612\"},stars:{on:\"\\u2605\",off:\"\\u2606\",disabled:\"\\u2606\"},folder:{on:\"\\u25BC\",off:\"\\u25B6\",disabled:\"\\u25B6\"},prefix:{pending:zp.symbols.question,submitted:zp.symbols.check,cancelled:zp.symbols.cross},separator:{pending:zp.symbols.pointerSmall,submitted:zp.symbols.middot,cancelled:zp.symbols.middot},radio:{off:rq?\"( )\":\"\\u25EF\",on:rq?\"(*)\":\"\\u25C9\",disabled:rq?\"(|)\":\"\\u24BE\"},numbers:[\"\\u24EA\",\"\\u2460\",\"\\u2461\",\"\\u2462\",\"\\u2463\",\"\\u2464\",\"\\u2465\",\"\\u2466\",\"\\u2467\",\"\\u2468\",\"\\u2469\",\"\\u246A\",\"\\u246B\",\"\\u246C\",\"\\u246D\",\"\\u246E\",\"\\u246F\",\"\\u2470\",\"\\u2471\",\"\\u2472\",\"\\u2473\",\"\\u3251\",\"\\u3252\",\"\\u3253\",\"\\u3254\",\"\\u3255\",\"\\u3256\",\"\\u3257\",\"\\u3258\",\"\\u3259\",\"\\u325A\",\"\\u325B\",\"\\u325C\",\"\\u325D\",\"\\u325E\",\"\\u325F\",\"\\u32B1\",\"\\u32B2\",\"\\u32B3\",\"\\u32B4\",\"\\u32B5\",\"\\u32B6\",\"\\u32B7\",\"\\u32B8\",\"\\u32B9\",\"\\u32BA\",\"\\u32BB\",\"\\u32BC\",\"\\u32BD\",\"\\u32BE\",\"\\u32BF\"]};nq.merge=t=>{let e=xat.merge({},zp.symbols,nq,t.symbols);return delete e.merge,e};Hde.exports=nq});var qde=_((WHt,Gde)=>{\"use strict\";var kat=_de(),Qat=jde(),Rat=Xo();Gde.exports=t=>{t.options=Rat.merge({},t.options.theme,t.options),t.symbols=Qat.merge(t.options),t.styles=kat.merge(t.options)}});var Kde=_((Vde,Jde)=>{\"use strict\";var Wde=process.env.TERM_PROGRAM===\"Apple_Terminal\",Tat=Ju(),iq=Xo(),Ku=Jde.exports=Vde,Ui=\"\\x1B[\",Yde=\"\\x07\",sq=!1,j0=Ku.code={bell:Yde,beep:Yde,beginning:`${Ui}G`,down:`${Ui}J`,esc:Ui,getPosition:`${Ui}6n`,hide:`${Ui}?25l`,line:`${Ui}2K`,lineEnd:`${Ui}K`,lineStart:`${Ui}1K`,restorePosition:Ui+(Wde?\"8\":\"u\"),savePosition:Ui+(Wde?\"7\":\"s\"),screen:`${Ui}2J`,show:`${Ui}?25h`,up:`${Ui}1J`},wm=Ku.cursor={get hidden(){return sq},hide(){return sq=!0,j0.hide},show(){return sq=!1,j0.show},forward:(t=1)=>`${Ui}${t}C`,backward:(t=1)=>`${Ui}${t}D`,nextLine:(t=1)=>`${Ui}E`.repeat(t),prevLine:(t=1)=>`${Ui}F`.repeat(t),up:(t=1)=>t?`${Ui}${t}A`:\"\",down:(t=1)=>t?`${Ui}${t}B`:\"\",right:(t=1)=>t?`${Ui}${t}C`:\"\",left:(t=1)=>t?`${Ui}${t}D`:\"\",to(t,e){return e?`${Ui}${e+1};${t+1}H`:`${Ui}${t+1}G`},move(t=0,e=0){let r=\"\";return r+=t<0?wm.left(-t):t>0?wm.right(t):\"\",r+=e<0?wm.up(-e):e>0?wm.down(e):\"\",r},restore(t={}){let{after:e,cursor:r,initial:s,input:a,prompt:n,size:c,value:f}=t;if(s=iq.isPrimitive(s)?String(s):\"\",a=iq.isPrimitive(a)?String(a):\"\",f=iq.isPrimitive(f)?String(f):\"\",c){let p=Ku.cursor.up(c)+Ku.cursor.to(n.length),h=a.length-r;return h>0&&(p+=Ku.cursor.left(h)),p}if(f||e){let p=!a&&s?-s.length:-a.length+r;return e&&(p-=e.length),a===\"\"&&s&&!n.includes(s)&&(p+=s.length),Ku.cursor.move(p)}}},oq=Ku.erase={screen:j0.screen,up:j0.up,down:j0.down,line:j0.line,lineEnd:j0.lineEnd,lineStart:j0.lineStart,lines(t){let e=\"\";for(let r=0;r<t;r++)e+=Ku.erase.line+(r<t-1?Ku.cursor.up(1):\"\");return t&&(e+=Ku.code.beginning),e}};Ku.clear=(t=\"\",e=process.stdout.columns)=>{if(!e)return oq.line+wm.to(0);let r=n=>[...Tat.unstyle(n)].length,s=t.split(/\\r?\\n/),a=0;for(let n of s)a+=1+Math.floor(Math.max(r(n)-1,0)/e);return(oq.line+wm.prevLine()).repeat(a-1)+oq.line+wm.to(0)}});var nC=_((YHt,Zde)=>{\"use strict\";var Fat=Ie(\"events\"),zde=Ju(),aq=Fde(),Nat=Ode(),Oat=Mde(),Lat=qde(),pl=Xo(),Bm=Kde(),lq=class t extends Fat{constructor(e={}){super(),this.name=e.name,this.type=e.type,this.options=e,Lat(this),Nat(this),this.state=new Oat(this),this.initial=[e.initial,e.default].find(r=>r!=null),this.stdout=e.stdout||process.stdout,this.stdin=e.stdin||process.stdin,this.scale=e.scale||1,this.term=this.options.term||process.env.TERM_PROGRAM,this.margin=Uat(this.options.margin),this.setMaxListeners(0),Mat(this)}async keypress(e,r={}){this.keypressed=!0;let s=aq.action(e,aq(e,r),this.options.actions);this.state.keypress=s,this.emit(\"keypress\",e,s),this.emit(\"state\",this.state.clone());let a=this.options[s.action]||this[s.action]||this.dispatch;if(typeof a==\"function\")return await a.call(this,e,s);this.alert()}alert(){delete this.state.alert,this.options.show===!1?this.emit(\"alert\"):this.stdout.write(Bm.code.beep)}cursorHide(){this.stdout.write(Bm.cursor.hide()),pl.onExit(()=>this.cursorShow())}cursorShow(){this.stdout.write(Bm.cursor.show())}write(e){e&&(this.stdout&&this.state.show!==!1&&this.stdout.write(e),this.state.buffer+=e)}clear(e=0){let r=this.state.buffer;this.state.buffer=\"\",!(!r&&!e||this.options.show===!1)&&this.stdout.write(Bm.cursor.down(e)+Bm.clear(r,this.width))}restore(){if(this.state.closed||this.options.show===!1)return;let{prompt:e,after:r,rest:s}=this.sections(),{cursor:a,initial:n=\"\",input:c=\"\",value:f=\"\"}=this,p=this.state.size=s.length,h={after:r,cursor:a,initial:n,input:c,prompt:e,size:p,value:f},E=Bm.cursor.restore(h);E&&this.stdout.write(E)}sections(){let{buffer:e,input:r,prompt:s}=this.state;s=zde.unstyle(s);let a=zde.unstyle(e),n=a.indexOf(s),c=a.slice(0,n),p=a.slice(n).split(`\n`),h=p[0],E=p[p.length-1],S=(s+(r?\" \"+r:\"\")).length,b=S<h.length?h.slice(S+1):\"\";return{header:c,prompt:h,after:b,rest:p.slice(1),last:E}}async submit(){this.state.submitted=!0,this.state.validating=!0,this.options.onSubmit&&await this.options.onSubmit.call(this,this.name,this.value,this);let e=this.state.error||await this.validate(this.value,this.state);if(e!==!0){let r=`\n`+this.symbols.pointer+\" \";typeof e==\"string\"?r+=e.trim():r+=\"Invalid input\",this.state.error=`\n`+this.styles.danger(r),this.state.submitted=!1,await this.render(),await this.alert(),this.state.validating=!1,this.state.error=void 0;return}this.state.validating=!1,await this.render(),await this.close(),this.value=await this.result(this.value),this.emit(\"submit\",this.value)}async cancel(e){this.state.cancelled=this.state.submitted=!0,await this.render(),await this.close(),typeof this.options.onCancel==\"function\"&&await this.options.onCancel.call(this,this.name,this.value,this),this.emit(\"cancel\",await this.error(e))}async close(){this.state.closed=!0;try{let e=this.sections(),r=Math.ceil(e.prompt.length/this.width);e.rest&&this.write(Bm.cursor.down(e.rest.length)),this.write(`\n`.repeat(r))}catch{}this.emit(\"close\")}start(){!this.stop&&this.options.show!==!1&&(this.stop=aq.listen(this,this.keypress.bind(this)),this.once(\"close\",this.stop))}async skip(){return this.skipped=this.options.skip===!0,typeof this.options.skip==\"function\"&&(this.skipped=await this.options.skip.call(this,this.name,this.value)),this.skipped}async initialize(){let{format:e,options:r,result:s}=this;if(this.format=()=>e.call(this,this.value),this.result=()=>s.call(this,this.value),typeof r.initial==\"function\"&&(this.initial=await r.initial.call(this,this)),typeof r.onRun==\"function\"&&await r.onRun.call(this,this),typeof r.onSubmit==\"function\"){let a=r.onSubmit.bind(this),n=this.submit.bind(this);delete this.options.onSubmit,this.submit=async()=>(await a(this.name,this.value,this),n())}await this.start(),await this.render()}render(){throw new Error(\"expected prompt to have a custom render method\")}run(){return new Promise(async(e,r)=>{if(this.once(\"submit\",e),this.once(\"cancel\",r),await this.skip())return this.render=()=>{},this.submit();await this.initialize(),this.emit(\"run\")})}async element(e,r,s){let{options:a,state:n,symbols:c,timers:f}=this,p=f&&f[e];n.timer=p;let h=a[e]||n[e]||c[e],E=r&&r[e]!=null?r[e]:await h;if(E===\"\")return E;let C=await this.resolve(E,n,r,s);return!C&&r&&r[e]?this.resolve(h,n,r,s):C}async prefix(){let e=await this.element(\"prefix\")||this.symbols,r=this.timers&&this.timers.prefix,s=this.state;return s.timer=r,pl.isObject(e)&&(e=e[s.status]||e.pending),pl.hasColor(e)?e:(this.styles[s.status]||this.styles.pending)(e)}async message(){let e=await this.element(\"message\");return pl.hasColor(e)?e:this.styles.strong(e)}async separator(){let e=await this.element(\"separator\")||this.symbols,r=this.timers&&this.timers.separator,s=this.state;s.timer=r;let a=e[s.status]||e.pending||s.separator,n=await this.resolve(a,s);return pl.isObject(n)&&(n=n[s.status]||n.pending),pl.hasColor(n)?n:this.styles.muted(n)}async pointer(e,r){let s=await this.element(\"pointer\",e,r);if(typeof s==\"string\"&&pl.hasColor(s))return s;if(s){let a=this.styles,n=this.index===r,c=n?a.primary:h=>h,f=await this.resolve(s[n?\"on\":\"off\"]||s,this.state),p=pl.hasColor(f)?f:c(f);return n?p:\" \".repeat(f.length)}}async indicator(e,r){let s=await this.element(\"indicator\",e,r);if(typeof s==\"string\"&&pl.hasColor(s))return s;if(s){let a=this.styles,n=e.enabled===!0,c=n?a.success:a.dark,f=s[n?\"on\":\"off\"]||s;return pl.hasColor(f)?f:c(f)}return\"\"}body(){return null}footer(){if(this.state.status===\"pending\")return this.element(\"footer\")}header(){if(this.state.status===\"pending\")return this.element(\"header\")}async hint(){if(this.state.status===\"pending\"&&!this.isValue(this.state.input)){let e=await this.element(\"hint\");return pl.hasColor(e)?e:this.styles.muted(e)}}error(e){return this.state.submitted?\"\":e||this.state.error}format(e){return e}result(e){return e}validate(e){return this.options.required===!0?this.isValue(e):!0}isValue(e){return e!=null&&e!==\"\"}resolve(e,...r){return pl.resolve(this,e,...r)}get base(){return t.prototype}get style(){return this.styles[this.state.status]}get height(){return this.options.rows||pl.height(this.stdout,25)}get width(){return this.options.columns||pl.width(this.stdout,80)}get size(){return{width:this.width,height:this.height}}set cursor(e){this.state.cursor=e}get cursor(){return this.state.cursor}set input(e){this.state.input=e}get input(){return this.state.input}set value(e){this.state.value=e}get value(){let{input:e,value:r}=this.state,s=[r,e].find(this.isValue.bind(this));return this.isValue(s)?s:this.initial}static get prompt(){return e=>new this(e).run()}};function Mat(t){let e=a=>t[a]===void 0||typeof t[a]==\"function\",r=[\"actions\",\"choices\",\"initial\",\"margin\",\"roles\",\"styles\",\"symbols\",\"theme\",\"timers\",\"value\"],s=[\"body\",\"footer\",\"error\",\"header\",\"hint\",\"indicator\",\"message\",\"prefix\",\"separator\",\"skip\"];for(let a of Object.keys(t.options)){if(r.includes(a)||/^on[A-Z]/.test(a))continue;let n=t.options[a];typeof n==\"function\"&&e(a)?s.includes(a)||(t[a]=n.bind(t)):typeof t[a]!=\"function\"&&(t[a]=n)}}function Uat(t){typeof t==\"number\"&&(t=[t,t,t,t]);let e=[].concat(t||[]),r=a=>a%2===0?`\n`:\" \",s=[];for(let a=0;a<4;a++){let n=r(a);e[a]?s.push(n.repeat(e[a])):s.push(\"\")}return s}Zde.exports=lq});var eme=_((VHt,$de)=>{\"use strict\";var _at=Xo(),Xde={default(t,e){return e},checkbox(t,e){throw new Error(\"checkbox role is not implemented yet\")},editable(t,e){throw new Error(\"editable role is not implemented yet\")},expandable(t,e){throw new Error(\"expandable role is not implemented yet\")},heading(t,e){return e.disabled=\"\",e.indicator=[e.indicator,\" \"].find(r=>r!=null),e.message=e.message||\"\",e},input(t,e){throw new Error(\"input role is not implemented yet\")},option(t,e){return Xde.default(t,e)},radio(t,e){throw new Error(\"radio role is not implemented yet\")},separator(t,e){return e.disabled=\"\",e.indicator=[e.indicator,\" \"].find(r=>r!=null),e.message=e.message||t.symbols.line.repeat(5),e},spacer(t,e){return e}};$de.exports=(t,e={})=>{let r=_at.merge({},Xde,e.roles);return r[t]||r.default}});var Wv=_((JHt,nme)=>{\"use strict\";var Hat=Ju(),jat=nC(),Gat=eme(),KT=Xo(),{reorder:cq,scrollUp:qat,scrollDown:Wat,isObject:tme,swap:Yat}=KT,uq=class extends jat{constructor(e){super(e),this.cursorHide(),this.maxSelected=e.maxSelected||1/0,this.multiple=e.multiple||!1,this.initial=e.initial||0,this.delay=e.delay||0,this.longest=0,this.num=\"\"}async initialize(){typeof this.options.initial==\"function\"&&(this.initial=await this.options.initial.call(this)),await this.reset(!0),await super.initialize()}async reset(){let{choices:e,initial:r,autofocus:s,suggest:a}=this.options;if(this.state._choices=[],this.state.choices=[],this.choices=await Promise.all(await this.toChoices(e)),this.choices.forEach(n=>n.enabled=!1),typeof a!=\"function\"&&this.selectable.length===0)throw new Error(\"At least one choice must be selectable\");tme(r)&&(r=Object.keys(r)),Array.isArray(r)?(s!=null&&(this.index=this.findIndex(s)),r.forEach(n=>this.enable(this.find(n))),await this.render()):(s!=null&&(r=s),typeof r==\"string\"&&(r=this.findIndex(r)),typeof r==\"number\"&&r>-1&&(this.index=Math.max(0,Math.min(r,this.choices.length)),this.enable(this.find(this.index)))),this.isDisabled(this.focused)&&await this.down()}async toChoices(e,r){this.state.loadingChoices=!0;let s=[],a=0,n=async(c,f)=>{typeof c==\"function\"&&(c=await c.call(this)),c instanceof Promise&&(c=await c);for(let p=0;p<c.length;p++){let h=c[p]=await this.toChoice(c[p],a++,f);s.push(h),h.choices&&await n(h.choices,h)}return s};return n(e,r).then(c=>(this.state.loadingChoices=!1,c))}async toChoice(e,r,s){if(typeof e==\"function\"&&(e=await e.call(this,this)),e instanceof Promise&&(e=await e),typeof e==\"string\"&&(e={name:e}),e.normalized)return e;e.normalized=!0;let a=e.value;if(e=Gat(e.role,this.options)(this,e),typeof e.disabled==\"string\"&&!e.hint&&(e.hint=e.disabled,e.disabled=!0),e.disabled===!0&&e.hint==null&&(e.hint=\"(disabled)\"),e.index!=null)return e;e.name=e.name||e.key||e.title||e.value||e.message,e.message=e.message||e.name||\"\",e.value=[e.value,e.name].find(this.isValue.bind(this)),e.input=\"\",e.index=r,e.cursor=0,KT.define(e,\"parent\",s),e.level=s?s.level+1:1,e.indent==null&&(e.indent=s?s.indent+\"  \":e.indent||\"\"),e.path=s?s.path+\".\"+e.name:e.name,e.enabled=!!(this.multiple&&!this.isDisabled(e)&&(e.enabled||this.isSelected(e))),this.isDisabled(e)||(this.longest=Math.max(this.longest,Hat.unstyle(e.message).length));let c={...e};return e.reset=(f=c.input,p=c.value)=>{for(let h of Object.keys(c))e[h]=c[h];e.input=f,e.value=p},a==null&&typeof e.initial==\"function\"&&(e.input=await e.initial.call(this,this.state,e,r)),e}async onChoice(e,r){this.emit(\"choice\",e,r,this),typeof e.onChoice==\"function\"&&await e.onChoice.call(this,this.state,e,r)}async addChoice(e,r,s){let a=await this.toChoice(e,r,s);return this.choices.push(a),this.index=this.choices.length-1,this.limit=this.choices.length,a}async newItem(e,r,s){let a={name:\"New choice name?\",editable:!0,newChoice:!0,...e},n=await this.addChoice(a,r,s);return n.updateChoice=()=>{delete n.newChoice,n.name=n.message=n.input,n.input=\"\",n.cursor=0},this.render()}indent(e){return e.indent==null?e.level>1?\"  \".repeat(e.level-1):\"\":e.indent}dispatch(e,r){if(this.multiple&&this[r.name])return this[r.name]();this.alert()}focus(e,r){return typeof r!=\"boolean\"&&(r=e.enabled),r&&!e.enabled&&this.selected.length>=this.maxSelected?this.alert():(this.index=e.index,e.enabled=r&&!this.isDisabled(e),e)}space(){return this.multiple?(this.toggle(this.focused),this.render()):this.alert()}a(){if(this.maxSelected<this.choices.length)return this.alert();let e=this.selectable.every(r=>r.enabled);return this.choices.forEach(r=>r.enabled=!e),this.render()}i(){return this.choices.length-this.selected.length>this.maxSelected?this.alert():(this.choices.forEach(e=>e.enabled=!e.enabled),this.render())}g(e=this.focused){return this.choices.some(r=>!!r.parent)?(this.toggle(e.parent&&!e.choices?e.parent:e),this.render()):this.a()}toggle(e,r){if(!e.enabled&&this.selected.length>=this.maxSelected)return this.alert();typeof r!=\"boolean\"&&(r=!e.enabled),e.enabled=r,e.choices&&e.choices.forEach(a=>this.toggle(a,r));let s=e.parent;for(;s;){let a=s.choices.filter(n=>this.isDisabled(n));s.enabled=a.every(n=>n.enabled===!0),s=s.parent}return rme(this,this.choices),this.emit(\"toggle\",e,this),e}enable(e){return this.selected.length>=this.maxSelected?this.alert():(e.enabled=!this.isDisabled(e),e.choices&&e.choices.forEach(this.enable.bind(this)),e)}disable(e){return e.enabled=!1,e.choices&&e.choices.forEach(this.disable.bind(this)),e}number(e){this.num+=e;let r=s=>{let a=Number(s);if(a>this.choices.length-1)return this.alert();let n=this.focused,c=this.choices.find(f=>a===f.index);if(!c.enabled&&this.selected.length>=this.maxSelected)return this.alert();if(this.visible.indexOf(c)===-1){let f=cq(this.choices),p=f.indexOf(c);if(n.index>p){let h=f.slice(p,p+this.limit),E=f.filter(C=>!h.includes(C));this.choices=h.concat(E)}else{let h=p-this.limit+1;this.choices=f.slice(h).concat(f.slice(0,h))}}return this.index=this.choices.indexOf(c),this.toggle(this.focused),this.render()};return clearTimeout(this.numberTimeout),new Promise(s=>{let a=this.choices.length,n=this.num,c=(f=!1,p)=>{clearTimeout(this.numberTimeout),f&&(p=r(n)),this.num=\"\",s(p)};if(n===\"0\"||n.length===1&&+(n+\"0\")>a)return c(!0);if(Number(n)>a)return c(!1,this.alert());this.numberTimeout=setTimeout(()=>c(!0),this.delay)})}home(){return this.choices=cq(this.choices),this.index=0,this.render()}end(){let e=this.choices.length-this.limit,r=cq(this.choices);return this.choices=r.slice(e).concat(r.slice(0,e)),this.index=this.limit-1,this.render()}first(){return this.index=0,this.render()}last(){return this.index=this.visible.length-1,this.render()}prev(){return this.visible.length<=1?this.alert():this.up()}next(){return this.visible.length<=1?this.alert():this.down()}right(){return this.cursor>=this.input.length?this.alert():(this.cursor++,this.render())}left(){return this.cursor<=0?this.alert():(this.cursor--,this.render())}up(){let e=this.choices.length,r=this.visible.length,s=this.index;return this.options.scroll===!1&&s===0?this.alert():e>r&&s===0?this.scrollUp():(this.index=(s-1%e+e)%e,this.isDisabled()?this.up():this.render())}down(){let e=this.choices.length,r=this.visible.length,s=this.index;return this.options.scroll===!1&&s===r-1?this.alert():e>r&&s===r-1?this.scrollDown():(this.index=(s+1)%e,this.isDisabled()?this.down():this.render())}scrollUp(e=0){return this.choices=qat(this.choices),this.index=e,this.isDisabled()?this.up():this.render()}scrollDown(e=this.visible.length-1){return this.choices=Wat(this.choices),this.index=e,this.isDisabled()?this.down():this.render()}async shiftUp(){if(this.options.sort===!0){this.sorting=!0,this.swap(this.index-1),await this.up(),this.sorting=!1;return}return this.scrollUp(this.index)}async shiftDown(){if(this.options.sort===!0){this.sorting=!0,this.swap(this.index+1),await this.down(),this.sorting=!1;return}return this.scrollDown(this.index)}pageUp(){return this.visible.length<=1?this.alert():(this.limit=Math.max(this.limit-1,0),this.index=Math.min(this.limit-1,this.index),this._limit=this.limit,this.isDisabled()?this.up():this.render())}pageDown(){return this.visible.length>=this.choices.length?this.alert():(this.index=Math.max(0,this.index),this.limit=Math.min(this.limit+1,this.choices.length),this._limit=this.limit,this.isDisabled()?this.down():this.render())}swap(e){Yat(this.choices,this.index,e)}isDisabled(e=this.focused){return e&&[\"disabled\",\"collapsed\",\"hidden\",\"completing\",\"readonly\"].some(s=>e[s]===!0)?!0:e&&e.role===\"heading\"}isEnabled(e=this.focused){if(Array.isArray(e))return e.every(r=>this.isEnabled(r));if(e.choices){let r=e.choices.filter(s=>!this.isDisabled(s));return e.enabled&&r.every(s=>this.isEnabled(s))}return e.enabled&&!this.isDisabled(e)}isChoice(e,r){return e.name===r||e.index===Number(r)}isSelected(e){return Array.isArray(this.initial)?this.initial.some(r=>this.isChoice(e,r)):this.isChoice(e,this.initial)}map(e=[],r=\"value\"){return[].concat(e||[]).reduce((s,a)=>(s[a]=this.find(a,r),s),{})}filter(e,r){let a=typeof e==\"function\"?e:(f,p)=>[f.name,p].includes(e),c=(this.options.multiple?this.state._choices:this.choices).filter(a);return r?c.map(f=>f[r]):c}find(e,r){if(tme(e))return r?e[r]:e;let a=typeof e==\"function\"?e:(c,f)=>[c.name,f].includes(e),n=this.choices.find(a);if(n)return r?n[r]:n}findIndex(e){return this.choices.indexOf(this.find(e))}async submit(){let e=this.focused;if(!e)return this.alert();if(e.newChoice)return e.input?(e.updateChoice(),this.render()):this.alert();if(this.choices.some(c=>c.newChoice))return this.alert();let{reorder:r,sort:s}=this.options,a=this.multiple===!0,n=this.selected;return n===void 0?this.alert():(Array.isArray(n)&&r!==!1&&s!==!0&&(n=KT.reorder(n)),this.value=a?n.map(c=>c.name):n.name,super.submit())}set choices(e=[]){this.state._choices=this.state._choices||[],this.state.choices=e;for(let r of e)this.state._choices.some(s=>s.name===r.name)||this.state._choices.push(r);if(!this._initial&&this.options.initial){this._initial=!0;let r=this.initial;if(typeof r==\"string\"||typeof r==\"number\"){let s=this.find(r);s&&(this.initial=s.index,this.focus(s,!0))}}}get choices(){return rme(this,this.state.choices||[])}set visible(e){this.state.visible=e}get visible(){return(this.state.visible||this.choices).slice(0,this.limit)}set limit(e){this.state.limit=e}get limit(){let{state:e,options:r,choices:s}=this,a=e.limit||this._limit||r.limit||s.length;return Math.min(a,this.height)}set value(e){super.value=e}get value(){return typeof super.value!=\"string\"&&super.value===this.initial?this.input:super.value}set index(e){this.state.index=e}get index(){return Math.max(0,this.state?this.state.index:0)}get enabled(){return this.filter(this.isEnabled.bind(this))}get focused(){let e=this.choices[this.index];return e&&this.state.submitted&&this.multiple!==!0&&(e.enabled=!0),e}get selectable(){return this.choices.filter(e=>!this.isDisabled(e))}get selected(){return this.multiple?this.enabled:this.focused}};function rme(t,e){if(e instanceof Promise)return e;if(typeof e==\"function\"){if(KT.isAsyncFn(e))return e;e=e.call(t,t)}for(let r of e){if(Array.isArray(r.choices)){let s=r.choices.filter(a=>!t.isDisabled(a));r.enabled=s.every(a=>a.enabled===!0)}t.isDisabled(r)===!0&&delete r.enabled}return e}nme.exports=uq});var G0=_((KHt,ime)=>{\"use strict\";var Vat=Wv(),fq=Xo(),Aq=class extends Vat{constructor(e){super(e),this.emptyError=this.options.emptyError||\"No items were selected\"}async dispatch(e,r){if(this.multiple)return this[r.name]?await this[r.name](e,r):await super.dispatch(e,r);this.alert()}separator(){if(this.options.separator)return super.separator();let e=this.styles.muted(this.symbols.ellipsis);return this.state.submitted?super.separator():e}pointer(e,r){return!this.multiple||this.options.pointer?super.pointer(e,r):\"\"}indicator(e,r){return this.multiple?super.indicator(e,r):\"\"}choiceMessage(e,r){let s=this.resolve(e.message,this.state,e,r);return e.role===\"heading\"&&!fq.hasColor(s)&&(s=this.styles.strong(s)),this.resolve(s,this.state,e,r)}choiceSeparator(){return\":\"}async renderChoice(e,r){await this.onChoice(e,r);let s=this.index===r,a=await this.pointer(e,r),n=await this.indicator(e,r)+(e.pad||\"\"),c=await this.resolve(e.hint,this.state,e,r);c&&!fq.hasColor(c)&&(c=this.styles.muted(c));let f=this.indent(e),p=await this.choiceMessage(e,r),h=()=>[this.margin[3],f+a+n,p,this.margin[1],c].filter(Boolean).join(\" \");return e.role===\"heading\"?h():e.disabled?(fq.hasColor(p)||(p=this.styles.disabled(p)),h()):(s&&(p=this.styles.em(p)),h())}async renderChoices(){if(this.state.loading===\"choices\")return this.styles.warning(\"Loading choices\");if(this.state.submitted)return\"\";let e=this.visible.map(async(n,c)=>await this.renderChoice(n,c)),r=await Promise.all(e);r.length||r.push(this.styles.danger(\"No matching choices\"));let s=this.margin[0]+r.join(`\n`),a;return this.options.choicesHeader&&(a=await this.resolve(this.options.choicesHeader,this.state)),[a,s].filter(Boolean).join(`\n`)}format(){return!this.state.submitted||this.state.cancelled?\"\":Array.isArray(this.selected)?this.selected.map(e=>this.styles.primary(e.name)).join(\", \"):this.styles.primary(this.selected.name)}async render(){let{submitted:e,size:r}=this.state,s=\"\",a=await this.header(),n=await this.prefix(),c=await this.separator(),f=await this.message();this.options.promptLine!==!1&&(s=[n,f,c,\"\"].join(\" \"),this.state.prompt=s);let p=await this.format(),h=await this.error()||await this.hint(),E=await this.renderChoices(),C=await this.footer();p&&(s+=p),h&&!s.includes(h)&&(s+=\" \"+h),e&&!p&&!E.trim()&&this.multiple&&this.emptyError!=null&&(s+=this.styles.danger(this.emptyError)),this.clear(r),this.write([a,s,E,C].filter(Boolean).join(`\n`)),this.write(this.margin[2]),this.restore()}};ime.exports=Aq});var ome=_((zHt,sme)=>{\"use strict\";var Jat=G0(),Kat=(t,e)=>{let r=t.toLowerCase();return s=>{let n=s.toLowerCase().indexOf(r),c=e(s.slice(n,n+r.length));return n>=0?s.slice(0,n)+c+s.slice(n+r.length):s}},pq=class extends Jat{constructor(e){super(e),this.cursorShow()}moveCursor(e){this.state.cursor+=e}dispatch(e){return this.append(e)}space(e){return this.options.multiple?super.space(e):this.append(e)}append(e){let{cursor:r,input:s}=this.state;return this.input=s.slice(0,r)+e+s.slice(r),this.moveCursor(1),this.complete()}delete(){let{cursor:e,input:r}=this.state;return r?(this.input=r.slice(0,e-1)+r.slice(e),this.moveCursor(-1),this.complete()):this.alert()}deleteForward(){let{cursor:e,input:r}=this.state;return r[e]===void 0?this.alert():(this.input=`${r}`.slice(0,e)+`${r}`.slice(e+1),this.complete())}number(e){return this.append(e)}async complete(){this.completing=!0,this.choices=await this.suggest(this.input,this.state._choices),this.state.limit=void 0,this.index=Math.min(Math.max(this.visible.length-1,0),this.index),await this.render(),this.completing=!1}suggest(e=this.input,r=this.state._choices){if(typeof this.options.suggest==\"function\")return this.options.suggest.call(this,e,r);let s=e.toLowerCase();return r.filter(a=>a.message.toLowerCase().includes(s))}pointer(){return\"\"}format(){if(!this.focused)return this.input;if(this.options.multiple&&this.state.submitted)return this.selected.map(e=>this.styles.primary(e.message)).join(\", \");if(this.state.submitted){let e=this.value=this.input=this.focused.value;return this.styles.primary(e)}return this.input}async render(){if(this.state.status!==\"pending\")return super.render();let e=this.options.highlight?this.options.highlight.bind(this):this.styles.placeholder,r=Kat(this.input,e),s=this.choices;this.choices=s.map(a=>({...a,message:r(a.message)})),await super.render(),this.choices=s}submit(){return this.options.multiple&&(this.value=this.selected.map(e=>e.name)),super.submit()}};sme.exports=pq});var gq=_((ZHt,ame)=>{\"use strict\";var hq=Xo();ame.exports=(t,e={})=>{t.cursorHide();let{input:r=\"\",initial:s=\"\",pos:a,showCursor:n=!0,color:c}=e,f=c||t.styles.placeholder,p=hq.inverse(t.styles.primary),h=T=>p(t.styles.black(T)),E=r,C=\" \",S=h(C);if(t.blink&&t.blink.off===!0&&(h=T=>T,S=\"\"),n&&a===0&&s===\"\"&&r===\"\")return h(C);if(n&&a===0&&(r===s||r===\"\"))return h(s[0])+f(s.slice(1));s=hq.isPrimitive(s)?`${s}`:\"\",r=hq.isPrimitive(r)?`${r}`:\"\";let b=s&&s.startsWith(r)&&s!==r,I=b?h(s[r.length]):S;if(a!==r.length&&n===!0&&(E=r.slice(0,a)+h(r[a])+r.slice(a+1),I=\"\"),n===!1&&(I=\"\"),b){let T=t.styles.unstyle(E+I);return E+I+f(s.slice(T.length))}return E+I}});var zT=_((XHt,lme)=>{\"use strict\";var zat=Ju(),Zat=G0(),Xat=gq(),dq=class extends Zat{constructor(e){super({...e,multiple:!0}),this.type=\"form\",this.initial=this.options.initial,this.align=[this.options.align,\"right\"].find(r=>r!=null),this.emptyError=\"\",this.values={}}async reset(e){return await super.reset(),e===!0&&(this._index=this.index),this.index=this._index,this.values={},this.choices.forEach(r=>r.reset&&r.reset()),this.render()}dispatch(e){return!!e&&this.append(e)}append(e){let r=this.focused;if(!r)return this.alert();let{cursor:s,input:a}=r;return r.value=r.input=a.slice(0,s)+e+a.slice(s),r.cursor++,this.render()}delete(){let e=this.focused;if(!e||e.cursor<=0)return this.alert();let{cursor:r,input:s}=e;return e.value=e.input=s.slice(0,r-1)+s.slice(r),e.cursor--,this.render()}deleteForward(){let e=this.focused;if(!e)return this.alert();let{cursor:r,input:s}=e;if(s[r]===void 0)return this.alert();let a=`${s}`.slice(0,r)+`${s}`.slice(r+1);return e.value=e.input=a,this.render()}right(){let e=this.focused;return e?e.cursor>=e.input.length?this.alert():(e.cursor++,this.render()):this.alert()}left(){let e=this.focused;return e?e.cursor<=0?this.alert():(e.cursor--,this.render()):this.alert()}space(e,r){return this.dispatch(e,r)}number(e,r){return this.dispatch(e,r)}next(){let e=this.focused;if(!e)return this.alert();let{initial:r,input:s}=e;return r&&r.startsWith(s)&&s!==r?(e.value=e.input=r,e.cursor=e.value.length,this.render()):super.next()}prev(){let e=this.focused;return e?e.cursor===0?super.prev():(e.value=e.input=\"\",e.cursor=0,this.render()):this.alert()}separator(){return\"\"}format(e){return this.state.submitted?\"\":super.format(e)}pointer(){return\"\"}indicator(e){return e.input?\"\\u29BF\":\"\\u2299\"}async choiceSeparator(e,r){let s=await this.resolve(e.separator,this.state,e,r)||\":\";return s?\" \"+this.styles.disabled(s):\"\"}async renderChoice(e,r){await this.onChoice(e,r);let{state:s,styles:a}=this,{cursor:n,initial:c=\"\",name:f,hint:p,input:h=\"\"}=e,{muted:E,submitted:C,primary:S,danger:b}=a,I=p,T=this.index===r,N=e.validate||(()=>!0),U=await this.choiceSeparator(e,r),W=e.message;this.align===\"right\"&&(W=W.padStart(this.longest+1,\" \")),this.align===\"left\"&&(W=W.padEnd(this.longest+1,\" \"));let ee=this.values[f]=h||c,ie=h?\"success\":\"dark\";await N.call(e,ee,this.state)!==!0&&(ie=\"danger\");let ue=a[ie],le=ue(await this.indicator(e,r))+(e.pad||\"\"),me=this.indent(e),pe=()=>[me,le,W+U,h,I].filter(Boolean).join(\" \");if(s.submitted)return W=zat.unstyle(W),h=C(h),I=\"\",pe();if(e.format)h=await e.format.call(this,h,e,r);else{let Be=this.styles.muted;h=Xat(this,{input:h,initial:c,pos:n,showCursor:T,color:Be})}return this.isValue(h)||(h=this.styles.muted(this.symbols.ellipsis)),e.result&&(this.values[f]=await e.result.call(this,ee,e,r)),T&&(W=S(W)),e.error?h+=(h?\" \":\"\")+b(e.error.trim()):e.hint&&(h+=(h?\" \":\"\")+E(e.hint.trim())),pe()}async submit(){return this.value=this.values,super.base.submit.call(this)}};lme.exports=dq});var mq=_(($Ht,ume)=>{\"use strict\";var $at=zT(),elt=()=>{throw new Error(\"expected prompt to have a custom authenticate method\")},cme=(t=elt)=>{class e extends $at{constructor(s){super(s)}async submit(){this.value=await t.call(this,this.values,this.state),super.base.submit.call(this)}static create(s){return cme(s)}}return e};ume.exports=cme()});var pme=_((ejt,Ame)=>{\"use strict\";var tlt=mq();function rlt(t,e){return t.username===this.options.username&&t.password===this.options.password}var fme=(t=rlt)=>{let e=[{name:\"username\",message:\"username\"},{name:\"password\",message:\"password\",format(s){return this.options.showPassword?s:(this.state.submitted?this.styles.primary:this.styles.muted)(this.symbols.asterisk.repeat(s.length))}}];class r extends tlt.create(t){constructor(a){super({...a,choices:e})}static create(a){return fme(a)}}return r};Ame.exports=fme()});var ZT=_((tjt,hme)=>{\"use strict\";var nlt=nC(),{isPrimitive:ilt,hasColor:slt}=Xo(),yq=class extends nlt{constructor(e){super(e),this.cursorHide()}async initialize(){let e=await this.resolve(this.initial,this.state);this.input=await this.cast(e),await super.initialize()}dispatch(e){return this.isValue(e)?(this.input=e,this.submit()):this.alert()}format(e){let{styles:r,state:s}=this;return s.submitted?r.success(e):r.primary(e)}cast(e){return this.isTrue(e)}isTrue(e){return/^[ty1]/i.test(e)}isFalse(e){return/^[fn0]/i.test(e)}isValue(e){return ilt(e)&&(this.isTrue(e)||this.isFalse(e))}async hint(){if(this.state.status===\"pending\"){let e=await this.element(\"hint\");return slt(e)?e:this.styles.muted(e)}}async render(){let{input:e,size:r}=this.state,s=await this.prefix(),a=await this.separator(),n=await this.message(),c=this.styles.muted(this.default),f=[s,n,c,a].filter(Boolean).join(\" \");this.state.prompt=f;let p=await this.header(),h=this.value=this.cast(e),E=await this.format(h),C=await this.error()||await this.hint(),S=await this.footer();C&&!f.includes(C)&&(E+=\" \"+C),f+=\" \"+E,this.clear(r),this.write([p,f,S].filter(Boolean).join(`\n`)),this.restore()}set value(e){super.value=e}get value(){return this.cast(super.value)}};hme.exports=yq});var dme=_((rjt,gme)=>{\"use strict\";var olt=ZT(),Eq=class extends olt{constructor(e){super(e),this.default=this.options.default||(this.initial?\"(Y/n)\":\"(y/N)\")}};gme.exports=Eq});var yme=_((njt,mme)=>{\"use strict\";var alt=G0(),llt=zT(),iC=llt.prototype,Iq=class extends alt{constructor(e){super({...e,multiple:!0}),this.align=[this.options.align,\"left\"].find(r=>r!=null),this.emptyError=\"\",this.values={}}dispatch(e,r){let s=this.focused,a=s.parent||{};return!s.editable&&!a.editable&&(e===\"a\"||e===\"i\")?super[e]():iC.dispatch.call(this,e,r)}append(e,r){return iC.append.call(this,e,r)}delete(e,r){return iC.delete.call(this,e,r)}space(e){return this.focused.editable?this.append(e):super.space()}number(e){return this.focused.editable?this.append(e):super.number(e)}next(){return this.focused.editable?iC.next.call(this):super.next()}prev(){return this.focused.editable?iC.prev.call(this):super.prev()}async indicator(e,r){let s=e.indicator||\"\",a=e.editable?s:super.indicator(e,r);return await this.resolve(a,this.state,e,r)||\"\"}indent(e){return e.role===\"heading\"?\"\":e.editable?\" \":\"  \"}async renderChoice(e,r){return e.indent=\"\",e.editable?iC.renderChoice.call(this,e,r):super.renderChoice(e,r)}error(){return\"\"}footer(){return this.state.error}async validate(){let e=!0;for(let r of this.choices){if(typeof r.validate!=\"function\"||r.role===\"heading\")continue;let s=r.parent?this.value[r.parent.name]:this.value;if(r.editable?s=r.value===r.name?r.initial||\"\":r.value:this.isDisabled(r)||(s=r.enabled===!0),e=await r.validate(s,this.state),e!==!0)break}return e!==!0&&(this.state.error=typeof e==\"string\"?e:\"Invalid Input\"),e}submit(){if(this.focused.newChoice===!0)return super.submit();if(this.choices.some(e=>e.newChoice))return this.alert();this.value={};for(let e of this.choices){let r=e.parent?this.value[e.parent.name]:this.value;if(e.role===\"heading\"){this.value[e.name]={};continue}e.editable?r[e.name]=e.value===e.name?e.initial||\"\":e.value:this.isDisabled(e)||(r[e.name]=e.enabled===!0)}return this.base.submit.call(this)}};mme.exports=Iq});var vm=_((ijt,Eme)=>{\"use strict\";var clt=nC(),ult=gq(),{isPrimitive:flt}=Xo(),Cq=class extends clt{constructor(e){super(e),this.initial=flt(this.initial)?String(this.initial):\"\",this.initial&&this.cursorHide(),this.state.prevCursor=0,this.state.clipboard=[]}async keypress(e,r={}){let s=this.state.prevKeypress;return this.state.prevKeypress=r,this.options.multiline===!0&&r.name===\"return\"&&(!s||s.name!==\"return\")?this.append(`\n`,r):super.keypress(e,r)}moveCursor(e){this.cursor+=e}reset(){return this.input=this.value=\"\",this.cursor=0,this.render()}dispatch(e,r){if(!e||r.ctrl||r.code)return this.alert();this.append(e)}append(e){let{cursor:r,input:s}=this.state;this.input=`${s}`.slice(0,r)+e+`${s}`.slice(r),this.moveCursor(String(e).length),this.render()}insert(e){this.append(e)}delete(){let{cursor:e,input:r}=this.state;if(e<=0)return this.alert();this.input=`${r}`.slice(0,e-1)+`${r}`.slice(e),this.moveCursor(-1),this.render()}deleteForward(){let{cursor:e,input:r}=this.state;if(r[e]===void 0)return this.alert();this.input=`${r}`.slice(0,e)+`${r}`.slice(e+1),this.render()}cutForward(){let e=this.cursor;if(this.input.length<=e)return this.alert();this.state.clipboard.push(this.input.slice(e)),this.input=this.input.slice(0,e),this.render()}cutLeft(){let e=this.cursor;if(e===0)return this.alert();let r=this.input.slice(0,e),s=this.input.slice(e),a=r.split(\" \");this.state.clipboard.push(a.pop()),this.input=a.join(\" \"),this.cursor=this.input.length,this.input+=s,this.render()}paste(){if(!this.state.clipboard.length)return this.alert();this.insert(this.state.clipboard.pop()),this.render()}toggleCursor(){this.state.prevCursor?(this.cursor=this.state.prevCursor,this.state.prevCursor=0):(this.state.prevCursor=this.cursor,this.cursor=0),this.render()}first(){this.cursor=0,this.render()}last(){this.cursor=this.input.length-1,this.render()}next(){let e=this.initial!=null?String(this.initial):\"\";if(!e||!e.startsWith(this.input))return this.alert();this.input=this.initial,this.cursor=this.initial.length,this.render()}prev(){if(!this.input)return this.alert();this.reset()}backward(){return this.left()}forward(){return this.right()}right(){return this.cursor>=this.input.length?this.alert():(this.moveCursor(1),this.render())}left(){return this.cursor<=0?this.alert():(this.moveCursor(-1),this.render())}isValue(e){return!!e}async format(e=this.value){let r=await this.resolve(this.initial,this.state);return this.state.submitted?this.styles.submitted(e||r):ult(this,{input:e,initial:r,pos:this.cursor})}async render(){let e=this.state.size,r=await this.prefix(),s=await this.separator(),a=await this.message(),n=[r,a,s].filter(Boolean).join(\" \");this.state.prompt=n;let c=await this.header(),f=await this.format(),p=await this.error()||await this.hint(),h=await this.footer();p&&!f.includes(p)&&(f+=\" \"+p),n+=\" \"+f,this.clear(e),this.write([c,n,h].filter(Boolean).join(`\n`)),this.restore()}};Eme.exports=Cq});var Cme=_((sjt,Ime)=>{\"use strict\";var Alt=t=>t.filter((e,r)=>t.lastIndexOf(e)===r),XT=t=>Alt(t).filter(Boolean);Ime.exports=(t,e={},r=\"\")=>{let{past:s=[],present:a=\"\"}=e,n,c;switch(t){case\"prev\":case\"undo\":return n=s.slice(0,s.length-1),c=s[s.length-1]||\"\",{past:XT([r,...n]),present:c};case\"next\":case\"redo\":return n=s.slice(1),c=s[0]||\"\",{past:XT([...n,r]),present:c};case\"save\":return{past:XT([...s,r]),present:\"\"};case\"remove\":return c=XT(s.filter(f=>f!==r)),a=\"\",c.length&&(a=c.pop()),{past:c,present:a};default:throw new Error(`Invalid action: \"${t}\"`)}}});var Bq=_((ojt,Bme)=>{\"use strict\";var plt=vm(),wme=Cme(),wq=class extends plt{constructor(e){super(e);let r=this.options.history;if(r&&r.store){let s=r.values||this.initial;this.autosave=!!r.autosave,this.store=r.store,this.data=this.store.get(\"values\")||{past:[],present:s},this.initial=this.data.present||this.data.past[this.data.past.length-1]}}completion(e){return this.store?(this.data=wme(e,this.data,this.input),this.data.present?(this.input=this.data.present,this.cursor=this.input.length,this.render()):this.alert()):this.alert()}altUp(){return this.completion(\"prev\")}altDown(){return this.completion(\"next\")}prev(){return this.save(),super.prev()}save(){this.store&&(this.data=wme(\"save\",this.data,this.input),this.store.set(\"values\",this.data))}submit(){return this.store&&this.autosave===!0&&this.save(),super.submit()}};Bme.exports=wq});var Sme=_((ajt,vme)=>{\"use strict\";var hlt=vm(),vq=class extends hlt{format(){return\"\"}};vme.exports=vq});var Pme=_((ljt,Dme)=>{\"use strict\";var glt=vm(),Sq=class extends glt{constructor(e={}){super(e),this.sep=this.options.separator||/, */,this.initial=e.initial||\"\"}split(e=this.value){return e?String(e).split(this.sep):[]}format(){let e=this.state.submitted?this.styles.primary:r=>r;return this.list.map(e).join(\", \")}async submit(e){let r=this.state.error||await this.validate(this.list,this.state);return r!==!0?(this.state.error=r,super.submit()):(this.value=this.list,super.submit())}get list(){return this.split()}};Dme.exports=Sq});var xme=_((cjt,bme)=>{\"use strict\";var dlt=G0(),Dq=class extends dlt{constructor(e){super({...e,multiple:!0})}};bme.exports=Dq});var bq=_((ujt,kme)=>{\"use strict\";var mlt=vm(),Pq=class extends mlt{constructor(e={}){super({style:\"number\",...e}),this.min=this.isValue(e.min)?this.toNumber(e.min):-1/0,this.max=this.isValue(e.max)?this.toNumber(e.max):1/0,this.delay=e.delay!=null?e.delay:1e3,this.float=e.float!==!1,this.round=e.round===!0||e.float===!1,this.major=e.major||10,this.minor=e.minor||1,this.initial=e.initial!=null?e.initial:\"\",this.input=String(this.initial),this.cursor=this.input.length,this.cursorShow()}append(e){return!/[-+.]/.test(e)||e===\".\"&&this.input.includes(\".\")?this.alert(\"invalid number\"):super.append(e)}number(e){return super.append(e)}next(){return this.input&&this.input!==this.initial?this.alert():this.isValue(this.initial)?(this.input=this.initial,this.cursor=String(this.initial).length,this.render()):this.alert()}up(e){let r=e||this.minor,s=this.toNumber(this.input);return s>this.max+r?this.alert():(this.input=`${s+r}`,this.render())}down(e){let r=e||this.minor,s=this.toNumber(this.input);return s<this.min-r?this.alert():(this.input=`${s-r}`,this.render())}shiftDown(){return this.down(this.major)}shiftUp(){return this.up(this.major)}format(e=this.input){return typeof this.options.format==\"function\"?this.options.format.call(this,e):this.styles.info(e)}toNumber(e=\"\"){return this.float?+e:Math.round(+e)}isValue(e){return/^[-+]?[0-9]+((\\.)|(\\.[0-9]+))?$/.test(e)}submit(){let e=[this.input,this.initial].find(r=>this.isValue(r));return this.value=this.toNumber(e||0),super.submit()}};kme.exports=Pq});var Rme=_((fjt,Qme)=>{Qme.exports=bq()});var Fme=_((Ajt,Tme)=>{\"use strict\";var ylt=vm(),xq=class extends ylt{constructor(e){super(e),this.cursorShow()}format(e=this.input){return this.keypressed?(this.state.submitted?this.styles.primary:this.styles.muted)(this.symbols.asterisk.repeat(e.length)):\"\"}};Tme.exports=xq});var Lme=_((pjt,Ome)=>{\"use strict\";var Elt=Ju(),Ilt=Wv(),Nme=Xo(),kq=class extends Ilt{constructor(e={}){super(e),this.widths=[].concat(e.messageWidth||50),this.align=[].concat(e.align||\"left\"),this.linebreak=e.linebreak||!1,this.edgeLength=e.edgeLength||3,this.newline=e.newline||`\n   `;let r=e.startNumber||1;typeof this.scale==\"number\"&&(this.scaleKey=!1,this.scale=Array(this.scale).fill(0).map((s,a)=>({name:a+r})))}async reset(){return this.tableized=!1,await super.reset(),this.render()}tableize(){if(this.tableized===!0)return;this.tableized=!0;let e=0;for(let r of this.choices){e=Math.max(e,r.message.length),r.scaleIndex=r.initial||2,r.scale=[];for(let s=0;s<this.scale.length;s++)r.scale.push({index:s})}this.widths[0]=Math.min(this.widths[0],e+3)}async dispatch(e,r){if(this.multiple)return this[r.name]?await this[r.name](e,r):await super.dispatch(e,r);this.alert()}heading(e,r,s){return this.styles.strong(e)}separator(){return this.styles.muted(this.symbols.ellipsis)}right(){let e=this.focused;return e.scaleIndex>=this.scale.length-1?this.alert():(e.scaleIndex++,this.render())}left(){let e=this.focused;return e.scaleIndex<=0?this.alert():(e.scaleIndex--,this.render())}indent(){return\"\"}format(){return this.state.submitted?this.choices.map(r=>this.styles.info(r.index)).join(\", \"):\"\"}pointer(){return\"\"}renderScaleKey(){return this.scaleKey===!1||this.state.submitted?\"\":[\"\",...this.scale.map(s=>`   ${s.name} - ${s.message}`)].map(s=>this.styles.muted(s)).join(`\n`)}renderScaleHeading(e){let r=this.scale.map(p=>p.name);typeof this.options.renderScaleHeading==\"function\"&&(r=this.options.renderScaleHeading.call(this,e));let s=this.scaleLength-r.join(\"\").length,a=Math.round(s/(r.length-1)),c=r.map(p=>this.styles.strong(p)).join(\" \".repeat(a)),f=\" \".repeat(this.widths[0]);return this.margin[3]+f+this.margin[1]+c}scaleIndicator(e,r,s){if(typeof this.options.scaleIndicator==\"function\")return this.options.scaleIndicator.call(this,e,r,s);let a=e.scaleIndex===r.index;return r.disabled?this.styles.hint(this.symbols.radio.disabled):a?this.styles.success(this.symbols.radio.on):this.symbols.radio.off}renderScale(e,r){let s=e.scale.map(n=>this.scaleIndicator(e,n,r)),a=this.term===\"Hyper\"?\"\":\" \";return s.join(a+this.symbols.line.repeat(this.edgeLength))}async renderChoice(e,r){await this.onChoice(e,r);let s=this.index===r,a=await this.pointer(e,r),n=await e.hint;n&&!Nme.hasColor(n)&&(n=this.styles.muted(n));let c=I=>this.margin[3]+I.replace(/\\s+$/,\"\").padEnd(this.widths[0],\" \"),f=this.newline,p=this.indent(e),h=await this.resolve(e.message,this.state,e,r),E=await this.renderScale(e,r),C=this.margin[1]+this.margin[3];this.scaleLength=Elt.unstyle(E).length,this.widths[0]=Math.min(this.widths[0],this.width-this.scaleLength-C.length);let b=Nme.wordWrap(h,{width:this.widths[0],newline:f}).split(`\n`).map(I=>c(I)+this.margin[1]);return s&&(E=this.styles.info(E),b=b.map(I=>this.styles.info(I))),b[0]+=E,this.linebreak&&b.push(\"\"),[p+a,b.join(`\n`)].filter(Boolean)}async renderChoices(){if(this.state.submitted)return\"\";this.tableize();let e=this.visible.map(async(a,n)=>await this.renderChoice(a,n)),r=await Promise.all(e),s=await this.renderScaleHeading();return this.margin[0]+[s,...r.map(a=>a.join(\" \"))].join(`\n`)}async render(){let{submitted:e,size:r}=this.state,s=await this.prefix(),a=await this.separator(),n=await this.message(),c=\"\";this.options.promptLine!==!1&&(c=[s,n,a,\"\"].join(\" \"),this.state.prompt=c);let f=await this.header(),p=await this.format(),h=await this.renderScaleKey(),E=await this.error()||await this.hint(),C=await this.renderChoices(),S=await this.footer(),b=this.emptyError;p&&(c+=p),E&&!c.includes(E)&&(c+=\" \"+E),e&&!p&&!C.trim()&&this.multiple&&b!=null&&(c+=this.styles.danger(b)),this.clear(r),this.write([f,c,h,C,S].filter(Boolean).join(`\n`)),this.state.submitted||this.write(this.margin[2]),this.restore()}submit(){this.value={};for(let e of this.choices)this.value[e.name]=e.scaleIndex;return this.base.submit.call(this)}};Ome.exports=kq});var _me=_((hjt,Ume)=>{\"use strict\";var Mme=Ju(),Clt=(t=\"\")=>typeof t==\"string\"?t.replace(/^['\"]|['\"]$/g,\"\"):\"\",Rq=class{constructor(e){this.name=e.key,this.field=e.field||{},this.value=Clt(e.initial||this.field.initial||\"\"),this.message=e.message||this.name,this.cursor=0,this.input=\"\",this.lines=[]}},wlt=async(t={},e={},r=s=>s)=>{let s=new Set,a=t.fields||[],n=t.template,c=[],f=[],p=[],h=1;typeof n==\"function\"&&(n=await n());let E=-1,C=()=>n[++E],S=()=>n[E+1],b=I=>{I.line=h,c.push(I)};for(b({type:\"bos\",value:\"\"});E<n.length-1;){let I=C();if(/^[^\\S\\n ]$/.test(I)){b({type:\"text\",value:I});continue}if(I===`\n`){b({type:\"newline\",value:I}),h++;continue}if(I===\"\\\\\"){I+=C(),b({type:\"text\",value:I});continue}if((I===\"$\"||I===\"#\"||I===\"{\")&&S()===\"{\"){let N=C();I+=N;let U={type:\"template\",open:I,inner:\"\",close:\"\",value:I},W;for(;W=C();){if(W===\"}\"){S()===\"}\"&&(W+=C()),U.value+=W,U.close=W;break}W===\":\"?(U.initial=\"\",U.key=U.inner):U.initial!==void 0&&(U.initial+=W),U.value+=W,U.inner+=W}U.template=U.open+(U.initial||U.inner)+U.close,U.key=U.key||U.inner,e.hasOwnProperty(U.key)&&(U.initial=e[U.key]),U=r(U),b(U),p.push(U.key),s.add(U.key);let ee=f.find(ie=>ie.name===U.key);U.field=a.find(ie=>ie.name===U.key),ee||(ee=new Rq(U),f.push(ee)),ee.lines.push(U.line-1);continue}let T=c[c.length-1];T.type===\"text\"&&T.line===h?T.value+=I:b({type:\"text\",value:I})}return b({type:\"eos\",value:\"\"}),{input:n,tabstops:c,unique:s,keys:p,items:f}};Ume.exports=async t=>{let e=t.options,r=new Set(e.required===!0?[]:e.required||[]),s={...e.values,...e.initial},{tabstops:a,items:n,keys:c}=await wlt(e,s),f=Qq(\"result\",t,e),p=Qq(\"format\",t,e),h=Qq(\"validate\",t,e,!0),E=t.isValue.bind(t);return async(C={},S=!1)=>{let b=0;C.required=r,C.items=n,C.keys=c,C.output=\"\";let I=async(W,ee,ie,ue)=>{let le=await h(W,ee,ie,ue);return le===!1?\"Invalid field \"+ie.name:le};for(let W of a){let ee=W.value,ie=W.key;if(W.type!==\"template\"){ee&&(C.output+=ee);continue}if(W.type===\"template\"){let ue=n.find(Ce=>Ce.name===ie);e.required===!0&&C.required.add(ue.name);let le=[ue.input,C.values[ue.value],ue.value,ee].find(E),pe=(ue.field||{}).message||W.inner;if(S){let Ce=await I(C.values[ie],C,ue,b);if(Ce&&typeof Ce==\"string\"||Ce===!1){C.invalid.set(ie,Ce);continue}C.invalid.delete(ie);let g=await f(C.values[ie],C,ue,b);C.output+=Mme.unstyle(g);continue}ue.placeholder=!1;let Be=ee;ee=await p(ee,C,ue,b),le!==ee?(C.values[ie]=le,ee=t.styles.typing(le),C.missing.delete(pe)):(C.values[ie]=void 0,le=`<${pe}>`,ee=t.styles.primary(le),ue.placeholder=!0,C.required.has(ie)&&C.missing.add(pe)),C.missing.has(pe)&&C.validating&&(ee=t.styles.warning(le)),C.invalid.has(ie)&&C.validating&&(ee=t.styles.danger(le)),b===C.index&&(Be!==ee?ee=t.styles.underline(ee):ee=t.styles.heading(Mme.unstyle(ee))),b++}ee&&(C.output+=ee)}let T=C.output.split(`\n`).map(W=>\" \"+W),N=n.length,U=0;for(let W of n)C.invalid.has(W.name)&&W.lines.forEach(ee=>{T[ee][0]===\" \"&&(T[ee]=C.styles.danger(C.symbols.bullet)+T[ee].slice(1))}),t.isValue(C.values[W.name])&&U++;return C.completed=(U/N*100).toFixed(0),C.output=T.join(`\n`),C.output}};function Qq(t,e,r,s){return(a,n,c,f)=>typeof c.field[t]==\"function\"?c.field[t].call(e,a,n,c,f):[s,a].find(p=>e.isValue(p))}});var jme=_((gjt,Hme)=>{\"use strict\";var Blt=Ju(),vlt=_me(),Slt=nC(),Tq=class extends Slt{constructor(e){super(e),this.cursorHide(),this.reset(!0)}async initialize(){this.interpolate=await vlt(this),await super.initialize()}async reset(e){this.state.keys=[],this.state.invalid=new Map,this.state.missing=new Set,this.state.completed=0,this.state.values={},e!==!0&&(await this.initialize(),await this.render())}moveCursor(e){let r=this.getItem();this.cursor+=e,r.cursor+=e}dispatch(e,r){if(!r.code&&!r.ctrl&&e!=null&&this.getItem()){this.append(e,r);return}this.alert()}append(e,r){let s=this.getItem(),a=s.input.slice(0,this.cursor),n=s.input.slice(this.cursor);this.input=s.input=`${a}${e}${n}`,this.moveCursor(1),this.render()}delete(){let e=this.getItem();if(this.cursor<=0||!e.input)return this.alert();let r=e.input.slice(this.cursor),s=e.input.slice(0,this.cursor-1);this.input=e.input=`${s}${r}`,this.moveCursor(-1),this.render()}increment(e){return e>=this.state.keys.length-1?0:e+1}decrement(e){return e<=0?this.state.keys.length-1:e-1}first(){this.state.index=0,this.render()}last(){this.state.index=this.state.keys.length-1,this.render()}right(){if(this.cursor>=this.input.length)return this.alert();this.moveCursor(1),this.render()}left(){if(this.cursor<=0)return this.alert();this.moveCursor(-1),this.render()}prev(){this.state.index=this.decrement(this.state.index),this.getItem(),this.render()}next(){this.state.index=this.increment(this.state.index),this.getItem(),this.render()}up(){this.prev()}down(){this.next()}format(e){let r=this.state.completed<100?this.styles.warning:this.styles.success;return this.state.submitted===!0&&this.state.completed!==100&&(r=this.styles.danger),r(`${this.state.completed}% completed`)}async render(){let{index:e,keys:r=[],submitted:s,size:a}=this.state,n=[this.options.newline,`\n`].find(W=>W!=null),c=await this.prefix(),f=await this.separator(),p=await this.message(),h=[c,p,f].filter(Boolean).join(\" \");this.state.prompt=h;let E=await this.header(),C=await this.error()||\"\",S=await this.hint()||\"\",b=s?\"\":await this.interpolate(this.state),I=this.state.key=r[e]||\"\",T=await this.format(I),N=await this.footer();T&&(h+=\" \"+T),S&&!T&&this.state.completed===0&&(h+=\" \"+S),this.clear(a);let U=[E,h,b,N,C.trim()];this.write(U.filter(Boolean).join(n)),this.restore()}getItem(e){let{items:r,keys:s,index:a}=this.state,n=r.find(c=>c.name===s[a]);return n&&n.input!=null&&(this.input=n.input,this.cursor=n.cursor),n}async submit(){typeof this.interpolate!=\"function\"&&await this.initialize(),await this.interpolate(this.state,!0);let{invalid:e,missing:r,output:s,values:a}=this.state;if(e.size){let f=\"\";for(let[p,h]of e)f+=`Invalid ${p}: ${h}\n`;return this.state.error=f,super.submit()}if(r.size)return this.state.error=\"Required: \"+[...r.keys()].join(\", \"),super.submit();let c=Blt.unstyle(s).split(`\n`).map(f=>f.slice(1)).join(`\n`);return this.value={values:a,result:c},super.submit()}};Hme.exports=Tq});var qme=_((djt,Gme)=>{\"use strict\";var Dlt=\"(Use <shift>+<up/down> to sort)\",Plt=G0(),Fq=class extends Plt{constructor(e){super({...e,reorder:!1,sort:!0,multiple:!0}),this.state.hint=[this.options.hint,Dlt].find(this.isValue.bind(this))}indicator(){return\"\"}async renderChoice(e,r){let s=await super.renderChoice(e,r),a=this.symbols.identicalTo+\" \",n=this.index===r&&this.sorting?this.styles.muted(a):\"  \";return this.options.drag===!1&&(n=\"\"),this.options.numbered===!0?n+`${r+1} - `+s:n+s}get selected(){return this.choices}submit(){return this.value=this.choices.map(e=>e.value),super.submit()}};Gme.exports=Fq});var Yme=_((mjt,Wme)=>{\"use strict\";var blt=Wv(),Nq=class extends blt{constructor(e={}){if(super(e),this.emptyError=e.emptyError||\"No items were selected\",this.term=process.env.TERM_PROGRAM,!this.options.header){let r=[\"\",\"4 - Strongly Agree\",\"3 - Agree\",\"2 - Neutral\",\"1 - Disagree\",\"0 - Strongly Disagree\",\"\"];r=r.map(s=>this.styles.muted(s)),this.state.header=r.join(`\n   `)}}async toChoices(...e){if(this.createdScales)return!1;this.createdScales=!0;let r=await super.toChoices(...e);for(let s of r)s.scale=xlt(5,this.options),s.scaleIdx=2;return r}dispatch(){this.alert()}space(){let e=this.focused,r=e.scale[e.scaleIdx],s=r.selected;return e.scale.forEach(a=>a.selected=!1),r.selected=!s,this.render()}indicator(){return\"\"}pointer(){return\"\"}separator(){return this.styles.muted(this.symbols.ellipsis)}right(){let e=this.focused;return e.scaleIdx>=e.scale.length-1?this.alert():(e.scaleIdx++,this.render())}left(){let e=this.focused;return e.scaleIdx<=0?this.alert():(e.scaleIdx--,this.render())}indent(){return\"   \"}async renderChoice(e,r){await this.onChoice(e,r);let s=this.index===r,a=this.term===\"Hyper\",n=a?9:8,c=a?\"\":\" \",f=this.symbols.line.repeat(n),p=\" \".repeat(n+(a?0:1)),h=ee=>(ee?this.styles.success(\"\\u25C9\"):\"\\u25EF\")+c,E=r+1+\".\",C=s?this.styles.heading:this.styles.noop,S=await this.resolve(e.message,this.state,e,r),b=this.indent(e),I=b+e.scale.map((ee,ie)=>h(ie===e.scaleIdx)).join(f),T=ee=>ee===e.scaleIdx?C(ee):ee,N=b+e.scale.map((ee,ie)=>T(ie)).join(p),U=()=>[E,S].filter(Boolean).join(\" \"),W=()=>[U(),I,N,\" \"].filter(Boolean).join(`\n`);return s&&(I=this.styles.cyan(I),N=this.styles.cyan(N)),W()}async renderChoices(){if(this.state.submitted)return\"\";let e=this.visible.map(async(s,a)=>await this.renderChoice(s,a)),r=await Promise.all(e);return r.length||r.push(this.styles.danger(\"No matching choices\")),r.join(`\n`)}format(){return this.state.submitted?this.choices.map(r=>this.styles.info(r.scaleIdx)).join(\", \"):\"\"}async render(){let{submitted:e,size:r}=this.state,s=await this.prefix(),a=await this.separator(),n=await this.message(),c=[s,n,a].filter(Boolean).join(\" \");this.state.prompt=c;let f=await this.header(),p=await this.format(),h=await this.error()||await this.hint(),E=await this.renderChoices(),C=await this.footer();(p||!h)&&(c+=\" \"+p),h&&!c.includes(h)&&(c+=\" \"+h),e&&!p&&!E&&this.multiple&&this.type!==\"form\"&&(c+=this.styles.danger(this.emptyError)),this.clear(r),this.write([c,f,E,C].filter(Boolean).join(`\n`)),this.restore()}submit(){this.value={};for(let e of this.choices)this.value[e.name]=e.scaleIdx;return this.base.submit.call(this)}};function xlt(t,e={}){if(Array.isArray(e.scale))return e.scale.map(s=>({...s}));let r=[];for(let s=1;s<t+1;s++)r.push({i:s,selected:!1});return r}Wme.exports=Nq});var Jme=_((yjt,Vme)=>{Vme.exports=Bq()});var zme=_((Ejt,Kme)=>{\"use strict\";var klt=ZT(),Oq=class extends klt{async initialize(){await super.initialize(),this.value=this.initial=!!this.options.initial,this.disabled=this.options.disabled||\"no\",this.enabled=this.options.enabled||\"yes\",await this.render()}reset(){this.value=this.initial,this.render()}delete(){this.alert()}toggle(){this.value=!this.value,this.render()}enable(){if(this.value===!0)return this.alert();this.value=!0,this.render()}disable(){if(this.value===!1)return this.alert();this.value=!1,this.render()}up(){this.toggle()}down(){this.toggle()}right(){this.toggle()}left(){this.toggle()}next(){this.toggle()}prev(){this.toggle()}dispatch(e=\"\",r){switch(e.toLowerCase()){case\" \":return this.toggle();case\"1\":case\"y\":case\"t\":return this.enable();case\"0\":case\"n\":case\"f\":return this.disable();default:return this.alert()}}format(){let e=s=>this.styles.primary.underline(s);return[this.value?this.disabled:e(this.disabled),this.value?e(this.enabled):this.enabled].join(this.styles.muted(\" / \"))}async render(){let{size:e}=this.state,r=await this.header(),s=await this.prefix(),a=await this.separator(),n=await this.message(),c=await this.format(),f=await this.error()||await this.hint(),p=await this.footer(),h=[s,n,a,c].join(\" \");this.state.prompt=h,f&&!h.includes(f)&&(h+=\" \"+f),this.clear(e),this.write([r,h,p].filter(Boolean).join(`\n`)),this.write(this.margin[2]),this.restore()}};Kme.exports=Oq});var Xme=_((Ijt,Zme)=>{\"use strict\";var Qlt=G0(),Lq=class extends Qlt{constructor(e){if(super(e),typeof this.options.correctChoice!=\"number\"||this.options.correctChoice<0)throw new Error(\"Please specify the index of the correct answer from the list of choices\")}async toChoices(e,r){let s=await super.toChoices(e,r);if(s.length<2)throw new Error(\"Please give at least two choices to the user\");if(this.options.correctChoice>s.length)throw new Error(\"Please specify the index of the correct answer from the list of choices\");return s}check(e){return e.index===this.options.correctChoice}async result(e){return{selectedAnswer:e,correctAnswer:this.options.choices[this.options.correctChoice].value,correct:await this.check(this.state)}}};Zme.exports=Lq});var eye=_(Mq=>{\"use strict\";var $me=Xo(),ks=(t,e)=>{$me.defineExport(Mq,t,e),$me.defineExport(Mq,t.toLowerCase(),e)};ks(\"AutoComplete\",()=>ome());ks(\"BasicAuth\",()=>pme());ks(\"Confirm\",()=>dme());ks(\"Editable\",()=>yme());ks(\"Form\",()=>zT());ks(\"Input\",()=>Bq());ks(\"Invisible\",()=>Sme());ks(\"List\",()=>Pme());ks(\"MultiSelect\",()=>xme());ks(\"Numeral\",()=>Rme());ks(\"Password\",()=>Fme());ks(\"Scale\",()=>Lme());ks(\"Select\",()=>G0());ks(\"Snippet\",()=>jme());ks(\"Sort\",()=>qme());ks(\"Survey\",()=>Yme());ks(\"Text\",()=>Jme());ks(\"Toggle\",()=>zme());ks(\"Quiz\",()=>Xme())});var rye=_((wjt,tye)=>{tye.exports={ArrayPrompt:Wv(),AuthPrompt:mq(),BooleanPrompt:ZT(),NumberPrompt:bq(),StringPrompt:vm()}});var Vv=_((Bjt,iye)=>{\"use strict\";var nye=Ie(\"assert\"),_q=Ie(\"events\"),q0=Xo(),zu=class extends _q{constructor(e,r){super(),this.options=q0.merge({},e),this.answers={...r}}register(e,r){if(q0.isObject(e)){for(let a of Object.keys(e))this.register(a,e[a]);return this}nye.equal(typeof r,\"function\",\"expected a function\");let s=e.toLowerCase();return r.prototype instanceof this.Prompt?this.prompts[s]=r:this.prompts[s]=r(this.Prompt,this),this}async prompt(e=[]){for(let r of[].concat(e))try{typeof r==\"function\"&&(r=await r.call(this)),await this.ask(q0.merge({},this.options,r))}catch(s){return Promise.reject(s)}return this.answers}async ask(e){typeof e==\"function\"&&(e=await e.call(this));let r=q0.merge({},this.options,e),{type:s,name:a}=e,{set:n,get:c}=q0;if(typeof s==\"function\"&&(s=await s.call(this,e,this.answers)),!s)return this.answers[a];nye(this.prompts[s],`Prompt \"${s}\" is not registered`);let f=new this.prompts[s](r),p=c(this.answers,a);f.state.answers=this.answers,f.enquirer=this,a&&f.on(\"submit\",E=>{this.emit(\"answer\",a,E,f),n(this.answers,a,E)});let h=f.emit.bind(f);return f.emit=(...E)=>(this.emit.call(this,...E),h(...E)),this.emit(\"prompt\",f,this),r.autofill&&p!=null?(f.value=f.input=p,r.autofill===\"show\"&&await f.submit()):p=f.value=await f.run(),p}use(e){return e.call(this,this),this}set Prompt(e){this._Prompt=e}get Prompt(){return this._Prompt||this.constructor.Prompt}get prompts(){return this.constructor.prompts}static set Prompt(e){this._Prompt=e}static get Prompt(){return this._Prompt||nC()}static get prompts(){return eye()}static get types(){return rye()}static get prompt(){let e=(r,...s)=>{let a=new this(...s),n=a.emit.bind(a);return a.emit=(...c)=>(e.emit(...c),n(...c)),a.prompt(r)};return q0.mixinEmitter(e,new _q),e}};q0.mixinEmitter(zu,new _q);var Uq=zu.prompts;for(let t of Object.keys(Uq)){let e=t.toLowerCase(),r=s=>new Uq[t](s).run();zu.prompt[e]=r,zu[e]=r,zu[t]||Reflect.defineProperty(zu,t,{get:()=>Uq[t]})}var Yv=t=>{q0.defineExport(zu,t,()=>zu.types[t])};Yv(\"ArrayPrompt\");Yv(\"AuthPrompt\");Yv(\"BooleanPrompt\");Yv(\"NumberPrompt\");Yv(\"StringPrompt\");iye.exports=zu});var Aye=_((Y6t,_lt)=>{_lt.exports={name:\"@yarnpkg/cli\",version:\"4.10.3\",license:\"BSD-2-Clause\",main:\"./sources/index.ts\",exports:{\".\":\"./sources/index.ts\",\"./polyfills\":\"./sources/polyfills.ts\",\"./package.json\":\"./package.json\"},dependencies:{\"@yarnpkg/core\":\"workspace:^\",\"@yarnpkg/fslib\":\"workspace:^\",\"@yarnpkg/libzip\":\"workspace:^\",\"@yarnpkg/parsers\":\"workspace:^\",\"@yarnpkg/plugin-catalog\":\"workspace:^\",\"@yarnpkg/plugin-compat\":\"workspace:^\",\"@yarnpkg/plugin-constraints\":\"workspace:^\",\"@yarnpkg/plugin-dlx\":\"workspace:^\",\"@yarnpkg/plugin-essentials\":\"workspace:^\",\"@yarnpkg/plugin-exec\":\"workspace:^\",\"@yarnpkg/plugin-file\":\"workspace:^\",\"@yarnpkg/plugin-git\":\"workspace:^\",\"@yarnpkg/plugin-github\":\"workspace:^\",\"@yarnpkg/plugin-http\":\"workspace:^\",\"@yarnpkg/plugin-init\":\"workspace:^\",\"@yarnpkg/plugin-interactive-tools\":\"workspace:^\",\"@yarnpkg/plugin-jsr\":\"workspace:^\",\"@yarnpkg/plugin-link\":\"workspace:^\",\"@yarnpkg/plugin-nm\":\"workspace:^\",\"@yarnpkg/plugin-npm\":\"workspace:^\",\"@yarnpkg/plugin-npm-cli\":\"workspace:^\",\"@yarnpkg/plugin-pack\":\"workspace:^\",\"@yarnpkg/plugin-patch\":\"workspace:^\",\"@yarnpkg/plugin-pnp\":\"workspace:^\",\"@yarnpkg/plugin-pnpm\":\"workspace:^\",\"@yarnpkg/plugin-stage\":\"workspace:^\",\"@yarnpkg/plugin-typescript\":\"workspace:^\",\"@yarnpkg/plugin-version\":\"workspace:^\",\"@yarnpkg/plugin-workspace-tools\":\"workspace:^\",\"@yarnpkg/shell\":\"workspace:^\",\"ci-info\":\"^4.0.0\",clipanion:\"^4.0.0-rc.2\",semver:\"^7.1.2\",tslib:\"^2.4.0\",typanion:\"^3.14.0\"},devDependencies:{\"@types/semver\":\"^7.1.0\",\"@yarnpkg/builder\":\"workspace:^\",\"@yarnpkg/monorepo\":\"workspace:^\",\"@yarnpkg/pnpify\":\"workspace:^\"},peerDependencies:{\"@yarnpkg/core\":\"workspace:^\"},scripts:{postpack:\"rm -rf lib\",prepack:'run build:compile \"$(pwd)\"',\"build:cli+hook\":\"run build:pnp:hook && builder build bundle\",\"build:cli\":\"builder build bundle\",\"run:cli\":\"builder run\",\"update-local\":\"run build:cli --no-git-hash && rsync -a --delete bundles/ bin/\"},publishConfig:{main:\"./lib/index.js\",bin:null,exports:{\".\":\"./lib/index.js\",\"./package.json\":\"./package.json\"}},files:[\"/lib/**/*\",\"!/lib/pluginConfiguration.*\",\"!/lib/cli.*\"],\"@yarnpkg/builder\":{bundles:{standard:[\"@yarnpkg/plugin-essentials\",\"@yarnpkg/plugin-compat\",\"@yarnpkg/plugin-constraints\",\"@yarnpkg/plugin-dlx\",\"@yarnpkg/plugin-exec\",\"@yarnpkg/plugin-file\",\"@yarnpkg/plugin-git\",\"@yarnpkg/plugin-github\",\"@yarnpkg/plugin-http\",\"@yarnpkg/plugin-init\",\"@yarnpkg/plugin-interactive-tools\",\"@yarnpkg/plugin-jsr\",\"@yarnpkg/plugin-link\",\"@yarnpkg/plugin-nm\",\"@yarnpkg/plugin-npm\",\"@yarnpkg/plugin-npm-cli\",\"@yarnpkg/plugin-pack\",\"@yarnpkg/plugin-patch\",\"@yarnpkg/plugin-pnp\",\"@yarnpkg/plugin-pnpm\",\"@yarnpkg/plugin-stage\",\"@yarnpkg/plugin-typescript\",\"@yarnpkg/plugin-version\",\"@yarnpkg/plugin-workspace-tools\",\"@yarnpkg/plugin-catalog\"]}},repository:{type:\"git\",url:\"git+https://github.com/yarnpkg/berry.git\",directory:\"packages/yarnpkg-cli\"},engines:{node:\">=18.12.0\"}}});var t5=_((v9t,vye)=>{\"use strict\";vye.exports=function(e,r){r===!0&&(r=0);var s=\"\";if(typeof e==\"string\")try{s=new URL(e).protocol}catch{}else e&&e.constructor===URL&&(s=e.protocol);var a=s.split(/\\:|\\+/).filter(Boolean);return typeof r==\"number\"?a[r]:a}});var Dye=_((S9t,Sye)=>{\"use strict\";var oct=t5();function act(t){var e={protocols:[],protocol:null,port:null,resource:\"\",host:\"\",user:\"\",password:\"\",pathname:\"\",hash:\"\",search:\"\",href:t,query:{},parse_failed:!1};try{var r=new URL(t);e.protocols=oct(r),e.protocol=e.protocols[0],e.port=r.port,e.resource=r.hostname,e.host=r.host,e.user=r.username||\"\",e.password=r.password||\"\",e.pathname=r.pathname,e.hash=r.hash.slice(1),e.search=r.search.slice(1),e.href=r.href,e.query=Object.fromEntries(r.searchParams)}catch{e.protocols=[\"file\"],e.protocol=e.protocols[0],e.port=\"\",e.resource=\"\",e.user=\"\",e.pathname=\"\",e.hash=\"\",e.search=\"\",e.href=t,e.query={},e.parse_failed=!0}return e}Sye.exports=act});var xye=_((D9t,bye)=>{\"use strict\";var lct=Dye();function cct(t){return t&&typeof t==\"object\"&&\"default\"in t?t:{default:t}}var uct=cct(lct),fct=\"text/plain\",Act=\"us-ascii\",Pye=(t,e)=>e.some(r=>r instanceof RegExp?r.test(t):r===t),pct=(t,{stripHash:e})=>{let r=/^data:(?<type>[^,]*?),(?<data>[^#]*?)(?:#(?<hash>.*))?$/.exec(t);if(!r)throw new Error(`Invalid URL: ${t}`);let{type:s,data:a,hash:n}=r.groups,c=s.split(\";\");n=e?\"\":n;let f=!1;c[c.length-1]===\"base64\"&&(c.pop(),f=!0);let p=(c.shift()||\"\").toLowerCase(),E=[...c.map(C=>{let[S,b=\"\"]=C.split(\"=\").map(I=>I.trim());return S===\"charset\"&&(b=b.toLowerCase(),b===Act)?\"\":`${S}${b?`=${b}`:\"\"}`}).filter(Boolean)];return f&&E.push(\"base64\"),(E.length>0||p&&p!==fct)&&E.unshift(p),`data:${E.join(\";\")},${f?a.trim():a}${n?`#${n}`:\"\"}`};function hct(t,e){if(e={defaultProtocol:\"http:\",normalizeProtocol:!0,forceHttp:!1,forceHttps:!1,stripAuthentication:!0,stripHash:!1,stripTextFragment:!0,stripWWW:!0,removeQueryParameters:[/^utm_\\w+/i],removeTrailingSlash:!0,removeSingleSlash:!0,removeDirectoryIndex:!1,sortQueryParameters:!0,...e},t=t.trim(),/^data:/i.test(t))return pct(t,e);if(/^view-source:/i.test(t))throw new Error(\"`view-source:` is not supported as it is a non-standard protocol\");let r=t.startsWith(\"//\");!r&&/^\\.*\\//.test(t)||(t=t.replace(/^(?!(?:\\w+:)?\\/\\/)|^\\/\\//,e.defaultProtocol));let a=new URL(t);if(e.forceHttp&&e.forceHttps)throw new Error(\"The `forceHttp` and `forceHttps` options cannot be used together\");if(e.forceHttp&&a.protocol===\"https:\"&&(a.protocol=\"http:\"),e.forceHttps&&a.protocol===\"http:\"&&(a.protocol=\"https:\"),e.stripAuthentication&&(a.username=\"\",a.password=\"\"),e.stripHash?a.hash=\"\":e.stripTextFragment&&(a.hash=a.hash.replace(/#?:~:text.*?$/i,\"\")),a.pathname){let c=/\\b[a-z][a-z\\d+\\-.]{1,50}:\\/\\//g,f=0,p=\"\";for(;;){let E=c.exec(a.pathname);if(!E)break;let C=E[0],S=E.index,b=a.pathname.slice(f,S);p+=b.replace(/\\/{2,}/g,\"/\"),p+=C,f=S+C.length}let h=a.pathname.slice(f,a.pathname.length);p+=h.replace(/\\/{2,}/g,\"/\"),a.pathname=p}if(a.pathname)try{a.pathname=decodeURI(a.pathname)}catch{}if(e.removeDirectoryIndex===!0&&(e.removeDirectoryIndex=[/^index\\.[a-z]+$/]),Array.isArray(e.removeDirectoryIndex)&&e.removeDirectoryIndex.length>0){let c=a.pathname.split(\"/\"),f=c[c.length-1];Pye(f,e.removeDirectoryIndex)&&(c=c.slice(0,-1),a.pathname=c.slice(1).join(\"/\")+\"/\")}if(a.hostname&&(a.hostname=a.hostname.replace(/\\.$/,\"\"),e.stripWWW&&/^www\\.(?!www\\.)[a-z\\-\\d]{1,63}\\.[a-z.\\-\\d]{2,63}$/.test(a.hostname)&&(a.hostname=a.hostname.replace(/^www\\./,\"\"))),Array.isArray(e.removeQueryParameters))for(let c of[...a.searchParams.keys()])Pye(c,e.removeQueryParameters)&&a.searchParams.delete(c);if(e.removeQueryParameters===!0&&(a.search=\"\"),e.sortQueryParameters){a.searchParams.sort();try{a.search=decodeURIComponent(a.search)}catch{}}e.removeTrailingSlash&&(a.pathname=a.pathname.replace(/\\/$/,\"\"));let n=t;return t=a.toString(),!e.removeSingleSlash&&a.pathname===\"/\"&&!n.endsWith(\"/\")&&a.hash===\"\"&&(t=t.replace(/\\/$/,\"\")),(e.removeTrailingSlash||a.pathname===\"/\")&&a.hash===\"\"&&e.removeSingleSlash&&(t=t.replace(/\\/$/,\"\")),r&&!e.normalizeProtocol&&(t=t.replace(/^http:\\/\\//,\"//\")),e.stripProtocol&&(t=t.replace(/^(?:https?:)?\\/\\//,\"\")),t}var r5=(t,e=!1)=>{let r=/^(?:([a-z_][a-z0-9_-]{0,31})@|https?:\\/\\/)([\\w\\.\\-@]+)[\\/:]([\\~,\\.\\w,\\-,\\_,\\/]+?(?:\\.git|\\/)?)$/,s=n=>{let c=new Error(n);throw c.subject_url=t,c};(typeof t!=\"string\"||!t.trim())&&s(\"Invalid url.\"),t.length>r5.MAX_INPUT_LENGTH&&s(\"Input exceeds maximum length. If needed, change the value of parseUrl.MAX_INPUT_LENGTH.\"),e&&(typeof e!=\"object\"&&(e={stripHash:!1}),t=hct(t,e));let a=uct.default(t);if(a.parse_failed){let n=a.href.match(r);n?(a.protocols=[\"ssh\"],a.protocol=\"ssh\",a.resource=n[2],a.host=n[2],a.user=n[1],a.pathname=`/${n[3]}`,a.parse_failed=!1):s(\"URL parsing failed.\")}return a};r5.MAX_INPUT_LENGTH=2048;bye.exports=r5});var Rye=_((P9t,Qye)=>{\"use strict\";var gct=t5();function kye(t){if(Array.isArray(t))return t.indexOf(\"ssh\")!==-1||t.indexOf(\"rsync\")!==-1;if(typeof t!=\"string\")return!1;var e=gct(t);if(t=t.substring(t.indexOf(\"://\")+3),kye(e))return!0;var r=new RegExp(\".([a-zA-Z\\\\d]+):(\\\\d+)/\");return!t.match(r)&&t.indexOf(\"@\")<t.indexOf(\":\")}Qye.exports=kye});var Nye=_((b9t,Fye)=>{\"use strict\";var dct=xye(),Tye=Rye();function mct(t){var e=dct(t);return e.token=\"\",e.password===\"x-oauth-basic\"?e.token=e.user:e.user===\"x-token-auth\"&&(e.token=e.password),Tye(e.protocols)||e.protocols.length===0&&Tye(t)?e.protocol=\"ssh\":e.protocols.length?e.protocol=e.protocols[0]:(e.protocol=\"file\",e.protocols=[\"file\"]),e.href=e.href.replace(/\\/$/,\"\"),e}Fye.exports=mct});var Lye=_((x9t,Oye)=>{\"use strict\";var yct=Nye();function n5(t){if(typeof t!=\"string\")throw new Error(\"The url must be a string.\");var e=/^([a-z\\d-]{1,39})\\/([-\\.\\w]{1,100})$/i;e.test(t)&&(t=\"https://github.com/\"+t);var r=yct(t),s=r.resource.split(\".\"),a=null;switch(r.toString=function(N){return n5.stringify(this,N)},r.source=s.length>2?s.slice(1-s.length).join(\".\"):r.source=r.resource,r.git_suffix=/\\.git$/.test(r.pathname),r.name=decodeURIComponent((r.pathname||r.href).replace(/(^\\/)|(\\/$)/g,\"\").replace(/\\.git$/,\"\")),r.owner=decodeURIComponent(r.user),r.source){case\"git.cloudforge.com\":r.owner=r.user,r.organization=s[0],r.source=\"cloudforge.com\";break;case\"visualstudio.com\":if(r.resource===\"vs-ssh.visualstudio.com\"){a=r.name.split(\"/\"),a.length===4&&(r.organization=a[1],r.owner=a[2],r.name=a[3],r.full_name=a[2]+\"/\"+a[3]);break}else{a=r.name.split(\"/\"),a.length===2?(r.owner=a[1],r.name=a[1],r.full_name=\"_git/\"+r.name):a.length===3?(r.name=a[2],a[0]===\"DefaultCollection\"?(r.owner=a[2],r.organization=a[0],r.full_name=r.organization+\"/_git/\"+r.name):(r.owner=a[0],r.full_name=r.owner+\"/_git/\"+r.name)):a.length===4&&(r.organization=a[0],r.owner=a[1],r.name=a[3],r.full_name=r.organization+\"/\"+r.owner+\"/_git/\"+r.name);break}case\"dev.azure.com\":case\"azure.com\":if(r.resource===\"ssh.dev.azure.com\"){a=r.name.split(\"/\"),a.length===4&&(r.organization=a[1],r.owner=a[2],r.name=a[3]);break}else{a=r.name.split(\"/\"),a.length===5?(r.organization=a[0],r.owner=a[1],r.name=a[4],r.full_name=\"_git/\"+r.name):a.length===3?(r.name=a[2],a[0]===\"DefaultCollection\"?(r.owner=a[2],r.organization=a[0],r.full_name=r.organization+\"/_git/\"+r.name):(r.owner=a[0],r.full_name=r.owner+\"/_git/\"+r.name)):a.length===4&&(r.organization=a[0],r.owner=a[1],r.name=a[3],r.full_name=r.organization+\"/\"+r.owner+\"/_git/\"+r.name),r.query&&r.query.path&&(r.filepath=r.query.path.replace(/^\\/+/g,\"\")),r.query&&r.query.version&&(r.ref=r.query.version.replace(/^GB/,\"\"));break}default:a=r.name.split(\"/\");var n=a.length-1;if(a.length>=2){var c=a.indexOf(\"-\",2),f=a.indexOf(\"blob\",2),p=a.indexOf(\"tree\",2),h=a.indexOf(\"commit\",2),E=a.indexOf(\"src\",2),C=a.indexOf(\"raw\",2),S=a.indexOf(\"edit\",2);n=c>0?c-1:f>0?f-1:p>0?p-1:h>0?h-1:E>0?E-1:C>0?C-1:S>0?S-1:n,r.owner=a.slice(0,n).join(\"/\"),r.name=a[n],h&&(r.commit=a[n+2])}r.ref=\"\",r.filepathtype=\"\",r.filepath=\"\";var b=a.length>n&&a[n+1]===\"-\"?n+1:n;a.length>b+2&&[\"raw\",\"src\",\"blob\",\"tree\",\"edit\"].indexOf(a[b+1])>=0&&(r.filepathtype=a[b+1],r.ref=a[b+2],a.length>b+3&&(r.filepath=a.slice(b+3).join(\"/\"))),r.organization=r.owner;break}r.full_name||(r.full_name=r.owner,r.name&&(r.full_name&&(r.full_name+=\"/\"),r.full_name+=r.name)),r.owner.startsWith(\"scm/\")&&(r.source=\"bitbucket-server\",r.owner=r.owner.replace(\"scm/\",\"\"),r.organization=r.owner,r.full_name=r.owner+\"/\"+r.name);var I=/(projects|users)\\/(.*?)\\/repos\\/(.*?)((\\/.*$)|$)/,T=I.exec(r.pathname);return T!=null&&(r.source=\"bitbucket-server\",T[1]===\"users\"?r.owner=\"~\"+T[2]:r.owner=T[2],r.organization=r.owner,r.name=T[3],a=T[4].split(\"/\"),a.length>1&&([\"raw\",\"browse\"].indexOf(a[1])>=0?(r.filepathtype=a[1],a.length>2&&(r.filepath=a.slice(2).join(\"/\"))):a[1]===\"commits\"&&a.length>2&&(r.commit=a[2])),r.full_name=r.owner+\"/\"+r.name,r.query.at?r.ref=r.query.at:r.ref=\"\"),r}n5.stringify=function(t,e){e=e||(t.protocols&&t.protocols.length?t.protocols.join(\"+\"):t.protocol);var r=t.port?\":\"+t.port:\"\",s=t.user||\"git\",a=t.git_suffix?\".git\":\"\";switch(e){case\"ssh\":return r?\"ssh://\"+s+\"@\"+t.resource+r+\"/\"+t.full_name+a:s+\"@\"+t.resource+\":\"+t.full_name+a;case\"git+ssh\":case\"ssh+git\":case\"ftp\":case\"ftps\":return e+\"://\"+s+\"@\"+t.resource+r+\"/\"+t.full_name+a;case\"http\":case\"https\":var n=t.token?Ect(t):t.user&&(t.protocols.includes(\"http\")||t.protocols.includes(\"https\"))?t.user+\"@\":\"\";return e+\"://\"+n+t.resource+r+\"/\"+Ict(t)+a;default:return t.href}};function Ect(t){switch(t.source){case\"bitbucket.org\":return\"x-token-auth:\"+t.token+\"@\";default:return t.token+\"@\"}}function Ict(t){switch(t.source){case\"bitbucket-server\":return\"scm/\"+t.full_name;default:return\"\"+t.full_name}}Oye.exports=n5});function Fct(t,e){return e===1&&Tct.has(t[0])}function nS(t){let e=Array.isArray(t)?t:Mu(t);return e.map((s,a)=>Qct.test(s)?`[${s}]`:Rct.test(s)&&!Fct(e,a)?`.${s}`:`[${JSON.stringify(s)}]`).join(\"\").replace(/^\\./,\"\")}function Nct(t,e){let r=[];if(e.methodName!==null&&r.push(he.pretty(t,e.methodName,he.Type.CODE)),e.file!==null){let s=[];s.push(he.pretty(t,e.file,he.Type.PATH)),e.line!==null&&(s.push(he.pretty(t,e.line,he.Type.NUMBER)),e.column!==null&&s.push(he.pretty(t,e.column,he.Type.NUMBER))),r.push(`(${s.join(he.pretty(t,\":\",\"grey\"))})`)}return r.join(\" \")}function nF(t,{manifestUpdates:e,reportedErrors:r},{fix:s}={}){let a=new Map,n=new Map,c=[...r.keys()].map(f=>[f,new Map]);for(let[f,p]of[...c,...e]){let h=r.get(f)?.map(b=>({text:b,fixable:!1}))??[],E=!1,C=t.getWorkspaceByCwd(f),S=C.manifest.exportTo({});for(let[b,I]of p){if(I.size>1){let T=[...I].map(([N,U])=>{let W=he.pretty(t.configuration,N,he.Type.INSPECT),ee=U.size>0?Nct(t.configuration,U.values().next().value):null;return ee!==null?`\n${W} at ${ee}`:`\n${W}`}).join(\"\");h.push({text:`Conflict detected in constraint targeting ${he.pretty(t.configuration,b,he.Type.CODE)}; conflicting values are:${T}`,fixable:!1})}else{let[[T]]=I,N=va(S,b);if(JSON.stringify(N)===JSON.stringify(T))continue;if(!s){let U=typeof N>\"u\"?`Missing field ${he.pretty(t.configuration,b,he.Type.CODE)}; expected ${he.pretty(t.configuration,T,he.Type.INSPECT)}`:typeof T>\"u\"?`Extraneous field ${he.pretty(t.configuration,b,he.Type.CODE)} currently set to ${he.pretty(t.configuration,N,he.Type.INSPECT)}`:`Invalid field ${he.pretty(t.configuration,b,he.Type.CODE)}; expected ${he.pretty(t.configuration,T,he.Type.INSPECT)}, found ${he.pretty(t.configuration,N,he.Type.INSPECT)}`;h.push({text:U,fixable:!0});continue}typeof T>\"u\"?A0(S,b):Jd(S,b,T),E=!0}E&&a.set(C,S)}h.length>0&&n.set(C,h)}return{changedWorkspaces:a,remainingErrors:n}}function Zye(t,{configuration:e}){let r={children:[]};for(let[s,a]of t){let n=[];for(let f of a){let p=f.text.split(/\\n/);f.fixable&&(p[0]=`${he.pretty(e,\"\\u2699\",\"gray\")} ${p[0]}`),n.push({value:he.tuple(he.Type.NO_HINT,p[0]),children:p.slice(1).map(h=>({value:he.tuple(he.Type.NO_HINT,h)}))})}let c={value:he.tuple(he.Type.LOCATOR,s.anchoredLocator),children:je.sortMap(n,f=>f.value[1])};r.children.push(c)}return r.children=je.sortMap(r.children,s=>s.value[1]),r}var WC,Qct,Rct,Tct,iS=Ze(()=>{Ge();ql();WC=class{constructor(e){this.indexedFields=e;this.items=[];this.indexes={};this.clear()}clear(){this.items=[];for(let e of this.indexedFields)this.indexes[e]=new Map}insert(e){this.items.push(e);for(let r of this.indexedFields){let s=Object.hasOwn(e,r)?e[r]:void 0;if(typeof s>\"u\")continue;je.getArrayWithDefault(this.indexes[r],s).push(e)}return e}find(e){if(typeof e>\"u\")return this.items;let r=Object.entries(e);if(r.length===0)return this.items;let s=[],a;for(let[c,f]of r){let p=c,h=Object.hasOwn(this.indexes,p)?this.indexes[p]:void 0;if(typeof h>\"u\"){s.push([p,f]);continue}let E=new Set(h.get(f)??[]);if(E.size===0)return[];if(typeof a>\"u\")a=E;else for(let C of a)E.has(C)||a.delete(C);if(a.size===0)break}let n=[...a??[]];return s.length>0&&(n=n.filter(c=>{for(let[f,p]of s)if(!(typeof p<\"u\"?Object.hasOwn(c,f)&&c[f]===p:Object.hasOwn(c,f)===!1))return!1;return!0})),n}},Qct=/^[0-9]+$/,Rct=/^[a-zA-Z0-9_]+$/,Tct=new Set([\"scripts\",...Ut.allDependencies])});var Xye=_((CYt,m5)=>{var Oct;(function(t){var e=function(){return{\"append/2\":[new t.type.Rule(new t.type.Term(\"append\",[new t.type.Var(\"X\"),new t.type.Var(\"L\")]),new t.type.Term(\"foldl\",[new t.type.Term(\"append\",[]),new t.type.Var(\"X\"),new t.type.Term(\"[]\",[]),new t.type.Var(\"L\")]))],\"append/3\":[new t.type.Rule(new t.type.Term(\"append\",[new t.type.Term(\"[]\",[]),new t.type.Var(\"X\"),new t.type.Var(\"X\")]),null),new t.type.Rule(new t.type.Term(\"append\",[new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"T\")]),new t.type.Var(\"X\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"S\")])]),new t.type.Term(\"append\",[new t.type.Var(\"T\"),new t.type.Var(\"X\"),new t.type.Var(\"S\")]))],\"member/2\":[new t.type.Rule(new t.type.Term(\"member\",[new t.type.Var(\"X\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"_\")])]),null),new t.type.Rule(new t.type.Term(\"member\",[new t.type.Var(\"X\"),new t.type.Term(\".\",[new t.type.Var(\"_\"),new t.type.Var(\"Xs\")])]),new t.type.Term(\"member\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]))],\"permutation/2\":[new t.type.Rule(new t.type.Term(\"permutation\",[new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"permutation\",[new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"T\")]),new t.type.Var(\"S\")]),new t.type.Term(\",\",[new t.type.Term(\"permutation\",[new t.type.Var(\"T\"),new t.type.Var(\"P\")]),new t.type.Term(\",\",[new t.type.Term(\"append\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"P\")]),new t.type.Term(\"append\",[new t.type.Var(\"X\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"Y\")]),new t.type.Var(\"S\")])])]))],\"maplist/2\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"X\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"Xs\")])]))],\"maplist/3\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"A\"),new t.type.Var(\"As\")]),new t.type.Term(\".\",[new t.type.Var(\"B\"),new t.type.Var(\"Bs\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"A\"),new t.type.Var(\"B\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"As\"),new t.type.Var(\"Bs\")])]))],\"maplist/4\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"A\"),new t.type.Var(\"As\")]),new t.type.Term(\".\",[new t.type.Var(\"B\"),new t.type.Var(\"Bs\")]),new t.type.Term(\".\",[new t.type.Var(\"C\"),new t.type.Var(\"Cs\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"A\"),new t.type.Var(\"B\"),new t.type.Var(\"C\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"As\"),new t.type.Var(\"Bs\"),new t.type.Var(\"Cs\")])]))],\"maplist/5\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"A\"),new t.type.Var(\"As\")]),new t.type.Term(\".\",[new t.type.Var(\"B\"),new t.type.Var(\"Bs\")]),new t.type.Term(\".\",[new t.type.Var(\"C\"),new t.type.Var(\"Cs\")]),new t.type.Term(\".\",[new t.type.Var(\"D\"),new t.type.Var(\"Ds\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"A\"),new t.type.Var(\"B\"),new t.type.Var(\"C\"),new t.type.Var(\"D\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"As\"),new t.type.Var(\"Bs\"),new t.type.Var(\"Cs\"),new t.type.Var(\"Ds\")])]))],\"maplist/6\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"A\"),new t.type.Var(\"As\")]),new t.type.Term(\".\",[new t.type.Var(\"B\"),new t.type.Var(\"Bs\")]),new t.type.Term(\".\",[new t.type.Var(\"C\"),new t.type.Var(\"Cs\")]),new t.type.Term(\".\",[new t.type.Var(\"D\"),new t.type.Var(\"Ds\")]),new t.type.Term(\".\",[new t.type.Var(\"E\"),new t.type.Var(\"Es\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"A\"),new t.type.Var(\"B\"),new t.type.Var(\"C\"),new t.type.Var(\"D\"),new t.type.Var(\"E\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"As\"),new t.type.Var(\"Bs\"),new t.type.Var(\"Cs\"),new t.type.Var(\"Ds\"),new t.type.Var(\"Es\")])]))],\"maplist/7\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"A\"),new t.type.Var(\"As\")]),new t.type.Term(\".\",[new t.type.Var(\"B\"),new t.type.Var(\"Bs\")]),new t.type.Term(\".\",[new t.type.Var(\"C\"),new t.type.Var(\"Cs\")]),new t.type.Term(\".\",[new t.type.Var(\"D\"),new t.type.Var(\"Ds\")]),new t.type.Term(\".\",[new t.type.Var(\"E\"),new t.type.Var(\"Es\")]),new t.type.Term(\".\",[new t.type.Var(\"F\"),new t.type.Var(\"Fs\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"A\"),new t.type.Var(\"B\"),new t.type.Var(\"C\"),new t.type.Var(\"D\"),new t.type.Var(\"E\"),new t.type.Var(\"F\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"As\"),new t.type.Var(\"Bs\"),new t.type.Var(\"Cs\"),new t.type.Var(\"Ds\"),new t.type.Var(\"Es\"),new t.type.Var(\"Fs\")])]))],\"maplist/8\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"A\"),new t.type.Var(\"As\")]),new t.type.Term(\".\",[new t.type.Var(\"B\"),new t.type.Var(\"Bs\")]),new t.type.Term(\".\",[new t.type.Var(\"C\"),new t.type.Var(\"Cs\")]),new t.type.Term(\".\",[new t.type.Var(\"D\"),new t.type.Var(\"Ds\")]),new t.type.Term(\".\",[new t.type.Var(\"E\"),new t.type.Var(\"Es\")]),new t.type.Term(\".\",[new t.type.Var(\"F\"),new t.type.Var(\"Fs\")]),new t.type.Term(\".\",[new t.type.Var(\"G\"),new t.type.Var(\"Gs\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"A\"),new t.type.Var(\"B\"),new t.type.Var(\"C\"),new t.type.Var(\"D\"),new t.type.Var(\"E\"),new t.type.Var(\"F\"),new t.type.Var(\"G\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"As\"),new t.type.Var(\"Bs\"),new t.type.Var(\"Cs\"),new t.type.Var(\"Ds\"),new t.type.Var(\"Es\"),new t.type.Var(\"Fs\"),new t.type.Var(\"Gs\")])]))],\"include/3\":[new t.type.Rule(new t.type.Term(\"include\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"include\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"T\")]),new t.type.Var(\"L\")]),new t.type.Term(\",\",[new t.type.Term(\"=..\",[new t.type.Var(\"P\"),new t.type.Var(\"A\")]),new t.type.Term(\",\",[new t.type.Term(\"append\",[new t.type.Var(\"A\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Term(\"[]\",[])]),new t.type.Var(\"B\")]),new t.type.Term(\",\",[new t.type.Term(\"=..\",[new t.type.Var(\"F\"),new t.type.Var(\"B\")]),new t.type.Term(\",\",[new t.type.Term(\";\",[new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"F\")]),new t.type.Term(\",\",[new t.type.Term(\"=\",[new t.type.Var(\"L\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"S\")])]),new t.type.Term(\"!\",[])])]),new t.type.Term(\"=\",[new t.type.Var(\"L\"),new t.type.Var(\"S\")])]),new t.type.Term(\"include\",[new t.type.Var(\"P\"),new t.type.Var(\"T\"),new t.type.Var(\"S\")])])])])]))],\"exclude/3\":[new t.type.Rule(new t.type.Term(\"exclude\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"exclude\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"T\")]),new t.type.Var(\"S\")]),new t.type.Term(\",\",[new t.type.Term(\"exclude\",[new t.type.Var(\"P\"),new t.type.Var(\"T\"),new t.type.Var(\"E\")]),new t.type.Term(\",\",[new t.type.Term(\"=..\",[new t.type.Var(\"P\"),new t.type.Var(\"L\")]),new t.type.Term(\",\",[new t.type.Term(\"append\",[new t.type.Var(\"L\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Term(\"[]\",[])]),new t.type.Var(\"Q\")]),new t.type.Term(\",\",[new t.type.Term(\"=..\",[new t.type.Var(\"R\"),new t.type.Var(\"Q\")]),new t.type.Term(\";\",[new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"R\")]),new t.type.Term(\",\",[new t.type.Term(\"!\",[]),new t.type.Term(\"=\",[new t.type.Var(\"S\"),new t.type.Var(\"E\")])])]),new t.type.Term(\"=\",[new t.type.Var(\"S\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"E\")])])])])])])]))],\"foldl/4\":[new t.type.Rule(new t.type.Term(\"foldl\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Var(\"I\"),new t.type.Var(\"I\")]),null),new t.type.Rule(new t.type.Term(\"foldl\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"T\")]),new t.type.Var(\"I\"),new t.type.Var(\"R\")]),new t.type.Term(\",\",[new t.type.Term(\"=..\",[new t.type.Var(\"P\"),new t.type.Var(\"L\")]),new t.type.Term(\",\",[new t.type.Term(\"append\",[new t.type.Var(\"L\"),new t.type.Term(\".\",[new t.type.Var(\"I\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Term(\"[]\",[])])])]),new t.type.Var(\"L2\")]),new t.type.Term(\",\",[new t.type.Term(\"=..\",[new t.type.Var(\"P2\"),new t.type.Var(\"L2\")]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P2\")]),new t.type.Term(\"foldl\",[new t.type.Var(\"P\"),new t.type.Var(\"T\"),new t.type.Var(\"X\"),new t.type.Var(\"R\")])])])])]))],\"select/3\":[new t.type.Rule(new t.type.Term(\"select\",[new t.type.Var(\"E\"),new t.type.Term(\".\",[new t.type.Var(\"E\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"Xs\")]),null),new t.type.Rule(new t.type.Term(\"select\",[new t.type.Var(\"E\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Ys\")])]),new t.type.Term(\"select\",[new t.type.Var(\"E\"),new t.type.Var(\"Xs\"),new t.type.Var(\"Ys\")]))],\"sum_list/2\":[new t.type.Rule(new t.type.Term(\"sum_list\",[new t.type.Term(\"[]\",[]),new t.type.Num(0,!1)]),null),new t.type.Rule(new t.type.Term(\"sum_list\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"S\")]),new t.type.Term(\",\",[new t.type.Term(\"sum_list\",[new t.type.Var(\"Xs\"),new t.type.Var(\"Y\")]),new t.type.Term(\"is\",[new t.type.Var(\"S\"),new t.type.Term(\"+\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\")])])]))],\"max_list/2\":[new t.type.Rule(new t.type.Term(\"max_list\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Term(\"[]\",[])]),new t.type.Var(\"X\")]),null),new t.type.Rule(new t.type.Term(\"max_list\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"S\")]),new t.type.Term(\",\",[new t.type.Term(\"max_list\",[new t.type.Var(\"Xs\"),new t.type.Var(\"Y\")]),new t.type.Term(\";\",[new t.type.Term(\",\",[new t.type.Term(\">=\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\")]),new t.type.Term(\",\",[new t.type.Term(\"=\",[new t.type.Var(\"S\"),new t.type.Var(\"X\")]),new t.type.Term(\"!\",[])])]),new t.type.Term(\"=\",[new t.type.Var(\"S\"),new t.type.Var(\"Y\")])])]))],\"min_list/2\":[new t.type.Rule(new t.type.Term(\"min_list\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Term(\"[]\",[])]),new t.type.Var(\"X\")]),null),new t.type.Rule(new t.type.Term(\"min_list\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"S\")]),new t.type.Term(\",\",[new t.type.Term(\"min_list\",[new t.type.Var(\"Xs\"),new t.type.Var(\"Y\")]),new t.type.Term(\";\",[new t.type.Term(\",\",[new t.type.Term(\"=<\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\")]),new t.type.Term(\",\",[new t.type.Term(\"=\",[new t.type.Var(\"S\"),new t.type.Var(\"X\")]),new t.type.Term(\"!\",[])])]),new t.type.Term(\"=\",[new t.type.Var(\"S\"),new t.type.Var(\"Y\")])])]))],\"prod_list/2\":[new t.type.Rule(new t.type.Term(\"prod_list\",[new t.type.Term(\"[]\",[]),new t.type.Num(1,!1)]),null),new t.type.Rule(new t.type.Term(\"prod_list\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"S\")]),new t.type.Term(\",\",[new t.type.Term(\"prod_list\",[new t.type.Var(\"Xs\"),new t.type.Var(\"Y\")]),new t.type.Term(\"is\",[new t.type.Var(\"S\"),new t.type.Term(\"*\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\")])])]))],\"last/2\":[new t.type.Rule(new t.type.Term(\"last\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Term(\"[]\",[])]),new t.type.Var(\"X\")]),null),new t.type.Rule(new t.type.Term(\"last\",[new t.type.Term(\".\",[new t.type.Var(\"_\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"X\")]),new t.type.Term(\"last\",[new t.type.Var(\"Xs\"),new t.type.Var(\"X\")]))],\"prefix/2\":[new t.type.Rule(new t.type.Term(\"prefix\",[new t.type.Var(\"Part\"),new t.type.Var(\"Whole\")]),new t.type.Term(\"append\",[new t.type.Var(\"Part\"),new t.type.Var(\"_\"),new t.type.Var(\"Whole\")]))],\"nth0/3\":[new t.type.Rule(new t.type.Term(\"nth0\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\")]),new t.type.Term(\";\",[new t.type.Term(\"->\",[new t.type.Term(\"var\",[new t.type.Var(\"X\")]),new t.type.Term(\"nth\",[new t.type.Num(0,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"_\")])]),new t.type.Term(\",\",[new t.type.Term(\">=\",[new t.type.Var(\"X\"),new t.type.Num(0,!1)]),new t.type.Term(\",\",[new t.type.Term(\"nth\",[new t.type.Num(0,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"_\")]),new t.type.Term(\"!\",[])])])]))],\"nth1/3\":[new t.type.Rule(new t.type.Term(\"nth1\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\")]),new t.type.Term(\";\",[new t.type.Term(\"->\",[new t.type.Term(\"var\",[new t.type.Var(\"X\")]),new t.type.Term(\"nth\",[new t.type.Num(1,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"_\")])]),new t.type.Term(\",\",[new t.type.Term(\">\",[new t.type.Var(\"X\"),new t.type.Num(0,!1)]),new t.type.Term(\",\",[new t.type.Term(\"nth\",[new t.type.Num(1,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"_\")]),new t.type.Term(\"!\",[])])])]))],\"nth0/4\":[new t.type.Rule(new t.type.Term(\"nth0\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"W\")]),new t.type.Term(\";\",[new t.type.Term(\"->\",[new t.type.Term(\"var\",[new t.type.Var(\"X\")]),new t.type.Term(\"nth\",[new t.type.Num(0,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"W\")])]),new t.type.Term(\",\",[new t.type.Term(\">=\",[new t.type.Var(\"X\"),new t.type.Num(0,!1)]),new t.type.Term(\",\",[new t.type.Term(\"nth\",[new t.type.Num(0,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"W\")]),new t.type.Term(\"!\",[])])])]))],\"nth1/4\":[new t.type.Rule(new t.type.Term(\"nth1\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"W\")]),new t.type.Term(\";\",[new t.type.Term(\"->\",[new t.type.Term(\"var\",[new t.type.Var(\"X\")]),new t.type.Term(\"nth\",[new t.type.Num(1,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"W\")])]),new t.type.Term(\",\",[new t.type.Term(\">\",[new t.type.Var(\"X\"),new t.type.Num(0,!1)]),new t.type.Term(\",\",[new t.type.Term(\"nth\",[new t.type.Num(1,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"W\")]),new t.type.Term(\"!\",[])])])]))],\"nth/5\":[new t.type.Rule(new t.type.Term(\"nth\",[new t.type.Var(\"N\"),new t.type.Var(\"N\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),null),new t.type.Rule(new t.type.Term(\"nth\",[new t.type.Var(\"N\"),new t.type.Var(\"O\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"Y\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Ys\")])]),new t.type.Term(\",\",[new t.type.Term(\"is\",[new t.type.Var(\"M\"),new t.type.Term(\"+\",[new t.type.Var(\"N\"),new t.type.Num(1,!1)])]),new t.type.Term(\"nth\",[new t.type.Var(\"M\"),new t.type.Var(\"O\"),new t.type.Var(\"Xs\"),new t.type.Var(\"Y\"),new t.type.Var(\"Ys\")])]))],\"length/2\":function(s,a,n){var c=n.args[0],f=n.args[1];if(!t.type.is_variable(f)&&!t.type.is_integer(f))s.throw_error(t.error.type(\"integer\",f,n.indicator));else if(t.type.is_integer(f)&&f.value<0)s.throw_error(t.error.domain(\"not_less_than_zero\",f,n.indicator));else{var p=new t.type.Term(\"length\",[c,new t.type.Num(0,!1),f]);t.type.is_integer(f)&&(p=new t.type.Term(\",\",[p,new t.type.Term(\"!\",[])])),s.prepend([new t.type.State(a.goal.replace(p),a.substitution,a)])}},\"length/3\":[new t.type.Rule(new t.type.Term(\"length\",[new t.type.Term(\"[]\",[]),new t.type.Var(\"N\"),new t.type.Var(\"N\")]),null),new t.type.Rule(new t.type.Term(\"length\",[new t.type.Term(\".\",[new t.type.Var(\"_\"),new t.type.Var(\"X\")]),new t.type.Var(\"A\"),new t.type.Var(\"N\")]),new t.type.Term(\",\",[new t.type.Term(\"succ\",[new t.type.Var(\"A\"),new t.type.Var(\"B\")]),new t.type.Term(\"length\",[new t.type.Var(\"X\"),new t.type.Var(\"B\"),new t.type.Var(\"N\")])]))],\"replicate/3\":function(s,a,n){var c=n.args[0],f=n.args[1],p=n.args[2];if(t.type.is_variable(f))s.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_integer(f))s.throw_error(t.error.type(\"integer\",f,n.indicator));else if(f.value<0)s.throw_error(t.error.domain(\"not_less_than_zero\",f,n.indicator));else if(!t.type.is_variable(p)&&!t.type.is_list(p))s.throw_error(t.error.type(\"list\",p,n.indicator));else{for(var h=new t.type.Term(\"[]\"),E=0;E<f.value;E++)h=new t.type.Term(\".\",[c,h]);s.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[h,p])),a.substitution,a)])}},\"sort/2\":function(s,a,n){var c=n.args[0],f=n.args[1];if(t.type.is_variable(c))s.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_variable(f)&&!t.type.is_fully_list(f))s.throw_error(t.error.type(\"list\",f,n.indicator));else{for(var p=[],h=c;h.indicator===\"./2\";)p.push(h.args[0]),h=h.args[1];if(t.type.is_variable(h))s.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_empty_list(h))s.throw_error(t.error.type(\"list\",c,n.indicator));else{for(var E=p.sort(t.compare),C=E.length-1;C>0;C--)E[C].equals(E[C-1])&&E.splice(C,1);for(var S=new t.type.Term(\"[]\"),C=E.length-1;C>=0;C--)S=new t.type.Term(\".\",[E[C],S]);s.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[S,f])),a.substitution,a)])}}},\"msort/2\":function(s,a,n){var c=n.args[0],f=n.args[1];if(t.type.is_variable(c))s.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_variable(f)&&!t.type.is_fully_list(f))s.throw_error(t.error.type(\"list\",f,n.indicator));else{for(var p=[],h=c;h.indicator===\"./2\";)p.push(h.args[0]),h=h.args[1];if(t.type.is_variable(h))s.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_empty_list(h))s.throw_error(t.error.type(\"list\",c,n.indicator));else{for(var E=p.sort(t.compare),C=new t.type.Term(\"[]\"),S=E.length-1;S>=0;S--)C=new t.type.Term(\".\",[E[S],C]);s.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[C,f])),a.substitution,a)])}}},\"keysort/2\":function(s,a,n){var c=n.args[0],f=n.args[1];if(t.type.is_variable(c))s.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_variable(f)&&!t.type.is_fully_list(f))s.throw_error(t.error.type(\"list\",f,n.indicator));else{for(var p=[],h,E=c;E.indicator===\"./2\";){if(h=E.args[0],t.type.is_variable(h)){s.throw_error(t.error.instantiation(n.indicator));return}else if(!t.type.is_term(h)||h.indicator!==\"-/2\"){s.throw_error(t.error.type(\"pair\",h,n.indicator));return}h.args[0].pair=h.args[1],p.push(h.args[0]),E=E.args[1]}if(t.type.is_variable(E))s.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_empty_list(E))s.throw_error(t.error.type(\"list\",c,n.indicator));else{for(var C=p.sort(t.compare),S=new t.type.Term(\"[]\"),b=C.length-1;b>=0;b--)S=new t.type.Term(\".\",[new t.type.Term(\"-\",[C[b],C[b].pair]),S]),delete C[b].pair;s.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[S,f])),a.substitution,a)])}}},\"take/3\":function(s,a,n){var c=n.args[0],f=n.args[1],p=n.args[2];if(t.type.is_variable(f)||t.type.is_variable(c))s.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_list(f))s.throw_error(t.error.type(\"list\",f,n.indicator));else if(!t.type.is_integer(c))s.throw_error(t.error.type(\"integer\",c,n.indicator));else if(!t.type.is_variable(p)&&!t.type.is_list(p))s.throw_error(t.error.type(\"list\",p,n.indicator));else{for(var h=c.value,E=[],C=f;h>0&&C.indicator===\"./2\";)E.push(C.args[0]),C=C.args[1],h--;if(h===0){for(var S=new t.type.Term(\"[]\"),h=E.length-1;h>=0;h--)S=new t.type.Term(\".\",[E[h],S]);s.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[S,p])),a.substitution,a)])}}},\"drop/3\":function(s,a,n){var c=n.args[0],f=n.args[1],p=n.args[2];if(t.type.is_variable(f)||t.type.is_variable(c))s.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_list(f))s.throw_error(t.error.type(\"list\",f,n.indicator));else if(!t.type.is_integer(c))s.throw_error(t.error.type(\"integer\",c,n.indicator));else if(!t.type.is_variable(p)&&!t.type.is_list(p))s.throw_error(t.error.type(\"list\",p,n.indicator));else{for(var h=c.value,E=[],C=f;h>0&&C.indicator===\"./2\";)E.push(C.args[0]),C=C.args[1],h--;h===0&&s.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[C,p])),a.substitution,a)])}},\"reverse/2\":function(s,a,n){var c=n.args[0],f=n.args[1],p=t.type.is_instantiated_list(c),h=t.type.is_instantiated_list(f);if(t.type.is_variable(c)&&t.type.is_variable(f))s.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_variable(c)&&!t.type.is_fully_list(c))s.throw_error(t.error.type(\"list\",c,n.indicator));else if(!t.type.is_variable(f)&&!t.type.is_fully_list(f))s.throw_error(t.error.type(\"list\",f,n.indicator));else if(!p&&!h)s.throw_error(t.error.instantiation(n.indicator));else{for(var E=p?c:f,C=new t.type.Term(\"[]\",[]);E.indicator===\"./2\";)C=new t.type.Term(\".\",[E.args[0],C]),E=E.args[1];s.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[C,p?f:c])),a.substitution,a)])}},\"list_to_set/2\":function(s,a,n){var c=n.args[0],f=n.args[1];if(t.type.is_variable(c))s.throw_error(t.error.instantiation(n.indicator));else{for(var p=c,h=[];p.indicator===\"./2\";)h.push(p.args[0]),p=p.args[1];if(t.type.is_variable(p))s.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_term(p)||p.indicator!==\"[]/0\")s.throw_error(t.error.type(\"list\",c,n.indicator));else{for(var E=[],C=new t.type.Term(\"[]\",[]),S,b=0;b<h.length;b++){S=!1;for(var I=0;I<E.length&&!S;I++)S=t.compare(h[b],E[I])===0;S||E.push(h[b])}for(b=E.length-1;b>=0;b--)C=new t.type.Term(\".\",[E[b],C]);s.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[f,C])),a.substitution,a)])}}}}},r=[\"append/2\",\"append/3\",\"member/2\",\"permutation/2\",\"maplist/2\",\"maplist/3\",\"maplist/4\",\"maplist/5\",\"maplist/6\",\"maplist/7\",\"maplist/8\",\"include/3\",\"exclude/3\",\"foldl/4\",\"sum_list/2\",\"max_list/2\",\"min_list/2\",\"prod_list/2\",\"last/2\",\"prefix/2\",\"nth0/3\",\"nth1/3\",\"nth0/4\",\"nth1/4\",\"length/2\",\"replicate/3\",\"select/3\",\"sort/2\",\"msort/2\",\"keysort/2\",\"take/3\",\"drop/3\",\"reverse/2\",\"list_to_set/2\"];typeof m5<\"u\"?m5.exports=function(s){t=s,new t.type.Module(\"lists\",e(),r)}:new t.type.Module(\"lists\",e(),r)})(Oct)});var pEe=_($r=>{\"use strict\";var Pm=process.platform===\"win32\",y5=\"aes-256-cbc\",Lct=\"sha256\",tEe=\"The current environment doesn't support interactive reading from TTY.\",si=Ie(\"fs\"),$ye=process.binding(\"tty_wrap\").TTY,I5=Ie(\"child_process\"),V0=Ie(\"path\"),C5={prompt:\"> \",hideEchoBack:!1,mask:\"*\",limit:[],limitMessage:\"Input another, please.$<( [)limit(])>\",defaultInput:\"\",trueValue:[],falseValue:[],caseSensitive:!1,keepWhitespace:!1,encoding:\"utf8\",bufferSize:1024,print:void 0,history:!0,cd:!1,phContent:void 0,preCheck:void 0},Zp=\"none\",Xu,VC,eEe=!1,Y0,sF,E5,Mct=0,D5=\"\",Dm=[],oF,rEe=!1,w5=!1,sS=!1;function nEe(t){function e(r){return r.replace(/[^\\w\\u0080-\\uFFFF]/g,function(s){return\"#\"+s.charCodeAt(0)+\";\"})}return sF.concat(function(r){var s=[];return Object.keys(r).forEach(function(a){r[a]===\"boolean\"?t[a]&&s.push(\"--\"+a):r[a]===\"string\"&&t[a]&&s.push(\"--\"+a,e(t[a]))}),s}({display:\"string\",displayOnly:\"boolean\",keyIn:\"boolean\",hideEchoBack:\"boolean\",mask:\"string\",limit:\"string\",caseSensitive:\"boolean\"}))}function Uct(t,e){function r(U){var W,ee=\"\",ie;for(E5=E5||Ie(\"os\").tmpdir();;){W=V0.join(E5,U+ee);try{ie=si.openSync(W,\"wx\")}catch(ue){if(ue.code===\"EEXIST\"){ee++;continue}else throw ue}si.closeSync(ie);break}return W}var s,a,n,c={},f,p,h=r(\"readline-sync.stdout\"),E=r(\"readline-sync.stderr\"),C=r(\"readline-sync.exit\"),S=r(\"readline-sync.done\"),b=Ie(\"crypto\"),I,T,N;I=b.createHash(Lct),I.update(\"\"+process.pid+Mct+++Math.random()),N=I.digest(\"hex\"),T=b.createDecipher(y5,N),s=nEe(t),Pm?(a=process.env.ComSpec||\"cmd.exe\",process.env.Q='\"',n=[\"/V:ON\",\"/S\",\"/C\",\"(%Q%\"+a+\"%Q% /V:ON /S /C %Q%%Q%\"+Y0+\"%Q%\"+s.map(function(U){return\" %Q%\"+U+\"%Q%\"}).join(\"\")+\" & (echo !ERRORLEVEL!)>%Q%\"+C+\"%Q%%Q%) 2>%Q%\"+E+\"%Q% |%Q%\"+process.execPath+\"%Q% %Q%\"+__dirname+\"\\\\encrypt.js%Q% %Q%\"+y5+\"%Q% %Q%\"+N+\"%Q% >%Q%\"+h+\"%Q% & (echo 1)>%Q%\"+S+\"%Q%\"]):(a=\"/bin/sh\",n=[\"-c\",'(\"'+Y0+'\"'+s.map(function(U){return\" '\"+U.replace(/'/g,\"'\\\\''\")+\"'\"}).join(\"\")+'; echo $?>\"'+C+'\") 2>\"'+E+'\" |\"'+process.execPath+'\" \"'+__dirname+'/encrypt.js\" \"'+y5+'\" \"'+N+'\" >\"'+h+'\"; echo 1 >\"'+S+'\"']),sS&&sS(\"_execFileSync\",s);try{I5.spawn(a,n,e)}catch(U){c.error=new Error(U.message),c.error.method=\"_execFileSync - spawn\",c.error.program=a,c.error.args=n}for(;si.readFileSync(S,{encoding:t.encoding}).trim()!==\"1\";);return(f=si.readFileSync(C,{encoding:t.encoding}).trim())===\"0\"?c.input=T.update(si.readFileSync(h,{encoding:\"binary\"}),\"hex\",t.encoding)+T.final(t.encoding):(p=si.readFileSync(E,{encoding:t.encoding}).trim(),c.error=new Error(tEe+(p?`\n`+p:\"\")),c.error.method=\"_execFileSync\",c.error.program=a,c.error.args=n,c.error.extMessage=p,c.error.exitCode=+f),si.unlinkSync(h),si.unlinkSync(E),si.unlinkSync(C),si.unlinkSync(S),c}function _ct(t){var e,r={},s,a={env:process.env,encoding:t.encoding};if(Y0||(Pm?process.env.PSModulePath?(Y0=\"powershell.exe\",sF=[\"-ExecutionPolicy\",\"Bypass\",\"-File\",__dirname+\"\\\\read.ps1\"]):(Y0=\"cscript.exe\",sF=[\"//nologo\",__dirname+\"\\\\read.cs.js\"]):(Y0=\"/bin/sh\",sF=[__dirname+\"/read.sh\"])),Pm&&!process.env.PSModulePath&&(a.stdio=[process.stdin]),I5.execFileSync){e=nEe(t),sS&&sS(\"execFileSync\",e);try{r.input=I5.execFileSync(Y0,e,a)}catch(n){s=n.stderr?(n.stderr+\"\").trim():\"\",r.error=new Error(tEe+(s?`\n`+s:\"\")),r.error.method=\"execFileSync\",r.error.program=Y0,r.error.args=e,r.error.extMessage=s,r.error.exitCode=n.status,r.error.code=n.code,r.error.signal=n.signal}}else r=Uct(t,a);return r.error||(r.input=r.input.replace(/^\\s*'|'\\s*$/g,\"\"),t.display=\"\"),r}function B5(t){var e=\"\",r=t.display,s=!t.display&&t.keyIn&&t.hideEchoBack&&!t.mask;function a(){var n=_ct(t);if(n.error)throw n.error;return n.input}return w5&&w5(t),function(){var n,c,f;function p(){return n||(n=process.binding(\"fs\"),c=process.binding(\"constants\")),n}if(typeof Zp==\"string\")if(Zp=null,Pm){if(f=function(h){var E=h.replace(/^\\D+/,\"\").split(\".\"),C=0;return(E[0]=+E[0])&&(C+=E[0]*1e4),(E[1]=+E[1])&&(C+=E[1]*100),(E[2]=+E[2])&&(C+=E[2]),C}(process.version),!(f>=20302&&f<40204||f>=5e4&&f<50100||f>=50600&&f<60200)&&process.stdin.isTTY)process.stdin.pause(),Zp=process.stdin.fd,VC=process.stdin._handle;else try{Zp=p().open(\"CONIN$\",c.O_RDWR,parseInt(\"0666\",8)),VC=new $ye(Zp,!0)}catch{}if(process.stdout.isTTY)Xu=process.stdout.fd;else{try{Xu=si.openSync(\"\\\\\\\\.\\\\CON\",\"w\")}catch{}if(typeof Xu!=\"number\")try{Xu=p().open(\"CONOUT$\",c.O_RDWR,parseInt(\"0666\",8))}catch{}}}else{if(process.stdin.isTTY){process.stdin.pause();try{Zp=si.openSync(\"/dev/tty\",\"r\"),VC=process.stdin._handle}catch{}}else try{Zp=si.openSync(\"/dev/tty\",\"r\"),VC=new $ye(Zp,!1)}catch{}if(process.stdout.isTTY)Xu=process.stdout.fd;else try{Xu=si.openSync(\"/dev/tty\",\"w\")}catch{}}}(),function(){var n,c,f=!t.hideEchoBack&&!t.keyIn,p,h,E,C,S;oF=\"\";function b(I){return I===eEe?!0:VC.setRawMode(I)!==0?!1:(eEe=I,!0)}if(rEe||!VC||typeof Xu!=\"number\"&&(t.display||!f)){e=a();return}if(t.display&&(si.writeSync(Xu,t.display),t.display=\"\"),!t.displayOnly){if(!b(!f)){e=a();return}for(h=t.keyIn?1:t.bufferSize,p=Buffer.allocUnsafe&&Buffer.alloc?Buffer.alloc(h):new Buffer(h),t.keyIn&&t.limit&&(c=new RegExp(\"[^\"+t.limit+\"]\",\"g\"+(t.caseSensitive?\"\":\"i\")));;){E=0;try{E=si.readSync(Zp,p,0,h)}catch(I){if(I.code!==\"EOF\"){b(!1),e+=a();return}}if(E>0?(C=p.toString(t.encoding,0,E),oF+=C):(C=`\n`,oF+=\"\\0\"),C&&typeof(S=(C.match(/^(.*?)[\\r\\n]/)||[])[1])==\"string\"&&(C=S,n=!0),C&&(C=C.replace(/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]/g,\"\")),C&&c&&(C=C.replace(c,\"\")),C&&(f||(t.hideEchoBack?t.mask&&si.writeSync(Xu,new Array(C.length+1).join(t.mask)):si.writeSync(Xu,C)),e+=C),!t.keyIn&&n||t.keyIn&&e.length>=h)break}!f&&!s&&si.writeSync(Xu,`\n`),b(!1)}}(),t.print&&!s&&t.print(r+(t.displayOnly?\"\":(t.hideEchoBack?new Array(e.length+1).join(t.mask):e)+`\n`),t.encoding),t.displayOnly?\"\":D5=t.keepWhitespace||t.keyIn?e:e.trim()}function Hct(t,e){var r=[];function s(a){a!=null&&(Array.isArray(a)?a.forEach(s):(!e||e(a))&&r.push(a))}return s(t),r}function P5(t){return t.replace(/[\\x00-\\x7f]/g,function(e){return\"\\\\x\"+(\"00\"+e.charCodeAt().toString(16)).substr(-2)})}function Vs(){var t=Array.prototype.slice.call(arguments),e,r;return t.length&&typeof t[0]==\"boolean\"&&(r=t.shift(),r&&(e=Object.keys(C5),t.unshift(C5))),t.reduce(function(s,a){return a==null||(a.hasOwnProperty(\"noEchoBack\")&&!a.hasOwnProperty(\"hideEchoBack\")&&(a.hideEchoBack=a.noEchoBack,delete a.noEchoBack),a.hasOwnProperty(\"noTrim\")&&!a.hasOwnProperty(\"keepWhitespace\")&&(a.keepWhitespace=a.noTrim,delete a.noTrim),r||(e=Object.keys(a)),e.forEach(function(n){var c;if(a.hasOwnProperty(n))switch(c=a[n],n){case\"mask\":case\"limitMessage\":case\"defaultInput\":case\"encoding\":c=c!=null?c+\"\":\"\",c&&n!==\"limitMessage\"&&(c=c.replace(/[\\r\\n]/g,\"\")),s[n]=c;break;case\"bufferSize\":!isNaN(c=parseInt(c,10))&&typeof c==\"number\"&&(s[n]=c);break;case\"displayOnly\":case\"keyIn\":case\"hideEchoBack\":case\"caseSensitive\":case\"keepWhitespace\":case\"history\":case\"cd\":s[n]=!!c;break;case\"limit\":case\"trueValue\":case\"falseValue\":s[n]=Hct(c,function(f){var p=typeof f;return p===\"string\"||p===\"number\"||p===\"function\"||f instanceof RegExp}).map(function(f){return typeof f==\"string\"?f.replace(/[\\r\\n]/g,\"\"):f});break;case\"print\":case\"phContent\":case\"preCheck\":s[n]=typeof c==\"function\"?c:void 0;break;case\"prompt\":case\"display\":s[n]=c??\"\";break}})),s},{})}function v5(t,e,r){return e.some(function(s){var a=typeof s;return a===\"string\"?r?t===s:t.toLowerCase()===s.toLowerCase():a===\"number\"?parseFloat(t)===s:a===\"function\"?s(t):s instanceof RegExp?s.test(t):!1})}function b5(t,e){var r=V0.normalize(Pm?(process.env.HOMEDRIVE||\"\")+(process.env.HOMEPATH||\"\"):process.env.HOME||\"\").replace(/[\\/\\\\]+$/,\"\");return t=V0.normalize(t),e?t.replace(/^~(?=\\/|\\\\|$)/,r):t.replace(new RegExp(\"^\"+P5(r)+\"(?=\\\\/|\\\\\\\\|$)\",Pm?\"i\":\"\"),\"~\")}function JC(t,e){var r=\"(?:\\\\(([\\\\s\\\\S]*?)\\\\))?(\\\\w+|.-.)(?:\\\\(([\\\\s\\\\S]*?)\\\\))?\",s=new RegExp(\"(\\\\$)?(\\\\$<\"+r+\">)\",\"g\"),a=new RegExp(\"(\\\\$)?(\\\\$\\\\{\"+r+\"\\\\})\",\"g\");function n(c,f,p,h,E,C){var S;return f||typeof(S=e(E))!=\"string\"?p:S?(h||\"\")+S+(C||\"\"):\"\"}return t.replace(s,n).replace(a,n)}function iEe(t,e,r){var s,a=[],n=-1,c=0,f=\"\",p;function h(E,C){return C.length>3?(E.push(C[0]+\"...\"+C[C.length-1]),p=!0):C.length&&(E=E.concat(C)),E}return s=t.reduce(function(E,C){return E.concat((C+\"\").split(\"\"))},[]).reduce(function(E,C){var S,b;return e||(C=C.toLowerCase()),S=/^\\d$/.test(C)?1:/^[A-Z]$/.test(C)?2:/^[a-z]$/.test(C)?3:0,r&&S===0?f+=C:(b=C.charCodeAt(0),S&&S===n&&b===c+1?a.push(C):(E=h(E,a),a=[C],n=S),c=b),E},[]),s=h(s,a),f&&(s.push(f),p=!0),{values:s,suppressed:p}}function sEe(t,e){return t.join(t.length>2?\", \":e?\" / \":\"/\")}function oEe(t,e){var r,s,a={},n;if(e.phContent&&(r=e.phContent(t,e)),typeof r!=\"string\")switch(t){case\"hideEchoBack\":case\"mask\":case\"defaultInput\":case\"caseSensitive\":case\"keepWhitespace\":case\"encoding\":case\"bufferSize\":case\"history\":case\"cd\":r=e.hasOwnProperty(t)?typeof e[t]==\"boolean\"?e[t]?\"on\":\"off\":e[t]+\"\":\"\";break;case\"limit\":case\"trueValue\":case\"falseValue\":s=e[e.hasOwnProperty(t+\"Src\")?t+\"Src\":t],e.keyIn?(a=iEe(s,e.caseSensitive),s=a.values):s=s.filter(function(c){var f=typeof c;return f===\"string\"||f===\"number\"}),r=sEe(s,a.suppressed);break;case\"limitCount\":case\"limitCountNotZero\":r=e[e.hasOwnProperty(\"limitSrc\")?\"limitSrc\":\"limit\"].length,r=r||t!==\"limitCountNotZero\"?r+\"\":\"\";break;case\"lastInput\":r=D5;break;case\"cwd\":case\"CWD\":case\"cwdHome\":r=process.cwd(),t===\"CWD\"?r=V0.basename(r):t===\"cwdHome\"&&(r=b5(r));break;case\"date\":case\"time\":case\"localeDate\":case\"localeTime\":r=new Date()[\"to\"+t.replace(/^./,function(c){return c.toUpperCase()})+\"String\"]();break;default:typeof(n=(t.match(/^history_m(\\d+)$/)||[])[1])==\"string\"&&(r=Dm[Dm.length-n]||\"\")}return r}function aEe(t){var e=/^(.)-(.)$/.exec(t),r=\"\",s,a,n,c;if(!e)return null;for(s=e[1].charCodeAt(0),a=e[2].charCodeAt(0),c=s<a?1:-1,n=s;n!==a+c;n+=c)r+=String.fromCharCode(n);return r}function S5(t){var e=new RegExp(/(\\s*)(?:(\"|')(.*?)(?:\\2|$)|(\\S+))/g),r,s=\"\",a=[],n;for(t=t.trim();r=e.exec(t);)n=r[3]||r[4]||\"\",r[1]&&(a.push(s),s=\"\"),s+=n;return s&&a.push(s),a}function lEe(t,e){return e.trueValue.length&&v5(t,e.trueValue,e.caseSensitive)?!0:e.falseValue.length&&v5(t,e.falseValue,e.caseSensitive)?!1:t}function cEe(t){var e,r,s,a,n,c,f;function p(E){return oEe(E,t)}function h(E){t.display+=(/[^\\r\\n]$/.test(t.display)?`\n`:\"\")+E}for(t.limitSrc=t.limit,t.displaySrc=t.display,t.limit=\"\",t.display=JC(t.display+\"\",p);;){if(e=B5(t),r=!1,s=\"\",t.defaultInput&&!e&&(e=t.defaultInput),t.history&&((a=/^\\s*\\!(?:\\!|-1)(:p)?\\s*$/.exec(e))?(n=Dm[0]||\"\",a[1]?r=!0:e=n,h(n+`\n`),r||(t.displayOnly=!0,B5(t),t.displayOnly=!1)):e&&e!==Dm[Dm.length-1]&&(Dm=[e])),!r&&t.cd&&e)switch(c=S5(e),c[0].toLowerCase()){case\"cd\":if(c[1])try{process.chdir(b5(c[1],!0))}catch(E){h(E+\"\")}r=!0;break;case\"pwd\":h(process.cwd()),r=!0;break}if(!r&&t.preCheck&&(f=t.preCheck(e,t),e=f.res,f.forceNext&&(r=!0)),!r){if(!t.limitSrc.length||v5(e,t.limitSrc,t.caseSensitive))break;t.limitMessage&&(s=JC(t.limitMessage,p))}h((s?s+`\n`:\"\")+JC(t.displaySrc+\"\",p))}return lEe(e,t)}$r._DBG_set_useExt=function(t){rEe=t};$r._DBG_set_checkOptions=function(t){w5=t};$r._DBG_set_checkMethod=function(t){sS=t};$r._DBG_clearHistory=function(){D5=\"\",Dm=[]};$r.setDefaultOptions=function(t){return C5=Vs(!0,t),Vs(!0)};$r.question=function(t,e){return cEe(Vs(Vs(!0,e),{display:t}))};$r.prompt=function(t){var e=Vs(!0,t);return e.display=e.prompt,cEe(e)};$r.keyIn=function(t,e){var r=Vs(Vs(!0,e),{display:t,keyIn:!0,keepWhitespace:!0});return r.limitSrc=r.limit.filter(function(s){var a=typeof s;return a===\"string\"||a===\"number\"}).map(function(s){return JC(s+\"\",aEe)}),r.limit=P5(r.limitSrc.join(\"\")),[\"trueValue\",\"falseValue\"].forEach(function(s){r[s]=r[s].reduce(function(a,n){var c=typeof n;return c===\"string\"||c===\"number\"?a=a.concat((n+\"\").split(\"\")):a.push(n),a},[])}),r.display=JC(r.display+\"\",function(s){return oEe(s,r)}),lEe(B5(r),r)};$r.questionEMail=function(t,e){return t==null&&(t=\"Input e-mail address: \"),$r.question(t,Vs({hideEchoBack:!1,limit:/^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,limitMessage:\"Input valid e-mail address, please.\",trueValue:null,falseValue:null},e,{keepWhitespace:!1,cd:!1}))};$r.questionNewPassword=function(t,e){var r,s,a,n=Vs({hideEchoBack:!0,mask:\"*\",limitMessage:`It can include: $<charlist>\nAnd the length must be: $<length>`,trueValue:null,falseValue:null,caseSensitive:!0},e,{history:!1,cd:!1,phContent:function(b){return b===\"charlist\"?r.text:b===\"length\"?s+\"...\"+a:null}}),c,f,p,h,E,C,S;for(e=e||{},c=JC(e.charlist?e.charlist+\"\":\"$<!-~>\",aEe),(isNaN(s=parseInt(e.min,10))||typeof s!=\"number\")&&(s=12),(isNaN(a=parseInt(e.max,10))||typeof a!=\"number\")&&(a=24),h=new RegExp(\"^[\"+P5(c)+\"]{\"+s+\",\"+a+\"}$\"),r=iEe([c],n.caseSensitive,!0),r.text=sEe(r.values,r.suppressed),f=e.confirmMessage!=null?e.confirmMessage:\"Reinput a same one to confirm it: \",p=e.unmatchMessage!=null?e.unmatchMessage:\"It differs from first one. Hit only the Enter key if you want to retry from first one.\",t==null&&(t=\"Input new password: \"),E=n.limitMessage;!S;)n.limit=h,n.limitMessage=E,C=$r.question(t,n),n.limit=[C,\"\"],n.limitMessage=p,S=$r.question(f,n);return C};function uEe(t,e,r){var s;function a(n){return s=r(n),!isNaN(s)&&typeof s==\"number\"}return $r.question(t,Vs({limitMessage:\"Input valid number, please.\"},e,{limit:a,cd:!1})),s}$r.questionInt=function(t,e){return uEe(t,e,function(r){return parseInt(r,10)})};$r.questionFloat=function(t,e){return uEe(t,e,parseFloat)};$r.questionPath=function(t,e){var r,s=\"\",a=Vs({hideEchoBack:!1,limitMessage:`$<error(\n)>Input valid path, please.$<( Min:)min>$<( Max:)max>`,history:!0,cd:!0},e,{keepWhitespace:!1,limit:function(n){var c,f,p;n=b5(n,!0),s=\"\";function h(E){E.split(/\\/|\\\\/).reduce(function(C,S){var b=V0.resolve(C+=S+V0.sep);if(!si.existsSync(b))si.mkdirSync(b);else if(!si.statSync(b).isDirectory())throw new Error(\"Non directory already exists: \"+b);return C},\"\")}try{if(c=si.existsSync(n),r=c?si.realpathSync(n):V0.resolve(n),!e.hasOwnProperty(\"exists\")&&!c||typeof e.exists==\"boolean\"&&e.exists!==c)return s=(c?\"Already exists\":\"No such file or directory\")+\": \"+r,!1;if(!c&&e.create&&(e.isDirectory?h(r):(h(V0.dirname(r)),si.closeSync(si.openSync(r,\"w\"))),r=si.realpathSync(r)),c&&(e.min||e.max||e.isFile||e.isDirectory)){if(f=si.statSync(r),e.isFile&&!f.isFile())return s=\"Not file: \"+r,!1;if(e.isDirectory&&!f.isDirectory())return s=\"Not directory: \"+r,!1;if(e.min&&f.size<+e.min||e.max&&f.size>+e.max)return s=\"Size \"+f.size+\" is out of range: \"+r,!1}if(typeof e.validate==\"function\"&&(p=e.validate(r))!==!0)return typeof p==\"string\"&&(s=p),!1}catch(E){return s=E+\"\",!1}return!0},phContent:function(n){return n===\"error\"?s:n!==\"min\"&&n!==\"max\"?null:e.hasOwnProperty(n)?e[n]+\"\":\"\"}});return e=e||{},t==null&&(t='Input path (you can \"cd\" and \"pwd\"): '),$r.question(t,a),r};function fEe(t,e){var r={},s={};return typeof t==\"object\"?(Object.keys(t).forEach(function(a){typeof t[a]==\"function\"&&(s[e.caseSensitive?a:a.toLowerCase()]=t[a])}),r.preCheck=function(a){var n;return r.args=S5(a),n=r.args[0]||\"\",e.caseSensitive||(n=n.toLowerCase()),r.hRes=n!==\"_\"&&s.hasOwnProperty(n)?s[n].apply(a,r.args.slice(1)):s.hasOwnProperty(\"_\")?s._.apply(a,r.args):null,{res:a,forceNext:!1}},s.hasOwnProperty(\"_\")||(r.limit=function(){var a=r.args[0]||\"\";return e.caseSensitive||(a=a.toLowerCase()),s.hasOwnProperty(a)})):r.preCheck=function(a){return r.args=S5(a),r.hRes=typeof t==\"function\"?t.apply(a,r.args):!0,{res:a,forceNext:!1}},r}$r.promptCL=function(t,e){var r=Vs({hideEchoBack:!1,limitMessage:\"Requested command is not available.\",caseSensitive:!1,history:!0},e),s=fEe(t,r);return r.limit=s.limit,r.preCheck=s.preCheck,$r.prompt(r),s.args};$r.promptLoop=function(t,e){for(var r=Vs({hideEchoBack:!1,trueValue:null,falseValue:null,caseSensitive:!1,history:!0},e);!t($r.prompt(r)););};$r.promptCLLoop=function(t,e){var r=Vs({hideEchoBack:!1,limitMessage:\"Requested command is not available.\",caseSensitive:!1,history:!0},e),s=fEe(t,r);for(r.limit=s.limit,r.preCheck=s.preCheck;$r.prompt(r),!s.hRes;);};$r.promptSimShell=function(t){return $r.prompt(Vs({hideEchoBack:!1,history:!0},t,{prompt:function(){return Pm?\"$<cwd>>\":(process.env.USER||\"\")+(process.env.HOSTNAME?\"@\"+process.env.HOSTNAME.replace(/\\..*$/,\"\"):\"\")+\":$<cwdHome>$ \"}()}))};function AEe(t,e,r){var s;return t==null&&(t=\"Are you sure? \"),(!e||e.guide!==!1)&&(t+=\"\")&&(t=t.replace(/\\s*:?\\s*$/,\"\")+\" [y/n]: \"),s=$r.keyIn(t,Vs(e,{hideEchoBack:!1,limit:r,trueValue:\"y\",falseValue:\"n\",caseSensitive:!1})),typeof s==\"boolean\"?s:\"\"}$r.keyInYN=function(t,e){return AEe(t,e)};$r.keyInYNStrict=function(t,e){return AEe(t,e,\"yn\")};$r.keyInPause=function(t,e){t==null&&(t=\"Continue...\"),(!e||e.guide!==!1)&&(t+=\"\")&&(t=t.replace(/\\s+$/,\"\")+\" (Hit any key)\"),$r.keyIn(t,Vs({limit:null},e,{hideEchoBack:!0,mask:\"\"}))};$r.keyInSelect=function(t,e,r){var s=Vs({hideEchoBack:!1},r,{trueValue:null,falseValue:null,caseSensitive:!1,phContent:function(p){return p===\"itemsCount\"?t.length+\"\":p===\"firstItem\"?(t[0]+\"\").trim():p===\"lastItem\"?(t[t.length-1]+\"\").trim():null}}),a=\"\",n={},c=49,f=`\n`;if(!Array.isArray(t)||!t.length||t.length>35)throw\"`items` must be Array (max length: 35).\";return t.forEach(function(p,h){var E=String.fromCharCode(c);a+=E,n[E]=h,f+=\"[\"+E+\"] \"+(p+\"\").trim()+`\n`,c=c===57?97:c+1}),(!r||r.cancel!==!1)&&(a+=\"0\",n[0]=-1,f+=\"[0] \"+(r&&r.cancel!=null&&typeof r.cancel!=\"boolean\"?(r.cancel+\"\").trim():\"CANCEL\")+`\n`),s.limit=a,f+=`\n`,e==null&&(e=\"Choose one from list: \"),(e+=\"\")&&((!r||r.guide!==!1)&&(e=e.replace(/\\s*:?\\s*$/,\"\")+\" [$<limit>]: \"),f+=e),n[$r.keyIn(f,s).toLowerCase()]};$r.getRawInput=function(){return oF};function oS(t,e){var r;return e.length&&(r={},r[t]=e[0]),$r.setDefaultOptions(r)[t]}$r.setPrint=function(){return oS(\"print\",arguments)};$r.setPrompt=function(){return oS(\"prompt\",arguments)};$r.setEncoding=function(){return oS(\"encoding\",arguments)};$r.setMask=function(){return oS(\"mask\",arguments)};$r.setBufferSize=function(){return oS(\"bufferSize\",arguments)}});var x5=_((BYt,ec)=>{(function(){var t={major:0,minor:2,patch:66,status:\"beta\"};tau_file_system={files:{},open:function(w,P,y){var F=tau_file_system.files[w];if(!F){if(y===\"read\")return null;F={path:w,text:\"\",type:P,get:function(z,Z){return Z===this.text.length||Z>this.text.length?\"end_of_file\":this.text.substring(Z,Z+z)},put:function(z,Z){return Z===\"end_of_file\"?(this.text+=z,!0):Z===\"past_end_of_file\"?null:(this.text=this.text.substring(0,Z)+z+this.text.substring(Z+z.length),!0)},get_byte:function(z){if(z===\"end_of_stream\")return-1;var Z=Math.floor(z/2);if(this.text.length<=Z)return-1;var $=n(this.text[Math.floor(z/2)],0);return z%2===0?$&255:$/256>>>0},put_byte:function(z,Z){var $=Z===\"end_of_stream\"?this.text.length:Math.floor(Z/2);if(this.text.length<$)return null;var oe=this.text.length===$?-1:n(this.text[Math.floor(Z/2)],0);return Z%2===0?(oe=oe/256>>>0,oe=(oe&255)<<8|z&255):(oe=oe&255,oe=(z&255)<<8|oe&255),this.text.length===$?this.text+=c(oe):this.text=this.text.substring(0,$)+c(oe)+this.text.substring($+1),!0},flush:function(){return!0},close:function(){var z=tau_file_system.files[this.path];return z?!0:null}},tau_file_system.files[w]=F}return y===\"write\"&&(F.text=\"\"),F}},tau_user_input={buffer:\"\",get:function(w,P){for(var y;tau_user_input.buffer.length<w;)y=window.prompt(),y&&(tau_user_input.buffer+=y);return y=tau_user_input.buffer.substr(0,w),tau_user_input.buffer=tau_user_input.buffer.substr(w),y}},tau_user_output={put:function(w,P){return console.log(w),!0},flush:function(){return!0}},nodejs_file_system={open:function(w,P,y){var F=Ie(\"fs\"),z=F.openSync(w,y[0]);return y===\"read\"&&!F.existsSync(w)?null:{get:function(Z,$){var oe=new Buffer(Z);return F.readSync(z,oe,0,Z,$),oe.toString()},put:function(Z,$){var oe=Buffer.from(Z);if($===\"end_of_file\")F.writeSync(z,oe);else{if($===\"past_end_of_file\")return null;F.writeSync(z,oe,0,oe.length,$)}return!0},get_byte:function(Z){return null},put_byte:function(Z,$){return null},flush:function(){return!0},close:function(){return F.closeSync(z),!0}}}},nodejs_user_input={buffer:\"\",get:function(w,P){for(var y,F=pEe();nodejs_user_input.buffer.length<w;)nodejs_user_input.buffer+=F.question();return y=nodejs_user_input.buffer.substr(0,w),nodejs_user_input.buffer=nodejs_user_input.buffer.substr(w),y}},nodejs_user_output={put:function(w,P){return process.stdout.write(w),!0},flush:function(){return!0}};var e;Array.prototype.indexOf?e=function(w,P){return w.indexOf(P)}:e=function(w,P){for(var y=w.length,F=0;F<y;F++)if(P===w[F])return F;return-1};var r=function(w,P){if(w.length!==0){for(var y=w[0],F=w.length,z=1;z<F;z++)y=P(y,w[z]);return y}},s;Array.prototype.map?s=function(w,P){return w.map(P)}:s=function(w,P){for(var y=[],F=w.length,z=0;z<F;z++)y.push(P(w[z]));return y};var a;Array.prototype.filter?a=function(w,P){return w.filter(P)}:a=function(w,P){for(var y=[],F=w.length,z=0;z<F;z++)P(w[z])&&y.push(w[z]);return y};var n;String.prototype.codePointAt?n=function(w,P){return w.codePointAt(P)}:n=function(w,P){return w.charCodeAt(P)};var c;String.fromCodePoint?c=function(){return String.fromCodePoint.apply(null,arguments)}:c=function(){return String.fromCharCode.apply(null,arguments)};var f=0,p=1,h=/(\\\\a)|(\\\\b)|(\\\\f)|(\\\\n)|(\\\\r)|(\\\\t)|(\\\\v)|\\\\x([0-9a-fA-F]+)\\\\|\\\\([0-7]+)\\\\|(\\\\\\\\)|(\\\\')|('')|(\\\\\")|(\\\\`)|(\\\\.)|(.)/g,E={\"\\\\a\":7,\"\\\\b\":8,\"\\\\f\":12,\"\\\\n\":10,\"\\\\r\":13,\"\\\\t\":9,\"\\\\v\":11};function C(w){var P=[],y=!1;return w.replace(h,function(F,z,Z,$,oe,xe,Re,lt,Ct,qt,ir,bt,gn,br,Ir,Or,nn){switch(!0){case Ct!==void 0:return P.push(parseInt(Ct,16)),\"\";case qt!==void 0:return P.push(parseInt(qt,8)),\"\";case ir!==void 0:case bt!==void 0:case gn!==void 0:case br!==void 0:case Ir!==void 0:return P.push(n(F.substr(1),0)),\"\";case nn!==void 0:return P.push(n(nn,0)),\"\";case Or!==void 0:y=!0;default:return P.push(E[F]),\"\"}}),y?null:P}function S(w,P){var y=\"\";if(w.length<2)return w;try{w=w.replace(/\\\\([0-7]+)\\\\/g,function($,oe){return c(parseInt(oe,8))}),w=w.replace(/\\\\x([0-9a-fA-F]+)\\\\/g,function($,oe){return c(parseInt(oe,16))})}catch{return null}for(var F=0;F<w.length;F++){var z=w.charAt(F),Z=w.charAt(F+1);if(z===P&&Z===P)F++,y+=P;else if(z===\"\\\\\")if([\"a\",\"b\",\"f\",\"n\",\"r\",\"t\",\"v\",\"'\",'\"',\"\\\\\",\"a\",\"\\b\",\"\\f\",`\n`,\"\\r\",\"\t\",\"\\v\"].indexOf(Z)!==-1)switch(F+=1,Z){case\"a\":y+=\"a\";break;case\"b\":y+=\"\\b\";break;case\"f\":y+=\"\\f\";break;case\"n\":y+=`\n`;break;case\"r\":y+=\"\\r\";break;case\"t\":y+=\"\t\";break;case\"v\":y+=\"\\v\";break;case\"'\":y+=\"'\";break;case'\"':y+='\"';break;case\"\\\\\":y+=\"\\\\\";break}else return null;else y+=z}return y}function b(w){for(var P=\"\",y=0;y<w.length;y++)switch(w.charAt(y)){case\"'\":P+=\"\\\\'\";break;case\"\\\\\":P+=\"\\\\\\\\\";break;case\"\\b\":P+=\"\\\\b\";break;case\"\\f\":P+=\"\\\\f\";break;case`\n`:P+=\"\\\\n\";break;case\"\\r\":P+=\"\\\\r\";break;case\"\t\":P+=\"\\\\t\";break;case\"\\v\":P+=\"\\\\v\";break;default:P+=w.charAt(y);break}return P}function I(w){var P=w.substr(2);switch(w.substr(0,2).toLowerCase()){case\"0x\":return parseInt(P,16);case\"0b\":return parseInt(P,2);case\"0o\":return parseInt(P,8);case\"0'\":return C(P)[0];default:return parseFloat(w)}}var T={whitespace:/^\\s*(?:(?:%.*)|(?:\\/\\*(?:\\n|\\r|.)*?\\*\\/)|(?:\\s+))\\s*/,variable:/^(?:[A-Z_][a-zA-Z0-9_]*)/,atom:/^(\\!|,|;|[a-z][0-9a-zA-Z_]*|[#\\$\\&\\*\\+\\-\\.\\/\\:\\<\\=\\>\\?\\@\\^\\~\\\\]+|'(?:[^']*?(?:\\\\(?:x?\\d+)?\\\\)*(?:'')*(?:\\\\')*)*')/,number:/^(?:0o[0-7]+|0x[0-9a-fA-F]+|0b[01]+|0'(?:''|\\\\[abfnrtv\\\\'\"`]|\\\\x?\\d+\\\\|[^\\\\])|\\d+(?:\\.\\d+(?:[eE][+-]?\\d+)?)?)/,string:/^(?:\"([^\"]|\"\"|\\\\\")*\"|`([^`]|``|\\\\`)*`)/,l_brace:/^(?:\\[)/,r_brace:/^(?:\\])/,l_bracket:/^(?:\\{)/,r_bracket:/^(?:\\})/,bar:/^(?:\\|)/,l_paren:/^(?:\\()/,r_paren:/^(?:\\))/};function N(w,P){return w.get_flag(\"char_conversion\").id===\"on\"?P.replace(/./g,function(y){return w.get_char_conversion(y)}):P}function U(w){this.thread=w,this.text=\"\",this.tokens=[]}U.prototype.set_last_tokens=function(w){return this.tokens=w},U.prototype.new_text=function(w){this.text=w,this.tokens=[]},U.prototype.get_tokens=function(w){var P,y=0,F=0,z=0,Z=[],$=!1;if(w){var oe=this.tokens[w-1];y=oe.len,P=N(this.thread,this.text.substr(oe.len)),F=oe.line,z=oe.start}else P=this.text;if(/^\\s*$/.test(P))return null;for(;P!==\"\";){var xe=[],Re=!1;if(/^\\n/.exec(P)!==null){F++,z=0,y++,P=P.replace(/\\n/,\"\"),$=!0;continue}for(var lt in T)if(T.hasOwnProperty(lt)){var Ct=T[lt].exec(P);Ct&&xe.push({value:Ct[0],name:lt,matches:Ct})}if(!xe.length)return this.set_last_tokens([{value:P,matches:[],name:\"lexical\",line:F,start:z}]);var oe=r(xe,function(br,Ir){return br.value.length>=Ir.value.length?br:Ir});switch(oe.start=z,oe.line=F,P=P.replace(oe.value,\"\"),z+=oe.value.length,y+=oe.value.length,oe.name){case\"atom\":oe.raw=oe.value,oe.value.charAt(0)===\"'\"&&(oe.value=S(oe.value.substr(1,oe.value.length-2),\"'\"),oe.value===null&&(oe.name=\"lexical\",oe.value=\"unknown escape sequence\"));break;case\"number\":oe.float=oe.value.substring(0,2)!==\"0x\"&&oe.value.match(/[.eE]/)!==null&&oe.value!==\"0'.\",oe.value=I(oe.value),oe.blank=Re;break;case\"string\":var qt=oe.value.charAt(0);oe.value=S(oe.value.substr(1,oe.value.length-2),qt),oe.value===null&&(oe.name=\"lexical\",oe.value=\"unknown escape sequence\");break;case\"whitespace\":var ir=Z[Z.length-1];ir&&(ir.space=!0),Re=!0;continue;case\"r_bracket\":Z.length>0&&Z[Z.length-1].name===\"l_bracket\"&&(oe=Z.pop(),oe.name=\"atom\",oe.value=\"{}\",oe.raw=\"{}\",oe.space=!1);break;case\"r_brace\":Z.length>0&&Z[Z.length-1].name===\"l_brace\"&&(oe=Z.pop(),oe.name=\"atom\",oe.value=\"[]\",oe.raw=\"[]\",oe.space=!1);break}oe.len=y,Z.push(oe),Re=!1}var bt=this.set_last_tokens(Z);return bt.length===0?null:bt};function W(w,P,y,F,z){if(!P[y])return{type:f,value:x.error.syntax(P[y-1],\"expression expected\",!0)};var Z;if(F===\"0\"){var $=P[y];switch($.name){case\"number\":return{type:p,len:y+1,value:new x.type.Num($.value,$.float)};case\"variable\":return{type:p,len:y+1,value:new x.type.Var($.value)};case\"string\":var oe;switch(w.get_flag(\"double_quotes\").id){case\"atom\":oe=new j($.value,[]);break;case\"codes\":oe=new j(\"[]\",[]);for(var xe=$.value.length-1;xe>=0;xe--)oe=new j(\".\",[new x.type.Num(n($.value,xe),!1),oe]);break;case\"chars\":oe=new j(\"[]\",[]);for(var xe=$.value.length-1;xe>=0;xe--)oe=new j(\".\",[new x.type.Term($.value.charAt(xe),[]),oe]);break}return{type:p,len:y+1,value:oe};case\"l_paren\":var bt=W(w,P,y+1,w.__get_max_priority(),!0);return bt.type!==p?bt:P[bt.len]&&P[bt.len].name===\"r_paren\"?(bt.len++,bt):{type:f,derived:!0,value:x.error.syntax(P[bt.len]?P[bt.len]:P[bt.len-1],\") or operator expected\",!P[bt.len])};case\"l_bracket\":var bt=W(w,P,y+1,w.__get_max_priority(),!0);return bt.type!==p?bt:P[bt.len]&&P[bt.len].name===\"r_bracket\"?(bt.len++,bt.value=new j(\"{}\",[bt.value]),bt):{type:f,derived:!0,value:x.error.syntax(P[bt.len]?P[bt.len]:P[bt.len-1],\"} or operator expected\",!P[bt.len])}}var Re=ee(w,P,y,z);return Re.type===p||Re.derived||(Re=ie(w,P,y),Re.type===p||Re.derived)?Re:{type:f,derived:!1,value:x.error.syntax(P[y],\"unexpected token\")}}var lt=w.__get_max_priority(),Ct=w.__get_next_priority(F),qt=y;if(P[y].name===\"atom\"&&P[y+1]&&(P[y].space||P[y+1].name!==\"l_paren\")){var $=P[y++],ir=w.__lookup_operator_classes(F,$.value);if(ir&&ir.indexOf(\"fy\")>-1){var bt=W(w,P,y,F,z);if(bt.type!==f)return $.value===\"-\"&&!$.space&&x.type.is_number(bt.value)?{value:new x.type.Num(-bt.value.value,bt.value.is_float),len:bt.len,type:p}:{value:new x.type.Term($.value,[bt.value]),len:bt.len,type:p};Z=bt}else if(ir&&ir.indexOf(\"fx\")>-1){var bt=W(w,P,y,Ct,z);if(bt.type!==f)return{value:new x.type.Term($.value,[bt.value]),len:bt.len,type:p};Z=bt}}y=qt;var bt=W(w,P,y,Ct,z);if(bt.type===p){y=bt.len;var $=P[y];if(P[y]&&(P[y].name===\"atom\"&&w.__lookup_operator_classes(F,$.value)||P[y].name===\"bar\"&&w.__lookup_operator_classes(F,\"|\"))){var gn=Ct,br=F,ir=w.__lookup_operator_classes(F,$.value);if(ir.indexOf(\"xf\")>-1)return{value:new x.type.Term($.value,[bt.value]),len:++bt.len,type:p};if(ir.indexOf(\"xfx\")>-1){var Ir=W(w,P,y+1,gn,z);return Ir.type===p?{value:new x.type.Term($.value,[bt.value,Ir.value]),len:Ir.len,type:p}:(Ir.derived=!0,Ir)}else if(ir.indexOf(\"xfy\")>-1){var Ir=W(w,P,y+1,br,z);return Ir.type===p?{value:new x.type.Term($.value,[bt.value,Ir.value]),len:Ir.len,type:p}:(Ir.derived=!0,Ir)}else if(bt.type!==f)for(;;){y=bt.len;var $=P[y];if($&&$.name===\"atom\"&&w.__lookup_operator_classes(F,$.value)){var ir=w.__lookup_operator_classes(F,$.value);if(ir.indexOf(\"yf\")>-1)bt={value:new x.type.Term($.value,[bt.value]),len:++y,type:p};else if(ir.indexOf(\"yfx\")>-1){var Ir=W(w,P,++y,gn,z);if(Ir.type===f)return Ir.derived=!0,Ir;y=Ir.len,bt={value:new x.type.Term($.value,[bt.value,Ir.value]),len:y,type:p}}else break}else break}}else Z={type:f,value:x.error.syntax(P[bt.len-1],\"operator expected\")};return bt}return bt}function ee(w,P,y,F){if(!P[y]||P[y].name===\"atom\"&&P[y].raw===\".\"&&!F&&(P[y].space||!P[y+1]||P[y+1].name!==\"l_paren\"))return{type:f,derived:!1,value:x.error.syntax(P[y-1],\"unfounded token\")};var z=P[y],Z=[];if(P[y].name===\"atom\"&&P[y].raw!==\",\"){if(y++,P[y-1].space)return{type:p,len:y,value:new x.type.Term(z.value,Z)};if(P[y]&&P[y].name===\"l_paren\"){if(P[y+1]&&P[y+1].name===\"r_paren\")return{type:f,derived:!0,value:x.error.syntax(P[y+1],\"argument expected\")};var $=W(w,P,++y,\"999\",!0);if($.type===f)return $.derived?$:{type:f,derived:!0,value:x.error.syntax(P[y]?P[y]:P[y-1],\"argument expected\",!P[y])};for(Z.push($.value),y=$.len;P[y]&&P[y].name===\"atom\"&&P[y].value===\",\";){if($=W(w,P,y+1,\"999\",!0),$.type===f)return $.derived?$:{type:f,derived:!0,value:x.error.syntax(P[y+1]?P[y+1]:P[y],\"argument expected\",!P[y+1])};Z.push($.value),y=$.len}if(P[y]&&P[y].name===\"r_paren\")y++;else return{type:f,derived:!0,value:x.error.syntax(P[y]?P[y]:P[y-1],\", or ) expected\",!P[y])}}return{type:p,len:y,value:new x.type.Term(z.value,Z)}}return{type:f,derived:!1,value:x.error.syntax(P[y],\"term expected\")}}function ie(w,P,y){if(!P[y])return{type:f,derived:!1,value:x.error.syntax(P[y-1],\"[ expected\")};if(P[y]&&P[y].name===\"l_brace\"){var F=W(w,P,++y,\"999\",!0),z=[F.value],Z=void 0;if(F.type===f)return P[y]&&P[y].name===\"r_brace\"?{type:p,len:y+1,value:new x.type.Term(\"[]\",[])}:{type:f,derived:!0,value:x.error.syntax(P[y],\"] expected\")};for(y=F.len;P[y]&&P[y].name===\"atom\"&&P[y].value===\",\";){if(F=W(w,P,y+1,\"999\",!0),F.type===f)return F.derived?F:{type:f,derived:!0,value:x.error.syntax(P[y+1]?P[y+1]:P[y],\"argument expected\",!P[y+1])};z.push(F.value),y=F.len}var $=!1;if(P[y]&&P[y].name===\"bar\"){if($=!0,F=W(w,P,y+1,\"999\",!0),F.type===f)return F.derived?F:{type:f,derived:!0,value:x.error.syntax(P[y+1]?P[y+1]:P[y],\"argument expected\",!P[y+1])};Z=F.value,y=F.len}return P[y]&&P[y].name===\"r_brace\"?{type:p,len:y+1,value:g(z,Z)}:{type:f,derived:!0,value:x.error.syntax(P[y]?P[y]:P[y-1],$?\"] expected\":\", or | or ] expected\",!P[y])}}return{type:f,derived:!1,value:x.error.syntax(P[y],\"list expected\")}}function ue(w,P,y){var F=P[y].line,z=W(w,P,y,w.__get_max_priority(),!1),Z=null,$;if(z.type!==f)if(y=z.len,P[y]&&P[y].name===\"atom\"&&P[y].raw===\".\")if(y++,x.type.is_term(z.value)){if(z.value.indicator===\":-/2\"?(Z=new x.type.Rule(z.value.args[0],Ce(z.value.args[1])),$={value:Z,len:y,type:p}):z.value.indicator===\"-->/2\"?(Z=pe(new x.type.Rule(z.value.args[0],z.value.args[1]),w),Z.body=Ce(Z.body),$={value:Z,len:y,type:x.type.is_rule(Z)?p:f}):(Z=new x.type.Rule(z.value,null),$={value:Z,len:y,type:p}),Z){var oe=Z.singleton_variables();oe.length>0&&w.throw_warning(x.warning.singleton(oe,Z.head.indicator,F))}return $}else return{type:f,value:x.error.syntax(P[y],\"callable expected\")};else return{type:f,value:x.error.syntax(P[y]?P[y]:P[y-1],\". or operator expected\")};return z}function le(w,P,y){y=y||{},y.from=y.from?y.from:\"$tau-js\",y.reconsult=y.reconsult!==void 0?y.reconsult:!0;var F=new U(w),z={},Z;F.new_text(P);var $=0,oe=F.get_tokens($);do{if(oe===null||!oe[$])break;var xe=ue(w,oe,$);if(xe.type===f)return new j(\"throw\",[xe.value]);if(xe.value.body===null&&xe.value.head.indicator===\"?-/1\"){var Re=new it(w.session);Re.add_goal(xe.value.head.args[0]),Re.answer(function(Ct){x.type.is_error(Ct)?w.throw_warning(Ct.args[0]):(Ct===!1||Ct===null)&&w.throw_warning(x.warning.failed_goal(xe.value.head.args[0],xe.len))}),$=xe.len;var lt=!0}else if(xe.value.body===null&&xe.value.head.indicator===\":-/1\"){var lt=w.run_directive(xe.value.head.args[0]);$=xe.len,xe.value.head.args[0].indicator===\"char_conversion/2\"&&(oe=F.get_tokens($),$=0)}else{Z=xe.value.head.indicator,y.reconsult!==!1&&z[Z]!==!0&&!w.is_multifile_predicate(Z)&&(w.session.rules[Z]=a(w.session.rules[Z]||[],function(qt){return qt.dynamic}),z[Z]=!0);var lt=w.add_rule(xe.value,y);$=xe.len}if(!lt)return lt}while(!0);return!0}function me(w,P){var y=new U(w);y.new_text(P);var F=0;do{var z=y.get_tokens(F);if(z===null)break;var Z=W(w,z,0,w.__get_max_priority(),!1);if(Z.type!==f){var $=Z.len,oe=$;if(z[$]&&z[$].name===\"atom\"&&z[$].raw===\".\")w.add_goal(Ce(Z.value));else{var xe=z[$];return new j(\"throw\",[x.error.syntax(xe||z[$-1],\". or operator expected\",!xe)])}F=Z.len+1}else return new j(\"throw\",[Z.value])}while(!0);return!0}function pe(w,P){w=w.rename(P);var y=P.next_free_variable(),F=Be(w.body,y,P);return F.error?F.value:(w.body=F.value,w.head.args=w.head.args.concat([y,F.variable]),w.head=new j(w.head.id,w.head.args),w)}function Be(w,P,y){var F;if(x.type.is_term(w)&&w.indicator===\"!/0\")return{value:w,variable:P,error:!1};if(x.type.is_term(w)&&w.indicator===\",/2\"){var z=Be(w.args[0],P,y);if(z.error)return z;var Z=Be(w.args[1],z.variable,y);return Z.error?Z:{value:new j(\",\",[z.value,Z.value]),variable:Z.variable,error:!1}}else{if(x.type.is_term(w)&&w.indicator===\"{}/1\")return{value:w.args[0],variable:P,error:!1};if(x.type.is_empty_list(w))return{value:new j(\"true\",[]),variable:P,error:!1};if(x.type.is_list(w)){F=y.next_free_variable();for(var $=w,oe;$.indicator===\"./2\";)oe=$,$=$.args[1];return x.type.is_variable($)?{value:x.error.instantiation(\"DCG\"),variable:P,error:!0}:x.type.is_empty_list($)?(oe.args[1]=F,{value:new j(\"=\",[P,w]),variable:F,error:!1}):{value:x.error.type(\"list\",w,\"DCG\"),variable:P,error:!0}}else return x.type.is_callable(w)?(F=y.next_free_variable(),w.args=w.args.concat([P,F]),w=new j(w.id,w.args),{value:w,variable:F,error:!1}):{value:x.error.type(\"callable\",w,\"DCG\"),variable:P,error:!0}}}function Ce(w){return x.type.is_variable(w)?new j(\"call\",[w]):x.type.is_term(w)&&[\",/2\",\";/2\",\"->/2\"].indexOf(w.indicator)!==-1?new j(w.id,[Ce(w.args[0]),Ce(w.args[1])]):w}function g(w,P){for(var y=P||new x.type.Term(\"[]\",[]),F=w.length-1;F>=0;F--)y=new x.type.Term(\".\",[w[F],y]);return y}function we(w,P){for(var y=w.length-1;y>=0;y--)w[y]===P&&w.splice(y,1)}function ye(w){for(var P={},y=[],F=0;F<w.length;F++)w[F]in P||(y.push(w[F]),P[w[F]]=!0);return y}function Ae(w,P,y,F){if(w.session.rules[y]!==null){for(var z=0;z<w.session.rules[y].length;z++)if(w.session.rules[y][z]===F){w.session.rules[y].splice(z,1),w.success(P);break}}}function se(w){return function(P,y,F){var z=F.args[0],Z=F.args.slice(1,w);if(x.type.is_variable(z))P.throw_error(x.error.instantiation(P.level));else if(!x.type.is_callable(z))P.throw_error(x.error.type(\"callable\",z,P.level));else{var $=new j(z.id,z.args.concat(Z));P.prepend([new be(y.goal.replace($),y.substitution,y)])}}}function X(w){for(var P=w.length-1;P>=0;P--)if(w.charAt(P)===\"/\")return new j(\"/\",[new j(w.substring(0,P)),new Te(parseInt(w.substring(P+1)),!1)])}function De(w){this.id=w}function Te(w,P){this.is_float=P!==void 0?P:parseInt(w)!==w,this.value=this.is_float?w:parseInt(w)}var mt=0;function j(w,P,y){this.ref=y||++mt,this.id=w,this.args=P||[],this.indicator=w+\"/\"+this.args.length}var rt=0;function Fe(w,P,y,F,z,Z){this.id=rt++,this.stream=w,this.mode=P,this.alias=y,this.type=F!==void 0?F:\"text\",this.reposition=z!==void 0?z:!0,this.eof_action=Z!==void 0?Z:\"eof_code\",this.position=this.mode===\"append\"?\"end_of_stream\":0,this.output=this.mode===\"write\"||this.mode===\"append\",this.input=this.mode===\"read\"}function Ne(w){w=w||{},this.links=w}function be(w,P,y){P=P||new Ne,y=y||null,this.goal=w,this.substitution=P,this.parent=y}function Ve(w,P,y){this.head=w,this.body=P,this.dynamic=y||!1}function ke(w){w=w===void 0||w<=0?1e3:w,this.rules={},this.src_predicates={},this.rename=0,this.modules=[],this.thread=new it(this),this.total_threads=1,this.renamed_variables={},this.public_predicates={},this.multifile_predicates={},this.limit=w,this.streams={user_input:new Fe(typeof ec<\"u\"&&ec.exports?nodejs_user_input:tau_user_input,\"read\",\"user_input\",\"text\",!1,\"reset\"),user_output:new Fe(typeof ec<\"u\"&&ec.exports?nodejs_user_output:tau_user_output,\"write\",\"user_output\",\"text\",!1,\"eof_code\")},this.file_system=typeof ec<\"u\"&&ec.exports?nodejs_file_system:tau_file_system,this.standard_input=this.streams.user_input,this.standard_output=this.streams.user_output,this.current_input=this.streams.user_input,this.current_output=this.streams.user_output,this.format_success=function(P){return P.substitution},this.format_error=function(P){return P.goal},this.flag={bounded:x.flag.bounded.value,max_integer:x.flag.max_integer.value,min_integer:x.flag.min_integer.value,integer_rounding_function:x.flag.integer_rounding_function.value,char_conversion:x.flag.char_conversion.value,debug:x.flag.debug.value,max_arity:x.flag.max_arity.value,unknown:x.flag.unknown.value,double_quotes:x.flag.double_quotes.value,occurs_check:x.flag.occurs_check.value,dialect:x.flag.dialect.value,version_data:x.flag.version_data.value,nodejs:x.flag.nodejs.value},this.__loaded_modules=[],this.__char_conversion={},this.__operators={1200:{\":-\":[\"fx\",\"xfx\"],\"-->\":[\"xfx\"],\"?-\":[\"fx\"]},1100:{\";\":[\"xfy\"]},1050:{\"->\":[\"xfy\"]},1e3:{\",\":[\"xfy\"]},900:{\"\\\\+\":[\"fy\"]},700:{\"=\":[\"xfx\"],\"\\\\=\":[\"xfx\"],\"==\":[\"xfx\"],\"\\\\==\":[\"xfx\"],\"@<\":[\"xfx\"],\"@=<\":[\"xfx\"],\"@>\":[\"xfx\"],\"@>=\":[\"xfx\"],\"=..\":[\"xfx\"],is:[\"xfx\"],\"=:=\":[\"xfx\"],\"=\\\\=\":[\"xfx\"],\"<\":[\"xfx\"],\"=<\":[\"xfx\"],\">\":[\"xfx\"],\">=\":[\"xfx\"]},600:{\":\":[\"xfy\"]},500:{\"+\":[\"yfx\"],\"-\":[\"yfx\"],\"/\\\\\":[\"yfx\"],\"\\\\/\":[\"yfx\"]},400:{\"*\":[\"yfx\"],\"/\":[\"yfx\"],\"//\":[\"yfx\"],rem:[\"yfx\"],mod:[\"yfx\"],\"<<\":[\"yfx\"],\">>\":[\"yfx\"]},200:{\"**\":[\"xfx\"],\"^\":[\"xfy\"],\"-\":[\"fy\"],\"+\":[\"fy\"],\"\\\\\":[\"fy\"]}}}function it(w){this.epoch=Date.now(),this.session=w,this.session.total_threads++,this.total_steps=0,this.cpu_time=0,this.cpu_time_last=0,this.points=[],this.debugger=!1,this.debugger_states=[],this.level=\"top_level/0\",this.__calls=[],this.current_limit=this.session.limit,this.warnings=[]}function Ue(w,P,y){this.id=w,this.rules=P,this.exports=y,x.module[w]=this}Ue.prototype.exports_predicate=function(w){return this.exports.indexOf(w)!==-1},De.prototype.unify=function(w,P){if(P&&e(w.variables(),this.id)!==-1&&!x.type.is_variable(w))return null;var y={};return y[this.id]=w,new Ne(y)},Te.prototype.unify=function(w,P){return x.type.is_number(w)&&this.value===w.value&&this.is_float===w.is_float?new Ne:null},j.prototype.unify=function(w,P){if(x.type.is_term(w)&&this.indicator===w.indicator){for(var y=new Ne,F=0;F<this.args.length;F++){var z=x.unify(this.args[F].apply(y),w.args[F].apply(y),P);if(z===null)return null;for(var Z in z.links)y.links[Z]=z.links[Z];y=y.apply(z)}return y}return null},Fe.prototype.unify=function(w,P){return x.type.is_stream(w)&&this.id===w.id?new Ne:null},De.prototype.toString=function(w){return this.id},Te.prototype.toString=function(w){return this.is_float&&e(this.value.toString(),\".\")===-1?this.value+\".0\":this.value.toString()},j.prototype.toString=function(w,P,y){if(w=w||{},w.quoted=w.quoted===void 0?!0:w.quoted,w.ignore_ops=w.ignore_ops===void 0?!1:w.ignore_ops,w.numbervars=w.numbervars===void 0?!1:w.numbervars,P=P===void 0?1200:P,y=y===void 0?\"\":y,w.numbervars&&this.indicator===\"$VAR/1\"&&x.type.is_integer(this.args[0])&&this.args[0].value>=0){var F=this.args[0].value,z=Math.floor(F/26),Z=F%26;return\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"[Z]+(z!==0?z:\"\")}switch(this.indicator){case\"[]/0\":case\"{}/0\":case\"!/0\":return this.id;case\"{}/1\":return\"{\"+this.args[0].toString(w)+\"}\";case\"./2\":for(var $=\"[\"+this.args[0].toString(w),oe=this.args[1];oe.indicator===\"./2\";)$+=\", \"+oe.args[0].toString(w),oe=oe.args[1];return oe.indicator!==\"[]/0\"&&($+=\"|\"+oe.toString(w)),$+=\"]\",$;case\",/2\":return\"(\"+this.args[0].toString(w)+\", \"+this.args[1].toString(w)+\")\";default:var xe=this.id,Re=w.session?w.session.lookup_operator(this.id,this.args.length):null;if(w.session===void 0||w.ignore_ops||Re===null)return w.quoted&&!/^(!|,|;|[a-z][0-9a-zA-Z_]*)$/.test(xe)&&xe!==\"{}\"&&xe!==\"[]\"&&(xe=\"'\"+b(xe)+\"'\"),xe+(this.args.length?\"(\"+s(this.args,function(ir){return ir.toString(w)}).join(\", \")+\")\":\"\");var lt=Re.priority>P.priority||Re.priority===P.priority&&(Re.class===\"xfy\"&&this.indicator!==P.indicator||Re.class===\"yfx\"&&this.indicator!==P.indicator||this.indicator===P.indicator&&Re.class===\"yfx\"&&y===\"right\"||this.indicator===P.indicator&&Re.class===\"xfy\"&&y===\"left\");Re.indicator=this.indicator;var Ct=lt?\"(\":\"\",qt=lt?\")\":\"\";return this.args.length===0?\"(\"+this.id+\")\":[\"fy\",\"fx\"].indexOf(Re.class)!==-1?Ct+xe+\" \"+this.args[0].toString(w,Re)+qt:[\"yf\",\"xf\"].indexOf(Re.class)!==-1?Ct+this.args[0].toString(w,Re)+\" \"+xe+qt:Ct+this.args[0].toString(w,Re,\"left\")+\" \"+this.id+\" \"+this.args[1].toString(w,Re,\"right\")+qt}},Fe.prototype.toString=function(w){return\"<stream>(\"+this.id+\")\"},Ne.prototype.toString=function(w){var P=\"{\";for(var y in this.links)this.links.hasOwnProperty(y)&&(P!==\"{\"&&(P+=\", \"),P+=y+\"/\"+this.links[y].toString(w));return P+=\"}\",P},be.prototype.toString=function(w){return this.goal===null?\"<\"+this.substitution.toString(w)+\">\":\"<\"+this.goal.toString(w)+\", \"+this.substitution.toString(w)+\">\"},Ve.prototype.toString=function(w){return this.body?this.head.toString(w)+\" :- \"+this.body.toString(w)+\".\":this.head.toString(w)+\".\"},ke.prototype.toString=function(w){for(var P=\"\",y=0;y<this.modules.length;y++)P+=\":- use_module(library(\"+this.modules[y]+`)).\n`;P+=`\n`;for(key in this.rules)for(y=0;y<this.rules[key].length;y++)P+=this.rules[key][y].toString(w),P+=`\n`;return P},De.prototype.clone=function(){return new De(this.id)},Te.prototype.clone=function(){return new Te(this.value,this.is_float)},j.prototype.clone=function(){return new j(this.id,s(this.args,function(w){return w.clone()}))},Fe.prototype.clone=function(){return new Stram(this.stream,this.mode,this.alias,this.type,this.reposition,this.eof_action)},Ne.prototype.clone=function(){var w={};for(var P in this.links)this.links.hasOwnProperty(P)&&(w[P]=this.links[P].clone());return new Ne(w)},be.prototype.clone=function(){return new be(this.goal.clone(),this.substitution.clone(),this.parent)},Ve.prototype.clone=function(){return new Ve(this.head.clone(),this.body!==null?this.body.clone():null)},De.prototype.equals=function(w){return x.type.is_variable(w)&&this.id===w.id},Te.prototype.equals=function(w){return x.type.is_number(w)&&this.value===w.value&&this.is_float===w.is_float},j.prototype.equals=function(w){if(!x.type.is_term(w)||this.indicator!==w.indicator)return!1;for(var P=0;P<this.args.length;P++)if(!this.args[P].equals(w.args[P]))return!1;return!0},Fe.prototype.equals=function(w){return x.type.is_stream(w)&&this.id===w.id},Ne.prototype.equals=function(w){var P;if(!x.type.is_substitution(w))return!1;for(P in this.links)if(this.links.hasOwnProperty(P)&&(!w.links[P]||!this.links[P].equals(w.links[P])))return!1;for(P in w.links)if(w.links.hasOwnProperty(P)&&!this.links[P])return!1;return!0},be.prototype.equals=function(w){return x.type.is_state(w)&&this.goal.equals(w.goal)&&this.substitution.equals(w.substitution)&&this.parent===w.parent},Ve.prototype.equals=function(w){return x.type.is_rule(w)&&this.head.equals(w.head)&&(this.body===null&&w.body===null||this.body!==null&&this.body.equals(w.body))},De.prototype.rename=function(w){return w.get_free_variable(this)},Te.prototype.rename=function(w){return this},j.prototype.rename=function(w){return new j(this.id,s(this.args,function(P){return P.rename(w)}))},Fe.prototype.rename=function(w){return this},Ve.prototype.rename=function(w){return new Ve(this.head.rename(w),this.body!==null?this.body.rename(w):null)},De.prototype.variables=function(){return[this.id]},Te.prototype.variables=function(){return[]},j.prototype.variables=function(){return[].concat.apply([],s(this.args,function(w){return w.variables()}))},Fe.prototype.variables=function(){return[]},Ve.prototype.variables=function(){return this.body===null?this.head.variables():this.head.variables().concat(this.body.variables())},De.prototype.apply=function(w){return w.lookup(this.id)?w.lookup(this.id):this},Te.prototype.apply=function(w){return this},j.prototype.apply=function(w){if(this.indicator===\"./2\"){for(var P=[],y=this;y.indicator===\"./2\";)P.push(y.args[0].apply(w)),y=y.args[1];for(var F=y.apply(w),z=P.length-1;z>=0;z--)F=new j(\".\",[P[z],F]);return F}return new j(this.id,s(this.args,function(Z){return Z.apply(w)}),this.ref)},Fe.prototype.apply=function(w){return this},Ve.prototype.apply=function(w){return new Ve(this.head.apply(w),this.body!==null?this.body.apply(w):null)},Ne.prototype.apply=function(w){var P,y={};for(P in this.links)this.links.hasOwnProperty(P)&&(y[P]=this.links[P].apply(w));return new Ne(y)},j.prototype.select=function(){for(var w=this;w.indicator===\",/2\";)w=w.args[0];return w},j.prototype.replace=function(w){return this.indicator===\",/2\"?this.args[0].indicator===\",/2\"?new j(\",\",[this.args[0].replace(w),this.args[1]]):w===null?this.args[1]:new j(\",\",[w,this.args[1]]):w},j.prototype.search=function(w){if(x.type.is_term(w)&&w.ref!==void 0&&this.ref===w.ref)return!0;for(var P=0;P<this.args.length;P++)if(x.type.is_term(this.args[P])&&this.args[P].search(w))return!0;return!1},ke.prototype.get_current_input=function(){return this.current_input},it.prototype.get_current_input=function(){return this.session.get_current_input()},ke.prototype.get_current_output=function(){return this.current_output},it.prototype.get_current_output=function(){return this.session.get_current_output()},ke.prototype.set_current_input=function(w){this.current_input=w},it.prototype.set_current_input=function(w){return this.session.set_current_input(w)},ke.prototype.set_current_output=function(w){this.current_input=w},it.prototype.set_current_output=function(w){return this.session.set_current_output(w)},ke.prototype.get_stream_by_alias=function(w){return this.streams[w]},it.prototype.get_stream_by_alias=function(w){return this.session.get_stream_by_alias(w)},ke.prototype.file_system_open=function(w,P,y){return this.file_system.open(w,P,y)},it.prototype.file_system_open=function(w,P,y){return this.session.file_system_open(w,P,y)},ke.prototype.get_char_conversion=function(w){return this.__char_conversion[w]||w},it.prototype.get_char_conversion=function(w){return this.session.get_char_conversion(w)},ke.prototype.parse=function(w){return this.thread.parse(w)},it.prototype.parse=function(w){var P=new U(this);P.new_text(w);var y=P.get_tokens();if(y===null)return!1;var F=W(this,y,0,this.__get_max_priority(),!1);return F.len!==y.length?!1:{value:F.value,expr:F,tokens:y}},ke.prototype.get_flag=function(w){return this.flag[w]},it.prototype.get_flag=function(w){return this.session.get_flag(w)},ke.prototype.add_rule=function(w,P){return P=P||{},P.from=P.from?P.from:\"$tau-js\",this.src_predicates[w.head.indicator]=P.from,this.rules[w.head.indicator]||(this.rules[w.head.indicator]=[]),this.rules[w.head.indicator].push(w),this.public_predicates.hasOwnProperty(w.head.indicator)||(this.public_predicates[w.head.indicator]=!1),!0},it.prototype.add_rule=function(w,P){return this.session.add_rule(w,P)},ke.prototype.run_directive=function(w){this.thread.run_directive(w)},it.prototype.run_directive=function(w){return x.type.is_directive(w)?(x.directive[w.indicator](this,w),!0):!1},ke.prototype.__get_max_priority=function(){return\"1200\"},it.prototype.__get_max_priority=function(){return this.session.__get_max_priority()},ke.prototype.__get_next_priority=function(w){var P=0;w=parseInt(w);for(var y in this.__operators)if(this.__operators.hasOwnProperty(y)){var F=parseInt(y);F>P&&F<w&&(P=F)}return P.toString()},it.prototype.__get_next_priority=function(w){return this.session.__get_next_priority(w)},ke.prototype.__lookup_operator_classes=function(w,P){return this.__operators.hasOwnProperty(w)&&this.__operators[w][P]instanceof Array&&this.__operators[w][P]||!1},it.prototype.__lookup_operator_classes=function(w,P){return this.session.__lookup_operator_classes(w,P)},ke.prototype.lookup_operator=function(w,P){for(var y in this.__operators)if(this.__operators[y][w]){for(var F=0;F<this.__operators[y][w].length;F++)if(P===0||this.__operators[y][w][F].length===P+1)return{priority:y,class:this.__operators[y][w][F]}}return null},it.prototype.lookup_operator=function(w,P){return this.session.lookup_operator(w,P)},ke.prototype.throw_warning=function(w){this.thread.throw_warning(w)},it.prototype.throw_warning=function(w){this.warnings.push(w)},ke.prototype.get_warnings=function(){return this.thread.get_warnings()},it.prototype.get_warnings=function(){return this.warnings},ke.prototype.add_goal=function(w,P){this.thread.add_goal(w,P)},it.prototype.add_goal=function(w,P,y){y=y||null,P===!0&&(this.points=[]);for(var F=w.variables(),z={},Z=0;Z<F.length;Z++)z[F[Z]]=new De(F[Z]);this.points.push(new be(w,new Ne(z),y))},ke.prototype.consult=function(w,P){return this.thread.consult(w,P)},it.prototype.consult=function(w,P){var y=\"\";if(typeof w==\"string\"){y=w;var F=y.length;if(y.substring(F-3,F)===\".pl\"&&document.getElementById(y)){var z=document.getElementById(y),Z=z.getAttribute(\"type\");Z!==null&&Z.replace(/ /g,\"\").toLowerCase()===\"text/prolog\"&&(y=z.text)}}else if(w.nodeName)switch(w.nodeName.toLowerCase()){case\"input\":case\"textarea\":y=w.value;break;default:y=w.innerHTML;break}else return!1;return this.warnings=[],le(this,y,P)},ke.prototype.query=function(w){return this.thread.query(w)},it.prototype.query=function(w){return this.points=[],this.debugger_points=[],me(this,w)},ke.prototype.head_point=function(){return this.thread.head_point()},it.prototype.head_point=function(){return this.points[this.points.length-1]},ke.prototype.get_free_variable=function(w){return this.thread.get_free_variable(w)},it.prototype.get_free_variable=function(w){var P=[];if(w.id===\"_\"||this.session.renamed_variables[w.id]===void 0){for(this.session.rename++,this.points.length>0&&(P=this.head_point().substitution.domain());e(P,x.format_variable(this.session.rename))!==-1;)this.session.rename++;if(w.id===\"_\")return new De(x.format_variable(this.session.rename));this.session.renamed_variables[w.id]=x.format_variable(this.session.rename)}return new De(this.session.renamed_variables[w.id])},ke.prototype.next_free_variable=function(){return this.thread.next_free_variable()},it.prototype.next_free_variable=function(){this.session.rename++;var w=[];for(this.points.length>0&&(w=this.head_point().substitution.domain());e(w,x.format_variable(this.session.rename))!==-1;)this.session.rename++;return new De(x.format_variable(this.session.rename))},ke.prototype.is_public_predicate=function(w){return!this.public_predicates.hasOwnProperty(w)||this.public_predicates[w]===!0},it.prototype.is_public_predicate=function(w){return this.session.is_public_predicate(w)},ke.prototype.is_multifile_predicate=function(w){return this.multifile_predicates.hasOwnProperty(w)&&this.multifile_predicates[w]===!0},it.prototype.is_multifile_predicate=function(w){return this.session.is_multifile_predicate(w)},ke.prototype.prepend=function(w){return this.thread.prepend(w)},it.prototype.prepend=function(w){for(var P=w.length-1;P>=0;P--)this.points.push(w[P])},ke.prototype.success=function(w,P){return this.thread.success(w,P)},it.prototype.success=function(w,y){var y=typeof y>\"u\"?w:y;this.prepend([new be(w.goal.replace(null),w.substitution,y)])},ke.prototype.throw_error=function(w){return this.thread.throw_error(w)},it.prototype.throw_error=function(w){this.prepend([new be(new j(\"throw\",[w]),new Ne,null,null)])},ke.prototype.step_rule=function(w,P){return this.thread.step_rule(w,P)},it.prototype.step_rule=function(w,P){var y=P.indicator;if(w===\"user\"&&(w=null),w===null&&this.session.rules.hasOwnProperty(y))return this.session.rules[y];for(var F=w===null?this.session.modules:e(this.session.modules,w)===-1?[]:[w],z=0;z<F.length;z++){var Z=x.module[F[z]];if(Z.rules.hasOwnProperty(y)&&(Z.rules.hasOwnProperty(this.level)||Z.exports_predicate(y)))return x.module[F[z]].rules[y]}return null},ke.prototype.step=function(){return this.thread.step()},it.prototype.step=function(){if(this.points.length!==0){var w=!1,P=this.points.pop();if(this.debugger&&this.debugger_states.push(P),x.type.is_term(P.goal)){var y=P.goal.select(),F=null,z=[];if(y!==null){this.total_steps++;for(var Z=P;Z.parent!==null&&Z.parent.goal.search(y);)Z=Z.parent;if(this.level=Z.parent===null?\"top_level/0\":Z.parent.goal.select().indicator,x.type.is_term(y)&&y.indicator===\":/2\"&&(F=y.args[0].id,y=y.args[1]),F===null&&x.type.is_builtin(y))this.__call_indicator=y.indicator,w=x.predicate[y.indicator](this,P,y);else{var $=this.step_rule(F,y);if($===null)this.session.rules.hasOwnProperty(y.indicator)||(this.get_flag(\"unknown\").id===\"error\"?this.throw_error(x.error.existence(\"procedure\",y.indicator,this.level)):this.get_flag(\"unknown\").id===\"warning\"&&this.throw_warning(\"unknown procedure \"+y.indicator+\" (from \"+this.level+\")\"));else if($ instanceof Function)w=$(this,P,y);else{for(var oe in $)if($.hasOwnProperty(oe)){var xe=$[oe];this.session.renamed_variables={},xe=xe.rename(this);var Re=this.get_flag(\"occurs_check\").indicator===\"true/0\",lt=new be,Ct=x.unify(y,xe.head,Re);Ct!==null&&(lt.goal=P.goal.replace(xe.body),lt.goal!==null&&(lt.goal=lt.goal.apply(Ct)),lt.substitution=P.substitution.apply(Ct),lt.parent=P,z.push(lt))}this.prepend(z)}}}}else x.type.is_variable(P.goal)?this.throw_error(x.error.instantiation(this.level)):this.throw_error(x.error.type(\"callable\",P.goal,this.level));return w}},ke.prototype.answer=function(w){return this.thread.answer(w)},it.prototype.answer=function(w){w=w||function(P){},this.__calls.push(w),!(this.__calls.length>1)&&this.again()},ke.prototype.answers=function(w,P,y){return this.thread.answers(w,P,y)},it.prototype.answers=function(w,P,y){var F=P||1e3,z=this;if(P<=0){y&&y();return}this.answer(function(Z){w(Z),Z!==!1?setTimeout(function(){z.answers(w,P-1,y)},1):y&&y()})},ke.prototype.again=function(w){return this.thread.again(w)},it.prototype.again=function(w){for(var P,y=Date.now();this.__calls.length>0;){for(this.warnings=[],w!==!1&&(this.current_limit=this.session.limit);this.current_limit>0&&this.points.length>0&&this.head_point().goal!==null&&!x.type.is_error(this.head_point().goal);)if(this.current_limit--,this.step()===!0)return;var F=Date.now();this.cpu_time_last=F-y,this.cpu_time+=this.cpu_time_last;var z=this.__calls.shift();this.current_limit<=0?z(null):this.points.length===0?z(!1):x.type.is_error(this.head_point().goal)?(P=this.session.format_error(this.points.pop()),this.points=[],z(P)):(this.debugger&&this.debugger_states.push(this.head_point()),P=this.session.format_success(this.points.pop()),z(P))}},ke.prototype.unfold=function(w){if(w.body===null)return!1;var P=w.head,y=w.body,F=y.select(),z=new it(this),Z=[];z.add_goal(F),z.step();for(var $=z.points.length-1;$>=0;$--){var oe=z.points[$],xe=P.apply(oe.substitution),Re=y.replace(oe.goal);Re!==null&&(Re=Re.apply(oe.substitution)),Z.push(new Ve(xe,Re))}var lt=this.rules[P.indicator],Ct=e(lt,w);return Z.length>0&&Ct!==-1?(lt.splice.apply(lt,[Ct,1].concat(Z)),!0):!1},it.prototype.unfold=function(w){return this.session.unfold(w)},De.prototype.interpret=function(w){return x.error.instantiation(w.level)},Te.prototype.interpret=function(w){return this},j.prototype.interpret=function(w){return x.type.is_unitary_list(this)?this.args[0].interpret(w):x.operate(w,this)},De.prototype.compare=function(w){return this.id<w.id?-1:this.id>w.id?1:0},Te.prototype.compare=function(w){if(this.value===w.value&&this.is_float===w.is_float)return 0;if(this.value<w.value||this.value===w.value&&this.is_float&&!w.is_float)return-1;if(this.value>w.value)return 1},j.prototype.compare=function(w){if(this.args.length<w.args.length||this.args.length===w.args.length&&this.id<w.id)return-1;if(this.args.length>w.args.length||this.args.length===w.args.length&&this.id>w.id)return 1;for(var P=0;P<this.args.length;P++){var y=x.compare(this.args[P],w.args[P]);if(y!==0)return y}return 0},Ne.prototype.lookup=function(w){return this.links[w]?this.links[w]:null},Ne.prototype.filter=function(w){var P={};for(var y in this.links)if(this.links.hasOwnProperty(y)){var F=this.links[y];w(y,F)&&(P[y]=F)}return new Ne(P)},Ne.prototype.exclude=function(w){var P={};for(var y in this.links)this.links.hasOwnProperty(y)&&e(w,y)===-1&&(P[y]=this.links[y]);return new Ne(P)},Ne.prototype.add=function(w,P){this.links[w]=P},Ne.prototype.domain=function(w){var P=w===!0?function(z){return z}:function(z){return new De(z)},y=[];for(var F in this.links)y.push(P(F));return y},De.prototype.compile=function(){return'new pl.type.Var(\"'+this.id.toString()+'\")'},Te.prototype.compile=function(){return\"new pl.type.Num(\"+this.value.toString()+\", \"+this.is_float.toString()+\")\"},j.prototype.compile=function(){return'new pl.type.Term(\"'+this.id.replace(/\"/g,'\\\\\"')+'\", ['+s(this.args,function(w){return w.compile()})+\"])\"},Ve.prototype.compile=function(){return\"new pl.type.Rule(\"+this.head.compile()+\", \"+(this.body===null?\"null\":this.body.compile())+\")\"},ke.prototype.compile=function(){var w,P=[],y;for(var F in this.rules)if(this.rules.hasOwnProperty(F)){var z=this.rules[F];y=[],w='\"'+F+'\": [';for(var Z=0;Z<z.length;Z++)y.push(z[Z].compile());w+=y.join(),w+=\"]\",P.push(w)}return\"{\"+P.join()+\"};\"},De.prototype.toJavaScript=function(){},Te.prototype.toJavaScript=function(){return this.value},j.prototype.toJavaScript=function(){if(this.args.length===0&&this.indicator!==\"[]/0\")return this.id;if(x.type.is_list(this)){for(var w=[],P=this,y;P.indicator===\"./2\";){if(y=P.args[0].toJavaScript(),y===void 0)return;w.push(y),P=P.args[1]}if(P.indicator===\"[]/0\")return w}},Ve.prototype.singleton_variables=function(){var w=this.head.variables(),P={},y=[];this.body!==null&&(w=w.concat(this.body.variables()));for(var F=0;F<w.length;F++)P[w[F]]===void 0&&(P[w[F]]=0),P[w[F]]++;for(var z in P)z!==\"_\"&&P[z]===1&&y.push(z);return y};var x={__env:typeof ec<\"u\"&&ec.exports?global:window,module:{},version:t,parser:{tokenizer:U,expression:W},utils:{str_indicator:X,codePointAt:n,fromCodePoint:c},statistics:{getCountTerms:function(){return mt}},fromJavaScript:{test:{boolean:function(w){return w===!0||w===!1},number:function(w){return typeof w==\"number\"},string:function(w){return typeof w==\"string\"},list:function(w){return w instanceof Array},variable:function(w){return w===void 0},any:function(w){return!0}},conversion:{boolean:function(w){return new j(w?\"true\":\"false\",[])},number:function(w){return new Te(w,w%1!==0)},string:function(w){return new j(w,[])},list:function(w){for(var P=[],y,F=0;F<w.length;F++){if(y=x.fromJavaScript.apply(w[F]),y===void 0)return;P.push(y)}return g(P)},variable:function(w){return new De(\"_\")},any:function(w){}},apply:function(w){for(var P in x.fromJavaScript.test)if(P!==\"any\"&&x.fromJavaScript.test[P](w))return x.fromJavaScript.conversion[P](w);return x.fromJavaScript.conversion.any(w)}},type:{Var:De,Num:Te,Term:j,Rule:Ve,State:be,Stream:Fe,Module:Ue,Thread:it,Session:ke,Substitution:Ne,order:[De,Te,j,Fe],compare:function(w,P){var y=e(x.type.order,w.constructor),F=e(x.type.order,P.constructor);if(y<F)return-1;if(y>F)return 1;if(w.constructor===Te){if(w.is_float&&P.is_float)return 0;if(w.is_float)return-1;if(P.is_float)return 1}return 0},is_substitution:function(w){return w instanceof Ne},is_state:function(w){return w instanceof be},is_rule:function(w){return w instanceof Ve},is_variable:function(w){return w instanceof De},is_stream:function(w){return w instanceof Fe},is_anonymous_var:function(w){return w instanceof De&&w.id===\"_\"},is_callable:function(w){return w instanceof j},is_number:function(w){return w instanceof Te},is_integer:function(w){return w instanceof Te&&!w.is_float},is_float:function(w){return w instanceof Te&&w.is_float},is_term:function(w){return w instanceof j},is_atom:function(w){return w instanceof j&&w.args.length===0},is_ground:function(w){if(w instanceof De)return!1;if(w instanceof j){for(var P=0;P<w.args.length;P++)if(!x.type.is_ground(w.args[P]))return!1}return!0},is_atomic:function(w){return w instanceof j&&w.args.length===0||w instanceof Te},is_compound:function(w){return w instanceof j&&w.args.length>0},is_list:function(w){return w instanceof j&&(w.indicator===\"[]/0\"||w.indicator===\"./2\")},is_empty_list:function(w){return w instanceof j&&w.indicator===\"[]/0\"},is_non_empty_list:function(w){return w instanceof j&&w.indicator===\"./2\"},is_fully_list:function(w){for(;w instanceof j&&w.indicator===\"./2\";)w=w.args[1];return w instanceof De||w instanceof j&&w.indicator===\"[]/0\"},is_instantiated_list:function(w){for(;w instanceof j&&w.indicator===\"./2\";)w=w.args[1];return w instanceof j&&w.indicator===\"[]/0\"},is_unitary_list:function(w){return w instanceof j&&w.indicator===\"./2\"&&w.args[1]instanceof j&&w.args[1].indicator===\"[]/0\"},is_character:function(w){return w instanceof j&&(w.id.length===1||w.id.length>0&&w.id.length<=2&&n(w.id,0)>=65536)},is_character_code:function(w){return w instanceof Te&&!w.is_float&&w.value>=0&&w.value<=1114111},is_byte:function(w){return w instanceof Te&&!w.is_float&&w.value>=0&&w.value<=255},is_operator:function(w){return w instanceof j&&x.arithmetic.evaluation[w.indicator]},is_directive:function(w){return w instanceof j&&x.directive[w.indicator]!==void 0},is_builtin:function(w){return w instanceof j&&x.predicate[w.indicator]!==void 0},is_error:function(w){return w instanceof j&&w.indicator===\"throw/1\"},is_predicate_indicator:function(w){return w instanceof j&&w.indicator===\"//2\"&&w.args[0]instanceof j&&w.args[0].args.length===0&&w.args[1]instanceof Te&&w.args[1].is_float===!1},is_flag:function(w){return w instanceof j&&w.args.length===0&&x.flag[w.id]!==void 0},is_value_flag:function(w,P){if(!x.type.is_flag(w))return!1;for(var y in x.flag[w.id].allowed)if(x.flag[w.id].allowed.hasOwnProperty(y)&&x.flag[w.id].allowed[y].equals(P))return!0;return!1},is_io_mode:function(w){return x.type.is_atom(w)&&[\"read\",\"write\",\"append\"].indexOf(w.id)!==-1},is_stream_option:function(w){return x.type.is_term(w)&&(w.indicator===\"alias/1\"&&x.type.is_atom(w.args[0])||w.indicator===\"reposition/1\"&&x.type.is_atom(w.args[0])&&(w.args[0].id===\"true\"||w.args[0].id===\"false\")||w.indicator===\"type/1\"&&x.type.is_atom(w.args[0])&&(w.args[0].id===\"text\"||w.args[0].id===\"binary\")||w.indicator===\"eof_action/1\"&&x.type.is_atom(w.args[0])&&(w.args[0].id===\"error\"||w.args[0].id===\"eof_code\"||w.args[0].id===\"reset\"))},is_stream_position:function(w){return x.type.is_integer(w)&&w.value>=0||x.type.is_atom(w)&&(w.id===\"end_of_stream\"||w.id===\"past_end_of_stream\")},is_stream_property:function(w){return x.type.is_term(w)&&(w.indicator===\"input/0\"||w.indicator===\"output/0\"||w.indicator===\"alias/1\"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0]))||w.indicator===\"file_name/1\"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0]))||w.indicator===\"position/1\"&&(x.type.is_variable(w.args[0])||x.type.is_stream_position(w.args[0]))||w.indicator===\"reposition/1\"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0])&&(w.args[0].id===\"true\"||w.args[0].id===\"false\"))||w.indicator===\"type/1\"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0])&&(w.args[0].id===\"text\"||w.args[0].id===\"binary\"))||w.indicator===\"mode/1\"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0])&&(w.args[0].id===\"read\"||w.args[0].id===\"write\"||w.args[0].id===\"append\"))||w.indicator===\"eof_action/1\"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0])&&(w.args[0].id===\"error\"||w.args[0].id===\"eof_code\"||w.args[0].id===\"reset\"))||w.indicator===\"end_of_stream/1\"&&(x.type.is_variable(w.args[0])||x.type.is_atom(w.args[0])&&(w.args[0].id===\"at\"||w.args[0].id===\"past\"||w.args[0].id===\"not\")))},is_streamable:function(w){return w.__proto__.stream!==void 0},is_read_option:function(w){return x.type.is_term(w)&&[\"variables/1\",\"variable_names/1\",\"singletons/1\"].indexOf(w.indicator)!==-1},is_write_option:function(w){return x.type.is_term(w)&&(w.indicator===\"quoted/1\"&&x.type.is_atom(w.args[0])&&(w.args[0].id===\"true\"||w.args[0].id===\"false\")||w.indicator===\"ignore_ops/1\"&&x.type.is_atom(w.args[0])&&(w.args[0].id===\"true\"||w.args[0].id===\"false\")||w.indicator===\"numbervars/1\"&&x.type.is_atom(w.args[0])&&(w.args[0].id===\"true\"||w.args[0].id===\"false\"))},is_close_option:function(w){return x.type.is_term(w)&&w.indicator===\"force/1\"&&x.type.is_atom(w.args[0])&&(w.args[0].id===\"true\"||w.args[0].id===\"false\")},is_modifiable_flag:function(w){return x.type.is_flag(w)&&x.flag[w.id].changeable},is_module:function(w){return w instanceof j&&w.indicator===\"library/1\"&&w.args[0]instanceof j&&w.args[0].args.length===0&&x.module[w.args[0].id]!==void 0}},arithmetic:{evaluation:{\"e/0\":{type_args:null,type_result:!0,fn:function(w){return Math.E}},\"pi/0\":{type_args:null,type_result:!0,fn:function(w){return Math.PI}},\"tau/0\":{type_args:null,type_result:!0,fn:function(w){return 2*Math.PI}},\"epsilon/0\":{type_args:null,type_result:!0,fn:function(w){return Number.EPSILON}},\"+/1\":{type_args:null,type_result:null,fn:function(w,P){return w}},\"-/1\":{type_args:null,type_result:null,fn:function(w,P){return-w}},\"\\\\/1\":{type_args:!1,type_result:!1,fn:function(w,P){return~w}},\"abs/1\":{type_args:null,type_result:null,fn:function(w,P){return Math.abs(w)}},\"sign/1\":{type_args:null,type_result:null,fn:function(w,P){return Math.sign(w)}},\"float_integer_part/1\":{type_args:!0,type_result:!1,fn:function(w,P){return parseInt(w)}},\"float_fractional_part/1\":{type_args:!0,type_result:!0,fn:function(w,P){return w-parseInt(w)}},\"float/1\":{type_args:null,type_result:!0,fn:function(w,P){return parseFloat(w)}},\"floor/1\":{type_args:!0,type_result:!1,fn:function(w,P){return Math.floor(w)}},\"truncate/1\":{type_args:!0,type_result:!1,fn:function(w,P){return parseInt(w)}},\"round/1\":{type_args:!0,type_result:!1,fn:function(w,P){return Math.round(w)}},\"ceiling/1\":{type_args:!0,type_result:!1,fn:function(w,P){return Math.ceil(w)}},\"sin/1\":{type_args:null,type_result:!0,fn:function(w,P){return Math.sin(w)}},\"cos/1\":{type_args:null,type_result:!0,fn:function(w,P){return Math.cos(w)}},\"tan/1\":{type_args:null,type_result:!0,fn:function(w,P){return Math.tan(w)}},\"asin/1\":{type_args:null,type_result:!0,fn:function(w,P){return Math.asin(w)}},\"acos/1\":{type_args:null,type_result:!0,fn:function(w,P){return Math.acos(w)}},\"atan/1\":{type_args:null,type_result:!0,fn:function(w,P){return Math.atan(w)}},\"atan2/2\":{type_args:null,type_result:!0,fn:function(w,P,y){return Math.atan2(w,P)}},\"exp/1\":{type_args:null,type_result:!0,fn:function(w,P){return Math.exp(w)}},\"sqrt/1\":{type_args:null,type_result:!0,fn:function(w,P){return Math.sqrt(w)}},\"log/1\":{type_args:null,type_result:!0,fn:function(w,P){return w>0?Math.log(w):x.error.evaluation(\"undefined\",P.__call_indicator)}},\"+/2\":{type_args:null,type_result:null,fn:function(w,P,y){return w+P}},\"-/2\":{type_args:null,type_result:null,fn:function(w,P,y){return w-P}},\"*/2\":{type_args:null,type_result:null,fn:function(w,P,y){return w*P}},\"//2\":{type_args:null,type_result:!0,fn:function(w,P,y){return P?w/P:x.error.evaluation(\"zero_division\",y.__call_indicator)}},\"///2\":{type_args:!1,type_result:!1,fn:function(w,P,y){return P?parseInt(w/P):x.error.evaluation(\"zero_division\",y.__call_indicator)}},\"**/2\":{type_args:null,type_result:!0,fn:function(w,P,y){return Math.pow(w,P)}},\"^/2\":{type_args:null,type_result:null,fn:function(w,P,y){return Math.pow(w,P)}},\"<</2\":{type_args:!1,type_result:!1,fn:function(w,P,y){return w<<P}},\">>/2\":{type_args:!1,type_result:!1,fn:function(w,P,y){return w>>P}},\"/\\\\/2\":{type_args:!1,type_result:!1,fn:function(w,P,y){return w&P}},\"\\\\//2\":{type_args:!1,type_result:!1,fn:function(w,P,y){return w|P}},\"xor/2\":{type_args:!1,type_result:!1,fn:function(w,P,y){return w^P}},\"rem/2\":{type_args:!1,type_result:!1,fn:function(w,P,y){return P?w%P:x.error.evaluation(\"zero_division\",y.__call_indicator)}},\"mod/2\":{type_args:!1,type_result:!1,fn:function(w,P,y){return P?w-parseInt(w/P)*P:x.error.evaluation(\"zero_division\",y.__call_indicator)}},\"max/2\":{type_args:null,type_result:null,fn:function(w,P,y){return Math.max(w,P)}},\"min/2\":{type_args:null,type_result:null,fn:function(w,P,y){return Math.min(w,P)}}}},directive:{\"dynamic/1\":function(w,P){var y=P.args[0];if(x.type.is_variable(y))w.throw_error(x.error.instantiation(P.indicator));else if(!x.type.is_compound(y)||y.indicator!==\"//2\")w.throw_error(x.error.type(\"predicate_indicator\",y,P.indicator));else if(x.type.is_variable(y.args[0])||x.type.is_variable(y.args[1]))w.throw_error(x.error.instantiation(P.indicator));else if(!x.type.is_atom(y.args[0]))w.throw_error(x.error.type(\"atom\",y.args[0],P.indicator));else if(!x.type.is_integer(y.args[1]))w.throw_error(x.error.type(\"integer\",y.args[1],P.indicator));else{var F=P.args[0].args[0].id+\"/\"+P.args[0].args[1].value;w.session.public_predicates[F]=!0,w.session.rules[F]||(w.session.rules[F]=[])}},\"multifile/1\":function(w,P){var y=P.args[0];x.type.is_variable(y)?w.throw_error(x.error.instantiation(P.indicator)):!x.type.is_compound(y)||y.indicator!==\"//2\"?w.throw_error(x.error.type(\"predicate_indicator\",y,P.indicator)):x.type.is_variable(y.args[0])||x.type.is_variable(y.args[1])?w.throw_error(x.error.instantiation(P.indicator)):x.type.is_atom(y.args[0])?x.type.is_integer(y.args[1])?w.session.multifile_predicates[P.args[0].args[0].id+\"/\"+P.args[0].args[1].value]=!0:w.throw_error(x.error.type(\"integer\",y.args[1],P.indicator)):w.throw_error(x.error.type(\"atom\",y.args[0],P.indicator))},\"set_prolog_flag/2\":function(w,P){var y=P.args[0],F=P.args[1];x.type.is_variable(y)||x.type.is_variable(F)?w.throw_error(x.error.instantiation(P.indicator)):x.type.is_atom(y)?x.type.is_flag(y)?x.type.is_value_flag(y,F)?x.type.is_modifiable_flag(y)?w.session.flag[y.id]=F:w.throw_error(x.error.permission(\"modify\",\"flag\",y)):w.throw_error(x.error.domain(\"flag_value\",new j(\"+\",[y,F]),P.indicator)):w.throw_error(x.error.domain(\"prolog_flag\",y,P.indicator)):w.throw_error(x.error.type(\"atom\",y,P.indicator))},\"use_module/1\":function(w,P){var y=P.args[0];if(x.type.is_variable(y))w.throw_error(x.error.instantiation(P.indicator));else if(!x.type.is_term(y))w.throw_error(x.error.type(\"term\",y,P.indicator));else if(x.type.is_module(y)){var F=y.args[0].id;e(w.session.modules,F)===-1&&w.session.modules.push(F)}},\"char_conversion/2\":function(w,P){var y=P.args[0],F=P.args[1];x.type.is_variable(y)||x.type.is_variable(F)?w.throw_error(x.error.instantiation(P.indicator)):x.type.is_character(y)?x.type.is_character(F)?y.id===F.id?delete w.session.__char_conversion[y.id]:w.session.__char_conversion[y.id]=F.id:w.throw_error(x.error.type(\"character\",F,P.indicator)):w.throw_error(x.error.type(\"character\",y,P.indicator))},\"op/3\":function(w,P){var y=P.args[0],F=P.args[1],z=P.args[2];if(x.type.is_variable(y)||x.type.is_variable(F)||x.type.is_variable(z))w.throw_error(x.error.instantiation(P.indicator));else if(!x.type.is_integer(y))w.throw_error(x.error.type(\"integer\",y,P.indicator));else if(!x.type.is_atom(F))w.throw_error(x.error.type(\"atom\",F,P.indicator));else if(!x.type.is_atom(z))w.throw_error(x.error.type(\"atom\",z,P.indicator));else if(y.value<0||y.value>1200)w.throw_error(x.error.domain(\"operator_priority\",y,P.indicator));else if(z.id===\",\")w.throw_error(x.error.permission(\"modify\",\"operator\",z,P.indicator));else if(z.id===\"|\"&&(y.value<1001||F.id.length!==3))w.throw_error(x.error.permission(\"modify\",\"operator\",z,P.indicator));else if([\"fy\",\"fx\",\"yf\",\"xf\",\"xfx\",\"yfx\",\"xfy\"].indexOf(F.id)===-1)w.throw_error(x.error.domain(\"operator_specifier\",F,P.indicator));else{var Z={prefix:null,infix:null,postfix:null};for(var $ in w.session.__operators)if(w.session.__operators.hasOwnProperty($)){var oe=w.session.__operators[$][z.id];oe&&(e(oe,\"fx\")!==-1&&(Z.prefix={priority:$,type:\"fx\"}),e(oe,\"fy\")!==-1&&(Z.prefix={priority:$,type:\"fy\"}),e(oe,\"xf\")!==-1&&(Z.postfix={priority:$,type:\"xf\"}),e(oe,\"yf\")!==-1&&(Z.postfix={priority:$,type:\"yf\"}),e(oe,\"xfx\")!==-1&&(Z.infix={priority:$,type:\"xfx\"}),e(oe,\"xfy\")!==-1&&(Z.infix={priority:$,type:\"xfy\"}),e(oe,\"yfx\")!==-1&&(Z.infix={priority:$,type:\"yfx\"}))}var xe;switch(F.id){case\"fy\":case\"fx\":xe=\"prefix\";break;case\"yf\":case\"xf\":xe=\"postfix\";break;default:xe=\"infix\";break}if(((Z.prefix&&xe===\"prefix\"||Z.postfix&&xe===\"postfix\"||Z.infix&&xe===\"infix\")&&Z[xe].type!==F.id||Z.infix&&xe===\"postfix\"||Z.postfix&&xe===\"infix\")&&y.value!==0)w.throw_error(x.error.permission(\"create\",\"operator\",z,P.indicator));else return Z[xe]&&(we(w.session.__operators[Z[xe].priority][z.id],F.id),w.session.__operators[Z[xe].priority][z.id].length===0&&delete w.session.__operators[Z[xe].priority][z.id]),y.value>0&&(w.session.__operators[y.value]||(w.session.__operators[y.value.toString()]={}),w.session.__operators[y.value][z.id]||(w.session.__operators[y.value][z.id]=[]),w.session.__operators[y.value][z.id].push(F.id)),!0}}},predicate:{\"op/3\":function(w,P,y){x.directive[\"op/3\"](w,y)&&w.success(P)},\"current_op/3\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=y.args[2],$=[];for(var oe in w.session.__operators)for(var xe in w.session.__operators[oe])for(var Re=0;Re<w.session.__operators[oe][xe].length;Re++)$.push(new be(P.goal.replace(new j(\",\",[new j(\"=\",[new Te(oe,!1),F]),new j(\",\",[new j(\"=\",[new j(w.session.__operators[oe][xe][Re],[]),z]),new j(\"=\",[new j(xe,[]),Z])])])),P.substitution,P));w.prepend($)},\";/2\":function(w,P,y){if(x.type.is_term(y.args[0])&&y.args[0].indicator===\"->/2\"){var F=w.points,z=w.session.format_success,Z=w.session.format_error;w.session.format_success=function(Re){return Re.substitution},w.session.format_error=function(Re){return Re.goal},w.points=[new be(y.args[0].args[0],P.substitution,P)];var $=function(Re){w.points=F,w.session.format_success=z,w.session.format_error=Z,Re===!1?w.prepend([new be(P.goal.replace(y.args[1]),P.substitution,P)]):x.type.is_error(Re)?w.throw_error(Re.args[0]):Re===null?(w.prepend([P]),w.__calls.shift()(null)):w.prepend([new be(P.goal.replace(y.args[0].args[1]).apply(Re),P.substitution.apply(Re),P)])};w.__calls.unshift($)}else{var oe=new be(P.goal.replace(y.args[0]),P.substitution,P),xe=new be(P.goal.replace(y.args[1]),P.substitution,P);w.prepend([oe,xe])}},\"!/0\":function(w,P,y){var F,z,Z=[];for(F=P,z=null;F.parent!==null&&F.parent.goal.search(y);)if(z=F,F=F.parent,F.goal!==null){var $=F.goal.select();if($&&$.id===\"call\"&&$.search(y)){F=z;break}}for(var oe=w.points.length-1;oe>=0;oe--){for(var xe=w.points[oe],Re=xe.parent;Re!==null&&Re!==F.parent;)Re=Re.parent;Re===null&&Re!==F.parent&&Z.push(xe)}w.points=Z.reverse(),w.success(P)},\"\\\\+/1\":function(w,P,y){var F=y.args[0];x.type.is_variable(F)?w.throw_error(x.error.instantiation(w.level)):x.type.is_callable(F)?w.prepend([new be(P.goal.replace(new j(\",\",[new j(\",\",[new j(\"call\",[F]),new j(\"!\",[])]),new j(\"fail\",[])])),P.substitution,P),new be(P.goal.replace(null),P.substitution,P)]):w.throw_error(x.error.type(\"callable\",F,w.level))},\"->/2\":function(w,P,y){var F=P.goal.replace(new j(\",\",[y.args[0],new j(\",\",[new j(\"!\"),y.args[1]])]));w.prepend([new be(F,P.substitution,P)])},\"fail/0\":function(w,P,y){},\"false/0\":function(w,P,y){},\"true/0\":function(w,P,y){w.success(P)},\"call/1\":se(1),\"call/2\":se(2),\"call/3\":se(3),\"call/4\":se(4),\"call/5\":se(5),\"call/6\":se(6),\"call/7\":se(7),\"call/8\":se(8),\"once/1\":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"call\",[F]),new j(\"!\",[])])),P.substitution,P)])},\"forall/2\":function(w,P,y){var F=y.args[0],z=y.args[1];w.prepend([new be(P.goal.replace(new j(\"\\\\+\",[new j(\",\",[new j(\"call\",[F]),new j(\"\\\\+\",[new j(\"call\",[z])])])])),P.substitution,P)])},\"repeat/0\":function(w,P,y){w.prepend([new be(P.goal.replace(null),P.substitution,P),P])},\"throw/1\":function(w,P,y){x.type.is_variable(y.args[0])?w.throw_error(x.error.instantiation(w.level)):w.throw_error(y.args[0])},\"catch/3\":function(w,P,y){var F=w.points;w.points=[],w.prepend([new be(y.args[0],P.substitution,P)]);var z=w.session.format_success,Z=w.session.format_error;w.session.format_success=function(oe){return oe.substitution},w.session.format_error=function(oe){return oe.goal};var $=function(oe){var xe=w.points;if(w.points=F,w.session.format_success=z,w.session.format_error=Z,x.type.is_error(oe)){for(var Re=[],lt=w.points.length-1;lt>=0;lt--){for(var ir=w.points[lt],Ct=ir.parent;Ct!==null&&Ct!==P.parent;)Ct=Ct.parent;Ct===null&&Ct!==P.parent&&Re.push(ir)}w.points=Re;var qt=w.get_flag(\"occurs_check\").indicator===\"true/0\",ir=new be,bt=x.unify(oe.args[0],y.args[1],qt);bt!==null?(ir.substitution=P.substitution.apply(bt),ir.goal=P.goal.replace(y.args[2]).apply(bt),ir.parent=P,w.prepend([ir])):w.throw_error(oe.args[0])}else if(oe!==!1){for(var gn=oe===null?[]:[new be(P.goal.apply(oe).replace(null),P.substitution.apply(oe),P)],br=[],lt=xe.length-1;lt>=0;lt--){br.push(xe[lt]);var Ir=xe[lt].goal!==null?xe[lt].goal.select():null;if(x.type.is_term(Ir)&&Ir.indicator===\"!/0\")break}var Or=s(br,function(nn){return nn.goal===null&&(nn.goal=new j(\"true\",[])),nn=new be(P.goal.replace(new j(\"catch\",[nn.goal,y.args[1],y.args[2]])),P.substitution.apply(nn.substitution),nn.parent),nn.exclude=y.args[0].variables(),nn}).reverse();w.prepend(Or),w.prepend(gn),oe===null&&(this.current_limit=0,w.__calls.shift()(null))}};w.__calls.unshift($)},\"=/2\":function(w,P,y){var F=w.get_flag(\"occurs_check\").indicator===\"true/0\",z=new be,Z=x.unify(y.args[0],y.args[1],F);Z!==null&&(z.goal=P.goal.apply(Z).replace(null),z.substitution=P.substitution.apply(Z),z.parent=P,w.prepend([z]))},\"unify_with_occurs_check/2\":function(w,P,y){var F=new be,z=x.unify(y.args[0],y.args[1],!0);z!==null&&(F.goal=P.goal.apply(z).replace(null),F.substitution=P.substitution.apply(z),F.parent=P,w.prepend([F]))},\"\\\\=/2\":function(w,P,y){var F=w.get_flag(\"occurs_check\").indicator===\"true/0\",z=x.unify(y.args[0],y.args[1],F);z===null&&w.success(P)},\"subsumes_term/2\":function(w,P,y){var F=w.get_flag(\"occurs_check\").indicator===\"true/0\",z=x.unify(y.args[1],y.args[0],F);z!==null&&y.args[1].apply(z).equals(y.args[1])&&w.success(P)},\"findall/3\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=y.args[2];if(x.type.is_variable(z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(z))w.throw_error(x.error.type(\"callable\",z,y.indicator));else if(!x.type.is_variable(Z)&&!x.type.is_list(Z))w.throw_error(x.error.type(\"list\",Z,y.indicator));else{var $=w.next_free_variable(),oe=new j(\",\",[z,new j(\"=\",[$,F])]),xe=w.points,Re=w.session.limit,lt=w.session.format_success;w.session.format_success=function(ir){return ir.substitution},w.add_goal(oe,!0,P);var Ct=[],qt=function(ir){if(ir!==!1&&ir!==null&&!x.type.is_error(ir))w.__calls.unshift(qt),Ct.push(ir.links[$.id]),w.session.limit=w.current_limit;else if(w.points=xe,w.session.limit=Re,w.session.format_success=lt,x.type.is_error(ir))w.throw_error(ir.args[0]);else if(w.current_limit>0){for(var bt=new j(\"[]\"),gn=Ct.length-1;gn>=0;gn--)bt=new j(\".\",[Ct[gn],bt]);w.prepend([new be(P.goal.replace(new j(\"=\",[Z,bt])),P.substitution,P)])}};w.__calls.unshift(qt)}},\"bagof/3\":function(w,P,y){var F,z=y.args[0],Z=y.args[1],$=y.args[2];if(x.type.is_variable(Z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(Z))w.throw_error(x.error.type(\"callable\",Z,y.indicator));else if(!x.type.is_variable($)&&!x.type.is_list($))w.throw_error(x.error.type(\"list\",$,y.indicator));else{var oe=w.next_free_variable(),xe;Z.indicator===\"^/2\"?(xe=Z.args[0].variables(),Z=Z.args[1]):xe=[],xe=xe.concat(z.variables());for(var Re=Z.variables().filter(function(Or){return e(xe,Or)===-1}),lt=new j(\"[]\"),Ct=Re.length-1;Ct>=0;Ct--)lt=new j(\".\",[new De(Re[Ct]),lt]);var qt=new j(\",\",[Z,new j(\"=\",[oe,new j(\",\",[lt,z])])]),ir=w.points,bt=w.session.limit,gn=w.session.format_success;w.session.format_success=function(Or){return Or.substitution},w.add_goal(qt,!0,P);var br=[],Ir=function(Or){if(Or!==!1&&Or!==null&&!x.type.is_error(Or)){w.__calls.unshift(Ir);var nn=!1,ai=Or.links[oe.id].args[0],Io=Or.links[oe.id].args[1];for(var ts in br)if(br.hasOwnProperty(ts)){var $s=br[ts];if($s.variables.equals(ai)){$s.answers.push(Io),nn=!0;break}}nn||br.push({variables:ai,answers:[Io]}),w.session.limit=w.current_limit}else if(w.points=ir,w.session.limit=bt,w.session.format_success=gn,x.type.is_error(Or))w.throw_error(Or.args[0]);else if(w.current_limit>0){for(var Co=[],Hi=0;Hi<br.length;Hi++){Or=br[Hi].answers;for(var eo=new j(\"[]\"),wo=Or.length-1;wo>=0;wo--)eo=new j(\".\",[Or[wo],eo]);Co.push(new be(P.goal.replace(new j(\",\",[new j(\"=\",[lt,br[Hi].variables]),new j(\"=\",[$,eo])])),P.substitution,P))}w.prepend(Co)}};w.__calls.unshift(Ir)}},\"setof/3\":function(w,P,y){var F,z=y.args[0],Z=y.args[1],$=y.args[2];if(x.type.is_variable(Z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(Z))w.throw_error(x.error.type(\"callable\",Z,y.indicator));else if(!x.type.is_variable($)&&!x.type.is_list($))w.throw_error(x.error.type(\"list\",$,y.indicator));else{var oe=w.next_free_variable(),xe;Z.indicator===\"^/2\"?(xe=Z.args[0].variables(),Z=Z.args[1]):xe=[],xe=xe.concat(z.variables());for(var Re=Z.variables().filter(function(Or){return e(xe,Or)===-1}),lt=new j(\"[]\"),Ct=Re.length-1;Ct>=0;Ct--)lt=new j(\".\",[new De(Re[Ct]),lt]);var qt=new j(\",\",[Z,new j(\"=\",[oe,new j(\",\",[lt,z])])]),ir=w.points,bt=w.session.limit,gn=w.session.format_success;w.session.format_success=function(Or){return Or.substitution},w.add_goal(qt,!0,P);var br=[],Ir=function(Or){if(Or!==!1&&Or!==null&&!x.type.is_error(Or)){w.__calls.unshift(Ir);var nn=!1,ai=Or.links[oe.id].args[0],Io=Or.links[oe.id].args[1];for(var ts in br)if(br.hasOwnProperty(ts)){var $s=br[ts];if($s.variables.equals(ai)){$s.answers.push(Io),nn=!0;break}}nn||br.push({variables:ai,answers:[Io]}),w.session.limit=w.current_limit}else if(w.points=ir,w.session.limit=bt,w.session.format_success=gn,x.type.is_error(Or))w.throw_error(Or.args[0]);else if(w.current_limit>0){for(var Co=[],Hi=0;Hi<br.length;Hi++){Or=br[Hi].answers.sort(x.compare);for(var eo=new j(\"[]\"),wo=Or.length-1;wo>=0;wo--)eo=new j(\".\",[Or[wo],eo]);Co.push(new be(P.goal.replace(new j(\",\",[new j(\"=\",[lt,br[Hi].variables]),new j(\"=\",[$,eo])])),P.substitution,P))}w.prepend(Co)}};w.__calls.unshift(Ir)}},\"functor/3\":function(w,P,y){var F,z=y.args[0],Z=y.args[1],$=y.args[2];if(x.type.is_variable(z)&&(x.type.is_variable(Z)||x.type.is_variable($)))w.throw_error(x.error.instantiation(\"functor/3\"));else if(!x.type.is_variable($)&&!x.type.is_integer($))w.throw_error(x.error.type(\"integer\",y.args[2],\"functor/3\"));else if(!x.type.is_variable(Z)&&!x.type.is_atomic(Z))w.throw_error(x.error.type(\"atomic\",y.args[1],\"functor/3\"));else if(x.type.is_integer(Z)&&x.type.is_integer($)&&$.value!==0)w.throw_error(x.error.type(\"atom\",y.args[1],\"functor/3\"));else if(x.type.is_variable(z)){if(y.args[2].value>=0){for(var oe=[],xe=0;xe<$.value;xe++)oe.push(w.next_free_variable());var Re=x.type.is_integer(Z)?Z:new j(Z.id,oe);w.prepend([new be(P.goal.replace(new j(\"=\",[z,Re])),P.substitution,P)])}}else{var lt=x.type.is_integer(z)?z:new j(z.id,[]),Ct=x.type.is_integer(z)?new Te(0,!1):new Te(z.args.length,!1),qt=new j(\",\",[new j(\"=\",[lt,Z]),new j(\"=\",[Ct,$])]);w.prepend([new be(P.goal.replace(qt),P.substitution,P)])}},\"arg/3\":function(w,P,y){if(x.type.is_variable(y.args[0])||x.type.is_variable(y.args[1]))w.throw_error(x.error.instantiation(y.indicator));else if(y.args[0].value<0)w.throw_error(x.error.domain(\"not_less_than_zero\",y.args[0],y.indicator));else if(!x.type.is_compound(y.args[1]))w.throw_error(x.error.type(\"compound\",y.args[1],y.indicator));else{var F=y.args[0].value;if(F>0&&F<=y.args[1].args.length){var z=new j(\"=\",[y.args[1].args[F-1],y.args[2]]);w.prepend([new be(P.goal.replace(z),P.substitution,P)])}}},\"=../2\":function(w,P,y){var F;if(x.type.is_variable(y.args[0])&&(x.type.is_variable(y.args[1])||x.type.is_non_empty_list(y.args[1])&&x.type.is_variable(y.args[1].args[0])))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_fully_list(y.args[1]))w.throw_error(x.error.type(\"list\",y.args[1],y.indicator));else if(x.type.is_variable(y.args[0])){if(!x.type.is_variable(y.args[1])){var Z=[];for(F=y.args[1].args[1];F.indicator===\"./2\";)Z.push(F.args[0]),F=F.args[1];x.type.is_variable(y.args[0])&&x.type.is_variable(F)?w.throw_error(x.error.instantiation(y.indicator)):Z.length===0&&x.type.is_compound(y.args[1].args[0])?w.throw_error(x.error.type(\"atomic\",y.args[1].args[0],y.indicator)):Z.length>0&&(x.type.is_compound(y.args[1].args[0])||x.type.is_number(y.args[1].args[0]))?w.throw_error(x.error.type(\"atom\",y.args[1].args[0],y.indicator)):Z.length===0?w.prepend([new be(P.goal.replace(new j(\"=\",[y.args[1].args[0],y.args[0]],P)),P.substitution,P)]):w.prepend([new be(P.goal.replace(new j(\"=\",[new j(y.args[1].args[0].id,Z),y.args[0]])),P.substitution,P)])}}else{if(x.type.is_atomic(y.args[0]))F=new j(\".\",[y.args[0],new j(\"[]\")]);else{F=new j(\"[]\");for(var z=y.args[0].args.length-1;z>=0;z--)F=new j(\".\",[y.args[0].args[z],F]);F=new j(\".\",[new j(y.args[0].id),F])}w.prepend([new be(P.goal.replace(new j(\"=\",[F,y.args[1]])),P.substitution,P)])}},\"copy_term/2\":function(w,P,y){var F=y.args[0].rename(w);w.prepend([new be(P.goal.replace(new j(\"=\",[F,y.args[1]])),P.substitution,P.parent)])},\"term_variables/2\":function(w,P,y){var F=y.args[0],z=y.args[1];if(!x.type.is_fully_list(z))w.throw_error(x.error.type(\"list\",z,y.indicator));else{var Z=g(s(ye(F.variables()),function($){return new De($)}));w.prepend([new be(P.goal.replace(new j(\"=\",[z,Z])),P.substitution,P)])}},\"clause/2\":function(w,P,y){if(x.type.is_variable(y.args[0]))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(y.args[0]))w.throw_error(x.error.type(\"callable\",y.args[0],y.indicator));else if(!x.type.is_variable(y.args[1])&&!x.type.is_callable(y.args[1]))w.throw_error(x.error.type(\"callable\",y.args[1],y.indicator));else if(w.session.rules[y.args[0].indicator]!==void 0)if(w.is_public_predicate(y.args[0].indicator)){var F=[];for(var z in w.session.rules[y.args[0].indicator])if(w.session.rules[y.args[0].indicator].hasOwnProperty(z)){var Z=w.session.rules[y.args[0].indicator][z];w.session.renamed_variables={},Z=Z.rename(w),Z.body===null&&(Z.body=new j(\"true\"));var $=new j(\",\",[new j(\"=\",[Z.head,y.args[0]]),new j(\"=\",[Z.body,y.args[1]])]);F.push(new be(P.goal.replace($),P.substitution,P))}w.prepend(F)}else w.throw_error(x.error.permission(\"access\",\"private_procedure\",y.args[0].indicator,y.indicator))},\"current_predicate/1\":function(w,P,y){var F=y.args[0];if(!x.type.is_variable(F)&&(!x.type.is_compound(F)||F.indicator!==\"//2\"))w.throw_error(x.error.type(\"predicate_indicator\",F,y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_variable(F.args[0])&&!x.type.is_atom(F.args[0]))w.throw_error(x.error.type(\"atom\",F.args[0],y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_variable(F.args[1])&&!x.type.is_integer(F.args[1]))w.throw_error(x.error.type(\"integer\",F.args[1],y.indicator));else{var z=[];for(var Z in w.session.rules)if(w.session.rules.hasOwnProperty(Z)){var $=Z.lastIndexOf(\"/\"),oe=Z.substr(0,$),xe=parseInt(Z.substr($+1,Z.length-($+1))),Re=new j(\"/\",[new j(oe),new Te(xe,!1)]),lt=new j(\"=\",[Re,F]);z.push(new be(P.goal.replace(lt),P.substitution,P))}w.prepend(z)}},\"asserta/1\":function(w,P,y){if(x.type.is_variable(y.args[0]))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(y.args[0]))w.throw_error(x.error.type(\"callable\",y.args[0],y.indicator));else{var F,z;y.args[0].indicator===\":-/2\"?(F=y.args[0].args[0],z=Ce(y.args[0].args[1])):(F=y.args[0],z=null),x.type.is_callable(F)?z!==null&&!x.type.is_callable(z)?w.throw_error(x.error.type(\"callable\",z,y.indicator)):w.is_public_predicate(F.indicator)?(w.session.rules[F.indicator]===void 0&&(w.session.rules[F.indicator]=[]),w.session.public_predicates[F.indicator]=!0,w.session.rules[F.indicator]=[new Ve(F,z,!0)].concat(w.session.rules[F.indicator]),w.success(P)):w.throw_error(x.error.permission(\"modify\",\"static_procedure\",F.indicator,y.indicator)):w.throw_error(x.error.type(\"callable\",F,y.indicator))}},\"assertz/1\":function(w,P,y){if(x.type.is_variable(y.args[0]))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(y.args[0]))w.throw_error(x.error.type(\"callable\",y.args[0],y.indicator));else{var F,z;y.args[0].indicator===\":-/2\"?(F=y.args[0].args[0],z=Ce(y.args[0].args[1])):(F=y.args[0],z=null),x.type.is_callable(F)?z!==null&&!x.type.is_callable(z)?w.throw_error(x.error.type(\"callable\",z,y.indicator)):w.is_public_predicate(F.indicator)?(w.session.rules[F.indicator]===void 0&&(w.session.rules[F.indicator]=[]),w.session.public_predicates[F.indicator]=!0,w.session.rules[F.indicator].push(new Ve(F,z,!0)),w.success(P)):w.throw_error(x.error.permission(\"modify\",\"static_procedure\",F.indicator,y.indicator)):w.throw_error(x.error.type(\"callable\",F,y.indicator))}},\"retract/1\":function(w,P,y){if(x.type.is_variable(y.args[0]))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_callable(y.args[0]))w.throw_error(x.error.type(\"callable\",y.args[0],y.indicator));else{var F,z;if(y.args[0].indicator===\":-/2\"?(F=y.args[0].args[0],z=y.args[0].args[1]):(F=y.args[0],z=new j(\"true\")),typeof P.retract>\"u\")if(w.is_public_predicate(F.indicator)){if(w.session.rules[F.indicator]!==void 0){for(var Z=[],$=0;$<w.session.rules[F.indicator].length;$++){w.session.renamed_variables={};var oe=w.session.rules[F.indicator][$],xe=oe.rename(w);xe.body===null&&(xe.body=new j(\"true\",[]));var Re=w.get_flag(\"occurs_check\").indicator===\"true/0\",lt=x.unify(new j(\",\",[F,z]),new j(\",\",[xe.head,xe.body]),Re);if(lt!==null){var Ct=new be(P.goal.replace(new j(\",\",[new j(\"retract\",[new j(\":-\",[F,z])]),new j(\",\",[new j(\"=\",[F,xe.head]),new j(\"=\",[z,xe.body])])])),P.substitution,P);Ct.retract=oe,Z.push(Ct)}}w.prepend(Z)}}else w.throw_error(x.error.permission(\"modify\",\"static_procedure\",F.indicator,y.indicator));else Ae(w,P,F.indicator,P.retract)}},\"retractall/1\":function(w,P,y){var F=y.args[0];x.type.is_variable(F)?w.throw_error(x.error.instantiation(y.indicator)):x.type.is_callable(F)?w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"retract\",[new x.type.Term(\":-\",[F,new De(\"_\")])]),new j(\"fail\",[])])),P.substitution,P),new be(P.goal.replace(null),P.substitution,P)]):w.throw_error(x.error.type(\"callable\",F,y.indicator))},\"abolish/1\":function(w,P,y){if(x.type.is_variable(y.args[0])||x.type.is_term(y.args[0])&&y.args[0].indicator===\"//2\"&&(x.type.is_variable(y.args[0].args[0])||x.type.is_variable(y.args[0].args[1])))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_term(y.args[0])||y.args[0].indicator!==\"//2\")w.throw_error(x.error.type(\"predicate_indicator\",y.args[0],y.indicator));else if(!x.type.is_atom(y.args[0].args[0]))w.throw_error(x.error.type(\"atom\",y.args[0].args[0],y.indicator));else if(!x.type.is_integer(y.args[0].args[1]))w.throw_error(x.error.type(\"integer\",y.args[0].args[1],y.indicator));else if(y.args[0].args[1].value<0)w.throw_error(x.error.domain(\"not_less_than_zero\",y.args[0].args[1],y.indicator));else if(x.type.is_number(w.get_flag(\"max_arity\"))&&y.args[0].args[1].value>w.get_flag(\"max_arity\").value)w.throw_error(x.error.representation(\"max_arity\",y.indicator));else{var F=y.args[0].args[0].id+\"/\"+y.args[0].args[1].value;w.is_public_predicate(F)?(delete w.session.rules[F],w.success(P)):w.throw_error(x.error.permission(\"modify\",\"static_procedure\",F,y.indicator))}},\"atom_length/2\":function(w,P,y){if(x.type.is_variable(y.args[0]))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_atom(y.args[0]))w.throw_error(x.error.type(\"atom\",y.args[0],y.indicator));else if(!x.type.is_variable(y.args[1])&&!x.type.is_integer(y.args[1]))w.throw_error(x.error.type(\"integer\",y.args[1],y.indicator));else if(x.type.is_integer(y.args[1])&&y.args[1].value<0)w.throw_error(x.error.domain(\"not_less_than_zero\",y.args[1],y.indicator));else{var F=new Te(y.args[0].id.length,!1);w.prepend([new be(P.goal.replace(new j(\"=\",[F,y.args[1]])),P.substitution,P)])}},\"atom_concat/3\":function(w,P,y){var F,z,Z=y.args[0],$=y.args[1],oe=y.args[2];if(x.type.is_variable(oe)&&(x.type.is_variable(Z)||x.type.is_variable($)))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(Z)&&!x.type.is_atom(Z))w.throw_error(x.error.type(\"atom\",Z,y.indicator));else if(!x.type.is_variable($)&&!x.type.is_atom($))w.throw_error(x.error.type(\"atom\",$,y.indicator));else if(!x.type.is_variable(oe)&&!x.type.is_atom(oe))w.throw_error(x.error.type(\"atom\",oe,y.indicator));else{var xe=x.type.is_variable(Z),Re=x.type.is_variable($);if(!xe&&!Re)z=new j(\"=\",[oe,new j(Z.id+$.id)]),w.prepend([new be(P.goal.replace(z),P.substitution,P)]);else if(xe&&!Re)F=oe.id.substr(0,oe.id.length-$.id.length),F+$.id===oe.id&&(z=new j(\"=\",[Z,new j(F)]),w.prepend([new be(P.goal.replace(z),P.substitution,P)]));else if(Re&&!xe)F=oe.id.substr(Z.id.length),Z.id+F===oe.id&&(z=new j(\"=\",[$,new j(F)]),w.prepend([new be(P.goal.replace(z),P.substitution,P)]));else{for(var lt=[],Ct=0;Ct<=oe.id.length;Ct++){var qt=new j(oe.id.substr(0,Ct)),ir=new j(oe.id.substr(Ct));z=new j(\",\",[new j(\"=\",[qt,Z]),new j(\"=\",[ir,$])]),lt.push(new be(P.goal.replace(z),P.substitution,P))}w.prepend(lt)}}},\"sub_atom/5\":function(w,P,y){var F,z=y.args[0],Z=y.args[1],$=y.args[2],oe=y.args[3],xe=y.args[4];if(x.type.is_variable(z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(Z)&&!x.type.is_integer(Z))w.throw_error(x.error.type(\"integer\",Z,y.indicator));else if(!x.type.is_variable($)&&!x.type.is_integer($))w.throw_error(x.error.type(\"integer\",$,y.indicator));else if(!x.type.is_variable(oe)&&!x.type.is_integer(oe))w.throw_error(x.error.type(\"integer\",oe,y.indicator));else if(x.type.is_integer(Z)&&Z.value<0)w.throw_error(x.error.domain(\"not_less_than_zero\",Z,y.indicator));else if(x.type.is_integer($)&&$.value<0)w.throw_error(x.error.domain(\"not_less_than_zero\",$,y.indicator));else if(x.type.is_integer(oe)&&oe.value<0)w.throw_error(x.error.domain(\"not_less_than_zero\",oe,y.indicator));else{var Re=[],lt=[],Ct=[];if(x.type.is_variable(Z))for(F=0;F<=z.id.length;F++)Re.push(F);else Re.push(Z.value);if(x.type.is_variable($))for(F=0;F<=z.id.length;F++)lt.push(F);else lt.push($.value);if(x.type.is_variable(oe))for(F=0;F<=z.id.length;F++)Ct.push(F);else Ct.push(oe.value);var qt=[];for(var ir in Re)if(Re.hasOwnProperty(ir)){F=Re[ir];for(var bt in lt)if(lt.hasOwnProperty(bt)){var gn=lt[bt],br=z.id.length-F-gn;if(e(Ct,br)!==-1&&F+gn+br===z.id.length){var Ir=z.id.substr(F,gn);if(z.id===z.id.substr(0,F)+Ir+z.id.substr(F+gn,br)){var Or=new j(\"=\",[new j(Ir),xe]),nn=new j(\"=\",[Z,new Te(F)]),ai=new j(\"=\",[$,new Te(gn)]),Io=new j(\"=\",[oe,new Te(br)]),ts=new j(\",\",[new j(\",\",[new j(\",\",[nn,ai]),Io]),Or]);qt.push(new be(P.goal.replace(ts),P.substitution,P))}}}}w.prepend(qt)}},\"atom_chars/2\":function(w,P,y){var F=y.args[0],z=y.args[1];if(x.type.is_variable(F)&&x.type.is_variable(z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_atom(F))w.throw_error(x.error.type(\"atom\",F,y.indicator));else if(x.type.is_variable(F)){for(var oe=z,xe=x.type.is_variable(F),Re=\"\";oe.indicator===\"./2\";){if(x.type.is_character(oe.args[0]))Re+=oe.args[0].id;else if(x.type.is_variable(oe.args[0])&&xe){w.throw_error(x.error.instantiation(y.indicator));return}else if(!x.type.is_variable(oe.args[0])){w.throw_error(x.error.type(\"character\",oe.args[0],y.indicator));return}oe=oe.args[1]}x.type.is_variable(oe)&&xe?w.throw_error(x.error.instantiation(y.indicator)):!x.type.is_empty_list(oe)&&!x.type.is_variable(oe)?w.throw_error(x.error.type(\"list\",z,y.indicator)):w.prepend([new be(P.goal.replace(new j(\"=\",[new j(Re),F])),P.substitution,P)])}else{for(var Z=new j(\"[]\"),$=F.id.length-1;$>=0;$--)Z=new j(\".\",[new j(F.id.charAt($)),Z]);w.prepend([new be(P.goal.replace(new j(\"=\",[z,Z])),P.substitution,P)])}},\"atom_codes/2\":function(w,P,y){var F=y.args[0],z=y.args[1];if(x.type.is_variable(F)&&x.type.is_variable(z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_atom(F))w.throw_error(x.error.type(\"atom\",F,y.indicator));else if(x.type.is_variable(F)){for(var oe=z,xe=x.type.is_variable(F),Re=\"\";oe.indicator===\"./2\";){if(x.type.is_character_code(oe.args[0]))Re+=c(oe.args[0].value);else if(x.type.is_variable(oe.args[0])&&xe){w.throw_error(x.error.instantiation(y.indicator));return}else if(!x.type.is_variable(oe.args[0])){w.throw_error(x.error.representation(\"character_code\",y.indicator));return}oe=oe.args[1]}x.type.is_variable(oe)&&xe?w.throw_error(x.error.instantiation(y.indicator)):!x.type.is_empty_list(oe)&&!x.type.is_variable(oe)?w.throw_error(x.error.type(\"list\",z,y.indicator)):w.prepend([new be(P.goal.replace(new j(\"=\",[new j(Re),F])),P.substitution,P)])}else{for(var Z=new j(\"[]\"),$=F.id.length-1;$>=0;$--)Z=new j(\".\",[new Te(n(F.id,$),!1),Z]);w.prepend([new be(P.goal.replace(new j(\"=\",[z,Z])),P.substitution,P)])}},\"char_code/2\":function(w,P,y){var F=y.args[0],z=y.args[1];if(x.type.is_variable(F)&&x.type.is_variable(z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_character(F))w.throw_error(x.error.type(\"character\",F,y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_integer(z))w.throw_error(x.error.type(\"integer\",z,y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_character_code(z))w.throw_error(x.error.representation(\"character_code\",y.indicator));else if(x.type.is_variable(z)){var Z=new Te(n(F.id,0),!1);w.prepend([new be(P.goal.replace(new j(\"=\",[Z,z])),P.substitution,P)])}else{var $=new j(c(z.value));w.prepend([new be(P.goal.replace(new j(\"=\",[$,F])),P.substitution,P)])}},\"number_chars/2\":function(w,P,y){var F,z=y.args[0],Z=y.args[1];if(x.type.is_variable(z)&&x.type.is_variable(Z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_number(z))w.throw_error(x.error.type(\"number\",z,y.indicator));else if(!x.type.is_variable(Z)&&!x.type.is_list(Z))w.throw_error(x.error.type(\"list\",Z,y.indicator));else{var $=x.type.is_variable(z);if(!x.type.is_variable(Z)){var oe=Z,xe=!0;for(F=\"\";oe.indicator===\"./2\";){if(x.type.is_character(oe.args[0]))F+=oe.args[0].id;else if(x.type.is_variable(oe.args[0]))xe=!1;else if(!x.type.is_variable(oe.args[0])){w.throw_error(x.error.type(\"character\",oe.args[0],y.indicator));return}oe=oe.args[1]}if(xe=xe&&x.type.is_empty_list(oe),!x.type.is_empty_list(oe)&&!x.type.is_variable(oe)){w.throw_error(x.error.type(\"list\",Z,y.indicator));return}if(!xe&&$){w.throw_error(x.error.instantiation(y.indicator));return}else if(xe)if(x.type.is_variable(oe)&&$){w.throw_error(x.error.instantiation(y.indicator));return}else{var Re=w.parse(F),lt=Re.value;!x.type.is_number(lt)||Re.tokens[Re.tokens.length-1].space?w.throw_error(x.error.syntax_by_predicate(\"parseable_number\",y.indicator)):w.prepend([new be(P.goal.replace(new j(\"=\",[z,lt])),P.substitution,P)]);return}}if(!$){F=z.toString();for(var Ct=new j(\"[]\"),qt=F.length-1;qt>=0;qt--)Ct=new j(\".\",[new j(F.charAt(qt)),Ct]);w.prepend([new be(P.goal.replace(new j(\"=\",[Z,Ct])),P.substitution,P)])}}},\"number_codes/2\":function(w,P,y){var F,z=y.args[0],Z=y.args[1];if(x.type.is_variable(z)&&x.type.is_variable(Z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_number(z))w.throw_error(x.error.type(\"number\",z,y.indicator));else if(!x.type.is_variable(Z)&&!x.type.is_list(Z))w.throw_error(x.error.type(\"list\",Z,y.indicator));else{var $=x.type.is_variable(z);if(!x.type.is_variable(Z)){var oe=Z,xe=!0;for(F=\"\";oe.indicator===\"./2\";){if(x.type.is_character_code(oe.args[0]))F+=c(oe.args[0].value);else if(x.type.is_variable(oe.args[0]))xe=!1;else if(!x.type.is_variable(oe.args[0])){w.throw_error(x.error.type(\"character_code\",oe.args[0],y.indicator));return}oe=oe.args[1]}if(xe=xe&&x.type.is_empty_list(oe),!x.type.is_empty_list(oe)&&!x.type.is_variable(oe)){w.throw_error(x.error.type(\"list\",Z,y.indicator));return}if(!xe&&$){w.throw_error(x.error.instantiation(y.indicator));return}else if(xe)if(x.type.is_variable(oe)&&$){w.throw_error(x.error.instantiation(y.indicator));return}else{var Re=w.parse(F),lt=Re.value;!x.type.is_number(lt)||Re.tokens[Re.tokens.length-1].space?w.throw_error(x.error.syntax_by_predicate(\"parseable_number\",y.indicator)):w.prepend([new be(P.goal.replace(new j(\"=\",[z,lt])),P.substitution,P)]);return}}if(!$){F=z.toString();for(var Ct=new j(\"[]\"),qt=F.length-1;qt>=0;qt--)Ct=new j(\".\",[new Te(n(F,qt),!1),Ct]);w.prepend([new be(P.goal.replace(new j(\"=\",[Z,Ct])),P.substitution,P)])}}},\"upcase_atom/2\":function(w,P,y){var F=y.args[0],z=y.args[1];x.type.is_variable(F)?w.throw_error(x.error.instantiation(y.indicator)):x.type.is_atom(F)?!x.type.is_variable(z)&&!x.type.is_atom(z)?w.throw_error(x.error.type(\"atom\",z,y.indicator)):w.prepend([new be(P.goal.replace(new j(\"=\",[z,new j(F.id.toUpperCase(),[])])),P.substitution,P)]):w.throw_error(x.error.type(\"atom\",F,y.indicator))},\"downcase_atom/2\":function(w,P,y){var F=y.args[0],z=y.args[1];x.type.is_variable(F)?w.throw_error(x.error.instantiation(y.indicator)):x.type.is_atom(F)?!x.type.is_variable(z)&&!x.type.is_atom(z)?w.throw_error(x.error.type(\"atom\",z,y.indicator)):w.prepend([new be(P.goal.replace(new j(\"=\",[z,new j(F.id.toLowerCase(),[])])),P.substitution,P)]):w.throw_error(x.error.type(\"atom\",F,y.indicator))},\"atomic_list_concat/2\":function(w,P,y){var F=y.args[0],z=y.args[1];w.prepend([new be(P.goal.replace(new j(\"atomic_list_concat\",[F,new j(\"\",[]),z])),P.substitution,P)])},\"atomic_list_concat/3\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=y.args[2];if(x.type.is_variable(z)||x.type.is_variable(F)&&x.type.is_variable(Z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_list(F))w.throw_error(x.error.type(\"list\",F,y.indicator));else if(!x.type.is_variable(Z)&&!x.type.is_atom(Z))w.throw_error(x.error.type(\"atom\",Z,y.indicator));else if(x.type.is_variable(Z)){for(var oe=\"\",xe=F;x.type.is_term(xe)&&xe.indicator===\"./2\";){if(!x.type.is_atom(xe.args[0])&&!x.type.is_number(xe.args[0])){w.throw_error(x.error.type(\"atomic\",xe.args[0],y.indicator));return}oe!==\"\"&&(oe+=z.id),x.type.is_atom(xe.args[0])?oe+=xe.args[0].id:oe+=\"\"+xe.args[0].value,xe=xe.args[1]}oe=new j(oe,[]),x.type.is_variable(xe)?w.throw_error(x.error.instantiation(y.indicator)):!x.type.is_term(xe)||xe.indicator!==\"[]/0\"?w.throw_error(x.error.type(\"list\",F,y.indicator)):w.prepend([new be(P.goal.replace(new j(\"=\",[oe,Z])),P.substitution,P)])}else{var $=g(s(Z.id.split(z.id),function(Re){return new j(Re,[])}));w.prepend([new be(P.goal.replace(new j(\"=\",[$,F])),P.substitution,P)])}},\"@=</2\":function(w,P,y){x.compare(y.args[0],y.args[1])<=0&&w.success(P)},\"==/2\":function(w,P,y){x.compare(y.args[0],y.args[1])===0&&w.success(P)},\"\\\\==/2\":function(w,P,y){x.compare(y.args[0],y.args[1])!==0&&w.success(P)},\"@</2\":function(w,P,y){x.compare(y.args[0],y.args[1])<0&&w.success(P)},\"@>/2\":function(w,P,y){x.compare(y.args[0],y.args[1])>0&&w.success(P)},\"@>=/2\":function(w,P,y){x.compare(y.args[0],y.args[1])>=0&&w.success(P)},\"compare/3\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=y.args[2];if(!x.type.is_variable(F)&&!x.type.is_atom(F))w.throw_error(x.error.type(\"atom\",F,y.indicator));else if(x.type.is_atom(F)&&[\"<\",\">\",\"=\"].indexOf(F.id)===-1)w.throw_error(x.type.domain(\"order\",F,y.indicator));else{var $=x.compare(z,Z);$=$===0?\"=\":$===-1?\"<\":\">\",w.prepend([new be(P.goal.replace(new j(\"=\",[F,new j($,[])])),P.substitution,P)])}},\"is/2\":function(w,P,y){var F=y.args[1].interpret(w);x.type.is_number(F)?w.prepend([new be(P.goal.replace(new j(\"=\",[y.args[0],F],w.level)),P.substitution,P)]):w.throw_error(F)},\"between/3\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=y.args[2];if(x.type.is_variable(F)||x.type.is_variable(z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_integer(F))w.throw_error(x.error.type(\"integer\",F,y.indicator));else if(!x.type.is_integer(z))w.throw_error(x.error.type(\"integer\",z,y.indicator));else if(!x.type.is_variable(Z)&&!x.type.is_integer(Z))w.throw_error(x.error.type(\"integer\",Z,y.indicator));else if(x.type.is_variable(Z)){var $=[new be(P.goal.replace(new j(\"=\",[Z,F])),P.substitution,P)];F.value<z.value&&$.push(new be(P.goal.replace(new j(\"between\",[new Te(F.value+1,!1),z,Z])),P.substitution,P)),w.prepend($)}else F.value<=Z.value&&z.value>=Z.value&&w.success(P)},\"succ/2\":function(w,P,y){var F=y.args[0],z=y.args[1];x.type.is_variable(F)&&x.type.is_variable(z)?w.throw_error(x.error.instantiation(y.indicator)):!x.type.is_variable(F)&&!x.type.is_integer(F)?w.throw_error(x.error.type(\"integer\",F,y.indicator)):!x.type.is_variable(z)&&!x.type.is_integer(z)?w.throw_error(x.error.type(\"integer\",z,y.indicator)):!x.type.is_variable(F)&&F.value<0?w.throw_error(x.error.domain(\"not_less_than_zero\",F,y.indicator)):!x.type.is_variable(z)&&z.value<0?w.throw_error(x.error.domain(\"not_less_than_zero\",z,y.indicator)):(x.type.is_variable(z)||z.value>0)&&(x.type.is_variable(F)?w.prepend([new be(P.goal.replace(new j(\"=\",[F,new Te(z.value-1,!1)])),P.substitution,P)]):w.prepend([new be(P.goal.replace(new j(\"=\",[z,new Te(F.value+1,!1)])),P.substitution,P)]))},\"=:=/2\":function(w,P,y){var F=x.arithmetic_compare(w,y.args[0],y.args[1]);x.type.is_term(F)?w.throw_error(F):F===0&&w.success(P)},\"=\\\\=/2\":function(w,P,y){var F=x.arithmetic_compare(w,y.args[0],y.args[1]);x.type.is_term(F)?w.throw_error(F):F!==0&&w.success(P)},\"</2\":function(w,P,y){var F=x.arithmetic_compare(w,y.args[0],y.args[1]);x.type.is_term(F)?w.throw_error(F):F<0&&w.success(P)},\"=</2\":function(w,P,y){var F=x.arithmetic_compare(w,y.args[0],y.args[1]);x.type.is_term(F)?w.throw_error(F):F<=0&&w.success(P)},\">/2\":function(w,P,y){var F=x.arithmetic_compare(w,y.args[0],y.args[1]);x.type.is_term(F)?w.throw_error(F):F>0&&w.success(P)},\">=/2\":function(w,P,y){var F=x.arithmetic_compare(w,y.args[0],y.args[1]);x.type.is_term(F)?w.throw_error(F):F>=0&&w.success(P)},\"var/1\":function(w,P,y){x.type.is_variable(y.args[0])&&w.success(P)},\"atom/1\":function(w,P,y){x.type.is_atom(y.args[0])&&w.success(P)},\"atomic/1\":function(w,P,y){x.type.is_atomic(y.args[0])&&w.success(P)},\"compound/1\":function(w,P,y){x.type.is_compound(y.args[0])&&w.success(P)},\"integer/1\":function(w,P,y){x.type.is_integer(y.args[0])&&w.success(P)},\"float/1\":function(w,P,y){x.type.is_float(y.args[0])&&w.success(P)},\"number/1\":function(w,P,y){x.type.is_number(y.args[0])&&w.success(P)},\"nonvar/1\":function(w,P,y){x.type.is_variable(y.args[0])||w.success(P)},\"ground/1\":function(w,P,y){y.variables().length===0&&w.success(P)},\"acyclic_term/1\":function(w,P,y){for(var F=P.substitution.apply(P.substitution),z=y.args[0].variables(),Z=0;Z<z.length;Z++)if(P.substitution.links[z[Z]]!==void 0&&!P.substitution.links[z[Z]].equals(F.links[z[Z]]))return;w.success(P)},\"callable/1\":function(w,P,y){x.type.is_callable(y.args[0])&&w.success(P)},\"is_list/1\":function(w,P,y){for(var F=y.args[0];x.type.is_term(F)&&F.indicator===\"./2\";)F=F.args[1];x.type.is_term(F)&&F.indicator===\"[]/0\"&&w.success(P)},\"current_input/1\":function(w,P,y){var F=y.args[0];!x.type.is_variable(F)&&!x.type.is_stream(F)&&!x.type.is_atom(F)?w.throw_error(x.error.domain(\"stream\",F,y.indicator)):(x.type.is_atom(F)&&w.get_stream_by_alias(F.id)&&(F=w.get_stream_by_alias(F.id)),w.prepend([new be(P.goal.replace(new j(\"=\",[F,w.get_current_input()])),P.substitution,P)]))},\"current_output/1\":function(w,P,y){var F=y.args[0];!x.type.is_variable(F)&&!x.type.is_stream(F)&&!x.type.is_atom(F)?w.throw_error(x.error.domain(\"stream_or_alias\",F,y.indicator)):(x.type.is_atom(F)&&w.get_stream_by_alias(F.id)&&(F=w.get_stream_by_alias(F.id)),w.prepend([new be(P.goal.replace(new j(\"=\",[F,w.get_current_output()])),P.substitution,P)]))},\"set_input/1\":function(w,P,y){var F=y.args[0],z=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);x.type.is_variable(F)?w.throw_error(x.error.instantiation(y.indicator)):!x.type.is_variable(F)&&!x.type.is_stream(F)&&!x.type.is_atom(F)?w.throw_error(x.error.domain(\"stream_or_alias\",F,y.indicator)):x.type.is_stream(z)?z.output===!0?w.throw_error(x.error.permission(\"input\",\"stream\",F,y.indicator)):(w.set_current_input(z),w.success(P)):w.throw_error(x.error.existence(\"stream\",F,y.indicator))},\"set_output/1\":function(w,P,y){var F=y.args[0],z=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);x.type.is_variable(F)?w.throw_error(x.error.instantiation(y.indicator)):!x.type.is_variable(F)&&!x.type.is_stream(F)&&!x.type.is_atom(F)?w.throw_error(x.error.domain(\"stream_or_alias\",F,y.indicator)):x.type.is_stream(z)?z.input===!0?w.throw_error(x.error.permission(\"output\",\"stream\",F,y.indicator)):(w.set_current_output(z),w.success(P)):w.throw_error(x.error.existence(\"stream\",F,y.indicator))},\"open/3\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=y.args[2];w.prepend([new be(P.goal.replace(new j(\"open\",[F,z,Z,new j(\"[]\",[])])),P.substitution,P)])},\"open/4\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=y.args[2],$=y.args[3];if(x.type.is_variable(F)||x.type.is_variable(z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_atom(z))w.throw_error(x.error.type(\"atom\",z,y.indicator));else if(!x.type.is_list($))w.throw_error(x.error.type(\"list\",$,y.indicator));else if(!x.type.is_variable(Z))w.throw_error(x.error.type(\"variable\",Z,y.indicator));else if(!x.type.is_atom(F)&&!x.type.is_streamable(F))w.throw_error(x.error.domain(\"source_sink\",F,y.indicator));else if(!x.type.is_io_mode(z))w.throw_error(x.error.domain(\"io_mode\",z,y.indicator));else{for(var oe={},xe=$,Re;x.type.is_term(xe)&&xe.indicator===\"./2\";){if(Re=xe.args[0],x.type.is_variable(Re)){w.throw_error(x.error.instantiation(y.indicator));return}else if(!x.type.is_stream_option(Re)){w.throw_error(x.error.domain(\"stream_option\",Re,y.indicator));return}oe[Re.id]=Re.args[0].id,xe=xe.args[1]}if(xe.indicator!==\"[]/0\"){x.type.is_variable(xe)?w.throw_error(x.error.instantiation(y.indicator)):w.throw_error(x.error.type(\"list\",$,y.indicator));return}else{var lt=oe.alias;if(lt&&w.get_stream_by_alias(lt)){w.throw_error(x.error.permission(\"open\",\"source_sink\",new j(\"alias\",[new j(lt,[])]),y.indicator));return}oe.type||(oe.type=\"text\");var Ct;if(x.type.is_atom(F)?Ct=w.file_system_open(F.id,oe.type,z.id):Ct=F.stream(oe.type,z.id),Ct===!1){w.throw_error(x.error.permission(\"open\",\"source_sink\",F,y.indicator));return}else if(Ct===null){w.throw_error(x.error.existence(\"source_sink\",F,y.indicator));return}var qt=new Fe(Ct,z.id,oe.alias,oe.type,oe.reposition===\"true\",oe.eof_action);lt?w.session.streams[lt]=qt:w.session.streams[qt.id]=qt,w.prepend([new be(P.goal.replace(new j(\"=\",[Z,qt])),P.substitution,P)])}}},\"close/1\":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(\"close\",[F,new j(\"[]\",[])])),P.substitution,P)])},\"close/2\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(x.type.is_variable(F)||x.type.is_variable(z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_list(z))w.throw_error(x.error.type(\"list\",z,y.indicator));else if(!x.type.is_stream(F)&&!x.type.is_atom(F))w.throw_error(x.error.domain(\"stream_or_alias\",F,y.indicator));else if(!x.type.is_stream(Z)||Z.stream===null)w.throw_error(x.error.existence(\"stream\",F,y.indicator));else{for(var $={},oe=z,xe;x.type.is_term(oe)&&oe.indicator===\"./2\";){if(xe=oe.args[0],x.type.is_variable(xe)){w.throw_error(x.error.instantiation(y.indicator));return}else if(!x.type.is_close_option(xe)){w.throw_error(x.error.domain(\"close_option\",xe,y.indicator));return}$[xe.id]=xe.args[0].id===\"true\",oe=oe.args[1]}if(oe.indicator!==\"[]/0\"){x.type.is_variable(oe)?w.throw_error(x.error.instantiation(y.indicator)):w.throw_error(x.error.type(\"list\",z,y.indicator));return}else{if(Z===w.session.standard_input||Z===w.session.standard_output){w.success(P);return}else Z===w.session.current_input?w.session.current_input=w.session.standard_input:Z===w.session.current_output&&(w.session.current_output=w.session.current_output);Z.alias!==null?delete w.session.streams[Z.alias]:delete w.session.streams[Z.id],Z.output&&Z.stream.flush();var Re=Z.stream.close();Z.stream=null,($.force===!0||Re===!0)&&w.success(P)}}},\"flush_output/0\":function(w,P,y){w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"current_output\",[new De(\"S\")]),new j(\"flush_output\",[new De(\"S\")])])),P.substitution,P)])},\"flush_output/1\":function(w,P,y){var F=y.args[0],z=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);x.type.is_variable(F)?w.throw_error(x.error.instantiation(y.indicator)):!x.type.is_stream(F)&&!x.type.is_atom(F)?w.throw_error(x.error.domain(\"stream_or_alias\",F,y.indicator)):!x.type.is_stream(z)||z.stream===null?w.throw_error(x.error.existence(\"stream\",F,y.indicator)):F.input===!0?w.throw_error(x.error.permission(\"output\",\"stream\",output,y.indicator)):(z.stream.flush(),w.success(P))},\"stream_property/2\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(!x.type.is_variable(F)&&!x.type.is_stream(F)&&!x.type.is_atom(F))w.throw_error(x.error.domain(\"stream_or_alias\",F,y.indicator));else if(!x.type.is_variable(F)&&(!x.type.is_stream(Z)||Z.stream===null))w.throw_error(x.error.existence(\"stream\",F,y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_stream_property(z))w.throw_error(x.error.domain(\"stream_property\",z,y.indicator));else{var $=[],oe=[];if(!x.type.is_variable(F))$.push(Z);else for(var xe in w.session.streams)$.push(w.session.streams[xe]);for(var Re=0;Re<$.length;Re++){var lt=[];$[Re].filename&&lt.push(new j(\"file_name\",[new j($[Re].file_name,[])])),lt.push(new j(\"mode\",[new j($[Re].mode,[])])),lt.push(new j($[Re].input?\"input\":\"output\",[])),$[Re].alias&&lt.push(new j(\"alias\",[new j($[Re].alias,[])])),lt.push(new j(\"position\",[typeof $[Re].position==\"number\"?new Te($[Re].position,!1):new j($[Re].position,[])])),lt.push(new j(\"end_of_stream\",[new j($[Re].position===\"end_of_stream\"?\"at\":$[Re].position===\"past_end_of_stream\"?\"past\":\"not\",[])])),lt.push(new j(\"eof_action\",[new j($[Re].eof_action,[])])),lt.push(new j(\"reposition\",[new j($[Re].reposition?\"true\":\"false\",[])])),lt.push(new j(\"type\",[new j($[Re].type,[])]));for(var Ct=0;Ct<lt.length;Ct++)oe.push(new be(P.goal.replace(new j(\",\",[new j(\"=\",[x.type.is_variable(F)?F:Z,$[Re]]),new j(\"=\",[z,lt[Ct]])])),P.substitution,P))}w.prepend(oe)}},\"at_end_of_stream/0\":function(w,P,y){w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"current_input\",[new De(\"S\")]),new j(\",\",[new j(\"stream_property\",[new De(\"S\"),new j(\"end_of_stream\",[new De(\"E\")])]),new j(\",\",[new j(\"!\",[]),new j(\";\",[new j(\"=\",[new De(\"E\"),new j(\"at\",[])]),new j(\"=\",[new De(\"E\"),new j(\"past\",[])])])])])])),P.substitution,P)])},\"at_end_of_stream/1\":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"stream_property\",[F,new j(\"end_of_stream\",[new De(\"E\")])]),new j(\",\",[new j(\"!\",[]),new j(\";\",[new j(\"=\",[new De(\"E\"),new j(\"at\",[])]),new j(\"=\",[new De(\"E\"),new j(\"past\",[])])])])])),P.substitution,P)])},\"set_stream_position/2\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);x.type.is_variable(F)||x.type.is_variable(z)?w.throw_error(x.error.instantiation(y.indicator)):!x.type.is_stream(F)&&!x.type.is_atom(F)?w.throw_error(x.error.domain(\"stream_or_alias\",F,y.indicator)):!x.type.is_stream(Z)||Z.stream===null?w.throw_error(x.error.existence(\"stream\",F,y.indicator)):x.type.is_stream_position(z)?Z.reposition===!1?w.throw_error(x.error.permission(\"reposition\",\"stream\",F,y.indicator)):(x.type.is_integer(z)?Z.position=z.value:Z.position=z.id,w.success(P)):w.throw_error(x.error.domain(\"stream_position\",z,y.indicator))},\"get_char/1\":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"current_input\",[new De(\"S\")]),new j(\"get_char\",[new De(\"S\"),F])])),P.substitution,P)])},\"get_char/2\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(x.type.is_variable(F))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_character(z))w.throw_error(x.error.type(\"in_character\",z,y.indicator));else if(!x.type.is_stream(F)&&!x.type.is_atom(F))w.throw_error(x.error.domain(\"stream_or_alias\",F,y.indicator));else if(!x.type.is_stream(Z)||Z.stream===null)w.throw_error(x.error.existence(\"stream\",F,y.indicator));else if(Z.output)w.throw_error(x.error.permission(\"input\",\"stream\",F,y.indicator));else if(Z.type===\"binary\")w.throw_error(x.error.permission(\"input\",\"binary_stream\",F,y.indicator));else if(Z.position===\"past_end_of_stream\"&&Z.eof_action===\"error\")w.throw_error(x.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{var $;if(Z.position===\"end_of_stream\")$=\"end_of_file\",Z.position=\"past_end_of_stream\";else{if($=Z.stream.get(1,Z.position),$===null){w.throw_error(x.error.representation(\"character\",y.indicator));return}Z.position++}w.prepend([new be(P.goal.replace(new j(\"=\",[new j($,[]),z])),P.substitution,P)])}},\"get_code/1\":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"current_input\",[new De(\"S\")]),new j(\"get_code\",[new De(\"S\"),F])])),P.substitution,P)])},\"get_code/2\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(x.type.is_variable(F))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_integer(z))w.throw_error(x.error.type(\"integer\",char,y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_stream(F)&&!x.type.is_atom(F))w.throw_error(x.error.domain(\"stream_or_alias\",F,y.indicator));else if(!x.type.is_stream(Z)||Z.stream===null)w.throw_error(x.error.existence(\"stream\",F,y.indicator));else if(Z.output)w.throw_error(x.error.permission(\"input\",\"stream\",F,y.indicator));else if(Z.type===\"binary\")w.throw_error(x.error.permission(\"input\",\"binary_stream\",F,y.indicator));else if(Z.position===\"past_end_of_stream\"&&Z.eof_action===\"error\")w.throw_error(x.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{var $;if(Z.position===\"end_of_stream\")$=-1,Z.position=\"past_end_of_stream\";else{if($=Z.stream.get(1,Z.position),$===null){w.throw_error(x.error.representation(\"character\",y.indicator));return}$=n($,0),Z.position++}w.prepend([new be(P.goal.replace(new j(\"=\",[new Te($,!1),z])),P.substitution,P)])}},\"peek_char/1\":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"current_input\",[new De(\"S\")]),new j(\"peek_char\",[new De(\"S\"),F])])),P.substitution,P)])},\"peek_char/2\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(x.type.is_variable(F))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_character(z))w.throw_error(x.error.type(\"in_character\",z,y.indicator));else if(!x.type.is_stream(F)&&!x.type.is_atom(F))w.throw_error(x.error.domain(\"stream_or_alias\",F,y.indicator));else if(!x.type.is_stream(Z)||Z.stream===null)w.throw_error(x.error.existence(\"stream\",F,y.indicator));else if(Z.output)w.throw_error(x.error.permission(\"input\",\"stream\",F,y.indicator));else if(Z.type===\"binary\")w.throw_error(x.error.permission(\"input\",\"binary_stream\",F,y.indicator));else if(Z.position===\"past_end_of_stream\"&&Z.eof_action===\"error\")w.throw_error(x.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{var $;if(Z.position===\"end_of_stream\")$=\"end_of_file\",Z.position=\"past_end_of_stream\";else if($=Z.stream.get(1,Z.position),$===null){w.throw_error(x.error.representation(\"character\",y.indicator));return}w.prepend([new be(P.goal.replace(new j(\"=\",[new j($,[]),z])),P.substitution,P)])}},\"peek_code/1\":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"current_input\",[new De(\"S\")]),new j(\"peek_code\",[new De(\"S\"),F])])),P.substitution,P)])},\"peek_code/2\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(x.type.is_variable(F))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_integer(z))w.throw_error(x.error.type(\"integer\",char,y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_stream(F)&&!x.type.is_atom(F))w.throw_error(x.error.domain(\"stream_or_alias\",F,y.indicator));else if(!x.type.is_stream(Z)||Z.stream===null)w.throw_error(x.error.existence(\"stream\",F,y.indicator));else if(Z.output)w.throw_error(x.error.permission(\"input\",\"stream\",F,y.indicator));else if(Z.type===\"binary\")w.throw_error(x.error.permission(\"input\",\"binary_stream\",F,y.indicator));else if(Z.position===\"past_end_of_stream\"&&Z.eof_action===\"error\")w.throw_error(x.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{var $;if(Z.position===\"end_of_stream\")$=-1,Z.position=\"past_end_of_stream\";else{if($=Z.stream.get(1,Z.position),$===null){w.throw_error(x.error.representation(\"character\",y.indicator));return}$=n($,0)}w.prepend([new be(P.goal.replace(new j(\"=\",[new Te($,!1),z])),P.substitution,P)])}},\"put_char/1\":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"current_output\",[new De(\"S\")]),new j(\"put_char\",[new De(\"S\"),F])])),P.substitution,P)])},\"put_char/2\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);x.type.is_variable(F)||x.type.is_variable(z)?w.throw_error(x.error.instantiation(y.indicator)):x.type.is_character(z)?!x.type.is_variable(F)&&!x.type.is_stream(F)&&!x.type.is_atom(F)?w.throw_error(x.error.domain(\"stream_or_alias\",F,y.indicator)):!x.type.is_stream(Z)||Z.stream===null?w.throw_error(x.error.existence(\"stream\",F,y.indicator)):Z.input?w.throw_error(x.error.permission(\"output\",\"stream\",F,y.indicator)):Z.type===\"binary\"?w.throw_error(x.error.permission(\"output\",\"binary_stream\",F,y.indicator)):Z.stream.put(z.id,Z.position)&&(typeof Z.position==\"number\"&&Z.position++,w.success(P)):w.throw_error(x.error.type(\"character\",z,y.indicator))},\"put_code/1\":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"current_output\",[new De(\"S\")]),new j(\"put_code\",[new De(\"S\"),F])])),P.substitution,P)])},\"put_code/2\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);x.type.is_variable(F)||x.type.is_variable(z)?w.throw_error(x.error.instantiation(y.indicator)):x.type.is_integer(z)?x.type.is_character_code(z)?!x.type.is_variable(F)&&!x.type.is_stream(F)&&!x.type.is_atom(F)?w.throw_error(x.error.domain(\"stream_or_alias\",F,y.indicator)):!x.type.is_stream(Z)||Z.stream===null?w.throw_error(x.error.existence(\"stream\",F,y.indicator)):Z.input?w.throw_error(x.error.permission(\"output\",\"stream\",F,y.indicator)):Z.type===\"binary\"?w.throw_error(x.error.permission(\"output\",\"binary_stream\",F,y.indicator)):Z.stream.put_char(c(z.value),Z.position)&&(typeof Z.position==\"number\"&&Z.position++,w.success(P)):w.throw_error(x.error.representation(\"character_code\",y.indicator)):w.throw_error(x.error.type(\"integer\",z,y.indicator))},\"nl/0\":function(w,P,y){w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"current_output\",[new De(\"S\")]),new j(\"put_char\",[new De(\"S\"),new j(`\n`,[])])])),P.substitution,P)])},\"nl/1\":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(\"put_char\",[F,new j(`\n`,[])])),P.substitution,P)])},\"get_byte/1\":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"current_input\",[new De(\"S\")]),new j(\"get_byte\",[new De(\"S\"),F])])),P.substitution,P)])},\"get_byte/2\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(x.type.is_variable(F))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_byte(z))w.throw_error(x.error.type(\"in_byte\",char,y.indicator));else if(!x.type.is_stream(F)&&!x.type.is_atom(F))w.throw_error(x.error.domain(\"stream_or_alias\",F,y.indicator));else if(!x.type.is_stream(Z)||Z.stream===null)w.throw_error(x.error.existence(\"stream\",F,y.indicator));else if(Z.output)w.throw_error(x.error.permission(\"input\",\"stream\",F,y.indicator));else if(Z.type===\"text\")w.throw_error(x.error.permission(\"input\",\"text_stream\",F,y.indicator));else if(Z.position===\"past_end_of_stream\"&&Z.eof_action===\"error\")w.throw_error(x.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{var $;if(Z.position===\"end_of_stream\")$=\"end_of_file\",Z.position=\"past_end_of_stream\";else{if($=Z.stream.get_byte(Z.position),$===null){w.throw_error(x.error.representation(\"byte\",y.indicator));return}Z.position++}w.prepend([new be(P.goal.replace(new j(\"=\",[new Te($,!1),z])),P.substitution,P)])}},\"peek_byte/1\":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"current_input\",[new De(\"S\")]),new j(\"peek_byte\",[new De(\"S\"),F])])),P.substitution,P)])},\"peek_byte/2\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(x.type.is_variable(F))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_variable(z)&&!x.type.is_byte(z))w.throw_error(x.error.type(\"in_byte\",char,y.indicator));else if(!x.type.is_stream(F)&&!x.type.is_atom(F))w.throw_error(x.error.domain(\"stream_or_alias\",F,y.indicator));else if(!x.type.is_stream(Z)||Z.stream===null)w.throw_error(x.error.existence(\"stream\",F,y.indicator));else if(Z.output)w.throw_error(x.error.permission(\"input\",\"stream\",F,y.indicator));else if(Z.type===\"text\")w.throw_error(x.error.permission(\"input\",\"text_stream\",F,y.indicator));else if(Z.position===\"past_end_of_stream\"&&Z.eof_action===\"error\")w.throw_error(x.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{var $;if(Z.position===\"end_of_stream\")$=\"end_of_file\",Z.position=\"past_end_of_stream\";else if($=Z.stream.get_byte(Z.position),$===null){w.throw_error(x.error.representation(\"byte\",y.indicator));return}w.prepend([new be(P.goal.replace(new j(\"=\",[new Te($,!1),z])),P.substitution,P)])}},\"put_byte/1\":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"current_output\",[new De(\"S\")]),new j(\"put_byte\",[new De(\"S\"),F])])),P.substitution,P)])},\"put_byte/2\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);x.type.is_variable(F)||x.type.is_variable(z)?w.throw_error(x.error.instantiation(y.indicator)):x.type.is_byte(z)?!x.type.is_variable(F)&&!x.type.is_stream(F)&&!x.type.is_atom(F)?w.throw_error(x.error.domain(\"stream_or_alias\",F,y.indicator)):!x.type.is_stream(Z)||Z.stream===null?w.throw_error(x.error.existence(\"stream\",F,y.indicator)):Z.input?w.throw_error(x.error.permission(\"output\",\"stream\",F,y.indicator)):Z.type===\"text\"?w.throw_error(x.error.permission(\"output\",\"text_stream\",F,y.indicator)):Z.stream.put_byte(z.value,Z.position)&&(typeof Z.position==\"number\"&&Z.position++,w.success(P)):w.throw_error(x.error.type(\"byte\",z,y.indicator))},\"read/1\":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"current_input\",[new De(\"S\")]),new j(\"read_term\",[new De(\"S\"),F,new j(\"[]\",[])])])),P.substitution,P)])},\"read/2\":function(w,P,y){var F=y.args[0],z=y.args[1];w.prepend([new be(P.goal.replace(new j(\"read_term\",[F,z,new j(\"[]\",[])])),P.substitution,P)])},\"read_term/2\":function(w,P,y){var F=y.args[0],z=y.args[1];w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"current_input\",[new De(\"S\")]),new j(\"read_term\",[new De(\"S\"),F,z])])),P.substitution,P)])},\"read_term/3\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=y.args[2],$=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(x.type.is_variable(F)||x.type.is_variable(Z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_list(Z))w.throw_error(x.error.type(\"list\",Z,y.indicator));else if(!x.type.is_stream(F)&&!x.type.is_atom(F))w.throw_error(x.error.domain(\"stream_or_alias\",F,y.indicator));else if(!x.type.is_stream($)||$.stream===null)w.throw_error(x.error.existence(\"stream\",F,y.indicator));else if($.output)w.throw_error(x.error.permission(\"input\",\"stream\",F,y.indicator));else if($.type===\"binary\")w.throw_error(x.error.permission(\"input\",\"binary_stream\",F,y.indicator));else if($.position===\"past_end_of_stream\"&&$.eof_action===\"error\")w.throw_error(x.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{for(var oe={},xe=Z,Re;x.type.is_term(xe)&&xe.indicator===\"./2\";){if(Re=xe.args[0],x.type.is_variable(Re)){w.throw_error(x.error.instantiation(y.indicator));return}else if(!x.type.is_read_option(Re)){w.throw_error(x.error.domain(\"read_option\",Re,y.indicator));return}oe[Re.id]=Re.args[0],xe=xe.args[1]}if(xe.indicator!==\"[]/0\"){x.type.is_variable(xe)?w.throw_error(x.error.instantiation(y.indicator)):w.throw_error(x.error.type(\"list\",Z,y.indicator));return}else{for(var lt,Ct,qt,ir=\"\",bt=[],gn=null;gn===null||gn.name!==\"atom\"||gn.value!==\".\"||qt.type===f&&x.flatten_error(new j(\"throw\",[qt.value])).found===\"token_not_found\";){if(lt=$.stream.get(1,$.position),lt===null){w.throw_error(x.error.representation(\"character\",y.indicator));return}if(lt===\"end_of_file\"||lt===\"past_end_of_file\"){qt?w.throw_error(x.error.syntax(bt[qt.len-1],\". or expression expected\",!1)):w.throw_error(x.error.syntax(null,\"token not found\",!0));return}$.position++,ir+=lt,Ct=new U(w),Ct.new_text(ir),bt=Ct.get_tokens(),gn=bt!==null&&bt.length>0?bt[bt.length-1]:null,bt!==null&&(qt=W(w,bt,0,w.__get_max_priority(),!1))}if(qt.type===p&&qt.len===bt.length-1&&gn.value===\".\"){qt=qt.value.rename(w);var br=new j(\"=\",[z,qt]);if(oe.variables){var Ir=g(s(ye(qt.variables()),function(Or){return new De(Or)}));br=new j(\",\",[br,new j(\"=\",[oe.variables,Ir])])}if(oe.variable_names){var Ir=g(s(ye(qt.variables()),function(nn){var ai;for(ai in w.session.renamed_variables)if(w.session.renamed_variables.hasOwnProperty(ai)&&w.session.renamed_variables[ai]===nn)break;return new j(\"=\",[new j(ai,[]),new De(nn)])}));br=new j(\",\",[br,new j(\"=\",[oe.variable_names,Ir])])}if(oe.singletons){var Ir=g(s(new Ve(qt,null).singleton_variables(),function(nn){var ai;for(ai in w.session.renamed_variables)if(w.session.renamed_variables.hasOwnProperty(ai)&&w.session.renamed_variables[ai]===nn)break;return new j(\"=\",[new j(ai,[]),new De(nn)])}));br=new j(\",\",[br,new j(\"=\",[oe.singletons,Ir])])}w.prepend([new be(P.goal.replace(br),P.substitution,P)])}else qt.type===p?w.throw_error(x.error.syntax(bt[qt.len],\"unexpected token\",!1)):w.throw_error(qt.value)}}},\"write/1\":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"current_output\",[new De(\"S\")]),new j(\"write\",[new De(\"S\"),F])])),P.substitution,P)])},\"write/2\":function(w,P,y){var F=y.args[0],z=y.args[1];w.prepend([new be(P.goal.replace(new j(\"write_term\",[F,z,new j(\".\",[new j(\"quoted\",[new j(\"false\",[])]),new j(\".\",[new j(\"ignore_ops\",[new j(\"false\")]),new j(\".\",[new j(\"numbervars\",[new j(\"true\")]),new j(\"[]\",[])])])])])),P.substitution,P)])},\"writeq/1\":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"current_output\",[new De(\"S\")]),new j(\"writeq\",[new De(\"S\"),F])])),P.substitution,P)])},\"writeq/2\":function(w,P,y){var F=y.args[0],z=y.args[1];w.prepend([new be(P.goal.replace(new j(\"write_term\",[F,z,new j(\".\",[new j(\"quoted\",[new j(\"true\",[])]),new j(\".\",[new j(\"ignore_ops\",[new j(\"false\")]),new j(\".\",[new j(\"numbervars\",[new j(\"true\")]),new j(\"[]\",[])])])])])),P.substitution,P)])},\"write_canonical/1\":function(w,P,y){var F=y.args[0];w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"current_output\",[new De(\"S\")]),new j(\"write_canonical\",[new De(\"S\"),F])])),P.substitution,P)])},\"write_canonical/2\":function(w,P,y){var F=y.args[0],z=y.args[1];w.prepend([new be(P.goal.replace(new j(\"write_term\",[F,z,new j(\".\",[new j(\"quoted\",[new j(\"true\",[])]),new j(\".\",[new j(\"ignore_ops\",[new j(\"true\")]),new j(\".\",[new j(\"numbervars\",[new j(\"false\")]),new j(\"[]\",[])])])])])),P.substitution,P)])},\"write_term/2\":function(w,P,y){var F=y.args[0],z=y.args[1];w.prepend([new be(P.goal.replace(new j(\",\",[new j(\"current_output\",[new De(\"S\")]),new j(\"write_term\",[new De(\"S\"),F,z])])),P.substitution,P)])},\"write_term/3\":function(w,P,y){var F=y.args[0],z=y.args[1],Z=y.args[2],$=x.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(x.type.is_variable(F)||x.type.is_variable(Z))w.throw_error(x.error.instantiation(y.indicator));else if(!x.type.is_list(Z))w.throw_error(x.error.type(\"list\",Z,y.indicator));else if(!x.type.is_stream(F)&&!x.type.is_atom(F))w.throw_error(x.error.domain(\"stream_or_alias\",F,y.indicator));else if(!x.type.is_stream($)||$.stream===null)w.throw_error(x.error.existence(\"stream\",F,y.indicator));else if($.input)w.throw_error(x.error.permission(\"output\",\"stream\",F,y.indicator));else if($.type===\"binary\")w.throw_error(x.error.permission(\"output\",\"binary_stream\",F,y.indicator));else if($.position===\"past_end_of_stream\"&&$.eof_action===\"error\")w.throw_error(x.error.permission(\"output\",\"past_end_of_stream\",F,y.indicator));else{for(var oe={},xe=Z,Re;x.type.is_term(xe)&&xe.indicator===\"./2\";){if(Re=xe.args[0],x.type.is_variable(Re)){w.throw_error(x.error.instantiation(y.indicator));return}else if(!x.type.is_write_option(Re)){w.throw_error(x.error.domain(\"write_option\",Re,y.indicator));return}oe[Re.id]=Re.args[0].id===\"true\",xe=xe.args[1]}if(xe.indicator!==\"[]/0\"){x.type.is_variable(xe)?w.throw_error(x.error.instantiation(y.indicator)):w.throw_error(x.error.type(\"list\",Z,y.indicator));return}else{oe.session=w.session;var lt=z.toString(oe);$.stream.put(lt,$.position),typeof $.position==\"number\"&&($.position+=lt.length),w.success(P)}}},\"halt/0\":function(w,P,y){w.points=[]},\"halt/1\":function(w,P,y){var F=y.args[0];x.type.is_variable(F)?w.throw_error(x.error.instantiation(y.indicator)):x.type.is_integer(F)?w.points=[]:w.throw_error(x.error.type(\"integer\",F,y.indicator))},\"current_prolog_flag/2\":function(w,P,y){var F=y.args[0],z=y.args[1];if(!x.type.is_variable(F)&&!x.type.is_atom(F))w.throw_error(x.error.type(\"atom\",F,y.indicator));else if(!x.type.is_variable(F)&&!x.type.is_flag(F))w.throw_error(x.error.domain(\"prolog_flag\",F,y.indicator));else{var Z=[];for(var $ in x.flag)if(x.flag.hasOwnProperty($)){var oe=new j(\",\",[new j(\"=\",[new j($),F]),new j(\"=\",[w.get_flag($),z])]);Z.push(new be(P.goal.replace(oe),P.substitution,P))}w.prepend(Z)}},\"set_prolog_flag/2\":function(w,P,y){var F=y.args[0],z=y.args[1];x.type.is_variable(F)||x.type.is_variable(z)?w.throw_error(x.error.instantiation(y.indicator)):x.type.is_atom(F)?x.type.is_flag(F)?x.type.is_value_flag(F,z)?x.type.is_modifiable_flag(F)?(w.session.flag[F.id]=z,w.success(P)):w.throw_error(x.error.permission(\"modify\",\"flag\",F)):w.throw_error(x.error.domain(\"flag_value\",new j(\"+\",[F,z]),y.indicator)):w.throw_error(x.error.domain(\"prolog_flag\",F,y.indicator)):w.throw_error(x.error.type(\"atom\",F,y.indicator))}},flag:{bounded:{allowed:[new j(\"true\"),new j(\"false\")],value:new j(\"true\"),changeable:!1},max_integer:{allowed:[new Te(Number.MAX_SAFE_INTEGER)],value:new Te(Number.MAX_SAFE_INTEGER),changeable:!1},min_integer:{allowed:[new Te(Number.MIN_SAFE_INTEGER)],value:new Te(Number.MIN_SAFE_INTEGER),changeable:!1},integer_rounding_function:{allowed:[new j(\"down\"),new j(\"toward_zero\")],value:new j(\"toward_zero\"),changeable:!1},char_conversion:{allowed:[new j(\"on\"),new j(\"off\")],value:new j(\"on\"),changeable:!0},debug:{allowed:[new j(\"on\"),new j(\"off\")],value:new j(\"off\"),changeable:!0},max_arity:{allowed:[new j(\"unbounded\")],value:new j(\"unbounded\"),changeable:!1},unknown:{allowed:[new j(\"error\"),new j(\"fail\"),new j(\"warning\")],value:new j(\"error\"),changeable:!0},double_quotes:{allowed:[new j(\"chars\"),new j(\"codes\"),new j(\"atom\")],value:new j(\"codes\"),changeable:!0},occurs_check:{allowed:[new j(\"false\"),new j(\"true\")],value:new j(\"false\"),changeable:!0},dialect:{allowed:[new j(\"tau\")],value:new j(\"tau\"),changeable:!1},version_data:{allowed:[new j(\"tau\",[new Te(t.major,!1),new Te(t.minor,!1),new Te(t.patch,!1),new j(t.status)])],value:new j(\"tau\",[new Te(t.major,!1),new Te(t.minor,!1),new Te(t.patch,!1),new j(t.status)]),changeable:!1},nodejs:{allowed:[new j(\"yes\"),new j(\"no\")],value:new j(typeof ec<\"u\"&&ec.exports?\"yes\":\"no\"),changeable:!1}},unify:function(w,P,y){y=y===void 0?!1:y;for(var F=[{left:w,right:P}],z={};F.length!==0;){var Z=F.pop();if(w=Z.left,P=Z.right,x.type.is_term(w)&&x.type.is_term(P)){if(w.indicator!==P.indicator)return null;for(var $=0;$<w.args.length;$++)F.push({left:w.args[$],right:P.args[$]})}else if(x.type.is_number(w)&&x.type.is_number(P)){if(w.value!==P.value||w.is_float!==P.is_float)return null}else if(x.type.is_variable(w)){if(x.type.is_variable(P)&&w.id===P.id)continue;if(y===!0&&P.variables().indexOf(w.id)!==-1)return null;if(w.id!==\"_\"){var oe=new Ne;oe.add(w.id,P);for(var $=0;$<F.length;$++)F[$].left=F[$].left.apply(oe),F[$].right=F[$].right.apply(oe);for(var $ in z)z[$]=z[$].apply(oe);z[w.id]=P}}else if(x.type.is_variable(P))F.push({left:P,right:w});else if(w.unify!==void 0){if(!w.unify(P))return null}else return null}return new Ne(z)},compare:function(w,P){var y=x.type.compare(w,P);return y!==0?y:w.compare(P)},arithmetic_compare:function(w,P,y){var F=P.interpret(w);if(x.type.is_number(F)){var z=y.interpret(w);return x.type.is_number(z)?F.value<z.value?-1:F.value>z.value?1:0:z}else return F},operate:function(w,P){if(x.type.is_operator(P)){for(var y=x.type.is_operator(P),F=[],z,Z=!1,$=0;$<P.args.length;$++){if(z=P.args[$].interpret(w),x.type.is_number(z)){if(y.type_args!==null&&z.is_float!==y.type_args)return x.error.type(y.type_args?\"float\":\"integer\",z,w.__call_indicator);F.push(z.value)}else return z;Z=Z||z.is_float}return F.push(w),z=x.arithmetic.evaluation[P.indicator].fn.apply(this,F),Z=y.type_result===null?Z:y.type_result,x.type.is_term(z)?z:z===Number.POSITIVE_INFINITY||z===Number.NEGATIVE_INFINITY?x.error.evaluation(\"overflow\",w.__call_indicator):Z===!1&&w.get_flag(\"bounded\").id===\"true\"&&(z>w.get_flag(\"max_integer\").value||z<w.get_flag(\"min_integer\").value)?x.error.evaluation(\"int_overflow\",w.__call_indicator):new Te(z,Z)}else return x.error.type(\"evaluable\",P.indicator,w.__call_indicator)},error:{existence:function(w,P,y){return typeof P==\"string\"&&(P=X(P)),new j(\"error\",[new j(\"existence_error\",[new j(w),P]),X(y)])},type:function(w,P,y){return new j(\"error\",[new j(\"type_error\",[new j(w),P]),X(y)])},instantiation:function(w){return new j(\"error\",[new j(\"instantiation_error\"),X(w)])},domain:function(w,P,y){return new j(\"error\",[new j(\"domain_error\",[new j(w),P]),X(y)])},representation:function(w,P){return new j(\"error\",[new j(\"representation_error\",[new j(w)]),X(P)])},permission:function(w,P,y,F){return new j(\"error\",[new j(\"permission_error\",[new j(w),new j(P),y]),X(F)])},evaluation:function(w,P){return new j(\"error\",[new j(\"evaluation_error\",[new j(w)]),X(P)])},syntax:function(w,P,y){w=w||{value:\"\",line:0,column:0,matches:[\"\"],start:0};var F=y&&w.matches.length>0?w.start+w.matches[0].length:w.start,z=y?new j(\"token_not_found\"):new j(\"found\",[new j(w.value.toString())]),Z=new j(\".\",[new j(\"line\",[new Te(w.line+1)]),new j(\".\",[new j(\"column\",[new Te(F+1)]),new j(\".\",[z,new j(\"[]\",[])])])]);return new j(\"error\",[new j(\"syntax_error\",[new j(P)]),Z])},syntax_by_predicate:function(w,P){return new j(\"error\",[new j(\"syntax_error\",[new j(w)]),X(P)])}},warning:{singleton:function(w,P,y){for(var F=new j(\"[]\"),z=w.length-1;z>=0;z--)F=new j(\".\",[new De(w[z]),F]);return new j(\"warning\",[new j(\"singleton_variables\",[F,X(P)]),new j(\".\",[new j(\"line\",[new Te(y,!1)]),new j(\"[]\")])])},failed_goal:function(w,P){return new j(\"warning\",[new j(\"failed_goal\",[w]),new j(\".\",[new j(\"line\",[new Te(P,!1)]),new j(\"[]\")])])}},format_variable:function(w){return\"_\"+w},format_answer:function(w,P,F){P instanceof ke&&(P=P.thread);var F=F||{};if(F.session=P?P.session:void 0,x.type.is_error(w))return\"uncaught exception: \"+w.args[0].toString();if(w===!1)return\"false.\";if(w===null)return\"limit exceeded ;\";var z=0,Z=\"\";if(x.type.is_substitution(w)){var $=w.domain(!0);w=w.filter(function(Re,lt){return!x.type.is_variable(lt)||$.indexOf(lt.id)!==-1&&Re!==lt.id})}for(var oe in w.links)w.links.hasOwnProperty(oe)&&(z++,Z!==\"\"&&(Z+=\", \"),Z+=oe.toString(F)+\" = \"+w.links[oe].toString(F));var xe=typeof P>\"u\"||P.points.length>0?\" ;\":\".\";return z===0?\"true\"+xe:Z+xe},flatten_error:function(w){if(!x.type.is_error(w))return null;w=w.args[0];var P={};return P.type=w.args[0].id,P.thrown=P.type===\"syntax_error\"?null:w.args[1].id,P.expected=null,P.found=null,P.representation=null,P.existence=null,P.existence_type=null,P.line=null,P.column=null,P.permission_operation=null,P.permission_type=null,P.evaluation_type=null,P.type===\"type_error\"||P.type===\"domain_error\"?(P.expected=w.args[0].args[0].id,P.found=w.args[0].args[1].toString()):P.type===\"syntax_error\"?w.args[1].indicator===\"./2\"?(P.expected=w.args[0].args[0].id,P.found=w.args[1].args[1].args[1].args[0],P.found=P.found.id===\"token_not_found\"?P.found.id:P.found.args[0].id,P.line=w.args[1].args[0].args[0].value,P.column=w.args[1].args[1].args[0].args[0].value):P.thrown=w.args[1].id:P.type===\"permission_error\"?(P.found=w.args[0].args[2].toString(),P.permission_operation=w.args[0].args[0].id,P.permission_type=w.args[0].args[1].id):P.type===\"evaluation_error\"?P.evaluation_type=w.args[0].args[0].id:P.type===\"representation_error\"?P.representation=w.args[0].args[0].id:P.type===\"existence_error\"&&(P.existence=w.args[0].args[1].toString(),P.existence_type=w.args[0].args[0].id),P},create:function(w){return new x.type.Session(w)}};typeof ec<\"u\"?ec.exports=x:window.pl=x})()});function hEe(t,e,r){t.prepend(r.map(s=>new hl.default.type.State(e.goal.replace(s),e.substitution,e)))}function k5(t){let e=dEe.get(t.session);if(e==null)throw new Error(\"Assertion failed: A project should have been registered for the active session\");return e}function mEe(t,e){dEe.set(t,e),t.consult(`:- use_module(library(${qct.id})).`)}var hl,gEe,J0,jct,Gct,dEe,qct,yEe=Ze(()=>{Ge();ql();hl=ut(x5()),gEe=ut(Ie(\"vm\")),{is_atom:J0,is_variable:jct,is_instantiated_list:Gct}=hl.default.type;dEe=new WeakMap;qct=new hl.default.type.Module(\"constraints\",{\"project_workspaces_by_descriptor/3\":(t,e,r)=>{let[s,a,n]=r.args;if(!J0(s)||!J0(a)){t.throw_error(hl.default.error.instantiation(r.indicator));return}let c=G.parseIdent(s.id),f=G.makeDescriptor(c,a.id),h=k5(t).tryWorkspaceByDescriptor(f);jct(n)&&h!==null&&hEe(t,e,[new hl.default.type.Term(\"=\",[n,new hl.default.type.Term(String(h.relativeCwd))])]),J0(n)&&h!==null&&h.relativeCwd===n.id&&t.success(e)},\"workspace_field/3\":(t,e,r)=>{let[s,a,n]=r.args;if(!J0(s)||!J0(a)){t.throw_error(hl.default.error.instantiation(r.indicator));return}let f=k5(t).tryWorkspaceByCwd(s.id);if(f==null)return;let p=va(f.manifest.raw,a.id);typeof p>\"u\"||hEe(t,e,[new hl.default.type.Term(\"=\",[n,new hl.default.type.Term(typeof p==\"object\"?JSON.stringify(p):p)])])},\"workspace_field_test/3\":(t,e,r)=>{let[s,a,n]=r.args;t.prepend([new hl.default.type.State(e.goal.replace(new hl.default.type.Term(\"workspace_field_test\",[s,a,n,new hl.default.type.Term(\"[]\",[])])),e.substitution,e)])},\"workspace_field_test/4\":(t,e,r)=>{let[s,a,n,c]=r.args;if(!J0(s)||!J0(a)||!J0(n)||!Gct(c)){t.throw_error(hl.default.error.instantiation(r.indicator));return}let p=k5(t).tryWorkspaceByCwd(s.id);if(p==null)return;let h=va(p.manifest.raw,a.id);if(typeof h>\"u\")return;let E={$$:h};for(let[S,b]of c.toJavaScript().entries())E[`$${S}`]=b;gEe.default.runInNewContext(n.id,E)&&t.success(e)}},[\"project_workspaces_by_descriptor/3\",\"workspace_field/3\",\"workspace_field_test/3\",\"workspace_field_test/4\"])});var aS={};Vt(aS,{Constraints:()=>R5,DependencyType:()=>wEe});function go(t){if(t instanceof KC.default.type.Num)return t.value;if(t instanceof KC.default.type.Term)switch(t.indicator){case\"throw/1\":return go(t.args[0]);case\"error/1\":return go(t.args[0]);case\"error/2\":if(t.args[0]instanceof KC.default.type.Term&&t.args[0].indicator===\"syntax_error/1\")return Object.assign(go(t.args[0]),...go(t.args[1]));{let e=go(t.args[0]);return e.message+=` (in ${go(t.args[1])})`,e}case\"syntax_error/1\":return new jt(43,`Syntax error: ${go(t.args[0])}`);case\"existence_error/2\":return new jt(44,`Existence error: ${go(t.args[0])} ${go(t.args[1])} not found`);case\"instantiation_error/0\":return new jt(75,\"Instantiation error: an argument is variable when an instantiated argument was expected\");case\"line/1\":return{line:go(t.args[0])};case\"column/1\":return{column:go(t.args[0])};case\"found/1\":return{found:go(t.args[0])};case\"./2\":return[go(t.args[0])].concat(go(t.args[1]));case\"//2\":return`${go(t.args[0])}/${go(t.args[1])}`;default:return t.id}throw`couldn't pretty print because of unsupported node ${t}`}function IEe(t){let e;try{e=go(t)}catch(r){throw typeof r==\"string\"?new jt(42,`Unknown error: ${t} (note: ${r})`):r}return typeof e.line<\"u\"&&typeof e.column<\"u\"&&(e.message+=` at line ${e.line}, column ${e.column}`),e}function bm(t){return t.id===\"null\"?null:`${t.toJavaScript()}`}function Wct(t){if(t.id===\"null\")return null;{let e=t.toJavaScript();if(typeof e!=\"string\")return JSON.stringify(e);try{return JSON.stringify(JSON.parse(e))}catch{return JSON.stringify(e)}}}function K0(t){return typeof t==\"string\"?`'${t}'`:\"[]\"}var CEe,KC,wEe,EEe,Q5,R5,lS=Ze(()=>{Ge();Ge();Dt();CEe=ut(Xye()),KC=ut(x5());iS();yEe();(0,CEe.default)(KC.default);wEe=(s=>(s.Dependencies=\"dependencies\",s.DevDependencies=\"devDependencies\",s.PeerDependencies=\"peerDependencies\",s))(wEe||{}),EEe=[\"dependencies\",\"devDependencies\",\"peerDependencies\"];Q5=class{constructor(e,r){let s=1e3*e.workspaces.length;this.session=KC.default.create(s),mEe(this.session,e),this.session.consult(\":- use_module(library(lists)).\"),this.session.consult(r)}fetchNextAnswer(){return new Promise(e=>{this.session.answer(r=>{e(r)})})}async*makeQuery(e){let r=this.session.query(e);if(r!==!0)throw IEe(r);for(;;){let s=await this.fetchNextAnswer();if(s===null)throw new jt(79,\"Resolution limit exceeded\");if(!s)break;if(s.id===\"throw\")throw IEe(s);yield s}}};R5=class t{constructor(e){this.source=\"\";this.project=e;let r=e.configuration.get(\"constraintsPath\");ce.existsSync(r)&&(this.source=ce.readFileSync(r,\"utf8\"))}static async find(e){return new t(e)}getProjectDatabase(){let e=\"\";for(let r of EEe)e+=`dependency_type(${r}).\n`;for(let r of this.project.workspacesByCwd.values()){let s=r.relativeCwd;e+=`workspace(${K0(s)}).\n`,e+=`workspace_ident(${K0(s)}, ${K0(G.stringifyIdent(r.anchoredLocator))}).\n`,e+=`workspace_version(${K0(s)}, ${K0(r.manifest.version)}).\n`;for(let a of EEe)for(let n of r.manifest[a].values())e+=`workspace_has_dependency(${K0(s)}, ${K0(G.stringifyIdent(n))}, ${K0(n.range)}, ${a}).\n`}return e+=`workspace(_) :- false.\n`,e+=`workspace_ident(_, _) :- false.\n`,e+=`workspace_version(_, _) :- false.\n`,e+=`workspace_has_dependency(_, _, _, _) :- false.\n`,e}getDeclarations(){let e=\"\";return e+=`gen_enforced_dependency(_, _, _, _) :- false.\n`,e+=`gen_enforced_field(_, _, _) :- false.\n`,e}get fullSource(){return`${this.getProjectDatabase()}\n${this.source}\n${this.getDeclarations()}`}createSession(){return new Q5(this.project,this.fullSource)}async processClassic(){let e=this.createSession();return{enforcedDependencies:await this.genEnforcedDependencies(e),enforcedFields:await this.genEnforcedFields(e)}}async process(){let{enforcedDependencies:e,enforcedFields:r}=await this.processClassic(),s=new Map;for(let{workspace:a,dependencyIdent:n,dependencyRange:c,dependencyType:f}of e){let p=nS([f,G.stringifyIdent(n)]),h=je.getMapWithDefault(s,a.cwd);je.getMapWithDefault(h,p).set(c??void 0,new Set)}for(let{workspace:a,fieldPath:n,fieldValue:c}of r){let f=nS(n),p=je.getMapWithDefault(s,a.cwd);je.getMapWithDefault(p,f).set(JSON.parse(c)??void 0,new Set)}return{manifestUpdates:s,reportedErrors:new Map}}async genEnforcedDependencies(e){let r=[];for await(let s of e.makeQuery(\"workspace(WorkspaceCwd), dependency_type(DependencyType), gen_enforced_dependency(WorkspaceCwd, DependencyIdent, DependencyRange, DependencyType).\")){let a=J.resolve(this.project.cwd,bm(s.links.WorkspaceCwd)),n=bm(s.links.DependencyIdent),c=bm(s.links.DependencyRange),f=bm(s.links.DependencyType);if(a===null||n===null)throw new Error(\"Invalid rule\");let p=this.project.getWorkspaceByCwd(a),h=G.parseIdent(n);r.push({workspace:p,dependencyIdent:h,dependencyRange:c,dependencyType:f})}return je.sortMap(r,[({dependencyRange:s})=>s!==null?\"0\":\"1\",({workspace:s})=>G.stringifyIdent(s.anchoredLocator),({dependencyIdent:s})=>G.stringifyIdent(s)])}async genEnforcedFields(e){let r=[];for await(let s of e.makeQuery(\"workspace(WorkspaceCwd), gen_enforced_field(WorkspaceCwd, FieldPath, FieldValue).\")){let a=J.resolve(this.project.cwd,bm(s.links.WorkspaceCwd)),n=bm(s.links.FieldPath),c=Wct(s.links.FieldValue);if(a===null||n===null)throw new Error(\"Invalid rule\");let f=this.project.getWorkspaceByCwd(a);r.push({workspace:f,fieldPath:n,fieldValue:c})}return je.sortMap(r,[({workspace:s})=>G.stringifyIdent(s.anchoredLocator),({fieldPath:s})=>s])}async*query(e){let r=this.createSession();for await(let s of r.makeQuery(e)){let a={};for(let[n,c]of Object.entries(s.links))n!==\"_\"&&(a[n]=bm(c));yield a}}}});var QEe=_(uF=>{\"use strict\";Object.defineProperty(uF,\"__esModule\",{value:!0});function BS(t){let e=[...t.caches],r=e.shift();return r===void 0?kEe():{get(s,a,n={miss:()=>Promise.resolve()}){return r.get(s,a,n).catch(()=>BS({caches:e}).get(s,a,n))},set(s,a){return r.set(s,a).catch(()=>BS({caches:e}).set(s,a))},delete(s){return r.delete(s).catch(()=>BS({caches:e}).delete(s))},clear(){return r.clear().catch(()=>BS({caches:e}).clear())}}}function kEe(){return{get(t,e,r={miss:()=>Promise.resolve()}){return e().then(a=>Promise.all([a,r.miss(a)])).then(([a])=>a)},set(t,e){return Promise.resolve(e)},delete(t){return Promise.resolve()},clear(){return Promise.resolve()}}}uF.createFallbackableCache=BS;uF.createNullCache=kEe});var TEe=_((iJt,REe)=>{REe.exports=QEe()});var FEe=_(Y5=>{\"use strict\";Object.defineProperty(Y5,\"__esModule\",{value:!0});function uut(t={serializable:!0}){let e={};return{get(r,s,a={miss:()=>Promise.resolve()}){let n=JSON.stringify(r);if(n in e)return Promise.resolve(t.serializable?JSON.parse(e[n]):e[n]);let c=s(),f=a&&a.miss||(()=>Promise.resolve());return c.then(p=>f(p)).then(()=>c)},set(r,s){return e[JSON.stringify(r)]=t.serializable?JSON.stringify(s):s,Promise.resolve(s)},delete(r){return delete e[JSON.stringify(r)],Promise.resolve()},clear(){return e={},Promise.resolve()}}}Y5.createInMemoryCache=uut});var OEe=_((oJt,NEe)=>{NEe.exports=FEe()});var MEe=_($u=>{\"use strict\";Object.defineProperty($u,\"__esModule\",{value:!0});function fut(t,e,r){let s={\"x-algolia-api-key\":r,\"x-algolia-application-id\":e};return{headers(){return t===V5.WithinHeaders?s:{}},queryParameters(){return t===V5.WithinQueryParameters?s:{}}}}function Aut(t){let e=0,r=()=>(e++,new Promise(s=>{setTimeout(()=>{s(t(r))},Math.min(100*e,1e3))}));return t(r)}function LEe(t,e=(r,s)=>Promise.resolve()){return Object.assign(t,{wait(r){return LEe(t.then(s=>Promise.all([e(s,r),s])).then(s=>s[1]))}})}function put(t){let e=t.length-1;for(e;e>0;e--){let r=Math.floor(Math.random()*(e+1)),s=t[e];t[e]=t[r],t[r]=s}return t}function hut(t,e){return e&&Object.keys(e).forEach(r=>{t[r]=e[r](t)}),t}function gut(t,...e){let r=0;return t.replace(/%s/g,()=>encodeURIComponent(e[r++]))}var dut=\"4.22.1\",mut=t=>()=>t.transporter.requester.destroy(),V5={WithinQueryParameters:0,WithinHeaders:1};$u.AuthMode=V5;$u.addMethods=hut;$u.createAuth=fut;$u.createRetryablePromise=Aut;$u.createWaitablePromise=LEe;$u.destroy=mut;$u.encode=gut;$u.shuffle=put;$u.version=dut});var vS=_((lJt,UEe)=>{UEe.exports=MEe()});var _Ee=_(J5=>{\"use strict\";Object.defineProperty(J5,\"__esModule\",{value:!0});var yut={Delete:\"DELETE\",Get:\"GET\",Post:\"POST\",Put:\"PUT\"};J5.MethodEnum=yut});var SS=_((uJt,HEe)=>{HEe.exports=_Ee()});var rIe=_(Wi=>{\"use strict\";Object.defineProperty(Wi,\"__esModule\",{value:!0});var GEe=SS();function K5(t,e){let r=t||{},s=r.data||{};return Object.keys(r).forEach(a=>{[\"timeout\",\"headers\",\"queryParameters\",\"data\",\"cacheable\"].indexOf(a)===-1&&(s[a]=r[a])}),{data:Object.entries(s).length>0?s:void 0,timeout:r.timeout||e,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}var DS={Read:1,Write:2,Any:3},sw={Up:1,Down:2,Timeouted:3},qEe=2*60*1e3;function Z5(t,e=sw.Up){return{...t,status:e,lastUpdate:Date.now()}}function WEe(t){return t.status===sw.Up||Date.now()-t.lastUpdate>qEe}function YEe(t){return t.status===sw.Timeouted&&Date.now()-t.lastUpdate<=qEe}function X5(t){return typeof t==\"string\"?{protocol:\"https\",url:t,accept:DS.Any}:{protocol:t.protocol||\"https\",url:t.url,accept:t.accept||DS.Any}}function Eut(t,e){return Promise.all(e.map(r=>t.get(r,()=>Promise.resolve(Z5(r))))).then(r=>{let s=r.filter(f=>WEe(f)),a=r.filter(f=>YEe(f)),n=[...s,...a],c=n.length>0?n.map(f=>X5(f)):e;return{getTimeout(f,p){return(a.length===0&&f===0?1:a.length+3+f)*p},statelessHosts:c}})}var Iut=({isTimedOut:t,status:e})=>!t&&~~e===0,Cut=t=>{let e=t.status;return t.isTimedOut||Iut(t)||~~(e/100)!==2&&~~(e/100)!==4},wut=({status:t})=>~~(t/100)===2,But=(t,e)=>Cut(t)?e.onRetry(t):wut(t)?e.onSuccess(t):e.onFail(t);function jEe(t,e,r,s){let a=[],n=ZEe(r,s),c=XEe(t,s),f=r.method,p=r.method!==GEe.MethodEnum.Get?{}:{...r.data,...s.data},h={\"x-algolia-agent\":t.userAgent.value,...t.queryParameters,...p,...s.queryParameters},E=0,C=(S,b)=>{let I=S.pop();if(I===void 0)throw tIe(z5(a));let T={data:n,headers:c,method:f,url:KEe(I,r.path,h),connectTimeout:b(E,t.timeouts.connect),responseTimeout:b(E,s.timeout)},N=W=>{let ee={request:T,response:W,host:I,triesLeft:S.length};return a.push(ee),ee},U={onSuccess:W=>VEe(W),onRetry(W){let ee=N(W);return W.isTimedOut&&E++,Promise.all([t.logger.info(\"Retryable failure\",$5(ee)),t.hostsCache.set(I,Z5(I,W.isTimedOut?sw.Timeouted:sw.Down))]).then(()=>C(S,b))},onFail(W){throw N(W),JEe(W,z5(a))}};return t.requester.send(T).then(W=>But(W,U))};return Eut(t.hostsCache,e).then(S=>C([...S.statelessHosts].reverse(),S.getTimeout))}function vut(t){let{hostsCache:e,logger:r,requester:s,requestsCache:a,responsesCache:n,timeouts:c,userAgent:f,hosts:p,queryParameters:h,headers:E}=t,C={hostsCache:e,logger:r,requester:s,requestsCache:a,responsesCache:n,timeouts:c,userAgent:f,headers:E,queryParameters:h,hosts:p.map(S=>X5(S)),read(S,b){let I=K5(b,C.timeouts.read),T=()=>jEe(C,C.hosts.filter(W=>(W.accept&DS.Read)!==0),S,I);if((I.cacheable!==void 0?I.cacheable:S.cacheable)!==!0)return T();let U={request:S,mappedRequestOptions:I,transporter:{queryParameters:C.queryParameters,headers:C.headers}};return C.responsesCache.get(U,()=>C.requestsCache.get(U,()=>C.requestsCache.set(U,T()).then(W=>Promise.all([C.requestsCache.delete(U),W]),W=>Promise.all([C.requestsCache.delete(U),Promise.reject(W)])).then(([W,ee])=>ee)),{miss:W=>C.responsesCache.set(U,W)})},write(S,b){return jEe(C,C.hosts.filter(I=>(I.accept&DS.Write)!==0),S,K5(b,C.timeouts.write))}};return C}function Sut(t){let e={value:`Algolia for JavaScript (${t})`,add(r){let s=`; ${r.segment}${r.version!==void 0?` (${r.version})`:\"\"}`;return e.value.indexOf(s)===-1&&(e.value=`${e.value}${s}`),e}};return e}function VEe(t){try{return JSON.parse(t.content)}catch(e){throw eIe(e.message,t)}}function JEe({content:t,status:e},r){let s=t;try{s=JSON.parse(t).message}catch{}return $Ee(s,e,r)}function Dut(t,...e){let r=0;return t.replace(/%s/g,()=>encodeURIComponent(e[r++]))}function KEe(t,e,r){let s=zEe(r),a=`${t.protocol}://${t.url}/${e.charAt(0)===\"/\"?e.substr(1):e}`;return s.length&&(a+=`?${s}`),a}function zEe(t){let e=r=>Object.prototype.toString.call(r)===\"[object Object]\"||Object.prototype.toString.call(r)===\"[object Array]\";return Object.keys(t).map(r=>Dut(\"%s=%s\",r,e(t[r])?JSON.stringify(t[r]):t[r])).join(\"&\")}function ZEe(t,e){if(t.method===GEe.MethodEnum.Get||t.data===void 0&&e.data===void 0)return;let r=Array.isArray(t.data)?t.data:{...t.data,...e.data};return JSON.stringify(r)}function XEe(t,e){let r={...t.headers,...e.headers},s={};return Object.keys(r).forEach(a=>{let n=r[a];s[a.toLowerCase()]=n}),s}function z5(t){return t.map(e=>$5(e))}function $5(t){let e=t.request.headers[\"x-algolia-api-key\"]?{\"x-algolia-api-key\":\"*****\"}:{};return{...t,request:{...t.request,headers:{...t.request.headers,...e}}}}function $Ee(t,e,r){return{name:\"ApiError\",message:t,status:e,transporterStackTrace:r}}function eIe(t,e){return{name:\"DeserializationError\",message:t,response:e}}function tIe(t){return{name:\"RetryError\",message:\"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.\",transporterStackTrace:t}}Wi.CallEnum=DS;Wi.HostStatusEnum=sw;Wi.createApiError=$Ee;Wi.createDeserializationError=eIe;Wi.createMappedRequestOptions=K5;Wi.createRetryError=tIe;Wi.createStatefulHost=Z5;Wi.createStatelessHost=X5;Wi.createTransporter=vut;Wi.createUserAgent=Sut;Wi.deserializeFailure=JEe;Wi.deserializeSuccess=VEe;Wi.isStatefulHostTimeouted=YEe;Wi.isStatefulHostUp=WEe;Wi.serializeData=ZEe;Wi.serializeHeaders=XEe;Wi.serializeQueryParameters=zEe;Wi.serializeUrl=KEe;Wi.stackFrameWithoutCredentials=$5;Wi.stackTraceWithoutCredentials=z5});var PS=_((AJt,nIe)=>{nIe.exports=rIe()});var iIe=_(Z0=>{\"use strict\";Object.defineProperty(Z0,\"__esModule\",{value:!0});var ow=vS(),Put=PS(),bS=SS(),but=t=>{let e=t.region||\"us\",r=ow.createAuth(ow.AuthMode.WithinHeaders,t.appId,t.apiKey),s=Put.createTransporter({hosts:[{url:`analytics.${e}.algolia.com`}],...t,headers:{...r.headers(),\"content-type\":\"application/json\",...t.headers},queryParameters:{...r.queryParameters(),...t.queryParameters}}),a=t.appId;return ow.addMethods({appId:a,transporter:s},t.methods)},xut=t=>(e,r)=>t.transporter.write({method:bS.MethodEnum.Post,path:\"2/abtests\",data:e},r),kut=t=>(e,r)=>t.transporter.write({method:bS.MethodEnum.Delete,path:ow.encode(\"2/abtests/%s\",e)},r),Qut=t=>(e,r)=>t.transporter.read({method:bS.MethodEnum.Get,path:ow.encode(\"2/abtests/%s\",e)},r),Rut=t=>e=>t.transporter.read({method:bS.MethodEnum.Get,path:\"2/abtests\"},e),Tut=t=>(e,r)=>t.transporter.write({method:bS.MethodEnum.Post,path:ow.encode(\"2/abtests/%s/stop\",e)},r);Z0.addABTest=xut;Z0.createAnalyticsClient=but;Z0.deleteABTest=kut;Z0.getABTest=Qut;Z0.getABTests=Rut;Z0.stopABTest=Tut});var oIe=_((hJt,sIe)=>{sIe.exports=iIe()});var lIe=_(xS=>{\"use strict\";Object.defineProperty(xS,\"__esModule\",{value:!0});var e9=vS(),Fut=PS(),aIe=SS(),Nut=t=>{let e=t.region||\"us\",r=e9.createAuth(e9.AuthMode.WithinHeaders,t.appId,t.apiKey),s=Fut.createTransporter({hosts:[{url:`personalization.${e}.algolia.com`}],...t,headers:{...r.headers(),\"content-type\":\"application/json\",...t.headers},queryParameters:{...r.queryParameters(),...t.queryParameters}});return e9.addMethods({appId:t.appId,transporter:s},t.methods)},Out=t=>e=>t.transporter.read({method:aIe.MethodEnum.Get,path:\"1/strategies/personalization\"},e),Lut=t=>(e,r)=>t.transporter.write({method:aIe.MethodEnum.Post,path:\"1/strategies/personalization\",data:e},r);xS.createPersonalizationClient=Nut;xS.getPersonalizationStrategy=Out;xS.setPersonalizationStrategy=Lut});var uIe=_((dJt,cIe)=>{cIe.exports=lIe()});var vIe=_(Ft=>{\"use strict\";Object.defineProperty(Ft,\"__esModule\",{value:!0});var Jt=vS(),gl=PS(),Pr=SS(),Mut=Ie(\"crypto\");function fF(t){let e=r=>t.request(r).then(s=>{if(t.batch!==void 0&&t.batch(s.hits),!t.shouldStop(s))return s.cursor?e({cursor:s.cursor}):e({page:(r.page||0)+1})});return e({})}var Uut=t=>{let e=t.appId,r=Jt.createAuth(t.authMode!==void 0?t.authMode:Jt.AuthMode.WithinHeaders,e,t.apiKey),s=gl.createTransporter({hosts:[{url:`${e}-dsn.algolia.net`,accept:gl.CallEnum.Read},{url:`${e}.algolia.net`,accept:gl.CallEnum.Write}].concat(Jt.shuffle([{url:`${e}-1.algolianet.com`},{url:`${e}-2.algolianet.com`},{url:`${e}-3.algolianet.com`}])),...t,headers:{...r.headers(),\"content-type\":\"application/x-www-form-urlencoded\",...t.headers},queryParameters:{...r.queryParameters(),...t.queryParameters}}),a={transporter:s,appId:e,addAlgoliaAgent(n,c){s.userAgent.add({segment:n,version:c})},clearCache(){return Promise.all([s.requestsCache.clear(),s.responsesCache.clear()]).then(()=>{})}};return Jt.addMethods(a,t.methods)};function fIe(){return{name:\"MissingObjectIDError\",message:\"All objects must have an unique objectID (like a primary key) to be valid. Algolia is also able to generate objectIDs automatically but *it's not recommended*. To do it, use the `{'autoGenerateObjectIDIfNotExist': true}` option.\"}}function AIe(){return{name:\"ObjectNotFoundError\",message:\"Object not found.\"}}function pIe(){return{name:\"ValidUntilNotFoundError\",message:\"ValidUntil not found in given secured api key.\"}}var _ut=t=>(e,r)=>{let{queryParameters:s,...a}=r||{},n={acl:e,...s!==void 0?{queryParameters:s}:{}},c=(f,p)=>Jt.createRetryablePromise(h=>kS(t)(f.key,p).catch(E=>{if(E.status!==404)throw E;return h()}));return Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Post,path:\"1/keys\",data:n},a),c)},Hut=t=>(e,r,s)=>{let a=gl.createMappedRequestOptions(s);return a.queryParameters[\"X-Algolia-User-ID\"]=e,t.transporter.write({method:Pr.MethodEnum.Post,path:\"1/clusters/mapping\",data:{cluster:r}},a)},jut=t=>(e,r,s)=>t.transporter.write({method:Pr.MethodEnum.Post,path:\"1/clusters/mapping/batch\",data:{users:e,cluster:r}},s),Gut=t=>(e,r)=>Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Post,path:Jt.encode(\"/1/dictionaries/%s/batch\",e),data:{clearExistingDictionaryEntries:!0,requests:{action:\"addEntry\",body:[]}}},r),(s,a)=>aw(t)(s.taskID,a)),AF=t=>(e,r,s)=>{let a=(n,c)=>QS(t)(e,{methods:{waitTask:hs}}).waitTask(n.taskID,c);return Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Post,path:Jt.encode(\"1/indexes/%s/operation\",e),data:{operation:\"copy\",destination:r}},s),a)},qut=t=>(e,r,s)=>AF(t)(e,r,{...s,scope:[hF.Rules]}),Wut=t=>(e,r,s)=>AF(t)(e,r,{...s,scope:[hF.Settings]}),Yut=t=>(e,r,s)=>AF(t)(e,r,{...s,scope:[hF.Synonyms]}),Vut=t=>(e,r)=>e.method===Pr.MethodEnum.Get?t.transporter.read(e,r):t.transporter.write(e,r),Jut=t=>(e,r)=>{let s=(a,n)=>Jt.createRetryablePromise(c=>kS(t)(e,n).then(c).catch(f=>{if(f.status!==404)throw f}));return Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Delete,path:Jt.encode(\"1/keys/%s\",e)},r),s)},Kut=t=>(e,r,s)=>{let a=r.map(n=>({action:\"deleteEntry\",body:{objectID:n}}));return Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Post,path:Jt.encode(\"/1/dictionaries/%s/batch\",e),data:{clearExistingDictionaryEntries:!1,requests:a}},s),(n,c)=>aw(t)(n.taskID,c))},zut=()=>(t,e)=>{let r=gl.serializeQueryParameters(e),s=Mut.createHmac(\"sha256\",t).update(r).digest(\"hex\");return Buffer.from(s+r).toString(\"base64\")},kS=t=>(e,r)=>t.transporter.read({method:Pr.MethodEnum.Get,path:Jt.encode(\"1/keys/%s\",e)},r),hIe=t=>(e,r)=>t.transporter.read({method:Pr.MethodEnum.Get,path:Jt.encode(\"1/task/%s\",e.toString())},r),Zut=t=>e=>t.transporter.read({method:Pr.MethodEnum.Get,path:\"/1/dictionaries/*/settings\"},e),Xut=t=>e=>t.transporter.read({method:Pr.MethodEnum.Get,path:\"1/logs\"},e),$ut=()=>t=>{let e=Buffer.from(t,\"base64\").toString(\"ascii\"),r=/validUntil=(\\d+)/,s=e.match(r);if(s===null)throw pIe();return parseInt(s[1],10)-Math.round(new Date().getTime()/1e3)},eft=t=>e=>t.transporter.read({method:Pr.MethodEnum.Get,path:\"1/clusters/mapping/top\"},e),tft=t=>(e,r)=>t.transporter.read({method:Pr.MethodEnum.Get,path:Jt.encode(\"1/clusters/mapping/%s\",e)},r),rft=t=>e=>{let{retrieveMappings:r,...s}=e||{};return r===!0&&(s.getClusters=!0),t.transporter.read({method:Pr.MethodEnum.Get,path:\"1/clusters/mapping/pending\"},s)},QS=t=>(e,r={})=>{let s={transporter:t.transporter,appId:t.appId,indexName:e};return Jt.addMethods(s,r.methods)},nft=t=>e=>t.transporter.read({method:Pr.MethodEnum.Get,path:\"1/keys\"},e),ift=t=>e=>t.transporter.read({method:Pr.MethodEnum.Get,path:\"1/clusters\"},e),sft=t=>e=>t.transporter.read({method:Pr.MethodEnum.Get,path:\"1/indexes\"},e),oft=t=>e=>t.transporter.read({method:Pr.MethodEnum.Get,path:\"1/clusters/mapping\"},e),aft=t=>(e,r,s)=>{let a=(n,c)=>QS(t)(e,{methods:{waitTask:hs}}).waitTask(n.taskID,c);return Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Post,path:Jt.encode(\"1/indexes/%s/operation\",e),data:{operation:\"move\",destination:r}},s),a)},lft=t=>(e,r)=>{let s=(a,n)=>Promise.all(Object.keys(a.taskID).map(c=>QS(t)(c,{methods:{waitTask:hs}}).waitTask(a.taskID[c],n)));return Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Post,path:\"1/indexes/*/batch\",data:{requests:e}},r),s)},cft=t=>(e,r)=>t.transporter.read({method:Pr.MethodEnum.Post,path:\"1/indexes/*/objects\",data:{requests:e}},r),uft=t=>(e,r)=>{let s=e.map(a=>({...a,params:gl.serializeQueryParameters(a.params||{})}));return t.transporter.read({method:Pr.MethodEnum.Post,path:\"1/indexes/*/queries\",data:{requests:s},cacheable:!0},r)},fft=t=>(e,r)=>Promise.all(e.map(s=>{let{facetName:a,facetQuery:n,...c}=s.params;return QS(t)(s.indexName,{methods:{searchForFacetValues:CIe}}).searchForFacetValues(a,n,{...r,...c})})),Aft=t=>(e,r)=>{let s=gl.createMappedRequestOptions(r);return s.queryParameters[\"X-Algolia-User-ID\"]=e,t.transporter.write({method:Pr.MethodEnum.Delete,path:\"1/clusters/mapping\"},s)},pft=t=>(e,r,s)=>{let a=r.map(n=>({action:\"addEntry\",body:n}));return Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Post,path:Jt.encode(\"/1/dictionaries/%s/batch\",e),data:{clearExistingDictionaryEntries:!0,requests:a}},s),(n,c)=>aw(t)(n.taskID,c))},hft=t=>(e,r)=>{let s=(a,n)=>Jt.createRetryablePromise(c=>kS(t)(e,n).catch(f=>{if(f.status!==404)throw f;return c()}));return Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Post,path:Jt.encode(\"1/keys/%s/restore\",e)},r),s)},gft=t=>(e,r,s)=>{let a=r.map(n=>({action:\"addEntry\",body:n}));return Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Post,path:Jt.encode(\"/1/dictionaries/%s/batch\",e),data:{clearExistingDictionaryEntries:!1,requests:a}},s),(n,c)=>aw(t)(n.taskID,c))},dft=t=>(e,r,s)=>t.transporter.read({method:Pr.MethodEnum.Post,path:Jt.encode(\"/1/dictionaries/%s/search\",e),data:{query:r},cacheable:!0},s),mft=t=>(e,r)=>t.transporter.read({method:Pr.MethodEnum.Post,path:\"1/clusters/mapping/search\",data:{query:e}},r),yft=t=>(e,r)=>Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Put,path:\"/1/dictionaries/*/settings\",data:e},r),(s,a)=>aw(t)(s.taskID,a)),Eft=t=>(e,r)=>{let s=Object.assign({},r),{queryParameters:a,...n}=r||{},c=a?{queryParameters:a}:{},f=[\"acl\",\"indexes\",\"referers\",\"restrictSources\",\"queryParameters\",\"description\",\"maxQueriesPerIPPerHour\",\"maxHitsPerQuery\"],p=E=>Object.keys(s).filter(C=>f.indexOf(C)!==-1).every(C=>{if(Array.isArray(E[C])&&Array.isArray(s[C])){let S=E[C];return S.length===s[C].length&&S.every((b,I)=>b===s[C][I])}else return E[C]===s[C]}),h=(E,C)=>Jt.createRetryablePromise(S=>kS(t)(e,C).then(b=>p(b)?Promise.resolve():S()));return Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Put,path:Jt.encode(\"1/keys/%s\",e),data:c},n),h)},aw=t=>(e,r)=>Jt.createRetryablePromise(s=>hIe(t)(e,r).then(a=>a.status!==\"published\"?s():void 0)),gIe=t=>(e,r)=>{let s=(a,n)=>hs(t)(a.taskID,n);return Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Post,path:Jt.encode(\"1/indexes/%s/batch\",t.indexName),data:{requests:e}},r),s)},Ift=t=>e=>fF({shouldStop:r=>r.cursor===void 0,...e,request:r=>t.transporter.read({method:Pr.MethodEnum.Post,path:Jt.encode(\"1/indexes/%s/browse\",t.indexName),data:r},e)}),Cft=t=>e=>{let r={hitsPerPage:1e3,...e};return fF({shouldStop:s=>s.hits.length<r.hitsPerPage,...r,request(s){return wIe(t)(\"\",{...r,...s}).then(a=>({...a,hits:a.hits.map(n=>(delete n._highlightResult,n))}))}})},wft=t=>e=>{let r={hitsPerPage:1e3,...e};return fF({shouldStop:s=>s.hits.length<r.hitsPerPage,...r,request(s){return BIe(t)(\"\",{...r,...s}).then(a=>({...a,hits:a.hits.map(n=>(delete n._highlightResult,n))}))}})},pF=t=>(e,r,s)=>{let{batchSize:a,...n}=s||{},c={taskIDs:[],objectIDs:[]},f=(p=0)=>{let h=[],E;for(E=p;E<e.length&&(h.push(e[E]),h.length!==(a||1e3));E++);return h.length===0?Promise.resolve(c):gIe(t)(h.map(C=>({action:r,body:C})),n).then(C=>(c.objectIDs=c.objectIDs.concat(C.objectIDs),c.taskIDs.push(C.taskID),E++,f(E)))};return Jt.createWaitablePromise(f(),(p,h)=>Promise.all(p.taskIDs.map(E=>hs(t)(E,h))))},Bft=t=>e=>Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Post,path:Jt.encode(\"1/indexes/%s/clear\",t.indexName)},e),(r,s)=>hs(t)(r.taskID,s)),vft=t=>e=>{let{forwardToReplicas:r,...s}=e||{},a=gl.createMappedRequestOptions(s);return r&&(a.queryParameters.forwardToReplicas=1),Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Post,path:Jt.encode(\"1/indexes/%s/rules/clear\",t.indexName)},a),(n,c)=>hs(t)(n.taskID,c))},Sft=t=>e=>{let{forwardToReplicas:r,...s}=e||{},a=gl.createMappedRequestOptions(s);return r&&(a.queryParameters.forwardToReplicas=1),Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Post,path:Jt.encode(\"1/indexes/%s/synonyms/clear\",t.indexName)},a),(n,c)=>hs(t)(n.taskID,c))},Dft=t=>(e,r)=>Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Post,path:Jt.encode(\"1/indexes/%s/deleteByQuery\",t.indexName),data:e},r),(s,a)=>hs(t)(s.taskID,a)),Pft=t=>e=>Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Delete,path:Jt.encode(\"1/indexes/%s\",t.indexName)},e),(r,s)=>hs(t)(r.taskID,s)),bft=t=>(e,r)=>Jt.createWaitablePromise(dIe(t)([e],r).then(s=>({taskID:s.taskIDs[0]})),(s,a)=>hs(t)(s.taskID,a)),dIe=t=>(e,r)=>{let s=e.map(a=>({objectID:a}));return pF(t)(s,km.DeleteObject,r)},xft=t=>(e,r)=>{let{forwardToReplicas:s,...a}=r||{},n=gl.createMappedRequestOptions(a);return s&&(n.queryParameters.forwardToReplicas=1),Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Delete,path:Jt.encode(\"1/indexes/%s/rules/%s\",t.indexName,e)},n),(c,f)=>hs(t)(c.taskID,f))},kft=t=>(e,r)=>{let{forwardToReplicas:s,...a}=r||{},n=gl.createMappedRequestOptions(a);return s&&(n.queryParameters.forwardToReplicas=1),Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Delete,path:Jt.encode(\"1/indexes/%s/synonyms/%s\",t.indexName,e)},n),(c,f)=>hs(t)(c.taskID,f))},Qft=t=>e=>mIe(t)(e).then(()=>!0).catch(r=>{if(r.status!==404)throw r;return!1}),Rft=t=>(e,r,s)=>t.transporter.read({method:Pr.MethodEnum.Post,path:Jt.encode(\"1/answers/%s/prediction\",t.indexName),data:{query:e,queryLanguages:r},cacheable:!0},s),Tft=t=>(e,r)=>{let{query:s,paginate:a,...n}=r||{},c=0,f=()=>IIe(t)(s||\"\",{...n,page:c}).then(p=>{for(let[h,E]of Object.entries(p.hits))if(e(E))return{object:E,position:parseInt(h,10),page:c};if(c++,a===!1||c>=p.nbPages)throw AIe();return f()});return f()},Fft=t=>(e,r)=>t.transporter.read({method:Pr.MethodEnum.Get,path:Jt.encode(\"1/indexes/%s/%s\",t.indexName,e)},r),Nft=()=>(t,e)=>{for(let[r,s]of Object.entries(t.hits))if(s.objectID===e)return parseInt(r,10);return-1},Oft=t=>(e,r)=>{let{attributesToRetrieve:s,...a}=r||{},n=e.map(c=>({indexName:t.indexName,objectID:c,...s?{attributesToRetrieve:s}:{}}));return t.transporter.read({method:Pr.MethodEnum.Post,path:\"1/indexes/*/objects\",data:{requests:n}},a)},Lft=t=>(e,r)=>t.transporter.read({method:Pr.MethodEnum.Get,path:Jt.encode(\"1/indexes/%s/rules/%s\",t.indexName,e)},r),mIe=t=>e=>t.transporter.read({method:Pr.MethodEnum.Get,path:Jt.encode(\"1/indexes/%s/settings\",t.indexName),data:{getVersion:2}},e),Mft=t=>(e,r)=>t.transporter.read({method:Pr.MethodEnum.Get,path:Jt.encode(\"1/indexes/%s/synonyms/%s\",t.indexName,e)},r),yIe=t=>(e,r)=>t.transporter.read({method:Pr.MethodEnum.Get,path:Jt.encode(\"1/indexes/%s/task/%s\",t.indexName,e.toString())},r),Uft=t=>(e,r)=>Jt.createWaitablePromise(EIe(t)([e],r).then(s=>({objectID:s.objectIDs[0],taskID:s.taskIDs[0]})),(s,a)=>hs(t)(s.taskID,a)),EIe=t=>(e,r)=>{let{createIfNotExists:s,...a}=r||{},n=s?km.PartialUpdateObject:km.PartialUpdateObjectNoCreate;return pF(t)(e,n,a)},_ft=t=>(e,r)=>{let{safe:s,autoGenerateObjectIDIfNotExist:a,batchSize:n,...c}=r||{},f=(I,T,N,U)=>Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Post,path:Jt.encode(\"1/indexes/%s/operation\",I),data:{operation:N,destination:T}},U),(W,ee)=>hs(t)(W.taskID,ee)),p=Math.random().toString(36).substring(7),h=`${t.indexName}_tmp_${p}`,E=t9({appId:t.appId,transporter:t.transporter,indexName:h}),C=[],S=f(t.indexName,h,\"copy\",{...c,scope:[\"settings\",\"synonyms\",\"rules\"]});C.push(S);let b=(s?S.wait(c):S).then(()=>{let I=E(e,{...c,autoGenerateObjectIDIfNotExist:a,batchSize:n});return C.push(I),s?I.wait(c):I}).then(()=>{let I=f(h,t.indexName,\"move\",c);return C.push(I),s?I.wait(c):I}).then(()=>Promise.all(C)).then(([I,T,N])=>({objectIDs:T.objectIDs,taskIDs:[I.taskID,...T.taskIDs,N.taskID]}));return Jt.createWaitablePromise(b,(I,T)=>Promise.all(C.map(N=>N.wait(T))))},Hft=t=>(e,r)=>r9(t)(e,{...r,clearExistingRules:!0}),jft=t=>(e,r)=>n9(t)(e,{...r,clearExistingSynonyms:!0}),Gft=t=>(e,r)=>Jt.createWaitablePromise(t9(t)([e],r).then(s=>({objectID:s.objectIDs[0],taskID:s.taskIDs[0]})),(s,a)=>hs(t)(s.taskID,a)),t9=t=>(e,r)=>{let{autoGenerateObjectIDIfNotExist:s,...a}=r||{},n=s?km.AddObject:km.UpdateObject;if(n===km.UpdateObject){for(let c of e)if(c.objectID===void 0)return Jt.createWaitablePromise(Promise.reject(fIe()))}return pF(t)(e,n,a)},qft=t=>(e,r)=>r9(t)([e],r),r9=t=>(e,r)=>{let{forwardToReplicas:s,clearExistingRules:a,...n}=r||{},c=gl.createMappedRequestOptions(n);return s&&(c.queryParameters.forwardToReplicas=1),a&&(c.queryParameters.clearExistingRules=1),Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Post,path:Jt.encode(\"1/indexes/%s/rules/batch\",t.indexName),data:e},c),(f,p)=>hs(t)(f.taskID,p))},Wft=t=>(e,r)=>n9(t)([e],r),n9=t=>(e,r)=>{let{forwardToReplicas:s,clearExistingSynonyms:a,replaceExistingSynonyms:n,...c}=r||{},f=gl.createMappedRequestOptions(c);return s&&(f.queryParameters.forwardToReplicas=1),(n||a)&&(f.queryParameters.replaceExistingSynonyms=1),Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Post,path:Jt.encode(\"1/indexes/%s/synonyms/batch\",t.indexName),data:e},f),(p,h)=>hs(t)(p.taskID,h))},IIe=t=>(e,r)=>t.transporter.read({method:Pr.MethodEnum.Post,path:Jt.encode(\"1/indexes/%s/query\",t.indexName),data:{query:e},cacheable:!0},r),CIe=t=>(e,r,s)=>t.transporter.read({method:Pr.MethodEnum.Post,path:Jt.encode(\"1/indexes/%s/facets/%s/query\",t.indexName,e),data:{facetQuery:r},cacheable:!0},s),wIe=t=>(e,r)=>t.transporter.read({method:Pr.MethodEnum.Post,path:Jt.encode(\"1/indexes/%s/rules/search\",t.indexName),data:{query:e}},r),BIe=t=>(e,r)=>t.transporter.read({method:Pr.MethodEnum.Post,path:Jt.encode(\"1/indexes/%s/synonyms/search\",t.indexName),data:{query:e}},r),Yft=t=>(e,r)=>{let{forwardToReplicas:s,...a}=r||{},n=gl.createMappedRequestOptions(a);return s&&(n.queryParameters.forwardToReplicas=1),Jt.createWaitablePromise(t.transporter.write({method:Pr.MethodEnum.Put,path:Jt.encode(\"1/indexes/%s/settings\",t.indexName),data:e},n),(c,f)=>hs(t)(c.taskID,f))},hs=t=>(e,r)=>Jt.createRetryablePromise(s=>yIe(t)(e,r).then(a=>a.status!==\"published\"?s():void 0)),Vft={AddObject:\"addObject\",Analytics:\"analytics\",Browser:\"browse\",DeleteIndex:\"deleteIndex\",DeleteObject:\"deleteObject\",EditSettings:\"editSettings\",Inference:\"inference\",ListIndexes:\"listIndexes\",Logs:\"logs\",Personalization:\"personalization\",Recommendation:\"recommendation\",Search:\"search\",SeeUnretrievableAttributes:\"seeUnretrievableAttributes\",Settings:\"settings\",Usage:\"usage\"},km={AddObject:\"addObject\",UpdateObject:\"updateObject\",PartialUpdateObject:\"partialUpdateObject\",PartialUpdateObjectNoCreate:\"partialUpdateObjectNoCreate\",DeleteObject:\"deleteObject\",DeleteIndex:\"delete\",ClearIndex:\"clear\"},hF={Settings:\"settings\",Synonyms:\"synonyms\",Rules:\"rules\"},Jft={None:\"none\",StopIfEnoughMatches:\"stopIfEnoughMatches\"},Kft={Synonym:\"synonym\",OneWaySynonym:\"oneWaySynonym\",AltCorrection1:\"altCorrection1\",AltCorrection2:\"altCorrection2\",Placeholder:\"placeholder\"};Ft.ApiKeyACLEnum=Vft;Ft.BatchActionEnum=km;Ft.ScopeEnum=hF;Ft.StrategyEnum=Jft;Ft.SynonymEnum=Kft;Ft.addApiKey=_ut;Ft.assignUserID=Hut;Ft.assignUserIDs=jut;Ft.batch=gIe;Ft.browseObjects=Ift;Ft.browseRules=Cft;Ft.browseSynonyms=wft;Ft.chunkedBatch=pF;Ft.clearDictionaryEntries=Gut;Ft.clearObjects=Bft;Ft.clearRules=vft;Ft.clearSynonyms=Sft;Ft.copyIndex=AF;Ft.copyRules=qut;Ft.copySettings=Wut;Ft.copySynonyms=Yut;Ft.createBrowsablePromise=fF;Ft.createMissingObjectIDError=fIe;Ft.createObjectNotFoundError=AIe;Ft.createSearchClient=Uut;Ft.createValidUntilNotFoundError=pIe;Ft.customRequest=Vut;Ft.deleteApiKey=Jut;Ft.deleteBy=Dft;Ft.deleteDictionaryEntries=Kut;Ft.deleteIndex=Pft;Ft.deleteObject=bft;Ft.deleteObjects=dIe;Ft.deleteRule=xft;Ft.deleteSynonym=kft;Ft.exists=Qft;Ft.findAnswers=Rft;Ft.findObject=Tft;Ft.generateSecuredApiKey=zut;Ft.getApiKey=kS;Ft.getAppTask=hIe;Ft.getDictionarySettings=Zut;Ft.getLogs=Xut;Ft.getObject=Fft;Ft.getObjectPosition=Nft;Ft.getObjects=Oft;Ft.getRule=Lft;Ft.getSecuredApiKeyRemainingValidity=$ut;Ft.getSettings=mIe;Ft.getSynonym=Mft;Ft.getTask=yIe;Ft.getTopUserIDs=eft;Ft.getUserID=tft;Ft.hasPendingMappings=rft;Ft.initIndex=QS;Ft.listApiKeys=nft;Ft.listClusters=ift;Ft.listIndices=sft;Ft.listUserIDs=oft;Ft.moveIndex=aft;Ft.multipleBatch=lft;Ft.multipleGetObjects=cft;Ft.multipleQueries=uft;Ft.multipleSearchForFacetValues=fft;Ft.partialUpdateObject=Uft;Ft.partialUpdateObjects=EIe;Ft.removeUserID=Aft;Ft.replaceAllObjects=_ft;Ft.replaceAllRules=Hft;Ft.replaceAllSynonyms=jft;Ft.replaceDictionaryEntries=pft;Ft.restoreApiKey=hft;Ft.saveDictionaryEntries=gft;Ft.saveObject=Gft;Ft.saveObjects=t9;Ft.saveRule=qft;Ft.saveRules=r9;Ft.saveSynonym=Wft;Ft.saveSynonyms=n9;Ft.search=IIe;Ft.searchDictionaryEntries=dft;Ft.searchForFacetValues=CIe;Ft.searchRules=wIe;Ft.searchSynonyms=BIe;Ft.searchUserIDs=mft;Ft.setDictionarySettings=yft;Ft.setSettings=Yft;Ft.updateApiKey=Eft;Ft.waitAppTask=aw;Ft.waitTask=hs});var DIe=_((yJt,SIe)=>{SIe.exports=vIe()});var PIe=_(gF=>{\"use strict\";Object.defineProperty(gF,\"__esModule\",{value:!0});function zft(){return{debug(t,e){return Promise.resolve()},info(t,e){return Promise.resolve()},error(t,e){return Promise.resolve()}}}var Zft={Debug:1,Info:2,Error:3};gF.LogLevelEnum=Zft;gF.createNullLogger=zft});var xIe=_((IJt,bIe)=>{bIe.exports=PIe()});var TIe=_(i9=>{\"use strict\";Object.defineProperty(i9,\"__esModule\",{value:!0});var kIe=Ie(\"http\"),QIe=Ie(\"https\"),Xft=Ie(\"url\"),RIe={keepAlive:!0},$ft=new kIe.Agent(RIe),eAt=new QIe.Agent(RIe);function tAt({agent:t,httpAgent:e,httpsAgent:r,requesterOptions:s={}}={}){let a=e||t||$ft,n=r||t||eAt;return{send(c){return new Promise(f=>{let p=Xft.parse(c.url),h=p.query===null?p.pathname:`${p.pathname}?${p.query}`,E={...s,agent:p.protocol===\"https:\"?n:a,hostname:p.hostname,path:h,method:c.method,headers:{...s&&s.headers?s.headers:{},...c.headers},...p.port!==void 0?{port:p.port||\"\"}:{}},C=(p.protocol===\"https:\"?QIe:kIe).request(E,T=>{let N=[];T.on(\"data\",U=>{N=N.concat(U)}),T.on(\"end\",()=>{clearTimeout(b),clearTimeout(I),f({status:T.statusCode||0,content:Buffer.concat(N).toString(),isTimedOut:!1})})}),S=(T,N)=>setTimeout(()=>{C.abort(),f({status:0,content:N,isTimedOut:!0})},T*1e3),b=S(c.connectTimeout,\"Connection timeout\"),I;C.on(\"error\",T=>{clearTimeout(b),clearTimeout(I),f({status:0,content:T.message,isTimedOut:!1})}),C.once(\"response\",()=>{clearTimeout(b),I=S(c.responseTimeout,\"Socket timeout\")}),c.data!==void 0&&C.write(c.data),C.end()})},destroy(){return a.destroy(),n.destroy(),Promise.resolve()}}}i9.createNodeHttpRequester=tAt});var NIe=_((wJt,FIe)=>{FIe.exports=TIe()});var UIe=_((BJt,MIe)=>{\"use strict\";var OIe=TEe(),rAt=OEe(),lw=oIe(),o9=vS(),s9=uIe(),Gt=DIe(),nAt=xIe(),iAt=NIe(),sAt=PS();function LIe(t,e,r){let s={appId:t,apiKey:e,timeouts:{connect:2,read:5,write:30},requester:iAt.createNodeHttpRequester(),logger:nAt.createNullLogger(),responsesCache:OIe.createNullCache(),requestsCache:OIe.createNullCache(),hostsCache:rAt.createInMemoryCache(),userAgent:sAt.createUserAgent(o9.version).add({segment:\"Node.js\",version:process.versions.node})},a={...s,...r},n=()=>c=>s9.createPersonalizationClient({...s,...c,methods:{getPersonalizationStrategy:s9.getPersonalizationStrategy,setPersonalizationStrategy:s9.setPersonalizationStrategy}});return Gt.createSearchClient({...a,methods:{search:Gt.multipleQueries,searchForFacetValues:Gt.multipleSearchForFacetValues,multipleBatch:Gt.multipleBatch,multipleGetObjects:Gt.multipleGetObjects,multipleQueries:Gt.multipleQueries,copyIndex:Gt.copyIndex,copySettings:Gt.copySettings,copyRules:Gt.copyRules,copySynonyms:Gt.copySynonyms,moveIndex:Gt.moveIndex,listIndices:Gt.listIndices,getLogs:Gt.getLogs,listClusters:Gt.listClusters,multipleSearchForFacetValues:Gt.multipleSearchForFacetValues,getApiKey:Gt.getApiKey,addApiKey:Gt.addApiKey,listApiKeys:Gt.listApiKeys,updateApiKey:Gt.updateApiKey,deleteApiKey:Gt.deleteApiKey,restoreApiKey:Gt.restoreApiKey,assignUserID:Gt.assignUserID,assignUserIDs:Gt.assignUserIDs,getUserID:Gt.getUserID,searchUserIDs:Gt.searchUserIDs,listUserIDs:Gt.listUserIDs,getTopUserIDs:Gt.getTopUserIDs,removeUserID:Gt.removeUserID,hasPendingMappings:Gt.hasPendingMappings,generateSecuredApiKey:Gt.generateSecuredApiKey,getSecuredApiKeyRemainingValidity:Gt.getSecuredApiKeyRemainingValidity,destroy:o9.destroy,clearDictionaryEntries:Gt.clearDictionaryEntries,deleteDictionaryEntries:Gt.deleteDictionaryEntries,getDictionarySettings:Gt.getDictionarySettings,getAppTask:Gt.getAppTask,replaceDictionaryEntries:Gt.replaceDictionaryEntries,saveDictionaryEntries:Gt.saveDictionaryEntries,searchDictionaryEntries:Gt.searchDictionaryEntries,setDictionarySettings:Gt.setDictionarySettings,waitAppTask:Gt.waitAppTask,customRequest:Gt.customRequest,initIndex:c=>f=>Gt.initIndex(c)(f,{methods:{batch:Gt.batch,delete:Gt.deleteIndex,findAnswers:Gt.findAnswers,getObject:Gt.getObject,getObjects:Gt.getObjects,saveObject:Gt.saveObject,saveObjects:Gt.saveObjects,search:Gt.search,searchForFacetValues:Gt.searchForFacetValues,waitTask:Gt.waitTask,setSettings:Gt.setSettings,getSettings:Gt.getSettings,partialUpdateObject:Gt.partialUpdateObject,partialUpdateObjects:Gt.partialUpdateObjects,deleteObject:Gt.deleteObject,deleteObjects:Gt.deleteObjects,deleteBy:Gt.deleteBy,clearObjects:Gt.clearObjects,browseObjects:Gt.browseObjects,getObjectPosition:Gt.getObjectPosition,findObject:Gt.findObject,exists:Gt.exists,saveSynonym:Gt.saveSynonym,saveSynonyms:Gt.saveSynonyms,getSynonym:Gt.getSynonym,searchSynonyms:Gt.searchSynonyms,browseSynonyms:Gt.browseSynonyms,deleteSynonym:Gt.deleteSynonym,clearSynonyms:Gt.clearSynonyms,replaceAllObjects:Gt.replaceAllObjects,replaceAllSynonyms:Gt.replaceAllSynonyms,searchRules:Gt.searchRules,getRule:Gt.getRule,deleteRule:Gt.deleteRule,saveRule:Gt.saveRule,saveRules:Gt.saveRules,replaceAllRules:Gt.replaceAllRules,browseRules:Gt.browseRules,clearRules:Gt.clearRules}}),initAnalytics:()=>c=>lw.createAnalyticsClient({...s,...c,methods:{addABTest:lw.addABTest,getABTest:lw.getABTest,getABTests:lw.getABTests,stopABTest:lw.stopABTest,deleteABTest:lw.deleteABTest}}),initPersonalization:n,initRecommendation:()=>c=>(a.logger.info(\"The `initRecommendation` method is deprecated. Use `initPersonalization` instead.\"),n()(c))}})}LIe.version=o9.version;MIe.exports=LIe});var l9=_((vJt,a9)=>{var _Ie=UIe();a9.exports=_Ie;a9.exports.default=_Ie});var f9=_((DJt,GIe)=>{\"use strict\";var jIe=Object.getOwnPropertySymbols,aAt=Object.prototype.hasOwnProperty,lAt=Object.prototype.propertyIsEnumerable;function cAt(t){if(t==null)throw new TypeError(\"Object.assign cannot be called with null or undefined\");return Object(t)}function uAt(){try{if(!Object.assign)return!1;var t=new String(\"abc\");if(t[5]=\"de\",Object.getOwnPropertyNames(t)[0]===\"5\")return!1;for(var e={},r=0;r<10;r++)e[\"_\"+String.fromCharCode(r)]=r;var s=Object.getOwnPropertyNames(e).map(function(n){return e[n]});if(s.join(\"\")!==\"0123456789\")return!1;var a={};return\"abcdefghijklmnopqrst\".split(\"\").forEach(function(n){a[n]=n}),Object.keys(Object.assign({},a)).join(\"\")===\"abcdefghijklmnopqrst\"}catch{return!1}}GIe.exports=uAt()?Object.assign:function(t,e){for(var r,s=cAt(t),a,n=1;n<arguments.length;n++){r=Object(arguments[n]);for(var c in r)aAt.call(r,c)&&(s[c]=r[c]);if(jIe){a=jIe(r);for(var f=0;f<a.length;f++)lAt.call(r,a[f])&&(s[a[f]]=r[a[f]])}}return s}});var sCe=_(Dn=>{\"use strict\";var p9=f9(),cw=60103,YIe=60106;Dn.Fragment=60107;Dn.StrictMode=60108;Dn.Profiler=60114;var VIe=60109,JIe=60110,KIe=60112;Dn.Suspense=60113;var zIe=60115,ZIe=60116;typeof Symbol==\"function\"&&Symbol.for&&(Gc=Symbol.for,cw=Gc(\"react.element\"),YIe=Gc(\"react.portal\"),Dn.Fragment=Gc(\"react.fragment\"),Dn.StrictMode=Gc(\"react.strict_mode\"),Dn.Profiler=Gc(\"react.profiler\"),VIe=Gc(\"react.provider\"),JIe=Gc(\"react.context\"),KIe=Gc(\"react.forward_ref\"),Dn.Suspense=Gc(\"react.suspense\"),zIe=Gc(\"react.memo\"),ZIe=Gc(\"react.lazy\"));var Gc,qIe=typeof Symbol==\"function\"&&Symbol.iterator;function fAt(t){return t===null||typeof t!=\"object\"?null:(t=qIe&&t[qIe]||t[\"@@iterator\"],typeof t==\"function\"?t:null)}function RS(t){for(var e=\"https://reactjs.org/docs/error-decoder.html?invariant=\"+t,r=1;r<arguments.length;r++)e+=\"&args[]=\"+encodeURIComponent(arguments[r]);return\"Minified React error #\"+t+\"; visit \"+e+\" for the full message or use the non-minified dev environment for full errors and additional helpful warnings.\"}var XIe={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},$Ie={};function uw(t,e,r){this.props=t,this.context=e,this.refs=$Ie,this.updater=r||XIe}uw.prototype.isReactComponent={};uw.prototype.setState=function(t,e){if(typeof t!=\"object\"&&typeof t!=\"function\"&&t!=null)throw Error(RS(85));this.updater.enqueueSetState(this,t,e,\"setState\")};uw.prototype.forceUpdate=function(t){this.updater.enqueueForceUpdate(this,t,\"forceUpdate\")};function eCe(){}eCe.prototype=uw.prototype;function h9(t,e,r){this.props=t,this.context=e,this.refs=$Ie,this.updater=r||XIe}var g9=h9.prototype=new eCe;g9.constructor=h9;p9(g9,uw.prototype);g9.isPureReactComponent=!0;var d9={current:null},tCe=Object.prototype.hasOwnProperty,rCe={key:!0,ref:!0,__self:!0,__source:!0};function nCe(t,e,r){var s,a={},n=null,c=null;if(e!=null)for(s in e.ref!==void 0&&(c=e.ref),e.key!==void 0&&(n=\"\"+e.key),e)tCe.call(e,s)&&!rCe.hasOwnProperty(s)&&(a[s]=e[s]);var f=arguments.length-2;if(f===1)a.children=r;else if(1<f){for(var p=Array(f),h=0;h<f;h++)p[h]=arguments[h+2];a.children=p}if(t&&t.defaultProps)for(s in f=t.defaultProps,f)a[s]===void 0&&(a[s]=f[s]);return{$$typeof:cw,type:t,key:n,ref:c,props:a,_owner:d9.current}}function AAt(t,e){return{$$typeof:cw,type:t.type,key:e,ref:t.ref,props:t.props,_owner:t._owner}}function m9(t){return typeof t==\"object\"&&t!==null&&t.$$typeof===cw}function pAt(t){var e={\"=\":\"=0\",\":\":\"=2\"};return\"$\"+t.replace(/[=:]/g,function(r){return e[r]})}var WIe=/\\/+/g;function A9(t,e){return typeof t==\"object\"&&t!==null&&t.key!=null?pAt(\"\"+t.key):e.toString(36)}function mF(t,e,r,s,a){var n=typeof t;(n===\"undefined\"||n===\"boolean\")&&(t=null);var c=!1;if(t===null)c=!0;else switch(n){case\"string\":case\"number\":c=!0;break;case\"object\":switch(t.$$typeof){case cw:case YIe:c=!0}}if(c)return c=t,a=a(c),t=s===\"\"?\".\"+A9(c,0):s,Array.isArray(a)?(r=\"\",t!=null&&(r=t.replace(WIe,\"$&/\")+\"/\"),mF(a,e,r,\"\",function(h){return h})):a!=null&&(m9(a)&&(a=AAt(a,r+(!a.key||c&&c.key===a.key?\"\":(\"\"+a.key).replace(WIe,\"$&/\")+\"/\")+t)),e.push(a)),1;if(c=0,s=s===\"\"?\".\":s+\":\",Array.isArray(t))for(var f=0;f<t.length;f++){n=t[f];var p=s+A9(n,f);c+=mF(n,e,r,p,a)}else if(p=fAt(t),typeof p==\"function\")for(t=p.call(t),f=0;!(n=t.next()).done;)n=n.value,p=s+A9(n,f++),c+=mF(n,e,r,p,a);else if(n===\"object\")throw e=\"\"+t,Error(RS(31,e===\"[object Object]\"?\"object with keys {\"+Object.keys(t).join(\", \")+\"}\":e));return c}function dF(t,e,r){if(t==null)return t;var s=[],a=0;return mF(t,s,\"\",\"\",function(n){return e.call(r,n,a++)}),s}function hAt(t){if(t._status===-1){var e=t._result;e=e(),t._status=0,t._result=e,e.then(function(r){t._status===0&&(r=r.default,t._status=1,t._result=r)},function(r){t._status===0&&(t._status=2,t._result=r)})}if(t._status===1)return t._result;throw t._result}var iCe={current:null};function Xp(){var t=iCe.current;if(t===null)throw Error(RS(321));return t}var gAt={ReactCurrentDispatcher:iCe,ReactCurrentBatchConfig:{transition:0},ReactCurrentOwner:d9,IsSomeRendererActing:{current:!1},assign:p9};Dn.Children={map:dF,forEach:function(t,e,r){dF(t,function(){e.apply(this,arguments)},r)},count:function(t){var e=0;return dF(t,function(){e++}),e},toArray:function(t){return dF(t,function(e){return e})||[]},only:function(t){if(!m9(t))throw Error(RS(143));return t}};Dn.Component=uw;Dn.PureComponent=h9;Dn.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=gAt;Dn.cloneElement=function(t,e,r){if(t==null)throw Error(RS(267,t));var s=p9({},t.props),a=t.key,n=t.ref,c=t._owner;if(e!=null){if(e.ref!==void 0&&(n=e.ref,c=d9.current),e.key!==void 0&&(a=\"\"+e.key),t.type&&t.type.defaultProps)var f=t.type.defaultProps;for(p in e)tCe.call(e,p)&&!rCe.hasOwnProperty(p)&&(s[p]=e[p]===void 0&&f!==void 0?f[p]:e[p])}var p=arguments.length-2;if(p===1)s.children=r;else if(1<p){f=Array(p);for(var h=0;h<p;h++)f[h]=arguments[h+2];s.children=f}return{$$typeof:cw,type:t.type,key:a,ref:n,props:s,_owner:c}};Dn.createContext=function(t,e){return e===void 0&&(e=null),t={$$typeof:JIe,_calculateChangedBits:e,_currentValue:t,_currentValue2:t,_threadCount:0,Provider:null,Consumer:null},t.Provider={$$typeof:VIe,_context:t},t.Consumer=t};Dn.createElement=nCe;Dn.createFactory=function(t){var e=nCe.bind(null,t);return e.type=t,e};Dn.createRef=function(){return{current:null}};Dn.forwardRef=function(t){return{$$typeof:KIe,render:t}};Dn.isValidElement=m9;Dn.lazy=function(t){return{$$typeof:ZIe,_payload:{_status:-1,_result:t},_init:hAt}};Dn.memo=function(t,e){return{$$typeof:zIe,type:t,compare:e===void 0?null:e}};Dn.useCallback=function(t,e){return Xp().useCallback(t,e)};Dn.useContext=function(t,e){return Xp().useContext(t,e)};Dn.useDebugValue=function(){};Dn.useEffect=function(t,e){return Xp().useEffect(t,e)};Dn.useImperativeHandle=function(t,e,r){return Xp().useImperativeHandle(t,e,r)};Dn.useLayoutEffect=function(t,e){return Xp().useLayoutEffect(t,e)};Dn.useMemo=function(t,e){return Xp().useMemo(t,e)};Dn.useReducer=function(t,e,r){return Xp().useReducer(t,e,r)};Dn.useRef=function(t){return Xp().useRef(t)};Dn.useState=function(t){return Xp().useState(t)};Dn.version=\"17.0.2\"});var hn=_((bJt,oCe)=>{\"use strict\";oCe.exports=sCe()});var yF=_((xJt,aCe)=>{function dAt(t){var e=typeof t;return t!=null&&(e==\"object\"||e==\"function\")}aCe.exports=dAt});var cCe=_((kJt,lCe)=>{var mAt=typeof global==\"object\"&&global&&global.Object===Object&&global;lCe.exports=mAt});var y9=_((QJt,uCe)=>{var yAt=cCe(),EAt=typeof self==\"object\"&&self&&self.Object===Object&&self,IAt=yAt||EAt||Function(\"return this\")();uCe.exports=IAt});var ACe=_((RJt,fCe)=>{var CAt=y9(),wAt=function(){return CAt.Date.now()};fCe.exports=wAt});var hCe=_((TJt,pCe)=>{var BAt=/\\s/;function vAt(t){for(var e=t.length;e--&&BAt.test(t.charAt(e)););return e}pCe.exports=vAt});var dCe=_((FJt,gCe)=>{var SAt=hCe(),DAt=/^\\s+/;function PAt(t){return t&&t.slice(0,SAt(t)+1).replace(DAt,\"\")}gCe.exports=PAt});var E9=_((NJt,mCe)=>{var bAt=y9(),xAt=bAt.Symbol;mCe.exports=xAt});var CCe=_((OJt,ICe)=>{var yCe=E9(),ECe=Object.prototype,kAt=ECe.hasOwnProperty,QAt=ECe.toString,TS=yCe?yCe.toStringTag:void 0;function RAt(t){var e=kAt.call(t,TS),r=t[TS];try{t[TS]=void 0;var s=!0}catch{}var a=QAt.call(t);return s&&(e?t[TS]=r:delete t[TS]),a}ICe.exports=RAt});var BCe=_((LJt,wCe)=>{var TAt=Object.prototype,FAt=TAt.toString;function NAt(t){return FAt.call(t)}wCe.exports=NAt});var PCe=_((MJt,DCe)=>{var vCe=E9(),OAt=CCe(),LAt=BCe(),MAt=\"[object Null]\",UAt=\"[object Undefined]\",SCe=vCe?vCe.toStringTag:void 0;function _At(t){return t==null?t===void 0?UAt:MAt:SCe&&SCe in Object(t)?OAt(t):LAt(t)}DCe.exports=_At});var xCe=_((UJt,bCe)=>{function HAt(t){return t!=null&&typeof t==\"object\"}bCe.exports=HAt});var QCe=_((_Jt,kCe)=>{var jAt=PCe(),GAt=xCe(),qAt=\"[object Symbol]\";function WAt(t){return typeof t==\"symbol\"||GAt(t)&&jAt(t)==qAt}kCe.exports=WAt});var NCe=_((HJt,FCe)=>{var YAt=dCe(),RCe=yF(),VAt=QCe(),TCe=NaN,JAt=/^[-+]0x[0-9a-f]+$/i,KAt=/^0b[01]+$/i,zAt=/^0o[0-7]+$/i,ZAt=parseInt;function XAt(t){if(typeof t==\"number\")return t;if(VAt(t))return TCe;if(RCe(t)){var e=typeof t.valueOf==\"function\"?t.valueOf():t;t=RCe(e)?e+\"\":e}if(typeof t!=\"string\")return t===0?t:+t;t=YAt(t);var r=KAt.test(t);return r||zAt.test(t)?ZAt(t.slice(2),r?2:8):JAt.test(t)?TCe:+t}FCe.exports=XAt});var MCe=_((jJt,LCe)=>{var $At=yF(),I9=ACe(),OCe=NCe(),ept=\"Expected a function\",tpt=Math.max,rpt=Math.min;function npt(t,e,r){var s,a,n,c,f,p,h=0,E=!1,C=!1,S=!0;if(typeof t!=\"function\")throw new TypeError(ept);e=OCe(e)||0,$At(r)&&(E=!!r.leading,C=\"maxWait\"in r,n=C?tpt(OCe(r.maxWait)||0,e):n,S=\"trailing\"in r?!!r.trailing:S);function b(le){var me=s,pe=a;return s=a=void 0,h=le,c=t.apply(pe,me),c}function I(le){return h=le,f=setTimeout(U,e),E?b(le):c}function T(le){var me=le-p,pe=le-h,Be=e-me;return C?rpt(Be,n-pe):Be}function N(le){var me=le-p,pe=le-h;return p===void 0||me>=e||me<0||C&&pe>=n}function U(){var le=I9();if(N(le))return W(le);f=setTimeout(U,T(le))}function W(le){return f=void 0,S&&s?b(le):(s=a=void 0,c)}function ee(){f!==void 0&&clearTimeout(f),h=0,s=p=a=f=void 0}function ie(){return f===void 0?c:W(I9())}function ue(){var le=I9(),me=N(le);if(s=arguments,a=this,p=le,me){if(f===void 0)return I(p);if(C)return clearTimeout(f),f=setTimeout(U,e),b(p)}return f===void 0&&(f=setTimeout(U,e)),c}return ue.cancel=ee,ue.flush=ie,ue}LCe.exports=npt});var _Ce=_((GJt,UCe)=>{var ipt=MCe(),spt=yF(),opt=\"Expected a function\";function apt(t,e,r){var s=!0,a=!0;if(typeof t!=\"function\")throw new TypeError(opt);return spt(r)&&(s=\"leading\"in r?!!r.leading:s,a=\"trailing\"in r?!!r.trailing:a),ipt(t,e,{leading:s,maxWait:e,trailing:a})}UCe.exports=apt});var w9=_((qJt,C9)=>{\"use strict\";var Cn=C9.exports;C9.exports.default=Cn;var Zn=\"\\x1B[\",NS=\"\\x1B]\",fw=\"\\x07\",EF=\";\",HCe=process.env.TERM_PROGRAM===\"Apple_Terminal\";Cn.cursorTo=(t,e)=>{if(typeof t!=\"number\")throw new TypeError(\"The `x` argument is required\");return typeof e!=\"number\"?Zn+(t+1)+\"G\":Zn+(e+1)+\";\"+(t+1)+\"H\"};Cn.cursorMove=(t,e)=>{if(typeof t!=\"number\")throw new TypeError(\"The `x` argument is required\");let r=\"\";return t<0?r+=Zn+-t+\"D\":t>0&&(r+=Zn+t+\"C\"),e<0?r+=Zn+-e+\"A\":e>0&&(r+=Zn+e+\"B\"),r};Cn.cursorUp=(t=1)=>Zn+t+\"A\";Cn.cursorDown=(t=1)=>Zn+t+\"B\";Cn.cursorForward=(t=1)=>Zn+t+\"C\";Cn.cursorBackward=(t=1)=>Zn+t+\"D\";Cn.cursorLeft=Zn+\"G\";Cn.cursorSavePosition=HCe?\"\\x1B7\":Zn+\"s\";Cn.cursorRestorePosition=HCe?\"\\x1B8\":Zn+\"u\";Cn.cursorGetPosition=Zn+\"6n\";Cn.cursorNextLine=Zn+\"E\";Cn.cursorPrevLine=Zn+\"F\";Cn.cursorHide=Zn+\"?25l\";Cn.cursorShow=Zn+\"?25h\";Cn.eraseLines=t=>{let e=\"\";for(let r=0;r<t;r++)e+=Cn.eraseLine+(r<t-1?Cn.cursorUp():\"\");return t&&(e+=Cn.cursorLeft),e};Cn.eraseEndLine=Zn+\"K\";Cn.eraseStartLine=Zn+\"1K\";Cn.eraseLine=Zn+\"2K\";Cn.eraseDown=Zn+\"J\";Cn.eraseUp=Zn+\"1J\";Cn.eraseScreen=Zn+\"2J\";Cn.scrollUp=Zn+\"S\";Cn.scrollDown=Zn+\"T\";Cn.clearScreen=\"\\x1Bc\";Cn.clearTerminal=process.platform===\"win32\"?`${Cn.eraseScreen}${Zn}0f`:`${Cn.eraseScreen}${Zn}3J${Zn}H`;Cn.beep=fw;Cn.link=(t,e)=>[NS,\"8\",EF,EF,e,fw,t,NS,\"8\",EF,EF,fw].join(\"\");Cn.image=(t,e={})=>{let r=`${NS}1337;File=inline=1`;return e.width&&(r+=`;width=${e.width}`),e.height&&(r+=`;height=${e.height}`),e.preserveAspectRatio===!1&&(r+=\";preserveAspectRatio=0\"),r+\":\"+t.toString(\"base64\")+fw};Cn.iTerm={setCwd:(t=process.cwd())=>`${NS}50;CurrentDir=${t}${fw}`,annotation:(t,e={})=>{let r=`${NS}1337;`,s=typeof e.x<\"u\",a=typeof e.y<\"u\";if((s||a)&&!(s&&a&&typeof e.length<\"u\"))throw new Error(\"`x`, `y` and `length` must be defined when `x` or `y` is defined\");return t=t.replace(/\\|/g,\"\"),r+=e.isHidden?\"AddHiddenAnnotation=\":\"AddAnnotation=\",e.length>0?r+=(s?[t,e.length,e.x,e.y]:[e.length,t]).join(\"|\"):r+=t,r+fw}}});var GCe=_((WJt,B9)=>{\"use strict\";var jCe=(t,e)=>{for(let r of Reflect.ownKeys(e))Object.defineProperty(t,r,Object.getOwnPropertyDescriptor(e,r));return t};B9.exports=jCe;B9.exports.default=jCe});var WCe=_((YJt,CF)=>{\"use strict\";var lpt=GCe(),IF=new WeakMap,qCe=(t,e={})=>{if(typeof t!=\"function\")throw new TypeError(\"Expected a function\");let r,s=0,a=t.displayName||t.name||\"<anonymous>\",n=function(...c){if(IF.set(n,++s),s===1)r=t.apply(this,c),t=null;else if(e.throw===!0)throw new Error(`Function \\`${a}\\` can only be called once`);return r};return lpt(n,t),IF.set(n,s),n};CF.exports=qCe;CF.exports.default=qCe;CF.exports.callCount=t=>{if(!IF.has(t))throw new Error(`The given function \\`${t.name}\\` is not wrapped by the \\`onetime\\` package`);return IF.get(t)}});var YCe=_((VJt,wF)=>{wF.exports=[\"SIGABRT\",\"SIGALRM\",\"SIGHUP\",\"SIGINT\",\"SIGTERM\"];process.platform!==\"win32\"&&wF.exports.push(\"SIGVTALRM\",\"SIGXCPU\",\"SIGXFSZ\",\"SIGUSR2\",\"SIGTRAP\",\"SIGSYS\",\"SIGQUIT\",\"SIGIOT\");process.platform===\"linux\"&&wF.exports.push(\"SIGIO\",\"SIGPOLL\",\"SIGPWR\",\"SIGSTKFLT\",\"SIGUNUSED\")});var D9=_((JJt,hw)=>{var Qi=global.process,Qm=function(t){return t&&typeof t==\"object\"&&typeof t.removeListener==\"function\"&&typeof t.emit==\"function\"&&typeof t.reallyExit==\"function\"&&typeof t.listeners==\"function\"&&typeof t.kill==\"function\"&&typeof t.pid==\"number\"&&typeof t.on==\"function\"};Qm(Qi)?(VCe=Ie(\"assert\"),Aw=YCe(),JCe=/^win/i.test(Qi.platform),OS=Ie(\"events\"),typeof OS!=\"function\"&&(OS=OS.EventEmitter),Qi.__signal_exit_emitter__?Js=Qi.__signal_exit_emitter__:(Js=Qi.__signal_exit_emitter__=new OS,Js.count=0,Js.emitted={}),Js.infinite||(Js.setMaxListeners(1/0),Js.infinite=!0),hw.exports=function(t,e){if(!Qm(global.process))return function(){};VCe.equal(typeof t,\"function\",\"a callback must be provided for exit handler\"),pw===!1&&v9();var r=\"exit\";e&&e.alwaysLast&&(r=\"afterexit\");var s=function(){Js.removeListener(r,t),Js.listeners(\"exit\").length===0&&Js.listeners(\"afterexit\").length===0&&BF()};return Js.on(r,t),s},BF=function(){!pw||!Qm(global.process)||(pw=!1,Aw.forEach(function(e){try{Qi.removeListener(e,vF[e])}catch{}}),Qi.emit=SF,Qi.reallyExit=S9,Js.count-=1)},hw.exports.unload=BF,Rm=function(e,r,s){Js.emitted[e]||(Js.emitted[e]=!0,Js.emit(e,r,s))},vF={},Aw.forEach(function(t){vF[t]=function(){if(Qm(global.process)){var r=Qi.listeners(t);r.length===Js.count&&(BF(),Rm(\"exit\",null,t),Rm(\"afterexit\",null,t),JCe&&t===\"SIGHUP\"&&(t=\"SIGINT\"),Qi.kill(Qi.pid,t))}}}),hw.exports.signals=function(){return Aw},pw=!1,v9=function(){pw||!Qm(global.process)||(pw=!0,Js.count+=1,Aw=Aw.filter(function(e){try{return Qi.on(e,vF[e]),!0}catch{return!1}}),Qi.emit=zCe,Qi.reallyExit=KCe)},hw.exports.load=v9,S9=Qi.reallyExit,KCe=function(e){Qm(global.process)&&(Qi.exitCode=e||0,Rm(\"exit\",Qi.exitCode,null),Rm(\"afterexit\",Qi.exitCode,null),S9.call(Qi,Qi.exitCode))},SF=Qi.emit,zCe=function(e,r){if(e===\"exit\"&&Qm(global.process)){r!==void 0&&(Qi.exitCode=r);var s=SF.apply(this,arguments);return Rm(\"exit\",Qi.exitCode,null),Rm(\"afterexit\",Qi.exitCode,null),s}else return SF.apply(this,arguments)}):hw.exports=function(){return function(){}};var VCe,Aw,JCe,OS,Js,BF,Rm,vF,pw,v9,S9,KCe,SF,zCe});var XCe=_((KJt,ZCe)=>{\"use strict\";var cpt=WCe(),upt=D9();ZCe.exports=cpt(()=>{upt(()=>{process.stderr.write(\"\\x1B[?25h\")},{alwaysLast:!0})})});var P9=_(gw=>{\"use strict\";var fpt=XCe(),DF=!1;gw.show=(t=process.stderr)=>{t.isTTY&&(DF=!1,t.write(\"\\x1B[?25h\"))};gw.hide=(t=process.stderr)=>{t.isTTY&&(fpt(),DF=!0,t.write(\"\\x1B[?25l\"))};gw.toggle=(t,e)=>{t!==void 0&&(DF=t),DF?gw.show(e):gw.hide(e)}});var rwe=_(LS=>{\"use strict\";var twe=LS&&LS.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(LS,\"__esModule\",{value:!0});var $Ce=twe(w9()),ewe=twe(P9()),Apt=(t,{showCursor:e=!1}={})=>{let r=0,s=\"\",a=!1,n=c=>{!e&&!a&&(ewe.default.hide(),a=!0);let f=c+`\n`;f!==s&&(s=f,t.write($Ce.default.eraseLines(r)+f),r=f.split(`\n`).length)};return n.clear=()=>{t.write($Ce.default.eraseLines(r)),s=\"\",r=0},n.done=()=>{s=\"\",r=0,e||(ewe.default.show(),a=!1)},n};LS.default={create:Apt}});var nwe=_((XJt,ppt)=>{ppt.exports=[{name:\"AppVeyor\",constant:\"APPVEYOR\",env:\"APPVEYOR\",pr:\"APPVEYOR_PULL_REQUEST_NUMBER\"},{name:\"Azure Pipelines\",constant:\"AZURE_PIPELINES\",env:\"SYSTEM_TEAMFOUNDATIONCOLLECTIONURI\",pr:\"SYSTEM_PULLREQUEST_PULLREQUESTID\"},{name:\"Bamboo\",constant:\"BAMBOO\",env:\"bamboo_planKey\"},{name:\"Bitbucket Pipelines\",constant:\"BITBUCKET\",env:\"BITBUCKET_COMMIT\",pr:\"BITBUCKET_PR_ID\"},{name:\"Bitrise\",constant:\"BITRISE\",env:\"BITRISE_IO\",pr:\"BITRISE_PULL_REQUEST\"},{name:\"Buddy\",constant:\"BUDDY\",env:\"BUDDY_WORKSPACE_ID\",pr:\"BUDDY_EXECUTION_PULL_REQUEST_ID\"},{name:\"Buildkite\",constant:\"BUILDKITE\",env:\"BUILDKITE\",pr:{env:\"BUILDKITE_PULL_REQUEST\",ne:\"false\"}},{name:\"CircleCI\",constant:\"CIRCLE\",env:\"CIRCLECI\",pr:\"CIRCLE_PULL_REQUEST\"},{name:\"Cirrus CI\",constant:\"CIRRUS\",env:\"CIRRUS_CI\",pr:\"CIRRUS_PR\"},{name:\"AWS CodeBuild\",constant:\"CODEBUILD\",env:\"CODEBUILD_BUILD_ARN\"},{name:\"Codeship\",constant:\"CODESHIP\",env:{CI_NAME:\"codeship\"}},{name:\"Drone\",constant:\"DRONE\",env:\"DRONE\",pr:{DRONE_BUILD_EVENT:\"pull_request\"}},{name:\"dsari\",constant:\"DSARI\",env:\"DSARI\"},{name:\"GitLab CI\",constant:\"GITLAB\",env:\"GITLAB_CI\"},{name:\"GoCD\",constant:\"GOCD\",env:\"GO_PIPELINE_LABEL\"},{name:\"Hudson\",constant:\"HUDSON\",env:\"HUDSON_URL\"},{name:\"Jenkins\",constant:\"JENKINS\",env:[\"JENKINS_URL\",\"BUILD_ID\"],pr:{any:[\"ghprbPullId\",\"CHANGE_ID\"]}},{name:\"Magnum CI\",constant:\"MAGNUM\",env:\"MAGNUM\"},{name:\"Netlify CI\",constant:\"NETLIFY\",env:\"NETLIFY_BUILD_BASE\",pr:{env:\"PULL_REQUEST\",ne:\"false\"}},{name:\"Sail CI\",constant:\"SAIL\",env:\"SAILCI\",pr:\"SAIL_PULL_REQUEST_NUMBER\"},{name:\"Semaphore\",constant:\"SEMAPHORE\",env:\"SEMAPHORE\",pr:\"PULL_REQUEST_NUMBER\"},{name:\"Shippable\",constant:\"SHIPPABLE\",env:\"SHIPPABLE\",pr:{IS_PULL_REQUEST:\"true\"}},{name:\"Solano CI\",constant:\"SOLANO\",env:\"TDDIUM\",pr:\"TDDIUM_PR_ID\"},{name:\"Strider CD\",constant:\"STRIDER\",env:\"STRIDER\"},{name:\"TaskCluster\",constant:\"TASKCLUSTER\",env:[\"TASK_ID\",\"RUN_ID\"]},{name:\"TeamCity\",constant:\"TEAMCITY\",env:\"TEAMCITY_VERSION\"},{name:\"Travis CI\",constant:\"TRAVIS\",env:\"TRAVIS\",pr:{env:\"TRAVIS_PULL_REQUEST\",ne:\"false\"}}]});var owe=_(tc=>{\"use strict\";var swe=nwe(),uA=process.env;Object.defineProperty(tc,\"_vendors\",{value:swe.map(function(t){return t.constant})});tc.name=null;tc.isPR=null;swe.forEach(function(t){var e=Array.isArray(t.env)?t.env:[t.env],r=e.every(function(s){return iwe(s)});if(tc[t.constant]=r,r)switch(tc.name=t.name,typeof t.pr){case\"string\":tc.isPR=!!uA[t.pr];break;case\"object\":\"env\"in t.pr?tc.isPR=t.pr.env in uA&&uA[t.pr.env]!==t.pr.ne:\"any\"in t.pr?tc.isPR=t.pr.any.some(function(s){return!!uA[s]}):tc.isPR=iwe(t.pr);break;default:tc.isPR=null}});tc.isCI=!!(uA.CI||uA.CONTINUOUS_INTEGRATION||uA.BUILD_NUMBER||uA.RUN_ID||tc.name);function iwe(t){return typeof t==\"string\"?!!uA[t]:Object.keys(t).every(function(e){return uA[e]===t[e]})}});var lwe=_((eKt,awe)=>{\"use strict\";awe.exports=owe().isCI});var uwe=_((tKt,cwe)=>{\"use strict\";var hpt=t=>{let e=new Set;do for(let r of Reflect.ownKeys(t))e.add([t,r]);while((t=Reflect.getPrototypeOf(t))&&t!==Object.prototype);return e};cwe.exports=(t,{include:e,exclude:r}={})=>{let s=a=>{let n=c=>typeof c==\"string\"?a===c:c.test(a);return e?e.some(n):r?!r.some(n):!0};for(let[a,n]of hpt(t.constructor.prototype)){if(n===\"constructor\"||!s(n))continue;let c=Reflect.getOwnPropertyDescriptor(a,n);c&&typeof c.value==\"function\"&&(t[n]=t[n].bind(t))}return t}});var dwe=_(Vn=>{\"use strict\";var mw,_S,kF,F9;typeof performance==\"object\"&&typeof performance.now==\"function\"?(fwe=performance,Vn.unstable_now=function(){return fwe.now()}):(b9=Date,Awe=b9.now(),Vn.unstable_now=function(){return b9.now()-Awe});var fwe,b9,Awe;typeof window>\"u\"||typeof MessageChannel!=\"function\"?(dw=null,x9=null,k9=function(){if(dw!==null)try{var t=Vn.unstable_now();dw(!0,t),dw=null}catch(e){throw setTimeout(k9,0),e}},mw=function(t){dw!==null?setTimeout(mw,0,t):(dw=t,setTimeout(k9,0))},_S=function(t,e){x9=setTimeout(t,e)},kF=function(){clearTimeout(x9)},Vn.unstable_shouldYield=function(){return!1},F9=Vn.unstable_forceFrameRate=function(){}):(pwe=window.setTimeout,hwe=window.clearTimeout,typeof console<\"u\"&&(gwe=window.cancelAnimationFrame,typeof window.requestAnimationFrame!=\"function\"&&console.error(\"This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills\"),typeof gwe!=\"function\"&&console.error(\"This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills\")),MS=!1,US=null,PF=-1,Q9=5,R9=0,Vn.unstable_shouldYield=function(){return Vn.unstable_now()>=R9},F9=function(){},Vn.unstable_forceFrameRate=function(t){0>t||125<t?console.error(\"forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported\"):Q9=0<t?Math.floor(1e3/t):5},T9=new MessageChannel,bF=T9.port2,T9.port1.onmessage=function(){if(US!==null){var t=Vn.unstable_now();R9=t+Q9;try{US(!0,t)?bF.postMessage(null):(MS=!1,US=null)}catch(e){throw bF.postMessage(null),e}}else MS=!1},mw=function(t){US=t,MS||(MS=!0,bF.postMessage(null))},_S=function(t,e){PF=pwe(function(){t(Vn.unstable_now())},e)},kF=function(){hwe(PF),PF=-1});var dw,x9,k9,pwe,hwe,gwe,MS,US,PF,Q9,R9,T9,bF;function N9(t,e){var r=t.length;t.push(e);e:for(;;){var s=r-1>>>1,a=t[s];if(a!==void 0&&0<xF(a,e))t[s]=e,t[r]=a,r=s;else break e}}function ef(t){return t=t[0],t===void 0?null:t}function QF(t){var e=t[0];if(e!==void 0){var r=t.pop();if(r!==e){t[0]=r;e:for(var s=0,a=t.length;s<a;){var n=2*(s+1)-1,c=t[n],f=n+1,p=t[f];if(c!==void 0&&0>xF(c,r))p!==void 0&&0>xF(p,c)?(t[s]=p,t[f]=r,s=f):(t[s]=c,t[n]=r,s=n);else if(p!==void 0&&0>xF(p,r))t[s]=p,t[f]=r,s=f;else break e}}return e}return null}function xF(t,e){var r=t.sortIndex-e.sortIndex;return r!==0?r:t.id-e.id}var fA=[],X0=[],gpt=1,qc=null,$o=3,RF=!1,Tm=!1,HS=!1;function O9(t){for(var e=ef(X0);e!==null;){if(e.callback===null)QF(X0);else if(e.startTime<=t)QF(X0),e.sortIndex=e.expirationTime,N9(fA,e);else break;e=ef(X0)}}function L9(t){if(HS=!1,O9(t),!Tm)if(ef(fA)!==null)Tm=!0,mw(M9);else{var e=ef(X0);e!==null&&_S(L9,e.startTime-t)}}function M9(t,e){Tm=!1,HS&&(HS=!1,kF()),RF=!0;var r=$o;try{for(O9(e),qc=ef(fA);qc!==null&&(!(qc.expirationTime>e)||t&&!Vn.unstable_shouldYield());){var s=qc.callback;if(typeof s==\"function\"){qc.callback=null,$o=qc.priorityLevel;var a=s(qc.expirationTime<=e);e=Vn.unstable_now(),typeof a==\"function\"?qc.callback=a:qc===ef(fA)&&QF(fA),O9(e)}else QF(fA);qc=ef(fA)}if(qc!==null)var n=!0;else{var c=ef(X0);c!==null&&_S(L9,c.startTime-e),n=!1}return n}finally{qc=null,$o=r,RF=!1}}var dpt=F9;Vn.unstable_IdlePriority=5;Vn.unstable_ImmediatePriority=1;Vn.unstable_LowPriority=4;Vn.unstable_NormalPriority=3;Vn.unstable_Profiling=null;Vn.unstable_UserBlockingPriority=2;Vn.unstable_cancelCallback=function(t){t.callback=null};Vn.unstable_continueExecution=function(){Tm||RF||(Tm=!0,mw(M9))};Vn.unstable_getCurrentPriorityLevel=function(){return $o};Vn.unstable_getFirstCallbackNode=function(){return ef(fA)};Vn.unstable_next=function(t){switch($o){case 1:case 2:case 3:var e=3;break;default:e=$o}var r=$o;$o=e;try{return t()}finally{$o=r}};Vn.unstable_pauseExecution=function(){};Vn.unstable_requestPaint=dpt;Vn.unstable_runWithPriority=function(t,e){switch(t){case 1:case 2:case 3:case 4:case 5:break;default:t=3}var r=$o;$o=t;try{return e()}finally{$o=r}};Vn.unstable_scheduleCallback=function(t,e,r){var s=Vn.unstable_now();switch(typeof r==\"object\"&&r!==null?(r=r.delay,r=typeof r==\"number\"&&0<r?s+r:s):r=s,t){case 1:var a=-1;break;case 2:a=250;break;case 5:a=1073741823;break;case 4:a=1e4;break;default:a=5e3}return a=r+a,t={id:gpt++,callback:e,priorityLevel:t,startTime:r,expirationTime:a,sortIndex:-1},r>s?(t.sortIndex=r,N9(X0,t),ef(fA)===null&&t===ef(X0)&&(HS?kF():HS=!0,_S(L9,r-s))):(t.sortIndex=a,N9(fA,t),Tm||RF||(Tm=!0,mw(M9))),t};Vn.unstable_wrapCallback=function(t){var e=$o;return function(){var r=$o;$o=e;try{return t.apply(this,arguments)}finally{$o=r}}}});var U9=_((nKt,mwe)=>{\"use strict\";mwe.exports=dwe()});var ywe=_((iKt,jS)=>{jS.exports=function(e){var r={},s=f9(),a=hn(),n=U9();function c(v){for(var D=\"https://reactjs.org/docs/error-decoder.html?invariant=\"+v,Q=1;Q<arguments.length;Q++)D+=\"&args[]=\"+encodeURIComponent(arguments[Q]);return\"Minified React error #\"+v+\"; visit \"+D+\" for the full message or use the non-minified dev environment for full errors and additional helpful warnings.\"}var f=a.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,p=60103,h=60106,E=60107,C=60108,S=60114,b=60109,I=60110,T=60112,N=60113,U=60120,W=60115,ee=60116,ie=60121,ue=60129,le=60130,me=60131;if(typeof Symbol==\"function\"&&Symbol.for){var pe=Symbol.for;p=pe(\"react.element\"),h=pe(\"react.portal\"),E=pe(\"react.fragment\"),C=pe(\"react.strict_mode\"),S=pe(\"react.profiler\"),b=pe(\"react.provider\"),I=pe(\"react.context\"),T=pe(\"react.forward_ref\"),N=pe(\"react.suspense\"),U=pe(\"react.suspense_list\"),W=pe(\"react.memo\"),ee=pe(\"react.lazy\"),ie=pe(\"react.block\"),pe(\"react.scope\"),ue=pe(\"react.debug_trace_mode\"),le=pe(\"react.offscreen\"),me=pe(\"react.legacy_hidden\")}var Be=typeof Symbol==\"function\"&&Symbol.iterator;function Ce(v){return v===null||typeof v!=\"object\"?null:(v=Be&&v[Be]||v[\"@@iterator\"],typeof v==\"function\"?v:null)}function g(v){if(v==null)return null;if(typeof v==\"function\")return v.displayName||v.name||null;if(typeof v==\"string\")return v;switch(v){case E:return\"Fragment\";case h:return\"Portal\";case S:return\"Profiler\";case C:return\"StrictMode\";case N:return\"Suspense\";case U:return\"SuspenseList\"}if(typeof v==\"object\")switch(v.$$typeof){case I:return(v.displayName||\"Context\")+\".Consumer\";case b:return(v._context.displayName||\"Context\")+\".Provider\";case T:var D=v.render;return D=D.displayName||D.name||\"\",v.displayName||(D!==\"\"?\"ForwardRef(\"+D+\")\":\"ForwardRef\");case W:return g(v.type);case ie:return g(v._render);case ee:D=v._payload,v=v._init;try{return g(v(D))}catch{}}return null}function we(v){var D=v,Q=v;if(v.alternate)for(;D.return;)D=D.return;else{v=D;do D=v,D.flags&1026&&(Q=D.return),v=D.return;while(v)}return D.tag===3?Q:null}function ye(v){if(we(v)!==v)throw Error(c(188))}function Ae(v){var D=v.alternate;if(!D){if(D=we(v),D===null)throw Error(c(188));return D!==v?null:v}for(var Q=v,H=D;;){var V=Q.return;if(V===null)break;var ne=V.alternate;if(ne===null){if(H=V.return,H!==null){Q=H;continue}break}if(V.child===ne.child){for(ne=V.child;ne;){if(ne===Q)return ye(V),v;if(ne===H)return ye(V),D;ne=ne.sibling}throw Error(c(188))}if(Q.return!==H.return)Q=V,H=ne;else{for(var Se=!1,_e=V.child;_e;){if(_e===Q){Se=!0,Q=V,H=ne;break}if(_e===H){Se=!0,H=V,Q=ne;break}_e=_e.sibling}if(!Se){for(_e=ne.child;_e;){if(_e===Q){Se=!0,Q=ne,H=V;break}if(_e===H){Se=!0,H=ne,Q=V;break}_e=_e.sibling}if(!Se)throw Error(c(189))}}if(Q.alternate!==H)throw Error(c(190))}if(Q.tag!==3)throw Error(c(188));return Q.stateNode.current===Q?v:D}function se(v){if(v=Ae(v),!v)return null;for(var D=v;;){if(D.tag===5||D.tag===6)return D;if(D.child)D.child.return=D,D=D.child;else{if(D===v)break;for(;!D.sibling;){if(!D.return||D.return===v)return null;D=D.return}D.sibling.return=D.return,D=D.sibling}}return null}function X(v){if(v=Ae(v),!v)return null;for(var D=v;;){if(D.tag===5||D.tag===6)return D;if(D.child&&D.tag!==4)D.child.return=D,D=D.child;else{if(D===v)break;for(;!D.sibling;){if(!D.return||D.return===v)return null;D=D.return}D.sibling.return=D.return,D=D.sibling}}return null}function De(v,D){for(var Q=v.alternate;D!==null;){if(D===v||D===Q)return!0;D=D.return}return!1}var Te=e.getPublicInstance,mt=e.getRootHostContext,j=e.getChildHostContext,rt=e.prepareForCommit,Fe=e.resetAfterCommit,Ne=e.createInstance,be=e.appendInitialChild,Ve=e.finalizeInitialChildren,ke=e.prepareUpdate,it=e.shouldSetTextContent,Ue=e.createTextInstance,x=e.scheduleTimeout,w=e.cancelTimeout,P=e.noTimeout,y=e.isPrimaryRenderer,F=e.supportsMutation,z=e.supportsPersistence,Z=e.supportsHydration,$=e.getInstanceFromNode,oe=e.makeOpaqueHydratingObject,xe=e.makeClientId,Re=e.beforeActiveInstanceBlur,lt=e.afterActiveInstanceBlur,Ct=e.preparePortalMount,qt=e.supportsTestSelectors,ir=e.findFiberRoot,bt=e.getBoundingRect,gn=e.getTextContent,br=e.isHiddenSubtree,Ir=e.matchAccessibilityRole,Or=e.setFocusIfFocusable,nn=e.setupIntersectionObserver,ai=e.appendChild,Io=e.appendChildToContainer,ts=e.commitTextUpdate,$s=e.commitMount,Co=e.commitUpdate,Hi=e.insertBefore,eo=e.insertInContainerBefore,wo=e.removeChild,QA=e.removeChildFromContainer,Af=e.resetTextContent,dh=e.hideInstance,mh=e.hideTextInstance,to=e.unhideInstance,jn=e.unhideTextInstance,Rs=e.clearContainer,ro=e.cloneInstance,ou=e.createContainerChildSet,au=e.appendChildToContainerChildSet,lu=e.finalizeContainerChildren,RA=e.replaceContainerChildren,TA=e.cloneHiddenInstance,oa=e.cloneHiddenTextInstance,aa=e.canHydrateInstance,FA=e.canHydrateTextInstance,gr=e.isSuspenseInstancePending,Bo=e.isSuspenseInstanceFallback,Me=e.getNextHydratableSibling,cu=e.getFirstHydratableChild,Cr=e.hydrateInstance,pf=e.hydrateTextInstance,NA=e.getNextHydratableInstanceAfterSuspenseInstance,OA=e.commitHydratedContainer,uu=e.commitHydratedSuspenseInstance,fu;function oc(v){if(fu===void 0)try{throw Error()}catch(Q){var D=Q.stack.trim().match(/\\n( *(at )?)/);fu=D&&D[1]||\"\"}return`\n`+fu+v}var ve=!1;function Nt(v,D){if(!v||ve)return\"\";ve=!0;var Q=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(D)if(D=function(){throw Error()},Object.defineProperty(D.prototype,\"props\",{set:function(){throw Error()}}),typeof Reflect==\"object\"&&Reflect.construct){try{Reflect.construct(D,[])}catch(pt){var H=pt}Reflect.construct(v,[],D)}else{try{D.call()}catch(pt){H=pt}v.call(D.prototype)}else{try{throw Error()}catch(pt){H=pt}v()}}catch(pt){if(pt&&H&&typeof pt.stack==\"string\"){for(var V=pt.stack.split(`\n`),ne=H.stack.split(`\n`),Se=V.length-1,_e=ne.length-1;1<=Se&&0<=_e&&V[Se]!==ne[_e];)_e--;for(;1<=Se&&0<=_e;Se--,_e--)if(V[Se]!==ne[_e]){if(Se!==1||_e!==1)do if(Se--,_e--,0>_e||V[Se]!==ne[_e])return`\n`+V[Se].replace(\" at new \",\" at \");while(1<=Se&&0<=_e);break}}}finally{ve=!1,Error.prepareStackTrace=Q}return(v=v?v.displayName||v.name:\"\")?oc(v):\"\"}var ac=[],Oi=-1;function no(v){return{current:v}}function Tt(v){0>Oi||(v.current=ac[Oi],ac[Oi]=null,Oi--)}function xn(v,D){Oi++,ac[Oi]=v.current,v.current=D}var la={},ji=no(la),Li=no(!1),Na=la;function dn(v,D){var Q=v.type.contextTypes;if(!Q)return la;var H=v.stateNode;if(H&&H.__reactInternalMemoizedUnmaskedChildContext===D)return H.__reactInternalMemoizedMaskedChildContext;var V={},ne;for(ne in Q)V[ne]=D[ne];return H&&(v=v.stateNode,v.__reactInternalMemoizedUnmaskedChildContext=D,v.__reactInternalMemoizedMaskedChildContext=V),V}function Kn(v){return v=v.childContextTypes,v!=null}function Au(){Tt(Li),Tt(ji)}function yh(v,D,Q){if(ji.current!==la)throw Error(c(168));xn(ji,D),xn(Li,Q)}function Oa(v,D,Q){var H=v.stateNode;if(v=D.childContextTypes,typeof H.getChildContext!=\"function\")return Q;H=H.getChildContext();for(var V in H)if(!(V in v))throw Error(c(108,g(D)||\"Unknown\",V));return s({},Q,H)}function La(v){return v=(v=v.stateNode)&&v.__reactInternalMemoizedMergedChildContext||la,Na=ji.current,xn(ji,v),xn(Li,Li.current),!0}function Ma(v,D,Q){var H=v.stateNode;if(!H)throw Error(c(169));Q?(v=Oa(v,D,Na),H.__reactInternalMemoizedMergedChildContext=v,Tt(Li),Tt(ji),xn(ji,v)):Tt(Li),xn(Li,Q)}var $e=null,Ua=null,hf=n.unstable_now;hf();var lc=0,wn=8;function ca(v){if(1&v)return wn=15,1;if(2&v)return wn=14,2;if(4&v)return wn=13,4;var D=24&v;return D!==0?(wn=12,D):v&32?(wn=11,32):(D=192&v,D!==0?(wn=10,D):v&256?(wn=9,256):(D=3584&v,D!==0?(wn=8,D):v&4096?(wn=7,4096):(D=4186112&v,D!==0?(wn=6,D):(D=62914560&v,D!==0?(wn=5,D):v&67108864?(wn=4,67108864):v&134217728?(wn=3,134217728):(D=805306368&v,D!==0?(wn=2,D):1073741824&v?(wn=1,1073741824):(wn=8,v))))))}function LA(v){switch(v){case 99:return 15;case 98:return 10;case 97:case 96:return 8;case 95:return 2;default:return 0}}function MA(v){switch(v){case 15:case 14:return 99;case 13:case 12:case 11:case 10:return 98;case 9:case 8:case 7:case 6:case 4:case 5:return 97;case 3:case 2:case 1:return 95;case 0:return 90;default:throw Error(c(358,v))}}function ua(v,D){var Q=v.pendingLanes;if(Q===0)return wn=0;var H=0,V=0,ne=v.expiredLanes,Se=v.suspendedLanes,_e=v.pingedLanes;if(ne!==0)H=ne,V=wn=15;else if(ne=Q&134217727,ne!==0){var pt=ne&~Se;pt!==0?(H=ca(pt),V=wn):(_e&=ne,_e!==0&&(H=ca(_e),V=wn))}else ne=Q&~Se,ne!==0?(H=ca(ne),V=wn):_e!==0&&(H=ca(_e),V=wn);if(H===0)return 0;if(H=31-rs(H),H=Q&((0>H?0:1<<H)<<1)-1,D!==0&&D!==H&&!(D&Se)){if(ca(D),V<=wn)return D;wn=V}if(D=v.entangledLanes,D!==0)for(v=v.entanglements,D&=H;0<D;)Q=31-rs(D),V=1<<Q,H|=v[Q],D&=~V;return H}function Bl(v){return v=v.pendingLanes&-1073741825,v!==0?v:v&1073741824?1073741824:0}function Mt(v,D){switch(v){case 15:return 1;case 14:return 2;case 12:return v=kn(24&~D),v===0?Mt(10,D):v;case 10:return v=kn(192&~D),v===0?Mt(8,D):v;case 8:return v=kn(3584&~D),v===0&&(v=kn(4186112&~D),v===0&&(v=512)),v;case 2:return D=kn(805306368&~D),D===0&&(D=268435456),D}throw Error(c(358,v))}function kn(v){return v&-v}function fa(v){for(var D=[],Q=0;31>Q;Q++)D.push(v);return D}function Ha(v,D,Q){v.pendingLanes|=D;var H=D-1;v.suspendedLanes&=H,v.pingedLanes&=H,v=v.eventTimes,D=31-rs(D),v[D]=Q}var rs=Math.clz32?Math.clz32:uc,cc=Math.log,pu=Math.LN2;function uc(v){return v===0?32:31-(cc(v)/pu|0)|0}var ja=n.unstable_runWithPriority,Mi=n.unstable_scheduleCallback,Is=n.unstable_cancelCallback,vl=n.unstable_shouldYield,gf=n.unstable_requestPaint,fc=n.unstable_now,wi=n.unstable_getCurrentPriorityLevel,Qn=n.unstable_ImmediatePriority,Ac=n.unstable_UserBlockingPriority,Ke=n.unstable_NormalPriority,st=n.unstable_LowPriority,St=n.unstable_IdlePriority,lr={},te=gf!==void 0?gf:function(){},Ee=null,Oe=null,dt=!1,Et=fc(),Pt=1e4>Et?fc:function(){return fc()-Et};function tr(){switch(wi()){case Qn:return 99;case Ac:return 98;case Ke:return 97;case st:return 96;case St:return 95;default:throw Error(c(332))}}function An(v){switch(v){case 99:return Qn;case 98:return Ac;case 97:return Ke;case 96:return st;case 95:return St;default:throw Error(c(332))}}function li(v,D){return v=An(v),ja(v,D)}function Gi(v,D,Q){return v=An(v),Mi(v,D,Q)}function Rn(){if(Oe!==null){var v=Oe;Oe=null,Is(v)}Ga()}function Ga(){if(!dt&&Ee!==null){dt=!0;var v=0;try{var D=Ee;li(99,function(){for(;v<D.length;v++){var Q=D[v];do Q=Q(!0);while(Q!==null)}}),Ee=null}catch(Q){throw Ee!==null&&(Ee=Ee.slice(v+1)),Mi(Qn,Rn),Q}finally{dt=!1}}}var my=f.ReactCurrentBatchConfig;function X1(v,D){return v===D&&(v!==0||1/v===1/D)||v!==v&&D!==D}var vo=typeof Object.is==\"function\"?Object.is:X1,yy=Object.prototype.hasOwnProperty;function Eh(v,D){if(vo(v,D))return!0;if(typeof v!=\"object\"||v===null||typeof D!=\"object\"||D===null)return!1;var Q=Object.keys(v),H=Object.keys(D);if(Q.length!==H.length)return!1;for(H=0;H<Q.length;H++)if(!yy.call(D,Q[H])||!vo(v[Q[H]],D[Q[H]]))return!1;return!0}function $1(v){switch(v.tag){case 5:return oc(v.type);case 16:return oc(\"Lazy\");case 13:return oc(\"Suspense\");case 19:return oc(\"SuspenseList\");case 0:case 2:case 15:return v=Nt(v.type,!1),v;case 11:return v=Nt(v.type.render,!1),v;case 22:return v=Nt(v.type._render,!1),v;case 1:return v=Nt(v.type,!0),v;default:return\"\"}}function So(v,D){if(v&&v.defaultProps){D=s({},D),v=v.defaultProps;for(var Q in v)D[Q]===void 0&&(D[Q]=v[Q]);return D}return D}var Ih=no(null),Ch=null,hu=null,wh=null;function Fg(){wh=hu=Ch=null}function Ng(v,D){v=v.type._context,y?(xn(Ih,v._currentValue),v._currentValue=D):(xn(Ih,v._currentValue2),v._currentValue2=D)}function Og(v){var D=Ih.current;Tt(Ih),v=v.type._context,y?v._currentValue=D:v._currentValue2=D}function Ey(v,D){for(;v!==null;){var Q=v.alternate;if((v.childLanes&D)===D){if(Q===null||(Q.childLanes&D)===D)break;Q.childLanes|=D}else v.childLanes|=D,Q!==null&&(Q.childLanes|=D);v=v.return}}function df(v,D){Ch=v,wh=hu=null,v=v.dependencies,v!==null&&v.firstContext!==null&&(v.lanes&D&&(Je=!0),v.firstContext=null)}function Do(v,D){if(wh!==v&&D!==!1&&D!==0)if((typeof D!=\"number\"||D===1073741823)&&(wh=v,D=1073741823),D={context:v,observedBits:D,next:null},hu===null){if(Ch===null)throw Error(c(308));hu=D,Ch.dependencies={lanes:0,firstContext:D,responders:null}}else hu=hu.next=D;return y?v._currentValue:v._currentValue2}var Sl=!1;function Bh(v){v.updateQueue={baseState:v.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null},effects:null}}function Lg(v,D){v=v.updateQueue,D.updateQueue===v&&(D.updateQueue={baseState:v.baseState,firstBaseUpdate:v.firstBaseUpdate,lastBaseUpdate:v.lastBaseUpdate,shared:v.shared,effects:v.effects})}function Dl(v,D){return{eventTime:v,lane:D,tag:0,payload:null,callback:null,next:null}}function Pl(v,D){if(v=v.updateQueue,v!==null){v=v.shared;var Q=v.pending;Q===null?D.next=D:(D.next=Q.next,Q.next=D),v.pending=D}}function Iy(v,D){var Q=v.updateQueue,H=v.alternate;if(H!==null&&(H=H.updateQueue,Q===H)){var V=null,ne=null;if(Q=Q.firstBaseUpdate,Q!==null){do{var Se={eventTime:Q.eventTime,lane:Q.lane,tag:Q.tag,payload:Q.payload,callback:Q.callback,next:null};ne===null?V=ne=Se:ne=ne.next=Se,Q=Q.next}while(Q!==null);ne===null?V=ne=D:ne=ne.next=D}else V=ne=D;Q={baseState:H.baseState,firstBaseUpdate:V,lastBaseUpdate:ne,shared:H.shared,effects:H.effects},v.updateQueue=Q;return}v=Q.lastBaseUpdate,v===null?Q.firstBaseUpdate=D:v.next=D,Q.lastBaseUpdate=D}function UA(v,D,Q,H){var V=v.updateQueue;Sl=!1;var ne=V.firstBaseUpdate,Se=V.lastBaseUpdate,_e=V.shared.pending;if(_e!==null){V.shared.pending=null;var pt=_e,Wt=pt.next;pt.next=null,Se===null?ne=Wt:Se.next=Wt,Se=pt;var Sr=v.alternate;if(Sr!==null){Sr=Sr.updateQueue;var Lr=Sr.lastBaseUpdate;Lr!==Se&&(Lr===null?Sr.firstBaseUpdate=Wt:Lr.next=Wt,Sr.lastBaseUpdate=pt)}}if(ne!==null){Lr=V.baseState,Se=0,Sr=Wt=pt=null;do{_e=ne.lane;var Xt=ne.eventTime;if((H&_e)===_e){Sr!==null&&(Sr=Sr.next={eventTime:Xt,lane:0,tag:ne.tag,payload:ne.payload,callback:ne.callback,next:null});e:{var zn=v,yi=ne;switch(_e=D,Xt=Q,yi.tag){case 1:if(zn=yi.payload,typeof zn==\"function\"){Lr=zn.call(Xt,Lr,_e);break e}Lr=zn;break e;case 3:zn.flags=zn.flags&-4097|64;case 0:if(zn=yi.payload,_e=typeof zn==\"function\"?zn.call(Xt,Lr,_e):zn,_e==null)break e;Lr=s({},Lr,_e);break e;case 2:Sl=!0}}ne.callback!==null&&(v.flags|=32,_e=V.effects,_e===null?V.effects=[ne]:_e.push(ne))}else Xt={eventTime:Xt,lane:_e,tag:ne.tag,payload:ne.payload,callback:ne.callback,next:null},Sr===null?(Wt=Sr=Xt,pt=Lr):Sr=Sr.next=Xt,Se|=_e;if(ne=ne.next,ne===null){if(_e=V.shared.pending,_e===null)break;ne=_e.next,_e.next=null,V.lastBaseUpdate=_e,V.shared.pending=null}}while(!0);Sr===null&&(pt=Lr),V.baseState=pt,V.firstBaseUpdate=Wt,V.lastBaseUpdate=Sr,Xg|=Se,v.lanes=Se,v.memoizedState=Lr}}function Cy(v,D,Q){if(v=D.effects,D.effects=null,v!==null)for(D=0;D<v.length;D++){var H=v[D],V=H.callback;if(V!==null){if(H.callback=null,H=Q,typeof V!=\"function\")throw Error(c(191,V));V.call(H)}}}var wy=new a.Component().refs;function _A(v,D,Q,H){D=v.memoizedState,Q=Q(H,D),Q=Q==null?D:s({},D,Q),v.memoizedState=Q,v.lanes===0&&(v.updateQueue.baseState=Q)}var HA={isMounted:function(v){return(v=v._reactInternals)?we(v)===v:!1},enqueueSetState:function(v,D,Q){v=v._reactInternals;var H=ko(),V=Bs(v),ne=Dl(H,V);ne.payload=D,Q!=null&&(ne.callback=Q),Pl(v,ne),Rl(v,V,H)},enqueueReplaceState:function(v,D,Q){v=v._reactInternals;var H=ko(),V=Bs(v),ne=Dl(H,V);ne.tag=1,ne.payload=D,Q!=null&&(ne.callback=Q),Pl(v,ne),Rl(v,V,H)},enqueueForceUpdate:function(v,D){v=v._reactInternals;var Q=ko(),H=Bs(v),V=Dl(Q,H);V.tag=2,D!=null&&(V.callback=D),Pl(v,V),Rl(v,H,Q)}};function Y(v,D,Q,H,V,ne,Se){return v=v.stateNode,typeof v.shouldComponentUpdate==\"function\"?v.shouldComponentUpdate(H,ne,Se):D.prototype&&D.prototype.isPureReactComponent?!Eh(Q,H)||!Eh(V,ne):!0}function xt(v,D,Q){var H=!1,V=la,ne=D.contextType;return typeof ne==\"object\"&&ne!==null?ne=Do(ne):(V=Kn(D)?Na:ji.current,H=D.contextTypes,ne=(H=H!=null)?dn(v,V):la),D=new D(Q,ne),v.memoizedState=D.state!==null&&D.state!==void 0?D.state:null,D.updater=HA,v.stateNode=D,D._reactInternals=v,H&&(v=v.stateNode,v.__reactInternalMemoizedUnmaskedChildContext=V,v.__reactInternalMemoizedMaskedChildContext=ne),D}function jA(v,D,Q,H){v=D.state,typeof D.componentWillReceiveProps==\"function\"&&D.componentWillReceiveProps(Q,H),typeof D.UNSAFE_componentWillReceiveProps==\"function\"&&D.UNSAFE_componentWillReceiveProps(Q,H),D.state!==v&&HA.enqueueReplaceState(D,D.state,null)}function Po(v,D,Q,H){var V=v.stateNode;V.props=Q,V.state=v.memoizedState,V.refs=wy,Bh(v);var ne=D.contextType;typeof ne==\"object\"&&ne!==null?V.context=Do(ne):(ne=Kn(D)?Na:ji.current,V.context=dn(v,ne)),UA(v,Q,V,H),V.state=v.memoizedState,ne=D.getDerivedStateFromProps,typeof ne==\"function\"&&(_A(v,D,ne,Q),V.state=v.memoizedState),typeof D.getDerivedStateFromProps==\"function\"||typeof V.getSnapshotBeforeUpdate==\"function\"||typeof V.UNSAFE_componentWillMount!=\"function\"&&typeof V.componentWillMount!=\"function\"||(D=V.state,typeof V.componentWillMount==\"function\"&&V.componentWillMount(),typeof V.UNSAFE_componentWillMount==\"function\"&&V.UNSAFE_componentWillMount(),D!==V.state&&HA.enqueueReplaceState(V,V.state,null),UA(v,Q,V,H),V.state=v.memoizedState),typeof V.componentDidMount==\"function\"&&(v.flags|=4)}var mf=Array.isArray;function yt(v,D,Q){if(v=Q.ref,v!==null&&typeof v!=\"function\"&&typeof v!=\"object\"){if(Q._owner){if(Q=Q._owner,Q){if(Q.tag!==1)throw Error(c(309));var H=Q.stateNode}if(!H)throw Error(c(147,v));var V=\"\"+v;return D!==null&&D.ref!==null&&typeof D.ref==\"function\"&&D.ref._stringRef===V?D.ref:(D=function(ne){var Se=H.refs;Se===wy&&(Se=H.refs={}),ne===null?delete Se[V]:Se[V]=ne},D._stringRef=V,D)}if(typeof v!=\"string\")throw Error(c(284));if(!Q._owner)throw Error(c(290,v))}return v}function gu(v,D){if(v.type!==\"textarea\")throw Error(c(31,Object.prototype.toString.call(D)===\"[object Object]\"?\"object with keys {\"+Object.keys(D).join(\", \")+\"}\":D))}function By(v){function D(et,qe){if(v){var gt=et.lastEffect;gt!==null?(gt.nextEffect=qe,et.lastEffect=qe):et.firstEffect=et.lastEffect=qe,qe.nextEffect=null,qe.flags=8}}function Q(et,qe){if(!v)return null;for(;qe!==null;)D(et,qe),qe=qe.sibling;return null}function H(et,qe){for(et=new Map;qe!==null;)qe.key!==null?et.set(qe.key,qe):et.set(qe.index,qe),qe=qe.sibling;return et}function V(et,qe){return et=Su(et,qe),et.index=0,et.sibling=null,et}function ne(et,qe,gt){return et.index=gt,v?(gt=et.alternate,gt!==null?(gt=gt.index,gt<qe?(et.flags=2,qe):gt):(et.flags=2,qe)):qe}function Se(et){return v&&et.alternate===null&&(et.flags=2),et}function _e(et,qe,gt,Zt){return qe===null||qe.tag!==6?(qe=P2(gt,et.mode,Zt),qe.return=et,qe):(qe=V(qe,gt),qe.return=et,qe)}function pt(et,qe,gt,Zt){return qe!==null&&qe.elementType===gt.type?(Zt=V(qe,gt.props),Zt.ref=yt(et,qe,gt),Zt.return=et,Zt):(Zt=sd(gt.type,gt.key,gt.props,null,et.mode,Zt),Zt.ref=yt(et,qe,gt),Zt.return=et,Zt)}function Wt(et,qe,gt,Zt){return qe===null||qe.tag!==4||qe.stateNode.containerInfo!==gt.containerInfo||qe.stateNode.implementation!==gt.implementation?(qe=Qo(gt,et.mode,Zt),qe.return=et,qe):(qe=V(qe,gt.children||[]),qe.return=et,qe)}function Sr(et,qe,gt,Zt,Dr){return qe===null||qe.tag!==7?(qe=kf(gt,et.mode,Zt,Dr),qe.return=et,qe):(qe=V(qe,gt),qe.return=et,qe)}function Lr(et,qe,gt){if(typeof qe==\"string\"||typeof qe==\"number\")return qe=P2(\"\"+qe,et.mode,gt),qe.return=et,qe;if(typeof qe==\"object\"&&qe!==null){switch(qe.$$typeof){case p:return gt=sd(qe.type,qe.key,qe.props,null,et.mode,gt),gt.ref=yt(et,null,qe),gt.return=et,gt;case h:return qe=Qo(qe,et.mode,gt),qe.return=et,qe}if(mf(qe)||Ce(qe))return qe=kf(qe,et.mode,gt,null),qe.return=et,qe;gu(et,qe)}return null}function Xt(et,qe,gt,Zt){var Dr=qe!==null?qe.key:null;if(typeof gt==\"string\"||typeof gt==\"number\")return Dr!==null?null:_e(et,qe,\"\"+gt,Zt);if(typeof gt==\"object\"&&gt!==null){switch(gt.$$typeof){case p:return gt.key===Dr?gt.type===E?Sr(et,qe,gt.props.children,Zt,Dr):pt(et,qe,gt,Zt):null;case h:return gt.key===Dr?Wt(et,qe,gt,Zt):null}if(mf(gt)||Ce(gt))return Dr!==null?null:Sr(et,qe,gt,Zt,null);gu(et,gt)}return null}function zn(et,qe,gt,Zt,Dr){if(typeof Zt==\"string\"||typeof Zt==\"number\")return et=et.get(gt)||null,_e(qe,et,\"\"+Zt,Dr);if(typeof Zt==\"object\"&&Zt!==null){switch(Zt.$$typeof){case p:return et=et.get(Zt.key===null?gt:Zt.key)||null,Zt.type===E?Sr(qe,et,Zt.props.children,Dr,Zt.key):pt(qe,et,Zt,Dr);case h:return et=et.get(Zt.key===null?gt:Zt.key)||null,Wt(qe,et,Zt,Dr)}if(mf(Zt)||Ce(Zt))return et=et.get(gt)||null,Sr(qe,et,Zt,Dr,null);gu(qe,Zt)}return null}function yi(et,qe,gt,Zt){for(var Dr=null,Xn=null,kr=qe,Tn=qe=0,_n=null;kr!==null&&Tn<gt.length;Tn++){kr.index>Tn?(_n=kr,kr=null):_n=kr.sibling;var zr=Xt(et,kr,gt[Tn],Zt);if(zr===null){kr===null&&(kr=_n);break}v&&kr&&zr.alternate===null&&D(et,kr),qe=ne(zr,qe,Tn),Xn===null?Dr=zr:Xn.sibling=zr,Xn=zr,kr=_n}if(Tn===gt.length)return Q(et,kr),Dr;if(kr===null){for(;Tn<gt.length;Tn++)kr=Lr(et,gt[Tn],Zt),kr!==null&&(qe=ne(kr,qe,Tn),Xn===null?Dr=kr:Xn.sibling=kr,Xn=kr);return Dr}for(kr=H(et,kr);Tn<gt.length;Tn++)_n=zn(kr,et,Tn,gt[Tn],Zt),_n!==null&&(v&&_n.alternate!==null&&kr.delete(_n.key===null?Tn:_n.key),qe=ne(_n,qe,Tn),Xn===null?Dr=_n:Xn.sibling=_n,Xn=_n);return v&&kr.forEach(function(ci){return D(et,ci)}),Dr}function za(et,qe,gt,Zt){var Dr=Ce(gt);if(typeof Dr!=\"function\")throw Error(c(150));if(gt=Dr.call(gt),gt==null)throw Error(c(151));for(var Xn=Dr=null,kr=qe,Tn=qe=0,_n=null,zr=gt.next();kr!==null&&!zr.done;Tn++,zr=gt.next()){kr.index>Tn?(_n=kr,kr=null):_n=kr.sibling;var ci=Xt(et,kr,zr.value,Zt);if(ci===null){kr===null&&(kr=_n);break}v&&kr&&ci.alternate===null&&D(et,kr),qe=ne(ci,qe,Tn),Xn===null?Dr=ci:Xn.sibling=ci,Xn=ci,kr=_n}if(zr.done)return Q(et,kr),Dr;if(kr===null){for(;!zr.done;Tn++,zr=gt.next())zr=Lr(et,zr.value,Zt),zr!==null&&(qe=ne(zr,qe,Tn),Xn===null?Dr=zr:Xn.sibling=zr,Xn=zr);return Dr}for(kr=H(et,kr);!zr.done;Tn++,zr=gt.next())zr=zn(kr,et,Tn,zr.value,Zt),zr!==null&&(v&&zr.alternate!==null&&kr.delete(zr.key===null?Tn:zr.key),qe=ne(zr,qe,Tn),Xn===null?Dr=zr:Xn.sibling=zr,Xn=zr);return v&&kr.forEach(function(Du){return D(et,Du)}),Dr}return function(et,qe,gt,Zt){var Dr=typeof gt==\"object\"&&gt!==null&&gt.type===E&&gt.key===null;Dr&&(gt=gt.props.children);var Xn=typeof gt==\"object\"&&gt!==null;if(Xn)switch(gt.$$typeof){case p:e:{for(Xn=gt.key,Dr=qe;Dr!==null;){if(Dr.key===Xn){switch(Dr.tag){case 7:if(gt.type===E){Q(et,Dr.sibling),qe=V(Dr,gt.props.children),qe.return=et,et=qe;break e}break;default:if(Dr.elementType===gt.type){Q(et,Dr.sibling),qe=V(Dr,gt.props),qe.ref=yt(et,Dr,gt),qe.return=et,et=qe;break e}}Q(et,Dr);break}else D(et,Dr);Dr=Dr.sibling}gt.type===E?(qe=kf(gt.props.children,et.mode,Zt,gt.key),qe.return=et,et=qe):(Zt=sd(gt.type,gt.key,gt.props,null,et.mode,Zt),Zt.ref=yt(et,qe,gt),Zt.return=et,et=Zt)}return Se(et);case h:e:{for(Dr=gt.key;qe!==null;){if(qe.key===Dr)if(qe.tag===4&&qe.stateNode.containerInfo===gt.containerInfo&&qe.stateNode.implementation===gt.implementation){Q(et,qe.sibling),qe=V(qe,gt.children||[]),qe.return=et,et=qe;break e}else{Q(et,qe);break}else D(et,qe);qe=qe.sibling}qe=Qo(gt,et.mode,Zt),qe.return=et,et=qe}return Se(et)}if(typeof gt==\"string\"||typeof gt==\"number\")return gt=\"\"+gt,qe!==null&&qe.tag===6?(Q(et,qe.sibling),qe=V(qe,gt),qe.return=et,et=qe):(Q(et,qe),qe=P2(gt,et.mode,Zt),qe.return=et,et=qe),Se(et);if(mf(gt))return yi(et,qe,gt,Zt);if(Ce(gt))return za(et,qe,gt,Zt);if(Xn&&gu(et,gt),typeof gt>\"u\"&&!Dr)switch(et.tag){case 1:case 22:case 0:case 11:case 15:throw Error(c(152,g(et.type)||\"Component\"))}return Q(et,qe)}}var Mg=By(!0),e2=By(!1),vh={},ur=no(vh),Ki=no(vh),yf=no(vh);function qa(v){if(v===vh)throw Error(c(174));return v}function Ug(v,D){xn(yf,D),xn(Ki,v),xn(ur,vh),v=mt(D),Tt(ur),xn(ur,v)}function du(){Tt(ur),Tt(Ki),Tt(yf)}function Ef(v){var D=qa(yf.current),Q=qa(ur.current);D=j(Q,v.type,D),Q!==D&&(xn(Ki,v),xn(ur,D))}function wt(v){Ki.current===v&&(Tt(ur),Tt(Ki))}var di=no(0);function GA(v){for(var D=v;D!==null;){if(D.tag===13){var Q=D.memoizedState;if(Q!==null&&(Q=Q.dehydrated,Q===null||gr(Q)||Bo(Q)))return D}else if(D.tag===19&&D.memoizedProps.revealOrder!==void 0){if(D.flags&64)return D}else if(D.child!==null){D.child.return=D,D=D.child;continue}if(D===v)break;for(;D.sibling===null;){if(D.return===null||D.return===v)return null;D=D.return}D.sibling.return=D.return,D=D.sibling}return null}var Wa=null,Aa=null,Ya=!1;function _g(v,D){var Q=Ka(5,null,null,0);Q.elementType=\"DELETED\",Q.type=\"DELETED\",Q.stateNode=D,Q.return=v,Q.flags=8,v.lastEffect!==null?(v.lastEffect.nextEffect=Q,v.lastEffect=Q):v.firstEffect=v.lastEffect=Q}function Sh(v,D){switch(v.tag){case 5:return D=aa(D,v.type,v.pendingProps),D!==null?(v.stateNode=D,!0):!1;case 6:return D=FA(D,v.pendingProps),D!==null?(v.stateNode=D,!0):!1;case 13:return!1;default:return!1}}function Hg(v){if(Ya){var D=Aa;if(D){var Q=D;if(!Sh(v,D)){if(D=Me(Q),!D||!Sh(v,D)){v.flags=v.flags&-1025|2,Ya=!1,Wa=v;return}_g(Wa,Q)}Wa=v,Aa=cu(D)}else v.flags=v.flags&-1025|2,Ya=!1,Wa=v}}function vy(v){for(v=v.return;v!==null&&v.tag!==5&&v.tag!==3&&v.tag!==13;)v=v.return;Wa=v}function qA(v){if(!Z||v!==Wa)return!1;if(!Ya)return vy(v),Ya=!0,!1;var D=v.type;if(v.tag!==5||D!==\"head\"&&D!==\"body\"&&!it(D,v.memoizedProps))for(D=Aa;D;)_g(v,D),D=Me(D);if(vy(v),v.tag===13){if(!Z)throw Error(c(316));if(v=v.memoizedState,v=v!==null?v.dehydrated:null,!v)throw Error(c(317));Aa=NA(v)}else Aa=Wa?Me(v.stateNode):null;return!0}function jg(){Z&&(Aa=Wa=null,Ya=!1)}var mu=[];function yu(){for(var v=0;v<mu.length;v++){var D=mu[v];y?D._workInProgressVersionPrimary=null:D._workInProgressVersionSecondary=null}mu.length=0}var If=f.ReactCurrentDispatcher,Ts=f.ReactCurrentBatchConfig,Eu=0,Gn=null,ns=null,bi=null,WA=!1,Cf=!1;function mn(){throw Error(c(321))}function Gg(v,D){if(D===null)return!1;for(var Q=0;Q<D.length&&Q<v.length;Q++)if(!vo(v[Q],D[Q]))return!1;return!0}function qg(v,D,Q,H,V,ne){if(Eu=ne,Gn=D,D.memoizedState=null,D.updateQueue=null,D.lanes=0,If.current=v===null||v.memoizedState===null?O:K,v=Q(H,V),Cf){ne=0;do{if(Cf=!1,!(25>ne))throw Error(c(301));ne+=1,bi=ns=null,D.updateQueue=null,If.current=re,v=Q(H,V)}while(Cf)}if(If.current=kt,D=ns!==null&&ns.next!==null,Eu=0,bi=ns=Gn=null,WA=!1,D)throw Error(c(300));return v}function is(){var v={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};return bi===null?Gn.memoizedState=bi=v:bi=bi.next=v,bi}function bl(){if(ns===null){var v=Gn.alternate;v=v!==null?v.memoizedState:null}else v=ns.next;var D=bi===null?Gn.memoizedState:bi.next;if(D!==null)bi=D,ns=v;else{if(v===null)throw Error(c(310));ns=v,v={memoizedState:ns.memoizedState,baseState:ns.baseState,baseQueue:ns.baseQueue,queue:ns.queue,next:null},bi===null?Gn.memoizedState=bi=v:bi=bi.next=v}return bi}function bo(v,D){return typeof D==\"function\"?D(v):D}function wf(v){var D=bl(),Q=D.queue;if(Q===null)throw Error(c(311));Q.lastRenderedReducer=v;var H=ns,V=H.baseQueue,ne=Q.pending;if(ne!==null){if(V!==null){var Se=V.next;V.next=ne.next,ne.next=Se}H.baseQueue=V=ne,Q.pending=null}if(V!==null){V=V.next,H=H.baseState;var _e=Se=ne=null,pt=V;do{var Wt=pt.lane;if((Eu&Wt)===Wt)_e!==null&&(_e=_e.next={lane:0,action:pt.action,eagerReducer:pt.eagerReducer,eagerState:pt.eagerState,next:null}),H=pt.eagerReducer===v?pt.eagerState:v(H,pt.action);else{var Sr={lane:Wt,action:pt.action,eagerReducer:pt.eagerReducer,eagerState:pt.eagerState,next:null};_e===null?(Se=_e=Sr,ne=H):_e=_e.next=Sr,Gn.lanes|=Wt,Xg|=Wt}pt=pt.next}while(pt!==null&&pt!==V);_e===null?ne=H:_e.next=Se,vo(H,D.memoizedState)||(Je=!0),D.memoizedState=H,D.baseState=ne,D.baseQueue=_e,Q.lastRenderedState=H}return[D.memoizedState,Q.dispatch]}function Bf(v){var D=bl(),Q=D.queue;if(Q===null)throw Error(c(311));Q.lastRenderedReducer=v;var H=Q.dispatch,V=Q.pending,ne=D.memoizedState;if(V!==null){Q.pending=null;var Se=V=V.next;do ne=v(ne,Se.action),Se=Se.next;while(Se!==V);vo(ne,D.memoizedState)||(Je=!0),D.memoizedState=ne,D.baseQueue===null&&(D.baseState=ne),Q.lastRenderedState=ne}return[ne,H]}function xl(v,D,Q){var H=D._getVersion;H=H(D._source);var V=y?D._workInProgressVersionPrimary:D._workInProgressVersionSecondary;if(V!==null?v=V===H:(v=v.mutableReadLanes,(v=(Eu&v)===v)&&(y?D._workInProgressVersionPrimary=H:D._workInProgressVersionSecondary=H,mu.push(D))),v)return Q(D._source);throw mu.push(D),Error(c(350))}function yn(v,D,Q,H){var V=so;if(V===null)throw Error(c(349));var ne=D._getVersion,Se=ne(D._source),_e=If.current,pt=_e.useState(function(){return xl(V,D,Q)}),Wt=pt[1],Sr=pt[0];pt=bi;var Lr=v.memoizedState,Xt=Lr.refs,zn=Xt.getSnapshot,yi=Lr.source;Lr=Lr.subscribe;var za=Gn;return v.memoizedState={refs:Xt,source:D,subscribe:H},_e.useEffect(function(){Xt.getSnapshot=Q,Xt.setSnapshot=Wt;var et=ne(D._source);if(!vo(Se,et)){et=Q(D._source),vo(Sr,et)||(Wt(et),et=Bs(za),V.mutableReadLanes|=et&V.pendingLanes),et=V.mutableReadLanes,V.entangledLanes|=et;for(var qe=V.entanglements,gt=et;0<gt;){var Zt=31-rs(gt),Dr=1<<Zt;qe[Zt]|=et,gt&=~Dr}}},[Q,D,H]),_e.useEffect(function(){return H(D._source,function(){var et=Xt.getSnapshot,qe=Xt.setSnapshot;try{qe(et(D._source));var gt=Bs(za);V.mutableReadLanes|=gt&V.pendingLanes}catch(Zt){qe(function(){throw Zt})}})},[D,H]),vo(zn,Q)&&vo(yi,D)&&vo(Lr,H)||(v={pending:null,dispatch:null,lastRenderedReducer:bo,lastRenderedState:Sr},v.dispatch=Wt=xh.bind(null,Gn,v),pt.queue=v,pt.baseQueue=null,Sr=xl(V,D,Q),pt.memoizedState=pt.baseState=Sr),Sr}function xo(v,D,Q){var H=bl();return yn(H,v,D,Q)}function Iu(v){var D=is();return typeof v==\"function\"&&(v=v()),D.memoizedState=D.baseState=v,v=D.queue={pending:null,dispatch:null,lastRenderedReducer:bo,lastRenderedState:v},v=v.dispatch=xh.bind(null,Gn,v),[D.memoizedState,v]}function pa(v,D,Q,H){return v={tag:v,create:D,destroy:Q,deps:H,next:null},D=Gn.updateQueue,D===null?(D={lastEffect:null},Gn.updateQueue=D,D.lastEffect=v.next=v):(Q=D.lastEffect,Q===null?D.lastEffect=v.next=v:(H=Q.next,Q.next=v,v.next=H,D.lastEffect=v)),v}function Fs(v){var D=is();return v={current:v},D.memoizedState=v}function Dh(){return bl().memoizedState}function YA(v,D,Q,H){var V=is();Gn.flags|=v,V.memoizedState=pa(1|D,Q,void 0,H===void 0?null:H)}function vf(v,D,Q,H){var V=bl();H=H===void 0?null:H;var ne=void 0;if(ns!==null){var Se=ns.memoizedState;if(ne=Se.destroy,H!==null&&Gg(H,Se.deps)){pa(D,Q,ne,H);return}}Gn.flags|=v,V.memoizedState=pa(1|D,Q,ne,H)}function io(v,D){return YA(516,4,v,D)}function Xr(v,D){return vf(516,4,v,D)}function Ph(v,D){return vf(4,2,v,D)}function VA(v,D){if(typeof D==\"function\")return v=v(),D(v),function(){D(null)};if(D!=null)return v=v(),D.current=v,function(){D.current=null}}function Sy(v,D,Q){return Q=Q!=null?Q.concat([v]):null,vf(4,2,VA.bind(null,D,v),Q)}function Wg(){}function bh(v,D){var Q=bl();D=D===void 0?null:D;var H=Q.memoizedState;return H!==null&&D!==null&&Gg(D,H[1])?H[0]:(Q.memoizedState=[v,D],v)}function pc(v,D){var Q=bl();D=D===void 0?null:D;var H=Q.memoizedState;return H!==null&&D!==null&&Gg(D,H[1])?H[0]:(v=v(),Q.memoizedState=[v,D],v)}function Dy(v,D){var Q=tr();li(98>Q?98:Q,function(){v(!0)}),li(97<Q?97:Q,function(){var H=Ts.transition;Ts.transition=1;try{v(!1),D()}finally{Ts.transition=H}})}function xh(v,D,Q){var H=ko(),V=Bs(v),ne={lane:V,action:Q,eagerReducer:null,eagerState:null,next:null},Se=D.pending;if(Se===null?ne.next=ne:(ne.next=Se.next,Se.next=ne),D.pending=ne,Se=v.alternate,v===Gn||Se!==null&&Se===Gn)Cf=WA=!0;else{if(v.lanes===0&&(Se===null||Se.lanes===0)&&(Se=D.lastRenderedReducer,Se!==null))try{var _e=D.lastRenderedState,pt=Se(_e,Q);if(ne.eagerReducer=Se,ne.eagerState=pt,vo(pt,_e))return}catch{}finally{}Rl(v,V,H)}}var kt={readContext:Do,useCallback:mn,useContext:mn,useEffect:mn,useImperativeHandle:mn,useLayoutEffect:mn,useMemo:mn,useReducer:mn,useRef:mn,useState:mn,useDebugValue:mn,useDeferredValue:mn,useTransition:mn,useMutableSource:mn,useOpaqueIdentifier:mn,unstable_isNewReconciler:!1},O={readContext:Do,useCallback:function(v,D){return is().memoizedState=[v,D===void 0?null:D],v},useContext:Do,useEffect:io,useImperativeHandle:function(v,D,Q){return Q=Q!=null?Q.concat([v]):null,YA(4,2,VA.bind(null,D,v),Q)},useLayoutEffect:function(v,D){return YA(4,2,v,D)},useMemo:function(v,D){var Q=is();return D=D===void 0?null:D,v=v(),Q.memoizedState=[v,D],v},useReducer:function(v,D,Q){var H=is();return D=Q!==void 0?Q(D):D,H.memoizedState=H.baseState=D,v=H.queue={pending:null,dispatch:null,lastRenderedReducer:v,lastRenderedState:D},v=v.dispatch=xh.bind(null,Gn,v),[H.memoizedState,v]},useRef:Fs,useState:Iu,useDebugValue:Wg,useDeferredValue:function(v){var D=Iu(v),Q=D[0],H=D[1];return io(function(){var V=Ts.transition;Ts.transition=1;try{H(v)}finally{Ts.transition=V}},[v]),Q},useTransition:function(){var v=Iu(!1),D=v[0];return v=Dy.bind(null,v[1]),Fs(v),[v,D]},useMutableSource:function(v,D,Q){var H=is();return H.memoizedState={refs:{getSnapshot:D,setSnapshot:null},source:v,subscribe:Q},yn(H,v,D,Q)},useOpaqueIdentifier:function(){if(Ya){var v=!1,D=oe(function(){throw v||(v=!0,Q(xe())),Error(c(355))}),Q=Iu(D)[1];return!(Gn.mode&2)&&(Gn.flags|=516,pa(5,function(){Q(xe())},void 0,null)),D}return D=xe(),Iu(D),D},unstable_isNewReconciler:!1},K={readContext:Do,useCallback:bh,useContext:Do,useEffect:Xr,useImperativeHandle:Sy,useLayoutEffect:Ph,useMemo:pc,useReducer:wf,useRef:Dh,useState:function(){return wf(bo)},useDebugValue:Wg,useDeferredValue:function(v){var D=wf(bo),Q=D[0],H=D[1];return Xr(function(){var V=Ts.transition;Ts.transition=1;try{H(v)}finally{Ts.transition=V}},[v]),Q},useTransition:function(){var v=wf(bo)[0];return[Dh().current,v]},useMutableSource:xo,useOpaqueIdentifier:function(){return wf(bo)[0]},unstable_isNewReconciler:!1},re={readContext:Do,useCallback:bh,useContext:Do,useEffect:Xr,useImperativeHandle:Sy,useLayoutEffect:Ph,useMemo:pc,useReducer:Bf,useRef:Dh,useState:function(){return Bf(bo)},useDebugValue:Wg,useDeferredValue:function(v){var D=Bf(bo),Q=D[0],H=D[1];return Xr(function(){var V=Ts.transition;Ts.transition=1;try{H(v)}finally{Ts.transition=V}},[v]),Q},useTransition:function(){var v=Bf(bo)[0];return[Dh().current,v]},useMutableSource:xo,useOpaqueIdentifier:function(){return Bf(bo)[0]},unstable_isNewReconciler:!1},de=f.ReactCurrentOwner,Je=!1;function At(v,D,Q,H){D.child=v===null?e2(D,null,Q,H):Mg(D,v.child,Q,H)}function dr(v,D,Q,H,V){Q=Q.render;var ne=D.ref;return df(D,V),H=qg(v,D,Q,H,ne,V),v!==null&&!Je?(D.updateQueue=v.updateQueue,D.flags&=-517,v.lanes&=~V,qn(v,D,V)):(D.flags|=1,At(v,D,H,V),D.child)}function vr(v,D,Q,H,V,ne){if(v===null){var Se=Q.type;return typeof Se==\"function\"&&!S2(Se)&&Se.defaultProps===void 0&&Q.compare===null&&Q.defaultProps===void 0?(D.tag=15,D.type=Se,Un(v,D,Se,H,V,ne)):(v=sd(Q.type,null,H,D,D.mode,ne),v.ref=D.ref,v.return=D,D.child=v)}return Se=v.child,!(V&ne)&&(V=Se.memoizedProps,Q=Q.compare,Q=Q!==null?Q:Eh,Q(V,H)&&v.ref===D.ref)?qn(v,D,ne):(D.flags|=1,v=Su(Se,H),v.ref=D.ref,v.return=D,D.child=v)}function Un(v,D,Q,H,V,ne){if(v!==null&&Eh(v.memoizedProps,H)&&v.ref===D.ref)if(Je=!1,(ne&V)!==0)v.flags&16384&&(Je=!0);else return D.lanes=v.lanes,qn(v,D,ne);return JA(v,D,Q,H,ne)}function mi(v,D,Q){var H=D.pendingProps,V=H.children,ne=v!==null?v.memoizedState:null;if(H.mode===\"hidden\"||H.mode===\"unstable-defer-without-hiding\")if(!(D.mode&4))D.memoizedState={baseLanes:0},qy(D,Q);else if(Q&1073741824)D.memoizedState={baseLanes:0},qy(D,ne!==null?ne.baseLanes:Q);else return v=ne!==null?ne.baseLanes|Q:Q,D.lanes=D.childLanes=1073741824,D.memoizedState={baseLanes:v},qy(D,v),null;else ne!==null?(H=ne.baseLanes|Q,D.memoizedState=null):H=Q,qy(D,H);return At(v,D,V,Q),D.child}function Cs(v,D){var Q=D.ref;(v===null&&Q!==null||v!==null&&v.ref!==Q)&&(D.flags|=128)}function JA(v,D,Q,H,V){var ne=Kn(Q)?Na:ji.current;return ne=dn(D,ne),df(D,V),Q=qg(v,D,Q,H,ne,V),v!==null&&!Je?(D.updateQueue=v.updateQueue,D.flags&=-517,v.lanes&=~V,qn(v,D,V)):(D.flags|=1,At(v,D,Q,V),D.child)}function ab(v,D,Q,H,V){if(Kn(Q)){var ne=!0;La(D)}else ne=!1;if(df(D,V),D.stateNode===null)v!==null&&(v.alternate=null,D.alternate=null,D.flags|=2),xt(D,Q,H),Po(D,Q,H,V),H=!0;else if(v===null){var Se=D.stateNode,_e=D.memoizedProps;Se.props=_e;var pt=Se.context,Wt=Q.contextType;typeof Wt==\"object\"&&Wt!==null?Wt=Do(Wt):(Wt=Kn(Q)?Na:ji.current,Wt=dn(D,Wt));var Sr=Q.getDerivedStateFromProps,Lr=typeof Sr==\"function\"||typeof Se.getSnapshotBeforeUpdate==\"function\";Lr||typeof Se.UNSAFE_componentWillReceiveProps!=\"function\"&&typeof Se.componentWillReceiveProps!=\"function\"||(_e!==H||pt!==Wt)&&jA(D,Se,H,Wt),Sl=!1;var Xt=D.memoizedState;Se.state=Xt,UA(D,H,Se,V),pt=D.memoizedState,_e!==H||Xt!==pt||Li.current||Sl?(typeof Sr==\"function\"&&(_A(D,Q,Sr,H),pt=D.memoizedState),(_e=Sl||Y(D,Q,_e,H,Xt,pt,Wt))?(Lr||typeof Se.UNSAFE_componentWillMount!=\"function\"&&typeof Se.componentWillMount!=\"function\"||(typeof Se.componentWillMount==\"function\"&&Se.componentWillMount(),typeof Se.UNSAFE_componentWillMount==\"function\"&&Se.UNSAFE_componentWillMount()),typeof Se.componentDidMount==\"function\"&&(D.flags|=4)):(typeof Se.componentDidMount==\"function\"&&(D.flags|=4),D.memoizedProps=H,D.memoizedState=pt),Se.props=H,Se.state=pt,Se.context=Wt,H=_e):(typeof Se.componentDidMount==\"function\"&&(D.flags|=4),H=!1)}else{Se=D.stateNode,Lg(v,D),_e=D.memoizedProps,Wt=D.type===D.elementType?_e:So(D.type,_e),Se.props=Wt,Lr=D.pendingProps,Xt=Se.context,pt=Q.contextType,typeof pt==\"object\"&&pt!==null?pt=Do(pt):(pt=Kn(Q)?Na:ji.current,pt=dn(D,pt));var zn=Q.getDerivedStateFromProps;(Sr=typeof zn==\"function\"||typeof Se.getSnapshotBeforeUpdate==\"function\")||typeof Se.UNSAFE_componentWillReceiveProps!=\"function\"&&typeof Se.componentWillReceiveProps!=\"function\"||(_e!==Lr||Xt!==pt)&&jA(D,Se,H,pt),Sl=!1,Xt=D.memoizedState,Se.state=Xt,UA(D,H,Se,V);var yi=D.memoizedState;_e!==Lr||Xt!==yi||Li.current||Sl?(typeof zn==\"function\"&&(_A(D,Q,zn,H),yi=D.memoizedState),(Wt=Sl||Y(D,Q,Wt,H,Xt,yi,pt))?(Sr||typeof Se.UNSAFE_componentWillUpdate!=\"function\"&&typeof Se.componentWillUpdate!=\"function\"||(typeof Se.componentWillUpdate==\"function\"&&Se.componentWillUpdate(H,yi,pt),typeof Se.UNSAFE_componentWillUpdate==\"function\"&&Se.UNSAFE_componentWillUpdate(H,yi,pt)),typeof Se.componentDidUpdate==\"function\"&&(D.flags|=4),typeof Se.getSnapshotBeforeUpdate==\"function\"&&(D.flags|=256)):(typeof Se.componentDidUpdate!=\"function\"||_e===v.memoizedProps&&Xt===v.memoizedState||(D.flags|=4),typeof Se.getSnapshotBeforeUpdate!=\"function\"||_e===v.memoizedProps&&Xt===v.memoizedState||(D.flags|=256),D.memoizedProps=H,D.memoizedState=yi),Se.props=H,Se.state=yi,Se.context=pt,H=Wt):(typeof Se.componentDidUpdate!=\"function\"||_e===v.memoizedProps&&Xt===v.memoizedState||(D.flags|=4),typeof Se.getSnapshotBeforeUpdate!=\"function\"||_e===v.memoizedProps&&Xt===v.memoizedState||(D.flags|=256),H=!1)}return t2(v,D,Q,H,ne,V)}function t2(v,D,Q,H,V,ne){Cs(v,D);var Se=(D.flags&64)!==0;if(!H&&!Se)return V&&Ma(D,Q,!1),qn(v,D,ne);H=D.stateNode,de.current=D;var _e=Se&&typeof Q.getDerivedStateFromError!=\"function\"?null:H.render();return D.flags|=1,v!==null&&Se?(D.child=Mg(D,v.child,null,ne),D.child=Mg(D,null,_e,ne)):At(v,D,_e,ne),D.memoizedState=H.state,V&&Ma(D,Q,!0),D.child}function Py(v){var D=v.stateNode;D.pendingContext?yh(v,D.pendingContext,D.pendingContext!==D.context):D.context&&yh(v,D.context,!1),Ug(v,D.containerInfo)}var kh={dehydrated:null,retryLane:0};function r2(v,D,Q){var H=D.pendingProps,V=di.current,ne=!1,Se;return(Se=(D.flags&64)!==0)||(Se=v!==null&&v.memoizedState===null?!1:(V&2)!==0),Se?(ne=!0,D.flags&=-65):v!==null&&v.memoizedState===null||H.fallback===void 0||H.unstable_avoidThisFallback===!0||(V|=1),xn(di,V&1),v===null?(H.fallback!==void 0&&Hg(D),v=H.children,V=H.fallback,ne?(v=Va(D,v,V,Q),D.child.memoizedState={baseLanes:Q},D.memoizedState=kh,v):typeof H.unstable_expectedLoadTime==\"number\"?(v=Va(D,v,V,Q),D.child.memoizedState={baseLanes:Q},D.memoizedState=kh,D.lanes=33554432,v):(Q=D2({mode:\"visible\",children:v},D.mode,Q,null),Q.return=D,D.child=Q)):v.memoizedState!==null?ne?(H=KA(v,D,H.children,H.fallback,Q),ne=D.child,V=v.child.memoizedState,ne.memoizedState=V===null?{baseLanes:Q}:{baseLanes:V.baseLanes|Q},ne.childLanes=v.childLanes&~Q,D.memoizedState=kh,H):(Q=n2(v,D,H.children,Q),D.memoizedState=null,Q):ne?(H=KA(v,D,H.children,H.fallback,Q),ne=D.child,V=v.child.memoizedState,ne.memoizedState=V===null?{baseLanes:Q}:{baseLanes:V.baseLanes|Q},ne.childLanes=v.childLanes&~Q,D.memoizedState=kh,H):(Q=n2(v,D,H.children,Q),D.memoizedState=null,Q)}function Va(v,D,Q,H){var V=v.mode,ne=v.child;return D={mode:\"hidden\",children:D},!(V&2)&&ne!==null?(ne.childLanes=0,ne.pendingProps=D):ne=D2(D,V,0,null),Q=kf(Q,V,H,null),ne.return=v,Q.return=v,ne.sibling=Q,v.child=ne,Q}function n2(v,D,Q,H){var V=v.child;return v=V.sibling,Q=Su(V,{mode:\"visible\",children:Q}),!(D.mode&2)&&(Q.lanes=H),Q.return=D,Q.sibling=null,v!==null&&(v.nextEffect=null,v.flags=8,D.firstEffect=D.lastEffect=v),D.child=Q}function KA(v,D,Q,H,V){var ne=D.mode,Se=v.child;v=Se.sibling;var _e={mode:\"hidden\",children:Q};return!(ne&2)&&D.child!==Se?(Q=D.child,Q.childLanes=0,Q.pendingProps=_e,Se=Q.lastEffect,Se!==null?(D.firstEffect=Q.firstEffect,D.lastEffect=Se,Se.nextEffect=null):D.firstEffect=D.lastEffect=null):Q=Su(Se,_e),v!==null?H=Su(v,H):(H=kf(H,ne,V,null),H.flags|=2),H.return=D,Q.return=D,Q.sibling=H,D.child=Q,H}function Qh(v,D){v.lanes|=D;var Q=v.alternate;Q!==null&&(Q.lanes|=D),Ey(v.return,D)}function by(v,D,Q,H,V,ne){var Se=v.memoizedState;Se===null?v.memoizedState={isBackwards:D,rendering:null,renderingStartTime:0,last:H,tail:Q,tailMode:V,lastEffect:ne}:(Se.isBackwards=D,Se.rendering=null,Se.renderingStartTime=0,Se.last=H,Se.tail=Q,Se.tailMode=V,Se.lastEffect=ne)}function lb(v,D,Q){var H=D.pendingProps,V=H.revealOrder,ne=H.tail;if(At(v,D,H.children,Q),H=di.current,H&2)H=H&1|2,D.flags|=64;else{if(v!==null&&v.flags&64)e:for(v=D.child;v!==null;){if(v.tag===13)v.memoizedState!==null&&Qh(v,Q);else if(v.tag===19)Qh(v,Q);else if(v.child!==null){v.child.return=v,v=v.child;continue}if(v===D)break e;for(;v.sibling===null;){if(v.return===null||v.return===D)break e;v=v.return}v.sibling.return=v.return,v=v.sibling}H&=1}if(xn(di,H),!(D.mode&2))D.memoizedState=null;else switch(V){case\"forwards\":for(Q=D.child,V=null;Q!==null;)v=Q.alternate,v!==null&&GA(v)===null&&(V=Q),Q=Q.sibling;Q=V,Q===null?(V=D.child,D.child=null):(V=Q.sibling,Q.sibling=null),by(D,!1,V,Q,ne,D.lastEffect);break;case\"backwards\":for(Q=null,V=D.child,D.child=null;V!==null;){if(v=V.alternate,v!==null&&GA(v)===null){D.child=V;break}v=V.sibling,V.sibling=Q,Q=V,V=v}by(D,!0,Q,null,ne,D.lastEffect);break;case\"together\":by(D,!1,null,null,void 0,D.lastEffect);break;default:D.memoizedState=null}return D.child}function qn(v,D,Q){if(v!==null&&(D.dependencies=v.dependencies),Xg|=D.lanes,Q&D.childLanes){if(v!==null&&D.child!==v.child)throw Error(c(153));if(D.child!==null){for(v=D.child,Q=Su(v,v.pendingProps),D.child=Q,Q.return=D;v.sibling!==null;)v=v.sibling,Q=Q.sibling=Su(v,v.pendingProps),Q.return=D;Q.sibling=null}return D.child}return null}function ss(v){v.flags|=4}var kl,Ql,Cu,ha;if(F)kl=function(v,D){for(var Q=D.child;Q!==null;){if(Q.tag===5||Q.tag===6)be(v,Q.stateNode);else if(Q.tag!==4&&Q.child!==null){Q.child.return=Q,Q=Q.child;continue}if(Q===D)break;for(;Q.sibling===null;){if(Q.return===null||Q.return===D)return;Q=Q.return}Q.sibling.return=Q.return,Q=Q.sibling}},Ql=function(){},Cu=function(v,D,Q,H,V){if(v=v.memoizedProps,v!==H){var ne=D.stateNode,Se=qa(ur.current);Q=ke(ne,Q,v,H,V,Se),(D.updateQueue=Q)&&ss(D)}},ha=function(v,D,Q,H){Q!==H&&ss(D)};else if(z){kl=function(v,D,Q,H){for(var V=D.child;V!==null;){if(V.tag===5){var ne=V.stateNode;Q&&H&&(ne=TA(ne,V.type,V.memoizedProps,V)),be(v,ne)}else if(V.tag===6)ne=V.stateNode,Q&&H&&(ne=oa(ne,V.memoizedProps,V)),be(v,ne);else if(V.tag!==4){if(V.tag===13&&V.flags&4&&(ne=V.memoizedState!==null)){var Se=V.child;if(Se!==null&&(Se.child!==null&&(Se.child.return=Se,kl(v,Se,!0,ne)),ne=Se.sibling,ne!==null)){ne.return=V,V=ne;continue}}if(V.child!==null){V.child.return=V,V=V.child;continue}}if(V===D)break;for(;V.sibling===null;){if(V.return===null||V.return===D)return;V=V.return}V.sibling.return=V.return,V=V.sibling}};var zA=function(v,D,Q,H){for(var V=D.child;V!==null;){if(V.tag===5){var ne=V.stateNode;Q&&H&&(ne=TA(ne,V.type,V.memoizedProps,V)),au(v,ne)}else if(V.tag===6)ne=V.stateNode,Q&&H&&(ne=oa(ne,V.memoizedProps,V)),au(v,ne);else if(V.tag!==4){if(V.tag===13&&V.flags&4&&(ne=V.memoizedState!==null)){var Se=V.child;if(Se!==null&&(Se.child!==null&&(Se.child.return=Se,zA(v,Se,!0,ne)),ne=Se.sibling,ne!==null)){ne.return=V,V=ne;continue}}if(V.child!==null){V.child.return=V,V=V.child;continue}}if(V===D)break;for(;V.sibling===null;){if(V.return===null||V.return===D)return;V=V.return}V.sibling.return=V.return,V=V.sibling}};Ql=function(v){var D=v.stateNode;if(v.firstEffect!==null){var Q=D.containerInfo,H=ou(Q);zA(H,v,!1,!1),D.pendingChildren=H,ss(v),lu(Q,H)}},Cu=function(v,D,Q,H,V){var ne=v.stateNode,Se=v.memoizedProps;if((v=D.firstEffect===null)&&Se===H)D.stateNode=ne;else{var _e=D.stateNode,pt=qa(ur.current),Wt=null;Se!==H&&(Wt=ke(_e,Q,Se,H,V,pt)),v&&Wt===null?D.stateNode=ne:(ne=ro(ne,Wt,Q,Se,H,D,v,_e),Ve(ne,Q,H,V,pt)&&ss(D),D.stateNode=ne,v?ss(D):kl(ne,D,!1,!1))}},ha=function(v,D,Q,H){Q!==H?(v=qa(yf.current),Q=qa(ur.current),D.stateNode=Ue(H,v,Q,D),ss(D)):D.stateNode=v.stateNode}}else Ql=function(){},Cu=function(){},ha=function(){};function ZA(v,D){if(!Ya)switch(v.tailMode){case\"hidden\":D=v.tail;for(var Q=null;D!==null;)D.alternate!==null&&(Q=D),D=D.sibling;Q===null?v.tail=null:Q.sibling=null;break;case\"collapsed\":Q=v.tail;for(var H=null;Q!==null;)Q.alternate!==null&&(H=Q),Q=Q.sibling;H===null?D||v.tail===null?v.tail=null:v.tail.sibling=null:H.sibling=null}}function HL(v,D,Q){var H=D.pendingProps;switch(D.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return null;case 1:return Kn(D.type)&&Au(),null;case 3:return du(),Tt(Li),Tt(ji),yu(),H=D.stateNode,H.pendingContext&&(H.context=H.pendingContext,H.pendingContext=null),(v===null||v.child===null)&&(qA(D)?ss(D):H.hydrate||(D.flags|=256)),Ql(D),null;case 5:wt(D);var V=qa(yf.current);if(Q=D.type,v!==null&&D.stateNode!=null)Cu(v,D,Q,H,V),v.ref!==D.ref&&(D.flags|=128);else{if(!H){if(D.stateNode===null)throw Error(c(166));return null}if(v=qa(ur.current),qA(D)){if(!Z)throw Error(c(175));v=Cr(D.stateNode,D.type,D.memoizedProps,V,v,D),D.updateQueue=v,v!==null&&ss(D)}else{var ne=Ne(Q,H,V,v,D);kl(ne,D,!1,!1),D.stateNode=ne,Ve(ne,Q,H,V,v)&&ss(D)}D.ref!==null&&(D.flags|=128)}return null;case 6:if(v&&D.stateNode!=null)ha(v,D,v.memoizedProps,H);else{if(typeof H!=\"string\"&&D.stateNode===null)throw Error(c(166));if(v=qa(yf.current),V=qa(ur.current),qA(D)){if(!Z)throw Error(c(176));pf(D.stateNode,D.memoizedProps,D)&&ss(D)}else D.stateNode=Ue(H,v,V,D)}return null;case 13:return Tt(di),H=D.memoizedState,D.flags&64?(D.lanes=Q,D):(H=H!==null,V=!1,v===null?D.memoizedProps.fallback!==void 0&&qA(D):V=v.memoizedState!==null,H&&!V&&D.mode&2&&(v===null&&D.memoizedProps.unstable_avoidThisFallback!==!0||di.current&1?ws===0&&(ws=3):((ws===0||ws===3)&&(ws=4),so===null||!(Xg&134217727)&&!(Fh&134217727)||Nh(so,Ns))),z&&H&&(D.flags|=4),F&&(H||V)&&(D.flags|=4),null);case 4:return du(),Ql(D),v===null&&Ct(D.stateNode.containerInfo),null;case 10:return Og(D),null;case 17:return Kn(D.type)&&Au(),null;case 19:if(Tt(di),H=D.memoizedState,H===null)return null;if(V=(D.flags&64)!==0,ne=H.rendering,ne===null)if(V)ZA(H,!1);else{if(ws!==0||v!==null&&v.flags&64)for(v=D.child;v!==null;){if(ne=GA(v),ne!==null){for(D.flags|=64,ZA(H,!1),v=ne.updateQueue,v!==null&&(D.updateQueue=v,D.flags|=4),H.lastEffect===null&&(D.firstEffect=null),D.lastEffect=H.lastEffect,v=Q,H=D.child;H!==null;)V=H,Q=v,V.flags&=2,V.nextEffect=null,V.firstEffect=null,V.lastEffect=null,ne=V.alternate,ne===null?(V.childLanes=0,V.lanes=Q,V.child=null,V.memoizedProps=null,V.memoizedState=null,V.updateQueue=null,V.dependencies=null,V.stateNode=null):(V.childLanes=ne.childLanes,V.lanes=ne.lanes,V.child=ne.child,V.memoizedProps=ne.memoizedProps,V.memoizedState=ne.memoizedState,V.updateQueue=ne.updateQueue,V.type=ne.type,Q=ne.dependencies,V.dependencies=Q===null?null:{lanes:Q.lanes,firstContext:Q.firstContext}),H=H.sibling;return xn(di,di.current&1|2),D.child}v=v.sibling}H.tail!==null&&Pt()>m2&&(D.flags|=64,V=!0,ZA(H,!1),D.lanes=33554432)}else{if(!V)if(v=GA(ne),v!==null){if(D.flags|=64,V=!0,v=v.updateQueue,v!==null&&(D.updateQueue=v,D.flags|=4),ZA(H,!0),H.tail===null&&H.tailMode===\"hidden\"&&!ne.alternate&&!Ya)return D=D.lastEffect=H.lastEffect,D!==null&&(D.nextEffect=null),null}else 2*Pt()-H.renderingStartTime>m2&&Q!==1073741824&&(D.flags|=64,V=!0,ZA(H,!1),D.lanes=33554432);H.isBackwards?(ne.sibling=D.child,D.child=ne):(v=H.last,v!==null?v.sibling=ne:D.child=ne,H.last=ne)}return H.tail!==null?(v=H.tail,H.rendering=v,H.tail=v.sibling,H.lastEffect=D.lastEffect,H.renderingStartTime=Pt(),v.sibling=null,D=di.current,xn(di,V?D&1|2:D&1),v):null;case 23:case 24:return B2(),v!==null&&v.memoizedState!==null!=(D.memoizedState!==null)&&H.mode!==\"unstable-defer-without-hiding\"&&(D.flags|=4),null}throw Error(c(156,D.tag))}function jL(v){switch(v.tag){case 1:Kn(v.type)&&Au();var D=v.flags;return D&4096?(v.flags=D&-4097|64,v):null;case 3:if(du(),Tt(Li),Tt(ji),yu(),D=v.flags,D&64)throw Error(c(285));return v.flags=D&-4097|64,v;case 5:return wt(v),null;case 13:return Tt(di),D=v.flags,D&4096?(v.flags=D&-4097|64,v):null;case 19:return Tt(di),null;case 4:return du(),null;case 10:return Og(v),null;case 23:case 24:return B2(),null;default:return null}}function Yg(v,D){try{var Q=\"\",H=D;do Q+=$1(H),H=H.return;while(H);var V=Q}catch(ne){V=`\nError generating stack: `+ne.message+`\n`+ne.stack}return{value:v,source:D,stack:V}}function Vg(v,D){try{console.error(D.value)}catch(Q){setTimeout(function(){throw Q})}}var qL=typeof WeakMap==\"function\"?WeakMap:Map;function i2(v,D,Q){Q=Dl(-1,Q),Q.tag=3,Q.payload={element:null};var H=D.value;return Q.callback=function(){_y||(_y=!0,y2=H),Vg(v,D)},Q}function Jg(v,D,Q){Q=Dl(-1,Q),Q.tag=3;var H=v.type.getDerivedStateFromError;if(typeof H==\"function\"){var V=D.value;Q.payload=function(){return Vg(v,D),H(V)}}var ne=v.stateNode;return ne!==null&&typeof ne.componentDidCatch==\"function\"&&(Q.callback=function(){typeof H!=\"function\"&&(hc===null?hc=new Set([this]):hc.add(this),Vg(v,D));var Se=D.stack;this.componentDidCatch(D.value,{componentStack:Se!==null?Se:\"\"})}),Q}var WL=typeof WeakSet==\"function\"?WeakSet:Set;function s2(v){var D=v.ref;if(D!==null)if(typeof D==\"function\")try{D(null)}catch(Q){xf(v,Q)}else D.current=null}function xy(v,D){switch(D.tag){case 0:case 11:case 15:case 22:return;case 1:if(D.flags&256&&v!==null){var Q=v.memoizedProps,H=v.memoizedState;v=D.stateNode,D=v.getSnapshotBeforeUpdate(D.elementType===D.type?Q:So(D.type,Q),H),v.__reactInternalSnapshotBeforeUpdate=D}return;case 3:F&&D.flags&256&&Rs(D.stateNode.containerInfo);return;case 5:case 6:case 4:case 17:return}throw Error(c(163))}function Rh(v,D){if(D=D.updateQueue,D=D!==null?D.lastEffect:null,D!==null){var Q=D=D.next;do{if((Q.tag&v)===v){var H=Q.destroy;Q.destroy=void 0,H!==void 0&&H()}Q=Q.next}while(Q!==D)}}function ub(v,D,Q){switch(Q.tag){case 0:case 11:case 15:case 22:if(D=Q.updateQueue,D=D!==null?D.lastEffect:null,D!==null){v=D=D.next;do{if((v.tag&3)===3){var H=v.create;v.destroy=H()}v=v.next}while(v!==D)}if(D=Q.updateQueue,D=D!==null?D.lastEffect:null,D!==null){v=D=D.next;do{var V=v;H=V.next,V=V.tag,V&4&&V&1&&(vb(Q,v),eM(Q,v)),v=H}while(v!==D)}return;case 1:v=Q.stateNode,Q.flags&4&&(D===null?v.componentDidMount():(H=Q.elementType===Q.type?D.memoizedProps:So(Q.type,D.memoizedProps),v.componentDidUpdate(H,D.memoizedState,v.__reactInternalSnapshotBeforeUpdate))),D=Q.updateQueue,D!==null&&Cy(Q,D,v);return;case 3:if(D=Q.updateQueue,D!==null){if(v=null,Q.child!==null)switch(Q.child.tag){case 5:v=Te(Q.child.stateNode);break;case 1:v=Q.child.stateNode}Cy(Q,D,v)}return;case 5:v=Q.stateNode,D===null&&Q.flags&4&&$s(v,Q.type,Q.memoizedProps,Q);return;case 6:return;case 4:return;case 12:return;case 13:Z&&Q.memoizedState===null&&(Q=Q.alternate,Q!==null&&(Q=Q.memoizedState,Q!==null&&(Q=Q.dehydrated,Q!==null&&uu(Q))));return;case 19:case 17:case 20:case 21:case 23:case 24:return}throw Error(c(163))}function fb(v,D){if(F)for(var Q=v;;){if(Q.tag===5){var H=Q.stateNode;D?dh(H):to(Q.stateNode,Q.memoizedProps)}else if(Q.tag===6)H=Q.stateNode,D?mh(H):jn(H,Q.memoizedProps);else if((Q.tag!==23&&Q.tag!==24||Q.memoizedState===null||Q===v)&&Q.child!==null){Q.child.return=Q,Q=Q.child;continue}if(Q===v)break;for(;Q.sibling===null;){if(Q.return===null||Q.return===v)return;Q=Q.return}Q.sibling.return=Q.return,Q=Q.sibling}}function ky(v,D){if(Ua&&typeof Ua.onCommitFiberUnmount==\"function\")try{Ua.onCommitFiberUnmount($e,D)}catch{}switch(D.tag){case 0:case 11:case 14:case 15:case 22:if(v=D.updateQueue,v!==null&&(v=v.lastEffect,v!==null)){var Q=v=v.next;do{var H=Q,V=H.destroy;if(H=H.tag,V!==void 0)if(H&4)vb(D,Q);else{H=D;try{V()}catch(ne){xf(H,ne)}}Q=Q.next}while(Q!==v)}break;case 1:if(s2(D),v=D.stateNode,typeof v.componentWillUnmount==\"function\")try{v.props=D.memoizedProps,v.state=D.memoizedState,v.componentWillUnmount()}catch(ne){xf(D,ne)}break;case 5:s2(D);break;case 4:F?gb(v,D):z&&z&&(D=D.stateNode.containerInfo,v=ou(D),RA(D,v))}}function Ab(v,D){for(var Q=D;;)if(ky(v,Q),Q.child===null||F&&Q.tag===4){if(Q===D)break;for(;Q.sibling===null;){if(Q.return===null||Q.return===D)return;Q=Q.return}Q.sibling.return=Q.return,Q=Q.sibling}else Q.child.return=Q,Q=Q.child}function Qy(v){v.alternate=null,v.child=null,v.dependencies=null,v.firstEffect=null,v.lastEffect=null,v.memoizedProps=null,v.memoizedState=null,v.pendingProps=null,v.return=null,v.updateQueue=null}function pb(v){return v.tag===5||v.tag===3||v.tag===4}function hb(v){if(F){e:{for(var D=v.return;D!==null;){if(pb(D))break e;D=D.return}throw Error(c(160))}var Q=D;switch(D=Q.stateNode,Q.tag){case 5:var H=!1;break;case 3:D=D.containerInfo,H=!0;break;case 4:D=D.containerInfo,H=!0;break;default:throw Error(c(161))}Q.flags&16&&(Af(D),Q.flags&=-17);e:t:for(Q=v;;){for(;Q.sibling===null;){if(Q.return===null||pb(Q.return)){Q=null;break e}Q=Q.return}for(Q.sibling.return=Q.return,Q=Q.sibling;Q.tag!==5&&Q.tag!==6&&Q.tag!==18;){if(Q.flags&2||Q.child===null||Q.tag===4)continue t;Q.child.return=Q,Q=Q.child}if(!(Q.flags&2)){Q=Q.stateNode;break e}}H?o2(v,Q,D):a2(v,Q,D)}}function o2(v,D,Q){var H=v.tag,V=H===5||H===6;if(V)v=V?v.stateNode:v.stateNode.instance,D?eo(Q,v,D):Io(Q,v);else if(H!==4&&(v=v.child,v!==null))for(o2(v,D,Q),v=v.sibling;v!==null;)o2(v,D,Q),v=v.sibling}function a2(v,D,Q){var H=v.tag,V=H===5||H===6;if(V)v=V?v.stateNode:v.stateNode.instance,D?Hi(Q,v,D):ai(Q,v);else if(H!==4&&(v=v.child,v!==null))for(a2(v,D,Q),v=v.sibling;v!==null;)a2(v,D,Q),v=v.sibling}function gb(v,D){for(var Q=D,H=!1,V,ne;;){if(!H){H=Q.return;e:for(;;){if(H===null)throw Error(c(160));switch(V=H.stateNode,H.tag){case 5:ne=!1;break e;case 3:V=V.containerInfo,ne=!0;break e;case 4:V=V.containerInfo,ne=!0;break e}H=H.return}H=!0}if(Q.tag===5||Q.tag===6)Ab(v,Q),ne?QA(V,Q.stateNode):wo(V,Q.stateNode);else if(Q.tag===4){if(Q.child!==null){V=Q.stateNode.containerInfo,ne=!0,Q.child.return=Q,Q=Q.child;continue}}else if(ky(v,Q),Q.child!==null){Q.child.return=Q,Q=Q.child;continue}if(Q===D)break;for(;Q.sibling===null;){if(Q.return===null||Q.return===D)return;Q=Q.return,Q.tag===4&&(H=!1)}Q.sibling.return=Q.return,Q=Q.sibling}}function l2(v,D){if(F){switch(D.tag){case 0:case 11:case 14:case 15:case 22:Rh(3,D);return;case 1:return;case 5:var Q=D.stateNode;if(Q!=null){var H=D.memoizedProps;v=v!==null?v.memoizedProps:H;var V=D.type,ne=D.updateQueue;D.updateQueue=null,ne!==null&&Co(Q,ne,V,v,H,D)}return;case 6:if(D.stateNode===null)throw Error(c(162));Q=D.memoizedProps,ts(D.stateNode,v!==null?v.memoizedProps:Q,Q);return;case 3:Z&&(D=D.stateNode,D.hydrate&&(D.hydrate=!1,OA(D.containerInfo)));return;case 12:return;case 13:db(D),Kg(D);return;case 19:Kg(D);return;case 17:return;case 23:case 24:fb(D,D.memoizedState!==null);return}throw Error(c(163))}switch(D.tag){case 0:case 11:case 14:case 15:case 22:Rh(3,D);return;case 12:return;case 13:db(D),Kg(D);return;case 19:Kg(D);return;case 3:Z&&(Q=D.stateNode,Q.hydrate&&(Q.hydrate=!1,OA(Q.containerInfo)));break;case 23:case 24:return}e:if(z){switch(D.tag){case 1:case 5:case 6:case 20:break e;case 3:case 4:D=D.stateNode,RA(D.containerInfo,D.pendingChildren);break e}throw Error(c(163))}}function db(v){v.memoizedState!==null&&(d2=Pt(),F&&fb(v.child,!0))}function Kg(v){var D=v.updateQueue;if(D!==null){v.updateQueue=null;var Q=v.stateNode;Q===null&&(Q=v.stateNode=new WL),D.forEach(function(H){var V=rM.bind(null,v,H);Q.has(H)||(Q.add(H),H.then(V,V))})}}function YL(v,D){return v!==null&&(v=v.memoizedState,v===null||v.dehydrated!==null)?(D=D.memoizedState,D!==null&&D.dehydrated===null):!1}var Ry=0,Ty=1,Fy=2,zg=3,Ny=4;if(typeof Symbol==\"function\"&&Symbol.for){var Zg=Symbol.for;Ry=Zg(\"selector.component\"),Ty=Zg(\"selector.has_pseudo_class\"),Fy=Zg(\"selector.role\"),zg=Zg(\"selector.test_id\"),Ny=Zg(\"selector.text\")}function Oy(v){var D=$(v);if(D!=null){if(typeof D.memoizedProps[\"data-testname\"]!=\"string\")throw Error(c(364));return D}if(v=ir(v),v===null)throw Error(c(362));return v.stateNode.current}function Sf(v,D){switch(D.$$typeof){case Ry:if(v.type===D.value)return!0;break;case Ty:e:{D=D.value,v=[v,0];for(var Q=0;Q<v.length;){var H=v[Q++],V=v[Q++],ne=D[V];if(H.tag!==5||!br(H)){for(;ne!=null&&Sf(H,ne);)V++,ne=D[V];if(V===D.length){D=!0;break e}else for(H=H.child;H!==null;)v.push(H,V),H=H.sibling}}D=!1}return D;case Fy:if(v.tag===5&&Ir(v.stateNode,D.value))return!0;break;case Ny:if((v.tag===5||v.tag===6)&&(v=gn(v),v!==null&&0<=v.indexOf(D.value)))return!0;break;case zg:if(v.tag===5&&(v=v.memoizedProps[\"data-testname\"],typeof v==\"string\"&&v.toLowerCase()===D.value.toLowerCase()))return!0;break;default:throw Error(c(365,D))}return!1}function Df(v){switch(v.$$typeof){case Ry:return\"<\"+(g(v.value)||\"Unknown\")+\">\";case Ty:return\":has(\"+(Df(v)||\"\")+\")\";case Fy:return'[role=\"'+v.value+'\"]';case Ny:return'\"'+v.value+'\"';case zg:return'[data-testname=\"'+v.value+'\"]';default:throw Error(c(365,v))}}function c2(v,D){var Q=[];v=[v,0];for(var H=0;H<v.length;){var V=v[H++],ne=v[H++],Se=D[ne];if(V.tag!==5||!br(V)){for(;Se!=null&&Sf(V,Se);)ne++,Se=D[ne];if(ne===D.length)Q.push(V);else for(V=V.child;V!==null;)v.push(V,ne),V=V.sibling}}return Q}function u2(v,D){if(!qt)throw Error(c(363));v=Oy(v),v=c2(v,D),D=[],v=Array.from(v);for(var Q=0;Q<v.length;){var H=v[Q++];if(H.tag===5)br(H)||D.push(H.stateNode);else for(H=H.child;H!==null;)v.push(H),H=H.sibling}return D}var Ly=null;function VL(v){if(Ly===null)try{var D=(\"require\"+Math.random()).slice(0,7);Ly=(jS&&jS[D]).call(jS,\"timers\").setImmediate}catch{Ly=function(H){var V=new MessageChannel;V.port1.onmessage=H,V.port2.postMessage(void 0)}}return Ly(v)}var JL=Math.ceil,My=f.ReactCurrentDispatcher,f2=f.ReactCurrentOwner,A2=f.IsSomeRendererActing,xr=0,so=null,zi=null,Ns=0,XA=0,p2=no(0),ws=0,Uy=null,Th=0,Xg=0,Fh=0,h2=0,g2=null,d2=0,m2=1/0;function Pf(){m2=Pt()+500}var sr=null,_y=!1,y2=null,hc=null,bf=!1,$g=null,ed=90,E2=[],I2=[],wu=null,td=0,C2=null,Hy=-1,Bu=0,jy=0,rd=null,nd=!1;function ko(){return xr&48?Pt():Hy!==-1?Hy:Hy=Pt()}function Bs(v){if(v=v.mode,!(v&2))return 1;if(!(v&4))return tr()===99?1:2;if(Bu===0&&(Bu=Th),my.transition!==0){jy!==0&&(jy=g2!==null?g2.pendingLanes:0),v=Bu;var D=4186112&~jy;return D&=-D,D===0&&(v=4186112&~v,D=v&-v,D===0&&(D=8192)),D}return v=tr(),xr&4&&v===98?v=Mt(12,Bu):(v=LA(v),v=Mt(v,Bu)),v}function Rl(v,D,Q){if(50<td)throw td=0,C2=null,Error(c(185));if(v=Gy(v,D),v===null)return null;Ha(v,D,Q),v===so&&(Fh|=D,ws===4&&Nh(v,Ns));var H=tr();D===1?xr&8&&!(xr&48)?w2(v):(ga(v,Q),xr===0&&(Pf(),Rn())):(!(xr&4)||H!==98&&H!==99||(wu===null?wu=new Set([v]):wu.add(v)),ga(v,Q)),g2=v}function Gy(v,D){v.lanes|=D;var Q=v.alternate;for(Q!==null&&(Q.lanes|=D),Q=v,v=v.return;v!==null;)v.childLanes|=D,Q=v.alternate,Q!==null&&(Q.childLanes|=D),Q=v,v=v.return;return Q.tag===3?Q.stateNode:null}function ga(v,D){for(var Q=v.callbackNode,H=v.suspendedLanes,V=v.pingedLanes,ne=v.expirationTimes,Se=v.pendingLanes;0<Se;){var _e=31-rs(Se),pt=1<<_e,Wt=ne[_e];if(Wt===-1){if(!(pt&H)||pt&V){Wt=D,ca(pt);var Sr=wn;ne[_e]=10<=Sr?Wt+250:6<=Sr?Wt+5e3:-1}}else Wt<=D&&(v.expiredLanes|=pt);Se&=~pt}if(H=ua(v,v===so?Ns:0),D=wn,H===0)Q!==null&&(Q!==lr&&Is(Q),v.callbackNode=null,v.callbackPriority=0);else{if(Q!==null){if(v.callbackPriority===D)return;Q!==lr&&Is(Q)}D===15?(Q=w2.bind(null,v),Ee===null?(Ee=[Q],Oe=Mi(Qn,Ga)):Ee.push(Q),Q=lr):D===14?Q=Gi(99,w2.bind(null,v)):(Q=MA(D),Q=Gi(Q,mb.bind(null,v))),v.callbackPriority=D,v.callbackNode=Q}}function mb(v){if(Hy=-1,jy=Bu=0,xr&48)throw Error(c(327));var D=v.callbackNode;if(vu()&&v.callbackNode!==D)return null;var Q=ua(v,v===so?Ns:0);if(Q===0)return null;var H=Q,V=xr;xr|=16;var ne=Cb();(so!==v||Ns!==H)&&(Pf(),Oh(v,H));do try{ZL();break}catch(_e){Ib(v,_e)}while(!0);if(Fg(),My.current=ne,xr=V,zi!==null?H=0:(so=null,Ns=0,H=ws),Th&Fh)Oh(v,0);else if(H!==0){if(H===2&&(xr|=64,v.hydrate&&(v.hydrate=!1,Rs(v.containerInfo)),Q=Bl(v),Q!==0&&(H=id(v,Q))),H===1)throw D=Uy,Oh(v,0),Nh(v,Q),ga(v,Pt()),D;switch(v.finishedWork=v.current.alternate,v.finishedLanes=Q,H){case 0:case 1:throw Error(c(345));case 2:$A(v);break;case 3:if(Nh(v,Q),(Q&62914560)===Q&&(H=d2+500-Pt(),10<H)){if(ua(v,0)!==0)break;if(V=v.suspendedLanes,(V&Q)!==Q){ko(),v.pingedLanes|=v.suspendedLanes&V;break}v.timeoutHandle=x($A.bind(null,v),H);break}$A(v);break;case 4:if(Nh(v,Q),(Q&4186112)===Q)break;for(H=v.eventTimes,V=-1;0<Q;){var Se=31-rs(Q);ne=1<<Se,Se=H[Se],Se>V&&(V=Se),Q&=~ne}if(Q=V,Q=Pt()-Q,Q=(120>Q?120:480>Q?480:1080>Q?1080:1920>Q?1920:3e3>Q?3e3:4320>Q?4320:1960*JL(Q/1960))-Q,10<Q){v.timeoutHandle=x($A.bind(null,v),Q);break}$A(v);break;case 5:$A(v);break;default:throw Error(c(329))}}return ga(v,Pt()),v.callbackNode===D?mb.bind(null,v):null}function Nh(v,D){for(D&=~h2,D&=~Fh,v.suspendedLanes|=D,v.pingedLanes&=~D,v=v.expirationTimes;0<D;){var Q=31-rs(D),H=1<<Q;v[Q]=-1,D&=~H}}function w2(v){if(xr&48)throw Error(c(327));if(vu(),v===so&&v.expiredLanes&Ns){var D=Ns,Q=id(v,D);Th&Fh&&(D=ua(v,D),Q=id(v,D))}else D=ua(v,0),Q=id(v,D);if(v.tag!==0&&Q===2&&(xr|=64,v.hydrate&&(v.hydrate=!1,Rs(v.containerInfo)),D=Bl(v),D!==0&&(Q=id(v,D))),Q===1)throw Q=Uy,Oh(v,0),Nh(v,D),ga(v,Pt()),Q;return v.finishedWork=v.current.alternate,v.finishedLanes=D,$A(v),ga(v,Pt()),null}function KL(){if(wu!==null){var v=wu;wu=null,v.forEach(function(D){D.expiredLanes|=24&D.pendingLanes,ga(D,Pt())})}Rn()}function yb(v,D){var Q=xr;xr|=1;try{return v(D)}finally{xr=Q,xr===0&&(Pf(),Rn())}}function Eb(v,D){var Q=xr;if(Q&48)return v(D);xr|=1;try{if(v)return li(99,v.bind(null,D))}finally{xr=Q,Rn()}}function qy(v,D){xn(p2,XA),XA|=D,Th|=D}function B2(){XA=p2.current,Tt(p2)}function Oh(v,D){v.finishedWork=null,v.finishedLanes=0;var Q=v.timeoutHandle;if(Q!==P&&(v.timeoutHandle=P,w(Q)),zi!==null)for(Q=zi.return;Q!==null;){var H=Q;switch(H.tag){case 1:H=H.type.childContextTypes,H!=null&&Au();break;case 3:du(),Tt(Li),Tt(ji),yu();break;case 5:wt(H);break;case 4:du();break;case 13:Tt(di);break;case 19:Tt(di);break;case 10:Og(H);break;case 23:case 24:B2()}Q=Q.return}so=v,zi=Su(v.current,null),Ns=XA=Th=D,ws=0,Uy=null,h2=Fh=Xg=0}function Ib(v,D){do{var Q=zi;try{if(Fg(),If.current=kt,WA){for(var H=Gn.memoizedState;H!==null;){var V=H.queue;V!==null&&(V.pending=null),H=H.next}WA=!1}if(Eu=0,bi=ns=Gn=null,Cf=!1,f2.current=null,Q===null||Q.return===null){ws=1,Uy=D,zi=null;break}e:{var ne=v,Se=Q.return,_e=Q,pt=D;if(D=Ns,_e.flags|=2048,_e.firstEffect=_e.lastEffect=null,pt!==null&&typeof pt==\"object\"&&typeof pt.then==\"function\"){var Wt=pt;if(!(_e.mode&2)){var Sr=_e.alternate;Sr?(_e.updateQueue=Sr.updateQueue,_e.memoizedState=Sr.memoizedState,_e.lanes=Sr.lanes):(_e.updateQueue=null,_e.memoizedState=null)}var Lr=(di.current&1)!==0,Xt=Se;do{var zn;if(zn=Xt.tag===13){var yi=Xt.memoizedState;if(yi!==null)zn=yi.dehydrated!==null;else{var za=Xt.memoizedProps;zn=za.fallback===void 0?!1:za.unstable_avoidThisFallback!==!0?!0:!Lr}}if(zn){var et=Xt.updateQueue;if(et===null){var qe=new Set;qe.add(Wt),Xt.updateQueue=qe}else et.add(Wt);if(!(Xt.mode&2)){if(Xt.flags|=64,_e.flags|=16384,_e.flags&=-2981,_e.tag===1)if(_e.alternate===null)_e.tag=17;else{var gt=Dl(-1,1);gt.tag=2,Pl(_e,gt)}_e.lanes|=1;break e}pt=void 0,_e=D;var Zt=ne.pingCache;if(Zt===null?(Zt=ne.pingCache=new qL,pt=new Set,Zt.set(Wt,pt)):(pt=Zt.get(Wt),pt===void 0&&(pt=new Set,Zt.set(Wt,pt))),!pt.has(_e)){pt.add(_e);var Dr=Db.bind(null,ne,Wt,_e);Wt.then(Dr,Dr)}Xt.flags|=4096,Xt.lanes=D;break e}Xt=Xt.return}while(Xt!==null);pt=Error((g(_e.type)||\"A React component\")+` suspended while rendering, but no fallback UI was specified.\n\nAdd a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.`)}ws!==5&&(ws=2),pt=Yg(pt,_e),Xt=Se;do{switch(Xt.tag){case 3:ne=pt,Xt.flags|=4096,D&=-D,Xt.lanes|=D;var Xn=i2(Xt,ne,D);Iy(Xt,Xn);break e;case 1:ne=pt;var kr=Xt.type,Tn=Xt.stateNode;if(!(Xt.flags&64)&&(typeof kr.getDerivedStateFromError==\"function\"||Tn!==null&&typeof Tn.componentDidCatch==\"function\"&&(hc===null||!hc.has(Tn)))){Xt.flags|=4096,D&=-D,Xt.lanes|=D;var _n=Jg(Xt,ne,D);Iy(Xt,_n);break e}}Xt=Xt.return}while(Xt!==null)}Bb(Q)}catch(zr){D=zr,zi===Q&&Q!==null&&(zi=Q=Q.return);continue}break}while(!0)}function Cb(){var v=My.current;return My.current=kt,v===null?kt:v}function id(v,D){var Q=xr;xr|=16;var H=Cb();so===v&&Ns===D||Oh(v,D);do try{zL();break}catch(V){Ib(v,V)}while(!0);if(Fg(),xr=Q,My.current=H,zi!==null)throw Error(c(261));return so=null,Ns=0,ws}function zL(){for(;zi!==null;)wb(zi)}function ZL(){for(;zi!==null&&!vl();)wb(zi)}function wb(v){var D=Pb(v.alternate,v,XA);v.memoizedProps=v.pendingProps,D===null?Bb(v):zi=D,f2.current=null}function Bb(v){var D=v;do{var Q=D.alternate;if(v=D.return,D.flags&2048){if(Q=jL(D),Q!==null){Q.flags&=2047,zi=Q;return}v!==null&&(v.firstEffect=v.lastEffect=null,v.flags|=2048)}else{if(Q=HL(Q,D,XA),Q!==null){zi=Q;return}if(Q=D,Q.tag!==24&&Q.tag!==23||Q.memoizedState===null||XA&1073741824||!(Q.mode&4)){for(var H=0,V=Q.child;V!==null;)H|=V.lanes|V.childLanes,V=V.sibling;Q.childLanes=H}v!==null&&!(v.flags&2048)&&(v.firstEffect===null&&(v.firstEffect=D.firstEffect),D.lastEffect!==null&&(v.lastEffect!==null&&(v.lastEffect.nextEffect=D.firstEffect),v.lastEffect=D.lastEffect),1<D.flags&&(v.lastEffect!==null?v.lastEffect.nextEffect=D:v.firstEffect=D,v.lastEffect=D))}if(D=D.sibling,D!==null){zi=D;return}zi=D=v}while(D!==null);ws===0&&(ws=5)}function $A(v){var D=tr();return li(99,XL.bind(null,v,D)),null}function XL(v,D){do vu();while($g!==null);if(xr&48)throw Error(c(327));var Q=v.finishedWork;if(Q===null)return null;if(v.finishedWork=null,v.finishedLanes=0,Q===v.current)throw Error(c(177));v.callbackNode=null;var H=Q.lanes|Q.childLanes,V=H,ne=v.pendingLanes&~V;v.pendingLanes=V,v.suspendedLanes=0,v.pingedLanes=0,v.expiredLanes&=V,v.mutableReadLanes&=V,v.entangledLanes&=V,V=v.entanglements;for(var Se=v.eventTimes,_e=v.expirationTimes;0<ne;){var pt=31-rs(ne),Wt=1<<pt;V[pt]=0,Se[pt]=-1,_e[pt]=-1,ne&=~Wt}if(wu!==null&&!(H&24)&&wu.has(v)&&wu.delete(v),v===so&&(zi=so=null,Ns=0),1<Q.flags?Q.lastEffect!==null?(Q.lastEffect.nextEffect=Q,H=Q.firstEffect):H=Q:H=Q.firstEffect,H!==null){V=xr,xr|=32,f2.current=null,rd=rt(v.containerInfo),nd=!1,sr=H;do try{$L()}catch(qe){if(sr===null)throw Error(c(330));xf(sr,qe),sr=sr.nextEffect}while(sr!==null);rd=null,sr=H;do try{for(Se=v;sr!==null;){var Sr=sr.flags;if(Sr&16&&F&&Af(sr.stateNode),Sr&128){var Lr=sr.alternate;if(Lr!==null){var Xt=Lr.ref;Xt!==null&&(typeof Xt==\"function\"?Xt(null):Xt.current=null)}}switch(Sr&1038){case 2:hb(sr),sr.flags&=-3;break;case 6:hb(sr),sr.flags&=-3,l2(sr.alternate,sr);break;case 1024:sr.flags&=-1025;break;case 1028:sr.flags&=-1025,l2(sr.alternate,sr);break;case 4:l2(sr.alternate,sr);break;case 8:_e=Se,ne=sr,F?gb(_e,ne):Ab(_e,ne);var zn=ne.alternate;Qy(ne),zn!==null&&Qy(zn)}sr=sr.nextEffect}}catch(qe){if(sr===null)throw Error(c(330));xf(sr,qe),sr=sr.nextEffect}while(sr!==null);nd&&lt(),Fe(v.containerInfo),v.current=Q,sr=H;do try{for(Sr=v;sr!==null;){var yi=sr.flags;if(yi&36&&ub(Sr,sr.alternate,sr),yi&128){Lr=void 0;var za=sr.ref;if(za!==null){var et=sr.stateNode;switch(sr.tag){case 5:Lr=Te(et);break;default:Lr=et}typeof za==\"function\"?za(Lr):za.current=Lr}}sr=sr.nextEffect}}catch(qe){if(sr===null)throw Error(c(330));xf(sr,qe),sr=sr.nextEffect}while(sr!==null);sr=null,te(),xr=V}else v.current=Q;if(bf)bf=!1,$g=v,ed=D;else for(sr=H;sr!==null;)D=sr.nextEffect,sr.nextEffect=null,sr.flags&8&&(yi=sr,yi.sibling=null,yi.stateNode=null),sr=D;if(H=v.pendingLanes,H===0&&(hc=null),H===1?v===C2?td++:(td=0,C2=v):td=0,Q=Q.stateNode,Ua&&typeof Ua.onCommitFiberRoot==\"function\")try{Ua.onCommitFiberRoot($e,Q,void 0,(Q.current.flags&64)===64)}catch{}if(ga(v,Pt()),_y)throw _y=!1,v=y2,y2=null,v;return xr&8||Rn(),null}function $L(){for(;sr!==null;){var v=sr.alternate;nd||rd===null||(sr.flags&8?De(sr,rd)&&(nd=!0,Re()):sr.tag===13&&YL(v,sr)&&De(sr,rd)&&(nd=!0,Re()));var D=sr.flags;D&256&&xy(v,sr),!(D&512)||bf||(bf=!0,Gi(97,function(){return vu(),null})),sr=sr.nextEffect}}function vu(){if(ed!==90){var v=97<ed?97:ed;return ed=90,li(v,tM)}return!1}function eM(v,D){E2.push(D,v),bf||(bf=!0,Gi(97,function(){return vu(),null}))}function vb(v,D){I2.push(D,v),bf||(bf=!0,Gi(97,function(){return vu(),null}))}function tM(){if($g===null)return!1;var v=$g;if($g=null,xr&48)throw Error(c(331));var D=xr;xr|=32;var Q=I2;I2=[];for(var H=0;H<Q.length;H+=2){var V=Q[H],ne=Q[H+1],Se=V.destroy;if(V.destroy=void 0,typeof Se==\"function\")try{Se()}catch(pt){if(ne===null)throw Error(c(330));xf(ne,pt)}}for(Q=E2,E2=[],H=0;H<Q.length;H+=2){V=Q[H],ne=Q[H+1];try{var _e=V.create;V.destroy=_e()}catch(pt){if(ne===null)throw Error(c(330));xf(ne,pt)}}for(_e=v.current.firstEffect;_e!==null;)v=_e.nextEffect,_e.nextEffect=null,_e.flags&8&&(_e.sibling=null,_e.stateNode=null),_e=v;return xr=D,Rn(),!0}function Sb(v,D,Q){D=Yg(Q,D),D=i2(v,D,1),Pl(v,D),D=ko(),v=Gy(v,1),v!==null&&(Ha(v,1,D),ga(v,D))}function xf(v,D){if(v.tag===3)Sb(v,v,D);else for(var Q=v.return;Q!==null;){if(Q.tag===3){Sb(Q,v,D);break}else if(Q.tag===1){var H=Q.stateNode;if(typeof Q.type.getDerivedStateFromError==\"function\"||typeof H.componentDidCatch==\"function\"&&(hc===null||!hc.has(H))){v=Yg(D,v);var V=Jg(Q,v,1);if(Pl(Q,V),V=ko(),Q=Gy(Q,1),Q!==null)Ha(Q,1,V),ga(Q,V);else if(typeof H.componentDidCatch==\"function\"&&(hc===null||!hc.has(H)))try{H.componentDidCatch(D,v)}catch{}break}}Q=Q.return}}function Db(v,D,Q){var H=v.pingCache;H!==null&&H.delete(D),D=ko(),v.pingedLanes|=v.suspendedLanes&Q,so===v&&(Ns&Q)===Q&&(ws===4||ws===3&&(Ns&62914560)===Ns&&500>Pt()-d2?Oh(v,0):h2|=Q),ga(v,D)}function rM(v,D){var Q=v.stateNode;Q!==null&&Q.delete(D),D=0,D===0&&(D=v.mode,D&2?D&4?(Bu===0&&(Bu=Th),D=kn(62914560&~Bu),D===0&&(D=4194304)):D=tr()===99?1:2:D=1),Q=ko(),v=Gy(v,D),v!==null&&(Ha(v,D,Q),ga(v,Q))}var Pb;Pb=function(v,D,Q){var H=D.lanes;if(v!==null)if(v.memoizedProps!==D.pendingProps||Li.current)Je=!0;else if(Q&H)Je=!!(v.flags&16384);else{switch(Je=!1,D.tag){case 3:Py(D),jg();break;case 5:Ef(D);break;case 1:Kn(D.type)&&La(D);break;case 4:Ug(D,D.stateNode.containerInfo);break;case 10:Ng(D,D.memoizedProps.value);break;case 13:if(D.memoizedState!==null)return Q&D.child.childLanes?r2(v,D,Q):(xn(di,di.current&1),D=qn(v,D,Q),D!==null?D.sibling:null);xn(di,di.current&1);break;case 19:if(H=(Q&D.childLanes)!==0,v.flags&64){if(H)return lb(v,D,Q);D.flags|=64}var V=D.memoizedState;if(V!==null&&(V.rendering=null,V.tail=null,V.lastEffect=null),xn(di,di.current),H)break;return null;case 23:case 24:return D.lanes=0,mi(v,D,Q)}return qn(v,D,Q)}else Je=!1;switch(D.lanes=0,D.tag){case 2:if(H=D.type,v!==null&&(v.alternate=null,D.alternate=null,D.flags|=2),v=D.pendingProps,V=dn(D,ji.current),df(D,Q),V=qg(null,D,H,v,V,Q),D.flags|=1,typeof V==\"object\"&&V!==null&&typeof V.render==\"function\"&&V.$$typeof===void 0){if(D.tag=1,D.memoizedState=null,D.updateQueue=null,Kn(H)){var ne=!0;La(D)}else ne=!1;D.memoizedState=V.state!==null&&V.state!==void 0?V.state:null,Bh(D);var Se=H.getDerivedStateFromProps;typeof Se==\"function\"&&_A(D,H,Se,v),V.updater=HA,D.stateNode=V,V._reactInternals=D,Po(D,H,v,Q),D=t2(null,D,H,!0,ne,Q)}else D.tag=0,At(null,D,V,Q),D=D.child;return D;case 16:V=D.elementType;e:{switch(v!==null&&(v.alternate=null,D.alternate=null,D.flags|=2),v=D.pendingProps,ne=V._init,V=ne(V._payload),D.type=V,ne=D.tag=iM(V),v=So(V,v),ne){case 0:D=JA(null,D,V,v,Q);break e;case 1:D=ab(null,D,V,v,Q);break e;case 11:D=dr(null,D,V,v,Q);break e;case 14:D=vr(null,D,V,So(V.type,v),H,Q);break e}throw Error(c(306,V,\"\"))}return D;case 0:return H=D.type,V=D.pendingProps,V=D.elementType===H?V:So(H,V),JA(v,D,H,V,Q);case 1:return H=D.type,V=D.pendingProps,V=D.elementType===H?V:So(H,V),ab(v,D,H,V,Q);case 3:if(Py(D),H=D.updateQueue,v===null||H===null)throw Error(c(282));if(H=D.pendingProps,V=D.memoizedState,V=V!==null?V.element:null,Lg(v,D),UA(D,H,null,Q),H=D.memoizedState.element,H===V)jg(),D=qn(v,D,Q);else{if(V=D.stateNode,(ne=V.hydrate)&&(Z?(Aa=cu(D.stateNode.containerInfo),Wa=D,ne=Ya=!0):ne=!1),ne){if(Z&&(v=V.mutableSourceEagerHydrationData,v!=null))for(V=0;V<v.length;V+=2)ne=v[V],Se=v[V+1],y?ne._workInProgressVersionPrimary=Se:ne._workInProgressVersionSecondary=Se,mu.push(ne);for(Q=e2(D,null,H,Q),D.child=Q;Q;)Q.flags=Q.flags&-3|1024,Q=Q.sibling}else At(v,D,H,Q),jg();D=D.child}return D;case 5:return Ef(D),v===null&&Hg(D),H=D.type,V=D.pendingProps,ne=v!==null?v.memoizedProps:null,Se=V.children,it(H,V)?Se=null:ne!==null&&it(H,ne)&&(D.flags|=16),Cs(v,D),At(v,D,Se,Q),D.child;case 6:return v===null&&Hg(D),null;case 13:return r2(v,D,Q);case 4:return Ug(D,D.stateNode.containerInfo),H=D.pendingProps,v===null?D.child=Mg(D,null,H,Q):At(v,D,H,Q),D.child;case 11:return H=D.type,V=D.pendingProps,V=D.elementType===H?V:So(H,V),dr(v,D,H,V,Q);case 7:return At(v,D,D.pendingProps,Q),D.child;case 8:return At(v,D,D.pendingProps.children,Q),D.child;case 12:return At(v,D,D.pendingProps.children,Q),D.child;case 10:e:{if(H=D.type._context,V=D.pendingProps,Se=D.memoizedProps,ne=V.value,Ng(D,ne),Se!==null){var _e=Se.value;if(ne=vo(_e,ne)?0:(typeof H._calculateChangedBits==\"function\"?H._calculateChangedBits(_e,ne):1073741823)|0,ne===0){if(Se.children===V.children&&!Li.current){D=qn(v,D,Q);break e}}else for(_e=D.child,_e!==null&&(_e.return=D);_e!==null;){var pt=_e.dependencies;if(pt!==null){Se=_e.child;for(var Wt=pt.firstContext;Wt!==null;){if(Wt.context===H&&Wt.observedBits&ne){_e.tag===1&&(Wt=Dl(-1,Q&-Q),Wt.tag=2,Pl(_e,Wt)),_e.lanes|=Q,Wt=_e.alternate,Wt!==null&&(Wt.lanes|=Q),Ey(_e.return,Q),pt.lanes|=Q;break}Wt=Wt.next}}else Se=_e.tag===10&&_e.type===D.type?null:_e.child;if(Se!==null)Se.return=_e;else for(Se=_e;Se!==null;){if(Se===D){Se=null;break}if(_e=Se.sibling,_e!==null){_e.return=Se.return,Se=_e;break}Se=Se.return}_e=Se}}At(v,D,V.children,Q),D=D.child}return D;case 9:return V=D.type,ne=D.pendingProps,H=ne.children,df(D,Q),V=Do(V,ne.unstable_observedBits),H=H(V),D.flags|=1,At(v,D,H,Q),D.child;case 14:return V=D.type,ne=So(V,D.pendingProps),ne=So(V.type,ne),vr(v,D,V,ne,H,Q);case 15:return Un(v,D,D.type,D.pendingProps,H,Q);case 17:return H=D.type,V=D.pendingProps,V=D.elementType===H?V:So(H,V),v!==null&&(v.alternate=null,D.alternate=null,D.flags|=2),D.tag=1,Kn(H)?(v=!0,La(D)):v=!1,df(D,Q),xt(D,H,V),Po(D,H,V,Q),t2(null,D,H,!0,v,Q);case 19:return lb(v,D,Q);case 23:return mi(v,D,Q);case 24:return mi(v,D,Q)}throw Error(c(156,D.tag))};var Wy={current:!1},Os=n.unstable_flushAllWithoutAsserting,bb=typeof Os==\"function\";function v2(){if(Os!==void 0)return Os();for(var v=!1;vu();)v=!0;return v}function da(v){try{v2(),VL(function(){v2()?da(v):v()})}catch(D){v(D)}}var Ja=0,Yy=!1;function nM(v,D,Q,H){this.tag=v,this.key=Q,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=D,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=H,this.flags=0,this.lastEffect=this.firstEffect=this.nextEffect=null,this.childLanes=this.lanes=0,this.alternate=null}function Ka(v,D,Q,H){return new nM(v,D,Q,H)}function S2(v){return v=v.prototype,!(!v||!v.isReactComponent)}function iM(v){if(typeof v==\"function\")return S2(v)?1:0;if(v!=null){if(v=v.$$typeof,v===T)return 11;if(v===W)return 14}return 2}function Su(v,D){var Q=v.alternate;return Q===null?(Q=Ka(v.tag,D,v.key,v.mode),Q.elementType=v.elementType,Q.type=v.type,Q.stateNode=v.stateNode,Q.alternate=v,v.alternate=Q):(Q.pendingProps=D,Q.type=v.type,Q.flags=0,Q.nextEffect=null,Q.firstEffect=null,Q.lastEffect=null),Q.childLanes=v.childLanes,Q.lanes=v.lanes,Q.child=v.child,Q.memoizedProps=v.memoizedProps,Q.memoizedState=v.memoizedState,Q.updateQueue=v.updateQueue,D=v.dependencies,Q.dependencies=D===null?null:{lanes:D.lanes,firstContext:D.firstContext},Q.sibling=v.sibling,Q.index=v.index,Q.ref=v.ref,Q}function sd(v,D,Q,H,V,ne){var Se=2;if(H=v,typeof v==\"function\")S2(v)&&(Se=1);else if(typeof v==\"string\")Se=5;else e:switch(v){case E:return kf(Q.children,V,ne,D);case ue:Se=8,V|=16;break;case C:Se=8,V|=1;break;case S:return v=Ka(12,Q,D,V|8),v.elementType=S,v.type=S,v.lanes=ne,v;case N:return v=Ka(13,Q,D,V),v.type=N,v.elementType=N,v.lanes=ne,v;case U:return v=Ka(19,Q,D,V),v.elementType=U,v.lanes=ne,v;case le:return D2(Q,V,ne,D);case me:return v=Ka(24,Q,D,V),v.elementType=me,v.lanes=ne,v;default:if(typeof v==\"object\"&&v!==null)switch(v.$$typeof){case b:Se=10;break e;case I:Se=9;break e;case T:Se=11;break e;case W:Se=14;break e;case ee:Se=16,H=null;break e;case ie:Se=22;break e}throw Error(c(130,v==null?v:typeof v,\"\"))}return D=Ka(Se,Q,D,V),D.elementType=v,D.type=H,D.lanes=ne,D}function kf(v,D,Q,H){return v=Ka(7,v,H,D),v.lanes=Q,v}function D2(v,D,Q,H){return v=Ka(23,v,H,D),v.elementType=le,v.lanes=Q,v}function P2(v,D,Q){return v=Ka(6,v,null,D),v.lanes=Q,v}function Qo(v,D,Q){return D=Ka(4,v.children!==null?v.children:[],v.key,D),D.lanes=Q,D.stateNode={containerInfo:v.containerInfo,pendingChildren:null,implementation:v.implementation},D}function sM(v,D,Q){this.tag=D,this.containerInfo=v,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=P,this.pendingContext=this.context=null,this.hydrate=Q,this.callbackNode=null,this.callbackPriority=0,this.eventTimes=fa(0),this.expirationTimes=fa(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=fa(0),Z&&(this.mutableSourceEagerHydrationData=null)}function xb(v){var D=v._reactInternals;if(D===void 0)throw typeof v.render==\"function\"?Error(c(188)):Error(c(268,Object.keys(v)));return v=se(D),v===null?null:v.stateNode}function kb(v,D){if(v=v.memoizedState,v!==null&&v.dehydrated!==null){var Q=v.retryLane;v.retryLane=Q!==0&&Q<D?Q:D}}function Vy(v,D){kb(v,D),(v=v.alternate)&&kb(v,D)}function oM(v){return v=se(v),v===null?null:v.stateNode}function aM(){return null}return r.IsThisRendererActing=Wy,r.act=function(v){function D(){Ja--,A2.current=Q,Wy.current=H}Yy===!1&&(Yy=!0,console.error(\"act(...) is not supported in production builds of React, and might not behave as expected.\")),Ja++;var Q=A2.current,H=Wy.current;A2.current=!0,Wy.current=!0;try{var V=yb(v)}catch(ne){throw D(),ne}if(V!==null&&typeof V==\"object\"&&typeof V.then==\"function\")return{then:function(ne,Se){V.then(function(){1<Ja||bb===!0&&Q===!0?(D(),ne()):da(function(_e){D(),_e?Se(_e):ne()})},function(_e){D(),Se(_e)})}};try{Ja!==1||bb!==!1&&Q!==!1||v2(),D()}catch(ne){throw D(),ne}return{then:function(ne){ne()}}},r.attemptContinuousHydration=function(v){if(v.tag===13){var D=ko();Rl(v,67108864,D),Vy(v,67108864)}},r.attemptHydrationAtCurrentPriority=function(v){if(v.tag===13){var D=ko(),Q=Bs(v);Rl(v,Q,D),Vy(v,Q)}},r.attemptSynchronousHydration=function(v){switch(v.tag){case 3:var D=v.stateNode;if(D.hydrate){var Q=ca(D.pendingLanes);D.expiredLanes|=Q&D.pendingLanes,ga(D,Pt()),!(xr&48)&&(Pf(),Rn())}break;case 13:var H=ko();Eb(function(){return Rl(v,1,H)}),Vy(v,4)}},r.attemptUserBlockingHydration=function(v){if(v.tag===13){var D=ko();Rl(v,4,D),Vy(v,4)}},r.batchedEventUpdates=function(v,D){var Q=xr;xr|=2;try{return v(D)}finally{xr=Q,xr===0&&(Pf(),Rn())}},r.batchedUpdates=yb,r.createComponentSelector=function(v){return{$$typeof:Ry,value:v}},r.createContainer=function(v,D,Q){return v=new sM(v,D,Q),D=Ka(3,null,null,D===2?7:D===1?3:0),v.current=D,D.stateNode=v,Bh(D),v},r.createHasPsuedoClassSelector=function(v){return{$$typeof:Ty,value:v}},r.createPortal=function(v,D,Q){var H=3<arguments.length&&arguments[3]!==void 0?arguments[3]:null;return{$$typeof:h,key:H==null?null:\"\"+H,children:v,containerInfo:D,implementation:Q}},r.createRoleSelector=function(v){return{$$typeof:Fy,value:v}},r.createTestNameSelector=function(v){return{$$typeof:zg,value:v}},r.createTextSelector=function(v){return{$$typeof:Ny,value:v}},r.deferredUpdates=function(v){return li(97,v)},r.discreteUpdates=function(v,D,Q,H,V){var ne=xr;xr|=4;try{return li(98,v.bind(null,D,Q,H,V))}finally{xr=ne,xr===0&&(Pf(),Rn())}},r.findAllNodes=u2,r.findBoundingRects=function(v,D){if(!qt)throw Error(c(363));D=u2(v,D),v=[];for(var Q=0;Q<D.length;Q++)v.push(bt(D[Q]));for(D=v.length-1;0<D;D--){Q=v[D];for(var H=Q.x,V=H+Q.width,ne=Q.y,Se=ne+Q.height,_e=D-1;0<=_e;_e--)if(D!==_e){var pt=v[_e],Wt=pt.x,Sr=Wt+pt.width,Lr=pt.y,Xt=Lr+pt.height;if(H>=Wt&&ne>=Lr&&V<=Sr&&Se<=Xt){v.splice(D,1);break}else if(H!==Wt||Q.width!==pt.width||Xt<ne||Lr>Se){if(!(ne!==Lr||Q.height!==pt.height||Sr<H||Wt>V)){Wt>H&&(pt.width+=Wt-H,pt.x=H),Sr<V&&(pt.width=V-Wt),v.splice(D,1);break}}else{Lr>ne&&(pt.height+=Lr-ne,pt.y=ne),Xt<Se&&(pt.height=Se-Lr),v.splice(D,1);break}}}return v},r.findHostInstance=xb,r.findHostInstanceWithNoPortals=function(v){return v=X(v),v===null?null:v.tag===20?v.stateNode.instance:v.stateNode},r.findHostInstanceWithWarning=function(v){return xb(v)},r.flushControlled=function(v){var D=xr;xr|=1;try{li(99,v)}finally{xr=D,xr===0&&(Pf(),Rn())}},r.flushDiscreteUpdates=function(){!(xr&49)&&(KL(),vu())},r.flushPassiveEffects=vu,r.flushSync=Eb,r.focusWithin=function(v,D){if(!qt)throw Error(c(363));for(v=Oy(v),D=c2(v,D),D=Array.from(D),v=0;v<D.length;){var Q=D[v++];if(!br(Q)){if(Q.tag===5&&Or(Q.stateNode))return!0;for(Q=Q.child;Q!==null;)D.push(Q),Q=Q.sibling}}return!1},r.getCurrentUpdateLanePriority=function(){return lc},r.getFindAllNodesFailureDescription=function(v,D){if(!qt)throw Error(c(363));var Q=0,H=[];v=[Oy(v),0];for(var V=0;V<v.length;){var ne=v[V++],Se=v[V++],_e=D[Se];if((ne.tag!==5||!br(ne))&&(Sf(ne,_e)&&(H.push(Df(_e)),Se++,Se>Q&&(Q=Se)),Se<D.length))for(ne=ne.child;ne!==null;)v.push(ne,Se),ne=ne.sibling}if(Q<D.length){for(v=[];Q<D.length;Q++)v.push(Df(D[Q]));return`findAllNodes was able to match part of the selector:\n  `+(H.join(\" > \")+`\n\nNo matching component was found for:\n  `)+v.join(\" > \")}return null},r.getPublicRootInstance=function(v){if(v=v.current,!v.child)return null;switch(v.child.tag){case 5:return Te(v.child.stateNode);default:return v.child.stateNode}},r.injectIntoDevTools=function(v){if(v={bundleType:v.bundleType,version:v.version,rendererPackageName:v.rendererPackageName,rendererConfig:v.rendererConfig,overrideHookState:null,overrideHookStateDeletePath:null,overrideHookStateRenamePath:null,overrideProps:null,overridePropsDeletePath:null,overridePropsRenamePath:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:f.ReactCurrentDispatcher,findHostInstanceByFiber:oM,findFiberByHostInstance:v.findFiberByHostInstance||aM,findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null},typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>\"u\")v=!1;else{var D=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(!D.isDisabled&&D.supportsFiber)try{$e=D.inject(v),Ua=D}catch{}v=!0}return v},r.observeVisibleRects=function(v,D,Q,H){if(!qt)throw Error(c(363));v=u2(v,D);var V=nn(v,Q,H).disconnect;return{disconnect:function(){V()}}},r.registerMutableSourceForHydration=function(v,D){var Q=D._getVersion;Q=Q(D._source),v.mutableSourceEagerHydrationData==null?v.mutableSourceEagerHydrationData=[D,Q]:v.mutableSourceEagerHydrationData.push(D,Q)},r.runWithPriority=function(v,D){var Q=lc;try{return lc=v,D()}finally{lc=Q}},r.shouldSuspend=function(){return!1},r.unbatchedUpdates=function(v,D){var Q=xr;xr&=-2,xr|=8;try{return v(D)}finally{xr=Q,xr===0&&(Pf(),Rn())}},r.updateContainer=function(v,D,Q,H){var V=D.current,ne=ko(),Se=Bs(V);e:if(Q){Q=Q._reactInternals;t:{if(we(Q)!==Q||Q.tag!==1)throw Error(c(170));var _e=Q;do{switch(_e.tag){case 3:_e=_e.stateNode.context;break t;case 1:if(Kn(_e.type)){_e=_e.stateNode.__reactInternalMemoizedMergedChildContext;break t}}_e=_e.return}while(_e!==null);throw Error(c(171))}if(Q.tag===1){var pt=Q.type;if(Kn(pt)){Q=Oa(Q,pt,_e);break e}}Q=_e}else Q=la;return D.context===null?D.context=Q:D.pendingContext=Q,D=Dl(ne,Se),D.payload={element:v},H=H===void 0?null:H,H!==null&&(D.callback=H),Pl(V,D),Rl(V,Se,ne),Se},r}});var Iwe=_((sKt,Ewe)=>{\"use strict\";Ewe.exports=ywe()});var wwe=_((oKt,Cwe)=>{\"use strict\";var mpt={ALIGN_COUNT:8,ALIGN_AUTO:0,ALIGN_FLEX_START:1,ALIGN_CENTER:2,ALIGN_FLEX_END:3,ALIGN_STRETCH:4,ALIGN_BASELINE:5,ALIGN_SPACE_BETWEEN:6,ALIGN_SPACE_AROUND:7,DIMENSION_COUNT:2,DIMENSION_WIDTH:0,DIMENSION_HEIGHT:1,DIRECTION_COUNT:3,DIRECTION_INHERIT:0,DIRECTION_LTR:1,DIRECTION_RTL:2,DISPLAY_COUNT:2,DISPLAY_FLEX:0,DISPLAY_NONE:1,EDGE_COUNT:9,EDGE_LEFT:0,EDGE_TOP:1,EDGE_RIGHT:2,EDGE_BOTTOM:3,EDGE_START:4,EDGE_END:5,EDGE_HORIZONTAL:6,EDGE_VERTICAL:7,EDGE_ALL:8,EXPERIMENTAL_FEATURE_COUNT:1,EXPERIMENTAL_FEATURE_WEB_FLEX_BASIS:0,FLEX_DIRECTION_COUNT:4,FLEX_DIRECTION_COLUMN:0,FLEX_DIRECTION_COLUMN_REVERSE:1,FLEX_DIRECTION_ROW:2,FLEX_DIRECTION_ROW_REVERSE:3,JUSTIFY_COUNT:6,JUSTIFY_FLEX_START:0,JUSTIFY_CENTER:1,JUSTIFY_FLEX_END:2,JUSTIFY_SPACE_BETWEEN:3,JUSTIFY_SPACE_AROUND:4,JUSTIFY_SPACE_EVENLY:5,LOG_LEVEL_COUNT:6,LOG_LEVEL_ERROR:0,LOG_LEVEL_WARN:1,LOG_LEVEL_INFO:2,LOG_LEVEL_DEBUG:3,LOG_LEVEL_VERBOSE:4,LOG_LEVEL_FATAL:5,MEASURE_MODE_COUNT:3,MEASURE_MODE_UNDEFINED:0,MEASURE_MODE_EXACTLY:1,MEASURE_MODE_AT_MOST:2,NODE_TYPE_COUNT:2,NODE_TYPE_DEFAULT:0,NODE_TYPE_TEXT:1,OVERFLOW_COUNT:3,OVERFLOW_VISIBLE:0,OVERFLOW_HIDDEN:1,OVERFLOW_SCROLL:2,POSITION_TYPE_COUNT:2,POSITION_TYPE_RELATIVE:0,POSITION_TYPE_ABSOLUTE:1,PRINT_OPTIONS_COUNT:3,PRINT_OPTIONS_LAYOUT:1,PRINT_OPTIONS_STYLE:2,PRINT_OPTIONS_CHILDREN:4,UNIT_COUNT:4,UNIT_UNDEFINED:0,UNIT_POINT:1,UNIT_PERCENT:2,UNIT_AUTO:3,WRAP_COUNT:3,WRAP_NO_WRAP:0,WRAP_WRAP:1,WRAP_WRAP_REVERSE:2};Cwe.exports=mpt});var Dwe=_((aKt,Swe)=>{\"use strict\";var ypt=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var s in r)Object.prototype.hasOwnProperty.call(r,s)&&(t[s]=r[s])}return t},TF=function(){function t(e,r){for(var s=0;s<r.length;s++){var a=r[s];a.enumerable=a.enumerable||!1,a.configurable=!0,\"value\"in a&&(a.writable=!0),Object.defineProperty(e,a.key,a)}}return function(e,r,s){return r&&t(e.prototype,r),s&&t(e,s),e}}();function _9(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function H9(t,e){if(!(t instanceof e))throw new TypeError(\"Cannot call a class as a function\")}var tf=wwe(),Ept=function(){function t(e,r,s,a,n,c){H9(this,t),this.left=e,this.right=r,this.top=s,this.bottom=a,this.width=n,this.height=c}return TF(t,[{key:\"fromJS\",value:function(r){r(this.left,this.right,this.top,this.bottom,this.width,this.height)}},{key:\"toString\",value:function(){return\"<Layout#\"+this.left+\":\"+this.right+\";\"+this.top+\":\"+this.bottom+\";\"+this.width+\":\"+this.height+\">\"}}]),t}(),Bwe=function(){TF(t,null,[{key:\"fromJS\",value:function(r){var s=r.width,a=r.height;return new t(s,a)}}]);function t(e,r){H9(this,t),this.width=e,this.height=r}return TF(t,[{key:\"fromJS\",value:function(r){r(this.width,this.height)}},{key:\"toString\",value:function(){return\"<Size#\"+this.width+\"x\"+this.height+\">\"}}]),t}(),vwe=function(){function t(e,r){H9(this,t),this.unit=e,this.value=r}return TF(t,[{key:\"fromJS\",value:function(r){r(this.unit,this.value)}},{key:\"toString\",value:function(){switch(this.unit){case tf.UNIT_POINT:return String(this.value);case tf.UNIT_PERCENT:return this.value+\"%\";case tf.UNIT_AUTO:return\"auto\";default:return this.value+\"?\"}}},{key:\"valueOf\",value:function(){return this.value}}]),t}();Swe.exports=function(t,e){function r(c,f,p){var h=c[f];c[f]=function(){for(var E=arguments.length,C=Array(E),S=0;S<E;S++)C[S]=arguments[S];return p.call.apply(p,[this,h].concat(C))}}for(var s=[\"setPosition\",\"setMargin\",\"setFlexBasis\",\"setWidth\",\"setHeight\",\"setMinWidth\",\"setMinHeight\",\"setMaxWidth\",\"setMaxHeight\",\"setPadding\"],a=function(){var f,p=s[n],h=(f={},_9(f,tf.UNIT_POINT,e.Node.prototype[p]),_9(f,tf.UNIT_PERCENT,e.Node.prototype[p+\"Percent\"]),_9(f,tf.UNIT_AUTO,e.Node.prototype[p+\"Auto\"]),f);r(e.Node.prototype,p,function(E){for(var C=arguments.length,S=Array(C>1?C-1:0),b=1;b<C;b++)S[b-1]=arguments[b];var I=S.pop(),T=void 0,N=void 0;if(I===\"auto\")T=tf.UNIT_AUTO,N=void 0;else if(I instanceof vwe)T=I.unit,N=I.valueOf();else if(T=typeof I==\"string\"&&I.endsWith(\"%\")?tf.UNIT_PERCENT:tf.UNIT_POINT,N=parseFloat(I),!Number.isNaN(I)&&Number.isNaN(N))throw new Error(\"Invalid value \"+I+\" for \"+p);if(!h[T])throw new Error('Failed to execute \"'+p+`\": Unsupported unit '`+I+\"'\");if(N!==void 0){var U;return(U=h[T]).call.apply(U,[this].concat(S,[N]))}else{var W;return(W=h[T]).call.apply(W,[this].concat(S))}})},n=0;n<s.length;n++)a();return r(e.Config.prototype,\"free\",function(){e.Config.destroy(this)}),r(e.Node,\"create\",function(c,f){return f?e.Node.createWithConfig(f):e.Node.createDefault()}),r(e.Node.prototype,\"free\",function(){e.Node.destroy(this)}),r(e.Node.prototype,\"freeRecursive\",function(){for(var c=0,f=this.getChildCount();c<f;++c)this.getChild(0).freeRecursive();this.free()}),r(e.Node.prototype,\"setMeasureFunc\",function(c,f){return f?c.call(this,function(){return Bwe.fromJS(f.apply(void 0,arguments))}):this.unsetMeasureFunc()}),r(e.Node.prototype,\"calculateLayout\",function(c){var f=arguments.length>1&&arguments[1]!==void 0?arguments[1]:NaN,p=arguments.length>2&&arguments[2]!==void 0?arguments[2]:NaN,h=arguments.length>3&&arguments[3]!==void 0?arguments[3]:tf.DIRECTION_LTR;return c.call(this,f,p,h)}),ypt({Config:e.Config,Node:e.Node,Layout:t(\"Layout\",Ept),Size:t(\"Size\",Bwe),Value:t(\"Value\",vwe),getInstanceCount:function(){return e.getInstanceCount.apply(e,arguments)}},tf)}});var Pwe=_((exports,module)=>{(function(t,e){typeof define==\"function\"&&define.amd?define([],function(){return e}):typeof module==\"object\"&&module.exports?module.exports=e:(t.nbind=t.nbind||{}).init=e})(exports,function(Module,cb){typeof Module==\"function\"&&(cb=Module,Module={}),Module.onRuntimeInitialized=function(t,e){return function(){t&&t.apply(this,arguments);try{Module.ccall(\"nbind_init\")}catch(r){e(r);return}e(null,{bind:Module._nbind_value,reflect:Module.NBind.reflect,queryType:Module.NBind.queryType,toggleLightGC:Module.toggleLightGC,lib:Module})}}(Module.onRuntimeInitialized,cb);var Module;Module||(Module=(typeof Module<\"u\"?Module:null)||{});var moduleOverrides={};for(var key in Module)Module.hasOwnProperty(key)&&(moduleOverrides[key]=Module[key]);var ENVIRONMENT_IS_WEB=!1,ENVIRONMENT_IS_WORKER=!1,ENVIRONMENT_IS_NODE=!1,ENVIRONMENT_IS_SHELL=!1;if(Module.ENVIRONMENT)if(Module.ENVIRONMENT===\"WEB\")ENVIRONMENT_IS_WEB=!0;else if(Module.ENVIRONMENT===\"WORKER\")ENVIRONMENT_IS_WORKER=!0;else if(Module.ENVIRONMENT===\"NODE\")ENVIRONMENT_IS_NODE=!0;else if(Module.ENVIRONMENT===\"SHELL\")ENVIRONMENT_IS_SHELL=!0;else throw new Error(\"The provided Module['ENVIRONMENT'] value is not valid. It must be one of: WEB|WORKER|NODE|SHELL.\");else ENVIRONMENT_IS_WEB=typeof window==\"object\",ENVIRONMENT_IS_WORKER=typeof importScripts==\"function\",ENVIRONMENT_IS_NODE=typeof process==\"object\"&&typeof Ie==\"function\"&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER,ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;if(ENVIRONMENT_IS_NODE){Module.print||(Module.print=console.log),Module.printErr||(Module.printErr=console.warn);var nodeFS,nodePath;Module.read=function(e,r){nodeFS||(nodeFS={}(\"\")),nodePath||(nodePath={}(\"\")),e=nodePath.normalize(e);var s=nodeFS.readFileSync(e);return r?s:s.toString()},Module.readBinary=function(e){var r=Module.read(e,!0);return r.buffer||(r=new Uint8Array(r)),assert(r.buffer),r},Module.load=function(e){globalEval(read(e))},Module.thisProgram||(process.argv.length>1?Module.thisProgram=process.argv[1].replace(/\\\\/g,\"/\"):Module.thisProgram=\"unknown-program\"),Module.arguments=process.argv.slice(2),typeof module<\"u\"&&(module.exports=Module),Module.inspect=function(){return\"[Emscripten Module object]\"}}else if(ENVIRONMENT_IS_SHELL)Module.print||(Module.print=print),typeof printErr<\"u\"&&(Module.printErr=printErr),typeof read<\"u\"?Module.read=read:Module.read=function(){throw\"no read() available\"},Module.readBinary=function(e){if(typeof readbuffer==\"function\")return new Uint8Array(readbuffer(e));var r=read(e,\"binary\");return assert(typeof r==\"object\"),r},typeof scriptArgs<\"u\"?Module.arguments=scriptArgs:typeof arguments<\"u\"&&(Module.arguments=arguments),typeof quit==\"function\"&&(Module.quit=function(t,e){quit(t)});else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(Module.read=function(e){var r=new XMLHttpRequest;return r.open(\"GET\",e,!1),r.send(null),r.responseText},ENVIRONMENT_IS_WORKER&&(Module.readBinary=function(e){var r=new XMLHttpRequest;return r.open(\"GET\",e,!1),r.responseType=\"arraybuffer\",r.send(null),new Uint8Array(r.response)}),Module.readAsync=function(e,r,s){var a=new XMLHttpRequest;a.open(\"GET\",e,!0),a.responseType=\"arraybuffer\",a.onload=function(){a.status==200||a.status==0&&a.response?r(a.response):s()},a.onerror=s,a.send(null)},typeof arguments<\"u\"&&(Module.arguments=arguments),typeof console<\"u\")Module.print||(Module.print=function(e){console.log(e)}),Module.printErr||(Module.printErr=function(e){console.warn(e)});else{var TRY_USE_DUMP=!1;Module.print||(Module.print=TRY_USE_DUMP&&typeof dump<\"u\"?function(t){dump(t)}:function(t){})}ENVIRONMENT_IS_WORKER&&(Module.load=importScripts),typeof Module.setWindowTitle>\"u\"&&(Module.setWindowTitle=function(t){document.title=t})}else throw\"Unknown runtime environment. Where are we?\";function globalEval(t){eval.call(null,t)}!Module.load&&Module.read&&(Module.load=function(e){globalEval(Module.read(e))}),Module.print||(Module.print=function(){}),Module.printErr||(Module.printErr=Module.print),Module.arguments||(Module.arguments=[]),Module.thisProgram||(Module.thisProgram=\"./this.program\"),Module.quit||(Module.quit=function(t,e){throw e}),Module.print=Module.print,Module.printErr=Module.printErr,Module.preRun=[],Module.postRun=[];for(var key in moduleOverrides)moduleOverrides.hasOwnProperty(key)&&(Module[key]=moduleOverrides[key]);moduleOverrides=void 0;var Runtime={setTempRet0:function(t){return tempRet0=t,t},getTempRet0:function(){return tempRet0},stackSave:function(){return STACKTOP},stackRestore:function(t){STACKTOP=t},getNativeTypeSize:function(t){switch(t){case\"i1\":case\"i8\":return 1;case\"i16\":return 2;case\"i32\":return 4;case\"i64\":return 8;case\"float\":return 4;case\"double\":return 8;default:{if(t[t.length-1]===\"*\")return Runtime.QUANTUM_SIZE;if(t[0]===\"i\"){var e=parseInt(t.substr(1));return assert(e%8===0),e/8}else return 0}}},getNativeFieldSize:function(t){return Math.max(Runtime.getNativeTypeSize(t),Runtime.QUANTUM_SIZE)},STACK_ALIGN:16,prepVararg:function(t,e){return e===\"double\"||e===\"i64\"?t&7&&(assert((t&7)===4),t+=4):assert((t&3)===0),t},getAlignSize:function(t,e,r){return!r&&(t==\"i64\"||t==\"double\")?8:t?Math.min(e||(t?Runtime.getNativeFieldSize(t):0),Runtime.QUANTUM_SIZE):Math.min(e,8)},dynCall:function(t,e,r){return r&&r.length?Module[\"dynCall_\"+t].apply(null,[e].concat(r)):Module[\"dynCall_\"+t].call(null,e)},functionPointers:[],addFunction:function(t){for(var e=0;e<Runtime.functionPointers.length;e++)if(!Runtime.functionPointers[e])return Runtime.functionPointers[e]=t,2*(1+e);throw\"Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.\"},removeFunction:function(t){Runtime.functionPointers[(t-2)/2]=null},warnOnce:function(t){Runtime.warnOnce.shown||(Runtime.warnOnce.shown={}),Runtime.warnOnce.shown[t]||(Runtime.warnOnce.shown[t]=1,Module.printErr(t))},funcWrappers:{},getFuncWrapper:function(t,e){if(t){assert(e),Runtime.funcWrappers[e]||(Runtime.funcWrappers[e]={});var r=Runtime.funcWrappers[e];return r[t]||(e.length===1?r[t]=function(){return Runtime.dynCall(e,t)}:e.length===2?r[t]=function(a){return Runtime.dynCall(e,t,[a])}:r[t]=function(){return Runtime.dynCall(e,t,Array.prototype.slice.call(arguments))}),r[t]}},getCompilerSetting:function(t){throw\"You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work\"},stackAlloc:function(t){var e=STACKTOP;return STACKTOP=STACKTOP+t|0,STACKTOP=STACKTOP+15&-16,e},staticAlloc:function(t){var e=STATICTOP;return STATICTOP=STATICTOP+t|0,STATICTOP=STATICTOP+15&-16,e},dynamicAlloc:function(t){var e=HEAP32[DYNAMICTOP_PTR>>2],r=(e+t+15|0)&-16;if(HEAP32[DYNAMICTOP_PTR>>2]=r,r>=TOTAL_MEMORY){var s=enlargeMemory();if(!s)return HEAP32[DYNAMICTOP_PTR>>2]=e,0}return e},alignMemory:function(t,e){var r=t=Math.ceil(t/(e||16))*(e||16);return r},makeBigInt:function(t,e,r){var s=r?+(t>>>0)+ +(e>>>0)*4294967296:+(t>>>0)+ +(e|0)*4294967296;return s},GLOBAL_BASE:8,QUANTUM_SIZE:4,__dummy__:0};Module.Runtime=Runtime;var ABORT=0,EXITSTATUS=0;function assert(t,e){t||abort(\"Assertion failed: \"+e)}function getCFunc(ident){var func=Module[\"_\"+ident];if(!func)try{func=eval(\"_\"+ident)}catch(t){}return assert(func,\"Cannot call unknown function \"+ident+\" (perhaps LLVM optimizations or closure removed it?)\"),func}var cwrap,ccall;(function(){var JSfuncs={stackSave:function(){Runtime.stackSave()},stackRestore:function(){Runtime.stackRestore()},arrayToC:function(t){var e=Runtime.stackAlloc(t.length);return writeArrayToMemory(t,e),e},stringToC:function(t){var e=0;if(t!=null&&t!==0){var r=(t.length<<2)+1;e=Runtime.stackAlloc(r),stringToUTF8(t,e,r)}return e}},toC={string:JSfuncs.stringToC,array:JSfuncs.arrayToC};ccall=function(e,r,s,a,n){var c=getCFunc(e),f=[],p=0;if(a)for(var h=0;h<a.length;h++){var E=toC[s[h]];E?(p===0&&(p=Runtime.stackSave()),f[h]=E(a[h])):f[h]=a[h]}var C=c.apply(null,f);if(r===\"string\"&&(C=Pointer_stringify(C)),p!==0){if(n&&n.async){EmterpreterAsync.asyncFinalizers.push(function(){Runtime.stackRestore(p)});return}Runtime.stackRestore(p)}return C};var sourceRegex=/^function\\s*[a-zA-Z$_0-9]*\\s*\\(([^)]*)\\)\\s*{\\s*([^*]*?)[\\s;]*(?:return\\s*(.*?)[;\\s]*)?}$/;function parseJSFunc(t){var e=t.toString().match(sourceRegex).slice(1);return{arguments:e[0],body:e[1],returnValue:e[2]}}var JSsource=null;function ensureJSsource(){if(!JSsource){JSsource={};for(var t in JSfuncs)JSfuncs.hasOwnProperty(t)&&(JSsource[t]=parseJSFunc(JSfuncs[t]))}}cwrap=function cwrap(ident,returnType,argTypes){argTypes=argTypes||[];var cfunc=getCFunc(ident),numericArgs=argTypes.every(function(t){return t===\"number\"}),numericRet=returnType!==\"string\";if(numericRet&&numericArgs)return cfunc;var argNames=argTypes.map(function(t,e){return\"$\"+e}),funcstr=\"(function(\"+argNames.join(\",\")+\") {\",nargs=argTypes.length;if(!numericArgs){ensureJSsource(),funcstr+=\"var stack = \"+JSsource.stackSave.body+\";\";for(var i=0;i<nargs;i++){var arg=argNames[i],type=argTypes[i];if(type!==\"number\"){var convertCode=JSsource[type+\"ToC\"];funcstr+=\"var \"+convertCode.arguments+\" = \"+arg+\";\",funcstr+=convertCode.body+\";\",funcstr+=arg+\"=(\"+convertCode.returnValue+\");\"}}}var cfuncname=parseJSFunc(function(){return cfunc}).returnValue;if(funcstr+=\"var ret = \"+cfuncname+\"(\"+argNames.join(\",\")+\");\",!numericRet){var strgfy=parseJSFunc(function(){return Pointer_stringify}).returnValue;funcstr+=\"ret = \"+strgfy+\"(ret);\"}return numericArgs||(ensureJSsource(),funcstr+=JSsource.stackRestore.body.replace(\"()\",\"(stack)\")+\";\"),funcstr+=\"return ret})\",eval(funcstr)}})(),Module.ccall=ccall,Module.cwrap=cwrap;function setValue(t,e,r,s){switch(r=r||\"i8\",r.charAt(r.length-1)===\"*\"&&(r=\"i32\"),r){case\"i1\":HEAP8[t>>0]=e;break;case\"i8\":HEAP8[t>>0]=e;break;case\"i16\":HEAP16[t>>1]=e;break;case\"i32\":HEAP32[t>>2]=e;break;case\"i64\":tempI64=[e>>>0,(tempDouble=e,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[t>>2]=tempI64[0],HEAP32[t+4>>2]=tempI64[1];break;case\"float\":HEAPF32[t>>2]=e;break;case\"double\":HEAPF64[t>>3]=e;break;default:abort(\"invalid type for setValue: \"+r)}}Module.setValue=setValue;function getValue(t,e,r){switch(e=e||\"i8\",e.charAt(e.length-1)===\"*\"&&(e=\"i32\"),e){case\"i1\":return HEAP8[t>>0];case\"i8\":return HEAP8[t>>0];case\"i16\":return HEAP16[t>>1];case\"i32\":return HEAP32[t>>2];case\"i64\":return HEAP32[t>>2];case\"float\":return HEAPF32[t>>2];case\"double\":return HEAPF64[t>>3];default:abort(\"invalid type for setValue: \"+e)}return null}Module.getValue=getValue;var ALLOC_NORMAL=0,ALLOC_STACK=1,ALLOC_STATIC=2,ALLOC_DYNAMIC=3,ALLOC_NONE=4;Module.ALLOC_NORMAL=ALLOC_NORMAL,Module.ALLOC_STACK=ALLOC_STACK,Module.ALLOC_STATIC=ALLOC_STATIC,Module.ALLOC_DYNAMIC=ALLOC_DYNAMIC,Module.ALLOC_NONE=ALLOC_NONE;function allocate(t,e,r,s){var a,n;typeof t==\"number\"?(a=!0,n=t):(a=!1,n=t.length);var c=typeof e==\"string\"?e:null,f;if(r==ALLOC_NONE?f=s:f=[typeof _malloc==\"function\"?_malloc:Runtime.staticAlloc,Runtime.stackAlloc,Runtime.staticAlloc,Runtime.dynamicAlloc][r===void 0?ALLOC_STATIC:r](Math.max(n,c?1:e.length)),a){var s=f,p;for(assert((f&3)==0),p=f+(n&-4);s<p;s+=4)HEAP32[s>>2]=0;for(p=f+n;s<p;)HEAP8[s++>>0]=0;return f}if(c===\"i8\")return t.subarray||t.slice?HEAPU8.set(t,f):HEAPU8.set(new Uint8Array(t),f),f;for(var h=0,E,C,S;h<n;){var b=t[h];if(typeof b==\"function\"&&(b=Runtime.getFunctionIndex(b)),E=c||e[h],E===0){h++;continue}E==\"i64\"&&(E=\"i32\"),setValue(f+h,b,E),S!==E&&(C=Runtime.getNativeTypeSize(E),S=E),h+=C}return f}Module.allocate=allocate;function getMemory(t){return staticSealed?runtimeInitialized?_malloc(t):Runtime.dynamicAlloc(t):Runtime.staticAlloc(t)}Module.getMemory=getMemory;function Pointer_stringify(t,e){if(e===0||!t)return\"\";for(var r=0,s,a=0;s=HEAPU8[t+a>>0],r|=s,!(s==0&&!e||(a++,e&&a==e)););e||(e=a);var n=\"\";if(r<128){for(var c=1024,f;e>0;)f=String.fromCharCode.apply(String,HEAPU8.subarray(t,t+Math.min(e,c))),n=n?n+f:f,t+=c,e-=c;return n}return Module.UTF8ToString(t)}Module.Pointer_stringify=Pointer_stringify;function AsciiToString(t){for(var e=\"\";;){var r=HEAP8[t++>>0];if(!r)return e;e+=String.fromCharCode(r)}}Module.AsciiToString=AsciiToString;function stringToAscii(t,e){return writeAsciiToMemory(t,e,!1)}Module.stringToAscii=stringToAscii;var UTF8Decoder=typeof TextDecoder<\"u\"?new TextDecoder(\"utf8\"):void 0;function UTF8ArrayToString(t,e){for(var r=e;t[r];)++r;if(r-e>16&&t.subarray&&UTF8Decoder)return UTF8Decoder.decode(t.subarray(e,r));for(var s,a,n,c,f,p,h=\"\";;){if(s=t[e++],!s)return h;if(!(s&128)){h+=String.fromCharCode(s);continue}if(a=t[e++]&63,(s&224)==192){h+=String.fromCharCode((s&31)<<6|a);continue}if(n=t[e++]&63,(s&240)==224?s=(s&15)<<12|a<<6|n:(c=t[e++]&63,(s&248)==240?s=(s&7)<<18|a<<12|n<<6|c:(f=t[e++]&63,(s&252)==248?s=(s&3)<<24|a<<18|n<<12|c<<6|f:(p=t[e++]&63,s=(s&1)<<30|a<<24|n<<18|c<<12|f<<6|p))),s<65536)h+=String.fromCharCode(s);else{var E=s-65536;h+=String.fromCharCode(55296|E>>10,56320|E&1023)}}}Module.UTF8ArrayToString=UTF8ArrayToString;function UTF8ToString(t){return UTF8ArrayToString(HEAPU8,t)}Module.UTF8ToString=UTF8ToString;function stringToUTF8Array(t,e,r,s){if(!(s>0))return 0;for(var a=r,n=r+s-1,c=0;c<t.length;++c){var f=t.charCodeAt(c);if(f>=55296&&f<=57343&&(f=65536+((f&1023)<<10)|t.charCodeAt(++c)&1023),f<=127){if(r>=n)break;e[r++]=f}else if(f<=2047){if(r+1>=n)break;e[r++]=192|f>>6,e[r++]=128|f&63}else if(f<=65535){if(r+2>=n)break;e[r++]=224|f>>12,e[r++]=128|f>>6&63,e[r++]=128|f&63}else if(f<=2097151){if(r+3>=n)break;e[r++]=240|f>>18,e[r++]=128|f>>12&63,e[r++]=128|f>>6&63,e[r++]=128|f&63}else if(f<=67108863){if(r+4>=n)break;e[r++]=248|f>>24,e[r++]=128|f>>18&63,e[r++]=128|f>>12&63,e[r++]=128|f>>6&63,e[r++]=128|f&63}else{if(r+5>=n)break;e[r++]=252|f>>30,e[r++]=128|f>>24&63,e[r++]=128|f>>18&63,e[r++]=128|f>>12&63,e[r++]=128|f>>6&63,e[r++]=128|f&63}}return e[r]=0,r-a}Module.stringToUTF8Array=stringToUTF8Array;function stringToUTF8(t,e,r){return stringToUTF8Array(t,HEAPU8,e,r)}Module.stringToUTF8=stringToUTF8;function lengthBytesUTF8(t){for(var e=0,r=0;r<t.length;++r){var s=t.charCodeAt(r);s>=55296&&s<=57343&&(s=65536+((s&1023)<<10)|t.charCodeAt(++r)&1023),s<=127?++e:s<=2047?e+=2:s<=65535?e+=3:s<=2097151?e+=4:s<=67108863?e+=5:e+=6}return e}Module.lengthBytesUTF8=lengthBytesUTF8;var UTF16Decoder=typeof TextDecoder<\"u\"?new TextDecoder(\"utf-16le\"):void 0;function demangle(t){var e=Module.___cxa_demangle||Module.__cxa_demangle;if(e){try{var r=t.substr(1),s=lengthBytesUTF8(r)+1,a=_malloc(s);stringToUTF8(r,a,s);var n=_malloc(4),c=e(a,0,0,n);if(getValue(n,\"i32\")===0&&c)return Pointer_stringify(c)}catch{}finally{a&&_free(a),n&&_free(n),c&&_free(c)}return t}return Runtime.warnOnce(\"warning: build with  -s DEMANGLE_SUPPORT=1  to link in libcxxabi demangling\"),t}function demangleAll(t){var e=/__Z[\\w\\d_]+/g;return t.replace(e,function(r){var s=demangle(r);return r===s?r:r+\" [\"+s+\"]\"})}function jsStackTrace(){var t=new Error;if(!t.stack){try{throw new Error(0)}catch(e){t=e}if(!t.stack)return\"(no stack trace available)\"}return t.stack.toString()}function stackTrace(){var t=jsStackTrace();return Module.extraStackTrace&&(t+=`\n`+Module.extraStackTrace()),demangleAll(t)}Module.stackTrace=stackTrace;var HEAP,buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferViews(){Module.HEAP8=HEAP8=new Int8Array(buffer),Module.HEAP16=HEAP16=new Int16Array(buffer),Module.HEAP32=HEAP32=new Int32Array(buffer),Module.HEAPU8=HEAPU8=new Uint8Array(buffer),Module.HEAPU16=HEAPU16=new Uint16Array(buffer),Module.HEAPU32=HEAPU32=new Uint32Array(buffer),Module.HEAPF32=HEAPF32=new Float32Array(buffer),Module.HEAPF64=HEAPF64=new Float64Array(buffer)}var STATIC_BASE,STATICTOP,staticSealed,STACK_BASE,STACKTOP,STACK_MAX,DYNAMIC_BASE,DYNAMICTOP_PTR;STATIC_BASE=STATICTOP=STACK_BASE=STACKTOP=STACK_MAX=DYNAMIC_BASE=DYNAMICTOP_PTR=0,staticSealed=!1;function abortOnCannotGrowMemory(){abort(\"Cannot enlarge memory arrays. Either (1) compile with  -s TOTAL_MEMORY=X  with X higher than the current value \"+TOTAL_MEMORY+\", (2) compile with  -s ALLOW_MEMORY_GROWTH=1  which allows increasing the size at runtime but prevents some optimizations, (3) set Module.TOTAL_MEMORY to a higher value before the program runs, or (4) if you want malloc to return NULL (0) instead of this abort, compile with  -s ABORTING_MALLOC=0 \")}function enlargeMemory(){abortOnCannotGrowMemory()}var TOTAL_STACK=Module.TOTAL_STACK||5242880,TOTAL_MEMORY=Module.TOTAL_MEMORY||134217728;TOTAL_MEMORY<TOTAL_STACK&&Module.printErr(\"TOTAL_MEMORY should be larger than TOTAL_STACK, was \"+TOTAL_MEMORY+\"! (TOTAL_STACK=\"+TOTAL_STACK+\")\"),Module.buffer?buffer=Module.buffer:buffer=new ArrayBuffer(TOTAL_MEMORY),updateGlobalBufferViews();function getTotalMemory(){return TOTAL_MEMORY}if(HEAP32[0]=1668509029,HEAP16[1]=25459,HEAPU8[2]!==115||HEAPU8[3]!==99)throw\"Runtime error: expected the system to be little-endian!\";Module.HEAP=HEAP,Module.buffer=buffer,Module.HEAP8=HEAP8,Module.HEAP16=HEAP16,Module.HEAP32=HEAP32,Module.HEAPU8=HEAPU8,Module.HEAPU16=HEAPU16,Module.HEAPU32=HEAPU32,Module.HEAPF32=HEAPF32,Module.HEAPF64=HEAPF64;function callRuntimeCallbacks(t){for(;t.length>0;){var e=t.shift();if(typeof e==\"function\"){e();continue}var r=e.func;typeof r==\"number\"?e.arg===void 0?Module.dynCall_v(r):Module.dynCall_vi(r,e.arg):r(e.arg===void 0?null:e.arg)}}var __ATPRERUN__=[],__ATINIT__=[],__ATMAIN__=[],__ATEXIT__=[],__ATPOSTRUN__=[],runtimeInitialized=!1,runtimeExited=!1;function preRun(){if(Module.preRun)for(typeof Module.preRun==\"function\"&&(Module.preRun=[Module.preRun]);Module.preRun.length;)addOnPreRun(Module.preRun.shift());callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){runtimeInitialized||(runtimeInitialized=!0,callRuntimeCallbacks(__ATINIT__))}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){callRuntimeCallbacks(__ATEXIT__),runtimeExited=!0}function postRun(){if(Module.postRun)for(typeof Module.postRun==\"function\"&&(Module.postRun=[Module.postRun]);Module.postRun.length;)addOnPostRun(Module.postRun.shift());callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(t){__ATPRERUN__.unshift(t)}Module.addOnPreRun=addOnPreRun;function addOnInit(t){__ATINIT__.unshift(t)}Module.addOnInit=addOnInit;function addOnPreMain(t){__ATMAIN__.unshift(t)}Module.addOnPreMain=addOnPreMain;function addOnExit(t){__ATEXIT__.unshift(t)}Module.addOnExit=addOnExit;function addOnPostRun(t){__ATPOSTRUN__.unshift(t)}Module.addOnPostRun=addOnPostRun;function intArrayFromString(t,e,r){var s=r>0?r:lengthBytesUTF8(t)+1,a=new Array(s),n=stringToUTF8Array(t,a,0,a.length);return e&&(a.length=n),a}Module.intArrayFromString=intArrayFromString;function intArrayToString(t){for(var e=[],r=0;r<t.length;r++){var s=t[r];s>255&&(s&=255),e.push(String.fromCharCode(s))}return e.join(\"\")}Module.intArrayToString=intArrayToString;function writeStringToMemory(t,e,r){Runtime.warnOnce(\"writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!\");var s,a;r&&(a=e+lengthBytesUTF8(t),s=HEAP8[a]),stringToUTF8(t,e,1/0),r&&(HEAP8[a]=s)}Module.writeStringToMemory=writeStringToMemory;function writeArrayToMemory(t,e){HEAP8.set(t,e)}Module.writeArrayToMemory=writeArrayToMemory;function writeAsciiToMemory(t,e,r){for(var s=0;s<t.length;++s)HEAP8[e++>>0]=t.charCodeAt(s);r||(HEAP8[e>>0]=0)}if(Module.writeAsciiToMemory=writeAsciiToMemory,(!Math.imul||Math.imul(4294967295,5)!==-5)&&(Math.imul=function t(e,r){var s=e>>>16,a=e&65535,n=r>>>16,c=r&65535;return a*c+(s*c+a*n<<16)|0}),Math.imul=Math.imul,!Math.fround){var froundBuffer=new Float32Array(1);Math.fround=function(t){return froundBuffer[0]=t,froundBuffer[0]}}Math.fround=Math.fround,Math.clz32||(Math.clz32=function(t){t=t>>>0;for(var e=0;e<32;e++)if(t&1<<31-e)return e;return 32}),Math.clz32=Math.clz32,Math.trunc||(Math.trunc=function(t){return t<0?Math.ceil(t):Math.floor(t)}),Math.trunc=Math.trunc;var Math_abs=Math.abs,Math_cos=Math.cos,Math_sin=Math.sin,Math_tan=Math.tan,Math_acos=Math.acos,Math_asin=Math.asin,Math_atan=Math.atan,Math_atan2=Math.atan2,Math_exp=Math.exp,Math_log=Math.log,Math_sqrt=Math.sqrt,Math_ceil=Math.ceil,Math_floor=Math.floor,Math_pow=Math.pow,Math_imul=Math.imul,Math_fround=Math.fround,Math_round=Math.round,Math_min=Math.min,Math_clz32=Math.clz32,Math_trunc=Math.trunc,runDependencies=0,runDependencyWatcher=null,dependenciesFulfilled=null;function getUniqueRunDependency(t){return t}function addRunDependency(t){runDependencies++,Module.monitorRunDependencies&&Module.monitorRunDependencies(runDependencies)}Module.addRunDependency=addRunDependency;function removeRunDependency(t){if(runDependencies--,Module.monitorRunDependencies&&Module.monitorRunDependencies(runDependencies),runDependencies==0&&(runDependencyWatcher!==null&&(clearInterval(runDependencyWatcher),runDependencyWatcher=null),dependenciesFulfilled)){var e=dependenciesFulfilled;dependenciesFulfilled=null,e()}}Module.removeRunDependency=removeRunDependency,Module.preloadedImages={},Module.preloadedAudios={};var ASM_CONSTS=[function(t,e,r,s,a,n,c,f){return _nbind.callbackSignatureList[t].apply(this,arguments)}];function _emscripten_asm_const_iiiiiiii(t,e,r,s,a,n,c,f){return ASM_CONSTS[t](e,r,s,a,n,c,f)}function _emscripten_asm_const_iiiii(t,e,r,s,a){return ASM_CONSTS[t](e,r,s,a)}function _emscripten_asm_const_iiidddddd(t,e,r,s,a,n,c,f,p){return ASM_CONSTS[t](e,r,s,a,n,c,f,p)}function _emscripten_asm_const_iiididi(t,e,r,s,a,n,c){return ASM_CONSTS[t](e,r,s,a,n,c)}function _emscripten_asm_const_iiii(t,e,r,s){return ASM_CONSTS[t](e,r,s)}function _emscripten_asm_const_iiiid(t,e,r,s,a){return ASM_CONSTS[t](e,r,s,a)}function _emscripten_asm_const_iiiiii(t,e,r,s,a,n){return ASM_CONSTS[t](e,r,s,a,n)}STATIC_BASE=Runtime.GLOBAL_BASE,STATICTOP=STATIC_BASE+12800,__ATINIT__.push({func:function(){__GLOBAL__sub_I_Yoga_cpp()}},{func:function(){__GLOBAL__sub_I_nbind_cc()}},{func:function(){__GLOBAL__sub_I_common_cc()}},{func:function(){__GLOBAL__sub_I_Binding_cc()}}),allocate([0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,192,127,0,0,192,127,0,0,192,127,3,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,3,0,0,0,0,0,192,127,3,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,192,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,192,127,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,0,0,128,191,0,0,128,191,0,0,192,127,0,0,0,0,0,0,0,0,0,0,128,63,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,2,0,0,0,0,0,0,0,190,12,0,0,200,12,0,0,208,12,0,0,216,12,0,0,230,12,0,0,242,12,0,0,1,0,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0,0,192,127,3,0,0,0,180,45,0,0,181,45,0,0,182,45,0,0,181,45,0,0,182,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,1,0,0,0,4,0,0,0,183,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,184,45,0,0,185,45,0,0,181,45,0,0,181,45,0,0,182,45,0,0,186,45,0,0,185,45,0,0,148,4,0,0,3,0,0,0,187,45,0,0,164,4,0,0,188,45,0,0,2,0,0,0,189,45,0,0,164,4,0,0,188,45,0,0,185,45,0,0,164,4,0,0,185,45,0,0,164,4,0,0,188,45,0,0,181,45,0,0,182,45,0,0,181,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,5,0,0,0,6,0,0,0,1,0,0,0,7,0,0,0,183,45,0,0,182,45,0,0,181,45,0,0,190,45,0,0,190,45,0,0,182,45,0,0,182,45,0,0,185,45,0,0,181,45,0,0,185,45,0,0,182,45,0,0,181,45,0,0,185,45,0,0,182,45,0,0,185,45,0,0,48,5,0,0,3,0,0,0,56,5,0,0,1,0,0,0,189,45,0,0,185,45,0,0,164,4,0,0,76,5,0,0,2,0,0,0,191,45,0,0,186,45,0,0,182,45,0,0,185,45,0,0,192,45,0,0,185,45,0,0,182,45,0,0,186,45,0,0,185,45,0,0,76,5,0,0,76,5,0,0,136,5,0,0,182,45,0,0,181,45,0,0,2,0,0,0,190,45,0,0,136,5,0,0,56,19,0,0,156,5,0,0,2,0,0,0,184,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,8,0,0,0,9,0,0,0,1,0,0,0,10,0,0,0,204,5,0,0,181,45,0,0,181,45,0,0,2,0,0,0,180,45,0,0,204,5,0,0,2,0,0,0,195,45,0,0,236,5,0,0,97,19,0,0,198,45,0,0,211,45,0,0,212,45,0,0,213,45,0,0,214,45,0,0,215,45,0,0,188,45,0,0,182,45,0,0,216,45,0,0,217,45,0,0,218,45,0,0,219,45,0,0,192,45,0,0,181,45,0,0,0,0,0,0,185,45,0,0,110,19,0,0,186,45,0,0,115,19,0,0,221,45,0,0,120,19,0,0,148,4,0,0,132,19,0,0,96,6,0,0,145,19,0,0,222,45,0,0,164,19,0,0,223,45,0,0,173,19,0,0,0,0,0,0,3,0,0,0,104,6,0,0,1,0,0,0,187,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,11,0,0,0,12,0,0,0,1,0,0,0,13,0,0,0,185,45,0,0,224,45,0,0,164,6,0,0,188,45,0,0,172,6,0,0,180,6,0,0,2,0,0,0,188,6,0,0,7,0,0,0,224,45,0,0,7,0,0,0,164,6,0,0,1,0,0,0,213,45,0,0,185,45,0,0,224,45,0,0,172,6,0,0,185,45,0,0,224,45,0,0,164,6,0,0,185,45,0,0,224,45,0,0,211,45,0,0,211,45,0,0,222,45,0,0,211,45,0,0,224,45,0,0,222,45,0,0,211,45,0,0,224,45,0,0,172,6,0,0,222,45,0,0,211,45,0,0,224,45,0,0,188,45,0,0,222,45,0,0,211,45,0,0,40,7,0,0,188,45,0,0,2,0,0,0,224,45,0,0,185,45,0,0,188,45,0,0,188,45,0,0,188,45,0,0,188,45,0,0,222,45,0,0,224,45,0,0,148,4,0,0,185,45,0,0,148,4,0,0,148,4,0,0,148,4,0,0,148,4,0,0,148,4,0,0,185,45,0,0,164,6,0,0,148,4,0,0,0,0,0,0,0,0,0,0,1,0,0,0,14,0,0,0,15,0,0,0,1,0,0,0,16,0,0,0,148,7,0,0,2,0,0,0,225,45,0,0,183,45,0,0,188,45,0,0,168,7,0,0,5,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,234,45,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,148,45,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,9,0,0,5,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,2,0,0,0,242,45,0,0,0,4,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67,111,117,108,100,32,110,111,116,32,97,108,108,111,99,97,116,101,32,109,101,109,111,114,121,32,102,111,114,32,110,111,100,101,0,67,97,110,110,111,116,32,114,101,115,101,116,32,97,32,110,111,100,101,32,119,104,105,99,104,32,115,116,105,108,108,32,104,97,115,32,99,104,105,108,100,114,101,110,32,97,116,116,97,99,104,101,100,0,67,97,110,110,111,116,32,114,101,115,101,116,32,97,32,110,111,100,101,32,115,116,105,108,108,32,97,116,116,97,99,104,101,100,32,116,111,32,97,32,112,97,114,101,110,116,0,67,111,117,108,100,32,110,111,116,32,97,108,108,111,99,97,116,101,32,109,101,109,111,114,121,32,102,111,114,32,99,111,110,102,105,103,0,67,97,110,110,111,116,32,115,101,116,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,58,32,78,111,100,101,115,32,119,105,116,104,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,32,99,97,110,110,111,116,32,104,97,118,101,32,99,104,105,108,100,114,101,110,46,0,67,104,105,108,100,32,97,108,114,101,97,100,121,32,104,97,115,32,97,32,112,97,114,101,110,116,44,32,105,116,32,109,117,115,116,32,98,101,32,114,101,109,111,118,101,100,32,102,105,114,115,116,46,0,67,97,110,110,111,116,32,97,100,100,32,99,104,105,108,100,58,32,78,111,100,101,115,32,119,105,116,104,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,32,99,97,110,110,111,116,32,104,97,118,101,32,99,104,105,108,100,114,101,110,46,0,79,110,108,121,32,108,101,97,102,32,110,111,100,101,115,32,119,105,116,104,32,99,117,115,116,111,109,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,115,104,111,117,108,100,32,109,97,110,117,97,108,108,121,32,109,97,114,107,32,116,104,101,109,115,101,108,118,101,115,32,97,115,32,100,105,114,116,121,0,67,97,110,110,111,116,32,103,101,116,32,108,97,121,111,117,116,32,112,114,111,112,101,114,116,105,101,115,32,111,102,32,109,117,108,116,105,45,101,100,103,101,32,115,104,111,114,116,104,97,110,100,115,0,37,115,37,100,46,123,91,115,107,105,112,112,101,100,93,32,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,97,119,58,32,37,102,32,97,104,58,32,37,102,32,61,62,32,100,58,32,40,37,102,44,32,37,102,41,32,37,115,10,0,37,115,37,100,46,123,37,115,0,42,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,97,119,58,32,37,102,32,97,104,58,32,37,102,32,37,115,10,0,37,115,37,100,46,125,37,115,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,100,58,32,40,37,102,44,32,37,102,41,32,37,115,10,0,79,117,116,32,111,102,32,99,97,99,104,101,32,101,110,116,114,105,101,115,33,10,0,83,99,97,108,101,32,102,97,99,116,111,114,32,115,104,111,117,108,100,32,110,111,116,32,98,101,32,108,101,115,115,32,116,104,97,110,32,122,101,114,111,0,105,110,105,116,105,97,108,0,37,115,10,0,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,0,85,78,68,69,70,73,78,69,68,0,69,88,65,67,84,76,89,0,65,84,95,77,79,83,84,0,76,65,89,95,85,78,68,69,70,73,78,69,68,0,76,65,89,95,69,88,65,67,84,76,89,0,76,65,89,95,65,84,95,77,79,83,84,0,97,118,97,105,108,97,98,108,101,87,105,100,116,104,32,105,115,32,105,110,100,101,102,105,110,105,116,101,32,115,111,32,119,105,100,116,104,77,101,97,115,117,114,101,77,111,100,101,32,109,117,115,116,32,98,101,32,89,71,77,101,97,115,117,114,101,77,111,100,101,85,110,100,101,102,105,110,101,100,0,97,118,97,105,108,97,98,108,101,72,101,105,103,104,116,32,105,115,32,105,110,100,101,102,105,110,105,116,101,32,115,111,32,104,101,105,103,104,116,77,101,97,115,117,114,101,77,111,100,101,32,109,117,115,116,32,98,101,32,89,71,77,101,97,115,117,114,101,77,111,100,101,85,110,100,101,102,105,110,101,100,0,102,108,101,120,0,115,116,114,101,116,99,104,0,109,117,108,116,105,108,105,110,101,45,115,116,114,101,116,99,104,0,69,120,112,101,99,116,101,100,32,110,111,100,101,32,116,111,32,104,97,118,101,32,99,117,115,116,111,109,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,0,109,101,97,115,117,114,101,0,69,120,112,101,99,116,32,99,117,115,116,111,109,32,98,97,115,101,108,105,110,101,32,102,117,110,99,116,105,111,110,32,116,111,32,110,111,116,32,114,101,116,117,114,110,32,78,97,78,0,97,98,115,45,109,101,97,115,117,114,101,0,97,98,115,45,108,97,121,111,117,116,0,78,111,100,101,0,99,114,101,97,116,101,68,101,102,97,117,108,116,0,99,114,101,97,116,101,87,105,116,104,67,111,110,102,105,103,0,100,101,115,116,114,111,121,0,114,101,115,101,116,0,99,111,112,121,83,116,121,108,101,0,115,101,116,80,111,115,105,116,105,111,110,84,121,112,101,0,115,101,116,80,111,115,105,116,105,111,110,0,115,101,116,80,111,115,105,116,105,111,110,80,101,114,99,101,110,116,0,115,101,116,65,108,105,103,110,67,111,110,116,101,110,116,0,115,101,116,65,108,105,103,110,73,116,101,109,115,0,115,101,116,65,108,105,103,110,83,101,108,102,0,115,101,116,70,108,101,120,68,105,114,101,99,116,105,111,110,0,115,101,116,70,108,101,120,87,114,97,112,0,115,101,116,74,117,115,116,105,102,121,67,111,110,116,101,110,116,0,115,101,116,77,97,114,103,105,110,0,115,101,116,77,97,114,103,105,110,80,101,114,99,101,110,116,0,115,101,116,77,97,114,103,105,110,65,117,116,111,0,115,101,116,79,118,101,114,102,108,111,119,0,115,101,116,68,105,115,112,108,97,121,0,115,101,116,70,108,101,120,0,115,101,116,70,108,101,120,66,97,115,105,115,0,115,101,116,70,108,101,120,66,97,115,105,115,80,101,114,99,101,110,116,0,115,101,116,70,108,101,120,71,114,111,119,0,115,101,116,70,108,101,120,83,104,114,105,110,107,0,115,101,116,87,105,100,116,104,0,115,101,116,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,87,105,100,116,104,65,117,116,111,0,115,101,116,72,101,105,103,104,116,0,115,101,116,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,72,101,105,103,104,116,65,117,116,111,0,115,101,116,77,105,110,87,105,100,116,104,0,115,101,116,77,105,110,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,77,105,110,72,101,105,103,104,116,0,115,101,116,77,105,110,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,77,97,120,87,105,100,116,104,0,115,101,116,77,97,120,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,77,97,120,72,101,105,103,104,116,0,115,101,116,77,97,120,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,65,115,112,101,99,116,82,97,116,105,111,0,115,101,116,66,111,114,100,101,114,0,115,101,116,80,97,100,100,105,110,103,0,115,101,116,80,97,100,100,105,110,103,80,101,114,99,101,110,116,0,103,101,116,80,111,115,105,116,105,111,110,84,121,112,101,0,103,101,116,80,111,115,105,116,105,111,110,0,103,101,116,65,108,105,103,110,67,111,110,116,101,110,116,0,103,101,116,65,108,105,103,110,73,116,101,109,115,0,103,101,116,65,108,105,103,110,83,101,108,102,0,103,101,116,70,108,101,120,68,105,114,101,99,116,105,111,110,0,103,101,116,70,108,101,120,87,114,97,112,0,103,101,116,74,117,115,116,105,102,121,67,111,110,116,101,110,116,0,103,101,116,77,97,114,103,105,110,0,103,101,116,70,108,101,120,66,97,115,105,115,0,103,101,116,70,108,101,120,71,114,111,119,0,103,101,116,70,108,101,120,83,104,114,105,110,107,0,103,101,116,87,105,100,116,104,0,103,101,116,72,101,105,103,104,116,0,103,101,116,77,105,110,87,105,100,116,104,0,103,101,116,77,105,110,72,101,105,103,104,116,0,103,101,116,77,97,120,87,105,100,116,104,0,103,101,116,77,97,120,72,101,105,103,104,116,0,103,101,116,65,115,112,101,99,116,82,97,116,105,111,0,103,101,116,66,111,114,100,101,114,0,103,101,116,79,118,101,114,102,108,111,119,0,103,101,116,68,105,115,112,108,97,121,0,103,101,116,80,97,100,100,105,110,103,0,105,110,115,101,114,116,67,104,105,108,100,0,114,101,109,111,118,101,67,104,105,108,100,0,103,101,116,67,104,105,108,100,67,111,117,110,116,0,103,101,116,80,97,114,101,110,116,0,103,101,116,67,104,105,108,100,0,115,101,116,77,101,97,115,117,114,101,70,117,110,99,0,117,110,115,101,116,77,101,97,115,117,114,101,70,117,110,99,0,109,97,114,107,68,105,114,116,121,0,105,115,68,105,114,116,121,0,99,97,108,99,117,108,97,116,101,76,97,121,111,117,116,0,103,101,116,67,111,109,112,117,116,101,100,76,101,102,116,0,103,101,116,67,111,109,112,117,116,101,100,82,105,103,104,116,0,103,101,116,67,111,109,112,117,116,101,100,84,111,112,0,103,101,116,67,111,109,112,117,116,101,100,66,111,116,116,111,109,0,103,101,116,67,111,109,112,117,116,101,100,87,105,100,116,104,0,103,101,116,67,111,109,112,117,116,101,100,72,101,105,103,104,116,0,103,101,116,67,111,109,112,117,116,101,100,76,97,121,111,117,116,0,103,101,116,67,111,109,112,117,116,101,100,77,97,114,103,105,110,0,103,101,116,67,111,109,112,117,116,101,100,66,111,114,100,101,114,0,103,101,116,67,111,109,112,117,116,101,100,80,97,100,100,105,110,103,0,67,111,110,102,105,103,0,99,114,101,97,116,101,0,115,101,116,69,120,112,101,114,105,109,101,110,116,97,108,70,101,97,116,117,114,101,69,110,97,98,108,101,100,0,115,101,116,80,111,105,110,116,83,99,97,108,101,70,97,99,116,111,114,0,105,115,69,120,112,101,114,105,109,101,110,116,97,108,70,101,97,116,117,114,101,69,110,97,98,108,101,100,0,86,97,108,117,101,0,76,97,121,111,117,116,0,83,105,122,101,0,103,101,116,73,110,115,116,97,110,99,101,67,111,117,110,116,0,73,110,116,54,52,0,1,1,1,2,2,4,4,4,4,8,8,4,8,118,111,105,100,0,98,111,111,108,0,115,116,100,58,58,115,116,114,105,110,103,0,99,98,70,117,110,99,116,105,111,110,32,38,0,99,111,110,115,116,32,99,98,70,117,110,99,116,105,111,110,32,38,0,69,120,116,101,114,110,97,108,0,66,117,102,102,101,114,0,78,66,105,110,100,73,68,0,78,66,105,110,100,0,98,105,110,100,95,118,97,108,117,101,0,114,101,102,108,101,99,116,0,113,117,101,114,121,84,121,112,101,0,108,97,108,108,111,99,0,108,114,101,115,101,116,0,123,114,101,116,117,114,110,40,95,110,98,105,110,100,46,99,97,108,108,98,97,99,107,83,105,103,110,97,116,117,114,101,76,105,115,116,91,36,48,93,46,97,112,112,108,121,40,116,104,105,115,44,97,114,103,117,109,101,110,116,115,41,41,59,125,0,95,110,98,105,110,100,95,110,101,119,0,17,0,10,0,17,17,17,0,0,0,0,5,0,0,0,0,0,0,9,0,0,0,0,11,0,0,0,0,0,0,0,0,17,0,15,10,17,17,17,3,10,7,0,1,19,9,11,11,0,0,9,6,11,0,0,11,0,6,17,0,0,0,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,17,0,10,10,17,17,17,0,10,0,0,2,0,9,11,0,0,0,9,0,11,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,0,0,0,0,9,12,0,0,0,0,0,12,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,13,0,0,0,4,13,0,0,0,0,9,14,0,0,0,0,0,14,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,15,0,0,0,0,9,16,0,0,0,0,0,16,0,0,16,0,0,18,0,0,0,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,0,0,18,18,18,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,10,0,0,0,0,9,11,0,0,0,0,0,11,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,0,0,0,0,9,12,0,0,0,0,0,12,0,0,12,0,0,45,43,32,32,32,48,88,48,120,0,40,110,117,108,108,41,0,45,48,88,43,48,88,32,48,88,45,48,120,43,48,120,32,48,120,0,105,110,102,0,73,78,70,0,110,97,110,0,78,65,78,0,48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70,46,0,84,33,34,25,13,1,2,3,17,75,28,12,16,4,11,29,18,30,39,104,110,111,112,113,98,32,5,6,15,19,20,21,26,8,22,7,40,36,23,24,9,10,14,27,31,37,35,131,130,125,38,42,43,60,61,62,63,67,71,74,77,88,89,90,91,92,93,94,95,96,97,99,100,101,102,103,105,106,107,108,114,115,116,121,122,123,124,0,73,108,108,101,103,97,108,32,98,121,116,101,32,115,101,113,117,101,110,99,101,0,68,111,109,97,105,110,32,101,114,114,111,114,0,82,101,115,117,108,116,32,110,111,116,32,114,101,112,114,101,115,101,110,116,97,98,108,101,0,78,111,116,32,97,32,116,116,121,0,80,101,114,109,105,115,115,105,111,110,32,100,101,110,105,101,100,0,79,112,101,114,97,116,105,111,110,32,110,111,116,32,112,101,114,109,105,116,116,101,100,0,78,111,32,115,117,99,104,32,102,105,108,101,32,111,114,32,100,105,114,101,99,116,111,114,121,0,78,111,32,115,117,99,104,32,112,114,111,99,101,115,115,0,70,105,108,101,32,101,120,105,115,116,115,0,86,97,108,117,101,32,116,111,111,32,108,97,114,103,101,32,102,111,114,32,100,97,116,97,32,116,121,112,101,0,78,111,32,115,112,97,99,101,32,108,101,102,116,32,111,110,32,100,101,118,105,99,101,0,79,117,116,32,111,102,32,109,101,109,111,114,121,0,82,101,115,111,117,114,99,101,32,98,117,115,121,0,73,110,116,101,114,114,117,112,116,101,100,32,115,121,115,116,101,109,32,99,97,108,108,0,82,101,115,111,117,114,99,101,32,116,101,109,112,111,114,97,114,105,108,121,32,117,110,97,118,97,105,108,97,98,108,101,0,73,110,118,97,108,105,100,32,115,101,101,107,0,67,114,111,115,115,45,100,101,118,105,99,101,32,108,105,110,107,0,82,101,97,100,45,111,110,108,121,32,102,105,108,101,32,115,121,115,116,101,109,0,68,105,114,101,99,116,111,114,121,32,110,111,116,32,101,109,112,116,121,0,67,111,110,110,101,99,116,105,111,110,32,114,101,115,101,116,32,98,121,32,112,101,101,114,0,79,112,101,114,97,116,105,111,110,32,116,105,109,101,100,32,111,117,116,0,67,111,110,110,101,99,116,105,111,110,32,114,101,102,117,115,101,100,0,72,111,115,116,32,105,115,32,100,111,119,110,0,72,111,115,116,32,105,115,32,117,110,114,101,97,99,104,97,98,108,101,0,65,100,100,114,101,115,115,32,105,110,32,117,115,101,0,66,114,111,107,101,110,32,112,105,112,101,0,73,47,79,32,101,114,114,111,114,0,78,111,32,115,117,99,104,32,100,101,118,105,99,101,32,111,114,32,97,100,100,114,101,115,115,0,66,108,111,99,107,32,100,101,118,105,99,101,32,114,101,113,117,105,114,101,100,0,78,111,32,115,117,99,104,32,100,101,118,105,99,101,0,78,111,116,32,97,32,100,105,114,101,99,116,111,114,121,0,73,115,32,97,32,100,105,114,101,99,116,111,114,121,0,84,101,120,116,32,102,105,108,101,32,98,117,115,121,0,69,120,101,99,32,102,111,114,109,97,116,32,101,114,114,111,114,0,73,110,118,97,108,105,100,32,97,114,103,117,109,101,110,116,0,65,114,103,117,109,101,110,116,32,108,105,115,116,32,116,111,111,32,108,111,110,103,0,83,121,109,98,111,108,105,99,32,108,105,110,107,32,108,111,111,112,0,70,105,108,101,110,97,109,101,32,116,111,111,32,108,111,110,103,0,84,111,111,32,109,97,110,121,32,111,112,101,110,32,102,105,108,101,115,32,105,110,32,115,121,115,116,101,109,0,78,111,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,115,32,97,118,97,105,108,97,98,108,101,0,66,97,100,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,0,78,111,32,99,104,105,108,100,32,112,114,111,99,101,115,115,0,66,97,100,32,97,100,100,114,101,115,115,0,70,105,108,101,32,116,111,111,32,108,97,114,103,101,0,84,111,111,32,109,97,110,121,32,108,105,110,107,115,0,78,111,32,108,111,99,107,115,32,97,118,97,105,108,97,98,108,101,0,82,101,115,111,117,114,99,101,32,100,101,97,100,108,111,99,107,32,119,111,117,108,100,32,111,99,99,117,114,0,83,116,97,116,101,32,110,111,116,32,114,101,99,111,118,101,114,97,98,108,101,0,80,114,101,118,105,111,117,115,32,111,119,110,101,114,32,100,105,101,100,0,79,112,101,114,97,116,105,111,110,32,99,97,110,99,101,108,101,100,0,70,117,110,99,116,105,111,110,32,110,111,116,32,105,109,112,108,101,109,101,110,116,101,100,0,78,111,32,109,101,115,115,97,103,101,32,111,102,32,100,101,115,105,114,101,100,32,116,121,112,101,0,73,100,101,110,116,105,102,105,101,114,32,114,101,109,111,118,101,100,0,68,101,118,105,99,101,32,110,111,116,32,97,32,115,116,114,101,97,109,0,78,111,32,100,97,116,97,32,97,118,97,105,108,97,98,108,101,0,68,101,118,105,99,101,32,116,105,109,101,111,117,116,0,79,117,116,32,111,102,32,115,116,114,101,97,109,115,32,114,101,115,111,117,114,99,101,115,0,76,105,110,107,32,104,97,115,32,98,101,101,110,32,115,101,118,101,114,101,100,0,80,114,111,116,111,99,111,108,32,101,114,114,111,114,0,66,97,100,32,109,101,115,115,97,103,101,0,70,105,108,101,32,100,101,115,99,114,105,112,116,111,114,32,105,110,32,98,97,100,32,115,116,97,116,101,0,78,111,116,32,97,32,115,111,99,107,101,116,0,68,101,115,116,105,110,97,116,105,111,110,32,97,100,100,114,101,115,115,32,114,101,113,117,105,114,101,100,0,77,101,115,115,97,103,101,32,116,111,111,32,108,97,114,103,101,0,80,114,111,116,111,99,111,108,32,119,114,111,110,103,32,116,121,112,101,32,102,111,114,32,115,111,99,107,101,116,0,80,114,111,116,111,99,111,108,32,110,111,116,32,97,118,97,105,108,97,98,108,101,0,80,114,111,116,111,99,111,108,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,83,111,99,107,101,116,32,116,121,112,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,78,111,116,32,115,117,112,112,111,114,116,101,100,0,80,114,111,116,111,99,111,108,32,102,97,109,105,108,121,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,65,100,100,114,101,115,115,32,102,97,109,105,108,121,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,98,121,32,112,114,111,116,111,99,111,108,0,65,100,100,114,101,115,115,32,110,111,116,32,97,118,97,105,108,97,98,108,101,0,78,101,116,119,111,114,107,32,105,115,32,100,111,119,110,0,78,101,116,119,111,114,107,32,117,110,114,101,97,99,104,97,98,108,101,0,67,111,110,110,101,99,116,105,111,110,32,114,101,115,101,116,32,98,121,32,110,101,116,119,111,114,107,0,67,111,110,110,101,99,116,105,111,110,32,97,98,111,114,116,101,100,0,78,111,32,98,117,102,102,101,114,32,115,112,97,99,101,32,97,118,97,105,108,97,98,108,101,0,83,111,99,107,101,116,32,105,115,32,99,111,110,110,101,99,116,101,100,0,83,111,99,107,101,116,32,110,111,116,32,99,111,110,110,101,99,116,101,100,0,67,97,110,110,111,116,32,115,101,110,100,32,97,102,116,101,114,32,115,111,99,107,101,116,32,115,104,117,116,100,111,119,110,0,79,112,101,114,97,116,105,111,110,32,97,108,114,101,97,100,121,32,105,110,32,112,114,111,103,114,101,115,115,0,79,112,101,114,97,116,105,111,110,32,105,110,32,112,114,111,103,114,101,115,115,0,83,116,97,108,101,32,102,105,108,101,32,104,97,110,100,108,101,0,82,101,109,111,116,101,32,73,47,79,32,101,114,114,111,114,0,81,117,111,116,97,32,101,120,99,101,101,100,101,100,0,78,111,32,109,101,100,105,117,109,32,102,111,117,110,100,0,87,114,111,110,103,32,109,101,100,105,117,109,32,116,121,112,101,0,78,111,32,101,114,114,111,114,32,105,110,102,111,114,109,97,116,105,111,110,0,0],\"i8\",ALLOC_NONE,Runtime.GLOBAL_BASE);var tempDoublePtr=STATICTOP;STATICTOP+=16;function _atexit(t,e){__ATEXIT__.unshift({func:t,arg:e})}function ___cxa_atexit(){return _atexit.apply(null,arguments)}function _abort(){Module.abort()}function __ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj(){Module.printErr(\"missing function: _ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj\"),abort(-1)}function __decorate(t,e,r,s){var a=arguments.length,n=a<3?e:s===null?s=Object.getOwnPropertyDescriptor(e,r):s,c;if(typeof Reflect==\"object\"&&typeof Reflect.decorate==\"function\")n=Reflect.decorate(t,e,r,s);else for(var f=t.length-1;f>=0;f--)(c=t[f])&&(n=(a<3?c(n):a>3?c(e,r,n):c(e,r))||n);return a>3&&n&&Object.defineProperty(e,r,n),n}function _defineHidden(t){return function(e,r){Object.defineProperty(e,r,{configurable:!1,enumerable:!1,value:t,writable:!0})}}var _nbind={};function __nbind_free_external(t){_nbind.externalList[t].dereference(t)}function __nbind_reference_external(t){_nbind.externalList[t].reference()}function _llvm_stackrestore(t){var e=_llvm_stacksave,r=e.LLVM_SAVEDSTACKS[t];e.LLVM_SAVEDSTACKS.splice(t,1),Runtime.stackRestore(r)}function __nbind_register_pool(t,e,r,s){_nbind.Pool.pageSize=t,_nbind.Pool.usedPtr=e/4,_nbind.Pool.rootPtr=r,_nbind.Pool.pagePtr=s/4,HEAP32[e/4]=16909060,HEAP8[e]==1&&(_nbind.bigEndian=!0),HEAP32[e/4]=0,_nbind.makeTypeKindTbl=(n={},n[1024]=_nbind.PrimitiveType,n[64]=_nbind.Int64Type,n[2048]=_nbind.BindClass,n[3072]=_nbind.BindClassPtr,n[4096]=_nbind.SharedClassPtr,n[5120]=_nbind.ArrayType,n[6144]=_nbind.ArrayType,n[7168]=_nbind.CStringType,n[9216]=_nbind.CallbackType,n[10240]=_nbind.BindType,n),_nbind.makeTypeNameTbl={Buffer:_nbind.BufferType,External:_nbind.ExternalType,Int64:_nbind.Int64Type,_nbind_new:_nbind.CreateValueType,bool:_nbind.BooleanType,\"cbFunction &\":_nbind.CallbackType,\"const cbFunction &\":_nbind.CallbackType,\"const std::string &\":_nbind.StringType,\"std::string\":_nbind.StringType},Module.toggleLightGC=_nbind.toggleLightGC,_nbind.callUpcast=Module.dynCall_ii;var a=_nbind.makeType(_nbind.constructType,{flags:2048,id:0,name:\"\"});a.proto=Module,_nbind.BindClass.list.push(a);var n}function _emscripten_set_main_loop_timing(t,e){if(Browser.mainLoop.timingMode=t,Browser.mainLoop.timingValue=e,!Browser.mainLoop.func)return 1;if(t==0)Browser.mainLoop.scheduler=function(){var c=Math.max(0,Browser.mainLoop.tickStartTime+e-_emscripten_get_now())|0;setTimeout(Browser.mainLoop.runner,c)},Browser.mainLoop.method=\"timeout\";else if(t==1)Browser.mainLoop.scheduler=function(){Browser.requestAnimationFrame(Browser.mainLoop.runner)},Browser.mainLoop.method=\"rAF\";else if(t==2){if(!window.setImmediate){let n=function(c){c.source===window&&c.data===s&&(c.stopPropagation(),r.shift()())};var a=n,r=[],s=\"setimmediate\";window.addEventListener(\"message\",n,!0),window.setImmediate=function(f){r.push(f),ENVIRONMENT_IS_WORKER?(Module.setImmediates===void 0&&(Module.setImmediates=[]),Module.setImmediates.push(f),window.postMessage({target:s})):window.postMessage(s,\"*\")}}Browser.mainLoop.scheduler=function(){window.setImmediate(Browser.mainLoop.runner)},Browser.mainLoop.method=\"immediate\"}return 0}function _emscripten_get_now(){abort()}function _emscripten_set_main_loop(t,e,r,s,a){Module.noExitRuntime=!0,assert(!Browser.mainLoop.func,\"emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters.\"),Browser.mainLoop.func=t,Browser.mainLoop.arg=s;var n;typeof s<\"u\"?n=function(){Module.dynCall_vi(t,s)}:n=function(){Module.dynCall_v(t)};var c=Browser.mainLoop.currentlyRunningMainloop;if(Browser.mainLoop.runner=function(){if(!ABORT){if(Browser.mainLoop.queue.length>0){var p=Date.now(),h=Browser.mainLoop.queue.shift();if(h.func(h.arg),Browser.mainLoop.remainingBlockers){var E=Browser.mainLoop.remainingBlockers,C=E%1==0?E-1:Math.floor(E);h.counted?Browser.mainLoop.remainingBlockers=C:(C=C+.5,Browser.mainLoop.remainingBlockers=(8*E+C)/9)}if(console.log('main loop blocker \"'+h.name+'\" took '+(Date.now()-p)+\" ms\"),Browser.mainLoop.updateStatus(),c<Browser.mainLoop.currentlyRunningMainloop)return;setTimeout(Browser.mainLoop.runner,0);return}if(!(c<Browser.mainLoop.currentlyRunningMainloop)){if(Browser.mainLoop.currentFrameNumber=Browser.mainLoop.currentFrameNumber+1|0,Browser.mainLoop.timingMode==1&&Browser.mainLoop.timingValue>1&&Browser.mainLoop.currentFrameNumber%Browser.mainLoop.timingValue!=0){Browser.mainLoop.scheduler();return}else Browser.mainLoop.timingMode==0&&(Browser.mainLoop.tickStartTime=_emscripten_get_now());Browser.mainLoop.method===\"timeout\"&&Module.ctx&&(Module.printErr(\"Looks like you are rendering without using requestAnimationFrame for the main loop. You should use 0 for the frame rate in emscripten_set_main_loop in order to use requestAnimationFrame, as that can greatly improve your frame rates!\"),Browser.mainLoop.method=\"\"),Browser.mainLoop.runIter(n),!(c<Browser.mainLoop.currentlyRunningMainloop)&&(typeof SDL==\"object\"&&SDL.audio&&SDL.audio.queueNewAudioData&&SDL.audio.queueNewAudioData(),Browser.mainLoop.scheduler())}}},a||(e&&e>0?_emscripten_set_main_loop_timing(0,1e3/e):_emscripten_set_main_loop_timing(1,1),Browser.mainLoop.scheduler()),r)throw\"SimulateInfiniteLoop\"}var Browser={mainLoop:{scheduler:null,method:\"\",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],pause:function(){Browser.mainLoop.scheduler=null,Browser.mainLoop.currentlyRunningMainloop++},resume:function(){Browser.mainLoop.currentlyRunningMainloop++;var t=Browser.mainLoop.timingMode,e=Browser.mainLoop.timingValue,r=Browser.mainLoop.func;Browser.mainLoop.func=null,_emscripten_set_main_loop(r,0,!1,Browser.mainLoop.arg,!0),_emscripten_set_main_loop_timing(t,e),Browser.mainLoop.scheduler()},updateStatus:function(){if(Module.setStatus){var t=Module.statusMessage||\"Please wait...\",e=Browser.mainLoop.remainingBlockers,r=Browser.mainLoop.expectedBlockers;e?e<r?Module.setStatus(t+\" (\"+(r-e)+\"/\"+r+\")\"):Module.setStatus(t):Module.setStatus(\"\")}},runIter:function(t){if(!ABORT){if(Module.preMainLoop){var e=Module.preMainLoop();if(e===!1)return}try{t()}catch(r){if(r instanceof ExitStatus)return;throw r&&typeof r==\"object\"&&r.stack&&Module.printErr(\"exception thrown: \"+[r,r.stack]),r}Module.postMainLoop&&Module.postMainLoop()}}},isFullscreen:!1,pointerLock:!1,moduleContextCreatedCallbacks:[],workers:[],init:function(){if(Module.preloadPlugins||(Module.preloadPlugins=[]),Browser.initted)return;Browser.initted=!0;try{new Blob,Browser.hasBlobConstructor=!0}catch{Browser.hasBlobConstructor=!1,console.log(\"warning: no blob constructor, cannot create blobs with mimetypes\")}Browser.BlobBuilder=typeof MozBlobBuilder<\"u\"?MozBlobBuilder:typeof WebKitBlobBuilder<\"u\"?WebKitBlobBuilder:Browser.hasBlobConstructor?null:console.log(\"warning: no BlobBuilder\"),Browser.URLObject=typeof window<\"u\"?window.URL?window.URL:window.webkitURL:void 0,!Module.noImageDecoding&&typeof Browser.URLObject>\"u\"&&(console.log(\"warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.\"),Module.noImageDecoding=!0);var t={};t.canHandle=function(n){return!Module.noImageDecoding&&/\\.(jpg|jpeg|png|bmp)$/i.test(n)},t.handle=function(n,c,f,p){var h=null;if(Browser.hasBlobConstructor)try{h=new Blob([n],{type:Browser.getMimetype(c)}),h.size!==n.length&&(h=new Blob([new Uint8Array(n).buffer],{type:Browser.getMimetype(c)}))}catch(b){Runtime.warnOnce(\"Blob constructor present but fails: \"+b+\"; falling back to blob builder\")}if(!h){var E=new Browser.BlobBuilder;E.append(new Uint8Array(n).buffer),h=E.getBlob()}var C=Browser.URLObject.createObjectURL(h),S=new Image;S.onload=function(){assert(S.complete,\"Image \"+c+\" could not be decoded\");var I=document.createElement(\"canvas\");I.width=S.width,I.height=S.height;var T=I.getContext(\"2d\");T.drawImage(S,0,0),Module.preloadedImages[c]=I,Browser.URLObject.revokeObjectURL(C),f&&f(n)},S.onerror=function(I){console.log(\"Image \"+C+\" could not be decoded\"),p&&p()},S.src=C},Module.preloadPlugins.push(t);var e={};e.canHandle=function(n){return!Module.noAudioDecoding&&n.substr(-4)in{\".ogg\":1,\".wav\":1,\".mp3\":1}},e.handle=function(n,c,f,p){var h=!1;function E(T){h||(h=!0,Module.preloadedAudios[c]=T,f&&f(n))}function C(){h||(h=!0,Module.preloadedAudios[c]=new Audio,p&&p())}if(Browser.hasBlobConstructor){try{var S=new Blob([n],{type:Browser.getMimetype(c)})}catch{return C()}var b=Browser.URLObject.createObjectURL(S),I=new Audio;I.addEventListener(\"canplaythrough\",function(){E(I)},!1),I.onerror=function(N){if(h)return;console.log(\"warning: browser could not fully decode audio \"+c+\", trying slower base64 approach\");function U(W){for(var ee=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\",ie=\"=\",ue=\"\",le=0,me=0,pe=0;pe<W.length;pe++)for(le=le<<8|W[pe],me+=8;me>=6;){var Be=le>>me-6&63;me-=6,ue+=ee[Be]}return me==2?(ue+=ee[(le&3)<<4],ue+=ie+ie):me==4&&(ue+=ee[(le&15)<<2],ue+=ie),ue}I.src=\"data:audio/x-\"+c.substr(-3)+\";base64,\"+U(n),E(I)},I.src=b,Browser.safeSetTimeout(function(){E(I)},1e4)}else return C()},Module.preloadPlugins.push(e);function r(){Browser.pointerLock=document.pointerLockElement===Module.canvas||document.mozPointerLockElement===Module.canvas||document.webkitPointerLockElement===Module.canvas||document.msPointerLockElement===Module.canvas}var s=Module.canvas;s&&(s.requestPointerLock=s.requestPointerLock||s.mozRequestPointerLock||s.webkitRequestPointerLock||s.msRequestPointerLock||function(){},s.exitPointerLock=document.exitPointerLock||document.mozExitPointerLock||document.webkitExitPointerLock||document.msExitPointerLock||function(){},s.exitPointerLock=s.exitPointerLock.bind(document),document.addEventListener(\"pointerlockchange\",r,!1),document.addEventListener(\"mozpointerlockchange\",r,!1),document.addEventListener(\"webkitpointerlockchange\",r,!1),document.addEventListener(\"mspointerlockchange\",r,!1),Module.elementPointerLock&&s.addEventListener(\"click\",function(a){!Browser.pointerLock&&Module.canvas.requestPointerLock&&(Module.canvas.requestPointerLock(),a.preventDefault())},!1))},createContext:function(t,e,r,s){if(e&&Module.ctx&&t==Module.canvas)return Module.ctx;var a,n;if(e){var c={antialias:!1,alpha:!1};if(s)for(var f in s)c[f]=s[f];n=GL.createContext(t,c),n&&(a=GL.getContext(n).GLctx)}else a=t.getContext(\"2d\");return a?(r&&(e||assert(typeof GLctx>\"u\",\"cannot set in module if GLctx is used, but we are a non-GL context that would replace it\"),Module.ctx=a,e&&GL.makeContextCurrent(n),Module.useWebGL=e,Browser.moduleContextCreatedCallbacks.forEach(function(p){p()}),Browser.init()),a):null},destroyContext:function(t,e,r){},fullscreenHandlersInstalled:!1,lockPointer:void 0,resizeCanvas:void 0,requestFullscreen:function(t,e,r){Browser.lockPointer=t,Browser.resizeCanvas=e,Browser.vrDevice=r,typeof Browser.lockPointer>\"u\"&&(Browser.lockPointer=!0),typeof Browser.resizeCanvas>\"u\"&&(Browser.resizeCanvas=!1),typeof Browser.vrDevice>\"u\"&&(Browser.vrDevice=null);var s=Module.canvas;function a(){Browser.isFullscreen=!1;var c=s.parentNode;(document.fullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||document.webkitFullscreenElement||document.webkitCurrentFullScreenElement)===c?(s.exitFullscreen=document.exitFullscreen||document.cancelFullScreen||document.mozCancelFullScreen||document.msExitFullscreen||document.webkitCancelFullScreen||function(){},s.exitFullscreen=s.exitFullscreen.bind(document),Browser.lockPointer&&s.requestPointerLock(),Browser.isFullscreen=!0,Browser.resizeCanvas&&Browser.setFullscreenCanvasSize()):(c.parentNode.insertBefore(s,c),c.parentNode.removeChild(c),Browser.resizeCanvas&&Browser.setWindowedCanvasSize()),Module.onFullScreen&&Module.onFullScreen(Browser.isFullscreen),Module.onFullscreen&&Module.onFullscreen(Browser.isFullscreen),Browser.updateCanvasDimensions(s)}Browser.fullscreenHandlersInstalled||(Browser.fullscreenHandlersInstalled=!0,document.addEventListener(\"fullscreenchange\",a,!1),document.addEventListener(\"mozfullscreenchange\",a,!1),document.addEventListener(\"webkitfullscreenchange\",a,!1),document.addEventListener(\"MSFullscreenChange\",a,!1));var n=document.createElement(\"div\");s.parentNode.insertBefore(n,s),n.appendChild(s),n.requestFullscreen=n.requestFullscreen||n.mozRequestFullScreen||n.msRequestFullscreen||(n.webkitRequestFullscreen?function(){n.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT)}:null)||(n.webkitRequestFullScreen?function(){n.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT)}:null),r?n.requestFullscreen({vrDisplay:r}):n.requestFullscreen()},requestFullScreen:function(t,e,r){return Module.printErr(\"Browser.requestFullScreen() is deprecated. Please call Browser.requestFullscreen instead.\"),Browser.requestFullScreen=function(s,a,n){return Browser.requestFullscreen(s,a,n)},Browser.requestFullscreen(t,e,r)},nextRAF:0,fakeRequestAnimationFrame:function(t){var e=Date.now();if(Browser.nextRAF===0)Browser.nextRAF=e+1e3/60;else for(;e+2>=Browser.nextRAF;)Browser.nextRAF+=1e3/60;var r=Math.max(Browser.nextRAF-e,0);setTimeout(t,r)},requestAnimationFrame:function t(e){typeof window>\"u\"?Browser.fakeRequestAnimationFrame(e):(window.requestAnimationFrame||(window.requestAnimationFrame=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame||window.oRequestAnimationFrame||Browser.fakeRequestAnimationFrame),window.requestAnimationFrame(e))},safeCallback:function(t){return function(){if(!ABORT)return t.apply(null,arguments)}},allowAsyncCallbacks:!0,queuedAsyncCallbacks:[],pauseAsyncCallbacks:function(){Browser.allowAsyncCallbacks=!1},resumeAsyncCallbacks:function(){if(Browser.allowAsyncCallbacks=!0,Browser.queuedAsyncCallbacks.length>0){var t=Browser.queuedAsyncCallbacks;Browser.queuedAsyncCallbacks=[],t.forEach(function(e){e()})}},safeRequestAnimationFrame:function(t){return Browser.requestAnimationFrame(function(){ABORT||(Browser.allowAsyncCallbacks?t():Browser.queuedAsyncCallbacks.push(t))})},safeSetTimeout:function(t,e){return Module.noExitRuntime=!0,setTimeout(function(){ABORT||(Browser.allowAsyncCallbacks?t():Browser.queuedAsyncCallbacks.push(t))},e)},safeSetInterval:function(t,e){return Module.noExitRuntime=!0,setInterval(function(){ABORT||Browser.allowAsyncCallbacks&&t()},e)},getMimetype:function(t){return{jpg:\"image/jpeg\",jpeg:\"image/jpeg\",png:\"image/png\",bmp:\"image/bmp\",ogg:\"audio/ogg\",wav:\"audio/wav\",mp3:\"audio/mpeg\"}[t.substr(t.lastIndexOf(\".\")+1)]},getUserMedia:function(t){window.getUserMedia||(window.getUserMedia=navigator.getUserMedia||navigator.mozGetUserMedia),window.getUserMedia(t)},getMovementX:function(t){return t.movementX||t.mozMovementX||t.webkitMovementX||0},getMovementY:function(t){return t.movementY||t.mozMovementY||t.webkitMovementY||0},getMouseWheelDelta:function(t){var e=0;switch(t.type){case\"DOMMouseScroll\":e=t.detail;break;case\"mousewheel\":e=t.wheelDelta;break;case\"wheel\":e=t.deltaY;break;default:throw\"unrecognized mouse wheel event: \"+t.type}return e},mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,touches:{},lastTouches:{},calculateMouseEvent:function(t){if(Browser.pointerLock)t.type!=\"mousemove\"&&\"mozMovementX\"in t?Browser.mouseMovementX=Browser.mouseMovementY=0:(Browser.mouseMovementX=Browser.getMovementX(t),Browser.mouseMovementY=Browser.getMovementY(t)),typeof SDL<\"u\"?(Browser.mouseX=SDL.mouseX+Browser.mouseMovementX,Browser.mouseY=SDL.mouseY+Browser.mouseMovementY):(Browser.mouseX+=Browser.mouseMovementX,Browser.mouseY+=Browser.mouseMovementY);else{var e=Module.canvas.getBoundingClientRect(),r=Module.canvas.width,s=Module.canvas.height,a=typeof window.scrollX<\"u\"?window.scrollX:window.pageXOffset,n=typeof window.scrollY<\"u\"?window.scrollY:window.pageYOffset;if(t.type===\"touchstart\"||t.type===\"touchend\"||t.type===\"touchmove\"){var c=t.touch;if(c===void 0)return;var f=c.pageX-(a+e.left),p=c.pageY-(n+e.top);f=f*(r/e.width),p=p*(s/e.height);var h={x:f,y:p};if(t.type===\"touchstart\")Browser.lastTouches[c.identifier]=h,Browser.touches[c.identifier]=h;else if(t.type===\"touchend\"||t.type===\"touchmove\"){var E=Browser.touches[c.identifier];E||(E=h),Browser.lastTouches[c.identifier]=E,Browser.touches[c.identifier]=h}return}var C=t.pageX-(a+e.left),S=t.pageY-(n+e.top);C=C*(r/e.width),S=S*(s/e.height),Browser.mouseMovementX=C-Browser.mouseX,Browser.mouseMovementY=S-Browser.mouseY,Browser.mouseX=C,Browser.mouseY=S}},asyncLoad:function(t,e,r,s){var a=s?\"\":\"al \"+t;Module.readAsync(t,function(n){assert(n,'Loading data file \"'+t+'\" failed (no arrayBuffer).'),e(new Uint8Array(n)),a&&removeRunDependency(a)},function(n){if(r)r();else throw'Loading data file \"'+t+'\" failed.'}),a&&addRunDependency(a)},resizeListeners:[],updateResizeListeners:function(){var t=Module.canvas;Browser.resizeListeners.forEach(function(e){e(t.width,t.height)})},setCanvasSize:function(t,e,r){var s=Module.canvas;Browser.updateCanvasDimensions(s,t,e),r||Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize:function(){if(typeof SDL<\"u\"){var t=HEAPU32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2];t=t|8388608,HEAP32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2]=t}Browser.updateResizeListeners()},setWindowedCanvasSize:function(){if(typeof SDL<\"u\"){var t=HEAPU32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2];t=t&-8388609,HEAP32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2]=t}Browser.updateResizeListeners()},updateCanvasDimensions:function(t,e,r){e&&r?(t.widthNative=e,t.heightNative=r):(e=t.widthNative,r=t.heightNative);var s=e,a=r;if(Module.forcedAspectRatio&&Module.forcedAspectRatio>0&&(s/a<Module.forcedAspectRatio?s=Math.round(a*Module.forcedAspectRatio):a=Math.round(s/Module.forcedAspectRatio)),(document.fullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||document.webkitFullscreenElement||document.webkitCurrentFullScreenElement)===t.parentNode&&typeof screen<\"u\"){var n=Math.min(screen.width/s,screen.height/a);s=Math.round(s*n),a=Math.round(a*n)}Browser.resizeCanvas?(t.width!=s&&(t.width=s),t.height!=a&&(t.height=a),typeof t.style<\"u\"&&(t.style.removeProperty(\"width\"),t.style.removeProperty(\"height\"))):(t.width!=e&&(t.width=e),t.height!=r&&(t.height=r),typeof t.style<\"u\"&&(s!=e||a!=r?(t.style.setProperty(\"width\",s+\"px\",\"important\"),t.style.setProperty(\"height\",a+\"px\",\"important\")):(t.style.removeProperty(\"width\"),t.style.removeProperty(\"height\"))))},wgetRequests:{},nextWgetRequestHandle:0,getNextWgetRequestHandle:function(){var t=Browser.nextWgetRequestHandle;return Browser.nextWgetRequestHandle++,t}},SYSCALLS={varargs:0,get:function(t){SYSCALLS.varargs+=4;var e=HEAP32[SYSCALLS.varargs-4>>2];return e},getStr:function(){var t=Pointer_stringify(SYSCALLS.get());return t},get64:function(){var t=SYSCALLS.get(),e=SYSCALLS.get();return t>=0?assert(e===0):assert(e===-1),t},getZero:function(){assert(SYSCALLS.get()===0)}};function ___syscall6(t,e){SYSCALLS.varargs=e;try{var r=SYSCALLS.getStreamFromFD();return FS.close(r),0}catch(s){return(typeof FS>\"u\"||!(s instanceof FS.ErrnoError))&&abort(s),-s.errno}}function ___syscall54(t,e){SYSCALLS.varargs=e;try{return 0}catch(r){return(typeof FS>\"u\"||!(r instanceof FS.ErrnoError))&&abort(r),-r.errno}}function _typeModule(t){var e=[[0,1,\"X\"],[1,1,\"const X\"],[128,1,\"X *\"],[256,1,\"X &\"],[384,1,\"X &&\"],[512,1,\"std::shared_ptr<X>\"],[640,1,\"std::unique_ptr<X>\"],[5120,1,\"std::vector<X>\"],[6144,2,\"std::array<X, Y>\"],[9216,-1,\"std::function<X (Y)>\"]];function r(p,h,E,C,S,b){if(h==1){var I=C&896;(I==128||I==256||I==384)&&(p=\"X const\")}var T;return b?T=E.replace(\"X\",p).replace(\"Y\",S):T=p.replace(\"X\",E).replace(\"Y\",S),T.replace(/([*&]) (?=[*&])/g,\"$1\")}function s(p,h,E,C,S){throw new Error(p+\" type \"+E.replace(\"X\",h+\"?\")+(C?\" with flag \"+C:\"\")+\" in \"+S)}function a(p,h,E,C,S,b,I,T){b===void 0&&(b=\"X\"),T===void 0&&(T=1);var N=E(p);if(N)return N;var U=C(p),W=U.placeholderFlag,ee=e[W];I&&ee&&(b=r(I[2],I[0],b,ee[0],\"?\",!0));var ie;W==0&&(ie=\"Unbound\"),W>=10&&(ie=\"Corrupt\"),T>20&&(ie=\"Deeply nested\"),ie&&s(ie,p,b,W,S||\"?\");var ue=U.paramList[0],le=a(ue,h,E,C,S,b,ee,T+1),me,pe={flags:ee[0],id:p,name:\"\",paramList:[le]},Be=[],Ce=\"?\";switch(U.placeholderFlag){case 1:me=le.spec;break;case 2:if((le.flags&15360)==1024&&le.spec.ptrSize==1){pe.flags=7168;break}case 3:case 6:case 5:me=le.spec,le.flags&15360;break;case 8:Ce=\"\"+U.paramList[1],pe.paramList.push(U.paramList[1]);break;case 9:for(var g=0,we=U.paramList[1];g<we.length;g++){var ye=we[g],Ae=a(ye,h,E,C,S,b,ee,T+1);Be.push(Ae.name),pe.paramList.push(Ae)}Ce=Be.join(\", \");break;default:break}if(pe.name=r(ee[2],ee[0],le.name,le.flags,Ce),me){for(var se=0,X=Object.keys(me);se<X.length;se++){var De=X[se];pe[De]=pe[De]||me[De]}pe.flags|=me.flags}return n(h,pe)}function n(p,h){var E=h.flags,C=E&896,S=E&15360;return!h.name&&S==1024&&(h.ptrSize==1?h.name=(E&16?\"\":(E&8?\"un\":\"\")+\"signed \")+\"char\":h.name=(E&8?\"u\":\"\")+(E&32?\"float\":\"int\")+(h.ptrSize*8+\"_t\")),h.ptrSize==8&&!(E&32)&&(S=64),S==2048&&(C==512||C==640?S=4096:C&&(S=3072)),p(S,h)}var c=function(){function p(h){this.id=h.id,this.name=h.name,this.flags=h.flags,this.spec=h}return p.prototype.toString=function(){return this.name},p}(),f={Type:c,getComplexType:a,makeType:n,structureList:e};return t.output=f,t.output||f}function __nbind_register_type(t,e){var r=_nbind.readAsciiString(e),s={flags:10240,id:t,name:r};_nbind.makeType(_nbind.constructType,s)}function __nbind_register_callback_signature(t,e){var r=_nbind.readTypeIdList(t,e),s=_nbind.callbackSignatureList.length;return _nbind.callbackSignatureList[s]=_nbind.makeJSCaller(r),s}function __extends(t,e){for(var r in e)e.hasOwnProperty(r)&&(t[r]=e[r]);function s(){this.constructor=t}s.prototype=e.prototype,t.prototype=new s}function __nbind_register_class(t,e,r,s,a,n,c){var f=_nbind.readAsciiString(c),p=_nbind.readPolicyList(e),h=HEAPU32.subarray(t/4,t/4+2),E={flags:2048|(p.Value?2:0),id:h[0],name:f},C=_nbind.makeType(_nbind.constructType,E);C.ptrType=_nbind.getComplexType(h[1],_nbind.constructType,_nbind.getType,_nbind.queryType),C.destroy=_nbind.makeMethodCaller(C.ptrType,{boundID:E.id,flags:0,name:\"destroy\",num:0,ptr:n,title:C.name+\".free\",typeList:[\"void\",\"uint32_t\",\"uint32_t\"]}),a&&(C.superIdList=Array.prototype.slice.call(HEAPU32.subarray(r/4,r/4+a)),C.upcastList=Array.prototype.slice.call(HEAPU32.subarray(s/4,s/4+a))),Module[C.name]=C.makeBound(p),_nbind.BindClass.list.push(C)}function _removeAccessorPrefix(t){var e=/^[Gg]et_?([A-Z]?([A-Z]?))/;return t.replace(e,function(r,s,a){return a?s:s.toLowerCase()})}function __nbind_register_function(t,e,r,s,a,n,c,f,p,h){var E=_nbind.getType(t),C=_nbind.readPolicyList(e),S=_nbind.readTypeIdList(r,s),b;if(c==5)b=[{direct:a,name:\"__nbindConstructor\",ptr:0,title:E.name+\" constructor\",typeList:[\"uint32_t\"].concat(S.slice(1))},{direct:n,name:\"__nbindValueConstructor\",ptr:0,title:E.name+\" value constructor\",typeList:[\"void\",\"uint32_t\"].concat(S.slice(1))}];else{var I=_nbind.readAsciiString(f),T=(E.name&&E.name+\".\")+I;(c==3||c==4)&&(I=_removeAccessorPrefix(I)),b=[{boundID:t,direct:n,name:I,ptr:a,title:T,typeList:S}]}for(var N=0,U=b;N<U.length;N++){var W=U[N];W.signatureType=c,W.policyTbl=C,W.num=p,W.flags=h,E.addMethod(W)}}function _nbind_value(t,e){_nbind.typeNameTbl[t]||_nbind.throwError(\"Unknown value type \"+t),Module.NBind.bind_value(t,e),_defineHidden(_nbind.typeNameTbl[t].proto.prototype.__nbindValueConstructor)(e.prototype,\"__nbindValueConstructor\")}Module._nbind_value=_nbind_value;function __nbind_get_value_object(t,e){var r=_nbind.popValue(t);if(!r.fromJS)throw new Error(\"Object \"+r+\" has no fromJS function\");r.fromJS(function(){r.__nbindValueConstructor.apply(this,Array.prototype.concat.apply([e],arguments))})}function _emscripten_memcpy_big(t,e,r){return HEAPU8.set(HEAPU8.subarray(e,e+r),t),t}function __nbind_register_primitive(t,e,r){var s={flags:1024|r,id:t,ptrSize:e};_nbind.makeType(_nbind.constructType,s)}var cttz_i8=allocate([8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0],\"i8\",ALLOC_STATIC);function ___setErrNo(t){return Module.___errno_location&&(HEAP32[Module.___errno_location()>>2]=t),t}function _llvm_stacksave(){var t=_llvm_stacksave;return t.LLVM_SAVEDSTACKS||(t.LLVM_SAVEDSTACKS=[]),t.LLVM_SAVEDSTACKS.push(Runtime.stackSave()),t.LLVM_SAVEDSTACKS.length-1}function ___syscall140(t,e){SYSCALLS.varargs=e;try{var r=SYSCALLS.getStreamFromFD(),s=SYSCALLS.get(),a=SYSCALLS.get(),n=SYSCALLS.get(),c=SYSCALLS.get(),f=a;return FS.llseek(r,f,c),HEAP32[n>>2]=r.position,r.getdents&&f===0&&c===0&&(r.getdents=null),0}catch(p){return(typeof FS>\"u\"||!(p instanceof FS.ErrnoError))&&abort(p),-p.errno}}function ___syscall146(t,e){SYSCALLS.varargs=e;try{var r=SYSCALLS.get(),s=SYSCALLS.get(),a=SYSCALLS.get(),n=0;___syscall146.buffer||(___syscall146.buffers=[null,[],[]],___syscall146.printChar=function(E,C){var S=___syscall146.buffers[E];assert(S),C===0||C===10?((E===1?Module.print:Module.printErr)(UTF8ArrayToString(S,0)),S.length=0):S.push(C)});for(var c=0;c<a;c++){for(var f=HEAP32[s+c*8>>2],p=HEAP32[s+(c*8+4)>>2],h=0;h<p;h++)___syscall146.printChar(r,HEAPU8[f+h]);n+=p}return n}catch(E){return(typeof FS>\"u\"||!(E instanceof FS.ErrnoError))&&abort(E),-E.errno}}function __nbind_finish(){for(var t=0,e=_nbind.BindClass.list;t<e.length;t++){var r=e[t];r.finish()}}var ___dso_handle=STATICTOP;STATICTOP+=16,function(_nbind){var typeIdTbl={};_nbind.typeNameTbl={};var Pool=function(){function t(){}return t.lalloc=function(e){e=e+7&-8;var r=HEAPU32[t.usedPtr];if(e>t.pageSize/2||e>t.pageSize-r){var s=_nbind.typeNameTbl.NBind.proto;return s.lalloc(e)}else return HEAPU32[t.usedPtr]=r+e,t.rootPtr+r},t.lreset=function(e,r){var s=HEAPU32[t.pagePtr];if(s){var a=_nbind.typeNameTbl.NBind.proto;a.lreset(e,r)}else HEAPU32[t.usedPtr]=e},t}();_nbind.Pool=Pool;function constructType(t,e){var r=t==10240?_nbind.makeTypeNameTbl[e.name]||_nbind.BindType:_nbind.makeTypeKindTbl[t],s=new r(e);return typeIdTbl[e.id]=s,_nbind.typeNameTbl[e.name]=s,s}_nbind.constructType=constructType;function getType(t){return typeIdTbl[t]}_nbind.getType=getType;function queryType(t){var e=HEAPU8[t],r=_nbind.structureList[e][1];t/=4,r<0&&(++t,r=HEAPU32[t]+1);var s=Array.prototype.slice.call(HEAPU32.subarray(t+1,t+1+r));return e==9&&(s=[s[0],s.slice(1)]),{paramList:s,placeholderFlag:e}}_nbind.queryType=queryType;function getTypes(t,e){return t.map(function(r){return typeof r==\"number\"?_nbind.getComplexType(r,constructType,getType,queryType,e):_nbind.typeNameTbl[r]})}_nbind.getTypes=getTypes;function readTypeIdList(t,e){return Array.prototype.slice.call(HEAPU32,t/4,t/4+e)}_nbind.readTypeIdList=readTypeIdList;function readAsciiString(t){for(var e=t;HEAPU8[e++];);return String.fromCharCode.apply(\"\",HEAPU8.subarray(t,e-1))}_nbind.readAsciiString=readAsciiString;function readPolicyList(t){var e={};if(t)for(;;){var r=HEAPU32[t/4];if(!r)break;e[readAsciiString(r)]=!0,t+=4}return e}_nbind.readPolicyList=readPolicyList;function getDynCall(t,e){var r={float32_t:\"d\",float64_t:\"d\",int64_t:\"d\",uint64_t:\"d\",void:\"v\"},s=t.map(function(n){return r[n.name]||\"i\"}).join(\"\"),a=Module[\"dynCall_\"+s];if(!a)throw new Error(\"dynCall_\"+s+\" not found for \"+e+\"(\"+t.map(function(n){return n.name}).join(\", \")+\")\");return a}_nbind.getDynCall=getDynCall;function addMethod(t,e,r,s){var a=t[e];t.hasOwnProperty(e)&&a?((a.arity||a.arity===0)&&(a=_nbind.makeOverloader(a,a.arity),t[e]=a),a.addMethod(r,s)):(r.arity=s,t[e]=r)}_nbind.addMethod=addMethod;function throwError(t){throw new Error(t)}_nbind.throwError=throwError,_nbind.bigEndian=!1,_a=_typeModule(_typeModule),_nbind.Type=_a.Type,_nbind.makeType=_a.makeType,_nbind.getComplexType=_a.getComplexType,_nbind.structureList=_a.structureList;var BindType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.heap=HEAPU32,r.ptrSize=4,r}return e.prototype.needsWireRead=function(r){return!!this.wireRead||!!this.makeWireRead},e.prototype.needsWireWrite=function(r){return!!this.wireWrite||!!this.makeWireWrite},e}(_nbind.Type);_nbind.BindType=BindType;var PrimitiveType=function(t){__extends(e,t);function e(r){var s=t.call(this,r)||this,a=r.flags&32?{32:HEAPF32,64:HEAPF64}:r.flags&8?{8:HEAPU8,16:HEAPU16,32:HEAPU32}:{8:HEAP8,16:HEAP16,32:HEAP32};return s.heap=a[r.ptrSize*8],s.ptrSize=r.ptrSize,s}return e.prototype.needsWireWrite=function(r){return!!r&&!!r.Strict},e.prototype.makeWireWrite=function(r,s){return s&&s.Strict&&function(a){if(typeof a==\"number\")return a;throw new Error(\"Type mismatch\")}},e}(BindType);_nbind.PrimitiveType=PrimitiveType;function pushCString(t,e){if(t==null){if(e&&e.Nullable)return 0;throw new Error(\"Type mismatch\")}if(e&&e.Strict){if(typeof t!=\"string\")throw new Error(\"Type mismatch\")}else t=t.toString();var r=Module.lengthBytesUTF8(t)+1,s=_nbind.Pool.lalloc(r);return Module.stringToUTF8Array(t,HEAPU8,s,r),s}_nbind.pushCString=pushCString;function popCString(t){return t===0?null:Module.Pointer_stringify(t)}_nbind.popCString=popCString;var CStringType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireRead=popCString,r.wireWrite=pushCString,r.readResources=[_nbind.resources.pool],r.writeResources=[_nbind.resources.pool],r}return e.prototype.makeWireWrite=function(r,s){return function(a){return pushCString(a,s)}},e}(BindType);_nbind.CStringType=CStringType;var BooleanType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireRead=function(s){return!!s},r}return e.prototype.needsWireWrite=function(r){return!!r&&!!r.Strict},e.prototype.makeWireRead=function(r){return\"!!(\"+r+\")\"},e.prototype.makeWireWrite=function(r,s){return s&&s.Strict&&function(a){if(typeof a==\"boolean\")return a;throw new Error(\"Type mismatch\")}||r},e}(BindType);_nbind.BooleanType=BooleanType;var Wrapper=function(){function t(){}return t.prototype.persist=function(){this.__nbindState|=1},t}();_nbind.Wrapper=Wrapper;function makeBound(t,e){var r=function(s){__extends(a,s);function a(n,c,f,p){var h=s.call(this)||this;if(!(h instanceof a))return new(Function.prototype.bind.apply(a,Array.prototype.concat.apply([null],arguments)));var E=c,C=f,S=p;if(n!==_nbind.ptrMarker){var b=h.__nbindConstructor.apply(h,arguments);E=4608,S=HEAPU32[b/4],C=HEAPU32[b/4+1]}var I={configurable:!0,enumerable:!1,value:null,writable:!1},T={__nbindFlags:E,__nbindPtr:C};S&&(T.__nbindShared=S,_nbind.mark(h));for(var N=0,U=Object.keys(T);N<U.length;N++){var W=U[N];I.value=T[W],Object.defineProperty(h,W,I)}return _defineHidden(0)(h,\"__nbindState\"),h}return a.prototype.free=function(){e.destroy.call(this,this.__nbindShared,this.__nbindFlags),this.__nbindState|=2,disableMember(this,\"__nbindShared\"),disableMember(this,\"__nbindPtr\")},a}(Wrapper);return __decorate([_defineHidden()],r.prototype,\"__nbindConstructor\",void 0),__decorate([_defineHidden()],r.prototype,\"__nbindValueConstructor\",void 0),__decorate([_defineHidden(t)],r.prototype,\"__nbindPolicies\",void 0),r}_nbind.makeBound=makeBound;function disableMember(t,e){function r(){throw new Error(\"Accessing deleted object\")}Object.defineProperty(t,e,{configurable:!1,enumerable:!1,get:r,set:r})}_nbind.ptrMarker={};var BindClass=function(t){__extends(e,t);function e(r){var s=t.call(this,r)||this;return s.wireRead=function(a){return _nbind.popValue(a,s.ptrType)},s.wireWrite=function(a){return pushPointer(a,s.ptrType,!0)},s.pendingSuperCount=0,s.ready=!1,s.methodTbl={},r.paramList?(s.classType=r.paramList[0].classType,s.proto=s.classType.proto):s.classType=s,s}return e.prototype.makeBound=function(r){var s=_nbind.makeBound(r,this);return this.proto=s,this.ptrType.proto=s,s},e.prototype.addMethod=function(r){var s=this.methodTbl[r.name]||[];s.push(r),this.methodTbl[r.name]=s},e.prototype.registerMethods=function(r,s){for(var a,n=0,c=Object.keys(r.methodTbl);n<c.length;n++)for(var f=c[n],p=r.methodTbl[f],h=0,E=p;h<E.length;h++){var C=E[h],S=void 0,b=void 0;if(S=this.proto.prototype,!(s&&C.signatureType!=1))switch(C.signatureType){case 1:S=this.proto;case 5:b=_nbind.makeCaller(C),_nbind.addMethod(S,C.name,b,C.typeList.length-1);break;case 4:a=_nbind.makeMethodCaller(r.ptrType,C);break;case 3:Object.defineProperty(S,C.name,{configurable:!0,enumerable:!1,get:_nbind.makeMethodCaller(r.ptrType,C),set:a});break;case 2:b=_nbind.makeMethodCaller(r.ptrType,C),_nbind.addMethod(S,C.name,b,C.typeList.length-1);break;default:break}}},e.prototype.registerSuperMethods=function(r,s,a){if(!a[r.name]){a[r.name]=!0;for(var n=0,c,f=0,p=r.superIdList||[];f<p.length;f++){var h=p[f],E=_nbind.getType(h);n++<s||s<0?c=-1:c=0,this.registerSuperMethods(E,c,a)}this.registerMethods(r,s<0)}},e.prototype.finish=function(){if(this.ready)return this;this.ready=!0,this.superList=(this.superIdList||[]).map(function(a){return _nbind.getType(a).finish()});var r=this.proto;if(this.superList.length){var s=function(){this.constructor=r};s.prototype=this.superList[0].proto.prototype,r.prototype=new s}return r!=Module&&(r.prototype.__nbindType=this),this.registerSuperMethods(this,1,{}),this},e.prototype.upcastStep=function(r,s){if(r==this)return s;for(var a=0;a<this.superList.length;++a){var n=this.superList[a].upcastStep(r,_nbind.callUpcast(this.upcastList[a],s));if(n)return n}return 0},e}(_nbind.BindType);BindClass.list=[],_nbind.BindClass=BindClass;function popPointer(t,e){return t?new e.proto(_nbind.ptrMarker,e.flags,t):null}_nbind.popPointer=popPointer;function pushPointer(t,e,r){if(!(t instanceof _nbind.Wrapper)){if(r)return _nbind.pushValue(t);throw new Error(\"Type mismatch\")}var s=t.__nbindPtr,a=t.__nbindType.classType,n=e.classType;if(t instanceof e.proto)for(;a!=n;)s=_nbind.callUpcast(a.upcastList[0],s),a=a.superList[0];else if(s=a.upcastStep(n,s),!s)throw new Error(\"Type mismatch\");return s}_nbind.pushPointer=pushPointer;function pushMutablePointer(t,e){var r=pushPointer(t,e);if(t.__nbindFlags&1)throw new Error(\"Passing a const value as a non-const argument\");return r}var BindClassPtr=function(t){__extends(e,t);function e(r){var s=t.call(this,r)||this;s.classType=r.paramList[0].classType,s.proto=s.classType.proto;var a=r.flags&1,n=(s.flags&896)==256&&r.flags&2,c=a?pushPointer:pushMutablePointer,f=n?_nbind.popValue:popPointer;return s.makeWireWrite=function(p,h){return h.Nullable?function(E){return E?c(E,s):0}:function(E){return c(E,s)}},s.wireRead=function(p){return f(p,s)},s.wireWrite=function(p){return c(p,s)},s}return e}(_nbind.BindType);_nbind.BindClassPtr=BindClassPtr;function popShared(t,e){var r=HEAPU32[t/4],s=HEAPU32[t/4+1];return s?new e.proto(_nbind.ptrMarker,e.flags,s,r):null}_nbind.popShared=popShared;function pushShared(t,e){if(!(t instanceof e.proto))throw new Error(\"Type mismatch\");return t.__nbindShared}function pushMutableShared(t,e){if(!(t instanceof e.proto))throw new Error(\"Type mismatch\");if(t.__nbindFlags&1)throw new Error(\"Passing a const value as a non-const argument\");return t.__nbindShared}var SharedClassPtr=function(t){__extends(e,t);function e(r){var s=t.call(this,r)||this;s.readResources=[_nbind.resources.pool],s.classType=r.paramList[0].classType,s.proto=s.classType.proto;var a=r.flags&1,n=a?pushShared:pushMutableShared;return s.wireRead=function(c){return popShared(c,s)},s.wireWrite=function(c){return n(c,s)},s}return e}(_nbind.BindType);_nbind.SharedClassPtr=SharedClassPtr,_nbind.externalList=[0];var firstFreeExternal=0,External=function(){function t(e){this.refCount=1,this.data=e}return t.prototype.register=function(){var e=firstFreeExternal;return e?firstFreeExternal=_nbind.externalList[e]:e=_nbind.externalList.length,_nbind.externalList[e]=this,e},t.prototype.reference=function(){++this.refCount},t.prototype.dereference=function(e){--this.refCount==0&&(this.free&&this.free(),_nbind.externalList[e]=firstFreeExternal,firstFreeExternal=e)},t}();_nbind.External=External;function popExternal(t){var e=_nbind.externalList[t];return e.dereference(t),e.data}function pushExternal(t){var e=new External(t);return e.reference(),e.register()}var ExternalType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireRead=popExternal,r.wireWrite=pushExternal,r}return e}(_nbind.BindType);_nbind.ExternalType=ExternalType,_nbind.callbackSignatureList=[];var CallbackType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireWrite=function(s){return typeof s!=\"function\"&&_nbind.throwError(\"Type mismatch\"),new _nbind.External(s).register()},r}return e}(_nbind.BindType);_nbind.CallbackType=CallbackType,_nbind.valueList=[0];var firstFreeValue=0;function pushValue(t){var e=firstFreeValue;return e?firstFreeValue=_nbind.valueList[e]:e=_nbind.valueList.length,_nbind.valueList[e]=t,e*2+1}_nbind.pushValue=pushValue;function popValue(t,e){if(t||_nbind.throwError(\"Value type JavaScript class is missing or not registered\"),t&1){t>>=1;var r=_nbind.valueList[t];return _nbind.valueList[t]=firstFreeValue,firstFreeValue=t,r}else{if(e)return _nbind.popShared(t,e);throw new Error(\"Invalid value slot \"+t)}}_nbind.popValue=popValue;var valueBase=18446744073709552e3;function push64(t){return typeof t==\"number\"?t:pushValue(t)*4096+valueBase}function pop64(t){return t<valueBase?t:popValue((t-valueBase)/4096)}var CreateValueType=function(t){__extends(e,t);function e(){return t!==null&&t.apply(this,arguments)||this}return e.prototype.makeWireWrite=function(r){return\"(_nbind.pushValue(new \"+r+\"))\"},e}(_nbind.BindType);_nbind.CreateValueType=CreateValueType;var Int64Type=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireWrite=push64,r.wireRead=pop64,r}return e}(_nbind.BindType);_nbind.Int64Type=Int64Type;function pushArray(t,e){if(!t)return 0;var r=t.length;if((e.size||e.size===0)&&r<e.size)throw new Error(\"Type mismatch\");var s=e.memberType.ptrSize,a=_nbind.Pool.lalloc(4+r*s);HEAPU32[a/4]=r;var n=e.memberType.heap,c=(a+4)/s,f=e.memberType.wireWrite,p=0;if(f)for(;p<r;)n[c++]=f(t[p++]);else for(;p<r;)n[c++]=t[p++];return a}_nbind.pushArray=pushArray;function popArray(t,e){if(t===0)return null;var r=HEAPU32[t/4],s=new Array(r),a=e.memberType.heap;t=(t+4)/e.memberType.ptrSize;var n=e.memberType.wireRead,c=0;if(n)for(;c<r;)s[c++]=n(a[t++]);else for(;c<r;)s[c++]=a[t++];return s}_nbind.popArray=popArray;var ArrayType=function(t){__extends(e,t);function e(r){var s=t.call(this,r)||this;return s.wireRead=function(a){return popArray(a,s)},s.wireWrite=function(a){return pushArray(a,s)},s.readResources=[_nbind.resources.pool],s.writeResources=[_nbind.resources.pool],s.memberType=r.paramList[0],r.paramList[1]&&(s.size=r.paramList[1]),s}return e}(_nbind.BindType);_nbind.ArrayType=ArrayType;function pushString(t,e){if(t==null)if(e&&e.Nullable)t=\"\";else throw new Error(\"Type mismatch\");if(e&&e.Strict){if(typeof t!=\"string\")throw new Error(\"Type mismatch\")}else t=t.toString();var r=Module.lengthBytesUTF8(t),s=_nbind.Pool.lalloc(4+r+1);return HEAPU32[s/4]=r,Module.stringToUTF8Array(t,HEAPU8,s+4,r+1),s}_nbind.pushString=pushString;function popString(t){if(t===0)return null;var e=HEAPU32[t/4];return Module.Pointer_stringify(t+4,e)}_nbind.popString=popString;var StringType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireRead=popString,r.wireWrite=pushString,r.readResources=[_nbind.resources.pool],r.writeResources=[_nbind.resources.pool],r}return e.prototype.makeWireWrite=function(r,s){return function(a){return pushString(a,s)}},e}(_nbind.BindType);_nbind.StringType=StringType;function makeArgList(t){return Array.apply(null,Array(t)).map(function(e,r){return\"a\"+(r+1)})}function anyNeedsWireWrite(t,e){return t.reduce(function(r,s){return r||s.needsWireWrite(e)},!1)}function anyNeedsWireRead(t,e){return t.reduce(function(r,s){return r||!!s.needsWireRead(e)},!1)}function makeWireRead(t,e,r,s){var a=t.length;return r.makeWireRead?r.makeWireRead(s,t,a):r.wireRead?(t[a]=r.wireRead,\"(convertParamList[\"+a+\"](\"+s+\"))\"):s}function makeWireWrite(t,e,r,s){var a,n=t.length;return r.makeWireWrite?a=r.makeWireWrite(s,e,t,n):a=r.wireWrite,a?typeof a==\"string\"?a:(t[n]=a,\"(convertParamList[\"+n+\"](\"+s+\"))\"):s}function buildCallerFunction(dynCall,ptrType,ptr,num,policyTbl,needsWireWrite,prefix,returnType,argTypeList,mask,err){var argList=makeArgList(argTypeList.length),convertParamList=[],callExpression=makeWireRead(convertParamList,policyTbl,returnType,\"dynCall(\"+[prefix].concat(argList.map(function(t,e){return makeWireWrite(convertParamList,policyTbl,argTypeList[e],t)})).join(\",\")+\")\"),resourceSet=_nbind.listResources([returnType],argTypeList),sourceCode=\"function(\"+argList.join(\",\")+\"){\"+(mask?\"this.__nbindFlags&mask&&err();\":\"\")+resourceSet.makeOpen()+\"var r=\"+callExpression+\";\"+resourceSet.makeClose()+\"return r;}\";return eval(\"(\"+sourceCode+\")\")}function buildJSCallerFunction(returnType,argTypeList){var argList=makeArgList(argTypeList.length),convertParamList=[],callExpression=makeWireWrite(convertParamList,null,returnType,\"_nbind.externalList[num].data(\"+argList.map(function(t,e){return makeWireRead(convertParamList,null,argTypeList[e],t)}).join(\",\")+\")\"),resourceSet=_nbind.listResources(argTypeList,[returnType]);resourceSet.remove(_nbind.resources.pool);var sourceCode=\"function(\"+[\"dummy\",\"num\"].concat(argList).join(\",\")+\"){\"+resourceSet.makeOpen()+\"var r=\"+callExpression+\";\"+resourceSet.makeClose()+\"return r;}\";return eval(\"(\"+sourceCode+\")\")}_nbind.buildJSCallerFunction=buildJSCallerFunction;function makeJSCaller(t){var e=t.length-1,r=_nbind.getTypes(t,\"callback\"),s=r[0],a=r.slice(1),n=anyNeedsWireRead(a,null),c=s.needsWireWrite(null);if(!c&&!n)switch(e){case 0:return function(f,p){return _nbind.externalList[p].data()};case 1:return function(f,p,h){return _nbind.externalList[p].data(h)};case 2:return function(f,p,h,E){return _nbind.externalList[p].data(h,E)};case 3:return function(f,p,h,E,C){return _nbind.externalList[p].data(h,E,C)};default:break}return buildJSCallerFunction(s,a)}_nbind.makeJSCaller=makeJSCaller;function makeMethodCaller(t,e){var r=e.typeList.length-1,s=e.typeList.slice(0);s.splice(1,0,\"uint32_t\",e.boundID);var a=_nbind.getTypes(s,e.title),n=a[0],c=a.slice(3),f=n.needsWireRead(e.policyTbl),p=anyNeedsWireWrite(c,e.policyTbl),h=e.ptr,E=e.num,C=_nbind.getDynCall(a,e.title),S=~e.flags&1;function b(){throw new Error(\"Calling a non-const method on a const object\")}if(!f&&!p)switch(r){case 0:return function(){return this.__nbindFlags&S?b():C(h,E,_nbind.pushPointer(this,t))};case 1:return function(I){return this.__nbindFlags&S?b():C(h,E,_nbind.pushPointer(this,t),I)};case 2:return function(I,T){return this.__nbindFlags&S?b():C(h,E,_nbind.pushPointer(this,t),I,T)};case 3:return function(I,T,N){return this.__nbindFlags&S?b():C(h,E,_nbind.pushPointer(this,t),I,T,N)};default:break}return buildCallerFunction(C,t,h,E,e.policyTbl,p,\"ptr,num,pushPointer(this,ptrType)\",n,c,S,b)}_nbind.makeMethodCaller=makeMethodCaller;function makeCaller(t){var e=t.typeList.length-1,r=_nbind.getTypes(t.typeList,t.title),s=r[0],a=r.slice(1),n=s.needsWireRead(t.policyTbl),c=anyNeedsWireWrite(a,t.policyTbl),f=t.direct,p=t.ptr;if(t.direct&&!n&&!c){var h=_nbind.getDynCall(r,t.title);switch(e){case 0:return function(){return h(f)};case 1:return function(b){return h(f,b)};case 2:return function(b,I){return h(f,b,I)};case 3:return function(b,I,T){return h(f,b,I,T)};default:break}p=0}var E;if(p){var C=t.typeList.slice(0);C.splice(1,0,\"uint32_t\"),r=_nbind.getTypes(C,t.title),E=\"ptr,num\"}else p=f,E=\"ptr\";var S=_nbind.getDynCall(r,t.title);return buildCallerFunction(S,null,p,t.num,t.policyTbl,c,E,s,a)}_nbind.makeCaller=makeCaller;function makeOverloader(t,e){var r=[];function s(){return r[arguments.length].apply(this,arguments)}return s.addMethod=function(a,n){r[n]=a},s.addMethod(t,e),s}_nbind.makeOverloader=makeOverloader;var Resource=function(){function t(e,r){var s=this;this.makeOpen=function(){return Object.keys(s.openTbl).join(\"\")},this.makeClose=function(){return Object.keys(s.closeTbl).join(\"\")},this.openTbl={},this.closeTbl={},e&&(this.openTbl[e]=!0),r&&(this.closeTbl[r]=!0)}return t.prototype.add=function(e){for(var r=0,s=Object.keys(e.openTbl);r<s.length;r++){var a=s[r];this.openTbl[a]=!0}for(var n=0,c=Object.keys(e.closeTbl);n<c.length;n++){var a=c[n];this.closeTbl[a]=!0}},t.prototype.remove=function(e){for(var r=0,s=Object.keys(e.openTbl);r<s.length;r++){var a=s[r];delete this.openTbl[a]}for(var n=0,c=Object.keys(e.closeTbl);n<c.length;n++){var a=c[n];delete this.closeTbl[a]}},t}();_nbind.Resource=Resource;function listResources(t,e){for(var r=new Resource,s=0,a=t;s<a.length;s++)for(var n=a[s],c=0,f=n.readResources||[];c<f.length;c++){var p=f[c];r.add(p)}for(var h=0,E=e;h<E.length;h++)for(var n=E[h],C=0,S=n.writeResources||[];C<S.length;C++){var p=S[C];r.add(p)}return r}_nbind.listResources=listResources,_nbind.resources={pool:new Resource(\"var used=HEAPU32[_nbind.Pool.usedPtr],page=HEAPU32[_nbind.Pool.pagePtr];\",\"_nbind.Pool.lreset(used,page);\")};var ExternalBuffer=function(t){__extends(e,t);function e(r,s){var a=t.call(this,r)||this;return a.ptr=s,a}return e.prototype.free=function(){_free(this.ptr)},e}(_nbind.External);function getBuffer(t){return t instanceof ArrayBuffer?new Uint8Array(t):t instanceof DataView?new Uint8Array(t.buffer,t.byteOffset,t.byteLength):t}function pushBuffer(t,e){if(t==null&&e&&e.Nullable&&(t=[]),typeof t!=\"object\")throw new Error(\"Type mismatch\");var r=t,s=r.byteLength||r.length;if(!s&&s!==0&&r.byteLength!==0)throw new Error(\"Type mismatch\");var a=_nbind.Pool.lalloc(8),n=_malloc(s),c=a/4;return HEAPU32[c++]=s,HEAPU32[c++]=n,HEAPU32[c++]=new ExternalBuffer(t,n).register(),HEAPU8.set(getBuffer(t),n),a}var BufferType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireWrite=pushBuffer,r.readResources=[_nbind.resources.pool],r.writeResources=[_nbind.resources.pool],r}return e.prototype.makeWireWrite=function(r,s){return function(a){return pushBuffer(a,s)}},e}(_nbind.BindType);_nbind.BufferType=BufferType;function commitBuffer(t,e,r){var s=_nbind.externalList[t].data,a=Buffer;if(typeof Buffer!=\"function\"&&(a=function(){}),!(s instanceof Array)){var n=HEAPU8.subarray(e,e+r);if(s instanceof a){var c=void 0;typeof Buffer.from==\"function\"&&Buffer.from.length>=3?c=Buffer.from(n):c=new Buffer(n),c.copy(s)}else getBuffer(s).set(n)}}_nbind.commitBuffer=commitBuffer;var dirtyList=[],gcTimer=0;function sweep(){for(var t=0,e=dirtyList;t<e.length;t++){var r=e[t];r.__nbindState&3||r.free()}dirtyList=[],gcTimer=0}_nbind.mark=function(t){};function toggleLightGC(t){t?_nbind.mark=function(e){dirtyList.push(e),gcTimer||(gcTimer=setTimeout(sweep,0))}:_nbind.mark=function(e){}}_nbind.toggleLightGC=toggleLightGC}(_nbind),Module.requestFullScreen=function t(e,r,s){Module.printErr(\"Module.requestFullScreen is deprecated. Please call Module.requestFullscreen instead.\"),Module.requestFullScreen=Module.requestFullscreen,Browser.requestFullScreen(e,r,s)},Module.requestFullscreen=function t(e,r,s){Browser.requestFullscreen(e,r,s)},Module.requestAnimationFrame=function t(e){Browser.requestAnimationFrame(e)},Module.setCanvasSize=function t(e,r,s){Browser.setCanvasSize(e,r,s)},Module.pauseMainLoop=function t(){Browser.mainLoop.pause()},Module.resumeMainLoop=function t(){Browser.mainLoop.resume()},Module.getUserMedia=function t(){Browser.getUserMedia()},Module.createContext=function t(e,r,s,a){return Browser.createContext(e,r,s,a)},ENVIRONMENT_IS_NODE?_emscripten_get_now=function(){var e=process.hrtime();return e[0]*1e3+e[1]/1e6}:typeof dateNow<\"u\"?_emscripten_get_now=dateNow:typeof self==\"object\"&&self.performance&&typeof self.performance.now==\"function\"?_emscripten_get_now=function(){return self.performance.now()}:typeof performance==\"object\"&&typeof performance.now==\"function\"?_emscripten_get_now=function(){return performance.now()}:_emscripten_get_now=Date.now,__ATEXIT__.push(function(){var t=Module._fflush;t&&t(0);var e=___syscall146.printChar;if(e){var r=___syscall146.buffers;r[1].length&&e(1,10),r[2].length&&e(2,10)}}),DYNAMICTOP_PTR=allocate(1,\"i32\",ALLOC_STATIC),STACK_BASE=STACKTOP=Runtime.alignMemory(STATICTOP),STACK_MAX=STACK_BASE+TOTAL_STACK,DYNAMIC_BASE=Runtime.alignMemory(STACK_MAX),HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE,staticSealed=!0;function invoke_viiiii(t,e,r,s,a,n){try{Module.dynCall_viiiii(t,e,r,s,a,n)}catch(c){if(typeof c!=\"number\"&&c!==\"longjmp\")throw c;Module.setThrew(1,0)}}function invoke_vif(t,e,r){try{Module.dynCall_vif(t,e,r)}catch(s){if(typeof s!=\"number\"&&s!==\"longjmp\")throw s;Module.setThrew(1,0)}}function invoke_vid(t,e,r){try{Module.dynCall_vid(t,e,r)}catch(s){if(typeof s!=\"number\"&&s!==\"longjmp\")throw s;Module.setThrew(1,0)}}function invoke_fiff(t,e,r,s){try{return Module.dynCall_fiff(t,e,r,s)}catch(a){if(typeof a!=\"number\"&&a!==\"longjmp\")throw a;Module.setThrew(1,0)}}function invoke_vi(t,e){try{Module.dynCall_vi(t,e)}catch(r){if(typeof r!=\"number\"&&r!==\"longjmp\")throw r;Module.setThrew(1,0)}}function invoke_vii(t,e,r){try{Module.dynCall_vii(t,e,r)}catch(s){if(typeof s!=\"number\"&&s!==\"longjmp\")throw s;Module.setThrew(1,0)}}function invoke_ii(t,e){try{return Module.dynCall_ii(t,e)}catch(r){if(typeof r!=\"number\"&&r!==\"longjmp\")throw r;Module.setThrew(1,0)}}function invoke_viddi(t,e,r,s,a){try{Module.dynCall_viddi(t,e,r,s,a)}catch(n){if(typeof n!=\"number\"&&n!==\"longjmp\")throw n;Module.setThrew(1,0)}}function invoke_vidd(t,e,r,s){try{Module.dynCall_vidd(t,e,r,s)}catch(a){if(typeof a!=\"number\"&&a!==\"longjmp\")throw a;Module.setThrew(1,0)}}function invoke_iiii(t,e,r,s){try{return Module.dynCall_iiii(t,e,r,s)}catch(a){if(typeof a!=\"number\"&&a!==\"longjmp\")throw a;Module.setThrew(1,0)}}function invoke_diii(t,e,r,s){try{return Module.dynCall_diii(t,e,r,s)}catch(a){if(typeof a!=\"number\"&&a!==\"longjmp\")throw a;Module.setThrew(1,0)}}function invoke_di(t,e){try{return Module.dynCall_di(t,e)}catch(r){if(typeof r!=\"number\"&&r!==\"longjmp\")throw r;Module.setThrew(1,0)}}function invoke_iid(t,e,r){try{return Module.dynCall_iid(t,e,r)}catch(s){if(typeof s!=\"number\"&&s!==\"longjmp\")throw s;Module.setThrew(1,0)}}function invoke_iii(t,e,r){try{return Module.dynCall_iii(t,e,r)}catch(s){if(typeof s!=\"number\"&&s!==\"longjmp\")throw s;Module.setThrew(1,0)}}function invoke_viiddi(t,e,r,s,a,n){try{Module.dynCall_viiddi(t,e,r,s,a,n)}catch(c){if(typeof c!=\"number\"&&c!==\"longjmp\")throw c;Module.setThrew(1,0)}}function invoke_viiiiii(t,e,r,s,a,n,c){try{Module.dynCall_viiiiii(t,e,r,s,a,n,c)}catch(f){if(typeof f!=\"number\"&&f!==\"longjmp\")throw f;Module.setThrew(1,0)}}function invoke_dii(t,e,r){try{return Module.dynCall_dii(t,e,r)}catch(s){if(typeof s!=\"number\"&&s!==\"longjmp\")throw s;Module.setThrew(1,0)}}function invoke_i(t){try{return Module.dynCall_i(t)}catch(e){if(typeof e!=\"number\"&&e!==\"longjmp\")throw e;Module.setThrew(1,0)}}function invoke_iiiiii(t,e,r,s,a,n){try{return Module.dynCall_iiiiii(t,e,r,s,a,n)}catch(c){if(typeof c!=\"number\"&&c!==\"longjmp\")throw c;Module.setThrew(1,0)}}function invoke_viiid(t,e,r,s,a){try{Module.dynCall_viiid(t,e,r,s,a)}catch(n){if(typeof n!=\"number\"&&n!==\"longjmp\")throw n;Module.setThrew(1,0)}}function invoke_viififi(t,e,r,s,a,n,c){try{Module.dynCall_viififi(t,e,r,s,a,n,c)}catch(f){if(typeof f!=\"number\"&&f!==\"longjmp\")throw f;Module.setThrew(1,0)}}function invoke_viii(t,e,r,s){try{Module.dynCall_viii(t,e,r,s)}catch(a){if(typeof a!=\"number\"&&a!==\"longjmp\")throw a;Module.setThrew(1,0)}}function invoke_v(t){try{Module.dynCall_v(t)}catch(e){if(typeof e!=\"number\"&&e!==\"longjmp\")throw e;Module.setThrew(1,0)}}function invoke_viid(t,e,r,s){try{Module.dynCall_viid(t,e,r,s)}catch(a){if(typeof a!=\"number\"&&a!==\"longjmp\")throw a;Module.setThrew(1,0)}}function invoke_idd(t,e,r){try{return Module.dynCall_idd(t,e,r)}catch(s){if(typeof s!=\"number\"&&s!==\"longjmp\")throw s;Module.setThrew(1,0)}}function invoke_viiii(t,e,r,s,a){try{Module.dynCall_viiii(t,e,r,s,a)}catch(n){if(typeof n!=\"number\"&&n!==\"longjmp\")throw n;Module.setThrew(1,0)}}Module.asmGlobalArg={Math,Int8Array,Int16Array,Int32Array,Uint8Array,Uint16Array,Uint32Array,Float32Array,Float64Array,NaN:NaN,Infinity:1/0},Module.asmLibraryArg={abort,assert,enlargeMemory,getTotalMemory,abortOnCannotGrowMemory,invoke_viiiii,invoke_vif,invoke_vid,invoke_fiff,invoke_vi,invoke_vii,invoke_ii,invoke_viddi,invoke_vidd,invoke_iiii,invoke_diii,invoke_di,invoke_iid,invoke_iii,invoke_viiddi,invoke_viiiiii,invoke_dii,invoke_i,invoke_iiiiii,invoke_viiid,invoke_viififi,invoke_viii,invoke_v,invoke_viid,invoke_idd,invoke_viiii,_emscripten_asm_const_iiiii,_emscripten_asm_const_iiidddddd,_emscripten_asm_const_iiiid,__nbind_reference_external,_emscripten_asm_const_iiiiiiii,_removeAccessorPrefix,_typeModule,__nbind_register_pool,__decorate,_llvm_stackrestore,___cxa_atexit,__extends,__nbind_get_value_object,__ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj,_emscripten_set_main_loop_timing,__nbind_register_primitive,__nbind_register_type,_emscripten_memcpy_big,__nbind_register_function,___setErrNo,__nbind_register_class,__nbind_finish,_abort,_nbind_value,_llvm_stacksave,___syscall54,_defineHidden,_emscripten_set_main_loop,_emscripten_get_now,__nbind_register_callback_signature,_emscripten_asm_const_iiiiii,__nbind_free_external,_emscripten_asm_const_iiii,_emscripten_asm_const_iiididi,___syscall6,_atexit,___syscall140,___syscall146,DYNAMICTOP_PTR,tempDoublePtr,ABORT,STACKTOP,STACK_MAX,cttz_i8,___dso_handle};var asm=function(t,e,r){var s=new t.Int8Array(r),a=new t.Int16Array(r),n=new t.Int32Array(r),c=new t.Uint8Array(r),f=new t.Uint16Array(r),p=new t.Uint32Array(r),h=new t.Float32Array(r),E=new t.Float64Array(r),C=e.DYNAMICTOP_PTR|0,S=e.tempDoublePtr|0,b=e.ABORT|0,I=e.STACKTOP|0,T=e.STACK_MAX|0,N=e.cttz_i8|0,U=e.___dso_handle|0,W=0,ee=0,ie=0,ue=0,le=t.NaN,me=t.Infinity,pe=0,Be=0,Ce=0,g=0,we=0,ye=0,Ae=t.Math.floor,se=t.Math.abs,X=t.Math.sqrt,De=t.Math.pow,Te=t.Math.cos,mt=t.Math.sin,j=t.Math.tan,rt=t.Math.acos,Fe=t.Math.asin,Ne=t.Math.atan,be=t.Math.atan2,Ve=t.Math.exp,ke=t.Math.log,it=t.Math.ceil,Ue=t.Math.imul,x=t.Math.min,w=t.Math.max,P=t.Math.clz32,y=t.Math.fround,F=e.abort,z=e.assert,Z=e.enlargeMemory,$=e.getTotalMemory,oe=e.abortOnCannotGrowMemory,xe=e.invoke_viiiii,Re=e.invoke_vif,lt=e.invoke_vid,Ct=e.invoke_fiff,qt=e.invoke_vi,ir=e.invoke_vii,bt=e.invoke_ii,gn=e.invoke_viddi,br=e.invoke_vidd,Ir=e.invoke_iiii,Or=e.invoke_diii,nn=e.invoke_di,ai=e.invoke_iid,Io=e.invoke_iii,ts=e.invoke_viiddi,$s=e.invoke_viiiiii,Co=e.invoke_dii,Hi=e.invoke_i,eo=e.invoke_iiiiii,wo=e.invoke_viiid,QA=e.invoke_viififi,Af=e.invoke_viii,dh=e.invoke_v,mh=e.invoke_viid,to=e.invoke_idd,jn=e.invoke_viiii,Rs=e._emscripten_asm_const_iiiii,ro=e._emscripten_asm_const_iiidddddd,ou=e._emscripten_asm_const_iiiid,au=e.__nbind_reference_external,lu=e._emscripten_asm_const_iiiiiiii,RA=e._removeAccessorPrefix,TA=e._typeModule,oa=e.__nbind_register_pool,aa=e.__decorate,FA=e._llvm_stackrestore,gr=e.___cxa_atexit,Bo=e.__extends,Me=e.__nbind_get_value_object,cu=e.__ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj,Cr=e._emscripten_set_main_loop_timing,pf=e.__nbind_register_primitive,NA=e.__nbind_register_type,OA=e._emscripten_memcpy_big,uu=e.__nbind_register_function,fu=e.___setErrNo,oc=e.__nbind_register_class,ve=e.__nbind_finish,Nt=e._abort,ac=e._nbind_value,Oi=e._llvm_stacksave,no=e.___syscall54,Tt=e._defineHidden,xn=e._emscripten_set_main_loop,la=e._emscripten_get_now,ji=e.__nbind_register_callback_signature,Li=e._emscripten_asm_const_iiiiii,Na=e.__nbind_free_external,dn=e._emscripten_asm_const_iiii,Kn=e._emscripten_asm_const_iiididi,Au=e.___syscall6,yh=e._atexit,Oa=e.___syscall140,La=e.___syscall146,Ma=y(0);let $e=y(0);function Ua(o){o=o|0;var l=0;return l=I,I=I+o|0,I=I+15&-16,l|0}function hf(){return I|0}function lc(o){o=o|0,I=o}function wn(o,l){o=o|0,l=l|0,I=o,T=l}function ca(o,l){o=o|0,l=l|0,W||(W=o,ee=l)}function LA(o){o=o|0,ye=o}function MA(){return ye|0}function ua(){var o=0,l=0;Qr(8104,8,400)|0,Qr(8504,408,540)|0,o=9044,l=o+44|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));s[9088]=0,s[9089]=1,n[2273]=0,n[2274]=948,n[2275]=948,gr(17,8104,U|0)|0}function Bl(o){o=o|0,dt(o+948|0)}function Mt(o){return o=y(o),((fb(o)|0)&2147483647)>>>0>2139095040|0}function kn(o,l,u){o=o|0,l=l|0,u=u|0;e:do if(n[o+(l<<3)+4>>2]|0)o=o+(l<<3)|0;else{if((l|2|0)==3&&n[o+60>>2]|0){o=o+56|0;break}switch(l|0){case 0:case 2:case 4:case 5:{if(n[o+52>>2]|0){o=o+48|0;break e}break}default:}if(n[o+68>>2]|0){o=o+64|0;break}else{o=(l|1|0)==5?948:u;break}}while(!1);return o|0}function fa(o){o=o|0;var l=0;return l=_b(1e3)|0,Ha(o,(l|0)!=0,2456),n[2276]=(n[2276]|0)+1,Qr(l|0,8104,1e3)|0,s[o+2>>0]|0&&(n[l+4>>2]=2,n[l+12>>2]=4),n[l+976>>2]=o,l|0}function Ha(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0;d=I,I=I+16|0,A=d,l||(n[A>>2]=u,Wg(o,5,3197,A)),I=d}function rs(){return fa(956)|0}function cc(o){o=o|0;var l=0;return l=Kt(1e3)|0,pu(l,o),Ha(n[o+976>>2]|0,1,2456),n[2276]=(n[2276]|0)+1,n[l+944>>2]=0,l|0}function pu(o,l){o=o|0,l=l|0;var u=0;Qr(o|0,l|0,948)|0,Dy(o+948|0,l+948|0),u=o+960|0,o=l+960|0,l=u+40|0;do n[u>>2]=n[o>>2],u=u+4|0,o=o+4|0;while((u|0)<(l|0))}function uc(o){o=o|0;var l=0,u=0,A=0,d=0;if(l=o+944|0,u=n[l>>2]|0,u|0&&(ja(u+948|0,o)|0,n[l>>2]=0),u=Mi(o)|0,u|0){l=0;do n[(Is(o,l)|0)+944>>2]=0,l=l+1|0;while((l|0)!=(u|0))}u=o+948|0,A=n[u>>2]|0,d=o+952|0,l=n[d>>2]|0,(l|0)!=(A|0)&&(n[d>>2]=l+(~((l+-4-A|0)>>>2)<<2)),vl(u),Hb(o),n[2276]=(n[2276]|0)+-1}function ja(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0;A=n[o>>2]|0,k=o+4|0,u=n[k>>2]|0,m=u;e:do if((A|0)==(u|0))d=A,B=4;else for(o=A;;){if((n[o>>2]|0)==(l|0)){d=o,B=4;break e}if(o=o+4|0,(o|0)==(u|0)){o=0;break}}while(!1);return(B|0)==4&&((d|0)!=(u|0)?(A=d+4|0,o=m-A|0,l=o>>2,l&&(Q2(d|0,A|0,o|0)|0,u=n[k>>2]|0),o=d+(l<<2)|0,(u|0)==(o|0)||(n[k>>2]=u+(~((u+-4-o|0)>>>2)<<2)),o=1):o=0),o|0}function Mi(o){return o=o|0,(n[o+952>>2]|0)-(n[o+948>>2]|0)>>2|0}function Is(o,l){o=o|0,l=l|0;var u=0;return u=n[o+948>>2]|0,(n[o+952>>2]|0)-u>>2>>>0>l>>>0?o=n[u+(l<<2)>>2]|0:o=0,o|0}function vl(o){o=o|0;var l=0,u=0,A=0,d=0;A=I,I=I+32|0,l=A,d=n[o>>2]|0,u=(n[o+4>>2]|0)-d|0,((n[o+8>>2]|0)-d|0)>>>0>u>>>0&&(d=u>>2,ky(l,d,d,o+8|0),Ab(o,l),Qy(l)),I=A}function gf(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0;M=Mi(o)|0;do if(M|0){if((n[(Is(o,0)|0)+944>>2]|0)==(o|0)){if(!(ja(o+948|0,l)|0))break;Qr(l+400|0,8504,540)|0,n[l+944>>2]=0,Oe(o);break}B=n[(n[o+976>>2]|0)+12>>2]|0,k=o+948|0,R=(B|0)==0,u=0,m=0;do A=n[(n[k>>2]|0)+(m<<2)>>2]|0,(A|0)==(l|0)?Oe(o):(d=cc(A)|0,n[(n[k>>2]|0)+(u<<2)>>2]=d,n[d+944>>2]=o,R||gU[B&15](A,d,o,u),u=u+1|0),m=m+1|0;while((m|0)!=(M|0));if(u>>>0<M>>>0){R=o+948|0,k=o+952|0,B=u,u=n[k>>2]|0;do m=(n[R>>2]|0)+(B<<2)|0,A=m+4|0,d=u-A|0,l=d>>2,l&&(Q2(m|0,A|0,d|0)|0,u=n[k>>2]|0),d=u,A=m+(l<<2)|0,(d|0)!=(A|0)&&(u=d+(~((d+-4-A|0)>>>2)<<2)|0,n[k>>2]=u),B=B+1|0;while((B|0)!=(M|0))}}while(!1)}function fc(o){o=o|0;var l=0,u=0,A=0,d=0;wi(o,(Mi(o)|0)==0,2491),wi(o,(n[o+944>>2]|0)==0,2545),l=o+948|0,u=n[l>>2]|0,A=o+952|0,d=n[A>>2]|0,(d|0)!=(u|0)&&(n[A>>2]=d+(~((d+-4-u|0)>>>2)<<2)),vl(l),l=o+976|0,u=n[l>>2]|0,Qr(o|0,8104,1e3)|0,s[u+2>>0]|0&&(n[o+4>>2]=2,n[o+12>>2]=4),n[l>>2]=u}function wi(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0;d=I,I=I+16|0,A=d,l||(n[A>>2]=u,xo(o,5,3197,A)),I=d}function Qn(){return n[2276]|0}function Ac(){var o=0;return o=_b(20)|0,Ke((o|0)!=0,2592),n[2277]=(n[2277]|0)+1,n[o>>2]=n[239],n[o+4>>2]=n[240],n[o+8>>2]=n[241],n[o+12>>2]=n[242],n[o+16>>2]=n[243],o|0}function Ke(o,l){o=o|0,l=l|0;var u=0,A=0;A=I,I=I+16|0,u=A,o||(n[u>>2]=l,xo(0,5,3197,u)),I=A}function st(o){o=o|0,Hb(o),n[2277]=(n[2277]|0)+-1}function St(o,l){o=o|0,l=l|0;var u=0;l?(wi(o,(Mi(o)|0)==0,2629),u=1):(u=0,l=0),n[o+964>>2]=l,n[o+988>>2]=u}function lr(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;A=I,I=I+16|0,m=A+8|0,d=A+4|0,B=A,n[d>>2]=l,wi(o,(n[l+944>>2]|0)==0,2709),wi(o,(n[o+964>>2]|0)==0,2763),te(o),l=o+948|0,n[B>>2]=(n[l>>2]|0)+(u<<2),n[m>>2]=n[B>>2],Ee(l,m,d)|0,n[(n[d>>2]|0)+944>>2]=o,Oe(o),I=A}function te(o){o=o|0;var l=0,u=0,A=0,d=0,m=0,B=0,k=0;if(u=Mi(o)|0,u|0&&(n[(Is(o,0)|0)+944>>2]|0)!=(o|0)){A=n[(n[o+976>>2]|0)+12>>2]|0,d=o+948|0,m=(A|0)==0,l=0;do B=n[(n[d>>2]|0)+(l<<2)>>2]|0,k=cc(B)|0,n[(n[d>>2]|0)+(l<<2)>>2]=k,n[k+944>>2]=o,m||gU[A&15](B,k,o,l),l=l+1|0;while((l|0)!=(u|0))}}function Ee(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0,Ye=0,Le=0,Qe=0,tt=0,Xe=0;tt=I,I=I+64|0,q=tt+52|0,k=tt+48|0,ae=tt+28|0,Ye=tt+24|0,Le=tt+20|0,Qe=tt,A=n[o>>2]|0,m=A,l=A+((n[l>>2]|0)-m>>2<<2)|0,A=o+4|0,d=n[A>>2]|0,B=o+8|0;do if(d>>>0<(n[B>>2]|0)>>>0){if((l|0)==(d|0)){n[l>>2]=n[u>>2],n[A>>2]=(n[A>>2]|0)+4;break}pb(o,l,d,l+4|0),l>>>0<=u>>>0&&(u=(n[A>>2]|0)>>>0>u>>>0?u+4|0:u),n[l>>2]=n[u>>2]}else{A=(d-m>>2)+1|0,d=O(o)|0,d>>>0<A>>>0&&sn(o),L=n[o>>2]|0,M=(n[B>>2]|0)-L|0,m=M>>1,ky(Qe,M>>2>>>0<d>>>1>>>0?m>>>0<A>>>0?A:m:d,l-L>>2,o+8|0),L=Qe+8|0,A=n[L>>2]|0,m=Qe+12|0,M=n[m>>2]|0,B=M,R=A;do if((A|0)==(M|0)){if(M=Qe+4|0,A=n[M>>2]|0,Xe=n[Qe>>2]|0,d=Xe,A>>>0<=Xe>>>0){A=B-d>>1,A=A|0?A:1,ky(ae,A,A>>>2,n[Qe+16>>2]|0),n[Ye>>2]=n[M>>2],n[Le>>2]=n[L>>2],n[k>>2]=n[Ye>>2],n[q>>2]=n[Le>>2],o2(ae,k,q),A=n[Qe>>2]|0,n[Qe>>2]=n[ae>>2],n[ae>>2]=A,A=ae+4|0,Xe=n[M>>2]|0,n[M>>2]=n[A>>2],n[A>>2]=Xe,A=ae+8|0,Xe=n[L>>2]|0,n[L>>2]=n[A>>2],n[A>>2]=Xe,A=ae+12|0,Xe=n[m>>2]|0,n[m>>2]=n[A>>2],n[A>>2]=Xe,Qy(ae),A=n[L>>2]|0;break}m=A,B=((m-d>>2)+1|0)/-2|0,k=A+(B<<2)|0,d=R-m|0,m=d>>2,m&&(Q2(k|0,A|0,d|0)|0,A=n[M>>2]|0),Xe=k+(m<<2)|0,n[L>>2]=Xe,n[M>>2]=A+(B<<2),A=Xe}while(!1);n[A>>2]=n[u>>2],n[L>>2]=(n[L>>2]|0)+4,l=hb(o,Qe,l)|0,Qy(Qe)}while(!1);return I=tt,l|0}function Oe(o){o=o|0;var l=0;do{if(l=o+984|0,s[l>>0]|0)break;s[l>>0]=1,h[o+504>>2]=y(le),o=n[o+944>>2]|0}while(o|0)}function dt(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-4-A|0)>>>2)<<2)),It(u))}function Et(o){return o=o|0,n[o+944>>2]|0}function Pt(o){o=o|0,wi(o,(n[o+964>>2]|0)!=0,2832),Oe(o)}function tr(o){return o=o|0,(s[o+984>>0]|0)!=0|0}function An(o,l){o=o|0,l=l|0,s6e(o,l,400)|0&&(Qr(o|0,l|0,400)|0,Oe(o))}function li(o){o=o|0;var l=$e;return l=y(h[o+44>>2]),o=Mt(l)|0,y(o?y(0):l)}function Gi(o){o=o|0;var l=$e;return l=y(h[o+48>>2]),Mt(l)|0&&(l=s[(n[o+976>>2]|0)+2>>0]|0?y(1):y(0)),y(l)}function Rn(o,l){o=o|0,l=l|0,n[o+980>>2]=l}function Ga(o){return o=o|0,n[o+980>>2]|0}function my(o,l){o=o|0,l=l|0;var u=0;u=o+4|0,(n[u>>2]|0)!=(l|0)&&(n[u>>2]=l,Oe(o))}function X1(o){return o=o|0,n[o+4>>2]|0}function vo(o,l){o=o|0,l=l|0;var u=0;u=o+8|0,(n[u>>2]|0)!=(l|0)&&(n[u>>2]=l,Oe(o))}function yy(o){return o=o|0,n[o+8>>2]|0}function Eh(o,l){o=o|0,l=l|0;var u=0;u=o+12|0,(n[u>>2]|0)!=(l|0)&&(n[u>>2]=l,Oe(o))}function $1(o){return o=o|0,n[o+12>>2]|0}function So(o,l){o=o|0,l=l|0;var u=0;u=o+16|0,(n[u>>2]|0)!=(l|0)&&(n[u>>2]=l,Oe(o))}function Ih(o){return o=o|0,n[o+16>>2]|0}function Ch(o,l){o=o|0,l=l|0;var u=0;u=o+20|0,(n[u>>2]|0)!=(l|0)&&(n[u>>2]=l,Oe(o))}function hu(o){return o=o|0,n[o+20>>2]|0}function wh(o,l){o=o|0,l=l|0;var u=0;u=o+24|0,(n[u>>2]|0)!=(l|0)&&(n[u>>2]=l,Oe(o))}function Fg(o){return o=o|0,n[o+24>>2]|0}function Ng(o,l){o=o|0,l=l|0;var u=0;u=o+28|0,(n[u>>2]|0)!=(l|0)&&(n[u>>2]=l,Oe(o))}function Og(o){return o=o|0,n[o+28>>2]|0}function Ey(o,l){o=o|0,l=l|0;var u=0;u=o+32|0,(n[u>>2]|0)!=(l|0)&&(n[u>>2]=l,Oe(o))}function df(o){return o=o|0,n[o+32>>2]|0}function Do(o,l){o=o|0,l=l|0;var u=0;u=o+36|0,(n[u>>2]|0)!=(l|0)&&(n[u>>2]=l,Oe(o))}function Sl(o){return o=o|0,n[o+36>>2]|0}function Bh(o,l){o=o|0,l=y(l);var u=0;u=o+40|0,y(h[u>>2])!=l&&(h[u>>2]=l,Oe(o))}function Lg(o,l){o=o|0,l=y(l);var u=0;u=o+44|0,y(h[u>>2])!=l&&(h[u>>2]=l,Oe(o))}function Dl(o,l){o=o|0,l=y(l);var u=0;u=o+48|0,y(h[u>>2])!=l&&(h[u>>2]=l,Oe(o))}function Pl(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=(m^1)&1,A=o+52|0,d=o+56|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function Iy(o,l){o=o|0,l=y(l);var u=0,A=0;A=o+52|0,u=o+56|0,y(h[A>>2])==l&&(n[u>>2]|0)==2||(h[A>>2]=l,A=Mt(l)|0,n[u>>2]=A?3:2,Oe(o))}function UA(o,l){o=o|0,l=l|0;var u=0,A=0;A=l+52|0,u=n[A+4>>2]|0,l=o,n[l>>2]=n[A>>2],n[l+4>>2]=u}function Cy(o,l,u){o=o|0,l=l|0,u=y(u);var A=0,d=0,m=0;m=Mt(u)|0,A=(m^1)&1,d=o+132+(l<<3)|0,l=o+132+(l<<3)+4|0,m|y(h[d>>2])==u&&(n[l>>2]|0)==(A|0)||(h[d>>2]=u,n[l>>2]=A,Oe(o))}function wy(o,l,u){o=o|0,l=l|0,u=y(u);var A=0,d=0,m=0;m=Mt(u)|0,A=m?0:2,d=o+132+(l<<3)|0,l=o+132+(l<<3)+4|0,m|y(h[d>>2])==u&&(n[l>>2]|0)==(A|0)||(h[d>>2]=u,n[l>>2]=A,Oe(o))}function _A(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=l+132+(u<<3)|0,l=n[A+4>>2]|0,u=o,n[u>>2]=n[A>>2],n[u+4>>2]=l}function HA(o,l,u){o=o|0,l=l|0,u=y(u);var A=0,d=0,m=0;m=Mt(u)|0,A=(m^1)&1,d=o+60+(l<<3)|0,l=o+60+(l<<3)+4|0,m|y(h[d>>2])==u&&(n[l>>2]|0)==(A|0)||(h[d>>2]=u,n[l>>2]=A,Oe(o))}function Y(o,l,u){o=o|0,l=l|0,u=y(u);var A=0,d=0,m=0;m=Mt(u)|0,A=m?0:2,d=o+60+(l<<3)|0,l=o+60+(l<<3)+4|0,m|y(h[d>>2])==u&&(n[l>>2]|0)==(A|0)||(h[d>>2]=u,n[l>>2]=A,Oe(o))}function xt(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=l+60+(u<<3)|0,l=n[A+4>>2]|0,u=o,n[u>>2]=n[A>>2],n[u+4>>2]=l}function jA(o,l){o=o|0,l=l|0;var u=0;u=o+60+(l<<3)+4|0,(n[u>>2]|0)!=3&&(h[o+60+(l<<3)>>2]=y(le),n[u>>2]=3,Oe(o))}function Po(o,l,u){o=o|0,l=l|0,u=y(u);var A=0,d=0,m=0;m=Mt(u)|0,A=(m^1)&1,d=o+204+(l<<3)|0,l=o+204+(l<<3)+4|0,m|y(h[d>>2])==u&&(n[l>>2]|0)==(A|0)||(h[d>>2]=u,n[l>>2]=A,Oe(o))}function mf(o,l,u){o=o|0,l=l|0,u=y(u);var A=0,d=0,m=0;m=Mt(u)|0,A=m?0:2,d=o+204+(l<<3)|0,l=o+204+(l<<3)+4|0,m|y(h[d>>2])==u&&(n[l>>2]|0)==(A|0)||(h[d>>2]=u,n[l>>2]=A,Oe(o))}function yt(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=l+204+(u<<3)|0,l=n[A+4>>2]|0,u=o,n[u>>2]=n[A>>2],n[u+4>>2]=l}function gu(o,l,u){o=o|0,l=l|0,u=y(u);var A=0,d=0,m=0;m=Mt(u)|0,A=(m^1)&1,d=o+276+(l<<3)|0,l=o+276+(l<<3)+4|0,m|y(h[d>>2])==u&&(n[l>>2]|0)==(A|0)||(h[d>>2]=u,n[l>>2]=A,Oe(o))}function By(o,l){return o=o|0,l=l|0,y(h[o+276+(l<<3)>>2])}function Mg(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=(m^1)&1,A=o+348|0,d=o+352|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function e2(o,l){o=o|0,l=y(l);var u=0,A=0;A=o+348|0,u=o+352|0,y(h[A>>2])==l&&(n[u>>2]|0)==2||(h[A>>2]=l,A=Mt(l)|0,n[u>>2]=A?3:2,Oe(o))}function vh(o){o=o|0;var l=0;l=o+352|0,(n[l>>2]|0)!=3&&(h[o+348>>2]=y(le),n[l>>2]=3,Oe(o))}function ur(o,l){o=o|0,l=l|0;var u=0,A=0;A=l+348|0,u=n[A+4>>2]|0,l=o,n[l>>2]=n[A>>2],n[l+4>>2]=u}function Ki(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=(m^1)&1,A=o+356|0,d=o+360|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function yf(o,l){o=o|0,l=y(l);var u=0,A=0;A=o+356|0,u=o+360|0,y(h[A>>2])==l&&(n[u>>2]|0)==2||(h[A>>2]=l,A=Mt(l)|0,n[u>>2]=A?3:2,Oe(o))}function qa(o){o=o|0;var l=0;l=o+360|0,(n[l>>2]|0)!=3&&(h[o+356>>2]=y(le),n[l>>2]=3,Oe(o))}function Ug(o,l){o=o|0,l=l|0;var u=0,A=0;A=l+356|0,u=n[A+4>>2]|0,l=o,n[l>>2]=n[A>>2],n[l+4>>2]=u}function du(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=(m^1)&1,A=o+364|0,d=o+368|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function Ef(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=m?0:2,A=o+364|0,d=o+368|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function wt(o,l){o=o|0,l=l|0;var u=0,A=0;A=l+364|0,u=n[A+4>>2]|0,l=o,n[l>>2]=n[A>>2],n[l+4>>2]=u}function di(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=(m^1)&1,A=o+372|0,d=o+376|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function GA(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=m?0:2,A=o+372|0,d=o+376|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function Wa(o,l){o=o|0,l=l|0;var u=0,A=0;A=l+372|0,u=n[A+4>>2]|0,l=o,n[l>>2]=n[A>>2],n[l+4>>2]=u}function Aa(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=(m^1)&1,A=o+380|0,d=o+384|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function Ya(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=m?0:2,A=o+380|0,d=o+384|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function _g(o,l){o=o|0,l=l|0;var u=0,A=0;A=l+380|0,u=n[A+4>>2]|0,l=o,n[l>>2]=n[A>>2],n[l+4>>2]=u}function Sh(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=(m^1)&1,A=o+388|0,d=o+392|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function Hg(o,l){o=o|0,l=y(l);var u=0,A=0,d=0,m=0;m=Mt(l)|0,u=m?0:2,A=o+388|0,d=o+392|0,m|y(h[A>>2])==l&&(n[d>>2]|0)==(u|0)||(h[A>>2]=l,n[d>>2]=u,Oe(o))}function vy(o,l){o=o|0,l=l|0;var u=0,A=0;A=l+388|0,u=n[A+4>>2]|0,l=o,n[l>>2]=n[A>>2],n[l+4>>2]=u}function qA(o,l){o=o|0,l=y(l);var u=0;u=o+396|0,y(h[u>>2])!=l&&(h[u>>2]=l,Oe(o))}function jg(o){return o=o|0,y(h[o+396>>2])}function mu(o){return o=o|0,y(h[o+400>>2])}function yu(o){return o=o|0,y(h[o+404>>2])}function If(o){return o=o|0,y(h[o+408>>2])}function Ts(o){return o=o|0,y(h[o+412>>2])}function Eu(o){return o=o|0,y(h[o+416>>2])}function Gn(o){return o=o|0,y(h[o+420>>2])}function ns(o,l){switch(o=o|0,l=l|0,wi(o,(l|0)<6,2918),l|0){case 0:{l=(n[o+496>>2]|0)==2?5:4;break}case 2:{l=(n[o+496>>2]|0)==2?4:5;break}default:}return y(h[o+424+(l<<2)>>2])}function bi(o,l){switch(o=o|0,l=l|0,wi(o,(l|0)<6,2918),l|0){case 0:{l=(n[o+496>>2]|0)==2?5:4;break}case 2:{l=(n[o+496>>2]|0)==2?4:5;break}default:}return y(h[o+448+(l<<2)>>2])}function WA(o,l){switch(o=o|0,l=l|0,wi(o,(l|0)<6,2918),l|0){case 0:{l=(n[o+496>>2]|0)==2?5:4;break}case 2:{l=(n[o+496>>2]|0)==2?4:5;break}default:}return y(h[o+472+(l<<2)>>2])}function Cf(o,l){o=o|0,l=l|0;var u=0,A=$e;return u=n[o+4>>2]|0,(u|0)==(n[l+4>>2]|0)?u?(A=y(h[o>>2]),o=y(se(y(A-y(h[l>>2]))))<y(999999974e-13)):o=1:o=0,o|0}function mn(o,l){o=y(o),l=y(l);var u=0;return Mt(o)|0?u=Mt(l)|0:u=y(se(y(o-l)))<y(999999974e-13),u|0}function Gg(o,l){o=o|0,l=l|0,qg(o,l)}function qg(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u+4|0,n[A>>2]=0,n[A+4>>2]=0,n[A+8>>2]=0,cu(A|0,o|0,l|0,0),xo(o,3,(s[A+11>>0]|0)<0?n[A>>2]|0:A,u),b6e(A),I=u}function is(o,l,u,A){o=y(o),l=y(l),u=u|0,A=A|0;var d=$e;o=y(o*l),d=y(cU(o,y(1)));do if(mn(d,y(0))|0)o=y(o-d);else{if(o=y(o-d),mn(d,y(1))|0){o=y(o+y(1));break}if(u){o=y(o+y(1));break}A||(d>y(.5)?d=y(1):(A=mn(d,y(.5))|0,d=y(A?1:0)),o=y(o+d))}while(!1);return y(o/l)}function bl(o,l,u,A,d,m,B,k,R,M,L,q,ae){o=o|0,l=y(l),u=u|0,A=y(A),d=d|0,m=y(m),B=B|0,k=y(k),R=y(R),M=y(M),L=y(L),q=y(q),ae=ae|0;var Ye=0,Le=$e,Qe=$e,tt=$e,Xe=$e,ct=$e,He=$e;return R<y(0)|M<y(0)?ae=0:(ae|0&&(Le=y(h[ae+4>>2]),Le!=y(0))?(tt=y(is(l,Le,0,0)),Xe=y(is(A,Le,0,0)),Qe=y(is(m,Le,0,0)),Le=y(is(k,Le,0,0))):(Qe=m,tt=l,Le=k,Xe=A),(d|0)==(o|0)?Ye=mn(Qe,tt)|0:Ye=0,(B|0)==(u|0)?ae=mn(Le,Xe)|0:ae=0,!Ye&&(ct=y(l-L),!(bo(o,ct,R)|0))&&!(wf(o,ct,d,R)|0)?Ye=Bf(o,ct,d,m,R)|0:Ye=1,!ae&&(He=y(A-q),!(bo(u,He,M)|0))&&!(wf(u,He,B,M)|0)?ae=Bf(u,He,B,k,M)|0:ae=1,ae=Ye&ae),ae|0}function bo(o,l,u){return o=o|0,l=y(l),u=y(u),(o|0)==1?o=mn(l,u)|0:o=0,o|0}function wf(o,l,u,A){return o=o|0,l=y(l),u=u|0,A=y(A),(o|0)==2&(u|0)==0?l>=A?o=1:o=mn(l,A)|0:o=0,o|0}function Bf(o,l,u,A,d){return o=o|0,l=y(l),u=u|0,A=y(A),d=y(d),(o|0)==2&(u|0)==2&A>l?d<=l?o=1:o=mn(l,d)|0:o=0,o|0}function xl(o,l,u,A,d,m,B,k,R,M,L){o=o|0,l=y(l),u=y(u),A=A|0,d=d|0,m=m|0,B=y(B),k=y(k),R=R|0,M=M|0,L=L|0;var q=0,ae=0,Ye=0,Le=0,Qe=$e,tt=$e,Xe=0,ct=0,He=0,We=0,Lt=0,Gr=0,fr=0,$t=0,Rr=0,Hr=0,cr=0,Hn=$e,Ro=$e,To=$e,Fo=0,Xa=0;cr=I,I=I+160|0,$t=cr+152|0,fr=cr+120|0,Gr=cr+104|0,He=cr+72|0,Le=cr+56|0,Lt=cr+8|0,ct=cr,We=(n[2279]|0)+1|0,n[2279]=We,Rr=o+984|0,s[Rr>>0]|0&&(n[o+512>>2]|0)!=(n[2278]|0)?Xe=4:(n[o+516>>2]|0)==(A|0)?Hr=0:Xe=4,(Xe|0)==4&&(n[o+520>>2]=0,n[o+924>>2]=-1,n[o+928>>2]=-1,h[o+932>>2]=y(-1),h[o+936>>2]=y(-1),Hr=1);e:do if(n[o+964>>2]|0)if(Qe=y(yn(o,2,B)),tt=y(yn(o,0,B)),q=o+916|0,To=y(h[q>>2]),Ro=y(h[o+920>>2]),Hn=y(h[o+932>>2]),bl(d,l,m,u,n[o+924>>2]|0,To,n[o+928>>2]|0,Ro,Hn,y(h[o+936>>2]),Qe,tt,L)|0)Xe=22;else if(Ye=n[o+520>>2]|0,!Ye)Xe=21;else for(ae=0;;){if(q=o+524+(ae*24|0)|0,Hn=y(h[q>>2]),Ro=y(h[o+524+(ae*24|0)+4>>2]),To=y(h[o+524+(ae*24|0)+16>>2]),bl(d,l,m,u,n[o+524+(ae*24|0)+8>>2]|0,Hn,n[o+524+(ae*24|0)+12>>2]|0,Ro,To,y(h[o+524+(ae*24|0)+20>>2]),Qe,tt,L)|0){Xe=22;break e}if(ae=ae+1|0,ae>>>0>=Ye>>>0){Xe=21;break}}else{if(R){if(q=o+916|0,!(mn(y(h[q>>2]),l)|0)){Xe=21;break}if(!(mn(y(h[o+920>>2]),u)|0)){Xe=21;break}if((n[o+924>>2]|0)!=(d|0)){Xe=21;break}q=(n[o+928>>2]|0)==(m|0)?q:0,Xe=22;break}if(Ye=n[o+520>>2]|0,!Ye)Xe=21;else for(ae=0;;){if(q=o+524+(ae*24|0)|0,mn(y(h[q>>2]),l)|0&&mn(y(h[o+524+(ae*24|0)+4>>2]),u)|0&&(n[o+524+(ae*24|0)+8>>2]|0)==(d|0)&&(n[o+524+(ae*24|0)+12>>2]|0)==(m|0)){Xe=22;break e}if(ae=ae+1|0,ae>>>0>=Ye>>>0){Xe=21;break}}}while(!1);do if((Xe|0)==21)s[11697]|0?(q=0,Xe=28):(q=0,Xe=31);else if((Xe|0)==22){if(ae=(s[11697]|0)!=0,!((q|0)!=0&(Hr^1)))if(ae){Xe=28;break}else{Xe=31;break}Le=q+16|0,n[o+908>>2]=n[Le>>2],Ye=q+20|0,n[o+912>>2]=n[Ye>>2],(s[11698]|0)==0|ae^1||(n[ct>>2]=Iu(We)|0,n[ct+4>>2]=We,xo(o,4,2972,ct),ae=n[o+972>>2]|0,ae|0&&ip[ae&127](o),d=pa(d,R)|0,m=pa(m,R)|0,Xa=+y(h[Le>>2]),Fo=+y(h[Ye>>2]),n[Lt>>2]=d,n[Lt+4>>2]=m,E[Lt+8>>3]=+l,E[Lt+16>>3]=+u,E[Lt+24>>3]=Xa,E[Lt+32>>3]=Fo,n[Lt+40>>2]=M,xo(o,4,2989,Lt))}while(!1);return(Xe|0)==28&&(ae=Iu(We)|0,n[Le>>2]=ae,n[Le+4>>2]=We,n[Le+8>>2]=Hr?3047:11699,xo(o,4,3038,Le),ae=n[o+972>>2]|0,ae|0&&ip[ae&127](o),Lt=pa(d,R)|0,Xe=pa(m,R)|0,n[He>>2]=Lt,n[He+4>>2]=Xe,E[He+8>>3]=+l,E[He+16>>3]=+u,n[He+24>>2]=M,xo(o,4,3049,He),Xe=31),(Xe|0)==31&&(Fs(o,l,u,A,d,m,B,k,R,L),s[11697]|0&&(ae=n[2279]|0,Lt=Iu(ae)|0,n[Gr>>2]=Lt,n[Gr+4>>2]=ae,n[Gr+8>>2]=Hr?3047:11699,xo(o,4,3083,Gr),ae=n[o+972>>2]|0,ae|0&&ip[ae&127](o),Lt=pa(d,R)|0,Gr=pa(m,R)|0,Fo=+y(h[o+908>>2]),Xa=+y(h[o+912>>2]),n[fr>>2]=Lt,n[fr+4>>2]=Gr,E[fr+8>>3]=Fo,E[fr+16>>3]=Xa,n[fr+24>>2]=M,xo(o,4,3092,fr)),n[o+516>>2]=A,q||(ae=o+520|0,q=n[ae>>2]|0,(q|0)==16&&(s[11697]|0&&xo(o,4,3124,$t),n[ae>>2]=0,q=0),R?q=o+916|0:(n[ae>>2]=q+1,q=o+524+(q*24|0)|0),h[q>>2]=l,h[q+4>>2]=u,n[q+8>>2]=d,n[q+12>>2]=m,n[q+16>>2]=n[o+908>>2],n[q+20>>2]=n[o+912>>2],q=0)),R&&(n[o+416>>2]=n[o+908>>2],n[o+420>>2]=n[o+912>>2],s[o+985>>0]=1,s[Rr>>0]=0),n[2279]=(n[2279]|0)+-1,n[o+512>>2]=n[2278],I=cr,Hr|(q|0)==0|0}function yn(o,l,u){o=o|0,l=l|0,u=y(u);var A=$e;return A=y(K(o,l,u)),y(A+y(re(o,l,u)))}function xo(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=I,I=I+16|0,d=m,n[d>>2]=A,o?A=n[o+976>>2]|0:A=0,bh(A,o,l,u,d),I=m}function Iu(o){return o=o|0,(o>>>0>60?3201:3201+(60-o)|0)|0}function pa(o,l){o=o|0,l=l|0;var u=0,A=0,d=0;return d=I,I=I+32|0,u=d+12|0,A=d,n[u>>2]=n[254],n[u+4>>2]=n[255],n[u+8>>2]=n[256],n[A>>2]=n[257],n[A+4>>2]=n[258],n[A+8>>2]=n[259],(o|0)>2?o=11699:o=n[(l?A:u)+(o<<2)>>2]|0,I=d,o|0}function Fs(o,l,u,A,d,m,B,k,R,M){o=o|0,l=y(l),u=y(u),A=A|0,d=d|0,m=m|0,B=y(B),k=y(k),R=R|0,M=M|0;var L=0,q=0,ae=0,Ye=0,Le=$e,Qe=$e,tt=$e,Xe=$e,ct=$e,He=$e,We=$e,Lt=0,Gr=0,fr=0,$t=$e,Rr=$e,Hr=0,cr=$e,Hn=0,Ro=0,To=0,Fo=0,Xa=0,Wh=0,Yh=0,gc=0,Vh=0,Tf=0,Ff=0,Jh=0,Kh=0,zh=0,on=0,dc=0,Zh=0,bu=0,Xh=$e,$h=$e,Nf=$e,Of=$e,xu=$e,oo=0,Ll=0,ma=0,mc=0,op=0,ap=$e,Lf=$e,lp=$e,cp=$e,ao=$e,Ms=$e,yc=0,Wn=$e,up=$e,No=$e,ku=$e,Oo=$e,Qu=$e,fp=0,Ap=0,Ru=$e,lo=$e,Ec=0,pp=0,hp=0,gp=0,Nr=$e,ui=0,Us=0,Lo=0,co=0,Mr=0,Ar=0,Ic=0,zt=$e,dp=0,Bi=0;Ic=I,I=I+16|0,oo=Ic+12|0,Ll=Ic+8|0,ma=Ic+4|0,mc=Ic,wi(o,(d|0)==0|(Mt(l)|0)^1,3326),wi(o,(m|0)==0|(Mt(u)|0)^1,3406),Us=At(o,A)|0,n[o+496>>2]=Us,Mr=dr(2,Us)|0,Ar=dr(0,Us)|0,h[o+440>>2]=y(K(o,Mr,B)),h[o+444>>2]=y(re(o,Mr,B)),h[o+428>>2]=y(K(o,Ar,B)),h[o+436>>2]=y(re(o,Ar,B)),h[o+464>>2]=y(vr(o,Mr)),h[o+468>>2]=y(Un(o,Mr)),h[o+452>>2]=y(vr(o,Ar)),h[o+460>>2]=y(Un(o,Ar)),h[o+488>>2]=y(mi(o,Mr,B)),h[o+492>>2]=y(Cs(o,Mr,B)),h[o+476>>2]=y(mi(o,Ar,B)),h[o+484>>2]=y(Cs(o,Ar,B));do if(n[o+964>>2]|0)JA(o,l,u,d,m,B,k);else{if(Lo=o+948|0,co=(n[o+952>>2]|0)-(n[Lo>>2]|0)>>2,!co){ab(o,l,u,d,m,B,k);break}if(!R&&t2(o,l,u,d,m,B,k)|0)break;te(o),dc=o+508|0,s[dc>>0]=0,Mr=dr(n[o+4>>2]|0,Us)|0,Ar=Py(Mr,Us)|0,ui=de(Mr)|0,Zh=n[o+8>>2]|0,pp=o+28|0,bu=(n[pp>>2]|0)!=0,Oo=ui?B:k,Ru=ui?k:B,Xh=y(kh(o,Mr,B)),$h=y(r2(o,Mr,B)),Le=y(kh(o,Ar,B)),Qu=y(Va(o,Mr,B)),lo=y(Va(o,Ar,B)),fr=ui?d:m,Ec=ui?m:d,Nr=ui?Qu:lo,ct=ui?lo:Qu,ku=y(yn(o,2,B)),Xe=y(yn(o,0,B)),Qe=y(y(Xr(o+364|0,B))-Nr),tt=y(y(Xr(o+380|0,B))-Nr),He=y(y(Xr(o+372|0,k))-ct),We=y(y(Xr(o+388|0,k))-ct),Nf=ui?Qe:He,Of=ui?tt:We,ku=y(l-ku),l=y(ku-Nr),Mt(l)|0?Nr=l:Nr=y($n(y(pd(l,tt)),Qe)),up=y(u-Xe),l=y(up-ct),Mt(l)|0?No=l:No=y($n(y(pd(l,We)),He)),Qe=ui?Nr:No,Wn=ui?No:Nr;e:do if((fr|0)==1)for(A=0,q=0;;){if(L=Is(o,q)|0,!A)y(KA(L))>y(0)&&y(Qh(L))>y(0)?A=L:A=0;else if(n2(L)|0){Ye=0;break e}if(q=q+1|0,q>>>0>=co>>>0){Ye=A;break}}else Ye=0;while(!1);Lt=Ye+500|0,Gr=Ye+504|0,A=0,L=0,l=y(0),ae=0;do{if(q=n[(n[Lo>>2]|0)+(ae<<2)>>2]|0,(n[q+36>>2]|0)==1)by(q),s[q+985>>0]=1,s[q+984>>0]=0;else{vf(q),R&&Ph(q,At(q,Us)|0,Qe,Wn,Nr);do if((n[q+24>>2]|0)!=1)if((q|0)==(Ye|0)){n[Lt>>2]=n[2278],h[Gr>>2]=y(0);break}else{lb(o,q,Nr,d,No,Nr,No,m,Us,M);break}else L|0&&(n[L+960>>2]=q),n[q+960>>2]=0,L=q,A=A|0?A:q;while(!1);Ms=y(h[q+504>>2]),l=y(l+y(Ms+y(yn(q,Mr,Nr))))}ae=ae+1|0}while((ae|0)!=(co|0));for(To=l>Qe,yc=bu&((fr|0)==2&To)?1:fr,Hn=(Ec|0)==1,Xa=Hn&(R^1),Wh=(yc|0)==1,Yh=(yc|0)==2,gc=976+(Mr<<2)|0,Vh=(Ec|2|0)==2,zh=Hn&(bu^1),Tf=1040+(Ar<<2)|0,Ff=1040+(Mr<<2)|0,Jh=976+(Ar<<2)|0,Kh=(Ec|0)!=1,To=bu&((fr|0)!=0&To),Ro=o+976|0,Hn=Hn^1,l=Qe,Hr=0,Fo=0,Ms=y(0),xu=y(0);;){e:do if(Hr>>>0<co>>>0)for(Gr=n[Lo>>2]|0,ae=0,We=y(0),He=y(0),tt=y(0),Qe=y(0),q=0,L=0,Ye=Hr;;){if(Lt=n[Gr+(Ye<<2)>>2]|0,(n[Lt+36>>2]|0)!=1&&(n[Lt+940>>2]=Fo,(n[Lt+24>>2]|0)!=1)){if(Xe=y(yn(Lt,Mr,Nr)),on=n[gc>>2]|0,u=y(Xr(Lt+380+(on<<3)|0,Oo)),ct=y(h[Lt+504>>2]),u=y(pd(u,ct)),u=y($n(y(Xr(Lt+364+(on<<3)|0,Oo)),u)),bu&(ae|0)!=0&y(Xe+y(He+u))>l){m=ae,Xe=We,fr=Ye;break e}Xe=y(Xe+u),u=y(He+Xe),Xe=y(We+Xe),n2(Lt)|0&&(tt=y(tt+y(KA(Lt))),Qe=y(Qe-y(ct*y(Qh(Lt))))),L|0&&(n[L+960>>2]=Lt),n[Lt+960>>2]=0,ae=ae+1|0,L=Lt,q=q|0?q:Lt}else Xe=We,u=He;if(Ye=Ye+1|0,Ye>>>0<co>>>0)We=Xe,He=u;else{m=ae,fr=Ye;break}}else m=0,Xe=y(0),tt=y(0),Qe=y(0),q=0,fr=Hr;while(!1);on=tt>y(0)&tt<y(1),$t=on?y(1):tt,on=Qe>y(0)&Qe<y(1),We=on?y(1):Qe;do if(Wh)on=51;else if(Xe<Nf&((Mt(Nf)|0)^1))l=Nf,on=51;else if(Xe>Of&((Mt(Of)|0)^1))l=Of,on=51;else if(s[(n[Ro>>2]|0)+3>>0]|0)on=51;else{if($t!=y(0)&&y(KA(o))!=y(0)){on=53;break}l=Xe,on=53}while(!1);if((on|0)==51&&(on=0,Mt(l)|0?on=53:(Rr=y(l-Xe),cr=l)),(on|0)==53&&(on=0,Xe<y(0)?(Rr=y(-Xe),cr=l):(Rr=y(0),cr=l)),!Xa&&(op=(q|0)==0,!op)){ae=n[gc>>2]|0,Ye=Rr<y(0),ct=y(Rr/We),Lt=Rr>y(0),He=y(Rr/$t),tt=y(0),Xe=y(0),l=y(0),L=q;do u=y(Xr(L+380+(ae<<3)|0,Oo)),Qe=y(Xr(L+364+(ae<<3)|0,Oo)),Qe=y(pd(u,y($n(Qe,y(h[L+504>>2]))))),Ye?(u=y(Qe*y(Qh(L))),u!=y(-0)&&(zt=y(Qe-y(ct*u)),ap=y(qn(L,Mr,zt,cr,Nr)),zt!=ap)&&(tt=y(tt-y(ap-Qe)),l=y(l+u))):Lt&&(Lf=y(KA(L)),Lf!=y(0))&&(zt=y(Qe+y(He*Lf)),lp=y(qn(L,Mr,zt,cr,Nr)),zt!=lp)&&(tt=y(tt-y(lp-Qe)),Xe=y(Xe-Lf)),L=n[L+960>>2]|0;while(L|0);if(l=y(We+l),Qe=y(Rr+tt),op)l=y(0);else{ct=y($t+Xe),Ye=n[gc>>2]|0,Lt=Qe<y(0),Gr=l==y(0),He=y(Qe/l),ae=Qe>y(0),ct=y(Qe/ct),l=y(0);do{zt=y(Xr(q+380+(Ye<<3)|0,Oo)),tt=y(Xr(q+364+(Ye<<3)|0,Oo)),tt=y(pd(zt,y($n(tt,y(h[q+504>>2]))))),Lt?(zt=y(tt*y(Qh(q))),Qe=y(-zt),zt!=y(-0)?(zt=y(He*Qe),Qe=y(qn(q,Mr,y(tt+(Gr?Qe:zt)),cr,Nr))):Qe=tt):ae&&(cp=y(KA(q)),cp!=y(0))?Qe=y(qn(q,Mr,y(tt+y(ct*cp)),cr,Nr)):Qe=tt,l=y(l-y(Qe-tt)),Xe=y(yn(q,Mr,Nr)),u=y(yn(q,Ar,Nr)),Qe=y(Qe+Xe),h[Ll>>2]=Qe,n[mc>>2]=1,tt=y(h[q+396>>2]);e:do if(Mt(tt)|0){L=Mt(Wn)|0;do if(!L){if(To|(io(q,Ar,Wn)|0|Hn)||(ss(o,q)|0)!=4||(n[(kl(q,Ar)|0)+4>>2]|0)==3||(n[(Ql(q,Ar)|0)+4>>2]|0)==3)break;h[oo>>2]=Wn,n[ma>>2]=1;break e}while(!1);if(io(q,Ar,Wn)|0){L=n[q+992+(n[Jh>>2]<<2)>>2]|0,zt=y(u+y(Xr(L,Wn))),h[oo>>2]=zt,L=Kh&(n[L+4>>2]|0)==2,n[ma>>2]=((Mt(zt)|0|L)^1)&1;break}else{h[oo>>2]=Wn,n[ma>>2]=L?0:2;break}}else zt=y(Qe-Xe),$t=y(zt/tt),zt=y(tt*zt),n[ma>>2]=1,h[oo>>2]=y(u+(ui?$t:zt));while(!1);Cu(q,Mr,cr,Nr,mc,Ll),Cu(q,Ar,Wn,Nr,ma,oo);do if(!(io(q,Ar,Wn)|0)&&(ss(o,q)|0)==4){if((n[(kl(q,Ar)|0)+4>>2]|0)==3){L=0;break}L=(n[(Ql(q,Ar)|0)+4>>2]|0)!=3}else L=0;while(!1);zt=y(h[Ll>>2]),$t=y(h[oo>>2]),dp=n[mc>>2]|0,Bi=n[ma>>2]|0,xl(q,ui?zt:$t,ui?$t:zt,Us,ui?dp:Bi,ui?Bi:dp,Nr,No,R&(L^1),3488,M)|0,s[dc>>0]=s[dc>>0]|s[q+508>>0],q=n[q+960>>2]|0}while(q|0)}}else l=y(0);if(l=y(Rr+l),Bi=l<y(0)&1,s[dc>>0]=Bi|c[dc>>0],Yh&l>y(0)?(L=n[gc>>2]|0,n[o+364+(L<<3)+4>>2]|0&&(ao=y(Xr(o+364+(L<<3)|0,Oo)),ao>=y(0))?Qe=y($n(y(0),y(ao-y(cr-l)))):Qe=y(0)):Qe=l,Lt=Hr>>>0<fr>>>0,Lt){Ye=n[Lo>>2]|0,ae=Hr,L=0;do q=n[Ye+(ae<<2)>>2]|0,n[q+24>>2]|0||(L=((n[(kl(q,Mr)|0)+4>>2]|0)==3&1)+L|0,L=L+((n[(Ql(q,Mr)|0)+4>>2]|0)==3&1)|0),ae=ae+1|0;while((ae|0)!=(fr|0));L?(Xe=y(0),u=y(0)):on=101}else on=101;e:do if((on|0)==101)switch(on=0,Zh|0){case 1:{L=0,Xe=y(Qe*y(.5)),u=y(0);break e}case 2:{L=0,Xe=Qe,u=y(0);break e}case 3:{if(m>>>0<=1){L=0,Xe=y(0),u=y(0);break e}u=y((m+-1|0)>>>0),L=0,Xe=y(0),u=y(y($n(Qe,y(0)))/u);break e}case 5:{u=y(Qe/y((m+1|0)>>>0)),L=0,Xe=u;break e}case 4:{u=y(Qe/y(m>>>0)),L=0,Xe=y(u*y(.5));break e}default:{L=0,Xe=y(0),u=y(0);break e}}while(!1);if(l=y(Xh+Xe),Lt){tt=y(Qe/y(L|0)),ae=n[Lo>>2]|0,q=Hr,Qe=y(0);do{L=n[ae+(q<<2)>>2]|0;e:do if((n[L+36>>2]|0)!=1){switch(n[L+24>>2]|0){case 1:{if(ha(L,Mr)|0){if(!R)break e;zt=y(zA(L,Mr,cr)),zt=y(zt+y(vr(o,Mr))),zt=y(zt+y(K(L,Mr,Nr))),h[L+400+(n[Ff>>2]<<2)>>2]=zt;break e}break}case 0:if(Bi=(n[(kl(L,Mr)|0)+4>>2]|0)==3,zt=y(tt+l),l=Bi?zt:l,R&&(Bi=L+400+(n[Ff>>2]<<2)|0,h[Bi>>2]=y(l+y(h[Bi>>2]))),Bi=(n[(Ql(L,Mr)|0)+4>>2]|0)==3,zt=y(tt+l),l=Bi?zt:l,Xa){zt=y(u+y(yn(L,Mr,Nr))),Qe=Wn,l=y(l+y(zt+y(h[L+504>>2])));break e}else{l=y(l+y(u+y(ZA(L,Mr,Nr)))),Qe=y($n(Qe,y(ZA(L,Ar,Nr))));break e}default:}R&&(zt=y(Xe+y(vr(o,Mr))),Bi=L+400+(n[Ff>>2]<<2)|0,h[Bi>>2]=y(zt+y(h[Bi>>2])))}while(!1);q=q+1|0}while((q|0)!=(fr|0))}else Qe=y(0);if(u=y($h+l),Vh?Xe=y(y(qn(o,Ar,y(lo+Qe),Ru,B))-lo):Xe=Wn,tt=y(y(qn(o,Ar,y(lo+(zh?Wn:Qe)),Ru,B))-lo),Lt&R){q=Hr;do{ae=n[(n[Lo>>2]|0)+(q<<2)>>2]|0;do if((n[ae+36>>2]|0)!=1){if((n[ae+24>>2]|0)==1){if(ha(ae,Ar)|0){if(zt=y(zA(ae,Ar,Wn)),zt=y(zt+y(vr(o,Ar))),zt=y(zt+y(K(ae,Ar,Nr))),L=n[Tf>>2]|0,h[ae+400+(L<<2)>>2]=zt,!(Mt(zt)|0))break}else L=n[Tf>>2]|0;zt=y(vr(o,Ar)),h[ae+400+(L<<2)>>2]=y(zt+y(K(ae,Ar,Nr)));break}L=ss(o,ae)|0;do if((L|0)==4){if((n[(kl(ae,Ar)|0)+4>>2]|0)==3){on=139;break}if((n[(Ql(ae,Ar)|0)+4>>2]|0)==3){on=139;break}if(io(ae,Ar,Wn)|0){l=Le;break}dp=n[ae+908+(n[gc>>2]<<2)>>2]|0,n[oo>>2]=dp,l=y(h[ae+396>>2]),Bi=Mt(l)|0,Qe=(n[S>>2]=dp,y(h[S>>2])),Bi?l=tt:(Rr=y(yn(ae,Ar,Nr)),zt=y(Qe/l),l=y(l*Qe),l=y(Rr+(ui?zt:l))),h[Ll>>2]=l,h[oo>>2]=y(y(yn(ae,Mr,Nr))+Qe),n[ma>>2]=1,n[mc>>2]=1,Cu(ae,Mr,cr,Nr,ma,oo),Cu(ae,Ar,Wn,Nr,mc,Ll),l=y(h[oo>>2]),Rr=y(h[Ll>>2]),zt=ui?l:Rr,l=ui?Rr:l,Bi=((Mt(zt)|0)^1)&1,xl(ae,zt,l,Us,Bi,((Mt(l)|0)^1)&1,Nr,No,1,3493,M)|0,l=Le}else on=139;while(!1);e:do if((on|0)==139){on=0,l=y(Xe-y(ZA(ae,Ar,Nr)));do if((n[(kl(ae,Ar)|0)+4>>2]|0)==3){if((n[(Ql(ae,Ar)|0)+4>>2]|0)!=3)break;l=y(Le+y($n(y(0),y(l*y(.5)))));break e}while(!1);if((n[(Ql(ae,Ar)|0)+4>>2]|0)==3){l=Le;break}if((n[(kl(ae,Ar)|0)+4>>2]|0)==3){l=y(Le+y($n(y(0),l)));break}switch(L|0){case 1:{l=Le;break e}case 2:{l=y(Le+y(l*y(.5)));break e}default:{l=y(Le+l);break e}}}while(!1);zt=y(Ms+l),Bi=ae+400+(n[Tf>>2]<<2)|0,h[Bi>>2]=y(zt+y(h[Bi>>2]))}while(!1);q=q+1|0}while((q|0)!=(fr|0))}if(Ms=y(Ms+tt),xu=y($n(xu,u)),m=Fo+1|0,fr>>>0>=co>>>0)break;l=cr,Hr=fr,Fo=m}do if(R){if(L=m>>>0>1,!L&&!(HL(o)|0))break;if(!(Mt(Wn)|0)){l=y(Wn-Ms);e:do switch(n[o+12>>2]|0){case 3:{Le=y(Le+l),He=y(0);break}case 2:{Le=y(Le+y(l*y(.5))),He=y(0);break}case 4:{Wn>Ms?He=y(l/y(m>>>0)):He=y(0);break}case 7:if(Wn>Ms){Le=y(Le+y(l/y(m<<1>>>0))),He=y(l/y(m>>>0)),He=L?He:y(0);break e}else{Le=y(Le+y(l*y(.5))),He=y(0);break e}case 6:{He=y(l/y(Fo>>>0)),He=Wn>Ms&L?He:y(0);break}default:He=y(0)}while(!1);if(m|0)for(Lt=1040+(Ar<<2)|0,Gr=976+(Ar<<2)|0,Ye=0,q=0;;){e:do if(q>>>0<co>>>0)for(Qe=y(0),tt=y(0),l=y(0),ae=q;;){L=n[(n[Lo>>2]|0)+(ae<<2)>>2]|0;do if((n[L+36>>2]|0)!=1&&!(n[L+24>>2]|0)){if((n[L+940>>2]|0)!=(Ye|0))break e;if(jL(L,Ar)|0&&(zt=y(h[L+908+(n[Gr>>2]<<2)>>2]),l=y($n(l,y(zt+y(yn(L,Ar,Nr)))))),(ss(o,L)|0)!=5)break;ao=y(Yg(L)),ao=y(ao+y(K(L,0,Nr))),zt=y(h[L+912>>2]),zt=y(y(zt+y(yn(L,0,Nr)))-ao),ao=y($n(tt,ao)),zt=y($n(Qe,zt)),Qe=zt,tt=ao,l=y($n(l,y(ao+zt)))}while(!1);if(L=ae+1|0,L>>>0<co>>>0)ae=L;else{ae=L;break}}else tt=y(0),l=y(0),ae=q;while(!1);if(ct=y(He+l),u=Le,Le=y(Le+ct),q>>>0<ae>>>0){Xe=y(u+tt),L=q;do{q=n[(n[Lo>>2]|0)+(L<<2)>>2]|0;e:do if((n[q+36>>2]|0)!=1&&!(n[q+24>>2]|0))switch(ss(o,q)|0){case 1:{zt=y(u+y(K(q,Ar,Nr))),h[q+400+(n[Lt>>2]<<2)>>2]=zt;break e}case 3:{zt=y(y(Le-y(re(q,Ar,Nr)))-y(h[q+908+(n[Gr>>2]<<2)>>2])),h[q+400+(n[Lt>>2]<<2)>>2]=zt;break e}case 2:{zt=y(u+y(y(ct-y(h[q+908+(n[Gr>>2]<<2)>>2]))*y(.5))),h[q+400+(n[Lt>>2]<<2)>>2]=zt;break e}case 4:{if(zt=y(u+y(K(q,Ar,Nr))),h[q+400+(n[Lt>>2]<<2)>>2]=zt,io(q,Ar,Wn)|0||(ui?(Qe=y(h[q+908>>2]),l=y(Qe+y(yn(q,Mr,Nr))),tt=ct):(tt=y(h[q+912>>2]),tt=y(tt+y(yn(q,Ar,Nr))),l=ct,Qe=y(h[q+908>>2])),mn(l,Qe)|0&&mn(tt,y(h[q+912>>2]))|0))break e;xl(q,l,tt,Us,1,1,Nr,No,1,3501,M)|0;break e}case 5:{h[q+404>>2]=y(y(Xe-y(Yg(q)))+y(zA(q,0,Wn)));break e}default:break e}while(!1);L=L+1|0}while((L|0)!=(ae|0))}if(Ye=Ye+1|0,(Ye|0)==(m|0))break;q=ae}}}while(!1);if(h[o+908>>2]=y(qn(o,2,ku,B,B)),h[o+912>>2]=y(qn(o,0,up,k,B)),yc|0&&(fp=n[o+32>>2]|0,Ap=(yc|0)==2,!(Ap&(fp|0)!=2))?Ap&(fp|0)==2&&(l=y(Qu+cr),l=y($n(y(pd(l,y(Vg(o,Mr,xu,Oo)))),Qu)),on=198):(l=y(qn(o,Mr,xu,Oo,B)),on=198),(on|0)==198&&(h[o+908+(n[976+(Mr<<2)>>2]<<2)>>2]=l),Ec|0&&(hp=n[o+32>>2]|0,gp=(Ec|0)==2,!(gp&(hp|0)!=2))?gp&(hp|0)==2&&(l=y(lo+Wn),l=y($n(y(pd(l,y(Vg(o,Ar,y(lo+Ms),Ru)))),lo)),on=204):(l=y(qn(o,Ar,y(lo+Ms),Ru,B)),on=204),(on|0)==204&&(h[o+908+(n[976+(Ar<<2)>>2]<<2)>>2]=l),R){if((n[pp>>2]|0)==2){q=976+(Ar<<2)|0,ae=1040+(Ar<<2)|0,L=0;do Ye=Is(o,L)|0,n[Ye+24>>2]|0||(dp=n[q>>2]|0,zt=y(h[o+908+(dp<<2)>>2]),Bi=Ye+400+(n[ae>>2]<<2)|0,zt=y(zt-y(h[Bi>>2])),h[Bi>>2]=y(zt-y(h[Ye+908+(dp<<2)>>2]))),L=L+1|0;while((L|0)!=(co|0))}if(A|0){L=ui?yc:d;do qL(o,A,Nr,L,No,Us,M),A=n[A+960>>2]|0;while(A|0)}if(L=(Mr|2|0)==3,q=(Ar|2|0)==3,L|q){A=0;do ae=n[(n[Lo>>2]|0)+(A<<2)>>2]|0,(n[ae+36>>2]|0)!=1&&(L&&i2(o,ae,Mr),q&&i2(o,ae,Ar)),A=A+1|0;while((A|0)!=(co|0))}}}while(!1);I=Ic}function Dh(o,l){o=o|0,l=y(l);var u=0;Ha(o,l>=y(0),3147),u=l==y(0),h[o+4>>2]=u?y(0):l}function YA(o,l,u,A){o=o|0,l=y(l),u=y(u),A=A|0;var d=$e,m=$e,B=0,k=0,R=0;n[2278]=(n[2278]|0)+1,vf(o),io(o,2,l)|0?(d=y(Xr(n[o+992>>2]|0,l)),R=1,d=y(d+y(yn(o,2,l)))):(d=y(Xr(o+380|0,l)),d>=y(0)?R=2:(R=((Mt(l)|0)^1)&1,d=l)),io(o,0,u)|0?(m=y(Xr(n[o+996>>2]|0,u)),k=1,m=y(m+y(yn(o,0,l)))):(m=y(Xr(o+388|0,u)),m>=y(0)?k=2:(k=((Mt(u)|0)^1)&1,m=u)),B=o+976|0,xl(o,d,m,A,R,k,l,u,1,3189,n[B>>2]|0)|0&&(Ph(o,n[o+496>>2]|0,l,u,l),VA(o,y(h[(n[B>>2]|0)+4>>2]),y(0),y(0)),s[11696]|0)&&Gg(o,7)}function vf(o){o=o|0;var l=0,u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0;k=I,I=I+32|0,B=k+24|0,m=k+16|0,A=k+8|0,d=k,u=0;do l=o+380+(u<<3)|0,n[o+380+(u<<3)+4>>2]|0&&(R=l,M=n[R+4>>2]|0,L=A,n[L>>2]=n[R>>2],n[L+4>>2]=M,L=o+364+(u<<3)|0,M=n[L+4>>2]|0,R=d,n[R>>2]=n[L>>2],n[R+4>>2]=M,n[m>>2]=n[A>>2],n[m+4>>2]=n[A+4>>2],n[B>>2]=n[d>>2],n[B+4>>2]=n[d+4>>2],Cf(m,B)|0)||(l=o+348+(u<<3)|0),n[o+992+(u<<2)>>2]=l,u=u+1|0;while((u|0)!=2);I=k}function io(o,l,u){o=o|0,l=l|0,u=y(u);var A=0;switch(o=n[o+992+(n[976+(l<<2)>>2]<<2)>>2]|0,n[o+4>>2]|0){case 0:case 3:{o=0;break}case 1:{y(h[o>>2])<y(0)?o=0:A=5;break}case 2:{y(h[o>>2])<y(0)?o=0:o=(Mt(u)|0)^1;break}default:A=5}return(A|0)==5&&(o=1),o|0}function Xr(o,l){switch(o=o|0,l=y(l),n[o+4>>2]|0){case 2:{l=y(y(y(h[o>>2])*l)/y(100));break}case 1:{l=y(h[o>>2]);break}default:l=y(le)}return y(l)}function Ph(o,l,u,A,d){o=o|0,l=l|0,u=y(u),A=y(A),d=y(d);var m=0,B=$e;l=n[o+944>>2]|0?l:1,m=dr(n[o+4>>2]|0,l)|0,l=Py(m,l)|0,u=y(ub(o,m,u)),A=y(ub(o,l,A)),B=y(u+y(K(o,m,d))),h[o+400+(n[1040+(m<<2)>>2]<<2)>>2]=B,u=y(u+y(re(o,m,d))),h[o+400+(n[1e3+(m<<2)>>2]<<2)>>2]=u,u=y(A+y(K(o,l,d))),h[o+400+(n[1040+(l<<2)>>2]<<2)>>2]=u,d=y(A+y(re(o,l,d))),h[o+400+(n[1e3+(l<<2)>>2]<<2)>>2]=d}function VA(o,l,u,A){o=o|0,l=y(l),u=y(u),A=y(A);var d=0,m=0,B=$e,k=$e,R=0,M=0,L=$e,q=0,ae=$e,Ye=$e,Le=$e,Qe=$e;if(l!=y(0)&&(d=o+400|0,Qe=y(h[d>>2]),m=o+404|0,Le=y(h[m>>2]),q=o+416|0,Ye=y(h[q>>2]),M=o+420|0,B=y(h[M>>2]),ae=y(Qe+u),L=y(Le+A),A=y(ae+Ye),k=y(L+B),R=(n[o+988>>2]|0)==1,h[d>>2]=y(is(Qe,l,0,R)),h[m>>2]=y(is(Le,l,0,R)),u=y(cU(y(Ye*l),y(1))),mn(u,y(0))|0?m=0:m=(mn(u,y(1))|0)^1,u=y(cU(y(B*l),y(1))),mn(u,y(0))|0?d=0:d=(mn(u,y(1))|0)^1,Qe=y(is(A,l,R&m,R&(m^1))),h[q>>2]=y(Qe-y(is(ae,l,0,R))),Qe=y(is(k,l,R&d,R&(d^1))),h[M>>2]=y(Qe-y(is(L,l,0,R))),m=(n[o+952>>2]|0)-(n[o+948>>2]|0)>>2,m|0)){d=0;do VA(Is(o,d)|0,l,ae,L),d=d+1|0;while((d|0)!=(m|0))}}function Sy(o,l,u,A,d){switch(o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,u|0){case 5:case 0:{o=dX(n[489]|0,A,d)|0;break}default:o=v6e(A,d)|0}return o|0}function Wg(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;d=I,I=I+16|0,m=d,n[m>>2]=A,bh(o,0,l,u,m),I=d}function bh(o,l,u,A,d){if(o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,o=o|0?o:956,LX[n[o+8>>2]&1](o,l,u,A,d)|0,(u|0)==5)Nt();else return}function pc(o,l,u){o=o|0,l=l|0,u=u|0,s[o+l>>0]=u&1}function Dy(o,l){o=o|0,l=l|0;var u=0,A=0;n[o>>2]=0,n[o+4>>2]=0,n[o+8>>2]=0,u=l+4|0,A=(n[u>>2]|0)-(n[l>>2]|0)>>2,A|0&&(xh(o,A),kt(o,n[l>>2]|0,n[u>>2]|0,A))}function xh(o,l){o=o|0,l=l|0;var u=0;if((O(o)|0)>>>0<l>>>0&&sn(o),l>>>0>1073741823)Nt();else{u=Kt(l<<2)|0,n[o+4>>2]=u,n[o>>2]=u,n[o+8>>2]=u+(l<<2);return}}function kt(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,A=o+4|0,o=u-l|0,(o|0)>0&&(Qr(n[A>>2]|0,l|0,o|0)|0,n[A>>2]=(n[A>>2]|0)+(o>>>2<<2))}function O(o){return o=o|0,1073741823}function K(o,l,u){return o=o|0,l=l|0,u=y(u),de(l)|0&&n[o+96>>2]|0?o=o+92|0:o=kn(o+60|0,n[1040+(l<<2)>>2]|0,992)|0,y(Je(o,u))}function re(o,l,u){return o=o|0,l=l|0,u=y(u),de(l)|0&&n[o+104>>2]|0?o=o+100|0:o=kn(o+60|0,n[1e3+(l<<2)>>2]|0,992)|0,y(Je(o,u))}function de(o){return o=o|0,(o|1|0)==3|0}function Je(o,l){return o=o|0,l=y(l),(n[o+4>>2]|0)==3?l=y(0):l=y(Xr(o,l)),y(l)}function At(o,l){return o=o|0,l=l|0,o=n[o>>2]|0,(o|0?o:(l|0)>1?l:1)|0}function dr(o,l){o=o|0,l=l|0;var u=0;e:do if((l|0)==2){switch(o|0){case 2:{o=3;break e}case 3:break;default:{u=4;break e}}o=2}else u=4;while(!1);return o|0}function vr(o,l){o=o|0,l=l|0;var u=$e;return de(l)|0&&n[o+312>>2]|0&&(u=y(h[o+308>>2]),u>=y(0))||(u=y($n(y(h[(kn(o+276|0,n[1040+(l<<2)>>2]|0,992)|0)>>2]),y(0)))),y(u)}function Un(o,l){o=o|0,l=l|0;var u=$e;return de(l)|0&&n[o+320>>2]|0&&(u=y(h[o+316>>2]),u>=y(0))||(u=y($n(y(h[(kn(o+276|0,n[1e3+(l<<2)>>2]|0,992)|0)>>2]),y(0)))),y(u)}function mi(o,l,u){o=o|0,l=l|0,u=y(u);var A=$e;return de(l)|0&&n[o+240>>2]|0&&(A=y(Xr(o+236|0,u)),A>=y(0))||(A=y($n(y(Xr(kn(o+204|0,n[1040+(l<<2)>>2]|0,992)|0,u)),y(0)))),y(A)}function Cs(o,l,u){o=o|0,l=l|0,u=y(u);var A=$e;return de(l)|0&&n[o+248>>2]|0&&(A=y(Xr(o+244|0,u)),A>=y(0))||(A=y($n(y(Xr(kn(o+204|0,n[1e3+(l<<2)>>2]|0,992)|0,u)),y(0)))),y(A)}function JA(o,l,u,A,d,m,B){o=o|0,l=y(l),u=y(u),A=A|0,d=d|0,m=y(m),B=y(B);var k=$e,R=$e,M=$e,L=$e,q=$e,ae=$e,Ye=0,Le=0,Qe=0;Qe=I,I=I+16|0,Ye=Qe,Le=o+964|0,wi(o,(n[Le>>2]|0)!=0,3519),k=y(Va(o,2,l)),R=y(Va(o,0,l)),M=y(yn(o,2,l)),L=y(yn(o,0,l)),Mt(l)|0?q=l:q=y($n(y(0),y(y(l-M)-k))),Mt(u)|0?ae=u:ae=y($n(y(0),y(y(u-L)-R))),(A|0)==1&(d|0)==1?(h[o+908>>2]=y(qn(o,2,y(l-M),m,m)),l=y(qn(o,0,y(u-L),B,m))):(MX[n[Le>>2]&1](Ye,o,q,A,ae,d),q=y(k+y(h[Ye>>2])),ae=y(l-M),h[o+908>>2]=y(qn(o,2,(A|2|0)==2?q:ae,m,m)),ae=y(R+y(h[Ye+4>>2])),l=y(u-L),l=y(qn(o,0,(d|2|0)==2?ae:l,B,m))),h[o+912>>2]=l,I=Qe}function ab(o,l,u,A,d,m,B){o=o|0,l=y(l),u=y(u),A=A|0,d=d|0,m=y(m),B=y(B);var k=$e,R=$e,M=$e,L=$e;M=y(Va(o,2,m)),k=y(Va(o,0,m)),L=y(yn(o,2,m)),R=y(yn(o,0,m)),l=y(l-L),h[o+908>>2]=y(qn(o,2,(A|2|0)==2?M:l,m,m)),u=y(u-R),h[o+912>>2]=y(qn(o,0,(d|2|0)==2?k:u,B,m))}function t2(o,l,u,A,d,m,B){o=o|0,l=y(l),u=y(u),A=A|0,d=d|0,m=y(m),B=y(B);var k=0,R=$e,M=$e;return k=(A|0)==2,!(l<=y(0)&k)&&!(u<=y(0)&(d|0)==2)&&!((A|0)==1&(d|0)==1)?o=0:(R=y(yn(o,0,m)),M=y(yn(o,2,m)),k=l<y(0)&k|(Mt(l)|0),l=y(l-M),h[o+908>>2]=y(qn(o,2,k?y(0):l,m,m)),l=y(u-R),k=u<y(0)&(d|0)==2|(Mt(u)|0),h[o+912>>2]=y(qn(o,0,k?y(0):l,B,m)),o=1),o|0}function Py(o,l){return o=o|0,l=l|0,Jg(o)|0?o=dr(2,l)|0:o=0,o|0}function kh(o,l,u){return o=o|0,l=l|0,u=y(u),u=y(mi(o,l,u)),y(u+y(vr(o,l)))}function r2(o,l,u){return o=o|0,l=l|0,u=y(u),u=y(Cs(o,l,u)),y(u+y(Un(o,l)))}function Va(o,l,u){o=o|0,l=l|0,u=y(u);var A=$e;return A=y(kh(o,l,u)),y(A+y(r2(o,l,u)))}function n2(o){return o=o|0,n[o+24>>2]|0?o=0:y(KA(o))!=y(0)?o=1:o=y(Qh(o))!=y(0),o|0}function KA(o){o=o|0;var l=$e;if(n[o+944>>2]|0){if(l=y(h[o+44>>2]),Mt(l)|0)return l=y(h[o+40>>2]),o=l>y(0)&((Mt(l)|0)^1),y(o?l:y(0))}else l=y(0);return y(l)}function Qh(o){o=o|0;var l=$e,u=0,A=$e;do if(n[o+944>>2]|0){if(l=y(h[o+48>>2]),Mt(l)|0){if(u=s[(n[o+976>>2]|0)+2>>0]|0,!(u<<24>>24)&&(A=y(h[o+40>>2]),A<y(0)&((Mt(A)|0)^1))){l=y(-A);break}l=u<<24>>24?y(1):y(0)}}else l=y(0);while(!1);return y(l)}function by(o){o=o|0;var l=0,u=0;if(eE(o+400|0,0,540)|0,s[o+985>>0]=1,te(o),u=Mi(o)|0,u|0){l=o+948|0,o=0;do by(n[(n[l>>2]|0)+(o<<2)>>2]|0),o=o+1|0;while((o|0)!=(u|0))}}function lb(o,l,u,A,d,m,B,k,R,M){o=o|0,l=l|0,u=y(u),A=A|0,d=y(d),m=y(m),B=y(B),k=k|0,R=R|0,M=M|0;var L=0,q=$e,ae=0,Ye=0,Le=$e,Qe=$e,tt=0,Xe=$e,ct=0,He=$e,We=0,Lt=0,Gr=0,fr=0,$t=0,Rr=0,Hr=0,cr=0,Hn=0,Ro=0;Hn=I,I=I+16|0,Gr=Hn+12|0,fr=Hn+8|0,$t=Hn+4|0,Rr=Hn,cr=dr(n[o+4>>2]|0,R)|0,We=de(cr)|0,q=y(Xr(WL(l)|0,We?m:B)),Lt=io(l,2,m)|0,Hr=io(l,0,B)|0;do if(!(Mt(q)|0)&&!(Mt(We?u:d)|0)){if(L=l+504|0,!(Mt(y(h[L>>2]))|0)&&(!(s2(n[l+976>>2]|0,0)|0)||(n[l+500>>2]|0)==(n[2278]|0)))break;h[L>>2]=y($n(q,y(Va(l,cr,m))))}else ae=7;while(!1);do if((ae|0)==7){if(ct=We^1,!(ct|Lt^1)){B=y(Xr(n[l+992>>2]|0,m)),h[l+504>>2]=y($n(B,y(Va(l,2,m))));break}if(!(We|Hr^1)){B=y(Xr(n[l+996>>2]|0,B)),h[l+504>>2]=y($n(B,y(Va(l,0,m))));break}h[Gr>>2]=y(le),h[fr>>2]=y(le),n[$t>>2]=0,n[Rr>>2]=0,Xe=y(yn(l,2,m)),He=y(yn(l,0,m)),Lt?(Le=y(Xe+y(Xr(n[l+992>>2]|0,m))),h[Gr>>2]=Le,n[$t>>2]=1,Ye=1):(Ye=0,Le=y(le)),Hr?(q=y(He+y(Xr(n[l+996>>2]|0,B))),h[fr>>2]=q,n[Rr>>2]=1,L=1):(L=0,q=y(le)),ae=n[o+32>>2]|0,We&(ae|0)==2?ae=2:Mt(Le)|0&&!(Mt(u)|0)&&(h[Gr>>2]=u,n[$t>>2]=2,Ye=2,Le=u),!((ae|0)==2&ct)&&Mt(q)|0&&!(Mt(d)|0)&&(h[fr>>2]=d,n[Rr>>2]=2,L=2,q=d),Qe=y(h[l+396>>2]),tt=Mt(Qe)|0;do if(tt)ae=Ye;else{if((Ye|0)==1&ct){h[fr>>2]=y(y(Le-Xe)/Qe),n[Rr>>2]=1,L=1,ae=1;break}We&(L|0)==1?(h[Gr>>2]=y(Qe*y(q-He)),n[$t>>2]=1,L=1,ae=1):ae=Ye}while(!1);Ro=Mt(u)|0,Ye=(ss(o,l)|0)!=4,!(We|Lt|((A|0)!=1|Ro)|(Ye|(ae|0)==1))&&(h[Gr>>2]=u,n[$t>>2]=1,!tt)&&(h[fr>>2]=y(y(u-Xe)/Qe),n[Rr>>2]=1,L=1),!(Hr|ct|((k|0)!=1|(Mt(d)|0))|(Ye|(L|0)==1))&&(h[fr>>2]=d,n[Rr>>2]=1,!tt)&&(h[Gr>>2]=y(Qe*y(d-He)),n[$t>>2]=1),Cu(l,2,m,m,$t,Gr),Cu(l,0,B,m,Rr,fr),u=y(h[Gr>>2]),d=y(h[fr>>2]),xl(l,u,d,R,n[$t>>2]|0,n[Rr>>2]|0,m,B,0,3565,M)|0,B=y(h[l+908+(n[976+(cr<<2)>>2]<<2)>>2]),h[l+504>>2]=y($n(B,y(Va(l,cr,m))))}while(!1);n[l+500>>2]=n[2278],I=Hn}function qn(o,l,u,A,d){return o=o|0,l=l|0,u=y(u),A=y(A),d=y(d),A=y(Vg(o,l,u,A)),y($n(A,y(Va(o,l,d))))}function ss(o,l){return o=o|0,l=l|0,l=l+20|0,l=n[(n[l>>2]|0?l:o+16|0)>>2]|0,(l|0)==5&&Jg(n[o+4>>2]|0)|0&&(l=1),l|0}function kl(o,l){return o=o|0,l=l|0,de(l)|0&&n[o+96>>2]|0?l=4:l=n[1040+(l<<2)>>2]|0,o+60+(l<<3)|0}function Ql(o,l){return o=o|0,l=l|0,de(l)|0&&n[o+104>>2]|0?l=5:l=n[1e3+(l<<2)>>2]|0,o+60+(l<<3)|0}function Cu(o,l,u,A,d,m){switch(o=o|0,l=l|0,u=y(u),A=y(A),d=d|0,m=m|0,u=y(Xr(o+380+(n[976+(l<<2)>>2]<<3)|0,u)),u=y(u+y(yn(o,l,A))),n[d>>2]|0){case 2:case 1:{d=Mt(u)|0,A=y(h[m>>2]),h[m>>2]=d|A<u?A:u;break}case 0:{Mt(u)|0||(n[d>>2]=2,h[m>>2]=u);break}default:}}function ha(o,l){return o=o|0,l=l|0,o=o+132|0,de(l)|0&&n[(kn(o,4,948)|0)+4>>2]|0?o=1:o=(n[(kn(o,n[1040+(l<<2)>>2]|0,948)|0)+4>>2]|0)!=0,o|0}function zA(o,l,u){o=o|0,l=l|0,u=y(u);var A=0,d=0;return o=o+132|0,de(l)|0&&(A=kn(o,4,948)|0,(n[A+4>>2]|0)!=0)?d=4:(A=kn(o,n[1040+(l<<2)>>2]|0,948)|0,n[A+4>>2]|0?d=4:u=y(0)),(d|0)==4&&(u=y(Xr(A,u))),y(u)}function ZA(o,l,u){o=o|0,l=l|0,u=y(u);var A=$e;return A=y(h[o+908+(n[976+(l<<2)>>2]<<2)>>2]),A=y(A+y(K(o,l,u))),y(A+y(re(o,l,u)))}function HL(o){o=o|0;var l=0,u=0,A=0;e:do if(Jg(n[o+4>>2]|0)|0)l=0;else if((n[o+16>>2]|0)!=5)if(u=Mi(o)|0,!u)l=0;else for(l=0;;){if(A=Is(o,l)|0,!(n[A+24>>2]|0)&&(n[A+20>>2]|0)==5){l=1;break e}if(l=l+1|0,l>>>0>=u>>>0){l=0;break}}else l=1;while(!1);return l|0}function jL(o,l){o=o|0,l=l|0;var u=$e;return u=y(h[o+908+(n[976+(l<<2)>>2]<<2)>>2]),u>=y(0)&((Mt(u)|0)^1)|0}function Yg(o){o=o|0;var l=$e,u=0,A=0,d=0,m=0,B=0,k=0,R=$e;if(u=n[o+968>>2]|0,u)R=y(h[o+908>>2]),l=y(h[o+912>>2]),l=y(TX[u&0](o,R,l)),wi(o,(Mt(l)|0)^1,3573);else{m=Mi(o)|0;do if(m|0){for(u=0,d=0;;){if(A=Is(o,d)|0,n[A+940>>2]|0){B=8;break}if((n[A+24>>2]|0)!=1)if(k=(ss(o,A)|0)==5,k){u=A;break}else u=u|0?u:A;if(d=d+1|0,d>>>0>=m>>>0){B=8;break}}if((B|0)==8&&!u)break;return l=y(Yg(u)),y(l+y(h[u+404>>2]))}while(!1);l=y(h[o+912>>2])}return y(l)}function Vg(o,l,u,A){o=o|0,l=l|0,u=y(u),A=y(A);var d=$e,m=0;return Jg(l)|0?(l=1,m=3):de(l)|0?(l=0,m=3):(A=y(le),d=y(le)),(m|0)==3&&(d=y(Xr(o+364+(l<<3)|0,A)),A=y(Xr(o+380+(l<<3)|0,A))),m=A<u&(A>=y(0)&((Mt(A)|0)^1)),u=m?A:u,m=d>=y(0)&((Mt(d)|0)^1)&u<d,y(m?d:u)}function qL(o,l,u,A,d,m,B){o=o|0,l=l|0,u=y(u),A=A|0,d=y(d),m=m|0,B=B|0;var k=$e,R=$e,M=0,L=0,q=$e,ae=$e,Ye=$e,Le=0,Qe=0,tt=0,Xe=0,ct=$e,He=0;tt=dr(n[o+4>>2]|0,m)|0,Le=Py(tt,m)|0,Qe=de(tt)|0,q=y(yn(l,2,u)),ae=y(yn(l,0,u)),io(l,2,u)|0?k=y(q+y(Xr(n[l+992>>2]|0,u))):ha(l,2)|0&&xy(l,2)|0?(k=y(h[o+908>>2]),R=y(vr(o,2)),R=y(k-y(R+y(Un(o,2)))),k=y(zA(l,2,u)),k=y(qn(l,2,y(R-y(k+y(Rh(l,2,u)))),u,u))):k=y(le),io(l,0,d)|0?R=y(ae+y(Xr(n[l+996>>2]|0,d))):ha(l,0)|0&&xy(l,0)|0?(R=y(h[o+912>>2]),ct=y(vr(o,0)),ct=y(R-y(ct+y(Un(o,0)))),R=y(zA(l,0,d)),R=y(qn(l,0,y(ct-y(R+y(Rh(l,0,d)))),d,u))):R=y(le),M=Mt(k)|0,L=Mt(R)|0;do if(M^L&&(Ye=y(h[l+396>>2]),!(Mt(Ye)|0)))if(M){k=y(q+y(y(R-ae)*Ye));break}else{ct=y(ae+y(y(k-q)/Ye)),R=L?ct:R;break}while(!1);L=Mt(k)|0,M=Mt(R)|0,L|M&&(He=(L^1)&1,A=u>y(0)&((A|0)!=0&L),k=Qe?k:A?u:k,xl(l,k,R,m,Qe?He:A?2:He,L&(M^1)&1,k,R,0,3623,B)|0,k=y(h[l+908>>2]),k=y(k+y(yn(l,2,u))),R=y(h[l+912>>2]),R=y(R+y(yn(l,0,u)))),xl(l,k,R,m,1,1,k,R,1,3635,B)|0,xy(l,tt)|0&&!(ha(l,tt)|0)?(He=n[976+(tt<<2)>>2]|0,ct=y(h[o+908+(He<<2)>>2]),ct=y(ct-y(h[l+908+(He<<2)>>2])),ct=y(ct-y(Un(o,tt))),ct=y(ct-y(re(l,tt,u))),ct=y(ct-y(Rh(l,tt,Qe?u:d))),h[l+400+(n[1040+(tt<<2)>>2]<<2)>>2]=ct):Xe=21;do if((Xe|0)==21){if(!(ha(l,tt)|0)&&(n[o+8>>2]|0)==1){He=n[976+(tt<<2)>>2]|0,ct=y(h[o+908+(He<<2)>>2]),ct=y(y(ct-y(h[l+908+(He<<2)>>2]))*y(.5)),h[l+400+(n[1040+(tt<<2)>>2]<<2)>>2]=ct;break}!(ha(l,tt)|0)&&(n[o+8>>2]|0)==2&&(He=n[976+(tt<<2)>>2]|0,ct=y(h[o+908+(He<<2)>>2]),ct=y(ct-y(h[l+908+(He<<2)>>2])),h[l+400+(n[1040+(tt<<2)>>2]<<2)>>2]=ct)}while(!1);xy(l,Le)|0&&!(ha(l,Le)|0)?(He=n[976+(Le<<2)>>2]|0,ct=y(h[o+908+(He<<2)>>2]),ct=y(ct-y(h[l+908+(He<<2)>>2])),ct=y(ct-y(Un(o,Le))),ct=y(ct-y(re(l,Le,u))),ct=y(ct-y(Rh(l,Le,Qe?d:u))),h[l+400+(n[1040+(Le<<2)>>2]<<2)>>2]=ct):Xe=30;do if((Xe|0)==30&&!(ha(l,Le)|0)){if((ss(o,l)|0)==2){He=n[976+(Le<<2)>>2]|0,ct=y(h[o+908+(He<<2)>>2]),ct=y(y(ct-y(h[l+908+(He<<2)>>2]))*y(.5)),h[l+400+(n[1040+(Le<<2)>>2]<<2)>>2]=ct;break}He=(ss(o,l)|0)==3,He^(n[o+28>>2]|0)==2&&(He=n[976+(Le<<2)>>2]|0,ct=y(h[o+908+(He<<2)>>2]),ct=y(ct-y(h[l+908+(He<<2)>>2])),h[l+400+(n[1040+(Le<<2)>>2]<<2)>>2]=ct)}while(!1)}function i2(o,l,u){o=o|0,l=l|0,u=u|0;var A=$e,d=0;d=n[976+(u<<2)>>2]|0,A=y(h[l+908+(d<<2)>>2]),A=y(y(h[o+908+(d<<2)>>2])-A),A=y(A-y(h[l+400+(n[1040+(u<<2)>>2]<<2)>>2])),h[l+400+(n[1e3+(u<<2)>>2]<<2)>>2]=A}function Jg(o){return o=o|0,(o|1|0)==1|0}function WL(o){o=o|0;var l=$e;switch(n[o+56>>2]|0){case 0:case 3:{l=y(h[o+40>>2]),l>y(0)&((Mt(l)|0)^1)?o=s[(n[o+976>>2]|0)+2>>0]|0?1056:992:o=1056;break}default:o=o+52|0}return o|0}function s2(o,l){return o=o|0,l=l|0,(s[o+l>>0]|0)!=0|0}function xy(o,l){return o=o|0,l=l|0,o=o+132|0,de(l)|0&&n[(kn(o,5,948)|0)+4>>2]|0?o=1:o=(n[(kn(o,n[1e3+(l<<2)>>2]|0,948)|0)+4>>2]|0)!=0,o|0}function Rh(o,l,u){o=o|0,l=l|0,u=y(u);var A=0,d=0;return o=o+132|0,de(l)|0&&(A=kn(o,5,948)|0,(n[A+4>>2]|0)!=0)?d=4:(A=kn(o,n[1e3+(l<<2)>>2]|0,948)|0,n[A+4>>2]|0?d=4:u=y(0)),(d|0)==4&&(u=y(Xr(A,u))),y(u)}function ub(o,l,u){return o=o|0,l=l|0,u=y(u),ha(o,l)|0?u=y(zA(o,l,u)):u=y(-y(Rh(o,l,u))),y(u)}function fb(o){return o=y(o),h[S>>2]=o,n[S>>2]|0|0}function ky(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>1073741823)Nt();else{d=Kt(l<<2)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<2)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<2)}function Ab(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>2)<<2)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function Qy(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-4-l|0)>>>2)<<2)),o=n[o>>2]|0,o|0&&It(o)}function pb(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0;if(B=o+4|0,k=n[B>>2]|0,d=k-A|0,m=d>>2,o=l+(m<<2)|0,o>>>0<u>>>0){A=k;do n[A>>2]=n[o>>2],o=o+4|0,A=(n[B>>2]|0)+4|0,n[B>>2]=A;while(o>>>0<u>>>0)}m|0&&Q2(k+(0-m<<2)|0,l|0,d|0)|0}function hb(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0;return k=l+4|0,R=n[k>>2]|0,d=n[o>>2]|0,B=u,m=B-d|0,A=R+(0-(m>>2)<<2)|0,n[k>>2]=A,(m|0)>0&&Qr(A|0,d|0,m|0)|0,d=o+4|0,m=l+8|0,A=(n[d>>2]|0)-B|0,(A|0)>0&&(Qr(n[m>>2]|0,u|0,A|0)|0,n[m>>2]=(n[m>>2]|0)+(A>>>2<<2)),B=n[o>>2]|0,n[o>>2]=n[k>>2],n[k>>2]=B,B=n[d>>2]|0,n[d>>2]=n[m>>2],n[m>>2]=B,B=o+8|0,u=l+12|0,o=n[B>>2]|0,n[B>>2]=n[u>>2],n[u>>2]=o,n[l>>2]=n[k>>2],R|0}function o2(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;if(B=n[l>>2]|0,m=n[u>>2]|0,(B|0)!=(m|0)){d=o+8|0,u=((m+-4-B|0)>>>2)+1|0,o=B,A=n[d>>2]|0;do n[A>>2]=n[o>>2],A=(n[d>>2]|0)+4|0,n[d>>2]=A,o=o+4|0;while((o|0)!=(m|0));n[l>>2]=B+(u<<2)}}function a2(){ua()}function gb(){var o=0;return o=Kt(4)|0,l2(o),o|0}function l2(o){o=o|0,n[o>>2]=Ac()|0}function db(o){o=o|0,o|0&&(Kg(o),It(o))}function Kg(o){o=o|0,st(n[o>>2]|0)}function YL(o,l,u){o=o|0,l=l|0,u=u|0,pc(n[o>>2]|0,l,u)}function Ry(o,l){o=o|0,l=y(l),Dh(n[o>>2]|0,l)}function Ty(o,l){return o=o|0,l=l|0,s2(n[o>>2]|0,l)|0}function Fy(){var o=0;return o=Kt(8)|0,zg(o,0),o|0}function zg(o,l){o=o|0,l=l|0,l?l=fa(n[l>>2]|0)|0:l=rs()|0,n[o>>2]=l,n[o+4>>2]=0,Rn(l,o)}function Ny(o){o=o|0;var l=0;return l=Kt(8)|0,zg(l,o),l|0}function Zg(o){o=o|0,o|0&&(Oy(o),It(o))}function Oy(o){o=o|0;var l=0;uc(n[o>>2]|0),l=o+4|0,o=n[l>>2]|0,n[l>>2]=0,o|0&&(Sf(o),It(o))}function Sf(o){o=o|0,Df(o)}function Df(o){o=o|0,o=n[o>>2]|0,o|0&&Na(o|0)}function c2(o){return o=o|0,Ga(o)|0}function u2(o){o=o|0;var l=0,u=0;u=o+4|0,l=n[u>>2]|0,n[u>>2]=0,l|0&&(Sf(l),It(l)),fc(n[o>>2]|0)}function Ly(o,l){o=o|0,l=l|0,An(n[o>>2]|0,n[l>>2]|0)}function VL(o,l){o=o|0,l=l|0,wh(n[o>>2]|0,l)}function JL(o,l,u){o=o|0,l=l|0,u=+u,Cy(n[o>>2]|0,l,y(u))}function My(o,l,u){o=o|0,l=l|0,u=+u,wy(n[o>>2]|0,l,y(u))}function f2(o,l){o=o|0,l=l|0,Eh(n[o>>2]|0,l)}function A2(o,l){o=o|0,l=l|0,So(n[o>>2]|0,l)}function xr(o,l){o=o|0,l=l|0,Ch(n[o>>2]|0,l)}function so(o,l){o=o|0,l=l|0,my(n[o>>2]|0,l)}function zi(o,l){o=o|0,l=l|0,Ng(n[o>>2]|0,l)}function Ns(o,l){o=o|0,l=l|0,vo(n[o>>2]|0,l)}function XA(o,l,u){o=o|0,l=l|0,u=+u,HA(n[o>>2]|0,l,y(u))}function p2(o,l,u){o=o|0,l=l|0,u=+u,Y(n[o>>2]|0,l,y(u))}function ws(o,l){o=o|0,l=l|0,jA(n[o>>2]|0,l)}function Uy(o,l){o=o|0,l=l|0,Ey(n[o>>2]|0,l)}function Th(o,l){o=o|0,l=l|0,Do(n[o>>2]|0,l)}function Xg(o,l){o=o|0,l=+l,Bh(n[o>>2]|0,y(l))}function Fh(o,l){o=o|0,l=+l,Pl(n[o>>2]|0,y(l))}function h2(o,l){o=o|0,l=+l,Iy(n[o>>2]|0,y(l))}function g2(o,l){o=o|0,l=+l,Lg(n[o>>2]|0,y(l))}function d2(o,l){o=o|0,l=+l,Dl(n[o>>2]|0,y(l))}function m2(o,l){o=o|0,l=+l,Mg(n[o>>2]|0,y(l))}function Pf(o,l){o=o|0,l=+l,e2(n[o>>2]|0,y(l))}function sr(o){o=o|0,vh(n[o>>2]|0)}function _y(o,l){o=o|0,l=+l,Ki(n[o>>2]|0,y(l))}function y2(o,l){o=o|0,l=+l,yf(n[o>>2]|0,y(l))}function hc(o){o=o|0,qa(n[o>>2]|0)}function bf(o,l){o=o|0,l=+l,du(n[o>>2]|0,y(l))}function $g(o,l){o=o|0,l=+l,Ef(n[o>>2]|0,y(l))}function ed(o,l){o=o|0,l=+l,di(n[o>>2]|0,y(l))}function E2(o,l){o=o|0,l=+l,GA(n[o>>2]|0,y(l))}function I2(o,l){o=o|0,l=+l,Aa(n[o>>2]|0,y(l))}function wu(o,l){o=o|0,l=+l,Ya(n[o>>2]|0,y(l))}function td(o,l){o=o|0,l=+l,Sh(n[o>>2]|0,y(l))}function C2(o,l){o=o|0,l=+l,Hg(n[o>>2]|0,y(l))}function Hy(o,l){o=o|0,l=+l,qA(n[o>>2]|0,y(l))}function Bu(o,l,u){o=o|0,l=l|0,u=+u,gu(n[o>>2]|0,l,y(u))}function jy(o,l,u){o=o|0,l=l|0,u=+u,Po(n[o>>2]|0,l,y(u))}function rd(o,l,u){o=o|0,l=l|0,u=+u,mf(n[o>>2]|0,l,y(u))}function nd(o){return o=o|0,Fg(n[o>>2]|0)|0}function ko(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0;A=I,I=I+16|0,d=A,_A(d,n[l>>2]|0,u),Bs(o,d),I=A}function Bs(o,l){o=o|0,l=l|0,Rl(o,n[l+4>>2]|0,+y(h[l>>2]))}function Rl(o,l,u){o=o|0,l=l|0,u=+u,n[o>>2]=l,E[o+8>>3]=u}function Gy(o){return o=o|0,$1(n[o>>2]|0)|0}function ga(o){return o=o|0,Ih(n[o>>2]|0)|0}function mb(o){return o=o|0,hu(n[o>>2]|0)|0}function Nh(o){return o=o|0,X1(n[o>>2]|0)|0}function w2(o){return o=o|0,Og(n[o>>2]|0)|0}function KL(o){return o=o|0,yy(n[o>>2]|0)|0}function yb(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0;A=I,I=I+16|0,d=A,xt(d,n[l>>2]|0,u),Bs(o,d),I=A}function Eb(o){return o=o|0,df(n[o>>2]|0)|0}function qy(o){return o=o|0,Sl(n[o>>2]|0)|0}function B2(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u,UA(A,n[l>>2]|0),Bs(o,A),I=u}function Oh(o){return o=o|0,+ +y(li(n[o>>2]|0))}function Ib(o){return o=o|0,+ +y(Gi(n[o>>2]|0))}function Cb(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u,ur(A,n[l>>2]|0),Bs(o,A),I=u}function id(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u,Ug(A,n[l>>2]|0),Bs(o,A),I=u}function zL(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u,wt(A,n[l>>2]|0),Bs(o,A),I=u}function ZL(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u,Wa(A,n[l>>2]|0),Bs(o,A),I=u}function wb(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u,_g(A,n[l>>2]|0),Bs(o,A),I=u}function Bb(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u,vy(A,n[l>>2]|0),Bs(o,A),I=u}function $A(o){return o=o|0,+ +y(jg(n[o>>2]|0))}function XL(o,l){return o=o|0,l=l|0,+ +y(By(n[o>>2]|0,l))}function $L(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0;A=I,I=I+16|0,d=A,yt(d,n[l>>2]|0,u),Bs(o,d),I=A}function vu(o,l,u){o=o|0,l=l|0,u=u|0,lr(n[o>>2]|0,n[l>>2]|0,u)}function eM(o,l){o=o|0,l=l|0,gf(n[o>>2]|0,n[l>>2]|0)}function vb(o){return o=o|0,Mi(n[o>>2]|0)|0}function tM(o){return o=o|0,o=Et(n[o>>2]|0)|0,o?o=c2(o)|0:o=0,o|0}function Sb(o,l){return o=o|0,l=l|0,o=Is(n[o>>2]|0,l)|0,o?o=c2(o)|0:o=0,o|0}function xf(o,l){o=o|0,l=l|0;var u=0,A=0;A=Kt(4)|0,Db(A,l),u=o+4|0,l=n[u>>2]|0,n[u>>2]=A,l|0&&(Sf(l),It(l)),St(n[o>>2]|0,1)}function Db(o,l){o=o|0,l=l|0,sM(o,l)}function rM(o,l,u,A,d,m){o=o|0,l=l|0,u=y(u),A=A|0,d=y(d),m=m|0;var B=0,k=0;B=I,I=I+16|0,k=B,Pb(k,Ga(l)|0,+u,A,+d,m),h[o>>2]=y(+E[k>>3]),h[o+4>>2]=y(+E[k+8>>3]),I=B}function Pb(o,l,u,A,d,m){o=o|0,l=l|0,u=+u,A=A|0,d=+d,m=m|0;var B=0,k=0,R=0,M=0,L=0;B=I,I=I+32|0,L=B+8|0,M=B+20|0,R=B,k=B+16|0,E[L>>3]=u,n[M>>2]=A,E[R>>3]=d,n[k>>2]=m,Wy(o,n[l+4>>2]|0,L,M,R,k),I=B}function Wy(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0;var B=0,k=0;B=I,I=I+16|0,k=B,Fl(k),l=Os(l)|0,bb(o,l,+E[u>>3],n[A>>2]|0,+E[d>>3],n[m>>2]|0),Nl(k),I=B}function Os(o){return o=o|0,n[o>>2]|0}function bb(o,l,u,A,d,m){o=o|0,l=l|0,u=+u,A=A|0,d=+d,m=m|0;var B=0;B=da(v2()|0)|0,u=+Ja(u),A=Yy(A)|0,d=+Ja(d),nM(o,Kn(0,B|0,l|0,+u,A|0,+d,Yy(m)|0)|0)}function v2(){var o=0;return s[7608]|0||(D2(9120),o=7608,n[o>>2]=1,n[o+4>>2]=0),9120}function da(o){return o=o|0,n[o+8>>2]|0}function Ja(o){return o=+o,+ +kf(o)}function Yy(o){return o=o|0,sd(o)|0}function nM(o,l){o=o|0,l=l|0;var u=0,A=0,d=0;d=I,I=I+32|0,u=d,A=l,A&1?(Ka(u,0),Me(A|0,u|0)|0,S2(o,u),iM(u)):(n[o>>2]=n[l>>2],n[o+4>>2]=n[l+4>>2],n[o+8>>2]=n[l+8>>2],n[o+12>>2]=n[l+12>>2]),I=d}function Ka(o,l){o=o|0,l=l|0,Su(o,l),n[o+8>>2]=0,s[o+24>>0]=0}function S2(o,l){o=o|0,l=l|0,l=l+8|0,n[o>>2]=n[l>>2],n[o+4>>2]=n[l+4>>2],n[o+8>>2]=n[l+8>>2],n[o+12>>2]=n[l+12>>2]}function iM(o){o=o|0,s[o+24>>0]=0}function Su(o,l){o=o|0,l=l|0,n[o>>2]=l}function sd(o){return o=o|0,o|0}function kf(o){return o=+o,+o}function D2(o){o=o|0,Qo(o,P2()|0,4)}function P2(){return 1064}function Qo(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u,n[o+8>>2]=ji(l|0,u+1|0)|0}function sM(o,l){o=o|0,l=l|0,l=n[l>>2]|0,n[o>>2]=l,au(l|0)}function xb(o){o=o|0;var l=0,u=0;u=o+4|0,l=n[u>>2]|0,n[u>>2]=0,l|0&&(Sf(l),It(l)),St(n[o>>2]|0,0)}function kb(o){o=o|0,Pt(n[o>>2]|0)}function Vy(o){return o=o|0,tr(n[o>>2]|0)|0}function oM(o,l,u,A){o=o|0,l=+l,u=+u,A=A|0,YA(n[o>>2]|0,y(l),y(u),A)}function aM(o){return o=o|0,+ +y(mu(n[o>>2]|0))}function v(o){return o=o|0,+ +y(If(n[o>>2]|0))}function D(o){return o=o|0,+ +y(yu(n[o>>2]|0))}function Q(o){return o=o|0,+ +y(Ts(n[o>>2]|0))}function H(o){return o=o|0,+ +y(Eu(n[o>>2]|0))}function V(o){return o=o|0,+ +y(Gn(n[o>>2]|0))}function ne(o,l){o=o|0,l=l|0,E[o>>3]=+y(mu(n[l>>2]|0)),E[o+8>>3]=+y(If(n[l>>2]|0)),E[o+16>>3]=+y(yu(n[l>>2]|0)),E[o+24>>3]=+y(Ts(n[l>>2]|0)),E[o+32>>3]=+y(Eu(n[l>>2]|0)),E[o+40>>3]=+y(Gn(n[l>>2]|0))}function Se(o,l){return o=o|0,l=l|0,+ +y(ns(n[o>>2]|0,l))}function _e(o,l){return o=o|0,l=l|0,+ +y(bi(n[o>>2]|0,l))}function pt(o,l){return o=o|0,l=l|0,+ +y(WA(n[o>>2]|0,l))}function Wt(){return Qn()|0}function Sr(){Lr(),Xt(),zn(),yi(),za(),et()}function Lr(){u4e(11713,4938,1)}function Xt(){x_e(10448)}function zn(){u_e(10408)}function yi(){TUe(10324)}function za(){HLe(10096)}function et(){qe(9132)}function qe(o){o=o|0;var l=0,u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0,Ye=0,Le=0,Qe=0,tt=0,Xe=0,ct=0,He=0,We=0,Lt=0,Gr=0,fr=0,$t=0,Rr=0,Hr=0,cr=0,Hn=0,Ro=0,To=0,Fo=0,Xa=0,Wh=0,Yh=0,gc=0,Vh=0,Tf=0,Ff=0,Jh=0,Kh=0,zh=0,on=0,dc=0,Zh=0,bu=0,Xh=0,$h=0,Nf=0,Of=0,xu=0,oo=0,Ll=0,ma=0,mc=0,op=0,ap=0,Lf=0,lp=0,cp=0,ao=0,Ms=0,yc=0,Wn=0,up=0,No=0,ku=0,Oo=0,Qu=0,fp=0,Ap=0,Ru=0,lo=0,Ec=0,pp=0,hp=0,gp=0,Nr=0,ui=0,Us=0,Lo=0,co=0,Mr=0,Ar=0,Ic=0;l=I,I=I+672|0,u=l+656|0,Ic=l+648|0,Ar=l+640|0,Mr=l+632|0,co=l+624|0,Lo=l+616|0,Us=l+608|0,ui=l+600|0,Nr=l+592|0,gp=l+584|0,hp=l+576|0,pp=l+568|0,Ec=l+560|0,lo=l+552|0,Ru=l+544|0,Ap=l+536|0,fp=l+528|0,Qu=l+520|0,Oo=l+512|0,ku=l+504|0,No=l+496|0,up=l+488|0,Wn=l+480|0,yc=l+472|0,Ms=l+464|0,ao=l+456|0,cp=l+448|0,lp=l+440|0,Lf=l+432|0,ap=l+424|0,op=l+416|0,mc=l+408|0,ma=l+400|0,Ll=l+392|0,oo=l+384|0,xu=l+376|0,Of=l+368|0,Nf=l+360|0,$h=l+352|0,Xh=l+344|0,bu=l+336|0,Zh=l+328|0,dc=l+320|0,on=l+312|0,zh=l+304|0,Kh=l+296|0,Jh=l+288|0,Ff=l+280|0,Tf=l+272|0,Vh=l+264|0,gc=l+256|0,Yh=l+248|0,Wh=l+240|0,Xa=l+232|0,Fo=l+224|0,To=l+216|0,Ro=l+208|0,Hn=l+200|0,cr=l+192|0,Hr=l+184|0,Rr=l+176|0,$t=l+168|0,fr=l+160|0,Gr=l+152|0,Lt=l+144|0,We=l+136|0,He=l+128|0,ct=l+120|0,Xe=l+112|0,tt=l+104|0,Qe=l+96|0,Le=l+88|0,Ye=l+80|0,ae=l+72|0,q=l+64|0,L=l+56|0,M=l+48|0,R=l+40|0,k=l+32|0,B=l+24|0,m=l+16|0,d=l+8|0,A=l,gt(o,3646),Zt(o,3651,2)|0,Dr(o,3665,2)|0,Xn(o,3682,18)|0,n[Ic>>2]=19,n[Ic+4>>2]=0,n[u>>2]=n[Ic>>2],n[u+4>>2]=n[Ic+4>>2],kr(o,3690,u)|0,n[Ar>>2]=1,n[Ar+4>>2]=0,n[u>>2]=n[Ar>>2],n[u+4>>2]=n[Ar+4>>2],Tn(o,3696,u)|0,n[Mr>>2]=2,n[Mr+4>>2]=0,n[u>>2]=n[Mr>>2],n[u+4>>2]=n[Mr+4>>2],_n(o,3706,u)|0,n[co>>2]=1,n[co+4>>2]=0,n[u>>2]=n[co>>2],n[u+4>>2]=n[co+4>>2],zr(o,3722,u)|0,n[Lo>>2]=2,n[Lo+4>>2]=0,n[u>>2]=n[Lo>>2],n[u+4>>2]=n[Lo+4>>2],zr(o,3734,u)|0,n[Us>>2]=3,n[Us+4>>2]=0,n[u>>2]=n[Us>>2],n[u+4>>2]=n[Us+4>>2],_n(o,3753,u)|0,n[ui>>2]=4,n[ui+4>>2]=0,n[u>>2]=n[ui>>2],n[u+4>>2]=n[ui+4>>2],_n(o,3769,u)|0,n[Nr>>2]=5,n[Nr+4>>2]=0,n[u>>2]=n[Nr>>2],n[u+4>>2]=n[Nr+4>>2],_n(o,3783,u)|0,n[gp>>2]=6,n[gp+4>>2]=0,n[u>>2]=n[gp>>2],n[u+4>>2]=n[gp+4>>2],_n(o,3796,u)|0,n[hp>>2]=7,n[hp+4>>2]=0,n[u>>2]=n[hp>>2],n[u+4>>2]=n[hp+4>>2],_n(o,3813,u)|0,n[pp>>2]=8,n[pp+4>>2]=0,n[u>>2]=n[pp>>2],n[u+4>>2]=n[pp+4>>2],_n(o,3825,u)|0,n[Ec>>2]=3,n[Ec+4>>2]=0,n[u>>2]=n[Ec>>2],n[u+4>>2]=n[Ec+4>>2],zr(o,3843,u)|0,n[lo>>2]=4,n[lo+4>>2]=0,n[u>>2]=n[lo>>2],n[u+4>>2]=n[lo+4>>2],zr(o,3853,u)|0,n[Ru>>2]=9,n[Ru+4>>2]=0,n[u>>2]=n[Ru>>2],n[u+4>>2]=n[Ru+4>>2],_n(o,3870,u)|0,n[Ap>>2]=10,n[Ap+4>>2]=0,n[u>>2]=n[Ap>>2],n[u+4>>2]=n[Ap+4>>2],_n(o,3884,u)|0,n[fp>>2]=11,n[fp+4>>2]=0,n[u>>2]=n[fp>>2],n[u+4>>2]=n[fp+4>>2],_n(o,3896,u)|0,n[Qu>>2]=1,n[Qu+4>>2]=0,n[u>>2]=n[Qu>>2],n[u+4>>2]=n[Qu+4>>2],ci(o,3907,u)|0,n[Oo>>2]=2,n[Oo+4>>2]=0,n[u>>2]=n[Oo>>2],n[u+4>>2]=n[Oo+4>>2],ci(o,3915,u)|0,n[ku>>2]=3,n[ku+4>>2]=0,n[u>>2]=n[ku>>2],n[u+4>>2]=n[ku+4>>2],ci(o,3928,u)|0,n[No>>2]=4,n[No+4>>2]=0,n[u>>2]=n[No>>2],n[u+4>>2]=n[No+4>>2],ci(o,3948,u)|0,n[up>>2]=5,n[up+4>>2]=0,n[u>>2]=n[up>>2],n[u+4>>2]=n[up+4>>2],ci(o,3960,u)|0,n[Wn>>2]=6,n[Wn+4>>2]=0,n[u>>2]=n[Wn>>2],n[u+4>>2]=n[Wn+4>>2],ci(o,3974,u)|0,n[yc>>2]=7,n[yc+4>>2]=0,n[u>>2]=n[yc>>2],n[u+4>>2]=n[yc+4>>2],ci(o,3983,u)|0,n[Ms>>2]=20,n[Ms+4>>2]=0,n[u>>2]=n[Ms>>2],n[u+4>>2]=n[Ms+4>>2],kr(o,3999,u)|0,n[ao>>2]=8,n[ao+4>>2]=0,n[u>>2]=n[ao>>2],n[u+4>>2]=n[ao+4>>2],ci(o,4012,u)|0,n[cp>>2]=9,n[cp+4>>2]=0,n[u>>2]=n[cp>>2],n[u+4>>2]=n[cp+4>>2],ci(o,4022,u)|0,n[lp>>2]=21,n[lp+4>>2]=0,n[u>>2]=n[lp>>2],n[u+4>>2]=n[lp+4>>2],kr(o,4039,u)|0,n[Lf>>2]=10,n[Lf+4>>2]=0,n[u>>2]=n[Lf>>2],n[u+4>>2]=n[Lf+4>>2],ci(o,4053,u)|0,n[ap>>2]=11,n[ap+4>>2]=0,n[u>>2]=n[ap>>2],n[u+4>>2]=n[ap+4>>2],ci(o,4065,u)|0,n[op>>2]=12,n[op+4>>2]=0,n[u>>2]=n[op>>2],n[u+4>>2]=n[op+4>>2],ci(o,4084,u)|0,n[mc>>2]=13,n[mc+4>>2]=0,n[u>>2]=n[mc>>2],n[u+4>>2]=n[mc+4>>2],ci(o,4097,u)|0,n[ma>>2]=14,n[ma+4>>2]=0,n[u>>2]=n[ma>>2],n[u+4>>2]=n[ma+4>>2],ci(o,4117,u)|0,n[Ll>>2]=15,n[Ll+4>>2]=0,n[u>>2]=n[Ll>>2],n[u+4>>2]=n[Ll+4>>2],ci(o,4129,u)|0,n[oo>>2]=16,n[oo+4>>2]=0,n[u>>2]=n[oo>>2],n[u+4>>2]=n[oo+4>>2],ci(o,4148,u)|0,n[xu>>2]=17,n[xu+4>>2]=0,n[u>>2]=n[xu>>2],n[u+4>>2]=n[xu+4>>2],ci(o,4161,u)|0,n[Of>>2]=18,n[Of+4>>2]=0,n[u>>2]=n[Of>>2],n[u+4>>2]=n[Of+4>>2],ci(o,4181,u)|0,n[Nf>>2]=5,n[Nf+4>>2]=0,n[u>>2]=n[Nf>>2],n[u+4>>2]=n[Nf+4>>2],zr(o,4196,u)|0,n[$h>>2]=6,n[$h+4>>2]=0,n[u>>2]=n[$h>>2],n[u+4>>2]=n[$h+4>>2],zr(o,4206,u)|0,n[Xh>>2]=7,n[Xh+4>>2]=0,n[u>>2]=n[Xh>>2],n[u+4>>2]=n[Xh+4>>2],zr(o,4217,u)|0,n[bu>>2]=3,n[bu+4>>2]=0,n[u>>2]=n[bu>>2],n[u+4>>2]=n[bu+4>>2],Du(o,4235,u)|0,n[Zh>>2]=1,n[Zh+4>>2]=0,n[u>>2]=n[Zh>>2],n[u+4>>2]=n[Zh+4>>2],lM(o,4251,u)|0,n[dc>>2]=4,n[dc+4>>2]=0,n[u>>2]=n[dc>>2],n[u+4>>2]=n[dc+4>>2],Du(o,4263,u)|0,n[on>>2]=5,n[on+4>>2]=0,n[u>>2]=n[on>>2],n[u+4>>2]=n[on+4>>2],Du(o,4279,u)|0,n[zh>>2]=6,n[zh+4>>2]=0,n[u>>2]=n[zh>>2],n[u+4>>2]=n[zh+4>>2],Du(o,4293,u)|0,n[Kh>>2]=7,n[Kh+4>>2]=0,n[u>>2]=n[Kh>>2],n[u+4>>2]=n[Kh+4>>2],Du(o,4306,u)|0,n[Jh>>2]=8,n[Jh+4>>2]=0,n[u>>2]=n[Jh>>2],n[u+4>>2]=n[Jh+4>>2],Du(o,4323,u)|0,n[Ff>>2]=9,n[Ff+4>>2]=0,n[u>>2]=n[Ff>>2],n[u+4>>2]=n[Ff+4>>2],Du(o,4335,u)|0,n[Tf>>2]=2,n[Tf+4>>2]=0,n[u>>2]=n[Tf>>2],n[u+4>>2]=n[Tf+4>>2],lM(o,4353,u)|0,n[Vh>>2]=12,n[Vh+4>>2]=0,n[u>>2]=n[Vh>>2],n[u+4>>2]=n[Vh+4>>2],od(o,4363,u)|0,n[gc>>2]=1,n[gc+4>>2]=0,n[u>>2]=n[gc>>2],n[u+4>>2]=n[gc+4>>2],ep(o,4376,u)|0,n[Yh>>2]=2,n[Yh+4>>2]=0,n[u>>2]=n[Yh>>2],n[u+4>>2]=n[Yh+4>>2],ep(o,4388,u)|0,n[Wh>>2]=13,n[Wh+4>>2]=0,n[u>>2]=n[Wh>>2],n[u+4>>2]=n[Wh+4>>2],od(o,4402,u)|0,n[Xa>>2]=14,n[Xa+4>>2]=0,n[u>>2]=n[Xa>>2],n[u+4>>2]=n[Xa+4>>2],od(o,4411,u)|0,n[Fo>>2]=15,n[Fo+4>>2]=0,n[u>>2]=n[Fo>>2],n[u+4>>2]=n[Fo+4>>2],od(o,4421,u)|0,n[To>>2]=16,n[To+4>>2]=0,n[u>>2]=n[To>>2],n[u+4>>2]=n[To+4>>2],od(o,4433,u)|0,n[Ro>>2]=17,n[Ro+4>>2]=0,n[u>>2]=n[Ro>>2],n[u+4>>2]=n[Ro+4>>2],od(o,4446,u)|0,n[Hn>>2]=18,n[Hn+4>>2]=0,n[u>>2]=n[Hn>>2],n[u+4>>2]=n[Hn+4>>2],od(o,4458,u)|0,n[cr>>2]=3,n[cr+4>>2]=0,n[u>>2]=n[cr>>2],n[u+4>>2]=n[cr+4>>2],ep(o,4471,u)|0,n[Hr>>2]=1,n[Hr+4>>2]=0,n[u>>2]=n[Hr>>2],n[u+4>>2]=n[Hr+4>>2],Qb(o,4486,u)|0,n[Rr>>2]=10,n[Rr+4>>2]=0,n[u>>2]=n[Rr>>2],n[u+4>>2]=n[Rr+4>>2],Du(o,4496,u)|0,n[$t>>2]=11,n[$t+4>>2]=0,n[u>>2]=n[$t>>2],n[u+4>>2]=n[$t+4>>2],Du(o,4508,u)|0,n[fr>>2]=3,n[fr+4>>2]=0,n[u>>2]=n[fr>>2],n[u+4>>2]=n[fr+4>>2],lM(o,4519,u)|0,n[Gr>>2]=4,n[Gr+4>>2]=0,n[u>>2]=n[Gr>>2],n[u+4>>2]=n[Gr+4>>2],yke(o,4530,u)|0,n[Lt>>2]=19,n[Lt+4>>2]=0,n[u>>2]=n[Lt>>2],n[u+4>>2]=n[Lt+4>>2],Eke(o,4542,u)|0,n[We>>2]=12,n[We+4>>2]=0,n[u>>2]=n[We>>2],n[u+4>>2]=n[We+4>>2],Ike(o,4554,u)|0,n[He>>2]=13,n[He+4>>2]=0,n[u>>2]=n[He>>2],n[u+4>>2]=n[He+4>>2],Cke(o,4568,u)|0,n[ct>>2]=2,n[ct+4>>2]=0,n[u>>2]=n[ct>>2],n[u+4>>2]=n[ct+4>>2],wke(o,4578,u)|0,n[Xe>>2]=20,n[Xe+4>>2]=0,n[u>>2]=n[Xe>>2],n[u+4>>2]=n[Xe+4>>2],Bke(o,4587,u)|0,n[tt>>2]=22,n[tt+4>>2]=0,n[u>>2]=n[tt>>2],n[u+4>>2]=n[tt+4>>2],kr(o,4602,u)|0,n[Qe>>2]=23,n[Qe+4>>2]=0,n[u>>2]=n[Qe>>2],n[u+4>>2]=n[Qe+4>>2],kr(o,4619,u)|0,n[Le>>2]=14,n[Le+4>>2]=0,n[u>>2]=n[Le>>2],n[u+4>>2]=n[Le+4>>2],vke(o,4629,u)|0,n[Ye>>2]=1,n[Ye+4>>2]=0,n[u>>2]=n[Ye>>2],n[u+4>>2]=n[Ye+4>>2],Ske(o,4637,u)|0,n[ae>>2]=4,n[ae+4>>2]=0,n[u>>2]=n[ae>>2],n[u+4>>2]=n[ae+4>>2],ep(o,4653,u)|0,n[q>>2]=5,n[q+4>>2]=0,n[u>>2]=n[q>>2],n[u+4>>2]=n[q+4>>2],ep(o,4669,u)|0,n[L>>2]=6,n[L+4>>2]=0,n[u>>2]=n[L>>2],n[u+4>>2]=n[L+4>>2],ep(o,4686,u)|0,n[M>>2]=7,n[M+4>>2]=0,n[u>>2]=n[M>>2],n[u+4>>2]=n[M+4>>2],ep(o,4701,u)|0,n[R>>2]=8,n[R+4>>2]=0,n[u>>2]=n[R>>2],n[u+4>>2]=n[R+4>>2],ep(o,4719,u)|0,n[k>>2]=9,n[k+4>>2]=0,n[u>>2]=n[k>>2],n[u+4>>2]=n[k+4>>2],ep(o,4736,u)|0,n[B>>2]=21,n[B+4>>2]=0,n[u>>2]=n[B>>2],n[u+4>>2]=n[B+4>>2],Dke(o,4754,u)|0,n[m>>2]=2,n[m+4>>2]=0,n[u>>2]=n[m>>2],n[u+4>>2]=n[m+4>>2],Qb(o,4772,u)|0,n[d>>2]=3,n[d+4>>2]=0,n[u>>2]=n[d>>2],n[u+4>>2]=n[d+4>>2],Qb(o,4790,u)|0,n[A>>2]=4,n[A+4>>2]=0,n[u>>2]=n[A>>2],n[u+4>>2]=n[A+4>>2],Qb(o,4808,u)|0,I=l}function gt(o,l){o=o|0,l=l|0;var u=0;u=RLe()|0,n[o>>2]=u,TLe(u,l),jh(n[o>>2]|0)}function Zt(o,l,u){return o=o|0,l=l|0,u=u|0,yLe(o,Bn(l)|0,u,0),o|0}function Dr(o,l,u){return o=o|0,l=l|0,u=u|0,rLe(o,Bn(l)|0,u,0),o|0}function Xn(o,l,u){return o=o|0,l=l|0,u=u|0,jOe(o,Bn(l)|0,u,0),o|0}function kr(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],DOe(o,l,d),I=A,o|0}function Tn(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],aOe(o,l,d),I=A,o|0}function _n(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],WNe(o,l,d),I=A,o|0}function zr(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],xNe(o,l,d),I=A,o|0}function ci(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],pNe(o,l,d),I=A,o|0}function Du(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],ZFe(o,l,d),I=A,o|0}function lM(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],NFe(o,l,d),I=A,o|0}function od(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],aFe(o,l,d),I=A,o|0}function ep(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],WTe(o,l,d),I=A,o|0}function Qb(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],xTe(o,l,d),I=A,o|0}function yke(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],pTe(o,l,d),I=A,o|0}function Eke(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],ZRe(o,l,d),I=A,o|0}function Ike(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],ORe(o,l,d),I=A,o|0}function Cke(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],CRe(o,l,d),I=A,o|0}function wke(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],iRe(o,l,d),I=A,o|0}function Bke(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],HQe(o,l,d),I=A,o|0}function vke(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],SQe(o,l,d),I=A,o|0}function Ske(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],aQe(o,l,d),I=A,o|0}function Dke(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Pke(o,l,d),I=A,o|0}function Pke(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],bke(o,u,d,1),I=A}function Bn(o){return o=o|0,o|0}function bke(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=cM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=xke(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,kke(m,A)|0,A),I=d}function cM(){var o=0,l=0;if(s[7616]|0||(pz(9136),gr(24,9136,U|0)|0,l=7616,n[l>>2]=1,n[l+4>>2]=0),!(_r(9136)|0)){o=9136,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));pz(9136)}return 9136}function xke(o){return o=o|0,0}function kke(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=cM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],Az(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(Tke(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function vn(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0;var B=0,k=0,R=0,M=0,L=0,q=0,ae=0,Ye=0;B=I,I=I+32|0,ae=B+24|0,q=B+20|0,R=B+16|0,L=B+12|0,M=B+8|0,k=B+4|0,Ye=B,n[q>>2]=l,n[R>>2]=u,n[L>>2]=A,n[M>>2]=d,n[k>>2]=m,m=o+28|0,n[Ye>>2]=n[m>>2],n[ae>>2]=n[Ye>>2],Qke(o+24|0,ae,q,L,M,R,k)|0,n[m>>2]=n[n[m>>2]>>2],I=B}function Qke(o,l,u,A,d,m,B){return o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,B=B|0,o=Rke(l)|0,l=Kt(24)|0,fz(l+4|0,n[u>>2]|0,n[A>>2]|0,n[d>>2]|0,n[m>>2]|0,n[B>>2]|0),n[l>>2]=n[o>>2],n[o>>2]=l,l|0}function Rke(o){return o=o|0,n[o>>2]|0}function fz(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,n[o>>2]=l,n[o+4>>2]=u,n[o+8>>2]=A,n[o+12>>2]=d,n[o+16>>2]=m}function yr(o,l){return o=o|0,l=l|0,l|o|0}function Az(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function Tke(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=Fke(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,Nke(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],Az(m,A,u),n[R>>2]=(n[R>>2]|0)+12,Oke(o,k),Lke(k),I=M;return}}function Fke(o){return o=o|0,357913941}function Nke(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function Oke(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function Lke(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function pz(o){o=o|0,_ke(o)}function Mke(o){o=o|0,Uke(o+24|0)}function _r(o){return o=o|0,n[o>>2]|0}function Uke(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function _ke(o){o=o|0;var l=0;l=en()|0,tn(o,2,3,l,Hke()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function en(){return 9228}function Hke(){return 1140}function jke(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0;return u=I,I=I+16|0,A=u+8|0,d=u,m=Gke(o)|0,o=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=o,n[A>>2]=n[d>>2],n[A+4>>2]=n[d+4>>2],l=qke(l,A)|0,I=u,l|0}function tn(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,n[o>>2]=l,n[o+4>>2]=u,n[o+8>>2]=A,n[o+12>>2]=d,n[o+16>>2]=m}function Gke(o){return o=o|0,(n[(cM()|0)+24>>2]|0)+(o*12|0)|0}function qke(o,l){o=o|0,l=l|0;var u=0,A=0,d=0;return d=I,I=I+48|0,A=d,u=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(u=n[(n[o>>2]|0)+u>>2]|0),sp[u&31](A,o),A=Wke(A)|0,I=d,A|0}function Wke(o){o=o|0;var l=0,u=0,A=0,d=0;return d=I,I=I+32|0,l=d+12|0,u=d,A=uM(hz()|0)|0,A?(fM(l,A),AM(u,l),Yke(o,u),o=pM(l)|0):o=Vke(o)|0,I=d,o|0}function hz(){var o=0;return s[7632]|0||(nQe(9184),gr(25,9184,U|0)|0,o=7632,n[o>>2]=1,n[o+4>>2]=0),9184}function uM(o){return o=o|0,n[o+36>>2]|0}function fM(o,l){o=o|0,l=l|0,n[o>>2]=l,n[o+4>>2]=o,n[o+8>>2]=0}function AM(o,l){o=o|0,l=l|0,n[o>>2]=n[l>>2],n[o+4>>2]=n[l+4>>2],n[o+8>>2]=0}function Yke(o,l){o=o|0,l=l|0,Zke(l,o,o+8|0,o+16|0,o+24|0,o+32|0,o+40|0)|0}function pM(o){return o=o|0,n[(n[o+4>>2]|0)+8>>2]|0}function Vke(o){o=o|0;var l=0,u=0,A=0,d=0,m=0,B=0,k=0,R=0;R=I,I=I+16|0,u=R+4|0,A=R,d=Tl(8)|0,m=d,B=Kt(48)|0,k=B,l=k+48|0;do n[k>>2]=n[o>>2],k=k+4|0,o=o+4|0;while((k|0)<(l|0));return l=m+4|0,n[l>>2]=B,k=Kt(8)|0,B=n[l>>2]|0,n[A>>2]=0,n[u>>2]=n[A>>2],gz(k,B,u),n[d>>2]=k,I=R,m|0}function gz(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,u=Kt(16)|0,n[u+4>>2]=0,n[u+8>>2]=0,n[u>>2]=1092,n[u+12>>2]=l,n[o+4>>2]=u}function Jke(o){o=o|0,$y(o),It(o)}function Kke(o){o=o|0,o=n[o+12>>2]|0,o|0&&It(o)}function zke(o){o=o|0,It(o)}function Zke(o,l,u,A,d,m,B){return o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,B=B|0,m=Xke(n[o>>2]|0,l,u,A,d,m,B)|0,B=o+4|0,n[(n[B>>2]|0)+8>>2]=m,n[(n[B>>2]|0)+8>>2]|0}function Xke(o,l,u,A,d,m,B){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,B=B|0;var k=0,R=0;return k=I,I=I+16|0,R=k,Fl(R),o=Os(o)|0,B=$ke(o,+E[l>>3],+E[u>>3],+E[A>>3],+E[d>>3],+E[m>>3],+E[B>>3])|0,Nl(R),I=k,B|0}function $ke(o,l,u,A,d,m,B){o=o|0,l=+l,u=+u,A=+A,d=+d,m=+m,B=+B;var k=0;return k=da(eQe()|0)|0,l=+Ja(l),u=+Ja(u),A=+Ja(A),d=+Ja(d),m=+Ja(m),ro(0,k|0,o|0,+l,+u,+A,+d,+m,+ +Ja(B))|0}function eQe(){var o=0;return s[7624]|0||(tQe(9172),o=7624,n[o>>2]=1,n[o+4>>2]=0),9172}function tQe(o){o=o|0,Qo(o,rQe()|0,6)}function rQe(){return 1112}function nQe(o){o=o|0,Lh(o)}function iQe(o){o=o|0,dz(o+24|0),mz(o+16|0)}function dz(o){o=o|0,oQe(o)}function mz(o){o=o|0,sQe(o)}function sQe(o){o=o|0;var l=0,u=0;if(l=n[o>>2]|0,l|0)do u=l,l=n[l>>2]|0,It(u);while(l|0);n[o>>2]=0}function oQe(o){o=o|0;var l=0,u=0;if(l=n[o>>2]|0,l|0)do u=l,l=n[l>>2]|0,It(u);while(l|0);n[o>>2]=0}function Lh(o){o=o|0;var l=0;n[o+16>>2]=0,n[o+20>>2]=0,l=o+24|0,n[l>>2]=0,n[o+28>>2]=l,n[o+36>>2]=0,s[o+40>>0]=0,s[o+41>>0]=0}function aQe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],lQe(o,u,d,0),I=A}function lQe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=hM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=cQe(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,uQe(m,A)|0,A),I=d}function hM(){var o=0,l=0;if(s[7640]|0||(Ez(9232),gr(26,9232,U|0)|0,l=7640,n[l>>2]=1,n[l+4>>2]=0),!(_r(9232)|0)){o=9232,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Ez(9232)}return 9232}function cQe(o){return o=o|0,0}function uQe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=hM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],yz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(fQe(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function yz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function fQe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=AQe(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,pQe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],yz(m,A,u),n[R>>2]=(n[R>>2]|0)+12,hQe(o,k),gQe(k),I=M;return}}function AQe(o){return o=o|0,357913941}function pQe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function hQe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function gQe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Ez(o){o=o|0,yQe(o)}function dQe(o){o=o|0,mQe(o+24|0)}function mQe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function yQe(o){o=o|0;var l=0;l=en()|0,tn(o,2,1,l,EQe()|0,3),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function EQe(){return 1144}function IQe(o,l,u,A,d){o=o|0,l=l|0,u=+u,A=+A,d=d|0;var m=0,B=0,k=0,R=0;m=I,I=I+16|0,B=m+8|0,k=m,R=CQe(o)|0,o=n[R+4>>2]|0,n[k>>2]=n[R>>2],n[k+4>>2]=o,n[B>>2]=n[k>>2],n[B+4>>2]=n[k+4>>2],wQe(l,B,u,A,d),I=m}function CQe(o){return o=o|0,(n[(hM()|0)+24>>2]|0)+(o*12|0)|0}function wQe(o,l,u,A,d){o=o|0,l=l|0,u=+u,A=+A,d=d|0;var m=0,B=0,k=0,R=0,M=0;M=I,I=I+16|0,B=M+2|0,k=M+1|0,R=M,m=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(m=n[(n[o>>2]|0)+m>>2]|0),Qf(B,u),u=+Rf(B,u),Qf(k,A),A=+Rf(k,A),tp(R,d),R=rp(R,d)|0,FX[m&1](o,u,A,R),I=M}function Qf(o,l){o=o|0,l=+l}function Rf(o,l){return o=o|0,l=+l,+ +vQe(l)}function tp(o,l){o=o|0,l=l|0}function rp(o,l){return o=o|0,l=l|0,BQe(l)|0}function BQe(o){return o=o|0,o|0}function vQe(o){return o=+o,+o}function SQe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],DQe(o,u,d,1),I=A}function DQe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=gM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=PQe(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,bQe(m,A)|0,A),I=d}function gM(){var o=0,l=0;if(s[7648]|0||(Cz(9268),gr(27,9268,U|0)|0,l=7648,n[l>>2]=1,n[l+4>>2]=0),!(_r(9268)|0)){o=9268,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Cz(9268)}return 9268}function PQe(o){return o=o|0,0}function bQe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=gM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],Iz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(xQe(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function Iz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function xQe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=kQe(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,QQe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],Iz(m,A,u),n[R>>2]=(n[R>>2]|0)+12,RQe(o,k),TQe(k),I=M;return}}function kQe(o){return o=o|0,357913941}function QQe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function RQe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function TQe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Cz(o){o=o|0,OQe(o)}function FQe(o){o=o|0,NQe(o+24|0)}function NQe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function OQe(o){o=o|0;var l=0;l=en()|0,tn(o,2,4,l,LQe()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function LQe(){return 1160}function MQe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0;return u=I,I=I+16|0,A=u+8|0,d=u,m=UQe(o)|0,o=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=o,n[A>>2]=n[d>>2],n[A+4>>2]=n[d+4>>2],l=_Qe(l,A)|0,I=u,l|0}function UQe(o){return o=o|0,(n[(gM()|0)+24>>2]|0)+(o*12|0)|0}function _Qe(o,l){o=o|0,l=l|0;var u=0;return u=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(u=n[(n[o>>2]|0)+u>>2]|0),wz(gd[u&31](o)|0)|0}function wz(o){return o=o|0,o&1|0}function HQe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],jQe(o,u,d,0),I=A}function jQe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=dM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=GQe(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,qQe(m,A)|0,A),I=d}function dM(){var o=0,l=0;if(s[7656]|0||(vz(9304),gr(28,9304,U|0)|0,l=7656,n[l>>2]=1,n[l+4>>2]=0),!(_r(9304)|0)){o=9304,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));vz(9304)}return 9304}function GQe(o){return o=o|0,0}function qQe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=dM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],Bz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(WQe(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function Bz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function WQe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=YQe(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,VQe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],Bz(m,A,u),n[R>>2]=(n[R>>2]|0)+12,JQe(o,k),KQe(k),I=M;return}}function YQe(o){return o=o|0,357913941}function VQe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function JQe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function KQe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function vz(o){o=o|0,XQe(o)}function zQe(o){o=o|0,ZQe(o+24|0)}function ZQe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function XQe(o){o=o|0;var l=0;l=en()|0,tn(o,2,5,l,$Qe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function $Qe(){return 1164}function eRe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;A=I,I=I+16|0,d=A+8|0,m=A,B=tRe(o)|0,o=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=o,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],rRe(l,d,u),I=A}function tRe(o){return o=o|0,(n[(dM()|0)+24>>2]|0)+(o*12|0)|0}function rRe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;m=I,I=I+16|0,d=m,A=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(A=n[(n[o>>2]|0)+A>>2]|0),Mh(d,u),u=Uh(d,u)|0,sp[A&31](o,u),_h(d),I=m}function Mh(o,l){o=o|0,l=l|0,nRe(o,l)}function Uh(o,l){return o=o|0,l=l|0,o|0}function _h(o){o=o|0,Sf(o)}function nRe(o,l){o=o|0,l=l|0,mM(o,l)}function mM(o,l){o=o|0,l=l|0,n[o>>2]=l}function iRe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],sRe(o,u,d,0),I=A}function sRe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=yM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=oRe(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,aRe(m,A)|0,A),I=d}function yM(){var o=0,l=0;if(s[7664]|0||(Dz(9340),gr(29,9340,U|0)|0,l=7664,n[l>>2]=1,n[l+4>>2]=0),!(_r(9340)|0)){o=9340,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Dz(9340)}return 9340}function oRe(o){return o=o|0,0}function aRe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=yM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],Sz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(lRe(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function Sz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function lRe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=cRe(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,uRe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],Sz(m,A,u),n[R>>2]=(n[R>>2]|0)+12,fRe(o,k),ARe(k),I=M;return}}function cRe(o){return o=o|0,357913941}function uRe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function fRe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function ARe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Dz(o){o=o|0,gRe(o)}function pRe(o){o=o|0,hRe(o+24|0)}function hRe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function gRe(o){o=o|0;var l=0;l=en()|0,tn(o,2,4,l,dRe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function dRe(){return 1180}function mRe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=yRe(o)|0,o=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=o,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],u=ERe(l,d,u)|0,I=A,u|0}function yRe(o){return o=o|0,(n[(yM()|0)+24>>2]|0)+(o*12|0)|0}function ERe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;return m=I,I=I+16|0,d=m,A=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(A=n[(n[o>>2]|0)+A>>2]|0),ad(d,u),d=ld(d,u)|0,d=Rb(hU[A&15](o,d)|0)|0,I=m,d|0}function ad(o,l){o=o|0,l=l|0}function ld(o,l){return o=o|0,l=l|0,IRe(l)|0}function Rb(o){return o=o|0,o|0}function IRe(o){return o=o|0,o|0}function CRe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],wRe(o,u,d,0),I=A}function wRe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=EM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=BRe(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,vRe(m,A)|0,A),I=d}function EM(){var o=0,l=0;if(s[7672]|0||(bz(9376),gr(30,9376,U|0)|0,l=7672,n[l>>2]=1,n[l+4>>2]=0),!(_r(9376)|0)){o=9376,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));bz(9376)}return 9376}function BRe(o){return o=o|0,0}function vRe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=EM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],Pz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(SRe(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function Pz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function SRe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=DRe(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,PRe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],Pz(m,A,u),n[R>>2]=(n[R>>2]|0)+12,bRe(o,k),xRe(k),I=M;return}}function DRe(o){return o=o|0,357913941}function PRe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function bRe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function xRe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function bz(o){o=o|0,RRe(o)}function kRe(o){o=o|0,QRe(o+24|0)}function QRe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function RRe(o){o=o|0;var l=0;l=en()|0,tn(o,2,5,l,xz()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function xz(){return 1196}function TRe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0;return u=I,I=I+16|0,A=u+8|0,d=u,m=FRe(o)|0,o=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=o,n[A>>2]=n[d>>2],n[A+4>>2]=n[d+4>>2],l=NRe(l,A)|0,I=u,l|0}function FRe(o){return o=o|0,(n[(EM()|0)+24>>2]|0)+(o*12|0)|0}function NRe(o,l){o=o|0,l=l|0;var u=0;return u=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(u=n[(n[o>>2]|0)+u>>2]|0),Rb(gd[u&31](o)|0)|0}function ORe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],LRe(o,u,d,1),I=A}function LRe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=IM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=MRe(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,URe(m,A)|0,A),I=d}function IM(){var o=0,l=0;if(s[7680]|0||(Qz(9412),gr(31,9412,U|0)|0,l=7680,n[l>>2]=1,n[l+4>>2]=0),!(_r(9412)|0)){o=9412,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Qz(9412)}return 9412}function MRe(o){return o=o|0,0}function URe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=IM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],kz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(_Re(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function kz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function _Re(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=HRe(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,jRe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],kz(m,A,u),n[R>>2]=(n[R>>2]|0)+12,GRe(o,k),qRe(k),I=M;return}}function HRe(o){return o=o|0,357913941}function jRe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function GRe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function qRe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Qz(o){o=o|0,VRe(o)}function WRe(o){o=o|0,YRe(o+24|0)}function YRe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function VRe(o){o=o|0;var l=0;l=en()|0,tn(o,2,6,l,Rz()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function Rz(){return 1200}function JRe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0;return u=I,I=I+16|0,A=u+8|0,d=u,m=KRe(o)|0,o=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=o,n[A>>2]=n[d>>2],n[A+4>>2]=n[d+4>>2],l=zRe(l,A)|0,I=u,l|0}function KRe(o){return o=o|0,(n[(IM()|0)+24>>2]|0)+(o*12|0)|0}function zRe(o,l){o=o|0,l=l|0;var u=0;return u=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(u=n[(n[o>>2]|0)+u>>2]|0),Tb(gd[u&31](o)|0)|0}function Tb(o){return o=o|0,o|0}function ZRe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],XRe(o,u,d,0),I=A}function XRe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=CM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=$Re(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,eTe(m,A)|0,A),I=d}function CM(){var o=0,l=0;if(s[7688]|0||(Fz(9448),gr(32,9448,U|0)|0,l=7688,n[l>>2]=1,n[l+4>>2]=0),!(_r(9448)|0)){o=9448,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Fz(9448)}return 9448}function $Re(o){return o=o|0,0}function eTe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=CM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],Tz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(tTe(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function Tz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function tTe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=rTe(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,nTe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],Tz(m,A,u),n[R>>2]=(n[R>>2]|0)+12,iTe(o,k),sTe(k),I=M;return}}function rTe(o){return o=o|0,357913941}function nTe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function iTe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function sTe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Fz(o){o=o|0,lTe(o)}function oTe(o){o=o|0,aTe(o+24|0)}function aTe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function lTe(o){o=o|0;var l=0;l=en()|0,tn(o,2,6,l,Nz()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function Nz(){return 1204}function cTe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;A=I,I=I+16|0,d=A+8|0,m=A,B=uTe(o)|0,o=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=o,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],fTe(l,d,u),I=A}function uTe(o){return o=o|0,(n[(CM()|0)+24>>2]|0)+(o*12|0)|0}function fTe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;m=I,I=I+16|0,d=m,A=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(A=n[(n[o>>2]|0)+A>>2]|0),wM(d,u),d=BM(d,u)|0,sp[A&31](o,d),I=m}function wM(o,l){o=o|0,l=l|0}function BM(o,l){return o=o|0,l=l|0,ATe(l)|0}function ATe(o){return o=o|0,o|0}function pTe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],hTe(o,u,d,0),I=A}function hTe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=vM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=gTe(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,dTe(m,A)|0,A),I=d}function vM(){var o=0,l=0;if(s[7696]|0||(Lz(9484),gr(33,9484,U|0)|0,l=7696,n[l>>2]=1,n[l+4>>2]=0),!(_r(9484)|0)){o=9484,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Lz(9484)}return 9484}function gTe(o){return o=o|0,0}function dTe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=vM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],Oz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(mTe(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function Oz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function mTe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=yTe(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,ETe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],Oz(m,A,u),n[R>>2]=(n[R>>2]|0)+12,ITe(o,k),CTe(k),I=M;return}}function yTe(o){return o=o|0,357913941}function ETe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function ITe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function CTe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Lz(o){o=o|0,vTe(o)}function wTe(o){o=o|0,BTe(o+24|0)}function BTe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function vTe(o){o=o|0;var l=0;l=en()|0,tn(o,2,1,l,STe()|0,2),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function STe(){return 1212}function DTe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0;d=I,I=I+16|0,m=d+8|0,B=d,k=PTe(o)|0,o=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=o,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],bTe(l,m,u,A),I=d}function PTe(o){return o=o|0,(n[(vM()|0)+24>>2]|0)+(o*12|0)|0}function bTe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0;k=I,I=I+16|0,m=k+1|0,B=k,d=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(d=n[(n[o>>2]|0)+d>>2]|0),wM(m,u),m=BM(m,u)|0,ad(B,A),B=ld(B,A)|0,F2[d&15](o,m,B),I=k}function xTe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],kTe(o,u,d,1),I=A}function kTe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=SM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=QTe(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,RTe(m,A)|0,A),I=d}function SM(){var o=0,l=0;if(s[7704]|0||(Uz(9520),gr(34,9520,U|0)|0,l=7704,n[l>>2]=1,n[l+4>>2]=0),!(_r(9520)|0)){o=9520,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Uz(9520)}return 9520}function QTe(o){return o=o|0,0}function RTe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=SM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],Mz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(TTe(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function Mz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function TTe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=FTe(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,NTe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],Mz(m,A,u),n[R>>2]=(n[R>>2]|0)+12,OTe(o,k),LTe(k),I=M;return}}function FTe(o){return o=o|0,357913941}function NTe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function OTe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function LTe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Uz(o){o=o|0,_Te(o)}function MTe(o){o=o|0,UTe(o+24|0)}function UTe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function _Te(o){o=o|0;var l=0;l=en()|0,tn(o,2,1,l,HTe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function HTe(){return 1224}function jTe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;return d=I,I=I+16|0,m=d+8|0,B=d,k=GTe(o)|0,o=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=o,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],A=+qTe(l,m,u),I=d,+A}function GTe(o){return o=o|0,(n[(SM()|0)+24>>2]|0)+(o*12|0)|0}function qTe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return m=I,I=I+16|0,d=m,A=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(A=n[(n[o>>2]|0)+A>>2]|0),tp(d,u),d=rp(d,u)|0,B=+kf(+OX[A&7](o,d)),I=m,+B}function WTe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],YTe(o,u,d,1),I=A}function YTe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=DM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=VTe(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,JTe(m,A)|0,A),I=d}function DM(){var o=0,l=0;if(s[7712]|0||(Hz(9556),gr(35,9556,U|0)|0,l=7712,n[l>>2]=1,n[l+4>>2]=0),!(_r(9556)|0)){o=9556,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Hz(9556)}return 9556}function VTe(o){return o=o|0,0}function JTe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=DM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],_z(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(KTe(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function _z(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function KTe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=zTe(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,ZTe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],_z(m,A,u),n[R>>2]=(n[R>>2]|0)+12,XTe(o,k),$Te(k),I=M;return}}function zTe(o){return o=o|0,357913941}function ZTe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function XTe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function $Te(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Hz(o){o=o|0,rFe(o)}function eFe(o){o=o|0,tFe(o+24|0)}function tFe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function rFe(o){o=o|0;var l=0;l=en()|0,tn(o,2,5,l,nFe()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function nFe(){return 1232}function iFe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=sFe(o)|0,o=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=o,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],u=+oFe(l,d),I=A,+u}function sFe(o){return o=o|0,(n[(DM()|0)+24>>2]|0)+(o*12|0)|0}function oFe(o,l){o=o|0,l=l|0;var u=0;return u=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(u=n[(n[o>>2]|0)+u>>2]|0),+ +kf(+NX[u&15](o))}function aFe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],lFe(o,u,d,1),I=A}function lFe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=PM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=cFe(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,uFe(m,A)|0,A),I=d}function PM(){var o=0,l=0;if(s[7720]|0||(Gz(9592),gr(36,9592,U|0)|0,l=7720,n[l>>2]=1,n[l+4>>2]=0),!(_r(9592)|0)){o=9592,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Gz(9592)}return 9592}function cFe(o){return o=o|0,0}function uFe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=PM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],jz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(fFe(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function jz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function fFe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=AFe(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,pFe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],jz(m,A,u),n[R>>2]=(n[R>>2]|0)+12,hFe(o,k),gFe(k),I=M;return}}function AFe(o){return o=o|0,357913941}function pFe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function hFe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function gFe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Gz(o){o=o|0,yFe(o)}function dFe(o){o=o|0,mFe(o+24|0)}function mFe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function yFe(o){o=o|0;var l=0;l=en()|0,tn(o,2,7,l,EFe()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function EFe(){return 1276}function IFe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0;return u=I,I=I+16|0,A=u+8|0,d=u,m=CFe(o)|0,o=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=o,n[A>>2]=n[d>>2],n[A+4>>2]=n[d+4>>2],l=wFe(l,A)|0,I=u,l|0}function CFe(o){return o=o|0,(n[(PM()|0)+24>>2]|0)+(o*12|0)|0}function wFe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0;return d=I,I=I+16|0,A=d,u=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(u=n[(n[o>>2]|0)+u>>2]|0),sp[u&31](A,o),A=qz(A)|0,I=d,A|0}function qz(o){o=o|0;var l=0,u=0,A=0,d=0;return d=I,I=I+32|0,l=d+12|0,u=d,A=uM(Wz()|0)|0,A?(fM(l,A),AM(u,l),BFe(o,u),o=pM(l)|0):o=vFe(o)|0,I=d,o|0}function Wz(){var o=0;return s[7736]|0||(FFe(9640),gr(25,9640,U|0)|0,o=7736,n[o>>2]=1,n[o+4>>2]=0),9640}function BFe(o,l){o=o|0,l=l|0,bFe(l,o,o+8|0)|0}function vFe(o){o=o|0;var l=0,u=0,A=0,d=0,m=0,B=0,k=0;return u=I,I=I+16|0,d=u+4|0,B=u,A=Tl(8)|0,l=A,k=Kt(16)|0,n[k>>2]=n[o>>2],n[k+4>>2]=n[o+4>>2],n[k+8>>2]=n[o+8>>2],n[k+12>>2]=n[o+12>>2],m=l+4|0,n[m>>2]=k,o=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],bM(o,m,d),n[A>>2]=o,I=u,l|0}function bM(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,u=Kt(16)|0,n[u+4>>2]=0,n[u+8>>2]=0,n[u>>2]=1244,n[u+12>>2]=l,n[o+4>>2]=u}function SFe(o){o=o|0,$y(o),It(o)}function DFe(o){o=o|0,o=n[o+12>>2]|0,o|0&&It(o)}function PFe(o){o=o|0,It(o)}function bFe(o,l,u){return o=o|0,l=l|0,u=u|0,l=xFe(n[o>>2]|0,l,u)|0,u=o+4|0,n[(n[u>>2]|0)+8>>2]=l,n[(n[u>>2]|0)+8>>2]|0}function xFe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0;return A=I,I=I+16|0,d=A,Fl(d),o=Os(o)|0,u=kFe(o,n[l>>2]|0,+E[u>>3])|0,Nl(d),I=A,u|0}function kFe(o,l,u){o=o|0,l=l|0,u=+u;var A=0;return A=da(QFe()|0)|0,l=Yy(l)|0,ou(0,A|0,o|0,l|0,+ +Ja(u))|0}function QFe(){var o=0;return s[7728]|0||(RFe(9628),o=7728,n[o>>2]=1,n[o+4>>2]=0),9628}function RFe(o){o=o|0,Qo(o,TFe()|0,2)}function TFe(){return 1264}function FFe(o){o=o|0,Lh(o)}function NFe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],OFe(o,u,d,1),I=A}function OFe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=xM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=LFe(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,MFe(m,A)|0,A),I=d}function xM(){var o=0,l=0;if(s[7744]|0||(Vz(9684),gr(37,9684,U|0)|0,l=7744,n[l>>2]=1,n[l+4>>2]=0),!(_r(9684)|0)){o=9684,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Vz(9684)}return 9684}function LFe(o){return o=o|0,0}function MFe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=xM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],Yz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(UFe(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function Yz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function UFe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=_Fe(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,HFe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],Yz(m,A,u),n[R>>2]=(n[R>>2]|0)+12,jFe(o,k),GFe(k),I=M;return}}function _Fe(o){return o=o|0,357913941}function HFe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function jFe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function GFe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Vz(o){o=o|0,YFe(o)}function qFe(o){o=o|0,WFe(o+24|0)}function WFe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function YFe(o){o=o|0;var l=0;l=en()|0,tn(o,2,5,l,VFe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function VFe(){return 1280}function JFe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=KFe(o)|0,o=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=o,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],u=zFe(l,d,u)|0,I=A,u|0}function KFe(o){return o=o|0,(n[(xM()|0)+24>>2]|0)+(o*12|0)|0}function zFe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return B=I,I=I+32|0,d=B,m=B+16|0,A=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(A=n[(n[o>>2]|0)+A>>2]|0),tp(m,u),m=rp(m,u)|0,F2[A&15](d,o,m),m=qz(d)|0,I=B,m|0}function ZFe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],XFe(o,u,d,1),I=A}function XFe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=kM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=$Fe(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,eNe(m,A)|0,A),I=d}function kM(){var o=0,l=0;if(s[7752]|0||(Kz(9720),gr(38,9720,U|0)|0,l=7752,n[l>>2]=1,n[l+4>>2]=0),!(_r(9720)|0)){o=9720,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Kz(9720)}return 9720}function $Fe(o){return o=o|0,0}function eNe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=kM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],Jz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(tNe(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function Jz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function tNe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=rNe(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,nNe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],Jz(m,A,u),n[R>>2]=(n[R>>2]|0)+12,iNe(o,k),sNe(k),I=M;return}}function rNe(o){return o=o|0,357913941}function nNe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function iNe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function sNe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Kz(o){o=o|0,lNe(o)}function oNe(o){o=o|0,aNe(o+24|0)}function aNe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function lNe(o){o=o|0;var l=0;l=en()|0,tn(o,2,8,l,cNe()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function cNe(){return 1288}function uNe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0;return u=I,I=I+16|0,A=u+8|0,d=u,m=fNe(o)|0,o=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=o,n[A>>2]=n[d>>2],n[A+4>>2]=n[d+4>>2],l=ANe(l,A)|0,I=u,l|0}function fNe(o){return o=o|0,(n[(kM()|0)+24>>2]|0)+(o*12|0)|0}function ANe(o,l){o=o|0,l=l|0;var u=0;return u=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(u=n[(n[o>>2]|0)+u>>2]|0),sd(gd[u&31](o)|0)|0}function pNe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],hNe(o,u,d,0),I=A}function hNe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=QM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=gNe(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,dNe(m,A)|0,A),I=d}function QM(){var o=0,l=0;if(s[7760]|0||(Zz(9756),gr(39,9756,U|0)|0,l=7760,n[l>>2]=1,n[l+4>>2]=0),!(_r(9756)|0)){o=9756,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));Zz(9756)}return 9756}function gNe(o){return o=o|0,0}function dNe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=QM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],zz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(mNe(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function zz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function mNe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=yNe(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,ENe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],zz(m,A,u),n[R>>2]=(n[R>>2]|0)+12,INe(o,k),CNe(k),I=M;return}}function yNe(o){return o=o|0,357913941}function ENe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function INe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function CNe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function Zz(o){o=o|0,vNe(o)}function wNe(o){o=o|0,BNe(o+24|0)}function BNe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function vNe(o){o=o|0;var l=0;l=en()|0,tn(o,2,8,l,SNe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function SNe(){return 1292}function DNe(o,l,u){o=o|0,l=l|0,u=+u;var A=0,d=0,m=0,B=0;A=I,I=I+16|0,d=A+8|0,m=A,B=PNe(o)|0,o=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=o,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],bNe(l,d,u),I=A}function PNe(o){return o=o|0,(n[(QM()|0)+24>>2]|0)+(o*12|0)|0}function bNe(o,l,u){o=o|0,l=l|0,u=+u;var A=0,d=0,m=0;m=I,I=I+16|0,d=m,A=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(A=n[(n[o>>2]|0)+A>>2]|0),Qf(d,u),u=+Rf(d,u),RX[A&31](o,u),I=m}function xNe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],kNe(o,u,d,0),I=A}function kNe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=RM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=QNe(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,RNe(m,A)|0,A),I=d}function RM(){var o=0,l=0;if(s[7768]|0||($z(9792),gr(40,9792,U|0)|0,l=7768,n[l>>2]=1,n[l+4>>2]=0),!(_r(9792)|0)){o=9792,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));$z(9792)}return 9792}function QNe(o){return o=o|0,0}function RNe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=RM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],Xz(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(TNe(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function Xz(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function TNe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=FNe(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,NNe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],Xz(m,A,u),n[R>>2]=(n[R>>2]|0)+12,ONe(o,k),LNe(k),I=M;return}}function FNe(o){return o=o|0,357913941}function NNe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function ONe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function LNe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function $z(o){o=o|0,_Ne(o)}function MNe(o){o=o|0,UNe(o+24|0)}function UNe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function _Ne(o){o=o|0;var l=0;l=en()|0,tn(o,2,1,l,HNe()|0,2),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function HNe(){return 1300}function jNe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=+A;var d=0,m=0,B=0,k=0;d=I,I=I+16|0,m=d+8|0,B=d,k=GNe(o)|0,o=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=o,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],qNe(l,m,u,A),I=d}function GNe(o){return o=o|0,(n[(RM()|0)+24>>2]|0)+(o*12|0)|0}function qNe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=+A;var d=0,m=0,B=0,k=0;k=I,I=I+16|0,m=k+1|0,B=k,d=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(d=n[(n[o>>2]|0)+d>>2]|0),tp(m,u),m=rp(m,u)|0,Qf(B,A),A=+Rf(B,A),_X[d&15](o,m,A),I=k}function WNe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],YNe(o,u,d,0),I=A}function YNe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=TM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=VNe(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,JNe(m,A)|0,A),I=d}function TM(){var o=0,l=0;if(s[7776]|0||(tZ(9828),gr(41,9828,U|0)|0,l=7776,n[l>>2]=1,n[l+4>>2]=0),!(_r(9828)|0)){o=9828,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));tZ(9828)}return 9828}function VNe(o){return o=o|0,0}function JNe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=TM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],eZ(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(KNe(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function eZ(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function KNe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=zNe(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,ZNe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],eZ(m,A,u),n[R>>2]=(n[R>>2]|0)+12,XNe(o,k),$Ne(k),I=M;return}}function zNe(o){return o=o|0,357913941}function ZNe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function XNe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function $Ne(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function tZ(o){o=o|0,rOe(o)}function eOe(o){o=o|0,tOe(o+24|0)}function tOe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function rOe(o){o=o|0;var l=0;l=en()|0,tn(o,2,7,l,nOe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function nOe(){return 1312}function iOe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;A=I,I=I+16|0,d=A+8|0,m=A,B=sOe(o)|0,o=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=o,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],oOe(l,d,u),I=A}function sOe(o){return o=o|0,(n[(TM()|0)+24>>2]|0)+(o*12|0)|0}function oOe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;m=I,I=I+16|0,d=m,A=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(A=n[(n[o>>2]|0)+A>>2]|0),tp(d,u),d=rp(d,u)|0,sp[A&31](o,d),I=m}function aOe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],lOe(o,u,d,0),I=A}function lOe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=FM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=cOe(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,uOe(m,A)|0,A),I=d}function FM(){var o=0,l=0;if(s[7784]|0||(nZ(9864),gr(42,9864,U|0)|0,l=7784,n[l>>2]=1,n[l+4>>2]=0),!(_r(9864)|0)){o=9864,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));nZ(9864)}return 9864}function cOe(o){return o=o|0,0}function uOe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=FM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],rZ(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(fOe(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function rZ(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function fOe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=AOe(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,pOe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],rZ(m,A,u),n[R>>2]=(n[R>>2]|0)+12,hOe(o,k),gOe(k),I=M;return}}function AOe(o){return o=o|0,357913941}function pOe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function hOe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function gOe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function nZ(o){o=o|0,yOe(o)}function dOe(o){o=o|0,mOe(o+24|0)}function mOe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function yOe(o){o=o|0;var l=0;l=en()|0,tn(o,2,8,l,EOe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function EOe(){return 1320}function IOe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;A=I,I=I+16|0,d=A+8|0,m=A,B=COe(o)|0,o=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=o,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],wOe(l,d,u),I=A}function COe(o){return o=o|0,(n[(FM()|0)+24>>2]|0)+(o*12|0)|0}function wOe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;m=I,I=I+16|0,d=m,A=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(A=n[(n[o>>2]|0)+A>>2]|0),BOe(d,u),d=vOe(d,u)|0,sp[A&31](o,d),I=m}function BOe(o,l){o=o|0,l=l|0}function vOe(o,l){return o=o|0,l=l|0,SOe(l)|0}function SOe(o){return o=o|0,o|0}function DOe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],POe(o,u,d,0),I=A}function POe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=NM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=bOe(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,xOe(m,A)|0,A),I=d}function NM(){var o=0,l=0;if(s[7792]|0||(sZ(9900),gr(43,9900,U|0)|0,l=7792,n[l>>2]=1,n[l+4>>2]=0),!(_r(9900)|0)){o=9900,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));sZ(9900)}return 9900}function bOe(o){return o=o|0,0}function xOe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=NM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],iZ(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(kOe(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function iZ(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function kOe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=QOe(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,ROe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],iZ(m,A,u),n[R>>2]=(n[R>>2]|0)+12,TOe(o,k),FOe(k),I=M;return}}function QOe(o){return o=o|0,357913941}function ROe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function TOe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function FOe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function sZ(o){o=o|0,LOe(o)}function NOe(o){o=o|0,OOe(o+24|0)}function OOe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function LOe(o){o=o|0;var l=0;l=en()|0,tn(o,2,22,l,MOe()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function MOe(){return 1344}function UOe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0;u=I,I=I+16|0,A=u+8|0,d=u,m=_Oe(o)|0,o=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=o,n[A>>2]=n[d>>2],n[A+4>>2]=n[d+4>>2],HOe(l,A),I=u}function _Oe(o){return o=o|0,(n[(NM()|0)+24>>2]|0)+(o*12|0)|0}function HOe(o,l){o=o|0,l=l|0;var u=0;u=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(u=n[(n[o>>2]|0)+u>>2]|0),ip[u&127](o)}function jOe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=n[o>>2]|0,d=OM()|0,o=GOe(u)|0,vn(m,l,d,o,qOe(u,A)|0,A)}function OM(){var o=0,l=0;if(s[7800]|0||(aZ(9936),gr(44,9936,U|0)|0,l=7800,n[l>>2]=1,n[l+4>>2]=0),!(_r(9936)|0)){o=9936,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));aZ(9936)}return 9936}function GOe(o){return o=o|0,o|0}function qOe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,R=OM()|0,B=R+24|0,l=yr(l,4)|0,n[m>>2]=l,u=R+28|0,A=n[u>>2]|0,A>>>0<(n[R+32>>2]|0)>>>0?(oZ(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(WOe(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function oZ(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function WOe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=YOe(o)|0,A>>>0<B>>>0)sn(o);else{R=n[o>>2]|0,L=(n[o+8>>2]|0)-R|0,M=L>>2,VOe(d,L>>3>>>0<A>>>1>>>0?M>>>0<B>>>0?B:M:A,(n[m>>2]|0)-R>>3,o+8|0),B=d+8|0,oZ(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,JOe(o,d),KOe(d),I=k;return}}function YOe(o){return o=o|0,536870911}function VOe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function JOe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function KOe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function aZ(o){o=o|0,XOe(o)}function zOe(o){o=o|0,ZOe(o+24|0)}function ZOe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function XOe(o){o=o|0;var l=0;l=en()|0,tn(o,1,23,l,Nz()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function $Oe(o,l){o=o|0,l=l|0,tLe(n[(eLe(o)|0)>>2]|0,l)}function eLe(o){return o=o|0,(n[(OM()|0)+24>>2]|0)+(o<<3)|0}function tLe(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u,wM(A,l),l=BM(A,l)|0,ip[o&127](l),I=u}function rLe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=n[o>>2]|0,d=LM()|0,o=nLe(u)|0,vn(m,l,d,o,iLe(u,A)|0,A)}function LM(){var o=0,l=0;if(s[7808]|0||(cZ(9972),gr(45,9972,U|0)|0,l=7808,n[l>>2]=1,n[l+4>>2]=0),!(_r(9972)|0)){o=9972,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));cZ(9972)}return 9972}function nLe(o){return o=o|0,o|0}function iLe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,R=LM()|0,B=R+24|0,l=yr(l,4)|0,n[m>>2]=l,u=R+28|0,A=n[u>>2]|0,A>>>0<(n[R+32>>2]|0)>>>0?(lZ(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(sLe(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function lZ(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function sLe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=oLe(o)|0,A>>>0<B>>>0)sn(o);else{R=n[o>>2]|0,L=(n[o+8>>2]|0)-R|0,M=L>>2,aLe(d,L>>3>>>0<A>>>1>>>0?M>>>0<B>>>0?B:M:A,(n[m>>2]|0)-R>>3,o+8|0),B=d+8|0,lZ(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,lLe(o,d),cLe(d),I=k;return}}function oLe(o){return o=o|0,536870911}function aLe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function lLe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function cLe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function cZ(o){o=o|0,ALe(o)}function uLe(o){o=o|0,fLe(o+24|0)}function fLe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function ALe(o){o=o|0;var l=0;l=en()|0,tn(o,1,9,l,pLe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function pLe(){return 1348}function hLe(o,l){return o=o|0,l=l|0,dLe(n[(gLe(o)|0)>>2]|0,l)|0}function gLe(o){return o=o|0,(n[(LM()|0)+24>>2]|0)+(o<<3)|0}function dLe(o,l){o=o|0,l=l|0;var u=0,A=0;return u=I,I=I+16|0,A=u,uZ(A,l),l=fZ(A,l)|0,l=Rb(gd[o&31](l)|0)|0,I=u,l|0}function uZ(o,l){o=o|0,l=l|0}function fZ(o,l){return o=o|0,l=l|0,mLe(l)|0}function mLe(o){return o=o|0,o|0}function yLe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=n[o>>2]|0,d=MM()|0,o=ELe(u)|0,vn(m,l,d,o,ILe(u,A)|0,A)}function MM(){var o=0,l=0;if(s[7816]|0||(pZ(10008),gr(46,10008,U|0)|0,l=7816,n[l>>2]=1,n[l+4>>2]=0),!(_r(10008)|0)){o=10008,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));pZ(10008)}return 10008}function ELe(o){return o=o|0,o|0}function ILe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,R=MM()|0,B=R+24|0,l=yr(l,4)|0,n[m>>2]=l,u=R+28|0,A=n[u>>2]|0,A>>>0<(n[R+32>>2]|0)>>>0?(AZ(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(CLe(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function AZ(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function CLe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=wLe(o)|0,A>>>0<B>>>0)sn(o);else{R=n[o>>2]|0,L=(n[o+8>>2]|0)-R|0,M=L>>2,BLe(d,L>>3>>>0<A>>>1>>>0?M>>>0<B>>>0?B:M:A,(n[m>>2]|0)-R>>3,o+8|0),B=d+8|0,AZ(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,vLe(o,d),SLe(d),I=k;return}}function wLe(o){return o=o|0,536870911}function BLe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function vLe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function SLe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function pZ(o){o=o|0,bLe(o)}function DLe(o){o=o|0,PLe(o+24|0)}function PLe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function bLe(o){o=o|0;var l=0;l=en()|0,tn(o,1,15,l,xz()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function xLe(o){return o=o|0,QLe(n[(kLe(o)|0)>>2]|0)|0}function kLe(o){return o=o|0,(n[(MM()|0)+24>>2]|0)+(o<<3)|0}function QLe(o){return o=o|0,Rb(Vb[o&7]()|0)|0}function RLe(){var o=0;return s[7832]|0||(_Le(10052),gr(25,10052,U|0)|0,o=7832,n[o>>2]=1,n[o+4>>2]=0),10052}function TLe(o,l){o=o|0,l=l|0,n[o>>2]=FLe()|0,n[o+4>>2]=NLe()|0,n[o+12>>2]=l,n[o+8>>2]=OLe()|0,n[o+32>>2]=2}function FLe(){return 11709}function NLe(){return 1188}function OLe(){return Fb()|0}function LLe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,(Hh(A,896)|0)==512?u|0&&(MLe(u),It(u)):l|0&&(Oy(l),It(l))}function Hh(o,l){return o=o|0,l=l|0,l&o|0}function MLe(o){o=o|0,o=n[o+4>>2]|0,o|0&&Gh(o)}function Fb(){var o=0;return s[7824]|0||(n[2511]=ULe()|0,n[2512]=0,o=7824,n[o>>2]=1,n[o+4>>2]=0),10044}function ULe(){return 0}function _Le(o){o=o|0,Lh(o)}function HLe(o){o=o|0;var l=0,u=0,A=0,d=0,m=0;l=I,I=I+32|0,u=l+24|0,m=l+16|0,d=l+8|0,A=l,jLe(o,4827),GLe(o,4834,3)|0,qLe(o,3682,47)|0,n[m>>2]=9,n[m+4>>2]=0,n[u>>2]=n[m>>2],n[u+4>>2]=n[m+4>>2],WLe(o,4841,u)|0,n[d>>2]=1,n[d+4>>2]=0,n[u>>2]=n[d>>2],n[u+4>>2]=n[d+4>>2],YLe(o,4871,u)|0,n[A>>2]=10,n[A+4>>2]=0,n[u>>2]=n[A>>2],n[u+4>>2]=n[A+4>>2],VLe(o,4891,u)|0,I=l}function jLe(o,l){o=o|0,l=l|0;var u=0;u=SUe()|0,n[o>>2]=u,DUe(u,l),jh(n[o>>2]|0)}function GLe(o,l,u){return o=o|0,l=l|0,u=u|0,cUe(o,Bn(l)|0,u,0),o|0}function qLe(o,l,u){return o=o|0,l=l|0,u=u|0,JMe(o,Bn(l)|0,u,0),o|0}function WLe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],xMe(o,l,d),I=A,o|0}function YLe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],uMe(o,l,d),I=A,o|0}function VLe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=n[u+4>>2]|0,n[m>>2]=n[u>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],JLe(o,l,d),I=A,o|0}function JLe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],KLe(o,u,d,1),I=A}function KLe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=UM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=zLe(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,ZLe(m,A)|0,A),I=d}function UM(){var o=0,l=0;if(s[7840]|0||(gZ(10100),gr(48,10100,U|0)|0,l=7840,n[l>>2]=1,n[l+4>>2]=0),!(_r(10100)|0)){o=10100,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));gZ(10100)}return 10100}function zLe(o){return o=o|0,0}function ZLe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=UM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],hZ(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(XLe(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function hZ(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function XLe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=$Le(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,eMe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],hZ(m,A,u),n[R>>2]=(n[R>>2]|0)+12,tMe(o,k),rMe(k),I=M;return}}function $Le(o){return o=o|0,357913941}function eMe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function tMe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function rMe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function gZ(o){o=o|0,sMe(o)}function nMe(o){o=o|0,iMe(o+24|0)}function iMe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function sMe(o){o=o|0;var l=0;l=en()|0,tn(o,2,6,l,oMe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function oMe(){return 1364}function aMe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;return A=I,I=I+16|0,d=A+8|0,m=A,B=lMe(o)|0,o=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=o,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],u=cMe(l,d,u)|0,I=A,u|0}function lMe(o){return o=o|0,(n[(UM()|0)+24>>2]|0)+(o*12|0)|0}function cMe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;return m=I,I=I+16|0,d=m,A=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(A=n[(n[o>>2]|0)+A>>2]|0),tp(d,u),d=rp(d,u)|0,d=wz(hU[A&15](o,d)|0)|0,I=m,d|0}function uMe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],fMe(o,u,d,0),I=A}function fMe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=_M()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=AMe(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,pMe(m,A)|0,A),I=d}function _M(){var o=0,l=0;if(s[7848]|0||(mZ(10136),gr(49,10136,U|0)|0,l=7848,n[l>>2]=1,n[l+4>>2]=0),!(_r(10136)|0)){o=10136,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));mZ(10136)}return 10136}function AMe(o){return o=o|0,0}function pMe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=_M()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],dZ(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(hMe(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function dZ(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function hMe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=gMe(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,dMe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],dZ(m,A,u),n[R>>2]=(n[R>>2]|0)+12,mMe(o,k),yMe(k),I=M;return}}function gMe(o){return o=o|0,357913941}function dMe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function mMe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function yMe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function mZ(o){o=o|0,CMe(o)}function EMe(o){o=o|0,IMe(o+24|0)}function IMe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function CMe(o){o=o|0;var l=0;l=en()|0,tn(o,2,9,l,wMe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function wMe(){return 1372}function BMe(o,l,u){o=o|0,l=l|0,u=+u;var A=0,d=0,m=0,B=0;A=I,I=I+16|0,d=A+8|0,m=A,B=vMe(o)|0,o=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=o,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],SMe(l,d,u),I=A}function vMe(o){return o=o|0,(n[(_M()|0)+24>>2]|0)+(o*12|0)|0}function SMe(o,l,u){o=o|0,l=l|0,u=+u;var A=0,d=0,m=0,B=$e;m=I,I=I+16|0,d=m,A=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(A=n[(n[o>>2]|0)+A>>2]|0),DMe(d,u),B=y(PMe(d,u)),QX[A&1](o,B),I=m}function DMe(o,l){o=o|0,l=+l}function PMe(o,l){return o=o|0,l=+l,y(bMe(l))}function bMe(o){return o=+o,y(o)}function xMe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,d=A+8|0,m=A,k=n[u>>2]|0,B=n[u+4>>2]|0,u=Bn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],kMe(o,u,d,0),I=A}function kMe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0,R=0,M=0,L=0;d=I,I=I+32|0,m=d+16|0,L=d+8|0,k=d,M=n[u>>2]|0,R=n[u+4>>2]|0,B=n[o>>2]|0,o=HM()|0,n[L>>2]=M,n[L+4>>2]=R,n[m>>2]=n[L>>2],n[m+4>>2]=n[L+4>>2],u=QMe(m)|0,n[k>>2]=M,n[k+4>>2]=R,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],vn(B,l,o,u,RMe(m,A)|0,A),I=d}function HM(){var o=0,l=0;if(s[7856]|0||(EZ(10172),gr(50,10172,U|0)|0,l=7856,n[l>>2]=1,n[l+4>>2]=0),!(_r(10172)|0)){o=10172,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));EZ(10172)}return 10172}function QMe(o){return o=o|0,0}function RMe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0;return L=I,I=I+32|0,d=L+24|0,B=L+16|0,k=L,R=L+8|0,m=n[o>>2]|0,A=n[o+4>>2]|0,n[k>>2]=m,n[k+4>>2]=A,q=HM()|0,M=q+24|0,o=yr(l,4)|0,n[R>>2]=o,l=q+28|0,u=n[l>>2]|0,u>>>0<(n[q+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=A,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],yZ(u,d,o),o=(n[l>>2]|0)+12|0,n[l>>2]=o):(TMe(M,k,R),o=n[l>>2]|0),I=L,((o-(n[M>>2]|0)|0)/12|0)+-1|0}function yZ(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=n[l+4>>2]|0,n[o>>2]=n[l>>2],n[o+4>>2]=A,n[o+8>>2]=u}function TMe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;if(M=I,I=I+48|0,A=M+32|0,B=M+24|0,k=M,R=o+4|0,d=(((n[R>>2]|0)-(n[o>>2]|0)|0)/12|0)+1|0,m=FMe(o)|0,m>>>0<d>>>0)sn(o);else{L=n[o>>2]|0,ae=((n[o+8>>2]|0)-L|0)/12|0,q=ae<<1,NMe(k,ae>>>0<m>>>1>>>0?q>>>0<d>>>0?d:q:m,((n[R>>2]|0)-L|0)/12|0,o+8|0),R=k+8|0,m=n[R>>2]|0,d=n[l+4>>2]|0,u=n[u>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[A>>2]=n[B>>2],n[A+4>>2]=n[B+4>>2],yZ(m,A,u),n[R>>2]=(n[R>>2]|0)+12,OMe(o,k),LMe(k),I=M;return}}function FMe(o){return o=o|0,357913941}function NMe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>357913941)Nt();else{d=Kt(l*12|0)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u*12|0)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l*12|0)}function OMe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function LMe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~(((A+-12-l|0)>>>0)/12|0)*12|0)),o=n[o>>2]|0,o|0&&It(o)}function EZ(o){o=o|0,_Me(o)}function MMe(o){o=o|0,UMe(o+24|0)}function UMe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~(((l+-12-A|0)>>>0)/12|0)*12|0)),It(u))}function _Me(o){o=o|0;var l=0;l=en()|0,tn(o,2,3,l,HMe()|0,2),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function HMe(){return 1380}function jMe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0;d=I,I=I+16|0,m=d+8|0,B=d,k=GMe(o)|0,o=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=o,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],qMe(l,m,u,A),I=d}function GMe(o){return o=o|0,(n[(HM()|0)+24>>2]|0)+(o*12|0)|0}function qMe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0;k=I,I=I+16|0,m=k+1|0,B=k,d=n[l>>2]|0,l=n[l+4>>2]|0,o=o+(l>>1)|0,l&1&&(d=n[(n[o>>2]|0)+d>>2]|0),tp(m,u),m=rp(m,u)|0,WMe(B,A),B=YMe(B,A)|0,F2[d&15](o,m,B),I=k}function WMe(o,l){o=o|0,l=l|0}function YMe(o,l){return o=o|0,l=l|0,VMe(l)|0}function VMe(o){return o=o|0,(o|0)!=0|0}function JMe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=n[o>>2]|0,d=jM()|0,o=KMe(u)|0,vn(m,l,d,o,zMe(u,A)|0,A)}function jM(){var o=0,l=0;if(s[7864]|0||(CZ(10208),gr(51,10208,U|0)|0,l=7864,n[l>>2]=1,n[l+4>>2]=0),!(_r(10208)|0)){o=10208,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));CZ(10208)}return 10208}function KMe(o){return o=o|0,o|0}function zMe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,R=jM()|0,B=R+24|0,l=yr(l,4)|0,n[m>>2]=l,u=R+28|0,A=n[u>>2]|0,A>>>0<(n[R+32>>2]|0)>>>0?(IZ(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(ZMe(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function IZ(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function ZMe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=XMe(o)|0,A>>>0<B>>>0)sn(o);else{R=n[o>>2]|0,L=(n[o+8>>2]|0)-R|0,M=L>>2,$Me(d,L>>3>>>0<A>>>1>>>0?M>>>0<B>>>0?B:M:A,(n[m>>2]|0)-R>>3,o+8|0),B=d+8|0,IZ(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,eUe(o,d),tUe(d),I=k;return}}function XMe(o){return o=o|0,536870911}function $Me(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function eUe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function tUe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function CZ(o){o=o|0,iUe(o)}function rUe(o){o=o|0,nUe(o+24|0)}function nUe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function iUe(o){o=o|0;var l=0;l=en()|0,tn(o,1,24,l,sUe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function sUe(){return 1392}function oUe(o,l){o=o|0,l=l|0,lUe(n[(aUe(o)|0)>>2]|0,l)}function aUe(o){return o=o|0,(n[(jM()|0)+24>>2]|0)+(o<<3)|0}function lUe(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u,uZ(A,l),l=fZ(A,l)|0,ip[o&127](l),I=u}function cUe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=n[o>>2]|0,d=GM()|0,o=uUe(u)|0,vn(m,l,d,o,fUe(u,A)|0,A)}function GM(){var o=0,l=0;if(s[7872]|0||(BZ(10244),gr(52,10244,U|0)|0,l=7872,n[l>>2]=1,n[l+4>>2]=0),!(_r(10244)|0)){o=10244,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));BZ(10244)}return 10244}function uUe(o){return o=o|0,o|0}function fUe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,R=GM()|0,B=R+24|0,l=yr(l,4)|0,n[m>>2]=l,u=R+28|0,A=n[u>>2]|0,A>>>0<(n[R+32>>2]|0)>>>0?(wZ(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(AUe(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function wZ(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function AUe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=pUe(o)|0,A>>>0<B>>>0)sn(o);else{R=n[o>>2]|0,L=(n[o+8>>2]|0)-R|0,M=L>>2,hUe(d,L>>3>>>0<A>>>1>>>0?M>>>0<B>>>0?B:M:A,(n[m>>2]|0)-R>>3,o+8|0),B=d+8|0,wZ(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,gUe(o,d),dUe(d),I=k;return}}function pUe(o){return o=o|0,536870911}function hUe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function gUe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function dUe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function BZ(o){o=o|0,EUe(o)}function mUe(o){o=o|0,yUe(o+24|0)}function yUe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function EUe(o){o=o|0;var l=0;l=en()|0,tn(o,1,16,l,IUe()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function IUe(){return 1400}function CUe(o){return o=o|0,BUe(n[(wUe(o)|0)>>2]|0)|0}function wUe(o){return o=o|0,(n[(GM()|0)+24>>2]|0)+(o<<3)|0}function BUe(o){return o=o|0,vUe(Vb[o&7]()|0)|0}function vUe(o){return o=o|0,o|0}function SUe(){var o=0;return s[7880]|0||(RUe(10280),gr(25,10280,U|0)|0,o=7880,n[o>>2]=1,n[o+4>>2]=0),10280}function DUe(o,l){o=o|0,l=l|0,n[o>>2]=PUe()|0,n[o+4>>2]=bUe()|0,n[o+12>>2]=l,n[o+8>>2]=xUe()|0,n[o+32>>2]=4}function PUe(){return 11711}function bUe(){return 1356}function xUe(){return Fb()|0}function kUe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,(Hh(A,896)|0)==512?u|0&&(QUe(u),It(u)):l|0&&(Kg(l),It(l))}function QUe(o){o=o|0,o=n[o+4>>2]|0,o|0&&Gh(o)}function RUe(o){o=o|0,Lh(o)}function TUe(o){o=o|0,FUe(o,4920),NUe(o)|0,OUe(o)|0}function FUe(o,l){o=o|0,l=l|0;var u=0;u=Wz()|0,n[o>>2]=u,n_e(u,l),jh(n[o>>2]|0)}function NUe(o){o=o|0;var l=0;return l=n[o>>2]|0,cd(l,VUe()|0),o|0}function OUe(o){o=o|0;var l=0;return l=n[o>>2]|0,cd(l,LUe()|0),o|0}function LUe(){var o=0;return s[7888]|0||(vZ(10328),gr(53,10328,U|0)|0,o=7888,n[o>>2]=1,n[o+4>>2]=0),_r(10328)|0||vZ(10328),10328}function cd(o,l){o=o|0,l=l|0,vn(o,0,l,0,0,0)}function vZ(o){o=o|0,_Ue(o),ud(o,10)}function MUe(o){o=o|0,UUe(o+24|0)}function UUe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function _Ue(o){o=o|0;var l=0;l=en()|0,tn(o,5,1,l,qUe()|0,2),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function HUe(o,l,u){o=o|0,l=l|0,u=+u,jUe(o,l,u)}function ud(o,l){o=o|0,l=l|0,n[o+20>>2]=l}function jUe(o,l,u){o=o|0,l=l|0,u=+u;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+16|0,m=A+8|0,k=A+13|0,d=A,B=A+12|0,tp(k,l),n[m>>2]=rp(k,l)|0,Qf(B,u),E[d>>3]=+Rf(B,u),GUe(o,m,d),I=A}function GUe(o,l,u){o=o|0,l=l|0,u=u|0,Rl(o+8|0,n[l>>2]|0,+E[u>>3]),s[o+24>>0]=1}function qUe(){return 1404}function WUe(o,l){return o=o|0,l=+l,YUe(o,l)|0}function YUe(o,l){o=o|0,l=+l;var u=0,A=0,d=0,m=0,B=0,k=0,R=0;return A=I,I=I+16|0,m=A+4|0,B=A+8|0,k=A,d=Tl(8)|0,u=d,R=Kt(16)|0,tp(m,o),o=rp(m,o)|0,Qf(B,l),Rl(R,o,+Rf(B,l)),B=u+4|0,n[B>>2]=R,o=Kt(8)|0,B=n[B>>2]|0,n[k>>2]=0,n[m>>2]=n[k>>2],bM(o,B,m),n[d>>2]=o,I=A,u|0}function VUe(){var o=0;return s[7896]|0||(SZ(10364),gr(54,10364,U|0)|0,o=7896,n[o>>2]=1,n[o+4>>2]=0),_r(10364)|0||SZ(10364),10364}function SZ(o){o=o|0,zUe(o),ud(o,55)}function JUe(o){o=o|0,KUe(o+24|0)}function KUe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function zUe(o){o=o|0;var l=0;l=en()|0,tn(o,5,4,l,e_e()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function ZUe(o){o=o|0,XUe(o)}function XUe(o){o=o|0,$Ue(o)}function $Ue(o){o=o|0,DZ(o+8|0),s[o+24>>0]=1}function DZ(o){o=o|0,n[o>>2]=0,E[o+8>>3]=0}function e_e(){return 1424}function t_e(){return r_e()|0}function r_e(){var o=0,l=0,u=0,A=0,d=0,m=0,B=0;return l=I,I=I+16|0,d=l+4|0,B=l,u=Tl(8)|0,o=u,A=Kt(16)|0,DZ(A),m=o+4|0,n[m>>2]=A,A=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],bM(A,m,d),n[u>>2]=A,I=l,o|0}function n_e(o,l){o=o|0,l=l|0,n[o>>2]=i_e()|0,n[o+4>>2]=s_e()|0,n[o+12>>2]=l,n[o+8>>2]=o_e()|0,n[o+32>>2]=5}function i_e(){return 11710}function s_e(){return 1416}function o_e(){return Nb()|0}function a_e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,(Hh(A,896)|0)==512?u|0&&(l_e(u),It(u)):l|0&&It(l)}function l_e(o){o=o|0,o=n[o+4>>2]|0,o|0&&Gh(o)}function Nb(){var o=0;return s[7904]|0||(n[2600]=c_e()|0,n[2601]=0,o=7904,n[o>>2]=1,n[o+4>>2]=0),10400}function c_e(){return n[357]|0}function u_e(o){o=o|0,f_e(o,4926),A_e(o)|0}function f_e(o,l){o=o|0,l=l|0;var u=0;u=hz()|0,n[o>>2]=u,B_e(u,l),jh(n[o>>2]|0)}function A_e(o){o=o|0;var l=0;return l=n[o>>2]|0,cd(l,p_e()|0),o|0}function p_e(){var o=0;return s[7912]|0||(PZ(10412),gr(56,10412,U|0)|0,o=7912,n[o>>2]=1,n[o+4>>2]=0),_r(10412)|0||PZ(10412),10412}function PZ(o){o=o|0,d_e(o),ud(o,57)}function h_e(o){o=o|0,g_e(o+24|0)}function g_e(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function d_e(o){o=o|0;var l=0;l=en()|0,tn(o,5,5,l,I_e()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function m_e(o){o=o|0,y_e(o)}function y_e(o){o=o|0,E_e(o)}function E_e(o){o=o|0;var l=0,u=0;l=o+8|0,u=l+48|0;do n[l>>2]=0,l=l+4|0;while((l|0)<(u|0));s[o+56>>0]=1}function I_e(){return 1432}function C_e(){return w_e()|0}function w_e(){var o=0,l=0,u=0,A=0,d=0,m=0,B=0,k=0;B=I,I=I+16|0,o=B+4|0,l=B,u=Tl(8)|0,A=u,d=Kt(48)|0,m=d,k=m+48|0;do n[m>>2]=0,m=m+4|0;while((m|0)<(k|0));return m=A+4|0,n[m>>2]=d,k=Kt(8)|0,m=n[m>>2]|0,n[l>>2]=0,n[o>>2]=n[l>>2],gz(k,m,o),n[u>>2]=k,I=B,A|0}function B_e(o,l){o=o|0,l=l|0,n[o>>2]=v_e()|0,n[o+4>>2]=S_e()|0,n[o+12>>2]=l,n[o+8>>2]=D_e()|0,n[o+32>>2]=6}function v_e(){return 11704}function S_e(){return 1436}function D_e(){return Nb()|0}function P_e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,(Hh(A,896)|0)==512?u|0&&(b_e(u),It(u)):l|0&&It(l)}function b_e(o){o=o|0,o=n[o+4>>2]|0,o|0&&Gh(o)}function x_e(o){o=o|0,k_e(o,4933),Q_e(o)|0,R_e(o)|0}function k_e(o,l){o=o|0,l=l|0;var u=0;u=r4e()|0,n[o>>2]=u,n4e(u,l),jh(n[o>>2]|0)}function Q_e(o){o=o|0;var l=0;return l=n[o>>2]|0,cd(l,Y_e()|0),o|0}function R_e(o){o=o|0;var l=0;return l=n[o>>2]|0,cd(l,T_e()|0),o|0}function T_e(){var o=0;return s[7920]|0||(bZ(10452),gr(58,10452,U|0)|0,o=7920,n[o>>2]=1,n[o+4>>2]=0),_r(10452)|0||bZ(10452),10452}function bZ(o){o=o|0,O_e(o),ud(o,1)}function F_e(o){o=o|0,N_e(o+24|0)}function N_e(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function O_e(o){o=o|0;var l=0;l=en()|0,tn(o,5,1,l,__e()|0,2),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function L_e(o,l,u){o=o|0,l=+l,u=+u,M_e(o,l,u)}function M_e(o,l,u){o=o|0,l=+l,u=+u;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+32|0,m=A+8|0,k=A+17|0,d=A,B=A+16|0,Qf(k,l),E[m>>3]=+Rf(k,l),Qf(B,u),E[d>>3]=+Rf(B,u),U_e(o,m,d),I=A}function U_e(o,l,u){o=o|0,l=l|0,u=u|0,xZ(o+8|0,+E[l>>3],+E[u>>3]),s[o+24>>0]=1}function xZ(o,l,u){o=o|0,l=+l,u=+u,E[o>>3]=l,E[o+8>>3]=u}function __e(){return 1472}function H_e(o,l){return o=+o,l=+l,j_e(o,l)|0}function j_e(o,l){o=+o,l=+l;var u=0,A=0,d=0,m=0,B=0,k=0,R=0;return A=I,I=I+16|0,B=A+4|0,k=A+8|0,R=A,d=Tl(8)|0,u=d,m=Kt(16)|0,Qf(B,o),o=+Rf(B,o),Qf(k,l),xZ(m,o,+Rf(k,l)),k=u+4|0,n[k>>2]=m,m=Kt(8)|0,k=n[k>>2]|0,n[R>>2]=0,n[B>>2]=n[R>>2],kZ(m,k,B),n[d>>2]=m,I=A,u|0}function kZ(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,u=Kt(16)|0,n[u+4>>2]=0,n[u+8>>2]=0,n[u>>2]=1452,n[u+12>>2]=l,n[o+4>>2]=u}function G_e(o){o=o|0,$y(o),It(o)}function q_e(o){o=o|0,o=n[o+12>>2]|0,o|0&&It(o)}function W_e(o){o=o|0,It(o)}function Y_e(){var o=0;return s[7928]|0||(QZ(10488),gr(59,10488,U|0)|0,o=7928,n[o>>2]=1,n[o+4>>2]=0),_r(10488)|0||QZ(10488),10488}function QZ(o){o=o|0,K_e(o),ud(o,60)}function V_e(o){o=o|0,J_e(o+24|0)}function J_e(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function K_e(o){o=o|0;var l=0;l=en()|0,tn(o,5,6,l,$_e()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function z_e(o){o=o|0,Z_e(o)}function Z_e(o){o=o|0,X_e(o)}function X_e(o){o=o|0,RZ(o+8|0),s[o+24>>0]=1}function RZ(o){o=o|0,n[o>>2]=0,n[o+4>>2]=0,n[o+8>>2]=0,n[o+12>>2]=0}function $_e(){return 1492}function e4e(){return t4e()|0}function t4e(){var o=0,l=0,u=0,A=0,d=0,m=0,B=0;return l=I,I=I+16|0,d=l+4|0,B=l,u=Tl(8)|0,o=u,A=Kt(16)|0,RZ(A),m=o+4|0,n[m>>2]=A,A=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],kZ(A,m,d),n[u>>2]=A,I=l,o|0}function r4e(){var o=0;return s[7936]|0||(c4e(10524),gr(25,10524,U|0)|0,o=7936,n[o>>2]=1,n[o+4>>2]=0),10524}function n4e(o,l){o=o|0,l=l|0,n[o>>2]=i4e()|0,n[o+4>>2]=s4e()|0,n[o+12>>2]=l,n[o+8>>2]=o4e()|0,n[o+32>>2]=7}function i4e(){return 11700}function s4e(){return 1484}function o4e(){return Nb()|0}function a4e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,(Hh(A,896)|0)==512?u|0&&(l4e(u),It(u)):l|0&&It(l)}function l4e(o){o=o|0,o=n[o+4>>2]|0,o|0&&Gh(o)}function c4e(o){o=o|0,Lh(o)}function u4e(o,l,u){o=o|0,l=l|0,u=u|0,o=Bn(l)|0,l=f4e(u)|0,u=A4e(u,0)|0,j4e(o,l,u,qM()|0,0)}function f4e(o){return o=o|0,o|0}function A4e(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,R=qM()|0,B=R+24|0,l=yr(l,4)|0,n[m>>2]=l,u=R+28|0,A=n[u>>2]|0,A>>>0<(n[R+32>>2]|0)>>>0?(FZ(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(E4e(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function qM(){var o=0,l=0;if(s[7944]|0||(TZ(10568),gr(61,10568,U|0)|0,l=7944,n[l>>2]=1,n[l+4>>2]=0),!(_r(10568)|0)){o=10568,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));TZ(10568)}return 10568}function TZ(o){o=o|0,g4e(o)}function p4e(o){o=o|0,h4e(o+24|0)}function h4e(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function g4e(o){o=o|0;var l=0;l=en()|0,tn(o,1,17,l,Rz()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function d4e(o){return o=o|0,y4e(n[(m4e(o)|0)>>2]|0)|0}function m4e(o){return o=o|0,(n[(qM()|0)+24>>2]|0)+(o<<3)|0}function y4e(o){return o=o|0,Tb(Vb[o&7]()|0)|0}function FZ(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function E4e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=I4e(o)|0,A>>>0<B>>>0)sn(o);else{R=n[o>>2]|0,L=(n[o+8>>2]|0)-R|0,M=L>>2,C4e(d,L>>3>>>0<A>>>1>>>0?M>>>0<B>>>0?B:M:A,(n[m>>2]|0)-R>>3,o+8|0),B=d+8|0,FZ(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,w4e(o,d),B4e(d),I=k;return}}function I4e(o){return o=o|0,536870911}function C4e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function w4e(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function B4e(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function v4e(){S4e()}function S4e(){D4e(10604)}function D4e(o){o=o|0,P4e(o,4955)}function P4e(o,l){o=o|0,l=l|0;var u=0;u=b4e()|0,n[o>>2]=u,x4e(u,l),jh(n[o>>2]|0)}function b4e(){var o=0;return s[7952]|0||(M4e(10612),gr(25,10612,U|0)|0,o=7952,n[o>>2]=1,n[o+4>>2]=0),10612}function x4e(o,l){o=o|0,l=l|0,n[o>>2]=T4e()|0,n[o+4>>2]=F4e()|0,n[o+12>>2]=l,n[o+8>>2]=N4e()|0,n[o+32>>2]=8}function jh(o){o=o|0;var l=0,u=0;l=I,I=I+16|0,u=l,Jy()|0,n[u>>2]=o,k4e(10608,u),I=l}function Jy(){return s[11714]|0||(n[2652]=0,gr(62,10608,U|0)|0,s[11714]=1),10608}function k4e(o,l){o=o|0,l=l|0;var u=0;u=Kt(8)|0,n[u+4>>2]=n[l>>2],n[u>>2]=n[o>>2],n[o>>2]=u}function Q4e(o){o=o|0,R4e(o)}function R4e(o){o=o|0;var l=0,u=0;if(l=n[o>>2]|0,l|0)do u=l,l=n[l>>2]|0,It(u);while(l|0);n[o>>2]=0}function T4e(){return 11715}function F4e(){return 1496}function N4e(){return Fb()|0}function O4e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,(Hh(A,896)|0)==512?u|0&&(L4e(u),It(u)):l|0&&It(l)}function L4e(o){o=o|0,o=n[o+4>>2]|0,o|0&&Gh(o)}function M4e(o){o=o|0,Lh(o)}function U4e(o,l){o=o|0,l=l|0;var u=0,A=0;Jy()|0,u=n[2652]|0;e:do if(u|0){for(;A=n[u+4>>2]|0,!(A|0&&!(gX(WM(A)|0,o)|0));)if(u=n[u>>2]|0,!u)break e;_4e(A,l)}while(!1)}function WM(o){return o=o|0,n[o+12>>2]|0}function _4e(o,l){o=o|0,l=l|0;var u=0;o=o+36|0,u=n[o>>2]|0,u|0&&(Sf(u),It(u)),u=Kt(4)|0,Db(u,l),n[o>>2]=u}function YM(){return s[11716]|0||(n[2664]=0,gr(63,10656,U|0)|0,s[11716]=1),10656}function NZ(){var o=0;return s[11717]|0?o=n[2665]|0:(H4e(),n[2665]=1504,s[11717]=1,o=1504),o|0}function H4e(){s[11740]|0||(s[11718]=yr(yr(8,0)|0,0)|0,s[11719]=yr(yr(0,0)|0,0)|0,s[11720]=yr(yr(0,16)|0,0)|0,s[11721]=yr(yr(8,0)|0,0)|0,s[11722]=yr(yr(0,0)|0,0)|0,s[11723]=yr(yr(8,0)|0,0)|0,s[11724]=yr(yr(0,0)|0,0)|0,s[11725]=yr(yr(8,0)|0,0)|0,s[11726]=yr(yr(0,0)|0,0)|0,s[11727]=yr(yr(8,0)|0,0)|0,s[11728]=yr(yr(0,0)|0,0)|0,s[11729]=yr(yr(0,0)|0,32)|0,s[11730]=yr(yr(0,0)|0,32)|0,s[11740]=1)}function OZ(){return 1572}function j4e(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0;var m=0,B=0,k=0,R=0,M=0,L=0;m=I,I=I+32|0,L=m+16|0,M=m+12|0,R=m+8|0,k=m+4|0,B=m,n[L>>2]=o,n[M>>2]=l,n[R>>2]=u,n[k>>2]=A,n[B>>2]=d,YM()|0,G4e(10656,L,M,R,k,B),I=m}function G4e(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0;var B=0;B=Kt(24)|0,fz(B+4|0,n[l>>2]|0,n[u>>2]|0,n[A>>2]|0,n[d>>2]|0,n[m>>2]|0),n[B>>2]=n[o>>2],n[o>>2]=B}function LZ(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0,Ye=0,Le=0,Qe=0,tt=0,Xe=0,ct=0;if(ct=I,I=I+32|0,Le=ct+20|0,Qe=ct+8|0,tt=ct+4|0,Xe=ct,l=n[l>>2]|0,l|0){Ye=Le+4|0,R=Le+8|0,M=Qe+4|0,L=Qe+8|0,q=Qe+8|0,ae=Le+8|0;do{if(B=l+4|0,k=VM(B)|0,k|0){if(d=b2(k)|0,n[Le>>2]=0,n[Ye>>2]=0,n[R>>2]=0,A=(x2(k)|0)+1|0,q4e(Le,A),A|0)for(;A=A+-1|0,Pu(Qe,n[d>>2]|0),m=n[Ye>>2]|0,m>>>0<(n[ae>>2]|0)>>>0?(n[m>>2]=n[Qe>>2],n[Ye>>2]=(n[Ye>>2]|0)+4):JM(Le,Qe),A;)d=d+4|0;A=k2(k)|0,n[Qe>>2]=0,n[M>>2]=0,n[L>>2]=0;e:do if(n[A>>2]|0)for(d=0,m=0;;){if((d|0)==(m|0)?W4e(Qe,A):(n[d>>2]=n[A>>2],n[M>>2]=(n[M>>2]|0)+4),A=A+4|0,!(n[A>>2]|0))break e;d=n[M>>2]|0,m=n[q>>2]|0}while(!1);n[tt>>2]=Ob(B)|0,n[Xe>>2]=_r(k)|0,Y4e(u,o,tt,Xe,Le,Qe),KM(Qe),np(Le)}l=n[l>>2]|0}while(l|0)}I=ct}function VM(o){return o=o|0,n[o+12>>2]|0}function b2(o){return o=o|0,n[o+12>>2]|0}function x2(o){return o=o|0,n[o+16>>2]|0}function q4e(o,l){o=o|0,l=l|0;var u=0,A=0,d=0;d=I,I=I+32|0,u=d,A=n[o>>2]|0,(n[o+8>>2]|0)-A>>2>>>0<l>>>0&&(WZ(u,l,(n[o+4>>2]|0)-A>>2,o+8|0),YZ(o,u),VZ(u)),I=d}function JM(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0;if(B=I,I=I+32|0,u=B,A=o+4|0,d=((n[A>>2]|0)-(n[o>>2]|0)>>2)+1|0,m=qZ(o)|0,m>>>0<d>>>0)sn(o);else{k=n[o>>2]|0,M=(n[o+8>>2]|0)-k|0,R=M>>1,WZ(u,M>>2>>>0<m>>>1>>>0?R>>>0<d>>>0?d:R:m,(n[A>>2]|0)-k>>2,o+8|0),m=u+8|0,n[n[m>>2]>>2]=n[l>>2],n[m>>2]=(n[m>>2]|0)+4,YZ(o,u),VZ(u),I=B;return}}function k2(o){return o=o|0,n[o+8>>2]|0}function W4e(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0;if(B=I,I=I+32|0,u=B,A=o+4|0,d=((n[A>>2]|0)-(n[o>>2]|0)>>2)+1|0,m=GZ(o)|0,m>>>0<d>>>0)sn(o);else{k=n[o>>2]|0,M=(n[o+8>>2]|0)-k|0,R=M>>1,f3e(u,M>>2>>>0<m>>>1>>>0?R>>>0<d>>>0?d:R:m,(n[A>>2]|0)-k>>2,o+8|0),m=u+8|0,n[n[m>>2]>>2]=n[l>>2],n[m>>2]=(n[m>>2]|0)+4,A3e(o,u),p3e(u),I=B;return}}function Ob(o){return o=o|0,n[o>>2]|0}function Y4e(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,V4e(o,l,u,A,d,m)}function KM(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-4-A|0)>>>2)<<2)),It(u))}function np(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-4-A|0)>>>2)<<2)),It(u))}function V4e(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0;var B=0,k=0,R=0,M=0,L=0,q=0;B=I,I=I+48|0,L=B+40|0,k=B+32|0,q=B+24|0,R=B+12|0,M=B,Fl(k),o=Os(o)|0,n[q>>2]=n[l>>2],u=n[u>>2]|0,A=n[A>>2]|0,zM(R,d),J4e(M,m),n[L>>2]=n[q>>2],K4e(o,L,u,A,R,M),KM(M),np(R),Nl(k),I=B}function zM(o,l){o=o|0,l=l|0;var u=0,A=0;n[o>>2]=0,n[o+4>>2]=0,n[o+8>>2]=0,u=l+4|0,A=(n[u>>2]|0)-(n[l>>2]|0)>>2,A|0&&(c3e(o,A),u3e(o,n[l>>2]|0,n[u>>2]|0,A))}function J4e(o,l){o=o|0,l=l|0;var u=0,A=0;n[o>>2]=0,n[o+4>>2]=0,n[o+8>>2]=0,u=l+4|0,A=(n[u>>2]|0)-(n[l>>2]|0)>>2,A|0&&(a3e(o,A),l3e(o,n[l>>2]|0,n[u>>2]|0,A))}function K4e(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0;var B=0,k=0,R=0,M=0,L=0,q=0;B=I,I=I+32|0,L=B+28|0,q=B+24|0,k=B+12|0,R=B,M=da(z4e()|0)|0,n[q>>2]=n[l>>2],n[L>>2]=n[q>>2],l=fd(L)|0,u=MZ(u)|0,A=ZM(A)|0,n[k>>2]=n[d>>2],L=d+4|0,n[k+4>>2]=n[L>>2],q=d+8|0,n[k+8>>2]=n[q>>2],n[q>>2]=0,n[L>>2]=0,n[d>>2]=0,d=XM(k)|0,n[R>>2]=n[m>>2],L=m+4|0,n[R+4>>2]=n[L>>2],q=m+8|0,n[R+8>>2]=n[q>>2],n[q>>2]=0,n[L>>2]=0,n[m>>2]=0,lu(0,M|0,o|0,l|0,u|0,A|0,d|0,Z4e(R)|0)|0,KM(R),np(k),I=B}function z4e(){var o=0;return s[7968]|0||(s3e(10708),o=7968,n[o>>2]=1,n[o+4>>2]=0),10708}function fd(o){return o=o|0,_Z(o)|0}function MZ(o){return o=o|0,UZ(o)|0}function ZM(o){return o=o|0,Tb(o)|0}function XM(o){return o=o|0,$4e(o)|0}function Z4e(o){return o=o|0,X4e(o)|0}function X4e(o){o=o|0;var l=0,u=0,A=0;if(A=(n[o+4>>2]|0)-(n[o>>2]|0)|0,u=A>>2,A=Tl(A+4|0)|0,n[A>>2]=u,u|0){l=0;do n[A+4+(l<<2)>>2]=UZ(n[(n[o>>2]|0)+(l<<2)>>2]|0)|0,l=l+1|0;while((l|0)!=(u|0))}return A|0}function UZ(o){return o=o|0,o|0}function $4e(o){o=o|0;var l=0,u=0,A=0;if(A=(n[o+4>>2]|0)-(n[o>>2]|0)|0,u=A>>2,A=Tl(A+4|0)|0,n[A>>2]=u,u|0){l=0;do n[A+4+(l<<2)>>2]=_Z((n[o>>2]|0)+(l<<2)|0)|0,l=l+1|0;while((l|0)!=(u|0))}return A|0}function _Z(o){o=o|0;var l=0,u=0,A=0,d=0;return d=I,I=I+32|0,l=d+12|0,u=d,A=uM(HZ()|0)|0,A?(fM(l,A),AM(u,l),Nje(o,u),o=pM(l)|0):o=e3e(o)|0,I=d,o|0}function HZ(){var o=0;return s[7960]|0||(i3e(10664),gr(25,10664,U|0)|0,o=7960,n[o>>2]=1,n[o+4>>2]=0),10664}function e3e(o){o=o|0;var l=0,u=0,A=0,d=0,m=0,B=0,k=0;return u=I,I=I+16|0,d=u+4|0,B=u,A=Tl(8)|0,l=A,k=Kt(4)|0,n[k>>2]=n[o>>2],m=l+4|0,n[m>>2]=k,o=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],jZ(o,m,d),n[A>>2]=o,I=u,l|0}function jZ(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,u=Kt(16)|0,n[u+4>>2]=0,n[u+8>>2]=0,n[u>>2]=1656,n[u+12>>2]=l,n[o+4>>2]=u}function t3e(o){o=o|0,$y(o),It(o)}function r3e(o){o=o|0,o=n[o+12>>2]|0,o|0&&It(o)}function n3e(o){o=o|0,It(o)}function i3e(o){o=o|0,Lh(o)}function s3e(o){o=o|0,Qo(o,o3e()|0,5)}function o3e(){return 1676}function a3e(o,l){o=o|0,l=l|0;var u=0;if((GZ(o)|0)>>>0<l>>>0&&sn(o),l>>>0>1073741823)Nt();else{u=Kt(l<<2)|0,n[o+4>>2]=u,n[o>>2]=u,n[o+8>>2]=u+(l<<2);return}}function l3e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,A=o+4|0,o=u-l|0,(o|0)>0&&(Qr(n[A>>2]|0,l|0,o|0)|0,n[A>>2]=(n[A>>2]|0)+(o>>>2<<2))}function GZ(o){return o=o|0,1073741823}function c3e(o,l){o=o|0,l=l|0;var u=0;if((qZ(o)|0)>>>0<l>>>0&&sn(o),l>>>0>1073741823)Nt();else{u=Kt(l<<2)|0,n[o+4>>2]=u,n[o>>2]=u,n[o+8>>2]=u+(l<<2);return}}function u3e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,A=o+4|0,o=u-l|0,(o|0)>0&&(Qr(n[A>>2]|0,l|0,o|0)|0,n[A>>2]=(n[A>>2]|0)+(o>>>2<<2))}function qZ(o){return o=o|0,1073741823}function f3e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>1073741823)Nt();else{d=Kt(l<<2)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<2)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<2)}function A3e(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>2)<<2)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function p3e(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-4-l|0)>>>2)<<2)),o=n[o>>2]|0,o|0&&It(o)}function WZ(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>1073741823)Nt();else{d=Kt(l<<2)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<2)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<2)}function YZ(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>2)<<2)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function VZ(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-4-l|0)>>>2)<<2)),o=n[o>>2]|0,o|0&&It(o)}function h3e(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0;var m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0,Ye=0,Le=0,Qe=0;if(Qe=I,I=I+32|0,L=Qe+20|0,q=Qe+12|0,M=Qe+16|0,ae=Qe+4|0,Ye=Qe,Le=Qe+8|0,k=NZ()|0,m=n[k>>2]|0,B=n[m>>2]|0,B|0)for(R=n[k+8>>2]|0,k=n[k+4>>2]|0;Pu(L,B),g3e(o,L,k,R),m=m+4|0,B=n[m>>2]|0,B;)R=R+1|0,k=k+1|0;if(m=OZ()|0,B=n[m>>2]|0,B|0)do Pu(L,B),n[q>>2]=n[m+4>>2],d3e(l,L,q),m=m+8|0,B=n[m>>2]|0;while(B|0);if(m=n[(Jy()|0)>>2]|0,m|0)do l=n[m+4>>2]|0,Pu(L,n[(Ky(l)|0)>>2]|0),n[q>>2]=WM(l)|0,m3e(u,L,q),m=n[m>>2]|0;while(m|0);if(Pu(M,0),m=YM()|0,n[L>>2]=n[M>>2],LZ(L,m,d),m=n[(Jy()|0)>>2]|0,m|0){o=L+4|0,l=L+8|0,u=L+8|0;do{if(R=n[m+4>>2]|0,Pu(q,n[(Ky(R)|0)>>2]|0),y3e(ae,JZ(R)|0),B=n[ae>>2]|0,B|0){n[L>>2]=0,n[o>>2]=0,n[l>>2]=0;do Pu(Ye,n[(Ky(n[B+4>>2]|0)|0)>>2]|0),k=n[o>>2]|0,k>>>0<(n[u>>2]|0)>>>0?(n[k>>2]=n[Ye>>2],n[o>>2]=(n[o>>2]|0)+4):JM(L,Ye),B=n[B>>2]|0;while(B|0);E3e(A,q,L),np(L)}n[Le>>2]=n[q>>2],M=KZ(R)|0,n[L>>2]=n[Le>>2],LZ(L,M,d),mz(ae),m=n[m>>2]|0}while(m|0)}I=Qe}function g3e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,Q3e(o,l,u,A)}function d3e(o,l,u){o=o|0,l=l|0,u=u|0,k3e(o,l,u)}function Ky(o){return o=o|0,o|0}function m3e(o,l,u){o=o|0,l=l|0,u=u|0,D3e(o,l,u)}function JZ(o){return o=o|0,o+16|0}function y3e(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0;if(m=I,I=I+16|0,d=m+8|0,u=m,n[o>>2]=0,A=n[l>>2]|0,n[d>>2]=A,n[u>>2]=o,u=S3e(u)|0,A|0){if(A=Kt(12)|0,B=(zZ(d)|0)+4|0,o=n[B+4>>2]|0,l=A+4|0,n[l>>2]=n[B>>2],n[l+4>>2]=o,l=n[n[d>>2]>>2]|0,n[d>>2]=l,!l)o=A;else for(l=A;o=Kt(12)|0,R=(zZ(d)|0)+4|0,k=n[R+4>>2]|0,B=o+4|0,n[B>>2]=n[R>>2],n[B+4>>2]=k,n[l>>2]=o,B=n[n[d>>2]>>2]|0,n[d>>2]=B,B;)l=o;n[o>>2]=n[u>>2],n[u>>2]=A}I=m}function E3e(o,l,u){o=o|0,l=l|0,u=u|0,I3e(o,l,u)}function KZ(o){return o=o|0,o+24|0}function I3e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+32|0,B=A+24|0,d=A+16|0,k=A+12|0,m=A,Fl(d),o=Os(o)|0,n[k>>2]=n[l>>2],zM(m,u),n[B>>2]=n[k>>2],C3e(o,B,m),np(m),Nl(d),I=A}function C3e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=I,I=I+32|0,B=A+16|0,k=A+12|0,d=A,m=da(w3e()|0)|0,n[k>>2]=n[l>>2],n[B>>2]=n[k>>2],l=fd(B)|0,n[d>>2]=n[u>>2],B=u+4|0,n[d+4>>2]=n[B>>2],k=u+8|0,n[d+8>>2]=n[k>>2],n[k>>2]=0,n[B>>2]=0,n[u>>2]=0,Rs(0,m|0,o|0,l|0,XM(d)|0)|0,np(d),I=A}function w3e(){var o=0;return s[7976]|0||(B3e(10720),o=7976,n[o>>2]=1,n[o+4>>2]=0),10720}function B3e(o){o=o|0,Qo(o,v3e()|0,2)}function v3e(){return 1732}function S3e(o){return o=o|0,n[o>>2]|0}function zZ(o){return o=o|0,n[o>>2]|0}function D3e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;A=I,I=I+32|0,m=A+16|0,d=A+8|0,B=A,Fl(d),o=Os(o)|0,n[B>>2]=n[l>>2],u=n[u>>2]|0,n[m>>2]=n[B>>2],ZZ(o,m,u),Nl(d),I=A}function ZZ(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;A=I,I=I+16|0,m=A+4|0,B=A,d=da(P3e()|0)|0,n[B>>2]=n[l>>2],n[m>>2]=n[B>>2],l=fd(m)|0,Rs(0,d|0,o|0,l|0,MZ(u)|0)|0,I=A}function P3e(){var o=0;return s[7984]|0||(b3e(10732),o=7984,n[o>>2]=1,n[o+4>>2]=0),10732}function b3e(o){o=o|0,Qo(o,x3e()|0,2)}function x3e(){return 1744}function k3e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;A=I,I=I+32|0,m=A+16|0,d=A+8|0,B=A,Fl(d),o=Os(o)|0,n[B>>2]=n[l>>2],u=n[u>>2]|0,n[m>>2]=n[B>>2],ZZ(o,m,u),Nl(d),I=A}function Q3e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0;d=I,I=I+32|0,B=d+16|0,m=d+8|0,k=d,Fl(m),o=Os(o)|0,n[k>>2]=n[l>>2],u=s[u>>0]|0,A=s[A>>0]|0,n[B>>2]=n[k>>2],R3e(o,B,u,A),Nl(m),I=d}function R3e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0;d=I,I=I+16|0,B=d+4|0,k=d,m=da(T3e()|0)|0,n[k>>2]=n[l>>2],n[B>>2]=n[k>>2],l=fd(B)|0,u=zy(u)|0,Li(0,m|0,o|0,l|0,u|0,zy(A)|0)|0,I=d}function T3e(){var o=0;return s[7992]|0||(N3e(10744),o=7992,n[o>>2]=1,n[o+4>>2]=0),10744}function zy(o){return o=o|0,F3e(o)|0}function F3e(o){return o=o|0,o&255|0}function N3e(o){o=o|0,Qo(o,O3e()|0,3)}function O3e(){return 1756}function L3e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;switch(ae=I,I=I+32|0,k=ae+8|0,R=ae+4|0,M=ae+20|0,L=ae,mM(o,0),A=Fje(l)|0,n[k>>2]=0,q=k+4|0,n[q>>2]=0,n[k+8>>2]=0,A<<24>>24){case 0:{s[M>>0]=0,M3e(R,u,M),Lb(o,R)|0,Df(R);break}case 8:{q=iU(l)|0,s[M>>0]=8,Pu(L,n[q+4>>2]|0),U3e(R,u,M,L,q+8|0),Lb(o,R)|0,Df(R);break}case 9:{if(m=iU(l)|0,l=n[m+4>>2]|0,l|0)for(B=k+8|0,d=m+12|0;l=l+-1|0,Pu(R,n[d>>2]|0),A=n[q>>2]|0,A>>>0<(n[B>>2]|0)>>>0?(n[A>>2]=n[R>>2],n[q>>2]=(n[q>>2]|0)+4):JM(k,R),l;)d=d+4|0;s[M>>0]=9,Pu(L,n[m+8>>2]|0),_3e(R,u,M,L,k),Lb(o,R)|0,Df(R);break}default:q=iU(l)|0,s[M>>0]=A,Pu(L,n[q+4>>2]|0),H3e(R,u,M,L),Lb(o,R)|0,Df(R)}np(k),I=ae}function M3e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0;A=I,I=I+16|0,d=A,Fl(d),l=Os(l)|0,e8e(o,l,s[u>>0]|0),Nl(d),I=A}function Lb(o,l){o=o|0,l=l|0;var u=0;return u=n[o>>2]|0,u|0&&Na(u|0),n[o>>2]=n[l>>2],n[l>>2]=0,o|0}function U3e(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0;var m=0,B=0,k=0,R=0;m=I,I=I+32|0,k=m+16|0,B=m+8|0,R=m,Fl(B),l=Os(l)|0,u=s[u>>0]|0,n[R>>2]=n[A>>2],d=n[d>>2]|0,n[k>>2]=n[R>>2],z3e(o,l,u,k,d),Nl(B),I=m}function _3e(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0;var m=0,B=0,k=0,R=0,M=0;m=I,I=I+32|0,R=m+24|0,B=m+16|0,M=m+12|0,k=m,Fl(B),l=Os(l)|0,u=s[u>>0]|0,n[M>>2]=n[A>>2],zM(k,d),n[R>>2]=n[M>>2],Y3e(o,l,u,R,k),np(k),Nl(B),I=m}function H3e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0;d=I,I=I+32|0,B=d+16|0,m=d+8|0,k=d,Fl(m),l=Os(l)|0,u=s[u>>0]|0,n[k>>2]=n[A>>2],n[B>>2]=n[k>>2],j3e(o,l,u,B),Nl(m),I=d}function j3e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0,B=0,k=0;d=I,I=I+16|0,m=d+4|0,k=d,B=da(G3e()|0)|0,u=zy(u)|0,n[k>>2]=n[A>>2],n[m>>2]=n[k>>2],Mb(o,Rs(0,B|0,l|0,u|0,fd(m)|0)|0),I=d}function G3e(){var o=0;return s[8e3]|0||(q3e(10756),o=8e3,n[o>>2]=1,n[o+4>>2]=0),10756}function Mb(o,l){o=o|0,l=l|0,mM(o,l)}function q3e(o){o=o|0,Qo(o,W3e()|0,2)}function W3e(){return 1772}function Y3e(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0;var m=0,B=0,k=0,R=0,M=0;m=I,I=I+32|0,R=m+16|0,M=m+12|0,B=m,k=da(V3e()|0)|0,u=zy(u)|0,n[M>>2]=n[A>>2],n[R>>2]=n[M>>2],A=fd(R)|0,n[B>>2]=n[d>>2],R=d+4|0,n[B+4>>2]=n[R>>2],M=d+8|0,n[B+8>>2]=n[M>>2],n[M>>2]=0,n[R>>2]=0,n[d>>2]=0,Mb(o,Li(0,k|0,l|0,u|0,A|0,XM(B)|0)|0),np(B),I=m}function V3e(){var o=0;return s[8008]|0||(J3e(10768),o=8008,n[o>>2]=1,n[o+4>>2]=0),10768}function J3e(o){o=o|0,Qo(o,K3e()|0,3)}function K3e(){return 1784}function z3e(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0;var m=0,B=0,k=0,R=0;m=I,I=I+16|0,k=m+4|0,R=m,B=da(Z3e()|0)|0,u=zy(u)|0,n[R>>2]=n[A>>2],n[k>>2]=n[R>>2],A=fd(k)|0,Mb(o,Li(0,B|0,l|0,u|0,A|0,ZM(d)|0)|0),I=m}function Z3e(){var o=0;return s[8016]|0||(X3e(10780),o=8016,n[o>>2]=1,n[o+4>>2]=0),10780}function X3e(o){o=o|0,Qo(o,$3e()|0,3)}function $3e(){return 1800}function e8e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;A=da(t8e()|0)|0,Mb(o,dn(0,A|0,l|0,zy(u)|0)|0)}function t8e(){var o=0;return s[8024]|0||(r8e(10792),o=8024,n[o>>2]=1,n[o+4>>2]=0),10792}function r8e(o){o=o|0,Qo(o,n8e()|0,1)}function n8e(){return 1816}function i8e(){s8e(),o8e(),a8e()}function s8e(){n[2702]=SX(65536)|0}function o8e(){P8e(10856)}function a8e(){l8e(10816)}function l8e(o){o=o|0,c8e(o,5044),u8e(o)|0}function c8e(o,l){o=o|0,l=l|0;var u=0;u=HZ()|0,n[o>>2]=u,C8e(u,l),jh(n[o>>2]|0)}function u8e(o){o=o|0;var l=0;return l=n[o>>2]|0,cd(l,f8e()|0),o|0}function f8e(){var o=0;return s[8032]|0||(XZ(10820),gr(64,10820,U|0)|0,o=8032,n[o>>2]=1,n[o+4>>2]=0),_r(10820)|0||XZ(10820),10820}function XZ(o){o=o|0,h8e(o),ud(o,25)}function A8e(o){o=o|0,p8e(o+24|0)}function p8e(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function h8e(o){o=o|0;var l=0;l=en()|0,tn(o,5,18,l,y8e()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function g8e(o,l){o=o|0,l=l|0,d8e(o,l)}function d8e(o,l){o=o|0,l=l|0;var u=0,A=0,d=0;u=I,I=I+16|0,A=u,d=u+4|0,ad(d,l),n[A>>2]=ld(d,l)|0,m8e(o,A),I=u}function m8e(o,l){o=o|0,l=l|0,$Z(o+4|0,n[l>>2]|0),s[o+8>>0]=1}function $Z(o,l){o=o|0,l=l|0,n[o>>2]=l}function y8e(){return 1824}function E8e(o){return o=o|0,I8e(o)|0}function I8e(o){o=o|0;var l=0,u=0,A=0,d=0,m=0,B=0,k=0;return u=I,I=I+16|0,d=u+4|0,B=u,A=Tl(8)|0,l=A,k=Kt(4)|0,ad(d,o),$Z(k,ld(d,o)|0),m=l+4|0,n[m>>2]=k,o=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],jZ(o,m,d),n[A>>2]=o,I=u,l|0}function Tl(o){o=o|0;var l=0,u=0;return o=o+7&-8,o>>>0<=32768&&(l=n[2701]|0,o>>>0<=(65536-l|0)>>>0)?(u=(n[2702]|0)+l|0,n[2701]=l+o,o=u):(o=SX(o+8|0)|0,n[o>>2]=n[2703],n[2703]=o,o=o+8|0),o|0}function C8e(o,l){o=o|0,l=l|0,n[o>>2]=w8e()|0,n[o+4>>2]=B8e()|0,n[o+12>>2]=l,n[o+8>>2]=v8e()|0,n[o+32>>2]=9}function w8e(){return 11744}function B8e(){return 1832}function v8e(){return Nb()|0}function S8e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,(Hh(A,896)|0)==512?u|0&&(D8e(u),It(u)):l|0&&It(l)}function D8e(o){o=o|0,o=n[o+4>>2]|0,o|0&&Gh(o)}function P8e(o){o=o|0,b8e(o,5052),x8e(o)|0,k8e(o,5058,26)|0,Q8e(o,5069,1)|0,R8e(o,5077,10)|0,T8e(o,5087,19)|0,F8e(o,5094,27)|0}function b8e(o,l){o=o|0,l=l|0;var u=0;u=Dje()|0,n[o>>2]=u,Pje(u,l),jh(n[o>>2]|0)}function x8e(o){o=o|0;var l=0;return l=n[o>>2]|0,cd(l,Aje()|0),o|0}function k8e(o,l,u){return o=o|0,l=l|0,u=u|0,JHe(o,Bn(l)|0,u,0),o|0}function Q8e(o,l,u){return o=o|0,l=l|0,u=u|0,THe(o,Bn(l)|0,u,0),o|0}function R8e(o,l,u){return o=o|0,l=l|0,u=u|0,fHe(o,Bn(l)|0,u,0),o|0}function T8e(o,l,u){return o=o|0,l=l|0,u=u|0,z8e(o,Bn(l)|0,u,0),o|0}function eX(o,l){o=o|0,l=l|0;var u=0,A=0;e:for(;;){for(u=n[2703]|0;;){if((u|0)==(l|0))break e;if(A=n[u>>2]|0,n[2703]=A,!u)u=A;else break}It(u)}n[2701]=o}function F8e(o,l,u){return o=o|0,l=l|0,u=u|0,N8e(o,Bn(l)|0,u,0),o|0}function N8e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=n[o>>2]|0,d=$M()|0,o=O8e(u)|0,vn(m,l,d,o,L8e(u,A)|0,A)}function $M(){var o=0,l=0;if(s[8040]|0||(rX(10860),gr(65,10860,U|0)|0,l=8040,n[l>>2]=1,n[l+4>>2]=0),!(_r(10860)|0)){o=10860,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));rX(10860)}return 10860}function O8e(o){return o=o|0,o|0}function L8e(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,R=$M()|0,B=R+24|0,l=yr(l,4)|0,n[m>>2]=l,u=R+28|0,A=n[u>>2]|0,A>>>0<(n[R+32>>2]|0)>>>0?(tX(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(M8e(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function tX(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function M8e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=U8e(o)|0,A>>>0<B>>>0)sn(o);else{R=n[o>>2]|0,L=(n[o+8>>2]|0)-R|0,M=L>>2,_8e(d,L>>3>>>0<A>>>1>>>0?M>>>0<B>>>0?B:M:A,(n[m>>2]|0)-R>>3,o+8|0),B=d+8|0,tX(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,H8e(o,d),j8e(d),I=k;return}}function U8e(o){return o=o|0,536870911}function _8e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function H8e(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function j8e(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function rX(o){o=o|0,W8e(o)}function G8e(o){o=o|0,q8e(o+24|0)}function q8e(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function W8e(o){o=o|0;var l=0;l=en()|0,tn(o,1,11,l,Y8e()|0,2),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function Y8e(){return 1840}function V8e(o,l,u){o=o|0,l=l|0,u=u|0,K8e(n[(J8e(o)|0)>>2]|0,l,u)}function J8e(o){return o=o|0,(n[($M()|0)+24>>2]|0)+(o<<3)|0}function K8e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;A=I,I=I+16|0,m=A+1|0,d=A,ad(m,l),l=ld(m,l)|0,ad(d,u),u=ld(d,u)|0,sp[o&31](l,u),I=A}function z8e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=n[o>>2]|0,d=eU()|0,o=Z8e(u)|0,vn(m,l,d,o,X8e(u,A)|0,A)}function eU(){var o=0,l=0;if(s[8048]|0||(iX(10896),gr(66,10896,U|0)|0,l=8048,n[l>>2]=1,n[l+4>>2]=0),!(_r(10896)|0)){o=10896,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));iX(10896)}return 10896}function Z8e(o){return o=o|0,o|0}function X8e(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,R=eU()|0,B=R+24|0,l=yr(l,4)|0,n[m>>2]=l,u=R+28|0,A=n[u>>2]|0,A>>>0<(n[R+32>>2]|0)>>>0?(nX(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):($8e(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function nX(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function $8e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=eHe(o)|0,A>>>0<B>>>0)sn(o);else{R=n[o>>2]|0,L=(n[o+8>>2]|0)-R|0,M=L>>2,tHe(d,L>>3>>>0<A>>>1>>>0?M>>>0<B>>>0?B:M:A,(n[m>>2]|0)-R>>3,o+8|0),B=d+8|0,nX(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,rHe(o,d),nHe(d),I=k;return}}function eHe(o){return o=o|0,536870911}function tHe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function rHe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function nHe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function iX(o){o=o|0,oHe(o)}function iHe(o){o=o|0,sHe(o+24|0)}function sHe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function oHe(o){o=o|0;var l=0;l=en()|0,tn(o,1,11,l,aHe()|0,1),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function aHe(){return 1852}function lHe(o,l){return o=o|0,l=l|0,uHe(n[(cHe(o)|0)>>2]|0,l)|0}function cHe(o){return o=o|0,(n[(eU()|0)+24>>2]|0)+(o<<3)|0}function uHe(o,l){o=o|0,l=l|0;var u=0,A=0;return u=I,I=I+16|0,A=u,ad(A,l),l=ld(A,l)|0,l=Tb(gd[o&31](l)|0)|0,I=u,l|0}function fHe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=n[o>>2]|0,d=tU()|0,o=AHe(u)|0,vn(m,l,d,o,pHe(u,A)|0,A)}function tU(){var o=0,l=0;if(s[8056]|0||(oX(10932),gr(67,10932,U|0)|0,l=8056,n[l>>2]=1,n[l+4>>2]=0),!(_r(10932)|0)){o=10932,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));oX(10932)}return 10932}function AHe(o){return o=o|0,o|0}function pHe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,R=tU()|0,B=R+24|0,l=yr(l,4)|0,n[m>>2]=l,u=R+28|0,A=n[u>>2]|0,A>>>0<(n[R+32>>2]|0)>>>0?(sX(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(hHe(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function sX(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function hHe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=gHe(o)|0,A>>>0<B>>>0)sn(o);else{R=n[o>>2]|0,L=(n[o+8>>2]|0)-R|0,M=L>>2,dHe(d,L>>3>>>0<A>>>1>>>0?M>>>0<B>>>0?B:M:A,(n[m>>2]|0)-R>>3,o+8|0),B=d+8|0,sX(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,mHe(o,d),yHe(d),I=k;return}}function gHe(o){return o=o|0,536870911}function dHe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function mHe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function yHe(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function oX(o){o=o|0,CHe(o)}function EHe(o){o=o|0,IHe(o+24|0)}function IHe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function CHe(o){o=o|0;var l=0;l=en()|0,tn(o,1,7,l,wHe()|0,2),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function wHe(){return 1860}function BHe(o,l,u){return o=o|0,l=l|0,u=u|0,SHe(n[(vHe(o)|0)>>2]|0,l,u)|0}function vHe(o){return o=o|0,(n[(tU()|0)+24>>2]|0)+(o<<3)|0}function SHe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0;return A=I,I=I+32|0,B=A+12|0,m=A+8|0,k=A,R=A+16|0,d=A+4|0,DHe(R,l),PHe(k,R,l),Mh(d,u),u=Uh(d,u)|0,n[B>>2]=n[k>>2],F2[o&15](m,B,u),u=bHe(m)|0,Df(m),_h(d),I=A,u|0}function DHe(o,l){o=o|0,l=l|0}function PHe(o,l,u){o=o|0,l=l|0,u=u|0,xHe(o,u)}function bHe(o){return o=o|0,Os(o)|0}function xHe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0;d=I,I=I+16|0,u=d,A=l,A&1?(kHe(u,0),Me(A|0,u|0)|0,QHe(o,u),RHe(u)):n[o>>2]=n[l>>2],I=d}function kHe(o,l){o=o|0,l=l|0,Su(o,l),n[o+4>>2]=0,s[o+8>>0]=0}function QHe(o,l){o=o|0,l=l|0,n[o>>2]=n[l+4>>2]}function RHe(o){o=o|0,s[o+8>>0]=0}function THe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=n[o>>2]|0,d=rU()|0,o=FHe(u)|0,vn(m,l,d,o,NHe(u,A)|0,A)}function rU(){var o=0,l=0;if(s[8064]|0||(lX(10968),gr(68,10968,U|0)|0,l=8064,n[l>>2]=1,n[l+4>>2]=0),!(_r(10968)|0)){o=10968,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));lX(10968)}return 10968}function FHe(o){return o=o|0,o|0}function NHe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,R=rU()|0,B=R+24|0,l=yr(l,4)|0,n[m>>2]=l,u=R+28|0,A=n[u>>2]|0,A>>>0<(n[R+32>>2]|0)>>>0?(aX(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(OHe(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function aX(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function OHe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=LHe(o)|0,A>>>0<B>>>0)sn(o);else{R=n[o>>2]|0,L=(n[o+8>>2]|0)-R|0,M=L>>2,MHe(d,L>>3>>>0<A>>>1>>>0?M>>>0<B>>>0?B:M:A,(n[m>>2]|0)-R>>3,o+8|0),B=d+8|0,aX(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,UHe(o,d),_He(d),I=k;return}}function LHe(o){return o=o|0,536870911}function MHe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function UHe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function _He(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function lX(o){o=o|0,GHe(o)}function HHe(o){o=o|0,jHe(o+24|0)}function jHe(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function GHe(o){o=o|0;var l=0;l=en()|0,tn(o,1,1,l,qHe()|0,5),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function qHe(){return 1872}function WHe(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,VHe(n[(YHe(o)|0)>>2]|0,l,u,A,d,m)}function YHe(o){return o=o|0,(n[(rU()|0)+24>>2]|0)+(o<<3)|0}function VHe(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0;var B=0,k=0,R=0,M=0,L=0,q=0;B=I,I=I+32|0,k=B+16|0,R=B+12|0,M=B+8|0,L=B+4|0,q=B,Mh(k,l),l=Uh(k,l)|0,Mh(R,u),u=Uh(R,u)|0,Mh(M,A),A=Uh(M,A)|0,Mh(L,d),d=Uh(L,d)|0,Mh(q,m),m=Uh(q,m)|0,kX[o&1](l,u,A,d,m),_h(q),_h(L),_h(M),_h(R),_h(k),I=B}function JHe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;m=n[o>>2]|0,d=nU()|0,o=KHe(u)|0,vn(m,l,d,o,zHe(u,A)|0,A)}function nU(){var o=0,l=0;if(s[8072]|0||(uX(11004),gr(69,11004,U|0)|0,l=8072,n[l>>2]=1,n[l+4>>2]=0),!(_r(11004)|0)){o=11004,l=o+36|0;do n[o>>2]=0,o=o+4|0;while((o|0)<(l|0));uX(11004)}return 11004}function KHe(o){return o=o|0,o|0}function zHe(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0,k=0,R=0;return k=I,I=I+16|0,d=k,m=k+4|0,n[d>>2]=o,R=nU()|0,B=R+24|0,l=yr(l,4)|0,n[m>>2]=l,u=R+28|0,A=n[u>>2]|0,A>>>0<(n[R+32>>2]|0)>>>0?(cX(A,o,l),l=(n[u>>2]|0)+8|0,n[u>>2]=l):(ZHe(B,d,m),l=n[u>>2]|0),I=k,(l-(n[B>>2]|0)>>3)+-1|0}function cX(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,n[o+4>>2]=u}function ZHe(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0;if(k=I,I=I+32|0,d=k,m=o+4|0,B=((n[m>>2]|0)-(n[o>>2]|0)>>3)+1|0,A=XHe(o)|0,A>>>0<B>>>0)sn(o);else{R=n[o>>2]|0,L=(n[o+8>>2]|0)-R|0,M=L>>2,$He(d,L>>3>>>0<A>>>1>>>0?M>>>0<B>>>0?B:M:A,(n[m>>2]|0)-R>>3,o+8|0),B=d+8|0,cX(n[B>>2]|0,n[l>>2]|0,n[u>>2]|0),n[B>>2]=(n[B>>2]|0)+8,eje(o,d),tje(d),I=k;return}}function XHe(o){return o=o|0,536870911}function $He(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0;n[o+12>>2]=0,n[o+16>>2]=A;do if(l)if(l>>>0>536870911)Nt();else{d=Kt(l<<3)|0;break}else d=0;while(!1);n[o>>2]=d,A=d+(u<<3)|0,n[o+8>>2]=A,n[o+4>>2]=A,n[o+12>>2]=d+(l<<3)}function eje(o,l){o=o|0,l=l|0;var u=0,A=0,d=0,m=0,B=0;A=n[o>>2]|0,B=o+4|0,m=l+4|0,d=(n[B>>2]|0)-A|0,u=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=u,(d|0)>0?(Qr(u|0,A|0,d|0)|0,A=m,u=n[m>>2]|0):A=m,m=n[o>>2]|0,n[o>>2]=u,n[A>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=o+8|0,B=l+12|0,o=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=o,n[l>>2]=n[A>>2]}function tje(o){o=o|0;var l=0,u=0,A=0;l=n[o+4>>2]|0,u=o+8|0,A=n[u>>2]|0,(A|0)!=(l|0)&&(n[u>>2]=A+(~((A+-8-l|0)>>>3)<<3)),o=n[o>>2]|0,o|0&&It(o)}function uX(o){o=o|0,ije(o)}function rje(o){o=o|0,nje(o+24|0)}function nje(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function ije(o){o=o|0;var l=0;l=en()|0,tn(o,1,12,l,sje()|0,2),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function sje(){return 1896}function oje(o,l,u){o=o|0,l=l|0,u=u|0,lje(n[(aje(o)|0)>>2]|0,l,u)}function aje(o){return o=o|0,(n[(nU()|0)+24>>2]|0)+(o<<3)|0}function lje(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;A=I,I=I+16|0,m=A+4|0,d=A,cje(m,l),l=uje(m,l)|0,Mh(d,u),u=Uh(d,u)|0,sp[o&31](l,u),_h(d),I=A}function cje(o,l){o=o|0,l=l|0}function uje(o,l){return o=o|0,l=l|0,fje(l)|0}function fje(o){return o=o|0,o|0}function Aje(){var o=0;return s[8080]|0||(fX(11040),gr(70,11040,U|0)|0,o=8080,n[o>>2]=1,n[o+4>>2]=0),_r(11040)|0||fX(11040),11040}function fX(o){o=o|0,gje(o),ud(o,71)}function pje(o){o=o|0,hje(o+24|0)}function hje(o){o=o|0;var l=0,u=0,A=0;u=n[o>>2]|0,A=u,u|0&&(o=o+4|0,l=n[o>>2]|0,(l|0)!=(u|0)&&(n[o>>2]=l+(~((l+-8-A|0)>>>3)<<3)),It(u))}function gje(o){o=o|0;var l=0;l=en()|0,tn(o,5,7,l,Eje()|0,0),n[o+24>>2]=0,n[o+28>>2]=0,n[o+32>>2]=0}function dje(o){o=o|0,mje(o)}function mje(o){o=o|0,yje(o)}function yje(o){o=o|0,s[o+8>>0]=1}function Eje(){return 1936}function Ije(){return Cje()|0}function Cje(){var o=0,l=0,u=0,A=0,d=0,m=0,B=0;return l=I,I=I+16|0,d=l+4|0,B=l,u=Tl(8)|0,o=u,m=o+4|0,n[m>>2]=Kt(1)|0,A=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],wje(A,m,d),n[u>>2]=A,I=l,o|0}function wje(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]=l,u=Kt(16)|0,n[u+4>>2]=0,n[u+8>>2]=0,n[u>>2]=1916,n[u+12>>2]=l,n[o+4>>2]=u}function Bje(o){o=o|0,$y(o),It(o)}function vje(o){o=o|0,o=n[o+12>>2]|0,o|0&&It(o)}function Sje(o){o=o|0,It(o)}function Dje(){var o=0;return s[8088]|0||(Tje(11076),gr(25,11076,U|0)|0,o=8088,n[o>>2]=1,n[o+4>>2]=0),11076}function Pje(o,l){o=o|0,l=l|0,n[o>>2]=bje()|0,n[o+4>>2]=xje()|0,n[o+12>>2]=l,n[o+8>>2]=kje()|0,n[o+32>>2]=10}function bje(){return 11745}function xje(){return 1940}function kje(){return Fb()|0}function Qje(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,(Hh(A,896)|0)==512?u|0&&(Rje(u),It(u)):l|0&&It(l)}function Rje(o){o=o|0,o=n[o+4>>2]|0,o|0&&Gh(o)}function Tje(o){o=o|0,Lh(o)}function Pu(o,l){o=o|0,l=l|0,n[o>>2]=l}function iU(o){return o=o|0,n[o>>2]|0}function Fje(o){return o=o|0,s[n[o>>2]>>0]|0}function Nje(o,l){o=o|0,l=l|0;var u=0,A=0;u=I,I=I+16|0,A=u,n[A>>2]=n[o>>2],Oje(l,A)|0,I=u}function Oje(o,l){o=o|0,l=l|0;var u=0;return u=Lje(n[o>>2]|0,l)|0,l=o+4|0,n[(n[l>>2]|0)+8>>2]=u,n[(n[l>>2]|0)+8>>2]|0}function Lje(o,l){o=o|0,l=l|0;var u=0,A=0;return u=I,I=I+16|0,A=u,Fl(A),o=Os(o)|0,l=Mje(o,n[l>>2]|0)|0,Nl(A),I=u,l|0}function Fl(o){o=o|0,n[o>>2]=n[2701],n[o+4>>2]=n[2703]}function Mje(o,l){o=o|0,l=l|0;var u=0;return u=da(Uje()|0)|0,dn(0,u|0,o|0,ZM(l)|0)|0}function Nl(o){o=o|0,eX(n[o>>2]|0,n[o+4>>2]|0)}function Uje(){var o=0;return s[8096]|0||(_je(11120),o=8096,n[o>>2]=1,n[o+4>>2]=0),11120}function _je(o){o=o|0,Qo(o,Hje()|0,1)}function Hje(){return 1948}function jje(){Gje()}function Gje(){var o=0,l=0,u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0,Ye=0,Le=0,Qe=0;if(Le=I,I=I+16|0,L=Le+4|0,q=Le,oa(65536,10804,n[2702]|0,10812),u=NZ()|0,l=n[u>>2]|0,o=n[l>>2]|0,o|0)for(A=n[u+8>>2]|0,u=n[u+4>>2]|0;pf(o|0,c[u>>0]|0|0,s[A>>0]|0),l=l+4|0,o=n[l>>2]|0,o;)A=A+1|0,u=u+1|0;if(o=OZ()|0,l=n[o>>2]|0,l|0)do NA(l|0,n[o+4>>2]|0),o=o+8|0,l=n[o>>2]|0;while(l|0);NA(qje()|0,5167),M=Jy()|0,o=n[M>>2]|0;e:do if(o|0){do Wje(n[o+4>>2]|0),o=n[o>>2]|0;while(o|0);if(o=n[M>>2]|0,o|0){R=M;do{for(;d=o,o=n[o>>2]|0,d=n[d+4>>2]|0,!!(Yje(d)|0);)if(n[q>>2]=R,n[L>>2]=n[q>>2],Vje(M,L)|0,!o)break e;if(Jje(d),R=n[R>>2]|0,l=AX(d)|0,m=Oi()|0,B=I,I=I+((1*(l<<2)|0)+15&-16)|0,k=I,I=I+((1*(l<<2)|0)+15&-16)|0,l=n[(JZ(d)|0)>>2]|0,l|0)for(u=B,A=k;n[u>>2]=n[(Ky(n[l+4>>2]|0)|0)>>2],n[A>>2]=n[l+8>>2],l=n[l>>2]|0,l;)u=u+4|0,A=A+4|0;Qe=Ky(d)|0,l=Kje(d)|0,u=AX(d)|0,A=zje(d)|0,oc(Qe|0,l|0,B|0,k|0,u|0,A|0,WM(d)|0),FA(m|0)}while(o|0)}}while(!1);if(o=n[(YM()|0)>>2]|0,o|0)do Qe=o+4|0,M=VM(Qe)|0,d=k2(M)|0,m=b2(M)|0,B=(x2(M)|0)+1|0,k=Ub(M)|0,R=pX(Qe)|0,M=_r(M)|0,L=Ob(Qe)|0,q=sU(Qe)|0,uu(0,d|0,m|0,B|0,k|0,R|0,M|0,L|0,q|0,oU(Qe)|0),o=n[o>>2]|0;while(o|0);o=n[(Jy()|0)>>2]|0;e:do if(o|0){t:for(;;){if(l=n[o+4>>2]|0,l|0&&(ae=n[(Ky(l)|0)>>2]|0,Ye=n[(KZ(l)|0)>>2]|0,Ye|0)){u=Ye;do{l=u+4|0,A=VM(l)|0;r:do if(A|0)switch(_r(A)|0){case 0:break t;case 4:case 3:case 2:{k=k2(A)|0,R=b2(A)|0,M=(x2(A)|0)+1|0,L=Ub(A)|0,q=_r(A)|0,Qe=Ob(l)|0,uu(ae|0,k|0,R|0,M|0,L|0,0,q|0,Qe|0,sU(l)|0,oU(l)|0);break r}case 1:{B=k2(A)|0,k=b2(A)|0,R=(x2(A)|0)+1|0,M=Ub(A)|0,L=pX(l)|0,q=_r(A)|0,Qe=Ob(l)|0,uu(ae|0,B|0,k|0,R|0,M|0,L|0,q|0,Qe|0,sU(l)|0,oU(l)|0);break r}case 5:{M=k2(A)|0,L=b2(A)|0,q=(x2(A)|0)+1|0,Qe=Ub(A)|0,uu(ae|0,M|0,L|0,q|0,Qe|0,Zje(A)|0,_r(A)|0,0,0,0);break r}default:break r}while(!1);u=n[u>>2]|0}while(u|0)}if(o=n[o>>2]|0,!o)break e}Nt()}while(!1);ve(),I=Le}function qje(){return 11703}function Wje(o){o=o|0,s[o+40>>0]=0}function Yje(o){return o=o|0,(s[o+40>>0]|0)!=0|0}function Vje(o,l){return o=o|0,l=l|0,l=Xje(l)|0,o=n[l>>2]|0,n[l>>2]=n[o>>2],It(o),n[l>>2]|0}function Jje(o){o=o|0,s[o+40>>0]=1}function AX(o){return o=o|0,n[o+20>>2]|0}function Kje(o){return o=o|0,n[o+8>>2]|0}function zje(o){return o=o|0,n[o+32>>2]|0}function Ub(o){return o=o|0,n[o+4>>2]|0}function pX(o){return o=o|0,n[o+4>>2]|0}function sU(o){return o=o|0,n[o+8>>2]|0}function oU(o){return o=o|0,n[o+16>>2]|0}function Zje(o){return o=o|0,n[o+20>>2]|0}function Xje(o){return o=o|0,n[o>>2]|0}function _b(o){o=o|0;var l=0,u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0,Ye=0,Le=0,Qe=0,tt=0,Xe=0,ct=0,He=0,We=0,Lt=0;Lt=I,I=I+16|0,ae=Lt;do if(o>>>0<245){if(M=o>>>0<11?16:o+11&-8,o=M>>>3,q=n[2783]|0,u=q>>>o,u&3|0)return l=(u&1^1)+o|0,o=11172+(l<<1<<2)|0,u=o+8|0,A=n[u>>2]|0,d=A+8|0,m=n[d>>2]|0,(o|0)==(m|0)?n[2783]=q&~(1<<l):(n[m+12>>2]=o,n[u>>2]=m),We=l<<3,n[A+4>>2]=We|3,We=A+We+4|0,n[We>>2]=n[We>>2]|1,We=d,I=Lt,We|0;if(L=n[2785]|0,M>>>0>L>>>0){if(u|0)return l=2<<o,l=u<<o&(l|0-l),l=(l&0-l)+-1|0,B=l>>>12&16,l=l>>>B,u=l>>>5&8,l=l>>>u,d=l>>>2&4,l=l>>>d,o=l>>>1&2,l=l>>>o,A=l>>>1&1,A=(u|B|d|o|A)+(l>>>A)|0,l=11172+(A<<1<<2)|0,o=l+8|0,d=n[o>>2]|0,B=d+8|0,u=n[B>>2]|0,(l|0)==(u|0)?(o=q&~(1<<A),n[2783]=o):(n[u+12>>2]=l,n[o>>2]=u,o=q),m=(A<<3)-M|0,n[d+4>>2]=M|3,A=d+M|0,n[A+4>>2]=m|1,n[A+m>>2]=m,L|0&&(d=n[2788]|0,l=L>>>3,u=11172+(l<<1<<2)|0,l=1<<l,o&l?(o=u+8|0,l=n[o>>2]|0):(n[2783]=o|l,l=u,o=u+8|0),n[o>>2]=d,n[l+12>>2]=d,n[d+8>>2]=l,n[d+12>>2]=u),n[2785]=m,n[2788]=A,We=B,I=Lt,We|0;if(k=n[2784]|0,k){if(u=(k&0-k)+-1|0,B=u>>>12&16,u=u>>>B,m=u>>>5&8,u=u>>>m,R=u>>>2&4,u=u>>>R,A=u>>>1&2,u=u>>>A,o=u>>>1&1,o=n[11436+((m|B|R|A|o)+(u>>>o)<<2)>>2]|0,u=(n[o+4>>2]&-8)-M|0,A=n[o+16+(((n[o+16>>2]|0)==0&1)<<2)>>2]|0,!A)R=o,m=u;else{do B=(n[A+4>>2]&-8)-M|0,R=B>>>0<u>>>0,u=R?B:u,o=R?A:o,A=n[A+16+(((n[A+16>>2]|0)==0&1)<<2)>>2]|0;while(A|0);R=o,m=u}if(B=R+M|0,R>>>0<B>>>0){d=n[R+24>>2]|0,l=n[R+12>>2]|0;do if((l|0)==(R|0)){if(o=R+20|0,l=n[o>>2]|0,!l&&(o=R+16|0,l=n[o>>2]|0,!l)){u=0;break}for(;;){if(u=l+20|0,A=n[u>>2]|0,A|0){l=A,o=u;continue}if(u=l+16|0,A=n[u>>2]|0,A)l=A,o=u;else break}n[o>>2]=0,u=l}else u=n[R+8>>2]|0,n[u+12>>2]=l,n[l+8>>2]=u,u=l;while(!1);do if(d|0){if(l=n[R+28>>2]|0,o=11436+(l<<2)|0,(R|0)==(n[o>>2]|0)){if(n[o>>2]=u,!u){n[2784]=k&~(1<<l);break}}else if(n[d+16+(((n[d+16>>2]|0)!=(R|0)&1)<<2)>>2]=u,!u)break;n[u+24>>2]=d,l=n[R+16>>2]|0,l|0&&(n[u+16>>2]=l,n[l+24>>2]=u),l=n[R+20>>2]|0,l|0&&(n[u+20>>2]=l,n[l+24>>2]=u)}while(!1);return m>>>0<16?(We=m+M|0,n[R+4>>2]=We|3,We=R+We+4|0,n[We>>2]=n[We>>2]|1):(n[R+4>>2]=M|3,n[B+4>>2]=m|1,n[B+m>>2]=m,L|0&&(A=n[2788]|0,l=L>>>3,u=11172+(l<<1<<2)|0,l=1<<l,q&l?(o=u+8|0,l=n[o>>2]|0):(n[2783]=q|l,l=u,o=u+8|0),n[o>>2]=A,n[l+12>>2]=A,n[A+8>>2]=l,n[A+12>>2]=u),n[2785]=m,n[2788]=B),We=R+8|0,I=Lt,We|0}else q=M}else q=M}else q=M}else if(o>>>0<=4294967231)if(o=o+11|0,M=o&-8,R=n[2784]|0,R){A=0-M|0,o=o>>>8,o?M>>>0>16777215?k=31:(q=(o+1048320|0)>>>16&8,He=o<<q,L=(He+520192|0)>>>16&4,He=He<<L,k=(He+245760|0)>>>16&2,k=14-(L|q|k)+(He<<k>>>15)|0,k=M>>>(k+7|0)&1|k<<1):k=0,u=n[11436+(k<<2)>>2]|0;e:do if(!u)u=0,o=0,He=57;else for(o=0,B=M<<((k|0)==31?0:25-(k>>>1)|0),m=0;;){if(d=(n[u+4>>2]&-8)-M|0,d>>>0<A>>>0)if(d)o=u,A=d;else{o=u,A=0,d=u,He=61;break e}if(d=n[u+20>>2]|0,u=n[u+16+(B>>>31<<2)>>2]|0,m=(d|0)==0|(d|0)==(u|0)?m:d,d=(u|0)==0,d){u=m,He=57;break}else B=B<<((d^1)&1)}while(!1);if((He|0)==57){if((u|0)==0&(o|0)==0){if(o=2<<k,o=R&(o|0-o),!o){q=M;break}q=(o&0-o)+-1|0,B=q>>>12&16,q=q>>>B,m=q>>>5&8,q=q>>>m,k=q>>>2&4,q=q>>>k,L=q>>>1&2,q=q>>>L,u=q>>>1&1,o=0,u=n[11436+((m|B|k|L|u)+(q>>>u)<<2)>>2]|0}u?(d=u,He=61):(k=o,B=A)}if((He|0)==61)for(;;)if(He=0,u=(n[d+4>>2]&-8)-M|0,q=u>>>0<A>>>0,u=q?u:A,o=q?d:o,d=n[d+16+(((n[d+16>>2]|0)==0&1)<<2)>>2]|0,d)A=u,He=61;else{k=o,B=u;break}if(k|0&&B>>>0<((n[2785]|0)-M|0)>>>0){if(m=k+M|0,k>>>0>=m>>>0)return We=0,I=Lt,We|0;d=n[k+24>>2]|0,l=n[k+12>>2]|0;do if((l|0)==(k|0)){if(o=k+20|0,l=n[o>>2]|0,!l&&(o=k+16|0,l=n[o>>2]|0,!l)){l=0;break}for(;;){if(u=l+20|0,A=n[u>>2]|0,A|0){l=A,o=u;continue}if(u=l+16|0,A=n[u>>2]|0,A)l=A,o=u;else break}n[o>>2]=0}else We=n[k+8>>2]|0,n[We+12>>2]=l,n[l+8>>2]=We;while(!1);do if(d){if(o=n[k+28>>2]|0,u=11436+(o<<2)|0,(k|0)==(n[u>>2]|0)){if(n[u>>2]=l,!l){A=R&~(1<<o),n[2784]=A;break}}else if(n[d+16+(((n[d+16>>2]|0)!=(k|0)&1)<<2)>>2]=l,!l){A=R;break}n[l+24>>2]=d,o=n[k+16>>2]|0,o|0&&(n[l+16>>2]=o,n[o+24>>2]=l),o=n[k+20>>2]|0,o&&(n[l+20>>2]=o,n[o+24>>2]=l),A=R}else A=R;while(!1);do if(B>>>0>=16){if(n[k+4>>2]=M|3,n[m+4>>2]=B|1,n[m+B>>2]=B,l=B>>>3,B>>>0<256){u=11172+(l<<1<<2)|0,o=n[2783]|0,l=1<<l,o&l?(o=u+8|0,l=n[o>>2]|0):(n[2783]=o|l,l=u,o=u+8|0),n[o>>2]=m,n[l+12>>2]=m,n[m+8>>2]=l,n[m+12>>2]=u;break}if(l=B>>>8,l?B>>>0>16777215?l=31:(He=(l+1048320|0)>>>16&8,We=l<<He,ct=(We+520192|0)>>>16&4,We=We<<ct,l=(We+245760|0)>>>16&2,l=14-(ct|He|l)+(We<<l>>>15)|0,l=B>>>(l+7|0)&1|l<<1):l=0,u=11436+(l<<2)|0,n[m+28>>2]=l,o=m+16|0,n[o+4>>2]=0,n[o>>2]=0,o=1<<l,!(A&o)){n[2784]=A|o,n[u>>2]=m,n[m+24>>2]=u,n[m+12>>2]=m,n[m+8>>2]=m;break}for(o=B<<((l|0)==31?0:25-(l>>>1)|0),u=n[u>>2]|0;;){if((n[u+4>>2]&-8|0)==(B|0)){He=97;break}if(A=u+16+(o>>>31<<2)|0,l=n[A>>2]|0,l)o=o<<1,u=l;else{He=96;break}}if((He|0)==96){n[A>>2]=m,n[m+24>>2]=u,n[m+12>>2]=m,n[m+8>>2]=m;break}else if((He|0)==97){He=u+8|0,We=n[He>>2]|0,n[We+12>>2]=m,n[He>>2]=m,n[m+8>>2]=We,n[m+12>>2]=u,n[m+24>>2]=0;break}}else We=B+M|0,n[k+4>>2]=We|3,We=k+We+4|0,n[We>>2]=n[We>>2]|1;while(!1);return We=k+8|0,I=Lt,We|0}else q=M}else q=M;else q=-1;while(!1);if(u=n[2785]|0,u>>>0>=q>>>0)return l=u-q|0,o=n[2788]|0,l>>>0>15?(We=o+q|0,n[2788]=We,n[2785]=l,n[We+4>>2]=l|1,n[We+l>>2]=l,n[o+4>>2]=q|3):(n[2785]=0,n[2788]=0,n[o+4>>2]=u|3,We=o+u+4|0,n[We>>2]=n[We>>2]|1),We=o+8|0,I=Lt,We|0;if(B=n[2786]|0,B>>>0>q>>>0)return ct=B-q|0,n[2786]=ct,We=n[2789]|0,He=We+q|0,n[2789]=He,n[He+4>>2]=ct|1,n[We+4>>2]=q|3,We=We+8|0,I=Lt,We|0;if(n[2901]|0?o=n[2903]|0:(n[2903]=4096,n[2902]=4096,n[2904]=-1,n[2905]=-1,n[2906]=0,n[2894]=0,o=ae&-16^1431655768,n[ae>>2]=o,n[2901]=o,o=4096),k=q+48|0,R=q+47|0,m=o+R|0,d=0-o|0,M=m&d,M>>>0<=q>>>0||(o=n[2893]|0,o|0&&(L=n[2891]|0,ae=L+M|0,ae>>>0<=L>>>0|ae>>>0>o>>>0)))return We=0,I=Lt,We|0;e:do if(n[2894]&4)l=0,He=133;else{u=n[2789]|0;t:do if(u){for(A=11580;o=n[A>>2]|0,!(o>>>0<=u>>>0&&(Qe=A+4|0,(o+(n[Qe>>2]|0)|0)>>>0>u>>>0));)if(o=n[A+8>>2]|0,o)A=o;else{He=118;break t}if(l=m-B&d,l>>>0<2147483647)if(o=qh(l|0)|0,(o|0)==((n[A>>2]|0)+(n[Qe>>2]|0)|0)){if((o|0)!=-1){B=l,m=o,He=135;break e}}else A=o,He=126;else l=0}else He=118;while(!1);do if((He|0)==118)if(u=qh(0)|0,(u|0)!=-1&&(l=u,Ye=n[2902]|0,Le=Ye+-1|0,l=(Le&l|0?(Le+l&0-Ye)-l|0:0)+M|0,Ye=n[2891]|0,Le=l+Ye|0,l>>>0>q>>>0&l>>>0<2147483647)){if(Qe=n[2893]|0,Qe|0&&Le>>>0<=Ye>>>0|Le>>>0>Qe>>>0){l=0;break}if(o=qh(l|0)|0,(o|0)==(u|0)){B=l,m=u,He=135;break e}else A=o,He=126}else l=0;while(!1);do if((He|0)==126){if(u=0-l|0,!(k>>>0>l>>>0&(l>>>0<2147483647&(A|0)!=-1)))if((A|0)==-1){l=0;break}else{B=l,m=A,He=135;break e}if(o=n[2903]|0,o=R-l+o&0-o,o>>>0>=2147483647){B=l,m=A,He=135;break e}if((qh(o|0)|0)==-1){qh(u|0)|0,l=0;break}else{B=o+l|0,m=A,He=135;break e}}while(!1);n[2894]=n[2894]|4,He=133}while(!1);if((He|0)==133&&M>>>0<2147483647&&(ct=qh(M|0)|0,Qe=qh(0)|0,tt=Qe-ct|0,Xe=tt>>>0>(q+40|0)>>>0,!((ct|0)==-1|Xe^1|ct>>>0<Qe>>>0&((ct|0)!=-1&(Qe|0)!=-1)^1))&&(B=Xe?tt:l,m=ct,He=135),(He|0)==135){l=(n[2891]|0)+B|0,n[2891]=l,l>>>0>(n[2892]|0)>>>0&&(n[2892]=l),R=n[2789]|0;do if(R){for(l=11580;;){if(o=n[l>>2]|0,u=l+4|0,A=n[u>>2]|0,(m|0)==(o+A|0)){He=145;break}if(d=n[l+8>>2]|0,d)l=d;else break}if((He|0)==145&&!(n[l+12>>2]&8|0)&&R>>>0<m>>>0&R>>>0>=o>>>0){n[u>>2]=A+B,We=R+8|0,We=We&7|0?0-We&7:0,He=R+We|0,We=(n[2786]|0)+(B-We)|0,n[2789]=He,n[2786]=We,n[He+4>>2]=We|1,n[He+We+4>>2]=40,n[2790]=n[2905];break}for(m>>>0<(n[2787]|0)>>>0&&(n[2787]=m),u=m+B|0,l=11580;;){if((n[l>>2]|0)==(u|0)){He=153;break}if(o=n[l+8>>2]|0,o)l=o;else break}if((He|0)==153&&!(n[l+12>>2]&8|0)){n[l>>2]=m,L=l+4|0,n[L>>2]=(n[L>>2]|0)+B,L=m+8|0,L=m+(L&7|0?0-L&7:0)|0,l=u+8|0,l=u+(l&7|0?0-l&7:0)|0,M=L+q|0,k=l-L-q|0,n[L+4>>2]=q|3;do if((l|0)!=(R|0)){if((l|0)==(n[2788]|0)){We=(n[2785]|0)+k|0,n[2785]=We,n[2788]=M,n[M+4>>2]=We|1,n[M+We>>2]=We;break}if(o=n[l+4>>2]|0,(o&3|0)==1){B=o&-8,A=o>>>3;e:do if(o>>>0<256)if(o=n[l+8>>2]|0,u=n[l+12>>2]|0,(u|0)==(o|0)){n[2783]=n[2783]&~(1<<A);break}else{n[o+12>>2]=u,n[u+8>>2]=o;break}else{m=n[l+24>>2]|0,o=n[l+12>>2]|0;do if((o|0)==(l|0)){if(A=l+16|0,u=A+4|0,o=n[u>>2]|0,!o)if(o=n[A>>2]|0,o)u=A;else{o=0;break}for(;;){if(A=o+20|0,d=n[A>>2]|0,d|0){o=d,u=A;continue}if(A=o+16|0,d=n[A>>2]|0,d)o=d,u=A;else break}n[u>>2]=0}else We=n[l+8>>2]|0,n[We+12>>2]=o,n[o+8>>2]=We;while(!1);if(!m)break;u=n[l+28>>2]|0,A=11436+(u<<2)|0;do if((l|0)!=(n[A>>2]|0)){if(n[m+16+(((n[m+16>>2]|0)!=(l|0)&1)<<2)>>2]=o,!o)break e}else{if(n[A>>2]=o,o|0)break;n[2784]=n[2784]&~(1<<u);break e}while(!1);if(n[o+24>>2]=m,u=l+16|0,A=n[u>>2]|0,A|0&&(n[o+16>>2]=A,n[A+24>>2]=o),u=n[u+4>>2]|0,!u)break;n[o+20>>2]=u,n[u+24>>2]=o}while(!1);l=l+B|0,d=B+k|0}else d=k;if(l=l+4|0,n[l>>2]=n[l>>2]&-2,n[M+4>>2]=d|1,n[M+d>>2]=d,l=d>>>3,d>>>0<256){u=11172+(l<<1<<2)|0,o=n[2783]|0,l=1<<l,o&l?(o=u+8|0,l=n[o>>2]|0):(n[2783]=o|l,l=u,o=u+8|0),n[o>>2]=M,n[l+12>>2]=M,n[M+8>>2]=l,n[M+12>>2]=u;break}l=d>>>8;do if(!l)l=0;else{if(d>>>0>16777215){l=31;break}He=(l+1048320|0)>>>16&8,We=l<<He,ct=(We+520192|0)>>>16&4,We=We<<ct,l=(We+245760|0)>>>16&2,l=14-(ct|He|l)+(We<<l>>>15)|0,l=d>>>(l+7|0)&1|l<<1}while(!1);if(A=11436+(l<<2)|0,n[M+28>>2]=l,o=M+16|0,n[o+4>>2]=0,n[o>>2]=0,o=n[2784]|0,u=1<<l,!(o&u)){n[2784]=o|u,n[A>>2]=M,n[M+24>>2]=A,n[M+12>>2]=M,n[M+8>>2]=M;break}for(o=d<<((l|0)==31?0:25-(l>>>1)|0),u=n[A>>2]|0;;){if((n[u+4>>2]&-8|0)==(d|0)){He=194;break}if(A=u+16+(o>>>31<<2)|0,l=n[A>>2]|0,l)o=o<<1,u=l;else{He=193;break}}if((He|0)==193){n[A>>2]=M,n[M+24>>2]=u,n[M+12>>2]=M,n[M+8>>2]=M;break}else if((He|0)==194){He=u+8|0,We=n[He>>2]|0,n[We+12>>2]=M,n[He>>2]=M,n[M+8>>2]=We,n[M+12>>2]=u,n[M+24>>2]=0;break}}else We=(n[2786]|0)+k|0,n[2786]=We,n[2789]=M,n[M+4>>2]=We|1;while(!1);return We=L+8|0,I=Lt,We|0}for(l=11580;o=n[l>>2]|0,!(o>>>0<=R>>>0&&(We=o+(n[l+4>>2]|0)|0,We>>>0>R>>>0));)l=n[l+8>>2]|0;d=We+-47|0,o=d+8|0,o=d+(o&7|0?0-o&7:0)|0,d=R+16|0,o=o>>>0<d>>>0?R:o,l=o+8|0,u=m+8|0,u=u&7|0?0-u&7:0,He=m+u|0,u=B+-40-u|0,n[2789]=He,n[2786]=u,n[He+4>>2]=u|1,n[He+u+4>>2]=40,n[2790]=n[2905],u=o+4|0,n[u>>2]=27,n[l>>2]=n[2895],n[l+4>>2]=n[2896],n[l+8>>2]=n[2897],n[l+12>>2]=n[2898],n[2895]=m,n[2896]=B,n[2898]=0,n[2897]=l,l=o+24|0;do He=l,l=l+4|0,n[l>>2]=7;while((He+8|0)>>>0<We>>>0);if((o|0)!=(R|0)){if(m=o-R|0,n[u>>2]=n[u>>2]&-2,n[R+4>>2]=m|1,n[o>>2]=m,l=m>>>3,m>>>0<256){u=11172+(l<<1<<2)|0,o=n[2783]|0,l=1<<l,o&l?(o=u+8|0,l=n[o>>2]|0):(n[2783]=o|l,l=u,o=u+8|0),n[o>>2]=R,n[l+12>>2]=R,n[R+8>>2]=l,n[R+12>>2]=u;break}if(l=m>>>8,l?m>>>0>16777215?u=31:(He=(l+1048320|0)>>>16&8,We=l<<He,ct=(We+520192|0)>>>16&4,We=We<<ct,u=(We+245760|0)>>>16&2,u=14-(ct|He|u)+(We<<u>>>15)|0,u=m>>>(u+7|0)&1|u<<1):u=0,A=11436+(u<<2)|0,n[R+28>>2]=u,n[R+20>>2]=0,n[d>>2]=0,l=n[2784]|0,o=1<<u,!(l&o)){n[2784]=l|o,n[A>>2]=R,n[R+24>>2]=A,n[R+12>>2]=R,n[R+8>>2]=R;break}for(o=m<<((u|0)==31?0:25-(u>>>1)|0),u=n[A>>2]|0;;){if((n[u+4>>2]&-8|0)==(m|0)){He=216;break}if(A=u+16+(o>>>31<<2)|0,l=n[A>>2]|0,l)o=o<<1,u=l;else{He=215;break}}if((He|0)==215){n[A>>2]=R,n[R+24>>2]=u,n[R+12>>2]=R,n[R+8>>2]=R;break}else if((He|0)==216){He=u+8|0,We=n[He>>2]|0,n[We+12>>2]=R,n[He>>2]=R,n[R+8>>2]=We,n[R+12>>2]=u,n[R+24>>2]=0;break}}}else{We=n[2787]|0,(We|0)==0|m>>>0<We>>>0&&(n[2787]=m),n[2895]=m,n[2896]=B,n[2898]=0,n[2792]=n[2901],n[2791]=-1,l=0;do We=11172+(l<<1<<2)|0,n[We+12>>2]=We,n[We+8>>2]=We,l=l+1|0;while((l|0)!=32);We=m+8|0,We=We&7|0?0-We&7:0,He=m+We|0,We=B+-40-We|0,n[2789]=He,n[2786]=We,n[He+4>>2]=We|1,n[He+We+4>>2]=40,n[2790]=n[2905]}while(!1);if(l=n[2786]|0,l>>>0>q>>>0)return ct=l-q|0,n[2786]=ct,We=n[2789]|0,He=We+q|0,n[2789]=He,n[He+4>>2]=ct|1,n[We+4>>2]=q|3,We=We+8|0,I=Lt,We|0}return n[(Zy()|0)>>2]=12,We=0,I=Lt,We|0}function Hb(o){o=o|0;var l=0,u=0,A=0,d=0,m=0,B=0,k=0,R=0;if(o){u=o+-8|0,d=n[2787]|0,o=n[o+-4>>2]|0,l=o&-8,R=u+l|0;do if(o&1)k=u,B=u;else{if(A=n[u>>2]|0,!(o&3)||(B=u+(0-A)|0,m=A+l|0,B>>>0<d>>>0))return;if((B|0)==(n[2788]|0)){if(o=R+4|0,l=n[o>>2]|0,(l&3|0)!=3){k=B,l=m;break}n[2785]=m,n[o>>2]=l&-2,n[B+4>>2]=m|1,n[B+m>>2]=m;return}if(u=A>>>3,A>>>0<256)if(o=n[B+8>>2]|0,l=n[B+12>>2]|0,(l|0)==(o|0)){n[2783]=n[2783]&~(1<<u),k=B,l=m;break}else{n[o+12>>2]=l,n[l+8>>2]=o,k=B,l=m;break}d=n[B+24>>2]|0,o=n[B+12>>2]|0;do if((o|0)==(B|0)){if(u=B+16|0,l=u+4|0,o=n[l>>2]|0,!o)if(o=n[u>>2]|0,o)l=u;else{o=0;break}for(;;){if(u=o+20|0,A=n[u>>2]|0,A|0){o=A,l=u;continue}if(u=o+16|0,A=n[u>>2]|0,A)o=A,l=u;else break}n[l>>2]=0}else k=n[B+8>>2]|0,n[k+12>>2]=o,n[o+8>>2]=k;while(!1);if(d){if(l=n[B+28>>2]|0,u=11436+(l<<2)|0,(B|0)==(n[u>>2]|0)){if(n[u>>2]=o,!o){n[2784]=n[2784]&~(1<<l),k=B,l=m;break}}else if(n[d+16+(((n[d+16>>2]|0)!=(B|0)&1)<<2)>>2]=o,!o){k=B,l=m;break}n[o+24>>2]=d,l=B+16|0,u=n[l>>2]|0,u|0&&(n[o+16>>2]=u,n[u+24>>2]=o),l=n[l+4>>2]|0,l?(n[o+20>>2]=l,n[l+24>>2]=o,k=B,l=m):(k=B,l=m)}else k=B,l=m}while(!1);if(!(B>>>0>=R>>>0)&&(o=R+4|0,A=n[o>>2]|0,!!(A&1))){if(A&2)n[o>>2]=A&-2,n[k+4>>2]=l|1,n[B+l>>2]=l,d=l;else{if(o=n[2788]|0,(R|0)==(n[2789]|0)){if(R=(n[2786]|0)+l|0,n[2786]=R,n[2789]=k,n[k+4>>2]=R|1,(k|0)!=(o|0))return;n[2788]=0,n[2785]=0;return}if((R|0)==(o|0)){R=(n[2785]|0)+l|0,n[2785]=R,n[2788]=B,n[k+4>>2]=R|1,n[B+R>>2]=R;return}d=(A&-8)+l|0,u=A>>>3;do if(A>>>0<256)if(l=n[R+8>>2]|0,o=n[R+12>>2]|0,(o|0)==(l|0)){n[2783]=n[2783]&~(1<<u);break}else{n[l+12>>2]=o,n[o+8>>2]=l;break}else{m=n[R+24>>2]|0,o=n[R+12>>2]|0;do if((o|0)==(R|0)){if(u=R+16|0,l=u+4|0,o=n[l>>2]|0,!o)if(o=n[u>>2]|0,o)l=u;else{u=0;break}for(;;){if(u=o+20|0,A=n[u>>2]|0,A|0){o=A,l=u;continue}if(u=o+16|0,A=n[u>>2]|0,A)o=A,l=u;else break}n[l>>2]=0,u=o}else u=n[R+8>>2]|0,n[u+12>>2]=o,n[o+8>>2]=u,u=o;while(!1);if(m|0){if(o=n[R+28>>2]|0,l=11436+(o<<2)|0,(R|0)==(n[l>>2]|0)){if(n[l>>2]=u,!u){n[2784]=n[2784]&~(1<<o);break}}else if(n[m+16+(((n[m+16>>2]|0)!=(R|0)&1)<<2)>>2]=u,!u)break;n[u+24>>2]=m,o=R+16|0,l=n[o>>2]|0,l|0&&(n[u+16>>2]=l,n[l+24>>2]=u),o=n[o+4>>2]|0,o|0&&(n[u+20>>2]=o,n[o+24>>2]=u)}}while(!1);if(n[k+4>>2]=d|1,n[B+d>>2]=d,(k|0)==(n[2788]|0)){n[2785]=d;return}}if(o=d>>>3,d>>>0<256){u=11172+(o<<1<<2)|0,l=n[2783]|0,o=1<<o,l&o?(l=u+8|0,o=n[l>>2]|0):(n[2783]=l|o,o=u,l=u+8|0),n[l>>2]=k,n[o+12>>2]=k,n[k+8>>2]=o,n[k+12>>2]=u;return}o=d>>>8,o?d>>>0>16777215?o=31:(B=(o+1048320|0)>>>16&8,R=o<<B,m=(R+520192|0)>>>16&4,R=R<<m,o=(R+245760|0)>>>16&2,o=14-(m|B|o)+(R<<o>>>15)|0,o=d>>>(o+7|0)&1|o<<1):o=0,A=11436+(o<<2)|0,n[k+28>>2]=o,n[k+20>>2]=0,n[k+16>>2]=0,l=n[2784]|0,u=1<<o;do if(l&u){for(l=d<<((o|0)==31?0:25-(o>>>1)|0),u=n[A>>2]|0;;){if((n[u+4>>2]&-8|0)==(d|0)){o=73;break}if(A=u+16+(l>>>31<<2)|0,o=n[A>>2]|0,o)l=l<<1,u=o;else{o=72;break}}if((o|0)==72){n[A>>2]=k,n[k+24>>2]=u,n[k+12>>2]=k,n[k+8>>2]=k;break}else if((o|0)==73){B=u+8|0,R=n[B>>2]|0,n[R+12>>2]=k,n[B>>2]=k,n[k+8>>2]=R,n[k+12>>2]=u,n[k+24>>2]=0;break}}else n[2784]=l|u,n[A>>2]=k,n[k+24>>2]=A,n[k+12>>2]=k,n[k+8>>2]=k;while(!1);if(R=(n[2791]|0)+-1|0,n[2791]=R,!R)o=11588;else return;for(;o=n[o>>2]|0,o;)o=o+8|0;n[2791]=-1}}}function $je(){return 11628}function e6e(o){o=o|0;var l=0,u=0;return l=I,I=I+16|0,u=l,n[u>>2]=n6e(n[o+60>>2]|0)|0,o=jb(Au(6,u|0)|0)|0,I=l,o|0}function hX(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0,Ye=0;q=I,I=I+48|0,M=q+16|0,m=q,d=q+32|0,k=o+28|0,A=n[k>>2]|0,n[d>>2]=A,R=o+20|0,A=(n[R>>2]|0)-A|0,n[d+4>>2]=A,n[d+8>>2]=l,n[d+12>>2]=u,A=A+u|0,B=o+60|0,n[m>>2]=n[B>>2],n[m+4>>2]=d,n[m+8>>2]=2,m=jb(La(146,m|0)|0)|0;e:do if((A|0)!=(m|0)){for(l=2;!((m|0)<0);)if(A=A-m|0,Ye=n[d+4>>2]|0,ae=m>>>0>Ye>>>0,d=ae?d+8|0:d,l=(ae<<31>>31)+l|0,Ye=m-(ae?Ye:0)|0,n[d>>2]=(n[d>>2]|0)+Ye,ae=d+4|0,n[ae>>2]=(n[ae>>2]|0)-Ye,n[M>>2]=n[B>>2],n[M+4>>2]=d,n[M+8>>2]=l,m=jb(La(146,M|0)|0)|0,(A|0)==(m|0)){L=3;break e}n[o+16>>2]=0,n[k>>2]=0,n[R>>2]=0,n[o>>2]=n[o>>2]|32,(l|0)==2?u=0:u=u-(n[d+4>>2]|0)|0}else L=3;while(!1);return(L|0)==3&&(Ye=n[o+44>>2]|0,n[o+16>>2]=Ye+(n[o+48>>2]|0),n[k>>2]=Ye,n[R>>2]=Ye),I=q,u|0}function t6e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;return d=I,I=I+32|0,m=d,A=d+20|0,n[m>>2]=n[o+60>>2],n[m+4>>2]=0,n[m+8>>2]=l,n[m+12>>2]=A,n[m+16>>2]=u,(jb(Oa(140,m|0)|0)|0)<0?(n[A>>2]=-1,o=-1):o=n[A>>2]|0,I=d,o|0}function jb(o){return o=o|0,o>>>0>4294963200&&(n[(Zy()|0)>>2]=0-o,o=-1),o|0}function Zy(){return(r6e()|0)+64|0}function r6e(){return aU()|0}function aU(){return 2084}function n6e(o){return o=o|0,o|0}function i6e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0;return d=I,I=I+32|0,A=d,n[o+36>>2]=1,!(n[o>>2]&64|0)&&(n[A>>2]=n[o+60>>2],n[A+4>>2]=21523,n[A+8>>2]=d+16,no(54,A|0)|0)&&(s[o+75>>0]=-1),A=hX(o,l,u)|0,I=d,A|0}function gX(o,l){o=o|0,l=l|0;var u=0,A=0;if(u=s[o>>0]|0,A=s[l>>0]|0,!(u<<24>>24)||u<<24>>24!=A<<24>>24)o=A;else{do o=o+1|0,l=l+1|0,u=s[o>>0]|0,A=s[l>>0]|0;while(!(!(u<<24>>24)||u<<24>>24!=A<<24>>24));o=A}return(u&255)-(o&255)|0}function s6e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0;e:do if(!u)o=0;else{for(;A=s[o>>0]|0,d=s[l>>0]|0,A<<24>>24==d<<24>>24;)if(u=u+-1|0,u)o=o+1|0,l=l+1|0;else{o=0;break e}o=(A&255)-(d&255)|0}while(!1);return o|0}function dX(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0,Ye=0,Le=0,Qe=0;Qe=I,I=I+224|0,L=Qe+120|0,q=Qe+80|0,Ye=Qe,Le=Qe+136|0,A=q,d=A+40|0;do n[A>>2]=0,A=A+4|0;while((A|0)<(d|0));return n[L>>2]=n[u>>2],(lU(0,l,L,Ye,q)|0)<0?u=-1:((n[o+76>>2]|0)>-1?ae=o6e(o)|0:ae=0,u=n[o>>2]|0,M=u&32,(s[o+74>>0]|0)<1&&(n[o>>2]=u&-33),A=o+48|0,n[A>>2]|0?u=lU(o,l,L,Ye,q)|0:(d=o+44|0,m=n[d>>2]|0,n[d>>2]=Le,B=o+28|0,n[B>>2]=Le,k=o+20|0,n[k>>2]=Le,n[A>>2]=80,R=o+16|0,n[R>>2]=Le+80,u=lU(o,l,L,Ye,q)|0,m&&(Yb[n[o+36>>2]&7](o,0,0)|0,u=n[k>>2]|0?u:-1,n[d>>2]=m,n[A>>2]=0,n[R>>2]=0,n[B>>2]=0,n[k>>2]=0)),A=n[o>>2]|0,n[o>>2]=A|M,ae|0&&a6e(o),u=A&32|0?-1:u),I=Qe,u|0}function lU(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0;var m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0,Ye=0,Le=0,Qe=0,tt=0,Xe=0,ct=0,He=0,We=0,Lt=0,Gr=0,fr=0,$t=0,Rr=0,Hr=0,cr=0;cr=I,I=I+64|0,fr=cr+16|0,$t=cr,Lt=cr+24|0,Rr=cr+8|0,Hr=cr+20|0,n[fr>>2]=l,ct=(o|0)!=0,He=Lt+40|0,We=He,Lt=Lt+39|0,Gr=Rr+4|0,B=0,m=0,L=0;e:for(;;){do if((m|0)>-1)if((B|0)>(2147483647-m|0)){n[(Zy()|0)>>2]=75,m=-1;break}else{m=B+m|0;break}while(!1);if(B=s[l>>0]|0,B<<24>>24)k=l;else{Xe=87;break}t:for(;;){switch(B<<24>>24){case 37:{B=k,Xe=9;break t}case 0:{B=k;break t}default:}tt=k+1|0,n[fr>>2]=tt,B=s[tt>>0]|0,k=tt}t:do if((Xe|0)==9)for(;;){if(Xe=0,(s[k+1>>0]|0)!=37)break t;if(B=B+1|0,k=k+2|0,n[fr>>2]=k,(s[k>>0]|0)==37)Xe=9;else break}while(!1);if(B=B-l|0,ct&&vs(o,l,B),B|0){l=k;continue}R=k+1|0,B=(s[R>>0]|0)+-48|0,B>>>0<10?(tt=(s[k+2>>0]|0)==36,Qe=tt?B:-1,L=tt?1:L,R=tt?k+3|0:R):Qe=-1,n[fr>>2]=R,B=s[R>>0]|0,k=(B<<24>>24)+-32|0;t:do if(k>>>0<32)for(M=0,q=B;;){if(B=1<<k,!(B&75913)){B=q;break t}if(M=B|M,R=R+1|0,n[fr>>2]=R,B=s[R>>0]|0,k=(B<<24>>24)+-32|0,k>>>0>=32)break;q=B}else M=0;while(!1);if(B<<24>>24==42){if(k=R+1|0,B=(s[k>>0]|0)+-48|0,B>>>0<10&&(s[R+2>>0]|0)==36)n[d+(B<<2)>>2]=10,B=n[A+((s[k>>0]|0)+-48<<3)>>2]|0,L=1,R=R+3|0;else{if(L|0){m=-1;break}ct?(L=(n[u>>2]|0)+3&-4,B=n[L>>2]|0,n[u>>2]=L+4,L=0,R=k):(B=0,L=0,R=k)}n[fr>>2]=R,tt=(B|0)<0,B=tt?0-B|0:B,M=tt?M|8192:M}else{if(B=mX(fr)|0,(B|0)<0){m=-1;break}R=n[fr>>2]|0}do if((s[R>>0]|0)==46){if((s[R+1>>0]|0)!=42){n[fr>>2]=R+1,k=mX(fr)|0,R=n[fr>>2]|0;break}if(q=R+2|0,k=(s[q>>0]|0)+-48|0,k>>>0<10&&(s[R+3>>0]|0)==36){n[d+(k<<2)>>2]=10,k=n[A+((s[q>>0]|0)+-48<<3)>>2]|0,R=R+4|0,n[fr>>2]=R;break}if(L|0){m=-1;break e}ct?(tt=(n[u>>2]|0)+3&-4,k=n[tt>>2]|0,n[u>>2]=tt+4):k=0,n[fr>>2]=q,R=q}else k=-1;while(!1);for(Le=0;;){if(((s[R>>0]|0)+-65|0)>>>0>57){m=-1;break e}if(tt=R+1|0,n[fr>>2]=tt,q=s[(s[R>>0]|0)+-65+(5178+(Le*58|0))>>0]|0,ae=q&255,(ae+-1|0)>>>0<8)Le=ae,R=tt;else break}if(!(q<<24>>24)){m=-1;break}Ye=(Qe|0)>-1;do if(q<<24>>24==19)if(Ye){m=-1;break e}else Xe=49;else{if(Ye){n[d+(Qe<<2)>>2]=ae,Ye=A+(Qe<<3)|0,Qe=n[Ye+4>>2]|0,Xe=$t,n[Xe>>2]=n[Ye>>2],n[Xe+4>>2]=Qe,Xe=49;break}if(!ct){m=0;break e}yX($t,ae,u)}while(!1);if((Xe|0)==49&&(Xe=0,!ct)){B=0,l=tt;continue}R=s[R>>0]|0,R=(Le|0)!=0&(R&15|0)==3?R&-33:R,Ye=M&-65537,Qe=M&8192|0?Ye:M;t:do switch(R|0){case 110:switch((Le&255)<<24>>24){case 0:{n[n[$t>>2]>>2]=m,B=0,l=tt;continue e}case 1:{n[n[$t>>2]>>2]=m,B=0,l=tt;continue e}case 2:{B=n[$t>>2]|0,n[B>>2]=m,n[B+4>>2]=((m|0)<0)<<31>>31,B=0,l=tt;continue e}case 3:{a[n[$t>>2]>>1]=m,B=0,l=tt;continue e}case 4:{s[n[$t>>2]>>0]=m,B=0,l=tt;continue e}case 6:{n[n[$t>>2]>>2]=m,B=0,l=tt;continue e}case 7:{B=n[$t>>2]|0,n[B>>2]=m,n[B+4>>2]=((m|0)<0)<<31>>31,B=0,l=tt;continue e}default:{B=0,l=tt;continue e}}case 112:{R=120,k=k>>>0>8?k:8,l=Qe|8,Xe=61;break}case 88:case 120:{l=Qe,Xe=61;break}case 111:{R=$t,l=n[R>>2]|0,R=n[R+4>>2]|0,ae=c6e(l,R,He)|0,Ye=We-ae|0,M=0,q=5642,k=(Qe&8|0)==0|(k|0)>(Ye|0)?k:Ye+1|0,Ye=Qe,Xe=67;break}case 105:case 100:if(R=$t,l=n[R>>2]|0,R=n[R+4>>2]|0,(R|0)<0){l=Gb(0,0,l|0,R|0)|0,R=ye,M=$t,n[M>>2]=l,n[M+4>>2]=R,M=1,q=5642,Xe=66;break t}else{M=(Qe&2049|0)!=0&1,q=Qe&2048|0?5643:Qe&1|0?5644:5642,Xe=66;break t}case 117:{R=$t,M=0,q=5642,l=n[R>>2]|0,R=n[R+4>>2]|0,Xe=66;break}case 99:{s[Lt>>0]=n[$t>>2],l=Lt,M=0,q=5642,ae=He,R=1,k=Ye;break}case 109:{R=u6e(n[(Zy()|0)>>2]|0)|0,Xe=71;break}case 115:{R=n[$t>>2]|0,R=R|0?R:5652,Xe=71;break}case 67:{n[Rr>>2]=n[$t>>2],n[Gr>>2]=0,n[$t>>2]=Rr,ae=-1,R=Rr,Xe=75;break}case 83:{l=n[$t>>2]|0,k?(ae=k,R=l,Xe=75):(Ls(o,32,B,0,Qe),l=0,Xe=84);break}case 65:case 71:case 70:case 69:case 97:case 103:case 102:case 101:{B=A6e(o,+E[$t>>3],B,k,Qe,R)|0,l=tt;continue e}default:M=0,q=5642,ae=He,R=k,k=Qe}while(!1);t:do if((Xe|0)==61)Qe=$t,Le=n[Qe>>2]|0,Qe=n[Qe+4>>2]|0,ae=l6e(Le,Qe,He,R&32)|0,q=(l&8|0)==0|(Le|0)==0&(Qe|0)==0,M=q?0:2,q=q?5642:5642+(R>>4)|0,Ye=l,l=Le,R=Qe,Xe=67;else if((Xe|0)==66)ae=Xy(l,R,He)|0,Ye=Qe,Xe=67;else if((Xe|0)==71)Xe=0,Qe=f6e(R,0,k)|0,Le=(Qe|0)==0,l=R,M=0,q=5642,ae=Le?R+k|0:Qe,R=Le?k:Qe-R|0,k=Ye;else if((Xe|0)==75){for(Xe=0,q=R,l=0,k=0;M=n[q>>2]|0,!(!M||(k=EX(Hr,M)|0,(k|0)<0|k>>>0>(ae-l|0)>>>0));)if(l=k+l|0,ae>>>0>l>>>0)q=q+4|0;else break;if((k|0)<0){m=-1;break e}if(Ls(o,32,B,l,Qe),!l)l=0,Xe=84;else for(M=0;;){if(k=n[R>>2]|0,!k){Xe=84;break t}if(k=EX(Hr,k)|0,M=k+M|0,(M|0)>(l|0)){Xe=84;break t}if(vs(o,Hr,k),M>>>0>=l>>>0){Xe=84;break}else R=R+4|0}}while(!1);if((Xe|0)==67)Xe=0,R=(l|0)!=0|(R|0)!=0,Qe=(k|0)!=0|R,R=((R^1)&1)+(We-ae)|0,l=Qe?ae:He,ae=He,R=Qe?(k|0)>(R|0)?k:R:k,k=(k|0)>-1?Ye&-65537:Ye;else if((Xe|0)==84){Xe=0,Ls(o,32,B,l,Qe^8192),B=(B|0)>(l|0)?B:l,l=tt;continue}Le=ae-l|0,Ye=(R|0)<(Le|0)?Le:R,Qe=Ye+M|0,B=(B|0)<(Qe|0)?Qe:B,Ls(o,32,B,Qe,k),vs(o,q,M),Ls(o,48,B,Qe,k^65536),Ls(o,48,Ye,Le,0),vs(o,l,Le),Ls(o,32,B,Qe,k^8192),l=tt}e:do if((Xe|0)==87&&!o)if(!L)m=0;else{for(m=1;l=n[d+(m<<2)>>2]|0,!!l;)if(yX(A+(m<<3)|0,l,u),m=m+1|0,(m|0)>=10){m=1;break e}for(;;){if(n[d+(m<<2)>>2]|0){m=-1;break e}if(m=m+1|0,(m|0)>=10){m=1;break}}}while(!1);return I=cr,m|0}function o6e(o){return o=o|0,0}function a6e(o){o=o|0}function vs(o,l,u){o=o|0,l=l|0,u=u|0,n[o>>2]&32||C6e(l,u,o)|0}function mX(o){o=o|0;var l=0,u=0,A=0;if(u=n[o>>2]|0,A=(s[u>>0]|0)+-48|0,A>>>0<10){l=0;do l=A+(l*10|0)|0,u=u+1|0,n[o>>2]=u,A=(s[u>>0]|0)+-48|0;while(A>>>0<10)}else l=0;return l|0}function yX(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;e:do if(l>>>0<=20)do switch(l|0){case 9:{A=(n[u>>2]|0)+3&-4,l=n[A>>2]|0,n[u>>2]=A+4,n[o>>2]=l;break e}case 10:{A=(n[u>>2]|0)+3&-4,l=n[A>>2]|0,n[u>>2]=A+4,A=o,n[A>>2]=l,n[A+4>>2]=((l|0)<0)<<31>>31;break e}case 11:{A=(n[u>>2]|0)+3&-4,l=n[A>>2]|0,n[u>>2]=A+4,A=o,n[A>>2]=l,n[A+4>>2]=0;break e}case 12:{A=(n[u>>2]|0)+7&-8,l=A,d=n[l>>2]|0,l=n[l+4>>2]|0,n[u>>2]=A+8,A=o,n[A>>2]=d,n[A+4>>2]=l;break e}case 13:{d=(n[u>>2]|0)+3&-4,A=n[d>>2]|0,n[u>>2]=d+4,A=(A&65535)<<16>>16,d=o,n[d>>2]=A,n[d+4>>2]=((A|0)<0)<<31>>31;break e}case 14:{d=(n[u>>2]|0)+3&-4,A=n[d>>2]|0,n[u>>2]=d+4,d=o,n[d>>2]=A&65535,n[d+4>>2]=0;break e}case 15:{d=(n[u>>2]|0)+3&-4,A=n[d>>2]|0,n[u>>2]=d+4,A=(A&255)<<24>>24,d=o,n[d>>2]=A,n[d+4>>2]=((A|0)<0)<<31>>31;break e}case 16:{d=(n[u>>2]|0)+3&-4,A=n[d>>2]|0,n[u>>2]=d+4,d=o,n[d>>2]=A&255,n[d+4>>2]=0;break e}case 17:{d=(n[u>>2]|0)+7&-8,m=+E[d>>3],n[u>>2]=d+8,E[o>>3]=m;break e}case 18:{d=(n[u>>2]|0)+7&-8,m=+E[d>>3],n[u>>2]=d+8,E[o>>3]=m;break e}default:break e}while(!1);while(!1)}function l6e(o,l,u,A){if(o=o|0,l=l|0,u=u|0,A=A|0,!((o|0)==0&(l|0)==0))do u=u+-1|0,s[u>>0]=c[5694+(o&15)>>0]|0|A,o=qb(o|0,l|0,4)|0,l=ye;while(!((o|0)==0&(l|0)==0));return u|0}function c6e(o,l,u){if(o=o|0,l=l|0,u=u|0,!((o|0)==0&(l|0)==0))do u=u+-1|0,s[u>>0]=o&7|48,o=qb(o|0,l|0,3)|0,l=ye;while(!((o|0)==0&(l|0)==0));return u|0}function Xy(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;if(l>>>0>0|(l|0)==0&o>>>0>4294967295){for(;A=AU(o|0,l|0,10,0)|0,u=u+-1|0,s[u>>0]=A&255|48,A=o,o=fU(o|0,l|0,10,0)|0,l>>>0>9|(l|0)==9&A>>>0>4294967295;)l=ye;l=o}else l=o;if(l)for(;u=u+-1|0,s[u>>0]=(l>>>0)%10|0|48,!(l>>>0<10);)l=(l>>>0)/10|0;return u|0}function u6e(o){return o=o|0,m6e(o,n[(d6e()|0)+188>>2]|0)|0}function f6e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;m=l&255,A=(u|0)!=0;e:do if(A&(o&3|0)!=0)for(d=l&255;;){if((s[o>>0]|0)==d<<24>>24){B=6;break e}if(o=o+1|0,u=u+-1|0,A=(u|0)!=0,!(A&(o&3|0)!=0)){B=5;break}}else B=5;while(!1);(B|0)==5&&(A?B=6:u=0);e:do if((B|0)==6&&(d=l&255,(s[o>>0]|0)!=d<<24>>24)){A=Ue(m,16843009)|0;t:do if(u>>>0>3){for(;m=n[o>>2]^A,!((m&-2139062144^-2139062144)&m+-16843009|0);)if(o=o+4|0,u=u+-4|0,u>>>0<=3){B=11;break t}}else B=11;while(!1);if((B|0)==11&&!u){u=0;break}for(;;){if((s[o>>0]|0)==d<<24>>24)break e;if(o=o+1|0,u=u+-1|0,!u){u=0;break}}}while(!1);return(u|0?o:0)|0}function Ls(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0;var m=0,B=0;if(B=I,I=I+256|0,m=B,(u|0)>(A|0)&(d&73728|0)==0){if(d=u-A|0,eE(m|0,l|0,(d>>>0<256?d:256)|0)|0,d>>>0>255){l=u-A|0;do vs(o,m,256),d=d+-256|0;while(d>>>0>255);d=l&255}vs(o,m,d)}I=B}function EX(o,l){return o=o|0,l=l|0,o?o=h6e(o,l,0)|0:o=0,o|0}function A6e(o,l,u,A,d,m){o=o|0,l=+l,u=u|0,A=A|0,d=d|0,m=m|0;var B=0,k=0,R=0,M=0,L=0,q=0,ae=0,Ye=0,Le=0,Qe=0,tt=0,Xe=0,ct=0,He=0,We=0,Lt=0,Gr=0,fr=0,$t=0,Rr=0,Hr=0,cr=0,Hn=0;Hn=I,I=I+560|0,R=Hn+8|0,tt=Hn,cr=Hn+524|0,Hr=cr,M=Hn+512|0,n[tt>>2]=0,Rr=M+12|0,IX(l)|0,(ye|0)<0?(l=-l,fr=1,Gr=5659):(fr=(d&2049|0)!=0&1,Gr=d&2048|0?5662:d&1|0?5665:5660),IX(l)|0,$t=ye&2146435072;do if($t>>>0<2146435072|($t|0)==2146435072&!1){if(Ye=+p6e(l,tt)*2,B=Ye!=0,B&&(n[tt>>2]=(n[tt>>2]|0)+-1),ct=m|32,(ct|0)==97){Le=m&32,ae=Le|0?Gr+9|0:Gr,q=fr|2,B=12-A|0;do if(A>>>0>11|(B|0)==0)l=Ye;else{l=8;do B=B+-1|0,l=l*16;while(B|0);if((s[ae>>0]|0)==45){l=-(l+(-Ye-l));break}else{l=Ye+l-l;break}}while(!1);k=n[tt>>2]|0,B=(k|0)<0?0-k|0:k,B=Xy(B,((B|0)<0)<<31>>31,Rr)|0,(B|0)==(Rr|0)&&(B=M+11|0,s[B>>0]=48),s[B+-1>>0]=(k>>31&2)+43,L=B+-2|0,s[L>>0]=m+15,M=(A|0)<1,R=(d&8|0)==0,B=cr;do $t=~~l,k=B+1|0,s[B>>0]=c[5694+$t>>0]|Le,l=(l-+($t|0))*16,(k-Hr|0)==1&&!(R&(M&l==0))?(s[k>>0]=46,B=B+2|0):B=k;while(l!=0);$t=B-Hr|0,Hr=Rr-L|0,Rr=(A|0)!=0&($t+-2|0)<(A|0)?A+2|0:$t,B=Hr+q+Rr|0,Ls(o,32,u,B,d),vs(o,ae,q),Ls(o,48,u,B,d^65536),vs(o,cr,$t),Ls(o,48,Rr-$t|0,0,0),vs(o,L,Hr),Ls(o,32,u,B,d^8192);break}k=(A|0)<0?6:A,B?(B=(n[tt>>2]|0)+-28|0,n[tt>>2]=B,l=Ye*268435456):(l=Ye,B=n[tt>>2]|0),$t=(B|0)<0?R:R+288|0,R=$t;do We=~~l>>>0,n[R>>2]=We,R=R+4|0,l=(l-+(We>>>0))*1e9;while(l!=0);if((B|0)>0)for(M=$t,q=R;;){if(L=(B|0)<29?B:29,B=q+-4|0,B>>>0>=M>>>0){R=0;do He=DX(n[B>>2]|0,0,L|0)|0,He=uU(He|0,ye|0,R|0,0)|0,We=ye,Xe=AU(He|0,We|0,1e9,0)|0,n[B>>2]=Xe,R=fU(He|0,We|0,1e9,0)|0,B=B+-4|0;while(B>>>0>=M>>>0);R&&(M=M+-4|0,n[M>>2]=R)}for(R=q;!(R>>>0<=M>>>0);)if(B=R+-4|0,!(n[B>>2]|0))R=B;else break;if(B=(n[tt>>2]|0)-L|0,n[tt>>2]=B,(B|0)>0)q=R;else break}else M=$t;if((B|0)<0){A=((k+25|0)/9|0)+1|0,Qe=(ct|0)==102;do{if(Le=0-B|0,Le=(Le|0)<9?Le:9,M>>>0<R>>>0){L=(1<<Le)+-1|0,q=1e9>>>Le,ae=0,B=M;do We=n[B>>2]|0,n[B>>2]=(We>>>Le)+ae,ae=Ue(We&L,q)|0,B=B+4|0;while(B>>>0<R>>>0);B=n[M>>2]|0?M:M+4|0,ae?(n[R>>2]=ae,M=B,B=R+4|0):(M=B,B=R)}else M=n[M>>2]|0?M:M+4|0,B=R;R=Qe?$t:M,R=(B-R>>2|0)>(A|0)?R+(A<<2)|0:B,B=(n[tt>>2]|0)+Le|0,n[tt>>2]=B}while((B|0)<0);B=M,A=R}else B=M,A=R;if(We=$t,B>>>0<A>>>0){if(R=(We-B>>2)*9|0,L=n[B>>2]|0,L>>>0>=10){M=10;do M=M*10|0,R=R+1|0;while(L>>>0>=M>>>0)}}else R=0;if(Qe=(ct|0)==103,Xe=(k|0)!=0,M=k-((ct|0)!=102?R:0)+((Xe&Qe)<<31>>31)|0,(M|0)<(((A-We>>2)*9|0)+-9|0)){if(M=M+9216|0,Le=$t+4+(((M|0)/9|0)+-1024<<2)|0,M=((M|0)%9|0)+1|0,(M|0)<9){L=10;do L=L*10|0,M=M+1|0;while((M|0)!=9)}else L=10;if(q=n[Le>>2]|0,ae=(q>>>0)%(L>>>0)|0,M=(Le+4|0)==(A|0),M&(ae|0)==0)M=Le;else if(Ye=((q>>>0)/(L>>>0)|0)&1|0?9007199254740994:9007199254740992,He=(L|0)/2|0,l=ae>>>0<He>>>0?.5:M&(ae|0)==(He|0)?1:1.5,fr&&(He=(s[Gr>>0]|0)==45,l=He?-l:l,Ye=He?-Ye:Ye),M=q-ae|0,n[Le>>2]=M,Ye+l!=Ye){if(He=M+L|0,n[Le>>2]=He,He>>>0>999999999)for(R=Le;M=R+-4|0,n[R>>2]=0,M>>>0<B>>>0&&(B=B+-4|0,n[B>>2]=0),He=(n[M>>2]|0)+1|0,n[M>>2]=He,He>>>0>999999999;)R=M;else M=Le;if(R=(We-B>>2)*9|0,q=n[B>>2]|0,q>>>0>=10){L=10;do L=L*10|0,R=R+1|0;while(q>>>0>=L>>>0)}}else M=Le;M=M+4|0,M=A>>>0>M>>>0?M:A,He=B}else M=A,He=B;for(ct=M;;){if(ct>>>0<=He>>>0){tt=0;break}if(B=ct+-4|0,!(n[B>>2]|0))ct=B;else{tt=1;break}}A=0-R|0;do if(Qe)if(B=((Xe^1)&1)+k|0,(B|0)>(R|0)&(R|0)>-5?(L=m+-1|0,k=B+-1-R|0):(L=m+-2|0,k=B+-1|0),B=d&8,B)Le=B;else{if(tt&&(Lt=n[ct+-4>>2]|0,(Lt|0)!=0))if((Lt>>>0)%10|0)M=0;else{M=0,B=10;do B=B*10|0,M=M+1|0;while(!((Lt>>>0)%(B>>>0)|0|0))}else M=9;if(B=((ct-We>>2)*9|0)+-9|0,(L|32|0)==102){Le=B-M|0,Le=(Le|0)>0?Le:0,k=(k|0)<(Le|0)?k:Le,Le=0;break}else{Le=B+R-M|0,Le=(Le|0)>0?Le:0,k=(k|0)<(Le|0)?k:Le,Le=0;break}}else L=m,Le=d&8;while(!1);if(Qe=k|Le,q=(Qe|0)!=0&1,ae=(L|32|0)==102,ae)Xe=0,B=(R|0)>0?R:0;else{if(B=(R|0)<0?A:R,B=Xy(B,((B|0)<0)<<31>>31,Rr)|0,M=Rr,(M-B|0)<2)do B=B+-1|0,s[B>>0]=48;while((M-B|0)<2);s[B+-1>>0]=(R>>31&2)+43,B=B+-2|0,s[B>>0]=L,Xe=B,B=M-B|0}if(B=fr+1+k+q+B|0,Ls(o,32,u,B,d),vs(o,Gr,fr),Ls(o,48,u,B,d^65536),ae){L=He>>>0>$t>>>0?$t:He,Le=cr+9|0,q=Le,ae=cr+8|0,M=L;do{if(R=Xy(n[M>>2]|0,0,Le)|0,(M|0)==(L|0))(R|0)==(Le|0)&&(s[ae>>0]=48,R=ae);else if(R>>>0>cr>>>0){eE(cr|0,48,R-Hr|0)|0;do R=R+-1|0;while(R>>>0>cr>>>0)}vs(o,R,q-R|0),M=M+4|0}while(M>>>0<=$t>>>0);if(Qe|0&&vs(o,5710,1),M>>>0<ct>>>0&(k|0)>0)for(;;){if(R=Xy(n[M>>2]|0,0,Le)|0,R>>>0>cr>>>0){eE(cr|0,48,R-Hr|0)|0;do R=R+-1|0;while(R>>>0>cr>>>0)}if(vs(o,R,(k|0)<9?k:9),M=M+4|0,R=k+-9|0,M>>>0<ct>>>0&(k|0)>9)k=R;else{k=R;break}}Ls(o,48,k+9|0,9,0)}else{if(Qe=tt?ct:He+4|0,(k|0)>-1){tt=cr+9|0,Le=(Le|0)==0,A=tt,q=0-Hr|0,ae=cr+8|0,L=He;do{R=Xy(n[L>>2]|0,0,tt)|0,(R|0)==(tt|0)&&(s[ae>>0]=48,R=ae);do if((L|0)==(He|0)){if(M=R+1|0,vs(o,R,1),Le&(k|0)<1){R=M;break}vs(o,5710,1),R=M}else{if(R>>>0<=cr>>>0)break;eE(cr|0,48,R+q|0)|0;do R=R+-1|0;while(R>>>0>cr>>>0)}while(!1);Hr=A-R|0,vs(o,R,(k|0)>(Hr|0)?Hr:k),k=k-Hr|0,L=L+4|0}while(L>>>0<Qe>>>0&(k|0)>-1)}Ls(o,48,k+18|0,18,0),vs(o,Xe,Rr-Xe|0)}Ls(o,32,u,B,d^8192)}else cr=(m&32|0)!=0,B=fr+3|0,Ls(o,32,u,B,d&-65537),vs(o,Gr,fr),vs(o,l!=l|!1?cr?5686:5690:cr?5678:5682,3),Ls(o,32,u,B,d^8192);while(!1);return I=Hn,((B|0)<(u|0)?u:B)|0}function IX(o){o=+o;var l=0;return E[S>>3]=o,l=n[S>>2]|0,ye=n[S+4>>2]|0,l|0}function p6e(o,l){return o=+o,l=l|0,+ +CX(o,l)}function CX(o,l){o=+o,l=l|0;var u=0,A=0,d=0;switch(E[S>>3]=o,u=n[S>>2]|0,A=n[S+4>>2]|0,d=qb(u|0,A|0,52)|0,d&2047){case 0:{o!=0?(o=+CX(o*18446744073709552e3,l),u=(n[l>>2]|0)+-64|0):u=0,n[l>>2]=u;break}case 2047:break;default:n[l>>2]=(d&2047)+-1022,n[S>>2]=u,n[S+4>>2]=A&-2146435073|1071644672,o=+E[S>>3]}return+o}function h6e(o,l,u){o=o|0,l=l|0,u=u|0;do if(o){if(l>>>0<128){s[o>>0]=l,o=1;break}if(!(n[n[(g6e()|0)+188>>2]>>2]|0))if((l&-128|0)==57216){s[o>>0]=l,o=1;break}else{n[(Zy()|0)>>2]=84,o=-1;break}if(l>>>0<2048){s[o>>0]=l>>>6|192,s[o+1>>0]=l&63|128,o=2;break}if(l>>>0<55296|(l&-8192|0)==57344){s[o>>0]=l>>>12|224,s[o+1>>0]=l>>>6&63|128,s[o+2>>0]=l&63|128,o=3;break}if((l+-65536|0)>>>0<1048576){s[o>>0]=l>>>18|240,s[o+1>>0]=l>>>12&63|128,s[o+2>>0]=l>>>6&63|128,s[o+3>>0]=l&63|128,o=4;break}else{n[(Zy()|0)>>2]=84,o=-1;break}}else o=1;while(!1);return o|0}function g6e(){return aU()|0}function d6e(){return aU()|0}function m6e(o,l){o=o|0,l=l|0;var u=0,A=0;for(A=0;;){if((c[5712+A>>0]|0)==(o|0)){o=2;break}if(u=A+1|0,(u|0)==87){u=5800,A=87,o=5;break}else A=u}if((o|0)==2&&(A?(u=5800,o=5):u=5800),(o|0)==5)for(;;){do o=u,u=u+1|0;while(s[o>>0]|0);if(A=A+-1|0,A)o=5;else break}return y6e(u,n[l+20>>2]|0)|0}function y6e(o,l){return o=o|0,l=l|0,E6e(o,l)|0}function E6e(o,l){return o=o|0,l=l|0,l?l=I6e(n[l>>2]|0,n[l+4>>2]|0,o)|0:l=0,(l|0?l:o)|0}function I6e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0;ae=(n[o>>2]|0)+1794895138|0,m=Ad(n[o+8>>2]|0,ae)|0,A=Ad(n[o+12>>2]|0,ae)|0,d=Ad(n[o+16>>2]|0,ae)|0;e:do if(m>>>0<l>>>2>>>0&&(q=l-(m<<2)|0,A>>>0<q>>>0&d>>>0<q>>>0)&&!((d|A)&3|0)){for(q=A>>>2,L=d>>>2,M=0;;){if(k=m>>>1,R=M+k|0,B=R<<1,d=B+q|0,A=Ad(n[o+(d<<2)>>2]|0,ae)|0,d=Ad(n[o+(d+1<<2)>>2]|0,ae)|0,!(d>>>0<l>>>0&A>>>0<(l-d|0)>>>0)){A=0;break e}if(s[o+(d+A)>>0]|0){A=0;break e}if(A=gX(u,o+d|0)|0,!A)break;if(A=(A|0)<0,(m|0)==1){A=0;break e}else M=A?M:R,m=A?k:m-k|0}A=B+L|0,d=Ad(n[o+(A<<2)>>2]|0,ae)|0,A=Ad(n[o+(A+1<<2)>>2]|0,ae)|0,A>>>0<l>>>0&d>>>0<(l-A|0)>>>0?A=s[o+(A+d)>>0]|0?0:o+A|0:A=0}else A=0;while(!1);return A|0}function Ad(o,l){o=o|0,l=l|0;var u=0;return u=xX(o|0)|0,(l|0?u:o)|0}function C6e(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0,k=0;A=u+16|0,d=n[A>>2]|0,d?m=5:w6e(u)|0?A=0:(d=n[A>>2]|0,m=5);e:do if((m|0)==5){if(k=u+20|0,B=n[k>>2]|0,A=B,(d-B|0)>>>0<l>>>0){A=Yb[n[u+36>>2]&7](u,o,l)|0;break}t:do if((s[u+75>>0]|0)>-1){for(B=l;;){if(!B){m=0,d=o;break t}if(d=B+-1|0,(s[o+d>>0]|0)==10)break;B=d}if(A=Yb[n[u+36>>2]&7](u,o,B)|0,A>>>0<B>>>0)break e;m=B,d=o+B|0,l=l-B|0,A=n[k>>2]|0}else m=0,d=o;while(!1);Qr(A|0,d|0,l|0)|0,n[k>>2]=(n[k>>2]|0)+l,A=m+l|0}while(!1);return A|0}function w6e(o){o=o|0;var l=0,u=0;return l=o+74|0,u=s[l>>0]|0,s[l>>0]=u+255|u,l=n[o>>2]|0,l&8?(n[o>>2]=l|32,o=-1):(n[o+8>>2]=0,n[o+4>>2]=0,u=n[o+44>>2]|0,n[o+28>>2]=u,n[o+20>>2]=u,n[o+16>>2]=u+(n[o+48>>2]|0),o=0),o|0}function $n(o,l){o=y(o),l=y(l);var u=0,A=0;u=wX(o)|0;do if((u&2147483647)>>>0<=2139095040){if(A=wX(l)|0,(A&2147483647)>>>0<=2139095040)if((A^u|0)<0){o=(u|0)<0?l:o;break}else{o=o<l?l:o;break}}else o=l;while(!1);return y(o)}function wX(o){return o=y(o),h[S>>2]=o,n[S>>2]|0|0}function pd(o,l){o=y(o),l=y(l);var u=0,A=0;u=BX(o)|0;do if((u&2147483647)>>>0<=2139095040){if(A=BX(l)|0,(A&2147483647)>>>0<=2139095040)if((A^u|0)<0){o=(u|0)<0?o:l;break}else{o=o<l?o:l;break}}else o=l;while(!1);return y(o)}function BX(o){return o=y(o),h[S>>2]=o,n[S>>2]|0|0}function cU(o,l){o=y(o),l=y(l);var u=0,A=0,d=0,m=0,B=0,k=0,R=0,M=0;m=(h[S>>2]=o,n[S>>2]|0),k=(h[S>>2]=l,n[S>>2]|0),u=m>>>23&255,B=k>>>23&255,R=m&-2147483648,d=k<<1;e:do if(d|0&&!((u|0)==255|((B6e(l)|0)&2147483647)>>>0>2139095040)){if(A=m<<1,A>>>0<=d>>>0)return l=y(o*y(0)),y((A|0)==(d|0)?l:o);if(u)A=m&8388607|8388608;else{if(u=m<<9,(u|0)>-1){A=u,u=0;do u=u+-1|0,A=A<<1;while((A|0)>-1)}else u=0;A=m<<1-u}if(B)k=k&8388607|8388608;else{if(m=k<<9,(m|0)>-1){d=0;do d=d+-1|0,m=m<<1;while((m|0)>-1)}else d=0;B=d,k=k<<1-d}d=A-k|0,m=(d|0)>-1;t:do if((u|0)>(B|0)){for(;;){if(m)if(d)A=d;else break;if(A=A<<1,u=u+-1|0,d=A-k|0,m=(d|0)>-1,(u|0)<=(B|0))break t}l=y(o*y(0));break e}while(!1);if(m)if(d)A=d;else{l=y(o*y(0));break}if(A>>>0<8388608)do A=A<<1,u=u+-1|0;while(A>>>0<8388608);(u|0)>0?u=A+-8388608|u<<23:u=A>>>(1-u|0),l=(n[S>>2]=u|R,y(h[S>>2]))}else M=3;while(!1);return(M|0)==3&&(l=y(o*l),l=y(l/l)),y(l)}function B6e(o){return o=y(o),h[S>>2]=o,n[S>>2]|0|0}function v6e(o,l){return o=o|0,l=l|0,dX(n[582]|0,o,l)|0}function sn(o){o=o|0,Nt()}function $y(o){o=o|0}function S6e(o,l){return o=o|0,l=l|0,0}function D6e(o){return o=o|0,(vX(o+4|0)|0)==-1?(ip[n[(n[o>>2]|0)+8>>2]&127](o),o=1):o=0,o|0}function vX(o){o=o|0;var l=0;return l=n[o>>2]|0,n[o>>2]=l+-1,l+-1|0}function Gh(o){o=o|0,D6e(o)|0&&P6e(o)}function P6e(o){o=o|0;var l=0;l=o+8|0,n[l>>2]|0&&(vX(l)|0)!=-1||ip[n[(n[o>>2]|0)+16>>2]&127](o)}function Kt(o){o=o|0;var l=0;for(l=o|0?o:1;o=_b(l)|0,!(o|0);){if(o=x6e()|0,!o){o=0;break}UX[o&0]()}return o|0}function SX(o){return o=o|0,Kt(o)|0}function It(o){o=o|0,Hb(o)}function b6e(o){o=o|0,(s[o+11>>0]|0)<0&&It(n[o>>2]|0)}function x6e(){var o=0;return o=n[2923]|0,n[2923]=o+0,o|0}function k6e(){}function Gb(o,l,u,A){return o=o|0,l=l|0,u=u|0,A=A|0,A=l-A-(u>>>0>o>>>0|0)>>>0,ye=A,o-u>>>0|0|0}function uU(o,l,u,A){return o=o|0,l=l|0,u=u|0,A=A|0,u=o+u>>>0,ye=l+A+(u>>>0<o>>>0|0)>>>0,u|0|0}function eE(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0,B=0;if(m=o+u|0,l=l&255,(u|0)>=67){for(;o&3;)s[o>>0]=l,o=o+1|0;for(A=m&-4|0,d=A-64|0,B=l|l<<8|l<<16|l<<24;(o|0)<=(d|0);)n[o>>2]=B,n[o+4>>2]=B,n[o+8>>2]=B,n[o+12>>2]=B,n[o+16>>2]=B,n[o+20>>2]=B,n[o+24>>2]=B,n[o+28>>2]=B,n[o+32>>2]=B,n[o+36>>2]=B,n[o+40>>2]=B,n[o+44>>2]=B,n[o+48>>2]=B,n[o+52>>2]=B,n[o+56>>2]=B,n[o+60>>2]=B,o=o+64|0;for(;(o|0)<(A|0);)n[o>>2]=B,o=o+4|0}for(;(o|0)<(m|0);)s[o>>0]=l,o=o+1|0;return m-u|0}function DX(o,l,u){return o=o|0,l=l|0,u=u|0,(u|0)<32?(ye=l<<u|(o&(1<<u)-1<<32-u)>>>32-u,o<<u):(ye=o<<u-32,0)}function qb(o,l,u){return o=o|0,l=l|0,u=u|0,(u|0)<32?(ye=l>>>u,o>>>u|(l&(1<<u)-1)<<32-u):(ye=0,l>>>u-32|0)}function Qr(o,l,u){o=o|0,l=l|0,u=u|0;var A=0,d=0,m=0;if((u|0)>=8192)return OA(o|0,l|0,u|0)|0;if(m=o|0,d=o+u|0,(o&3)==(l&3)){for(;o&3;){if(!u)return m|0;s[o>>0]=s[l>>0]|0,o=o+1|0,l=l+1|0,u=u-1|0}for(u=d&-4|0,A=u-64|0;(o|0)<=(A|0);)n[o>>2]=n[l>>2],n[o+4>>2]=n[l+4>>2],n[o+8>>2]=n[l+8>>2],n[o+12>>2]=n[l+12>>2],n[o+16>>2]=n[l+16>>2],n[o+20>>2]=n[l+20>>2],n[o+24>>2]=n[l+24>>2],n[o+28>>2]=n[l+28>>2],n[o+32>>2]=n[l+32>>2],n[o+36>>2]=n[l+36>>2],n[o+40>>2]=n[l+40>>2],n[o+44>>2]=n[l+44>>2],n[o+48>>2]=n[l+48>>2],n[o+52>>2]=n[l+52>>2],n[o+56>>2]=n[l+56>>2],n[o+60>>2]=n[l+60>>2],o=o+64|0,l=l+64|0;for(;(o|0)<(u|0);)n[o>>2]=n[l>>2],o=o+4|0,l=l+4|0}else for(u=d-4|0;(o|0)<(u|0);)s[o>>0]=s[l>>0]|0,s[o+1>>0]=s[l+1>>0]|0,s[o+2>>0]=s[l+2>>0]|0,s[o+3>>0]=s[l+3>>0]|0,o=o+4|0,l=l+4|0;for(;(o|0)<(d|0);)s[o>>0]=s[l>>0]|0,o=o+1|0,l=l+1|0;return m|0}function PX(o){o=o|0;var l=0;return l=s[N+(o&255)>>0]|0,(l|0)<8?l|0:(l=s[N+(o>>8&255)>>0]|0,(l|0)<8?l+8|0:(l=s[N+(o>>16&255)>>0]|0,(l|0)<8?l+16|0:(s[N+(o>>>24)>>0]|0)+24|0))}function bX(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0;var m=0,B=0,k=0,R=0,M=0,L=0,q=0,ae=0,Ye=0,Le=0;if(L=o,R=l,M=R,B=u,ae=A,k=ae,!M)return m=(d|0)!=0,k?m?(n[d>>2]=o|0,n[d+4>>2]=l&0,ae=0,d=0,ye=ae,d|0):(ae=0,d=0,ye=ae,d|0):(m&&(n[d>>2]=(L>>>0)%(B>>>0),n[d+4>>2]=0),ae=0,d=(L>>>0)/(B>>>0)>>>0,ye=ae,d|0);m=(k|0)==0;do if(B){if(!m){if(m=(P(k|0)|0)-(P(M|0)|0)|0,m>>>0<=31){q=m+1|0,k=31-m|0,l=m-31>>31,B=q,o=L>>>(q>>>0)&l|M<<k,l=M>>>(q>>>0)&l,m=0,k=L<<k;break}return d?(n[d>>2]=o|0,n[d+4>>2]=R|l&0,ae=0,d=0,ye=ae,d|0):(ae=0,d=0,ye=ae,d|0)}if(m=B-1|0,m&B|0){k=(P(B|0)|0)+33-(P(M|0)|0)|0,Le=64-k|0,q=32-k|0,R=q>>31,Ye=k-32|0,l=Ye>>31,B=k,o=q-1>>31&M>>>(Ye>>>0)|(M<<q|L>>>(k>>>0))&l,l=l&M>>>(k>>>0),m=L<<Le&R,k=(M<<Le|L>>>(Ye>>>0))&R|L<<q&k-33>>31;break}return d|0&&(n[d>>2]=m&L,n[d+4>>2]=0),(B|0)==1?(Ye=R|l&0,Le=o|0|0,ye=Ye,Le|0):(Le=PX(B|0)|0,Ye=M>>>(Le>>>0)|0,Le=M<<32-Le|L>>>(Le>>>0)|0,ye=Ye,Le|0)}else{if(m)return d|0&&(n[d>>2]=(M>>>0)%(B>>>0),n[d+4>>2]=0),Ye=0,Le=(M>>>0)/(B>>>0)>>>0,ye=Ye,Le|0;if(!L)return d|0&&(n[d>>2]=0,n[d+4>>2]=(M>>>0)%(k>>>0)),Ye=0,Le=(M>>>0)/(k>>>0)>>>0,ye=Ye,Le|0;if(m=k-1|0,!(m&k))return d|0&&(n[d>>2]=o|0,n[d+4>>2]=m&M|l&0),Ye=0,Le=M>>>((PX(k|0)|0)>>>0),ye=Ye,Le|0;if(m=(P(k|0)|0)-(P(M|0)|0)|0,m>>>0<=30){l=m+1|0,k=31-m|0,B=l,o=M<<k|L>>>(l>>>0),l=M>>>(l>>>0),m=0,k=L<<k;break}return d?(n[d>>2]=o|0,n[d+4>>2]=R|l&0,Ye=0,Le=0,ye=Ye,Le|0):(Ye=0,Le=0,ye=Ye,Le|0)}while(!1);if(!B)M=k,R=0,k=0;else{q=u|0|0,L=ae|A&0,M=uU(q|0,L|0,-1,-1)|0,u=ye,R=k,k=0;do A=R,R=m>>>31|R<<1,m=k|m<<1,A=o<<1|A>>>31|0,ae=o>>>31|l<<1|0,Gb(M|0,u|0,A|0,ae|0)|0,Le=ye,Ye=Le>>31|((Le|0)<0?-1:0)<<1,k=Ye&1,o=Gb(A|0,ae|0,Ye&q|0,(((Le|0)<0?-1:0)>>31|((Le|0)<0?-1:0)<<1)&L|0)|0,l=ye,B=B-1|0;while(B|0);M=R,R=0}return B=0,d|0&&(n[d>>2]=o,n[d+4>>2]=l),Ye=(m|0)>>>31|(M|B)<<1|(B<<1|m>>>31)&0|R,Le=(m<<1|0)&-2|k,ye=Ye,Le|0}function fU(o,l,u,A){return o=o|0,l=l|0,u=u|0,A=A|0,bX(o,l,u,A,0)|0}function qh(o){o=o|0;var l=0,u=0;return u=o+15&-16|0,l=n[C>>2]|0,o=l+u|0,(u|0)>0&(o|0)<(l|0)|(o|0)<0?(oe()|0,fu(12),-1):(n[C>>2]=o,(o|0)>($()|0)&&!(Z()|0)?(n[C>>2]=l,fu(12),-1):l|0)}function Q2(o,l,u){o=o|0,l=l|0,u=u|0;var A=0;if((l|0)<(o|0)&(o|0)<(l+u|0)){for(A=o,l=l+u|0,o=o+u|0;(u|0)>0;)o=o-1|0,l=l-1|0,u=u-1|0,s[o>>0]=s[l>>0]|0;o=A}else Qr(o,l,u)|0;return o|0}function AU(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0;var d=0,m=0;return m=I,I=I+16|0,d=m|0,bX(o,l,u,A,d)|0,I=m,ye=n[d+4>>2]|0,n[d>>2]|0|0}function xX(o){return o=o|0,(o&255)<<24|(o>>8&255)<<16|(o>>16&255)<<8|o>>>24|0}function Q6e(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,kX[o&1](l|0,u|0,A|0,d|0,m|0)}function R6e(o,l,u){o=o|0,l=l|0,u=y(u),QX[o&1](l|0,y(u))}function T6e(o,l,u){o=o|0,l=l|0,u=+u,RX[o&31](l|0,+u)}function F6e(o,l,u,A){return o=o|0,l=l|0,u=y(u),A=y(A),y(TX[o&0](l|0,y(u),y(A)))}function N6e(o,l){o=o|0,l=l|0,ip[o&127](l|0)}function O6e(o,l,u){o=o|0,l=l|0,u=u|0,sp[o&31](l|0,u|0)}function L6e(o,l){return o=o|0,l=l|0,gd[o&31](l|0)|0}function M6e(o,l,u,A,d){o=o|0,l=l|0,u=+u,A=+A,d=d|0,FX[o&1](l|0,+u,+A,d|0)}function U6e(o,l,u,A){o=o|0,l=l|0,u=+u,A=+A,EGe[o&1](l|0,+u,+A)}function _6e(o,l,u,A){return o=o|0,l=l|0,u=u|0,A=A|0,Yb[o&7](l|0,u|0,A|0)|0}function H6e(o,l,u,A){return o=o|0,l=l|0,u=u|0,A=A|0,+IGe[o&1](l|0,u|0,A|0)}function j6e(o,l){return o=o|0,l=l|0,+NX[o&15](l|0)}function G6e(o,l,u){return o=o|0,l=l|0,u=+u,CGe[o&1](l|0,+u)|0}function q6e(o,l,u){return o=o|0,l=l|0,u=u|0,hU[o&15](l|0,u|0)|0}function W6e(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=+A,d=+d,m=m|0,wGe[o&1](l|0,u|0,+A,+d,m|0)}function Y6e(o,l,u,A,d,m,B){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,B=B|0,BGe[o&1](l|0,u|0,A|0,d|0,m|0,B|0)}function V6e(o,l,u){return o=o|0,l=l|0,u=u|0,+OX[o&7](l|0,u|0)}function J6e(o){return o=o|0,Vb[o&7]()|0}function K6e(o,l,u,A,d,m){return o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,LX[o&1](l|0,u|0,A|0,d|0,m|0)|0}function z6e(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=+d,vGe[o&1](l|0,u|0,A|0,+d)}function Z6e(o,l,u,A,d,m,B){o=o|0,l=l|0,u=u|0,A=y(A),d=d|0,m=y(m),B=B|0,MX[o&1](l|0,u|0,y(A),d|0,y(m),B|0)}function X6e(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,F2[o&15](l|0,u|0,A|0)}function $6e(o){o=o|0,UX[o&0]()}function eGe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=+A,_X[o&15](l|0,u|0,+A)}function tGe(o,l,u){return o=o|0,l=+l,u=+u,SGe[o&1](+l,+u)|0}function rGe(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,gU[o&15](l|0,u|0,A|0,d|0)}function nGe(o,l,u,A,d){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,F(0)}function iGe(o,l){o=o|0,l=y(l),F(1)}function Za(o,l){o=o|0,l=+l,F(2)}function sGe(o,l,u){return o=o|0,l=y(l),u=y(u),F(3),$e}function wr(o){o=o|0,F(4)}function R2(o,l){o=o|0,l=l|0,F(5)}function Ol(o){return o=o|0,F(6),0}function oGe(o,l,u,A){o=o|0,l=+l,u=+u,A=A|0,F(7)}function aGe(o,l,u){o=o|0,l=+l,u=+u,F(8)}function lGe(o,l,u){return o=o|0,l=l|0,u=u|0,F(9),0}function cGe(o,l,u){return o=o|0,l=l|0,u=u|0,F(10),0}function hd(o){return o=o|0,F(11),0}function uGe(o,l){return o=o|0,l=+l,F(12),0}function T2(o,l){return o=o|0,l=l|0,F(13),0}function fGe(o,l,u,A,d){o=o|0,l=l|0,u=+u,A=+A,d=d|0,F(14)}function AGe(o,l,u,A,d,m){o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,m=m|0,F(15)}function pU(o,l){return o=o|0,l=l|0,F(16),0}function pGe(){return F(17),0}function hGe(o,l,u,A,d){return o=o|0,l=l|0,u=u|0,A=A|0,d=d|0,F(18),0}function gGe(o,l,u,A){o=o|0,l=l|0,u=u|0,A=+A,F(19)}function dGe(o,l,u,A,d,m){o=o|0,l=l|0,u=y(u),A=A|0,d=y(d),m=m|0,F(20)}function Wb(o,l,u){o=o|0,l=l|0,u=u|0,F(21)}function mGe(){F(22)}function tE(o,l,u){o=o|0,l=l|0,u=+u,F(23)}function yGe(o,l){return o=+o,l=+l,F(24),0}function rE(o,l,u,A){o=o|0,l=l|0,u=u|0,A=A|0,F(25)}var kX=[nGe,h3e],QX=[iGe,Ry],RX=[Za,Xg,Fh,h2,g2,d2,m2,Pf,_y,y2,bf,$g,ed,E2,I2,wu,td,C2,Hy,Za,Za,Za,Za,Za,Za,Za,Za,Za,Za,Za,Za,Za],TX=[sGe],ip=[wr,$y,Jke,Kke,zke,SFe,DFe,PFe,G_e,q_e,W_e,t3e,r3e,n3e,Bje,vje,Sje,Bl,Zg,u2,sr,hc,xb,kb,Mke,iQe,dQe,FQe,zQe,pRe,kRe,WRe,oTe,wTe,MTe,eFe,dFe,qFe,oNe,wNe,MNe,eOe,dOe,NOe,zOe,uLe,DLe,db,nMe,EMe,MMe,rUe,mUe,MUe,JUe,ZUe,h_e,m_e,F_e,V_e,z_e,p4e,Q4e,dz,A8e,G8e,iHe,EHe,HHe,rje,pje,dje,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr,wr],sp=[R2,Ly,VL,f2,A2,xr,so,zi,Ns,ws,Uy,Th,B2,Cb,id,zL,ZL,wb,Bb,eM,xf,ne,UOe,$Oe,oUe,g8e,U4e,eX,R2,R2,R2,R2],gd=[Ol,e6e,Ny,nd,Gy,ga,mb,Nh,w2,KL,Eb,qy,vb,tM,Vy,xLe,CUe,d4e,E8e,Tl,Ol,Ol,Ol,Ol,Ol,Ol,Ol,Ol,Ol,Ol,Ol,Ol],FX=[oGe,oM],EGe=[aGe,L_e],Yb=[lGe,hX,t6e,i6e,mRe,JFe,aMe,BHe],IGe=[cGe,jTe],NX=[hd,Oh,Ib,$A,aM,v,D,Q,H,V,hd,hd,hd,hd,hd,hd],CGe=[uGe,WUe],hU=[T2,S6e,Sb,jke,MQe,TRe,JRe,IFe,uNe,hLe,Ty,lHe,T2,T2,T2,T2],wGe=[fGe,IQe],BGe=[AGe,WHe],OX=[pU,XL,Se,_e,pt,iFe,pU,pU],Vb=[pGe,Wt,Fy,gb,t_e,C_e,e4e,Ije],LX=[hGe,Sy],vGe=[gGe,jNe],MX=[dGe,rM],F2=[Wb,ko,yb,$L,vu,eRe,cTe,iOe,IOe,YL,L3e,V8e,oje,Wb,Wb,Wb],UX=[mGe],_X=[tE,JL,My,XA,p2,Bu,jy,rd,DNe,BMe,HUe,tE,tE,tE,tE,tE],SGe=[yGe,H_e],gU=[rE,DTe,LLe,jMe,kUe,a_e,P_e,a4e,O4e,S8e,Qje,rE,rE,rE,rE,rE];return{_llvm_bswap_i32:xX,dynCall_idd:tGe,dynCall_i:J6e,_i64Subtract:Gb,___udivdi3:fU,dynCall_vif:R6e,setThrew:ca,dynCall_viii:X6e,_bitshift64Lshr:qb,_bitshift64Shl:DX,dynCall_vi:N6e,dynCall_viiddi:W6e,dynCall_diii:H6e,dynCall_iii:q6e,_memset:eE,_sbrk:qh,_memcpy:Qr,__GLOBAL__sub_I_Yoga_cpp:a2,dynCall_vii:O6e,___uremdi3:AU,dynCall_vid:T6e,stackAlloc:Ua,_nbind_init:jje,getTempRet0:MA,dynCall_di:j6e,dynCall_iid:G6e,setTempRet0:LA,_i64Add:uU,dynCall_fiff:F6e,dynCall_iiii:_6e,_emscripten_get_global_libc:$je,dynCall_viid:eGe,dynCall_viiid:z6e,dynCall_viififi:Z6e,dynCall_ii:L6e,__GLOBAL__sub_I_Binding_cc:i8e,dynCall_viiii:rGe,dynCall_iiiiii:K6e,stackSave:hf,dynCall_viiiii:Q6e,__GLOBAL__sub_I_nbind_cc:Sr,dynCall_vidd:U6e,_free:Hb,runPostSets:k6e,dynCall_viiiiii:Y6e,establishStackSpace:wn,_memmove:Q2,stackRestore:lc,_malloc:_b,__GLOBAL__sub_I_common_cc:v4e,dynCall_viddi:M6e,dynCall_dii:V6e,dynCall_v:$6e}}(Module.asmGlobalArg,Module.asmLibraryArg,buffer),_llvm_bswap_i32=Module._llvm_bswap_i32=asm._llvm_bswap_i32,getTempRet0=Module.getTempRet0=asm.getTempRet0,___udivdi3=Module.___udivdi3=asm.___udivdi3,setThrew=Module.setThrew=asm.setThrew,_bitshift64Lshr=Module._bitshift64Lshr=asm._bitshift64Lshr,_bitshift64Shl=Module._bitshift64Shl=asm._bitshift64Shl,_memset=Module._memset=asm._memset,_sbrk=Module._sbrk=asm._sbrk,_memcpy=Module._memcpy=asm._memcpy,stackAlloc=Module.stackAlloc=asm.stackAlloc,___uremdi3=Module.___uremdi3=asm.___uremdi3,_nbind_init=Module._nbind_init=asm._nbind_init,_i64Subtract=Module._i64Subtract=asm._i64Subtract,setTempRet0=Module.setTempRet0=asm.setTempRet0,_i64Add=Module._i64Add=asm._i64Add,_emscripten_get_global_libc=Module._emscripten_get_global_libc=asm._emscripten_get_global_libc,__GLOBAL__sub_I_Yoga_cpp=Module.__GLOBAL__sub_I_Yoga_cpp=asm.__GLOBAL__sub_I_Yoga_cpp,__GLOBAL__sub_I_Binding_cc=Module.__GLOBAL__sub_I_Binding_cc=asm.__GLOBAL__sub_I_Binding_cc,stackSave=Module.stackSave=asm.stackSave,__GLOBAL__sub_I_nbind_cc=Module.__GLOBAL__sub_I_nbind_cc=asm.__GLOBAL__sub_I_nbind_cc,_free=Module._free=asm._free,runPostSets=Module.runPostSets=asm.runPostSets,establishStackSpace=Module.establishStackSpace=asm.establishStackSpace,_memmove=Module._memmove=asm._memmove,stackRestore=Module.stackRestore=asm.stackRestore,_malloc=Module._malloc=asm._malloc,__GLOBAL__sub_I_common_cc=Module.__GLOBAL__sub_I_common_cc=asm.__GLOBAL__sub_I_common_cc,dynCall_viiiii=Module.dynCall_viiiii=asm.dynCall_viiiii,dynCall_vif=Module.dynCall_vif=asm.dynCall_vif,dynCall_vid=Module.dynCall_vid=asm.dynCall_vid,dynCall_fiff=Module.dynCall_fiff=asm.dynCall_fiff,dynCall_vi=Module.dynCall_vi=asm.dynCall_vi,dynCall_vii=Module.dynCall_vii=asm.dynCall_vii,dynCall_ii=Module.dynCall_ii=asm.dynCall_ii,dynCall_viddi=Module.dynCall_viddi=asm.dynCall_viddi,dynCall_vidd=Module.dynCall_vidd=asm.dynCall_vidd,dynCall_iiii=Module.dynCall_iiii=asm.dynCall_iiii,dynCall_diii=Module.dynCall_diii=asm.dynCall_diii,dynCall_di=Module.dynCall_di=asm.dynCall_di,dynCall_iid=Module.dynCall_iid=asm.dynCall_iid,dynCall_iii=Module.dynCall_iii=asm.dynCall_iii,dynCall_viiddi=Module.dynCall_viiddi=asm.dynCall_viiddi,dynCall_viiiiii=Module.dynCall_viiiiii=asm.dynCall_viiiiii,dynCall_dii=Module.dynCall_dii=asm.dynCall_dii,dynCall_i=Module.dynCall_i=asm.dynCall_i,dynCall_iiiiii=Module.dynCall_iiiiii=asm.dynCall_iiiiii,dynCall_viiid=Module.dynCall_viiid=asm.dynCall_viiid,dynCall_viififi=Module.dynCall_viififi=asm.dynCall_viififi,dynCall_viii=Module.dynCall_viii=asm.dynCall_viii,dynCall_v=Module.dynCall_v=asm.dynCall_v,dynCall_viid=Module.dynCall_viid=asm.dynCall_viid,dynCall_idd=Module.dynCall_idd=asm.dynCall_idd,dynCall_viiii=Module.dynCall_viiii=asm.dynCall_viiii;Runtime.stackAlloc=Module.stackAlloc,Runtime.stackSave=Module.stackSave,Runtime.stackRestore=Module.stackRestore,Runtime.establishStackSpace=Module.establishStackSpace,Runtime.setTempRet0=Module.setTempRet0,Runtime.getTempRet0=Module.getTempRet0,Module.asm=asm;function ExitStatus(t){this.name=\"ExitStatus\",this.message=\"Program terminated with exit(\"+t+\")\",this.status=t}ExitStatus.prototype=new Error,ExitStatus.prototype.constructor=ExitStatus;var initialStackTop,preloadStartTime=null,calledMain=!1;dependenciesFulfilled=function t(){Module.calledRun||run(),Module.calledRun||(dependenciesFulfilled=t)},Module.callMain=Module.callMain=function t(e){e=e||[],ensureInitRuntime();var r=e.length+1;function s(){for(var p=0;p<3;p++)a.push(0)}var a=[allocate(intArrayFromString(Module.thisProgram),\"i8\",ALLOC_NORMAL)];s();for(var n=0;n<r-1;n=n+1)a.push(allocate(intArrayFromString(e[n]),\"i8\",ALLOC_NORMAL)),s();a.push(0),a=allocate(a,\"i32\",ALLOC_NORMAL);try{var c=Module._main(r,a,0);exit(c,!0)}catch(p){if(p instanceof ExitStatus)return;if(p==\"SimulateInfiniteLoop\"){Module.noExitRuntime=!0;return}else{var f=p;p&&typeof p==\"object\"&&p.stack&&(f=[p,p.stack]),Module.printErr(\"exception thrown: \"+f),Module.quit(1,p)}}finally{calledMain=!0}};function run(t){if(t=t||Module.arguments,preloadStartTime===null&&(preloadStartTime=Date.now()),runDependencies>0||(preRun(),runDependencies>0)||Module.calledRun)return;function e(){Module.calledRun||(Module.calledRun=!0,!ABORT&&(ensureInitRuntime(),preMain(),Module.onRuntimeInitialized&&Module.onRuntimeInitialized(),Module._main&&shouldRunNow&&Module.callMain(t),postRun()))}Module.setStatus?(Module.setStatus(\"Running...\"),setTimeout(function(){setTimeout(function(){Module.setStatus(\"\")},1),e()},1)):e()}Module.run=Module.run=run;function exit(t,e){e&&Module.noExitRuntime||(Module.noExitRuntime||(ABORT=!0,EXITSTATUS=t,STACKTOP=initialStackTop,exitRuntime(),Module.onExit&&Module.onExit(t)),ENVIRONMENT_IS_NODE&&process.exit(t),Module.quit(t,new ExitStatus(t)))}Module.exit=Module.exit=exit;var abortDecorators=[];function abort(t){Module.onAbort&&Module.onAbort(t),t!==void 0?(Module.print(t),Module.printErr(t),t=JSON.stringify(t)):t=\"\",ABORT=!0,EXITSTATUS=1;var e=`\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.`,r=\"abort(\"+t+\") at \"+stackTrace()+e;throw abortDecorators&&abortDecorators.forEach(function(s){r=s(r,t)}),r}if(Module.abort=Module.abort=abort,Module.preInit)for(typeof Module.preInit==\"function\"&&(Module.preInit=[Module.preInit]);Module.preInit.length>0;)Module.preInit.pop()();var shouldRunNow=!0;Module.noInitialRun&&(shouldRunNow=!1),run()})});var Fm=_((cKt,bwe)=>{\"use strict\";var Ipt=Dwe(),Cpt=Pwe(),j9=!1,G9=null;Cpt({},function(t,e){if(!j9){if(j9=!0,t)throw t;G9=e}});if(!j9)throw new Error(\"Failed to load the yoga module - it needed to be loaded synchronously, but didn't\");bwe.exports=Ipt(G9.bind,G9.lib)});var W9=_((uKt,q9)=>{\"use strict\";var xwe=t=>Number.isNaN(t)?!1:t>=4352&&(t<=4447||t===9001||t===9002||11904<=t&&t<=12871&&t!==12351||12880<=t&&t<=19903||19968<=t&&t<=42182||43360<=t&&t<=43388||44032<=t&&t<=55203||63744<=t&&t<=64255||65040<=t&&t<=65049||65072<=t&&t<=65131||65281<=t&&t<=65376||65504<=t&&t<=65510||110592<=t&&t<=110593||127488<=t&&t<=127569||131072<=t&&t<=262141);q9.exports=xwe;q9.exports.default=xwe});var Qwe=_((fKt,kwe)=>{\"use strict\";kwe.exports=function(){return/\\uD83C\\uDFF4\\uDB40\\uDC67\\uDB40\\uDC62(?:\\uDB40\\uDC65\\uDB40\\uDC6E\\uDB40\\uDC67|\\uDB40\\uDC73\\uDB40\\uDC63\\uDB40\\uDC74|\\uDB40\\uDC77\\uDB40\\uDC6C\\uDB40\\uDC73)\\uDB40\\uDC7F|\\uD83D\\uDC68(?:\\uD83C\\uDFFC\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68\\uD83C\\uDFFB|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFF\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB-\\uDFFE])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFE\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB-\\uDFFD])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFD\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB\\uDFFC])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\u200D(?:\\u2764\\uFE0F\\u200D(?:\\uD83D\\uDC8B\\u200D)?\\uD83D\\uDC68|(?:\\uD83D[\\uDC68\\uDC69])\\u200D(?:\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC67\\u200D(?:\\uD83D[\\uDC66\\uDC67]))|\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC67\\u200D(?:\\uD83D[\\uDC66\\uDC67])|(?:\\uD83D[\\uDC68\\uDC69])\\u200D(?:\\uD83D[\\uDC66\\uDC67])|[\\u2695\\u2696\\u2708]\\uFE0F|\\uD83D[\\uDC66\\uDC67]|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|(?:\\uD83C\\uDFFB\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFF\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFE\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFD\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFC\\u200D[\\u2695\\u2696\\u2708])\\uFE0F|\\uD83C\\uDFFB\\u200D(?:\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C[\\uDFFB-\\uDFFF])|(?:\\uD83E\\uDDD1\\uD83C\\uDFFB\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1|\\uD83D\\uDC69\\uD83C\\uDFFC\\u200D\\uD83E\\uDD1D\\u200D\\uD83D\\uDC69)\\uD83C\\uDFFB|\\uD83E\\uDDD1(?:\\uD83C\\uDFFF\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1(?:\\uD83C[\\uDFFB-\\uDFFF])|\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1)|(?:\\uD83E\\uDDD1\\uD83C\\uDFFE\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1|\\uD83D\\uDC69\\uD83C\\uDFFF\\u200D\\uD83E\\uDD1D\\u200D(?:\\uD83D[\\uDC68\\uDC69]))(?:\\uD83C[\\uDFFB-\\uDFFE])|(?:\\uD83E\\uDDD1\\uD83C\\uDFFC\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1|\\uD83D\\uDC69\\uD83C\\uDFFD\\u200D\\uD83E\\uDD1D\\u200D\\uD83D\\uDC69)(?:\\uD83C[\\uDFFB\\uDFFC])|\\uD83D\\uDC69(?:\\uD83C\\uDFFE\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB-\\uDFFD\\uDFFF])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFC\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB\\uDFFD-\\uDFFF])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFB\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFC-\\uDFFF])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFD\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB\\uDFFC\\uDFFE\\uDFFF])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\u200D(?:\\u2764\\uFE0F\\u200D(?:\\uD83D\\uDC8B\\u200D(?:\\uD83D[\\uDC68\\uDC69])|\\uD83D[\\uDC68\\uDC69])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFF\\u200D(?:\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD]))|\\uD83D\\uDC69\\u200D\\uD83D\\uDC69\\u200D(?:\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC67\\u200D(?:\\uD83D[\\uDC66\\uDC67]))|(?:\\uD83E\\uDDD1\\uD83C\\uDFFD\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1|\\uD83D\\uDC69\\uD83C\\uDFFE\\u200D\\uD83E\\uDD1D\\u200D\\uD83D\\uDC69)(?:\\uD83C[\\uDFFB-\\uDFFD])|\\uD83D\\uDC69\\u200D\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC69\\u200D\\uD83D\\uDC69\\u200D(?:\\uD83D[\\uDC66\\uDC67])|(?:\\uD83D\\uDC41\\uFE0F\\u200D\\uD83D\\uDDE8|\\uD83D\\uDC69(?:\\uD83C\\uDFFF\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFE\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFC\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFB\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFD\\u200D[\\u2695\\u2696\\u2708]|\\u200D[\\u2695\\u2696\\u2708])|(?:(?:\\u26F9|\\uD83C[\\uDFCB\\uDFCC]|\\uD83D\\uDD75)\\uFE0F|\\uD83D\\uDC6F|\\uD83E[\\uDD3C\\uDDDE\\uDDDF])\\u200D[\\u2640\\u2642]|(?:\\u26F9|\\uD83C[\\uDFCB\\uDFCC]|\\uD83D\\uDD75)(?:\\uD83C[\\uDFFB-\\uDFFF])\\u200D[\\u2640\\u2642]|(?:\\uD83C[\\uDFC3\\uDFC4\\uDFCA]|\\uD83D[\\uDC6E\\uDC71\\uDC73\\uDC77\\uDC81\\uDC82\\uDC86\\uDC87\\uDE45-\\uDE47\\uDE4B\\uDE4D\\uDE4E\\uDEA3\\uDEB4-\\uDEB6]|\\uD83E[\\uDD26\\uDD37-\\uDD39\\uDD3D\\uDD3E\\uDDB8\\uDDB9\\uDDCD-\\uDDCF\\uDDD6-\\uDDDD])(?:(?:\\uD83C[\\uDFFB-\\uDFFF])\\u200D[\\u2640\\u2642]|\\u200D[\\u2640\\u2642])|\\uD83C\\uDFF4\\u200D\\u2620)\\uFE0F|\\uD83D\\uDC69\\u200D\\uD83D\\uDC67\\u200D(?:\\uD83D[\\uDC66\\uDC67])|\\uD83C\\uDFF3\\uFE0F\\u200D\\uD83C\\uDF08|\\uD83D\\uDC15\\u200D\\uD83E\\uDDBA|\\uD83D\\uDC69\\u200D\\uD83D\\uDC66|\\uD83D\\uDC69\\u200D\\uD83D\\uDC67|\\uD83C\\uDDFD\\uD83C\\uDDF0|\\uD83C\\uDDF4\\uD83C\\uDDF2|\\uD83C\\uDDF6\\uD83C\\uDDE6|[#\\*0-9]\\uFE0F\\u20E3|\\uD83C\\uDDE7(?:\\uD83C[\\uDDE6\\uDDE7\\uDDE9-\\uDDEF\\uDDF1-\\uDDF4\\uDDF6-\\uDDF9\\uDDFB\\uDDFC\\uDDFE\\uDDFF])|\\uD83C\\uDDF9(?:\\uD83C[\\uDDE6\\uDDE8\\uDDE9\\uDDEB-\\uDDED\\uDDEF-\\uDDF4\\uDDF7\\uDDF9\\uDDFB\\uDDFC\\uDDFF])|\\uD83C\\uDDEA(?:\\uD83C[\\uDDE6\\uDDE8\\uDDEA\\uDDEC\\uDDED\\uDDF7-\\uDDFA])|\\uD83E\\uDDD1(?:\\uD83C[\\uDFFB-\\uDFFF])|\\uD83C\\uDDF7(?:\\uD83C[\\uDDEA\\uDDF4\\uDDF8\\uDDFA\\uDDFC])|\\uD83D\\uDC69(?:\\uD83C[\\uDFFB-\\uDFFF])|\\uD83C\\uDDF2(?:\\uD83C[\\uDDE6\\uDDE8-\\uDDED\\uDDF0-\\uDDFF])|\\uD83C\\uDDE6(?:\\uD83C[\\uDDE8-\\uDDEC\\uDDEE\\uDDF1\\uDDF2\\uDDF4\\uDDF6-\\uDDFA\\uDDFC\\uDDFD\\uDDFF])|\\uD83C\\uDDF0(?:\\uD83C[\\uDDEA\\uDDEC-\\uDDEE\\uDDF2\\uDDF3\\uDDF5\\uDDF7\\uDDFC\\uDDFE\\uDDFF])|\\uD83C\\uDDED(?:\\uD83C[\\uDDF0\\uDDF2\\uDDF3\\uDDF7\\uDDF9\\uDDFA])|\\uD83C\\uDDE9(?:\\uD83C[\\uDDEA\\uDDEC\\uDDEF\\uDDF0\\uDDF2\\uDDF4\\uDDFF])|\\uD83C\\uDDFE(?:\\uD83C[\\uDDEA\\uDDF9])|\\uD83C\\uDDEC(?:\\uD83C[\\uDDE6\\uDDE7\\uDDE9-\\uDDEE\\uDDF1-\\uDDF3\\uDDF5-\\uDDFA\\uDDFC\\uDDFE])|\\uD83C\\uDDF8(?:\\uD83C[\\uDDE6-\\uDDEA\\uDDEC-\\uDDF4\\uDDF7-\\uDDF9\\uDDFB\\uDDFD-\\uDDFF])|\\uD83C\\uDDEB(?:\\uD83C[\\uDDEE-\\uDDF0\\uDDF2\\uDDF4\\uDDF7])|\\uD83C\\uDDF5(?:\\uD83C[\\uDDE6\\uDDEA-\\uDDED\\uDDF0-\\uDDF3\\uDDF7-\\uDDF9\\uDDFC\\uDDFE])|\\uD83C\\uDDFB(?:\\uD83C[\\uDDE6\\uDDE8\\uDDEA\\uDDEC\\uDDEE\\uDDF3\\uDDFA])|\\uD83C\\uDDF3(?:\\uD83C[\\uDDE6\\uDDE8\\uDDEA-\\uDDEC\\uDDEE\\uDDF1\\uDDF4\\uDDF5\\uDDF7\\uDDFA\\uDDFF])|\\uD83C\\uDDE8(?:\\uD83C[\\uDDE6\\uDDE8\\uDDE9\\uDDEB-\\uDDEE\\uDDF0-\\uDDF5\\uDDF7\\uDDFA-\\uDDFF])|\\uD83C\\uDDF1(?:\\uD83C[\\uDDE6-\\uDDE8\\uDDEE\\uDDF0\\uDDF7-\\uDDFB\\uDDFE])|\\uD83C\\uDDFF(?:\\uD83C[\\uDDE6\\uDDF2\\uDDFC])|\\uD83C\\uDDFC(?:\\uD83C[\\uDDEB\\uDDF8])|\\uD83C\\uDDFA(?:\\uD83C[\\uDDE6\\uDDEC\\uDDF2\\uDDF3\\uDDF8\\uDDFE\\uDDFF])|\\uD83C\\uDDEE(?:\\uD83C[\\uDDE8-\\uDDEA\\uDDF1-\\uDDF4\\uDDF6-\\uDDF9])|\\uD83C\\uDDEF(?:\\uD83C[\\uDDEA\\uDDF2\\uDDF4\\uDDF5])|(?:\\uD83C[\\uDFC3\\uDFC4\\uDFCA]|\\uD83D[\\uDC6E\\uDC71\\uDC73\\uDC77\\uDC81\\uDC82\\uDC86\\uDC87\\uDE45-\\uDE47\\uDE4B\\uDE4D\\uDE4E\\uDEA3\\uDEB4-\\uDEB6]|\\uD83E[\\uDD26\\uDD37-\\uDD39\\uDD3D\\uDD3E\\uDDB8\\uDDB9\\uDDCD-\\uDDCF\\uDDD6-\\uDDDD])(?:\\uD83C[\\uDFFB-\\uDFFF])|(?:\\u26F9|\\uD83C[\\uDFCB\\uDFCC]|\\uD83D\\uDD75)(?:\\uD83C[\\uDFFB-\\uDFFF])|(?:[\\u261D\\u270A-\\u270D]|\\uD83C[\\uDF85\\uDFC2\\uDFC7]|\\uD83D[\\uDC42\\uDC43\\uDC46-\\uDC50\\uDC66\\uDC67\\uDC6B-\\uDC6D\\uDC70\\uDC72\\uDC74-\\uDC76\\uDC78\\uDC7C\\uDC83\\uDC85\\uDCAA\\uDD74\\uDD7A\\uDD90\\uDD95\\uDD96\\uDE4C\\uDE4F\\uDEC0\\uDECC]|\\uD83E[\\uDD0F\\uDD18-\\uDD1C\\uDD1E\\uDD1F\\uDD30-\\uDD36\\uDDB5\\uDDB6\\uDDBB\\uDDD2-\\uDDD5])(?:\\uD83C[\\uDFFB-\\uDFFF])|(?:[\\u231A\\u231B\\u23E9-\\u23EC\\u23F0\\u23F3\\u25FD\\u25FE\\u2614\\u2615\\u2648-\\u2653\\u267F\\u2693\\u26A1\\u26AA\\u26AB\\u26BD\\u26BE\\u26C4\\u26C5\\u26CE\\u26D4\\u26EA\\u26F2\\u26F3\\u26F5\\u26FA\\u26FD\\u2705\\u270A\\u270B\\u2728\\u274C\\u274E\\u2753-\\u2755\\u2757\\u2795-\\u2797\\u27B0\\u27BF\\u2B1B\\u2B1C\\u2B50\\u2B55]|\\uD83C[\\uDC04\\uDCCF\\uDD8E\\uDD91-\\uDD9A\\uDDE6-\\uDDFF\\uDE01\\uDE1A\\uDE2F\\uDE32-\\uDE36\\uDE38-\\uDE3A\\uDE50\\uDE51\\uDF00-\\uDF20\\uDF2D-\\uDF35\\uDF37-\\uDF7C\\uDF7E-\\uDF93\\uDFA0-\\uDFCA\\uDFCF-\\uDFD3\\uDFE0-\\uDFF0\\uDFF4\\uDFF8-\\uDFFF]|\\uD83D[\\uDC00-\\uDC3E\\uDC40\\uDC42-\\uDCFC\\uDCFF-\\uDD3D\\uDD4B-\\uDD4E\\uDD50-\\uDD67\\uDD7A\\uDD95\\uDD96\\uDDA4\\uDDFB-\\uDE4F\\uDE80-\\uDEC5\\uDECC\\uDED0-\\uDED2\\uDED5\\uDEEB\\uDEEC\\uDEF4-\\uDEFA\\uDFE0-\\uDFEB]|\\uD83E[\\uDD0D-\\uDD3A\\uDD3C-\\uDD45\\uDD47-\\uDD71\\uDD73-\\uDD76\\uDD7A-\\uDDA2\\uDDA5-\\uDDAA\\uDDAE-\\uDDCA\\uDDCD-\\uDDFF\\uDE70-\\uDE73\\uDE78-\\uDE7A\\uDE80-\\uDE82\\uDE90-\\uDE95])|(?:[#\\*0-9\\xA9\\xAE\\u203C\\u2049\\u2122\\u2139\\u2194-\\u2199\\u21A9\\u21AA\\u231A\\u231B\\u2328\\u23CF\\u23E9-\\u23F3\\u23F8-\\u23FA\\u24C2\\u25AA\\u25AB\\u25B6\\u25C0\\u25FB-\\u25FE\\u2600-\\u2604\\u260E\\u2611\\u2614\\u2615\\u2618\\u261D\\u2620\\u2622\\u2623\\u2626\\u262A\\u262E\\u262F\\u2638-\\u263A\\u2640\\u2642\\u2648-\\u2653\\u265F\\u2660\\u2663\\u2665\\u2666\\u2668\\u267B\\u267E\\u267F\\u2692-\\u2697\\u2699\\u269B\\u269C\\u26A0\\u26A1\\u26AA\\u26AB\\u26B0\\u26B1\\u26BD\\u26BE\\u26C4\\u26C5\\u26C8\\u26CE\\u26CF\\u26D1\\u26D3\\u26D4\\u26E9\\u26EA\\u26F0-\\u26F5\\u26F7-\\u26FA\\u26FD\\u2702\\u2705\\u2708-\\u270D\\u270F\\u2712\\u2714\\u2716\\u271D\\u2721\\u2728\\u2733\\u2734\\u2744\\u2747\\u274C\\u274E\\u2753-\\u2755\\u2757\\u2763\\u2764\\u2795-\\u2797\\u27A1\\u27B0\\u27BF\\u2934\\u2935\\u2B05-\\u2B07\\u2B1B\\u2B1C\\u2B50\\u2B55\\u3030\\u303D\\u3297\\u3299]|\\uD83C[\\uDC04\\uDCCF\\uDD70\\uDD71\\uDD7E\\uDD7F\\uDD8E\\uDD91-\\uDD9A\\uDDE6-\\uDDFF\\uDE01\\uDE02\\uDE1A\\uDE2F\\uDE32-\\uDE3A\\uDE50\\uDE51\\uDF00-\\uDF21\\uDF24-\\uDF93\\uDF96\\uDF97\\uDF99-\\uDF9B\\uDF9E-\\uDFF0\\uDFF3-\\uDFF5\\uDFF7-\\uDFFF]|\\uD83D[\\uDC00-\\uDCFD\\uDCFF-\\uDD3D\\uDD49-\\uDD4E\\uDD50-\\uDD67\\uDD6F\\uDD70\\uDD73-\\uDD7A\\uDD87\\uDD8A-\\uDD8D\\uDD90\\uDD95\\uDD96\\uDDA4\\uDDA5\\uDDA8\\uDDB1\\uDDB2\\uDDBC\\uDDC2-\\uDDC4\\uDDD1-\\uDDD3\\uDDDC-\\uDDDE\\uDDE1\\uDDE3\\uDDE8\\uDDEF\\uDDF3\\uDDFA-\\uDE4F\\uDE80-\\uDEC5\\uDECB-\\uDED2\\uDED5\\uDEE0-\\uDEE5\\uDEE9\\uDEEB\\uDEEC\\uDEF0\\uDEF3-\\uDEFA\\uDFE0-\\uDFEB]|\\uD83E[\\uDD0D-\\uDD3A\\uDD3C-\\uDD45\\uDD47-\\uDD71\\uDD73-\\uDD76\\uDD7A-\\uDDA2\\uDDA5-\\uDDAA\\uDDAE-\\uDDCA\\uDDCD-\\uDDFF\\uDE70-\\uDE73\\uDE78-\\uDE7A\\uDE80-\\uDE82\\uDE90-\\uDE95])\\uFE0F|(?:[\\u261D\\u26F9\\u270A-\\u270D]|\\uD83C[\\uDF85\\uDFC2-\\uDFC4\\uDFC7\\uDFCA-\\uDFCC]|\\uD83D[\\uDC42\\uDC43\\uDC46-\\uDC50\\uDC66-\\uDC78\\uDC7C\\uDC81-\\uDC83\\uDC85-\\uDC87\\uDC8F\\uDC91\\uDCAA\\uDD74\\uDD75\\uDD7A\\uDD90\\uDD95\\uDD96\\uDE45-\\uDE47\\uDE4B-\\uDE4F\\uDEA3\\uDEB4-\\uDEB6\\uDEC0\\uDECC]|\\uD83E[\\uDD0F\\uDD18-\\uDD1F\\uDD26\\uDD30-\\uDD39\\uDD3C-\\uDD3E\\uDDB5\\uDDB6\\uDDB8\\uDDB9\\uDDBB\\uDDCD-\\uDDCF\\uDDD1-\\uDDDD])/g}});var GS=_((AKt,Y9)=>{\"use strict\";var wpt=dk(),Bpt=W9(),vpt=Qwe(),Rwe=t=>{if(typeof t!=\"string\"||t.length===0||(t=wpt(t),t.length===0))return 0;t=t.replace(vpt(),\"  \");let e=0;for(let r=0;r<t.length;r++){let s=t.codePointAt(r);s<=31||s>=127&&s<=159||s>=768&&s<=879||(s>65535&&r++,e+=Bpt(s)?2:1)}return e};Y9.exports=Rwe;Y9.exports.default=Rwe});var J9=_((pKt,V9)=>{\"use strict\";var Spt=GS(),Twe=t=>{let e=0;for(let r of t.split(`\n`))e=Math.max(e,Spt(r));return e};V9.exports=Twe;V9.exports.default=Twe});var Fwe=_(qS=>{\"use strict\";var Dpt=qS&&qS.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(qS,\"__esModule\",{value:!0});var Ppt=Dpt(J9()),K9={};qS.default=t=>{if(t.length===0)return{width:0,height:0};if(K9[t])return K9[t];let e=Ppt.default(t),r=t.split(`\n`).length;return K9[t]={width:e,height:r},{width:e,height:r}}});var Nwe=_(WS=>{\"use strict\";var bpt=WS&&WS.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(WS,\"__esModule\",{value:!0});var Pn=bpt(Fm()),xpt=(t,e)=>{\"position\"in e&&t.setPositionType(e.position===\"absolute\"?Pn.default.POSITION_TYPE_ABSOLUTE:Pn.default.POSITION_TYPE_RELATIVE)},kpt=(t,e)=>{\"marginLeft\"in e&&t.setMargin(Pn.default.EDGE_START,e.marginLeft||0),\"marginRight\"in e&&t.setMargin(Pn.default.EDGE_END,e.marginRight||0),\"marginTop\"in e&&t.setMargin(Pn.default.EDGE_TOP,e.marginTop||0),\"marginBottom\"in e&&t.setMargin(Pn.default.EDGE_BOTTOM,e.marginBottom||0)},Qpt=(t,e)=>{\"paddingLeft\"in e&&t.setPadding(Pn.default.EDGE_LEFT,e.paddingLeft||0),\"paddingRight\"in e&&t.setPadding(Pn.default.EDGE_RIGHT,e.paddingRight||0),\"paddingTop\"in e&&t.setPadding(Pn.default.EDGE_TOP,e.paddingTop||0),\"paddingBottom\"in e&&t.setPadding(Pn.default.EDGE_BOTTOM,e.paddingBottom||0)},Rpt=(t,e)=>{var r;\"flexGrow\"in e&&t.setFlexGrow((r=e.flexGrow)!==null&&r!==void 0?r:0),\"flexShrink\"in e&&t.setFlexShrink(typeof e.flexShrink==\"number\"?e.flexShrink:1),\"flexDirection\"in e&&(e.flexDirection===\"row\"&&t.setFlexDirection(Pn.default.FLEX_DIRECTION_ROW),e.flexDirection===\"row-reverse\"&&t.setFlexDirection(Pn.default.FLEX_DIRECTION_ROW_REVERSE),e.flexDirection===\"column\"&&t.setFlexDirection(Pn.default.FLEX_DIRECTION_COLUMN),e.flexDirection===\"column-reverse\"&&t.setFlexDirection(Pn.default.FLEX_DIRECTION_COLUMN_REVERSE)),\"flexBasis\"in e&&(typeof e.flexBasis==\"number\"?t.setFlexBasis(e.flexBasis):typeof e.flexBasis==\"string\"?t.setFlexBasisPercent(Number.parseInt(e.flexBasis,10)):t.setFlexBasis(NaN)),\"alignItems\"in e&&((e.alignItems===\"stretch\"||!e.alignItems)&&t.setAlignItems(Pn.default.ALIGN_STRETCH),e.alignItems===\"flex-start\"&&t.setAlignItems(Pn.default.ALIGN_FLEX_START),e.alignItems===\"center\"&&t.setAlignItems(Pn.default.ALIGN_CENTER),e.alignItems===\"flex-end\"&&t.setAlignItems(Pn.default.ALIGN_FLEX_END)),\"alignSelf\"in e&&((e.alignSelf===\"auto\"||!e.alignSelf)&&t.setAlignSelf(Pn.default.ALIGN_AUTO),e.alignSelf===\"flex-start\"&&t.setAlignSelf(Pn.default.ALIGN_FLEX_START),e.alignSelf===\"center\"&&t.setAlignSelf(Pn.default.ALIGN_CENTER),e.alignSelf===\"flex-end\"&&t.setAlignSelf(Pn.default.ALIGN_FLEX_END)),\"justifyContent\"in e&&((e.justifyContent===\"flex-start\"||!e.justifyContent)&&t.setJustifyContent(Pn.default.JUSTIFY_FLEX_START),e.justifyContent===\"center\"&&t.setJustifyContent(Pn.default.JUSTIFY_CENTER),e.justifyContent===\"flex-end\"&&t.setJustifyContent(Pn.default.JUSTIFY_FLEX_END),e.justifyContent===\"space-between\"&&t.setJustifyContent(Pn.default.JUSTIFY_SPACE_BETWEEN),e.justifyContent===\"space-around\"&&t.setJustifyContent(Pn.default.JUSTIFY_SPACE_AROUND))},Tpt=(t,e)=>{var r,s;\"width\"in e&&(typeof e.width==\"number\"?t.setWidth(e.width):typeof e.width==\"string\"?t.setWidthPercent(Number.parseInt(e.width,10)):t.setWidthAuto()),\"height\"in e&&(typeof e.height==\"number\"?t.setHeight(e.height):typeof e.height==\"string\"?t.setHeightPercent(Number.parseInt(e.height,10)):t.setHeightAuto()),\"minWidth\"in e&&(typeof e.minWidth==\"string\"?t.setMinWidthPercent(Number.parseInt(e.minWidth,10)):t.setMinWidth((r=e.minWidth)!==null&&r!==void 0?r:0)),\"minHeight\"in e&&(typeof e.minHeight==\"string\"?t.setMinHeightPercent(Number.parseInt(e.minHeight,10)):t.setMinHeight((s=e.minHeight)!==null&&s!==void 0?s:0))},Fpt=(t,e)=>{\"display\"in e&&t.setDisplay(e.display===\"flex\"?Pn.default.DISPLAY_FLEX:Pn.default.DISPLAY_NONE)},Npt=(t,e)=>{if(\"borderStyle\"in e){let r=typeof e.borderStyle==\"string\"?1:0;t.setBorder(Pn.default.EDGE_TOP,r),t.setBorder(Pn.default.EDGE_BOTTOM,r),t.setBorder(Pn.default.EDGE_LEFT,r),t.setBorder(Pn.default.EDGE_RIGHT,r)}};WS.default=(t,e={})=>{xpt(t,e),kpt(t,e),Qpt(t,e),Rpt(t,e),Tpt(t,e),Fpt(t,e),Npt(t,e)}});var Mwe=_((dKt,Lwe)=>{\"use strict\";var YS=GS(),Opt=dk(),Lpt=sk(),Z9=new Set([\"\\x1B\",\"\\x9B\"]),Mpt=39,Owe=t=>`${Z9.values().next().value}[${t}m`,Upt=t=>t.split(\" \").map(e=>YS(e)),z9=(t,e,r)=>{let s=[...e],a=!1,n=YS(Opt(t[t.length-1]));for(let[c,f]of s.entries()){let p=YS(f);if(n+p<=r?t[t.length-1]+=f:(t.push(f),n=0),Z9.has(f))a=!0;else if(a&&f===\"m\"){a=!1;continue}a||(n+=p,n===r&&c<s.length-1&&(t.push(\"\"),n=0))}!n&&t[t.length-1].length>0&&t.length>1&&(t[t.length-2]+=t.pop())},_pt=t=>{let e=t.split(\" \"),r=e.length;for(;r>0&&!(YS(e[r-1])>0);)r--;return r===e.length?t:e.slice(0,r).join(\" \")+e.slice(r).join(\"\")},Hpt=(t,e,r={})=>{if(r.trim!==!1&&t.trim()===\"\")return\"\";let s=\"\",a=\"\",n,c=Upt(t),f=[\"\"];for(let[p,h]of t.split(\" \").entries()){r.trim!==!1&&(f[f.length-1]=f[f.length-1].trimLeft());let E=YS(f[f.length-1]);if(p!==0&&(E>=e&&(r.wordWrap===!1||r.trim===!1)&&(f.push(\"\"),E=0),(E>0||r.trim===!1)&&(f[f.length-1]+=\" \",E++)),r.hard&&c[p]>e){let C=e-E,S=1+Math.floor((c[p]-C-1)/e);Math.floor((c[p]-1)/e)<S&&f.push(\"\"),z9(f,h,e);continue}if(E+c[p]>e&&E>0&&c[p]>0){if(r.wordWrap===!1&&E<e){z9(f,h,e);continue}f.push(\"\")}if(E+c[p]>e&&r.wordWrap===!1){z9(f,h,e);continue}f[f.length-1]+=h}r.trim!==!1&&(f=f.map(_pt)),s=f.join(`\n`);for(let[p,h]of[...s].entries()){if(a+=h,Z9.has(h)){let C=parseFloat(/\\d[^m]*/.exec(s.slice(p,p+4)));n=C===Mpt?null:C}let E=Lpt.codes.get(Number(n));n&&E&&(s[p+1]===`\n`?a+=Owe(E):h===`\n`&&(a+=Owe(n)))}return a};Lwe.exports=(t,e,r)=>String(t).normalize().replace(/\\r\\n/g,`\n`).split(`\n`).map(s=>Hpt(s,e,r)).join(`\n`)});var Hwe=_((mKt,_we)=>{\"use strict\";var Uwe=\"[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]\",jpt=t=>t&&t.exact?new RegExp(`^${Uwe}$`):new RegExp(Uwe,\"g\");_we.exports=jpt});var X9=_((yKt,Wwe)=>{\"use strict\";var Gpt=W9(),qpt=Hwe(),jwe=sk(),qwe=[\"\\x1B\",\"\\x9B\"],FF=t=>`${qwe[0]}[${t}m`,Gwe=(t,e,r)=>{let s=[];t=[...t];for(let a of t){let n=a;a.match(\";\")&&(a=a.split(\";\")[0][0]+\"0\");let c=jwe.codes.get(parseInt(a,10));if(c){let f=t.indexOf(c.toString());f>=0?t.splice(f,1):s.push(FF(e?c:n))}else if(e){s.push(FF(0));break}else s.push(FF(n))}if(e&&(s=s.filter((a,n)=>s.indexOf(a)===n),r!==void 0)){let a=FF(jwe.codes.get(parseInt(r,10)));s=s.reduce((n,c)=>c===a?[c,...n]:[...n,c],[])}return s.join(\"\")};Wwe.exports=(t,e,r)=>{let s=[...t.normalize()],a=[];r=typeof r==\"number\"?r:s.length;let n=!1,c,f=0,p=\"\";for(let[h,E]of s.entries()){let C=!1;if(qwe.includes(E)){let S=/\\d[^m]*/.exec(t.slice(h,h+18));c=S&&S.length>0?S[0]:void 0,f<r&&(n=!0,c!==void 0&&a.push(c))}else n&&E===\"m\"&&(n=!1,C=!0);if(!n&&!C&&++f,!qpt({exact:!0}).test(E)&&Gpt(E.codePointAt())&&++f,f>e&&f<=r)p+=E;else if(f===e&&!n&&c!==void 0)p=Gwe(a);else if(f>=r){p+=Gwe(a,!0,c);break}}return p}});var Vwe=_((EKt,Ywe)=>{\"use strict\";var $0=X9(),Wpt=GS();function NF(t,e,r){if(t.charAt(e)===\" \")return e;for(let s=1;s<=3;s++)if(r){if(t.charAt(e+s)===\" \")return e+s}else if(t.charAt(e-s)===\" \")return e-s;return e}Ywe.exports=(t,e,r)=>{r={position:\"end\",preferTruncationOnSpace:!1,...r};let{position:s,space:a,preferTruncationOnSpace:n}=r,c=\"\\u2026\",f=1;if(typeof t!=\"string\")throw new TypeError(`Expected \\`input\\` to be a string, got ${typeof t}`);if(typeof e!=\"number\")throw new TypeError(`Expected \\`columns\\` to be a number, got ${typeof e}`);if(e<1)return\"\";if(e===1)return c;let p=Wpt(t);if(p<=e)return t;if(s===\"start\"){if(n){let h=NF(t,p-e+1,!0);return c+$0(t,h,p).trim()}return a===!0&&(c+=\" \",f=2),c+$0(t,p-e+f,p)}if(s===\"middle\"){a===!0&&(c=\" \"+c+\" \",f=3);let h=Math.floor(e/2);if(n){let E=NF(t,h),C=NF(t,p-(e-h)+1,!0);return $0(t,0,E)+c+$0(t,C,p).trim()}return $0(t,0,h)+c+$0(t,p-(e-h)+f,p)}if(s===\"end\"){if(n){let h=NF(t,e-1);return $0(t,0,h)+c}return a===!0&&(c=\" \"+c,f=2),$0(t,0,e-f)+c}throw new Error(`Expected \\`options.position\\` to be either \\`start\\`, \\`middle\\` or \\`end\\`, got ${s}`)}});var eW=_(VS=>{\"use strict\";var Jwe=VS&&VS.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(VS,\"__esModule\",{value:!0});var Ypt=Jwe(Mwe()),Vpt=Jwe(Vwe()),$9={};VS.default=(t,e,r)=>{let s=t+String(e)+String(r);if($9[s])return $9[s];let a=t;if(r===\"wrap\"&&(a=Ypt.default(t,e,{trim:!1,hard:!0})),r.startsWith(\"truncate\")){let n=\"end\";r===\"truncate-middle\"&&(n=\"middle\"),r===\"truncate-start\"&&(n=\"start\"),a=Vpt.default(t,e,{position:n})}return $9[s]=a,a}});var rW=_(tW=>{\"use strict\";Object.defineProperty(tW,\"__esModule\",{value:!0});var Kwe=t=>{let e=\"\";if(t.childNodes.length>0)for(let r of t.childNodes){let s=\"\";r.nodeName===\"#text\"?s=r.nodeValue:((r.nodeName===\"ink-text\"||r.nodeName===\"ink-virtual-text\")&&(s=Kwe(r)),s.length>0&&typeof r.internal_transform==\"function\"&&(s=r.internal_transform(s))),e+=s}return e};tW.default=Kwe});var nW=_(Pi=>{\"use strict\";var JS=Pi&&Pi.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(Pi,\"__esModule\",{value:!0});Pi.setTextNodeValue=Pi.createTextNode=Pi.setStyle=Pi.setAttribute=Pi.removeChildNode=Pi.insertBeforeNode=Pi.appendChildNode=Pi.createNode=Pi.TEXT_NAME=void 0;var Jpt=JS(Fm()),zwe=JS(Fwe()),Kpt=JS(Nwe()),zpt=JS(eW()),Zpt=JS(rW());Pi.TEXT_NAME=\"#text\";Pi.createNode=t=>{var e;let r={nodeName:t,style:{},attributes:{},childNodes:[],parentNode:null,yogaNode:t===\"ink-virtual-text\"?void 0:Jpt.default.Node.create()};return t===\"ink-text\"&&((e=r.yogaNode)===null||e===void 0||e.setMeasureFunc(Xpt.bind(null,r))),r};Pi.appendChildNode=(t,e)=>{var r;e.parentNode&&Pi.removeChildNode(e.parentNode,e),e.parentNode=t,t.childNodes.push(e),e.yogaNode&&((r=t.yogaNode)===null||r===void 0||r.insertChild(e.yogaNode,t.yogaNode.getChildCount())),(t.nodeName===\"ink-text\"||t.nodeName===\"ink-virtual-text\")&&OF(t)};Pi.insertBeforeNode=(t,e,r)=>{var s,a;e.parentNode&&Pi.removeChildNode(e.parentNode,e),e.parentNode=t;let n=t.childNodes.indexOf(r);if(n>=0){t.childNodes.splice(n,0,e),e.yogaNode&&((s=t.yogaNode)===null||s===void 0||s.insertChild(e.yogaNode,n));return}t.childNodes.push(e),e.yogaNode&&((a=t.yogaNode)===null||a===void 0||a.insertChild(e.yogaNode,t.yogaNode.getChildCount())),(t.nodeName===\"ink-text\"||t.nodeName===\"ink-virtual-text\")&&OF(t)};Pi.removeChildNode=(t,e)=>{var r,s;e.yogaNode&&((s=(r=e.parentNode)===null||r===void 0?void 0:r.yogaNode)===null||s===void 0||s.removeChild(e.yogaNode)),e.parentNode=null;let a=t.childNodes.indexOf(e);a>=0&&t.childNodes.splice(a,1),(t.nodeName===\"ink-text\"||t.nodeName===\"ink-virtual-text\")&&OF(t)};Pi.setAttribute=(t,e,r)=>{t.attributes[e]=r};Pi.setStyle=(t,e)=>{t.style=e,t.yogaNode&&Kpt.default(t.yogaNode,e)};Pi.createTextNode=t=>{let e={nodeName:\"#text\",nodeValue:t,yogaNode:void 0,parentNode:null,style:{}};return Pi.setTextNodeValue(e,t),e};var Xpt=function(t,e){var r,s;let a=t.nodeName===\"#text\"?t.nodeValue:Zpt.default(t),n=zwe.default(a);if(n.width<=e||n.width>=1&&e>0&&e<1)return n;let c=(s=(r=t.style)===null||r===void 0?void 0:r.textWrap)!==null&&s!==void 0?s:\"wrap\",f=zpt.default(a,e,c);return zwe.default(f)},Zwe=t=>{var e;if(!(!t||!t.parentNode))return(e=t.yogaNode)!==null&&e!==void 0?e:Zwe(t.parentNode)},OF=t=>{let e=Zwe(t);e?.markDirty()};Pi.setTextNodeValue=(t,e)=>{typeof e!=\"string\"&&(e=String(e)),t.nodeValue=e,OF(t)}});var r1e=_(KS=>{\"use strict\";var t1e=KS&&KS.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(KS,\"__esModule\",{value:!0});var Xwe=U9(),$pt=t1e(Iwe()),$we=t1e(Fm()),ea=nW(),e1e=t=>{t?.unsetMeasureFunc(),t?.freeRecursive()};KS.default=$pt.default({schedulePassiveEffects:Xwe.unstable_scheduleCallback,cancelPassiveEffects:Xwe.unstable_cancelCallback,now:Date.now,getRootHostContext:()=>({isInsideText:!1}),prepareForCommit:()=>null,preparePortalMount:()=>null,clearContainer:()=>!1,shouldDeprioritizeSubtree:()=>!1,resetAfterCommit:t=>{if(t.isStaticDirty){t.isStaticDirty=!1,typeof t.onImmediateRender==\"function\"&&t.onImmediateRender();return}typeof t.onRender==\"function\"&&t.onRender()},getChildHostContext:(t,e)=>{let r=t.isInsideText,s=e===\"ink-text\"||e===\"ink-virtual-text\";return r===s?t:{isInsideText:s}},shouldSetTextContent:()=>!1,createInstance:(t,e,r,s)=>{if(s.isInsideText&&t===\"ink-box\")throw new Error(\"<Box> can\\u2019t be nested inside <Text> component\");let a=t===\"ink-text\"&&s.isInsideText?\"ink-virtual-text\":t,n=ea.createNode(a);for(let[c,f]of Object.entries(e))c!==\"children\"&&(c===\"style\"?ea.setStyle(n,f):c===\"internal_transform\"?n.internal_transform=f:c===\"internal_static\"?n.internal_static=!0:ea.setAttribute(n,c,f));return n},createTextInstance:(t,e,r)=>{if(!r.isInsideText)throw new Error(`Text string \"${t}\" must be rendered inside <Text> component`);return ea.createTextNode(t)},resetTextContent:()=>{},hideTextInstance:t=>{ea.setTextNodeValue(t,\"\")},unhideTextInstance:(t,e)=>{ea.setTextNodeValue(t,e)},getPublicInstance:t=>t,hideInstance:t=>{var e;(e=t.yogaNode)===null||e===void 0||e.setDisplay($we.default.DISPLAY_NONE)},unhideInstance:t=>{var e;(e=t.yogaNode)===null||e===void 0||e.setDisplay($we.default.DISPLAY_FLEX)},appendInitialChild:ea.appendChildNode,appendChild:ea.appendChildNode,insertBefore:ea.insertBeforeNode,finalizeInitialChildren:(t,e,r,s)=>(t.internal_static&&(s.isStaticDirty=!0,s.staticNode=t),!1),supportsMutation:!0,appendChildToContainer:ea.appendChildNode,insertInContainerBefore:ea.insertBeforeNode,removeChildFromContainer:(t,e)=>{ea.removeChildNode(t,e),e1e(e.yogaNode)},prepareUpdate:(t,e,r,s,a)=>{t.internal_static&&(a.isStaticDirty=!0);let n={},c=Object.keys(s);for(let f of c)if(s[f]!==r[f]){if(f===\"style\"&&typeof s.style==\"object\"&&typeof r.style==\"object\"){let h=s.style,E=r.style,C=Object.keys(h);for(let S of C){if(S===\"borderStyle\"||S===\"borderColor\"){if(typeof n.style!=\"object\"){let b={};n.style=b}n.style.borderStyle=h.borderStyle,n.style.borderColor=h.borderColor}if(h[S]!==E[S]){if(typeof n.style!=\"object\"){let b={};n.style=b}n.style[S]=h[S]}}continue}n[f]=s[f]}return n},commitUpdate:(t,e)=>{for(let[r,s]of Object.entries(e))r!==\"children\"&&(r===\"style\"?ea.setStyle(t,s):r===\"internal_transform\"?t.internal_transform=s:r===\"internal_static\"?t.internal_static=!0:ea.setAttribute(t,r,s))},commitTextUpdate:(t,e,r)=>{ea.setTextNodeValue(t,r)},removeChild:(t,e)=>{ea.removeChildNode(t,e),e1e(e.yogaNode)}})});var i1e=_((vKt,n1e)=>{\"use strict\";n1e.exports=(t,e=1,r)=>{if(r={indent:\" \",includeEmptyLines:!1,...r},typeof t!=\"string\")throw new TypeError(`Expected \\`input\\` to be a \\`string\\`, got \\`${typeof t}\\``);if(typeof e!=\"number\")throw new TypeError(`Expected \\`count\\` to be a \\`number\\`, got \\`${typeof e}\\``);if(typeof r.indent!=\"string\")throw new TypeError(`Expected \\`options.indent\\` to be a \\`string\\`, got \\`${typeof r.indent}\\``);if(e===0)return t;let s=r.includeEmptyLines?/^/gm:/^(?!\\s*$)/gm;return t.replace(s,r.indent.repeat(e))}});var s1e=_(zS=>{\"use strict\";var eht=zS&&zS.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(zS,\"__esModule\",{value:!0});var LF=eht(Fm());zS.default=t=>t.getComputedWidth()-t.getComputedPadding(LF.default.EDGE_LEFT)-t.getComputedPadding(LF.default.EDGE_RIGHT)-t.getComputedBorder(LF.default.EDGE_LEFT)-t.getComputedBorder(LF.default.EDGE_RIGHT)});var o1e=_((DKt,tht)=>{tht.exports={single:{topLeft:\"\\u250C\",topRight:\"\\u2510\",bottomRight:\"\\u2518\",bottomLeft:\"\\u2514\",vertical:\"\\u2502\",horizontal:\"\\u2500\"},double:{topLeft:\"\\u2554\",topRight:\"\\u2557\",bottomRight:\"\\u255D\",bottomLeft:\"\\u255A\",vertical:\"\\u2551\",horizontal:\"\\u2550\"},round:{topLeft:\"\\u256D\",topRight:\"\\u256E\",bottomRight:\"\\u256F\",bottomLeft:\"\\u2570\",vertical:\"\\u2502\",horizontal:\"\\u2500\"},bold:{topLeft:\"\\u250F\",topRight:\"\\u2513\",bottomRight:\"\\u251B\",bottomLeft:\"\\u2517\",vertical:\"\\u2503\",horizontal:\"\\u2501\"},singleDouble:{topLeft:\"\\u2553\",topRight:\"\\u2556\",bottomRight:\"\\u255C\",bottomLeft:\"\\u2559\",vertical:\"\\u2551\",horizontal:\"\\u2500\"},doubleSingle:{topLeft:\"\\u2552\",topRight:\"\\u2555\",bottomRight:\"\\u255B\",bottomLeft:\"\\u2558\",vertical:\"\\u2502\",horizontal:\"\\u2550\"},classic:{topLeft:\"+\",topRight:\"+\",bottomRight:\"+\",bottomLeft:\"+\",vertical:\"|\",horizontal:\"-\"}}});var l1e=_((PKt,iW)=>{\"use strict\";var a1e=o1e();iW.exports=a1e;iW.exports.default=a1e});var sW=_(XS=>{\"use strict\";var rht=XS&&XS.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(XS,\"__esModule\",{value:!0});var ZS=rht(RE()),nht=/^(rgb|hsl|hsv|hwb)\\(\\s?(\\d+),\\s?(\\d+),\\s?(\\d+)\\s?\\)$/,iht=/^(ansi|ansi256)\\(\\s?(\\d+)\\s?\\)$/,MF=(t,e)=>e===\"foreground\"?t:\"bg\"+t[0].toUpperCase()+t.slice(1);XS.default=(t,e,r)=>{if(!e)return t;if(e in ZS.default){let a=MF(e,r);return ZS.default[a](t)}if(e.startsWith(\"#\")){let a=MF(\"hex\",r);return ZS.default[a](e)(t)}if(e.startsWith(\"ansi\")){let a=iht.exec(e);if(!a)return t;let n=MF(a[1],r),c=Number(a[2]);return ZS.default[n](c)(t)}if(e.startsWith(\"rgb\")||e.startsWith(\"hsl\")||e.startsWith(\"hsv\")||e.startsWith(\"hwb\")){let a=nht.exec(e);if(!a)return t;let n=MF(a[1],r),c=Number(a[2]),f=Number(a[3]),p=Number(a[4]);return ZS.default[n](c,f,p)(t)}return t}});var u1e=_($S=>{\"use strict\";var c1e=$S&&$S.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty($S,\"__esModule\",{value:!0});var sht=c1e(l1e()),oW=c1e(sW());$S.default=(t,e,r,s)=>{if(typeof r.style.borderStyle==\"string\"){let a=r.yogaNode.getComputedWidth(),n=r.yogaNode.getComputedHeight(),c=r.style.borderColor,f=sht.default[r.style.borderStyle],p=oW.default(f.topLeft+f.horizontal.repeat(a-2)+f.topRight,c,\"foreground\"),h=(oW.default(f.vertical,c,\"foreground\")+`\n`).repeat(n-2),E=oW.default(f.bottomLeft+f.horizontal.repeat(a-2)+f.bottomRight,c,\"foreground\");s.write(t,e,p,{transformers:[]}),s.write(t,e+1,h,{transformers:[]}),s.write(t+a-1,e+1,h,{transformers:[]}),s.write(t,e+n-1,E,{transformers:[]})}}});var A1e=_(eD=>{\"use strict\";var Nm=eD&&eD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(eD,\"__esModule\",{value:!0});var oht=Nm(Fm()),aht=Nm(J9()),lht=Nm(i1e()),cht=Nm(eW()),uht=Nm(s1e()),fht=Nm(rW()),Aht=Nm(u1e()),pht=(t,e)=>{var r;let s=(r=t.childNodes[0])===null||r===void 0?void 0:r.yogaNode;if(s){let a=s.getComputedLeft(),n=s.getComputedTop();e=`\n`.repeat(n)+lht.default(e,a)}return e},f1e=(t,e,r)=>{var s;let{offsetX:a=0,offsetY:n=0,transformers:c=[],skipStaticElements:f}=r;if(f&&t.internal_static)return;let{yogaNode:p}=t;if(p){if(p.getDisplay()===oht.default.DISPLAY_NONE)return;let h=a+p.getComputedLeft(),E=n+p.getComputedTop(),C=c;if(typeof t.internal_transform==\"function\"&&(C=[t.internal_transform,...c]),t.nodeName===\"ink-text\"){let S=fht.default(t);if(S.length>0){let b=aht.default(S),I=uht.default(p);if(b>I){let T=(s=t.style.textWrap)!==null&&s!==void 0?s:\"wrap\";S=cht.default(S,I,T)}S=pht(t,S),e.write(h,E,S,{transformers:C})}return}if(t.nodeName===\"ink-box\"&&Aht.default(h,E,t,e),t.nodeName===\"ink-root\"||t.nodeName===\"ink-box\")for(let S of t.childNodes)f1e(S,e,{offsetX:h,offsetY:E,transformers:C,skipStaticElements:f})}};eD.default=f1e});var g1e=_(tD=>{\"use strict\";var h1e=tD&&tD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(tD,\"__esModule\",{value:!0});var p1e=h1e(X9()),hht=h1e(GS()),aW=class{constructor(e){this.writes=[];let{width:r,height:s}=e;this.width=r,this.height=s}write(e,r,s,a){let{transformers:n}=a;s&&this.writes.push({x:e,y:r,text:s,transformers:n})}get(){let e=[];for(let s=0;s<this.height;s++)e.push(\" \".repeat(this.width));for(let s of this.writes){let{x:a,y:n,text:c,transformers:f}=s,p=c.split(`\n`),h=0;for(let E of p){let C=e[n+h];if(!C)continue;let S=hht.default(E);for(let b of f)E=b(E);e[n+h]=p1e.default(C,0,a)+E+p1e.default(C,a+S),h++}}return{output:e.map(s=>s.trimRight()).join(`\n`),height:e.length}}};tD.default=aW});var y1e=_(rD=>{\"use strict\";var lW=rD&&rD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(rD,\"__esModule\",{value:!0});var ght=lW(Fm()),d1e=lW(A1e()),m1e=lW(g1e());rD.default=(t,e)=>{var r;if(t.yogaNode.setWidth(e),t.yogaNode){t.yogaNode.calculateLayout(void 0,void 0,ght.default.DIRECTION_LTR);let s=new m1e.default({width:t.yogaNode.getComputedWidth(),height:t.yogaNode.getComputedHeight()});d1e.default(t,s,{skipStaticElements:!0});let a;!((r=t.staticNode)===null||r===void 0)&&r.yogaNode&&(a=new m1e.default({width:t.staticNode.yogaNode.getComputedWidth(),height:t.staticNode.yogaNode.getComputedHeight()}),d1e.default(t.staticNode,a,{skipStaticElements:!1}));let{output:n,height:c}=s.get();return{output:n,outputHeight:c,staticOutput:a?`${a.get().output}\n`:\"\"}}return{output:\"\",outputHeight:0,staticOutput:\"\"}}});var w1e=_((TKt,C1e)=>{\"use strict\";var E1e=Ie(\"stream\"),I1e=[\"assert\",\"count\",\"countReset\",\"debug\",\"dir\",\"dirxml\",\"error\",\"group\",\"groupCollapsed\",\"groupEnd\",\"info\",\"log\",\"table\",\"time\",\"timeEnd\",\"timeLog\",\"trace\",\"warn\"],cW={},dht=t=>{let e=new E1e.PassThrough,r=new E1e.PassThrough;e.write=a=>t(\"stdout\",a),r.write=a=>t(\"stderr\",a);let s=new console.Console(e,r);for(let a of I1e)cW[a]=console[a],console[a]=s[a];return()=>{for(let a of I1e)console[a]=cW[a];cW={}}};C1e.exports=dht});var fW=_(uW=>{\"use strict\";Object.defineProperty(uW,\"__esModule\",{value:!0});uW.default=new WeakMap});var pW=_(AW=>{\"use strict\";Object.defineProperty(AW,\"__esModule\",{value:!0});var mht=hn(),B1e=mht.createContext({exit:()=>{}});B1e.displayName=\"InternalAppContext\";AW.default=B1e});var gW=_(hW=>{\"use strict\";Object.defineProperty(hW,\"__esModule\",{value:!0});var yht=hn(),v1e=yht.createContext({stdin:void 0,setRawMode:()=>{},isRawModeSupported:!1,internal_exitOnCtrlC:!0});v1e.displayName=\"InternalStdinContext\";hW.default=v1e});var mW=_(dW=>{\"use strict\";Object.defineProperty(dW,\"__esModule\",{value:!0});var Eht=hn(),S1e=Eht.createContext({stdout:void 0,write:()=>{}});S1e.displayName=\"InternalStdoutContext\";dW.default=S1e});var EW=_(yW=>{\"use strict\";Object.defineProperty(yW,\"__esModule\",{value:!0});var Iht=hn(),D1e=Iht.createContext({stderr:void 0,write:()=>{}});D1e.displayName=\"InternalStderrContext\";yW.default=D1e});var UF=_(IW=>{\"use strict\";Object.defineProperty(IW,\"__esModule\",{value:!0});var Cht=hn(),P1e=Cht.createContext({activeId:void 0,add:()=>{},remove:()=>{},activate:()=>{},deactivate:()=>{},enableFocus:()=>{},disableFocus:()=>{},focusNext:()=>{},focusPrevious:()=>{},focus:()=>{}});P1e.displayName=\"InternalFocusContext\";IW.default=P1e});var x1e=_((_Kt,b1e)=>{\"use strict\";var wht=/[|\\\\{}()[\\]^$+*?.-]/g;b1e.exports=t=>{if(typeof t!=\"string\")throw new TypeError(\"Expected a string\");return t.replace(wht,\"\\\\$&\")}});var T1e=_((HKt,R1e)=>{\"use strict\";var Bht=x1e(),vht=typeof process==\"object\"&&process&&typeof process.cwd==\"function\"?process.cwd():\".\",Q1e=[].concat(Ie(\"module\").builtinModules,\"bootstrap_node\",\"node\").map(t=>new RegExp(`(?:\\\\((?:node:)?${t}(?:\\\\.js)?:\\\\d+:\\\\d+\\\\)$|^\\\\s*at (?:node:)?${t}(?:\\\\.js)?:\\\\d+:\\\\d+$)`));Q1e.push(/\\((?:node:)?internal\\/[^:]+:\\d+:\\d+\\)$/,/\\s*at (?:node:)?internal\\/[^:]+:\\d+:\\d+$/,/\\/\\.node-spawn-wrap-\\w+-\\w+\\/node:\\d+:\\d+\\)?$/);var CW=class t{constructor(e){e={ignoredPackages:[],...e},\"internals\"in e||(e.internals=t.nodeInternals()),\"cwd\"in e||(e.cwd=vht),this._cwd=e.cwd.replace(/\\\\/g,\"/\"),this._internals=[].concat(e.internals,Sht(e.ignoredPackages)),this._wrapCallSite=e.wrapCallSite||!1}static nodeInternals(){return[...Q1e]}clean(e,r=0){r=\" \".repeat(r),Array.isArray(e)||(e=e.split(`\n`)),!/^\\s*at /.test(e[0])&&/^\\s*at /.test(e[1])&&(e=e.slice(1));let s=!1,a=null,n=[];return e.forEach(c=>{if(c=c.replace(/\\\\/g,\"/\"),this._internals.some(p=>p.test(c)))return;let f=/^\\s*at /.test(c);s?c=c.trimEnd().replace(/^(\\s+)at /,\"$1\"):(c=c.trim(),f&&(c=c.slice(3))),c=c.replace(`${this._cwd}/`,\"\"),c&&(f?(a&&(n.push(a),a=null),n.push(c)):(s=!0,a=c))}),n.map(c=>`${r}${c}\n`).join(\"\")}captureString(e,r=this.captureString){typeof e==\"function\"&&(r=e,e=1/0);let{stackTraceLimit:s}=Error;e&&(Error.stackTraceLimit=e);let a={};Error.captureStackTrace(a,r);let{stack:n}=a;return Error.stackTraceLimit=s,this.clean(n)}capture(e,r=this.capture){typeof e==\"function\"&&(r=e,e=1/0);let{prepareStackTrace:s,stackTraceLimit:a}=Error;Error.prepareStackTrace=(f,p)=>this._wrapCallSite?p.map(this._wrapCallSite):p,e&&(Error.stackTraceLimit=e);let n={};Error.captureStackTrace(n,r);let{stack:c}=n;return Object.assign(Error,{prepareStackTrace:s,stackTraceLimit:a}),c}at(e=this.at){let[r]=this.capture(1,e);if(!r)return{};let s={line:r.getLineNumber(),column:r.getColumnNumber()};k1e(s,r.getFileName(),this._cwd),r.isConstructor()&&(s.constructor=!0),r.isEval()&&(s.evalOrigin=r.getEvalOrigin()),r.isNative()&&(s.native=!0);let a;try{a=r.getTypeName()}catch{}a&&a!==\"Object\"&&a!==\"[object Object]\"&&(s.type=a);let n=r.getFunctionName();n&&(s.function=n);let c=r.getMethodName();return c&&n!==c&&(s.method=c),s}parseLine(e){let r=e&&e.match(Dht);if(!r)return null;let s=r[1]===\"new\",a=r[2],n=r[3],c=r[4],f=Number(r[5]),p=Number(r[6]),h=r[7],E=r[8],C=r[9],S=r[10]===\"native\",b=r[11]===\")\",I,T={};if(E&&(T.line=Number(E)),C&&(T.column=Number(C)),b&&h){let N=0;for(let U=h.length-1;U>0;U--)if(h.charAt(U)===\")\")N++;else if(h.charAt(U)===\"(\"&&h.charAt(U-1)===\" \"&&(N--,N===-1&&h.charAt(U-1)===\" \")){let W=h.slice(0,U-1);h=h.slice(U+1),a+=` (${W}`;break}}if(a){let N=a.match(Pht);N&&(a=N[1],I=N[2])}return k1e(T,h,this._cwd),s&&(T.constructor=!0),n&&(T.evalOrigin=n,T.evalLine=f,T.evalColumn=p,T.evalFile=c&&c.replace(/\\\\/g,\"/\")),S&&(T.native=!0),a&&(T.function=a),I&&a!==I&&(T.method=I),T}};function k1e(t,e,r){e&&(e=e.replace(/\\\\/g,\"/\"),e.startsWith(`${r}/`)&&(e=e.slice(r.length+1)),t.file=e)}function Sht(t){if(t.length===0)return[];let e=t.map(r=>Bht(r));return new RegExp(`[/\\\\\\\\]node_modules[/\\\\\\\\](?:${e.join(\"|\")})[/\\\\\\\\][^:]+:\\\\d+:\\\\d+`)}var Dht=new RegExp(\"^(?:\\\\s*at )?(?:(new) )?(?:(.*?) \\\\()?(?:eval at ([^ ]+) \\\\((.+?):(\\\\d+):(\\\\d+)\\\\), )?(?:(.+?):(\\\\d+):(\\\\d+)|(native))(\\\\)?)$\"),Pht=/^(.*?) \\[as (.*?)\\]$/;R1e.exports=CW});var N1e=_((jKt,F1e)=>{\"use strict\";F1e.exports=(t,e)=>t.replace(/^\\t+/gm,r=>\" \".repeat(r.length*(e||2)))});var L1e=_((GKt,O1e)=>{\"use strict\";var bht=N1e(),xht=(t,e)=>{let r=[],s=t-e,a=t+e;for(let n=s;n<=a;n++)r.push(n);return r};O1e.exports=(t,e,r)=>{if(typeof t!=\"string\")throw new TypeError(\"Source code is missing.\");if(!e||e<1)throw new TypeError(\"Line number must start from `1`.\");if(t=bht(t).split(/\\r?\\n/),!(e>t.length))return r={around:3,...r},xht(e,r.around).filter(s=>t[s-1]!==void 0).map(s=>({line:s,value:t[s-1]}))}});var _F=_(rf=>{\"use strict\";var kht=rf&&rf.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),Qht=rf&&rf.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),Rht=rf&&rf.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.hasOwnProperty.call(t,r)&&kht(e,t,r);return Qht(e,t),e},Tht=rf&&rf.__rest||function(t,e){var r={};for(var s in t)Object.prototype.hasOwnProperty.call(t,s)&&e.indexOf(s)<0&&(r[s]=t[s]);if(t!=null&&typeof Object.getOwnPropertySymbols==\"function\")for(var a=0,s=Object.getOwnPropertySymbols(t);a<s.length;a++)e.indexOf(s[a])<0&&Object.prototype.propertyIsEnumerable.call(t,s[a])&&(r[s[a]]=t[s[a]]);return r};Object.defineProperty(rf,\"__esModule\",{value:!0});var M1e=Rht(hn()),wW=M1e.forwardRef((t,e)=>{var{children:r}=t,s=Tht(t,[\"children\"]);let a=Object.assign(Object.assign({},s),{marginLeft:s.marginLeft||s.marginX||s.margin||0,marginRight:s.marginRight||s.marginX||s.margin||0,marginTop:s.marginTop||s.marginY||s.margin||0,marginBottom:s.marginBottom||s.marginY||s.margin||0,paddingLeft:s.paddingLeft||s.paddingX||s.padding||0,paddingRight:s.paddingRight||s.paddingX||s.padding||0,paddingTop:s.paddingTop||s.paddingY||s.padding||0,paddingBottom:s.paddingBottom||s.paddingY||s.padding||0});return M1e.default.createElement(\"ink-box\",{ref:e,style:a},r)});wW.displayName=\"Box\";wW.defaultProps={flexDirection:\"row\",flexGrow:0,flexShrink:1};rf.default=wW});var SW=_(nD=>{\"use strict\";var BW=nD&&nD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(nD,\"__esModule\",{value:!0});var Fht=BW(hn()),yw=BW(RE()),U1e=BW(sW()),vW=({color:t,backgroundColor:e,dimColor:r,bold:s,italic:a,underline:n,strikethrough:c,inverse:f,wrap:p,children:h})=>{if(h==null)return null;let E=C=>(r&&(C=yw.default.dim(C)),t&&(C=U1e.default(C,t,\"foreground\")),e&&(C=U1e.default(C,e,\"background\")),s&&(C=yw.default.bold(C)),a&&(C=yw.default.italic(C)),n&&(C=yw.default.underline(C)),c&&(C=yw.default.strikethrough(C)),f&&(C=yw.default.inverse(C)),C);return Fht.default.createElement(\"ink-text\",{style:{flexGrow:0,flexShrink:1,flexDirection:\"row\",textWrap:p},internal_transform:E},h)};vW.displayName=\"Text\";vW.defaultProps={dimColor:!1,bold:!1,italic:!1,underline:!1,strikethrough:!1,wrap:\"wrap\"};nD.default=vW});var G1e=_(nf=>{\"use strict\";var Nht=nf&&nf.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),Oht=nf&&nf.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),Lht=nf&&nf.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.hasOwnProperty.call(t,r)&&Nht(e,t,r);return Oht(e,t),e},iD=nf&&nf.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(nf,\"__esModule\",{value:!0});var _1e=Lht(Ie(\"fs\")),Qs=iD(hn()),H1e=iD(T1e()),Mht=iD(L1e()),$p=iD(_F()),AA=iD(SW()),j1e=new H1e.default({cwd:process.cwd(),internals:H1e.default.nodeInternals()}),Uht=({error:t})=>{let e=t.stack?t.stack.split(`\n`).slice(1):void 0,r=e?j1e.parseLine(e[0]):void 0,s,a=0;if(r?.file&&r?.line&&_1e.existsSync(r.file)){let n=_1e.readFileSync(r.file,\"utf8\");if(s=Mht.default(n,r.line),s)for(let{line:c}of s)a=Math.max(a,String(c).length)}return Qs.default.createElement($p.default,{flexDirection:\"column\",padding:1},Qs.default.createElement($p.default,null,Qs.default.createElement(AA.default,{backgroundColor:\"red\",color:\"white\"},\" \",\"ERROR\",\" \"),Qs.default.createElement(AA.default,null,\" \",t.message)),r&&Qs.default.createElement($p.default,{marginTop:1},Qs.default.createElement(AA.default,{dimColor:!0},r.file,\":\",r.line,\":\",r.column)),r&&s&&Qs.default.createElement($p.default,{marginTop:1,flexDirection:\"column\"},s.map(({line:n,value:c})=>Qs.default.createElement($p.default,{key:n},Qs.default.createElement($p.default,{width:a+1},Qs.default.createElement(AA.default,{dimColor:n!==r.line,backgroundColor:n===r.line?\"red\":void 0,color:n===r.line?\"white\":void 0},String(n).padStart(a,\" \"),\":\")),Qs.default.createElement(AA.default,{key:n,backgroundColor:n===r.line?\"red\":void 0,color:n===r.line?\"white\":void 0},\" \"+c)))),t.stack&&Qs.default.createElement($p.default,{marginTop:1,flexDirection:\"column\"},t.stack.split(`\n`).slice(1).map(n=>{let c=j1e.parseLine(n);return c?Qs.default.createElement($p.default,{key:n},Qs.default.createElement(AA.default,{dimColor:!0},\"- \"),Qs.default.createElement(AA.default,{dimColor:!0,bold:!0},c.function),Qs.default.createElement(AA.default,{dimColor:!0,color:\"gray\"},\" \",\"(\",c.file,\":\",c.line,\":\",c.column,\")\")):Qs.default.createElement($p.default,{key:n},Qs.default.createElement(AA.default,{dimColor:!0},\"- \"),Qs.default.createElement(AA.default,{dimColor:!0,bold:!0},n))})))};nf.default=Uht});var W1e=_(sf=>{\"use strict\";var _ht=sf&&sf.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),Hht=sf&&sf.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),jht=sf&&sf.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.hasOwnProperty.call(t,r)&&_ht(e,t,r);return Hht(e,t),e},Lm=sf&&sf.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(sf,\"__esModule\",{value:!0});var Om=jht(hn()),q1e=Lm(P9()),Ght=Lm(pW()),qht=Lm(gW()),Wht=Lm(mW()),Yht=Lm(EW()),Vht=Lm(UF()),Jht=Lm(G1e()),Kht=\"\t\",zht=\"\\x1B[Z\",Zht=\"\\x1B\",HF=class extends Om.PureComponent{constructor(){super(...arguments),this.state={isFocusEnabled:!0,activeFocusId:void 0,focusables:[],error:void 0},this.rawModeEnabledCount=0,this.handleSetRawMode=e=>{let{stdin:r}=this.props;if(!this.isRawModeSupported())throw r===process.stdin?new Error(`Raw mode is not supported on the current process.stdin, which Ink uses as input stream by default.\nRead about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported`):new Error(`Raw mode is not supported on the stdin provided to Ink.\nRead about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported`);if(r.setEncoding(\"utf8\"),e){this.rawModeEnabledCount===0&&(r.addListener(\"data\",this.handleInput),r.resume(),r.setRawMode(!0)),this.rawModeEnabledCount++;return}--this.rawModeEnabledCount===0&&(r.setRawMode(!1),r.removeListener(\"data\",this.handleInput),r.pause())},this.handleInput=e=>{e===\"\u0003\"&&this.props.exitOnCtrlC&&this.handleExit(),e===Zht&&this.state.activeFocusId&&this.setState({activeFocusId:void 0}),this.state.isFocusEnabled&&this.state.focusables.length>0&&(e===Kht&&this.focusNext(),e===zht&&this.focusPrevious())},this.handleExit=e=>{this.isRawModeSupported()&&this.handleSetRawMode(!1),this.props.onExit(e)},this.enableFocus=()=>{this.setState({isFocusEnabled:!0})},this.disableFocus=()=>{this.setState({isFocusEnabled:!1})},this.focus=e=>{this.setState(r=>r.focusables.some(a=>a?.id===e)?{activeFocusId:e}:r)},this.focusNext=()=>{this.setState(e=>{var r;let s=(r=e.focusables[0])===null||r===void 0?void 0:r.id;return{activeFocusId:this.findNextFocusable(e)||s}})},this.focusPrevious=()=>{this.setState(e=>{var r;let s=(r=e.focusables[e.focusables.length-1])===null||r===void 0?void 0:r.id;return{activeFocusId:this.findPreviousFocusable(e)||s}})},this.addFocusable=(e,{autoFocus:r})=>{this.setState(s=>{let a=s.activeFocusId;return!a&&r&&(a=e),{activeFocusId:a,focusables:[...s.focusables,{id:e,isActive:!0}]}})},this.removeFocusable=e=>{this.setState(r=>({activeFocusId:r.activeFocusId===e?void 0:r.activeFocusId,focusables:r.focusables.filter(s=>s.id!==e)}))},this.activateFocusable=e=>{this.setState(r=>({focusables:r.focusables.map(s=>s.id!==e?s:{id:e,isActive:!0})}))},this.deactivateFocusable=e=>{this.setState(r=>({activeFocusId:r.activeFocusId===e?void 0:r.activeFocusId,focusables:r.focusables.map(s=>s.id!==e?s:{id:e,isActive:!1})}))},this.findNextFocusable=e=>{var r;let s=e.focusables.findIndex(a=>a.id===e.activeFocusId);for(let a=s+1;a<e.focusables.length;a++)if(!((r=e.focusables[a])===null||r===void 0)&&r.isActive)return e.focusables[a].id},this.findPreviousFocusable=e=>{var r;let s=e.focusables.findIndex(a=>a.id===e.activeFocusId);for(let a=s-1;a>=0;a--)if(!((r=e.focusables[a])===null||r===void 0)&&r.isActive)return e.focusables[a].id}}static getDerivedStateFromError(e){return{error:e}}isRawModeSupported(){return this.props.stdin.isTTY}render(){return Om.default.createElement(Ght.default.Provider,{value:{exit:this.handleExit}},Om.default.createElement(qht.default.Provider,{value:{stdin:this.props.stdin,setRawMode:this.handleSetRawMode,isRawModeSupported:this.isRawModeSupported(),internal_exitOnCtrlC:this.props.exitOnCtrlC}},Om.default.createElement(Wht.default.Provider,{value:{stdout:this.props.stdout,write:this.props.writeToStdout}},Om.default.createElement(Yht.default.Provider,{value:{stderr:this.props.stderr,write:this.props.writeToStderr}},Om.default.createElement(Vht.default.Provider,{value:{activeId:this.state.activeFocusId,add:this.addFocusable,remove:this.removeFocusable,activate:this.activateFocusable,deactivate:this.deactivateFocusable,enableFocus:this.enableFocus,disableFocus:this.disableFocus,focusNext:this.focusNext,focusPrevious:this.focusPrevious,focus:this.focus}},this.state.error?Om.default.createElement(Jht.default,{error:this.state.error}):this.props.children)))))}componentDidMount(){q1e.default.hide(this.props.stdout)}componentWillUnmount(){q1e.default.show(this.props.stdout),this.isRawModeSupported()&&this.handleSetRawMode(!1)}componentDidCatch(e){this.handleExit(e)}};sf.default=HF;HF.displayName=\"InternalApp\"});var J1e=_(of=>{\"use strict\";var Xht=of&&of.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),$ht=of&&of.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),e0t=of&&of.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.hasOwnProperty.call(t,r)&&Xht(e,t,r);return $ht(e,t),e},af=of&&of.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(of,\"__esModule\",{value:!0});var t0t=af(hn()),Y1e=_Ce(),r0t=af(rwe()),n0t=af(w9()),i0t=af(lwe()),s0t=af(uwe()),DW=af(r1e()),o0t=af(y1e()),a0t=af(D9()),l0t=af(w1e()),c0t=e0t(nW()),u0t=af(fW()),f0t=af(W1e()),Ew=process.env.CI===\"false\"?!1:i0t.default,V1e=()=>{},PW=class{constructor(e){this.resolveExitPromise=()=>{},this.rejectExitPromise=()=>{},this.unsubscribeExit=()=>{},this.onRender=()=>{if(this.isUnmounted)return;let{output:r,outputHeight:s,staticOutput:a}=o0t.default(this.rootNode,this.options.stdout.columns||80),n=a&&a!==`\n`;if(this.options.debug){n&&(this.fullStaticOutput+=a),this.options.stdout.write(this.fullStaticOutput+r);return}if(Ew){n&&this.options.stdout.write(a),this.lastOutput=r;return}if(n&&(this.fullStaticOutput+=a),s>=this.options.stdout.rows){this.options.stdout.write(n0t.default.clearTerminal+this.fullStaticOutput+r),this.lastOutput=r;return}n&&(this.log.clear(),this.options.stdout.write(a),this.log(r)),!n&&r!==this.lastOutput&&this.throttledLog(r),this.lastOutput=r},s0t.default(this),this.options=e,this.rootNode=c0t.createNode(\"ink-root\"),this.rootNode.onRender=e.debug?this.onRender:Y1e(this.onRender,32,{leading:!0,trailing:!0}),this.rootNode.onImmediateRender=this.onRender,this.log=r0t.default.create(e.stdout),this.throttledLog=e.debug?this.log:Y1e(this.log,void 0,{leading:!0,trailing:!0}),this.isUnmounted=!1,this.lastOutput=\"\",this.fullStaticOutput=\"\",this.container=DW.default.createContainer(this.rootNode,0,!1,null),this.unsubscribeExit=a0t.default(this.unmount,{alwaysLast:!1}),e.patchConsole&&this.patchConsole(),Ew||(e.stdout.on(\"resize\",this.onRender),this.unsubscribeResize=()=>{e.stdout.off(\"resize\",this.onRender)})}render(e){let r=t0t.default.createElement(f0t.default,{stdin:this.options.stdin,stdout:this.options.stdout,stderr:this.options.stderr,writeToStdout:this.writeToStdout,writeToStderr:this.writeToStderr,exitOnCtrlC:this.options.exitOnCtrlC,onExit:this.unmount},e);DW.default.updateContainer(r,this.container,null,V1e)}writeToStdout(e){if(!this.isUnmounted){if(this.options.debug){this.options.stdout.write(e+this.fullStaticOutput+this.lastOutput);return}if(Ew){this.options.stdout.write(e);return}this.log.clear(),this.options.stdout.write(e),this.log(this.lastOutput)}}writeToStderr(e){if(!this.isUnmounted){if(this.options.debug){this.options.stderr.write(e),this.options.stdout.write(this.fullStaticOutput+this.lastOutput);return}if(Ew){this.options.stderr.write(e);return}this.log.clear(),this.options.stderr.write(e),this.log(this.lastOutput)}}unmount(e){this.isUnmounted||(this.onRender(),this.unsubscribeExit(),typeof this.restoreConsole==\"function\"&&this.restoreConsole(),typeof this.unsubscribeResize==\"function\"&&this.unsubscribeResize(),Ew?this.options.stdout.write(this.lastOutput+`\n`):this.options.debug||this.log.done(),this.isUnmounted=!0,DW.default.updateContainer(null,this.container,null,V1e),u0t.default.delete(this.options.stdout),e instanceof Error?this.rejectExitPromise(e):this.resolveExitPromise())}waitUntilExit(){return this.exitPromise||(this.exitPromise=new Promise((e,r)=>{this.resolveExitPromise=e,this.rejectExitPromise=r})),this.exitPromise}clear(){!Ew&&!this.options.debug&&this.log.clear()}patchConsole(){this.options.debug||(this.restoreConsole=l0t.default((e,r)=>{e===\"stdout\"&&this.writeToStdout(r),e===\"stderr\"&&(r.startsWith(\"The above error occurred\")||this.writeToStderr(r))}))}};of.default=PW});var z1e=_(sD=>{\"use strict\";var K1e=sD&&sD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(sD,\"__esModule\",{value:!0});var A0t=K1e(J1e()),jF=K1e(fW()),p0t=Ie(\"stream\"),h0t=(t,e)=>{let r=Object.assign({stdout:process.stdout,stdin:process.stdin,stderr:process.stderr,debug:!1,exitOnCtrlC:!0,patchConsole:!0},g0t(e)),s=d0t(r.stdout,()=>new A0t.default(r));return s.render(t),{rerender:s.render,unmount:()=>s.unmount(),waitUntilExit:s.waitUntilExit,cleanup:()=>jF.default.delete(r.stdout),clear:s.clear}};sD.default=h0t;var g0t=(t={})=>t instanceof p0t.Stream?{stdout:t,stdin:process.stdin}:t,d0t=(t,e)=>{let r;return jF.default.has(t)?r=jF.default.get(t):(r=e(),jF.default.set(t,r)),r}});var X1e=_(eh=>{\"use strict\";var m0t=eh&&eh.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r),Object.defineProperty(t,s,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),y0t=eh&&eh.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),E0t=eh&&eh.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.hasOwnProperty.call(t,r)&&m0t(e,t,r);return y0t(e,t),e};Object.defineProperty(eh,\"__esModule\",{value:!0});var oD=E0t(hn()),Z1e=t=>{let{items:e,children:r,style:s}=t,[a,n]=oD.useState(0),c=oD.useMemo(()=>e.slice(a),[e,a]);oD.useLayoutEffect(()=>{n(e.length)},[e.length]);let f=c.map((h,E)=>r(h,a+E)),p=oD.useMemo(()=>Object.assign({position:\"absolute\",flexDirection:\"column\"},s),[s]);return oD.default.createElement(\"ink-box\",{internal_static:!0,style:p},f)};Z1e.displayName=\"Static\";eh.default=Z1e});var e2e=_(aD=>{\"use strict\";var I0t=aD&&aD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(aD,\"__esModule\",{value:!0});var C0t=I0t(hn()),$1e=({children:t,transform:e})=>t==null?null:C0t.default.createElement(\"ink-text\",{style:{flexGrow:0,flexShrink:1,flexDirection:\"row\"},internal_transform:e},t);$1e.displayName=\"Transform\";aD.default=$1e});var r2e=_(lD=>{\"use strict\";var w0t=lD&&lD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(lD,\"__esModule\",{value:!0});var B0t=w0t(hn()),t2e=({count:t=1})=>B0t.default.createElement(\"ink-text\",null,`\n`.repeat(t));t2e.displayName=\"Newline\";lD.default=t2e});var s2e=_(cD=>{\"use strict\";var n2e=cD&&cD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(cD,\"__esModule\",{value:!0});var v0t=n2e(hn()),S0t=n2e(_F()),i2e=()=>v0t.default.createElement(S0t.default,{flexGrow:1});i2e.displayName=\"Spacer\";cD.default=i2e});var GF=_(uD=>{\"use strict\";var D0t=uD&&uD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(uD,\"__esModule\",{value:!0});var P0t=hn(),b0t=D0t(gW()),x0t=()=>P0t.useContext(b0t.default);uD.default=x0t});var a2e=_(fD=>{\"use strict\";var k0t=fD&&fD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(fD,\"__esModule\",{value:!0});var o2e=hn(),Q0t=k0t(GF()),R0t=(t,e={})=>{let{stdin:r,setRawMode:s,internal_exitOnCtrlC:a}=Q0t.default();o2e.useEffect(()=>{if(e.isActive!==!1)return s(!0),()=>{s(!1)}},[e.isActive,s]),o2e.useEffect(()=>{if(e.isActive===!1)return;let n=c=>{let f=String(c),p={upArrow:f===\"\\x1B[A\",downArrow:f===\"\\x1B[B\",leftArrow:f===\"\\x1B[D\",rightArrow:f===\"\\x1B[C\",pageDown:f===\"\\x1B[6~\",pageUp:f===\"\\x1B[5~\",return:f===\"\\r\",escape:f===\"\\x1B\",ctrl:!1,shift:!1,tab:f===\"\t\"||f===\"\\x1B[Z\",backspace:f===\"\\b\",delete:f===\"\\x7F\"||f===\"\\x1B[3~\",meta:!1};f<=\"\u001a\"&&!p.return&&(f=String.fromCharCode(f.charCodeAt(0)+97-1),p.ctrl=!0),f.startsWith(\"\\x1B\")&&(f=f.slice(1),p.meta=!0);let h=f>=\"A\"&&f<=\"Z\",E=f>=\"\\u0410\"&&f<=\"\\u042F\";f.length===1&&(h||E)&&(p.shift=!0),p.tab&&f===\"[Z\"&&(p.shift=!0),(p.tab||p.backspace||p.delete)&&(f=\"\"),(!(f===\"c\"&&p.ctrl)||!a)&&t(f,p)};return r?.on(\"data\",n),()=>{r?.off(\"data\",n)}},[e.isActive,r,a,t])};fD.default=R0t});var l2e=_(AD=>{\"use strict\";var T0t=AD&&AD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(AD,\"__esModule\",{value:!0});var F0t=hn(),N0t=T0t(pW()),O0t=()=>F0t.useContext(N0t.default);AD.default=O0t});var c2e=_(pD=>{\"use strict\";var L0t=pD&&pD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(pD,\"__esModule\",{value:!0});var M0t=hn(),U0t=L0t(mW()),_0t=()=>M0t.useContext(U0t.default);pD.default=_0t});var u2e=_(hD=>{\"use strict\";var H0t=hD&&hD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(hD,\"__esModule\",{value:!0});var j0t=hn(),G0t=H0t(EW()),q0t=()=>j0t.useContext(G0t.default);hD.default=q0t});var A2e=_(dD=>{\"use strict\";var f2e=dD&&dD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(dD,\"__esModule\",{value:!0});var gD=hn(),W0t=f2e(UF()),Y0t=f2e(GF()),V0t=({isActive:t=!0,autoFocus:e=!1,id:r}={})=>{let{isRawModeSupported:s,setRawMode:a}=Y0t.default(),{activeId:n,add:c,remove:f,activate:p,deactivate:h,focus:E}=gD.useContext(W0t.default),C=gD.useMemo(()=>r??Math.random().toString().slice(2,7),[r]);return gD.useEffect(()=>(c(C,{autoFocus:e}),()=>{f(C)}),[C,e]),gD.useEffect(()=>{t?p(C):h(C)},[t,C]),gD.useEffect(()=>{if(!(!s||!t))return a(!0),()=>{a(!1)}},[t]),{isFocused:!!C&&n===C,focus:E}};dD.default=V0t});var p2e=_(mD=>{\"use strict\";var J0t=mD&&mD.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(mD,\"__esModule\",{value:!0});var K0t=hn(),z0t=J0t(UF()),Z0t=()=>{let t=K0t.useContext(z0t.default);return{enableFocus:t.enableFocus,disableFocus:t.disableFocus,focusNext:t.focusNext,focusPrevious:t.focusPrevious,focus:t.focus}};mD.default=Z0t});var h2e=_(bW=>{\"use strict\";Object.defineProperty(bW,\"__esModule\",{value:!0});bW.default=t=>{var e,r,s,a;return{width:(r=(e=t.yogaNode)===null||e===void 0?void 0:e.getComputedWidth())!==null&&r!==void 0?r:0,height:(a=(s=t.yogaNode)===null||s===void 0?void 0:s.getComputedHeight())!==null&&a!==void 0?a:0}}});var Wc=_(mo=>{\"use strict\";Object.defineProperty(mo,\"__esModule\",{value:!0});var X0t=z1e();Object.defineProperty(mo,\"render\",{enumerable:!0,get:function(){return X0t.default}});var $0t=_F();Object.defineProperty(mo,\"Box\",{enumerable:!0,get:function(){return $0t.default}});var egt=SW();Object.defineProperty(mo,\"Text\",{enumerable:!0,get:function(){return egt.default}});var tgt=X1e();Object.defineProperty(mo,\"Static\",{enumerable:!0,get:function(){return tgt.default}});var rgt=e2e();Object.defineProperty(mo,\"Transform\",{enumerable:!0,get:function(){return rgt.default}});var ngt=r2e();Object.defineProperty(mo,\"Newline\",{enumerable:!0,get:function(){return ngt.default}});var igt=s2e();Object.defineProperty(mo,\"Spacer\",{enumerable:!0,get:function(){return igt.default}});var sgt=a2e();Object.defineProperty(mo,\"useInput\",{enumerable:!0,get:function(){return sgt.default}});var ogt=l2e();Object.defineProperty(mo,\"useApp\",{enumerable:!0,get:function(){return ogt.default}});var agt=GF();Object.defineProperty(mo,\"useStdin\",{enumerable:!0,get:function(){return agt.default}});var lgt=c2e();Object.defineProperty(mo,\"useStdout\",{enumerable:!0,get:function(){return lgt.default}});var cgt=u2e();Object.defineProperty(mo,\"useStderr\",{enumerable:!0,get:function(){return cgt.default}});var ugt=A2e();Object.defineProperty(mo,\"useFocus\",{enumerable:!0,get:function(){return ugt.default}});var fgt=p2e();Object.defineProperty(mo,\"useFocusManager\",{enumerable:!0,get:function(){return fgt.default}});var Agt=h2e();Object.defineProperty(mo,\"measureElement\",{enumerable:!0,get:function(){return Agt.default}})});var kW={};Vt(kW,{Gem:()=>xW});var g2e,Mm,xW,qF=Ze(()=>{g2e=ut(Wc()),Mm=ut(hn()),xW=(0,Mm.memo)(({active:t})=>{let e=(0,Mm.useMemo)(()=>t?\"\\u25C9\":\"\\u25EF\",[t]),r=(0,Mm.useMemo)(()=>t?\"green\":\"yellow\",[t]);return Mm.default.createElement(g2e.Text,{color:r},e)})});var m2e={};Vt(m2e,{useKeypress:()=>Um});function Um({active:t},e,r){let{stdin:s}=(0,d2e.useStdin)(),a=(0,WF.useCallback)((n,c)=>e(n,c),r);(0,WF.useEffect)(()=>{if(!(!t||!s))return s.on(\"keypress\",a),()=>{s.off(\"keypress\",a)}},[t,a,s])}var d2e,WF,yD=Ze(()=>{d2e=ut(Wc()),WF=ut(hn())});var E2e={};Vt(E2e,{FocusRequest:()=>y2e,useFocusRequest:()=>QW});var y2e,QW,RW=Ze(()=>{yD();y2e=(r=>(r.BEFORE=\"before\",r.AFTER=\"after\",r))(y2e||{}),QW=function({active:t},e,r){Um({active:t},(s,a)=>{a.name===\"tab\"&&(a.shift?e(\"before\"):e(\"after\"))},r)}});var I2e={};Vt(I2e,{useListInput:()=>ED});var ED,YF=Ze(()=>{yD();ED=function(t,e,{active:r,minus:s,plus:a,set:n,loop:c=!0}){Um({active:r},(f,p)=>{let h=e.indexOf(t);switch(p.name){case s:{let E=h-1;if(c){n(e[(e.length+E)%e.length]);return}if(E<0)return;n(e[E])}break;case a:{let E=h+1;if(c){n(e[E%e.length]);return}if(E>=e.length)return;n(e[E])}break}},[e,t,a,n,c])}});var VF={};Vt(VF,{ScrollableItems:()=>pgt});var eg,dl,pgt,JF=Ze(()=>{eg=ut(Wc()),dl=ut(hn());RW();YF();pgt=({active:t=!0,children:e=[],radius:r=10,size:s=1,loop:a=!0,onFocusRequest:n,willReachEnd:c})=>{let f=N=>{if(N.key===null)throw new Error(\"Expected all children to have a key\");return N.key},p=dl.default.Children.map(e,N=>f(N)),h=p[0],[E,C]=(0,dl.useState)(h),S=p.indexOf(E);(0,dl.useEffect)(()=>{p.includes(E)||C(h)},[e]),(0,dl.useEffect)(()=>{c&&S>=p.length-2&&c()},[S]),QW({active:t&&!!n},N=>{n?.(N)},[n]),ED(E,p,{active:t,minus:\"up\",plus:\"down\",set:C,loop:a});let b=S-r,I=S+r;I>p.length&&(b-=I-p.length,I=p.length),b<0&&(I+=-b,b=0),I>=p.length&&(I=p.length-1);let T=[];for(let N=b;N<=I;++N){let U=p[N],W=t&&U===E;T.push(dl.default.createElement(eg.Box,{key:U,height:s},dl.default.createElement(eg.Box,{marginLeft:1,marginRight:1},dl.default.createElement(eg.Text,null,W?dl.default.createElement(eg.Text,{color:\"cyan\",bold:!0},\">\"):\" \")),dl.default.createElement(eg.Box,null,dl.default.cloneElement(e[N],{active:W}))))}return dl.default.createElement(eg.Box,{flexDirection:\"column\",width:\"100%\"},T)}});var C2e,th,w2e,TW,B2e,FW=Ze(()=>{C2e=ut(Wc()),th=ut(hn()),w2e=Ie(\"readline\"),TW=th.default.createContext(null),B2e=({children:t})=>{let{stdin:e,setRawMode:r}=(0,C2e.useStdin)();(0,th.useEffect)(()=>{r&&r(!0),e&&(0,w2e.emitKeypressEvents)(e)},[e,r]);let[s,a]=(0,th.useState)(new Map),n=(0,th.useMemo)(()=>({getAll:()=>s,get:c=>s.get(c),set:(c,f)=>a(new Map([...s,[c,f]]))}),[s,a]);return th.default.createElement(TW.Provider,{value:n,children:t})}});var NW={};Vt(NW,{useMinistore:()=>hgt});function hgt(t,e){let r=(0,KF.useContext)(TW);if(r===null)throw new Error(\"Expected this hook to run with a ministore context attached\");if(typeof t>\"u\")return r.getAll();let s=(0,KF.useCallback)(n=>{r.set(t,n)},[t,r.set]),a=r.get(t);return typeof a>\"u\"&&(a=e),[a,s]}var KF,OW=Ze(()=>{KF=ut(hn());FW()});var ZF={};Vt(ZF,{renderForm:()=>ggt});async function ggt(t,e,{stdin:r,stdout:s,stderr:a}){let n,c=p=>{let{exit:h}=(0,zF.useApp)();Um({active:!0},(E,C)=>{C.name===\"return\"&&(n=p,h())},[h,p])},{waitUntilExit:f}=(0,zF.render)(LW.default.createElement(B2e,null,LW.default.createElement(t,{...e,useSubmit:c})),{stdin:r,stdout:s,stderr:a});return await f(),n}var zF,LW,XF=Ze(()=>{zF=ut(Wc()),LW=ut(hn());FW();yD()});var P2e=_(ID=>{\"use strict\";Object.defineProperty(ID,\"__esModule\",{value:!0});ID.UncontrolledTextInput=void 0;var S2e=hn(),MW=hn(),v2e=Wc(),_m=RE(),D2e=({value:t,placeholder:e=\"\",focus:r=!0,mask:s,highlightPastedText:a=!1,showCursor:n=!0,onChange:c,onSubmit:f})=>{let[{cursorOffset:p,cursorWidth:h},E]=MW.useState({cursorOffset:(t||\"\").length,cursorWidth:0});MW.useEffect(()=>{E(T=>{if(!r||!n)return T;let N=t||\"\";return T.cursorOffset>N.length-1?{cursorOffset:N.length,cursorWidth:0}:T})},[t,r,n]);let C=a?h:0,S=s?s.repeat(t.length):t,b=S,I=e?_m.grey(e):void 0;if(n&&r){I=e.length>0?_m.inverse(e[0])+_m.grey(e.slice(1)):_m.inverse(\" \"),b=S.length>0?\"\":_m.inverse(\" \");let T=0;for(let N of S)T>=p-C&&T<=p?b+=_m.inverse(N):b+=N,T++;S.length>0&&p===S.length&&(b+=_m.inverse(\" \"))}return v2e.useInput((T,N)=>{if(N.upArrow||N.downArrow||N.ctrl&&T===\"c\"||N.tab||N.shift&&N.tab)return;if(N.return){f&&f(t);return}let U=p,W=t,ee=0;N.leftArrow?n&&U--:N.rightArrow?n&&U++:N.backspace||N.delete?p>0&&(W=t.slice(0,p-1)+t.slice(p,t.length),U--):(W=t.slice(0,p)+T+t.slice(p,t.length),U+=T.length,T.length>1&&(ee=T.length)),p<0&&(U=0),p>t.length&&(U=t.length),E({cursorOffset:U,cursorWidth:ee}),W!==t&&c(W)},{isActive:r}),S2e.createElement(v2e.Text,null,e?S.length>0?b:I:b)};ID.default=D2e;ID.UncontrolledTextInput=({initialValue:t=\"\",...e})=>{let[r,s]=MW.useState(t);return S2e.createElement(D2e,Object.assign({},e,{value:r,onChange:s}))}});var k2e={};Vt(k2e,{Pad:()=>UW});var b2e,x2e,UW,_W=Ze(()=>{b2e=ut(Wc()),x2e=ut(hn()),UW=({length:t,active:e})=>{if(t===0)return null;let r=t>1?` ${\"-\".repeat(t-1)}`:\" \";return x2e.default.createElement(b2e.Text,{dimColor:!e},r)}});var Q2e={};Vt(Q2e,{ItemOptions:()=>dgt});var wD,tg,dgt,R2e=Ze(()=>{wD=ut(Wc()),tg=ut(hn());YF();qF();_W();dgt=function({active:t,skewer:e,options:r,value:s,onChange:a,sizes:n=[]}){let c=r.filter(({label:p})=>!!p).map(({value:p})=>p),f=r.findIndex(p=>p.value===s&&p.label!=\"\");return ED(s,c,{active:t,minus:\"left\",plus:\"right\",set:a}),tg.default.createElement(tg.default.Fragment,null,r.map(({label:p},h)=>{let E=h===f,C=n[h]-1||0,S=p.replace(/[\\u001b\\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,\"\"),b=Math.max(0,C-S.length-2);return p?tg.default.createElement(wD.Box,{key:p,width:C,marginLeft:1},tg.default.createElement(wD.Text,{wrap:\"truncate\"},tg.default.createElement(xW,{active:E}),\" \",p),e?tg.default.createElement(UW,{active:t,length:b}):null):tg.default.createElement(wD.Box,{key:`spacer-${h}`,width:C,marginLeft:1})}))}});var V2e=_((VZt,Y2e)=>{var ZW;Y2e.exports=()=>(typeof ZW>\"u\"&&(ZW=Ie(\"zlib\").brotliDecompressSync(Buffer.from(\"W4midoC5qbXRudsGgPTx9WbM6x6QwRgOjLr/GOIPlSLC3nJB5jZ9BXGdN9O3ILjKOQ1VVTOTyhiagEtbABF0bvv+pwVzOEIoEiqpkHNjocGMCve9WzcMZ8HTjWoZHXZgeqrltMRK9CV0qqKBVSbFngqcVz1hqG33qAlDRWBKCZ3h0834GWPct19RBMPlufdGrzzRWx/82JdE0srV0tbGKoGA8P2lqz2e/9H7IGN3krKPubn4n7REcgyzbNu+FbxskhKddObaesTHADpuvV5AUCaF6TGDWYjeJw4X8RCfFja1N/q8JkQ5tLDsXqlWCNfrC2HLTilFcH79mvoY9VJiBbKs4wr0ATtvLze3BdrLpvbP52V0hcV1VwiGIUXX60spKzAkcgFNwNfkOT/9aX19G+VYKxbXisXzbCmdLTdA2DgNU9Jhs1n+7/MiHdIqIVVry5wGW/JINhs2RffMr/36y+x/fr7e3M/ah3vcZreIhGHLnGhIT4RiN7wQNyxGmIxKtZi2KhG1Bk1LnZVdLj+tQUnQx3Js1fd8LApAIWJu/Us61lYmDowvlj798qfV1682Q43MXoj4EjMbIufC3pAJjZggPVTdvQZcxcB2czSECfgBtlQt+28q4qsLfKcypvZD5Tg6DqBV4BhcLWwecH6t+XW8js2E9QjW+nACmkFuoFv8YE9IrvBEiffHg4OgiOObzW6zbYMpQXoj1UE+8eX7U3w/nY5rwu14ZZXArv6mL92zgwXHF4iuzZr2+mrc9k4OMWkBA94A+1FDrT8edv8PtpUd+fhedTUUAuxGQYl8k+VJNVEmWEYJ0vjxja3jYQ9S2a4d33wGHBTqgVR0M1w+5G6YuPslotopxgsH9j9TGgRhGJS6ad2O753ADBIyI/ClH2r0+XF3t26SdrOfTxrNIAw4goxj/OfiRlCSOLu4JSmhcJLKQK6RHwwCD1zAWlhsPh8+TNFa+5zdbHIBDsyFiPSHtu6FiKi2PSI8Yun64+G3AbYen2RNIrrZfqTKwtuTv8Yc/pjv5+cCSFc+E0Aft5KWUO4if2o3ghzKioKBh3pVrSwuxfb9BUDsV4QkOnU2ZC9kDmlnzp3//72vWtWZopw6plmajDrLIKUOIc97zfHPOftu8b8fTHzg0wJAykWlZdGRtFwh3XPOfR8/QQWAshukXVWSXO7KYdQhhNm0e9yDWc9GkkZdf1+m+d/23MyqQoHoZoNsSgLV+hL1bfNpvrHbKYCUsc+4/nY3frF5vPecvNF57816qswqjKoyCyFUViGEKpDxWVXABGGYWQCoAprdA3b3+wOypReU+TOUeROUfcY3QXaE2GxFiGT3N916YySN1Yzft76xbjV/Ny72xtjl389uNvtZL2Y3y+VfLWexHP+/vd83OxGNtBM0waPE/Krad7P6v+4mJ8VCgr8n1e74yMkoU7c/ocfBvTY/2xnBjHEd8DGUeSkqabU+5qr5tuT9/9/aPggRmILAFUKZomyujP//e7NeOj8DaGYGQmRmbPq+c95e0+oq+f8OP3iCQwx3733ufVKVpNFo2jmykAg2gKiq2zEww/d149uZmjnFt7Z238ogoMCSQLJEAs0Sjphx5yEG8hjbUAdVv/f39t6eJR1SFBqjTj2FRKL0De+So0oqZBWTAuMoFAiNAyHRFBKJtBTGoijkd9/5b4z/Vq2cTXWAe1TKIxFGkJ0ehu9XJ7Go197s9VZFSJBohRUs01lJgEpgBp6Kfjuu/ZvAzWrYRXYbKHfeLniMQAwNBRI0aCmlRYuIJQSpvAzP3P7/HRP1OfCP+29LTZE1VARUcOUsVzkbCA6USsvGLd9Yf/5/zvgOSdQ5Ucf3dndmNKGpFA2IdtRgLWApLUVjypSzf1OAmwJNm6EVLySCLCcQNWK3Wc/L7ua8LSyESJhCwgSGMIXwp7CYQogQCVNYCLEwsMVCXnJb075/8O+ck/rz32CDCSaYYAIFCgQWRhgFwgjcgbA7UKAHCtrQQfHooIPxx6yL+r0VWFgYGAgEGgKBQEMgMFV/+v7QO/f/z/d3nQOj57/FFhVLVJShDBURFWGoCENFHkREhPciIvKgokST2xXhY/MHbN7ftEdtQmlPvMGDlZrPxH5+I5SSZNsNvZtfS5dSKpTzZ+AxohQLEjyY1IACQbT63srvSZKZyezdDY+bb0fXQr924niJ4AkFiiaIVShUEJEIVqjcefRl25UVyj8JmQP+qJEP463HHAsnjju36FSBHyNpUz86tx2vAqs5lac648W57aA6kBD51jdq/c/l+V0rl6Wj89jxKvCW1WJbh+jQXyI8ctfeP9vSr3JbxdpL6HurTFpD7a83oCr6o1NuhV9m59vE4bYY7XjlkKCWh+fOLqerAJ4c4xx2XNSAJu8rxx+4WE/ZNJVvBI3BiyYmo0MwCF9sg/gTFskGn7BPRGN4S4ObhuqXtABhbih1qfUpSYWqxGF9G837mhThCI11v+Rzmux1tinrUo3T68CbvW2LjN9PWO5if84akiIdCE8MuPULSRtyNxSyhLI4h/sknFWSUoUsDJ+Sfl6lPkydEV1tif9Bx9hYWy7sX0C0kv/Lb2K3cJitYd4FwtqnNLa5J/kxBhIvcZGozxo0LyggMuT5T9uf4XS+F/53ZP7HwHj4m10bQXqQJGCJ3k+cdH35UrrPrGcoProqlxNZZ/au9fBSNeRRbP38XyQmsZ6cw7t6clQwcpy+6BCDL8eLFEisZ5V8kRgrNA21wSJxeyK+TlgsXkMR1QeLJGaOqsr4rBvNTqm0Oz9qGqlXmOciKf59lt78jYrr3+eo7N+YeXsTdSXKu5DQ15stmh8rsnp9pDWIpGdqrHp4ljHw7JuOFsrO4aDAl6eb8vmBNf5dZJsUH10nPhG8b43EQjG3aysGmf6E9s67HSMjz1HHCNObYETsQ6VMDBrZhYCNqC3uYFhibj/CfCNw0RwdP0XPeYc8kjAEkc12MXApbYZWOl/dOcTk1Bhyc7gAVWtM08axNfhDKwW5QYYgwN6RKkOU2q2cjUDa3V+dWIukEOKY7zuuwEy+cDLnAZkTQ1vcXf0C6OpWz//QDEFkKi+MIlkbs9X91akkAxpD1GLDMHglFIwYFLVnh+6Mva8bsUTDPb7U9nUrs5tS5VdpvVYnkeQbP3UlO+nNcvsc9Ujq/4cnW3/20cRRXp3YbchjmoE5ZCbwir4YY5+thy4unCmq0a9toPBX6pAA3pVDbw4KJXsfV4WUIab3k/q9Dr0CeiQs+xNDn5f/da99B9khal+EJ0nILtJzPIGeBZZ9Gt/HwaA/wtOPEKg/0p3EI9+3O9z3Uv66CkWLkeHw+iUhpuzS6lJNRetIE4902GVxyTZehRAEg0oQwW51WTXR3yqFJLSju9arD8Z+ydtNNW9UthW1ryb9lsTJgHy1yblz7Fsorp+TQt2eVYdr2JZs18g8d1c9lHkzY0I/bdsOGcYYv53XhAA0hPud9SLTAPVIC6EJacKF3oe8Z7RpJWb0Psr3Ub7P8p1ldb9Hpklyz7TpLiKNUu9S6tKkIWZHMJumqzDt0tq7Pg2DNcR+0+AyUvTrPWlOwHGk8P8PJ007F0jxk0njxXprclja9+WrChcrvVUsl3X8qtnXDk3Tuwb/HhcdYYsRTYTf1SAPk6IOCXcqWv/QYuRsBHo3yvlJVe+uetxhUp+PuMtsWXcl1ISslDEE3nmvjeY/wIUNFiPTQUY7bVF32T1FZl0yKq66jbhSeyrPux0QfkbQRxk6o/dXcn14ilBXnxssukdrm4wJ7z1RDV9kYQUyJxpd7VdlOMGYR5UnM5VlVIJw5fW0W5DOPn7TOZzNQuVpy7Xj046+PMyRcmqIn7AbC+kRM8Pod//5JmtV7ZATEzLaRjipLDaJHBP45IoEYNmPCKoqOIVFM74Ve3YOs+bz1cjiKSN7UskqrnzZjPdbqpFAzdBv6XAC4aUhr+QGAQ8hTSwq0kmQSGWitqInNV4uEUKpDhq4kLeNUh4QTvMQy3IaYV4z2uKdhAyK7tBOzSp+oyBft9vyMfFpitb8zGjfNhuXpkR7mklTZ7Zen6YfCfy6PtCl+r3KBPbS1XhaEZ2U+a6R5oWUOm3vIE9XdohPM7KQIgVcbKbihh/ZdVH2ezXajfxJbirPTXoXaxzF6NK3T4qNasqFXZybse1XYr0UiSD1O5sCP/lfKkwbBrohuVjsfzvUKGq8hHmgMHQre9/7JZJ/SHvVoLl7C+4OcqefMH5hAAez2be7SpEOD8syGC7t4MkPLlNeeqIj86F65G7tr/1s8DmTb26Ry7eWk2YpamTNhKKR/lPjELDHV/LfPWsKsh1gfyy09qYTnHjggWEjf9ZWc5jxhDBw6lAcTQZco5EwPyJThoOqAZsF2Z/IJ764MZ9Rhocy/mt420gUBoflsohpSyfwRCt9ySZGfYtrwys8D5rWuVFCtIqUHyGUjHaFCHCzE1aMm3swW0LYPpDy0/90nnlVWywoZabC7twQhx2N3LzLrhy0I7M8zME6mbSGXnGR/ySZiVXCRdNVl1pwXcgcgdQnydTOyvgHv2xPiKkIOqR9P85GeVEtBkvEtJ//5649cQKpc2/kXcjzUX2vgmvhtDqW+VIQFMPwGFsOJCi/SmxF/LYyFkFG0r46r4BcTmajjiloZ2KN14o3v9RJNQqLa65u9uEBrQweo5lKwa94OYGA0xhV4Dq0UwUrUkRvMjt6pJAf3l4w9JcbjfydB9LL/qNTZ+zm7t3m8nOySrLaBBTid+uuDI78kaDPn9NdSlBqXaC8nVPmaaXZiuHoEhu6j2xIfy4aqEl2lX74Nfbunx763qSCC6l7YDG4szYPUwpBjCgcCtOplGdo2HC0EuKR2dyX0EeDAE20IJVmejc5PPZtQhuT/gh0+Yr85ESUOI4IL8s9Rg6dxmpJKIerKUGvBtXtTEF01+KN1MoCY9thezIMVW65Ax2swAmdsdiJqKkXebVJac+qIqoiiQ8Q1UMumrx9KAq7ds8cIBh6hYvHzwJpHHqZFaxzI4n3uxCmWXQo2k9JY3H++crTnwFitwZQx2UgPFmQ4lQGR9eHkz16UbfpY9P8omPWZOW7H+eL4mjKVIDMv4LERqVAeci6h4rWVFrRuTGTaprBx7ugj5/XAw+G9d2po6zykBR41Cy4ToeDOP31Yta6czdSUZ8oyhAjtrOuC/o4HMZL6xlK0AhFjsJGeSmuw2tFDgnbcoYx+GjBaCFrdMeu8dKAIdrA8gzpOJhDo/W9ibG993CjlTIndqfZpiqZUJRprmjE9qcN12HJtrpmCoassCuS96IiGYgeyO/zZK4t9ziaZDuYl5cRd6bqh3SH16M+x4j57BesaGtx+HQW+halN6I0w+GgiPhMz/NLmMzBlyTvJ/OLHK+NHg6pK7/ZdDHjzI2TunkC5NHqR0sAwy9jspBmz2XeGybn60hBRIjOTjXLdUR0ZnROJuWmXWInV5YcolTvlUIYSO4ASGQ1zB6+MtdagiXRQRcRJI0VMGoupqhU79TzpBaqXL5hViy/2CyeoQwp6CDLYJ8KQzCp9eRkGaPOwGyJhsZ3qTnzojMzzKkse2s+kdXBhHYHyycbQ7EwdLaQFGm89xq/n4hbSMIG+1Jd9i4Xjfq+ZB8fonl2gil483+zvg10xqQbzSV5lmjq2OIjK8X+LTqcWnrE3cXeZhfdO9GRrCFPmCmmZCJLXfHyYxrHAbLi4m4bIX3FWpQ2o2gCbunfboAy1BCVM0dzzfkOluMKdcbZ/AIbKgkuWCM2SdnlbJUaGEmBo3xjQ3dUqrki/rUTJnxPXBaGLHd5jzOzZKGqi85aZPJuxvFK7s8p9Uqkvx2JyMnlyF0CpC+EhHoMjMp0E6K00mYxgka+80JhWUvLkELMx7usLjUR06x/v5Cqr+UIJBcII1aXRekRootZ6gMkDV6TQZb7mFeYQVVGh1ybq3UEDePUPk9cYZVnGLq9AiBprS4cQGtwuLXrmTklTyeH/48LO3X5mcdelswDi5YZenIu4x2YovfpopTqd7AEwpAQD4FqWqYm1m2BNZq4syMtQJHKvLcjXYpkDJy8F5bmvTcK1Mm1XNRej5gs6qy7UDIhdbbMQ22mIlmydm1qNtwL78S39ctksJXPdRNmg6iwCQ47g7EpUQqeqs6rNxzd9DnafcZia7duQpcfcRSG9htfrgy8x0kOjYE1KpbbmTREkoYzGI5ocuFH2p9kc8OO5tFba9ok74JGf8C5LpLrI1ksGXUprti6ZPDQH8J3lnBeffKLJrwWn4/mx+eqxA+ddHfT+MxEOaCPcPmFnfF0bUKhpCtvBUrXh4r7yXxk/LoG9BwsE9myF437xRjSWxeZYSKrvXA6ZU4lhmUCuLdwDyc55ml4UYZrgx9HU2UdzHPbrbYuBi7YQtfyy8oWhVt7PzUUUihUUzL5i514HUI83eONVg08SThqg/aIRe0NRif1KWFTSuSHs9ggTcfMO9CGABXgkt7rGpyS30Zctq14M3fPSBKxXAfcYnLfAnCiLVDkVFOXK0AUHE+j/bkdDmB1y5WSL6tr1Uir0TQIP9JYNVa9khU0YRFlId5rsAwqtt1fuKYkVt1VlNCkfsTgAbtg8QUHd/IWJ3zeg3yHudvdsTt3M9m+YyS99lGVrETFK5ZwoG1bIaahawsO7XtnCZIzs9Mz6l/eFAqLKwsrR832MNW1E9DeFK0uJr7/PI1xjCoqUOHIbd8sw/R+az1bqJYpdDIxSKzVokdQl7jrXmzefdUa9q55bm02Q+JeqNtiwZdmqRc/ErBcbUxBLJpRC4XUMr2xxpYhkJA+dXUX2Ai9HLSk3S0eu0Tdhjk9SPHd7w/3odCyt5Vn+Zd+wE0h49IeD4zopjuu7aKmqCpNW9BMFDOp1Q+jWzi5lIKdeKQoDrIJskcGe6CZ7G2Vznc7pOO3nzq2TJNCdfZrRK+AgIfpxYLytg19tt0+hj6ehvGZp3f4JX/BkVaL9SpxH9EGbbFAo5PzHkYj8hPb7wN2qtNR+51+CnLmVQcscdnhWNw3+VfGuR+evyfNhs1vDEcyg/N7qc4AMQNuU55J1gDtB1hiapaujhJj1rlG1syxSaINL0nYHaNg2SAYyTx+Hy23MIlcCsOQgFapPFKHN8xKAsOvZgWanXd0Xo4ytwy1gpcGJWbRSwT448Xpgeoss/a73R+XsIK9TGvvbzuu6Lleo11jLKcpGeGfh2KEYVifq3ByvFxXEt+a4V+f/rHe10R9twCWqYOmv0pxKJIyvKAeRgXIHvl6sejdBo9fzrWfDBPotNa12wXN3FEyoIUy4Ac2hETxo14uzwafFMBpTaBWjz4sPhaWhaNKca2Yk0xke+IiQfqLhXDWZekA5v8KxBSwwx8vAZVxxR6sLWOLm+rdKiKGcBN9D1faso7GNFtMUPDpe90k0quRmhVYd4rqOwwYFzDhw+FES06hBTbyVWlASEqiVelkMhdcMfRL0hBzsQglQp2RiW0nX+/umAG4WzzLOq+pjjOTOarFrPzYH3gvng+/rHXH7kuJpPnPBfNb/+NP9mbEDn3y5AHz2PtUoXoZNmw6fP9ckFvpr2C420/0pd3X5Q47rFjb++kOr//xOVfB6sj1vcldYKL2xsJA+btxJuWjuh037ePLdwyT2fp39oxhXw6znyN7fGZinrtDyJzDDg/RwQrs7GGb3X4sv3CVwBX+4l6qEg1jxjg9MmKWDx0qM5oPGiN3pqW5axlDBuMgw0GDe3T+IqnrF/qqwHCx0pwqbE5Jy76tw1HGqPOFtrr2RCrh9/laY9p7C2TqdoJXxQKrHprbDiNAJJ/L9aqJroFi1LxI8Iq/Tjv7CqRaOxDmXSqCz8nBKopiqix3z78f9Os4/cJTYd/8Mktl+gW66Mwl1SZVWA/9JaPvhw0gLeL0ytoUbj3RJDoEaFc6RPeSFDV5NFGYtzZqG8k342FdriGCCrOi8jiq7GgKiS/z5SElq0CzDc2LvxjlKglO4DBAWlHvigvf8DTpOWOFdV3vtawrjpVX66ce6pskurWm9RHz7vOiiT2v+BZG9eqBxcY5eBNq5Qpz8XStW+t3Vqs3227x6scrkneuXlvbLP/WUwzsgk2Sc/rU9kT5LXLE9S8JWylnNOdDAGnS1EgxDiXkfSyhrmYI5qc7RmsII+Y6VJkPR1J70gu6/euUZi6QnzAsUGTnLzNxJi6RjKf6+06qydLOa2ZZS3cgmX+0WFlH6i0erGotc7k8wW512YJPkJjx73u4dzzVCE1KKZh8J9eTkwFqS0rRIicFLkn0/Ce4tzLmEm7leeLfzD5LvTCzPeBSjvHBRQbjCpLL46k17n0TU9Ogxb8bTInZLH+zrsyfe6S1b4ToQ6gYbPTQ28S+XfKzAc2QSFK0aQpEqs1o3enql6FRHf6lG0QolsZcCJ0DL91es9I3cnKhVfHYpeU2Fp2x2oCuIC0qAOZn1gNe+DRL21lFlr2zAsDfEsByI99ev+sXPS0gbHPXZ5CNBqDfwAHYcI5Eh6KDjjfskuB2LzrHOMY6lsdLAuCnRrp5AaiQqzw3YPKfrfXa7Dzq+vNmWs1LeCfP1RevZKoViuxJKVJfffJYqNHW9ymbH7CZGyHzQHVDUHDcnAp9fRVMTn1BGCyneUOrSctqUTtXgCmtJnP0H9QlCt2nr2pQwH3kVLaFE1v9sRMZ5iMng1WsN9DSv2RH2XP2fvXiui47SfXrACyFV4CkVhgP2ZWxG7F6Q1NU1nHtQrXwTs4X7PCR8cmrNGcWTTT2K6SnkBdMzmtuxBF4pCKUlgNc9LQFzAqjSF871TC0ISipTZbrh7Fvf44FetdluG/NdOzE4Yq7FG0aS3Exkmb8KgqOY64Lx4AYKr4Bgjm7Do+/3XDfNrFqZpqO2vBmz2pcpOl200QSFb3X7buYCgqsyoa7EBqpttwRreumS77tbD8G7Idy3T2MfIaHm0a8xbQoIta3diRoLh8H4K4U4ggnU9m3fQmZwxJud+OUi3BSepyxOnM5y7lcfyYfzV35vj6yjcsSZ+7CzZ/NbnodikxqgCy0eP8MAH3lXw3P+eaCrKhAahYC1HM+Y58jOsT0T9n51HlzowtOYv87Ijz9Vf7+eFh9VO3nS5v5u677jKlh5Px4KlxRnhv1Ta7toSZoAuXMeygioqOHd7ePLNWSWCHS33VjyCRYEn3cFuL7zQRnAnFjboqTBcqmfcVlR2awUMtlTAoY6UOV7jNjrxMjTsbgn5dsYBmRdzjLv/etvkqc/M5lYMYy9OGkvDfVHXvktl75+h/zR5bINVmRYdsnLg4apme94E3fps5N/7JzYLV6D9io56UGlU4JNplLbeWXZsHN9DnZRqrPApFsdkjY7/SqC6sn3HBkcFWYX3qIVaNOc9UKMnDOhv+ofRDOjlXqmw0eAbZZXX4A0pz1WfY/IfDgB2nLFoejRXtibFN/bBP2bAqT7QgxkdpQl9SNQc4STO6eBN4ZbjgOefHGVJsE5kKmsVQodfC8j+evlVy7gZzDiyyndeU04u+xMFz5AjXvR2IZncN2lO9iSlad/ynDJNlOtUBIG2JnPwNAp36OyTZGlLuTMQvJaT0e2PW5o45k7Q0qAarCXW43CinTmWkPFJsnRlhnStLQMmxWRnVZONYv+4lTkHhIloMBHq/35nDwsnf5dhXtvf9EQvP4Zh9tLseVvM/HN/gS/V2ImozmlYLI9PqrrqO9PqFu0tTq2zj3YWTJtwG1jWxF53jJY7ljwBsIhSxnK/CEiqbqaYemAncpnQNBY18itFH/8P0L2uR8GkFb1xsnovmlDkbhXEAWAxrnuqceKw/w8Y8KiWDqtix5ruxE6KgLWvj9+xO4qwES+fUJ7kt+ymIDmMpRoj2Z0o7zfGEyBtcFPP1zO1v30rplnVH1Lti+iAQ/ajEXAf0vPayD0+0pFIAXKOa0DHQfnM0N4jP4IHaTR2IbQeKP+FL87NtR5IXukhUbyKM0gdUYE3j6TmxQ4DuqUTuknxoK1mke7n4GNtTaFmDK7ArnLrIgdHZJTcB3YzVabaYESS/Hhpf/J1v1Jf9QEWWOWrjHA6qj3vpPVtOh/Nbn2cy0ybPDWWyja6X7+X+c5o0s60s6WNySQQ/XE86WpM4rDfKlIti5lMciyOUBi59gUYh2REeY/HvJzLVCFZbC1zUHnq9sq+XT+C9d/d3c3KuF8+M5W62CUnJjo4PDCgiuteNsX1bV58Y7zaR43DTzh52tsMA5hPmsy7d7LErHyaitIxeIJZp8ZTmCta0ab8jFSR5kKS3p2HGFNFtSY7cfijgSnEh6jIzT25vtHTRvGsZh6jQqbMybFte4tKxNVPxyqm2xqKf3ZXhZqq+/57TV5zEZ/mJzlFry8ZfIl7p9/yw9bZd0v6wqDd/3gOK0FQjGh0wc89Lel9+j2VyjLBmhKU/OGEnM51BmTtbgJ11Ok9mGcB1lwpaNUz0vuZAF01Msj77VrZfCelr6iofu8KYVUMvoFX7u+WwgPCNVId1pWCxFP85DQlu9ba6+2rOZwTF9ePlb44i7UzPkvswz7Wz8J0UjnE7Vne+HqOO/6KXVlUOSyZjbw74fYKWhe5WbpkPmEbI4sj6PRPy8GrDzVdsSt5mMdaco9tfPsvWkmILxaxs2/E/IF+QaEXMPHql2kn7fPmjCcem8Xy3nlH2LldjfJtGzaNP3tjNyyImitx65I9XF+Yuv3WEVNb3CTSW0Z/8+Fsl6HDaVAyrLE9akbyKM/nHeiCBtnoMrhRm3xMM6IM07eXaI5qyqF5CSCd2A59f/ofqQ2rgLg6vgIDOXrr+swCN31zgT6+N2Xr6QpzmcnNdU/yxXm/hb33iEAffgKi36em3ZDey3dpdj2rfntvOOK/yCQcta2jv5ZQ3fpDUN85psms7LkuX1yTXdXqQpGG23YfE8F99n3YSmcrToeow6Pjz0tX6q65LuBPCMGlFMzmcoRtUGFg0MBkfFdT3GrxW8YkKmy1flTvwjl6Yoqfk8Qm8pucMXfvyeTvIXqsdtdqeYSOLSHDl4uB12/snKLFsKKPse52Pa2IVd3tUN7974+wYj3p9FQNGk+ftIn6llqKpSBDvLovog9246mjm9T8A/1HFisOtxzuY5FU2/todlYrkPSnsE46ZFGTWeqR3uD0mG2ep5tl00k/fdM7y+qsWqUPBfDvcX8vBHpShySs/C3kjDi7l1Elm0oDsC4yHy7xrhB8WE6SsWi+cJaQVELGe+gdcVrsg3+qBeoX5wxSae7xVe7C5wgloFjyr6Nqtw9iYcPd7WDS7R2M7xS+heFXltZWtlyzQ3261AfPtbLD2CbmmN97ulu/LRcHalil4DiTgXQs4gwF4ZwBu5oQEbEUEZS3XX8sbw+TVj2QZPGcBJro7D4UbeiFAePUX5rOY0DrHbZiKWwfI08pVn25NaBSZec+yzPhlGvPvY6BdGYZQ6RWTpKKYsqhExMTWMk9GZ5CQdHYlCoESZreSy2dxGybiWtUbriPfTqKY5LAGvJNtpsBd5KaEYAswqw6Bw+b+9R0nKzTpK5RSSiF2HrWhGh48zOJMra7A2JB9AmUstSLR0aFjXuOmHH4AKCS/y4rMBIvNgSMIz9MVLv5zo9zczPtXAthUjj81AKlPR+/ZtpvNk2akTJBy0d+bKxl6CgDyqzdEVwKAuL8MKF3YMVoo5Vojt+nWANF0StuyTfEkJApTF1EMbvIFPtsB5sSLbRsTlE+CZgGFS0Vq/jzetY52QFcRH3m248QsJ9UKrXgVxj4W+XfR5EOJLfGyALnzqxDq4cqmKYOJL+XgRI+VR3067KBosWWpI4ri7nfeDgY0V+OjY62/kcRMhC49tfr1Z1JpWRI0DcYs6otNbJ8e4M4Kmz1PUXMYMGXl5lNcbE2gkFBTn+1PGExvlEq04LolfFU7KeKOonFk8Ua5nI3QuQmcltJnp0vep7iH7THT6aCRRRh3F9AS1zsd5J52xgj1qZGUKGR6kYYJPclN3cSh3/5VvrTVMoiClEZnSq5OIY3uCW+fjvZPOWOkRVbI1jVxC+TmRnNuH3+99nV/nPjR3ADnyAdsL44Xp2MnF7h7dHPKIOxe2ZqGB/eXTztzqMh+otb5YWYFALJYD8UfBTm8bDFoTTY7faXgDOiEMZZm99E+bYWU5C1CNVcR+3u8KpMVNQYAKCZvOA7DUYf/6S5H6QUTgBZjsBSzxerPcsmQRq9ZZHP4agDcPIKw7xGuf/pimZwn4QY8gReH460S6QFGF7c18SUJ/CoTOT+j8hLikblIPj4hlwFkjU8jMcvzmylUEIpYBFyvWyUx1TPNM8szxzPKYhmV74c5iRyBZIxFlrTfAemgWD0CWwBDfswk/fmiWz/s8Pdu5+3QxTtu+SHmQZOxMU3fJAZ/jY2OChaaxeGQtliwN0CEQ+L3bOzfqLw9On/d4UURubiwN3yOyDjl3FsX220mLI5IZUoZEuikBD0XJGf58ZUH9Zrr/wXMdXL3ywpBbGUYpj6aCbC8EW7hRUOstkyAdRldjGlkgz4InNomMXg/APyUA76wA5uPIxneBrwyANBsASx20ZoZ/g43RItdvK2TTkdFT4gx0G8UNcYhUJsWYeZjDPBSMwRLJHDKHeAxPVfRxXML910Ry8hYpsxhHHNS/gRIQ6scPFU8uPLD3/zLYYvIp2Ar/N28XhnDl474MhxzWWiSus4d4S7P48x9wP7gG5sAXrBPZKNjqKbqfd6/biZrdJUz+Dp3lwtx4Mw+FwINQrlYvWoLHnthpL5cuEh/MMSI7lu8Qol+inDuQ3WWIMca9tqByE9Ea240OtuvQEOh3zx0Z/9ipQXSMm1F3p+vgjTCtPdrd/lxGyYceEMOOxN02RSXebl/VQMTIpUmizNdbcTx8GSaEVeiOZKcCf9H6zC80YffSpZ0XX+KlY1wjkP262dv7a/k0t0I7Wy+F3AFkOBTop4gUZ8/xjtrXkUM0V87gKxvsuCfJmNWHhPxEusjWdjKCLZrbNOKy9ba6p/46Y83GUd20H8mdFZv40P9v+P+s5hT2VZ/bm3Aetz9ohP/cxWNicnfGJoq7Fp4rAPzlaUVMeHviT+aLXwqtmopmg+yZSzxIbCFbVC7fFbtiF1xZ17RpVa1RYTNHGYc3k5QX9D+yeFAzNpLqpjCXZCxu1l4kCVQhoQ0YsDOCecsmbD1ILlxhhA2vXC+MUjkY0NfV+WlUscgIRLCmhs6TrUtmfo39IfK6aBBRC4ByTSCrGjr27pvcA4qntZGUBPAZ0i99bW9NyRItBkzKRjDKBZ/5Rquu/7Y+q2DB+qabyMk0Y6OTbtZ/c2EuNGhnNdTGB9bjgdaIuqGr6+vFON1kElM+qVX9vXra59J8oE/7gY3ymDdVDzQBsqILpuxpi9ugVRJumqM8LdLPjIqUilMMxZd2g9GVWLP9IIMrC+vh/BTKMD3ibCOqilTs5ViIfsOb1tdcXhs6fTLV57plIMtga2w6O2BxxZlZxxPn2odrdN5+iAg9V0I/PULPi9D5CeWNgfWt2WBEMtObrrqBMagLgT75w5nLEpFC6sbLlqNs0VAYMeulNZhZUooiUjeMJhd6oJfGcOaySaigutG1z1m22GiMr/WBQS3FJ3SoM2E7V9OVWTfwJrBAwLXY4Fuf9qCfCoCfbNAaZ0/LBrFROcSxQCKS0shcmDnbW52MfXvBSIq5p8xRueqwSr2dtkverYQHJlHTSVMwVvnqpvjLSdx3xS6wGB9E3T8N0YeJ9WdeGYowEre4t05bPGz/lGgwhFN7gXeuN17sob/oDTL6a8Xz2EISK0S2pRIsKFFLaNDMAiuAQFmF5Rwxe1m5qZer6KX43AmdkdD5CdVnw+jl1wOrjA2dz2baWI6yyqrPuFl/LK1TPwQAvCKozymiQJLMOpLnMJ41PXM8WY9k+ZS+hsle4snCeuMH9SVaNkigElyxZEsvdzDMBCGAee7xr1ZW8QMRpwz5aLA8PTuK85fioMGwTrJEi26Ofy3mmj5EA3emYnrO5ecFLZa8uBgYfjKpjFS5fDuAu03jBqVt7triGxX4hNpaX5pr2w4FDbU4txXtjUt418CeRCQbp8cDid15Ci0OOQXEXACPyHJoJGPZrq9YrWc/Lk3lp7nX+dB3G0Cpdj9UmLfrrmxJn9KNjPNsWj9XTz0ufPkc1wuR2ohLyCSeyGlwVgyATjZwREM8CKgAwJQFglmWOqVvIAk6+WnpP3EGp89VVlGCmZxqiZEa6AgUU54dyoAYAKMFCQUfaZYoYAI9q/rZogQW5AS0s0bzxcKS7UtHTmRj3e85cken/pKS3GiC1/txmwRvlzxM628g554XsO1lkT+/2pZqv82e/kDJPRdtyoBaA0MxX7a1dVV+KKXcIT6jm74E3V5a9iAp9/C6tyil9XGJBXJr9tZH4QJNFVb3wEPu6uvK2rcvzfHAkByPhzxIIU4HGfoBsfYWakqohd3fesP6BUvjUC++147k/PLW6iLT26pp6ysre4kxN2O2ohG583jRx7U9r8xbQTN/iwtIkd0YHh2EtzZfr8hiLx5+eVP28fP0DO1TW4SYfeDlPtTWPPbhdeQ/K1a5CjPp1UvpJe627A3i8oS+/D3DyqaXhvTIyKOyAoAfFKEGbRh6/Pc3x9QZWXjvevzmLI9k+COxdUYbXut++G1jUWJH+WEXsGFItmyYarFv63Be08UwFb4lZTyfC5g4A8kO6uCoj0WFA8YxB5fiYt/W4XyGDsr+VB3H0nYFufHmvyeS4VmQ7FsfzhdGd6KO4bSPh0u9efJPCehvyT+320+n7O73qEC9ZUaiCneeIzD92jdxASlY/IOaJ9FWWvTVgj+ROrT9M0fEuPB7JvebVhUcUyms39Zji7YGz9WTP1boMJlscfg9TQbk+cSD+TL9vMDw7PoKQEZLmRWkPUy3a7S2zIoyazySthlRu8y96a8Kx7LnKrK2lPpcTRWRy8RQW60W19Y+6dDZELDdVxKwW4EuWtDPMkfPl+iZuOuwe4v7WpKDlqtw8IETlgegtqzIrBNQOUCM5RJvppGShlQJCJJhKfWSVRL0+SPBWJI3oiIQvHiHR4/48MG/n96vvN7jowXKKwHoi4fPYHbRQByDWZQG+ieaoDloM0De9K8kRm9v19C9LpZ6+om/bSjTkL5ef3FbHm61IYVedDPxKr39w2lvaZr7xrj3CdsCn4PwiBLmVyviwKB+sos+Z4pPgTl+loC36dmCKLvUjagHsWpQzxWBNQPZ43Cse0U3u1pLa0tndx5cV3hcsamYvM9OkZRi1m84tH4hlW1QZN0C99G1EpyuqpnUIpIuF0cBSun6G/ougsdk8ZankwdsqOBqEkFZ54Cpoy/1ECx9y07868uSlBeSp01LU3jr9lPs7qa4keeUzcHYcddeEeSZ+NcF+Npjo62f6CN4P5AAUPkM48HCJQjQqmN8TyO2lhxy6b5wHCghmaEtGXmmAavelyclvYKLicf9uPmWbfT9dp9ufM1ez6vcJkFDfyNG2hoe3iHpjc+eKOjbusgnlrTC6CMVUxxzcid4fhe9TVSDEUZKPDyXPDy4dRzZDfetitoJsChVrJRFS0HiyuLgZ7F5cvNMTsSnU1NYQGxyfDhey2n1usYlqx8PtBTozVtB0pcEg17SOlicbio09qf0aotp67MPTFwAakXrXvqsDGho1GlRxwlTrJqlV2lEWu+3VCo9mmZprYl1kJDDxBvDEx5Lqu+3xUwWH7x1HmQTrVaEEb3++FW9/EDmULB0cpoo6QtnUR2n0XimhM5E6PkRei6EHkeovuqW3heTWtw3BJD5kAzrqz9hWO8jlWMpT9qAECN8ynXP9CCmrAfxM2WCXG3NNP2BT0EFSDSdrPr6bPoykSS3eMkYQnil4s/6Y9HVI3vJGHFnbqCtlyUoHQwGG0JFmipFbx9PX7WkqOurF9DyAUnW7evpq5mYiq6qAeFkElX2/GI1I74frBNpWEOQ15Qc/xxuC/GzPCW/MsrLdzsle7nsQdop2Kej9oFvcQ90dl8e5Yu5+LduXm4ypbE3xQW6Ut+eHhjxXzXz1qc3pvM9+Z33SPHoK53fbogQ7lZ3T72Lp0017hLO2wLwmt0c9t8UjS/J5ITWIm2safAdWXFFAnFEOnQMmhl58ow5ZHR5JYknXhQZ2Y7gVjHhKYaJQI+63crs3IOmoe/vnqE7SB3t+md96kZo0xq/75OcAOn/QqKMnihkYfQkGnCZ7osIlFT+/cB3sjiwrCPPeGIrW2kqztgdPgaLNWTiBlF7//NyuKqP/EMYS98qZccMxq8/AR4caFXmuo+StUhwMVn3tbshAMQG+DK5zrN4iX2zdqgHYsINtdVphyhufuFCOdvZQGt5h394wnB9DgOyP3ziOXyeDbgKtCBkLlCP6MkCxnsmryVZUphIcNpiJA/Ag1iIuFiAe8/itWJN36R7iA8JuJUZDYYqPdOmRe8oPpJMpDb08smPYXcXrESHiAHsFGY9wnGm/Qzn1TencVfJ/JRnMX76Avc9gbc2RwEt9VubkBnX14slxFgHihHUJHSCHEKeOdRyBbUnqbKAdRP/9ZL9DallBwW/1w/Xr6/ALFIhL82MUUEWqHzaAlv5uiHOHDPlDVifSl18u5TrgAUEfKzsBcPZXhBY1gt6S3lBRuAtrzWvLwouWX3Wg0LJ/HHEWAUAvRIAZwi0lvD16ivwoM9OMrMgpFpfTV+f1UlaMrWTRD3B1IM6YiF49oTOTug5E3p+hM5CSPIwAn0eiCnr1Q46dT24jrQWAAU9INE6+L8pV3WC8moAdOqgI60FQEEPPobTehTPkp4pntU8a3iSHt2mC3WTg3pOZgWQZ2qSGrDpntDg30iuZnSKkSjHiT+bUvHjH/QltyCAPPOTJAEEj4RQle0sI4n6Ywo+0DxWQp/radp62KcGPA7D+uMk9CpPkRLBFn8ppVblx+lMxYxXUfdCVtuAfS0QMVDmg/UcR5jIAt2VAmBQDSDOMgHgFweANg6IbPbrczDDWK9GnxQA6BVX/NdnacRAlKsWc060+uYC+kUGKVqL+8iFbLmSn5KBor4TNr0iLZOjwdoZX0TLYPpJD/rSZR8KccLWn6ZtsEA33XALKqfPHgIL8Zh+TIVeuaCwqoJjlsgGXtMLCaQM6ptfaIBPocI54zIADHEjHLWSWBv8RH9FVneFjpXzQWDxju1uiTX4wkshSGLVcf8Vbu7P36yQ0WCb/Etb529S2+x/74d7Yvua6Po4do0zACf1rYkW8V1mZWnUaY/XxNqz7EYCWzbsaBlLOF5bo2f+QDmyalct7JLL3DbFbvFsfhLUu1DWxip1srPLOgHbTCznHtPA2Q7hflOKsXccu1Nj70k/WI338YCvZXOydY748UV43Ri7V0rMlcasJj31tsm0U5y0/iqSu088uhE2+wtmc5UbZEQPzrgPGV1bfp0Pidzhhaih+yZAvCbUFvEm8Rl9sCQeXdO2XExk+/gE5goeXuMiwRW/wQwNJX3U3LzD7lHQ/WCthUzxjmXB42a+WFovz9KJN69kkl7UO/C6T7uH1kbmm3FO+ciQeshGbONrz2RfzsY0V9uboeleWBgia1957b4ioay91v41s7kZi7fnAv6ZP8A95kzIPeQjY6fRqU0fML1rUd/gCb/onIuYoGbpltpchr5hF/XigoyxoQxhvE9KwCdenf0isNg0+aeQfIs0ArVH9JOjOmljEqTXhmWYc7dFjcCoxblNxuMX2PNtiQRTrLX2Rwf8mwlMw++Cm8DcQpqfgs8nWRTSqKUnfkfstfAm8u3nPEUDDb7fLStUNbV1fCmzyjuM1TORxaRwcD7v5rjwZLihgVJACg34oZPUsAw86zn7kBERVZVaA1T52J62tpM2Bp7UnaC7CGLqpdhhfTwOtJs/vPKPbZXUZNww2rf5s0Zhoi+4FZjHQcmd9NAi8PdWjFFnv/TE0bHnWLT4ltNcfOfgmUFlXhWjt6YYD+5W9HxgbrM5RqzfV9DQlrS1G5MbRq2qq3GLP8LQFCz+9acGoBiL/cLfkZlB89bAtaTXpi1ezhHDIY8+KR4Q5W2QbdtiigMR/gJc3f0/5Ul4PchPvYs8KLnhPMCllxQt6/TBtrxrYDpIdeM5s0xx4vgxPx+zqPTn0vN8mLEsVMZKKl8pYhVCVTl+xCF8GG+yEvPzYRqklCMkTJfZeb9ToSawP6q5cyE7nam7QOdQmhXmYsb1/NyRgwyzquZg20KpkdhhE5H9/ErK+rTV3myv4+MANoLhY+pH6fDL+12JkQ+f57Az/o9zl+r05FxrXw3PUdkGH/ntExI5XP5fPIeHRE7v7mZRPFhT29nNlmMjMqY/rtCuNLCbUvrLhM+n40zRP9kIU3jIwB/BOrrHpZ8GYh2x6kRAUIaJ/qm9IObzoyamVyaLGRkFQS1a8dUfS2LbdKXdKyF9yJpV7Z3YL/jPIBM0GM6KRsXKvOxhOJfrqqQIL+I/FtuYijzx9Z7II/pKq6dd/1oG9DmbI3vWbcWD1HB7qYY3J622X2zJ42CkMtuhKRIyHJAhxC6yi7D7TKWCieY+7KE0A+dDEBailaFRKoh6oYmmnosoAN0KDMTNEpxpQRxgcm/ZCsE7RURxXLNX8Q0r1secZltVNYQmIkRvuy/HC+2xmE2uRiUltOFu2daNJfAXxHLHZWZJFuVV2WGZbq+0f1+U7Uq7LV0I4AM3JFfI2Qh7au06BQBxsBfD57pDEJ6PWYki0Hkb1Wor/gxPJuJlj46mpQekCJlaWWdf4wdblrHBpCqVLh6nTsUxKhIfJldrn/ofOaZ0BCMVE3LELEteyzNGxwJfebzPsI6/CK8/d4EyfJ9PzGYAOOU4sMF6QbN2PpRhES9zYlT6Eos/12x7dbYQvc/VZwyRMbCIaWXPNLb4C9H8Qo5Oqu5xAG846nzAJinQe0HCq38gYIQLE9ty43+epALLGfMfvse7abwh/gZh7JK2c4mL88TeD4bXucfW5++qnGBTopjljPFEwJz4Mh/vkwWhIdbx+85AqpBwpocS1UifhI2cr4fcPfMh609XXN8jigMib873+zrOfL3uCWRAkG/lRBX2RufNAagyTmoXBtzZ9uclom1PvJZFJdNS4dgpqu04Ax1z6Vc+6/a9tDimQ8TJhRqxh2A3j5ihDifjVO0Rep/186sdy2vU2ZvGExugSMT1OLXlRgTPXZ+5rPqfbd3xnPKZWjywbbo7tMe9LaL9/Hi/b54tpmfTM3Q/MXn2eBHPc1+xvLTPzqbVu0SmB5qWUA2esgffLsSY/JAxHmwQXnlUhZNbQMSzCSbC6TQU+Y4O4ZJmJLDfLeserCGjcPQC+xt6C2cinEK0xqh/5Mf58H0asT/M95gtxdNAP/e5oJ79XNCWP9xBz+E4jNDmqCqcQginGSRbuITnQKnPH7ml85FeClCjs/r00QcMJ2JuRiugqqEjDevxI79mlTfb/1z+r15dfyY2u+ACRFD4yxwAC97PIWDAre7Gp37akY4pIHkeiXQamrLWbmfbUigcRMkTIcCaJvTA7i8h6PCmLfOqz4yq7KxCE9T3l6OunyDmFDui9SXRyET//Uwk3Q3muvWypgITPaltb0mTspvOYocer165o4LUM8fEHB86lV4wuOgBVT3NWHcoRwOuemO3/FjhQjsSN11HQEXD2ExrazNQxr9brMu6JV/WHZyOuz/XogmrJMvDyYXQG+EgMMqBqm/yYCu3fnBZPLFuu4ExEejtFH/iVfat4HJG21jqCZ7EXjSNna/k+KHizG9cY17PvPfnqHg2h1GGzQ6cwLF6f+OBH7yhNltyngsbfDvB2MBkn3q8/JOLj20V4JnqR3JwIzTccZ5g19xJ6rzYdbby3aX5vaufhLsjVENfy79fo0V4TyQb+hrmO6vHAarJ0Oj7ZqzBC4U+V3O7Ld+nG7vP0S1DSV36z+bEm+2sEHfeuYGl/V8pVtm0pDKuDWLWY4+MJEydOjv56vpczDH1VJJoKqHUJNBcD9qsDBngB1eDqEhNxNO9qWHoF7KT4MsU7zsSZL77sZtNXWzz4MO5rAXB2g/+2i/q51qt7yY3y1yDVA+sZraeljZz/k3HOFfmD4xqEbSM+wZax3+79WloNk++qedYWBGmGedEmIFhBDPBIzGQHOImDBBQUywEq1iq2deltvsXmnPDIFs60S+BiJl2+/rDGmRHiLzs0lNKqdvrT0PUNH7agPPceSB8rpI+7PxhI8PcN2ktXyTcNM+StTmEjCJMl+EJI/A2bDu/XIv+lK1TXPVSwdvTJ4j57XOV+dHip3B4e3ncJf3GA9pVn/+clejshNHL4+PfGX0+c6AxGtdj78FFkIkteTgZ2ykWHMDyI0QkG5zDSXdUu6DekQunXhEn+hxpm2hb1/ycahy5JU0ZcEAtg/rrp1vaB5S0PsrakG9cdG8c2yAtl62hkBOFZFHWNrbTYUq099VFp+7iJSvuNgtuS72ojUztSqZQcvZzdY2WRuyrgRVbj1NW5VRyNRqsAb88ziZ8/pomLiX44o696Yo9PgEGXB8jmbO8OaiCikOAOx2K3XJEQCexOnpjx/JmQHmaaf1vac7h2UxbsozroD4Fc69nH3mbAK9HDNGhvSkxeoBVwlccE8W+M3So3eMxMEaJfPQF8R7joQzD+ryq3MNUANS+86NEe9jHkgsz/9vEgU6Nrxv8fm6+c/Bz7d3WluJ2w8CSm6V7plmHpbOVblgUQ60H/FAafXyco51YtwXpMKmP6B0qocpBW9gMYGUJeLnhLDAHJ8o6iwzYSn08sK1COa+PSEsW/jh5I+iHgroPBMLCtRfW53ii8gSJK6siEZQBXS2P5CQtyxLmsmL4IplpRH7vYnnbwjwJ0rdMfz/n22mrUOL8CIMuAjTMn4ydKGTekThcmfSFjyEYDEiJNoicHPcWTev8SEcJxl4fBXksOe0NQoL82heTX2nGaSlPMhh5vSeWATSWwAUDZaZhkHc9nCk07EfnxZI3iDuXp2eOhzqe5+Z+ECs7jFaqmgLhvnyVFXD9FXIM0+IG9dJ0P/vqXyxS/Dn/5CD41N8clqDWYrjjAtTEQmsbCi5F0t0T70YZ3LZu+luXauvjOAbt6Lpzis0u/2m2x4ChHKfkET+d5FCzTvgYiqCC/BeGWlpuJoNU6ySD/KX6yP8RNcXVJx6LPnEUiXnsM0Jgf9T2Al2HC4lxn4BC+njJx3kcxIGmJM9pgd2RWoQIeQr+ypmgDGsPjYhq3cp5cRBxt9M75AFg8VvU8Q8UmU8fHa6KhPlyDITN2p+kV+MHU9jHajM20uRwII89w7DLUea4Oi8nRlrMon2HjI/hjI0qYX3R6+yrTmggahSy9T+wYDVWWGegK5bUKGxmr2IXJ//NzuMaeZn7LTPRMHqFHBRyKZ8hQpo2Lwg09oBq06Lm/HWxIeayMajkfJoLvWHb31oO4jBqGFiM3bZC5nNZPfuzOF+FB2uzm27+EnB2G7OGl2Fz1lEVGROTqxLm3V9GdYr7P5OU7kdNkroUkOGpJCiSPj/BZjqGc0N6AJI6ffYiVBlVPcqRKf2jCIW4yzq2LfRG612Nb8wyVtMcG6scBAntkIc5EFnxyvqZLV2gOXZgHv/p/u+DKTyvlwoZ49mlFTRAa7bHnE3P0aZ96nGOlDPhZo82I56Y+yLkUsPMb5wo5D7jM7lYOvMiUUfKqTz/gCVBhmJCgWDlfvnkeb78qeXD+XhPxO1TPsVLU4UPtADJ8QKYtPwALqYaGdttgXU56jl+hgpLT1DwAtJAPcBb2cM0boDMcMVoSt++psEgIQQONG2a3O9a9cbz7G3Wd0xFprnpg6Y8vx45t2WDzHYtHS7aoKo87zlgKod6c30lFvjbwMtqHMCKwpOMG3ngAYnJF6NREBUfQeUAIN/yy6RLXpZxsZIvzzjp5roZ2fCNhtirc8c/6BrUMq4IANNkAI2OBa1XoLS+GuKhTFLQbXWri/HBeU07gZD2Hpz8bT85M7L2j41xzH21Iya1SlwF2fNzyFZFcVEnVamZsDooGqN5i6QpydC/LhQtCcdlCfthRIzIk6/YdELEMna5iKwKWXrZovAerAd5HP7H5RwK82ntBNfKaR8EBAxfEYrogay5E6N8MJizVvawmB6mt/MIrHake43eXVOAeYoYHr1fIszlxLhOzjPr1vtMpKdPiA+K8ycCVn1HCn0VgtqjiI/Dc/IT3/V6LhLosCBpdJBGkOzNhtqLQJtc1WiFf4wnxbSqe/V6WGsKPMafpB0a1t3SuS0rB98Im+Pa2wyXWm3KyiUWfuQCGY8GSzzF0XpuSDGt2alugCYAUJkuZNx2bACshc24JA1A13vR6wrxIqdMOO6OUxviiKV5q6djaiXqrj8dVMUfKjMPu90+ONWgH1tETNOwgNF3XJABgsCHoBFxzI9SMsj88f1u0sU70OEWdkk8nZF508ENdc//cRkFQhneRkUdufegut6ljtrP80hbZyoS6Vt0g0nvsfucMuW3LSSBym8qQhGNjzXYTPNFsGkGhHqo/5b0JCTxbGtv3jSevEucg0QumpCreJ9ZwiQN+RUuEIqTUGyBMF+L8V0lRCTOBW0gzeJ3aVSszU+t021ouUNN9Hdcf1RL1KzhHlRlYBoC8gAyf64p0BFUIyaJr1saH/sTEqZ7dyPuiSaTGpDZg8ERpC4h2tiD5B+xW+uTgvhZ1kK+mk8mNsT3kakiC4/rgvs6DCSMu+iYwsAwHlzEnREdXTB3dZLBefe86HXVU1Sb6HwCHxxbFcFcNC+26WWeaxkGPo6k46OGYibuVvwYHUo8msdUefiJdxIsUfgkOkxog5Qw0tsr0X6yi5Q6xNL0LQThxIRhgswLjBJ5YlQ6iuCUrho0eq2zMARmvjiHnCJMYrEyJeB2DxEuNR6k299Y6PFsdRRovLXgkRgW12/eefjdnv2mFSQs1CwxD96TW0kxHguhU7oTHHBZc0cpVdpNYHEo3WOpfnGPd/x23UPN9+q0h0sW1ACeboTkO2I3wbLUiMixjrmo/65Kkp8cL4mScYiDQwdhKLyUOmk3ZT+Atxs8NL//Dxwq1PnutyuYNaAH1xCe8cRDg6k4PFX/+S/ybEF0CuYJ8IYkvG0kBQ7hkNUMoxKGkA611mP071DDLVPVmPxFYd1CRYWgSKlQcqGYPz0Hl7UsyOcUUdjz9+YEZi35o/CoZxl37azVq/j86S2KNqGG+rhQMh+egLJceFYkSDUahAnnlrDYaS5QiJS1RMKb5c/B8+i0g9YDfzVTJyhDgq9WyMZwgd2DHVOP7HPYmwzCaaTBWe6RCMKWPJ1cCbFcbJkKNspe9yTxCOaK8EWnPFkZJnaby8Yes8eT3ldDyV9Rf4PuP57+R2tdDL1oXUnqC/jiaAXRo8pSqCKdQSdm/aTi0MFzpdOsog1QdaN28gITfE33LyDDHbIUnZ4zCYkgsyvWi1c9hAJn3TfRm0OakXceGG4gkQsvYb5nJVSzWrGhFKZqj/pTsVePq1gBfZ4ILeEZFsj3J4pGojaKYa6ZxLBQFp4PRTeCYbmNIo8qPqtQY7mGed6UdcwWT5w8PM2DumZUhwuNIuWugNH2XaJJnQZlHBvDKLvs5Z9M3nFzOw0JGjDGI4T6Wqq4L4VYrE6Zra7JGqWvxDh6uPBcbeR9edTF9xh2Z+225BA7wYDQ6wW1Fhdwx/4l76F6wM7qZnFsYIhhH61ur20YeVgA7y2USHIzHqtRsW1vc8/W725hpiHkQea84KkCJ4dvhiBzoaSB50kjbg+ZT+loYjCUf0qeKuAgPf+vsc1dBNFPAbhQERaY2BmdEcE+1qWwGYV3rBt5Xh2DlkUMdN8qUEk+HbGyGAdp9lTFkSfPxNuflfpnKXjirxyKCgSahOACvfAiKsJcw/0VfG4mbj7ZsYLx3T3mUnn2/kSdYnweYcAzwUH1keEiCEaDsYwG1joFs5hjgnDcg6a5mxbhnQPTwNOJ3yW/9Vyf76XP3noJZm47CLeO9plP+9cogSHzPWjGoS4TrJv5C4HPsrqv5q8Oh3dsFrD8Pt+1Sb+9Rpu2R8A6NKoCO6VnrfuaYA4Z+cCYI9RrPuPUYKSzZRKkyzlfFXfVAp78oA2HumnC112LLz/PskgvFJ2UESUwXs0CK5UqNcqXsnI2L/CQN/yoEMddgjd5SJv03yIKAB/gAyl85DFeJR2OEE23qbRq8jjASjybijFLSDcfXMuPuLOD4Byt5XvusxR5/eGNIB378qRSIQWhBdp6SAtOleeDU+TmfjX6u+VD7rgaM7cN4BmUv02CXyBBATeB2pOgrZGWZzL99dSn23AxgHe0u5kGxN9EGY67AGZMgySiH7/ShEpQDAf/ypMoOtSUyiGFbUSYE2QpjIIUvOCwf5b4hYgp1aJ4UMrDmCSlCZFkQ8vHXqh5MjLa9WGt41Yen2FlpxRGtlB5CDGa+9E++zqW/BZnw5U/RL7c+cfP/ZtTG2eBQn9gDUQra3VzwaXzYF/Ek2VeFJN7pb68enUy+7BRbG+4xYO+lT2IacQ/+bxZg/T7zjt9MmS5dh0mh+8Aod5zAYC1+NW6RX7MCKU3IeZVJTRaivTzi0wD3xU8Aya2WLtAv66E8qiI+oyLpWsxifaT/IQl84FtWj0f/FpdD8xQtkflKcTpjGY8W58c1Wq0AbMXqYDZ3agH8Me9wp9GGL+6z3brGln6IAB1sNoPGHUFQHsCy0k23K+G7Af8Cd7yj4kxrQvB/3eQkf9XCrHq858HZVXBsvxeTy65+vUf807FSVXUzjaK786YOJCr5QQMQwjVoKkXm15FcSapGza9vl7YlfCHVoZ4GStYllmSHlsSokJdEMnJ7BOSIIskY3qPtD5yw4l5CNS36Qg60U4abzJKC/BzN/T2hhTqlkUdCJjYDBnBlKtVoPiNgQGDzQBB+gPUEqCedoDG2wGTeesn+1AYlnPAh4Yz9aBxfnrkuxT4iP5GiHLi0l7JQOyvpk+EWjon1zILvxuosGvosQ5VALpLGKeXU0PHtfAX1onaxJio5RHSSx90L/+hjdZfPgx/OKHGNSOwgBt7ydY5rO1vFHAMt4txAQbvv7tksD1+aAMMY2ruf3Ex3A1AyS27V5j28JD2UWoXvalPoO2CIO3TChs3ecpN63Vff0D8A0WjkpzMY0OqduiIouFAFus1aGEQiJ59UG2cOFGEt8baslIbTQQDwBuvfZjdv6JmJO8iwd7c6nwfvKWtraG2Gv+SnzI5j+DVrIIMZzLk3m6PfSmYteEEjk1NzyaYx+ZoFiFfGKUtiOwLjRCnyN2V/BojXzOqd129B8uQSYcf+xtnx6/1tiVS/HpZ9LnLiPK4MMGKmxVoF/rFxAYyJfsVUfyQfp+SAMihy9zh8nB3VcruGNl5vOwsDh8r0yEQdycXL9ws0HF3+KbdAlW6i5WLUaXl/Otadu+m7CmsT/hPzTk13i4OOBfGQlmlstXq50uQpE9fWovHKH2BGejwLozqAgia502YMw8toMLMycPpAUw6YINR3P0wldXcog+8cMeRzlMazGIJiy8AhIV20ml6Ac0DXq0IbxYwWBH+WBne/z94xurU6xesAY8Bj0WFVc76TiyGat0naFlFWsUz8WLK+0GhjYhOCd5Y1gShAbOGPAInzE3t3DuPuJA1mySxFu93vJ8hWE3kgPGM5YDllG4gK68gi1gusGIVvUhoGwhNhdICc9EYRNsq+LSFxSCaazTmACGoRhQJRAk6CnwgNIpYTGIdhBwFnUfVCKwhVkHjAmURdBBoDMFGQHONRsFhLLNoRpytmFeACsssGqNoch7LQ2kv6AiWEcQGPnsky28Cm6oLkz889QGkkajyqPYvlv5STYL7iVVFnuBPLP1ja4L7GZ+u9OTygiVn2wgPkRGR3uQRS7/UCA/KtyltlU/RdEyc5LeHgqUZjQkeBj5c6dkCo0loBkGb+UZEnUSrBE2JZSe0Hf9cae1hhqbMqhXagSsiNxa+sLRilYXWWVTkVoNj6YplKbQl/xFpCd9YWrMshLvMFyKtc2KvBE/3LFW462gsPaDIPeELSxuWo+Bu5MOUHrxyaByoVXhPI1UpvC9GqpnwfjlSFRIeTBCjhN+zV3409GZl5O7z6ccSdx9e/mb//Mz+qB/Vbe7+3D9xHOWovmPTy4uV92xUBi8TmyhnWo/86Pnd6hd+KM203vEDOrH6N2fnzOpH+laOte7Y9vxm9T1bpcLrxDZSQX1NP5Nf7Rr6ic30zl23R5fl/FTrpiLWO6+RkVQpht/jB0BET9OsgUTSaUJRyHF53Aac0hxmKLJQmwwUUXAbk5jqaLAbKNTjh2lHV4uygaJjRAMc27GBEdiOhs4LZNDoQOzW3LGEoh5RHykQWdya94TbXu7MZN/3e4c6mot1RqXvYe9bQU5RhlxQUjci5we9gaPHOjsKVHjrDeI47NlhFZ5hN9DerHF0CIZ6RJeRPGh0CBuoqpti07jYgQx6A/cWNkl0CCzLL1M7oSiCDRSNaBqTEgI2CRQBK8WQChs4inUGG8iST+m8gUI9rcAglvJl0RzJi7BJICrDmQiNAxZnHVawDIrao7l0zpjMovT7ncfTmMJeIL2agyjkBg5FjMj30ZDTMtEkfkGsGlnSs4QII5T95Wy6Wc4NfHYkpMLbLlV+RF17JG0og7fh6M0SEkebLl1lTBXyu/gEQ2b6b6dZQjtIKEMBe78pOqDxBkV25Pij9XdOHIKBBAe7gScFI+wTNN4QwuxocLtQwA7UyQ1QsoS3VaJw5iJPccdelOTbohjqWzgpWBS2wrGPgVM6COqfLULtjzTZFR025SrDVZqRwp6rcN8Y9jKz50TRMI9QeAvmVTKrKhRs+L2ZG9uzkMEzFAu0GzWHyPVOs4TD6GIsonS4KZ5OpR/gTGyZ7dW0lcjJBbrMXpfO7nB1fmJoZWB/M2fy4p0mzFAmP9Tt2Ili1c/OmO021Uc3Hxz9HCP+F3j/Y0Fl8Pv/mtqnjpPsjckF+Rj8JN3MZJeiYReFgk1JQqczgfh6X3o7oc0ts18G4G+2NJAsgrgShUNI5UgM+++AcsH3rch5hjoeOPDQmiJaIjJ4tfvFYCXPwBaqPCsb4Pjas3PgBnsWRwPGnK1fxH3DcpVRsPS4wgiFFIvFYVkdwxESt25YulkT/3i6facUb+LWOqHeU2C411eWwOuEMOQVDiGPt6+4dKXEd3uPBG5HZPhnHslCBwEUUZKX031icj2e9OmQxjV4IVjuuioftDtmj+8WlYkSmEn/iojDunYHPkgo2iGLKal5J6OoAKAJfQgUbZBfcRKIHA2l4PB2NpSyjvbvbyJskAuKEbGAQiZhL6RzaLS+kN2LfW16JDCZRGbmZBBZXg/pHUv5Qvq6akS1MbmxQp724TQzYD1Ww5qW1NTxiWMHiQA/aBRoEysIFqpNPJzy/qL+1y2ephGJCwPfOzVw+F0IErobmA3kMfRQwJHACj058OBmQFF+WcwdHaCI3ykW1z6WwAyFSEjNP77ZsLpQlSpYayM0hN9BYHu9VwDfgK/LxD6NoGw/jUm18vMC/jo1WUxULtRQNNJVMokUgMwdGGxohemYkpcOaKBQR/IydGAer9N1dIE2UPXChtlcnB+xfwTLucz8SMqW3MI8p2yey/Il9k/Bltwn63N5/pD2/0zsLnfN7uDp9og1nS2qo0acprFhXyRSc44lTzE1MJxBJM7JqKTLC9IxAocqe1uyzEThYGX+Lkh97uQ0TbpQUMB/hS1Bjw5aEwE/JzBtWP3INch+nJgdBaoZYGNmALiRhdPT+Jfpv48Ec+yApQlAlXoo0EKBKyBiDthCRdBvDTDxc3PKF4zXqx8Qsf20PgOYKIH5IWanoiQzd91Tju1CkSxGvhO795+tOESqqpxGpbRhUqsr1JeU46KFlNoteJ9uySIyj3RvJvt9fVnG/mwRTAdhh9mizSDeET3N3X3tjdhHNIY+tTgZjWXcbtR4ggROaHj9di3tY04uwj//ei9aiw4dSBRMFTaUkTkJDJyOzJHAh0omRKCg83EQ2k+DgiRev4kWOvG6L2SJh5OGYRugKGeDOLoCY0smhhHy6bazPuyAT9emAVMlxI9MWfV0b1+mHeE2DegeQOyBUhIlYB9bifTz7e3M8YfR3B23IXIVExDbAixxG42A8xuIWhwhHiZDgamHnyBfMZnMO94Wpx9pDPhMtqJwqZvdpKkM+K1HolwYe0EHOkigXbKin4WEqIve/jB1LZnWBBMITBz6s+GoxckgP3AjoqExM/ZcirXjqFwijULw5SQSzuPlmmJyNoVCpD6cNLZbrLuebxP7a2nL61QsGylpakbH5sLDDf55J956urd+EV8X2kDFXvurYfywmHskZWzAdOAN1MzpROEoIc4ZWkZMk6zIq+m2GbPm9gjEfeduUSn3XjeDKpzhFOVNR92gN07UxNN2n8EUGMYUCs+HWCzOxLI7pIy4qrRRTYHOJP1U1jrYhMFtrBZagEDQ4ATc+DtDwNLE11UWBuz98VMVCtCpNiUcclLU3kc+/GJlyQhGuPgpY6KdWnz/TCQB86kDndjNCNZ9Ojz0srHEifG+bQbY67fNADwAU2IKbNgCOgWdjHmUzHXO4hu1ExURC+8jMeKSNx5OK8S7vT1MOJYPZXqXesQCmKEobIYL7u4MzVNMiQGBQU2Q1IiQMTWB+EGuHZ1ozUZZv5KKXsx8n/JQfnhFftl3EE/3KXJ23Y+ecAcJ+H+WDn+5GV6upnQxc0/UpHAhx7axOESSLhmiWxdow5wyGrtrj3HOgKDsM09GOOMqzzWS6msh82zgk1Baqhjzn8l5AmqCqnlpbsgDv1802MjomQmiMPWTkSFqqyvLMcBbqCwjW5v0siqSq7RNME5PZRJxIHSYH9kAlkOJ9AJ4xviCzIcr7eYZHYk93s5tKbBLTYmvwKyuFtAdobxVkxAykioCqSTqxbjEzkyoYzaGzXDYqEYPu4gm9poh/f9UoOFFZFFXSSamFsF/yCHV2gWi/QUOSj0x1JxlQdQdblLdVFEIST0DGMlbeE8PoCovcMFSqh5U3CPPRZkP1bwOTf0pho4fTQ9+rh/c43GNUdWN4Yjf7OO2Aj5o0xOfKie3m/Pu3Xdfvcf3GnzBz6s66W6zgUsz2qc7Eo7tNMqVjlr1yGjD37Mi6CohJbm3QSK/sq3iOCUJYceoMYhTlo7Dhbc2cEnAWF5DrJkooWGlFdhDHAxBazIwWPeavvbo3w3NNma+/UM5ejzpbkF4N43UFftCBtjsWY6mHXUnc10MatPweyIsP7DvWm3OxyYitJEYu7g07GXxn/gzb/LrqSYx/Zpl6oMNrq1oini3vi6QLhSVm+GUjyMMKkPBGN4EZOdxdl7pJLn4sTg8PJRo7qh6Q0J4GP1V67VQhYzAItEB9vpQxoSLyHpI3I4R7K0ymCvJMDu3l/N8py5X0ziGBIY6rRDb1HFRBr3jksOLSYCa1g5XghH3T3grdYk8A4Dh2OUX5QBUu4m14kjfOUOF6uWFuKgKeYnTH1xAeakYGszuLzUyUYWCZ6ptKiUSTgjFjBV0g5VOhfQjHI9OUKv6c5UuymMoYljGnhQzpJ/fMWWiX442uiRmYDhVMULEUVX1OpdtBD93oS7q4ssiS5/dvPbRoFpbixBYTeRHJ5ap2Yd8vuGNmfB1Zd36zTwvqtpXJUz5Bpp4WxvWDw2NXains15TP7+yaNIFq0W8nwpwRK8DWS6zlq9emnHSHRJ2eX9O8XAtmwm0pBsX5QJEGhcwk4l3LuLVogV7OPlcYULT3hRX4IO81gaMYGCp23EkFDtGUMBRcPvHOpX3Pd3EpeH8gSZ4/NmM6qlr1/afI35Mls8XuNJJsIjESVX4SVNP5qMTin3X0xGxg0g9taMOILoWz7XtuBWlL1Kl3nI5P3LUyuRFRwgy6ZUi2yEDHdVewYLIfDdHCCqqby6wC4YjhaoEHOGqJtWGQlXNC/NejAogmtyaBfZCDugH5kBTX202pSboHv61X8pvBe8XLdpBoCjFpSfSnX4/pDuDu2zHlOOcUXCGs5U4Zl/ABf1irIFnODOBQjpWmBSzYcdExRK/h7CAo+E8TgGDelxtlQRqlRW5Aq/VYiuf0tJtQuVqA+K467VnYqBz69GQmXuEh2hlFU1YUFGiwKT2kuPDQaxCtYLZElTg9sFFjIMVDGqBZUsiqy5sq4a08SBRcD7HAs/VZ4u1o9ApcJqg01P3S7XFlkIwrTihVhhiVI6Ugtv9gkg4qHK6Ihp3he4CGLUjc57Jb7/XoGhhIBW1RwhjyWDwYnrcwUjoQO8eRLgPqbNe2M1LRFZwi+vnMNnfX0cS/vqgz2kQ/VDpTGHsjvQU47PfwbJ/m6RJfLg3iOPKHF12NiXhQI8CrHz+ejsptd/msk7HBizOAhpvT4ajQ2hFGEDlykaUkGoVTEtBl/uXudIEwYAqH5djWFizGAFKSgw13epRb3WvGRt1v8Jbz829mbo4RwJVqnowZrwAGQrN02ZBsmvRSU6S6cHNpBfdTa2IXRqJb4WcmyBHhknz/0gFen3zlZL/IXuKzIRvuy+2YFEr2QwhsvgKbi9P2PW/DItdBFt2ejWtKf1uqTK7hq6Pc4mvkW0va7HKiwoH9naXp8/NpxUxpNmDw6KyP+9UDGO7p6GIqmqLdFtm0GagQZWZ58OwQVcovg+cP0xuc1gQYMXW5pFStGGrJOysDqAfpGoGVNUJkANQcXuQ5F9XjvTZIpzG0ASLHbsWmVCWUh3zuipkarcnTfggZk2eqBEWzUACQ5AD0LC61UQEsOsKBQWUSGEWHOUiu4GaxQOobvrgOABVVx2cGMiGlepwgrM+DZLyl9fVJbzshsR0uM6/AGfDQwYGeaDCkgTPCCXT7CyFCgfh4m1WP+Pke4JdpuJGAAri1sJcTtf5wFGpMDeP50U6hhrOAtcoGQEzlLzNU/NRDGl9jzzBEMVMqOu92P/apBtWsqTNUiThEIH4jjRVKIa0MYpKNLrTU0PVBsB8gOymyLpZbndhwiliGH3Y1tg8mhJJABmHc7B+QSzHzYsJ9GSJoIpK8AGWHoa4+T/C/EEH1VOhnvgAGPN/wDeKGEPfBwFe4ihWovXSA/hjAtOh3O22wLldeSo4JLWKhQc1FA1NpoGoWqQoNTWhACs22Qg5GbksEEpHOUxaR3MytALPsIwOg3vVAg2vGhJRkdYQeezlYW1kUyStRJlORmWKadosMUVKsP9ZvFtnkKGmU7qqVOa9MHbJGfIOpCYfLwkmb+e1l60NQ3LQFLMnMuLDrEQboMpguj0QGljZ86uhgLclGzRNRtfg9h1otMYK/DqGaejUDgxHacxRAsGHBdor3Zr2Sjm5TQrGS4xz/d24SwcqOFrlOGF3kDaYLr9GHGYvjreucuLeR0fAvH8Es/hsim8DqjaSF6LM9Zfmy5XkdSV0oO7ZuHBAIZZqmTR0PBlErhrsJeA0QYJHZk2h8doK3mpOMUlF4SCJXQCSL0Pn8Z2KuBTzDpQvNepcLJLxxqmIJ8NsKXjrrGzQtIJecxF+mbqLqTXcZPueT8747mgix9BDST7RdRTG2uJ+CulV1KAGY3JrCPqtu5kUbyt2S31JtBlUBHXgHef5XD7svPdio8PbMlLAlrk9YUM3A0Z8A0hAcoSR18SMSxhfK3AR2mioPfZ352YCOFwytL7Aw0qIEgpc4Rxfi49B2Jifd1+/Jqpxp0K3ninvLXXo4jAC3DfNbZEs9svnSvcfgwTbT73sxjop/4RcvIhHB3i1CCxbmJM0TaMwgbnL9b1DOO/L9xSTa++fjcfp6GABATlTBa0V8nPtroShvugGYBkXwFQsg3o3hxhwKzdQvIHzWJrX3N2phZfZiKTTEwfFny8jYAHZoJ6yzWjYg31OT1ZCiWFEZcEx7pfnMYT6O2oxJPrJpJnkuFQsOA0bLa8Z4ahePBMP96pJLdKTg87+V9ItO8rUyf4CDbBxTnwcdcjjkki/q+rv9462e166C79G8xRhFZq13/DCKRiZWKCugyNVlxTLhvHf6cEr3kMafAJVqE7EKBjwG38GLfOisWJTeXZezCifoBP38MQTgnHiYUxsKo/O/ysVKk/JmDlXfrtxxyp20sSHmEiPlrsVwgojtdvss6vyQULcJzCh1lbJOvtqpqqCua4ziw7/TH/wpwK6KiJ5vVVUPam+2RfyyKGNKka9cN41vsoLFzlqvO1DEQ0xiVnX4mdHVbdPF7W2xXohOi3c7KgE06DAHUoxrsep5g5QkDzw7UudztxxHckF9guXoK5E5bOEf8PwO/PGVSGJyd+pKQP2xpd92mAg+eCvL4sHgjUZPgi5U1Mp2IwSYO8Wbygq4fMOT3y+6RwbOFlVAZdma7q7l3TOb+GIpIKtTqW9d7RYlKHdhgfDl8/ycMss7sit7Uya1OXo27oEbVlHDr3qk+uG1Opy4ebZ8I9j4Tru157MamdDULyUlnpywEWED+Ubv3j/ZbpXljeECO0fZ/pB1yd1ZIIZqbPlZimeah/mUQp+G9QavKinSWHESK0vjTYRJcGnLtiMUhkWImMaZfAB1Eugo3aG/F2argyeJU4eGLs2+HrPIMXeZtMfREw45Y/G79WXfcd//IwfMJmJo6OhP2y98F5YxlKV9ulLuMku5OxpFpVDp/dEp9Kw+vTj00wxQ9soIRi5D9tfQi/jfe6vDB6qUCANBFISdBoNgwujLH3BdACKcfBpT8tun97a1f9n+dP4GgbntMFi6glltOaIzxLZVuXUTHw/I96+CNQa190gLUsY815quYBVxoHkmNnBXZrl8+ebyAyXhjmHBFU7NgGrh+pHop6pxNv1vShc+O8XvD5SJ2DN+GmfbwhskI6Lus0o796bSRGIUx3gkJQmf4ELTwjsx/jCDvv7Cq0Hn196jJbFft02F91Ky/Eu7zTiZ+cqfrsCH9Tib6eBnRx/ivh3YKMcmb59JYlVzVa171OVqkjbem/2w0UO9nLpbuj+vit1JXtYvpyDKNR9flMJwK1jI1+usYCU/KVKkfT0HPkv3DB16CCKc2XJraERvJ4vNpiDj+Eo1zkysMXWN8WJLL5M33gXVUD3HOmSR/Io0sXQytv+pQw1Hy2ENcQWaH3PhGLM2ZLGiLYFWP71JJeOghaCOANfb60FOu93Pga7A+DwgHgLQZ3yVYny9DJlNiS2gCKeP/aaVWcHoyvC02476MoX9i/+OUh8K7Am3oDcGuYlt78+ttKx5o/4u//2gY4wWP9rLNQck0VRAijlKUOdl+6T3ARYxVeLiPaqSDCjdKdfky3rQxNcN/HPYertUiYBcGz/7UeVzs2Akt0OIbGujnotYDzF4+TePs3NVRTzB2vzQHYZjhK5Ke6W+uJDkLwmj/NweLQ6ltzHQE1exhHoxRd7F5p6q/dO60/3B/x1tiFzUmk2jmdwELJ1Q8+/r6SmAhhyenVv2uaeIn8fxpyZUJ5FOsNeHue5Q4d43kpW7EVextNgrWshjyObHhN5hkP27erXn/BQvt8JbousxqK1pTgG4RnCj965PyyNHgWDbkbk7vLRTdVRVizxTNF12iftfg4Eg57H9/7Yh8WanMKF2/PRqEqNNqptPsmb0PCvkrIY9Dqbe95QHNcGCnYF2sYUk6DTYiIv3iIZ8S1+QRr3AO0YrE5/bAmsub00KHKv+TpEzwU4mjYM+xCFczrVZxpZH8l8YZCt7rg2jx8FMfsfdOXQih6dkMpQAGCMLi7QuEJHHYH9dkl6DUsaXb8PHPwLUG4+gSBqod8qGxDH1Euo6wv8GY0i8vULBKL1+hM7FuLSaX2HhUO58qX+XkdS2xynAzjoIWfPiujBaXtqkrPpcFR+H/fPE61XsH9YbPnYbz8K0PfgtQwuto8WhwKORrvfe3gnBthW0BIDffMgw9E9DEPSCMuZWBwiaLyyI2CjJnSaXyoAmZsgJOUUJRoUSPfPhbDsh8CbSaR99tLtTKKDJmwzPTcde1+wQgdSERtSAzkTAdM1K+JLoDiwhjbfsr5ZYwMNBHSXu7dDwobmIVEtHlzs8/Gb0H/N6dHxLX2uHQ22pumZZ0iWLOYQDO3KvFW8TOfwhRzm9zVGZlh3N6geGngoArjNWUXzmn8f7AdT7S/Px8CJ72AMdYSwLmX8iF8BguIBg3dtAVCnP/yYEMRaFNUvtvLhD8MdQH4zfhZwHeBRB3mp64p4a26Ke4Dr/1wg8mOFijEgi/UWH6Hdn5vT/XT6e1Hubi2slLNpWyFxYUpHbUcYoENQw+bko21qelwhhYxiorbcYgWsFexJ0mONlBAVT0b8qXqFxWHU9lmhsO1zMO48arncr3dQ1ilFNoohWAN/RjfY+2ZgHJbsbgBpBw6HHMO8WktRewsoqsq5PNW7AZqFHU7o9NuMAjG7ftMaWLA1DQh6uK2FwEKp+BeE8cRmhN1Jn4pZIdZm3X2yioz5tFArJBWU5hbEYQtneBf9htUwEnTXpg2xKSRV16FQCiQrwR+I/r5DBH+o1lcHS+eO2abxsKsnvXeiGNr1YTJY5Rre8GP0O6BYnnUdywQaVvMruI35GsilQSNZsfp78GlrRkf96KyLhfzvpWS8syKWTxqem3XyeMUK8VtLVNdb1VaMIAUDiyBgov0ESI1HeEDzh9oSx9RifVp/ZIDAF2vKXDzdBuwv8yERv18opyGCb6vTX6JL4UKr3EKq+2qluHruEJrygkvN2XTp5JUdIq8fZTE080vVRS+t2j8mL5bcGPIWpdSz5C48bVJaWKoiFL3XNPQ3U03vm/TuxX/DQrz9HyMBk8MiXZwu5Ft8eJCFGB8SJ5bU2sfzmHHc0vRzqj5vp0XN46K2U69+tOAGbYSFL0a6eiIaVQaILnfwtafd1UwdU0FzMMl4KRjvxtJjvKx8QZbcmsGhnpcXXHwPuvY0cvdrolzBw3LtlbdVtRfsySjZX+vL5/IS7fP66nqf/oyu8hyQkul8pqXirjHvubtzRHGUcGuMcwBGVjgjPq6g+1g8VY1/ry61mOBC3yLd2dReHCIG9EYcLnxe5mYOoeXW0B6zF8sbCyYDFFL9QBq+d9oOoMzbgay6ka07hh7b325iFXS0KY+gJgp+jJtRPl8VOYDk9LWB/Qick9cS/XgUnvH5A6FVvfDWRvh+09rb5xdwmi5gQKwFh/kGtmXDazthIyfDNPfw2mBBNOPnZ6arE252BLRBOKy45mVu0S74uooGAzIUez2i7rJm4/xOkfKoUwZeTzNeID6hh2kAWm9kHVw54kFwZL2D/IUc7bInjg3frYnbtYOVonUnPjaJy/QkGxjTKsUIi76xLudIpriBfa8P/xoagl7jck07J366unahBVcIwlLE2AGnsa5dWhag0xC89yVlQ63yQK7tp+ZqMXLrlUPYgZEDDLTfVhAhsyWxOCuYq6jBtvQW6ihhzl2h5aPez67kSXSF7g4q/WEgC3qLnZuOlGzCS1SPP6BrORXA21q6G5i/oXbogNwr7b7GwygJY43ZFW0vLOle2ZfFQsCaaFDv2FGraxwSWSGuRUnEKcfIAisofu3iS5paEpXZnyKn+XcEmnWHCbcliC2oHTyQhw6zWjN6agFFvgKlBLhr2oHKUIhh7sCIWyJUcCxs0c0krYauCtPJ3Pt4s9UWUV7pIJcBSr5Ij0TY/xCv6B70lmlMEYnX3bXeOKeGCxejUfEjSqfUya2vgg74b7/roR0UFs0bz3K0dMLE3CUUu6H6AXtgRELk68PGMVlTb/tlILmjnU+J89/bxx4F2hKZyvGThFE5twpdbVydNRvDltnHFCYJ9c5jTQ939Rq7aL8o72IgVjdaEYXrIGvXJYZEtD+odPnStSpZ3klbwv4qqKgPiE3QMy9rt1IY9jId6h6+bm2K4WXQ6wUB5u6nmWTJJlpBjsncB2v+Aj+nrR2TVAG/oElrCZH51fBOhcvS2/d3IzHIuhX7RbJtz9TIYOSV2bnmfprPVsClGVxLPxFkW1AXLdN1KCViqZ9XqtfkSVma4fj3QagqL2eL3Bpsq5hHMUODDpFUZxaqrnOWqlB7FrAmbOBMKPZpFm9rJ4B+anWJuBFXpfx5AfOSzdpzg7pW9XI17iFixIfw327XxDtmlREZSPFKv2YVriO/Bf32lM8XerqL4uFmGV27F9xMp8Fqs9PxhvcKbz1g1zuN913BuOplM5qSwDGW6fqIgdJ23290Nx4pysarKjayWsz+PVyc/I7SjRKPTnhiG9L1i/GyFVi5YGkjY+YrQN+gF2wEKrAoW2F06kiW1polpY34PE44I3lRopEwsR8THdJlExXDmq7cIMsBUjgVjK8EZAXf69Ko3y3/IUZcPjv08puYOBbK+zm1oWLV0IYtJBXXVodZaLnCEGURxHNECnO7lsCE52quKqP0il9bHwY687zgEWxb5pnx5QHxsfJ6HuTEvy85Aa9TB34JTEkDQFKsX9REB8E59kFx/68Dq64MJuLPL9QGfHfdQkdmc/8KzVZvAfYOBGV9UfWzWf5qTxFKlitIUUdE51ef0y/PZI6AKsjniHuDb4zw9sjehKZSyhFn7Xu8PW4Dp8CGajQnmKbfrmClRDmVmmETSIlKKS0vJq4aNpUiy9qpwV5XTRGgkHIhI8hRlvM9HmI3NpXc4rPlTj3g0x0i37CbIIfQCPj1FXhvUTUglJ4JqgnR3YlTlBSDIqWBokb2aWfYFUT9UTi8W7XvyP/VfvTE9oiCxxEaICGfNY+MprrSDbzZ5uOb3mMujLYn0bncu/bRP96IOC1NHopBxtzBo6PqyN8H425cre3dKt7v1uZJ8S3Z+005TAV5jNZEPQh0QzW5TqcvroS3vWWlC/syn7iyeFRZenelBJpzQKJUrCOzUtGiLoyVLuLwQ43EBwmErUMXLSpr3J06vpVbUQSuXI7SQ7G9cc23WtChXRiWxykQsL2PCqogHH7fQOX1ahUBqyTpBEl8nCpA3eWEhY+47SsSaEvZWFJqtaOzb5BL+MmAoL/SVDSYGXNarvB4PfEDo6WzEEC61x7xvdcbyjqWzjPksmKuwd99rAx3irJL/IfpwalAq86zASlqujwyrWMmSmjUlZGkA9bQCjlttHZWXXuory3ttIcowJCOEZc2/djQiSKtUE5jT9G3VpnWLcFwGNxwDnAoeTftD386oiaPE9ZFHfVef+wI3PFEqf7EgtwSy5fj8v79MJUNEnxpbjsPgSkdwGflHEPMqVoJJvLLMdxpnzutPzFFcvTKIz4d3MaDi011hlf/Ns27t/PQWqN8r6tnC78R3fuQ/4HpvaAYsGoZTC9A7cSgJmls6YDqJdiOoU4lcDJLZ2PDYafRclzm9mnOIC/ufp6W9M0ozyUCqZfiVGg/VgIDuxlie2ifOINo1Er11Dlw8JsJteZqyEi72FK0USUVSf0cczuV6NEmagy8WQ/zG3604+PV96wQ3QwOnJu3mAF16fVIAu9VYB4X8IXtlBEh9r/25NP4DJ8QAReu+R4LwOAtQW83XHoAN3hJPYx7pH7C9j5IC4dLG2+1GvoKr3VtPp5NexcTHWXvTLV8O8/D8hNOIhFWjmebNVdh0JziRG3kpQ89EQ+BebYA/G714mg0/7C8B/tNigGX7wAwJ4WEWVvlM2G10iEki9qYqj7HEQi91zF1xxQduuXwYJAisphW08JA4nEbIR+wSkeINwv7mO8xY+nuC4Fpa9lb2MhhdRHWt3PWUZqy9dwED93/B2diEXM6QSzlm1tBroaqcsu1YOvSLNphw36K8zTkImjpkDCqsE43bRssJTjTtJQbqZ9jQeIlbt7zUd3CuG6vRgnmM6H0JinBz0ePUIgc3t27S1K7RE7xkffWCtDGIVqDTvcmNZoV8+sdxBadhcdgY+KFarnCddbhjZUOyyNdhM/sqC5mRvqJ1j8Y5kkg7OzzcRcTmtjv37tUyKZT+BuP1HIO9UdsWX0epeq48j2b2F59PtWXUpXJwG3euN6lURxECsVd4+4nh10+ZfJY0YAyo6uQx0lxcJV46M/XYAlHlmrfo7yVRF5qP6tXxOE0ypboMoa36JU5yryxzJq4Ko1TtwQpI6F8bUSRMe+cGkFR7jMd/MKwzJUpJUb24k2QF6hSYuJapWQx1ZlQZpb6cJxTzMISN1dzkOgs+oZhuMUpxrlayA2XdWxv6QCZ5MGYDMRPO/aoZRct0ofUnpQrIaqjyaGeMgTH4G8LchdDIYW3zTmJbN67KE4Ggg2PWSxj3BUWpa1yr9Z85IU46MJrTXjL5R1ISCBbyqhNu1qBiJMf9yR/i53kuMIAge0vN0WBJ4RuUSZglVjmLWmtA4JFwd6jI7zpCh1C1irffnEp3JOvtgP9GMYmInk1ZBReI4wwVQ1mt+MJk3gHOeF6H63uHmuCwh7GVDLFNnXy6lAhgNsHzQ1V53zVmLDFeRqpE1AXA8q+zXz5omos8JBjyCRLrfF9jQy92IZW3ECDyJBMc4weYDsBXtkZLfGv0CJqnoZkMqY3kmZMRJzZZaayzrKKHgiZxW4WPyAMxmZ87JZhcPsAbHs94CMmk1hPIWwLvFWzmYBNLP9AQy+/LakVGP9kdNYIhL858gZmlUErc8shqDMd3aGvj+w4tAGJq+yJJ3anZKy92bKBJcfuGERXq+vcVXX4Nmfl6mdSwq3KRpVbDXRF4BND8VUTWjejytHmPK8jqYXaILld5rWwF9iUWTUL7t8lyWJOW+TlNmo9hIM6azImEkAPgxQD7+kgvc5uayoPFWr7NxPJIXnfN2blQqQeOjDEffBoB0mC22r0YEqv2bNc+J3uZgj/GgiWLRKxMUegkIXcOnGwYKqQrRKVL8zPN0yDiM8iMjnI4q2VYNhUVjQrIuLvIS+WzF7O3Cmxh77uovc9qNduD/daKetEH3rHFUxM695nuIAl0dD7aV7S0j0sLfznYPwj/QGJOKX7ZC7mim9BAuGn6Y4wvxCzdN8lwuwT/XKaJl585OJlYsy+w/k42m5oeee27Sa0DdqzgbU/ZlqCQZ4q3Ub36T9zpX/DrgRrNDSLiR/+hjrSOcZ845spIzBhLthcxBpWoA5IA9G2cOHP476u0P3OVYwPGJjqOi+xBf1G//rU5Ugr1nk5X9ZDUvhIZdQj72hZEmaaNs5d6RiCVOk0r3LAogaSvz6NNizMou3D8vkZEy92bJT3SwDiF1kI8/gWSgL3ZbUEf0byWl2p2xlXlRaGbfXRWe1JqV0wqeV1gjF7t8cMqxRa4tRQWasKF18x3lQG887JKe7L/bQvQKxQYzipzt4pgxEvBH0xwhi2juzQcASWW1DTkdH1Kg5YW58t6RZuDIksBMtzKWc10D5RrMkXC0Pw4mPlnkDo3TxHspENw9XvSakIcPKxnc1FBqNzMEU09WVsSXVyBKD9YdgJZzh6LE9z9qNnOaurMTFVL4wA4VnrmZamtx37jk6ueHCgEOv1bL8d6wVzsnizGLFyqv21duFTmR2P88jpOWpFJTQf/QWgpnuTuEpQ5FVs0hlVu2FZ64V8XIhOR5XiJKf1753HWG4UvsqUH1rLkxmJvdttKNJIRTg4a/cIhlmfC71yyeXAwGuKzdJvKbFcsIqiQX4jjqdxUcfiCuHbhM/+RZ+L6gPKKBRcY5+uHo2h/+U81JMiuOFRntKxHpJMKnai9YfBoiTlEXxHpCDEvyPGPwW1aiONJyWsTZvdrPLa0Z7kNUXVzSrVoTx9AlbS4Z+pSYLaEiyDQOx+O6d9AVx8wevbzIcOt2PcevQ/uRQlWV1cxz4bbUwnz7kr0np9hn3UCJh95c56H9Q7tBeFRWYBScz308WFSibdsgT25Lv52vrp9qdlTjItfxfloda8l43dhKCIBv8h/yMyITGp89uTFCM/LdaVO76XbxD0GXMcPHtnnur0h5YqqFAtwEeUT8DQ7ef+iKM3KFXIiCYbGnHkiuTmc0QUVicXgOmnr8AFgDyP2A1zSq3gKx4t0uOMoGilM32atLNp1UN/zaaOi93OkGJcEdkgabq8ayMGATSFg+adCRwehzjzQ1Mh2sN7mK6rEGtqwaMvRP6+VrbGlc83XbgZnjWda8BFLx0sWxhyBTBCXS0NFxUtYXkdJy2F7gzM+CrsLGgQeRhgg/ReufRGktvX5vhzhN+71NhdLTK48hnbeQHIl6MIoFbVpvzru4dOCfBFVJk7QTifGn6MIUvN90gRquRh7P0dwhMkdvNA7imZtMMkrMrWT93IY3RwPhYqMGXN+u9T/LDLyABwn8l3MfVRVCDTEfvpGi13vr8MKJ6YVjPKFtALMvVibQwaGpezK9xQzSX5qSM1ubOUDUYJAzt9mzjMwss0CgZPeT6NUrqH9tfDjbJu++/WHl3oNAUGmvUBYfCeWJoPRIfDih3qYpkfqcYGDkOumw4hLyAjv8ZQZcqteOJob1jAvOVoAi644S7NJul4hzZmU3Ys8IPJkC1z34fXr3ZgI4M47/luqlf48CbATpjccd+ooYHCRhSK/Z3vQO55b1bqJNBPOQ+Z8LSo5chxUgz94EMFaZUCSlN6pR23udvBXaF3UDYno6LJRtHt+QiejQEbFW6wItgnqPwIvd87Jo7EaHziqgmFVpdlZqIF9zSDtehL3FnFMgYmEoiem/T7GLwDeDYEv5AJ+f9bwnRvH21SeC0a7DuENlX9xtST6pzdj8ZqNbuo6KjshcqAahgLKYo3dEpYZNq4bgyV0h317VCUKFbllVFe8fF4Pw2HhAXsQd0dk7EoYgFX5oAb/4V1B/hUbXangwHZrQpYfsUFB5wUH+INh6RN+DQ42JIKBVjV7olkxQIFVaPBlZoJs9a1gXUnrLCPi6FHhFw1mbgCOLZYfsgQFKxP0KUYDn9C6ASSIgDnpQk3cCs3ACsiMcmKJCm2QpI1jlkSmOXwentD/p7Yk7xLKwc/Mi2DFoU1UyiQQaVRIkwFoGw18G2/nMFP/8eyWnLv0/uEZzAm/nGSSQYDrIxRixFlttmOMuCr9Qqqr2Q0CISsQpVBsWBYWcUNFnhVpMuuCn2fMq8HN4hkWYGcZQJg25sQ7gikO1w9M2rPrtoAAH9p0sxcLXQih2AkzNUJhlxWYDBlvDHyEwbfdlCe7/Y4zBK43fMBIShZBRICQIodM3zjDMwnlQb5t69LGsB/Q+B+dD7djAwkss7EG6RjhHSMl4Y4qul48vQqzYj38g2Eu4nK3CpQnJ+NQUrHJgAVg9rzZKv0QlwoKIlRhI72aj2J1NU/TmTfwPgsh2v4h5jmAQxI3JzxbzxFw689odT5LmtGpw9Rpv7syJJeJI+nrnR0W+vlLpSgy2B+upT8Pc+U4/OProP92TS6mGZmxZHWPsdSAk0AUq2m6DUn+6xnSpprP208bpFFTmMVAWW4GvJ2PwJsFQhI2nzq1Gras6bIZyYpZT6zB71nA6OOmrk2RLHGeQvuwDoYJe43IhmzD1iBWFaaLP6TtoakGKDuxul9lSyLKs4AQlNlXczQRWAXggLwtaIcJGCoCElZNcTpOcoKlKFDFeXCh9YVTvVg2kMKJdpRjsQJtC4HRDhRiMhrRY8cxzQlARjEbEAeQOWhOYRU9MXGSdxC3E8lLECy+QwcGGEoWZNoBoGrUfrquK/iMcdssyeh9BFUr0HpWFbAn3MglfAdFvw/L+UYE1nn6UOSYYxF4o+4Rgvved75h9L3HcqqORH8rlqbb4uxrAlTmeFr1ehUBNKtHyiUsuHwyUO2mHS1TFUAdFB2q98IQlbLC1qPR3cUS6UuokB9wdNRo/hPLSkApWKviYOfWOTSo5JSWc3ZKg0IVri/U2DEX0dvtch6MBg1+xEbY3dKPaPY2y5KZ9RqGM1QGR68QUjMda84Nw6MtL4nRoOXUKyGfPk4mFML7tWhMPDluwTylYoaqt6TfBwiOR8Z1OA1qRp6klsnSX+qP6tbnSRIE1l+Gk3rBQh51S1y6BCI7og2/tSdxAOsNhI8KUWRP+bo9zZYo5vh3GxQ4EK5oi1ytfSa2NY7SPhVMyzNo1Oz35g9Y4MVaUZTHhk2NPj2v448z4JgEWh18L3qHRMUD+FcYbwHLBoxhryM4NukWrkZ3o8WxDa++YizzNdb71a5lgTGnGUzDT0OwchV554240Dq6aEU2V3meC82y2CTohEbNbFOrzEu6zGyxScd5tXx1iwZMgwG7y0YVlKbDjoLTS9C+lEUuuf+pk1ZMjXWgGt2iTz6A8DlxHJ9RY4wtWB/Fit8A1AFmVEBISAnUg+maQZHCVeQbKjtbtEgtVuJJEZMHYnGV3SG03PoOpo18ZRR4iZEh/WGiUDyNA/BSKP2Ia24nUPhyXFY7Tdidk5Xn+rEl/XAmEC4Ru1ujsThgRp/jHQ1Q+1OaM6c7vE3zDtMCVoRqUiBsEf5W6HzvTlIVPCrpLOBLgV6hc89/fkt0eR52V2Yk5YIfIgHytqpNmp0RwwyInwrVhQ4nhVai76LY2t+ad+6c2LnusKEJlM0OZNrRsIkk2nQdpUth92RQvzl5XiD8cxpXhcp27AwYzbDtGRJ3k1axEF8cOJs2paGu6TkY2fws83t2UfgVjTgr7PMnUrUU9C6e2dJ1qt84EnBXmAd24fFhfXfHv57dZbucxnVL6u6uEMfLfcTx4bw0/on6i+GcJh0BJAgmLyLuQbClMfJNtdkC6JwN2gEImRQ29t8UWuJA97VdXWsL2PUW3rK4ys6/eHidwd5RZ05kCdrO47EFCdP105l62GFqnZDfhiylzXJcD4AgRtMUeNocVhktLc+oaHoVu49uuatJVyahpLyn6hPNOCrR4h+D/lISv53ML/AzoZfjIZe6SNV/8Gq9w6kSO0btDQEng9swEqH5Wf67exUQZE4CkRlzeIVpNz3c3k2PTXMDO+CQxi14B7sYcaAnXm3DYUDQX+OnVGuk552ib1M6bYOpfDY/XbhVntRAbWDQ8zQ5dqIcyBJVueuMBebek3ZAA9ZGS+shkE5Ou2so2N8KpF4CNlGVhbxNMa40r1j2l/nXDfKKprN9JTD+oA90eAQ6O6l8uxdfLeWbjyDHYDTNJcBerJU963sqOJ2atryu14PR1d0dLxyZxQLFJnizMLDcXZkN3SWxk+7xiWSvKUb1dmd0taHXD8GZW5+zIhn5mVGM6+a9J5KogilfK3iB51kliaZNWazpi+9q+VE1TeXKxAlq4cOHaIhGrO8Wm+Xyw1iI9a3mqw3eEZCzeo53TjlT3J2ROUKkYBYtWwM0sTVoIapM8n+LAHIsh4W3e5CEbpAyfRFfIK2AHEnZ4sPRKetIQpuJm7wUsaBV4Je+t3faXopMYADloa7HBIQ6F1zbjArpWBAijHnTv6JCt9w+8wGOEZeJ+oYGnWMxmILG04hVxvDNbfuHIJ+w1JyqZVzFTGWls24udMR6jTUuJP5SrAqZihSANi2EUfnhdbRnIGo4hh54XCn7pgGj6wDgwWn6udFMrlnsSCWGHB3ztWTUKc2I0xULiZ1jXcujttiYiJBTtOf4unZEnOuMNoSzCqDynEEkJpAAtzZpwu59E5VjUUU5IQ7BN8Vk8dKR1HI83SkjVOBtokEicnI29XIFFE9ajLBc+oCVQJuLi4mo/OCCJfZnKUhWBMDhY2SpVyxYN94Ze46TNOAK55wl2O2kAmS7VEMYlxUnUpSADoenhyObz4Wt0pDzkQI0tRiKKSGzEA4FxU4KR+TpCMzxckL/M+FLAkRkFj0KBsCQDhyZsKUrEAa6++bzl+vWDLiJTtQLZa4+CH1vj6sVZwW/boNRdWXkbXY0yALgJGFBVrPQuLuNB96+fwX6EvP+S8EgpseNFF6c1LafUxiNj6wNHl6yqwLDxbRkeM+C7xbHX2FDWqBh3BeRQ5jmzniRKam2m+dlzKoOiCiw6tSGeUwV57eWHtyuZouLozNn6D63eKbgLXhvga1lSur+p/0tb5TrEQ1ipVfm/j8cDWII8uDBVM98e+kS2cjHhz7scok63T8G8TL78SvnkJv/vtWbg4fllxppKOJ/Z8ltgo5rYp7W2qUFP/yaKGPeWzF6IwfQ3QzEeVY1t+WmlKWCLhVUAfMgkgbqT+uLYDueHn9ulE1KOTQ75M25Xfvh/wvPAVgHcrjf8HeQleROnxcsYaC3v8268ZAcI4lIqBa33hk+QhQtZFbM18mK7kZ0ax1ZPHjVmpDfofBtDpJGehCAz7b0ePiQHsXZXoGTmrW1PmKO8rmH7+ajRFFZVLJios2E9WryJi5Z2XC2idIS+65r+GUdkfaGPJ5EI2C9y3nI3egyYHFCfn9JG9o7cDerDYTsoMrlpV5bsBBxmfXuNhP24FuiEv2V2EBd9qdpOXNmBVK5YON6QobbhiioETvLPKkK6Vgf2hw/yVgr3HtoFmGqVkAox0aHdxVag5Z2zpAkarV1zjuZZ0Rxh27z8+P78VoZNL5gx1z31D23VtLz5zEy4j721GmHtgcxAh1fEOj2/fRe/I0H2rFvC/vTxNsjMBaGC7wxMUeWnYePd9A0r2el5hIljdzSMM5831sdunMHh2gq8MwdZ4MLyZhPcaM729nIaeNTlA6W0fCZZCf5qpsmO8L19CgWDMLxEl5zDcapiwxGM+Y29TLIlYhUyhuZ9ZxUm4nRtaFXue5w3gpzrDeZ3X9mYl9+uo5DdYT0wk1j5uh3vQVakMo5zGkP+8I7kJMfenAKAyzY3tpzrpBfAvfIj0TOVVusvA5X4pGHrCJbgasgksDGXpmMyjUa46IgdDGE8DXrVCjQLuF1eH4IMuCZ343P6asrq0MqnxBA5x7uIxOeelS+8GiJS6itJskxgfH16klVtC3ctttibgYfz375rXw5yJ0UCwuCckQBaRnsFIM24LuClhFSnhAE3NGuggAYfyDCOco9RBXfaABv53ZPBZGaZg9iL+avp81gdVGrxtFL1/vEa8GeGhYKS8dIqtBXBiJjQOtc2YzYDu4FHoSls2AYvBA+NXOKAUAc6Cn3a8CvF97OFyOHIX6o2JpdrBJqNy5lJMOzYSeC6VGDfNbNG+vOTFzPgFtleel+9M0hYWjgq75qBLinRrN9TFD9UEEj8nQ2q5pWdroWgxdW+qBM2iVt4CaUuZePFgSwu7hokIPabgXeElY6lPlZ2zyaU5uIZ1Xtd3YFzPMuML6KiX4Ch+1o6Z/A7AyPRXQGEsoKPFw0jGujZIXRTk4wZh3MW3PMoetuUxGKbv+6aZs2DscQqboUGuYaIiBaCLGTJ3PrtogLV61QkR14J0TfxM33nJlqfrTfx6XvFFvMV8vRCSStzYuBgIJsUfkSeWfWJS3KNVCmWmHbOycQDaqP+1Gx80RDUMPp4vZbA2t0jgsDFihP0ArYPlFVyLSmPvKwlLVnLLmFVIbGuGC+O1oTHGj+JpWO9ezqI3FBUcQlI7Y0b93OlaNezU4LNvBYxxdi7S7tWWAS/MFReQLr3q4x1rwXPKXXBHHVn9NClk/yOnv3SYYPZICGzgZxXlYLtAVKzN60U7mEWjBoGj989VAxWG9MOWSVnSfzCnZeAbbhUIEWAxOXweoxEd1Xmd/XZnPLpHd6GPm3M39ERk2v06q7kF+5qHasyzPJxlLqS4XLqyTXuR5ihzaVe9gTu6s35CALCtOus7TjAlF5pJ+Ig65hSZgso4NWEO4yCIIaBsPclznMLMyQlcyGHPXuXg/1IJf3z6kWK9Q7m517g9kESTbidSG/gIIpvqI53QhQFrlCxu/j9YL+Ir+tOyo356OY8pXPKZjLpqbwAaOmziyJrEUX3OQ4A/LXFdK7TDrtc/HbUxl2B/dmdzdaSOAdx9Hefzu+7CxYaxglChQJ28NIsdExa8lWQTo3rvu32Pgou69GUpbC6L6viSOloblGPyR/99qnW/hx4CpBZPgkYrgdoj8XP4sItybv3PM2poeyvMluZtzwloempRHpAddCg7lcIu+48Wq/ooIAJK6OF3QBTps2UJqc0kX6+qUk8Ez3dUUY3JrwOF1NdO4rvC0w/i28HTDg+JEkQJ3A2/MyNZIYIgNm7p1p8st11R3acXkbh1z6s6AOAfQ+fbaOxsZLD3Opwuf1NZ8Tci8SD5CQGtR6SrUG2eG5L7rciJ1TRpylxuASxguB0mu2VA2hbw7H8Rb/bamaH1LGjK5ogRzPJ44jRKJ7BcsK631kfgdygd8bK9o9yhyRyieI8jK5nfJVZaGbhv0wl50lWhVcrljE7nMPJxr9Qfamk/YwBi9/+ubQJHYaWUY/mDjO4hUZtNbofA0ChO5ShhpIQe14l9ZhkIKFAsbTxSnCJ+iIc5lMIMFSqHJi3lDVFAlKVQK5Ny5AxRF2fXCWnDhfQaS5b3mpKytvRCdDtTiEAoJm5WEagNTlTzu3oeHygkRSTqB4nkKluRxPAwR8Svd6BFDJ4rrY+88d8gio7o4GOOhUn3jgQ46bCi/mgCqg6fpERIKFH1BAa7qY9csHCfCTUBsgL2MMVdfvStbZ3v4l+Alt0GC2a7kg/8Ck+S6C81QtrvyyNZv0o35TsKoxzvVNhb+TcJAW2E35LlDh9Lo0oT2RLCq4kyEiZjoDPd/wejZcGckX6b7H7DGs8EbZV9Zny2yY7bMhuxzdpl5u7dF9pC17J8ss9dMcy++OF0yfbb18JoN7vudvuE/xwCG89zkQaFqnUOCot1m24p2HV5QjpK28iiwEQ3vBIsM7gp0i4sItbrk/VKbXasjsTIV9mchO5vuN096XQP7U5JDDz4qXv/yOHsrSR4m8PtdEnargmfMjSYvxzmHLNmc/T48GfKkxXYkRnVt+hG8MUCN3w5GQ54ay0J8CqNKEe4TxlLSByeNrDW/aqVwOdiWxEvWme9ZgDFbi6JGtL1CFV/o6iUZ1N2hOUh4FInKEATWzdA4JjSamFtAAJ+zttQC7U25HW+VrJg9zOYcJy/djxkWThIybHv5wvcwbL+EEgC4W1sDvMwWVjAe/sb2G+zS6jFU5lHG+S5TCe7etcbJQ+HuMFrP15XHq9SzsPc0WXZ0S1DvhfWrkpuE9nFVNjp6/JpAh6MB3wC4YAOOlLjzl8KsAep0+8BtUtZC8fUaIipu0DJWHlZylrhKkpfaxPpaIXRMvYZLj5s7dH+oGGThuc61tDRhvJCet5uAqRIrH1/Scs1QeLrVJPjtC5PqkvBg2Hg4z2NRa/s1jSgtQsfdShru9lN7w5wFpcY4m46VfBnGdsowCVLaKAvzPsv5u316gCOUcM3ECVIgfBoJvlZgit352NEFb81TMsGo8Woqil6vIV6NZJg2iEHNw2Yi0EzPcw3oVDxzTIrjhXjjvcXucIkEnIomOsiiDK5BOcAhLdoiCXClnB4+Hl+dlEDEaBJe/igC3fq1QwxtrcjiqSHH5slTmsybjJspT5K/djeG6nfbAOmFvLuVI9u7U5+qufOelmEeIHlTRJXUsnPFziF4zSRy/dXfn7Ead95dsokzhN8OnxcuF/PLOzbbDEzHRjarGRVPRcF9ArhOPfQQLxGeqpgcN/a0DPOc0ArzTxk/cq9gsLam3rk7bXB8b+sh2j3XZ+UcSFaBspo4rAClTKQVXo/aDpFJXXd6vd4DmCHB0aOvAHgDPze3OZG+ra8cKP71rdagYL3iRmJRwtNbWV4XXOEb3lPECOWxjEbR+R7WlWx/Uxi8YNeqaIYUkPTGwLr26N0kQNGc/+3aj283ivaE4/jOd3k5p0h2Aw3hOHcaR8+MNB+V0jXJo9zN2eJqVbFsXsamqYNKGaBgE6+YB62VOJEd7/wS2DCG1B2p3hIHjlCdcSt7+RlnUwQZVCXhruLKWUpnGwIuDDoLn1DpcdVxBOdgtWz085krqpjw3gPZaqI4f3U5SJc+VK//yjHkAKByFEf5RQm1q4mblzrl7i/f+MHfZ9nTso2sVgxSMQPpeiUyzje5Eyhezmkf74e0laHvGefmUTTfXk2JRlBQE94hFIwHwrLREF19CuKoHazdBVssNM2sEaoHZ1wF+jLHSEIA7TJtVWbM0XE0xGMBvSg3TL7qBduFSSVUkdhRe2GoVFWOsaxLGrhhXoxLwRqcMzOD5jJ0oXjFk/MU1hlb0ZEnOXpivqH1GDk5k29QtGK6ys5rOTY5SAcqeym/VJDNqKm/yGgRLk2U2yE2XZR2MwLOjR8oLousmvib6JRvhFwiVEDirUPqWZI24kxaHrnsotxNBhYLA0DKzpdCZiYxpkHg67BlWAqXJ5PFEUvdczJfby9UlFNDMQro2HZraCfiaFqz2ZQgUsOG+CFN/mELgy+booxE+0GR2UQE6xLdIXILLo3gpoFDv/IV7V2iSd65aLJZzWPlELgD3mb7PuZsflS55iHv9ZRG1AuYX46qvcmL3uHbX7WT1G//kybI63AMDLqDCGwfD0xzUFMvtoKYRG9vRTLBxQJeHkr81qXpP6IcuScWqU7JQXTdcSXL1E0lYQvpy2fbGtSlzq8pJl9PCiiy8zATE6JgwW6kwm+miJn3jOdg4tWxwaxsS6ljU9MJj9LrioFGhTylvGNsmQ7qTiGVIUEo6KC39HlLSeV2zCdunDbHFrv+F7T6g9S+qJpU2l4iOd8R8iU+EKEMy3V7tlLUVD/wcCA/QHIuevhumrvMYvp8G1kDCMxWHd5modYWAI538y4ILcGAvYVv+25osGv84e+zHi4ZLsiDKb1XuhUgEPfqtUidjosUfr1Ei70tppY/qBfdYb5uhG5b0FledY3fUjHkoYuXP4gweFXjcSI39Ipc7Ww62zpZULJV11lnV/mH91AhapW0AztUq1wKyxETQVhln5XjZRyGTjGpaw7AqzavHw3r07dr7l19USCzoeEuLrCGJLDkG/3av/CGLyRvOtZ81eR7oYqSjyoOT1jEDmQtTIIHKOu0Q6hOdJ8qKG2xfsladUeU4GmS692M8CZVTGTMSKPMsfchDa69MCJ79dRQRrNzzaEtrk/jBNTPhMSWY6aMT/6I57U2DS8bozNsOdblEeuIKFyhpWs2nM5NBq2RZvCSlik1nurr9YMx2kTkVkMSo5mRlteJGocTEA6MRkzmPFh56IingYgLb25qQ1FgDuLpP9a9F4bcSurwX2WdrNMaa40VVVF1JjoTvaneNF3hN4bg2Hrb2b/Q3hOsuAURoGF6Mm1iYud8MiqQpgRn5/skQ/jn7emSTuUCs845G0XfBZ7G/+gp8HCyMPSF8/uFTkI/OGh4L6oFHtSZna9Pekmnk+hN9Pm0iWHKTHzMccO9aXo+2W44+U19vg7tt7kog/ZHex36ceBBhmCcwrHHe/JjI7rbGUAuuNDNrCJOEv0Xfmwsq85vGIEHEOSbIHwLMYWaGOabzC2KUvlDZVacGF04W0bqQ7LBcc4MW289Qrgb5brCCnIrj7ByYdBFCryGskaLpqcIhfK6FBV0Ft6XTrz93uYlQPHIB1TuSXyBHp1ZeJGmNZxTV2wcW/s3H1vP7w5rOW1mc0Ytv7HSaJARaNoYC2T4Zjmjhivu/0x370X2ylshpnRFwi3xNrl9a3qZImXOl0V65vmChrC24Gza8XkRr/kU8cD4JH9LUeni/xsz7//qqqFjRBeebLIZkBVGQDYx/woGDeFtcvvW9FKY0k8LWfTMNuOynZiH/AoSJLLCngYjdQQSvxINpIEoYBNKfJ5sPUJ7RWRPkQcfdnAIgy9pBGPti6wJW6WbtcrpT+fDt+kWACud49OycZu2GD5fOKW4fnJzSoNER98RbHrmNITMPfjqR9OmEX4SRBF4aOqE+gxJsEP1d4cOXPhxN6cOmFsMZJRxrNT7h91EDT6ifS45fXs/H9JEEUXSG8Sj5RnbJHY7IItbUc5yXkOx6jpbObDRILCSAmXqWpWtOPihI7jpqj7wOQXcYKaHyAGs/tqe1K9XVRetg5FzwQvkWxzN2alUBNgDPxQynxonPdCWv8FFZqV0Wfm+rccD+0w+3L1BkOdCAUXEOh4dvgQf9Z2Waik9y9vE6ro9dTzr1kjEL/WHDfmAE3IfmP3s+O+cI7/b6g8+BGm0n6am098WhrZ2PP+IwIejaTM/7xvucKloR42V09177wFjmWBbsHwV6KC26wMazQuK7u0eRfkwr8HUCiv3pgG43GyA29PH+19G2bURVc2jYOgU1bHBvrqh1M6l5kOMVJFpnaLLbWDjVQKd9zpu97eur5Gn82w18ZcWcMKYqIa/egl+dBBzYUoT1yBqpwhe31OeXZ4pTclwJd3A1ClDKjrC8YbCOBu2l1Hl7JbQFTo+WV/vWmTYirpKd7Y3ipyLG4mXT6rj+ZdRf2XGkjFTvDzUeLiaHhTNUhrNgAlR8+gLaJmE+d+2I8CQ//Y7X57qWBacoRXcvpxTPNDAcu/6G9HGsiEo9A97BidrxxniRLcUsTYZwQZOKYCLR64QTEOF5XuNxEe2fnaldA/dEO3nTFXvPjD9ssDmeDwA4DxETt6vZeWnzjTfV3Hkab9wd48R4NvvbDOBDUwPXNHPbLuHBLbG9hq/39dXKqMCBMeBt2h6xuNBaRbv9ya6g02zZVRpsFisEl+pz5SLhTF3Mz++cgzvm4moCEOJbkr+gvxB3aIl7oPRZW3j7+8W60mTYG4u/w3hwa88VwlkdPgg5OmHljCxZ7sPVzd+uvrD7ZdpfxfTzk/4UN/oLHWtjYP+jp8zpir7x5Luw1GE6LrCsGTGEDdBfZ0UArSt4/mQufif3ftQi9W14c55vJzT9PjGg9FxHgs1z3TYYnCJVSbSxXVYTvdSce/Y/tvZOAXfi3HTsHe6DH62/c+beZ3nb9s6VnemQF6quu+0AYMKeNmrxWYahZpAYDa2ieXDHVmWI36bWpSZiM9JRmPgvRi3r8W4dUjroph/AZRQCl4Vnozu8a79mIpkUnjZdA/mZ0TTuKmm37fBk34N5uNt8k/WxsdUHmmnskMvWBylw8ctvAMZ9B2EW9AL02VB6SShiFZRZpU8nOAJWbz/lAfB4UxjyM7WFU0qD8edDW0IBnryaO34gkyMlgOuNOGCFjlGmZGTJuIOM+WceCSOIOCOdug5YaAJ/7T/pH2OT+PjshwcxNPKugGXBZtqz7sRz2K2fhAQBKAePr7bynaGe9HhPmc936ufhJPR4jtCgAK5CnuD8KJvSFi4rOAFf+u/iSO86mzx4OVVkauzTh8k1+DViHOXQcLCLN1lk1eCzMpQzBvWjPSdSqJBmYHfbkNTGMRDA+1fLeOm4M/b8N1ojPJbet+hsv60LXyAB1DA41dzlX5arJJCqBjWgl+hNURPZyDL89s2ECBqb3ZqIgbfcu9IFxs/P9p4TZY4bpRx+NMMRkuvGD8+FhDMqh1aKE35qLX2aOOCbj66aBwsUKch+Js9Q5M36BEPepyV4CMfAYJy+lKnWuSntePdhUb/2c9J488zHwWRR6/M4pagmuuRU5xCG/a0Q+nICzo53tE19tQjM6OT4pa2OYdyRE4sYsBIET0nHOmET/R0ROfzX62c3Lp9WuhBdJI6l3nv0t3s634mCxkIJKUeCZfCfsTN2FfNB5F3hABxxN5Qo0coz0SlIVzntqG0WyO8Uab5B56MLo/WBi/1Re9VeyybS9ZJ54pMcx8z3P+s9+iMPWd/4xgIQUjz0LQlu+vPVa841WEDhsw5491CEY6nn+babxjuD098EuSInutvGCt/jW68wfF3DMPd0+MUWQ2aHXT4GBR76Yp3f8R+vAM1n4By+9Pgk67Fn6BLMDe7jRB9dlookmRz35oiPPxPolqnQKCcgElC6E8RqKzJ+bZ5UZgwQQDKCZgkCIIAmCVAEAJgkiAIAk1AukxsA0tuVcBLVICXqAAvFQGuQU5ykpwfPbLJ4Qg5fh8vSbzXmAsJk2XYC58XZX03dOPvCTzkAwMKyzBU/oY/HrZhGLChArY9IeIbXdyo4fiLDk64SNg4w3cxjjtuozt/fRKWphccroK7dth+a8vbpB/rOSjNYg/fLlHy91bGqNuG56RM3Os7pOkf2GNT+XCBa1qj5YAXOmHohA5GTx5JERMlFBb0pLjnPSI9cHmHayI+C7UETR1XT3BZcKrj49cRv3P2aX/akWNdWIpFTY2q9a9wPR5ppmA4Q9DrhnoSQwzGlZ6oJi7h9Q8qxvfvWxmMTmngHYxS4V2zw4nOGiQ30ETfK61mzTfXPPMMxenbppyR58iM+hrylnb3uFbgHSZy7teTLzRl7khgbES0QmraxWEfIVKFv18YclCn/6eRjgnbGolNmZchHDqP2OZ1zqgoVT0oWtWStntMkPMqjRC4Bz7LBdvzc2koaOh7JESz3EvS1NEnyYiVFrfvLVcB7dJLi1HI7mme94jqI+xZPNU2aic7ZrOqRn2uNrC+A7oxPUdRfkz4iIrthavLPlFke1qmpWLTBtGcITIudwY5Sma0hrDM1OQOMOJkuBMMlTJ3qOVGfFLhlNWQtECOSnes5UVU9OxOtfwVA725i1puxUwHVJyi7c5iKqqAZCopQiOPmPqhuTBTZScz71LWi3OsV1PIJCluEZdBeVjbI6BFh9JY9Y+8aLdBSBEYExgn+FvjycGoGKEO7eBV2+s9Hk9Y0cBAuACxhgsUkhztIqqwpx6LO+kSFb1ZShuF/iSzJL3qtPLA7mIEDau15mXS1LErCglMkcVwD6Pc8+ISFbTFSnsAjjsxNc4qdVNdQ579aCjPaZc7fIBPhNrX7d8Jy62DpP2lY4ZLMGDwKpcLgy/5VF/2Sf8DYyX3o10htGuPwhBoprOKSJ8KCaTv9mc+5XgkZDrsOYWNir7B8Y3MtwRL84cccc7oOQdsQetAsLO3S7HpbYqZBLBecY+EO9RyIz6pdMpqSFogR8/uWMuLqOjNnWr5KwY6uItabsWMvchRQTI6Yngqm+I0MpJeHkr47cDKsLo83ppobHXI2plqt5QUaH8rFhq3m1Z0XXwNW29a4o8ekgj2F01ozYfNUlSMeC9NzG/FQlVQ23qBgWyO4ogcZsqY2O/+zgDRDKjC5FZcWhA4htOszK6WIE0EOAL8vkn90N1QI7i5mO81pRjXytvLFrXno/azrlAbXtrstIlOH74nqo+l3e/T5we8gqxgQ/5uultye8f5M9bOMGkrXVx0fz1bfBO0/lm48JbIWoCJyTKdg1l5sd5Zq0yDn9LmdCxpzLwH0BnQpRglwqPjkiJEWF2u1AC1cdVpLvPCCZzMIszlmbHd1BoVQRkCrtYyc4kVEVAeHfdYi0Tm2EHVDRG4qovNss5f4WA64YU+H3IN4N61uGYTLJ/x49WR1ac4dWpd8Ipp3f0nK1h4X9ZisFcvw7UcGtnsGFrxrFeiVHTal2jdgcTJcN0Fme2JXVngg0zxb6pKfoBMs0nomS9ATGlVveevVTcG8dTi+pDsNXvUVUViOeIyybpQErLgQ1OWpGl+xCRPa+p0XCl1qAw9tkBgCBrg0QyLDbHojLgdTR7W9YpVkLeBQbWL2SJbhaeAi+RIlpe1irSPibKP6BjzJmcu6I5iyRLTle79gZRZ69uV5ZnkO+BKBcBRU7o5CBw4j4c+uDR0ZYXzkf0Mr8tsIXcIKKoP2QhWcTp03RhmGKOG26enXLaWcdRZH8VcrY4R7BZ0oBSTSlUZpddRUqrCYr1v6qAEpPtuhnZnzQvgVIoEFsvv9wntQmHTAWu7rdniwEaXO6y8A+mrqUcRYLrKVBwlde56pgB8DHM7mBGgAhxQ0ntYcR8xfF5glvseX6hlg5+or5Aa9CA+xWxyR60O+AUdGSfZqFiJ14JRVgNTyep0EfcZnwyVLbTCtuP9odBI3paKhQBMF6UG4V1gvAWg2G/T8HtD1Mfmh0i3myRsSAHg6ceETWdr5aWgqpwyu2LKidpMSRlnpJ52eyq1pnrfzjireS6ZKNhrLHJ6u8ZSnI/YqKZbJ18go2JofFt9xxunFs/z3eNqQ5ZYOX2cqGA7FBu2jGZ2TjWxH1LrE6o4ryDwlqETu6E9vuabV4vGryWJRgxyv8fDuLpjAi9zdWUko+TaIxFVlDR688xnyt1ynEfEfTsV2shjj0dMjmD4gTAy2mHhpT0Bm37/YmxPg4tV1M6YRnARq23HMY9PwNIiUrssUkVxeXlViY4xXg0U0YEe2WzpQXX1zpkqzUxCqE/72IDNpgsnRa3tgZuq3vrTIB4WacFDzC5o3+SK9opBMaJm0p6mNbws63wZl1ui/2HpDNrHpTzj44bvgoLjSANTplxtLiAbbwNJBFec6VTEKRTyfBsQ0d4KWb41Et0WOU5B8rBTKkN5ZIZclDlIXpShImdXGCbZeYNW97do2Z2S1acIFCbRmoNLK06qAJm0BO032EgtYr8FEs93r9++tXAtMYKxKYvxINwZLqJRni77QAkCUH1rJsMDdpsYQdD6Phxx/nCqQSTEz4AdtR3efRNo4c1x3bzRdXp9LGskYVJI+U580TB7lOU/147ey0mSjmNFwgcktDg2mr9bKkX5NHsbQKYAz0d51Q5i9Olwqm55FyUKudziTPv5Qgtsr+k3pvCqQMmt6Jbqaei42bjWlCYq5jom0js8dN8WW+O/H8ohtTfzLO/kHndVXYfIyrc4imRPKpUHjcV82s8afh0f2p4Fz3+1/bfpjpI72eu5SN7/oFM+KUsqS797v/oMuUm9fFF8H2/q0stpws4pztYtiUQSgHBipRAnJYKHfPpV/xQRIRHKtuLpImR5buWFTJG4JeICa6kfMVCK79v9PPIBET2Pod6fzkzt10pdXDPYg/j6NVB2xXdrNN862YDx74OM2D60/sb2v35P7jf9/Zji+L1P4t2V/B+lq5P/RVvGhUlmXdzRJDCZRaIVJjp/2y4TbB1D5yHohccissx4E839KKzH/itJnzyegmundZSDJGn/KF3ZrXo7bZOpJlm0o8SNSl9k9v7PIt3pkhd7Cvp06YGEpdvgRriFX14ZSoCVckr4YHAPAiQxBe0CJycwV79dV+jPsxS9mkOShRZUskh0AL5eoTCapdGLOVuhPAYbHBpQDepeUCga9U+kCwXSRWloIL/krbpp6iAu9IurRzlMCn8GpOC3/0xhqDA9crXwjo97CVSEbjIMjv1dP1wdB/2Gwm/O+mbHSMVs1pzneDhKo5HPIusPAwU0kIcK3QOl4BE4A6u+Es5DR6XXqSLrpiS74aI3nWu8Eiph84orL6IUbKqsUEkxJfhMB7eYBqCw7jhd5xLjZ+OrmruU6t9QwmHpSMcANqbf2HmZgT8MM36Fj35D6cSaZYjC5d4+boPH4qgWfJXkOcyG4wly29nLbWkqKo4CEwdbqu1xcQOcveGKeTyxh81UPfvI+m0u99nKKrBg81BsVaaXaUSVEo6MZcbOZ1j5B5FMw/yABllDAgalUSQ/ppcIYyW4S6VMMXmJm3vXfOKzwC6RZ0PMOo8lxqmw9hSlNN0sUHSgP3yDiOQJCX1dJuEkfDFTkNMBqVq/cyUMgnsfMQjV02YWOK8KdWaut8JD0ACoH5lBvfbrOs/sljC9xVW05aWA8GrKBIY7GTcOtVPz/wAIiglvJ+XD/gJ7rd3sRtS1g9e4pdHdKSE2SCSs3CIjypBTiw1TZ60eaZ1EVo4JPBOxV3k5D0W6bGhXmbW/oNiObsekRQQg7AzYG9BTuNkqs2d5JMuRO0OQmOTGynKUGMAhwHW0eqVdQbwE9wHxJ69fTYoI8DNrvmPzs8pfsTE8fTKzWfEk1vaX9O2GmqJ8rjKRZh0Pxu9/wmRhuNZqwvEMkR81LR1PoDr4SaUp/A17kmRpS4DWS2fpgR3Shjm7dO+AxeXm7lCiSqST+snpHLSt/q99R9QI141rj5QL06id/zKRVYTyEZCMTzV9MTjO8wRoLYpHtQQOowetcArfIfWgQ2xhmEJCxCCJIRIihiVEvpJEXf+cPhcKqhAVa7NeNSjgHFA/rrr4zPUosuvLFjtNH14JUfBeetn64gQ+bXDJ8vzgBDxBceQo7m6vf4plhY1paffwuAEYPchCqir/E7VzePFf3xQkcae13BYWmeW7VoCGTbnmzD4dK+0Mbt6TLfFcGuwXUEg3Iyq9XFLDKEMa7VrgbsSKkiCiTV6ZWTF3Zu02+TqLdEKz4wMfq6aSPsUlPlZ1Xs/BAftz+nzAxp1J2buOInc6iRUCXSuDNsgqAfFwq2yej78TBxVz2LIFhjRAbBA9rtGcoZcEjxPzpIdx6nurIhYfy6IBq8VBOrSooJcBPswZE+z/wfrJWsEzFufd6RxdlIIdBgqy7dQ+/r+XFFFBiujptApEu6HlHUQSB7Wl0NqIvTaiJIUYbyTE8FLNjEmrQfYFWdkuEYGVrX93Y5nMOkRWvDpoJ3HKRy2P1v8vjdXKavQNBDIr5k+V/2riXjc0vm+8PslEA/6OamJQW8wJhxqO64S5R3L85oxQZQLokIiUnYzbDWZrl68eM9toZPSDhf2Zvciw7dCCOWNHEc2aHi9moRbfvnNMnN173NtefASopSBNoBcxgO3aVxsADKG1rG1ik22cla3Q9dCV2KDDBCS3BKtoRo7OnLj873QUedBJqR3JtZSoLELCx8KhDjTSvJ5GS0q6oaLUzdBYkGiSaoPmn4Hva0rCbo8N+lYHeD6Q3ugSok6TYgoJRTw+HmoMy6EpqfUvwo03GahrW2DWSBNcbTwZu1av+t/RR3/PMPlAOkxVoa4XBzaj0aJAKynAdSkb0bSfby6X5mvuUSUpLtKjDJd7GhIAgTNOwYp0PZJ49YsUH5AhK0tJS6waAdHl+mpMdiGLCpp648Ed+bYeXb8mknSBtzzR3PlzCtKuZUj1+9UR/QD8ywQ1hqFat3XLaZwHjHhgSSP5smc51zZWyv8DJGF/os7N3yWSM53ohJjSb6qwu4VyK/+eEwimvh5J2fVugzaKlpVgmRHA9TaC1xj3FXeuGtOCoDWyNByglicVXCgpEhUuKyz3v4ocpiipfT7SuKXyI5SGTneZIMbrOT0BRlhWWSoZdZG6rsl+DDAlHMOT9tw2MvudddwUQth2HXW2vZbm2qFaK5IhyrdlH7Mt95GBjrV38GASCugvMHyQBLIuiiGNSVof4OX9nOoRP1kTGYDTH4Izgj1TD+N/R7QEWMQdzFV1sCRHFyJrYNbXYvv0bMA5YzsibDryXPsO8RzkKHXIQez9Ev5MsYzMDySCBrXVQmkGcCwUK+dSEOgZ1vjOQBWgaCtROBdtRoJo0xz9VEsd1giBgospcIPRfaEyg/9hUP1yZdyOzWxy2720k0KCA3pAdctxLR2gYwHnPH5dxaqC0UqkAcKbJpib2VkbcDYe+cY5UIEhFaMvTSs6QfNp9+cCSWeuYZWpSS5CIZL+rt3gTxuwPHCvBytiyiorAcxgdWzwSHQK0IZFS6M9dmn1BOcXG+c6faoBIYEVRCaGcQnmvCMuVrpAR4RMi5WXK98XwoqFQdyEUAykwsW7Z/mRXEQroHJ8KvtMRerhLja0ih1zIhTO8n9TDAjG10JNt4NJCAkxAJHZv0vYi6yd9LR7pPEqkgjJuVs8GxDtnckTC1iG1hzIHQQJYU0XXwE0yHaDG9cy6YdscHHujPQxpALa+yqUsEAHUqxLpOeAWOwsnXs8mmcL6vPjflXzP2OUzu1cO2gscqO6oudSlGmwBJZgiIUwA46TFCphQjF6vQzs0PE5Ub3VgS+MPJiaBCpVg31UJv4SesrdOy+oK89B9FJvI8GJGc1JQhRulu3Ia6TYbBMEpzh5p9E1DbpCqdiCtgXjQSTry92ebubIYhtztqi1mrcrZEJ7bvJ7463IaxLoEoQ+oFhDb9gTxObNGLge9H8bO+PAa1JiblFcKjY1zvVC1qgcEyjWoSXm3t4wLgY13cOlHhjccb2Ib80dk8u0ePM6i3PAPz0jsVXcFhBVByPFIFcFeC8jqm/6bY6gDXQSkQKLmdhmVWSvp0d3bx5ylFEnIag62vvpcGxb5h5hBVXlKdLPgsAebMnxwklDBrsfJb85Come8cEE90K0J/3A2j7+U59uat0MZpHR9OfNMNAjHarTbymzh5E450VsVH4MOEJS4ZbsrF8IHBa9qO0IIbRoNHIT31lGK6FuRFzBwojqtThiIZOd6/VGE647sEKIwwklMMcWi4VQhB/paPebCOqPnCUgHoTLKb0x05ZVAb4FTrMkrw80BU4JW8dSoRXeB4o3hU2mkjkx1o2V1aS4g4162pTR3hcNbBxu7Muqn7Ujc5zX7OAQfORUHzs3wTw0v6wGr4ucigB0TWgHujQadsK0zq5l2wjvfZPvDcYY2UmIWVCLsHRigivJpwR8CqmBxNJGxoMI1w+J/4/bUH9Cx4wTPHO8pAqejYotcWrWR34INO7sL9LfWFFG0x0Zb2DZKxiNI0/5FhimK9Es/bZzVvKTr4y9rehGUBROp+sv8MpLgpnLFdTtSDXqR59zJCheRDHCUO6CPVSy2nM/u7wuo+5RKaVFFG/LeGom/rNo2dWBWsxYJHDKEASuZqaNqpqBAQOpmwlW+09Yngqa3y+Sa1GfmTIx2U+wneAYriNY6vkrpjj0tM415RnztHPVICKpAc2xfhDrKAq3A/K8zqAGF9K4JQmknI0xuttbV5VJS9l8zAbrTn1lKyD8TLHoqd0iDFgS8yyVoLql11NNV4jpv/eXHwjBQh9j6wvpDOsv+ihFLHb66C4UEkq6wMpq3wFStX32ajA2viDIKtCkNPYLV03habQ1BFH12foZjHEZWqhVnm63eJovJrozYhascj3ZNDvj3wnKnJFkKLSn7EgajEKf0r9L3FgNjCfDoHj9zBXBMy2CdQ/gP/2Sy5wUy4MZtW85OBTZr7EBHwjvpDG9phIcjV0hA7zVv8lEFTS882a52EeCkZCIoZRS0GkeCDVntamZg1Ner4YAU0pISwSAY2KmIY3muuImqLiPhXEeaR7jpqoTDFg5Kk1ZBW44q3bpEf60CiK8RZksXzZvjY9JxxoBpWqYKOSj1C2YNUaDJNKV2k5FyeJEeFWnPGX0FHWUiQLSNp0SYDhg4g873i9CmLARLREEdyZYv633xx8fc/mbmBCUtAvR86l4k0hxahxiO14wVAIAnqV0KlIrvsrT8u/vMu2CcsnDVGBvQfKSnJHUHbsctmcpHJbA2vz59gr3IDlCTK5TkIHGm7FghbUScB+n8k31n6Z9mcX6aBTfLqdRDlOUYwZuZTGzZJU7HRd4YYQ4vztovOezLAxoZMR9pSiyERx1bjf7gtxgcWImgXHBZu6MRyC6Eaq88wbstDU5KY9qLQgIuIYF5wdWjaB1eb0b20tLsUJHwdwb/JwpDlMZnkbnIJHeXfqo1DTHhQegNh7OZw4xoq/sJ/jSCQnD4tlZ8bO7T2+d+8RCuSOyihoXAmhz8rsBKMIcwSkPy0cVlWmU0ns60/q8ntMwXZ/qCVjQnwBPXT6gmkGEAfLqcksLojuE4rPZl38vNhKNxSmp8ExNpPJTVb2q7YxrKD4Bkjy9YGMsSETlogGwBkNrts/BbPxhbC3IGuCpKO7vgqTBFVLZ0F2/GbkLhS+LLyNLuR+rDSCMNTnxR2OOpwFqyyOkU6lRQjjGDZ6PbvhOtOEYNV8Tix8ey/Vi/G/y9vfR6PyNzd9JAPTcxGCTfaSMOxBrYXDhwRLIggQbqJu3F4CK6t58MKU+o6npVlF89fOadm6BYl9gKCUMYABT5W/NIC0cU9ztaRB2kT4YVcrHeOrja39kNW0HA5g6egQGqDwnuGdNov0hXiavjH34c7vDqZqGEN7dUdPTzPQ247VFx8gke2xEUqcKadTVJUIu/Pk3vu6Qp2a9m015ECk3WDlKq5YdkQjBRWjTmLYvce458vwh4Eil9N0kk67c+eD8Q3BsRVPxgTZfw5kJlhQLC7GLeRqINanrMX7kw2PRj62YDXjltltLQFNs/QbFkvILgGO8YGANVXza4Etp/TNHovpdhTrMoeZVbPqlgW1o1dSmDX/zizGoBC47yjSePjSE59b1gL+a63wbFod5vD5R+hX7TfIRgdIgxibtb7UvyzM+Wt64cDFYsgImYMhrRQP+Q0MhfcGpK/WTBjpZOI9tb66moUy9aG1szbL6q47BY2m2njud74eJ1rkwrZPzmbTREgL5gb977gFUbmkCf8F/jIo8Gfk+tw3G51IQSBK1awjSeEt5LjZ//rdMTRLILAcWnNld0v81/cMS0EGAbtIaUSXS7KbkajFse50dllmiMd+esr+Nsan/lWaS15WcUsxGke44p0Otc+Pi3IbrGixRxkajGJ4CY8PoyrhNBzFktK9GfjJTIOj4BeihCvDTPu2QR3vj5/xnw6+4ua+W37707mf9gVDu9WmexVSNQcXyS502v1EziCsBAY7YALovuTBOLipg6gcjpTfgC/vVMB80WAamlGseiW7QPODV5khaEvQeVMJpvEOGpnViplIsUD6uW8FIWlsiXNNV/JJNnYHFhuXneqk8S+qDVzUf8pDyisGz8BiPXMLL+OeQQPJhEUDeSUs9yhtHHDceLcXLnr2fTxjmdueFhL3G3YImFcbO7ecAN7q0b1yAjxYWQ3ZDY8X69pbljOYn1zJnlrtDkwWg1U+6xb23TOLQaHC9kUcQo65xtdhCZFTeMZ/Kv7H1m7vYiiT5nj0RsrWjL9x4BhvoN548NkHuSz/Ew4u2CRCESyDRRqT4vM4x+OKSBe2dTiULtafNX5h7LtphamQPhzl6Ihruyh8Oht2z9J3aybF3d1jO046ruVPsx4mnIHv4o/f2gVQxTNvreQV4tymW43QEQT/BN89CJVhA9048oEAdSuw1LtEfyrkrmpTvnIYhts6IBFW+wFpvNakxtmPKCuLXBSMEewgns0gDa16kxHPZi8MW6CxuzYD16oE2vg73w1QUcqIX5+ziiJQqWaQXfE4jKr4+tKJwjlgyJy1BdGIySy6cHxVFGc/9+5OMjs/ZHlmHgn7n5DbE9zRDdFkDNX2MixJlz8dCLpLAOWTQsadPmmREAynWX7Rq7CvLCnULmJb8COf2hnnItkZc21nupUMSgvcoF2GtAiE/ECRPnjjDp20W1M7W6LwDvjw963ozYNABCILRSoAtZKcebGDnLOfNTzp9ht3kOJNdWCu6cDpY5hzs3w5KmedPAQfjVjqldMMnGdL6/AN22vP7rdb7E5rCwtkQktjhJe6eRgsO/YsPgpzGSOI4z/f4N/OQRuIQd0SMcO8Cd2wfTrRnt+VR48/tbL79csIOONLXspii95+HeeZknpx8mZChfl/unKVuM/x7xdpUhTX5B5bcHLVwRxlMjMHBNx9LGq3U2E6JP2D8IbyQaAA/4mWL3E+UrKjkJT53mdPrTknXJuwXejJbw9HPm4gQO615givgM/9w6FRkWbxbKhnPCB1rnpMgA+yFcuILyoUVcm5KuKlkE/fwXuOeccv3tjf867jwqvN1Kd6S09t0EMLdMk9yzc4Z7cox2E4ZOPEfQy+BLXD35yMcToQb/z1+2bbOcd52aGUq4du4rkTCRjYGEcKS10C3zohgmQz9F4faesjDxOZe9YKCzhpjinRYiUb86U0vc2zYjLMLeK6rPWefAystU2kpubkrxmwJfH7zIOmbjCRrGk8PN0Kt2VG0/azjv5r++ZCoagqFdKmsvC0wLiPMF0RvUa5kCdGfRdrBOqmRERt8adSjNibLJ4eJerL5Q7t/NHXzzldmbwCFjwU2WJpxB4YPwS0TetbQVsFIkPti5IY43xixiczexYxaS41DEWwQn8kzH6+mQ3zs1P2IddliYe6sXRflbiesquDMwtJwmyf0AbC824DgMuadDBMjLihtfnicfJYRegZ8R4ZORmpk/uT1c6YRQ6my8gTqj6l+4oOSxWt+igYhXLAsqAcTmjXWIajW8jyxoDDNgRdM6ADOqD0zyzvlkSI9JCrdUINKccpyWuKSfRRvfRalnf9CA+/YR/Az8FIHndJAvQIq42YCXNyTM1zqP3Zr9stl2pFR0doh7pd1AlIgW7FNAZumPsiNppEc/BPSCYK60lEaDwN1bYhTHyWZSgVuiza7vHbqUdrGUuqq7tyOOVrYZkLu2R5hBTvrUzvTE5Gidpmcgauus9NjZWunvsWLN7OcUDzzMiCgZoAi7yVkEQSKXGIQWsjxF2OKYsrqB+va3GpfyOaUZkKiH1oqi3N3EKU1TR7ZyNyLj9Iw+sX4V5r/eK39l1t4WFgU7wGKxb4yd9dLIRTFWBSScGJZhpo0gxByhOokAVfxhWUjxeLAX1RTEvLKiMuCe8TMquTc6bS6WmxQ84vWzhplPFnS4mDfJdrGLzRrnpUf0mosZIQUsgibLN1WFUOi+ijLonXioLZVu407NmdBWWOIJEtFTQzQ1t7UnqZ1dpVE0uP0i8YW3nackrx6S9pmIWlWttdedfylWmGGsXm0ewhPG9Lmrb24V8q8dMs1CVsyEzA4nSFvpNUiLMqf69DZYtUHW8E+ENGBWMOmsRRLCs3Swpv8IUXlBh00zeowPn3aQeHLx2AZ4Q9JzMIlJgtG9rzM5g4m5wBQp9VP7Z2GeYUyAlGz367VOr7wKp3M3QkchxbU9kPIKGVs6qXniDebB1vp6qoX2keRbbvfEWzEVukRE9Tj1aFB3qGwW/YPA+D0duEPN/KFmDvNuqXlv2ZY8SwMLnUvquSUvka5nRRWmjMDUp0BfdxOiosmAltjd6H2LLvDiqQC1/owHccl70DY/GOApi4NvT8OJTzY7WiYVthcPrjrA+IPvQlU875s4QKES7n/zsn+x14eH499/w/QYD0m+YTYUMfpgTXxzywcKuJy/2lnGT7ZIkf7H8cWGRS3pzWGnYRiHfZtQ9ml3Z213brkeE+fDHccavR/SvgiZ+0GiXiEq6ffG9WhjMlga4H8FVCFMiVCx44tkVmWgu6cSUNNRTbbo2ENujjfr4K34moJgburcw0viTtt47jJ+Ohvutcayu58VXAn8ljpeTLMAUHeFEMWoREos/LzH2niT9xWLOTNbdBgdy8f4cmtcpgCe3qnu5XK7RIXWSx5c3492kWeBmSgLWhGQIVaD0jQ2o1ZcFAcdAggULARNCNpK/yQ0aBh4j+fyd2/s9ZZeis3URSAnoo0VE7ChqAmyYxpxfATp/VqahTAuyZzKB2HTsy19uxU/R8As5RgjdO0/UJEKqELtrOCZRf2CdNx+3GvxxD5ZHPHW4kxU7u3Ev4soFTIPW+pSEHYFzY063ksV633LF8Vd3lSuOhjVMidWmKTZGbfM05to18WjF+CzXKGSppyvh2KEhPaRaPF4WQ7+jecoCmB+fSadvEWadwDmCQLHyToKX2xDcr7NG+4PCPiKaIsVQaAjnVQYmWDCqKq8ONjayMTynWCzIZtyGdiNcQ3KUTfE9VkK9YTOZxXW7Nj9+OMeMxcPtng8aCIU5odvpKNoxcYWuwF9VdFypJ8UZTzXJ+FKB4jtRwIEsU3OBIcq3MRamvHlo+mbpRjL8cZfEyVTzZ2qBwbaMvHoeujYLU33c0KJrhF9eSPcLYYgaMwJuA68LvLqAz/vPNVQEhkAjOfXiN9jkaY+MXMAc1qp5/uJOTNb9WF5MhfX3IN4ZEn99+wxl+Znijdsht/yPOqiOILYX5xzN/VLNnmwc0NWdplKDOHojEl+D/TMt+TmTjlPsyJPt+C+WtqwnzQsiH9sljpTen8S3lgwZC/h/lpjoR3N0UTmtumKkWbz7QjYI42hvrTTE38d4LV/Pz/ZOuwkePd2QxIyxu79fpNVmWKs5wyT5ta58gFWEdUAy4+JyhNM+4YzD1SD8FMz0hFyNjQwhY3HiyHRAkWSbnkifeCWyQ5oRsBzBwzWDejkFag/fnLNC+Dq6bH7QQYaUehG6x144DP6gxPUuFgSkcp1guLzUCsCU0yap7+EzoYt69xEXGVNKw6kQoevjiLzh5kI1GJla8eI4gNbftzw0Y8K6Ph318pFlFD+y2u4Iv1HG1DSS8y9JTBIu+03z8RLayruW3YwWhQJPbqBwYX+d1UXZgDQd+9ciGQQTYh5grvgC4+Y0xRHi19PlpglVlq+GErwy/BmAOyVzbYQmjbCc3n8l8GDbKFZryIjiEA6pEtt/EDj/h5MVWI6XHVlv4vjJeFAXYB+ndpytdTLgRwIdTq6J+ka2heFsbpferCdOT8eCnCKyIfRXy4UFppGf+BVf0ccxePzB2IjSyqUDD19eXiUBhJ9PcWhTvsgAgut77tpTGEdR5zHVe7aJWPcxUuAB2ZVoaCKDwPS89fRygu2rfvjOs70Uhy6MbQOF5oLTS4q2b8AdArTDIdQE8epW4wz06G+fsw9EqGTA+HryaTQKx9aFIy2nopH5b73jf7xKOgKFiQSSZOyhqkmDR1JaTOK0r5vZWJthhGxqsF1Tc4GNtrY+qctTRWPCyO2bfRYCfUOTiaCCWitUWTRpV1VnWWCLfjwkQAyeBRFLb9Cd2W4rZDq7XADTcYKSJqdeDWD5FJwDvbs6cY7AKUOYghgiroxPSK8J9GFDBnBLnclN7a9fLvmfTs7coQNp7rUp1mL4WkEIulNcU0Zs2UFhSnV6sBgMgWAmcMEH5b6b8SEDUtUBe3HKQmgdGTzwAZjBdglwBH/ZuGnPC/Fd4DMJWASRN6hTVDdDVu8iLIhdqL4w0Ae6++Hr7H768qD4dTdbHw8npId2GKe+VMsTe99ZaJu3x3PCMwouURofrxJwKLQzyRCgFtgoxlhdwU4YR1ot5uAJKu68eH69+fzrR3L7L4T1XtmMYsE6Hwp7lmkEpjOoDSMYLEOUurf6GEg/SVceCwF18ZrHGCLOwnbPQGHT6vXkYTthYRJfd7WkGa8s5KVFt3uFnFaDVbaxDtXHuzB0YzttYiYZcKkoal2cvEZt853oaaN8LeMVJNiNyBNi0M6so/9UPUg2qt1OiXWv2U172OWmrUnSbdKuhGkSIt9a0Vc2kJXaUKoaXLoqSXkhQeFgH/KrhVClIie90+wprgyU2oiSXzrBP8+WRZKrEi7RSSSyYTRnMczeHN0ZqjsZjaYmgxucWYKWoKQs0IKWm0TJ576X8Fsk3Ud+RIcTQXnqU+K9XsihLQfh3Nn7QVU7LuOxhSgwU6hGRuBhQD+4cC8+eWxigjiTsc+PVXM2K/D/4zziARfM5xCDSj//qBPyRb+j9bRt9Mjfh4LxU868KV9eI+4f/60f6RuKZSbIpQIOFSQUgbT3KLZP7jTVfQcdWR92YQDzZRSdihf3BYDp0SYWlaA5dSlGrPFuoyVa73ywfG7appqo1gir9Zv4tfF6aDhF4Z6xIBEcZcM481s63Jn5qAxrlktOcRNsiFYxrrYvGJnt329B7j57oxa3InjtfJEmBY7N60SvlPcyD+rqh7sIpMfEPjjt8lTH3H3WpwfEvSQb0TdgInjVaUDPpyF/x03A95j6+WB2x5e67ovMZnLnqtdmZSJlw1itzjlAwS673zME+x1dgzdNsQORaA8bE28l1JJzEC+7Oi3IO+TM2EEvbir0rAe8JSa66rJQejZd/KrpMQXrDZoJMoLR1PNJaA2Lq117SEJSWl67OBLb5ghsAXcffczwmHKJFEsZf+9pCwRO3Lz1UEVhHz41v8uZdNB6awJSRaZM1w3Dta41Sh1ni0IjSffGHhkpuRqD55zXrfsLTk59syycruZyo1PkQt5Nyrq5hBlBcDAdwgjR8QD/hFR9mkY92pPL8dRqYuJc+gHOQtNrnwce+TSIphGYw1VFFE0fMM2dmBb8VwqI0yon5ChcqKFiz2zQCA58Gaj+oyRSuA5qDH1QFvkQFP6i4cxQ/y7tCyMfTl9JfBhdEbx79pQect+DwEz1NVNIjoRfjaEg5LB+GPaWTT6bsCjv1t87godeON3SPT0J1Gabf+JHhvSLUh1F2OadckCsc9yCMsiPddU+u8RYi2F0kq9zApvHY+svUWISrS0PpaepvfzzzPXrgzqTtHUiUp3VJWuidtlf/Q68uARrrh741ZyEXDzbfUIJezsSpvZpOkUYK+XDwDamafPCoVez2nZDURmQk/yVYjovYiXKPqldEYPbcUT0ioNMSMRd7F7BDzWVamGDAt5DtsQ98bFO+Q8Ij5TIIEwPW2lNRM41CcuHLXpaQDtnHQD3WFhRu7ox5+Ue+F4+ZOTE8mpJOI+njylMCQd5nK7A98fBaFTPywIOQsNdBBnssk4hqndZTA3zmbyVkDfRUi3kChHFElDOdeqooEiooRhtUrAAjl3Ja4s18c72GF1eo3PnT5uSjhbSXdWPC5kbl0Q5PYdTtSMkL/6NxRG9w2+/VCepT3wD2++KnzHstrlSvpDdqVoeFkxuDdrtkXqI0MfE9CfcT0b7ckz34HSqLidduITCumu5WJRZAfd6Oyomk/AJNc91JI2g2TYdOYyEalOoJcTFVqR1Aj24vF2L5uCjHK5HBE4raazxSsDtXl3AYYmDHi0GOB8MR5DiVfO7WSY7GUZSagUi8pyEWKEc+v2+pSu0gYqrQpIONKrhNno9gkQzmranVDEWGDosB/OA3h9/qRCnas9kxaI2V4GaMM8RfgxGUEspPOw4+CKY7R4SmoZgZm8mT0BSJ7Il21H715DvItZ6thnODKdjCrieLRakfkajkGtz/U4EF/SqzmxBNHKnDhJIXItTnJkeQk51leTOq6lG2SphgF6i8Akd+9UtvH65x+vrib3Xmi18ENf69M8lAIwEEmOh5FnCkqQHomviYgwBoOdg/GOcTCO4ihIgivkHEc26KNAglPk7IzhOSAt/c7mG6JDnzch85Bi9sAyftKMzw6ZGmpGBkZ6kyuNOcUcKa+Fw6ONRL8N7AWk9twadxbVhhk4SwSOs6y0Y4W7OW07kXaehHMzQg1qYmI0HLxX1aqFEWll4nC01OeWpYJkwIFjeYESXPDsL24lPkMSbOc94XnmF9m1NRs78YzG9+t7dnjra2kFehsejpBEfxjIl8JBpKowVIpVOVdb6V1ePvMyXpSL43d6yo4ZGXJ8QJuFIzCdr3IqM1zT96o7l3pY4q3NO0S3ueHhsoWRg8rVrkfoWtuM2+MC3KL9cvK7U0t89898Hq4Fdu72DHwO18f3YyNW7Zev1nEt1jHCMpbkDk9jr9/irBHo01sVJTpbAuW/TUNfSn3HznexPDCdRrrwtdQxGR3cyMFrlhmyOeFXkdEll50uEk7RnBfqqRu/Wj3uh1b/ZF+Bcjfgt6ee9khD2y12BSRGazrVEX7ZuwKnWf78ugBNia3tRe0dP1+k5DZPvJ2ZhaGGONMd5nKPLpK0Zdn0suveccjSvduJvsp8DLZGh8pSrFYuPot1rSn6+oExq42HQ83NcXX1ZEO0goZMz2WJxfG9roi1FdAKpl6M0omw1Kw5wylh8D6aFCrKouCyAw9F3cyZ1TsN9t7yTzX9PGHd+b4zccarSRQGg/xkl6l4agQlxNFklfuxpWSyud0EOkU337JVKhi3x0jcVeWxx6S9m9AGKTJfrfb09MoyO0fiCxz3C9Jk5PrwjxUzebLET9uPNRpttQNwkql+NmOgbeqDVxgsxAbyzcMRTJ4ZKhzRMZDR6Z3jFGifLAf6qvOiAa3aLJ8SG++Dio8SRYpZQK+Ea3TVrrabZS5rwkoFW5Glh4Dq+b9YG6OABuRoE8rPFQ4oTDGirmoKUkNG5uI8LgMLooCz+YCueNf303fKK8XYjNr1HJh6zZEp5ERXaua+cDC/X6qL44OXf4sHUWAs2D3T7wREXkqx9m759tqS+Z8YgTCxHVXidLHxrSF0on8j4ThTmfqzvEK+Tx5Yiw+AD4Yay3mJ76Ke/bmQGP6Bx8PibrvcxXV+4+9DtdSbFbSmpujd7nLpPr+dk5Ded4AsINs/34ZK2F5rWNvltVWsgXjQM8v92Teh6zRPTBUpEbWFi18EVit5kekOus2fyZ7pAMiWLO0j9GQmhSNK21Itcj+shkWY8w/mbN95LWNg2rDtpPw9Oz1K8X9tQmp5BuYV3SHY8b2HHcS1d8ViV6vinFNkBQm1zgCvFZGZTK3pCYmXvlW6AuTjmqkvtZZ7ZoXtQMDroVFr2QiuURuqGpcp17ZOjpHa46PHLCr5rrSfQotERlUP39QiD4+XMWug8cXXaFUUoHFN3p6xSEoXOqnTCnVfoT0V2aGxc36F3w66/IE2tdtPOTh1VY6bIzcJX3+SUMs+znIJyENqzZ7m9Qs8NSqUkHDUC6Zu4E9Nd1sk3zHqfRRfNLErJ/H8TAcNP6KZVp3rIYnlmVcGV+XcZPw9EJPThq5J6eH8wQu8cSzhPyk/wxl4OnJ1Hn0O9Fb/kE08h6z/oqoHbpcJJWJxiD7WP1Vk5VS7rzavB72Q0Q/jY7p/dCIiRAbatsWPaWcYOfLkkRhCe3zY+Ik1OYv1bJzGjttJpUWH7e9X8a10J23Yd9J6I1yH7swrn2xqQTRbZRTxR9Q6bRBdG4FS4NUmiPg0NtpIq593AiKREeNcYASbdUJTlU3agzj9b1eSjXdBUun+dnthjtv6hwRavUfC7qx67wOb43M9er6tVdoodmbr0ArgqQ1VTdxfZ/LMm2xbvkQU5jmZWVWnPY21nkoVCOQ9qqDAG8iOvvuaTVUeBSN2FjMNEhDLWw2GwvQFs7Yosp8bXF7vY31TrQvx42Kc0oJlFpDKR8C1SZ8gj1nT242pM7gdrKW2Ky7/RKIjcxOh9vu9c6HTd8iIb1WnMUsUck1Wk+D15Bb58tirk8XdAMUvI6UIY457+wJL+oTv5uc2DQXPK+wJZYQcx+r/fuITcDbukTLaeOOvUGKMU/P+xpFQRu9GvaU7Tum+/v0vUkWrs+khVa5hB0/r/Gwe/EYFxNF63XTFxGWSow0RvaofTi5N8pK0DSm7L3IBPGq7PAVKUxVwKnwrFi7SRC5Q9B1ebUs2zesRnO52mJcOZN2Cc05PrugVTeQjrroBGTiwYn2ve//mW/Ycpo6Qc1Njie3ZGy9MYl7n3fl/A/kSuuTTEn342gn2vPgab6LnT4hMdGgeYXJ+5JkFuVeGZWjKl0NhdheQ2eSvFAZlm55/+MCK4t1TPaTsDXL53jWk1H2YOMLTDRZOKS4dOM4HiO8wZg5000aTmjQmJqi/iZhqdVCroysFmR1a6IyFM7c0BoZts1oDM/2cGGQiucInXUDO1a1jQ47Pl/ryQ2kGNoGHzZyZLHdE3QMbUUT2tbRlNNtiIz7ZnQKj0FPooFO/7uhfCiM6BBTbx7+B/Px0eh8KFxptNsvGqoApOklQZUO0w4JLBYLvAm41x2kXFEXBrVMEpVmHeUZJJRvVyg8J2ceyjONMOQxXaTrFs2PgBBdVw7qWKoJKhiaeeEFW4A1VNA/aGZWHfadFFYCLpGxInx9QfuGBpLgxvihkmS5SH+825Sd/uECuHv+HRuvcsGThJNA+VOKNDP2wmWceoPTr517Azwbp43caLdPALG2UTqMklKwXzi7NTSzaUeybjyuLDiiY6UQbxaM+rCwF13vVz7rPZ+cVQpMKaXyXIo7iq6VypUS8bCLoaETOVf0ykUUEteK0NGHuANRSf846C6Oe4KQefC3ZmCpoN4rSKHQanOaHrdmiF0KBCqsPF5YNCzFEZBR0XEQEUkAqpO+NrItQxHcjA19vLWxVaZj6BMWwBo4YIkNLDuHHg3JcXlBKAJ+x5URBJ33EnslPJLeSVIwHVV02WXW4Oz3tizclkkOjDkCI3Y3lP2cBvDoKI3qyh2iSvVY9NaOME4xTqM4zqlMp/u1IZGA3k10V0BXKPyFT5VM8PrM8vMEhxQ8fbmUschhBLA7P7QMDzpUh0oJOOor6lewgrEFbOE7QfXeFleoUXKzEs+jOX1m7KNMrVwhOjIXCnFA5UMr4OAGzYWxgWKxWzbCm8SZCIUWUpz5WQ+GK3F4FG3HsSHlH5rGnhN9sTO7J2mLpTjnyVWRcoC2xDQSNm7dq87unlkTVkkB4o9TID3X5omLqko9aUjYlXtXp3JtPTmaFaObIZdxnXVEIOT+95VvSfYPMsgd2lCAMZj13ByuRxUkdhD29mctMg7PmC7tjGy+83AqNOxu2aUrcd1NtzU1atczU0iKLF0SkwbRXsnN7fPk2WVSJuZSc/JYjOL9seVNez/3c446O8uCMJ/97nMw+rMnhcsZPgbT1tLo707WTj79IZ1qGad+ZFNA5d62Ta2X93T10VSKXvibpadM2oLDzIHrjGkAy6dwM9ag8Dx0A3M1Rv6m98VvYKrRGOW9Mteu0oG1o38kpzM2/PxfsPZPDnbuqQZtGysAj2Tcsr0518nUcEYp+n6eXguuzpzth8gceg6bhdMKWvzB02+TvMP4aA0bo7daXR9taHxk9IaLN8eJzOHtm2jhF/3czzRQJWr2vjao1vgIS3BuwupsyPgpxIH10RKf9IFe3uAuUxKxcRefhAnojMIqsO3AVHmId5XuRPAjs5swLS2K/n3SOONSfA2TsauVU0WJSeKO05kGPBJOK6ndnDvaKgY0V0sHe7+/rNrvu4lQ4iQxP3Dy3qQ0hcxS6cQ0isqVUJvML/Z5BNr+Ik61xtujuv7jSOlh4VNGb4EE9l/Bs5egI6nWp9fvRrQymjca6ucUw0Ts1cm9oMAO5cNam7ZjWBKBZuNtjY3TFek5ivRUlrdignD2jWCd6Zd22KyQfxGlN9GWASJ7rKvAXtl3UXUc/wIMaK5fzv2zLVf5uBWZZmKXwMiIft/AczJ0X4lMc8d01eKPITc0pQOSNhAlTblx5U1a+UFSU0/VHN4S/AVsH/6lPbVIyhzgr3lqPbI91t5D6fGb0fzDhsnVGHUS8q/kaZq6p0LBXu73+7XycNKF/HExmj7jE4qyC8I4Of1rRPyNXJLHScPJoboPm/M02iXH+EQcKbWfq+obOtkp14vdEEGxsG+llmp4fEk9osNqkUW6y2Oeyy/RM1eZynGU7b5bIdrJ5xq/fUOKv9OdMWLq4SXQZNEWvMejTcjQGMt5ZTPdU9jocvT7+FXXomRF72jm3G27jUy72PbaUSU3t4TwPpf1ucj697WNaIX0kiv3NCoxImfIatfFeUpLETg1kKWdwiaVEZVrs9OVLA51gZwmnigj/ip2/Ckl1PYBHnnyqxcm8FWZnlHe4VrEUzdgKoTxvo5i2Nl0WOEFIhqZU+mSok5BQkmErA5YmOrADgUBlVCnLdIjUDJMOoq7VFI9UIvr8epEz5iH9Dumq2MywOdmLZoIla8tsHcPCxBEjo43mdZ/i2bPxYMVI/Y7gdcOyMiauCUF21tATqjuK2AFugqpTWbSYh5dLrGCitVqAj7Wz7rU4nu1nNR9FmcvxLyQCtHIMyutq4I4MJq14KIiI6HRUaHB3Jk9QbIwW0JQT0cVlYcJxTJCJ8XarKeCURg3SiucdZwAH6e6cC/V9s6Gk9oogfnRU1FjSxa93j+LwrZRh8R0XgenzLzE/IjgI8eIlFBHv9HJMbiO8yypvne7uHmwgO220a6wOvGs8fBxjRamjWxNJ55eCK5QrSZ0SHULz+JxGnUY5A1tHK7w6eIiubshyf9J5utNI/pfEbQQrK39e6b5Fq+/UPH2L1PwmLf1+vv9V/i2fw+wLRts2YCNnp1fPa2fnP6ahiVwVIKPJTBx7/fH7edBqbsfo8jjHNwdbSkHN92sd/U5GdezbahAKg4ldqioM+xDyGCRNBnqVK/8eXMW7X0QFL9wxpX5mEJjSrhekskOUci+yMSH7fWCRPzEXM7qVXutQmgFOL4MckZSohCUJk7AYSoRwRbubZRkaRmYJYGeivTc0LIxJnX1Kr2HkU8ZmEifi9UleOFA/w4IwBF941Y1gk+F/6MNYj7sHnUgjm91TcG809CGIdJWBCyewlICn5UzZjYu/bgyOF9FMNzFxBuqQuQiVSWetu6JQ6Z+VVJeyAJRrzjuEB8pHYcUSb0JYzTKU50iZVVUVTLLHxc0W7PiRNTf3Gtxk8qBmjzfbn72U3pUciFF29quQ+7jmSAmEgkOVKfI5pRdK/vSJ57KrgQUCEuURjTgU3i0k7vWFNz/X55TAQitjTVjnxcQhbZHj1mxZwmll3trxxIdoDgzppPriJzAOZHDKtHES8O1C8Kb/uIoeN6G4793OP14opgGbz7tRbQFhHSymkpcqhw6CfSSiNNEwlKc93Tj5IVgTA5DpxaYJDkiQBWW1acR4r+pa+w3Zlqcf9cbxmElM5mURoRP7YWuqFKoWZ5HSjSaytQJynY9IVkEYZSEsGYD8+/GRvTXok1rkhzLKcdCzhxuJImpps24v81eRZkdAmxt+Qv9upR0XS+aP+gdls4UFaOJq2NuBhdhCEWtDHULi8CDPFFM5oKShwHijRbP/X0uix4YpGm/0800R4TG3YOqPZckOFuwgX1xlfgcFU5xZGiU0+7jxiXrH3TcMquQk0tGtyQ3FtY7ZuPsWfg0cjX8y1PtZRc94NM8YpxEm8exFvfKHNPA9vwk8g4lzGUXn+7NCnnik9uBOvbg9SNoC5gFdKsX2KuxPxvLSmn9jfx6eBzQODvsbPRzFIhwAlOqhrDJeBU4vgOgR4dvA91FVLaBGzM3vm6QXu4rtfaHbUUryY/m5oN4xX0qZivRD6SwKAMcx8w/darNdaLkG4+uFO3MJmDTyYxewXkKOmBLdWKL65OA9OLnF5HtLMTlcG0QEZluKlKFU8UkT41wzijEKgWJLRvsJyTBDG9owG15Qah0GRttfraxQEYYfYjsjL8xnA/+4pDF1sCantsT2Zd3bm5ld+AeTspWb3vbxzkbff3QbnJlJNSsWrE2cvtJW51rZSFr1ZFlcJwfD6ItbWwIlxS0xJVNxGjPDDG5vWwSxw2pG+0i0JZiqxHMWLIbwx2jFZM2/hL80KyMfnPXOATChvM0IEUFr8baPX5UFVFQiwgS5T0ocveEDC6vNkrhgdnnjmLjYGJRF4RW42bFKI/UrinRshBGYGIyaGuuBhA07OVRQf+Py60rH6KsjaT1YOK/gqOX2fB+6xfhVC36pbNPqd+Pap9K3ln1r2Lz8RAI2XghT/LZDbvn8FxOXtu78aqkTDj/Uj5zTSJYDEcBoTP0Pkq1WLjxO2PmhO7xA4UKCj+1Gi+ZxDQVLTabXpGg7e6G+1MKmb86/ZxkYvLNTMU9uHmvBnMif6+1Wtr5lFz2bZi3LwT0dKJIAhzUlWWVNtJXlSYBFieFO7ItsVufctEyjq+2KPXsqYzyPrbeOeN2WMTLptl1UjOHSsnKEBAEmCYFXcMlJ6Wt5BYTcmofbqv0filxCBA+SSazp+tJUV2i8ykpyNQ6TQSKpNf7UA593ez7NK6ZOFf4wlZ5TG30kW3+Klx4SbGTCpelwfwM6VkvPh0k20GOXmgrK3wp+5co8tCLXwzYiG4/fprebEyaFoPL63Ksvbh3R5yVPLbIlDNhOd00hAiNCbAgd+cR37HxpYNnLLE8wQjjk06vZtrJfYQvnXqnyQwnINtpnFK2EfBIstBq5hTUay7QWoin0FK7oqO/CCIFBikWynJye6zohsQnxQVXSfQuoFbR4QijNaCSkzc9BPDwdck8rSAprB3jmT7rsYBvqoSXC7ctIBKG1ySPDmic/LLNyBgj3AeWLAjDLP+AgD1amkPPa4RpqBMukYwrE7jJ+oDJqItc4/MzqlyhKaq/Y3uSkNJx4WSF6505l2MfnOO8P4rKT7XVd/yYjn8tU33kTDjOidF8RpXAA5rY6/8i2pktSYUG2iehNgpDqipMTSm+alnBDiC/OK3EkyZTctjD9tNgUwlJxxERNPxcETkFSkWjPUEUusW5sJaF0HrtOAnoGiD38wROkip04vsJwHJgQuIpXW1VnU0VC6vmmNerFSFd6I+n1zLc7kRVPY6woZSQ6JyGU+2jGx1UBNDvKdHkg3AFZEwC3Z1lH9oG1ibkPqCACJGmdQs842B3FqtP74bLh9zOpSNO3mAsn5e2OanNjf0asFGxJi/hv554eVaeRS+SY/TV1M4i+yJZqOeLtUm4D+y1LpXKNaaLqPkoM8n7AQuDMmdaxQ+laVx3HKC42JlJ8aozhaQ29pOoO8blFDN4Kyw6gYPaSTYeJl6e6T7v9bW7RhTNFivDNf0GXFAXkaJz7oUQW7SP7NjU5AQzLsSS/tG8Vkij007GzUfNd1u5jQY7k8BhwXuWGpoH8xcXYG/B2jQ9fHdcqdk5ZNmDpEGLKWPa0C6uzJNW1qRgIY6rwUiBQMhIxzkHb+1jDfBoorUaraOcxo15O9eJIVfUfafOC4SL8JkCXhhy09IDpJqw4x1W9FIFYdFiX6QXclk5rWeHvTMpAaOApkvR50LAnO3is49s085VYfxcrZnVvyvYaxQc/8KMgSUh99icsMSjzezbPvaAZw+kd55R0+t/kr+pI/lPrnHxjSudbSWumXAxhQkhSbRUqOxcsRYt4mYb729WSMSCoSzwqSggxwXFpJLrOWthAwRMV8Dcvd8rxq5cfeBJhBtS0AfHjcqzfh8V9igGgrdO/H/ZdTy4NhZH9pXpqfR0zs4guKWXUWo9cuH9ig+VG+fZ1BT/DYG6rcQYLtOgfWYz8CCu5xTL2p8iBEaVxKjSiI5yFKKdh+gBa4nNB2sIT/cTd6snpPmFDrCgah4Tjg91VHe1Ga4TifH1qO1tr7CwxBF/5NTK1444199vZOKQOEXQxy1Sx7B/iYUPOqRD9x1TKP/m2Lc8a9uzVcvqSAyIYssxi7I63lyRmGrf4PQ4ciD9cY5sjzGJiTo5GuVfWEAtOySZO3njPGjoh5aZ7zbPDMDFD6BxIVK5b96GgH3xhNgsQDPZmwVLDqAW1kbSQhlazWMVU4T0uK2oZaBaJzLIWYTtjeAQNVHvljBR5Ja06+kLob8kddUqUcszQ0HSDZ+v8jXTVIyd930CGP/dzR3buRRv9es7JvJlkkNPSkG/bVq8SU6TZBh6QEj5nsZdwSoGUCqNCrxS4pj4puX5j0uGuAG0mWURnyoUWkVbtbTeYPndWyrehsrBugZiewanbahUkQYV5BW1pa8NETMMaa76Vx9i3d1DCr2IDe/J4rN+20L3YTOd1M97MS1S5Q59DI8OUgPLK2Wknrl+fUSgPxXC6SMB1hYtta3P5u7Ar6PvCD8elpeLnEOMJmFyPDd4E1+ZMc784a1K3ysxBkyvDLv3bAkpPt26Wwgn3rtGk1byxBmFjj4eyROFLnpu/4tMKsh6WWbZDsT0x/B0lPxTLlUdIAYjjNS+pm7HT0XGxyHf9K/vuphqRAbR5/i7AEv6RqrxR2k5wB5xpfqMTkVReznsOQNiaKxWiyFIw8z3lxPCptD7MoMInDQ9+14iB+6jUwQaPV6P6Kmxw3KZOSkRumA7ygkiM1gwmNGPgvy2vSXY4LZYuYixKJiRXOWSmhv3s1GM4GWgIYdCP79c0uX1kIgxidLrgWCIsdykt+8bSyS6BX6npFY1qk4V51P70mAEV6bgKDMU6nps4LNNdYVtnGEaWr5JvBapiYOpCKZPzrtHs0cRsVaQ/xAY7CBg1KKP7BNrgcFc3mfDBxSd7nHcPxra2SKDrNCk4sfgqFLyXTp6fl8+re/geMhkfdeJW9MjJ/zlzXOK/f3xxwzvDNLtm72BEJejSNAFcqD9JMHhKr25t+hZPfx5qp6+hS99elIyhD/2bT7+2D/SogATAgaeyHKfHRmAxtnc8BPFbGv5IZpcIK1VR3nMvT7fsEIzvarUHxlOhVnHoabVTp7YfU/B1jOWt+ta2k3b803dHeVY1kn4s3eKaST6xHuKGEbBL/NI4ofaDqg+WClGG8kIZqU83fzxvutCGmXNJ0sUJpvUB8fGY31Yg/0Mcgw48qOSrNBhanLANo5Aru6LKZrE2YQ4dtVls/6fWDptjGy7BgaUutVEgJ5kRYqvjF4cBXK+rReEfveEZ16sW/uapzXlhJpTu4kP3e0p0lnr4gAHfGAxxTsOBo/k6kGjiiiiYM7E21334EX5clOxtg9ZYgyZsXdMVz7/zbBOpTQHxyDeM4MnVlHm1C8mfEH6kd33rJ3h+egSe6sNdKF4CwqNPKKpQqg1pwdSDSRkj1tFIOxjEYjy/O2rnLrJMxvUyMz+pNqyHXAaqx+AKUGEYH/PtNA+tFaeozeLaJ9haxmVi4nODHXyBX3p7uNVkfjiHtlCIOQQwodrWNYooUgH7G236CtRy9ZEeVKFmebFThF3tybbEd/SuhTar8Q+cWNoz6lR3rPeQeWAVMeoZv9OADu/RhgJ9PUJ0l3tnImZ3h7AZXJm+xoWvB2lcOkhDrTHw97itexQW/chzvWe5QfLWsemxd4EIeUl7uDK9ShRzC5az1q1eQYOyfR4Qjtsx5A4snriRSD/Icil3ghsVaumylwwWc/DHVpQNmUth7CW4pirjEWm4C3quI7kTQdvQzTTCybtFBLKshN3Au+Lf2+zsKf/i1p4m6SVRF1L0DRiLIBrxHMBS5PpznFp+BHXqRMj1MoK4qxA2tBpbH6MYeMRXQTChPP4LpSGTn9ElgwvnWXrRSJ4IIqHgNkDY5BfF8v2gpjla0PIZdMhNkzN9DEgxKSrjqgdw4E9gXri9Qv+HS53nPIF5HhedIbo7B4xLVO0eDcZRfEIJeCMBSwIUndLMRzKkbUQm1QwKlTRt4Z05LIl8Gz0mg6HDmcoZrG0LNvLCkjDUEkOl6F2vpaXzZ2mFpVdae0CHv1cENiAKCXdAZqOYfFbY/M/2OXBlsl+ppvDKfNO6wgreH1XEUuKCrGCQ16PWtShaQR3QD25rU+3j6uNlmVVgf7QsBIcjbDCDPw7jCE5AEtBegz0uKaUtEnKy0/lZRQHc4opzhdyZOEZMmDnLVKaKiUehjW3UdX9qIq0IAxQ/Jg0KtDgJkFN9VuJ2oS7RIgz1dS4DKXWqf/HX4IVnxrxqj/kpmkXfGtVoUlF4xcR8eJ/43JIhO7J+YGolXj/ABmz179DCAzuR5Ozdxu6uTchl0zeKRx+NNLffopeGRk8fvFRgA/q8qtUXXixf8DyL7kQhIcnCF4nb4TsQtvPIqbapiWBwPDehXby6dsg34Ot+LKOH9WFaB87Xvd1vWOojnhMd+J+CIUkP7WtshaX7pjzCtrHjoDlCfeOWhSCeywAwjjEI6fEHoqMci4U85KLYDFnDxjjmM8q8zt6r5cCmeL/MvY5a9iYR1198dYcwhvvAEA/yxklg/6iKKRE40q3XZimmFRQ6ZeXCtV70qzKMevxSgxlFPbZo2QKdAGLJZBtZB0FJUvsY54cY8Kv9NSLHdCYxIygPMmXbAYEUnNl6W27XIaq5enVTDHJHNRBa0+bAOkX26mfY+qSXzc3yLslGniTjMYaiXrL/uKzyQMYyyTySUfTFCNFPEpW+lBX/AejTVJj2QikbBkZ5Df+1DBHnqaqwg61w5WENf1zKTo5rYlmeJV7bDLOf8Hoz5Wt4GZuxROveASmLHNK8fCvM3FkCn3NV/oTdey0s5mrwZT4XOBB/6l/+5cLas1vw9AeUIglRU1FfDSjph5QyJ5P0muWNsXnYizEL2bxm3edeE4RFs+wVUZ4SaYlGywxmURGAZgxC/TJJp9Srvj4+PRKshC02VwaFolLotbHUlp6872QkBwwnQ7sFh0ue2Wp39Uv70FfJAPmz/Y6szDFLIkFU+5lM5Y+JseH4yCHF71TlEWmZONobYV49PyAhhK8LRHMUEvG5g0XUrsquUfzveYvzRt9OYHdsiFToJ7UVihbl4nzaae4SerJ+nekq5K3+iMNnrU05IrbKSTL1+2oSz/5MMZ2y2Ps3qefMdz5SICrpHrtzblI1EAeNVtWAyyODIC78VfDuwdxpCKXgaXeoEJHonLGbdTLdZkr9e472vNJmJnsAXqmybG9AGWVlJZyu8xC0UE3i3+M94HodSAD2dq2G4abYsQEI6USUbem0pRnK3pnxLIvHCTuUYo3u+JdnL/0mz+E0hbhVffHX7Y0U6VCOl9bZBqs1omdOwJRGjBRguXaZN1EsMpMMukZfjFRzeQGGS3hae7Pj6lP4g9bt1sS67rDA/jKqsk6C4ebMiesMBDfBM419A3V3r9cYH5hF8135mobeb+IzVNxpfmSyGvisTYxTQVL94WewvP1DFI98y2P/LD6Uky54t+plQkF3xfu056C9smKDizxxMqBbtmY3dZoJlfF5N/EIH7x4bZ8mDhVMhvDgrQerG2KRrQ2S+q2DYipc/IfsR//gilG/n2+xmmsvnPaB+b4tS63k6RwaeL04n3q8dO+sKnRhOIJf35aqtcmLXjDWXpeRdG3TLgT6bIaghHLxdi3vV9JVv9CIpnfJa1Do5HdWXaPoXh3ORbX4iQuCKL/xU2uZQn3Po0RD4JsYXGrvcjx1FkHUVMXn2tA/b5lactTXNWCRpySqcro9sCEpd/tOx/o5Tg1KTiWfW0ZOVnp7v26/GRlpvSeJNiV6Nd/nrgiKYo5kL+PbOP8OMab6Bh1fdYjofSodjLGUleeh4W8z3l4T2Uw/J0/6kzta9lwDEO0cT40c02e0I1wS6yB+MONWWlnVuoGCIsPe6zfMIPwLt4+FzDRZZHlQxMzRHgTP7J+6tKgeOzDdw/8D32HTGrWnS0bV9yVjM5GMPz/JpBvAHKmg+3nA3dGorW5XCE16xSG7CsKuKyspmh2+64v5mOQDercbMJ18qgb1cucKiVutyoEtdpDUgmxb3xniod1Misy48zyteLSYcbO7YOGxZsvQopipGaS13tce85MaMyYP2KJIGuYu2FFZvrWE/PXRrPGkcZKlLZxFq/MglWGTSbWVU0PflkUpqLaxyqspYm2rqVeA2OM+FgRmLkuozxex1iAcqO0Vv9gYgkZ/Jej+fMuLfxjntN/k98XOX63HVMrmLOaG0EnAssyfpuuOJNi4AtjKfr2GmUksbvDRBYWmc0E0FSTS3N4eWT2qk/hcUVykY+Mt2fFGK/6hJN21qIJP5p5zKZAjyYv2EgOpNRyzYhSshqt3d0bNT7MZipWmzx/QAEDlHHZjo8zIYIOMaugK4SLLaquZxrhlLcj5qDoibXmJQvsMJJyXQGnNNoliJdglM4oAhP48IHVqfLphA20PLqo4Q95r3cpFpo0uSXkqoKjX4mt4Z2gxfJndneogpNcXWTe1XjT5GX+QsFDdbHP7dTc156/X3afY+kA3WNAzRaZztueaOj9X59Y5L3vx1xxe54fOtGCKaUcMkA48MgfyY6pLsMczjl8z1yw6QvunUSGccf2OXQFS5eFk8BBTi8LojB0GodVGQ8DWl7lmuuBaBAXQlENpDDI56Gn5z2Q3lNXsgg9KX7K4bVxXnzdGZFvt6ZRsF6C3fP+KRXrMUTLcmBgWD0FUtG5jsPqdE6HGnuQYdjHj2rBJgZu9fLtRbXuZIW41cICCYsw5+1hV6jUEkUTcjMm+xrM4vIacqKLfZz9eF4+lVhsI35GyKPx4NmErZs05e1gERkLmtDqEvUx2tDnds/tZdNi7rh+l+Q3gXLwJKv9wiMvwIWHKvSgE6ZBjrZ/4yzvpsE9lfPpY0oZg7D0GJSP0LuWLBmESfucpLInLRBtQfoKxFo4Z12sJqUUn88A2wgOxdwNDTor6mhH4ErEcYHx+KIzt36qSuZ7Ud36m637lkf4Z7gc2z+10/ukjt/BcXANj7FfvxpkYFFjbGHI5ov3WEwL9naGUuviRyvvHRnbxxW9YZDnB3qIHyB7KS/2kugPTxGeeP1xadd7/l2KiiQTxOp1pSKSgKohKod5avOtYifFVteo14yYUk52C/84lcsdJy+zPsN9kqZaoLbNSCkfDe7tKSNGmcbCYlfbRqZ4djyQoKcyRwrXCR9gAynvlPOx1ApvBzM+1GMmmQcqC+TmTypck3mlS1ILWLUiCaQNehGRnIAT6wHwujp0WtIoWZUo6R3APml5rG/hHo5TiJlfFcOhCOVRwK8bSyRdRKscog3URyEeam2R68Dw8XVdi59R70Od0PKYC1PzTrr7vvLn/UaxxSpT6a/zmeAWiLYeoknHy+nGm5G9SvLDzGQw308ntSD3sclFGAU19nKmyoThhsgGJ9nPaeiuc4cap7uNiYdFhmXnobVVUhk0P9Zj6Xn+dQtfGgYLIGtK7Vj8Qw843YppHcP10bNoofVVvh8vwtoZy+4aMZUto8PVU0lIvqYTfVlVRYPLjETUA6Vi2UkTsqAdnKs+RW58KBDuCfFGBunKWTJgOfHIIwn4SMQlSjYmXtm1Ql2sijgmQrgoVav5Nv8/s4s1REzHashJ3WO9Zk+/5sfQ4/sAGSrvSmdUynR11UVa90RrJfPRwzFNcxe7GDpOd1nNqHvGbjIq8o9j22an9plruvxUoiWF0T3vMwsU+NN48cCWBRsiXt0J/Zspxh2UWFLFmi3ffrxgPnJvfelrddYHwwa7jSzeYK3yJbW4pEqF3dB6vVneSx35Nekmmdj2bynte105oenFezSgcGoY35KdQ9fno3x60ID5NRS38p3vqMUMjsRyKZcnP/uD6mvi/bFqkMH0G9G6GUQOtW0oC8uBE1mKHdUcQljE+B5rzBkqt7JsLnfXCyqYjNUHPT904R+R9oBkRFHM6HycsoBEOLvjLRhLZz7W91wAeBBzAw6ERSvoWn6R3fAYEQJHHqqrf5Fsp+yL45gw/5vyehipl/xVt8KJug//oSCrmnowe3SLwvsQxHB13RfHtaHPSoK71eCWvDYgpMHH3j2Qha1t2wD1ANdyKrIsupTOwlDRnLgOnJLoqm6qx3IQSylf36i1+nsrSpBFCXwYOJW0ot1jNdKOX8ddf1klVaLQdVxH6oPXYz7gQWhYAAJmJejR1QfC/XJb786As5QvDO+AJjwp5qBS+KCvfkIguTXF9fRrvUpUXuP3jknzevHCod29lBQc0nPLe9u1TF2rlzafGKIOq17fZH2nk2gLzJQd39+KEx+uL3TijzHnnf5eiETUVd0z9VhEztUJW1kDDAZX8du68RMcTww7y8I5nRz+l4iiA8bd0skKUWR53E6OEunsg5+GNBI3fmPiq3Z3FE5Pk3s0LfAl4X+g/eWT/zHrDEx2ydLgo3hY3GOkzIWaSkcf1RuiOe5eNHgYgOKRxqfxGxEeEoh72yDnMMG4rIYNpkMXk23y0PYkzG/PgtEAn+T0++x8LzeO46K1CDOZ4oBPnRVYtQvkk5Eey9PeFX6zS3sp+Xv85xxRfxLQlfKJvVPk5SCP6gUz+ba6FPQ37pR5TRRFPDBhgHU+INPqOMcNzJj5XXALJn7iEy7ypFM0JzqqpDrTI+9RBPEs5q2WDQuj7GqjXzCE3pPQdiapICVP5tzElXupZU1ktnQxucLSeyEdHTbxqPr7nak0uRTWp/Rn5FHNWwhIdOVc2bCBw/LnVTMEEi2qUzKisajQHst8iLF74BLh9eTczLfAaKfVkKD4E9f7QHGoyj5/gnZbaMEMvFeC28+Sa5MiEdOqfcqIUK3BgT4iGdoWY/+xbndKZ08xRbjt41Zwy3g8qYiL//tXubyxSod1vvjicbPI0E4ek7gcB/eIT88JVkKLOuZqnxGunNhXVQTimdL7Y0UbAvNFi28lEiGOdXhzHqc6WAe0XIZauVeDXOMPgSWjISzaz6RkG5e5l3zgQlCMfadlooaADwPbLG/RFawS/TXM1bWl7tFpPyV1y3cBTIffV8QhOGXkCaMV8HR0MDXOE574gZjWk5q/IrZh5tw1n3zCP3hcYnkuZdLUMXbzpPmjnR6kXjH2v7PGqBKOKndjefIdmMFhZ59E+7x7iej7hBNMIx7eRTqqN7i49QftE+Jl4dnomDaDr7j8t/FXNmPOD68JWzfNmPlRxoIIvv5DHRMeTKmYT8Jz3nwFsTGz+jwPtjAROfK/69dYAO/0rC5ZPdbqhDH3A6JAIbLq2yo63a5QhOtFR9BmgqoKz4rLdC3orhqHjp0YAbvf2VWdDdAZnKiMGkYeKTbjTnt//MkKi3a/6rg7m35uVG6Ihzce9MtTMMyEZ2X10+LlyBPWvV9Ev4hZRPlLtU9GVwO9U8QHnYrbMH+PSZ9K2iTz4DzMIppsYyCDbRmMKqPzHuwkJMcrB53lOO2vgmbOsPifA2kY9t976h7aYX1Ql6u919mUlsPUyvG9ozi6c4yyHppB9l62dKLJtfsRXF7ESfzAc4jrvbO7LbGrGmfDy8YsuZYRdygceQMoa4vAC0b13UUZu4tNQ07v46ooj6WwbPXgLgvJhMexUiwBARVzlv7CTFpoWPaJFjLzhiP7VQpCFSZiev3UaJYFdM55l1qnjocLxh8h1lS5zC8xiiHRd4ZFF/6BSJtY5ONrNVW4SahxzzRCG8JhgsMz0vklB8qYtILSuup8hmWd1gTBo0YSCbq2yV901KeJbWjrmsjtHtOrLQt/MlMaeg1sYIv4uQ/KsdJ39nGKxGpkH0+emXpHU6nxsgFriQ42Jgt2326Dgz10sSQTeGXSKi8SuwEpLXt5IPcUEHt8jTDKV8xZXoeGRboFvK47WSL9HZWyPtWQo1E162IuQbF9eopeYkXhUriOgwsl3YJY6+XckPQoVjKsk7B1NfhzSX8tDRNR4RUR64puDHReTAnCwSFVL8wLBlKcVzLzIOQH63SpdLwkZ8LkONXSc8PbyVkP/pTidoZ3sjWqWOB6MKgS1v/9VLn/4Tn3Z0qK0yrEQU5yo7jCBLJ5vDT8g/SUNyum6wmkSCidPTV26/T6hc+7T3fdB2dwqX91Ihhns0OcvXpIpY2zDr/wKl46KLoxyB9ES+6q/lqAefGXszRbGsFDQ9wncb8o7X8toyc8zAWQcE5ZWfvZRGEepXk7496KqyVMH2ka/f04qgfTvtmlIXqvebbKSArD7DKbQsVTkauBALPARCEgKvY5knimWh82efF5drayl3F6Y3M2z/wcxLFh8bwbtev6nPua8dMYJtEuvl2mWbFxHtvk2X6tTB+3IaNcx7yA0BzgIShyMt0SymlHp0wT5edljnOlrukNwUAvfSosMrEXBEEAQnMQBAEIzwFCIuUFQRAEuoS5bqfTW17Gc9HywJJU0TKM8mW6JAgw4iRkQAEgJa6wN8TzSJi4rODF84gjvOrslNzbqxnWMILwjFuXLF1CnthhRrhTGEchoLTWQ/crHfHr/rPyWhIU/3CeHBoEzwIr50rMokbm4EZoCGvUU7AC0whJTxGuNVcmeWm8ijGP/dxCGlPdGI+4yNG3GFHRih7PUZCVaMX4PBBqAmGSVdGLy71Ub6jbqybBKm0kzIB+Yy12lSMM7LoTsV4m+Y4tXwCBvXi2fYQUgg9LtN7vxgDK8gum/HzbydeNA5Yb7onSdHkpZjc5yVKUA5Y6q4eGodvHyp028x0vi+gxBem7lmSb6KpTr1ZzsKRQgn4XbrnjeGlF2q/JIjKEmXC2S5Dhfn5ZxJUOIbz26AxJulWN9+nn2MPrIJWLFjMq5x8hnse7M5Znl9ig/Cdj3a9QyjvxSNHzEl0oxBDl+88KZFOuL4nDmQ3EJDpj8Th1BIElbIIGAr/b4EKHmx8pSjduWi++m0f9TXGQuvDkrhYX18L62wsKH0Ed2jAMKZfZtIOfXaw5MAi2wBqb3et2tHzgtwnTLc4SR8zw/uFpeJZEpyu+k3kUpERAnnqNDRhJEvTg/aZS4NTxwQ5rVjtiGeHuzCriOXwhbcLcmpV2Rp0S4uA8IGY6ecNs/8WExRF7qO64PHvIFiyDg2BwFQLAsYS+GUnBCv+RUlDUWYVYlehV/9NaOYvya0uwL9SWS3IMrpYdMVvhCqG8LINHyY4hg/v72XsxVfsaJBDkiwvLN+PU2WhVO4YN2hkH0/SNMcE5iLB8iWxzzT0hc5S3wcwEQqax5PgdpoWx4jO6lP3AhzfUvaWKRhACG3b1BnROz2Iafeon25AlYVAQ06iQeHk2FQiBRVgYfsK+jJzlr7X23ODMPICvhWmMg6FjsBCaKNP048pnkUPBeMR3boB0rW6MQwnEPbGTdEPgcCzc2X7f2HuZCGYDI/WZpjHqORbFXs3PpOSbMTmLnK/nKHLXf83YX+Jewp8V2qOGsyCy/f4fYv8OhS3IilZ+T0iavUyvKZs+uBkZGBnEyXmVdIhesnVjvvgBq2hgFZHPX0GP4ke/RXYVW71k4KoriITYRbmjHJGuC7I7XCGuIBdOCCCZbANXRR2k6NLb62y0WybIBxs2MXJE9Vo1nfA/PT3B/r2EBq8rzRT/Umv1SFyOPxZaCTMdr7ytDVeH8mR6XFSkuG204yhKr6bok2c/9kH4ze8yOnorNLqxakYwG75S03FjXxSTHDKtAjJYYF1Zb83V7kXaEDpAbLtBsWpURf4+haK8uJMcdTupTDZ6m+0fA+LvXbskYLsklfVKupQYS6k3S0U37dbewamsk85eUabfJBZzeqGcs1Otipln8C2+cT+PoioB+Htxb7hI4sos12g8w6XGRCJZpo05UFm9uT1y40jw0KLxpfCpN4hFsCdPCvyNI6AA6B+Fw9gjhsXs5hea4LTRiJNNlTgxIRSpDMVp6NqaV80YxUnnQKZVSviAP6o6CinbxuveHt7AhW9Opylrx2fVhy18HR+L8EJ143kzT0VPo39x8Z3IJ7yJ16pM11zg+kaznZih3BWrZfL2/SoM5u/HHfCzOLCqSXqMtwF60EiZRqIijwAfJCjiew6Zz5u0gpsrcTPf43f6a4VkTZlypFhMuWK97Jwhq0zE+12hUETk62GsPgtlbV3n789bvxYRsDglQFWG7JqiTDYsBW1KMC/molJbsmYmgb2Qgudi0HGZ7AmsrK1BTyfKYxaH6WpWbXjq01KVMgQTt+gj7+g1MijqV9mCE+pQdAWaze4g+Vr/bd9LLRZIvBXZqvC9i1vxyZGLVfz7zkPXQ9HA/dlGb6bc3G3C6hXfvtLzjy0E+YjCFLKO8dNaWqpOc66dmHKMCqwBhahcS4tty7t+vOAy7W1ivM6mkS6dLiJU4P483EN8Dzv4hYlu8K4V6cppvgfZGkBjrr8LbyOTup3SItbI3/Pz5yU2TgxZje+Xx8prajF2K2UDmD2ro1I2JT/K1f3AUHpb4kL4J75qF+hCkI4SQyBRuZ5pjvF15PHP9+2Rv3v1ETgCRD76qUA6xgubzHUa9ni748nzcWXqRvslhLgvHSixxgfFFSI5XgeXAuuolcsvd4vfJF06YtzdvuyEIe1Lu5xvrDYeU6R03fMHL2tf/bjRRiJoavjiSa0hPYMr7U1G58x7TPEJYn3Dc2+xoRY6t6HJ9yTdhmIX0Tu5wGoPeimHGbWctPDXQP2Z69L0MPH8BVrnbv1S6ZGV8WfvDkxEs+s4CbkDWNI9hCc56FP1UWTgurKt64Yh30xIPoSAzV/jQ3rjKGYoO67PuB5g8jjsmOZj2TEUamtDJbKQbhjrkbIysJedwVhIsv7fEJGi8juCzw15KAhJzP5m0yNd1EIQL+DEcRE5ojR+q5ftw3hs3DaNee/C4coxSbiyZDNwts6Io/sQqfvlU8F2Y6V1VOqtUq2lWW5ftGZ6mqKmaK9NUV+uem7uHs3f9bkhYxsM2O/1x8cuN3dUOKm95uew2hwSk18mhQDo58KPT7AHqTJL5eutRnmdMxqql49ZM8BAxjRSy7dcab5N0jlyssOO1RWbMfPTQabkMHGzcNfKDpY6mfLtpxYMpFKFEWIG5MtJukxawl5UvpteCQ1q1GJ4cdoefBDg1KuTOvvR1nNmNkm884HjdMvdi3jMg7U95lkqiErIpPxD71nRk4NvttnLk4RHUvDeYvE6Uo04ChOBVI7e5kVFHJtPsDjdtKn9lmY2SEEPJKLPTsUC4fmmqk6JRb5XQGq1pVdFZ4y6V2sDrfPuAcek68aqeKksMwErx4FtMYjvbM6FOTKC9O5bMJBDDinX0xf/QlsJP6VOjnAPYv0dWlHMnu1JU0RJTGFJpWkAxcuITCMDzc1NsAQLljMNneMJ94jir5N+VArYzPCV9tojsZDnLUmt6dN2t6+0vw6hW/v69ErYOixLPKyQeJAKAH3UXtPNulF5xOCMrGJ2iWszJA7LYJZFo4MuwWopR49T8bvbt56WMaVnJ8OzXiuuBwNEabHolqQBDNhsILCUVCjZWzGbeo9HDjp6ZZLKlNk3rNUtwVqs2I0Oitgu7RiepuxUzx0qRKWboz5TJpjn90mahMe4d55WWIDwpr6jBVdK6IQCVtFFoxvtNCI6e1mVxSx3S+ZIXSi0kbNMAko9cidPfw2n/fdt6OjjJqa5JnDmmnaN27+62/kEHQPMHGVFtto80YuA7N9IvydagUfdhC4qPDjYDrz0crO26fiiuCSml/7hYoC++bQcGBp1jUp3X67pz2jJvaORB5w8E0+nQwchJJqIiYZTs8WE44/QlYcPij9inaoRIAFX/DGRs4B7Wrcp04QlX5uKvuK9ry9nUk2GE8vT5JDiFuoBL3nmZxwYVQgyvFTMBNxzQr9h6YngsRdjvos23Zx/ItJIQOCL52AJSuFK2X3hRYY/TPKzUxep8D7JU++pXm90GGM6PrrKUS1pDYsvu9wCwaHChudR562RcccHCkDi6Ll8S0IatH3V0q4p03tGtAssaKRpvU4Fllrjpu3TDeRUT4g47ZBRH+2bmmCEIU1k6Kmff6ofGwufjgUAyxZPsfetIb/F7xK2hjGkjqFkrbxgItwUhjRITTC3Bfc1O7oKTg20wPNxFXxt3c96wTIvr0nvsVU8LgiNfA2ijyu8RQtsPD9pulzwavEo/U5WSw8uyy4cncedigcpHvxVdqHlTWh6CxcFVH4FiLpgWo4LKSQvbcAUj5R0h2bv+dhPcjOiUKaiq9XIFGqMh9OyruN5aDDaiRfVtQMmntnHQ/cDpp+qCpgw40DHhQdmBLraIZSyd/0+xKV3luyXoamIjVpjQH1rVBsvgZUJUMINXmEgFUo7Rh3hfdTpNqAKyUKLDD8wjBwd563UUcjHz4W1oOynzbaq52R1g0lx06Qf3Kk3leGnMJJG/OLNW0PuS4PNlGpoHYvLBdjJiEHBvp8S+CBh7mYTfKVh9krvnPj+0gtgKfgjgT4fkZGj45RGwQK8RTWdcBqlgpIAHQpAIgqG46c5/vwHpgCvTDpp+TdhqiMuCBK+sbtp+TkYsBM2/ik35ZJvs0nLdt6BxnHXY3MMz5el56K4uFccek6Qf0d8cOL7agOW3cPTO1e7k8KfeKNlcHzepnLX5+2cz9jEnJEa8D4R52pVeaG2n2P6quUbZyxuDizPA4tjNjhR3INKY0oWMl3YJvHixLBU/gEosB9jYz9mrx0cM8AIj6CA0Sj5tN8Lg4kJSkr9N0TFm2c+Y+IgOx+lXRxSpYbE7rZqc+lY3I86RVn2mvw2OcpSgy56LD8B0psc2fS263MwtD+IhDnM8ZW/ZmGIbcAWNsfbrM9zKDsXVb6NYy4juSb99C8N5RO5i1bX0SPHsJC5ywG9fUmt9BLAnevYoNBOUvvw6HjsyuM/KEP7VQmbeujagu8Eyrr8gETmI9iyck00YK7IJrFi5mnpQbCVE1aHH/RyI1xwbVsM5akkJ9Qij5FwKNAdPtdUPMGXA1Sq0i70ZBTR3rJz07T/D7ewgZlAcpZB4vSp8LD5plsvLU1noW3dqqhNuSsfK+Nb5X/nyshwGJLkIqpS4JwY9MWXXo26gmmzfMIoYqLK3QywDJdNkRZsXOlc2FeZDhSJPQakWm8i8Tpuaat3LbBBYSes6nhv2BYjC1/pnTDaphcL08vo6tiIkaj4Bl6x1L3gwCcdjBxekNQKtb+QOAa4H+qmARWfmYf3shhJWcj2d0iVyAeguCT5QR2WpkuKHGtsY3W56u1Ik7ZNo14H7f/xM4rcz9vgmGTWApXahuJjUmJq49RNsqGdBaNlXb9RMFeH3lof4RZiY9/s2wqrQqihrcwnP+nkZiy+UDY7dl4rPHzAd9IXgvRvb9JX7vtb4dTtzgRF7DRrvKgcz9A3RANaqFMHGbbzkzpP4RAsocpXE29JtoXWp7RsrAeUjVeVjqUNLBmclyVs3ArxPi54aDrcHW67AtnCBpwPSIODMCbT8bnjsG8fJfVkU0dmae+RET8Bqhdyyb41xRCSLT/G2Qa6EUQdiKocS9IzozRD2K39K30FELy+FTiIO9+jYeSb3Cy1+eaHqPGQvBVYBzVCqjNFSoP7l+eXZtZWLSylwwZs8t2+h/sswGOnTf37FFMEvm7I/MnNYKa2iAQknItgu1mOZSsuRz6Lv28RNVp/Vbp3kfIoTJTGIBLHF4Wm/Zn0dMgj7XjQzrvXUje7YsiQPeMInlxyS7dyDmCqUuYYhMq6OCOxA5qLecnIa93/cyTup8wR38yQlUSkqImIcO2e5LWU5fOK7beeGuFZ05mBz/r3kyWY1te0yCS4HCKR51jmEgxS9NttgEUQAzk+eQbIUE4aVrpdKbpXFnndTd51MEzNASfFAXqgOugm+A0iD/Ih7CHBhNik4v8+xLqHGZRj5qd6vKq4UqygRRBsDpAxBvskAv11C2bOqqPjNYmXrskcOo3YhNAjxTvufAGVRcf0g2z2eFzuJn9hRM2qn51g4ZEpuLZe4KpMJuzUk3DR5imy2NJfoPYSdc/y2+vQSzecLIF03UfKt75XS0m7V559GLNFRLGNjXtUVaYnRbT7UCYn6Ko4MFkeh3sXQxoHvn0CaC5gBoo20zD6+lcFErs9nLMwW3NI6XxPh35GVrBkeBlHsceJcxW8tZtUAgsH4NGbNFRe6XrdJfhGiSasCJUZh7Cux+jgF8SFr9GdWIQNChpeisMNfL/8u2Mu0CDAEfGdB/1qXLalvJa+4PdnzK1Denz2WPqNhUaLUwlHNTGSwnGm/HmjpBMG1wClg6iwgWAJg2VhoAIBLFKZifNvdy4xihKjffN/J+xcXCFTIPKgO5Ak57jkbotiAapdMe4LlCkk8a0yu0xG4SxiH0DVdBR2gAqWr9GgHHRHcdwo2w/oz7AfMRbfry7OKmLBFMWz5kyG/mbRK3YLJCVBft/XbL++cdyXHKApxcQuvQGxkunpO9iJuK1y8igwPQvGh7Ppm5Tz10Cj5F6RRQY62WJ75Xs53g6bNIrSbY8n4RDFYQfwyxTMBuhZUxiMX9SIO40bOQaF0VvHyhu3QusEYSRLifdYIGxmmzLcELLtHFGDrQc8mYwpU042AEO2bd2Knu5+FgFed1zqw3SPPY7y9ReXEmT/C5t7DfPJRnBQZwkb80VQTNGkcxd6ec3iJh6+JZfefl1ox+s5lDlx9fbPaIVyZuT/cVe8pKUf+9dRxkjLaBNcs729WOyfr2LTffn4/fI/HWkX0wUv71jQRnbWtkC41CULtgZ1qqUKGZa63PPgw7aHsMBWLnBWlknZ7jugDgQzxA0hCwtllWso+MgJDefmsCcH63fDF0M2Dm5jwtHABSOQptdCvf3sT0qfq0hB9qFgea4/vsoOIe6Tk35YYk3z2IOdYBuHolLTNhatMJNmwFxlfeSYp4IpEkXIFIkiZI5HkK4SfEFbtSuih9X7Eo4sXxk0Up+gwhiKNjePnLwzqK+9DsJt9BbXaNedYt7j35u8tI037eu8zdnIZ3HnTUneyDm7JovWjIoyfFI1ZeBVhRgpKkA3/km/4Ytbf+KcivY56zt8m17vHjiGSCyQn6PAkv+LHW/JOcbdqaOhM7QPyZdB0a7Mv0LR2j0gktI4QFodxAmpdknB1ciCsZ3YGGVx2FKj/7ae8iWmVXto0e96sK2UAU65080WT68oolHc/2EaAB1kreK2Z0HojJ5DBHt5/no/ZkKXeIgoHmyuag8Xh2WIsTILFLChTr9adXk2OuqjVlc+NU6nF8om1OHm3RjWVoDmQiGoiHkH4/5eESW5xRHzW3ovFxozwYYFrNWhBJmoPTc7A15Yiw0iru1kzu6wCTB7nTwW3fBFFqwo63YouJkmING0mQaRX3juNc9ShtAuZgQVgVfDwkDYiemDkzks2Rrws++BTY47wSjrhSgD7AEELysJ31fjnBp65awAtlCM4ezHycuV31OxbnkG0+eDeyZxtQVjzaKaqr7e5NSsEuRlInOFWLpdYIvhEidDyFBj2w3PpVGvJ9kCg+QbxDR62v4lnY1zNc6CjJcgifNOuthwXgWuyvJtx/uaAqRTTMhOkaKP8V/J6c8VJn5JxfTYB8NobiGUII9069Y327Enj3PlD8Zn+lNL85efRQVZJvdo4gGqYdVgem3XKBJKoHo3+G76C+rUukhN1njeBgYXRQnbhBoP5vsmFI/aizbRLK2MnNwa+Oo6tHq7xetdf/42ZRSc4Ziu+H8etT4PScLkSlwjUDVBhtfQgObAVRrfqQn8aa/s8b4bMAtFxP5lLJ8O1ma2VhTHlXm/xUCAUVNQYjW0q44McEesvVIYCCXpeFG3pXb6slx0llPmZd/nTK7JhgwRcPSpzvBZ53bJxpPvdXXej4TvA0RV7zIpoXebqgkEJhNEVGx0khLRSVkBF0UKiCVMlKQQJ383JjZztvuv4vxHUph4ixdmRMXSta8SXIl0rHRWoPvUSBlcOpQdpmjEqkkxXFT4FA3oo+R5CDRc9iwhYpNR0qQJrPIYo+/zhW8U07ALGTHm0JZoYkbxjDL35K29Q3tjBXDlDpkVNJwQHNsG938u/fqheoP6gpsIhmH6j7v2qqm/0MkuXoBfl9QFw3cBg4/LjgOTzsCpJmC5RofasMtHLl1xQ5LSBMriiwb8CxQzm3mCP9BMnJ8D1HSOTkw4L3E8G3LVYtMGiN6Z8TZ1C+9pKPRxr8+rIqLp6RgVx/9R4wBV668EcEz1R/Gv48Kdi8OdSkhw4z2QDz+NWE/uV1V8IGfl5Owh48yFih4ew/r1N7BLDJR7n3aZsh4jdzUXpzaKgMiKse3276LsD60QqEfN7iuIdoK1ywURsMnayTI22EZzJWGsF10YVbSUdvhQlZYVL3gnWC+Kbgg22B5qtfK4CxS99x1EzTC73OP7DLIqmveMvqF9a0QLLvQ9QzR9svs0fbfVYLUVuGCDiJqbCB7ObQ2HF+mzqFECTYvtyng4AKzOe/ASeP70khMcsY7YTrpR3yDrYH3ji3gjcTsgRF7HL7iU93fk751NPbjuiqD9SoGORGiIOralcdMFvyRLlT02//RpSk7loSTnn1J+guqYiwsYS8H7W0XDwopQ2FEdx488EPtUFOdJTUa99yfY2+385btIJ3rf+k8hIsfZocf/cx6QWrC9eAuiF/nIIcNlkpiRoUJD++SoMgkl6KSZFC+dI5NJNLFI/QCjYAzXWlt4IfEdOaLRf9jfhv4PWUBZwIbeKrrBQT4DmwYH1ZSrSr49KSauBksUFJt8yRwSivPusPJE0GY5r4C/C7IICMknDSkENxlZIviOA4aqufPHSNFs/xv4WvxfN+iPZMODk7jwXzWPteh/fiD/mbMPV/vkS/CvtV2rVf5rSfmH/zZ/adr7H8NMg//r3JjElNMUb632v5aEP0sNah+L2uXyv/0NvbQq1YLSyoMbbRQc47fjmIcPFgRo7NRfg8v/mScEAdTR//08EjJJli3x80MUoYN6e7EiH1NQyh3ExSzd0hFtXJnBUZrT6dLi9G+vggu/z35vM6yB8i+t1LxTHZ/CtqNZPYHigSBY0ybH3KonCAfBTBq9T6S49dervOu5qZbc60ztUjn9LoVyzuZurmWB+zk87534tAKfIRvOW+8IXlXsPaLqAYoHCdyvXM5mq47gQWvBsUg6ULwNuFOl5pA9vQGWvzn1gkOTCHwier/7oTbYSq51/E/OIy7UHbQfYIuE8XDy0VPnhM4SDrhPtH9qWLkWYIpCQb7Erll4WkF7kf76iWiS0ut4zedecTZ+EV3K9TYpQtDy9QqcFZJjOvC/phzZsKhj1rBQlzLU8Ujp9etTtQWSI6jqdDz8zmEX+DPd5e/HtN3bUs63asRYeQG9c+5T7srzj5Va+GZy7BX76+PiSTWeXt3uwNavu8jl+wWOZtDceAueopBTdD8FmtcVflx/ebNbhycsV0xdsMXuIYe90FbWXJ9WPPiP/ZIU7NWaScfDVtmyv5qJtEs5TvBPa1iW2AnBrwuc4CX5X3L1SMnmkWAO9W+idbWj83SNonavhu16DjvvLynAg7QQvKTI683pUl0NeLVdTWSz+Osja/TW4eVKMkiXO90sPNSovtJ4s0n4a9H9Ff3ng4I2oO/pyn+e+snryU/feMuLZ4q39P5lCeLeH5KxaD1lHmvkyiENCvn/XYG917D9XXmsYTwXgjxl3vYFbt+7UWBUv5K3+CVhbYLdNeE0p2Qt8Soz+urE3eqAEZLYmlXz3lfqsOahVUGzzgucIUDBngIadxOFEw2yp91to1CLA59CCxz7N8azzgVerVCj2ddajvKgoA2NHrVictuRjja+bpbgcZHKX3r9Um0praUD6j3FZa/BnBZK8RI1ndtK4tMoLkG7RsPznWtgRifiLFoUdpusOkHgDtluXLZfodY4yXamHCzOgWE3in+qw6He7FsmtXA18Ki1ZUfOhWgd+J1a/LVjSPV1uUWv1gDWXT79/rwxPjslrE76sT4o4IpPqxRV0j89ro7kGMAhxSx0ysPqbXdinl5DLHDtcqgeVCpvuIECFPw7sA/sJ/L244OuXatIbdlpeCgLAcoz+0sRxGrVm4nuOx9gcvkwG29Fw3RqcS597jnMVrTuIcJL226h7r75sWKem6vtn/De7l0RlXOhI45hEJWnaCd8Zn+OkVwbWsryzmhK6T762s0onw7xkLfrr8cx/Cp/4ZVYbz9+mY9Jb7zdvQ9y1v9bIQr4ZYozK3qTabPAG296nNDORvHFmqnLeCOH31bxpWb4K4sTe65sTvwEzGaE1bRa4AMvsWOCb4Jb6xnKl+FgDu9tcTVkhueAv7bnMu/Q7kTxiRWBpbfKPjZgASO8fkiR82lWQWsHQL3+Xbri/+9gLE/W4bExzjeJb3oNVXYfd61lGI/j0bcd9IWGYT/gZ3ixvpUw3vl09O/we98+mLD4Xrur800uVv6XD6ZoSzdMqArz3jMfPJzXFy0R4AXOZGeGWxbGG2xslb/wRAX/4BkrZyVEGuMPQblUjql6dnBKNbJz7qkKro2/CKhKIDaskUTsWLsE4kBnsiQ6jypXxJIWWZMyrUsmtdyZPJCMJ5VH4sQB2RJnPLgoKdKZHEjKRuWd1HOCPkkjJ+cnqeDJ+J8CeqUfioYtdETdsXVeUw/8MP6gdp6VDqj8tl/CLVcDd1ZVdnCq1Qe7kW9endiVnFv1Sa3s1S646thbMFx3lFb94HrgL7dbLp2LyYFty+ePJJ4jzrX65WHkXqs1y5FfJpc0b1/gC1bORcmZ/srlLGtNNbQly9JUoJyPPRJgw0ePBvDChxovgDMLNw18V/yRNheoJH+l+C/gO1OPDdDAxx47QMlnxhtQx8cUGXDgpxRrwJJPx/5/MB2HlAo4VnxlquAoebav/+S8zFa5vsrbMntUWS7fjtko15P8UWV/+o+D/LvJ/qnBFR852hqGoshDkb4imXf9F9AWvxf4Hv7yXMh7Sp2ElFKmVEqfbJaoLgkWua8ulw7pK0FyD7pbwUdjAkz9GHmVsfQ5v3kYKg8VUcZNZ87e+J3G2Ux0rYsA+yEYjgvljbODoBcl1XFPNrTvVduVkxNCXfqZdN0DGsHuWfrQi8V+A2dJztrMJp1DdY8dWP1qmqx2zAgBEj1Sghg0D+4w73Tmx7GXBWNOFvyDE/FhMYvzcsoD878yzLg6mAQmNF0wt8XEpgdwrnafc+bqRZ8MkH8HhvyJMYcFCsU2X+ZF5KPuRjwP4iUEY+JuI8rxx6YtpAMwrTutQnl/uE7hdVD2miPYvDecxnQKGwIf4vySag36kZRU/lGuL7XJ9sLt40NnumeOU74IO8s5kz8NtDabYMZ3l0Rv4QLw2WQjrgO1QXsYoekqizYQ4DB2vzXq2HYJf0kkH62g7sMnp5ZHqgpsLNkTLYp7hqhtzv6JIUWi37AddSEhO73k6gj5UztKM9YCD8YSkrNjYE2ocG3YvZxUp88U+qJlMgwn0sZ/bVpGGvwBALftMaBWkAdEyXDUAijPRbvsWtIajMeJHaEClPkkbeZ+do2rA/5p3rtSJ1UnpLcNMhsnK/ij7Bh/DD3adowUX0JU4YTONgic+jIORxKSwvyqmodLSFpi/jEqLGX4DLjt35A4OhLJVw6rsvbOoXsLTBWxnZtp4yCQ3p/FnVdnru+MolgYmWf/jS8Gtif8dGpvyY8yXG13SWul6OU5qxgRKhseh9h9y5/DyONb7iBLNK0ER1EWrqIglxrz3jDakWJyHXg+D/Le8nRyZiusfJMcO41liOjoh5RjIwtIzs4zO51X2d4BeDE7hI1ZdS7OL+xlioD1Vc84SRKWQxKoSEfWIfHLQudRvdruUvgcwrceddI2FVUkFJXxreUluweg92efZy47X7aG9Gw3PSy8ObEEK8g8ifB1WNLzZgFW3ov4PY1Sr5vt9258un8NNFGjealLsIYobzy8+1zk5Sac0lETG0aARe6ixlz0sarZyR1CtpvFCoLu6WUb0iN9PodDzsgqInkuVY+Jmuxj1sytdDY/d7SVbabC/hOLwMKZRRU/fBixGTZwdF3isrRLI0XSYi+EVy8LWhXzPuPxBMCl5uQaee4AOi3JufSAqrsfjdqroZf6dzOgCY/pqvO2JNm7hCpUstKMU9ona0Dw6A8pHR+dcWVwniI7y/AOMG0wQ0TxR56oshRtsUiPL8ugeVzr2Q3eioQpJWpUnHjHD8rVK08073EtO6ULFfcIiRIdhfjHohs0IAhqK6LqonHwJ1WZqAHYYP/vzhHt2XfNUK0/ILL+5BzRPDliePL498YYHT0wpYden9fpIFstKRxOQtpy5M5b6yuAI722b35eoikxWtCb6SCGYRjG7c85TV7kP3bNz6Y7qu7Tb0Gn6+5w9ixhIFIBy/UIwVGIzH/M3pgwRLu86PXd9nN/d1L3nEodYIe2UGlKzW4JkyxnSaIVdZqNBNLbR19GIzCign6d4vMx1ROzaaS4dmEaClJCYg8dIsvS0H3vX/PHwLpzhFMO40mcNc90Zk4HZFczw0+w/ZIPMoQyzEPvesVAVFjEKEkTxYmE3nvySpK5BYHcsRSYskazoC5Ls9jzO6Yp3JAjZw+B+ZYmQZIL+HciM9hyJjST5vnhXM2wfPn45IX9MGUybUfgDmFAwp8Ti+pMXBJOEI97D9PGM3rxbZ61AeHdF6bnuQy7IyJJ3HjMDLl8hrkM7nMQtWB3GmhdjA+1kJXq+dH8SALpNr2h7KwFG2Dh9xqGjNTLwhYZTFEL369pS8yXeJjDpNnZ8w3dPkPYEKfnRtFHBkdpRNcNM61cNy8IvLJIDqVmjxeoKdHRM+qp6SBz+y7Ow1kDpxuEY7KKj+g+FHjpZ1VyyYaSYpw7os7eWyXpu+L4zhDGZe81cZSmb3wl96q9H1Pm36gJJfVVzvtYgRm3ksK9bFHk93XqsNNwijcS5BOqUU/fEm/uR/FmzTZIdx6RatM9kaRHx4S5g/qBLPLWI2667Qitd0fv11PAfHISxlvm0XkaQnJIVsNyQMda4PdI8s7y+F6Gis6twhNr4RNwqRIzMlx4e5/RwFnSsecSugDwbo+0eU02+uxOPzU8zHKo0Lz4qCjpl+xYd+NL7znUooGevC1U4q90n2YdcolKIJD5dcWGgOGz103IO+OLsnXsaYD/bD9oks1pdjl/Ezo6VBYfN587uBGT1YInOyKaH1eWiehR9WXMIhL2rPX29LBIMkQGdCZJjKewRykzaoEuOvcQL+XC98wPCETezp0eiUvrDqX5n4PIZVmi2CiZCAwXduI83tHIDxeFRvuh/oDEiOqRpMfzgMtrOTrZ6ywmgo1cOaGfQ4Ic3k6jEhkoiSalquPwBZgkMNDuO13mtGb+jrP10IIIjBmr2jwvi8yiF/efPePf5LkHgQueBo3v2tuzLUjNG2sQ6LAtPo8mVmAKLlDJCvld1AfMEUgTQkR2KijyQU06Gbrtexyfzbx82xEh2EknIcga5WaYCYrC78wPa/nPDgbO2XV6gkh/t5N35BpnSEcMWs7xPFfNuWkxhq9muz+dp5ceOnDRDlfau0jI/r7p2DqX6G00fWLBHHBO+OA6cZfGBkkupAhLL39swWJ8z7vk8tzMB6+Kc/O/8D7M2OWZrG8C6beGoGODJ21PMCKrcF10v+Yrorn1KwHZtmWaloRRN8tNgp8beqELbT8mCvkYJ81BtQnRy4U7YTadj4TgjPgThmEYRuwY7KxfdnehLUmjBVDMzJqIPlkA4bmLObh0e9hEORNUNIV5dHZyMYaOCay29OVVjAcc7a8icUaCf81q51lIpzW9i+AF4EeRlLBoUecXs9uJQ88V3R2eecHZQ37T/st76awmpoABRSwvdePgK4L2DjTgDRmGmYPAlvJONGSCcnEm304nqgofQ9RoytREer6PnyBJvm3kOuzIGESIXBV31QNVgqqxRELc6O/PAnv/dEAlDchuIVEbINczjD1HeUAlM8hN1dJvD1XZk7qc8X6Z/fyGR3h0PkiyTYwlQAbyQCqoh+ZEAlkjCGo+uJfqKoRs2JNL0tGUiLxayDzTsusPToCf3NoypNooKxG3+CI1LOKGYZK44r9n2GT79E/kvZZW1w5fDzcL+oUeVq5BHAKpJ4PimjOJ+15hpEqJ8cE6GFqraqyWrrRdsNv0wP3px1y6E2+zR2JeVM35LHwhUas1Aq5Br5mY8Hhr5cGNu3bFF7MAOSjbLPdZk9oPpwxKW92MDHGyfP/NmW/q0f2zzyRiXNEk8UlDHRcdei7co5Pw9oM7zKntM+jYyU0cJr7ZCFvF7jG0Ff623pZBqnl8jc/af24vxfvulygJXqXmybyDXcvcnnsFt4s24Qpp7Wa+g3zvojqoPku56zxEqV9waJReFm9UowrtRa9+0m7QwD8dhJUyTux/P5OrtSLxeCjw4wzxAljDiXB5iIJkCTZuyIzFQ7VMN1QF1TAEHH15vGfQz2yJHGqIvcitnCEqfyHT6DL9zlH7IyR2vKppCglEbe8vC+Gb/JxQr+pskRWXvLBr8NaYFsWc8CMx93aRSnN6u7ayLAr/SicN2sPKUY6Nb/CuMX8KfS73M2vaz4KW5wWmBYRDsDPqZqxGzxNsNbuRJzegMx1+eFKeM+HZjA87sbOAWHxJeyd0aO8XTVkw7qatsaxusQ3gSgf8hL5nAROMXe1A93aSOBXLuTk+1iVXvLiUcst8TnVfayE5aFIshQnW1sXtwompyez4rb8YBuqPindS+OMg4OFUY0N6KFftUl3wwie5K7XX7AdFr7dAFUdpLe+rNRszznluXluDHcBp+fMdE6oG4+IvZXL5c9OkUVbsiHK2nhz85pnvw7xUPqocpjfOT9FdYBKEFh7wVoos+tWJPwM8iV0kUSDwePWOvA3qoXPNGeV/nB2mQP/SVykPZ0Vf01BBdYUFLYnF1zi9fgBhycxtkaJBLxAPlZr6Cxhr2+5elMZuSZyUXuDTbDz0YHTcgNaQ914DTIo6mNG+dJ5rrCdx24/iGrmiHwQencSFzucuaDEuyljh6w/9sKzvU5ncL8ArbFbtvpXWsK5VmGiImHFeaTN+ckJFNotmFodhGIZvz1G/G+QO2Egv22uRYKLRcUQmcCWiagYfuI5seQ13RQBKGLCz3yTw8tmOQWfFAffff+L+O1c5pagbajBJYs24gGp/n/RAy+8kGi8W5OXQ1Zqio2IrMZNqajEz/9f/qH6GXY2PRnyYbDm5S9Pw1HD5KNxQ0FS0+r58APNPDL2V4lKwRF37IVxNgilmzj+9yTGPkfzDT8chAtj7Mv2hxLbU0IwV15ymH4iuPlxqrEMCnfJEyYzAt+kUIvbBt68f8NhWg70qNox6y2HBE3y4DAjGfiyoRwJOphg2yOPyVGGDUiOm8OWalYht3bX4+k4rZQnkNYhgljpXsoFlpiVsCgUhmiKvw8rIo5zidud00q0Yj6RwS5gcf1uCWHnrI+SvUA0xMwXnSDJQNgbjo6HcuNibOpKavGrsFs1QYFs1Ku65RnXKavkmXXBzpVta6pkk2xWo/dJ9wJT1pvaZGDmEmhngR985c7teNyyJYnBcizGOO9Xu26h+7cYyBaV1k5FXPqB663VQIMKosV4JfQeOZMQ+TmJ4GTqETmCAniuQYinLKB11Phas+YCE7f0opHF7jfsiWYQJkHKfwL49TlZURqlXN08h1OMGb+PZvArr/cFmng2Ehw41NdaXdRWXNMEhrJIYe+l4X1g+kS+f79/lyFQOF/jmrUOS3JJpDLYAmyrd94l1rEDg+hzYsf8+XaV4HyKcWlzUWHGJFys+3AAwPX7Dcxtfwgbryf2/x/z1OxzwjmlZHxFSaCFDiUAJInUiPoXFeHW9pVMo2vqc/Wmr84jT6/P4UvaRToWkDyttR9dLR9TrPrSJagjxaGqo69TmjfT9ysj8Ba0fp1qoTjR74w79A6sFZV6BgTr3G+JIT2wSATEB4beAsFGm4dDhhR19asst3A7T7fVasJI6gYYgVdq/o1WSGL41GGtPgVERN0ez0KCDUF7ZsnBPPppSTAIM1TO1EtTBdZ38IApSFv4bdxPUXHYzVS+XOQqUi3BoFvREn0A3VQ9rBM0Wnix/NUCK8NZhFN0nkxv6hMTUE5ucnQCr2bsoKMnZpnYTZ6OHSb9Dmeez8Oq9AsSQeiB4ieq+5afRogCdM8XX+WT4pkrHvyEgJPmJ4XhrBx/IRcp2wBc9DZfYbxqnyn6A5oLdETAcRA4KoCHnygZkNLXCh6P+D/KZhCa+vphPMs5y8343II9oPJ9LqC313Ng1DtCYFrrGOUFBfHg7Q1UvXDIY+q0vG1usbD7rj5Dc1fAC47iCELhMQ39vOXJNbAV2rmSvb2r8GKRYXlFSvHaOk+262wS11+w89NbGG+i3amQ6Kw6R3vL1Cs7dGJWWTiyF10cOpsPQgfno7qwLHIm56k2OalVgGIZhHOqaWqpybNMTInz1/69QCuw/9ttRzt+bPfTzFBW3BSsvWz1to5I6jHYJuj10M7YLhc0ChDXHVEEODUyX6nR0xR/3aJwjuAjlgULXXV0Dosh/yxrsSw8fDz4fn7/u4UF+Fxady86Vai+c+/LqdFtUm4kiyCfekziMNm33oXr5lo/AASda7UyrgRlfrRiCxewsyxMzkVsTR2x6/V6wUhn5P65CxADoyYQqMC5ZJ+LMLvJeBheicmOT849ilaqTN1DBX4kN7oEh/wviKandPOUnvOaUYwOxZSOrfrNsJHcesJPOdMhN0NmvOBwBK+WPHmA7Rqc1tFf04bn1JpkHaSmU4ry6MHP56XhTC54s+P7k/A7HuqpbQVP9gJ1KYRnetDEjtUp+bA0hsgm8iuJfVgeuPiuXAIHu5kgplDAXJmymRGjXTFI2/enZ5waZe3eUkJfCWZfD70XUFQDlGiXcRNKQd9HFFu92lP/EBqArQboLeBrIY2JM5Mf5Ofi3x+SxQiD8/fTlaWOWkazSeJlqnpg/GUUjPayQMFMOXO9EA5xJ6DT2IdjwQqxXHdflcyqtbRCdZNvNk7S7H1/PU6mCC4qAUp4RhcuC4qV7aDy4TPJfb7YGlXZzKnRinr/71ME/m8zj9mHhWG9xJzFdkZ50lS07qEg8uTkfzZUZ1xtClqvXe33bGW6hdfh68ulzxGuYScVXU67o/IulLhbpz5fIysUrYj60rfN6RY1TqJOSeHLqRw4kMl5b6t5agB/F+PkLgxM54XUktVHnsHhwuaAGojkO0XYCCngq8WrQ0A63e+co/+BU4Ok2fgV9Z4yWwrcXrCPAWlDs78fagOplkpDehXu4R1H4OtcOM9dkxk2DXxqtVKCqxERspAHLDXgS79wzzp7+fhRJ6eCYGCJRyCxoHVxAGYfNhiQTGOcOX2o7g4lu6sU4NroRNpvlQuAgcZNrXDR/MOx3SqSOvc4ZZOvrKY++0lwfPktBblh7y9iHzB5T0jalH4pzgbTNnn31QSEo9mOfYyQ8EvMA6N5K6JCDIGzmRpXlUtYIpBpnQlpNXkxvkUZmtfmT3FieYCcjHFE131P9+AaG6GSNyC1X56BpE7/KKU6n7LiaVqIY8OhhFwJzBsw+kT8QsoS7w2/VuZIHK+WIbt04B79fTkollVcUDRHg09gK1EpHfxJ4T8ZJzSsrsmIaQ4q2FOcN5UiXKXxZL0QispmX7Qrb44g4MfteK9PE9f9IUKIDHSgmQaXva72GivCHbLrOC8k1O966iQfIWb+vEIOoovALWWap400zQ055drdex27zj+bFIXnawCbUNL6VmoQAn3MJSEVwj+nWco/VuyyTfgalZZW2zH1JxNeEsaAXP/gSis2asRLxIQULhjwhylFccmDpKsH3k6gTRIPiAenKCXxB8Rlp5wTDhGJG6k7QehR/kAYniJLiHdKtEwgUZdKYgiGgyCJdZEF7RfHnkloWxA2KfZGus8B/KL6YNGfB8IMijJQfCNoSxX8mxUgQf1G8NunmA4HXKI4mTSPB8IjipkiXI0E7o/hhSV4SxBzFnZGuOgJHFB9N2nUEwzuKyUi9I2j3KH5b0tARxDHFo0m3HYEbivcmjX8KhiuKSyNdzATtG8U/S2ozQTyjeGGk65nADxTfTZpnguGAwkLKUdAExVmliIJ4QfFSSTejwB2Kg0pTFAxrFFdKuoyCtkfxb0kOBLFAca+kq4HARxSfVNoNBMMnip2S+kDQNih+L2kYCOKU4q1KtwOBCcWm0rgXDAlFV9JFK2h/UPxVUmsFcYfimZKuW4HfKL6qNLeC4YhiUFL+KmiXKP5XKQpB/EPxRqWbXwUeUZxUmgrBsEVxq6TLQtAuKH6p1BpCeWAZOLhObySo3OLA/hw71w2h1S3LwJXTGRoJGn5x4IunMzeEyi/LwL9H57aRoFziQHjs5BdCw4pl4N7pjF8kWq1w4D9PJyZC+cwy8Ml1LiaJyhcOvPZ0br4QWn2xDOycTpskGp5w4OjpTBOh8sQy8PvRuZ4kyj8cuDnHzuVEaDi3DLx1nXmSaHXOgR/OOlZCmVkGNtfJVaJS48Cdx85VT2hVswx0pxO9RMMHDnz0dHY9ofLBMvDX0blZJcoLHJg8dnpPaHhgGXjmdKZeotUDDvx2sTP0hPKHZeCr61z2EpUTDjx6Orc9odWJZWBwOv6doOEaB957OuO/QuWaZeB/17kqJyjfceDSY+eiFBr+swy8cZ1dOUGr/zjwz8VOK4XyjmXg5Dq9nKCyw4EXHjvXpdBqxzJw63SGcoKGQw5893TmUqgc6sAvR+e2nKBgZcFMoLksVkZmJjTnjJUVM4rm8rJygZmd0ZyXWHmOmcFoLg8rDTPjQnMOWHmFmaY0lz8r15iZleYMKMql8YpgqFDkmXTRELQ3FH8eCU1ZsBeYaEZTRvYmTDjTlBV7iomWNeUCrbuWuRGhQ5R7aKmMiMwQRaAlKgkGSNlAiygJaRHlElpqJUGDKLfQEpyITJBSQ0tyInEuP47qnE6wRoQ2iXVerK/I+4dk4h7W4H+/HRuXv+apYf8N0Vr8N0RxWen/wWx29dPfWuV15T/dPQjr+JIf415zEr1L6/YuvXTbn37WQ9r33A8Gg1/Lxq+H74qX8fE3xFN5npRn/n+QwN9a22oofkrvA6yiaFZX7OHJ9tJq1davV3Errv+N32+wqahr/gtVOUDVOUBVxqCo1AOA3oCqduDdURQuV8DU8Pq/BaDRS0TjO2IxQldwFY1jlWGhZT4mjpUllWOGdiUHRk92wfBnrkC72xv4/geLIYvoVZpnHCITuScckLsqIM7uoMRCTcNn3Dx1GtWupPlCQcMY0vWMK/YmaGeWBmfdjZJ3xNoKp7oV/UjT0AtBTZdy4rIcOUoCR6K8kNTa3Z7aE2s9gtWG8SFGxxM+TOiqeXZeVbOsBdo3FggX/KopAWGRfGT+vUdGlV3qmeJegMZ1JtAvyMbErj1ehMrig0g/xxT49+DIf6qaHfM4N471tzv499IEO/UbeWRlp6oMCzp50q4ZIQM1hrRk2gTIaJJ/02vSJgQ076jBYqAfV2S6rPBZe4sj0CJGAQYrS5gIyjUSic4BmSicn/BE7fxNbGhdDhQN5nKgbpg5jFKeiUcc6loT7lRZstpODKqcR5q0zRQQtSsONPq2NSKXNCOFsYzgcc+4s0D9lW8IkUZFmEdMrUAUUxEsBlRFLCrqIsSOG6QhwT2AoKmAmWCpQK/ekYwD0pOgQwaS8giNJOc75BSwhQoUgXkRUnp7hWjuHZ3sS1pcbI68gugxWpfIlxABHK1kkNn+r63PWMQ7bB1yB7HBeO4H8i1EZXBSLc5xQcwNakSfICh4ysh7iB1Ga0Q+gxBl0rc3ramXjqgVqkD/wZ14gW1AdohHQ0XkBhEXOI0ac4BIDtWjv2Pfjj7YSuQtxNaM1U/kG4jgcJwhB4h8hq1BP2ARb7DdIMfiWVg2jOf+IlcjqoxT1OIcHDHPqFf0TwgSTwG5GOJZjdYa+dwQMsKx1bRWR9Qj1Bn6Efeyb7D9RV4Y4klRS+STEfEDnAqNWRSROqh7o8SD/DbYjpHXhujduPTXyFeGCB0cJ2QzRH4J2xz9nEV8wPaMnA2xcSYe35DvjKhmOPVanueOmM9Q3+j/IfgTT1fIB0Ps3EtWkPsFIdGkr5WW59oRdUTt0d0s4iO2F2QuiMeMEmQpEUecXjVmMUQaoDbog3mQ3wnbKfJmQWyzcenXyNdKhAGOP8hQRD7AtkAvl0Vcsd0hJ2UJZIvn/iEflahanJZanCtFzFvUH/S/RrDHU0LeKeJ5NFoz8oUipMDxUdO6PSPqAnWBfrzcy77H9g95qYinEXWJfK9E/BWnM42ZMyI1ULdam2f3ID8Ntl/klSP6zrj0K+RLR4QGju9IZ0S+gq1CP10W8R7bE3LniE3HxGOFfOtENcHpXstzPCPmE9QX+j8j+AJPK+S9I3ad0ZqQzxwhPQuF1tSNI+oe6gT919yJl9g+kN0RjzNUjdyciCucvjXmoIhUonboH2bfjj/YDpG3jtjOjNVv5BsnQonjAXJwRP4X2zX64crKgU2RI/uoG8bqD3KFqMBJNOZgiDkoQx+VAJ5ALhDP0WidI59DiMFxrTX11RlRG9QMvSh3so/YRuQFxFNEZeQTRCw47TVmgUgK1Wpt/nk8yM+ErUBeQ/SDcekvka8ggsLxE9kg8gJbRD8ri7hh65EzxGZg4vEW+Q6icjhttDwnR8wdakL/VoIzPDXIB4jdYLRWyH0hJJv09U1r6nxG1Bn1g75Xd+ITtldkFuKxRQVkGRETpz8aszgijVCP6H/UvhUfbGfIm0JsW2P1hXxtRBjheIQMQ+QPsC3RL8oi3mK7R04mAsZz/5GPRlQdnC61OFeOmHdQ7+hfSvASnubIO0M8F0brAvnCEDLDcatp3TminqEO0E/KvewnbN/IS0M8Fagr5Hsj4p84QftFT4AYrFu12bRHvQYl6g0lSopcG9RrUAbvlkGfOIMWqNegwy1fRCAPaHVU5PqDMimhtN4XhbZFrgvUm1AKnaMUuixy3YbuNziNV9PoDadRhXs9zuQ9MOm8yPWF02uFM3kn9LkedIJ7JU6v/zi96iLXDvdKnNLbUeo/Tqlr/B9bEmkF6RM03so6MveWosQkykY0xqR3ghSJFhVtmNMKL+qy0kuMFr0tkTFB7Z66iNKCkDAO0kWJ3h6RKWFta9KepK3ISxs7ZSsxWUQbEUvQppXbSE0rjeRUKY8SY5PsgYgkQHvq8wAbCLxDRzAiTBA00FApAWagXBNrO4eVriPBaOM6MvCLvdcGBnLwaYjKdXiJbdRmKQ7BsGIHQbsVsIJuDRDXcU2c78+VVdYJXac4ypiMniwaZXAQE3zKhc4OCsFjTaxPUNUm9e7K3bM4BOsrRD6fZ6BdO8adJqM4Ab4iVpo1ZmBjJwdg++qvy2srmeioLKLYzn85qvdKvol3DozfpT+7ObP+krsUnh5UpDgoHWBVdXfuFFkjipxjhFe87TAx35S8wwv/7YKmin+/z/gd2OwLzApEzoFc0W1YFrcJMmBcp5waW4P/OtG6js7fJofv4Ln8wdnfK4s89BvMkrNDqrt+YXsOYYmPycj+u2p/UnsdVDAeM2qeoPBsECkd5lg8ppu8kKSyC5cdzXIxhQueyRuDpnbLIbJcsqgPtMl9ZLDvqgyvFYwOyx62wnDYYnknGvTqPP20sVB9doZFze6QyYZTuoV2P/Fs36HP6oB31fJ1H3iJfIlwAPmunrBLcMPQJk6lYudsWmp/lzjg0ywOKfkeFlyASzwvWX8w0NPywFn63acDDZvGvkR18fOgfj4hw8e8L/56tS0wvzrn14Hwjm3UjSqskxnWbGlaR406A8xr4YZajRSF6rAg8rdi9/yqpFmDaPrbWweHkCd5cD6MS7Vg9gEKIGll4TS9VVtuxRK3SzYf+J1hrWMiOy1AtMObmTLjxy7h4Coo/LHl7etfrwJuylCJu5lgRqWfKPWN5WlH94uL8oFD8If7jfylQ2AK34Wi0n6kdJOA0UFyzH1yDqiFHv77d7nCGlwSKHFw+PR6tYLQ15oVVgdxH2EJV1lCagMd4N+ap7KIqjNXdjgkYzaqiGMtBHyqxKfz5DRs23k8bDLlgD/ALkqdYv7Rkx4KgL9aoblrGTzDMz/jUW1h9V0vaAZvFyIdh4PxFFD/SC5PQGkfEHoiSFO1Up95HkdrZpd+bfle9B1wF5eCwdNC4OMhPdatZ0/rFDzUVpLJUC9RdDvnNTvXok1RPauFmoUKhyiXDMppxJcIvKx8ZopIiss++LmowAlVOXpftHusF83zY+z+mXt14x/ETZb1p8c+Nsw2AQbw65dw0t6cEg9DSfNrpUeq2rvRAKuvztu+QpDp6LvZl7JQIl2wKttRepFFS7KzSOyn3nuEX3LSbt7DfSj+MMY8vPRap1aDQB7uTKWdDH1j0KGSKTvrT1kRJ/qZGlU+jRY6rZC4aCFMlycfVK0um16eJhn6US1B8Xoi6w1IXYUQlCjeffjx1Jhca1VDHQpBFf50i5vT/nYDeC7e2pc0iCb220b2ZJiv3YRx7SfFhAMkTfOkd2AL7ZNw0JR8F4IGDtXrms9rfIsNrh2iSgiSjUglc67sfEhxtaUQunnAfhOAQbvGCUO0wBOtyQVHemHRF9aXgU9RqQMZVbTqanVtgbGUcSc+l4a79So791YLq+PMsk9xFr7DZNWUTFPpOIRfSUFyX60IFeYGFGbR8LwTZQ+R91TCeO6d6RjMmqKUMhKT2S2cGq6ouWak86URCs96Asv2n3pK2j7bOtpxr6OspMamoJ880WuK+dI6va3SomEJJEvSmjaZoeYT+RH2DeRuHfqnLPw119lPb4148gi/17xZyHfzEsfLHQGs/24iTyJGydF2lZ1HcQ/Syoy/75HEXepR8hjTs3C/2+R2DjN6CJiMalGh9KoT48hZqqB4Hg+PIAvzq2kaRWhKyUkJWvxLwk9f3dJt3Tecq0gcIJqSO8pMFTRjm78rxavGHjxy9aAwA06mYX7qRKYqZRyvZ47j4YfPTmEFydmAm1a/ml3ISz8Lgzl8sBIZ6QjyyfAcEIkS5JK66XfCuvlz8yePSdHtPPzJwXDx+ILDsR1r2ym/V705dKPn3PH2xmKrVPKffgA0DqgU4Ajg0gBVf9f0/Co7VvniVxegxfF46f/VsN0No1N4iIo+BYtOevnll6eaXvVA2H1bFak2GSBkskINbYydSUfH3ECvjeCypq1knswnETaq1hmh1jb4Wf/f3ynpcEMCdlamMZIsiY9P1WwjPK55YCW3VGphWlGZhCHFbxugKk1WoVfkXI+8qLV4LVW1bJiclCTNJwJikUxmQHzLzwOrUIuslktxR+3/596jf8vx49Ez9IKq+s6dw2YOUxlRDBN4xcp3YRBJEceYsUzEM28+rqbRkCzSs9eHqBtrKs34ykRyRZrY8VMhHdZZbFuaY0gkFLBBO/rzrvz0L+dasiRy/ggXXTaxwGcourReLgsMzVnDTCb+gBEATUxiZNsazSnQcn5tM01kYU4F/8rUAuqKeUVDGqpnxVs8KfonVx6zHYkPM4H9T+IoCewDbWNQGjMbsw2Hq5P9g6kRgzUqkJ634HEYYzecKnF9IYGGFbGnCVAH+tqBFcqAaN0EPIM008icmEc/Z2aMbdiPPKmDi60yycwBo1po0FgyAtnZm0PFWZnHxd8Xg1odJ141lTAVil0ZEDG+nEreQ8lWist8E8pHJxF/NmEJ2rw3vyC89ttBTrjc2BiX+HgAm2PBqTFfosgNgmSRbJO40Mb1CBdT4FP4TljA8r8orVpNoujObicqbhYIqtcEsh1ob7nrPGsKGjXjlLTyliCZlwgVTcp66rzG1mdkcsWqXOcY8PQbOHiN1FMaeNabvu5d2HSiymfd/0SozdvQ8ZVyOLQZtmjpmFr5JonrHQu+LstUyPA0lvgFLu9lXZTWIhI4ghSPsoxu7HAbER2NBOvVeJ42h/M1Dier4+d2vozFtM0VdB1bMrcK6ckZYd1UaPFvhCx1EKTxb7+wf6YJMrU46a8gBVPJdbr4/J/RMBbclyrOi5FsnIyG4KH05Fdq3ZzKUUA6qX8uvklMUqrFnCqQEyyUlgG7CoRc5EBjj6XSnPjVWAcRNh9vFcw5VN7S3dBXklbKjBwmalkfmhHySL6aMmiuzny07tY4YpAQjJoGt9/c04H3v6BJgChyU70r5A8nYXwuP8o9fDfXeef2N95FE+WF64A4rbKrc8wZEq9J6qYmji8ZNcS8JStEBwEr827mpctuTw/hI+B2ygTuy1GgIPFZa/tDv55CE2V0/9wbIWSl+xaRup5Ujo/un/pTkSpcfiTcHS2TvlwiMLC/4+3YwNdhyXx4enq0vjaIGVtONoevPJ2EsbmKJO2OfsK0hzxcFvnwDl7AxB6Mh/NXOVYAcZ7+RLf88FMtORwBe88vVVJuMF4BuOq9+KhutNOoh3EALgDQGfaG4E5/e/lwC0MaJDz4UJjN6c3EEk39uG1gsj/uKmNwA+xUp7nx/wMUGNTzh1obcE25ewxN9egibBdnfY7mIHuHwdFMf5iBss3LrTMzZneO6CDcaBybXgDyR/3CGb6I+oyY7Nf7oIgruyeGRrX/MHMcE7BHN387/m7fhPtGS90hkJQHEcX65o5O45ZzDZjlHkDKwGL3X2pBJzDwJdr4dYhu3ZcabKLh/4E0FtuTveBH7pz9aVMKaXvs1D6YhFY0iQgF4B/PhvgUdaUbHxtKnON/r3pzk6g4O+Vf2gUIigK8kXyBrOdS7AY8JvXSyYBSbjOxwLCLZZ3/bVQzHSv1ERyVlx1ua1h2pw9InM+a9QWYh2GDre0s5fn6jeSoUc33PNtiBUPNo/3C2hEHJ48L9/yUy0v5svDvuVEnDOcRNXD+Qj6zGN438lN/aMNWRjFLMVwduGBLz9Z4F/nGd835YIZIA46bJb805G/ez02EXFgDWJLQHXN3xY8DetHMQDsxGedljyi7u7bk/TJL6HiNu0/nzZhDx+3/1QFsL+tt/1arCKereRLK+EdpjH/KdlmETce0NqBPQuCfftJ80zTphKuLq9GqJ1TzLve1RCaVNMC5JFkY4rL1UKLVMRc0lHFEWMRU5/elAeJWwffkBSLbDGQYnosdOH9nuGqA7LTCLSZiusH2+fbualM5z8sxjP5/B3Fd9F6yzSm9Vjxw69+umcs5Qaw0HCkdxHA5iZcIYIjb1dVA8aKQ21mKUhBCDo6iI6oKmIfK7auUP6rzi+dquIizq9vnqbc7CznkfDsYuC9kdFrkGxdGcuOiK0rvJyyxybHUtjV/zHDCU1RuRN3cFDN3lsC6xmeu+amTVFmOk047PfyxlP2Nn0m8nkXmGVO53brAViS/DCD9ffInke/9Z3fcBPoa+P2L/MZid79TXMbuw+XfeJ6n85toIpo3vQwvQFJwXcR6WBIzRbdwv/Fgi4ILiXuyuQxvTa5OYW55B8731+Ig8fGMQTyvmQJ5zLVbM9O+lWglCTbbzAcNQnByJpIfxaVDR8gydjMc4mcZOykR8mejW15T1OScnp9xlx56I+rzY+gCvqrlp4NFviK7I+ai8YQiYUvuioGtrVV+xWfPA+7mBYS2PSSi09x/BnXwR+o2h4viQu9SRYaf+7VI/fsuDEBjQr18bX5tW3pddyuFb36WSIjL6OWae4s2h44wYV9ZPZ3DkPq0snxaR5mDtfy0Tpe6puauV+htq7oRp3LsXqVOpAMq+1OdqyY3iKPmn/6StiTCyKlrXjtKEGY0uPbNGJGR2eu4f29jarTg134gUmEq5ZpPdN6rV8JWukOovVjZX/t1MLDTK6Ot30tvbLrtp1aPk+0qbfENE/XulsXq+K7buXTZaLrHJ8pcDwD7xPWNXfxd2W6u1MHi4Crsg62rdsIiaMxsWWvZqWSdsHXdS7zcbtEwvaeog9jxjNPX0ZR7qCqD7VpLzzmgDlu2bW5HINZ3ZGrrTj8G1bl2V6oy+nZWU1ldu6f9IIcUCFXZXrMvXWw9XYsqGqe2HjQDhwtUTjk0HNF2qbK/7lG0ymw7totWiq0ns3/NDft43VPp2kq67tlfo/THay5sMxzNpyvLZdidfNUrsdOonOy84lWIUCGoUnYmnh8JJaYr6am/JBu1g2FpZX+RLGeJ22lfpEZdvIayrrihA8AXL1SRVcxPK1h/DoAFr9paLH9UNbArdwej2OdsQSJw/fTTYaBsfRHjQS1hh1wfB2cJsC0Y/TjkqPs6eJxa52QN5tMCzYfSpMXxt6uHZUVnqeAtz5TrHnqyNLX8eVM3glRXmQp9KSaCEz8evcYspOg5d486pHQOhsOKr66G9OBVD11XPqlv7LowLPPgRg7fCB7qyjQPHPu8A57zyelgnuSM6Laferv/tQyF9av0J+YBKlTPr2zRshWvw+Pr0E/uV8wIscnS75TTHE3a5KzINAFMMxeDs3t08kBGr/u8B7jJ4JoWoE0dSeNjaPr2ZCU+snqrMJNURRP2KU/+QiGJ16t0gaWZ3ZOzF2PHDKjEMPfIRpHC5Z0mgGWEi+Q6srBb8vjNomJgH1CripkylEzuv/1viE23oeqoLhtzptSl23pr95g4fE6RzAmsrqXDvVFkKDjdIXTUAkU8hLPwrKHPToZYdzCptNT6AWIOkVJ6/vCs1JBJbmnrg4YcKgHk/NaxzmC10XUtHc4YQcKgsLKGDkNGvucS4YtTAuleilh+Mhfp0JA9fGulzgBVNb3fpkynFDxpyAV/3JxKxwDpiosRPrOIqpouP0thZSE6Qy6q6sP2KGkalVTkgkW/GWV01mlZvLafdIKV07p0wv2g3FLEApa0Wjy9BGHLdRYgPU8Gx6eXDpHSJfJY/mXMwqtq+pz6wUGHfAQXVfW2HEXhfHQRoJbhe61gdm4Msqqly8YZoskdakm1ZQORuwRd1Wtakp66jSZW1tFnV40LYOeh0bKyuljy21PLdAeT1OcEm3doT8a3/J3YmY9IWAi29LjccjzBm5Plh/nt/PmZfbiULdEyt+md6ZoLqNk8uebxBR7jNzd/0YacKnrOgd8PVZ04JBb2WmLU2qlWzvfWhbei/F32qF/dsC20sAldO9sgR6AULBGLllXzON+nRTnbTNsXX5teXljmD1N2oRXVHeqPsmhbUKt7u3b/TaXaYR7FKulKPwmFVqgrFd0W3dzL6g4QjiLdhR387l48ZKLA90EDJZ9gbevC10fNX6od8usXCMRN7Jp2qP2LJ5P9XblD3ww1//BFlsf5eXFLtjD1OdwBUbuf2w3rqPBPgCDKrmRhLmz7cwkaE82Se0cRMOqAwxNKOpLvNuDYzIuteuu516gzO/eNb4IdcDsUF8Kh3eaPmXiLB3bbsgw8jYR3SNGj3+LjCuPz/rMs5AXT2nMawD/xKzyp7I9oVqbl3Bnz8ofkcf6DIJRoUa6IyV005bAbqht5yjdyphmBPFPzbcIZ5h8Te9eLLaN+7x2WQ/NjCYNIzho4V3rba2g4ICIR86VmcGQwBUB8OFptGYQ5wdhxI5WG0zEkD5B/HgEz5DwHHmvWvHoGMUnjSIenCQTbGObjzC5p8vhmie67S5EhZDEhlgf4JW6Lx7mXYNNGd2wEzc8kpdUsSsX3tlune4ZWm4c9iYlJs5ILBexFT81dG80foN68j15Wo0/Vx7MaLUWgmBNCl7Hd0K/PIE9XPB+/O1Pe/pmf//Sr3222hjGzYfMjZ449joaZiP0U0SbcobDv5nm0L/MJdoVdSuLnHJQKF/f3glWM87Y1CL/WUiRX/xRZdhg+BXOyt0Y9PVPV8ry3tmK9iBk+TZ2fAI6WYM1taZbhap30Q58BKWixaEi3KXN/626rYgcuJjAukfVBC16Se3rNoFY3iLTGwSJoBksg2ko1sMADdaNtUeQt0QFsrSG+6G0GpXc8fdvbzSJoBgd4RAvswbwLMWCqiM4Hf7neCL2Y1beYGWnsPA1JeIOvRPOwnXJRGyUVgyDYePMg0XYzC338HwyxAa8XNBbwrZQzqhrm9RfSNgK+ZNtghFbUVCg3BjIf8Ug2MeiTYG6Y1Vy4RL4BQQC9ORgQpJ0TtnojxK+pCgpKblv6bXAAFWqrMQghhkEuVH+eMmTSoe5EvbocDWekhb54wrSUELpqkO/jcGdA8clVZQ64CstlaJkxA5CDFB45EotPQhLChuYm4YNnN7Q9kmWFbqAYewIj5SybCyLHPSVR2SmK+cJXdkF06PCCUDftj55tNMckuqkDvdO1AQ5lxlb70Laab/VoRZj6uEFG3RiuDwRBPJ9VJNbmpncPhCRzmCPUIyGHeRURMrdMHucS4UEn8BIB+mdIGGOG8sHgkR/vCs1RFzO4oRgxsOYJ1OGGyrjHUqUvEcpAqSniMh+uBe7MwgQmHfqogEiLwEjk2+vMl3P1+tfS75IxMANeZxV5GG9eI9997/Ru9FkohC/fMD3Xqmyt/Svq8K5ngJ1L+ws1WAZRuwHmeI1U3mjxWuSwJcUa5YyG0JDG35c66g3FycfeQ0uPs78z5BBtV5jKGDamLWOc/Ju6d6bsC4K02Dv2lStO/NrLvbh9hTVWoYUq6U4XFOjoAdWmfSFX0smGgOKhRZUSj86cgnjlXFgwN2KOxmZJ+4VJnRhTCEk7kt/aZqWl7Wt3Hu3UkPgaFtrqqsfQdLiUwTgcgRkJZux1CwP/5dbOMJquDYjwv2rMt0JHcCgc+0D5BJ5RZFIjZFNPoZEJWdSsceKhRfBMQKLYark67EQ+Rs46niukORz6jba+Xuc8GoRb03CqJku84U8w+YtoXMHHoav59QbW4vllMpjT8RCMYU8SrtSJXUsWXJJmLV75x37WpsKLYCh7KnefvHYMczy0YBIzXrEeezAr1zq7FbmR7AEj40MRzeuKHCexGK1SEBqRgSWUQN2UgK85jgsBQFaXeaRQTyOLIWtLMOZIbpCzWvGi6PsH50w9W19GSqzGa8DqzVX0ES7DKJKaD/mnXV+255L448rxJ3+YGajFmo7nCMQLUqy9unomYvPWPI/y4RkZehC8xASpkyz9sjCKlnkgQzt1pl61XLhyAC8FapM0xrcySMNTVk6XnSztMvSayCuCeLMLBryoPDk4q1FnmjIs2xPFcy1jIWaJevIORukv1U48YLuELx7fQTJyu91yyfv1pssvI2kbB+7P4ysaf4XwT331VpqTNsfyxsBnH2+/W+LghuesT1z6rx8aP9ZtxWNGY2nEI9SBE7kQ2UAMbvlSOGdAUPQg+SMjsUYul1qQnk1V1jTPyD8JYgZIdZSWJLpd+bSqfbMa7VF7DNYOEbQpNXbeOR1/6NU0Z+0xHSQlsdVyFuWYdJnUPMaq0gf+yNlTRG5ILQpeiA6GVEa3PQOrPrUsDNqghrHxFU9YupgjkZaGpo+swZcIfwOjmNI1EaTZON71u0xIXUe8i/GeTx31LjDtFbU9AaNnJMlBxDTkaKiu4+Vptop+UjPgc0fcVJs2POrdnlx/kwvdbKWYVGqICA+pGdInRPJxas3Z75pHP8UO/Ugv9O/Fu388d06YUh0ljdhmD9W2WxeRkFeJw2VVQ/qkT3lrCuOKOSknbWSnn2ejPt8lm+sp1Yjisi0+QlEttkfFyvxPHUwk4yl31Tg1z9/WGnt014gG1esxCzNAMPwbVz4E8PfqTUzp5ke1igKW2PjU5VB6gSI3k8EFZmuyedJzfCiPHHx5CbPTgJmC5MD0MHac+5enkx2NGXhfWCffMGoBcLsIJYHN9vg6KEVbpj1LVL+cpunLBeiR3HKJrHJLsChk6q1F7EIx11TbfhhqX5KIyAIsqAU8Zov+TVswhrG0MWcqEnzqyEFGj+o8aL0FhNpATVUbnQgrr8+gfr7nCddN4skESR1CSfdDxl1qZYhVSeBU6kbk/MKmbw+iuGh9kEbJ9t3FhoTn/LCN1Q0FD0WBYKc46HfStppT2LbgBeQvsydcjgnUtDeEzfYH1znrpyssN4+OUNMIqaZxEHklJWZuBzh123j7ju3gERSiVSH2I4frgTarUXvfRne0hWxtrQ3bVMurndq+fSL6NvNEmt9N7C/IqV/VZE5uhftTsoRUf6eMJymioOxk3tCaI+/LGrTf5xd63cDfipWyrB2jpqVlmCD9Fi5sFI2f6xSL0UjwcMLOVvu2e+RsvNlHYUGrwOqm/kDCBkUrjNKjULuEkHqohuwl6chvVIFIL3O69Rm2P6I6qXBtsJUDArWjxbRpKdgCjLybFzVxG/l2F6wSAD1FEAWRY4pw9zi5NPtHWTV1JgwhWTSIsdIqFA2+jEJWaDztAtsjyDl3QYxY9DmebGjSz1YkUBifirOmbRRMpex1kp9NCiaVbmBbOpkrO9Q9m/eI68kKQPUlb+xIf6Asda5NmKJ6ZcOeGbO4fatrwwb6A2hX4rpaOEQJq5Hwt3NIdz8ChrOzc9rjRpWglR7/CBBwxNUdjyEevKlHSQeEQ4S7WXD1qn/vEkb9bbGly/mTYjOovCXY7fTK1cBKYhpmMNnFh323IyABBGPdH8Azl0NkLojjb8yj+hNZt8IhkFxGVrpKlE3xQg/LhzwEevnmozNijE+Pd9w/iU9gf9/xL8Sjnwaw5nnh46KAXU4gswA9vDqgDR0W18gcHLfAphf4ybH2rVcIYszO7KmxzngFpS4PWCzdxDHUelgG1MS1sMTcuLfGHf7PoHX1TkQI5BC2tMJ1Nuk2Ys2yQkIkkWxnWsi2xySfZ/TFKd4Uzq8gDjByoCjBAh1+G85Pctg71Yj+QLnGDy/IjcufvO4Fcu6dMHTLHrRoUMvThYOvGDodMv9barXo+MKSr/lyuUi17wCOqnqJWAzcFJNdaoTVZNuqe20uLsamWY/MPbYGQYikAfQh7KllzsZpjgZpTLj94oV9KwQqz7kQ/ZMpvhuNI8wNQ9CInxhSxuiRMNIM+SJkG5tIKZMsw6+wE7eqMRmp/kL4W6dFKSezO4w/3VDLyLdVdZlgH3CTatWWeJFs1BBsbHf26s8a8CmCmgllAqzsszYB7BHFcp6iQ/m54y2vPv1lUcSTGmLhybLBloDJ7VOmv4ONIGFvWdTmb2ZFalg1Lm0jJayfIO7e+IdEb8EEWOzmHlDFcMo1WD2VMOseuQf1MDaRykKIOjVGDOixcX1ZOOJGyoQPQg6XGoEd4xQSQyLtUpg/2hfgMZXDeW8gyfRnB9hTT+a8gf7cNs9nRhf9ndiaAHF1QgIExEFBX9BQ6LrEMj6KBWqttjKoiR8OzmRHqKeWSKrZwlFQ59MDm2lb2kA3i2VuAnR+HIYxbhsFsUHpXir3YR9HhI+U0IKve/bHPWDMZTuaP8UIcQXUMsTUhuePae8vYUXU9nleOxjqx9NMuKWvrh/r9SmVFJSFQ8+EkjjrPjs01ua6LjYUuNoNNZjfdiSriI7Fjf3jPT1I9aBiH5eH4CtJwZ9m7E223StfmDhe3wYNKCPgXW7BzMEVFHsp4sszKSek4eZkYroiYWk5XqK1FOJVwiKjdvN9J7qXvhQjVtoKGLAHRYcLKYoG3QqmOQHj8hBQtAoxuF2breNYaeEBsrgV1p4QcNfnI+pJtgJa39tZH76jt/CZtqSQgqTGxXC+1guo5n1xaiApavX8XCwxippjNuDXF1reTNWTrvbn1xFmJmngRK7WQux5wjSbbtt+m78UOvNQaqEGo1kD8f0eRJDod0nPolrHrYLmnM4azNYws5a3OxtJLMmwFIAwtvJlP/rxuxopQjx7aDJ/QRkhIKymD4ImsiuxuQ2hKJJOiHsjwE3x0xQre5YpeSvAGdlJWUIUhgSmjS0fymRQMNGCEG8omv+8vGGxw1pOQBqIlpOwTZ3T12kEjxH5E1mbfBa07+KDel5hFqSyGmaghnr4Sv4sqPjiOagUTpIG+Gx4md89nG/LTMYAnA4zW8n3yT0smzXZOYHuqYY3Lu7wcm7YlcKQ16ILLyLxIzOe1omjU8q5VA5vOnm9bpHBPgltUjzMVpCHs4kpWOQ8tSHor2DdsEPb63WlfDghR5qYI75puajEevjsgc4gxc+Na/r/tFxw+b/KVncb+k05WG05NF5nNHSjSeubKX3tk49cx4gX53PHBhhCwn83EXv39+mqN4NeZ6i8kTSlkBCCjNoMNJFq+X+KINFFVDtVROBizIdlAhyeFwIC61a4l378X2a/rYZzlv04pj/IytWFpen7bUvqCcP4/yUoBt08JsAKgBRNRFVavxq1rluscQrwpA3rkiqnJjUpjXC2HC7YN2XU6H0UK2Z0evktrdwjR3hvjHfjZZaHgewODIeLHiM5t63ogMQhGLvOUA3wz+f6p3pJh3qYfmILn4dajXpVr4/71yyfjVp2FYktrVBITZexJB/4wltpK38jcPhHMuOq75+71XQwH6hXjhsx+qYlkBuQt2uWrchzqjpFHhBLwiJ4XBEDpQ9uREzVZpGXAg6M+iBJvaKS5kJAi9VzxLqBJY7fz4dOmJ3HFUcsEglU5sJIS/hWSUQethor7mkiBkOb+fdo1xly22dPWnCNKBezZP9sdLBkE+ZJc5+USm9OGlUcZQdQ5KK6emjM8T8wAIkJ9vROKJ7GuGyG7BvAdIs3MnSQ1b6k5R34Q71x0cpoRHAel8y69ti7MbKGH7q/ja7pG3kmtzIjSv8sAJ2WgENgKzNch18DCEc2KHTQJKQuq4XUuo5e5G9vscLq6b0mQMGJ0n2z8rXEV3BDDg1XofRwEgWIlyw4KZtEkUx5oc+8EnLbIFXFr9F/96Yw9gvTyLt/mCu5+gLRZqtk7oDDZnj2UkefF+erPqJxooaP/ng9jQGddp2t1KffcMlsPW/lubOt039mI/V3lzw9xtN/ITw9eHCarF6HTv7FHJzczcHpHRycInBYUFs1megbMCeYJtaIbeXtO4kEqanixT/V8VNg4PdR0tA3pJutlYRH+dRfEn/u4Nav7Ec2+TCGh3duwn0QBt53/Nip1sh492hm8EU8tbMnL5+OvPLI/9x8IRMlwZTjgRvyPgkfd62+T5GcXGX3IyUQ+RaCqQ9VCxKmXXiyuQ6x4/iae5pMVVxx3sbvoQexwIA7zJ2IcHwIRSwN/xsyb7mFTaBYGVKPEShMuTSvJajlovF8zKVATWraLNOQNSPCAUfzOLYrKeYNpThnFT8YjKyZlbQptGAb2McByje2SkrzT2YGj2yW8ngf5BN6t88m9d9+cD8X7VcW3gXXzaDI0Jqf7QjT7BhX2UFY16NvZI1rC4mqebav6Om8Y1QBN8AqzqwHKvt40LtJgn2p41dxfYHK5avkRxvbtPybE0uXn9ZYLLVgG+PqJnyp9sqDbchGvQi7P5QcAFT39ep7GgvN1sfANj7ReyRxqKvUC5HvoLXGSGst802seP1Y1UjivpAKqwRVXoMCwWKSYql5ZRCHYqMk02nHlUhQlCIYFiumewQmG/x8+vs+E+P+aO8HKS21yrFLzFmlAvdgP6rJWw+4Xa8YOknYaFT9DfkiM369jxj5GEFkTmC+MlHCz+NdevYE3maOU2hLRYRVeR39hRhxqA3cMq529cCHBvVhRFLxfEplAKvhTCRFYVH3wTSESl8NLS5hxRpDPcthd/rYbEqD8fRPzwqMT1H4u3Kvu7oeN1n4+DPsQarymNfWtMnW7o07oofExyQWZ2o+KhohW5BAHIXJAOM0iPAee/2FfU9XvveuKQdnBdcCvXw6NE7yRWYMgw9AVi2ZqOvlLhqtVmBGo6RjUBUcmYbI9CgPztI3D8bCCvj5+74MKbF46W31AolsrIgmNEpdRNZGYkBHvhvF2AiRP9NnKdMuQ7VIIC5GfBSRahXPm41sQ9tBlyIhbCXEbJubBHX6gOuPS0M9mkdZQpJ8o8+eJLL7pmlu5fbhrl3VvrGr1kjlqdXXl1TESZZPW4btsdGki+CVV1eUDsr5LPQ+OV+qHtQJ11qrgfaG9moOh2jNsZEc+2LIRuhyfEQnQobiPRfaiWOvj99A0WMenhhyV8l+vNqQczRT1klHdNu+TPYjV0YUzu7mHOLZ/Jz2sgaCn0GvDLFO894KAvidg9tnNLwChSsyRAlUwG+c+xG56q633WPqmIV5kTAH+YkLeE9dnesoZoJxzr5RIyI92DWU6paBTIakFCzv3ukysaOnxdTXLVGjFJlBE+i7V+ZkVEqFPRO/3YD7zmbXzHL4qoRZqt00jEpPszp2mo5EHoCFQtzLT4CPud/NFSbMCixkFDoOOD53MYWYcDU9S0azJuMAVx1KLMBr1cwCfUwwyEJGfT1TokE8luLL5COKz/QkqctCi6d76Nr7Nsj2xC1QONuLIXSRx9X7YZbcxwKgNE19tVGARRfYANt9EKTIJpYQbAf5PqC5BoBNe5u4FHuhpC4bya8Hv3nEO2vSGoSlbcJYCVjNGxcZfxbJ2z92TK9HK83Qqu10Ua9Bex2keehCWwzf8fVdF8tPLPmnXO179skxwiCZlH+aj/9PzKRJfjdm4o/hz8jRvdg/ZtGA8vX+JTT/UEBXsIFdAhsi9Q+CFdll+dnWev9wxHfqYfpnfGPWfCz+8cboD9re6wY8jusjvjwgcekU8qjc+KxtbOgWOzxO6GCAhR0Nkm2Fm9umiRUz/vYS4tieKS/a8cMTNSzheOyyMH2tA1KtP4r4ZzL5A1wk9ZUcWq5pJnh/ntkxkhavvOS2CeHdE1tJB0r7axcHOs7tzB4fjkRcxnt82VtKYOPDWu392poJ+Lg4JZtrwiPNau245yDsMB974kRKW27iw7tp55lWvblPzGgsJsYN41MoVO1qWMapXMwIRdomBAthi81NwbD0b9/kqzztIQ4SwjVv1ZRdPgxqkk0DNZQycXVx9FcP4C9K8FTdtd96YyHDF04pz+ExSEur71Z4XkuNQ9Y1Sax4r153q+Xibbdl6o8liTmCxkcugL5dLc9JPBu7haCx+BqfHZCxv+aeMLDAUR046pa1/6qtnJxnqMGLZMnSN9t84OBj8AKZ59KaUANd/8X0XfbvIuPdd+hphgBBnlaE0C+/ZdkvspI/634bj18fz+uD7vEygYG+ablbepxnBvg1m5lUePuiESz/HjMqCD+7R3aZp139+paiK8bdMFBt2c2vkqxbwS4i3Mio3hxXm9edIlfKb6+FBUqNf43kpVKGD8GSD8P5E49KNHLYx2SjVnDmPmEF56TtDGndI5lu/5QR+Sgckao021hvbuEimi2InrSolKWeHO2XIniEjXjFA/Vg7t6mfnurKYOmT8cqRAiHHNSKAW2IMReWjcK3Wk9EHib2t4LM/EIH9/ausljjGeTvDMeHhV6I4EoLzWDLDmNLuDpioPDPtUhHEzM8aG5iAyG2UZRyjVKSPQnIO7otk+ufBU//+RycYuZiZqpZ/y5mo9voRjfkqSnmH996PRjlty7qkva+2CxMBuSlZoOa7P6JBr8RW7+5JRJtCyRCWsL4HTzZW1rprGV269pEfDKL31QeHclYAA85YpfKEmjNys8L2flXoGPV+laHP9gxIyvxuDKOD+q05t98bEdawvh8Ed5gG8sL4+n4NZ2t3sqdeTjRurE/7ni8GEAU2M7mmNdiQkhKAAa4oAnMOYPrzPoS4KN8gcXusnCOOyvOE3OerfNcnafgPEPnXGdR7eZJeQExv5p5UDtVL3T2m4cQxNqLfXH/Aub5KLNUBKL/uD78I4sIjzH3fIuBwJgZaTTyYtQQ/a3o3pD6ce29TmwUkloTPC4QldkDjQrh7W8jhyIaH9T4Qcu8BLm9HQ0LklPz/PCyniUk2Y7DOvqLBlUOoe2jN23B4Mcn6sw/12XwJR7hmEdAuLqkf7yU317qwdzw/qirSU2PLPdAmSIpWgRuvPMpSm9WZ/7PWRY+GTaOKVMe1ebeeoR0/qPOs3kGwmkfe8QRblYnQrZndcsOBXQzXxFBzUovTbg3y2De5fzN3RXuf8rJvFUDnM/Q5nnBsv8HI+n5s0ePITHurRz0misp4XPyoSVqfr9HGC27a9JOb6aDtYdbKK/4wYdLwg4+OkZXGtU2+1/XPfpgY3P163CM6HAUzKJtXNUI5z1Cs5Fcgna8Uig+XVLJkyoXtZ46Cp3GKBEd/cWiz3YRCTfeVBtH987NdIjzhLgi99XZk9wn0pkKAqjBoywC8M32WxmUvEGZM7711Rvjr7DRiZ0SiuJ1krnMbTwz0ENUq7zbFxbiXRSCbTKGpxvrDRzozVVt2zu8Q0OhH/xQYYZXu5Wo/HqUcrEct0wzfgCSE+y7KrTqtpLRvtt+RHlgT1uGLdwNbCViTTLLXVOd2htZo2Amk063VwIJXmldXox8afHPceCLWeDa+C1RZvkCwhf6YYVHgJno2zahTr6nkrmYvoxjxhwOBNxB+pP+LkBCcwzv1gXrdyZkvxhIePVM8DpyvWoRdUrRUZ8CC9ytFIsUDMVlaqDcTPOVjRTZqTuXc9WGlBKBVX97RRm3Z3VAwYQsYYCwwLQH6SHg27uBra2R84815ZzCZUwAo72qIwxUiSAn12lut1nUf+fivPOwxljHX48D4F+SvZeQki9YFhvV+jFinqM816yNKgM/SLJ1mUsAj03ebaoq/whANx2tn2zPDa7ijRf1Cf+znQ8Y2Pph11WA6COxVfTX4cDyRerpCzw0/mdW7aJLza2USP+7G5FAw2kEsKyV8sdnwfTwezPv5/m54+mgpHbnWR5VwbVEslX1TUePCGefhgcgbZNaLAdW8IG9s7II/K/xvz7dSzXxA0zkTo3nigmqrzPxPhvcPk1rVN5UKwb9GLXbqtDyXKUojHhN1E8D3+XEkQywUCbczrntxmc5ALCQPug4T3WMcypSY2c8ALFztbAMt2q8EaFziaFcvtCEcTO7dv4hTGR0CHugv/vyKcSwU8WI62f3Pj922vNDXrAIwm0u/f2RQ47MfqgCYcoRadkzUxEvlmzSRuQLCkNhx0DPXO2eTJSdbvpiyS/+xhHXtGFhsdXTvICJIAicjdiA9ms/hc8z+r3yiChXy1QqTmPKkiYDpnL1Z/mZP1sGUfmte76sS+gqVPwbVvI7M1yxdeTV3eJNdU2NDNA/55tNivbKoWfYxbm0tYO3vOxoN0eI31+tHQn4Vlj9bVlj4ouijO60Wj9lSfChYDph5HdldYNpoJvxvGL5K0/FmOD1AN4X4tohrdLZ854XErerMpP7OkV5vWph1xola//IBabP44wFtDm7Fi64BgBDZfliKO+lwhAk/fqU9K526X6QvylWmt1IiKkpi++QaK81Mf1H/AVUsvJK0VR/BZHWwmU4OEOC9p6fQY6v98jfNiafeMHIH8BPt81dbI7ItOCSwdevVBHKBxdJzGMd6lcCg9plTfRErVSKr6hSTFQXfsaIGkr7pE9Z3+DG6vaEBGFKw/y9BVeFf+DzDqA6anl4SkA9WE9PD65bLYLwMIY+jD5Y+A3zY1rz3nrjs6pAMT8MpKWqtl23v9tku7DsAOJd7xvT1NfWPJNxJF73Yf8nkG2/Y+xCSP36VLO24rQh9w5QvO01NJE1FdBTFn8yBUeBj+oNutrOPlb9/GdnRclxwo2h97ML3yJvAjcuYChrEpArNcU/L3v3w3PlYb3SKANm444aa4P1JPjr0/ZTbqiv4lmnM458CjjmJIZ8upfR3v+iSYU7VPvSjxRtfpaUFvqKjt/sUg1CveelwsdBcuM41LIBUVfJCB/A0yuh3a8IG2QS/WSJT3+JUocglM1akotUli1CoRNysFtQ+F6bLcDnQVXmdapyhqNnnqd3THcE/L5jWu94Jrf/O+W2PxXq1mFWt5y66PKOz7lpTyRZ/rpsf5x1gByAZqlkqY3R9mHYPLhXvuTgItUq8RFu4Kgt6KvUEr9wizspvvlwrxk7sRTl7fHtpqZcrAvYiJgf/QwuVFS7kE851pm+my1TCL01dejfrob8ohCqr3Pus0QLY3RrK9bQURlGT/PF5mKMMZLmH3lLphgdWupZY6VAZ3HOWFh8XVSaxC3rY0vh+u1syXOcygkeayGjIvLu0U3mExmAK+Rug5qEM+nOhNT9gGJVDlWpBvsS+bBuAfK2SR7UznVtlyahMzF3DnNSmhtt0rCH1Vq7W881F/P1NN0Q/2Gyk1z4pINmRU72Qg5/0F+q/E8VJz6m2v+9YPMHOPmhhvGrQxZMjdtR9dqt1O1Nsd/3W+p/vfj3GO/P5qQ+BLo/J07gVLoEzSdtLOfyw+OiX8zR6/Wz//3ZzAmEz+Xv0IjvoZ7x0yYiehMuPnAXa6aSvwHMhr1Q8oKYPJ5+VCB+FmJnieivDYiRf6DRjFQP7Jg63vdoTaSJ2o8oPgJp/zyPWJEjcjjIJRhtVL5iRVRahG0m+K21Q6ZEGEHJNPdbLyvxFfxLBE6eLWIbBy2/AtXWR8/kaBkxvqrOQIHmDghNaZ8vemcXIpO9S9LuOUvzN1KECVevPzt6L2ETQj3ORaU1CtEkBiihBIX4eZSTBLESKu2xgD7IznNjHHE0RUg08U99HqhK2+HIK8qrVae3jfN1sax7lg75Un73/E3Rp5PVQFfu57GW7YgSmQMmR3d5SAt88CzQV90I/l7U8rIHRVwbOQ5AbzIHpC956ocqW0YIcJKpqb+S+glHnHtXSWV9qT2rkA0Ofl0EJdj0JrkOCzkVe07BZYa/J+tPij/0XFnYZNj6CYIUVkwK5578x/Rz/97XB7JX3YedLGBXAB2NToer3UXdR2gcaapHLVctGQOVHPBUISFn2yYF/tLflfqBWDbxlgmlXjUt8N8T3a5Kkjg7oovU8rWCGbsESqsCMHiRJVIrVqNBS0oq22m7OLRtmMzj9FU6ofsgG/ubce2f5t1Dc3AVjpxOWZHfIvRweV8tJFgHJOGg7pPBw3US8cN7leQfrkjhkE/g+q7Bul2PrOTv6uqETC15oWA0it6ybFNGa3yBomn3tEMEiEZPQBDmSYe+bKRdA/p8TH8JVmjdPT1R5ETd8qC9+iB/t2xyanVWB66notvCDB0I/q4gJOmcND/IoHaN2g9nxeMCk7Q5Ez6oCvWZMpUoqTHi7SYThqk628zjRfkuIMLP4k5ch5VuLJKzu47Up2sFvozZvzjbHX2kOLSleFEmrxzxUspueSmNBFy8RP3e4qPZ9iZHr/wpqTkPgIfcdPyQc2vzcHaw98vEdcUmr2Q9rH1wK2ekhCxUvjhGO1gVnYdjb8SvAs68w6QHbL63/71QzzvJ9rOrW7lAymU7Pp5DGM+gthoM4xzIGSD/4hE68SGynXcSp2+zwoG4AeERVIOwfURFuwSQhJ0K9D5m334obG5f3w3p1mTaQsOf3f5o7w1P3L/bPhIAVxW90osyhris7MPVlJhEJ7XZeHwnCvVOoPhI1Zat23vTrZKsLhPa/qoFxP3ZJmey6ci+sfIDUWSmlkqqDTQTcrXrUFWy7kBjPYog5l3eBy9gmIi3PgmifP+28kW6MCY7iuT7UYdmfwdJyK3EaVA/Z6rqloc5LalpXjbRLmvF7osSTCZnn773M403flxuXMLvjbUljX4xoz3J3iWKl3SrMx6EdPL4aZidDOjN/tnZ3qYB9cW/N699HK0BaDXeHGLHRPw7lzdYZFnOWgSoCQ8ZCEQTImdWS1r+9mcH0TonAYnX/I9yPFCoaS0hV7WQkUoumyv0YuSsdiiF+pcqNUYr1N13GQPKpDSRAaHuRdlW5KY73YwcNrFNAExCceukSuQJw/0Ln3sJmdJSDY+ZEb6rHceAoxQN82kIBwi1XQSdv4KNMsIG08W8Gcis6XMAvNGr6oaiapqtSBDwkPVCO7phPJe9Hkgh06J3v09tKHl8A5j87+vkDlcPJQd0qwtYktqivlUrElmaKBADJV9UWwgbP8jsCSa3WmsTNhJxcY5xpfEWlxlv7XdvHpoGQxPPGAOTupnU6Ube+6/qzqP/IlPTCyhG+KxpE9AgDW2tMrNRcKphE9/ypzfi1q9UtWLt7kZj0ki5GGGWUiral9I0fKrIkIpyEx4/+0WYbA4dcIynzpLppCJrvMpeipxDmLi0kJBzDOTX+AnF9wiTZ4Ar8Sq7kSdbv+SvD9U6t4W1ZLtmv1H9andf16DFHR++Y0EZEGQJkaeFIOTbJDxPX1NMSLj2IEDb25VxBJm/awXKuced7uhLJHAo6OlB4emCDT5loMtMjqkNB5LnrZhmsKi+xtnGNPnds9O6raBjGOeeBoHaMYuPDXl9JRNrLZdxDvpypaZNA8PRwCHd1OHELb2k9mXvO5dB+0GBye5+PCAJ5/6vVCf2BwvEE5NPbU907f99lvBe6ZblALYTDWXWmmqlX4Pv1pzhCN2e+r4VmlN0BkyOtTOzLmrRemqJhd0JQKmXi8TV0ch6e1D0r2hyv1SugaXkmfha3koGb+n61twEPD5yNnH0hhsAe+Jjpgd67k8snz8WRC6Gs7PlHRsaEdft4F3R2FKIIR+0YcgZigJj8xQjE2hvln0KkwhdRtvV/hE6TtHba3RGUTDlztni5ovheP26k59w9XDOcqZ1myWsOsVoDyGwN4dC1fYgkXHucgQK5fsvuzwtqTd4rDaFcG4GID4eMQPFxPZf9YMlKEURxkUXy5EnbkcilrcjzaMm6YbVz7CGi++8pcofp6IVlIu87jeRDstpVEwD7J7XUXFueBXEOoxjVMDfeFKJ3yDo9lNtaFIvwtcXgnZjDJBo7PmL8Jj5PGcIqcgQ1lzyIp9VvJi7q/DBQ0b03oIaENtD5IuvUnzoG7u551YQO/mXUyamq3ZmuyuFQcDzVDzPt1MKkw3B6+OI/ZjG4zFybSLPI+idx7zazKiAfdrHRuBbjwYYuJi1iOZ+3Exv+/7NyLghYmo3nwGwioRdrrWrCtRuN/WbKheHs2KvNaf6/SavN/ZtIYu5Q24Bg21522pIHmvgIcW8PvbkCVacjPyHN4M4WypUFwq9jrlZC99ZgJkwU3utwN5R5yeVh9OoprRFK1mFkXfZNHXyNCsmt8pDjxCmTGByaxuVznW5Lhq9dVc03wVlESHX3IWWbg8AonBseLBnKs2RSv2AJRVZlMe7M6JfG3fFcE5gZDq//5shQyHpGwOV/+LLHKDuQWujvGqDNQoESLhRXmQS/ngLUWi06nPJX2sAC+nASocKFyzm02s9U6l3qa8nVuV7c4lfsVrBFhZLffHtjI79vfi6YyxJur49pf1hHVKFo2mU+pQi+eFdv2pX+7gboPajF2+EjagMJ/XU5Ksmzb3SJBlXWm059ba2+OHxyMnTsKjJ6S86Xg2N5rRV1v56rvPp9ty5/0HvOWhc2oUKONDDcyvfuhbDQoIPnT+/vgMo6jzPqMCb+ZMly56ngP7WXD4y3gdzw4+HUxDqqQdCLjvIyffv5gYwLqPp30ovVkVCns0NEPg6WZ9q7K3Uzvlh0tbBb9erygYJ3dFeqPvDwPZXHbNbI/pMmG2rkji40fPW0LcxS5YNmKouxS6Ziz7QuzCNQNoBE35CNrTdQ9RsP+WFQJi3kx0z1JOxg3Z1WLyzhnfBAGxziUBeoopcMyXPTH2LwsBLzmDBYXvK8Lzjij4II0DIeVnftFFIhJDtpF1RcOoDfPkrtQ7sWBXGLRq8XNeb1keBzPvtdE7acmIgNH1vb1+GU6vnPciEf0cU8tB8F09FD3DqgxV/KXULSvePQmdUUBkiZNNX9O4HBfQ9bLcWKvYA37+N+03gpz3Rd6maXR97ChQAV0qmXu1QkuaxqZARd0dtCc5Oclgcwno6UOj/kDffOC6zh7mRKNfIkqCwrpMtEDcBztxVN8D7vF90JRfeW51lkRZULf1w0huOuSZCFaMNso0NkqngAJgpaIYL9oYv8kzX49NBTyR2iHKdHZY1qD97hiwfagPrnwautyF9ojK2L+a4FiLjx8clYap1eruB5UHPChgdaOFqXax4kS6Z7nZY/o0APLwhs3WO2gzZkChkbDA2L3bRQPcDw4fO5la9ezYKHDYAbvCBI8EHXfcbVbuSupXZM6NSEIx25NYp8pso+PNDsLjFZlmYNSFJlh3DRH/m/RgTgeGZwy9hFLSKE/7hv2r74TGNmCmzjBaHi/uRaaYq47ZHibfPIpnkX9qxZ6rb30QucUnP7pUj7++bpiRT4Gk7iRh/xOnhb5lbL/J8Wt7nA+Wdz3CWWabdU9lHQ2mn48/87xjgjTVU3ikn+I49eLb0f3Pmuxp3kD3gd/Mjs3LwN52dRvF8K3xi9TwOiLKpbcLyG7ynxd0Xg6TutP407VXGrS1zNpxAZfu8ejVv2oPUK4ufw/Inx2k1UqBPLXrGQ0+m1d2itMszbolV2+YPxvMvmVaN+0qjegkgQyMNDLQdHRTlQfk4dahQaUAUk5tATQloULtoFayUTfvcwMRO82vCORtf+8Piovgio1Yc+8skxxAzS1+9MX1jBUBMJ44UIB6GRkfPZpl8xdtEjPolLCvQKdNjU1COguNVliP11t65+q8MksagJZWTdAIbkCLgl688+7v+C/N74NpftGpHEyuIEyD4Vxu+NaGqr6ggII4SKfG/XYphrHGiwKKWbmSidyotir3xDz7SZ1k4rcrlIoCv+ITZ2DGBeZDpSLCjq7bgwgAmhb73CTvXICgWyIrNUkng5n/oPFNaiFRzLXr/GfdGx0KKiwv1OvYwnNO9JQzyQqTvlP1ic99Zutgcx4X4InzRtjHYsXGc7MAGllt/qFBIEXsvY7WFWzRkc4m1tSC1j0BVSuPt9DtpMP2qK13nlc/zRmw98+u2Rj0zfDw0f0VaYdGcP34/MaaDQtClK/Ty7RVGfks/vI9qz1h6zvDmNhz5B95Q5yni/Wy+HvwZXDqFI6A/W9B0S928T7h0t2JMi7ekeP81/3+amvkmqVfAs8lsPufr5mET6t05MOH8jrnDlVcN7Mo8fwerPeAwniMIczqkXwhzEMXvGgjTIyET/T6Zyr4EKzrvWsUwT3UbDbhm22ZgD7YdksP4RSA3SAKOOzdY15uEFqgNRh4i0nxmAZT6GQGyEJ8z/O0dd9hsyPHNcNzPTZy4tOXyxOJHTjLXljFTeXD4wc7Oc8CnnQPZ+GkLJ5EzYmbY6O9RxLZsiTskPMKiuxcd77kwW5Lu6FA+VONDP053cMYZyCbhOvZe2ySiasjh6gH52g5YnIsxJQx+Pl67fBieHVxAkPvEv4i4IXHJAlpsjT1XUEkn+nHzeMkTzW0zm8m8KYm08ESIGxedJwP/f1l6zD8h6AxRzeqAmGW6OdlHt1zkuz5YfKbqm6HsA5j4h+zxAbFQZUXVWGBkISSfKp5gpSVeE6GhEVeT8xWRA9Z9QwBesQX8UmLY5hRNlcz2K/ZXbmcpVNImed7BzAscTZFvJyQXny76/iclupR2QsI0E3kIZaUd3CaJGF9LQq7LOGunIIsn7aY4qij9AKjGrM6C7QD4FIsyjdO1vdsbzTXpjs5lSrbbhAvagRAnMuAOADPNbRXblF8AwrS9XubYr/oiaSjgaWBW1CKVVb+0W7dIEfSSQ+la/NZ5YJKmtb/7Vflm1eTbP9IrazEl5bqlvOfSGtJUF9zr4YZESa0SNzxWa7w3YQ4q+hu1RG4KHCo4scEFEfy8/PJnv5iMS5NX1VIbmw8dTQGSdBfdngxd3P4ylDXJULyHBAqEdBLaOt8Dinvaqjhw36/ryGt+dUCE5YCstSYuKJzh4YzzAa0PB9K56bQy32fRWnJsGucyTbayhEBstlzB8oMvJTCbLyk0pHORnx8qWN1eWgXs+DBZB3tHEYpHmtdIk0nyeeFSh9DRY4b+eIUkoni4Qrd8K+QLJAzGtx+flJmGq1B75BKeA+avMpO2Rpo8Jb2FVp8McLNXKAgSiMCIp0MT8vuL8NTF3x5IBkDH4Fo/SyClkJ22QLBu76cUrRUTxlRT961fnqiNvUDqw0maDfAs1VLL6YAWb8j11DItdi12ucC0RuuCkrKc5dpkDRWOSQEyO9jT7DpO/fP+vxdZ3k6M56SW0Esn958R9tIj+8ZFjQSlZKsBMx23LwFXVYgt3W5rke4jk9j4I2CXlWVwy6Tm3D4u6UAryWEC3/AzeY1LPheP+B/erCNwGXbWoH9aCu3Yf9Jpt5qzGge+EWgN91AT2XPuzyPVKle6KsFsiST73zwODaBfmLxuPjV7p3zSZnEea3NtrM21sbY9B3CcLjI7oMZKXWudvngvTWrfcfsVQxKmEDgh2nvDLKNUUCZkkicnkVgluiSmIWk1lOrSwvFrwZi70RyEMsMpdaPEt1iJ7D3O56WzdYHG/JbjNLm/rVdh/ca9wWqk+Q/Sg5ol/qBmcTyoK5UJv7vdT6CtRcPwaO+Wg8HYNAN62djHxqhYZLBaMgYoMJK37NbqzWOW7b4Hi2IGu63CWby0ulEPEX5KIZH8YhXjSyITPp4EGohJ8OZteWZYfMz1YWLuMIjBtLDowXQsixYo7ZeNNUaw6q3T49z1sCj3h5QcXMqwgo/0m1PawXW4Jz/eYyyM9S5+wieukUBsMCDgZiyKuMf3u/VuGw5YGGM7Bt/u+EZ0bCij7/GBdS7ry4Tvr7vg/10PjdQvzw+lbjcuE2mWnyx8IQD4hLi4rNArZGN7y5AEswMk8S5+JuGQEJc4uYvIdPHzSfkV3fI37O60naWYbpLbCQY0S0d7a98QKd2kcaXafDBOq2mm4PZM1/UD22Y02dnrZ/yjOqEOmX0JOl4GhPoHDG/4nVtE0wiK0HGNwptTn/C1JCEinOJOkxHLUn1AxxX26rJczswuUWPiTypxoIHjRs8jy3KFROQ2dmATUXwhT7rs95T8IO9y2VcxC/Sc/aj64QKkR13VS7xyIQ1Co2mO3MKjev/MRJDpnts3QU6PumkoDDYRIFarkhUhnVUcSkGFPvb0W1PQDy7FLLDq3Etj6fi8mJ9cis4+RHamv1mZHgLVgMJceozafzTTxOmoCbEpZ+ss0x3awFm4Ht28F/fqZOatmZ1R2tarDIyncwyvZr+kSK+T2M4cPjQvXA3vuEbu8hWpqmJ2giqryRlx4+VpXcTjLhv4qlrJNxssNWmR6hIsOwT4M6HwDJAxXYukMao+Nh/RVKzMrri45SoBXqZtAGwgnpHNcQAqfpjsYAGupIzQJXIDiPcdzDB0QONoUxmY+BJaoL8EIOHAqglpwPWc4bO8fsVrKCPMRhpHHF3uBBL6kZ+om69Hglw53YCze+LzG4qWAeK2mks3/mtpgymHhx544KsM0+K83nscAlpmgtjMJnmHJOUM/NF6iCWWXyuQcfqSQ8EhmW7UgEROjK5zOzOSqqrT+vHKutTpIgJkZg6BjHc+llPY5WZnRL5odCpa+VTYDtiBPbx+s80dWk4syBa4FrkxkySGG5DRY98THJCgDpxnxudgyCLR90k2T6QA1Gy8EvLC0cKGc4KRAsDP8U2iMrUinSIzepUXXa5B3+SEb6gd+Ajy3Su6WysD+Z0bLh+DByhyb6ySyxnduXt5ZSLrIfpoq8XJFstjENOYsuIcf1qviNiAC3r54DrBvhejBiFfWoFossVxVAXVMSpMONJlRUNc1ky3DawULEbiWuZZ6rXkJHV35nzhh0D4OnVjZeWD1kH4dt3XKvzSMlljy94P3eE1RQyGMfds7SB35RSs+lqwZGteugTOYIgeld4TzftgiUEoajgspuIDUe7o74NEQ8G18TDH91Nc3jfYcXO9m6sbpxSDN2ZssGSQABCLgxI73c5KvunFhWeVJJ77KHcyfojWjIo4nxt5vsDivL82127ntB+qZFHvAb/92Y12Gd4hJIPloZzzyYRk8csm9mFx5/MxjYLwX+Mmb9npuZxxMKhviytZMt2GCbiT97+ebfVGbTQDKYmCpC8CKfToXvpxSgR3Cx62iqfXnXA3/6Lb80c9RZmFMhDz47f3Ty7FwFFC+roIGOx/qliM7BZVGwB9Cza6bayf0/PI3+qicSQVNNhGlbNvtbOK7DdREEMOM7DCrE6otVD6S/NUhxsXgIBF3di9cigqtft9AHXw7EGlYdsW1OG79NEpg/mcz5plxlKQksfYcj9C58fYDnm8LjlvnmnekhjK+MSxfKBX2F9qb1+FPYvu9lvgFDt/dUeGsZseVEc7eDQ5QfrxY31uEUc1CF5CsirfQ6oIRyhWpbUwTlVhHuVqoUtWJp5YpWqNxWqa0zBk/RNlbgPkr7uxsZFgprzk+zvWt+GisBfSGvD9+BOGMEJin0Yn2TtQnqFEnNk8kaHou85efiXvNMP1zKWN3owjGzm5bWDodgiff8NV5VzcTatnpjQlr8kw+FTv3QlWDIyQjs4Xj7afxIt8d7yF8OhIGhHkfHIhxOSWOIvDFuXr70eCwgUfxOneSJPqeLzzMgSqMMPl1nhL2ScBxGtTF+ZIWFzTdl6v8uOQbxnxFg/CjWhtLBHfr6yZwS/FYStwXBMVCTqmeMcdv9pZcfEmElNYJd9RGwploByUUHDp6krgjUceu4QxPF8PBQGUJ9WuKIwSwQsjeTHsnGwurPkpMXx+/P/pezucbeWcl1C+huchZstGgPVBIieqXgUxpFmP5uPFsqaYZy5MHm20CRBsRBrGqS3mMT7sgBgXhq4ojIfuFnRCgVpPmcwVLsHiyIp4SVPUVcDXZj9WxgPbhRpoCjA1Go9qp47uDjM7317piesVJUjTYs1LjCEXVhOjSwVhDk6GpcO0HeP2B6qFKQAfK0+zHTnZCyXlAjiuxolx49qgCw1kK5v1FB8U5+Ucof5dpHhpzWIh14RxhuQGoQCReVW4sdGJ7apzTbedROcTw2wj4gDx4ITEJfHgH3NFpUbgvGtHdTFpo5qSv57e6O2Pi0qAyi/IpdOur0VVnj/vw10Qp+YXkqM6XbsaELNcTcvmnj6/9Cavg25cN6zTkeTFXT9rH5mnImppXEvmAXBsQlQF+j8vxIYbuBuXBM2XscXNz2m4mv2Ihme8uQP4LMvW8LB7cQ4itybHJKY9vUTyW3gMClg6e0ZZfh/87zaHLaSqzU/Eueg2kJ/gBk+yHxhxmLlsEC4/bX0qBspekhs8W73CmNyxvwVBFP/xPNbvA2NuPNYu2L7AO+Nr7v3MAoE1Obr6BjLzrNgd1KuLfXSa1++/oI7s3n7lrgMFR85SDbzxYMb8jUiofnWp+wPcTJiqN6xgfZq9bURVngAGsi/fNGIvkIHu0r3p71EjXjSNenlQsPOmE2qMMgYlrB9Bldi+jX6Zf71G9/991zc8jKoRjbFRj/R8R+K64ObDYrg1gdC6DVXs3WyqNkvYoNn7GAuLbDxzM71ePzLyTSKjE06/scHQHLxhTgW9elAivO6MR9huOPuLQ0H/7BdY8S38RJjAA4g1wKzsDf3nMiWATkhNSqDQmo0WysdGgCOEYElo+t3KlEMp0gVJvvV8BQZ8odtujdFQUrt4G17Bzs1722oQXPUBXFvut47sca9xjjAxm+dJsMplu8XmQ9pqtStR64n90rwSCijABVXNu/GLihc2wwnqQkTXeD9Ty4LXvHYwthB245no/+iTfaJzRHdGudzH2CfOqhNQeP8HOTdlC0tiCXAwkwi9Cq1CeneH6B+eqZbk/UHCxNWqr/5UMm0psPS7JHbbg1Sw/gAC/x+93/sdQyQ9AFz/lN89B616fXtNSUEg7+ypxwmvHkK2yiTUmWW7SA7jKssOWh7Y06Z4ocQvbY4ICpshJWGrvN+/XXBjV1sg4GNYQonRPqZLS6+h+X4sSLdwjlMee6YuEccugdsCSxdpFVtq3MUFMpBGQT8m9IKJ7gWFOQBZ+JdoiUZaizF4r1CUNz7CjYDp2Dk5vATzCPceWeEHiKBDtJPZB0lSU+g6Oe8k/stZC4M4qiynE5tikBM++ynPIQuOppentr1nZ3Oje1zbZB+n0PvzjW7iTKB0pkXs7XDihRApUoJEbWLdZmFUNibRduf7MQPOixDZK7Y9MJjX1sx5OdSY8P7eqpHd63vK6VrUHfrz3NDbLMEStZUfI2YyGCKnzVVYKF6szC1qOMV7SxmxUqHB0vxlMQ81GUezpGbUdIBeVQuJwnivZYZQs/CLiso1WX7buh0/yIfCSU3O5AxkCpi3TjKoyGeQWfEDQLR15H/y68DYhDCiLzBSg5xqjvNL4fyuCjA7R1LlcBOfm0mNlyz1OI7tAouyUWAObm9fJxJI/lBQBkFuv53wIx4XhkqKkrGy3HzAIaDWU/QwL9vFMNjpP7jmyiQFlgosTkRmzAZ3RbcEo0mE5O+jHHCorwoDJdmmMHABnSN3A5CwWLNzyhItat11plmrJkvWekvlpTz8W6d1GzYO7lKcbsLGnn4zt5pHM2yY5zAlM0CXSs61TnPle5sjzuPXChTg1B8qs7jLAfeptnwAfUrzA4QyNfSpyD3LlwhNxu/yMQuYwFoQV4x0Sf13CXGxNdcMkGdor+BBJyGqktRtT8LtCTqNp7txcStjbJNGJA2euBTdHENdQuknqG/Nqmo3zra3rv3Q5p6BsfmGJMKqkxd7tKP05+iTvg1SyUJGpYt7B7a1rR51nuHiRi+oZlnlozC3jaoM6BFcOoGt4Ik1wGLLbYRfBXxOAaW0g9mc6e73JnKKulGEMZukRqsTCUYi5SNmXyGVgSk/N7aJxAn76wdOEXi6S2DjM6mM1aHN3e2zrMk7hRsyeNNkDOSg7N5mDxQG/3Xbrblhsxd+DryA3NG37r+FdtcfC31RgqRSvh57VkCY4aCdZFWhAC2ESZScSpr/jSZpjWGKM0Py/3ts5EvLBCySTUBaU1RgHeBB3wAsQHSyBVUBmZNO2ClSt2WCzlVFZ5FjDRHIWIRSGoKaWjFlmNIpNcERf3cqbIFwqEigF/lFR1wh73VqgMrQgWwWHCaaY+5/dsxQ0buTMoUBrjUz4qDxrbYxKGEjkS4M9NjQYkdZX3UkO4bxvVKZSjJ5IxD5ShXgnY1DHCpjB6YJOZi8TdFwmbrQhiEFZYPHxTRK2cIO2Y04LrOCfIgkNwHx6TJs5p8QmFdrqZr6nPfKy+a3GXhYB/w/1XkK3I5B0gB8SDRw/OWQ8JLolf8PglWSWgtyTrZSqKhiPyAfEpqmSEwt/FUWNhih0GcVhLacfFMEEMr+uwbgOLAwcVLiVbac3/zBuQIPq4JXq1h9fIVCkhUXE5RQu2tpqvXPs+GEQyY4ZVTN+ABzcFOQsgJDFSHr7IopwxZ/qK2I47eBBzliO5ekpMHf8iDaQDIcErBWJCSrXDAU22wnCCspqShB4CNJDIvW890QuQBb6+8iXg2tGKJwfevTWanTPNkS2HbAlZOeQ1LpuM+mb9XTiDXKtW+U3rDKtmt+s1O3P/WIDD5KSP3S2OuXh2B7aaWu5T+KlGfWy1mpDf+ygpsnvKXei2w7usKTnocnZJItRA9n7n69RnAFGuJA83pdddNWW3pudRNtrjZgI5uy0RtvmMAMGDXyKMXRYplPHV4oocbtNHO/sEvudievMONJHWZqMOhoewGyR7+AGVdRyqcA1LMqlF0OcrKBzf32OxRKi+BTqckGDruLaHKFTsIFwqCD8BouYrj2NXrOqhlfXO9iXY4Z9kO4Nzffrkt8766POKFhwcHVAZMa0QkGQ52rnBg1EYOeqsBzCZYc03jmV3hdQLMQ+h06rCOua14aSsVi6pbq4xj+ZHdVFG0uKjttfBBOpFFTAgVvn4aj67Ui05fblgKKvYxAwZeY8n/6wgijo+Sq5rCK+52mNj0f55eQwxjh7W9BzRBLnEUHGEhgtoQ+GVt2hEiXxwgn5Y9dWbJSK5nsFl7shwuNBfMDQM1D8mqG0qIDrIw/rxuln8D3LqJN7heYi3nmt0kmD2lbfusBy7aU+0Sfq7y44OpKzPYBP4OyMyP22pxPELaJY2QDvUqNA12OpRGuSpYve8ZycmEnS4GEEPp3Rj5bRiSOrBT5Vefo7o5Yc5VM7S1eSoxPd0UAuUh6jIF8PwPbXVWbGtfz1MSLm2ljslvWDKKQOVnKB0iCKwR7mfTvX4Ko6kikZY4eNjnYbddjwygd4UiHJNp5IDwB/zBHgst2M61QEjSPtCyuGQULU+nz+v55bUP9z0n3A4z9on2PGMAxnPtPRxZe2x1umoPWwr+OqGwvnMVwl9VoBc3HvWMXt0jfxVYW5xP6G3B2Sr2fdHnosc1l5cgXqaVuCqQco8diSAyDXkskyVEUiuI0n6Udv9KwSLPhwQVFEra7Hi1VdcCR8/xEv0h19nuUXDh6aGJ1V8+Lm+wdrym7CLZFGIz3auYh4kDYauwoEkepSq1beCL59+2yuj96RkppSdfNa2RNCf+UcPP02/eHqbscihjm2TBrXca/GoJ5jLP5cf59t+13qMG1acz4N8J6x4/suuPYzx4ufypL6SR0k2gq5Frk1dw7erSj59x6ZzIe3LASXptDH/RL6t+lRBFgObpMJbhcXVeOPuEgPYfMzWmFrgHKq4zJWnLd++q5TzN0e7b4MnMuCKW0dmMcInlCXIS4rKhBAiLEx+/AdOqJ3hge/7j05Hrgre7v2g0mMLHrnGeWiHYpQf5PO716PsWM5ip3dHsVbZsaiclq+dLkj62Axa77AgdhAs7Dgg5Qikc/va/n2uTz40+4SE6fHAahS4nz+Oca0pKH27p/NUu3jEXWTegdcujKKGFZHj5jV/ARPWl6XQsbd2ZO9YrwBYJmN8oBXw6QJd7Q71gU7ATKjElLqwa4g+Cpydr9FQyQkRm1X4zuGlRmqyuq0u1H3NM4X/3y0XDgzPeP+WF0S1y+uk+NHwqhTSTwtKXw6XA+Q2ZTYqjiqu3G8ebzH5FHKhH29DSYz2mlp15Gq1e6Nruv2MHOVGAnS+72tkVzrcgS634OyU9DjS2HAjB8rXSqtK6JPQBu3GMM9wgScf3codb46rBojxZ6OUsTCgg8oS+7XvqJlvAgzjnw4dTqliFzsdkYZhqKjcHORc6lrfrAnY/8p0UBnYmB9J5nMEEKmvjspdQBz8cIFaFPwC3+c6h1sv+Rv2sVkaqU9RpXCX5W00wNgkm5VkqWzuokZOrzA2TKz6XlPszk5JJXdkTfioiX3QzLjik2LIzrHAfrXQv1Cgf5cKVSbsswPSNrg8TBR0sRhxnNvkhiiei6aUJvNSqJPhY0/rZ86vzo2wrfZ3POoMazBE9M0TY0JKWJzRA2ifu4JyKCBqcXKma0iRf1h4J0AjDb1dILg4P1l9Wy2qKGFRHmZFeRB5qBdYmL6+FuRJkjOYAhY+oLUeUI1yVsLDgyRDveB0juxiW4pL8JFEUG/WegOwViVLYmUGMkWJUot24Uw3h86lh8b/kkS5xCGHWlOUTwCqepr+isW1aEQPOIu5EDPaLaxBG+L8cR1QOwRHkpk6SZWx18yE1PpIZlFBRpidFz9jmlbXdE7stM9gWhesAPCUFON8anO03PTXGpby7WUzJOqDUGh4GLmNGoM3DwL/4cUwy1ytS150x4TyGB8WMdIhAm3+YOtu5sfUPcKEH+hgqaQqpfOvk/dSXI8IpRbsINNFlNZjKYjGcQFvyGs59ry3WxJN3OlsTt+LY1RzlYrbl8l7eerXLHPJJ7hqwfLXbiNaFe8DC3Lrpl1KeAx470H/hsRSKgq03DP3/eAEsK+UmJyjO+oXFgpGS3O2vu0AYyE1fW+CHGoP2mTv7kiuEkAA+MMNtU10BTngiUd72wx4a7xFfHCIV38hVOHuHC3Zsx7GgDdvO25pIxo+VgrNwlCdOuhIF12/vt8eS3uf/VNCDtAOf7J+F9YMgong1OO37rGfH6JDiAiYBGz+ZrxjSe/Fyx0TNnCHbetAo6a6ql8EG0gKVlZj8ymLyVRqfRZHjU02KY+lcVv7jBoDoKmQIonOJHRGaZTD3P0FSFMX7QSIvq6ZBdOspqYamYlRg/JDishopl2HGvni3BbjulrlSlwcpHWC26vrimypafUMkCbxzSP45w6clKrYTeO2kgqtvt3RvF+4RGfOB0PV5x5UqSiZx4PnFe6Z1dmqP/fMNWK+kU7GPt7bDk/oyuDXiP0g+Rtmn7QUAj9+3CkkdbJzn0aa3zrdfyosLRwxq5H/blnRWkixvgkQEs7NHE6kMq94GsTLml99PL1JJkYjZ7k0B3dA6v4N6EFJuMAFHzwSg5IZhuPDVs6szyQOUwBVbQSPjSfV5j2CDpUblvLNMwijRxZNG3ohnCseTMcmCj7NV5fZIjgCVXvIKlDgXBdAap+4rBRq6w0l/je5f4OBDSkqfRU0N+3l/aHSk1mEwq6qCBAlEYGmMoadWkOCBMaccz1LUG6WPwtvO3zAD+h52ucIc+qIHu5DAzdKIgHc46sAhMl9FZO8Q1sd+uYHwtT3V+sumIT4ukZ10ih0JP6eBnaFmb+7hWL1eFaZXgLFSmyacFWh+VVCEVoems8y1uXpDkdlGMoEKkl7kC4CJM7QZSAbH+UTr0Jes1C7dIwuwmmG/k0aMW1zpfUA9d3SVUyfKwP06KeXBT0h3BlnWWigvOVlf7ns+hp9p31/LQkDvrs6twY72jFOJWb1rnXJ5OaVD2pBpcMDlJrbGlulp5vguGlTHimfhSr3rPjakbxopWXaU7YNjeF4Ek5GxrIlpeIhS0O7IEWxp52Tna5x99vD1OvdMTULE/k24sho5AGd1RndYpv0qF1Y2imJHRoeRdedpz77iHceoldm6aXzr96Oy8l73oZiwnxGxghQq07Usbo8EDD6HVh/5vrdv0WAkJfiRX5cPytcpLW5YP6KisNGX3WuBtW25yPnzYeo/OVMrBMxnfP6jiT5YANNWqVDuSSeEbeqFUl2fBSE4mm48uV1qlWtd8PSQYqJZ9zRMUanK8sHXkdZQlzGCz0ofJEoRhsasA6R2QvtBSTp1y45GHvzynq9P4EEA9ByATnAga/ohNUzhkYaz3VGeSc/XVlOQkQyVWMFuuYm5AMOjbI6sxp4bLnfxbJ5FMJQ9SIcwatzkT37iFLgEGRnEk66AWV5Fe8QT2W3OAHgsk4Qy8NuXx/zspgO60FdHZD0l8kTuu9khWWImr2GVRKyswpRLhQQ9pd2u2Sm3tgTAsmdIdQ9V+IY55u2QWDJoMPg+j2WNmEwNl6Q9+fFoiTvqPqJh6i/Yd39ZTaIWbp6JIcXBaZ2OfqttT5DrlYonOYipaODgigdSOGRQJbG0QbRUEMPxAKrgsAnZ+tMc6eUzs9pk/bg3YB+IABVZMQbw4DzJ5Jfhu2tJJ4Sonm0tmAPHkSUpTrXzxHJVugLMZTOrI2NEPv6GIHdZQDaXAqGNsWT/ibWQfH66Ysv66OBkXqOue8Ly6rj5z9eZqqKFO9UMRZTJYp3mbXsJlI5am5ZvetqoDucowAoK/L7i5ZveqBLWWD8SUPy7f+2S4C5RJiezO9yKV626Q6evFVxV7p5SXCbKlGYN9WTdsGvwo4hrZg/5n9FnSEO7dgjN3daBOxnUqf/c9Sv/WjvpckuGZAWz4OTuBIzfBf+tn4ScQH/vhysLhdleufh+ltGyTrl4D7so6wpdbFHy8/tV/AHr74dNHxosfr5tFIpT9S6eQlrR3X3JOMG0LPNs7dxsSq/WyzGOoXTmFRmR7PuszH5vhDGXHch3X8DpPjX/J8RRLY3rPGbpL4T6e9Nq9qPO4T2w+tN0nsMs4Grlaw2NrbxRBOPNaUENdZksUvS7Hs7TKie/9IdJr9j6cMPaYUdlumLrvWKSRTy+RUxYFh5T74PomiFD721eAMY49x+qnwk9elIXAlNfePTCjLLzibum2v5PEBuplKl68Cus/xibl0Y/aJQuZaIcbO+g5O5Jjyr/OW4S5YbcF+4ITjBeKBzvB1Nk5FBNk4ZUJsn5/wo0puziw2+1osL4UBWWfPwC5KntSqDTtIWKXpkxP0tAPcq5r5n8DTYYT37bfh5WwoWho2kkP2CmHlgknUwAktheidjw4/Uzg8NMOh/G7wNh/OoUUfjr/KK397eBLPchJL1bbbDL4OjIFGVXeE0R1os1B7KvxVY7QLPJXr2HHA9uHERjO+MLEl4d4JJAmt9VxiBxWqglLphxT91RGStfQKd2rP6m8Z9Vn+f+m859f8zWlm0t5ccvv1Q69NJOHiUBubo1tfoaWT2UIw5a1thXNSncoUmXWdXSA2CLk3tF7546aVZ7QtQ/VNDsL4EYhYTb/lIkQfG98SWAYWmTMTShbk4Qfy11k80jK/laNfWYyUEAtWsnnfMbCfYIrI/2rTDmOL1CessZfi06agP3n1y0y9gHyf9PCE/b2N5/x6w3ixas/9z/Ad2v1jPTfJcO/VaNEK7Dzx9e4s1dptoW88QYNKMXqXazVxg2M4AmHmqkJG9p5xjDfVHjei1jbTr18XGKsh2TkgPZ1/KTKNHUf3e5VaQlo8qeKkX0xfWZ0EU9zrUMtjWnqhECWhPVFnurOWs/WRHEP4FMtu9BkrJL0oVvieC+FHmHUGVxeEhVSTsHwU9o8AY9hgpSHYGXrcIfT1Fb+uASiNt5Dl0zdz+1AYbb6y10prr7y0gJiPtlJ4l4ctd/vUUFpkC3UmMRf8C6L1J+5jMHRasfShichdcpb5rtTHmE2nshgtiwyS62PM0yP4hWYiW/96FRVGTIc65CiLCehj0fZRE09SEc7sEXpj3EB2sKoNm11+AZhccCWbA1lx6Tw3ZqhXqdE6TqZbjw9VvomDzfIkXIq7YHLnRYPTt2dAbbBBF/A+NIfe+vSS6P+zjDsEOC6d29pwWUujMeZuI45Zetr7CGhEOimMTB7hi9j6UlMB9OHBNTjIQB12e/rW4qFE7OMGFrVdcD2JuR7P1I+MNJ5XZkVaDs5F5Q3ZN8ZzkNc/VZ/hv9uMlGaQ05sBJBY1L9xExqM6AWieO+rwGqa3Ko4HPX60J+Apdjwk9fwGy20V4gA80/BUTIgPmwLtfKzjmdcplIOsjucS52mu+K9aTdh/ieUwRlT4LuOl9U1JKyWIlKVN+q1+fDHPsZ5E/iFFI2clNmxsMCejzrch3MHPoiEOle4icmBqlifqxfhgwmQcqiaoI/jSkwWUqmVTZbVmPzWU27Tbwb+tcfU/EbTek/vnlwil9ZrHzrUS0yQ8WrD9CwW+qtgoS76ByTcskj05uMxFrn+ZJ177ZBsxFwtY8o4axcrVq2Q+ngP0k7y7UJVmjuUJWWamb5AkMMZAAmpmZBiI09bXT16KzYB5S1fWdUW7UYlLyqB9eVBzBx3N5GrW5GEQXItwf0Y/xk3mPI8pOLLhTRRE9zvAONYJVex0vtFdL7t/3hKOpRydCKFf0XWBMJYb5VYerW/Dx7w7fk+/cL9cma0X8/6AKrOePs3Ddh08rJu6xbd4u+SxHNwFofsbemylGs0buc1/60Fyh9gNjblDV7w912H8eHUmxV1wDjeOqhusV1gTKmphq2u6R6K7Rqc051zy/lZzw/2+VPAJhYKqFdXvReioT21xHAMs+CeeOWnHFty7oiShombJ8p/rty+adf12j2OZw77mhr+qifdBd5ig9DqLtcX+WeOZvlBQQVseJMIyheWGWM7HLWiSbq54ubwcA4i6JRWD3dMTKLQgZAEDHfJT/VkMBL78cRDxdLxgbjAeGac42K96xtMSV2MzPkM58j42JUTbDEkGSQx2Ce4fu/qnpz1CFt2gC/3nLjINBh5IRl/DW/QlsX8QNwHUObrmb8Kp9Ns95M2HGDgU07syy5tS8ZsWHXyWYKH9916xkAXKJ+kyyPYeiCN2TWrqcyVRFKsF5VvUWGfq15DFV+1LzZK+4Z7XcMT3MBRTvEYB21VpYe1kKasDyb1t6TiNvBgReGNQ0SM7VxxSfpoc+NqLU0Y6225wmCaNrwwXVSGHoBxT351K7v1qIn6BzJnRVogbq44R9U/sKFW7+DLLnVl+Ev49AYYENfc39/7r8nkftSvoU0RctQKtMhC3kG0cHpttFmbXftsSV7Yy/A21oYeSBZ41keRqfTU8pypllpooUVqWHtL3iiMAw/4zB/fxnOp7gxgt8J6tFPqGAIFKhoCf05pIJvURZXT2xzRw0lMN5Vm2sVz14RCI2wEjtieLsG3ngYZXbeb/n+JCnoO10tyQesaMfRl+hV1eyS/9sevT7OqPliVjyWIBd+mrPXuRtFlriHV2yrVEk8dJQaxyFUovz3yuHDV5eZjT3qNiOukGdAqra7sGRp32bjoLx3dC431D6Rh7RcgvWriENz5ChUeiAo64IHUIM473AYvwvpg/kHrvPgFt3X/BZExcBW2+wylxkjz1SO2jG3+v5MnHiHM5xx3DtuJ9cSTsI5nWcr6cJLjQLcT7cgqIy38PADedoEh2fBDOdrXVHP3W52S8sIcH3hEiEV78NT/POdLqcrXCKs8EXqDPuinj5RDQovMQu3fhVqEyJF+bqO2Ec9vjaN9bnu/Slp1l0ycU7pAKoSGZ8IZmKIbtvBY3QnjcYZpb1jcTYt3F29qqsNn/Apwd1aH8PCi8GgMp8HMFLTqvQxgHZSBH0oTwO0sfvX8PdzA41VXYyf7OlzavxGDe8bY3RtIb1faLz3n7qcXFYULWXCG2HBbQrJX9mLfwuay22OZb926J6Bcvbe1I4JuTUSDxEOi+1/gssplHK0X1t0YJF15NCytDTij0Frj1y00QjveQEm+fZQO80SBQODfL8VqMjHgtHk4JpefGTi7+aPq4IG9A86Eyv4r32puOcrC9HhuVRKugXC6mB+uX1FybmepPg4w8/iwpyud/80F6kf7LrAsbxGNaSsT9ZpFeHv7TF3FqgDQIq5MF5eBYdV1kxgFzPc0G8TFA3qyy3Zegg9IukEH2hIzmgV4fP2StvD4R8vRITHmY9PO57MjKjkSvk6f/TNZ6G87oCQQEq8pLr2Z3Py6Iel84KaYX3l4fwTDO09BWHI3xUQ4IC7wejd179zrMOUt0zt5Vpuo3rt/8PF6dNL68dobLMLZb/aTrwq5drXO/9ZnaIczDl84RYe67lRiN1FqVtOal/SJp6mNnDEIawklxqjc5VSYSgyyhCV/o/LKM9yEmZcHsCKWI04zMPPnuKxmYRx2XFzTCv6VXqgkCWM592DCdGx6MThxVvlIexRZD5u/ic8vh0l+ZG9PUfua0j/AxxWAbVZkLHsuqId0XJeJotV5auUiBfGJlpBw8/16kbNuHP0gOXQmhrKlStEjmS+t76lk11081V6y+F1O2cEHzBsnPFY11RyQLzObGcUf5HFKP/84ROllnmx6u0Kw41Do5M3rE5Uzmjz3RuLNHdSv/XE1DGSyI91nJ09oop1uQMAsaCH7c4bnpiLkS3ORz0exGUivhskeZJTszQCXsLtaevb218dwYPSCYWl73A3srYo2emf2cDrsNDzSUqE1ks4HDorZQ8qBgwuv9QNRQJE1f1tYklVVrCDF9s9xAW5WSTAd0Pc6QCI/ptrd9fQ2q2fj8KChu8X63jl4rD+luMJxUK46bPOaD2zB2+cAQ9OuHyZZ1lXvQ9U89QaFbAvh8pmyDil+A4RAFcqkG64k3FLu7KGVyqOd/7/MIltteIhqXT759jmAGNSDpex1F0KVuSjYTq91Bvhee66h96KP65CLnDZLXY51wRd4L7U0vhnGder1dltktWBqZ4ACH7YjJ/w4J+r9OcZv6tpuoRKhV4i8cxJy760PR68sgUQcTx9KloJcWFy6luuL43CW8Gk436voIcleJOXj+QhEoTPo4/eIUqiNyWLBshUEhuuUMySww9Het1IkeXRkhJbv5DFSYFtFWRQSyJi0vEnAzgq2aJsiL92wDPHeqMu5B9ao7uBlKPWeLOUSPKIgQ0nGTLvWzDDK2imz/QKAsXLXLKcAI2KX8jE52PzyOcCG0ShODTM/TTRyTsMns8jN5HtBeMqy6ihNQZZOZ8av0rFnljO1sCSnzojG58SFuCJ3sSQcR6S6KfWu14iGG8IkOYnyq9qziNURMwgSjQiwZbUce+z2MtRpHpywmfDAfvEUbwW1lyFQmEyZEyf/jr7GGwMGtTJG7p3/dc14QBU7VJbSaolBFVH17ueILulsVCXQMJDo4z7GTJDEfXfCgLg2yhcOmd2okFEJRFhxHlB745zamCUoNMk7xDv/4n8tzw3m2rC0r7Ja5VC1urV2IDrMA+xxV/Mh7szka/F/3Sdo4y8B4EHmR2YMtmYLdbGd7+qsbLAQh3ps2DxnqSrYI6phwAMcE1BK+FImTFDumzavuVRJqYR13k0AZa8V1G4uGhMwLkRkuf2A7NOqsL6YWAStKL3LlzG8e3TN7DPbuosUtESzM/slfbbqolZQ53jCSfJVLOUXxZHLI1evqWbarh3dgAAMTxfl4QmzHC5Wv143nnaxnbRPkZ1TtZQbxjVjqtwW0cpTYtfBv6Ofg4P3tiXu8fdP0PjMN44/4uxk/JHwfMPVlRm7GvaQnJ2Sc1/2tr5Vbvbr1ZQ3NBKt58GVNb9ARdHJiRO7FNSbXLrjDVom5n3vC7F4gWRw0lw1GCCgzZyhdqUs4Y6JAlrZeDfLu3q93xJqaAOpveFHPscps5oO0AORqQ2O3uwo2XXIEA5P/WYz1/rXxh7/y7WospS9bQA=\",\"base64\")).toString()),ZW)});var hBe=_((yXt,pBe)=>{var oY=Symbol(\"arg flag\"),Yc=class t extends Error{constructor(e,r){super(e),this.name=\"ArgError\",this.code=r,Object.setPrototypeOf(this,t.prototype)}};function UD(t,{argv:e=process.argv.slice(2),permissive:r=!1,stopAtPositional:s=!1}={}){if(!t)throw new Yc(\"argument specification object is required\",\"ARG_CONFIG_NO_SPEC\");let a={_:[]},n={},c={};for(let f of Object.keys(t)){if(!f)throw new Yc(\"argument key cannot be an empty string\",\"ARG_CONFIG_EMPTY_KEY\");if(f[0]!==\"-\")throw new Yc(`argument key must start with '-' but found: '${f}'`,\"ARG_CONFIG_NONOPT_KEY\");if(f.length===1)throw new Yc(`argument key must have a name; singular '-' keys are not allowed: ${f}`,\"ARG_CONFIG_NONAME_KEY\");if(typeof t[f]==\"string\"){n[f]=t[f];continue}let p=t[f],h=!1;if(Array.isArray(p)&&p.length===1&&typeof p[0]==\"function\"){let[E]=p;p=(C,S,b=[])=>(b.push(E(C,S,b[b.length-1])),b),h=E===Boolean||E[oY]===!0}else if(typeof p==\"function\")h=p===Boolean||p[oY]===!0;else throw new Yc(`type missing or not a function or valid array type: ${f}`,\"ARG_CONFIG_VAD_TYPE\");if(f[1]!==\"-\"&&f.length>2)throw new Yc(`short argument keys (with a single hyphen) must have only one character: ${f}`,\"ARG_CONFIG_SHORTOPT_TOOLONG\");c[f]=[p,h]}for(let f=0,p=e.length;f<p;f++){let h=e[f];if(s&&a._.length>0){a._=a._.concat(e.slice(f));break}if(h===\"--\"){a._=a._.concat(e.slice(f+1));break}if(h.length>1&&h[0]===\"-\"){let E=h[1]===\"-\"||h.length===2?[h]:h.slice(1).split(\"\").map(C=>`-${C}`);for(let C=0;C<E.length;C++){let S=E[C],[b,I]=S[1]===\"-\"?S.split(/=(.*)/,2):[S,void 0],T=b;for(;T in n;)T=n[T];if(!(T in c))if(r){a._.push(S);continue}else throw new Yc(`unknown or unexpected option: ${b}`,\"ARG_UNKNOWN_OPTION\");let[N,U]=c[T];if(!U&&C+1<E.length)throw new Yc(`option requires argument (but was followed by another short argument): ${b}`,\"ARG_MISSING_REQUIRED_SHORTARG\");if(U)a[T]=N(!0,T,a[T]);else if(I===void 0){if(e.length<f+2||e[f+1].length>1&&e[f+1][0]===\"-\"&&!(e[f+1].match(/^-?\\d*(\\.(?=\\d))?\\d*$/)&&(N===Number||typeof BigInt<\"u\"&&N===BigInt))){let W=b===T?\"\":` (alias for ${T})`;throw new Yc(`option requires argument: ${b}${W}`,\"ARG_MISSING_REQUIRED_LONGARG\")}a[T]=N(e[f+1],T,a[T]),++f}else a[T]=N(I,T,a[T])}}else a._.push(h)}return a}UD.flag=t=>(t[oY]=!0,t);UD.COUNT=UD.flag((t,e,r)=>(r||0)+1);UD.ArgError=Yc;pBe.exports=UD});var wBe=_((JXt,CBe)=>{var uY;CBe.exports=()=>(typeof uY>\"u\"&&(uY=Ie(\"zlib\").brotliDecompressSync(Buffer.from(\"W7YZIYpg4/ADhvxMjEQIGwcAGt8pgGWBbYj0o7UviYayJiw3vPFeTWWzdDZyI4g/zgB3ckSMeng+3aqqyQXxrRke/8Sqq0wDa5K1CuJ/ezX/3z9fZ50Gk2s5pcrpxSnVo3lixZWXGAHDxdl15uF/qnNnmbDSZHOomC6KSBu2bPKR50q1+UC6iJWq1rOp1jRMYxXuzFYYDpzTV4Je9yHEA03SbVpbvGIj/FQJeL7mh66qm3q9nguUEq1qZdc5Bn12j6J2/kKrr2lzEef375uWG0mAuCZIlekoidc4xutCHUUBu+q+d8U26Bl0A9ACxME4cD051ryqev+hu9GDRYNcCVxyjXWRjAtdFk8QbxhxKJvFUmkvPyEM1vBe/pU5naPXNGFth1H+DrZxgMyxYUJtZhbCaRtLz27ruqft3aYkgfCKiCF2X2y+j35IelDY2sSHrMOWZSUQ/ub3Y5mPrFirEXvpHAx4f9Rs/55yglK8C2Wx18DfjESbpWL5Uxafo02ms1ZJqz/dtngtnMql1YJ+v71s08jzoZlHGNE7NvPPiEXF3le+xheXLcUhOThn/6HG0jL516CHg6SeKYP/iC4fUokGT71K5LM7212ZyHT2QzO2dMJGJ1tpT7XjAjQYVWBIR2RJBjCjJxuzntxFq6x96E/kH0A/snZ/1w3kBnPChH8d4GdAjrG0oDZrAfb/C4KgIV+fEmjqxTLdJnB4PF7VGbJgQxu7OPuYJkVxZ7Bi+rub4dQCXGP+EAZk/mUFvUvi4pxd/N0U/HHhuh3F4lj5iO6bVyhvIQyNSyZRtBrzQOMO7JFSRbHsfiNEDB8IXTG4CSDMi3KKtNtQqRCwbDtpfUezkpqP+JuqmwsuZcL2NkgQjEedwMnFr6TCWRvXQwPUXAD+lhMwu+lNro/7VpwXEtxj8hHtrXMOADNQ4cFD7h+rxUrlZko0NfmIb8I54Nos5DONiyQQZmP9ow+RKkJ0i1cgfUQ4aUBgwp+rKUzly6REWSPwLqbpA+zAVnNGNZB8Uu1qeJ6vkhPp8u2pwbnk4QZnmIaTvHCgzBbcRDjvDv2eCf6WdNfch/zVQ+jk+T+kQD6NLl38f7xoh1ZEDAryVb1wCLBHFy0aE3FuZY73LGF3dKslVQu59ysM5G4pYvnKAU9damJz/0eknF708c2eC6wBHcdur37hekn2fh9EgmYq/4RWTQHrNglQkyMyDBAoFL+hHT3BjXoy96O8psGR+QTvg4XW5KdjMGCj0atxV61XAJlhVBWA/HvRqn+8qL4h2gNT9Yj7mznFCcCaVC6Uvr6DLEmJcs5J6fPPjBB8kkPjz6vQ4AmU99Vqs809/uySk4TSwfKNaXmfh0UsyzkMy09SgFWth+lu7VtImU9KhadmM4sd5KZZ2jZW/I2qLTj50XNwv3jOwlLMU69B22pogDPr1gYaobzhO+HRC6tF0ryj65xKZ2hgiQOI36RLUjllTXiDVwG8UKh+kgT6u45VlC95L2DZXrPln6Uko337svBb6fCfIF+p/F5+YeWijIfxC4z0qcEXZsDAJnXWDqKtIuVjmya4DHUjndKETXIMIHFKCFAmcsVmtu99MVy37vZRymW3R9rJR7/+82E484JOGqGW0mJDAo5bHOdYZjmS2DXSmhOCfs1LMQXjpoyEHpEctD1t2lmXU9QqlPY4Wb2xVynNDz4PcGyFK9+5Dv9ZKh9cfz0lr7A2S4g6g/BGTGzLJW7pxCq7Yoougq4Uzu7gVbfeSI8FCIj0OJ5BDmPpI2ioFgE4Q82q0iREfbgxfrEUz2gmkxSPRF2Z0uylN6krioG0dMdUewkyUdKRoGT2czC2BSmrmlf67wzXCu6+hlENc0YAAHnU8ifl6W4VjxKe3Gwn24DMgiG+HwWQrBnLSnsZ86BxcsDTk3ARbIx+yAZSPA0YffDCJtGaiC6JIqqW4IHC6NikeQ+A8+Iyq/LIan+Tomj4e84V+3DedENFS5MC9eqkCuh1fs9cOm6BTseTMjhtfPXFoTzAk7cpW2qwpSL8fHTeMSHVXLdUWrc2aZoqNOLevM3c5KGk8XFvCPZ7k+WyP5putfYT9bhWBHwyy35+QqoY9xAyeSiyN/Ow+de8dEVxjiO/1/TdUwIyC4LBQgjzh9NSDX1DFDVj81S3SNrrcoskAwU+MfkV5qRqO3GSCUCiPAkBBqqlSRWct75lqe4fTsrja5xDx8KNq26ZgwXNkKn69zIjzJ76RGpANs0ahAwhnfp9QPAk23SNIcHP/nVWhaJsIcXf7P2ZQYfAtgxIp5RAqdVVk3T5ZyXzGUUPyQ5DcHQpCOxCiyk2lFkLtOEE0xzugED1vI8S1U/4Y5jlZgGVM2bvTY8xPPpsvuHu5KyrEecMGIigi0WOLtR5g6OD95i9BmSl24ORZsYMf0ZusSSNq7qSRpQCLUe2BbB40bdsFJBmrLH+FXLczUK0WyUf9B0xk+lYqk6yXzmQYPVf3e4xlUbETyNDp7m59l7XHZNtJpbcgOMYLatBVKxjLGKSMIc0s3R1rZqWlHgABmx+eRyqfgqrt8T0AMdw/j0OY4oX9D4ymSMsiD6cJvyyQEuJKxB+tI0MNcy9784oIq+H+n6FqEZl1wihMarly7SOuO3KfrI0BZudTh6W6FPhx4m5eioQazCRNsnfFn1jRymtjVt0htfNi8QOOi79TUBwqDfqgtH7ms/mPCuZ5deTajrWhrxFlk+yYdWzpcHjuIk5S6c0pvA4RWKQhW0ZrlcpTLGiiihb227YY4IsOUOpafaanHlrFz7L+kyXTB/vMKf+wOcJrKJvpq/aDf2+oNNC9Nc9wFQP9BZfh68s3LsbQfyIlBOc95FoUOAeTW23njcxvoxurud1/XZ6IdaTrP3vsJ13AATa9njnpzaW/4ICcmkU+INciDjNr6DRTLOHPIOzF7HzXtiXFsainupUGqfh8nIUW1vGlbYBeAwn04D4NPsjJYFIrzko/1jViy0NwT65o0usO95lc/3sz/HM0lqNSFrepApkLuArH7MLk4Ud2FpCkHxxlVt3rrBOMa8tQt/aO8s6UaNd1oE9Mvb1ZfjlY4KdXhvNNHXKM5S6zxuj93bUaUFTFs0hXlBIyzyvhqqwtH3J57JCDfVqilT2+4v1T7RV/lc1IMp3jGuhyfkV6Rhd3OCiE7ElRGRCEDNHXazuEzKPP9lfqZ4l/rrpuXVydf/Eny+O48Cu1LPqAb3hPsyELxbyuE/EmXNcy0UNUFcsWhYzAY09S3+HOthcOAFEbCGK72x47AIAlbKq1LOqxZyGnOiLqTIzF82ko/YMPdZA1u35gWi2dXytsg6Dx73BLHPvNbr0+ZbGWhn2K8Jng+R75gfUN+TnNozA27QvgezhtGt3cw465Ve1o6BxRtgYL/mZIfKl2N4Q7I9rchlh+uVgH0tVBdKxp3lySqXkD2YbQzzh3uz4xRdomZ1A0OH9IGa1Moud+rbztgKiAzHAxOOTNxy+ZtPWnPWTHFDmlIfZMmvpU7jOtakpxejjhh3gYIcd9vH3766rS4/UFJnzFQuS0BeljjW9MY2mGhjFisY2jAFticOIgG9ntAnTVOx/Yy5wYdIMjLjLXrvgDQUGJ2runk1niyi1G0LrgH4rFw9bfuT6UzCP+8QwxdNPdnDsLWzHkrwSWt/EAfY6AZevfFPtcMsZU4t7aWrvJLiN70CzN8AUHnfzquATdPr342AYsZJj/rQ72YddOnbdf4ZzY7yPw7cgZmQlSBdfDqfJPpqzeNOPVaEY+l/2XNAeCstnNhZQKwtmH6sAAXfl9yuVJTi/magBJAxUbivQRKHCyxBmEl8pPIyk0MPq58LYx1iJkVg9Iu1/yLotS1F4y2fD1mm3CQnrphi6KURxydEshzi6W58CRn7afwPntq4bq12rzdlnlsD5AZMAyRK9fQbQNR3rAdvfG8eZ1/n49icsiUssBfYXK2iaVlUfYTkZj8RMpBxtxdRlWMQdELGlRPqWZl5tRPf9fJ/XNgd7YU2olh2VjW/2gfo+va+tfFyeFjvq5tvTMtNkHTcqKR5T/YL38aDImuvqm10LfhjkhzJpP2K6G/7Qz/MFdWlNGiycVs65WCOOXqVPufVResqbv/sPJNAktAUAwPhi63Y6F9EJDPBVfDmEQVpbSmcpl0j3HnvjFA3L2msqZBFphCBEaxuBKrmeqAtKa2iKoHEdDJ9Re1Jrx4j8QT2ybiTKEcJyHLIHDJojd9NcftJIuh2YHY0x6Bb++6Dtf73UpsIZgrnS9nakE9ayWlk/r8Xrn0ibW4deGgt/KZT7x/2x6RvB2ShOP7WGVQMNDVgaBhsnKr5ToiegazDrScH4zauteqNk3sSykTXx1cR5MShxFZIHlDrqsHJWesyrJTQuNJx3mpA1nnINBmWSVchFUD9VXSX7sfHXHd1lEiOGTPrlOZQvqoU5V4gAKctLd2jLXOFtZ5fCFa7OBcZaKHyJQSBUARJu/+vkVkg+ov0n6lYKPFHQ/Gakx0ns6IWc4q3pt7r5sN39Is12vWpTncKUOPL+nqmgO8T6zm6Xb8Xhcil+8mSH5ZNVnWpD4GdqwUP2FkiAZoDl3YBlwPHA2HKLD81OKdAeDXVGK+EJopfaq7XkIzhqBWRh6whrxOusdiIV1tbhid5K+ZYeB4HwUhV1v2P11U+MAOWZGNYlXX3eMjD1fm6kjSGKHa72+lLHiMM7K+dEhVNDTc51NUWwSsXcx3c84m0RLdbxv5g8h3R4D2/1BbYbT7zOCo5dXtmzSmHViTZxvZqbwz4jSj6wc/sYabvhhfy73XKz26oz/+T71R/G1frWlc4obxqaDTWIj9HG98/3+rPtnE9tjas3Yyn9UhO2PJErMN7DKinTMlksp05+GakYwb4ZAA4zQZSqrGyHsktqctSjTpMtaVdA4DwemhPyrmwcW+0NlDL9MrhvGiOS+eVu4bCo4jj9d/SV0i1kFZ5CTs/WjOU6Ml9d3JAf6pE89rv73/vApw9U3w11fy0wbP0WCX6V8c7Bmr8t7vhpBemDewoSVo6ghefic5xgecP8ysYyB1QC+Dk2JoiXTkwaEIU1d720dCIf5y0SYm9l5quKY2Yv5LeiFNbtLS98NQJ5mQs12Cp7BsJHzT1c5GLsm+hdKkAzxKA7R7hGPuIauQaNttK6XTBT1OZG5cM6ovLs52W7MA/HNbkjpwAuvzgnrg3T+Df1s3q8GIwwxlHfYvXfxUKsTx5t4cEZxsk2700PH3l3brazpnHEDDa1MLF2q1QGTvUpRt5Xbp+OMr5USgxt07r7JXR95TxwfnGIp8ocvTW1d5vunjz2oyORJzC+vrJ1drWx3XfYJGe7VlkOVPoHuYz49GYjmCXQp9EtzfUaAzKBEBTuhkU0cPYMcpaoLK3XiQtHd+dz6/GxMtpNFEOIqr0AiJGrBH+Gp+sNad0n9quQM4hqu5ohrF2G1Szx6s11MVqJRvd3QlxH8+mQ+4E54gFHyoz5iuQ77qXp49kehksFrzuZSI40Y3aR3T/Z/OnRX2egHXHoibXzcFFK19vVfCXReF6ItIzYw+U1Nx6UkwuJpcdR47EGr/xKs8UOEyZ6V/eJxtxF/qmtW9265WzSrqwNewgxToBKfVnkUrJdmiQIaNqb9r+UDgDuArRTpUUPqMzysWTQQIJbd+Xr9V8aUEpZ0371aZhhI/84RfW+dmtpjRn+yQIllTg7FK5LV0lyUk8eAITuqxaZfESPTa/QEWwg9+66Rbpmc1CBY/Oqk6pNubyv5segdfcpYgTsEpbzVndcExR7oEc4eJRw57hvSNN+AqH8ziy3hOB19jKuML6MKFSCuRVcix9x84zYfUftMusmkOvyGNUGrnKM7tw5Wmrsih6RTdtXe8+O1S6E0TMl8bL59GuZcXke7MfxnQvRvECXjo+1BQOpd75XyPL9Yfm8fLNjZzbMwk0ZgqVv3bFA+7Qu+xFgxwsJbo83PhOeNr6Mcq18n4EtGQhvrzAwQY61aBoMIv3G/FBw/SgYaPrk9ng1MffgnFfcJDNP/5se7spF7Gox82SeuOpiPaXZZFnKIF/5zLH1TMGUJHR8ySsXitq4sIuBlyykqukQhDEiN2DRUBDh2Z1M2h1BQtmcQpxhs8HJ13hVVENSgG3lOPlazd3sYmG92GvbvPbpKJip1q+WDwbQtfa8RkSKAoaY2IgQoLo/rJtMq71UR2VJ5T6Y85hL0JGFT56IQmcCseQ8ouKnL0Vwrs0bxTpbwScO+JYPcMBt3zvI6rqGpHxkDDMm9yLuWS7gRlOktJMAq1M6P2pDQkNcx6QSTmuWmHwHYEgskf9zZa6WdV2o23rX5hg78wKfLDaBkXcnI6ylSbSp+2NEzZ2NQOCt8NQGNc80A5OulHFQhCx8WkzDwEvXT419TFAuCmp18MmKi0ydLVgc7MPg6wnWJ51o6EnXvuOyp+/TJS56u6yiomDYxB3XXpSIxWyztaGhjqXYmOGcdu2bvO3UQcdXidioZ8lJawPuUAF+3VaoJIj6eF0KIrbdhZCmxWD2czpmWFKEMrycyV2MBqzr17lW7xVM/WdWWR/TkO941KAzOxL44QS9OU/M+5Py/kS9Jzg3d3/e2siuhogdsRGdGUYUno62enVUsYpt60mhAk2Y86s60H1QPA0/7U9nydqtBysJKQGT0WrdGcdUns62evVUsYrtHUmjMs2EVNi9Li7OKcOHj96u926XXb9AFnfg0lveGOVK6cWJuUZCQdM2WDBocMGB4RpkNVrvo321gNLF5WNEk22kk4oZaW+BmTxmd0QqgclRBtjJfCMoq8FXtRoFDHSKW0d5nxUtS+oABoxQc9Gg7h78va6jiDbpW7dwrVuEo2m9km21wjB1x61EvLs5trGzerpHde31jqvFWFp/cHhRrjnm2lAcCLsHxu/TsvafBu9P3vuT954F6Rpt25Gks9N3C4e2kfurO0y6v6/y9D7K0/s0T82aRk2bplVjlin5fpEdtwAql0Rk1G07gIufdqJB1j4w3t5FUPApCSdEkGznnFN/k6Ft2fVA5rZ0qVvQgDely/xvUvMgFRWKLUrcedIlqbk4VVnq4GvlqxyXhagrDku8eyTMEeKWnMjfW/94EspJUbqxpihAdFeLGbU8OzHdDcT/9Z7c0OY/vwHm6h4wc0fwj3w/2w4nCLptJ5MXXwad0U4YyFqFVitCvFv1IGnSo23W5yI4R3dYF2y6O0ze3oG6u/tRp7wPgyl57aYPfA7KJfKlgEmWlEkQl84CSFEfeHAnk5mhg6C6Fw/sGFW6Mo1pGPQWx+L8rzYlmce0abEbvNLIdGPj/JEvB4u7ow/zpzjZf36STbphaAbHf3YUksjbVSlOf1crtroPP5bOnfnydVL6zNkulKLzeEN7Cg+3k34rS9tTc670/JVgLvRawvNqKF/jfz/aZytcHkZ29OBZtQXoBGupMUboqsk59ai14cMpj3XHxVnFzFzTzuEyXuF/bnmKFvMTwYFG/UmoxS8ueocx3waoBBQ0G4KSOGHB55gKRMk8DNS5KxLExF7GTe9jU7wGN9vlFEeBD6lF+26RT6RInLpnDDmzERW31XTRHtxL2N7xoxb6onLubI49gVZ09Zq1x6C0t5mdk5WhD4LjxJ55oU7toCwbmZbLiCMR2lBcSk05iRcSma1hWDZdjl6tD94ohLBMSWwy2AbGyv/jbi7dLoGlT/ezqOm33fIA0b/aD18vTsI9I/N4HIIsxuU4uJe7c2Xj3R08xAjfKZAbbgibJqG0MjSEvWVDjki2UkNf13Vd13XUZC0DTx2bDwbsBH8fj2Hxn6DbLxEPq/QhLzcJEp4urxiMY8FRXecFSmDgL14S640Qkkhm+fzdV+xXWGM/p09EFViqjiv6KuiXzHphc4vol9T/UsKbIW5OB0bLOtsC4eR6duJtnxq8FgL0Lpb2B5aLpXyGjDHrCkDHMFTmn8sdIroYt/UVzIKjk0PhbBlisKdX5l/L1+wSG1cHztxB4XqXCgSDSR+TV7Oaxi448DHsYvT6BucMDab0e3AJM6gAeRCVHSNODMzz5zOIaOkle/XBj9NE6FinCSQ0r9ITp6mlDqKb7Ffl4A88ULI0Qp1awaBjjbwaNjId7GhM5vKZ4BQb8vzJnXnbEjajStV9ZlEnYp+8Tq5/az27/kPe/63evzvv/y7v3773POrXvx6DjGCuX2H1kcSQanT+WKPiUsJliz5KOWnC5wk9WtlvJcjJAmQ2USOgId3v/FZARaaO3jZadHXWqJNf9Chrfw8pjHoDJ81McWojt2MfyR0uO722bmS33+BDLNVDDXbIKGyZ9d3occQjO1dc/GhydaLE3ZBuyGdMvDiCkk4dx9G47sGU/sbZM7F6QYmOmLm2zvQyXV0fcr+Yped1XYdi9Ve12efh93r6EjM/DHkXkVq/DZErtsF/9zbH2d+CnbitS3X413Zg7t9DfDu1xEiWz66j5CVH/JaBKNZl2Uo79Uul1Eqx5nIXS/Fb72/3/i16//a975d58Zvt7Fc5JPT2anmarAlrp365mvUPoZ1S93AIK7p+waHQxZJIOzXbNGs2mqbR6ItJ+Zcs7Ko9BC9z2EBfFAtDOKfO6qJZfnNDFjdAdnqqv6fToPqZxig9IK2oNhX6hZTqIVGuFRt96Zr998DmmIdqnz3UlycZX/hnsVjV6Z/UYKJXpeHqK//49+ea+69+Y9DheUDnPA5RVw9nnh+gJ01XJrNjI+MmfyzWM2YXsb34d9x0eFoY4aOaWSOt+XZUtITHcMqWcE2v0v2ZqL5Xu1C8f3MBErrnQW05ul+zM7hk87HOqTQo1y+1znZ8UvvlU/fbMvKvj+Ec0Cv2YE/3W0LwoJvFgQPr9GUpjfYejnSnUJnRheU059qwNpKX1/RbakgJ9nKb9MuARm91wSk7wrb7lAWNEM6voL9MaLjsON1y2VA+P2Rh6rXMyJRspXjbjDretCxLwtqvve0ed0UAJclesqbidU5hxOL9IUu1WHeXZehNLzQMY+yfjIlGu3ArXU2LcpIDh0koQTTy/f/X69ul/mEyAr2S/PHEOfMyXbymM+Riva1xymz+fon2M7SEKpt5DOUz48NHqDB/7I0ILMB9Sk1n5MIp7OcrvIAw2epfCVC9UwyNSdl1Kx+x2IM9OMWgtAdQiKHeLax0/E0ZD2s52JOR+hEXA17aT9nSE0zFLExj3hUS5y0U5tPttXeNRUeWoaVHuht7j3knrVmLeIunqu3zqSZgzmdG+HgVKwNW9A8vCsuyFwzMOmdd5qHy2cBnCaG3AKokR0AW9RefKmI5BfHIVyw5s4Yg1DtB9xhszA270uiOCB8D+BenA20hHOpl/MVWCROFC1DAeQ10fu99qMpsQA8jfhDDoUqBCvJRW6J2pzqLnt8Mzoj/+ekeL2XRRgJhJ3qb4AXTV4aK/3Y3vY6DuN920Okd2WOPp08DfE1bQkBfPhf2f4DSORjXtwn7CaReEMU94zGEFKTW0gxHkFXd4qE5SclFXH4NMVNp557O+j7FT7iQMsPUhbdC4JFMphbansagkmu3SH+D8LNgaHeFLw6CrbEbe9Vvr8JjssSHy2DhhuD4J9OY24/T0N2HnjpwQr23izNcsz0OTSgl6HbYHxguT1X310zImOVKEYMeUTve3Caiih2i/Czr9SFu412TwspMTMhTno+cIq7hkm4/V5CUox/7c1LiVCYDfTsMn+WAjI9oYruk+Mo2Fo39BNc3n+Fuxm5sPUOUVNJY11ZkOjsYivrJcAqrKj0/E+pcq5R1JXIYouWzjPw4+8Fsa4xP40kzxBQRuX+KakC/OtjLXnhDoB98jWRcVUB0x5gjcQWCep0B31VeC+0coDBmXyeakM5adQ/eh/7DR3gxgfShsfABlCf+cKbAAh9HQze7MGeX+twMOnuJiQ+V+N33tl40X/z4OMPZbxu8iEMGUKL5peB+LtMHkAhzON15jSF9EsiaLx/i9SQyA52R4z1Zd04/SI7TsnSOQHSk2Idexi3ZU3b3iaPVM0mfFXp26lVupSzmHmPD3xtj+cLJZFNiFr+RpouhImOd70A4yRE5fwSUJds25rGVOMthYLt4Z2DSQFF0FQ9zmcrSfCGV/gGCU+jXsDv8b8QGX430pERs7CdIhk4yBwsLKgdIgbu0hcK5O8Jw1pMBa4ppsY9pAY6lQ/R5JbWsXMzFeY+nxzUeF0pNFweHkRrmg3sT+yX+zzad81iYfQIFKcv7qZ5jArC7UGZ8N9AUrzc87uCCavsUcfDghX26yBUJ7fCUD58hJ+f7Gsrlr0kDvDWVE81YkASoPUhifNjDekl9cHWdao+BmJNy4wAdUKtohv3KpWRhIiruWpp1zHYXYXjLs/gTOoqL5L8wRKt86ZHL8/uhqpz/8eFl8aLVkeWEkVAmh0IvSiFrMjlbEZL33lYnGjWSbveG/f5x/6X+I/0iVg3/Y/JMH08I895zjFmjl47uh99Gpo+wToBxddQPh1NszyEGDRSWwVzajG3tTtuqBnyMJouYE9hUF8UgvDKF+gq7LUjeLWNZ+uwVIIBWsoULBbto+RFS7N1YMgN9MbFBzQkuWhVEW+HdC6Z3sbtg3DwQa3MQiu3VnCXH1aTpb1lHY8/36jN7xdolzctdbjwZua2JJT12FSQJhM5JrMzdeKijSeVwHx8r7U9jSaED+XF6FzQ5dpthmAgOY1Rj+NkgxgNDkQ/AcHtrAQve1bcQLUwC3KUo5GyBTXRwvi+LMf1S5HDn1wTI/UnOFQiy7TVVD3755WuaEh/hRccyHVqVGR4o7Y6d1HakUEalTvswRZUYfWWbzdY36zTlQkk85VpLOQd3k9fUb+2EE4WyoHe5c7XHNnjP5wIBExdVhlh9miYTFY+a6/dlWUQU6N+HkvTbsv5mtRfaDwTwGj2I6MYz52z2o1fJ+/sGytq2u3e5crJzze4RDn+bVadJSgRec0QxcUQcHihrVCCK5rRVHGkYNTICvQWMqabLpiXatW69ON6sy/QgJ674u6+V+IlvY+ENFQoG81NSA7/6jObtmuI5gXPd+Q7Grd6WRVsIR9KCsjde2WZzkhum7VuwInzdrFTFRrqYT6DXkfQk9cuwN7jZOqAJHSj05LX8OQWzpo37SCt8WjBGYN50o0F76Gf+oFu7p73k8vE0vOuo/jjEm2O2BhwMHAP0+VdGTD8P4PH4D71h5BkJKXUGNH8CJFoGLT8zJWij5g95rjeJH47SO4yW02WexMt7zR2C46ThSWcSm2JqWjT+GG7AcgvHQadqUcDKjdTgE4Ub0tqlEPpgKTmZNw5Jd1DAs3rKAzp8+0furclUDr28+5dZUW/ybEfjBB1++nHXKXtuk+nz8sW76+dLvLtycDstCBCmkspzzcjvTQI8k2ho6fE0WKsuq4LQfxmyVjnHcKLJi3T4/vRqNd0ozdijYGNzct6ITHM6ORtfniyESPNWMBTbWRxSNGkFv8uZqfxpl42DVOGkrvP/ssJ1gbh9XdnQiSRXTq/kmpw7H7LM8XKtXwxfvoYW0APq+JvGSv0M+5lUhiAzwAq8O66O0f8qTS6MEIOUWjijJ0/ZCraxaJPhkpX49yAonqXZ8zAwX2tkIDp5IjjD2kvb1G6/QeVVv7qD5azxLHBpIWbI28rx6q+5D9nzUwkP2wOlDKsGw2/SJiOao4BPWyCXjRg2OXuPp228KdglNL17euvPYXUSGBO6FYxo42R6Ol7yNtW/MZD86somgsK1PR/IVstv3srrKUkbFnPBbpYYeNJs+p2w2fbfKnBxxi4zYK7cvr9ckBhxe+otENmKYn/Hh1YAZQEdReEZ5ZBRnwCO/G6kdDYuIw0Ewd60xZpkj209Bvh9LMJrLiT1tNsrTYy1wbxFCNgOzk8xPkzWye03VL3Jh6qQLRjTkth129p5IUhBfiDQyd131I/tLXEMJnRGwQBV2/X/L7Tv+VC3uYHo0zXq4CWw844CUJqYfDJLqkwaItbIreQF6svTa0TNvScy8r0j7VlLVqczG4USLIqC775j6VhD470dyQzM/16xBeQEy/X6tkgJQKSjL5N6J41QlPCxGHScYuYvTpJGcdVYq+bObbZdZK4v3BtLj3Vc5+/lTWrcSfyvc8LBExCmWLfJviNBX8c8ixX6VGS5VYWp0jjli1CeUgoHzA9zkDBbBM54ESqVKQecS1vWexQpK5UIsOMNSa8NYkRp25MkRpwF7OIQyAb9X8sZuPXgmsD1jbSFA+uweZsQNqGkYVPkBXLSphKJ/C2lIHdCfVKfqbkqTyl5co2vummREV3HZ+qbZBG5yG4G95Znbq56Dh1zYuOGWXhKoRyb+Fq7KYYV9bVJUk52DYc3VFLhlL6Qbkoy8G2Y0tCpCwXcwVBxu6GeicCChN24faPn9IB8cUD+hp3kvjKceZpSsmXP5PCO5piSt/bn+PL/gjVPgvub5jOgq7nNIaA3OqQMljSz8Vs0rD9t2BhzyPEOmpLsqlFtyJQZL8zLy1xJiDiVKOcrWuUdHtDEfILHwsqHsjuc8FY1AQqqj9eGqVtxRTYRMTGYUZPE4S0WfJ7DiRMfTADsQnDHlF+OA64ySBzOxLfNpOdwckf2zFgMQtG7JaygfYm/Xvw9GLu8hdlSf5mZO8coUGi87cEu+Y2LcFASUicf9TgShhXtYI3pZqFK75aBuQY4QLKNtM+1d+law/utG9LwahWnCLwRv2mZrbU9nOtnqcE70KSReJShsp72y7S/NvKWAfQRjoi1hHYvXngDd0xJtKeAJg5TRRkrhIwdD2+5YDWTXpv6DWka7njyJ3+KJ3+ql3gDYkvh5wUtLDo7+x9ieXW7fMMHUWgcF9g4dzHAQDaKZEPGOivoKFfwWcBZEKSo9f64bgDtRu+MPsXwiyfxVF1+9ouXD9TfFJT+mvASGsFIkW04E4Pk6QFt/jaUtQ+ZUuzJm9j6/E1sfV68/A43r5150Wch4uvNOOkKwHBFMfC7OBFob4hFCGp6WE7iMnUzu+OULbC1d1CLoInDP8ACxjiWgSE/N6YVpp7avokMwyJ+T72/AKOx0QfXthxqCYC8cSJmmpAjbQEAMqTtI3Sc4z8IyLiqpdSijDyR65ax/vmBXGOjz03+f8tZx+O5Pq6N68X6jbUb6+X6zbWba++XA1iv1+1SNtra53qtx+VDZn2YHxK7fIHWrz98HTqCd60G6juzQjrYVZbhi8pE3/QYc9NomQ0Ez+9ELpyaKyqpDcrLMGJxPKsFO6YEofopC46C2AU7LtgY3R7Jod8407Id+KwUE4DZ5JrV7K42vTUGtSV/5+TE6t3TkI8mEcr80pHiDMQzGQ1hxfO/y2KChIqxdMavftJ1c9UFSCMVMDhdHj4AcSbd8jJoOKd4kMTB89rjpiZbMCu3kS53nzKehcAb3L+r+II9l2iMFRVUVD+ghglHv0jaQVzLFJXt3QS763tfKo8V6UTxoNRxEVVDX5FLgavrZibQVdQMDHbs5/+WxpStii6woTFaBmXZFROE9Cc3+y0pEAdFxkpOzSBsLtPtWNJKigbwPmO1C5k25PgE3hLaORZi10reiVD1UnELZIw6fn4pYJGMoyUlnw4c04dUt+qZptvBhw33Lnd2iZTSWh3rJtWIpPFc/3Qsy4lMm45lNy2aqY8+aC7gidvQhQrxfmuaAiWKtWtGY43OmmJYnNr2XYMaVcnXosYANFzD8uGEQjAUioJFLJBRFuXNuOukSso2slYR0KLSAhz5lY7q1rroavP1eEGAcASAWbjfnBFK9IswYgGHA5BdQjJew7u4ZXaC3QTgGcaIUYyPEiSucelWSTuXUiG1LMXM8oIR+RU9W0qjNFg6fBugXD10ZeHkvyTrC4Cla5/q5MLq9memnJ8lQjCaYJPvnoYyXm2ByZjV6ZOL7d09CEUvdcIvF389YLM5OPeyxfBWUjiPqMfIGvgOBfjPGQW12cBc/YzZbxgYu92wRiOrYixVM5dG6fmqo6ZX6CK/bqqHboDFCUp73KU/YIS7DEu6Unw0H6X96WuVb2l36CMPyTLgjvFdAFCTA5kmyl1S7/mZ3xOqv651jJX+TnIfP193JOZKKEWTMhhvn1StNy/Twhd1gpgysTnFNWFl5O6/5cP/R2zcJU9ikalZB8sbL1Z4Ok5UqgiX/ZQTaOO+5+zXNcLvODwG2b+8dHsI0r9OSS/UZ0+h01p/chHZu2TvLVMaEqJxkyj10YV5yHd58pbHPIclCt5CeKNcMx5kSr+GsBUhcyT7lr/mRnyR2Sm9tpjpf7a3oR+H00IabdcdATsFp/9yGGPCLqqwyl6lpt9D97XV5mjcim80uvhG6AXM+Ewx4CBr4XXIIwZsYzkWKHrwhWZJM+ztSWXd2ErNAGPs+ZFpa5NxBrm8rN0tHrzoHNExuwMoB6SdGGldMXKFhcy+q99NjgYngNDKRu/vTPALyd3ZcCWg+pv3uW7lylwtESPVrRTHvPIJI9lH0z7FB8MQN0tddxm55q+hZSlHGn4HTIn1qYnBdytlMSEyfTXVh7rpRGakuXPD0vtF8W3QbN8GXgUrwbCybkIaMR9UGREBwaoa8M7qqGTpuHj6ekl9tZxBBouoxbJlLapftgCK1NIrtr6K9YBROQ1UBbINXOiw0wZ5r9zagqRBDFMQFyvzYFnYh8Ig5NoqlDFqSEd+WHiCEAafi3IUpXVePI8oy9fD7QDRWKpQMrIqyRqLMSAn7evHjrNRNKspUBOCq2ytGVeT8T2eOTeau8+WOvHmiLE/AOUmcgVQdwJVlvDgr8UFuw7pcXJArQozzSJo+2DmaKYphScNeSxACQsp4f1xmomLafbNNzK90dk4tdjwL9inPgZWECkUUjcBKLkATF/pFDq3q8VP1dnDEtXN6Ihxx26oXeBRLim6qo5s7nyCeEWn9uc4raEXSDlPqk/bHO1i2XXkIP/zF9RvnkQR1T4ftxeicKzDz7xlegnxpauHhn1hcP/Emh+vsw2CVHWC4V27XblqaC/xkO4YPJP6LpL6KEyLE9VbxKK813gqpcNy7oalqhJ92RanoMF1xUVtyRG0U31KceJT0bR5h8su5sVyAHil2LnWe4QPLNbS1lk5FefiiG2b3IX12+Ez+3Z7RbSvqVxtWcghZBStcIfYtE4wk9ZR0TB2axfOFw3iX6FdlE8tJFwqKr5D0HGTnZ3zvS1qvLEybAAHRSseffG3+vDgpSuyckW9TQTYbPc05tmGMPtCymY/OwC/7KqvBxPavQi/2pToMKv3ysfwamTLeW4bZrqKADs4q67jiKN2/yyucS8StnHeTg/Lm3VqVUHAVfyb0yLTUgpwCgBLocswkQtPaQ8d+y6cBWs1Annqp1igcpQLpghOOVHYg82cXYEYICfygPOL5hvAd9ShDTg5xbEaVI4yaS2ZQQ3+DYY1n1xCJa7Ue2KRIeZIgZQBem1NmIOBfPvonVqOs77IChs0HqPbdpjbrlhTT2YRFnSfOQcEsQG+w33eotwEpkbN3MOv8VvQIfmuY7vd1kG8WnVvzMxnZYubJHccY6zt3Iqw3jp0ehCj26dOpVzveIQ+JdBs7z9mi1F1WRHbG1nCZKkjzXeZWRsmAVuV63K+6fxczgXicHNOJ1byuXpDxgsiM4vGlf37hbCEojg5vBE/THcQU9c5ulMBqczQkatKAOyj1PTEHtuASZ7plKRQ86aNZPWcDTKBdjsZ8Q2H5ayc9oD/mPycHq6U+1y4P8yFbZkvfoLHvnE+hzdismty7Na2YWmYHREuaa7nfhBpxqKVsf0TI1f917qMKTieUfdlNsEnYhT7TbcgKFvREH46deSh9qjtW9KUSpPOWMqONNPcL1F4LUzN2UCO89sAnoX1H/WtjHdkqMtYzswsd1El/me4hRszg6YO0GgWxNuH38Tm2nUIAdMxaZmEKJ8L4rRiAe5WH7Hg8W8njHEcVDB2flFwshvQiuTLoN0XbKrhWHNW+CSKj/6oZf6TL52UpV5UHr/4fY3zbEnkSctnyS1fq8mlfy7IDBeKTRksjn5uKai+tWArnq4FyLGWTCS9Ajp60isRCoFJi1+ndJekdhnWAhnveiA6icBgsxQzkEVrAjZALn3tw/1UmTqKt8m1OdOY/v38fB3j4mcnBX2rrU1uGtLz+9jTF4/o6Ytlk4O5NiiyTKBCLOwKP7HhZqG1fQnBYtxks9dVZRHYDpVvtIokwERT7NPeSwnKqAWGHxPsiAL6YvVI+BBMtunYk+99NOWWtyiadeaGwCbDFz+OFqnQM9GPHlQ5/Lnt3tnrRWyXyaR/4mO/E/fv65K911gFohqGSVGLnzgM71eBIw8LF2+BLqq+mPqi8ovIVdliBIwN+MDY4zKOxfyM4zPjWIdHsZM19d1SrB7nmiLRA8+AP2XBcFaAm6B/sJ2iJA8=\",\"base64\")).toString()),uY)});var PBe=_((dY,mY)=>{(function(t){dY&&typeof dY==\"object\"&&typeof mY<\"u\"?mY.exports=t():typeof define==\"function\"&&define.amd?define([],t):typeof window<\"u\"?window.isWindows=t():typeof global<\"u\"?global.isWindows=t():typeof self<\"u\"?self.isWindows=t():this.isWindows=t()})(function(){\"use strict\";return function(){return process&&(process.platform===\"win32\"||/^(msys|cygwin)$/.test(process.env.OSTYPE))}})});var QBe=_((Y$t,kBe)=>{\"use strict\";yY.ifExists=mdt;var Dw=Ie(\"util\"),Vc=Ie(\"path\"),bBe=PBe(),hdt=/^#!\\s*(?:\\/usr\\/bin\\/env)?\\s*([^ \\t]+)(.*)$/,gdt={createPwshFile:!0,createCmdFile:bBe(),fs:Ie(\"fs\")},ddt=new Map([[\".js\",\"node\"],[\".cjs\",\"node\"],[\".mjs\",\"node\"],[\".cmd\",\"cmd\"],[\".bat\",\"cmd\"],[\".ps1\",\"pwsh\"],[\".sh\",\"sh\"]]);function xBe(t){let e={...gdt,...t},r=e.fs;return e.fs_={chmod:r.chmod?Dw.promisify(r.chmod):async()=>{},mkdir:Dw.promisify(r.mkdir),readFile:Dw.promisify(r.readFile),stat:Dw.promisify(r.stat),unlink:Dw.promisify(r.unlink),writeFile:Dw.promisify(r.writeFile)},e}async function yY(t,e,r){let s=xBe(r);await s.fs_.stat(t),await Edt(t,e,s)}function mdt(t,e,r){return yY(t,e,r).catch(()=>{})}function ydt(t,e){return e.fs_.unlink(t).catch(()=>{})}async function Edt(t,e,r){let s=await vdt(t,r);return await Idt(e,r),Cdt(t,e,s,r)}function Idt(t,e){return e.fs_.mkdir(Vc.dirname(t),{recursive:!0})}function Cdt(t,e,r,s){let a=xBe(s),n=[{generator:Pdt,extension:\"\"}];return a.createCmdFile&&n.push({generator:Ddt,extension:\".cmd\"}),a.createPwshFile&&n.push({generator:bdt,extension:\".ps1\"}),Promise.all(n.map(c=>Sdt(t,e+c.extension,r,c.generator,a)))}function wdt(t,e){return ydt(t,e)}function Bdt(t,e){return xdt(t,e)}async function vdt(t,e){let a=(await e.fs_.readFile(t,\"utf8\")).trim().split(/\\r*\\n/)[0].match(hdt);if(!a){let n=Vc.extname(t).toLowerCase();return{program:ddt.get(n)||null,additionalArgs:\"\"}}return{program:a[1],additionalArgs:a[2]}}async function Sdt(t,e,r,s,a){let n=a.preserveSymlinks?\"--preserve-symlinks\":\"\",c=[r.additionalArgs,n].filter(f=>f).join(\" \");return a=Object.assign({},a,{prog:r.program,args:c}),await wdt(e,a),await a.fs_.writeFile(e,s(t,e,a),\"utf8\"),Bdt(e,a)}function Ddt(t,e,r){let a=Vc.relative(Vc.dirname(e),t).split(\"/\").join(\"\\\\\"),n=Vc.isAbsolute(a)?`\"${a}\"`:`\"%~dp0\\\\${a}\"`,c,f=r.prog,p=r.args||\"\",h=EY(r.nodePath).win32;f?(c=`\"%~dp0\\\\${f}.exe\"`,a=n):(f=n,p=\"\",a=\"\");let E=r.progArgs?`${r.progArgs.join(\" \")} `:\"\",C=h?`@SET NODE_PATH=${h}\\r\n`:\"\";return c?C+=`@IF EXIST ${c} (\\r\n  ${c} ${p} ${a} ${E}%*\\r\n) ELSE (\\r\n  @SETLOCAL\\r\n  @SET PATHEXT=%PATHEXT:;.JS;=;%\\r\n  ${f} ${p} ${a} ${E}%*\\r\n)\\r\n`:C+=`@${f} ${p} ${a} ${E}%*\\r\n`,C}function Pdt(t,e,r){let s=Vc.relative(Vc.dirname(e),t),a=r.prog&&r.prog.split(\"\\\\\").join(\"/\"),n;s=s.split(\"\\\\\").join(\"/\");let c=Vc.isAbsolute(s)?`\"${s}\"`:`\"$basedir/${s}\"`,f=r.args||\"\",p=EY(r.nodePath).posix;a?(n=`\"$basedir/${r.prog}\"`,s=c):(a=c,f=\"\",s=\"\");let h=r.progArgs?`${r.progArgs.join(\" \")} `:\"\",E=`#!/bin/sh\nbasedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\\\\\,/,g')\")\n\ncase \\`uname\\` in\n    *CYGWIN*) basedir=\\`cygpath -w \"$basedir\"\\`;;\nesac\n\n`,C=r.nodePath?`export NODE_PATH=\"${p}\"\n`:\"\";return n?E+=`${C}if [ -x ${n} ]; then\n  exec ${n} ${f} ${s} ${h}\"$@\"\nelse\n  exec ${a} ${f} ${s} ${h}\"$@\"\nfi\n`:E+=`${C}${a} ${f} ${s} ${h}\"$@\"\nexit $?\n`,E}function bdt(t,e,r){let s=Vc.relative(Vc.dirname(e),t),a=r.prog&&r.prog.split(\"\\\\\").join(\"/\"),n=a&&`\"${a}$exe\"`,c;s=s.split(\"\\\\\").join(\"/\");let f=Vc.isAbsolute(s)?`\"${s}\"`:`\"$basedir/${s}\"`,p=r.args||\"\",h=EY(r.nodePath),E=h.win32,C=h.posix;n?(c=`\"$basedir/${r.prog}$exe\"`,s=f):(n=f,p=\"\",s=\"\");let S=r.progArgs?`${r.progArgs.join(\" \")} `:\"\",b=`#!/usr/bin/env pwsh\n$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent\n\n$exe=\"\"\n${r.nodePath?`$env_node_path=$env:NODE_PATH\n$env:NODE_PATH=\"${E}\"\n`:\"\"}if ($PSVersionTable.PSVersion -lt \"6.0\" -or $IsWindows) {\n  # Fix case when both the Windows and Linux builds of Node\n  # are installed in the same directory\n  $exe=\".exe\"\n}`;return r.nodePath&&(b+=` else {\n  $env:NODE_PATH=\"${C}\"\n}`),c?b+=`\n$ret=0\nif (Test-Path ${c}) {\n  # Support pipeline input\n  if ($MyInvocation.ExpectingInput) {\n    $input | & ${c} ${p} ${s} ${S}$args\n  } else {\n    & ${c} ${p} ${s} ${S}$args\n  }\n  $ret=$LASTEXITCODE\n} else {\n  # Support pipeline input\n  if ($MyInvocation.ExpectingInput) {\n    $input | & ${n} ${p} ${s} ${S}$args\n  } else {\n    & ${n} ${p} ${s} ${S}$args\n  }\n  $ret=$LASTEXITCODE\n}\n${r.nodePath?`$env:NODE_PATH=$env_node_path\n`:\"\"}exit $ret\n`:b+=`\n# Support pipeline input\nif ($MyInvocation.ExpectingInput) {\n  $input | & ${n} ${p} ${s} ${S}$args\n} else {\n  & ${n} ${p} ${s} ${S}$args\n}\n${r.nodePath?`$env:NODE_PATH=$env_node_path\n`:\"\"}exit $LASTEXITCODE\n`,b}function xdt(t,e){return e.fs_.chmod(t,493)}function EY(t){if(!t)return{win32:\"\",posix:\"\"};let e=typeof t==\"string\"?t.split(Vc.delimiter):Array.from(t),r={};for(let s=0;s<e.length;s++){let a=e[s].split(\"/\").join(\"\\\\\"),n=bBe()?e[s].split(\"\\\\\").join(\"/\").replace(/^([^:\\\\/]*):/,(c,f)=>`/mnt/${f.toLowerCase()}`):e[s];r.win32=r.win32?`${r.win32};${a}`:a,r.posix=r.posix?`${r.posix}:${n}`:n,r[s]={win32:a,posix:n}}return r}kBe.exports=yY});var TY=_((Ctr,zBe)=>{zBe.exports=Ie(\"stream\")});var eve=_((wtr,$Be)=>{\"use strict\";function ZBe(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(t);e&&(s=s.filter(function(a){return Object.getOwnPropertyDescriptor(t,a).enumerable})),r.push.apply(r,s)}return r}function cmt(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?ZBe(Object(r),!0).forEach(function(s){umt(t,s,r[s])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):ZBe(Object(r)).forEach(function(s){Object.defineProperty(t,s,Object.getOwnPropertyDescriptor(r,s))})}return t}function umt(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function fmt(t,e){if(!(t instanceof e))throw new TypeError(\"Cannot call a class as a function\")}function XBe(t,e){for(var r=0;r<e.length;r++){var s=e[r];s.enumerable=s.enumerable||!1,s.configurable=!0,\"value\"in s&&(s.writable=!0),Object.defineProperty(t,s.key,s)}}function Amt(t,e,r){return e&&XBe(t.prototype,e),r&&XBe(t,r),t}var pmt=Ie(\"buffer\"),AN=pmt.Buffer,hmt=Ie(\"util\"),FY=hmt.inspect,gmt=FY&&FY.custom||\"inspect\";function dmt(t,e,r){AN.prototype.copy.call(t,e,r)}$Be.exports=function(){function t(){fmt(this,t),this.head=null,this.tail=null,this.length=0}return Amt(t,[{key:\"push\",value:function(r){var s={data:r,next:null};this.length>0?this.tail.next=s:this.head=s,this.tail=s,++this.length}},{key:\"unshift\",value:function(r){var s={data:r,next:this.head};this.length===0&&(this.tail=s),this.head=s,++this.length}},{key:\"shift\",value:function(){if(this.length!==0){var r=this.head.data;return this.length===1?this.head=this.tail=null:this.head=this.head.next,--this.length,r}}},{key:\"clear\",value:function(){this.head=this.tail=null,this.length=0}},{key:\"join\",value:function(r){if(this.length===0)return\"\";for(var s=this.head,a=\"\"+s.data;s=s.next;)a+=r+s.data;return a}},{key:\"concat\",value:function(r){if(this.length===0)return AN.alloc(0);for(var s=AN.allocUnsafe(r>>>0),a=this.head,n=0;a;)dmt(a.data,s,n),n+=a.data.length,a=a.next;return s}},{key:\"consume\",value:function(r,s){var a;return r<this.head.data.length?(a=this.head.data.slice(0,r),this.head.data=this.head.data.slice(r)):r===this.head.data.length?a=this.shift():a=s?this._getString(r):this._getBuffer(r),a}},{key:\"first\",value:function(){return this.head.data}},{key:\"_getString\",value:function(r){var s=this.head,a=1,n=s.data;for(r-=n.length;s=s.next;){var c=s.data,f=r>c.length?c.length:r;if(f===c.length?n+=c:n+=c.slice(0,r),r-=f,r===0){f===c.length?(++a,s.next?this.head=s.next:this.head=this.tail=null):(this.head=s,s.data=c.slice(f));break}++a}return this.length-=a,n}},{key:\"_getBuffer\",value:function(r){var s=AN.allocUnsafe(r),a=this.head,n=1;for(a.data.copy(s),r-=a.data.length;a=a.next;){var c=a.data,f=r>c.length?c.length:r;if(c.copy(s,s.length-r,0,f),r-=f,r===0){f===c.length?(++n,a.next?this.head=a.next:this.head=this.tail=null):(this.head=a,a.data=c.slice(f));break}++n}return this.length-=n,s}},{key:gmt,value:function(r,s){return FY(this,cmt({},s,{depth:0,customInspect:!1}))}}]),t}()});var OY=_((Btr,rve)=>{\"use strict\";function mmt(t,e){var r=this,s=this._readableState&&this._readableState.destroyed,a=this._writableState&&this._writableState.destroyed;return s||a?(e?e(t):t&&(this._writableState?this._writableState.errorEmitted||(this._writableState.errorEmitted=!0,process.nextTick(NY,this,t)):process.nextTick(NY,this,t)),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(t||null,function(n){!e&&n?r._writableState?r._writableState.errorEmitted?process.nextTick(pN,r):(r._writableState.errorEmitted=!0,process.nextTick(tve,r,n)):process.nextTick(tve,r,n):e?(process.nextTick(pN,r),e(n)):process.nextTick(pN,r)}),this)}function tve(t,e){NY(t,e),pN(t)}function pN(t){t._writableState&&!t._writableState.emitClose||t._readableState&&!t._readableState.emitClose||t.emit(\"close\")}function ymt(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finalCalled=!1,this._writableState.prefinished=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}function NY(t,e){t.emit(\"error\",e)}function Emt(t,e){var r=t._readableState,s=t._writableState;r&&r.autoDestroy||s&&s.autoDestroy?t.destroy(e):t.emit(\"error\",e)}rve.exports={destroy:mmt,undestroy:ymt,errorOrDestroy:Emt}});var lg=_((vtr,sve)=>{\"use strict\";var ive={};function Kc(t,e,r){r||(r=Error);function s(n,c,f){return typeof e==\"string\"?e:e(n,c,f)}class a extends r{constructor(c,f,p){super(s(c,f,p))}}a.prototype.name=r.name,a.prototype.code=t,ive[t]=a}function nve(t,e){if(Array.isArray(t)){let r=t.length;return t=t.map(s=>String(s)),r>2?`one of ${e} ${t.slice(0,r-1).join(\", \")}, or `+t[r-1]:r===2?`one of ${e} ${t[0]} or ${t[1]}`:`of ${e} ${t[0]}`}else return`of ${e} ${String(t)}`}function Imt(t,e,r){return t.substr(!r||r<0?0:+r,e.length)===e}function Cmt(t,e,r){return(r===void 0||r>t.length)&&(r=t.length),t.substring(r-e.length,r)===e}function wmt(t,e,r){return typeof r!=\"number\"&&(r=0),r+e.length>t.length?!1:t.indexOf(e,r)!==-1}Kc(\"ERR_INVALID_OPT_VALUE\",function(t,e){return'The value \"'+e+'\" is invalid for option \"'+t+'\"'},TypeError);Kc(\"ERR_INVALID_ARG_TYPE\",function(t,e,r){let s;typeof e==\"string\"&&Imt(e,\"not \")?(s=\"must not be\",e=e.replace(/^not /,\"\")):s=\"must be\";let a;if(Cmt(t,\" argument\"))a=`The ${t} ${s} ${nve(e,\"type\")}`;else{let n=wmt(t,\".\")?\"property\":\"argument\";a=`The \"${t}\" ${n} ${s} ${nve(e,\"type\")}`}return a+=`. Received type ${typeof r}`,a},TypeError);Kc(\"ERR_STREAM_PUSH_AFTER_EOF\",\"stream.push() after EOF\");Kc(\"ERR_METHOD_NOT_IMPLEMENTED\",function(t){return\"The \"+t+\" method is not implemented\"});Kc(\"ERR_STREAM_PREMATURE_CLOSE\",\"Premature close\");Kc(\"ERR_STREAM_DESTROYED\",function(t){return\"Cannot call \"+t+\" after a stream was destroyed\"});Kc(\"ERR_MULTIPLE_CALLBACK\",\"Callback called multiple times\");Kc(\"ERR_STREAM_CANNOT_PIPE\",\"Cannot pipe, not readable\");Kc(\"ERR_STREAM_WRITE_AFTER_END\",\"write after end\");Kc(\"ERR_STREAM_NULL_VALUES\",\"May not write null values to stream\",TypeError);Kc(\"ERR_UNKNOWN_ENCODING\",function(t){return\"Unknown encoding: \"+t},TypeError);Kc(\"ERR_STREAM_UNSHIFT_AFTER_END_EVENT\",\"stream.unshift() after end event\");sve.exports.codes=ive});var LY=_((Str,ove)=>{\"use strict\";var Bmt=lg().codes.ERR_INVALID_OPT_VALUE;function vmt(t,e,r){return t.highWaterMark!=null?t.highWaterMark:e?t[r]:null}function Smt(t,e,r,s){var a=vmt(e,s,r);if(a!=null){if(!(isFinite(a)&&Math.floor(a)===a)||a<0){var n=s?r:\"highWaterMark\";throw new Bmt(n,a)}return Math.floor(a)}return t.objectMode?16:16*1024}ove.exports={getHighWaterMark:Smt}});var ave=_((Dtr,MY)=>{typeof Object.create==\"function\"?MY.exports=function(e,r){r&&(e.super_=r,e.prototype=Object.create(r.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}))}:MY.exports=function(e,r){if(r){e.super_=r;var s=function(){};s.prototype=r.prototype,e.prototype=new s,e.prototype.constructor=e}}});var cg=_((Ptr,_Y)=>{try{if(UY=Ie(\"util\"),typeof UY.inherits!=\"function\")throw\"\";_Y.exports=UY.inherits}catch{_Y.exports=ave()}var UY});var cve=_((btr,lve)=>{lve.exports=Ie(\"util\").deprecate});var GY=_((xtr,gve)=>{\"use strict\";gve.exports=Yi;function fve(t){var e=this;this.next=null,this.entry=null,this.finish=function(){Xmt(e,t)}}var Rw;Yi.WritableState=XD;var Dmt={deprecate:cve()},Ave=TY(),gN=Ie(\"buffer\").Buffer,Pmt=global.Uint8Array||function(){};function bmt(t){return gN.from(t)}function xmt(t){return gN.isBuffer(t)||t instanceof Pmt}var jY=OY(),kmt=LY(),Qmt=kmt.getHighWaterMark,ug=lg().codes,Rmt=ug.ERR_INVALID_ARG_TYPE,Tmt=ug.ERR_METHOD_NOT_IMPLEMENTED,Fmt=ug.ERR_MULTIPLE_CALLBACK,Nmt=ug.ERR_STREAM_CANNOT_PIPE,Omt=ug.ERR_STREAM_DESTROYED,Lmt=ug.ERR_STREAM_NULL_VALUES,Mmt=ug.ERR_STREAM_WRITE_AFTER_END,Umt=ug.ERR_UNKNOWN_ENCODING,Tw=jY.errorOrDestroy;cg()(Yi,Ave);function _mt(){}function XD(t,e,r){Rw=Rw||Ym(),t=t||{},typeof r!=\"boolean\"&&(r=e instanceof Rw),this.objectMode=!!t.objectMode,r&&(this.objectMode=this.objectMode||!!t.writableObjectMode),this.highWaterMark=Qmt(this,t,\"writableHighWaterMark\",r),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var s=t.decodeStrings===!1;this.decodeStrings=!s,this.defaultEncoding=t.defaultEncoding||\"utf8\",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(a){Vmt(e,a)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.emitClose=t.emitClose!==!1,this.autoDestroy=!!t.autoDestroy,this.bufferedRequestCount=0,this.corkedRequestsFree=new fve(this)}XD.prototype.getBuffer=function(){for(var e=this.bufferedRequest,r=[];e;)r.push(e),e=e.next;return r};(function(){try{Object.defineProperty(XD.prototype,\"buffer\",{get:Dmt.deprecate(function(){return this.getBuffer()},\"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.\",\"DEP0003\")})}catch{}})();var hN;typeof Symbol==\"function\"&&Symbol.hasInstance&&typeof Function.prototype[Symbol.hasInstance]==\"function\"?(hN=Function.prototype[Symbol.hasInstance],Object.defineProperty(Yi,Symbol.hasInstance,{value:function(e){return hN.call(this,e)?!0:this!==Yi?!1:e&&e._writableState instanceof XD}})):hN=function(e){return e instanceof this};function Yi(t){Rw=Rw||Ym();var e=this instanceof Rw;if(!e&&!hN.call(Yi,this))return new Yi(t);this._writableState=new XD(t,this,e),this.writable=!0,t&&(typeof t.write==\"function\"&&(this._write=t.write),typeof t.writev==\"function\"&&(this._writev=t.writev),typeof t.destroy==\"function\"&&(this._destroy=t.destroy),typeof t.final==\"function\"&&(this._final=t.final)),Ave.call(this)}Yi.prototype.pipe=function(){Tw(this,new Nmt)};function Hmt(t,e){var r=new Mmt;Tw(t,r),process.nextTick(e,r)}function jmt(t,e,r,s){var a;return r===null?a=new Lmt:typeof r!=\"string\"&&!e.objectMode&&(a=new Rmt(\"chunk\",[\"string\",\"Buffer\"],r)),a?(Tw(t,a),process.nextTick(s,a),!1):!0}Yi.prototype.write=function(t,e,r){var s=this._writableState,a=!1,n=!s.objectMode&&xmt(t);return n&&!gN.isBuffer(t)&&(t=bmt(t)),typeof e==\"function\"&&(r=e,e=null),n?e=\"buffer\":e||(e=s.defaultEncoding),typeof r!=\"function\"&&(r=_mt),s.ending?Hmt(this,r):(n||jmt(this,s,t,r))&&(s.pendingcb++,a=qmt(this,s,n,t,e,r)),a};Yi.prototype.cork=function(){this._writableState.corked++};Yi.prototype.uncork=function(){var t=this._writableState;t.corked&&(t.corked--,!t.writing&&!t.corked&&!t.bufferProcessing&&t.bufferedRequest&&pve(this,t))};Yi.prototype.setDefaultEncoding=function(e){if(typeof e==\"string\"&&(e=e.toLowerCase()),!([\"hex\",\"utf8\",\"utf-8\",\"ascii\",\"binary\",\"base64\",\"ucs2\",\"ucs-2\",\"utf16le\",\"utf-16le\",\"raw\"].indexOf((e+\"\").toLowerCase())>-1))throw new Umt(e);return this._writableState.defaultEncoding=e,this};Object.defineProperty(Yi.prototype,\"writableBuffer\",{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}});function Gmt(t,e,r){return!t.objectMode&&t.decodeStrings!==!1&&typeof e==\"string\"&&(e=gN.from(e,r)),e}Object.defineProperty(Yi.prototype,\"writableHighWaterMark\",{enumerable:!1,get:function(){return this._writableState.highWaterMark}});function qmt(t,e,r,s,a,n){if(!r){var c=Gmt(e,s,a);s!==c&&(r=!0,a=\"buffer\",s=c)}var f=e.objectMode?1:s.length;e.length+=f;var p=e.length<e.highWaterMark;if(p||(e.needDrain=!0),e.writing||e.corked){var h=e.lastBufferedRequest;e.lastBufferedRequest={chunk:s,encoding:a,isBuf:r,callback:n,next:null},h?h.next=e.lastBufferedRequest:e.bufferedRequest=e.lastBufferedRequest,e.bufferedRequestCount+=1}else HY(t,e,!1,f,s,a,n);return p}function HY(t,e,r,s,a,n,c){e.writelen=s,e.writecb=c,e.writing=!0,e.sync=!0,e.destroyed?e.onwrite(new Omt(\"write\")):r?t._writev(a,e.onwrite):t._write(a,n,e.onwrite),e.sync=!1}function Wmt(t,e,r,s,a){--e.pendingcb,r?(process.nextTick(a,s),process.nextTick(ZD,t,e),t._writableState.errorEmitted=!0,Tw(t,s)):(a(s),t._writableState.errorEmitted=!0,Tw(t,s),ZD(t,e))}function Ymt(t){t.writing=!1,t.writecb=null,t.length-=t.writelen,t.writelen=0}function Vmt(t,e){var r=t._writableState,s=r.sync,a=r.writecb;if(typeof a!=\"function\")throw new Fmt;if(Ymt(r),e)Wmt(t,r,s,e,a);else{var n=hve(r)||t.destroyed;!n&&!r.corked&&!r.bufferProcessing&&r.bufferedRequest&&pve(t,r),s?process.nextTick(uve,t,r,n,a):uve(t,r,n,a)}}function uve(t,e,r,s){r||Jmt(t,e),e.pendingcb--,s(),ZD(t,e)}function Jmt(t,e){e.length===0&&e.needDrain&&(e.needDrain=!1,t.emit(\"drain\"))}function pve(t,e){e.bufferProcessing=!0;var r=e.bufferedRequest;if(t._writev&&r&&r.next){var s=e.bufferedRequestCount,a=new Array(s),n=e.corkedRequestsFree;n.entry=r;for(var c=0,f=!0;r;)a[c]=r,r.isBuf||(f=!1),r=r.next,c+=1;a.allBuffers=f,HY(t,e,!0,e.length,a,\"\",n.finish),e.pendingcb++,e.lastBufferedRequest=null,n.next?(e.corkedRequestsFree=n.next,n.next=null):e.corkedRequestsFree=new fve(e),e.bufferedRequestCount=0}else{for(;r;){var p=r.chunk,h=r.encoding,E=r.callback,C=e.objectMode?1:p.length;if(HY(t,e,!1,C,p,h,E),r=r.next,e.bufferedRequestCount--,e.writing)break}r===null&&(e.lastBufferedRequest=null)}e.bufferedRequest=r,e.bufferProcessing=!1}Yi.prototype._write=function(t,e,r){r(new Tmt(\"_write()\"))};Yi.prototype._writev=null;Yi.prototype.end=function(t,e,r){var s=this._writableState;return typeof t==\"function\"?(r=t,t=null,e=null):typeof e==\"function\"&&(r=e,e=null),t!=null&&this.write(t,e),s.corked&&(s.corked=1,this.uncork()),s.ending||Zmt(this,s,r),this};Object.defineProperty(Yi.prototype,\"writableLength\",{enumerable:!1,get:function(){return this._writableState.length}});function hve(t){return t.ending&&t.length===0&&t.bufferedRequest===null&&!t.finished&&!t.writing}function Kmt(t,e){t._final(function(r){e.pendingcb--,r&&Tw(t,r),e.prefinished=!0,t.emit(\"prefinish\"),ZD(t,e)})}function zmt(t,e){!e.prefinished&&!e.finalCalled&&(typeof t._final==\"function\"&&!e.destroyed?(e.pendingcb++,e.finalCalled=!0,process.nextTick(Kmt,t,e)):(e.prefinished=!0,t.emit(\"prefinish\")))}function ZD(t,e){var r=hve(e);if(r&&(zmt(t,e),e.pendingcb===0&&(e.finished=!0,t.emit(\"finish\"),e.autoDestroy))){var s=t._readableState;(!s||s.autoDestroy&&s.endEmitted)&&t.destroy()}return r}function Zmt(t,e,r){e.ending=!0,ZD(t,e),r&&(e.finished?process.nextTick(r):t.once(\"finish\",r)),e.ended=!0,t.writable=!1}function Xmt(t,e,r){var s=t.entry;for(t.entry=null;s;){var a=s.callback;e.pendingcb--,a(r),s=s.next}e.corkedRequestsFree.next=t}Object.defineProperty(Yi.prototype,\"destroyed\",{enumerable:!1,get:function(){return this._writableState===void 0?!1:this._writableState.destroyed},set:function(e){this._writableState&&(this._writableState.destroyed=e)}});Yi.prototype.destroy=jY.destroy;Yi.prototype._undestroy=jY.undestroy;Yi.prototype._destroy=function(t,e){e(t)}});var Ym=_((ktr,mve)=>{\"use strict\";var $mt=Object.keys||function(t){var e=[];for(var r in t)e.push(r);return e};mve.exports=dA;var dve=YY(),WY=GY();cg()(dA,dve);for(qY=$mt(WY.prototype),dN=0;dN<qY.length;dN++)mN=qY[dN],dA.prototype[mN]||(dA.prototype[mN]=WY.prototype[mN]);var qY,mN,dN;function dA(t){if(!(this instanceof dA))return new dA(t);dve.call(this,t),WY.call(this,t),this.allowHalfOpen=!0,t&&(t.readable===!1&&(this.readable=!1),t.writable===!1&&(this.writable=!1),t.allowHalfOpen===!1&&(this.allowHalfOpen=!1,this.once(\"end\",eyt)))}Object.defineProperty(dA.prototype,\"writableHighWaterMark\",{enumerable:!1,get:function(){return this._writableState.highWaterMark}});Object.defineProperty(dA.prototype,\"writableBuffer\",{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}});Object.defineProperty(dA.prototype,\"writableLength\",{enumerable:!1,get:function(){return this._writableState.length}});function eyt(){this._writableState.ended||process.nextTick(tyt,this)}function tyt(t){t.end()}Object.defineProperty(dA.prototype,\"destroyed\",{enumerable:!1,get:function(){return this._readableState===void 0||this._writableState===void 0?!1:this._readableState.destroyed&&this._writableState.destroyed},set:function(e){this._readableState===void 0||this._writableState===void 0||(this._readableState.destroyed=e,this._writableState.destroyed=e)}})});var Ive=_((VY,Eve)=>{var yN=Ie(\"buffer\"),ah=yN.Buffer;function yve(t,e){for(var r in t)e[r]=t[r]}ah.from&&ah.alloc&&ah.allocUnsafe&&ah.allocUnsafeSlow?Eve.exports=yN:(yve(yN,VY),VY.Buffer=Fw);function Fw(t,e,r){return ah(t,e,r)}yve(ah,Fw);Fw.from=function(t,e,r){if(typeof t==\"number\")throw new TypeError(\"Argument must not be a number\");return ah(t,e,r)};Fw.alloc=function(t,e,r){if(typeof t!=\"number\")throw new TypeError(\"Argument must be a number\");var s=ah(t);return e!==void 0?typeof r==\"string\"?s.fill(e,r):s.fill(e):s.fill(0),s};Fw.allocUnsafe=function(t){if(typeof t!=\"number\")throw new TypeError(\"Argument must be a number\");return ah(t)};Fw.allocUnsafeSlow=function(t){if(typeof t!=\"number\")throw new TypeError(\"Argument must be a number\");return yN.SlowBuffer(t)}});var zY=_(wve=>{\"use strict\";var KY=Ive().Buffer,Cve=KY.isEncoding||function(t){switch(t=\"\"+t,t&&t.toLowerCase()){case\"hex\":case\"utf8\":case\"utf-8\":case\"ascii\":case\"binary\":case\"base64\":case\"ucs2\":case\"ucs-2\":case\"utf16le\":case\"utf-16le\":case\"raw\":return!0;default:return!1}};function ryt(t){if(!t)return\"utf8\";for(var e;;)switch(t){case\"utf8\":case\"utf-8\":return\"utf8\";case\"ucs2\":case\"ucs-2\":case\"utf16le\":case\"utf-16le\":return\"utf16le\";case\"latin1\":case\"binary\":return\"latin1\";case\"base64\":case\"ascii\":case\"hex\":return t;default:if(e)return;t=(\"\"+t).toLowerCase(),e=!0}}function nyt(t){var e=ryt(t);if(typeof e!=\"string\"&&(KY.isEncoding===Cve||!Cve(t)))throw new Error(\"Unknown encoding: \"+t);return e||t}wve.StringDecoder=$D;function $D(t){this.encoding=nyt(t);var e;switch(this.encoding){case\"utf16le\":this.text=cyt,this.end=uyt,e=4;break;case\"utf8\":this.fillLast=oyt,e=4;break;case\"base64\":this.text=fyt,this.end=Ayt,e=3;break;default:this.write=pyt,this.end=hyt;return}this.lastNeed=0,this.lastTotal=0,this.lastChar=KY.allocUnsafe(e)}$D.prototype.write=function(t){if(t.length===0)return\"\";var e,r;if(this.lastNeed){if(e=this.fillLast(t),e===void 0)return\"\";r=this.lastNeed,this.lastNeed=0}else r=0;return r<t.length?e?e+this.text(t,r):this.text(t,r):e||\"\"};$D.prototype.end=lyt;$D.prototype.text=ayt;$D.prototype.fillLast=function(t){if(this.lastNeed<=t.length)return t.copy(this.lastChar,this.lastTotal-this.lastNeed,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);t.copy(this.lastChar,this.lastTotal-this.lastNeed,0,t.length),this.lastNeed-=t.length};function JY(t){return t<=127?0:t>>5===6?2:t>>4===14?3:t>>3===30?4:t>>6===2?-1:-2}function iyt(t,e,r){var s=e.length-1;if(s<r)return 0;var a=JY(e[s]);return a>=0?(a>0&&(t.lastNeed=a-1),a):--s<r||a===-2?0:(a=JY(e[s]),a>=0?(a>0&&(t.lastNeed=a-2),a):--s<r||a===-2?0:(a=JY(e[s]),a>=0?(a>0&&(a===2?a=0:t.lastNeed=a-3),a):0))}function syt(t,e,r){if((e[0]&192)!==128)return t.lastNeed=0,\"\\uFFFD\";if(t.lastNeed>1&&e.length>1){if((e[1]&192)!==128)return t.lastNeed=1,\"\\uFFFD\";if(t.lastNeed>2&&e.length>2&&(e[2]&192)!==128)return t.lastNeed=2,\"\\uFFFD\"}}function oyt(t){var e=this.lastTotal-this.lastNeed,r=syt(this,t,e);if(r!==void 0)return r;if(this.lastNeed<=t.length)return t.copy(this.lastChar,e,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);t.copy(this.lastChar,e,0,t.length),this.lastNeed-=t.length}function ayt(t,e){var r=iyt(this,t,e);if(!this.lastNeed)return t.toString(\"utf8\",e);this.lastTotal=r;var s=t.length-(r-this.lastNeed);return t.copy(this.lastChar,0,s),t.toString(\"utf8\",e,s)}function lyt(t){var e=t&&t.length?this.write(t):\"\";return this.lastNeed?e+\"\\uFFFD\":e}function cyt(t,e){if((t.length-e)%2===0){var r=t.toString(\"utf16le\",e);if(r){var s=r.charCodeAt(r.length-1);if(s>=55296&&s<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=t[t.length-2],this.lastChar[1]=t[t.length-1],r.slice(0,-1)}return r}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=t[t.length-1],t.toString(\"utf16le\",e,t.length-1)}function uyt(t){var e=t&&t.length?this.write(t):\"\";if(this.lastNeed){var r=this.lastTotal-this.lastNeed;return e+this.lastChar.toString(\"utf16le\",0,r)}return e}function fyt(t,e){var r=(t.length-e)%3;return r===0?t.toString(\"base64\",e):(this.lastNeed=3-r,this.lastTotal=3,r===1?this.lastChar[0]=t[t.length-1]:(this.lastChar[0]=t[t.length-2],this.lastChar[1]=t[t.length-1]),t.toString(\"base64\",e,t.length-r))}function Ayt(t){var e=t&&t.length?this.write(t):\"\";return this.lastNeed?e+this.lastChar.toString(\"base64\",0,3-this.lastNeed):e}function pyt(t){return t.toString(this.encoding)}function hyt(t){return t&&t.length?this.write(t):\"\"}});var EN=_((Rtr,Sve)=>{\"use strict\";var Bve=lg().codes.ERR_STREAM_PREMATURE_CLOSE;function gyt(t){var e=!1;return function(){if(!e){e=!0;for(var r=arguments.length,s=new Array(r),a=0;a<r;a++)s[a]=arguments[a];t.apply(this,s)}}}function dyt(){}function myt(t){return t.setHeader&&typeof t.abort==\"function\"}function vve(t,e,r){if(typeof e==\"function\")return vve(t,null,e);e||(e={}),r=gyt(r||dyt);var s=e.readable||e.readable!==!1&&t.readable,a=e.writable||e.writable!==!1&&t.writable,n=function(){t.writable||f()},c=t._writableState&&t._writableState.finished,f=function(){a=!1,c=!0,s||r.call(t)},p=t._readableState&&t._readableState.endEmitted,h=function(){s=!1,p=!0,a||r.call(t)},E=function(I){r.call(t,I)},C=function(){var I;if(s&&!p)return(!t._readableState||!t._readableState.ended)&&(I=new Bve),r.call(t,I);if(a&&!c)return(!t._writableState||!t._writableState.ended)&&(I=new Bve),r.call(t,I)},S=function(){t.req.on(\"finish\",f)};return myt(t)?(t.on(\"complete\",f),t.on(\"abort\",C),t.req?S():t.on(\"request\",S)):a&&!t._writableState&&(t.on(\"end\",n),t.on(\"close\",n)),t.on(\"end\",h),t.on(\"finish\",f),e.error!==!1&&t.on(\"error\",E),t.on(\"close\",C),function(){t.removeListener(\"complete\",f),t.removeListener(\"abort\",C),t.removeListener(\"request\",S),t.req&&t.req.removeListener(\"finish\",f),t.removeListener(\"end\",n),t.removeListener(\"close\",n),t.removeListener(\"finish\",f),t.removeListener(\"end\",h),t.removeListener(\"error\",E),t.removeListener(\"close\",C)}}Sve.exports=vve});var Pve=_((Ttr,Dve)=>{\"use strict\";var IN;function fg(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var yyt=EN(),Ag=Symbol(\"lastResolve\"),Vm=Symbol(\"lastReject\"),eP=Symbol(\"error\"),CN=Symbol(\"ended\"),Jm=Symbol(\"lastPromise\"),ZY=Symbol(\"handlePromise\"),Km=Symbol(\"stream\");function pg(t,e){return{value:t,done:e}}function Eyt(t){var e=t[Ag];if(e!==null){var r=t[Km].read();r!==null&&(t[Jm]=null,t[Ag]=null,t[Vm]=null,e(pg(r,!1)))}}function Iyt(t){process.nextTick(Eyt,t)}function Cyt(t,e){return function(r,s){t.then(function(){if(e[CN]){r(pg(void 0,!0));return}e[ZY](r,s)},s)}}var wyt=Object.getPrototypeOf(function(){}),Byt=Object.setPrototypeOf((IN={get stream(){return this[Km]},next:function(){var e=this,r=this[eP];if(r!==null)return Promise.reject(r);if(this[CN])return Promise.resolve(pg(void 0,!0));if(this[Km].destroyed)return new Promise(function(c,f){process.nextTick(function(){e[eP]?f(e[eP]):c(pg(void 0,!0))})});var s=this[Jm],a;if(s)a=new Promise(Cyt(s,this));else{var n=this[Km].read();if(n!==null)return Promise.resolve(pg(n,!1));a=new Promise(this[ZY])}return this[Jm]=a,a}},fg(IN,Symbol.asyncIterator,function(){return this}),fg(IN,\"return\",function(){var e=this;return new Promise(function(r,s){e[Km].destroy(null,function(a){if(a){s(a);return}r(pg(void 0,!0))})})}),IN),wyt),vyt=function(e){var r,s=Object.create(Byt,(r={},fg(r,Km,{value:e,writable:!0}),fg(r,Ag,{value:null,writable:!0}),fg(r,Vm,{value:null,writable:!0}),fg(r,eP,{value:null,writable:!0}),fg(r,CN,{value:e._readableState.endEmitted,writable:!0}),fg(r,ZY,{value:function(n,c){var f=s[Km].read();f?(s[Jm]=null,s[Ag]=null,s[Vm]=null,n(pg(f,!1))):(s[Ag]=n,s[Vm]=c)},writable:!0}),r));return s[Jm]=null,yyt(e,function(a){if(a&&a.code!==\"ERR_STREAM_PREMATURE_CLOSE\"){var n=s[Vm];n!==null&&(s[Jm]=null,s[Ag]=null,s[Vm]=null,n(a)),s[eP]=a;return}var c=s[Ag];c!==null&&(s[Jm]=null,s[Ag]=null,s[Vm]=null,c(pg(void 0,!0))),s[CN]=!0}),e.on(\"readable\",Iyt.bind(null,s)),s};Dve.exports=vyt});var Qve=_((Ftr,kve)=>{\"use strict\";function bve(t,e,r,s,a,n,c){try{var f=t[n](c),p=f.value}catch(h){r(h);return}f.done?e(p):Promise.resolve(p).then(s,a)}function Syt(t){return function(){var e=this,r=arguments;return new Promise(function(s,a){var n=t.apply(e,r);function c(p){bve(n,s,a,c,f,\"next\",p)}function f(p){bve(n,s,a,c,f,\"throw\",p)}c(void 0)})}}function xve(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(t);e&&(s=s.filter(function(a){return Object.getOwnPropertyDescriptor(t,a).enumerable})),r.push.apply(r,s)}return r}function Dyt(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?xve(Object(r),!0).forEach(function(s){Pyt(t,s,r[s])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):xve(Object(r)).forEach(function(s){Object.defineProperty(t,s,Object.getOwnPropertyDescriptor(r,s))})}return t}function Pyt(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var byt=lg().codes.ERR_INVALID_ARG_TYPE;function xyt(t,e,r){var s;if(e&&typeof e.next==\"function\")s=e;else if(e&&e[Symbol.asyncIterator])s=e[Symbol.asyncIterator]();else if(e&&e[Symbol.iterator])s=e[Symbol.iterator]();else throw new byt(\"iterable\",[\"Iterable\"],e);var a=new t(Dyt({objectMode:!0},r)),n=!1;a._read=function(){n||(n=!0,c())};function c(){return f.apply(this,arguments)}function f(){return f=Syt(function*(){try{var p=yield s.next(),h=p.value,E=p.done;E?a.push(null):a.push(yield h)?c():n=!1}catch(C){a.destroy(C)}}),f.apply(this,arguments)}return a}kve.exports=xyt});var YY=_((Otr,Hve)=>{\"use strict\";Hve.exports=bn;var Nw;bn.ReadableState=Nve;var Ntr=Ie(\"events\").EventEmitter,Fve=function(e,r){return e.listeners(r).length},rP=TY(),wN=Ie(\"buffer\").Buffer,kyt=global.Uint8Array||function(){};function Qyt(t){return wN.from(t)}function Ryt(t){return wN.isBuffer(t)||t instanceof kyt}var XY=Ie(\"util\"),cn;XY&&XY.debuglog?cn=XY.debuglog(\"stream\"):cn=function(){};var Tyt=eve(),sV=OY(),Fyt=LY(),Nyt=Fyt.getHighWaterMark,BN=lg().codes,Oyt=BN.ERR_INVALID_ARG_TYPE,Lyt=BN.ERR_STREAM_PUSH_AFTER_EOF,Myt=BN.ERR_METHOD_NOT_IMPLEMENTED,Uyt=BN.ERR_STREAM_UNSHIFT_AFTER_END_EVENT,Ow,$Y,eV;cg()(bn,rP);var tP=sV.errorOrDestroy,tV=[\"error\",\"close\",\"destroy\",\"pause\",\"resume\"];function _yt(t,e,r){if(typeof t.prependListener==\"function\")return t.prependListener(e,r);!t._events||!t._events[e]?t.on(e,r):Array.isArray(t._events[e])?t._events[e].unshift(r):t._events[e]=[r,t._events[e]]}function Nve(t,e,r){Nw=Nw||Ym(),t=t||{},typeof r!=\"boolean\"&&(r=e instanceof Nw),this.objectMode=!!t.objectMode,r&&(this.objectMode=this.objectMode||!!t.readableObjectMode),this.highWaterMark=Nyt(this,t,\"readableHighWaterMark\",r),this.buffer=new Tyt,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.paused=!0,this.emitClose=t.emitClose!==!1,this.autoDestroy=!!t.autoDestroy,this.destroyed=!1,this.defaultEncoding=t.defaultEncoding||\"utf8\",this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,t.encoding&&(Ow||(Ow=zY().StringDecoder),this.decoder=new Ow(t.encoding),this.encoding=t.encoding)}function bn(t){if(Nw=Nw||Ym(),!(this instanceof bn))return new bn(t);var e=this instanceof Nw;this._readableState=new Nve(t,this,e),this.readable=!0,t&&(typeof t.read==\"function\"&&(this._read=t.read),typeof t.destroy==\"function\"&&(this._destroy=t.destroy)),rP.call(this)}Object.defineProperty(bn.prototype,\"destroyed\",{enumerable:!1,get:function(){return this._readableState===void 0?!1:this._readableState.destroyed},set:function(e){this._readableState&&(this._readableState.destroyed=e)}});bn.prototype.destroy=sV.destroy;bn.prototype._undestroy=sV.undestroy;bn.prototype._destroy=function(t,e){e(t)};bn.prototype.push=function(t,e){var r=this._readableState,s;return r.objectMode?s=!0:typeof t==\"string\"&&(e=e||r.defaultEncoding,e!==r.encoding&&(t=wN.from(t,e),e=\"\"),s=!0),Ove(this,t,e,!1,s)};bn.prototype.unshift=function(t){return Ove(this,t,null,!0,!1)};function Ove(t,e,r,s,a){cn(\"readableAddChunk\",e);var n=t._readableState;if(e===null)n.reading=!1,Gyt(t,n);else{var c;if(a||(c=Hyt(n,e)),c)tP(t,c);else if(n.objectMode||e&&e.length>0)if(typeof e!=\"string\"&&!n.objectMode&&Object.getPrototypeOf(e)!==wN.prototype&&(e=Qyt(e)),s)n.endEmitted?tP(t,new Uyt):rV(t,n,e,!0);else if(n.ended)tP(t,new Lyt);else{if(n.destroyed)return!1;n.reading=!1,n.decoder&&!r?(e=n.decoder.write(e),n.objectMode||e.length!==0?rV(t,n,e,!1):iV(t,n)):rV(t,n,e,!1)}else s||(n.reading=!1,iV(t,n))}return!n.ended&&(n.length<n.highWaterMark||n.length===0)}function rV(t,e,r,s){e.flowing&&e.length===0&&!e.sync?(e.awaitDrain=0,t.emit(\"data\",r)):(e.length+=e.objectMode?1:r.length,s?e.buffer.unshift(r):e.buffer.push(r),e.needReadable&&vN(t)),iV(t,e)}function Hyt(t,e){var r;return!Ryt(e)&&typeof e!=\"string\"&&e!==void 0&&!t.objectMode&&(r=new Oyt(\"chunk\",[\"string\",\"Buffer\",\"Uint8Array\"],e)),r}bn.prototype.isPaused=function(){return this._readableState.flowing===!1};bn.prototype.setEncoding=function(t){Ow||(Ow=zY().StringDecoder);var e=new Ow(t);this._readableState.decoder=e,this._readableState.encoding=this._readableState.decoder.encoding;for(var r=this._readableState.buffer.head,s=\"\";r!==null;)s+=e.write(r.data),r=r.next;return this._readableState.buffer.clear(),s!==\"\"&&this._readableState.buffer.push(s),this._readableState.length=s.length,this};var Rve=1073741824;function jyt(t){return t>=Rve?t=Rve:(t--,t|=t>>>1,t|=t>>>2,t|=t>>>4,t|=t>>>8,t|=t>>>16,t++),t}function Tve(t,e){return t<=0||e.length===0&&e.ended?0:e.objectMode?1:t!==t?e.flowing&&e.length?e.buffer.head.data.length:e.length:(t>e.highWaterMark&&(e.highWaterMark=jyt(t)),t<=e.length?t:e.ended?e.length:(e.needReadable=!0,0))}bn.prototype.read=function(t){cn(\"read\",t),t=parseInt(t,10);var e=this._readableState,r=t;if(t!==0&&(e.emittedReadable=!1),t===0&&e.needReadable&&((e.highWaterMark!==0?e.length>=e.highWaterMark:e.length>0)||e.ended))return cn(\"read: emitReadable\",e.length,e.ended),e.length===0&&e.ended?nV(this):vN(this),null;if(t=Tve(t,e),t===0&&e.ended)return e.length===0&&nV(this),null;var s=e.needReadable;cn(\"need readable\",s),(e.length===0||e.length-t<e.highWaterMark)&&(s=!0,cn(\"length less than watermark\",s)),e.ended||e.reading?(s=!1,cn(\"reading or ended\",s)):s&&(cn(\"do read\"),e.reading=!0,e.sync=!0,e.length===0&&(e.needReadable=!0),this._read(e.highWaterMark),e.sync=!1,e.reading||(t=Tve(r,e)));var a;return t>0?a=Uve(t,e):a=null,a===null?(e.needReadable=e.length<=e.highWaterMark,t=0):(e.length-=t,e.awaitDrain=0),e.length===0&&(e.ended||(e.needReadable=!0),r!==t&&e.ended&&nV(this)),a!==null&&this.emit(\"data\",a),a};function Gyt(t,e){if(cn(\"onEofChunk\"),!e.ended){if(e.decoder){var r=e.decoder.end();r&&r.length&&(e.buffer.push(r),e.length+=e.objectMode?1:r.length)}e.ended=!0,e.sync?vN(t):(e.needReadable=!1,e.emittedReadable||(e.emittedReadable=!0,Lve(t)))}}function vN(t){var e=t._readableState;cn(\"emitReadable\",e.needReadable,e.emittedReadable),e.needReadable=!1,e.emittedReadable||(cn(\"emitReadable\",e.flowing),e.emittedReadable=!0,process.nextTick(Lve,t))}function Lve(t){var e=t._readableState;cn(\"emitReadable_\",e.destroyed,e.length,e.ended),!e.destroyed&&(e.length||e.ended)&&(t.emit(\"readable\"),e.emittedReadable=!1),e.needReadable=!e.flowing&&!e.ended&&e.length<=e.highWaterMark,oV(t)}function iV(t,e){e.readingMore||(e.readingMore=!0,process.nextTick(qyt,t,e))}function qyt(t,e){for(;!e.reading&&!e.ended&&(e.length<e.highWaterMark||e.flowing&&e.length===0);){var r=e.length;if(cn(\"maybeReadMore read 0\"),t.read(0),r===e.length)break}e.readingMore=!1}bn.prototype._read=function(t){tP(this,new Myt(\"_read()\"))};bn.prototype.pipe=function(t,e){var r=this,s=this._readableState;switch(s.pipesCount){case 0:s.pipes=t;break;case 1:s.pipes=[s.pipes,t];break;default:s.pipes.push(t);break}s.pipesCount+=1,cn(\"pipe count=%d opts=%j\",s.pipesCount,e);var a=(!e||e.end!==!1)&&t!==process.stdout&&t!==process.stderr,n=a?f:T;s.endEmitted?process.nextTick(n):r.once(\"end\",n),t.on(\"unpipe\",c);function c(N,U){cn(\"onunpipe\"),N===r&&U&&U.hasUnpiped===!1&&(U.hasUnpiped=!0,E())}function f(){cn(\"onend\"),t.end()}var p=Wyt(r);t.on(\"drain\",p);var h=!1;function E(){cn(\"cleanup\"),t.removeListener(\"close\",b),t.removeListener(\"finish\",I),t.removeListener(\"drain\",p),t.removeListener(\"error\",S),t.removeListener(\"unpipe\",c),r.removeListener(\"end\",f),r.removeListener(\"end\",T),r.removeListener(\"data\",C),h=!0,s.awaitDrain&&(!t._writableState||t._writableState.needDrain)&&p()}r.on(\"data\",C);function C(N){cn(\"ondata\");var U=t.write(N);cn(\"dest.write\",U),U===!1&&((s.pipesCount===1&&s.pipes===t||s.pipesCount>1&&_ve(s.pipes,t)!==-1)&&!h&&(cn(\"false write response, pause\",s.awaitDrain),s.awaitDrain++),r.pause())}function S(N){cn(\"onerror\",N),T(),t.removeListener(\"error\",S),Fve(t,\"error\")===0&&tP(t,N)}_yt(t,\"error\",S);function b(){t.removeListener(\"finish\",I),T()}t.once(\"close\",b);function I(){cn(\"onfinish\"),t.removeListener(\"close\",b),T()}t.once(\"finish\",I);function T(){cn(\"unpipe\"),r.unpipe(t)}return t.emit(\"pipe\",r),s.flowing||(cn(\"pipe resume\"),r.resume()),t};function Wyt(t){return function(){var r=t._readableState;cn(\"pipeOnDrain\",r.awaitDrain),r.awaitDrain&&r.awaitDrain--,r.awaitDrain===0&&Fve(t,\"data\")&&(r.flowing=!0,oV(t))}}bn.prototype.unpipe=function(t){var e=this._readableState,r={hasUnpiped:!1};if(e.pipesCount===0)return this;if(e.pipesCount===1)return t&&t!==e.pipes?this:(t||(t=e.pipes),e.pipes=null,e.pipesCount=0,e.flowing=!1,t&&t.emit(\"unpipe\",this,r),this);if(!t){var s=e.pipes,a=e.pipesCount;e.pipes=null,e.pipesCount=0,e.flowing=!1;for(var n=0;n<a;n++)s[n].emit(\"unpipe\",this,{hasUnpiped:!1});return this}var c=_ve(e.pipes,t);return c===-1?this:(e.pipes.splice(c,1),e.pipesCount-=1,e.pipesCount===1&&(e.pipes=e.pipes[0]),t.emit(\"unpipe\",this,r),this)};bn.prototype.on=function(t,e){var r=rP.prototype.on.call(this,t,e),s=this._readableState;return t===\"data\"?(s.readableListening=this.listenerCount(\"readable\")>0,s.flowing!==!1&&this.resume()):t===\"readable\"&&!s.endEmitted&&!s.readableListening&&(s.readableListening=s.needReadable=!0,s.flowing=!1,s.emittedReadable=!1,cn(\"on readable\",s.length,s.reading),s.length?vN(this):s.reading||process.nextTick(Yyt,this)),r};bn.prototype.addListener=bn.prototype.on;bn.prototype.removeListener=function(t,e){var r=rP.prototype.removeListener.call(this,t,e);return t===\"readable\"&&process.nextTick(Mve,this),r};bn.prototype.removeAllListeners=function(t){var e=rP.prototype.removeAllListeners.apply(this,arguments);return(t===\"readable\"||t===void 0)&&process.nextTick(Mve,this),e};function Mve(t){var e=t._readableState;e.readableListening=t.listenerCount(\"readable\")>0,e.resumeScheduled&&!e.paused?e.flowing=!0:t.listenerCount(\"data\")>0&&t.resume()}function Yyt(t){cn(\"readable nexttick read 0\"),t.read(0)}bn.prototype.resume=function(){var t=this._readableState;return t.flowing||(cn(\"resume\"),t.flowing=!t.readableListening,Vyt(this,t)),t.paused=!1,this};function Vyt(t,e){e.resumeScheduled||(e.resumeScheduled=!0,process.nextTick(Jyt,t,e))}function Jyt(t,e){cn(\"resume\",e.reading),e.reading||t.read(0),e.resumeScheduled=!1,t.emit(\"resume\"),oV(t),e.flowing&&!e.reading&&t.read(0)}bn.prototype.pause=function(){return cn(\"call pause flowing=%j\",this._readableState.flowing),this._readableState.flowing!==!1&&(cn(\"pause\"),this._readableState.flowing=!1,this.emit(\"pause\")),this._readableState.paused=!0,this};function oV(t){var e=t._readableState;for(cn(\"flow\",e.flowing);e.flowing&&t.read()!==null;);}bn.prototype.wrap=function(t){var e=this,r=this._readableState,s=!1;t.on(\"end\",function(){if(cn(\"wrapped end\"),r.decoder&&!r.ended){var c=r.decoder.end();c&&c.length&&e.push(c)}e.push(null)}),t.on(\"data\",function(c){if(cn(\"wrapped data\"),r.decoder&&(c=r.decoder.write(c)),!(r.objectMode&&c==null)&&!(!r.objectMode&&(!c||!c.length))){var f=e.push(c);f||(s=!0,t.pause())}});for(var a in t)this[a]===void 0&&typeof t[a]==\"function\"&&(this[a]=function(f){return function(){return t[f].apply(t,arguments)}}(a));for(var n=0;n<tV.length;n++)t.on(tV[n],this.emit.bind(this,tV[n]));return this._read=function(c){cn(\"wrapped _read\",c),s&&(s=!1,t.resume())},this};typeof Symbol==\"function\"&&(bn.prototype[Symbol.asyncIterator]=function(){return $Y===void 0&&($Y=Pve()),$Y(this)});Object.defineProperty(bn.prototype,\"readableHighWaterMark\",{enumerable:!1,get:function(){return this._readableState.highWaterMark}});Object.defineProperty(bn.prototype,\"readableBuffer\",{enumerable:!1,get:function(){return this._readableState&&this._readableState.buffer}});Object.defineProperty(bn.prototype,\"readableFlowing\",{enumerable:!1,get:function(){return this._readableState.flowing},set:function(e){this._readableState&&(this._readableState.flowing=e)}});bn._fromList=Uve;Object.defineProperty(bn.prototype,\"readableLength\",{enumerable:!1,get:function(){return this._readableState.length}});function Uve(t,e){if(e.length===0)return null;var r;return e.objectMode?r=e.buffer.shift():!t||t>=e.length?(e.decoder?r=e.buffer.join(\"\"):e.buffer.length===1?r=e.buffer.first():r=e.buffer.concat(e.length),e.buffer.clear()):r=e.buffer.consume(t,e.decoder),r}function nV(t){var e=t._readableState;cn(\"endReadable\",e.endEmitted),e.endEmitted||(e.ended=!0,process.nextTick(Kyt,e,t))}function Kyt(t,e){if(cn(\"endReadableNT\",t.endEmitted,t.length),!t.endEmitted&&t.length===0&&(t.endEmitted=!0,e.readable=!1,e.emit(\"end\"),t.autoDestroy)){var r=e._writableState;(!r||r.autoDestroy&&r.finished)&&e.destroy()}}typeof Symbol==\"function\"&&(bn.from=function(t,e){return eV===void 0&&(eV=Qve()),eV(bn,t,e)});function _ve(t,e){for(var r=0,s=t.length;r<s;r++)if(t[r]===e)return r;return-1}});var aV=_((Ltr,Gve)=>{\"use strict\";Gve.exports=lh;var SN=lg().codes,zyt=SN.ERR_METHOD_NOT_IMPLEMENTED,Zyt=SN.ERR_MULTIPLE_CALLBACK,Xyt=SN.ERR_TRANSFORM_ALREADY_TRANSFORMING,$yt=SN.ERR_TRANSFORM_WITH_LENGTH_0,DN=Ym();cg()(lh,DN);function eEt(t,e){var r=this._transformState;r.transforming=!1;var s=r.writecb;if(s===null)return this.emit(\"error\",new Zyt);r.writechunk=null,r.writecb=null,e!=null&&this.push(e),s(t);var a=this._readableState;a.reading=!1,(a.needReadable||a.length<a.highWaterMark)&&this._read(a.highWaterMark)}function lh(t){if(!(this instanceof lh))return new lh(t);DN.call(this,t),this._transformState={afterTransform:eEt.bind(this),needTransform:!1,transforming:!1,writecb:null,writechunk:null,writeencoding:null},this._readableState.needReadable=!0,this._readableState.sync=!1,t&&(typeof t.transform==\"function\"&&(this._transform=t.transform),typeof t.flush==\"function\"&&(this._flush=t.flush)),this.on(\"prefinish\",tEt)}function tEt(){var t=this;typeof this._flush==\"function\"&&!this._readableState.destroyed?this._flush(function(e,r){jve(t,e,r)}):jve(this,null,null)}lh.prototype.push=function(t,e){return this._transformState.needTransform=!1,DN.prototype.push.call(this,t,e)};lh.prototype._transform=function(t,e,r){r(new zyt(\"_transform()\"))};lh.prototype._write=function(t,e,r){var s=this._transformState;if(s.writecb=r,s.writechunk=t,s.writeencoding=e,!s.transforming){var a=this._readableState;(s.needTransform||a.needReadable||a.length<a.highWaterMark)&&this._read(a.highWaterMark)}};lh.prototype._read=function(t){var e=this._transformState;e.writechunk!==null&&!e.transforming?(e.transforming=!0,this._transform(e.writechunk,e.writeencoding,e.afterTransform)):e.needTransform=!0};lh.prototype._destroy=function(t,e){DN.prototype._destroy.call(this,t,function(r){e(r)})};function jve(t,e,r){if(e)return t.emit(\"error\",e);if(r!=null&&t.push(r),t._writableState.length)throw new $yt;if(t._transformState.transforming)throw new Xyt;return t.push(null)}});var Yve=_((Mtr,Wve)=>{\"use strict\";Wve.exports=nP;var qve=aV();cg()(nP,qve);function nP(t){if(!(this instanceof nP))return new nP(t);qve.call(this,t)}nP.prototype._transform=function(t,e,r){r(null,t)}});var Zve=_((Utr,zve)=>{\"use strict\";var lV;function rEt(t){var e=!1;return function(){e||(e=!0,t.apply(void 0,arguments))}}var Kve=lg().codes,nEt=Kve.ERR_MISSING_ARGS,iEt=Kve.ERR_STREAM_DESTROYED;function Vve(t){if(t)throw t}function sEt(t){return t.setHeader&&typeof t.abort==\"function\"}function oEt(t,e,r,s){s=rEt(s);var a=!1;t.on(\"close\",function(){a=!0}),lV===void 0&&(lV=EN()),lV(t,{readable:e,writable:r},function(c){if(c)return s(c);a=!0,s()});var n=!1;return function(c){if(!a&&!n){if(n=!0,sEt(t))return t.abort();if(typeof t.destroy==\"function\")return t.destroy();s(c||new iEt(\"pipe\"))}}}function Jve(t){t()}function aEt(t,e){return t.pipe(e)}function lEt(t){return!t.length||typeof t[t.length-1]!=\"function\"?Vve:t.pop()}function cEt(){for(var t=arguments.length,e=new Array(t),r=0;r<t;r++)e[r]=arguments[r];var s=lEt(e);if(Array.isArray(e[0])&&(e=e[0]),e.length<2)throw new nEt(\"streams\");var a,n=e.map(function(c,f){var p=f<e.length-1,h=f>0;return oEt(c,p,h,function(E){a||(a=E),E&&n.forEach(Jve),!p&&(n.forEach(Jve),s(a))})});return e.reduce(aEt)}zve.exports=cEt});var Lw=_((zc,sP)=>{var iP=Ie(\"stream\");process.env.READABLE_STREAM===\"disable\"&&iP?(sP.exports=iP.Readable,Object.assign(sP.exports,iP),sP.exports.Stream=iP):(zc=sP.exports=YY(),zc.Stream=iP||zc,zc.Readable=zc,zc.Writable=GY(),zc.Duplex=Ym(),zc.Transform=aV(),zc.PassThrough=Yve(),zc.finished=EN(),zc.pipeline=Zve())});var eSe=_((_tr,$ve)=>{\"use strict\";var{Buffer:cf}=Ie(\"buffer\"),Xve=Symbol.for(\"BufferList\");function Ci(t){if(!(this instanceof Ci))return new Ci(t);Ci._init.call(this,t)}Ci._init=function(e){Object.defineProperty(this,Xve,{value:!0}),this._bufs=[],this.length=0,e&&this.append(e)};Ci.prototype._new=function(e){return new Ci(e)};Ci.prototype._offset=function(e){if(e===0)return[0,0];let r=0;for(let s=0;s<this._bufs.length;s++){let a=r+this._bufs[s].length;if(e<a||s===this._bufs.length-1)return[s,e-r];r=a}};Ci.prototype._reverseOffset=function(t){let e=t[0],r=t[1];for(let s=0;s<e;s++)r+=this._bufs[s].length;return r};Ci.prototype.get=function(e){if(e>this.length||e<0)return;let r=this._offset(e);return this._bufs[r[0]][r[1]]};Ci.prototype.slice=function(e,r){return typeof e==\"number\"&&e<0&&(e+=this.length),typeof r==\"number\"&&r<0&&(r+=this.length),this.copy(null,0,e,r)};Ci.prototype.copy=function(e,r,s,a){if((typeof s!=\"number\"||s<0)&&(s=0),(typeof a!=\"number\"||a>this.length)&&(a=this.length),s>=this.length||a<=0)return e||cf.alloc(0);let n=!!e,c=this._offset(s),f=a-s,p=f,h=n&&r||0,E=c[1];if(s===0&&a===this.length){if(!n)return this._bufs.length===1?this._bufs[0]:cf.concat(this._bufs,this.length);for(let C=0;C<this._bufs.length;C++)this._bufs[C].copy(e,h),h+=this._bufs[C].length;return e}if(p<=this._bufs[c[0]].length-E)return n?this._bufs[c[0]].copy(e,r,E,E+p):this._bufs[c[0]].slice(E,E+p);n||(e=cf.allocUnsafe(f));for(let C=c[0];C<this._bufs.length;C++){let S=this._bufs[C].length-E;if(p>S)this._bufs[C].copy(e,h,E),h+=S;else{this._bufs[C].copy(e,h,E,E+p),h+=S;break}p-=S,E&&(E=0)}return e.length>h?e.slice(0,h):e};Ci.prototype.shallowSlice=function(e,r){if(e=e||0,r=typeof r!=\"number\"?this.length:r,e<0&&(e+=this.length),r<0&&(r+=this.length),e===r)return this._new();let s=this._offset(e),a=this._offset(r),n=this._bufs.slice(s[0],a[0]+1);return a[1]===0?n.pop():n[n.length-1]=n[n.length-1].slice(0,a[1]),s[1]!==0&&(n[0]=n[0].slice(s[1])),this._new(n)};Ci.prototype.toString=function(e,r,s){return this.slice(r,s).toString(e)};Ci.prototype.consume=function(e){if(e=Math.trunc(e),Number.isNaN(e)||e<=0)return this;for(;this._bufs.length;)if(e>=this._bufs[0].length)e-=this._bufs[0].length,this.length-=this._bufs[0].length,this._bufs.shift();else{this._bufs[0]=this._bufs[0].slice(e),this.length-=e;break}return this};Ci.prototype.duplicate=function(){let e=this._new();for(let r=0;r<this._bufs.length;r++)e.append(this._bufs[r]);return e};Ci.prototype.append=function(e){if(e==null)return this;if(e.buffer)this._appendBuffer(cf.from(e.buffer,e.byteOffset,e.byteLength));else if(Array.isArray(e))for(let r=0;r<e.length;r++)this.append(e[r]);else if(this._isBufferList(e))for(let r=0;r<e._bufs.length;r++)this.append(e._bufs[r]);else typeof e==\"number\"&&(e=e.toString()),this._appendBuffer(cf.from(e));return this};Ci.prototype._appendBuffer=function(e){this._bufs.push(e),this.length+=e.length};Ci.prototype.indexOf=function(t,e,r){if(r===void 0&&typeof e==\"string\"&&(r=e,e=void 0),typeof t==\"function\"||Array.isArray(t))throw new TypeError('The \"value\" argument must be one of type string, Buffer, BufferList, or Uint8Array.');if(typeof t==\"number\"?t=cf.from([t]):typeof t==\"string\"?t=cf.from(t,r):this._isBufferList(t)?t=t.slice():Array.isArray(t.buffer)?t=cf.from(t.buffer,t.byteOffset,t.byteLength):cf.isBuffer(t)||(t=cf.from(t)),e=Number(e||0),isNaN(e)&&(e=0),e<0&&(e=this.length+e),e<0&&(e=0),t.length===0)return e>this.length?this.length:e;let s=this._offset(e),a=s[0],n=s[1];for(;a<this._bufs.length;a++){let c=this._bufs[a];for(;n<c.length;)if(c.length-n>=t.length){let p=c.indexOf(t,n);if(p!==-1)return this._reverseOffset([a,p]);n=c.length-t.length+1}else{let p=this._reverseOffset([a,n]);if(this._match(p,t))return p;n++}n=0}return-1};Ci.prototype._match=function(t,e){if(this.length-t<e.length)return!1;for(let r=0;r<e.length;r++)if(this.get(t+r)!==e[r])return!1;return!0};(function(){let t={readDoubleBE:8,readDoubleLE:8,readFloatBE:4,readFloatLE:4,readInt32BE:4,readInt32LE:4,readUInt32BE:4,readUInt32LE:4,readInt16BE:2,readInt16LE:2,readUInt16BE:2,readUInt16LE:2,readInt8:1,readUInt8:1,readIntBE:null,readIntLE:null,readUIntBE:null,readUIntLE:null};for(let e in t)(function(r){t[r]===null?Ci.prototype[r]=function(s,a){return this.slice(s,s+a)[r](0,a)}:Ci.prototype[r]=function(s=0){return this.slice(s,s+t[r])[r](0)}})(e)})();Ci.prototype._isBufferList=function(e){return e instanceof Ci||Ci.isBufferList(e)};Ci.isBufferList=function(e){return e!=null&&e[Xve]};$ve.exports=Ci});var tSe=_((Htr,PN)=>{\"use strict\";var cV=Lw().Duplex,uEt=cg(),oP=eSe();function ra(t){if(!(this instanceof ra))return new ra(t);if(typeof t==\"function\"){this._callback=t;let e=function(s){this._callback&&(this._callback(s),this._callback=null)}.bind(this);this.on(\"pipe\",function(s){s.on(\"error\",e)}),this.on(\"unpipe\",function(s){s.removeListener(\"error\",e)}),t=null}oP._init.call(this,t),cV.call(this)}uEt(ra,cV);Object.assign(ra.prototype,oP.prototype);ra.prototype._new=function(e){return new ra(e)};ra.prototype._write=function(e,r,s){this._appendBuffer(e),typeof s==\"function\"&&s()};ra.prototype._read=function(e){if(!this.length)return this.push(null);e=Math.min(e,this.length),this.push(this.slice(0,e)),this.consume(e)};ra.prototype.end=function(e){cV.prototype.end.call(this,e),this._callback&&(this._callback(null,this.slice()),this._callback=null)};ra.prototype._destroy=function(e,r){this._bufs.length=0,this.length=0,r(e)};ra.prototype._isBufferList=function(e){return e instanceof ra||e instanceof oP||ra.isBufferList(e)};ra.isBufferList=oP.isBufferList;PN.exports=ra;PN.exports.BufferListStream=ra;PN.exports.BufferList=oP});var AV=_(Uw=>{var fEt=Buffer.alloc,AEt=\"0000000000000000000\",pEt=\"7777777777777777777\",rSe=48,nSe=Buffer.from(\"ustar\\0\",\"binary\"),hEt=Buffer.from(\"00\",\"binary\"),gEt=Buffer.from(\"ustar \",\"binary\"),dEt=Buffer.from(\" \\0\",\"binary\"),mEt=parseInt(\"7777\",8),aP=257,fV=263,yEt=function(t,e,r){return typeof t!=\"number\"?r:(t=~~t,t>=e?e:t>=0||(t+=e,t>=0)?t:0)},EEt=function(t){switch(t){case 0:return\"file\";case 1:return\"link\";case 2:return\"symlink\";case 3:return\"character-device\";case 4:return\"block-device\";case 5:return\"directory\";case 6:return\"fifo\";case 7:return\"contiguous-file\";case 72:return\"pax-header\";case 55:return\"pax-global-header\";case 27:return\"gnu-long-link-path\";case 28:case 30:return\"gnu-long-path\"}return null},IEt=function(t){switch(t){case\"file\":return 0;case\"link\":return 1;case\"symlink\":return 2;case\"character-device\":return 3;case\"block-device\":return 4;case\"directory\":return 5;case\"fifo\":return 6;case\"contiguous-file\":return 7;case\"pax-header\":return 72}return 0},iSe=function(t,e,r,s){for(;r<s;r++)if(t[r]===e)return r;return s},sSe=function(t){for(var e=256,r=0;r<148;r++)e+=t[r];for(var s=156;s<512;s++)e+=t[s];return e},hg=function(t,e){return t=t.toString(8),t.length>e?pEt.slice(0,e)+\" \":AEt.slice(0,e-t.length)+t+\" \"};function CEt(t){var e;if(t[0]===128)e=!0;else if(t[0]===255)e=!1;else return null;for(var r=[],s=t.length-1;s>0;s--){var a=t[s];e?r.push(a):r.push(255-a)}var n=0,c=r.length;for(s=0;s<c;s++)n+=r[s]*Math.pow(256,s);return e?n:-1*n}var gg=function(t,e,r){if(t=t.slice(e,e+r),e=0,t[e]&128)return CEt(t);for(;e<t.length&&t[e]===32;)e++;for(var s=yEt(iSe(t,32,e,t.length),t.length,t.length);e<s&&t[e]===0;)e++;return s===e?0:parseInt(t.slice(e,s).toString(),8)},Mw=function(t,e,r,s){return t.slice(e,iSe(t,0,e,e+r)).toString(s)},uV=function(t){var e=Buffer.byteLength(t),r=Math.floor(Math.log(e)/Math.log(10))+1;return e+r>=Math.pow(10,r)&&r++,e+r+t};Uw.decodeLongPath=function(t,e){return Mw(t,0,t.length,e)};Uw.encodePax=function(t){var e=\"\";t.name&&(e+=uV(\" path=\"+t.name+`\n`)),t.linkname&&(e+=uV(\" linkpath=\"+t.linkname+`\n`));var r=t.pax;if(r)for(var s in r)e+=uV(\" \"+s+\"=\"+r[s]+`\n`);return Buffer.from(e)};Uw.decodePax=function(t){for(var e={};t.length;){for(var r=0;r<t.length&&t[r]!==32;)r++;var s=parseInt(t.slice(0,r).toString(),10);if(!s)return e;var a=t.slice(r+1,s-1).toString(),n=a.indexOf(\"=\");if(n===-1)return e;e[a.slice(0,n)]=a.slice(n+1),t=t.slice(s)}return e};Uw.encode=function(t){var e=fEt(512),r=t.name,s=\"\";if(t.typeflag===5&&r[r.length-1]!==\"/\"&&(r+=\"/\"),Buffer.byteLength(r)!==r.length)return null;for(;Buffer.byteLength(r)>100;){var a=r.indexOf(\"/\");if(a===-1)return null;s+=s?\"/\"+r.slice(0,a):r.slice(0,a),r=r.slice(a+1)}return Buffer.byteLength(r)>100||Buffer.byteLength(s)>155||t.linkname&&Buffer.byteLength(t.linkname)>100?null:(e.write(r),e.write(hg(t.mode&mEt,6),100),e.write(hg(t.uid,6),108),e.write(hg(t.gid,6),116),e.write(hg(t.size,11),124),e.write(hg(t.mtime.getTime()/1e3|0,11),136),e[156]=rSe+IEt(t.type),t.linkname&&e.write(t.linkname,157),nSe.copy(e,aP),hEt.copy(e,fV),t.uname&&e.write(t.uname,265),t.gname&&e.write(t.gname,297),e.write(hg(t.devmajor||0,6),329),e.write(hg(t.devminor||0,6),337),s&&e.write(s,345),e.write(hg(sSe(e),6),148),e)};Uw.decode=function(t,e,r){var s=t[156]===0?0:t[156]-rSe,a=Mw(t,0,100,e),n=gg(t,100,8),c=gg(t,108,8),f=gg(t,116,8),p=gg(t,124,12),h=gg(t,136,12),E=EEt(s),C=t[157]===0?null:Mw(t,157,100,e),S=Mw(t,265,32),b=Mw(t,297,32),I=gg(t,329,8),T=gg(t,337,8),N=sSe(t);if(N===8*32)return null;if(N!==gg(t,148,8))throw new Error(\"Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?\");if(nSe.compare(t,aP,aP+6)===0)t[345]&&(a=Mw(t,345,155,e)+\"/\"+a);else if(!(gEt.compare(t,aP,aP+6)===0&&dEt.compare(t,fV,fV+2)===0)){if(!r)throw new Error(\"Invalid tar header: unknown format.\")}return s===0&&a&&a[a.length-1]===\"/\"&&(s=5),{name:a,mode:n,uid:c,gid:f,size:p,mtime:new Date(1e3*h),type:E,linkname:C,uname:S,gname:b,devmajor:I,devminor:T}}});var ASe=_((Gtr,fSe)=>{var aSe=Ie(\"util\"),wEt=tSe(),lP=AV(),lSe=Lw().Writable,cSe=Lw().PassThrough,uSe=function(){},oSe=function(t){return t&=511,t&&512-t},BEt=function(t,e){var r=new bN(t,e);return r.end(),r},vEt=function(t,e){return e.path&&(t.name=e.path),e.linkpath&&(t.linkname=e.linkpath),e.size&&(t.size=parseInt(e.size,10)),t.pax=e,t},bN=function(t,e){this._parent=t,this.offset=e,cSe.call(this,{autoDestroy:!1})};aSe.inherits(bN,cSe);bN.prototype.destroy=function(t){this._parent.destroy(t)};var ch=function(t){if(!(this instanceof ch))return new ch(t);lSe.call(this,t),t=t||{},this._offset=0,this._buffer=wEt(),this._missing=0,this._partial=!1,this._onparse=uSe,this._header=null,this._stream=null,this._overflow=null,this._cb=null,this._locked=!1,this._destroyed=!1,this._pax=null,this._paxGlobal=null,this._gnuLongPath=null,this._gnuLongLinkPath=null;var e=this,r=e._buffer,s=function(){e._continue()},a=function(S){if(e._locked=!1,S)return e.destroy(S);e._stream||s()},n=function(){e._stream=null;var S=oSe(e._header.size);S?e._parse(S,c):e._parse(512,C),e._locked||s()},c=function(){e._buffer.consume(oSe(e._header.size)),e._parse(512,C),s()},f=function(){var S=e._header.size;e._paxGlobal=lP.decodePax(r.slice(0,S)),r.consume(S),n()},p=function(){var S=e._header.size;e._pax=lP.decodePax(r.slice(0,S)),e._paxGlobal&&(e._pax=Object.assign({},e._paxGlobal,e._pax)),r.consume(S),n()},h=function(){var S=e._header.size;this._gnuLongPath=lP.decodeLongPath(r.slice(0,S),t.filenameEncoding),r.consume(S),n()},E=function(){var S=e._header.size;this._gnuLongLinkPath=lP.decodeLongPath(r.slice(0,S),t.filenameEncoding),r.consume(S),n()},C=function(){var S=e._offset,b;try{b=e._header=lP.decode(r.slice(0,512),t.filenameEncoding,t.allowUnknownFormat)}catch(I){e.emit(\"error\",I)}if(r.consume(512),!b){e._parse(512,C),s();return}if(b.type===\"gnu-long-path\"){e._parse(b.size,h),s();return}if(b.type===\"gnu-long-link-path\"){e._parse(b.size,E),s();return}if(b.type===\"pax-global-header\"){e._parse(b.size,f),s();return}if(b.type===\"pax-header\"){e._parse(b.size,p),s();return}if(e._gnuLongPath&&(b.name=e._gnuLongPath,e._gnuLongPath=null),e._gnuLongLinkPath&&(b.linkname=e._gnuLongLinkPath,e._gnuLongLinkPath=null),e._pax&&(e._header=b=vEt(b,e._pax),e._pax=null),e._locked=!0,!b.size||b.type===\"directory\"){e._parse(512,C),e.emit(\"entry\",b,BEt(e,S),a);return}e._stream=new bN(e,S),e.emit(\"entry\",b,e._stream,a),e._parse(b.size,n),s()};this._onheader=C,this._parse(512,C)};aSe.inherits(ch,lSe);ch.prototype.destroy=function(t){this._destroyed||(this._destroyed=!0,t&&this.emit(\"error\",t),this.emit(\"close\"),this._stream&&this._stream.emit(\"close\"))};ch.prototype._parse=function(t,e){this._destroyed||(this._offset+=t,this._missing=t,e===this._onheader&&(this._partial=!1),this._onparse=e)};ch.prototype._continue=function(){if(!this._destroyed){var t=this._cb;this._cb=uSe,this._overflow?this._write(this._overflow,void 0,t):t()}};ch.prototype._write=function(t,e,r){if(!this._destroyed){var s=this._stream,a=this._buffer,n=this._missing;if(t.length&&(this._partial=!0),t.length<n)return this._missing-=t.length,this._overflow=null,s?s.write(t,r):(a.append(t),r());this._cb=r,this._missing=0;var c=null;t.length>n&&(c=t.slice(n),t=t.slice(0,n)),s?s.end(t):a.append(t),this._overflow=c,this._onparse()}};ch.prototype._final=function(t){if(this._partial)return this.destroy(new Error(\"Unexpected end of data\"));t()};fSe.exports=ch});var hSe=_((qtr,pSe)=>{pSe.exports=Ie(\"fs\").constants||Ie(\"constants\")});var ESe=_((Wtr,ySe)=>{var _w=hSe(),gSe=aH(),kN=cg(),SEt=Buffer.alloc,dSe=Lw().Readable,Hw=Lw().Writable,DEt=Ie(\"string_decoder\").StringDecoder,xN=AV(),PEt=parseInt(\"755\",8),bEt=parseInt(\"644\",8),mSe=SEt(1024),hV=function(){},pV=function(t,e){e&=511,e&&t.push(mSe.slice(0,512-e))};function xEt(t){switch(t&_w.S_IFMT){case _w.S_IFBLK:return\"block-device\";case _w.S_IFCHR:return\"character-device\";case _w.S_IFDIR:return\"directory\";case _w.S_IFIFO:return\"fifo\";case _w.S_IFLNK:return\"symlink\"}return\"file\"}var QN=function(t){Hw.call(this),this.written=0,this._to=t,this._destroyed=!1};kN(QN,Hw);QN.prototype._write=function(t,e,r){if(this.written+=t.length,this._to.push(t))return r();this._to._drain=r};QN.prototype.destroy=function(){this._destroyed||(this._destroyed=!0,this.emit(\"close\"))};var RN=function(){Hw.call(this),this.linkname=\"\",this._decoder=new DEt(\"utf-8\"),this._destroyed=!1};kN(RN,Hw);RN.prototype._write=function(t,e,r){this.linkname+=this._decoder.write(t),r()};RN.prototype.destroy=function(){this._destroyed||(this._destroyed=!0,this.emit(\"close\"))};var cP=function(){Hw.call(this),this._destroyed=!1};kN(cP,Hw);cP.prototype._write=function(t,e,r){r(new Error(\"No body allowed for this entry\"))};cP.prototype.destroy=function(){this._destroyed||(this._destroyed=!0,this.emit(\"close\"))};var mA=function(t){if(!(this instanceof mA))return new mA(t);dSe.call(this,t),this._drain=hV,this._finalized=!1,this._finalizing=!1,this._destroyed=!1,this._stream=null};kN(mA,dSe);mA.prototype.entry=function(t,e,r){if(this._stream)throw new Error(\"already piping an entry\");if(!(this._finalized||this._destroyed)){typeof e==\"function\"&&(r=e,e=null),r||(r=hV);var s=this;if((!t.size||t.type===\"symlink\")&&(t.size=0),t.type||(t.type=xEt(t.mode)),t.mode||(t.mode=t.type===\"directory\"?PEt:bEt),t.uid||(t.uid=0),t.gid||(t.gid=0),t.mtime||(t.mtime=new Date),typeof e==\"string\"&&(e=Buffer.from(e)),Buffer.isBuffer(e)){t.size=e.length,this._encode(t);var a=this.push(e);return pV(s,t.size),a?process.nextTick(r):this._drain=r,new cP}if(t.type===\"symlink\"&&!t.linkname){var n=new RN;return gSe(n,function(f){if(f)return s.destroy(),r(f);t.linkname=n.linkname,s._encode(t),r()}),n}if(this._encode(t),t.type!==\"file\"&&t.type!==\"contiguous-file\")return process.nextTick(r),new cP;var c=new QN(this);return this._stream=c,gSe(c,function(f){if(s._stream=null,f)return s.destroy(),r(f);if(c.written!==t.size)return s.destroy(),r(new Error(\"size mismatch\"));pV(s,t.size),s._finalizing&&s.finalize(),r()}),c}};mA.prototype.finalize=function(){if(this._stream){this._finalizing=!0;return}this._finalized||(this._finalized=!0,this.push(mSe),this.push(null))};mA.prototype.destroy=function(t){this._destroyed||(this._destroyed=!0,t&&this.emit(\"error\",t),this.emit(\"close\"),this._stream&&this._stream.destroy&&this._stream.destroy())};mA.prototype._encode=function(t){if(!t.pax){var e=xN.encode(t);if(e){this.push(e);return}}this._encodePax(t)};mA.prototype._encodePax=function(t){var e=xN.encodePax({name:t.name,linkname:t.linkname,pax:t.pax}),r={name:\"PaxHeader\",mode:t.mode,uid:t.uid,gid:t.gid,size:e.length,mtime:t.mtime,type:\"pax-header\",linkname:t.linkname&&\"PaxHeader\",uname:t.uname,gname:t.gname,devmajor:t.devmajor,devminor:t.devminor};this.push(xN.encode(r)),this.push(e),pV(this,e.length),r.size=t.size,r.type=t.type,this.push(xN.encode(r))};mA.prototype._read=function(t){var e=this._drain;this._drain=hV,e()};ySe.exports=mA});var ISe=_(gV=>{gV.extract=ASe();gV.pack=ESe()});var TSe=_(Ra=>{\"use strict\";var jEt=Ra&&Ra.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(Ra,\"__esModule\",{value:!0});Ra.Minipass=Ra.isWritable=Ra.isReadable=Ra.isStream=void 0;var bSe=typeof process==\"object\"&&process?process:{stdout:null,stderr:null},PV=Ie(\"node:events\"),RSe=jEt(Ie(\"node:stream\")),GEt=Ie(\"node:string_decoder\"),qEt=t=>!!t&&typeof t==\"object\"&&(t instanceof HN||t instanceof RSe.default||(0,Ra.isReadable)(t)||(0,Ra.isWritable)(t));Ra.isStream=qEt;var WEt=t=>!!t&&typeof t==\"object\"&&t instanceof PV.EventEmitter&&typeof t.pipe==\"function\"&&t.pipe!==RSe.default.Writable.prototype.pipe;Ra.isReadable=WEt;var YEt=t=>!!t&&typeof t==\"object\"&&t instanceof PV.EventEmitter&&typeof t.write==\"function\"&&typeof t.end==\"function\";Ra.isWritable=YEt;var uh=Symbol(\"EOF\"),fh=Symbol(\"maybeEmitEnd\"),dg=Symbol(\"emittedEnd\"),NN=Symbol(\"emittingEnd\"),uP=Symbol(\"emittedError\"),ON=Symbol(\"closed\"),xSe=Symbol(\"read\"),LN=Symbol(\"flush\"),kSe=Symbol(\"flushChunk\"),uf=Symbol(\"encoding\"),Gw=Symbol(\"decoder\"),Ks=Symbol(\"flowing\"),fP=Symbol(\"paused\"),qw=Symbol(\"resume\"),zs=Symbol(\"buffer\"),Qa=Symbol(\"pipes\"),Zs=Symbol(\"bufferLength\"),CV=Symbol(\"bufferPush\"),MN=Symbol(\"bufferShift\"),na=Symbol(\"objectMode\"),es=Symbol(\"destroyed\"),wV=Symbol(\"error\"),BV=Symbol(\"emitData\"),QSe=Symbol(\"emitEnd\"),vV=Symbol(\"emitEnd2\"),EA=Symbol(\"async\"),SV=Symbol(\"abort\"),UN=Symbol(\"aborted\"),AP=Symbol(\"signal\"),zm=Symbol(\"dataListeners\"),rc=Symbol(\"discarded\"),pP=t=>Promise.resolve().then(t),VEt=t=>t(),JEt=t=>t===\"end\"||t===\"finish\"||t===\"prefinish\",KEt=t=>t instanceof ArrayBuffer||!!t&&typeof t==\"object\"&&t.constructor&&t.constructor.name===\"ArrayBuffer\"&&t.byteLength>=0,zEt=t=>!Buffer.isBuffer(t)&&ArrayBuffer.isView(t),_N=class{src;dest;opts;ondrain;constructor(e,r,s){this.src=e,this.dest=r,this.opts=s,this.ondrain=()=>e[qw](),this.dest.on(\"drain\",this.ondrain)}unpipe(){this.dest.removeListener(\"drain\",this.ondrain)}proxyErrors(e){}end(){this.unpipe(),this.opts.end&&this.dest.end()}},DV=class extends _N{unpipe(){this.src.removeListener(\"error\",this.proxyErrors),super.unpipe()}constructor(e,r,s){super(e,r,s),this.proxyErrors=a=>r.emit(\"error\",a),e.on(\"error\",this.proxyErrors)}},ZEt=t=>!!t.objectMode,XEt=t=>!t.objectMode&&!!t.encoding&&t.encoding!==\"buffer\",HN=class extends PV.EventEmitter{[Ks]=!1;[fP]=!1;[Qa]=[];[zs]=[];[na];[uf];[EA];[Gw];[uh]=!1;[dg]=!1;[NN]=!1;[ON]=!1;[uP]=null;[Zs]=0;[es]=!1;[AP];[UN]=!1;[zm]=0;[rc]=!1;writable=!0;readable=!0;constructor(...e){let r=e[0]||{};if(super(),r.objectMode&&typeof r.encoding==\"string\")throw new TypeError(\"Encoding and objectMode may not be used together\");ZEt(r)?(this[na]=!0,this[uf]=null):XEt(r)?(this[uf]=r.encoding,this[na]=!1):(this[na]=!1,this[uf]=null),this[EA]=!!r.async,this[Gw]=this[uf]?new GEt.StringDecoder(this[uf]):null,r&&r.debugExposeBuffer===!0&&Object.defineProperty(this,\"buffer\",{get:()=>this[zs]}),r&&r.debugExposePipes===!0&&Object.defineProperty(this,\"pipes\",{get:()=>this[Qa]});let{signal:s}=r;s&&(this[AP]=s,s.aborted?this[SV]():s.addEventListener(\"abort\",()=>this[SV]()))}get bufferLength(){return this[Zs]}get encoding(){return this[uf]}set encoding(e){throw new Error(\"Encoding must be set at instantiation time\")}setEncoding(e){throw new Error(\"Encoding must be set at instantiation time\")}get objectMode(){return this[na]}set objectMode(e){throw new Error(\"objectMode must be set at instantiation time\")}get async(){return this[EA]}set async(e){this[EA]=this[EA]||!!e}[SV](){this[UN]=!0,this.emit(\"abort\",this[AP]?.reason),this.destroy(this[AP]?.reason)}get aborted(){return this[UN]}set aborted(e){}write(e,r,s){if(this[UN])return!1;if(this[uh])throw new Error(\"write after end\");if(this[es])return this.emit(\"error\",Object.assign(new Error(\"Cannot call write after a stream was destroyed\"),{code:\"ERR_STREAM_DESTROYED\"})),!0;typeof r==\"function\"&&(s=r,r=\"utf8\"),r||(r=\"utf8\");let a=this[EA]?pP:VEt;if(!this[na]&&!Buffer.isBuffer(e)){if(zEt(e))e=Buffer.from(e.buffer,e.byteOffset,e.byteLength);else if(KEt(e))e=Buffer.from(e);else if(typeof e!=\"string\")throw new Error(\"Non-contiguous data written to non-objectMode stream\")}return this[na]?(this[Ks]&&this[Zs]!==0&&this[LN](!0),this[Ks]?this.emit(\"data\",e):this[CV](e),this[Zs]!==0&&this.emit(\"readable\"),s&&a(s),this[Ks]):e.length?(typeof e==\"string\"&&!(r===this[uf]&&!this[Gw]?.lastNeed)&&(e=Buffer.from(e,r)),Buffer.isBuffer(e)&&this[uf]&&(e=this[Gw].write(e)),this[Ks]&&this[Zs]!==0&&this[LN](!0),this[Ks]?this.emit(\"data\",e):this[CV](e),this[Zs]!==0&&this.emit(\"readable\"),s&&a(s),this[Ks]):(this[Zs]!==0&&this.emit(\"readable\"),s&&a(s),this[Ks])}read(e){if(this[es])return null;if(this[rc]=!1,this[Zs]===0||e===0||e&&e>this[Zs])return this[fh](),null;this[na]&&(e=null),this[zs].length>1&&!this[na]&&(this[zs]=[this[uf]?this[zs].join(\"\"):Buffer.concat(this[zs],this[Zs])]);let r=this[xSe](e||null,this[zs][0]);return this[fh](),r}[xSe](e,r){if(this[na])this[MN]();else{let s=r;e===s.length||e===null?this[MN]():typeof s==\"string\"?(this[zs][0]=s.slice(e),r=s.slice(0,e),this[Zs]-=e):(this[zs][0]=s.subarray(e),r=s.subarray(0,e),this[Zs]-=e)}return this.emit(\"data\",r),!this[zs].length&&!this[uh]&&this.emit(\"drain\"),r}end(e,r,s){return typeof e==\"function\"&&(s=e,e=void 0),typeof r==\"function\"&&(s=r,r=\"utf8\"),e!==void 0&&this.write(e,r),s&&this.once(\"end\",s),this[uh]=!0,this.writable=!1,(this[Ks]||!this[fP])&&this[fh](),this}[qw](){this[es]||(!this[zm]&&!this[Qa].length&&(this[rc]=!0),this[fP]=!1,this[Ks]=!0,this.emit(\"resume\"),this[zs].length?this[LN]():this[uh]?this[fh]():this.emit(\"drain\"))}resume(){return this[qw]()}pause(){this[Ks]=!1,this[fP]=!0,this[rc]=!1}get destroyed(){return this[es]}get flowing(){return this[Ks]}get paused(){return this[fP]}[CV](e){this[na]?this[Zs]+=1:this[Zs]+=e.length,this[zs].push(e)}[MN](){return this[na]?this[Zs]-=1:this[Zs]-=this[zs][0].length,this[zs].shift()}[LN](e=!1){do;while(this[kSe](this[MN]())&&this[zs].length);!e&&!this[zs].length&&!this[uh]&&this.emit(\"drain\")}[kSe](e){return this.emit(\"data\",e),this[Ks]}pipe(e,r){if(this[es])return e;this[rc]=!1;let s=this[dg];return r=r||{},e===bSe.stdout||e===bSe.stderr?r.end=!1:r.end=r.end!==!1,r.proxyErrors=!!r.proxyErrors,s?r.end&&e.end():(this[Qa].push(r.proxyErrors?new DV(this,e,r):new _N(this,e,r)),this[EA]?pP(()=>this[qw]()):this[qw]()),e}unpipe(e){let r=this[Qa].find(s=>s.dest===e);r&&(this[Qa].length===1?(this[Ks]&&this[zm]===0&&(this[Ks]=!1),this[Qa]=[]):this[Qa].splice(this[Qa].indexOf(r),1),r.unpipe())}addListener(e,r){return this.on(e,r)}on(e,r){let s=super.on(e,r);if(e===\"data\")this[rc]=!1,this[zm]++,!this[Qa].length&&!this[Ks]&&this[qw]();else if(e===\"readable\"&&this[Zs]!==0)super.emit(\"readable\");else if(JEt(e)&&this[dg])super.emit(e),this.removeAllListeners(e);else if(e===\"error\"&&this[uP]){let a=r;this[EA]?pP(()=>a.call(this,this[uP])):a.call(this,this[uP])}return s}removeListener(e,r){return this.off(e,r)}off(e,r){let s=super.off(e,r);return e===\"data\"&&(this[zm]=this.listeners(\"data\").length,this[zm]===0&&!this[rc]&&!this[Qa].length&&(this[Ks]=!1)),s}removeAllListeners(e){let r=super.removeAllListeners(e);return(e===\"data\"||e===void 0)&&(this[zm]=0,!this[rc]&&!this[Qa].length&&(this[Ks]=!1)),r}get emittedEnd(){return this[dg]}[fh](){!this[NN]&&!this[dg]&&!this[es]&&this[zs].length===0&&this[uh]&&(this[NN]=!0,this.emit(\"end\"),this.emit(\"prefinish\"),this.emit(\"finish\"),this[ON]&&this.emit(\"close\"),this[NN]=!1)}emit(e,...r){let s=r[0];if(e!==\"error\"&&e!==\"close\"&&e!==es&&this[es])return!1;if(e===\"data\")return!this[na]&&!s?!1:this[EA]?(pP(()=>this[BV](s)),!0):this[BV](s);if(e===\"end\")return this[QSe]();if(e===\"close\"){if(this[ON]=!0,!this[dg]&&!this[es])return!1;let n=super.emit(\"close\");return this.removeAllListeners(\"close\"),n}else if(e===\"error\"){this[uP]=s,super.emit(wV,s);let n=!this[AP]||this.listeners(\"error\").length?super.emit(\"error\",s):!1;return this[fh](),n}else if(e===\"resume\"){let n=super.emit(\"resume\");return this[fh](),n}else if(e===\"finish\"||e===\"prefinish\"){let n=super.emit(e);return this.removeAllListeners(e),n}let a=super.emit(e,...r);return this[fh](),a}[BV](e){for(let s of this[Qa])s.dest.write(e)===!1&&this.pause();let r=this[rc]?!1:super.emit(\"data\",e);return this[fh](),r}[QSe](){return this[dg]?!1:(this[dg]=!0,this.readable=!1,this[EA]?(pP(()=>this[vV]()),!0):this[vV]())}[vV](){if(this[Gw]){let r=this[Gw].end();if(r){for(let s of this[Qa])s.dest.write(r);this[rc]||super.emit(\"data\",r)}}for(let r of this[Qa])r.end();let e=super.emit(\"end\");return this.removeAllListeners(\"end\"),e}async collect(){let e=Object.assign([],{dataLength:0});this[na]||(e.dataLength=0);let r=this.promise();return this.on(\"data\",s=>{e.push(s),this[na]||(e.dataLength+=s.length)}),await r,e}async concat(){if(this[na])throw new Error(\"cannot concat in objectMode\");let e=await this.collect();return this[uf]?e.join(\"\"):Buffer.concat(e,e.dataLength)}async promise(){return new Promise((e,r)=>{this.on(es,()=>r(new Error(\"stream destroyed\"))),this.on(\"error\",s=>r(s)),this.on(\"end\",()=>e())})}[Symbol.asyncIterator](){this[rc]=!1;let e=!1,r=async()=>(this.pause(),e=!0,{value:void 0,done:!0});return{next:()=>{if(e)return r();let a=this.read();if(a!==null)return Promise.resolve({done:!1,value:a});if(this[uh])return r();let n,c,f=C=>{this.off(\"data\",p),this.off(\"end\",h),this.off(es,E),r(),c(C)},p=C=>{this.off(\"error\",f),this.off(\"end\",h),this.off(es,E),this.pause(),n({value:C,done:!!this[uh]})},h=()=>{this.off(\"error\",f),this.off(\"data\",p),this.off(es,E),r(),n({done:!0,value:void 0})},E=()=>f(new Error(\"stream destroyed\"));return new Promise((C,S)=>{c=S,n=C,this.once(es,E),this.once(\"error\",f),this.once(\"end\",h),this.once(\"data\",p)})},throw:r,return:r,[Symbol.asyncIterator](){return this}}}[Symbol.iterator](){this[rc]=!1;let e=!1,r=()=>(this.pause(),this.off(wV,r),this.off(es,r),this.off(\"end\",r),e=!0,{done:!0,value:void 0}),s=()=>{if(e)return r();let a=this.read();return a===null?r():{done:!1,value:a}};return this.once(\"end\",r),this.once(wV,r),this.once(es,r),{next:s,throw:r,return:r,[Symbol.iterator](){return this}}}destroy(e){if(this[es])return e?this.emit(\"error\",e):this.emit(es),this;this[es]=!0,this[rc]=!0,this[zs].length=0,this[Zs]=0;let r=this;return typeof r.close==\"function\"&&!this[ON]&&r.close(),e?this.emit(\"error\",e):this.emit(es),this}static get isStream(){return Ra.isStream}};Ra.Minipass=HN});var OSe=_((prr,IA)=>{\"use strict\";var gP=Ie(\"crypto\"),{Minipass:$Et}=TSe(),xV=[\"sha512\",\"sha384\",\"sha256\"],QV=[\"sha512\"],eIt=/^[a-z0-9+/]+(?:=?=?)$/i,tIt=/^([a-z0-9]+)-([^?]+)([?\\S*]*)$/,rIt=/^([a-z0-9]+)-([A-Za-z0-9+/=]{44,88})(\\?[\\x21-\\x7E]*)?$/,nIt=/^[\\x21-\\x7E]+$/,dP=t=>t?.length?`?${t.join(\"?\")}`:\"\",kV=class extends $Et{#t;#r;#i;constructor(e){super(),this.size=0,this.opts=e,this.#e(),e?.algorithms?this.algorithms=[...e.algorithms]:this.algorithms=[...QV],this.algorithm!==null&&!this.algorithms.includes(this.algorithm)&&this.algorithms.push(this.algorithm),this.hashes=this.algorithms.map(gP.createHash)}#e(){this.sri=this.opts?.integrity?nc(this.opts?.integrity,this.opts):null,this.expectedSize=this.opts?.size,this.sri?this.sri.isHash?(this.goodSri=!0,this.algorithm=this.sri.algorithm):(this.goodSri=!this.sri.isEmpty(),this.algorithm=this.sri.pickAlgorithm(this.opts)):this.algorithm=null,this.digests=this.goodSri?this.sri[this.algorithm]:null,this.optString=dP(this.opts?.options)}on(e,r){return e===\"size\"&&this.#r?r(this.#r):e===\"integrity\"&&this.#t?r(this.#t):e===\"verified\"&&this.#i?r(this.#i):super.on(e,r)}emit(e,r){return e===\"end\"&&this.#n(),super.emit(e,r)}write(e){return this.size+=e.length,this.hashes.forEach(r=>r.update(e)),super.write(e)}#n(){this.goodSri||this.#e();let e=nc(this.hashes.map((s,a)=>`${this.algorithms[a]}-${s.digest(\"base64\")}${this.optString}`).join(\" \"),this.opts),r=this.goodSri&&e.match(this.sri,this.opts);if(typeof this.expectedSize==\"number\"&&this.size!==this.expectedSize){let s=new Error(`stream size mismatch when checking ${this.sri}.\n  Wanted: ${this.expectedSize}\n  Found: ${this.size}`);s.code=\"EBADSIZE\",s.found=this.size,s.expected=this.expectedSize,s.sri=this.sri,this.emit(\"error\",s)}else if(this.sri&&!r){let s=new Error(`${this.sri} integrity checksum failed when using ${this.algorithm}: wanted ${this.digests} but got ${e}. (${this.size} bytes)`);s.code=\"EINTEGRITY\",s.found=e,s.expected=this.digests,s.algorithm=this.algorithm,s.sri=this.sri,this.emit(\"error\",s)}else this.#r=this.size,this.emit(\"size\",this.size),this.#t=e,this.emit(\"integrity\",e),r&&(this.#i=r,this.emit(\"verified\",r))}},Ah=class{get isHash(){return!0}constructor(e,r){let s=r?.strict;this.source=e.trim(),this.digest=\"\",this.algorithm=\"\",this.options=[];let a=this.source.match(s?rIt:tIt);if(!a||s&&!xV.includes(a[1]))return;this.algorithm=a[1],this.digest=a[2];let n=a[3];n&&(this.options=n.slice(1).split(\"?\"))}hexDigest(){return this.digest&&Buffer.from(this.digest,\"base64\").toString(\"hex\")}toJSON(){return this.toString()}match(e,r){let s=nc(e,r);if(!s)return!1;if(s.isIntegrity){let a=s.pickAlgorithm(r,[this.algorithm]);if(!a)return!1;let n=s[a].find(c=>c.digest===this.digest);return n||!1}return s.digest===this.digest?s:!1}toString(e){return e?.strict&&!(xV.includes(this.algorithm)&&this.digest.match(eIt)&&this.options.every(r=>r.match(nIt)))?\"\":`${this.algorithm}-${this.digest}${dP(this.options)}`}};function FSe(t,e,r,s){let a=t!==\"\",n=!1,c=\"\",f=s.length-1;for(let h=0;h<f;h++){let E=Ah.prototype.toString.call(s[h],r);E&&(n=!0,c+=E,c+=e)}let p=Ah.prototype.toString.call(s[f],r);return p&&(n=!0,c+=p),a&&n?t+e+c:t+c}var Zm=class{get isIntegrity(){return!0}toJSON(){return this.toString()}isEmpty(){return Object.keys(this).length===0}toString(e){let r=e?.sep||\" \",s=\"\";if(e?.strict){r=r.replace(/\\S+/g,\" \");for(let a of xV)this[a]&&(s=FSe(s,r,e,this[a]))}else for(let a of Object.keys(this))s=FSe(s,r,e,this[a]);return s}concat(e,r){let s=typeof e==\"string\"?e:hP(e,r);return nc(`${this.toString(r)} ${s}`,r)}hexDigest(){return nc(this,{single:!0}).hexDigest()}merge(e,r){let s=nc(e,r);for(let a in s)if(this[a]){if(!this[a].find(n=>s[a].find(c=>n.digest===c.digest)))throw new Error(\"hashes do not match, cannot update integrity\")}else this[a]=s[a]}match(e,r){let s=nc(e,r);if(!s)return!1;let a=s.pickAlgorithm(r,Object.keys(this));return!!a&&this[a]&&s[a]&&this[a].find(n=>s[a].find(c=>n.digest===c.digest))||!1}pickAlgorithm(e,r){let s=e?.pickAlgorithm||fIt,a=Object.keys(this).filter(n=>r?.length?r.includes(n):!0);return a.length?a.reduce((n,c)=>s(n,c)||n):null}};IA.exports.parse=nc;function nc(t,e){if(!t)return null;if(typeof t==\"string\")return bV(t,e);if(t.algorithm&&t.digest){let r=new Zm;return r[t.algorithm]=[t],bV(hP(r,e),e)}else return bV(hP(t,e),e)}function bV(t,e){if(e?.single)return new Ah(t,e);let r=t.trim().split(/\\s+/).reduce((s,a)=>{let n=new Ah(a,e);if(n.algorithm&&n.digest){let c=n.algorithm;s[c]||(s[c]=[]),s[c].push(n)}return s},new Zm);return r.isEmpty()?null:r}IA.exports.stringify=hP;function hP(t,e){return t.algorithm&&t.digest?Ah.prototype.toString.call(t,e):typeof t==\"string\"?hP(nc(t,e),e):Zm.prototype.toString.call(t,e)}IA.exports.fromHex=iIt;function iIt(t,e,r){let s=dP(r?.options);return nc(`${e}-${Buffer.from(t,\"hex\").toString(\"base64\")}${s}`,r)}IA.exports.fromData=sIt;function sIt(t,e){let r=e?.algorithms||[...QV],s=dP(e?.options);return r.reduce((a,n)=>{let c=gP.createHash(n).update(t).digest(\"base64\"),f=new Ah(`${n}-${c}${s}`,e);if(f.algorithm&&f.digest){let p=f.algorithm;a[p]||(a[p]=[]),a[p].push(f)}return a},new Zm)}IA.exports.fromStream=oIt;function oIt(t,e){let r=RV(e);return new Promise((s,a)=>{t.pipe(r),t.on(\"error\",a),r.on(\"error\",a);let n;r.on(\"integrity\",c=>{n=c}),r.on(\"end\",()=>s(n)),r.resume()})}IA.exports.checkData=aIt;function aIt(t,e,r){if(e=nc(e,r),!e||!Object.keys(e).length){if(r?.error)throw Object.assign(new Error(\"No valid integrity hashes to check against\"),{code:\"EINTEGRITY\"});return!1}let s=e.pickAlgorithm(r),a=gP.createHash(s).update(t).digest(\"base64\"),n=nc({algorithm:s,digest:a}),c=n.match(e,r);if(r=r||{},c||!r.error)return c;if(typeof r.size==\"number\"&&t.length!==r.size){let f=new Error(`data size mismatch when checking ${e}.\n  Wanted: ${r.size}\n  Found: ${t.length}`);throw f.code=\"EBADSIZE\",f.found=t.length,f.expected=r.size,f.sri=e,f}else{let f=new Error(`Integrity checksum failed when using ${s}: Wanted ${e}, but got ${n}. (${t.length} bytes)`);throw f.code=\"EINTEGRITY\",f.found=n,f.expected=e,f.algorithm=s,f.sri=e,f}}IA.exports.checkStream=lIt;function lIt(t,e,r){if(r=r||Object.create(null),r.integrity=e,e=nc(e,r),!e||!Object.keys(e).length)return Promise.reject(Object.assign(new Error(\"No valid integrity hashes to check against\"),{code:\"EINTEGRITY\"}));let s=RV(r);return new Promise((a,n)=>{t.pipe(s),t.on(\"error\",n),s.on(\"error\",n);let c;s.on(\"verified\",f=>{c=f}),s.on(\"end\",()=>a(c)),s.resume()})}IA.exports.integrityStream=RV;function RV(t=Object.create(null)){return new kV(t)}IA.exports.create=cIt;function cIt(t){let e=t?.algorithms||[...QV],r=dP(t?.options),s=e.map(gP.createHash);return{update:function(a,n){return s.forEach(c=>c.update(a,n)),this},digest:function(){return e.reduce((n,c)=>{let f=s.shift().digest(\"base64\"),p=new Ah(`${c}-${f}${r}`,t);if(p.algorithm&&p.digest){let h=p.algorithm;n[h]||(n[h]=[]),n[h].push(p)}return n},new Zm)}}}var uIt=gP.getHashes(),NSe=[\"md5\",\"whirlpool\",\"sha1\",\"sha224\",\"sha256\",\"sha384\",\"sha512\",\"sha3\",\"sha3-256\",\"sha3-384\",\"sha3-512\",\"sha3_256\",\"sha3_384\",\"sha3_512\"].filter(t=>uIt.includes(t));function fIt(t,e){return NSe.indexOf(t.toLowerCase())>=NSe.indexOf(e.toLowerCase())?t:e}});var TV=_(mg=>{\"use strict\";Object.defineProperty(mg,\"__esModule\",{value:!0});mg.Signature=mg.Envelope=void 0;mg.Envelope={fromJSON(t){return{payload:jN(t.payload)?Buffer.from(LSe(t.payload)):Buffer.alloc(0),payloadType:jN(t.payloadType)?globalThis.String(t.payloadType):\"\",signatures:globalThis.Array.isArray(t?.signatures)?t.signatures.map(e=>mg.Signature.fromJSON(e)):[]}},toJSON(t){let e={};return t.payload.length!==0&&(e.payload=MSe(t.payload)),t.payloadType!==\"\"&&(e.payloadType=t.payloadType),t.signatures?.length&&(e.signatures=t.signatures.map(r=>mg.Signature.toJSON(r))),e}};mg.Signature={fromJSON(t){return{sig:jN(t.sig)?Buffer.from(LSe(t.sig)):Buffer.alloc(0),keyid:jN(t.keyid)?globalThis.String(t.keyid):\"\"}},toJSON(t){let e={};return t.sig.length!==0&&(e.sig=MSe(t.sig)),t.keyid!==\"\"&&(e.keyid=t.keyid),e}};function LSe(t){return Uint8Array.from(globalThis.Buffer.from(t,\"base64\"))}function MSe(t){return globalThis.Buffer.from(t).toString(\"base64\")}function jN(t){return t!=null}});var _Se=_(GN=>{\"use strict\";Object.defineProperty(GN,\"__esModule\",{value:!0});GN.Timestamp=void 0;GN.Timestamp={fromJSON(t){return{seconds:USe(t.seconds)?globalThis.String(t.seconds):\"0\",nanos:USe(t.nanos)?globalThis.Number(t.nanos):0}},toJSON(t){let e={};return t.seconds!==\"0\"&&(e.seconds=t.seconds),t.nanos!==0&&(e.nanos=Math.round(t.nanos)),e}};function USe(t){return t!=null}});var Ww=_(Ur=>{\"use strict\";Object.defineProperty(Ur,\"__esModule\",{value:!0});Ur.TimeRange=Ur.X509CertificateChain=Ur.SubjectAlternativeName=Ur.X509Certificate=Ur.DistinguishedName=Ur.ObjectIdentifierValuePair=Ur.ObjectIdentifier=Ur.PublicKeyIdentifier=Ur.PublicKey=Ur.RFC3161SignedTimestamp=Ur.LogId=Ur.MessageSignature=Ur.HashOutput=Ur.SubjectAlternativeNameType=Ur.PublicKeyDetails=Ur.HashAlgorithm=void 0;Ur.hashAlgorithmFromJSON=jSe;Ur.hashAlgorithmToJSON=GSe;Ur.publicKeyDetailsFromJSON=qSe;Ur.publicKeyDetailsToJSON=WSe;Ur.subjectAlternativeNameTypeFromJSON=YSe;Ur.subjectAlternativeNameTypeToJSON=VSe;var AIt=_Se(),yl;(function(t){t[t.HASH_ALGORITHM_UNSPECIFIED=0]=\"HASH_ALGORITHM_UNSPECIFIED\",t[t.SHA2_256=1]=\"SHA2_256\",t[t.SHA2_384=2]=\"SHA2_384\",t[t.SHA2_512=3]=\"SHA2_512\",t[t.SHA3_256=4]=\"SHA3_256\",t[t.SHA3_384=5]=\"SHA3_384\"})(yl||(Ur.HashAlgorithm=yl={}));function jSe(t){switch(t){case 0:case\"HASH_ALGORITHM_UNSPECIFIED\":return yl.HASH_ALGORITHM_UNSPECIFIED;case 1:case\"SHA2_256\":return yl.SHA2_256;case 2:case\"SHA2_384\":return yl.SHA2_384;case 3:case\"SHA2_512\":return yl.SHA2_512;case 4:case\"SHA3_256\":return yl.SHA3_256;case 5:case\"SHA3_384\":return yl.SHA3_384;default:throw new globalThis.Error(\"Unrecognized enum value \"+t+\" for enum HashAlgorithm\")}}function GSe(t){switch(t){case yl.HASH_ALGORITHM_UNSPECIFIED:return\"HASH_ALGORITHM_UNSPECIFIED\";case yl.SHA2_256:return\"SHA2_256\";case yl.SHA2_384:return\"SHA2_384\";case yl.SHA2_512:return\"SHA2_512\";case yl.SHA3_256:return\"SHA3_256\";case yl.SHA3_384:return\"SHA3_384\";default:throw new globalThis.Error(\"Unrecognized enum value \"+t+\" for enum HashAlgorithm\")}}var rn;(function(t){t[t.PUBLIC_KEY_DETAILS_UNSPECIFIED=0]=\"PUBLIC_KEY_DETAILS_UNSPECIFIED\",t[t.PKCS1_RSA_PKCS1V5=1]=\"PKCS1_RSA_PKCS1V5\",t[t.PKCS1_RSA_PSS=2]=\"PKCS1_RSA_PSS\",t[t.PKIX_RSA_PKCS1V5=3]=\"PKIX_RSA_PKCS1V5\",t[t.PKIX_RSA_PSS=4]=\"PKIX_RSA_PSS\",t[t.PKIX_RSA_PKCS1V15_2048_SHA256=9]=\"PKIX_RSA_PKCS1V15_2048_SHA256\",t[t.PKIX_RSA_PKCS1V15_3072_SHA256=10]=\"PKIX_RSA_PKCS1V15_3072_SHA256\",t[t.PKIX_RSA_PKCS1V15_4096_SHA256=11]=\"PKIX_RSA_PKCS1V15_4096_SHA256\",t[t.PKIX_RSA_PSS_2048_SHA256=16]=\"PKIX_RSA_PSS_2048_SHA256\",t[t.PKIX_RSA_PSS_3072_SHA256=17]=\"PKIX_RSA_PSS_3072_SHA256\",t[t.PKIX_RSA_PSS_4096_SHA256=18]=\"PKIX_RSA_PSS_4096_SHA256\",t[t.PKIX_ECDSA_P256_HMAC_SHA_256=6]=\"PKIX_ECDSA_P256_HMAC_SHA_256\",t[t.PKIX_ECDSA_P256_SHA_256=5]=\"PKIX_ECDSA_P256_SHA_256\",t[t.PKIX_ECDSA_P384_SHA_384=12]=\"PKIX_ECDSA_P384_SHA_384\",t[t.PKIX_ECDSA_P521_SHA_512=13]=\"PKIX_ECDSA_P521_SHA_512\",t[t.PKIX_ED25519=7]=\"PKIX_ED25519\",t[t.PKIX_ED25519_PH=8]=\"PKIX_ED25519_PH\",t[t.LMS_SHA256=14]=\"LMS_SHA256\",t[t.LMOTS_SHA256=15]=\"LMOTS_SHA256\"})(rn||(Ur.PublicKeyDetails=rn={}));function qSe(t){switch(t){case 0:case\"PUBLIC_KEY_DETAILS_UNSPECIFIED\":return rn.PUBLIC_KEY_DETAILS_UNSPECIFIED;case 1:case\"PKCS1_RSA_PKCS1V5\":return rn.PKCS1_RSA_PKCS1V5;case 2:case\"PKCS1_RSA_PSS\":return rn.PKCS1_RSA_PSS;case 3:case\"PKIX_RSA_PKCS1V5\":return rn.PKIX_RSA_PKCS1V5;case 4:case\"PKIX_RSA_PSS\":return rn.PKIX_RSA_PSS;case 9:case\"PKIX_RSA_PKCS1V15_2048_SHA256\":return rn.PKIX_RSA_PKCS1V15_2048_SHA256;case 10:case\"PKIX_RSA_PKCS1V15_3072_SHA256\":return rn.PKIX_RSA_PKCS1V15_3072_SHA256;case 11:case\"PKIX_RSA_PKCS1V15_4096_SHA256\":return rn.PKIX_RSA_PKCS1V15_4096_SHA256;case 16:case\"PKIX_RSA_PSS_2048_SHA256\":return rn.PKIX_RSA_PSS_2048_SHA256;case 17:case\"PKIX_RSA_PSS_3072_SHA256\":return rn.PKIX_RSA_PSS_3072_SHA256;case 18:case\"PKIX_RSA_PSS_4096_SHA256\":return rn.PKIX_RSA_PSS_4096_SHA256;case 6:case\"PKIX_ECDSA_P256_HMAC_SHA_256\":return rn.PKIX_ECDSA_P256_HMAC_SHA_256;case 5:case\"PKIX_ECDSA_P256_SHA_256\":return rn.PKIX_ECDSA_P256_SHA_256;case 12:case\"PKIX_ECDSA_P384_SHA_384\":return rn.PKIX_ECDSA_P384_SHA_384;case 13:case\"PKIX_ECDSA_P521_SHA_512\":return rn.PKIX_ECDSA_P521_SHA_512;case 7:case\"PKIX_ED25519\":return rn.PKIX_ED25519;case 8:case\"PKIX_ED25519_PH\":return rn.PKIX_ED25519_PH;case 14:case\"LMS_SHA256\":return rn.LMS_SHA256;case 15:case\"LMOTS_SHA256\":return rn.LMOTS_SHA256;default:throw new globalThis.Error(\"Unrecognized enum value \"+t+\" for enum PublicKeyDetails\")}}function WSe(t){switch(t){case rn.PUBLIC_KEY_DETAILS_UNSPECIFIED:return\"PUBLIC_KEY_DETAILS_UNSPECIFIED\";case rn.PKCS1_RSA_PKCS1V5:return\"PKCS1_RSA_PKCS1V5\";case rn.PKCS1_RSA_PSS:return\"PKCS1_RSA_PSS\";case rn.PKIX_RSA_PKCS1V5:return\"PKIX_RSA_PKCS1V5\";case rn.PKIX_RSA_PSS:return\"PKIX_RSA_PSS\";case rn.PKIX_RSA_PKCS1V15_2048_SHA256:return\"PKIX_RSA_PKCS1V15_2048_SHA256\";case rn.PKIX_RSA_PKCS1V15_3072_SHA256:return\"PKIX_RSA_PKCS1V15_3072_SHA256\";case rn.PKIX_RSA_PKCS1V15_4096_SHA256:return\"PKIX_RSA_PKCS1V15_4096_SHA256\";case rn.PKIX_RSA_PSS_2048_SHA256:return\"PKIX_RSA_PSS_2048_SHA256\";case rn.PKIX_RSA_PSS_3072_SHA256:return\"PKIX_RSA_PSS_3072_SHA256\";case rn.PKIX_RSA_PSS_4096_SHA256:return\"PKIX_RSA_PSS_4096_SHA256\";case rn.PKIX_ECDSA_P256_HMAC_SHA_256:return\"PKIX_ECDSA_P256_HMAC_SHA_256\";case rn.PKIX_ECDSA_P256_SHA_256:return\"PKIX_ECDSA_P256_SHA_256\";case rn.PKIX_ECDSA_P384_SHA_384:return\"PKIX_ECDSA_P384_SHA_384\";case rn.PKIX_ECDSA_P521_SHA_512:return\"PKIX_ECDSA_P521_SHA_512\";case rn.PKIX_ED25519:return\"PKIX_ED25519\";case rn.PKIX_ED25519_PH:return\"PKIX_ED25519_PH\";case rn.LMS_SHA256:return\"LMS_SHA256\";case rn.LMOTS_SHA256:return\"LMOTS_SHA256\";default:throw new globalThis.Error(\"Unrecognized enum value \"+t+\" for enum PublicKeyDetails\")}}var CA;(function(t){t[t.SUBJECT_ALTERNATIVE_NAME_TYPE_UNSPECIFIED=0]=\"SUBJECT_ALTERNATIVE_NAME_TYPE_UNSPECIFIED\",t[t.EMAIL=1]=\"EMAIL\",t[t.URI=2]=\"URI\",t[t.OTHER_NAME=3]=\"OTHER_NAME\"})(CA||(Ur.SubjectAlternativeNameType=CA={}));function YSe(t){switch(t){case 0:case\"SUBJECT_ALTERNATIVE_NAME_TYPE_UNSPECIFIED\":return CA.SUBJECT_ALTERNATIVE_NAME_TYPE_UNSPECIFIED;case 1:case\"EMAIL\":return CA.EMAIL;case 2:case\"URI\":return CA.URI;case 3:case\"OTHER_NAME\":return CA.OTHER_NAME;default:throw new globalThis.Error(\"Unrecognized enum value \"+t+\" for enum SubjectAlternativeNameType\")}}function VSe(t){switch(t){case CA.SUBJECT_ALTERNATIVE_NAME_TYPE_UNSPECIFIED:return\"SUBJECT_ALTERNATIVE_NAME_TYPE_UNSPECIFIED\";case CA.EMAIL:return\"EMAIL\";case CA.URI:return\"URI\";case CA.OTHER_NAME:return\"OTHER_NAME\";default:throw new globalThis.Error(\"Unrecognized enum value \"+t+\" for enum SubjectAlternativeNameType\")}}Ur.HashOutput={fromJSON(t){return{algorithm:ds(t.algorithm)?jSe(t.algorithm):0,digest:ds(t.digest)?Buffer.from(Xm(t.digest)):Buffer.alloc(0)}},toJSON(t){let e={};return t.algorithm!==0&&(e.algorithm=GSe(t.algorithm)),t.digest.length!==0&&(e.digest=$m(t.digest)),e}};Ur.MessageSignature={fromJSON(t){return{messageDigest:ds(t.messageDigest)?Ur.HashOutput.fromJSON(t.messageDigest):void 0,signature:ds(t.signature)?Buffer.from(Xm(t.signature)):Buffer.alloc(0)}},toJSON(t){let e={};return t.messageDigest!==void 0&&(e.messageDigest=Ur.HashOutput.toJSON(t.messageDigest)),t.signature.length!==0&&(e.signature=$m(t.signature)),e}};Ur.LogId={fromJSON(t){return{keyId:ds(t.keyId)?Buffer.from(Xm(t.keyId)):Buffer.alloc(0)}},toJSON(t){let e={};return t.keyId.length!==0&&(e.keyId=$m(t.keyId)),e}};Ur.RFC3161SignedTimestamp={fromJSON(t){return{signedTimestamp:ds(t.signedTimestamp)?Buffer.from(Xm(t.signedTimestamp)):Buffer.alloc(0)}},toJSON(t){let e={};return t.signedTimestamp.length!==0&&(e.signedTimestamp=$m(t.signedTimestamp)),e}};Ur.PublicKey={fromJSON(t){return{rawBytes:ds(t.rawBytes)?Buffer.from(Xm(t.rawBytes)):void 0,keyDetails:ds(t.keyDetails)?qSe(t.keyDetails):0,validFor:ds(t.validFor)?Ur.TimeRange.fromJSON(t.validFor):void 0}},toJSON(t){let e={};return t.rawBytes!==void 0&&(e.rawBytes=$m(t.rawBytes)),t.keyDetails!==0&&(e.keyDetails=WSe(t.keyDetails)),t.validFor!==void 0&&(e.validFor=Ur.TimeRange.toJSON(t.validFor)),e}};Ur.PublicKeyIdentifier={fromJSON(t){return{hint:ds(t.hint)?globalThis.String(t.hint):\"\"}},toJSON(t){let e={};return t.hint!==\"\"&&(e.hint=t.hint),e}};Ur.ObjectIdentifier={fromJSON(t){return{id:globalThis.Array.isArray(t?.id)?t.id.map(e=>globalThis.Number(e)):[]}},toJSON(t){let e={};return t.id?.length&&(e.id=t.id.map(r=>Math.round(r))),e}};Ur.ObjectIdentifierValuePair={fromJSON(t){return{oid:ds(t.oid)?Ur.ObjectIdentifier.fromJSON(t.oid):void 0,value:ds(t.value)?Buffer.from(Xm(t.value)):Buffer.alloc(0)}},toJSON(t){let e={};return t.oid!==void 0&&(e.oid=Ur.ObjectIdentifier.toJSON(t.oid)),t.value.length!==0&&(e.value=$m(t.value)),e}};Ur.DistinguishedName={fromJSON(t){return{organization:ds(t.organization)?globalThis.String(t.organization):\"\",commonName:ds(t.commonName)?globalThis.String(t.commonName):\"\"}},toJSON(t){let e={};return t.organization!==\"\"&&(e.organization=t.organization),t.commonName!==\"\"&&(e.commonName=t.commonName),e}};Ur.X509Certificate={fromJSON(t){return{rawBytes:ds(t.rawBytes)?Buffer.from(Xm(t.rawBytes)):Buffer.alloc(0)}},toJSON(t){let e={};return t.rawBytes.length!==0&&(e.rawBytes=$m(t.rawBytes)),e}};Ur.SubjectAlternativeName={fromJSON(t){return{type:ds(t.type)?YSe(t.type):0,identity:ds(t.regexp)?{$case:\"regexp\",regexp:globalThis.String(t.regexp)}:ds(t.value)?{$case:\"value\",value:globalThis.String(t.value)}:void 0}},toJSON(t){let e={};return t.type!==0&&(e.type=VSe(t.type)),t.identity?.$case===\"regexp\"?e.regexp=t.identity.regexp:t.identity?.$case===\"value\"&&(e.value=t.identity.value),e}};Ur.X509CertificateChain={fromJSON(t){return{certificates:globalThis.Array.isArray(t?.certificates)?t.certificates.map(e=>Ur.X509Certificate.fromJSON(e)):[]}},toJSON(t){let e={};return t.certificates?.length&&(e.certificates=t.certificates.map(r=>Ur.X509Certificate.toJSON(r))),e}};Ur.TimeRange={fromJSON(t){return{start:ds(t.start)?HSe(t.start):void 0,end:ds(t.end)?HSe(t.end):void 0}},toJSON(t){let e={};return t.start!==void 0&&(e.start=t.start.toISOString()),t.end!==void 0&&(e.end=t.end.toISOString()),e}};function Xm(t){return Uint8Array.from(globalThis.Buffer.from(t,\"base64\"))}function $m(t){return globalThis.Buffer.from(t).toString(\"base64\")}function pIt(t){let e=(globalThis.Number(t.seconds)||0)*1e3;return e+=(t.nanos||0)/1e6,new globalThis.Date(e)}function HSe(t){return t instanceof globalThis.Date?t:typeof t==\"string\"?new globalThis.Date(t):pIt(AIt.Timestamp.fromJSON(t))}function ds(t){return t!=null}});var FV=_(ms=>{\"use strict\";Object.defineProperty(ms,\"__esModule\",{value:!0});ms.TransparencyLogEntry=ms.InclusionPromise=ms.InclusionProof=ms.Checkpoint=ms.KindVersion=void 0;var JSe=Ww();ms.KindVersion={fromJSON(t){return{kind:Ta(t.kind)?globalThis.String(t.kind):\"\",version:Ta(t.version)?globalThis.String(t.version):\"\"}},toJSON(t){let e={};return t.kind!==\"\"&&(e.kind=t.kind),t.version!==\"\"&&(e.version=t.version),e}};ms.Checkpoint={fromJSON(t){return{envelope:Ta(t.envelope)?globalThis.String(t.envelope):\"\"}},toJSON(t){let e={};return t.envelope!==\"\"&&(e.envelope=t.envelope),e}};ms.InclusionProof={fromJSON(t){return{logIndex:Ta(t.logIndex)?globalThis.String(t.logIndex):\"0\",rootHash:Ta(t.rootHash)?Buffer.from(qN(t.rootHash)):Buffer.alloc(0),treeSize:Ta(t.treeSize)?globalThis.String(t.treeSize):\"0\",hashes:globalThis.Array.isArray(t?.hashes)?t.hashes.map(e=>Buffer.from(qN(e))):[],checkpoint:Ta(t.checkpoint)?ms.Checkpoint.fromJSON(t.checkpoint):void 0}},toJSON(t){let e={};return t.logIndex!==\"0\"&&(e.logIndex=t.logIndex),t.rootHash.length!==0&&(e.rootHash=WN(t.rootHash)),t.treeSize!==\"0\"&&(e.treeSize=t.treeSize),t.hashes?.length&&(e.hashes=t.hashes.map(r=>WN(r))),t.checkpoint!==void 0&&(e.checkpoint=ms.Checkpoint.toJSON(t.checkpoint)),e}};ms.InclusionPromise={fromJSON(t){return{signedEntryTimestamp:Ta(t.signedEntryTimestamp)?Buffer.from(qN(t.signedEntryTimestamp)):Buffer.alloc(0)}},toJSON(t){let e={};return t.signedEntryTimestamp.length!==0&&(e.signedEntryTimestamp=WN(t.signedEntryTimestamp)),e}};ms.TransparencyLogEntry={fromJSON(t){return{logIndex:Ta(t.logIndex)?globalThis.String(t.logIndex):\"0\",logId:Ta(t.logId)?JSe.LogId.fromJSON(t.logId):void 0,kindVersion:Ta(t.kindVersion)?ms.KindVersion.fromJSON(t.kindVersion):void 0,integratedTime:Ta(t.integratedTime)?globalThis.String(t.integratedTime):\"0\",inclusionPromise:Ta(t.inclusionPromise)?ms.InclusionPromise.fromJSON(t.inclusionPromise):void 0,inclusionProof:Ta(t.inclusionProof)?ms.InclusionProof.fromJSON(t.inclusionProof):void 0,canonicalizedBody:Ta(t.canonicalizedBody)?Buffer.from(qN(t.canonicalizedBody)):Buffer.alloc(0)}},toJSON(t){let e={};return t.logIndex!==\"0\"&&(e.logIndex=t.logIndex),t.logId!==void 0&&(e.logId=JSe.LogId.toJSON(t.logId)),t.kindVersion!==void 0&&(e.kindVersion=ms.KindVersion.toJSON(t.kindVersion)),t.integratedTime!==\"0\"&&(e.integratedTime=t.integratedTime),t.inclusionPromise!==void 0&&(e.inclusionPromise=ms.InclusionPromise.toJSON(t.inclusionPromise)),t.inclusionProof!==void 0&&(e.inclusionProof=ms.InclusionProof.toJSON(t.inclusionProof)),t.canonicalizedBody.length!==0&&(e.canonicalizedBody=WN(t.canonicalizedBody)),e}};function qN(t){return Uint8Array.from(globalThis.Buffer.from(t,\"base64\"))}function WN(t){return globalThis.Buffer.from(t).toString(\"base64\")}function Ta(t){return t!=null}});var NV=_(Zc=>{\"use strict\";Object.defineProperty(Zc,\"__esModule\",{value:!0});Zc.Bundle=Zc.VerificationMaterial=Zc.TimestampVerificationData=void 0;var KSe=TV(),wA=Ww(),zSe=FV();Zc.TimestampVerificationData={fromJSON(t){return{rfc3161Timestamps:globalThis.Array.isArray(t?.rfc3161Timestamps)?t.rfc3161Timestamps.map(e=>wA.RFC3161SignedTimestamp.fromJSON(e)):[]}},toJSON(t){let e={};return t.rfc3161Timestamps?.length&&(e.rfc3161Timestamps=t.rfc3161Timestamps.map(r=>wA.RFC3161SignedTimestamp.toJSON(r))),e}};Zc.VerificationMaterial={fromJSON(t){return{content:yg(t.publicKey)?{$case:\"publicKey\",publicKey:wA.PublicKeyIdentifier.fromJSON(t.publicKey)}:yg(t.x509CertificateChain)?{$case:\"x509CertificateChain\",x509CertificateChain:wA.X509CertificateChain.fromJSON(t.x509CertificateChain)}:yg(t.certificate)?{$case:\"certificate\",certificate:wA.X509Certificate.fromJSON(t.certificate)}:void 0,tlogEntries:globalThis.Array.isArray(t?.tlogEntries)?t.tlogEntries.map(e=>zSe.TransparencyLogEntry.fromJSON(e)):[],timestampVerificationData:yg(t.timestampVerificationData)?Zc.TimestampVerificationData.fromJSON(t.timestampVerificationData):void 0}},toJSON(t){let e={};return t.content?.$case===\"publicKey\"?e.publicKey=wA.PublicKeyIdentifier.toJSON(t.content.publicKey):t.content?.$case===\"x509CertificateChain\"?e.x509CertificateChain=wA.X509CertificateChain.toJSON(t.content.x509CertificateChain):t.content?.$case===\"certificate\"&&(e.certificate=wA.X509Certificate.toJSON(t.content.certificate)),t.tlogEntries?.length&&(e.tlogEntries=t.tlogEntries.map(r=>zSe.TransparencyLogEntry.toJSON(r))),t.timestampVerificationData!==void 0&&(e.timestampVerificationData=Zc.TimestampVerificationData.toJSON(t.timestampVerificationData)),e}};Zc.Bundle={fromJSON(t){return{mediaType:yg(t.mediaType)?globalThis.String(t.mediaType):\"\",verificationMaterial:yg(t.verificationMaterial)?Zc.VerificationMaterial.fromJSON(t.verificationMaterial):void 0,content:yg(t.messageSignature)?{$case:\"messageSignature\",messageSignature:wA.MessageSignature.fromJSON(t.messageSignature)}:yg(t.dsseEnvelope)?{$case:\"dsseEnvelope\",dsseEnvelope:KSe.Envelope.fromJSON(t.dsseEnvelope)}:void 0}},toJSON(t){let e={};return t.mediaType!==\"\"&&(e.mediaType=t.mediaType),t.verificationMaterial!==void 0&&(e.verificationMaterial=Zc.VerificationMaterial.toJSON(t.verificationMaterial)),t.content?.$case===\"messageSignature\"?e.messageSignature=wA.MessageSignature.toJSON(t.content.messageSignature):t.content?.$case===\"dsseEnvelope\"&&(e.dsseEnvelope=KSe.Envelope.toJSON(t.content.dsseEnvelope)),e}};function yg(t){return t!=null}});var OV=_(Ti=>{\"use strict\";Object.defineProperty(Ti,\"__esModule\",{value:!0});Ti.ClientTrustConfig=Ti.SigningConfig=Ti.TrustedRoot=Ti.CertificateAuthority=Ti.TransparencyLogInstance=void 0;var El=Ww();Ti.TransparencyLogInstance={fromJSON(t){return{baseUrl:ia(t.baseUrl)?globalThis.String(t.baseUrl):\"\",hashAlgorithm:ia(t.hashAlgorithm)?(0,El.hashAlgorithmFromJSON)(t.hashAlgorithm):0,publicKey:ia(t.publicKey)?El.PublicKey.fromJSON(t.publicKey):void 0,logId:ia(t.logId)?El.LogId.fromJSON(t.logId):void 0,checkpointKeyId:ia(t.checkpointKeyId)?El.LogId.fromJSON(t.checkpointKeyId):void 0}},toJSON(t){let e={};return t.baseUrl!==\"\"&&(e.baseUrl=t.baseUrl),t.hashAlgorithm!==0&&(e.hashAlgorithm=(0,El.hashAlgorithmToJSON)(t.hashAlgorithm)),t.publicKey!==void 0&&(e.publicKey=El.PublicKey.toJSON(t.publicKey)),t.logId!==void 0&&(e.logId=El.LogId.toJSON(t.logId)),t.checkpointKeyId!==void 0&&(e.checkpointKeyId=El.LogId.toJSON(t.checkpointKeyId)),e}};Ti.CertificateAuthority={fromJSON(t){return{subject:ia(t.subject)?El.DistinguishedName.fromJSON(t.subject):void 0,uri:ia(t.uri)?globalThis.String(t.uri):\"\",certChain:ia(t.certChain)?El.X509CertificateChain.fromJSON(t.certChain):void 0,validFor:ia(t.validFor)?El.TimeRange.fromJSON(t.validFor):void 0}},toJSON(t){let e={};return t.subject!==void 0&&(e.subject=El.DistinguishedName.toJSON(t.subject)),t.uri!==\"\"&&(e.uri=t.uri),t.certChain!==void 0&&(e.certChain=El.X509CertificateChain.toJSON(t.certChain)),t.validFor!==void 0&&(e.validFor=El.TimeRange.toJSON(t.validFor)),e}};Ti.TrustedRoot={fromJSON(t){return{mediaType:ia(t.mediaType)?globalThis.String(t.mediaType):\"\",tlogs:globalThis.Array.isArray(t?.tlogs)?t.tlogs.map(e=>Ti.TransparencyLogInstance.fromJSON(e)):[],certificateAuthorities:globalThis.Array.isArray(t?.certificateAuthorities)?t.certificateAuthorities.map(e=>Ti.CertificateAuthority.fromJSON(e)):[],ctlogs:globalThis.Array.isArray(t?.ctlogs)?t.ctlogs.map(e=>Ti.TransparencyLogInstance.fromJSON(e)):[],timestampAuthorities:globalThis.Array.isArray(t?.timestampAuthorities)?t.timestampAuthorities.map(e=>Ti.CertificateAuthority.fromJSON(e)):[]}},toJSON(t){let e={};return t.mediaType!==\"\"&&(e.mediaType=t.mediaType),t.tlogs?.length&&(e.tlogs=t.tlogs.map(r=>Ti.TransparencyLogInstance.toJSON(r))),t.certificateAuthorities?.length&&(e.certificateAuthorities=t.certificateAuthorities.map(r=>Ti.CertificateAuthority.toJSON(r))),t.ctlogs?.length&&(e.ctlogs=t.ctlogs.map(r=>Ti.TransparencyLogInstance.toJSON(r))),t.timestampAuthorities?.length&&(e.timestampAuthorities=t.timestampAuthorities.map(r=>Ti.CertificateAuthority.toJSON(r))),e}};Ti.SigningConfig={fromJSON(t){return{mediaType:ia(t.mediaType)?globalThis.String(t.mediaType):\"\",caUrl:ia(t.caUrl)?globalThis.String(t.caUrl):\"\",oidcUrl:ia(t.oidcUrl)?globalThis.String(t.oidcUrl):\"\",tlogUrls:globalThis.Array.isArray(t?.tlogUrls)?t.tlogUrls.map(e=>globalThis.String(e)):[],tsaUrls:globalThis.Array.isArray(t?.tsaUrls)?t.tsaUrls.map(e=>globalThis.String(e)):[]}},toJSON(t){let e={};return t.mediaType!==\"\"&&(e.mediaType=t.mediaType),t.caUrl!==\"\"&&(e.caUrl=t.caUrl),t.oidcUrl!==\"\"&&(e.oidcUrl=t.oidcUrl),t.tlogUrls?.length&&(e.tlogUrls=t.tlogUrls),t.tsaUrls?.length&&(e.tsaUrls=t.tsaUrls),e}};Ti.ClientTrustConfig={fromJSON(t){return{mediaType:ia(t.mediaType)?globalThis.String(t.mediaType):\"\",trustedRoot:ia(t.trustedRoot)?Ti.TrustedRoot.fromJSON(t.trustedRoot):void 0,signingConfig:ia(t.signingConfig)?Ti.SigningConfig.fromJSON(t.signingConfig):void 0}},toJSON(t){let e={};return t.mediaType!==\"\"&&(e.mediaType=t.mediaType),t.trustedRoot!==void 0&&(e.trustedRoot=Ti.TrustedRoot.toJSON(t.trustedRoot)),t.signingConfig!==void 0&&(e.signingConfig=Ti.SigningConfig.toJSON(t.signingConfig)),e}};function ia(t){return t!=null}});var $Se=_(Vr=>{\"use strict\";Object.defineProperty(Vr,\"__esModule\",{value:!0});Vr.Input=Vr.Artifact=Vr.ArtifactVerificationOptions_ObserverTimestampOptions=Vr.ArtifactVerificationOptions_TlogIntegratedTimestampOptions=Vr.ArtifactVerificationOptions_TimestampAuthorityOptions=Vr.ArtifactVerificationOptions_CtlogOptions=Vr.ArtifactVerificationOptions_TlogOptions=Vr.ArtifactVerificationOptions=Vr.PublicKeyIdentities=Vr.CertificateIdentities=Vr.CertificateIdentity=void 0;var ZSe=NV(),Eg=Ww(),XSe=OV();Vr.CertificateIdentity={fromJSON(t){return{issuer:gi(t.issuer)?globalThis.String(t.issuer):\"\",san:gi(t.san)?Eg.SubjectAlternativeName.fromJSON(t.san):void 0,oids:globalThis.Array.isArray(t?.oids)?t.oids.map(e=>Eg.ObjectIdentifierValuePair.fromJSON(e)):[]}},toJSON(t){let e={};return t.issuer!==\"\"&&(e.issuer=t.issuer),t.san!==void 0&&(e.san=Eg.SubjectAlternativeName.toJSON(t.san)),t.oids?.length&&(e.oids=t.oids.map(r=>Eg.ObjectIdentifierValuePair.toJSON(r))),e}};Vr.CertificateIdentities={fromJSON(t){return{identities:globalThis.Array.isArray(t?.identities)?t.identities.map(e=>Vr.CertificateIdentity.fromJSON(e)):[]}},toJSON(t){let e={};return t.identities?.length&&(e.identities=t.identities.map(r=>Vr.CertificateIdentity.toJSON(r))),e}};Vr.PublicKeyIdentities={fromJSON(t){return{publicKeys:globalThis.Array.isArray(t?.publicKeys)?t.publicKeys.map(e=>Eg.PublicKey.fromJSON(e)):[]}},toJSON(t){let e={};return t.publicKeys?.length&&(e.publicKeys=t.publicKeys.map(r=>Eg.PublicKey.toJSON(r))),e}};Vr.ArtifactVerificationOptions={fromJSON(t){return{signers:gi(t.certificateIdentities)?{$case:\"certificateIdentities\",certificateIdentities:Vr.CertificateIdentities.fromJSON(t.certificateIdentities)}:gi(t.publicKeys)?{$case:\"publicKeys\",publicKeys:Vr.PublicKeyIdentities.fromJSON(t.publicKeys)}:void 0,tlogOptions:gi(t.tlogOptions)?Vr.ArtifactVerificationOptions_TlogOptions.fromJSON(t.tlogOptions):void 0,ctlogOptions:gi(t.ctlogOptions)?Vr.ArtifactVerificationOptions_CtlogOptions.fromJSON(t.ctlogOptions):void 0,tsaOptions:gi(t.tsaOptions)?Vr.ArtifactVerificationOptions_TimestampAuthorityOptions.fromJSON(t.tsaOptions):void 0,integratedTsOptions:gi(t.integratedTsOptions)?Vr.ArtifactVerificationOptions_TlogIntegratedTimestampOptions.fromJSON(t.integratedTsOptions):void 0,observerOptions:gi(t.observerOptions)?Vr.ArtifactVerificationOptions_ObserverTimestampOptions.fromJSON(t.observerOptions):void 0}},toJSON(t){let e={};return t.signers?.$case===\"certificateIdentities\"?e.certificateIdentities=Vr.CertificateIdentities.toJSON(t.signers.certificateIdentities):t.signers?.$case===\"publicKeys\"&&(e.publicKeys=Vr.PublicKeyIdentities.toJSON(t.signers.publicKeys)),t.tlogOptions!==void 0&&(e.tlogOptions=Vr.ArtifactVerificationOptions_TlogOptions.toJSON(t.tlogOptions)),t.ctlogOptions!==void 0&&(e.ctlogOptions=Vr.ArtifactVerificationOptions_CtlogOptions.toJSON(t.ctlogOptions)),t.tsaOptions!==void 0&&(e.tsaOptions=Vr.ArtifactVerificationOptions_TimestampAuthorityOptions.toJSON(t.tsaOptions)),t.integratedTsOptions!==void 0&&(e.integratedTsOptions=Vr.ArtifactVerificationOptions_TlogIntegratedTimestampOptions.toJSON(t.integratedTsOptions)),t.observerOptions!==void 0&&(e.observerOptions=Vr.ArtifactVerificationOptions_ObserverTimestampOptions.toJSON(t.observerOptions)),e}};Vr.ArtifactVerificationOptions_TlogOptions={fromJSON(t){return{threshold:gi(t.threshold)?globalThis.Number(t.threshold):0,performOnlineVerification:gi(t.performOnlineVerification)?globalThis.Boolean(t.performOnlineVerification):!1,disable:gi(t.disable)?globalThis.Boolean(t.disable):!1}},toJSON(t){let e={};return t.threshold!==0&&(e.threshold=Math.round(t.threshold)),t.performOnlineVerification!==!1&&(e.performOnlineVerification=t.performOnlineVerification),t.disable!==!1&&(e.disable=t.disable),e}};Vr.ArtifactVerificationOptions_CtlogOptions={fromJSON(t){return{threshold:gi(t.threshold)?globalThis.Number(t.threshold):0,disable:gi(t.disable)?globalThis.Boolean(t.disable):!1}},toJSON(t){let e={};return t.threshold!==0&&(e.threshold=Math.round(t.threshold)),t.disable!==!1&&(e.disable=t.disable),e}};Vr.ArtifactVerificationOptions_TimestampAuthorityOptions={fromJSON(t){return{threshold:gi(t.threshold)?globalThis.Number(t.threshold):0,disable:gi(t.disable)?globalThis.Boolean(t.disable):!1}},toJSON(t){let e={};return t.threshold!==0&&(e.threshold=Math.round(t.threshold)),t.disable!==!1&&(e.disable=t.disable),e}};Vr.ArtifactVerificationOptions_TlogIntegratedTimestampOptions={fromJSON(t){return{threshold:gi(t.threshold)?globalThis.Number(t.threshold):0,disable:gi(t.disable)?globalThis.Boolean(t.disable):!1}},toJSON(t){let e={};return t.threshold!==0&&(e.threshold=Math.round(t.threshold)),t.disable!==!1&&(e.disable=t.disable),e}};Vr.ArtifactVerificationOptions_ObserverTimestampOptions={fromJSON(t){return{threshold:gi(t.threshold)?globalThis.Number(t.threshold):0,disable:gi(t.disable)?globalThis.Boolean(t.disable):!1}},toJSON(t){let e={};return t.threshold!==0&&(e.threshold=Math.round(t.threshold)),t.disable!==!1&&(e.disable=t.disable),e}};Vr.Artifact={fromJSON(t){return{data:gi(t.artifactUri)?{$case:\"artifactUri\",artifactUri:globalThis.String(t.artifactUri)}:gi(t.artifact)?{$case:\"artifact\",artifact:Buffer.from(hIt(t.artifact))}:gi(t.artifactDigest)?{$case:\"artifactDigest\",artifactDigest:Eg.HashOutput.fromJSON(t.artifactDigest)}:void 0}},toJSON(t){let e={};return t.data?.$case===\"artifactUri\"?e.artifactUri=t.data.artifactUri:t.data?.$case===\"artifact\"?e.artifact=gIt(t.data.artifact):t.data?.$case===\"artifactDigest\"&&(e.artifactDigest=Eg.HashOutput.toJSON(t.data.artifactDigest)),e}};Vr.Input={fromJSON(t){return{artifactTrustRoot:gi(t.artifactTrustRoot)?XSe.TrustedRoot.fromJSON(t.artifactTrustRoot):void 0,artifactVerificationOptions:gi(t.artifactVerificationOptions)?Vr.ArtifactVerificationOptions.fromJSON(t.artifactVerificationOptions):void 0,bundle:gi(t.bundle)?ZSe.Bundle.fromJSON(t.bundle):void 0,artifact:gi(t.artifact)?Vr.Artifact.fromJSON(t.artifact):void 0}},toJSON(t){let e={};return t.artifactTrustRoot!==void 0&&(e.artifactTrustRoot=XSe.TrustedRoot.toJSON(t.artifactTrustRoot)),t.artifactVerificationOptions!==void 0&&(e.artifactVerificationOptions=Vr.ArtifactVerificationOptions.toJSON(t.artifactVerificationOptions)),t.bundle!==void 0&&(e.bundle=ZSe.Bundle.toJSON(t.bundle)),t.artifact!==void 0&&(e.artifact=Vr.Artifact.toJSON(t.artifact)),e}};function hIt(t){return Uint8Array.from(globalThis.Buffer.from(t,\"base64\"))}function gIt(t){return globalThis.Buffer.from(t).toString(\"base64\")}function gi(t){return t!=null}});var mP=_(Xc=>{\"use strict\";var dIt=Xc&&Xc.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||(\"get\"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),Yw=Xc&&Xc.__exportStar||function(t,e){for(var r in t)r!==\"default\"&&!Object.prototype.hasOwnProperty.call(e,r)&&dIt(e,t,r)};Object.defineProperty(Xc,\"__esModule\",{value:!0});Yw(TV(),Xc);Yw(NV(),Xc);Yw(Ww(),Xc);Yw(FV(),Xc);Yw(OV(),Xc);Yw($Se(),Xc)});var YN=_(Il=>{\"use strict\";Object.defineProperty(Il,\"__esModule\",{value:!0});Il.BUNDLE_V03_MEDIA_TYPE=Il.BUNDLE_V03_LEGACY_MEDIA_TYPE=Il.BUNDLE_V02_MEDIA_TYPE=Il.BUNDLE_V01_MEDIA_TYPE=void 0;Il.isBundleWithCertificateChain=mIt;Il.isBundleWithPublicKey=yIt;Il.isBundleWithMessageSignature=EIt;Il.isBundleWithDsseEnvelope=IIt;Il.BUNDLE_V01_MEDIA_TYPE=\"application/vnd.dev.sigstore.bundle+json;version=0.1\";Il.BUNDLE_V02_MEDIA_TYPE=\"application/vnd.dev.sigstore.bundle+json;version=0.2\";Il.BUNDLE_V03_LEGACY_MEDIA_TYPE=\"application/vnd.dev.sigstore.bundle+json;version=0.3\";Il.BUNDLE_V03_MEDIA_TYPE=\"application/vnd.dev.sigstore.bundle.v0.3+json\";function mIt(t){return t.verificationMaterial.content.$case===\"x509CertificateChain\"}function yIt(t){return t.verificationMaterial.content.$case===\"publicKey\"}function EIt(t){return t.content.$case===\"messageSignature\"}function IIt(t){return t.content.$case===\"dsseEnvelope\"}});var tDe=_(JN=>{\"use strict\";Object.defineProperty(JN,\"__esModule\",{value:!0});JN.toMessageSignatureBundle=wIt;JN.toDSSEBundle=BIt;var CIt=mP(),VN=YN();function wIt(t){return{mediaType:t.certificateChain?VN.BUNDLE_V02_MEDIA_TYPE:VN.BUNDLE_V03_MEDIA_TYPE,content:{$case:\"messageSignature\",messageSignature:{messageDigest:{algorithm:CIt.HashAlgorithm.SHA2_256,digest:t.digest},signature:t.signature}},verificationMaterial:eDe(t)}}function BIt(t){return{mediaType:t.certificateChain?VN.BUNDLE_V02_MEDIA_TYPE:VN.BUNDLE_V03_MEDIA_TYPE,content:{$case:\"dsseEnvelope\",dsseEnvelope:vIt(t)},verificationMaterial:eDe(t)}}function vIt(t){return{payloadType:t.artifactType,payload:t.artifact,signatures:[SIt(t)]}}function SIt(t){return{keyid:t.keyHint||\"\",sig:t.signature}}function eDe(t){return{content:DIt(t),tlogEntries:[],timestampVerificationData:{rfc3161Timestamps:[]}}}function DIt(t){return t.certificate?t.certificateChain?{$case:\"x509CertificateChain\",x509CertificateChain:{certificates:[{rawBytes:t.certificate}]}}:{$case:\"certificate\",certificate:{rawBytes:t.certificate}}:{$case:\"publicKey\",publicKey:{hint:t.keyHint||\"\"}}}});var MV=_(KN=>{\"use strict\";Object.defineProperty(KN,\"__esModule\",{value:!0});KN.ValidationError=void 0;var LV=class extends Error{constructor(e,r){super(e),this.fields=r}};KN.ValidationError=LV});var UV=_(ey=>{\"use strict\";Object.defineProperty(ey,\"__esModule\",{value:!0});ey.assertBundle=PIt;ey.assertBundleV01=rDe;ey.isBundleV01=bIt;ey.assertBundleV02=xIt;ey.assertBundleLatest=kIt;var zN=MV();function PIt(t){let e=ZN(t);if(e.length>0)throw new zN.ValidationError(\"invalid bundle\",e)}function rDe(t){let e=[];if(e.push(...ZN(t)),e.push(...QIt(t)),e.length>0)throw new zN.ValidationError(\"invalid v0.1 bundle\",e)}function bIt(t){try{return rDe(t),!0}catch{return!1}}function xIt(t){let e=[];if(e.push(...ZN(t)),e.push(...nDe(t)),e.length>0)throw new zN.ValidationError(\"invalid v0.2 bundle\",e)}function kIt(t){let e=[];if(e.push(...ZN(t)),e.push(...nDe(t)),e.push(...RIt(t)),e.length>0)throw new zN.ValidationError(\"invalid bundle\",e)}function ZN(t){let e=[];if((t.mediaType===void 0||!t.mediaType.match(/^application\\/vnd\\.dev\\.sigstore\\.bundle\\+json;version=\\d\\.\\d/)&&!t.mediaType.match(/^application\\/vnd\\.dev\\.sigstore\\.bundle\\.v\\d\\.\\d\\+json/))&&e.push(\"mediaType\"),t.content===void 0)e.push(\"content\");else switch(t.content.$case){case\"messageSignature\":t.content.messageSignature.messageDigest===void 0?e.push(\"content.messageSignature.messageDigest\"):t.content.messageSignature.messageDigest.digest.length===0&&e.push(\"content.messageSignature.messageDigest.digest\"),t.content.messageSignature.signature.length===0&&e.push(\"content.messageSignature.signature\");break;case\"dsseEnvelope\":t.content.dsseEnvelope.payload.length===0&&e.push(\"content.dsseEnvelope.payload\"),t.content.dsseEnvelope.signatures.length!==1?e.push(\"content.dsseEnvelope.signatures\"):t.content.dsseEnvelope.signatures[0].sig.length===0&&e.push(\"content.dsseEnvelope.signatures[0].sig\");break}if(t.verificationMaterial===void 0)e.push(\"verificationMaterial\");else{if(t.verificationMaterial.content===void 0)e.push(\"verificationMaterial.content\");else switch(t.verificationMaterial.content.$case){case\"x509CertificateChain\":t.verificationMaterial.content.x509CertificateChain.certificates.length===0&&e.push(\"verificationMaterial.content.x509CertificateChain.certificates\"),t.verificationMaterial.content.x509CertificateChain.certificates.forEach((r,s)=>{r.rawBytes.length===0&&e.push(`verificationMaterial.content.x509CertificateChain.certificates[${s}].rawBytes`)});break;case\"certificate\":t.verificationMaterial.content.certificate.rawBytes.length===0&&e.push(\"verificationMaterial.content.certificate.rawBytes\");break}t.verificationMaterial.tlogEntries===void 0?e.push(\"verificationMaterial.tlogEntries\"):t.verificationMaterial.tlogEntries.length>0&&t.verificationMaterial.tlogEntries.forEach((r,s)=>{r.logId===void 0&&e.push(`verificationMaterial.tlogEntries[${s}].logId`),r.kindVersion===void 0&&e.push(`verificationMaterial.tlogEntries[${s}].kindVersion`)})}return e}function QIt(t){let e=[];return t.verificationMaterial&&t.verificationMaterial.tlogEntries?.length>0&&t.verificationMaterial.tlogEntries.forEach((r,s)=>{r.inclusionPromise===void 0&&e.push(`verificationMaterial.tlogEntries[${s}].inclusionPromise`)}),e}function nDe(t){let e=[];return t.verificationMaterial&&t.verificationMaterial.tlogEntries?.length>0&&t.verificationMaterial.tlogEntries.forEach((r,s)=>{r.inclusionProof===void 0?e.push(`verificationMaterial.tlogEntries[${s}].inclusionProof`):r.inclusionProof.checkpoint===void 0&&e.push(`verificationMaterial.tlogEntries[${s}].inclusionProof.checkpoint`)}),e}function RIt(t){let e=[];return t.verificationMaterial?.content?.$case===\"x509CertificateChain\"&&e.push(\"verificationMaterial.content.$case\"),e}});var sDe=_(BA=>{\"use strict\";Object.defineProperty(BA,\"__esModule\",{value:!0});BA.envelopeToJSON=BA.envelopeFromJSON=BA.bundleToJSON=BA.bundleFromJSON=void 0;var XN=mP(),iDe=YN(),_V=UV(),TIt=t=>{let e=XN.Bundle.fromJSON(t);switch(e.mediaType){case iDe.BUNDLE_V01_MEDIA_TYPE:(0,_V.assertBundleV01)(e);break;case iDe.BUNDLE_V02_MEDIA_TYPE:(0,_V.assertBundleV02)(e);break;default:(0,_V.assertBundleLatest)(e);break}return e};BA.bundleFromJSON=TIt;var FIt=t=>XN.Bundle.toJSON(t);BA.bundleToJSON=FIt;var NIt=t=>XN.Envelope.fromJSON(t);BA.envelopeFromJSON=NIt;var OIt=t=>XN.Envelope.toJSON(t);BA.envelopeToJSON=OIt});var EP=_(Zr=>{\"use strict\";Object.defineProperty(Zr,\"__esModule\",{value:!0});Zr.isBundleV01=Zr.assertBundleV02=Zr.assertBundleV01=Zr.assertBundleLatest=Zr.assertBundle=Zr.envelopeToJSON=Zr.envelopeFromJSON=Zr.bundleToJSON=Zr.bundleFromJSON=Zr.ValidationError=Zr.isBundleWithPublicKey=Zr.isBundleWithMessageSignature=Zr.isBundleWithDsseEnvelope=Zr.isBundleWithCertificateChain=Zr.BUNDLE_V03_MEDIA_TYPE=Zr.BUNDLE_V03_LEGACY_MEDIA_TYPE=Zr.BUNDLE_V02_MEDIA_TYPE=Zr.BUNDLE_V01_MEDIA_TYPE=Zr.toMessageSignatureBundle=Zr.toDSSEBundle=void 0;var oDe=tDe();Object.defineProperty(Zr,\"toDSSEBundle\",{enumerable:!0,get:function(){return oDe.toDSSEBundle}});Object.defineProperty(Zr,\"toMessageSignatureBundle\",{enumerable:!0,get:function(){return oDe.toMessageSignatureBundle}});var Ig=YN();Object.defineProperty(Zr,\"BUNDLE_V01_MEDIA_TYPE\",{enumerable:!0,get:function(){return Ig.BUNDLE_V01_MEDIA_TYPE}});Object.defineProperty(Zr,\"BUNDLE_V02_MEDIA_TYPE\",{enumerable:!0,get:function(){return Ig.BUNDLE_V02_MEDIA_TYPE}});Object.defineProperty(Zr,\"BUNDLE_V03_LEGACY_MEDIA_TYPE\",{enumerable:!0,get:function(){return Ig.BUNDLE_V03_LEGACY_MEDIA_TYPE}});Object.defineProperty(Zr,\"BUNDLE_V03_MEDIA_TYPE\",{enumerable:!0,get:function(){return Ig.BUNDLE_V03_MEDIA_TYPE}});Object.defineProperty(Zr,\"isBundleWithCertificateChain\",{enumerable:!0,get:function(){return Ig.isBundleWithCertificateChain}});Object.defineProperty(Zr,\"isBundleWithDsseEnvelope\",{enumerable:!0,get:function(){return Ig.isBundleWithDsseEnvelope}});Object.defineProperty(Zr,\"isBundleWithMessageSignature\",{enumerable:!0,get:function(){return Ig.isBundleWithMessageSignature}});Object.defineProperty(Zr,\"isBundleWithPublicKey\",{enumerable:!0,get:function(){return Ig.isBundleWithPublicKey}});var LIt=MV();Object.defineProperty(Zr,\"ValidationError\",{enumerable:!0,get:function(){return LIt.ValidationError}});var $N=sDe();Object.defineProperty(Zr,\"bundleFromJSON\",{enumerable:!0,get:function(){return $N.bundleFromJSON}});Object.defineProperty(Zr,\"bundleToJSON\",{enumerable:!0,get:function(){return $N.bundleToJSON}});Object.defineProperty(Zr,\"envelopeFromJSON\",{enumerable:!0,get:function(){return $N.envelopeFromJSON}});Object.defineProperty(Zr,\"envelopeToJSON\",{enumerable:!0,get:function(){return $N.envelopeToJSON}});var yP=UV();Object.defineProperty(Zr,\"assertBundle\",{enumerable:!0,get:function(){return yP.assertBundle}});Object.defineProperty(Zr,\"assertBundleLatest\",{enumerable:!0,get:function(){return yP.assertBundleLatest}});Object.defineProperty(Zr,\"assertBundleV01\",{enumerable:!0,get:function(){return yP.assertBundleV01}});Object.defineProperty(Zr,\"assertBundleV02\",{enumerable:!0,get:function(){return yP.assertBundleV02}});Object.defineProperty(Zr,\"isBundleV01\",{enumerable:!0,get:function(){return yP.isBundleV01}})});var IP=_(tO=>{\"use strict\";Object.defineProperty(tO,\"__esModule\",{value:!0});tO.ByteStream=void 0;var HV=class extends Error{},eO=class t{constructor(e){this.start=0,e?(this.buf=e,this.view=Buffer.from(e)):(this.buf=new ArrayBuffer(0),this.view=Buffer.from(this.buf))}get buffer(){return this.view.subarray(0,this.start)}get length(){return this.view.byteLength}get position(){return this.start}seek(e){this.start=e}slice(e,r){let s=e+r;if(s>this.length)throw new HV(\"request past end of buffer\");return this.view.subarray(e,s)}appendChar(e){this.ensureCapacity(1),this.view[this.start]=e,this.start+=1}appendUint16(e){this.ensureCapacity(2);let r=new Uint16Array([e]),s=new Uint8Array(r.buffer);this.view[this.start]=s[1],this.view[this.start+1]=s[0],this.start+=2}appendUint24(e){this.ensureCapacity(3);let r=new Uint32Array([e]),s=new Uint8Array(r.buffer);this.view[this.start]=s[2],this.view[this.start+1]=s[1],this.view[this.start+2]=s[0],this.start+=3}appendView(e){this.ensureCapacity(e.length),this.view.set(e,this.start),this.start+=e.length}getBlock(e){if(e<=0)return Buffer.alloc(0);if(this.start+e>this.view.length)throw new Error(\"request past end of buffer\");let r=this.view.subarray(this.start,this.start+e);return this.start+=e,r}getUint8(){return this.getBlock(1)[0]}getUint16(){let e=this.getBlock(2);return e[0]<<8|e[1]}ensureCapacity(e){if(this.start+e>this.view.byteLength){let r=t.BLOCK_SIZE+(e>t.BLOCK_SIZE?e:0);this.realloc(this.view.byteLength+r)}}realloc(e){let r=new ArrayBuffer(e),s=Buffer.from(r);s.set(this.view),this.buf=r,this.view=s}};tO.ByteStream=eO;eO.BLOCK_SIZE=1024});var rO=_(Vw=>{\"use strict\";Object.defineProperty(Vw,\"__esModule\",{value:!0});Vw.ASN1TypeError=Vw.ASN1ParseError=void 0;var jV=class extends Error{};Vw.ASN1ParseError=jV;var GV=class extends Error{};Vw.ASN1TypeError=GV});var lDe=_(nO=>{\"use strict\";Object.defineProperty(nO,\"__esModule\",{value:!0});nO.decodeLength=MIt;nO.encodeLength=UIt;var aDe=rO();function MIt(t){let e=t.getUint8();if(!(e&128))return e;let r=e&127;if(r>6)throw new aDe.ASN1ParseError(\"length exceeds 6 byte limit\");let s=0;for(let a=0;a<r;a++)s=s*256+t.getUint8();if(s===0)throw new aDe.ASN1ParseError(\"indefinite length encoding not supported\");return s}function UIt(t){if(t<128)return Buffer.from([t]);let e=BigInt(t),r=[];for(;e>0n;)r.unshift(Number(e&255n)),e=e>>8n;return Buffer.from([128|r.length,...r])}});var uDe=_(Cg=>{\"use strict\";Object.defineProperty(Cg,\"__esModule\",{value:!0});Cg.parseInteger=jIt;Cg.parseStringASCII=cDe;Cg.parseTime=GIt;Cg.parseOID=qIt;Cg.parseBoolean=WIt;Cg.parseBitString=YIt;var _It=/^(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\.\\d{3})?Z$/,HIt=/^(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\.\\d{3})?Z$/;function jIt(t){let e=0,r=t.length,s=t[e],a=s>127,n=a?255:0;for(;s==n&&++e<r;)s=t[e];if(r-e===0)return BigInt(a?-1:0);s=a?s-256:s;let f=BigInt(s);for(let p=e+1;p<r;++p)f=f*BigInt(256)+BigInt(t[p]);return f}function cDe(t){return t.toString(\"ascii\")}function GIt(t,e){let r=cDe(t),s=e?_It.exec(r):HIt.exec(r);if(!s)throw new Error(\"invalid time\");if(e){let a=Number(s[1]);a+=a>=50?1900:2e3,s[1]=a.toString()}return new Date(`${s[1]}-${s[2]}-${s[3]}T${s[4]}:${s[5]}:${s[6]}Z`)}function qIt(t){let e=0,r=t.length,s=t[e++],a=Math.floor(s/40),n=s%40,c=`${a}.${n}`,f=0;for(;e<r;++e)s=t[e],f=(f<<7)+(s&127),s&128||(c+=`.${f}`,f=0);return c}function WIt(t){return t[0]!==0}function YIt(t){let e=t[0],r=1,s=t.length,a=[];for(let n=r;n<s;++n){let c=t[n],f=n===s-1?e:0;for(let p=7;p>=f;--p)a.push(c>>p&1)}return a}});var ADe=_(iO=>{\"use strict\";Object.defineProperty(iO,\"__esModule\",{value:!0});iO.ASN1Tag=void 0;var fDe=rO(),ty={BOOLEAN:1,INTEGER:2,BIT_STRING:3,OCTET_STRING:4,OBJECT_IDENTIFIER:6,SEQUENCE:16,SET:17,PRINTABLE_STRING:19,UTC_TIME:23,GENERALIZED_TIME:24},qV={UNIVERSAL:0,APPLICATION:1,CONTEXT_SPECIFIC:2,PRIVATE:3},WV=class{constructor(e){if(this.number=e&31,this.constructed=(e&32)===32,this.class=e>>6,this.number===31)throw new fDe.ASN1ParseError(\"long form tags not supported\");if(this.class===qV.UNIVERSAL&&this.number===0)throw new fDe.ASN1ParseError(\"unsupported tag 0x00\")}isUniversal(){return this.class===qV.UNIVERSAL}isContextSpecific(e){let r=this.class===qV.CONTEXT_SPECIFIC;return e!==void 0?r&&this.number===e:r}isBoolean(){return this.isUniversal()&&this.number===ty.BOOLEAN}isInteger(){return this.isUniversal()&&this.number===ty.INTEGER}isBitString(){return this.isUniversal()&&this.number===ty.BIT_STRING}isOctetString(){return this.isUniversal()&&this.number===ty.OCTET_STRING}isOID(){return this.isUniversal()&&this.number===ty.OBJECT_IDENTIFIER}isUTCTime(){return this.isUniversal()&&this.number===ty.UTC_TIME}isGeneralizedTime(){return this.isUniversal()&&this.number===ty.GENERALIZED_TIME}toDER(){return this.number|(this.constructed?32:0)|this.class<<6}};iO.ASN1Tag=WV});var dDe=_(oO=>{\"use strict\";Object.defineProperty(oO,\"__esModule\",{value:!0});oO.ASN1Obj=void 0;var YV=IP(),ry=rO(),hDe=lDe(),Jw=uDe(),VIt=ADe(),sO=class{constructor(e,r,s){this.tag=e,this.value=r,this.subs=s}static parseBuffer(e){return gDe(new YV.ByteStream(e))}toDER(){let e=new YV.ByteStream;if(this.subs.length>0)for(let a of this.subs)e.appendView(a.toDER());else e.appendView(this.value);let r=e.buffer,s=new YV.ByteStream;return s.appendChar(this.tag.toDER()),s.appendView((0,hDe.encodeLength)(r.length)),s.appendView(r),s.buffer}toBoolean(){if(!this.tag.isBoolean())throw new ry.ASN1TypeError(\"not a boolean\");return(0,Jw.parseBoolean)(this.value)}toInteger(){if(!this.tag.isInteger())throw new ry.ASN1TypeError(\"not an integer\");return(0,Jw.parseInteger)(this.value)}toOID(){if(!this.tag.isOID())throw new ry.ASN1TypeError(\"not an OID\");return(0,Jw.parseOID)(this.value)}toDate(){switch(!0){case this.tag.isUTCTime():return(0,Jw.parseTime)(this.value,!0);case this.tag.isGeneralizedTime():return(0,Jw.parseTime)(this.value,!1);default:throw new ry.ASN1TypeError(\"not a date\")}}toBitString(){if(!this.tag.isBitString())throw new ry.ASN1TypeError(\"not a bit string\");return(0,Jw.parseBitString)(this.value)}};oO.ASN1Obj=sO;function gDe(t){let e=new VIt.ASN1Tag(t.getUint8()),r=(0,hDe.decodeLength)(t),s=t.slice(t.position,r),a=t.position,n=[];if(e.constructed)n=pDe(t,r);else if(e.isOctetString())try{n=pDe(t,r)}catch{}return n.length===0&&t.seek(a+r),new sO(e,s,n)}function pDe(t,e){let r=t.position+e;if(r>t.length)throw new ry.ASN1ParseError(\"invalid length\");let s=[];for(;t.position<r;)s.push(gDe(t));if(t.position!==r)throw new ry.ASN1ParseError(\"invalid length\");return s}});var lO=_(aO=>{\"use strict\";Object.defineProperty(aO,\"__esModule\",{value:!0});aO.ASN1Obj=void 0;var JIt=dDe();Object.defineProperty(aO,\"ASN1Obj\",{enumerable:!0,get:function(){return JIt.ASN1Obj}})});var Kw=_(wg=>{\"use strict\";var KIt=wg&&wg.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(wg,\"__esModule\",{value:!0});wg.createPublicKey=zIt;wg.digest=ZIt;wg.verify=XIt;wg.bufferEqual=$It;var CP=KIt(Ie(\"crypto\"));function zIt(t,e=\"spki\"){return typeof t==\"string\"?CP.default.createPublicKey(t):CP.default.createPublicKey({key:t,format:\"der\",type:e})}function ZIt(t,...e){let r=CP.default.createHash(t);for(let s of e)r.update(s);return r.digest()}function XIt(t,e,r,s){try{return CP.default.verify(s,t,e,r)}catch{return!1}}function $It(t,e){try{return CP.default.timingSafeEqual(t,e)}catch{return!1}}});var mDe=_(VV=>{\"use strict\";Object.defineProperty(VV,\"__esModule\",{value:!0});VV.preAuthEncoding=tCt;var eCt=\"DSSEv1\";function tCt(t,e){let r=[eCt,t.length,t,e.length,\"\"].join(\" \");return Buffer.concat([Buffer.from(r,\"ascii\"),e])}});var IDe=_(cO=>{\"use strict\";Object.defineProperty(cO,\"__esModule\",{value:!0});cO.base64Encode=rCt;cO.base64Decode=nCt;var yDe=\"base64\",EDe=\"utf-8\";function rCt(t){return Buffer.from(t,EDe).toString(yDe)}function nCt(t){return Buffer.from(t,yDe).toString(EDe)}});var CDe=_(KV=>{\"use strict\";Object.defineProperty(KV,\"__esModule\",{value:!0});KV.canonicalize=JV;function JV(t){let e=\"\";if(t===null||typeof t!=\"object\"||t.toJSON!=null)e+=JSON.stringify(t);else if(Array.isArray(t)){e+=\"[\";let r=!0;t.forEach(s=>{r||(e+=\",\"),r=!1,e+=JV(s)}),e+=\"]\"}else{e+=\"{\";let r=!0;Object.keys(t).sort().forEach(s=>{r||(e+=\",\"),r=!1,e+=JSON.stringify(s),e+=\":\",e+=JV(t[s])}),e+=\"}\"}return e}});var zV=_(uO=>{\"use strict\";Object.defineProperty(uO,\"__esModule\",{value:!0});uO.toDER=oCt;uO.fromDER=aCt;var iCt=/-----BEGIN (.*)-----/,sCt=/-----END (.*)-----/;function oCt(t){let e=\"\";return t.split(`\n`).forEach(r=>{r.match(iCt)||r.match(sCt)||(e+=r)}),Buffer.from(e,\"base64\")}function aCt(t,e=\"CERTIFICATE\"){let s=t.toString(\"base64\").match(/.{1,64}/g)||\"\";return[`-----BEGIN ${e}-----`,...s,`-----END ${e}-----`].join(`\n`).concat(`\n`)}});var fO=_(zw=>{\"use strict\";Object.defineProperty(zw,\"__esModule\",{value:!0});zw.SHA2_HASH_ALGOS=zw.ECDSA_SIGNATURE_ALGOS=void 0;zw.ECDSA_SIGNATURE_ALGOS={\"1.2.840.10045.4.3.1\":\"sha224\",\"1.2.840.10045.4.3.2\":\"sha256\",\"1.2.840.10045.4.3.3\":\"sha384\",\"1.2.840.10045.4.3.4\":\"sha512\"};zw.SHA2_HASH_ALGOS={\"2.16.840.1.101.3.4.2.1\":\"sha256\",\"2.16.840.1.101.3.4.2.2\":\"sha384\",\"2.16.840.1.101.3.4.2.3\":\"sha512\"}});var XV=_(AO=>{\"use strict\";Object.defineProperty(AO,\"__esModule\",{value:!0});AO.RFC3161TimestampVerificationError=void 0;var ZV=class extends Error{};AO.RFC3161TimestampVerificationError=ZV});var BDe=_(vA=>{\"use strict\";var lCt=vA&&vA.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||(\"get\"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),cCt=vA&&vA.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),uCt=vA&&vA.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.prototype.hasOwnProperty.call(t,r)&&lCt(e,t,r);return cCt(e,t),e};Object.defineProperty(vA,\"__esModule\",{value:!0});vA.TSTInfo=void 0;var wDe=uCt(Kw()),fCt=fO(),ACt=XV(),$V=class{constructor(e){this.root=e}get version(){return this.root.subs[0].toInteger()}get genTime(){return this.root.subs[4].toDate()}get messageImprintHashAlgorithm(){let e=this.messageImprintObj.subs[0].subs[0].toOID();return fCt.SHA2_HASH_ALGOS[e]}get messageImprintHashedMessage(){return this.messageImprintObj.subs[1].value}get raw(){return this.root.toDER()}verify(e){let r=wDe.digest(this.messageImprintHashAlgorithm,e);if(!wDe.bufferEqual(r,this.messageImprintHashedMessage))throw new ACt.RFC3161TimestampVerificationError(\"message imprint does not match artifact\")}get messageImprintObj(){return this.root.subs[2]}};vA.TSTInfo=$V});var SDe=_(SA=>{\"use strict\";var pCt=SA&&SA.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||(\"get\"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),hCt=SA&&SA.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),gCt=SA&&SA.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.prototype.hasOwnProperty.call(t,r)&&pCt(e,t,r);return hCt(e,t),e};Object.defineProperty(SA,\"__esModule\",{value:!0});SA.RFC3161Timestamp=void 0;var dCt=lO(),e7=gCt(Kw()),vDe=fO(),wP=XV(),mCt=BDe(),yCt=\"1.2.840.113549.1.7.2\",ECt=\"1.2.840.113549.1.9.16.1.4\",ICt=\"1.2.840.113549.1.9.4\",t7=class t{constructor(e){this.root=e}static parse(e){let r=dCt.ASN1Obj.parseBuffer(e);return new t(r)}get status(){return this.pkiStatusInfoObj.subs[0].toInteger()}get contentType(){return this.contentTypeObj.toOID()}get eContentType(){return this.eContentTypeObj.toOID()}get signingTime(){return this.tstInfo.genTime}get signerIssuer(){return this.signerSidObj.subs[0].value}get signerSerialNumber(){return this.signerSidObj.subs[1].value}get signerDigestAlgorithm(){let e=this.signerDigestAlgorithmObj.subs[0].toOID();return vDe.SHA2_HASH_ALGOS[e]}get signatureAlgorithm(){let e=this.signatureAlgorithmObj.subs[0].toOID();return vDe.ECDSA_SIGNATURE_ALGOS[e]}get signatureValue(){return this.signatureValueObj.value}get tstInfo(){return new mCt.TSTInfo(this.eContentObj.subs[0].subs[0])}verify(e,r){if(!this.timeStampTokenObj)throw new wP.RFC3161TimestampVerificationError(\"timeStampToken is missing\");if(this.contentType!==yCt)throw new wP.RFC3161TimestampVerificationError(`incorrect content type: ${this.contentType}`);if(this.eContentType!==ECt)throw new wP.RFC3161TimestampVerificationError(`incorrect encapsulated content type: ${this.eContentType}`);this.tstInfo.verify(e),this.verifyMessageDigest(),this.verifySignature(r)}verifyMessageDigest(){let e=e7.digest(this.signerDigestAlgorithm,this.tstInfo.raw),r=this.messageDigestAttributeObj.subs[1].subs[0].value;if(!e7.bufferEqual(e,r))throw new wP.RFC3161TimestampVerificationError(\"signed data does not match tstInfo\")}verifySignature(e){let r=this.signedAttrsObj.toDER();if(r[0]=49,!e7.verify(r,e,this.signatureValue,this.signatureAlgorithm))throw new wP.RFC3161TimestampVerificationError(\"signature verification failed\")}get pkiStatusInfoObj(){return this.root.subs[0]}get timeStampTokenObj(){return this.root.subs[1]}get contentTypeObj(){return this.timeStampTokenObj.subs[0]}get signedDataObj(){return this.timeStampTokenObj.subs.find(r=>r.tag.isContextSpecific(0)).subs[0]}get encapContentInfoObj(){return this.signedDataObj.subs[2]}get signerInfosObj(){let e=this.signedDataObj;return e.subs[e.subs.length-1]}get signerInfoObj(){return this.signerInfosObj.subs[0]}get eContentTypeObj(){return this.encapContentInfoObj.subs[0]}get eContentObj(){return this.encapContentInfoObj.subs[1]}get signedAttrsObj(){return this.signerInfoObj.subs.find(r=>r.tag.isContextSpecific(0))}get messageDigestAttributeObj(){return this.signedAttrsObj.subs.find(r=>r.subs[0].tag.isOID()&&r.subs[0].toOID()===ICt)}get signerSidObj(){return this.signerInfoObj.subs[1]}get signerDigestAlgorithmObj(){return this.signerInfoObj.subs[2]}get signatureAlgorithmObj(){return this.signerInfoObj.subs[4]}get signatureValueObj(){return this.signerInfoObj.subs[5]}};SA.RFC3161Timestamp=t7});var DDe=_(pO=>{\"use strict\";Object.defineProperty(pO,\"__esModule\",{value:!0});pO.RFC3161Timestamp=void 0;var CCt=SDe();Object.defineProperty(pO,\"RFC3161Timestamp\",{enumerable:!0,get:function(){return CCt.RFC3161Timestamp}})});var bDe=_(DA=>{\"use strict\";var wCt=DA&&DA.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||(\"get\"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),BCt=DA&&DA.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),vCt=DA&&DA.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.prototype.hasOwnProperty.call(t,r)&&wCt(e,t,r);return BCt(e,t),e};Object.defineProperty(DA,\"__esModule\",{value:!0});DA.SignedCertificateTimestamp=void 0;var SCt=vCt(Kw()),PDe=IP(),r7=class t{constructor(e){this.version=e.version,this.logID=e.logID,this.timestamp=e.timestamp,this.extensions=e.extensions,this.hashAlgorithm=e.hashAlgorithm,this.signatureAlgorithm=e.signatureAlgorithm,this.signature=e.signature}get datetime(){return new Date(Number(this.timestamp.readBigInt64BE()))}get algorithm(){switch(this.hashAlgorithm){case 0:return\"none\";case 1:return\"md5\";case 2:return\"sha1\";case 3:return\"sha224\";case 4:return\"sha256\";case 5:return\"sha384\";case 6:return\"sha512\";default:return\"unknown\"}}verify(e,r){let s=new PDe.ByteStream;return s.appendChar(this.version),s.appendChar(0),s.appendView(this.timestamp),s.appendUint16(1),s.appendView(e),s.appendUint16(this.extensions.byteLength),this.extensions.byteLength>0&&s.appendView(this.extensions),SCt.verify(s.buffer,r,this.signature,this.algorithm)}static parse(e){let r=new PDe.ByteStream(e),s=r.getUint8(),a=r.getBlock(32),n=r.getBlock(8),c=r.getUint16(),f=r.getBlock(c),p=r.getUint8(),h=r.getUint8(),E=r.getUint16(),C=r.getBlock(E);if(r.position!==e.length)throw new Error(\"SCT buffer length mismatch\");return new t({version:s,logID:a,timestamp:n,extensions:f,hashAlgorithm:p,signatureAlgorithm:h,signature:C})}};DA.SignedCertificateTimestamp=r7});var c7=_(sa=>{\"use strict\";Object.defineProperty(sa,\"__esModule\",{value:!0});sa.X509SCTExtension=sa.X509SubjectKeyIDExtension=sa.X509AuthorityKeyIDExtension=sa.X509SubjectAlternativeNameExtension=sa.X509KeyUsageExtension=sa.X509BasicConstraintsExtension=sa.X509Extension=void 0;var DCt=IP(),PCt=bDe(),ph=class{constructor(e){this.root=e}get oid(){return this.root.subs[0].toOID()}get critical(){return this.root.subs.length===3?this.root.subs[1].toBoolean():!1}get value(){return this.extnValueObj.value}get valueObj(){return this.extnValueObj}get extnValueObj(){return this.root.subs[this.root.subs.length-1]}};sa.X509Extension=ph;var n7=class extends ph{get isCA(){return this.sequence.subs[0]?.toBoolean()??!1}get pathLenConstraint(){return this.sequence.subs.length>1?this.sequence.subs[1].toInteger():void 0}get sequence(){return this.extnValueObj.subs[0]}};sa.X509BasicConstraintsExtension=n7;var i7=class extends ph{get digitalSignature(){return this.bitString[0]===1}get keyCertSign(){return this.bitString[5]===1}get crlSign(){return this.bitString[6]===1}get bitString(){return this.extnValueObj.subs[0].toBitString()}};sa.X509KeyUsageExtension=i7;var s7=class extends ph{get rfc822Name(){return this.findGeneralName(1)?.value.toString(\"ascii\")}get uri(){return this.findGeneralName(6)?.value.toString(\"ascii\")}otherName(e){let r=this.findGeneralName(0);return r===void 0||r.subs[0].toOID()!==e?void 0:r.subs[1].subs[0].value.toString(\"ascii\")}findGeneralName(e){return this.generalNames.find(r=>r.tag.isContextSpecific(e))}get generalNames(){return this.extnValueObj.subs[0].subs}};sa.X509SubjectAlternativeNameExtension=s7;var o7=class extends ph{get keyIdentifier(){return this.findSequenceMember(0)?.value}findSequenceMember(e){return this.sequence.subs.find(r=>r.tag.isContextSpecific(e))}get sequence(){return this.extnValueObj.subs[0]}};sa.X509AuthorityKeyIDExtension=o7;var a7=class extends ph{get keyIdentifier(){return this.extnValueObj.subs[0].value}};sa.X509SubjectKeyIDExtension=a7;var l7=class extends ph{constructor(e){super(e)}get signedCertificateTimestamps(){let e=this.extnValueObj.subs[0].value,r=new DCt.ByteStream(e),s=r.getUint16()+2,a=[];for(;r.position<s;){let n=r.getUint16(),c=r.getBlock(n);a.push(PCt.SignedCertificateTimestamp.parse(c))}if(r.position!==s)throw new Error(\"SCT list length does not match actual length\");return a}};sa.X509SCTExtension=l7});var QDe=_(ic=>{\"use strict\";var bCt=ic&&ic.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||(\"get\"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),xCt=ic&&ic.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),kDe=ic&&ic.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.prototype.hasOwnProperty.call(t,r)&&bCt(e,t,r);return xCt(e,t),e};Object.defineProperty(ic,\"__esModule\",{value:!0});ic.X509Certificate=ic.EXTENSION_OID_SCT=void 0;var kCt=lO(),xDe=kDe(Kw()),QCt=fO(),RCt=kDe(zV()),ny=c7(),TCt=\"2.5.29.14\",FCt=\"2.5.29.15\",NCt=\"2.5.29.17\",OCt=\"2.5.29.19\",LCt=\"2.5.29.35\";ic.EXTENSION_OID_SCT=\"1.3.6.1.4.1.11129.2.4.2\";var u7=class t{constructor(e){this.root=e}static parse(e){let r=typeof e==\"string\"?RCt.toDER(e):e,s=kCt.ASN1Obj.parseBuffer(r);return new t(s)}get tbsCertificate(){return this.tbsCertificateObj}get version(){return`v${(this.versionObj.subs[0].toInteger()+BigInt(1)).toString()}`}get serialNumber(){return this.serialNumberObj.value}get notBefore(){return this.validityObj.subs[0].toDate()}get notAfter(){return this.validityObj.subs[1].toDate()}get issuer(){return this.issuerObj.value}get subject(){return this.subjectObj.value}get publicKey(){return this.subjectPublicKeyInfoObj.toDER()}get signatureAlgorithm(){let e=this.signatureAlgorithmObj.subs[0].toOID();return QCt.ECDSA_SIGNATURE_ALGOS[e]}get signatureValue(){return this.signatureValueObj.value.subarray(1)}get subjectAltName(){let e=this.extSubjectAltName;return e?.uri||e?.rfc822Name}get extensions(){return this.extensionsObj?.subs[0]?.subs||[]}get extKeyUsage(){let e=this.findExtension(FCt);return e?new ny.X509KeyUsageExtension(e):void 0}get extBasicConstraints(){let e=this.findExtension(OCt);return e?new ny.X509BasicConstraintsExtension(e):void 0}get extSubjectAltName(){let e=this.findExtension(NCt);return e?new ny.X509SubjectAlternativeNameExtension(e):void 0}get extAuthorityKeyID(){let e=this.findExtension(LCt);return e?new ny.X509AuthorityKeyIDExtension(e):void 0}get extSubjectKeyID(){let e=this.findExtension(TCt);return e?new ny.X509SubjectKeyIDExtension(e):void 0}get extSCT(){let e=this.findExtension(ic.EXTENSION_OID_SCT);return e?new ny.X509SCTExtension(e):void 0}get isCA(){let e=this.extBasicConstraints?.isCA||!1;return this.extKeyUsage?e&&this.extKeyUsage.keyCertSign:e}extension(e){let r=this.findExtension(e);return r?new ny.X509Extension(r):void 0}verify(e){let r=e?.publicKey||this.publicKey,s=xDe.createPublicKey(r);return xDe.verify(this.tbsCertificate.toDER(),s,this.signatureValue,this.signatureAlgorithm)}validForDate(e){return this.notBefore<=e&&e<=this.notAfter}equals(e){return this.root.toDER().equals(e.root.toDER())}clone(){let e=this.root.toDER(),r=Buffer.alloc(e.length);return e.copy(r),t.parse(r)}findExtension(e){return this.extensions.find(r=>r.subs[0].toOID()===e)}get tbsCertificateObj(){return this.root.subs[0]}get signatureAlgorithmObj(){return this.root.subs[1]}get signatureValueObj(){return this.root.subs[2]}get versionObj(){return this.tbsCertificateObj.subs[0]}get serialNumberObj(){return this.tbsCertificateObj.subs[1]}get issuerObj(){return this.tbsCertificateObj.subs[3]}get validityObj(){return this.tbsCertificateObj.subs[4]}get subjectObj(){return this.tbsCertificateObj.subs[5]}get subjectPublicKeyInfoObj(){return this.tbsCertificateObj.subs[6]}get extensionsObj(){return this.tbsCertificateObj.subs.find(e=>e.tag.isContextSpecific(3))}};ic.X509Certificate=u7});var TDe=_(Bg=>{\"use strict\";Object.defineProperty(Bg,\"__esModule\",{value:!0});Bg.X509SCTExtension=Bg.X509Certificate=Bg.EXTENSION_OID_SCT=void 0;var RDe=QDe();Object.defineProperty(Bg,\"EXTENSION_OID_SCT\",{enumerable:!0,get:function(){return RDe.EXTENSION_OID_SCT}});Object.defineProperty(Bg,\"X509Certificate\",{enumerable:!0,get:function(){return RDe.X509Certificate}});var MCt=c7();Object.defineProperty(Bg,\"X509SCTExtension\",{enumerable:!0,get:function(){return MCt.X509SCTExtension}})});var Cl=_(Jn=>{\"use strict\";var UCt=Jn&&Jn.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||(\"get\"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),_Ct=Jn&&Jn.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),BP=Jn&&Jn.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.prototype.hasOwnProperty.call(t,r)&&UCt(e,t,r);return _Ct(e,t),e};Object.defineProperty(Jn,\"__esModule\",{value:!0});Jn.X509SCTExtension=Jn.X509Certificate=Jn.EXTENSION_OID_SCT=Jn.ByteStream=Jn.RFC3161Timestamp=Jn.pem=Jn.json=Jn.encoding=Jn.dsse=Jn.crypto=Jn.ASN1Obj=void 0;var HCt=lO();Object.defineProperty(Jn,\"ASN1Obj\",{enumerable:!0,get:function(){return HCt.ASN1Obj}});Jn.crypto=BP(Kw());Jn.dsse=BP(mDe());Jn.encoding=BP(IDe());Jn.json=BP(CDe());Jn.pem=BP(zV());var jCt=DDe();Object.defineProperty(Jn,\"RFC3161Timestamp\",{enumerable:!0,get:function(){return jCt.RFC3161Timestamp}});var GCt=IP();Object.defineProperty(Jn,\"ByteStream\",{enumerable:!0,get:function(){return GCt.ByteStream}});var f7=TDe();Object.defineProperty(Jn,\"EXTENSION_OID_SCT\",{enumerable:!0,get:function(){return f7.EXTENSION_OID_SCT}});Object.defineProperty(Jn,\"X509Certificate\",{enumerable:!0,get:function(){return f7.X509Certificate}});Object.defineProperty(Jn,\"X509SCTExtension\",{enumerable:!0,get:function(){return f7.X509SCTExtension}})});var FDe=_(A7=>{\"use strict\";Object.defineProperty(A7,\"__esModule\",{value:!0});A7.extractJWTSubject=WCt;var qCt=Cl();function WCt(t){let e=t.split(\".\",3),r=JSON.parse(qCt.encoding.base64Decode(e[1]));switch(r.iss){case\"https://accounts.google.com\":case\"https://oauth2.sigstore.dev/auth\":return r.email;default:return r.sub}}});var NDe=_((Zrr,YCt)=>{YCt.exports={name:\"@sigstore/sign\",version:\"3.1.0\",description:\"Sigstore signing library\",main:\"dist/index.js\",types:\"dist/index.d.ts\",scripts:{clean:\"shx rm -rf dist *.tsbuildinfo\",build:\"tsc --build\",test:\"jest\"},files:[\"dist\"],author:\"bdehamer@github.com\",license:\"Apache-2.0\",repository:{type:\"git\",url:\"git+https://github.com/sigstore/sigstore-js.git\"},bugs:{url:\"https://github.com/sigstore/sigstore-js/issues\"},homepage:\"https://github.com/sigstore/sigstore-js/tree/main/packages/sign#readme\",publishConfig:{provenance:!0},devDependencies:{\"@sigstore/jest\":\"^0.0.0\",\"@sigstore/mock\":\"^0.10.0\",\"@sigstore/rekor-types\":\"^3.0.0\",\"@types/make-fetch-happen\":\"^10.0.4\",\"@types/promise-retry\":\"^1.1.6\"},dependencies:{\"@sigstore/bundle\":\"^3.1.0\",\"@sigstore/core\":\"^2.0.0\",\"@sigstore/protobuf-specs\":\"^0.4.0\",\"make-fetch-happen\":\"^14.0.2\",\"proc-log\":\"^5.0.0\",\"promise-retry\":\"^2.0.1\"},engines:{node:\"^18.17.0 || >=20.5.0\"}}});var LDe=_(Zw=>{\"use strict\";var VCt=Zw&&Zw.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(Zw,\"__esModule\",{value:!0});Zw.getUserAgent=void 0;var ODe=VCt(Ie(\"os\")),JCt=()=>{let t=NDe().version,e=process.version,r=ODe.default.platform(),s=ODe.default.arch();return`sigstore-js/${t} (Node ${e}) (${r}/${s})`};Zw.getUserAgent=JCt});var vg=_(Vi=>{\"use strict\";var KCt=Vi&&Vi.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||(\"get\"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),zCt=Vi&&Vi.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),MDe=Vi&&Vi.__importStar||function(){var t=function(e){return t=Object.getOwnPropertyNames||function(r){var s=[];for(var a in r)Object.prototype.hasOwnProperty.call(r,a)&&(s[s.length]=a);return s},t(e)};return function(e){if(e&&e.__esModule)return e;var r={};if(e!=null)for(var s=t(e),a=0;a<s.length;a++)s[a]!==\"default\"&&KCt(r,e,s[a]);return zCt(r,e),r}}();Object.defineProperty(Vi,\"__esModule\",{value:!0});Vi.ua=Vi.oidc=Vi.pem=Vi.json=Vi.encoding=Vi.dsse=Vi.crypto=void 0;var vP=Cl();Object.defineProperty(Vi,\"crypto\",{enumerable:!0,get:function(){return vP.crypto}});Object.defineProperty(Vi,\"dsse\",{enumerable:!0,get:function(){return vP.dsse}});Object.defineProperty(Vi,\"encoding\",{enumerable:!0,get:function(){return vP.encoding}});Object.defineProperty(Vi,\"json\",{enumerable:!0,get:function(){return vP.json}});Object.defineProperty(Vi,\"pem\",{enumerable:!0,get:function(){return vP.pem}});Vi.oidc=MDe(FDe());Vi.ua=MDe(LDe())});var h7=_(hO=>{\"use strict\";Object.defineProperty(hO,\"__esModule\",{value:!0});hO.BaseBundleBuilder=void 0;var p7=class{constructor(e){this.signer=e.signer,this.witnesses=e.witnesses}async create(e){let r=await this.prepare(e).then(f=>this.signer.sign(f)),s=await this.package(e,r),a=await Promise.all(this.witnesses.map(f=>f.testify(s.content,ZCt(r.key)))),n=[],c=[];return a.forEach(({tlogEntries:f,rfc3161Timestamps:p})=>{n.push(...f??[]),c.push(...p??[])}),s.verificationMaterial.tlogEntries=n,s.verificationMaterial.timestampVerificationData={rfc3161Timestamps:c},s}async prepare(e){return e.data}};hO.BaseBundleBuilder=p7;function ZCt(t){switch(t.$case){case\"publicKey\":return t.publicKey;case\"x509Certificate\":return t.certificate}}});var d7=_(PA=>{\"use strict\";var XCt=PA&&PA.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||(\"get\"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),$Ct=PA&&PA.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),ewt=PA&&PA.__importStar||function(){var t=function(e){return t=Object.getOwnPropertyNames||function(r){var s=[];for(var a in r)Object.prototype.hasOwnProperty.call(r,a)&&(s[s.length]=a);return s},t(e)};return function(e){if(e&&e.__esModule)return e;var r={};if(e!=null)for(var s=t(e),a=0;a<s.length;a++)s[a]!==\"default\"&&XCt(r,e,s[a]);return $Ct(r,e),r}}();Object.defineProperty(PA,\"__esModule\",{value:!0});PA.toMessageSignatureBundle=twt;PA.toDSSEBundle=rwt;var UDe=ewt(EP()),g7=vg();function twt(t,e){let r=g7.crypto.digest(\"sha256\",t.data);return UDe.toMessageSignatureBundle({digest:r,signature:e.signature,certificate:e.key.$case===\"x509Certificate\"?g7.pem.toDER(e.key.certificate):void 0,keyHint:e.key.$case===\"publicKey\"?e.key.hint:void 0,certificateChain:!0})}function rwt(t,e,r){return UDe.toDSSEBundle({artifact:t.data,artifactType:t.type,signature:e.signature,certificate:e.key.$case===\"x509Certificate\"?g7.pem.toDER(e.key.certificate):void 0,keyHint:e.key.$case===\"publicKey\"?e.key.hint:void 0,certificateChain:r})}});var HDe=_(gO=>{\"use strict\";Object.defineProperty(gO,\"__esModule\",{value:!0});gO.DSSEBundleBuilder=void 0;var nwt=vg(),iwt=h7(),swt=d7(),m7=class extends iwt.BaseBundleBuilder{constructor(e){super(e),this.certificateChain=e.certificateChain??!1}async prepare(e){let r=_De(e);return nwt.dsse.preAuthEncoding(r.type,r.data)}async package(e,r){return(0,swt.toDSSEBundle)(_De(e),r,this.certificateChain)}};gO.DSSEBundleBuilder=m7;function _De(t){return{...t,type:t.type??\"\"}}});var jDe=_(dO=>{\"use strict\";Object.defineProperty(dO,\"__esModule\",{value:!0});dO.MessageSignatureBundleBuilder=void 0;var owt=h7(),awt=d7(),y7=class extends owt.BaseBundleBuilder{constructor(e){super(e)}async package(e,r){return(0,awt.toMessageSignatureBundle)(e,r)}};dO.MessageSignatureBundleBuilder=y7});var GDe=_(Xw=>{\"use strict\";Object.defineProperty(Xw,\"__esModule\",{value:!0});Xw.MessageSignatureBundleBuilder=Xw.DSSEBundleBuilder=void 0;var lwt=HDe();Object.defineProperty(Xw,\"DSSEBundleBuilder\",{enumerable:!0,get:function(){return lwt.DSSEBundleBuilder}});var cwt=jDe();Object.defineProperty(Xw,\"MessageSignatureBundleBuilder\",{enumerable:!0,get:function(){return cwt.MessageSignatureBundleBuilder}})});var yO=_(mO=>{\"use strict\";Object.defineProperty(mO,\"__esModule\",{value:!0});mO.HTTPError=void 0;var E7=class extends Error{constructor({status:e,message:r,location:s}){super(`(${e}) ${r}`),this.statusCode=e,this.location=s}};mO.HTTPError=E7});var $w=_(SP=>{\"use strict\";Object.defineProperty(SP,\"__esModule\",{value:!0});SP.InternalError=void 0;SP.internalError=fwt;var uwt=yO(),EO=class extends Error{constructor({code:e,message:r,cause:s}){super(r),this.name=this.constructor.name,this.cause=s,this.code=e}};SP.InternalError=EO;function fwt(t,e,r){throw t instanceof uwt.HTTPError&&(r+=` - ${t.message}`),new EO({code:e,message:r,cause:t})}});var IO=_((anr,qDe)=>{qDe.exports=fetch});var WDe=_(e1=>{\"use strict\";var Awt=e1&&e1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e1,\"__esModule\",{value:!0});e1.CIContextProvider=void 0;var pwt=Awt(IO()),hwt=[gwt,dwt],I7=class{constructor(e=\"sigstore\"){this.audience=e}async getToken(){return Promise.any(hwt.map(e=>e(this.audience))).catch(()=>Promise.reject(\"CI: no tokens available\"))}};e1.CIContextProvider=I7;async function gwt(t){if(!process.env.ACTIONS_ID_TOKEN_REQUEST_URL||!process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN)return Promise.reject(\"no token available\");let e=new URL(process.env.ACTIONS_ID_TOKEN_REQUEST_URL);return e.searchParams.append(\"audience\",t),(await(0,pwt.default)(e.href,{retry:2,headers:{Accept:\"application/json\",Authorization:`Bearer ${process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN}`}})).json().then(s=>s.value)}async function dwt(){return process.env.SIGSTORE_ID_TOKEN?process.env.SIGSTORE_ID_TOKEN:Promise.reject(\"no token available\")}});var YDe=_(CO=>{\"use strict\";Object.defineProperty(CO,\"__esModule\",{value:!0});CO.CIContextProvider=void 0;var mwt=WDe();Object.defineProperty(CO,\"CIContextProvider\",{enumerable:!0,get:function(){return mwt.CIContextProvider}})});var JDe=_((unr,VDe)=>{var ywt=Symbol(\"proc-log.meta\");VDe.exports={META:ywt,output:{LEVELS:[\"standard\",\"error\",\"buffer\",\"flush\"],KEYS:{standard:\"standard\",error:\"error\",buffer:\"buffer\",flush:\"flush\"},standard:function(...t){return process.emit(\"output\",\"standard\",...t)},error:function(...t){return process.emit(\"output\",\"error\",...t)},buffer:function(...t){return process.emit(\"output\",\"buffer\",...t)},flush:function(...t){return process.emit(\"output\",\"flush\",...t)}},log:{LEVELS:[\"notice\",\"error\",\"warn\",\"info\",\"verbose\",\"http\",\"silly\",\"timing\",\"pause\",\"resume\"],KEYS:{notice:\"notice\",error:\"error\",warn:\"warn\",info:\"info\",verbose:\"verbose\",http:\"http\",silly:\"silly\",timing:\"timing\",pause:\"pause\",resume:\"resume\"},error:function(...t){return process.emit(\"log\",\"error\",...t)},notice:function(...t){return process.emit(\"log\",\"notice\",...t)},warn:function(...t){return process.emit(\"log\",\"warn\",...t)},info:function(...t){return process.emit(\"log\",\"info\",...t)},verbose:function(...t){return process.emit(\"log\",\"verbose\",...t)},http:function(...t){return process.emit(\"log\",\"http\",...t)},silly:function(...t){return process.emit(\"log\",\"silly\",...t)},timing:function(...t){return process.emit(\"log\",\"timing\",...t)},pause:function(){return process.emit(\"log\",\"pause\")},resume:function(){return process.emit(\"log\",\"resume\")}},time:{LEVELS:[\"start\",\"end\"],KEYS:{start:\"start\",end:\"end\"},start:function(t,e){process.emit(\"time\",\"start\",t);function r(){return process.emit(\"time\",\"end\",t)}if(typeof e==\"function\"){let s=e();return s&&s.finally?s.finally(r):(r(),s)}return r},end:function(t){return process.emit(\"time\",\"end\",t)}},input:{LEVELS:[\"start\",\"end\",\"read\"],KEYS:{start:\"start\",end:\"end\",read:\"read\"},start:function(t){process.emit(\"input\",\"start\");function e(){return process.emit(\"input\",\"end\")}if(typeof t==\"function\"){let r=t();return r&&r.finally?r.finally(e):(e(),r)}return e},end:function(){return process.emit(\"input\",\"end\")},read:function(...t){let e,r,s=new Promise((a,n)=>{e=a,r=n});return process.emit(\"input\",\"read\",e,r,...t),s}}}});var ZDe=_((fnr,zDe)=>{\"use strict\";function KDe(t,e){for(let r in e)Object.defineProperty(t,r,{value:e[r],enumerable:!0,configurable:!0});return t}function Ewt(t,e,r){if(!t||typeof t==\"string\")throw new TypeError(\"Please pass an Error to err-code\");r||(r={}),typeof e==\"object\"&&(r=e,e=void 0),e!=null&&(r.code=e);try{return KDe(t,r)}catch{r.message=t.message,r.stack=t.stack;let a=function(){};return a.prototype=Object.create(Object.getPrototypeOf(t)),KDe(new a,r)}}zDe.exports=Ewt});var $De=_((Anr,XDe)=>{function $c(t,e){typeof e==\"boolean\"&&(e={forever:e}),this._originalTimeouts=JSON.parse(JSON.stringify(t)),this._timeouts=t,this._options=e||{},this._maxRetryTime=e&&e.maxRetryTime||1/0,this._fn=null,this._errors=[],this._attempts=1,this._operationTimeout=null,this._operationTimeoutCb=null,this._timeout=null,this._operationStart=null,this._options.forever&&(this._cachedTimeouts=this._timeouts.slice(0))}XDe.exports=$c;$c.prototype.reset=function(){this._attempts=1,this._timeouts=this._originalTimeouts};$c.prototype.stop=function(){this._timeout&&clearTimeout(this._timeout),this._timeouts=[],this._cachedTimeouts=null};$c.prototype.retry=function(t){if(this._timeout&&clearTimeout(this._timeout),!t)return!1;var e=new Date().getTime();if(t&&e-this._operationStart>=this._maxRetryTime)return this._errors.unshift(new Error(\"RetryOperation timeout occurred\")),!1;this._errors.push(t);var r=this._timeouts.shift();if(r===void 0)if(this._cachedTimeouts)this._errors.splice(this._errors.length-1,this._errors.length),this._timeouts=this._cachedTimeouts.slice(0),r=this._timeouts.shift();else return!1;var s=this,a=setTimeout(function(){s._attempts++,s._operationTimeoutCb&&(s._timeout=setTimeout(function(){s._operationTimeoutCb(s._attempts)},s._operationTimeout),s._options.unref&&s._timeout.unref()),s._fn(s._attempts)},r);return this._options.unref&&a.unref(),!0};$c.prototype.attempt=function(t,e){this._fn=t,e&&(e.timeout&&(this._operationTimeout=e.timeout),e.cb&&(this._operationTimeoutCb=e.cb));var r=this;this._operationTimeoutCb&&(this._timeout=setTimeout(function(){r._operationTimeoutCb()},r._operationTimeout)),this._operationStart=new Date().getTime(),this._fn(this._attempts)};$c.prototype.try=function(t){console.log(\"Using RetryOperation.try() is deprecated\"),this.attempt(t)};$c.prototype.start=function(t){console.log(\"Using RetryOperation.start() is deprecated\"),this.attempt(t)};$c.prototype.start=$c.prototype.try;$c.prototype.errors=function(){return this._errors};$c.prototype.attempts=function(){return this._attempts};$c.prototype.mainError=function(){if(this._errors.length===0)return null;for(var t={},e=null,r=0,s=0;s<this._errors.length;s++){var a=this._errors[s],n=a.message,c=(t[n]||0)+1;t[n]=c,c>=r&&(e=a,r=c)}return e}});var ePe=_(iy=>{var Iwt=$De();iy.operation=function(t){var e=iy.timeouts(t);return new Iwt(e,{forever:t&&t.forever,unref:t&&t.unref,maxRetryTime:t&&t.maxRetryTime})};iy.timeouts=function(t){if(t instanceof Array)return[].concat(t);var e={retries:10,factor:2,minTimeout:1*1e3,maxTimeout:1/0,randomize:!1};for(var r in t)e[r]=t[r];if(e.minTimeout>e.maxTimeout)throw new Error(\"minTimeout is greater than maxTimeout\");for(var s=[],a=0;a<e.retries;a++)s.push(this.createTimeout(a,e));return t&&t.forever&&!s.length&&s.push(this.createTimeout(a,e)),s.sort(function(n,c){return n-c}),s};iy.createTimeout=function(t,e){var r=e.randomize?Math.random()+1:1,s=Math.round(r*e.minTimeout*Math.pow(e.factor,t));return s=Math.min(s,e.maxTimeout),s};iy.wrap=function(t,e,r){if(e instanceof Array&&(r=e,e=null),!r){r=[];for(var s in t)typeof t[s]==\"function\"&&r.push(s)}for(var a=0;a<r.length;a++){var n=r[a],c=t[n];t[n]=function(p){var h=iy.operation(e),E=Array.prototype.slice.call(arguments,1),C=E.pop();E.push(function(S){h.retry(S)||(S&&(arguments[0]=h.mainError()),C.apply(this,arguments))}),h.attempt(function(){p.apply(t,E)})}.bind(t,c),t[n].options=e}}});var rPe=_((hnr,tPe)=>{tPe.exports=ePe()});var sPe=_((gnr,iPe)=>{\"use strict\";var Cwt=ZDe(),wwt=rPe(),Bwt=Object.prototype.hasOwnProperty;function nPe(t){return t&&t.code===\"EPROMISERETRY\"&&Bwt.call(t,\"retried\")}function vwt(t,e){var r,s;return typeof t==\"object\"&&typeof e==\"function\"&&(r=e,e=t,t=r),s=wwt.operation(e),new Promise(function(a,n){s.attempt(function(c){Promise.resolve().then(function(){return t(function(f){throw nPe(f)&&(f=f.retried),Cwt(new Error(\"Retrying\"),\"EPROMISERETRY\",{retried:f})},c)}).then(a,function(f){nPe(f)&&(f=f.retried,s.retry(f||new Error))||n(f)})})})}iPe.exports=vwt});var wO=_(DP=>{\"use strict\";var aPe=DP&&DP.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(DP,\"__esModule\",{value:!0});DP.fetchWithRetry=Owt;var Swt=Ie(\"http2\"),Dwt=aPe(IO()),oPe=JDe(),Pwt=aPe(sPe()),bwt=vg(),xwt=yO(),{HTTP2_HEADER_LOCATION:kwt,HTTP2_HEADER_CONTENT_TYPE:Qwt,HTTP2_HEADER_USER_AGENT:Rwt,HTTP_STATUS_INTERNAL_SERVER_ERROR:Twt,HTTP_STATUS_TOO_MANY_REQUESTS:Fwt,HTTP_STATUS_REQUEST_TIMEOUT:Nwt}=Swt.constants;async function Owt(t,e){return(0,Pwt.default)(async(r,s)=>{let a=e.method||\"POST\",n={[Rwt]:bwt.ua.getUserAgent(),...e.headers},c=await(0,Dwt.default)(t,{method:a,headers:n,body:e.body,timeout:e.timeout,retry:!1}).catch(f=>(oPe.log.http(\"fetch\",`${a} ${t} attempt ${s} failed with ${f}`),r(f)));if(c.ok)return c;{let f=await Lwt(c);if(oPe.log.http(\"fetch\",`${a} ${t} attempt ${s} failed with ${c.status}`),Mwt(c.status))return r(f);throw f}},Uwt(e.retry))}var Lwt=async t=>{let e=t.statusText,r=t.headers.get(kwt)||void 0;if(t.headers.get(Qwt)?.includes(\"application/json\"))try{e=(await t.json()).message||e}catch{}return new xwt.HTTPError({status:t.status,message:e,location:r})},Mwt=t=>[Nwt,Fwt].includes(t)||t>=Twt,Uwt=t=>typeof t==\"boolean\"?{retries:t?1:0}:typeof t==\"number\"?{retries:t}:{retries:0,...t}});var lPe=_(BO=>{\"use strict\";Object.defineProperty(BO,\"__esModule\",{value:!0});BO.Fulcio=void 0;var _wt=wO(),C7=class{constructor(e){this.options=e}async createSigningCertificate(e){let{baseURL:r,retry:s,timeout:a}=this.options,n=`${r}/api/v2/signingCert`;return(await(0,_wt.fetchWithRetry)(n,{headers:{\"Content-Type\":\"application/json\"},body:JSON.stringify(e),timeout:a,retry:s})).json()}};BO.Fulcio=C7});var cPe=_(vO=>{\"use strict\";Object.defineProperty(vO,\"__esModule\",{value:!0});vO.CAClient=void 0;var Hwt=$w(),jwt=lPe(),w7=class{constructor(e){this.fulcio=new jwt.Fulcio({baseURL:e.fulcioBaseURL,retry:e.retry,timeout:e.timeout})}async createSigningCertificate(e,r,s){let a=Gwt(e,r,s);try{let n=await this.fulcio.createSigningCertificate(a);return(n.signedCertificateEmbeddedSct?n.signedCertificateEmbeddedSct:n.signedCertificateDetachedSct).chain.certificates}catch(n){(0,Hwt.internalError)(n,\"CA_CREATE_SIGNING_CERTIFICATE_ERROR\",\"error creating signing certificate\")}}};vO.CAClient=w7;function Gwt(t,e,r){return{credentials:{oidcIdentityToken:t},publicKeyRequest:{publicKey:{algorithm:\"ECDSA\",content:e},proofOfPossession:r.toString(\"base64\")}}}});var fPe=_(t1=>{\"use strict\";var qwt=t1&&t1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(t1,\"__esModule\",{value:!0});t1.EphemeralSigner=void 0;var uPe=qwt(Ie(\"crypto\")),Wwt=\"ec\",Ywt=\"P-256\",B7=class{constructor(){this.keypair=uPe.default.generateKeyPairSync(Wwt,{namedCurve:Ywt})}async sign(e){let r=uPe.default.sign(null,e,this.keypair.privateKey),s=this.keypair.publicKey.export({format:\"pem\",type:\"spki\"}).toString(\"ascii\");return{signature:r,key:{$case:\"publicKey\",publicKey:s}}}};t1.EphemeralSigner=B7});var APe=_(sy=>{\"use strict\";Object.defineProperty(sy,\"__esModule\",{value:!0});sy.FulcioSigner=sy.DEFAULT_FULCIO_URL=void 0;var v7=$w(),Vwt=vg(),Jwt=cPe(),Kwt=fPe();sy.DEFAULT_FULCIO_URL=\"https://fulcio.sigstore.dev\";var S7=class{constructor(e){this.ca=new Jwt.CAClient({...e,fulcioBaseURL:e.fulcioBaseURL||sy.DEFAULT_FULCIO_URL}),this.identityProvider=e.identityProvider,this.keyHolder=e.keyHolder||new Kwt.EphemeralSigner}async sign(e){let r=await this.getIdentityToken(),s;try{s=Vwt.oidc.extractJWTSubject(r)}catch(f){throw new v7.InternalError({code:\"IDENTITY_TOKEN_PARSE_ERROR\",message:`invalid identity token: ${r}`,cause:f})}let a=await this.keyHolder.sign(Buffer.from(s));if(a.key.$case!==\"publicKey\")throw new v7.InternalError({code:\"CA_CREATE_SIGNING_CERTIFICATE_ERROR\",message:\"unexpected format for signing key\"});let n=await this.ca.createSigningCertificate(r,a.key.publicKey,a.signature);return{signature:(await this.keyHolder.sign(e)).signature,key:{$case:\"x509Certificate\",certificate:n[0]}}}async getIdentityToken(){try{return await this.identityProvider.getToken()}catch(e){throw new v7.InternalError({code:\"IDENTITY_TOKEN_READ_ERROR\",message:\"error retrieving identity token\",cause:e})}}};sy.FulcioSigner=S7});var hPe=_(r1=>{\"use strict\";Object.defineProperty(r1,\"__esModule\",{value:!0});r1.FulcioSigner=r1.DEFAULT_FULCIO_URL=void 0;var pPe=APe();Object.defineProperty(r1,\"DEFAULT_FULCIO_URL\",{enumerable:!0,get:function(){return pPe.DEFAULT_FULCIO_URL}});Object.defineProperty(r1,\"FulcioSigner\",{enumerable:!0,get:function(){return pPe.FulcioSigner}})});var mPe=_(SO=>{\"use strict\";Object.defineProperty(SO,\"__esModule\",{value:!0});SO.Rekor=void 0;var gPe=wO(),D7=class{constructor(e){this.options=e}async createEntry(e){let{baseURL:r,timeout:s,retry:a}=this.options,n=`${r}/api/v1/log/entries`,f=await(await(0,gPe.fetchWithRetry)(n,{headers:{\"Content-Type\":\"application/json\",Accept:\"application/json\"},body:JSON.stringify(e),timeout:s,retry:a})).json();return dPe(f)}async getEntry(e){let{baseURL:r,timeout:s,retry:a}=this.options,n=`${r}/api/v1/log/entries/${e}`,f=await(await(0,gPe.fetchWithRetry)(n,{method:\"GET\",headers:{Accept:\"application/json\"},timeout:s,retry:a})).json();return dPe(f)}};SO.Rekor=D7;function dPe(t){let e=Object.entries(t);if(e.length!=1)throw new Error(\"Received multiple entries in Rekor response\");let[r,s]=e[0];return{...s,uuid:r}}});var EPe=_(DO=>{\"use strict\";Object.defineProperty(DO,\"__esModule\",{value:!0});DO.TLogClient=void 0;var yPe=$w(),zwt=yO(),Zwt=mPe(),P7=class{constructor(e){this.fetchOnConflict=e.fetchOnConflict??!1,this.rekor=new Zwt.Rekor({baseURL:e.rekorBaseURL,retry:e.retry,timeout:e.timeout})}async createEntry(e){let r;try{r=await this.rekor.createEntry(e)}catch(s){if(Xwt(s)&&this.fetchOnConflict){let a=s.location.split(\"/\").pop()||\"\";try{r=await this.rekor.getEntry(a)}catch(n){(0,yPe.internalError)(n,\"TLOG_FETCH_ENTRY_ERROR\",\"error fetching tlog entry\")}}else(0,yPe.internalError)(s,\"TLOG_CREATE_ENTRY_ERROR\",\"error creating tlog entry\")}return r}};DO.TLogClient=P7;function Xwt(t){return t instanceof zwt.HTTPError&&t.statusCode===409&&t.location!==void 0}});var IPe=_(b7=>{\"use strict\";Object.defineProperty(b7,\"__esModule\",{value:!0});b7.toProposedEntry=e1t;var $wt=EP(),Sg=vg(),PP=\"sha256\";function e1t(t,e,r=\"dsse\"){switch(t.$case){case\"dsseEnvelope\":return r===\"intoto\"?n1t(t.dsseEnvelope,e):r1t(t.dsseEnvelope,e);case\"messageSignature\":return t1t(t.messageSignature,e)}}function t1t(t,e){let r=t.messageDigest.digest.toString(\"hex\"),s=t.signature.toString(\"base64\"),a=Sg.encoding.base64Encode(e);return{apiVersion:\"0.0.1\",kind:\"hashedrekord\",spec:{data:{hash:{algorithm:PP,value:r}},signature:{content:s,publicKey:{content:a}}}}}function r1t(t,e){let r=JSON.stringify((0,$wt.envelopeToJSON)(t)),s=Sg.encoding.base64Encode(e);return{apiVersion:\"0.0.1\",kind:\"dsse\",spec:{proposedContent:{envelope:r,verifiers:[s]}}}}function n1t(t,e){let r=Sg.crypto.digest(PP,t.payload).toString(\"hex\"),s=i1t(t,e),a=Sg.encoding.base64Encode(t.payload.toString(\"base64\")),n=Sg.encoding.base64Encode(t.signatures[0].sig.toString(\"base64\")),c=t.signatures[0].keyid,f=Sg.encoding.base64Encode(e),p={payloadType:t.payloadType,payload:a,signatures:[{sig:n,publicKey:f}]};return c.length>0&&(p.signatures[0].keyid=c),{apiVersion:\"0.0.2\",kind:\"intoto\",spec:{content:{envelope:p,hash:{algorithm:PP,value:s},payloadHash:{algorithm:PP,value:r}}}}}function i1t(t,e){let r={payloadType:t.payloadType,payload:t.payload.toString(\"base64\"),signatures:[{sig:t.signatures[0].sig.toString(\"base64\"),publicKey:e}]};return t.signatures[0].keyid.length>0&&(r.signatures[0].keyid=t.signatures[0].keyid),Sg.crypto.digest(PP,Sg.json.canonicalize(r)).toString(\"hex\")}});var CPe=_(oy=>{\"use strict\";Object.defineProperty(oy,\"__esModule\",{value:!0});oy.RekorWitness=oy.DEFAULT_REKOR_URL=void 0;var s1t=vg(),o1t=EPe(),a1t=IPe();oy.DEFAULT_REKOR_URL=\"https://rekor.sigstore.dev\";var x7=class{constructor(e){this.entryType=e.entryType,this.tlog=new o1t.TLogClient({...e,rekorBaseURL:e.rekorBaseURL||oy.DEFAULT_REKOR_URL})}async testify(e,r){let s=(0,a1t.toProposedEntry)(e,r,this.entryType),a=await this.tlog.createEntry(s);return l1t(a)}};oy.RekorWitness=x7;function l1t(t){let e=Buffer.from(t.logID,\"hex\"),r=s1t.encoding.base64Decode(t.body),s=JSON.parse(r),a=t?.verification?.signedEntryTimestamp?c1t(t.verification.signedEntryTimestamp):void 0,n=t?.verification?.inclusionProof?u1t(t.verification.inclusionProof):void 0;return{tlogEntries:[{logIndex:t.logIndex.toString(),logId:{keyId:e},integratedTime:t.integratedTime.toString(),kindVersion:{kind:s.kind,version:s.apiVersion},inclusionPromise:a,inclusionProof:n,canonicalizedBody:Buffer.from(t.body,\"base64\")}]}}function c1t(t){return{signedEntryTimestamp:Buffer.from(t,\"base64\")}}function u1t(t){return{logIndex:t.logIndex.toString(),treeSize:t.treeSize.toString(),rootHash:Buffer.from(t.rootHash,\"hex\"),hashes:t.hashes.map(e=>Buffer.from(e,\"hex\")),checkpoint:{envelope:t.checkpoint}}}});var wPe=_(PO=>{\"use strict\";Object.defineProperty(PO,\"__esModule\",{value:!0});PO.TimestampAuthority=void 0;var f1t=wO(),k7=class{constructor(e){this.options=e}async createTimestamp(e){let{baseURL:r,timeout:s,retry:a}=this.options,n=`${r}/api/v1/timestamp`;return(await(0,f1t.fetchWithRetry)(n,{headers:{\"Content-Type\":\"application/json\"},body:JSON.stringify(e),timeout:s,retry:a})).buffer()}};PO.TimestampAuthority=k7});var vPe=_(bO=>{\"use strict\";Object.defineProperty(bO,\"__esModule\",{value:!0});bO.TSAClient=void 0;var A1t=$w(),p1t=wPe(),h1t=vg(),BPe=\"sha256\",Q7=class{constructor(e){this.tsa=new p1t.TimestampAuthority({baseURL:e.tsaBaseURL,retry:e.retry,timeout:e.timeout})}async createTimestamp(e){let r={artifactHash:h1t.crypto.digest(BPe,e).toString(\"base64\"),hashAlgorithm:BPe};try{return await this.tsa.createTimestamp(r)}catch(s){(0,A1t.internalError)(s,\"TSA_CREATE_TIMESTAMP_ERROR\",\"error creating timestamp\")}}};bO.TSAClient=Q7});var SPe=_(xO=>{\"use strict\";Object.defineProperty(xO,\"__esModule\",{value:!0});xO.TSAWitness=void 0;var g1t=vPe(),R7=class{constructor(e){this.tsa=new g1t.TSAClient({tsaBaseURL:e.tsaBaseURL,retry:e.retry,timeout:e.timeout})}async testify(e){let r=d1t(e);return{rfc3161Timestamps:[{signedTimestamp:await this.tsa.createTimestamp(r)}]}}};xO.TSAWitness=R7;function d1t(t){switch(t.$case){case\"dsseEnvelope\":return t.dsseEnvelope.signatures[0].sig;case\"messageSignature\":return t.messageSignature.signature}}});var PPe=_(Dg=>{\"use strict\";Object.defineProperty(Dg,\"__esModule\",{value:!0});Dg.TSAWitness=Dg.RekorWitness=Dg.DEFAULT_REKOR_URL=void 0;var DPe=CPe();Object.defineProperty(Dg,\"DEFAULT_REKOR_URL\",{enumerable:!0,get:function(){return DPe.DEFAULT_REKOR_URL}});Object.defineProperty(Dg,\"RekorWitness\",{enumerable:!0,get:function(){return DPe.RekorWitness}});var m1t=SPe();Object.defineProperty(Dg,\"TSAWitness\",{enumerable:!0,get:function(){return m1t.TSAWitness}})});var F7=_(ys=>{\"use strict\";Object.defineProperty(ys,\"__esModule\",{value:!0});ys.TSAWitness=ys.RekorWitness=ys.DEFAULT_REKOR_URL=ys.FulcioSigner=ys.DEFAULT_FULCIO_URL=ys.CIContextProvider=ys.InternalError=ys.MessageSignatureBundleBuilder=ys.DSSEBundleBuilder=void 0;var bPe=GDe();Object.defineProperty(ys,\"DSSEBundleBuilder\",{enumerable:!0,get:function(){return bPe.DSSEBundleBuilder}});Object.defineProperty(ys,\"MessageSignatureBundleBuilder\",{enumerable:!0,get:function(){return bPe.MessageSignatureBundleBuilder}});var y1t=$w();Object.defineProperty(ys,\"InternalError\",{enumerable:!0,get:function(){return y1t.InternalError}});var E1t=YDe();Object.defineProperty(ys,\"CIContextProvider\",{enumerable:!0,get:function(){return E1t.CIContextProvider}});var xPe=hPe();Object.defineProperty(ys,\"DEFAULT_FULCIO_URL\",{enumerable:!0,get:function(){return xPe.DEFAULT_FULCIO_URL}});Object.defineProperty(ys,\"FulcioSigner\",{enumerable:!0,get:function(){return xPe.FulcioSigner}});var T7=PPe();Object.defineProperty(ys,\"DEFAULT_REKOR_URL\",{enumerable:!0,get:function(){return T7.DEFAULT_REKOR_URL}});Object.defineProperty(ys,\"RekorWitness\",{enumerable:!0,get:function(){return T7.RekorWitness}});Object.defineProperty(ys,\"TSAWitness\",{enumerable:!0,get:function(){return T7.TSAWitness}})});var QPe=_(bP=>{\"use strict\";var kPe=bP&&bP.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(bP,\"__esModule\",{value:!0});bP.appDataPath=C1t;var I1t=kPe(Ie(\"os\")),n1=kPe(Ie(\"path\"));function C1t(t){let e=I1t.default.homedir();switch(process.platform){case\"darwin\":{let r=n1.default.join(e,\"Library\",\"Application Support\");return n1.default.join(r,t)}case\"win32\":{let r=process.env.LOCALAPPDATA||n1.default.join(e,\"AppData\",\"Local\");return n1.default.join(r,t,\"Data\")}default:{let r=process.env.XDG_DATA_HOME||n1.default.join(e,\".local\",\"share\");return n1.default.join(r,t)}}}});var bA=_(wl=>{\"use strict\";Object.defineProperty(wl,\"__esModule\",{value:!0});wl.UnsupportedAlgorithmError=wl.CryptoError=wl.LengthOrHashMismatchError=wl.UnsignedMetadataError=wl.RepositoryError=wl.ValueError=void 0;var N7=class extends Error{};wl.ValueError=N7;var xP=class extends Error{};wl.RepositoryError=xP;var O7=class extends xP{};wl.UnsignedMetadataError=O7;var L7=class extends xP{};wl.LengthOrHashMismatchError=L7;var kO=class extends Error{};wl.CryptoError=kO;var M7=class extends kO{};wl.UnsupportedAlgorithmError=M7});var TPe=_(Pg=>{\"use strict\";Object.defineProperty(Pg,\"__esModule\",{value:!0});Pg.isDefined=w1t;Pg.isObject=RPe;Pg.isStringArray=B1t;Pg.isObjectArray=v1t;Pg.isStringRecord=S1t;Pg.isObjectRecord=D1t;function w1t(t){return t!==void 0}function RPe(t){return typeof t==\"object\"&&t!==null}function B1t(t){return Array.isArray(t)&&t.every(e=>typeof e==\"string\")}function v1t(t){return Array.isArray(t)&&t.every(RPe)}function S1t(t){return typeof t==\"object\"&&t!==null&&Object.keys(t).every(e=>typeof e==\"string\")&&Object.values(t).every(e=>typeof e==\"string\")}function D1t(t){return typeof t==\"object\"&&t!==null&&Object.keys(t).every(e=>typeof e==\"string\")&&Object.values(t).every(e=>typeof e==\"object\"&&e!==null)}});var _7=_((Fnr,OPe)=>{var FPe=\",\",P1t=\":\",b1t=\"[\",x1t=\"]\",k1t=\"{\",Q1t=\"}\";function U7(t){let e=[];if(typeof t==\"string\")e.push(NPe(t));else if(typeof t==\"boolean\")e.push(JSON.stringify(t));else if(Number.isInteger(t))e.push(JSON.stringify(t));else if(t===null)e.push(JSON.stringify(t));else if(Array.isArray(t)){e.push(b1t);let r=!0;t.forEach(s=>{r||e.push(FPe),r=!1,e.push(U7(s))}),e.push(x1t)}else if(typeof t==\"object\"){e.push(k1t);let r=!0;Object.keys(t).sort().forEach(s=>{r||e.push(FPe),r=!1,e.push(NPe(s)),e.push(P1t),e.push(U7(t[s]))}),e.push(Q1t)}else throw new TypeError(\"cannot encode \"+t.toString());return e.join(\"\")}function NPe(t){return'\"'+t.replace(/\\\\/g,\"\\\\\\\\\").replace(/\"/g,'\\\\\"')+'\"'}OPe.exports={canonicalize:U7}});var LPe=_(i1=>{\"use strict\";var R1t=i1&&i1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(i1,\"__esModule\",{value:!0});i1.verifySignature=void 0;var T1t=_7(),F1t=R1t(Ie(\"crypto\")),N1t=(t,e,r)=>{let s=Buffer.from((0,T1t.canonicalize)(t));return F1t.default.verify(void 0,s,e,Buffer.from(r,\"hex\"))};i1.verifySignature=N1t});var ff=_(eu=>{\"use strict\";var O1t=eu&&eu.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||(\"get\"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),L1t=eu&&eu.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),MPe=eu&&eu.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.prototype.hasOwnProperty.call(t,r)&&O1t(e,t,r);return L1t(e,t),e};Object.defineProperty(eu,\"__esModule\",{value:!0});eu.crypto=eu.guard=void 0;eu.guard=MPe(TPe());eu.crypto=MPe(LPe())});var ay=_(hh=>{\"use strict\";var M1t=hh&&hh.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(hh,\"__esModule\",{value:!0});hh.Signed=hh.MetadataKind=void 0;hh.isMetadataKind=_1t;var U1t=M1t(Ie(\"util\")),kP=bA(),H7=ff(),UPe=[\"1\",\"0\",\"31\"],j7;(function(t){t.Root=\"root\",t.Timestamp=\"timestamp\",t.Snapshot=\"snapshot\",t.Targets=\"targets\"})(j7||(hh.MetadataKind=j7={}));function _1t(t){return typeof t==\"string\"&&Object.values(j7).includes(t)}var G7=class t{constructor(e){this.specVersion=e.specVersion||UPe.join(\".\");let r=this.specVersion.split(\".\");if(!(r.length===2||r.length===3)||!r.every(s=>H1t(s)))throw new kP.ValueError(\"Failed to parse specVersion\");if(r[0]!=UPe[0])throw new kP.ValueError(\"Unsupported specVersion\");this.expires=e.expires,this.version=e.version,this.unrecognizedFields=e.unrecognizedFields||{}}equals(e){return e instanceof t?this.specVersion===e.specVersion&&this.expires===e.expires&&this.version===e.version&&U1t.default.isDeepStrictEqual(this.unrecognizedFields,e.unrecognizedFields):!1}isExpired(e){return e||(e=new Date),e>=new Date(this.expires)}static commonFieldsFromJSON(e){let{spec_version:r,expires:s,version:a,...n}=e;if(H7.guard.isDefined(r)){if(typeof r!=\"string\")throw new TypeError(\"spec_version must be a string\")}else throw new kP.ValueError(\"spec_version is not defined\");if(H7.guard.isDefined(s)){if(typeof s!=\"string\")throw new TypeError(\"expires must be a string\")}else throw new kP.ValueError(\"expires is not defined\");if(H7.guard.isDefined(a)){if(typeof a!=\"number\")throw new TypeError(\"version must be a number\")}else throw new kP.ValueError(\"version is not defined\");return{specVersion:r,expires:s,version:a,unrecognizedFields:n}}};hh.Signed=G7;function H1t(t){return!isNaN(Number(t))}});var QP=_(xg=>{\"use strict\";var _Pe=xg&&xg.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(xg,\"__esModule\",{value:!0});xg.TargetFile=xg.MetaFile=void 0;var HPe=_Pe(Ie(\"crypto\")),RO=_Pe(Ie(\"util\")),bg=bA(),QO=ff(),q7=class t{constructor(e){if(e.version<=0)throw new bg.ValueError(\"Metafile version must be at least 1\");e.length!==void 0&&jPe(e.length),this.version=e.version,this.length=e.length,this.hashes=e.hashes,this.unrecognizedFields=e.unrecognizedFields||{}}equals(e){return e instanceof t?this.version===e.version&&this.length===e.length&&RO.default.isDeepStrictEqual(this.hashes,e.hashes)&&RO.default.isDeepStrictEqual(this.unrecognizedFields,e.unrecognizedFields):!1}verify(e){if(this.length!==void 0&&e.length!==this.length)throw new bg.LengthOrHashMismatchError(`Expected length ${this.length} but got ${e.length}`);this.hashes&&Object.entries(this.hashes).forEach(([r,s])=>{let a;try{a=HPe.default.createHash(r)}catch{throw new bg.LengthOrHashMismatchError(`Hash algorithm ${r} not supported`)}let n=a.update(e).digest(\"hex\");if(n!==s)throw new bg.LengthOrHashMismatchError(`Expected hash ${s} but got ${n}`)})}toJSON(){let e={version:this.version,...this.unrecognizedFields};return this.length!==void 0&&(e.length=this.length),this.hashes&&(e.hashes=this.hashes),e}static fromJSON(e){let{version:r,length:s,hashes:a,...n}=e;if(typeof r!=\"number\")throw new TypeError(\"version must be a number\");if(QO.guard.isDefined(s)&&typeof s!=\"number\")throw new TypeError(\"length must be a number\");if(QO.guard.isDefined(a)&&!QO.guard.isStringRecord(a))throw new TypeError(\"hashes must be string keys and values\");return new t({version:r,length:s,hashes:a,unrecognizedFields:n})}};xg.MetaFile=q7;var W7=class t{constructor(e){jPe(e.length),this.length=e.length,this.path=e.path,this.hashes=e.hashes,this.unrecognizedFields=e.unrecognizedFields||{}}get custom(){let e=this.unrecognizedFields.custom;return!e||Array.isArray(e)||typeof e!=\"object\"?{}:e}equals(e){return e instanceof t?this.length===e.length&&this.path===e.path&&RO.default.isDeepStrictEqual(this.hashes,e.hashes)&&RO.default.isDeepStrictEqual(this.unrecognizedFields,e.unrecognizedFields):!1}async verify(e){let r=0,s=Object.keys(this.hashes).reduce((a,n)=>{try{a[n]=HPe.default.createHash(n)}catch{throw new bg.LengthOrHashMismatchError(`Hash algorithm ${n} not supported`)}return a},{});for await(let a of e)r+=a.length,Object.values(s).forEach(n=>{n.update(a)});if(r!==this.length)throw new bg.LengthOrHashMismatchError(`Expected length ${this.length} but got ${r}`);Object.entries(s).forEach(([a,n])=>{let c=this.hashes[a],f=n.digest(\"hex\");if(f!==c)throw new bg.LengthOrHashMismatchError(`Expected hash ${c} but got ${f}`)})}toJSON(){return{length:this.length,hashes:this.hashes,...this.unrecognizedFields}}static fromJSON(e,r){let{length:s,hashes:a,...n}=r;if(typeof s!=\"number\")throw new TypeError(\"length must be a number\");if(!QO.guard.isStringRecord(a))throw new TypeError(\"hashes must have string keys and values\");return new t({length:s,path:e,hashes:a,unrecognizedFields:n})}};xg.TargetFile=W7;function jPe(t){if(t<0)throw new bg.ValueError(\"Length must be at least 0\")}});var GPe=_(Y7=>{\"use strict\";Object.defineProperty(Y7,\"__esModule\",{value:!0});Y7.encodeOIDString=G1t;var j1t=6;function G1t(t){let e=t.split(\".\"),r=parseInt(e[0],10)*40+parseInt(e[1],10),s=[];e.slice(2).forEach(n=>{let c=q1t(parseInt(n,10));s.push(...c)});let a=Buffer.from([r,...s]);return Buffer.from([j1t,a.length,...a])}function q1t(t){let e=[],r=0;for(;t>0;)e.unshift(t&127|r),t>>=7,r=128;return e}});var VPe=_(TP=>{\"use strict\";var W1t=TP&&TP.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(TP,\"__esModule\",{value:!0});TP.getPublicKey=K1t;var s1=W1t(Ie(\"crypto\")),RP=bA(),V7=GPe(),TO=48,qPe=3,WPe=0,Y1t=\"1.3.101.112\",V1t=\"1.2.840.10045.2.1\",J1t=\"1.2.840.10045.3.1.7\",J7=\"-----BEGIN PUBLIC KEY-----\";function K1t(t){switch(t.keyType){case\"rsa\":return z1t(t);case\"ed25519\":return Z1t(t);case\"ecdsa\":case\"ecdsa-sha2-nistp256\":case\"ecdsa-sha2-nistp384\":return X1t(t);default:throw new RP.UnsupportedAlgorithmError(`Unsupported key type: ${t.keyType}`)}}function z1t(t){if(!t.keyVal.startsWith(J7))throw new RP.CryptoError(\"Invalid key format\");let e=s1.default.createPublicKey(t.keyVal);switch(t.scheme){case\"rsassa-pss-sha256\":return{key:e,padding:s1.default.constants.RSA_PKCS1_PSS_PADDING};default:throw new RP.UnsupportedAlgorithmError(`Unsupported RSA scheme: ${t.scheme}`)}}function Z1t(t){let e;if(t.keyVal.startsWith(J7))e=s1.default.createPublicKey(t.keyVal);else{if(!YPe(t.keyVal))throw new RP.CryptoError(\"Invalid key format\");e=s1.default.createPublicKey({key:$1t.hexToDER(t.keyVal),format:\"der\",type:\"spki\"})}return{key:e}}function X1t(t){let e;if(t.keyVal.startsWith(J7))e=s1.default.createPublicKey(t.keyVal);else{if(!YPe(t.keyVal))throw new RP.CryptoError(\"Invalid key format\");e=s1.default.createPublicKey({key:e2t.hexToDER(t.keyVal),format:\"der\",type:\"spki\"})}return{key:e}}var $1t={hexToDER:t=>{let e=Buffer.from(t,\"hex\"),r=(0,V7.encodeOIDString)(Y1t),s=Buffer.concat([Buffer.concat([Buffer.from([TO]),Buffer.from([r.length]),r]),Buffer.concat([Buffer.from([qPe]),Buffer.from([e.length+1]),Buffer.from([WPe]),e])]);return Buffer.concat([Buffer.from([TO]),Buffer.from([s.length]),s])}},e2t={hexToDER:t=>{let e=Buffer.from(t,\"hex\"),r=Buffer.concat([Buffer.from([qPe]),Buffer.from([e.length+1]),Buffer.from([WPe]),e]),s=Buffer.concat([(0,V7.encodeOIDString)(V1t),(0,V7.encodeOIDString)(J1t)]),a=Buffer.concat([Buffer.from([TO]),Buffer.from([s.length]),s]);return Buffer.concat([Buffer.from([TO]),Buffer.from([a.length+r.length]),a,r])}},YPe=t=>/^[0-9a-fA-F]+$/.test(t)});var FO=_(o1=>{\"use strict\";var t2t=o1&&o1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(o1,\"__esModule\",{value:!0});o1.Key=void 0;var JPe=t2t(Ie(\"util\")),FP=bA(),KPe=ff(),r2t=VPe(),K7=class t{constructor(e){let{keyID:r,keyType:s,scheme:a,keyVal:n,unrecognizedFields:c}=e;this.keyID=r,this.keyType=s,this.scheme=a,this.keyVal=n,this.unrecognizedFields=c||{}}verifySignature(e){let r=e.signatures[this.keyID];if(!r)throw new FP.UnsignedMetadataError(\"no signature for key found in metadata\");if(!this.keyVal.public)throw new FP.UnsignedMetadataError(\"no public key found\");let s=(0,r2t.getPublicKey)({keyType:this.keyType,scheme:this.scheme,keyVal:this.keyVal.public}),a=e.signed.toJSON();try{if(!KPe.crypto.verifySignature(a,s,r.sig))throw new FP.UnsignedMetadataError(`failed to verify ${this.keyID} signature`)}catch(n){throw n instanceof FP.UnsignedMetadataError?n:new FP.UnsignedMetadataError(`failed to verify ${this.keyID} signature`)}}equals(e){return e instanceof t?this.keyID===e.keyID&&this.keyType===e.keyType&&this.scheme===e.scheme&&JPe.default.isDeepStrictEqual(this.keyVal,e.keyVal)&&JPe.default.isDeepStrictEqual(this.unrecognizedFields,e.unrecognizedFields):!1}toJSON(){return{keytype:this.keyType,scheme:this.scheme,keyval:this.keyVal,...this.unrecognizedFields}}static fromJSON(e,r){let{keytype:s,scheme:a,keyval:n,...c}=r;if(typeof s!=\"string\")throw new TypeError(\"keytype must be a string\");if(typeof a!=\"string\")throw new TypeError(\"scheme must be a string\");if(!KPe.guard.isStringRecord(n))throw new TypeError(\"keyval must be a string record\");return new t({keyID:e,keyType:s,scheme:a,keyVal:n,unrecognizedFields:c})}};o1.Key=K7});var ebe=_((jnr,$Pe)=>{\"use strict\";$Pe.exports=ZPe;function ZPe(t,e,r){t instanceof RegExp&&(t=zPe(t,r)),e instanceof RegExp&&(e=zPe(e,r));var s=XPe(t,e,r);return s&&{start:s[0],end:s[1],pre:r.slice(0,s[0]),body:r.slice(s[0]+t.length,s[1]),post:r.slice(s[1]+e.length)}}function zPe(t,e){var r=e.match(t);return r?r[0]:null}ZPe.range=XPe;function XPe(t,e,r){var s,a,n,c,f,p=r.indexOf(t),h=r.indexOf(e,p+1),E=p;if(p>=0&&h>0){for(s=[],n=r.length;E>=0&&!f;)E==p?(s.push(E),p=r.indexOf(t,E+1)):s.length==1?f=[s.pop(),h]:(a=s.pop(),a<n&&(n=a,c=h),h=r.indexOf(e,E+1)),E=p<h&&p>=0?p:h;s.length&&(f=[n,c])}return f}});var lbe=_((Gnr,abe)=>{var tbe=ebe();abe.exports=s2t;var rbe=\"\\0SLASH\"+Math.random()+\"\\0\",nbe=\"\\0OPEN\"+Math.random()+\"\\0\",Z7=\"\\0CLOSE\"+Math.random()+\"\\0\",ibe=\"\\0COMMA\"+Math.random()+\"\\0\",sbe=\"\\0PERIOD\"+Math.random()+\"\\0\";function z7(t){return parseInt(t,10)==t?parseInt(t,10):t.charCodeAt(0)}function n2t(t){return t.split(\"\\\\\\\\\").join(rbe).split(\"\\\\{\").join(nbe).split(\"\\\\}\").join(Z7).split(\"\\\\,\").join(ibe).split(\"\\\\.\").join(sbe)}function i2t(t){return t.split(rbe).join(\"\\\\\").split(nbe).join(\"{\").split(Z7).join(\"}\").split(ibe).join(\",\").split(sbe).join(\".\")}function obe(t){if(!t)return[\"\"];var e=[],r=tbe(\"{\",\"}\",t);if(!r)return t.split(\",\");var s=r.pre,a=r.body,n=r.post,c=s.split(\",\");c[c.length-1]+=\"{\"+a+\"}\";var f=obe(n);return n.length&&(c[c.length-1]+=f.shift(),c.push.apply(c,f)),e.push.apply(e,c),e}function s2t(t){return t?(t.substr(0,2)===\"{}\"&&(t=\"\\\\{\\\\}\"+t.substr(2)),NP(n2t(t),!0).map(i2t)):[]}function o2t(t){return\"{\"+t+\"}\"}function a2t(t){return/^-?0\\d/.test(t)}function l2t(t,e){return t<=e}function c2t(t,e){return t>=e}function NP(t,e){var r=[],s=tbe(\"{\",\"}\",t);if(!s)return[t];var a=s.pre,n=s.post.length?NP(s.post,!1):[\"\"];if(/\\$$/.test(s.pre))for(var c=0;c<n.length;c++){var f=a+\"{\"+s.body+\"}\"+n[c];r.push(f)}else{var p=/^-?\\d+\\.\\.-?\\d+(?:\\.\\.-?\\d+)?$/.test(s.body),h=/^[a-zA-Z]\\.\\.[a-zA-Z](?:\\.\\.-?\\d+)?$/.test(s.body),E=p||h,C=s.body.indexOf(\",\")>=0;if(!E&&!C)return s.post.match(/,.*\\}/)?(t=s.pre+\"{\"+s.body+Z7+s.post,NP(t)):[t];var S;if(E)S=s.body.split(/\\.\\./);else if(S=obe(s.body),S.length===1&&(S=NP(S[0],!1).map(o2t),S.length===1))return n.map(function(Ce){return s.pre+S[0]+Ce});var b;if(E){var I=z7(S[0]),T=z7(S[1]),N=Math.max(S[0].length,S[1].length),U=S.length==3?Math.abs(z7(S[2])):1,W=l2t,ee=T<I;ee&&(U*=-1,W=c2t);var ie=S.some(a2t);b=[];for(var ue=I;W(ue,T);ue+=U){var le;if(h)le=String.fromCharCode(ue),le===\"\\\\\"&&(le=\"\");else if(le=String(ue),ie){var me=N-le.length;if(me>0){var pe=new Array(me+1).join(\"0\");ue<0?le=\"-\"+pe+le.slice(1):le=pe+le}}b.push(le)}}else{b=[];for(var Be=0;Be<S.length;Be++)b.push.apply(b,NP(S[Be],!1))}for(var Be=0;Be<b.length;Be++)for(var c=0;c<n.length;c++){var f=a+b[Be]+n[c];(!e||E||f)&&r.push(f)}}return r}});var cbe=_(NO=>{\"use strict\";Object.defineProperty(NO,\"__esModule\",{value:!0});NO.assertValidPattern=void 0;var u2t=1024*64,f2t=t=>{if(typeof t!=\"string\")throw new TypeError(\"invalid pattern\");if(t.length>u2t)throw new TypeError(\"pattern is too long\")};NO.assertValidPattern=f2t});var fbe=_(OO=>{\"use strict\";Object.defineProperty(OO,\"__esModule\",{value:!0});OO.parseClass=void 0;var A2t={\"[:alnum:]\":[\"\\\\p{L}\\\\p{Nl}\\\\p{Nd}\",!0],\"[:alpha:]\":[\"\\\\p{L}\\\\p{Nl}\",!0],\"[:ascii:]\":[\"\\\\x00-\\\\x7f\",!1],\"[:blank:]\":[\"\\\\p{Zs}\\\\t\",!0],\"[:cntrl:]\":[\"\\\\p{Cc}\",!0],\"[:digit:]\":[\"\\\\p{Nd}\",!0],\"[:graph:]\":[\"\\\\p{Z}\\\\p{C}\",!0,!0],\"[:lower:]\":[\"\\\\p{Ll}\",!0],\"[:print:]\":[\"\\\\p{C}\",!0],\"[:punct:]\":[\"\\\\p{P}\",!0],\"[:space:]\":[\"\\\\p{Z}\\\\t\\\\r\\\\n\\\\v\\\\f\",!0],\"[:upper:]\":[\"\\\\p{Lu}\",!0],\"[:word:]\":[\"\\\\p{L}\\\\p{Nl}\\\\p{Nd}\\\\p{Pc}\",!0],\"[:xdigit:]\":[\"A-Fa-f0-9\",!1]},OP=t=>t.replace(/[[\\]\\\\-]/g,\"\\\\$&\"),p2t=t=>t.replace(/[-[\\]{}()*+?.,\\\\^$|#\\s]/g,\"\\\\$&\"),ube=t=>t.join(\"\"),h2t=(t,e)=>{let r=e;if(t.charAt(r)!==\"[\")throw new Error(\"not in a brace expression\");let s=[],a=[],n=r+1,c=!1,f=!1,p=!1,h=!1,E=r,C=\"\";e:for(;n<t.length;){let T=t.charAt(n);if((T===\"!\"||T===\"^\")&&n===r+1){h=!0,n++;continue}if(T===\"]\"&&c&&!p){E=n+1;break}if(c=!0,T===\"\\\\\"&&!p){p=!0,n++;continue}if(T===\"[\"&&!p){for(let[N,[U,W,ee]]of Object.entries(A2t))if(t.startsWith(N,n)){if(C)return[\"$.\",!1,t.length-r,!0];n+=N.length,ee?a.push(U):s.push(U),f=f||W;continue e}}if(p=!1,C){T>C?s.push(OP(C)+\"-\"+OP(T)):T===C&&s.push(OP(T)),C=\"\",n++;continue}if(t.startsWith(\"-]\",n+1)){s.push(OP(T+\"-\")),n+=2;continue}if(t.startsWith(\"-\",n+1)){C=T,n+=2;continue}s.push(OP(T)),n++}if(E<n)return[\"\",!1,0,!1];if(!s.length&&!a.length)return[\"$.\",!1,t.length-r,!0];if(a.length===0&&s.length===1&&/^\\\\?.$/.test(s[0])&&!h){let T=s[0].length===2?s[0].slice(-1):s[0];return[p2t(T),!1,E-r,!1]}let S=\"[\"+(h?\"^\":\"\")+ube(s)+\"]\",b=\"[\"+(h?\"\":\"^\")+ube(a)+\"]\";return[s.length&&a.length?\"(\"+S+\"|\"+b+\")\":s.length?S:b,f,E-r,!0]};OO.parseClass=h2t});var MO=_(LO=>{\"use strict\";Object.defineProperty(LO,\"__esModule\",{value:!0});LO.unescape=void 0;var g2t=(t,{windowsPathsNoEscape:e=!1}={})=>e?t.replace(/\\[([^\\/\\\\])\\]/g,\"$1\"):t.replace(/((?!\\\\).|^)\\[([^\\/\\\\])\\]/g,\"$1$2\").replace(/\\\\([^\\/])/g,\"$1\");LO.unescape=g2t});var eJ=_(HO=>{\"use strict\";Object.defineProperty(HO,\"__esModule\",{value:!0});HO.AST=void 0;var d2t=fbe(),UO=MO(),m2t=new Set([\"!\",\"?\",\"+\",\"*\",\"@\"]),Abe=t=>m2t.has(t),y2t=\"(?!(?:^|/)\\\\.\\\\.?(?:$|/))\",_O=\"(?!\\\\.)\",E2t=new Set([\"[\",\".\"]),I2t=new Set([\"..\",\".\"]),C2t=new Set(\"().*{}+?[]^$\\\\!\"),w2t=t=>t.replace(/[-[\\]{}()*+?.,\\\\^$|#\\s]/g,\"\\\\$&\"),$7=\"[^/]\",pbe=$7+\"*?\",hbe=$7+\"+?\",X7=class t{type;#t;#r;#i=!1;#e=[];#n;#o;#l;#a=!1;#s;#c;#f=!1;constructor(e,r,s={}){this.type=e,e&&(this.#r=!0),this.#n=r,this.#t=this.#n?this.#n.#t:this,this.#s=this.#t===this?s:this.#t.#s,this.#l=this.#t===this?[]:this.#t.#l,e===\"!\"&&!this.#t.#a&&this.#l.push(this),this.#o=this.#n?this.#n.#e.length:0}get hasMagic(){if(this.#r!==void 0)return this.#r;for(let e of this.#e)if(typeof e!=\"string\"&&(e.type||e.hasMagic))return this.#r=!0;return this.#r}toString(){return this.#c!==void 0?this.#c:this.type?this.#c=this.type+\"(\"+this.#e.map(e=>String(e)).join(\"|\")+\")\":this.#c=this.#e.map(e=>String(e)).join(\"\")}#p(){if(this!==this.#t)throw new Error(\"should only call on root\");if(this.#a)return this;this.toString(),this.#a=!0;let e;for(;e=this.#l.pop();){if(e.type!==\"!\")continue;let r=e,s=r.#n;for(;s;){for(let a=r.#o+1;!s.type&&a<s.#e.length;a++)for(let n of e.#e){if(typeof n==\"string\")throw new Error(\"string part in extglob AST??\");n.copyIn(s.#e[a])}r=s,s=r.#n}}return this}push(...e){for(let r of e)if(r!==\"\"){if(typeof r!=\"string\"&&!(r instanceof t&&r.#n===this))throw new Error(\"invalid part: \"+r);this.#e.push(r)}}toJSON(){let e=this.type===null?this.#e.slice().map(r=>typeof r==\"string\"?r:r.toJSON()):[this.type,...this.#e.map(r=>r.toJSON())];return this.isStart()&&!this.type&&e.unshift([]),this.isEnd()&&(this===this.#t||this.#t.#a&&this.#n?.type===\"!\")&&e.push({}),e}isStart(){if(this.#t===this)return!0;if(!this.#n?.isStart())return!1;if(this.#o===0)return!0;let e=this.#n;for(let r=0;r<this.#o;r++){let s=e.#e[r];if(!(s instanceof t&&s.type===\"!\"))return!1}return!0}isEnd(){if(this.#t===this||this.#n?.type===\"!\")return!0;if(!this.#n?.isEnd())return!1;if(!this.type)return this.#n?.isEnd();let e=this.#n?this.#n.#e.length:0;return this.#o===e-1}copyIn(e){typeof e==\"string\"?this.push(e):this.push(e.clone(this))}clone(e){let r=new t(this.type,e);for(let s of this.#e)r.copyIn(s);return r}static#u(e,r,s,a){let n=!1,c=!1,f=-1,p=!1;if(r.type===null){let b=s,I=\"\";for(;b<e.length;){let T=e.charAt(b++);if(n||T===\"\\\\\"){n=!n,I+=T;continue}if(c){b===f+1?(T===\"^\"||T===\"!\")&&(p=!0):T===\"]\"&&!(b===f+2&&p)&&(c=!1),I+=T;continue}else if(T===\"[\"){c=!0,f=b,p=!1,I+=T;continue}if(!a.noext&&Abe(T)&&e.charAt(b)===\"(\"){r.push(I),I=\"\";let N=new t(T,r);b=t.#u(e,N,b,a),r.push(N);continue}I+=T}return r.push(I),b}let h=s+1,E=new t(null,r),C=[],S=\"\";for(;h<e.length;){let b=e.charAt(h++);if(n||b===\"\\\\\"){n=!n,S+=b;continue}if(c){h===f+1?(b===\"^\"||b===\"!\")&&(p=!0):b===\"]\"&&!(h===f+2&&p)&&(c=!1),S+=b;continue}else if(b===\"[\"){c=!0,f=h,p=!1,S+=b;continue}if(Abe(b)&&e.charAt(h)===\"(\"){E.push(S),S=\"\";let I=new t(b,E);E.push(I),h=t.#u(e,I,h,a);continue}if(b===\"|\"){E.push(S),S=\"\",C.push(E),E=new t(null,r);continue}if(b===\")\")return S===\"\"&&r.#e.length===0&&(r.#f=!0),E.push(S),S=\"\",r.push(...C,E),h;S+=b}return r.type=null,r.#r=void 0,r.#e=[e.substring(s-1)],h}static fromGlob(e,r={}){let s=new t(null,void 0,r);return t.#u(e,s,0,r),s}toMMPattern(){if(this!==this.#t)return this.#t.toMMPattern();let e=this.toString(),[r,s,a,n]=this.toRegExpSource();if(!(a||this.#r||this.#s.nocase&&!this.#s.nocaseMagicOnly&&e.toUpperCase()!==e.toLowerCase()))return s;let f=(this.#s.nocase?\"i\":\"\")+(n?\"u\":\"\");return Object.assign(new RegExp(`^${r}$`,f),{_src:r,_glob:e})}get options(){return this.#s}toRegExpSource(e){let r=e??!!this.#s.dot;if(this.#t===this&&this.#p(),!this.type){let p=this.isStart()&&this.isEnd(),h=this.#e.map(b=>{let[I,T,N,U]=typeof b==\"string\"?t.#h(b,this.#r,p):b.toRegExpSource(e);return this.#r=this.#r||N,this.#i=this.#i||U,I}).join(\"\"),E=\"\";if(this.isStart()&&typeof this.#e[0]==\"string\"&&!(this.#e.length===1&&I2t.has(this.#e[0]))){let I=E2t,T=r&&I.has(h.charAt(0))||h.startsWith(\"\\\\.\")&&I.has(h.charAt(2))||h.startsWith(\"\\\\.\\\\.\")&&I.has(h.charAt(4)),N=!r&&!e&&I.has(h.charAt(0));E=T?y2t:N?_O:\"\"}let C=\"\";return this.isEnd()&&this.#t.#a&&this.#n?.type===\"!\"&&(C=\"(?:$|\\\\/)\"),[E+h+C,(0,UO.unescape)(h),this.#r=!!this.#r,this.#i]}let s=this.type===\"*\"||this.type===\"+\",a=this.type===\"!\"?\"(?:(?!(?:\":\"(?:\",n=this.#A(r);if(this.isStart()&&this.isEnd()&&!n&&this.type!==\"!\"){let p=this.toString();return this.#e=[p],this.type=null,this.#r=void 0,[p,(0,UO.unescape)(this.toString()),!1,!1]}let c=!s||e||r||!_O?\"\":this.#A(!0);c===n&&(c=\"\"),c&&(n=`(?:${n})(?:${c})*?`);let f=\"\";if(this.type===\"!\"&&this.#f)f=(this.isStart()&&!r?_O:\"\")+hbe;else{let p=this.type===\"!\"?\"))\"+(this.isStart()&&!r&&!e?_O:\"\")+pbe+\")\":this.type===\"@\"?\")\":this.type===\"?\"?\")?\":this.type===\"+\"&&c?\")\":this.type===\"*\"&&c?\")?\":`)${this.type}`;f=a+n+p}return[f,(0,UO.unescape)(n),this.#r=!!this.#r,this.#i]}#A(e){return this.#e.map(r=>{if(typeof r==\"string\")throw new Error(\"string type in extglob ast??\");let[s,a,n,c]=r.toRegExpSource(e);return this.#i=this.#i||c,s}).filter(r=>!(this.isStart()&&this.isEnd())||!!r).join(\"|\")}static#h(e,r,s=!1){let a=!1,n=\"\",c=!1;for(let f=0;f<e.length;f++){let p=e.charAt(f);if(a){a=!1,n+=(C2t.has(p)?\"\\\\\":\"\")+p;continue}if(p===\"\\\\\"){f===e.length-1?n+=\"\\\\\\\\\":a=!0;continue}if(p===\"[\"){let[h,E,C,S]=(0,d2t.parseClass)(e,f);if(C){n+=h,c=c||E,f+=C-1,r=r||S;continue}}if(p===\"*\"){s&&e===\"*\"?n+=hbe:n+=pbe,r=!0;continue}if(p===\"?\"){n+=$7,r=!0;continue}n+=w2t(p)}return[n,(0,UO.unescape)(e),!!r,c]}};HO.AST=X7});var tJ=_(jO=>{\"use strict\";Object.defineProperty(jO,\"__esModule\",{value:!0});jO.escape=void 0;var B2t=(t,{windowsPathsNoEscape:e=!1}={})=>e?t.replace(/[?*()[\\]]/g,\"[$&]\"):t.replace(/[?*()[\\]\\\\]/g,\"\\\\$&\");jO.escape=B2t});var Cbe=_(pr=>{\"use strict\";var v2t=pr&&pr.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(pr,\"__esModule\",{value:!0});pr.unescape=pr.escape=pr.AST=pr.Minimatch=pr.match=pr.makeRe=pr.braceExpand=pr.defaults=pr.filter=pr.GLOBSTAR=pr.sep=pr.minimatch=void 0;var S2t=v2t(lbe()),GO=cbe(),mbe=eJ(),D2t=tJ(),P2t=MO(),b2t=(t,e,r={})=>((0,GO.assertValidPattern)(e),!r.nocomment&&e.charAt(0)===\"#\"?!1:new ly(e,r).match(t));pr.minimatch=b2t;var x2t=/^\\*+([^+@!?\\*\\[\\(]*)$/,k2t=t=>e=>!e.startsWith(\".\")&&e.endsWith(t),Q2t=t=>e=>e.endsWith(t),R2t=t=>(t=t.toLowerCase(),e=>!e.startsWith(\".\")&&e.toLowerCase().endsWith(t)),T2t=t=>(t=t.toLowerCase(),e=>e.toLowerCase().endsWith(t)),F2t=/^\\*+\\.\\*+$/,N2t=t=>!t.startsWith(\".\")&&t.includes(\".\"),O2t=t=>t!==\".\"&&t!==\"..\"&&t.includes(\".\"),L2t=/^\\.\\*+$/,M2t=t=>t!==\".\"&&t!==\"..\"&&t.startsWith(\".\"),U2t=/^\\*+$/,_2t=t=>t.length!==0&&!t.startsWith(\".\"),H2t=t=>t.length!==0&&t!==\".\"&&t!==\"..\",j2t=/^\\?+([^+@!?\\*\\[\\(]*)?$/,G2t=([t,e=\"\"])=>{let r=ybe([t]);return e?(e=e.toLowerCase(),s=>r(s)&&s.toLowerCase().endsWith(e)):r},q2t=([t,e=\"\"])=>{let r=Ebe([t]);return e?(e=e.toLowerCase(),s=>r(s)&&s.toLowerCase().endsWith(e)):r},W2t=([t,e=\"\"])=>{let r=Ebe([t]);return e?s=>r(s)&&s.endsWith(e):r},Y2t=([t,e=\"\"])=>{let r=ybe([t]);return e?s=>r(s)&&s.endsWith(e):r},ybe=([t])=>{let e=t.length;return r=>r.length===e&&!r.startsWith(\".\")},Ebe=([t])=>{let e=t.length;return r=>r.length===e&&r!==\".\"&&r!==\"..\"},Ibe=typeof process==\"object\"&&process?typeof process.env==\"object\"&&process.env&&process.env.__MINIMATCH_TESTING_PLATFORM__||process.platform:\"posix\",gbe={win32:{sep:\"\\\\\"},posix:{sep:\"/\"}};pr.sep=Ibe===\"win32\"?gbe.win32.sep:gbe.posix.sep;pr.minimatch.sep=pr.sep;pr.GLOBSTAR=Symbol(\"globstar **\");pr.minimatch.GLOBSTAR=pr.GLOBSTAR;var V2t=\"[^/]\",J2t=V2t+\"*?\",K2t=\"(?:(?!(?:\\\\/|^)(?:\\\\.{1,2})($|\\\\/)).)*?\",z2t=\"(?:(?!(?:\\\\/|^)\\\\.).)*?\",Z2t=(t,e={})=>r=>(0,pr.minimatch)(r,t,e);pr.filter=Z2t;pr.minimatch.filter=pr.filter;var tu=(t,e={})=>Object.assign({},t,e),X2t=t=>{if(!t||typeof t!=\"object\"||!Object.keys(t).length)return pr.minimatch;let e=pr.minimatch;return Object.assign((s,a,n={})=>e(s,a,tu(t,n)),{Minimatch:class extends e.Minimatch{constructor(a,n={}){super(a,tu(t,n))}static defaults(a){return e.defaults(tu(t,a)).Minimatch}},AST:class extends e.AST{constructor(a,n,c={}){super(a,n,tu(t,c))}static fromGlob(a,n={}){return e.AST.fromGlob(a,tu(t,n))}},unescape:(s,a={})=>e.unescape(s,tu(t,a)),escape:(s,a={})=>e.escape(s,tu(t,a)),filter:(s,a={})=>e.filter(s,tu(t,a)),defaults:s=>e.defaults(tu(t,s)),makeRe:(s,a={})=>e.makeRe(s,tu(t,a)),braceExpand:(s,a={})=>e.braceExpand(s,tu(t,a)),match:(s,a,n={})=>e.match(s,a,tu(t,n)),sep:e.sep,GLOBSTAR:pr.GLOBSTAR})};pr.defaults=X2t;pr.minimatch.defaults=pr.defaults;var $2t=(t,e={})=>((0,GO.assertValidPattern)(t),e.nobrace||!/\\{(?:(?!\\{).)*\\}/.test(t)?[t]:(0,S2t.default)(t));pr.braceExpand=$2t;pr.minimatch.braceExpand=pr.braceExpand;var eBt=(t,e={})=>new ly(t,e).makeRe();pr.makeRe=eBt;pr.minimatch.makeRe=pr.makeRe;var tBt=(t,e,r={})=>{let s=new ly(e,r);return t=t.filter(a=>s.match(a)),s.options.nonull&&!t.length&&t.push(e),t};pr.match=tBt;pr.minimatch.match=pr.match;var dbe=/[?*]|[+@!]\\(.*?\\)|\\[|\\]/,rBt=t=>t.replace(/[-[\\]{}()*+?.,\\\\^$|#\\s]/g,\"\\\\$&\"),ly=class{options;set;pattern;windowsPathsNoEscape;nonegate;negate;comment;empty;preserveMultipleSlashes;partial;globSet;globParts;nocase;isWindows;platform;windowsNoMagicRoot;regexp;constructor(e,r={}){(0,GO.assertValidPattern)(e),r=r||{},this.options=r,this.pattern=e,this.platform=r.platform||Ibe,this.isWindows=this.platform===\"win32\",this.windowsPathsNoEscape=!!r.windowsPathsNoEscape||r.allowWindowsEscape===!1,this.windowsPathsNoEscape&&(this.pattern=this.pattern.replace(/\\\\/g,\"/\")),this.preserveMultipleSlashes=!!r.preserveMultipleSlashes,this.regexp=null,this.negate=!1,this.nonegate=!!r.nonegate,this.comment=!1,this.empty=!1,this.partial=!!r.partial,this.nocase=!!this.options.nocase,this.windowsNoMagicRoot=r.windowsNoMagicRoot!==void 0?r.windowsNoMagicRoot:!!(this.isWindows&&this.nocase),this.globSet=[],this.globParts=[],this.set=[],this.make()}hasMagic(){if(this.options.magicalBraces&&this.set.length>1)return!0;for(let e of this.set)for(let r of e)if(typeof r!=\"string\")return!0;return!1}debug(...e){}make(){let e=this.pattern,r=this.options;if(!r.nocomment&&e.charAt(0)===\"#\"){this.comment=!0;return}if(!e){this.empty=!0;return}this.parseNegate(),this.globSet=[...new Set(this.braceExpand())],r.debug&&(this.debug=(...n)=>console.error(...n)),this.debug(this.pattern,this.globSet);let s=this.globSet.map(n=>this.slashSplit(n));this.globParts=this.preprocess(s),this.debug(this.pattern,this.globParts);let a=this.globParts.map((n,c,f)=>{if(this.isWindows&&this.windowsNoMagicRoot){let p=n[0]===\"\"&&n[1]===\"\"&&(n[2]===\"?\"||!dbe.test(n[2]))&&!dbe.test(n[3]),h=/^[a-z]:/i.test(n[0]);if(p)return[...n.slice(0,4),...n.slice(4).map(E=>this.parse(E))];if(h)return[n[0],...n.slice(1).map(E=>this.parse(E))]}return n.map(p=>this.parse(p))});if(this.debug(this.pattern,a),this.set=a.filter(n=>n.indexOf(!1)===-1),this.isWindows)for(let n=0;n<this.set.length;n++){let c=this.set[n];c[0]===\"\"&&c[1]===\"\"&&this.globParts[n][2]===\"?\"&&typeof c[3]==\"string\"&&/^[a-z]:$/i.test(c[3])&&(c[2]=\"?\")}this.debug(this.pattern,this.set)}preprocess(e){if(this.options.noglobstar)for(let s=0;s<e.length;s++)for(let a=0;a<e[s].length;a++)e[s][a]===\"**\"&&(e[s][a]=\"*\");let{optimizationLevel:r=1}=this.options;return r>=2?(e=this.firstPhasePreProcess(e),e=this.secondPhasePreProcess(e)):r>=1?e=this.levelOneOptimize(e):e=this.adjascentGlobstarOptimize(e),e}adjascentGlobstarOptimize(e){return e.map(r=>{let s=-1;for(;(s=r.indexOf(\"**\",s+1))!==-1;){let a=s;for(;r[a+1]===\"**\";)a++;a!==s&&r.splice(s,a-s)}return r})}levelOneOptimize(e){return e.map(r=>(r=r.reduce((s,a)=>{let n=s[s.length-1];return a===\"**\"&&n===\"**\"?s:a===\"..\"&&n&&n!==\"..\"&&n!==\".\"&&n!==\"**\"?(s.pop(),s):(s.push(a),s)},[]),r.length===0?[\"\"]:r))}levelTwoFileOptimize(e){Array.isArray(e)||(e=this.slashSplit(e));let r=!1;do{if(r=!1,!this.preserveMultipleSlashes){for(let a=1;a<e.length-1;a++){let n=e[a];a===1&&n===\"\"&&e[0]===\"\"||(n===\".\"||n===\"\")&&(r=!0,e.splice(a,1),a--)}e[0]===\".\"&&e.length===2&&(e[1]===\".\"||e[1]===\"\")&&(r=!0,e.pop())}let s=0;for(;(s=e.indexOf(\"..\",s+1))!==-1;){let a=e[s-1];a&&a!==\".\"&&a!==\"..\"&&a!==\"**\"&&(r=!0,e.splice(s-1,2),s-=2)}}while(r);return e.length===0?[\"\"]:e}firstPhasePreProcess(e){let r=!1;do{r=!1;for(let s of e){let a=-1;for(;(a=s.indexOf(\"**\",a+1))!==-1;){let c=a;for(;s[c+1]===\"**\";)c++;c>a&&s.splice(a+1,c-a);let f=s[a+1],p=s[a+2],h=s[a+3];if(f!==\"..\"||!p||p===\".\"||p===\"..\"||!h||h===\".\"||h===\"..\")continue;r=!0,s.splice(a,1);let E=s.slice(0);E[a]=\"**\",e.push(E),a--}if(!this.preserveMultipleSlashes){for(let c=1;c<s.length-1;c++){let f=s[c];c===1&&f===\"\"&&s[0]===\"\"||(f===\".\"||f===\"\")&&(r=!0,s.splice(c,1),c--)}s[0]===\".\"&&s.length===2&&(s[1]===\".\"||s[1]===\"\")&&(r=!0,s.pop())}let n=0;for(;(n=s.indexOf(\"..\",n+1))!==-1;){let c=s[n-1];if(c&&c!==\".\"&&c!==\"..\"&&c!==\"**\"){r=!0;let p=n===1&&s[n+1]===\"**\"?[\".\"]:[];s.splice(n-1,2,...p),s.length===0&&s.push(\"\"),n-=2}}}}while(r);return e}secondPhasePreProcess(e){for(let r=0;r<e.length-1;r++)for(let s=r+1;s<e.length;s++){let a=this.partsMatch(e[r],e[s],!this.preserveMultipleSlashes);if(a){e[r]=[],e[s]=a;break}}return e.filter(r=>r.length)}partsMatch(e,r,s=!1){let a=0,n=0,c=[],f=\"\";for(;a<e.length&&n<r.length;)if(e[a]===r[n])c.push(f===\"b\"?r[n]:e[a]),a++,n++;else if(s&&e[a]===\"**\"&&r[n]===e[a+1])c.push(e[a]),a++;else if(s&&r[n]===\"**\"&&e[a]===r[n+1])c.push(r[n]),n++;else if(e[a]===\"*\"&&r[n]&&(this.options.dot||!r[n].startsWith(\".\"))&&r[n]!==\"**\"){if(f===\"b\")return!1;f=\"a\",c.push(e[a]),a++,n++}else if(r[n]===\"*\"&&e[a]&&(this.options.dot||!e[a].startsWith(\".\"))&&e[a]!==\"**\"){if(f===\"a\")return!1;f=\"b\",c.push(r[n]),a++,n++}else return!1;return e.length===r.length&&c}parseNegate(){if(this.nonegate)return;let e=this.pattern,r=!1,s=0;for(let a=0;a<e.length&&e.charAt(a)===\"!\";a++)r=!r,s++;s&&(this.pattern=e.slice(s)),this.negate=r}matchOne(e,r,s=!1){let a=this.options;if(this.isWindows){let T=typeof e[0]==\"string\"&&/^[a-z]:$/i.test(e[0]),N=!T&&e[0]===\"\"&&e[1]===\"\"&&e[2]===\"?\"&&/^[a-z]:$/i.test(e[3]),U=typeof r[0]==\"string\"&&/^[a-z]:$/i.test(r[0]),W=!U&&r[0]===\"\"&&r[1]===\"\"&&r[2]===\"?\"&&typeof r[3]==\"string\"&&/^[a-z]:$/i.test(r[3]),ee=N?3:T?0:void 0,ie=W?3:U?0:void 0;if(typeof ee==\"number\"&&typeof ie==\"number\"){let[ue,le]=[e[ee],r[ie]];ue.toLowerCase()===le.toLowerCase()&&(r[ie]=ue,ie>ee?r=r.slice(ie):ee>ie&&(e=e.slice(ee)))}}let{optimizationLevel:n=1}=this.options;n>=2&&(e=this.levelTwoFileOptimize(e)),this.debug(\"matchOne\",this,{file:e,pattern:r}),this.debug(\"matchOne\",e.length,r.length);for(var c=0,f=0,p=e.length,h=r.length;c<p&&f<h;c++,f++){this.debug(\"matchOne loop\");var E=r[f],C=e[c];if(this.debug(r,E,C),E===!1)return!1;if(E===pr.GLOBSTAR){this.debug(\"GLOBSTAR\",[r,E,C]);var S=c,b=f+1;if(b===h){for(this.debug(\"** at the end\");c<p;c++)if(e[c]===\".\"||e[c]===\"..\"||!a.dot&&e[c].charAt(0)===\".\")return!1;return!0}for(;S<p;){var I=e[S];if(this.debug(`\nglobstar while`,e,S,r,b,I),this.matchOne(e.slice(S),r.slice(b),s))return this.debug(\"globstar found match!\",S,p,I),!0;if(I===\".\"||I===\"..\"||!a.dot&&I.charAt(0)===\".\"){this.debug(\"dot detected!\",e,S,r,b);break}this.debug(\"globstar swallow a segment, and continue\"),S++}return!!(s&&(this.debug(`\n>>> no match, partial?`,e,S,r,b),S===p))}let T;if(typeof E==\"string\"?(T=C===E,this.debug(\"string match\",E,C,T)):(T=E.test(C),this.debug(\"pattern match\",E,C,T)),!T)return!1}if(c===p&&f===h)return!0;if(c===p)return s;if(f===h)return c===p-1&&e[c]===\"\";throw new Error(\"wtf?\")}braceExpand(){return(0,pr.braceExpand)(this.pattern,this.options)}parse(e){(0,GO.assertValidPattern)(e);let r=this.options;if(e===\"**\")return pr.GLOBSTAR;if(e===\"\")return\"\";let s,a=null;(s=e.match(U2t))?a=r.dot?H2t:_2t:(s=e.match(x2t))?a=(r.nocase?r.dot?T2t:R2t:r.dot?Q2t:k2t)(s[1]):(s=e.match(j2t))?a=(r.nocase?r.dot?q2t:G2t:r.dot?W2t:Y2t)(s):(s=e.match(F2t))?a=r.dot?O2t:N2t:(s=e.match(L2t))&&(a=M2t);let n=mbe.AST.fromGlob(e,this.options).toMMPattern();return a&&typeof n==\"object\"&&Reflect.defineProperty(n,\"test\",{value:a}),n}makeRe(){if(this.regexp||this.regexp===!1)return this.regexp;let e=this.set;if(!e.length)return this.regexp=!1,this.regexp;let r=this.options,s=r.noglobstar?J2t:r.dot?K2t:z2t,a=new Set(r.nocase?[\"i\"]:[]),n=e.map(p=>{let h=p.map(E=>{if(E instanceof RegExp)for(let C of E.flags.split(\"\"))a.add(C);return typeof E==\"string\"?rBt(E):E===pr.GLOBSTAR?pr.GLOBSTAR:E._src});return h.forEach((E,C)=>{let S=h[C+1],b=h[C-1];E!==pr.GLOBSTAR||b===pr.GLOBSTAR||(b===void 0?S!==void 0&&S!==pr.GLOBSTAR?h[C+1]=\"(?:\\\\/|\"+s+\"\\\\/)?\"+S:h[C]=s:S===void 0?h[C-1]=b+\"(?:\\\\/|\"+s+\")?\":S!==pr.GLOBSTAR&&(h[C-1]=b+\"(?:\\\\/|\\\\/\"+s+\"\\\\/)\"+S,h[C+1]=pr.GLOBSTAR))}),h.filter(E=>E!==pr.GLOBSTAR).join(\"/\")}).join(\"|\"),[c,f]=e.length>1?[\"(?:\",\")\"]:[\"\",\"\"];n=\"^\"+c+n+f+\"$\",this.negate&&(n=\"^(?!\"+n+\").+$\");try{this.regexp=new RegExp(n,[...a].join(\"\"))}catch{this.regexp=!1}return this.regexp}slashSplit(e){return this.preserveMultipleSlashes?e.split(\"/\"):this.isWindows&&/^\\/\\/[^\\/]+/.test(e)?[\"\",...e.split(/\\/+/)]:e.split(/\\/+/)}match(e,r=this.partial){if(this.debug(\"match\",e,this.pattern),this.comment)return!1;if(this.empty)return e===\"\";if(e===\"/\"&&r)return!0;let s=this.options;this.isWindows&&(e=e.split(\"\\\\\").join(\"/\"));let a=this.slashSplit(e);this.debug(this.pattern,\"split\",a);let n=this.set;this.debug(this.pattern,\"set\",n);let c=a[a.length-1];if(!c)for(let f=a.length-2;!c&&f>=0;f--)c=a[f];for(let f=0;f<n.length;f++){let p=n[f],h=a;if(s.matchBase&&p.length===1&&(h=[c]),this.matchOne(h,p,r))return s.flipNegate?!0:!this.negate}return s.flipNegate?!1:this.negate}static defaults(e){return pr.minimatch.defaults(e).Minimatch}};pr.Minimatch=ly;var nBt=eJ();Object.defineProperty(pr,\"AST\",{enumerable:!0,get:function(){return nBt.AST}});var iBt=tJ();Object.defineProperty(pr,\"escape\",{enumerable:!0,get:function(){return iBt.escape}});var sBt=MO();Object.defineProperty(pr,\"unescape\",{enumerable:!0,get:function(){return sBt.unescape}});pr.minimatch.AST=mbe.AST;pr.minimatch.Minimatch=ly;pr.minimatch.escape=D2t.escape;pr.minimatch.unescape=P2t.unescape});var iJ=_(ru=>{\"use strict\";var wbe=ru&&ru.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(ru,\"__esModule\",{value:!0});ru.SuccinctRoles=ru.DelegatedRole=ru.Role=ru.TOP_LEVEL_ROLE_NAMES=void 0;var Bbe=wbe(Ie(\"crypto\")),oBt=Cbe(),qO=wbe(Ie(\"util\")),WO=bA(),cy=ff();ru.TOP_LEVEL_ROLE_NAMES=[\"root\",\"targets\",\"snapshot\",\"timestamp\"];var LP=class t{constructor(e){let{keyIDs:r,threshold:s,unrecognizedFields:a}=e;if(aBt(r))throw new WO.ValueError(\"duplicate key IDs found\");if(s<1)throw new WO.ValueError(\"threshold must be at least 1\");this.keyIDs=r,this.threshold=s,this.unrecognizedFields=a||{}}equals(e){return e instanceof t?this.threshold===e.threshold&&qO.default.isDeepStrictEqual(this.keyIDs,e.keyIDs)&&qO.default.isDeepStrictEqual(this.unrecognizedFields,e.unrecognizedFields):!1}toJSON(){return{keyids:this.keyIDs,threshold:this.threshold,...this.unrecognizedFields}}static fromJSON(e){let{keyids:r,threshold:s,...a}=e;if(!cy.guard.isStringArray(r))throw new TypeError(\"keyids must be an array\");if(typeof s!=\"number\")throw new TypeError(\"threshold must be a number\");return new t({keyIDs:r,threshold:s,unrecognizedFields:a})}};ru.Role=LP;function aBt(t){return new Set(t).size!==t.length}var rJ=class t extends LP{constructor(e){super(e);let{name:r,terminating:s,paths:a,pathHashPrefixes:n}=e;if(this.name=r,this.terminating=s,e.paths&&e.pathHashPrefixes)throw new WO.ValueError(\"paths and pathHashPrefixes are mutually exclusive\");this.paths=a,this.pathHashPrefixes=n}equals(e){return e instanceof t?super.equals(e)&&this.name===e.name&&this.terminating===e.terminating&&qO.default.isDeepStrictEqual(this.paths,e.paths)&&qO.default.isDeepStrictEqual(this.pathHashPrefixes,e.pathHashPrefixes):!1}isDelegatedPath(e){if(this.paths)return this.paths.some(r=>cBt(e,r));if(this.pathHashPrefixes){let s=Bbe.default.createHash(\"sha256\").update(e).digest(\"hex\");return this.pathHashPrefixes.some(a=>s.startsWith(a))}return!1}toJSON(){let e={...super.toJSON(),name:this.name,terminating:this.terminating};return this.paths&&(e.paths=this.paths),this.pathHashPrefixes&&(e.path_hash_prefixes=this.pathHashPrefixes),e}static fromJSON(e){let{keyids:r,threshold:s,name:a,terminating:n,paths:c,path_hash_prefixes:f,...p}=e;if(!cy.guard.isStringArray(r))throw new TypeError(\"keyids must be an array of strings\");if(typeof s!=\"number\")throw new TypeError(\"threshold must be a number\");if(typeof a!=\"string\")throw new TypeError(\"name must be a string\");if(typeof n!=\"boolean\")throw new TypeError(\"terminating must be a boolean\");if(cy.guard.isDefined(c)&&!cy.guard.isStringArray(c))throw new TypeError(\"paths must be an array of strings\");if(cy.guard.isDefined(f)&&!cy.guard.isStringArray(f))throw new TypeError(\"path_hash_prefixes must be an array of strings\");return new t({keyIDs:r,threshold:s,name:a,terminating:n,paths:c,pathHashPrefixes:f,unrecognizedFields:p})}};ru.DelegatedRole=rJ;var lBt=(t,e)=>t.map((r,s)=>[r,e[s]]);function cBt(t,e){let r=t.split(\"/\"),s=e.split(\"/\");return s.length!=r.length?!1:lBt(r,s).every(([a,n])=>(0,oBt.minimatch)(a,n))}var nJ=class t extends LP{constructor(e){super(e);let{bitLength:r,namePrefix:s}=e;if(r<=0||r>32)throw new WO.ValueError(\"bitLength must be between 1 and 32\");this.bitLength=r,this.namePrefix=s,this.numberOfBins=Math.pow(2,r),this.suffixLen=(this.numberOfBins-1).toString(16).length}equals(e){return e instanceof t?super.equals(e)&&this.bitLength===e.bitLength&&this.namePrefix===e.namePrefix:!1}getRoleForTarget(e){let a=Bbe.default.createHash(\"sha256\").update(e).digest().subarray(0,4),n=32-this.bitLength,f=(a.readUInt32BE()>>>n).toString(16).padStart(this.suffixLen,\"0\");return`${this.namePrefix}-${f}`}*getRoles(){for(let e=0;e<this.numberOfBins;e++){let r=e.toString(16).padStart(this.suffixLen,\"0\");yield`${this.namePrefix}-${r}`}}isDelegatedRole(e){let r=this.namePrefix+\"-\";if(!e.startsWith(r))return!1;let s=e.slice(r.length,e.length);if(s.length!=this.suffixLen||!s.match(/^[0-9a-fA-F]+$/))return!1;let a=parseInt(s,16);return 0<=a&&a<this.numberOfBins}toJSON(){return{...super.toJSON(),bit_length:this.bitLength,name_prefix:this.namePrefix}}static fromJSON(e){let{keyids:r,threshold:s,bit_length:a,name_prefix:n,...c}=e;if(!cy.guard.isStringArray(r))throw new TypeError(\"keyids must be an array of strings\");if(typeof s!=\"number\")throw new TypeError(\"threshold must be a number\");if(typeof a!=\"number\")throw new TypeError(\"bit_length must be a number\");if(typeof n!=\"string\")throw new TypeError(\"name_prefix must be a string\");return new t({keyIDs:r,threshold:s,bitLength:a,namePrefix:n,unrecognizedFields:c})}};ru.SuccinctRoles=nJ});var aJ=_(a1=>{\"use strict\";var uBt=a1&&a1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(a1,\"__esModule\",{value:!0});a1.Root=void 0;var vbe=uBt(Ie(\"util\")),sJ=ay(),Sbe=bA(),fBt=FO(),YO=iJ(),VO=ff(),oJ=class t extends sJ.Signed{constructor(e){if(super(e),this.type=sJ.MetadataKind.Root,this.keys=e.keys||{},this.consistentSnapshot=e.consistentSnapshot??!0,!e.roles)this.roles=YO.TOP_LEVEL_ROLE_NAMES.reduce((r,s)=>({...r,[s]:new YO.Role({keyIDs:[],threshold:1})}),{});else{let r=new Set(Object.keys(e.roles));if(!YO.TOP_LEVEL_ROLE_NAMES.every(s=>r.has(s)))throw new Sbe.ValueError(\"missing top-level role\");this.roles=e.roles}}addKey(e,r){if(!this.roles[r])throw new Sbe.ValueError(`role ${r} does not exist`);this.roles[r].keyIDs.includes(e.keyID)||this.roles[r].keyIDs.push(e.keyID),this.keys[e.keyID]=e}equals(e){return e instanceof t?super.equals(e)&&this.consistentSnapshot===e.consistentSnapshot&&vbe.default.isDeepStrictEqual(this.keys,e.keys)&&vbe.default.isDeepStrictEqual(this.roles,e.roles):!1}toJSON(){return{_type:this.type,spec_version:this.specVersion,version:this.version,expires:this.expires,keys:ABt(this.keys),roles:pBt(this.roles),consistent_snapshot:this.consistentSnapshot,...this.unrecognizedFields}}static fromJSON(e){let{unrecognizedFields:r,...s}=sJ.Signed.commonFieldsFromJSON(e),{keys:a,roles:n,consistent_snapshot:c,...f}=r;if(typeof c!=\"boolean\")throw new TypeError(\"consistent_snapshot must be a boolean\");return new t({...s,keys:hBt(a),roles:gBt(n),consistentSnapshot:c,unrecognizedFields:f})}};a1.Root=oJ;function ABt(t){return Object.entries(t).reduce((e,[r,s])=>({...e,[r]:s.toJSON()}),{})}function pBt(t){return Object.entries(t).reduce((e,[r,s])=>({...e,[r]:s.toJSON()}),{})}function hBt(t){let e;if(VO.guard.isDefined(t)){if(!VO.guard.isObjectRecord(t))throw new TypeError(\"keys must be an object\");e=Object.entries(t).reduce((r,[s,a])=>({...r,[s]:fBt.Key.fromJSON(s,a)}),{})}return e}function gBt(t){let e;if(VO.guard.isDefined(t)){if(!VO.guard.isObjectRecord(t))throw new TypeError(\"roles must be an object\");e=Object.entries(t).reduce((r,[s,a])=>({...r,[s]:YO.Role.fromJSON(a)}),{})}return e}});var cJ=_(JO=>{\"use strict\";Object.defineProperty(JO,\"__esModule\",{value:!0});JO.Signature=void 0;var lJ=class t{constructor(e){let{keyID:r,sig:s}=e;this.keyID=r,this.sig=s}toJSON(){return{keyid:this.keyID,sig:this.sig}}static fromJSON(e){let{keyid:r,sig:s}=e;if(typeof r!=\"string\")throw new TypeError(\"keyid must be a string\");if(typeof s!=\"string\")throw new TypeError(\"sig must be a string\");return new t({keyID:r,sig:s})}};JO.Signature=lJ});var AJ=_(l1=>{\"use strict\";var dBt=l1&&l1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(l1,\"__esModule\",{value:!0});l1.Snapshot=void 0;var mBt=dBt(Ie(\"util\")),uJ=ay(),Pbe=QP(),Dbe=ff(),fJ=class t extends uJ.Signed{constructor(e){super(e),this.type=uJ.MetadataKind.Snapshot,this.meta=e.meta||{\"targets.json\":new Pbe.MetaFile({version:1})}}equals(e){return e instanceof t?super.equals(e)&&mBt.default.isDeepStrictEqual(this.meta,e.meta):!1}toJSON(){return{_type:this.type,meta:yBt(this.meta),spec_version:this.specVersion,version:this.version,expires:this.expires,...this.unrecognizedFields}}static fromJSON(e){let{unrecognizedFields:r,...s}=uJ.Signed.commonFieldsFromJSON(e),{meta:a,...n}=r;return new t({...s,meta:EBt(a),unrecognizedFields:n})}};l1.Snapshot=fJ;function yBt(t){return Object.entries(t).reduce((e,[r,s])=>({...e,[r]:s.toJSON()}),{})}function EBt(t){let e;if(Dbe.guard.isDefined(t))if(Dbe.guard.isObjectRecord(t))e=Object.entries(t).reduce((r,[s,a])=>({...r,[s]:Pbe.MetaFile.fromJSON(a)}),{});else throw new TypeError(\"meta field is malformed\");return e}});var bbe=_(c1=>{\"use strict\";var IBt=c1&&c1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(c1,\"__esModule\",{value:!0});c1.Delegations=void 0;var KO=IBt(Ie(\"util\")),CBt=bA(),wBt=FO(),pJ=iJ(),zO=ff(),hJ=class t{constructor(e){if(this.keys=e.keys,this.unrecognizedFields=e.unrecognizedFields||{},e.roles&&Object.keys(e.roles).some(r=>pJ.TOP_LEVEL_ROLE_NAMES.includes(r)))throw new CBt.ValueError(\"Delegated role name conflicts with top-level role name\");this.succinctRoles=e.succinctRoles,this.roles=e.roles}equals(e){return e instanceof t?KO.default.isDeepStrictEqual(this.keys,e.keys)&&KO.default.isDeepStrictEqual(this.roles,e.roles)&&KO.default.isDeepStrictEqual(this.unrecognizedFields,e.unrecognizedFields)&&KO.default.isDeepStrictEqual(this.succinctRoles,e.succinctRoles):!1}*rolesForTarget(e){if(this.roles)for(let r of Object.values(this.roles))r.isDelegatedPath(e)&&(yield{role:r.name,terminating:r.terminating});else this.succinctRoles&&(yield{role:this.succinctRoles.getRoleForTarget(e),terminating:!0})}toJSON(){let e={keys:BBt(this.keys),...this.unrecognizedFields};return this.roles?e.roles=vBt(this.roles):this.succinctRoles&&(e.succinct_roles=this.succinctRoles.toJSON()),e}static fromJSON(e){let{keys:r,roles:s,succinct_roles:a,...n}=e,c;return zO.guard.isObject(a)&&(c=pJ.SuccinctRoles.fromJSON(a)),new t({keys:SBt(r),roles:DBt(s),unrecognizedFields:n,succinctRoles:c})}};c1.Delegations=hJ;function BBt(t){return Object.entries(t).reduce((e,[r,s])=>({...e,[r]:s.toJSON()}),{})}function vBt(t){return Object.values(t).map(e=>e.toJSON())}function SBt(t){if(!zO.guard.isObjectRecord(t))throw new TypeError(\"keys is malformed\");return Object.entries(t).reduce((e,[r,s])=>({...e,[r]:wBt.Key.fromJSON(r,s)}),{})}function DBt(t){let e;if(zO.guard.isDefined(t)){if(!zO.guard.isObjectArray(t))throw new TypeError(\"roles is malformed\");e=t.reduce((r,s)=>{let a=pJ.DelegatedRole.fromJSON(s);return{...r,[a.name]:a}},{})}return e}});var mJ=_(u1=>{\"use strict\";var PBt=u1&&u1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(u1,\"__esModule\",{value:!0});u1.Targets=void 0;var xbe=PBt(Ie(\"util\")),gJ=ay(),bBt=bbe(),xBt=QP(),ZO=ff(),dJ=class t extends gJ.Signed{constructor(e){super(e),this.type=gJ.MetadataKind.Targets,this.targets=e.targets||{},this.delegations=e.delegations}addTarget(e){this.targets[e.path]=e}equals(e){return e instanceof t?super.equals(e)&&xbe.default.isDeepStrictEqual(this.targets,e.targets)&&xbe.default.isDeepStrictEqual(this.delegations,e.delegations):!1}toJSON(){let e={_type:this.type,spec_version:this.specVersion,version:this.version,expires:this.expires,targets:kBt(this.targets),...this.unrecognizedFields};return this.delegations&&(e.delegations=this.delegations.toJSON()),e}static fromJSON(e){let{unrecognizedFields:r,...s}=gJ.Signed.commonFieldsFromJSON(e),{targets:a,delegations:n,...c}=r;return new t({...s,targets:QBt(a),delegations:RBt(n),unrecognizedFields:c})}};u1.Targets=dJ;function kBt(t){return Object.entries(t).reduce((e,[r,s])=>({...e,[r]:s.toJSON()}),{})}function QBt(t){let e;if(ZO.guard.isDefined(t))if(ZO.guard.isObjectRecord(t))e=Object.entries(t).reduce((r,[s,a])=>({...r,[s]:xBt.TargetFile.fromJSON(s,a)}),{});else throw new TypeError(\"targets must be an object\");return e}function RBt(t){let e;if(ZO.guard.isDefined(t))if(ZO.guard.isObject(t))e=bBt.Delegations.fromJSON(t);else throw new TypeError(\"delegations must be an object\");return e}});var CJ=_(XO=>{\"use strict\";Object.defineProperty(XO,\"__esModule\",{value:!0});XO.Timestamp=void 0;var yJ=ay(),kbe=QP(),EJ=ff(),IJ=class t extends yJ.Signed{constructor(e){super(e),this.type=yJ.MetadataKind.Timestamp,this.snapshotMeta=e.snapshotMeta||new kbe.MetaFile({version:1})}equals(e){return e instanceof t?super.equals(e)&&this.snapshotMeta.equals(e.snapshotMeta):!1}toJSON(){return{_type:this.type,spec_version:this.specVersion,version:this.version,expires:this.expires,meta:{\"snapshot.json\":this.snapshotMeta.toJSON()},...this.unrecognizedFields}}static fromJSON(e){let{unrecognizedFields:r,...s}=yJ.Signed.commonFieldsFromJSON(e),{meta:a,...n}=r;return new t({...s,snapshotMeta:TBt(a),unrecognizedFields:n})}};XO.Timestamp=IJ;function TBt(t){let e;if(EJ.guard.isDefined(t)){let r=t[\"snapshot.json\"];if(!EJ.guard.isDefined(r)||!EJ.guard.isObject(r))throw new TypeError(\"missing snapshot.json in meta\");e=kbe.MetaFile.fromJSON(r)}return e}});var Rbe=_(A1=>{\"use strict\";var FBt=A1&&A1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(A1,\"__esModule\",{value:!0});A1.Metadata=void 0;var NBt=_7(),Qbe=FBt(Ie(\"util\")),f1=ay(),MP=bA(),OBt=aJ(),LBt=cJ(),MBt=AJ(),UBt=mJ(),_Bt=CJ(),wJ=ff(),BJ=class t{constructor(e,r,s){this.signed=e,this.signatures=r||{},this.unrecognizedFields=s||{}}sign(e,r=!0){let s=Buffer.from((0,NBt.canonicalize)(this.signed.toJSON())),a=e(s);r||(this.signatures={}),this.signatures[a.keyID]=a}verifyDelegate(e,r){let s,a={};switch(this.signed.type){case f1.MetadataKind.Root:a=this.signed.keys,s=this.signed.roles[e];break;case f1.MetadataKind.Targets:if(!this.signed.delegations)throw new MP.ValueError(`No delegations found for ${e}`);a=this.signed.delegations.keys,this.signed.delegations.roles?s=this.signed.delegations.roles[e]:this.signed.delegations.succinctRoles&&this.signed.delegations.succinctRoles.isDelegatedRole(e)&&(s=this.signed.delegations.succinctRoles);break;default:throw new TypeError(\"invalid metadata type\")}if(!s)throw new MP.ValueError(`no delegation found for ${e}`);let n=new Set;if(s.keyIDs.forEach(c=>{let f=a[c];if(f)try{f.verifySignature(r),n.add(f.keyID)}catch{}}),n.size<s.threshold)throw new MP.UnsignedMetadataError(`${e} was signed by ${n.size}/${s.threshold} keys`)}equals(e){return e instanceof t?this.signed.equals(e.signed)&&Qbe.default.isDeepStrictEqual(this.signatures,e.signatures)&&Qbe.default.isDeepStrictEqual(this.unrecognizedFields,e.unrecognizedFields):!1}toJSON(){return{signatures:Object.values(this.signatures).map(r=>r.toJSON()),signed:this.signed.toJSON(),...this.unrecognizedFields}}static fromJSON(e,r){let{signed:s,signatures:a,...n}=r;if(!wJ.guard.isDefined(s)||!wJ.guard.isObject(s))throw new TypeError(\"signed is not defined\");if(e!==s._type)throw new MP.ValueError(`expected '${e}', got ${s._type}`);if(!wJ.guard.isObjectArray(a))throw new TypeError(\"signatures is not an array\");let c;switch(e){case f1.MetadataKind.Root:c=OBt.Root.fromJSON(s);break;case f1.MetadataKind.Timestamp:c=_Bt.Timestamp.fromJSON(s);break;case f1.MetadataKind.Snapshot:c=MBt.Snapshot.fromJSON(s);break;case f1.MetadataKind.Targets:c=UBt.Targets.fromJSON(s);break;default:throw new TypeError(\"invalid metadata type\")}let f={};return a.forEach(p=>{let h=LBt.Signature.fromJSON(p);if(f[h.keyID])throw new MP.ValueError(`multiple signatures found for keyid: ${h.keyID}`);f[h.keyID]=h}),new t(c,f,n)}};A1.Metadata=BJ});var $O=_(Fi=>{\"use strict\";Object.defineProperty(Fi,\"__esModule\",{value:!0});Fi.Timestamp=Fi.Targets=Fi.Snapshot=Fi.Signature=Fi.Root=Fi.Metadata=Fi.Key=Fi.TargetFile=Fi.MetaFile=Fi.ValueError=Fi.MetadataKind=void 0;var HBt=ay();Object.defineProperty(Fi,\"MetadataKind\",{enumerable:!0,get:function(){return HBt.MetadataKind}});var jBt=bA();Object.defineProperty(Fi,\"ValueError\",{enumerable:!0,get:function(){return jBt.ValueError}});var Tbe=QP();Object.defineProperty(Fi,\"MetaFile\",{enumerable:!0,get:function(){return Tbe.MetaFile}});Object.defineProperty(Fi,\"TargetFile\",{enumerable:!0,get:function(){return Tbe.TargetFile}});var GBt=FO();Object.defineProperty(Fi,\"Key\",{enumerable:!0,get:function(){return GBt.Key}});var qBt=Rbe();Object.defineProperty(Fi,\"Metadata\",{enumerable:!0,get:function(){return qBt.Metadata}});var WBt=aJ();Object.defineProperty(Fi,\"Root\",{enumerable:!0,get:function(){return WBt.Root}});var YBt=cJ();Object.defineProperty(Fi,\"Signature\",{enumerable:!0,get:function(){return YBt.Signature}});var VBt=AJ();Object.defineProperty(Fi,\"Snapshot\",{enumerable:!0,get:function(){return VBt.Snapshot}});var JBt=mJ();Object.defineProperty(Fi,\"Targets\",{enumerable:!0,get:function(){return JBt.Targets}});var KBt=CJ();Object.defineProperty(Fi,\"Timestamp\",{enumerable:!0,get:function(){return KBt.Timestamp}})});var Nbe=_((air,Fbe)=>{var p1=1e3,h1=p1*60,g1=h1*60,uy=g1*24,zBt=uy*7,ZBt=uy*365.25;Fbe.exports=function(t,e){e=e||{};var r=typeof t;if(r===\"string\"&&t.length>0)return XBt(t);if(r===\"number\"&&isFinite(t))return e.long?evt(t):$Bt(t);throw new Error(\"val is not a non-empty string or a valid number. val=\"+JSON.stringify(t))};function XBt(t){if(t=String(t),!(t.length>100)){var e=/^(-?(?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(t);if(e){var r=parseFloat(e[1]),s=(e[2]||\"ms\").toLowerCase();switch(s){case\"years\":case\"year\":case\"yrs\":case\"yr\":case\"y\":return r*ZBt;case\"weeks\":case\"week\":case\"w\":return r*zBt;case\"days\":case\"day\":case\"d\":return r*uy;case\"hours\":case\"hour\":case\"hrs\":case\"hr\":case\"h\":return r*g1;case\"minutes\":case\"minute\":case\"mins\":case\"min\":case\"m\":return r*h1;case\"seconds\":case\"second\":case\"secs\":case\"sec\":case\"s\":return r*p1;case\"milliseconds\":case\"millisecond\":case\"msecs\":case\"msec\":case\"ms\":return r;default:return}}}}function $Bt(t){var e=Math.abs(t);return e>=uy?Math.round(t/uy)+\"d\":e>=g1?Math.round(t/g1)+\"h\":e>=h1?Math.round(t/h1)+\"m\":e>=p1?Math.round(t/p1)+\"s\":t+\"ms\"}function evt(t){var e=Math.abs(t);return e>=uy?eL(t,e,uy,\"day\"):e>=g1?eL(t,e,g1,\"hour\"):e>=h1?eL(t,e,h1,\"minute\"):e>=p1?eL(t,e,p1,\"second\"):t+\" ms\"}function eL(t,e,r,s){var a=e>=r*1.5;return Math.round(t/r)+\" \"+s+(a?\"s\":\"\")}});var vJ=_((lir,Obe)=>{function tvt(t){r.debug=r,r.default=r,r.coerce=p,r.disable=c,r.enable=a,r.enabled=f,r.humanize=Nbe(),r.destroy=h,Object.keys(t).forEach(E=>{r[E]=t[E]}),r.names=[],r.skips=[],r.formatters={};function e(E){let C=0;for(let S=0;S<E.length;S++)C=(C<<5)-C+E.charCodeAt(S),C|=0;return r.colors[Math.abs(C)%r.colors.length]}r.selectColor=e;function r(E){let C,S=null,b,I;function T(...N){if(!T.enabled)return;let U=T,W=Number(new Date),ee=W-(C||W);U.diff=ee,U.prev=C,U.curr=W,C=W,N[0]=r.coerce(N[0]),typeof N[0]!=\"string\"&&N.unshift(\"%O\");let ie=0;N[0]=N[0].replace(/%([a-zA-Z%])/g,(le,me)=>{if(le===\"%%\")return\"%\";ie++;let pe=r.formatters[me];if(typeof pe==\"function\"){let Be=N[ie];le=pe.call(U,Be),N.splice(ie,1),ie--}return le}),r.formatArgs.call(U,N),(U.log||r.log).apply(U,N)}return T.namespace=E,T.useColors=r.useColors(),T.color=r.selectColor(E),T.extend=s,T.destroy=r.destroy,Object.defineProperty(T,\"enabled\",{enumerable:!0,configurable:!1,get:()=>S!==null?S:(b!==r.namespaces&&(b=r.namespaces,I=r.enabled(E)),I),set:N=>{S=N}}),typeof r.init==\"function\"&&r.init(T),T}function s(E,C){let S=r(this.namespace+(typeof C>\"u\"?\":\":C)+E);return S.log=this.log,S}function a(E){r.save(E),r.namespaces=E,r.names=[],r.skips=[];let C=(typeof E==\"string\"?E:\"\").trim().replace(\" \",\",\").split(\",\").filter(Boolean);for(let S of C)S[0]===\"-\"?r.skips.push(S.slice(1)):r.names.push(S)}function n(E,C){let S=0,b=0,I=-1,T=0;for(;S<E.length;)if(b<C.length&&(C[b]===E[S]||C[b]===\"*\"))C[b]===\"*\"?(I=b,T=S,b++):(S++,b++);else if(I!==-1)b=I+1,T++,S=T;else return!1;for(;b<C.length&&C[b]===\"*\";)b++;return b===C.length}function c(){let E=[...r.names,...r.skips.map(C=>\"-\"+C)].join(\",\");return r.enable(\"\"),E}function f(E){for(let C of r.skips)if(n(E,C))return!1;for(let C of r.names)if(n(E,C))return!0;return!1}function p(E){return E instanceof Error?E.stack||E.message:E}function h(){console.warn(\"Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.\")}return r.enable(r.load()),r}Obe.exports=tvt});var Lbe=_((sc,tL)=>{sc.formatArgs=nvt;sc.save=ivt;sc.load=svt;sc.useColors=rvt;sc.storage=ovt();sc.destroy=(()=>{let t=!1;return()=>{t||(t=!0,console.warn(\"Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.\"))}})();sc.colors=[\"#0000CC\",\"#0000FF\",\"#0033CC\",\"#0033FF\",\"#0066CC\",\"#0066FF\",\"#0099CC\",\"#0099FF\",\"#00CC00\",\"#00CC33\",\"#00CC66\",\"#00CC99\",\"#00CCCC\",\"#00CCFF\",\"#3300CC\",\"#3300FF\",\"#3333CC\",\"#3333FF\",\"#3366CC\",\"#3366FF\",\"#3399CC\",\"#3399FF\",\"#33CC00\",\"#33CC33\",\"#33CC66\",\"#33CC99\",\"#33CCCC\",\"#33CCFF\",\"#6600CC\",\"#6600FF\",\"#6633CC\",\"#6633FF\",\"#66CC00\",\"#66CC33\",\"#9900CC\",\"#9900FF\",\"#9933CC\",\"#9933FF\",\"#99CC00\",\"#99CC33\",\"#CC0000\",\"#CC0033\",\"#CC0066\",\"#CC0099\",\"#CC00CC\",\"#CC00FF\",\"#CC3300\",\"#CC3333\",\"#CC3366\",\"#CC3399\",\"#CC33CC\",\"#CC33FF\",\"#CC6600\",\"#CC6633\",\"#CC9900\",\"#CC9933\",\"#CCCC00\",\"#CCCC33\",\"#FF0000\",\"#FF0033\",\"#FF0066\",\"#FF0099\",\"#FF00CC\",\"#FF00FF\",\"#FF3300\",\"#FF3333\",\"#FF3366\",\"#FF3399\",\"#FF33CC\",\"#FF33FF\",\"#FF6600\",\"#FF6633\",\"#FF9900\",\"#FF9933\",\"#FFCC00\",\"#FFCC33\"];function rvt(){if(typeof window<\"u\"&&window.process&&(window.process.type===\"renderer\"||window.process.__nwjs))return!0;if(typeof navigator<\"u\"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\\/(\\d+)/))return!1;let t;return typeof document<\"u\"&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||typeof window<\"u\"&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||typeof navigator<\"u\"&&navigator.userAgent&&(t=navigator.userAgent.toLowerCase().match(/firefox\\/(\\d+)/))&&parseInt(t[1],10)>=31||typeof navigator<\"u\"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\\/(\\d+)/)}function nvt(t){if(t[0]=(this.useColors?\"%c\":\"\")+this.namespace+(this.useColors?\" %c\":\" \")+t[0]+(this.useColors?\"%c \":\" \")+\"+\"+tL.exports.humanize(this.diff),!this.useColors)return;let e=\"color: \"+this.color;t.splice(1,0,e,\"color: inherit\");let r=0,s=0;t[0].replace(/%[a-zA-Z%]/g,a=>{a!==\"%%\"&&(r++,a===\"%c\"&&(s=r))}),t.splice(s,0,e)}sc.log=console.debug||console.log||(()=>{});function ivt(t){try{t?sc.storage.setItem(\"debug\",t):sc.storage.removeItem(\"debug\")}catch{}}function svt(){let t;try{t=sc.storage.getItem(\"debug\")}catch{}return!t&&typeof process<\"u\"&&\"env\"in process&&(t=process.env.DEBUG),t}function ovt(){try{return localStorage}catch{}}tL.exports=vJ()(sc);var{formatters:avt}=tL.exports;avt.j=function(t){try{return JSON.stringify(t)}catch(e){return\"[UnexpectedJSONParseError]: \"+e.message}}});var Ube=_((Xs,nL)=>{var lvt=Ie(\"tty\"),rL=Ie(\"util\");Xs.init=gvt;Xs.log=Avt;Xs.formatArgs=uvt;Xs.save=pvt;Xs.load=hvt;Xs.useColors=cvt;Xs.destroy=rL.deprecate(()=>{},\"Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.\");Xs.colors=[6,2,3,4,5,1];try{let t=Ie(\"supports-color\");t&&(t.stderr||t).level>=2&&(Xs.colors=[20,21,26,27,32,33,38,39,40,41,42,43,44,45,56,57,62,63,68,69,74,75,76,77,78,79,80,81,92,93,98,99,112,113,128,129,134,135,148,149,160,161,162,163,164,165,166,167,168,169,170,171,172,173,178,179,184,185,196,197,198,199,200,201,202,203,204,205,206,207,208,209,214,215,220,221])}catch{}Xs.inspectOpts=Object.keys(process.env).filter(t=>/^debug_/i.test(t)).reduce((t,e)=>{let r=e.substring(6).toLowerCase().replace(/_([a-z])/g,(a,n)=>n.toUpperCase()),s=process.env[e];return/^(yes|on|true|enabled)$/i.test(s)?s=!0:/^(no|off|false|disabled)$/i.test(s)?s=!1:s===\"null\"?s=null:s=Number(s),t[r]=s,t},{});function cvt(){return\"colors\"in Xs.inspectOpts?!!Xs.inspectOpts.colors:lvt.isatty(process.stderr.fd)}function uvt(t){let{namespace:e,useColors:r}=this;if(r){let s=this.color,a=\"\\x1B[3\"+(s<8?s:\"8;5;\"+s),n=`  ${a};1m${e} \\x1B[0m`;t[0]=n+t[0].split(`\n`).join(`\n`+n),t.push(a+\"m+\"+nL.exports.humanize(this.diff)+\"\\x1B[0m\")}else t[0]=fvt()+e+\" \"+t[0]}function fvt(){return Xs.inspectOpts.hideDate?\"\":new Date().toISOString()+\" \"}function Avt(...t){return process.stderr.write(rL.formatWithOptions(Xs.inspectOpts,...t)+`\n`)}function pvt(t){t?process.env.DEBUG=t:delete process.env.DEBUG}function hvt(){return process.env.DEBUG}function gvt(t){t.inspectOpts={};let e=Object.keys(Xs.inspectOpts);for(let r=0;r<e.length;r++)t.inspectOpts[e[r]]=Xs.inspectOpts[e[r]]}nL.exports=vJ()(Xs);var{formatters:Mbe}=nL.exports;Mbe.o=function(t){return this.inspectOpts.colors=this.useColors,rL.inspect(t,this.inspectOpts).split(`\n`).map(e=>e.trim()).join(\" \")};Mbe.O=function(t){return this.inspectOpts.colors=this.useColors,rL.inspect(t,this.inspectOpts)}});var DJ=_((cir,SJ)=>{typeof process>\"u\"||process.type===\"renderer\"||process.browser===!0||process.__nwjs?SJ.exports=Lbe():SJ.exports=Ube()});var sL=_(Ji=>{\"use strict\";Object.defineProperty(Ji,\"__esModule\",{value:!0});Ji.DownloadHTTPError=Ji.DownloadLengthMismatchError=Ji.DownloadError=Ji.ExpiredMetadataError=Ji.EqualVersionError=Ji.BadVersionError=Ji.RepositoryError=Ji.PersistError=Ji.RuntimeError=Ji.ValueError=void 0;var PJ=class extends Error{};Ji.ValueError=PJ;var bJ=class extends Error{};Ji.RuntimeError=bJ;var xJ=class extends Error{};Ji.PersistError=xJ;var UP=class extends Error{};Ji.RepositoryError=UP;var iL=class extends UP{};Ji.BadVersionError=iL;var kJ=class extends iL{};Ji.EqualVersionError=kJ;var QJ=class extends UP{};Ji.ExpiredMetadataError=QJ;var _P=class extends Error{};Ji.DownloadError=_P;var RJ=class extends _P{};Ji.DownloadLengthMismatchError=RJ;var TJ=class extends _P{constructor(e,r){super(e),this.statusCode=r}};Ji.DownloadHTTPError=TJ});var Hbe=_(d1=>{\"use strict\";var NJ=d1&&d1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(d1,\"__esModule\",{value:!0});d1.withTempFile=void 0;var FJ=NJ(Ie(\"fs/promises\")),dvt=NJ(Ie(\"os\")),_be=NJ(Ie(\"path\")),mvt=async t=>yvt(async e=>t(_be.default.join(e,\"tempfile\")));d1.withTempFile=mvt;var yvt=async t=>{let e=await FJ.default.realpath(dvt.default.tmpdir()),r=await FJ.default.mkdtemp(e+_be.default.sep);try{return await t(r)}finally{await FJ.default.rm(r,{force:!0,recursive:!0,maxRetries:3})}}});var LJ=_(kg=>{\"use strict\";var aL=kg&&kg.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(kg,\"__esModule\",{value:!0});kg.DefaultFetcher=kg.BaseFetcher=void 0;var Evt=aL(DJ()),jbe=aL(Ie(\"fs\")),Ivt=aL(IO()),Cvt=aL(Ie(\"util\")),Gbe=sL(),wvt=Hbe(),Bvt=(0,Evt.default)(\"tuf:fetch\"),oL=class{async downloadFile(e,r,s){return(0,wvt.withTempFile)(async a=>{let n=await this.fetch(e),c=0,f=jbe.default.createWriteStream(a);try{for await(let p of n){let h=Buffer.from(p);if(c+=h.length,c>r)throw new Gbe.DownloadLengthMismatchError(\"Max length reached\");await vvt(f,h)}}finally{await Cvt.default.promisify(f.close).bind(f)()}return s(a)})}async downloadBytes(e,r){return this.downloadFile(e,r,async s=>{let a=jbe.default.createReadStream(s),n=[];for await(let c of a)n.push(c);return Buffer.concat(n)})}};kg.BaseFetcher=oL;var OJ=class extends oL{constructor(e={}){super(),this.timeout=e.timeout,this.retry=e.retry}async fetch(e){Bvt(\"GET %s\",e);let r=await(0,Ivt.default)(e,{timeout:this.timeout,retry:this.retry});if(!r.ok||!r?.body)throw new Gbe.DownloadHTTPError(\"Failed to download\",r.status);return r.body}};kg.DefaultFetcher=OJ;var vvt=async(t,e)=>new Promise((r,s)=>{t.write(e,a=>{a&&s(a),r(!0)})})});var qbe=_(lL=>{\"use strict\";Object.defineProperty(lL,\"__esModule\",{value:!0});lL.defaultConfig=void 0;lL.defaultConfig={maxRootRotations:256,maxDelegations:32,rootMaxLength:512e3,timestampMaxLength:16384,snapshotMaxLength:2e6,targetsMaxLength:5e6,prefixTargetsWithHash:!0,fetchTimeout:1e5,fetchRetries:void 0,fetchRetry:2}});var Wbe=_(cL=>{\"use strict\";Object.defineProperty(cL,\"__esModule\",{value:!0});cL.TrustedMetadataStore=void 0;var Es=$O(),_i=sL(),MJ=class{constructor(e){this.trustedSet={},this.referenceTime=new Date,this.loadTrustedRoot(e)}get root(){if(!this.trustedSet.root)throw new ReferenceError(\"No trusted root metadata\");return this.trustedSet.root}get timestamp(){return this.trustedSet.timestamp}get snapshot(){return this.trustedSet.snapshot}get targets(){return this.trustedSet.targets}getRole(e){return this.trustedSet[e]}updateRoot(e){let r=JSON.parse(e.toString(\"utf8\")),s=Es.Metadata.fromJSON(Es.MetadataKind.Root,r);if(s.signed.type!=Es.MetadataKind.Root)throw new _i.RepositoryError(`Expected 'root', got ${s.signed.type}`);if(this.root.verifyDelegate(Es.MetadataKind.Root,s),s.signed.version!=this.root.signed.version+1)throw new _i.BadVersionError(`Expected version ${this.root.signed.version+1}, got ${s.signed.version}`);return s.verifyDelegate(Es.MetadataKind.Root,s),this.trustedSet.root=s,s}updateTimestamp(e){if(this.snapshot)throw new _i.RuntimeError(\"Cannot update timestamp after snapshot\");if(this.root.signed.isExpired(this.referenceTime))throw new _i.ExpiredMetadataError(\"Final root.json is expired\");let r=JSON.parse(e.toString(\"utf8\")),s=Es.Metadata.fromJSON(Es.MetadataKind.Timestamp,r);if(s.signed.type!=Es.MetadataKind.Timestamp)throw new _i.RepositoryError(`Expected 'timestamp', got ${s.signed.type}`);if(this.root.verifyDelegate(Es.MetadataKind.Timestamp,s),this.timestamp){if(s.signed.version<this.timestamp.signed.version)throw new _i.BadVersionError(`New timestamp version ${s.signed.version} is less than current version ${this.timestamp.signed.version}`);if(s.signed.version===this.timestamp.signed.version)throw new _i.EqualVersionError(`New timestamp version ${s.signed.version} is equal to current version ${this.timestamp.signed.version}`);let a=this.timestamp.signed.snapshotMeta,n=s.signed.snapshotMeta;if(n.version<a.version)throw new _i.BadVersionError(`New snapshot version ${n.version} is less than current version ${a.version}`)}return this.trustedSet.timestamp=s,this.checkFinalTimestamp(),s}updateSnapshot(e,r=!1){if(!this.timestamp)throw new _i.RuntimeError(\"Cannot update snapshot before timestamp\");if(this.targets)throw new _i.RuntimeError(\"Cannot update snapshot after targets\");this.checkFinalTimestamp();let s=this.timestamp.signed.snapshotMeta;r||s.verify(e);let a=JSON.parse(e.toString(\"utf8\")),n=Es.Metadata.fromJSON(Es.MetadataKind.Snapshot,a);if(n.signed.type!=Es.MetadataKind.Snapshot)throw new _i.RepositoryError(`Expected 'snapshot', got ${n.signed.type}`);return this.root.verifyDelegate(Es.MetadataKind.Snapshot,n),this.snapshot&&Object.entries(this.snapshot.signed.meta).forEach(([c,f])=>{let p=n.signed.meta[c];if(!p)throw new _i.RepositoryError(`Missing file ${c} in new snapshot`);if(p.version<f.version)throw new _i.BadVersionError(`New version ${p.version} of ${c} is less than current version ${f.version}`)}),this.trustedSet.snapshot=n,this.checkFinalSnapsnot(),n}updateDelegatedTargets(e,r,s){if(!this.snapshot)throw new _i.RuntimeError(\"Cannot update delegated targets before snapshot\");this.checkFinalSnapsnot();let a=this.trustedSet[s];if(!a)throw new _i.RuntimeError(`No trusted ${s} metadata`);let n=this.snapshot.signed.meta?.[`${r}.json`];if(!n)throw new _i.RepositoryError(`Missing ${r}.json in snapshot`);n.verify(e);let c=JSON.parse(e.toString(\"utf8\")),f=Es.Metadata.fromJSON(Es.MetadataKind.Targets,c);if(f.signed.type!=Es.MetadataKind.Targets)throw new _i.RepositoryError(`Expected 'targets', got ${f.signed.type}`);a.verifyDelegate(r,f);let p=f.signed.version;if(p!=n.version)throw new _i.BadVersionError(`Version ${p} of ${r} does not match snapshot version ${n.version}`);if(f.signed.isExpired(this.referenceTime))throw new _i.ExpiredMetadataError(`${r}.json is expired`);this.trustedSet[r]=f}loadTrustedRoot(e){let r=JSON.parse(e.toString(\"utf8\")),s=Es.Metadata.fromJSON(Es.MetadataKind.Root,r);if(s.signed.type!=Es.MetadataKind.Root)throw new _i.RepositoryError(`Expected 'root', got ${s.signed.type}`);s.verifyDelegate(Es.MetadataKind.Root,s),this.trustedSet.root=s}checkFinalTimestamp(){if(!this.timestamp)throw new ReferenceError(\"No trusted timestamp metadata\");if(this.timestamp.signed.isExpired(this.referenceTime))throw new _i.ExpiredMetadataError(\"Final timestamp.json is expired\")}checkFinalSnapsnot(){if(!this.snapshot)throw new ReferenceError(\"No trusted snapshot metadata\");if(!this.timestamp)throw new ReferenceError(\"No trusted timestamp metadata\");if(this.snapshot.signed.isExpired(this.referenceTime))throw new _i.ExpiredMetadataError(\"snapshot.json is expired\");let e=this.timestamp.signed.snapshotMeta;if(this.snapshot.signed.version!==e.version)throw new _i.BadVersionError(\"Snapshot version doesn't match timestamp\")}};cL.TrustedMetadataStore=MJ});var Ybe=_(UJ=>{\"use strict\";Object.defineProperty(UJ,\"__esModule\",{value:!0});UJ.join=Dvt;var Svt=Ie(\"url\");function Dvt(t,e){return new Svt.URL(Pvt(t)+bvt(e)).toString()}function Pvt(t){return t.endsWith(\"/\")?t:t+\"/\"}function bvt(t){return t.startsWith(\"/\")?t.slice(1):t}});var Vbe=_(nu=>{\"use strict\";var xvt=nu&&nu.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||(\"get\"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),kvt=nu&&nu.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),jJ=nu&&nu.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.prototype.hasOwnProperty.call(t,r)&&xvt(e,t,r);return kvt(e,t),e},Qvt=nu&&nu.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(nu,\"__esModule\",{value:!0});nu.Updater=void 0;var xA=$O(),Rvt=Qvt(DJ()),m1=jJ(Ie(\"fs\")),uL=jJ(Ie(\"path\")),Tvt=qbe(),fy=sL(),Fvt=LJ(),Nvt=Wbe(),HP=jJ(Ybe()),_J=(0,Rvt.default)(\"tuf:cache\"),HJ=class{constructor(e){let{metadataDir:r,metadataBaseUrl:s,targetDir:a,targetBaseUrl:n,fetcher:c,config:f}=e;this.dir=r,this.metadataBaseUrl=s,this.targetDir=a,this.targetBaseUrl=n,this.forceCache=e.forceCache??!1;let p=this.loadLocalMetadata(xA.MetadataKind.Root);this.trustedSet=new Nvt.TrustedMetadataStore(p),this.config={...Tvt.defaultConfig,...f},this.fetcher=c||new Fvt.DefaultFetcher({timeout:this.config.fetchTimeout,retry:this.config.fetchRetries??this.config.fetchRetry})}async refresh(){if(this.forceCache)try{await this.loadTimestamp({checkRemote:!1})}catch{await this.loadRoot(),await this.loadTimestamp()}else await this.loadRoot(),await this.loadTimestamp();await this.loadSnapshot(),await this.loadTargets(xA.MetadataKind.Targets,xA.MetadataKind.Root)}async getTargetInfo(e){return this.trustedSet.targets||await this.refresh(),this.preorderDepthFirstWalk(e)}async downloadTarget(e,r,s){let a=r||this.generateTargetPath(e);if(!s){if(!this.targetBaseUrl)throw new fy.ValueError(\"Target base URL not set\");s=this.targetBaseUrl}let n=e.path;if(this.trustedSet.root.signed.consistentSnapshot&&this.config.prefixTargetsWithHash){let p=Object.values(e.hashes),{dir:h,base:E}=uL.parse(n),C=`${p[0]}.${E}`;n=h?`${h}/${C}`:C}let f=HP.join(s,n);return await this.fetcher.downloadFile(f,e.length,async p=>{await e.verify(m1.createReadStream(p)),_J(\"WRITE %s\",a),m1.copyFileSync(p,a)}),a}async findCachedTarget(e,r){r||(r=this.generateTargetPath(e));try{if(m1.existsSync(r))return await e.verify(m1.createReadStream(r)),r}catch{return}}loadLocalMetadata(e){let r=uL.join(this.dir,`${e}.json`);return _J(\"READ %s\",r),m1.readFileSync(r)}async loadRoot(){let r=this.trustedSet.root.signed.version+1,s=r+this.config.maxRootRotations;for(let a=r;a<s;a++){let n=HP.join(this.metadataBaseUrl,`${a}.root.json`);try{let c=await this.fetcher.downloadBytes(n,this.config.rootMaxLength);this.trustedSet.updateRoot(c),this.persistMetadata(xA.MetadataKind.Root,c)}catch(c){if(c instanceof fy.DownloadHTTPError&&[403,404].includes(c.statusCode))break;throw c}}}async loadTimestamp({checkRemote:e}={checkRemote:!0}){try{let a=this.loadLocalMetadata(xA.MetadataKind.Timestamp);if(this.trustedSet.updateTimestamp(a),!e)return}catch{}let r=HP.join(this.metadataBaseUrl,\"timestamp.json\"),s=await this.fetcher.downloadBytes(r,this.config.timestampMaxLength);try{this.trustedSet.updateTimestamp(s)}catch(a){if(a instanceof fy.EqualVersionError)return;throw a}this.persistMetadata(xA.MetadataKind.Timestamp,s)}async loadSnapshot(){try{let e=this.loadLocalMetadata(xA.MetadataKind.Snapshot);this.trustedSet.updateSnapshot(e,!0)}catch{if(!this.trustedSet.timestamp)throw new ReferenceError(\"No timestamp metadata\");let r=this.trustedSet.timestamp.signed.snapshotMeta,s=r.length||this.config.snapshotMaxLength,a=this.trustedSet.root.signed.consistentSnapshot?r.version:void 0,n=HP.join(this.metadataBaseUrl,a?`${a}.snapshot.json`:\"snapshot.json\");try{let c=await this.fetcher.downloadBytes(n,s);this.trustedSet.updateSnapshot(c),this.persistMetadata(xA.MetadataKind.Snapshot,c)}catch(c){throw new fy.RuntimeError(`Unable to load snapshot metadata error ${c}`)}}}async loadTargets(e,r){if(this.trustedSet.getRole(e))return this.trustedSet.getRole(e);try{let s=this.loadLocalMetadata(e);this.trustedSet.updateDelegatedTargets(s,e,r)}catch{if(!this.trustedSet.snapshot)throw new ReferenceError(\"No snapshot metadata\");let a=this.trustedSet.snapshot.signed.meta[`${e}.json`],n=a.length||this.config.targetsMaxLength,c=this.trustedSet.root.signed.consistentSnapshot?a.version:void 0,f=encodeURIComponent(e),p=HP.join(this.metadataBaseUrl,c?`${c}.${f}.json`:`${f}.json`);try{let h=await this.fetcher.downloadBytes(p,n);this.trustedSet.updateDelegatedTargets(h,e,r),this.persistMetadata(e,h)}catch(h){throw new fy.RuntimeError(`Unable to load targets error ${h}`)}}return this.trustedSet.getRole(e)}async preorderDepthFirstWalk(e){let r=[{roleName:xA.MetadataKind.Targets,parentRoleName:xA.MetadataKind.Root}],s=new Set;for(;s.size<=this.config.maxDelegations&&r.length>0;){let{roleName:a,parentRoleName:n}=r.pop();if(s.has(a))continue;let c=(await this.loadTargets(a,n))?.signed;if(!c)continue;let f=c.targets?.[e];if(f)return f;if(s.add(a),c.delegations){let p=[],h=c.delegations.rolesForTarget(e);for(let{role:E,terminating:C}of h)if(p.push({roleName:E,parentRoleName:a}),C){r.splice(0);break}p.reverse(),r.push(...p)}}}generateTargetPath(e){if(!this.targetDir)throw new fy.ValueError(\"Target directory not set\");let r=encodeURIComponent(e.path);return uL.join(this.targetDir,r)}persistMetadata(e,r){let s=encodeURIComponent(e);try{let a=uL.join(this.dir,`${s}.json`);_J(\"WRITE %s\",a),m1.writeFileSync(a,r.toString(\"utf8\"))}catch(a){throw new fy.PersistError(`Failed to persist metadata ${s} error: ${a}`)}}};nu.Updater=HJ});var Jbe=_(Qg=>{\"use strict\";Object.defineProperty(Qg,\"__esModule\",{value:!0});Qg.Updater=Qg.BaseFetcher=Qg.TargetFile=void 0;var Ovt=$O();Object.defineProperty(Qg,\"TargetFile\",{enumerable:!0,get:function(){return Ovt.TargetFile}});var Lvt=LJ();Object.defineProperty(Qg,\"BaseFetcher\",{enumerable:!0,get:function(){return Lvt.BaseFetcher}});var Mvt=Vbe();Object.defineProperty(Qg,\"Updater\",{enumerable:!0,get:function(){return Mvt.Updater}})});var qJ=_(fL=>{\"use strict\";Object.defineProperty(fL,\"__esModule\",{value:!0});fL.TUFError=void 0;var GJ=class extends Error{constructor({code:e,message:r,cause:s}){super(r),this.code=e,this.cause=s,this.name=this.constructor.name}};fL.TUFError=GJ});var Kbe=_(jP=>{\"use strict\";var Uvt=jP&&jP.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(jP,\"__esModule\",{value:!0});jP.readTarget=Hvt;var _vt=Uvt(Ie(\"fs\")),AL=qJ();async function Hvt(t,e){let r=await jvt(t,e);return new Promise((s,a)=>{_vt.default.readFile(r,\"utf-8\",(n,c)=>{n?a(new AL.TUFError({code:\"TUF_READ_TARGET_ERROR\",message:`error reading target ${r}`,cause:n})):s(c)})})}async function jvt(t,e){let r;try{r=await t.getTargetInfo(e)}catch(a){throw new AL.TUFError({code:\"TUF_REFRESH_METADATA_ERROR\",message:\"error refreshing TUF metadata\",cause:a})}if(!r)throw new AL.TUFError({code:\"TUF_FIND_TARGET_ERROR\",message:`target ${e} not found`});let s=await t.findCachedTarget(r);if(!s)try{s=await t.downloadTarget(r)}catch(a){throw new AL.TUFError({code:\"TUF_DOWNLOAD_TARGET_ERROR\",message:`error downloading target ${s}`,cause:a})}return s}});var zbe=_((Iir,Gvt)=>{Gvt.exports={\"https://tuf-repo-cdn.sigstore.dev\":{\"root.json\":\"ewogInNpZ25hdHVyZXMiOiBbCiAgewogICAia2V5aWQiOiAiNmYyNjAwODlkNTkyM2RhZjIwMTY2Y2E2NTdjNTQzYWY2MTgzNDZhYjk3MTg4NGE5OTk2MmIwMTk4OGJiZTBjMyIsCiAgICJzaWciOiAiMzA0NjAyMjEwMDhhYjFmNmYxN2Q0ZjllNmQ3ZGNmMWM4ODkxMmI2YjUzY2MxMDM4ODY0NGFlMWYwOWJjMzdhMDgyY2QwNjAwM2UwMjIxMDBlMTQ1ZWY0YzdiNzgyZDRlODEwN2I1MzQzN2U2NjlkMDQ3Njg5MmNlOTk5OTAzYWUzM2QxNDQ0ODM2Njk5NmU3IgogIH0sCiAgewogICAia2V5aWQiOiAiZTcxYTU0ZDU0MzgzNWJhODZhZGFkOTQ2MDM3OWM3NjQxZmI4NzI2ZDE2NGVhNzY2ODAxYTFjNTIyYWJhN2VhMiIsCiAgICJzaWciOiAiMzA0NTAyMjEwMGM3NjhiMmY4NmRhOTk1NjkwMTljMTYwYTA4MWRhNTRhZTM2YzM0YzBhMzEyMGQzY2I2OWI1M2I3ZDExMzc1OGUwMjIwNGY2NzE1MThmNjE3YjIwZDQ2NTM3ZmFlNmMzYjYzYmFlODkxM2Y0ZjE5NjIxNTYxMDVjYzRmMDE5YWMzNWM2YSIKICB9LAogIHsKICAgImtleWlkIjogIjIyZjRjYWVjNmQ4ZTZmOTU1NWFmNjZiM2Q0YzNjYjA2YTNiYjIzZmRjN2UzOWM5MTZjNjFmNDYyZTZmNTJiMDYiLAogICAic2lnIjogIjMwNDUwMjIxMDBiNDQzNGU2OTk1ZDM2OGQyM2U3NDc1OWFjZDBjYjkwMTNjODNhNWQzNTExZjBmOTk3ZWM1NGM0NTZhZTQzNTBhMDIyMDE1YjBlMjY1ZDE4MmQyYjYxZGM3NGUxNTVkOThiM2MzZmJlNTY0YmEwNTI4NmFhMTRjOGRmMDJjOWI3NTY1MTYiCiAgfSwKICB7CiAgICJrZXlpZCI6ICI2MTY0MzgzODEyNWI0NDBiNDBkYjY5NDJmNWNiNWEzMWMwZGMwNDM2ODMxNmViMmFhYTU4Yjk1OTA0YTU4MjIyIiwKICAgInNpZyI6ICIzMDQ1MDIyMTAwODJjNTg0MTFkOTg5ZWI5Zjg2MTQxMDg1N2Q0MjM4MTU5MGVjOTQyNGRiZGFhNTFlNzhlZDEzNTE1NDMxOTA0ZTAyMjAxMTgxODVkYTZhNmMyOTQ3MTMxYzE3Nzk3ZTJiYjc2MjBjZTI2ZTVmMzAxZDFjZWFjNWYyYTdlNThmOWRjZjJlIgogIH0sCiAgewogICAia2V5aWQiOiAiYTY4N2U1YmY0ZmFiODJiMGVlNThkNDZlMDVjOTUzNTE0NWEyYzlhZmI0NThmNDNkNDJiNDVjYTBmZGNlMmE3MCIsCiAgICJzaWciOiAiMzA0NjAyMjEwMGM3ODUxMzg1NGNhZTljMzJlYWE2Yjg4ZTE4OTEyZjQ4MDA2YzI3NTdhMjU4ZjkxNzMxMmNhYmE3NTk0OGViOWUwMjIxMDBkOWUxYjRjZTBhZGZlOWZkMmUyMTQ4ZDdmYTI3YTJmNDBiYTExMjJiZDY5ZGE3NjEyZDhkMTc3NmIwMTNjOTFkIgogIH0sCiAgewogICAia2V5aWQiOiAiZmRmYTgzYTA3YjVhODM1ODliODdkZWQ0MWY3N2YzOWQyMzJhZDkxZjdjY2U1Mjg2OGRhY2QwNmJhMDg5ODQ5ZiIsCiAgICJzaWciOiAiMzA0NTAyMjA1NjQ4M2EyZDVkOWVhOWNlYzZlMTFlYWRmYjMzYzQ4NGI2MTQyOThmYWNhMTVhY2YxYzQzMWIxMWVkN2Y3MzRjMDIyMTAwZDBjMWQ3MjZhZjkyYTg3ZTRlNjY0NTljYTVhZGYzOGEwNWI0NGUxZjk0MzE4NDIzZjk1NGJhZThiY2E1YmIyZSIKICB9LAogIHsKICAgImtleWlkIjogImUyZjU5YWNiOTQ4ODUxOTQwN2UxOGNiZmM5MzI5NTEwYmUwM2MwNGFjYTk5MjlkMmYwMzAxMzQzZmVjODU1MjMiLAogICAic2lnIjogIjMwNDYwMjIxMDBkMDA0ZGU4ODAyNGMzMmRjNTY1M2E5ZjQ4NDNjZmM1MjE1NDI3MDQ4YWQ5NjAwZDJjZjljOTY5ZTZlZGZmM2QyMDIyMTAwZDllYmI3OThmNWZjNjZhZjEwODk5ZGVjZTAxNGE4NjI4Y2NmM2M1NDAyY2Q0YTQyNzAyMDc0NzJmOGY2ZTcxMiIKICB9LAogIHsKICAgImtleWlkIjogIjNjMzQ0YWEwNjhmZDRjYzRlODdkYzUwYjYxMmMwMjQzMWZiYzc3MWU5NTAwMzk5MzY4M2EyYjBiZjI2MGNmMGUiLAogICAic2lnIjogIjMwNDYwMjIxMDBiN2IwOTk5NmM0NWNhMmQ0YjA1NjAzZTU2YmFlZmEyOTcxOGEwYjcxMTQ3Y2Y4YzZlNjYzNDliYWE2MTQ3N2RmMDIyMTAwYzRkYTgwYzcxN2I0ZmE3YmJhMGZkNWM3MmRhOGEwNDk5MzU4YjAxMzU4YjIzMDlmNDFkMTQ1NmVhMWU3ZTFkOSIKICB9LAogIHsKICAgImtleWlkIjogImVjODE2Njk3MzRlMDE3OTk2YzViODVmM2QwMmMzZGUxZGQ0NjM3YTE1MjAxOWZlMWFmMTI1ZDJmOTM2OGI5NWUiLAogICAic2lnIjogIjMwNDYwMjIxMDBiZTk3ODJjMzA3NDRlNDExYTgyZmE4NWI1MTM4ZDYwMWNlMTQ4YmMxOTI1OGFlYzY0ZTdlYzI0NDc4ZjM4ODEyMDIyMTAwY2FlZjYzZGNhZjFhNGI5YTUwMGQzYmQwZTNmMTY0ZWMxOGYxYjYzZDdhOTQ2MGQ5YWNhYjEwNjZkYjBmMDE2ZCIKICB9LAogIHsKICAgImtleWlkIjogIjFlMWQ2NWNlOThiMTBhZGRhZDQ3NjRmZWJmN2RkYTJkMDQzNmIzZDNhMzg5MzU3OWMwZGRkYWVhMjBlNTQ4NDkiLAogICAic2lnIjogIjMwNDUwMjIwNzQ2ZWMzZjg1MzRjZTU1NTMxZDBkMDFmZjY0OTY0ZWY0NDBkMWU3ZDJjNGMxNDI0MDliOGU5NzY5ZjFhZGE2ZjAyMjEwMGUzYjkyOWZjZDkzZWExOGZlYWEwODI1ODg3YTcyMTA0ODk4NzlhNjY3ODBjMDdhODNmNGJkNDZlMmYwOWFiM2IiCiAgfQogXSwKICJzaWduZWQiOiB7CiAgIl90eXBlIjogInJvb3QiLAogICJjb25zaXN0ZW50X3NuYXBzaG90IjogdHJ1ZSwKICAiZXhwaXJlcyI6ICIyMDI1LTAyLTE5VDA4OjA0OjMyWiIsCiAgImtleXMiOiB7CiAgICIyMmY0Y2FlYzZkOGU2Zjk1NTVhZjY2YjNkNGMzY2IwNmEzYmIyM2ZkYzdlMzljOTE2YzYxZjQ2MmU2ZjUyYjA2IjogewogICAgImtleWlkX2hhc2hfYWxnb3JpdGhtcyI6IFsKICAgICAic2hhMjU2IiwKICAgICAic2hhNTEyIgogICAgXSwKICAgICJrZXl0eXBlIjogImVjZHNhIiwKICAgICJrZXl2YWwiOiB7CiAgICAgInB1YmxpYyI6ICItLS0tLUJFR0lOIFBVQkxJQyBLRVktLS0tLVxuTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFekJ6Vk9tSENQb2pNVkxTSTM2NFdpaVY4TlByRFxuNklnUnhWbGlza3ovdit5M0pFUjVtY1ZHY09ObGlEY1dNQzVKMmxmSG1qUE5QaGI0SDd4bThMemZTQT09XG4tLS0tLUVORCBQVUJMSUMgS0VZLS0tLS1cbiIKICAgIH0sCiAgICAic2NoZW1lIjogImVjZHNhLXNoYTItbmlzdHAyNTYiLAogICAgIngtdHVmLW9uLWNpLWtleW93bmVyIjogIkBzYW50aWFnb3RvcnJlcyIKICAgfSwKICAgIjYxNjQzODM4MTI1YjQ0MGI0MGRiNjk0MmY1Y2I1YTMxYzBkYzA0MzY4MzE2ZWIyYWFhNThiOTU5MDRhNTgyMjIiOiB7CiAgICAia2V5aWRfaGFzaF9hbGdvcml0aG1zIjogWwogICAgICJzaGEyNTYiLAogICAgICJzaGE1MTIiCiAgICBdLAogICAgImtleXR5cGUiOiAiZWNkc2EiLAogICAgImtleXZhbCI6IHsKICAgICAicHVibGljIjogIi0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tXG5NRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVpbmlrU3NBUW1Za05lSDVlWXEvQ25JekxhYWNPXG54bFNhYXdRRE93cUt5L3RDcXhxNXh4UFNKYzIxSzRXSWhzOUd5T2tLZnp1ZVkzR0lMemNNSlo0Y1d3PT1cbi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLVxuIgogICAgfSwKICAgICJzY2hlbWUiOiAiZWNkc2Etc2hhMi1uaXN0cDI1NiIsCiAgICAieC10dWYtb24tY2kta2V5b3duZXIiOiAiQGJvYmNhbGxhd2F5IgogICB9LAogICAiNmYyNjAwODlkNTkyM2RhZjIwMTY2Y2E2NTdjNTQzYWY2MTgzNDZhYjk3MTg4NGE5OTk2MmIwMTk4OGJiZTBjMyI6IHsKICAgICJrZXlpZF9oYXNoX2FsZ29yaXRobXMiOiBbCiAgICAgInNoYTI1NiIsCiAgICAgInNoYTUxMiIKICAgIF0sCiAgICAia2V5dHlwZSI6ICJlY2RzYSIsCiAgICAia2V5dmFsIjogewogICAgICJwdWJsaWMiOiAiLS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS1cbk1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRXk4WEtzbWhCWURJOEpjMEd3ekJ4ZUtheDBjbTVcblNUS0VVNjVIUEZ1blVuNDFzVDhwaTBGak00SWtIei9ZVW13bUxVTzBXdDdseGhqNkJrTElLNHFZQXc9PVxuLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tXG4iCiAgICB9LAogICAgInNjaGVtZSI6ICJlY2RzYS1zaGEyLW5pc3RwMjU2IiwKICAgICJ4LXR1Zi1vbi1jaS1rZXlvd25lciI6ICJAZGxvcmVuYyIKICAgfSwKICAgIjcyNDdmMGRiYWQ4NWIxNDdlMTg2M2JhZGU3NjEyNDNjYzc4NWRjYjdhYTQxMGU3MTA1ZGQzZDJiNjFhMzZkMmMiOiB7CiAgICAia2V5aWRfaGFzaF9hbGdvcml0aG1zIjogWwogICAgICJzaGEyNTYiLAogICAgICJzaGE1MTIiCiAgICBdLAogICAgImtleXR5cGUiOiAiZWNkc2EiLAogICAgImtleXZhbCI6IHsKICAgICAicHVibGljIjogIi0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tXG5NRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVXUmlHcjUraiszSjVTc0grWnRyNW5FMkgyd083XG5CVituTzNzOTNnTGNhMThxVE96SFkxb1d5QUdEeWtNU3NHVFVCU3Q5RCtBbjBLZktzRDJtZlNNNDJRPT1cbi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLVxuIgogICAgfSwKICAgICJzY2hlbWUiOiAiZWNkc2Etc2hhMi1uaXN0cDI1NiIsCiAgICAieC10dWYtb24tY2ktb25saW5lLXVyaSI6ICJnY3BrbXM6Ly9wcm9qZWN0cy9zaWdzdG9yZS1yb290LXNpZ25pbmcvbG9jYXRpb25zL2dsb2JhbC9rZXlSaW5ncy9yb290L2NyeXB0b0tleXMvdGltZXN0YW1wIgogICB9LAogICAiYTY4N2U1YmY0ZmFiODJiMGVlNThkNDZlMDVjOTUzNTE0NWEyYzlhZmI0NThmNDNkNDJiNDVjYTBmZGNlMmE3MCI6IHsKICAgICJrZXlpZF9oYXNoX2FsZ29yaXRobXMiOiBbCiAgICAgInNoYTI1NiIsCiAgICAgInNoYTUxMiIKICAgIF0sCiAgICAia2V5dHlwZSI6ICJlY2RzYSIsCiAgICAia2V5dmFsIjogewogICAgICJwdWJsaWMiOiAiLS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS1cbk1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRTBnaHJoOTJMdzFZcjNpZEdWNVdxQ3RNREI4Q3hcbitEOGhkQzR3MlpMTklwbFZSb1ZHTHNrWWEzZ2hlTXlPamlKOGtQaTE1YVEyLy83UCtvajdVdkpQR3c9PVxuLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tXG4iCiAgICB9LAogICAgInNjaGVtZSI6ICJlY2RzYS1zaGEyLW5pc3RwMjU2IiwKICAgICJ4LXR1Zi1vbi1jaS1rZXlvd25lciI6ICJAam9zaHVhZ2wiCiAgIH0sCiAgICJlNzFhNTRkNTQzODM1YmE4NmFkYWQ5NDYwMzc5Yzc2NDFmYjg3MjZkMTY0ZWE3NjY4MDFhMWM1MjJhYmE3ZWEyIjogewogICAgImtleWlkX2hhc2hfYWxnb3JpdGhtcyI6IFsKICAgICAic2hhMjU2IiwKICAgICAic2hhNTEyIgogICAgXSwKICAgICJrZXl0eXBlIjogImVjZHNhIiwKICAgICJrZXl2YWwiOiB7CiAgICAgInB1YmxpYyI6ICItLS0tLUJFR0lOIFBVQkxJQyBLRVktLS0tLVxuTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFRVhzejNTWlhGYjhqTVY0Mmo2cEpseWpialI4S1xuTjNCd29jZXhxNkxNSWI1cXNXS09RdkxOMTZOVWVmTGM0SHN3T291bVJzVlZhYWpTcFFTNmZvYmtSdz09XG4tLS0tLUVORCBQVUJMSUMgS0VZLS0tLS1cbiIKICAgIH0sCiAgICAic2NoZW1lIjogImVjZHNhLXNoYTItbmlzdHAyNTYiLAogICAgIngtdHVmLW9uLWNpLWtleW93bmVyIjogIkBtbm02NzgiCiAgIH0KICB9LAogICJyb2xlcyI6IHsKICAgInJvb3QiOiB7CiAgICAia2V5aWRzIjogWwogICAgICI2ZjI2MDA4OWQ1OTIzZGFmMjAxNjZjYTY1N2M1NDNhZjYxODM0NmFiOTcxODg0YTk5OTYyYjAxOTg4YmJlMGMzIiwKICAgICAiZTcxYTU0ZDU0MzgzNWJhODZhZGFkOTQ2MDM3OWM3NjQxZmI4NzI2ZDE2NGVhNzY2ODAxYTFjNTIyYWJhN2VhMiIsCiAgICAgIjIyZjRjYWVjNmQ4ZTZmOTU1NWFmNjZiM2Q0YzNjYjA2YTNiYjIzZmRjN2UzOWM5MTZjNjFmNDYyZTZmNTJiMDYiLAogICAgICI2MTY0MzgzODEyNWI0NDBiNDBkYjY5NDJmNWNiNWEzMWMwZGMwNDM2ODMxNmViMmFhYTU4Yjk1OTA0YTU4MjIyIiwKICAgICAiYTY4N2U1YmY0ZmFiODJiMGVlNThkNDZlMDVjOTUzNTE0NWEyYzlhZmI0NThmNDNkNDJiNDVjYTBmZGNlMmE3MCIKICAgIF0sCiAgICAidGhyZXNob2xkIjogMwogICB9LAogICAic25hcHNob3QiOiB7CiAgICAia2V5aWRzIjogWwogICAgICI3MjQ3ZjBkYmFkODViMTQ3ZTE4NjNiYWRlNzYxMjQzY2M3ODVkY2I3YWE0MTBlNzEwNWRkM2QyYjYxYTM2ZDJjIgogICAgXSwKICAgICJ0aHJlc2hvbGQiOiAxLAogICAgIngtdHVmLW9uLWNpLWV4cGlyeS1wZXJpb2QiOiAzNjUwLAogICAgIngtdHVmLW9uLWNpLXNpZ25pbmctcGVyaW9kIjogMzY1CiAgIH0sCiAgICJ0YXJnZXRzIjogewogICAgImtleWlkcyI6IFsKICAgICAiNmYyNjAwODlkNTkyM2RhZjIwMTY2Y2E2NTdjNTQzYWY2MTgzNDZhYjk3MTg4NGE5OTk2MmIwMTk4OGJiZTBjMyIsCiAgICAgImU3MWE1NGQ1NDM4MzViYTg2YWRhZDk0NjAzNzljNzY0MWZiODcyNmQxNjRlYTc2NjgwMWExYzUyMmFiYTdlYTIiLAogICAgICIyMmY0Y2FlYzZkOGU2Zjk1NTVhZjY2YjNkNGMzY2IwNmEzYmIyM2ZkYzdlMzljOTE2YzYxZjQ2MmU2ZjUyYjA2IiwKICAgICAiNjE2NDM4MzgxMjViNDQwYjQwZGI2OTQyZjVjYjVhMzFjMGRjMDQzNjgzMTZlYjJhYWE1OGI5NTkwNGE1ODIyMiIsCiAgICAgImE2ODdlNWJmNGZhYjgyYjBlZTU4ZDQ2ZTA1Yzk1MzUxNDVhMmM5YWZiNDU4ZjQzZDQyYjQ1Y2EwZmRjZTJhNzAiCiAgICBdLAogICAgInRocmVzaG9sZCI6IDMKICAgfSwKICAgInRpbWVzdGFtcCI6IHsKICAgICJrZXlpZHMiOiBbCiAgICAgIjcyNDdmMGRiYWQ4NWIxNDdlMTg2M2JhZGU3NjEyNDNjYzc4NWRjYjdhYTQxMGU3MTA1ZGQzZDJiNjFhMzZkMmMiCiAgICBdLAogICAgInRocmVzaG9sZCI6IDEsCiAgICAieC10dWYtb24tY2ktZXhwaXJ5LXBlcmlvZCI6IDcsCiAgICAieC10dWYtb24tY2ktc2lnbmluZy1wZXJpb2QiOiA0CiAgIH0KICB9LAogICJzcGVjX3ZlcnNpb24iOiAiMS4wIiwKICAidmVyc2lvbiI6IDEwLAogICJ4LXR1Zi1vbi1jaS1leHBpcnktcGVyaW9kIjogMTgyLAogICJ4LXR1Zi1vbi1jaS1zaWduaW5nLXBlcmlvZCI6IDMxCiB9Cn0=\",targets:{\"trusted_root.json\":\"ewogICJtZWRpYVR5cGUiOiAiYXBwbGljYXRpb24vdm5kLmRldi5zaWdzdG9yZS50cnVzdGVkcm9vdCtqc29uO3ZlcnNpb249MC4xIiwKICAidGxvZ3MiOiBbCiAgICB7CiAgICAgICJiYXNlVXJsIjogImh0dHBzOi8vcmVrb3Iuc2lnc3RvcmUuZGV2IiwKICAgICAgImhhc2hBbGdvcml0aG0iOiAiU0hBMl8yNTYiLAogICAgICAicHVibGljS2V5IjogewogICAgICAgICJyYXdCeXRlcyI6ICJNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUUyRzJZKzJ0YWJkVFY1QmNHaUJJeDBhOWZBRndya0JibUxTR3RrczRMM3FYNnlZWTB6dWZCbmhDOFVyL2l5NTVHaFdQLzlBL2JZMkxoQzMwTTkrUll0dz09IiwKICAgICAgICAia2V5RGV0YWlscyI6ICJQS0lYX0VDRFNBX1AyNTZfU0hBXzI1NiIsCiAgICAgICAgInZhbGlkRm9yIjogewogICAgICAgICAgInN0YXJ0IjogIjIwMjEtMDEtMTJUMTE6NTM6MjcuMDAwWiIKICAgICAgICB9CiAgICAgIH0sCiAgICAgICJsb2dJZCI6IHsKICAgICAgICAia2V5SWQiOiAid05JOWF0UUdseitWV2ZPNkxSeWdINFFVZlkvOFc0UkZ3aVQ1aTVXUmdCMD0iCiAgICAgIH0KICAgIH0KICBdLAogICJjZXJ0aWZpY2F0ZUF1dGhvcml0aWVzIjogWwogICAgewogICAgICAic3ViamVjdCI6IHsKICAgICAgICAib3JnYW5pemF0aW9uIjogInNpZ3N0b3JlLmRldiIsCiAgICAgICAgImNvbW1vbk5hbWUiOiAic2lnc3RvcmUiCiAgICAgIH0sCiAgICAgICJ1cmkiOiAiaHR0cHM6Ly9mdWxjaW8uc2lnc3RvcmUuZGV2IiwKICAgICAgImNlcnRDaGFpbiI6IHsKICAgICAgICAiY2VydGlmaWNhdGVzIjogWwogICAgICAgICAgewogICAgICAgICAgICAicmF3Qnl0ZXMiOiAiTUlJQitEQ0NBWDZnQXdJQkFnSVROVmtEWm9DaW9mUERzeTdkZm02Z2VMYnVoekFLQmdncWhrak9QUVFEQXpBcU1SVXdFd1lEVlFRS0V3eHphV2R6ZEc5eVpTNWtaWFl4RVRBUEJnTlZCQU1UQ0hOcFozTjBiM0psTUI0WERUSXhNRE13TnpBek1qQXlPVm9YRFRNeE1ESXlNekF6TWpBeU9Wb3dLakVWTUJNR0ExVUVDaE1NYzJsbmMzUnZjbVV1WkdWMk1SRXdEd1lEVlFRREV3aHphV2R6ZEc5eVpUQjJNQkFHQnlxR1NNNDlBZ0VHQlN1QkJBQWlBMklBQkxTeUE3SWk1aytwTk84WkVXWTB5bGVtV0Rvd09rTmEza0wrR1pFNVo1R1dlaEw5L0E5YlJOQTNSYnJzWjVpMEpjYXN0YVJMN1NwNWZwL2pENWR4cWMvVWRUVm5sdlMxNmFuKzJZZnN3ZS9RdUxvbFJVQ3JjT0UyKzJpQTUrdHpkNk5tTUdRd0RnWURWUjBQQVFIL0JBUURBZ0VHTUJJR0ExVWRFd0VCL3dRSU1BWUJBZjhDQVFFd0hRWURWUjBPQkJZRUZNakZIUUJCbWlRcE1sRWs2dzJ1U3UxS0J0UHNNQjhHQTFVZEl3UVlNQmFBRk1qRkhRQkJtaVFwTWxFazZ3MnVTdTFLQnRQc01Bb0dDQ3FHU000OUJBTURBMmdBTUdVQ01IOGxpV0pmTXVpNnZYWEJoakRnWTRNd3NsbU4vVEp4VmUvODNXckZvbXdtTmYwNTZ5MVg0OEY5YzRtM2Ezb3pYQUl4QUtqUmF5NS9hai9qc0tLR0lrbVFhdGpJOHV1cEhyLytDeEZ2YUpXbXBZcU5rTERHUlUrOW9yemg1aEkyUnJjdWFRPT0iCiAgICAgICAgICB9CiAgICAgICAgXQogICAgICB9LAogICAgICAidmFsaWRGb3IiOiB7CiAgICAgICAgInN0YXJ0IjogIjIwMjEtMDMtMDdUMDM6MjA6MjkuMDAwWiIsCiAgICAgICAgImVuZCI6ICIyMDIyLTEyLTMxVDIzOjU5OjU5Ljk5OVoiCiAgICAgIH0KICAgIH0sCiAgICB7CiAgICAgICJzdWJqZWN0IjogewogICAgICAgICJvcmdhbml6YXRpb24iOiAic2lnc3RvcmUuZGV2IiwKICAgICAgICAiY29tbW9uTmFtZSI6ICJzaWdzdG9yZSIKICAgICAgfSwKICAgICAgInVyaSI6ICJodHRwczovL2Z1bGNpby5zaWdzdG9yZS5kZXYiLAogICAgICAiY2VydENoYWluIjogewogICAgICAgICJjZXJ0aWZpY2F0ZXMiOiBbCiAgICAgICAgICB7CiAgICAgICAgICAgICJyYXdCeXRlcyI6ICJNSUlDR2pDQ0FhR2dBd0lCQWdJVUFMblZpVmZuVTBickphc21Sa0hybi9VbmZhUXdDZ1lJS29aSXpqMEVBd013S2pFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUkV3RHdZRFZRUURFd2h6YVdkemRHOXlaVEFlRncweU1qQTBNVE15TURBMk1UVmFGdzB6TVRFd01EVXhNelUyTlRoYU1EY3hGVEFUQmdOVkJBb1RESE5wWjNOMGIzSmxMbVJsZGpFZU1Cd0dBMVVFQXhNVmMybG5jM1J2Y21VdGFXNTBaWEp0WldScFlYUmxNSFl3RUFZSEtvWkl6ajBDQVFZRks0RUVBQ0lEWWdBRThSVlMveXNIK05PdnVEWnlQSVp0aWxnVUY5TmxhcllwQWQ5SFAxdkJCSDFVNUNWNzdMU1M3czBaaUg0bkU3SHY3cHRTNkx2dlIvU1RrNzk4TFZnTXpMbEo0SGVJZkYzdEhTYWV4TGNZcFNBU3Ixa1MwTi9SZ0JKei85aldDaVhubzNzd2VUQU9CZ05WSFE4QkFmOEVCQU1DQVFZd0V3WURWUjBsQkF3d0NnWUlLd1lCQlFVSEF3TXdFZ1lEVlIwVEFRSC9CQWd3QmdFQi93SUJBREFkQmdOVkhRNEVGZ1FVMzlQcHoxWWtFWmI1cU5qcEtGV2l4aTRZWkQ4d0h3WURWUjBqQkJnd0ZvQVVXTUFlWDVGRnBXYXBlc3lRb1pNaTBDckZ4Zm93Q2dZSUtvWkl6ajBFQXdNRFp3QXdaQUl3UENzUUs0RFlpWllEUElhRGk1SEZLbmZ4WHg2QVNTVm1FUmZzeW5ZQmlYMlg2U0pSblpVODQvOURaZG5GdnZ4bUFqQk90NlFwQmxjNEovMER4dmtUQ3FwY2x2emlMNkJDQ1BuamRsSUIzUHUzQnhzUG15Z1VZN0lpMnpiZENkbGlpb3c9IgogICAgICAgICAgfSwKICAgICAgICAgIHsKICAgICAgICAgICAgInJhd0J5dGVzIjogIk1JSUI5ekNDQVh5Z0F3SUJBZ0lVQUxaTkFQRmR4SFB3amVEbG9Ed3lZQ2hBTy80d0NnWUlLb1pJemowRUF3TXdLakVWTUJNR0ExVUVDaE1NYzJsbmMzUnZjbVV1WkdWMk1SRXdEd1lEVlFRREV3aHphV2R6ZEc5eVpUQWVGdzB5TVRFd01EY3hNelUyTlRsYUZ3MHpNVEV3TURVeE16VTJOVGhhTUNveEZUQVRCZ05WQkFvVERITnBaM04wYjNKbExtUmxkakVSTUE4R0ExVUVBeE1JYzJsbmMzUnZjbVV3ZGpBUUJnY3Foa2pPUFFJQkJnVXJnUVFBSWdOaUFBVDdYZUZUNHJiM1BRR3dTNElhanRMazMvT2xucGdhbmdhQmNsWXBzWUJyNWkrNHluQjA3Y2ViM0xQME9JT1pkeGV4WDY5YzVpVnV5SlJRK0h6MDV5aStVRjN1QldBbEhwaVM1c2gwK0gyR0hFN1NYcmsxRUM1bTFUcjE5TDlnZzkyall6QmhNQTRHQTFVZER3RUIvd1FFQXdJQkJqQVBCZ05WSFJNQkFmOEVCVEFEQVFIL01CMEdBMVVkRGdRV0JCUll3QjVma1VXbFpxbDZ6SkNoa3lMUUtzWEYrakFmQmdOVkhTTUVHREFXZ0JSWXdCNWZrVVdsWnFsNnpKQ2hreUxRS3NYRitqQUtCZ2dxaGtqT1BRUURBd05wQURCbUFqRUFqMW5IZVhacCsxM05XQk5hK0VEc0RQOEcxV1dnMXRDTVdQL1dIUHFwYVZvMGpoc3dlTkZaZ1NzMGVFN3dZSTRxQWpFQTJXQjlvdDk4c0lrb0YzdlpZZGQzL1Z0V0I1YjlUTk1lYTdJeC9zdEo1VGZjTExlQUJMRTRCTkpPc1E0dm5CSEoiCiAgICAgICAgICB9CiAgICAgICAgXQogICAgICB9LAogICAgICAidmFsaWRGb3IiOiB7CiAgICAgICAgInN0YXJ0IjogIjIwMjItMDQtMTNUMjA6MDY6MTUuMDAwWiIKICAgICAgfQogICAgfQogIF0sCiAgImN0bG9ncyI6IFsKICAgIHsKICAgICAgImJhc2VVcmwiOiAiaHR0cHM6Ly9jdGZlLnNpZ3N0b3JlLmRldi90ZXN0IiwKICAgICAgImhhc2hBbGdvcml0aG0iOiAiU0hBMl8yNTYiLAogICAgICAicHVibGljS2V5IjogewogICAgICAgICJyYXdCeXRlcyI6ICJNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUViZndSK1JKdWRYc2NnUkJScEtYMVhGRHkzUHl1ZER4ei9TZm5SaTFmVDhla3BmQmQyTzF1b3o3anIzWjhuS3p4QTY5RVVRK2VGQ0ZJM3pldWJQV1U3dz09IiwKICAgICAgICAia2V5RGV0YWlscyI6ICJQS0lYX0VDRFNBX1AyNTZfU0hBXzI1NiIsCiAgICAgICAgInZhbGlkRm9yIjogewogICAgICAgICAgInN0YXJ0IjogIjIwMjEtMDMtMTRUMDA6MDA6MDAuMDAwWiIsCiAgICAgICAgICAiZW5kIjogIjIwMjItMTAtMzFUMjM6NTk6NTkuOTk5WiIKICAgICAgICB9CiAgICAgIH0sCiAgICAgICJsb2dJZCI6IHsKICAgICAgICAia2V5SWQiOiAiQ0dDUzhDaFMvMmhGMGRGcko0U2NSV2NZckJZOXd6alNiZWE4SWdZMmIzST0iCiAgICAgIH0KICAgIH0sCiAgICB7CiAgICAgICJiYXNlVXJsIjogImh0dHBzOi8vY3RmZS5zaWdzdG9yZS5kZXYvMjAyMiIsCiAgICAgICJoYXNoQWxnb3JpdGhtIjogIlNIQTJfMjU2IiwKICAgICAgInB1YmxpY0tleSI6IHsKICAgICAgICAicmF3Qnl0ZXMiOiAiTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFaVBTbEZpMENtRlRmRWpDVXFGOUh1Q0VjWVhOS0FhWWFsSUptQlo4eXllelBqVHFoeHJLQnBNbmFvY1Z0TEpCSTFlTTN1WG5RelFHQUpkSjRnczlGeXc9PSIsCiAgICAgICAgImtleURldGFpbHMiOiAiUEtJWF9FQ0RTQV9QMjU2X1NIQV8yNTYiLAogICAgICAgICJ2YWxpZEZvciI6IHsKICAgICAgICAgICJzdGFydCI6ICIyMDIyLTEwLTIwVDAwOjAwOjAwLjAwMFoiCiAgICAgICAgfQogICAgICB9LAogICAgICAibG9nSWQiOiB7CiAgICAgICAgImtleUlkIjogIjNUMHdhc2JIRVRKakdSNGNtV2MzQXFKS1hyamVQSzMvaDRweWdDOHA3bzQ9IgogICAgICB9CiAgICB9CiAgXSwKICAidGltZXN0YW1wQXV0aG9yaXRpZXMiOiBbCiAgICB7CiAgICAgICJzdWJqZWN0IjogewogICAgICAgICJvcmdhbml6YXRpb24iOiAiR2l0SHViLCBJbmMuIiwKICAgICAgICAiY29tbW9uTmFtZSI6ICJJbnRlcm5hbCBTZXJ2aWNlcyBSb290IgogICAgICB9LAogICAgICAiY2VydENoYWluIjogewogICAgICAgICJjZXJ0aWZpY2F0ZXMiOiBbCiAgICAgICAgICB7CiAgICAgICAgICAgICJyYXdCeXRlcyI6ICJNSUlCM0RDQ0FXS2dBd0lCQWdJVWNoa05zSDM2WGEwNGIxTHFJYytxcjlEVmVjTXdDZ1lJS29aSXpqMEVBd013TWpFVk1CTUdBMVVFQ2hNTVIybDBTSFZpTENCSmJtTXVNUmt3RndZRFZRUURFeEJVVTBFZ2FXNTBaWEp0WldScFlYUmxNQjRYRFRJek1EUXhOREF3TURBd01Gb1hEVEkwTURReE16QXdNREF3TUZvd01qRVZNQk1HQTFVRUNoTU1SMmwwU0hWaUxDQkpibU11TVJrd0Z3WURWUVFERXhCVVUwRWdWR2x0WlhOMFlXMXdhVzVuTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFVUQ1Wk5iU3FZTWQ2cjhxcE9PRVg5aWJHblpUOUdzdVhPaHIvZjhVOUZKdWdCR0V4S1lwNDBPVUxTMGVyalpXN3hWOXhWNTJObkpmNU9lRHE0ZTVaS3FOV01GUXdEZ1lEVlIwUEFRSC9CQVFEQWdlQU1CTUdBMVVkSlFRTU1Bb0dDQ3NHQVFVRkJ3TUlNQXdHQTFVZEV3RUIvd1FDTUFBd0h3WURWUjBqQkJnd0ZvQVVhVzFSdWRPZ1Z0MGxlcVkwV0tZYnVQcjQ3d0F3Q2dZSUtvWkl6ajBFQXdNRGFBQXdaUUl3YlVIOUh2RDRlakNaSk9XUW5xQWxrcVVSbGx2dTlNOCtWcUxiaVJLK3pTZlpDWndzaWxqUm44TVFRUlNrWEVFNUFqRUFnK1Z4cXRvamZWZnU4RGh6emhDeDlHS0VUYkpIYjE5aVY3Mm1NS1ViREFGbXpaNmJROGI1NFpiOHRpZHk1YVdlIgogICAgICAgICAgfSwKICAgICAgICAgIHsKICAgICAgICAgICAgInJhd0J5dGVzIjogIk1JSUNFRENDQVpXZ0F3SUJBZ0lVWDhaTzVRWFA3dk40ZE1RNWU5c1UzbnViOE9nd0NnWUlLb1pJemowRUF3TXdPREVWTUJNR0ExVUVDaE1NUjJsMFNIVmlMQ0JKYm1NdU1SOHdIUVlEVlFRREV4WkpiblJsY201aGJDQlRaWEoyYVdObGN5QlNiMjkwTUI0WERUSXpNRFF4TkRBd01EQXdNRm9YRFRJNE1EUXhNakF3TURBd01Gb3dNakVWTUJNR0ExVUVDaE1NUjJsMFNIVmlMQ0JKYm1NdU1Sa3dGd1lEVlFRREV4QlVVMEVnYVc1MFpYSnRaV1JwWVhSbE1IWXdFQVlIS29aSXpqMENBUVlGSzRFRUFDSURZZ0FFdk1MWS9kVFZidklKWUFOQXVzekV3Sm5RRTFsbGZ0eW55TUtJTWhoNDhIbXFiVnI1eWd5YnpzTFJMVktiQldPZFoyMWFlSnorZ1ppeXRaZXRxY3lGOVdsRVI1TkVNZjZKVjdaTm9qUXB4SHE0UkhHb0dTY2VRdi9xdlRpWnhFREtvMll3WkRBT0JnTlZIUThCQWY4RUJBTUNBUVl3RWdZRFZSMFRBUUgvQkFnd0JnRUIvd0lCQURBZEJnTlZIUTRFRmdRVWFXMVJ1ZE9nVnQwbGVxWTBXS1lidVByNDd3QXdId1lEVlIwakJCZ3dGb0FVOU5ZWWxvYm5BRzRjMC9xanh5SC9scS93eitRd0NnWUlLb1pJemowRUF3TURhUUF3WmdJeEFLMUIxODV5Z0NySVlGbElzM0dqc3dqbndTTUc2TFk4d29MVmRha0tEWnhWYThmOGNxTXMxRGhjeEowKzA5dzk1UUl4QU8rdEJ6Wms3dmpVSjlpSmdENFI2WldUeFFXS3FObTc0ak85OW8rbzlzdjRGSS9TWlRaVEZ5TW4wSUpFSGRObXlBPT0iCiAgICAgICAgICB9LAogICAgICAgICAgewogICAgICAgICAgICAicmF3Qnl0ZXMiOiAiTUlJQjlEQ0NBWHFnQXdJQkFnSVVhL0pBa2RVaks0SlV3c3F0YWlSSkdXaHFMU293Q2dZSUtvWkl6ajBFQXdNd09ERVZNQk1HQTFVRUNoTU1SMmwwU0hWaUxDQkpibU11TVI4d0hRWURWUVFERXhaSmJuUmxjbTVoYkNCVFpYSjJhV05sY3lCU2IyOTBNQjRYRFRJek1EUXhOREF3TURBd01Gb1hEVE16TURReE1UQXdNREF3TUZvd09ERVZNQk1HQTFVRUNoTU1SMmwwU0hWaUxDQkpibU11TVI4d0hRWURWUVFERXhaSmJuUmxjbTVoYkNCVFpYSjJhV05sY3lCU2IyOTBNSFl3RUFZSEtvWkl6ajBDQVFZRks0RUVBQ0lEWWdBRWY5akZBWHh6NGt4NjhBSFJNT2tGQmhmbERjTVR2emFYejR4L0ZDY1hqSi8xcUVLb24vcVBJR25hVVJza0R0eU5iTkRPcGVKVERERnF0NDhpTVBybnpweDZJWndxZW1mVUpONHhCRVpmemErcFl0L2l5b2QrOXRacjIwUlJXU3YvbzBVd1F6QU9CZ05WSFE4QkFmOEVCQU1DQVFZd0VnWURWUjBUQVFIL0JBZ3dCZ0VCL3dJQkFqQWRCZ05WSFE0RUZnUVU5TllZbG9ibkFHNGMwL3FqeHlIL2xxL3d6K1F3Q2dZSUtvWkl6ajBFQXdNRGFBQXdaUUl4QUxaTFo4QmdSWHpLeExNTU45VklsTytlNGhyQm5OQmdGN3R6N0hucm93djJOZXRaRXJJQUNLRnltQmx2V0R2dE1BSXdaTytraTZzc1ExYnNabzk4TzhtRUFmMk5aN2lpQ2dERFUwVndqZWNvNnp5ZWgwekJUczkvN2dWNkFITlE1M3hEIgogICAgICAgICAgfQogICAgICAgIF0KICAgICAgfSwKICAgICAgInZhbGlkRm9yIjogewogICAgICAgICJzdGFydCI6ICIyMDIzLTA0LTE0VDAwOjAwOjAwLjAwMFoiCiAgICAgIH0KICAgIH0KICBdCn0K\",\"registry.npmjs.org%2Fkeys.json\":\"ewogICAgImtleXMiOiBbCiAgICAgICAgewogICAgICAgICAgICAia2V5SWQiOiAiU0hBMjU2OmpsM2J3c3d1ODBQampva0NnaDBvMnc1YzJVNExoUUFFNTdnajljejFrekEiLAogICAgICAgICAgICAia2V5VXNhZ2UiOiAibnBtOnNpZ25hdHVyZXMiLAogICAgICAgICAgICAicHVibGljS2V5IjogewogICAgICAgICAgICAgICAgInJhd0J5dGVzIjogIk1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRTFPbGIzek1BRkZ4WEtIaUlrUU81Y0ozWWhsNWk2VVBwK0lodXRlQkpidUhjQTVVb2dLbzBFV3RsV3dXNktTYUtvVE5FWUw3SmxDUWlWbmtoQmt0VWdnPT0iLAogICAgICAgICAgICAgICAgImtleURldGFpbHMiOiAiUEtJWF9FQ0RTQV9QMjU2X1NIQV8yNTYiLAogICAgICAgICAgICAgICAgInZhbGlkRm9yIjogewogICAgICAgICAgICAgICAgICAgICJzdGFydCI6ICIxOTk5LTAxLTAxVDAwOjAwOjAwLjAwMFoiLAogICAgICAgICAgICAgICAgICAgICJlbmQiOiAiMjAyNS0wMS0yOVQwMDowMDowMC4wMDBaIgogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAgICJrZXlJZCI6ICJTSEEyNTY6amwzYndzd3U4MFBqam9rQ2doMG8ydzVjMlU0TGhRQUU1N2dqOWN6MWt6QSIsCiAgICAgICAgICAgICJrZXlVc2FnZSI6ICJucG06YXR0ZXN0YXRpb25zIiwKICAgICAgICAgICAgInB1YmxpY0tleSI6IHsKICAgICAgICAgICAgICAgICJyYXdCeXRlcyI6ICJNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUUxT2xiM3pNQUZGeFhLSGlJa1FPNWNKM1lobDVpNlVQcCtJaHV0ZUJKYnVIY0E1VW9nS28wRVd0bFd3VzZLU2FLb1RORVlMN0psQ1FpVm5raEJrdFVnZz09IiwKICAgICAgICAgICAgICAgICJrZXlEZXRhaWxzIjogIlBLSVhfRUNEU0FfUDI1Nl9TSEFfMjU2IiwKICAgICAgICAgICAgICAgICJ2YWxpZEZvciI6IHsKICAgICAgICAgICAgICAgICAgICAic3RhcnQiOiAiMjAyMi0xMi0wMVQwMDowMDowMC4wMDBaIiwKICAgICAgICAgICAgICAgICAgICAiZW5kIjogIjIwMjUtMDEtMjlUMDA6MDA6MDAuMDAwWiIKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgICAia2V5SWQiOiAiU0hBMjU2OkRoUTh3UjVBUEJ2RkhMRi8rVGMrQVl2UE9kVHBjSURxT2h4c0JIUndDN1UiLAogICAgICAgICAgICAia2V5VXNhZ2UiOiAibnBtOnNpZ25hdHVyZXMiLAogICAgICAgICAgICAicHVibGljS2V5IjogewogICAgICAgICAgICAgICAgInJhd0J5dGVzIjogIk1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRVk2WWE3VysrN2FVUHp2TVRyZXpINlljeDNjK0hPS1lDY05HeWJKWlNDSnEvZmQ3UWE4dXVBS3RkSWtVUXRRaUVLRVJoQW1FNWxNTUpoUDhPa0RPYTJnPT0iLAogICAgICAgICAgICAgICAgImtleURldGFpbHMiOiAiUEtJWF9FQ0RTQV9QMjU2X1NIQV8yNTYiLAogICAgICAgICAgICAgICAgInZhbGlkRm9yIjogewogICAgICAgICAgICAgICAgICAgICJzdGFydCI6ICIyMDI1LTAxLTEzVDAwOjAwOjAwLjAwMFoiCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICAgImtleUlkIjogIlNIQTI1NjpEaFE4d1I1QVBCdkZITEYvK1RjK0FZdlBPZFRwY0lEcU9oeHNCSFJ3QzdVIiwKICAgICAgICAgICAgImtleVVzYWdlIjogIm5wbTphdHRlc3RhdGlvbnMiLAogICAgICAgICAgICAicHVibGljS2V5IjogewogICAgICAgICAgICAgICAgInJhd0J5dGVzIjogIk1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRVk2WWE3VysrN2FVUHp2TVRyZXpINlljeDNjK0hPS1lDY05HeWJKWlNDSnEvZmQ3UWE4dXVBS3RkSWtVUXRRaUVLRVJoQW1FNWxNTUpoUDhPa0RPYTJnPT0iLAogICAgICAgICAgICAgICAgImtleURldGFpbHMiOiAiUEtJWF9FQ0RTQV9QMjU2X1NIQV8yNTYiLAogICAgICAgICAgICAgICAgInZhbGlkRm9yIjogewogICAgICAgICAgICAgICAgICAgICJzdGFydCI6ICIyMDI1LTAxLTEzVDAwOjAwOjAwLjAwMFoiCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICBdCn0K\"}}}});var Xbe=_(y1=>{\"use strict\";var Zbe=y1&&y1.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(y1,\"__esModule\",{value:!0});y1.TUFClient=void 0;var Rg=Zbe(Ie(\"fs\")),GP=Zbe(Ie(\"path\")),qvt=Jbe(),Wvt=pL(),Yvt=Kbe(),YJ=\"targets\",WJ=class{constructor(e){let r=new URL(e.mirrorURL),s=encodeURIComponent(r.host+r.pathname.replace(/\\/$/,\"\")),a=GP.default.join(e.cachePath,s);Vvt(a),Jvt({cachePath:a,mirrorURL:e.mirrorURL,tufRootPath:e.rootPath,forceInit:e.forceInit}),this.updater=Kvt({mirrorURL:e.mirrorURL,cachePath:a,forceCache:e.forceCache,retry:e.retry,timeout:e.timeout})}async refresh(){return this.updater.refresh()}getTarget(e){return(0,Yvt.readTarget)(this.updater,e)}};y1.TUFClient=WJ;function Vvt(t){let e=GP.default.join(t,YJ);Rg.default.existsSync(t)||Rg.default.mkdirSync(t,{recursive:!0}),Rg.default.existsSync(e)||Rg.default.mkdirSync(e)}function Jvt({cachePath:t,mirrorURL:e,tufRootPath:r,forceInit:s}){let a=GP.default.join(t,\"root.json\");if(!Rg.default.existsSync(a)||s)if(r)Rg.default.copyFileSync(r,a);else{let c=zbe()[e];if(!c)throw new Wvt.TUFError({code:\"TUF_INIT_CACHE_ERROR\",message:`No root.json found for mirror: ${e}`});Rg.default.writeFileSync(a,Buffer.from(c[\"root.json\"],\"base64\")),Object.entries(c.targets).forEach(([f,p])=>{Rg.default.writeFileSync(GP.default.join(t,YJ,f),Buffer.from(p,\"base64\"))})}}function Kvt(t){let e={fetchTimeout:t.timeout,fetchRetry:t.retry};return new qvt.Updater({metadataBaseUrl:t.mirrorURL,targetBaseUrl:`${t.mirrorURL}/targets`,metadataDir:t.cachePath,targetDir:GP.default.join(t.cachePath,YJ),forceCache:t.forceCache,config:e})}});var pL=_(gh=>{\"use strict\";Object.defineProperty(gh,\"__esModule\",{value:!0});gh.TUFError=gh.DEFAULT_MIRROR_URL=void 0;gh.getTrustedRoot=nSt;gh.initTUF=iSt;var zvt=mP(),Zvt=QPe(),Xvt=Xbe();gh.DEFAULT_MIRROR_URL=\"https://tuf-repo-cdn.sigstore.dev\";var $vt=\"sigstore-js\",eSt={retries:2},tSt=5e3,rSt=\"trusted_root.json\";async function nSt(t={}){let r=await $be(t).getTarget(rSt);return zvt.TrustedRoot.fromJSON(JSON.parse(r))}async function iSt(t={}){let e=$be(t);return e.refresh().then(()=>e)}function $be(t){return new Xvt.TUFClient({cachePath:t.cachePath||(0,Zvt.appDataPath)($vt),rootPath:t.rootPath,mirrorURL:t.mirrorURL||gh.DEFAULT_MIRROR_URL,retry:t.retry??eSt,timeout:t.timeout??tSt,forceCache:t.forceCache??!1,forceInit:t.forceInit??t.force??!1})}var sSt=qJ();Object.defineProperty(gh,\"TUFError\",{enumerable:!0,get:function(){return sSt.TUFError}})});var exe=_(hL=>{\"use strict\";Object.defineProperty(hL,\"__esModule\",{value:!0});hL.DSSESignatureContent=void 0;var qP=Cl(),VJ=class{constructor(e){this.env=e}compareDigest(e){return qP.crypto.bufferEqual(e,qP.crypto.digest(\"sha256\",this.env.payload))}compareSignature(e){return qP.crypto.bufferEqual(e,this.signature)}verifySignature(e){return qP.crypto.verify(this.preAuthEncoding,e,this.signature)}get signature(){return this.env.signatures.length>0?this.env.signatures[0].sig:Buffer.from(\"\")}get preAuthEncoding(){return qP.dsse.preAuthEncoding(this.env.payloadType,this.env.payload)}};hL.DSSESignatureContent=VJ});var txe=_(gL=>{\"use strict\";Object.defineProperty(gL,\"__esModule\",{value:!0});gL.MessageSignatureContent=void 0;var JJ=Cl(),KJ=class{constructor(e,r){this.signature=e.signature,this.messageDigest=e.messageDigest.digest,this.artifact=r}compareSignature(e){return JJ.crypto.bufferEqual(e,this.signature)}compareDigest(e){return JJ.crypto.bufferEqual(e,this.messageDigest)}verifySignature(e){return JJ.crypto.verify(this.artifact,e,this.signature)}};gL.MessageSignatureContent=KJ});var nxe=_(dL=>{\"use strict\";Object.defineProperty(dL,\"__esModule\",{value:!0});dL.toSignedEntity=lSt;dL.signatureContent=rxe;var zJ=Cl(),oSt=exe(),aSt=txe();function lSt(t,e){let{tlogEntries:r,timestampVerificationData:s}=t.verificationMaterial,a=[];for(let n of r)a.push({$case:\"transparency-log\",tlogEntry:n});for(let n of s?.rfc3161Timestamps??[])a.push({$case:\"timestamp-authority\",timestamp:zJ.RFC3161Timestamp.parse(n.signedTimestamp)});return{signature:rxe(t,e),key:cSt(t),tlogEntries:r,timestamps:a}}function rxe(t,e){switch(t.content.$case){case\"dsseEnvelope\":return new oSt.DSSESignatureContent(t.content.dsseEnvelope);case\"messageSignature\":return new aSt.MessageSignatureContent(t.content.messageSignature,e)}}function cSt(t){switch(t.verificationMaterial.content.$case){case\"publicKey\":return{$case:\"public-key\",hint:t.verificationMaterial.content.publicKey.hint};case\"x509CertificateChain\":return{$case:\"certificate\",certificate:zJ.X509Certificate.parse(t.verificationMaterial.content.x509CertificateChain.certificates[0].rawBytes)};case\"certificate\":return{$case:\"certificate\",certificate:zJ.X509Certificate.parse(t.verificationMaterial.content.certificate.rawBytes)}}}});var Eo=_(E1=>{\"use strict\";Object.defineProperty(E1,\"__esModule\",{value:!0});E1.PolicyError=E1.VerificationError=void 0;var mL=class extends Error{constructor({code:e,message:r,cause:s}){super(r),this.code=e,this.cause=s,this.name=this.constructor.name}},ZJ=class extends mL{};E1.VerificationError=ZJ;var XJ=class extends mL{};E1.PolicyError=XJ});var ixe=_(yL=>{\"use strict\";Object.defineProperty(yL,\"__esModule\",{value:!0});yL.filterCertAuthorities=uSt;yL.filterTLogAuthorities=fSt;function uSt(t,e){return t.filter(r=>r.validFor.start<=e.start&&r.validFor.end>=e.end)}function fSt(t,e){return t.filter(r=>e.logID&&!r.logID.equals(e.logID)?!1:r.validFor.start<=e.targetDate&&e.targetDate<=r.validFor.end)}});var py=_(Ay=>{\"use strict\";Object.defineProperty(Ay,\"__esModule\",{value:!0});Ay.filterTLogAuthorities=Ay.filterCertAuthorities=void 0;Ay.toTrustMaterial=pSt;var $J=Cl(),WP=mP(),ASt=Eo(),eK=new Date(0),tK=new Date(864e13),axe=ixe();Object.defineProperty(Ay,\"filterCertAuthorities\",{enumerable:!0,get:function(){return axe.filterCertAuthorities}});Object.defineProperty(Ay,\"filterTLogAuthorities\",{enumerable:!0,get:function(){return axe.filterTLogAuthorities}});function pSt(t,e){let r=typeof e==\"function\"?e:hSt(e);return{certificateAuthorities:t.certificateAuthorities.map(oxe),timestampAuthorities:t.timestampAuthorities.map(oxe),tlogs:t.tlogs.map(sxe),ctlogs:t.ctlogs.map(sxe),publicKey:r}}function sxe(t){let e=t.publicKey.keyDetails,r=e===WP.PublicKeyDetails.PKCS1_RSA_PKCS1V5||e===WP.PublicKeyDetails.PKIX_RSA_PKCS1V5||e===WP.PublicKeyDetails.PKIX_RSA_PKCS1V15_2048_SHA256||e===WP.PublicKeyDetails.PKIX_RSA_PKCS1V15_3072_SHA256||e===WP.PublicKeyDetails.PKIX_RSA_PKCS1V15_4096_SHA256?\"pkcs1\":\"spki\";return{logID:t.logId.keyId,publicKey:$J.crypto.createPublicKey(t.publicKey.rawBytes,r),validFor:{start:t.publicKey.validFor?.start||eK,end:t.publicKey.validFor?.end||tK}}}function oxe(t){return{certChain:t.certChain.certificates.map(e=>$J.X509Certificate.parse(e.rawBytes)),validFor:{start:t.validFor?.start||eK,end:t.validFor?.end||tK}}}function hSt(t){return e=>{let r=(t||{})[e];if(!r)throw new ASt.VerificationError({code:\"PUBLIC_KEY_ERROR\",message:`key not found: ${e}`});return{publicKey:$J.crypto.createPublicKey(r.rawBytes),validFor:s=>(r.validFor?.start||eK)<=s&&(r.validFor?.end||tK)>=s}}}});var rK=_(YP=>{\"use strict\";Object.defineProperty(YP,\"__esModule\",{value:!0});YP.CertificateChainVerifier=void 0;YP.verifyCertificateChain=dSt;var hy=Eo(),gSt=py();function dSt(t,e){let r=(0,gSt.filterCertAuthorities)(e,{start:t.notBefore,end:t.notAfter}),s;for(let a of r)try{return new EL({trustedCerts:a.certChain,untrustedCert:t}).verify()}catch(n){s=n}throw new hy.VerificationError({code:\"CERTIFICATE_ERROR\",message:\"Failed to verify certificate chain\",cause:s})}var EL=class{constructor(e){this.untrustedCert=e.untrustedCert,this.trustedCerts=e.trustedCerts,this.localCerts=mSt([...e.trustedCerts,e.untrustedCert])}verify(){let e=this.sort();return this.checkPath(e),e}sort(){let e=this.untrustedCert,r=this.buildPaths(e);if(r=r.filter(a=>a.some(n=>this.trustedCerts.includes(n))),r.length===0)throw new hy.VerificationError({code:\"CERTIFICATE_ERROR\",message:\"no trusted certificate path found\"});let s=r.reduce((a,n)=>a.length<n.length?a:n);return[e,...s].slice(0,-1)}buildPaths(e){let r=[],s=this.findIssuer(e);if(s.length===0)throw new hy.VerificationError({code:\"CERTIFICATE_ERROR\",message:\"no valid certificate path found\"});for(let a=0;a<s.length;a++){let n=s[a];if(n.equals(e)){r.push([e]);continue}let c=this.buildPaths(n);for(let f=0;f<c.length;f++)r.push([n,...c[f]])}return r}findIssuer(e){let r=[],s;return e.subject.equals(e.issuer)&&e.verify()?[e]:(e.extAuthorityKeyID&&(s=e.extAuthorityKeyID.keyIdentifier),this.localCerts.forEach(a=>{if(s&&a.extSubjectKeyID){a.extSubjectKeyID.keyIdentifier.equals(s)&&r.push(a);return}a.subject.equals(e.issuer)&&r.push(a)}),r=r.filter(a=>{try{return e.verify(a)}catch{return!1}}),r)}checkPath(e){if(e.length<1)throw new hy.VerificationError({code:\"CERTIFICATE_ERROR\",message:\"certificate chain must contain at least one certificate\"});if(!e.slice(1).every(s=>s.isCA))throw new hy.VerificationError({code:\"CERTIFICATE_ERROR\",message:\"intermediate certificate is not a CA\"});for(let s=e.length-2;s>=0;s--)if(!e[s].issuer.equals(e[s+1].subject))throw new hy.VerificationError({code:\"CERTIFICATE_ERROR\",message:\"incorrect certificate name chaining\"});for(let s=0;s<e.length;s++){let a=e[s];if(a.extBasicConstraints?.isCA){let n=a.extBasicConstraints.pathLenConstraint;if(n!==void 0&&n<s-1)throw new hy.VerificationError({code:\"CERTIFICATE_ERROR\",message:\"path length constraint exceeded\"})}}}};YP.CertificateChainVerifier=EL;function mSt(t){for(let e=0;e<t.length;e++)for(let r=e+1;r<t.length;r++)t[e].equals(t[r])&&(t.splice(r,1),r--);return t}});var lxe=_(nK=>{\"use strict\";Object.defineProperty(nK,\"__esModule\",{value:!0});nK.verifySCTs=ISt;var IL=Cl(),ySt=Eo(),ESt=py();function ISt(t,e,r){let s,a=t.clone();for(let p=0;p<a.extensions.length;p++){let h=a.extensions[p];if(h.subs[0].toOID()===IL.EXTENSION_OID_SCT){s=new IL.X509SCTExtension(h),a.extensions.splice(p,1);break}}if(!s)return[];if(s.signedCertificateTimestamps.length===0)return[];let n=new IL.ByteStream,c=IL.crypto.digest(\"sha256\",e.publicKey);n.appendView(c);let f=a.tbsCertificate.toDER();return n.appendUint24(f.length),n.appendView(f),s.signedCertificateTimestamps.map(p=>{if(!(0,ESt.filterTLogAuthorities)(r,{logID:p.logID,targetDate:p.datetime}).some(C=>p.verify(n.buffer,C.publicKey)))throw new ySt.VerificationError({code:\"CERTIFICATE_ERROR\",message:\"SCT verification failed\"});return p.logID})}});var uxe=_(CL=>{\"use strict\";Object.defineProperty(CL,\"__esModule\",{value:!0});CL.verifyPublicKey=DSt;CL.verifyCertificate=PSt;var CSt=Cl(),cxe=Eo(),wSt=rK(),BSt=lxe(),vSt=\"1.3.6.1.4.1.57264.1.1\",SSt=\"1.3.6.1.4.1.57264.1.8\";function DSt(t,e,r){let s=r.publicKey(t);return e.forEach(a=>{if(!s.validFor(a))throw new cxe.VerificationError({code:\"PUBLIC_KEY_ERROR\",message:`Public key is not valid for timestamp: ${a.toISOString()}`})}),{key:s.publicKey}}function PSt(t,e,r){let s=(0,wSt.verifyCertificateChain)(t,r.certificateAuthorities);if(!e.every(n=>s.every(c=>c.validForDate(n))))throw new cxe.VerificationError({code:\"CERTIFICATE_ERROR\",message:\"certificate is not valid or expired at the specified date\"});return{scts:(0,BSt.verifySCTs)(s[0],s[1],r.ctlogs),signer:bSt(s[0])}}function bSt(t){let e,r=t.extension(SSt);r?e=r.valueObj.subs?.[0]?.value.toString(\"ascii\"):e=t.extension(vSt)?.value.toString(\"ascii\");let s={extensions:{issuer:e},subjectAlternativeName:t.subjectAltName};return{key:CSt.crypto.createPublicKey(t.publicKey),identity:s}}});var Axe=_(wL=>{\"use strict\";Object.defineProperty(wL,\"__esModule\",{value:!0});wL.verifySubjectAlternativeName=xSt;wL.verifyExtensions=kSt;var fxe=Eo();function xSt(t,e){if(e===void 0||!e.match(t))throw new fxe.PolicyError({code:\"UNTRUSTED_SIGNER_ERROR\",message:`certificate identity error - expected ${t}, got ${e}`})}function kSt(t,e={}){let r;for(r in t)if(e[r]!==t[r])throw new fxe.PolicyError({code:\"UNTRUSTED_SIGNER_ERROR\",message:`invalid certificate extension - expected ${r}=${t[r]}, got ${r}=${e[r]}`})}});var pxe=_(lK=>{\"use strict\";Object.defineProperty(lK,\"__esModule\",{value:!0});lK.verifyCheckpoint=TSt;var sK=Cl(),I1=Eo(),QSt=py(),iK=`\n\n`,RSt=/\\u2014 (\\S+) (\\S+)\\n/g;function TSt(t,e){let r=(0,QSt.filterTLogAuthorities)(e,{targetDate:new Date(Number(t.integratedTime)*1e3)}),s=t.inclusionProof,a=oK.fromString(s.checkpoint.envelope),n=aK.fromString(a.note);if(!FSt(a,r))throw new I1.VerificationError({code:\"TLOG_INCLUSION_PROOF_ERROR\",message:\"invalid checkpoint signature\"});if(!sK.crypto.bufferEqual(n.logHash,s.rootHash))throw new I1.VerificationError({code:\"TLOG_INCLUSION_PROOF_ERROR\",message:\"root hash mismatch\"})}function FSt(t,e){let r=Buffer.from(t.note,\"utf-8\");return t.signatures.every(s=>{let a=e.find(n=>sK.crypto.bufferEqual(n.logID.subarray(0,4),s.keyHint));return a?sK.crypto.verify(r,a.publicKey,s.signature):!1})}var oK=class t{constructor(e,r){this.note=e,this.signatures=r}static fromString(e){if(!e.includes(iK))throw new I1.VerificationError({code:\"TLOG_INCLUSION_PROOF_ERROR\",message:\"missing checkpoint separator\"});let r=e.indexOf(iK),s=e.slice(0,r+1),n=e.slice(r+iK.length).matchAll(RSt),c=Array.from(n,f=>{let[,p,h]=f,E=Buffer.from(h,\"base64\");if(E.length<5)throw new I1.VerificationError({code:\"TLOG_INCLUSION_PROOF_ERROR\",message:\"malformed checkpoint signature\"});return{name:p,keyHint:E.subarray(0,4),signature:E.subarray(4)}});if(c.length===0)throw new I1.VerificationError({code:\"TLOG_INCLUSION_PROOF_ERROR\",message:\"no signatures found in checkpoint\"});return new t(s,c)}},aK=class t{constructor(e,r,s,a){this.origin=e,this.logSize=r,this.logHash=s,this.rest=a}static fromString(e){let r=e.trimEnd().split(`\n`);if(r.length<3)throw new I1.VerificationError({code:\"TLOG_INCLUSION_PROOF_ERROR\",message:\"too few lines in checkpoint header\"});let s=r[0],a=BigInt(r[1]),n=Buffer.from(r[2],\"base64\"),c=r.slice(3);return new t(s,a,n,c)}}});var hxe=_(AK=>{\"use strict\";Object.defineProperty(AK,\"__esModule\",{value:!0});AK.verifyMerkleInclusion=LSt;var fK=Cl(),cK=Eo(),NSt=Buffer.from([0]),OSt=Buffer.from([1]);function LSt(t){let e=t.inclusionProof,r=BigInt(e.logIndex),s=BigInt(e.treeSize);if(r<0n||r>=s)throw new cK.VerificationError({code:\"TLOG_INCLUSION_PROOF_ERROR\",message:`invalid index: ${r}`});let{inner:a,border:n}=MSt(r,s);if(e.hashes.length!==a+n)throw new cK.VerificationError({code:\"TLOG_INCLUSION_PROOF_ERROR\",message:\"invalid hash count\"});let c=e.hashes.slice(0,a),f=e.hashes.slice(a),p=qSt(t.canonicalizedBody),h=_St(USt(p,c,r),f);if(!fK.crypto.bufferEqual(h,e.rootHash))throw new cK.VerificationError({code:\"TLOG_INCLUSION_PROOF_ERROR\",message:\"calculated root hash does not match inclusion proof\"})}function MSt(t,e){let r=HSt(t,e),s=jSt(t>>BigInt(r));return{inner:r,border:s}}function USt(t,e,r){return e.reduce((s,a,n)=>r>>BigInt(n)&BigInt(1)?uK(a,s):uK(s,a),t)}function _St(t,e){return e.reduce((r,s)=>uK(s,r),t)}function HSt(t,e){return GSt(t^e-BigInt(1))}function jSt(t){return t.toString(2).split(\"1\").length-1}function GSt(t){return t===0n?0:t.toString(2).length}function uK(t,e){return fK.crypto.digest(\"sha256\",OSt,t,e)}function qSt(t){return fK.crypto.digest(\"sha256\",NSt,t)}});var dxe=_(pK=>{\"use strict\";Object.defineProperty(pK,\"__esModule\",{value:!0});pK.verifyTLogSET=VSt;var gxe=Cl(),WSt=Eo(),YSt=py();function VSt(t,e){if(!(0,YSt.filterTLogAuthorities)(e,{logID:t.logId.keyId,targetDate:new Date(Number(t.integratedTime)*1e3)}).some(a=>{let n=JSt(t),c=Buffer.from(gxe.json.canonicalize(n),\"utf8\"),f=t.inclusionPromise.signedEntryTimestamp;return gxe.crypto.verify(c,a.publicKey,f)}))throw new WSt.VerificationError({code:\"TLOG_INCLUSION_PROMISE_ERROR\",message:\"inclusion promise could not be verified\"})}function JSt(t){let{integratedTime:e,logIndex:r,logId:s,canonicalizedBody:a}=t;return{body:a.toString(\"base64\"),integratedTime:Number(e),logIndex:Number(r),logID:s.keyId.toString(\"hex\")}}});var mxe=_(dK=>{\"use strict\";Object.defineProperty(dK,\"__esModule\",{value:!0});dK.verifyRFC3161Timestamp=ZSt;var hK=Cl(),gK=Eo(),KSt=rK(),zSt=py();function ZSt(t,e,r){let s=t.signingTime;if(r=(0,zSt.filterCertAuthorities)(r,{start:s,end:s}),r=$St(r,{serialNumber:t.signerSerialNumber,issuer:t.signerIssuer}),!r.some(n=>{try{return XSt(t,e,n),!0}catch{return!1}}))throw new gK.VerificationError({code:\"TIMESTAMP_ERROR\",message:\"timestamp could not be verified\"})}function XSt(t,e,r){let[s,...a]=r.certChain,n=hK.crypto.createPublicKey(s.publicKey),c=t.signingTime;try{new KSt.CertificateChainVerifier({untrustedCert:s,trustedCerts:a}).verify()}catch{throw new gK.VerificationError({code:\"TIMESTAMP_ERROR\",message:\"invalid certificate chain\"})}if(!r.certChain.every(p=>p.validForDate(c)))throw new gK.VerificationError({code:\"TIMESTAMP_ERROR\",message:\"timestamp was signed with an expired certificate\"});t.verify(e,n)}function $St(t,e){return t.filter(r=>r.certChain.length>0&&hK.crypto.bufferEqual(r.certChain[0].serialNumber,e.serialNumber)&&hK.crypto.bufferEqual(r.certChain[0].issuer,e.issuer))}});var yxe=_(BL=>{\"use strict\";Object.defineProperty(BL,\"__esModule\",{value:!0});BL.verifyTSATimestamp=sDt;BL.verifyTLogTimestamp=oDt;var eDt=Eo(),tDt=pxe(),rDt=hxe(),nDt=dxe(),iDt=mxe();function sDt(t,e,r){return(0,iDt.verifyRFC3161Timestamp)(t,e,r),{type:\"timestamp-authority\",logID:t.signerSerialNumber,timestamp:t.signingTime}}function oDt(t,e){let r=!1;if(aDt(t)&&((0,nDt.verifyTLogSET)(t,e),r=!0),lDt(t)&&((0,rDt.verifyMerkleInclusion)(t),(0,tDt.verifyCheckpoint)(t,e),r=!0),!r)throw new eDt.VerificationError({code:\"TLOG_MISSING_INCLUSION_ERROR\",message:\"inclusion could not be verified\"});return{type:\"transparency-log\",logID:t.logId.keyId,timestamp:new Date(Number(t.integratedTime)*1e3)}}function aDt(t){return t.inclusionPromise!==void 0}function lDt(t){return t.inclusionProof!==void 0}});var Exe=_(mK=>{\"use strict\";Object.defineProperty(mK,\"__esModule\",{value:!0});mK.verifyDSSETLogBody=cDt;var vL=Eo();function cDt(t,e){switch(t.apiVersion){case\"0.0.1\":return uDt(t,e);default:throw new vL.VerificationError({code:\"TLOG_BODY_ERROR\",message:`unsupported dsse version: ${t.apiVersion}`})}}function uDt(t,e){if(t.spec.signatures?.length!==1)throw new vL.VerificationError({code:\"TLOG_BODY_ERROR\",message:\"signature count mismatch\"});let r=t.spec.signatures[0].signature;if(!e.compareSignature(Buffer.from(r,\"base64\")))throw new vL.VerificationError({code:\"TLOG_BODY_ERROR\",message:\"tlog entry signature mismatch\"});let s=t.spec.payloadHash?.value||\"\";if(!e.compareDigest(Buffer.from(s,\"hex\")))throw new vL.VerificationError({code:\"TLOG_BODY_ERROR\",message:\"DSSE payload hash mismatch\"})}});var Ixe=_(EK=>{\"use strict\";Object.defineProperty(EK,\"__esModule\",{value:!0});EK.verifyHashedRekordTLogBody=fDt;var yK=Eo();function fDt(t,e){switch(t.apiVersion){case\"0.0.1\":return ADt(t,e);default:throw new yK.VerificationError({code:\"TLOG_BODY_ERROR\",message:`unsupported hashedrekord version: ${t.apiVersion}`})}}function ADt(t,e){let r=t.spec.signature.content||\"\";if(!e.compareSignature(Buffer.from(r,\"base64\")))throw new yK.VerificationError({code:\"TLOG_BODY_ERROR\",message:\"signature mismatch\"});let s=t.spec.data.hash?.value||\"\";if(!e.compareDigest(Buffer.from(s,\"hex\")))throw new yK.VerificationError({code:\"TLOG_BODY_ERROR\",message:\"digest mismatch\"})}});var Cxe=_(IK=>{\"use strict\";Object.defineProperty(IK,\"__esModule\",{value:!0});IK.verifyIntotoTLogBody=pDt;var SL=Eo();function pDt(t,e){switch(t.apiVersion){case\"0.0.2\":return hDt(t,e);default:throw new SL.VerificationError({code:\"TLOG_BODY_ERROR\",message:`unsupported intoto version: ${t.apiVersion}`})}}function hDt(t,e){if(t.spec.content.envelope.signatures?.length!==1)throw new SL.VerificationError({code:\"TLOG_BODY_ERROR\",message:\"signature count mismatch\"});let r=gDt(t.spec.content.envelope.signatures[0].sig);if(!e.compareSignature(Buffer.from(r,\"base64\")))throw new SL.VerificationError({code:\"TLOG_BODY_ERROR\",message:\"tlog entry signature mismatch\"});let s=t.spec.content.payloadHash?.value||\"\";if(!e.compareDigest(Buffer.from(s,\"hex\")))throw new SL.VerificationError({code:\"TLOG_BODY_ERROR\",message:\"DSSE payload hash mismatch\"})}function gDt(t){return Buffer.from(t,\"base64\").toString(\"utf-8\")}});var Bxe=_(CK=>{\"use strict\";Object.defineProperty(CK,\"__esModule\",{value:!0});CK.verifyTLogBody=EDt;var wxe=Eo(),dDt=Exe(),mDt=Ixe(),yDt=Cxe();function EDt(t,e){let{kind:r,version:s}=t.kindVersion,a=JSON.parse(t.canonicalizedBody.toString(\"utf8\"));if(r!==a.kind||s!==a.apiVersion)throw new wxe.VerificationError({code:\"TLOG_BODY_ERROR\",message:`kind/version mismatch - expected: ${r}/${s}, received: ${a.kind}/${a.apiVersion}`});switch(a.kind){case\"dsse\":return(0,dDt.verifyDSSETLogBody)(a,e);case\"intoto\":return(0,yDt.verifyIntotoTLogBody)(a,e);case\"hashedrekord\":return(0,mDt.verifyHashedRekordTLogBody)(a,e);default:throw new wxe.VerificationError({code:\"TLOG_BODY_ERROR\",message:`unsupported kind: ${r}`})}}});var bxe=_(DL=>{\"use strict\";Object.defineProperty(DL,\"__esModule\",{value:!0});DL.Verifier=void 0;var IDt=Ie(\"util\"),C1=Eo(),vxe=uxe(),Sxe=Axe(),Dxe=yxe(),CDt=Bxe(),wK=class{constructor(e,r={}){this.trustMaterial=e,this.options={ctlogThreshold:r.ctlogThreshold??1,tlogThreshold:r.tlogThreshold??1,tsaThreshold:r.tsaThreshold??0}}verify(e,r){let s=this.verifyTimestamps(e),a=this.verifySigningKey(e,s);return this.verifyTLogs(e),this.verifySignature(e,a),r&&this.verifyPolicy(r,a.identity||{}),a}verifyTimestamps(e){let r=0,s=0,a=e.timestamps.map(n=>{switch(n.$case){case\"timestamp-authority\":return s++,(0,Dxe.verifyTSATimestamp)(n.timestamp,e.signature.signature,this.trustMaterial.timestampAuthorities);case\"transparency-log\":return r++,(0,Dxe.verifyTLogTimestamp)(n.tlogEntry,this.trustMaterial.tlogs)}});if(Pxe(a))throw new C1.VerificationError({code:\"TIMESTAMP_ERROR\",message:\"duplicate timestamp\"});if(r<this.options.tlogThreshold)throw new C1.VerificationError({code:\"TIMESTAMP_ERROR\",message:`expected ${this.options.tlogThreshold} tlog timestamps, got ${r}`});if(s<this.options.tsaThreshold)throw new C1.VerificationError({code:\"TIMESTAMP_ERROR\",message:`expected ${this.options.tsaThreshold} tsa timestamps, got ${s}`});return a.map(n=>n.timestamp)}verifySigningKey({key:e},r){switch(e.$case){case\"public-key\":return(0,vxe.verifyPublicKey)(e.hint,r,this.trustMaterial);case\"certificate\":{let s=(0,vxe.verifyCertificate)(e.certificate,r,this.trustMaterial);if(Pxe(s.scts))throw new C1.VerificationError({code:\"CERTIFICATE_ERROR\",message:\"duplicate SCT\"});if(s.scts.length<this.options.ctlogThreshold)throw new C1.VerificationError({code:\"CERTIFICATE_ERROR\",message:`expected ${this.options.ctlogThreshold} SCTs, got ${s.scts.length}`});return s.signer}}}verifyTLogs({signature:e,tlogEntries:r}){r.forEach(s=>(0,CDt.verifyTLogBody)(s,e))}verifySignature(e,r){if(!e.signature.verifySignature(r.key))throw new C1.VerificationError({code:\"SIGNATURE_ERROR\",message:\"signature verification failed\"})}verifyPolicy(e,r){e.subjectAlternativeName&&(0,Sxe.verifySubjectAlternativeName)(e.subjectAlternativeName,r.subjectAlternativeName),e.extensions&&(0,Sxe.verifyExtensions)(e.extensions,r.extensions)}};DL.Verifier=wK;function Pxe(t){for(let e=0;e<t.length;e++)for(let r=e+1;r<t.length;r++)if((0,IDt.isDeepStrictEqual)(t[e],t[r]))return!0;return!1}});var PL=_(iu=>{\"use strict\";Object.defineProperty(iu,\"__esModule\",{value:!0});iu.Verifier=iu.toTrustMaterial=iu.VerificationError=iu.PolicyError=iu.toSignedEntity=void 0;var wDt=nxe();Object.defineProperty(iu,\"toSignedEntity\",{enumerable:!0,get:function(){return wDt.toSignedEntity}});var xxe=Eo();Object.defineProperty(iu,\"PolicyError\",{enumerable:!0,get:function(){return xxe.PolicyError}});Object.defineProperty(iu,\"VerificationError\",{enumerable:!0,get:function(){return xxe.VerificationError}});var BDt=py();Object.defineProperty(iu,\"toTrustMaterial\",{enumerable:!0,get:function(){return BDt.toTrustMaterial}});var vDt=bxe();Object.defineProperty(iu,\"Verifier\",{enumerable:!0,get:function(){return vDt.Verifier}})});var kxe=_(Fa=>{\"use strict\";Object.defineProperty(Fa,\"__esModule\",{value:!0});Fa.DEFAULT_TIMEOUT=Fa.DEFAULT_RETRY=void 0;Fa.createBundleBuilder=PDt;Fa.createKeyFinder=bDt;Fa.createVerificationPolicy=xDt;var SDt=Cl(),w1=F7(),DDt=PL();Fa.DEFAULT_RETRY={retries:2};Fa.DEFAULT_TIMEOUT=5e3;function PDt(t,e){let r={signer:kDt(e),witnesses:RDt(e)};switch(t){case\"messageSignature\":return new w1.MessageSignatureBundleBuilder(r);case\"dsseEnvelope\":return new w1.DSSEBundleBuilder({...r,certificateChain:e.legacyCompatibility})}}function bDt(t){return e=>{let r=t(e);if(!r)throw new DDt.VerificationError({code:\"PUBLIC_KEY_ERROR\",message:`key not found: ${e}`});return{publicKey:SDt.crypto.createPublicKey(r),validFor:()=>!0}}}function xDt(t){let e={},r=t.certificateIdentityEmail||t.certificateIdentityURI;return r&&(e.subjectAlternativeName=r),t.certificateIssuer&&(e.extensions={issuer:t.certificateIssuer}),e}function kDt(t){return new w1.FulcioSigner({fulcioBaseURL:t.fulcioURL,identityProvider:t.identityProvider||QDt(t),retry:t.retry??Fa.DEFAULT_RETRY,timeout:t.timeout??Fa.DEFAULT_TIMEOUT})}function QDt(t){let e=t.identityToken;return e?{getToken:()=>Promise.resolve(e)}:new w1.CIContextProvider(\"sigstore\")}function RDt(t){let e=[];return TDt(t)&&e.push(new w1.RekorWitness({rekorBaseURL:t.rekorURL,entryType:t.legacyCompatibility?\"intoto\":\"dsse\",fetchOnConflict:!1,retry:t.retry??Fa.DEFAULT_RETRY,timeout:t.timeout??Fa.DEFAULT_TIMEOUT})),FDt(t)&&e.push(new w1.TSAWitness({tsaBaseURL:t.tsaServerURL,retry:t.retry??Fa.DEFAULT_RETRY,timeout:t.timeout??Fa.DEFAULT_TIMEOUT})),e}function TDt(t){return t.tlogUpload!==!1}function FDt(t){return t.tsaServerURL!==void 0}});var Txe=_(su=>{\"use strict\";var NDt=su&&su.__createBinding||(Object.create?function(t,e,r,s){s===void 0&&(s=r);var a=Object.getOwnPropertyDescriptor(e,r);(!a||(\"get\"in a?!e.__esModule:a.writable||a.configurable))&&(a={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,s,a)}:function(t,e,r,s){s===void 0&&(s=r),t[s]=e[r]}),ODt=su&&su.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),Qxe=su&&su.__importStar||function(){var t=function(e){return t=Object.getOwnPropertyNames||function(r){var s=[];for(var a in r)Object.prototype.hasOwnProperty.call(r,a)&&(s[s.length]=a);return s},t(e)};return function(e){if(e&&e.__esModule)return e;var r={};if(e!=null)for(var s=t(e),a=0;a<s.length;a++)s[a]!==\"default\"&&NDt(r,e,s[a]);return ODt(r,e),r}}();Object.defineProperty(su,\"__esModule\",{value:!0});su.sign=MDt;su.attest=UDt;su.verify=_Dt;su.createVerifier=Rxe;var vK=EP(),LDt=Qxe(pL()),BK=PL(),B1=Qxe(kxe());async function MDt(t,e={}){let s=await B1.createBundleBuilder(\"messageSignature\",e).create({data:t});return(0,vK.bundleToJSON)(s)}async function UDt(t,e,r={}){let a=await B1.createBundleBuilder(\"dsseEnvelope\",r).create({data:t,type:e});return(0,vK.bundleToJSON)(a)}async function _Dt(t,e,r){let s;return Buffer.isBuffer(e)?s=e:r=e,Rxe(r).then(a=>a.verify(t,s))}async function Rxe(t={}){let e=await LDt.getTrustedRoot({mirrorURL:t.tufMirrorURL,rootPath:t.tufRootPath,cachePath:t.tufCachePath,forceCache:t.tufForceCache,retry:t.retry??B1.DEFAULT_RETRY,timeout:t.timeout??B1.DEFAULT_TIMEOUT}),r=t.keySelector?B1.createKeyFinder(t.keySelector):void 0,s=(0,BK.toTrustMaterial)(e,r),a={ctlogThreshold:t.ctLogThreshold,tlogThreshold:t.tlogThreshold},n=new BK.Verifier(s,a),c=B1.createVerificationPolicy(t);return{verify:(f,p)=>{let h=(0,vK.bundleFromJSON)(f),E=(0,BK.toSignedEntity)(h,p);n.verify(E,c)}}}});var Nxe=_(Ni=>{\"use strict\";Object.defineProperty(Ni,\"__esModule\",{value:!0});Ni.verify=Ni.sign=Ni.createVerifier=Ni.attest=Ni.VerificationError=Ni.PolicyError=Ni.TUFError=Ni.InternalError=Ni.DEFAULT_REKOR_URL=Ni.DEFAULT_FULCIO_URL=Ni.ValidationError=void 0;var HDt=EP();Object.defineProperty(Ni,\"ValidationError\",{enumerable:!0,get:function(){return HDt.ValidationError}});var SK=F7();Object.defineProperty(Ni,\"DEFAULT_FULCIO_URL\",{enumerable:!0,get:function(){return SK.DEFAULT_FULCIO_URL}});Object.defineProperty(Ni,\"DEFAULT_REKOR_URL\",{enumerable:!0,get:function(){return SK.DEFAULT_REKOR_URL}});Object.defineProperty(Ni,\"InternalError\",{enumerable:!0,get:function(){return SK.InternalError}});var jDt=pL();Object.defineProperty(Ni,\"TUFError\",{enumerable:!0,get:function(){return jDt.TUFError}});var Fxe=PL();Object.defineProperty(Ni,\"PolicyError\",{enumerable:!0,get:function(){return Fxe.PolicyError}});Object.defineProperty(Ni,\"VerificationError\",{enumerable:!0,get:function(){return Fxe.VerificationError}});var bL=Txe();Object.defineProperty(Ni,\"attest\",{enumerable:!0,get:function(){return bL.attest}});Object.defineProperty(Ni,\"createVerifier\",{enumerable:!0,get:function(){return bL.createVerifier}});Object.defineProperty(Ni,\"sign\",{enumerable:!0,get:function(){return bL.sign}});Object.defineProperty(Ni,\"verify\",{enumerable:!0,get:function(){return bL.verify}})});Dt();Ge();Dt();var pke=Ie(\"child_process\"),hke=ut(Fd());Yt();var $I=new Map([]);var Gv={};Vt(Gv,{BaseCommand:()=>ft,WorkspaceRequiredError:()=>ar,getCli:()=>Bde,getDynamicLibs:()=>wde,getPluginConfiguration:()=>tC,openWorkspace:()=>eC,pluginCommands:()=>$I,runExit:()=>YT});Yt();var ft=class extends ot{constructor(){super(...arguments);this.cwd=ge.String(\"--cwd\",{hidden:!0})}validateAndExecute(){if(typeof this.cwd<\"u\")throw new nt(\"The --cwd option is ambiguous when used anywhere else than the very first parameter provided in the command line, before even the command path\");return super.validateAndExecute()}};Ge();Dt();Yt();var ar=class extends nt{constructor(e,r){let s=J.relative(e,r),a=J.join(e,Ut.fileName);super(`This command can only be run from within a workspace of your project (${s} isn't a workspace of ${a}).`)}};Ge();Dt();eA();wc();pv();Yt();var hat=ut(Ai());Ul();var wde=()=>new Map([[\"@yarnpkg/cli\",Gv],[\"@yarnpkg/core\",jv],[\"@yarnpkg/fslib\",_2],[\"@yarnpkg/libzip\",fv],[\"@yarnpkg/parsers\",J2],[\"@yarnpkg/shell\",mv],[\"clipanion\",oB],[\"semver\",hat],[\"typanion\",Ea]]);Ge();async function eC(t,e){let{project:r,workspace:s}=await Rt.find(t,e);if(!s)throw new ar(r.cwd,e);return s}Ge();Dt();eA();wc();pv();Yt();var fbt=ut(Ai());Ul();var f5={};Vt(f5,{AddCommand:()=>sC,BinCommand:()=>oC,CacheCleanCommand:()=>aC,ClipanionCommand:()=>pC,ConfigCommand:()=>fC,ConfigGetCommand:()=>lC,ConfigSetCommand:()=>cC,ConfigUnsetCommand:()=>uC,DedupeCommand:()=>AC,EntryCommand:()=>gC,ExecCommand:()=>mC,ExplainCommand:()=>IC,ExplainPeerRequirementsCommand:()=>yC,HelpCommand:()=>hC,InfoCommand:()=>CC,LinkCommand:()=>BC,NodeCommand:()=>vC,PluginCheckCommand:()=>SC,PluginImportCommand:()=>bC,PluginImportSourcesCommand:()=>xC,PluginListCommand:()=>DC,PluginRemoveCommand:()=>kC,PluginRuntimeCommand:()=>QC,RebuildCommand:()=>RC,RemoveCommand:()=>TC,RunCommand:()=>NC,RunIndexCommand:()=>FC,SetResolutionCommand:()=>OC,SetVersionCommand:()=>EC,SetVersionSourcesCommand:()=>PC,UnlinkCommand:()=>LC,UpCommand:()=>MC,VersionCommand:()=>dC,WhyCommand:()=>UC,WorkspaceCommand:()=>qC,WorkspacesListCommand:()=>GC,YarnCommand:()=>wC,dedupeUtils:()=>tF,default:()=>bct,suggestUtils:()=>Zu});var Yye=ut(Fd());Ge();Ge();Ge();Yt();var uye=ut(Vv());Ul();var Zu={};Vt(Zu,{Modifier:()=>jq,Strategy:()=>$T,Target:()=>Jv,WorkspaceModifier:()=>sye,applyModifier:()=>Flt,extractDescriptorFromPath:()=>Gq,extractRangeModifier:()=>oye,fetchDescriptorFrom:()=>qq,findProjectDescriptors:()=>cye,getModifier:()=>Kv,getSuggestedDescriptors:()=>zv,makeWorkspaceDescriptor:()=>lye,toWorkspaceModifier:()=>aye});Ge();Ge();Dt();var Hq=ut(Ai()),Rlt=\"workspace:\",Jv=(s=>(s.REGULAR=\"dependencies\",s.DEVELOPMENT=\"devDependencies\",s.PEER=\"peerDependencies\",s))(Jv||{}),jq=(s=>(s.CARET=\"^\",s.TILDE=\"~\",s.EXACT=\"\",s))(jq||{}),sye=(s=>(s.CARET=\"^\",s.TILDE=\"~\",s.EXACT=\"*\",s))(sye||{}),$T=(n=>(n.KEEP=\"keep\",n.REUSE=\"reuse\",n.PROJECT=\"project\",n.LATEST=\"latest\",n.CACHE=\"cache\",n))($T||{});function Kv(t,e){return t.exact?\"\":t.caret?\"^\":t.tilde?\"~\":e.configuration.get(\"defaultSemverRangePrefix\")}var Tlt=/^([\\^~]?)[0-9]+(?:\\.[0-9]+){0,2}(?:-\\S+)?$/;function oye(t,{project:e}){let r=t.match(Tlt);return r?r[1]:e.configuration.get(\"defaultSemverRangePrefix\")}function Flt(t,e){let{protocol:r,source:s,params:a,selector:n}=G.parseRange(t.range);return Hq.default.valid(n)&&(n=`${e}${t.range}`),G.makeDescriptor(t,G.makeRange({protocol:r,source:s,params:a,selector:n}))}function aye(t){switch(t){case\"^\":return\"^\";case\"~\":return\"~\";case\"\":return\"*\";default:throw new Error(`Assertion failed: Unknown modifier: \"${t}\"`)}}function lye(t,e){return G.makeDescriptor(t.anchoredDescriptor,`${Rlt}${aye(e)}`)}async function cye(t,{project:e,target:r}){let s=new Map,a=n=>{let c=s.get(n.descriptorHash);return c||s.set(n.descriptorHash,c={descriptor:n,locators:[]}),c};for(let n of e.workspaces)if(r===\"peerDependencies\"){let c=n.manifest.peerDependencies.get(t.identHash);c!==void 0&&a(c).locators.push(n.anchoredLocator)}else{let c=n.manifest.dependencies.get(t.identHash),f=n.manifest.devDependencies.get(t.identHash);r===\"devDependencies\"?f!==void 0?a(f).locators.push(n.anchoredLocator):c!==void 0&&a(c).locators.push(n.anchoredLocator):c!==void 0?a(c).locators.push(n.anchoredLocator):f!==void 0&&a(f).locators.push(n.anchoredLocator)}return s}async function Gq(t,{cwd:e,workspace:r}){return await Olt(async s=>{J.isAbsolute(t)||(t=J.relative(r.cwd,J.resolve(e,t)),t.match(/^\\.{0,2}\\//)||(t=`./${t}`));let{project:a}=r,n=await qq(G.makeIdent(null,\"archive\"),t,{project:r.project,cache:s,workspace:r});if(!n)throw new Error(\"Assertion failed: The descriptor should have been found\");let c=new ki,f=a.configuration.makeResolver(),p=a.configuration.makeFetcher(),h={checksums:a.storedChecksums,project:a,cache:s,fetcher:p,report:c,resolver:f},E=f.bindDescriptor(n,r.anchoredLocator,h),C=G.convertDescriptorToLocator(E),S=await p.fetch(C,h),b=await Ut.find(S.prefixPath,{baseFs:S.packageFs});if(!b.name)throw new Error(\"Target path doesn't have a name\");return G.makeDescriptor(b.name,t)})}function Nlt(t){if(t.range===\"unknown\")return{type:\"resolve\",range:\"latest\"};if(Fr.validRange(t.range))return{type:\"fixed\",range:t.range};if(Mp.test(t.range))return{type:\"resolve\",range:t.range};let e=t.range.match(/^(?:jsr:|npm:)(.*)/);if(!e)return{type:\"fixed\",range:t.range};let[,r]=e,s=`${G.stringifyIdent(t)}@`;return r.startsWith(s)&&(r=r.slice(s.length)),Fr.validRange(r)?{type:\"fixed\",range:t.range}:Mp.test(r)?{type:\"resolve\",range:t.range}:{type:\"fixed\",range:t.range}}async function zv(t,{project:e,workspace:r,cache:s,target:a,fixed:n,modifier:c,strategies:f,maxResults:p=1/0}){if(!(p>=0))throw new Error(`Invalid maxResults (${p})`);let h=!n||t.range===\"unknown\"?Nlt(t):{type:\"fixed\",range:t.range};if(h.type===\"fixed\")return{suggestions:[{descriptor:t,name:`Use ${G.prettyDescriptor(e.configuration,t)}`,reason:\"(unambiguous explicit request)\"}],rejections:[]};let E=typeof r<\"u\"&&r!==null&&r.manifest[a].get(t.identHash)||null,C=[],S=[],b=async I=>{try{await I()}catch(T){S.push(T)}};for(let I of f){if(C.length>=p)break;switch(I){case\"keep\":await b(async()=>{E&&C.push({descriptor:E,name:`Keep ${G.prettyDescriptor(e.configuration,E)}`,reason:\"(no changes)\"})});break;case\"reuse\":await b(async()=>{for(let{descriptor:T,locators:N}of(await cye(t,{project:e,target:a})).values()){if(N.length===1&&N[0].locatorHash===r.anchoredLocator.locatorHash&&f.includes(\"keep\"))continue;let U=`(originally used by ${G.prettyLocator(e.configuration,N[0])}`;U+=N.length>1?` and ${N.length-1} other${N.length>2?\"s\":\"\"})`:\")\",C.push({descriptor:T,name:`Reuse ${G.prettyDescriptor(e.configuration,T)}`,reason:U})}});break;case\"cache\":await b(async()=>{for(let T of e.storedDescriptors.values())T.identHash===t.identHash&&C.push({descriptor:T,name:`Reuse ${G.prettyDescriptor(e.configuration,T)}`,reason:\"(already used somewhere in the lockfile)\"})});break;case\"project\":await b(async()=>{if(r.manifest.name!==null&&t.identHash===r.manifest.name.identHash)return;let T=e.tryWorkspaceByIdent(t);if(T===null)return;let N=lye(T,c);C.push({descriptor:N,name:`Attach ${G.prettyDescriptor(e.configuration,N)}`,reason:`(local workspace at ${he.pretty(e.configuration,T.relativeCwd,he.Type.PATH)})`})});break;case\"latest\":{let T=e.configuration.get(\"enableNetwork\"),N=e.configuration.get(\"enableOfflineMode\");await b(async()=>{if(a===\"peerDependencies\")C.push({descriptor:G.makeDescriptor(t,\"*\"),name:\"Use *\",reason:\"(catch-all peer dependency pattern)\"});else if(!T&&!N)C.push({descriptor:null,name:\"Resolve from latest\",reason:he.pretty(e.configuration,\"(unavailable because enableNetwork is toggled off)\",\"grey\")});else{let U=await qq(t,h.range,{project:e,cache:s,workspace:r,modifier:c});U&&C.push({descriptor:U,name:`Use ${G.prettyDescriptor(e.configuration,U)}`,reason:`(resolved from ${N?\"the cache\":\"latest\"})`})}})}break}}return{suggestions:C.slice(0,p),rejections:S.slice(0,p)}}async function qq(t,e,{project:r,cache:s,workspace:a,preserveModifier:n=!0,modifier:c}){let f=r.configuration.normalizeDependency(G.makeDescriptor(t,e)),p=new ki,h=r.configuration.makeFetcher(),E=r.configuration.makeResolver(),C={project:r,fetcher:h,cache:s,checksums:r.storedChecksums,report:p,cacheOptions:{skipIntegrityCheck:!0}},S={...C,resolver:E,fetchOptions:C},b=E.bindDescriptor(f,a.anchoredLocator,S),I=await E.getCandidates(b,{},S);if(I.length===0)return null;let T=I[0],{protocol:N,source:U,params:W,selector:ee}=G.parseRange(G.convertToManifestRange(T.reference));if(N===r.configuration.get(\"defaultProtocol\")&&(N=null),Hq.default.valid(ee)){let ie=ee;if(typeof c<\"u\")ee=c+ee;else if(n!==!1){let me=typeof n==\"string\"?n:f.range;ee=oye(me,{project:r})+ee}let ue=G.makeDescriptor(T,G.makeRange({protocol:N,source:U,params:W,selector:ee}));(await E.getCandidates(r.configuration.normalizeDependency(ue),{},S)).length!==1&&(ee=ie)}return G.makeDescriptor(T,G.makeRange({protocol:N,source:U,params:W,selector:ee}))}async function Olt(t){return await ce.mktempPromise(async e=>{let r=ze.create(e);return r.useWithSource(e,{enableMirror:!1,compressionLevel:0},e,{overwrite:!0}),await t(new Kr(e,{configuration:r,check:!1,immutable:!1}))})}var sC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.fixed=ge.Boolean(\"-F,--fixed\",!1,{description:\"Store dependency tags as-is instead of resolving them\"});this.exact=ge.Boolean(\"-E,--exact\",!1,{description:\"Don't use any semver modifier on the resolved range\"});this.tilde=ge.Boolean(\"-T,--tilde\",!1,{description:\"Use the `~` semver modifier on the resolved range\"});this.caret=ge.Boolean(\"-C,--caret\",!1,{description:\"Use the `^` semver modifier on the resolved range\"});this.dev=ge.Boolean(\"-D,--dev\",!1,{description:\"Add a package as a dev dependency\"});this.peer=ge.Boolean(\"-P,--peer\",!1,{description:\"Add a package as a peer dependency\"});this.optional=ge.Boolean(\"-O,--optional\",!1,{description:\"Add / upgrade a package to an optional regular / peer dependency\"});this.preferDev=ge.Boolean(\"--prefer-dev\",!1,{description:\"Add / upgrade a package to a dev dependency\"});this.interactive=ge.Boolean(\"-i,--interactive\",{description:\"Reuse the specified package from other workspaces in the project\"});this.cached=ge.Boolean(\"--cached\",!1,{description:\"Reuse the highest version already used somewhere within the project\"});this.mode=ge.String(\"--mode\",{description:\"Change what artifacts installs generate\",validator:fo($l)});this.silent=ge.Boolean(\"--silent\",{hidden:!0});this.packages=ge.Rest()}static{this.paths=[[\"add\"]]}static{this.usage=ot.Usage({description:\"add dependencies to the project\",details:\"\\n      This command adds a package to the package.json for the nearest workspace.\\n\\n      - If it didn't exist before, the package will by default be added to the regular `dependencies` field, but this behavior can be overriden thanks to the `-D,--dev` flag (which will cause the dependency to be added to the `devDependencies` field instead) and the `-P,--peer` flag (which will do the same but for `peerDependencies`).\\n\\n      - If the package was already listed in your dependencies, it will by default be upgraded whether it's part of your `dependencies` or `devDependencies` (it won't ever update `peerDependencies`, though).\\n\\n      - If set, the `--prefer-dev` flag will operate as a more flexible `-D,--dev` in that it will add the package to your `devDependencies` if it isn't already listed in either `dependencies` or `devDependencies`, but it will also happily upgrade your `dependencies` if that's what you already use (whereas `-D,--dev` would throw an exception).\\n\\n      - If set, the `-O,--optional` flag will add the package to the `optionalDependencies` field and, in combination with the `-P,--peer` flag, it will add the package as an optional peer dependency. If the package was already listed in your `dependencies`, it will be upgraded to `optionalDependencies`. If the package was already listed in your `peerDependencies`, in combination with the `-P,--peer` flag, it will be upgraded to an optional peer dependency: `\\\"peerDependenciesMeta\\\": { \\\"<package>\\\": { \\\"optional\\\": true } }`\\n\\n      - If the added package doesn't specify a range at all its `latest` tag will be resolved and the returned version will be used to generate a new semver range (using the `^` modifier by default unless otherwise configured via the `defaultSemverRangePrefix` configuration, or the `~` modifier if `-T,--tilde` is specified, or no modifier at all if `-E,--exact` is specified). Two exceptions to this rule: the first one is that if the package is a workspace then its local version will be used, and the second one is that if you use `-P,--peer` the default range will be `*` and won't be resolved at all.\\n\\n      - If the added package specifies a range (such as `^1.0.0`, `latest`, or `rc`), Yarn will add this range as-is in the resulting package.json entry (in particular, tags such as `rc` will be encoded as-is rather than being converted into a semver range).\\n\\n      If the `--cached` option is used, Yarn will preferably reuse the highest version already used somewhere within the project, even if through a transitive dependency.\\n\\n      If the `-i,--interactive` option is used (or if the `preferInteractive` settings is toggled on) the command will first try to check whether other workspaces in the project use the specified package and, if so, will offer to reuse them.\\n\\n      If the `--mode=<mode>` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\\n\\n      - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\\n\\n      - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\\n\\n      For a compilation of all the supported protocols, please consult the dedicated page from our website: https://yarnpkg.com/protocols.\\n    \",examples:[[\"Add a regular package to the current workspace\",\"$0 add lodash\"],[\"Add a specific version for a package to the current workspace\",\"$0 add lodash@1.2.3\"],[\"Add a package from a GitHub repository (the master branch) to the current workspace using a URL\",\"$0 add lodash@https://github.com/lodash/lodash\"],[\"Add a package from a GitHub repository (the master branch) to the current workspace using the GitHub protocol\",\"$0 add lodash@github:lodash/lodash\"],[\"Add a package from a GitHub repository (the master branch) to the current workspace using the GitHub protocol (shorthand)\",\"$0 add lodash@lodash/lodash\"],[\"Add a package from a specific branch of a GitHub repository to the current workspace using the GitHub protocol (shorthand)\",\"$0 add lodash-es@lodash/lodash#es\"],[\"Add a local package (gzipped tarball format) to the current workspace\",\"$0 add local-package-name@file:../path/to/local-package-name-v0.1.2.tgz\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState({restoreResolutions:!1});let c=this.fixed,f=r.isInteractive({interactive:this.interactive,stdout:this.context.stdout}),p=f||r.get(\"preferReuse\"),h=Kv(this,s),E=[p?\"reuse\":void 0,\"project\",this.cached?\"cache\":void 0,\"latest\"].filter(W=>typeof W<\"u\"),C=f?1/0:1,S=W=>{let ee=G.tryParseDescriptor(W.slice(4));return ee?ee.range===\"unknown\"?G.makeDescriptor(ee,`jsr:${G.stringifyIdent(ee)}@latest`):G.makeDescriptor(ee,`jsr:${ee.range}`):null},b=await Promise.all(this.packages.map(async W=>{let ee=W.match(/^\\.{0,2}\\//)?await Gq(W,{cwd:this.context.cwd,workspace:a}):W.startsWith(\"jsr:\")?S(W):G.tryParseDescriptor(W),ie=W.match(/^(https?:|git@github)/);if(ie)throw new nt(`It seems you are trying to add a package using a ${he.pretty(r,`${ie[0]}...`,he.Type.RANGE)} url; we now require package names to be explicitly specified.\nTry running the command again with the package name prefixed: ${he.pretty(r,\"yarn add\",he.Type.CODE)} ${he.pretty(r,G.makeDescriptor(G.makeIdent(null,\"my-package\"),`${ie[0]}...`),he.Type.DESCRIPTOR)}`);if(!ee)throw new nt(`The ${he.pretty(r,W,he.Type.CODE)} string didn't match the required format (package-name@range). Did you perhaps forget to explicitly reference the package name?`);let ue=Llt(a,ee,{dev:this.dev,peer:this.peer,preferDev:this.preferDev,optional:this.optional});return await Promise.all(ue.map(async me=>{let pe=await zv(ee,{project:s,workspace:a,cache:n,fixed:c,target:me,modifier:h,strategies:E,maxResults:C});return{request:ee,suggestedDescriptors:pe,target:me}}))})).then(W=>W.flat()),I=await lA.start({configuration:r,stdout:this.context.stdout,suggestInstall:!1},async W=>{for(let{request:ee,suggestedDescriptors:{suggestions:ie,rejections:ue}}of b)if(ie.filter(me=>me.descriptor!==null).length===0){let[me]=ue;if(typeof me>\"u\")throw new Error(\"Assertion failed: Expected an error to have been set\");s.configuration.get(\"enableNetwork\")?W.reportError(27,`${G.prettyDescriptor(r,ee)} can't be resolved to a satisfying range`):W.reportError(27,`${G.prettyDescriptor(r,ee)} can't be resolved to a satisfying range (note: network resolution has been disabled)`),W.reportSeparator(),W.reportExceptionOnce(me)}});if(I.hasErrors())return I.exitCode();let T=!1,N=[],U=[];for(let{suggestedDescriptors:{suggestions:W},target:ee}of b){let ie,ue=W.filter(Be=>Be.descriptor!==null),le=ue[0].descriptor,me=ue.every(Be=>G.areDescriptorsEqual(Be.descriptor,le));ue.length===1||me?ie=le:(T=!0,{answer:ie}=await(0,uye.prompt)({type:\"select\",name:\"answer\",message:\"Which range do you want to use?\",choices:W.map(({descriptor:Be,name:Ce,reason:g})=>Be?{name:Ce,hint:g,descriptor:Be}:{name:Ce,hint:g,disabled:!0}),onCancel:()=>process.exit(130),result(Be){return this.find(Be,\"descriptor\")},stdin:this.context.stdin,stdout:this.context.stdout}));let pe=a.manifest[ee].get(ie.identHash);(typeof pe>\"u\"||pe.descriptorHash!==ie.descriptorHash)&&(a.manifest[ee].set(ie.identHash,ie),this.optional&&(ee===\"dependencies\"?a.manifest.ensureDependencyMeta({...ie,range:\"unknown\"}).optional=!0:ee===\"peerDependencies\"&&(a.manifest.ensurePeerDependencyMeta({...ie,range:\"unknown\"}).optional=!0)),typeof pe>\"u\"?N.push([a,ee,ie,E]):U.push([a,ee,pe,ie]))}return await r.triggerMultipleHooks(W=>W.afterWorkspaceDependencyAddition,N),await r.triggerMultipleHooks(W=>W.afterWorkspaceDependencyReplacement,U),T&&this.context.stdout.write(`\n`),await s.installWithNewReport({json:this.json,stdout:this.context.stdout,quiet:this.context.quiet},{cache:n,mode:this.mode})}};function Llt(t,e,{dev:r,peer:s,preferDev:a,optional:n}){let c=t.manifest.dependencies.has(e.identHash),f=t.manifest.devDependencies.has(e.identHash),p=t.manifest.peerDependencies.has(e.identHash);if((r||s)&&c)throw new nt(`Package \"${G.prettyIdent(t.project.configuration,e)}\" is already listed as a regular dependency - remove the -D,-P flags or remove it from your dependencies first`);if(!r&&!s&&p)throw new nt(`Package \"${G.prettyIdent(t.project.configuration,e)}\" is already listed as a peer dependency - use either of -D or -P, or remove it from your peer dependencies first`);if(n&&f)throw new nt(`Package \"${G.prettyIdent(t.project.configuration,e)}\" is already listed as a dev dependency - remove the -O flag or remove it from your dev dependencies first`);if(n&&!s&&p)throw new nt(`Package \"${G.prettyIdent(t.project.configuration,e)}\" is already listed as a peer dependency - remove the -O flag or add the -P flag or remove it from your peer dependencies first`);if((r||a)&&n)throw new nt(`Package \"${G.prettyIdent(t.project.configuration,e)}\" cannot simultaneously be a dev dependency and an optional dependency`);let h=[];return s&&h.push(\"peerDependencies\"),(r||a)&&h.push(\"devDependencies\"),n&&h.push(\"dependencies\"),h.length>0?h:f?[\"devDependencies\"]:p?[\"peerDependencies\"]:[\"dependencies\"]}Ge();Ge();Yt();var oC=class extends ft{constructor(){super(...arguments);this.verbose=ge.Boolean(\"-v,--verbose\",!1,{description:\"Print both the binary name and the locator of the package that provides the binary\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.name=ge.String({required:!1})}static{this.paths=[[\"bin\"]]}static{this.usage=ot.Usage({description:\"get the path to a binary script\",details:`\n      When used without arguments, this command will print the list of all the binaries available in the current workspace. Adding the \\`-v,--verbose\\` flag will cause the output to contain both the binary name and the locator of the package that provides the binary.\n\n      When an argument is specified, this command will just print the path to the binary on the standard output and exit. Note that the reported path may be stored within a zip archive.\n    `,examples:[[\"List all the available binaries\",\"$0 bin\"],[\"Print the path to a specific binary\",\"$0 bin eslint\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,locator:a}=await Rt.find(r,this.context.cwd);if(await s.restoreInstallState(),this.name){let f=(await In.getPackageAccessibleBinaries(a,{project:s})).get(this.name);if(!f)throw new nt(`Couldn't find a binary named \"${this.name}\" for package \"${G.prettyLocator(r,a)}\"`);let[,p]=f;return this.context.stdout.write(`${p}\n`),0}return(await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout},async c=>{let f=await In.getPackageAccessibleBinaries(a,{project:s}),h=Array.from(f.keys()).reduce((E,C)=>Math.max(E,C.length),0);for(let[E,[C,S]]of f)c.reportJson({name:E,source:G.stringifyIdent(C),path:S});if(this.verbose)for(let[E,[C]]of f)c.reportInfo(null,`${E.padEnd(h,\" \")}   ${G.prettyLocator(r,C)}`);else for(let E of f.keys())c.reportInfo(null,E)})).exitCode()}};Ge();Dt();Yt();var aC=class extends ft{constructor(){super(...arguments);this.mirror=ge.Boolean(\"--mirror\",!1,{description:\"Remove the global cache files instead of the local cache files\"});this.all=ge.Boolean(\"--all\",!1,{description:\"Remove both the global cache files and the local cache files of the current project\"})}static{this.paths=[[\"cache\",\"clean\"],[\"cache\",\"clear\"]]}static{this.usage=ot.Usage({description:\"remove the shared cache files\",details:`\n      This command will remove all the files from the cache.\n    `,examples:[[\"Remove all the local archives\",\"$0 cache clean\"],[\"Remove all the archives stored in the ~/.yarn directory\",\"$0 cache clean --mirror\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins);if(!r.get(\"enableCacheClean\"))throw new nt(\"Cache cleaning is currently disabled. To enable it, set `enableCacheClean: true` in your configuration file. Note: Cache cleaning is typically not required and should be avoided when using Zero-Installs.\");let s=await Kr.find(r);return(await Ot.start({configuration:r,stdout:this.context.stdout},async()=>{let n=(this.all||this.mirror)&&s.mirrorCwd!==null,c=!this.mirror;n&&(await ce.removePromise(s.mirrorCwd),await r.triggerHook(f=>f.cleanGlobalArtifacts,r)),c&&await ce.removePromise(s.cwd)})).exitCode()}};Ge();Yt();ql();var Wq=Ie(\"util\"),lC=class extends ft{constructor(){super(...arguments);this.why=ge.Boolean(\"--why\",!1,{description:\"Print the explanation for why a setting has its value\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.unsafe=ge.Boolean(\"--no-redacted\",!1,{description:\"Don't redact secrets (such as tokens) from the output\"});this.name=ge.String()}static{this.paths=[[\"config\",\"get\"]]}static{this.usage=ot.Usage({description:\"read a configuration settings\",details:`\n      This command will print a configuration setting.\n\n      Secrets (such as tokens) will be redacted from the output by default. If this behavior isn't desired, set the \\`--no-redacted\\` to get the untransformed value.\n    `,examples:[[\"Print a simple configuration setting\",\"yarn config get yarnPath\"],[\"Print a complex configuration setting\",\"yarn config get packageExtensions\"],[\"Print a nested field from the configuration\",`yarn config get 'npmScopes[\"my-company\"].npmRegistryServer'`],[\"Print a token from the configuration\",\"yarn config get npmAuthToken --no-redacted\"],[\"Print a configuration setting as JSON\",\"yarn config get packageExtensions --json\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=this.name.replace(/[.[].*$/,\"\"),a=this.name.replace(/^[^.[]*/,\"\");if(typeof r.settings.get(s)>\"u\")throw new nt(`Couldn't find a configuration settings named \"${s}\"`);let c=r.getSpecial(s,{hideSecrets:!this.unsafe,getNativePaths:!0}),f=je.convertMapsToIndexableObjects(c),p=a?va(f,a):f,h=await Ot.start({configuration:r,includeFooter:!1,json:this.json,stdout:this.context.stdout},async E=>{E.reportJson(p)});if(!this.json){if(typeof p==\"string\")return this.context.stdout.write(`${p}\n`),h.exitCode();Wq.inspect.styles.name=\"cyan\",this.context.stdout.write(`${(0,Wq.inspect)(p,{depth:1/0,colors:r.get(\"enableColors\"),compact:!1})}\n`)}return h.exitCode()}};Ge();Yt();ql();var Yq=Ie(\"util\"),cC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Set complex configuration settings to JSON values\"});this.home=ge.Boolean(\"-H,--home\",!1,{description:\"Update the home configuration instead of the project configuration\"});this.name=ge.String();this.value=ge.String()}static{this.paths=[[\"config\",\"set\"]]}static{this.usage=ot.Usage({description:\"change a configuration settings\",details:`\n      This command will set a configuration setting.\n\n      When used without the \\`--json\\` flag, it can only set a simple configuration setting (a string, a number, or a boolean).\n\n      When used with the \\`--json\\` flag, it can set both simple and complex configuration settings, including Arrays and Objects.\n    `,examples:[[\"Set a simple configuration setting (a string, a number, or a boolean)\",\"yarn config set initScope myScope\"],[\"Set a simple configuration setting (a string, a number, or a boolean) using the `--json` flag\",'yarn config set initScope --json \\\\\"myScope\\\\\"'],[\"Set a complex configuration setting (an Array) using the `--json` flag\",`yarn config set unsafeHttpWhitelist --json '[\"*.example.com\", \"example.com\"]'`],[\"Set a complex configuration setting (an Object) using the `--json` flag\",`yarn config set packageExtensions --json '{ \"@babel/parser@*\": { \"dependencies\": { \"@babel/types\": \"*\" } } }'`],[\"Set a nested configuration setting\",'yarn config set npmScopes.company.npmRegistryServer \"https://npm.example.com\"'],[\"Set a nested configuration setting using indexed access for non-simple keys\",`yarn config set 'npmRegistries[\"//npm.example.com\"].npmAuthToken' \"ffffffff-ffff-ffff-ffff-ffffffffffff\"`]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=()=>{if(!r.projectCwd)throw new nt(\"This command must be run from within a project folder\");return r.projectCwd},a=this.name.replace(/[.[].*$/,\"\"),n=this.name.replace(/^[^.[]*\\.?/,\"\");if(typeof r.settings.get(a)>\"u\")throw new nt(`Couldn't find a configuration settings named \"${a}\"`);if(a===\"enableStrictSettings\")throw new nt(\"This setting only affects the file it's in, and thus cannot be set from the CLI\");let f=this.json?JSON.parse(this.value):this.value;await(this.home?I=>ze.updateHomeConfiguration(I):I=>ze.updateConfiguration(s(),I))(I=>{if(n){let T=f0(I);return Jd(T,this.name,f),T}else return{...I,[a]:f}});let E=(await ze.find(this.context.cwd,this.context.plugins)).getSpecial(a,{hideSecrets:!0,getNativePaths:!0}),C=je.convertMapsToIndexableObjects(E),S=n?va(C,n):C;return(await Ot.start({configuration:r,includeFooter:!1,stdout:this.context.stdout},async I=>{Yq.inspect.styles.name=\"cyan\",I.reportInfo(0,`Successfully set ${this.name} to ${(0,Yq.inspect)(S,{depth:1/0,colors:r.get(\"enableColors\"),compact:!1})}`)})).exitCode()}};Ge();Yt();ql();var uC=class extends ft{constructor(){super(...arguments);this.home=ge.Boolean(\"-H,--home\",!1,{description:\"Update the home configuration instead of the project configuration\"});this.name=ge.String()}static{this.paths=[[\"config\",\"unset\"]]}static{this.usage=ot.Usage({description:\"unset a configuration setting\",details:`\n      This command will unset a configuration setting.\n    `,examples:[[\"Unset a simple configuration setting\",\"yarn config unset initScope\"],[\"Unset a complex configuration setting\",\"yarn config unset packageExtensions\"],[\"Unset a nested configuration setting\",\"yarn config unset npmScopes.company.npmRegistryServer\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=()=>{if(!r.projectCwd)throw new nt(\"This command must be run from within a project folder\");return r.projectCwd},a=this.name.replace(/[.[].*$/,\"\"),n=this.name.replace(/^[^.[]*\\.?/,\"\");if(typeof r.settings.get(a)>\"u\")throw new nt(`Couldn't find a configuration settings named \"${a}\"`);let f=this.home?h=>ze.updateHomeConfiguration(h):h=>ze.updateConfiguration(s(),h);return(await Ot.start({configuration:r,includeFooter:!1,stdout:this.context.stdout},async h=>{let E=!1;await f(C=>{if(!vB(C,this.name))return h.reportWarning(0,`Configuration doesn't contain setting ${this.name}; there is nothing to unset`),E=!0,C;let S=n?f0(C):{...C};return A0(S,this.name),S}),E||h.reportInfo(0,`Successfully unset ${this.name}`)})).exitCode()}};Ge();Dt();Yt();var eF=Ie(\"util\"),fC=class extends ft{constructor(){super(...arguments);this.noDefaults=ge.Boolean(\"--no-defaults\",!1,{description:\"Omit the default values from the display\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.verbose=ge.Boolean(\"-v,--verbose\",{hidden:!0});this.why=ge.Boolean(\"--why\",{hidden:!0});this.names=ge.Rest()}static{this.paths=[[\"config\"]]}static{this.usage=ot.Usage({description:\"display the current configuration\",details:`\n      This command prints the current active configuration settings.\n    `,examples:[[\"Print the active configuration settings\",\"$0 config\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins,{strict:!1}),s=await SI({configuration:r,stdout:this.context.stdout,forceError:this.json},[{option:this.verbose,message:\"The --verbose option is deprecated, the settings' descriptions are now always displayed\"},{option:this.why,message:\"The --why option is deprecated, the settings' sources are now always displayed\"}]);if(s!==null)return s;let a=this.names.length>0?[...new Set(this.names)].sort():[...r.settings.keys()].sort(),n,c=await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async f=>{if(r.invalid.size>0&&!this.json){for(let[p,h]of r.invalid)f.reportError(34,`Invalid configuration key \"${p}\" in ${h}`);f.reportSeparator()}if(this.json)for(let p of a){if(this.noDefaults&&!r.sources.has(p))continue;let h=r.settings.get(p);typeof h>\"u\"&&f.reportError(34,`No configuration key named \"${p}\"`);let E=r.getSpecial(p,{hideSecrets:!0,getNativePaths:!0}),C=r.sources.get(p)??\"<default>\",S=C&&C[0]!==\"<\"?fe.fromPortablePath(C):C;f.reportJson({key:p,effective:E,source:S,...h})}else{let p={breakLength:1/0,colors:r.get(\"enableColors\"),maxArrayLength:2},h={},E={children:h};for(let C of a){if(this.noDefaults&&!r.sources.has(C))continue;let S=r.settings.get(C),b=r.sources.get(C)??\"<default>\",I=r.getSpecial(C,{hideSecrets:!0,getNativePaths:!0}),T={Description:{label:\"Description\",value:he.tuple(he.Type.MARKDOWN,{text:S.description,format:this.cli.format(),paragraphs:!1})},Source:{label:\"Source\",value:he.tuple(b[0]===\"<\"?he.Type.CODE:he.Type.PATH,b)}};h[C]={value:he.tuple(he.Type.CODE,C),children:T};let N=(U,W)=>{for(let[ee,ie]of W)if(ie instanceof Map){let ue={};U[ee]={children:ue},N(ue,ie)}else U[ee]={label:ee,value:he.tuple(he.Type.NO_HINT,(0,eF.inspect)(ie,p))}};I instanceof Map?N(T,I):T.Value={label:\"Value\",value:he.tuple(he.Type.NO_HINT,(0,eF.inspect)(I,p))}}a.length!==1&&(n=void 0),xs.emitTree(E,{configuration:r,json:this.json,stdout:this.context.stdout,separators:2})}});if(!this.json&&typeof n<\"u\"){let f=a[0],p=(0,eF.inspect)(r.getSpecial(f,{hideSecrets:!0,getNativePaths:!0}),{colors:r.get(\"enableColors\")});this.context.stdout.write(`\n`),this.context.stdout.write(`${p}\n`)}return c.exitCode()}};Ge();Yt();Ul();var tF={};Vt(tF,{Strategy:()=>Zv,acceptedStrategies:()=>Mlt,dedupe:()=>Vq});Ge();Ge();var fye=ut(Go()),Zv=(e=>(e.HIGHEST=\"highest\",e))(Zv||{}),Mlt=new Set(Object.values(Zv)),Ult={highest:async(t,e,{resolver:r,fetcher:s,resolveOptions:a,fetchOptions:n})=>{let c=new Map;for(let[p,h]of t.storedResolutions){let E=t.storedDescriptors.get(p);if(typeof E>\"u\")throw new Error(`Assertion failed: The descriptor (${p}) should have been registered`);je.getSetWithDefault(c,E.identHash).add(h)}let f=new Map(je.mapAndFilter(t.storedDescriptors.values(),p=>G.isVirtualDescriptor(p)?je.mapAndFilter.skip:[p.descriptorHash,je.makeDeferred()]));for(let p of t.storedDescriptors.values()){let h=f.get(p.descriptorHash);if(typeof h>\"u\")throw new Error(`Assertion failed: The descriptor (${p.descriptorHash}) should have been registered`);let E=t.storedResolutions.get(p.descriptorHash);if(typeof E>\"u\")throw new Error(`Assertion failed: The resolution (${p.descriptorHash}) should have been registered`);let C=t.originalPackages.get(E);if(typeof C>\"u\")throw new Error(`Assertion failed: The package (${E}) should have been registered`);Promise.resolve().then(async()=>{let S=r.getResolutionDependencies(p,a),b=Object.fromEntries(await je.allSettledSafe(Object.entries(S).map(async([ee,ie])=>{let ue=f.get(ie.descriptorHash);if(typeof ue>\"u\")throw new Error(`Assertion failed: The descriptor (${ie.descriptorHash}) should have been registered`);let le=await ue.promise;if(!le)throw new Error(\"Assertion failed: Expected the dependency to have been through the dedupe process itself\");return[ee,le.updatedPackage]})));if(e.length&&!fye.default.isMatch(G.stringifyIdent(p),e)||!r.shouldPersistResolution(C,a))return C;let I=c.get(p.identHash);if(typeof I>\"u\")throw new Error(`Assertion failed: The resolutions (${p.identHash}) should have been registered`);if(I.size===1)return C;let T=[...I].map(ee=>{let ie=t.originalPackages.get(ee);if(typeof ie>\"u\")throw new Error(`Assertion failed: The package (${ee}) should have been registered`);return ie}),N=await r.getSatisfying(p,b,T,a),U=N.locators?.[0];if(typeof U>\"u\"||!N.sorted)return C;let W=t.originalPackages.get(U.locatorHash);if(typeof W>\"u\")throw new Error(`Assertion failed: The package (${U.locatorHash}) should have been registered`);return W}).then(async S=>{let b=await t.preparePackage(S,{resolver:r,resolveOptions:a});h.resolve({descriptor:p,currentPackage:C,updatedPackage:S,resolvedPackage:b})}).catch(S=>{h.reject(S)})}return[...f.values()].map(p=>p.promise)}};async function Vq(t,{strategy:e,patterns:r,cache:s,report:a}){let{configuration:n}=t,c=new ki,f=n.makeResolver(),p=n.makeFetcher(),h={cache:s,checksums:t.storedChecksums,fetcher:p,project:t,report:c,cacheOptions:{skipIntegrityCheck:!0}},E={project:t,resolver:f,report:c,fetchOptions:h};return await a.startTimerPromise(\"Deduplication step\",async()=>{let C=Ult[e],S=await C(t,r,{resolver:f,resolveOptions:E,fetcher:p,fetchOptions:h}),b=Ao.progressViaCounter(S.length);await a.reportProgress(b);let I=0;await Promise.all(S.map(U=>U.then(W=>{if(W===null||W.currentPackage.locatorHash===W.updatedPackage.locatorHash)return;I++;let{descriptor:ee,currentPackage:ie,updatedPackage:ue}=W;a.reportInfo(0,`${G.prettyDescriptor(n,ee)} can be deduped from ${G.prettyLocator(n,ie)} to ${G.prettyLocator(n,ue)}`),a.reportJson({descriptor:G.stringifyDescriptor(ee),currentResolution:G.stringifyLocator(ie),updatedResolution:G.stringifyLocator(ue)}),t.storedResolutions.set(ee.descriptorHash,ue.locatorHash)}).finally(()=>b.tick())));let T;switch(I){case 0:T=\"No packages\";break;case 1:T=\"One package\";break;default:T=`${I} packages`}let N=he.pretty(n,e,he.Type.CODE);return a.reportInfo(0,`${T} can be deduped using the ${N} strategy`),I})}var AC=class extends ft{constructor(){super(...arguments);this.strategy=ge.String(\"-s,--strategy\",\"highest\",{description:\"The strategy to use when deduping dependencies\",validator:fo(Zv)});this.check=ge.Boolean(\"-c,--check\",!1,{description:\"Exit with exit code 1 when duplicates are found, without persisting the dependency tree\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.mode=ge.String(\"--mode\",{description:\"Change what artifacts installs generate\",validator:fo($l)});this.patterns=ge.Rest()}static{this.paths=[[\"dedupe\"]]}static{this.usage=ot.Usage({description:\"deduplicate dependencies with overlapping ranges\",details:\"\\n      Duplicates are defined as descriptors with overlapping ranges being resolved and locked to different locators. They are a natural consequence of Yarn's deterministic installs, but they can sometimes pile up and unnecessarily increase the size of your project.\\n\\n      This command dedupes dependencies in the current project using different strategies (only one is implemented at the moment):\\n\\n      - `highest`: Reuses (where possible) the locators with the highest versions. This means that dependencies can only be upgraded, never downgraded. It's also guaranteed that it never takes more than a single pass to dedupe the entire dependency tree.\\n\\n      **Note:** Even though it never produces a wrong dependency tree, this command should be used with caution, as it modifies the dependency tree, which can sometimes cause problems when packages don't strictly follow semver recommendations. Because of this, it is recommended to also review the changes manually.\\n\\n      If set, the `-c,--check` flag will only report the found duplicates, without persisting the modified dependency tree. If changes are found, the command will exit with a non-zero exit code, making it suitable for CI purposes.\\n\\n      If the `--mode=<mode>` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\\n\\n      - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\\n\\n      - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\\n\\n      This command accepts glob patterns as arguments (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\\n\\n      ### In-depth explanation:\\n\\n      Yarn doesn't deduplicate dependencies by default, otherwise installs wouldn't be deterministic and the lockfile would be useless. What it actually does is that it tries to not duplicate dependencies in the first place.\\n\\n      **Example:** If `foo@^2.3.4` (a dependency of a dependency) has already been resolved to `foo@2.3.4`, running `yarn add foo@*`will cause Yarn to reuse `foo@2.3.4`, even if the latest `foo` is actually `foo@2.10.14`, thus preventing unnecessary duplication.\\n\\n      Duplication happens when Yarn can't unlock dependencies that have already been locked inside the lockfile.\\n\\n      **Example:** If `foo@^2.3.4` (a dependency of a dependency) has already been resolved to `foo@2.3.4`, running `yarn add foo@2.10.14` will cause Yarn to install `foo@2.10.14` because the existing resolution doesn't satisfy the range `2.10.14`. This behavior can lead to (sometimes) unwanted duplication, since now the lockfile contains 2 separate resolutions for the 2 `foo` descriptors, even though they have overlapping ranges, which means that the lockfile can be simplified so that both descriptors resolve to `foo@2.10.14`.\\n    \",examples:[[\"Dedupe all packages\",\"$0 dedupe\"],[\"Dedupe all packages using a specific strategy\",\"$0 dedupe --strategy highest\"],[\"Dedupe a specific package\",\"$0 dedupe lodash\"],[\"Dedupe all packages with the `@babel/*` scope\",\"$0 dedupe '@babel/*'\"],[\"Check for duplicates (can be used as a CI step)\",\"$0 dedupe --check\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Rt.find(r,this.context.cwd),a=await Kr.find(r);await s.restoreInstallState({restoreResolutions:!1});let n=0,c=await Ot.start({configuration:r,includeFooter:!1,stdout:this.context.stdout,json:this.json},async f=>{n=await Vq(s,{strategy:this.strategy,patterns:this.patterns,cache:a,report:f})});return c.hasErrors()?c.exitCode():this.check?n?1:0:await s.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:a,mode:this.mode})}};Ge();Yt();var pC=class extends ft{static{this.paths=[[\"--clipanion=definitions\"]]}async execute(){let{plugins:e}=await ze.find(this.context.cwd,this.context.plugins),r=[];for(let c of e){let{commands:f}=c[1];if(f){let h=Ca.from(f).definitions();r.push([c[0],h])}}let s=this.cli.definitions(),a=(c,f)=>c.split(\" \").slice(1).join()===f.split(\" \").slice(1).join(),n=Aye()[\"@yarnpkg/builder\"].bundles.standard;for(let c of r){let f=c[1];for(let p of f)s.find(h=>a(h.path,p.path)).plugin={name:c[0],isDefault:n.includes(c[0])}}this.context.stdout.write(`${JSON.stringify(s,null,2)}\n`)}};var hC=class extends ft{static{this.paths=[[\"help\"],[\"--help\"],[\"-h\"]]}async execute(){this.context.stdout.write(this.cli.usage(null))}};Ge();Dt();Yt();var gC=class extends ft{constructor(){super(...arguments);this.leadingArgument=ge.String();this.args=ge.Proxy()}async execute(){if(this.leadingArgument.match(/[\\\\/]/)&&!G.tryParseIdent(this.leadingArgument)){let r=J.resolve(this.context.cwd,fe.toPortablePath(this.leadingArgument));return await this.cli.run(this.args,{cwd:r})}else return await this.cli.run([\"run\",this.leadingArgument,...this.args])}};Ge();var dC=class extends ft{static{this.paths=[[\"-v\"],[\"--version\"]]}async execute(){this.context.stdout.write(`${fn||\"<unknown>\"}\n`)}};Ge();Ge();Yt();var mC=class extends ft{constructor(){super(...arguments);this.commandName=ge.String();this.args=ge.Proxy()}static{this.paths=[[\"exec\"]]}static{this.usage=ot.Usage({description:\"execute a shell script\",details:`\n      This command simply executes a shell script within the context of the root directory of the active workspace using the portable shell.\n\n      It also makes sure to call it in a way that's compatible with the current project (for example, on PnP projects the environment will be setup in such a way that PnP will be correctly injected into the environment).\n    `,examples:[[\"Execute a single shell command\",\"$0 exec echo Hello World\"],[\"Execute a shell script\",'$0 exec \"tsc & babel src --out-dir lib\"']]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,locator:a}=await Rt.find(r,this.context.cwd);return await s.restoreInstallState(),await In.executePackageShellcode(a,this.commandName,this.args,{cwd:this.context.cwd,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr,project:s})}};Ge();Yt();Ul();var yC=class extends ft{constructor(){super(...arguments);this.hash=ge.String({required:!1,validator:Nx(wE(),[X2(/^p[0-9a-f]{6}$/)])})}static{this.paths=[[\"explain\",\"peer-requirements\"]]}static{this.usage=ot.Usage({description:\"explain a set of peer requirements\",details:`\n      A peer requirement represents all peer requests that a subject must satisfy when providing a requested package to requesters.\n\n      When the hash argument is specified, this command prints a detailed explanation of the peer requirement corresponding to the hash and whether it is satisfied or not.\n\n      When used without arguments, this command lists all peer requirements and the corresponding hash that can be used to get detailed information about a given requirement.\n\n      **Note:** A hash is a seven-letter code consisting of the letter 'p' followed by six characters that can be obtained from peer dependency warnings or from the list of all peer requirements(\\`yarn explain peer-requirements\\`).\n    `,examples:[[\"Explain the corresponding peer requirement for a hash\",\"$0 explain peer-requirements p1a4ed\"],[\"List all peer requirements\",\"$0 explain peer-requirements\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Rt.find(r,this.context.cwd);return await s.restoreInstallState({restoreResolutions:!1}),await s.applyLightResolution(),typeof this.hash<\"u\"?await Hlt(this.hash,s,{stdout:this.context.stdout}):await jlt(s,{stdout:this.context.stdout})}};async function Hlt(t,e,r){let s=e.peerRequirementNodes.get(t);if(typeof s>\"u\")throw new Error(`No peerDependency requirements found for hash: \"${t}\"`);let a=new Set,n=p=>a.has(p.requester.locatorHash)?{value:he.tuple(he.Type.DEPENDENT,{locator:p.requester,descriptor:p.descriptor}),children:p.children.size>0?[{value:he.tuple(he.Type.NO_HINT,\"...\")}]:[]}:(a.add(p.requester.locatorHash),{value:he.tuple(he.Type.DEPENDENT,{locator:p.requester,descriptor:p.descriptor}),children:Object.fromEntries(Array.from(p.children.values(),h=>[G.stringifyLocator(h.requester),n(h)]))}),c=e.peerWarnings.find(p=>p.hash===t);return(await Ot.start({configuration:e.configuration,stdout:r.stdout,includeFooter:!1,includePrefix:!1},async p=>{let h=he.mark(e.configuration),E=c?h.Cross:h.Check;if(p.reportInfo(0,`Package ${he.pretty(e.configuration,s.subject,he.Type.LOCATOR)} is requested to provide ${he.pretty(e.configuration,s.ident,he.Type.IDENT)} by its descendants`),p.reportSeparator(),p.reportInfo(0,he.pretty(e.configuration,s.subject,he.Type.LOCATOR)),xs.emitTree({children:Object.fromEntries(Array.from(s.requests.values(),C=>[G.stringifyLocator(C.requester),n(C)]))},{configuration:e.configuration,stdout:r.stdout,json:!1}),p.reportSeparator(),s.provided.range===\"missing:\"){let C=c?\"\":\" , but all peer requests are optional\";p.reportInfo(0,`${E} Package ${he.pretty(e.configuration,s.subject,he.Type.LOCATOR)} does not provide ${he.pretty(e.configuration,s.ident,he.Type.IDENT)}${C}.`)}else{let C=e.storedResolutions.get(s.provided.descriptorHash);if(!C)throw new Error(\"Assertion failed: Expected the descriptor to be registered\");let S=e.storedPackages.get(C);if(!S)throw new Error(\"Assertion failed: Expected the package to be registered\");p.reportInfo(0,`${E} Package ${he.pretty(e.configuration,s.subject,he.Type.LOCATOR)} provides ${he.pretty(e.configuration,s.ident,he.Type.IDENT)} with version ${G.prettyReference(e.configuration,S.version??\"0.0.0\")}, ${c?\"which does not satisfy all requests.\":\"which satisfies all requests\"}`),c?.type===3&&(c.range?p.reportInfo(0,`  The combined requested range is ${he.pretty(e.configuration,c.range,he.Type.RANGE)}`):p.reportInfo(0,\"  Unfortunately, the requested ranges have no overlap\"))}})).exitCode()}async function jlt(t,e){return(await Ot.start({configuration:t.configuration,stdout:e.stdout,includeFooter:!1,includePrefix:!1},async s=>{let a=he.mark(t.configuration),n=je.sortMap(t.peerRequirementNodes,[([,c])=>G.stringifyLocator(c.subject),([,c])=>G.stringifyIdent(c.ident)]);for(let[,c]of n.values()){if(!c.root)continue;let f=t.peerWarnings.find(E=>E.hash===c.hash),p=[...G.allPeerRequests(c)],h;if(p.length>2?h=` and ${p.length-1} other dependencies`:p.length===2?h=\" and 1 other dependency\":h=\"\",c.provided.range!==\"missing:\"){let E=t.storedResolutions.get(c.provided.descriptorHash);if(!E)throw new Error(\"Assertion failed: Expected the resolution to have been registered\");let C=t.storedPackages.get(E);if(!C)throw new Error(\"Assertion failed: Expected the provided package to have been registered\");let S=`${he.pretty(t.configuration,c.hash,he.Type.CODE)} \\u2192 ${f?a.Cross:a.Check} ${G.prettyLocator(t.configuration,c.subject)} provides ${G.prettyLocator(t.configuration,C)} to ${G.prettyLocator(t.configuration,p[0].requester)}${h}`;f?s.reportWarning(0,S):s.reportInfo(0,S)}else{let E=`${he.pretty(t.configuration,c.hash,he.Type.CODE)} \\u2192 ${f?a.Cross:a.Check} ${G.prettyLocator(t.configuration,c.subject)} doesn't provide ${G.prettyIdent(t.configuration,c.ident)} to ${G.prettyLocator(t.configuration,p[0].requester)}${h}`;f?s.reportWarning(0,E):s.reportInfo(0,E)}}})).exitCode()}Ge();Yt();Ul();Ge();Ge();Dt();Yt();var pye=ut(Ai()),EC=class extends ft{constructor(){super(...arguments);this.useYarnPath=ge.Boolean(\"--yarn-path\",{description:\"Set the yarnPath setting even if the version can be accessed by Corepack\"});this.onlyIfNeeded=ge.Boolean(\"--only-if-needed\",!1,{description:\"Only lock the Yarn version if it isn't already locked\"});this.version=ge.String()}static{this.paths=[[\"set\",\"version\"]]}static{this.usage=ot.Usage({description:\"lock the Yarn version used by the project\",details:\"\\n      This command will set a specific release of Yarn to be used by Corepack: https://nodejs.org/api/corepack.html.\\n\\n      By default it only will set the `packageManager` field at the root of your project, but if the referenced release cannot be represented this way, if you already have `yarnPath` configured, or if you set the `--yarn-path` command line flag, then the release will also be downloaded from the Yarn GitHub repository, stored inside your project, and referenced via the `yarnPath` settings from your project `.yarnrc.yml` file.\\n\\n      A very good use case for this command is to enforce the version of Yarn used by any single member of your team inside the same project - by doing this you ensure that you have control over Yarn upgrades and downgrades (including on your deployment servers), and get rid of most of the headaches related to someone using a slightly different version and getting different behavior.\\n\\n      The version specifier can be:\\n\\n      - a tag:\\n        - `latest` / `berry` / `stable` -> the most recent stable berry (`>=2.0.0`) release\\n        - `canary` -> the most recent canary (release candidate) berry (`>=2.0.0`) release\\n        - `classic` -> the most recent classic (`^0.x || ^1.x`) release\\n\\n      - a semver range (e.g. `2.x`) -> the most recent version satisfying the range (limited to berry releases)\\n\\n      - a semver version (e.g. `2.4.1`, `1.22.1`)\\n\\n      - a local file referenced through either a relative or absolute path\\n\\n      - `self` -> the version used to invoke the command\\n    \",examples:[[\"Download the latest release from the Yarn repository\",\"$0 set version latest\"],[\"Download the latest canary release from the Yarn repository\",\"$0 set version canary\"],[\"Download the latest classic release from the Yarn repository\",\"$0 set version classic\"],[\"Download the most recent Yarn 3 build\",\"$0 set version 3.x\"],[\"Download a specific Yarn 2 build\",\"$0 set version 2.0.0-rc.30\"],[\"Switch back to a specific Yarn 1 release\",\"$0 set version 1.22.1\"],[\"Use a release from the local filesystem\",\"$0 set version ./yarn.cjs\"],[\"Use a release from a URL\",\"$0 set version https://repo.yarnpkg.com/3.1.0/packages/yarnpkg-cli/bin/yarn.js\"],[\"Download the version used to invoke the command\",\"$0 set version self\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins);if(this.onlyIfNeeded&&r.get(\"yarnPath\")){let f=r.sources.get(\"yarnPath\");if(!f)throw new Error(\"Assertion failed: Expected 'yarnPath' to have a source\");let p=r.projectCwd??r.startingCwd;if(J.contains(p,f))return 0}let s=()=>{if(typeof fn>\"u\")throw new nt(\"The --install flag can only be used without explicit version specifier from the Yarn CLI\");return`file://${process.argv[1]}`},a,n=(f,p)=>({version:p,url:f.replace(/\\{\\}/g,p)});if(this.version===\"self\")a={url:s(),version:fn??\"self\"};else if(this.version===\"latest\"||this.version===\"berry\"||this.version===\"stable\")a=n(\"https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js\",await Xv(r,\"stable\"));else if(this.version===\"canary\")a=n(\"https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js\",await Xv(r,\"canary\"));else if(this.version===\"classic\")a={url:\"https://classic.yarnpkg.com/latest.js\",version:\"classic\"};else if(this.version.match(/^https?:/))a={url:this.version,version:\"remote\"};else if(this.version.match(/^\\.{0,2}[\\\\/]/)||fe.isAbsolute(this.version))a={url:`file://${J.resolve(fe.toPortablePath(this.version))}`,version:\"file\"};else if(Fr.satisfiesWithPrereleases(this.version,\">=2.0.0\"))a=n(\"https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js\",this.version);else if(Fr.satisfiesWithPrereleases(this.version,\"^0.x || ^1.x\"))a=n(\"https://github.com/yarnpkg/yarn/releases/download/v{}/yarn-{}.js\",this.version);else if(Fr.validRange(this.version))a=n(\"https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js\",await Glt(r,this.version));else throw new nt(`Invalid version descriptor \"${this.version}\"`);return(await Ot.start({configuration:r,stdout:this.context.stdout,includeLogs:!this.context.quiet},async f=>{let p=async()=>{let h=\"file://\";return a.url.startsWith(h)?(f.reportInfo(0,`Retrieving ${he.pretty(r,a.url,he.Type.PATH)}`),await ce.readFilePromise(a.url.slice(h.length))):(f.reportInfo(0,`Downloading ${he.pretty(r,a.url,he.Type.URL)}`),await ln.get(a.url,{configuration:r}))};await Jq(r,a.version,p,{report:f,useYarnPath:this.useYarnPath})})).exitCode()}};async function Glt(t,e){let s=(await ln.get(\"https://repo.yarnpkg.com/tags\",{configuration:t,jsonResponse:!0})).tags.filter(a=>Fr.satisfiesWithPrereleases(a,e));if(s.length===0)throw new nt(`No matching release found for range ${he.pretty(t,e,he.Type.RANGE)}.`);return s[0]}async function Xv(t,e){let r=await ln.get(\"https://repo.yarnpkg.com/tags\",{configuration:t,jsonResponse:!0});if(!r.latest[e])throw new nt(`Tag ${he.pretty(t,e,he.Type.RANGE)} not found`);return r.latest[e]}async function Jq(t,e,r,{report:s,useYarnPath:a}){let n,c=async()=>(typeof n>\"u\"&&(n=await r()),n);if(e===null){let ee=await c();await ce.mktempPromise(async ie=>{let ue=J.join(ie,\"yarn.cjs\");await ce.writeFilePromise(ue,ee);let{stdout:le}=await qr.execvp(process.execPath,[fe.fromPortablePath(ue),\"--version\"],{cwd:ie,env:{...t.env,YARN_IGNORE_PATH:\"1\"}});if(e=le.trim(),!pye.default.valid(e))throw new Error(`Invalid semver version. ${he.pretty(t,\"yarn --version\",he.Type.CODE)} returned:\n${e}`)})}let f=t.projectCwd??t.startingCwd,p=J.resolve(f,\".yarn/releases\"),h=J.resolve(p,`yarn-${e}.cjs`),E=J.relative(t.startingCwd,h),C=je.isTaggedYarnVersion(e),S=t.get(\"yarnPath\"),b=!C,I=b||!!S||!!a;if(a===!1){if(b)throw new jt(0,\"You explicitly opted out of yarnPath usage in your command line, but the version you specified cannot be represented by Corepack\");I=!1}else!I&&!process.env.COREPACK_ROOT&&(s.reportWarning(0,`You don't seem to have ${he.applyHyperlink(t,\"Corepack\",\"https://nodejs.org/api/corepack.html\")} enabled; we'll have to rely on ${he.applyHyperlink(t,\"yarnPath\",\"https://yarnpkg.com/configuration/yarnrc#yarnPath\")} instead`),I=!0);if(I){let ee=await c();s.reportInfo(0,`Saving the new release in ${he.pretty(t,E,\"magenta\")}`),await ce.removePromise(J.dirname(h)),await ce.mkdirPromise(J.dirname(h),{recursive:!0}),await ce.writeFilePromise(h,ee,{mode:493}),await ze.updateConfiguration(f,{yarnPath:J.relative(f,h)})}else await ce.removePromise(J.dirname(h)),await ze.updateConfiguration(f,{yarnPath:ze.deleteProperty});let T=await Ut.tryFind(f)||new Ut;T.packageManager=`yarn@${C?e:await Xv(t,\"stable\")}`;let N={};T.exportTo(N);let U=J.join(f,Ut.fileName),W=`${JSON.stringify(N,null,T.indent)}\n`;return await ce.changeFilePromise(U,W,{automaticNewlines:!0}),{bundleVersion:e}}function hye(t){return Br[jx(t)]}var qlt=/## (?<code>YN[0-9]{4}) - `(?<name>[A-Z_]+)`\\n\\n(?<details>(?:.(?!##))+)/gs;async function Wlt(t){let r=`https://repo.yarnpkg.com/${je.isTaggedYarnVersion(fn)?fn:await Xv(t,\"canary\")}/packages/docusaurus/docs/advanced/01-general-reference/error-codes.mdx`,s=await ln.get(r,{configuration:t});return new Map(Array.from(s.toString().matchAll(qlt),({groups:a})=>{if(!a)throw new Error(\"Assertion failed: Expected the match to have been successful\");let n=hye(a.code);if(a.name!==n)throw new Error(`Assertion failed: Invalid error code data: Expected \"${a.name}\" to be named \"${n}\"`);return[a.code,a.details]}))}var IC=class extends ft{constructor(){super(...arguments);this.code=ge.String({required:!1,validator:$2(wE(),[X2(/^YN[0-9]{4}$/)])});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}static{this.paths=[[\"explain\"]]}static{this.usage=ot.Usage({description:\"explain an error code\",details:`\n      When the code argument is specified, this command prints its name and its details.\n\n      When used without arguments, this command lists all error codes and their names.\n    `,examples:[[\"Explain an error code\",\"$0 explain YN0006\"],[\"List all error codes\",\"$0 explain\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins);if(typeof this.code<\"u\"){let s=hye(this.code),a=he.pretty(r,s,he.Type.CODE),n=this.cli.format().header(`${this.code} - ${a}`),f=(await Wlt(r)).get(this.code),p=typeof f<\"u\"?he.jsonOrPretty(this.json,r,he.tuple(he.Type.MARKDOWN,{text:f,format:this.cli.format(),paragraphs:!0})):`This error code does not have a description.\n\nYou can help us by editing this page on GitHub \\u{1F642}:\n${he.jsonOrPretty(this.json,r,he.tuple(he.Type.URL,\"https://github.com/yarnpkg/berry/blob/master/packages/docusaurus/docs/advanced/01-general-reference/error-codes.mdx\"))}\n`;this.json?this.context.stdout.write(`${JSON.stringify({code:this.code,name:s,details:p})}\n`):this.context.stdout.write(`${n}\n\n${p}\n`)}else{let s={children:je.mapAndFilter(Object.entries(Br),([a,n])=>Number.isNaN(Number(a))?je.mapAndFilter.skip:{label:Yf(Number(a)),value:he.tuple(he.Type.CODE,n)})};xs.emitTree(s,{configuration:r,stdout:this.context.stdout,json:this.json})}}};Ge();Dt();Yt();var gye=ut(Go()),CC=class extends ft{constructor(){super(...arguments);this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Print versions of a package from the whole project\"});this.recursive=ge.Boolean(\"-R,--recursive\",!1,{description:\"Print information for all packages, including transitive dependencies\"});this.extra=ge.Array(\"-X,--extra\",[],{description:\"An array of requests of extra data provided by plugins\"});this.cache=ge.Boolean(\"--cache\",!1,{description:\"Print information about the cache entry of a package (path, size, checksum)\"});this.dependents=ge.Boolean(\"--dependents\",!1,{description:\"Print all dependents for each matching package\"});this.manifest=ge.Boolean(\"--manifest\",!1,{description:\"Print data obtained by looking at the package archive (license, homepage, ...)\"});this.nameOnly=ge.Boolean(\"--name-only\",!1,{description:\"Only print the name for the matching packages\"});this.virtuals=ge.Boolean(\"--virtuals\",!1,{description:\"Print each instance of the virtual packages\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.patterns=ge.Rest()}static{this.paths=[[\"info\"]]}static{this.usage=ot.Usage({description:\"see information related to packages\",details:\"\\n      This command prints various information related to the specified packages, accepting glob patterns.\\n\\n      By default, if the locator reference is missing, Yarn will default to print the information about all the matching direct dependencies of the package for the active workspace. To instead print all versions of the package that are direct dependencies of any of your workspaces, use the `-A,--all` flag. Adding the `-R,--recursive` flag will also report transitive dependencies.\\n\\n      Some fields will be hidden by default in order to keep the output readable, but can be selectively displayed by using additional options (`--dependents`, `--manifest`, `--virtuals`, ...) described in the option descriptions.\\n\\n      Note that this command will only print the information directly related to the selected packages - if you wish to know why the package is there in the first place, use `yarn why` which will do just that (it also provides a `-R,--recursive` flag that may be of some help).\\n    \",examples:[[\"Show information about Lodash\",\"$0 info lodash\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n=await Kr.find(r);if(!a&&!this.all)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState();let c=new Set(this.extra);this.cache&&c.add(\"cache\"),this.dependents&&c.add(\"dependents\"),this.manifest&&c.add(\"manifest\");let f=(ie,{recursive:ue})=>{let le=ie.anchoredLocator.locatorHash,me=new Map,pe=[le];for(;pe.length>0;){let Be=pe.shift();if(me.has(Be))continue;let Ce=s.storedPackages.get(Be);if(typeof Ce>\"u\")throw new Error(\"Assertion failed: Expected the package to be registered\");if(me.set(Be,Ce),G.isVirtualLocator(Ce)&&pe.push(G.devirtualizeLocator(Ce).locatorHash),!(!ue&&Be!==le))for(let g of Ce.dependencies.values()){let we=s.storedResolutions.get(g.descriptorHash);if(typeof we>\"u\")throw new Error(\"Assertion failed: Expected the resolution to be registered\");pe.push(we)}}return me.values()},p=({recursive:ie})=>{let ue=new Map;for(let le of s.workspaces)for(let me of f(le,{recursive:ie}))ue.set(me.locatorHash,me);return ue.values()},h=({all:ie,recursive:ue})=>ie&&ue?s.storedPackages.values():ie?p({recursive:ue}):f(a,{recursive:ue}),E=({all:ie,recursive:ue})=>{let le=h({all:ie,recursive:ue}),me=this.patterns.map(Ce=>{let g=G.parseLocator(Ce),we=gye.default.makeRe(G.stringifyIdent(g)),ye=G.isVirtualLocator(g),Ae=ye?G.devirtualizeLocator(g):g;return se=>{let X=G.stringifyIdent(se);if(!we.test(X))return!1;if(g.reference===\"unknown\")return!0;let De=G.isVirtualLocator(se),Te=De?G.devirtualizeLocator(se):se;return!(ye&&De&&g.reference!==se.reference||Ae.reference!==Te.reference)}}),pe=je.sortMap([...le],Ce=>G.stringifyLocator(Ce));return{selection:pe.filter(Ce=>me.length===0||me.some(g=>g(Ce))),sortedLookup:pe}},{selection:C,sortedLookup:S}=E({all:this.all,recursive:this.recursive});if(C.length===0)throw new nt(\"No package matched your request\");let b=new Map;if(this.dependents)for(let ie of S)for(let ue of ie.dependencies.values()){let le=s.storedResolutions.get(ue.descriptorHash);if(typeof le>\"u\")throw new Error(\"Assertion failed: Expected the resolution to be registered\");je.getArrayWithDefault(b,le).push(ie)}let I=new Map;for(let ie of S){if(!G.isVirtualLocator(ie))continue;let ue=G.devirtualizeLocator(ie);je.getArrayWithDefault(I,ue.locatorHash).push(ie)}let T={},N={children:T},U=r.makeFetcher(),W={project:s,fetcher:U,cache:n,checksums:s.storedChecksums,report:new ki,cacheOptions:{skipIntegrityCheck:!0}},ee=[async(ie,ue,le)=>{if(!ue.has(\"manifest\"))return;let me=await U.fetch(ie,W),pe;try{pe=await Ut.find(me.prefixPath,{baseFs:me.packageFs})}finally{me.releaseFs?.()}le(\"Manifest\",{License:he.tuple(he.Type.NO_HINT,pe.license),Homepage:he.tuple(he.Type.URL,pe.raw.homepage??null)})},async(ie,ue,le)=>{if(!ue.has(\"cache\"))return;let me=s.storedChecksums.get(ie.locatorHash)??null,pe=n.getLocatorPath(ie,me),Be;if(pe!==null)try{Be=await ce.statPromise(pe)}catch{}let Ce=typeof Be<\"u\"?[Be.size,he.Type.SIZE]:void 0;le(\"Cache\",{Checksum:he.tuple(he.Type.NO_HINT,me),Path:he.tuple(he.Type.PATH,pe),Size:Ce})}];for(let ie of C){let ue=G.isVirtualLocator(ie);if(!this.virtuals&&ue)continue;let le={},me={value:[ie,he.Type.LOCATOR],children:le};if(T[G.stringifyLocator(ie)]=me,this.nameOnly){delete me.children;continue}let pe=I.get(ie.locatorHash);typeof pe<\"u\"&&(le.Instances={label:\"Instances\",value:he.tuple(he.Type.NUMBER,pe.length)}),le.Version={label:\"Version\",value:he.tuple(he.Type.NO_HINT,ie.version)};let Be=(g,we)=>{let ye={};if(le[g]=ye,Array.isArray(we))ye.children=we.map(Ae=>({value:Ae}));else{let Ae={};ye.children=Ae;for(let[se,X]of Object.entries(we))typeof X>\"u\"||(Ae[se]={label:se,value:X})}};if(!ue){for(let g of ee)await g(ie,c,Be);await r.triggerHook(g=>g.fetchPackageInfo,ie,c,Be)}ie.bin.size>0&&!ue&&Be(\"Exported Binaries\",[...ie.bin.keys()].map(g=>he.tuple(he.Type.PATH,g)));let Ce=b.get(ie.locatorHash);typeof Ce<\"u\"&&Ce.length>0&&Be(\"Dependents\",Ce.map(g=>he.tuple(he.Type.LOCATOR,g))),ie.dependencies.size>0&&!ue&&Be(\"Dependencies\",[...ie.dependencies.values()].map(g=>{let we=s.storedResolutions.get(g.descriptorHash),ye=typeof we<\"u\"?s.storedPackages.get(we)??null:null;return he.tuple(he.Type.RESOLUTION,{descriptor:g,locator:ye})})),ie.peerDependencies.size>0&&ue&&Be(\"Peer dependencies\",[...ie.peerDependencies.values()].map(g=>{let we=ie.dependencies.get(g.identHash),ye=typeof we<\"u\"?s.storedResolutions.get(we.descriptorHash)??null:null,Ae=ye!==null?s.storedPackages.get(ye)??null:null;return he.tuple(he.Type.RESOLUTION,{descriptor:g,locator:Ae})}))}xs.emitTree(N,{configuration:r,json:this.json,stdout:this.context.stdout,separators:this.nameOnly?0:2})}};Ge();Dt();wc();var rF=ut(Fd());Yt();var Kq=ut(Ai());Ul();var Ylt=[{selector:t=>t===-1,name:\"nodeLinker\",value:\"node-modules\"},{selector:t=>t!==-1&&t<8,name:\"enableGlobalCache\",value:!1},{selector:t=>t!==-1&&t<8,name:\"compressionLevel\",value:\"mixed\"}],wC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.immutable=ge.Boolean(\"--immutable\",{description:\"Abort with an error exit code if the lockfile was to be modified\"});this.immutableCache=ge.Boolean(\"--immutable-cache\",{description:\"Abort with an error exit code if the cache folder was to be modified\"});this.refreshLockfile=ge.Boolean(\"--refresh-lockfile\",{description:\"Refresh the package metadata stored in the lockfile\"});this.checkCache=ge.Boolean(\"--check-cache\",{description:\"Always refetch the packages and ensure that their checksums are consistent\"});this.checkResolutions=ge.Boolean(\"--check-resolutions\",{description:\"Validates that the package resolutions are coherent\"});this.inlineBuilds=ge.Boolean(\"--inline-builds\",{description:\"Verbosely print the output of the build steps of dependencies\"});this.mode=ge.String(\"--mode\",{description:\"Change what artifacts installs generate\",validator:fo($l)});this.cacheFolder=ge.String(\"--cache-folder\",{hidden:!0});this.frozenLockfile=ge.Boolean(\"--frozen-lockfile\",{hidden:!0});this.ignoreEngines=ge.Boolean(\"--ignore-engines\",{hidden:!0});this.nonInteractive=ge.Boolean(\"--non-interactive\",{hidden:!0});this.preferOffline=ge.Boolean(\"--prefer-offline\",{hidden:!0});this.production=ge.Boolean(\"--production\",{hidden:!0});this.registry=ge.String(\"--registry\",{hidden:!0});this.silent=ge.Boolean(\"--silent\",{hidden:!0});this.networkTimeout=ge.String(\"--network-timeout\",{hidden:!0})}static{this.paths=[[\"install\"],ot.Default]}static{this.usage=ot.Usage({description:\"install the project dependencies\",details:\"\\n      This command sets up your project if needed. The installation is split into four different steps that each have their own characteristics:\\n\\n      - **Resolution:** First the package manager will resolve your dependencies. The exact way a dependency version is privileged over another isn't standardized outside of the regular semver guarantees. If a package doesn't resolve to what you would expect, check that all dependencies are correctly declared (also check our website for more information: ).\\n\\n      - **Fetch:** Then we download all the dependencies if needed, and make sure that they're all stored within our cache (check the value of `cacheFolder` in `yarn config` to see where the cache files are stored).\\n\\n      - **Link:** Then we send the dependency tree information to internal plugins tasked with writing them on the disk in some form (for example by generating the `.pnp.cjs` file you might know).\\n\\n      - **Build:** Once the dependency tree has been written on the disk, the package manager will now be free to run the build scripts for all packages that might need it, in a topological order compatible with the way they depend on one another. See https://yarnpkg.com/advanced/lifecycle-scripts for detail.\\n\\n      Note that running this command is not part of the recommended workflow. Yarn supports zero-installs, which means that as long as you store your cache and your `.pnp.cjs` file inside your repository, everything will work without requiring any install right after cloning your repository or switching branches.\\n\\n      If the `--immutable` option is set (defaults to true on CI), Yarn will abort with an error exit code if the lockfile was to be modified (other paths can be added using the `immutablePatterns` configuration setting). For backward compatibility we offer an alias under the name of `--frozen-lockfile`, but it will be removed in a later release.\\n\\n      If the `--immutable-cache` option is set, Yarn will abort with an error exit code if the cache folder was to be modified (either because files would be added, or because they'd be removed).\\n\\n      If the `--refresh-lockfile` option is set, Yarn will keep the same resolution for the packages currently in the lockfile but will refresh their metadata. If used together with `--immutable`, it can validate that the lockfile information are consistent. This flag is enabled by default when Yarn detects it runs within a pull request context.\\n\\n      If the `--check-cache` option is set, Yarn will always refetch the packages and will ensure that their checksum matches what's 1/ described in the lockfile 2/ inside the existing cache files (if present). This is recommended as part of your CI workflow if you're both following the Zero-Installs model and accepting PRs from third-parties, as they'd otherwise have the ability to alter the checked-in packages before submitting them.\\n\\n      If the `--inline-builds` option is set, Yarn will verbosely print the output of the build steps of your dependencies (instead of writing them into individual files). This is likely useful mostly for debug purposes only when using Docker-like environments.\\n\\n      If the `--mode=<mode>` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\\n\\n      - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\\n\\n      - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\\n    \",examples:[[\"Install the project\",\"$0 install\"],[\"Validate a project when using Zero-Installs\",\"$0 install --immutable --immutable-cache\"],[\"Validate a project when using Zero-Installs (slightly safer if you accept external PRs)\",\"$0 install --immutable --immutable-cache --check-cache\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins);typeof this.inlineBuilds<\"u\"&&r.useWithSource(\"<cli>\",{enableInlineBuilds:this.inlineBuilds},r.startingCwd,{overwrite:!0});let s=!!process.env.FUNCTION_TARGET||!!process.env.GOOGLE_RUNTIME,a=await SI({configuration:r,stdout:this.context.stdout},[{option:this.ignoreEngines,message:\"The --ignore-engines option is deprecated; engine checking isn't a core feature anymore\",error:!rF.default.VERCEL},{option:this.registry,message:\"The --registry option is deprecated; prefer setting npmRegistryServer in your .yarnrc.yml file\"},{option:this.preferOffline,message:\"The --prefer-offline flag is deprecated; use the --cached flag with 'yarn add' instead\",error:!rF.default.VERCEL},{option:this.production,message:\"The --production option is deprecated on 'install'; use 'yarn workspaces focus' instead\",error:!0},{option:this.nonInteractive,message:\"The --non-interactive option is deprecated\",error:!s},{option:this.frozenLockfile,message:\"The --frozen-lockfile option is deprecated; use --immutable and/or --immutable-cache instead\",callback:()=>this.immutable=this.frozenLockfile},{option:this.cacheFolder,message:\"The cache-folder option has been deprecated; use rc settings instead\",error:!rF.default.NETLIFY}]);if(a!==null)return a;let n=this.mode===\"update-lockfile\";if(n&&(this.immutable||this.immutableCache))throw new nt(`${he.pretty(r,\"--immutable\",he.Type.CODE)} and ${he.pretty(r,\"--immutable-cache\",he.Type.CODE)} cannot be used with ${he.pretty(r,\"--mode=update-lockfile\",he.Type.CODE)}`);let c=(this.immutable??r.get(\"enableImmutableInstalls\"))&&!n,f=this.immutableCache&&!n;if(r.projectCwd!==null){let T=await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async N=>{let U=!1;await Klt(r,c)&&(N.reportInfo(48,\"Automatically removed core plugins that are now builtins \\u{1F44D}\"),U=!0),await Jlt(r,c)&&(N.reportInfo(48,\"Automatically fixed merge conflicts \\u{1F44D}\"),U=!0),U&&N.reportSeparator()});if(T.hasErrors())return T.exitCode()}if(r.projectCwd!==null){let T=await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async N=>{if(ze.telemetry?.isNew)ze.telemetry.commitTips(),N.reportInfo(65,\"Yarn will periodically gather anonymous telemetry: https://yarnpkg.com/advanced/telemetry\"),N.reportInfo(65,`Run ${he.pretty(r,\"yarn config set --home enableTelemetry 0\",he.Type.CODE)} to disable`),N.reportSeparator();else if(ze.telemetry?.shouldShowTips){let U=await ln.get(\"https://repo.yarnpkg.com/tags\",{configuration:r,jsonResponse:!0}).catch(()=>null);if(U!==null){let W=null;if(fn!==null){let ie=Kq.default.prerelease(fn)?\"canary\":\"stable\",ue=U.latest[ie];Kq.default.gt(ue,fn)&&(W=[ie,ue])}if(W)ze.telemetry.commitTips(),N.reportInfo(88,`${he.applyStyle(r,`A new ${W[0]} version of Yarn is available:`,he.Style.BOLD)} ${G.prettyReference(r,W[1])}!`),N.reportInfo(88,`Upgrade now by running ${he.pretty(r,`yarn set version ${W[1]}`,he.Type.CODE)}`),N.reportSeparator();else{let ee=ze.telemetry.selectTip(U.tips);ee&&(N.reportInfo(89,he.pretty(r,ee.message,he.Type.MARKDOWN_INLINE)),ee.url&&N.reportInfo(89,`Learn more at ${ee.url}`),N.reportSeparator())}}}});if(T.hasErrors())return T.exitCode()}let{project:p,workspace:h}=await Rt.find(r,this.context.cwd),E=p.lockfileLastVersion;if(E!==null){let T=await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async N=>{let U={};for(let W of Ylt)W.selector(E)&&typeof r.sources.get(W.name)>\"u\"&&(r.use(\"<compat>\",{[W.name]:W.value},p.cwd,{overwrite:!0}),U[W.name]=W.value);Object.keys(U).length>0&&(await ze.updateConfiguration(p.cwd,U),N.reportInfo(87,\"Migrated your project to the latest Yarn version \\u{1F680}\"),N.reportSeparator())});if(T.hasErrors())return T.exitCode()}let C=await Kr.find(r,{immutable:f,check:this.checkCache});if(!h)throw new ar(p.cwd,this.context.cwd);await p.restoreInstallState({restoreResolutions:!1});let S=r.get(\"enableHardenedMode\");S&&typeof r.sources.get(\"enableHardenedMode\")>\"u\"&&await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async T=>{T.reportWarning(0,\"Yarn detected that the current workflow is executed from a public pull request. For safety the hardened mode has been enabled.\"),T.reportWarning(0,`It will prevent malicious lockfile manipulations, in exchange for a slower install time. You can opt-out if necessary; check our ${he.applyHyperlink(r,\"documentation\",\"https://yarnpkg.com/features/security#hardened-mode\")} for more details.`),T.reportSeparator()}),(this.refreshLockfile??S)&&(p.lockfileNeedsRefresh=!0);let b=this.checkResolutions??S;return(await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout,forceSectionAlignment:!0,includeLogs:!0,includeVersion:!0},async T=>{await p.install({cache:C,report:T,immutable:c,checkResolutions:b,mode:this.mode})})).exitCode()}},Vlt=\"<<<<<<<\";async function Jlt(t,e){if(!t.projectCwd)return!1;let r=J.join(t.projectCwd,Er.lockfile);if(!await ce.existsPromise(r)||!(await ce.readFilePromise(r,\"utf8\")).includes(Vlt))return!1;if(e)throw new jt(47,\"Cannot autofix a lockfile when running an immutable install\");let a=await qr.execvp(\"git\",[\"rev-parse\",\"MERGE_HEAD\",\"HEAD\"],{cwd:t.projectCwd});if(a.code!==0&&(a=await qr.execvp(\"git\",[\"rev-parse\",\"REBASE_HEAD\",\"HEAD\"],{cwd:t.projectCwd})),a.code!==0&&(a=await qr.execvp(\"git\",[\"rev-parse\",\"CHERRY_PICK_HEAD\",\"HEAD\"],{cwd:t.projectCwd})),a.code!==0)throw new jt(83,\"Git returned an error when trying to find the commits pertaining to the conflict\");let n=await Promise.all(a.stdout.trim().split(/\\n/).map(async f=>{let p=await qr.execvp(\"git\",[\"show\",`${f}:./${Er.lockfile}`],{cwd:t.projectCwd});if(p.code!==0)throw new jt(83,`Git returned an error when trying to access the lockfile content in ${f}`);try{return as(p.stdout)}catch{throw new jt(46,\"A variant of the conflicting lockfile failed to parse\")}}));n=n.filter(f=>!!f.__metadata);for(let f of n){if(f.__metadata.version<7)for(let p of Object.keys(f)){if(p===\"__metadata\")continue;let h=G.parseDescriptor(p,!0),E=t.normalizeDependency(h),C=G.stringifyDescriptor(E);C!==p&&(f[C]=f[p],delete f[p])}for(let p of Object.keys(f)){if(p===\"__metadata\")continue;let h=f[p].checksum;typeof h>\"u\"||h.includes(\"/\")||(f[p].checksum=`${f.__metadata.cacheKey}/${h}`)}}let c=Object.assign({},...n);c.__metadata.version=`${Math.min(...n.map(f=>parseInt(f.__metadata.version??0)))}`,c.__metadata.cacheKey=\"merged\";for(let[f,p]of Object.entries(c))typeof p==\"string\"&&delete c[f];return await ce.changeFilePromise(r,nl(c),{automaticNewlines:!0}),!0}async function Klt(t,e){if(!t.projectCwd)return!1;let r=[],s=J.join(t.projectCwd,\".yarn/plugins/@yarnpkg\");return await ze.updateConfiguration(t.projectCwd,{plugins:n=>{if(!Array.isArray(n))return n;let c=n.filter(f=>{if(!f.path)return!0;let p=J.resolve(t.projectCwd,f.path),h=ov.has(f.spec)&&J.contains(s,p);return h&&r.push(p),!h});return c.length===0?ze.deleteProperty:c.length===n.length?n:c}},{immutable:e})?(await Promise.all(r.map(async n=>{await ce.removePromise(n)})),!0):!1}Ge();Dt();Yt();var BC=class extends ft{constructor(){super(...arguments);this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Link all workspaces belonging to the target projects to the current one\"});this.private=ge.Boolean(\"-p,--private\",!1,{description:\"Also link private workspaces belonging to the target projects to the current one\"});this.relative=ge.Boolean(\"-r,--relative\",!1,{description:\"Link workspaces using relative paths instead of absolute paths\"});this.destinations=ge.Rest()}static{this.paths=[[\"link\"]]}static{this.usage=ot.Usage({description:\"connect the local project to another one\",details:\"\\n      This command will set a new `resolutions` field in the project-level manifest and point it to the workspace at the specified location (even if part of another project).\\n    \",examples:[[\"Register one or more remote workspaces for use in the current project\",\"$0 link ~/ts-loader ~/jest\"],[\"Register all workspaces from a remote project for use in the current project\",\"$0 link ~/jest --all\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState({restoreResolutions:!1});let c=s.topLevelWorkspace,f=[];for(let p of this.destinations){let h=J.resolve(this.context.cwd,fe.toPortablePath(p)),E=await ze.find(h,this.context.plugins,{useRc:!1,strict:!1}),{project:C,workspace:S}=await Rt.find(E,h);if(s.cwd===C.cwd)throw new nt(`Invalid destination '${p}'; Can't link the project to itself`);if(!S)throw new ar(C.cwd,h);if(this.all){let b=!1;for(let I of C.workspaces)I.manifest.name&&(!I.manifest.private||this.private)&&(f.push(I),b=!0);if(!b)throw new nt(`No workspace found to be linked in the target project: ${p}`)}else{if(!S.manifest.name)throw new nt(`The target workspace at '${p}' doesn't have a name and thus cannot be linked`);if(S.manifest.private&&!this.private)throw new nt(`The target workspace at '${p}' is marked private - use the --private flag to link it anyway`);f.push(S)}}for(let p of f){let h=G.stringifyIdent(p.anchoredLocator),E=this.relative?J.relative(s.cwd,p.cwd):p.cwd;c.manifest.resolutions.push({pattern:{descriptor:{fullName:h}},reference:`portal:${E}`})}return await s.installWithNewReport({stdout:this.context.stdout},{cache:n})}};Yt();var vC=class extends ft{constructor(){super(...arguments);this.args=ge.Proxy()}static{this.paths=[[\"node\"]]}static{this.usage=ot.Usage({description:\"run node with the hook already setup\",details:`\n      This command simply runs Node. It also makes sure to call it in a way that's compatible with the current project (for example, on PnP projects the environment will be setup in such a way that PnP will be correctly injected into the environment).\n\n      The Node process will use the exact same version of Node as the one used to run Yarn itself, which might be a good way to ensure that your commands always use a consistent Node version.\n    `,examples:[[\"Run a Node script\",\"$0 node ./my-script.js\"]]})}async execute(){return this.cli.run([\"exec\",\"node\",...this.args])}};Ge();Yt();var SC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}static{this.paths=[[\"plugin\",\"check\"]]}static{this.usage=ot.Usage({category:\"Plugin-related commands\",description:\"find all third-party plugins that differ from their own spec\",details:`\n      Check only the plugins from https.\n\n      If this command detects any plugin differences in the CI environment, it will throw an error.\n    `,examples:[[\"find all third-party plugins that differ from their own spec\",\"$0 plugin check\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=await ze.findRcFiles(this.context.cwd);return(await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout},async n=>{for(let c of s)if(c.data?.plugins)for(let f of c.data.plugins){if(!f.checksum||!f.spec.match(/^https?:/))continue;let p=await ln.get(f.spec,{configuration:r}),h=Nn.makeHash(p);if(f.checksum===h)continue;let E=he.pretty(r,f.path,he.Type.PATH),C=he.pretty(r,f.spec,he.Type.URL),S=`${E} is different from the file provided by ${C}`;n.reportJson({...f,newChecksum:h}),n.reportError(0,S)}})).exitCode()}};Ge();Ge();Dt();Yt();var Iye=Ie(\"os\");Ge();Dt();Yt();var dye=Ie(\"os\");Ge();wc();Yt();var zlt=\"https://raw.githubusercontent.com/yarnpkg/berry/master/plugins.yml\";async function Sm(t,e){let r=await ln.get(zlt,{configuration:t}),s=as(r.toString());return Object.fromEntries(Object.entries(s).filter(([a,n])=>!e||Fr.satisfiesWithPrereleases(e,n.range??\"<4.0.0-rc.1\")))}var DC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}static{this.paths=[[\"plugin\",\"list\"]]}static{this.usage=ot.Usage({category:\"Plugin-related commands\",description:\"list the available official plugins\",details:\"\\n      This command prints the plugins available directly from the Yarn repository. Only those plugins can be referenced by name in `yarn plugin import`.\\n    \",examples:[[\"List the official plugins\",\"$0 plugin list\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins);return(await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout},async a=>{let n=await Sm(r,fn);for(let[c,{experimental:f,...p}]of Object.entries(n)){let h=c;f&&(h+=\" [experimental]\"),a.reportJson({name:c,experimental:f,...p}),a.reportInfo(null,h)}})).exitCode()}};var Zlt=/^[0-9]+$/,Xlt=process.platform===\"win32\";function mye(t){return Zlt.test(t)?`pull/${t}/head`:t}var $lt=({repository:t,branch:e},r)=>[[\"git\",\"init\",fe.fromPortablePath(r)],[\"git\",\"remote\",\"add\",\"origin\",t],[\"git\",\"fetch\",\"origin\",\"--depth=1\",mye(e)],[\"git\",\"reset\",\"--hard\",\"FETCH_HEAD\"]],ect=({branch:t})=>[[\"git\",\"fetch\",\"origin\",\"--depth=1\",mye(t),\"--force\"],[\"git\",\"reset\",\"--hard\",\"FETCH_HEAD\"],[\"git\",\"clean\",\"-dfx\",\"-e\",\"packages/yarnpkg-cli/bundles\"]],tct=({plugins:t,noMinify:e},r,s)=>[[\"yarn\",\"build:cli\",...new Array().concat(...t.map(a=>[\"--plugin\",J.resolve(s,a)])),...e?[\"--no-minify\"]:[],\"|\"],[Xlt?\"move\":\"mv\",\"packages/yarnpkg-cli/bundles/yarn.js\",fe.fromPortablePath(r),\"|\"]],PC=class extends ft{constructor(){super(...arguments);this.installPath=ge.String(\"--path\",{description:\"The path where the repository should be cloned to\"});this.repository=ge.String(\"--repository\",\"https://github.com/yarnpkg/berry.git\",{description:\"The repository that should be cloned\"});this.branch=ge.String(\"--branch\",\"master\",{description:\"The branch of the repository that should be cloned\"});this.plugins=ge.Array(\"--plugin\",[],{description:\"An array of additional plugins that should be included in the bundle\"});this.dryRun=ge.Boolean(\"-n,--dry-run\",!1,{description:\"If set, the bundle will be built but not added to the project\"});this.noMinify=ge.Boolean(\"--no-minify\",!1,{description:\"Build a bundle for development (debugging) - non-minified and non-mangled\"});this.force=ge.Boolean(\"-f,--force\",!1,{description:\"Always clone the repository instead of trying to fetch the latest commits\"});this.skipPlugins=ge.Boolean(\"--skip-plugins\",!1,{description:\"Skip updating the contrib plugins\"})}static{this.paths=[[\"set\",\"version\",\"from\",\"sources\"]]}static{this.usage=ot.Usage({description:\"build Yarn from master\",details:`\n      This command will clone the Yarn repository into a temporary folder, then build it. The resulting bundle will then be copied into the local project.\n\n      By default, it also updates all contrib plugins to the same commit the bundle is built from. This behavior can be disabled by using the \\`--skip-plugins\\` flag.\n    `,examples:[[\"Build Yarn from master\",\"$0 set version from sources\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Rt.find(r,this.context.cwd),a=typeof this.installPath<\"u\"?J.resolve(this.context.cwd,fe.toPortablePath(this.installPath)):J.resolve(fe.toPortablePath((0,dye.tmpdir)()),\"yarnpkg-sources\",Nn.makeHash(this.repository).slice(0,6));return(await Ot.start({configuration:r,stdout:this.context.stdout},async c=>{await zq(this,{configuration:r,report:c,target:a}),c.reportSeparator(),c.reportInfo(0,\"Building a fresh bundle\"),c.reportSeparator();let f=await qr.execvp(\"git\",[\"rev-parse\",\"--short\",\"HEAD\"],{cwd:a,strict:!0}),p=J.join(a,`packages/yarnpkg-cli/bundles/yarn-${f.stdout.trim()}.js`);ce.existsSync(p)||(await $v(tct(this,p,a),{configuration:r,context:this.context,target:a}),c.reportSeparator());let h=await ce.readFilePromise(p);if(!this.dryRun){let{bundleVersion:E}=await Jq(r,null,async()=>h,{report:c});this.skipPlugins||await rct(this,E,{project:s,report:c,target:a})}})).exitCode()}};async function $v(t,{configuration:e,context:r,target:s}){for(let[a,...n]of t){let c=n[n.length-1]===\"|\";if(c&&n.pop(),c)await qr.pipevp(a,n,{cwd:s,stdin:r.stdin,stdout:r.stdout,stderr:r.stderr,strict:!0});else{r.stdout.write(`${he.pretty(e,`  $ ${[a,...n].join(\" \")}`,\"grey\")}\n`);try{await qr.execvp(a,n,{cwd:s,strict:!0})}catch(f){throw r.stdout.write(f.stdout||f.stack),f}}}}async function zq(t,{configuration:e,report:r,target:s}){let a=!1;if(!t.force&&ce.existsSync(J.join(s,\".git\"))){r.reportInfo(0,\"Fetching the latest commits\"),r.reportSeparator();try{await $v(ect(t),{configuration:e,context:t.context,target:s}),a=!0}catch{r.reportSeparator(),r.reportWarning(0,\"Repository update failed; we'll try to regenerate it\")}}a||(r.reportInfo(0,\"Cloning the remote repository\"),r.reportSeparator(),await ce.removePromise(s),await ce.mkdirPromise(s,{recursive:!0}),await $v($lt(t,s),{configuration:e,context:t.context,target:s}))}async function rct(t,e,{project:r,report:s,target:a}){let n=await Sm(r.configuration,e),c=new Set(Object.keys(n));for(let f of r.configuration.plugins.keys())c.has(f)&&await Zq(f,t,{project:r,report:s,target:a})}Ge();Ge();Dt();Yt();var yye=ut(Ai()),Eye=Ie(\"vm\");var bC=class extends ft{constructor(){super(...arguments);this.name=ge.String();this.checksum=ge.Boolean(\"--checksum\",!0,{description:\"Whether to care if this plugin is modified\"})}static{this.paths=[[\"plugin\",\"import\"]]}static{this.usage=ot.Usage({category:\"Plugin-related commands\",description:\"download a plugin\",details:`\n      This command downloads the specified plugin from its remote location and updates the configuration to reference it in further CLI invocations.\n\n      Three types of plugin references are accepted:\n\n      - If the plugin is stored within the Yarn repository, it can be referenced by name.\n      - Third-party plugins can be referenced directly through their public urls.\n      - Local plugins can be referenced by their path on the disk.\n\n      If the \\`--no-checksum\\` option is set, Yarn will no longer care if the plugin is modified.\n\n      Plugins cannot be downloaded from the npm registry, and aren't allowed to have dependencies (they need to be bundled into a single file, possibly thanks to the \\`@yarnpkg/builder\\` package).\n    `,examples:[['Download and activate the \"@yarnpkg/plugin-exec\" plugin',\"$0 plugin import @yarnpkg/plugin-exec\"],['Download and activate the \"@yarnpkg/plugin-exec\" plugin (shorthand)',\"$0 plugin import exec\"],[\"Download and activate a community plugin\",\"$0 plugin import https://example.org/path/to/plugin.js\"],[\"Activate a local plugin\",\"$0 plugin import ./path/to/plugin.js\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins);return(await Ot.start({configuration:r,stdout:this.context.stdout},async a=>{let{project:n}=await Rt.find(r,this.context.cwd),c,f;if(this.name.match(/^\\.{0,2}[\\\\/]/)||fe.isAbsolute(this.name)){let p=J.resolve(this.context.cwd,fe.toPortablePath(this.name));a.reportInfo(0,`Reading ${he.pretty(r,p,he.Type.PATH)}`),c=J.relative(n.cwd,p),f=await ce.readFilePromise(p)}else{let p;if(this.name.match(/^https?:/)){try{new URL(this.name)}catch{throw new jt(52,`Plugin specifier \"${this.name}\" is neither a plugin name nor a valid url`)}c=this.name,p=this.name}else{let h=G.parseLocator(this.name.replace(/^((@yarnpkg\\/)?plugin-)?/,\"@yarnpkg/plugin-\"));if(h.reference!==\"unknown\"&&!yye.default.valid(h.reference))throw new jt(0,\"Official plugins only accept strict version references. Use an explicit URL if you wish to download them from another location.\");let E=G.stringifyIdent(h),C=await Sm(r,fn);if(!Object.hasOwn(C,E)){let S=`Couldn't find a plugin named ${G.prettyIdent(r,h)} on the remote registry.\n`;throw r.plugins.has(E)?S+=`A plugin named ${G.prettyIdent(r,h)} is already installed; possibly attempting to import a built-in plugin.`:S+=`Note that only the plugins referenced on our website (${he.pretty(r,\"https://github.com/yarnpkg/berry/blob/master/plugins.yml\",he.Type.URL)}) can be referenced by their name; any other plugin will have to be referenced through its public url (for example ${he.pretty(r,\"https://github.com/yarnpkg/berry/raw/master/packages/plugin-typescript/bin/%40yarnpkg/plugin-typescript.js\",he.Type.URL)}).`,new jt(51,S)}c=E,p=C[E].url,h.reference!==\"unknown\"?p=p.replace(/\\/master\\//,`/${E}/${h.reference}/`):fn!==null&&(p=p.replace(/\\/master\\//,`/@yarnpkg/cli/${fn}/`))}a.reportInfo(0,`Downloading ${he.pretty(r,p,\"green\")}`),f=await ln.get(p,{configuration:r})}await Xq(c,f,{checksum:this.checksum,project:n,report:a})})).exitCode()}};async function Xq(t,e,{checksum:r=!0,project:s,report:a}){let{configuration:n}=s,c={},f={exports:c};(0,Eye.runInNewContext)(e.toString(),{module:f,exports:c});let h=`.yarn/plugins/${f.exports.name}.cjs`,E=J.resolve(s.cwd,h);a.reportInfo(0,`Saving the new plugin in ${he.pretty(n,h,\"magenta\")}`),await ce.mkdirPromise(J.dirname(E),{recursive:!0}),await ce.writeFilePromise(E,e);let C={path:h,spec:t};r&&(C.checksum=Nn.makeHash(e)),await ze.addPlugin(s.cwd,[C])}var nct=({pluginName:t,noMinify:e},r)=>[[\"yarn\",`build:${t}`,...e?[\"--no-minify\"]:[],\"|\"]],xC=class extends ft{constructor(){super(...arguments);this.installPath=ge.String(\"--path\",{description:\"The path where the repository should be cloned to\"});this.repository=ge.String(\"--repository\",\"https://github.com/yarnpkg/berry.git\",{description:\"The repository that should be cloned\"});this.branch=ge.String(\"--branch\",\"master\",{description:\"The branch of the repository that should be cloned\"});this.noMinify=ge.Boolean(\"--no-minify\",!1,{description:\"Build a plugin for development (debugging) - non-minified and non-mangled\"});this.force=ge.Boolean(\"-f,--force\",!1,{description:\"Always clone the repository instead of trying to fetch the latest commits\"});this.name=ge.String()}static{this.paths=[[\"plugin\",\"import\",\"from\",\"sources\"]]}static{this.usage=ot.Usage({category:\"Plugin-related commands\",description:\"build a plugin from sources\",details:`\n      This command clones the Yarn repository into a temporary folder, builds the specified contrib plugin and updates the configuration to reference it in further CLI invocations.\n\n      The plugins can be referenced by their short name if sourced from the official Yarn repository.\n    `,examples:[['Build and activate the \"@yarnpkg/plugin-exec\" plugin',\"$0 plugin import from sources @yarnpkg/plugin-exec\"],['Build and activate the \"@yarnpkg/plugin-exec\" plugin (shorthand)',\"$0 plugin import from sources exec\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=typeof this.installPath<\"u\"?J.resolve(this.context.cwd,fe.toPortablePath(this.installPath)):J.resolve(fe.toPortablePath((0,Iye.tmpdir)()),\"yarnpkg-sources\",Nn.makeHash(this.repository).slice(0,6));return(await Ot.start({configuration:r,stdout:this.context.stdout},async n=>{let{project:c}=await Rt.find(r,this.context.cwd),f=G.parseIdent(this.name.replace(/^((@yarnpkg\\/)?plugin-)?/,\"@yarnpkg/plugin-\")),p=G.stringifyIdent(f),h=await Sm(r,fn);if(!Object.hasOwn(h,p))throw new jt(51,`Couldn't find a plugin named \"${p}\" on the remote registry. Note that only the plugins referenced on our website (https://github.com/yarnpkg/berry/blob/master/plugins.yml) can be built and imported from sources.`);let E=p;await zq(this,{configuration:r,report:n,target:s}),await Zq(E,this,{project:c,report:n,target:s})})).exitCode()}};async function Zq(t,{context:e,noMinify:r},{project:s,report:a,target:n}){let c=t.replace(/@yarnpkg\\//,\"\"),{configuration:f}=s;a.reportSeparator(),a.reportInfo(0,`Building a fresh ${c}`),a.reportSeparator(),await $v(nct({pluginName:c,noMinify:r},n),{configuration:f,context:e,target:n}),a.reportSeparator();let p=J.resolve(n,`packages/${c}/bundles/${t}.js`),h=await ce.readFilePromise(p);await Xq(t,h,{project:s,report:a})}Ge();Dt();Yt();var kC=class extends ft{constructor(){super(...arguments);this.name=ge.String()}static{this.paths=[[\"plugin\",\"remove\"]]}static{this.usage=ot.Usage({category:\"Plugin-related commands\",description:\"remove a plugin\",details:`\n      This command deletes the specified plugin from the .yarn/plugins folder and removes it from the configuration.\n\n      **Note:** The plugins have to be referenced by their name property, which can be obtained using the \\`yarn plugin runtime\\` command. Shorthands are not allowed.\n   `,examples:[[\"Remove a plugin imported from the Yarn repository\",\"$0 plugin remove @yarnpkg/plugin-typescript\"],[\"Remove a plugin imported from a local file\",\"$0 plugin remove my-local-plugin\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Rt.find(r,this.context.cwd);return(await Ot.start({configuration:r,stdout:this.context.stdout},async n=>{let c=this.name,f=G.parseIdent(c);if(!r.plugins.has(c))throw new nt(`${G.prettyIdent(r,f)} isn't referenced by the current configuration`);let p=`.yarn/plugins/${c}.cjs`,h=J.resolve(s.cwd,p);ce.existsSync(h)&&(n.reportInfo(0,`Removing ${he.pretty(r,p,he.Type.PATH)}...`),await ce.removePromise(h)),n.reportInfo(0,\"Updating the configuration...\"),await ze.updateConfiguration(s.cwd,{plugins:E=>{if(!Array.isArray(E))return E;let C=E.filter(S=>S.path!==p);return C.length===0?ze.deleteProperty:C.length===E.length?E:C}})})).exitCode()}};Ge();Yt();var QC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}static{this.paths=[[\"plugin\",\"runtime\"]]}static{this.usage=ot.Usage({category:\"Plugin-related commands\",description:\"list the active plugins\",details:`\n      This command prints the currently active plugins. Will be displayed both builtin plugins and external plugins.\n    `,examples:[[\"List the currently active plugins\",\"$0 plugin runtime\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins);return(await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout},async a=>{for(let n of r.plugins.keys()){let c=this.context.plugins.plugins.has(n),f=n;c&&(f+=\" [builtin]\"),a.reportJson({name:n,builtin:c}),a.reportInfo(null,`${f}`)}})).exitCode()}};Ge();Ge();Yt();var RC=class extends ft{constructor(){super(...arguments);this.idents=ge.Rest()}static{this.paths=[[\"rebuild\"]]}static{this.usage=ot.Usage({description:\"rebuild the project's native packages\",details:`\n      This command will automatically cause Yarn to forget about previous compilations of the given packages and to run them again.\n\n      Note that while Yarn forgets the compilation, the previous artifacts aren't erased from the filesystem and may affect the next builds (in good or bad). To avoid this, you may remove the .yarn/unplugged folder, or any other relevant location where packages might have been stored (Yarn may offer a way to do that automatically in the future).\n\n      By default all packages will be rebuilt, but you can filter the list by specifying the names of the packages you want to clear from memory.\n    `,examples:[[\"Rebuild all packages\",\"$0 rebuild\"],[\"Rebuild fsevents only\",\"$0 rebuild fsevents\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);let c=new Set;for(let f of this.idents)c.add(G.parseIdent(f).identHash);if(await s.restoreInstallState({restoreResolutions:!1}),await s.resolveEverything({cache:n,report:new ki}),c.size>0)for(let f of s.storedPackages.values())c.has(f.identHash)&&(s.storedBuildState.delete(f.locatorHash),s.skippedBuilds.delete(f.locatorHash));else s.storedBuildState.clear(),s.skippedBuilds.clear();return await s.installWithNewReport({stdout:this.context.stdout,quiet:this.context.quiet},{cache:n})}};Ge();Ge();Ge();Yt();var $q=ut(Go());Ul();var TC=class extends ft{constructor(){super(...arguments);this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Apply the operation to all workspaces from the current project\"});this.mode=ge.String(\"--mode\",{description:\"Change what artifacts installs generate\",validator:fo($l)});this.patterns=ge.Rest()}static{this.paths=[[\"remove\"]]}static{this.usage=ot.Usage({description:\"remove dependencies from the project\",details:`\n      This command will remove the packages matching the specified patterns from the current workspace.\n\n      If the \\`--mode=<mode>\\` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\n\n      - \\`skip-build\\` will not run the build scripts at all. Note that this is different from setting \\`enableScripts\\` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\n\n      - \\`update-lockfile\\` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\n\n      This command accepts glob patterns as arguments (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\n    `,examples:[[\"Remove a dependency from the current project\",\"$0 remove lodash\"],[\"Remove a dependency from all workspaces at once\",\"$0 remove lodash --all\"],[\"Remove all dependencies starting with `eslint-`\",\"$0 remove 'eslint-*'\"],[\"Remove all dependencies with the `@babel` scope\",\"$0 remove '@babel/*'\"],[\"Remove all dependencies matching `react-dom` or `react-helmet`\",\"$0 remove 'react-{dom,helmet}'\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState({restoreResolutions:!1});let c=this.all?s.workspaces:[a],f=[\"dependencies\",\"devDependencies\",\"peerDependencies\"],p=[],h=!1,E=[];for(let I of this.patterns){let T=!1,N=G.parseIdent(I);for(let U of c){let W=[...U.manifest.peerDependenciesMeta.keys()];for(let ee of(0,$q.default)(W,I))U.manifest.peerDependenciesMeta.delete(ee),h=!0,T=!0;for(let ee of f){let ie=U.manifest.getForScope(ee),ue=[...ie.values()].map(le=>G.stringifyIdent(le));for(let le of(0,$q.default)(ue,G.stringifyIdent(N))){let{identHash:me}=G.parseIdent(le),pe=ie.get(me);if(typeof pe>\"u\")throw new Error(\"Assertion failed: Expected the descriptor to be registered\");U.manifest[ee].delete(me),E.push([U,ee,pe]),h=!0,T=!0}}}T||p.push(I)}let C=p.length>1?\"Patterns\":\"Pattern\",S=p.length>1?\"don't\":\"doesn't\",b=this.all?\"any\":\"this\";if(p.length>0)throw new nt(`${C} ${he.prettyList(r,p,he.Type.CODE)} ${S} match any packages referenced by ${b} workspace`);return h?(await r.triggerMultipleHooks(I=>I.afterWorkspaceDependencyRemoval,E),await s.installWithNewReport({stdout:this.context.stdout},{cache:n,mode:this.mode})):0}};Ge();Ge();Yt();var Cye=Ie(\"util\"),FC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}static{this.paths=[[\"run\"]]}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);return(await Ot.start({configuration:r,stdout:this.context.stdout,json:this.json},async c=>{let f=a.manifest.scripts,p=je.sortMap(f.keys(),C=>C),h={breakLength:1/0,colors:r.get(\"enableColors\"),maxArrayLength:2},E=p.reduce((C,S)=>Math.max(C,S.length),0);for(let[C,S]of f.entries())c.reportInfo(null,`${C.padEnd(E,\" \")}   ${(0,Cye.inspect)(S,h)}`),c.reportJson({name:C,script:S})})).exitCode()}};Ge();Ge();Yt();var NC=class extends ft{constructor(){super(...arguments);this.inspect=ge.String(\"--inspect\",!1,{tolerateBoolean:!0,description:\"Forwarded to the underlying Node process when executing a binary\"});this.inspectBrk=ge.String(\"--inspect-brk\",!1,{tolerateBoolean:!0,description:\"Forwarded to the underlying Node process when executing a binary\"});this.topLevel=ge.Boolean(\"-T,--top-level\",!1,{description:\"Check the root workspace for scripts and/or binaries instead of the current one\"});this.binariesOnly=ge.Boolean(\"-B,--binaries-only\",!1,{description:\"Ignore any user defined scripts and only check for binaries\"});this.require=ge.String(\"--require\",{description:\"Forwarded to the underlying Node process when executing a binary\"});this.silent=ge.Boolean(\"--silent\",{hidden:!0});this.scriptName=ge.String();this.args=ge.Proxy()}static{this.paths=[[\"run\"]]}static{this.usage=ot.Usage({description:\"run a script defined in the package.json\",details:`\n      This command will run a tool. The exact tool that will be executed will depend on the current state of your workspace:\n\n      - If the \\`scripts\\` field from your local package.json contains a matching script name, its definition will get executed.\n\n      - Otherwise, if one of the local workspace's dependencies exposes a binary with a matching name, this binary will get executed.\n\n      - Otherwise, if the specified name contains a colon character and if one of the workspaces in the project contains exactly one script with a matching name, then this script will get executed.\n\n      Whatever happens, the cwd of the spawned process will be the workspace that declares the script (which makes it possible to call commands cross-workspaces using the third syntax).\n    `,examples:[[\"Run the tests from the local workspace\",\"$0 run test\"],['Same thing, but without the \"run\" keyword',\"$0 test\"],[\"Inspect Webpack while running\",\"$0 run --inspect-brk webpack\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a,locator:n}=await Rt.find(r,this.context.cwd);await s.restoreInstallState();let c=this.topLevel?s.topLevelWorkspace.anchoredLocator:n;if(!this.binariesOnly&&await In.hasPackageScript(c,this.scriptName,{project:s}))return await In.executePackageScript(c,this.scriptName,this.args,{project:s,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});let f=await In.getPackageAccessibleBinaries(c,{project:s});if(f.get(this.scriptName)){let h=[];return this.inspect&&(typeof this.inspect==\"string\"?h.push(`--inspect=${this.inspect}`):h.push(\"--inspect\")),this.inspectBrk&&(typeof this.inspectBrk==\"string\"?h.push(`--inspect-brk=${this.inspectBrk}`):h.push(\"--inspect-brk\")),this.require&&h.push(`--require=${this.require}`),await In.executePackageAccessibleBinary(c,this.scriptName,this.args,{cwd:this.context.cwd,project:s,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr,nodeArgs:h,packageAccessibleBinaries:f})}if(!this.topLevel&&!this.binariesOnly&&a&&this.scriptName.includes(\":\")){let E=(await Promise.all(s.workspaces.map(async C=>C.manifest.scripts.has(this.scriptName)?C:null))).filter(C=>C!==null);if(E.length===1)return await In.executeWorkspaceScript(E[0],this.scriptName,this.args,{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr})}if(this.topLevel)throw this.scriptName===\"node-gyp\"?new nt(`Couldn't find a script name \"${this.scriptName}\" in the top-level (used by ${G.prettyLocator(r,n)}). This typically happens because some package depends on \"node-gyp\" to build itself, but didn't list it in their dependencies. To fix that, please run \"yarn add node-gyp\" into your top-level workspace. You also can open an issue on the repository of the specified package to suggest them to use an optional peer dependency.`):new nt(`Couldn't find a script name \"${this.scriptName}\" in the top-level (used by ${G.prettyLocator(r,n)}).`);{if(this.scriptName===\"global\")throw new nt(\"The 'yarn global' commands have been removed in 2.x - consider using 'yarn dlx' or a third-party plugin instead\");let h=[this.scriptName].concat(this.args);for(let[E,C]of $I)for(let S of C)if(h.length>=S.length&&JSON.stringify(h.slice(0,S.length))===JSON.stringify(S))throw new nt(`Couldn't find a script named \"${this.scriptName}\", but a matching command can be found in the ${E} plugin. You can install it with \"yarn plugin import ${E}\".`);throw new nt(`Couldn't find a script named \"${this.scriptName}\".`)}}};Ge();Ge();Yt();var OC=class extends ft{constructor(){super(...arguments);this.descriptor=ge.String();this.resolution=ge.String()}static{this.paths=[[\"set\",\"resolution\"]]}static{this.usage=ot.Usage({description:\"enforce a package resolution\",details:'\\n      This command updates the resolution table so that `descriptor` is resolved by `resolution`.\\n\\n      Note that by default this command only affect the current resolution table - meaning that this \"manual override\" will disappear if you remove the lockfile, or if the package disappear from the table. If you wish to make the enforced resolution persist whatever happens, edit the `resolutions` field in your top-level manifest.\\n\\n      Note that no attempt is made at validating that `resolution` is a valid resolution entry for `descriptor`.\\n    ',examples:[[\"Force all instances of lodash@npm:^1.2.3 to resolve to 1.5.0\",\"$0 set resolution lodash@npm:^1.2.3 npm:1.5.0\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n=await Kr.find(r);if(await s.restoreInstallState({restoreResolutions:!1}),!a)throw new ar(s.cwd,this.context.cwd);let c=G.parseDescriptor(this.descriptor,!0),f=G.makeDescriptor(c,this.resolution);return s.storedDescriptors.set(c.descriptorHash,c),s.storedDescriptors.set(f.descriptorHash,f),s.resolutionAliases.set(c.descriptorHash,f.descriptorHash),await s.installWithNewReport({stdout:this.context.stdout},{cache:n})}};Ge();Dt();Yt();var wye=ut(Go()),LC=class extends ft{constructor(){super(...arguments);this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Unlink all workspaces belonging to the target project from the current one\"});this.leadingArguments=ge.Rest()}static{this.paths=[[\"unlink\"]]}static{this.usage=ot.Usage({description:\"disconnect the local project from another one\",details:`\n      This command will remove any resolutions in the project-level manifest that would have been added via a yarn link with similar arguments.\n    `,examples:[[\"Unregister a remote workspace in the current project\",\"$0 unlink ~/ts-loader\"],[\"Unregister all workspaces from a remote project in the current project\",\"$0 unlink ~/jest --all\"],[\"Unregister all previously linked workspaces\",\"$0 unlink --all\"],[\"Unregister all workspaces matching a glob\",\"$0 unlink '@babel/*' 'pkg-{a,b}'\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);let c=s.topLevelWorkspace,f=new Set;if(this.leadingArguments.length===0&&this.all)for(let{pattern:p,reference:h}of c.manifest.resolutions)h.startsWith(\"portal:\")&&f.add(p.descriptor.fullName);if(this.leadingArguments.length>0)for(let p of this.leadingArguments){let h=J.resolve(this.context.cwd,fe.toPortablePath(p));if(je.isPathLike(p)){let E=await ze.find(h,this.context.plugins,{useRc:!1,strict:!1}),{project:C,workspace:S}=await Rt.find(E,h);if(!S)throw new ar(C.cwd,h);if(this.all){for(let b of C.workspaces)b.manifest.name&&f.add(G.stringifyIdent(b.anchoredLocator));if(f.size===0)throw new nt(\"No workspace found to be unlinked in the target project\")}else{if(!S.manifest.name)throw new nt(\"The target workspace doesn't have a name and thus cannot be unlinked\");f.add(G.stringifyIdent(S.anchoredLocator))}}else{let E=[...c.manifest.resolutions.map(({pattern:C})=>C.descriptor.fullName)];for(let C of(0,wye.default)(E,p))f.add(C)}}return c.manifest.resolutions=c.manifest.resolutions.filter(({pattern:p})=>!f.has(p.descriptor.fullName)),await s.installWithNewReport({stdout:this.context.stdout,quiet:this.context.quiet},{cache:n})}};Ge();Ge();Ge();Yt();var Bye=ut(Vv()),e5=ut(Go());Ul();var MC=class extends ft{constructor(){super(...arguments);this.interactive=ge.Boolean(\"-i,--interactive\",{description:\"Offer various choices, depending on the detected upgrade paths\"});this.fixed=ge.Boolean(\"-F,--fixed\",!1,{description:\"Store dependency tags as-is instead of resolving them\"});this.exact=ge.Boolean(\"-E,--exact\",!1,{description:\"Don't use any semver modifier on the resolved range\"});this.tilde=ge.Boolean(\"-T,--tilde\",!1,{description:\"Use the `~` semver modifier on the resolved range\"});this.caret=ge.Boolean(\"-C,--caret\",!1,{description:\"Use the `^` semver modifier on the resolved range\"});this.recursive=ge.Boolean(\"-R,--recursive\",!1,{description:\"Resolve again ALL resolutions for those packages\"});this.mode=ge.String(\"--mode\",{description:\"Change what artifacts installs generate\",validator:fo($l)});this.patterns=ge.Rest()}static{this.paths=[[\"up\"]]}static{this.usage=ot.Usage({description:\"upgrade dependencies across the project\",details:\"\\n      This command upgrades the packages matching the list of specified patterns to their latest available version across the whole project (regardless of whether they're part of `dependencies` or `devDependencies` - `peerDependencies` won't be affected). This is a project-wide command: all workspaces will be upgraded in the process.\\n\\n      If `-R,--recursive` is set the command will change behavior and no other switch will be allowed. When operating under this mode `yarn up` will force all ranges matching the selected packages to be resolved again (often to the highest available versions) before being stored in the lockfile. It however won't touch your manifests anymore, so depending on your needs you might want to run both `yarn up` and `yarn up -R` to cover all bases.\\n\\n      If `-i,--interactive` is set (or if the `preferInteractive` settings is toggled on) the command will offer various choices, depending on the detected upgrade paths. Some upgrades require this flag in order to resolve ambiguities.\\n\\n      The, `-C,--caret`, `-E,--exact` and  `-T,--tilde` options have the same meaning as in the `add` command (they change the modifier used when the range is missing or a tag, and are ignored when the range is explicitly set).\\n\\n      If the `--mode=<mode>` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\\n\\n      - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\\n\\n      - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\\n\\n      Generally you can see `yarn up` as a counterpart to what was `yarn upgrade --latest` in Yarn 1 (ie it ignores the ranges previously listed in your manifests), but unlike `yarn upgrade` which only upgraded dependencies in the current workspace, `yarn up` will upgrade all workspaces at the same time.\\n\\n      This command accepts glob patterns as arguments (if valid Descriptors and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\\n\\n      **Note:** The ranges have to be static, only the package scopes and names can contain glob patterns.\\n    \",examples:[[\"Upgrade all instances of lodash to the latest release\",\"$0 up lodash\"],[\"Upgrade all instances of lodash to the latest release, but ask confirmation for each\",\"$0 up lodash -i\"],[\"Upgrade all instances of lodash to 1.2.3\",\"$0 up lodash@1.2.3\"],[\"Upgrade all instances of packages with the `@babel` scope to the latest release\",\"$0 up '@babel/*'\"],[\"Upgrade all instances of packages containing the word `jest` to the latest release\",\"$0 up '*jest*'\"],[\"Upgrade all instances of packages with the `@babel` scope to 7.0.0\",\"$0 up '@babel/*@7.0.0'\"]]})}static{this.schema=[tB(\"recursive\",qf.Forbids,[\"interactive\",\"exact\",\"tilde\",\"caret\"],{ignore:[void 0,!1]})]}async execute(){return this.recursive?await this.executeUpRecursive():await this.executeUpClassic()}async executeUpRecursive(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState({restoreResolutions:!1});let c=[...s.storedDescriptors.values()],f=c.map(E=>G.stringifyIdent(E)),p=new Set;for(let E of this.patterns){if(G.parseDescriptor(E).range!==\"unknown\")throw new nt(\"Ranges aren't allowed when using --recursive\");for(let C of(0,e5.default)(f,E)){let S=G.parseIdent(C);p.add(S.identHash)}}let h=c.filter(E=>p.has(E.identHash));for(let E of h)s.storedDescriptors.delete(E.descriptorHash),s.storedResolutions.delete(E.descriptorHash);return await s.installWithNewReport({stdout:this.context.stdout},{cache:n,mode:this.mode})}async executeUpClassic(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState({restoreResolutions:!1});let c=this.fixed,f=r.isInteractive({interactive:this.interactive,stdout:this.context.stdout}),p=Kv(this,s),h=f?[\"keep\",\"reuse\",\"project\",\"latest\"]:[\"project\",\"latest\"],E=[],C=[];for(let N of this.patterns){let U=!1,W=G.parseDescriptor(N),ee=G.stringifyIdent(W);for(let ie of s.workspaces)for(let ue of[\"dependencies\",\"devDependencies\"]){let me=[...ie.manifest.getForScope(ue).values()].map(Be=>G.stringifyIdent(Be)),pe=ee===\"*\"?me:(0,e5.default)(me,ee);for(let Be of pe){let Ce=G.parseIdent(Be),g=ie.manifest[ue].get(Ce.identHash);if(typeof g>\"u\")throw new Error(\"Assertion failed: Expected the descriptor to be registered\");let we=G.makeDescriptor(Ce,W.range);E.push(Promise.resolve().then(async()=>[ie,ue,g,await zv(we,{project:s,workspace:ie,cache:n,target:ue,fixed:c,modifier:p,strategies:h})])),U=!0}}U||C.push(N)}if(C.length>1)throw new nt(`Patterns ${he.prettyList(r,C,he.Type.CODE)} don't match any packages referenced by any workspace`);if(C.length>0)throw new nt(`Pattern ${he.prettyList(r,C,he.Type.CODE)} doesn't match any packages referenced by any workspace`);let S=await Promise.all(E),b=await lA.start({configuration:r,stdout:this.context.stdout,suggestInstall:!1},async N=>{for(let[,,U,{suggestions:W,rejections:ee}]of S){let ie=W.filter(ue=>ue.descriptor!==null);if(ie.length===0){let[ue]=ee;if(typeof ue>\"u\")throw new Error(\"Assertion failed: Expected an error to have been set\");let le=this.cli.error(ue);s.configuration.get(\"enableNetwork\")?N.reportError(27,`${G.prettyDescriptor(r,U)} can't be resolved to a satisfying range\n\n${le}`):N.reportError(27,`${G.prettyDescriptor(r,U)} can't be resolved to a satisfying range (note: network resolution has been disabled)\n\n${le}`)}else ie.length>1&&!f&&N.reportError(27,`${G.prettyDescriptor(r,U)} has multiple possible upgrade strategies; use -i to disambiguate manually`)}});if(b.hasErrors())return b.exitCode();let I=!1,T=[];for(let[N,U,,{suggestions:W}]of S){let ee,ie=W.filter(pe=>pe.descriptor!==null),ue=ie[0].descriptor,le=ie.every(pe=>G.areDescriptorsEqual(pe.descriptor,ue));ie.length===1||le?ee=ue:(I=!0,{answer:ee}=await(0,Bye.prompt)({type:\"select\",name:\"answer\",message:`Which range do you want to use in ${G.prettyWorkspace(r,N)} \\u276F ${U}?`,choices:W.map(({descriptor:pe,name:Be,reason:Ce})=>pe?{name:Be,hint:Ce,descriptor:pe}:{name:Be,hint:Ce,disabled:!0}),onCancel:()=>process.exit(130),result(pe){return this.find(pe,\"descriptor\")},stdin:this.context.stdin,stdout:this.context.stdout}));let me=N.manifest[U].get(ee.identHash);if(typeof me>\"u\")throw new Error(\"Assertion failed: This descriptor should have a matching entry\");if(me.descriptorHash!==ee.descriptorHash)N.manifest[U].set(ee.identHash,ee),T.push([N,U,me,ee]);else{let pe=r.makeResolver(),Be={project:s,resolver:pe},Ce=r.normalizeDependency(me),g=pe.bindDescriptor(Ce,N.anchoredLocator,Be);s.forgetResolution(g)}}return await r.triggerMultipleHooks(N=>N.afterWorkspaceDependencyReplacement,T),I&&this.context.stdout.write(`\n`),await s.installWithNewReport({stdout:this.context.stdout},{cache:n,mode:this.mode})}};Ge();Ge();Ge();Yt();var UC=class extends ft{constructor(){super(...arguments);this.recursive=ge.Boolean(\"-R,--recursive\",!1,{description:\"List, for each workspace, what are all the paths that lead to the dependency\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.peers=ge.Boolean(\"--peers\",!1,{description:\"Also print the peer dependencies that match the specified name\"});this.package=ge.String()}static{this.paths=[[\"why\"]]}static{this.usage=ot.Usage({description:\"display the reason why a package is needed\",details:`\n      This command prints the exact reasons why a package appears in the dependency tree.\n\n      If \\`-R,--recursive\\` is set, the listing will go in depth and will list, for each workspaces, what are all the paths that lead to the dependency. Note that the display is somewhat optimized in that it will not print the package listing twice for a single package, so if you see a leaf named \"Foo\" when looking for \"Bar\", it means that \"Foo\" already got printed higher in the tree.\n    `,examples:[[\"Explain why lodash is used in your project\",\"$0 why lodash\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState();let n=G.parseIdent(this.package).identHash,c=this.recursive?sct(s,n,{configuration:r,peers:this.peers}):ict(s,n,{configuration:r,peers:this.peers});xs.emitTree(c,{configuration:r,stdout:this.context.stdout,json:this.json,separators:1})}};function ict(t,e,{configuration:r,peers:s}){let a=je.sortMap(t.storedPackages.values(),f=>G.stringifyLocator(f)),n={},c={children:n};for(let f of a){let p={};for(let E of f.dependencies.values()){if(!s&&f.peerDependencies.has(E.identHash))continue;let C=t.storedResolutions.get(E.descriptorHash);if(!C)throw new Error(\"Assertion failed: The resolution should have been registered\");let S=t.storedPackages.get(C);if(!S)throw new Error(\"Assertion failed: The package should have been registered\");if(S.identHash!==e)continue;{let I=G.stringifyLocator(f);n[I]={value:[f,he.Type.LOCATOR],children:p}}let b=G.stringifyLocator(S);p[b]={value:[{descriptor:E,locator:S},he.Type.DEPENDENT]}}}return c}function sct(t,e,{configuration:r,peers:s}){let a=je.sortMap(t.workspaces,S=>G.stringifyLocator(S.anchoredLocator)),n=new Set,c=new Set,f=S=>{if(n.has(S.locatorHash))return c.has(S.locatorHash);if(n.add(S.locatorHash),S.identHash===e)return c.add(S.locatorHash),!0;let b=!1;S.identHash===e&&(b=!0);for(let I of S.dependencies.values()){if(!s&&S.peerDependencies.has(I.identHash))continue;let T=t.storedResolutions.get(I.descriptorHash);if(!T)throw new Error(\"Assertion failed: The resolution should have been registered\");let N=t.storedPackages.get(T);if(!N)throw new Error(\"Assertion failed: The package should have been registered\");f(N)&&(b=!0)}return b&&c.add(S.locatorHash),b};for(let S of a)f(S.anchoredPackage);let p=new Set,h={},E={children:h},C=(S,b,I)=>{if(!c.has(S.locatorHash))return;let T=I!==null?he.tuple(he.Type.DEPENDENT,{locator:S,descriptor:I}):he.tuple(he.Type.LOCATOR,S),N={},U={value:T,children:N},W=G.stringifyLocator(S);if(b[W]=U,!(I!==null&&t.tryWorkspaceByLocator(S))&&!p.has(S.locatorHash)){p.add(S.locatorHash);for(let ee of S.dependencies.values()){if(!s&&S.peerDependencies.has(ee.identHash))continue;let ie=t.storedResolutions.get(ee.descriptorHash);if(!ie)throw new Error(\"Assertion failed: The resolution should have been registered\");let ue=t.storedPackages.get(ie);if(!ue)throw new Error(\"Assertion failed: The package should have been registered\");C(ue,N,ee)}}};for(let S of a)C(S.anchoredPackage,h,null);return E}Ge();var u5={};Vt(u5,{GitFetcher:()=>tS,GitResolver:()=>rS,default:()=>Dct,gitUtils:()=>ka});Ge();Dt();var ka={};Vt(ka,{TreeishProtocols:()=>eS,clone:()=>c5,fetchBase:()=>qye,fetchChangedFiles:()=>Wye,fetchChangedWorkspaces:()=>vct,fetchRoot:()=>Gye,isGitUrl:()=>jC,lsRemote:()=>jye,normalizeLocator:()=>Bct,normalizeRepoUrl:()=>_C,resolveUrl:()=>l5,splitRepoUrl:()=>W0,validateRepoUrl:()=>a5});Ge();Dt();Yt();ql();var _ye=ut(Lye()),HC=ut(Ie(\"querystring\")),s5=ut(Ai());function i5(t,e,r){let s=t.indexOf(r);return t.lastIndexOf(e,s>-1?s:1/0)}function Mye(t){try{return new URL(t)}catch{return}}function Cct(t){let e=i5(t,\"@\",\"#\"),r=i5(t,\":\",\"#\");return r>e&&(t=`${t.slice(0,r)}/${t.slice(r+1)}`),i5(t,\":\",\"#\")===-1&&t.indexOf(\"//\")===-1&&(t=`ssh://${t}`),t}function Uye(t){return Mye(t)||Mye(Cct(t))}function _C(t,{git:e=!1}={}){if(t=t.replace(/^git\\+https:/,\"https:\"),t=t.replace(/^(?:github:|https:\\/\\/github\\.com\\/|git:\\/\\/github\\.com\\/)?(?!\\.{1,2}\\/)([a-zA-Z0-9._-]+)\\/(?!\\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)(?:\\.git)?(#.*)?$/,\"https://github.com/$1/$2.git$3\"),t=t.replace(/^https:\\/\\/github\\.com\\/(?!\\.{1,2}\\/)([a-zA-Z0-9._-]+)\\/(?!\\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)\\/tarball\\/(.+)?$/,\"https://github.com/$1/$2.git#$3\"),e){let r=Uye(t);r&&(t=r.href),t=t.replace(/^git\\+([^:]+):/,\"$1:\")}return t}function Hye(){return{...process.env,GIT_SSH_COMMAND:process.env.GIT_SSH_COMMAND||`${process.env.GIT_SSH||\"ssh\"} -o BatchMode=yes`}}var wct=[/^ssh:/,/^git(?:\\+[^:]+)?:/,/^(?:git\\+)?https?:[^#]+\\/[^#]+(?:\\.git)(?:#.*)?$/,/^git@[^#]+\\/[^#]+\\.git(?:#.*)?$/,/^(?:github:|https:\\/\\/github\\.com\\/)?(?!\\.{1,2}\\/)([a-zA-Z._0-9-]+)\\/(?!\\.{1,2}(?:#|$))([a-zA-Z._0-9-]+?)(?:\\.git)?(?:#.*)?$/,/^https:\\/\\/github\\.com\\/(?!\\.{1,2}\\/)([a-zA-Z0-9._-]+)\\/(?!\\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)\\/tarball\\/(.+)?$/],eS=(a=>(a.Commit=\"commit\",a.Head=\"head\",a.Tag=\"tag\",a.Semver=\"semver\",a))(eS||{});function jC(t){return t?wct.some(e=>!!t.match(e)):!1}function W0(t){t=_C(t);let e=t.indexOf(\"#\");if(e===-1)return{repo:t,treeish:{protocol:\"head\",request:\"HEAD\"},extra:{}};let r=t.slice(0,e),s=t.slice(e+1);if(s.match(/^[a-z]+=/)){let a=HC.default.parse(s);for(let[p,h]of Object.entries(a))if(typeof h!=\"string\")throw new Error(`Assertion failed: The ${p} parameter must be a literal string`);let n=Object.values(eS).find(p=>Object.hasOwn(a,p)),[c,f]=typeof n<\"u\"?[n,a[n]]:[\"head\",\"HEAD\"];for(let p of Object.values(eS))delete a[p];return{repo:r,treeish:{protocol:c,request:f},extra:a}}else{let a=s.indexOf(\":\"),[n,c]=a===-1?[null,s]:[s.slice(0,a),s.slice(a+1)];return{repo:r,treeish:{protocol:n,request:c},extra:{}}}}function Bct(t){return G.makeLocator(t,_C(t.reference))}function a5(t,{configuration:e}){let r=_C(t,{git:!0});if(!ln.getNetworkSettings(`https://${(0,_ye.default)(r).resource}`,{configuration:e}).enableNetwork)throw new jt(80,`Request to '${r}' has been blocked because of your configuration settings`);return r}async function jye(t,e){let r=a5(t,{configuration:e}),s=await o5(\"listing refs\",[\"ls-remote\",r],{cwd:e.startingCwd,env:Hye()},{configuration:e,normalizedRepoUrl:r}),a=new Map,n=/^([a-f0-9]{40})\\t([^\\n]+)/gm,c;for(;(c=n.exec(s.stdout))!==null;)a.set(c[2],c[1]);return a}async function l5(t,e){let{repo:r,treeish:{protocol:s,request:a},extra:n}=W0(t),c=await jye(r,e),f=(h,E)=>{switch(h){case\"commit\":{if(!E.match(/^[a-f0-9]{40}$/))throw new Error(\"Invalid commit hash\");return HC.default.stringify({...n,commit:E})}case\"head\":{let C=c.get(E===\"HEAD\"?E:`refs/heads/${E}`);if(typeof C>\"u\")throw new Error(`Unknown head (\"${E}\")`);return HC.default.stringify({...n,commit:C})}case\"tag\":{let C=c.get(`refs/tags/${E}`);if(typeof C>\"u\")throw new Error(`Unknown tag (\"${E}\")`);return HC.default.stringify({...n,commit:C})}case\"semver\":{let C=Fr.validRange(E);if(!C)throw new Error(`Invalid range (\"${E}\")`);let S=new Map([...c.entries()].filter(([I])=>I.startsWith(\"refs/tags/\")).map(([I,T])=>[s5.default.parse(I.slice(10)),T]).filter(I=>I[0]!==null)),b=s5.default.maxSatisfying([...S.keys()],C);if(b===null)throw new Error(`No matching range (\"${E}\")`);return HC.default.stringify({...n,commit:S.get(b)})}case null:{let C;if((C=p(\"commit\",E))!==null||(C=p(\"tag\",E))!==null||(C=p(\"head\",E))!==null)return C;throw E.match(/^[a-f0-9]+$/)?new Error(`Couldn't resolve \"${E}\" as either a commit, a tag, or a head - if a commit, use the 40-characters commit hash`):new Error(`Couldn't resolve \"${E}\" as either a commit, a tag, or a head`)}default:throw new Error(`Invalid Git resolution protocol (\"${h}\")`)}},p=(h,E)=>{try{return f(h,E)}catch{return null}};return _C(`${r}#${f(s,a)}`)}async function c5(t,e){return await e.getLimit(\"cloneConcurrency\")(async()=>{let{repo:r,treeish:{protocol:s,request:a}}=W0(t);if(s!==\"commit\")throw new Error(\"Invalid treeish protocol when cloning\");let n=a5(r,{configuration:e}),c=await ce.mktempPromise(),f={cwd:c,env:Hye()};return await o5(\"cloning the repository\",[\"clone\",\"-c core.autocrlf=false\",n,fe.fromPortablePath(c)],f,{configuration:e,normalizedRepoUrl:n}),await o5(\"switching branch\",[\"checkout\",`${a}`],f,{configuration:e,normalizedRepoUrl:n}),c})}async function Gye(t){let e,r=t;do{if(e=r,await ce.existsPromise(J.join(e,\".git\")))return e;r=J.dirname(e)}while(r!==e);return null}async function qye(t,{baseRefs:e}){if(e.length===0)throw new nt(\"Can't run this command with zero base refs specified.\");let r=[];for(let f of e){let{code:p}=await qr.execvp(\"git\",[\"merge-base\",f,\"HEAD\"],{cwd:t});p===0&&r.push(f)}if(r.length===0)throw new nt(`No ancestor could be found between any of HEAD and ${e.join(\", \")}`);let{stdout:s}=await qr.execvp(\"git\",[\"merge-base\",\"HEAD\",...r],{cwd:t,strict:!0}),a=s.trim(),{stdout:n}=await qr.execvp(\"git\",[\"show\",\"--quiet\",\"--pretty=format:%s\",a],{cwd:t,strict:!0}),c=n.trim();return{hash:a,title:c}}async function Wye(t,{base:e,project:r}){let s=je.buildIgnorePattern(r.configuration.get(\"changesetIgnorePatterns\")),{stdout:a}=await qr.execvp(\"git\",[\"diff\",\"--name-only\",`${e}`],{cwd:t,strict:!0}),n=a.split(/\\r\\n|\\r|\\n/).filter(h=>h.length>0).map(h=>J.resolve(t,fe.toPortablePath(h))),{stdout:c}=await qr.execvp(\"git\",[\"ls-files\",\"--others\",\"--exclude-standard\"],{cwd:t,strict:!0}),f=c.split(/\\r\\n|\\r|\\n/).filter(h=>h.length>0).map(h=>J.resolve(t,fe.toPortablePath(h))),p=[...new Set([...n,...f].sort())];return s?p.filter(h=>!J.relative(r.cwd,h).match(s)):p}async function vct({ref:t,project:e}){if(e.configuration.projectCwd===null)throw new nt(\"This command can only be run from within a Yarn project\");let r=[J.resolve(e.cwd,Er.lockfile),J.resolve(e.cwd,e.configuration.get(\"cacheFolder\")),J.resolve(e.cwd,e.configuration.get(\"installStatePath\")),J.resolve(e.cwd,e.configuration.get(\"virtualFolder\"))];await e.configuration.triggerHook(c=>c.populateYarnPaths,e,c=>{c!=null&&r.push(c)});let s=await Gye(e.configuration.projectCwd);if(s==null)throw new nt(\"This command can only be run on Git repositories\");let a=await qye(s,{baseRefs:typeof t==\"string\"?[t]:e.configuration.get(\"changesetBaseRefs\")}),n=await Wye(s,{base:a.hash,project:e});return new Set(je.mapAndFilter(n,c=>{let f=e.tryWorkspaceByFilePath(c);return f===null?je.mapAndFilter.skip:r.some(p=>c.startsWith(p))?je.mapAndFilter.skip:f}))}async function o5(t,e,r,{configuration:s,normalizedRepoUrl:a}){try{return await qr.execvp(\"git\",e,{...r,strict:!0})}catch(n){if(!(n instanceof qr.ExecError))throw n;let c=n.reportExtra,f=n.stderr.toString();throw new jt(1,`Failed ${t}`,p=>{p.reportError(1,`  ${he.prettyField(s,{label:\"Repository URL\",value:he.tuple(he.Type.URL,a)})}`);for(let h of f.matchAll(/^(.+?): (.*)$/gm)){let[,E,C]=h;E=E.toLowerCase();let S=E===\"error\"?\"Error\":`${PB(E)} Error`;p.reportError(1,`  ${he.prettyField(s,{label:S,value:he.tuple(he.Type.NO_HINT,C)})}`)}c?.(p)})}}var tS=class{supports(e,r){return jC(e.reference)}getLocalPath(e,r){return null}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,a=new Map(r.checksums);a.set(e.locatorHash,s);let n={...r,checksums:a},c=await this.downloadHosted(e,n);if(c!==null)return c;let[f,p,h]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${G.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote repository`),loader:()=>this.cloneFromRemote(e,n),...r.cacheOptions});return{packageFs:f,releaseFs:p,prefixPath:G.getIdentVendorPath(e),checksum:h}}async downloadHosted(e,r){return r.project.configuration.reduceHook(s=>s.fetchHostedRepository,null,e,r)}async cloneFromRemote(e,r){let s=W0(e.reference),a=await c5(e.reference,r.project.configuration),n=J.resolve(a,s.extra.cwd??vt.dot),c=J.join(n,\"package.tgz\");await In.prepareExternalProject(n,c,{configuration:r.project.configuration,report:r.report,workspace:s.extra.workspace,locator:e});let f=await ce.readFilePromise(c);return await je.releaseAfterUseAsync(async()=>await ps.convertToZip(f,{configuration:r.project.configuration,prefixPath:G.getIdentVendorPath(e),stripComponents:1}))}};Ge();Ge();var rS=class{supportsDescriptor(e,r){return jC(e.range)}supportsLocator(e,r){return jC(e.reference)}shouldPersistResolution(e,r){return!0}bindDescriptor(e,r,s){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){let a=await l5(e.range,s.project.configuration);return[G.makeLocator(e,a)]}async getSatisfying(e,r,s,a){let n=W0(e.range);return{locators:s.filter(f=>{if(f.identHash!==e.identHash)return!1;let p=W0(f.reference);return!(n.repo!==p.repo||n.treeish.protocol===\"commit\"&&n.treeish.request!==p.treeish.request)}),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let s=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Ut.find(s.prefixPath,{baseFs:s.packageFs}),s.releaseFs);return{...e,version:a.version||\"0.0.0\",languageName:a.languageName||r.project.configuration.get(\"defaultLanguageName\"),linkType:\"HARD\",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var Sct={configuration:{changesetBaseRefs:{description:\"The base git refs that the current HEAD is compared against when detecting changes. Supports git branches, tags, and commits.\",type:\"STRING\",isArray:!0,isNullable:!1,default:[\"master\",\"origin/master\",\"upstream/master\",\"main\",\"origin/main\",\"upstream/main\"]},changesetIgnorePatterns:{description:\"Array of glob patterns; files matching them will be ignored when fetching the changed files\",type:\"STRING\",default:[],isArray:!0},cloneConcurrency:{description:\"Maximal number of concurrent clones\",type:\"NUMBER\",default:2}},fetchers:[tS],resolvers:[rS]};var Dct=Sct;Yt();var GC=class extends ft{constructor(){super(...arguments);this.since=ge.String(\"--since\",{description:\"Only include workspaces that have been changed since the specified ref.\",tolerateBoolean:!0});this.recursive=ge.Boolean(\"-R,--recursive\",!1,{description:\"Find packages via dependencies/devDependencies instead of using the workspaces field\"});this.noPrivate=ge.Boolean(\"--no-private\",{description:\"Exclude workspaces that have the private field set to true\"});this.verbose=ge.Boolean(\"-v,--verbose\",!1,{description:\"Also return the cross-dependencies between workspaces\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}static{this.paths=[[\"workspaces\",\"list\"]]}static{this.usage=ot.Usage({category:\"Workspace-related commands\",description:\"list all available workspaces\",details:\"\\n      This command will print the list of all workspaces in the project.\\n\\n      - If `--since` is set, Yarn will only list workspaces that have been modified since the specified ref. By default Yarn will use the refs specified by the `changesetBaseRefs` configuration option.\\n\\n      - If `-R,--recursive` is set, Yarn will find workspaces to run the command on by recursively evaluating `dependencies` and `devDependencies` fields, instead of looking at the `workspaces` fields.\\n\\n      - If `--no-private` is set, Yarn will not list any workspaces that have the `private` field set to `true`.\\n\\n      - If both the `-v,--verbose` and `--json` options are set, Yarn will also return the cross-dependencies between each workspaces (useful when you wish to automatically generate Buck / Bazel rules).\\n    \"})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Rt.find(r,this.context.cwd);return(await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout},async n=>{let c=this.since?await ka.fetchChangedWorkspaces({ref:this.since,project:s}):s.workspaces,f=new Set(c);if(this.recursive)for(let p of[...c].map(h=>h.getRecursiveWorkspaceDependents()))for(let h of p)f.add(h);for(let p of f){let{manifest:h}=p;if(h.private&&this.noPrivate)continue;let E;if(this.verbose){let C=new Set,S=new Set;for(let b of Ut.hardDependencies)for(let[I,T]of h.getForScope(b)){let N=s.tryWorkspaceByDescriptor(T);N===null?s.workspacesByIdent.has(I)&&S.add(T):C.add(N)}E={workspaceDependencies:Array.from(C).map(b=>b.relativeCwd),mismatchedWorkspaceDependencies:Array.from(S).map(b=>G.stringifyDescriptor(b))}}n.reportInfo(null,`${p.relativeCwd}`),n.reportJson({location:p.relativeCwd,name:h.name?G.stringifyIdent(h.name):null,...E})}})).exitCode()}};Ge();Ge();Yt();var qC=class extends ft{constructor(){super(...arguments);this.workspaceName=ge.String();this.commandName=ge.String();this.args=ge.Proxy()}static{this.paths=[[\"workspace\"]]}static{this.usage=ot.Usage({category:\"Workspace-related commands\",description:\"run a command within the specified workspace\",details:`\n      This command will run a given sub-command on a single workspace.\n    `,examples:[[\"Add a package to a single workspace\",\"yarn workspace components add -D react\"],[\"Run build script on a single workspace\",\"yarn workspace components run build\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);let n=s.workspaces,c=new Map(n.map(p=>[G.stringifyIdent(p.anchoredLocator),p])),f=c.get(this.workspaceName);if(f===void 0){let p=Array.from(c.keys()).sort();throw new nt(`Workspace '${this.workspaceName}' not found. Did you mean any of the following:\n  - ${p.join(`\n  - `)}?`)}return this.cli.run([this.commandName,...this.args],{cwd:f.cwd})}};var Pct={configuration:{enableImmutableInstalls:{description:\"If true (the default on CI), prevents the install command from modifying the lockfile\",type:\"BOOLEAN\",default:Yye.isCI},defaultSemverRangePrefix:{description:\"The default save prefix: '^', '~' or ''\",type:\"STRING\",values:[\"^\",\"~\",\"\"],default:\"^\"},preferReuse:{description:\"If true, `yarn add` will attempt to reuse the most common dependency range in other workspaces.\",type:\"BOOLEAN\",default:!1}},commands:[aC,lC,cC,uC,OC,PC,EC,GC,pC,hC,gC,dC,sC,oC,fC,AC,mC,yC,IC,CC,wC,BC,LC,vC,SC,xC,bC,kC,DC,QC,RC,TC,FC,NC,MC,UC,qC]},bct=Pct;var d5={};Vt(d5,{default:()=>kct});Ge();var Qt={optional:!0},A5=[[\"@tailwindcss/aspect-ratio@<0.2.1\",{peerDependencies:{tailwindcss:\"^2.0.2\"}}],[\"@tailwindcss/line-clamp@<0.2.1\",{peerDependencies:{tailwindcss:\"^2.0.2\"}}],[\"@fullhuman/postcss-purgecss@3.1.3 || 3.1.3-alpha.0\",{peerDependencies:{postcss:\"^8.0.0\"}}],[\"@samverschueren/stream-to-observable@<0.3.1\",{peerDependenciesMeta:{rxjs:Qt,zenObservable:Qt}}],[\"any-observable@<0.5.1\",{peerDependenciesMeta:{rxjs:Qt,zenObservable:Qt}}],[\"@pm2/agent@<1.0.4\",{dependencies:{debug:\"*\"}}],[\"debug@<4.2.0\",{peerDependenciesMeta:{\"supports-color\":Qt}}],[\"got@<11\",{dependencies:{\"@types/responselike\":\"^1.0.0\",\"@types/keyv\":\"^3.1.1\"}}],[\"cacheable-lookup@<4.1.2\",{dependencies:{\"@types/keyv\":\"^3.1.1\"}}],[\"http-link-dataloader@*\",{peerDependencies:{graphql:\"^0.13.1 || ^14.0.0\"}}],[\"typescript-language-server@*\",{dependencies:{\"vscode-jsonrpc\":\"^5.0.1\",\"vscode-languageserver-protocol\":\"^3.15.0\"}}],[\"postcss-syntax@*\",{peerDependenciesMeta:{\"postcss-html\":Qt,\"postcss-jsx\":Qt,\"postcss-less\":Qt,\"postcss-markdown\":Qt,\"postcss-scss\":Qt}}],[\"jss-plugin-rule-value-function@<=10.1.1\",{dependencies:{\"tiny-warning\":\"^1.0.2\"}}],[\"ink-select-input@<4.1.0\",{peerDependencies:{react:\"^16.8.2\"}}],[\"license-webpack-plugin@<2.3.18\",{peerDependenciesMeta:{webpack:Qt}}],[\"snowpack@>=3.3.0\",{dependencies:{\"node-gyp\":\"^7.1.0\"}}],[\"promise-inflight@*\",{peerDependenciesMeta:{bluebird:Qt}}],[\"reactcss@*\",{peerDependencies:{react:\"*\"}}],[\"react-color@<=2.19.0\",{peerDependencies:{react:\"*\"}}],[\"gatsby-plugin-i18n@*\",{dependencies:{ramda:\"^0.24.1\"}}],[\"useragent@^2.0.0\",{dependencies:{request:\"^2.88.0\",yamlparser:\"0.0.x\",semver:\"5.5.x\"}}],[\"@apollographql/apollo-tools@<=0.5.2\",{peerDependencies:{graphql:\"^14.2.1 || ^15.0.0\"}}],[\"material-table@^2.0.0\",{dependencies:{\"@babel/runtime\":\"^7.11.2\"}}],[\"@babel/parser@*\",{dependencies:{\"@babel/types\":\"^7.8.3\"}}],[\"fork-ts-checker-webpack-plugin@<=6.3.4\",{peerDependencies:{eslint:\">= 6\",typescript:\">= 2.7\",webpack:\">= 4\",\"vue-template-compiler\":\"*\"},peerDependenciesMeta:{eslint:Qt,\"vue-template-compiler\":Qt}}],[\"rc-animate@<=3.1.1\",{peerDependencies:{react:\">=16.9.0\",\"react-dom\":\">=16.9.0\"}}],[\"react-bootstrap-table2-paginator@*\",{dependencies:{classnames:\"^2.2.6\"}}],[\"react-draggable@<=4.4.3\",{peerDependencies:{react:\">= 16.3.0\",\"react-dom\":\">= 16.3.0\"}}],[\"apollo-upload-client@<14\",{peerDependencies:{graphql:\"14 - 15\"}}],[\"react-instantsearch-core@<=6.7.0\",{peerDependencies:{algoliasearch:\">= 3.1 < 5\"}}],[\"react-instantsearch-dom@<=6.7.0\",{dependencies:{\"react-fast-compare\":\"^3.0.0\"}}],[\"ws@<7.2.1\",{peerDependencies:{bufferutil:\"^4.0.1\",\"utf-8-validate\":\"^5.0.2\"},peerDependenciesMeta:{bufferutil:Qt,\"utf-8-validate\":Qt}}],[\"react-portal@<4.2.2\",{peerDependencies:{\"react-dom\":\"^15.0.0-0 || ^16.0.0-0 || ^17.0.0-0\"}}],[\"react-scripts@<=4.0.1\",{peerDependencies:{react:\"*\"}}],[\"testcafe@<=1.10.1\",{dependencies:{\"@babel/plugin-transform-for-of\":\"^7.12.1\",\"@babel/runtime\":\"^7.12.5\"}}],[\"testcafe-legacy-api@<=4.2.0\",{dependencies:{\"testcafe-hammerhead\":\"^17.0.1\",\"read-file-relative\":\"^1.2.0\"}}],[\"@google-cloud/firestore@<=4.9.3\",{dependencies:{protobufjs:\"^6.8.6\"}}],[\"gatsby-source-apiserver@*\",{dependencies:{\"babel-polyfill\":\"^6.26.0\"}}],[\"@webpack-cli/package-utils@<=1.0.1-alpha.4\",{dependencies:{\"cross-spawn\":\"^7.0.3\"}}],[\"gatsby-remark-prismjs@<3.3.28\",{dependencies:{lodash:\"^4\"}}],[\"gatsby-plugin-favicon@*\",{peerDependencies:{webpack:\"*\"}}],[\"gatsby-plugin-sharp@<=4.6.0-next.3\",{dependencies:{debug:\"^4.3.1\"}}],[\"gatsby-react-router-scroll@<=5.6.0-next.0\",{dependencies:{\"prop-types\":\"^15.7.2\"}}],[\"@rebass/forms@*\",{dependencies:{\"@styled-system/should-forward-prop\":\"^5.0.0\"},peerDependencies:{react:\"^16.8.6\"}}],[\"rebass@*\",{peerDependencies:{react:\"^16.8.6\"}}],[\"@ant-design/react-slick@<=0.28.3\",{peerDependencies:{react:\">=16.0.0\"}}],[\"mqtt@<4.2.7\",{dependencies:{duplexify:\"^4.1.1\"}}],[\"vue-cli-plugin-vuetify@<=2.0.3\",{dependencies:{semver:\"^6.3.0\"},peerDependenciesMeta:{\"sass-loader\":Qt,\"vuetify-loader\":Qt}}],[\"vue-cli-plugin-vuetify@<=2.0.4\",{dependencies:{\"null-loader\":\"^3.0.0\"}}],[\"vue-cli-plugin-vuetify@>=2.4.3\",{peerDependencies:{vue:\"*\"}}],[\"@vuetify/cli-plugin-utils@<=0.0.4\",{dependencies:{semver:\"^6.3.0\"},peerDependenciesMeta:{\"sass-loader\":Qt}}],[\"@vue/cli-plugin-typescript@<=5.0.0-alpha.0\",{dependencies:{\"babel-loader\":\"^8.1.0\"}}],[\"@vue/cli-plugin-typescript@<=5.0.0-beta.0\",{dependencies:{\"@babel/core\":\"^7.12.16\"},peerDependencies:{\"vue-template-compiler\":\"^2.0.0\"},peerDependenciesMeta:{\"vue-template-compiler\":Qt}}],[\"cordova-ios@<=6.3.0\",{dependencies:{underscore:\"^1.9.2\"}}],[\"cordova-lib@<=10.0.1\",{dependencies:{underscore:\"^1.9.2\"}}],[\"git-node-fs@*\",{peerDependencies:{\"js-git\":\"^0.7.8\"},peerDependenciesMeta:{\"js-git\":Qt}}],[\"consolidate@<0.16.0\",{peerDependencies:{mustache:\"^3.0.0\"},peerDependenciesMeta:{mustache:Qt}}],[\"consolidate@<=0.16.0\",{peerDependencies:{velocityjs:\"^2.0.1\",tinyliquid:\"^0.2.34\",\"liquid-node\":\"^3.0.1\",jade:\"^1.11.0\",\"then-jade\":\"*\",dust:\"^0.3.0\",\"dustjs-helpers\":\"^1.7.4\",\"dustjs-linkedin\":\"^2.7.5\",swig:\"^1.4.2\",\"swig-templates\":\"^2.0.3\",\"razor-tmpl\":\"^1.3.1\",atpl:\">=0.7.6\",liquor:\"^0.0.5\",twig:\"^1.15.2\",ejs:\"^3.1.5\",eco:\"^1.1.0-rc-3\",jazz:\"^0.0.18\",jqtpl:\"~1.1.0\",hamljs:\"^0.6.2\",hamlet:\"^0.3.3\",whiskers:\"^0.4.0\",\"haml-coffee\":\"^1.14.1\",\"hogan.js\":\"^3.0.2\",templayed:\">=0.2.3\",handlebars:\"^4.7.6\",underscore:\"^1.11.0\",lodash:\"^4.17.20\",pug:\"^3.0.0\",\"then-pug\":\"*\",qejs:\"^3.0.5\",walrus:\"^0.10.1\",mustache:\"^4.0.1\",just:\"^0.1.8\",ect:\"^0.5.9\",mote:\"^0.2.0\",toffee:\"^0.3.6\",dot:\"^1.1.3\",\"bracket-template\":\"^1.1.5\",ractive:\"^1.3.12\",nunjucks:\"^3.2.2\",htmling:\"^0.0.8\",\"babel-core\":\"^6.26.3\",plates:\"~0.4.11\",\"react-dom\":\"^16.13.1\",react:\"^16.13.1\",\"arc-templates\":\"^0.5.3\",vash:\"^0.13.0\",slm:\"^2.0.0\",marko:\"^3.14.4\",teacup:\"^2.0.0\",\"coffee-script\":\"^1.12.7\",squirrelly:\"^5.1.0\",twing:\"^5.0.2\"},peerDependenciesMeta:{velocityjs:Qt,tinyliquid:Qt,\"liquid-node\":Qt,jade:Qt,\"then-jade\":Qt,dust:Qt,\"dustjs-helpers\":Qt,\"dustjs-linkedin\":Qt,swig:Qt,\"swig-templates\":Qt,\"razor-tmpl\":Qt,atpl:Qt,liquor:Qt,twig:Qt,ejs:Qt,eco:Qt,jazz:Qt,jqtpl:Qt,hamljs:Qt,hamlet:Qt,whiskers:Qt,\"haml-coffee\":Qt,\"hogan.js\":Qt,templayed:Qt,handlebars:Qt,underscore:Qt,lodash:Qt,pug:Qt,\"then-pug\":Qt,qejs:Qt,walrus:Qt,mustache:Qt,just:Qt,ect:Qt,mote:Qt,toffee:Qt,dot:Qt,\"bracket-template\":Qt,ractive:Qt,nunjucks:Qt,htmling:Qt,\"babel-core\":Qt,plates:Qt,\"react-dom\":Qt,react:Qt,\"arc-templates\":Qt,vash:Qt,slm:Qt,marko:Qt,teacup:Qt,\"coffee-script\":Qt,squirrelly:Qt,twing:Qt}}],[\"vue-loader@<=16.3.3\",{peerDependencies:{\"@vue/compiler-sfc\":\"^3.0.8\",webpack:\"^4.1.0 || ^5.0.0-0\"},peerDependenciesMeta:{\"@vue/compiler-sfc\":Qt}}],[\"vue-loader@^16.7.0\",{peerDependencies:{\"@vue/compiler-sfc\":\"^3.0.8\",vue:\"^3.2.13\"},peerDependenciesMeta:{\"@vue/compiler-sfc\":Qt,vue:Qt}}],[\"scss-parser@<=1.0.5\",{dependencies:{lodash:\"^4.17.21\"}}],[\"query-ast@<1.0.5\",{dependencies:{lodash:\"^4.17.21\"}}],[\"redux-thunk@<=2.3.0\",{peerDependencies:{redux:\"^4.0.0\"}}],[\"skypack@<=0.3.2\",{dependencies:{tar:\"^6.1.0\"}}],[\"@npmcli/metavuln-calculator@<2.0.0\",{dependencies:{\"json-parse-even-better-errors\":\"^2.3.1\"}}],[\"bin-links@<2.3.0\",{dependencies:{\"mkdirp-infer-owner\":\"^1.0.2\"}}],[\"rollup-plugin-polyfill-node@<=0.8.0\",{peerDependencies:{rollup:\"^1.20.0 || ^2.0.0\"}}],[\"snowpack@<3.8.6\",{dependencies:{\"magic-string\":\"^0.25.7\"}}],[\"elm-webpack-loader@*\",{dependencies:{temp:\"^0.9.4\"}}],[\"winston-transport@<=4.4.0\",{dependencies:{logform:\"^2.2.0\"}}],[\"jest-vue-preprocessor@*\",{dependencies:{\"@babel/core\":\"7.8.7\",\"@babel/template\":\"7.8.6\"},peerDependencies:{pug:\"^2.0.4\"},peerDependenciesMeta:{pug:Qt}}],[\"redux-persist@*\",{peerDependencies:{react:\">=16\"},peerDependenciesMeta:{react:Qt}}],[\"sodium@>=3\",{dependencies:{\"node-gyp\":\"^3.8.0\"}}],[\"babel-plugin-graphql-tag@<=3.1.0\",{peerDependencies:{graphql:\"^14.0.0 || ^15.0.0\"}}],[\"@playwright/test@<=1.14.1\",{dependencies:{\"jest-matcher-utils\":\"^26.4.2\"}}],...[\"babel-plugin-remove-graphql-queries@<3.14.0-next.1\",\"babel-preset-gatsby-package@<1.14.0-next.1\",\"create-gatsby@<1.14.0-next.1\",\"gatsby-admin@<0.24.0-next.1\",\"gatsby-cli@<3.14.0-next.1\",\"gatsby-core-utils@<2.14.0-next.1\",\"gatsby-design-tokens@<3.14.0-next.1\",\"gatsby-legacy-polyfills@<1.14.0-next.1\",\"gatsby-plugin-benchmark-reporting@<1.14.0-next.1\",\"gatsby-plugin-graphql-config@<0.23.0-next.1\",\"gatsby-plugin-image@<1.14.0-next.1\",\"gatsby-plugin-mdx@<2.14.0-next.1\",\"gatsby-plugin-netlify-cms@<5.14.0-next.1\",\"gatsby-plugin-no-sourcemaps@<3.14.0-next.1\",\"gatsby-plugin-page-creator@<3.14.0-next.1\",\"gatsby-plugin-preact@<5.14.0-next.1\",\"gatsby-plugin-preload-fonts@<2.14.0-next.1\",\"gatsby-plugin-schema-snapshot@<2.14.0-next.1\",\"gatsby-plugin-styletron@<6.14.0-next.1\",\"gatsby-plugin-subfont@<3.14.0-next.1\",\"gatsby-plugin-utils@<1.14.0-next.1\",\"gatsby-recipes@<0.25.0-next.1\",\"gatsby-source-shopify@<5.6.0-next.1\",\"gatsby-source-wikipedia@<3.14.0-next.1\",\"gatsby-transformer-screenshot@<3.14.0-next.1\",\"gatsby-worker@<0.5.0-next.1\"].map(t=>[t,{dependencies:{\"@babel/runtime\":\"^7.14.8\"}}]),[\"gatsby-core-utils@<2.14.0-next.1\",{dependencies:{got:\"8.3.2\"}}],[\"gatsby-plugin-gatsby-cloud@<=3.1.0-next.0\",{dependencies:{\"gatsby-core-utils\":\"^2.13.0-next.0\"}}],[\"gatsby-plugin-gatsby-cloud@<=3.2.0-next.1\",{peerDependencies:{webpack:\"*\"}}],[\"babel-plugin-remove-graphql-queries@<=3.14.0-next.1\",{dependencies:{\"gatsby-core-utils\":\"^2.8.0-next.1\"}}],[\"gatsby-plugin-netlify@3.13.0-next.1\",{dependencies:{\"gatsby-core-utils\":\"^2.13.0-next.0\"}}],[\"clipanion-v3-codemod@<=0.2.0\",{peerDependencies:{jscodeshift:\"^0.11.0\"}}],[\"react-live@*\",{peerDependencies:{\"react-dom\":\"*\",react:\"*\"}}],[\"webpack@<4.44.1\",{peerDependenciesMeta:{\"webpack-cli\":Qt,\"webpack-command\":Qt}}],[\"webpack@<5.0.0-beta.23\",{peerDependenciesMeta:{\"webpack-cli\":Qt}}],[\"webpack-dev-server@<3.10.2\",{peerDependenciesMeta:{\"webpack-cli\":Qt}}],[\"@docusaurus/responsive-loader@<1.5.0\",{peerDependenciesMeta:{sharp:Qt,jimp:Qt}}],[\"eslint-module-utils@*\",{peerDependenciesMeta:{\"eslint-import-resolver-node\":Qt,\"eslint-import-resolver-typescript\":Qt,\"eslint-import-resolver-webpack\":Qt,\"@typescript-eslint/parser\":Qt}}],[\"eslint-plugin-import@*\",{peerDependenciesMeta:{\"@typescript-eslint/parser\":Qt}}],[\"critters-webpack-plugin@<3.0.2\",{peerDependenciesMeta:{\"html-webpack-plugin\":Qt}}],[\"terser@<=5.10.0\",{dependencies:{acorn:\"^8.5.0\"}}],[\"babel-preset-react-app@10.0.x <10.0.2\",{dependencies:{\"@babel/plugin-proposal-private-property-in-object\":\"^7.16.7\"}}],[\"eslint-config-react-app@*\",{peerDependenciesMeta:{typescript:Qt}}],[\"@vue/eslint-config-typescript@<11.0.0\",{peerDependenciesMeta:{typescript:Qt}}],[\"unplugin-vue2-script-setup@<0.9.1\",{peerDependencies:{\"@vue/composition-api\":\"^1.4.3\",\"@vue/runtime-dom\":\"^3.2.26\"}}],[\"@cypress/snapshot@*\",{dependencies:{debug:\"^3.2.7\"}}],[\"auto-relay@<=0.14.0\",{peerDependencies:{\"reflect-metadata\":\"^0.1.13\"}}],[\"vue-template-babel-compiler@<1.2.0\",{peerDependencies:{\"vue-template-compiler\":\"^2.6.0\"}}],[\"@parcel/transformer-image@<2.5.0\",{peerDependencies:{\"@parcel/core\":\"*\"}}],[\"@parcel/transformer-js@<2.5.0\",{peerDependencies:{\"@parcel/core\":\"*\"}}],[\"parcel@*\",{peerDependenciesMeta:{\"@parcel/core\":Qt}}],[\"react-scripts@*\",{peerDependencies:{eslint:\"*\"}}],[\"focus-trap-react@^8.0.0\",{dependencies:{tabbable:\"^5.3.2\"}}],[\"react-rnd@<10.3.7\",{peerDependencies:{react:\">=16.3.0\",\"react-dom\":\">=16.3.0\"}}],[\"connect-mongo@<5.0.0\",{peerDependencies:{\"express-session\":\"^1.17.1\"}}],[\"vue-i18n@<9\",{peerDependencies:{vue:\"^2\"}}],[\"vue-router@<4\",{peerDependencies:{vue:\"^2\"}}],[\"unified@<10\",{dependencies:{\"@types/unist\":\"^2.0.0\"}}],[\"react-github-btn@<=1.3.0\",{peerDependencies:{react:\">=16.3.0\"}}],[\"react-dev-utils@*\",{peerDependencies:{typescript:\">=2.7\",webpack:\">=4\"},peerDependenciesMeta:{typescript:Qt}}],[\"@asyncapi/react-component@<=1.0.0-next.39\",{peerDependencies:{react:\">=16.8.0\",\"react-dom\":\">=16.8.0\"}}],[\"xo@*\",{peerDependencies:{webpack:\">=1.11.0\"},peerDependenciesMeta:{webpack:Qt}}],[\"babel-plugin-remove-graphql-queries@<=4.20.0-next.0\",{dependencies:{\"@babel/types\":\"^7.15.4\"}}],[\"gatsby-plugin-page-creator@<=4.20.0-next.1\",{dependencies:{\"fs-extra\":\"^10.1.0\"}}],[\"gatsby-plugin-utils@<=3.14.0-next.1\",{dependencies:{fastq:\"^1.13.0\"},peerDependencies:{graphql:\"^15.0.0\"}}],[\"gatsby-plugin-mdx@<3.1.0-next.1\",{dependencies:{mkdirp:\"^1.0.4\"}}],[\"gatsby-plugin-mdx@^2\",{peerDependencies:{gatsby:\"^3.0.0-next\"}}],[\"fdir@<=5.2.0\",{peerDependencies:{picomatch:\"2.x\"},peerDependenciesMeta:{picomatch:Qt}}],[\"babel-plugin-transform-typescript-metadata@<=0.3.2\",{peerDependencies:{\"@babel/core\":\"^7\",\"@babel/traverse\":\"^7\"},peerDependenciesMeta:{\"@babel/traverse\":Qt}}],[\"graphql-compose@>=9.0.10\",{peerDependencies:{graphql:\"^14.2.0 || ^15.0.0 || ^16.0.0\"}}],[\"vite-plugin-vuetify@<=1.0.2\",{peerDependencies:{vue:\"^3.0.0\"}}],[\"webpack-plugin-vuetify@<=2.0.1\",{peerDependencies:{vue:\"^3.2.6\"}}],[\"eslint-import-resolver-vite@<2.0.1\",{dependencies:{debug:\"^4.3.4\",resolve:\"^1.22.8\"}}],[\"notistack@^3.0.0\",{dependencies:{csstype:\"^3.0.10\"}}],[\"@fastify/type-provider-typebox@^5.0.0\",{peerDependencies:{fastify:\"^5.0.0\"}}],[\"@fastify/type-provider-typebox@^4.0.0\",{peerDependencies:{fastify:\"^4.0.0\"}}]];var p5;function Vye(){return typeof p5>\"u\"&&(p5=Ie(\"zlib\").brotliDecompressSync(Buffer.from(\"G7weAByFTVk3Vs7UfHhq4yykgEM7pbW7TI43SG2S5tvGrwHBAzdz+s/npQ6tgEvobvxisrPIadkXeUAJotBn5bDZ5kAhcRqsIHe3F75Walet5hNalwgFDtxb0BiDUjiUQkjG0yW2hto9HPgiCkm316d6bC0kST72YN7D7rfkhCE9x4J0XwB0yavalxpUu2t9xszHrmtwalOxT7VslsxWcB1qpqZwERUra4psWhTV8BgwWeizurec82Caf1ABL11YMfbf8FJ9JBceZOkgmvrQPbC9DUldX/yMbmX06UQluCEjSwUoyO+EZPIjofr+/oAZUck2enraRD+oWLlnlYnj8xB+gwSo9lmmks4fXv574qSqcWA6z21uYkzMu3EWj+K23RxeQlLqiE35/rC8GcS4CGkKHKKq+zAIQwD9iRDNfiAqueLLpicFFrNsAI4zeTD/eO9MHcnRa5m8UT+M2+V+AkFST4BlKneiAQRSdST8KEAIyFlULt6wa9EBd0Ds28VmpaxquJdVt+nwdEs5xUskI13OVtFyY0UrQIRAlCuvvWivvlSKQfTO+2Q8OyUR1W5RvetaPz4jD27hdtwHFFA1Ptx6Ee/t2cY2rg2G46M1pNDRf2pWhvpy8pqMnuI3++4OF3+7OFIWXGjh+o7Nr2jNvbiYcQdQS1h903/jVFgOpA0yJ78z+x759bFA0rq+6aY5qPB4FzS3oYoLupDUhD9nDz6F6H7hpnlMf18KNKDu4IKjTWwrAnY6MFQw1W6ymOALHlFyCZmQhldg1MQHaMVVQTVgDC60TfaBqG++Y8PEoFhN/PBTZT175KNP/BlHDYGOOBmnBdzqJKplZ/ljiVG0ZBzfqeBRrrUkn6rA54462SgiliKoYVnbeptMdXNfAuaupIEi0bApF10TlgHfmEJAPUVidRVFyDupSem5po5vErPqWKhKbUIp0LozpYsIKK57dM/HKr+nguF+7924IIWMICkQ8JUigs9D+W+c4LnNoRtPPKNRUiCYmP+Jfo2lfKCKw8qpraEeWU3uiNRO6zcyKQoXPR5htmzzLznke7b4YbXW3I1lIRzmgG02Udb58U+7TpwyN7XymCgH+wuPDthZVQvRZuEP+SnLtMicz9m5zASWOBiAcLmkuFlTKuHspSIhCBD0yUPKcxu81A+4YD78rA2vtwsUEday9WNyrShyrl60rWmA+SmbYZkQOwFJWArxRYYc5jGhA5ikxYw1rx3ei4NmeX/lKiwpZ9Ln1tV2Ae7sArvxuVLbJjqJRjW1vFXAyHpvLG+8MJ6T2Ubx5M2KDa2SN6vuIGxJ9WQM9Mk3Q7aCNiZONXllhqq24DmoLbQfW2rYWsOgHWjtOmIQMyMKdiHZDjoyIq5+U700nZ6odJAoYXPQBvFNiQ78d5jaXliBqLTJEqUCwi+LiH2mx92EmNKDsJL74Z613+3lf20pxkV1+erOrjj8pW00vsPaahKUM+05ssd5uwM7K482KWEf3TCwlg/o3e5ngto7qSMz7YteIgCsF1UOcsLk7F7MxWbvrPMY473ew0G+noVL8EPbkmEMftMSeL6HFub/zy+2JQ==\",\"base64\")).toString()),p5}var h5;function Jye(){return typeof h5>\"u\"&&(h5=Ie(\"zlib\").brotliDecompressSync(Buffer.from(\"G8MSIIzURnVBnObTcvb3XE6v2S9Qgc2K801Oa5otNKEtK8BINZNcaQHy+9/vf/WXBimwutXC33P2DPc64pps5rz7NGGWaOKNSPL4Y2KRE8twut2lFOIN+OXPtRmPMRhMTILib2bEQx43az2I5d3YS8Roa5UZpF/ujHb3Djd3GDvYUfvFYSUQ39vb2cmifp/rgB4J/65JK3wRBTvMBoNBmn3mbXC63/gbBkW/2IRPri0O8bcsRBsmarF328pAln04nyJFkwUAvNu934supAqLtyerZZpJ8I8suJHhf/ocMV+scKwa8NOiDKIPXw6Ex/EEZD6TEGaW8N5zvNHYF10l6Lfooj7D5W2k3dgvQSbp2Wv8TGOayS978gxlOLVjTGXs66ozewbrjwElLtyrYNnWTfzzdEutgROUFPVMhnMoy8EjJLLlWwIEoySxliim9kYW30JUHiPVyjt0iAw/ZpPmCbUCltYPnq6ZNblIKhTNhqS/oqC9iya5sGKZTOVsTEg34n92uZTf2iPpcZih8rPW8CzA+adIGmyCPcKdLMsBLShd+zuEbTrqpwuh+DLmracZcjPC5Sdf5odDAhKpFuOsQS67RT+1VgWWygSv3YwxDnylc04/PYuaMeIzhBkLrvs7e/OUzRTF56MmfY6rI63QtEjEQzq637zQqJ39nNhu3NmoRRhW/086bHGBUtx0PE0j3aEGvkdh9WJC8y8j8mqqke9/dQ5la+Q3ba4RlhvTbnfQhPDDab3tUifkjKuOsp13mXEmO00Mu88F/M67R7LXfoFDFLNtgCSWjWX+3Jn1371pJTK9xPBiMJafvDjtFyAzu8rxeQ0TKMQXNPs5xxiBOd+BRJP8KP88XPtJIbZKh/cdW8KvBUkpqKpGoiIaA32c3/JnQr4efXt85mXvidOvn/eU3Pase1typLYBalJ14mCso9h79nuMOuCa/kZAOkJHmTjP5RM2WNoPasZUAnT1TAE/NH25hUxcQv6hQWR/m1PKk4ooXMcM4SR1iYU3fUohvqk4RY2hbmTVVIXv6TvqO+0doOjgeVFAcom+RlwJQmOVH7pr1Q9LoJT6n1DeQEB+NHygsATbIwTcOKZlJsY8G4+suX1uQLjUWwLjjs0mvSvZcLTpIGAekeR7GCgl8eo3ndAqEe2XCav4huliHjdbIPBsGJuPX7lrO9HX1UbXRH5opOe1x6JsOSgHZR+EaxuXVhpLLxm6jk1LJtZfHSc6BKPun3CpYYVMJGwEUyk8MTGG0XL5MfEwaXpnc9TKnBmlGn6nHiGREc3ysn47XIBDzA+YvFdjZzVIEDcKGpS6PbUJehFRjEne8D0lVU1XuRtlgszq6pTNlQ/3MzNOEgCWPyTct22V2mEi2krizn5VDo9B19/X2DB3hCGRMM7ONbtnAcIx/OWB1u5uPbW1gsH8irXxT/IzG0PoXWYjhbMsH3KTuoOl5o17PulcgvsfTSnKFM354GWI8luqZnrswWjiXy3G+Vbyo1KMopFmmvBwNELgaS8z8dNZchx/Cl/xjddxhMcyqtzFyONb2Zdu90NkI8pAeufe7YlXrp53v8Dj/l8vWeVspRKBGXScBBPI/HinSTGmLDOGGOCIyH0JFdOZx0gWsacNlQLJMIrBhqRxXxHF/5pseWwejlAAvZ3klZSDSYY8mkToaWejXhgNomeGtx1DTLEUFMRkgF5yFB22WYdJnaWN14r1YJj81hGi45+jrADS5nYRhCiSlCJJ1nL8pYX+HDSMhdTEWyRcgHVp/IsUIZYMfT+YYncUQPgcxNGCHfZ88vDdrcUuaGIl6zhAsiaq7R5dfqrqXH/JcBhfjT8D0azayIyEz75Nxp6YkcyDxlJq3EXnJUpqDohJJOysL1t1uNiHESlvsxPb5cpbW0+ICZqJmUZus1BMW0F5IVBODLIo2zHHjA0=\",\"base64\")).toString()),h5}var g5;function Kye(){return typeof g5>\"u\"&&(g5=Ie(\"zlib\").brotliDecompressSync(Buffer.from(\"m9XmPqMRsZ7bFo1U5CxexdgYepcdMsrcAbbqv7/rCXGM7SZhmJ2jPScITf1tA+qxuDFE8KC9mQaCs84ftss/pB0UrlDfSS52Q7rXyYIcHbrGG2egYMqC8FFfnNfZVLU+4ZieJEVLu1qxY0MYkbD8opX7TYstjKzqxwBObq8HUIQwogljOgs72xyCrxj0q79cf/hN2Ys/0fU6gkRgxFedikACuQLS4lvO/N5NpZ85m+BdO3c5VplDLMcfEDt6umRCbfM16uxnqUKPvPFg/qtuzzId3SjAxZFoZRqK3pdtWt/C+VU6+zuX09NsoBs3MwobpU1yyoXZnzA1EmiMRS5GfJeLxV51/jSXrfgTWr1af9hwKvqCfSVHiQuk+uO/N16Cror2c1QlthM7WkS/86azhK3b47PG6f5TAJVtrK7g+zlR2boyKBV+QkdOXcfBDrI8yCciS3LktLb+d3gopE3R1QYFN1QWdQtrso2qK3+OTVYpTdPAfICTe9//3y/1+6mixIob4kfOI1WT3DxyD2ZuR06a6RPOPlftc/bZeqWqUtoqSetJlgP0AOBsOOeWqkpKJDtgP25CmIz+ZAo8+zwb3wI5ZD/0a7Qb7Q8Ag8HkWzhVQqzLFksA/nKSsR6hEu4tymzAQcZUDV4D2f17NbNSreHMVG0D1Knfa5n//prG6IzFVH7GSdEZn+1eEohVH5hmz6wxnj0biDxnMlq0fHQ2v7ogu8tEBnHaJICmVgLINf+jr4b/AVtDfPSZWelMen+u+pT60nu+9LrK0z0L/oyvC+kDtsi13AdC/i6pd29uB/1alOsA0Kc6N0wICwzbHkBQGJ94pBZ5TyKj7lzzUQ5CYn3Xp/cLhrJ2GpBakWmkymfeKcX2Vy2QEDcIxnju2369rf+l+H7E96GzyVs0gyDzUD0ipfKdmd7LN80sxjSiau/0PX2e7EMt4hNqThHEad9B1L44EDU1ZyFL+QJ0n1v7McxqupfO9zYGEBGJ0XxHdZmWuNKcV+0WJmzGd4y1qu3RfbunEBAQgZyBUWwjoXAwxk2XVRjBAy1jWcGsnb/Tu2oRKUbqGxHjFxUihoreyXW2M2ZnxkQYPfCorcVYq7rnrfuUV1ZYBNakboTPj+b+PLaIyFVsA5nmcP8ZS23WpTvTnSog5wfhixjwbRCqUZs5CmhOL9EgGmgj/26ysZ0jCMvtwDK2F7UktN2QnwoB1S1oLmpPmOrFf/CT8ITb/UkMLLqMjdVY/y/EH/MtrH9VkMaxM7mf8v/TkuD1ov5CqEgw9xvc/+8UXQ/+Idb2isH35w98+skf/i3b72L4ElozP8Dyc9wbdJcY70N/9F9PVz4uSI/nhcrSt21q/fpyf6UbWyso4Ds08/rSPGAcAJs8sBMCYualxyZxlLqfQnp9jYxdy/TQVs6vYmnTgEERAfmtB2No5xf8eqN4yCWgmnR91NQZQ4CmYCqijiU983mMTgUPedf8L8/XiCu9jbsDMIARuL0a0MZlq7lU2nxB8T+N/F7EFutvEuWhxf3XFlS0KcKMiAbpPy3gv/6r+NIQcVkdlqicBgiYOnzr6FjwJVz+QQxpM+uMAIW4F13oWQzNh95KZlI9LOFocgrLUo8g+i+ZNTor6ypk+7O/PlsJ9WsFhRgnLuNv5P2Isk25gqT6i2tMopOL1+RQcnRBuKZ06E8Ri4/BOrY/bQ4GAZPE+LXKsS5jTYjEl5jHNgnm+kjV9trqJ4C9pcDVxTWux8uovsXQUEYh9BP+NR07OqmcjOsakIEI/xofJioScCLW09tzJAVwZwgbQtVnkX3x8H1sI2y8Hs4AiQYfXRNklTmb9mn9RgbJl2yf19aSzCGZqFq79dXW791Na6an1ydMUb/LNp5HdEZkkmTAdP7EPMC563MSh6zxa+Bz5hMDuNq43JYIRJRIWCuNWvM1xTjf8XaHnVPKElBLyFDMJyWiSAElJ0FJVA++8CIBc8ItAWrxhecW+tOoGq4yReF6Dcz615ifhRWLpIOaf8WTs3zUcjEBS1JEXbIByQhm6+oAoTb3QPkok35qz9L2c/mp5WEuCJgerL5QCxMXUWHBJ80t+LevvZ65pBkFa72ITFw4oGQ05TynQJyDjU1AqBylBAdTE9uIflWo0b+xSUCJ9Ty3GlCggfasdT0PX/ue3w16GUfU+QVQddTm9XiY2Bckz2tKt2il7oUIGBRa7Ft5qJfrRIK3mVs9QsDo9higyTz0N9jmILeRhROdecjV44DDZzYnJNryISvfdIq2x4c2/8e2UXrlRm303TE6kxkQ/0kylxgtsQimZ/nb6jUaggIXXN+F2vyIqMGIuJXQR8yzdFIHknqeWFDgsdvcftmkZyWojcZc+ZFY4rua8nU3XuMNchfTDpBbrjMXsJGonJ+vKX0sZbNcoakrr9c9i+bj6uf6f4yNDdaiXLRhJrlh5zmfbkOGQkosfTqWYgpEKdYx2Kxfb+ZDz4Ufteybj63LzVc7oklSvXHh5Nab4+b8DeoXZihVLRZRCBJuj0J6zk3PtbkjaEH3sD3j6hHhwmufk+pBoGYd9qCJEFL21AmLzzHHktN9jW7GSpe1p91X10Bm5/Dhxo3BNex+EtiAFD3dTK0NcvT58F0IFIQIhgLP6s1MX8wofvtnPX1PQ/bLAwNP+ulKiokjXruRYKzTErNjFrvX5n6QD7oiRbOs3OQUswDgOxzcd+WwGZH1ONZJLEKk2T4VGPrrdkN9ncxP/oQ8UFvRbI7zGVrpNjlniCHT6nYmp7SlDcZ1XmS7tm9CXTMumh89LnaNuF3/wPVa/NLSE195Ntstwz1V2ZLc/sULMGaL4gdF3src9sR1Fh33/xiS3qOrJQlLpy2luR0/y+0q0RnVBBBe4yi4ueiNOdNAq/pR8JehYiEiu7YVJJcGBNBHlCOREQviO39dwxTxdulwW+UOO+OrXOskQ/csaLPIKxUOUHktlUtch/SkuaV5QD2G4vweAaCoSxMZ8k9jagIRR/irArsMUBBkvwQBZj1NYclQ1WtdeoYsd38CObL/DJksETohDEy6ZCixViSEPvNKiV1SSCwIiVk0dPGwTZxeNwPoA0BDhYNc4tIkej3DcTHVTS8W1vYFlURRUS4k2naQ5xI0fseTRBHJQ3WJ6Tn45afc9k9VffnLeTH+Kdd9X9Rnont4E39i8pr21YM+umrbIBTB8Ex2jNapeDYMPaeXACP6jpZnFy8NEyG2AF+Ega5vkvKIWjidXnkItArCkmeU63Fx+eg8KiP95JfLbUQus2hJTKPeGTz9b9A0TJtnTVcdJW15L/+3ZIOQ3jeoFsEuB9IGzxFY52ntO1vJvNdPQMJhXkvTNcRYz7Qz6l09rNUNGbfVNOW7tQgzdp42/0sZtnFW0+64nFJ127Niq3QLT8vwHYw3kOplK43u3yllVjU+RYv76vu3JMghXWGsSB0u3ESlir8CjF5ZIflzQoMn0xbP3qWknhPYHTAfu11TcndM/gV+npAK5/yKkwjnzWs5UXGXJHwAFo1FU99jtfiDBlqk9Xmq1YKsy7YkB5nOmw6dy9mjCqYT72Nz9S4+BsTCObdH/e/YZR3MzUt/j/sjQMujqJNOqABq9wAJCDwn/vwSbELgikVGYviA89VqCQjLBkWsMBf7qNjRT3hPXMbT+DM+fsTUEgPlFV5oq2qzdgZ6uAb0yK/szd/zKqTdSC0GlgQ//otU9TAFEtm4moY7QTBAIb2YdPBQAqhW1LevpeqAvf9tku0fT+IfpA8fDsqAOAQxGbPa0YLgAOIZRFlh3WHrFyBDcFLdrSJP+9Ikfv1V16ukcQt9i8sBbU/+m0SAUsjdTq6mtQfoeI7xPWpsP+1vTo73Rz8VnYLmgxaDWgOuNmD8+vxzpyCIC1upRk0+Wd7Z0smljU7G9IdJYlY5vyGTyzRkkN88RMEm9OKFJ4IHwBxzcQtMNeMUwwUATphdaafYwiPK8NptzFLY0dUIAFj2UVoHzUBmmTP1mWCmKvvesqnrG3hj+FHkfjO3nN+MaWXgorgAAA6K9IXTUD1+uwaqHXsEALRgD82K6GVuzjQznaC89QI2B34wNf1dPIwydDO38xCsAKCdf19/ePn1xejxPZgLmzLlTLvloYWMde1luC66/CFwUdwGF5iJ4QIAM5jvbl94r6EYr52H2W12SlcjAHBSzoVjusrp7UZh18Z/J+vwjQccSS/JBNE2b1adygAAyNgJ5P+bqz5+CPu24bqx6Gjcz84IAtVx2VEyBJTqrocOCI9I7r4vD7cz9L3AGZ6DBzEu36w6fQsAkN2IsmzCZWMxqbMTE75ymnyFiK09l327D2K9sywTANigkEkmLwTn4RqDiPxpy5HKA4aeYqbSoi0AUAKsGA5go3ZXjR0qpUsAoMWolyNxzyiIPZ+qsEM7QDgbHW9WJWwBADq5800tDEPPiPa6ialFj0uNAEDJEC4am4A/oPGPxmDmXdikl4cLKa8CgG7265rxY/wjtmbutfwJ6M9Mer8dKHyeZkalbAEA49jkE8MATNz+qKwsMOlGAEC+lkvGJh0ds/j5uNtg3tilTY+NTe/JnqF4N6uSDACAHKQP1Lht8vSzU7iEyzPjut2EPs/Y38IspIepXm+8s+bS2w8QPd+8ONuavlmV3gIAJLA8T+O2x6fBKOJyYweNq/YsVtd2SjETADgxiwkX4POo7fsmuHnc8rCP05hqlnABgBq023MivCisNnZRtK+sru0oXAIAK+fRHim5pkf85kL/YfPLQ/xReQkXAChjtR0XhfDJaiOHaB9ZXctR2AQARsyesDkUv0deoTWmffvT4f6SYAUA6+xXzrX3Smi6X8zthH22b/w19LM0XlWqr0rjAgAWs1Wq4T6AhPsAVGoEAAa5PpwVKjiHWlfJ2TZJf63FjF8SUG6KBOOL9A4PW3qOHE295pQyfVPIvxcJeU+CKduBk6Q+a2BAVtKhf4QnHrHLFpj6sNDUDvhCfNPmtn4pdDSUkHE1wPPrF1UvkQS/L1S52Zv0Sb/r9YK+jx51oWU+i39Owb1p4MDw3LcwvjpMvtDXPEWBlLcw4DNpOOC8f11nKez61/hc4txssbudIo5lL+aszAI1EiiSfkCetqOyBs4trCbou3jqJZ4diL4zvDnDBRgP+086X66Tvj3JOY1rJwmj/sJrubDrVb32PWhOs6BN+sJXQ+6nOZJTgPRg4PWz8sp/wWI3wsGBQoSU6tr0dWOkrwhDNCN5mfGAM5vfnawcoCdm2CdzIN0r72XbbDWqjom1cMjYh229sPnvzWLZAaSiQR3bSL1XjCwFH1wa4ZmmLeiaD4xutxAZfzu0FwMUkXTsvb7SX7TLM4zwjGg+HbjiaRWI92lgwaxTyKgiXbnThL9j7uBDihzuMULvXXes0e9x7PwRK+6mBLGD9z7PAt7b7va1J2EHu/zZfZ6JPoQVd849MZCk3RJOxd5Nsxi+O0lUD4Pochlk5+4naG1j6yiVRKBPobLOad//hDECeD1ORiB9M37JsSxMC6yAkKEdy7S1aRmXRGrLECneqByM8iQ8x6d71F1uhkYUi3WEjh/A9Yw//HCidh7pl7XD8vEkuN/f7XQ3+fhmSfR/9fHkNcRp4qCD13IGIBIAsQXtoDUnASJc+5H5f7YWufNDdZ3SiHJqVvKw8K1RNB/4mJi3YzQP47nmN2cw2BH4yKk+zk7wcLx2bVzeS773YW/7nMg8DMlWZGeYPJ8lYLzOnN4o/0fk9Fb9upq1yXbRyN7iDSRnOnj+kn3vLjHbn3NmA2tRwcfVd/KHGxPybUwcg9e742hY/XBtEgCQYe9Qh8t8fte6aEo1Lt7a9rryutsDxLxo0o9/lhdL/GMs9n3cCxZiuv3as0lchJm9dQGckDBOT/R+y2ft/W/eswB4NFnsqcrBTerQmx0BTPclttiZPF+ctHerFc2RW9MJzpuGOShqyTLCNsCjhPV3EtMF8nVQf2TL6GzI6EphQEjQgG6JrtMu/0zWg2e97o/uoTIf4ipUvVVM0KYey+VkMCWrFynVZh/hpTTXcm3+EV7yX7W6Ehrz8KON4P9MrENJx2msYomlnUT80OrH6Y1+KEfOWn8KyenbZuHQkjBZcDAx5+J64Aj6TSooLJw3anwLeZGOQeSSPXLe6dVY7MF7HhAl2HU9fwES3l2dLETAm5btht91AwjpdUoQghLn7RhAIRWFRVWJa2Jtc0Tm+dHRGiAvx6wG/OCGa7BsWuJ6U3LwfOzSY5qNsj3Qpt6+JyEhflEfl2YZ7jhjJ3y+3ehNh4IBG4eEmVuhYdlx/EQQvnVDqC5Lodj7NWEXjMFyT14tjF768alhticUJrdl3w6P7cKsF4rhxIKWxOSELDHpzaBPR0EgNZlKdZrSiJfPGaWK++nvRxwoo0gt4maZU1CAx33oq3e+NirCq8K514FHpLc0jbti5KzNlr3ttdqoSeYKrOsq+jS0w4q5Z2AMeYnbAgCra8oCHFF0wJ/PTdXUMVyIdTRhS8cJZVr5dTMliVhKm9/TZduaYLTA346l+ILCTo1es+CVq/f+2MU+XuX47AuupenBsoFCNMV/2ywHjCr2flEAWipfnI46tqmjq81ytF7IWoydKyHCSI4ew+k4+ATvUzq2buldaR6SAI4VKAMyMT7zkBkAMB00NLbwmtJqj2k7NAGAqHKufA41DAksWEk7A33esJTuBprShiAOZCMOdd72+E7b1umdzQCSOsdaB3BxZgCAIhUUSdbxYbW7MfnSRjQBAOeidlz5FgodFOhlNAn2jcFu6KmERUygbnHGMpnfdLZ+KTEVgF9WExaIcJy8hr/tp7Y+ofIvp0nKjrUMZqLMAMAsmaCWuxWW9dpVpoxoAgBXKtOVhyhPGCAhWFJty3Ija39F5udrAvbBC+QD+d2Qpx5Dhfh+FqLgzUW10AwAWChUQzuhruPOnJ3rUZXMdgmhZDvzdRCfX1UCN4/l/wPrk1X0qHN3KbpjTKBihdxy04nZgZFKr7EcDqvvSSpivzg7QGxmssgfLo5KZRV1TZtdbR+k3S/kYjTNfDUZyWrcFtxkiVhetaWfvcxumYBgVeSozNkvIgSbt+L/2Cl6TuiPToNFUi3gzvnWRxo0ES1a/Wjq0Zc47dikmBBXXE4/cj/BEnTUGU8vsXsssBsmrEbCzB27QqDQGPdcgFpmIb3VQSk9zfTyXFlADILp0V5qUnuHn2SAu8QszfXheW/UnD34sJXHTECWUYQhLc5QozwqlP1qnYO/j2pQmGU03C06s3d2EjlIdLNuy+Z0X9GIUUWCXDpwtAPYI/zXrF26ADyEpyyj5o5bn4GKoyNdkhskDGYenTTQ+fRqo0EL0yIqcAfyVOvo2jq3CjCRKOLgRzv8NZ30rd0sMLzpKrIwt866C8KrAes6AeYvDWFOdG2WjV8dNiG2wUyaYIU3T/cDo3COPFw8EPEFcIZAcCNE6BpH0CBPxefguDvpbTKPZF5TYE+uaLtxvaIUB3bIQI6/yK34JNzrQt1az5ucZEtXCMlBED4lW3rAfndm6l/kCGLzwMc1jaGqJo9VNR0VIO4dMQMAo+m4cpFwrKQXPzW3czk7Vehrc4bS6j+UCQBQhrljlDaOxR/+L+5R2jt6Tz+GWNGIJbKP1cd9mk9gzEk9hjdUxnNNvHTW4dOvtRS4MRoQDFpUwYuR+pe67JmTNfNtDqx7LG4zNLjh8a/7i6F+adgW4ci+DW1Ilf9ok+1zg/3+lfN6pK5X6QelSexeWGj2JnH1ym6sQa173zvfno297vUcHC6hAoTC/3enX+ej+9JNHu5RQubQD4++jHOK2fiK8Df3A4QC1LZSDmK46S0VdPvZ8VSJnWHbWlJDsshRGb3dyRkMr3d8VnqqBEcrMSKUyBqMsk6yUayfov2tM+rgwqxlrsiFu4pvawUNfFtcuWrc8FmGXzmz8Vn5LxfzeQoLfUX/JWNR9xC9tZZamjtBesX5eUAqtw7rpFfDcdbgXsMcsICLg6iqrNnoDTf4umgefPn5ZdXLAEaKmKr9K2jWq3EjfHsxMwBg48Ul4dwopQnV1GzvwQsXaQIAGfxz3b1L+LfNKAGAuxiMqmZyB+AYNU1XTRJXly88AYU39jt8cP2yet2jRRzcU6scgDEiEryUmuE0/9XcsZcfId18ZowZMT1Pn3IAxpBI9rrhhqfOkyl7L398ZNuIPH7ElH1o1LGcrV7PCOR1IzMAwAuoc0mYU0VR8SZmewtvuEATAGjx8Jyr7ndZRRabBAAakrqa1eFyutex5al/HR9+Pg/51BPSD406ljMQA8pRvJ9nBgCMQyre6J1RTDLuzPw1pAsbjcEeOqQ1rdTmu87PE3XTX6L5Gyznwp9PhH9fPkpGQ8UNREgtj619rgZb/3wPFNQVbHc/a4jvwl/8oBKYjqAA6N6ujHBoGb4ATrvhNBnDILjc0CJKnveWTCZsDPoCAtX87ot1zaqQIOzniFoY5+YhQw5B2c/phhnSAZA9ApFkx0IJ7sCLThlPpxnHyv9oR13WpgPR4gUqXIl2N4nXnTkJrp58Eu4njBlKzTOEZg8IxnUq8+sqOnQo9N2SE6jdRZ1z/fsQ3CJqNvCck7DRQdc3RveF/dc5mlOPI8T4uL+oz+Z8sJ9wZo/NELlDNct9N677yFvr2oYCQ3/83EfWnj06lnR27o268AYQhVTPo3RYYPpkhgyVUD50TQGcbIPBCGxagjGtFBjceJbYSX958r3v5q3JbgoA8LXamYl9ce+UOusgjorz1/LGw/LsWuxIqVZLUflBNNzqe8wfBnngUekITgge65Xj6xD8Ero1H/HAEgzxiww6j8ZB7I9hA4PQLxy2xTCSF3tJ/60ye1nRAiEhHZjEwgdaaD7HdmaDiTG4HD0ArtUhToud4pjcKlanIcEUD7j13JTtBA9u040VgeqfcMoXejWyk7YDcHR0TNJsYM2cyGylQEg654jKROckKeaXtByXo7DqAQhhd+e41CpRPIm6zoUBBU30L6veKGoHUvVujt12wrswKY0GCX7BAJ1ePs85euedVbtDdCFD6u6HVpjhIAJuyalS4D2EoUBc+OfKne64AHj8o92ql+v1XqI15bZv54pNU+xgh2zxoFup3vOQ40Jgk6wnrxfKqgVYJ8SCL5iRzYqxfYJEKQ6I4V7umobUg1tBdDZCI6wYso5GIsPj5aztuwBIib7SFoG3neHuUIkB0omw3HgYMqAVKWPKX3j0zEOeXOXa53uihs/cCwK2zTUdWfmdaBXGvP2ca3oubeEUEhTjUTjLD469sBTbSoNat4Q6NAHDoLn1d7TVHjJAmwfrggxygS3ojqv4siKiccTvzqizQ/sT37uxiPOJBH54kEryjipahqC4WYQ3Ztrduw39FZkaL80/Kl1M7mFa0VRxRoxS2hASYUpIdRLxT54CSsaACskZURcD6T7DueOjXevevtHYqtG2ZT+lHHVdNiMYIjJ4fu/nmbJp1zaOCONKPSKaP8J95Ije8V4Dnzyb3018HkdmaFbKBJDZMrXEB/VBy2mXVnq8WJSTK8CQuWPax3x8N3IdHtP+nKkRuXSj644Hnl38rAj9tk+2VVRuWRjNa1nsrvymeydN2VmUP4vo65rVvUozV8g+vFK0Pl3TTFjraGzjnpqnYj8fEn7y8xRGCb8o0PpJFDvkn5OOcISVLmQL98k0v89Y4snCvN8eEeM3lT34MjVzW2tBDx823AnRhLHF+wMcfn1USCfNH/y2+Nkmud//9f0xIbj11Zu5Zj4+4VjnVY/3brOKzwL+ejBmAOA47WPUljHF/2vcrorTjC9qauGcdjWqnl4Xqn61TABAfHiRvtpVT/BXt6udWv7G98iwegCujaC1eL1yhl59ATcUPRL3AaIOA+I5uupJcT1P8HWp2/hzT0Sgulz3jhhpRAGwRce+/k0LmNKMTfgx0HDnnYCoD4hwwcoVOwxDBCUhRKsQoCSRhCue2/9c9F4/djN/iU8vqQQAu2W7NleXuELigy7hrrH0ugYBzkBDFOm6hLH5gmTFDrY922J2jrjyFiDRWEKvovHJtvocMB+GdcfEc26nXAIxds31Zvyjgg9jDEkcu356cP45FQyWQ/2Xr9D3uuWTcP5rnCe2ZJ0E+rAzmSuB7q8l5kKexhJKIEgrqufzwt4z0Ma+6Z2Tc87Mxal5/108FsEkt5OMAUkkyPVYQvnEFI//BZi8mLGfYTCJKmKnPSOjj6PKKtrk9r4yTzXtIoLNfgCFXbO64O3y2dHOc0mB/cn4z5fkuA4VivPPReLcHVz8e0Cn05dLt14MyJdAU5yPV1oQSPcU194ylCH1I3Xt+oTMx7XGZgDuxpWddWvXNDuvgrl5OdL1SFnrVEM9U/0qfyz+6vo/VODmhzpDG/dFXZtJ7jTriHeSCKPhhLO5/uYBuSfw1POp6E8u60XdpKOROkyUcoWjqimnNyHhPDDdV1/7ND2Bh/7aiuxpFbYlYhwZNrk3v2ylTvyNsFmfuRontBwiqKx329Zob7jLYDIb9PrG+AWk4nN4QAF3naK32CroJjFK0dzBGBdbhqGvOwlO4Bqc2B+K8vMn9SgTYKOTXQpGthMF0aJQHsdrTiN+fG+eK6bKky6CiukeqBgoB0KYhl0ngc3MWhYQhR6ULDmmmrqvURCguRGH+xUW59GyJPI78e38CbKxEQpOnYlmZUheRl8+5Orw0KnDEZXpMdVzYEcr8V95gf54U3cS7adnQVQm9yAR5pkyblumE52RaVLbIouY4WxcNzoLJraAqsbN7CUaEyQRtqm83YVxgTXFBNPk2z9SfS/2mTSulgEfWUOYmQEfiAaWnX+P0ezKFz1BzO/T9SX4B8Sm7NUmDnbHI74izpe3Dq/k2jqvsxNBX7keI1eux798aA+Ee3pag6xpPDa7uIun6dXBDb9xrdpAFa1TYvlj/3iacVrXUYInG3OQv5lASKQr6Ok3CWTOFrkE3Ab4lFR8hbY0DZsgpiXw3Ic8YccFXomJeuZ+zNjq4CmlxYhcXQnrgtpWb2S+JXEp5JHh9APA4IjKN4hdm0qnHRzhSFfJCcOkg/RinGMzwtgNDahb4H/uNWjrIexsVRC9uYlMT3CCWCLeq12rSi3BlAQrnIAdFhL2INatBUy7ruc1TE+6eZ2XkZ/C6d6+CJrwouvF0ghjWDogxPbgxotmr56iGJoKnuwNF/VWHb037trPU+K8a9PCmGGWrqdiVkSOISAAc7D91xXG8Svq43DBvltxo/jeFylAbMWcCDXDm0rM6DbyRvFtLzAazwd/SPi1x5/NHyxHgX5VESDDn1tRHXzSlbjz2ulMvtv9Dp+Ic6KQZ3edNwa+9iZsx7kIwYF4aRfPuiAwhoYbkgvhVzlgwfF3Z5tX5KgmwkDs6AQdqyuZv1U3sFzdM7UxaJQ6JM5ELO+d+/k6PEylnYrwSOBlurpS2rECSHSp8S5Sbrm9jweZ44BxmkOBY4P5BmhH1PRRkCRcXYG91K0JRzOD/B1vQCcHf//8atBI/HuWuilLAbut+HwOMwBwqaIhe73RUkx4vCmUs4j6ALwz2cUa21NgLwszAYDj7hk5AvfEbG4HnKsavV0z2HZTPwBwNCiFQ3kIus/yxQ2assWZAi2zvyzAEU2C3XdnMwLHq7+vztaFd9UtqeZAqkKXkjoBs2vNdgByZS2cA1XNs70DCmO/0wQp1xWZZFWF8W3oy6uDaQnLF/YRxHk4rtJAAui5f4zymPhhpt+bgyGzSZdePfx3cSoXJIAuErW2pSJav7eSO0FL2bOd0eNgTenDatV0qcMQm4q085gBgJZgp6OlHCwNuT4pJjv46ZFji8t1ho8XaAIABIPsmTYL/HWV3harXQv7AQAWvtqIyuK3dJ+Cj9PGMb7K/JvB5xoGYzzTeucCQeXKMYa5Jh9EzhnyD3aGdQvU/FS1qMnjkPpyqtBQbX+HZgCANU1TteXcz9EMPZ0a78Xu1gxoX41fMf9Gx5SxOfgyF43WlePpTPS7KysCZeKjhxfH8OR2QZTGU8btjQNsDjEviJ5zZ659N/5Cs3tCTKjmg9XhwU2AieBC2CpJAc9MszqjvkvHbiHW4L7rMM9qMRXNBirYkwJvjoctYaKk80gNWxIUK2xDd1rykGGMhRq2glXBCIanrVbE4ctMSCncz7rDmN8J8+7xEr+37HpwPbbLV7DuIoUNODXiuNOYAYAdqqXg3NFSErZEqkops7NsF4dEt0pzJgBg3t6nyOT+ujWUO3o/HWboODheW/ZPjzH7Y2vJl5Vf1yz6cJxee134g1HHKtqNR06Yb1afnVoMAHh1fMz7KJmMuovLqpY/VRzDP+iqbrVar9VPSZxLCflzMZyzGDZ8juE3iuEfdIFWywg4UAxhvkt7H3Vz2Nmijfg10C3pDCGbW5HkGR033VTgXud+mVEqiPa0FRwBokdONicFMVWtN2cDyUBXkaaL5B06Dqt35stna5O88Hr68+Z+0vHQeOL7mZXCPby/RztHkz1eoTOcHLwcfGzDjP9lqtKlou5FzABAt+Kmy07cqDp8+QpF+lRyz702fCBvwQM5RRMAiMkiog3HhpH3/YCarpVzwsDVzQUBQNA83tWEAQVHZpGCKOs9UgWB0sS0CoJt+jEqKJxR4KigJF3udZC6mslAYLpqlIKwZZRLawYKHLe1OAacLM8+C5yT/b4tcDp1RVdidcVxOsa8Vfh2fiRZ4tPLrNuhQJAAyu8f42gdo2Z48/uSo/P29+J71n4oGiSAghLF0zoExPPe086JT6uNadoIQf+UfWOXtuWPNasWv/o8ZgCguhluxCuXg+UWd3uW2hGf5Yq3s0gTAMDia0wbFX5SKZfmYVwWGgQAHXyMEWXhV+k+Ar+tjd34iPkX4kOGQRqfp70XJHXkjm/sJ/ruOb4mSeuYnTfjCWFvoEcG4BwfnEtpFvRelrlGIum4+DYYBA7AtEQyHmxHxTHP/CVxmr/Sp7QXobUx4qP+rGJRXehvjg/uZD3fs2M5+cf7E5+fOPC8KOzGyYE0ZYwhuF0MBVh+MePAVk05a3djJn7kqrUyvLsOroqbM46Z+nM6JvdaGsEjVfwqoN2SfHc135EyJUq88XZEIX8I5nbsDEklYj4fVQqmNM/LjlmbbOv7O+qij/N1bqYrmUIugDHNlrEKYJjRKVYXlHSPdfyGYRC+RPqs64u/jo2ougiKUNbbpI+Db/x2xXsz0rs6VPAcqFgWBi/RYfXDhM5Ens0FyhIjELEM6DiViir7E6DJ9dNP4HqWVSnodz119e7ebZ8KbVAEGh++0g/ApiYn5VRNSkMFBkNiOgyUXPxXrPkCEEh32BdBNi3O8TCdjh1Kx36Mgtx2wdrve3T5Tblwg3Dy+gFH1Y8bEJ4Y8CpF3f2ifCSfFN4eSp3qgkZwRVzRWFGKT6KmfJbumRyGcIXhjcutiG3UCPipFIo5tES/QJQ4o5fA1zjdnptOZ6UTfGNOqVAk55iL3/7V9vAJgEzoLJTAOcpesyuSLJ9+IW+7q3ToWSR3w5Y1jIGVKSSunuyIIgcV81NlP/hsnTQRh8qFuSJCUR//D4NH89aIdvtqj5KNjOeCsW9jtsu+p9no9a8geJI1GJXPffb0anRpeUfz4mHRTMBWKl2PDpgKGxjEFyPzEZovmYVbBJqzI/RTaIuAbGwW7lIsDnvF2tLp7Hu1b3qfcsk+/G3PLnDBtaF3JHFxcZZjXgxceGu9ILgKdVl711k70N7xjW3vWAcAGE3Dl1+jmMZYWowjir3aY4c8NRZirPY0Ev1+E7PCsPpUUrFDWx5UL3Rodd/wKDQrtaeR5aVhbA3ILyE3ZJhjvRLYnEuAOyGwKzeB1SZsOJCWaGuT/p5rkM+b8QSzB+lVCEqxH0kxZyEM08yz5OVyjGpfkg0zhcnqroQ1mRg3mTReLxNIU9elAcNGtsPJ5lXSDFeEIunTdwmY2MhZ8LoROcH35TLh3OplkQ6JJnwA1CB9d6SN0ThG3scVgT6N+LHBf3cmMBRjqZn7XbXIGemgb/Xk8bt/mx5VZe42eAID680ptynUQBNR9Rf8HbSWhuPaSJA7qG83SvHE4ZU8OEZqIpGXZ2GlaMKbIbq4uiDYovInRvGODQYcpAO4zgeB4dnzqV7jSqHt230tB5CUBEsE9/4cJkpF0SBAh3k35zXTHvCenvz1Ud2TezFEu6rBNFZnsbQrAZqU7ErkypRSf6XKqPZigpk+a+0vsVaED2D3JhRNwxIY2pE+dvJNX6SJNv8AiFzDxFryAUsX4o48r+31f43Yzj4WI6eSDCeJu+GPFvJDu133wd1RnUutlzOH90ntQT/X7R/amKrLW7A0s7jEKi1VMJ5La3AvXzgwxMrp+bww7wFh1HKN3Xhvv+lKLFWQ4sUEOD0zd8CG7eucPfHjJI21YN1vyB1iSH3wVqtyGD321FZKYMEewOQgYKGh26SN3RxAK4uhux5ehCjaQ3GjyCMS4cIeECSG9Ami/Bv5lzzDc4SKixDRO7muxtyUi7xbSGtZIACJ1BYtKuVj8nKICZEkv6tAB0p5TtJpK/9/XVrKVqIC5Gn5Gl+0A2Rp6qk+LbeXn8lN20x2VCwnMxjORdqIQiITNmlKN5I4thKV3Ze3OPhGP46gumAIlPrjldf1dBKZVqhtblr7/oNQt+T9uE7exCNrEZu9oghu1pbzbmo/SpgGJQZbzXpocaLCH1LDy+GH68PkYGdP4CubBJyQ1g6E90ERC3NTSp0QBu/GHRqDgqyK3V2j9dxCEcVLFpXzSIB7on3SnT1kN8WtZr7ekIrjZi5f0VjZ7TRFA2LXcUfw+v714j3uPV07vb6V+Guqzup7wTfa5UOr6bDQ1T3NbY5CGPvUfib/szeX2BjA7h6u+ioHp1/cw2IrfMVok9S9Z7yhpsnxkOmq8Xo0MV1RmRf8bpBvDNH6cgLW961Vv5SeD4Jpn5HEoPWpbBq9Bpna680qtL7lTEt5D8J1k+uhkho8aCcB6XQ2X8v3eZNlMhvyPqR7PLF2hJCMfG8uj+rFeMWAK3akFPtO/o/VbnP2iGtkR7/rWe7ck92lDvk8q6oXiA3cZktHYFYSaLq/Wd2Evot7Yw3RHQToOu7B9UKkrATgIggmR6iaaXml2a1gHX2n548XA7GA0NQHEl1jZVE8ujv65YK5p+tg0LLvdzacpN/toxn+ebxUhZ9WrxYP/6fr9Dd/3jKT9qPcwb0ZHjwa/vmHOeZ72aED+8NvjT7aj4YMnL9DKEMLCLsQsf5EarQaDzcmTWgys8xKOyFBrbcOon9JCV+wNpa53kzxvzJ5O7bVGIgO402v5IAgHbO+6RUbSNbEWEGK5hXuh+Ctu9QahUtfNk/FnItXny1lltmcqOehqOIVT1blWCfzlpMrYeA2qZwB3KGKD+QmDdOALt20yVYVTB5tTj2+GmMDy7xkk08/ezZRHkiu8F0SYN6kOz01gIVGhx4PnxMBNNZ19oSmZ0G7FbhqlOWIIN2tq4hR3nQRsLN+eWFM6eCpGpYrQ5lDB1p4wKcLgCNRIbYX1syQAvEl1a7llGiQmb6ECq/7/nV3Xt89iAoMLWoQN9mTtC42bTObuALCdRI0FV310Ea36gJCuyQ4X4E50iOCXlEIKYZ45eU7UrnNCS17WqO8MCAmY/Yand6v9O4d4kmT7ZC6qk2ekv8GIkgTdUVpWwTWFjLkaZ6q9fkiCDJsYM825A3DCEUh5hZUZGJFNwjUOTlKo3HuGa4aRV7sQlx3cjhkPGRIchPPtePHjmm8Ip2DZR/q5o86FVBaF5Sk9XumrXpwRZPTIQ8bJxNId0kTDy1nEIPjmvYo3kUVH3D7CVqAmawsvm8JH2Z8KLO8/ycLE/DBQ4WvxhWo0Pph5K98UQLfVWZ/UytitHvuWl11gNnpSwBMZijoDMvuarjMIyi2buz2w3nFt2lpdsU17X3m7DfPdSAU9ozBqxNBx8mWf4WzrW5IfaqvHR+vH+6YsTi6rz0tLf4aYgt3gu05+/SiYYq5pqhILfws18fN2XL7xjVL8jw9EWjAFXcAuix8blRIvBCOgrr//dB0izhF6Q4oWfD+aK30NB7cqT/Opn3kXl2QFB4JyrpPrPt0JPzeIdIfbzbr/hE9plcxZZnOkVdFV/zSp8FxdslyWpjEPNJJXZ1ePgtW8Q+fbzcSjnd79KdsHHypr2ZwICYguSrAJJFHlydIA6Ttjc067yPgP6S3LV3rdJuwzy3VURPPHcEuBE9RKTDdFVjDOea4iMrycYG+WNjo2W4TIQg4t+3bQ0kjB2yZ4EE1MQaEyWQTd7kBeL8RFGoyLWXUR5C3g+NeYxfCxVsIvZVoBp9HFHTUJCbXacDeU4pAR7s52EfaGGusTdyg4bF2zu/jkG6jO2B4phg6J6GFn4PPaNgei5xBroUV92Oj5wuQfwYpJO3/plgv5Y0r80XSsnGEXuAWiWmZmY1lsQ8US4K1dYzPRcTy5Jlxw4fYlmKuVWTRbRMYKmuw1I33DmDEq1P8VP92Od4QKQnw9hFYWJPYbHR0xKSftb2WMjZ8tBAxQRPsko2tgFd8fyI6MCWnUbiNYeCpRs+YHAIoP5A+IMw7ilfD67stGzBQbPe0rkPkdzvafekGuhsTZkCc1If+8DSkV43eb9zvJrl1ePyIq5kn1iSK48mmVI5s6WKnHAb87PJYKWmHAK/LiVmO1GT1IDxFSZpp6kLIrQ7z8uqWdiM1+HzjCOwrqHqwKVQCrrOeaQZV3Cn2NWhvzqwXdibTusuLztkgAGUlBxHXhPHbYl7s4t/uGwwBytV2qw66lXlF+tFiQG8sAr/l2+r8X+oPmPxVda9IVEtMFPehuoD+szcvsVuBjanjPfYXvZ1sY08gp19W6SxEGa5MH9kyBEfRetwvbGSqFojHD2jSJn5jmQ3OFTtWNPaj6WgL4LGDmfRvLGMwm5o3lTJkx2kAkCf27T4iS0PfW7p0PeQeHjoPZ90eKsPWr9dxgOSg7PKMbAB5+v0/X3SUGA8BZjFKz+g1kLfK4vgHtHa9G7ODeBAEKJ7NZ+pZtitnlTsDdSbUu3PeQvYjt8EhRO0QBPg22kUkFv+JRStiXAXYTTqYAjjf+cCyqr7UJcxbMM371xP4jigI4Kub0l4rz7G2iqZkzSvv47XPVqmV/l/qyRaVUsyrWGaB8Foer1e7OepmcSpQxfAbod3dnOIX4z27UQXtQgJobSIkWYTYZkjCAP37uo9WcCNqL9w4NRW40ADhRMYBmRub96mtPmEO9KOezoayE3UFzDVvk8YxLZha/Bzt9LXEfY5sF/FVyV4e+iHBKpbaCoIB/I7Ntfnf+qFO6ZQlYjH5ecDmKYSk61/ngM7IN9BaZKepxqwDSNsMK7eQ/gnoyGTVPFcPQgoPz7GMBocsvBftsYYjogrg5iLJtK+2TCKSnAt8VEF6h8ypqi4A7HaAjqhK8eQZOfi9fjaw35vff2n6/3Hy5fs4iRuaT43Vwu+NN/BLTk6tyTyTsd6o3OFwet5g6ojRzhtMnS3peiBHGEcGtg2GVTrJWp2gIFIs5KPyrAophV8Onw+qo/HH+YrmB6vkPieGt7VPry2xQCKnJ+lVCQrgZd0AQMCqvBgQp+mYcCLJzoVtart15zDIVzi0momismLW61a7tTrqbvnlGgR2GxHMECE3111MlUkwFXYtx1vcYe3fbYFXXPoPAKAoMCf2s2xwctbtusDZ1cPHEXsrhg3/zviTN7gbp4AtQqyGI8COwAUt782BS/OxOwDrfsN2AABVtfQvvN+Hai79m45zarWdRnmo7b48HqADqqPphAJOcVWmE6TrpjEPAGAPOIiNuy1QkZ2ZPlALnj0c0LW8YUJQOzVQI7Hs7nij+oX37OGikkz/Wu24Xl39/yx0G2C/WP7edwTWwENB1ZgUIXWF4/F+Hr/JnytTZk0+iu+3VNsAqsF0OLj5/sh79nCxF2bkfPhkWvtMijpO7Xf5R9kf4nyPCXtlFsb3H7YCf10Rc171fYX4MvixfNsA9tosnsxd4BIi9GaGT9iv+W53tfpIK2XugXoVRKRQcdx53QCAj68BNFTUdcqnmZ0LqS3ukg5q5isckmNHUVkxdEhOiVRJXISuGBHtETFhrrvIs0ngCmrX4y0mW/s3YzC3S/8BgF4cqD32EwR0ZN2mDHppiwcL+sT+RgXMwSnAcSFsTduP80FQBb4rDv49Ge9DKs6aW2psI90rV4gcAt7Eced1AQDnKIrYj0f8uwKmfu8wMr+ex/at+DweCrbC59l7ZD2HUL4oysJnurkIaug40ygE01hSAAAwASJFtvhpiPUHId5mMwgZ6lpROiDZvVwHAFBCCGOLuZhnvWQqIkz3JdKaxm5xUzevRXZkZY2929k7imOvtveTwVj3lH3OvBEvfIB4tw9/pcogEIS51MV2nLx6pta2ufndi5N/XyuzHOp4tX07VU0OQJPa84WmSZDrrfWbtTcfv/T39LPko+c1rF7YEz9rM6U1rF96M59g9cktVllRpsCqYhx3PjcAsAqrGUXBMKXcZPANOTGTJeUMraxbO2swl+LlKxzaRURxdsUEzquwS5GzJE5olHIeIgAQaVnLCVY9BRMda0k5d/1pC0gNvOwfANA6kA2xHyfxZ0FOob30iIXKxTmcqD8XxRNkr+jI0nuOA5Q5l/Jq2URemRf4ru8IkTdlT1JNaolgiwm6GXecj6Cx55gVt7BVgStP9CpJzZzxZDKMpraMBPF149VfuDk5W+JGpq7KhshgFoHBMTY8t4SruiUqOBuCgtuPmODsnl5BFd3SdTQ73pZ8fnYEBJfWAo1wYJhoYDrBwFRigU2n1YOJBAYIBC6Vl740850tyXxjgoDL/nFsp8JEAHMIANYhIQCe+XZ6Ki4wtj9z4s37J596qh8oJuSRpUTYdqvLqsl1IUNgMbGRMMVQqerjwIoOBIvhvCkAwLkOnN3usRMeBy7stGOP+bpL3ptAVFwl49CpoGt7WR4AcBwjboIWbqo65luDaW/ux0yvmj+YTumfhIntczgdVuwSmAxrg0FquqAGm9CpGElDj+MzoaBJj1s1e8vq2PD8Ub2HA5/0xTXL6K5pu/r9MM/tLnWJod96/hO400WAK2z3904HZ8b1HBMZXTWZkKNVzTR4IrD65o26AQALhQp4AbG8mTGwc8Xd5VXAeQsBSI0FsgDUVRK44G+FVjUhAgAtQ+sCJ9jUbPh1vDfcvcq/u15rNNB14z8A4DLk6XV+vLY4F6t5HHCxBfFN67IRXJ6mvw0U11QrpXisIL3DrfdWpyz1CcoU42Cq6+fWA06z7mHXSHJldz1Bkhc25j3eTjWa2gGAlJE0ZPmG5u00UW83EtQFOSsNCaSuMQ8AcA48R8Oh45ZVgdmyMih2uCIF5pZlo6wCC7EG1KjAVndAsbwg4+KWFd314aQ4TlpwPkNrbKkHhuodKaKYFRv6GbIfc/DTIS/9MrZTgbEBVOVonNhbndOIfBT6ofxW+ho/Rk89QuxZWDnKVkL8bABfj2PvaSj90uinomMD2POweJQ+Be/a1Cs42xFUIjL6yvFiE2NViUHkDnHced0AwLTOPzTImzsFZKTtprPxkryFUOjqikroqCpQTJVErdB9TYgAQEPQ4oYTrGru8jzeG2ZV+zfX4LSW/gMAWhl0k/3EBfraag4BBtTFkzBTRYeW3rOkWslLmQW+pPdhq706C5QyfZhgboceEvIzWO9lEqQ/ZO9xT/HNeinsY643vp+BGEBexdfzbQAABp/qaNw2vRWCquO3vPmnlM4CUVXQ3ZaB1pHCzA0IZ/H5u0IIma4MsYIQth1nEYuQ0CoWEwAA0w7bVYgUzJcJKp0cm5hka1dmMgCz4uQadgCA2UKsWExpLWFdNnMDYE1LvDGwFmySEogbcIxKHHj06/lwe8wpUMf+TymTqZT6cQlfVbGD4QS7nmACn+6OoP3enWfJG24ruwwvWxvb68HL+c16gt2TNasMXmaRIQBw0wgS+ynUJluos5PourUM3SwnJ0+i6Jh8vnMBH/+0qCq7K1ACAtXukEDFAHoaEAEAAARd7lPLiAJJU3vVf9PRNLE6vfgfABhAc5D5sxXKqv6W3tzG39LG2/hb36bb5EtKrTsBavpEC4MXLK+L+eAi1n/VrN8H+SC7f/79K/05bxVuEMRc/u+Ca6A8krSyN+q8ZhSj3vrcZL3BMXZZjEh+4pkDr12cFHsL/559wPd/sIUbHivH/4Z5/tj48SgOcLjTe8v3zOSy2/2M/gD9GkMWsVtTdyTVvg+3W6uwXhxk1FmId6QMP/uZeku8OJb5sRrrttOGRRDG+lpD88P7L10woNhld50dJssC2L3OGDzF47ApDuFpTp8CAII2lRzF8nnl43Csejuv2TTXrZuiCoipt3LVOC0PABikV4MhsqosnJsXcqNaGTOB3Fwn21xB7shpsLqgtLcrKqoQbBdOMXxwF9rGKrzKaemo3h+DlyEn+EL3F9zk7rf19d/HjKBNRb3EHooiBcy33plc/Tq+s+a6zu92p3tcZQgAjDX4ErKRamcBDryZOGA15vzu1LqhQJ9MYfDu3aUOAXV1EvABnDIihDlXeK67OE1OtL0glpV/vEGwZDDsxn8AYCRou9f8WQRwqr+tN5f4C228xF9cW+ZKN5RiEvjuRGUEldYn6Vt6kYQpp0tCIGG2M1CioNRuuxtMQ+kqZyxYIdOdZe0AQFgFBdiWL2IhA6bbLuIhJbK0klBFVWCVpjwAgOXhVVVBBTZuakC27IxTIAme7VmQXt6QEkijCio1Ltwj4zaUKHzkPcM5RXxjvU0t/cBQqSFFqKKiiIIb/jhTMe8lrqmdy2oNoAJD4wToKYbsWyW9Ofg7we/ImDz9CLE/XaFI8Oi10pejA7vfHCY/l9oawP52tWFpigZrOPMgp/nE2huTszl7klaVCKxzoloEDgCk2x8faoc3NwRE0HbZXL8sZyH17dVYFBuoUp1EWUDHRgR6xv+f6y66tlSUkduLpmZr/6Z3ZEMdTFfjPwAwIDTXNH+2QtTUn9Ob2/hb2ngbf+vadq70glDzAu6AcGy/akkqsE1/TKEItTbUb1F8oT/nBx9PzPQmWmTCtfG1dm8LcVdwF5g4UxQft+VK5Nvoj208DiQ8dQu3/atIawDmRPJ43jNDVrWAFTJ0OAJEYJGQzpeDGKkybTYd5mukPmldavVcjb4/dyfi/gLd/Ozoq0tIKBWjJy2eLim1ITyuoX2Edm7GMqOichceVrfRhypP98e5uOAaIt1SMlMZ2IhIq6e3SphC+I/h0nbG27Ai2dMU2mYYBoNsoANzwdjT0gvkUj0hNRpsDGuJBYmO1C7D5OPki6qP4mLe/obk8oiOTLSuUWjYBtLtYyCHeyA5Tw3tYSJItv1hitwsHaSGHT2dNhvkLxqYUw9Hu7C9CIQD18omTNkPwc1IQXEGbuS07nkzR6JsqXjCoNSB/tnqWkLsaDcUAmA8z86JiEM/Ni+SODFvBxi1gEAWZHLIlnoB1VkBkOBrf239cXXlpVD8c2NFej6ddl8uARiyiGrmQ9Hka+APe1xY9NRUTfwzLfv6FcD5A6WEtXxtbID+ymrVY9/J4iwNREZjukGdhjkX8hGsswGUWk7vnC9l7ibCX6ASP04eueRlIMD4qCzdpyeVoe+2oS3Uyi7xW4CtNYNLneV35GHLjDUvqWAwFviZPsYXKd3Uqh3A9GlyAfPGM0WbZ5+eTm8XiG9bTN+ULlK8BXWhTt9eX0xw6fmhzbNPz7XywsmFvyOUfKx3j5Wv9QMd33Kp0ouJJv36ePfA/bGqXGotwjghbiLn9s4bFtrzcNYh5vdx9wS8PmsHjblJ8rX0ORBx4SCS1KvrdExAQ9xPWeNmlEJnwqBsif2jfm+PyTxBNaN3rYpFkTQK+0rrGNAOxWV/wBCJ0kwgxiXHwLVoG8NTIrrxMiIcUDX6olm6hzE3XbRZFf1Psjqff6ujR29sTcPei1pgfGRzvgAqIHDToyngNbDbYTzaHmDsZMwrhVALcC6VHdMmJNirZ+h4+Aqx1qof3sHNn848n6ekkUKtk4gQdIA2AD2rUSVwMTGA95YBHeotFyOYhipzN3srWpDN6Iflf14z5Ob9ObbbRt2rWegh7JrzO+k0WiiO3AYhqgJrXDZ2t8iMcJNlDZRCMV8DndlBfACGGHAiLJcZtnQk7PVJE6jP8ceelv9dOzC53kfXG+wBAH1T9CXY8UBfmYmhWLzTo5rAMblPkTRKEaBgtZkotQhQ7LLEKNFqfgwbPtog3XsLUMN2ClDrVbGAADVaNwDlEhNsrXS6Fh2BW9tuLbBiz44n5lsQyCo5cbubMgQ5d85YKiOkr0f5k9PV5zqcONcoRMnJkGJoUL1q4RSvmp3aVQeS0lXTQxLDB3tHSL1gYmoFOfhhlYFVoBnIPzXLs4M6sfAJNaRCERBjfr4x17J5b7xCQllj2FP/auE0VrHLhG4qKin4El9AiQ9IcW4M8pntZMUtXK5iTkRlzvjn7m0nwtCCXVkoqCIlK6MULVW0ja07CkDffd/ZVrm6DRDZeDQv+PL2Pp6XH5qd5BLchhHXRrowk70ZsWolmlycHZeoRNFvkmOKUHKbe+0bYAslGi3kgZycD86ZfTZmRG4vKBRMphUh1Fh9Fyxz3n5RsXa4Fg9wYMTpDx4t5qxHiwKc9GSKY51QEz8zu/ENXOaQh+f8YjWU34kzjdUuErVYbcqaQkD6BQqcfSpwev9ejYSyePgOtL5aFtgex6x8BCSSdarUMGq9tUM+h7pXYPAnPvxK/trfumJ1bVjGnipf9E19v5hwCkD6GkwAgIDA0KbHTMcJyqIElfmfNAhW0nXG7kKw5twCNhvBunaR2DIAlxHBWm6unYoAAIgDcKLFgUb0ddjaX3MDHDhqAAgAcgPyiv0YByqrMdO9MjKCLhXFyfWXFHSblSYEBzYKdrKXAAVHZQbsqWAE3rVVYFw1hFuLXOXsbizkapuNJcPbVzcNEAFAlmDqdN/2OGovNz01d7tgMgPJVU6FTCfNhAAAF8As2rgpAgylZ3bHfVXaGDx7r5hsZmUQhwMzqBE7mFVjglV1DsU4rHmlNPXnfG4FjY7fKtQNoFpGYwS66swnSb8lOekLqzlu++bV36rWDWBfvdqocZ33hBvhXyZ3r8G/Gvvp1d8mlzydVnUtBMW2bB4ObwAT5g2gVoMJAKBewCzTwzOGq2ZRAqr4HwQm2HQoY1SflfFGpgGCtzGSVHhyqa2mhdv52no9+aJxO0zx0cU1B1GL+QH6viaAAEAH/LX5A+GHWrPCAHcFsZJY9ojfZZZ68VGlgozuYRGP1v5ZE1vnlIRkfUa71ybJ9dO1uT3X5/5+4usJ2R6uGEEGCTDhlSIelpNdDXBgDfkhCBXLMqgScP45B8E35l8YsGcK4Fw7QxJghRXQANhjyxkDshs+AACXENSWw0JPISL192ZMEJPWDZvfcaNoUgUWr8my5pPkuicgZwfXzWjenE2FgLkUZ0UjcwqkCxvDOpLUmfI84zmoYq4lrtJtYlvE0Rg2OJGLBAwb6zDa3AKN0xtp9MFLGD3+0V35Odcp3O5aBh7+rXbNUcL9weBlnWkPdwtovF19Mk3c9umJgmBvNLbXy/I4RKcX1VEid0n29ti6Wru6riQeoFgn7W2ZsDdAig0mAEBqgOnh6eMB1GUAyrXvEuyg9owogT3MgADAXpZECI9aJAoAqCAKw4hoGqCovAslO1ssU2z+xIvrKK6WagMAKHdsYcxmqYUBGtQ1dLmFHLASXdRstJktG2pqLXHrVu9Km2j6dKTaNSRecmGA9qR1RQ8ybuAEjYHGvy5OlEYDp5devkvTF9419AjUSoOS5RqG+RsheEFXiOU99MAgRldcPnYA8spa/hAAHFTSddLyHYfI69FHjjvfTtr1GStXaUzA5sw2rd/bwkxqm3uXVrj2bTNHsIXt+zFbJgi2cKeKY9tlsEVYYQ+eGGyzT6kR88DR5/KUvrhw0VS4vVLkuHwZmhvWJcb9+vDTWxjn+VWHK/kX/SoUq3XqR0HBGTPh2QLmpsEEANhq4LoN9XPvOoKU+F8UBOnUn1Glx5gGAh7XSBLxrEWiAIAPYtCMiINxvTWehk9Wqi4xuspxDTzbEA8ATDcorOHi3J3Pg4quWM3oQAuaOJv+nCho05SaGjfypyDOlHa9bu2tZMVZa/9jA26ti1vDuy4Gt11HeEMwHM276IdGeBEfuyWDSxogAoBbgzdj++6Wwc3W3N0ddJriKpdNi1hptqqGbxb5nHT+/YIBNdzO2JKvoMZaZqCCOhrZIxV0H4OYKdDNGrFJoAbFpivYPtPh8zIXnWTb4NoMHX9Ry20AdRga5LxjHugH46M3mZujv7QGO7LVx3JrfbcB7NhWfIaTEPDHbemR6f1aLg16p7axgc96WnvDbFfX3mDZOmlPyYQ9BnxoMAEAfAGmwtNHAXhn/kkD4OGGbFt7xj6AHWZANMAelkQQj1wkCgDwIKrDiGiM3q4BivTrJaIktTL/gMNFewCAKzU3zCRFgIYLM84tHjj8KvxqvSnhc7TxCk/L23TBjwvXHiotEtbfKvw5+lkkFSKsNf9Thf0xxbdyL0dmfhsdeZV96q/qm31cL/cESbWfcYgVSXcZmWQwLWX/OcrSNJ3jpCS+0D1+A3c9q/MHX0J4ghoN41Frez4G87xwUEUa3SS4QtPiGQjKX3b3V3oW8PrArxQTyNmt9IIQV8IZNPPN+xiDR7jOYBlumI9m+ndavwQK8ml2TBDE7KrwJRJLIrn933ZRANS++RXGPp5aMdhSrynKLZVl246VVuF28T/3Hn5NBXZYO3PdwK5YwbGAq7bkp0NM8ZZ8AABTuwjFcFc0An8wqrLx71lPM8Nb7ER+vOdplI0sAMBin1K76Ch1eqH2yGZ2Lu3EDKrTZYurZ3nk8Y3q4OOG8SVdqLdVwHYO1puo1IsrUjqt6k1Phhu+CwaMh00+Km9c85JuEr71c6VVc6coTDYFApkwkL5KBMBGkf7cdn4lfi756Ou6Iy5S8+ndlkiwa9w/tg7BPXed8XgIXq2t5KXgpeNnDGFXYCAtFKodFqHWisX+NAQAQNKCjEjHjDI6QG/rdRLRB9bgS/YaTXsAQN9mECdZpIQpcB+s8gqBTWC2tJk4uAlsR0uMy9xNswksRi6FG5OXWJJ+ZU+6uIlKLJ8pQMyjuLRZO127IrQ5dg/uumPEImCZvK/Lml4CluX7+axh4z38jDODyjDNmCHlRwt7m+xaULzsS+/TFP+b2XbHspvwWjdkEDxXhn/+BvDZ6YmXQQ6sjdKFuQiUIcsugueudKltySz0EOPMn0RzN0l5hU0iIj7H5H1Gz+NIo14fqzygBDhyqr6EhzVel9pnCR4A5ye8oyUn4drLXgFM3DSeijXfhN5+ndLoizM2fjpdAmKqvn+Snqv+DW0Rk5GiKkcF03T2GfKlFk7koDmkTRmuCo6N/+zDxA9a0gLghsGHa3f7GzHXnwufk7RCTgAGCjS113fL3VyubGSz8C9VH+J/TK/wlYbHe0XiOoCssAqQhVkOS85pjRk2/zek1zm94jq4saDT5fWk/ic7uyhNxQaIu7LyxeJbA2YtXN1P8V+fA+oqF+5lf1IrZOQoEtY1WkB4fxbUSPoEY/6uc8T/1/ZhckpcKWjvprk6wVs6sg3IUODu0ZONHFcd5ZLmswfUJMfvlsiykJf3jDY0f+sAYIYjjho0sQ2dX8JZIXw89IAQsCMyZnx3zb0lYgpPOEjADm2GTHmEMGSyRfXChbWO2QPb1UZmJNavM3IH52+cZz5oByzl+TwmeeBoGVT4zh2AHcEd2CTOq5zP2JnU9ZIhEU3pEacXOubXNmPYT9Iyrz2PkZDbaY4WD/ht8sKMY9q9r4QvYas9aWviMNFJ7+q9aTPy/dt0kK9cnAfMlygmIvIQnsU/inaR6Tqd2tTz6bImJEJrFGYCwef/j8G584jsg7cSkZ1JF7UcWR22TCVpWf993SKBcqVNaP6vE2h0aYGTARq0Jjksjoe12bjEw032fDSJyPo4Bj9xi9L9O1yaT3PfAikuJrNzdXzglixr6TVyW9QzWhZk588b3VhVCbcC4xJTFxmnmDpX3GLqAY5jTDVTGFTkj1k0gaF7sdGOfOKJtC34HbEThv/ggIetpwlCFx6rmTp37GbqgujyqYuM7QyKgtJjP1OXKRb0zm/d6pY/XjR1aeJHUxcST5o6pzcy2PGmqQ5+/GnqIRKPmmph8ampSxavyhWCsQWKjmflDxIyLTn48a5yuvCMFxofIbGbU486JeA8t6yE1FZkNQufzUtrjxxFUZqkrRb2bTiFNhiUFOkCkzvjRVs3+aQn9s+dK3UXPLHo6UEST47bcLYJGx5JyYXpCWpTCk4rYnqgJwpNKUPiECRAmoNrbKSqfJtl4GbRdC1ZtfiNNVsnc5QVV2ZQiC+Z7KDjcoTZG7RxejediCl9yz/pDuqIWIO7v8c6o26FgDWcOKdW2qUNpk5wVqZ7ptFicadaSggAbPUME2/Blh11ariFwULd92UWmY1TY4TgZCMXELL7gAFASrd5nTm20qrowm2O0CZ0+fa8hEMp+VDfYeNfM73HtRrCU936vdKrvZ2nniDHEYbSlRIGzTajAABaAClphug+jeeCBFabf1QPM439WLly2aO58otQF1wCtUUMYVdgIk0EbBsR5Jmiu9MQAADJ1WMSuftRfQBU7eskAt2jRClNewAAeuaMqUxS2Iv5w5rVDXyc3mTjs7QxG59lTLGZgghu8cozqD3JijALFJ0U7Ukv0uFieJ16c5d/rCI8scluSbvbRFbhssluR6vflGlG6h44PE0v1L1aehIANKeQjcJSuwGgBUFNleVrp+PcBWxq45x6tt0YTNtUh6kya7DVlNJMCAAwAcZVyHWi8K1gynpm50IIyLOxByE6BoFriBHrxHhNcgY6eZNjNMYb9XN/jvYv8QwfriF/EQKegg4B6o66JycYhQ3/gt8TNnbp1ww6pQJB/iMzP1UdAlQoyG9/mDg3Ka+NJbtD+ZDoVVWZIP+3VeaOqpnlsf2PBdz2cZHwYETZAuOijAIAzNGsbHlXe4jpul6Isq3L6V9z+S53FV57s2dYur2pDXToHok04xKlpSclUQCAWtQQRD3ZgTpUnE1s0KhLewDAZF57QdJ1rqUPcxgOh3Kc2TpUDsTnTYZ6SZ26LYJIdt3145JnScv+tSRc8pb7FhtjgQf6vRj++ubchl+5sg5v9gEyLz1kYmWXk62IXeBlOdlNA7fTXAIA3BXC3dAN7g4qlnMQpmH+jUrIe5qxR/047jpiuT7FOGsrJx0bGcfNGL68lS4nhNEu+gAA5vImDjGNuCyDjgTaXTWQggSvl7IAAHABIkrMhex5e3g6EjGxmeQN2beiyFIsMcXT9hZ3iuyPG+xLwkZ0je1mWAbOHxQNfKQpTmx6utzIWX3CX3kE3jpVnVXcTXJZCUe/tcVqnzf82BTL1RHGinX5gk01owAAG7FypjoLb2AATgBlas80DSjLDDQENMWSNAH2VG67rHZ9nrYUejhRlKgUI1qpTGTGF3BJr5fDAwCcXlAK+1EKkkWrqewEvULy2BZrcEF5WZuGkObGuuqUfsEkKmkb9kSXnAomtUSlWMAa3PdzsXaHIWs4UdUo7dmdYd2c+PANkUj5mKNI0finPMZ+7Q5msZJbXywQAmte7Cnnh4AIx+4TS5oJIjFCTBcDy+MV4BASLz0JALBuJLJcajcA4MoQFrF8LJ1nmNgilrLejmU3h9yVoTCYvedGEsw0EgIAmCQ5IpvLtrRwFBa7UcG6ui3NGr1awncZ2ga+y4QwofRV11jkIzgc831wRyDcOfZ9wuF8ujaslSif6D1qlWhvh0erDpx815boU9Cr1KLjboNFyIRZ7GvDwHIUp6MAAAr20U0nSOBQBuBlksIR2mzXma6B0G67BToSoavmSDqPxezCtWtGuM/7f56GAACIsTlRYnxOZSIXyZlr1AYAeD1DEM6oqJj9aA7ScNpM7RakydliXc/yg6hZLqUDyUu6a/3qPrPClqjkqmgU9+kSttRiwKbAu9ie6H6RzVoltjmJKhJMBLfdpUCIcDlsFAMRicNDGRAxu/QkAKAiJHFZajcA0L1Iiqf7kq4xPKBUc8cMpKp2VgRSHNZiQgDg4oTUauPSAlHOYKZRT5Qgo9K2IKOGsPluuPIquJia7Nufg4G3vbzgle+an/rvjhIrkkdV8vSiyY9lgfZxkXAaK9ey5KKIAgDcpWVv9UHkSpghSn0tAS+jlbvU2vmzK/RObXBA79VIJ85ccydtbi5QRKe03cTCKVGigz/+PQ67vqfziSqw0toAQFIrt7eSTrjssPD1jSVsyFzDbt8UKhDfeknToq27Ma/VLILrCknIq1vdzfGkfZYf9ZBRkydeukarr4LTHYTj3U7fmBxSsz48bCRP1SNCuQWUAMCm2Vm6GwDqgOI+9x4Jq+Fm7uL3eAcFCoZBm/3YTPOXj3u/dodfCq9c7Sr9478LSSSCQ4BKAPnt8RFmePFS/GQXvScfH5UKAPnP/GhWjT2uNvJPhw2292QYi3DRA5VSAAABI9UbVTFgYAs7yjNoOSDSoKFslJSKOlgwcduCqmxaW6QsEoh8IsEsxgMAOUAVkBcEcwY0HxcY4dbg8Ddo5thf+Or2EaYtZpAaF1cr2j59eY/k8Naz34seqeGRQSO5bhwydxXC3YniHBMA4ASoiwakl6g5B2F5DHDHQOZqZ6YHyJWuHE6sOcdQmIotHwvYqf/lXd/fFAn/IrGkC+jKzMsKG72neWn9SgIMsZb0gFdVW3Mn8JjlLAAAywXOwHDZ61tZUxJXozMvs129AjtniVWVBoJQcfffVak6ZognkNVP0rE+MijVuHUtoVZ7UQkaA41/VZxg8FE/kVvCOfkeIhEmfDpSQocNvw/f8R4uGSfp859wPXeh6nPW+BNxc6zfmDBuANxFcVoKAOAKDfUecH0lwJr9vJReqfpsVeMvb9s02OAtTaQ9wIUHXWM8bJOTKS9s3l1+DE6Zs0mUO5/eFUA99zqJEK7rFSaF3oZ4AEB0V1IlN8J+jBxRODTKapqeY73IUFli805CgE9geLP0VnmSFnsYwPK13nD62MBJa2QKhKCqeZcDUHUPeuq1xJBt7MI8D3lu+yBlRJuYz75QuY4eDVN/v/mwJRiiwrOMep/u1Qw7Boqcn6jpOpjfhm/FvzwPNuLtrWabFcXgVWG9nBXG/FP3N5slV1GFVP2BcohbSVCoXrdT3gNr7w3KIMOut9BvxuXNTe3gami2d2hgW7A8QabjNRuaaAkZkGmRFSH76GMMtFKFF6VJ4Uk/YIv/iZQooCIDM7pFPSQzdF2/py+WDSQo9rU0Q+FWmX3+t1DKAxY3EyLKkl0CC6AJmtF4eRiEqgChrTDnsh09afuxJ9csBnUPYVk35msPV7WwyOp94BCpCvT7TvyTaqY33Lgq5XAIY5butFhBbjePXBgoRYpxNObIQbCz3csteRS/Y0EWHXc/4gp8MA6BCw/mcqvz8y4kSiAYbIJFhjzwzQ5mXg7Fgl1oFHSKB1FRQ8hxY/qFJ8RHJz0PfDInOMJNxcuVPWiQ7nfORkOaaKIRaKEL8U5h3cf9ad3HCa378I+OqNf707oPi3wrHIAew+4tfQMpqChw+0EvGZ7pow/ub0BNi5yLvx78hDIKKaXMOUxKEKYekUoU7gfrPoYWiBUR9j45q3jGPQsjh1z+aRO6Bjnjwzj8El9kRqyraAuDfhWNNQ5YuDmIVjteui6G2rVJChUNWOnidyteR21FVirTNPBOzlnqOQjmclsbhdH3SMKeoktqZ2QQN9OLakubJS8mIGcB6ZArqOPhJXwgFqOiuycvMyMcatrFJ2bLsKAkuMb6VQkBgNzKzcTMqga1eAGOsqz4cJdkgqKo+DSXZQdoUfENL38INKIyXfvk4erResTmPg3OhDBdBdj6neA1KyFTSxVNuut6XZv8wHE1H3xq5dEiRPGueZJ5Rcc973b8I5quLGvS5D43j6or2+R3nrqKnGvVGOqyeEDPD+BhmkwoL3CfTRF7Xy7xm3cRKhw82Kq1Pj/QfJWv0EPRiRbc7pTb4/FqWa1QYWdkMWH25IuiwN7lKAAA+xirKBDL0plFqEz+p7pvwFjp323tmUvrTwFczQxcAVxkSa7FQzfvAgAYCrfHiaZu5oNNxKFVidrrH3hHarggHgCwJBNl/lh7wezEKrysprWgqMLYkiX7du5JjKm9txJqr4mT1QxYuElUS9aFnrwhZ5MowM5E9BI4tkOgBoAT9bA6MclJo376/N/FYJSFy3Vtq9Pg7S4nEwDUZ0hNt6dijFSLjECcqns/By5c2VhxF0+UCkZbvbdr/l1EouPM7GRskga1MrxBptUsW21kOsMgpAZZyLlWnmwdqBH3a7xpiG2Or1z4XkcTYqL/hS6wEvOvVTF07bUi4dtd3LLXvdMoAIAd2XU6zZlKsiLAHY7bzur25s9ce/WXdtUGLrSrSnJxZtT9L14AwIgCS8SKibYoXIui2cQJTTG5BwBUkFlhUuoWP76pxp15Fmfyxt44BDPx6BBTS+2gpaP33O0xtsjH/u0dqSy6UrDhOtScTxxBQE3QhCgWxrJtPUglqWpkgJrdNmjmlsoEgA2EHFMdGkoQpICMiMBd70UycRc2MGvGYVenseu8jVaekEL8m87+AEIM8TtT5989vD9lOjZNbhqj8EIG707iqQ6t03YLLYYNTCkFABigpbpRrAF3odnps31ZQGus2EALOkrSgirxAgAGpi7aBZ1NHG7oS+4BAJ2y1DAplvwRTS9zEkQoPjdccYBcT79lBR7BfaDZv/E1qef/onV5e7KR/4/t5Pf0CzxQ+7+qPP1X9c3e17palAmNWjQBAEBUmGFzFJrYQS3VgFvoNTviIgDHfqowrVLB+DuZ89x+zu953TiSprj7L+uPO6uJPq+ykAMAwGhd3JJaGW1w8H+vYfXZpBdaAIAx+qZyuU4FDIaSBpx5o+tY6ysxMbXW16qJ1Ky7ir2RUMZ/T91WKEiT+YGjqL2fzz/hHILfaDlBfarPwwjhnUJLzm0XUgCAKtpWcUMPQxQHvSiOAIvWO0s3smfOL+MtDQuD0SJZ9hxfazCqOwGEaWJ5FwDYwWhcnFF0nEtLProykWAVXhQPAHDxO2UX1g2yB9WH9CYXH6ONBXysKSXi6/R3hO8yBBKo1cO62lMDdm6yBduZ2N4ApBwCGgaoOGw0l0/T/10MRq3AQdc2HYG8Xk4mANC3EM1tTzlZJK0wAs60sUxy4AJruYqsxlS0gppaSAgATGX59QrWroVjGumTixk0g3y31hdazoZb69vzNuQgxIbqyVTFeM7P+6EhF+CDRh6WG1wf8aE4lFQvVYwDFc3u36vTOeHtZ1Txj6ejAAAqHpVTX52cnsoEVDNxVTzzzJl/fWTlSgZjZOWMpmPYogCkcRcAwDY0BXKiaaaBlhOpxqpE9wPu/46kuCAeAPBKpmW6WJ08zIO+UIzW9O52o2RlLbHTzeQlNag5JhUWmJ3idbsKocmKUyj+t1EQOpJQLMML/fhSJRT3GnpuonCa23qVCFY4nxVWO+eES6PG/5PwV5JjFG7dsa2eQapKy8kEAKEbUrvbU3EbqfZ1DYpXwKHZijtb5BQxUUMhAMCrZcrpY3WczSBNPaNmkLaZLTJIrwkhk/HEninzMcz0nzcDTo/z2RgbWqo9Z7SJof1NQSycOWQ6SokUAEDreTj+aCM/Bim1SwLejgZ1eTeyo9Kb1chc3cWVuZ8pf51qVt20ijFR9yzwAgADdCsuygvaOvGcqcSH6r7VcArxAMBokSx+dgOFsgjDmpOoZFrk4+IqZD0cqFoKDc2yK2ooeL9eyzEOKIvgHULLrn0MflgNbjpRfbQkAbSgwnAK0XaYCiUZ/UPfWNntSHdWoUwAKC0SGHV0sLKDq762BIrdk9PYYeP5CxDvGAte8KL06EJC/1ygT2p9ANGGeH50zxuWpP5ojzHlEiqVIw0J+tOCHkYMZ4pvPTVWKQUAWBXij8Z7YJBSqQbcheYyaARKHBiAcBqgS7wAQICKizJDn4fqM59YXMdiPAAQQBUQFgRzBjQfFxgx1eCE77oT8aG1hn+95Xg+xvMXOaKLqezwhuK7lqc/qjx4YZa9HELc2NV1mT1F6MFFEwDAQMRt0IMacEC98/td9tQ8eRs4/GBSFZlDFMve1d00hqHsblKeWYuQ8FFBMdFaXny6/Jou6idliJ+l3XXWcr3WLGpPXXl5UI4NLWx4V8qNCa14+0nhSQkOEAKyd3GFiuo18uLGPC+8MGFqQrFj3kmpv67078hXk0stMi2+frECpzezP5xLzKqmaqr+BIwIAHlx0mWje/pBvMGCHABgKMRMgbHMHJOxRSGZoLLmvMLsI3mdZhYAQEVB8pTposztl6cjSUFspm4WH/1BKVsPVEEcQaWYe6LeHZzl1vpL29NBmCA2NVDrsLRGsA60Uofd2c0BR4OG3DvDvOoIWsBXqc8/KWXy6td56555jDWs9IKBNcgXZK0vttHbZw6L7aiJj0RqozCEw6v8WHSlmhJqSqRATNPjaCEl9KYqiKQ73l9EeRL00EAN3JG8B59DKynocr5jPTlSDj6WNkLiMEHZhGxGciDWQnd3go42qClbafoELdPTDKM+/PrHeW+Iw/tdlTu5vqxiVkqanOxXrlg9QVTfbdZysCRR6mYUAEAaARNohgUb1yYPJIVYNgHFLe4B1Ecxhi+XUo0zYqzdTqFdJCR8VF0j2qqN9Ezkg8Mkz2lYRF/L5PHRJp2uINr+hcNcT/RitpEddkKCh4aWVF3zLjXuXw4XTpe/KzfMNa6xwnwF58PaMBxDV0J+hKulnP6E252B+GxGD6U1Ert8FwDQhkHX8iPOnlG09fitJ2NRl2heeaMiTXRDPABgubJ8pQA2f8ICOpHC7tuRaXaYWygUb0dWXCARUGjejnK7Rt8MEGfsNzI1hCLFC0MgQ0BY5XgRU5MCyrcqE6eQko8PxIWUprVwkrL/pFCltM0XM0RKN3Xb2WPgTkOZADAgmNCi7pFBpg2Cqw3NMP+tdLTGyu48xidts5kQAHA53Y0gi23jPAUNdu3MONCwwrPHCw0JBjEpaJXpMtsRJaPsxNklyHI7eR6H+EyAFr+Wu1tt+t7CSZCs/r/ONq6YFQWqy4bqrYWpLdVSUwspAADFht6u04NaSe5T0RpQ5HuGETJrbi5gZQYBsMQLACyomOgGejrYU4n1xIuDldwDAJr07YFSVPQzFfQdrKC5A146CsG4RnTvQch3ggndi56+BzucCEwxwnndLnYfcElnIhsD7AwjcGUO7aN2GZtrQe0xRteBuq7ddhf+saFMAHALdK1FNZuBa+sGTUCphKGE9aQzzU53X4hSIQDQYIW4+iXXwQkyPbSiHrDIHnuw4wd7MHkyMNDhKrwhI9zDMe6C+OWIeUU66f88q+/5bW7dywGKJYYbYCkFACAwoaGjCxYFSTgRSEC5uQUnMwggJV4AoFF7WjR34OQTl+u6GA8ACGwBZLCYUyD5eAHV7zrQDF7gSAHQnu60i91p7NkG57E7n9gb3yRlBYFnVZ0DJdhGB0owrpauzG3XaTVwoUwAoBYNGLV0sHKDraU9FQquNhPfk9rG91ypqz/kOwT2Ff2wRbbifQr3p/RAgEhX/K4dAJNcD2hetJu2v4D6iES54v9LDbPOdVxpeGK4AJRSAAAAkeoFrAgEwNzcgMkMNuASLwBQ4ERFj2Z9C5NPHLAW4wEAESz5Ixpc0Gxo9DqIUKyDlO8LiF/T1n/2LCb8d+qfvfXzbgzq18A/vhj2xwCb7fLg95bz4BvVQeTDRAPfs50lK1CV+dDjBRMAYJZ2qrlhmsbZkYMtCwKQBbuE1bV75mcPPbrSByhaGu+r6q74MPzus25ffqCBnb4/swfE/1X++1BdqH41n57m2UV39mbKtBUa2mmbMo3pijBXLQnXETtN1rJbid0/qYtdNeobpJrXZAEACO6JN86opJvmSq6FXDqt6U59KTfLta0uNqRy3fe3l9E7xFJQxtJ6l5XlmwRl3FqUsjiR5/hA8mtVILxavKcfPQIzjR8zj6aU0NEUTq9YsFYCk4oaMWHNAbo0owAArgLCMdMz3fQbIcYmoPTE498wUXHN1csxAqmtFVQVYBekfFwGOzu1EwAIaI62uZxooaSCmmx1baLjCXe16l0UDwBM42vzP+c+S4rv0ZvT+KnCeCoMky8lrfE+wV/o7xv8lSlwh7fNvHCDt6hPxC3ekBPogDfibDrhjTmjzngztdu6sDq3oEwAqGKgk0bt4WGdKgd7GXRPCcU3pWykNMvNhACAJeBgC5e+hhWkArOyM1uuUIZptsCztwaaxTKI7YL2wm6yA8/1mfYPU3HjUuX1KQBnOHmBh/jMaqX+RvfOlLzGFyswVv/5nL+qwNpM09lQw1qYyv3LNLWUAgBQtGHq9EzXU+FMjE4ApdqfxL9n9oXJmpsjaq4W5B2kK+oCAAInIjqQ2unBmkoswqGsG+YS8QBAffvuICOXfWTvG9vkQmal8dMDHYybhpAOtnwH6OB6noLlW6xwckiCBU4vEsHwLvLqlxUipK5Eqiy5bXfAVCB3xgqbPjjaSZ3GT5erYy7mJPexY9tc83aj0UwmAKgPafrsqfd4u5kxCHwVTEoOXDSdkWJlivj2HlSaEAB4pvs7qADXNEPvQYaZdI7HwY6zdXAiCB3E1JznlOvllt0FxUOllxDdpDdXOB5bcZf9EyOGg9qlFABAB0CqB+UqkAd0bs4AZwZ5KC3qAgA+ELKIIPOJAqcUDwBMt+3DwhFADSZsdgrqHsYnHwss+W6wGTwghcCyITCnXeRuq6UdwSsTyWPjVv6TwOTENNl4g/AptNhBapOVjAWtZrcn3FAslgkABRanFo1XEGybnj8GlxCBkjV2ui/HdD9v/xrmsdqFjZTKBItmxfcSFEjigQDRrfhdewJmzdTXA9cuZRLtdCWyFf/LTuD5Jbfu9VpBi2EDU0oBABboSL3ZSWiBYsAdK8CCys0JRGZwARZ1AYAFOyrqvcdZiHwiwSzGAwA5MAKoAB85c+CyMWl88l1gMbhBsP/ga70JnBvwnJXpxVHhNbLd7ylG7fI9tRH4kDISAKY4gQate1Cx0nMYOyWmaQiB4cRZeURPolI7P5cY/UImFqe7Ptx3/mWSDm4C7Hlb3c4bwRCm6nPMAqbyj/fYoyx8Pw9W77Z5aBpW6sERWsYBCUkKeAXWLb65e3yvxWCRRWniEIzl7Qhf+rFTQr83mCUQtK1DrWnuwj82gX2cp0vK7f0a1a075sa4iCnp6FqsoRcVp9w98OxdpKHRn9KNK15VN3oEIzK7mIWuGWyVGuwGfH58x4KvDEIVM0FsFm8AgAZKzNwfK7L4dlFptgaVQf58X62yzAIAREdJlnTZznr7jw+6Pg3I4MydDgg9ICaG9wtI+lDr5R2brvFXBIEa4LFH1uJN5c04CEpJNg2d7DKdYo6NJnEgQMyzHVxKb9MEHa7ZW3tum9WxwijycNI0itQ3Tseox9mncAd3S9gKAAvg4Bnm8X2a85Vj852EwM6fX+PDqV2BaNC+L6ymBfnXy8rqC87WjZkp7GZJFwDoQGpBlNOxqx5QLjFd5xYHWdoDAHgoTxQohRMl2pWp/K6jBeWweQh21aMmGNsDM+swNzJw/yeYg+Hu8zVkjX+fYAocLnMQbIvFSa/aQg4ul2NGsexGKwqOblKi7ehmSjQe3Wzy20e35cUyAcDF5RmyattdanbQoEvjVCWcnnK8G+okCgGAnj2LpRmWQ8kVbNGZZfbQjsahpsg+HeLVEBA0midLc2eZLlBPJYeBwipvDhNL8B2sGeN2zkTsBPCbzBUA3k8zd8L5lf4BFAVeedXP+pya8zsaJwb9TGdSFwCQVIIoH5oY6ANyKjFlvHYQyT0A4BhVOFAKG5d0tLP8igqaDUJ5BxOGj1YfboqJfR5AB4FPSAB/fLBY0OHfW24JjfDS9pawJex8oti6E0lAtu5ZyUa27l3JSLZGKbstXjTAYpkAIDpOsWpYczY/GMiSKPMIuL37Qk/vHbvJxvCCOa4rQwAHxDJztFHfg4iyvb9wI4iMts1BTpQ5UHo49E7S3c/QD0Annn/AwVGYJm4FgAUF8Qzz+J76M3cZZcEisIDOzQVkZrAAFXUBgAIpiwwyn2ium2I8AABwRA/B8CZofHxssLIPARG8979uBxVQPFzcElzhpa13YUso+USxdXskAdm6c5KNbN1zkpFs3efsNnnRaBXLBADRMc2qYc1cfjCQKVFmF57dD83ptfkYPWNU0zVv76h7ErsCwMKnSJNzAFH4eD4jhDIktZVbYwT3W+YdReCT0BUAFmjG08zt698j/RelKpAHVG7OAGYGeSgu6gIAPhCySCDyieK6FOMBgAYjegA6bDb5hixcNhaNL/tgsMPrkauPZ5Hh/xTVx9cy8jhHMpzD47/4Fx99uptiNG6wG0M4Wxt16Kmzte735N/vgqq3BxDt4vuLXcuP+m5O/KrHNQOEt3e3r3MTR7zVhdiXtWt+OywrmazPDUA93Fd82qtWXlzDyREPXF0sFF2rpHiSRAqkm9O0vnks6JXW0auyN3kfrYqZzW01yFo6JSEMGEDoBHISrfXXnaGBn2PjjPi+NnGstVVr1s/TIu6iYgQ+YbAPYGN56wZnTGXU89pAVxIAAudXACJYLd7u5Hvn3hQsXE/1FcZ4gX0WQHXr/hQ/PRI6rf9AIZYYkUnwuCN2bL5AhOglScUiRHdVXGRT9J9hTa0H+dZKTgIfURn9ZCuJxD1q+feF48pEzVHxf6ZtDotC6aiPBpTXnYNmibyhxiWQ16hJGk2TTk5j49pcHznrISXLcPjoXjyL7qO12v4raIhVQOLpe8qCLLNZZPeMTX6tkvcoY1N+3Lg+clEl6S7CRFWURYeLjv0yT9uU/urrwkbNt+Ms+ysCjcAKz7N1tc6uFqHVQYvQoX32t/je8bVtNyQQP6rWCrvAa/vDNeWZ7nnOsDUxfEVIgQxzPmSaC5kFfrecfUoKW/lHUhGY0xBayFMsQBzRTW9d/5m3qdcTVj9/h9BZWAf9ScJkpocTjamoWmXZOJMEhuMGgWpWHGmUyE9msihjgijVMayAsVUeG8zpC7L6YqEHGeBIIiJpAW808RWYRE6HofNLAmKkXFs70Nxl/70AMe1jfUm+wKJJxLalbtlCU+ABmc2IWeVjgVYyuIh+SrLeyQ9DXUScL8SpKUA+bTEtCIgKOa3jvWSVu0B/3AqoqHepvrEA3nB0LSQxy3dMX8RpZJ5BSUMAqYumdWepHnuI/XQewBJXXw2mrjhzjlCehsGI6MSKvXqaNFQvncKU+fAmGIGsBHNDlRBk1eaU+3Gvu/yN+g7BRp1z0FUQkPXkZRjxEzE3VLJZQcFsxoJ5aAtb/zLKbBpk6aQYjInSGrQlnrnzuvOfOYV5qjQtT0XJd5oq+pYJmV39gxMgLlB9uLT9vNhCMpk7A9PJeasWPBbOUlxIJEBqorrIesY35MkdxrFj9WrFDCDCkeyg7Je92OW05tDhKwiEnIWGwKkRpXURVNugtDIoMtm/XAKxpYZnzkT0YYnwxifqwmBJbqW0PtTNZvDU3te/d6b0Pt0X6kNuuKGHIxKDnyDu2Nq9Y3DYcPzDEtHiWZFDck++iCdgE9esQsy40FLokvtZ61HRKCrLTUIfBssNEEmHqbqfik6yMHX2w3v8hqGXdqyQjp0LDb8qhT7G/2Nvu73a78QS+5pYL6H5r9inSqjp8DJNqLnqoP7NvdlQMYSs0W3lopkwOX8O678qIepfbHXEH+ZGCq6yLd6yUA98mJLRse4/6Keyoa+zBb+bnzYhVeddHdxu6zBFhgxX6d63qeoJ6K4wu/seG7C+x49C6HWkkMTli+C1RBMSUdnmAiFYPRAPDHtUHqLPeReao6lgFEeI3EhzfReP1gjC8KlrdklHZoSX7Bj1W0Jnj7Ymv5tnADH3FDh+nVIytDyo1grvA0Do1k1IpVgE7nU8bFBDGRZD69nFSy3UvJf1OWwFrIhmWt90NtqgBDvj0fNHycyDc9QRRGvvgGUshqGtX42vAsO4tSt1DvJQ6UkBEIc+aXWOTVa99+WbOxDhMwRyYCZY7zYk3oihjI4Bj3kL7zfJ+BKQWzHwKH3DpQTdqeg7ED9yoRnQNJDCf7jcillJGhJxBYjYAdKwAaBsJ18S6D9nXmo4/0Lh+nPA8d9ZmIKPXeTN3dBwYB9C0UZp3KYoqKdEXz9k9zMNeD/9a0DyAwKKOmik5CAYeynb8raKJhY0Hc1g6fuEgWwmDO1mktqcDtBQXN5nqXnccYk8F1vfqQz7LE8mGKhHfkgsgwrUyHhBBdQO9F0QmHPB9MQU/YoUL/aNBXi5wPbup2Oa7DLrnACEWxzoLQ9QcTySOhYFZXvgQXcG8zE6q7xukivOOz8H44YT7rJJikywt0kwt1viT6vxy5oDz83yTouI78Z9Ux4EDbiWewhiI0fXSWVKSd+nUSdo2ZnBazv9m/rI9l1cH06KAswFolWytH4qZgmUJoE+lawZcgBlmXclXECDeU123a198j4H7Sq6GWUOTmj6tmqPJxGlopoSbbSo04Ci+jsTiUrROSNhs29ox7p2O98gnnrWh0S6UopfF8fRVZG6/o0nMEt8YpJH0iYKH3oXtdURpgo+zZI0pOnsWBZ5ha+gCftYn2KLHKSbUFQMC49QBm31FifBBwFENHeL0iTllYE5hRs57GbQ0LCI/z+gc5v+qZGBUY9HHYBU100FmUDfBVpn2QrLNamEbNhNWA+ynkyYvoLkZw1HdlmJ0dBB4ZhdmB/+DXVx3/Te3NZymCwMGM4MACcAvRGom6bwE2eKhIqHYVOtV2TgmoQDYw3qHl2HwrD+tM2+1ULm12r5nr4QjRzihyLnP4/edfJtsQWxdvD9YyfJxv/OeGDXhlF0x59Xv+UVvZm9XWFedVoyfQH2I0ztSxo20r1ZKcNmYXJC6PmIRwpNZp9S6lYVLsiUe5jR7JE35OFk1Ozsgojavt1k1ER7IohaZnd7lG8tmreZuYf2C43UlDQOfKx3WICBfv2VmUMjfcmdMTRyJOZ+KZGQ1eolpSWsOZ4qVm/qTnxP/6pP528flWdyglLkU5m6vnxPWUUFAptK2lE3ulEYfoiUlKlzR2TZ4EbuZDYDZwBYRfpZzvraIWXfTgZGt9t5YGE4435gov8/AwAC69pNBjLaXTJwe7sSckCDL15JSOvAiswKkb8HZr4YSLFd4EOchsPx6SL4efP+zAj6uIh2tqyebeyKLeqWraPrvGNyalt0n0tqRy99JfD5NOIPi4QCuTSTZyCZN0z+k9JewzvYJKhG7Kvkb+C/VPzjt3To9L7d5CPHfeXJembyomMU6pqBrBpcPgBncB8GdHkXgBPdZwEt7v4AnFtN0Hgz+wBM4RpYtPUuANO+Bhal2K0/DeT3zp9CPzGBb5MOCQhmi0oUuC4oHJzeUqkCV1gI22uNUzTGm2htZcG/r5QHAIYtTE5JBObnIiy/e4LVSVwaKCltZzKRuLu3rqBNp/eIkDZylGZ5iKMqoI01UReLUOSCj7DIgoEucKMXV4qKb6PKqT8HAj1Djqx/H3a5Fs8Gi2FZ+QVnERFZbSKHHHUN4TdjKApEeG9djAnBN8VfZPXMWsKxZZFvEb/SfJZOfvylx66TqaA2UjxdEG3TyEsSoUQtvZGkAxmzSov9x5toHtyz8+LXAiW68vpsbSnysrUogBb735H6ym8QdV5goZgU/qlQSMj3zjAIVzuFlfZP67IzcKUqA9hWiySaQiksO6PW6oZFO+vkQXcTKJX+asdnsYO7k2364jUgyVxH4jyuT3jl4jOFaOd4PCYixU28cAzA9kxmxEccZ5W+vgP7GIguiEjJc8x5CBsyX2gGQXvtHjQN7C3qAzjYxrKe0y+8RXAt7c4qEQixhKmPGUrUVqHR1/z8iMlni/EVOA29I+fINkuIQEDH59HwqBSfmitPhR/PM0RfBOLM/nyc0Nog1BON5D3QWzrGkMLaEbEkwqTR+V8f3y5gv+n0zn5M850OGBtfAApiQVsVfwwXEJVCH4WQTAl/5dvKHUF8UwJeSWeMRFdgUTnArtnOOdusnXNyWne2c153bnJid8ad2TK4GVI/a0jjrGKyxNhJQC/g6u+U5vLvFLv+O8c+gM7ufQGdYZ+ANyA0BBLy/OULODoFRJg6VoJwIUpx1Q5ZlDeqYRIVFgcTza1wmBQ7Iff+Oo6b7nq0qyjgQSqJSbUwnrDfOQaHtLm1/1GHd/PueSO0kCCUiSxb2Meps4Bad7mIfw39a1lJi0VlI765sx+ESHyMMyLHtuOD0QTK2yLayTMT3spDbUne9K0rp5iUA6XTrEpMk0tzs16wkk8oZzMhe8OHHoWA0sJIJsVXdjWnatsyay3IZRzCeqwY671Eza1dvLGVDCRJOfQDe0TMcB+sHoNJQemqQa2jjXaNyVlbGbtDQ4rfXSh8VfcN6N4xFR1rcp5Z4Jn9OCXcM9NGjSWbZIrBesmF1/iN86BGWmtvuQKJcpVGyYqbTdqAscRuR7cAD1d0p9z5TtnBGAYDRwqt+9ySNJvONDrn2TsDj3pWzmhQWN9R2oF27vxz1ZstYWeyUfI8qFMm5r4MDo+Ctsr+87qX0hum3GVWMnQlG4XCKSnql5PcV/e1RK0sW6K3/viVL6QqwJZkrPRasrNa1YLJxCg+GZMCM0dGRTYrUwDWo88FEaDCcG70apOyr8mXjNXqk7Fa3i6NKI7DKxNmJAwVrMlqh+XWSFHUOrAlVO+1ZGKWliI9qia9ymoJ2UHZqqmWJNZPLdFzQEZDk2Q45f4dufuyS8o1FRlzScWW+ZMeT7YpV1TIuaDiCIr7ur3KycRbtD+jTZyQbYnxmJKzKZThW4vzhdl9lTFufS6uqRIakE5ZNJACeJEQBS5xGgvljbLLN12Dk46bL0dx8TVwgfyy8XfXztmllhRfw7TpInvu/If6SrqmIuEr9krZsr8Ejc0Ts7hEvkwtsUEfGUterwtS5J98OfW5N1wzR8RbUgdCYq9GpuZvp5gHNEM5lZAFJCgJXbElXuiGByUFsMUl/yzkL4nILR4EgzmP4SVD9vyBVOu+ppTAacGj+v65MAWLr55QTV9kMTCfw+GiTCPM25vmGY/4E9+yD9T4hx4XX8pG/iT80Mx8Svng1YFTYKHgtXYqFz4CoTLA647tVU4I7tyfqyMsZX3XHfbFqSVtvZbbn9Hy/ORLoKNYofGbgo28BLeJapnGfgPig6vMrYu9okWpg2IzOyG3fiXpFeW834Q9yuNjJRF0nRjE0fZ7vv05MmviuhRP1dQP13cpQY3Ikf2AJU6UujIlOM5LzEXAi7QYN+iv1OL4Jgwau3Tresb39peHUu+2w591fvm9jY/Ivs5d2VHqqf694D4e9Hb1JnH3/Sx7XOag75knrm9oEFkEfZOChrCJy6RxVY+mUo/OKE6M34npq4GyF8enXlZf1ZBQSj4p8X1PA7hdkMREmnEgCa4iE8CU/Bp4oVCI5sKRaYp+tlQKweAJoJHwJpU7fHwOEQmhk/ntgyLZIGJB6ASXF5aWA6pT76qitdCeKT2QTYcFbffZ1s/7pqnywq3rWziqIKyvGnWIqlexPNQ1nJ+UP3vNTEIzjQksk/Lvy7DvKzGlLMBK/bC2AFjt2Ce+g0kg8gXdVfVW2wk7bstlfOjQAniWAA5wENiA6eLHcmubmEzvObFM+m6z77tB2qlNNcF/EKZWYU4Ty5gjOB0uBgt0GiGcofPoxOJgI0rc4oZRvCWB88saKH8wK6IFCRf4WgmuKMa9kg85JXjvEFKptgC+bQC2ADkDIISw06Li6lgbBlzSOcTlSitaDvhmAdyg0eFisQYARUSlXyPXgqGZdImceg/s3rWzr6sweDPYfqBVDKbaAvh6ACJtg0lTqSZk3mJbZmQmr1qDjAD2hwMGW7fRK77mUitexpHlc1msfthDomF11HS+hC7iq4IvNJhUmg+ONqc8l5R0QmPL89cKWUdTS3zxP8T6bgBB/DPok2JZOob4BOVxrENbnShM98RMysmfaXwqnbBlKYEO54w9X4wABB1OY8eOc3zWgkCodEEh5HqSqJ+aWLVmE//JKkBVrlqdjiJD+Wp9ukD451E7eM/As1ZCpOO7NaSZ13mh8fqGkFptLBwQ5uZ/4mXwf+K7Z8hvL8UmOHxZ0xWokU6fXq0BbuFfC/Lcxv2btgYYUW/YWLekvdmoKxN6qXV8qmEZdfj9d+CAzJudUy91O1bu4og01lJkTOTFHFHRO9frAEkHTzydVJwAQFDCC5wh2TOK6+enMTnXwVNK5RvCOWAFB5I94RgXL4ALTyk1CHLVgmKpIH301fWB8ibto2hKqRhhxQbECESYwtmTffMwaPV5lDDippaKi6GcQVjSBboYG0AODD2g5xXgTQWzKvPV/4IUDNQtRxdMrVYCNU3lT7ZZT3nzCBBAYK8F8DEFjD3RHvLw3sIdSE0GBuhXAELBWbdzUzbxq1A+aYWnYEt7PIxyZgF61g81yJa18fRK+hEl8ifpxh+Piz/xC5QFTuGaOZJsaXYINUAved54PjbeFwUHS5w8kc28cYfGno4OJizliCkGweF0sazgAkhMF/MPxIfj6tWUe+Ve4CTZW2Azf+zx2dM5o8ufVzqdYIoJazr/+HB8sFhuUAJCZw7nm388giN/2eLT4QIzfDocTofzD0ekw8VwASqIMQUxBZ+gEsJMUTv36ivJg5fgcdKsCT6/7IFI7IlGfM7ZE0JF1ndZeh1c50uDytl1k5Gj+UagknbzWfiVteODp9prGD3Fgtek4I65leMugso978cunBIfI8221n9WdL51XyAVAoOdDcc23YDZPt2muhvoS+NhdIbUuylyusTq9HIafR4dP/1zwFurCzmnm6r14eC5Z5cyFG3Icp8oOmLk9xGiQ7ePyOWRv+CFxXxKHhWR9JXwYAj7aqzQy2HtFX4CAKDzUwop3Kj9nAr+BK8I6QgKQipCA4GIAB9BB09owkQtPHUtCgy3wfSvtCzG6sABoxRV4mtaLOZW1Nyhj+Xady2aLyn/yRJcP86JBX2JRXWvHh5fH0N0QTujs5anK1eD9TgfRhJQi3zDL8/hC/kPvW/l0yvzFWOuT7dGZWE4gdFVMT1mTkbBjApPlBihJORJxsYKbxSo6b8r2Ow9WrA3aoEFmxxLGinRqEjEp+FR0ClQN39bcNyzsT3m73wUWguBiACg+/yVXFrBKv9tCbcXUq5bz8Dppkjpq75IvmROd0fGWVSgyQXYJlmjUdOIYIfAQnCCHm64d9LUPqk6KO1NlLGPsiaBGjNqkikJxKGnpx6dEHNlRT7MBRZL1psDk4eR2gN+RXt4M6hZye2qt1iP3xyAkHb6qv2eABhSnUVPIfAUM0JHPAIAFsrs8V0BTIRzxLwph/SN1g9OfWku8e3rCXY36mYvCj41ooH7Y57cpc0s10f4Oc2+Fox36Xv2+QVnCiQEv17N4zMZZAhE/Z2259iqT2baI2Y86YwnA5225+mCdNl5YZKJpQNe8P2HzwAAL1Yz46XcICq45KiUaLaHEzNHIPyZX5f0fY21m899lfmKUfwwUbdx8cGO0E3mvTfUPUOIkNO9FDKA0ViJSQCz4h5bhvuCY2foju96LsPldrCrolih55QtV4rMRHaruo43hCnaOeKBljBczeXNkUm4E7CsEIgnWTyJHry2askAXIS+mt0TV/xV0QAA3W6/ay9u9c1uGkW+QTRnPMqcZXmIyAVr+mn7Ka8ERWFD/moxtAiEQoBTP4OmsArmMYz1Dmmyrt2cwUc0XF2mzHWHC8EeB12GF6FpolsFosagKaJ7Kz2/GlVi3QJxYC+R9Wslt/w6S03FSVwT7eXXXUpy9k0sEZAwcQZXhNsDTWX0SRffyIprm1dJhFynuhD2ObfW3jn50W86OT0J/r4XmCHpKqLHyQLjhhIcnVySdhY7Xv75xrapwWY/MFfwPTn1wjSgsSxdUgmDk7C9WAeMI8kjil2onrJLbrrkSXrasCGQ8p422/I3YfAiXoqnYd6LptEZDxLPS808G7YlzW3RG9ETZ50DN7Z7uevubJaamvpOn0qjdovkBBN3hkq8pcTk+Gv4L82LZQ6aETE7bBQJEB1takIqYVyKUPYZpkT/pbNOZ19smJMNSmTURiiK77wKlZvYu8LmXmQFWP7zwaDaHbgNzBdgNBa+vHgA4TtnwO9I5N2RXI7etwscg7GFisbJi5v6o+68k5pPCiuvaIPwvkjbzOn1smMR7lzRyUKHhGFpzmdRTfOTpKiTOng3ehoHW/5UFM2LkgUg2wgnbcjAmsh+y0zQJj03oA8HJVNColAPYW9cVszdrRntOO2c5OBNqqitHOD1ZP0TiiX+noPLDLTMsx+7FtpmpgUFUsK6clkVK5bnQTn0Dv1WRcoj5qmhf4DN6jPP0xBt/Kk2X5KxA7NmWjs+MBe/zQNFbF+2jvwy0QdG5m6jmaIAHigFhb5LobPU1/My/2TeurS61yasvwNNbVkdM8AgMPSx4oL0yRm1DPqYaWP63AR9vGtb+myCPnW3eX0OQV96Wre+GYK+EK1p3xzJm08RJniX4vz88O5aiH5EegRIWr1q7VMNjO4zY8TcR51Wb8Qp2sQwKeNCUcCG4X1Am0kK0Tfqpw5vLMnjBpLS7ZRUhu7wds3dlAu2/vlaiS6Q/s06h11CjxfxcaoUKzCcx45U9M900Flq4HaXoAEArBWC8LFJcl1vnB1BVAxuZnq9EbNEZ97cDDQ71cG+pUPMXnXtbE1DyZ3rkt0yPYWECgcR1x/UAEKmjYFkAgh3bQukI4DY3eZBLgLIPa0bNEUAmWhNoQH1On103C3+/K2r3vy17GFlcQub/XBW/focHAPICc6nUOAtQ3c/c2JLbrAERGZM0Lpy5F5igG4U8Nm8JoFojvsJL5M/y/zJAHjAg30e2srcWH5yx7VFylr1i2/ZzhZZkrIYSUIDZXLX2ofdKejVbE8P4SFaX9/O4HZ1/5+JuqXnUwfAtqGpuWHvC5xKQ0eqsoJAsLsJ5iBBYXlCAABvQdDJPcQYEAE6/9QOxDm1HaptpH1tL3YO6dAW+UAo1ji6WQ7UFbV/zRmoMWnr20fCpvF1ydcO72AMXxTviK93PFn74/M6cGg8L/4SUpNwwwPRWhMu4PzSBYGIvWfrCpnu+n43ONzQ3Zk/fJxmIOd9zufJ6nSP42x+nd7qB5jucv+YfcTQ3eHW2gCAuvGwtluFwQ2NkS/Ma2h+IvCbm8DcRuNyNZM9JfrMp/dmxbB/MPpW/vz0ri5dSwg03CgdFRnOih9cfEaCwD2nghM13EJ79R6hw220qMI4jTskJhIFOD6fLOn4CFxLB6rZBCJOikDM14zAhHtkDEHA73ediZn8qdYFg0kQ4veVe19nci5/dxNv9XfesugnyIdnOfOolbWxdO+x8K1Vh8mlxMtx05pL1G4i/gr+QYsdFK67TfrGLgV42nwEXlFA9qYaxEUB7WxqQTYU0N2mPOSWHqb8u92V6GFQv9ceTMFqXm4COKQ+yKsinh6LwZ/fAazWf6039dGtZH7/MZKprOkc4TOTLuBLVfOmjzX1OmDHkiQ/OfIHQN0bgVLX+JCYnHC/XhKS89DfbylLpxaALXq63RR6Hdaro05eyxyGixAO65PR7mY9V0iC3Lq3+x/10KBo9f65U0d+L020uPWOAMCdZaK9f9zrNROd+W3UJ4r16UbfnQqvELGaJe3VUPbXoL435ou+fzNxmkn96ZH3j6aQDix1jykaDGOGvv77oexh4UAmz9433Levmf0wG8+yc6l+DfW6db9XyeWvUveUTUiElu5dbconDnSvsKUKocJjqNTjN758m/v0EXl8NLp4fXpIEAHEFMfGE7oDWrlkQZ/Po2J1VRArAoi/nWy42Rbc8Y4AYEqLTvX3eoct7H7EEQV4rpTn0+DYhyu9ubVjWDPvhLU93kHs9bVwewDDhEv3POHt7LGDRL1L0ACARGKYBOcEJ1mFAcHdW6wN66vDMP3M9kxypRPQQ2XF95PTbu1g7aAt3TVPpRVEdmvJtLx081zfBkemU3w0Uyg7mi4hTVzCFr/uzbuyorQR+sOJaNI07YfeeCT+kO2QLDmbIkdBEaZZpTRxoZ2VJSZ8ixPahjMTfYjn1Bi4QxzlmOtyJo7SQ0nOqP2mKz8K6wO0v+3Pr9NmPctarUhmuybxustm3pwRt4U3XZ23xYB1Z4R598GfZWqGGhJXuTMCJ81CrgIuYGVuQH+t+y6oquVLm7wRNB5Kfw1Vg79mfCcKSFEWhPkO/nnQUa02yaStZCVle9twrJ0Qn4Dhxto9COnri5l3buRlSuCV5bDJScQkAbjcNSmWWj3oYJk0yZQvJT2/YoagJNO8d/cqfIpqvRSPdPTw/q0DPyDbIx0/oj8ryM9Ds/3se5JEONLqIfNfN39k/Sck41nltNPfT0eoWWoPvei5O1J3JG98l5d9XQGUrR9v8skdAU7/eDAwfzoVp5zDWL2qlHR4aw0o8xu4LBIWahVb3xrdY3U/rMBWW4UtkX/t2SJneC67unXOuL+WoV1QW2HXVnhQhqqJjdg0x5CoNpEtDZYzkGCh3XN2HcRyloIBAGyjZyaQbK+kpmKBskLNjj9sMKQJt9Nfk5iD6/O2BpoLa9i3hZhb1u5sB5recV6G2WOcbhayR3AGVuZ84Jasy52B7bR5rhq+5EIHY66O0WTgohNr0IytX6Pzn82lO5Pj4DZsqvvqF8pX1zgFiy92MTHTzFutXSjP6x5yRUiLdglda9JV3UKRebjnO3O8mtGEpg/3+tEWO3VSNBow98QxxFRb6m20rTF2V87GETJu/3C7EHanrSdKhGFw6Drh8Lpt5O4VoHiq6lPWdtQeZNdK5Fq7t2Ta/Onm3XzLZJhmXUetz7pM473r3/Ngxg6mfyDu6tqBuzn/46ZaAFIxCGd9OcrrmQYTWPdQ6dPvOO9Q0t6ah/IO7L8LxFEuvNyh4ui4VjpUqozjPGlAi/csEW1L4/ItJQ2VKu2Mg8B8bHLA9tT+XQ5Yu4vapWamWn/HXTGuEHKBdyV0gx7Y/UkDu+2QsKaBE1obNge4UevCHgK3afPYa77EvisIsP0oeZ21jY99atCOjxomXbp0CP+OIWojqOah3Fc7Ptw/Z3ucENRt/oTu7V+vrfvwL12zwA83rNQMBY2qkXr/G3dWIWGVfxfTxztWnIgF3Qx0hVxWDgrycMt53Ic8bV9QpwxBN51OGAAJdzqUMDFzgus1jJCss4fjQBjzMsTCEmx1+J/glnge3v0i/ZfWfw4TOuUAQxzSbfWEESzdc7GSf3e/tP7kMmE8lx2Wl1djmpDsuaxofeylk6uRUn3P1RV5tNF2FWgLuwcrvA3FcqgXDhDeeYIVIwH0q+sBcAQQNh+zntA1UIklhWbD7yHBWap9aHcHnhhGrEhHADAHFh6fG2SEI2Depj46r1hfr1+DC9+b5DUeRxlWorgfhYRAMTaueIhzxT0/o6CzeikYAHAO09k6zM1ce5VbOtGX6elmfqFunYzSZhGXeP2rvM5fp0VfMhH8iM/q++1T7zMjvNLGq77GtxUk5DTfShc7jXcuFq6k43LugpTtTrRgek3BNL21eW56lasMjDrLYDU3SbC9jPVqgJY4HGSATI2eZLxRHbt76J1qdswjQLGsioHIpQDFrGJh3KvDTkap6ncWW5yMUvOqdmYgRz8fz2wcR7ggYxe/Mf8ezLRz5+feSh19zQ78H1WkPNGOi6anWzbV9/zsswMAk1/Q/VF98LP7ICi2MyMGYfjyXAhXD6sz6vCuonwvt542Mj555mIAAMChF1qextCbMMFWgUSZzEe8Rfl8ggcp2D2LwQAAtBRQO8uqF+1sWr0zizuC3k5tXhPILbh+HSVoS67dAQIq5C6RIMNwQSwKMts2xq4d2cJ1mBrbYpPrMFPugu3u/kzaGVfH40XaSyfWs8XIu7wHu/IWsyVMufQn27tMau6ga1x301FEXmuXIwQAxw10rHIPz16kU2L9m4XS43t+FHCiNbi5tmKRgbbA9njZDVzi6B4ciK5t/7hoiNNs61UswkRfkbzRjkI6qg6T6MnT0woyu9LDg+E04AAAo1L/lBYm1eFtXpcwhQVRMKu36Z/L0e6S8NcLzQCAHbxFVOf2qLdiZIvlbZPOPxcWvFYdelcBR9XHNIC3+x1pAqzc6qcoJNXHR1LHgFptk2FAt3aZRtKY3+kgU4v3PT4YH5zcB2nkYFbzITgYih0dyWBcLPhsSKW+xwgmdCR40FllwEcX+NJyK6u/Ny4Pq3uUDxmwakvVBZUl0ar0jg1OPT748z/OHsb/N/QQW9nIqaS3xGeLozO2Yyn+Ox4zRMoVSJtBkrPcc41GIJFzgg0JpPWYdqUkl/Dk6MYxkbRJ0R49xencyZ+rwXV7A2EPl5nuLHAKByZQnnzpVkSyLpUMC0mLF52VOIkbmrJGjkDz7L1zUEh1VSRcHkOHXeXRrfZg8Kqu/FXXmgdU9+F5BFDfAGg8oRRQiSWFvsZNz7EX3MH5QnUv0RfGkhhx4yYBwA648h99YCxDF+aPC+EPPYOfz7YgOd5X0PveM+rnVYeeYebN0cFxLgYo0g1OKQwAOGhLxAazAn7dt/Vi8HdjwvO58/2vN28eex/g8+Ojzpg247mlzEXvHnkO6L1a8EQ7mfp8u5/bWN0WlsEAgI39HLsAKop0yqZxASEmnDHa2W0gvVbnDSTEqcfGHDMkZFK1s3iyid4ZXRAUAPWp2hjUFdQ3aFvQCNS3dhfQPCT66OqAGiRQ5y6DOcKBipTffBT4V5EN8S5pI0F7K92zQnQrUZwLAACcQMfuCAUwxwRFAmky5mwAzjB0xaAaDWEAgGuB6dJXy3HhN4tWbBccuAUPWpzq88QDSdSwuxugUbdjErpyuS4HNpTVcZApjmzAm8g1tDJT1zcCMSfrMk0o53EXprXK6ZjtDN0tnOX0No8dDiMJiZwlbBZib0wpsucGBtOlUcUMkHY8pLbtZ85Ff0GLW/5oYkm7Pl3J69NPs3ToB6fyNeec9ryRFkyjVxU/1ESapHn/HPpfIC3o6n9ga0B8t9HjaA9if1aBk/pt4n+TiT735J/uB3VtBZPBIkgcUvRt0pdw6AhxfiTbW7rS6i0Fccd6MLiqtSpbzKHBdWEVpsteyZ60f949yLPd1qduuSEK6fUajgI732mg7x6Rp2bP0XQOkKoGHAAg1WDQ+gULBjAKcXgas9qGGoCZze6MgYOGF5oBADS+XdmTpX9ZZ8zdYMOdsu6PDaT7tgadK8jorY1RBeDgbuQUNALs/qQlV4WRuG8Oc0NX2hojAt3VtphVkLvlLpjNTZoAO7LR7wUGJnmwLdDBXcYrNlgHnSB2E2KjLytsEcnWsp6eAjtzQe09gimCqhiCtU5lH5p5rUk+7voUhTcSAACmfN3EglP5WnlOf27UCaZ0UsUcJ2xFwWDKc8rFcC3HRzHQ67vA9PmIDZJumwMbnsrj0q1kxpdKJ4bs7Uusd8EMVYbh4AeBcP2f1BeHe7wGrdFkwRHt/Qx55GI5gxWbgWpnOx/NFqHnzk+1WF51H55HAHUGAMcKsjtgicWFdsHqgYvOLvrqAhXcYFQIPP99BACpoF3nP86CkwxzmD/qgrRs07u/vQ323ixbI/agZ9BkHWPhszOz3saCo5WDCphmCX3yYwMFR3umwTg3yf5t+GKKnbBsVgwbwAunu6/dLAk6eI2PfesKE3IlhU6A6alZGhR4mEJn2spewVO9EtdXbbp+gK4Z+3EXxK0rn2diuop4UpXBlfOT7Mm/h6Cq0fCpGuuCMNbAF7p/jYPNjVNqtzTO9tehdaLuTGqKWI/mxerjx3dlUfrb5k8odZ1dOCA31SR72qON0BuV4sZAXYnwU4lz9CbIK8JUKrKxzJD+YO7Oky2gbI0QVFciRHRbGSAg2tYFLCboQMbADgNOGTuGA3AZMyzCwdv87k1rgz9fVet7FU8S37rZz0jeHI13tRAAADiCauidCSjYENwrDie6eznGPAIgwzy3Ik4l4u+cDwYArJHeLoO/ZsFXM9MXCsX2ksMtMR6I0nKmQs/QV1ex+/DEyp00dHCZL6fjXiinUkYIFPIPNA1amWFD07Z1GQqaznCGoV3lmDsOqzyj1gvshC+x9kJUtSvFNERh640iMJCmOSAAyBpMkR9uGtracfuXbjBpy3JaUBlrMTbobns8d6AspjsSlGq2fyGCDHptvWnCvR+8hVdHMfZe4B/tXTon74qzugFIVLmic3EAANPLWhhy6W39XtL1Kk7XkgFdwRCzThHvaGbvgMQ2mQEAYoHB/g7Gl+D9uTjpH85JOXCH0iWXx3YEFZ0YPCv/rkHMVGspCbhJJq93UxmzBuS+K4UHptfubw2IJiNREcTE2mgaZK11cQ1IFGNwHwNj2dFgGFjiwaMDlr7HpDTIbhYPoggKubBEAXNb6rnxXRTZi0SnUHGq6qIOZjB9TR8BwGWBHRuP3d2sEKfuYjkNJiTjBSYNpHlXi5IJMMvLZWoJ3F07FVYBW26NtmuA1bX3225gDrUVVzd8jD6GKqe/rwqbW/B0BaH6A/X5+EICqPQAZE/IC9RiSaOn6fdQ4CJWFGgHo1SMqOhHALAEVzePfb1wB+OrgtQR8jmSTztL6bmcWLsArN9kc/XJY/fymgogbeUQAcMxz8eHnEnBGSwGAwDmfDqppmw9FWflwCmGc1X0volr9L5s5epn8vDVXuXB7Wm1jhZvVbGz5oM7/7t41favd++//fife+PD3MryGqE8eqfrGCrC1vDB7aZ/Jj9PVR/kUeB2m8EAgJRUAHv1BZwFvDTisim1C8yoPm+X4DZq2M8WlqjduRnQFAvJHOgbHTN6omAI7TLbDu+ESIwBc0iswXZYhcRmeSwLJG8Y8JXWufUDI4SzT0KlhiRtLyp+0u0OgVAdPDHMSMk4Q9tKq2OnGdr2uYJ2wIa93fI3DnPv6nAqeikTPYcfLgoDAIb0jrULqgA4l+I0rJTSalOfFzZoqCJsKjkXzc4FS7U7A1/8jPmyBi0YIQNxUlZm5phMVFqXZYMxGMOK4KacnS03uBOHdmuIJKcuHB6x6+9g/D+JsaX5lBZm/39/j/8BVLxy5pQarOp6I7QZFKo5IACAF+yJgSgmmpY0t2GFC5O2vOonjfFUSzB+8x6dl2D0ridY/z1EBbpiPJESKuiKNp4zHpeJV1HaBb6qAHTmZ6n4siYOSKIZD8NOmtL85JCj6wOtrwr2ybvCwo5Ar5pOAIDeYV/7mU784ZCoHIV+GR/CRFAPL9QOkByvHi0ghWdbBWq7yQwA8BKc7Zq2awCd4mMsAXTX/rkIcq8O3WNAdbUxvgEc3o3GDW2l7f7CeVOm7zgk3l1x0tbmHHAu1uXOwNa6C6kaZKrjGgVtZIpwggMOGOKuExMM5m64Kva/S+2MIbeM2f/f7xOhDQ/hwMsKWoSAas4DIeP62yK48qKaWhA5E0E3ypPl7xxgd6EAAGAO5GTzF3oa4lWVIJureE1ZSKJ9gdE10jjWongKGO9lJOVl/K7j/0W2bPvn+3Drf/Zg87cglrtXhSH+2u/j0eUE7tWHMJcWaev2ACFeKY0v4G8qGK5IOHMcvGEE309e79B28qscVtOAbHFUaAOitQzRWqgzcreZh7mtc89zi6zkIcitFNX5YABAHCa1VsHVm7mfqbPScKjh5fSCJH6tof9L+vv6uPWpryoJez6948M7VDedwe7TOwHYhCk4RqbQefQ028JPLQoDANJshCnrC6QDEhlxk46XAWtX6F3y8EFvrx6bRWbI/jU5A8tPcj0p92AAXOiEgF35XByxkDaGPYFYaetC9OB0RKwhYyAwVztJYvvdSNHjYmFPSMd/1inf0e94n36o999UHX7hvMxf+DFpaAZJ3DixlIcp9LeMkGwUlMDanPg3KPO7yidJvXHRM51hTgHm9AInwyWcx+nMtBcqprbQmQJxFAy6LLhGeoPfhZO3f3drbiY7O0+F6cwFJCihz3gfqmBuzgkDAManVVXL1tXYpdNM9sAMYNaEc5WLtbH2WZ03Ja1vath3ho1Nj5U2c1LV4B8WnIWoF+VQRBDGQbpSlMZe4NcU9Pwkb6gkkW/4w626ZtNJwsEQdJ2MuILsWTAF+mmyLvkD+FT+CcF6KjzIcWIF5ilc6IJsyy2DtpA2ZtGEttJty8KAtobuwiJCLrYdoNWgy7Wfs07s6sR67kNHNlTFkhFVIa+nUsRxKatAcw2McVFk5JJyeDqwp7p/rgAy8tsj+Dacpol4U+wY6DLrnxx0Pb68nYJ8ncLtWIvG1B0GdtEiNxu4Ga4L5IueC4oTC5idcW0bZsYWTy0ryP5e2hp2cR5588OvEuHeENRY/wd+gaeeWYu7vt+IW9mpx3H7/vE7nuFhh6dJ+hk2kGmcJwG+Yk+Lvxl6ssISfPkkku8QOKj9bMCC7cFvaZVAmUU44kCP7Tdfq9qV891AIPcirduHo/6FQM3C2UuI4Qe31FqOBmirjr3x0zsV+kUTqjOZFwuDbuIKErqcOddRgcA6615enHLHxd9maKDSF+uQPaWw02DtBsA17AAAIOxl9IuZQF9ANG5hrBOGxau3Ds9laKfwrYVmAEDEYKWKtjEI0hybAQVV/k1ABbXo0dJb2PNMkRdq8FUIc1daCFT4O4pxSx8/pYAf4JsBfOwui/DSrWrz4QlTBfEuVG+mVeWU7jNJwikAyk/rmxAKeqxL1NmGIQZwGCLsNhDndxRmvD/xE9jxX0Em4e73sSWhh7P/UEamG5x4W2wVR7nLnBdCOY4OkEOCxoXFAzAs1rNuYJuXVRYH2Bo3o4sgxzUGvOEiSxYAgK4x+f3x3g1u4To23FBX5jLZFCCOdYlRsSBvuwsldYCCrctVvNUSqzKuu+huF3KJtkUBkcvY2ieDPHbXY6TNDx+1z2YeTbjH/MG3u/tP3t5A/wy4kmwmZlNnR2+6fL7RrqjgVRaDAQAHFWxtaf0arm1WDEsK+X08a/PeNZbeF5+plr2+qoPbC3VOiNj21DhtJ3xTgatiR1OHtQK8YYNSXQBn85waBY0UJGsxGADAU4HwKgwG4Zvav9S7h5W2GH/Wx6FtviD4bl9sWIfRqM0p3N+B4TXUzU8Tvn9uHpmlQtxcqqJUtOIL5K16mGwnjg2HwpsiPhLsuo/p1Gmy5zIOKmiKih501YqKtFY9Zks2r674l5Mza8zV7P863Tf9qtocqqPvE6lvjPrvCS1CMmE85aWQGrogSERZGWnwxbZFrsMXGYOMKVxaynMOkIZspgcpn3msxvlWVvKtohruZL0wb4X8xZvQnmjBHQnbn27dMz0hEymQuGkAAEgWuJLWucyEOwpcDxe8bQQ65z4DAv3L8HOVd6+0qapgMxgAoDoVj11e10Hum0khZx63RBlVYu9UoXc9FWP4V/rqwNxExZVhNBwmZ4xMXmr2uQPtqhZKpcMMCzk5YuzpqLIyZ0DHsXU5BzruMIbzIM93DtDNlfLSdmhvG5CbxYlMRh0qOZYj5Y0h9smmUJVcsr1kdH1xdH1BdH0F0/X9dM02mim1eKOrJJrWiHLGyPaS0vUZdE3+c+J5S7f30zWf0lipRTpdicw5hwyG4EoTp/9qFFmowXUrqi5sIiXctrUgMitgEAtqjckGxMs5boKPauDcUn0a/JfNhvXuDr4Hth6qifu+cVjpsFpX6iP3w9nvMn6kutByExbVhJ/SNdOO1gJeZW7Ipz1W63zQxB3qwdoy9QaEqu1fHYVp/Gri/e6KOHn7adnAtAi3ntbhfA55EzzG5r6tk7c3peumADcvDO4wx//BTx/GbV8WDUzICZdkaFU7CrP6JMwdz94juFSDGQBwDIQWOtqAIWCtRslNnxn72RjpHylrpqZuJwPkxJqzqbCayr+75zVt6F1bMjW7qUSonjXO4tTpGIfMuaAslMgqbJIlP2Bm969s0afumU7bAed16vPQ6SSm8SMlNftvpt+Mmw2nHGGvCborDTRX6dNlr4W9nW1iVBqhGcmkU4A2Gq3amskcNO6zLjO9ch6iMdtdmGFtckZ0mOYE5IzPCZ6LoC0XLYITAySH69ALMfFlhbuGeCLrUadDt5NafUkVYwhKMQ1kR7Cb/NYmobmmBQAAg9HqJrcvITR7xNXIdIMYXChxB3mqLjG+CTQzXYuypekkgxbM5WrNbLSKL7k7CcEVq+4TXaVAcEXxfv1VZIJr7Kpivz64q731t+j/Fxo6l8QIL0AqRH8oQycvx+/ti+LoD5fGF//K4BOdT1Yb8CgTLB5c9sU2rQo9fS9Zv5v0uBAGAKS1WgHVuqarUe6NRjxCD9nr4mDgFzx87jRotXJwk1ITO8lV8B6phnXYS26ttapiQR29G6EPQ7wOgYkwAMBeAjIGjbaqORvgdN6Yw+tAsxWdUlS1ZPAoxBvmXbMYhSy9IR2dHGXcIZnaSWWxi+2kFg1KnaO+r8BbDTTHOuoT5q3GgHmUd57xSvpd47IX3BH6VLs8AABMo+bIMw2h5KDQgxg6JFMtVfJcSzSkn8s7O2XgdJK6JNZxbPf2VNhIrowqR00+TzroSXgd8Ow9j0LFHxkENkjCCHH3c37FPxcyK55oXS4AT2IMF3LnYmkCraLRXlmdKsfGsf7aJNoDp86UOoRHKpFVj9CtMhGNV41v1z/Inrll6QkVUakZbHOlPsi+t8gW2cecWnZ+LXuP9xKXaWc20ZiarTdyKmqGIQ4Npo737xDE9oXNWSS7bS1UBDtljaVFqqtMN96CufIkFnfH/qEKeZWz79wQNuQeUjkaBevufHF3x8nbKxaCFaypYbP3sUqpw3upuIfcR6oMd7uS83UAgOOKihhxJWXDcGXL1sMKctqZjvBq77lmAMCh+HRlW8IKTLYNV3r+X9/993aUoiTOkxT3rkDf3vyf+XuFrwKNetwKyrpbi5mL37uyfI+gu584vL2CPe/n9g+p6/ZK8lvvL3EGM65h3/n1lmjHmG0isu15X9ayVBOu+jMGSQa0yt4MjT/WLyP8nRLDJohSyuqdyXQLbtsN3kKBXbnbsBcUwXUig4O+uJwa787kARZ0EhHv5qIqNOjMg3MoFZH9V8Zg/DBPs/CTuGHgzR/VuAAADLa3/89oo68mV82D8cMcdAYuGgxG4o/DGhMACMt6j7LLU24G1vG294qtNL7OfjOxwkKXmXQVeJVKlN78UIqW05eszbSYwoX3iqAYXTQcCwAU1La2n53dhxUUOnr9O4hC1cNOsw+D3wAYL3TwmZFby4HQKCDI5I42+6Nm1egSFC+FAQA76O4ZhAAT9Gf3tufFyMuWvCbCx9+TPLq9NFjpDvZQvyLUayethS3ExXjkYr+CDltjn14/3tf6LDEPuU4fn5X2XBW3C81zF0yq4vZsDN4xtBZ0z60dAmu9qhaDAQAHh3ZnugtsGKG037Oa3r3Pll+Um9J8FkLXqs9zIUE7JZ1hrVzH3ESFbkDuvmPK9p+Z9uwH3aN7PJsq7vVNr12XGsSZ3Lp8MJNv/FXyVLkgXg3kCdsYXxvy3OoXX850St4uxuDLZMcoU4ADlJ7dZIrLY4PKISiTN6zw7qa+92GMz65grmcc0HEk+/cx+B5Jn4K/N4xmuXFldyOqsWn6kHCt0FcFP9XBzfcT+/kBXXUCnGLACoHI1sX/zqsV63KPoYQG1g3964Dbhv7VEmevBynsEMJs6aIH+A3YOQBjKIwXewqwhifIscrtDAY/vx2l+b0oHJ5DMsSJtRjMVe8PXU/djVB7XIFAzhYMeDSyuV3urD1142583+I32Z2NWc03BJI4Oo3ew1QLpql0kLYoFInsqzpYe/No6WJL4Dn5wZcML+kXj4sOt7LX9Ql5wU7+r0+eDSRPhFs9+kwzH0bC+4Q/pBCV/N9j99bG99MjXrah7FP888CcJRPL5hfHSwJBMXaHLgSlY4N0IzjVaoznicLGGehOWry0qR25IAwAcBzqHb7OglNVikjl5MVzhY6KDK8zL7uBMjNd8DkvInPTuZHbgrBoZ4BVas3fgLW0C8KuDiXagLW3bQy7loB1pH5h53pMxDpdY+cXvM5ujwPEprnO7qFLy+ZA27RDtFRDm6MjtVeBMuxHcppXmih/rS/rLcCctbfx7yMZ15v9SO74SiPnMQEAa8bfNMjlhDct5Rrvgenh+qeDXJqkLpj94kBMsHnaGi9trhsow2krprBQZvO9NzVDoivLjG2I855042Qv6qQGo5Mhh5/5ML3dtLnZge3OzGyH0JQryQo0I7gZxjW+LYQ5bWI52VmIp0k+Fmsz5PMLxRNdcW9QX9qJWIyVee04ez8dcvZGUVGVvkcKMONiZ7PfKgVm1xRcRheGApmY50MVnO7FYADAjApUp76gawCRPM8MvUGNnpbApPWVbtlHOz/R/mwbDbp1IG1Gf58TPI8RcnXELe94+9Qy08Ba1iXV6/hQ8iYuQwrQHxlA4H66IqtX5VibvGGOfThx5zD6y/G3a2GBG7kie5xiOfR6yhlFqJxXonHYV6G/PExfYCdvz6UDXYQ76syf6CFdhsdA9dW/5O0PcpEcBK+0WAEAKAHI6R1yhaEkiIUzSGr1TAM6BRAwz9VrsGQF6akykJ2bZD9B3YJnA0JEpG8MvbBYURHtVuglUAxXw2cQsVxJkYFwfS4Bu3CvEnywDFItJBPx10XMrDpvIz6qaOmFgXLEJ0wGmFVVHqhfDkdWnZysI+WchhO1CRrFpYYEtq/TaYqODxGZ5eqjqZUd7umoAICUu/DDgfPwtM0T27J+eeck+c1z4by4mQ3luluLQfW9RMBL2We4wPOaxnCciCR2ktU8FNj8Er/D/o/SH4be//bMaS23l3LG1IsVvXbULkuH3GzimLOp7o4iiFRRyXgWYAgi1VFKg+lm6J+s7cfOJnpd4D9SHW5RGABQBzTowDdhpnLYEjyPoZfC056d5+5GrnjrSvjmcHgxcZWt3DCg+GSGZM59b1DisTPZymsJIQfrklWuU38nU/qHYCyk1MgTCcO92bNlGD2Ewz/FffCn4E7Y9xMfuroecun6/G5w9+qUsx7/BdRn/2A/gOe49gdftOrTCi8BqAHSb1fOQydWHq5SsmL5ejYbTp5uaGQG1FxuBAYw5SccEFU98jfgGwcWPaqaSnh8TDp6BK7k+eWFeP++s3kQ6PK7sSSwZOMFX1iH5+gSOPi9XH+6b3Y/cBe/Njjxd3h9Lub2VIfg7m/Wkp+fFaehNuqdqY7ORDGO8ewz/p9h5vPT4qo55YurCjzaLX8STLKf3ya4xZamKR30krko8TSYZDFNOu0u7rmLOqZigLFAU5AvYd9lS8pn7Ic+RzyBW5/D3K5n5gsjJ6Lt2NBHfV5KuWVZWr71XOmHmOFbXqFzXlvpmWjWXY6UoLYL+SJh09cnt+Q3hubO8COP6War8uqA+M9XqMh1l2+vFpfL4TU4H7gWB1cBfE7g+UFteZ7vI05o+u3xUsP9UZK3bgCNNCoAAI0D6NY76sWwwgYZaQyKByN1wjQ1oHfxTuXzPe7tCgq3GAwAMFRgKBN+05NcZkfAmOepBTipzpueqSzvJEXPhN9wHt9IQGs3tlLAJ5EEH6A72McDtjmqTJBB2bEBO1WKjpk1YIdWdMvCgB2NYi6sDNhrt25EiT9gb/afYgEQx7Vvp94/l4lQs3y6CpjUYRYL6FszcVtDtcmxChhMZolEADDXAGfpIG4dgHO/+42ekjghnfPv9q0OWvv8q/5UZR8eYx/f3Bvb+L6w7/pON2u7fbO85b0+3MlVn3053tMWO4O5xmTC1TofFrnRPXjqV+QxerGjYvs5jkrsR0f07/RUYf0w5vURO62d6WOAT+g4YLNWNuULi6qrWhCPU+jskS+PeK7S4LlRhzWPfrpIJ9ILzzZo5yfpZcvwbpisaQijY3lrQK64Oq/nkHdP3AUr4aEYG/qyG18xuJYrb+j2zYsdi1sFzZjG586pDdm9b/ZVu28Ca8fKT3aktXL+4rMD4H4jsyPodkZvG7OjPnfMKFeh/TmbB1kgnkauWMd0NbZUxN/JXs5nzij+XXnBF2UTNX/7m3YL63UvByhLwwXhxY7E6cOb7J8rx/4V9POIDU/l+xnxOsT4TbQn6svnbM8VFhiirzobqG7CMllCe++j7cI3F2l9Fnpwe67vKl14wWIFACDG2yl0vCDbVVBV5mBCT8efBwLEyqMvkagiXnxaGABgxJsqw98xPJ0dgTkzzxVnlhvJ2jP0dummQxlAX+Xm2ef5idunR18xMJThcjCJIR0Cbqf687AUB0F1F29XYG9sDGpV4AjbgoYKnMQX0HSLaEPrRhmJjq0BI2ANl+jKA/LuN0k3zNWcDWcUnDBQ+h7AOTO5krUrz+cekJFCPLOL/0THPo/AKTDmixuvK0vq9Ulp3dBwnWkOLa/4R9nkfs4U+aMIo00vYzBL1SeYrb3XoZplSZPq1Mvt2iUSAcDShVxM8UOzkFaK9Q8CpveiHw20NW0tlmkafNyGfV41X7yO/PcUnp3XZ+c1DM43ifNdG/8MbPHaM7ctvH7Bfe58+qy89rq+m+ziscCOY86oWkGDYscthaWA1uVBK5rxV1p9XuVEpti6T79c8Tg7i9Gl/YPz9uvXa4xrQ7a9TcBvPdn3rNsxnjiOveaCMABAc/iioafZem8NEzrTrSm8MECeZ+JARW/YPKvz4gUe8cSeqK0GiQz5/ETRF6Y8InJsl0NmmKSmSUfPzGTmhZOJe7MtW4OchAbDdjJnvzG7bfu2xQH21EJsOTxPXp8nr2ExvnyIdPR26W1/eH5x+D6ensGb1zDs4OA6HwX4qryTBV9CT8HeStOs6KvOZqiL3kwhONHhH+b156T7iGeuqDX6s9CDb73cd5M5wHONCgCAF8CWip1N5zMV2J7S4Pq0qkRnTa1mH8XLjT6SpoF5dvCLXtcnl02dqpxH8t42gwEAvps8UZ92+ka2PkQKETOT9WOHRTjexQxntaCiMg97QDODWT2nPlXwjN+Y1fcVA0N5UfojCuMOSN76sUtoaYQkcZ5DsGRjMJweBbcIz226ZcYtwteaC7MqsHXtG6sALNASsNAEKkiqDCJpMGIJVNt96k6qusBNfp1x5rVkx2sHMvorxoZ/qfU/87VzW1T9Hqi2arYe58Xt4n/WAYCthkgunYswtQKy/iD02p+bEGyVpIofsiQOxfsnBW7rgr8iQaruFF3BbUh3SrUU7SwapCkq//ZDm2P8bd+VPw8n6NvuWj/1sZt6S3d2UOFzb/eMqosIfIhLKXYsxK2UBuOkVa1BZePpFoUBAO4YpoHRVhcsm4VdjefJ6W2KNzo7b6NS9I7T7Znw9o7D1lSeBafbBFm3W5CCM9Ayh2ZhH8yWdrkwmG2D4Qbcon3bPnDLNmLRzKJzqCt5Ps+lYuchzZfhu/7UP+Hl9g2YZmXOe1PfTU4BaSxWAADSzb7uLTXPFd7aGLxG8e7Ka2P60duYUxPgqIYwAGCKfdsWB6xcYPA2Rt4dkd5MZR4xM4ArA7QKq0uxr+YniqC4snpAsQ2CdBewJYTHQbA4DzigBqeqmNkYj/Ex+gWHh1HKDCfiYt/YBnFjC9iDgqriRCmDN7KbvaEhH7bV4/9o8iqpt0UijZeK23fqXPbwbLEu9l5qH4qOLfxsXPvOyZqOi7ptV29mkEylzceyh1rHKduSdPqEVtt98zl85h7vsomK8+M9/w++WIvOoaq8J3yCf7UYvCR8OKm+lE/yGH2CB+m5Dv6JidLoIU/mh/hiOQXtjzhatQ85YkdsD7v/8VPmJEog7ZUKj2jCxvO6LsXNCcLK7+niPQryHDEdafxurmo3xH/8VbK/jwV5rg03y/tvC9T1Rd8JKI2usEZSQgV1ss8+gJtjtpcD\",\"base64\")).toString()),g5}var zye=new Map([[G.makeIdent(null,\"fsevents\").identHash,Vye],[G.makeIdent(null,\"resolve\").identHash,Jye],[G.makeIdent(null,\"typescript\").identHash,Kye]]),xct={hooks:{registerPackageExtensions:async(t,e)=>{for(let[r,s]of A5)e(G.parseDescriptor(r,!0),s)},getBuiltinPatch:async(t,e)=>{let r=\"compat/\";if(!e.startsWith(r))return;let s=G.parseIdent(e.slice(r.length)),a=zye.get(s.identHash)?.();return typeof a<\"u\"?a:null},reduceDependency:async(t,e,r,s)=>typeof zye.get(t.identHash)>\"u\"?t:G.makeDescriptor(t,G.makeRange({protocol:\"patch:\",source:G.stringifyDescriptor(t),selector:`optional!builtin<compat/${G.stringifyIdent(t)}>`,params:null}))}},kct=xct;var T5={};Vt(T5,{ConstraintsCheckCommand:()=>XC,ConstraintsQueryCommand:()=>zC,ConstraintsSourceCommand:()=>ZC,default:()=>Kct});Ge();Ge();iS();var YC=class{constructor(e){this.project=e}createEnvironment(){let e=new WC([\"cwd\",\"ident\"]),r=new WC([\"workspace\",\"type\",\"ident\"]),s=new WC([\"ident\"]),a={manifestUpdates:new Map,reportedErrors:new Map},n=new Map,c=new Map;for(let f of this.project.storedPackages.values()){let p=Array.from(f.peerDependencies.values(),h=>[G.stringifyIdent(h),h.range]);n.set(f.locatorHash,{workspace:null,ident:G.stringifyIdent(f),version:f.version,dependencies:new Map,peerDependencies:new Map(p.filter(([h])=>f.peerDependenciesMeta.get(h)?.optional!==!0)),optionalPeerDependencies:new Map(p.filter(([h])=>f.peerDependenciesMeta.get(h)?.optional===!0))})}for(let f of this.project.storedPackages.values()){let p=n.get(f.locatorHash);p.dependencies=new Map(Array.from(f.dependencies.values(),h=>{let E=this.project.storedResolutions.get(h.descriptorHash);if(typeof E>\"u\")throw new Error(\"Assertion failed: The resolution should have been registered\");let C=n.get(E);if(typeof C>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");return[G.stringifyIdent(h),C]})),p.dependencies.delete(p.ident)}for(let f of this.project.workspaces){let p=G.stringifyIdent(f.anchoredLocator),h=f.manifest.exportTo({}),E=n.get(f.anchoredLocator.locatorHash);if(typeof E>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");let C=(T,N,{caller:U=fs.getCaller()}={})=>{let W=nS(T),ee=je.getMapWithDefault(a.manifestUpdates,f.cwd),ie=je.getMapWithDefault(ee,W),ue=je.getSetWithDefault(ie,N);U!==null&&ue.add(U)},S=T=>C(T,void 0,{caller:fs.getCaller()}),b=T=>{je.getArrayWithDefault(a.reportedErrors,f.cwd).push(T)},I=e.insert({cwd:f.relativeCwd,ident:p,manifest:h,pkg:E,set:C,unset:S,error:b});c.set(f,I);for(let T of Ut.allDependencies)for(let N of f.manifest[T].values()){let U=G.stringifyIdent(N),W=()=>{C([T,U],void 0,{caller:fs.getCaller()})},ee=ue=>{C([T,U],ue,{caller:fs.getCaller()})},ie=null;if(T!==\"peerDependencies\"&&(T!==\"dependencies\"||!f.manifest.devDependencies.has(N.identHash))){let ue=f.anchoredPackage.dependencies.get(N.identHash);if(ue){if(typeof ue>\"u\")throw new Error(\"Assertion failed: The dependency should have been registered\");let le=this.project.storedResolutions.get(ue.descriptorHash);if(typeof le>\"u\")throw new Error(\"Assertion failed: The resolution should have been registered\");let me=n.get(le);if(typeof me>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");ie=me}}r.insert({workspace:I,ident:U,range:N.range,type:T,resolution:ie,update:ee,delete:W,error:b})}}for(let f of this.project.storedPackages.values()){let p=this.project.tryWorkspaceByLocator(f);if(!p)continue;let h=c.get(p);if(typeof h>\"u\")throw new Error(\"Assertion failed: The workspace should have been registered\");let E=n.get(f.locatorHash);if(typeof E>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");E.workspace=h}return{workspaces:e,dependencies:r,packages:s,result:a}}async process(){let e=this.createEnvironment(),r={Yarn:{workspace:a=>e.workspaces.find(a)[0]??null,workspaces:a=>e.workspaces.find(a),dependency:a=>e.dependencies.find(a)[0]??null,dependencies:a=>e.dependencies.find(a),package:a=>e.packages.find(a)[0]??null,packages:a=>e.packages.find(a)}},s=await this.project.loadUserConfig();return s?.constraints?(await s.constraints(r),e.result):null}};Ge();Ge();Yt();var zC=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.query=ge.String()}static{this.paths=[[\"constraints\",\"query\"]]}static{this.usage=ot.Usage({category:\"Constraints-related commands\",description:\"query the constraints fact database\",details:`\n      This command will output all matches to the given prolog query.\n    `,examples:[[\"List all dependencies throughout the workspace\",\"yarn constraints query 'workspace_has_dependency(_, DependencyName, _, _).'\"]]})}async execute(){let{Constraints:r}=await Promise.resolve().then(()=>(lS(),aS)),s=await ze.find(this.context.cwd,this.context.plugins),{project:a}=await Rt.find(s,this.context.cwd),n=await r.find(a),c=this.query;return c.endsWith(\".\")||(c=`${c}.`),(await Ot.start({configuration:s,json:this.json,stdout:this.context.stdout},async p=>{for await(let h of n.query(c)){let E=Array.from(Object.entries(h)),C=E.length,S=E.reduce((b,[I])=>Math.max(b,I.length),0);for(let b=0;b<C;b++){let[I,T]=E[b];p.reportInfo(null,`${Vct(b,C)}${I.padEnd(S,\" \")} = ${Yct(T)}`)}p.reportJson(h)}})).exitCode()}};function Yct(t){return typeof t!=\"string\"?`${t}`:t.match(/^[a-zA-Z][a-zA-Z0-9_]+$/)?t:`'${t}'`}function Vct(t,e){let r=t===0,s=t===e-1;return r&&s?\"\":r?\"\\u250C \":s?\"\\u2514 \":\"\\u2502 \"}Ge();Yt();var ZC=class extends ft{constructor(){super(...arguments);this.verbose=ge.Boolean(\"-v,--verbose\",!1,{description:\"Also print the fact database automatically compiled from the workspace manifests\"})}static{this.paths=[[\"constraints\",\"source\"]]}static{this.usage=ot.Usage({category:\"Constraints-related commands\",description:\"print the source code for the constraints\",details:\"\\n      This command will print the Prolog source code used by the constraints engine. Adding the `-v,--verbose` flag will print the *full* source code, including the fact database automatically compiled from the workspace manifests.\\n    \",examples:[[\"Prints the source code\",\"yarn constraints source\"],[\"Print the source code and the fact database\",\"yarn constraints source -v\"]]})}async execute(){let{Constraints:r}=await Promise.resolve().then(()=>(lS(),aS)),s=await ze.find(this.context.cwd,this.context.plugins),{project:a}=await Rt.find(s,this.context.cwd),n=await r.find(a);this.context.stdout.write(this.verbose?n.fullSource:n.source)}};Ge();Ge();Yt();iS();var XC=class extends ft{constructor(){super(...arguments);this.fix=ge.Boolean(\"--fix\",!1,{description:\"Attempt to automatically fix unambiguous issues, following a multi-pass process\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}static{this.paths=[[\"constraints\"]]}static{this.usage=ot.Usage({category:\"Constraints-related commands\",description:\"check that the project constraints are met\",details:`\n      This command will run constraints on your project and emit errors for each one that is found but isn't met. If any error is emitted the process will exit with a non-zero exit code.\n\n      If the \\`--fix\\` flag is used, Yarn will attempt to automatically fix the issues the best it can, following a multi-pass process (with a maximum of 10 iterations). Some ambiguous patterns cannot be autofixed, in which case you'll have to manually specify the right resolution.\n\n      For more information as to how to write constraints, please consult our dedicated page on our website: https://yarnpkg.com/features/constraints.\n    `,examples:[[\"Check that all constraints are satisfied\",\"yarn constraints\"],[\"Autofix all unmet constraints\",\"yarn constraints --fix\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Rt.find(r,this.context.cwd);await s.restoreInstallState();let a=await s.loadUserConfig(),n;if(a?.constraints)n=new YC(s);else{let{Constraints:h}=await Promise.resolve().then(()=>(lS(),aS));n=await h.find(s)}let c,f=!1,p=!1;for(let h=this.fix?10:1;h>0;--h){let E=await n.process();if(!E)break;let{changedWorkspaces:C,remainingErrors:S}=nF(s,E,{fix:this.fix}),b=[];for(let[I,T]of C){let N=I.manifest.indent;I.manifest=new Ut,I.manifest.indent=N,I.manifest.load(T),b.push(I.persistManifest())}if(await Promise.all(b),!(C.size>0&&h>1)){c=Zye(S,{configuration:r}),f=!1,p=!0;for(let[,I]of S)for(let T of I)T.fixable?f=!0:p=!1}}if(c.children.length===0)return 0;if(f){let h=p?`Those errors can all be fixed by running ${he.pretty(r,\"yarn constraints --fix\",he.Type.CODE)}`:`Errors prefixed by '\\u2699' can be fixed by running ${he.pretty(r,\"yarn constraints --fix\",he.Type.CODE)}`;await Ot.start({configuration:r,stdout:this.context.stdout,includeNames:!1,includeFooter:!1},async E=>{E.reportInfo(0,h),E.reportSeparator()})}return c.children=je.sortMap(c.children,h=>h.value[1]),xs.emitTree(c,{configuration:r,stdout:this.context.stdout,json:this.json,separators:1}),1}};iS();var Jct={configuration:{enableConstraintsChecks:{description:\"If true, constraints will run during installs\",type:\"BOOLEAN\",default:!1},constraintsPath:{description:\"The path of the constraints file.\",type:\"ABSOLUTE_PATH\",default:\"./constraints.pro\"}},commands:[zC,ZC,XC],hooks:{async validateProjectAfterInstall(t,{reportError:e}){if(!t.configuration.get(\"enableConstraintsChecks\"))return;let r=await t.loadUserConfig(),s;if(r?.constraints)s=new YC(t);else{let{Constraints:c}=await Promise.resolve().then(()=>(lS(),aS));s=await c.find(t)}let a=await s.process();if(!a)return;let{remainingErrors:n}=nF(t,a);if(n.size!==0)if(t.configuration.isCI)for(let[c,f]of n)for(let p of f)e(84,`${he.pretty(t.configuration,c.anchoredLocator,he.Type.IDENT)}: ${p.text}`);else e(84,`Constraint check failed; run ${he.pretty(t.configuration,\"yarn constraints\",he.Type.CODE)} for more details`)}}},Kct=Jct;var F5={};Vt(F5,{CreateCommand:()=>$C,DlxCommand:()=>ew,default:()=>Zct});Ge();Yt();var $C=class extends ft{constructor(){super(...arguments);this.pkg=ge.String(\"-p,--package\",{description:\"The package to run the provided command from\"});this.quiet=ge.Boolean(\"-q,--quiet\",!1,{description:\"Only report critical errors instead of printing the full install logs\"});this.command=ge.String();this.args=ge.Proxy()}static{this.paths=[[\"create\"]]}async execute(){let r=[];this.pkg&&r.push(\"--package\",this.pkg),this.quiet&&r.push(\"--quiet\");let s=this.command.replace(/^(@[^@/]+)(@|$)/,\"$1/create$2\"),a=G.parseDescriptor(s),n=a.name.match(/^create(-|$)/)?a:a.scope?G.makeIdent(a.scope,`create-${a.name}`):G.makeIdent(null,`create-${a.name}`),c=G.stringifyIdent(n);return a.range!==\"unknown\"&&(c+=`@${a.range}`),this.cli.run([\"dlx\",...r,c,...this.args])}};Ge();Ge();Dt();Yt();var ew=class extends ft{constructor(){super(...arguments);this.packages=ge.Array(\"-p,--package\",{description:\"The package(s) to install before running the command\"});this.quiet=ge.Boolean(\"-q,--quiet\",!1,{description:\"Only report critical errors instead of printing the full install logs\"});this.command=ge.String();this.args=ge.Proxy()}static{this.paths=[[\"dlx\"]]}static{this.usage=ot.Usage({description:\"run a package in a temporary environment\",details:\"\\n      This command will install a package within a temporary environment, and run its binary script if it contains any. The binary will run within the current cwd.\\n\\n      By default Yarn will download the package named `command`, but this can be changed through the use of the `-p,--package` flag which will instruct Yarn to still run the same command but from a different package.\\n\\n      Using `yarn dlx` as a replacement of `yarn add` isn't recommended, as it makes your project non-deterministic (Yarn doesn't keep track of the packages installed through `dlx` - neither their name, nor their version).\\n    \",examples:[[\"Use create-vite to scaffold a new Vite project\",\"yarn dlx create-vite\"],[\"Install multiple packages for a single command\",`yarn dlx -p typescript -p ts-node ts-node --transpile-only -e \"console.log('hello!')\"`]]})}async execute(){return ze.telemetry=null,await ce.mktempPromise(async r=>{let s=J.join(r,`dlx-${process.pid}`);await ce.mkdirPromise(s),await ce.writeFilePromise(J.join(s,\"package.json\"),`{}\n`),await ce.writeFilePromise(J.join(s,\"yarn.lock\"),\"\");let a=J.join(s,\".yarnrc.yml\"),n=await ze.findProjectCwd(this.context.cwd),f={enableGlobalCache:!(await ze.find(this.context.cwd,null,{strict:!1})).get(\"enableGlobalCache\"),enableTelemetry:!1,logFilters:[{code:Yf(68),level:he.LogLevel.Discard}]},p=n!==null?J.join(n,\".yarnrc.yml\"):null;p!==null&&ce.existsSync(p)?(await ce.copyFilePromise(p,a),await ze.updateConfiguration(s,N=>{let U=je.toMerged(N,f);return Array.isArray(N.plugins)&&(U.plugins=N.plugins.map(W=>{let ee=typeof W==\"string\"?W:W.path,ie=fe.isAbsolute(ee)?ee:fe.resolve(fe.fromPortablePath(n),ee);return typeof W==\"string\"?ie:{path:ie,spec:W.spec}})),U})):await ce.writeJsonPromise(a,f);let h=this.packages??[this.command],E=G.parseDescriptor(this.command).name,C=await this.cli.run([\"add\",\"--fixed\",\"--\",...h],{cwd:s,quiet:this.quiet});if(C!==0)return C;this.quiet||this.context.stdout.write(`\n`);let S=await ze.find(s,this.context.plugins),{project:b,workspace:I}=await Rt.find(S,s);if(I===null)throw new ar(b.cwd,s);await b.restoreInstallState();let T=await In.getWorkspaceAccessibleBinaries(I);return T.has(E)===!1&&T.size===1&&typeof this.packages>\"u\"&&(E=Array.from(T)[0][0]),await In.executeWorkspaceAccessibleBinary(I,E,this.args,{packageAccessibleBinaries:T,cwd:this.context.cwd,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr})})}};var zct={commands:[$C,ew]},Zct=zct;var L5={};Vt(L5,{ExecFetcher:()=>uS,ExecResolver:()=>fS,default:()=>eut,execUtils:()=>aF});Ge();Ge();Dt();var cA=\"exec:\";var aF={};Vt(aF,{loadGeneratorFile:()=>cS,makeLocator:()=>O5,makeSpec:()=>BEe,parseSpec:()=>N5});Ge();Dt();function N5(t){let{params:e,selector:r}=G.parseRange(t),s=fe.toPortablePath(r);return{parentLocator:e&&typeof e.locator==\"string\"?G.parseLocator(e.locator):null,path:s}}function BEe({parentLocator:t,path:e,generatorHash:r,protocol:s}){let a=t!==null?{locator:G.stringifyLocator(t)}:{},n=typeof r<\"u\"?{hash:r}:{};return G.makeRange({protocol:s,source:e,selector:e,params:{...n,...a}})}function O5(t,{parentLocator:e,path:r,generatorHash:s,protocol:a}){return G.makeLocator(t,BEe({parentLocator:e,path:r,generatorHash:s,protocol:a}))}async function cS(t,e,r){let{parentLocator:s,path:a}=G.parseFileStyleRange(t,{protocol:e}),n=J.isAbsolute(a)?{packageFs:new Sn(vt.root),prefixPath:vt.dot,localPath:vt.root}:await r.fetcher.fetch(s,r),c=n.localPath?{packageFs:new Sn(vt.root),prefixPath:J.relative(vt.root,n.localPath)}:n;n!==c&&n.releaseFs&&n.releaseFs();let f=c.packageFs,p=J.join(c.prefixPath,a);return await f.readFilePromise(p,\"utf8\")}var uS=class{supports(e,r){return!!e.reference.startsWith(cA)}getLocalPath(e,r){let{parentLocator:s,path:a}=G.parseFileStyleRange(e.reference,{protocol:cA});if(J.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(s,r);return n===null?null:J.resolve(n,a)}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e),loader:()=>this.fetchFromDisk(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:c}}async fetchFromDisk(e,r){let s=await cS(e.reference,cA,r);return ce.mktempPromise(async a=>{let n=J.join(a,\"generator.js\");return await ce.writeFilePromise(n,s),ce.mktempPromise(async c=>{if(await this.generatePackage(c,e,n,r),!ce.existsSync(J.join(c,\"build\")))throw new Error(\"The script should have generated a build directory\");return await ps.makeArchiveFromDirectory(J.join(c,\"build\"),{prefixPath:G.getIdentVendorPath(e),compressionLevel:r.project.configuration.get(\"compressionLevel\")})})})}async generatePackage(e,r,s,a){return await ce.mktempPromise(async n=>{let c=await In.makeScriptEnv({project:a.project,binFolder:n}),f=J.join(e,\"runtime.js\");return await ce.mktempPromise(async p=>{let h=J.join(p,\"buildfile.log\"),E=J.join(e,\"generator\"),C=J.join(e,\"build\");await ce.mkdirPromise(E),await ce.mkdirPromise(C);let S={tempDir:fe.fromPortablePath(E),buildDir:fe.fromPortablePath(C),locator:G.stringifyLocator(r)};await ce.writeFilePromise(f,`\n          // Expose 'Module' as a global variable\n          Object.defineProperty(global, 'Module', {\n            get: () => require('module'),\n            configurable: true,\n            enumerable: false,\n          });\n\n          // Expose non-hidden built-in modules as global variables\n          for (const name of Module.builtinModules.filter((name) => name !== 'module' && !name.startsWith('_'))) {\n            Object.defineProperty(global, name, {\n              get: () => require(name),\n              configurable: true,\n              enumerable: false,\n            });\n          }\n\n          // Expose the 'execEnv' global variable\n          Object.defineProperty(global, 'execEnv', {\n            value: {\n              ...${JSON.stringify(S)},\n            },\n            enumerable: true,\n          });\n        `);let b=c.NODE_OPTIONS||\"\",I=/\\s*--require\\s+\\S*\\.pnp\\.c?js\\s*/g;b=b.replace(I,\" \").trim(),c.NODE_OPTIONS=b;let{stdout:T,stderr:N}=a.project.configuration.getSubprocessStreams(h,{header:`# This file contains the result of Yarn generating a package (${G.stringifyLocator(r)})\n`,prefix:G.prettyLocator(a.project.configuration,r),report:a.report}),{code:U}=await qr.pipevp(process.execPath,[\"--require\",fe.fromPortablePath(f),fe.fromPortablePath(s),G.stringifyIdent(r)],{cwd:e,env:c,stdin:null,stdout:T,stderr:N});if(U!==0)throw ce.detachTemp(p),new Error(`Package generation failed (exit code ${U}, logs can be found here: ${he.pretty(a.project.configuration,h,he.Type.PATH)})`)})})}};Ge();Ge();var Xct=2,fS=class{supportsDescriptor(e,r){return!!e.range.startsWith(cA)}supportsLocator(e,r){return!!e.reference.startsWith(cA)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,s){return G.bindDescriptor(e,{locator:G.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){if(!s.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let{path:a,parentLocator:n}=N5(e.range);if(n===null)throw new Error(\"Assertion failed: The descriptor should have been bound\");let c=await cS(G.makeRange({protocol:cA,source:a,selector:a,params:{locator:G.stringifyLocator(n)}}),cA,s.fetchOptions),f=Nn.makeHash(`${Xct}`,c).slice(0,6);return[O5(e,{parentLocator:n,path:a,generatorHash:f,protocol:cA})]}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let s=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Ut.find(s.prefixPath,{baseFs:s.packageFs}),s.releaseFs);return{...e,version:a.version||\"0.0.0\",languageName:a.languageName||r.project.configuration.get(\"defaultLanguageName\"),linkType:\"HARD\",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var $ct={fetchers:[uS],resolvers:[fS]},eut=$ct;var U5={};Vt(U5,{FileFetcher:()=>gS,FileResolver:()=>dS,TarballFileFetcher:()=>mS,TarballFileResolver:()=>yS,default:()=>nut,fileUtils:()=>xm});Ge();Dt();var tw=/^(?:[a-zA-Z]:[\\\\/]|\\.{0,2}\\/)/,AS=/^[^?]*\\.(?:tar\\.gz|tgz)(?:::.*)?$/,$i=\"file:\";var xm={};Vt(xm,{fetchArchiveFromLocator:()=>hS,makeArchiveFromLocator:()=>lF,makeBufferFromLocator:()=>M5,makeLocator:()=>rw,makeSpec:()=>vEe,parseSpec:()=>pS});Ge();Dt();function pS(t){let{params:e,selector:r}=G.parseRange(t),s=fe.toPortablePath(r);return{parentLocator:e&&typeof e.locator==\"string\"?G.parseLocator(e.locator):null,path:s}}function vEe({parentLocator:t,path:e,hash:r,protocol:s}){let a=t!==null?{locator:G.stringifyLocator(t)}:{},n=typeof r<\"u\"?{hash:r}:{};return G.makeRange({protocol:s,source:e,selector:e,params:{...n,...a}})}function rw(t,{parentLocator:e,path:r,hash:s,protocol:a}){return G.makeLocator(t,vEe({parentLocator:e,path:r,hash:s,protocol:a}))}async function hS(t,e){let{parentLocator:r,path:s}=G.parseFileStyleRange(t.reference,{protocol:$i}),a=J.isAbsolute(s)?{packageFs:new Sn(vt.root),prefixPath:vt.dot,localPath:vt.root}:await e.fetcher.fetch(r,e),n=a.localPath?{packageFs:new Sn(vt.root),prefixPath:J.relative(vt.root,a.localPath)}:a;a!==n&&a.releaseFs&&a.releaseFs();let c=n.packageFs,f=J.join(n.prefixPath,s);return await je.releaseAfterUseAsync(async()=>await c.readFilePromise(f),n.releaseFs)}async function lF(t,{protocol:e,fetchOptions:r,inMemory:s=!1}){let{parentLocator:a,path:n}=G.parseFileStyleRange(t.reference,{protocol:e}),c=J.isAbsolute(n)?{packageFs:new Sn(vt.root),prefixPath:vt.dot,localPath:vt.root}:await r.fetcher.fetch(a,r),f=c.localPath?{packageFs:new Sn(vt.root),prefixPath:J.relative(vt.root,c.localPath)}:c;c!==f&&c.releaseFs&&c.releaseFs();let p=f.packageFs,h=J.join(f.prefixPath,n);return await je.releaseAfterUseAsync(async()=>await ps.makeArchiveFromDirectory(h,{baseFs:p,prefixPath:G.getIdentVendorPath(t),compressionLevel:r.project.configuration.get(\"compressionLevel\"),inMemory:s}),f.releaseFs)}async function M5(t,{protocol:e,fetchOptions:r}){return(await lF(t,{protocol:e,fetchOptions:r,inMemory:!0})).getBufferAndClose()}var gS=class{supports(e,r){return!!e.reference.startsWith($i)}getLocalPath(e,r){let{parentLocator:s,path:a}=G.parseFileStyleRange(e.reference,{protocol:$i});if(J.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(s,r);return n===null?null:J.resolve(n,a)}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${G.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the disk`),loader:()=>this.fetchFromDisk(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:c}}async fetchFromDisk(e,r){return lF(e,{protocol:$i,fetchOptions:r})}};Ge();Ge();var tut=2,dS=class{supportsDescriptor(e,r){return e.range.match(tw)?!0:!!e.range.startsWith($i)}supportsLocator(e,r){return!!e.reference.startsWith($i)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,s){return tw.test(e.range)&&(e=G.makeDescriptor(e,`${$i}${e.range}`)),G.bindDescriptor(e,{locator:G.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){if(!s.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let{path:a,parentLocator:n}=pS(e.range);if(n===null)throw new Error(\"Assertion failed: The descriptor should have been bound\");let c=await M5(G.makeLocator(e,G.makeRange({protocol:$i,source:a,selector:a,params:{locator:G.stringifyLocator(n)}})),{protocol:$i,fetchOptions:s.fetchOptions}),f=Nn.makeHash(`${tut}`,c).slice(0,6);return[rw(e,{parentLocator:n,path:a,hash:f,protocol:$i})]}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let s=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Ut.find(s.prefixPath,{baseFs:s.packageFs}),s.releaseFs);return{...e,version:a.version||\"0.0.0\",languageName:a.languageName||r.project.configuration.get(\"defaultLanguageName\"),linkType:\"HARD\",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};Ge();var mS=class{supports(e,r){return AS.test(e.reference)?!!e.reference.startsWith($i):!1}getLocalPath(e,r){return null}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${G.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the disk`),loader:()=>this.fetchFromDisk(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),checksum:c}}async fetchFromDisk(e,r){let s=await hS(e,r);return await ps.convertToZip(s,{configuration:r.project.configuration,prefixPath:G.getIdentVendorPath(e),stripComponents:1})}};Ge();Ge();Ge();var yS=class{supportsDescriptor(e,r){return AS.test(e.range)?!!(e.range.startsWith($i)||tw.test(e.range)):!1}supportsLocator(e,r){return AS.test(e.reference)?!!e.reference.startsWith($i):!1}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,s){return tw.test(e.range)&&(e=G.makeDescriptor(e,`${$i}${e.range}`)),G.bindDescriptor(e,{locator:G.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){if(!s.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let{path:a,parentLocator:n}=pS(e.range);if(n===null)throw new Error(\"Assertion failed: The descriptor should have been bound\");let c=rw(e,{parentLocator:n,path:a,hash:\"\",protocol:$i}),f=await hS(c,s.fetchOptions),p=Nn.makeHash(f).slice(0,6);return[rw(e,{parentLocator:n,path:a,hash:p,protocol:$i})]}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let s=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Ut.find(s.prefixPath,{baseFs:s.packageFs}),s.releaseFs);return{...e,version:a.version||\"0.0.0\",languageName:a.languageName||r.project.configuration.get(\"defaultLanguageName\"),linkType:\"HARD\",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var rut={fetchers:[mS,gS],resolvers:[yS,dS]},nut=rut;var j5={};Vt(j5,{GithubFetcher:()=>ES,default:()=>sut,githubUtils:()=>cF});Ge();Dt();var cF={};Vt(cF,{invalidGithubUrlMessage:()=>PEe,isGithubUrl:()=>_5,parseGithubUrl:()=>H5});var SEe=ut(Ie(\"querystring\")),DEe=[/^https?:\\/\\/(?:([^/]+?)@)?github.com\\/([^/#]+)\\/([^/#]+)\\/tarball\\/([^/#]+)(?:#(.*))?$/,/^https?:\\/\\/(?:([^/]+?)@)?github.com\\/([^/#]+)\\/([^/#]+?)(?:\\.git)?(?:#(.*))?$/];function _5(t){return t?DEe.some(e=>!!t.match(e)):!1}function H5(t){let e;for(let f of DEe)if(e=t.match(f),e)break;if(!e)throw new Error(PEe(t));let[,r,s,a,n=\"master\"]=e,{commit:c}=SEe.default.parse(n);return n=c||n.replace(/[^:]*:/,\"\"),{auth:r,username:s,reponame:a,treeish:n}}function PEe(t){return`Input cannot be parsed as a valid GitHub URL ('${t}').`}var ES=class{supports(e,r){return!!_5(e.reference)}getLocalPath(e,r){return null}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${G.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from GitHub`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),checksum:c}}async fetchFromNetwork(e,r){let s=await ln.get(this.getLocatorUrl(e,r),{configuration:r.project.configuration});return await ce.mktempPromise(async a=>{let n=new Sn(a);await ps.extractArchiveTo(s,n,{stripComponents:1});let c=ka.splitRepoUrl(e.reference),f=J.join(a,\"package.tgz\");await In.prepareExternalProject(a,f,{configuration:r.project.configuration,report:r.report,workspace:c.extra.workspace,locator:e});let p=await ce.readFilePromise(f);return await ps.convertToZip(p,{configuration:r.project.configuration,prefixPath:G.getIdentVendorPath(e),stripComponents:1})})}getLocatorUrl(e,r){let{auth:s,username:a,reponame:n,treeish:c}=H5(e.reference);return`https://${s?`${s}@`:\"\"}github.com/${a}/${n}/archive/${c}.tar.gz`}};var iut={hooks:{async fetchHostedRepository(t,e,r){if(t!==null)return t;let s=new ES;if(!s.supports(e,r))return null;try{return await s.fetch(e,r)}catch{return null}}}},sut=iut;var G5={};Vt(G5,{TarballHttpFetcher:()=>CS,TarballHttpResolver:()=>wS,default:()=>aut});Ge();function IS(t){let e;try{e=new URL(t)}catch{return!1}return!(e.protocol!==\"http:\"&&e.protocol!==\"https:\"||!e.pathname.match(/(\\.tar\\.gz|\\.tgz|\\/[^.]+)$/))}var CS=class{supports(e,r){return IS(e.reference)}getLocalPath(e,r){return null}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${G.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote server`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),checksum:c}}async fetchFromNetwork(e,r){let s=await ln.get(e.reference,{configuration:r.project.configuration});return await ps.convertToZip(s,{configuration:r.project.configuration,prefixPath:G.getIdentVendorPath(e),stripComponents:1})}};Ge();Ge();var wS=class{supportsDescriptor(e,r){return IS(e.range)}supportsLocator(e,r){return IS(e.reference)}shouldPersistResolution(e,r){return!0}bindDescriptor(e,r,s){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){return[G.convertDescriptorToLocator(e)]}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let s=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Ut.find(s.prefixPath,{baseFs:s.packageFs}),s.releaseFs);return{...e,version:a.version||\"0.0.0\",languageName:a.languageName||r.project.configuration.get(\"defaultLanguageName\"),linkType:\"HARD\",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var out={fetchers:[CS],resolvers:[wS]},aut=out;var q5={};Vt(q5,{InitCommand:()=>z0,InitInitializerCommand:()=>nw,default:()=>cut});Yt();Ge();Ge();Dt();Yt();var z0=class extends ft{constructor(){super(...arguments);this.private=ge.Boolean(\"-p,--private\",!1,{description:\"Initialize a private package\"});this.workspace=ge.Boolean(\"-w,--workspace\",!1,{description:\"Initialize a workspace root with a `packages/` directory\"});this.install=ge.String(\"-i,--install\",!1,{tolerateBoolean:!0,description:\"Initialize a package with a specific bundle that will be locked in the project\"});this.name=ge.String(\"-n,--name\",{description:\"Initialize a package with the given name\"});this.usev2=ge.Boolean(\"-2\",!1,{hidden:!0});this.yes=ge.Boolean(\"-y,--yes\",{hidden:!0})}static{this.paths=[[\"init\"]]}static{this.usage=ot.Usage({description:\"create a new package\",details:\"\\n      This command will setup a new package in your local directory.\\n\\n      If the `-p,--private` or `-w,--workspace` options are set, the package will be private by default.\\n\\n      If the `-w,--workspace` option is set, the package will be configured to accept a set of workspaces in the `packages/` directory.\\n\\n      If the `-i,--install` option is given a value, Yarn will first download it using `yarn set version` and only then forward the init call to the newly downloaded bundle. Without arguments, the downloaded bundle will be `latest`.\\n\\n      The initial settings of the manifest can be changed by using the `initScope` and `initFields` configuration values. Additionally, Yarn will generate an EditorConfig file whose rules can be altered via `initEditorConfig`, and will initialize a Git repository in the current directory.\\n    \",examples:[[\"Create a new package in the local directory\",\"yarn init\"],[\"Create a new private package in the local directory\",\"yarn init -p\"],[\"Create a new package and store the Yarn release inside\",\"yarn init -i=latest\"],[\"Create a new private package and defines it as a workspace root\",\"yarn init -w\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=typeof this.install==\"string\"?this.install:this.usev2||this.install===!0?\"latest\":null;return s!==null?await this.executeProxy(r,s):await this.executeRegular(r)}async executeProxy(r,s){if(r.projectCwd!==null&&r.projectCwd!==this.context.cwd)throw new nt(\"Cannot use the --install flag from within a project subdirectory\");ce.existsSync(this.context.cwd)||await ce.mkdirPromise(this.context.cwd,{recursive:!0});let a=J.join(this.context.cwd,Er.lockfile);ce.existsSync(a)||await ce.writeFilePromise(a,\"\");let n=await this.cli.run([\"set\",\"version\",s],{quiet:!0});if(n!==0)return n;let c=[];return this.private&&c.push(\"-p\"),this.workspace&&c.push(\"-w\"),this.name&&c.push(`-n=${this.name}`),this.yes&&c.push(\"-y\"),await ce.mktempPromise(async f=>{let{code:p}=await qr.pipevp(\"yarn\",[\"init\",...c],{cwd:this.context.cwd,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr,env:await In.makeScriptEnv({binFolder:f})});return p})}async initialize(){}async executeRegular(r){let s=null;try{s=(await Rt.find(r,this.context.cwd)).project}catch{s=null}ce.existsSync(this.context.cwd)||await ce.mkdirPromise(this.context.cwd,{recursive:!0});let a=await Ut.tryFind(this.context.cwd),n=a??new Ut,c=Object.fromEntries(r.get(\"initFields\").entries());n.load(c),n.name=n.name??G.makeIdent(r.get(\"initScope\"),this.name??J.basename(this.context.cwd)),n.packageManager=fn&&je.isTaggedYarnVersion(fn)?`yarn@${fn}`:null,(!a&&this.workspace||this.private)&&(n.private=!0),this.workspace&&n.workspaceDefinitions.length===0&&(await ce.mkdirPromise(J.join(this.context.cwd,\"packages\"),{recursive:!0}),n.workspaceDefinitions=[{pattern:\"packages/*\"}]);let f={};n.exportTo(f);let p=J.join(this.context.cwd,Ut.fileName);await ce.changeFilePromise(p,`${JSON.stringify(f,null,2)}\n`,{automaticNewlines:!0});let h=[p],E=J.join(this.context.cwd,\"README.md\");if(ce.existsSync(E)||(await ce.writeFilePromise(E,`# ${G.stringifyIdent(n.name)}\n`),h.push(E)),!s||s.cwd===this.context.cwd){let C=J.join(this.context.cwd,Er.lockfile);ce.existsSync(C)||(await ce.writeFilePromise(C,\"\"),h.push(C));let b=[\".yarn/*\",\"!.yarn/patches\",\"!.yarn/plugins\",\"!.yarn/releases\",\"!.yarn/sdks\",\"!.yarn/versions\",\"\",\"# Whether you use PnP or not, the node_modules folder is often used to store\",\"# build artifacts that should be gitignored\",\"node_modules\",\"\",\"# Swap the comments on the following lines if you wish to use zero-installs\",\"# In that case, don't forget to run `yarn config set enableGlobalCache false`!\",\"# Documentation here: https://yarnpkg.com/features/caching#zero-installs\",\"\",\"#!.yarn/cache\",\".pnp.*\"].map(ue=>`${ue}\n`).join(\"\"),I=J.join(this.context.cwd,\".gitignore\");ce.existsSync(I)||(await ce.writeFilePromise(I,b),h.push(I));let N=[\"/.yarn/**            linguist-vendored\",\"/.yarn/releases/*    binary\",\"/.yarn/plugins/**/*  binary\",\"/.pnp.*              binary linguist-generated\"].map(ue=>`${ue}\n`).join(\"\"),U=J.join(this.context.cwd,\".gitattributes\");ce.existsSync(U)||(await ce.writeFilePromise(U,N),h.push(U));let W={\"*\":{charset:\"utf-8\",endOfLine:\"lf\",indentSize:2,indentStyle:\"space\",insertFinalNewline:!0}};je.mergeIntoTarget(W,r.get(\"initEditorConfig\"));let ee=`root = true\n`;for(let[ue,le]of Object.entries(W)){ee+=`\n[${ue}]\n`;for(let[me,pe]of Object.entries(le)){let Be=me.replace(/[A-Z]/g,Ce=>`_${Ce.toLowerCase()}`);ee+=`${Be} = ${pe}\n`}}let ie=J.join(this.context.cwd,\".editorconfig\");ce.existsSync(ie)||(await ce.writeFilePromise(ie,ee),h.push(ie)),await this.cli.run([\"install\"],{quiet:!0}),await this.initialize(),ce.existsSync(J.join(this.context.cwd,\".git\"))||(await qr.execvp(\"git\",[\"init\"],{cwd:this.context.cwd}),await qr.execvp(\"git\",[\"add\",\"--\",...h],{cwd:this.context.cwd}),await qr.execvp(\"git\",[\"commit\",\"--allow-empty\",\"-m\",\"First commit\"],{cwd:this.context.cwd}))}}};var nw=class extends z0{constructor(){super(...arguments);this.initializer=ge.String();this.argv=ge.Proxy()}static{this.paths=[[\"init\"]]}async initialize(){this.context.stdout.write(`\n`),await this.cli.run([\"dlx\",this.initializer,...this.argv],{quiet:!0})}};var lut={configuration:{initScope:{description:\"Scope used when creating packages via the init command\",type:\"STRING\",default:null},initFields:{description:\"Additional fields to set when creating packages via the init command\",type:\"MAP\",valueDefinition:{description:\"\",type:\"ANY\"}},initEditorConfig:{description:\"Extra rules to define in the generator editorconfig\",type:\"MAP\",valueDefinition:{description:\"\",type:\"ANY\"}}},commands:[z0,nw]},cut=lut;var HW={};Vt(HW,{SearchCommand:()=>Iw,UpgradeInteractiveCommand:()=>Cw,default:()=>ygt});Ge();var xEe=ut(Ie(\"os\"));function iw({stdout:t}){if(xEe.default.endianness()===\"BE\")throw new Error(\"Interactive commands cannot be used on big-endian systems because ink depends on yoga-layout-prebuilt which only supports little-endian architectures\");if(!t.isTTY)throw new Error(\"Interactive commands can only be used inside a TTY environment\")}Yt();var HIe=ut(l9()),c9={appId:\"OFCNCOG2CU\",apiKey:\"6fe4476ee5a1832882e326b506d14126\",indexName:\"npm-search\"},oAt=(0,HIe.default)(c9.appId,c9.apiKey).initIndex(c9.indexName),u9=async(t,e=0)=>await oAt.search(t,{analyticsTags:[\"yarn-plugin-interactive-tools\"],attributesToRetrieve:[\"name\",\"version\",\"owner\",\"repository\",\"humanDownloadsLast30Days\"],page:e,hitsPerPage:10});var CD=[\"regular\",\"dev\",\"peer\"],Iw=class extends ft{static{this.paths=[[\"search\"]]}static{this.usage=ot.Usage({category:\"Interactive commands\",description:\"open the search interface\",details:`\n    This command opens a fullscreen terminal interface where you can search for and install packages from the npm registry.\n    `,examples:[[\"Open the search window\",\"yarn search\"]]})}async execute(){iw(this.context);let{Gem:e}=await Promise.resolve().then(()=>(qF(),kW)),{ScrollableItems:r}=await Promise.resolve().then(()=>(JF(),VF)),{useKeypress:s}=await Promise.resolve().then(()=>(yD(),m2e)),{useMinistore:a}=await Promise.resolve().then(()=>(OW(),NW)),{renderForm:n}=await Promise.resolve().then(()=>(XF(),ZF)),{default:c}=await Promise.resolve().then(()=>ut(P2e())),{Box:f,Text:p}=await Promise.resolve().then(()=>ut(Wc())),{default:h,useEffect:E,useState:C}=await Promise.resolve().then(()=>ut(hn())),S=await ze.find(this.context.cwd,this.context.plugins),b=()=>h.createElement(f,{flexDirection:\"row\"},h.createElement(f,{flexDirection:\"column\",width:48},h.createElement(f,null,h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<up>\"),\"/\",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<down>\"),\" to move between packages.\")),h.createElement(f,null,h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<space>\"),\" to select a package.\")),h.createElement(f,null,h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<space>\"),\" again to change the target.\"))),h.createElement(f,{flexDirection:\"column\"},h.createElement(f,{marginLeft:1},h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<enter>\"),\" to install the selected packages.\")),h.createElement(f,{marginLeft:1},h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<ctrl+c>\"),\" to abort.\")))),I=()=>h.createElement(h.Fragment,null,h.createElement(f,{width:15},h.createElement(p,{bold:!0,underline:!0,color:\"gray\"},\"Owner\")),h.createElement(f,{width:11},h.createElement(p,{bold:!0,underline:!0,color:\"gray\"},\"Version\")),h.createElement(f,{width:10},h.createElement(p,{bold:!0,underline:!0,color:\"gray\"},\"Downloads\"))),T=()=>h.createElement(f,{width:17},h.createElement(p,{bold:!0,underline:!0,color:\"gray\"},\"Target\")),N=({hit:pe,active:Be})=>{let[Ce,g]=a(pe.name,null);s({active:Be},(Ae,se)=>{if(se.name!==\"space\")return;if(!Ce){g(CD[0]);return}let X=CD.indexOf(Ce)+1;X===CD.length?g(null):g(CD[X])},[Ce,g]);let we=G.parseIdent(pe.name),ye=G.prettyIdent(S,we);return h.createElement(f,null,h.createElement(f,{width:45},h.createElement(p,{bold:!0,wrap:\"wrap\"},ye)),h.createElement(f,{width:14,marginLeft:1},h.createElement(p,{bold:!0,wrap:\"truncate\"},pe.owner.name)),h.createElement(f,{width:10,marginLeft:1},h.createElement(p,{italic:!0,wrap:\"truncate\"},pe.version)),h.createElement(f,{width:16,marginLeft:1},h.createElement(p,null,pe.humanDownloadsLast30Days)))},U=({name:pe,active:Be})=>{let[Ce]=a(pe,null),g=G.parseIdent(pe);return h.createElement(f,null,h.createElement(f,{width:47},h.createElement(p,{bold:!0},\" - \",G.prettyIdent(S,g))),CD.map(we=>h.createElement(f,{key:we,width:14,marginLeft:1},h.createElement(p,null,\" \",h.createElement(e,{active:Ce===we}),\" \",h.createElement(p,{bold:!0},we)))))},W=()=>h.createElement(f,{marginTop:1},h.createElement(p,null,\"Powered by Algolia.\")),ie=await n(({useSubmit:pe})=>{let Be=a();pe(Be);let Ce=Array.from(Be.keys()).filter(j=>Be.get(j)!==null),[g,we]=C(\"\"),[ye,Ae]=C(0),[se,X]=C([]),De=j=>{j.match(/\\t| /)||we(j)},Te=async()=>{Ae(0);let j=await u9(g);j.query===g&&X(j.hits)},mt=async()=>{let j=await u9(g,ye+1);j.query===g&&j.page-1===ye&&(Ae(j.page),X([...se,...j.hits]))};return E(()=>{g?Te():X([])},[g]),h.createElement(f,{flexDirection:\"column\"},h.createElement(b,null),h.createElement(f,{flexDirection:\"row\",marginTop:1},h.createElement(p,{bold:!0},\"Search: \"),h.createElement(f,{width:41},h.createElement(c,{value:g,onChange:De,placeholder:\"i.e. babel, webpack, react...\",showCursor:!1})),h.createElement(I,null)),se.length?h.createElement(r,{radius:2,loop:!1,children:se.map(j=>h.createElement(N,{key:j.name,hit:j,active:!1})),willReachEnd:mt}):h.createElement(p,{color:\"gray\"},\"Start typing...\"),h.createElement(f,{flexDirection:\"row\",marginTop:1},h.createElement(f,{width:49},h.createElement(p,{bold:!0},\"Selected:\")),h.createElement(T,null)),Ce.length?Ce.map(j=>h.createElement(U,{key:j,name:j,active:!1})):h.createElement(p,{color:\"gray\"},\"No selected packages...\"),h.createElement(W,null))},{},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof ie>\"u\")return 1;let ue=Array.from(ie.keys()).filter(pe=>ie.get(pe)===\"regular\"),le=Array.from(ie.keys()).filter(pe=>ie.get(pe)===\"dev\"),me=Array.from(ie.keys()).filter(pe=>ie.get(pe)===\"peer\");return ue.length&&await this.cli.run([\"add\",...ue]),le.length&&await this.cli.run([\"add\",\"--dev\",...le]),me&&await this.cli.run([\"add\",\"--peer\",...me]),0}};Ge();Yt();GG();var F2e=ut(Ai()),T2e=/^((?:[\\^~]|>=?)?)([0-9]+)(\\.[0-9]+)(\\.[0-9]+)((?:-\\S+)?)$/;function N2e(t,e){return t.length>0?[t.slice(0,e)].concat(N2e(t.slice(e),e)):[]}var Cw=class extends ft{static{this.paths=[[\"upgrade-interactive\"]]}static{this.usage=ot.Usage({category:\"Interactive commands\",description:\"open the upgrade interface\",details:`\n      This command opens a fullscreen terminal interface where you can see any out of date packages used by your application, their status compared to the latest versions available on the remote registry, and select packages to upgrade.\n    `,examples:[[\"Open the upgrade window\",\"yarn upgrade-interactive\"]]})}async execute(){iw(this.context);let{ItemOptions:e}=await Promise.resolve().then(()=>(R2e(),Q2e)),{Pad:r}=await Promise.resolve().then(()=>(_W(),k2e)),{ScrollableItems:s}=await Promise.resolve().then(()=>(JF(),VF)),{useMinistore:a}=await Promise.resolve().then(()=>(OW(),NW)),{renderForm:n}=await Promise.resolve().then(()=>(XF(),ZF)),{Box:c,Text:f}=await Promise.resolve().then(()=>ut(Wc())),{default:p,useEffect:h,useRef:E,useState:C}=await Promise.resolve().then(()=>ut(hn())),S=await ze.find(this.context.cwd,this.context.plugins),{project:b,workspace:I}=await Rt.find(S,this.context.cwd),T=await Kr.find(S);if(!I)throw new ar(b.cwd,this.context.cwd);await b.restoreInstallState({restoreResolutions:!1});let N=this.context.stdout.rows-7,U=(we,ye)=>{let Ae=pde(we,ye),se=\"\";for(let X of Ae)X.added?se+=he.pretty(S,X.value,\"green\"):X.removed||(se+=X.value);return se},W=(we,ye)=>{if(we===ye)return ye;let Ae=G.parseRange(we),se=G.parseRange(ye),X=Ae.selector.match(T2e),De=se.selector.match(T2e);if(!X||!De)return U(we,ye);let Te=[\"gray\",\"red\",\"yellow\",\"green\",\"magenta\"],mt=null,j=\"\";for(let rt=1;rt<Te.length;++rt)mt!==null||X[rt]!==De[rt]?(mt===null&&(mt=Te[rt-1]),j+=he.pretty(S,De[rt],mt)):j+=De[rt];return j},ee=async(we,ye,Ae)=>{let se=await Zu.fetchDescriptorFrom(we,Ae,{project:b,cache:T,preserveModifier:ye,workspace:I});return se!==null?se.range:we.range},ie=async we=>{let ye=F2e.default.valid(we.range)?`^${we.range}`:we.range,[Ae,se]=await Promise.all([ee(we,we.range,ye).catch(()=>null),ee(we,we.range,\"latest\").catch(()=>null)]),X=[{value:null,label:we.range}];return Ae&&Ae!==we.range?X.push({value:Ae,label:W(we.range,Ae)}):X.push({value:null,label:\"\"}),se&&se!==Ae&&se!==we.range?X.push({value:se,label:W(we.range,se)}):X.push({value:null,label:\"\"}),X},ue=()=>p.createElement(c,{flexDirection:\"row\"},p.createElement(c,{flexDirection:\"column\",width:49},p.createElement(c,{marginLeft:1},p.createElement(f,null,\"Press \",p.createElement(f,{bold:!0,color:\"cyanBright\"},\"<up>\"),\"/\",p.createElement(f,{bold:!0,color:\"cyanBright\"},\"<down>\"),\" to select packages.\")),p.createElement(c,{marginLeft:1},p.createElement(f,null,\"Press \",p.createElement(f,{bold:!0,color:\"cyanBright\"},\"<left>\"),\"/\",p.createElement(f,{bold:!0,color:\"cyanBright\"},\"<right>\"),\" to select versions.\"))),p.createElement(c,{flexDirection:\"column\"},p.createElement(c,{marginLeft:1},p.createElement(f,null,\"Press \",p.createElement(f,{bold:!0,color:\"cyanBright\"},\"<enter>\"),\" to install.\")),p.createElement(c,{marginLeft:1},p.createElement(f,null,\"Press \",p.createElement(f,{bold:!0,color:\"cyanBright\"},\"<ctrl+c>\"),\" to abort.\")))),le=()=>p.createElement(c,{flexDirection:\"row\",paddingTop:1,paddingBottom:1},p.createElement(c,{width:50},p.createElement(f,{bold:!0},p.createElement(f,{color:\"greenBright\"},\"?\"),\" Pick the packages you want to upgrade.\")),p.createElement(c,{width:17},p.createElement(f,{bold:!0,underline:!0,color:\"gray\"},\"Current\")),p.createElement(c,{width:17},p.createElement(f,{bold:!0,underline:!0,color:\"gray\"},\"Range\")),p.createElement(c,{width:17},p.createElement(f,{bold:!0,underline:!0,color:\"gray\"},\"Latest\"))),me=({active:we,descriptor:ye,suggestions:Ae})=>{let[se,X]=a(ye.descriptorHash,null),De=G.stringifyIdent(ye),Te=Math.max(0,45-De.length);return p.createElement(p.Fragment,null,p.createElement(c,null,p.createElement(c,{width:45},p.createElement(f,{bold:!0},G.prettyIdent(S,ye)),p.createElement(r,{active:we,length:Te})),p.createElement(e,{active:we,options:Ae,value:se,skewer:!0,onChange:X,sizes:[17,17,17]})))},pe=({dependencies:we})=>{let[ye,Ae]=C(we.map(()=>null)),se=E(!0),X=async De=>{let Te=await ie(De);return Te.filter(mt=>mt.label!==\"\").length<=1?null:{descriptor:De,suggestions:Te}};return h(()=>()=>{se.current=!1},[]),h(()=>{let De=Math.trunc(N*1.75),Te=we.slice(0,De),mt=we.slice(De),j=N2e(mt,N),rt=Te.map(X).reduce(async(Fe,Ne)=>{await Fe;let be=await Ne;be!==null&&se.current&&Ae(Ve=>{let ke=Ve.findIndex(Ue=>Ue===null),it=[...Ve];return it[ke]=be,it})},Promise.resolve());j.reduce((Fe,Ne)=>Promise.all(Ne.map(be=>Promise.resolve().then(()=>X(be)))).then(async be=>{be=be.filter(Ve=>Ve!==null),await Fe,se.current&&Ae(Ve=>{let ke=Ve.findIndex(it=>it===null);return Ve.slice(0,ke).concat(be).concat(Ve.slice(ke+be.length))})}),rt).then(()=>{se.current&&Ae(Fe=>Fe.filter(Ne=>Ne!==null))})},[]),ye.length?p.createElement(s,{radius:N>>1,children:ye.map((De,Te)=>De!==null?p.createElement(me,{key:Te,active:!1,descriptor:De.descriptor,suggestions:De.suggestions}):p.createElement(f,{key:Te},\"Loading...\"))}):p.createElement(f,null,\"No upgrades found\")},Ce=await n(({useSubmit:we})=>{we(a());let ye=new Map;for(let se of b.workspaces)for(let X of[\"dependencies\",\"devDependencies\"])for(let De of se.manifest[X].values())b.tryWorkspaceByDescriptor(De)===null&&(De.range.startsWith(\"link:\")||ye.set(De.descriptorHash,De));let Ae=je.sortMap(ye.values(),se=>G.stringifyDescriptor(se));return p.createElement(c,{flexDirection:\"column\"},p.createElement(ue,null),p.createElement(le,null),p.createElement(pe,{dependencies:Ae}))},{},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof Ce>\"u\")return 1;let g=!1;for(let we of b.workspaces)for(let ye of[\"dependencies\",\"devDependencies\"]){let Ae=we.manifest[ye];for(let se of Ae.values()){let X=Ce.get(se.descriptorHash);typeof X<\"u\"&&X!==null&&(Ae.set(se.identHash,G.makeDescriptor(se,X)),g=!0)}}return g?await b.installWithNewReport({quiet:this.context.quiet,stdout:this.context.stdout},{cache:T}):0}};var mgt={commands:[Iw,Cw]},ygt=mgt;var GW={};Vt(GW,{default:()=>wgt});Ge();var BD=\"jsr:\";Ge();Ge();function ww(t){let e=t.range.slice(4);if(Fr.validRange(e))return G.makeDescriptor(t,`npm:${G.stringifyIdent(G.wrapIdentIntoScope(t,\"jsr\"))}@${e}`);let r=G.tryParseDescriptor(e,!0);if(r!==null)return G.makeDescriptor(t,`npm:${G.stringifyIdent(G.wrapIdentIntoScope(r,\"jsr\"))}@${r.range}`);throw new Error(`Invalid range: ${t.range}`)}function Bw(t){return G.makeLocator(G.wrapIdentIntoScope(t,\"jsr\"),`npm:${t.reference.slice(4)}`)}function jW(t){return G.makeLocator(G.unwrapIdentFromScope(t,\"jsr\"),`jsr:${t.reference.slice(4)}`)}var $F=class{supports(e,r){return e.reference.startsWith(BD)}getLocalPath(e,r){let s=Bw(e);return r.fetcher.getLocalPath(s,r)}fetch(e,r){let s=Bw(e);return r.fetcher.fetch(s,r)}};var eN=class{supportsDescriptor(e,r){return!!e.range.startsWith(BD)}supportsLocator(e,r){return!!e.reference.startsWith(BD)}shouldPersistResolution(e,r){let s=Bw(e);return r.resolver.shouldPersistResolution(s,r)}bindDescriptor(e,r,s){return e}getResolutionDependencies(e,r){return{inner:ww(e)}}async getCandidates(e,r,s){let a=s.project.configuration.normalizeDependency(ww(e));return(await s.resolver.getCandidates(a,r,s)).map(c=>jW(c))}async getSatisfying(e,r,s,a){let n=a.project.configuration.normalizeDependency(ww(e));return a.resolver.getSatisfying(n,r,s,a)}async resolve(e,r){let s=Bw(e),a=await r.resolver.resolve(s,r);return{...a,...jW(a)}}};var Egt=[\"dependencies\",\"devDependencies\",\"peerDependencies\"];function Igt(t,e){for(let r of Egt)for(let s of t.manifest.getForScope(r).values()){if(!s.range.startsWith(\"jsr:\"))continue;let a=ww(s),n=r===\"dependencies\"?G.makeDescriptor(s,\"unknown\"):null,c=n!==null&&t.manifest.ensureDependencyMeta(n).optional?\"optionalDependencies\":r;e[c][G.stringifyIdent(s)]=a.range}}var Cgt={hooks:{beforeWorkspacePacking:Igt},resolvers:[eN],fetchers:[$F]},wgt=Cgt;var qW={};Vt(qW,{LinkFetcher:()=>vD,LinkResolver:()=>SD,PortalFetcher:()=>DD,PortalResolver:()=>PD,default:()=>vgt});Ge();Dt();var rh=\"portal:\",nh=\"link:\";var vD=class{supports(e,r){return!!e.reference.startsWith(nh)}getLocalPath(e,r){let{parentLocator:s,path:a}=G.parseFileStyleRange(e.reference,{protocol:nh});if(J.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(s,r);return n===null?null:J.resolve(n,a)}async fetch(e,r){let{parentLocator:s,path:a}=G.parseFileStyleRange(e.reference,{protocol:nh}),n=J.isAbsolute(a)?{packageFs:new Sn(vt.root),prefixPath:vt.dot,localPath:vt.root}:await r.fetcher.fetch(s,r),c=n.localPath?{packageFs:new Sn(vt.root),prefixPath:J.relative(vt.root,n.localPath),localPath:vt.root}:n;n!==c&&n.releaseFs&&n.releaseFs();let f=c.packageFs,p=J.resolve(c.localPath??c.packageFs.getRealPath(),c.prefixPath,a);return n.localPath?{packageFs:new Sn(p,{baseFs:f}),releaseFs:c.releaseFs,prefixPath:vt.dot,discardFromLookup:!0,localPath:p}:{packageFs:new Hf(p,{baseFs:f}),releaseFs:c.releaseFs,prefixPath:vt.dot,discardFromLookup:!0}}};Ge();Dt();var SD=class{supportsDescriptor(e,r){return!!e.range.startsWith(nh)}supportsLocator(e,r){return!!e.reference.startsWith(nh)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,s){return G.bindDescriptor(e,{locator:G.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){let a=e.range.slice(nh.length);return[G.makeLocator(e,`${nh}${fe.toPortablePath(a)}`)]}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){return{...e,version:\"0.0.0\",languageName:r.project.configuration.get(\"defaultLanguageName\"),linkType:\"SOFT\",conditions:null,dependencies:new Map,peerDependencies:new Map,dependenciesMeta:new Map,peerDependenciesMeta:new Map,bin:new Map}}};Ge();Dt();var DD=class{supports(e,r){return!!e.reference.startsWith(rh)}getLocalPath(e,r){let{parentLocator:s,path:a}=G.parseFileStyleRange(e.reference,{protocol:rh});if(J.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(s,r);return n===null?null:J.resolve(n,a)}async fetch(e,r){let{parentLocator:s,path:a}=G.parseFileStyleRange(e.reference,{protocol:rh}),n=J.isAbsolute(a)?{packageFs:new Sn(vt.root),prefixPath:vt.dot,localPath:vt.root}:await r.fetcher.fetch(s,r),c=n.localPath?{packageFs:new Sn(vt.root),prefixPath:J.relative(vt.root,n.localPath),localPath:vt.root}:n;n!==c&&n.releaseFs&&n.releaseFs();let f=c.packageFs,p=J.resolve(c.localPath??c.packageFs.getRealPath(),c.prefixPath,a);return n.localPath?{packageFs:new Sn(p,{baseFs:f}),releaseFs:c.releaseFs,prefixPath:vt.dot,localPath:p}:{packageFs:new Hf(p,{baseFs:f}),releaseFs:c.releaseFs,prefixPath:vt.dot}}};Ge();Ge();Dt();var PD=class{supportsDescriptor(e,r){return!!e.range.startsWith(rh)}supportsLocator(e,r){return!!e.reference.startsWith(rh)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,s){return G.bindDescriptor(e,{locator:G.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){let a=e.range.slice(rh.length);return[G.makeLocator(e,`${rh}${fe.toPortablePath(a)}`)]}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let s=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await je.releaseAfterUseAsync(async()=>await Ut.find(s.prefixPath,{baseFs:s.packageFs}),s.releaseFs);return{...e,version:a.version||\"0.0.0\",languageName:a.languageName||r.project.configuration.get(\"defaultLanguageName\"),linkType:\"SOFT\",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var Bgt={fetchers:[vD,DD],resolvers:[SD,PD]},vgt=Bgt;var PY={};Vt(PY,{NodeModulesLinker:()=>jD,NodeModulesMode:()=>BY,PnpLooseLinker:()=>GD,default:()=>Hdt});Dt();Ge();Dt();Dt();var YW=(t,e)=>`${t}@${e}`,O2e=(t,e)=>{let r=e.indexOf(\"#\"),s=r>=0?e.substring(r+1):e;return YW(t,s)};var M2e=(t,e={})=>{let r=e.debugLevel||Number(process.env.NM_DEBUG_LEVEL||-1),s=e.check||r>=9,a=e.hoistingLimits||new Map,n={check:s,debugLevel:r,hoistingLimits:a,fastLookupPossible:!0},c;n.debugLevel>=0&&(c=Date.now());let f=Qgt(t,n),p=!1,h=0;do{let E=VW(f,[f],new Set([f.locator]),new Map,n);p=E.anotherRoundNeeded||E.isGraphChanged,n.fastLookupPossible=!1,h++}while(p);if(n.debugLevel>=0&&console.log(`hoist time: ${Date.now()-c}ms, rounds: ${h}`),n.debugLevel>=1){let E=bD(f);if(VW(f,[f],new Set([f.locator]),new Map,n).isGraphChanged)throw new Error(`The hoisting result is not terminal, prev tree:\n${E}, next tree:\n${bD(f)}`);let S=U2e(f);if(S)throw new Error(`${S}, after hoisting finished:\n${bD(f)}`)}return n.debugLevel>=2&&console.log(bD(f)),Rgt(f)},Sgt=t=>{let e=t[t.length-1],r=new Map,s=new Set,a=n=>{if(!s.has(n)){s.add(n);for(let c of n.hoistedDependencies.values())r.set(c.name,c);for(let c of n.dependencies.values())n.peerNames.has(c.name)||a(c)}};return a(e),r},Dgt=t=>{let e=t[t.length-1],r=new Map,s=new Set,a=new Set,n=(c,f)=>{if(s.has(c))return;s.add(c);for(let h of c.hoistedDependencies.values())if(!f.has(h.name)){let E;for(let C of t)E=C.dependencies.get(h.name),E&&r.set(E.name,E)}let p=new Set;for(let h of c.dependencies.values())p.add(h.name);for(let h of c.dependencies.values())c.peerNames.has(h.name)||n(h,p)};return n(e,a),r},L2e=(t,e)=>{if(e.decoupled)return e;let{name:r,references:s,ident:a,locator:n,dependencies:c,originalDependencies:f,hoistedDependencies:p,peerNames:h,reasons:E,isHoistBorder:C,hoistPriority:S,dependencyKind:b,hoistedFrom:I,hoistedTo:T}=e,N={name:r,references:new Set(s),ident:a,locator:n,dependencies:new Map(c),originalDependencies:new Map(f),hoistedDependencies:new Map(p),peerNames:new Set(h),reasons:new Map(E),decoupled:!0,isHoistBorder:C,hoistPriority:S,dependencyKind:b,hoistedFrom:new Map(I),hoistedTo:new Map(T)},U=N.dependencies.get(r);return U&&U.ident==N.ident&&N.dependencies.set(r,N),t.dependencies.set(N.name,N),N},Pgt=(t,e)=>{let r=new Map([[t.name,[t.ident]]]);for(let a of t.dependencies.values())t.peerNames.has(a.name)||r.set(a.name,[a.ident]);let s=Array.from(e.keys());s.sort((a,n)=>{let c=e.get(a),f=e.get(n);if(f.hoistPriority!==c.hoistPriority)return f.hoistPriority-c.hoistPriority;{let p=c.dependents.size+c.peerDependents.size;return f.dependents.size+f.peerDependents.size-p}});for(let a of s){let n=a.substring(0,a.indexOf(\"@\",1)),c=a.substring(n.length+1);if(!t.peerNames.has(n)){let f=r.get(n);f||(f=[],r.set(n,f)),f.indexOf(c)<0&&f.push(c)}}return r},WW=t=>{let e=new Set,r=(s,a=new Set)=>{if(!a.has(s)){a.add(s);for(let n of s.peerNames)if(!t.peerNames.has(n)){let c=t.dependencies.get(n);c&&!e.has(c)&&r(c,a)}e.add(s)}};for(let s of t.dependencies.values())t.peerNames.has(s.name)||r(s);return e},VW=(t,e,r,s,a,n=new Set)=>{let c=e[e.length-1];if(n.has(c))return{anotherRoundNeeded:!1,isGraphChanged:!1};n.add(c);let f=Tgt(c),p=Pgt(c,f),h=t==c?new Map:a.fastLookupPossible?Sgt(e):Dgt(e),E,C=!1,S=!1,b=new Map(Array.from(p.entries()).map(([T,N])=>[T,N[0]])),I=new Map;do{let T=kgt(t,e,r,h,b,p,s,I,a);T.isGraphChanged&&(S=!0),T.anotherRoundNeeded&&(C=!0),E=!1;for(let[N,U]of p)U.length>1&&!c.dependencies.has(N)&&(b.delete(N),U.shift(),b.set(N,U[0]),E=!0)}while(E);for(let T of c.dependencies.values())if(!c.peerNames.has(T.name)&&!r.has(T.locator)){r.add(T.locator);let N=VW(t,[...e,T],r,I,a);N.isGraphChanged&&(S=!0),N.anotherRoundNeeded&&(C=!0),r.delete(T.locator)}return{anotherRoundNeeded:C,isGraphChanged:S}},bgt=t=>{for(let[e,r]of t.dependencies)if(!t.peerNames.has(e)&&r.ident!==t.ident)return!0;return!1},xgt=(t,e,r,s,a,n,c,f,{outputReason:p,fastLookupPossible:h})=>{let E,C=null,S=new Set;p&&(E=`${Array.from(e).map(N=>yo(N)).join(\"\\u2192\")}`);let b=r[r.length-1],T=!(s.ident===b.ident);if(p&&!T&&(C=\"- self-reference\"),T&&(T=s.dependencyKind!==1,p&&!T&&(C=\"- workspace\")),T&&s.dependencyKind===2&&(T=!bgt(s),p&&!T&&(C=\"- external soft link with unhoisted dependencies\")),T&&(T=!t.peerNames.has(s.name),p&&!T&&(C=`- cannot shadow peer: ${yo(t.originalDependencies.get(s.name).locator)} at ${E}`)),T){let N=!1,U=a.get(s.name);if(N=!U||U.ident===s.ident,p&&!N&&(C=`- filled by: ${yo(U.locator)} at ${E}`),N)for(let W=r.length-1;W>=1;W--){let ie=r[W].dependencies.get(s.name);if(ie&&ie.ident!==s.ident){N=!1;let ue=f.get(b);ue||(ue=new Set,f.set(b,ue)),ue.add(s.name),p&&(C=`- filled by ${yo(ie.locator)} at ${r.slice(0,W).map(le=>yo(le.locator)).join(\"\\u2192\")}`);break}}T=N}if(T&&(T=n.get(s.name)===s.ident,p&&!T&&(C=`- filled by: ${yo(c.get(s.name)[0])} at ${E}`)),T){let N=!0,U=new Set(s.peerNames);for(let W=r.length-1;W>=1;W--){let ee=r[W];for(let ie of U){if(ee.peerNames.has(ie)&&ee.originalDependencies.has(ie))continue;let ue=ee.dependencies.get(ie);ue&&t.dependencies.get(ie)!==ue&&(W===r.length-1?S.add(ue):(S=null,N=!1,p&&(C=`- peer dependency ${yo(ue.locator)} from parent ${yo(ee.locator)} was not hoisted to ${E}`))),U.delete(ie)}if(!N)break}T=N}if(T&&!h)for(let N of s.hoistedDependencies.values()){let U=a.get(N.name)||t.dependencies.get(N.name);if(!U||N.ident!==U.ident){T=!1,p&&(C=`- previously hoisted dependency mismatch, needed: ${yo(N.locator)}, available: ${yo(U?.locator)}`);break}}return S!==null&&S.size>0?{isHoistable:2,dependsOn:S,reason:C}:{isHoistable:T?0:1,reason:C}},tN=t=>`${t.name}@${t.locator}`,kgt=(t,e,r,s,a,n,c,f,p)=>{let h=e[e.length-1],E=new Set,C=!1,S=!1,b=(U,W,ee,ie,ue)=>{if(E.has(ie))return;let le=[...W,tN(ie)],me=[...ee,tN(ie)],pe=new Map,Be=new Map;for(let Ae of WW(ie)){let se=xgt(h,r,[h,...U,ie],Ae,s,a,n,f,{outputReason:p.debugLevel>=2,fastLookupPossible:p.fastLookupPossible});if(Be.set(Ae,se),se.isHoistable===2)for(let X of se.dependsOn){let De=pe.get(X.name)||new Set;De.add(Ae.name),pe.set(X.name,De)}}let Ce=new Set,g=(Ae,se,X)=>{if(!Ce.has(Ae)){Ce.add(Ae),Be.set(Ae,{isHoistable:1,reason:X});for(let De of pe.get(Ae.name)||[])g(ie.dependencies.get(De),se,p.debugLevel>=2?`- peer dependency ${yo(Ae.locator)} from parent ${yo(ie.locator)} was not hoisted`:\"\")}};for(let[Ae,se]of Be)se.isHoistable===1&&g(Ae,se,se.reason);let we=!1;for(let Ae of Be.keys())if(!Ce.has(Ae)){S=!0;let se=c.get(ie);se&&se.has(Ae.name)&&(C=!0),we=!0,ie.dependencies.delete(Ae.name),ie.hoistedDependencies.set(Ae.name,Ae),ie.reasons.delete(Ae.name);let X=h.dependencies.get(Ae.name);if(p.debugLevel>=2){let De=Array.from(W).concat([ie.locator]).map(mt=>yo(mt)).join(\"\\u2192\"),Te=h.hoistedFrom.get(Ae.name);Te||(Te=[],h.hoistedFrom.set(Ae.name,Te)),Te.push(De),ie.hoistedTo.set(Ae.name,Array.from(e).map(mt=>yo(mt.locator)).join(\"\\u2192\"))}if(!X)h.ident!==Ae.ident&&(h.dependencies.set(Ae.name,Ae),ue.add(Ae));else for(let De of Ae.references)X.references.add(De)}if(ie.dependencyKind===2&&we&&(C=!0),p.check){let Ae=U2e(t);if(Ae)throw new Error(`${Ae}, after hoisting dependencies of ${[h,...U,ie].map(se=>yo(se.locator)).join(\"\\u2192\")}:\n${bD(t)}`)}let ye=WW(ie);for(let Ae of ye)if(Ce.has(Ae)){let se=Be.get(Ae);if((a.get(Ae.name)===Ae.ident||!ie.reasons.has(Ae.name))&&se.isHoistable!==0&&ie.reasons.set(Ae.name,se.reason),!Ae.isHoistBorder&&me.indexOf(tN(Ae))<0){E.add(ie);let De=L2e(ie,Ae);b([...U,ie],le,me,De,T),E.delete(ie)}}},I,T=new Set(WW(h)),N=Array.from(e).map(U=>tN(U));do{I=T,T=new Set;for(let U of I){if(U.locator===h.locator||U.isHoistBorder)continue;let W=L2e(h,U);b([],Array.from(r),N,W,T)}}while(T.size>0);return{anotherRoundNeeded:C,isGraphChanged:S}},U2e=t=>{let e=[],r=new Set,s=new Set,a=(n,c,f)=>{if(r.has(n)||(r.add(n),s.has(n)))return;let p=new Map(c);for(let h of n.dependencies.values())n.peerNames.has(h.name)||p.set(h.name,h);for(let h of n.originalDependencies.values()){let E=p.get(h.name),C=()=>`${Array.from(s).concat([n]).map(S=>yo(S.locator)).join(\"\\u2192\")}`;if(n.peerNames.has(h.name)){let S=c.get(h.name);(S!==E||!S||S.ident!==h.ident)&&e.push(`${C()} - broken peer promise: expected ${h.ident} but found ${S&&S.ident}`)}else{let S=f.hoistedFrom.get(n.name),b=n.hoistedTo.get(h.name),I=`${S?` hoisted from ${S.join(\", \")}`:\"\"}`,T=`${b?` hoisted to ${b}`:\"\"}`,N=`${C()}${I}`;E?E.ident!==h.ident&&e.push(`${N} - broken require promise for ${h.name}${T}: expected ${h.ident}, but found: ${E.ident}`):e.push(`${N} - broken require promise: no required dependency ${h.name}${T} found`)}}s.add(n);for(let h of n.dependencies.values())n.peerNames.has(h.name)||a(h,p,n);s.delete(n)};return a(t,t.dependencies,t),e.join(`\n`)},Qgt=(t,e)=>{let{identName:r,name:s,reference:a,peerNames:n}=t,c={name:s,references:new Set([a]),locator:YW(r,a),ident:O2e(r,a),dependencies:new Map,originalDependencies:new Map,hoistedDependencies:new Map,peerNames:new Set(n),reasons:new Map,decoupled:!0,isHoistBorder:!0,hoistPriority:0,dependencyKind:1,hoistedFrom:new Map,hoistedTo:new Map},f=new Map([[t,c]]),p=(h,E)=>{let C=f.get(h),S=!!C;if(!C){let{name:b,identName:I,reference:T,peerNames:N,hoistPriority:U,dependencyKind:W}=h,ee=e.hoistingLimits.get(E.locator);C={name:b,references:new Set([T]),locator:YW(I,T),ident:O2e(I,T),dependencies:new Map,originalDependencies:new Map,hoistedDependencies:new Map,peerNames:new Set(N),reasons:new Map,decoupled:!0,isHoistBorder:ee?ee.has(b):!1,hoistPriority:U||0,dependencyKind:W||0,hoistedFrom:new Map,hoistedTo:new Map},f.set(h,C)}if(E.dependencies.set(h.name,C),E.originalDependencies.set(h.name,C),S){let b=new Set,I=T=>{if(!b.has(T)){b.add(T),T.decoupled=!1;for(let N of T.dependencies.values())T.peerNames.has(N.name)||I(N)}};I(C)}else for(let b of h.dependencies)p(b,C)};for(let h of t.dependencies)p(h,c);return c},JW=t=>t.substring(0,t.indexOf(\"@\",1)),Rgt=t=>{let e={name:t.name,identName:JW(t.locator),references:new Set(t.references),dependencies:new Set},r=new Set([t]),s=(a,n,c)=>{let f=r.has(a),p;if(n===a)p=c;else{let{name:h,references:E,locator:C}=a;p={name:h,identName:JW(C),references:E,dependencies:new Set}}if(c.dependencies.add(p),!f){r.add(a);for(let h of a.dependencies.values())a.peerNames.has(h.name)||s(h,a,p);r.delete(a)}};for(let a of t.dependencies.values())s(a,t,e);return e},Tgt=t=>{let e=new Map,r=new Set([t]),s=c=>`${c.name}@${c.ident}`,a=c=>{let f=s(c),p=e.get(f);return p||(p={dependents:new Set,peerDependents:new Set,hoistPriority:0},e.set(f,p)),p},n=(c,f)=>{let p=!!r.has(f);if(a(f).dependents.add(c.ident),!p){r.add(f);for(let E of f.dependencies.values()){let C=a(E);C.hoistPriority=Math.max(C.hoistPriority,E.hoistPriority),f.peerNames.has(E.name)?C.peerDependents.add(f.ident):n(f,E)}}};for(let c of t.dependencies.values())t.peerNames.has(c.name)||n(t,c);return e},yo=t=>{if(!t)return\"none\";let e=t.indexOf(\"@\",1),r=t.substring(0,e);r.endsWith(\"$wsroot$\")&&(r=`wh:${r.replace(\"$wsroot$\",\"\")}`);let s=t.substring(e+1);if(s===\"workspace:.\")return\".\";if(s){let a=(s.indexOf(\"#\")>0?s.split(\"#\")[1]:s).replace(\"npm:\",\"\");return s.startsWith(\"virtual\")&&(r=`v:${r}`),a.startsWith(\"workspace\")&&(r=`w:${r}`,a=\"\"),`${r}${a?`@${a}`:\"\"}`}else return`${r}`};var bD=t=>{let e=0,r=(a,n,c=\"\")=>{if(e>5e4||n.has(a))return\"\";e++;let f=Array.from(a.dependencies.values()).sort((h,E)=>h.name===E.name?0:h.name>E.name?1:-1),p=\"\";n.add(a);for(let h=0;h<f.length;h++){let E=f[h];if(!a.peerNames.has(E.name)&&E!==a){let C=a.reasons.get(E.name),S=JW(E.locator);p+=`${c}${h<f.length-1?\"\\u251C\\u2500\":\"\\u2514\\u2500\"}${(n.has(E)?\">\":\"\")+(S!==E.name?`a:${E.name}:`:\"\")+yo(E.locator)+(C?` ${C}`:\"\")}\n`,p+=r(E,n,`${c}${h<f.length-1?\"\\u2502 \":\"  \"}`)}}return n.delete(a),p};return r(t,new Set)+(e>5e4?`\nTree is too large, part of the tree has been dunped\n`:\"\")};var xD=(s=>(s.WORKSPACES=\"workspaces\",s.DEPENDENCIES=\"dependencies\",s.NONE=\"none\",s))(xD||{}),_2e=\"node_modules\",rg=\"$wsroot$\";var kD=(t,e)=>{let{packageTree:r,hoistingLimits:s,errors:a,preserveSymlinksRequired:n}=Ngt(t,e),c=null;if(a.length===0){let f=M2e(r,{hoistingLimits:s});c=Lgt(t,f,e)}return{tree:c,errors:a,preserveSymlinksRequired:n}},pA=t=>`${t.name}@${t.reference}`,zW=t=>{let e=new Map;for(let[r,s]of t.entries())if(!s.dirList){let a=e.get(s.locator);a||(a={target:s.target,linkType:s.linkType,locations:[],aliases:s.aliases},e.set(s.locator,a)),a.locations.push(r)}for(let r of e.values())r.locations=r.locations.sort((s,a)=>{let n=s.split(J.delimiter).length,c=a.split(J.delimiter).length;return a===s?0:n!==c?c-n:a>s?1:-1});return e},H2e=(t,e)=>{let r=G.isVirtualLocator(t)?G.devirtualizeLocator(t):t,s=G.isVirtualLocator(e)?G.devirtualizeLocator(e):e;return G.areLocatorsEqual(r,s)},KW=(t,e,r,s)=>{if(t.linkType!==\"SOFT\")return!1;let a=fe.toPortablePath(r.resolveVirtual&&e.reference&&e.reference.startsWith(\"virtual:\")?r.resolveVirtual(t.packageLocation):t.packageLocation);return J.contains(s,a)===null},Fgt=t=>{let e=t.getPackageInformation(t.topLevel);if(e===null)throw new Error(\"Assertion failed: Expected the top-level package to have been registered\");if(t.findPackageLocator(e.packageLocation)===null)throw new Error(\"Assertion failed: Expected the top-level package to have a physical locator\");let s=fe.toPortablePath(e.packageLocation.slice(0,-1)),a=new Map,n={children:new Map},c=t.getDependencyTreeRoots(),f=new Map,p=new Set,h=(S,b)=>{let I=pA(S);if(p.has(I))return;p.add(I);let T=t.getPackageInformation(S);if(T){let N=b?pA(b):\"\";if(pA(S)!==N&&T.linkType===\"SOFT\"&&!S.reference.startsWith(\"link:\")&&!KW(T,S,t,s)){let U=j2e(T,S,t);(!f.get(U)||S.reference.startsWith(\"workspace:\"))&&f.set(U,S)}for(let[U,W]of T.packageDependencies)W!==null&&(T.packagePeers.has(U)||h(t.getLocator(U,W),S))}};for(let S of c)h(S,null);let E=s.split(J.sep);for(let S of f.values()){let b=t.getPackageInformation(S),T=fe.toPortablePath(b.packageLocation.slice(0,-1)).split(J.sep).slice(E.length),N=n;for(let U of T){let W=N.children.get(U);W||(W={children:new Map},N.children.set(U,W)),N=W}N.workspaceLocator=S}let C=(S,b)=>{if(S.workspaceLocator){let I=pA(b),T=a.get(I);T||(T=new Set,a.set(I,T)),T.add(S.workspaceLocator)}for(let I of S.children.values())C(I,S.workspaceLocator||b)};for(let S of n.children.values())C(S,n.workspaceLocator);return a},Ngt=(t,e)=>{let r=[],s=!1,a=new Map,n=Fgt(t),c=t.getPackageInformation(t.topLevel);if(c===null)throw new Error(\"Assertion failed: Expected the top-level package to have been registered\");let f=t.findPackageLocator(c.packageLocation);if(f===null)throw new Error(\"Assertion failed: Expected the top-level package to have a physical locator\");let p=fe.toPortablePath(c.packageLocation.slice(0,-1)),h={name:f.name,identName:f.name,reference:f.reference,peerNames:c.packagePeers,dependencies:new Set,dependencyKind:1},E=new Map,C=(b,I)=>`${pA(I)}:${b}`,S=(b,I,T,N,U,W,ee,ie)=>{let ue=C(b,T),le=E.get(ue),me=!!le;!me&&T.name===f.name&&T.reference===f.reference&&(le=h,E.set(ue,h));let pe=KW(I,T,t,p);if(!le){let Ae=0;pe?Ae=2:I.linkType===\"SOFT\"&&T.name.endsWith(rg)&&(Ae=1),le={name:b,identName:T.name,reference:T.reference,dependencies:new Set,peerNames:Ae===1?new Set:I.packagePeers,dependencyKind:Ae},E.set(ue,le)}let Be;if(pe?Be=2:U.linkType===\"SOFT\"?Be=1:Be=0,le.hoistPriority=Math.max(le.hoistPriority||0,Be),ie&&!pe){let Ae=pA({name:N.identName,reference:N.reference}),se=a.get(Ae)||new Set;a.set(Ae,se),se.add(le.name)}let Ce=new Map(I.packageDependencies);if(e.project){let Ae=e.project.workspacesByCwd.get(fe.toPortablePath(I.packageLocation.slice(0,-1)));if(Ae){let se=new Set([...Array.from(Ae.manifest.peerDependencies.values(),X=>G.stringifyIdent(X)),...Array.from(Ae.manifest.peerDependenciesMeta.keys())]);for(let X of se)Ce.has(X)||(Ce.set(X,W.get(X)||null),le.peerNames.add(X))}}let g=pA({name:T.name.replace(rg,\"\"),reference:T.reference}),we=n.get(g);if(we)for(let Ae of we)Ce.set(`${Ae.name}${rg}`,Ae.reference);(I!==U||I.linkType!==\"SOFT\"||!pe&&(!e.selfReferencesByCwd||e.selfReferencesByCwd.get(ee)))&&N.dependencies.add(le);let ye=T!==f&&I.linkType===\"SOFT\"&&!T.name.endsWith(rg)&&!pe;if(!me&&!ye){let Ae=new Map;for(let[se,X]of Ce)if(X!==null){let De=t.getLocator(se,X),Te=t.getLocator(se.replace(rg,\"\"),X),mt=t.getPackageInformation(Te);if(mt===null)throw new Error(\"Assertion failed: Expected the package to have been registered\");let j=KW(mt,De,t,p);if(e.validateExternalSoftLinks&&e.project&&j){mt.packageDependencies.size>0&&(s=!0);for(let[Ve,ke]of mt.packageDependencies)if(ke!==null){let it=G.parseLocator(Array.isArray(ke)?`${ke[0]}@${ke[1]}`:`${Ve}@${ke}`);if(pA(it)!==pA(De)){let Ue=Ce.get(Ve);if(Ue){let x=G.parseLocator(Array.isArray(Ue)?`${Ue[0]}@${Ue[1]}`:`${Ve}@${Ue}`);H2e(x,it)||r.push({messageName:71,text:`Cannot link ${G.prettyIdent(e.project.configuration,G.parseIdent(De.name))} into ${G.prettyLocator(e.project.configuration,G.parseLocator(`${T.name}@${T.reference}`))} dependency ${G.prettyLocator(e.project.configuration,it)} conflicts with parent dependency ${G.prettyLocator(e.project.configuration,x)}`})}else{let x=Ae.get(Ve);if(x){let w=x.target,P=G.parseLocator(Array.isArray(w)?`${w[0]}@${w[1]}`:`${Ve}@${w}`);H2e(P,it)||r.push({messageName:71,text:`Cannot link ${G.prettyIdent(e.project.configuration,G.parseIdent(De.name))} into ${G.prettyLocator(e.project.configuration,G.parseLocator(`${T.name}@${T.reference}`))} dependency ${G.prettyLocator(e.project.configuration,it)} conflicts with dependency ${G.prettyLocator(e.project.configuration,P)} from sibling portal ${G.prettyIdent(e.project.configuration,G.parseIdent(x.portal.name))}`})}else Ae.set(Ve,{target:it.reference,portal:De})}}}}let rt=e.hoistingLimitsByCwd?.get(ee),Fe=j?ee:J.relative(p,fe.toPortablePath(mt.packageLocation))||vt.dot,Ne=e.hoistingLimitsByCwd?.get(Fe);S(se,mt,De,le,I,Ce,Fe,rt===\"dependencies\"||Ne===\"dependencies\"||Ne===\"workspaces\")}}};return S(f.name,c,f,h,c,c.packageDependencies,vt.dot,!1),{packageTree:h,hoistingLimits:a,errors:r,preserveSymlinksRequired:s}};function j2e(t,e,r){let s=r.resolveVirtual&&e.reference&&e.reference.startsWith(\"virtual:\")?r.resolveVirtual(t.packageLocation):t.packageLocation;return fe.toPortablePath(s||t.packageLocation)}function Ogt(t,e,r){let s=e.getLocator(t.name.replace(rg,\"\"),t.reference),a=e.getPackageInformation(s);if(a===null)throw new Error(\"Assertion failed: Expected the package to be registered\");return r.pnpifyFs?{linkType:\"SOFT\",target:fe.toPortablePath(a.packageLocation)}:{linkType:a.linkType,target:j2e(a,t,e)}}var Lgt=(t,e,r)=>{let s=new Map,a=(E,C,S)=>{let{linkType:b,target:I}=Ogt(E,t,r);return{locator:pA(E),nodePath:C,target:I,linkType:b,aliases:S}},n=E=>{let[C,S]=E.split(\"/\");return S?{scope:C,name:S}:{scope:null,name:C}},c=new Set,f=(E,C,S)=>{if(c.has(E))return;c.add(E);let b=Array.from(E.references).sort().join(\"#\");for(let I of E.dependencies){let T=Array.from(I.references).sort().join(\"#\");if(I.identName===E.identName.replace(rg,\"\")&&T===b)continue;let N=Array.from(I.references).sort(),U={name:I.identName,reference:N[0]},{name:W,scope:ee}=n(I.name),ie=ee?[ee,W]:[W],ue=J.join(C,_2e),le=J.join(ue,...ie),me=`${S}/${U.name}`,pe=a(U,S,N.slice(1)),Be=!1;if(pe.linkType===\"SOFT\"&&r.project){let Ce=r.project.workspacesByCwd.get(pe.target.slice(0,-1));Be=!!(Ce&&!Ce.manifest.name)}if(!I.name.endsWith(rg)&&!Be){let Ce=s.get(le);if(Ce){if(Ce.dirList)throw new Error(`Assertion failed: ${le} cannot merge dir node with leaf node`);{let ye=G.parseLocator(Ce.locator),Ae=G.parseLocator(pe.locator);if(Ce.linkType!==pe.linkType)throw new Error(`Assertion failed: ${le} cannot merge nodes with different link types ${Ce.nodePath}/${G.stringifyLocator(ye)} and ${S}/${G.stringifyLocator(Ae)}`);if(ye.identHash!==Ae.identHash)throw new Error(`Assertion failed: ${le} cannot merge nodes with different idents ${Ce.nodePath}/${G.stringifyLocator(ye)} and ${S}/s${G.stringifyLocator(Ae)}`);pe.aliases=[...pe.aliases,...Ce.aliases,G.parseLocator(Ce.locator).reference]}}s.set(le,pe);let g=le.split(\"/\"),we=g.indexOf(_2e);for(let ye=g.length-1;we>=0&&ye>we;ye--){let Ae=fe.toPortablePath(g.slice(0,ye).join(J.sep)),se=g[ye],X=s.get(Ae);if(!X)s.set(Ae,{dirList:new Set([se])});else if(X.dirList){if(X.dirList.has(se))break;X.dirList.add(se)}}}f(I,pe.linkType===\"SOFT\"?pe.target:le,me)}},p=a({name:e.name,reference:Array.from(e.references)[0]},\"\",[]),h=p.target;return s.set(h,p),f(e,h,\"\"),s};Ge();Ge();Dt();Dt();eA();wc();var gY={};Vt(gY,{PnpInstaller:()=>Gm,PnpLinker:()=>sg,UnplugCommand:()=>Sw,default:()=>pdt,getPnpPath:()=>og,jsInstallUtils:()=>gA,pnpUtils:()=>HD,quotePathIfNeeded:()=>DBe});Dt();var SBe=Ie(\"url\");Ge();Ge();Dt();Dt();var G2e={DEFAULT:{collapsed:!1,next:{\"*\":\"DEFAULT\"}},TOP_LEVEL:{collapsed:!1,next:{fallbackExclusionList:\"FALLBACK_EXCLUSION_LIST\",packageRegistryData:\"PACKAGE_REGISTRY_DATA\",\"*\":\"DEFAULT\"}},FALLBACK_EXCLUSION_LIST:{collapsed:!1,next:{\"*\":\"FALLBACK_EXCLUSION_ENTRIES\"}},FALLBACK_EXCLUSION_ENTRIES:{collapsed:!0,next:{\"*\":\"FALLBACK_EXCLUSION_DATA\"}},FALLBACK_EXCLUSION_DATA:{collapsed:!0,next:{\"*\":\"DEFAULT\"}},PACKAGE_REGISTRY_DATA:{collapsed:!1,next:{\"*\":\"PACKAGE_REGISTRY_ENTRIES\"}},PACKAGE_REGISTRY_ENTRIES:{collapsed:!0,next:{\"*\":\"PACKAGE_STORE_DATA\"}},PACKAGE_STORE_DATA:{collapsed:!1,next:{\"*\":\"PACKAGE_STORE_ENTRIES\"}},PACKAGE_STORE_ENTRIES:{collapsed:!0,next:{\"*\":\"PACKAGE_INFORMATION_DATA\"}},PACKAGE_INFORMATION_DATA:{collapsed:!1,next:{packageDependencies:\"PACKAGE_DEPENDENCIES\",\"*\":\"DEFAULT\"}},PACKAGE_DEPENDENCIES:{collapsed:!1,next:{\"*\":\"PACKAGE_DEPENDENCY\"}},PACKAGE_DEPENDENCY:{collapsed:!0,next:{\"*\":\"DEFAULT\"}}};function Mgt(t,e,r){let s=\"\";s+=\"[\";for(let a=0,n=t.length;a<n;++a)s+=rN(String(a),t[a],e,r).replace(/^ +/g,\"\"),a+1<n&&(s+=\", \");return s+=\"]\",s}function Ugt(t,e,r){let s=`${r}  `,a=\"\";a+=r,a+=`[\n`;for(let n=0,c=t.length;n<c;++n)a+=s+rN(String(n),t[n],e,s).replace(/^ +/,\"\"),n+1<c&&(a+=\",\"),a+=`\n`;return a+=r,a+=\"]\",a}function _gt(t,e,r){let s=Object.keys(t),a=\"\";a+=\"{\";for(let n=0,c=s.length,f=0;n<c;++n){let p=s[n],h=t[p];typeof h>\"u\"||(f!==0&&(a+=\", \"),a+=JSON.stringify(p),a+=\": \",a+=rN(p,h,e,r).replace(/^ +/g,\"\"),f+=1)}return a+=\"}\",a}function Hgt(t,e,r){let s=Object.keys(t),a=`${r}  `,n=\"\";n+=r,n+=`{\n`;let c=0;for(let f=0,p=s.length;f<p;++f){let h=s[f],E=t[h];typeof E>\"u\"||(c!==0&&(n+=\",\",n+=`\n`),n+=a,n+=JSON.stringify(h),n+=\": \",n+=rN(h,E,e,a).replace(/^ +/g,\"\"),c+=1)}return c!==0&&(n+=`\n`),n+=r,n+=\"}\",n}function rN(t,e,r,s){let{next:a}=G2e[r],n=a[t]||a[\"*\"];return q2e(e,n,s)}function q2e(t,e,r){let{collapsed:s}=G2e[e];return Array.isArray(t)?s?Mgt(t,e,r):Ugt(t,e,r):typeof t==\"object\"&&t!==null?s?_gt(t,e,r):Hgt(t,e,r):JSON.stringify(t)}function W2e(t){return q2e(t,\"TOP_LEVEL\",\"\")}function QD(t,e){let r=Array.from(t);Array.isArray(e)||(e=[e]);let s=[];for(let n of e)s.push(r.map(c=>n(c)));let a=r.map((n,c)=>c);return a.sort((n,c)=>{for(let f of s){let p=f[n]<f[c]?-1:f[n]>f[c]?1:0;if(p!==0)return p}return 0}),a.map(n=>r[n])}function jgt(t){let e=new Map,r=QD(t.fallbackExclusionList||[],[({name:s,reference:a})=>s,({name:s,reference:a})=>a]);for(let{name:s,reference:a}of r){let n=e.get(s);typeof n>\"u\"&&e.set(s,n=new Set),n.add(a)}return Array.from(e).map(([s,a])=>[s,Array.from(a)])}function Ggt(t){return QD(t.fallbackPool||[],([e])=>e)}function qgt(t){let e=[],r=t.dependencyTreeRoots.find(s=>t.packageRegistry.get(s.name)?.get(s.reference)?.packageLocation===\"./\");for(let[s,a]of QD(t.packageRegistry,([n])=>n===null?\"0\":`1${n}`)){if(s===null)continue;let n=[];e.push([s,n]);for(let[c,{packageLocation:f,packageDependencies:p,packagePeers:h,linkType:E,discardFromLookup:C}]of QD(a,([S])=>S===null?\"0\":`1${S}`)){if(c===null)continue;let S=[];s!==null&&c!==null&&!p.has(s)&&S.push([s,c]);for(let[U,W]of p)S.push([U,W]);let b=QD(S,([U])=>U),I=h&&h.size>0?Array.from(h):void 0,N={packageLocation:f,packageDependencies:b,packagePeers:I,linkType:E,discardFromLookup:C||void 0};n.push([c,N]),r&&s===r.name&&c===r.reference&&e.unshift([null,[[null,N]]])}}return e}function RD(t){return{__info:[\"This file is automatically generated. Do not touch it, or risk\",\"your modifications being lost.\"],dependencyTreeRoots:t.dependencyTreeRoots,enableTopLevelFallback:t.enableTopLevelFallback||!1,ignorePatternData:t.ignorePattern||null,pnpZipBackend:t.pnpZipBackend,fallbackExclusionList:jgt(t),fallbackPool:Ggt(t),packageRegistryData:qgt(t)}}var J2e=ut(V2e());function K2e(t,e){return[t?`${t}\n`:\"\",`/* eslint-disable */\n`,`// @ts-nocheck\n`,`\"use strict\";\n`,`\n`,e,`\n`,(0,J2e.default)()].join(\"\")}function Wgt(t){return JSON.stringify(t,null,2)}function Ygt(t){return`'${t.replace(/\\\\/g,\"\\\\\\\\\").replace(/'/g,\"\\\\'\").replace(/\\n/g,`\\\\\n`)}'`}function Vgt(t){return[`const RAW_RUNTIME_STATE =\n`,`${Ygt(W2e(t))};\n\n`,`function $$SETUP_STATE(hydrateRuntimeState, basePath) {\n`,`  return hydrateRuntimeState(JSON.parse(RAW_RUNTIME_STATE), {basePath: basePath || __dirname});\n`,`}\n`].join(\"\")}function Jgt(){return[`function $$SETUP_STATE(hydrateRuntimeState, basePath) {\n`,`  const fs = require('fs');\n`,`  const path = require('path');\n`,`  const pnpDataFilepath = path.resolve(__dirname, ${JSON.stringify(Er.pnpData)});\n`,`  return hydrateRuntimeState(JSON.parse(fs.readFileSync(pnpDataFilepath, 'utf8')), {basePath: basePath || __dirname});\n`,`}\n`].join(\"\")}function z2e(t){let e=RD(t),r=Vgt(e);return K2e(t.shebang,r)}function Z2e(t){let e=RD(t),r=Jgt(),s=K2e(t.shebang,r);return{dataFile:Wgt(e),loaderFile:s}}Dt();function XW(t,{basePath:e}){let r=fe.toPortablePath(e),s=J.resolve(r),a=t.ignorePatternData!==null?new RegExp(t.ignorePatternData):null,n=new Map,c=new Map(t.packageRegistryData.map(([C,S])=>[C,new Map(S.map(([b,I])=>{if(C===null!=(b===null))throw new Error(\"Assertion failed: The name and reference should be null, or neither should\");let T=I.discardFromLookup??!1,N={name:C,reference:b},U=n.get(I.packageLocation);U?(U.discardFromLookup=U.discardFromLookup&&T,T||(U.locator=N)):n.set(I.packageLocation,{locator:N,discardFromLookup:T});let W=null;return[b,{packageDependencies:new Map(I.packageDependencies),packagePeers:new Set(I.packagePeers),linkType:I.linkType,discardFromLookup:T,get packageLocation(){return W||(W=J.join(s,I.packageLocation))}}]}))])),f=new Map(t.fallbackExclusionList.map(([C,S])=>[C,new Set(S)])),p=new Map(t.fallbackPool),h=t.dependencyTreeRoots,E=t.enableTopLevelFallback;return{basePath:r,dependencyTreeRoots:h,enableTopLevelFallback:E,fallbackExclusionList:f,pnpZipBackend:t.pnpZipBackend,fallbackPool:p,ignorePattern:a,packageLocatorsByLocations:n,packageRegistry:c}}Dt();Dt();var sh=Ie(\"module\"),jm=Ie(\"url\"),lY=Ie(\"util\");var ta=Ie(\"url\");var tBe=ut(Ie(\"assert\"));var $W=Array.isArray,TD=JSON.stringify,FD=Object.getOwnPropertyNames,Hm=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),eY=(t,e)=>RegExp.prototype.exec.call(t,e),tY=(t,...e)=>RegExp.prototype[Symbol.replace].apply(t,e),ng=(t,...e)=>String.prototype.endsWith.apply(t,e),rY=(t,...e)=>String.prototype.includes.apply(t,e),nY=(t,...e)=>String.prototype.lastIndexOf.apply(t,e),ND=(t,...e)=>String.prototype.indexOf.apply(t,e),X2e=(t,...e)=>String.prototype.replace.apply(t,e),ig=(t,...e)=>String.prototype.slice.apply(t,e),hA=(t,...e)=>String.prototype.startsWith.apply(t,e),$2e=Map,eBe=JSON.parse;function OD(t,e,r){return class extends r{constructor(...s){super(e(...s)),this.code=t,this.name=`${r.name} [${t}]`}}}var rBe=OD(\"ERR_PACKAGE_IMPORT_NOT_DEFINED\",(t,e,r)=>`Package import specifier \"${t}\" is not defined${e?` in package ${e}package.json`:\"\"} imported from ${r}`,TypeError),iY=OD(\"ERR_INVALID_MODULE_SPECIFIER\",(t,e,r=void 0)=>`Invalid module \"${t}\" ${e}${r?` imported from ${r}`:\"\"}`,TypeError),nBe=OD(\"ERR_INVALID_PACKAGE_TARGET\",(t,e,r,s=!1,a=void 0)=>{let n=typeof r==\"string\"&&!s&&r.length&&!hA(r,\"./\");return e===\".\"?((0,tBe.default)(s===!1),`Invalid \"exports\" main target ${TD(r)} defined in the package config ${t}package.json${a?` imported from ${a}`:\"\"}${n?'; targets must start with \"./\"':\"\"}`):`Invalid \"${s?\"imports\":\"exports\"}\" target ${TD(r)} defined for '${e}' in the package config ${t}package.json${a?` imported from ${a}`:\"\"}${n?'; targets must start with \"./\"':\"\"}`},Error),LD=OD(\"ERR_INVALID_PACKAGE_CONFIG\",(t,e,r)=>`Invalid package config ${t}${e?` while importing ${e}`:\"\"}${r?`. ${r}`:\"\"}`,Error),iBe=OD(\"ERR_PACKAGE_PATH_NOT_EXPORTED\",(t,e,r=void 0)=>e===\".\"?`No \"exports\" main defined in ${t}package.json${r?` imported from ${r}`:\"\"}`:`Package subpath '${e}' is not defined by \"exports\" in ${t}package.json${r?` imported from ${r}`:\"\"}`,Error);var iN=Ie(\"url\");function sBe(t,e){let r=Object.create(null);for(let s=0;s<e.length;s++){let a=e[s];Hm(t,a)&&(r[a]=t[a])}return r}var nN=new $2e;function Kgt(t,e,r,s){let a=nN.get(t);if(a!==void 0)return a;let n=s(t);if(n===void 0){let b={pjsonPath:t,exists:!1,main:void 0,name:void 0,type:\"none\",exports:void 0,imports:void 0};return nN.set(t,b),b}let c;try{c=eBe(n)}catch(b){throw new LD(t,(r?`\"${e}\" from `:\"\")+(0,iN.fileURLToPath)(r||e),b.message)}let{imports:f,main:p,name:h,type:E}=sBe(c,[\"imports\",\"main\",\"name\",\"type\"]),C=Hm(c,\"exports\")?c.exports:void 0;(typeof f!=\"object\"||f===null)&&(f=void 0),typeof p!=\"string\"&&(p=void 0),typeof h!=\"string\"&&(h=void 0),E!==\"module\"&&E!==\"commonjs\"&&(E=\"none\");let S={pjsonPath:t,exists:!0,main:p,name:h,type:E,exports:C,imports:f};return nN.set(t,S),S}function oBe(t,e){let r=new URL(\"./package.json\",t);for(;;){let n=r.pathname;if(ng(n,\"node_modules/package.json\"))break;let c=Kgt((0,iN.fileURLToPath)(r),t,void 0,e);if(c.exists)return c;let f=r;if(r=new URL(\"../package.json\",r),r.pathname===f.pathname)break}let s=(0,iN.fileURLToPath)(r),a={pjsonPath:s,exists:!1,main:void 0,name:void 0,type:\"none\",exports:void 0,imports:void 0};return nN.set(s,a),a}function zgt(t,e,r){throw new rBe(t,e&&(0,ta.fileURLToPath)(new URL(\".\",e)),(0,ta.fileURLToPath)(r))}function Zgt(t,e,r,s){let a=`request is not a valid subpath for the \"${r?\"imports\":\"exports\"}\" resolution of ${(0,ta.fileURLToPath)(e)}`;throw new iY(t,a,s&&(0,ta.fileURLToPath)(s))}function MD(t,e,r,s,a){throw typeof e==\"object\"&&e!==null?e=TD(e,null,\"\"):e=`${e}`,new nBe((0,ta.fileURLToPath)(new URL(\".\",r)),t,e,s,a&&(0,ta.fileURLToPath)(a))}var aBe=/(^|\\\\|\\/)((\\.|%2e)(\\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))(\\\\|\\/|$)/i,lBe=/\\*/g;function Xgt(t,e,r,s,a,n,c,f){if(e!==\"\"&&!n&&t[t.length-1]!==\"/\"&&MD(r,t,s,c,a),!hA(t,\"./\")){if(c&&!hA(t,\"../\")&&!hA(t,\"/\")){let C=!1;try{new URL(t),C=!0}catch{}if(!C)return n?tY(lBe,t,()=>e):t+e}MD(r,t,s,c,a)}eY(aBe,ig(t,2))!==null&&MD(r,t,s,c,a);let p=new URL(t,s),h=p.pathname,E=new URL(\".\",s).pathname;if(hA(h,E)||MD(r,t,s,c,a),e===\"\")return p;if(eY(aBe,e)!==null){let C=n?X2e(r,\"*\",()=>e):r+e;Zgt(C,s,c,a)}return n?new URL(tY(lBe,p.href,()=>e)):new URL(e,p)}function $gt(t){let e=+t;return`${e}`!==t?!1:e>=0&&e<4294967295}function vw(t,e,r,s,a,n,c,f){if(typeof e==\"string\")return Xgt(e,r,s,t,a,n,c,f);if($W(e)){if(e.length===0)return null;let p;for(let h=0;h<e.length;h++){let E=e[h],C;try{C=vw(t,E,r,s,a,n,c,f)}catch(S){if(p=S,S.code===\"ERR_INVALID_PACKAGE_TARGET\")continue;throw S}if(C!==void 0){if(C===null){p=null;continue}return C}}if(p==null)return p;throw p}else if(typeof e==\"object\"&&e!==null){let p=FD(e);for(let h=0;h<p.length;h++){let E=p[h];if($gt(E))throw new LD((0,ta.fileURLToPath)(t),a,'\"exports\" cannot contain numeric property keys.')}for(let h=0;h<p.length;h++){let E=p[h];if(E===\"default\"||f.has(E)){let C=e[E],S=vw(t,C,r,s,a,n,c,f);if(S===void 0)continue;return S}}return}else if(e===null)return null;MD(s,e,t,c,a)}function uBe(t,e){let r=ND(t,\"*\"),s=ND(e,\"*\"),a=r===-1?t.length:r+1,n=s===-1?e.length:s+1;return a>n?-1:n>a||r===-1?1:s===-1||t.length>e.length?-1:e.length>t.length?1:0}function edt(t,e,r){if(typeof t==\"string\"||$W(t))return!0;if(typeof t!=\"object\"||t===null)return!1;let s=FD(t),a=!1,n=0;for(let c=0;c<s.length;c++){let f=s[c],p=f===\"\"||f[0]!==\".\";if(n++===0)a=p;else if(a!==p)throw new LD((0,ta.fileURLToPath)(e),r,`\"exports\" cannot contain some keys starting with '.' and some not. The exports object must either be an object of package subpath keys or an object of main entry condition name keys only.`)}return a}function sY(t,e,r){throw new iBe((0,ta.fileURLToPath)(new URL(\".\",e)),t,r&&(0,ta.fileURLToPath)(r))}var cBe=new Set;function tdt(t,e,r){let s=(0,ta.fileURLToPath)(e);cBe.has(s+\"|\"+t)||(cBe.add(s+\"|\"+t),process.emitWarning(`Use of deprecated trailing slash pattern mapping \"${t}\" in the \"exports\" field module resolution of the package at ${s}${r?` imported from ${(0,ta.fileURLToPath)(r)}`:\"\"}. Mapping specifiers ending in \"/\" is no longer supported.`,\"DeprecationWarning\",\"DEP0155\"))}function fBe({packageJSONUrl:t,packageSubpath:e,exports:r,base:s,conditions:a}){if(edt(r,t,s)&&(r={\".\":r}),Hm(r,e)&&!rY(e,\"*\")&&!ng(e,\"/\")){let p=r[e],h=vw(t,p,\"\",e,s,!1,!1,a);return h==null&&sY(e,t,s),h}let n=\"\",c,f=FD(r);for(let p=0;p<f.length;p++){let h=f[p],E=ND(h,\"*\");if(E!==-1&&hA(e,ig(h,0,E))){ng(e,\"/\")&&tdt(e,t,s);let C=ig(h,E+1);e.length>=h.length&&ng(e,C)&&uBe(n,h)===1&&nY(h,\"*\")===E&&(n=h,c=ig(e,E,e.length-C.length))}}if(n){let p=r[n],h=vw(t,p,c,n,s,!0,!1,a);return h==null&&sY(e,t,s),h}sY(e,t,s)}function ABe({name:t,base:e,conditions:r,readFileSyncFn:s}){if(t===\"#\"||hA(t,\"#/\")||ng(t,\"/\")){let c=\"is not a valid internal imports specifier name\";throw new iY(t,c,(0,ta.fileURLToPath)(e))}let a,n=oBe(e,s);if(n.exists){a=(0,ta.pathToFileURL)(n.pjsonPath);let c=n.imports;if(c)if(Hm(c,t)&&!rY(t,\"*\")){let f=vw(a,c[t],\"\",t,e,!1,!0,r);if(f!=null)return f}else{let f=\"\",p,h=FD(c);for(let E=0;E<h.length;E++){let C=h[E],S=ND(C,\"*\");if(S!==-1&&hA(t,ig(C,0,S))){let b=ig(C,S+1);t.length>=C.length&&ng(t,b)&&uBe(f,C)===1&&nY(C,\"*\")===S&&(f=C,p=ig(t,S,t.length-b.length))}}if(f){let E=c[f],C=vw(a,E,p,f,e,!0,!0,r);if(C!=null)return C}}}zgt(t,a,e)}Dt();var rdt=new Set([\"BUILTIN_NODE_RESOLUTION_FAILED\",\"MISSING_DEPENDENCY\",\"MISSING_PEER_DEPENDENCY\",\"QUALIFIED_PATH_RESOLUTION_FAILED\",\"UNDECLARED_DEPENDENCY\"]);function gs(t,e,r={},s){s??=rdt.has(t)?\"MODULE_NOT_FOUND\":t;let a={configurable:!0,writable:!0,enumerable:!1};return Object.defineProperties(new Error(e),{code:{...a,value:s},pnpCode:{...a,value:t},data:{...a,value:r}})}function lf(t){return fe.normalize(fe.fromPortablePath(t))}var dBe=ut(hBe());function mBe(t){return ndt(),aY[t]}var aY;function ndt(){aY||(aY={\"--conditions\":[],...gBe(idt()),...gBe(process.execArgv)})}function gBe(t){return(0,dBe.default)({\"--conditions\":[String],\"-C\":\"--conditions\"},{argv:t,permissive:!0})}function idt(){let t=[],e=sdt(process.env.NODE_OPTIONS||\"\",t);return t.length,e}function sdt(t,e){let r=[],s=!1,a=!0;for(let n=0;n<t.length;++n){let c=t[n];if(c===\"\\\\\"&&s){if(n+1===t.length)return e.push(`invalid value for NODE_OPTIONS (invalid escape)\n`),r;c=t[++n]}else if(c===\" \"&&!s){a=!0;continue}else if(c==='\"'){s=!s;continue}a?(r.push(c),a=!1):r[r.length-1]+=c}return s&&e.push(`invalid value for NODE_OPTIONS (unterminated string)\n`),r}Dt();var[ml,ih]=process.versions.node.split(\".\").map(t=>parseInt(t,10)),yBe=ml>19||ml===19&&ih>=2||ml===18&&ih>=13,IXt=ml===20&&ih<6||ml===19&&ih>=3,CXt=ml>19||ml===19&&ih>=6,wXt=ml>=21||ml===20&&ih>=10||ml===18&&ih>=19,BXt=ml>=21||ml===20&&ih>=10||ml===18&&ih>=20,vXt=ml>=22;function EBe(t){if(process.env.WATCH_REPORT_DEPENDENCIES&&process.send)if(t=t.map(e=>fe.fromPortablePath(uo.resolveVirtual(fe.toPortablePath(e)))),yBe)process.send({\"watch:require\":t});else for(let e of t)process.send({\"watch:require\":e})}function cY(t,e){let r=Number(process.env.PNP_ALWAYS_WARN_ON_FALLBACK)>0,s=Number(process.env.PNP_DEBUG_LEVEL),a=/^(?![a-zA-Z]:[\\\\/]|\\\\\\\\|\\.{0,2}(?:\\/|$))((?:node:)?(?:@[^/]+\\/)?[^/]+)\\/*(.*|)$/,n=/^(\\/|\\.{1,2}(\\/|$))/,c=/\\/$/,f=/^\\.{0,2}\\//,p={name:null,reference:null},h=[],E=new Set;if(t.enableTopLevelFallback===!0&&h.push(p),e.compatibilityMode!==!1)for(let Fe of[\"react-scripts\",\"gatsby\"]){let Ne=t.packageRegistry.get(Fe);if(Ne)for(let be of Ne.keys()){if(be===null)throw new Error(\"Assertion failed: This reference shouldn't be null\");h.push({name:Fe,reference:be})}}let{ignorePattern:C,packageRegistry:S,packageLocatorsByLocations:b}=t;function I(Fe,Ne){return{fn:Fe,args:Ne,error:null,result:null}}function T(Fe){let Ne=process.stderr?.hasColors?.()??process.stdout.isTTY,be=(it,Ue)=>`\\x1B[${it}m${Ue}\\x1B[0m`,Ve=Fe.error;console.error(Ve?be(\"31;1\",`\\u2716 ${Fe.error?.message.replace(/\\n.*/s,\"\")}`):be(\"33;1\",\"\\u203C Resolution\")),Fe.args.length>0&&console.error();for(let it of Fe.args)console.error(`  ${be(\"37;1\",\"In \\u2190\")} ${(0,lY.inspect)(it,{colors:Ne,compact:!0})}`);Fe.result&&(console.error(),console.error(`  ${be(\"37;1\",\"Out \\u2192\")} ${(0,lY.inspect)(Fe.result,{colors:Ne,compact:!0})}`));let ke=new Error().stack.match(/(?<=^ +)at.*/gm)?.slice(2)??[];if(ke.length>0){console.error();for(let it of ke)console.error(`  ${be(\"38;5;244\",it)}`)}console.error()}function N(Fe,Ne){if(e.allowDebug===!1)return Ne;if(Number.isFinite(s)){if(s>=2)return(...be)=>{let Ve=I(Fe,be);try{return Ve.result=Ne(...be)}catch(ke){throw Ve.error=ke}finally{T(Ve)}};if(s>=1)return(...be)=>{try{return Ne(...be)}catch(Ve){let ke=I(Fe,be);throw ke.error=Ve,T(ke),Ve}}}return Ne}function U(Fe){let Ne=g(Fe);if(!Ne)throw gs(\"INTERNAL\",\"Couldn't find a matching entry in the dependency tree for the specified parent (this is probably an internal error)\");return Ne}function W(Fe){if(Fe.name===null)return!0;for(let Ne of t.dependencyTreeRoots)if(Ne.name===Fe.name&&Ne.reference===Fe.reference)return!0;return!1}let ee=new Set([\"node\",\"require\",...mBe(\"--conditions\")]);function ie(Fe,Ne=ee,be){let Ve=Ae(J.join(Fe,\"internal.js\"),{resolveIgnored:!0,includeDiscardFromLookup:!0});if(Ve===null)throw gs(\"INTERNAL\",`The locator that owns the \"${Fe}\" path can't be found inside the dependency tree (this is probably an internal error)`);let{packageLocation:ke}=U(Ve),it=J.join(ke,Er.manifest);if(!e.fakeFs.existsSync(it))return null;let Ue=JSON.parse(e.fakeFs.readFileSync(it,\"utf8\"));if(Ue.exports==null)return null;let x=J.contains(ke,Fe);if(x===null)throw gs(\"INTERNAL\",\"unqualifiedPath doesn't contain the packageLocation (this is probably an internal error)\");x!==\".\"&&!f.test(x)&&(x=`./${x}`);try{let w=fBe({packageJSONUrl:(0,jm.pathToFileURL)(fe.fromPortablePath(it)),packageSubpath:x,exports:Ue.exports,base:be?(0,jm.pathToFileURL)(fe.fromPortablePath(be)):null,conditions:Ne});return fe.toPortablePath((0,jm.fileURLToPath)(w))}catch(w){throw gs(\"EXPORTS_RESOLUTION_FAILED\",w.message,{unqualifiedPath:lf(Fe),locator:Ve,pkgJson:Ue,subpath:lf(x),conditions:Ne},w.code)}}function ue(Fe,Ne,{extensions:be}){let Ve;try{Ne.push(Fe),Ve=e.fakeFs.statSync(Fe)}catch{}if(Ve&&!Ve.isDirectory())return e.fakeFs.realpathSync(Fe);if(Ve&&Ve.isDirectory()){let ke;try{ke=JSON.parse(e.fakeFs.readFileSync(J.join(Fe,Er.manifest),\"utf8\"))}catch{}let it;if(ke&&ke.main&&(it=J.resolve(Fe,ke.main)),it&&it!==Fe){let Ue=ue(it,Ne,{extensions:be});if(Ue!==null)return Ue}}for(let ke=0,it=be.length;ke<it;ke++){let Ue=`${Fe}${be[ke]}`;if(Ne.push(Ue),e.fakeFs.existsSync(Ue))return Ue}if(Ve&&Ve.isDirectory())for(let ke=0,it=be.length;ke<it;ke++){let Ue=J.format({dir:Fe,name:\"index\",ext:be[ke]});if(Ne.push(Ue),e.fakeFs.existsSync(Ue))return Ue}return null}function le(Fe){let Ne=new sh.Module(Fe,null);return Ne.filename=Fe,Ne.paths=sh.Module._nodeModulePaths(Fe),Ne}function me(Fe,Ne){return Ne.endsWith(\"/\")&&(Ne=J.join(Ne,\"internal.js\")),sh.Module._resolveFilename(fe.fromPortablePath(Fe),le(fe.fromPortablePath(Ne)),!1,{plugnplay:!1})}function pe(Fe){if(C===null)return!1;let Ne=J.contains(t.basePath,Fe);return Ne===null?!1:!!C.test(Ne.replace(/\\/$/,\"\"))}let Be={std:3,resolveVirtual:1,getAllLocators:1},Ce=p;function g({name:Fe,reference:Ne}){let be=S.get(Fe);if(!be)return null;let Ve=be.get(Ne);return Ve||null}function we({name:Fe,reference:Ne}){let be=[];for(let[Ve,ke]of S)if(Ve!==null)for(let[it,Ue]of ke)it===null||Ue.packageDependencies.get(Fe)!==Ne||Ve===Fe&&it===Ne||be.push({name:Ve,reference:it});return be}function ye(Fe,Ne){let be=new Map,Ve=new Set,ke=Ue=>{let x=JSON.stringify(Ue.name);if(Ve.has(x))return;Ve.add(x);let w=we(Ue);for(let P of w)if(U(P).packagePeers.has(Fe))ke(P);else{let F=be.get(P.name);typeof F>\"u\"&&be.set(P.name,F=new Set),F.add(P.reference)}};ke(Ne);let it=[];for(let Ue of[...be.keys()].sort())for(let x of[...be.get(Ue)].sort())it.push({name:Ue,reference:x});return it}function Ae(Fe,{resolveIgnored:Ne=!1,includeDiscardFromLookup:be=!1}={}){if(pe(Fe)&&!Ne)return null;let Ve=J.relative(t.basePath,Fe);Ve.match(n)||(Ve=`./${Ve}`),Ve.endsWith(\"/\")||(Ve=`${Ve}/`);do{let ke=b.get(Ve);if(typeof ke>\"u\"||ke.discardFromLookup&&!be){Ve=Ve.substring(0,Ve.lastIndexOf(\"/\",Ve.length-2)+1);continue}return ke.locator}while(Ve!==\"\");return null}function se(Fe){try{return e.fakeFs.readFileSync(fe.toPortablePath(Fe),\"utf8\")}catch(Ne){if(Ne.code===\"ENOENT\")return;throw Ne}}function X(Fe,Ne,{considerBuiltins:be=!0}={}){if(Fe.startsWith(\"#\"))throw new Error(\"resolveToUnqualified can not handle private import mappings\");if(Fe===\"pnpapi\")return fe.toPortablePath(e.pnpapiResolution);if(be&&(0,sh.isBuiltin)(Fe))return null;let Ve=lf(Fe),ke=Ne&&lf(Ne);if(Ne&&pe(Ne)&&(!J.isAbsolute(Fe)||Ae(Fe)===null)){let x=me(Fe,Ne);if(x===!1)throw gs(\"BUILTIN_NODE_RESOLUTION_FAILED\",`The builtin node resolution algorithm was unable to resolve the requested module (it didn't go through the pnp resolver because the issuer was explicitely ignored by the regexp)\n\nRequire request: \"${Ve}\"\nRequired by: ${ke}\n`,{request:Ve,issuer:ke});return fe.toPortablePath(x)}let it,Ue=Fe.match(a);if(Ue){if(!Ne)throw gs(\"API_ERROR\",\"The resolveToUnqualified function must be called with a valid issuer when the path isn't a builtin nor absolute\",{request:Ve,issuer:ke});let[,x,w]=Ue,P=Ae(Ne);if(!P){let Re=me(Fe,Ne);if(Re===!1)throw gs(\"BUILTIN_NODE_RESOLUTION_FAILED\",`The builtin node resolution algorithm was unable to resolve the requested module (it didn't go through the pnp resolver because the issuer doesn't seem to be part of the Yarn-managed dependency tree).\n\nRequire path: \"${Ve}\"\nRequired by: ${ke}\n`,{request:Ve,issuer:ke});return fe.toPortablePath(Re)}let F=U(P).packageDependencies.get(x),z=null;if(F==null&&P.name!==null){let Re=t.fallbackExclusionList.get(P.name);if(!Re||!Re.has(P.reference)){for(let Ct=0,qt=h.length;Ct<qt;++Ct){let bt=U(h[Ct]).packageDependencies.get(x);if(bt!=null){r?z=bt:F=bt;break}}if(t.enableTopLevelFallback&&F==null&&z===null){let Ct=t.fallbackPool.get(x);Ct!=null&&(z=Ct)}}}let Z=null;if(F===null)if(W(P))Z=gs(\"MISSING_PEER_DEPENDENCY\",`Your application tried to access ${x} (a peer dependency); this isn't allowed as there is no ancestor to satisfy the requirement. Use a devDependency if needed.\n\nRequired package: ${x}${x!==Ve?` (via \"${Ve}\")`:\"\"}\nRequired by: ${ke}\n`,{request:Ve,issuer:ke,dependencyName:x});else{let Re=ye(x,P);Re.every(lt=>W(lt))?Z=gs(\"MISSING_PEER_DEPENDENCY\",`${P.name} tried to access ${x} (a peer dependency) but it isn't provided by your application; this makes the require call ambiguous and unsound.\n\nRequired package: ${x}${x!==Ve?` (via \"${Ve}\")`:\"\"}\nRequired by: ${P.name}@${P.reference} (via ${ke})\n${Re.map(lt=>`Ancestor breaking the chain: ${lt.name}@${lt.reference}\n`).join(\"\")}\n`,{request:Ve,issuer:ke,issuerLocator:Object.assign({},P),dependencyName:x,brokenAncestors:Re}):Z=gs(\"MISSING_PEER_DEPENDENCY\",`${P.name} tried to access ${x} (a peer dependency) but it isn't provided by its ancestors; this makes the require call ambiguous and unsound.\n\nRequired package: ${x}${x!==Ve?` (via \"${Ve}\")`:\"\"}\nRequired by: ${P.name}@${P.reference} (via ${ke})\n\n${Re.map(lt=>`Ancestor breaking the chain: ${lt.name}@${lt.reference}\n`).join(\"\")}\n`,{request:Ve,issuer:ke,issuerLocator:Object.assign({},P),dependencyName:x,brokenAncestors:Re})}else F===void 0&&(!be&&(0,sh.isBuiltin)(Fe)?W(P)?Z=gs(\"UNDECLARED_DEPENDENCY\",`Your application tried to access ${x}. While this module is usually interpreted as a Node builtin, your resolver is running inside a non-Node resolution context where such builtins are ignored. Since ${x} isn't otherwise declared in your dependencies, this makes the require call ambiguous and unsound.\n\nRequired package: ${x}${x!==Ve?` (via \"${Ve}\")`:\"\"}\nRequired by: ${ke}\n`,{request:Ve,issuer:ke,dependencyName:x}):Z=gs(\"UNDECLARED_DEPENDENCY\",`${P.name} tried to access ${x}. While this module is usually interpreted as a Node builtin, your resolver is running inside a non-Node resolution context where such builtins are ignored. Since ${x} isn't otherwise declared in ${P.name}'s dependencies, this makes the require call ambiguous and unsound.\n\nRequired package: ${x}${x!==Ve?` (via \"${Ve}\")`:\"\"}\nRequired by: ${ke}\n`,{request:Ve,issuer:ke,issuerLocator:Object.assign({},P),dependencyName:x}):W(P)?Z=gs(\"UNDECLARED_DEPENDENCY\",`Your application tried to access ${x}, but it isn't declared in your dependencies; this makes the require call ambiguous and unsound.\n\nRequired package: ${x}${x!==Ve?` (via \"${Ve}\")`:\"\"}\nRequired by: ${ke}\n`,{request:Ve,issuer:ke,dependencyName:x}):Z=gs(\"UNDECLARED_DEPENDENCY\",`${P.name} tried to access ${x}, but it isn't declared in its dependencies; this makes the require call ambiguous and unsound.\n\nRequired package: ${x}${x!==Ve?` (via \"${Ve}\")`:\"\"}\nRequired by: ${P.name}@${P.reference} (via ${ke})\n`,{request:Ve,issuer:ke,issuerLocator:Object.assign({},P),dependencyName:x}));if(F==null){if(z===null||Z===null)throw Z||new Error(\"Assertion failed: Expected an error to have been set\");F=z;let Re=Z.message.replace(/\\n.*/g,\"\");Z.message=Re,!E.has(Re)&&s!==0&&(E.add(Re),process.emitWarning(Z))}let $=Array.isArray(F)?{name:F[0],reference:F[1]}:{name:x,reference:F},oe=U($);if(!oe.packageLocation)throw gs(\"MISSING_DEPENDENCY\",`A dependency seems valid but didn't get installed for some reason. This might be caused by a partial install, such as dev vs prod.\n\nRequired package: ${$.name}@${$.reference}${$.name!==Ve?` (via \"${Ve}\")`:\"\"}\nRequired by: ${P.name}@${P.reference} (via ${ke})\n`,{request:Ve,issuer:ke,dependencyLocator:Object.assign({},$)});let xe=oe.packageLocation;w?it=J.join(xe,w):it=xe}else if(J.isAbsolute(Fe))it=J.normalize(Fe);else{if(!Ne)throw gs(\"API_ERROR\",\"The resolveToUnqualified function must be called with a valid issuer when the path isn't a builtin nor absolute\",{request:Ve,issuer:ke});let x=J.resolve(Ne);Ne.match(c)?it=J.normalize(J.join(x,Fe)):it=J.normalize(J.join(J.dirname(x),Fe))}return J.normalize(it)}function De(Fe,Ne,be=ee,Ve){if(n.test(Fe))return Ne;let ke=ie(Ne,be,Ve);return ke?J.normalize(ke):Ne}function Te(Fe,{extensions:Ne=Object.keys(sh.Module._extensions)}={}){let be=[],Ve=ue(Fe,be,{extensions:Ne});if(Ve)return J.normalize(Ve);{EBe(be.map(Ue=>fe.fromPortablePath(Ue)));let ke=lf(Fe),it=Ae(Fe);if(it){let{packageLocation:Ue}=U(it),x=!0;try{e.fakeFs.accessSync(Ue)}catch(w){if(w?.code===\"ENOENT\")x=!1;else{let P=(w?.message??w??\"empty exception thrown\").replace(/^[A-Z]/,y=>y.toLowerCase());throw gs(\"QUALIFIED_PATH_RESOLUTION_FAILED\",`Required package exists but could not be accessed (${P}).\n\nMissing package: ${it.name}@${it.reference}\nExpected package location: ${lf(Ue)}\n`,{unqualifiedPath:ke,extensions:Ne})}}if(!x){let w=Ue.includes(\"/unplugged/\")?\"Required unplugged package missing from disk. This may happen when switching branches without running installs (unplugged packages must be fully materialized on disk to work).\":\"Required package missing from disk. If you keep your packages inside your repository then restarting the Node process may be enough. Otherwise, try to run an install first.\";throw gs(\"QUALIFIED_PATH_RESOLUTION_FAILED\",`${w}\n\nMissing package: ${it.name}@${it.reference}\nExpected package location: ${lf(Ue)}\n`,{unqualifiedPath:ke,extensions:Ne})}}throw gs(\"QUALIFIED_PATH_RESOLUTION_FAILED\",`Qualified path resolution failed: we looked for the following paths, but none could be accessed.\n\nSource path: ${ke}\n${be.map(Ue=>`Not found: ${lf(Ue)}\n`).join(\"\")}`,{unqualifiedPath:ke,extensions:Ne})}}function mt(Fe,Ne,be){if(!Ne)throw new Error(\"Assertion failed: An issuer is required to resolve private import mappings\");let Ve=ABe({name:Fe,base:(0,jm.pathToFileURL)(fe.fromPortablePath(Ne)),conditions:be.conditions??ee,readFileSyncFn:se});if(Ve instanceof URL)return Te(fe.toPortablePath((0,jm.fileURLToPath)(Ve)),{extensions:be.extensions});if(Ve.startsWith(\"#\"))throw new Error(\"Mapping from one private import to another isn't allowed\");return j(Ve,Ne,be)}function j(Fe,Ne,be={}){try{if(Fe.startsWith(\"#\"))return mt(Fe,Ne,be);let{considerBuiltins:Ve,extensions:ke,conditions:it}=be,Ue=X(Fe,Ne,{considerBuiltins:Ve});if(Fe===\"pnpapi\")return Ue;if(Ue===null)return null;let x=()=>Ne!==null?pe(Ne):!1,w=(!Ve||!(0,sh.isBuiltin)(Fe))&&!x()?De(Fe,Ue,it,Ne):Ue;return Te(w,{extensions:ke})}catch(Ve){throw Object.hasOwn(Ve,\"pnpCode\")&&Object.assign(Ve.data,{request:lf(Fe),issuer:Ne&&lf(Ne)}),Ve}}function rt(Fe){let Ne=J.normalize(Fe),be=uo.resolveVirtual(Ne);return be!==Ne?be:null}return{VERSIONS:Be,topLevel:Ce,getLocator:(Fe,Ne)=>Array.isArray(Ne)?{name:Ne[0],reference:Ne[1]}:{name:Fe,reference:Ne},getDependencyTreeRoots:()=>[...t.dependencyTreeRoots],getAllLocators(){let Fe=[];for(let[Ne,be]of S)for(let Ve of be.keys())Ne!==null&&Ve!==null&&Fe.push({name:Ne,reference:Ve});return Fe},getPackageInformation:Fe=>{let Ne=g(Fe);if(Ne===null)return null;let be=fe.fromPortablePath(Ne.packageLocation);return{...Ne,packageLocation:be}},findPackageLocator:Fe=>Ae(fe.toPortablePath(Fe)),resolveToUnqualified:N(\"resolveToUnqualified\",(Fe,Ne,be)=>{let Ve=Ne!==null?fe.toPortablePath(Ne):null,ke=X(fe.toPortablePath(Fe),Ve,be);return ke===null?null:fe.fromPortablePath(ke)}),resolveUnqualified:N(\"resolveUnqualified\",(Fe,Ne)=>fe.fromPortablePath(Te(fe.toPortablePath(Fe),Ne))),resolveRequest:N(\"resolveRequest\",(Fe,Ne,be)=>{let Ve=Ne!==null?fe.toPortablePath(Ne):null,ke=j(fe.toPortablePath(Fe),Ve,be);return ke===null?null:fe.fromPortablePath(ke)}),resolveVirtual:N(\"resolveVirtual\",Fe=>{let Ne=rt(fe.toPortablePath(Fe));return Ne!==null?fe.fromPortablePath(Ne):null})}}Dt();var IBe=(t,e,r)=>{let s=RD(t),a=XW(s,{basePath:e}),n=fe.join(e,Er.pnpCjs);return cY(a,{fakeFs:r,pnpapiResolution:n})};var fY=ut(wBe());Yt();var gA={};Vt(gA,{checkManifestCompatibility:()=>BBe,extractBuildRequest:()=>sN,getExtractHint:()=>AY,hasBindingGyp:()=>pY});Ge();Dt();function BBe(t){return G.isPackageCompatible(t,fs.getArchitectureSet())}function sN(t,e,r,{configuration:s}){let a=[];for(let n of[\"preinstall\",\"install\",\"postinstall\"])e.manifest.scripts.has(n)&&a.push({type:0,script:n});return!e.manifest.scripts.has(\"install\")&&e.misc.hasBindingGyp&&a.push({type:1,script:\"node-gyp rebuild\"}),a.length===0?null:t.linkType!==\"HARD\"?{skipped:!0,explain:n=>n.reportWarningOnce(6,`${G.prettyLocator(s,t)} lists build scripts, but is referenced through a soft link. Soft links don't support build scripts, so they'll be ignored.`)}:r&&r.built===!1?{skipped:!0,explain:n=>n.reportInfoOnce(5,`${G.prettyLocator(s,t)} lists build scripts, but its build has been explicitly disabled through configuration.`)}:!s.get(\"enableScripts\")&&!r.built?{skipped:!0,explain:n=>n.reportWarningOnce(4,`${G.prettyLocator(s,t)} lists build scripts, but all build scripts have been disabled.`)}:BBe(t)?{skipped:!1,directives:a}:{skipped:!0,explain:n=>n.reportWarningOnce(76,`${G.prettyLocator(s,t)} The ${fs.getArchitectureName()} architecture is incompatible with this package, build skipped.`)}}var adt=new Set([\".exe\",\".bin\",\".h\",\".hh\",\".hpp\",\".c\",\".cc\",\".cpp\",\".java\",\".jar\",\".node\"]);function AY(t){return t.packageFs.getExtractHint({relevantExtensions:adt})}function pY(t){let e=J.join(t.prefixPath,\"binding.gyp\");return t.packageFs.existsSync(e)}var HD={};Vt(HD,{getUnpluggedPath:()=>_D});Ge();Dt();function _D(t,{configuration:e}){return J.resolve(e.get(\"pnpUnpluggedFolder\"),G.slugifyLocator(t))}var ldt=new Set([G.makeIdent(null,\"open\").identHash,G.makeIdent(null,\"opn\").identHash]),sg=class{constructor(){this.mode=\"strict\";this.pnpCache=new Map}getCustomDataKey(){return JSON.stringify({name:\"PnpLinker\",version:2})}supportsPackage(e,r){return this.isEnabled(r)}async findPackageLocation(e,r){if(!this.isEnabled(r))throw new Error(\"Assertion failed: Expected the PnP linker to be enabled\");let s=og(r.project).cjs;if(!ce.existsSync(s))throw new nt(`The project in ${he.pretty(r.project.configuration,`${r.project.cwd}/package.json`,he.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let a=je.getFactoryWithDefault(this.pnpCache,s,()=>je.dynamicRequire(s,{cachingStrategy:je.CachingStrategy.FsTime})),n={name:G.stringifyIdent(e),reference:e.reference},c=a.getPackageInformation(n);if(!c)throw new nt(`Couldn't find ${G.prettyLocator(r.project.configuration,e)} in the currently installed PnP map - running an install might help`);return fe.toPortablePath(c.packageLocation)}async findPackageLocator(e,r){if(!this.isEnabled(r))return null;let s=og(r.project).cjs;if(!ce.existsSync(s))return null;let n=je.getFactoryWithDefault(this.pnpCache,s,()=>je.dynamicRequire(s,{cachingStrategy:je.CachingStrategy.FsTime})).findPackageLocator(fe.fromPortablePath(e));return n?G.makeLocator(G.parseIdent(n.name),n.reference):null}makeInstaller(e){return new Gm(e)}isEnabled(e){return!(e.project.configuration.get(\"nodeLinker\")!==\"pnp\"||e.project.configuration.get(\"pnpMode\")!==this.mode)}},Gm=class{constructor(e){this.opts=e;this.mode=\"strict\";this.asyncActions=new je.AsyncActions(10);this.packageRegistry=new Map;this.virtualTemplates=new Map;this.isESMLoaderRequired=!1;this.customData={store:new Map};this.unpluggedPaths=new Set;this.opts=e}attachCustomData(e){this.customData=e}async installPackage(e,r,s){let a=G.stringifyIdent(e),n=e.reference,c=!!this.opts.project.tryWorkspaceByLocator(e),f=G.isVirtualLocator(e),p=e.peerDependencies.size>0&&!f,h=!p&&!c,E=!p&&e.linkType!==\"SOFT\",C,S;if(h||E){let ee=f?G.devirtualizeLocator(e):e;C=this.customData.store.get(ee.locatorHash),typeof C>\"u\"&&(C=await cdt(r),e.linkType===\"HARD\"&&this.customData.store.set(ee.locatorHash,C)),C.manifest.type===\"module\"&&(this.isESMLoaderRequired=!0),S=this.opts.project.getDependencyMeta(ee,e.version)}let b=h?sN(e,C,S,{configuration:this.opts.project.configuration}):null,I=E?await this.unplugPackageIfNeeded(e,C,r,S,s):r.packageFs;if(J.isAbsolute(r.prefixPath))throw new Error(`Assertion failed: Expected the prefix path (${r.prefixPath}) to be relative to the parent`);let T=J.resolve(I.getRealPath(),r.prefixPath),N=hY(this.opts.project.cwd,T),U=new Map,W=new Set;if(f){for(let ee of e.peerDependencies.values())U.set(G.stringifyIdent(ee),null),W.add(G.stringifyIdent(ee));if(!c){let ee=G.devirtualizeLocator(e);this.virtualTemplates.set(ee.locatorHash,{location:hY(this.opts.project.cwd,uo.resolveVirtual(T)),locator:ee})}}return je.getMapWithDefault(this.packageRegistry,a).set(n,{packageLocation:N,packageDependencies:U,packagePeers:W,linkType:e.linkType,discardFromLookup:r.discardFromLookup||!1}),{packageLocation:T,buildRequest:b}}async attachInternalDependencies(e,r){let s=this.getPackageInformation(e);for(let[a,n]of r){let c=G.areIdentsEqual(a,n)?n.reference:[G.stringifyIdent(n),n.reference];s.packageDependencies.set(G.stringifyIdent(a),c)}}async attachExternalDependents(e,r){for(let s of r)this.getDiskInformation(s).packageDependencies.set(G.stringifyIdent(e),e.reference)}async finalizeInstall(){if(this.opts.project.configuration.get(\"pnpMode\")!==this.mode)return;let e=og(this.opts.project);if(this.isEsmEnabled()||await ce.removePromise(e.esmLoader),this.opts.project.configuration.get(\"nodeLinker\")!==\"pnp\"){await ce.removePromise(e.cjs),await ce.removePromise(e.data),await ce.removePromise(e.esmLoader),await ce.removePromise(this.opts.project.configuration.get(\"pnpUnpluggedFolder\"));return}for(let{locator:C,location:S}of this.virtualTemplates.values())je.getMapWithDefault(this.packageRegistry,G.stringifyIdent(C)).set(C.reference,{packageLocation:S,packageDependencies:new Map,packagePeers:new Set,linkType:\"SOFT\",discardFromLookup:!1});let r=this.opts.project.configuration.get(\"pnpFallbackMode\"),s=this.opts.project.workspaces.map(({anchoredLocator:C})=>({name:G.stringifyIdent(C),reference:C.reference})),a=r!==\"none\",n=[],c=new Map,f=je.buildIgnorePattern([\".yarn/sdks/**\",...this.opts.project.configuration.get(\"pnpIgnorePatterns\")]),p=this.packageRegistry,h=this.opts.project.configuration.get(\"pnpShebang\"),E=this.opts.project.configuration.get(\"pnpZipBackend\");if(r===\"dependencies-only\")for(let C of this.opts.project.storedPackages.values())this.opts.project.tryWorkspaceByLocator(C)&&n.push({name:G.stringifyIdent(C),reference:C.reference});return await this.asyncActions.wait(),await this.finalizeInstallWithPnp({dependencyTreeRoots:s,enableTopLevelFallback:a,fallbackExclusionList:n,fallbackPool:c,ignorePattern:f,pnpZipBackend:E,packageRegistry:p,shebang:h}),{customData:this.customData}}async transformPnpSettings(e){}isEsmEnabled(){if(this.opts.project.configuration.sources.has(\"pnpEnableEsmLoader\"))return this.opts.project.configuration.get(\"pnpEnableEsmLoader\");if(this.isESMLoaderRequired)return!0;for(let e of this.opts.project.workspaces)if(e.manifest.type===\"module\")return!0;return!1}async finalizeInstallWithPnp(e){let r=og(this.opts.project),s=await this.locateNodeModules(e.ignorePattern);if(s.length>0){this.opts.report.reportWarning(31,\"One or more node_modules have been detected and will be removed. This operation may take some time.\");for(let n of s)await ce.removePromise(n)}if(await this.transformPnpSettings(e),this.opts.project.configuration.get(\"pnpEnableInlining\")){let n=z2e(e);await ce.changeFilePromise(r.cjs,n,{automaticNewlines:!0,mode:493}),await ce.removePromise(r.data)}else{let{dataFile:n,loaderFile:c}=Z2e(e);await ce.changeFilePromise(r.cjs,c,{automaticNewlines:!0,mode:493}),await ce.changeFilePromise(r.data,n,{automaticNewlines:!0,mode:420})}this.isEsmEnabled()&&(this.opts.report.reportWarning(0,\"ESM support for PnP uses the experimental loader API and is therefore experimental\"),await ce.changeFilePromise(r.esmLoader,(0,fY.default)(),{automaticNewlines:!0,mode:420}));let a=this.opts.project.configuration.get(\"pnpUnpluggedFolder\");if(this.unpluggedPaths.size===0)await ce.removePromise(a);else for(let n of await ce.readdirPromise(a)){let c=J.resolve(a,n);this.unpluggedPaths.has(c)||await ce.removePromise(c)}}async locateNodeModules(e){let r=[],s=e?new RegExp(e):null;for(let a of this.opts.project.workspaces){let n=J.join(a.cwd,\"node_modules\");if(s&&s.test(J.relative(this.opts.project.cwd,a.cwd))||!ce.existsSync(n))continue;let c=await ce.readdirPromise(n,{withFileTypes:!0}),f=c.filter(p=>!p.isDirectory()||p.name===\".bin\"||!p.name.startsWith(\".\"));if(f.length===c.length)r.push(n);else for(let p of f)r.push(J.join(n,p.name))}return r}async unplugPackageIfNeeded(e,r,s,a,n){return this.shouldBeUnplugged(e,r,a)?this.unplugPackage(e,s,n):s.packageFs}shouldBeUnplugged(e,r,s){return typeof s.unplugged<\"u\"?s.unplugged:ldt.has(e.identHash)||e.conditions!=null?!0:r.manifest.preferUnplugged!==null?r.manifest.preferUnplugged:!!(sN(e,r,s,{configuration:this.opts.project.configuration})?.skipped===!1||r.misc.extractHint)}async unplugPackage(e,r,s){let a=_D(e,{configuration:this.opts.project.configuration});return this.opts.project.disabledLocators.has(e.locatorHash)?new _f(a,{baseFs:r.packageFs,pathUtils:J}):(this.unpluggedPaths.add(a),s.holdFetchResult(this.asyncActions.set(e.locatorHash,async()=>{let n=J.join(a,r.prefixPath,\".ready\");await ce.existsPromise(n)||(this.opts.project.storedBuildState.delete(e.locatorHash),await ce.mkdirPromise(a,{recursive:!0}),await ce.copyPromise(a,vt.dot,{baseFs:r.packageFs,overwrite:!1}),await ce.writeFilePromise(n,\"\"))})),new Sn(a))}getPackageInformation(e){let r=G.stringifyIdent(e),s=e.reference,a=this.packageRegistry.get(r);if(!a)throw new Error(`Assertion failed: The package information store should have been available (for ${G.prettyIdent(this.opts.project.configuration,e)})`);let n=a.get(s);if(!n)throw new Error(`Assertion failed: The package information should have been available (for ${G.prettyLocator(this.opts.project.configuration,e)})`);return n}getDiskInformation(e){let r=je.getMapWithDefault(this.packageRegistry,\"@@disk\"),s=hY(this.opts.project.cwd,e);return je.getFactoryWithDefault(r,s,()=>({packageLocation:s,packageDependencies:new Map,packagePeers:new Set,linkType:\"SOFT\",discardFromLookup:!1}))}};function hY(t,e){let r=J.relative(t,e);return r.match(/^\\.{0,2}\\//)||(r=`./${r}`),r.replace(/\\/?$/,\"/\")}async function cdt(t){let e=await Ut.tryFind(t.prefixPath,{baseFs:t.packageFs})??new Ut,r=new Set([\"preinstall\",\"install\",\"postinstall\"]);for(let s of e.scripts.keys())r.has(s)||e.scripts.delete(s);return{manifest:{scripts:e.scripts,preferUnplugged:e.preferUnplugged,type:e.type},misc:{extractHint:AY(t),hasBindingGyp:pY(t)}}}Ge();Ge();Yt();var vBe=ut(Go());var Sw=class extends ft{constructor(){super(...arguments);this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Unplug direct dependencies from the entire project\"});this.recursive=ge.Boolean(\"-R,--recursive\",!1,{description:\"Unplug both direct and transitive dependencies\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.patterns=ge.Rest()}static{this.paths=[[\"unplug\"]]}static{this.usage=ot.Usage({description:\"force the unpacking of a list of packages\",details:\"\\n      This command will add the selectors matching the specified patterns to the list of packages that must be unplugged when installed.\\n\\n      A package being unplugged means that instead of being referenced directly through its archive, it will be unpacked at install time in the directory configured via `pnpUnpluggedFolder`. Note that unpacking packages this way is generally not recommended because it'll make it harder to store your packages within the repository. However, it's a good approach to quickly and safely debug some packages, and can even sometimes be required depending on the context (for example when the package contains shellscripts).\\n\\n      Running the command will set a persistent flag inside your top-level `package.json`, in the `dependenciesMeta` field. As such, to undo its effects, you'll need to revert the changes made to the manifest and run `yarn install` to apply the modification.\\n\\n      By default, only direct dependencies from the current workspace are affected. If `-A,--all` is set, direct dependencies from the entire project are affected. Using the `-R,--recursive` flag will affect transitive dependencies as well as direct ones.\\n\\n      This command accepts glob patterns inside the scope and name components (not the range). Make sure to escape the patterns to prevent your own shell from trying to expand them.\\n    \",examples:[[\"Unplug the lodash dependency from the active workspace\",\"yarn unplug lodash\"],[\"Unplug all instances of lodash referenced by any workspace\",\"yarn unplug lodash -A\"],[\"Unplug all instances of lodash referenced by the active workspace and its dependencies\",\"yarn unplug lodash -R\"],[\"Unplug all instances of lodash, anywhere\",\"yarn unplug lodash -AR\"],[\"Unplug one specific version of lodash\",\"yarn unplug lodash@1.2.3\"],[\"Unplug all packages with the `@babel` scope\",\"yarn unplug '@babel/*'\"],[\"Unplug all packages (only for testing, not recommended)\",\"yarn unplug -R '*'\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);if(r.get(\"nodeLinker\")!==\"pnp\")throw new nt(\"This command can only be used if the `nodeLinker` option is set to `pnp`\");await s.restoreInstallState();let c=new Set(this.patterns),f=this.patterns.map(b=>{let I=G.parseDescriptor(b),T=I.range!==\"unknown\"?I:G.makeDescriptor(I,\"*\");if(!Fr.validRange(T.range))throw new nt(`The range of the descriptor patterns must be a valid semver range (${G.prettyDescriptor(r,T)})`);return N=>{let U=G.stringifyIdent(N);return!vBe.default.isMatch(U,G.stringifyIdent(T))||N.version&&!Fr.satisfiesWithPrereleases(N.version,T.range)?!1:(c.delete(b),!0)}}),p=()=>{let b=[];for(let I of s.storedPackages.values())!s.tryWorkspaceByLocator(I)&&!G.isVirtualLocator(I)&&f.some(T=>T(I))&&b.push(I);return b},h=b=>{let I=new Set,T=[],N=(U,W)=>{if(I.has(U.locatorHash))return;let ee=!!s.tryWorkspaceByLocator(U);if(!(W>0&&!this.recursive&&ee)&&(I.add(U.locatorHash),!s.tryWorkspaceByLocator(U)&&f.some(ie=>ie(U))&&T.push(U),!(W>0&&!this.recursive)))for(let ie of U.dependencies.values()){let ue=s.storedResolutions.get(ie.descriptorHash);if(!ue)throw new Error(\"Assertion failed: The resolution should have been registered\");let le=s.storedPackages.get(ue);if(!le)throw new Error(\"Assertion failed: The package should have been registered\");N(le,W+1)}};for(let U of b)N(U.anchoredPackage,0);return T},E,C;if(this.all&&this.recursive?(E=p(),C=\"the project\"):this.all?(E=h(s.workspaces),C=\"any workspace\"):(E=h([a]),C=\"this workspace\"),c.size>1)throw new nt(`Patterns ${he.prettyList(r,c,he.Type.CODE)} don't match any packages referenced by ${C}`);if(c.size>0)throw new nt(`Pattern ${he.prettyList(r,c,he.Type.CODE)} doesn't match any packages referenced by ${C}`);E=je.sortMap(E,b=>G.stringifyLocator(b));let S=await Ot.start({configuration:r,stdout:this.context.stdout,json:this.json},async b=>{for(let I of E){let T=I.version??\"unknown\",N=s.topLevelWorkspace.manifest.ensureDependencyMeta(G.makeDescriptor(I,T));N.unplugged=!0,b.reportInfo(0,`Will unpack ${G.prettyLocator(r,I)} to ${he.pretty(r,_D(I,{configuration:r}),he.Type.PATH)}`),b.reportJson({locator:G.stringifyLocator(I),version:T})}await s.topLevelWorkspace.persistManifest(),this.json||b.reportSeparator()});return S.hasErrors()?S.exitCode():await s.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:n})}};var og=t=>({cjs:J.join(t.cwd,Er.pnpCjs),data:J.join(t.cwd,Er.pnpData),esmLoader:J.join(t.cwd,Er.pnpEsmLoader)}),DBe=t=>/\\s/.test(t)?JSON.stringify(t):t;async function udt(t,e,r){let s=/\\s*--require\\s+\\S*\\.pnp\\.c?js\\s*/g,a=/\\s*--experimental-loader\\s+\\S*\\.pnp\\.loader\\.mjs\\s*/,n=(e.NODE_OPTIONS??\"\").replace(s,\" \").replace(a,\" \").trim();if(t.configuration.get(\"nodeLinker\")!==\"pnp\"){e.NODE_OPTIONS=n||void 0;return}let c=og(t),f=`--require ${DBe(fe.fromPortablePath(c.cjs))}`;ce.existsSync(c.esmLoader)&&(f=`${f} --experimental-loader ${(0,SBe.pathToFileURL)(fe.fromPortablePath(c.esmLoader)).href}`),ce.existsSync(c.cjs)&&(e.NODE_OPTIONS=n?`${f} ${n}`:f)}async function fdt(t,e){let r=og(t);e(r.cjs),e(r.data),e(r.esmLoader),e(t.configuration.get(\"pnpUnpluggedFolder\"))}var Adt={hooks:{populateYarnPaths:fdt,setupScriptEnvironment:udt},configuration:{nodeLinker:{description:'The linker used for installing Node packages, one of: \"pnp\", \"pnpm\", or \"node-modules\"',type:\"STRING\",default:\"pnp\"},minizip:{description:\"Whether Yarn should use minizip to extract archives\",type:\"BOOLEAN\",default:!1},winLinkType:{description:\"Whether Yarn should use Windows Junctions or symlinks when creating links on Windows.\",type:\"STRING\",values:[\"junctions\",\"symlinks\"],default:\"junctions\"},pnpMode:{description:\"If 'strict', generates standard PnP maps. If 'loose', merges them with the n_m resolution.\",type:\"STRING\",default:\"strict\"},pnpShebang:{description:\"String to prepend to the generated PnP script\",type:\"STRING\",default:\"#!/usr/bin/env node\"},pnpIgnorePatterns:{description:\"Array of glob patterns; files matching them will use the classic resolution\",type:\"STRING\",default:[],isArray:!0},pnpZipBackend:{description:\"Whether to use the experimental js implementation for the ZipFS\",type:\"STRING\",values:[\"libzip\",\"js\"],default:\"libzip\"},pnpEnableEsmLoader:{description:\"If true, Yarn will generate an ESM loader (`.pnp.loader.mjs`). If this is not explicitly set Yarn tries to automatically detect whether ESM support is required.\",type:\"BOOLEAN\",default:!1},pnpEnableInlining:{description:\"If true, the PnP data will be inlined along with the generated loader\",type:\"BOOLEAN\",default:!0},pnpFallbackMode:{description:\"If true, the generated PnP loader will follow the top-level fallback rule\",type:\"STRING\",default:\"dependencies-only\"},pnpUnpluggedFolder:{description:\"Folder where the unplugged packages must be stored\",type:\"ABSOLUTE_PATH\",default:\"./.yarn/unplugged\"}},linkers:[sg],commands:[Sw]},pdt=Adt;var FBe=ut(QBe());Yt();var wY=ut(Ie(\"crypto\")),NBe=ut(Ie(\"fs\")),OBe=1,Ri=\"node_modules\",oN=\".bin\",LBe=\".yarn-state.yml\",kdt=1e3,BY=(s=>(s.CLASSIC=\"classic\",s.HARDLINKS_LOCAL=\"hardlinks-local\",s.HARDLINKS_GLOBAL=\"hardlinks-global\",s))(BY||{}),jD=class{constructor(){this.installStateCache=new Map}getCustomDataKey(){return JSON.stringify({name:\"NodeModulesLinker\",version:3})}supportsPackage(e,r){return this.isEnabled(r)}async findPackageLocation(e,r){if(!this.isEnabled(r))throw new Error(\"Assertion failed: Expected the node-modules linker to be enabled\");let s=r.project.tryWorkspaceByLocator(e);if(s)return s.cwd;let a=await je.getFactoryWithDefault(this.installStateCache,r.project.cwd,async()=>await CY(r.project,{unrollAliases:!0}));if(a===null)throw new nt(\"Couldn't find the node_modules state file - running an install might help (findPackageLocation)\");let n=a.locatorMap.get(G.stringifyLocator(e));if(!n){let p=new nt(`Couldn't find ${G.prettyLocator(r.project.configuration,e)} in the currently installed node_modules map - running an install might help`);throw p.code=\"LOCATOR_NOT_INSTALLED\",p}let c=n.locations.sort((p,h)=>p.split(J.sep).length-h.split(J.sep).length),f=J.join(r.project.configuration.startingCwd,Ri);return c.find(p=>J.contains(f,p))||n.locations[0]}async findPackageLocator(e,r){if(!this.isEnabled(r))return null;let s=await je.getFactoryWithDefault(this.installStateCache,r.project.cwd,async()=>await CY(r.project,{unrollAliases:!0}));if(s===null)return null;let{locationRoot:a,segments:n}=aN(J.resolve(e),{skipPrefix:r.project.cwd}),c=s.locationTree.get(a);if(!c)return null;let f=c.locator;for(let p of n){if(c=c.children.get(p),!c)break;f=c.locator||f}return G.parseLocator(f)}makeInstaller(e){return new IY(e)}isEnabled(e){return e.project.configuration.get(\"nodeLinker\")===\"node-modules\"}},IY=class{constructor(e){this.opts=e;this.localStore=new Map;this.realLocatorChecksums=new Map;this.customData={store:new Map}}attachCustomData(e){this.customData=e}async installPackage(e,r){let s=J.resolve(r.packageFs.getRealPath(),r.prefixPath),a=this.customData.store.get(e.locatorHash);if(typeof a>\"u\"&&(a=await Qdt(e,r),e.linkType===\"HARD\"&&this.customData.store.set(e.locatorHash,a)),!G.isPackageCompatible(e,this.opts.project.configuration.getSupportedArchitectures()))return{packageLocation:null,buildRequest:null};let n=new Map,c=new Set;n.has(G.stringifyIdent(e))||n.set(G.stringifyIdent(e),e.reference);let f=e;if(G.isVirtualLocator(e)){f=G.devirtualizeLocator(e);for(let E of e.peerDependencies.values())n.set(G.stringifyIdent(E),null),c.add(G.stringifyIdent(E))}let p={packageLocation:`${fe.fromPortablePath(s)}/`,packageDependencies:n,packagePeers:c,linkType:e.linkType,discardFromLookup:r.discardFromLookup??!1};this.localStore.set(e.locatorHash,{pkg:e,customPackageData:a,dependencyMeta:this.opts.project.getDependencyMeta(e,e.version),pnpNode:p});let h=r.checksum?r.checksum.substring(r.checksum.indexOf(\"/\")+1):null;return this.realLocatorChecksums.set(f.locatorHash,h),{packageLocation:s,buildRequest:null}}async attachInternalDependencies(e,r){let s=this.localStore.get(e.locatorHash);if(typeof s>\"u\")throw new Error(\"Assertion failed: Expected information object to have been registered\");for(let[a,n]of r){let c=G.areIdentsEqual(a,n)?n.reference:[G.stringifyIdent(n),n.reference];s.pnpNode.packageDependencies.set(G.stringifyIdent(a),c)}}async attachExternalDependents(e,r){throw new Error(\"External dependencies haven't been implemented for the node-modules linker\")}async finalizeInstall(){if(this.opts.project.configuration.get(\"nodeLinker\")!==\"node-modules\")return;let e=new uo({baseFs:new $f({maxOpenFiles:80,readOnlyArchives:!0})}),r=await CY(this.opts.project),s=this.opts.project.configuration.get(\"nmMode\");(r===null||s!==r.nmMode)&&(this.opts.project.storedBuildState.clear(),r={locatorMap:new Map,binSymlinks:new Map,locationTree:new Map,nmMode:s,mtimeMs:0});let a=new Map(this.opts.project.workspaces.map(S=>{let b=this.opts.project.configuration.get(\"nmHoistingLimits\");try{b=je.validateEnum(xD,S.manifest.installConfig?.hoistingLimits??b)}catch{let I=G.prettyWorkspace(this.opts.project.configuration,S);this.opts.report.reportWarning(57,`${I}: Invalid 'installConfig.hoistingLimits' value. Expected one of ${Object.values(xD).join(\", \")}, using default: \"${b}\"`)}return[S.relativeCwd,b]})),n=new Map(this.opts.project.workspaces.map(S=>{let b=this.opts.project.configuration.get(\"nmSelfReferences\");return b=S.manifest.installConfig?.selfReferences??b,[S.relativeCwd,b]})),c={VERSIONS:{std:1},topLevel:{name:null,reference:null},getLocator:(S,b)=>Array.isArray(b)?{name:b[0],reference:b[1]}:{name:S,reference:b},getDependencyTreeRoots:()=>this.opts.project.workspaces.map(S=>{let b=S.anchoredLocator;return{name:G.stringifyIdent(b),reference:b.reference}}),getPackageInformation:S=>{let b=S.reference===null?this.opts.project.topLevelWorkspace.anchoredLocator:G.makeLocator(G.parseIdent(S.name),S.reference),I=this.localStore.get(b.locatorHash);if(typeof I>\"u\")throw new Error(\"Assertion failed: Expected the package reference to have been registered\");return I.pnpNode},findPackageLocator:S=>{let b=this.opts.project.tryWorkspaceByCwd(fe.toPortablePath(S));if(b!==null){let I=b.anchoredLocator;return{name:G.stringifyIdent(I),reference:I.reference}}throw new Error(\"Assertion failed: Unimplemented\")},resolveToUnqualified:()=>{throw new Error(\"Assertion failed: Unimplemented\")},resolveUnqualified:()=>{throw new Error(\"Assertion failed: Unimplemented\")},resolveRequest:()=>{throw new Error(\"Assertion failed: Unimplemented\")},resolveVirtual:S=>fe.fromPortablePath(uo.resolveVirtual(fe.toPortablePath(S)))},{tree:f,errors:p,preserveSymlinksRequired:h}=kD(c,{pnpifyFs:!1,validateExternalSoftLinks:!0,hoistingLimitsByCwd:a,project:this.opts.project,selfReferencesByCwd:n});if(!f){for(let{messageName:S,text:b}of p)this.opts.report.reportError(S,b);return}let E=zW(f);await Mdt(r,E,{baseFs:e,project:this.opts.project,report:this.opts.report,realLocatorChecksums:this.realLocatorChecksums,loadManifest:async S=>{let b=G.parseLocator(S),I=this.localStore.get(b.locatorHash);if(typeof I>\"u\")throw new Error(\"Assertion failed: Expected the slot to exist\");return I.customPackageData.manifest}});let C=[];for(let[S,b]of E.entries()){if(_Be(S))continue;let I=G.parseLocator(S),T=this.localStore.get(I.locatorHash);if(typeof T>\"u\")throw new Error(\"Assertion failed: Expected the slot to exist\");if(this.opts.project.tryWorkspaceByLocator(T.pkg))continue;let N=gA.extractBuildRequest(T.pkg,T.customPackageData,T.dependencyMeta,{configuration:this.opts.project.configuration});N&&C.push({buildLocations:b.locations,locator:I,buildRequest:N})}return h&&this.opts.report.reportWarning(72,`The application uses portals and that's why ${he.pretty(this.opts.project.configuration,\"--preserve-symlinks\",he.Type.CODE)} Node option is required for launching it`),{customData:this.customData,records:C}}};async function Qdt(t,e){let r=await Ut.tryFind(e.prefixPath,{baseFs:e.packageFs})??new Ut,s=new Set([\"preinstall\",\"install\",\"postinstall\"]);for(let a of r.scripts.keys())s.has(a)||r.scripts.delete(a);return{manifest:{bin:r.bin,scripts:r.scripts},misc:{hasBindingGyp:gA.hasBindingGyp(e)}}}async function Rdt(t,e,r,s,{installChangedByUser:a}){let n=\"\";n+=`# Warning: This file is automatically generated. Removing it is fine, but will\n`,n+=`# cause your node_modules installation to become invalidated.\n`,n+=`\n`,n+=`__metadata:\n`,n+=`  version: ${OBe}\n`,n+=`  nmMode: ${s.value}\n`;let c=Array.from(e.keys()).sort(),f=G.stringifyLocator(t.topLevelWorkspace.anchoredLocator);for(let E of c){let C=e.get(E);n+=`\n`,n+=`${JSON.stringify(E)}:\n`,n+=`  locations:\n`;for(let S of C.locations){let b=J.contains(t.cwd,S);if(b===null)throw new Error(`Assertion failed: Expected the path to be within the project (${S})`);n+=`    - ${JSON.stringify(b)}\n`}if(C.aliases.length>0){n+=`  aliases:\n`;for(let S of C.aliases)n+=`    - ${JSON.stringify(S)}\n`}if(E===f&&r.size>0){n+=`  bin:\n`;for(let[S,b]of r){let I=J.contains(t.cwd,S);if(I===null)throw new Error(`Assertion failed: Expected the path to be within the project (${S})`);n+=`    ${JSON.stringify(I)}:\n`;for(let[T,N]of b){let U=J.relative(J.join(S,Ri),N);n+=`      ${JSON.stringify(T)}: ${JSON.stringify(U)}\n`}}}}let p=t.cwd,h=J.join(p,Ri,LBe);a&&await ce.removePromise(h),await ce.changeFilePromise(h,n,{automaticNewlines:!0})}async function CY(t,{unrollAliases:e=!1}={}){let r=t.cwd,s=J.join(r,Ri,LBe),a;try{a=await ce.statPromise(s)}catch{}if(!a)return null;let n=as(await ce.readFilePromise(s,\"utf8\"));if(n.__metadata.version>OBe)return null;let c=n.__metadata.nmMode||\"classic\",f=new Map,p=new Map;delete n.__metadata;for(let[h,E]of Object.entries(n)){let C=E.locations.map(b=>J.join(r,b)),S=E.bin;if(S)for(let[b,I]of Object.entries(S)){let T=J.join(r,fe.toPortablePath(b)),N=je.getMapWithDefault(p,T);for(let[U,W]of Object.entries(I))N.set(U,fe.toPortablePath([T,Ri,W].join(J.sep)))}if(f.set(h,{target:vt.dot,linkType:\"HARD\",locations:C,aliases:E.aliases||[]}),e&&E.aliases)for(let b of E.aliases){let{scope:I,name:T}=G.parseLocator(h),N=G.makeLocator(G.makeIdent(I,T),b),U=G.stringifyLocator(N);f.set(U,{target:vt.dot,linkType:\"HARD\",locations:C,aliases:[]})}}return{locatorMap:f,binSymlinks:p,locationTree:MBe(f,{skipPrefix:t.cwd}),nmMode:c,mtimeMs:a.mtimeMs}}var Pw=async(t,e)=>{if(t.split(J.sep).indexOf(Ri)<0)throw new Error(`Assertion failed: trying to remove dir that doesn't contain node_modules: ${t}`);try{let r;if(!e.innerLoop&&(r=await ce.lstatPromise(t),!r.isDirectory()&&!r.isSymbolicLink()||r.isSymbolicLink()&&!e.isWorkspaceDir)){await ce.unlinkPromise(t);return}let s=await ce.readdirPromise(t,{withFileTypes:!0});for(let n of s){let c=J.join(t,n.name);n.isDirectory()?(n.name!==Ri||e&&e.innerLoop)&&await Pw(c,{innerLoop:!0,contentsOnly:!1}):await ce.unlinkPromise(c)}let a=!e.innerLoop&&e.isWorkspaceDir&&r?.isSymbolicLink();!e.contentsOnly&&!a&&await ce.rmdirPromise(t)}catch(r){if(r.code!==\"ENOENT\"&&r.code!==\"ENOTEMPTY\")throw r}},RBe=4,aN=(t,{skipPrefix:e})=>{let r=J.contains(e,t);if(r===null)throw new Error(`Assertion failed: Writing attempt prevented to ${t} which is outside project root: ${e}`);let s=r.split(J.sep).filter(p=>p!==\"\"),a=s.indexOf(Ri),n=s.slice(0,a).join(J.sep),c=J.join(e,n),f=s.slice(a);return{locationRoot:c,segments:f}},MBe=(t,{skipPrefix:e})=>{let r=new Map;if(t===null)return r;let s=()=>({children:new Map,linkType:\"HARD\"});for(let[a,n]of t.entries()){if(n.linkType===\"SOFT\"&&J.contains(e,n.target)!==null){let f=je.getFactoryWithDefault(r,n.target,s);f.locator=a,f.linkType=n.linkType}for(let c of n.locations){let{locationRoot:f,segments:p}=aN(c,{skipPrefix:e}),h=je.getFactoryWithDefault(r,f,s);for(let E=0;E<p.length;++E){let C=p[E];if(C!==\".\"){let S=je.getFactoryWithDefault(h.children,C,s);h.children.set(C,S),h=S}E===p.length-1&&(h.locator=a,h.linkType=n.linkType)}}}return r},vY=async(t,e,r)=>{if(process.platform===\"win32\"&&r===\"junctions\"){let s;try{s=await ce.lstatPromise(t)}catch{}if(!s||s.isDirectory()){await ce.symlinkPromise(t,e,\"junction\");return}}await ce.symlinkPromise(J.relative(J.dirname(e),t),e)};async function UBe(t,e,r){let s=J.join(t,`${wY.default.randomBytes(16).toString(\"hex\")}.tmp`);try{await ce.writeFilePromise(s,r);try{await ce.linkPromise(s,e)}catch{}}finally{await ce.unlinkPromise(s)}}async function Tdt({srcPath:t,dstPath:e,entry:r,globalHardlinksStore:s,baseFs:a,nmMode:n}){if(r.kind===\"file\"){if(n.value===\"hardlinks-global\"&&s&&r.digest){let f=J.join(s,r.digest.substring(0,2),`${r.digest.substring(2)}.dat`),p;try{let h=await ce.statPromise(f);if(h&&(!r.mtimeMs||h.mtimeMs>r.mtimeMs||h.mtimeMs<r.mtimeMs-kdt))if(await Nn.checksumFile(f,{baseFs:ce,algorithm:\"sha1\"})!==r.digest){let C=J.join(s,`${wY.default.randomBytes(16).toString(\"hex\")}.tmp`);await ce.renamePromise(f,C);let S=await a.readFilePromise(t);await ce.writeFilePromise(C,S);try{await ce.linkPromise(C,f),r.mtimeMs=new Date().getTime(),await ce.unlinkPromise(C)}catch{}}else r.mtimeMs||(r.mtimeMs=Math.ceil(h.mtimeMs));await ce.linkPromise(f,e),p=!0}catch{p=!1}if(!p){let h=await a.readFilePromise(t);await UBe(s,f,h),r.mtimeMs=new Date().getTime();try{await ce.linkPromise(f,e)}catch(E){E&&E.code&&E.code==\"EXDEV\"&&(n.value=\"hardlinks-local\",await a.copyFilePromise(t,e))}}}else await a.copyFilePromise(t,e);let c=r.mode&511;c!==420&&await ce.chmodPromise(e,c)}}var Fdt=async(t,e,{baseFs:r,globalHardlinksStore:s,nmMode:a,windowsLinkType:n,packageChecksum:c})=>{await ce.mkdirPromise(t,{recursive:!0});let f=async(E=vt.dot)=>{let C=J.join(e,E),S=await r.readdirPromise(C,{withFileTypes:!0}),b=new Map;for(let I of S){let T=J.join(E,I.name),N,U=J.join(C,I.name);if(I.isFile()){if(N={kind:\"file\",mode:(await r.lstatPromise(U)).mode},a.value===\"hardlinks-global\"){let W=await Nn.checksumFile(U,{baseFs:r,algorithm:\"sha1\"});N.digest=W}}else if(I.isDirectory())N={kind:\"directory\"};else if(I.isSymbolicLink())N={kind:\"symlink\",symlinkTo:await r.readlinkPromise(U)};else throw new Error(`Unsupported file type (file: ${U}, mode: 0o${await r.statSync(U).mode.toString(8).padStart(6,\"0\")})`);if(b.set(T,N),I.isDirectory()&&T!==Ri){let W=await f(T);for(let[ee,ie]of W)b.set(ee,ie)}}return b},p;if(a.value===\"hardlinks-global\"&&s&&c){let E=J.join(s,c.substring(0,2),`${c.substring(2)}.json`);try{p=new Map(Object.entries(JSON.parse(await ce.readFilePromise(E,\"utf8\"))))}catch{p=await f()}}else p=await f();let h=!1;for(let[E,C]of p){let S=J.join(e,E),b=J.join(t,E);if(C.kind===\"directory\")await ce.mkdirPromise(b,{recursive:!0});else if(C.kind===\"file\"){let I=C.mtimeMs;await Tdt({srcPath:S,dstPath:b,entry:C,nmMode:a,baseFs:r,globalHardlinksStore:s}),C.mtimeMs!==I&&(h=!0)}else C.kind===\"symlink\"&&await vY(J.resolve(J.dirname(b),C.symlinkTo),b,n)}if(a.value===\"hardlinks-global\"&&s&&h&&c){let E=J.join(s,c.substring(0,2),`${c.substring(2)}.json`);await ce.removePromise(E),await UBe(s,E,Buffer.from(JSON.stringify(Object.fromEntries(p))))}};function Ndt(t,e,r,s){let a=new Map,n=new Map,c=new Map,f=!1,p=(h,E,C,S,b)=>{let I=!0,T=J.join(h,E),N=new Set;if(E===Ri||E.startsWith(\"@\")){let W;try{W=ce.statSync(T)}catch{}I=!!W,W?W.mtimeMs>r?(f=!0,N=new Set(ce.readdirSync(T))):N=new Set(C.children.get(E).children.keys()):f=!0;let ee=e.get(h);if(ee){let ie=J.join(h,Ri,oN),ue;try{ue=ce.statSync(ie)}catch{}if(!ue)f=!0;else if(ue.mtimeMs>r){f=!0;let le=new Set(ce.readdirSync(ie)),me=new Map;n.set(h,me);for(let[pe,Be]of ee)le.has(pe)&&me.set(pe,Be)}else n.set(h,ee)}}else I=b.has(E);let U=C.children.get(E);if(I){let{linkType:W,locator:ee}=U,ie={children:new Map,linkType:W,locator:ee};if(S.children.set(E,ie),ee){let ue=je.getSetWithDefault(c,ee);ue.add(T),c.set(ee,ue)}for(let ue of U.children.keys())p(T,ue,U,ie,N)}else U.locator&&s.storedBuildState.delete(G.parseLocator(U.locator).locatorHash)};for(let[h,E]of t){let{linkType:C,locator:S}=E,b={children:new Map,linkType:C,locator:S};if(a.set(h,b),S){let I=je.getSetWithDefault(c,E.locator);I.add(h),c.set(E.locator,I)}E.children.has(Ri)&&p(h,Ri,E,b,new Set)}return{locationTree:a,binSymlinks:n,locatorLocations:c,installChangedByUser:f}}function _Be(t){let e=G.parseDescriptor(t);return G.isVirtualDescriptor(e)&&(e=G.devirtualizeDescriptor(e)),e.range.startsWith(\"link:\")}async function Odt(t,e,r,{loadManifest:s}){let a=new Map;for(let[f,{locations:p}]of t){let h=_Be(f)?null:await s(f,p[0]),E=new Map;if(h)for(let[C,S]of h.bin){let b=J.join(p[0],S);S!==\"\"&&ce.existsSync(b)&&E.set(C,S)}a.set(f,E)}let n=new Map,c=(f,p,h)=>{let E=new Map,C=J.contains(r,f);if(h.locator&&C!==null){let S=a.get(h.locator);for(let[b,I]of S){let T=J.join(f,fe.toPortablePath(I));E.set(b,T)}for(let[b,I]of h.children){let T=J.join(f,b),N=c(T,T,I);N.size>0&&n.set(f,new Map([...n.get(f)||new Map,...N]))}}else for(let[S,b]of h.children){let I=c(J.join(f,S),p,b);for(let[T,N]of I)E.set(T,N)}return E};for(let[f,p]of e){let h=c(f,f,p);h.size>0&&n.set(f,new Map([...n.get(f)||new Map,...h]))}return n}var TBe=(t,e)=>{if(!t||!e)return t===e;let r=G.parseLocator(t);G.isVirtualLocator(r)&&(r=G.devirtualizeLocator(r));let s=G.parseLocator(e);return G.isVirtualLocator(s)&&(s=G.devirtualizeLocator(s)),G.areLocatorsEqual(r,s)};function SY(t){return J.join(t.get(\"globalFolder\"),\"store\")}function Ldt(t,e){let r=s=>{let a=s.split(J.sep),n=a.lastIndexOf(Ri);if(n<0||n==a.length-1)throw new Error(`Assertion failed. Path is outside of any node_modules package ${s}`);return a.slice(0,n+(a[n+1].startsWith(\"@\")?3:2)).join(J.sep)};for(let s of t.values())for(let[a,n]of s)e.has(r(n))&&s.delete(a)}async function Mdt(t,e,{baseFs:r,project:s,report:a,loadManifest:n,realLocatorChecksums:c}){let f=J.join(s.cwd,Ri),{locationTree:p,binSymlinks:h,locatorLocations:E,installChangedByUser:C}=Ndt(t.locationTree,t.binSymlinks,t.mtimeMs,s),S=MBe(e,{skipPrefix:s.cwd}),b=[],I=async({srcDir:Be,dstDir:Ce,linkType:g,globalHardlinksStore:we,nmMode:ye,windowsLinkType:Ae,packageChecksum:se})=>{let X=(async()=>{try{g===\"SOFT\"?(await ce.mkdirPromise(J.dirname(Ce),{recursive:!0}),await vY(J.resolve(Be),Ce,Ae)):await Fdt(Ce,Be,{baseFs:r,globalHardlinksStore:we,nmMode:ye,windowsLinkType:Ae,packageChecksum:se})}catch(De){throw De.message=`While persisting ${Be} -> ${Ce} ${De.message}`,De}finally{ie.tick()}})().then(()=>b.splice(b.indexOf(X),1));b.push(X),b.length>RBe&&await Promise.race(b)},T=async(Be,Ce,g)=>{let we=(async()=>{let ye=async(Ae,se,X)=>{try{X.innerLoop||await ce.mkdirPromise(se,{recursive:!0});let De=await ce.readdirPromise(Ae,{withFileTypes:!0});for(let Te of De){if(!X.innerLoop&&Te.name===oN)continue;let mt=J.join(Ae,Te.name),j=J.join(se,Te.name);Te.isDirectory()?(Te.name!==Ri||X&&X.innerLoop)&&(await ce.mkdirPromise(j,{recursive:!0}),await ye(mt,j,{...X,innerLoop:!0})):me.value===\"hardlinks-local\"||me.value===\"hardlinks-global\"?await ce.linkPromise(mt,j):await ce.copyFilePromise(mt,j,NBe.default.constants.COPYFILE_FICLONE)}}catch(De){throw X.innerLoop||(De.message=`While cloning ${Ae} -> ${se} ${De.message}`),De}finally{X.innerLoop||ie.tick()}};await ye(Be,Ce,g)})().then(()=>b.splice(b.indexOf(we),1));b.push(we),b.length>RBe&&await Promise.race(b)},N=async(Be,Ce,g)=>{if(g)for(let[we,ye]of Ce.children){let Ae=g.children.get(we);await N(J.join(Be,we),ye,Ae)}else{Ce.children.has(Ri)&&await Pw(J.join(Be,Ri),{contentsOnly:!1});let we=J.basename(Be)===Ri&&p.has(J.join(J.dirname(Be)));await Pw(Be,{contentsOnly:Be===f,isWorkspaceDir:we})}};for(let[Be,Ce]of p){let g=S.get(Be);for(let[we,ye]of Ce.children){if(we===\".\")continue;let Ae=g&&g.children.get(we),se=J.join(Be,we);await N(se,ye,Ae)}}let U=async(Be,Ce,g)=>{if(g){TBe(Ce.locator,g.locator)||await Pw(Be,{contentsOnly:Ce.linkType===\"HARD\"});for(let[we,ye]of Ce.children){let Ae=g.children.get(we);await U(J.join(Be,we),ye,Ae)}}else{Ce.children.has(Ri)&&await Pw(J.join(Be,Ri),{contentsOnly:!0});let we=J.basename(Be)===Ri&&S.has(J.join(J.dirname(Be)));await Pw(Be,{contentsOnly:Ce.linkType===\"HARD\",isWorkspaceDir:we})}};for(let[Be,Ce]of S){let g=p.get(Be);for(let[we,ye]of Ce.children){if(we===\".\")continue;let Ae=g&&g.children.get(we);await U(J.join(Be,we),ye,Ae)}}let W=new Map,ee=[];for(let[Be,Ce]of E)for(let g of Ce){let{locationRoot:we,segments:ye}=aN(g,{skipPrefix:s.cwd}),Ae=S.get(we),se=we;if(Ae){for(let X of ye)if(se=J.join(se,X),Ae=Ae.children.get(X),!Ae)break;if(Ae){let X=TBe(Ae.locator,Be),De=e.get(Ae.locator),Te=De.target,mt=se,j=De.linkType;if(X)W.has(Te)||W.set(Te,mt);else if(Te!==mt){let rt=G.parseLocator(Ae.locator);G.isVirtualLocator(rt)&&(rt=G.devirtualizeLocator(rt)),ee.push({srcDir:Te,dstDir:mt,linkType:j,realLocatorHash:rt.locatorHash})}}}}for(let[Be,{locations:Ce}]of e.entries())for(let g of Ce){let{locationRoot:we,segments:ye}=aN(g,{skipPrefix:s.cwd}),Ae=p.get(we),se=S.get(we),X=we,De=e.get(Be),Te=G.parseLocator(Be);G.isVirtualLocator(Te)&&(Te=G.devirtualizeLocator(Te));let mt=Te.locatorHash,j=De.target,rt=g;if(j===rt)continue;let Fe=De.linkType;for(let Ne of ye)se=se.children.get(Ne);if(!Ae)ee.push({srcDir:j,dstDir:rt,linkType:Fe,realLocatorHash:mt});else for(let Ne of ye)if(X=J.join(X,Ne),Ae=Ae.children.get(Ne),!Ae){ee.push({srcDir:j,dstDir:rt,linkType:Fe,realLocatorHash:mt});break}}let ie=Ao.progressViaCounter(ee.length),ue=a.reportProgress(ie),le=s.configuration.get(\"nmMode\"),me={value:le},pe=s.configuration.get(\"winLinkType\");try{let Be=me.value===\"hardlinks-global\"?`${SY(s.configuration)}/v1`:null;if(Be&&!await ce.existsPromise(Be)){await ce.mkdirpPromise(Be);for(let g=0;g<256;g++)await ce.mkdirPromise(J.join(Be,g.toString(16).padStart(2,\"0\")))}for(let g of ee)(g.linkType===\"SOFT\"||!W.has(g.srcDir))&&(W.set(g.srcDir,g.dstDir),await I({...g,globalHardlinksStore:Be,nmMode:me,windowsLinkType:pe,packageChecksum:c.get(g.realLocatorHash)||null}));await Promise.all(b),b.length=0;for(let g of ee){let we=W.get(g.srcDir);g.linkType!==\"SOFT\"&&g.dstDir!==we&&await T(we,g.dstDir,{nmMode:me})}await Promise.all(b),await ce.mkdirPromise(f,{recursive:!0}),Ldt(h,new Set(ee.map(g=>g.dstDir)));let Ce=await Odt(e,S,s.cwd,{loadManifest:n});await Udt(h,Ce,s.cwd,pe),await Rdt(s,e,Ce,me,{installChangedByUser:C}),le==\"hardlinks-global\"&&me.value==\"hardlinks-local\"&&a.reportWarningOnce(74,\"'nmMode' has been downgraded to 'hardlinks-local' due to global cache and install folder being on different devices\")}finally{ue.stop()}}async function Udt(t,e,r,s){for(let a of t.keys()){if(J.contains(r,a)===null)throw new Error(`Assertion failed. Excepted bin symlink location to be inside project dir, instead it was at ${a}`);if(!e.has(a)){let n=J.join(a,Ri,oN);await ce.removePromise(n)}}for(let[a,n]of e){if(J.contains(r,a)===null)throw new Error(`Assertion failed. Excepted bin symlink location to be inside project dir, instead it was at ${a}`);let c=J.join(a,Ri,oN),f=t.get(a)||new Map;await ce.mkdirPromise(c,{recursive:!0});for(let p of f.keys())n.has(p)||(await ce.removePromise(J.join(c,p)),process.platform===\"win32\"&&await ce.removePromise(J.join(c,`${p}.cmd`)));for(let[p,h]of n){let E=f.get(p),C=J.join(c,p);E!==h&&(process.platform===\"win32\"?await(0,FBe.default)(fe.fromPortablePath(h),fe.fromPortablePath(C),{createPwshFile:!1}):(await ce.removePromise(C),await vY(h,C,s),J.contains(r,await ce.realpathPromise(h))!==null&&await ce.chmodPromise(h,493)))}}}Ge();Dt();eA();var GD=class extends sg{constructor(){super(...arguments);this.mode=\"loose\"}makeInstaller(r){return new DY(r)}},DY=class extends Gm{constructor(){super(...arguments);this.mode=\"loose\"}async transformPnpSettings(r){let s=new uo({baseFs:new $f({maxOpenFiles:80,readOnlyArchives:!0})}),a=IBe(r,this.opts.project.cwd,s),{tree:n,errors:c}=kD(a,{pnpifyFs:!1,project:this.opts.project});if(!n){for(let{messageName:C,text:S}of c)this.opts.report.reportError(C,S);return}let f=new Map;r.fallbackPool=f;let p=(C,S)=>{let b=G.parseLocator(S.locator),I=G.stringifyIdent(b);I===C?f.set(C,b.reference):f.set(C,[I,b.reference])},h=J.join(this.opts.project.cwd,Er.nodeModules),E=n.get(h);if(!(typeof E>\"u\")){if(\"target\"in E)throw new Error(\"Assertion failed: Expected the root junction point to be a directory\");for(let C of E.dirList){let S=J.join(h,C),b=n.get(S);if(typeof b>\"u\")throw new Error(\"Assertion failed: Expected the child to have been registered\");if(\"target\"in b)p(C,b);else for(let I of b.dirList){let T=J.join(S,I),N=n.get(T);if(typeof N>\"u\")throw new Error(\"Assertion failed: Expected the subchild to have been registered\");if(\"target\"in N)p(`${C}/${I}`,N);else throw new Error(\"Assertion failed: Expected the leaf junction to be a package\")}}}}};var _dt={hooks:{cleanGlobalArtifacts:async t=>{let e=SY(t);await ce.removePromise(e)}},configuration:{nmHoistingLimits:{description:\"Prevents packages to be hoisted past specific levels\",type:\"STRING\",values:[\"workspaces\",\"dependencies\",\"none\"],default:\"none\"},nmMode:{description:\"Defines in which measure Yarn must use hardlinks and symlinks when generated `node_modules` directories.\",type:\"STRING\",values:[\"classic\",\"hardlinks-local\",\"hardlinks-global\"],default:\"classic\"},nmSelfReferences:{description:\"Defines whether the linker should generate self-referencing symlinks for workspaces.\",type:\"BOOLEAN\",default:!0}},linkers:[jD,GD]},Hdt=_dt;var PK={};Vt(PK,{NpmHttpFetcher:()=>VD,NpmRemapResolver:()=>JD,NpmSemverFetcher:()=>oh,NpmSemverResolver:()=>KD,NpmTagResolver:()=>zD,default:()=>rPt,npmConfigUtils:()=>hi,npmHttpUtils:()=>an,npmPublishUtils:()=>v1});Ge();var JBe=ut(Ai());var oi=\"npm:\";var an={};Vt(an,{AuthType:()=>WBe,customPackageError:()=>qm,del:()=>imt,get:()=>Wm,getIdentUrl:()=>WD,getPackageMetadata:()=>Qw,handleInvalidAuthenticationError:()=>ag,post:()=>rmt,put:()=>nmt});Ge();Ge();Dt();var kY=ut(Vv());ql();var qBe=ut(Ai());var hi={};Vt(hi,{RegistryType:()=>jBe,getAuditRegistry:()=>jdt,getAuthConfiguration:()=>xY,getDefaultRegistry:()=>qD,getPublishRegistry:()=>Gdt,getRegistryConfiguration:()=>GBe,getScopeConfiguration:()=>bY,getScopeRegistry:()=>bw,isPackageApproved:()=>xw,normalizeRegistry:()=>Jc});Ge();var HBe=ut(Go()),jBe=(s=>(s.AUDIT_REGISTRY=\"npmAuditRegistry\",s.FETCH_REGISTRY=\"npmRegistryServer\",s.PUBLISH_REGISTRY=\"npmPublishRegistry\",s))(jBe||{});function Jc(t){return t.replace(/\\/$/,\"\")}function jdt({configuration:t}){return qD({configuration:t,type:\"npmAuditRegistry\"})}function Gdt(t,{configuration:e}){return t.publishConfig?.registry?Jc(t.publishConfig.registry):t.name?bw(t.name.scope,{configuration:e,type:\"npmPublishRegistry\"}):qD({configuration:e,type:\"npmPublishRegistry\"})}function bw(t,{configuration:e,type:r=\"npmRegistryServer\"}){let s=bY(t,{configuration:e});if(s===null)return qD({configuration:e,type:r});let a=s.get(r);return a===null?qD({configuration:e,type:r}):Jc(a)}function qD({configuration:t,type:e=\"npmRegistryServer\"}){let r=t.get(e);return Jc(r!==null?r:t.get(\"npmRegistryServer\"))}function GBe(t,{configuration:e}){let r=e.get(\"npmRegistries\"),s=Jc(t),a=r.get(s);if(typeof a<\"u\")return a;let n=r.get(s.replace(/^[a-z]+:/,\"\"));return typeof n<\"u\"?n:null}var qdt=new Map([[\"npmRegistryServer\",\"https://npm.jsr.io/\"]]);function bY(t,{configuration:e}){if(t===null)return null;let s=e.get(\"npmScopes\").get(t);return s||(t===\"jsr\"?qdt:null)}function xY(t,{configuration:e,ident:r}){let s=r&&bY(r.scope,{configuration:e});return s?.get(\"npmAuthIdent\")||s?.get(\"npmAuthToken\")?s:GBe(t,{configuration:e})||e}function Wdt({configuration:t,version:e,publishTimes:r}){let s=t.get(\"npmMinimalAgeGate\");if(s){let a=r?.[e];if(typeof a>\"u\"||(new Date().getTime()-new Date(a).getTime())/60/1e3<s)return!0}return!1}function Ydt(t,e,r){let s=G.tryParseDescriptor(r);if(!s||s.identHash!==t.identHash&&!HBe.default.isMatch(G.stringifyIdent(t),G.stringifyIdent(s)))return!1;if(s.range===\"unknown\")return!0;let a=Fr.validRange(s.range);return!(!a||!a.test(e))}function Vdt({configuration:t,ident:e,version:r}){return t.get(\"npmPreapprovedPackages\").some(s=>Ydt(e,r,s))}function xw(t){return!Wdt(t)||Vdt(t)}var WBe=(a=>(a[a.NO_AUTH=0]=\"NO_AUTH\",a[a.BEST_EFFORT=1]=\"BEST_EFFORT\",a[a.CONFIGURATION=2]=\"CONFIGURATION\",a[a.ALWAYS_AUTH=3]=\"ALWAYS_AUTH\",a))(WBe||{});async function ag(t,{attemptedAs:e,registry:r,headers:s,configuration:a}){if(cN(t))throw new jt(41,\"Invalid OTP token\");if(t.originalError?.name===\"HTTPError\"&&t.originalError?.response.statusCode===401)throw new jt(41,`Invalid authentication (${typeof e!=\"string\"?`as ${await omt(r,s,{configuration:a})}`:`attempted as ${e}`})`)}function qm(t,e){let r=t.response?.statusCode;return r?r===404?\"Package not found\":r>=500&&r<600?`The registry appears to be down (using a ${he.applyHyperlink(e,\"local cache\",\"https://yarnpkg.com/advanced/lexicon#local-cache\")} might have protected you against such outages)`:null:null}function WD(t){return t.scope?`/@${t.scope}%2f${t.name}`:`/${t.name}`}var YBe=new Map,Jdt=new Map;async function Kdt(t){return await je.getFactoryWithDefault(YBe,t,async()=>{let e=null;try{e=await ce.readJsonPromise(t)}catch{}return e})}async function zdt(t,e,{configuration:r,cached:s,registry:a,headers:n,version:c,...f}){return await je.getFactoryWithDefault(Jdt,t,async()=>await Wm(WD(e),{...f,customErrorMessage:qm,configuration:r,registry:a,ident:e,headers:{...n,\"If-None-Match\":s?.etag,\"If-Modified-Since\":s?.lastModified},wrapNetworkRequest:async p=>async()=>{let h=await p();if(h.statusCode===304){if(s===null)throw new Error(\"Assertion failed: cachedMetadata should not be null\");return{...h,body:s.metadata}}let E=Xdt(JSON.parse(h.body.toString())),C={metadata:E,etag:h.headers.etag,lastModified:h.headers[\"last-modified\"]};return YBe.set(t,Promise.resolve(C)),Promise.resolve().then(async()=>{let S=`${t}-${process.pid}.tmp`;await ce.mkdirPromise(J.dirname(S),{recursive:!0}),await ce.writeJsonPromise(S,C,{compact:!0}),await ce.renamePromise(S,t)}).catch(()=>{}),{...h,body:E}}}))}function Zdt(t){return t.scope!==null?`@${t.scope}-${t.name}-${t.scope.length}`:t.name}async function Qw(t,{cache:e,project:r,registry:s,headers:a,version:n,...c}){let{configuration:f}=r;s=YD(f,{ident:t,registry:s});let p=emt(f,s),h=J.join(p,`${Zdt(t)}.json`),E=null;if(!r.lockfileNeedsRefresh&&(E=await Kdt(h),E)){if(typeof n<\"u\"&&typeof E.metadata.versions[n]<\"u\")return E.metadata;if(f.get(\"enableOfflineMode\")){let C=structuredClone(E.metadata),S=new Set;if(e){for(let I of Object.keys(C.versions)){let T=G.makeLocator(t,`npm:${I}`),N=e.getLocatorMirrorPath(T);(!N||!ce.existsSync(N))&&(delete C.versions[I],S.add(I))}let b=C[\"dist-tags\"].latest;if(S.has(b)){let I=Object.keys(E.metadata.versions).sort(qBe.default.compare),T=I.indexOf(b);for(;S.has(I[T])&&T>=0;)T-=1;T>=0?C[\"dist-tags\"].latest=I[T]:delete C[\"dist-tags\"].latest}}return C}}return await zdt(h,t,{...c,configuration:f,cached:E,registry:s,headers:a,version:n})}var VBe=[\"name\",\"dist.tarball\",\"bin\",\"scripts\",\"os\",\"cpu\",\"libc\",\"dependencies\",\"dependenciesMeta\",\"optionalDependencies\",\"peerDependencies\",\"peerDependenciesMeta\",\"deprecated\"];function Xdt(t){return{\"dist-tags\":t[\"dist-tags\"],versions:Object.fromEntries(Object.entries(t.versions).map(([e,r])=>[e,Kd(r,VBe)])),time:t.time}}var $dt=Nn.makeHash(\"time\",...VBe).slice(0,6);function emt(t,e){let r=tmt(t),s=new URL(e);return J.join(r,$dt,s.hostname)}function tmt(t){return J.join(t.get(\"globalFolder\"),\"metadata/npm\")}async function Wm(t,{configuration:e,headers:r,ident:s,authType:a,allowOidc:n,registry:c,...f}){c=YD(e,{ident:s,registry:c}),s&&s.scope&&typeof a>\"u\"&&(a=1);let p=await lN(c,{authType:a,allowOidc:n,configuration:e,ident:s});p&&(r={...r,authorization:p});try{return await ln.get(t.charAt(0)===\"/\"?`${c}${t}`:t,{configuration:e,headers:r,...f})}catch(h){throw await ag(h,{registry:c,configuration:e,headers:r}),h}}async function rmt(t,e,{attemptedAs:r,configuration:s,headers:a,ident:n,authType:c=3,allowOidc:f,registry:p,otp:h,...E}){p=YD(s,{ident:n,registry:p});let C=await lN(p,{authType:c,allowOidc:f,configuration:s,ident:n});C&&(a={...a,authorization:C}),h&&(a={...a,...kw(h)});try{return await ln.post(p+t,e,{configuration:s,headers:a,...E})}catch(S){if(!cN(S)||h)throw await ag(S,{attemptedAs:r,registry:p,configuration:s,headers:a}),S;h=await QY(S,{configuration:s});let b={...a,...kw(h)};try{return await ln.post(`${p}${t}`,e,{configuration:s,headers:b,...E})}catch(I){throw await ag(I,{attemptedAs:r,registry:p,configuration:s,headers:a}),I}}}async function nmt(t,e,{attemptedAs:r,configuration:s,headers:a,ident:n,authType:c=3,allowOidc:f,registry:p,otp:h,...E}){p=YD(s,{ident:n,registry:p});let C=await lN(p,{authType:c,allowOidc:f,configuration:s,ident:n});C&&(a={...a,authorization:C}),h&&(a={...a,...kw(h)});try{return await ln.put(p+t,e,{configuration:s,headers:a,...E})}catch(S){if(!cN(S))throw await ag(S,{attemptedAs:r,registry:p,configuration:s,headers:a}),S;h=await QY(S,{configuration:s});let b={...a,...kw(h)};try{return await ln.put(`${p}${t}`,e,{configuration:s,headers:b,...E})}catch(I){throw await ag(I,{attemptedAs:r,registry:p,configuration:s,headers:a}),I}}}async function imt(t,{attemptedAs:e,configuration:r,headers:s,ident:a,authType:n=3,allowOidc:c,registry:f,otp:p,...h}){f=YD(r,{ident:a,registry:f});let E=await lN(f,{authType:n,allowOidc:c,configuration:r,ident:a});E&&(s={...s,authorization:E}),p&&(s={...s,...kw(p)});try{return await ln.del(f+t,{configuration:r,headers:s,...h})}catch(C){if(!cN(C)||p)throw await ag(C,{attemptedAs:e,registry:f,configuration:r,headers:s}),C;p=await QY(C,{configuration:r});let S={...s,...kw(p)};try{return await ln.del(`${f}${t}`,{configuration:r,headers:S,...h})}catch(b){throw await ag(b,{attemptedAs:e,registry:f,configuration:r,headers:s}),b}}}function YD(t,{ident:e,registry:r}){if(typeof r>\"u\"&&e)return bw(e.scope,{configuration:t});if(typeof r!=\"string\")throw new Error(\"Assertion failed: The registry should be a string\");return Jc(r)}async function lN(t,{authType:e=2,allowOidc:r=!1,configuration:s,ident:a}){let n=xY(t,{configuration:s,ident:a}),c=smt(n,e);if(!c)return null;let f=await s.reduceHook(p=>p.getNpmAuthenticationHeader,void 0,t,{configuration:s,ident:a});if(f)return f;if(n.get(\"npmAuthToken\"))return`Bearer ${n.get(\"npmAuthToken\")}`;if(n.get(\"npmAuthIdent\")){let p=n.get(\"npmAuthIdent\");return p.includes(\":\")?`Basic ${Buffer.from(p).toString(\"base64\")}`:`Basic ${p}`}if(r&&a){let p=await amt(t,{configuration:s,ident:a});if(p)return`Bearer ${p}`}if(c&&e!==1)throw new jt(33,\"No authentication configured for request\");return null}function smt(t,e){switch(e){case 2:return t.get(\"npmAlwaysAuth\");case 1:case 3:return!0;case 0:return!1;default:throw new Error(\"Unreachable\")}}async function omt(t,e,{configuration:r}){if(typeof e>\"u\"||typeof e.authorization>\"u\")return\"an anonymous user\";try{return(await ln.get(new URL(`${t}/-/whoami`).href,{configuration:r,headers:e,jsonResponse:!0})).username??\"an unknown user\"}catch{return\"an unknown user\"}}async function QY(t,{configuration:e}){let r=t.originalError?.response.headers[\"npm-notice\"];if(r&&(await Ot.start({configuration:e,stdout:process.stdout,includeFooter:!1},async a=>{if(a.reportInfo(0,r.replace(/(https?:\\/\\/\\S+)/g,he.pretty(e,\"$1\",he.Type.URL))),!process.env.YARN_IS_TEST_ENV){let n=r.match(/open (https?:\\/\\/\\S+)/i);if(n&&fs.openUrl){let{openNow:c}=await(0,kY.prompt)({type:\"confirm\",name:\"openNow\",message:\"Do you want to try to open this url now?\",required:!0,initial:!0,onCancel:()=>process.exit(130)});c&&(await fs.openUrl(n[1])||(a.reportSeparator(),a.reportWarning(0,\"We failed to automatically open the url; you'll have to open it yourself in your browser of choice.\")))}}}),process.stdout.write(`\n`)),process.env.YARN_IS_TEST_ENV)return process.env.YARN_INJECT_NPM_2FA_TOKEN||\"\";let{otp:s}=await(0,kY.prompt)({type:\"password\",name:\"otp\",message:\"One-time password:\",required:!0,onCancel:()=>process.exit(130)});return process.stdout.write(`\n`),s}function cN(t){if(t.originalError?.name!==\"HTTPError\")return!1;try{return(t.originalError?.response.headers[\"www-authenticate\"].split(/,\\s*/).map(r=>r.toLowerCase())).includes(\"otp\")}catch{return!1}}function kw(t){return{\"npm-otp\":t}}async function amt(t,{configuration:e,ident:r}){let s=null;if(process.env.GITLAB)s=process.env.NPM_ID_TOKEN||null;else if(process.env.GITHUB_ACTIONS){if(!(process.env.ACTIONS_ID_TOKEN_REQUEST_URL&&process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN))return null;let a=`npm:${new URL(t).host.replace(\"registry.yarnpkg.com\",\"registry.npmjs.org\").replace(\"yarn.npmjs.org\",\"registry.npmjs.org\")}`,n=new URL(process.env.ACTIONS_ID_TOKEN_REQUEST_URL);n.searchParams.append(\"audience\",a),s=(await ln.get(n.href,{configuration:e,jsonResponse:!0,headers:{Authorization:`Bearer ${process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN}`}})).value}if(!s)return null;try{return(await ln.post(`${t}/-/npm/v1/oidc/token/exchange/package${WD(r)}`,null,{configuration:e,jsonResponse:!0,headers:{Authorization:`Bearer ${s}`}})).token||null}catch{}return null}var VD=class{supports(e,r){if(!e.reference.startsWith(oi))return!1;let{selector:s,params:a}=G.parseRange(e.reference);return!(!JBe.default.valid(s)||a===null||typeof a.__archiveUrl!=\"string\")}getLocalPath(e,r){return null}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${G.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote server`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),checksum:c}}async fetchFromNetwork(e,r){let{params:s}=G.parseRange(e.reference);if(s===null||typeof s.__archiveUrl!=\"string\")throw new Error(\"Assertion failed: The archiveUrl querystring parameter should have been available\");let a=await Wm(s.__archiveUrl,{customErrorMessage:qm,configuration:r.project.configuration,ident:e});return await ps.convertToZip(a,{configuration:r.project.configuration,prefixPath:G.getIdentVendorPath(e),stripComponents:1})}};Ge();var JD=class{supportsDescriptor(e,r){return!(!e.range.startsWith(oi)||!G.tryParseDescriptor(e.range.slice(oi.length),!0))}supportsLocator(e,r){return!1}shouldPersistResolution(e,r){throw new Error(\"Unreachable\")}bindDescriptor(e,r,s){return e}getResolutionDependencies(e,r){let s=r.project.configuration.normalizeDependency(G.parseDescriptor(e.range.slice(oi.length),!0));return r.resolver.getResolutionDependencies(s,r)}async getCandidates(e,r,s){let a=s.project.configuration.normalizeDependency(G.parseDescriptor(e.range.slice(oi.length),!0));return await s.resolver.getCandidates(a,r,s)}async getSatisfying(e,r,s,a){let n=a.project.configuration.normalizeDependency(G.parseDescriptor(e.range.slice(oi.length),!0));return a.resolver.getSatisfying(n,r,s,a)}resolve(e,r){throw new Error(\"Unreachable\")}};Ge();Ge();var KBe=ut(Ai());var oh=class t{supports(e,r){if(!e.reference.startsWith(oi))return!1;let s=new URL(e.reference);return!(!KBe.default.valid(s.pathname)||s.searchParams.has(\"__archiveUrl\"))}getLocalPath(e,r){return null}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${G.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote registry`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),checksum:c}}async fetchFromNetwork(e,r){let s;try{s=await Wm(t.getLocatorUrl(e),{customErrorMessage:qm,configuration:r.project.configuration,ident:e})}catch{s=await Wm(t.getLocatorUrl(e).replace(/%2f/g,\"/\"),{customErrorMessage:qm,configuration:r.project.configuration,ident:e})}return await ps.convertToZip(s,{configuration:r.project.configuration,prefixPath:G.getIdentVendorPath(e),stripComponents:1})}static isConventionalTarballUrl(e,r,{configuration:s}){let a=bw(e.scope,{configuration:s}),n=t.getLocatorUrl(e);return r=r.replace(/^https?:(\\/\\/(?:[^/]+\\.)?npmjs.org(?:$|\\/))/,\"https:$1\"),a=a.replace(/^https:\\/\\/registry\\.npmjs\\.org($|\\/)/,\"https://registry.yarnpkg.com$1\"),r=r.replace(/^https:\\/\\/registry\\.npmjs\\.org($|\\/)/,\"https://registry.yarnpkg.com$1\"),r===a+n||r===a+n.replace(/%2f/g,\"/\")}static getLocatorUrl(e){let r=Fr.clean(e.reference.slice(oi.length));if(r===null)throw new jt(10,\"The npm semver resolver got selected, but the version isn't semver\");return`${WD(e)}/-/${e.name}-${r}.tgz`}};Ge();Ge();Ge();var RY=ut(Ai());var uN=G.makeIdent(null,\"node-gyp\"),lmt=/\\b(node-gyp|prebuild-install)\\b/,KD=class{supportsDescriptor(e,r){return e.range.startsWith(oi)?!!Fr.validRange(e.range.slice(oi.length)):!1}supportsLocator(e,r){if(!e.reference.startsWith(oi))return!1;let{selector:s}=G.parseRange(e.reference);return!!RY.default.valid(s)}shouldPersistResolution(e,r){return!0}bindDescriptor(e,r,s){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){let a=Fr.validRange(e.range.slice(oi.length));if(a===null)throw new Error(`Expected a valid range, got ${e.range.slice(oi.length)}`);let n=await Qw(e,{cache:s.fetchOptions?.cache,project:s.project,version:RY.default.valid(a.raw)?a.raw:void 0}),c=je.mapAndFilter(Object.keys(n.versions),h=>{try{let E=new Fr.SemVer(h);if(a.test(E))return xw({configuration:s.project.configuration,ident:e,version:h,publishTimes:n.time})?E:je.mapAndFilter.skip}catch{}return je.mapAndFilter.skip}),f=c.filter(h=>!n.versions[h.raw].deprecated),p=f.length>0?f:c;return p.sort((h,E)=>-h.compare(E)),p.map(h=>{let E=G.makeLocator(e,`${oi}${h.raw}`),C=n.versions[h.raw].dist.tarball;return oh.isConventionalTarballUrl(E,C,{configuration:s.project.configuration})?E:G.bindLocator(E,{__archiveUrl:C})})}async getSatisfying(e,r,s,a){let n=Fr.validRange(e.range.slice(oi.length));if(n===null)throw new Error(`Expected a valid range, got ${e.range.slice(oi.length)}`);return{locators:je.mapAndFilter(s,p=>{if(p.identHash!==e.identHash)return je.mapAndFilter.skip;let h=G.tryParseRange(p.reference,{requireProtocol:oi});if(!h)return je.mapAndFilter.skip;let E=new Fr.SemVer(h.selector);return n.test(E)?{locator:p,version:E}:je.mapAndFilter.skip}).sort((p,h)=>-p.version.compare(h.version)).map(({locator:p})=>p),sorted:!0}}async resolve(e,r){let{selector:s}=G.parseRange(e.reference),a=Fr.clean(s);if(a===null)throw new jt(10,\"The npm semver resolver got selected, but the version isn't semver\");let n=await Qw(e,{cache:r.fetchOptions?.cache,project:r.project,version:a});if(!Object.hasOwn(n,\"versions\"))throw new jt(15,'Registry returned invalid data for - missing \"versions\" field');if(!Object.hasOwn(n.versions,a))throw new jt(16,`Registry failed to return reference \"${a}\"`);let c=new Ut;if(c.load(n.versions[a]),!c.dependencies.has(uN.identHash)&&!c.peerDependencies.has(uN.identHash)){for(let f of c.scripts.values())if(f.match(lmt)){c.dependencies.set(uN.identHash,G.makeDescriptor(uN,\"latest\"));break}}return{...e,version:a,languageName:\"node\",linkType:\"HARD\",conditions:c.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(c.dependencies),peerDependencies:c.peerDependencies,dependenciesMeta:c.dependenciesMeta,peerDependenciesMeta:c.peerDependenciesMeta,bin:c.bin}}};Ge();Ge();var fN=ut(Ai());var zD=class{supportsDescriptor(e,r){return!(!e.range.startsWith(oi)||!Mp.test(e.range.slice(oi.length)))}supportsLocator(e,r){return!1}shouldPersistResolution(e,r){throw new Error(\"Unreachable\")}bindDescriptor(e,r,s){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,s){let a=e.range.slice(oi.length),n=await Qw(e,{cache:s.fetchOptions?.cache,project:s.project});if(!Object.hasOwn(n,\"dist-tags\"))throw new jt(15,'Registry returned invalid data - missing \"dist-tags\" field');let c=n[\"dist-tags\"];if(!Object.hasOwn(c,a))throw new jt(16,`Registry failed to return tag \"${a}\"`);let f=Object.keys(n.versions),p=n.time,h=c[a];if(a===\"latest\"&&!xw({configuration:s.project.configuration,ident:e,version:h,publishTimes:p})){let S=h.includes(\"-\"),b=fN.default.rsort(f).find(I=>fN.default.lt(I,h)&&(S||!I.includes(\"-\"))&&xw({configuration:s.project.configuration,ident:e,version:I,publishTimes:p}));if(!b)throw new jt(16,`The version for tag \"${a}\" is quarantined, and no lower version is available`);h=b}let E=G.makeLocator(e,`${oi}${h}`),C=n.versions[h].dist.tarball;return oh.isConventionalTarballUrl(E,C,{configuration:s.project.configuration})?[E]:[G.bindLocator(E,{__archiveUrl:C})]}async getSatisfying(e,r,s,a){let n=[];for(let c of s){if(c.identHash!==e.identHash)continue;let f=G.tryParseRange(c.reference,{requireProtocol:oi});if(!(!f||!fN.default.valid(f.selector))){if(f.params?.__archiveUrl){let p=G.makeRange({protocol:oi,selector:f.selector,source:null,params:null}),[h]=await a.resolver.getCandidates(G.makeDescriptor(e,p),r,a);if(c.reference!==h.reference)continue}n.push(c)}}return{locators:n,sorted:!1}}async resolve(e,r){throw new Error(\"Unreachable\")}};var v1={};Vt(v1,{getGitHead:()=>$Dt,getPublishAccess:()=>Uxe,getReadmeContent:()=>_xe,makePublishBody:()=>XDt});Ge();Ge();Dt();var IV={};Vt(IV,{PackCommand:()=>jw,default:()=>HEt,packUtils:()=>yA});Ge();Ge();Ge();Dt();Yt();var yA={};Vt(yA,{genPackList:()=>FN,genPackStream:()=>EV,genPackageManifest:()=>DSe,hasPackScripts:()=>mV,prepareForPack:()=>yV});Ge();Dt();var dV=ut(Go()),vSe=ut(ISe()),SSe=Ie(\"zlib\"),kEt=[\"/package.json\",\"/readme\",\"/readme.*\",\"/license\",\"/license.*\",\"/licence\",\"/licence.*\",\"/changelog\",\"/changelog.*\"],QEt=[\"/package.tgz\",\".github\",\".git\",\".hg\",\"node_modules\",\".npmignore\",\".gitignore\",\".#*\",\".DS_Store\"];async function mV(t){return!!(In.hasWorkspaceScript(t,\"prepack\")||In.hasWorkspaceScript(t,\"postpack\"))}async function yV(t,{report:e},r){await In.maybeExecuteWorkspaceLifecycleScript(t,\"prepack\",{report:e});try{let s=J.join(t.cwd,Ut.fileName);await ce.existsPromise(s)&&await t.manifest.loadFile(s,{baseFs:ce}),await r()}finally{await In.maybeExecuteWorkspaceLifecycleScript(t,\"postpack\",{report:e})}}async function EV(t,e){typeof e>\"u\"&&(e=await FN(t));let r=new Set;for(let n of t.manifest.publishConfig?.executableFiles??new Set)r.add(J.normalize(n));for(let n of t.manifest.bin.values())r.add(J.normalize(n));let s=vSe.default.pack();process.nextTick(async()=>{for(let n of e){let c=J.normalize(n),f=J.resolve(t.cwd,c),p=J.join(\"package\",c),h=await ce.lstatPromise(f),E={name:p,mtime:new Date(fi.SAFE_TIME*1e3)},C=r.has(c)?493:420,S,b,I=new Promise((N,U)=>{S=N,b=U}),T=N=>{N?b(N):S()};if(h.isFile()){let N;c===\"package.json\"?N=Buffer.from(JSON.stringify(await DSe(t),null,2)):N=await ce.readFilePromise(f),s.entry({...E,mode:C,type:\"file\"},N,T)}else h.isSymbolicLink()?s.entry({...E,mode:C,type:\"symlink\",linkname:await ce.readlinkPromise(f)},T):T(new Error(`Unsupported file type ${h.mode} for ${fe.fromPortablePath(c)}`));await I}s.finalize()});let a=(0,SSe.createGzip)();return s.pipe(a),a}async function DSe(t){let e=JSON.parse(JSON.stringify(t.manifest.raw));return await t.project.configuration.triggerHook(r=>r.beforeWorkspacePacking,t,e),e}async function FN(t){let e=t.project,r=e.configuration,s={accept:[],reject:[]};for(let C of QEt)s.reject.push(C);for(let C of kEt)s.accept.push(C);s.reject.push(r.get(\"rcFilename\"));let a=C=>{if(C===null||!C.startsWith(`${t.cwd}/`))return;let S=J.relative(t.cwd,C),b=J.resolve(vt.root,S);s.reject.push(b)};a(J.resolve(e.cwd,Er.lockfile)),a(r.get(\"cacheFolder\")),a(r.get(\"globalFolder\")),a(r.get(\"installStatePath\")),a(r.get(\"virtualFolder\")),a(r.get(\"yarnPath\")),await r.triggerHook(C=>C.populateYarnPaths,e,C=>{a(C)});for(let C of e.workspaces){let S=J.relative(t.cwd,C.cwd);S!==\"\"&&!S.match(/^(\\.\\.)?\\//)&&s.reject.push(`/${S}`)}let n={accept:[],reject:[]},c=t.manifest.publishConfig?.main??t.manifest.main,f=t.manifest.publishConfig?.module??t.manifest.module,p=t.manifest.publishConfig?.browser??t.manifest.browser,h=t.manifest.publishConfig?.bin??t.manifest.bin;c!=null&&n.accept.push(J.resolve(vt.root,c)),f!=null&&n.accept.push(J.resolve(vt.root,f)),typeof p==\"string\"&&n.accept.push(J.resolve(vt.root,p));for(let C of h.values())n.accept.push(J.resolve(vt.root,C));if(p instanceof Map)for(let[C,S]of p.entries())n.accept.push(J.resolve(vt.root,C)),typeof S==\"string\"&&n.accept.push(J.resolve(vt.root,S));let E=t.manifest.files!==null;if(E){n.reject.push(\"/*\");for(let C of t.manifest.files)PSe(n.accept,C,{cwd:vt.root})}return await REt(t.cwd,{hasExplicitFileList:E,globalList:s,ignoreList:n})}async function REt(t,{hasExplicitFileList:e,globalList:r,ignoreList:s}){let a=[],n=new Hf(t),c=[[vt.root,[s]]];for(;c.length>0;){let[f,p]=c.pop(),h=await n.lstatPromise(f);if(!wSe(f,{globalList:r,ignoreLists:h.isDirectory()?null:p}))if(h.isDirectory()){let E=await n.readdirPromise(f),C=!1,S=!1;if(!e||f!==vt.root)for(let T of E)C=C||T===\".gitignore\",S=S||T===\".npmignore\";let b=S?await CSe(n,f,\".npmignore\"):C?await CSe(n,f,\".gitignore\"):null,I=b!==null?[b].concat(p):p;wSe(f,{globalList:r,ignoreLists:p})&&(I=[...p,{accept:[],reject:[\"**/*\"]}]);for(let T of E)c.push([J.resolve(f,T),I])}else(h.isFile()||h.isSymbolicLink())&&a.push(J.relative(vt.root,f))}return a.sort()}async function CSe(t,e,r){let s={accept:[],reject:[]},a=await t.readFilePromise(J.join(e,r),\"utf8\");for(let n of a.split(/\\n/g))PSe(s.reject,n,{cwd:e});return s}function TEt(t,{cwd:e}){let r=t[0]===\"!\";return r&&(t=t.slice(1)),t.match(/\\.{0,1}\\//)&&(t=J.resolve(e,t)),r&&(t=`!${t}`),t}function PSe(t,e,{cwd:r}){let s=e.trim();s===\"\"||s[0]===\"#\"||t.push(TEt(s,{cwd:r}))}function wSe(t,{globalList:e,ignoreLists:r}){let s=TN(t,e.accept);if(s!==0)return s===2;let a=TN(t,e.reject);if(a!==0)return a===1;if(r!==null)for(let n of r){let c=TN(t,n.accept);if(c!==0)return c===2;let f=TN(t,n.reject);if(f!==0)return f===1}return!1}function TN(t,e){let r=e,s=[];for(let a=0;a<e.length;++a)e[a][0]!==\"!\"?r!==e&&r.push(e[a]):(r===e&&(r=e.slice(0,a)),s.push(e[a].slice(1)));return BSe(t,s)?2:BSe(t,r)?1:0}function BSe(t,e){let r=e,s=[];for(let a=0;a<e.length;++a)e[a].includes(\"/\")?r!==e&&r.push(e[a]):(r===e&&(r=e.slice(0,a)),s.push(e[a]));return!!(dV.default.isMatch(t,r,{dot:!0,nocase:!0})||dV.default.isMatch(t,s,{dot:!0,basename:!0,nocase:!0}))}var jw=class extends ft{constructor(){super(...arguments);this.installIfNeeded=ge.Boolean(\"--install-if-needed\",!1,{description:\"Run a preliminary `yarn install` if the package contains build scripts\"});this.dryRun=ge.Boolean(\"-n,--dry-run\",!1,{description:\"Print the file paths without actually generating the package archive\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.out=ge.String(\"-o,--out\",{description:\"Create the archive at the specified path\"});this.filename=ge.String(\"--filename\",{hidden:!0})}static{this.paths=[[\"pack\"]]}static{this.usage=ot.Usage({description:\"generate a tarball from the active workspace\",details:\"\\n      This command will turn the active workspace into a compressed archive suitable for publishing. The archive will by default be stored at the root of the workspace (`package.tgz`).\\n\\n      If the `-o,--out` is set the archive will be created at the specified path. The `%s` and `%v` variables can be used within the path and will be respectively replaced by the package name and version.\\n    \",examples:[[\"Create an archive from the active workspace\",\"yarn pack\"],[\"List the files that would be made part of the workspace's archive\",\"yarn pack --dry-run\"],[\"Name and output the archive in a dedicated folder\",\"yarn pack --out /artifacts/%s-%v.tgz\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);await mV(a)&&(this.installIfNeeded?await s.install({cache:await Kr.find(r),report:new ki}):await s.restoreInstallState());let n=this.out??this.filename,c=typeof n<\"u\"?J.resolve(this.context.cwd,FEt(n,{workspace:a})):J.resolve(a.cwd,\"package.tgz\");return(await Ot.start({configuration:r,stdout:this.context.stdout,json:this.json},async p=>{await yV(a,{report:p},async()=>{p.reportJson({base:fe.fromPortablePath(a.cwd)});let h=await FN(a);for(let E of h)p.reportInfo(null,fe.fromPortablePath(E)),p.reportJson({location:fe.fromPortablePath(E)});if(!this.dryRun){let E=await EV(a,h);await ce.mkdirPromise(J.dirname(c),{recursive:!0});let C=ce.createWriteStream(c);E.pipe(C),await new Promise(S=>{C.on(\"finish\",S)})}}),this.dryRun||(p.reportInfo(0,`Package archive generated in ${he.pretty(r,c,he.Type.PATH)}`),p.reportJson({output:fe.fromPortablePath(c)}))})).exitCode()}};function FEt(t,{workspace:e}){let r=t.replace(\"%s\",NEt(e)).replace(\"%v\",OEt(e));return fe.toPortablePath(r)}function NEt(t){return t.manifest.name!==null?G.slugifyIdent(t.manifest.name):\"package\"}function OEt(t){return t.manifest.version!==null?t.manifest.version:\"unknown\"}var LEt=[\"dependencies\",\"devDependencies\",\"peerDependencies\"],MEt=\"workspace:\",UEt=(t,e)=>{e.publishConfig&&(e.publishConfig.type&&(e.type=e.publishConfig.type),e.publishConfig.main&&(e.main=e.publishConfig.main),e.publishConfig.browser&&(e.browser=e.publishConfig.browser),e.publishConfig.module&&(e.module=e.publishConfig.module),e.publishConfig.exports&&(e.exports=e.publishConfig.exports),e.publishConfig.imports&&(e.imports=e.publishConfig.imports),e.publishConfig.bin&&(e.bin=e.publishConfig.bin));let r=t.project;for(let s of LEt)for(let a of t.manifest.getForScope(s).values()){let n=r.tryWorkspaceByDescriptor(a),c=G.parseRange(a.range);if(c.protocol===MEt)if(n===null){if(r.tryWorkspaceByIdent(a)===null)throw new jt(21,`${G.prettyDescriptor(r.configuration,a)}: No local workspace found for this range`)}else{let f;G.areDescriptorsEqual(a,n.anchoredDescriptor)||c.selector===\"*\"?f=n.manifest.version??\"0.0.0\":c.selector===\"~\"||c.selector===\"^\"?f=`${c.selector}${n.manifest.version??\"0.0.0\"}`:f=c.selector;let p=s===\"dependencies\"?G.makeDescriptor(a,\"unknown\"):null,h=p!==null&&t.manifest.ensureDependencyMeta(p).optional?\"optionalDependencies\":s;e[h][G.stringifyIdent(a)]=f}}},_Et={hooks:{beforeWorkspacePacking:UEt},commands:[jw]},HEt=_Et;var Mxe=ut(OSe());Ge();var Oxe=ut(Nxe()),{env:Bt}=process,GDt=\"application/vnd.in-toto+json\",qDt=\"https://in-toto.io/Statement/v0.1\",WDt=\"https://in-toto.io/Statement/v1\",YDt=\"https://slsa.dev/provenance/v0.2\",VDt=\"https://slsa.dev/provenance/v1\",JDt=\"https://github.com/actions/runner\",KDt=\"https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1\",zDt=\"https://github.com/npm/cli/gitlab\",ZDt=\"v0alpha1\",Lxe=async(t,e)=>{let r;if(Bt.GITHUB_ACTIONS){if(!Bt.ACTIONS_ID_TOKEN_REQUEST_URL)throw new jt(91,'Provenance generation in GitHub Actions requires \"write\" access to the \"id-token\" permission');let s=(Bt.GITHUB_WORKFLOW_REF||\"\").replace(`${Bt.GITHUB_REPOSITORY}/`,\"\"),a=s.indexOf(\"@\"),n=s.slice(0,a),c=s.slice(a+1);r={_type:WDt,subject:t,predicateType:VDt,predicate:{buildDefinition:{buildType:KDt,externalParameters:{workflow:{ref:c,repository:`${Bt.GITHUB_SERVER_URL}/${Bt.GITHUB_REPOSITORY}`,path:n}},internalParameters:{github:{event_name:Bt.GITHUB_EVENT_NAME,repository_id:Bt.GITHUB_REPOSITORY_ID,repository_owner_id:Bt.GITHUB_REPOSITORY_OWNER_ID}},resolvedDependencies:[{uri:`git+${Bt.GITHUB_SERVER_URL}/${Bt.GITHUB_REPOSITORY}@${Bt.GITHUB_REF}`,digest:{gitCommit:Bt.GITHUB_SHA}}]},runDetails:{builder:{id:`${JDt}/${Bt.RUNNER_ENVIRONMENT}`},metadata:{invocationId:`${Bt.GITHUB_SERVER_URL}/${Bt.GITHUB_REPOSITORY}/actions/runs/${Bt.GITHUB_RUN_ID}/attempts/${Bt.GITHUB_RUN_ATTEMPT}`}}}}}else if(Bt.GITLAB_CI){if(!Bt.SIGSTORE_ID_TOKEN)throw new jt(91,`Provenance generation in GitLab CI requires \"SIGSTORE_ID_TOKEN\" with \"sigstore\" audience to be present in \"id_tokens\". For more info see:\nhttps://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html`);r={_type:qDt,subject:t,predicateType:YDt,predicate:{buildType:`${zDt}/${ZDt}`,builder:{id:`${Bt.CI_PROJECT_URL}/-/runners/${Bt.CI_RUNNER_ID}`},invocation:{configSource:{uri:`git+${Bt.CI_PROJECT_URL}`,digest:{sha1:Bt.CI_COMMIT_SHA},entryPoint:Bt.CI_JOB_NAME},parameters:{CI:Bt.CI,CI_API_GRAPHQL_URL:Bt.CI_API_GRAPHQL_URL,CI_API_V4_URL:Bt.CI_API_V4_URL,CI_BUILD_BEFORE_SHA:Bt.CI_BUILD_BEFORE_SHA,CI_BUILD_ID:Bt.CI_BUILD_ID,CI_BUILD_NAME:Bt.CI_BUILD_NAME,CI_BUILD_REF:Bt.CI_BUILD_REF,CI_BUILD_REF_NAME:Bt.CI_BUILD_REF_NAME,CI_BUILD_REF_SLUG:Bt.CI_BUILD_REF_SLUG,CI_BUILD_STAGE:Bt.CI_BUILD_STAGE,CI_COMMIT_BEFORE_SHA:Bt.CI_COMMIT_BEFORE_SHA,CI_COMMIT_BRANCH:Bt.CI_COMMIT_BRANCH,CI_COMMIT_REF_NAME:Bt.CI_COMMIT_REF_NAME,CI_COMMIT_REF_PROTECTED:Bt.CI_COMMIT_REF_PROTECTED,CI_COMMIT_REF_SLUG:Bt.CI_COMMIT_REF_SLUG,CI_COMMIT_SHA:Bt.CI_COMMIT_SHA,CI_COMMIT_SHORT_SHA:Bt.CI_COMMIT_SHORT_SHA,CI_COMMIT_TIMESTAMP:Bt.CI_COMMIT_TIMESTAMP,CI_COMMIT_TITLE:Bt.CI_COMMIT_TITLE,CI_CONFIG_PATH:Bt.CI_CONFIG_PATH,CI_DEFAULT_BRANCH:Bt.CI_DEFAULT_BRANCH,CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX:Bt.CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX,CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX:Bt.CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX,CI_DEPENDENCY_PROXY_SERVER:Bt.CI_DEPENDENCY_PROXY_SERVER,CI_DEPENDENCY_PROXY_USER:Bt.CI_DEPENDENCY_PROXY_USER,CI_JOB_ID:Bt.CI_JOB_ID,CI_JOB_NAME:Bt.CI_JOB_NAME,CI_JOB_NAME_SLUG:Bt.CI_JOB_NAME_SLUG,CI_JOB_STAGE:Bt.CI_JOB_STAGE,CI_JOB_STARTED_AT:Bt.CI_JOB_STARTED_AT,CI_JOB_URL:Bt.CI_JOB_URL,CI_NODE_TOTAL:Bt.CI_NODE_TOTAL,CI_PAGES_DOMAIN:Bt.CI_PAGES_DOMAIN,CI_PAGES_URL:Bt.CI_PAGES_URL,CI_PIPELINE_CREATED_AT:Bt.CI_PIPELINE_CREATED_AT,CI_PIPELINE_ID:Bt.CI_PIPELINE_ID,CI_PIPELINE_IID:Bt.CI_PIPELINE_IID,CI_PIPELINE_SOURCE:Bt.CI_PIPELINE_SOURCE,CI_PIPELINE_URL:Bt.CI_PIPELINE_URL,CI_PROJECT_CLASSIFICATION_LABEL:Bt.CI_PROJECT_CLASSIFICATION_LABEL,CI_PROJECT_DESCRIPTION:Bt.CI_PROJECT_DESCRIPTION,CI_PROJECT_ID:Bt.CI_PROJECT_ID,CI_PROJECT_NAME:Bt.CI_PROJECT_NAME,CI_PROJECT_NAMESPACE:Bt.CI_PROJECT_NAMESPACE,CI_PROJECT_NAMESPACE_ID:Bt.CI_PROJECT_NAMESPACE_ID,CI_PROJECT_PATH:Bt.CI_PROJECT_PATH,CI_PROJECT_PATH_SLUG:Bt.CI_PROJECT_PATH_SLUG,CI_PROJECT_REPOSITORY_LANGUAGES:Bt.CI_PROJECT_REPOSITORY_LANGUAGES,CI_PROJECT_ROOT_NAMESPACE:Bt.CI_PROJECT_ROOT_NAMESPACE,CI_PROJECT_TITLE:Bt.CI_PROJECT_TITLE,CI_PROJECT_URL:Bt.CI_PROJECT_URL,CI_PROJECT_VISIBILITY:Bt.CI_PROJECT_VISIBILITY,CI_REGISTRY:Bt.CI_REGISTRY,CI_REGISTRY_IMAGE:Bt.CI_REGISTRY_IMAGE,CI_REGISTRY_USER:Bt.CI_REGISTRY_USER,CI_RUNNER_DESCRIPTION:Bt.CI_RUNNER_DESCRIPTION,CI_RUNNER_ID:Bt.CI_RUNNER_ID,CI_RUNNER_TAGS:Bt.CI_RUNNER_TAGS,CI_SERVER_HOST:Bt.CI_SERVER_HOST,CI_SERVER_NAME:Bt.CI_SERVER_NAME,CI_SERVER_PORT:Bt.CI_SERVER_PORT,CI_SERVER_PROTOCOL:Bt.CI_SERVER_PROTOCOL,CI_SERVER_REVISION:Bt.CI_SERVER_REVISION,CI_SERVER_SHELL_SSH_HOST:Bt.CI_SERVER_SHELL_SSH_HOST,CI_SERVER_SHELL_SSH_PORT:Bt.CI_SERVER_SHELL_SSH_PORT,CI_SERVER_URL:Bt.CI_SERVER_URL,CI_SERVER_VERSION:Bt.CI_SERVER_VERSION,CI_SERVER_VERSION_MAJOR:Bt.CI_SERVER_VERSION_MAJOR,CI_SERVER_VERSION_MINOR:Bt.CI_SERVER_VERSION_MINOR,CI_SERVER_VERSION_PATCH:Bt.CI_SERVER_VERSION_PATCH,CI_TEMPLATE_REGISTRY_HOST:Bt.CI_TEMPLATE_REGISTRY_HOST,GITLAB_CI:Bt.GITLAB_CI,GITLAB_FEATURES:Bt.GITLAB_FEATURES,GITLAB_USER_ID:Bt.GITLAB_USER_ID,GITLAB_USER_LOGIN:Bt.GITLAB_USER_LOGIN,RUNNER_GENERATE_ARTIFACTS_METADATA:Bt.RUNNER_GENERATE_ARTIFACTS_METADATA},environment:{name:Bt.CI_RUNNER_DESCRIPTION,architecture:Bt.CI_RUNNER_EXECUTABLE_ARCH,server:Bt.CI_SERVER_URL,project:Bt.CI_PROJECT_PATH,job:{id:Bt.CI_JOB_ID},pipeline:{id:Bt.CI_PIPELINE_ID,ref:Bt.CI_CONFIG_PATH}}},metadata:{buildInvocationId:`${Bt.CI_JOB_URL}`,completeness:{parameters:!0,environment:!0,materials:!1},reproducible:!1},materials:[{uri:`git+${Bt.CI_PROJECT_URL}`,digest:{sha1:Bt.CI_COMMIT_SHA}}]}}}else throw new jt(91,\"Provenance generation is only supported in GitHub Actions and GitLab CI\");return Oxe.attest(Buffer.from(JSON.stringify(r)),GDt,e)};async function XDt(t,e,{access:r,tag:s,registry:a,gitHead:n,provenance:c}){let f=t.manifest.name,p=t.manifest.version,h=G.stringifyIdent(f),E=Mxe.default.fromData(e,{algorithms:[\"sha1\",\"sha512\"]}),C=r??Uxe(t,f),S=await _xe(t),b=await yA.genPackageManifest(t),I=`${h}-${p}.tgz`,T=new URL(`${Jc(a)}/${h}/-/${I}`),N={[I]:{content_type:\"application/octet-stream\",data:e.toString(\"base64\"),length:e.length}};if(c){let U={name:`pkg:npm/${h.replace(/^@/,\"%40\")}@${p}`,digest:{sha512:E.sha512[0].hexDigest()}},W=await Lxe([U]),ee=JSON.stringify(W);N[`${h}-${p}.sigstore`]={content_type:W.mediaType,data:ee,length:ee.length}}return{_id:h,_attachments:N,name:h,access:C,\"dist-tags\":{[s]:p},versions:{[p]:{...b,_id:`${h}@${p}`,name:h,version:p,gitHead:n,dist:{shasum:E.sha1[0].hexDigest(),integrity:E.sha512[0].toString(),tarball:T.toString()}}},readme:S}}async function $Dt(t){try{let{stdout:e}=await qr.execvp(\"git\",[\"rev-parse\",\"--revs-only\",\"HEAD\"],{cwd:t});return e.trim()===\"\"?void 0:e.trim()}catch{return}}function Uxe(t,e){let r=t.project.configuration;return t.manifest.publishConfig&&typeof t.manifest.publishConfig.access==\"string\"?t.manifest.publishConfig.access:r.get(\"npmPublishAccess\")!==null?r.get(\"npmPublishAccess\"):e.scope?\"restricted\":\"public\"}async function _xe(t){let e=fe.toPortablePath(`${t.cwd}/README.md`),r=t.manifest.name,a=`# ${G.stringifyIdent(r)}\n`;try{a=await ce.readFilePromise(e,\"utf8\")}catch(n){if(n.code===\"ENOENT\")return a;throw n}return a}var DK={npmAlwaysAuth:{description:\"URL of the selected npm registry (note: npm enterprise isn't supported)\",type:\"BOOLEAN\",default:!1},npmAuthIdent:{description:\"Authentication identity for the npm registry (_auth in npm and yarn v1)\",type:\"SECRET\",default:null},npmAuthToken:{description:\"Authentication token for the npm registry (_authToken in npm and yarn v1)\",type:\"SECRET\",default:null}},Hxe={npmAuditRegistry:{description:\"Registry to query for audit reports\",type:\"STRING\",default:null},npmPublishRegistry:{description:\"Registry to push packages to\",type:\"STRING\",default:null},npmRegistryServer:{description:\"URL of the selected npm registry (note: npm enterprise isn't supported)\",type:\"STRING\",default:\"https://registry.yarnpkg.com\"}},ePt={npmMinimalAgeGate:{description:\"Minimum age of a package version according to the publish date on the npm registry in minutes to be considered for installation\",type:\"NUMBER\",default:0},npmPreapprovedPackages:{description:\"Array of package descriptors or package name glob patterns to exclude from the minimum release age check\",type:\"STRING\",isArray:!0,default:[]}},tPt={configuration:{...DK,...Hxe,...ePt,npmScopes:{description:\"Settings per package scope\",type:\"MAP\",valueDefinition:{description:\"\",type:\"SHAPE\",properties:{...DK,...Hxe}}},npmRegistries:{description:\"Settings per registry\",type:\"MAP\",normalizeKeys:Jc,valueDefinition:{description:\"\",type:\"SHAPE\",properties:{...DK}}}},fetchers:[VD,oh],resolvers:[JD,KD,zD]},rPt=tPt;var OK={};Vt(OK,{NpmAuditCommand:()=>D1,NpmInfoCommand:()=>P1,NpmLoginCommand:()=>b1,NpmLogoutCommand:()=>k1,NpmPublishCommand:()=>Q1,NpmTagAddCommand:()=>T1,NpmTagListCommand:()=>R1,NpmTagRemoveCommand:()=>F1,NpmWhoamiCommand:()=>N1,default:()=>cPt,npmAuditTypes:()=>KP,npmAuditUtils:()=>xL});Ge();Ge();Yt();var RK=ut(Go());Ul();var KP={};Vt(KP,{Environment:()=>VP,Severity:()=>JP});var VP=(s=>(s.All=\"all\",s.Production=\"production\",s.Development=\"development\",s))(VP||{}),JP=(n=>(n.Info=\"info\",n.Low=\"low\",n.Moderate=\"moderate\",n.High=\"high\",n.Critical=\"critical\",n))(JP||{});var xL={};Vt(xL,{allSeverities:()=>S1,getPackages:()=>QK,getReportTree:()=>xK,getSeverityInclusions:()=>bK,getTopLevelDependencies:()=>kK});Ge();var jxe=ut(Ai());var S1=[\"info\",\"low\",\"moderate\",\"high\",\"critical\"];function bK(t){if(typeof t>\"u\")return new Set(S1);let e=S1.indexOf(t),r=S1.slice(e);return new Set(r)}function xK(t){let e={},r={children:e};for(let[s,a]of je.sortMap(Object.entries(t),n=>n[0]))for(let n of je.sortMap(a,c=>`${c.id}`))e[`${s}/${n.id}`]={value:he.tuple(he.Type.IDENT,G.parseIdent(s)),children:{ID:typeof n.id<\"u\"&&{label:\"ID\",value:he.tuple(he.Type.ID,n.id)},Issue:{label:\"Issue\",value:he.tuple(he.Type.NO_HINT,n.title)},URL:typeof n.url<\"u\"&&{label:\"URL\",value:he.tuple(he.Type.URL,n.url)},Severity:{label:\"Severity\",value:he.tuple(he.Type.NO_HINT,n.severity)},\"Vulnerable Versions\":{label:\"Vulnerable Versions\",value:he.tuple(he.Type.RANGE,n.vulnerable_versions)},\"Tree Versions\":{label:\"Tree Versions\",children:[...n.versions].sort(jxe.default.compare).map(c=>({value:he.tuple(he.Type.REFERENCE,c)}))},Dependents:{label:\"Dependents\",children:je.sortMap(n.dependents,c=>G.stringifyLocator(c)).map(c=>({value:he.tuple(he.Type.LOCATOR,c)}))}}};return r}function kK(t,e,{all:r,environment:s}){let a=[],n=r?t.workspaces:[e],c=[\"all\",\"production\"].includes(s),f=[\"all\",\"development\"].includes(s);for(let p of n)for(let h of p.anchoredPackage.dependencies.values())(p.manifest.devDependencies.has(h.identHash)?!f:!c)||a.push({workspace:p,dependency:h});return a}function QK(t,e,{recursive:r}){let s=new Map,a=new Set,n=[],c=(f,p)=>{let h=t.storedResolutions.get(p.descriptorHash);if(typeof h>\"u\")throw new Error(\"Assertion failed: The resolution should have been registered\");if(!a.has(h))a.add(h);else return;let E=t.storedPackages.get(h);if(typeof E>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");if(G.ensureDevirtualizedLocator(E).reference.startsWith(\"npm:\")&&E.version!==null){let S=G.stringifyIdent(E),b=je.getMapWithDefault(s,S);je.getArrayWithDefault(b,E.version).push(f)}if(r)for(let S of E.dependencies.values())n.push([E,S])};for(let{workspace:f,dependency:p}of e)n.push([f.anchoredLocator,p]);for(;n.length>0;){let[f,p]=n.shift();c(f,p)}return s}var D1=class extends ft{constructor(){super(...arguments);this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Audit dependencies from all workspaces\"});this.recursive=ge.Boolean(\"-R,--recursive\",!1,{description:\"Audit transitive dependencies as well\"});this.environment=ge.String(\"--environment\",\"all\",{description:\"Which environments to cover\",validator:fo(VP)});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.noDeprecations=ge.Boolean(\"--no-deprecations\",!1,{description:\"Don't warn about deprecated packages\"});this.severity=ge.String(\"--severity\",\"info\",{description:\"Minimal severity requested for packages to be displayed\",validator:fo(JP)});this.excludes=ge.Array(\"--exclude\",[],{description:\"Array of glob patterns of packages to exclude from audit\"});this.ignores=ge.Array(\"--ignore\",[],{description:\"Array of glob patterns of advisory ID's to ignore in the audit report\"})}static{this.paths=[[\"npm\",\"audit\"]]}static{this.usage=ot.Usage({description:\"perform a vulnerability audit against the installed packages\",details:`\n      This command checks for known security reports on the packages you use. The reports are by default extracted from the npm registry, and may or may not be relevant to your actual program (not all vulnerabilities affect all code paths).\n\n      For consistency with our other commands the default is to only check the direct dependencies for the active workspace. To extend this search to all workspaces, use \\`-A,--all\\`. To extend this search to both direct and transitive dependencies, use \\`-R,--recursive\\`.\n\n      Applying the \\`--severity\\` flag will limit the audit table to vulnerabilities of the corresponding severity and above. Valid values are ${S1.map(r=>`\\`${r}\\``).join(\", \")}.\n\n      If the \\`--json\\` flag is set, Yarn will print the output exactly as received from the registry. Regardless of this flag, the process will exit with a non-zero exit code if a report is found for the selected packages.\n\n      If certain packages produce false positives for a particular environment, the \\`--exclude\\` flag can be used to exclude any number of packages from the audit. This can also be set in the configuration file with the \\`npmAuditExcludePackages\\` option.\n\n      If particular advisories are needed to be ignored, the \\`--ignore\\` flag can be used with Advisory ID's to ignore any number of advisories in the audit report. This can also be set in the configuration file with the \\`npmAuditIgnoreAdvisories\\` option.\n\n      To understand the dependency tree requiring vulnerable packages, check the raw report with the \\`--json\\` flag or use \\`yarn why package\\` to get more information as to who depends on them.\n    `,examples:[[\"Checks for known security issues with the installed packages. The output is a list of known issues.\",\"yarn npm audit\"],[\"Audit dependencies in all workspaces\",\"yarn npm audit --all\"],[\"Limit auditing to `dependencies` (excludes `devDependencies`)\",\"yarn npm audit --environment production\"],[\"Show audit report as valid JSON\",\"yarn npm audit --json\"],[\"Audit all direct and transitive dependencies\",\"yarn npm audit --recursive\"],[\"Output moderate (or more severe) vulnerabilities\",\"yarn npm audit --severity moderate\"],[\"Exclude certain packages\",\"yarn npm audit --exclude package1 --exclude package2\"],[\"Ignore specific advisories\",\"yarn npm audit --ignore 1234567 --ignore 7654321\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState();let n=kK(s,a,{all:this.all,environment:this.environment}),c=QK(s,n,{recursive:this.recursive}),f=Array.from(new Set([...r.get(\"npmAuditExcludePackages\"),...this.excludes])),p=Object.create(null);for(let[N,U]of c)f.some(W=>RK.default.isMatch(N,W))||(p[N]=[...U.keys()]);let h=hi.getAuditRegistry({configuration:r}),E,C=await lA.start({configuration:r,stdout:this.context.stdout},async()=>{let N=an.post(\"/-/npm/v1/security/advisories/bulk\",p,{authType:an.AuthType.BEST_EFFORT,configuration:r,jsonResponse:!0,registry:h}),U=this.noDeprecations?[]:await Promise.all(Array.from(Object.entries(p),async([ee,ie])=>{let ue=await an.getPackageMetadata(G.parseIdent(ee),{project:s});return je.mapAndFilter(ie,le=>{let{deprecated:me}=ue.versions[le];return me?[ee,le,me]:je.mapAndFilter.skip})})),W=await N;for(let[ee,ie,ue]of U.flat(1))Object.hasOwn(W,ee)&&W[ee].some(le=>Fr.satisfiesWithPrereleases(ie,le.vulnerable_versions))||(W[ee]??=[],W[ee].push({id:`${ee} (deprecation)`,title:(typeof ue==\"string\"?ue:\"\").trim()||\"This package has been deprecated.\",severity:\"moderate\",vulnerable_versions:ie}));E=W});if(C.hasErrors())return C.exitCode();let S=bK(this.severity),b=Array.from(new Set([...r.get(\"npmAuditIgnoreAdvisories\"),...this.ignores])),I=Object.create(null);for(let[N,U]of Object.entries(E)){let W=U.filter(ee=>!RK.default.isMatch(`${ee.id}`,b)&&S.has(ee.severity));W.length>0&&(I[N]=W.map(ee=>{let ie=c.get(N);if(typeof ie>\"u\")throw new Error(\"Assertion failed: Expected the registry to only return packages that were requested\");let ue=[...ie.keys()].filter(me=>Fr.satisfiesWithPrereleases(me,ee.vulnerable_versions)),le=new Map;for(let me of ue)for(let pe of ie.get(me))le.set(pe.locatorHash,pe);return{...ee,versions:ue,dependents:[...le.values()]}}))}let T=Object.keys(I).length>0;return T?(xs.emitTree(xK(I),{configuration:r,json:this.json,stdout:this.context.stdout,separators:2}),1):(await Ot.start({configuration:r,includeFooter:!1,json:this.json,stdout:this.context.stdout},async N=>{N.reportInfo(1,\"No audit suggestions\")}),T?1:0)}};Ge();Ge();Dt();Yt();var TK=ut(Ai()),FK=Ie(\"util\"),P1=class extends ft{constructor(){super(...arguments);this.fields=ge.String(\"-f,--fields\",{description:\"A comma-separated list of manifest fields that should be displayed\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.packages=ge.Rest()}static{this.paths=[[\"npm\",\"info\"]]}static{this.usage=ot.Usage({category:\"Npm-related commands\",description:\"show information about a package\",details:\"\\n      This command fetches information about a package from the npm registry and prints it in a tree format.\\n\\n      The package does not have to be installed locally, but needs to have been published (in particular, local changes will be ignored even for workspaces).\\n\\n      Append `@<range>` to the package argument to provide information specific to the latest version that satisfies the range or to the corresponding tagged version. If the range is invalid or if there is no version satisfying the range, the command will print a warning and fall back to the latest version.\\n\\n      If the `-f,--fields` option is set, it's a comma-separated list of fields which will be used to only display part of the package information.\\n\\n      By default, this command won't return the `dist`, `readme`, and `users` fields, since they are often very long. To explicitly request those fields, explicitly list them with the `--fields` flag or request the output in JSON mode.\\n    \",examples:[[\"Show all available information about react (except the `dist`, `readme`, and `users` fields)\",\"yarn npm info react\"],[\"Show all available information about react as valid JSON (including the `dist`, `readme`, and `users` fields)\",\"yarn npm info react --json\"],[\"Show all available information about react@16.12.0\",\"yarn npm info react@16.12.0\"],[\"Show all available information about react@next\",\"yarn npm info react@next\"],[\"Show the description of react\",\"yarn npm info react --fields description\"],[\"Show all available versions of react\",\"yarn npm info react --fields versions\"],[\"Show the readme of react\",\"yarn npm info react --fields readme\"],[\"Show a few fields of react\",\"yarn npm info react --fields homepage,repository\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Rt.find(r,this.context.cwd),a=typeof this.fields<\"u\"?new Set([\"name\",...this.fields.split(/\\s*,\\s*/)]):null,n=[],c=!1,f=await Ot.start({configuration:r,includeFooter:!1,json:this.json,stdout:this.context.stdout},async p=>{for(let h of this.packages){let E;if(h===\".\"){let ie=s.topLevelWorkspace;if(!ie.manifest.name)throw new nt(`Missing ${he.pretty(r,\"name\",he.Type.CODE)} field in ${fe.fromPortablePath(J.join(ie.cwd,Er.manifest))}`);E=G.makeDescriptor(ie.manifest.name,\"unknown\")}else E=G.parseDescriptor(h);let C=an.getIdentUrl(E),S=NK(await an.get(C,{configuration:r,ident:E,jsonResponse:!0,customErrorMessage:an.customPackageError})),b=Object.keys(S.versions).sort(TK.default.compareLoose),T=S[\"dist-tags\"].latest||b[b.length-1],N=Fr.validRange(E.range);if(N){let ie=TK.default.maxSatisfying(b,N);ie!==null?T=ie:(p.reportWarning(0,`Unmet range ${G.prettyRange(r,E.range)}; falling back to the latest version`),c=!0)}else Object.hasOwn(S[\"dist-tags\"],E.range)?T=S[\"dist-tags\"][E.range]:E.range!==\"unknown\"&&(p.reportWarning(0,`Unknown tag ${G.prettyRange(r,E.range)}; falling back to the latest version`),c=!0);let U=S.versions[T],W={...S,...U,version:T,versions:b},ee;if(a!==null){ee={};for(let ie of a){let ue=W[ie];if(typeof ue<\"u\")ee[ie]=ue;else{p.reportWarning(1,`The ${he.pretty(r,ie,he.Type.CODE)} field doesn't exist inside ${G.prettyIdent(r,E)}'s information`),c=!0;continue}}}else this.json||(delete W.dist,delete W.readme,delete W.users),ee=W;p.reportJson(ee),this.json||n.push(ee)}});FK.inspect.styles.name=\"cyan\";for(let p of n)(p!==n[0]||c)&&this.context.stdout.write(`\n`),this.context.stdout.write(`${(0,FK.inspect)(p,{depth:1/0,colors:!0,compact:!1})}\n`);return f.exitCode()}};function NK(t){if(Array.isArray(t)){let e=[];for(let r of t)r=NK(r),r&&e.push(r);return e}else if(typeof t==\"object\"&&t!==null){let e={};for(let r of Object.keys(t)){if(r.startsWith(\"_\"))continue;let s=NK(t[r]);s&&(e[r]=s)}return e}else return t||null}Ge();Ge();Yt();var Gxe=ut(Vv()),b1=class extends ft{constructor(){super(...arguments);this.scope=ge.String(\"-s,--scope\",{description:\"Login to the registry configured for a given scope\"});this.publish=ge.Boolean(\"--publish\",!1,{description:\"Login to the publish registry\"});this.alwaysAuth=ge.Boolean(\"--always-auth\",{description:\"Set the npmAlwaysAuth configuration\"})}static{this.paths=[[\"npm\",\"login\"]]}static{this.usage=ot.Usage({category:\"Npm-related commands\",description:\"store new login info to access the npm registry\",details:\"\\n      This command will ask you for your username, password, and 2FA One-Time-Password (when it applies). It will then modify your local configuration (in your home folder, never in the project itself) to reference the new tokens thus generated.\\n\\n      Adding the `-s,--scope` flag will cause the authentication to be done against whatever registry is configured for the associated scope (see also `npmScopes`).\\n\\n      Adding the `--publish` flag will cause the authentication to be done against the registry used when publishing the package (see also `publishConfig.registry` and `npmPublishRegistry`).\\n    \",examples:[[\"Login to the default registry\",\"yarn npm login\"],[\"Login to the registry linked to the @my-scope registry\",\"yarn npm login --scope my-scope\"],[\"Login to the publish registry for the current package\",\"yarn npm login --publish\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=await kL({configuration:r,cwd:this.context.cwd,publish:this.publish,scope:this.scope});return(await Ot.start({configuration:r,stdout:this.context.stdout,includeFooter:!1},async n=>{let c=await sPt({configuration:r,registry:s,report:n,stdin:this.context.stdin,stdout:this.context.stdout}),f=await nPt(s,c,r);return await iPt(s,f,{alwaysAuth:this.alwaysAuth,scope:this.scope}),n.reportInfo(0,\"Successfully logged in\")})).exitCode()}};async function kL({scope:t,publish:e,configuration:r,cwd:s}){return t&&e?hi.getScopeRegistry(t,{configuration:r,type:hi.RegistryType.PUBLISH_REGISTRY}):t?hi.getScopeRegistry(t,{configuration:r}):e?hi.getPublishRegistry((await eC(r,s)).manifest,{configuration:r}):hi.getDefaultRegistry({configuration:r})}async function nPt(t,e,r){let s=`/-/user/org.couchdb.user:${encodeURIComponent(e.name)}`,a={_id:`org.couchdb.user:${e.name}`,name:e.name,password:e.password,type:\"user\",roles:[],date:new Date().toISOString()},n={attemptedAs:e.name,configuration:r,registry:t,jsonResponse:!0,authType:an.AuthType.NO_AUTH};try{return(await an.put(s,a,n)).token}catch(E){if(!(E.originalError?.name===\"HTTPError\"&&E.originalError?.response.statusCode===409))throw E}let c={...n,authType:an.AuthType.NO_AUTH,headers:{authorization:`Basic ${Buffer.from(`${e.name}:${e.password}`).toString(\"base64\")}`}},f=await an.get(s,c);for(let[E,C]of Object.entries(f))(!a[E]||E===\"roles\")&&(a[E]=C);let p=`${s}/-rev/${a._rev}`;return(await an.put(p,a,c)).token}async function iPt(t,e,{alwaysAuth:r,scope:s}){let a=c=>f=>{let p=je.isIndexableObject(f)?f:{},h=p[c],E=je.isIndexableObject(h)?h:{};return{...p,[c]:{...E,...r!==void 0?{npmAlwaysAuth:r}:{},npmAuthToken:e}}},n=s?{npmScopes:a(s)}:{npmRegistries:a(t)};return await ze.updateHomeConfiguration(n)}async function sPt({configuration:t,registry:e,report:r,stdin:s,stdout:a}){r.reportInfo(0,`Logging in to ${he.pretty(t,e,he.Type.URL)}`);let n=!1;if(e.match(/^https:\\/\\/npm\\.pkg\\.github\\.com(\\/|$)/)&&(r.reportInfo(0,\"You seem to be using the GitHub Package Registry. Tokens must be generated with the 'repo', 'write:packages', and 'read:packages' permissions.\"),n=!0),r.reportSeparator(),t.env.YARN_IS_TEST_ENV)return{name:t.env.YARN_INJECT_NPM_USER||\"\",password:t.env.YARN_INJECT_NPM_PASSWORD||\"\"};let c=await(0,Gxe.prompt)([{type:\"input\",name:\"name\",message:\"Username:\",required:!0,onCancel:()=>process.exit(130),stdin:s,stdout:a},{type:\"password\",name:\"password\",message:n?\"Token:\":\"Password:\",required:!0,onCancel:()=>process.exit(130),stdin:s,stdout:a}]);return r.reportSeparator(),c}Ge();Ge();Yt();var x1=new Set([\"npmAuthIdent\",\"npmAuthToken\"]),k1=class extends ft{constructor(){super(...arguments);this.scope=ge.String(\"-s,--scope\",{description:\"Logout of the registry configured for a given scope\"});this.publish=ge.Boolean(\"--publish\",!1,{description:\"Logout of the publish registry\"});this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Logout of all registries\"})}static{this.paths=[[\"npm\",\"logout\"]]}static{this.usage=ot.Usage({category:\"Npm-related commands\",description:\"logout of the npm registry\",details:\"\\n      This command will log you out by modifying your local configuration (in your home folder, never in the project itself) to delete all credentials linked to a registry.\\n\\n      Adding the `-s,--scope` flag will cause the deletion to be done against whatever registry is configured for the associated scope (see also `npmScopes`).\\n\\n      Adding the `--publish` flag will cause the deletion to be done against the registry used when publishing the package (see also `publishConfig.registry` and `npmPublishRegistry`).\\n\\n      Adding the `-A,--all` flag will cause the deletion to be done against all registries and scopes.\\n    \",examples:[[\"Logout of the default registry\",\"yarn npm logout\"],[\"Logout of the @my-scope scope\",\"yarn npm logout --scope my-scope\"],[\"Logout of the publish registry for the current package\",\"yarn npm logout --publish\"],[\"Logout of all registries\",\"yarn npm logout --all\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s=async()=>{let n=await kL({configuration:r,cwd:this.context.cwd,publish:this.publish,scope:this.scope}),c=await ze.find(this.context.cwd,this.context.plugins),f=G.makeIdent(this.scope??null,\"pkg\");return!hi.getAuthConfiguration(n,{configuration:c,ident:f}).get(\"npmAuthToken\")};return(await Ot.start({configuration:r,stdout:this.context.stdout},async n=>{if(this.all&&(await aPt(),n.reportInfo(0,\"Successfully logged out from everything\")),this.scope){await qxe(\"npmScopes\",this.scope),await s()?n.reportInfo(0,`Successfully logged out from ${this.scope}`):n.reportWarning(0,\"Scope authentication settings removed, but some other ones settings still apply to it\");return}let c=await kL({configuration:r,cwd:this.context.cwd,publish:this.publish});await qxe(\"npmRegistries\",c),await s()?n.reportInfo(0,`Successfully logged out from ${c}`):n.reportWarning(0,\"Registry authentication settings removed, but some other ones settings still apply to it\")})).exitCode()}};function oPt(t,e){let r=t[e];if(!je.isIndexableObject(r))return!1;let s=new Set(Object.keys(r));if([...x1].every(n=>!s.has(n)))return!1;for(let n of x1)s.delete(n);if(s.size===0)return t[e]=void 0,!0;let a={...r};for(let n of x1)delete a[n];return t[e]=a,!0}async function aPt(){let t=e=>{let r=!1,s=je.isIndexableObject(e)?{...e}:{};s.npmAuthToken&&(delete s.npmAuthToken,r=!0);for(let a of Object.keys(s))oPt(s,a)&&(r=!0);if(Object.keys(s).length!==0)return r?s:e};return await ze.updateHomeConfiguration({npmRegistries:t,npmScopes:t})}async function qxe(t,e){return await ze.updateHomeConfiguration({[t]:r=>{let s=je.isIndexableObject(r)?r:{};if(!Object.hasOwn(s,e))return r;let a=s[e],n=je.isIndexableObject(a)?a:{},c=new Set(Object.keys(n));if([...x1].every(p=>!c.has(p)))return r;for(let p of x1)c.delete(p);if(c.size===0)return Object.keys(s).length===1?void 0:{...s,[e]:void 0};let f={};for(let p of x1)f[p]=void 0;return{...s,[e]:{...n,...f}}}})}Ge();Dt();Yt();var Q1=class extends ft{constructor(){super(...arguments);this.access=ge.String(\"--access\",{description:\"The access for the published package (public or restricted)\"});this.tag=ge.String(\"--tag\",\"latest\",{description:\"The tag on the registry that the package should be attached to\"});this.tolerateRepublish=ge.Boolean(\"--tolerate-republish\",!1,{description:\"Warn and exit when republishing an already existing version of a package\"});this.otp=ge.String(\"--otp\",{description:\"The OTP token to use with the command\"});this.provenance=ge.Boolean(\"--provenance\",!1,{description:\"Generate provenance for the package. Only available in GitHub Actions and GitLab CI. Can be set globally through the `npmPublishProvenance` setting or the `YARN_NPM_CONFIG_PROVENANCE` environment variable, or per-package through the `publishConfig.provenance` field in package.json.\"});this.dryRun=ge.Boolean(\"-n,--dry-run\",!1,{description:\"Show what would be published without actually publishing\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Output the result in JSON format\"})}static{this.paths=[[\"npm\",\"publish\"]]}static{this.usage=ot.Usage({category:\"Npm-related commands\",description:\"publish the active workspace to the npm registry\",details:'\\n      This command will pack the active workspace into a fresh archive and upload it to the npm registry.\\n\\n      The package will by default be attached to the `latest` tag on the registry, but this behavior can be overridden by using the `--tag` option.\\n\\n      Note that for legacy reasons scoped packages are by default published with an access set to `restricted` (aka \"private packages\"). This requires you to register for a paid npm plan. In case you simply wish to publish a public scoped package to the registry (for free), just add the `--access public` flag. This behavior can be enabled by default through the `npmPublishAccess` settings.\\n    ',examples:[[\"Publish the active workspace\",\"yarn npm publish\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);if(a.manifest.private)throw new nt(\"Private workspaces cannot be published\");if(a.manifest.name===null||a.manifest.version===null)throw new nt(\"Workspaces must have valid names and versions to be published on an external registry\");await s.restoreInstallState();let n=a.manifest.name,c=a.manifest.version,f=hi.getPublishRegistry(a.manifest,{configuration:r});return(await Ot.start({configuration:r,stdout:this.context.stdout,json:this.json},async h=>{if(this.tolerateRepublish)try{let E=await an.get(an.getIdentUrl(n),{configuration:r,registry:f,ident:n,jsonResponse:!0});if(!Object.hasOwn(E,\"versions\"))throw new jt(15,'Registry returned invalid data for - missing \"versions\" field');if(Object.hasOwn(E.versions,c)){let C=`Registry already knows about version ${c}; skipping.`;h.reportWarning(0,C),h.reportJson({name:n.name,version:c,registry:f,warning:C,skipped:!0});return}}catch(E){if(E.originalError?.response?.statusCode!==404)throw E}await In.maybeExecuteWorkspaceLifecycleScript(a,\"prepublish\",{report:h}),await yA.prepareForPack(a,{report:h},async()=>{let E=await yA.genPackList(a);for(let W of E)h.reportInfo(null,fe.fromPortablePath(W)),h.reportJson({file:fe.fromPortablePath(W)});let C=await yA.genPackStream(a,E),S=await je.bufferStream(C),b=await v1.getGitHead(a.cwd),I=!1,T=\"\";a.manifest.publishConfig&&\"provenance\"in a.manifest.publishConfig?(I=!!a.manifest.publishConfig.provenance,T=I?\"Generating provenance statement because `publishConfig.provenance` field is set.\":\"Skipping provenance statement because `publishConfig.provenance` field is set to false.\"):this.provenance?(I=!0,T=\"Generating provenance statement because `--provenance` flag is set.\"):r.get(\"npmPublishProvenance\")&&(I=!0,T=\"Generating provenance statement because `npmPublishProvenance` setting is set.\"),T&&(h.reportInfo(null,T),h.reportJson({type:\"provenance\",enabled:I,provenanceMessage:T}));let N=await v1.makePublishBody(a,S,{access:this.access,tag:this.tag,registry:f,gitHead:b,provenance:I});this.dryRun||await an.put(an.getIdentUrl(n),N,{configuration:r,registry:f,ident:n,otp:this.otp,jsonResponse:!0,allowOidc:!!(process.env.CI&&(process.env.GITHUB_ACTIONS||process.env.GITLAB))});let U=this.dryRun?`[DRY RUN] Package would be published to ${f} with tag ${this.tag}`:\"Package archive published\";h.reportInfo(0,U),h.reportJson({name:n.name,version:c,registry:f,tag:this.tag||\"latest\",files:E.map(W=>fe.fromPortablePath(W)),access:this.access||null,dryRun:this.dryRun,published:!this.dryRun,message:U,provenance:!!I})})})).exitCode()}};Ge();Yt();var Wxe=ut(Ai());Ge();Dt();Yt();var R1=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.package=ge.String({required:!1})}static{this.paths=[[\"npm\",\"tag\",\"list\"]]}static{this.usage=ot.Usage({category:\"Npm-related commands\",description:\"list all dist-tags of a package\",details:`\n      This command will list all tags of a package from the npm registry.\n\n      If the package is not specified, Yarn will default to the current workspace.\n    `,examples:[[\"List all tags of package `my-pkg`\",\"yarn npm tag list my-pkg\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n;if(typeof this.package<\"u\")n=G.parseIdent(this.package);else{if(!a)throw new ar(s.cwd,this.context.cwd);if(!a.manifest.name)throw new nt(`Missing 'name' field in ${fe.fromPortablePath(J.join(a.cwd,Er.manifest))}`);n=a.manifest.name}let c=await zP(n,r),p={children:je.sortMap(Object.entries(c),([h])=>h).map(([h,E])=>({value:he.tuple(he.Type.RESOLUTION,{descriptor:G.makeDescriptor(n,h),locator:G.makeLocator(n,E)})}))};return xs.emitTree(p,{configuration:r,json:this.json,stdout:this.context.stdout})}};async function zP(t,e){let r=`/-/package${an.getIdentUrl(t)}/dist-tags`;return an.get(r,{configuration:e,ident:t,jsonResponse:!0,customErrorMessage:an.customPackageError})}var T1=class extends ft{constructor(){super(...arguments);this.package=ge.String();this.tag=ge.String()}static{this.paths=[[\"npm\",\"tag\",\"add\"]]}static{this.usage=ot.Usage({category:\"Npm-related commands\",description:\"add a tag for a specific version of a package\",details:`\n      This command will add a tag to the npm registry for a specific version of a package. If the tag already exists, it will be overwritten.\n    `,examples:[[\"Add a `beta` tag for version `2.3.4-beta.4` of package `my-pkg`\",\"yarn npm tag add my-pkg@2.3.4-beta.4 beta\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);let n=G.parseDescriptor(this.package,!0),c=n.range;if(!Wxe.default.valid(c))throw new nt(`The range ${he.pretty(r,n.range,he.Type.RANGE)} must be a valid semver version`);let f=hi.getPublishRegistry(a.manifest,{configuration:r}),p=he.pretty(r,n,he.Type.IDENT),h=he.pretty(r,c,he.Type.RANGE),E=he.pretty(r,this.tag,he.Type.CODE);return(await Ot.start({configuration:r,stdout:this.context.stdout},async S=>{let b=await zP(n,r);Object.hasOwn(b,this.tag)&&b[this.tag]===c&&S.reportWarning(0,`Tag ${E} is already set to version ${h}`);let I=`/-/package${an.getIdentUrl(n)}/dist-tags/${encodeURIComponent(this.tag)}`;await an.put(I,c,{configuration:r,registry:f,ident:n,jsonRequest:!0,jsonResponse:!0}),S.reportInfo(0,`Tag ${E} added to version ${h} of package ${p}`)})).exitCode()}};Ge();Yt();var F1=class extends ft{constructor(){super(...arguments);this.package=ge.String();this.tag=ge.String()}static{this.paths=[[\"npm\",\"tag\",\"remove\"]]}static{this.usage=ot.Usage({category:\"Npm-related commands\",description:\"remove a tag from a package\",details:`\n      This command will remove a tag from a package from the npm registry.\n    `,examples:[[\"Remove the `beta` tag from package `my-pkg`\",\"yarn npm tag remove my-pkg beta\"]]})}async execute(){if(this.tag===\"latest\")throw new nt(\"The 'latest' tag cannot be removed.\");let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);let n=G.parseIdent(this.package),c=hi.getPublishRegistry(a.manifest,{configuration:r}),f=he.pretty(r,this.tag,he.Type.CODE),p=he.pretty(r,n,he.Type.IDENT),h=await zP(n,r);if(!Object.hasOwn(h,this.tag))throw new nt(`${f} is not a tag of package ${p}`);return(await Ot.start({configuration:r,stdout:this.context.stdout},async C=>{let S=`/-/package${an.getIdentUrl(n)}/dist-tags/${encodeURIComponent(this.tag)}`;await an.del(S,{configuration:r,registry:c,ident:n,jsonResponse:!0}),C.reportInfo(0,`Tag ${f} removed from package ${p}`)})).exitCode()}};Ge();Ge();Yt();var N1=class extends ft{constructor(){super(...arguments);this.scope=ge.String(\"-s,--scope\",{description:\"Print username for the registry configured for a given scope\"});this.publish=ge.Boolean(\"--publish\",!1,{description:\"Print username for the publish registry\"})}static{this.paths=[[\"npm\",\"whoami\"]]}static{this.usage=ot.Usage({category:\"Npm-related commands\",description:\"display the name of the authenticated user\",details:\"\\n      Print the username associated with the current authentication settings to the standard output.\\n\\n      When using `-s,--scope`, the username printed will be the one that matches the authentication settings of the registry associated with the given scope (those settings can be overriden using the `npmRegistries` map, and the registry associated with the scope is configured via the `npmScopes` map).\\n\\n      When using `--publish`, the registry we'll select will by default be the one used when publishing packages (`publishConfig.registry` or `npmPublishRegistry` if available, otherwise we'll fallback to the regular `npmRegistryServer`).\\n    \",examples:[[\"Print username for the default registry\",\"yarn npm whoami\"],[\"Print username for the registry on a given scope\",\"yarn npm whoami --scope company\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),s;return this.scope&&this.publish?s=hi.getScopeRegistry(this.scope,{configuration:r,type:hi.RegistryType.PUBLISH_REGISTRY}):this.scope?s=hi.getScopeRegistry(this.scope,{configuration:r}):this.publish?s=hi.getPublishRegistry((await eC(r,this.context.cwd)).manifest,{configuration:r}):s=hi.getDefaultRegistry({configuration:r}),(await Ot.start({configuration:r,stdout:this.context.stdout},async n=>{let c;try{c=await an.get(\"/-/whoami\",{configuration:r,registry:s,authType:an.AuthType.ALWAYS_AUTH,jsonResponse:!0,ident:this.scope?G.makeIdent(this.scope,\"\"):void 0})}catch(f){if(f.response?.statusCode===401||f.response?.statusCode===403){n.reportError(41,\"Authentication failed - your credentials may have expired\");return}else throw f}n.reportInfo(0,c.username)})).exitCode()}};var lPt={configuration:{npmPublishAccess:{description:\"Default access of the published packages\",type:\"STRING\",default:null},npmPublishProvenance:{description:\"Whether to generate provenance for the published packages\",type:\"BOOLEAN\",default:!1},npmAuditExcludePackages:{description:\"Array of glob patterns of packages to exclude from npm audit\",type:\"STRING\",default:[],isArray:!0},npmAuditIgnoreAdvisories:{description:\"Array of glob patterns of advisory IDs to exclude from npm audit\",type:\"STRING\",default:[],isArray:!0}},commands:[D1,P1,b1,k1,Q1,T1,R1,F1,N1]},cPt=lPt;var GK={};Vt(GK,{PatchCommand:()=>H1,PatchCommitCommand:()=>_1,PatchFetcher:()=>tb,PatchResolver:()=>rb,default:()=>PPt,patchUtils:()=>gy});Ge();Ge();Dt();eA();var gy={};Vt(gy,{applyPatchFile:()=>RL,diffFolders:()=>HK,ensureUnpatchedDescriptor:()=>LK,ensureUnpatchedLocator:()=>FL,extractPackageToDisk:()=>_K,extractPatchFlags:()=>Xxe,isParentRequired:()=>UK,isPatchDescriptor:()=>TL,isPatchLocator:()=>Tg,loadPatchFiles:()=>eb,makeDescriptor:()=>NL,makeLocator:()=>MK,makePatchHash:()=>jK,parseDescriptor:()=>XP,parseLocator:()=>$P,parsePatchFile:()=>ZP,unpatchDescriptor:()=>vPt,unpatchLocator:()=>SPt});Ge();Dt();Ge();Dt();var uPt=/^@@ -(\\d+)(,(\\d+))? \\+(\\d+)(,(\\d+))? @@.*/;function O1(t){return J.relative(vt.root,J.resolve(vt.root,fe.toPortablePath(t)))}function fPt(t){let e=t.trim().match(uPt);if(!e)throw new Error(`Bad header line: '${t}'`);return{original:{start:Math.max(Number(e[1]),1),length:Number(e[3]||1)},patched:{start:Math.max(Number(e[4]),1),length:Number(e[6]||1)}}}var APt=420,pPt=493;var Yxe=()=>({semverExclusivity:null,diffLineFromPath:null,diffLineToPath:null,oldMode:null,newMode:null,deletedFileMode:null,newFileMode:null,renameFrom:null,renameTo:null,beforeHash:null,afterHash:null,fromPath:null,toPath:null,hunks:null}),hPt=t=>({header:fPt(t),parts:[]}),gPt={\"@\":\"header\",\"-\":\"deletion\",\"+\":\"insertion\",\" \":\"context\",\"\\\\\":\"pragma\",undefined:\"context\"};function dPt(t){let e=[],r=Yxe(),s=\"parsing header\",a=null,n=null;function c(){a&&(n&&(a.parts.push(n),n=null),r.hunks.push(a),a=null)}function f(){c(),e.push(r),r=Yxe()}for(let p=0;p<t.length;p++){let h=t[p];if(s===\"parsing header\")if(h.startsWith(\"@@\"))s=\"parsing hunks\",r.hunks=[],p-=1;else if(h.startsWith(\"diff --git \")){r&&r.diffLineFromPath&&f();let E=h.match(/^diff --git a\\/(.*?) b\\/(.*?)\\s*$/);if(!E)throw new Error(`Bad diff line: ${h}`);r.diffLineFromPath=E[1],r.diffLineToPath=E[2]}else if(h.startsWith(\"old mode \"))r.oldMode=h.slice(9).trim();else if(h.startsWith(\"new mode \"))r.newMode=h.slice(9).trim();else if(h.startsWith(\"deleted file mode \"))r.deletedFileMode=h.slice(18).trim();else if(h.startsWith(\"new file mode \"))r.newFileMode=h.slice(14).trim();else if(h.startsWith(\"rename from \"))r.renameFrom=h.slice(12).trim();else if(h.startsWith(\"rename to \"))r.renameTo=h.slice(10).trim();else if(h.startsWith(\"index \")){let E=h.match(/(\\w+)\\.\\.(\\w+)/);if(!E)continue;r.beforeHash=E[1],r.afterHash=E[2]}else h.startsWith(\"semver exclusivity \")?r.semverExclusivity=h.slice(19).trim():h.startsWith(\"--- \")?r.fromPath=h.slice(6).trim():h.startsWith(\"+++ \")&&(r.toPath=h.slice(6).trim());else{let E=gPt[h[0]]||null;switch(E){case\"header\":c(),a=hPt(h);break;case null:s=\"parsing header\",f(),p-=1;break;case\"pragma\":{if(!h.startsWith(\"\\\\ No newline at end of file\"))throw new Error(`Unrecognized pragma in patch file: ${h}`);if(!n)throw new Error(\"Bad parser state: No newline at EOF pragma encountered without context\");n.noNewlineAtEndOfFile=!0}break;case\"context\":case\"deletion\":case\"insertion\":{if(!a)throw new Error(\"Bad parser state: Hunk lines encountered before hunk header\");n&&n.type!==E&&(a.parts.push(n),n=null),n||(n={type:E,lines:[],noNewlineAtEndOfFile:!1}),n.lines.push(h.slice(1))}break;default:je.assertNever(E);break}}}f();for(let{hunks:p}of e)if(p)for(let h of p)yPt(h);return e}function mPt(t){let e=[];for(let r of t){let{semverExclusivity:s,diffLineFromPath:a,diffLineToPath:n,oldMode:c,newMode:f,deletedFileMode:p,newFileMode:h,renameFrom:E,renameTo:C,beforeHash:S,afterHash:b,fromPath:I,toPath:T,hunks:N}=r,U=E?\"rename\":p?\"file deletion\":h?\"file creation\":N&&N.length>0?\"patch\":\"mode change\",W=null;switch(U){case\"rename\":{if(!E||!C)throw new Error(\"Bad parser state: rename from & to not given\");e.push({type:\"rename\",semverExclusivity:s,fromPath:O1(E),toPath:O1(C)}),W=C}break;case\"file deletion\":{let ee=a||I;if(!ee)throw new Error(\"Bad parse state: no path given for file deletion\");e.push({type:\"file deletion\",semverExclusivity:s,hunk:N&&N[0]||null,path:O1(ee),mode:QL(p),hash:S})}break;case\"file creation\":{let ee=n||T;if(!ee)throw new Error(\"Bad parse state: no path given for file creation\");e.push({type:\"file creation\",semverExclusivity:s,hunk:N&&N[0]||null,path:O1(ee),mode:QL(h),hash:b})}break;case\"patch\":case\"mode change\":W=T||n;break;default:je.assertNever(U);break}W&&c&&f&&c!==f&&e.push({type:\"mode change\",semverExclusivity:s,path:O1(W),oldMode:QL(c),newMode:QL(f)}),W&&N&&N.length&&e.push({type:\"patch\",semverExclusivity:s,path:O1(W),hunks:N,beforeHash:S,afterHash:b})}if(e.length===0)throw new Error(\"Unable to parse patch file: No changes found. Make sure the patch is a valid UTF8 encoded string\");return e}function QL(t){let e=parseInt(t,8)&511;if(e!==APt&&e!==pPt)throw new Error(`Unexpected file mode string: ${t}`);return e}function ZP(t){let e=t.split(/\\n/g);return e[e.length-1]===\"\"&&e.pop(),mPt(dPt(e))}function yPt(t){let e=0,r=0;for(let{type:s,lines:a}of t.parts)switch(s){case\"context\":r+=a.length,e+=a.length;break;case\"deletion\":e+=a.length;break;case\"insertion\":r+=a.length;break;default:je.assertNever(s);break}if(e!==t.header.original.length||r!==t.header.patched.length){let s=a=>a<0?a:`+${a}`;throw new Error(`hunk header integrity check failed (expected @@ ${s(t.header.original.length)} ${s(t.header.patched.length)} @@, got @@ ${s(e)} ${s(r)} @@)`)}}Ge();Dt();var L1=class extends Error{constructor(r,s){super(`Cannot apply hunk #${r+1}`);this.hunk=s}};async function M1(t,e,r){let s=await t.lstatPromise(e),a=await r();typeof a<\"u\"&&(e=a),await t.lutimesPromise(e,s.atime,s.mtime)}async function RL(t,{baseFs:e=new Yn,dryRun:r=!1,version:s=null}={}){for(let a of t)if(!(a.semverExclusivity!==null&&s!==null&&!Fr.satisfiesWithPrereleases(s,a.semverExclusivity)))switch(a.type){case\"file deletion\":if(r){if(!e.existsSync(a.path))throw new Error(`Trying to delete a file that doesn't exist: ${a.path}`)}else await M1(e,J.dirname(a.path),async()=>{await e.unlinkPromise(a.path)});break;case\"rename\":if(r){if(!e.existsSync(a.fromPath))throw new Error(`Trying to move a file that doesn't exist: ${a.fromPath}`)}else await M1(e,J.dirname(a.fromPath),async()=>{await M1(e,J.dirname(a.toPath),async()=>{await M1(e,a.fromPath,async()=>(await e.movePromise(a.fromPath,a.toPath),a.toPath))})});break;case\"file creation\":if(r){if(e.existsSync(a.path))throw new Error(`Trying to create a file that already exists: ${a.path}`)}else{let n=a.hunk?a.hunk.parts[0].lines.join(`\n`)+(a.hunk.parts[0].noNewlineAtEndOfFile?\"\":`\n`):\"\";await e.mkdirpPromise(J.dirname(a.path),{chmod:493,utimes:[fi.SAFE_TIME,fi.SAFE_TIME]}),await e.writeFilePromise(a.path,n,{mode:a.mode}),await e.utimesPromise(a.path,fi.SAFE_TIME,fi.SAFE_TIME)}break;case\"patch\":await M1(e,a.path,async()=>{await CPt(a,{baseFs:e,dryRun:r})});break;case\"mode change\":{let c=(await e.statPromise(a.path)).mode;if(Vxe(a.newMode)!==Vxe(c))continue;await M1(e,a.path,async()=>{await e.chmodPromise(a.path,a.newMode)})}break;default:je.assertNever(a);break}}function Vxe(t){return(t&64)>0}function Jxe(t){return t.replace(/\\s+$/,\"\")}function IPt(t,e){return Jxe(t)===Jxe(e)}async function CPt({hunks:t,path:e},{baseFs:r,dryRun:s=!1}){let a=await r.statSync(e).mode,c=(await r.readFileSync(e,\"utf8\")).split(/\\n/),f=[],p=0,h=0;for(let C of t){let S=Math.max(h,C.header.patched.start+p),b=Math.max(0,S-h),I=Math.max(0,c.length-S-C.header.original.length),T=Math.max(b,I),N=0,U=0,W=null;for(;N<=T;){if(N<=b&&(U=S-N,W=Kxe(C,c,U),W!==null)){N=-N;break}if(N<=I&&(U=S+N,W=Kxe(C,c,U),W!==null))break;N+=1}if(W===null)throw new L1(t.indexOf(C),C);f.push(W),p+=N,h=U+C.header.original.length}if(s)return;let E=0;for(let C of f)for(let S of C)switch(S.type){case\"splice\":{let b=S.index+E;c.splice(b,S.numToDelete,...S.linesToInsert),E+=S.linesToInsert.length-S.numToDelete}break;case\"pop\":c.pop();break;case\"push\":c.push(S.line);break;default:je.assertNever(S);break}await r.writeFilePromise(e,c.join(`\n`),{mode:a})}function Kxe(t,e,r){let s=[];for(let a of t.parts)switch(a.type){case\"context\":case\"deletion\":{for(let n of a.lines){let c=e[r];if(c==null||!IPt(c,n))return null;r+=1}a.type===\"deletion\"&&(s.push({type:\"splice\",index:r-a.lines.length,numToDelete:a.lines.length,linesToInsert:[]}),a.noNewlineAtEndOfFile&&s.push({type:\"push\",line:\"\"}))}break;case\"insertion\":s.push({type:\"splice\",index:r,numToDelete:0,linesToInsert:a.lines}),a.noNewlineAtEndOfFile&&s.push({type:\"pop\"});break;default:je.assertNever(a.type);break}return s}var BPt=/^builtin<([^>]+)>$/;function U1(t,e){let{protocol:r,source:s,selector:a,params:n}=G.parseRange(t);if(r!==\"patch:\")throw new Error(\"Invalid patch range\");if(s===null)throw new Error(\"Patch locators must explicitly define their source\");let c=a?a.split(/&/).map(E=>fe.toPortablePath(E)):[],f=n&&typeof n.locator==\"string\"?G.parseLocator(n.locator):null,p=n&&typeof n.version==\"string\"?n.version:null,h=e(s);return{parentLocator:f,sourceItem:h,patchPaths:c,sourceVersion:p}}function TL(t){return t.range.startsWith(\"patch:\")}function Tg(t){return t.reference.startsWith(\"patch:\")}function XP(t){let{sourceItem:e,...r}=U1(t.range,G.parseDescriptor);return{...r,sourceDescriptor:e}}function $P(t){let{sourceItem:e,...r}=U1(t.reference,G.parseLocator);return{...r,sourceLocator:e}}function vPt(t){let{sourceItem:e}=U1(t.range,G.parseDescriptor);return e}function SPt(t){let{sourceItem:e}=U1(t.reference,G.parseLocator);return e}function LK(t){if(!TL(t))return t;let{sourceItem:e}=U1(t.range,G.parseDescriptor);return e}function FL(t){if(!Tg(t))return t;let{sourceItem:e}=U1(t.reference,G.parseLocator);return e}function zxe({parentLocator:t,sourceItem:e,patchPaths:r,sourceVersion:s,patchHash:a},n){let c=t!==null?{locator:G.stringifyLocator(t)}:{},f=typeof s<\"u\"?{version:s}:{},p=typeof a<\"u\"?{hash:a}:{};return G.makeRange({protocol:\"patch:\",source:n(e),selector:r.join(\"&\"),params:{...f,...p,...c}})}function NL(t,{parentLocator:e,sourceDescriptor:r,patchPaths:s}){return G.makeDescriptor(t,zxe({parentLocator:e,sourceItem:r,patchPaths:s},G.stringifyDescriptor))}function MK(t,{parentLocator:e,sourcePackage:r,patchPaths:s,patchHash:a}){return G.makeLocator(t,zxe({parentLocator:e,sourceItem:r,sourceVersion:r.version,patchPaths:s,patchHash:a},G.stringifyLocator))}function Zxe({onAbsolute:t,onRelative:e,onProject:r,onBuiltin:s},a){let n=a.lastIndexOf(\"!\");n!==-1&&(a=a.slice(n+1));let c=a.match(BPt);return c!==null?s(c[1]):a.startsWith(\"~/\")?r(a.slice(2)):J.isAbsolute(a)?t(a):e(a)}function Xxe(t){let e=t.lastIndexOf(\"!\");return{optional:(e!==-1?new Set(t.slice(0,e).split(/!/)):new Set).has(\"optional\")}}function UK(t){return Zxe({onAbsolute:()=>!1,onRelative:()=>!0,onProject:()=>!1,onBuiltin:()=>!1},t)}async function eb(t,e,r){let s=t!==null?await r.fetcher.fetch(t,r):null,a=s&&s.localPath?{packageFs:new Sn(vt.root),prefixPath:J.relative(vt.root,s.localPath)}:s;s&&s!==a&&s.releaseFs&&s.releaseFs();let n=await je.releaseAfterUseAsync(async()=>await Promise.all(e.map(async c=>{let f=Xxe(c),p=await Zxe({onAbsolute:async h=>await ce.readFilePromise(h,\"utf8\"),onRelative:async h=>{if(a===null)throw new Error(\"Assertion failed: The parent locator should have been fetched\");return await a.packageFs.readFilePromise(J.join(a.prefixPath,h),\"utf8\")},onProject:async h=>await ce.readFilePromise(J.join(r.project.cwd,h),\"utf8\"),onBuiltin:async h=>await r.project.configuration.firstHook(E=>E.getBuiltinPatch,r.project,h)},c);return{...f,source:p}})));for(let c of n)typeof c.source==\"string\"&&(c.source=c.source.replace(/\\r\\n?/g,`\n`));return n}async function _K(t,{cache:e,project:r}){let s=r.storedPackages.get(t.locatorHash);if(typeof s>\"u\")throw new Error(\"Assertion failed: Expected the package to be registered\");let a=FL(t),n=r.storedChecksums,c=new ki,f=await ce.mktempPromise(),p=J.join(f,\"source\"),h=J.join(f,\"user\"),E=J.join(f,\".yarn-patch.json\"),C=r.configuration.makeFetcher(),S=[];try{let b,I;if(t.locatorHash===a.locatorHash){let T=await C.fetch(t,{cache:e,project:r,fetcher:C,checksums:n,report:c});S.push(()=>T.releaseFs?.()),b=T,I=T}else b=await C.fetch(t,{cache:e,project:r,fetcher:C,checksums:n,report:c}),S.push(()=>b.releaseFs?.()),I=await C.fetch(t,{cache:e,project:r,fetcher:C,checksums:n,report:c}),S.push(()=>I.releaseFs?.());await Promise.all([ce.copyPromise(p,b.prefixPath,{baseFs:b.packageFs}),ce.copyPromise(h,I.prefixPath,{baseFs:I.packageFs}),ce.writeJsonPromise(E,{locator:G.stringifyLocator(t),version:s.version})])}finally{for(let b of S)b()}return ce.detachTemp(f),h}async function HK(t,e){let r=fe.fromPortablePath(t).replace(/\\\\/g,\"/\"),s=fe.fromPortablePath(e).replace(/\\\\/g,\"/\"),{stdout:a,stderr:n}=await qr.execvp(\"git\",[\"-c\",\"core.safecrlf=false\",\"diff\",\"--src-prefix=a/\",\"--dst-prefix=b/\",\"--ignore-cr-at-eol\",\"--full-index\",\"--no-index\",\"--no-renames\",\"--text\",r,s],{cwd:fe.toPortablePath(process.cwd()),env:{...process.env,GIT_CONFIG_NOSYSTEM:\"1\",HOME:\"\",XDG_CONFIG_HOME:\"\",USERPROFILE:\"\"}});if(n.length>0)throw new Error(`Unable to diff directories. Make sure you have a recent version of 'git' available in PATH.\nThe following error was reported by 'git':\n${n}`);let c=r.startsWith(\"/\")?f=>f.slice(1):f=>f;return a.replace(new RegExp(`(a|b)(${je.escapeRegExp(`/${c(r)}/`)})`,\"g\"),\"$1/\").replace(new RegExp(`(a|b)${je.escapeRegExp(`/${c(s)}/`)}`,\"g\"),\"$1/\").replace(new RegExp(je.escapeRegExp(`${r}/`),\"g\"),\"\").replace(new RegExp(je.escapeRegExp(`${s}/`),\"g\"),\"\")}function jK(t,e){let r=[];for(let{source:s}of t){if(s===null)continue;let a=ZP(s);for(let n of a){let{semverExclusivity:c,...f}=n;c!==null&&e!==null&&!Fr.satisfiesWithPrereleases(e,c)||r.push(JSON.stringify(f))}}return Nn.makeHash(`${3}`,...r).slice(0,6)}Ge();function $xe(t,{configuration:e,report:r}){for(let s of t.parts)for(let a of s.lines)switch(s.type){case\"context\":r.reportInfo(null,`  ${he.pretty(e,a,\"grey\")}`);break;case\"deletion\":r.reportError(28,`- ${he.pretty(e,a,he.Type.REMOVED)}`);break;case\"insertion\":r.reportError(28,`+ ${he.pretty(e,a,he.Type.ADDED)}`);break;default:je.assertNever(s.type)}}var tb=class{supports(e,r){return!!Tg(e)}getLocalPath(e,r){return null}async fetch(e,r){let s=r.checksums.get(e.locatorHash)||null,[a,n,c]=await r.cache.fetchPackageFromCache(e,s,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${G.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the disk`),loader:()=>this.patchPackage(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:G.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:c}}async patchPackage(e,r){let{parentLocator:s,sourceLocator:a,sourceVersion:n,patchPaths:c}=$P(e),f=await eb(s,c,r),p=await ce.mktempPromise(),h=J.join(p,\"current.zip\"),E=await r.fetcher.fetch(a,r),C=G.getIdentVendorPath(e),S=new As(h,{create:!0,level:r.project.configuration.get(\"compressionLevel\")});await je.releaseAfterUseAsync(async()=>{await S.copyPromise(C,E.prefixPath,{baseFs:E.packageFs,stableSort:!0})},E.releaseFs),S.saveAndClose();for(let{source:b,optional:I}of f){if(b===null)continue;let T=new As(h,{level:r.project.configuration.get(\"compressionLevel\")}),N=new Sn(J.resolve(vt.root,C),{baseFs:T});try{await RL(ZP(b),{baseFs:N,version:n})}catch(U){if(!(U instanceof L1))throw U;let W=r.project.configuration.get(\"enableInlineHunks\"),ee=!W&&!I?\" (set enableInlineHunks for details)\":\"\",ie=`${G.prettyLocator(r.project.configuration,e)}: ${U.message}${ee}`,ue=le=>{W&&$xe(U.hunk,{configuration:r.project.configuration,report:le})};if(T.discardAndClose(),I){r.report.reportWarningOnce(66,ie,{reportExtra:ue});continue}else throw new jt(66,ie,ue)}T.saveAndClose()}return new As(h,{level:r.project.configuration.get(\"compressionLevel\")})}};Ge();var rb=class{supportsDescriptor(e,r){return!!TL(e)}supportsLocator(e,r){return!!Tg(e)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,s){let{patchPaths:a}=XP(e);return a.every(n=>!UK(n))?e:G.bindDescriptor(e,{locator:G.stringifyLocator(r)})}getResolutionDependencies(e,r){let{sourceDescriptor:s}=XP(e);return{sourceDescriptor:r.project.configuration.normalizeDependency(s)}}async getCandidates(e,r,s){if(!s.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let{parentLocator:a,patchPaths:n}=XP(e),c=await eb(a,n,s.fetchOptions),f=r.sourceDescriptor;if(typeof f>\"u\")throw new Error(\"Assertion failed: The dependency should have been resolved\");let p=jK(c,f.version);return[MK(e,{parentLocator:a,sourcePackage:f,patchPaths:n,patchHash:p})]}async getSatisfying(e,r,s,a){let[n]=await this.getCandidates(e,r,a);return{locators:s.filter(c=>c.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){let{sourceLocator:s}=$P(e);return{...await r.resolver.resolve(s,r),...e}}};Ge();Dt();Yt();var _1=class extends ft{constructor(){super(...arguments);this.save=ge.Boolean(\"-s,--save\",!1,{description:\"Add the patch to your resolution entries\"});this.patchFolder=ge.String()}static{this.paths=[[\"patch-commit\"]]}static{this.usage=ot.Usage({description:\"generate a patch out of a directory\",details:\"\\n      By default, this will print a patchfile on stdout based on the diff between the folder passed in and the original version of the package. Such file is suitable for consumption with the `patch:` protocol.\\n\\n      With the `-s,--save` option set, the patchfile won't be printed on stdout anymore and will instead be stored within a local file (by default kept within `.yarn/patches`, but configurable via the `patchFolder` setting). A `resolutions` entry will also be added to your top-level manifest, referencing the patched package via the `patch:` protocol.\\n\\n      Note that only folders generated by `yarn patch` are accepted as valid input for `yarn patch-commit`.\\n    \"})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState();let n=J.resolve(this.context.cwd,fe.toPortablePath(this.patchFolder)),c=J.join(n,\"../source\"),f=J.join(n,\"../.yarn-patch.json\");if(!ce.existsSync(c))throw new nt(\"The argument folder didn't get created by 'yarn patch'\");let p=await HK(c,n),h=await ce.readJsonPromise(f),E=G.parseLocator(h.locator,!0);if(!s.storedPackages.has(E.locatorHash))throw new nt(\"No package found in the project for the given locator\");if(!this.save){this.context.stdout.write(p);return}let C=r.get(\"patchFolder\"),S=J.join(C,`${G.slugifyLocator(E)}.patch`);await ce.mkdirPromise(C,{recursive:!0}),await ce.writeFilePromise(S,p);let b=[],I=new Map;for(let T of s.storedPackages.values()){if(G.isVirtualLocator(T))continue;let N=T.dependencies.get(E.identHash);if(!N)continue;let U=G.ensureDevirtualizedDescriptor(N),W=LK(U),ee=s.storedResolutions.get(W.descriptorHash);if(!ee)throw new Error(\"Assertion failed: Expected the resolution to have been registered\");if(!s.storedPackages.get(ee))throw new Error(\"Assertion failed: Expected the package to have been registered\");let ue=s.tryWorkspaceByLocator(T);if(ue)b.push(ue);else{let le=s.originalPackages.get(T.locatorHash);if(!le)throw new Error(\"Assertion failed: Expected the original package to have been registered\");let me=le.dependencies.get(N.identHash);if(!me)throw new Error(\"Assertion failed: Expected the original dependency to have been registered\");I.set(me.descriptorHash,me)}}for(let T of b)for(let N of Ut.hardDependencies){let U=T.manifest[N].get(E.identHash);if(!U)continue;let W=NL(U,{parentLocator:null,sourceDescriptor:G.convertLocatorToDescriptor(E),patchPaths:[J.join(Er.home,J.relative(s.cwd,S))]});T.manifest[N].set(U.identHash,W)}for(let T of I.values()){let N=NL(T,{parentLocator:null,sourceDescriptor:G.convertLocatorToDescriptor(E),patchPaths:[J.join(Er.home,J.relative(s.cwd,S))]});s.topLevelWorkspace.manifest.resolutions.push({pattern:{descriptor:{fullName:G.stringifyIdent(N),description:T.range}},reference:N.range})}await s.persist()}};Ge();Dt();Yt();var H1=class extends ft{constructor(){super(...arguments);this.update=ge.Boolean(\"-u,--update\",!1,{description:\"Reapply local patches that already apply to this packages\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.package=ge.String()}static{this.paths=[[\"patch\"]]}static{this.usage=ot.Usage({description:\"prepare a package for patching\",details:\"\\n      This command will cause a package to be extracted in a temporary directory intended to be editable at will.\\n\\n      Once you're done with your changes, run `yarn patch-commit -s path` (with `path` being the temporary directory you received) to generate a patchfile and register it into your top-level manifest via the `patch:` protocol. Run `yarn patch-commit -h` for more details.\\n\\n      Calling the command when you already have a patch won't import it by default (in other words, the default behavior is to reset existing patches). However, adding the `-u,--update` flag will import any current patch.\\n    \"})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState();let c=G.parseLocator(this.package);if(c.reference===\"unknown\"){let f=je.mapAndFilter([...s.storedPackages.values()],p=>p.identHash!==c.identHash?je.mapAndFilter.skip:G.isVirtualLocator(p)?je.mapAndFilter.skip:Tg(p)!==this.update?je.mapAndFilter.skip:p);if(f.length===0)throw new nt(\"No package found in the project for the given locator\");if(f.length>1)throw new nt(`Multiple candidate packages found; explicitly choose one of them (use \\`yarn why <package>\\` to get more information as to who depends on them):\n${f.map(p=>`\n- ${G.prettyLocator(r,p)}`).join(\"\")}`);c=f[0]}if(!s.storedPackages.has(c.locatorHash))throw new nt(\"No package found in the project for the given locator\");await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout},async f=>{let p=FL(c),h=await _K(c,{cache:n,project:s});f.reportJson({locator:G.stringifyLocator(p),path:fe.fromPortablePath(h)});let E=this.update?\" along with its current modifications\":\"\";f.reportInfo(0,`Package ${G.prettyLocator(r,p)} got extracted with success${E}!`),f.reportInfo(0,`You can now edit the following folder: ${he.pretty(r,fe.fromPortablePath(h),\"magenta\")}`),f.reportInfo(0,`Once you are done run ${he.pretty(r,`yarn patch-commit -s ${process.platform===\"win32\"?'\"':\"\"}${fe.fromPortablePath(h)}${process.platform===\"win32\"?'\"':\"\"}`,\"cyan\")} and Yarn will store a patchfile based on your changes.`)})}};var DPt={configuration:{enableInlineHunks:{description:\"If true, the installs will print unmatched patch hunks\",type:\"BOOLEAN\",default:!1},patchFolder:{description:\"Folder where the patch files must be written\",type:\"ABSOLUTE_PATH\",default:\"./.yarn/patches\"}},commands:[_1,H1],fetchers:[tb],resolvers:[rb]},PPt=DPt;var YK={};Vt(YK,{PnpmLinker:()=>nb,default:()=>TPt});Ge();Dt();Yt();var nb=class{getCustomDataKey(){return JSON.stringify({name:\"PnpmLinker\",version:3})}supportsPackage(e,r){return this.isEnabled(r)}async findPackageLocation(e,r){if(!this.isEnabled(r))throw new Error(\"Assertion failed: Expected the pnpm linker to be enabled\");let s=this.getCustomDataKey(),a=r.project.linkersCustomData.get(s);if(!a)throw new nt(`The project in ${he.pretty(r.project.configuration,`${r.project.cwd}/package.json`,he.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let n=a.pathsByLocator.get(e.locatorHash);if(typeof n>\"u\")throw new nt(`Couldn't find ${G.prettyLocator(r.project.configuration,e)} in the currently installed pnpm map - running an install might help`);return n.packageLocation}async findPackageLocator(e,r){if(!this.isEnabled(r))return null;let s=this.getCustomDataKey(),a=r.project.linkersCustomData.get(s);if(!a)throw new nt(`The project in ${he.pretty(r.project.configuration,`${r.project.cwd}/package.json`,he.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let n=e.match(/(^.*\\/node_modules\\/(@[^/]*\\/)?[^/]+)(\\/.*$)/);if(n){let p=a.locatorByPath.get(n[1]);if(p)return p}let c=e,f=e;do{f=c,c=J.dirname(f);let p=a.locatorByPath.get(f);if(p)return p}while(c!==f);return null}makeInstaller(e){return new qK(e)}isEnabled(e){return e.project.configuration.get(\"nodeLinker\")===\"pnpm\"}},qK=class{constructor(e){this.opts=e;this.asyncActions=new je.AsyncActions(10);this.customData={pathsByLocator:new Map,locatorByPath:new Map};this.indexFolderPromise=$b(ce,{indexPath:J.join(e.project.configuration.get(\"globalFolder\"),\"index\")})}attachCustomData(e){}async installPackage(e,r,s){switch(e.linkType){case\"SOFT\":return this.installPackageSoft(e,r,s);case\"HARD\":return this.installPackageHard(e,r,s)}throw new Error(\"Assertion failed: Unsupported package link type\")}async installPackageSoft(e,r,s){let a=J.resolve(r.packageFs.getRealPath(),r.prefixPath),n=this.opts.project.tryWorkspaceByLocator(e)?J.join(a,Er.nodeModules):null;return this.customData.pathsByLocator.set(e.locatorHash,{packageLocation:a,dependenciesLocation:n}),{packageLocation:a,buildRequest:null}}async installPackageHard(e,r,s){let a=xPt(e,{project:this.opts.project}),n=a.packageLocation;this.customData.locatorByPath.set(n,G.stringifyLocator(e)),this.customData.pathsByLocator.set(e.locatorHash,a),s.holdFetchResult(this.asyncActions.set(e.locatorHash,async()=>{await ce.mkdirPromise(n,{recursive:!0}),await ce.copyPromise(n,r.prefixPath,{baseFs:r.packageFs,overwrite:!1,linkStrategy:{type:\"HardlinkFromIndex\",indexPath:await this.indexFolderPromise,autoRepair:!0}})}));let f=G.isVirtualLocator(e)?G.devirtualizeLocator(e):e,p={manifest:await Ut.tryFind(r.prefixPath,{baseFs:r.packageFs})??new Ut,misc:{hasBindingGyp:gA.hasBindingGyp(r)}},h=this.opts.project.getDependencyMeta(f,e.version),E=gA.extractBuildRequest(e,p,h,{configuration:this.opts.project.configuration});return{packageLocation:n,buildRequest:E}}async attachInternalDependencies(e,r){if(this.opts.project.configuration.get(\"nodeLinker\")!==\"pnpm\"||!eke(e,{project:this.opts.project}))return;let s=this.customData.pathsByLocator.get(e.locatorHash);if(typeof s>\"u\")throw new Error(`Assertion failed: Expected the package to have been registered (${G.stringifyLocator(e)})`);let{dependenciesLocation:a}=s;a&&this.asyncActions.reduce(e.locatorHash,async n=>{await ce.mkdirPromise(a,{recursive:!0});let c=await kPt(a),f=new Map(c),p=[n],h=(C,S)=>{let b=S;eke(S,{project:this.opts.project})||(this.opts.report.reportWarningOnce(0,\"The pnpm linker doesn't support providing different versions to workspaces' peer dependencies\"),b=G.devirtualizeLocator(S));let I=this.customData.pathsByLocator.get(b.locatorHash);if(typeof I>\"u\")throw new Error(`Assertion failed: Expected the package to have been registered (${G.stringifyLocator(S)})`);let T=G.stringifyIdent(C),N=J.join(a,T),U=J.relative(J.dirname(N),I.packageLocation),W=f.get(T);f.delete(T),p.push(Promise.resolve().then(async()=>{if(W){if(W.isSymbolicLink()&&await ce.readlinkPromise(N)===U)return;await ce.removePromise(N)}await ce.mkdirpPromise(J.dirname(N)),process.platform==\"win32\"&&this.opts.project.configuration.get(\"winLinkType\")===\"junctions\"?await ce.symlinkPromise(I.packageLocation,N,\"junction\"):await ce.symlinkPromise(U,N)}))},E=!1;for(let[C,S]of r)C.identHash===e.identHash&&(E=!0),h(C,S);!E&&!this.opts.project.tryWorkspaceByLocator(e)&&h(G.convertLocatorToDescriptor(e),e),p.push(QPt(a,f)),await Promise.all(p)})}async attachExternalDependents(e,r){throw new Error(\"External dependencies haven't been implemented for the pnpm linker\")}async finalizeInstall(){let e=tke(this.opts.project);if(this.opts.project.configuration.get(\"nodeLinker\")!==\"pnpm\")await ce.removePromise(e);else{let r;try{r=new Set(await ce.readdirPromise(e))}catch{r=new Set}for(let{dependenciesLocation:s}of this.customData.pathsByLocator.values()){if(!s)continue;let a=J.contains(e,s);if(a===null)continue;let[n]=a.split(J.sep);r.delete(n)}await Promise.all([...r].map(async s=>{await ce.removePromise(J.join(e,s))}))}return await this.asyncActions.wait(),await WK(e),this.opts.project.configuration.get(\"nodeLinker\")!==\"node-modules\"&&await WK(bPt(this.opts.project)),{customData:this.customData}}};function bPt(t){return J.join(t.cwd,Er.nodeModules)}function tke(t){return t.configuration.get(\"pnpmStoreFolder\")}function xPt(t,{project:e}){let r=G.slugifyLocator(t),s=tke(e),a=J.join(s,r,\"package\"),n=J.join(s,r,Er.nodeModules);return{packageLocation:a,dependenciesLocation:n}}function eke(t,{project:e}){return!G.isVirtualLocator(t)||!e.tryWorkspaceByLocator(t)}async function kPt(t){let e=new Map,r=[];try{r=await ce.readdirPromise(t,{withFileTypes:!0})}catch(s){if(s.code!==\"ENOENT\")throw s}try{for(let s of r)if(!s.name.startsWith(\".\"))if(s.name.startsWith(\"@\")){let a=await ce.readdirPromise(J.join(t,s.name),{withFileTypes:!0});if(a.length===0)e.set(s.name,s);else for(let n of a)e.set(`${s.name}/${n.name}`,n)}else e.set(s.name,s)}catch(s){if(s.code!==\"ENOENT\")throw s}return e}async function QPt(t,e){let r=[],s=new Set;for(let a of e.keys()){r.push(ce.removePromise(J.join(t,a)));let n=G.tryParseIdent(a)?.scope;n&&s.add(`@${n}`)}return Promise.all(r).then(()=>Promise.all([...s].map(a=>WK(J.join(t,a)))))}async function WK(t){try{await ce.rmdirPromise(t)}catch(e){if(e.code!==\"ENOENT\"&&e.code!==\"ENOTEMPTY\"&&e.code!==\"EBUSY\")throw e}}var RPt={configuration:{pnpmStoreFolder:{description:\"By default, the store is stored in the 'node_modules/.store' of the project. Sometimes in CI scenario's it is convenient to store this in a different location so it can be cached and reused.\",type:\"ABSOLUTE_PATH\",default:\"./node_modules/.store\"}},linkers:[nb]},TPt=RPt;var $K={};Vt($K,{StageCommand:()=>j1,default:()=>qPt,stageUtils:()=>LL});Ge();Dt();Yt();Ge();Dt();var LL={};Vt(LL,{ActionType:()=>VK,checkConsensus:()=>OL,expandDirectory:()=>zK,findConsensus:()=>ZK,findVcsRoot:()=>JK,genCommitMessage:()=>XK,getCommitPrefix:()=>rke,isYarnFile:()=>KK});Dt();var VK=(n=>(n[n.CREATE=0]=\"CREATE\",n[n.DELETE=1]=\"DELETE\",n[n.ADD=2]=\"ADD\",n[n.REMOVE=3]=\"REMOVE\",n[n.MODIFY=4]=\"MODIFY\",n))(VK||{});async function JK(t,{marker:e}){do if(!ce.existsSync(J.join(t,e)))t=J.dirname(t);else return t;while(t!==\"/\");return null}function KK(t,{roots:e,names:r}){if(r.has(J.basename(t)))return!0;do if(!e.has(t))t=J.dirname(t);else return!0;while(t!==\"/\");return!1}function zK(t){let e=[],r=[t];for(;r.length>0;){let s=r.pop(),a=ce.readdirSync(s);for(let n of a){let c=J.resolve(s,n);ce.lstatSync(c).isDirectory()?r.push(c):e.push(c)}}return e}function OL(t,e){let r=0,s=0;for(let a of t)a!==\"wip\"&&(e.test(a)?r+=1:s+=1);return r>=s}function ZK(t){let e=OL(t,/^(\\w\\(\\w+\\):\\s*)?\\w+s/),r=OL(t,/^(\\w\\(\\w+\\):\\s*)?[A-Z]/),s=OL(t,/^\\w\\(\\w+\\):/);return{useThirdPerson:e,useUpperCase:r,useComponent:s}}function rke(t){return t.useComponent?\"chore(yarn): \":\"\"}var FPt=new Map([[0,\"create\"],[1,\"delete\"],[2,\"add\"],[3,\"remove\"],[4,\"update\"]]);function XK(t,e){let r=rke(t),s=[],a=e.slice().sort((n,c)=>n[0]-c[0]);for(;a.length>0;){let[n,c]=a.shift(),f=FPt.get(n);t.useUpperCase&&s.length===0&&(f=`${f[0].toUpperCase()}${f.slice(1)}`),t.useThirdPerson&&(f+=\"s\");let p=[c];for(;a.length>0&&a[0][0]===n;){let[,E]=a.shift();p.push(E)}p.sort();let h=p.shift();p.length===1?h+=\" (and one other)\":p.length>1&&(h+=` (and ${p.length} others)`),s.push(`${f} ${h}`)}return`${r}${s.join(\", \")}`}var NPt=\"Commit generated via `yarn stage`\",OPt=11;async function nke(t){let{code:e,stdout:r}=await qr.execvp(\"git\",[\"log\",\"-1\",\"--pretty=format:%H\"],{cwd:t});return e===0?r.trim():null}async function LPt(t,e){let r=[],s=e.filter(h=>J.basename(h.path)===\"package.json\");for(let{action:h,path:E}of s){let C=J.relative(t,E);if(h===4){let S=await nke(t),{stdout:b}=await qr.execvp(\"git\",[\"show\",`${S}:${C}`],{cwd:t,strict:!0}),I=await Ut.fromText(b),T=await Ut.fromFile(E),N=new Map([...T.dependencies,...T.devDependencies]),U=new Map([...I.dependencies,...I.devDependencies]);for(let[W,ee]of U){let ie=G.stringifyIdent(ee),ue=N.get(W);ue?ue.range!==ee.range&&r.push([4,`${ie} to ${ue.range}`]):r.push([3,ie])}for(let[W,ee]of N)U.has(W)||r.push([2,G.stringifyIdent(ee)])}else if(h===0){let S=await Ut.fromFile(E);S.name?r.push([0,G.stringifyIdent(S.name)]):r.push([0,\"a package\"])}else if(h===1){let S=await nke(t),{stdout:b}=await qr.execvp(\"git\",[\"show\",`${S}:${C}`],{cwd:t,strict:!0}),I=await Ut.fromText(b);I.name?r.push([1,G.stringifyIdent(I.name)]):r.push([1,\"a package\"])}else throw new Error(\"Assertion failed: Unsupported action type\")}let{code:a,stdout:n}=await qr.execvp(\"git\",[\"log\",`-${OPt}`,\"--pretty=format:%s\"],{cwd:t}),c=a===0?n.split(/\\n/g).filter(h=>h!==\"\"):[],f=ZK(c);return XK(f,r)}var MPt={0:[\" A \",\"?? \"],4:[\" M \"],1:[\" D \"]},UPt={0:[\"A  \"],4:[\"M  \"],1:[\"D  \"]},ike={async findRoot(t){return await JK(t,{marker:\".git\"})},async filterChanges(t,e,r,s){let{stdout:a}=await qr.execvp(\"git\",[\"status\",\"-s\"],{cwd:t,strict:!0}),n=a.toString().split(/\\n/g),c=s?.staged?UPt:MPt;return[].concat(...n.map(p=>{if(p===\"\")return[];let h=p.slice(0,3),E=J.resolve(t,p.slice(3));if(!s?.staged&&h===\"?? \"&&p.endsWith(\"/\"))return zK(E).map(C=>({action:0,path:C}));{let S=[0,4,1].find(b=>c[b].includes(h));return S!==void 0?[{action:S,path:E}]:[]}})).filter(p=>KK(p.path,{roots:e,names:r}))},async genCommitMessage(t,e){return await LPt(t,e)},async makeStage(t,e){let r=e.map(s=>fe.fromPortablePath(s.path));await qr.execvp(\"git\",[\"add\",\"--\",...r],{cwd:t,strict:!0})},async makeCommit(t,e,r){let s=e.map(a=>fe.fromPortablePath(a.path));await qr.execvp(\"git\",[\"add\",\"-N\",\"--\",...s],{cwd:t,strict:!0}),await qr.execvp(\"git\",[\"commit\",\"-m\",`${r}\n\n${NPt}\n`,\"--\",...s],{cwd:t,strict:!0})},async makeReset(t,e){let r=e.map(s=>fe.fromPortablePath(s.path));await qr.execvp(\"git\",[\"reset\",\"HEAD\",\"--\",...r],{cwd:t,strict:!0})}};var _Pt=[ike],j1=class extends ft{constructor(){super(...arguments);this.commit=ge.Boolean(\"-c,--commit\",!1,{description:\"Commit the staged files\"});this.reset=ge.Boolean(\"-r,--reset\",!1,{description:\"Remove all files from the staging area\"});this.dryRun=ge.Boolean(\"-n,--dry-run\",!1,{description:\"Print the commit message and the list of modified files without staging / committing\"});this.update=ge.Boolean(\"-u,--update\",!1,{hidden:!0})}static{this.paths=[[\"stage\"]]}static{this.usage=ot.Usage({description:\"add all yarn files to your vcs\",details:\"\\n      This command will add to your staging area the files belonging to Yarn (typically any modified `package.json` and `.yarnrc.yml` files, but also linker-generated files, cache data, etc). It will take your ignore list into account, so the cache files won't be added if the cache is ignored in a `.gitignore` file (assuming you use Git).\\n\\n      Running `--reset` will instead remove them from the staging area (the changes will still be there, but won't be committed until you stage them back).\\n\\n      Since the staging area is a non-existent concept in Mercurial, Yarn will always create a new commit when running this command on Mercurial repositories. You can get this behavior when using Git by using the `--commit` flag which will directly create a commit.\\n    \",examples:[[\"Adds all modified project files to the staging area\",\"yarn stage\"],[\"Creates a new commit containing all modified project files\",\"yarn stage --commit\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s}=await Rt.find(r,this.context.cwd),{driver:a,root:n}=await HPt(s.cwd),c=[r.get(\"cacheFolder\"),r.get(\"globalFolder\"),r.get(\"virtualFolder\"),r.get(\"yarnPath\")];await r.triggerHook(C=>C.populateYarnPaths,s,C=>{c.push(C)});let f=new Set;for(let C of c)for(let S of jPt(n,C))f.add(S);let p=new Set([r.get(\"rcFilename\"),Er.lockfile,Er.manifest]),h=await a.filterChanges(n,f,p),E=await a.genCommitMessage(n,h);if(this.dryRun)if(this.commit)this.context.stdout.write(`${E}\n`);else for(let C of h)this.context.stdout.write(`${fe.fromPortablePath(C.path)}\n`);else if(this.reset){let C=await a.filterChanges(n,f,p,{staged:!0});C.length===0?this.context.stdout.write(\"No staged changes found!\"):await a.makeReset(n,C)}else h.length===0?this.context.stdout.write(\"No changes found!\"):this.commit?await a.makeCommit(n,h,E):(await a.makeStage(n,h),this.context.stdout.write(E))}};async function HPt(t){let e=null,r=null;for(let s of _Pt)if((r=await s.findRoot(t))!==null){e=s;break}if(e===null||r===null)throw new nt(\"No stage driver has been found for your current project\");return{driver:e,root:r}}function jPt(t,e){let r=[];if(e===null)return r;for(;;){(e===t||e.startsWith(`${t}/`))&&r.push(e);let s;try{s=ce.statSync(e)}catch{break}if(s.isSymbolicLink())e=J.resolve(J.dirname(e),ce.readlinkSync(e));else break}return r}var GPt={commands:[j1]},qPt=GPt;var ez={};Vt(ez,{default:()=>XPt});Ge();Ge();Dt();var ake=ut(Ai());Ge();var ske=ut(l9()),WPt=\"e8e1bd300d860104bb8c58453ffa1eb4\",YPt=\"OFCNCOG2CU\",oke=async(t,e)=>{let r=G.stringifyIdent(t),a=VPt(e).initIndex(\"npm-search\");try{return(await a.getObject(r,{attributesToRetrieve:[\"types\"]})).types?.ts===\"definitely-typed\"}catch{return!1}},VPt=t=>(0,ske.default)(YPt,WPt,{requester:{async send(r){try{let s=await ln.request(r.url,r.data||null,{configuration:t,headers:r.headers});return{content:s.body,isTimedOut:!1,status:s.statusCode}}catch(s){return{content:s.response.body,isTimedOut:!1,status:s.response.statusCode}}}}});var lke=t=>t.scope?`${t.scope}__${t.name}`:`${t.name}`,JPt=async(t,e,r,s)=>{if(r.scope===\"types\")return;let{project:a}=t,{configuration:n}=a;if(!(n.get(\"tsEnableAutoTypes\")??(ce.existsSync(J.join(t.cwd,\"tsconfig.json\"))||ce.existsSync(J.join(a.cwd,\"tsconfig.json\")))))return;let f=n.makeResolver(),p={project:a,resolver:f,report:new ki};if(!await oke(r,n))return;let E=lke(r),C=G.parseRange(r.range).selector;if(!Fr.validRange(C)){let N=n.normalizeDependency(r),U=await f.getCandidates(N,{},p);C=G.parseRange(U[0].reference).selector}let S=ake.default.coerce(C);if(S===null)return;let b=`${Zu.Modifier.CARET}${S.major}`,I=G.makeDescriptor(G.makeIdent(\"types\",E),b),T=je.mapAndFind(a.workspaces,N=>{let U=N.manifest.dependencies.get(r.identHash)?.descriptorHash,W=N.manifest.devDependencies.get(r.identHash)?.descriptorHash;if(U!==r.descriptorHash&&W!==r.descriptorHash)return je.mapAndFind.skip;let ee=[];for(let ie of Ut.allDependencies){let ue=N.manifest[ie].get(I.identHash);typeof ue>\"u\"||ee.push([ie,ue])}return ee.length===0?je.mapAndFind.skip:ee});if(typeof T<\"u\")for(let[N,U]of T)t.manifest[N].set(U.identHash,U);else{try{let N=n.normalizeDependency(I);if((await f.getCandidates(N,{},p)).length===0)return}catch{return}t.manifest[Zu.Target.DEVELOPMENT].set(I.identHash,I)}},KPt=async(t,e,r)=>{if(r.scope===\"types\")return;let{project:s}=t,{configuration:a}=s;if(!(a.get(\"tsEnableAutoTypes\")??(ce.existsSync(J.join(t.cwd,\"tsconfig.json\"))||ce.existsSync(J.join(s.cwd,\"tsconfig.json\")))))return;let c=lke(r),f=G.makeIdent(\"types\",c);for(let p of Ut.allDependencies)typeof t.manifest[p].get(f.identHash)>\"u\"||t.manifest[p].delete(f.identHash)},zPt=(t,e)=>{e.publishConfig&&e.publishConfig.typings&&(e.typings=e.publishConfig.typings),e.publishConfig&&e.publishConfig.types&&(e.types=e.publishConfig.types)},ZPt={configuration:{tsEnableAutoTypes:{description:\"Whether Yarn should auto-install @types/ dependencies on 'yarn add'\",type:\"BOOLEAN\",isNullable:!0,default:null}},hooks:{afterWorkspaceDependencyAddition:JPt,afterWorkspaceDependencyRemoval:KPt,beforeWorkspacePacking:zPt}},XPt=ZPt;var sz={};Vt(sz,{VersionApplyCommand:()=>Y1,VersionCheckCommand:()=>V1,VersionCommand:()=>J1,default:()=>nbt,versionUtils:()=>W1});Ge();Ge();Yt();var W1={};Vt(W1,{Decision:()=>G1,applyPrerelease:()=>cke,applyReleases:()=>iz,applyStrategy:()=>ib,clearVersionFiles:()=>tz,getUndecidedDependentWorkspaces:()=>ob,getUndecidedWorkspaces:()=>ML,openVersionFile:()=>q1,requireMoreDecisions:()=>ebt,resolveVersionFiles:()=>sb,suggestStrategy:()=>nz,updateVersionFiles:()=>rz,validateReleaseDecision:()=>dy});Ge();Dt();wc();Yt();ql();var kA=ut(Ai()),$Pt=/^(>=|[~^]|)(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(-(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\\+[0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*)?$/,G1=(h=>(h.UNDECIDED=\"undecided\",h.DECLINE=\"decline\",h.MAJOR=\"major\",h.MINOR=\"minor\",h.PATCH=\"patch\",h.PREMAJOR=\"premajor\",h.PREMINOR=\"preminor\",h.PREPATCH=\"prepatch\",h.PRERELEASE=\"prerelease\",h))(G1||{});function dy(t){let e=kA.default.valid(t);return e||je.validateEnum(N4(G1,\"UNDECIDED\"),t)}async function sb(t,{prerelease:e=null}={}){let r=new Map,s=t.configuration.get(\"deferredVersionFolder\");if(!ce.existsSync(s))return r;let a=await ce.readdirPromise(s);for(let n of a){if(!n.endsWith(\".yml\"))continue;let c=J.join(s,n),f=await ce.readFilePromise(c,\"utf8\"),p=as(f);for(let[h,E]of Object.entries(p.releases||{})){if(E===\"decline\")continue;let C=G.parseIdent(h),S=t.tryWorkspaceByIdent(C);if(S===null)throw new Error(`Assertion failed: Expected a release definition file to only reference existing workspaces (${J.basename(c)} references ${h})`);if(S.manifest.version===null)throw new Error(`Assertion failed: Expected the workspace to have a version (${G.prettyLocator(t.configuration,S.anchoredLocator)})`);let b=S.manifest.raw.stableVersion??S.manifest.version,I=r.get(S),T=ib(E===\"prerelease\"?S.manifest.version:b,dy(E));if(T===null)throw new Error(`Assertion failed: Expected ${b} to support being bumped via strategy ${E}`);let N=typeof I<\"u\"?kA.default.gt(T,I)?T:I:T;r.set(S,N)}}return e&&(r=new Map([...r].map(([n,c])=>[n,cke(c,{current:n.manifest.version,prerelease:e})]))),r}async function tz(t){let e=t.configuration.get(\"deferredVersionFolder\");ce.existsSync(e)&&await ce.removePromise(e)}async function rz(t,e){let r=new Set(e),s=t.configuration.get(\"deferredVersionFolder\");if(!ce.existsSync(s))return;let a=await ce.readdirPromise(s);for(let n of a){if(!n.endsWith(\".yml\"))continue;let c=J.join(s,n),f=await ce.readFilePromise(c,\"utf8\"),p=as(f),h=p?.releases;if(h){for(let E of Object.keys(h)){let C=G.parseIdent(E),S=t.tryWorkspaceByIdent(C);(S===null||r.has(S))&&delete p.releases[E]}Object.keys(p.releases).length>0?await ce.changeFilePromise(c,nl(new nl.PreserveOrdering(p))):await ce.unlinkPromise(c)}}}async function q1(t,{allowEmpty:e=!1}={}){let r=t.configuration;if(r.projectCwd===null)throw new nt(\"This command can only be run from within a Yarn project\");let s=await ka.fetchRoot(r.projectCwd),a=s!==null?await ka.fetchBase(s,{baseRefs:r.get(\"changesetBaseRefs\")}):null,n=s!==null?await ka.fetchChangedFiles(s,{base:a.hash,project:t}):[],c=r.get(\"deferredVersionFolder\"),f=n.filter(b=>J.contains(c,b)!==null);if(f.length>1)throw new nt(`Your current branch contains multiple versioning files; this isn't supported:\n- ${f.map(b=>fe.fromPortablePath(b)).join(`\n- `)}`);let p=new Set(je.mapAndFilter(n,b=>{let I=t.tryWorkspaceByFilePath(b);return I===null?je.mapAndFilter.skip:I}));if(f.length===0&&p.size===0&&!e)return null;let h=f.length===1?f[0]:J.join(c,`${Nn.makeHash(Math.random().toString()).slice(0,8)}.yml`),E=ce.existsSync(h)?await ce.readFilePromise(h,\"utf8\"):\"{}\",C=as(E),S=new Map;for(let b of C.declined||[]){let I=G.parseIdent(b),T=t.getWorkspaceByIdent(I);S.set(T,\"decline\")}for(let[b,I]of Object.entries(C.releases||{})){let T=G.parseIdent(b),N=t.getWorkspaceByIdent(T);S.set(N,dy(I))}return{project:t,root:s,baseHash:a!==null?a.hash:null,baseTitle:a!==null?a.title:null,changedFiles:new Set(n),changedWorkspaces:p,releaseRoots:new Set([...p].filter(b=>b.manifest.version!==null)),releases:S,async saveAll(){let b={},I=[],T=[];for(let N of t.workspaces){if(N.manifest.version===null)continue;let U=G.stringifyIdent(N.anchoredLocator),W=S.get(N);W===\"decline\"?I.push(U):typeof W<\"u\"?b[U]=dy(W):p.has(N)&&T.push(U)}await ce.mkdirPromise(J.dirname(h),{recursive:!0}),await ce.changeFilePromise(h,nl(new nl.PreserveOrdering({releases:Object.keys(b).length>0?b:void 0,declined:I.length>0?I:void 0,undecided:T.length>0?T:void 0})))}}}function ebt(t){return ML(t).size>0||ob(t).length>0}function ML(t){let e=new Set;for(let r of t.changedWorkspaces)r.manifest.version!==null&&(t.releases.has(r)||e.add(r));return e}function ob(t,{include:e=new Set}={}){let r=[],s=new Map(je.mapAndFilter([...t.releases],([n,c])=>c===\"decline\"?je.mapAndFilter.skip:[n.anchoredLocator.locatorHash,n])),a=new Map(je.mapAndFilter([...t.releases],([n,c])=>c!==\"decline\"?je.mapAndFilter.skip:[n.anchoredLocator.locatorHash,n]));for(let n of t.project.workspaces)if(!(!e.has(n)&&(a.has(n.anchoredLocator.locatorHash)||s.has(n.anchoredLocator.locatorHash)))&&n.manifest.version!==null)for(let c of Ut.hardDependencies)for(let f of n.manifest.getForScope(c).values()){let p=t.project.tryWorkspaceByDescriptor(f);p!==null&&s.has(p.anchoredLocator.locatorHash)&&r.push([n,p])}return r}function nz(t,e){let r=kA.default.clean(e);for(let s of Object.values(G1))if(s!==\"undecided\"&&s!==\"decline\"&&kA.default.inc(t,s)===r)return s;return null}function ib(t,e){if(kA.default.valid(e))return e;if(t===null)throw new nt(`Cannot apply the release strategy \"${e}\" unless the workspace already has a valid version`);if(!kA.default.valid(t))throw new nt(`Cannot apply the release strategy \"${e}\" on a non-semver version (${t})`);let r=kA.default.inc(t,e);if(r===null)throw new nt(`Cannot apply the release strategy \"${e}\" on the specified version (${t})`);return r}function iz(t,e,{report:r,exact:s}){let a=new Map;for(let n of t.workspaces)for(let c of Ut.allDependencies)for(let f of n.manifest[c].values()){let p=t.tryWorkspaceByDescriptor(f);if(p===null||!e.has(p))continue;je.getArrayWithDefault(a,p).push([n,c,f.identHash])}for(let[n,c]of e){let f=n.manifest.version;n.manifest.version=c,kA.default.prerelease(c)===null?delete n.manifest.raw.stableVersion:n.manifest.raw.stableVersion||(n.manifest.raw.stableVersion=f);let p=n.manifest.name!==null?G.stringifyIdent(n.manifest.name):null;r.reportInfo(0,`${G.prettyLocator(t.configuration,n.anchoredLocator)}: Bumped to ${c}`),r.reportJson({cwd:fe.fromPortablePath(n.cwd),ident:p,oldVersion:f,newVersion:c});let h=a.get(n);if(!(typeof h>\"u\"))for(let[E,C,S]of h){let b=E.manifest[C].get(S);if(typeof b>\"u\")throw new Error(\"Assertion failed: The dependency should have existed\");let I=b.range,T=!1;if(I.startsWith(Ei.protocol)&&(I=I.slice(Ei.protocol.length),T=!0,I===n.relativeCwd))continue;let N=I.match($Pt);if(!N){r.reportWarning(0,`Couldn't auto-upgrade range ${I} (in ${G.prettyLocator(t.configuration,E.anchoredLocator)})`);continue}let U=s?`${c}`:`${N[1]}${c}`;T&&(U=`${Ei.protocol}${U}`);let W=G.makeDescriptor(b,U);E.manifest[C].set(S,W)}}}var tbt=new Map([[\"%n\",{extract:t=>t.length>=1?[t[0],t.slice(1)]:null,generate:(t=0)=>`${t+1}`}]]);function cke(t,{current:e,prerelease:r}){let s=new kA.default.SemVer(e),a=s.prerelease.slice(),n=[];s.prerelease=[],s.format()!==t&&(a.length=0);let c=!0,f=r.split(/\\./g);for(let p of f){let h=tbt.get(p);if(typeof h>\"u\")n.push(p),a[0]===p?a.shift():c=!1;else{let E=c?h.extract(a):null;E!==null&&typeof E[0]==\"number\"?(n.push(h.generate(E[0])),a=E[1]):(n.push(h.generate()),c=!1)}}return s.prerelease&&(s.prerelease=[]),`${t}-${n.join(\".\")}`}var Y1=class extends ft{constructor(){super(...arguments);this.all=ge.Boolean(\"--all\",!1,{description:\"Apply the deferred version changes on all workspaces\"});this.dryRun=ge.Boolean(\"--dry-run\",!1,{description:\"Print the versions without actually generating the package archive\"});this.prerelease=ge.String(\"--prerelease\",{description:\"Add a prerelease identifier to new versions\",tolerateBoolean:!0});this.exact=ge.Boolean(\"--exact\",!1,{description:\"Use the exact version of each package, removes any range. Useful for nightly releases where the range might match another version.\"});this.recursive=ge.Boolean(\"-R,--recursive\",{description:\"Release the transitive workspaces as well\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}static{this.paths=[[\"version\",\"apply\"]]}static{this.usage=ot.Usage({category:\"Release-related commands\",description:\"apply all the deferred version bumps at once\",details:`\n      This command will apply the deferred version changes and remove their definitions from the repository.\n\n      Note that if \\`--prerelease\\` is set, the given prerelease identifier (by default \\`rc.%n\\`) will be used on all new versions and the version definitions will be kept as-is.\n\n      By default only the current workspace will be bumped, but you can configure this behavior by using one of:\n\n      - \\`--recursive\\` to also apply the version bump on its dependencies\n      - \\`--all\\` to apply the version bump on all packages in the repository\n\n      Note that this command will also update the \\`workspace:\\` references across all your local workspaces, thus ensuring that they keep referring to the same workspaces even after the version bump.\n    `,examples:[[\"Apply the version change to the local workspace\",\"yarn version apply\"],[\"Apply the version change to all the workspaces in the local workspace\",\"yarn version apply --all\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n=await Kr.find(r);if(!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState({restoreResolutions:!1});let c=await Ot.start({configuration:r,json:this.json,stdout:this.context.stdout},async f=>{let p=this.prerelease?typeof this.prerelease!=\"boolean\"?this.prerelease:\"rc.%n\":null,h=await sb(s,{prerelease:p}),E=new Map;if(this.all)E=h;else{let C=this.recursive?a.getRecursiveWorkspaceDependencies():[a];for(let S of C){let b=h.get(S);typeof b<\"u\"&&E.set(S,b)}}if(E.size===0){let C=h.size>0?\" Did you want to add --all?\":\"\";f.reportWarning(0,`The current workspace doesn't seem to require a version bump.${C}`);return}iz(s,E,{report:f,exact:this.exact}),this.dryRun||(p||(this.all?await tz(s):await rz(s,[...E.keys()])),f.reportSeparator())});return this.dryRun||c.hasErrors()?c.exitCode():await s.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:n})}};Ge();Dt();Yt();var UL=ut(Ai());var V1=class extends ft{constructor(){super(...arguments);this.interactive=ge.Boolean(\"-i,--interactive\",{description:\"Open an interactive interface used to set version bumps\"})}static{this.paths=[[\"version\",\"check\"]]}static{this.usage=ot.Usage({category:\"Release-related commands\",description:\"check that all the relevant packages have been bumped\",details:\"\\n      **Warning:** This command currently requires Git.\\n\\n      This command will check that all the packages covered by the files listed in argument have been properly bumped or declined to bump.\\n\\n      In the case of a bump, the check will also cover transitive packages - meaning that should `Foo` be bumped, a package `Bar` depending on `Foo` will require a decision as to whether `Bar` will need to be bumped. This check doesn't cross packages that have declined to bump.\\n\\n      In case no arguments are passed to the function, the list of modified files will be generated by comparing the HEAD against `master`.\\n    \",examples:[[\"Check whether the modified packages need a bump\",\"yarn version check\"]]})}async execute(){return this.interactive?await this.executeInteractive():await this.executeStandard()}async executeInteractive(){iw(this.context);let{Gem:r}=await Promise.resolve().then(()=>(qF(),kW)),{ScrollableItems:s}=await Promise.resolve().then(()=>(JF(),VF)),{FocusRequest:a}=await Promise.resolve().then(()=>(RW(),E2e)),{useListInput:n}=await Promise.resolve().then(()=>(YF(),I2e)),{renderForm:c}=await Promise.resolve().then(()=>(XF(),ZF)),{Box:f,Text:p}=await Promise.resolve().then(()=>ut(Wc())),{default:h,useCallback:E,useState:C}=await Promise.resolve().then(()=>ut(hn())),S=await ze.find(this.context.cwd,this.context.plugins),{project:b,workspace:I}=await Rt.find(S,this.context.cwd);if(!I)throw new ar(b.cwd,this.context.cwd);await b.restoreInstallState();let T=await q1(b);if(T===null||T.releaseRoots.size===0)return 0;if(T.root===null)throw new nt(\"This command can only be run on Git repositories\");let N=()=>h.createElement(f,{flexDirection:\"row\",paddingBottom:1},h.createElement(f,{flexDirection:\"column\",width:60},h.createElement(f,null,h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<up>\"),\"/\",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<down>\"),\" to select workspaces.\")),h.createElement(f,null,h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<left>\"),\"/\",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<right>\"),\" to select release strategies.\"))),h.createElement(f,{flexDirection:\"column\"},h.createElement(f,{marginLeft:1},h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<enter>\"),\" to save.\")),h.createElement(f,{marginLeft:1},h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<ctrl+c>\"),\" to abort.\")))),U=({workspace:me,active:pe,decision:Be,setDecision:Ce})=>{let g=me.manifest.raw.stableVersion??me.manifest.version;if(g===null)throw new Error(`Assertion failed: The version should have been set (${G.prettyLocator(S,me.anchoredLocator)})`);if(UL.default.prerelease(g)!==null)throw new Error(`Assertion failed: Prerelease identifiers shouldn't be found (${g})`);let we=[\"undecided\",\"decline\",\"patch\",\"minor\",\"major\"];n(Be,we,{active:pe,minus:\"left\",plus:\"right\",set:Ce});let ye=Be===\"undecided\"?h.createElement(p,{color:\"yellow\"},g):Be===\"decline\"?h.createElement(p,{color:\"green\"},g):h.createElement(p,null,h.createElement(p,{color:\"magenta\"},g),\" \\u2192 \",h.createElement(p,{color:\"green\"},UL.default.valid(Be)?Be:UL.default.inc(g,Be)));return h.createElement(f,{flexDirection:\"column\"},h.createElement(f,null,h.createElement(p,null,G.prettyLocator(S,me.anchoredLocator),\" - \",ye)),h.createElement(f,null,we.map(Ae=>h.createElement(f,{key:Ae,paddingLeft:2},h.createElement(p,null,h.createElement(r,{active:Ae===Be}),\" \",Ae)))))},W=me=>{let pe=new Set(T.releaseRoots),Be=new Map([...me].filter(([Ce])=>pe.has(Ce)));for(;;){let Ce=ob({project:T.project,releases:Be}),g=!1;if(Ce.length>0){for(let[we]of Ce)if(!pe.has(we)){pe.add(we),g=!0;let ye=me.get(we);typeof ye<\"u\"&&Be.set(we,ye)}}if(!g)break}return{relevantWorkspaces:pe,relevantReleases:Be}},ee=()=>{let[me,pe]=C(()=>new Map(T.releases)),Be=E((Ce,g)=>{let we=new Map(me);g!==\"undecided\"?we.set(Ce,g):we.delete(Ce);let{relevantReleases:ye}=W(we);pe(ye)},[me,pe]);return[me,Be]},ie=({workspaces:me,releases:pe})=>{let Be=[];Be.push(`${me.size} total`);let Ce=0,g=0;for(let we of me){let ye=pe.get(we);typeof ye>\"u\"?g+=1:ye!==\"decline\"&&(Ce+=1)}return Be.push(`${Ce} release${Ce===1?\"\":\"s\"}`),Be.push(`${g} remaining`),h.createElement(p,{color:\"yellow\"},Be.join(\", \"))},le=await c(({useSubmit:me})=>{let[pe,Be]=ee();me(pe);let{relevantWorkspaces:Ce}=W(pe),g=new Set([...Ce].filter(se=>!T.releaseRoots.has(se))),[we,ye]=C(0),Ae=E(se=>{switch(se){case a.BEFORE:ye(we-1);break;case a.AFTER:ye(we+1);break}},[we,ye]);return h.createElement(f,{flexDirection:\"column\"},h.createElement(N,null),h.createElement(f,null,h.createElement(p,{wrap:\"wrap\"},\"The following files have been modified in your local checkout.\")),h.createElement(f,{flexDirection:\"column\",marginTop:1,paddingLeft:2},[...T.changedFiles].map(se=>h.createElement(f,{key:se},h.createElement(p,null,h.createElement(p,{color:\"grey\"},fe.fromPortablePath(T.root)),fe.sep,fe.relative(fe.fromPortablePath(T.root),fe.fromPortablePath(se)))))),T.releaseRoots.size>0&&h.createElement(h.Fragment,null,h.createElement(f,{marginTop:1},h.createElement(p,{wrap:\"wrap\"},\"Because of those files having been modified, the following workspaces may need to be released again (note that private workspaces are also shown here, because even though they won't be published, releasing them will allow us to flag their dependents for potential re-release):\")),g.size>3?h.createElement(f,{marginTop:1},h.createElement(ie,{workspaces:T.releaseRoots,releases:pe})):null,h.createElement(f,{marginTop:1,flexDirection:\"column\"},h.createElement(s,{active:we%2===0,radius:1,size:2,onFocusRequest:Ae},[...T.releaseRoots].map(se=>h.createElement(U,{key:se.cwd,workspace:se,decision:pe.get(se)||\"undecided\",setDecision:X=>Be(se,X)}))))),g.size>0?h.createElement(h.Fragment,null,h.createElement(f,{marginTop:1},h.createElement(p,{wrap:\"wrap\"},\"The following workspaces depend on other workspaces that have been marked for release, and thus may need to be released as well:\")),h.createElement(f,null,h.createElement(p,null,\"(Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<tab>\"),\" to move the focus between the workspace groups.)\")),g.size>5?h.createElement(f,{marginTop:1},h.createElement(ie,{workspaces:g,releases:pe})):null,h.createElement(f,{marginTop:1,flexDirection:\"column\"},h.createElement(s,{active:we%2===1,radius:2,size:2,onFocusRequest:Ae},[...g].map(se=>h.createElement(U,{key:se.cwd,workspace:se,decision:pe.get(se)||\"undecided\",setDecision:X=>Be(se,X)}))))):null)},{versionFile:T},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof le>\"u\")return 1;T.releases.clear();for(let[me,pe]of le)T.releases.set(me,pe);await T.saveAll()}async executeStandard(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);return await s.restoreInstallState(),(await Ot.start({configuration:r,stdout:this.context.stdout},async c=>{let f=await q1(s);if(f===null||f.releaseRoots.size===0)return;if(f.root===null)throw new nt(\"This command can only be run on Git repositories\");if(c.reportInfo(0,`Your PR was started right after ${he.pretty(r,f.baseHash.slice(0,7),\"yellow\")} ${he.pretty(r,f.baseTitle,\"magenta\")}`),f.changedFiles.size>0){c.reportInfo(0,\"You have changed the following files since then:\"),c.reportSeparator();for(let S of f.changedFiles)c.reportInfo(null,`${he.pretty(r,fe.fromPortablePath(f.root),\"gray\")}${fe.sep}${fe.relative(fe.fromPortablePath(f.root),fe.fromPortablePath(S))}`)}let p=!1,h=!1,E=ML(f);if(E.size>0){p||c.reportSeparator();for(let S of E)c.reportError(0,`${G.prettyLocator(r,S.anchoredLocator)} has been modified but doesn't have a release strategy attached`);p=!0}let C=ob(f);for(let[S,b]of C)h||c.reportSeparator(),c.reportError(0,`${G.prettyLocator(r,S.anchoredLocator)} doesn't have a release strategy attached, but depends on ${G.prettyWorkspace(r,b)} which is planned for release.`),h=!0;(p||h)&&(c.reportSeparator(),c.reportInfo(0,\"This command detected that at least some workspaces have received modifications without explicit instructions as to how they had to be released (if needed).\"),c.reportInfo(0,\"To correct these errors, run `yarn version check --interactive` then follow the instructions.\"))})).exitCode()}};Ge();Yt();var _L=ut(Ai());var J1=class extends ft{constructor(){super(...arguments);this.deferred=ge.Boolean(\"-d,--deferred\",{description:\"Prepare the version to be bumped during the next release cycle\"});this.immediate=ge.Boolean(\"-i,--immediate\",{description:\"Bump the version immediately\"});this.strategy=ge.String()}static{this.paths=[[\"version\"]]}static{this.usage=ot.Usage({category:\"Release-related commands\",description:\"apply a new version to the current package\",details:\"\\n      This command will bump the version number for the given package, following the specified strategy:\\n\\n      - If `major`, the first number from the semver range will be increased (`X.0.0`).\\n      - If `minor`, the second number from the semver range will be increased (`0.X.0`).\\n      - If `patch`, the third number from the semver range will be increased (`0.0.X`).\\n      - If prefixed by `pre` (`premajor`, ...), a `-0` suffix will be set (`0.0.0-0`).\\n      - If `prerelease`, the suffix will be increased (`0.0.0-X`); the third number from the semver range will also be increased if there was no suffix in the previous version.\\n      - If `decline`, the nonce will be increased for `yarn version check` to pass without version bump.\\n      - If a valid semver range, it will be used as new version.\\n      - If unspecified, Yarn will ask you for guidance.\\n\\n      For more information about the `--deferred` flag, consult our documentation (https://yarnpkg.com/features/release-workflow#deferred-versioning).\\n    \",examples:[[\"Immediately bump the version to the next major\",\"yarn version major\"],[\"Prepare the version to be bumped to the next major\",\"yarn version major --deferred\"]]})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd);if(!a)throw new ar(s.cwd,this.context.cwd);let n=r.get(\"preferDeferredVersions\");this.deferred&&(n=!0),this.immediate&&(n=!1);let c=_L.default.valid(this.strategy),f=this.strategy===\"decline\",p;if(c)if(a.manifest.version!==null){let E=nz(a.manifest.version,this.strategy);E!==null?p=E:p=this.strategy}else p=this.strategy;else{let E=a.manifest.version;if(!f){if(E===null)throw new nt(\"Can't bump the version if there wasn't a version to begin with - use 0.0.0 as initial version then run the command again.\");if(typeof E!=\"string\"||!_L.default.valid(E))throw new nt(`Can't bump the version (${E}) if it's not valid semver`)}p=dy(this.strategy)}if(!n){let C=(await sb(s)).get(a);if(typeof C<\"u\"&&p!==\"decline\"){let S=ib(a.manifest.version,p);if(_L.default.lt(S,C))throw new nt(`Can't bump the version to one that would be lower than the current deferred one (${C})`)}}let h=await q1(s,{allowEmpty:!0});return h.releases.set(a,p),await h.saveAll(),n?0:await this.cli.run([\"version\",\"apply\"])}};var rbt={configuration:{deferredVersionFolder:{description:\"Folder where are stored the versioning files\",type:\"ABSOLUTE_PATH\",default:\"./.yarn/versions\"},preferDeferredVersions:{description:\"If true, running `yarn version` will assume the `--deferred` flag unless `--immediate` is set\",type:\"BOOLEAN\",default:!1}},commands:[Y1,V1,J1]},nbt=rbt;var oz={};Vt(oz,{WorkspacesFocusCommand:()=>K1,WorkspacesForeachCommand:()=>Z1,default:()=>obt});Ge();Ge();Yt();var K1=class extends ft{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.production=ge.Boolean(\"--production\",!1,{description:\"Only install regular dependencies by omitting dev dependencies\"});this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Install the entire project\"});this.workspaces=ge.Rest()}static{this.paths=[[\"workspaces\",\"focus\"]]}static{this.usage=ot.Usage({category:\"Workspace-related commands\",description:\"install a single workspace and its dependencies\",details:\"\\n      This command will run an install as if the specified workspaces (and all other workspaces they depend on) were the only ones in the project. If no workspaces are explicitly listed, the active one will be assumed.\\n\\n      Note that this command is only very moderately useful when using zero-installs, since the cache will contain all the packages anyway - meaning that the only difference between a full install and a focused install would just be a few extra lines in the `.pnp.cjs` file, at the cost of introducing an extra complexity.\\n\\n      If the `-A,--all` flag is set, the entire project will be installed. Combine with `--production` to replicate the old `yarn install --production`.\\n    \"})}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd),n=await Kr.find(r);await s.restoreInstallState({restoreResolutions:!1});let c;if(this.all)c=new Set(s.workspaces);else if(this.workspaces.length===0){if(!a)throw new ar(s.cwd,this.context.cwd);c=new Set([a])}else c=new Set(this.workspaces.map(f=>s.getWorkspaceByIdent(G.parseIdent(f))));for(let f of c)for(let p of this.production?[\"dependencies\"]:Ut.hardDependencies)for(let h of f.manifest.getForScope(p).values()){let E=s.tryWorkspaceByDescriptor(h);E!==null&&c.add(E)}for(let f of s.workspaces)c.has(f)?this.production&&f.manifest.devDependencies.clear():(f.manifest.installConfig=f.manifest.installConfig||{},f.manifest.installConfig.selfReferences=!1,f.manifest.dependencies.clear(),f.manifest.devDependencies.clear(),f.manifest.peerDependencies.clear(),f.manifest.scripts.clear());return await s.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:n,persistProject:!1})}};Ge();Ge();Ge();Yt();var z1=ut(Go()),fke=ut(Ld());Ul();var Z1=class extends ft{constructor(){super(...arguments);this.from=ge.Array(\"--from\",{description:\"An array of glob pattern idents or paths from which to base any recursion\"});this.all=ge.Boolean(\"-A,--all\",{description:\"Run the command on all workspaces of a project\"});this.recursive=ge.Boolean(\"-R,--recursive\",{description:\"Run the command on the current workspace and all of its recursive dependencies\"});this.worktree=ge.Boolean(\"-W,--worktree\",{description:\"Run the command on all workspaces of the current worktree\"});this.verbose=ge.Counter(\"-v,--verbose\",{description:\"Increase level of logging verbosity up to 2 times\"});this.parallel=ge.Boolean(\"-p,--parallel\",!1,{description:\"Run the commands in parallel\"});this.interlaced=ge.Boolean(\"-i,--interlaced\",!1,{description:\"Print the output of commands in real-time instead of buffering it\"});this.jobs=ge.String(\"-j,--jobs\",{description:\"The maximum number of parallel tasks that the execution will be limited to; or `unlimited`\",validator:h_([fo([\"unlimited\"]),$2(p_(),[d_(),g_(1)])])});this.topological=ge.Boolean(\"-t,--topological\",!1,{description:\"Run the command after all workspaces it depends on (regular) have finished\"});this.topologicalDev=ge.Boolean(\"--topological-dev\",!1,{description:\"Run the command after all workspaces it depends on (regular + dev) have finished\"});this.include=ge.Array(\"--include\",[],{description:\"An array of glob pattern idents or paths; only matching workspaces will be traversed\"});this.exclude=ge.Array(\"--exclude\",[],{description:\"An array of glob pattern idents or paths; matching workspaces won't be traversed\"});this.publicOnly=ge.Boolean(\"--no-private\",{description:\"Avoid running the command on private workspaces\"});this.since=ge.String(\"--since\",{description:\"Only include workspaces that have been changed since the specified ref.\",tolerateBoolean:!0});this.dryRun=ge.Boolean(\"-n,--dry-run\",{description:\"Print the commands that would be run, without actually running them\"});this.commandName=ge.String();this.args=ge.Proxy()}static{this.paths=[[\"workspaces\",\"foreach\"]]}static{this.usage=ot.Usage({category:\"Workspace-related commands\",description:\"run a command on all workspaces\",details:\"\\n      This command will run a given sub-command on current and all its descendant workspaces. Various flags can alter the exact behavior of the command:\\n\\n      - If `-p,--parallel` is set, the commands will be ran in parallel; they'll by default be limited to a number of parallel tasks roughly equal to half your core number, but that can be overridden via `-j,--jobs`, or disabled by setting `-j unlimited`.\\n\\n      - If `-p,--parallel` and `-i,--interlaced` are both set, Yarn will print the lines from the output as it receives them. If `-i,--interlaced` wasn't set, it would instead buffer the output from each process and print the resulting buffers only after their source processes have exited.\\n\\n      - If `-t,--topological` is set, Yarn will only run the command after all workspaces that it depends on through the `dependencies` field have successfully finished executing. If `--topological-dev` is set, both the `dependencies` and `devDependencies` fields will be considered when figuring out the wait points.\\n\\n      - If `-A,--all` is set, Yarn will run the command on all the workspaces of a project.\\n\\n      - If `-R,--recursive` is set, Yarn will find workspaces to run the command on by recursively evaluating `dependencies` and `devDependencies` fields, instead of looking at the `workspaces` fields.\\n\\n      - If `-W,--worktree` is set, Yarn will find workspaces to run the command on by looking at the current worktree.\\n\\n      - If `--from` is set, Yarn will use the packages matching the 'from' glob as the starting point for any recursive search.\\n\\n      - If `--since` is set, Yarn will only run the command on workspaces that have been modified since the specified ref. By default Yarn will use the refs specified by the `changesetBaseRefs` configuration option.\\n\\n      - If `--dry-run` is set, Yarn will explain what it would do without actually doing anything.\\n\\n      - The command may apply to only some workspaces through the use of `--include` which acts as a whitelist. The `--exclude` flag will do the opposite and will be a list of packages that mustn't execute the script. Both flags accept glob patterns (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them. You can also use the `--no-private` flag to avoid running the command in private workspaces.\\n\\n      The `-v,--verbose` flag can be passed up to twice: once to prefix output lines with the originating workspace's name, and again to include start/finish/timing log lines. Maximum verbosity is enabled by default in terminal environments.\\n\\n      If the command is `run` and the script being run does not exist the child workspace will be skipped without error.\\n    \",examples:[[\"Publish all packages\",\"yarn workspaces foreach -A --no-private npm publish --tolerate-republish\"],[\"Run the build script on all descendant packages\",\"yarn workspaces foreach -A run build\"],[\"Run the build script on current and all descendant packages in parallel, building package dependencies first\",\"yarn workspaces foreach -Apt run build\"],[\"Run the build script on several packages and all their dependencies, building dependencies first\",\"yarn workspaces foreach -Rpt --from '{workspace-a,workspace-b}' run build\"]]})}static{this.schema=[tB(\"all\",qf.Forbids,[\"from\",\"recursive\",\"since\",\"worktree\"],{missingIf:\"undefined\"}),m_([\"all\",\"recursive\",\"since\",\"worktree\"],{missingIf:\"undefined\"})]}async execute(){let r=await ze.find(this.context.cwd,this.context.plugins),{project:s,workspace:a}=await Rt.find(r,this.context.cwd);if(!this.all&&!a)throw new ar(s.cwd,this.context.cwd);await s.restoreInstallState();let n=this.cli.process([this.commandName,...this.args]),c=n.path.length===1&&n.path[0]===\"run\"&&typeof n.scriptName<\"u\"?n.scriptName:null;if(n.path.length===0)throw new nt(\"Invalid subcommand name for iteration - use the 'run' keyword if you wish to execute a script\");let f=Ce=>{this.dryRun&&this.context.stdout.write(`${Ce}\n`)},p=()=>{let Ce=this.from.map(g=>z1.default.matcher(g));return s.workspaces.filter(g=>{let we=G.stringifyIdent(g.anchoredLocator),ye=g.relativeCwd;return Ce.some(Ae=>Ae(we)||Ae(ye))})},h=[];if(this.since?(f(\"Option --since is set; selecting the changed workspaces as root for workspace selection\"),h=Array.from(await ka.fetchChangedWorkspaces({ref:this.since,project:s}))):this.from?(f(\"Option --from is set; selecting the specified workspaces\"),h=[...p()]):this.worktree?(f(\"Option --worktree is set; selecting the current workspace\"),h=[a]):this.recursive?(f(\"Option --recursive is set; selecting the current workspace\"),h=[a]):this.all&&(f(\"Option --all is set; selecting all workspaces\"),h=[...s.workspaces]),this.dryRun&&!this.all){for(let Ce of h)f(`\n- ${Ce.relativeCwd}\n  ${G.prettyLocator(r,Ce.anchoredLocator)}`);h.length>0&&f(\"\")}let E;if(this.recursive?this.since?(f(\"Option --recursive --since is set; recursively selecting all dependent workspaces\"),E=new Set(h.map(Ce=>[...Ce.getRecursiveWorkspaceDependents()]).flat())):(f(\"Option --recursive is set; recursively selecting all transitive dependencies\"),E=new Set(h.map(Ce=>[...Ce.getRecursiveWorkspaceDependencies()]).flat())):this.worktree?(f(\"Option --worktree is set; recursively selecting all nested workspaces\"),E=new Set(h.map(Ce=>[...Ce.getRecursiveWorkspaceChildren()]).flat())):E=null,E!==null&&(h=[...new Set([...h,...E])],this.dryRun))for(let Ce of E)f(`\n- ${Ce.relativeCwd}\n  ${G.prettyLocator(r,Ce.anchoredLocator)}`);let C=[],S=!1;if(c?.includes(\":\")){for(let Ce of s.workspaces)if(Ce.manifest.scripts.has(c)&&(S=!S,S===!1))break}for(let Ce of h){if(c&&!Ce.manifest.scripts.has(c)&&!S&&!(await In.getWorkspaceAccessibleBinaries(Ce)).has(c)){f(`Excluding ${Ce.relativeCwd} because it doesn't have a \"${c}\" script`);continue}if(!(c===r.env.npm_lifecycle_event&&Ce.cwd===a.cwd)){if(this.include.length>0&&!z1.default.isMatch(G.stringifyIdent(Ce.anchoredLocator),this.include)&&!z1.default.isMatch(Ce.relativeCwd,this.include)){f(`Excluding ${Ce.relativeCwd} because it doesn't match the --include filter`);continue}if(this.exclude.length>0&&(z1.default.isMatch(G.stringifyIdent(Ce.anchoredLocator),this.exclude)||z1.default.isMatch(Ce.relativeCwd,this.exclude))){f(`Excluding ${Ce.relativeCwd} because it matches the --exclude filter`);continue}if(this.publicOnly&&Ce.manifest.private===!0){f(`Excluding ${Ce.relativeCwd} because it's a private workspace and --no-private was set`);continue}C.push(Ce)}}if(this.dryRun)return 0;let b=this.verbose??(this.context.stdout.isTTY?1/0:0),I=b>0,T=b>1,N=this.parallel?this.jobs===\"unlimited\"?1/0:Number(this.jobs)||Math.ceil(fs.availableParallelism()/2):1,U=N===1?!1:this.parallel,W=U?this.interlaced:!0,ee=(0,fke.default)(N),ie=new Map,ue=new Set,le=0,me=null,pe=!1,Be=await Ot.start({configuration:r,stdout:this.context.stdout,includePrefix:!1},async Ce=>{let g=async(we,{commandIndex:ye})=>{if(pe)return-1;!U&&T&&ye>1&&Ce.reportSeparator();let Ae=ibt(we,{configuration:r,label:I,commandIndex:ye}),[se,X]=uke(Ce,{prefix:Ae,interlaced:W}),[De,Te]=uke(Ce,{prefix:Ae,interlaced:W});try{T&&Ce.reportInfo(null,`${Ae?`${Ae} `:\"\"}Process started`);let mt=Date.now(),j=await this.cli.run([this.commandName,...this.args],{cwd:we.cwd,stdout:se,stderr:De})||0;se.end(),De.end(),await X,await Te;let rt=Date.now();if(T){let Fe=r.get(\"enableTimers\")?`, completed in ${he.pretty(r,rt-mt,he.Type.DURATION)}`:\"\";Ce.reportInfo(null,`${Ae?`${Ae} `:\"\"}Process exited (exit code ${j})${Fe}`)}return j===130&&(pe=!0,me=j),j}catch(mt){throw se.end(),De.end(),await X,await Te,mt}};for(let we of C)ie.set(we.anchoredLocator.locatorHash,we);for(;ie.size>0&&!Ce.hasErrors();){let we=[];for(let[X,De]of ie){if(ue.has(De.anchoredDescriptor.descriptorHash))continue;let Te=!0;if(this.topological||this.topologicalDev){let mt=this.topologicalDev?new Map([...De.manifest.dependencies,...De.manifest.devDependencies]):De.manifest.dependencies;for(let j of mt.values()){let rt=s.tryWorkspaceByDescriptor(j);if(Te=rt===null||!ie.has(rt.anchoredLocator.locatorHash),!Te)break}}if(Te&&(ue.add(De.anchoredDescriptor.descriptorHash),we.push(ee(async()=>{let mt=await g(De,{commandIndex:++le});return ie.delete(X),ue.delete(De.anchoredDescriptor.descriptorHash),{workspace:De,exitCode:mt}})),!U))break}if(we.length===0){let X=Array.from(ie.values()).map(De=>G.prettyLocator(r,De.anchoredLocator)).join(\", \");Ce.reportError(3,`Dependency cycle detected (${X})`);return}let ye=await Promise.all(we);ye.forEach(({workspace:X,exitCode:De})=>{De!==0&&Ce.reportError(0,`The command failed in workspace ${G.prettyLocator(r,X.anchoredLocator)} with exit code ${De}`)});let se=ye.map(X=>X.exitCode).find(X=>X!==0);(this.topological||this.topologicalDev)&&typeof se<\"u\"&&Ce.reportError(0,\"The command failed for workspaces that are depended upon by other workspaces; can't satisfy the dependency graph\")}});return me!==null?me:Be.exitCode()}};function uke(t,{prefix:e,interlaced:r}){let s=t.createStreamReporter(e),a=new je.DefaultStream;a.pipe(s,{end:!1}),a.on(\"finish\",()=>{s.end()});let n=new Promise(f=>{s.on(\"finish\",()=>{f(a.active)})});if(r)return[a,n];let c=new je.BufferStream;return c.pipe(a,{end:!1}),c.on(\"finish\",()=>{a.end()}),[c,n]}function ibt(t,{configuration:e,commandIndex:r,label:s}){if(!s)return null;let n=`[${G.stringifyIdent(t.anchoredLocator)}]:`,c=[\"#2E86AB\",\"#A23B72\",\"#F18F01\",\"#C73E1D\",\"#CCE2A3\"],f=c[r%c.length];return he.pretty(e,n,f)}var sbt={commands:[K1,Z1]},obt=sbt;var uz={};Vt(uz,{default:()=>ubt});Ge();Ge();var az=\"catalog:\";var lz=t=>t.startsWith(az),abt=t=>t.range.slice(az.length)||null,Ake=t=>t===null?\"default catalog\":`catalog \"${t}\"`,lbt=t=>t.scope?`@${t.scope}/${t.name}`:t.name,cz=(t,e,r,s)=>{let a=abt(e),n;if(a===null)n=t.configuration.get(\"catalog\");else try{let E=t.configuration.get(\"catalogs\");E&&(n=E.get(a))}catch{n=void 0}if(!n||n.size===0)throw new jt(82,`${G.prettyDescriptor(t.configuration,e)}: ${Ake(a)} not found or empty`);let c=lbt(e),f=n.get(c);if(!f)throw new jt(82,`${G.prettyDescriptor(t.configuration,e)}: entry not found in ${Ake(a)}`);let p=t.configuration.normalizeDependency(G.makeDescriptor(e,f));return r.bindDescriptor(p,t.topLevelWorkspace.anchoredLocator,s)};var cbt={configuration:{catalog:{description:\"The default catalog of packages\",type:\"MAP\",valueDefinition:{description:\"The catalog of packages\",type:\"STRING\"}},catalogs:{description:\"Named catalogs of packages\",type:\"MAP\",valueDefinition:{description:\"A named catalog\",type:\"MAP\",valueDefinition:{description:\"Package version in the catalog\",type:\"STRING\"}}}},hooks:{beforeWorkspacePacking:(t,e)=>{let r=t.project,s=r.configuration.makeResolver(),a={project:r,resolver:s,report:new ki};for(let n of Ut.allDependencies){let c=e[n];if(c)for(let[f,p]of Object.entries(c)){if(typeof p!=\"string\"||!lz(p))continue;let h=G.parseIdent(f),E=G.makeDescriptor(h,p),C=cz(r,E,s,a),{protocol:S,source:b,params:I,selector:T}=G.parseRange(G.convertToManifestRange(C.range));S===t.project.configuration.get(\"defaultProtocol\")&&(S=null),c[f]=G.makeRange({protocol:S,source:b,params:I,selector:T})}}},reduceDependency:async(t,e,r,s,{resolver:a,resolveOptions:n})=>lz(t.range)?cz(e,t,a,n):t}},ubt=cbt;var tC=()=>({modules:new Map([[\"@yarnpkg/cli\",Gv],[\"@yarnpkg/core\",jv],[\"@yarnpkg/fslib\",_2],[\"@yarnpkg/libzip\",fv],[\"@yarnpkg/parsers\",J2],[\"@yarnpkg/shell\",mv],[\"clipanion\",oB],[\"semver\",fbt],[\"typanion\",Ea],[\"@yarnpkg/plugin-essentials\",f5],[\"@yarnpkg/plugin-compat\",d5],[\"@yarnpkg/plugin-constraints\",T5],[\"@yarnpkg/plugin-dlx\",F5],[\"@yarnpkg/plugin-exec\",L5],[\"@yarnpkg/plugin-file\",U5],[\"@yarnpkg/plugin-git\",u5],[\"@yarnpkg/plugin-github\",j5],[\"@yarnpkg/plugin-http\",G5],[\"@yarnpkg/plugin-init\",q5],[\"@yarnpkg/plugin-interactive-tools\",HW],[\"@yarnpkg/plugin-jsr\",GW],[\"@yarnpkg/plugin-link\",qW],[\"@yarnpkg/plugin-nm\",PY],[\"@yarnpkg/plugin-npm\",PK],[\"@yarnpkg/plugin-npm-cli\",OK],[\"@yarnpkg/plugin-pack\",IV],[\"@yarnpkg/plugin-patch\",GK],[\"@yarnpkg/plugin-pnp\",gY],[\"@yarnpkg/plugin-pnpm\",YK],[\"@yarnpkg/plugin-stage\",$K],[\"@yarnpkg/plugin-typescript\",ez],[\"@yarnpkg/plugin-version\",sz],[\"@yarnpkg/plugin-workspace-tools\",oz],[\"@yarnpkg/plugin-catalog\",uz]]),plugins:new Set([\"@yarnpkg/plugin-essentials\",\"@yarnpkg/plugin-compat\",\"@yarnpkg/plugin-constraints\",\"@yarnpkg/plugin-dlx\",\"@yarnpkg/plugin-exec\",\"@yarnpkg/plugin-file\",\"@yarnpkg/plugin-git\",\"@yarnpkg/plugin-github\",\"@yarnpkg/plugin-http\",\"@yarnpkg/plugin-init\",\"@yarnpkg/plugin-interactive-tools\",\"@yarnpkg/plugin-jsr\",\"@yarnpkg/plugin-link\",\"@yarnpkg/plugin-nm\",\"@yarnpkg/plugin-npm\",\"@yarnpkg/plugin-npm-cli\",\"@yarnpkg/plugin-pack\",\"@yarnpkg/plugin-patch\",\"@yarnpkg/plugin-pnp\",\"@yarnpkg/plugin-pnpm\",\"@yarnpkg/plugin-stage\",\"@yarnpkg/plugin-typescript\",\"@yarnpkg/plugin-version\",\"@yarnpkg/plugin-workspace-tools\",\"@yarnpkg/plugin-catalog\"])});function gke({cwd:t,pluginConfiguration:e}){let r=new Ca({binaryLabel:\"Yarn Package Manager\",binaryName:\"yarn\",binaryVersion:fn??\"<unknown>\"});return Object.assign(r,{defaultContext:{...Ca.defaultContext,cwd:t,plugins:e,quiet:!1,stdin:process.stdin,stdout:process.stdout,stderr:process.stderr}})}function Abt(t){if(je.parseOptionalBoolean(process.env.YARN_IGNORE_NODE))return!0;let r=process.versions.node,s=\">=18.12.0\";if(Fr.satisfiesWithPrereleases(r,s))return!0;let a=new nt(`This tool requires a Node version compatible with ${s} (got ${r}). Upgrade Node, or set \\`YARN_IGNORE_NODE=1\\` in your environment.`);return Ca.defaultContext.stdout.write(t.error(a)),!1}async function dke({selfPath:t,pluginConfiguration:e}){return await ze.find(fe.toPortablePath(process.cwd()),e,{strict:!1,usePathCheck:t})}function pbt(t,e,{yarnPath:r}){if(!ce.existsSync(r))return t.error(new Error(`The \"yarn-path\" option has been set, but the specified location doesn't exist (${r}).`)),1;process.on(\"SIGINT\",()=>{});let s={stdio:\"inherit\",env:{...process.env,YARN_IGNORE_PATH:\"1\"}};try{(0,pke.execFileSync)(process.execPath,[fe.fromPortablePath(r),...e],s)}catch(a){return a.status??1}return 0}function hbt(t,e){let r=null,s=e;return e.length>=2&&e[0]===\"--cwd\"?(r=fe.toPortablePath(e[1]),s=e.slice(2)):e.length>=1&&e[0].startsWith(\"--cwd=\")?(r=fe.toPortablePath(e[0].slice(6)),s=e.slice(1)):e[0]===\"add\"&&e[e.length-2]===\"--cwd\"&&(r=fe.toPortablePath(e[e.length-1]),s=e.slice(0,e.length-2)),t.defaultContext.cwd=r!==null?J.resolve(r):J.cwd(),s}function gbt(t,{configuration:e}){if(!e.get(\"enableTelemetry\")||hke.isCI||!process.stdout.isTTY)return;ze.telemetry=new XI(e,\"puba9cdc10ec5790a2cf4969dd413a47270\");let s=/^@yarnpkg\\/plugin-(.*)$/;for(let a of e.plugins.keys())$I.has(a.match(s)?.[1]??\"\")&&ze.telemetry?.reportPluginName(a);t.binaryVersion&&ze.telemetry.reportVersion(t.binaryVersion)}function mke(t,{configuration:e}){for(let r of e.plugins.values())for(let s of r.commands||[])t.register(s)}async function dbt(t,e,{selfPath:r,pluginConfiguration:s}){if(!Abt(t))return 1;let a=await dke({selfPath:r,pluginConfiguration:s}),n=a.get(\"yarnPath\"),c=a.get(\"ignorePath\");if(n&&!c)return pbt(t,e,{yarnPath:n});delete process.env.YARN_IGNORE_PATH;let f=hbt(t,e);gbt(t,{configuration:a}),mke(t,{configuration:a});let p=t.process(f,t.defaultContext);return p.help||ze.telemetry?.reportCommandName(p.path.join(\" \")),await t.run(p,t.defaultContext)}async function Bde({cwd:t=J.cwd(),pluginConfiguration:e=tC()}={}){let r=gke({cwd:t,pluginConfiguration:e}),s=await dke({pluginConfiguration:e,selfPath:null});return mke(r,{configuration:s}),r}async function YT(t,{cwd:e=J.cwd(),selfPath:r,pluginConfiguration:s}){let a=gke({cwd:e,pluginConfiguration:s});function n(){Ca.defaultContext.stdout.write(`ERROR: Yarn is terminating due to an unexpected empty event loop.\nPlease report this issue at https://github.com/yarnpkg/berry/issues.`)}process.once(\"beforeExit\",n);try{process.exitCode=42,process.exitCode=await dbt(a,t,{selfPath:r,pluginConfiguration:s})}catch(c){Ca.defaultContext.stdout.write(a.error(c)),process.exitCode=1}finally{process.off(\"beforeExit\",n),await ce.rmtempPromise()}}YT(process.argv.slice(2),{cwd:J.cwd(),selfPath:fe.toPortablePath(fe.resolve(process.argv[1])),pluginConfiguration:tC()});})();\n/**\n  @license\n  Copyright (c) 2015, Rebecca Turner\n\n  Permission to use, copy, modify, and/or distribute this software for any\n  purpose with or without fee is hereby granted, provided that the above\n  copyright notice and this permission notice appear in all copies.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\n  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND\n  FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\n  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\n  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\n  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\n  PERFORMANCE OF THIS SOFTWARE.\n */\n/**\n  @license\n  Copyright Node.js contributors. All rights reserved.\n\n  Permission is hereby granted, free of charge, to any person obtaining a copy\n  of this software and associated documentation files (the \"Software\"), to\n  deal in the Software without restriction, including without limitation the\n  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n  sell copies of the Software, and to permit persons to whom the Software is\n  furnished to do so, subject to the following conditions:\n\n  The above copyright notice and this permission notice shall be included in\n  all copies or substantial portions of the Software.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n  IN THE SOFTWARE.\n*/\n/**\n  @license\n  The MIT License (MIT)\n\n  Copyright (c) 2014 Blake Embrey (hello@blakeembrey.com)\n\n  Permission is hereby granted, free of charge, to any person obtaining a copy\n  of this software and associated documentation files (the \"Software\"), to deal\n  in the Software without restriction, including without limitation the rights\n  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  copies of the Software, and to permit persons to whom the Software is\n  furnished to do so, subject to the following conditions:\n\n  The above copyright notice and this permission notice shall be included in\n  all copies or substantial portions of the Software.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  THE SOFTWARE.\n*/\n/**\n  @license\n  Copyright Joyent, Inc. and other Node contributors.\n\n  Permission is hereby granted, free of charge, to any person obtaining a\n  copy of this software and associated documentation files (the\n  \"Software\"), to deal in the Software without restriction, including\n  without limitation the rights to use, copy, modify, merge, publish,\n  distribute, sublicense, and/or sell copies of the Software, and to permit\n  persons to whom the Software is furnished to do so, subject to the\n  following conditions:\n\n  The above copyright notice and this permission notice shall be included\n  in all copies or substantial portions of the Software.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n  NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n  OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n  USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n/*! Bundled license information:\n\nis-number/index.js:\n  (*!\n   * is-number <https://github.com/jonschlinkert/is-number>\n   *\n   * Copyright (c) 2014-present, Jon Schlinkert.\n   * Released under the MIT License.\n   *)\n\nto-regex-range/index.js:\n  (*!\n   * to-regex-range <https://github.com/micromatch/to-regex-range>\n   *\n   * Copyright (c) 2015-present, Jon Schlinkert.\n   * Released under the MIT License.\n   *)\n\nfill-range/index.js:\n  (*!\n   * fill-range <https://github.com/jonschlinkert/fill-range>\n   *\n   * Copyright (c) 2014-present, Jon Schlinkert.\n   * Licensed under the MIT License.\n   *)\n\nis-extglob/index.js:\n  (*!\n   * is-extglob <https://github.com/jonschlinkert/is-extglob>\n   *\n   * Copyright (c) 2014-2016, Jon Schlinkert.\n   * Licensed under the MIT License.\n   *)\n\nis-glob/index.js:\n  (*!\n   * is-glob <https://github.com/jonschlinkert/is-glob>\n   *\n   * Copyright (c) 2014-2017, Jon Schlinkert.\n   * Released under the MIT License.\n   *)\n\nqueue-microtask/index.js:\n  (*! queue-microtask. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> *)\n\nrun-parallel/index.js:\n  (*! run-parallel. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> *)\n\ngit-url-parse/lib/index.js:\n  (*!\n   * buildToken\n   * Builds OAuth token prefix (helper function)\n   *\n   * @name buildToken\n   * @function\n   * @param {GitUrl} obj The parsed Git url object.\n   * @return {String} token prefix\n   *)\n\nobject-assign/index.js:\n  (*\n  object-assign\n  (c) Sindre Sorhus\n  @license MIT\n  *)\n\nreact/cjs/react.production.min.js:\n  (** @license React v17.0.2\n   * react.production.min.js\n   *\n   * Copyright (c) Facebook, Inc. and its affiliates.\n   *\n   * This source code is licensed under the MIT license found in the\n   * LICENSE file in the root directory of this source tree.\n   *)\n\nscheduler/cjs/scheduler.production.min.js:\n  (** @license React v0.20.2\n   * scheduler.production.min.js\n   *\n   * Copyright (c) Facebook, Inc. and its affiliates.\n   *\n   * This source code is licensed under the MIT license found in the\n   * LICENSE file in the root directory of this source tree.\n   *)\n\nreact-reconciler/cjs/react-reconciler.production.min.js:\n  (** @license React v0.26.2\n   * react-reconciler.production.min.js\n   *\n   * Copyright (c) Facebook, Inc. and its affiliates.\n   *\n   * This source code is licensed under the MIT license found in the\n   * LICENSE file in the root directory of this source tree.\n   *)\n\nis-windows/index.js:\n  (*!\n   * is-windows <https://github.com/jonschlinkert/is-windows>\n   *\n   * Copyright © 2015-2018, Jon Schlinkert.\n   * Released under the MIT License.\n   *)\n*/\n"
  },
  {
    "path": ".yarnrc.yml",
    "content": "compressionLevel: 0\n\nenableGlobalCache: true\n\ninstallStatePath: ./.yarn/root-install-state.gz\n\nlogFilters:\n  - code: YN0007\n    level: discard\n  - code: YN0005\n    level: discard\n  - code: YN0076\n    level: discard\n\nnodeLinker: node-modules\n\nnpmPublishAccess: public\n\ntsEnableAutoTypes: true\n\nnpmRegistryServer: \"https://registry.yarnpkg.com\"\n\n# See https://github.com/nrwl/nx/issues/22177\n# This is a workaround for a yarn berry issue and remote caching in NX.\nsupportedArchitectures:\n  cpu:\n    - current\n    - x64\n    - arm64\n  os:\n    - current\n    - linux\n    - darwin\n\nunsafeHttpWhitelist:\n  - localhost\n\nyarnPath: .yarn/releases/yarn-4.10.3.cjs\n"
  },
  {
    "path": "AGENTS.md",
    "content": "# Storybook Agent Instructions\n\nKeep this file, `AGENTS.md`, up to date when Storybook's architecture, tooling, workflows, or contributor guidance changes.\n\nThis file is the canonical instruction source for coding agents. Files like `CLAUDE.md` should point here instead of duplicating instructions.\n\n## Repository Overview\n\nStorybook is a large TypeScript monorepo. The git root is the repo root, the main code lives in `code/`, and build tooling lives in `scripts/`. The default branch is `next`.\n\n- **Base branch**: `next` (all PRs should target `next`, not `main`)\n- **Node.js**: `22.21.1` (see `.nvmrc`)\n- **Package Manager**: Yarn Berry\n- **Task orchestration**: NX plus the custom `yarn task` runner\n- **CI environment**: Linux and Windows\n\n## Repository Structure\n\n```text\nstorybook/\n├── .github/                      # GitHub configs and workflows\n├── .nx/                          # NX workflow state\n├── code/                         # Main codebase\n│   ├── .storybook/               # Internal Storybook UI config\n│   ├── core/                     # Core package published as \"storybook\"\n│   ├── addons/                   # Core addons\n│   ├── builders/                 # Builder integrations\n│   ├── renderers/                # Renderer integrations\n│   ├── frameworks/               # Framework integrations\n│   ├── lib/                      # Supporting libraries\n│   ├── presets/                  # Webpack-oriented presets\n│   └── sandbox/                  # Internal build artifacts\n├── scripts/                      # Build and development scripts\n├── docs/                         # Documentation\n├── test-storybooks/              # Test repos\n└── ../storybook-sandboxes/       # Generated sandboxes outside repo\n```\n\n## Architecture\n\n### Renderer vs builder vs framework\n\n| Concept   | Role                                  | Example                   |\n| --------- | ------------------------------------- | ------------------------- |\n| Renderer  | Mounts UI framework to the DOM        | `@storybook/react`        |\n| Builder   | Bundles and serves Storybook          | `@storybook/builder-vite` |\n| Framework | Renderer + builder + framework config | `@storybook/react-vite`   |\n\n### Core package\n\nThe main package is `code/core/src/`. The most important areas are:\n\n- `core-server/` for dev server, static build, and presets\n- `manager/` and `manager-api/` for the Storybook UI\n- `preview/` and `preview-api/` for story rendering\n- `channels/` for manager <-> preview communication\n- `csf-tools/` for AST-based story indexing\n- `common/` for shared Node.js utilities\n- `test/` and `instrumenter/` for testing support\n\nPublic exports include:\n\n- `storybook/actions`\n- `storybook/preview-api`\n- `storybook/manager-api`\n- `storybook/theming`\n- `storybook/test`\n\nInternal exports include:\n\n- `storybook/internal/core-server`\n- `storybook/internal/csf-tools`\n- `storybook/internal/common`\n- `storybook/internal/channels`\n\n### Key flow\n\n- `.storybook/main.ts` is loaded at startup\n- `.storybook/preview.ts` is bundled into preview\n- `.storybook/manager.ts` is bundled into manager\n- `*.stories.*` files are indexed by AST before runtime\n- Story selection loads the module, prepares the story, and renders it\n\nAST indexing keeps the sidebar fast and prevents one broken story file from breaking the whole UI.\n\n## Common Commands\n\nRun commands from the repository root unless stated otherwise.\n\nFor routine agent work, prefer the faster non-production commands first. Add `-c production` only when you need sandbox-related NX tasks or you are explicitly matching CI behavior.\n\n### Install and compile\n\n```bash\nyarn\nyarn task compile\nyarn nx run-many -t compile\nyarn nx compile <package-name>\n```\n\n### Lint and typecheck\n\n```bash\nyarn lint\nyarn --cwd code lint:js:cmd <file-relative-to-code-folder> --fix\nyarn task check\nyarn nx run-many -t check\n```\n\n### Development and tests\n\n```bash\ncd code && yarn storybook:ui\ncd code && yarn storybook:ui:build\nyarn test\nyarn test:watch\nyarn storybook:vitest\n```\n\n### Common task scenarios\n\n| Scenario                        | Command                                                                        |\n| ------------------------------- | ------------------------------------------------------------------------------ |\n| Compile everything quickly      | `yarn nx run-many -t compile`                                                  |\n| Compile one package             | `yarn nx compile <package-name>`                                               |\n| Check TypeScript errors quickly | `yarn nx run-many -t check`                                                    |\n| Start the internal Storybook UI | `cd code && yarn storybook:ui`                                                 |\n| Build the internal Storybook UI | `cd code && yarn storybook:ui:build`                                           |\n| Run unit tests                  | `yarn test`                                                                    |\n| Run Storybook Vitest tests      | `yarn storybook:vitest`                                                        |\n| Generate a sandbox              | `yarn task sandbox --template react-vite/default-ts --start-from auto`         |\n| Run sandbox E2E tests           | `yarn task e2e-tests-dev --template react-vite/default-ts --start-from auto`   |\n| Run sandbox test-runner tests   | `yarn task test-runner-dev --template react-vite/default-ts --start-from auto` |\n\n## NX and `yarn task`\n\nUse NX when you want better caching and dependency tracking. Prefer these faster defaults first, and only add `-c production` or `--no-link` when you specifically need sandbox parity or CI-like behavior.\n\n```bash\n# Compile all packages\nyarn task compile\nyarn nx run-many -t compile\n\n# Check all packages\nyarn task check\nyarn nx run-many -t check\n\n# Run E2E tests for a template\nyarn task e2e-tests-dev --template react-vite/default-ts --start-from auto\nyarn nx e2e-tests-dev react-vite/default-ts -c production\n\n# Jump to a later step\nyarn task e2e-tests-dev --start-from e2e-tests --template react-vite/default-ts\nyarn nx e2e-tests-dev -c production --exclude-task-dependencies\n```\n\nKey points:\n\n- `-c production` is required for sandbox-related NX commands and CI-parity runs\n- `react-vite/default-ts` is the default sandbox template\n- `--no-link` is opt-in, not the default\n- NX handles task dependencies via `nx.json`\n\n## Sandbox Notes\n\nSandboxes are generated outside the repository at `../storybook-sandboxes/` by default.\n\n- `STORYBOOK_SANDBOX_ROOT=./sandbox` forces local output, but is usually not preferred\n- `./sandbox` inside the repo mainly exists for NX outputs, not CI sandboxes\n- If sandbox generation fails, fall back to `cd code && yarn storybook:ui`\n\nGenerate and use a sandbox with the same `sandbox` command shape used elsewhere in this file:\n\n```bash\nyarn task sandbox --template react-vite/default-ts --start-from auto\n# Same sandbox step via NX\nyarn nx sandbox react-vite/default-ts -c production\ncd ../storybook-sandboxes/react-vite-default-ts\nyarn install\nyarn storybook\n```\n\nCommon templates:\n\n- `react-vite/default-ts`\n- `react-webpack/default-ts`\n- `angular-cli/default-ts`\n- `svelte-vite/default-ts`\n- `vue3-vite/default-ts`\n- `nextjs/default-ts`\n\n## How To Work In This Repo\n\n### For normal code changes\n\n1. Install if needed: `yarn`\n2. Compile with NX: `yarn nx run-many -t compile`\n3. Make changes\n4. Recompile affected packages\n5. Validate there are no TypeScript errors with `yarn nx run-many -t check`\n6. Run relevant lint and tests\n7. Validate behavior in the internal Storybook UI first, then switch to sandbox or `-c production` flows only if you need template or CI parity\n\n### For addon, framework, or renderer work\n\n1. Edit the relevant package under `code/addons/`, `code/frameworks/`, or `code/renderers/`\n2. Recompile with NX, starting without `-c production`\n3. Generate a matching sandbox\n4. Run the relevant test-runner, E2E, or Storybook UI validation flow\n\n## Testing Expectations\n\n- Use `yarn test` for unit tests\n- Use Storybook UI or Chromatic for visual validation\n- Use `yarn task e2e-tests --start-from auto` or `yarn task e2e-tests-dev --start-from auto` for E2E coverage\n- Use `yarn task test-runner --start-from auto` or `yarn task test-runner-dev --start-from auto` for test-runner scenarios\n- Use `yarn task smoke-test --start-from auto` for smoke checks\n\nWatch-mode commands:\n\n```bash\nyarn test:watch\nyarn storybook:vitest\n```\n\nWhen writing tests:\n\n- Export functions that need direct tests\n- Test real behavior, not just syntax patterns\n- Use coverage when useful: `yarn vitest run --coverage <test-file>`\n- Mock external dependencies like file system access and loggers\n\n## Quality and Logging\n\nAfter changing files:\n\n1. Format with `cd code && oxfmt`\n2. Lint with `yarn --cwd code lint:js:cmd <file-relative-to-code-folder> --fix` or `cd code && yarn lint:js:cmd <file-relative-to-code-folder>`\n3. Run relevant tests before submitting a PR\n\nUse Storybook loggers instead of raw `console.*` in normal code paths:\n\n- Server-side: `storybook/internal/node-logger`\n- Client-side: `storybook/internal/client-logger`\n\nFor TypeScript source in the repo, prefer explicit file extensions for relative code imports and exports such as `./foo.ts` or `./bar.tsx` when the target is another TS/JS module in this repository. Keep framework-specific component imports like `.vue` and `.svelte` in the form already expected by their package tooling.\n\nThe pre-commit hook automatically detects AI agents (via `std-env`) and switches from check-only to write mode, so formatting is auto-fixed when agents commit.\n\nAvoid `console.log`, `console.warn`, and `console.error` unless the file is isolated enough that importing the logger is not reasonable.\n\n## Troubleshooting\n\n- Build failures are often fixed by rerunning `yarn` and `yarn nx run-many -t compile`\n- Storybook UI uses port `6006` by default\n- Large compiles may require more Node.js memory\n- Sandbox paths are `../storybook-sandboxes/`, not `./sandbox` or `code/sandbox/`\n- Use `--debug` for verbose CLI output\n- Check generated sandbox directories and `.cache/` for build artifacts\n\n## Environment Variables\n\n| Variable                      | Purpose                     |\n| ----------------------------- | --------------------------- |\n| `IN_STORYBOOK_SANDBOX`        | Set during sandbox creation |\n| `STORYBOOK_DISABLE_TELEMETRY` | Disable telemetry           |\n| `STORYBOOK_TELEMETRY_DEBUG`   | Log telemetry events        |\n| `DEBUG`                       | Enable debug logging        |\n\n## Commands To Avoid\n\n- **DO NOT RUN** `yarn task dev` without an explicit sandbox template\n- **DO NOT RUN** `yarn start`\n\nThese usually start long-running development servers and are the wrong default for agents.\n\n## Maintenance Rules For Agents\n\n- Use this file as the canonical instruction source\n- Update `AGENTS.md` when architecture, commands, versions, release flows, or contributor guidance changes\n- Keep `CLAUDE.md` and other agent entrypoints as thin references to `AGENTS.md`\n- Do not reintroduce duplicated instruction files when a reference will do\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## 10.3.3\n\n- Addon-Vitest: Streamline vite(st) config detection across init and postinstall - [#34193](https://github.com/storybookjs/storybook/pull/34193), thanks @valentinpalkovic!\n\n## 10.3.2\n\n- CLI: Shorten CTA link messages - [#34236](https://github.com/storybookjs/storybook/pull/34236), thanks @shilman!\n- React Native Web: Fix vite8 support by bumping vite-plugin-rnw - [#34231](https://github.com/storybookjs/storybook/pull/34231), thanks @dannyhw!\n\n## 10.3.1\n\n- CLI: Use npm info to fetch versions in repro command - [#34214](https://github.com/storybookjs/storybook/pull/34214), thanks @yannbf!\n- Core: Prevent story-local viewport from persisting in URL - [#34153](https://github.com/storybookjs/storybook/pull/34153), thanks @ghengeveld!\n\n## 10.3.0\n\n_> Improved developer experience, AI-assisting tools, and broader ecosystem support_\n\nStorybook 10.3 contains hundreds of fixes and improvements including:\n\n- 🤖 Storybook MCP: Agentic component dev, docs, and test (Preview release for React)\n- ⚡ Vite 8 support\n- ▲ Next.js 16.2 support\n- 📝 ESLint 10 support\n- 〰️ Addon Pseudo-States: Tailwind v4 support\n- 🔧 Addon-Vitest: Simplified configuration - no more setup files required\n- ♿ Numerous accessibility improvements across the UI\n\n<details>\n<summary>List of all updates</summary>\n- A11y: Add ScrollArea prop focusable for when it has static children - [#33876](https://github.com/storybookjs/storybook/pull/33876), thanks @Sidnioulz!\n- A11y: Ensure popover dialogs have an ARIA label - [#33500](https://github.com/storybookjs/storybook/pull/33500), thanks @gayanMatch!\n- A11y: Make resize handles for addon panel and sidebar accessible [#33980](https://github.com/storybookjs/storybook/pull/33980)\n- A11y: Underline MDX links for WCAG SC 1.4.1 compliance - [#33139](https://github.com/storybookjs/storybook/pull/33139), thanks @NikhilChowdhury27!\n- Actions: Add expandLevel parameter to configure tree depth - [#33977](https://github.com/storybookjs/storybook/pull/33977), thanks @mixelburg!\n- Actions: Fix HandlerFunction type to support async callback props - [#33864](https://github.com/storybookjs/storybook/pull/33864), thanks @mixelburg!\n- Addon-Docs: Add React as optimizeDeps entry - [#34176](https://github.com/storybookjs/storybook/pull/34176), thanks @valentinpalkovic!\n- Addon-Docs: Add support for `sourceState: 'none'` to canvas block parameters - [#33627](https://github.com/storybookjs/storybook/pull/33627), thanks @quisido!\n- Addon-docs: Restore `docs.components` overrides for doc blocks [#34111](https://github.com/storybookjs/storybook/pull/34111)\n- Addon-Vitest: Add channel API to programmatically trigger test runs - [#33206](https://github.com/storybookjs/storybook/pull/33206), thanks @JReinhold!\n- Addon-Vitest: Handle additional vitest config export patterns in postinstall - [#34106](https://github.com/storybookjs/storybook/pull/34106), thanks @copilot-swe-agent!\n- Addon-Vitest: Make Playwright `--with-deps` platform-aware to avoid `sudo` prompt on Linux [#34121](https://github.com/storybookjs/storybook/pull/34121)\n- Addon-Vitest: Refactor Vitest setup to eliminate the need for a dedicated setup file - [#34025](https://github.com/storybookjs/storybook/pull/34025), thanks @valentinpalkovic!\n- Addon-Vitest: Support Vitest canaries - [#33833](https://github.com/storybookjs/storybook/pull/33833), thanks @valentinpalkovic!\n- Angular: Add moduleResolution: bundler to tsconfig - [#34085](https://github.com/storybookjs/storybook/pull/34085), thanks @valentinpalkovic!\n- Angular: only load webpack dependencies on demand - [#34043](https://github.com/storybookjs/storybook/pull/34043), thanks @sod!\n- Angular: Storybook fails with unknown option silent - [#33736](https://github.com/storybookjs/storybook/pull/33736), thanks @tanujbhaud!\n- Build: Update @types/node - [#34037](https://github.com/storybookjs/storybook/pull/34037), thanks @valentinpalkovic!\n- Builder-Vite: Centralize Vite plugins for builder-vite and addon-vitest - [#33819](https://github.com/storybookjs/storybook/pull/33819), thanks @valentinpalkovic!\n- Builder-Vite: Fix cold-cache vitest failures for story paths containing glob special characters - [#34044](https://github.com/storybookjs/storybook/pull/34044), thanks @copilot-swe-agent!\n- Builder-Vite: Use preview annotations as entry points for optimizeDeps - [#33875](https://github.com/storybookjs/storybook/pull/33875), thanks @copilot-swe-agent!\n- CI: declare explicit permissions for stale and weekly cron workflows - [#33902](https://github.com/storybookjs/storybook/pull/33902), thanks @Rohan5commit!\n- CLI: Add vike CLI metadata - [#34189](https://github.com/storybookjs/storybook/pull/34189), thanks @yannbf!\n- CLI: Avoid hanging of postinstall during init - [#34175](https://github.com/storybookjs/storybook/pull/34175), thanks @valentinpalkovic!\n- CLI: Fix onboarding not opening - [#33609](https://github.com/storybookjs/storybook/pull/33609), thanks @ndelangen!\n- CLI: Show multiple favicons warning as debug message - [#34069](https://github.com/storybookjs/storybook/pull/34069), thanks @remino!\n- Cli: Use npm for registry URL in PNPMProxy to avoid workspace errors - [#33571](https://github.com/storybookjs/storybook/pull/33571), thanks @ia319!\n- Controls: Allow story argTypes to override control: false from meta - [#33729](https://github.com/storybookjs/storybook/pull/33729), thanks @jonathan-fulton!\n- Controls: Fix Object contrast issue and tidy up code - [#33923](https://github.com/storybookjs/storybook/pull/33923), thanks @Sidnioulz!\n- Core: Ensure telemetry is never triggered on initial load of checklist data - [#33918](https://github.com/storybookjs/storybook/pull/33918), thanks @ghengeveld!\n- Core: Fix event source URL based on refId when multiple iframes share the same origin [#34105](https://github.com/storybookjs/storybook/pull/34105)\n- Core: Fix false-positive CJS warning when 'exports' appears in strings or comments - [#33572](https://github.com/storybookjs/storybook/pull/33572), thanks @reeseo3o!\n- Core: Fix handling complex viewport sizes [#33615](https://github.com/storybookjs/storybook/pull/33615)\n- Core: Fix iframe reference for composed Storybook on a subpath [#34100](https://github.com/storybookjs/storybook/pull/34100)\n- Core: Fix typos: occured -> occurred, recieves -> receives - [#33727](https://github.com/storybookjs/storybook/pull/33727), thanks @jonathan-fulton!\n- Core: Handle BROWSER=none correctly and improve error messages - [#33730](https://github.com/storybookjs/storybook/pull/33730), thanks @jonathan-fulton!\n- Core: Ignore empty files when indexing - [#33782](https://github.com/storybookjs/storybook/pull/33782), thanks @JReinhold!\n- Core: Register CORS middleware before index.json route - [#33728](https://github.com/storybookjs/storybook/pull/33728), thanks @jonathan-fulton!\n- Core: Revert Pull Request #33420 from Maelryn/fix/copy-button-overlap - [#33877](https://github.com/storybookjs/storybook/pull/33877), thanks @Sidnioulz!\n- Core: Zoom tool refinements - Hide reset button when value is initial - [#33635](https://github.com/storybookjs/storybook/pull/33635), thanks @superLipbalm!\n- Docs: Edit JSON button is now accessible at 320x256 viewport (WCAG 2.1 Reflow test) - [#33707](https://github.com/storybookjs/storybook/pull/33707), thanks @TheSeydiCharyyev!\n- Docs: Make CSS ordering in DocsContainer more predictable [#34015](https://github.com/storybookjs/storybook/pull/34015)\n- ESLint-plugin: Disallow extra properties in eslint plugin rule options - [#32056](https://github.com/storybookjs/storybook/pull/32056), thanks @andreww2012!\n- ESLint: bail out config setup if eslint-plugin-storybook is already imported - [#34089](https://github.com/storybookjs/storybook/pull/34089), thanks @copilot-swe-agent!\n- HMR: Fix race conditions causing stale play functions to fire on re-rendered stories - [#33930](https://github.com/storybookjs/storybook/pull/33930), thanks @copilot-swe-agent!\n- Maintenance: Revert pull request #33930 HMR events - [#34190](https://github.com/storybookjs/storybook/pull/34190), thanks @yannbf!\n- Maintenance: Use std-env for AI agent detection in telemetry [#34114](https://github.com/storybookjs/storybook/pull/34114)\n- Manifest: Add docs entries to debugger - [#33607](https://github.com/storybookjs/storybook/pull/33607), thanks @JReinhold!\n- Manifest: Rename `experimentalComponentsManifest` → `componentsManifest`, default to `true` [#33974](https://github.com/storybookjs/storybook/pull/33974)\n- Manifests: Fix Attached MDX causing wrong component entries [#34101](https://github.com/storybookjs/storybook/pull/34101)\n- Next.js-Vite: Fix failing postcss mutation - [#33879](https://github.com/storybookjs/storybook/pull/33879), thanks @valentinpalkovic!\n- Next.js: Move image configuration from FrameworkOptions to parameters [#32639](https://github.com/storybookjs/storybook/pull/32639), thanks @y-hsgw!\n- Preact: Support inferring props from component types - [#33828](https://github.com/storybookjs/storybook/pull/33828), thanks @JoviDeCroock!\n- React Native Web: Fix inconsistent example stories - [#33891](https://github.com/storybookjs/storybook/pull/33891), thanks @danielalanbates!\n- React: Add react-docgen-typescript to component manifest - [#33818](https://github.com/storybookjs/storybook/pull/33818), thanks @kasperpeulen!\n- Revert \"Toolbar: Remove extra toolbar divider when zoom controls not shown\" - [#34099](https://github.com/storybookjs/storybook/pull/34099), thanks @valentinpalkovic!\n- Test: Fix clearing mocks in Vitest [#34078](https://github.com/storybookjs/storybook/pull/34078)\n- Test: Update @testing-library/jest-dom - [#33928](https://github.com/storybookjs/storybook/pull/33928), thanks @valentinpalkovic!\n- Theming: Export interface declaration for `ThemesGlobals` - [#33343](https://github.com/storybookjs/storybook/pull/33343), thanks @icopp!\n- Toolbar: Remove extra toolbar divider when zoom controls not shown - [#33731](https://github.com/storybookjs/storybook/pull/33731), thanks @jonathan-fulton!\n- UI: Allow direct kb/mouse actions on zoom tool button - [#33496](https://github.com/storybookjs/storybook/pull/33496), thanks @Sidnioulz!\n- UI: Avoid large animation for reduced motion users - [#33530](https://github.com/storybookjs/storybook/pull/33530), thanks @Sidnioulz!\n- UI: Ensure Link without href is keyboard-reachable - [#34163](https://github.com/storybookjs/storybook/pull/34163), thanks @Sidnioulz!\n- UI: Fix `z-index` problem with `popover`s and `modal`s nesting - [#33757](https://github.com/storybookjs/storybook/pull/33757), thanks @ndelangen!\n- UI: Fix code/copy buttons overlap with content - [#33889](https://github.com/storybookjs/storybook/pull/33889), thanks @Sidnioulz!\n- UI: Fix Copy button overlapping code in portrait mode - [#33420](https://github.com/storybookjs/storybook/pull/33420), thanks @Maelryn!\n- UI: Fix modal text selection - [#33967](https://github.com/storybookjs/storybook/pull/33967), thanks @Sidnioulz!\n- UI: Fix tab navigation after closing addon panel - [#33971](https://github.com/storybookjs/storybook/pull/33971), thanks @copilot-swe-agent!\n- UI: Handle kb nav edge cases when preview and panel are hidden - [#33588](https://github.com/storybookjs/storybook/pull/33588), thanks @Sidnioulz!\n- UI: Hide addon panel Drag on pages without a panel - [#34162](https://github.com/storybookjs/storybook/pull/34162), thanks @Sidnioulz!\n- UI: Hide manifest tag for now - [#34165](https://github.com/storybookjs/storybook/pull/34165), thanks @Sidnioulz!\n- UI: Make disabled Buttons keyboard-focusable - [#34166](https://github.com/storybookjs/storybook/pull/34166), thanks @Sidnioulz!\n- UI: Make TagsFilter state persistent [#33374](https://github.com/storybookjs/storybook/pull/33374)\n- UI: Use correct selector for addon panel focus check - [#34164](https://github.com/storybookjs/storybook/pull/34164), thanks @Sidnioulz!\n- UI: Zoom faster when pressing shift - [#34185](https://github.com/storybookjs/storybook/pull/34185), thanks @Sidnioulz!\n- Viewport: Skip viewport validation before parameters load - [#33794](https://github.com/storybookjs/storybook/pull/33794), thanks @ia319!\n- Vite: Add mock entries to optimizeDeps.entries - [#34167](https://github.com/storybookjs/storybook/pull/34167), thanks @valentinpalkovic!\n- Vue3-Vite: Allow paths in docgen tsconfig option [#32310](https://github.com/storybookjs/storybook/pull/32310), thanks @Thomaash!\n</details>\n\n## 10.2.19\n\n- Maintenance: Support vite-plugin-svelte@7 which supports Vite 8 - [#34115](https://github.com/storybookjs/storybook/pull/34115), thanks @valentinpalkovic!\n- Vite: Support Vite 8 - [#33788](https://github.com/storybookjs/storybook/pull/33788), thanks @valentinpalkovic!\n\n## 10.2.18\n\n- Core: Correctly fallback to first detected vitest config file - [#33865](https://github.com/storybookjs/storybook/pull/33865), thanks @yannbf!\n- Core: Fix error reporting in ManagerErrorBoundary - [#33915](https://github.com/storybookjs/storybook/pull/33915), thanks @ghengeveld!\n\n## 10.2.17\n\n- Next.js: Add support for v16.2 - [#34046](https://github.com/storybookjs/storybook/pull/34046), thanks @valentinpalkovic!\n\n## 10.2.16\n\n- CSF-Factories: Fix ConfigFile parser false warning on `definePreview({...}).type<T>()` export default - [#33885](https://github.com/storybookjs/storybook/pull/33885), thanks @copilot-swe-agent!\n- Core: Add host/origin validation to requests and websocket connections - [#33835](https://github.com/storybookjs/storybook/pull/33835), thanks @ghengeveld!\n- Core: Add vike metadata frameworks - [#33965](https://github.com/storybookjs/storybook/pull/33965), thanks @yannbf!\n- Core: Resolve builder preset path correctly in pnpm strict mode - [#34032](https://github.com/storybookjs/storybook/pull/34032), thanks @braedenfoster!\n- Core: Update default allowed hosts in host validation middleware - [#34045](https://github.com/storybookjs/storybook/pull/34045), thanks @ghengeveld!\n\n## 10.2.15\n\n- Core: Storybook failed to load iframe.html when publishing - [#33896](https://github.com/storybookjs/storybook/pull/33896), thanks @danielalanbates!\n- Manager-API: Update refs sequentially in experimental_setFilter - [#33958](https://github.com/storybookjs/storybook/pull/33958), thanks @ia319!\n- React: Handle render identifier in manifest snippet generation - [#33940](https://github.com/storybookjs/storybook/pull/33940), thanks @kasperpeulen!\n\n## 10.2.14\n\n- CLI: Set STORYBOOK environment variable - [#33938](https://github.com/storybookjs/storybook/pull/33938), thanks @yannbf!\n- UI: Prevent crash when tag filters contain undefined entries - [#33931](https://github.com/storybookjs/storybook/pull/33931), thanks @abhaysinh1000!\n\n## 10.2.13\n\n- Addon Pseudo-states: Process all nested css rules - [#33605](https://github.com/storybookjs/storybook/pull/33605), thanks @hpohlmeyer!\n- Builder-Vite: Prevent config duplication - [#33883](https://github.com/storybookjs/storybook/pull/33883), thanks @copilot-swe-agent!\n- CLI: Fix React native web A11y issues - [#33937](https://github.com/storybookjs/storybook/pull/33937), thanks @jonniebigodes!\n- Core: Avoid hanging when inferring args for recursive calls on DOM elemens - [#33922](https://github.com/storybookjs/storybook/pull/33922), thanks @valentinpalkovic!\n- Eslint: Fix ESLint 10 compatibility in eslint-plugin-storybook rules - [#33884](https://github.com/storybookjs/storybook/pull/33884), thanks @copilot-swe-agent!\n- Viewport: Prioritize story viewport globals and avoid user-global pollution - [#33849](https://github.com/storybookjs/storybook/pull/33849), thanks @ia319!\n\n## 10.2.12\n\n- Core: Sanitize inputs for save from controls - [#33868](https://github.com/storybookjs/storybook/pull/33868), thanks @valentinpalkovic!\n- Telemetry: Add project age - [#33910](https://github.com/storybookjs/storybook/pull/33910), thanks @shilman!\n- Webpack: Improve performance of module-mocking plugins - [#33169](https://github.com/storybookjs/storybook/pull/33169), thanks @valentinpalkovic!\n\n## 10.2.11\n\n- Addon-Vitest: Fix postinstall a11y installation - [#33888](https://github.com/storybookjs/storybook/pull/33888), thanks @valentinpalkovic!\n- Manifests: Use correct story name - [#33709](https://github.com/storybookjs/storybook/pull/33709), thanks @JReinhold!\n- Next.js: Handle legacyBehavior prop in Link mock component - [#33862](https://github.com/storybookjs/storybook/pull/33862), thanks @yatishgoel!\n- React: Fix manifest stories empty when meta has no explicit title - [#33878](https://github.com/storybookjs/storybook/pull/33878), thanks @kasperpeulen!\n\n## 10.2.10\n\n- Core: Require token for websocket connections - [#33820](https://github.com/storybookjs/storybook/pull/33820), thanks @ghengeveld!\n\n## 10.2.9\n\n- Addon-Vitest: Improve config file detection in monorepos - [#33814](https://github.com/storybookjs/storybook/pull/33814), thanks @valentinpalkovic!\n- Builder-Vite: Update dependencies react-vite framework - [#33810](https://github.com/storybookjs/storybook/pull/33810), thanks @valentinpalkovic!\n- Builder-Vite: Use relative path for mocker entry in production builds - [#33792](https://github.com/storybookjs/storybook/pull/33792), thanks @DukeDeSouth!\n- Next.js: Fix Link component override in appDirectory configuration - [#31251](https://github.com/storybookjs/storybook/pull/31251), thanks @yatishgoel!\n\n## 10.2.8\n\n- Telemetry: Add Expo metaframework - [#33783](https://github.com/storybookjs/storybook/pull/33783), thanks @copilot-swe-agent!\n- Telemetry: Add init exit event - [#33773](https://github.com/storybookjs/storybook/pull/33773), thanks @valentinpalkovic!\n- Telemetry: Add share events - [#33766](https://github.com/storybookjs/storybook/pull/33766), thanks @ndelangen!\n- Test: Update event creation logic in user-event package - [#33787](https://github.com/storybookjs/storybook/pull/33787), thanks @valentinpalkovic!\n\n## 10.2.7\n\n- CSF: Fix cross-file story imports in csf-factories codemod - [#33723](https://github.com/storybookjs/storybook/pull/33723), thanks @yatishgoel!\n- Core: Fix rendering of View Transitions in Firefox - [#33651](https://github.com/storybookjs/storybook/pull/33651), thanks @ghengeveld!\n- Globals: Repair dynamicTitle: false for user-defined tools - [#33284](https://github.com/storybookjs/storybook/pull/33284), thanks @ia319!\n- Logger: Honor --loglevel for npmlog output - [#33776](https://github.com/storybookjs/storybook/pull/33776), thanks @LouisLau-art!\n\n## 10.2.6\n\n- Addon-Vitest: Skip postinstall setup when configured - [#33712](https://github.com/storybookjs/storybook/pull/33712), thanks @valentinpalkovic!\n- Addon-Vitest: Support vite/vitest config with deferred export - [#33755](https://github.com/storybookjs/storybook/pull/33755), thanks @valentinpalkovic!\n- CLI: Support addon-vitest setup when --skip-install is passed - [#33718](https://github.com/storybookjs/storybook/pull/33718), thanks @valentinpalkovic!\n- Manager: Update logic to use base path instead of full pathname - [#33686](https://github.com/storybookjs/storybook/pull/33686), thanks @JSMike!\n\n## 10.2.5\n\n- Angular: fix --loglevel options in docs and descriptions - [#33726](https://github.com/storybookjs/storybook/pull/33726), thanks @theRuslan!\n- Builder-Vite: Add plugin to enforce Storybook's output directory in Vite build configuration - [#33740](https://github.com/storybookjs/storybook/pull/33740), thanks @valentinpalkovic!\n- Core: Invalidate cache on Storybook version upgrade - [#33717](https://github.com/storybookjs/storybook/pull/33717), thanks @copilot-swe-agent!\n\n## 10.2.4\n\n- CSF-Factories: Fix codemod for preview files without exports - [#33673](https://github.com/storybookjs/storybook/pull/33673), thanks @kasperpeulen!\n- CSF: Fix false positive detection of Zod v4 .meta() as CSF Factory - [#33666](https://github.com/storybookjs/storybook/pull/33666), thanks @kasperpeulen!\n- CSFFactories: Add non-interactive mode and --glob flag - [#33648](https://github.com/storybookjs/storybook/pull/33648), thanks @kasperpeulen!\n- CSFFactories: Preserve leading comments when adding imports - [#33645](https://github.com/storybookjs/storybook/pull/33645), thanks @kasperpeulen!\n- Codemod: Fix csf-2-to-3 failing due to quoted filenames - [#33646](https://github.com/storybookjs/storybook/pull/33646), thanks @kasperpeulen!\n- Codemod: Fix glob pattern handling on Windows - [#33714](https://github.com/storybookjs/storybook/pull/33714), thanks @kasperpeulen!\n- Manager: Remove deprecated `active` prop warning in ZoomButton - [#33697](https://github.com/storybookjs/storybook/pull/33697), thanks @yatishgoel!\n- Next.js: Alias AppRouterContext to shared runtime to fix Link navigation - [#33419](https://github.com/storybookjs/storybook/pull/33419), thanks @pallaprolus!\n\n## 10.2.3\n\n- Addon-Vitest: Normalize Windows paths in addon-vitest automigration - [#33340](https://github.com/storybookjs/storybook/pull/33340), thanks @tanujbhaud!\n- Core: Fix `previewHref` when current path does not end with a slash - [#33647](https://github.com/storybookjs/storybook/pull/33647), thanks @ghengeveld!\n\n## 10.2.2\n\n- Addon Vitest: Support simple vite.config without defineConfig helper - [#33694](https://github.com/storybookjs/storybook/pull/33694), thanks @valentinpalkovic!\n- Addon-Vitest: Append Storybook project to existing test.projects array without double nesting - [#33708](https://github.com/storybookjs/storybook/pull/33708), thanks @valentinpalkovic!\n- Addon-Vitest: Update Vitest plugin configuration to disable requireAssertions for expect - [#33693](https://github.com/storybookjs/storybook/pull/33693), thanks @valentinpalkovic!\n- Composition: Handle 401 responses with loginUrl from Chromatic - [#33705](https://github.com/storybookjs/storybook/pull/33705), thanks @kasperpeulen!\n- Telemetry: Add agent detection - [#33675](https://github.com/storybookjs/storybook/pull/33675), thanks @valentinpalkovic!\n\n## 10.2.1\n\n- Builder-Webpack5: Fix @vitest/mocker resolution issue - [#33315](https://github.com/storybookjs/storybook/pull/33315), thanks @valentinpalkovic!\n- CLI: Add init telemetry for CLI integrations - [#33603](https://github.com/storybookjs/storybook/pull/33603), thanks @shilman!\n\n## 10.2.0\n\n> Improved UI and story authoring ergonomics\n\nStorybook 10.2 contains hundreds of fixes and improvement including:\n\n- 💅 New Viewports and Zoom UI\n- 🏭 Typesafe CSF factories for Vue, Angular, Web Components (preview)\n- 📄 MDX support for Storybook MCP (experimental)\n\n<details>\n<summary>List of all updates</summary>\n\n- Addon-A11y: Lock vision filter dropdown for stories with `vision` global - [#33599](https://github.com/storybookjs/storybook/pull/33599), thanks @ghengeveld!\n- Addon-Docs: Add MDX manifest generation - [#33408](https://github.com/storybookjs/storybook/pull/33408), thanks @copilot-swe-agent!\n- Addon-Docs: Skip `!autodocs` stories when computing primary story - [#32712](https://github.com/storybookjs/storybook/pull/32712), thanks @ia319!\n- Addon-Pseudo States: Fix stylesheet rewrite for `:not()` with parenthesis in inner selector - [#33491](https://github.com/storybookjs/storybook/pull/33491), thanks @ghengeveld!\n- Addon-Vitest: Added timeout for fetching localhost 6006 during global setup. - [#33232](https://github.com/storybookjs/storybook/pull/33232), thanks @snippy4!\n- Addon-Vitest: Fallback detecting vitest version in postinstall - [#33415](https://github.com/storybookjs/storybook/pull/33415), thanks @ndelangen!\n- Addon-Vitest: Improve error message in testing widget modal - [#33481](https://github.com/storybookjs/storybook/pull/33481), thanks @yannbf!\n- Addon-Vitest: Improve perf & fix loading incorrect `.env` file - [#33469](https://github.com/storybookjs/storybook/pull/33469), thanks @ndelangen!\n- CLI: Detect free port when running dev during initiate - [#33532](https://github.com/storybookjs/storybook/pull/33532), thanks @ndelangen!\n- CLI: Remove any return type of getAbsolutePath - [#32977](https://github.com/storybookjs/storybook/pull/32977), thanks @nzws!\n- CLI: Skip vitest transform for CSF Factories in a11y-addon-test automigration - [#31941](https://github.com/storybookjs/storybook/pull/31941), thanks @mrginglymus!\n- Codemod: Fix glob string to only match stories files - [#33592](https://github.com/storybookjs/storybook/pull/33592), thanks @JReinhold!\n- Controls: Allow resetting the Select control - [#33289](https://github.com/storybookjs/storybook/pull/33289), thanks @Sidnioulz!\n- Controls: Fix displaying as object instead of select for optional union types - [#33200](https://github.com/storybookjs/storybook/pull/33200), thanks @tanujbhaud!\n- Controls: Force object control JSON mode to reset - [#33330](https://github.com/storybookjs/storybook/pull/33330), thanks @Sidnioulz!\n- Core and Vite: Use story index as source of truth for Vite paths - [#30612](https://github.com/storybookjs/storybook/pull/30612), thanks @JReinhold!\n- Core: Add `getStoryHrefs` manager API and add hotkey for \"open in isolation\" - [#33416](https://github.com/storybookjs/storybook/pull/33416), thanks @ghengeveld!\n- Core: Add global error boundary for Manager UI - [#33211](https://github.com/storybookjs/storybook/pull/33211), thanks @copilot-swe-agent!\n- Core: Add support for wrapped components in component transformer - [#33578](https://github.com/storybookjs/storybook/pull/33578), thanks @yannbf!\n- Core: Add try-catch for cross-origin access in Storybook hooks - [#33448](https://github.com/storybookjs/storybook/pull/33448), thanks @ndelangen!\n- Core: Add zoom level 8 and limit manual input to 800% - [#33561](https://github.com/storybookjs/storybook/pull/33561), thanks @ghengeveld!\n- Core: Avoid late layout shift and improve ChecklistWidget perceived performance - [#33184](https://github.com/storybookjs/storybook/pull/33184), thanks @ghengeveld!\n- Core: Ensure /project.json route is up before builders serve local FS - [#33303](https://github.com/storybookjs/storybook/pull/33303), thanks @Sidnioulz!\n- Core: Fix `react-docgen-typescript` support in story creation - [#33586](https://github.com/storybookjs/storybook/pull/33586), thanks @yannbf!\n- Core: Fix Checklist behavior with hidden sidebar - [#33556](https://github.com/storybookjs/storybook/pull/33556), thanks @ghengeveld!\n- Core: Fix cwd handling for negated globs - [#33241](https://github.com/storybookjs/storybook/pull/33241), thanks @ia319!\n- Core: Fix Date input layout - [#33595](https://github.com/storybookjs/storybook/pull/33595), thanks @ghengeveld!\n- Core: Fix import statement for `react-docgen-typescript` - [#33589](https://github.com/storybookjs/storybook/pull/33589), thanks @yannbf!\n- Core: Fix input width - [#33591](https://github.com/storybookjs/storybook/pull/33591), thanks @ghengeveld!\n- Core: Fix manual zoom input field UX - [#33581](https://github.com/storybookjs/storybook/pull/33581), thanks @ghengeveld!\n- Core: Fix onboarding visual bugs, survey telemetry and modal dismissal - [#33326](https://github.com/storybookjs/storybook/pull/33326), thanks @ghengeveld!\n- Core: Fix play function `mount` detection when destructuring in the function body - [#33367](https://github.com/storybookjs/storybook/pull/33367), thanks @ghengeveld!\n- Core: Fix viewport args handling and reset option - [#33560](https://github.com/storybookjs/storybook/pull/33560), thanks @ghengeveld!\n- Core: Honor BROWSER shell scripts before xdg-open - [#33292](https://github.com/storybookjs/storybook/pull/33292), thanks @robbchar!\n- Core: Improve addon sanitization - [#33554](https://github.com/storybookjs/storybook/pull/33554), thanks @yannbf!\n- Core: Improve path handling in arg types data extraction - [#33536](https://github.com/storybookjs/storybook/pull/33536), thanks @yannbf!\n- Core: Improve the story generation experience - [#33259](https://github.com/storybookjs/storybook/pull/33259), thanks @yannbf!\n- Core: Redesign and refactor Viewports tool - [#33290](https://github.com/storybookjs/storybook/pull/33290), thanks @ghengeveld!\n- Core: Refactor channel initialization - [#33520](https://github.com/storybookjs/storybook/pull/33520), thanks @yannbf!\n- Core: Render sidebar toggle on settings pages - [#33501](https://github.com/storybookjs/storybook/pull/33501), thanks @ghengeveld!\n- Core: Retry `writeFile` cache when EBUSY error occurs - [#32981](https://github.com/storybookjs/storybook/pull/32981), thanks @reduckted!\n- Core: Support defineConfig when setting up ESLint plugin - [#32878](https://github.com/storybookjs/storybook/pull/32878), thanks @copilot-swe-agent!\n- Core: Support disabling Checklist widget through feature config - [#33430](https://github.com/storybookjs/storybook/pull/33430), thanks @ghengeveld!\n- Core: Track vision simulator state through globals and apply styles in preview - [#33418](https://github.com/storybookjs/storybook/pull/33418), thanks @ghengeveld!\n- Core: Use canonical links in sidebar and menu - [#33400](https://github.com/storybookjs/storybook/pull/33400), thanks @Sidnioulz!\n- Core: Viewport UX fixes - [#33557](https://github.com/storybookjs/storybook/pull/33557), thanks @ghengeveld!\n- Core: Zoom tool reimplementation - [#33375](https://github.com/storybookjs/storybook/pull/33375), thanks @ghengeveld!\n- CSF-Factories: Add CSF Factories for Vue3, Web Components, and Angular - [#33365](https://github.com/storybookjs/storybook/pull/33365), thanks @kasperpeulen!\n- CSF-Factories: Allow kebab-case HTML attribute names in web components args - [#33526](https://github.com/storybookjs/storybook/pull/33526), thanks @kasperpeulen!\n- CSF-Factories: Export WebComponentsTypes and VueTypes - [#33521](https://github.com/storybookjs/storybook/pull/33521), thanks @kasperpeulen!\n- CSF-Factories: Skip non-factory exports instead of throwing error - [#33550](https://github.com/storybookjs/storybook/pull/33550), thanks @kasperpeulen!\n- CSF: Export type to prevent `type cannot be named`-errors - [#33216](https://github.com/storybookjs/storybook/pull/33216), thanks @unional!\n- Dependencies: Bump various packages - [#33412](https://github.com/storybookjs/storybook/pull/33412), thanks @ndelangen!\n- Dependencies: Update `baseline-browser-mapping` - [#33576](https://github.com/storybookjs/storybook/pull/33576), thanks @ndelangen!\n- Docgen: Update extraction of React docgen - [#33598](https://github.com/storybookjs/storybook/pull/33598), thanks @ndelangen!\n- Docs-Blocks: Fix broken tooltip in ArgValue details - [#33264](https://github.com/storybookjs/storybook/pull/33264), thanks @Sidnioulz!\n- Docs: Ensure CodePanel hooks are called within component - [#33162](https://github.com/storybookjs/storybook/pull/33162), thanks @mrginglymus!\n- Interactions: Add disable parameter for interactions panel - [#33368](https://github.com/storybookjs/storybook/pull/33368), thanks @jeevikar14!\n- Interactions: Fix state reset bug when switching stories with date mocks - [#33388](https://github.com/storybookjs/storybook/pull/33388), thanks @Sidnioulz!\n- Manager: Ensure reset item only appears in globals toolbar when specified - [#33276](https://github.com/storybookjs/storybook/pull/33276), thanks @mrginglymus!\n- Manager: Fix system query parameters being overridable - [#33535](https://github.com/storybookjs/storybook/pull/33535), thanks @JReinhold!\n- Manifests: Add support for summaries in MDX files - [#33475](https://github.com/storybookjs/storybook/pull/33475), thanks @JReinhold!\n- Manifests: Refactor from `componentManifestGenerator` to extensible `manifests` preset property - [#33392](https://github.com/storybookjs/storybook/pull/33392), thanks @JReinhold!\n- Manifests: Support `!manifest` tag in preview files - [#33406](https://github.com/storybookjs/storybook/pull/33406), thanks @JReinhold!\n- NextJS: Import `next/dist` with `.js`-extension for ESM compat - [#33380](https://github.com/storybookjs/storybook/pull/33380), thanks @yue4u!\n- NextJS: Support top-level weight/style in next/font/local with string src - [#32998](https://github.com/storybookjs/storybook/pull/32998), thanks @Chiman2937!\n- NextJSVite: Add `@opentelemetry/api` to `optimizeDeps` - [#33577](https://github.com/storybookjs/storybook/pull/33577), thanks @ndelangen!\n- NextJSVite: Update vite-plugin-storybook-nextjs to v3.1.7 - [#33351](https://github.com/storybookjs/storybook/pull/33351), thanks @valentinpalkovic!\n- NextJSVite: Upgrade plugin - [#33538](https://github.com/storybookjs/storybook/pull/33538), thanks @ndelangen!\n- Onboarding: Fix navigation to first story when configure-your-project entry missing - [#33559](https://github.com/storybookjs/storybook/pull/33559), thanks @copilot-swe-agent!\n- Onboarding: Hide TourGuide as soon as tests start - [#33587](https://github.com/storybookjs/storybook/pull/33587), thanks @ghengeveld!\n- Preview: Prevent error in RN due to `navigator?.clipboard` - [#33219](https://github.com/storybookjs/storybook/pull/33219), thanks @ndelangen!\n- Preview: Treat canceled animations as finished - [#32401](https://github.com/storybookjs/storybook/pull/32401), thanks @bawjensen!\n- React: Use self-closing tag for code snippets - [#33342](https://github.com/storybookjs/storybook/pull/33342), thanks @valentinpalkovic!\n- SvelteKit: Align JS template with TS template - [#31451](https://github.com/storybookjs/storybook/pull/31451), thanks @brettearle!\n- Telemetry: Add `packageJson.type` - [#33525](https://github.com/storybookjs/storybook/pull/33525), thanks @ndelangen!\n- TypeScript: Fix summary undefined type issue - [#32585](https://github.com/storybookjs/storybook/pull/32585), thanks @afsalshamsudeen!\n- TypeScript: Improve globalTypes type-strictness - [#33313](https://github.com/storybookjs/storybook/pull/33313), thanks @mrginglymus!\n- TypeScript: Reduce `cannot be named` errors - [#33344](https://github.com/storybookjs/storybook/pull/33344), thanks @icopp!\n- TypeScript: Support `exactOptionalPropertyTypes` for public API types - [#33149](https://github.com/storybookjs/storybook/pull/33149), thanks @copilot-swe-agent!\n- UI: Ensure consistent right padding in TreeNode - [#33322](https://github.com/storybookjs/storybook/pull/33322), thanks @Sidnioulz!\n- UI: Ensure preview error displays use a readable text color - [#33580](https://github.com/storybookjs/storybook/pull/33580), thanks @Sidnioulz!\n- UI: Fix border color for Select picker - [#33585](https://github.com/storybookjs/storybook/pull/33585), thanks @ghengeveld!\n- UI: Fix empty sidebar after navigating from search - [#33590](https://github.com/storybookjs/storybook/pull/33590), thanks @Sidnioulz!\n- UI: Fix regression in select close handler focus - [#33470](https://github.com/storybookjs/storybook/pull/33470), thanks @Sidnioulz!\n- UI: Fix search highlight visibility in High Contrast Mode - [#33427](https://github.com/storybookjs/storybook/pull/33427), thanks @Maelryn!\n- UI: Improve landmark navigation - [#33457](https://github.com/storybookjs/storybook/pull/33457), thanks @Sidnioulz!\n- UI: Keep preview frame stable in overall layout - [#33447](https://github.com/storybookjs/storybook/pull/33447), thanks @Sidnioulz!\n- UI: Make vertical alignment of TestStatusIcon more robust - [#33305](https://github.com/storybookjs/storybook/pull/33305), thanks @Sidnioulz!\n- UI: Prevent primary story from duplicating anchor ID - [#33384](https://github.com/storybookjs/storybook/pull/33384), thanks @Sidnioulz!\n- UI: Prevent updating non-existent stories in sidebar - [#33037](https://github.com/storybookjs/storybook/pull/33037), thanks @ia319!\n- Upgrade: Preserve package.json indentation when upgrading - [#32280](https://github.com/storybookjs/storybook/pull/32280), thanks @y-hsgw!\n- Vue3: Update renderer's setup function to allow passing generic HostElement type - [#32029](https://github.com/storybookjs/storybook/pull/32029), thanks @DamianGlowala!\n- Webpack: Revert \"disable `bugfixes` property in swc and babel - [#33498](https://github.com/storybookjs/storybook/pull/33498), thanks @ndelangen!\n- Zoom: Keyboard-shortcut for the `plus` key - [#33565](https://github.com/storybookjs/storybook/pull/33565), thanks @ndelangen!\n\n</details>\n\n## 10.1.11\n\n- React: Fix several CSF factory bugs - [#33354](https://github.com/storybookjs/storybook/pull/33354), thanks @kasperpeulen!\n- UI: Fix React error 300 on some addons - [#33381](https://github.com/storybookjs/storybook/pull/33381), thanks @Sidnioulz!\n\n## 10.1.10\n\n- Core: Fix `.env`-file parsing - [#33383](https://github.com/storybookjs/storybook/pull/33383), thanks @JReinhold!\n- Next.js: Handle v14 compatibility for draftMode import - [#33341](https://github.com/storybookjs/storybook/pull/33341), thanks @tanujbhaud!\n\n## 10.1.9\n\n- Telemetry: Remove instance of check for sub-error handling - [#33356](https://github.com/storybookjs/storybook/pull/33356), thanks @valentinpalkovic!\n\n## 10.1.8\n\n- React-Vite: Update @joshwooding/vite-plugin-react-docgen-typescript - [#33349](https://github.com/storybookjs/storybook/pull/33349), thanks @valentinpalkovic!\n\n## 10.1.7\n\n- Automigrate: Fix missing await - [#33333](https://github.com/storybookjs/storybook/pull/33333), thanks @valentinpalkovic!\n- CLI: Remove REACT_PROJECT projectType - [#33334](https://github.com/storybookjs/storybook/pull/33334), thanks @valentinpalkovic!\n- Core: Exclude open from pre-bundling to make local xdg-open reachable - [#33325](https://github.com/storybookjs/storybook/pull/33325), thanks @Sidnioulz!\n- Nextjs-Vite: Install `vite` during migration if not installed yet - [#33316](https://github.com/storybookjs/storybook/pull/33316), thanks @ghengeveld!\n- Telemetry: Fix race condition in telemetry cache causing malformed JSON - [#33323](https://github.com/storybookjs/storybook/pull/33323), thanks @valentinpalkovic!\n\n## 10.1.6\n\n- Manager: Do not display non-existing shortcuts in the settings page - [#32711](https://github.com/storybookjs/storybook/pull/32711), thanks @DKER2!\n- Preview: Enforce inert body if manager is focus-trapped - [#33186](https://github.com/storybookjs/storybook/pull/33186), thanks @Sidnioulz!\n- Telemetry: Await pending operations in getLastEvents to prevent race conditions - [#33285](https://github.com/storybookjs/storybook/pull/33285), thanks @valentinpalkovic!\n- UI: Fix keyboard navigation bug for \"reset\" option in `Select` - [#33268](https://github.com/storybookjs/storybook/pull/33268), thanks @Sidnioulz!\n\n## 10.1.5\n\n- Addon-Vitest: Isolate error reasons during postinstall - [#33295](https://github.com/storybookjs/storybook/pull/33295), thanks @valentinpalkovic!\n- CLI: Fix react native template not copying in init - [#33308](https://github.com/storybookjs/storybook/pull/33308), thanks @dannyhw!\n- Docs: Support Rolldown bundler module namespace objects - [#33280](https://github.com/storybookjs/storybook/pull/33280), thanks @akornmeier!\n\n## 10.1.4\n\n- Core: Enhance getPrettier function to provide prettier interface - [#33260](https://github.com/storybookjs/storybook/pull/33260), thanks @valentinpalkovic!\n- NextJS: Alias image to use fileURLToPath for better resolution - [#33256](https://github.com/storybookjs/storybook/pull/33256), thanks @ndelangen!\n- Telemetry: Cache Storybook metadata by main config content hash - [#33247](https://github.com/storybookjs/storybook/pull/33247), thanks @valentinpalkovic!\n\n## 10.1.3\n\n- Angular: Honor --loglevel and --logfile in dev/build - [#33212](https://github.com/storybookjs/storybook/pull/33212), thanks @valentinpalkovic!\n- Core: Minor UI fixes - [#33218](https://github.com/storybookjs/storybook/pull/33218), thanks @ghengeveld!\n- Telemetry: Add playwright-prompt - [#33229](https://github.com/storybookjs/storybook/pull/33229), thanks @valentinpalkovic!\n\n## 10.1.2\n\n- Checklist: Fix how state changes are reported and drop some completion restrictions - [#33217](https://github.com/storybookjs/storybook/pull/33217), thanks @ghengeveld!\n\n## 10.1.1\n\n- Core: Improve globbing using dynamic CWD (REVERT) - [#33201](https://github.com/storybookjs/storybook/pull/33201), thanks @ndelangen!\n- Solid: Add Solid to the list of supported frameworks for addon-vitest - [#33084](https://github.com/storybookjs/storybook/pull/33084), thanks @valentinpalkovic!\n- UI: Fix excessive height in TabbedArgsTable - [#33205](https://github.com/storybookjs/storybook/pull/33205), thanks @Sidnioulz!\n\n## 10.1.0\n\n> _Easier to setup, more accessible to use_\n\nStorybook 10.1 focuses on two key improvements: installation and accessibility:\n\n- ♿ UI overhaul to fix hundreds of a11y issues\n- 🧑‍💻 CLI overhaul for faster, more reliable install\n- ✅ Checklist-based onboarding guide for new users\n\nThe release also contains compatibility fixes for:\n\n- 🅰️ Angular 21 support\n- 🦀 RSbuild install support in CLI\n- ⚡️ Preact support for Vitest addon\n\nFinally, it contains two highly-requested experimental features:\n\n- 📋 Component manifest for Storybook MCP\n- ⚛️ Improved JSX code snippets for React\n\n<details>\n<summary>List of all updates</summary>\n\n- A11y: Add aria-selected attribute to tab buttons - [#32656](https://github.com/storybookjs/storybook/pull/32656), thanks @Nischit-Ekbote!\n- A11y: Make search clear button keyboard accessible - [#32590](https://github.com/storybookjs/storybook/pull/32590), thanks @ritoban23!\n- Addon-Vitest: Ensure Storybook starts correctly across platforms by using shell in spawn - [#33116](https://github.com/storybookjs/storybook/pull/33116), thanks @valentinpalkovic!\n- Angular: Add preset entry point for framework - [#33154](https://github.com/storybookjs/storybook/pull/33154), thanks @valentinpalkovic!\n- Angular: Add support for v21 - [#33098](https://github.com/storybookjs/storybook/pull/33098), thanks @valentinpalkovic!\n- Angular: Don't kill dev command by using observables - [#33185](https://github.com/storybookjs/storybook/pull/33185), thanks @valentinpalkovic!\n- Angular: Migrate from RxJS to async/await in command builders and run Compodoc utility as spinner - [#33156](https://github.com/storybookjs/storybook/pull/33156), thanks @valentinpalkovic!\n- Angular: Replace deprecated import of ApplicationConfig - [#33125](https://github.com/storybookjs/storybook/pull/33125), thanks @EtiennePasteur!\n- Automigration: Update description and link for addon-a11y-addon-test - [#33133](https://github.com/storybookjs/storybook/pull/33133), thanks @valentinpalkovic!\n- Build: Add Rsbuild-based sandboxes - [#33039](https://github.com/storybookjs/storybook/pull/33039), thanks @valentinpalkovic!\n- Build: Fix async telemetry event sending - [#33115](https://github.com/storybookjs/storybook/pull/33115), thanks @valentinpalkovic!\n- Build: Update dependencies in yarn.lock and clean up comments - [#33089](https://github.com/storybookjs/storybook/pull/33089), thanks @ndelangen!\n- Checklist: Autocomplete \"See what's new\" on URL navigation - [#33167](https://github.com/storybookjs/storybook/pull/33167), thanks @ghengeveld!\n- Checklist: Data improvements - [#33129](https://github.com/storybookjs/storybook/pull/33129), thanks @ghengeveld!\n- CLI: Change yarn package manager value to yarn1 - [#33099](https://github.com/storybookjs/storybook/pull/33099), thanks @valentinpalkovic!\n- CLI: Fix 'beforeVersion' evaluation for Storybook package - [#33141](https://github.com/storybookjs/storybook/pull/33141), thanks @valentinpalkovic!\n- CLI: Fix access to getOptionValue in postAction hook - [#33119](https://github.com/storybookjs/storybook/pull/33119), thanks @valentinpalkovic!\n- CLI: Fix framework config validation path and messages - [#33146](https://github.com/storybookjs/storybook/pull/33146), thanks @valentinpalkovic!\n- CLI: Fix passing flags for bun users during init - [#33166](https://github.com/storybookjs/storybook/pull/33166), thanks @valentinpalkovic!\n- CLI: Fix Vitest v3 installs and refactor AddonVitestService; align create‑storybook usage - [#33131](https://github.com/storybookjs/storybook/pull/33131), thanks @valentinpalkovic!\n- CLI: In csf-factories codemod only remove types which are unused - [#33020](https://github.com/storybookjs/storybook/pull/33020), thanks @yannbf!\n- CLI: Minor improvements - [#33180](https://github.com/storybookjs/storybook/pull/33180), thanks @valentinpalkovic!\n- CLI: Modernize Storybook CLI with new init workflow, Clack UI, and Generator System - [#32717](https://github.com/storybookjs/storybook/pull/32717), thanks @valentinpalkovic!\n- CLI: Standardize debug log messages across the application - [#33123](https://github.com/storybookjs/storybook/pull/33123), thanks @valentinpalkovic!\n- CLI: Update clack - [#33151](https://github.com/storybookjs/storybook/pull/33151), thanks @valentinpalkovic!\n- CLI: Update compatibility guidance link in summary message - [#33117](https://github.com/storybookjs/storybook/pull/33117), thanks @valentinpalkovic!\n- CLI: Update postAction hook to use command parameter for logfile retrieval - [#33137](https://github.com/storybookjs/storybook/pull/33137), thanks @valentinpalkovic!\n- CLI: Update upgrade message - [#33182](https://github.com/storybookjs/storybook/pull/33182), thanks @yannbf!\n- Core: Fix `getDocsUrl` for canary versions - [#33128](https://github.com/storybookjs/storybook/pull/33128), thanks @ghengeveld!\n- Core: Fix testing widget focus outline - [#33172](https://github.com/storybookjs/storybook/pull/33172), thanks @ghengeveld!\n- Core: Improve globbing using dynamic CWD - [#32990](https://github.com/storybookjs/storybook/pull/32990), thanks @ia319!\n- Core: Rename `Listbox` component to `ActionList` and use it in `TagsFilterPanel` - [#33140](https://github.com/storybookjs/storybook/pull/33140), thanks @ghengeveld!\n- Core: Significantly improve Storybook's own accessibility - [#32458](https://github.com/storybookjs/storybook/pull/32458), thanks @Sidnioulz!\n- Core: Update `getDocsUrl` to add a default `ref` param and set `guide` as ref for links in the Guide - [#33111](https://github.com/storybookjs/storybook/pull/33111), thanks @ghengeveld!\n- Guide: Collapse checklist items by default - [#33160](https://github.com/storybookjs/storybook/pull/33160), thanks @ghengeveld!\n- Guide: Hide items for which their required feature is disabled (controls, viewport, interactions) - [#33113](https://github.com/storybookjs/storybook/pull/33113), thanks @ghengeveld!\n- Maintenance: Enable syntax minification for dead code elimination - [#33001](https://github.com/storybookjs/storybook/pull/33001), thanks @mrginglymus!\n- Manager: Added tokens and a dark color scheme for status colors - [#33081](https://github.com/storybookjs/storybook/pull/33081), thanks @MichaelArestad!\n- Middleware: Prepend `file://` to middleware `import` for Windows support - [#32955](https://github.com/storybookjs/storybook/pull/32955), thanks @ndelangen!\n- Onboarding: Guided tour checklist - [#32795](https://github.com/storybookjs/storybook/pull/32795), thanks @ghengeveld!\n- React: Add isPackage flag to component imports for better package identification - [#33090](https://github.com/storybookjs/storybook/pull/33090), thanks @kasperpeulen!\n- React: Add manifests/components.html page - [#32905](https://github.com/storybookjs/storybook/pull/32905), thanks @kasperpeulen!\n- React: Change examples to stories in manifests and show correct examples and prop types - [#32908](https://github.com/storybookjs/storybook/pull/32908), thanks @kasperpeulen!\n- React: Experimental code examples - [#32813](https://github.com/storybookjs/storybook/pull/32813), thanks @kasperpeulen!\n- React: Implement manifests/component.json for React - [#32751](https://github.com/storybookjs/storybook/pull/32751), thanks @kasperpeulen!\n- React: Improve automatic component, automatic imports, support barrel files and enhance story filtering - [#32939](https://github.com/storybookjs/storybook/pull/32939), thanks @kasperpeulen!\n- React: Improve error handling of component manifest generation - [#32855](https://github.com/storybookjs/storybook/pull/32855), thanks @kasperpeulen!\n- React: Improve error messages in component manifest - [#32954](https://github.com/storybookjs/storybook/pull/32954), thanks @kasperpeulen!\n- React: Improve import rewriting when tsconfig paths are used - [#33072](https://github.com/storybookjs/storybook/pull/33072), thanks @kasperpeulen!\n- Remove yarn esbuild pnp plugin - [#33097](https://github.com/storybookjs/storybook/pull/33097), thanks @mrginglymus!\n- Theming: Set `themes.normal` according to user preference and export `getPreferredColorScheme` - [#28721](https://github.com/storybookjs/storybook/pull/28721), thanks @elisezhg!\n- UI: Add padding for ArgsTable shadow in TabbedArgsTable - [#33034](https://github.com/storybookjs/storybook/pull/33034), thanks @Sidnioulz!\n- UI: Add VRTs to FileSearchModal in light theme - [#33022](https://github.com/storybookjs/storybook/pull/33022), thanks @Sidnioulz!\n- UI: Fix crashes in Select when passed falsy non-string options - [#33164](https://github.com/storybookjs/storybook/pull/33164), thanks @Sidnioulz!\n- UI: Fix regression on addon panel empty content fontsize - [#33021](https://github.com/storybookjs/storybook/pull/33021), thanks @Sidnioulz!\n- UI: Fix trivial RefBlocks ARIA violations - [#33026](https://github.com/storybookjs/storybook/pull/33026), thanks @Sidnioulz!\n- UI: Improve status handling in sidebar nodes - [#32965](https://github.com/storybookjs/storybook/pull/32965), thanks @yannbf!\n- UI: Increase border contrast of Checkbox, Radio, and Range - [#33064](https://github.com/storybookjs/storybook/pull/33064), thanks @MichaelArestad!\n- UI: Refocus search input after clearing it - [#33165](https://github.com/storybookjs/storybook/pull/33165), thanks @Sidnioulz!\n- UI: Rework default background of Color swatch for dark mode - [#33023](https://github.com/storybookjs/storybook/pull/33023), thanks @Sidnioulz!\n- Upgrade: Satellite compatible with 10.1 prerelease - [#32877](https://github.com/storybookjs/storybook/pull/32877), thanks @ndelangen!\n\n</details>\n\n## 10.0.8\n\n- React Native Web: Fix react native resuables and nativewind - [#33056](https://github.com/storybookjs/storybook/pull/33056), thanks @dannyhw!\n- React Native Web: Update vite-plugin-rnw for overall improvements - [#32991](https://github.com/storybookjs/storybook/pull/32991), thanks @dannyhw!\n- WebComponents: Fix `custom-elements.json` not being loaded - [#33045](https://github.com/storybookjs/storybook/pull/33045), thanks @ndelangen!\n\n## 10.0.7\n\n- ESLint: Only apply csf-strict rules on stories files - [#31963](https://github.com/storybookjs/storybook/pull/31963), thanks @cylewaitforit!\n- Next.js: Update SWC loader to support new wasm detection - [#33003](https://github.com/storybookjs/storybook/pull/33003), thanks @yannbf!\n\n## 10.0.6\n\n- CSF: Fix export interface declaration for NextPreview - [#32914](https://github.com/storybookjs/storybook/pull/32914), thanks @icopp!\n- Controls: Add range validation in Number Control - [#32539](https://github.com/storybookjs/storybook/pull/32539), thanks @ia319!\n- Fix: Export interface declaration for ReactMeta - [#32915](https://github.com/storybookjs/storybook/pull/32915), thanks @icopp!\n- Vitest Addon: Add support for Preact - [#32948](https://github.com/storybookjs/storybook/pull/32948), thanks @yannbf!\n\n## 10.0.5\n\n- Core: Add reentry guard to focus patch - [#32655](https://github.com/storybookjs/storybook/pull/32655), thanks @ia319!\n- Nextjs Vite: Update internal plugin to support `svgr` use cases - [#32957](https://github.com/storybookjs/storybook/pull/32957), thanks @yannbf!\n\n## 10.0.4\n\n- CLI: Fix issue with running Storybook after being initialized - [#32929](https://github.com/storybookjs/storybook/pull/32929), thanks @yannbf!\n- CRA: Fix `module` not defined in ESM - [#32940](https://github.com/storybookjs/storybook/pull/32940), thanks @ndelangen!\n\n## 10.0.3\n\n- Core: Better handling for TypeScript satisfies/as syntaxes - [#32891](https://github.com/storybookjs/storybook/pull/32891), thanks @yannbf!\n- Core: Fix wrong import to fix Yarn PnP support - [#32928](https://github.com/storybookjs/storybook/pull/32928), thanks @yannbf!\n- ESlint: Update `@storybook/experimental-nextjs-vite` in `no-renderer-packages` rule - [#32909](https://github.com/storybookjs/storybook/pull/32909), thanks @ndelangen!\n- React Native: Update withStorybook setup instructions - [#32919](https://github.com/storybookjs/storybook/pull/32919), thanks @dannyhw!\n\n## 10.0.2\n\n- CLI: Fix glob string formatting in csf-factories codemod - [#32880](https://github.com/storybookjs/storybook/pull/32880), thanks @yannbf!\n- Core: Improve file path resolution on Windows - [#32893](https://github.com/storybookjs/storybook/pull/32893), thanks @yannbf!\n- Vite: Update `optimizeViteDeps` for addon-docs and addon-vitest - [#32881](https://github.com/storybookjs/storybook/pull/32881), thanks @ndelangen!\n\n## 10.0.1\n\n- Presets: Fix incorrect imports - [#32875](https://github.com/storybookjs/storybook/pull/32875), thanks @ndelangen!\n- Upgrade: Satellite compatible with 10.1 prerelease - [#32877](https://github.com/storybookjs/storybook/pull/32877), thanks @ndelangen!\n\n## 10.0.0\n\nStorybook 10 contains one breaking change: it’s ESM-only. This simplifies our distribution and reduces install size by 29% while simultaneously unminifying dist code for easier debugging.\nIt also includes features to level up your UI development, documentation, and testing workflows:\n\n- 🧩 Module automocking for easier testing\n- 🏭 Typesafe CSF factories Preview for React\n- 💫 UI editing and sharing optimizations\n- 🏷️ Tag filtering exclusion and configuration for sidebar management\n- 🔀 Next 16, Vitest 4, Svelte async components, and more!\n\n<details>\n<summary>List of all updates</summary>\n\n- A11Y: Bugfix missing `manager.js` entry-file - [#32780](https://github.com/storybookjs/storybook/pull/32780), thanks @ndelangen!\n- A11y: Persist tab/highlight across docs navigation - [#32762](https://github.com/storybookjs/storybook/pull/32762), thanks @404Dealer!\n- Addon A11y: Prevent setting highlights for old results - [#32178](https://github.com/storybookjs/storybook/pull/32178), thanks @ghengeveld!\n- Addon Docs: Fix Symbol conversion issue in docs page and controls panel - [#32220](https://github.com/storybookjs/storybook/pull/32220), thanks @yannbf!\n- Addon Vitest: Fix incorrect file modifications during setup - [#32844](https://github.com/storybookjs/storybook/pull/32844), thanks @yannbf!\n- Addon Vitest: Support modifying mergeConfig on addon setup - [#32753](https://github.com/storybookjs/storybook/pull/32753), thanks @yannbf!\n- Addon-docs: Add eject button to canvas toolbar - [#29825](https://github.com/storybookjs/storybook/pull/29825), thanks @mihkeleidast!\n- AddonA11Y: Fix postinstall - [#32309](https://github.com/storybookjs/storybook/pull/32309), thanks @ndelangen!\n- AddonViewport: Stricter types - [#32324](https://github.com/storybookjs/storybook/pull/32324), thanks @hpohlmeyer!\n- Angular: Add fileURLToPath for preview annotation paths - [#32812](https://github.com/storybookjs/storybook/pull/32812), thanks @brandonroberts!\n- Angular: Fix `entry.polyfills` undefined error - [#32230](https://github.com/storybookjs/storybook/pull/32230), thanks @sk-pub!\n- Angular: Inherit options from browserTarget - [#32108](https://github.com/storybookjs/storybook/pull/32108), thanks @gingeekrishna!\n- AutoMigration: Fix sb10 migration when main config contains `require` - [#32558](https://github.com/storybookjs/storybook/pull/32558), thanks @ndelangen!\n- Build: Fix dts bundling external detection - [#32366](https://github.com/storybookjs/storybook/pull/32366), thanks @mrginglymus!\n- Cleanup: Remove duplicated entrypoints in core - [#32507](https://github.com/storybookjs/storybook/pull/32507), thanks @ndelangen!\n- CLI: Add addon-console automigration - [#32083](https://github.com/storybookjs/storybook/pull/32083), thanks @Sidnioulz!\n- CLI: Avoid mixed CSF in files with unconventional stories - [#32716](https://github.com/storybookjs/storybook/pull/32716), thanks @yannbf!\n- CLI: Change message in downgrade-blocker - [#32745](https://github.com/storybookjs/storybook/pull/32745), thanks @ndelangen!\n- CLI: CSF factories codemod - support annotations in npx context - [#32741](https://github.com/storybookjs/storybook/pull/32741), thanks @yannbf!\n- CLI: Fix CSF factories addon syncing in storybook add command - [#32728](https://github.com/storybookjs/storybook/pull/32728), thanks @yannbf!\n- CLI: Fix throwing in readonly environments - [#31785](https://github.com/storybookjs/storybook/pull/31785), thanks @JReinhold!\n- CLI: Init not running `dev` when it should fixed - [#32457](https://github.com/storybookjs/storybook/pull/32457), thanks @ndelangen!\n- CLI: Make relative imports default in csf-factories codemod - [#32610](https://github.com/storybookjs/storybook/pull/32610), thanks @copilot-swe-agent!\n- CLI: Switch over to modern-tar - [#32763](https://github.com/storybookjs/storybook/pull/32763), thanks @ayuhito!\n- Codemod: Replace `globby` with `tinyglobby` - [#31407](https://github.com/storybookjs/storybook/pull/31407), thanks @benmccann!\n- Controls: Allow primitive values of ReactNode argType - [#31931](https://github.com/storybookjs/storybook/pull/31931), thanks @alexey-kozlenkov!\n- Controls: Fix adding new values to arrays - [#32512](https://github.com/storybookjs/storybook/pull/32512), thanks @takashi-kasajima!\n- Core: Add \"open in editor\" feature - [#32452](https://github.com/storybookjs/storybook/pull/32452), thanks @yannbf!\n- Core: Add parameter typings for addon-pseudo-state - [#32384](https://github.com/storybookjs/storybook/pull/32384), thanks @mrginglymus!\n- Core: Dedupe aria-query and @testing-library/dom packages - [#32801](https://github.com/storybookjs/storybook/pull/32801), thanks @mrginglymus!\n- Core: Enhance warning for Testing Library's `screen` usage in docs mode - [#32851](https://github.com/storybookjs/storybook/pull/32851), thanks @yannbf!\n- Core: Ensure valid QR code URL - [#32661](https://github.com/storybookjs/storybook/pull/32661), thanks @ghengeveld!\n- Core: Fix `external-globals-plugin` handle `undefined` cache dir - [#32579](https://github.com/storybookjs/storybook/pull/32579), thanks @walkerburgin!\n- Core: Fix Node 24 deprecation warning - [#32382](https://github.com/storybookjs/storybook/pull/32382), thanks @JReinhold!\n- Core: Fix staticCopy not copying `index.html` to sub directory - [#32259](https://github.com/storybookjs/storybook/pull/32259), thanks @ndelangen!\n- Core: Fix stepping back through story interactions panel - [#32793](https://github.com/storybookjs/storybook/pull/32793), thanks @ia319!\n- Core: Improve addon detection in automigrations on windows - [#31937](https://github.com/storybookjs/storybook/pull/31937), thanks @mrginglymus!\n- Core: Improve es-toolkit usage for better tree-shaking - [#32787](https://github.com/storybookjs/storybook/pull/32787), thanks @mrginglymus!\n- Core: Join framework preset path with slash - [#32838](https://github.com/storybookjs/storybook/pull/32838), thanks @brandonroberts!\n- Core: Make `subtype` an optional property on an index input - [#32602](https://github.com/storybookjs/storybook/pull/32602), thanks @JReinhold!\n- Core: Mark pnp support as deprecated - [#32645](https://github.com/storybookjs/storybook/pull/32645), thanks @ndelangen!\n- Core: Prevent `BAIL` state from showing in interactions panel when switching stories - [#32172](https://github.com/storybookjs/storybook/pull/32172), thanks @ghengeveld!\n- Core: Prevent navigating to hidden (filtered) item - [#32715](https://github.com/storybookjs/storybook/pull/32715), thanks @ghengeveld!\n- Core: Remove CJS bundles, only ship ESM - [#31819](https://github.com/storybookjs/storybook/pull/31819), thanks @ndelangen!\n- Core: Replace es-toolkit compat imports with non-compat - [#32837](https://github.com/storybookjs/storybook/pull/32837), thanks @mrginglymus!\n- Core: Switch from `mlly` to `exsolve` - [#32383](https://github.com/storybookjs/storybook/pull/32383), thanks @mrginglymus!\n- Core: Update tags filter UI - [#32343](https://github.com/storybookjs/storybook/pull/32343), thanks @ghengeveld!\n- Core: Use `exsolve` `resolveModulePath` for `safeResolveModule` - [#32477](https://github.com/storybookjs/storybook/pull/32477), thanks @mrginglymus!\n- Core: Various QA fixes - [#32629](https://github.com/storybookjs/storybook/pull/32629), thanks @ghengeveld!\n- CoreServer: Fix `Arc can't get every window` - [#32508](https://github.com/storybookjs/storybook/pull/32508), thanks @ndelangen!\n- CSF: Add Storybook test syntax (Storybook v10) - [#32455](https://github.com/storybookjs/storybook/pull/32455), thanks @yannbf!\n- CSF: Enhance config-to-csf-factory to support type wrappers - [#32543](https://github.com/storybookjs/storybook/pull/32543), thanks @yannbf!\n- Dev: Improve the browser opening experience - [#32488](https://github.com/storybookjs/storybook/pull/32488), thanks @ndelangen!\n- Dts: Ensure `.tsx` files emit `.d.ts` type files - [#32461](https://github.com/storybookjs/storybook/pull/32461), thanks @mrginglymus!\n- Fix: Allow proceeding without selecting automigrations in upgrade command - [#32597](https://github.com/storybookjs/storybook/pull/32597), thanks @copilot-swe-agent!\n- Fix: ESLint plugin homepage URL updates - [#32445](https://github.com/storybookjs/storybook/pull/32445), thanks @VivekKavala!\n- Fix: Incorrect URLS for the upgrade command - [#32624](https://github.com/storybookjs/storybook/pull/32624), thanks @jonniebigodes!\n- Maintenance: Fix bundle size bloat caused by `SyntaxHighlighter` (`createElement`) - [#32800](https://github.com/storybookjs/storybook/pull/32800), thanks @mrginglymus!\n- Maintenance: Hotfix for missing nextjs dts files, thanks @ndelangen!\n- Maintenance: Remove globalization for dropped entrypoints - [#32491](https://github.com/storybookjs/storybook/pull/32491), thanks @ndelangen!\n- Mock: Catch errors when transforming preview files - [#32216](https://github.com/storybookjs/storybook/pull/32216), thanks @valentinpalkovic!\n- Modernize: Replace `fs-extra` with native APIs - [#32296](https://github.com/storybookjs/storybook/pull/32296), thanks @y-hsgw!\n- Move: Addon jest into it's own repository - [#32646](https://github.com/storybookjs/storybook/pull/32646), thanks @ndelangen!\n- Next.js-vite: Use `fileURLToPath` for module resolution in preset - [#32386](https://github.com/storybookjs/storybook/pull/32386), thanks @ndelangen!\n- Next.js: Avoid multiple webpack versions at runtime - [#32313](https://github.com/storybookjs/storybook/pull/32313), thanks @valentinpalkovic!\n- Next.js: Remove next/config usage in Next.js >=v16 projects - [#32547](https://github.com/storybookjs/storybook/pull/32547), thanks @valentinpalkovic!\n- Next.js: Return mocked router instead of actual router in useRouter - [#32131](https://github.com/storybookjs/storybook/pull/32131), thanks @JulioJ11!\n- Nextjs: Fix config access for Vite - [#32759](https://github.com/storybookjs/storybook/pull/32759), thanks @valentinpalkovic!\n- Nextjs: Fix Nextjs version detection with prereleases - [#32724](https://github.com/storybookjs/storybook/pull/32724), thanks @yannbf!\n- Onboarding: Prevent confetti overlay from intercepting pointer events - [#32660](https://github.com/storybookjs/storybook/pull/32660), thanks @ghengeveld!\n- Onboarding: Tweak referral wording in survey - [#32185](https://github.com/storybookjs/storybook/pull/32185), thanks @shilman!\n- PreactVite: Add `node` entry point - [#32534](https://github.com/storybookjs/storybook/pull/32534), thanks @ndelangen!\n- Presets: Support extensionless imports in TS-based presets - [#32641](https://github.com/storybookjs/storybook/pull/32641), thanks @JReinhold!\n- React Native: Fix document reference error in open-in-editor - [#32572](https://github.com/storybookjs/storybook/pull/32572), thanks @dannyhw!\n- React: Simplify version detection - [#32802](https://github.com/storybookjs/storybook/pull/32802), thanks @mrginglymus!\n- Replace: Use `empathic` over `find-up` - [#31338](https://github.com/storybookjs/storybook/pull/31338), thanks @beeequeue!\n- Svelte: Improve support for async components - [#31476](https://github.com/storybookjs/storybook/pull/31476), thanks @JReinhold!\n- Svelte: Simplify public types - use modern `Component` - [#31394](https://github.com/storybookjs/storybook/pull/31394), thanks @xeho91!\n- SvelteKit: Add support for mocking `$app/state` - [#31369](https://github.com/storybookjs/storybook/pull/31369), thanks @xeho91!\n- SvelteKit: Fix `set_context_after_init` error when experimental async is enabled - [#32513](https://github.com/storybookjs/storybook/pull/32513), thanks @Jakeii!\n- Tags: Remove undocumented x-only tags - [#32360](https://github.com/storybookjs/storybook/pull/32360), thanks @shilman!\n- Telemetry: Improve dev cancellation handling - [#32218](https://github.com/storybookjs/storybook/pull/32218), thanks @shilman!\n- Telemetry: Send index stats on dev exit - [#32168](https://github.com/storybookjs/storybook/pull/32168), thanks @shilman!\n- UI: Allow showing or hiding the addon panel - [#32348](https://github.com/storybookjs/storybook/pull/32348), thanks @Sidnioulz!\n- UI: Improve sidebar empty state - [#32548](https://github.com/storybookjs/storybook/pull/32548), thanks @ghengeveld!\n- UI: Improve syntax-highlighter bundling - [#32776](https://github.com/storybookjs/storybook/pull/32776), thanks @mrginglymus!\n- Update: Satellite repos after major version bump - [#32303](https://github.com/storybookjs/storybook/pull/32303), thanks @ndelangen!\n- Upgrade: Enhance ESM compatibility checks and banner generation - [#32694](https://github.com/storybookjs/storybook/pull/32694), thanks @ndelangen!\n- Upgrade: Packages `open` - [#32484](https://github.com/storybookjs/storybook/pull/32484), thanks @ndelangen!\n- Upgrades: Packages `boxen` `commander` `giget` - [#32469](https://github.com/storybookjs/storybook/pull/32469), thanks @ndelangen!\n- Vite: Optimize @storybook/addon-docs/blocks dependency - [#32798](https://github.com/storybookjs/storybook/pull/32798), thanks @mrginglymus!\n\n</details>\n\n## 9.1.16\n\n- CLI: Fix Nextjs project creation in empty directories - [#32828](https://github.com/storybookjs/storybook/pull/32828), thanks @yannbf!\n- Core: Add `experimental_devServer` preset - [#32862](https://github.com/storybookjs/storybook/pull/32862), thanks @yannbf!\n- Telemetry: Fix preview-first-load event - [#32859](https://github.com/storybookjs/storybook/pull/32859), thanks @shilman!\n\n## 9.1.15\n\n- Core: Add `preview-first-load` telemetry - [#32770](https://github.com/storybookjs/storybook/pull/32770), thanks @shilman!\n- Dependencies: Update `vite-plugin-storybook-nextjs` - [#32821](https://github.com/storybookjs/storybook/pull/32821), thanks @ndelangen!\n\n## 9.1.14\n\n- NextJS: Add NextJS 16 support - [#32791](https://github.com/storybookjs/storybook/pull/32791), thanks @yannbf and @ndelangen!\n- Addon-Vitest: Support Vitest 4 - [#32819](https://github.com/storybookjs/storybook/pull/32819), thanks @yannbf and @ndelangen!\n- CSF: Fix `play-fn` tag for methods - [#32695](https://github.com/storybookjs/storybook/pull/32695), thanks @shilman!\n\n## 9.1.13\n\n- Nextjs: Fix config access for Vite - [#32759](https://github.com/storybookjs/storybook/pull/32759), thanks @valentinpalkovic!\n\n## 9.1.12\n\n- Maintenance: Hotfix for missing nextjs dts files, thanks @ndelangen!\n\n## 9.1.11\n\n- Automigration: Improve the viewport/backgrounds automigration - [#32619](https://github.com/storybookjs/storybook/pull/32619), thanks @valentinpalkovic!\n- Mocking: Fix `sb.mock` usage in Storybook's deployed in subpaths - [#32678](https://github.com/storybookjs/storybook/pull/32678), thanks @valentinpalkovic!\n- NextJS-Vite: Automatically fix bad PostCSS configuration - [#32691](https://github.com/storybookjs/storybook/pull/32691), thanks @ndelangen!\n- React Native Web: Fix REACT_NATIVE_AND_RNW should detect vite builder - [#32718](https://github.com/storybookjs/storybook/pull/32718), thanks @dannyhw!\n- Telemetry: Add metadata for react routers - [#32615](https://github.com/storybookjs/storybook/pull/32615), thanks @shilman!\n\n## 9.1.10\n\n- Automigrations: Add automigration for viewport and backgrounds - [#31614](https://github.com/storybookjs/storybook/pull/31614), thanks @valentinpalkovic!\n- Telemetry: Log userAgent in onboarding - [#32566](https://github.com/storybookjs/storybook/pull/32566), thanks @shilman!\n\n## 9.1.9\n\n- Angular: Enable experimental zoneless detection on Angular v21 - [#32580](https://github.com/storybookjs/storybook/pull/32580), thanks @yannbf!\n- Svelte: Ignore inherited `HTMLAttributes` docgen when using utility types - [#32173](https://github.com/storybookjs/storybook/pull/32173), thanks @steciuk!\n\n## 9.1.8\n\n- PreactVite: Add `node` entry point - [#32534](https://github.com/storybookjs/storybook/pull/32534), thanks @ndelangen!\n\n## 9.1.7\n\n- Dependencies: Update `vite-plugin-storybook-nextjs` to 2.0.7 - [#32331](https://github.com/storybookjs/storybook/pull/32331), thanks @k35o!\n- React: Preserve `@ts-expect-error` in preview - [#32442](https://github.com/storybookjs/storybook/pull/32442), thanks @mrginglymus!\n- Telemetry: Queue error reporting & filter browser-extention - [#32499](https://github.com/storybookjs/storybook/pull/32499), thanks @ndelangen!\n\n## 9.1.6\n\n- CLI: Capture the version specifier used in `create-storybook` - [#32344](https://github.com/storybookjs/storybook/pull/32344), thanks @shilman!\n- Instrumenter: Fix userEvent.type performance regression - [#32439](https://github.com/storybookjs/storybook/pull/32439), thanks @ndelangen!\n- React Native Web: Fix RNW peer dependency version - [#32438](https://github.com/storybookjs/storybook/pull/32438), thanks @dannyhw!\n- Telemetry: Record known CLI integrations - [#32448](https://github.com/storybookjs/storybook/pull/32448), thanks @shilman!\n\n## 9.1.5\n\n- CSF: Support `satisfies x as y` syntax - [#32169](https://github.com/storybookjs/storybook/pull/32169), thanks @diagramatics!\n- Vitest addon: Handle Playwright installation errors gracefully - [#32329](https://github.com/storybookjs/storybook/pull/32329), thanks @ndelangen!\n\n## 9.1.4\n\n- Angular: Properly merge builder options and browserTarget options - [#32272](https://github.com/storybookjs/storybook/pull/32272), thanks @kroeder!\n- Core: Optimize bundlesize, by reusing internal/babel in mocking-utils - [#32350](https://github.com/storybookjs/storybook/pull/32350), thanks @ndelangen!\n- Svelte & Vue: Add framework-specific `docgen` option to disable docgen processing - [#32319](https://github.com/storybookjs/storybook/pull/32319), thanks @copilot-swe-agent!\n- Svelte: Support `@sveltejs/vite-plugin-svelte` v6 - [#32320](https://github.com/storybookjs/storybook/pull/32320), thanks @JReinhold!\n\n## 9.1.3\n\n- Docs: Move button in ArgsTable heading to fix screenreader announcements - [#32238](https://github.com/storybookjs/storybook/pull/32238), thanks @Sidnioulz!\n- Mock: Catch errors when transforming preview files - [#32216](https://github.com/storybookjs/storybook/pull/32216), thanks @valentinpalkovic!\n- Next.js: Fix version mismatch error in Webpack - [#32306](https://github.com/storybookjs/storybook/pull/32306), thanks @valentinpalkovic!\n- Telemetry: Disambiguate traffic coming from error/upgrade links - [#32287](https://github.com/storybookjs/storybook/pull/32287), thanks @shilman!\n- Telemetry: Disambiguate unattributed traffic from Onboarding - [#32286](https://github.com/storybookjs/storybook/pull/32286), thanks @shilman!\n\n## 9.1.2\n\n- Addon Docs: Fix Symbol conversion issue in docs page and controls panel - [#32220](https://github.com/storybookjs/storybook/pull/32220), thanks @yannbf!\n- Angular: Fix `entry.polyfills` undefined error - [#32230](https://github.com/storybookjs/storybook/pull/32230), thanks @sk-pub!\n- Angular: Inherit options from browserTarget - [#32108](https://github.com/storybookjs/storybook/pull/32108), thanks @gingeekrishna!\n- Core: Improve addon detection in automigrations on windows - [#31937](https://github.com/storybookjs/storybook/pull/31937), thanks @mrginglymus!\n- Next.js: Return mocked router instead of actual router in useRouter - [#32131](https://github.com/storybookjs/storybook/pull/32131), thanks @JulioJ11!\n- Telemetry: Improve dev cancellation handling - [#32218](https://github.com/storybookjs/storybook/pull/32218), thanks @shilman!\n\n## 9.1.1\n\n- CLI: Fix throwing in readonly environments - [#31785](https://github.com/storybookjs/storybook/pull/31785), thanks @JReinhold!\n- Onboarding: Tweak referral wording in survey - [#32185](https://github.com/storybookjs/storybook/pull/32185), thanks @shilman!\n- Telemetry: Send index stats on dev exit - [#32168](https://github.com/storybookjs/storybook/pull/32168), thanks @shilman!\n\n## 9.1.0\n\nStorybook 9.1 is packed with new features and improvements to enhance accessibility, streamline testing, and make your development workflow even smoother!\n\n🚀 Improved upgrade command with monorepo support for seamless upgrades\n🅰 Angular fixes for Tailwind 4, cache busting, and zoneless compatibility\n🧪 `sb.mock` API and Automocking: one-line module mocking to simplify your testing workflow\n🧪 Favicon shows test run status for quick visual feedback\n⚛️ Easier configuration for React Native projects\n🔥 Auto-abort play functions on HMR to avoid unwanted side effects\n🏗️ Improved CSF factories API for type safe story definitions\n♿️ A11y improvements across Storybook’s UI — addon panel, toolbar, sidebar, mobile & more\n💯 Dozens more fixes and improvements based on community feedback!\n\n<details>\n<summary>List of all updates</summary>\n\n- A11y: Improved toolbar a11y by fixing semantics - [#28672](https://github.com/storybookjs/storybook/pull/28672), thanks @mehm8128!\n- Addon Vitest: Remove Optimize deps candidates due to Vitest warnings - [#31809](https://github.com/storybookjs/storybook/pull/31809), thanks @valentinpalkovic!\n- Angular: Bundle using TSup - [#31690](https://github.com/storybookjs/storybook/pull/31690), thanks @ndelangen!\n- Angular: Prevent directory import in Angular builders - [#32012](https://github.com/storybookjs/storybook/pull/32012), thanks @ghengeveld!\n- Automigration: Await updateMainConfig in removeEssentials - [#32140](https://github.com/storybookjs/storybook/pull/32140), thanks @valentinpalkovic!\n- Builder-Vite: Fix logic related to setting allowedHosts when IP address used - [#31472](https://github.com/storybookjs/storybook/pull/31472), thanks @JSMike!\n- Controls: Improve the accessibility of the object control - [#31581](https://github.com/storybookjs/storybook/pull/31581), thanks @Sidnioulz!\n- Core: Abort play function on HMR - [#31542](https://github.com/storybookjs/storybook/pull/31542), thanks @ghengeveld!\n- Core: Avoid pausing animations in non-Vitest Playwright environments - [#32123](https://github.com/storybookjs/storybook/pull/32123), thanks @ghengeveld!\n- Core: Cleanup of type following up v9 and small verbatimModuleSyntax type fix - [#31823](https://github.com/storybookjs/storybook/pull/31823), thanks @alcpereira!\n- Core: Fix aria-controls attribute on sidebar nodes to include all children - [#31491](https://github.com/storybookjs/storybook/pull/31491), thanks @candrepa1!\n- Core: Fix horizontal scrollbar covering part of the toolbar - [#31704](https://github.com/storybookjs/storybook/pull/31704), thanks @Sidnioulz!\n- Core: Fix moving log file across drives and projectRoot detection on Windows - [#32020](https://github.com/storybookjs/storybook/pull/32020), thanks @ghengeveld!\n- Core: Prevent interactions panel from flickering and showing incorrect state - [#32150](https://github.com/storybookjs/storybook/pull/32150), thanks @ghengeveld!\n- Core: Serve dynamic favicon based on testing module status - [#31763](https://github.com/storybookjs/storybook/pull/31763), thanks @ghengeveld!\n- Core: Support container queries in addon panels - [#23261](https://github.com/storybookjs/storybook/pull/23261), thanks @neil-morrison44!\n- CSF Factories: Add parameters/globals types, `extend` API, portable stories - [#30601](https://github.com/storybookjs/storybook/pull/30601), thanks @kasperpeulen!\n- CSF: Improve controls parameters - [#31745](https://github.com/storybookjs/storybook/pull/31745), thanks @kasperpeulen!\n- CSF: Improve docs parameter types - [#31736](https://github.com/storybookjs/storybook/pull/31736), thanks @kasperpeulen!\n- CSF: Only add preview annotations to definePreview in csf-factories automigration - [#31727](https://github.com/storybookjs/storybook/pull/31727), thanks @kasperpeulen!\n- Docs: Update @storybook/icons - [#32144](https://github.com/storybookjs/storybook/pull/32144), thanks @valentinpalkovic!\n- Docs: Update `react-element-to-jsx-string` - [#31170](https://github.com/storybookjs/storybook/pull/31170), thanks @7rulnik!\n- Init: Exclude mdx stories when docs feature isn't selected during init - [#32142](https://github.com/storybookjs/storybook/pull/32142), thanks @valentinpalkovic!\n- Maintenance: Add flag to toggle default automigrations - [#32113](https://github.com/storybookjs/storybook/pull/32113), thanks @yannbf!\n- React Native Web: Simplify config by using vite-plugin-rnw - [#32051](https://github.com/storybookjs/storybook/pull/32051), thanks @dannyhw!\n- Telemetry: Add automigration errors - [#32103](https://github.com/storybookjs/storybook/pull/32103), thanks @yannbf!\n- Telemetry: Fix `project.json` for getAbsolutePath - [#31510](https://github.com/storybookjs/storybook/pull/31510), thanks @ndelangen!\n- Test: Add mock capabilities - [#31987](https://github.com/storybookjs/storybook/pull/31987), thanks @valentinpalkovic!\n- Test: Consider exports map - [#32157](https://github.com/storybookjs/storybook/pull/32157), thanks @valentinpalkovic!\n- Test: Fix missing source map for Webpack/Vite mock loaders and plugins - [#32111](https://github.com/storybookjs/storybook/pull/32111), thanks @valentinpalkovic!\n- Test: Invalidate vite cache for manual mocks - [#32152](https://github.com/storybookjs/storybook/pull/32152), thanks @valentinpalkovic!\n- Test: Remove source map generation from webpack automock-loader - [#32115](https://github.com/storybookjs/storybook/pull/32115), thanks @valentinpalkovic!\n- UI: Apply user updates for mobile navigation accessibility - [#31401](https://github.com/storybookjs/storybook/pull/31401), thanks @yatishgoel!\n- UI: Fix interaction step collapse icon - [#31853](https://github.com/storybookjs/storybook/pull/31853), thanks @AvitalHass!\n- UI: Visual focus indicators (VFIs) aren't visible in high contrast mode (rebase) - [#31848](https://github.com/storybookjs/storybook/pull/31848), thanks @Sidnioulz!\n\n</details>\n\n## 9.0.18\n\n- CLI: Fix Storybook doctor compatibility checks - [#32077](https://github.com/storybookjs/storybook/pull/32077), thanks @yannbf!\n- Svelte: Fix union types generating invalid labels in argTypes - [#31980](https://github.com/storybookjs/storybook/pull/31980), thanks @grantralls!\n- Telemetry: Add nodeLinker to telemetry - [#32072](https://github.com/storybookjs/storybook/pull/32072), thanks @valentinpalkovic!\n\n## 9.0.17\n\n- Addon Vitest: Fix support for plain `stories.tsx` files - [#32041](https://github.com/storybookjs/storybook/pull/32041), thanks @ghengeveld!\n- Onboarding: Intent survey - [#31944](https://github.com/storybookjs/storybook/pull/31944), thanks @ghengeveld!\n- UI: Fix text color for failing stories in sidebar - [#32042](https://github.com/storybookjs/storybook/pull/32042), thanks @ghengeveld!\n\n## 9.0.16\n\n- Automigration: Fail with non-zero exit code on migration failure - [#31923](https://github.com/storybookjs/storybook/pull/31923), thanks @mrginglymus!\n- CLI: Fix `sb` CLI by explicitly exporting `bin/index.cjs` from `storybook` package - [#31922](https://github.com/storybookjs/storybook/pull/31922), thanks @ghengeveld!\n- Core: Fix issue where collapsed test controls can be tabbed into - [#31921](https://github.com/storybookjs/storybook/pull/31921), thanks @zenocross!\n- Core: Various fixes - [#31870](https://github.com/storybookjs/storybook/pull/31870), thanks @ghengeveld!\n- Docs: Prevent JSON tree control from swallowing keyboard events when not in focus - [#31841](https://github.com/storybookjs/storybook/pull/31841), thanks @takashi-kasajima!\n- Ember: Allow ember v5 as peer deps - [#25893](https://github.com/storybookjs/storybook/pull/25893), thanks @gossi!\n- Next.js: upgrade sass-loader to 16.0.5 - [#31855](https://github.com/storybookjs/storybook/pull/31855), thanks @terrymun!\n- NextJs-Vite: Enable next/font loading when using next-vite - [#31906](https://github.com/storybookjs/storybook/pull/31906), thanks @k35o!\n- Portable stories: Fix playwright CT to allow functions to be passed as props - [#31335](https://github.com/storybookjs/storybook/pull/31335), thanks @adamscybot!\n- UI: Set color scheme to sync scrollbar color with user-selected theme - [#28666](https://github.com/storybookjs/storybook/pull/28666), thanks @elisezhg!\n\n## 9.0.15\n\n- CLI: Do not fail incompatible package check in doctor if only core packages used - [#31886](https://github.com/storybookjs/storybook/pull/31886), thanks @mrginglymus!\n- React: Bump @joshwooding/vite-plugin-react-docgen-typescript to 0.6.1 - [#31899](https://github.com/storybookjs/storybook/pull/31899), thanks @mrginglymus!\n\n## 9.0.14\n\n- CLI: Prebundle more in cli-storybook package - [#31746](https://github.com/storybookjs/storybook/pull/31746), thanks @ndelangen!\n- Core: Fix FIPS compliance - [#31806](https://github.com/storybookjs/storybook/pull/31806), thanks @JReinhold!\n- Core: Fix addon scrollbars and align scrollbar colors with toolbars - [#31844](https://github.com/storybookjs/storybook/pull/31844), thanks @Sidnioulz!\n- Deps: Extend `vite` peerDependencies range to include `7.0.0` - [#31859](https://github.com/storybookjs/storybook/pull/31859), thanks @ghengeveld!\n- Deps: Update vite-plugin-babel to 1.3.2 to fix vite 7.0.0 peerDependency issue - [#31888](https://github.com/storybookjs/storybook/pull/31888), thanks @ghengeveld!\n- UI: Hide keyboard shortcuts entry from menu when shortcuts are disabled - [#23411](https://github.com/storybookjs/storybook/pull/23411), thanks @Spielboerg!\n\n## 9.0.13\n\n- Core: Gracefully handle disallowed cross-origin clipboard access - [#31834](https://github.com/storybookjs/storybook/pull/31834), thanks @ghengeveld!\n- Core: Support array-based catch-all Next.js route segments in AppRouterProvider - [#31524](https://github.com/storybookjs/storybook/pull/31524), thanks @yatishgoel!\n- Next.js-Vite: Support Next.js v15.4 - [#31828](https://github.com/storybookjs/storybook/pull/31828), thanks @valentinpalkovic!\n- React Native Web: Fix shift spread operator in react-native-web-vite presets - [#31804](https://github.com/storybookjs/storybook/pull/31804), thanks @xlecunff-pass!\n- Telemetry: Fix prompting without checking isTTY - [#31781](https://github.com/storybookjs/storybook/pull/31781), thanks @Synar!\n- Vite: Remove addon-themes and theming from optimized deps list - [#31833](https://github.com/storybookjs/storybook/pull/31833), thanks @ghengeveld!\n\n## 9.0.12\n\n- Addon Vitest: Support init in Vitest >= 3.2 - [#31715](https://github.com/storybookjs/storybook/pull/31715), thanks @valentinpalkovic!\n- CLI: Fix package manager instantiation in empty directories - [#31743](https://github.com/storybookjs/storybook/pull/31743), thanks @yannbf!\n- CLI: Improve support for upgrading Storybook in monorepos - [#31557](https://github.com/storybookjs/storybook/pull/31557), thanks @yannbf!\n- CLI: Show Storybook version in the upgrade command - [#31774](https://github.com/storybookjs/storybook/pull/31774), thanks @yannbf!\n- Core: Enhance package manager install methods to support optional force flag - [#31796](https://github.com/storybookjs/storybook/pull/31796), thanks @valentinpalkovic!\n\n## 9.0.11\n\n- Addons: Use chromatic-com/storybook without version specifier - [#31627](https://github.com/storybookjs/storybook/pull/31627), thanks @valentinpalkovic!\n- Angular: Tailwind 4 compatibility - [#31759](https://github.com/storybookjs/storybook/pull/31759), thanks @valentinpalkovic!\n- Angular: fix Storybook experimentalZoneless is not compatible with Angular 20 - [#31772](https://github.com/storybookjs/storybook/pull/31772), thanks @guysenpai!\n- React Native: Fix window event listeners that dont exist on rn - [#31780](https://github.com/storybookjs/storybook/pull/31780), thanks @dannyhw!\n\n## 9.0.10\n\n- CLI: Add RN/RNW \"both\" init option - [#31778](https://github.com/storybookjs/storybook/pull/31778), thanks @shilman!\n- Nextjs-Vite: Use tsconfig paths plugin - [#31764](https://github.com/storybookjs/storybook/pull/31764), thanks @kasperpeulen!\n\n## 9.0.9\n\n- Angular: Update MiniCssExtractPlugin configuration for cache busting - [#31752](https://github.com/storybookjs/storybook/pull/31752), thanks @valentinpalkovic!\n- CSF: Story ComponentAnnotations['subcomponents'] to correctly use its own type for subcomponents rather than attempt to inherit from the component - [#31723](https://github.com/storybookjs/storybook/pull/31723), thanks @mihkeleidast!\n- Core: Delete shim addon packages - [#31728](https://github.com/storybookjs/storybook/pull/31728), thanks @ndelangen!\n- Core: Disable interactions debugger on composed stories to avoid cross-origin error - [#31685](https://github.com/storybookjs/storybook/pull/31685), thanks @ghengeveld!\n- Core: Fix cyclical dependency in core addons - [#31750](https://github.com/storybookjs/storybook/pull/31750), thanks @JReinhold!\n- Core: Restore original clipboard after invoking `userEvent.setup()` - [#31730](https://github.com/storybookjs/storybook/pull/31730), thanks @ghengeveld!\n- Next.js: Add webpack alias to resolve Next.js package conflicts - [#31755](https://github.com/storybookjs/storybook/pull/31755), thanks @valentinpalkovic!\n- Next.js: Enhance Vite configuration with styled-jsx aliasing - [#31757](https://github.com/storybookjs/storybook/pull/31757), thanks @valentinpalkovic!\n\n## 9.0.8\n\n- Addon Docs: Fix SyntaxHighlighter \"Copy\" button by avoiding potentially mocked clipboard - [#31682](https://github.com/storybookjs/storybook/pull/31682), thanks @ghengeveld!\n- Addon Themes: Define missing React dependencies - [#31688](https://github.com/storybookjs/storybook/pull/31688), thanks @ghengeveld!\n- Addon-vitest: Fix adding with `--skip-install` failing missing packageJson invariant - [#31720](https://github.com/storybookjs/storybook/pull/31720), thanks @JReinhold!\n- AddonDocs: Remove export of blocks - [#31724](https://github.com/storybookjs/storybook/pull/31724), thanks @ndelangen!\n- Automigration: Enhance removeEssentials to convert options - [#31658](https://github.com/storybookjs/storybook/pull/31658), thanks @ndelangen!\n- CLI: Don't install addon-onboarding during minimal installs - [#31616](https://github.com/storybookjs/storybook/pull/31616), thanks @ghengeveld!\n\n> [!NOTE]  \n> Version 9.0.7 was skipped because of a bad release of `eslint-plugin-storybook`.\n\n## 9.0.6\n\n- Addon Docs: Fix reference to global JSX namespace - [#31671](https://github.com/storybookjs/storybook/pull/31671), thanks @mrginglymus!\n- Angular: Improve Vite compatibility - [#31686](https://github.com/storybookjs/storybook/pull/31686), thanks @ndelangen!\n- Preview: Fix type issues - [#31537](https://github.com/storybookjs/storybook/pull/31537), thanks @mrginglymus!\n- Telemetry: Improve error handling - [#31656](https://github.com/storybookjs/storybook/pull/31656), thanks @ndelangen!\n\n## 9.0.5\n\n- Addon A11y: Briefly disable highlights while Axe is running - [#31621](https://github.com/storybookjs/storybook/pull/31621), thanks @ghengeveld!\n- CLI: Consider Storybook React Native packages in upgrade command - [#31645](https://github.com/storybookjs/storybook/pull/31645), thanks @yannbf!\n- Next.js: Fix module transpilation - [#31501](https://github.com/storybookjs/storybook/pull/31501), thanks @valentinpalkovic!\n- Svelte: Fix source view always using `<wrapper ...>` - [#31639](https://github.com/storybookjs/storybook/pull/31639), thanks @JReinhold!\n- Testing: Fix `toSatisfy`-matcher implementation - [#31664](https://github.com/storybookjs/storybook/pull/31664), thanks @ndelangen!\n\n## 9.0.4\n\n- Addon Vitest: Fix path comparison on Windows - [#31630](https://github.com/storybookjs/storybook/pull/31630), thanks @valentinpalkovic!\n- Addon Vitest: Fix path comparison on Windows - [#31634](https://github.com/storybookjs/storybook/pull/31634), thanks @valentinpalkovic!\n\n## 9.0.3\n\n- Addon-Vitest: Properly merge configs - [#31629](https://github.com/storybookjs/storybook/pull/31629), thanks @valentinpalkovic!\n- Angular: Support v20 - [#31611](https://github.com/storybookjs/storybook/pull/31611), thanks @valentinpalkovic!\n- CLI: Update VTA version range for storybook init - [#31612](https://github.com/storybookjs/storybook/pull/31612), thanks @ghengeveld!\n\n## 9.0.2\n\n- CLI: Respect --skip-install in postinstall scripts - [#31605](https://github.com/storybookjs/storybook/pull/31605), thanks @yannbf!\n\n## 9.0.1\n\n- Angular: Include 20.x in version range - [#31602](https://github.com/storybookjs/storybook/pull/31602), thanks @shilman!\n- CLI: Update React Native init generator for v9 - [#31600](https://github.com/storybookjs/storybook/pull/31600), thanks @dannyhw!\n- React Native Web: Include expo in babel transforms - [#31607](https://github.com/storybookjs/storybook/pull/31607), thanks @dannyhw!\n- Telemetry: Fix storybook version and add test run events - [#31473](https://github.com/storybookjs/storybook/pull/31473), thanks @tmeasday!\n\n## 9.0.0\n\n#### Storybook 9.0 is here\n\nThis is a huge release focused on testing and bundle size.\n\n- Component testing\n  - 👆 Interactions\n  - ♿️ Accessibility\n  - 👁️ Visual changes\n  - 🛡️ Coverage\n- 🪶 48% lighter bundle\n- 🏷️ Tags-based organization\n- 🌐 Story globals\n- 🏗️ Major upgrades: Svelte, Next, React Native, Angular\n\nPlease checkout our [Migration guide](https://storybook.js.org/docs/9/migration-guide) to upgrade from earlier versions of Storybook. To see a comprehensive list of changes that went into 9.0, you can refer to the [9.0 prerelease changelogs](./CHANGELOG.prerelease.md)\n\n<details>\n<summary>List of all updates</summary>\n\n- Addon A11y: Add `linkPath` to Axe results and use it in copy link action - [#31009](https://github.com/storybookjs/storybook/pull/31009), thanks @ghengeveld!\n- Addon A11y: Fix setup as part of storybook create - [#31403](https://github.com/storybookjs/storybook/pull/31403), thanks @yannbf!\n- Addon A11y: Fix usage of axe-core in pnpm projects - [#31422](https://github.com/storybookjs/storybook/pull/31422), thanks @yannbf!\n- Addon A11y: Fix various issues and inconsistencies - [#31432](https://github.com/storybookjs/storybook/pull/31432), thanks @ghengeveld!\n- Addon A11y: Improve selector automigration detection - [#31392](https://github.com/storybookjs/storybook/pull/31392), thanks @yannbf!\n- Addon A11y: Only run checks in story mode - [#30976](https://github.com/storybookjs/storybook/pull/30976), thanks @kroeder!\n- Addon A11y: Provide full report in a11y manual runs - [#31325](https://github.com/storybookjs/storybook/pull/31325), thanks @yannbf!\n- Addon A11y: Use short titles and friendly summary messages in A11y report - [#31185](https://github.com/storybookjs/storybook/pull/31185), thanks @ghengeveld!\n- Addon Controls: Fix loading state UI in addon panel - [#31168](https://github.com/storybookjs/storybook/pull/31168), thanks @iineineno03k!\n- Addon Docs: Fix `layout: centered` in conjunction with `inline: false` - [#31430](https://github.com/storybookjs/storybook/pull/31430), thanks @ghengeveld!\n- Addon Docs: Fix docs-content overflow with TOC - [#27167](https://github.com/storybookjs/storybook/pull/27167), thanks @njsokol!\n- Addon Docs: Fix iframe content width in centered layout - [#31320](https://github.com/storybookjs/storybook/pull/31320), thanks @Audie80!\n- Addon Docs: Improve TableOfContents HTML structure and a11y - [#31327](https://github.com/storybookjs/storybook/pull/31327), thanks @Sidnioulz!\n- Addon Docs: Reset error boundary when story changes to recover from erros - [#31242](https://github.com/storybookjs/storybook/pull/31242), thanks @yatishgoel!\n- Addon Docs: Simplify color parsing and color cycling logic - [#29840](https://github.com/storybookjs/storybook/pull/29840), thanks @leyvae!\n- Addon Docs: Update telejson - [#31115](https://github.com/storybookjs/storybook/pull/31115), thanks @valentinpalkovic!\n- Addon Pseudo States: Move package into monorepo - [#31123](https://github.com/storybookjs/storybook/pull/31123), thanks @ghengeveld!\n- Addon Test: Improve unhandled error messages - [#30755](https://github.com/storybookjs/storybook/pull/30755), thanks @yannbf!\n- Addon Test: Rename `@storybook/experimental-addon-test` to `@storybook/addon-vitest` - [#31014](https://github.com/storybookjs/storybook/pull/31014), thanks @valentinpalkovic!\n- Addon Vitest: Ensure vitest exclusions are relative to the project root, not cwd - [#31514](https://github.com/storybookjs/storybook/pull/31514), thanks @mrginglymus!\n- Addon Vitest: Fix broken docs links - [#31445](https://github.com/storybookjs/storybook/pull/31445), thanks @kylegach!\n- Addon Vitest: Fix watch mode for new files - [#31156](https://github.com/storybookjs/storybook/pull/31156), thanks @valentinpalkovic!\n- Addon Vitest: Ignore mdx files as part of tests - [#31457](https://github.com/storybookjs/storybook/pull/31457), thanks @yannbf!\n- Addon Vitest: Improve handling multiple browser mode projects - [#31508](https://github.com/storybookjs/storybook/pull/31508), thanks @yannbf!\n- Addon Vitest: Support `vitest.projects.ts` file as workspace file during postinstall - [#31565](https://github.com/storybookjs/storybook/pull/31565), thanks @ghengeveld!\n- Addon Vitest: Transform @storybook/nextjs imports to @storybook/nextjs-vite during init - [#31180](https://github.com/storybookjs/storybook/pull/31180), thanks @valentinpalkovic!\n- Addon Vitest: Use its own cache directory - [#31439](https://github.com/storybookjs/storybook/pull/31439), thanks @yannbf!\n- Addon-a11y: Replace `element` parameter with `context` - [#31036](https://github.com/storybookjs/storybook/pull/31036), thanks @JReinhold!\n- Addon-A11y: Various improvements - [#30774](https://github.com/storybookjs/storybook/pull/30774), thanks @ghengeveld!\n- Addon-Essentials: Remove addon-docs - [#30856](https://github.com/storybookjs/storybook/pull/30856), thanks @ndelangen!\n- Addon-Test: Automatically load before all - [#30584](https://github.com/storybookjs/storybook/pull/30584), thanks @kasperpeulen!\n- Addon-test: Exclude `storybook-static` from coverage reports - [#31005](https://github.com/storybookjs/storybook/pull/31005), thanks @JReinhold!\n- Addon-test: Fix watching non-story files, run all tests on preview change - [#31045](https://github.com/storybookjs/storybook/pull/31045), thanks @JReinhold!\n- Addon-Test: Migrate to new test provider API, drop Vitest 2 support - [#30875](https://github.com/storybookjs/storybook/pull/30875), thanks @JReinhold!\n- Addon-Vitest: Always clean coverage before (re)running - [#31540](https://github.com/storybookjs/storybook/pull/31540), thanks @JReinhold!\n- Addon-vitest: Fix coverage being disabled with Run All button - [#31074](https://github.com/storybookjs/storybook/pull/31074), thanks @JReinhold!\n- Addon-vitest: Fix coverage when restarting Vitest due to config change - [#31069](https://github.com/storybookjs/storybook/pull/31069), thanks @JReinhold!\n- Addon-vitest: Fix wrong test count in telemetry - [#31504](https://github.com/storybookjs/storybook/pull/31504), thanks @JReinhold!\n- Addon-vitest: Remove internal log for `staticDir` - [#31340](https://github.com/storybookjs/storybook/pull/31340), thanks @JReinhold!\n- Addon-vitest: Support paths with spaces - [#31437](https://github.com/storybookjs/storybook/pull/31437), thanks @ndelangen!\n- Addons: Add shim Storybook addons for previously removed addons - [#31520](https://github.com/storybookjs/storybook/pull/31520), thanks @valentinpalkovic!\n- Addons: Move @storybook/addon-interactions into core - [#30916](https://github.com/storybookjs/storybook/pull/30916), thanks @valentinpalkovic!\n- Addons: Remove @storybook/addon-storysource - [#31007](https://github.com/storybookjs/storybook/pull/31007), thanks @valentinpalkovic!\n- Addons: Update the Viewport and Background Addon - [#30841](https://github.com/storybookjs/storybook/pull/30841), thanks @ndelangen!\n- AddonVitest: Use framework package, not renderer - [#31133](https://github.com/storybookjs/storybook/pull/31133), thanks @ndelangen!\n- All packages: Remove unused dependencies - [#31227](https://github.com/storybookjs/storybook/pull/31227), thanks @webpro!\n- Angular: Add @angular-devkit/build-angular to default installed pacakages in angular - [#30790](https://github.com/storybookjs/storybook/pull/30790), thanks @kasperpeulen!\n- Angular: Filter non-inputs from controls - [#30550](https://github.com/storybookjs/storybook/pull/30550), thanks @robertIsaac!\n- Angular: remove invalid defaults for start-storybook - [#31337](https://github.com/storybookjs/storybook/pull/31337), thanks @AgentEnder!\n- ArgTypes: Always extract argTypes, even without `addon-docs` - [#31488](https://github.com/storybookjs/storybook/pull/31488), thanks @JReinhold!\n- Autoblock: Add autoblocker for addon-test - [#31068](https://github.com/storybookjs/storybook/pull/31068), thanks @valentinpalkovic!\n- Autoblock: Fix link - [#31236](https://github.com/storybookjs/storybook/pull/31236), thanks @valentinpalkovic!\n- AutoBlocker: Add major version upgrade blocker - [#30714](https://github.com/storybookjs/storybook/pull/30714), thanks @ndelangen!\n- Automigrate: Disable `missingStorybookDependencies` for 9.0 - [#30769](https://github.com/storybookjs/storybook/pull/30769), thanks @ndelangen!\n- Automigrate: Prefer framework import - [#30785](https://github.com/storybookjs/storybook/pull/30785), thanks @ndelangen!\n- Automigration: Add new Storybook addons to consolidated packages mapping - [#30993](https://github.com/storybookjs/storybook/pull/30993), thanks @valentinpalkovic!\n- Automigration: Adjust addon-docs install condition - [#31343](https://github.com/storybookjs/storybook/pull/31343), thanks @valentinpalkovic!\n- Automigration: Always scan file system to substitute essential addons - [#31176](https://github.com/storybookjs/storybook/pull/31176), thanks @valentinpalkovic!\n- Automigration: Correctly apply the wrap-require automigration in ESM modules - [#31420](https://github.com/storybookjs/storybook/pull/31420), thanks @valentinpalkovic!\n- Automigration: Enhance import transformation to handle partial package matches - [#31033](https://github.com/storybookjs/storybook/pull/31033), thanks @valentinpalkovic!\n- Automigration: Ensure correct addition of missing dependencies - [#31023](https://github.com/storybookjs/storybook/pull/31023), thanks @valentinpalkovic!\n- Automigration: Fix an issue when main.js addons have dynamic values - [#31273](https://github.com/storybookjs/storybook/pull/31273), thanks @valentinpalkovic!\n- Automigration: Fix consolidated-imports with sub-paths - [#31135](https://github.com/storybookjs/storybook/pull/31135), thanks @ndelangen!\n- Automigration: Fix wrap require wrapper - [#31569](https://github.com/storybookjs/storybook/pull/31569), thanks @valentinpalkovic!\n- Automigration: Improve renderer to framework automigration - [#31397](https://github.com/storybookjs/storybook/pull/31397), thanks @valentinpalkovic!\n- Automigration: Migrate users to codePanel - [#31313](https://github.com/storybookjs/storybook/pull/31313), thanks @valentinpalkovic!\n- Automigration: Misc addon-essentials migration fixes - [#31072](https://github.com/storybookjs/storybook/pull/31072), thanks @valentinpalkovic!\n- Automigration: Pass over flags when calling automigrations - [#31342](https://github.com/storybookjs/storybook/pull/31342), thanks @valentinpalkovic!\n- Automigration: Remove `@storybook/addon-essentials` proper - [#31015](https://github.com/storybookjs/storybook/pull/31015), thanks @ndelangen!\n- Automigration: Remove `docs.autodocs` field - [#31203](https://github.com/storybookjs/storybook/pull/31203), thanks @ndelangen!\n- Automigration: Respect config-dir option - [#31233](https://github.com/storybookjs/storybook/pull/31233), thanks @valentinpalkovic!\n- Automigration: Update mapping for '@storybook/experimental-nextjs-vite' - [#30991](https://github.com/storybookjs/storybook/pull/30991), thanks @valentinpalkovic!\n- Automigrations: Add logging - [#31066](https://github.com/storybookjs/storybook/pull/31066), thanks @valentinpalkovic!\n- Automigrations: Fix installation of addon-docs - [#31399](https://github.com/storybookjs/storybook/pull/31399), thanks @valentinpalkovic!\n- Automigrations: Re-add renderer-to-framework and fix issue in monorepositories - [#31011](https://github.com/storybookjs/storybook/pull/31011), thanks @valentinpalkovic!\n- Backgrounds/Viewport: Fix resetting - [#31386](https://github.com/storybookjs/storybook/pull/31386), thanks @valentinpalkovic!\n- Blocks: IconGallery improvement - [#30743](https://github.com/storybookjs/storybook/pull/30743), thanks @leeovictor!\n- Build: Update import paths and enable syntax minification - [#31390](https://github.com/storybookjs/storybook/pull/31390), thanks @ndelangen!\n- Cleanup: Remove obsolete dependency - [#31177](https://github.com/storybookjs/storybook/pull/31177), thanks @valentinpalkovic!\n- CLI: Add `storybook-static` to `.gitignore` on init - [#31201](https://github.com/storybookjs/storybook/pull/31201), thanks @JReinhold!\n- CLI: Add detection for the storybook package being behind any other core packages - [#30861](https://github.com/storybookjs/storybook/pull/30861), thanks @kasperpeulen!\n- CLI: Add index command / API - [#30071](https://github.com/storybookjs/storybook/pull/30071), thanks @shilman!\n- CLI: Add React Native `.rnstorybook` CLI automigration - [#30882](https://github.com/storybookjs/storybook/pull/30882), thanks @shilman!\n- CLI: Detect correct storybook version on upgrade - [#31393](https://github.com/storybookjs/storybook/pull/31393), thanks @yannbf!\n- CLI: Do not install renderer package on `init` - [#30799](https://github.com/storybookjs/storybook/pull/30799), thanks @ndelangen!\n- CLI: Enhance compatibility check: deprecated detection - [#31317](https://github.com/storybookjs/storybook/pull/31317), thanks @ndelangen!\n- CLI: Fix framework for preview imports - [#31101](https://github.com/storybookjs/storybook/pull/31101), thanks @valentinpalkovic!\n- CLI: Fix get versions utility for NPM - [#29577](https://github.com/storybookjs/storybook/pull/29577), thanks @johnrcui!\n- CLI: Improve CLI upgrade process for @latest and @next - [#31356](https://github.com/storybookjs/storybook/pull/31356), thanks @yannbf!\n- CLI: Improve package upgrade logic - [#31406](https://github.com/storybookjs/storybook/pull/31406), thanks @yannbf!\n- CLI: Install prereleases of `@chromatic-com/storybook` - [#30662](https://github.com/storybookjs/storybook/pull/30662), thanks @JReinhold!\n- CLI: Make sure that the add commands logs all output to the console - [#30865](https://github.com/storybookjs/storybook/pull/30865), thanks @kasperpeulen!\n- CLI: Remove `@latest` from `yarn create` commands - [#31458](https://github.com/storybookjs/storybook/pull/31458), thanks @ndelangen!\n- CLI: Supress npm notice update log messages - [#31334](https://github.com/storybookjs/storybook/pull/31334), thanks @yannbf!\n- CLI: Tweak init prompt - [#31376](https://github.com/storybookjs/storybook/pull/31376), thanks @shilman!\n- CLI: Update nx docs in Storybook detection error - [#31266](https://github.com/storybookjs/storybook/pull/31266), thanks @yannbf!\n- CLI: Wrap object addon names in wrap-require migration - [#31285](https://github.com/storybookjs/storybook/pull/31285), thanks @yatishgoel!\n- CodePanel: Show originalSource code - [#31456](https://github.com/storybookjs/storybook/pull/31456), thanks @valentinpalkovic!\n- Controls: Embed addon-controls into the core - [#30864](https://github.com/storybookjs/storybook/pull/30864), thanks @ndelangen!\n- Controls: Remove empty state video link - [#31539](https://github.com/storybookjs/storybook/pull/31539), thanks @kylegach!\n- Core / Addon A11y: Emit `STORY_HOT_UPDATED` and rerun A11y tests on HMR - [#31423](https://github.com/storybookjs/storybook/pull/31423), thanks @ghengeveld!\n- Core: Add error boundary to tabs to prevent addon errors breaking Storybook - [#30952](https://github.com/storybookjs/storybook/pull/30952), thanks @kasperpeulen!\n- Core: Add highlight as public API - [#31134](https://github.com/storybookjs/storybook/pull/31134), thanks @valentinpalkovic!\n- Core: Add preview navigator and `--preview-only` CLI flag - [#31102](https://github.com/storybookjs/storybook/pull/31102), thanks @JReinhold!\n- Core: Automatically expand testing module on unhandled error - [#31028](https://github.com/storybookjs/storybook/pull/31028), thanks @ghengeveld!\n- Core: Avoid pre-bundling of preview-api in manager entries - [#31385](https://github.com/storybookjs/storybook/pull/31385), thanks @valentinpalkovic!\n- Core: Bring back loading globals from global types in portable stories - [#31328](https://github.com/storybookjs/storybook/pull/31328), thanks @yannbf!\n- Core: Builder-manager disable metafile - [#31467](https://github.com/storybookjs/storybook/pull/31467), thanks @ndelangen!\n- Core: Change require.resolve path for storybook/package.json - [#31230](https://github.com/storybookjs/storybook/pull/31230), thanks @valentinpalkovic!\n- Core: Cleanup dependencies - [#31222](https://github.com/storybookjs/storybook/pull/31222), thanks @JReinhold!\n- Core: Create `features` for addons moved into core - [#31146](https://github.com/storybookjs/storybook/pull/31146), thanks @ndelangen!\n- Core: Do not show 'Render story' step in interactions - [#31452](https://github.com/storybookjs/storybook/pull/31452), thanks @ghengeveld!\n- Core: Draw highlights on top of canvas and add various new features - [#30894](https://github.com/storybookjs/storybook/pull/30894), thanks @ghengeveld!\n- Core: Fix core annotations applied twice - [#31361](https://github.com/storybookjs/storybook/pull/31361), thanks @valentinpalkovic!\n- Core: Fix favicon issue on dev server - [#30818](https://github.com/storybookjs/storybook/pull/30818), thanks @MuhdHishamP!\n- Core: Fix flaky unit tests related to stores - [#30963](https://github.com/storybookjs/storybook/pull/30963), thanks @JReinhold!\n- Core: Fix highlight `clickEvent` serialization and export public types - [#31179](https://github.com/storybookjs/storybook/pull/31179), thanks @ghengeveld!\n- Core: Fix highlight conflicts - [#31204](https://github.com/storybookjs/storybook/pull/31204), thanks @ghengeveld!\n- Core: Fix highlighting zero-pixel elements and focus on single element - [#31183](https://github.com/storybookjs/storybook/pull/31183), thanks @ghengeveld!\n- Core: Fix sidebar accessibility order for screen readers - [#31250](https://github.com/storybookjs/storybook/pull/31250), thanks @yatishgoel!\n- Core: Improve unhandled error detection - [#31440](https://github.com/storybookjs/storybook/pull/31440), thanks @kasperpeulen!\n- Core: Increase compile targets for node & browsers - [#31139](https://github.com/storybookjs/storybook/pull/31139), thanks @JReinhold!\n- Core: Make sure to only mutate writable arrays - [#31578](https://github.com/storybookjs/storybook/pull/31578), thanks @kasperpeulen!\n- Core: Move @storybook/addon-actions into storybook - [#30765](https://github.com/storybookjs/storybook/pull/30765), thanks @valentinpalkovic!\n- Core: Move @storybook/instrumenter into core - [#30740](https://github.com/storybookjs/storybook/pull/30740), thanks @valentinpalkovic!\n- Core: New Status Store - [#30764](https://github.com/storybookjs/storybook/pull/30764), thanks @JReinhold!\n- Core: New Test Provider Store - [#30828](https://github.com/storybookjs/storybook/pull/30828), thanks @JReinhold!\n- Core: Prebundle jsdoc-type-pratt-parser again - [#30923](https://github.com/storybookjs/storybook/pull/30923), thanks @kasperpeulen!\n- Core: Re-Export renderers from frameworks - [#30771](https://github.com/storybookjs/storybook/pull/30771), thanks @ndelangen!\n- Core: Remove `util`, `browser-assert`, `process` deps - [#30805](https://github.com/storybookjs/storybook/pull/30805), thanks @ndelangen!\n- Core: Remove `uuid` package from core - [#31219](https://github.com/storybookjs/storybook/pull/31219), thanks @JReinhold!\n- Core: Remove deprecated parts of test provider API - [#30962](https://github.com/storybookjs/storybook/pull/30962), thanks @JReinhold!\n- Core: Remove duplicate notification dot on sidebar buttons on mobile - [#31485](https://github.com/storybookjs/storybook/pull/31485), thanks @ghengeveld!\n- Core: Remove maximum-scale=1 from viewport meta tag - [#31283](https://github.com/storybookjs/storybook/pull/31283), thanks @yatishgoel!\n- Core: Rename local tests to interactions - [#31141](https://github.com/storybookjs/storybook/pull/31141), thanks @yannbf!\n- Core: Set a minimum height/width for the targetable area of highlights - [#31486](https://github.com/storybookjs/storybook/pull/31486), thanks @ghengeveld!\n- Core: Show \"Render story\" event explicitly in Component Tests event trace - [#31027](https://github.com/storybookjs/storybook/pull/31027), thanks @ghengeveld!\n- Core: Support groups and info icon in highlight popover menu - [#31475](https://github.com/storybookjs/storybook/pull/31475), thanks @ghengeveld!\n- Core: Support React Native environment without static class blocks - [#31282](https://github.com/storybookjs/storybook/pull/31282), thanks @JReinhold!\n- Core: Testing Module UI improvements - [#30773](https://github.com/storybookjs/storybook/pull/30773), thanks @ghengeveld!\n- Core: Wait for animations before completing render cycle - [#31287](https://github.com/storybookjs/storybook/pull/31287), thanks @ghengeveld!\n- CSF-Tools: Add support for existing node imports and improve import handling - [#31497](https://github.com/storybookjs/storybook/pull/31497), thanks @valentinpalkovic!\n- Csf-Tools: Enhance setFieldNode logic to handle variable declarations - [#31056](https://github.com/storybookjs/storybook/pull/31056), thanks @valentinpalkovic!\n- CSF: Fix handling of renamed story exports - [#31519](https://github.com/storybookjs/storybook/pull/31519), thanks @JReinhold!\n- Dependencies: Update dependencies - [#31143](https://github.com/storybookjs/storybook/pull/31143), thanks @valentinpalkovic!\n- Dependencies: Update docgen - [#31465](https://github.com/storybookjs/storybook/pull/31465), thanks @ndelangen!\n- Dependencies: Upgrade @types/estree package to version v1.0.6 - [#29477](https://github.com/storybookjs/storybook/pull/29477), thanks @hakshu25!\n- Dependencies: Upgrade `telejson` - [#30998](https://github.com/storybookjs/storybook/pull/30998), thanks @ndelangen!\n- Dependencies: Upgrades - [#30515](https://github.com/storybookjs/storybook/pull/30515), thanks @ndelangen!\n- Dependencies: Upgrades for security - [#31235](https://github.com/storybookjs/storybook/pull/31235), thanks @ndelangen!\n- Dependencies: Upgrades for security - [#31276](https://github.com/storybookjs/storybook/pull/31276), thanks @ndelangen!\n- Dependencies: Upgrades for security - [#31291](https://github.com/storybookjs/storybook/pull/31291), thanks @ndelangen!\n- Docs: Consolidate blocks into addon-docs - [#31097](https://github.com/storybookjs/storybook/pull/31097), thanks @ndelangen!\n- Docs: Fix source code panel - [#31245](https://github.com/storybookjs/storybook/pull/31245), thanks @valentinpalkovic!\n- Eslint-plugin: Handle JSON5 format - [#31336](https://github.com/storybookjs/storybook/pull/31336), thanks @yatishgoel!\n- ESLint: Fix flat config setup - [#31192](https://github.com/storybookjs/storybook/pull/31192), thanks @yannbf!\n- Essentials: Move remaining addons into core - [#30924](https://github.com/storybookjs/storybook/pull/30924), thanks @ndelangen!\n- Highlights: Dont run highlights when the feature is disabled - [#31239](https://github.com/storybookjs/storybook/pull/31239), thanks @dannyhw!\n- Hooks: Stabilize experimental afterEach hook - [#31438](https://github.com/storybookjs/storybook/pull/31438), thanks @valentinpalkovic!\n- HTML Framework: Remove support for HTML Webpack 5 - [#30990](https://github.com/storybookjs/storybook/pull/30990), thanks @valentinpalkovic!\n- Indexer: Do not create autodocs entries unless addon-docs installed - [#31331](https://github.com/storybookjs/storybook/pull/31331), thanks @ndelangen!\n- Init: Install framework stories instead of renderer stories - [#31160](https://github.com/storybookjs/storybook/pull/31160), thanks @valentinpalkovic!\n- Instrumenter: Fix `preview-api` import for react-native - [#31057](https://github.com/storybookjs/storybook/pull/31057), thanks @ndelangen!\n- Interactions: Rename component test panel - [#31130](https://github.com/storybookjs/storybook/pull/31130), thanks @valentinpalkovic!\n- Maintenance: Drop tooling support - [#30940](https://github.com/storybookjs/storybook/pull/30940), thanks @valentinpalkovic!\n- Maintenance: Merge `@storybook/core` with `storybook` - [#30168](https://github.com/storybookjs/storybook/pull/30168), thanks @ndelangen!\n- Maintenance: Migrate eslint-storybook-plugin into the monorepo - [#31151](https://github.com/storybookjs/storybook/pull/31151), thanks @yannbf!\n- Maintenance: Remove aliasses in builder configurations & scripts - [#31344](https://github.com/storybookjs/storybook/pull/31344), thanks @ndelangen!\n- Maintenance: Remove deprecated APIs - [#30926](https://github.com/storybookjs/storybook/pull/30926), thanks @valentinpalkovic!\n- Maintenance: Remove deprecated packages - [#30690](https://github.com/storybookjs/storybook/pull/30690), thanks @ndelangen!\n- Maintenance: Remove obsolete automigrations - [#30945](https://github.com/storybookjs/storybook/pull/30945), thanks @valentinpalkovic!\n- Maintenance: Specify that Addon Test now requires Vitest 3.0 - [#30948](https://github.com/storybookjs/storybook/pull/30948), thanks @yannbf!\n- Manager: Add reactivity to useParameter - [#31579](https://github.com/storybookjs/storybook/pull/31579), thanks @valentinpalkovic!\n- Manager: Fix `Uncaught ReferenceError: global is not defined` - [#30970](https://github.com/storybookjs/storybook/pull/30970), thanks @JReinhold!\n- Migration: Add auto-automigration for merged packages - [#30753](https://github.com/storybookjs/storybook/pull/30753), thanks @ndelangen!\n- Migration: Improve glob question text - [#31118](https://github.com/storybookjs/storybook/pull/31118), thanks @ndelangen!\n- Next.js-Vite: Stabilize @storybook/experimental-nextjs-vite - [#30956](https://github.com/storybookjs/storybook/pull/30956), thanks @valentinpalkovic!\n- Next.js: Remove deprecated compatibility files - [#31295](https://github.com/storybookjs/storybook/pull/31295), thanks @valentinpalkovic!\n- Next.js: Upgrade image-size to 2.0 - [#30741](https://github.com/storybookjs/storybook/pull/30741), thanks @valentinpalkovic!\n- Nextjs Vite: Add runtime check for malformed postcss config - [#31184](https://github.com/storybookjs/storybook/pull/31184), thanks @valentinpalkovic!\n- Nextjs-Vite: Update vite-plugin-storybook-nextjs version and add optimizeDeps - [#31037](https://github.com/storybookjs/storybook/pull/31037), thanks @valentinpalkovic!\n- Node.js: Align Node.js version support - [#31041](https://github.com/storybookjs/storybook/pull/31041), thanks @valentinpalkovic!\n- Preact: Remove support for Preact Webpack 5 - [#30957](https://github.com/storybookjs/storybook/pull/30957), thanks @valentinpalkovic!\n- Presets: Use `.js` files when `.cjs` files are passed for entries that should be ESM - [#31556](https://github.com/storybookjs/storybook/pull/31556), thanks @JReinhold!\n- Pseudo States: Ignore escaped pseudo-class names - [#31515](https://github.com/storybookjs/storybook/pull/31515), thanks @sentience!\n- React Native Web: Add RNW to vitest supported frameworks - [#31253](https://github.com/storybookjs/storybook/pull/31253), thanks @dannyhw!\n- React Native: Fix support for 9.0 - [#31518](https://github.com/storybookjs/storybook/pull/31518), thanks @JReinhold!\n- React-Native: Fix `__STORYBOOK_ADDON_INTERACTIONS_INSTRUMENTER_STATE__` access - [#30820](https://github.com/storybookjs/storybook/pull/30820), thanks @dannyhw!\n- React-Native: Fix `userEvent.setup()` errors in jest - [#30833](https://github.com/storybookjs/storybook/pull/30833), thanks @dannyhw!\n- React-Native: Fix `userEvent.setup()` errors outside browser context - [#30831](https://github.com/storybookjs/storybook/pull/30831), thanks @dannyhw!\n- React-Native: Update config directory to .rnstorybook - [#30819](https://github.com/storybookjs/storybook/pull/30819), thanks @dannyhw!\n- React: Don't use Act wrapper in Storybook when rendering in docs - [#31483](https://github.com/storybookjs/storybook/pull/31483), thanks @kasperpeulen!\n- React: Ensure render functions and decorators are react components - [#30869](https://github.com/storybookjs/storybook/pull/30869), thanks @kasperpeulen!\n- React: Export returntype of ReactMeta#story - [#30580](https://github.com/storybookjs/storybook/pull/30580), thanks @mrginglymus!\n- React: Remove react import in template files - [#30757](https://github.com/storybookjs/storybook/pull/30757), thanks @kasperpeulen!\n- Refactor: Update panel IDs in vitest addon to use new constants - [#31132](https://github.com/storybookjs/storybook/pull/31132), thanks @ndelangen!\n- Remove: Addon mdx-gfm (`@storybook/addon-mdx-gfm`) - [#30996](https://github.com/storybookjs/storybook/pull/30996), thanks @ndelangen!\n- Revert \"Svelte: Adjust Svelte typings to include Svelte 5 function components\" - [#30851](https://github.com/storybookjs/storybook/pull/30851), thanks @kasperpeulen!\n- Save from Controls: Replace rendererPackage with frameworkPackage - [#31114](https://github.com/storybookjs/storybook/pull/31114), thanks @valentinpalkovic!\n- Source Loader: Remove package - [#31466](https://github.com/storybookjs/storybook/pull/31466), thanks @valentinpalkovic!\n- Source: Support async parameters.docs.source.transform - [#30426](https://github.com/storybookjs/storybook/pull/30426), thanks @valentinpalkovic!\n- Svelte-vite: Improve SvelteKit detection error - [#31038](https://github.com/storybookjs/storybook/pull/31038), thanks @JReinhold!\n- Svelte: Adjust Svelte typings to include Svelte 5 function components - [#30812](https://github.com/storybookjs/storybook/pull/30812), thanks @dummdidumm!\n- Svelte: Drop Support for Svelte < 5 - [#30703](https://github.com/storybookjs/storybook/pull/30703), thanks @valentinpalkovic!\n- Svelte: Fix missing `ts-dedent` dependency - [#31289](https://github.com/storybookjs/storybook/pull/31289), thanks @JReinhold!\n- Svelte: Install `latest` version of `@storybook/addon-svelte-csf` - [#31398](https://github.com/storybookjs/storybook/pull/31398), thanks @JReinhold!\n- Svelte: Pin svelte2tsx to solve argType regression - [#30783](https://github.com/storybookjs/storybook/pull/30783), thanks @kasperpeulen!\n- Svelte: Remove dependency on `sveltedoc-parser` - [#31246](https://github.com/storybookjs/storybook/pull/31246), thanks @JReinhold!\n- Svelte: Remove unused `svelte-preprocess` dependency - [#31332](https://github.com/storybookjs/storybook/pull/31332), thanks @JReinhold!\n- SvelteKit: Forward form events when mocking `enhance` - [#31360](https://github.com/storybookjs/storybook/pull/31360), thanks @JReinhold!\n- Telemetry: Add Svelte CSF usage - [#31255](https://github.com/storybookjs/storybook/pull/31255), thanks @shilman!\n- Telemetry: Use version from our package.json for `storybookVersion` - [#31577](https://github.com/storybookjs/storybook/pull/31577), thanks @tmeasday!\n- Test Addon: Stabilize and remove experimental status - [#30727](https://github.com/storybookjs/storybook/pull/30727), thanks @valentinpalkovic!\n- Test: Allow generics in expect matchers - [#31395](https://github.com/storybookjs/storybook/pull/31395), thanks @yannbf!\n- Test: Handle non-configurable properties in instrumenter for expect.toThrow - [#30876](https://github.com/storybookjs/storybook/pull/30876), thanks @kasperpeulen!\n- Test: Make sure that expect has no different behavior after instrumentation - [#30935](https://github.com/storybookjs/storybook/pull/30935), thanks @kasperpeulen!\n- Test: Move `@storybook/test` into `storybook/test` - [#30742](https://github.com/storybookjs/storybook/pull/30742), thanks @valentinpalkovic!\n- Test: Patch HTMLElement.prototype.focus method for settable focus in tests - [#31487](https://github.com/storybookjs/storybook/pull/31487), thanks @valentinpalkovic!\n- Test: Remove legacy Vitest v2 code - [#31271](https://github.com/storybookjs/storybook/pull/31271), thanks @valentinpalkovic!\n- Test: Upgrade to vitest 3 - [#30840](https://github.com/storybookjs/storybook/pull/30840), thanks @kasperpeulen!\n- Test: Use @testing-library/dom as devDependency - [#31188](https://github.com/storybookjs/storybook/pull/31188), thanks @valentinpalkovic!\n- Toolbars: Embed addon-toolbars into the core - [#30871](https://github.com/storybookjs/storybook/pull/30871), thanks @ndelangen!\n- Typescript: Drop Typescript < 4.9 support - [#30736](https://github.com/storybookjs/storybook/pull/30736), thanks @valentinpalkovic!\n- UI: Add options to hide sidebar and toolbar per story - [#29516](https://github.com/storybookjs/storybook/pull/29516), thanks @Sidnioulz!\n- UI: Clear filters on run all and clear all statuses - [#31073](https://github.com/storybookjs/storybook/pull/31073), thanks @JReinhold!\n- UI: Don't include error state in sidebar context menu - [#31054](https://github.com/storybookjs/storybook/pull/31054), thanks @ghengeveld!\n- UI: Fix status missing from sidebar - [#30830](https://github.com/storybookjs/storybook/pull/30830), thanks @JReinhold!\n- UI: Visual tweaks to badges and improved layout for a11y panel - [#30955](https://github.com/storybookjs/storybook/pull/30955), thanks @ghengeveld!\n- Update react-router-dom to lowest React19 type-compatible version - [#31358](https://github.com/storybookjs/storybook/pull/31358), thanks @mrginglymus!\n- Viewport: Embed addon-viewport in the core - [#30909](https://github.com/storybookjs/storybook/pull/30909), thanks @ndelangen!\n- Viewport: Fix globals type - [#31374](https://github.com/storybookjs/storybook/pull/31374), thanks @flaval!\n- Vite-Builder: Handle undefined previewConfig - [#31216](https://github.com/storybookjs/storybook/pull/31216), thanks @valentinpalkovic!\n- Vite: Add 'storybook/viewport' to INCLUDE_CANDIDATES in optimizeDeps.ts - [#31039](https://github.com/storybookjs/storybook/pull/31039), thanks @valentinpalkovic!\n- Vite: Improve handling of preview annotations - [#28798](https://github.com/storybookjs/storybook/pull/28798), thanks @tobiasdiez!\n- Vite: Normalize preview annotation paths - [#31238](https://github.com/storybookjs/storybook/pull/31238), thanks @mrginglymus!\n- Vite: Support Vite 6 and Docs - [#31061](https://github.com/storybookjs/storybook/pull/31061), thanks @valentinpalkovic!\n- Vitest: Remove beforeAll in vitest.setup.ts in automigration - [#31460](https://github.com/storybookjs/storybook/pull/31460), thanks @kasperpeulen!\n- Vue3: Remove support for Webpack 5 - [#30958](https://github.com/storybookjs/storybook/pull/30958), thanks @valentinpalkovic!\n- Web Components: Remove Webpack 5 support - [#30988](https://github.com/storybookjs/storybook/pull/30988), thanks @valentinpalkovic!\n- Yarn: Update Yarn package command execution to use 'exec' - [#31065](https://github.com/storybookjs/storybook/pull/31065), thanks @valentinpalkovic!\n\nTotal contributions: 240\nUnique contributors: 29\n\n</details>\n\n## 8.6.14\n\n- CLI: Add skip onboarding, recommended/minimal config - [#30930](https://github.com/storybookjs/storybook/pull/30930), thanks @shilman!\n- Core: Fix using dates in expect statements - [#28413](https://github.com/storybookjs/storybook/pull/28413), thanks @yann-combarnous!\n- React Native Web: Fix expo router by setting JSX to automatic - [#31484](https://github.com/storybookjs/storybook/pull/31484), thanks @dannyhw!\n- Test: Make sure that lit arrays are not cloned - [#31435](https://github.com/storybookjs/storybook/pull/31435), thanks @kasperpeulen!\n\n## 8.6.13\n\n- Controls: Fix boxShadow on empty controls - [#27193](https://github.com/storybookjs/storybook/pull/27193), thanks @H0onnn!\n- React Native Web: Update `react-native-web` - [#31324](https://github.com/storybookjs/storybook/pull/31324), thanks @ndelangen!\n\n## 8.6.12\n\n- CLI: Only install Visual Test Addon if test feature is selected - [#30966](https://github.com/storybookjs/storybook/pull/30966), thanks @ghengeveld!\n- Core: Fix telemetry error on Storybook UI - [#30953](https://github.com/storybookjs/storybook/pull/30953), thanks @yannbf!\n- Ember: Fix `ember-template-compiler` import for ember 6+ - [#30682](https://github.com/storybookjs/storybook/pull/30682), thanks @leoeuclids!\n- Next: Update vite-plugin-storybook-nextjs to 2.0.0--canary.33.17a2310.0 - [#30997](https://github.com/storybookjs/storybook/pull/30997), thanks @kasperpeulen!\n- Svelte: Exclude `node_modules` from docgen - [#30981](https://github.com/storybookjs/storybook/pull/30981), thanks @JReinhold!\n\n## 8.6.11\n\n- Angular: Fix zone.js support for Angular libraries - [#30941](https://github.com/storybookjs/storybook/pull/30941), thanks @valentinpalkovic!\n\n## 8.6.10\n\n- Addon-docs: Fix non-string handling in Stories block - [#30913](https://github.com/storybookjs/storybook/pull/30913), thanks @JamesIves!\n- Nextjs: Fix styled-jsx optimize vite warnings - [#30932](https://github.com/storybookjs/storybook/pull/30932), thanks @kasperpeulen!\n- React: Fix actImplementation is not a function - [#30929](https://github.com/storybookjs/storybook/pull/30929), thanks @kasperpeulen!\n\n## 8.6.9\n\n- Next: Fix react aliases in next vite plugin - [#30914](https://github.com/storybookjs/storybook/pull/30914), thanks @kasperpeulen!\n\n## 8.6.8\n\n- Angular: Export all files in Angular package.json - [#30849](https://github.com/storybookjs/storybook/pull/30849), thanks @kasperpeulen!\n- CLI: Don't add packageManager entry to package.json automatically - [#30855](https://github.com/storybookjs/storybook/pull/30855), thanks @kasperpeulen!\n- React: Allow portable stories to be used in SSR - [#30847](https://github.com/storybookjs/storybook/pull/30847), thanks @kasperpeulen!\n- Svelte: Adjust Svelte typings to include Svelte 5 function components - [#30852](https://github.com/storybookjs/storybook/pull/30852), thanks @dummdidumm!\n- Telemetry: Make sure that telemetry doesn't fail on init - [#30857](https://github.com/storybookjs/storybook/pull/30857), thanks @kasperpeulen!\n- Vite: Update HMR filter to target specific story file types - [#30845](https://github.com/storybookjs/storybook/pull/30845), thanks @kasperpeulen!\n\n## 8.6.7\n\n- React-Native-Web: Fix errors in CLI template stories - [#30821](https://github.com/storybookjs/storybook/pull/30821), thanks @dannyhw!\n\n## 8.6.6\n\n- Angular: Make sure that polyfills are loaded before the storybook is loaded - [#30811](https://github.com/storybookjs/storybook/pull/30811), thanks @kasperpeulen!\n- CSF: Fix CSF subcomponent type - [#30729](https://github.com/storybookjs/storybook/pull/30729), thanks @filipemelo2002!\n\n## 8.6.5\n\n- Addon A11y: Promote @storybook/global to full dependency - [#30723](https://github.com/storybookjs/storybook/pull/30723), thanks @mrginglymus!\n- Angular: Add `@angular-devkit/build-angular` to installed packages - [#30790](https://github.com/storybookjs/storybook/pull/30790), thanks @kasperpeulen!\n- CLI: Fix test install in RNW projects - [#30786](https://github.com/storybookjs/storybook/pull/30786), thanks @shilman!\n- Core: Replace 'min' instead of 'm' in printDuration - [#30668](https://github.com/storybookjs/storybook/pull/30668), thanks @wlewis-formative!\n- Next.js: Use latest version when init in empty directory - [#30659](https://github.com/storybookjs/storybook/pull/30659), thanks @valentinpalkovic!\n- Svelte: Fix Vite crashing on virtual module imports - [#26838](https://github.com/storybookjs/storybook/pull/26838), thanks @rChaoz!\n- Svelte: Fix automatic argTypes inference coming up empty with `svelte2tsx@0.7.35` - [#30784](https://github.com/storybookjs/storybook/pull/30784), thanks @JReinhold!\n- Universal Store: Don't use `crypto.randomUUID` - [#30781](https://github.com/storybookjs/storybook/pull/30781), thanks @JReinhold!\n\n## 8.6.4\n\n- Manager: Add Content-Type to fix Cloud IDEs - [#30606](https://github.com/storybookjs/storybook/pull/30606), thanks @GCHQDeveloper548!\n- Vite: Include `node_modules` in stats file - [#30711](https://github.com/storybookjs/storybook/pull/30711), thanks @JReinhold!\n\n## 8.6.3\n\n- CSF Factories: Align addon-essentials import with other addons - [#30716](https://github.com/storybookjs/storybook/pull/30716), thanks @kasperpeulen!\n- Next: Support Next 15.2 - [#30702](https://github.com/storybookjs/storybook/pull/30702), thanks @kasperpeulen!\n\n## 8.6.2\n\n- Core: Support TS3.8+ again - [#30700](https://github.com/storybookjs/storybook/pull/30700), thanks @kasperpeulen!\n- Revert \"CLI: Don't initially select Documentation and Testing features\" - [#30694](https://github.com/storybookjs/storybook/pull/30694), thanks @shilman!\n\n## 8.6.1\n\n- CSF: Only export definePreview from the framework - [#30676](https://github.com/storybookjs/storybook/pull/30676), thanks @kasperpeulen!\n- Codemod: Only remove types when they are unused - [#30644](https://github.com/storybookjs/storybook/pull/30644), thanks @yannbf!\n\n## 8.6.0\n\nThe 8.6 release focuses on [Storybook Test](https://storybook.js.org/blog/storybook-test-sneak-peek/), which brings realtime component, accessibility, and visual UI tests to your favorite component workshop.\n\nHere’s what’s new:\n\n- 🎁 **Storybook Test installer** for out-of-the-box tests in new projects\n- 🦾 **Accessibility “todo” workflow** to systematically fix a11y violations\n- 🗜️ **80% smaller create-storybook** package for much faster installs\n- 🧪 **Dozens of Test fixes** based on user feedback\n- 📕 **Docs fixes** for table of contents, code snippets, and more\n- 🚨 **Key security fixes** for Vite and ESbuild\n- 💯 Hundreds more improvements\n\n<details>\n<summary>List of all updates</summary>\n\n- Addon A11y: Introduce parameters.a11y.test - [#30516](https://github.com/storybookjs/storybook/pull/30516), thanks @valentinpalkovic!\n- Addon-A11y: Fix preset loading when loaded via getAbsolutePath - [#30563](https://github.com/storybookjs/storybook/pull/30563), thanks @valentinpalkovic!\n- Addon-Docs: Change URL hash when TOC item is clicked, and fix TOC loading bugs - [#30130](https://github.com/storybookjs/storybook/pull/30130), thanks @Sidnioulz!\n- Addon-docs: Consider custom code snippet in story code panel and update styles - [#30179](https://github.com/storybookjs/storybook/pull/30179), thanks @larsrickert!\n- Addon-Test: Add telemetry data for Focused Tests - [#30568](https://github.com/storybookjs/storybook/pull/30568), thanks @JReinhold!\n- Addon-Test: Fix config and watch mode inconsistencies - [#30491](https://github.com/storybookjs/storybook/pull/30491), thanks @JReinhold!\n- Addon-Test: Fix console error in build mode - [#30625](https://github.com/storybookjs/storybook/pull/30625), thanks @JReinhold!\n- Addon-Test: Make sure that only one global portable story config is ever loaded - [#30582](https://github.com/storybookjs/storybook/pull/30582), thanks @kasperpeulen!\n- Angular: Fix accent character issue - [#30276](https://github.com/storybookjs/storybook/pull/30276), thanks @valentinpalkovic!\n- Angular: Support experimental zoneless mode - [#28657](https://github.com/storybookjs/storybook/pull/28657), thanks @anedomansky!\n- Angular: Support v19.2 when @angular/animations is not installed - [#30611](https://github.com/storybookjs/storybook/pull/30611), thanks @valentinpalkovic!\n- Builder-Vite: Fix resolve id warning - [#30511](https://github.com/storybookjs/storybook/pull/30511), thanks @valentinpalkovic!\n- Builder-Vite: Fix runtime and iframe 404 on first load - [#30567](https://github.com/storybookjs/storybook/pull/30567), thanks @valentinpalkovic!\n- Bun: Add support for text lock file - [#30160](https://github.com/storybookjs/storybook/pull/30160), thanks @Arctomachine!\n- Cleanup: Remove unused constants in viewport addon - [#30479](https://github.com/storybookjs/storybook/pull/30479), thanks @Guria!\n- CLI: Don't initially select Documentation and Testing features - [#30599](https://github.com/storybookjs/storybook/pull/30599), thanks @ghengeveld!\n- CLI: Fix peer dep issues for npm users during upgrade - [#30616](https://github.com/storybookjs/storybook/pull/30616), thanks @valentinpalkovic!\n- CLI: Fix printing of selected features - [#30605](https://github.com/storybookjs/storybook/pull/30605), thanks @ghengeveld!\n- CLI: Make telemetry data an object - [#30581](https://github.com/storybookjs/storybook/pull/30581), thanks @ndelangen!\n- CLI: Prompt users for RN vs RNW on init - [#30635](https://github.com/storybookjs/storybook/pull/30635), thanks @shilman!\n- CLI: Reimplement features prompt logic to handle `--yes` and fix `--features` - [#30534](https://github.com/storybookjs/storybook/pull/30534), thanks @ghengeveld!\n- CLI: Remove Storybook dependencies before adding re-adding them - [#30600](https://github.com/storybookjs/storybook/pull/30600), thanks @valentinpalkovic!\n- CLI: Use correct storybook internals import in automigration - [#30290](https://github.com/storybookjs/storybook/pull/30290), thanks @yannbf!\n- Codemod: Always get real path of files - [#30650](https://github.com/storybookjs/storybook/pull/30650), thanks @yannbf!\n- Codemod: Handle addon essentials differently in csf factories - [#30649](https://github.com/storybookjs/storybook/pull/30649), thanks @yannbf!\n- Codemod: Migrate meta.args to meta.input.args in csf factories - [#30641](https://github.com/storybookjs/storybook/pull/30641), thanks @yannbf!\n- Codemod: Use real path from symbolic links - [#30642](https://github.com/storybookjs/storybook/pull/30642), thanks @yannbf!\n- Core: Add `UniversalStore` API to sync state/events between multiple environments - [#30445](https://github.com/storybookjs/storybook/pull/30445), thanks @JReinhold!\n- Core: Add connection timeout notification - [#30288](https://github.com/storybookjs/storybook/pull/30288), thanks @valentinpalkovic!\n- Core: Allow empty render functions in CSF factories - [#30565](https://github.com/storybookjs/storybook/pull/30565), thanks @kasperpeulen!\n- Core: Always place cache dir inside `node_modules` - [#30643](https://github.com/storybookjs/storybook/pull/30643), thanks @ndelangen!\n- Core: Don't set process.env.NODE_ENV and process.env.DEV - [#30651](https://github.com/storybookjs/storybook/pull/30651), thanks @valentinpalkovic!\n- Core: Fix addon essentials preview preset - [#30647](https://github.com/storybookjs/storybook/pull/30647), thanks @yannbf!\n- Core: Fix extracting import path when it's not a core addon - [#30640](https://github.com/storybookjs/storybook/pull/30640), thanks @yannbf!\n- Core: Fix invalid Websocket termination - [#30408](https://github.com/storybookjs/storybook/pull/30408), thanks @valentinpalkovic!\n- Core: Fix statically serving single files and multiple dirs on the same endpoint - [#30467](https://github.com/storybookjs/storybook/pull/30467), thanks @JReinhold!\n- Core: Fix undeclared internal dependencies - [#30566](https://github.com/storybookjs/storybook/pull/30566), thanks @kasperpeulen!\n- Core: Improve type compatibility with React 19 - [#30031](https://github.com/storybookjs/storybook/pull/30031), thanks @mrginglymus!\n- Core: Move CSF to monorepo - [#30488](https://github.com/storybookjs/storybook/pull/30488), thanks @kasperpeulen!\n- Csf Tools: Allow ConfigFile to create more import syntaxes - [#30204](https://github.com/storybookjs/storybook/pull/30204), thanks @yannbf!\n- CSF: Add support for CSF factories - [#30197](https://github.com/storybookjs/storybook/pull/30197), thanks @kasperpeulen!\n- Essentials: Fix `addon-essentials` not working when used with `getAbsolutePath` - [#30557](https://github.com/storybookjs/storybook/pull/30557), thanks @JReinhold!\n- Manager: Escape single quotes in dynamic import paths in wrapManagerEntries function - [#30278](https://github.com/storybookjs/storybook/pull/30278), thanks @valentinpalkovic!\n- Manager: Fix escaping of single quotes in dynamic import paths - [#30278](https://github.com/storybookjs/storybook/pull/30278), thanks @valentinpalkovic!\n- Manager: Fix panel reactivity - [#30638](https://github.com/storybookjs/storybook/pull/30638), thanks @valentinpalkovic!\n- React: Fix incorrect import in preview.ts - [#30542](https://github.com/storybookjs/storybook/pull/30542), thanks @mrginglymus!\n- Svelte: Fix conflicting variable names and support for `+page.svelte` files - [#30369](https://github.com/storybookjs/storybook/pull/30369), thanks @xeho91!\n- Test addon: Only update `vitest.config.ts` with workspaces, otherwise create `vitest.workspace.ts` - [#30583](https://github.com/storybookjs/storybook/pull/30583), thanks @ghengeveld!\n</details>\n\n## 8.5.8\n\n- Core: Support `esbuild@^0.25` - [#30574](https://github.com/storybookjs/storybook/pull/30574), thanks @JReinhold!\n\n## 8.5.7\n\n- Tags: Add story/meta usage telemetry - [#30555](https://github.com/storybookjs/storybook/pull/30555), thanks @shilman!\n- Telemetry: Don't count example stories towards CSF feature stats - [#30561](https://github.com/storybookjs/storybook/pull/30561), thanks @shilman!\n- Vite: Fix not stripping all HMR boundaries - [#30562](https://github.com/storybookjs/storybook/pull/30562), thanks @JReinhold!\n\n## 8.5.6\n\n- Builder-Vite: Fix defaulting to allowing all hosts - [#30523](https://github.com/storybookjs/storybook/pull/30523), thanks @JReinhold!\n- UI: Fix tags sort for browser back-compat - [#30547](https://github.com/storybookjs/storybook/pull/30547), thanks @shilman!\n\n## 8.5.5\n\n- Builder-Vite: Fix Turbosnap - [#30522](https://github.com/storybookjs/storybook/pull/30522), thanks @valentinpalkovic!\n\n## 8.5.4\n\n- Addon A11y: Make Vitest Axe optional - [#30442](https://github.com/storybookjs/storybook/pull/30442), thanks @valentinpalkovic!\n- Builder-Vite: Fix allowedHosts handling for custom hosts - [#30432](https://github.com/storybookjs/storybook/pull/30432), thanks @JSMike!\n- Builder-Vite: Fix resolve id warning - [#30511](https://github.com/storybookjs/storybook/pull/30511), thanks @valentinpalkovic!\n- React: Update react-docgen-typescript to fix CI hanging issues - [#30422](https://github.com/storybookjs/storybook/pull/30422), thanks @yannbf!\n\n## 8.5.3\n\n- Preview: Add `globals` to `extract()` - [#30415](https://github.com/storybookjs/storybook/pull/30415), thanks @ndelangen!\n- Vite: Fix add component UI invalidation - [#30438](https://github.com/storybookjs/storybook/pull/30438), thanks @shilman!\n\n## 8.5.2\n\n- Addon Test: Support Vitest 3 browser.test.instances field - [#30309](https://github.com/storybookjs/storybook/pull/30309), thanks @valentinpalkovic!\n- CLI: Corrected Next.js createScript for pnpm. - [#30304](https://github.com/storybookjs/storybook/pull/30304), thanks @zhyd1997!\n\n## 8.5.1\n\n- Addon Test: Replace `interaction test` -> `component test` - [#30333](https://github.com/storybookjs/storybook/pull/30333), thanks @kylegach!\n- Addon Test: Support Vitest 3 browser.test.instances field - [#30309](https://github.com/storybookjs/storybook/pull/30309), thanks @valentinpalkovic!\n- Manager: Fix escaping of single quotes in dynamic import paths - [#30278](https://github.com/storybookjs/storybook/pull/30278), thanks @valentinpalkovic!\n- RNW-Vite: Support requires for images/fonts - [#30305](https://github.com/storybookjs/storybook/pull/30305), thanks @dannyhw!\n\n## 8.5.0\n\nStorybook 8.5 is packed with powerful features to enhance your development workflow. This release makes it easier than ever to build accessible, well-tested UIs. Here’s what’s new:\n\n- 🦾 Realtime accessibility tests to help build UIs for everybody\n- 🛡️ Project code coverage to measure the completeness of your tests\n- 🎯 Focused tests for faster test feedback\n- ⚛️ React Native Web Vite framework (experimental) for testing mobile UI⚛️\n- 🎁 Storybook test early access program to level up your testing game\n- 💯 Hundreds more improvements\n\n<details>\n<summary>List of all updates</summary>\n\n- Addon A11y: Add conditional rendering for a11y violation number in Testing Module - [#30073](https://github.com/storybookjs/storybook/pull/30073), thanks @valentinpalkovic!\n- Addon A11y: Add typesVersions support for TypeScript definitions in a11y package - [#30005](https://github.com/storybookjs/storybook/pull/30005), thanks @valentinpalkovic!\n- Addon A11y: Adjust default behaviour when using with experimental-addon-test - [#30162](https://github.com/storybookjs/storybook/pull/30162), thanks @valentinpalkovic!\n- Addon A11y: Change default element selector - [#30253](https://github.com/storybookjs/storybook/pull/30253), thanks @valentinpalkovic!\n- Addon A11y: Create a11y test provider and revamp a11y addon - [#29643](https://github.com/storybookjs/storybook/pull/29643), thanks @valentinpalkovic!\n- Addon A11y: Don't set a11y tag as comment in automigrations - [#30257](https://github.com/storybookjs/storybook/pull/30257), thanks @valentinpalkovic!\n- Addon A11y: Fix skipped status handling in Testing Module - [#30077](https://github.com/storybookjs/storybook/pull/30077), thanks @valentinpalkovic!\n- Addon A11y: Refactor environment variable handling for Vitest integration - [#30022](https://github.com/storybookjs/storybook/pull/30022), thanks @valentinpalkovic!\n- Addon A11y: Remove warnings API - [#30049](https://github.com/storybookjs/storybook/pull/30049), thanks @kasperpeulen!\n- Addon A11y: Run the a11y automigration on postInstall - [#30004](https://github.com/storybookjs/storybook/pull/30004), thanks @kasperpeulen!\n- Addon A11y: Show errors of axe properly - [#30050](https://github.com/storybookjs/storybook/pull/30050), thanks @kasperpeulen!\n- Addon A11y: Update accessibility status handling in TestProviderRender - [#30027](https://github.com/storybookjs/storybook/pull/30027), thanks @valentinpalkovic!\n- Addon Docs: Dynamically import rehype - [#29544](https://github.com/storybookjs/storybook/pull/29544), thanks @valentinpalkovic!\n- Addon Docs: Make new code panel opt in - [#30248](https://github.com/storybookjs/storybook/pull/30248), thanks @shilman!\n- Addon Onboarding: Prebundle react-confetti - [#29996](https://github.com/storybookjs/storybook/pull/29996), thanks @yannbf!\n- Addon Test: Add `@vitest/coverage-v8` during postinstall if no coverage reporter is installed - [#29993](https://github.com/storybookjs/storybook/pull/29993), thanks @ghengeveld!\n- Addon Test: Add prerequisite check for MSW - [#30193](https://github.com/storybookjs/storybook/pull/30193), thanks @yannbf!\n- Addon Test: Add support for previewHead - [#29808](https://github.com/storybookjs/storybook/pull/29808), thanks @ndelangen!\n- Addon Test: Add Vitest 3 support - [#30181](https://github.com/storybookjs/storybook/pull/30181), thanks @valentinpalkovic!\n- Addon Test: Always run Vitest in watch mode internally - [#29749](https://github.com/storybookjs/storybook/pull/29749), thanks @JReinhold!\n- Addon Test: Always use installed version of vitest - [#30134](https://github.com/storybookjs/storybook/pull/30134), thanks @kasperpeulen!\n- Addon Test: Clarify message when `vitest` detects missing deps - [#29763](https://github.com/storybookjs/storybook/pull/29763), thanks @ndelangen!\n- Addon Test: Clear coverage data when starting or watching - [#30072](https://github.com/storybookjs/storybook/pull/30072), thanks @ghengeveld!\n- Addon Test: Context menu UI - [#29727](https://github.com/storybookjs/storybook/pull/29727), thanks @ghengeveld!\n- Addon Test: Context menu updates - [#30107](https://github.com/storybookjs/storybook/pull/30107), thanks @ghengeveld!\n- Addon Test: Correctly stop Storybook when Vitest closes - [#30012](https://github.com/storybookjs/storybook/pull/30012), thanks @JReinhold!\n- Addon Test: Filter out falsy test results in TestProviderRender - [#30001](https://github.com/storybookjs/storybook/pull/30001), thanks @valentinpalkovic!\n- Addon Test: Fix documentation links - [#30128](https://github.com/storybookjs/storybook/pull/30128), thanks @yannbf!\n- Addon Test: Fix duplicate `test.include` patterns - [#30029](https://github.com/storybookjs/storybook/pull/30029), thanks @JReinhold!\n- Addon Test: Fix environment variable for Vitest Storybook integration - [#30054](https://github.com/storybookjs/storybook/pull/30054), thanks @valentinpalkovic!\n- Addon Test: Fix error reporting for `vitest` crashes - [#29751](https://github.com/storybookjs/storybook/pull/29751), thanks @ndelangen!\n- Addon Test: Fix generated path to `vitest.setup.js` - [#30233](https://github.com/storybookjs/storybook/pull/30233), thanks @JReinhold!\n- Addon Test: Fix indexing behavior - [#29836](https://github.com/storybookjs/storybook/pull/29836), thanks @yannbf!\n- Addon Test: Fix printing null% for coverage - [#30061](https://github.com/storybookjs/storybook/pull/30061), thanks @ghengeveld!\n- Addon Test: Fix run request while booting or restarting Vitest - [#29829](https://github.com/storybookjs/storybook/pull/29829), thanks @ghengeveld!\n- Addon Test: Handle undefined storyId - [#29998](https://github.com/storybookjs/storybook/pull/29998), thanks @ghengeveld!\n- Addon Test: Improve error message on missing coverage package - [#30088](https://github.com/storybookjs/storybook/pull/30088), thanks @JReinhold!\n- Addon Test: Improve support for mono-repos - [#30216](https://github.com/storybookjs/storybook/pull/30216), thanks @valentinpalkovic!\n- Addon Test: Make component tests status row link to the story\\'s tests panel - [#29992](https://github.com/storybookjs/storybook/pull/29992), thanks @ghengeveld!\n- Addon Test: Merge viteFinal config into vitest config - [#29806](https://github.com/storybookjs/storybook/pull/29806), thanks @ndelangen!\n- Addon Test: Only optimize react deps if applicable in vitest-plugin - [#29617](https://github.com/storybookjs/storybook/pull/29617), thanks @yannbf!\n- Addon Test: Only reset story count on file change when watch mode is enabled - [#30121](https://github.com/storybookjs/storybook/pull/30121), thanks @ghengeveld!\n- Addon Test: Optimize internal dependencies - [#29595](https://github.com/storybookjs/storybook/pull/29595), thanks @yannbf!\n- Addon Test: Prompt switch to `experimental-nextjs-vite` - [#29814](https://github.com/storybookjs/storybook/pull/29814), thanks @ndelangen!\n- Addon Test: Refactor test addon to include stories automatically - [#29367](https://github.com/storybookjs/storybook/pull/29367), thanks @yannbf!\n- Addon Test: Remove a11y placeholder - [#29769](https://github.com/storybookjs/storybook/pull/29769), thanks @JReinhold!\n- Addon Test: Replace `glob` with `tinyglobby` - [#29817](https://github.com/storybookjs/storybook/pull/29817), thanks @ghengeveld!\n- Addon Test: Serve `staticDirs` with Vitest - [#29811](https://github.com/storybookjs/storybook/pull/29811), thanks @ghengeveld!\n- Addon Test: Show sub test provider toggle state in main testing module - [#30019](https://github.com/storybookjs/storybook/pull/30019), thanks @ghengeveld!\n- Addon Test: Support Storybook environment variables in Vitest - [#29792](https://github.com/storybookjs/storybook/pull/29792), thanks @ghengeveld!\n- Addon Test: Use correct vitest config file path - [#30135](https://github.com/storybookjs/storybook/pull/30135), thanks @kasperpeulen!\n- Addon Test: Use local storybook binary instead - [#30021](https://github.com/storybookjs/storybook/pull/30021), thanks @kasperpeulen!\n- Addon Test: Use ProgressSpinner for stop button in Testing Module - [#29997](https://github.com/storybookjs/storybook/pull/29997), thanks @ghengeveld!\n- Addon Test: Wait for 2 seconds before showing result mismatch warning - [#30002](https://github.com/storybookjs/storybook/pull/30002), thanks @ghengeveld!\n- Addon Test: Wrap sub-paths exported with `require.resolve` - [#30026](https://github.com/storybookjs/storybook/pull/30026), thanks @ndelangen!\n- Addon Themes: Deprecate useThemeParameters - [#30111](https://github.com/storybookjs/storybook/pull/30111), thanks @yannbf!\n- Angular: Support statsJson in angular schemas - [#29233](https://github.com/storybookjs/storybook/pull/29233), thanks @yannbf!\n- Automigration: Improve addon-a11y-addon-test - [#30127](https://github.com/storybookjs/storybook/pull/30127), thanks @valentinpalkovic!\n- Automigration: Improve setup file transformation and version range handling for a11y migration - [#30060](https://github.com/storybookjs/storybook/pull/30060), thanks @valentinpalkovic!\n- Automigrations: Skip vite config file migration for react native web - [#30190](https://github.com/storybookjs/storybook/pull/30190), thanks @dannyhw!\n- Build: Downgrade to esbuild 0.24.0 - [#30116](https://github.com/storybookjs/storybook/pull/30116), thanks @yannbf!\n- Build: Revert Downgrade to esbuild 0.24.0 - [#30120](https://github.com/storybookjs/storybook/pull/30120), thanks @yannbf!\n- CLI: Fix init help for `storybook` command - [#29480](https://github.com/storybookjs/storybook/pull/29480), thanks @toothlessdev!\n- CLI: Fix new-frameworks automigration - [#29804](https://github.com/storybookjs/storybook/pull/29804), thanks @yannbf!\n- CLI: Re-Add Nuxt support - [#28607](https://github.com/storybookjs/storybook/pull/28607), thanks @valentinpalkovic!\n- CLI: Update a11y-test comment with experimental caveat - [#30258](https://github.com/storybookjs/storybook/pull/30258), thanks @shilman!\n- Composition: Fix composed story search - [#29453](https://github.com/storybookjs/storybook/pull/29453), thanks @jsingh0026!\n- Composition: Hide contextMenu on composed storybooks - [#29803](https://github.com/storybookjs/storybook/pull/29803), thanks @ndelangen!\n- Core / Addon Test: Add config UI to Testing Module - [#29708](https://github.com/storybookjs/storybook/pull/29708), thanks @ghengeveld!\n- Core / Addon Test: Support intercepting and modifying internal test provider state updates - [#29680](https://github.com/storybookjs/storybook/pull/29680), thanks @ghengeveld!\n- Core + Addon Test: Refactor test API and fix total test count - [#29656](https://github.com/storybookjs/storybook/pull/29656), thanks @ghengeveld!\n- Core: Add bun support with npm fallback - [#29267](https://github.com/storybookjs/storybook/pull/29267), thanks @stephenjason89!\n- Core: Avoid getting stuck in locked state - [#29768](https://github.com/storybookjs/storybook/pull/29768), thanks @ghengeveld!\n- Core: Disable SidebarContextMenu in static builds - [#29743](https://github.com/storybookjs/storybook/pull/29743), thanks @ndelangen!\n- Core: Emit deprecated `TESTING_MODULE_RUN_ALL_REQUEST` for backward compatibility - [#29711](https://github.com/storybookjs/storybook/pull/29711), thanks @ghengeveld!\n- Core: Evaluate main config when checking \\'whats new\\' notifications - [#29622](https://github.com/storybookjs/storybook/pull/29622), thanks @yannbf!\n- Core: Fix `ERR_PACKAGE_PATH_NOT_EXPORTED` in `@storybook/node-logger` - [#30093](https://github.com/storybookjs/storybook/pull/30093), thanks @JReinhold!\n- Core: Fix `scrollIntoView` behavior and reimplement testing module time rendering - [#30044](https://github.com/storybookjs/storybook/pull/30044), thanks @ghengeveld!\n- Core: Fix bundling of React - [#30003](https://github.com/storybookjs/storybook/pull/30003), thanks @yannbf!\n- Core: Float context menu button on top of story titles in sidebar - [#30080](https://github.com/storybookjs/storybook/pull/30080), thanks @ghengeveld!\n- Core: Prevent clipping box shadow on file search modal - [#29523](https://github.com/storybookjs/storybook/pull/29523), thanks @ghengeveld!\n- Core: Prevent infinite rerendering caused by comparison by reference - [#30081](https://github.com/storybookjs/storybook/pull/30081), thanks @ghengeveld!\n- Docs: Add code snippet to addons panel - [#29253](https://github.com/storybookjs/storybook/pull/29253), thanks @larsrickert!\n- Interactions: Correctly load preset when absolute paths are used - [#30264](https://github.com/storybookjs/storybook/pull/30264), thanks @JReinhold!\n- Maintenance: Move `@types/node` to `devDeps` consistently - [#30163](https://github.com/storybookjs/storybook/pull/30163), thanks @ndelangen!\n- Manager API: Fix infinite render-loop caused by `useSharedState` - [#30259](https://github.com/storybookjs/storybook/pull/30259), thanks @JReinhold!\n- Manager: Add tags property to GroupEntry objects - [#29672](https://github.com/storybookjs/storybook/pull/29672), thanks @Sidnioulz!\n- Manager: Fix size regression - [#29660](https://github.com/storybookjs/storybook/pull/29660), thanks @JReinhold!\n- Manager: Optimize getPanels function with memoization - [#30192](https://github.com/storybookjs/storybook/pull/30192), thanks @valentinpalkovic!\n- Next.js: Fix webpack fsCache not working - [#29654](https://github.com/storybookjs/storybook/pull/29654), thanks @sentience!\n- Next.js: Support v15.1.1 - [#30068](https://github.com/storybookjs/storybook/pull/30068), thanks @valentinpalkovic!\n- Next.js: Upgrade sass-loader from ^13.2.0 to ^14.2.1 - [#29264](https://github.com/storybookjs/storybook/pull/29264), thanks @HoncharenkoZhenya!\n- Nextjs-Vite: Add TS docgen support - [#29824](https://github.com/storybookjs/storybook/pull/29824), thanks @yannbf!\n- Nextjs-Vite: Fix docgen types in main config - [#30042](https://github.com/storybookjs/storybook/pull/30042), thanks @yannbf!\n- Onboarding: Replace `react-confetti` with `@neoconfetti/react` - [#30098](https://github.com/storybookjs/storybook/pull/30098), thanks @ndelangen!\n- React Native Web: Add framework, CLI integration, sandboxes - [#29520](https://github.com/storybookjs/storybook/pull/29520), thanks @shilman!\n- React: Fix RSC compatibility with addon-themes and hooks - [#26243](https://github.com/storybookjs/storybook/pull/26243), thanks @shilman!\n- React: Force act running always in sequence - [#30191](https://github.com/storybookjs/storybook/pull/30191), thanks @valentinpalkovic!\n- React: Use Act wrapper in Storybook for component rendering - [#30037](https://github.com/storybookjs/storybook/pull/30037), thanks @valentinpalkovic!\n- ReactVite: Add `@storybook/test` as optional peer dependency - [#29754](https://github.com/storybookjs/storybook/pull/29754), thanks @yannbf!\n- RNW-Vite: Add built-in Flow support - [#29756](https://github.com/storybookjs/storybook/pull/29756), thanks @dannyhw!\n- RNW-Vite: Add tsconfig path aliases support - [#29953](https://github.com/storybookjs/storybook/pull/29953), thanks @shilman!\n- RNW-Vite: Fix flow plugin including too many things - [#29952](https://github.com/storybookjs/storybook/pull/29952), thanks @dannyhw!\n- RNW-Vite: Fix reanimated support with babel plugin for node_modules - [#30188](https://github.com/storybookjs/storybook/pull/30188), thanks @dannyhw!\n- RNW-Vite: Integrate with experimental-addon-test - [#29645](https://github.com/storybookjs/storybook/pull/29645), thanks @shilman!\n- Storysource Addon: Fix source-loader prettier imports - [#29669](https://github.com/storybookjs/storybook/pull/29669), thanks @slax57!\n- Telemetry: Add metadata distinguishing \"apps\" from \"design systems\" - [#30070](https://github.com/storybookjs/storybook/pull/30070), thanks @tmeasday!\n- Test: Add coverage feature - [#29713](https://github.com/storybookjs/storybook/pull/29713), thanks @ndelangen!\n- TestAddon: Refactor UI & add config options - [#29662](https://github.com/storybookjs/storybook/pull/29662), thanks @ndelangen!\n- Toolbars: Suppress deprecation warning when using dynamic icons - [#29545](https://github.com/storybookjs/storybook/pull/29545), thanks @ValeraS!\n- UI: Add support for groups to `TooltipLinkList` and use it in main menu - [#29507](https://github.com/storybookjs/storybook/pull/29507), thanks @ghengeveld!\n- UI: Add Yarn to About Section - [#29225](https://github.com/storybookjs/storybook/pull/29225), thanks @grantwforsythe!\n- UI: Fix controls and parameters on tag-filtered stories - [#30038](https://github.com/storybookjs/storybook/pull/30038), thanks @shilman!\n- UI: Fix overlapping shadow of testing module on scrollbar - [#30132](https://github.com/storybookjs/storybook/pull/30132), thanks @valentinpalkovic!\n- UI: Fix test provider event handling on startup - [#30083](https://github.com/storybookjs/storybook/pull/30083), thanks @ghengeveld!\n- UI: Keep failing stories in the sidebar, disregarding filters - [#30086](https://github.com/storybookjs/storybook/pull/30086), thanks @JReinhold!\n- UI: Sidebar context menu addon API - [#29557](https://github.com/storybookjs/storybook/pull/29557), thanks @ndelangen!\n- Vite: Add extra entries to `optimizeDeps` - [#30117](https://github.com/storybookjs/storybook/pull/30117), thanks @ndelangen!\n- Vite: Don\\'t prefix story import with `@fs` - [#28941](https://github.com/storybookjs/storybook/pull/28941), thanks @tobiasdiez!\n- Vite: Fix preview runtime import - [#29802](https://github.com/storybookjs/storybook/pull/29802), thanks @yannbf!\n- Vite: Fix wrong import paths when configDir is not in project root - [#30206](https://github.com/storybookjs/storybook/pull/30206), thanks @JReinhold!\n- Vite: Import preview runtime as ordinary module - [#29172](https://github.com/storybookjs/storybook/pull/29172), thanks @tobiasdiez!\n- Vitest: Add plugins from `viteFinal` - [#30105](https://github.com/storybookjs/storybook/pull/30105), thanks @JReinhold!\n- Vue: Extend sourceDecorator to support v-bind and nested keys in slots - [#28787](https://github.com/storybookjs/storybook/pull/28787), thanks @JoCa96!\n- Vue: Fix `vue-component-meta` docgen HMR not working - [#29518](https://github.com/storybookjs/storybook/pull/29518), thanks @IonianPlayboy!\n</details>\n\n## 8.4.7\n\n- Telemetry: Improve anonymous id calculation - [#29736](https://github.com/storybookjs/storybook/pull/29736), thanks @tmeasday!\n- Vue: Properly resolve Vite plugin - [#29795](https://github.com/storybookjs/storybook/pull/29795), thanks @tobiasdiez!\n\n## 8.4.6\n\n- Addon Test: Use pathe for better windows support - [#29676](https://github.com/storybookjs/storybook/pull/29676), thanks @yannbf!\n- Angular: Default to standalone components in Angular v19 - [#29677](https://github.com/storybookjs/storybook/pull/29677), thanks @ingowagner!\n- Frameworks: Add Vite 6 support - [#29710](https://github.com/storybookjs/storybook/pull/29710), thanks @yannbf!\n- Portable stories: Support multiple annotation notations from preview - [#29733](https://github.com/storybookjs/storybook/pull/29733), thanks @yannbf!\n- React: Upgrade react-docgen-typescript to support Vite 6 - [#29724](https://github.com/storybookjs/storybook/pull/29724), thanks @yannbf!\n- Svelte: Support `@sveltejs/vite-plugin-svelte` v5 - [#29731](https://github.com/storybookjs/storybook/pull/29731), thanks @JReinhold!\n\n## 8.4.5\n\n- Angular: Support v19 - [#29659](https://github.com/storybookjs/storybook/pull/29659), thanks @leosvelperez!\n- CLI: Disable corepack auto pin behavior - [#29627](https://github.com/storybookjs/storybook/pull/29627), thanks @yannbf!\n- CLI: Fix qwik init - [#29632](https://github.com/storybookjs/storybook/pull/29632), thanks @shilman!\n- Nextjs-Vite: Add Next.js 15 support - [#29640](https://github.com/storybookjs/storybook/pull/29640), thanks @yannbf!\n\n## 8.4.4\n\n- Addon Test: Only optimize react deps if applicable in vitest-plugin - [#29617](https://github.com/storybookjs/storybook/pull/29617), thanks @yannbf!\n\n## 8.4.3\n\n- Addon Test: Optimize internal dependencies - [#29595](https://github.com/storybookjs/storybook/pull/29595), thanks @yannbf!\n- Next.js: Add support for Next 15 - [#29587](https://github.com/storybookjs/storybook/pull/29587), thanks @yannbf!\n\n## 8.4.2\n\n- Addon Test: Fix post-install logic for Next.js Vite framework support - [#29524](https://github.com/storybookjs/storybook/pull/29524), thanks @valentinpalkovic!\n- Addon Test: Only render the TestingModule component in development mode - [#29501](https://github.com/storybookjs/storybook/pull/29501), thanks @yannbf!\n- CLI: Fix Solid init by installing `@storybook/test` - [#29514](https://github.com/storybookjs/storybook/pull/29514), thanks @shilman!\n- Core: Shim CJS-only globals in ESM output - [#29157](https://github.com/storybookjs/storybook/pull/29157), thanks @valentinpalkovic!\n- Next.js: Fix bundled react and react-dom in monorepos - [#29444](https://github.com/storybookjs/storybook/pull/29444), thanks @sentience!\n\n## 8.4.1\n\n- Core: Relax peer dep constraint of shim packages - [#29503](https://github.com/storybookjs/storybook/pull/29503), thanks @kasperpeulen!\n\n## 8.4.0\n\nStorybook 8.4 comes with a ton of exciting new features designed to give you the best experience developing, testing, and debugging tests in the browser!\n\n- ▶️ **Unified UI** for component testing\n- 5️⃣ **Svelte 5** and Svelte CSF support\n- ⚛️ **React Native Storybook 8** release\n- 🏷️ **Tags-based filtering** to organize your Storybook\n- 🫧 **Dependency cleanup** to reduce install footprint\n- 💯 **Hundreds** more improvements\n\n<details>\n<summary>List of all updates</summary>\n\n- Addon Test: Adjust file exports to be ESM/CJS compatible - [#29471](https://github.com/storybookjs/storybook/pull/29471), thanks @valentinpalkovic!\n- Addon Test: Error when addon interactions exists - [#29434](https://github.com/storybookjs/storybook/pull/29434), thanks @valentinpalkovic!\n- Addon Test: Escape XML when converting ANSI to HTML in test errors - [#29446](https://github.com/storybookjs/storybook/pull/29446), thanks @ghengeveld!\n- Addon Test: Fix hiding stacktrace for assertion errors in test panel - [#29458](https://github.com/storybookjs/storybook/pull/29458), thanks @ghengeveld!\n- Addon Test: Improve Error Handling - [#29476](https://github.com/storybookjs/storybook/pull/29476), thanks @valentinpalkovic!\n- Addon Test: Improve postinstall script - [#29479](https://github.com/storybookjs/storybook/pull/29479), thanks @yannbf!\n- Addon Test: Improve unsupported vitest message - [#29486](https://github.com/storybookjs/storybook/pull/29486), thanks @valentinpalkovic!\n- Addon Test: Only register testing module in Vite projects - [#29472](https://github.com/storybookjs/storybook/pull/29472), thanks @yannbf!\n- Addon Test: Throttle Vitest progress updates more heavily - [#29482](https://github.com/storybookjs/storybook/pull/29482), thanks @ghengeveld!\n- Addon-docs, blocks: Prebundle dependencies - [#29301](https://github.com/storybookjs/storybook/pull/29301), thanks @JReinhold!\n- Addon-Test: Support for `@vitest/browser` v2.1.2 - [#29407](https://github.com/storybookjs/storybook/pull/29407), thanks @strozw!\n- Blocks: Prebundle `es-toolkit` - [#29259](https://github.com/storybookjs/storybook/pull/29259), thanks @JReinhold!\n- Builder-vite: Replace .at() call with [] in codegen - [#29048](https://github.com/storybookjs/storybook/pull/29048), thanks @Chudesnov!\n- CLI: Don't add `@storybook/addon-links` by default - [#29177](https://github.com/storybookjs/storybook/pull/29177), thanks @tobiasdiez!\n- CLI: Ensure `.gitignore` updated via CLI ends with a newline - [#29124](https://github.com/storybookjs/storybook/pull/29124), thanks @3w36zj6!\n- CLI: Fix `yarn` detection - [#29448](https://github.com/storybookjs/storybook/pull/29448), thanks @ndelangen!\n- CLI: Migrate from `chalk` to `picocolors` - [#28262](https://github.com/storybookjs/storybook/pull/28262), thanks @43081j!\n- CLI: Refactor NPMProxy error parsing logic - [#29459](https://github.com/storybookjs/storybook/pull/29459), thanks @yannbf!\n- ConfigFile: Fix `export { X }` parsing - [#29344](https://github.com/storybookjs/storybook/pull/29344), thanks @vctqs1!\n- Core: Add unified UI Testing Module - [#29241](https://github.com/storybookjs/storybook/pull/29241), thanks @yannbf!\n- Core: Close story status menu when selecting an item - [#29455](https://github.com/storybookjs/storybook/pull/29455), thanks @ghengeveld!\n- Core: Fix building Storybook deleting project root files - [#29371](https://github.com/storybookjs/storybook/pull/29371), thanks @JReinhold!\n- Core: Fix race condition during empty folder init - [#29490](https://github.com/storybookjs/storybook/pull/29490), thanks @valentinpalkovic!\n- Core: Make `prettier` an optional peer dependency - [#29223](https://github.com/storybookjs/storybook/pull/29223), thanks @JReinhold!\n- Core: Migrate from `express` to `polka` - [#29230](https://github.com/storybookjs/storybook/pull/29230), thanks @43081j!\n- Core: Migrate from `qs` to `picoquery` - [#28315](https://github.com/storybookjs/storybook/pull/28315), thanks @43081j!\n- Core: Open 'Component tests' addon panel when clicking a story status - [#29456](https://github.com/storybookjs/storybook/pull/29456), thanks @ghengeveld!\n- Core: Remove `handlebars` usage - [#29208](https://github.com/storybookjs/storybook/pull/29208), thanks @ndelangen!\n- Core: Remove dependence on `file-system-cache` - [#29256](https://github.com/storybookjs/storybook/pull/29256), thanks @ndelangen!\n- Core: Replace `fs-extra` with the native APIs - [#29126](https://github.com/storybookjs/storybook/pull/29126), thanks @ziebam!\n- Core: Replace `lodash` with `es-toolkit` - [#28981](https://github.com/storybookjs/storybook/pull/28981), thanks @ndelangen!\n- Core: Show checkmark icon in story status dropdown and update status label for component tests - [#29451](https://github.com/storybookjs/storybook/pull/29451), thanks @ghengeveld!\n- Core: Show tooltip on filter toggles to clarify their purpose - [#29447](https://github.com/storybookjs/storybook/pull/29447), thanks @ghengeveld!\n- Core: Track test provider state in sessionStorage - [#29450](https://github.com/storybookjs/storybook/pull/29450), thanks @ghengeveld!\n- Core: Upgrade `esbuild`, broadening version range - [#29254](https://github.com/storybookjs/storybook/pull/29254), thanks @ndelangen!\n- Dependencies: Upgrade VTA to v3.1.0 - [#29449](https://github.com/storybookjs/storybook/pull/29449), thanks @ghengeveld!\n- Dependencies: Upgrade VTA to v3.2.0 to resolve peerDep conflict - [#29461](https://github.com/storybookjs/storybook/pull/29461), thanks @ghengeveld!\n- Interactions: Escape xml of interactions errors - [#29414](https://github.com/storybookjs/storybook/pull/29414), thanks @kasperpeulen!\n- Maintenance: Fix broken and outdated documentation links - [#29412](https://github.com/storybookjs/storybook/pull/29412), thanks @jonniebigodes!\n- Manager: Add tags property to ComponentEntry objects - [#29343](https://github.com/storybookjs/storybook/pull/29343), thanks @Sidnioulz!\n- React: Prebundle all of `renderers/react`'s dependencies - [#29298](https://github.com/storybookjs/storybook/pull/29298), thanks @ndelangen!\n- Svelte: Improve argTypes inference with `svelte2tsx` - support runes - [#29423](https://github.com/storybookjs/storybook/pull/29423), thanks @JReinhold!\n- Test: Remove unused `util` dependency - [#29310](https://github.com/storybookjs/storybook/pull/29310), thanks @JReinhold!\n- UI: Brand image css class conflict causes image to resize on hot reloads - [#29129](https://github.com/storybookjs/storybook/pull/29129), thanks @ShreySinha02!\n- UI: Fix RefIndicator to use CheckIcon instead of string - [#29209](https://github.com/storybookjs/storybook/pull/29209), thanks @JSMike!\n- UI: Simple tag filtering - [#29333](https://github.com/storybookjs/storybook/pull/29333), thanks @shilman!\n- UI: Use production-mode `react` in manager - [#29197](https://github.com/storybookjs/storybook/pull/29197), thanks @ndelangen!\n- Viewport-addon: Add InitialViewportKeys type to viewport addon - [#29182](https://github.com/storybookjs/storybook/pull/29182), thanks @hyeongrok7874!\n- Vite: Add jsdoc-type-pratt-parser to `optimizeDeps` - [#29179](https://github.com/storybookjs/storybook/pull/29179), thanks @tobiasdiez!\n- Vite: Cleanup and prebundle dependencies - [#29302](https://github.com/storybookjs/storybook/pull/29302), thanks @JReinhold!\n- Webpack: Fix export 'act' (imported as 'React4') was not found in 'react' errors in webpack - [#29235](https://github.com/storybookjs/storybook/pull/29235), thanks @kasperpeulen!\n\n</details>\n\n## 8.3.6\n\n- CLI: Install Svelte CSF v5 in Svelte5 projects - [#29323](https://github.com/storybookjs/storybook/pull/29323), thanks @shilman!\n- Svelte: Add v5 stories to CLI templates - [#29382](https://github.com/storybookjs/storybook/pull/29382), thanks @JReinhold!\n\n## 8.3.5\n\n- CLI: Update the React Native init to include v8 dependencies - [#29273](https://github.com/storybookjs/storybook/pull/29273), thanks @dannyhw!\n- Vitest plugin: Fix renamed export stories - [#29250](https://github.com/storybookjs/storybook/pull/29250), thanks @shilman!\n\n## 8.3.4\n\n- Addon Test: Support story name as test description - [#29147](https://github.com/storybookjs/storybook/pull/29147), thanks @InfiniteXyy!\n- Addon-Interactions: Use ansi-to-html for colored test errors - [#29110](https://github.com/storybookjs/storybook/pull/29110), thanks @kasperpeulen!\n\n## 8.3.3\n\n- CLI: Show constraints in error when getting depndencies - [#29187](https://github.com/storybookjs/storybook/pull/29187), thanks @andrasczeh!\n- React-Vite: Downgrade react-docgen-typescript plugin - [#29184](https://github.com/storybookjs/storybook/pull/29184), thanks @shilman!\n- UI: Fix composed storybook TooltipLinkList bug where href isn't passed forward - [#29175](https://github.com/storybookjs/storybook/pull/29175), thanks @JSMike!\n\n## 8.3.2\n\n- CLI: Fix skip-install for stable latest releases - [#29133](https://github.com/storybookjs/storybook/pull/29133), thanks @valentinpalkovic!\n- Core: Do not add packageManager field to package.json during `storybook dev` - [#29152](https://github.com/storybookjs/storybook/pull/29152), thanks @valentinpalkovic!\n\n## 8.3.1\n\n- Angular: Fix sourceDecorator to apply excludeDecorators flag - [#29069](https://github.com/storybookjs/storybook/pull/29069), thanks @JSMike!\n- Core: Do not prebundle better-opn - [#29137](https://github.com/storybookjs/storybook/pull/29137), thanks @valentinpalkovic!\n- Core: Do not prebundle jsdoc-type-pratt-parser - [#29134](https://github.com/storybookjs/storybook/pull/29134), thanks @valentinpalkovic!\n- Next.js: Upgrade sass-loader from ^12 to ^13 - [#29040](https://github.com/storybookjs/storybook/pull/29040), thanks @HoncharenkoZhenya!\n\n## 8.3.0\n\nFresh out of the oven! Storybook 8.3 brings you:\n\n- ⚡️ **First-class Vitest integration** to run stories as component tests\n- 🔼 **Next.js-Vite framework** for Vitest compatibility and better DX\n- 🗜️ **Further reduced bundle size** for a smaller install footprint\n- 🌐 **Experimental Story globals** to standardize stories for themes, viewports, and locales\n- 💯 **Hundreds** more improvements\n\n<details>\n<summary>List of all updates</summary>\n\n- Addon Test: Improve messages and post install script handling - [#29036](https://github.com/storybookjs/storybook/pull/29036), thanks @yannbf!\n- Addon Viewport: Add default options via parameters - [#28944](https://github.com/storybookjs/storybook/pull/28944), thanks @ndelangen!\n- Addon Test: Add experimental vitest integration - [#28768](https://github.com/storybookjs/storybook/pull/28768), thanks @kasperpeulen!\n- Addon Test: Fix error message logic in set up file - [#28906](https://github.com/storybookjs/storybook/pull/28906), thanks @yannbf!\n- Addon Test: Fix indentation of 'vitePluginNext' in generated Vitest config file - [#29011](https://github.com/storybookjs/storybook/pull/29011), thanks @ghengeveld!\n- Addon Test: Fix postinstall file types - [#28978](https://github.com/storybookjs/storybook/pull/28978), thanks @shilman!\n- Addon Test: Fix tests potentially not existing in non-isolate mode - [#28993](https://github.com/storybookjs/storybook/pull/28993), thanks @yannbf!\n- Addon Test: Improve transformation logic to avoid duplicate tests - [#28929](https://github.com/storybookjs/storybook/pull/28929), thanks @yannbf!\n- Addon Test: Set default viewport if applicable - [#28905](https://github.com/storybookjs/storybook/pull/28905), thanks @yannbf!\n- Addon Test: Set screenshotFailures to false by default - [#28908](https://github.com/storybookjs/storybook/pull/28908), thanks @yannbf!\n- Addon Docs: Remove babel dependency - [#28915](https://github.com/storybookjs/storybook/pull/28915), thanks @shilman!\n- Addon Interactions: Fix status in panel tab - [#28580](https://github.com/storybookjs/storybook/pull/28580), thanks @yannbf!\n- Angular: Fix Angular template error for props with a circular reference - [#28498](https://github.com/storybookjs/storybook/pull/28498), thanks @Marklb!\n- Angular: Fix template props not able to use dot notation - [#28588](https://github.com/storybookjs/storybook/pull/28588), thanks @Marklb!\n- Backgrounds/Viewports: Make defaults overridable in `StoryGlobals`-mode - [#29025](https://github.com/storybookjs/storybook/pull/29025), thanks @JReinhold!\n- Blocks: Fix scroll to non-ascii anchors - [#28826](https://github.com/storybookjs/storybook/pull/28826), thanks @SkReD!\n- Build: Remove external overrides, use package.json as source of truth - [#28632](https://github.com/storybookjs/storybook/pull/28632), thanks @kasperpeulen!\n- Builder-Vite: Add null character prefix to virtual file IDs - [#28863](https://github.com/storybookjs/storybook/pull/28863), thanks @valentinpalkovic!\n- Builder-Vite: Fix 'condition node never be used' warning - [#28989](https://github.com/storybookjs/storybook/pull/28989), thanks @valentinpalkovic!\n- CLI: Add conditional logging for manager and preview start - [#28603](https://github.com/storybookjs/storybook/pull/28603), thanks @tobiasdiez!\n- CLI: Fix dedent import in package managers - [#28980](https://github.com/storybookjs/storybook/pull/28980), thanks @shilman!\n- CLI: Fix the initialization of Storybook in workspaces - [#28699](https://github.com/storybookjs/storybook/pull/28699), thanks @valentinpalkovic!\n- CLI: Handle Yarn PnP wrapper scenario when adding an addon - [#29027](https://github.com/storybookjs/storybook/pull/29027), thanks @yannbf!\n- CLI: Make PackageJson optional for starting a dev server - [#28594](https://github.com/storybookjs/storybook/pull/28594), thanks @tobiasdiez!\n- CLI: Update spawn options in proxy.ts to support Windows - [#28990](https://github.com/storybookjs/storybook/pull/28990), thanks @valentinpalkovic!\n- Components: Remove external overrides - [#28632](https://github.com/storybookjs/storybook/pull/28632), thanks @kasperpeulen!\n- ConfigFile: Fix `as const satisfies` modifiers - [#29000](https://github.com/storybookjs/storybook/pull/29000), thanks @shilman!\n- Controls: Add disableSave parameter - [#28734](https://github.com/storybookjs/storybook/pull/28734), thanks @valentinpalkovic!\n- Core: Add Rsbuild frameworks to known frameworks - [#28694](https://github.com/storybookjs/storybook/pull/28694), thanks @fi3ework!\n- Core: De-duplicate babel use in core - [#28972](https://github.com/storybookjs/storybook/pull/28972), thanks @ndelangen!\n- Core: Fix header for MountMustBeDestructuredError message - [#28590](https://github.com/storybookjs/storybook/pull/28590), thanks @0916dhkim!\n- Core: Fix manager-builder `tsconfig` to emit `react-jsx` - [#28541](https://github.com/storybookjs/storybook/pull/28541), thanks @williamhelmrath!\n- Core: Introduce setProjectAnnotations API to more renderers and frameworks - [#28907](https://github.com/storybookjs/storybook/pull/28907), thanks @yannbf!\n- Core: Make sure CJS build always has lowest prio - [#28829](https://github.com/storybookjs/storybook/pull/28829), thanks @kasperpeulen!\n- Core: Move `util` to regular dependency - [#29008](https://github.com/storybookjs/storybook/pull/29008), thanks @ndelangen!\n- Core: Split Storybook CLI - [#28519](https://github.com/storybookjs/storybook/pull/28519), thanks @kasperpeulen!\n- Core: Upgrade docs-mdx for smaller install - [#28552](https://github.com/storybookjs/storybook/pull/28552), thanks @shilman!\n- CPC: Add `ESM` export to `docs-tools` & `node-logger` packages - [#28539](https://github.com/storybookjs/storybook/pull/28539), thanks @ndelangen!\n- CPC: Fix missing dependency in `@storybook/addon-interactions` - [#28518](https://github.com/storybookjs/storybook/pull/28518), thanks @ndelangen!\n- CPC: Fix type generation - [#28507](https://github.com/storybookjs/storybook/pull/28507), thanks @ndelangen!\n- CPC: Revert renames of panels, addon_ids - [#28524](https://github.com/storybookjs/storybook/pull/28524), thanks @ndelangen!\n- CSF: Allow overridding globals at the story level - [#26654](https://github.com/storybookjs/storybook/pull/26654), thanks @tmeasday!\n- Dependencies: Upgrade `commander` - [#28857](https://github.com/storybookjs/storybook/pull/28857), thanks @43081j!\n- Fix: Add header for MountMustBeDestructuredError message - [#28590](https://github.com/storybookjs/storybook/pull/28590), thanks @0916dhkim!\n- Fix: Prevent iframe from capturing mouse events in composed Storybooks - [#28568](https://github.com/storybookjs/storybook/pull/28568), thanks @Vincentdevreede!\n- Maintenance: Add `node:`-prefix to node core-modules - [#28860](https://github.com/storybookjs/storybook/pull/28860), thanks @ndelangen!\n- Maintenance: Rename addon-vitest to addon-test - [#29014](https://github.com/storybookjs/storybook/pull/29014), thanks @yannbf!\n- Next.js-Vite: Fix vite plugin exports - [#29046](https://github.com/storybookjs/storybook/pull/29046), thanks @valentinpalkovic!\n- Next.js-Vite: Streamline Next.js dir option - [#28995](https://github.com/storybookjs/storybook/pull/28995), thanks @valentinpalkovic!\n- Next.js-Vite: Update next and vite-plugin-storybook-nextjs dependencies - [#28994](https://github.com/storybookjs/storybook/pull/28994), thanks @valentinpalkovic!\n- Next.js: Add @storybook/nextjs-vite package - [#28800](https://github.com/storybookjs/storybook/pull/28800), thanks @valentinpalkovic!\n- Next.js: Fix wrong Next.js framework reference - [#28992](https://github.com/storybookjs/storybook/pull/28992), thanks @valentinpalkovic!\n- Next.js: Make RSC portable-stories compatible - [#28756](https://github.com/storybookjs/storybook/pull/28756), thanks @valentinpalkovic!\n- Next.js: Update dependencies - [#29052](https://github.com/storybookjs/storybook/pull/29052), thanks @valentinpalkovic!\n- Nextjs-Vite: Re-export vite-plugin-storybook-nextjs - [#29012](https://github.com/storybookjs/storybook/pull/29012), thanks @valentinpalkovic!\n- Portable Stories: Improve Handling of React Updates and Errors - [#29044](https://github.com/storybookjs/storybook/pull/29044), thanks @valentinpalkovic!\n- React: Avoid 'Dynamic require of react is not possible' issue - [#28730](https://github.com/storybookjs/storybook/pull/28730), thanks @valentinpalkovic!\n- React: Bundle in `lodash` - [#28609](https://github.com/storybookjs/storybook/pull/28609), thanks @ndelangen!\n- Svelte: Fix events not being logged in Actions when a story has decorators - [#28247](https://github.com/storybookjs/storybook/pull/28247), thanks @JReinhold!\n- SvelteKit: Introduce portable stories support - [#28918](https://github.com/storybookjs/storybook/pull/28918), thanks @yannbf!\n- SvelteKit/Vue3: Refactor plugin export paths - [#29016](https://github.com/storybookjs/storybook/pull/29016), thanks @yannbf!\n- Telemetry: Add globals stats - [#28822](https://github.com/storybookjs/storybook/pull/28822), thanks @shilman!\n- Telemetry: Add portable stories - [#26764](https://github.com/storybookjs/storybook/pull/26764), thanks @shilman!\n- Test: Fix support for TS < 4.7 - [#28887](https://github.com/storybookjs/storybook/pull/28887), thanks @ndelangen!\n- Test: Rename vitest plugin entrypoint - [#29067](https://github.com/storybookjs/storybook/pull/29067), thanks @yannbf!\n- Test: Upgrade Vitest to v2 - [#28788](https://github.com/storybookjs/storybook/pull/28788), thanks @yannbf!\n- Types: Adjust beforeAll to be non-nullable in NormalizedProjectAnnotations - [#28671](https://github.com/storybookjs/storybook/pull/28671), thanks @kasperpeulen!\n- Types: Update type signatures of objects and functions - [#28503](https://github.com/storybookjs/storybook/pull/28503), thanks @valentinpalkovic!\n- UI: Fix collapse/expand all functionality - [#28582](https://github.com/storybookjs/storybook/pull/28582), thanks @filipemelo2002!\n- UI: Fix conditional hooks usage in sidebar - [#28979](https://github.com/storybookjs/storybook/pull/28979), thanks @JReinhold!\n- UI: Fix sidebar not wrapping - [#29055](https://github.com/storybookjs/storybook/pull/29055), thanks @JReinhold!\n- Vite: Fix HMR - [#28876](https://github.com/storybookjs/storybook/pull/28876), thanks @ndelangen!\n- Vite: Fix missing source map warning - [#28984](https://github.com/storybookjs/storybook/pull/28984), thanks @valentinpalkovic!\n- Vitest: Fix add command - [#28975](https://github.com/storybookjs/storybook/pull/28975), thanks @ghengeveld!\n- Vitest: Fix default viewport - [#28943](https://github.com/storybookjs/storybook/pull/28943), thanks @kasperpeulen!\n- Vitest: Implement add command for vitest addon - [#28920](https://github.com/storybookjs/storybook/pull/28920), thanks @kasperpeulen!\n- Vue: Add missing prop controls when using `vue-component-meta` docgen plugin - [#28760](https://github.com/storybookjs/storybook/pull/28760), thanks @larsrickert!\n- Vue: Improve generated code snippets - [#27194](https://github.com/storybookjs/storybook/pull/27194), thanks @larsrickert!\n- Vue3: Add vite plugin for portable stories - [#29004](https://github.com/storybookjs/storybook/pull/29004), thanks @yannbf!\n\n</details>\n\n## 8.2.9\n\n- CLI: Fix `init --skip-install` - [#28853](https://github.com/storybookjs/storybook/pull/28853), thanks @ndelangen!\n- Telemetry: Disable save-from-controls logs for example stories - [#28870](https://github.com/storybookjs/storybook/pull/28870), thanks @shilman!\n\n## 8.2.8\n\n- CLI: Parse more Yarn Berry errors - [#28816](https://github.com/storybookjs/storybook/pull/28816), thanks @yannbf!\n- Fix: Invariant failed: Expected package.json#version to be defined in the \"undefined\" package - [#28752](https://github.com/storybookjs/storybook/pull/28752), thanks @abcdmku!\n\n## 8.2.7\n\n- CPC: Fix type usage in renderers - [#28745](https://github.com/storybookjs/storybook/pull/28745), thanks @ndelangen!\n- Core: Introduce run over play in portable stories, and revert back play changes of 8.2 - [#28764](https://github.com/storybookjs/storybook/pull/28764), thanks @kasperpeulen!\n\n## 8.2.6\n\n- CPC: Fix missing exports for addon-kit - [#28691](https://github.com/storybookjs/storybook/pull/28691), thanks @ndelangen!\n\n## 8.2.5\n\n- CPC: Add the globals export for manager - [#28650](https://github.com/storybookjs/storybook/pull/28650), thanks @ndelangen!\n- CPC: Correct path to the `@storybook/theming/create` alias - [#28643](https://github.com/storybookjs/storybook/pull/28643), thanks @Averethel!\n- Components: Remove external overrides - [#28632](https://github.com/storybookjs/storybook/pull/28632), thanks @kasperpeulen!\n- Core: Fix header for MountMustBeDestructuredError message - [#28590](https://github.com/storybookjs/storybook/pull/28590), thanks @0916dhkim!\n- Onboarding: Fix code snippet when story name differs from export name - [#28649](https://github.com/storybookjs/storybook/pull/28649), thanks @ghengeveld!\n- Telemetry: Add mount, beforeEach, moduleMock stats - [#28624](https://github.com/storybookjs/storybook/pull/28624), thanks @shilman!\n- Telemetry: CSF feature usage - [#28622](https://github.com/storybookjs/storybook/pull/28622), thanks @shilman!\n\n## 8.2.4\n\n- CLI: Add diagnostic when the `storybook` package is missing - [#28604](https://github.com/storybookjs/storybook/pull/28604), thanks @kasperpeulen!\n- CLI: Make a few automigrations run on all version upgrades - [#28601](https://github.com/storybookjs/storybook/pull/28601), thanks @yannbf!\n- CPC: Direct dependencies on shim packages in renderers - [#28599](https://github.com/storybookjs/storybook/pull/28599), thanks @ndelangen!\n\n## 8.2.3\n\n- Bug: Fix invalid docs links in Configure.mdx template page - [#28560](https://github.com/storybookjs/storybook/pull/28560), thanks @kylegach!\n- CLI: Add \"missing-storybook-dependencies\" automigration - [#28579](https://github.com/storybookjs/storybook/pull/28579), thanks @yannbf!\n- CPC: Add `theming/create` aliases in docs preset - [#28570](https://github.com/storybookjs/storybook/pull/28570), thanks @ndelangen!\n- CPC: Fix incorrect re-export in `core-events` - [#28573](https://github.com/storybookjs/storybook/pull/28573), thanks @ndelangen!\n- CPC: Fix Vite builder had wrong conditions - [#28581](https://github.com/storybookjs/storybook/pull/28581), thanks @ndelangen!\n- CSF: Fix small typing issue - [#28587](https://github.com/storybookjs/storybook/pull/28587), thanks @valentinpalkovic!\n- Portable stories: Remove unused types - [#28548](https://github.com/storybookjs/storybook/pull/28548), thanks @kasperpeulen!\n- Webpack: Fix sourceMap generation in csf-tools - [#28585](https://github.com/storybookjs/storybook/pull/28585), thanks @valentinpalkovic!\n\n## 8.2.2\n\n- CPC: Add `ESM` export to `docs-tools` & `node-logger` packages - [#28539](https://github.com/storybookjs/storybook/pull/28539), thanks @ndelangen!\n- CPC: Fix missing dependency in `@storybook/addon-interactions` - [#28518](https://github.com/storybookjs/storybook/pull/28518), thanks @ndelangen!\n- CPC: Revert renames of panels, addon_ids - [#28524](https://github.com/storybookjs/storybook/pull/28524), thanks @ndelangen!\n\n## 8.2.1\n\n- CPC: Fix type generation - [#28507](https://github.com/storybookjs/storybook/pull/28507), thanks @ndelangen!\n- Types: Update type signatures of objects and functions - [#28503](https://github.com/storybookjs/storybook/pull/28503), thanks @valentinpalkovic!\n\n## 8.2.0\n\nHold onto your hats! Storybook 8.2 has dropped, packed with a treasure trove of new features and bug fixes:\n\n- 🪝 New test hook `beforeAll`\n- 🕹️ Enhanced `play` function\n- 📦 Portable stories that let you use your stories in other testing tools\n- 🎁 Consolidated dependency to bring you better performance in a smaller package\n- ✨ Brand new onboarding experience to get you up to speed quicker\n- 💯 Hundreds more improvements\n\n<details>\n<summary>List of all updates</summary>\n\n- Addon Controls: Fix saving on Windows - [#28485](https://github.com/storybookjs/storybook/pull/28485), thanks @ghengeveld!\n- Addon Interactions: Use unique keys when rendering array nodes in panel - [#28423](https://github.com/storybookjs/storybook/pull/28423), thanks @yannbf!\n- Addon Onboarding: Add icons for dev/test/doc to the splash screen - [#28389](https://github.com/storybookjs/storybook/pull/28389), thanks @ghengeveld!\n- Addon Onboarding: New design and flow based on Save from Controls - [#28327](https://github.com/storybookjs/storybook/pull/28327), thanks @ghengeveld!\n- Addon Onboarding: Trigger onboarding during init for Vue and Angular projects - [#28482](https://github.com/storybookjs/storybook/pull/28482), thanks @ghengeveld!\n- Addon-A11y: Fix property default assignment - [#27224](https://github.com/storybookjs/storybook/pull/27224), thanks @valentinpalkovic!\n- Angular: Allow format configuration of custom source preview - [#28305](https://github.com/storybookjs/storybook/pull/28305), thanks @64BitAsura!\n- Angular: Allow outputPath object syntax - [#28144](https://github.com/storybookjs/storybook/pull/28144), thanks @valentinpalkovic!\n- Angular: Cleanup types - [#27189](https://github.com/storybookjs/storybook/pull/27189), thanks @valentinpalkovic!\n- Angular: Fix enableProdMode setting - [#28415](https://github.com/storybookjs/storybook/pull/28415), thanks @valentinpalkovic!\n- Angular: Fix wrong detection of standalone components - [#27353](https://github.com/storybookjs/storybook/pull/27353), thanks @dario-baumberger!\n- Angular: Introduce preserveSymlink builder option - [#28145](https://github.com/storybookjs/storybook/pull/28145), thanks @valentinpalkovic!\n- Angular: Update outputPath default value in angular-cli-webpack.js - [#28418](https://github.com/storybookjs/storybook/pull/28418), thanks @valentinpalkovic!\n- Babel: Ensure story files not transpiled earlier than ES2017 - [#28469](https://github.com/storybookjs/storybook/pull/28469), thanks @kasperpeulen!\n- Blocks: Fix reference to storybook core - [#28422](https://github.com/storybookjs/storybook/pull/28422), thanks @yannbf!\n- Blocks: Prebundle `tocbot` - [#28318](https://github.com/storybookjs/storybook/pull/28318), thanks @shilman!\n- Build: Change require/import order, so that import has higher prio if both are specified - [#27730](https://github.com/storybookjs/storybook/pull/27730), thanks @kasperpeulen!\n- Build: Ignore ts stories in cra/default-js sandbox - [#28354](https://github.com/storybookjs/storybook/pull/28354), thanks @valentinpalkovic!\n- CLI: Add `--no-dev` option to `init` - [#26918](https://github.com/storybookjs/storybook/pull/26918), thanks @fastfrwrd!\n- CLI: Add optional `--dev` and `--no-dev` options to `storybook init` CLI - [#26918](https://github.com/storybookjs/storybook/pull/26918), thanks @fastfrwrd!\n- CLI: Add support for Nuxt to project init - [#26884](https://github.com/storybookjs/storybook/pull/26884), thanks @tobiasdiez!\n- CLI: Fix CLI always asking all automigrations - [#28238](https://github.com/storybookjs/storybook/pull/28238), thanks @ndelangen!\n- CLI: Improve error message when fetching CLI version - [#28289](https://github.com/storybookjs/storybook/pull/28289), thanks @yannbf!\n- CLI: Include `@storybook/addon-svelte-csf` when initializing new projects - [#27070](https://github.com/storybookjs/storybook/pull/27070), thanks @benmccann!\n- CLI: Prebundle get-npm-tarball-url and @ndelangen/get-tarball - [#28481](https://github.com/storybookjs/storybook/pull/28481), thanks @ndelangen!\n- Config: Apply JavaScript-only story glob extensions for JavaScript projects - [#28338](https://github.com/storybookjs/storybook/pull/28338), thanks @valentinpalkovic!\n- Controls: Fix date picker control validation and assignment - [#26695](https://github.com/storybookjs/storybook/pull/26695), thanks @leeovictor!\n- Controls: Fix grouped Radio controls to have the same name - [#23374](https://github.com/storybookjs/storybook/pull/23374), thanks @srapilly!\n- Controls: Throttling makes Color control lagging - [#22615](https://github.com/storybookjs/storybook/pull/22615), thanks @gitstart!\n- Core: Add context as a property of the context (self-referencing) - [#28353](https://github.com/storybookjs/storybook/pull/28353), thanks @kasperpeulen!\n- Core: Add support for `beforeAll` hook - [#28255](https://github.com/storybookjs/storybook/pull/28255), thanks @ghengeveld!\n- Core: Fix startup hang caused by watchStorySpecifiers - [#27016](https://github.com/storybookjs/storybook/pull/27016), thanks @heyimalex!\n- Core: Make sure StorybookError message shows up in browser console and interactions panel - [#28464](https://github.com/storybookjs/storybook/pull/28464), thanks @kasperpeulen!\n- Core: Migrate from `pkg-dir` to `fd-package-json` - [#28270](https://github.com/storybookjs/storybook/pull/28270), thanks @43081j!\n- Core: Refactor phases to run in order `loading` -> `rendering` -> `playing` - [#28431](https://github.com/storybookjs/storybook/pull/28431), thanks @kasperpeulen!\n- Core: Remove more `.stories.mdx` handling - [#25973](https://github.com/storybookjs/storybook/pull/25973), thanks @JReinhold!\n- Core: Remove util dependency - [#28191](https://github.com/storybookjs/storybook/pull/28191), thanks @43081j!\n- CPC: Add `CJS` for `core/components` - [#28440](https://github.com/storybookjs/storybook/pull/28440), thanks @ndelangen!\n- CPC: Core Package Consolidation - [#27039](https://github.com/storybookjs/storybook/pull/27039), thanks @ndelangen!\n- CSF: Automatically extract componentPath - [#24396](https://github.com/storybookjs/storybook/pull/24396), thanks @shilman!\n- CSF: Rename `preview.js` `globals` to `initialGlobals` - [#27517](https://github.com/storybookjs/storybook/pull/27517), thanks @shilman!\n- Dependencies: Allow esbuild version 0.21.x - [#28245](https://github.com/storybookjs/storybook/pull/28245), thanks @edoardocavazza!\n- Dependency: bump `markdown-to-jsx` to v7.4.5 - [#26694](https://github.com/storybookjs/storybook/pull/26694), thanks @xyy94813!\n- Dependency: Bump Express.js - [#26680](https://github.com/storybookjs/storybook/pull/26680), thanks @valentinpalkovic!\n- Dependency: Remove node-fetch - [#28160](https://github.com/storybookjs/storybook/pull/28160), thanks @yk-kd!\n- Dependency: Upgrade `webpack-virtual-modules` to 0.6.0 - [#27102](https://github.com/storybookjs/storybook/pull/27102), thanks @fyodorovandrei!\n- Deps: Migrate from `read-pkg-up` to `fd-package-json` - [#28272](https://github.com/storybookjs/storybook/pull/28272), thanks @43081j!\n- Docs-tools: Replace `doctrine` with `jsdoc-type-pratt-parser` - [#26305](https://github.com/storybookjs/storybook/pull/26305), thanks @43081j!\n- Docs: Filter mount stories from `Stories` block, error when referenced in MDX - [#28434](https://github.com/storybookjs/storybook/pull/28434), thanks @kasperpeulen!\n- Docs: Fix `Typeset` Doc block `fontSizes` type - [#26475](https://github.com/storybookjs/storybook/pull/26475), thanks @noranda!\n- Index: Fix MDX to override project-level autodocs - [#28461](https://github.com/storybookjs/storybook/pull/28461), thanks @shilman!\n- Indexer: Improve locating stories with specials chars in path - [#22110](https://github.com/storybookjs/storybook/pull/22110), thanks @jankoritak!\n- Next: Set default targets for next babel config - [#28443](https://github.com/storybookjs/storybook/pull/28443), thanks @kasperpeulen!\n- Next.js: Set `env.bugfixes` in SWC so destructuring is never transpiled - [#28363](https://github.com/storybookjs/storybook/pull/28363), thanks @kasperpeulen!\n- React: Export ButtonProps and HeaderProps in CLI templates - [#28487](https://github.com/storybookjs/storybook/pull/28487), thanks @valentinpalkovic!\n- SWC: Set default targets for swc that align with our esbuild targets - [#28435](https://github.com/storybookjs/storybook/pull/28435), thanks @kasperpeulen!\n- Telemetry: Stop prompting about crash reports in CI - [#28433](https://github.com/storybookjs/storybook/pull/28433), thanks @yannbf!\n- Test: Add args to `mount` in react, svelte, and vue renderers - [#28385](https://github.com/storybookjs/storybook/pull/28385), thanks @kasperpeulen!\n- Test: Add mount property to the story context - [#28383](https://github.com/storybookjs/storybook/pull/28383), thanks @kasperpeulen!\n- Test: Enhance the context with canvas when the test package is used - [#28368](https://github.com/storybookjs/storybook/pull/28368), thanks @kasperpeulen!\n- Test: Improve MountMustBeDestructuredError error message - [#28468](https://github.com/storybookjs/storybook/pull/28468), thanks @kasperpeulen!\n- Test: Reactive spies preserve the this instance - [#28445](https://github.com/storybookjs/storybook/pull/28445), thanks @kasperpeulen!\n- Types: Fix type implementation for `CompatibleString` - [#27180](https://github.com/storybookjs/storybook/pull/27180), thanks @sni-J!\n- Vite: Fix asset warning by externalizing sb-common-assets font - [#27110](https://github.com/storybookjs/storybook/pull/27110), thanks @valentinpalkovic!\n- Vue3: Enable new hydration mismatch compile time flag - [#27192](https://github.com/storybookjs/storybook/pull/27192), thanks @Cherry!\n- Webpack5/Vite: Fix sourcemaps - [#27171](https://github.com/storybookjs/storybook/pull/27171), thanks @valentinpalkovic!\n\n</details>\n\n## 8.1.11\n\n- Telemetry: Detect Node version - [#28299](https://github.com/storybookjs/storybook/pull/28299), thanks @yannbf!\n- Test: Upgrade deps of @storybook/test - [#27862](https://github.com/storybookjs/storybook/pull/27862), thanks @kasperpeulen!\n\n## 8.1.10\n\n- Addon-interactions: Fix deprecation warnings - [#28250](https://github.com/storybookjs/storybook/pull/28250), thanks @shilman!\n- Test: Upgrade deps of @storybook/test - [#27862](https://github.com/storybookjs/storybook/pull/27862), thanks @kasperpeulen!\n\n## 8.1.9\n\n- Addon-a11y: Workaround for Vite 5.3.0 compat - [#28241](https://github.com/storybookjs/storybook/pull/28241), thanks @shilman!\n- CLI: Add `--no-dev` option to `init` - [#26918](https://github.com/storybookjs/storybook/pull/26918), thanks @fastfrwrd!\n- CLI: Fix `init --skip-install` - [#28226](https://github.com/storybookjs/storybook/pull/28226), thanks @shilman!\n\n## 8.1.8\n\n- Automigrations: Make VTA \"learn more\" link clickable - [#28020](https://github.com/storybookjs/storybook/pull/28020), thanks @deiga!\n- CLI: Fix `init --skip-install` - [#28226](https://github.com/storybookjs/storybook/pull/28226), thanks @shilman!\n\n## 8.1.7\n\n- Addon-actions: Only log spies with names - [#28091](https://github.com/storybookjs/storybook/pull/28091), thanks @kasperpeulen!\n- CLI: Fix typo in React Docgen migration - [#27536](https://github.com/storybookjs/storybook/pull/27536), thanks @jonniebigodes!\n- Portable Stories: Add tags to composed story - [#27708](https://github.com/storybookjs/storybook/pull/27708), thanks @yannbf!\n- Test: Display toHaveBeenCalledWith expected / received values on failure - [#28088](https://github.com/storybookjs/storybook/pull/28088), thanks @kasperpeulen!\n\n## 8.1.6\n\n- CLI: Only log the UpgradeStorybookToSameVersionError but continue the upgrade as normal - [#27217](https://github.com/storybookjs/storybook/pull/27217), thanks @kasperpeulen!\n- Core: Replace ip function with a small helper function to address security concerns - [#27529](https://github.com/storybookjs/storybook/pull/27529), thanks @tony19!\n- Tags: Fix unsafe project-level tags lookup - [#27511](https://github.com/storybookjs/storybook/pull/27511), thanks @shilman!\n- Vite: Fix stats-plugin to normalize file names with posix paths - [#27218](https://github.com/storybookjs/storybook/pull/27218), thanks @AlexAtVista!\n\n## 8.1.5\n\n- CSF-Tools: Fix export specifier bug - [#27418](https://github.com/storybookjs/storybook/pull/27418), thanks @valentinpalkovic!\n- Dependency: Upgrade tempy - [#27366](https://github.com/storybookjs/storybook/pull/27366), thanks @mnigh!\n- Tags: Refine composition behavior - [#27379](https://github.com/storybookjs/storybook/pull/27379), thanks @shilman!\n- Theming: Fix self-referencing type - [#27155](https://github.com/storybookjs/storybook/pull/27155), thanks @SimenB!\n\n## 8.1.4\n\n- Angular: Revert style adjustments - [#27361](https://github.com/storybookjs/storybook/pull/27361), thanks @valentinpalkovic!\n- Svelte: Support latest prerelease - [#27378](https://github.com/storybookjs/storybook/pull/27378), thanks @valentinpalkovic!\n- Tags: Fix composition with older storybooks - [#27358](https://github.com/storybookjs/storybook/pull/27358), thanks @shilman!\n- Vite: Fix HMR issue for Storybook preview files - [#27256](https://github.com/storybookjs/storybook/pull/27256), thanks @valentinpalkovic!\n\n## 8.1.3\n\n- Angular: Support v18 - [#27237](https://github.com/storybookjs/storybook/pull/27237), thanks @valentinpalkovic!\n- Telemetry: Add test packages - [#27226](https://github.com/storybookjs/storybook/pull/27226), thanks @shilman!\n\n## 8.1.2\n\n- Angular: Fix filtering of workspace config styles - [#27108](https://github.com/storybookjs/storybook/pull/27108), thanks @valentinpalkovic!\n- Next.js: Avoid interfering with the svgr loader - [#27198](https://github.com/storybookjs/storybook/pull/27198), thanks @seanparmelee!\n\n## 8.1.1\n\n- Docgen: Only add react-docgen info when a component is defined in the file - [#26967](https://github.com/storybookjs/storybook/pull/26967), thanks @glenjamin!\n- Docs: Fix MDX Stories block tag-filtering behavior - [#27144](https://github.com/storybookjs/storybook/pull/27144), thanks @shilman!\n- Docs: Fix Subtitle block when no `of` prop passed - [#27147](https://github.com/storybookjs/storybook/pull/27147), thanks @JReinhold!\n- Next.js: Add typing for NextImage to main framework options type - [#27105](https://github.com/storybookjs/storybook/pull/27105), thanks @valentinpalkovic!\n- Next.js: Avoid conflicts with the raw loader - [#27093](https://github.com/storybookjs/storybook/pull/27093), thanks @seanparmelee!\n- Types: Fix typing for main.framework/builder fields - [#27088](https://github.com/storybookjs/storybook/pull/27088), thanks @valentinpalkovic!\n\n## 8.1.0\n\nStorybook 8.1 is here with a tone of new features and bug fixes:\n\n- 🏷️ Static tag-based filtering\n- 🦺 Type-safe, standards-based module mocking\n- 🐣 New `beforeEach` test hook\n- 🧳 Portable Stories API for Playwright Component Testing\n- 🐕‍🦺 Support the new signal-based input & output functions in Angular\n- 2️⃣ Two new ways to create stories: generating them from story controls or from your components directly!\n\n<details>\n<summary>List of all updates</summary>\n\n- Addon-actions: Fix falsy args printing as object - 22163 - [#26917](https://github.com/storybookjs/storybook/pull/26917), thanks @Fatcat560!\n- Addon-docs: Fix MDX compilation with `@vitejs/plugin-react-swc` and plugins - [#26837](https://github.com/storybookjs/storybook/pull/26837), thanks @JReinhold!\n- Addon-docs: Fix `providerImportSource` extension - [#26868](https://github.com/storybookjs/storybook/pull/26868), thanks @bashmish!\n- Addon-docs: Fix `react-dom/server` imports breaking stories and docs - [#26557](https://github.com/storybookjs/storybook/pull/26557), thanks @JReinhold!\n- Addon-docs: Support Stencil based display names in source snippets - [#26592](https://github.com/storybookjs/storybook/pull/26592), thanks @yannbf!\n- Addon-docs: Fix `[Object object]` displayName in some JSX components - [#26566](https://github.com/storybookjs/storybook/pull/26566), thanks @yannbf!\n- Angular: Add type support for Angular\\'s input signals - [#26413](https://github.com/storybookjs/storybook/pull/26413), thanks @valentinpalkovic!\n- Angular: Add type support for Angular\\'s output signals - [#26546](https://github.com/storybookjs/storybook/pull/26546), thanks @valentinpalkovic!\n- API: Add API access to sidebar renderLabel - [#27099](https://github.com/storybookjs/storybook/pull/27099), thanks @shilman!\n- Args: Add possibility to mark controls as read-only - [#26577](https://github.com/storybookjs/storybook/pull/26577), thanks @valentinpalkovic!\n- Automigrations: Fix name of VTA addon - [#26816](https://github.com/storybookjs/storybook/pull/26816), thanks @valentinpalkovic!\n- Automigrations: Add migration note about new react-docgen default - [#26620](https://github.com/storybookjs/storybook/pull/26620), thanks @valentinpalkovic!\n- Automigrations: Fix missing support for mts vite config - [#26441](https://github.com/storybookjs/storybook/pull/26441), thanks @drik98!\n- Automigrations: Improve react-docgen automigration prompt - [#27106](https://github.com/storybookjs/storybook/pull/27106), thanks @valentinpalkovic!\n- Blocks: Add `of` prop to `Subtitle` - [#22552](https://github.com/storybookjs/storybook/pull/22552), thanks @joaonunomota!\n- Blocks: Add `of` prop to `Title` - [#23728](https://github.com/storybookjs/storybook/pull/23728), thanks @Sidnioulz!\n- CLI: Add --config-dir flag to add command - [#26771](https://github.com/storybookjs/storybook/pull/26771), thanks @eric-blue!\n- CLI: Add --config-dir flag to migrate command - [#26721](https://github.com/storybookjs/storybook/pull/26721), thanks @yannbf!\n- CLI: Add main.js `docs.autodocs` automigration - [#27089](https://github.com/storybookjs/storybook/pull/27089), thanks @shilman!\n- CLI: Add Visual Tests addon install auto-migration when upgrading to 8.0.x - [#26766](https://github.com/storybookjs/storybook/pull/26766), thanks @ndelangen!\n- CLI: Automigrate improve upgrade storybook related packages - [#26497](https://github.com/storybookjs/storybook/pull/26497), thanks @ndelangen!\n- CLI: Automigrations copy edits - [#26342](https://github.com/storybookjs/storybook/pull/26342), thanks @joevaugh4n!\n- CLI: Fix eslint configuration for string `extends` - [#27097](https://github.com/storybookjs/storybook/pull/27097), thanks @shilman!\n- CLI: Improve Yarn berry error parsing - [#26616](https://github.com/storybookjs/storybook/pull/26616), thanks @yannbf!\n- CLI: Improve `vite-config-file.ts` - [#26375](https://github.com/storybookjs/storybook/pull/26375), thanks @joevaugh4n!\n- CLI: Instruct the correct auto-migration command - [#26515](https://github.com/storybookjs/storybook/pull/26515), thanks @ndelangen!\n- CLI: Introduce package manager fallback for initializing Storybook in an empty directory with yarn1 - [#26500](https://github.com/storybookjs/storybook/pull/26500), thanks @valentinpalkovic!\n- CLI: Throw an error when running upgrade command in incorrect cwd - [#26585](https://github.com/storybookjs/storybook/pull/26585), thanks @yannbf!\n- Codemods: Escape filename given as argument - [#26430](https://github.com/storybookjs/storybook/pull/26430), thanks @YukiKitagata!\n- Controls: Add Channels API to search for files in the project root - [#26726](https://github.com/storybookjs/storybook/pull/26726), thanks @valentinpalkovic!\n- Controls: Added server channel to create a new story - [#26769](https://github.com/storybookjs/storybook/pull/26769), thanks @valentinpalkovic!\n- Controls: Add UI to create new story files - [#26875](https://github.com/storybookjs/storybook/pull/26875), thanks @valentinpalkovic!\n- Controls: Fix crashing when docgen extraction partially fails - [#26862](https://github.com/storybookjs/storybook/pull/26862), thanks @yannbf!\n- Controls: Fix disable condition in ArgControl component - [#26567](https://github.com/storybookjs/storybook/pull/26567), thanks @valentinpalkovic!\n- Controls: Fix number controls do not reset - [#26372](https://github.com/storybookjs/storybook/pull/26372), thanks @jiyiru!\n- Core: Add `duration` and `onClick` support to Notification API and improve Notification UI - [#26696](https://github.com/storybookjs/storybook/pull/26696), thanks @ghengeveld!\n- Core: Drop unneeded `UPDATE_STORY_ARGS` which was for SSv6 - [#25993](https://github.com/storybookjs/storybook/pull/25993), thanks @tmeasday!\n- Core: Ensure that simultaneous onStoriesChanged don\\'t clobber each other - [#26882](https://github.com/storybookjs/storybook/pull/26882), thanks @tmeasday!\n- Core: Fix filters not being applied in WebKit - [#26949](https://github.com/storybookjs/storybook/pull/26949), thanks @JReinhold!\n- Core: Fix preloading too early - [#26442](https://github.com/storybookjs/storybook/pull/26442), thanks @ndelangen!\n- Core: Implement file formatter - [#26809](https://github.com/storybookjs/storybook/pull/26809), thanks @valentinpalkovic!\n- Core: Optimize clearNotification - [#26415](https://github.com/storybookjs/storybook/pull/26415), thanks @ndelangen!\n- Core: Save from controls - [#26827](https://github.com/storybookjs/storybook/pull/26827), thanks @ndelangen!\n- CSF: Allow default export without title or component attributes - [#26516](https://github.com/storybookjs/storybook/pull/26516), thanks @kasperpeulen!\n- CSF: Fix typings for control and other properties of argTypes - [#26824](https://github.com/storybookjs/storybook/pull/26824), thanks @kasperpeulen!\n- CSF: Make sure loaders/decorators can be used as array - [#26514](https://github.com/storybookjs/storybook/pull/26514), thanks @kasperpeulen!\n- Dependencies: Upgrade @storybook/csf to 0.1.5 - [#26958](https://github.com/storybookjs/storybook/pull/26958), thanks @Cherry!\n- Dependencies: Upgrade `@joshwooding/vite-plugin-react-docgen-typescript` to `0.3.1` - [#26673](https://github.com/storybookjs/storybook/pull/26673), thanks @joshwooding!\n- Dependencies: Upgrade `ejs` to `3.1.10` - [#27054](https://github.com/storybookjs/storybook/pull/27054), thanks @RiuSalvi!\n- Dependencies: Bump es-module-lexer - [#26737](https://github.com/storybookjs/storybook/pull/26737), thanks @valentinpalkovic!\n- Dependencies: Update globby dependency - [#26733](https://github.com/storybookjs/storybook/pull/26733), thanks @valentinpalkovic!\n- Dependencies: Update postcss-loader in Next.js framework - [#26707](https://github.com/storybookjs/storybook/pull/26707), thanks @valentinpalkovic!\n- Doc Tools: Signature Type Error Handling - [#26774](https://github.com/storybookjs/storybook/pull/26774), thanks @ethriel3695!\n- Indexer: Escape special characters in storyImport regex - [#22545](https://github.com/storybookjs/storybook/pull/22545), thanks @VojGin!\n- Maintenance: Fix performance regressions - [#26411](https://github.com/storybookjs/storybook/pull/26411), thanks @kasperpeulen!\n- MDX: Do not transform `http://` links - [#26488](https://github.com/storybookjs/storybook/pull/26488), thanks @JReinhold!\n- Next.js: Fix Compatibility with <v14.0.4 - [#27082](https://github.com/storybookjs/storybook/pull/27082), thanks @JReinhold!\n- Next.js: Fix next/font usage on Windows machines - [#26700](https://github.com/storybookjs/storybook/pull/26700), thanks @valentinpalkovic!\n- Next.js: Move sharp into optional deps - [#26787](https://github.com/storybookjs/storybook/pull/26787), thanks @shuta13!\n- Next.js: Support v14.2 useParams functionality - [#26874](https://github.com/storybookjs/storybook/pull/26874), thanks @yannbf!\n- Next.js: Implement next redirect and the RedirectBoundary - [#27050](https://github.com/storybookjs/storybook/pull/27050), thanks @yannbf!\n- Next.js: Support path aliases when no base url is set - [#26651](https://github.com/storybookjs/storybook/pull/26651), thanks @yannbf!\n- Node: Safe use of `document` for preview - [#24248](https://github.com/storybookjs/storybook/pull/24248), thanks @DylanPiercey!\n- Onboarding: Improve UI - [#27074](https://github.com/storybookjs/storybook/pull/27074), thanks @ndelangen!\n- Portable stories: Introduce experimental Playwright CT API and Support for more renderers - [#26063](https://github.com/storybookjs/storybook/pull/26063), thanks @yannbf!\n- Portable stories: Make setProjectAnnotations accept multiple types of imports - [#26316](https://github.com/storybookjs/storybook/pull/26316), thanks @yannbf!\n- Portable Stories: Remove link to missing docs - [#27075](https://github.com/storybookjs/storybook/pull/27075), thanks @JReinhold!\n- Portable Stories: Warn when rendering stories without cleaning up first - [#27008](https://github.com/storybookjs/storybook/pull/27008), thanks @JReinhold!\n- React-Docgen: Make sure to be able to handle empty unions - [#26639](https://github.com/storybookjs/storybook/pull/26639), thanks @kasperpeulen!\n- React: Support v19 betas in peer dependencies - [#26960](https://github.com/storybookjs/storybook/pull/26960), thanks @JReinhold!\n- React: Support v19 in `react-dom-shim` - [#26898](https://github.com/storybookjs/storybook/pull/26898), thanks @Tobbe!\n- Tags: Add project tags, negation, `dev`/`autodocs`/`test` system tags - [#26634](https://github.com/storybookjs/storybook/pull/26634), thanks @shilman!\n- Tags: Fix missing default tags if no `preview.js` - [#27098](https://github.com/storybookjs/storybook/pull/27098), thanks @shilman!\n- Test: Add @storybook/test as dev dependency - [#26458](https://github.com/storybookjs/storybook/pull/26458), thanks @arnabsen!\n- Test: Make spies reactive so that they can be logged by addon-actions - [#26740](https://github.com/storybookjs/storybook/pull/26740), thanks @kasperpeulen!\n- Test: Remove chai as dependency of @storybook/test - [#26852](https://github.com/storybookjs/storybook/pull/26852), thanks @kasperpeulen!\n- Test: Support module mocking with conditional subpath imports in `package.json` - [#26688](https://github.com/storybookjs/storybook/pull/26688), thanks @kasperpeulen!\n- Theming: Update emotion dependencies - [#26623](https://github.com/storybookjs/storybook/pull/26623), thanks @SimenB!\n- Typescript: Add types for `experimental-playwright` entries without `type:bundler` - [#27107](https://github.com/storybookjs/storybook/pull/27107), thanks @ndelangen!\n- UI: Add key property to list children in Highlight component - [#26471](https://github.com/storybookjs/storybook/pull/26471), thanks @valentinpalkovic!\n- UI: Fix not re-rendering tabs on state change - [#26899](https://github.com/storybookjs/storybook/pull/26899), thanks @lifeiscontent!\n- UI: Fix panel layout resizing do not apply when done too fast - [#26460](https://github.com/storybookjs/storybook/pull/26460), thanks @jorge-ji!\n- UI: Fix search result color contrast - [#26287](https://github.com/storybookjs/storybook/pull/26287), thanks @winchesHe!\n- UI: Fix sidebar search hanging when selecting a story in touch mode - [#26807](https://github.com/storybookjs/storybook/pull/26807), thanks @JReinhold!\n- UI: Fix theming of elements inside bars - [#26527](https://github.com/storybookjs/storybook/pull/26527), thanks @valentinpalkovic!\n- UI: Improve empty state of addon panel - [#26481](https://github.com/storybookjs/storybook/pull/26481), thanks @yannbf!\n- UI: Replace the icon prop in the Manager API - [#26477](https://github.com/storybookjs/storybook/pull/26477), thanks @cdedreuille!\n- Viewport: Fix missing style - [#26530](https://github.com/storybookjs/storybook/pull/26530), thanks @jpzwarte!\n- Vite: Merge assetsInclude property with Storybook default values - [#26860](https://github.com/storybookjs/storybook/pull/26860), thanks @yuemori!\n- Vue: Disable controls for events, slots, and expose - [#26751](https://github.com/storybookjs/storybook/pull/26751), thanks @shilman!\n- Webpack: Bump webpack-dev-middleware to patch high security issue - [#26655](https://github.com/storybookjs/storybook/pull/26655), thanks @jwilliams-met!\n- Webpack: Fix sourcemap generation in webpack react-docgen-loader - [#26676](https://github.com/storybookjs/storybook/pull/26676), thanks @valentinpalkovic!\n- Webpack: Hide runtime errors - [#23175](https://github.com/storybookjs/storybook/pull/23175), thanks @donaldpipowitch!\n</details>\n\n## 8.0.10\n\n- MDX: Don't transform `http://` links - [#26488](https://github.com/storybookjs/storybook/pull/26488), thanks @JReinhold!\n- React: Support v19 in `react-dom-shim` - [#26898](https://github.com/storybookjs/storybook/pull/26898), thanks @Tobbe!\n- Vite: Merge assetsInclude property with Storybook default values - [#26860](https://github.com/storybookjs/storybook/pull/26860), thanks @yuemori!\n\n## 8.0.9\n\n- Addon-docs: Fix MDX compilation when using `@vitejs/plugin-react-swc` with plugins - [#26837](https://github.com/storybookjs/storybook/pull/26837), thanks @JReinhold!\n- CSF: Fix typings for control and other properties of argTypes - [#26824](https://github.com/storybookjs/storybook/pull/26824), thanks @kasperpeulen!\n- Controls: Fix crashing when docgen extraction partially fails - [#26862](https://github.com/storybookjs/storybook/pull/26862), thanks @yannbf!\n- Doc Tools: Signature Type Error Handling - [#26774](https://github.com/storybookjs/storybook/pull/26774), thanks @ethriel3695!\n- Next.js: Move sharp into optional deps - [#26787](https://github.com/storybookjs/storybook/pull/26787), thanks @shuta13!\n- Nextjs: Support next 14.2 useParams functionality - [#26874](https://github.com/storybookjs/storybook/pull/26874), thanks @yannbf!\n- Test: Remove chai as dependency of @storybook/test - [#26852](https://github.com/storybookjs/storybook/pull/26852), thanks @kasperpeulen!\n- UI: Fix sidebar search hanging when selecting a story in touch mode - [#26807](https://github.com/storybookjs/storybook/pull/26807), thanks @JReinhold!\n\n## 8.0.8\n\n- Automigration: Fix name of VTA addon - [#26816](https://github.com/storybookjs/storybook/pull/26816), thanks @valentinpalkovic!\n\n## 8.0.7\n\n- CLI: Add Visual Tests addon install auto-migration when upgrading to 8.0.x - [#26766](https://github.com/storybookjs/storybook/pull/26766), thanks @ndelangen!\n- Next.js: Move sharp into optional deps - [#26787](https://github.com/storybookjs/storybook/pull/26787), thanks @shuta13!\n- Vue: Disable controls for events, slots, and expose - [#26751](https://github.com/storybookjs/storybook/pull/26751), thanks @shilman!\n- Webpack: Bump webpack-dev-middleware to patch high security issue - [#26655](https://github.com/storybookjs/storybook/pull/26655), thanks @jwilliams-met!\n\n## 8.0.6\n\n- CLI: Add --config-dir flag to migrate command - [#26721](https://github.com/storybookjs/storybook/pull/26721), thanks @yannbf!\n- Next.js: Fix next/font usage on Windows machines - [#26700](https://github.com/storybookjs/storybook/pull/26700), thanks @valentinpalkovic!\n- Next.js: Support path aliases when no base url is set - [#26651](https://github.com/storybookjs/storybook/pull/26651), thanks @yannbf!\n- Webpack: Fix sourcemap generation in webpack react-docgen-loader - [#26676](https://github.com/storybookjs/storybook/pull/26676), thanks @valentinpalkovic!\n\n## 8.0.5\n\n- Addon-docs: Fix `react-dom/server` imports breaking stories and docs - [#26557](https://github.com/storybookjs/storybook/pull/26557), thanks @JReinhold!\n- Automigrations: Fix missing support for mts vite config - [#26441](https://github.com/storybookjs/storybook/pull/26441), thanks @drik98!\n- CLI: Improve Yarn berry error parsing - [#26616](https://github.com/storybookjs/storybook/pull/26616), thanks @yannbf!\n- React-Docgen: Make sure to be able to handle empty unions - [#26639](https://github.com/storybookjs/storybook/pull/26639), thanks @kasperpeulen!\n- Viewport: Fix missing style - [#26530](https://github.com/storybookjs/storybook/pull/26530), thanks @jpzwarte!\n\n## 8.0.4\n\n- Addon Docs: Support Stencil based display names in source snippets - [#26592](https://github.com/storybookjs/storybook/pull/26592), thanks @yannbf!\n- CLI: Instruct the correct auto-migration command - [#26515](https://github.com/storybookjs/storybook/pull/26515), thanks @ndelangen!\n- CLI: Throw an error when running upgrade command in incorrect cwd - [#26585](https://github.com/storybookjs/storybook/pull/26585), thanks @yannbf!\n\n## 8.0.3\n\n- Bug: Remove redundant component check, as we auto-generate titles from the file system - [#26516](https://github.com/storybookjs/storybook/pull/26516), thanks @kasperpeulen!\n- UI: Replace the icon prop in the Manager API - [#26477](https://github.com/storybookjs/storybook/pull/26477), thanks @cdedreuille!\n\n## 8.0.2\n\n- Addon Docs: Fix [Object object] displayName in some JSX components - [#26566](https://github.com/storybookjs/storybook/pull/26566), thanks @yannbf!\n- CLI: Add yarn1 package manager fallback for init in empty directory - [#26500](https://github.com/storybookjs/storybook/pull/26500), thanks @valentinpalkovic!\n- CSF: Make sure loaders/decorators can be used as array - [#26514](https://github.com/storybookjs/storybook/pull/26514), thanks @kasperpeulen!\n- Controls: Fix disable condition in ArgControl component - [#26567](https://github.com/storybookjs/storybook/pull/26567), thanks @valentinpalkovic!\n- UI: Add key property to list children in Highlight component - [#26471](https://github.com/storybookjs/storybook/pull/26471), thanks @valentinpalkovic!\n- UI: Fix theming of elements inside bars - [#26527](https://github.com/storybookjs/storybook/pull/26527), thanks @valentinpalkovic!\n- UI: Improve empty state of addon panel - [#26481](https://github.com/storybookjs/storybook/pull/26481), thanks @yannbf!\n\n## 8.0.1\n\n- Controls: Fix type summary when table.type unset - [#26283](https://github.com/storybookjs/storybook/pull/26283), thanks @shilman!\n- Core: Fix addon bundling script - [#26145](https://github.com/storybookjs/storybook/pull/26145), thanks @ndelangen!\n- Core: Fix fail to load `main.ts` error message - [#26035](https://github.com/storybookjs/storybook/pull/26035), thanks @ndelangen!\n- Maintenance: Fix performance regressions - [#26411](https://github.com/storybookjs/storybook/pull/26411), thanks @kasperpeulen!\n\n## 8.0.0\n\n#### Storybook 8.0 is here\n\nIt brings major improvements to Storybook's feature set for testing and documentation, with strengthened framework support across React, Vue, Angular, web-components, Svelte, and more.\n\n- 🩻 Built-in visual testing\n- ⚛️ React Server Component support\n- 🎛️ Improved controls for React and Vue projects\n- ⚡️ Improved Vite architecture, Vitest testing, and Vite 5 support\n- 🧪 2-4x faster Storybooks for testing\n- ✨ Refreshed desktop UI\n- 📲 Rebuilt mobile UX\n- 🙅‍♀️ No more React requirement in non-React projects\n\nPlease checkout our [Migration Guide](https://storybook.js.org/docs/8.0/migration-guide) to upgrade from earlier versions of Storybook. To see a comprehensive list of changes that went into 8.0, you can refer to the [8.0 prerelease changelogs](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.prerelease.md).\n\n## 7.6.17\n\n- Addon-docs: Fix Table of Contents heading leak - [#23677](https://github.com/storybookjs/storybook/pull/23677), thanks [@vmizg](https://github.com/vmizg)!\n- Core: Update ip version to fix CVE-2023-42282 - [#26086](https://github.com/storybookjs/storybook/pull/26086), thanks [@drik98](https://github.com/drik98)!\n\n## 7.6.16\n\n- Addon Themes: Make type generic less strict - [#26042](https://github.com/storybookjs/storybook/pull/26042), thanks [@yannbf](https://github.com/yannbf)!\n- Interaction: Make sure that adding spies doesn't cause infinite loops with self referencing args [#26019](https://github.com/storybookjs/storybook/pull/26019), thanks @kasperpeulen!\n\n## 7.6.15\n\nThis release accidentally didn't contain anything.\n\n## 7.6.14\n\n- Core: Fix boolean `true` args in URL getting ignored - [#25950](https://github.com/storybookjs/storybook/pull/25950), thanks [@JReinhold](https://github.com/JReinhold)!\n\n## 7.6.13\n\n- Next.js: Fix frameworkOptions resolution - [#25907](https://github.com/storybookjs/storybook/pull/25907), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- React Native: Fix init fails when package is already installed - [#25908](https://github.com/storybookjs/storybook/pull/25908), thanks [@dannyhw](https://github.com/dannyhw)!\n- React Native: Remove watcher from init - [#25895](https://github.com/storybookjs/storybook/pull/25895), thanks [@dannyhw](https://github.com/dannyhw)!\n- Webpack: Update StorybookConfig import in core-webpack types.ts - [#25740](https://github.com/storybookjs/storybook/pull/25740), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n\n## 7.6.12\n\n- CLI: Fix `upgrade` detecting the wrong version of existing Storybooks - [#25752](https://github.com/storybookjs/storybook/pull/25752), thanks [@JReinhold](https://github.com/JReinhold)!\n\n## 7.6.11\n\n- CLI: Update init for react native v7 - [#25780](https://github.com/storybookjs/storybook/pull/25780), thanks [@dannyhw](https://github.com/dannyhw)!\n- Codemods: Add support for multiple file extensions in runCodemod function - [#25708](https://github.com/storybookjs/storybook/pull/25708), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n\n## 7.6.10\n\n- CLI: Fix existing version detection in `upgrade` - [#25642](https://github.com/storybookjs/storybook/pull/25642), thanks [@JReinhold](https://github.com/JReinhold)!\n- React: Fix acorn ecma version warning - [#25634](https://github.com/storybookjs/storybook/pull/25634), thanks [@dannyhw](https://github.com/dannyhw)!\n\n## 7.6.9\n\n- ConfigFile: Fix export specifiers - [#25590](https://github.com/storybookjs/storybook/pull/25590), thanks [@shilman](https://github.com/shilman)!\n- Webpack5: Make export-order-loader compatible with both esm and cjs - [#25540](https://github.com/storybookjs/storybook/pull/25540), thanks [@mlazari](https://github.com/mlazari)!\n- CLI: Support version specifiers in `init`, `upgrade` and `sandbox` - [#25526](https://github.com/storybookjs/storybook/pull/25526), thanks [@ndelangen](https://github.com/ndelangen), [@jreinhold](https://github.com/jreinhold)!\n\n## 7.6.8\n\n- Addon-actions: Fix module resolution for react-native - [#25296](https://github.com/storybookjs/storybook/pull/25296), thanks [@dannyhw](https://github.com/dannyhw)!\n- Storysource: Fix import error - [#25391](https://github.com/storybookjs/storybook/pull/25391), thanks [@unional](https://github.com/unional)!\n\n## 7.6.7\n\n- Core: Skip no-framework error when ignorePreview=true - [#25286](https://github.com/storybookjs/storybook/pull/25286), thanks [@ndelangen](https://github.com/ndelangen)!\n- Dependencies: Semver dependency fixes - [#25283](https://github.com/storybookjs/storybook/pull/25283), thanks [@ndelangen](https://github.com/ndelangen)!\n- Vite: Fix pre-transform error in Vite 5 - [#25329](https://github.com/storybookjs/storybook/pull/25329), thanks [@yannbf](https://github.com/yannbf)!\n- Vue3: Fix pnp by making compiler-core a dependency - [#25311](https://github.com/storybookjs/storybook/pull/25311), thanks [@shilman](https://github.com/shilman)!\n\n## 7.6.6\n\n- SvelteKit: Support 2.0 modules with mocks - [#25244](https://github.com/storybookjs/storybook/pull/25244), thanks [@paoloricciuti](https://github.com/paoloricciuti)!\n\n## 7.6.5\n\n- Angular: Update Angular cli templates - [#25152](https://github.com/storybookjs/storybook/pull/25152), thanks [@Marklb](https://github.com/Marklb)!\n- Blocks: Fix Subtitle block for unattached docs pages - [#25157](https://github.com/storybookjs/storybook/pull/25157), thanks [@kripod](https://github.com/kripod)!\n- SvelteKit: Fix missing `$app` modules - [#25132](https://github.com/storybookjs/storybook/pull/25132), thanks [@paoloricciuti](https://github.com/paoloricciuti)!\n\n## 7.6.4\n\n- Angular: Fix CSF Plugin - [#25098](https://github.com/storybookjs/storybook/pull/25098), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Viewport: Fix viewport dts files - [#25107](https://github.com/storybookjs/storybook/pull/25107), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n\n## 7.6.3\n\n- Next.js: Fix next/font/local usage in babel mode - [#25045](https://github.com/storybookjs/storybook/pull/25045), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n\n## 7.6.2\n\n- CLI: Improve dependency metadata detection in storybook doctor - [#25037](https://github.com/storybookjs/storybook/pull/25037), thanks [@yannbf](https://github.com/yannbf)!\n- React-Docgen: Make error-handling more gentle - [#25055](https://github.com/storybookjs/storybook/pull/25055), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n\n## 7.6.1\n\n- Next.js: Fix AppRouterProvider usage - [#25032](https://github.com/storybookjs/storybook/pull/25032), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- SvelteKit: Fix HMR not working - [#25031](https://github.com/storybookjs/storybook/pull/25031), thanks [@JReinhold](https://github.com/JReinhold)!\n- Test: Downgrade @testing-library/user-event to 14.3.0 - [#25004](https://github.com/storybookjs/storybook/pull/25004), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Webpack: Fix exclude regex in react-docgen-loader - [#25030](https://github.com/storybookjs/storybook/pull/25030), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n\n## 7.6.0\n\nStorybook 7.6 is here with increased performance and much more!\n\n- 🔥 Improved SWC support\n- 🧪 New test utilities and fast build mode\n- 🔼 NextJS SWC + avif support & fixes\n- 🤡 SvelteKit page and navigation mocking\n- ⚛️ React-docgen upgrade\n- 🎨 Controls a11y, background theming, and viewports\n- 🩺 CLI: The doctor is in!\n- 🚫 Addons: Remove React as a peer dependency\n- 🪦 Storyshots and Vue2 deprecated\n\n<details>\n  <summary>\n    List of all updates\n  </summary>\n\n- Actions: Attach spies on actions across stories when defined in meta - [#24451](https://github.com/storybookjs/storybook/pull/24451), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Actions: Fix `@storybook/core-events/preview-errors` dependency missing for Yarn PnP - [#24973](https://github.com/storybookjs/storybook/pull/24973), thanks [@JReinhold](https://github.com/JReinhold)!\n- Actions: Fix missing crypto module crashing React Native - [#24546](https://github.com/storybookjs/storybook/pull/24546), thanks [@dannyhw](https://github.com/dannyhw)!\n- Actions: Warn on implicit actions - [#24856](https://github.com/storybookjs/storybook/pull/24856), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Addon A11y: Avoid CSP issue - [#24477](https://github.com/storybookjs/storybook/pull/24477), thanks [@Marklb](https://github.com/Marklb)!\n- Addon: Move Visual Test addon to the code directory - [#24771](https://github.com/storybookjs/storybook/pull/24771), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- Addons, core: Make `react` and Storybook packages `devDependencies` where possible - [#24676](https://github.com/storybookjs/storybook/pull/24676), thanks [@JReinhold](https://github.com/JReinhold)!\n- Addons, core: Make `react` and Storybook packages `devDependencies` where possible - ATTEMPT 2 - [#24834](https://github.com/storybookjs/storybook/pull/24834), thanks [@JReinhold](https://github.com/JReinhold)!\n- Angular: Add source-map option to builder - [#24466](https://github.com/storybookjs/storybook/pull/24466), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Angular: Handle nested module metadata - [#24798](https://github.com/storybookjs/storybook/pull/24798), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Angular: Include object configured styles - [#24768](https://github.com/storybookjs/storybook/pull/24768), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Babel: Update all @babel/\\* dependencies - [#24610](https://github.com/storybookjs/storybook/pull/24610), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- CLI: Add \"doctor\" command - [#22236](https://github.com/storybookjs/storybook/pull/22236), thanks [@yannbf](https://github.com/yannbf)!\n- CLI: Add @storybook/addon-designs to non-core list - [#24507](https://github.com/storybookjs/storybook/pull/24507), thanks [@yannbf](https://github.com/yannbf)!\n- CLI: Ensure errors with opening the browser are caught - [#24668](https://github.com/storybookjs/storybook/pull/24668), thanks [@xueyawei](https://github.com/xueyawei)!\n- CLI: Ignore `addon-onboarding` when checking versions - [#24634](https://github.com/storybookjs/storybook/pull/24634), thanks [@JReinhold](https://github.com/JReinhold)!\n- CLI: Use @storybook/test in template stories - [#24393](https://github.com/storybookjs/storybook/pull/24393), thanks [@yannbf](https://github.com/yannbf)!\n- Controls: Improve accessibility of BooleanControl for screen readers - [#24418](https://github.com/storybookjs/storybook/pull/24418), thanks [@danielmarcano](https://github.com/danielmarcano)!\n- Core-Server: Ignore all node_module folders for watchpack - [#24553](https://github.com/storybookjs/storybook/pull/24553), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Core: Add deprecation notice for Vite + CommonJS - [#23950](https://github.com/storybookjs/storybook/pull/23950), thanks [@JReinhold](https://github.com/JReinhold)!\n- Core: Detect no matching export error in storybook start and build - [#24877](https://github.com/storybookjs/storybook/pull/24877), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Fix `useStoryPrepared` hook failing with `undefined` data - [#22631](https://github.com/storybookjs/storybook/pull/22631), thanks [@SpookyJelly](https://github.com/SpookyJelly)!\n- Core: Fix pnp support when cache dir is outside working dir - [#24572](https://github.com/storybookjs/storybook/pull/24572), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Core: Fix post message channel location.search access for React Native - [#24545](https://github.com/storybookjs/storybook/pull/24545), thanks [@dannyhw](https://github.com/dannyhw)!\n- Core: Gracefully handle error when parsing preview.js file - [#24858](https://github.com/storybookjs/storybook/pull/24858), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Make warnOnIncompatibleAddons fault-tolerant - [#24880](https://github.com/storybookjs/storybook/pull/24880), thanks [@taozhou-glean](https://github.com/taozhou-glean)!\n- Dependencies: Fix Yarn 4 failing to install due to jscodeshift dependency issue - [#24914](https://github.com/storybookjs/storybook/pull/24914), thanks [@samvv](https://github.com/samvv)!\n- Dependencies: Update @babel/traverse and @babel/core to fix vulnerability - [#24670](https://github.com/storybookjs/storybook/pull/24670), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Dependencies: Update browserify-sign transitive dependency - [#24674](https://github.com/storybookjs/storybook/pull/24674), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Dependencies: Update jscodeshift to v0.15.1 - [#24882](https://github.com/storybookjs/storybook/pull/24882), thanks [@epreston](https://github.com/epreston)!\n- Dependencies: Update nx dependencies to v17 - [#24671](https://github.com/storybookjs/storybook/pull/24671), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Doc Blocks: Add support for `of` prop to `Primary` block - [#23849](https://github.com/storybookjs/storybook/pull/23849), thanks [@Wilson2k](https://github.com/Wilson2k)!\n- Doc Blocks: Remove `defaultProps` in `Stories` block - [#24506](https://github.com/storybookjs/storybook/pull/24506), thanks [@WouterK12](https://github.com/WouterK12)!\n- Docs: Changes corresponding to docs design updates - [#24925](https://github.com/storybookjs/storybook/pull/24925), thanks [@kylegach](https://github.com/kylegach)!\n- Maintenance: Split renderers preview entrypoints - [#24623](https://github.com/storybookjs/storybook/pull/24623), thanks [@ndelangen](https://github.com/ndelangen)!\n- Manager: Update `store.settings.lastTrackedStoryId` - [#24115](https://github.com/storybookjs/storybook/pull/24115), thanks [@rashidshamloo](https://github.com/rashidshamloo)!\n- ManagerAPI: Fix setting status without index, crashes storybook - [#24866](https://github.com/storybookjs/storybook/pull/24866), thanks [@ndelangen](https://github.com/ndelangen)!\n- ManagerBuilder: Fix `\"type\": \"commonjs\"` compatibility - [#24534](https://github.com/storybookjs/storybook/pull/24534), thanks [@ndelangen](https://github.com/ndelangen)!\n- Next.js: Add avif support - [#24611](https://github.com/storybookjs/storybook/pull/24611), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Next.js: Add back image context CommonJS export - [#24885](https://github.com/storybookjs/storybook/pull/24885), thanks [@martinnabhan](https://github.com/martinnabhan)!\n- Next.js: Add experimental SWC support - [#24852](https://github.com/storybookjs/storybook/pull/24852), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Next.js: Fix Fast Refresh config for SWC mode - [#24991](https://github.com/storybookjs/storybook/pull/24991), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Next.js: Fix forwarding ref for Image component - [#24648](https://github.com/storybookjs/storybook/pull/24648), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Next.js: Fix import path in swc loader - [#24922](https://github.com/storybookjs/storybook/pull/24922), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Next.js: Fix react-docgen usage with preset-env settings - [#24993](https://github.com/storybookjs/storybook/pull/24993), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Next.js: Remove duplicate Fast Refresh plugin init - [#24963](https://github.com/storybookjs/storybook/pull/24963), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- React: Upgrade `react-docgen` to v7 - [#24530](https://github.com/storybookjs/storybook/pull/24530), thanks [@shilman](https://github.com/shilman)!\n- ReactNative: Fix missing assert dep in docs-tools - [#24732](https://github.com/storybookjs/storybook/pull/24732), thanks [@dannyhw](https://github.com/dannyhw)!\n- Svelte: Fix decorators always running twice - [#24921](https://github.com/storybookjs/storybook/pull/24921), thanks [@paoloricciuti](https://github.com/paoloricciuti)!\n- Svelte: Fix source with decorators always showing the `SlotDecorator` component - [#24800](https://github.com/storybookjs/storybook/pull/24800), thanks [@JReinhold](https://github.com/JReinhold)!\n- SvelteKit: Add experimental page and navigation mocking - [#24795](https://github.com/storybookjs/storybook/pull/24795), thanks [@paoloricciuti](https://github.com/paoloricciuti)!\n- SvelteKit: Default to log an action for `goto`, `invalidate` and `invalidateAll` - [#24955](https://github.com/storybookjs/storybook/pull/24955), thanks [@paoloricciuti](https://github.com/paoloricciuti)!\n- SWC: Add settings for react and preact - [#24805](https://github.com/storybookjs/storybook/pull/24805), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Test Build: Add env-variable support to `--test` CLI-flag - [#24862](https://github.com/storybookjs/storybook/pull/24862), thanks [@ndelangen](https://github.com/ndelangen)!\n- Test Build: Add tests and rename to camelCase - [#24911](https://github.com/storybookjs/storybook/pull/24911), thanks [@ndelangen](https://github.com/ndelangen)!\n- Test Build: Disable composition when `--test` is `true` - [#24799](https://github.com/storybookjs/storybook/pull/24799), thanks [@ndelangen](https://github.com/ndelangen)!\n- Test Build: Disable docs related stuff for test builds - [#24691](https://github.com/storybookjs/storybook/pull/24691), thanks [@ndelangen](https://github.com/ndelangen)!\n- Test Build: Disable telemetry for test builds - [#24706](https://github.com/storybookjs/storybook/pull/24706), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Test Build: Disable warnOnIncompatibleAddons - [#24797](https://github.com/storybookjs/storybook/pull/24797), thanks [@ndelangen](https://github.com/ndelangen)!\n- Test Build: Filter out addon-docs from essentials in the test build - [#24994](https://github.com/storybookjs/storybook/pull/24994), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Test Build: Fix disabledAddons filter - [#24924](https://github.com/storybookjs/storybook/pull/24924), thanks [@IanVS](https://github.com/IanVS)!\n- Test Build: Fix indexer bug - [#24890](https://github.com/storybookjs/storybook/pull/24890), thanks [@ndelangen](https://github.com/ndelangen)!\n- Test Build: Globalize `@storybook/blocks` if `build.test.emptyBlocks` is `true` - [#24650](https://github.com/storybookjs/storybook/pull/24650), thanks [@ndelangen](https://github.com/ndelangen)!\n- Test Build: Implement builder options for test build - [#24826](https://github.com/storybookjs/storybook/pull/24826), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Test Build: Improve config loading & naming - [#24837](https://github.com/storybookjs/storybook/pull/24837), thanks [@ndelangen](https://github.com/ndelangen)!\n- Test Build: No sourcemaps for test builds - [#24804](https://github.com/storybookjs/storybook/pull/24804), thanks [@ndelangen](https://github.com/ndelangen)!\n- Test Build: Revert defaulting to SWC in test build, but keep using esbuild for minification - [#24843](https://github.com/storybookjs/storybook/pull/24843), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Test: Create @storybook/test package based on vitest - [#24392](https://github.com/storybookjs/storybook/pull/24392), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Test: Don\\'t attach action to function mock if action was added already - [#24966](https://github.com/storybookjs/storybook/pull/24966), thanks [@tmeasday](https://github.com/tmeasday)!\n- Test: Model loaders as before each and restore mocks properly - [#24948](https://github.com/storybookjs/storybook/pull/24948), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Theming: Add theme variable to set the preview background color - [#24575](https://github.com/storybookjs/storybook/pull/24575), thanks [@JReinhold](https://github.com/JReinhold)!\n- Typescript: Add \\'skipCompiler\\' option to TypeScript presets - [#24847](https://github.com/storybookjs/storybook/pull/24847), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- UI: Fix horizontal scroll bar in Canvas hidden by styling - [#24408](https://github.com/storybookjs/storybook/pull/24408), thanks [@yoshi2no](https://github.com/yoshi2no)!\n- UI: improve A11Y remove redundant styling rules, update icon color - [#24402](https://github.com/storybookjs/storybook/pull/24402), thanks [@tolkadot](https://github.com/tolkadot)!\n- UI: Logo fixed value - [#24726](https://github.com/storybookjs/storybook/pull/24726), thanks [@black-arm](https://github.com/black-arm)!\n- UI: Update zIndex on NotificationList to fix the notification not being clickable in certain cases - [#24602](https://github.com/storybookjs/storybook/pull/24602), thanks [@yoshi2no](https://github.com/yoshi2no)!\n- Viewport: Add newer device viewports - [#24777](https://github.com/storybookjs/storybook/pull/24777), thanks [@Tomo5524](https://github.com/Tomo5524)!\n- Vite: Prevent non-deterministic build output - [#24833](https://github.com/storybookjs/storybook/pull/24833), thanks [@henkerik](https://github.com/henkerik)!\n- Webpack: Add export-order-loader and remove babel-plugin-named-exports-order - [#24749](https://github.com/storybookjs/storybook/pull/24749), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Webpack: Add react-docgen loader and remove babel-plugin-react-docgen - [#24762](https://github.com/storybookjs/storybook/pull/24762), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Webpack: Fix race condition for export-order loader - [#24817](https://github.com/storybookjs/storybook/pull/24817), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Webpack: Hide critical dependency warning - [#24784](https://github.com/storybookjs/storybook/pull/24784), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Webpack: Only load babel config when babel-loader is used - [#25002](https://github.com/storybookjs/storybook/pull/25002), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Webpack: Resolve circular dependency and fix HMR - [#24974](https://github.com/storybookjs/storybook/pull/24974), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n</details>\n\n## 7.5.2\n\n- Addon-themes: Fix globals not being set when using absolute path - [#24596](https://github.com/storybookjs/storybook/pull/24596), thanks [@JReinhold](https://github.com/JReinhold)!\n- CLI: Allow Yarn v4 in `link` command - [#24551](https://github.com/storybookjs/storybook/pull/24551), thanks [@yannbf](https://github.com/yannbf)!\n- Next.js: Support v14.0.0 - [#24593](https://github.com/storybookjs/storybook/pull/24593), thanks [@nikospapcom](https://github.com/nikospapcom)!\n\n## 7.5.1\n\n- Angular: update wrong type for webpackStatsJson in start-storybook schema.json - [#24494](https://github.com/storybookjs/storybook/pull/24494), thanks [@LucaVazz](https://github.com/LucaVazz)!\n- Themes: Run postinstall in shell for windows - [#24389](https://github.com/storybookjs/storybook/pull/24389), thanks [@Integrayshaun](https://github.com/Integrayshaun)!\n\n## 7.5.0\n\nStorybook 7.5 enhances your Storybook experience with several key updates:\n\n- 💃🏼 Now supports Lit 3.0 and Vite 5\n- 👻 storiesOf and storyStoreV6 officially deprecated\n- 🔨 Fix Webpack5 build errors not being propagated\n- 🀄 Support rename font import for Next.js\n- ⬆️ Upgrade react-docgen to 6.0.x and improve argTypes\n- ✨ Many Angular improvements such as introducing argsToTemplate , new schema debugging options, support for standalone directives, etc.\n<details>\n  <summary>\n    List of all updates\n  </summary>\n\n- Angular: Introduce argsToTemplate for property and event Bindings - [#24434](https://github.com/storybookjs/storybook/pull/24434), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Angular: Add schema options (debugWebpack, webpackStatsJson, and more) - [#24388](https://github.com/storybookjs/storybook/pull/24388), thanks [@yannbf](https://github.com/yannbf)!\n- Angular: Categorize legacy build options error - [#24014](https://github.com/storybookjs/storybook/pull/24014), thanks [@yannbf](https://github.com/yannbf)!\n- Angular: Fix Angular 15 support and add zone.js v0.14.x support - [#24367](https://github.com/storybookjs/storybook/pull/24367), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Angular: Allow loading standalone directives - [#24448](https://github.com/storybookjs/storybook/pull/24448), thanks [@osnoser1](https://github.com/osnoser1)!\n- CLI: Inform the user how to dedupe and strip color from info command - [#24087](https://github.com/storybookjs/storybook/pull/24087), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- CLI: Add more information to storybook info command - [#24003](https://github.com/storybookjs/storybook/pull/24003), thanks [@JReinhold](https://github.com/JReinhold)!\n- CLI: Change /Date$/ to /Dates$/i - [#24195](https://github.com/storybookjs/storybook/pull/24195), thanks [@arup1221](https://github.com/arup1221)!\n- CLI: Improve sanitization logic in crash reports - [#24028](https://github.com/storybookjs/storybook/pull/24028), thanks [@yannbf](https://github.com/yannbf)!\n- CLI: Remove random commas in storybook upgrade logs - [#22333](https://github.com/storybookjs/storybook/pull/22333), thanks [@joaonunomota](https://github.com/joaonunomota)!\n- Controls: Fix select / multiselect when value contains multiple spaces - [#22334](https://github.com/storybookjs/storybook/pull/22334), thanks [@oxcened](https://github.com/oxcened)!\n- Core: Add class name to Storybook error name - [#24371](https://github.com/storybookjs/storybook/pull/24371), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Deprecate storyStoreV6 (including storiesOf) and storyIndexers - [#23938](https://github.com/storybookjs/storybook/pull/23938), thanks [@JReinhold](https://github.com/JReinhold)!\n- Doc Blocks: Add title to Meta prop types - [#23370](https://github.com/storybookjs/storybook/pull/23370), thanks [@iqbalcodes6602](https://github.com/iqbalcodes6602)!\n- ManagerAPI: Fix bug with story redirection when URL has partial storyId - [#24345](https://github.com/storybookjs/storybook/pull/24345), thanks [@ndelangen](https://github.com/ndelangen)!\n- NextJS: Support rename font import - [#24406](https://github.com/storybookjs/storybook/pull/24406), thanks [@yoshi2no](https://github.com/yoshi2no)!\n- NextJS: Change babel plugins from proposal-... to transform-... - [#24290](https://github.com/storybookjs/storybook/pull/24290), thanks [@roottool](https://github.com/roottool)!\n- NextJS: Fix default next image loader when src has params - [#24187](https://github.com/storybookjs/storybook/pull/24187), thanks [@json-betsec](https://github.com/json-betsec)!\n- NextJS: Fix Image Context re-use via singleton - [#24146](https://github.com/storybookjs/storybook/pull/24146), thanks [@martinnabhan](https://github.com/martinnabhan)!\n- NextJS: Improve support for Windows-style paths - [#23695](https://github.com/storybookjs/storybook/pull/23695), thanks [@T99](https://github.com/T99)!\n- React: Upgrade `react-docgen` to `6.0.x` and improve argTypes - [#23825](https://github.com/storybookjs/storybook/pull/23825), thanks [@shilman](https://github.com/shilman)!\n- Svelte: Fix docs generating when using `lang=\"ts\"` or optional chaining - [#24096](https://github.com/storybookjs/storybook/pull/24096), thanks [@j3rem1e](https://github.com/j3rem1e)!\n- UI: Filter some manager errors - [#24217](https://github.com/storybookjs/storybook/pull/24217), thanks [@yannbf](https://github.com/yannbf)!\n- UI: Update ScrollArea with radix - [#24413](https://github.com/storybookjs/storybook/pull/24413), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- UI: Improve contrast ratio between focus / hover - [#24205](https://github.com/storybookjs/storybook/pull/24205), thanks [@chocoscoding](https://github.com/chocoscoding)!\n- UI: Fix className missing in syntaxhighlighter - [#24491](https://github.com/storybookjs/storybook/pull/24491), thanks [@ndelangen](https://github.com/ndelangen)!\n- Vite: Move mdx-plugin from `@storybook/builder-vite` to `@storybook/addon-docs` - [#24166](https://github.com/storybookjs/storybook/pull/24166), thanks [@bryanjtc](https://github.com/bryanjtc)!\n- Vite: Support Vite 5 - [#24395](https://github.com/storybookjs/storybook/pull/24395), thanks [@IanVS](https://github.com/IanVS)!\n- Web-components: Add Lit3 support - [#24437](https://github.com/storybookjs/storybook/pull/24437), thanks [@shilman](https://github.com/shilman)!\n- Webpack: Display errors on build - [#24377](https://github.com/storybookjs/storybook/pull/24377), thanks [@yannbf](https://github.com/yannbf)!\n- Webpack: Categorize builder error - [#24031](https://github.com/storybookjs/storybook/pull/24031), thanks [@yannbf](https://github.com/yannbf)!\n- Webpack: Use logger.warn on warnings - [#24472](https://github.com/storybookjs/storybook/pull/24472), thanks [@yannbf](https://github.com/yannbf)!\n</details>\n\n## 7.4.6\n\n- CLI: Fix Nextjs project detection - [#24346](https://github.com/storybookjs/storybook/pull/24346), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Fix missing favicon during dev - [#24356](https://github.com/storybookjs/storybook/pull/24356), thanks [@ndelangen](https://github.com/ndelangen)!\n\n## 7.4.5\n\n- UI: Fix infinite hook call causing browsers to freeze - [#24291](https://github.com/storybookjs/storybook/pull/24291), thanks [@yannbf](https://github.com/yannbf)!\n\n## 7.4.4\n\n- Core: Fix Promise cycle bug in useSharedState - [#24268](https://github.com/storybookjs/storybook/pull/24268), thanks [@ndelangen](https://github.com/ndelangen)!\n- Manager: Fix useAddonState when using a setter function - [#24237](https://github.com/storybookjs/storybook/pull/24237), thanks [@ndelangen](https://github.com/ndelangen)!\n\n## 7.4.3\n\n- CLI: Fix `sb add` adding duplicative entries - [#24229](https://github.com/storybookjs/storybook/pull/24229), thanks [@ndelangen](https://github.com/ndelangen)!\n- NextJS: Add compatibility with nextjs `13.5` - [#24239](https://github.com/storybookjs/storybook/pull/24239), thanks [@ndelangen](https://github.com/ndelangen)!\n- NextJS: Aliases `react` and `react-dom` like `next.js` does - [#23671](https://github.com/storybookjs/storybook/pull/23671), thanks [@sookmax](https://github.com/sookmax)!\n- Types: Allow `null` in value of `experimental_updateStatus` to clear status - [#24206](https://github.com/storybookjs/storybook/pull/24206), thanks [@ndelangen](https://github.com/ndelangen)!\n\n## 7.4.2\n\n- Addon API: Improve the updateStatus API - [#24007](https://github.com/storybookjs/storybook/pull/24007), thanks [@ndelangen](https://github.com/ndelangen)!\n- Nextjs: Migrate from config to previewAnnotations - [#24178](https://github.com/storybookjs/storybook/pull/24178), thanks [@yannbf](https://github.com/yannbf)!\n- UI: Fix SVG override fill when path has a fill attribute - [#24156](https://github.com/storybookjs/storybook/pull/24156), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: Improve look and feel of status UI in sidebar - [#24099](https://github.com/storybookjs/storybook/pull/24099), thanks [@ndelangen](https://github.com/ndelangen)!\n\n## 7.4.1\n\n- CLI: Add uncaughtException handler - [#24018](https://github.com/storybookjs/storybook/pull/24018), thanks [@yannbf](https://github.com/yannbf)!\n- CLI: Fix packageManager handling in `sb add` - [#24079](https://github.com/storybookjs/storybook/pull/24079), thanks [@Integrayshaun](https://github.com/Integrayshaun)!\n- Core: Add CJS entrypoints to errors in core events - [#24038](https://github.com/storybookjs/storybook/pull/24038), thanks [@yannbf](https://github.com/yannbf)!\n- Docs: Fix TOC import - [#24047](https://github.com/storybookjs/storybook/pull/24047), thanks [@shilman](https://github.com/shilman)!\n- Telemetry: Filter addon options to protect sensitive info - [#24000](https://github.com/storybookjs/storybook/pull/24000), thanks [@shilman](https://github.com/shilman)!\n- Types: Remove `@types/react` dep from `@storybook/types` - [#24042](https://github.com/storybookjs/storybook/pull/24042), thanks [@JReinhold](https://github.com/JReinhold)!\n- Vue3: Remove console.log in sourceDecorator - [#24062](https://github.com/storybookjs/storybook/pull/24062), thanks [@oruman](https://github.com/oruman)!\n\n## 7.4.0\n\n- Addon-docs: Resolve `mdx-react-shim` & `@storybook/global` correctly - [#23941](https://github.com/storybookjs/storybook/pull/23941), thanks [@ndelangen](https://github.com/ndelangen)!\n- Addons: Fix key is not a prop warning - [#23935](https://github.com/storybookjs/storybook/pull/23935), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Build: Migrate @storybook/scripts to strict-ts - [#23818](https://github.com/storybookjs/storybook/pull/23818), thanks [@stilt0n](https://github.com/stilt0n)!\n- CLI: Exclude addon-styling from upgrade - [#23841](https://github.com/storybookjs/storybook/pull/23841), thanks [@Integrayshaun](https://github.com/Integrayshaun)!\n- CLI: Improve autotitle stories format handling in GFM automigration - [#23964](https://github.com/storybookjs/storybook/pull/23964), thanks [@yannbf](https://github.com/yannbf)!\n- CLI: Install latest version of non-core addon - [#23956](https://github.com/storybookjs/storybook/pull/23956), thanks [@Integrayshaun](https://github.com/Integrayshaun)!\n- CLI: Pass package manager to postinstall - [#23913](https://github.com/storybookjs/storybook/pull/23913), thanks [@Integrayshaun](https://github.com/Integrayshaun)!\n- CLI: Provide guidance for users who try to initialize Storybook on an empty dir - [#23874](https://github.com/storybookjs/storybook/pull/23874), thanks [@yannbf](https://github.com/yannbf)!\n- CLI: Set server init generator to use Webpack5 - [#23971](https://github.com/storybookjs/storybook/pull/23971), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Add error categorization framework - [#23653](https://github.com/storybookjs/storybook/pull/23653), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Fix error thrown if `docs.defaultName` is unset - [#23893](https://github.com/storybookjs/storybook/pull/23893), thanks [@stilt0n](https://github.com/stilt0n)!\n- Core: Fix indexing for non-prefixed `stories.*` stories - [#23974](https://github.com/storybookjs/storybook/pull/23974), thanks [@shilman](https://github.com/shilman)!\n- Core: Fix race-condition relating to `addons.setConfig` - [#23802](https://github.com/storybookjs/storybook/pull/23802), thanks [@ndelangen](https://github.com/ndelangen)!\n- Core: Throw an error when detecting empty stories field - [#23942](https://github.com/storybookjs/storybook/pull/23942), thanks [@yannbf](https://github.com/yannbf)!\n- Dependencies: Upgrade `escodegen` to fix security issue - [#23973](https://github.com/storybookjs/storybook/pull/23973), thanks [@shilman](https://github.com/shilman)!\n- Index: Fix `*.story.*` CSF indexing - [#23852](https://github.com/storybookjs/storybook/pull/23852), thanks [@shilman](https://github.com/shilman)!\n- Logger: Fix double error messages/stack - [#23919](https://github.com/storybookjs/storybook/pull/23919), thanks [@ndelangen](https://github.com/ndelangen)!\n- Maintenance: Categorize server errors - [#23912](https://github.com/storybookjs/storybook/pull/23912), thanks [@yannbf](https://github.com/yannbf)!\n- Maintenance: Move filtering of sidebar into the state - [#23911](https://github.com/storybookjs/storybook/pull/23911), thanks [@ndelangen](https://github.com/ndelangen)!\n- Maintenance: Remove need for `react` as peerDependency - [#23897](https://github.com/storybookjs/storybook/pull/23897), thanks [@ndelangen](https://github.com/ndelangen)!\n- Maintenance: Remove sourcemaps generation - [#23936](https://github.com/storybookjs/storybook/pull/23936), thanks [@ndelangen](https://github.com/ndelangen)!\n- Maintenance: Revert \"WebpackBuilder: Remove need for `react` as peerDependency\" - [#23882](https://github.com/storybookjs/storybook/pull/23882), thanks [@vanessayuenn](https://github.com/vanessayuenn)!\n- Manager API: Fix `api.getAddonState`default value - [#23804](https://github.com/storybookjs/storybook/pull/23804), thanks [@sookmax](https://github.com/sookmax)!\n- Preset: Add common preset overrides mechanism - [#23915](https://github.com/storybookjs/storybook/pull/23915), thanks [@yannbf](https://github.com/yannbf)!\n- Publish: Don't distribute src files or unnecessary template files - [#23853](https://github.com/storybookjs/storybook/pull/23853), thanks [@shilman](https://github.com/shilman)!\n- Shortcuts: Execute preventDefault only if keyboard shortcuts are enabled - [#23412](https://github.com/storybookjs/storybook/pull/23412), thanks [@Spielboerg](https://github.com/Spielboerg)!\n- Types: Fix `React.ReactElement` not found - [#23967](https://github.com/storybookjs/storybook/pull/23967), thanks [@abu-osos](https://github.com/abu-osos)!\n- UI: Add an experimental API for adding sidebar bottom toolbar - [#23778](https://github.com/storybookjs/storybook/pull/23778), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: Add an experimental API for adding sidebar filter functions at runtime - [#23722](https://github.com/storybookjs/storybook/pull/23722), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: Add an experimental API for adding sidebar top toolbar - [#23811](https://github.com/storybookjs/storybook/pull/23811), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: Removal of experimental components - [#23907](https://github.com/storybookjs/storybook/pull/23907), thanks [@ndelangen](https://github.com/ndelangen)!\n- Vue3: Add support for Global Apps install - [#23772](https://github.com/storybookjs/storybook/pull/23772), thanks [@chakAs3](https://github.com/chakAs3)!\n- Vue3: Use slot value directly if it's a string in source decorator - [#23784](https://github.com/storybookjs/storybook/pull/23784), thanks [@nasvillanueva](https://github.com/nasvillanueva)!\n\n## 7.3.2\n\n- Maintenance: Revert \"WebpackBuilder: Remove need for `react` as peerDependency\" - [#23882](https://github.com/storybookjs/storybook/pull/23882), thanks [@vanessayuenn](https://github.com/vanessayuenn)!\n\n## 7.3.1\n\n- Index: Fix `*.story.*` CSF indexing - [#23852](https://github.com/storybookjs/storybook/pull/23852), thanks [@shilman](https://github.com/shilman)!\n\n## 7.3.0\n\n- ✨ Indexer: Introduce new experimental `indexer` API - #23691, thanks [@JReinhold](https://github.com/jreinhold)!\n- ✨ CLI: Update postinstall to look for addon script - [#23791](https://github.com/storybookjs/storybook/pull/23791), thanks [@Integrayshaun](https://github.com/Integrayshaun)!\n- ✨ Server: Add support for tags - #23660, thanks [@JReinhold](https://github.com/jreinhold)!\n- 🐛 CSF-Tools: Remove prettier from printConfig - [#23766](https://github.com/storybookjs/storybook/pull/23766), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- 🐛 Build: Support Chrome 100, Safari 15 and Firefox 91 - [#23800](https://github.com/storybookjs/storybook/pull/23800), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- 🐛 Vue3: Don't automatically assign values to all slots - [#23697](https://github.com/storybookjs/storybook/pull/23697), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- 🐛 Core: Fix `composeStories` typings - [#23577](https://github.com/storybookjs/storybook/pull/23577), thanks [@yannbf](https://github.com/yannbf)!\n- 🐛 WebpackBuilder: Remove need for `react` as peerDependency - [#23496](https://github.com/storybookjs/storybook/pull/23496), thanks [@ndelangen](https://github.com/ndelangen)!\n- 🔧 Addon-docs, Core, Server: Use new `indexer` API - #23660, thanks [@JReinhold](https://github.com/jreinhold)!\n- 🔧 Core-server: Improve internal types - #23632, thanks [@JReinhold](https://github.com/jreinhold)!\n- 🔧 UI: Improve Link component - [#23767](https://github.com/storybookjs/storybook/pull/23767), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- 🔧 UI: Improve new `Button` component - [#23765](https://github.com/storybookjs/storybook/pull/23765), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- 🔧 UI: Update Button types to allow for no children on iconOnly buttons - [#23735](https://github.com/storybookjs/storybook/pull/23735), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- 🔧 UI: Upgrade Icon component - [#23680](https://github.com/storybookjs/storybook/pull/23680), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- 🔧 Addons: Deprecate key in addon render function as it is not available anymore - [#23792](https://github.com/storybookjs/storybook/pull/23792), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- 🔧 UI: Update IconButton and add new Toolbar component - [#23795](https://github.com/storybookjs/storybook/pull/23795), thanks [@cdedreuille](https://github.com/cdedreuille)!\n\n## 7.2.3\n\n- Build: Support Chrome 100, Safari 15 and Firefox 91 - [#23800](https://github.com/storybookjs/storybook/pull/23800), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n\n## 7.2.2\n\n- CSF-Tools: Remove prettier from printConfig - [#23766](https://github.com/storybookjs/storybook/pull/23766), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n\n## 7.2.1\n\n- Addon docs: Add safe check in Webpack preset - [#23687](https://github.com/storybookjs/storybook/pull/23687), thanks [@yannbf](https://github.com/yannbf)!\n- Autodocs: Fix docs pages ignoring `meta.id` when calculating their ID - [#23520](https://github.com/storybookjs/storybook/pull/23520), thanks [@sookmax](https://github.com/sookmax)!\n- CLI: Fix error logging being swallowed from dev/build failures - [#23689](https://github.com/storybookjs/storybook/pull/23689), thanks [@yannbf](https://github.com/yannbf)!\n- Channels: Remove self-referencing in `package.json` - [#23681](https://github.com/storybookjs/storybook/pull/23681), thanks [@stof](https://github.com/stof)!\n- UI: Fix ArgsTable empty state on docs - [#23688](https://github.com/storybookjs/storybook/pull/23688), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- UI: Improve controls addon - [#23635](https://github.com/storybookjs/storybook/pull/23635), thanks [@cdedreuille](https://github.com/cdedreuille)!\n\n## 7.2.0\n\nThis month, we're going to experiment with our launch cycle by making smaller but more frequent releases. Our goal is to bring you new features more quickly, while also smoothing the upgrade process.\n\nStorybook 7.2 is the first of these new, faster releases:\n\n- Automigration: Fix wrap-require automigration for common js main.js files - [#23644](https://github.com/storybookjs/storybook/pull/23644), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- CSF Tools: Use recast for printing in csf-tools - [#23427](https://github.com/storybookjs/storybook/pull/23427), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- CSF-tools: Parse stories using typescript keywords 'satisfies' and 'as' - [#23638](https://github.com/storybookjs/storybook/pull/23638), thanks [@joaonunomota](https://github.com/joaonunomota)!\n- Core: Fix channelOptions for serverChannel - [#23615](https://github.com/storybookjs/storybook/pull/23615), thanks [@ndelangen](https://github.com/ndelangen)!\n- NextJS: Add `@babel/core` as a dependency - [#22450](https://github.com/storybookjs/storybook/pull/22450), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Vite: Fix config loading - project directory - [#22240](https://github.com/storybookjs/storybook/pull/22240), thanks [@nVitius](https://github.com/nVitius)!\n- Angular: Fix initialization of Storybook in Angular 16.1 - [#23598](https://github.com/storybookjs/storybook/pull/23598), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Dependencies: Downgrade `jest-mock` - [#23597](https://github.com/storybookjs/storybook/pull/23597), thanks [@ndelangen](https://github.com/ndelangen)!\n- Dependencies: Upgrade simple-update-notifier - [#23396](https://github.com/storybookjs/storybook/pull/23396), thanks [@dartess](https://github.com/dartess)!\n- Storyshots: fix broken storyshots with angular - [#23555](https://github.com/storybookjs/storybook/pull/23555), thanks [@mattlewis92](https://github.com/mattlewis92)!\n- TypeScript: Added `expanded` to `CoreCommon_StorybookRefs` to fix typescript errors - [#23488](https://github.com/storybookjs/storybook/pull/23488), thanks [@DotwoodMedia](https://github.com/DotwoodMedia)!\n- TypeScript: Downgrade to the last version of type-fest that doesn't need typescript 5.0 - [#23574](https://github.com/storybookjs/storybook/pull/23574), thanks [@ndelangen](https://github.com/ndelangen)!\n- Vue2: Source Decorator reactivity - [#23149](https://github.com/storybookjs/storybook/pull/23149), thanks [@chakAs3](https://github.com/chakAs3)!\n- Router: Support RegExp in Route component - [#23292](https://github.com/storybookjs/storybook/pull/23292), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: Improve tabs component, more type correct, allow for FC as title - [#23288](https://github.com/storybookjs/storybook/pull/23288), thanks [@ndelangen](https://github.com/ndelangen)!\n- Addons: Improve code quality by using title as FC & sharing state via useAddonState - [#23298](https://github.com/storybookjs/storybook/pull/23298), thanks [@ndelangen](https://github.com/ndelangen)!\n- InteractionsAddon: Improve code quality by using title as FC & sharing state via useAddonState - [#23291](https://github.com/storybookjs/storybook/pull/23291), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: Add storyStatus to sidebar UI - [#23342](https://github.com/storybookjs/storybook/pull/23342), thanks [@ndelangen](https://github.com/ndelangen)!\n- Addon API: Add experimental page addon type - [#23307](https://github.com/storybookjs/storybook/pull/23307), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: refactor Canvas component so we can improve types for PREVIEW addons and TAB addons - [#23311](https://github.com/storybookjs/storybook/pull/23311), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: Improve Button layout and props - [#23356](https://github.com/storybookjs/storybook/pull/23356), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- Dependencies: Remove references to api and the 2 deprecated channel packages - [#23384](https://github.com/storybookjs/storybook/pull/23384), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: Show the story status in the search results - [#23441](https://github.com/storybookjs/storybook/pull/23441), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: Create new form elements in the new Core UI (Input, TextArea, Select) - [#23469](https://github.com/storybookjs/storybook/pull/23469), thanks [@cdedreuille](https://github.com/cdedreuille)!\n\n## 7.1.1\n\n- Angular: Make enableProdMode optional - [#23489](https://github.com/storybookjs/storybook/pull/23489), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- CLI: Gracefully shutdown and cleanup execa child processes - [#23538](https://github.com/storybookjs/storybook/pull/23538), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- CLI: Improve support of mono repositories - [#23458](https://github.com/storybookjs/storybook/pull/23458), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n\n## 7.1.0 (July 18, 2023)\n\nStorybook 7.1 is here! 🎉\n\n- 🏄‍♀️ [**In-app onboarding**](https://storybook.js.org/blog/in-app-tour-for-new-users/) to help you set up new projects\n- 💅 [**Zero-config styling support**](https://storybook.js.org/blog/zero-config-support-for-tailwind-mui-styled-components-and-emotion/) for major libraries\n- 🗃️ [**API reference documentation**](https://storybook.js.org/blog/docs-updates/) and TypeScript-first snippets\n- 📇 [**Table of Contents for docs**](https://storybook.js.org/docs/7.1/react/writing-docs/autodocs#generate-a-table-of-contents)\n- 🎨 [**Figma** **Design addon**](https://github.com/storybookjs/addon-designs) official support\n- 📗 **Vue3 source snippets** and reactivity improvements\n- 💯 **Hundreds more** fixes and improvements\n\n  7.1 contains hundreds more fixes, features, and tweaks. Browse the changelogs matching `7.1.0-alpha.*`, `7.1.0-beta.*`, and `7.1.0-rc.*` for the full list of changes.\n\nFor a better upgrade experience, please use one of the following commands:\n\nnpm or yarn 1:\n`npx storybook@latest upgrade`\n\npnpm:\n`pnpm dlx storybook@latest upgrade`\n\nyarn berry:\n`yarn dlx storybook@latest upgrade`\n\n## 7.0.27\n\n- Angular: Enable prod mode when Storybook is built - [#23404](https://github.com/storybookjs/storybook/pull/23404), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Angular: Fix esm issue in combination with rxjs v6 - [#23405](https://github.com/storybookjs/storybook/pull/23405), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- CLI: Exit when user does not select a storybook project type - [#23201](https://github.com/storybookjs/storybook/pull/23201), thanks [@yannbf](https://github.com/yannbf)!\n- Next.js: Fix for @nx/react/plugin/storybook with SVGs - [#23210](https://github.com/storybookjs/storybook/pull/23210), thanks [@daves28](https://github.com/daves28)!\n- Svelte-Webpack: Support Svelte v4 - [#23336](https://github.com/storybookjs/storybook/pull/23336), thanks [@JReinhold](https://github.com/JReinhold)!\n\n## 7.0.26\n\n- Next.js: Fix next/image usage in latest Next.js release - [#23296](https://github.com/storybookjs/storybook/pull/23296), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- NextJS: Fix `useParams` support - [#22946](https://github.com/storybookjs/storybook/pull/22946), thanks [@gitstart-storybook](https://github.com/gitstart-storybook)!\n- NextJS: Allow disabling next/image lazy loading - [#21909](https://github.com/storybookjs/storybook/pull/21909), thanks [@martinnabhan](https://github.com/martinnabhan)\n\n## 7.0.25\n\n- CLI: Fix pnp paths logic in storybook metadata - [#23259](https://github.com/storybookjs/storybook/pull/23259), thanks [@yannbf](https://github.com/yannbf)!\n- Controls: Fix UI to add array items - [#22993](https://github.com/storybookjs/storybook/pull/22993), thanks [@sookmax](https://github.com/sookmax)!\n- Next.js: Support disableStaticImages setting - [#23167](https://github.com/storybookjs/storybook/pull/23167), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- React: Fix decorators to conditionally render children - [#22336](https://github.com/storybookjs/storybook/pull/22336), thanks [@redbugz](https://github.com/redbugz)!\n\n## 7.0.24\n\n- CLI: Parse pnp paths in storybook metadata - [#23199](https://github.com/storybookjs/storybook/pull/23199), thanks [@yannbf](https://github.com/yannbf)!\n- Dependencies: Pin `file-system-cache` to 2.3.0 - [#23221](https://github.com/storybookjs/storybook/pull/23221), thanks [@JReinhold](https://github.com/JReinhold)!\n- Svelte: Support v4 - [#22905](https://github.com/storybookjs/storybook/pull/22905), thanks [@JReinhold](https://github.com/JReinhold)!\n\n## 7.0.23\n\n- Core: Fix compat by disabling name mangling in `esbuild` require - [#22486](https://github.com/storybookjs/storybook/pull/22486), thanks [@youngboy](https://github.com/youngboy)!\n- Core: Prebundle node-logger and make it CJS only - [#23109](https://github.com/storybookjs/storybook/pull/23109), thanks [@ndelangen](https://github.com/ndelangen)!\n- NextJS: Fix fonts not loading with 3+ words in name - [#23121](https://github.com/storybookjs/storybook/pull/23121), thanks [@ygkn](https://github.com/ygkn)!\n- Telemetry: Count onboarding stories - [#23092](https://github.com/storybookjs/storybook/pull/23092), thanks [@shilman](https://github.com/shilman)!\n\n## 7.0.22\n\n- CLI: Prebundle boxen to resolve a ESM/CJS incompatibility - [#23080](https://github.com/storybookjs/storybook/pull/23080), thanks [@ndelangen](https://github.com/ndelangen)!\n- Core: Fix core-common to use node-fetch - [#23077](https://github.com/storybookjs/storybook/pull/23077), thanks [@ndelangen](https://github.com/ndelangen)!\n- Telemetry: Count onboarding stories - [#23092](https://github.com/storybookjs/storybook/pull/23092), thanks [@shilman](https://github.com/shilman)!\n\n## 7.0.21\n\n- Angular: Fix 16.1 compatibility - [#23064](https://github.com/storybookjs/storybook/pull/23064), thanks [@ndelangen](https://github.com/ndelangen)!\n- Angular: Fix ivy preset - [#23070](https://github.com/storybookjs/storybook/pull/23070), thanks [@ndelangen](https://github.com/ndelangen)!\n- CLI: Improve steps in storybook init - [#22502](https://github.com/storybookjs/storybook/pull/22502), thanks [@yannbf](https://github.com/yannbf)!\n- CLI: Skip builder selection for react native - [#23042](https://github.com/storybookjs/storybook/pull/23042), thanks [@dannyhw](https://github.com/dannyhw)!\n- Core: Fix `builder-manager` adding multiple dashes to relative path - [#22974](https://github.com/storybookjs/storybook/pull/22974), thanks [@MarioCadenas](https://github.com/MarioCadenas)!\n- Core: Improve `of={...}` DocBlock error in story index - [#22782](https://github.com/storybookjs/storybook/pull/22782), thanks [@shilman](https://github.com/shilman)!\n- Dependencies: Set vue-component-type-helpers to latest - [#23015](https://github.com/storybookjs/storybook/pull/23015), thanks [@ndelangen](https://github.com/ndelangen)!\n- Vue3: Fix source decorator to generate correct story code - [#22518](https://github.com/storybookjs/storybook/pull/22518), thanks [@chakAs3](https://github.com/chakAs3)!\n- Web-components: Fix custom-elements order of property application - [#19183](https://github.com/storybookjs/storybook/pull/19183), thanks [@sonntag-philipp](https://github.com/sonntag-philipp)!\n\n## 7.0.20 (June 8, 2023)\n\n#### Bug Fixes\n\n- Server: Fix .stories.yml support [#22906](https://github.com/storybooks/storybook/pull/22906)\n- Docs: Fix Source block snippet updates [#22835](https://github.com/storybooks/storybook/pull/22835)\n- Core: Fix indexing errors by excluding node_modules stories [#22873](https://github.com/storybooks/storybook/pull/22873)\n- CLI: Fix upgrade notification message [#22933](https://github.com/storybooks/storybook/pull/22933)\n- Angular: Add --open/--no-open flag to dev command [#22964](https://github.com/storybooks/storybook/pull/22964)\n- Angular: Silence compodoc when running storybook with --quiet [#22957](https://github.com/storybooks/storybook/pull/22957)\n\n#### Maintenance\n\n- Core: Improve MDX of error in story index [#22782](https://github.com/storybooks/storybook/pull/22782)\n\n#### Build\n\n- Build: Fix the theme output during development [#22841](https://github.com/storybooks/storybook/pull/22841)\n- Revert \"Docs: E2E tests for Source block update fix\" [#22934](https://github.com/storybookjs/storybook/pull/22934)\n\n## 7.0.19 (June 8, 2023)\n\nBad release\n\n## 7.0.18 (May 26, 2023)\n\n#### Bug Fixes\n\n- Vue3: Fix TS 5.0 compat with vue-component-type-helpers [#22814](https://github.com/storybooks/storybook/pull/22814)\n- Vue3: Fix reactive args updates in decorators [#22717](https://github.com/storybooks/storybook/pull/22717)\n- Vue3: Revert v7 breaking change, restore reactive v6-compat API [#22692](https://github.com/storybooks/storybook/pull/22692)\n\n#### Build\n\n- Build: Add more checks to ci:daily workflow [#22815](https://github.com/storybooks/storybook/pull/22815)\n- Build: Fix Nextjs E2E tests [#22816](https://github.com/storybooks/storybook/pull/22816)\n- Build: Bring back new Vue3 tests to main [#22685](https://github.com/storybooks/storybook/pull/22685)\n\n## 7.0.17 (May 24, 2023)\n\n#### Bug Fixes\n\n- Vite: Fix pnpm support by replacing @storybook/global with `window` [#22709](https://github.com/storybooks/storybook/pull/22709)\n- Core: Fix `managerHead` preset in `main.ts` [#22701](https://github.com/storybooks/storybook/pull/22701)\n\n## 7.0.16 (May 24, 2023)\n\nAccidental no-op\n\n## 7.0.15 (May 24, 2023)\n\n#### Bug Fixes\n\n- UI: Fix `.mp3` support for builder-manager [#22699](https://github.com/storybooks/storybook/pull/22699)\n- Vite: Fix missing @storybook/global dependency [#22700](https://github.com/storybooks/storybook/pull/22700)\n- NextJS: Fix compatibility with Next 13.4.3 [#22697](https://github.com/storybooks/storybook/pull/22697)\n\n## 7.0.14 (May 23, 2023)\n\n#### Bug Fixes\n\n- Core: Only connect to serverChannel in development mode [#22575](https://github.com/storybooks/storybook/pull/22575)\n- CLI: Fix error parsing on NPM proxy [#22690](https://github.com/storybooks/storybook/pull/22690)\n\n#### Maintenance\n\n- Core: Create server channel from window.location [#22055](https://github.com/storybooks/storybook/pull/22055)\n\n## 7.0.13 (May 22, 2023)\n\n#### Bug Fixes\n\n- Angular: Fix process I/O for compodoc command [#22441](https://github.com/storybooks/storybook/pull/22441)\n- CLI: Improve error handling when dealing with angular.json files [#22663](https://github.com/storybooks/storybook/pull/22663)\n- CLI: Skip prompting for eslint plugin with --yes flag [#22651](https://github.com/storybooks/storybook/pull/22651)\n- CLI: Account for windows paths when copying templates [#22644](https://github.com/storybooks/storybook/pull/22644)\n- CLI: Fix pnpm init command [#22635](https://github.com/storybooks/storybook/pull/22635)\n- UI: Add legacy font formats [#22576](https://github.com/storybooks/storybook/pull/22576)\n- Webpack: Remove the alias for `global` [#22393](https://github.com/storybooks/storybook/pull/22393)\n\n#### Maintenance\n\n- Angular: Enable unit tests [#22355](https://github.com/storybooks/storybook/pull/22355)\n- CLI: Reduce installation noise and improve error handling [#22554](https://github.com/storybooks/storybook/pull/22554)\n- CLI: Only handle CTRL + C on init event [#22687](https://github.com/storybooks/storybook/pull/22687)\n- CLI: Don't touch nx packages on upgrade [#22419](https://github.com/storybooks/storybook/pull/22419)\n\n#### Build\n\n- Build: Add discord notification when generating sandboxes fails [#22638](https://github.com/storybooks/storybook/pull/22638)\n- Build: Set correct ref on sandboxes Github action [#22625](https://github.com/storybooks/storybook/pull/22625)\n- Build: Fix sandbox generation scripts [#22620](https://github.com/storybooks/storybook/pull/22620)\n\n## 7.0.12 (May 15, 2023)\n\n#### Bug Fixes\n\n- Core: Fix source snippets for stories with mapped args [#22135](https://github.com/storybooks/storybook/pull/22135)\n- CLI: Fix `getFrameworkPackage` logic [#22559](https://github.com/storybooks/storybook/pull/22559)\n- CLI: Remove automigrate reference from init command [#22561](https://github.com/storybooks/storybook/pull/22561)\n\n#### Maintenance\n\n- CLI: Detach automigrate command from storybook init [#22523](https://github.com/storybooks/storybook/pull/22523)\n\n## 7.0.11 (May 12, 2023)\n\n#### Bug Fixes\n\n- Toolbars: Fix title behavior in UI [#22496](https://github.com/storybooks/storybook/pull/22496)\n- CLI: Fix storybook upgrade precheckfailure object [#22517](https://github.com/storybooks/storybook/pull/22517)\n- CLI: Throw errors instead of rejecting promises [#22515](https://github.com/storybooks/storybook/pull/22515)\n- CLI: Remove unsupported frameworks/renderers and improve builder detection [#22492](https://github.com/storybooks/storybook/pull/22492)\n- Web-components: Fix source decorator to handle document fragments [#22513](https://github.com/storybooks/storybook/pull/22513)\n- Core: Fix windows path error in StoryStore v6 [#22512](https://github.com/storybooks/storybook/pull/22512)\n- CLI: Do not show a migration summary on sb init [#22109](https://github.com/storybooks/storybook/pull/22109)\n- UI: Show current search shortcut in search box sidebar [#21619](https://github.com/storybooks/storybook/pull/21619)\n- Outline: Fix additional outline border in docs mode [#21773](https://github.com/storybooks/storybook/pull/21773)\n- Measure: Deactivate when switching to Docs mode [#21602](https://github.com/storybooks/storybook/pull/21602)\n- CSF: Expose story id in composeStories [#22471](https://github.com/storybooks/storybook/pull/22471)\n- CLI: Prompt to force initialization when storybook folder is detected [#22392](https://github.com/storybooks/storybook/pull/22392)\n- UI: Fix css inconsistency in Button and Icon components [#22497](https://github.com/storybooks/storybook/pull/22497)\n\n## 7.0.10 (May 9, 2023)\n\n#### Bug Fixes\n\n- CLI: Fix copyTemplate failures on `init` [#22375](https://github.com/storybooks/storybook/pull/22375)\n- CLI: Fix server init [#22443](https://github.com/storybooks/storybook/pull/22443)\n- CLI: Scope styles in sample components from the CLI templates [#22162](https://github.com/storybooks/storybook/pull/22162)\n- React: Use correct default annotations for composeStories [#22308](https://github.com/storybooks/storybook/pull/22308)\n- Server: Add json indexer [#22460](https://github.com/storybooks/storybook/pull/22460)\n- UI: Fix opacity from list-item color [#22074](https://github.com/storybooks/storybook/pull/22074)\n\n#### Maintenance\n\n- CLI: Refactor package manager methods to be async [#22401](https://github.com/storybooks/storybook/pull/22401)\n- Improve Error message for Angular.json file not found [#22377](https://github.com/storybooks/storybook/pull/22377)\n\n## 7.0.9 (May 5, 2023)\n\n#### Bug Fixes\n\n- Core: Fix virtual modules excluded for babel-loader [#22331](https://github.com/storybooks/storybook/pull/22331)\n\n#### Maintenance\n\n- Angular: Allow TypeScript 4.0.0 and 5.0.0 [#22391](https://github.com/storybooks/storybook/pull/22391)\n\n## 7.0.8 (May 3, 2023)\n\n#### Bug Fixes\n\n- Typescript: Fix bad typings caused by tsup bug [#22261](https://github.com/storybooks/storybook/pull/22261)\n- Migrate: skip the automigration for gf markdown when user isn't using mdx [#22186](https://github.com/storybooks/storybook/pull/22186)\n- UI: Addon panel does not update after disabling/enabling an addon [#22258](https://github.com/storybooks/storybook/pull/22258)\n- Vue3: Fix compiler error when there is double tag [#22286](https://github.com/storybooks/storybook/pull/22286)\n- Args: Fix multiple mapped args return array of labels [#22169](https://github.com/storybooks/storybook/pull/22169)\n- CLI: Add web-components webpack5 to missing-babelrc automigration [#22202](https://github.com/storybooks/storybook/pull/22202)\n- Docs: Fix inline story style [#21870](https://github.com/storybooks/storybook/pull/21870)\n- UI: Fix shift + 7 shortcut to focus search field [#22073](https://github.com/storybooks/storybook/pull/22073)\n- UI: Fix controls missing when navigating from story [#21967](https://github.com/storybooks/storybook/pull/21967)\n- NextJS: Fix tsconfig resolution [#22160](https://github.com/storybooks/storybook/pull/22160)\n\n#### Maintenance\n\n- Telemetry: Persist sessionId across runs [#22325](https://github.com/storybooks/storybook/pull/22325)\n- Packaging: Move `types` condition to the front in all `package.json.exports` maps [#22321](https://github.com/storybooks/storybook/pull/22321)\n- Core: Rename manager UI mjs to js [#22247](https://github.com/storybooks/storybook/pull/22247)\n- Angular: Add support for Angular 16 [#22096](https://github.com/storybooks/storybook/pull/22096)\n- Packaging: Don't generate ESM dist for preset files [#22330](https://github.com/storybooks/storybook/pull/22330)\n- Packaging: Fix url for all packages in package.json [#22101](https://github.com/storybooks/storybook/pull/22101)\n- Add regex to ignore outdated Browserslist in Jest initialization base file [#22260](https://github.com/storybooks/storybook/pull/22260)\n\n## 7.0.7 (April 24, 2023)\n\n#### Bug Fixes\n\n- Core: Pass parameters in `SET_INDEX` for docs entries [#22154](https://github.com/storybooks/storybook/pull/22154)\n- Addon-actions: Fix ESM by upgrading from uuid-browser to uuid [#22037](https://github.com/storybooks/storybook/pull/22037)\n- Addon-actions: Fix decorator type [#22175](https://github.com/storybooks/storybook/pull/22175)\n- Core: Add new tags to distinguish docs attachment [#22120](https://github.com/storybooks/storybook/pull/22120)\n- Core: Restore Docs `useParameter` using `DOCS_PREPARED` [#22118](https://github.com/storybooks/storybook/pull/22118)\n\n#### Maintenance\n\n- CSF: Improve error message for bad default export [#22190](https://github.com/storybooks/storybook/pull/22190)\n- CLI: Add addon query-params to list of SB7 incompatible addons [#22095](https://github.com/storybooks/storybook/pull/22095)\n- UI: Add remount story shortcut [#21401](https://github.com/storybooks/storybook/pull/21401)\n\n#### Build\n\n- Build: Fix lit sandboxes [#22201](https://github.com/storybooks/storybook/pull/22201)\n- Build: Fix sandbox publish script [#22206](https://github.com/storybooks/storybook/pull/22206)\n\n## 7.0.6 (April 19, 2023)\n\n#### Bug Fixes\n\n- Core: Fix `module` guard in non-webpack environments [#22085](https://github.com/storybooks/storybook/pull/22085)\n\n#### Maintenance\n\n- CLI: Mark qwik as using addon-interactions [#22000](https://github.com/storybooks/storybook/pull/22000)\n\n#### Build\n\n- Build: Upgrade Playwright to 1.32.3 [#22087](https://github.com/storybooks/storybook/pull/22087)\n\n## 7.0.5 (April 15, 2023)\n\n#### Bug Fixes\n\n- Docs: Fix source snippets when parameters.docs.source.type = 'code' [#22048](https://github.com/storybooks/storybook/pull/22048)\n- CLI: Mention how to setup a monorepo manually in babelrc automigration [#22052](https://github.com/storybooks/storybook/pull/22052)\n- UI: Fix upgrade command in about page [#22056](https://github.com/storybooks/storybook/pull/22056)\n- CLI: Fix CLI sandbox command [#21977](https://github.com/storybooks/storybook/pull/21977)\n\n## 7.0.4 (April 12, 2023)\n\nStorybook 7.0 is here! 🎉\n\n- ⚡️ [First-class Vite](https://storybook.js.org/blog/first-class-vite-support-in-storybook/)\n- 🔼 [Zero-config NextJS](https://storybook.js.org/blog/integrate-nextjs-and-storybook-automatically/)\n- 🇸 [Zero-config SvelteKit](https://storybook.js.org/blog/storybook-for-sveltekit/)\n- 🏗️ [Frameworks API](https://storybook.js.org/blog/framework-api/)\n- 3️⃣ [Component Story Format v3](https://storybook.js.org/blog/storybook-csf3-is-here/)\n- 🛡️ [Improved type safety](https://storybook.js.org/blog/improved-type-safety-in-storybook-7/)\n- 📚 [Docs overhaul with MDx2 support](https://storybook.js.org/blog/storybook-7-docs/)\n- ☂️ [Code coverage for interaction testing](https://storybook.js.org/blog/code-coverage-with-the-storybook-test-runner/)\n- 🖼️ [UI design refresh](https://storybook.js.org/blog/7-0-design-alpha/)\n- 🏛️ [Improved stability](https://storybook.js.org/blog/storybook-ecosystem-ci/)\n\n  7.0 contains hundreds more fixes, features, and tweaks. Browse the changelogs matching `7.0.0-alpha.*`, `7.0.0-beta.*`, and `7.0.0-rc.*` for the full list of changes.\n\nSee our [Migration guide](https://storybook.js.org/migration-guides/7.0) to upgrade from earlier versions of Storybook.\n\n#### Bug Fixes\n\n- CLI: Catch errors thrown on sanity check of SB installs [#22039](https://github.com/storybooks/storybook/pull/22039)\n\n#### Dependency Upgrades\n\n- Addon-docs: Remove mdx1-csf as optional peer dep [#22038](https://github.com/storybooks/storybook/pull/22038)\n\n## 7.0.3 (April 12, 2023)\n\n#### Bug Fixes\n\n- React: Fix default export docgen for React.FC and forwardRef [#22024](https://github.com/storybooks/storybook/pull/22024)\n- Viewport: Remove transitions when switching viewports [#21963](https://github.com/storybooks/storybook/pull/21963)\n- CLI: Fix JsPackageManager typo [#22006](https://github.com/storybooks/storybook/pull/22006)\n- Viewport: Fix the `defaultOrientation` config option [#21962](https://github.com/storybooks/storybook/pull/21962)\n- UI: Fix story data access for broken About page [#21951](https://github.com/storybooks/storybook/pull/21951)\n- Angular: Fix components disappearing on docs page on property change [#21944](https://github.com/storybooks/storybook/pull/21944)\n- React: Don't show decorators in JSX snippets [#21907](https://github.com/storybooks/storybook/pull/21907)\n- Addon-docs: Include decorators by default in source decorators [#21902](https://github.com/storybooks/storybook/pull/21902)\n- CLI: Fix npm list command [#21947](https://github.com/storybooks/storybook/pull/21947)\n- Core: Revert Emotion `:first-child` (etc) workarounds [#21213](https://github.com/storybooks/storybook/pull/21213)\n\n#### Maintenance\n\n- UI: Add remount story shortcut [#21401](https://github.com/storybooks/storybook/pull/21401)\n- Telemetry: Add CLI version to context [#21999](https://github.com/storybooks/storybook/pull/21999)\n- CLI: Update template code references to 7.0 [#21845](https://github.com/storybooks/storybook/pull/21845)\n- Addon-actions: Fix non-included type file [#21922](https://github.com/storybooks/storybook/pull/21922)\n- Addon GFM: Fix node-logger dependency [#21938](https://github.com/storybooks/storybook/pull/21938)\n\n#### Dependency Upgrades\n\n- React-vite: Fix perf regression by pinning vite-plugin-react-docgen-ts [#22013](https://github.com/storybooks/storybook/pull/22013)\n- Update `@emotion/cache` version [#21941](https://github.com/storybooks/storybook/pull/21941)\n\n## 7.0.2 (April 3, 2023)\n\nStorybook 7.0 is here! 🎉\n\n- ⚡️ [First-class Vite](https://storybook.js.org/blog/first-class-vite-support-in-storybook/)\n- 🔼 [Zero-config NextJS](https://storybook.js.org/blog/integrate-nextjs-and-storybook-automatically/)\n- 🇸 [Zero-config SvelteKit](https://storybook.js.org/blog/storybook-for-sveltekit/)\n- 🏗️ [Frameworks API](https://storybook.js.org/blog/framework-api/)\n- 3️⃣ [Component Story Format v3](https://storybook.js.org/blog/storybook-csf3-is-here/)\n- 🛡️ [Improved type safety](https://storybook.js.org/blog/improved-type-safety-in-storybook-7/)\n- 📚 [Docs overhaul with MDx2 support](https://storybook.js.org/blog/storybook-7-docs/)\n- ☂️ [Code coverage for interaction testing](https://storybook.js.org/blog/code-coverage-with-the-storybook-test-runner/)\n- 🖼️ [UI design refresh](https://storybook.js.org/blog/7-0-design-alpha/)\n- 🏛️ [Improved stability](https://storybook.js.org/blog/storybook-ecosystem-ci/)\n\n  7.0 contains hundreds more fixes, features, and tweaks. Browse the changelogs matching `7.0.0-alpha.*`, `7.0.0-beta.*`, and `7.0.0-rc.*` for the full list of changes.\n\nSee our [Migration guide](https://storybook.js.org/migration-guides/7.0) to upgrade from earlier versions of Storybook.\n\n#### Bug Fixes\n\n- CLI: Improve incompatible addons logic [#21883](https://github.com/storybooks/storybook/pull/21883)\n\n## 7.0.1 (April 3, 2023)\n\n#### Bug Fixes\n\n- CLI: Always send error events if init doesn't succeed [#21879](https://github.com/storybooks/storybook/pull/21879)\n- CLI: Warn when community addons are incompatible with Storybook 7 [#21863](https://github.com/storybooks/storybook/pull/21863)\n- CLI: Fix migration summary message [#21862](https://github.com/storybooks/storybook/pull/21862)\n- CLI: Fix link to new framework API migrations [#21875](https://github.com/storybooks/storybook/pull/21875)\n\n#### Maintenance\n\n- Angular: Remove deprecated `component`/`propsMeta` from story [#21807](https://github.com/storybooks/storybook/pull/21807)\n- Remove deprecated flags and properties [#21852](https://github.com/storybooks/storybook/pull/21852)\n\n#### Dependencies\n\n- Fix codemod dependency conflict [#21876](https://github.com/storybooks/storybook/pull/21876)\n- Upgrade satellite repos for 7.0 [#21881](https://github.com/storybooks/storybook/pull/21881)\n\n## 7.0.0 (March 31, 2023)\n\nStorybook 7.0 is here! 🎉\n\n- ⚡️ [First-class Vite](https://storybook.js.org/blog/first-class-vite-support-in-storybook/)\n- 🔼 [Zero-config NextJS](https://storybook.js.org/blog/integrate-nextjs-and-storybook-automatically/)\n- 🇸 [Zero-config SvelteKit](https://storybook.js.org/blog/storybook-for-sveltekit/)\n- 🏗️ [Frameworks API](https://storybook.js.org/blog/framework-api/)\n- 3️⃣ [Component Story Format v3](https://storybook.js.org/blog/storybook-csf3-is-here/)\n- 🛡️ [Improved type safety](https://storybook.js.org/blog/improved-type-safety-in-storybook-7/)\n- 📚 [Docs overhaul with MDx2 support](https://storybook.js.org/blog/storybook-7-docs/)\n- ☂️ [Code coverage for interaction testing](https://storybook.js.org/blog/code-coverage-with-the-storybook-test-runner/)\n- 🖼️ [UI design refresh](https://storybook.js.org/blog/7-0-design-alpha/)\n- 🏛️ [Improved stability](https://storybook.js.org/blog/storybook-ecosystem-ci/)\n\n  7.0 contains hundreds more fixes, features, and tweaks. Browse the changelogs matching `7.0.0-alpha.*`, `7.0.0-beta.*`, and `7.0.0-rc.*` for the full list of changes.\n\nSee our [Migration guide](https://storybook.js.org/migration-guides/7.0) to upgrade from earlier versions of Storybook.\n\nFull announcement and proper release to the `latest` npm tag coming soon. 😘\n\n## 7.0.0-rc.11 (March 31, 2023)\n\n#### Features\n\n- CLI: Update stories glob in mdx codemod and not in mdx automigration [#21809](https://github.com/storybooks/storybook/pull/21809)\n\n#### Bug Fixes\n\n- TS: Make sure components with interfaces or no props don't raise decorator assignability issues [#21833](https://github.com/storybooks/storybook/pull/21833)\n- Angular: Export applicationConfig decorator and adjust documentation for usage [#21851](https://github.com/storybooks/storybook/pull/21851)\n- Vite: Polyfill global by default [#21832](https://github.com/storybooks/storybook/pull/21832)\n- NextJS: Add explicit require.resolve calls to nextjs webpack loader config [#21834](https://github.com/storybooks/storybook/pull/21834)\n- Angular: Fix support on Windows when Storystore v7 is disabled [#21830](https://github.com/storybooks/storybook/pull/21830)\n- Angular: Fix module imported twice [#21770](https://github.com/storybooks/storybook/pull/21770)\n\n#### Maintenance\n\n- CLI: Fix duplicated dependency warning for major version differences [#21850](https://github.com/storybooks/storybook/pull/21850)\n- Vite: downgrade remark related dependencies [#21836](https://github.com/storybooks/storybook/pull/21836)\n\n#### Build\n\n- Build: Remove workflow we no longer use [#21829](https://github.com/storybooks/storybook/pull/21829)\n\n## 7.0.0-rc.10 (March 29, 2023)\n\n#### Features\n\n- CLI: Warn the user for duplicated versions after automigrate [#21791](https://github.com/storybooks/storybook/pull/21791)\n\n#### Bug Fixes\n\n- Addon-docs: Add `remark-slug` and `remark-external-links` to Vite builder [#21796](https://github.com/storybooks/storybook/pull/21796)\n- Blocks: Add children prop types [#21803](https://github.com/storybooks/storybook/pull/21803)\n\n#### Maintenance\n\n- CLI: Upgrade to latest storybook/react-native version [#21811](https://github.com/storybooks/storybook/pull/21811)\n\n## 7.0.0-rc.9 (March 29, 2023)\n\n#### Bug Fixes\n\n- CLI: Don't inline template functions in CSF2 to 3 codemod [#21539](https://github.com/storybooks/storybook/pull/21539)\n- ArgTypes: Fix JSdoc missing deprecated tag [#21794](https://github.com/storybooks/storybook/pull/21794)\n- UI: Scroll to highlighted search result [#21692](https://github.com/storybooks/storybook/pull/21692)\n- Actions: Fix clearing number of actions [#21760](https://github.com/storybooks/storybook/pull/21760)\n- UI: Fix cannot read properties of undefined at SearchResults [#21728](https://github.com/storybooks/storybook/pull/21728)\n- CLI: Fix an issue where port can be NaN [#21785](https://github.com/storybooks/storybook/pull/21785)\n- Docs: Exclude decorators by default from source [#21722](https://github.com/storybooks/storybook/pull/21722)\n- Docs: Fix ArgsTable crashing on subcomponents [#21769](https://github.com/storybooks/storybook/pull/21769)\n- Docs: Make Source `transform` API consistent [#21749](https://github.com/storybooks/storybook/pull/21749)\n\n#### Maintenance\n\n- Telemetry: Count components [#21774](https://github.com/storybooks/storybook/pull/21774)\n\n#### Dependency Upgrades\n\n- Vite: Unpin rollup version [#21748](https://github.com/storybooks/storybook/pull/21748)\n- Upgrade slash package to v5.x [#21786](https://github.com/storybooks/storybook/pull/21786)\n\n## 7.0.0-rc.8 (March 25, 2023)\n\n#### Bug Fixes\n\n- TypeScript: Fix missing env in StorybookConfig [#21732](https://github.com/storybooks/storybook/pull/21732)\n- Composition: Fix src of iframe unless the version changes [#21713](https://github.com/storybooks/storybook/pull/21713)\n- Composition: Fix the ref loading state showing up as empty instead [#21690](https://github.com/storybooks/storybook/pull/21690)\n\n#### Build\n\n- Build: Add e2e-tests-dev task [#21546](https://github.com/storybooks/storybook/pull/21546)\n- Build: Fix CI after github.com SSH change [#21764](https://github.com/storybooks/storybook/pull/21764)\n\n## 7.0.0-rc.7 (March 23, 2023)\n\n#### Bug Fixes\n\n- Svelte: Remount when resetting args in controls [#21659](https://github.com/storybooks/storybook/pull/21659)\n- CLI: Fix support for env vars when running `dev`/`build` commands [#21152](https://github.com/storybooks/storybook/pull/21152)\n\n#### Maintenance\n\n- Core: upgrade esbuild, remove watch option from options [#21727](https://github.com/storybooks/storybook/pull/21727)\n\n## 7.0.0-rc.6 (March 23, 2023)\n\n#### Bug Fixes\n\n- CLI: Fix sb add / mdx-gfm for addons with non-serializable values [#21731](https://github.com/storybooks/storybook/pull/21731)\n- CSF-plugin: Fix sourcemaps [#21704](https://github.com/storybooks/storybook/pull/21704)\n- React: Fix TS docgen for Functional Components [#21693](https://github.com/storybooks/storybook/pull/21693)\n- TypeScript: Add previewMainTemplate option to StorybookConfig [#21620](https://github.com/storybooks/storybook/pull/21620)\n- UI: Fix titles for addons/controls/panel tabs to support render fns and JSX elements [#21650](https://github.com/storybooks/storybook/pull/21650)\n- UI: Fix active state for menu iconbutton [#21666](https://github.com/storybooks/storybook/pull/21666)\n- CLI: Update renderer templates to provide correct typescript examples [#21647](https://github.com/storybooks/storybook/pull/21647)\n- Composition: Fix various CORS issues [#21682](https://github.com/storybooks/storybook/pull/21682)\n- Composition: Fix version switcher [#21621](https://github.com/storybooks/storybook/pull/21621)\n\n#### Dependency Upgrades\n\n- Pin rollup version to 3.19.1 [#21723](https://github.com/storybooks/storybook/pull/21723)\n\n## 7.0.0-rc.5 (March 20, 2023)\n\n#### Bug Fixes\n\n- UI: Fix IconButton to be in active state when corresponding menu is open [#21622](https://github.com/storybooks/storybook/pull/21622)\n- Angular: Fix `sb init` library support [#21675](https://github.com/storybooks/storybook/pull/21675)\n- CLI: Fix Vue3 template CSS [#21674](https://github.com/storybooks/storybook/pull/21674)\n- Core: fix storySort not reading from `.mjs` & `.cjs` files [#21637](https://github.com/storybooks/storybook/pull/21637)\n- Core: Fix cts/mts file extensions for config files [#21465](https://github.com/storybooks/storybook/pull/21465)\n- Core: Fix conflicting staticDirs case when -s flag is used [#21591](https://github.com/storybooks/storybook/pull/21591)\n- Angular: Fix source preview for angular stories [#21609](https://github.com/storybooks/storybook/pull/21609)\n\n## 7.0.0-rc.4 (March 17, 2023)\n\n#### Features\n\n- Angular: Add \"assets\" build option [#21116](https://github.com/storybooks/storybook/pull/21116)\n\n#### Bug Fixes\n\n- React: Fix missing framework options in shim [#21644](https://github.com/storybooks/storybook/pull/21644)\n- Docs: Update MDX `Link` component to be more user friendly [#21570](https://github.com/storybooks/storybook/pull/21570)\n- Links: Update LinkTo component [#21569](https://github.com/storybooks/storybook/pull/21569)\n- Vite: Allow vue files in importfn [#21550](https://github.com/storybooks/storybook/pull/21550)\n- Controls: Fix glitchy range control [#21459](https://github.com/storybooks/storybook/pull/21459)\n- CLI: Fix styling regression on CLI starter Introduction.mdx file [#21466](https://github.com/storybooks/storybook/pull/21466)\n- Addon-docs: Fix csf-plugin for Angular [#21629](https://github.com/storybooks/storybook/pull/21629)\n- Vite: Fix alias array converted incorrectly to an object [#21480](https://github.com/storybooks/storybook/pull/21480)\n- UI: Default white preview background [#21593](https://github.com/storybooks/storybook/pull/21593)\n- Vite: Fix dev and yarn pnp by adding lodash files to optimizeDeps.include [#21535](https://github.com/storybooks/storybook/pull/21535)\n- Composition: Fix blank page when ref is missing but specified in url [#21598](https://github.com/storybooks/storybook/pull/21598)\n- Core: Disable cache in dev-mode [#21574](https://github.com/storybooks/storybook/pull/21574)\n- Vite: Fix react-vite and projects with absolute path preview entries on Windows [#21545](https://github.com/storybooks/storybook/pull/21545)\n- UI: Change the way of preloading fonts [#21599](https://github.com/storybooks/storybook/pull/21599)\n- Core: Add preload and prefetch links for runtime.mjs and related files [#21594](https://github.com/storybooks/storybook/pull/21594)\n- React: Fix type inconsistencies in composeStories [#21575](https://github.com/storybooks/storybook/pull/21575)\n- UI: Fix WithTooltip to use visible prop instead of defaultVisible [#21589](https://github.com/storybooks/storybook/pull/21589)\n\n#### Maintenance\n\n- Blocks: Iprove error messages [#21615](https://github.com/storybooks/storybook/pull/21615)\n\n#### Build\n\n- Build: Regen lockfiles [#21576](https://github.com/storybooks/storybook/pull/21576)\n- Build: Fix coverage job in CircleCI [#21633](https://github.com/storybooks/storybook/pull/21633)\n- Vite: Update sandbox template for vue2 script [#20750](https://github.com/storybooks/storybook/pull/20750)\n\n## 7.0.0-rc.3 (March 14, 2023)\n\n#### Bug Fixes\n\n- Revert \"CLI: Upgrade non-core storybook packages better\" [#21583](https://github.com/storybooks/storybook/pull/21583)\n- CLI: Fix loading main.cjs files in automigration [#21582](https://github.com/storybooks/storybook/pull/21582)\n- Outline: Fixed a typo [#21515](https://github.com/storybooks/storybook/pull/21515)\n\n#### Maintenance\n\n- CLI: Improve MDX codemod message regarding Story.id deprecation [#21541](https://github.com/storybooks/storybook/pull/21541)\n\n## 7.0.0-rc.2 (March 13, 2023)\n\n#### Bug Fixes\n\n- CLI: Fix MDX codemod to update imports even when no stories are extracted [#21549](https://github.com/storybooks/storybook/pull/21549)\n- NextJS: Support next/font in Next v13.2.4 [#21560](https://github.com/storybooks/storybook/pull/21560)\n\n#### Build\n\n- Fix 'yarn build' command on windows systems [#21531](https://github.com/storybooks/storybook/pull/21531)\n\n## 7.0.0-rc.1 (March 10, 2023)\n\n#### Bug Fixes\n\n- Revert \"Merge pull request #21486 from storybookjs/norbert/wrap-for-pnp\" [#21532](https://github.com/storybooks/storybook/pull/21532)\n- Revert \"Merge pull request #21497 from storybookjs/tom/21432-replace-… [#21526](https://github.com/storybooks/storybook/pull/21526)\n- Csf-tools: Update babelParse to use legacy decorator syntax [#21506](https://github.com/storybooks/storybook/pull/21506)\n\n## 7.0.0-rc.0 (March 10, 2023)\n\n#### Bug Fixes\n\n- CLI: Upgrade non-core storybook packages better [#21508](https://github.com/storybooks/storybook/pull/21508)\n- Svelte: Pass all arguments to configure through to fix StoryStoreV6 [#21491](https://github.com/storybooks/storybook/pull/21491)\n- Core: Fix project root detection in yarn PnP without git [#21461](https://github.com/storybooks/storybook/pull/21461)\n- Telemetry: Replace isomorphic-unfetch with node-fetch in telemetry [#21497](https://github.com/storybooks/storybook/pull/21497)\n- Core: Fix builders/renderer PnP support [#21486](https://github.com/storybooks/storybook/pull/21486)\n- CLI: Require main.js without cache in automigrations [#21498](https://github.com/storybooks/storybook/pull/21498)\n\n#### Maintenance\n\n- CLI: Filter out internal static dir logging [#21137](https://github.com/storybooks/storybook/pull/21137)\n- Docs: Error if you try to index an MDX file in ssv6 [#21495](https://github.com/storybooks/storybook/pull/21495)\n\n#### Build\n\n- Build: add slash to fix windows test [#21518](https://github.com/storybooks/storybook/pull/21518)\n\n## 7.0.0-beta.64 (March 9, 2023)\n\n#### Bug Fixes\n\n- Vite: Fix HMR of preview.js [#21485](https://github.com/storybooks/storybook/pull/21485)\n- Vite: Make sure we update the vite import map when .mdx is added [#21490](https://github.com/storybooks/storybook/pull/21490)\n- Docs: Don't allow passing `of={}` with undefined prop [#21452](https://github.com/storybooks/storybook/pull/21452)\n- Composition: Restore support for v2 stories.json [#21354](https://github.com/storybooks/storybook/pull/21354)\n\n## 7.0.0-beta.63 (March 9, 2023)\n\n#### Bug Fixes\n\n- Story Index: Fix storySort parsing for parameters variable [#21481](https://github.com/storybooks/storybook/pull/21481)\n- React/Vite: Add some missing types [#21449](https://github.com/storybooks/storybook/pull/21449)\n- Docs: Cleanup with Promise instead of setTimeout [#21476](https://github.com/storybooks/storybook/pull/21476)\n- Docs: Re-render MDX files when you fix a thrown error [#21454](https://github.com/storybooks/storybook/pull/21454)\n- CLI: Fix mdx-to-csf codemod blocks imports [#21448](https://github.com/storybooks/storybook/pull/21448)\n\n#### Maintenance\n\n- CLI: Copy tweaks for automigrations [#21475](https://github.com/storybooks/storybook/pull/21475)\n- CLI: Warn the user when stories glob does not match any file [#21392](https://github.com/storybooks/storybook/pull/21392)\n- Docs: Use `Of` type in `useOf` argument [#21442](https://github.com/storybooks/storybook/pull/21442)\n- Telemetry: Is interactive shell [#21436](https://github.com/storybooks/storybook/pull/21436)\n\n## 7.0.0-beta.62 (March 6, 2023)\n\n#### Bug Fixes\n\n- Vite: Add react docgen types [#21338](https://github.com/storybooks/storybook/pull/21338)\n- Core: Print errors in `withTelemetry` before prompting [#21407](https://github.com/storybooks/storybook/pull/21407)\n- Add Angular Builder Codemods [#21409](https://github.com/storybooks/storybook/pull/21409)\n- Docs: Use async import rather than require in docs [#21402](https://github.com/storybooks/storybook/pull/21402)\n- Docs: Don't warn if we find the same entry twice [#21403](https://github.com/storybooks/storybook/pull/21403)\n- Telemetry: Ensure we report errors even when unexpected things happen [#21416](https://github.com/storybooks/storybook/pull/21416)\n- CLI: Fix versions.ts to install latest prerelease packages [#21418](https://github.com/storybooks/storybook/pull/21418)\n- Core: Remove pointless `module.hot.decline()` in addons [#21421](https://github.com/storybooks/storybook/pull/21421)\n- Docs: Allow ArgTable usage unattached [#21371](https://github.com/storybooks/storybook/pull/21371)\n\n#### Maintenance\n\n- Addon-docs: Polish styling for 7.0 [#21255](https://github.com/storybooks/storybook/pull/21255)\n\n## 7.0.0-beta.61 (March 4, 2023)\n\n#### Features\n\n- Docs: Show MDX errors using our error overlay [#21369](https://github.com/storybooks/storybook/pull/21369)\n\n#### Bug Fixes\n\n- Core: Remove state deprecation warnings by default [#21367](https://github.com/storybooks/storybook/pull/21367)\n- Core: Fix default export storySort handling [#21389](https://github.com/storybooks/storybook/pull/21389)\n- Vue3: Add slot TS types [#21359](https://github.com/storybooks/storybook/pull/21359)\n- Docs: Fix issue with referencing non-story files with names similar or equal to docs files [#21348](https://github.com/storybooks/storybook/pull/21348)\n\n#### Maintenance\n\n- Docs: Update invalid `<Meta of={}>` error to be more helpful. [#21365](https://github.com/storybooks/storybook/pull/21365)\n\n#### Dependency Upgrades\n\n- Upgrade react-docgen-typescript-plugin for TS4.8 [#21380](https://github.com/storybooks/storybook/pull/21380)\n\n## 7.0.0-beta.60 (March 3, 2023)\n\n#### Bug Fixes\n\n- Core: Fix storySort parsing in preview.js with default export [#21353](https://github.com/storybooks/storybook/pull/21353)\n- CLI: Remove the workspace root flag from the install command for yarn2 [#21356](https://github.com/storybooks/storybook/pull/21356)\n- Svelte/Vite: Prevent crash when no svelte.config file [#21339](https://github.com/storybooks/storybook/pull/21339)\n- Use stable Next.js v13.2.0 next/font [#21247](https://github.com/storybooks/storybook/pull/21247)\n\n#### Dependency Upgrades\n\n- Bump version of get-tarball [#21355](https://github.com/storybooks/storybook/pull/21355)\n\n## 7.0.0-beta.59 (March 2, 2023)\n\n#### Bug Fixes\n\n- CLI: Improve yarn/pnpm workspaces support for adding dependencies in CLI [#21331](https://github.com/storybooks/storybook/pull/21331)\n- Core: Fix `manager.js` ignored when `sideEffects:false` in `package.json` [#21335](https://github.com/storybooks/storybook/pull/21335)\n- Vite: Fix glob path creation for Windows [#21305](https://github.com/storybookjs/storybook/pull/21305)\n\n## 7.0.0-beta.58 (March 1, 2023)\n\n#### Bug Fixes\n\n- UI: Fix enableShortcuts, exclude it from being persisted [#21291](https://github.com/storybooks/storybook/pull/21291)\n- NextJS: Fix type references in Next.js >= 13.2.0 [#21304](https://github.com/storybooks/storybook/pull/21304)\n- CLI: Fix formatting of autodocs-true automigration [#21314](https://github.com/storybooks/storybook/pull/21314)\n- Docs: Remove warning when browsing away in React [#21214](https://github.com/storybooks/storybook/pull/21214)\n\n#### Maintenance\n\n- CLI: Fix security report around `download-tarball` package [#21201](https://github.com/storybooks/storybook/pull/21201)\n- CSF-Tools/Codemods: Un-bundle babel, limit semver range of babel packages [#21326](https://github.com/storybooks/storybook/pull/21326)\n\n## 7.0.0-beta.57 (March 1, 2023)\n\n#### Bug Fixes\n\n- CSF-tools/Codemods: Pre-bundle all babel related packages [#21301](https://github.com/storybooks/storybook/pull/21301)\n- UI: Fix height adjustment in ZoomElement in Safari [#21174](https://github.com/storybooks/storybook/pull/21174)\n\n## 7.0.0-beta.56 (March 1, 2023)\n\n#### Bug Fixes\n\n- Core: Improve framework field validation [#21299](https://github.com/storybooks/storybook/pull/21299)\n- SvelteKit: Only disable SSR when building, not serving [#21290](https://github.com/storybooks/storybook/pull/21290)\n- CLI: Account for legacy framework values in automigration [#21184](https://github.com/storybooks/storybook/pull/21184)\n- TypeScript: Add `env` type to BuilderOptions [#21173](https://github.com/storybooks/storybook/pull/21173)\n- Core: Reverse order of project decorators [#21182](https://github.com/storybooks/storybook/pull/21182)\n\n#### Maintenance\n\n- React-webpack: Fix dependencies to remove peerDep warnings [#21278](https://github.com/storybooks/storybook/pull/21278)\n\n#### Build\n\n- Build: Improve sandbox task logs [#21296](https://github.com/storybooks/storybook/pull/21296)\n\n## 7.0.0-beta.55 (February 27, 2023)\n\n#### Bug Fixes\n\n- NextJS: Fix next/babel preset [#21104](https://github.com/storybooks/storybook/pull/21104)\n- CLI: Pass config dir from upgrade to automigration [#21270](https://github.com/storybooks/storybook/pull/21270)\n- Docs: Show errors when stories throw in docs [#21212](https://github.com/storybooks/storybook/pull/21212)\n- CLI: Fix performance regression of storybook dev [#21269](https://github.com/storybooks/storybook/pull/21269)\n\n#### Build\n\n- Build: Remove jest_workaround swc package by adding extra jest.mock functions [#21249](https://github.com/storybooks/storybook/pull/21249)\n- Build: Upgrade playwright & re-enable bench [#21241](https://github.com/storybooks/storybook/pull/21241)\n\n## 7.0.0-beta.54 (February 24, 2023)\n\n#### Features\n\n- Core: Add `preview.js` default export support [#21227](https://github.com/storybooks/storybook/pull/21227)\n- TypeScript: Add preview type and update CLI template [#21205](https://github.com/storybooks/storybook/pull/21205)\n- Autodocs: Hide Stories block when only primary story exists [#21178](https://github.com/storybooks/storybook/pull/21178)\n- CLI: Add automigration for GFM in MDX [#21186](https://github.com/storybooks/storybook/pull/21186)\n\n#### Bug Fixes\n\n- Docs: Remove `react-dom@18` warning in docs [#21197](https://github.com/storybooks/storybook/pull/21197)\n- mdx-to-csf codemod: Fix wrong export referenced in generated mdx [#21226](https://github.com/storybooks/storybook/pull/21226)\n- Preact: Enable ts plugin by default [#21225](https://github.com/storybooks/storybook/pull/21225)\n- pnpm: Fix run command for pnpm API [#21165](https://github.com/storybooks/storybook/pull/21165)\n- Angular: Properly destroy component when switching to another Story [#21219](https://github.com/storybooks/storybook/pull/21219)\n- CLI: Fix SvelteKit automigration package name [#21210](https://github.com/storybooks/storybook/pull/21210)\n- Angular: Initialize .storybook without references to root in sub projects [#21202](https://github.com/storybooks/storybook/pull/21202)\n\n#### Maintenance\n\n- CLI: Only run useful automigrations on init [#21203](https://github.com/storybooks/storybook/pull/21203)\n\n#### Build\n\n- Build: Disable broken cra-bench [#21238](https://github.com/storybooks/storybook/pull/21238)\n- Revert \"Remove vue-cli as sandbox template is currently busted\" [#21237](https://github.com/storybooks/storybook/pull/21237)\n- Build: Add mixed exports test case to composeConfigs [#21230](https://github.com/storybooks/storybook/pull/21230)\n- Build: pass debug option to sandbox generate task [#21200](https://github.com/storybooks/storybook/pull/21200)\n- Build: add @storybook/bench [#21199](https://github.com/storybooks/storybook/pull/21199)\n- Build: Fix Playwright to v1.30.0 [#21194](https://github.com/storybooks/storybook/pull/21194)\n\n## 7.0.0-beta.53 (February 22, 2023)\n\n#### Features\n\n- Codemod: Convert `.stories.mdx` to MDX and CSF [#21073](https://github.com/storybooks/storybook/pull/21073)\n\n#### Bug Fixes\n\n- Csf Tools: Fix overriding scalar named export values [#21190](https://github.com/storybooks/storybook/pull/21190)\n- Csf Tools: Support satisfies and as TS operator with module.exports [#21188](https://github.com/storybooks/storybook/pull/21188)\n- Core: try harder to resolve `.mjs` files for the browser entries [#21161](https://github.com/storybooks/storybook/pull/21161)\n- CLI: Fix jscodeshift error: env: node\\r: No such file or directory [#21180](https://github.com/storybooks/storybook/pull/21180)\n- Angular: Fix NG0800 error [#21181](https://github.com/storybooks/storybook/pull/21181)\n- Addon-docs: Fix style bleeding [#21150](https://github.com/storybooks/storybook/pull/21150)\n- CLI: Improve how automigrations read `main.js` [#21168](https://github.com/storybooks/storybook/pull/21168)\n\n#### Build\n\n- Build: Add check step to `ci:daily` workflow [#21169](https://github.com/storybooks/storybook/pull/21169)\n\n## 7.0.0-beta.52 (February 21, 2023)\n\n#### Features\n\n- Core: Coalesce multiple indexing errors into one [#21114](https://github.com/storybooks/storybook/pull/21114)\n- Core: Don't crash when there are errors indexing [#21112](https://github.com/storybooks/storybook/pull/21112)\n\n#### Bug Fixes\n\n- CLI: Fix CRA init, ensure the new version of the preset [#21166](https://github.com/storybooks/storybook/pull/21166)\n- Angular: Fix 'isStandalone' function not available error [#21167](https://github.com/storybooks/storybook/pull/21167)\n- Angular: Fix constructor dependencies [#21059](https://github.com/storybooks/storybook/pull/21059)\n- NextJS: Add missing dependencies to fix pnpm [#21162](https://github.com/storybooks/storybook/pull/21162)\n\n## 7.0.0-beta.51 (February 20, 2023)\n\n#### Features\n\n- CLI: Improve monorepo support in `automigrate` and revamp framework-related migrations [#20647](https://github.com/storybooks/storybook/pull/20647)\n\n#### Bug Fixes\n\n- UI: Correctly detect Safari in browser supports CSS Zoom [#21163](https://github.com/storybooks/storybook/pull/21163)\n- Web-components: Fix StorybookConfig of webcomponents-webpack5 [#21144](https://github.com/storybooks/storybook/pull/21144)\n- Storysource: Fallback to the `docs.source.originalSource` parameter [#21159](https://github.com/storybooks/storybook/pull/21159)\n- UI: Fix skip to canvas link style [#21021](https://github.com/storybooks/storybook/pull/21021)\n- Vue2: Fix events to use bracket notation [#20754](https://github.com/storybooks/storybook/pull/20754)\n\n### Maintenance\n\n- Maintenance: Fix type errors on automigrate `check` step [#21164](https://github.com/storybooks/storybook/pull/21164)\n- Core: Rename `framework` parameter to `renderer` [#21108](https://github.com/storybooks/storybook/pull/21108)\n- Docs: Remove `DocsOptions.disable` [#21098](https://github.com/storybooks/storybook/pull/21098)\n\n## 7.0.0-beta.50 (February 18, 2023)\n\n#### Bug Fixes\n\n- Revert upgrade to react-docgen-typescript-plugin [#21147](https://github.com/storybooks/storybook/pull/21147)\n- Revert Vite fix storysource addon support [#21146](https://github.com/storybooks/storybook/pull/21146)\n- UI: Fix Canvas zoom height [#21138](https://github.com/storybooks/storybook/pull/21138)\n- Addon-interaction: Fix tooltips don't disappear correctly [#21105](https://github.com/storybooks/storybook/pull/21105)\n- UI: Fix CSS zoom in Safari [#21069](https://github.com/storybooks/storybook/pull/21069)\n\n#### Maintenance\n\n- Storysource: Rename \"Story\" tab to \"Code\" [#21132](https://github.com/storybooks/storybook/pull/21132)\n- TypeScript: Fix `@ts-expect-error` strict types [#20981](https://github.com/storybooks/storybook/pull/20981)\n- UI: Update border color to match Design System proposal [#20660](https://github.com/storybooks/storybook/pull/20660)\n- CLI: Don't render issue template reproduction section with shell [#21128](https://github.com/storybooks/storybook/pull/21128)\n\n#### Dependency Upgrades\n\n- Vite: Update dep range for @storybook/mdx1-csf [#21123](https://github.com/storybooks/storybook/pull/21123)\n\n## 7.0.0-beta.49 (February 17, 2023)\n\n#### Bug Fixes\n\n- NextJS: Fix static dirs lookup [#21119](https://github.com/storybooks/storybook/pull/21119)\n- Svelte/Vue: Use Vite by default [#21002](https://github.com/storybooks/storybook/pull/21002)\n- Storyshots: Fix issue with default export in main.js [#21097](https://github.com/storybooks/storybook/pull/21097)\n- Args: Fix boolean arg types parsing and encoding [#21102](https://github.com/storybooks/storybook/pull/21102)\n\n#### Maintenance\n\n- CRA: Add CRA preset to monorepo [#21107](https://github.com/storybooks/storybook/pull/21107)\n- Web-components: Drop lit1 support [#21106](https://github.com/storybooks/storybook/pull/21106)\n- NextJS: Fix some dependency warnings [#21117](https://github.com/storybooks/storybook/pull/21117)\n- Types: Remove unnecessary dependencies [#20993](https://github.com/storybooks/storybook/pull/20993)\n\n#### Build\n\n- Build: regen lockfiles [#21126](https://github.com/storybooks/storybook/pull/21126)\n\n## 7.0.0-beta.48 (February 15, 2023)\n\n#### Features\n\n- Interactions: Add debugger to the addon panel [#21088](https://github.com/storybooks/storybook/pull/21088)\n\n#### Bug Fixes\n\n- CLI: Fix pnp support & add auto-detection [#21046](https://github.com/storybooks/storybook/pull/21046)\n- Vite: Fix storysource addon support [#21096](https://github.com/storybooks/storybook/pull/21096)\n- NextJS: Fix dynamic source snippets [#21029](https://github.com/storybooks/storybook/pull/21029)\n- Addon-docs: Fix source snippets for duplicate source blocks [#20915](https://github.com/storybooks/storybook/pull/20915)\n\n#### Maintenance\n\n- TypeScript: Fix some unsound type check errors [#21081](https://github.com/storybooks/storybook/pull/21081)\n\n#### Build\n\n- Build: Fix yarn build command [#21099](https://github.com/storybooks/storybook/pull/21099)\n- Tech: upgrades [#21086](https://github.com/storybooks/storybook/pull/21086)\n\n#### Dependency Upgrades\n\n- Remove unused dependencies from core-common [#20994](https://github.com/storybooks/storybook/pull/20994)\n- Upgrade react-docgen-typescript-plugin [#21095](https://github.com/storybooks/storybook/pull/21095)\n\n## 7.0.0-beta.47 (February 14, 2023)\n\n#### Features\n\n- Vite: Support legacyMdx1 fallback flag [#20823](https://github.com/storybooks/storybook/pull/20823)\n- CLI: Automigration to update `mdx` stories config [#21035](https://github.com/storybooks/storybook/pull/21035)\n\n#### Bug Fixes\n\n- Vue3: Fix CSF2 support with decorators [#20995](https://github.com/storybooks/storybook/pull/20995)\n- CLI: Do not use modern TS assets in legacy TS projects [#20458](https://github.com/storybooks/storybook/pull/20458)\n- CLI: Fix conflicts in static dirs [#21064](https://github.com/storybooks/storybook/pull/21064)\n\n#### Maintenance\n\n- CLI: Update init script for react-native v6.5 [#20719](https://github.com/storybooks/storybook/pull/20719)\n- CLI: Re-enable vue-vite in new-frameworks automigration [#20970](https://github.com/storybooks/storybook/pull/20970)\n\n## 7.0.0-beta.46 (February 10, 2023)\n\n#### Features\n\n- CLI: Add Solid integration [#20991](https://github.com/storybooks/storybook/pull/20991)\n- Viewport: Add `defaultOrientation` parameter [#21048](https://github.com/storybooks/storybook/pull/21048)\n\n#### Bug Fixes\n\n- CLI: Account for pnp when creating main.js in `storybook init` [#21049](https://github.com/storybooks/storybook/pull/21049)\n- Core: Detect mdx2 errors and provide guidance to fix them [#20917](https://github.com/storybooks/storybook/pull/20917)\n- Angular: provideHttpClient when HttpClientModule is present in the imports array [#21028](https://github.com/storybooks/storybook/pull/21028)\n\n#### Build\n\n- Build: Allow `stories` folder to be served by vite sandboxes [#21022](https://github.com/storybooks/storybook/pull/21022)\n\n## 7.0.0-beta.45 (February 9, 2023)\n\n#### Features\n\n- UI: Menu design upgrade [#20898](https://github.com/storybooks/storybook/pull/20898)\n\n#### Bug Fixes\n\n- Vite: Use posix paths for glob [#21013](https://github.com/storybooks/storybook/pull/21013)\n\n#### Maintenance\n\n- Telemetry: Hash error messages [#20990](https://github.com/storybooks/storybook/pull/20990)\n\n## 7.0.0-beta.44 (February 7, 2023)\n\n#### Features\n\n- Feature: Add woff2 support for builder-manager [#20962](https://github.com/storybooks/storybook/pull/20962)\n- Feature: Add super early node version check [#20964](https://github.com/storybooks/storybook/pull/20964)\n- Csf-tools: Add `satisfies` support to ConfigFile [#20936](https://github.com/storybooks/storybook/pull/20936)\n\n#### Bug Fixes\n\n- Angular: Fix changeDetectorRef should be defined [#20984](https://github.com/storybooks/storybook/pull/20984)\n- Angular: Fix standalone components to be included in the imports array [#20983](https://github.com/storybooks/storybook/pull/20983)\n- CLI: Fix Introduction MDX for Next.js and Typescript [#20798](https://github.com/storybooks/storybook/pull/20798)\n- CLI: Fix detection of JS projects with type checking [#20944](https://github.com/storybooks/storybook/pull/20944)\n- UI: Fix fonts missing/warnings [#20957](https://github.com/storybooks/storybook/pull/20957)\n- Core: Undo AST main.js check in validateConfigFile [#20952](https://github.com/storybooks/storybook/pull/20952)\n- Csf-tools: Fix error handling for storySort variable references [#20930](https://github.com/storybooks/storybook/pull/20930)\n\n#### Maintenance\n\n- Core: Fix missing dependency for core-server [#20989](https://github.com/storybooks/storybook/pull/20989)\n- CLI: Add a default background to newly initialized storybooks [#20982](https://github.com/storybooks/storybook/pull/20982)\n- Svelte/Vite: Remove `svelte-options` [#20942](https://github.com/storybooks/storybook/pull/20942)\n- Vite: Correctly preserve existing vite envPrefix config [#20918](https://github.com/storybooks/storybook/pull/20918)\n\n#### Dependencies\n\n- Deps: Upgrade glob-promise [#20959](https://github.com/storybooks/storybook/pull/20959)\n- Deps: Update glob for storyshots [#20954](https://github.com/storybooks/storybook/pull/20954)\n\n#### Build\n\n- Build: upgrade yarn [#20986](https://github.com/storybooks/storybook/pull/20986)\n- Build: add more sandboxes to CI tests [#20892](https://github.com/storybooks/storybook/pull/20892)\n\n## 7.0.0-beta.43 (February 4, 2023)\n\n#### Bug Fixes\n\n- Core: Fix globs on windows [#20929](https://github.com/storybooks/storybook/pull/20929)\n- Revert addon-docs: update story index generator [#20809](https://github.com/storybooks/storybook/pull/20809)\n\n## 7.0.0-beta.42 (February 4, 2023)\n\n#### Features\n\n- CLI: Add type annotations in javascript main config files [#20887](https://github.com/storybooks/storybook/pull/20887)\n- UI: Tab Improvements [#20783](https://github.com/storybooks/storybook/pull/20783)\n\n#### Build\n\n- Build: fix next [#20924](https://github.com/storybooks/storybook/pull/20924)\n\n#### Dependency Upgrades\n\n- Upgrade jscodeshift to 0.14.0 [#20925](https://github.com/storybooks/storybook/pull/20925)\n- Upgrade glob to 8.1.0 [#20927](https://github.com/storybooks/storybook/pull/20927)\n\n## 7.0.0-beta.41 (February 3, 2023)\n\n#### Features\n\n- UI: Add nunito sans font [#20846](https://github.com/storybooks/storybook/pull/20846)\n\n#### Bug Fixes\n\n- Vite/Addon-docs: Fix customization of MDX plugins [#20116](https://github.com/storybooks/storybook/pull/20116)\n- Angular: Support NoopAnimationsModule [#20868](https://github.com/storybooks/storybook/pull/20868)\n- Core: Fix index error handling [#20906](https://github.com/storybooks/storybook/pull/20906)\n- Outline: Fix outline initial state [#20818](https://github.com/storybooks/storybook/pull/20818)\n\n#### Maintenance\n\n- CLI: Remove the deprecated `--no-manager-cache` flag [#20895](https://github.com/storybooks/storybook/pull/20895)\n\n#### Build\n\n- Build: Change `rootDir` in TS plugin [#20911](https://github.com/storybooks/storybook/pull/20911)\n- Build: Improve task log and error messages for event log [#20902](https://github.com/storybooks/storybook/pull/20902)\n- Build: minor fixes [#20894](https://github.com/storybooks/storybook/pull/20894)\n\n## 7.0.0-beta.40 (February 2, 2023)\n\n#### Features\n\n- Addo-docs: Turn on autodocs for CSF with attached meta [#20867](https://github.com/storybooks/storybook/pull/20867)\n\n#### Bug Fixes\n\n- Vue3: Fix args losing reactivity when using decorators [#20854](https://github.com/storybooks/storybook/pull/20854)\n- Doc Blocks: Fix styling and parameter bugs [#20803](https://github.com/storybooks/storybook/pull/20803)\n- Addon-docs: Export controls from doc blocks [#20806](https://github.com/storybooks/storybook/pull/20806)\n- Webpack: Support builder options from framework [#20842](https://github.com/storybooks/storybook/pull/20842)\n\n## 7.0.0-beta.39 (February 1, 2023)\n\n#### Features\n\n- Core: return address of dev server from buildDevStandalone [#20820](https://github.com/storybooks/storybook/pull/20820)\n- Addons: Fix env variables not available inside addons [#20834](https://github.com/storybooks/storybook/pull/20834)\n- CLI: Add warning when main config does not use default exports [#20802](https://github.com/storybooks/storybook/pull/20802)\n\n#### Bug Fixes\n\n- SvelteKit: Disable failing `vite-plugin-sveltekit-guard` [#20870](https://github.com/storybooks/storybook/pull/20870)\n\n#### Maintenance\n\n- Core: Remove core-js as a dependency [#20833](https://github.com/storybooks/storybook/pull/20833)\n\n#### Build\n\n- Build: cleanup CI config [#20853](https://github.com/storybooks/storybook/pull/20853)\n- Change forceReRender story to forceRemount [#20752](https://github.com/storybooks/storybook/pull/20752)\n\n## 7.0.0-beta.38 (January 31, 2023)\n\n#### Features\n\n- CLI: Generate main config with default exports [#20797](https://github.com/storybooks/storybook/pull/20797)\n\n#### Bug Fixes\n\n- CLI: Only add dependencies on sb init if they do not exist [#20811](https://github.com/storybooks/storybook/pull/20811)\n- CLI: Install prerelease of @storybook/testing-library in CLI starters [#20819](https://github.com/storybooks/storybook/pull/20819)\n\n#### Dependency Upgrades\n\n- Update lazy-universal-dotenv & regen lockfile [#20832](https://github.com/storybooks/storybook/pull/20832)\n- Instrumenter: Remove unused core-js dependency [#20831](https://github.com/storybooks/storybook/pull/20831)\n\n## 7.0.0-beta.37 (January 31, 2023)\n\nFailed publish\n\n## 7.0.0-beta.36 (January 28, 2023)\n\n#### Features\n\n- Core: Story context is prepared before for supporting fine grained updates [#20755](https://github.com/storybooks/storybook/pull/20755)\n- Addon-docs: New Markdown block [#20796](https://github.com/storybooks/storybook/pull/20796)\n- Addon-docs: Disable Markdown transclusion and support ?raw .md files [#20790](https://github.com/storybooks/storybook/pull/20790)\n\n#### Bug Fixes\n\n- Addon-docs: Allow using `<Source code=\"..\" />` unattached. [#20807](https://github.com/storybooks/storybook/pull/20807)\n- Vite: Replace vite-plugin-externals with custom plugin [#20698](https://github.com/storybooks/storybook/pull/20698)\n- Sveltekit: Ensure SSR is disabled [#20804](https://github.com/storybooks/storybook/pull/20804)\n\n## 7.0.0-beta.35 (January 27, 2023)\n\n#### Bug Fixes\n\n- Storysource: Support CSF3 object exports, co-exist with addon-docs [#20799](https://github.com/storybooks/storybook/pull/20799)\n- Vite: Do not pre-bundle @vitejs/plugin-vue [#20787](https://github.com/storybooks/storybook/pull/20787)\n- CLI: Fix new-frameworks automigration in angular projects [#20788](https://github.com/storybooks/storybook/pull/20788)\n\n## 7.0.0-beta.34 (January 26, 2023)\n\n#### Features\n\n- Addon-docs: Add legacy transitional support for MDX1 [#20747](https://github.com/storybooks/storybook/pull/20747)\n\n#### Bug Fixes\n\n- CLI: Fix global flag corner case [#20776](https://github.com/storybooks/storybook/pull/20776)\n- Csf-tools: Fix ConfigFile string literal property handling [#20785](https://github.com/storybooks/storybook/pull/20785)\n- Angular: Ensure docsMode flag has effect [#20711](https://github.com/storybooks/storybook/pull/20711)\n- Angular: Use Providers in boostrapApplication option [#20746](https://github.com/storybooks/storybook/pull/20746)\n- WebComponents: Fix Button type error [#20722](https://github.com/storybooks/storybook/pull/20722)\n\n#### Build\n\n- Verify consistency of anonymous id [#20781](https://github.com/storybooks/storybook/pull/20781)\n- Build: fix playwright unsynced version in CI [#20778](https://github.com/storybooks/storybook/pull/20778)\n- Upgrade playwright [#20777](https://github.com/storybooks/storybook/pull/20777)\n\n#### Dependency Upgrades\n\n- Deps: Upgrade fs-extra to 11.1.0 [#20772](https://github.com/storybooks/storybook/pull/20772)\n\n## 7.0.0-beta.33 (January 24, 2023)\n\n#### Features\n\n- Addon-docs: Allow `<Story/>` to reference the first story [#20765](https://github.com/storybooks/storybook/pull/20765)\n\n#### Bug Fixes\n\n- Angular: Fix issue if BrowserAnimationsModule is imported [#20709](https://github.com/storybooks/storybook/pull/20709)\n- Core: Fix issue with inconsistent CSF ordering in sandboxes [#20705](https://github.com/storybooks/storybook/pull/20705)\n- Fixed paths in generated main.cjs for the default sandbox on Windows [#20724](https://github.com/storybooks/storybook/pull/20724)\n- Blocks: Ignore known blocks with global CSS selector [#20757](https://github.com/storybooks/storybook/pull/20757)\n\n#### Maintenance\n\n- Docs: Make reference stories consistent [#20759](https://github.com/storybooks/storybook/pull/20759)\n- Blocks: New Canvas API [#20723](https://github.com/storybooks/storybook/pull/20723)\n\n#### Build\n\n- Fix vue sandbox: remove the lang=ts in a file, that should remain agnostic [#20768](https://github.com/storybooks/storybook/pull/20768)\n- Build: do not treat check as a cache-able operation && cleanup [#20762](https://github.com/storybooks/storybook/pull/20762)\n\n## 7.0.0-beta.32 (January 24, 2023)\n\n#### Features\n\n- CLI: Add init support for qwik projects [#20411](https://github.com/storybooks/storybook/pull/20411)\n\n#### Bug Fixes\n\n- Vue3: Fix reactive args + many vue app creation issue [#20712](https://github.com/storybooks/storybook/pull/20712)\n- Docs: Allow \"declaring\" stories with `story={}` [#20702](https://github.com/storybooks/storybook/pull/20702)\n- Addon-links: Fix the d.ts file, deprecate LinkTo [#20671](https://github.com/storybooks/storybook/pull/20671)\n- CLI: Fix package execution for npm package manager [#20708](https://github.com/storybooks/storybook/pull/20708)\n\n#### Maintenance\n\n- Upgrade react-popper-tooltip [#20736](https://github.com/storybooks/storybook/pull/20736)\n- CLI: Upgrade automigrations to use new safe helpers [#20693](https://github.com/storybooks/storybook/pull/20693)\n- Csf-tools: Add helpers to get name from node path [#20691](https://github.com/storybooks/storybook/pull/20691)\n- Build: remove preact-webpack5 from babelrc automigration [#20706](https://github.com/storybooks/storybook/pull/20706)\n\n#### Build\n\n- Fix windows snapshot [#20707](https://github.com/storybooks/storybook/pull/20707)\n\n## 7.0.0-beta.31 (January 20, 2023)\n\n#### Features\n\n- Docs: Added source stories and updated API [#20603](https://github.com/storybooks/storybook/pull/20603)\n- Docs: Implement Controls block [#20683](https://github.com/storybooks/storybook/pull/20683)\n- Docs: Created `ArgTypes` component and stories [#20664](https://github.com/storybooks/storybook/pull/20664)\n- Docs: Show primary story description and headline in autodocs [#20604](https://github.com/storybooks/storybook/pull/20604)\n\n#### Bug Fixes\n\n- Source-loader: Fix export default variable references [#20688](https://github.com/storybooks/storybook/pull/20688)\n\n#### Maintenance\n\n- CLI: Make missing-babelrc an automatic migration [#20689](https://github.com/storybooks/storybook/pull/20689)\n- Addon-docs: Update story index generator glob [#20679](https://github.com/storybooks/storybook/pull/20679)\n- Docs: Move validation logic into `context.resolveOf` [#20662](https://github.com/storybooks/storybook/pull/20662)\n- Csf-plugin: Move source to docs.source.originalSource [#20665](https://github.com/storybooks/storybook/pull/20665)\n\n#### Build\n\n- Fix ui example story [#20692](https://github.com/storybooks/storybook/pull/20692)\n\n## 7.0.0-beta.30 (January 18, 2023)\n\n#### Features\n\n- UI: Add Sun, Moon, Sidebyside, and stacked icons [#20621](https://github.com/storybooks/storybook/pull/20621)\n- Angular: Add multi-project setup for ng workspaces [#20559](https://github.com/storybooks/storybook/pull/20559)\n- Addon-docs: Support @deprecated jsdoc tag [#20154](https://github.com/storybooks/storybook/pull/20154)\n- Csf-plugin: Support meta description comments [#20632](https://github.com/storybooks/storybook/pull/20632)\n\n#### Bug Fixes\n\n- Core: Fix `core` preset default value [#20646](https://github.com/storybooks/storybook/pull/20646)\n- Addon-docs: Fix issue with unattached `.mdx` files [#20661](https://github.com/storybooks/storybook/pull/20661)\n- Webpack: aAd error catching when template is not set [#20669](https://github.com/storybooks/storybook/pull/20669)\n- Addons: Fix Viewport resetting shortcut key not working [#20167](https://github.com/storybooks/storybook/pull/20167)\n- Core: Show \"booting\" progress until story is specified or errors [#20425](https://github.com/storybooks/storybook/pull/20425)\n- Vue: Update events binding in Vue render [#19860](https://github.com/storybooks/storybook/pull/19860)\n- Addon-actions: Fix webpack hot reload code in manager bundle [#20649](https://github.com/storybooks/storybook/pull/20649)\n- UI: Fix HMR issue in Manager UI [#20654](https://github.com/storybooks/storybook/pull/20654)\n\n#### Maintenance\n\n- Docs: Refactor props of Story block [#20530](https://github.com/storybooks/storybook/pull/20530)\n- Vite: TypeScript type cleanup [#20642](https://github.com/storybooks/storybook/pull/20642)\n\n#### Build\n\n- Add required jobs to daily workflow [#20263](https://github.com/storybooks/storybook/pull/20263)\n- Fix typings files to ensure this the check command succeeds [#20598](https://github.com/storybooks/storybook/pull/20598)\n\n#### Dependency Upgrades\n\n- Svelte: Remove babel/core peer dep [#20650](https://github.com/storybooks/storybook/pull/20650)\n\n## 7.0.0-beta.29 (January 17, 2023)\n\n#### Features\n\n- CLI: Add codemod to upgrade deprecated types [#20618](https://github.com/storybooks/storybook/pull/20618)\n- CLI: overhaul `storybook repro` command and rename it to `storybook sandbox` [#20507](https://github.com/storybooks/storybook/pull/20507)\n- Vue3: Add source decorator vue template and setup script + supports of multi slots [#20498](https://github.com/storybooks/storybook/pull/20498)\n\n#### Bug Fixes\n\n- Angular: Fix handling of docsMode option in angular builder [#20608](https://github.com/storybooks/storybook/pull/20608)\n- UI: Bring back support for `favicon.ico` [#20612](https://github.com/storybooks/storybook/pull/20612)\n- CLI: Fix missing css import on Vue3 button [#20470](https://github.com/storybooks/storybook/pull/20470)\n- Codemods: Fix `csf-2-to-3` ignores Typescript types [#20273](https://github.com/storybooks/storybook/pull/20273)\n- NextJS: Fix image loader [#20615](https://github.com/storybooks/storybook/pull/20615)\n- Storyshots: Fix transpilation [#20630](https://github.com/storybooks/storybook/pull/20630)\n\n#### Maintenance\n\n- React: Change deprecated `React.VFC` to `React.FC` [#20619](https://github.com/storybooks/storybook/pull/20619)\n\n#### Dependency Upgrades\n\n- Upgrade babel-loader to ^9.0.0 [#20577](https://github.com/storybooks/storybook/pull/20577)\n\n## 7.0.0-beta.28 (January 14, 2023)\n\n#### Maintenance\n\n- CSF: Remove deprecated ArgTypes.defaultValue [#19492](https://github.com/storybooks/storybook/pull/19492)\n\n#### Dependency Upgrades\n\n- Addon-controls: Fix version of preview api [#20622](https://github.com/storybooks/storybook/pull/20622)\n\n## 7.0.0-beta.27 (January 14, 2023)\n\n#### Features\n\n- CLI: Add \"missing-babelrc\" automigration [#20341](https://github.com/storybooks/storybook/pull/20341)\n\n#### Bug Fixes\n\n- Angular: Fix isStandaloneComponent check [#20295](https://github.com/storybooks/storybook/pull/20295)\n- Blocks: Do not copy code snippet when text inside preview is selected [#19788](https://github.com/storybooks/storybook/pull/19788)\n- Vue: Fix type.name check in extractArgTypes [#19956](https://github.com/storybooks/storybook/pull/19956)\n- TypeScript: Add children to CanvasProps [#20451](https://github.com/storybooks/storybook/pull/20451)\n- CLI: Fix angular/core version in init using devDependencies [#20609](https://github.com/storybooks/storybook/pull/20609)\n\n#### Maintenance\n\n- Svelte: don't add `svelte-loader` nor `svelte` when initializing Svelte projects [#18799](https://github.com/storybooks/storybook/pull/18799)\n- Core: prepareMeta function similar to prepareStory [#20592](https://github.com/storybooks/storybook/pull/20592)\n\n#### Build\n\n- Build: Enable Scorecard Github Action and Badge [#19755](https://github.com/storybooks/storybook/pull/19755)\n- Build: Add e2e test for static JSON files [#19463](https://github.com/storybooks/storybook/pull/19463)\n\n## 7.0.0-beta.26 (January 14, 2023)\n\n#### Features\n\n- Core: Expose port from buildDevStandalone [#20575](https://github.com/storybooks/storybook/pull/20575)\n- CLI: Add auto-migration for MDX html-type comments to JS-type comments [#20349](https://github.com/storybooks/storybook/pull/20349)\n\n#### Bug Fixes\n\n- API: Fix typing on useArgs [#20610](https://github.com/storybooks/storybook/pull/20610)\n- Addon-docs: Fix docs crash by simplifying element before stringify [#19188](https://github.com/storybooks/storybook/pull/19188)\n- Vite: Fix duplicate code in preview [#20594](https://github.com/storybooks/storybook/pull/20594)\n- Addons: Warn when addon is not installed [#20455](https://github.com/storybooks/storybook/pull/20455)\n- Blocks: Handle undefined extractComponentDescription [#20590](https://github.com/storybooks/storybook/pull/20590)\n\n#### Maintenance\n\n- CLI: Fix removal of --no-dll flag [#20589](https://github.com/storybooks/storybook/pull/20589)\n- SvelteKit: Automatically support Kit-specific features [#20239](https://github.com/storybooks/storybook/pull/20239)\n\n#### Build\n\n- Build: Fix issue with jest projects matching `ui/node_modules` [#20601](https://github.com/storybooks/storybook/pull/20601)\n- TypeScript: Fix typings files to ensure check command succeeds [#20605](https://github.com/storybooks/storybook/pull/20605)\n- CLI: Fix repros creation not working on windows [#20606](https://github.com/storybooks/storybook/pull/20606)\n- Build: Fix template stories to make them work with stricter Typescript settings [#20591](https://github.com/storybooks/storybook/pull/20591)\n- Build: Allow creating internal templates that extend others and pass `main.js` options [#20054](https://github.com/storybooks/storybook/pull/20054)\n\n## 7.0.0-beta.25 (January 12, 2023)\n\n#### Features\n\n- Vue3: Rendering slots passed from controls [#20536](https://github.com/storybooks/storybook/pull/20536)\n\n#### Bug Fixes\n\n- Core: Export build from core-server instead of standalone [#20574](https://github.com/storybooks/storybook/pull/20574)\n\n#### Maintenance\n\n- Blocks: New Description API, introduce useOf [#20563](https://github.com/storybooks/storybook/pull/20563)\n\n## 7.0.0-beta.24 (January 11, 2023)\n\n#### Maintenance\n\n- Migrations: Add `preact-vite` to new frameworks automigration [#20542](https://github.com/storybooks/storybook/pull/20542)\n\n#### Build\n\n- Build: remove unneeded dependencies & upgrades [#20533](https://github.com/storybooks/storybook/pull/20533)\n- Build: upgrade verdaccio [#20561](https://github.com/storybooks/storybook/pull/20561)\n- Build: remove usage of enzyme [#20534](https://github.com/storybooks/storybook/pull/20534)\n\n## 7.0.0-beta.23 (January 10, 2023)\n\n#### Features\n\n- Composition: Add basic auth support [#20488](https://github.com/storybooks/storybook/pull/20488)\n\n#### Bug Fixes\n\n- UI: Fix managerEntries containing long paths with hidden folders [#20550](https://github.com/storybooks/storybook/pull/20550)\n- Addon-docs: Fix attachment logic [#20531](https://github.com/storybooks/storybook/pull/20531)\n\n#### Maintenance\n\n- Addon-docs: Move reactPeerCheck to docs package [#20560](https://github.com/storybooks/storybook/pull/20560)\n- Addon-docs: Rename `storyByModuleExport` to `resolveModuleExport` [#20517](https://github.com/storybooks/storybook/pull/20517)\n- Telemetry: Filter out example stories/docs from summary [#20553](https://github.com/storybooks/storybook/pull/20553)\n- Telemetry: Count play function usage [#20541](https://github.com/storybooks/storybook/pull/20541)\n- Telemetry: Add pageStoryCount [#20539](https://github.com/storybooks/storybook/pull/20539)\n- Vite/Vue3: Pre-bundle @vitejs/plugin-vue [#20343](https://github.com/storybooks/storybook/pull/20343)\n\n#### Build\n\n- Build: downgrade slash to non-ESM [#20543](https://github.com/storybooks/storybook/pull/20543)\n\n#### Other\n\n- Update GH action to use \"linear-ghaction\" label for sync [#20546](https://github.com/storybooks/storybook/pull/20546)\n\n## 7.0.0-beta.22 (January 10, 2023)\n\nFailed publish\n\n## 7.0.0-beta.21 (January 9, 2023)\n\n#### Maintenance\n\n- Ember: Build with tsc [#20524](https://github.com/storybooks/storybook/pull/20524)\n- Storyshots: Build with tsc [#20523](https://github.com/storybooks/storybook/pull/20523)\n\n#### Dependencies\n\n- Downgrade find-cache-dir [#20532](https://github.com/storybooks/storybook/pull/20532)\n\n#### Build\n\n- Build: Cleanup babel prepare related code & dependencies [#20156](https://github.com/storybooks/storybook/pull/20156)\n- Build: Create a tsc prepare script, use it for angular framework, add ESM to angular dist [#20516](https://github.com/storybooks/storybook/pull/20516)\n- Build: Fix InternalCanvas story tests [#20521](https://github.com/storybooks/storybook/pull/20521)\n\n## 7.0.0-beta.20 (January 6, 2023)\n\n#### Bug Fixes\n\n- Telemetry: Move 'dev'/'build' events to the end of the process [#20380](https://github.com/storybooks/storybook/pull/20380)\n- Blocks: Export Unstyled block in index.ts [#20489](https://github.com/storybooks/storybook/pull/20489)\n- Vite: Fix missing await in builder [#20409](https://github.com/storybooks/storybook/pull/20409)\n\n#### Maintenance\n\n- Build: use tsup for csf-plugin [#20150](https://github.com/storybooks/storybook/pull/20150)\n- Migration: Update autodocs migration to deal with `docs.docsPage` [#20379](https://github.com/storybooks/storybook/pull/20379)\n\n#### Build\n\n- Blocks: Use example Button for stories [#20483](https://github.com/storybooks/storybook/pull/20483)\n- Build: cleanup prep script where possible [#20151](https://github.com/storybooks/storybook/pull/20151)\n- cleanup CI config [#20510](https://github.com/storybooks/storybook/pull/20510)\n- Build: Fix CI parallelism [#20476](https://github.com/storybooks/storybook/pull/20476)\n- Web-components: Restore missing script stories [#20477](https://github.com/storybooks/storybook/pull/20477)\n\n## 7.0.0-beta.19 (January 1, 2023)\n\n#### Features\n\n- NextJS: Add next/head support [#20436](https://github.com/storybooks/storybook/pull/20436)\n\n#### Bug Fixes\n\n- CLI: Do not use legacy-peer-deps for npm [#20456](https://github.com/storybooks/storybook/pull/20456)\n- CLI: Use closest lockfile to determine package manager [#20464](https://github.com/storybooks/storybook/pull/20464)\n- CLI: Use correct package manager for automigrate [#20428](https://github.com/storybooks/storybook/pull/20428)\n- CLI: Add prop-types dependency if not using TypeScript [#20449](https://github.com/storybooks/storybook/pull/20449)\n- CLI: Add peer dependency on react [#20459](https://github.com/storybooks/storybook/pull/20459)\n\n#### Maintenance\n\n- Vue3: Add TS / legacy TS CLI templates [#20434](https://github.com/storybooks/storybook/pull/20434)\n- Core: Delete outdated onerror handler [#20462](https://github.com/storybooks/storybook/pull/20462)\n\n#### Build\n\n- Build: Add extensions to lodash imports [#20443](https://github.com/storybooks/storybook/pull/20443)\n\n## 7.0.0-beta.18 (January 1, 2023)\n\nBad npm publish\n\n## 7.0.0-beta.17 (December 30, 2022)\n\n#### Bug Fixes\n\n- Svelte: Do not warn about .svelte files in storyStoreV7 [#20442](https://github.com/storybooks/storybook/pull/20442)\n- Core: Fix import paths on Windows [#20430](https://github.com/storybooks/storybook/pull/20430)\n- UI: Set min-height relative to the viewport and the zoom level. [#20352](https://github.com/storybooks/storybook/pull/20352)\n\n#### Maintenance\n\n- Docs: Use `stories-mdx` and `autodocs` tags instead of `standalone: false` in index [#20424](https://github.com/storybooks/storybook/pull/20424)\n- Docs: Use `'stories-mdx'` tag to indicate story defined in MDX file [#20417](https://github.com/storybooks/storybook/pull/20417)\n- Preact-Vite: Minor readme and dependency cleanups [#20432](https://github.com/storybooks/storybook/pull/20432)\n\n#### Build\n\n- Tech: ESLint allow devDependencies imports in prebundled packages [#20440](https://github.com/storybooks/storybook/pull/20440)\n- Fix yarn task command on Windows machines [#20431](https://github.com/storybooks/storybook/pull/20431)\n\n## 7.0.0-beta.16 (December 29, 2022)\n\n#### Features\n\n- Preact-Vite: Add framework [#20390](https://github.com/storybooks/storybook/pull/20390)\n\n#### Maintenance\n\n- NextJS: Fix unnecessary addon-actions dev dep [#20426](https://github.com/storybooks/storybook/pull/20426)\n\n## 7.0.0-beta.15 (December 24, 2022)\n\n#### Bug Fixes\n\n- Codemods: Fix peer dependency issue [#20399](https://github.com/storybooks/storybook/pull/20399)\n- Core: Wrap manager entries to handle exports using a cache directory [#20331](https://github.com/storybooks/storybook/pull/20331)\n- UI: fix deprecated ReactDOM.findDOMNode calls [#20368](https://github.com/storybooks/storybook/pull/20368)\n\n#### Maintenance\n\n- Build: Use tsup for core-server [#20134](https://github.com/storybooks/storybook/pull/20134)\n\n#### Build\n\n- Build: Make tests use SWC, not babel [#20397](https://github.com/storybooks/storybook/pull/20397)\n- Build: Fix trim vulnerability [#20371](https://github.com/storybooks/storybook/pull/20371)\n\n## 7.0.0-beta.14 (December 23, 2022)\n\n#### Features\n\n- CLI: Write into a log file if automigrations fail [#20310](https://github.com/storybooks/storybook/pull/20310)\n- CLI: Add nodejs check in automigrations [#20342](https://github.com/storybooks/storybook/pull/20342)\n\n#### Bug Fixes\n\n- UI: Disable React.strictmode to avoid findNode deprecation warnings [#20345](https://github.com/storybooks/storybook/pull/20345)\n- Vite: Fix peerDep warning by updating `@joshwooding/vite-plugin-react-docgen-typescript` [#20359](https://github.com/storybooks/storybook/pull/20359)\n\n#### Maintenance\n\n- Don't allow setting `Meta of={X}` if `X` is tagged with `'autodocs'` [#20373](https://github.com/storybooks/storybook/pull/20373)\n- Rename `docsPage` => `autodocs` [#20364](https://github.com/storybooks/storybook/pull/20364)\n- Rename `docsOptions.enabled` to `docsOptions.disable` [#20363](https://github.com/storybooks/storybook/pull/20363)\n- Angular: Switch to default to inlineStories=true [#20118](https://github.com/storybooks/storybook/pull/20118)\n- Types: Add Addon_OptionsParameterV7 type [#20384](https://github.com/storybooks/storybook/pull/20384)\n\n#### Build\n\n- Build: regen lockfiles [#20386](https://github.com/storybooks/storybook/pull/20386)\n- Build: fix prettydocs CI flakyness [#20385](https://github.com/storybooks/storybook/pull/20385)\n- Build: Update Playwright to 1.29.1 [#20372](https://github.com/storybooks/storybook/pull/20372)\n- Build: store extra metadata for each sandbox test [#20365](https://github.com/storybooks/storybook/pull/20365)\n- Build: Remove the non-cross-platform dash-S option [#20360](https://github.com/storybooks/storybook/pull/20360)\n- Build: sync issues of `next` packages [#20354](https://github.com/storybooks/storybook/pull/20354)\n\n## 6.5.15 (December 20, 2022)\n\n#### Bug Fixes\n\n- Support Angular 15.0.4 [#20287](https://github.com/storybooks/storybook/pull/20287)\n- CLI: execute automigrations when pressing enter in the prompts [#20208](https://github.com/storybooks/storybook/pull/20208)\n\n## 7.0.0-beta.13 (December 20, 2022)\n\n#### Features\n\n- Angular: Support compodoc output arg [#20338](https://github.com/storybooks/storybook/pull/20338)\n- NextJS: Support @next/font [#20291](https://github.com/storybooks/storybook/pull/20291)\n- NextJS: Support useSelectedLayoutSegment and useSelectedLayoutSegments [#20330](https://github.com/storybooks/storybook/pull/20330)\n- Preview Api: export `userOrAutoTitle` function [#20325](https://github.com/storybooks/storybook/pull/20325)\n\n#### Bug Fixes\n\n- Fix: peer dependency warning for `vite-react` [#20328](https://github.com/storybooks/storybook/pull/20328)\n- UI: swap `react-sizeme` for `react-resize-detector` [#20333](https://github.com/storybooks/storybook/pull/20333)\n- Vite: Detect React SWC plugin [#20335](https://github.com/storybooks/storybook/pull/20335)\n- CLI: Fix automigrate filtering [#20329](https://github.com/storybooks/storybook/pull/20329)\n- Vite: Include user config `optimizeDeps` in final `optimizeDeps` [#20313](https://github.com/storybooks/storybook/pull/20313)\n\n#### Maintenance\n\n- Tech: improve global types [#20184](https://github.com/storybooks/storybook/pull/20184)\n- CLI: Fix sb migrate csf-2-to-3 for multiple file extensions [#20290](https://github.com/storybooks/storybook/pull/20290)\n- CLI: Replace `update-notifier` with `simple-update-notifier` [#20266](https://github.com/storybooks/storybook/pull/20266)\n\n#### Build\n\n- Build: remove borders in task error message [#20305](https://github.com/storybooks/storybook/pull/20305)\n- Build: Fix pretty-docs CI job [#20319](https://github.com/storybooks/storybook/pull/20319)\n- Build: Update Playwright to 1.29 [#20318](https://github.com/storybooks/storybook/pull/20318)\n\n#### Dependencies\n\n- NextJS: Make addon-actions a regular dependency [#20324](https://github.com/storybooks/storybook/pull/20324)\n- NextJS: Fix addon-actions peerdependency [#20324](https://github.com/storybooks/storybook/pull/20324)\n- Vite-react: Fix peer dependency warning [#20328](https://github.com/storybooks/storybook/pull/20328)\n\n## 7.0.0-beta.12 (December 16, 2022)\n\n#### Other\n\n- Revert \"Core: Wrap manager entries to handle exports\" [#20311](https://github.com/storybooks/storybook/pull/20311)\n\n## 7.0.0-beta.11 (December 16, 2022)\n\n#### Features\n\n- CLI: Improve automigration to show prompt-only migrations [#20292](https://github.com/storybooks/storybook/pull/20292)\n\n#### Bug Fixes\n\n- Angular: Fix webpackStatsJson types in angular-builder [#20296](https://github.com/storybooks/storybook/pull/20296)\n- Fix: addon-storysource has no managerEntry, but defines a register and preset [#20304](https://github.com/storybooks/storybook/pull/20304)\n\n#### Maintenance\n\n- Core: Wrap manager entries to handle exports [#20308](https://github.com/storybooks/storybook/pull/20308)\n- Core: improve manager-entries failure message [#20306](https://github.com/storybooks/storybook/pull/20306)\n- Telemetry: Fix flakey test [#20282](https://github.com/storybooks/storybook/pull/20282)\n\n#### Dependency Upgrades\n\n- Vite: Make vite a peer dependency, update plugins [#20281](https://github.com/storybooks/storybook/pull/20281)\n- Vite/Svelte: Remove addon-svelte-csf dep [#20280](https://github.com/storybooks/storybook/pull/20280)\n\n## 7.0.0-beta.10 (December 16, 2022)\n\n#### Build\n\n- Build: compile detection was using a non-conforming package, causing cache to miss always. [#20297](https://github.com/storybooks/storybook/pull/20297)\n\n#### Dependency Upgrades\n\n- React-vite: Pin react-docgen version [#20300](https://github.com/storybooks/storybook/pull/20300)\n\n## 7.0.0-beta.9 (December 16, 2022)\n\n#### Features\n\n- CLI: Add interactive babel config file generation [#20234](https://github.com/storybooks/storybook/pull/20234)\n- CLI: Add automigration summary [#20276](https://github.com/storybooks/storybook/pull/20276)\n\n#### Bug Fixes\n\n- UI: Fix `enableShortcuts` support in `manager.ts` [#20264](https://github.com/storybooks/storybook/pull/20264)\n- UI: Ensure manager entries load even if preceding ones failed [#20286](https://github.com/storybooks/storybook/pull/20286)\n- Addon-viewport: Fix composition support [#20289](https://github.com/storybooks/storybook/pull/20289)\n- Support Angular 15.0.4 [#20287](https://github.com/storybooks/storybook/pull/20287)\n- Fix: peerDependencies issues reported [#20279](https://github.com/storybooks/storybook/pull/20279)\n\n#### Build\n\n- Build: ui/.storybook should not import from dist [#20284](https://github.com/storybooks/storybook/pull/20284)\n- Build: bundle script a bit less repetitive, add a completion indicator [#20277](https://github.com/storybooks/storybook/pull/20277)\n- Build: regen lockfiles [#20278](https://github.com/storybooks/storybook/pull/20278)\n\n## 7.0.0-beta.8 (December 14, 2022)\n\n#### Features\n\n- Addon-docs: Use jsxOptions instead of mdxBabelOptions [#20271](https://github.com/storybooks/storybook/pull/20271)\n\n#### Maintenance\n\n- Svelte-vite: remove `svelteOptions` in automigration [#20270](https://github.com/storybooks/storybook/pull/20270)\n\n#### Build\n\n- Fix handling of inverted yes flag in `task` steps [#20268](https://github.com/storybooks/storybook/pull/20268)\n\n## 7.0.0-beta.7 (December 14, 2022)\n\n#### Features\n\n- CLI: Add Next.js framework automigration [#19574](https://github.com/storybooks/storybook/pull/19574)\n\n#### Bug Fixes\n\n- Don't export renderer from framework [#20259](https://github.com/storybooks/storybook/pull/20259)\n- Upgrade sb dep as well in sb upgrade [#20258](https://github.com/storybooks/storybook/pull/20258)\n- Vite: Make the bail function work if the server fails to start [#20243](https://github.com/storybooks/storybook/pull/20243)\n- Csf-tools: Fix local vars handling in MDX-generated CSF [#20255](https://github.com/storybooks/storybook/pull/20255)\n- Csf-plugin: Fix spurious storiesOf warnings [#20256](https://github.com/storybooks/storybook/pull/20256)\n- Core: Remove unnecessary peer deps [#20231](https://github.com/storybooks/storybook/pull/20231)\n- Fix issues with running SSv6 [#20253](https://github.com/storybooks/storybook/pull/20253)\n- Core: Fix config.base relative paths [#20232](https://github.com/storybooks/storybook/pull/20232)\n- Fix: vite devmode with storyStoreV6 by ensuring singleton via global [#20207](https://github.com/storybooks/storybook/pull/20207)\n\n#### Maintenance\n\n- Addon-docs: Upgrade mdx2-csf and use its JSX handling [#20261](https://github.com/storybooks/storybook/pull/20261)\n- Vite: Use mdx2 babel pre-processing [#20241](https://github.com/storybooks/storybook/pull/20241)\n- Addon-docs: Restore deprecated blocks entry point [#20246](https://github.com/storybooks/storybook/pull/20246)\n\n#### Build\n\n- Add Next 12 sandbox [#20092](https://github.com/storybooks/storybook/pull/20092)\n\n#### Dependency Upgrades\n\n- Add optional TypeScript peer dependency [#20244](https://github.com/storybooks/storybook/pull/20244)\n\n## 7.0.0-beta.6 (December 14, 2022)\n\n#### Dependency Upgrades\n\n- Vite: Use Vite 3 (temporarily) [#20216](https://github.com/storybooks/storybook/pull/20216)\n\n## 7.0.0-beta.5 (December 13, 2022)\n\n#### Features\n\n- CLI: Split sb-scripts into two different migrations [#20223](https://github.com/storybooks/storybook/pull/20223)\n\n#### Bug Fixes\n\n- Vite: Support async Vite plugins [#20194](https://github.com/storybooks/storybook/pull/20194)\n- Telemetry: Don't send boot event when cliOptions.disableTelemetry is passed [#20144](https://github.com/storybooks/storybook/pull/20144)\n\n#### Maintenance\n\n- CLI: Add React peer dep runtime check [#20206](https://github.com/storybooks/storybook/pull/20206)\n\n#### Dependency Upgrades\n\n- Upgrade esbuild [#20199](https://github.com/storybooks/storybook/pull/20199)\n\n## 7.0.0-beta.4 (December 13, 2022)\n\n#### Features\n\n- Re-enable TS 4.9 CLI templates [#20159](https://github.com/storybooks/storybook/pull/20159)\n\n#### Bug Fixes\n\n- CLI: execute automigrations when pressing enter in the prompts [#20208](https://github.com/storybooks/storybook/pull/20208)\n- Interactions: Fix storyId access in instrumenter [#20201](https://github.com/storybooks/storybook/pull/20201)\n- Typescript: Fix bug with meta not working well as generic parameter for StoryObj [#20165](https://github.com/storybooks/storybook/pull/20165)\n- SvelteKit: Support `v1.0.0-next.574` and above [#20181](https://github.com/storybooks/storybook/pull/20181)\n\n#### Build\n\n- Svelte: Fix argTypes inference in Button component [#20212](https://github.com/storybooks/storybook/pull/20212)\n- React-Vite: Ignore React MDX stories in sandbox [#20210](https://github.com/storybooks/storybook/pull/20210)\n\n## 7.0.0-beta.3 (December 10, 2022)\n\n#### Bug Fixes\n\n- CLI: Fix sb migrate codemods [#20191](https://github.com/storybooks/storybook/pull/20191)\n- Measure: Fix measure not working on disabled elements [#19985](https://github.com/storybooks/storybook/pull/19985)\n\n#### Maintenance\n\n- SvelteKit: Automigration [#20094](https://github.com/storybooks/storybook/pull/20094)\n- Tech: change `package.json` engines fields, set to minimal node16 and up [#20170](https://github.com/storybooks/storybook/pull/20170)\n\n## 7.0.0-beta.2 (December 9, 2022)\n\n#### Bug Fixes\n\n- Core: Catch and do nothing to avoid triggering unhandled exception problems [#20177](https://github.com/storybooks/storybook/pull/20177)\n- Controls: Fix color control not resetting when initial value is defined [#20049](https://github.com/storybooks/storybook/pull/20049)\n- Core: Fix typescript.checkOptions not a valid interface [#20166](https://github.com/storybooks/storybook/pull/20166)\n- NextJS: Fixlogic around `next/future/image` [#20173](https://github.com/storybooks/storybook/pull/20173)\n\n#### Maintenance\n\n- Revert \"Revert \"Telemetry: Add precedingUpgrade data to dev/build/error events\"\" [#20176](https://github.com/storybooks/storybook/pull/20176)\n- Telemetry: Add `chromatic` to addons list [#20143](https://github.com/storybooks/storybook/pull/20143)\n- Vite: Support vite 4 [#20139](https://github.com/storybooks/storybook/pull/20139)\n\n## 7.0.0-beta.1 (December 9, 2022)\n\n#### Bug Fixes\n\n- Revert \"Telemetry: Add precedingUpgrade data to dev/build/error events\" [#20168](https://github.com/storybooks/storybook/pull/20168)\n- Controls: Fix file controls not resetting [#19998](https://github.com/storybooks/storybook/pull/19998)\n\n#### Dependency Upgrades\n\n- Upgrade express to fix security warning [#20152](https://github.com/storybooks/storybook/pull/20152)\n\n## 7.0.0-beta.0 (December 8, 2022)\n\nWe made it to beta, folks! 🎉\n\nSB7 overhauls our build architecture, modernizes our output to ESM only, promotes Vite to a first-class peer to Webpack, rethinks our Docs addon, cleans up the UI, and contains hundreds of improvements at every level of the stack. We've been sharing some of these changes on [the Storybook blog](https://storybook.js.org/blog/) and will share more over the coming weeks.\n\nBeta means that we don't have any more major changes on the radar for 7.0 and it's mostly stabilization from here on out. The core team is doing some basic testing now, and once we have a good QA plan, we'd love your help to make that happen. Please keep an eye out on the blog and on our [Twitter](https://twitter.com/storybookjs) or Mastadon (coming soon!) or [Discord](https://discord.gg/storybook) if you're interested in helping.\n\n#### Bug Fixes\n\n- Extend Angular Zone.js peer dependency range [#20107](https://github.com/storybooks/storybook/pull/20107)\n- Vite: Fix static source handling for addon-docs [#20147](https://github.com/storybooks/storybook/pull/20147)\n- Controls: Arrow keys don't work on number controls [#19954](https://github.com/storybooks/storybook/pull/19954)\n\n## 7.0.0-alpha.62 (December 8, 2022)\n\n#### Bug Fixes\n\n- Fix new-frameworks automigration failing to read frameworkOptions field [#20128](https://github.com/storybooks/storybook/pull/20128)\n- Fix Next.js lower than 12.2.0 [#20129](https://github.com/storybooks/storybook/pull/20129)\n- Fix iframe.html not available upon early browser opening [#20123](https://github.com/storybooks/storybook/pull/20123)\n\n#### Maintenance\n\n- Add args generic to CSFExports [#20135](https://github.com/storybooks/storybook/pull/20135)\n- Modernize favicon [#20130](https://github.com/storybooks/storybook/pull/20130)\n- Telemetry: Add precedingUpgrade data to dev/build/error events [#20136](https://github.com/storybooks/storybook/pull/20136)\n- CLI: Replace addon-docs Meta with blocks and add blocks dep [#20133](https://github.com/storybooks/storybook/pull/20133)\n- CLI: Fix upgrade --prerelease to upgrade to the next tag [#20126](https://github.com/storybooks/storybook/pull/20126)\n\n## 7.0.0-alpha.61 (December 7, 2022)\n\n#### Features\n\n- NextJS: Support next/navigation in Next.js v13 [#20065](https://github.com/storybooks/storybook/pull/20065)\n\n#### Maintenance\n\n- Vite/MDX: Fix mdx compiler for vite [#20121](https://github.com/storybooks/storybook/pull/20121)\n- Fix more peerDependencies issues [#20120](https://github.com/storybooks/storybook/pull/20120)\n\n## 7.0.0-alpha.60 (December 7, 2022)\n\n#### Bug Fixes\n\n- Deal with a lot of different edge cases for git URLs [#20115](https://github.com/storybooks/storybook/pull/20115)\n\n#### Maintenance\n\n- Clean up babelModeV7 migration and code [#20117](https://github.com/storybooks/storybook/pull/20117)\n- Fix peer dependencies for npm8/pnpm/yarn pnp [#20110](https://github.com/storybooks/storybook/pull/20110)\n- Remove peer deps from core-common [#20109](https://github.com/storybooks/storybook/pull/20109)\n\n#### Build\n\n- Add more linting config to vs-code settings.json [#20101](https://github.com/storybooks/storybook/pull/20101)\n\n## 7.0.0-alpha.59 (December 6, 2022)\n\n#### Features\n\n- CSF: Add satisfies support to csf-tools [#20088](https://github.com/storybooks/storybook/pull/20088)\n\n#### Bug Fixes\n\n- Next.js: only set next/future/image mocks from version 12.2 [#20098](https://github.com/storybooks/storybook/pull/20098)\n- Core: Batch the loading of CSF files for `extract()` etc [#20055](https://github.com/storybooks/storybook/pull/20055)\n- Fix SSR in external docs via `node` exports [#20083](https://github.com/storybooks/storybook/pull/20083)\n- CLI: Improve sb-scripts automigration logic [#20035](https://github.com/storybooks/storybook/pull/20035)\n\n#### Maintenance\n\n- Revert \"Telemetry: Add precedingUpgrade data to dev/build events\" [#20105](https://github.com/storybooks/storybook/pull/20105)\n- Telemetry: Instrument init event [#20097](https://github.com/storybooks/storybook/pull/20097)\n\n#### Build\n\n- Fix next [#20106](https://github.com/storybooks/storybook/pull/20106)\n- Build: Run sb init locally in sandbox creation [#20100](https://github.com/storybooks/storybook/pull/20100)\n- Build: Add missing dependencies to manager, unify TS to ~4.9.3 [#20021](https://github.com/storybooks/storybook/pull/20021)\n\n#### Dependency Upgrades\n\n- Bump store2 to 2.14.2 license clarification [#19899](https://github.com/storybooks/storybook/pull/19899)\n\n## 7.0.0-alpha.58 (December 5, 2022)\n\n#### Features\n\n- Add `--tag` option to `upgrade` script [#20075](https://github.com/storybooks/storybook/pull/20075)\n- HTML: Add `html-vite` framework [#19698](https://github.com/storybooks/storybook/pull/19698)\n- SvelteKit: Create framework [#20039](https://github.com/storybooks/storybook/pull/20039)\n\n#### Maintenance\n\n- Core: Remove postcss feature flag [#20003](https://github.com/storybooks/storybook/pull/20003)\n- Telemetry: Add precedingUpgrade data to dev/build events [#20084](https://github.com/storybooks/storybook/pull/20084)\n- Core: make managerEntries load as ESM, for improved tree-shaking [#20070](https://github.com/storybooks/storybook/pull/20070)\n\n## 7.0.0-alpha.57 (December 3, 2022)\n\n#### Bug Fixes\n\n- Vite: Reinstate (deprecated) `StorybookViteConfig` [#20057](https://github.com/storybooks/storybook/pull/20057)\n- Docs: using targeted styles, not components to style MDX [#19958](https://github.com/storybooks/storybook/pull/19958)\n- Docs: Return to filtering toolbars in docs mode, but don't filter menu [#19959](https://github.com/storybooks/storybook/pull/19959)\n- Angular: Don't set `argType.defaultValue` in angular/compodoc [#19935](https://github.com/storybooks/storybook/pull/19935)\n- NextJS: Support next/image component in v12/13 properly [#20028](https://github.com/storybooks/storybook/pull/20028)\n- Svelte: Use JSDocs in JS CLI templates and put manual enum arg type back as it is not inferred [#20042](https://github.com/storybooks/storybook/pull/20042)\n\n#### Maintenance\n\n- CLI: Add a new `version-update` check telemetry event [#20074](https://github.com/storybooks/storybook/pull/20074)\n- CLI: Add upgrade telemetry details [#20064](https://github.com/storybooks/storybook/pull/20064)\n- Core: added .entries property to error thrown when duplicate stories are present [#20038](https://github.com/storybooks/storybook/pull/20038)\n\n#### Build\n\n- Improve framework version specific story handling [#20027](https://github.com/storybooks/storybook/pull/20027)\n- Fix repro templates script [#20063](https://github.com/storybooks/storybook/pull/20063)\n- Build: replace image placeholder url in example stories for nextjs [#20069](https://github.com/storybooks/storybook/pull/20069)\n- Build: improve inDevelopment mode for yarn task [#20067](https://github.com/storybooks/storybook/pull/20067)\n- Build: revamp interactions e2e test [#20060](https://github.com/storybooks/storybook/pull/20060)\n\n#### Dependency Upgrades\n\n- Build: Update jest pretty-format to 29 [#20047](https://github.com/storybooks/storybook/pull/20047)\n\n## 7.0.0-alpha.56 (December 1, 2022)\n\n#### Bug Fixes\n\n- Addon-interactions: Fix duplicated elements in the panel [#20004](https://github.com/storybooks/storybook/pull/20004)\n- Core: Fix ability to use component-level play functions [#17817](https://github.com/storybooks/storybook/pull/17817)\n- CLI: Fix `docsPage` automatic migration [#19982](https://github.com/storybooks/storybook/pull/19982)\n\n#### Build\n\n- e2e: change onClick to click to support svelte examples [#20034](https://github.com/storybooks/storybook/pull/20034)\n\n## 7.0.0-alpha.55 (November 30, 2022)\n\n#### Features\n\n- CLI: Add TS 4.9 CLI templates [#19986](https://github.com/storybooks/storybook/pull/19986)\n- CLI: Remove render functions and infer argTypes for svelte CLI templates [#20007](https://github.com/storybooks/storybook/pull/20007)\n\n#### Bug Fixes\n\n- Svelte: Fix decorators with slots [#19987](https://github.com/storybooks/storybook/pull/19987)\n- Core: Open browser after manager is ready [#20005](https://github.com/storybooks/storybook/pull/20005)\n- Core: Add backwards support for manager-api package rename [#20006](https://github.com/storybooks/storybook/pull/20006)\n- Vite: Fix prebundling [#19978](https://github.com/storybooks/storybook/pull/19978)\n\n#### Maintenance\n\n- Maintenance: Use typescript legacy templates until our ecosystem fully supports ts 4.9 [#20032](https://github.com/storybooks/storybook/pull/20032)\n- CLI: Rollback next TS 4.9 templates as the next babel preset doesn't support satisfies [#20029](https://github.com/storybooks/storybook/pull/20029)\n- Addon-docs: Use `.mdx` globs in templates and defaults [#19795](https://github.com/storybooks/storybook/pull/19795)\n- Types: Rationalize story-based types and de-prefix [#19919](https://github.com/storybooks/storybook/pull/19919)\n- API: Export the controlOrMetaKey fn from manager-api [#19972](https://github.com/storybooks/storybook/pull/19972)\n- Blocks: Description stories [#19806](https://github.com/storybooks/storybook/pull/19806)\n\n#### Build\n\n- Upgrade yarn [#20025](https://github.com/storybooks/storybook/pull/20025)\n- Build: Add a retry mechanism for exports file generation [#20018](https://github.com/storybooks/storybook/pull/20018)\n- Build: Rollback forking off git-shallow-clone-orb [#20020](https://github.com/storybooks/storybook/pull/20020)\n- Build: Clean up @storybook/preview dependencies [#19997](https://github.com/storybooks/storybook/pull/19997)\n- No unused locals in tsconfig to disable deepscan [#20012](https://github.com/storybooks/storybook/pull/20012)\n- Build: generate the `exports.ts` file in a single pass without `exec` [#20002](https://github.com/storybooks/storybook/pull/20002)\n- Build a mechanism to E2E telemetry [#19946](https://github.com/storybooks/storybook/pull/19946)\n- Add debug to chromatic task [#19933](https://github.com/storybooks/storybook/pull/19933)\n- Build: Sanitise user input in github workflow [#19980](https://github.com/storybooks/storybook/pull/19980)\n- Blocks: Add story for Canvas `className` prop, cleanup UI SB `preview.tsx [#19886](https://github.com/storybooks/storybook/pull/19886)\n- Change export-generating script to use exec util instead of shelljs [#19979](https://github.com/storybooks/storybook/pull/19979)\n- Regen lockfiles [#19967](https://github.com/storybooks/storybook/pull/19967)\n\n#### Dependency Upgrades\n\n- Build: Upgrade jest-specific-snapshot [#19996](https://github.com/storybooks/storybook/pull/19996)\n- Upgrade telejson [#19983](https://github.com/storybooks/storybook/pull/19983)\n\n## 7.0.0-alpha.54 (November 25, 2022)\n\n#### Bug Fixes\n\n- Vite: Support environment variables in viteFinal define config [#19905](https://github.com/storybooks/storybook/pull/19905)\n\n#### Maintenance\n\n- Build: split `lib/addons` into manager & preview part, move code to `manager-api` [#19952](https://github.com/storybooks/storybook/pull/19952)\n- TypeScript: Satisfy stricter compilerOption rules [#19953](https://github.com/storybooks/storybook/pull/19953)\n- API: Rename `api` to `manager-api` [#19944](https://github.com/storybooks/storybook/pull/19944)\n- API: Add `preview-api` package [#19749](https://github.com/storybooks/storybook/pull/19749)\n\n#### Build\n\n- Build: Improve security in Github actions [#19949](https://github.com/storybooks/storybook/pull/19949)\n\n#### Dependencies\n\n- NextJS: Add Next13 peer dependency [#19932](https://github.com/storybooks/storybook/pull/19932)\n\n## 7.0.0-alpha.53 (November 24, 2022)\n\n#### Bug Fixes\n\n- Angular: Fix \"**webpack_require**.nmd is not a function\" in v15 [#19937](https://github.com/storybooks/storybook/pull/19937)\n- Controls: Exclude `{ table: { disable: true } }` from panel count [#19877](https://github.com/storybooks/storybook/pull/19877)\n\n#### Maintenance\n\n- Core: Prebundle the preview [#19718](https://github.com/storybooks/storybook/pull/19718)\n- Builder-vite: Build with tsup [#19895](https://github.com/storybooks/storybook/pull/19895)\n- Components: Fix missing export [#19923](https://github.com/storybooks/storybook/pull/19923)\n\n#### Build\n\n- Remove the fix we added when enhanced-resolve was broken [#19942](https://github.com/storybooks/storybook/pull/19942)\n- Fix CI which was broken by enhanced-resolve [#19936](https://github.com/storybooks/storybook/pull/19936)\n- Drop `inDevelopment` from `cra/default-js` [#19934](https://github.com/storybooks/storybook/pull/19934)\n- Fix execa import in get-report-message [#19913](https://github.com/storybooks/storybook/pull/19913)\n\n## 7.0.0-alpha.52 (November 21, 2022)\n\n#### Bug Fixes\n\n- NextJS: Fix v13 `next/link` [#19834](https://github.com/storybooks/storybook/pull/19834)\n- Docs: Fix ordering of entries in `Stories` block [#19907](https://github.com/storybooks/storybook/pull/19907)\n\n#### Build\n\n- Maintenance: fix execa usage in build and check scripts [#19909](https://github.com/storybooks/storybook/pull/19909)\n- Use execa 6.x in `scripts` [#19759](https://github.com/storybooks/storybook/pull/19759)\n- Build: Create a generate task and use in the sandbox process [#19840](https://github.com/storybooks/storybook/pull/19840)\n\n#### Dependency Upgrades\n\n- Upgrade docs-mdx to fix yarn pnp [#19835](https://github.com/storybooks/storybook/pull/19835)\n\n## 7.0.0-alpha.51 (November 19, 2022)\n\n#### Bug Fixes\n\n- NextJS: Fix out-of-the-box babel handling [#19842](https://github.com/storybooks/storybook/pull/19842)\n- NextJS: Fix import url on windows [#19798](https://github.com/storybooks/storybook/pull/19798)\n- UI: Fix panel invisible for any addon listed after the interactions panel [#19771](https://github.com/storybooks/storybook/pull/19771)\n- Core: Bail preview builder on failure [#19849](https://github.com/storybooks/storybook/pull/19849)\n- Core: Fix double esbuild-register register [#19852](https://github.com/storybooks/storybook/pull/19852)\n- Composition: Fix regression in the `#root` to `#storybook-root` change [#19848](https://github.com/storybooks/storybook/pull/19848)\n- UI: Fix `showPanel=false` doesn't work on mobile view [#19807](https://github.com/storybooks/storybook/pull/19807)\n\n#### Maintenance\n\n- CLI: Replace degit with giget [#19870](https://github.com/storybooks/storybook/pull/19870)\n- Build: Bundle lib/channel-websocket with tsup [#19694](https://github.com/storybooks/storybook/pull/19694)\n- Maintenance: Upgrade monorepo to TS 4.9 [#19869](https://github.com/storybooks/storybook/pull/19869)\n\n#### Build\n\n- Build: Downgrade @types/node [#19890](https://github.com/storybooks/storybook/pull/19890)\n- Maintenance: Add angular 14 template and skip test runner on angular 15 for now [#19871](https://github.com/storybooks/storybook/pull/19871)\n- Build: Upgrade Jest to 29 [#19863](https://github.com/storybooks/storybook/pull/19863)\n- Build: Fix chromatic version to 6.11.2 in local scripts [#19889](https://github.com/storybooks/storybook/pull/19889)\n- Build: Pin chromatic version to 6.11.2 to temporary fix flakiness [#19874](https://github.com/storybooks/storybook/pull/19874)\n\n#### Dependency Upgrades\n\n- Bump mdx2-csf dependency [#19885](https://github.com/storybooks/storybook/pull/19885)\n\n## 7.0.0-alpha.50 (November 17, 2022)\n\n#### Features\n\n- Expose more CSF types in all renderers [#19833](https://github.com/storybooks/storybook/pull/19833)\n- CSF: Renamed Framework to Renderer [#19802](https://github.com/storybooks/storybook/pull/19802)\n\n#### Bug Fixes\n\n- Next.js: use file path instead of image contents for next-image-loader-stub [#19858](https://github.com/storybooks/storybook/pull/19858)\n- TypeScript: Fix type inference bug with decorators [#19839](https://github.com/storybooks/storybook/pull/19839)\n- Vite: Keep using absolute path node_modules splitting [#19836](https://github.com/storybooks/storybook/pull/19836)\n- Vite: Fix preview annotation paths on Windows [#19822](https://github.com/storybooks/storybook/pull/19822)\n- Fix csf-plugin ignoring options [#19823](https://github.com/storybooks/storybook/pull/19823)\n- Controls: Checkbox does not update when using useArgs hook [#19508](https://github.com/storybooks/storybook/pull/19508)\n\n#### Maintenance\n\n- Jest: switch from Parameters to StorybookInternalParameters [#19853](https://github.com/storybooks/storybook/pull/19853)\n- Blocks: Story stories [#19805](https://github.com/storybooks/storybook/pull/19805)\n- Blocks: Canvas stories [#19804](https://github.com/storybooks/storybook/pull/19804)\n- Tech: TypeScript should check stories and tests as well [#19831](https://github.com/storybooks/storybook/pull/19831)\n\n#### Build\n\n- UI Storybook: Disable sourcemaps when building in CI [#19862](https://github.com/storybooks/storybook/pull/19862)\n- Build: Increase max node memory for jobs [#19856](https://github.com/storybooks/storybook/pull/19856)\n- CI: improve error reporting mechanism [#19841](https://github.com/storybooks/storybook/pull/19841)\n- Fix tests on Windows [#19777](https://github.com/storybooks/storybook/pull/19777)\n- Build: Fix benchmark to run on local packages [#19832](https://github.com/storybooks/storybook/pull/19832)\n- CI: Report failures on discord [#19801](https://github.com/storybooks/storybook/pull/19801)\n\n## 7.0.0-alpha.49 (November 13, 2022)\n\n#### Bug Fixes\n\n- Essentials: Fix preview annotations for Vite pnpm support [#19689](https://github.com/storybooks/storybook/pull/19689)\n\n#### Maintenance\n\n- Build: convert addon-docs to use ts-up [#19790](https://github.com/storybooks/storybook/pull/19790)\n- Core: Allow overriding WebView and UrlStore [#19623](https://github.com/storybooks/storybook/pull/19623)\n- Storyshots: Support .cjs and .mjs file extensions [#19726](https://github.com/storybooks/storybook/pull/19726)\n\n#### Build\n\n- Build: less noise when compiling [#19808](https://github.com/storybooks/storybook/pull/19808)\n- Build: Upgrade bench to `next` [#19791](https://github.com/storybooks/storybook/pull/19791)\n- Maintenance: improve error feedback when tasks fail in CI [#19786](https://github.com/storybooks/storybook/pull/19786)\n- UI: Enable TurboSnap for UI Storybook [#19767](https://github.com/storybooks/storybook/pull/19767)\n- CI: Use a new cadence (ci, pr, merged, daily) and trigger CircleCI from github actions [#19768](https://github.com/storybooks/storybook/pull/19768)\n- Maintenance: provide expected failure metadata in junit reports [#19775](https://github.com/storybooks/storybook/pull/19775)\n\n## 7.0.0-alpha.48 (November 7, 2022)\n\n#### Breaking Changes\n\n- Preact: Make preact use inline stories (without iframe) by default in docs [#19741](https://github.com/storybooks/storybook/pull/19741)\n\n#### Features\n\n- Angular: Undo template gen removal during deprecation property removal [#19614](https://github.com/storybooks/storybook/pull/19614)\n- CSF-tools: Support main.js default exports [#19738](https://github.com/storybooks/storybook/pull/19738)\n- Addon-docs: Disable play functions in docs mode unless you set `parameters.docs.autoplay` [#19659](https://github.com/storybooks/storybook/pull/19659)\n- Addon-docs: Add docsPage `automatic` to create docs entries for all components [#19713](https://github.com/storybooks/storybook/pull/19713)\n- CLI: Add docsPage to all Button/Header story templates [#19715](https://github.com/storybooks/storybook/pull/19715)\n\n#### Bug Fixes\n\n- Svelte: Fix docs rendering [#19705](https://github.com/storybooks/storybook/pull/19705)\n- React: Expose ReactFramework type [#19704](https://github.com/storybooks/storybook/pull/19704)\n\n#### Maintenance\n\n- Core: Update index generation to use tags to detect MDX stories [#19712](https://github.com/storybooks/storybook/pull/19712)\n- CI: Fix cross OS github actions [#19754](https://github.com/storybooks/storybook/pull/19754)\n- Blocks: Redo stories for controls [#19744](https://github.com/storybooks/storybook/pull/19744)\n- Blocks: Setup and create example story for blocks with context [#19740](https://github.com/storybooks/storybook/pull/19740)\n- Client-api: Fix export from store [#19720](https://github.com/storybooks/storybook/pull/19720)\n- Pull renderer+builder from framework's package.json + a known list [#19717](https://github.com/storybooks/storybook/pull/19717)\n- CLI: Add automigration to set docsPage = 'automatic' for existing Storybooks [#19716](https://github.com/storybooks/storybook/pull/19716)\n- Builder-webpack5: Use import.meta.webpackHot instead of module.hot for check [#19686](https://github.com/storybooks/storybook/pull/19686)\n- Fix: Point to correct .d.ts files from export maps [#19724](https://github.com/storybooks/storybook/pull/19724)\n- CLI: Remove deprecated `-s` flag on `sb init` [#19585](https://github.com/storybooks/storybook/pull/19585)\n\n#### Build\n\n- Build: Fix eslint formatting in scripts [#19765](https://github.com/storybooks/storybook/pull/19765)\n- Sandboxes: Fix up stories entry to allow HMR [#19750](https://github.com/storybooks/storybook/pull/19750)\n- Fix prepare script on Windows machines [#19762](https://github.com/storybooks/storybook/pull/19762)\n- CI: Fix fix handle-release-branches workflow [#19756](https://github.com/storybooks/storybook/pull/19756)\n- Build: Cancel workflow in CI on steps failure [#19748](https://github.com/storybooks/storybook/pull/19748)\n- CI: Schedule a daily job that runs all sandboxes [#19699](https://github.com/storybooks/storybook/pull/19699)\n- Build: Delete node_modules in repro generation [#19734](https://github.com/storybooks/storybook/pull/19734)\n- Fix: dts facade generator did not support deep links [#19723](https://github.com/storybooks/storybook/pull/19723)\n- Build: Re-enable test-runner for vue-cli [#19706](https://github.com/storybooks/storybook/pull/19706)\n\n#### Dependency Upgrades\n\n- Upgrade mdx2-csf to fix mdxSource generation [#19766](https://github.com/storybooks/storybook/pull/19766)\n- Dependencies: Bump prettier dependency, cleanup config [#19672](https://github.com/storybooks/storybook/pull/19672)\n- Vue: Add babel loader 9.0.0 to vue-webpack5 peer dependencies [#19697](https://github.com/storybooks/storybook/pull/19697)\n\n## 7.0.0-alpha.47 (November 1, 2022)\n\n#### Features\n\n- CSF-tools: Turn story comments into docs descriptions [#19684](https://github.com/storybooks/storybook/pull/19684)\n- CLI: Migrate CLI templates to CSF3 [#19665](https://github.com/storybooks/storybook/pull/19665)\n- Vite: Set default `base` for subfolder deployments [#19383](https://github.com/storybooks/storybook/pull/19383)\n\n#### Bug Fixes\n\n- Disable keyboard shortcuts during (docs) play functions and add tests [#19668](https://github.com/storybooks/storybook/pull/19668)\n\n#### Maintenance\n\n- Addon-docs: Replace source-loader with csf-plugin [#19680](https://github.com/storybooks/storybook/pull/19680)\n- CLI: Move all templates out of cli into renderers [#19664](https://github.com/storybooks/storybook/pull/19664)\n- Addon-docs: Remove mdx-compiler-plugin [#19681](https://github.com/storybooks/storybook/pull/19681)\n\n## 7.0.0-alpha.46 (October 28, 2022)\n\n#### Features\n\n- Addon-docs: Don't show docspage unless the user opts in [#19627](https://github.com/storybooks/storybook/pull/19627)\n- Core: Allow setting tags in storiesOf via parameters. [#19642](https://github.com/storybooks/storybook/pull/19642)\n\n#### Bug Fixes\n\n- Addon-docs: Fix React Profiler in source snippets [#19004](https://github.com/storybooks/storybook/pull/19004)\n\n#### Maintenance\n\n- Telemetry: Measure version update check [#19660](https://github.com/storybooks/storybook/pull/19660)\n- Build: Bundle lib/preview-web with ts-up [#19655](https://github.com/storybooks/storybook/pull/19655)\n- CSF-tools: Make ESM node compatible [#19661](https://github.com/storybooks/storybook/pull/19661)\n- Telemetry: Measure docs usage [#19648](https://github.com/storybooks/storybook/pull/19648)\n- Go back to `csf@next` [#19657](https://github.com/storybooks/storybook/pull/19657)\n\n#### Build\n\n- Build: Reduce parallelism in check task [#19662](https://github.com/storybooks/storybook/pull/19662)\n\n## 7.0.0-alpha.45 (October 28, 2022)\n\n#### Bug Fixes\n\n- Svelte: Fix regression causing all stories to error [#19653](https://github.com/storybooks/storybook/pull/19653)\n- CSF: Fix `StoryObj<typeof Cmp>` to work the same as old ComponentStoryObj [#19651](https://github.com/storybooks/storybook/pull/19651)\n\n#### Maintenance\n\n- Core: Misc dead code removal [#19654](https://github.com/storybooks/storybook/pull/19654)\n- Addon-actions: Move decorator to its own entrypoint [#19650](https://github.com/storybooks/storybook/pull/19650)\n\n#### Build\n\n- Build: Reduce resource classes [#19652](https://github.com/storybooks/storybook/pull/19652)\n\n## 7.0.0-alpha.44 (October 27, 2022)\n\n#### Features\n\n- Add tags to story and index [#19625](https://github.com/storybooks/storybook/pull/19625)\n- CSF tools: Add tags support [#19626](https://github.com/storybooks/storybook/pull/19626)\n- Vue2: Improve CSF3 types [#19603](https://github.com/storybooks/storybook/pull/19603)\n- Vue3: Improve CSF3 types [#19602](https://github.com/storybooks/storybook/pull/19602)\n\n#### Bug Fixes\n\n- Core: Fix v6 store when no explicit renderer [#19624](https://github.com/storybooks/storybook/pull/19624)\n- CLI/React native: Fix addons template to import register instead of manager [#19620](https://github.com/storybooks/storybook/pull/19620)\n\n#### Maintenance\n\n- Build-storybook: Only copy .mjs files for manager build [#19647](https://github.com/storybooks/storybook/pull/19647)\n- Rename storybook/ui to storybook/manager [#19635](https://github.com/storybooks/storybook/pull/19635)\n- Addons: Support SSR by not using global.window to store hooks context [#19631](https://github.com/storybooks/storybook/pull/19631)\n- Breaking: Final few deprecations removal in a batch [#19553](https://github.com/storybooks/storybook/pull/19553)\n- TypeScript: Misc types improvements [#19633](https://github.com/storybooks/storybook/pull/19633)\n- TypeScript: Restructure storybook types [#19580](https://github.com/storybooks/storybook/pull/19580)\n- TypeScript: cleanup types [#19621](https://github.com/storybooks/storybook/pull/19621)\n\n#### Build\n\n- Build: Reduce CI usage by 60% [#19644](https://github.com/storybooks/storybook/pull/19644)\n- Remove `netlify.toml` [#19645](https://github.com/storybooks/storybook/pull/19645)\n- Small fixes for `check` task [#19643](https://github.com/storybooks/storybook/pull/19643)\n- Storybook for `@storybook/blocks` only [#19630](https://github.com/storybooks/storybook/pull/19630)\n- Fix broken stories in UI Storybook [#19632](https://github.com/storybooks/storybook/pull/19632)\n- Ugrade eslint [#19601](https://github.com/storybooks/storybook/pull/19601)\n- Integrate standalone Storybook with Chromatic [#19619](https://github.com/storybooks/storybook/pull/19619)\n\n## 7.0.0-alpha.43 (October 25, 2022)\n\n#### Bug Fixes\n\n- Core: Add `renderer` field to frameworks, and use to drive v6 store entrypoints [#19595](https://github.com/storybooks/storybook/pull/19595)\n- Core: Add new SET_INDEX event [#19590](https://github.com/storybooks/storybook/pull/19590)\n- CLI: Don't run MDX2 automigration on node_modules [#19611](https://github.com/storybooks/storybook/pull/19611)\n- Core: Ensure preview annotations are resolved relative to the cwd [#19594](https://github.com/storybooks/storybook/pull/19594)\n- Core: Fix addon URLs on Windows [#19589](https://github.com/storybooks/storybook/pull/19589)\n\n#### Maintenance\n\n- Vite: Tidy up mdx-plugin [#19563](https://github.com/storybooks/storybook/pull/19563)\n- Web-components/Vite: remove unused dependencies [#19583](https://github.com/storybooks/storybook/pull/19583)\n\n#### Build\n\n- Remove DocBlocks example Storybook [#19616](https://github.com/storybooks/storybook/pull/19616)\n- Move and include `@storybook/blocks` in standalone Storybook [#19615](https://github.com/storybooks/storybook/pull/19615)\n- Move and include `@storybook/components` in standalone Storybook [#19598](https://github.com/storybooks/storybook/pull/19598)\n- Move examples -> test-storybooks [#19599](https://github.com/storybooks/storybook/pull/19599)\n- MDX iframe stories [#19586](https://github.com/storybooks/storybook/pull/19586)\n\n#### Dependency Upgrades\n\n- Upgrade mdx2-csf to next [#19600](https://github.com/storybooks/storybook/pull/19600)\n\n## 7.0.0-alpha.42 (October 24, 2022)\n\n#### Features\n\n- Svelte: Improve CSF3 types [#19512](https://github.com/storybooks/storybook/pull/19512)\n\n#### Maintenance\n\n- Telemetry: Use a wrapper around all CLI commands to send boot and error events [#19566](https://github.com/storybooks/storybook/pull/19566)\n\n#### Build\n\n- Add ability to run tasks from code dir [#19588](https://github.com/storybooks/storybook/pull/19588)\n- Make the reporter dynamic [#19587](https://github.com/storybooks/storybook/pull/19587)\n- Add vite-react benchmark [#19558](https://github.com/storybooks/storybook/pull/19558)\n\n#### Dependency Upgrades\n\n- Fix test-runner version conflicts [#19581](https://github.com/storybooks/storybook/pull/19581)\n\n## 7.0.0-alpha.41 (October 21, 2022)\n\n#### Features\n\n- Add `@storybook/nextjs` framework [#19382](https://github.com/storybooks/storybook/pull/19382)\n- CLI: Enable `@storybook/nextjs` framework [#19478](https://github.com/storybooks/storybook/pull/19478)\n- CLI: Automigrate from MDX1 to MDX2 [#19568](https://github.com/storybooks/storybook/pull/19568)\n\n#### Maintenance\n\n- Remove warning of removed feature in lib/client-api [#19544](https://github.com/storybooks/storybook/pull/19544)\n- Remove vite-plugin-svelte-kit when detected [#19522](https://github.com/storybooks/storybook/pull/19522)\n\n#### Build\n\n- Delete Svelte example [#19549](https://github.com/storybooks/storybook/pull/19549)\n- Fix circle test results [#19552](https://github.com/storybooks/storybook/pull/19552)\n\n#### Dependency Upgrades\n\n- Update the version of the \"update-notifier\" package [#19569](https://github.com/storybooks/storybook/pull/19569)\n\n## 7.0.0-alpha.40 (October 20, 2022)\n\n#### Breaking Changes\n\n- Addon-docs: Upgrade to MDXv2 [#19495](https://github.com/storybooks/storybook/pull/19495)\n\n#### Bug Fixes\n\n- Addon-docs: Don't generate docs page entries for CSF files with no stories [#19529](https://github.com/storybooks/storybook/pull/19529)\n\n#### Maintenance\n\n- Remove deprecate features from preview-web [#19540](https://github.com/storybooks/storybook/pull/19540)\n- Remove deprecated features in lib/api [#19539](https://github.com/storybooks/storybook/pull/19539)\n- Remove default selection in docblocks [#19537](https://github.com/storybooks/storybook/pull/19537)\n\n#### Build\n\n- Remove .git folder when generating repros [#19535](https://github.com/storybooks/storybook/pull/19535)\n- Some task runner tweaks + move test-runner into sandbox task. [#19505](https://github.com/storybooks/storybook/pull/19505)\n- Build builder-webpack5 with ts-up [#19435](https://github.com/storybooks/storybook/pull/19435)\n\n## 7.0.0-alpha.39 (October 19, 2022)\n\n#### Breaking Changes\n\n- Addons: Remove deprecations [#19524](https://github.com/storybooks/storybook/pull/19524)\n\n#### Features\n\n- Core: Throw an error if renderer is used as framework [#19452](https://github.com/storybooks/storybook/pull/19452)\n- CLI: Add pnpm support [#19425](https://github.com/storybooks/storybook/pull/19425)\n- CLI: support .json in eslint-plugin migration [#19511](https://github.com/storybooks/storybook/pull/19511)\n\n#### Bug Fixes\n\n- Vite/React: Align with webpack react docgen [#19399](https://github.com/storybooks/storybook/pull/19399)\n- Core: Direct logs to stdout [#19434](https://github.com/storybooks/storybook/pull/19434)\n- Telemetry: Send start/build events even when there is no generator [#19507](https://github.com/storybooks/storybook/pull/19507)\n- Core: Fix inconsistent telemetry debug [#19509](https://github.com/storybooks/storybook/pull/19509)\n\n#### Maintenance\n\n- Addon-docs: Define children for DocsContainer [#19437](https://github.com/storybooks/storybook/pull/19437)\n- Convert issue templates to forms [#19370](https://github.com/storybooks/storybook/pull/19370)\n- Change once.warn to deprecate when that is the actual intent [#19521](https://github.com/storybooks/storybook/pull/19521)\n- Cleanup framework angular dependencies [#19389](https://github.com/storybooks/storybook/pull/19389)\n- Frameworks: Don't re-export renderer types from frameworks [#19510](https://github.com/storybooks/storybook/pull/19510)\n- Core: Remove storyStore.getSelection [#19491](https://github.com/storybooks/storybook/pull/19491)\n- CLI: rename \"latest\" to \"v13\" app name in angular v13 repro template [#19498](https://github.com/storybooks/storybook/pull/19498)\n\n#### Build\n\n- Improve misc build parts [#19520](https://github.com/storybooks/storybook/pull/19520)\n- Build: Bundle addons/storysource with ts-up [#19482](https://github.com/storybooks/storybook/pull/19482)\n- Build: Bundle lib/docs-tools & lib/instrumenter with ts-up [#19206](https://github.com/storybooks/storybook/pull/19206)\n- Actions: update actions/setup-node to v3 [#19444](https://github.com/storybooks/storybook/pull/19444)\n- Actions: update actions/checkout to v3 [#19441](https://github.com/storybooks/storybook/pull/19441)\n- Build: Bundle lib/codemod with ts-up [#19398](https://github.com/storybooks/storybook/pull/19398)\n- Build: Bundle addons/highlight with ts-up [#19483](https://github.com/storybooks/storybook/pull/19483)\n- Enable preact templates and remove `preact-kitchen-sink` [#19454](https://github.com/storybooks/storybook/pull/19454)\n\n#### Dependency Upgrades\n\n- Addon-docs: Make babel-loader an optional peer dependency [#19385](https://github.com/storybooks/storybook/pull/19385)\n- Add missing addons/docs dependency for fs-extra [#19493](https://github.com/storybooks/storybook/pull/19493)\n\n## 7.0.0-alpha.38 (October 15, 2022)\n\n#### Bug Fixes\n\n- Vite: Fix bail not being defined for vite builder [#19405](https://github.com/storybooks/storybook/pull/19405)\n\n#### Maintenance\n\n- Breaking: Remove onBeforeRender [#19489](https://github.com/storybooks/storybook/pull/19489)\n- Breaking: Upgrade to use node 16 everywhere [#19458](https://github.com/storybooks/storybook/pull/19458)\n- Breaking: Remove the old showRoots config option [#19440](https://github.com/storybooks/storybook/pull/19440)\n- CLI: Make the button component accept a label prop, (not children) [#19461](https://github.com/storybooks/storybook/pull/19461)\n- Remove `angular-cli` example [#19202](https://github.com/storybooks/storybook/pull/19202)\n- Breakimg: Remove the html entrypoint of lib/components [#19487](https://github.com/storybooks/storybook/pull/19487)\n- Vite: Add partial SvelteKit support [#19338](https://github.com/storybooks/storybook/pull/19338)\n\n#### Build\n\n- Angular: Add angular 14 sandbox template [#19181](https://github.com/storybooks/storybook/pull/19181)\n- Storybook for Storybook - step 1: `ui/manager` [#19465](https://github.com/storybooks/storybook/pull/19465)\n- Don't pass the full path to repro generators [#19480](https://github.com/storybooks/storybook/pull/19480)\n- Bundle lib/channel-postmessage with ts-up [#19388](https://github.com/storybooks/storybook/pull/19388)\n- Disable smoke test [#19475](https://github.com/storybooks/storybook/pull/19475)\n- Remove angular example from monorepo [#19467](https://github.com/storybooks/storybook/pull/19467)\n- Add angular 13 repro template [#19428](https://github.com/storybooks/storybook/pull/19428)\n- Add a TypeScript check task and configure ci to run it [#19471](https://github.com/storybooks/storybook/pull/19471)\n- Add Preact/Webpack templates and update renderer/preset (2) [#19451](https://github.com/storybooks/storybook/pull/19451)\n- Disable another smoke test [#19466](https://github.com/storybooks/storybook/pull/19466)\n\n#### Dependency Upgrades\n\n- Ipgrade chromatic [#19468](https://github.com/storybooks/storybook/pull/19468)\n\n## 7.0.0-alpha.37 (October 13, 2022)\n\n#### Features\n\n- React: Sound arg types for CSF3 [#19238](https://github.com/storybooks/storybook/pull/19238)\n- Vite: Add web-components/lit framework support [#19164](https://github.com/storybooks/storybook/pull/19164)\n- UI: Update colors for 7.0 [#19023](https://github.com/storybooks/storybook/pull/19023)\n\n#### Bug Fixes\n\n- Server: Ensure consistent route handling by always starting `managerBuilder` before `previewBuilder` [#19406](https://github.com/storybooks/storybook/pull/19406)\n- UI: Fix addon URL escaping in manager [#19375](https://github.com/storybooks/storybook/pull/19375)\n- CLI: remove `npx` usage from storybook scripts [#19366](https://github.com/storybooks/storybook/pull/19366)\n- Webpack5: Fix lazy compilation/fscache builderOptions when base config is disabled [#19387](https://github.com/storybooks/storybook/pull/19387)\n\n#### Maintenance\n\n- Breaking: remove the deprecated Preview component [#19445](https://github.com/storybooks/storybook/pull/19445)\n- Breaking: remove deprecated channel apis [#19443](https://github.com/storybooks/storybook/pull/19443)\n- Breaking: remove framework angulars storymodule story-component handling [#19442](https://github.com/storybooks/storybook/pull/19442)\n- Breaking: remove deprecated glob fixing [#19438](https://github.com/storybooks/storybook/pull/19438)\n- Refactor bootstrap+sandbox into \"task\" framework [#19275](https://github.com/storybooks/storybook/pull/19275)\n- CI: Fix test-runner build step [#19255](https://github.com/storybooks/storybook/pull/19255)\n- Angular: Drop support for angular < 13 [#19368](https://github.com/storybooks/storybook/pull/19368)\n- Build: Add installScripts step in bootstrap command [#19270](https://github.com/storybooks/storybook/pull/19270)\n- Vite: Move default cache dir to node_modules/.cache [#19384](https://github.com/storybooks/storybook/pull/19384)\n\n#### Build\n\n- Addon-docs: Refactor MDX examples to sandboxes [#19301](https://github.com/storybooks/storybook/pull/19301)\n- Undo accidental push of tom/sb-557-typescript-2 [#19450](https://github.com/storybooks/storybook/pull/19450)\n- Ensure we kill all controllers before exiting [#19449](https://github.com/storybooks/storybook/pull/19449)\n- Examples: Remove official-storybook [#19343](https://github.com/storybooks/storybook/pull/19343)\n- Build: Improve template stories [#19402](https://github.com/storybooks/storybook/pull/19402)\n- Vue: Delete vue-cli/vue-kitchen-sink examples [#19429](https://github.com/storybooks/storybook/pull/19429)\n- React: Remove react-ts example [#19424](https://github.com/storybooks/storybook/pull/19424)\n- Web-components: Port template stories and delete web-components-kitchen-sink [#19430](https://github.com/storybooks/storybook/pull/19430)\n- remove html-kitchen-sink example [#19360](https://github.com/storybooks/storybook/pull/19360)\n- add template for html-webpack5 [#19377](https://github.com/storybooks/storybook/pull/19377)\n- use a single version of yarn [#19417](https://github.com/storybooks/storybook/pull/19417)\n- fix build command for netlify [#19418](https://github.com/storybooks/storybook/pull/19418)\n- Re-enable `svelte-vite/default-ts` template [#19369](https://github.com/storybooks/storybook/pull/19369)\n- Only persist the (single) built sandbox [#19372](https://github.com/storybooks/storybook/pull/19372)\n\n#### Dependency Upgrades\n\n- Replace @storybook/semver with semver [#19292](https://github.com/storybooks/storybook/pull/19292)\n- Upgrade playwright [#19416](https://github.com/storybooks/storybook/pull/19416)\n\n## 7.0.0-alpha.36 (October 13, 2022)\n\nBad publish\n\n## 7.0.0-alpha.35 (October 5, 2022)\n\n#### Features\n\n- Angular: Disable ngcc when not needed [#19307](https://github.com/storybooks/storybook/pull/19307)\n- Vite: Add vue-vite framework for Vue2 [#19230](https://github.com/storybooks/storybook/pull/19230)\n- Storyshots-puppeteer: Add browserLaunchOptions to CommonConfig [#18927](https://github.com/storybooks/storybook/pull/18927)\n\n#### Bug Fixes\n\n- Vite: Fix svelte docgen and svelte-native stories [#19339](https://github.com/storybooks/storybook/pull/19339)\n- CLI: Exclude @storybook/testing-react from outdated check [#19272](https://github.com/storybooks/storybook/pull/19272)\n- Interactions: Fix path to checkActionsLoaded [#19334](https://github.com/storybooks/storybook/pull/19334)\n- Webpack: Fix resolution of webpack config relating to resolve fallbacks (assert) [#19358](https://github.com/storybooks/storybook/pull/19358)\n- Vite: Add vite framework plugin if not found [#19259](https://github.com/storybooks/storybook/pull/19259)\n- Vue2: Fix play function `within` & args updating in decorators [#19207](https://github.com/storybooks/storybook/pull/19207)\n\n#### Maintenance\n\n- Addon-docs: Remove STORYBOOK_REACT_CLASSES and global/globals.ts [#19300](https://github.com/storybooks/storybook/pull/19300)\n- Cleanup premature merge [#19332](https://github.com/storybooks/storybook/pull/19332)\n- CLI: Update sb add for main.js [#19312](https://github.com/storybooks/storybook/pull/19312)\n- React: Move argType stories to template/stories folder [#19265](https://github.com/storybooks/storybook/pull/19265)\n\n#### Build\n\n- Build: Add react17 + webpack5 template [#19342](https://github.com/storybooks/storybook/pull/19342)\n- Build: Add react18 + webpack5 template [#19341](https://github.com/storybooks/storybook/pull/19341)\n- Build: Forward parameters in nx command execution [#19283](https://github.com/storybooks/storybook/pull/19283)\n- Build: cleanup after moving to tsup [#19268](https://github.com/storybooks/storybook/pull/19268)\n- Build: change the vue e2e test to use webpack5, since we stopped supporting webpack4 in 7.0 [#19257](https://github.com/storybooks/storybook/pull/19257)\n- Build: Add vue-cli/vue2 repro template [#19314](https://github.com/storybooks/storybook/pull/19314)\n- Build: Bundle addons-actions with ts-up [#18775](https://github.com/storybooks/storybook/pull/18775)\n- Build: Bundle lib/addons with ts-up [#18805](https://github.com/storybooks/storybook/pull/18805)\n- Build: improve the tsconfig [#19346](https://github.com/storybooks/storybook/pull/19346)\n- Build: Bundle lib/telemetry with ts-up [#19317](https://github.com/storybooks/storybook/pull/19317)\n- Build: Bundle lib/store with tsup [#19308](https://github.com/storybooks/storybook/pull/19308)\n- Build: Bundle lib/source-loader with ts-up [#19313](https://github.com/storybooks/storybook/pull/19313)\n- Build: Bundle lib/csf-tools with ts-up [#18914](https://github.com/storybooks/storybook/pull/18914)\n- Build: Bundle lib/core-client with ts-up [#19276](https://github.com/storybooks/storybook/pull/19276)\n- Build: Bundle lib/client-api with ts-up [#19271](https://github.com/storybooks/storybook/pull/19271)\n- Build: Bundle lib/postinstall with ts-up [#19327](https://github.com/storybooks/storybook/pull/19327)\n- Build: Add react18 + webpack5 template [#19341](https://github.com/storybooks/storybook/pull/19341)\n- Build: Remove cypress from monorepo [#19303](https://github.com/storybooks/storybook/pull/19303)\n- Build: Disable smoke test on cra/default-ts [#19352](https://github.com/storybooks/storybook/pull/19352)\n- Build: Fix prepare bundle on Windows [#19243](https://github.com/storybooks/storybook/pull/19243)\n- Build: Bundle addons/essentials with ts-up [#19322](https://github.com/storybooks/storybook/pull/19322)\n\n## 7.0.0-alpha.34 (September 27, 2022)\n\n#### Features\n\n- Vite: Export storybook utilities from frameworks for better pnpm support [#19216](https://github.com/storybooks/storybook/pull/19216)\n\n#### Bug Fixes\n\n- Vite: Do not add Webpack loaders when using Vite builder [#19263](https://github.com/storybooks/storybook/pull/19263)\n- Source-loader: Fix invalid call to CSF sanitize [#18930](https://github.com/storybooks/storybook/pull/18930)\n- Svelte: generate preview file with js extension always [#19253](https://github.com/storybooks/storybook/pull/19253)\n- UI: Fix react runtime for addons in manager [#19226](https://github.com/storybooks/storybook/pull/19226)\n- Svelte: Fix button component not accepting the onClick handler [#19249](https://github.com/storybooks/storybook/pull/19249)\n- Vite: Support runStep in Vite builder SSv6 [#19235](https://github.com/storybooks/storybook/pull/19235)\n- Angular: Alias decorateStory as applyDecorators [#19189](https://github.com/storybooks/storybook/pull/19189)\n- UI: Recalculate height of ZoomElement when child element updates [#15472](https://github.com/storybooks/storybook/pull/15472)\n- UI: Fix copy button copying outdated snippet [#18888](https://github.com/storybooks/storybook/pull/18888)\n- UI: Fix clipboard issue [#18999](https://github.com/storybooks/storybook/pull/18999)\n- CLI: Do not remove framework dependency in automigration [#19129](https://github.com/storybooks/storybook/pull/19129)\n- TS: Type `storyIdToEntry` explicitly [#19123](https://github.com/storybooks/storybook/pull/19123)\n\n#### Maintenance\n\n- Vue3: Add generic renderer stories & delete vue3 example [#19219](https://github.com/storybooks/storybook/pull/19219)\n- Build: Remove unused angular_modern_inline_rendering [#19254](https://github.com/storybooks/storybook/pull/19254)\n- Build: bundle csf-tools with tsup [#19141](https://github.com/storybooks/storybook/pull/19141)\n- Build: Enforce @ts-expect-error via eslint [#19198](https://github.com/storybooks/storybook/pull/19198)\n- Vue: Add repro template for vue-cli [#19165](https://github.com/storybooks/storybook/pull/19165)\n- Build: Link renderer-specific stories inside the sandbox's real stories dir [#19185](https://github.com/storybooks/storybook/pull/19185)\n- Build: Remove `cra-kitchen-sink` example [#19179](https://github.com/storybooks/storybook/pull/19179)\n- Build: Fix the check script [#19184](https://github.com/storybooks/storybook/pull/19184)\n- Build: Build lib/node-logger with ts-up [#19173](https://github.com/storybooks/storybook/pull/19173)\n- Build: Fix sandbox running multiple versions of react [#19156](https://github.com/storybooks/storybook/pull/19156)\n- Build: fix playwright version again [#19250](https://github.com/storybooks/storybook/pull/19250)\n- Build: upgrade playwright version (and lock it) [#19227](https://github.com/storybooks/storybook/pull/19227)\n\n#### Dependency Upgrades\n\n- Remove @nicolo-ribaudo/chokidar-2 [#19244](https://github.com/storybooks/storybook/pull/19244)\n\n## 7.0.0-alpha.33 (September 13, 2022)\n\n#### Features\n\n- Core: Add a new `throwPlayFunctionExceptions` parameter [#19143](https://github.com/storybooks/storybook/pull/19143)\n\n#### Bug Fixes\n\n- Fix issue in instrumenter with `waitFor` [#19145](https://github.com/storybooks/storybook/pull/19145)\n- Core: Fix static dirs targeting same destination [#19064](https://github.com/storybooks/storybook/pull/19064)\n- React: Fix issue with react 18 implementation [#19125](https://github.com/storybooks/storybook/pull/19125)\n- CLI: Fix spawning child processes on windows [#19019](https://github.com/storybooks/storybook/pull/19019)\n- Vite: Ensure we set `DOCS_OPTIONS` in the vite builder [#19127](https://github.com/storybooks/storybook/pull/19127)\n\n#### Maintenance\n\n- Build: Bundle @storybook/cli with tsup [#19138](https://github.com/storybooks/storybook/pull/19138)\n- Examples: Remove `cra-ts-essentials` [#19170](https://github.com/storybooks/storybook/pull/19170)\n- Added some basic interactions stories [#19153](https://github.com/storybooks/storybook/pull/19153)\n- Presets: Replace `config` with `previewAnnotations`, remove `previewEntries` [#19152](https://github.com/storybooks/storybook/pull/19152)\n- Addon-links: Move stories into addon [#19124](https://github.com/storybooks/storybook/pull/19124)\n- Addon-a11y: Move stories into addon [#19114](https://github.com/storybooks/storybook/pull/19114)\n- Toolbars: Generic example stories [#19166](https://github.com/storybooks/storybook/pull/19166)\n- TypeScript: Revert a few @ts-expect-errors [#19168](https://github.com/storybooks/storybook/pull/19168)\n- Addon-docs: Generic stories for DocsPage [#19162](https://github.com/storybooks/storybook/pull/19162)\n- Controls: Generic stories for sorting [#19161](https://github.com/storybooks/storybook/pull/19161)\n- Build: Generic stories for addon-controls [#19149](https://github.com/storybooks/storybook/pull/19149)\n- remove node12 from the matrix [#19147](https://github.com/storybooks/storybook/pull/19147)\n- Build libs/router with ts-up [#19140](https://github.com/storybooks/storybook/pull/19140)\n- Build: Bundle addon-interactions with tsup [#19139](https://github.com/storybooks/storybook/pull/19139)\n- Generic stories for remaining core features [#19118](https://github.com/storybooks/storybook/pull/19118)\n- Add parameter, loader and decorator stories to `lib/store` [#19105](https://github.com/storybooks/storybook/pull/19105)\n- Convert @ts-ignore to @ts-expect-error [#19122](https://github.com/storybooks/storybook/pull/19122)\n\n#### Dependency Upgrades\n\n- Upgrade emotion deps again [#19054](https://github.com/storybooks/storybook/pull/19054)\n\n## 7.0.0-alpha.31 (September 7, 2022)\n\n#### Maintenance\n\n- Doc blocks: Update ArgTable Reset button to use IconButton [#19052](https://github.com/storybooks/storybook/pull/19052)\n- UI: Update a handful of icons [#19084](https://github.com/storybooks/storybook/pull/19084)\n- Build: Update to latest nx [#19078](https://github.com/storybooks/storybook/pull/19078)\n- Vite: Fix plugin types [#19095](https://github.com/storybooks/storybook/pull/19095)\n\n#### Dependency Upgrades\n\n- Chore: Remove unused dependencies in /lib [#19100](https://github.com/storybooks/storybook/pull/19100)\n\n## 7.0.0-alpha.30 (September 6, 2022)\n\n#### Bug Fixes\n\n- CLI: Fix include rendererAssets in npm bundle [#19115](https://github.com/storybooks/storybook/pull/19115)\n\n#### Maintenance\n\n- CLI: remove outdated comment in Angular starter [#19097](https://github.com/storybooks/storybook/pull/19097)\n\n#### Dependency Upgrades\n\n- Remove deprecated `stable` dependency [#19103](https://github.com/storybooks/storybook/pull/19103)\n- Svelte: Update sveltedoc dependencies [#19111](https://github.com/storybooks/storybook/pull/19111)\n- Deps: Remove core-js from most packages [#19098](https://github.com/storybooks/storybook/pull/19098)\n- Deps: Upgrade react-element-to-jsx-string and react-inspector for React 18 [#19104](https://github.com/storybooks/storybook/pull/19104)\n\n## 7.0.0-alpha.29 (September 2, 2022)\n\n#### Bug Fixes\n\n- CLI/Vite: Don't add babel dependencies during init [#19088](https://github.com/storybooks/storybook/pull/19088)\n- CLI: Fix sb init to use renderer assets instead of frameworks [#19091](https://github.com/storybooks/storybook/pull/19091)\n- Core: Ensure if a docs render is torndown during preparation, it throws [#19071](https://github.com/storybooks/storybook/pull/19071)\n\n#### Maintenance\n\n- Addon-viewport: Move stories into addon [#19086](https://github.com/storybooks/storybook/pull/19086)\n- Addon-backgrounds: Move stories into addon [#19085](https://github.com/storybooks/storybook/pull/19085)\n- Addon-actions: Move stories into addon [#19082](https://github.com/storybooks/storybook/pull/19082)\n- Build: Exit yarn bootstrap with nonzero code if failed [#19089](https://github.com/storybooks/storybook/pull/19089)\n- Vite: cleanup custom plugins [#19087](https://github.com/storybooks/storybook/pull/19087)\n- Build: Prefix generic addon stories in sandbox storybooks [#19092](https://github.com/storybooks/storybook/pull/19092)\n\n## 7.0.0-alpha.28 (September 2, 2022)\n\n#### Features\n\n- Vite: Automatically use vite.config.js [#19026](https://github.com/storybooks/storybook/pull/19026)\n\n#### Bug Fixes\n\n- CLI: Fix race condition in sb init [#19083](https://github.com/storybooks/storybook/pull/19083)\n- Vite: Fix framework option checks, and SSv6 [#19062](https://github.com/storybooks/storybook/pull/19062)\n- Core: Fix WebProjectAnnotations export in preview-web for back-compat [#19048](https://github.com/storybooks/storybook/pull/19048)\n- Blocks: Fix Checkbox control update when using useArgs hook\n\n#### Maintenance\n\n- Update to new TS reference format (?) [#19072](https://github.com/storybooks/storybook/pull/19072)\n- Build: Conditionally force vite rebuilds in sandbox [#19063](https://github.com/storybooks/storybook/pull/19063)\n- Build: Fix CRA bench [#19066](https://github.com/storybooks/storybook/pull/19066)\n\n## 7.0.0-alpha.27 (August 31, 2022)\n\n#### Features\n\n- Vite: Set `resolve.preserveSymlinks` based on env vars [#19039](https://github.com/storybooks/storybook/pull/19039)\n\n#### Bug Fixes\n\n- Core: Restore `/preview` etc package exports; return unresolved path from presets. [#19045](https://github.com/storybooks/storybook/pull/19045)\n\n#### Maintenance\n\n- Core: Add previewHead and previewBody to StorybookConfig interface [#19047](https://github.com/storybooks/storybook/pull/19047)\n- Build: Fix the sb-bench CI step [#19029](https://github.com/storybooks/storybook/pull/19029)\n- Remove sandbox from `.ignore` [#19040](https://github.com/storybooks/storybook/pull/19040)\n- Build: Use new test runner with builtin junit [#19028](https://github.com/storybooks/storybook/pull/19028)\n\n#### Dependency Upgrades\n\n- Vite: Clean up framework dependencies / unused files [#19035](https://github.com/storybooks/storybook/pull/19035)\n\n## 7.0.0-alpha.26 (August 26, 2022)\n\n#### Features\n\n- CLI: Add react, vue3, and svelte vite to new-frameworks automigration [#19016](https://github.com/storybooks/storybook/pull/19016)\n- Svelte: Add svelte-vite framework [#18978](https://github.com/storybooks/storybook/pull/18978)\n\n#### Bug Fixes\n\n- Core: Fix default story glob [#19018](https://github.com/storybooks/storybook/pull/19018)\n\n#### Dependency Upgrades\n\n- React-vite: update/cleanup dependencies [#19025](https://github.com/storybooks/storybook/pull/19025)\n- Remove babel-loader from core-common [#19022](https://github.com/storybooks/storybook/pull/19022)\n\n## 7.0.0-alpha.25 (August 25, 2022)\n\n#### Features\n\n- Vite: Add builder-vite, react-vite, and vue3-vite [#19007](https://github.com/storybooks/storybook/pull/19007)\n\n#### Maintenance\n\n- CI: use runner with playwright installed for cra_bench [#18951](https://github.com/storybooks/storybook/pull/18951)\n- Replace rollup-plugin-node-polyfills to analogs [#18975](https://github.com/storybooks/storybook/pull/18975)\n\n## 7.0.0-alpha.24 (August 24, 2022)\n\n#### Breaking changes\n\n- Preview: Rename Storybook DOM root IDs [#10638](https://github.com/storybooks/storybook/pull/10638)\n\n#### Features\n\n- Interactions: Add `step` function and support multiple levels of nesting [#18555](https://github.com/storybooks/storybook/pull/18555)\n\n#### Bug Fixes\n\n- Addon-docs: Fix canvas support expand code for non-story [#18808](https://github.com/storybooks/storybook/pull/18808)\n- Components: Avoid including line numbers when copying the code [#18725](https://github.com/storybooks/storybook/pull/18725)\n- Vue: Fix enum check in extractArgTypes [#18959](https://github.com/storybooks/storybook/pull/18959)\n- Core: Fix frameworkOptions preset [#18979](https://github.com/storybooks/storybook/pull/18979)\n\n#### Maintenance\n\n- Addon-a11y: Remove achromatomaly color filter [#18852](https://github.com/storybooks/storybook/pull/18852)\n- Build: Use ts-up to build core-webpack [#18912](https://github.com/storybooks/storybook/pull/18912)\n- Build: Use ts-up to build addon-viewport [#18943](https://github.com/storybooks/storybook/pull/18943)\n- Build: Improve generate-repros-next [#19001](https://github.com/storybooks/storybook/pull/19001)\n- Examples: Remove refs in angular example [#18986](https://github.com/storybooks/storybook/pull/18986)\n- Build: Use ts-up to build client-logger [#18893](https://github.com/storybooks/storybook/pull/18893)\n- Generate-repros: Run local registry on `--local-registry` option [#18997](https://github.com/storybooks/storybook/pull/18997)\n- Build: Remove unused bootstrap --cleanup [#18981](https://github.com/storybooks/storybook/pull/18981)\n- CLI: Fix local repro publishing [#18977](https://github.com/storybooks/storybook/pull/18977)\n- Build: Run verdaccio on 6001 to enable web UI [#18983](https://github.com/storybooks/storybook/pull/18983)\n- CLI: determine whether to add interactive stories from `renderer` rather than `framework` [#18968](https://github.com/storybooks/storybook/pull/18968)\n- CLI: Auto-accept migrations when running `generate-repros-next` [#18969](https://github.com/storybooks/storybook/pull/18969)\n\n## 7.0.0-alpha.23 (August 18, 2022)\n\n#### Features\n\n- UI: Polish canvas and sidebar for 7.0 [#18894](https://github.com/storybooks/storybook/pull/18894)\n\n#### Maintenance\n\n- Sandbox: Add ability to run from local repro [#18950](https://github.com/storybooks/storybook/pull/18950)\n- Repros: Add ability to generate repros using local registry [#18948](https://github.com/storybooks/storybook/pull/18948)\n- CLI: Move write/read package json into JsPackageManager [#18942](https://github.com/storybooks/storybook/pull/18942)\n\n## 7.0.0-alpha.22 (August 18, 2022)\n\nFailed publish to npm\n\n## 7.0.0-alpha.21 (August 17, 2022)\n\n#### Maintenance\n\n- UI: Update every icon for v7 design [#18809](https://github.com/storybooks/storybook/pull/18809)\n\n## 7.0.0-alpha.20 (August 16, 2022)\n\n#### Features\n\n- CLI: Automigration for new frameworks [#18919](https://github.com/storybooks/storybook/pull/18919)\n\n#### Bug Fixes\n\n- UI: Fix the order of addons appearing in prebuilt manager [#18918](https://github.com/storybooks/storybook/pull/18918)\n\n#### Maintenance\n\n- Exit sandbox gracefully on cancel [#18936](https://github.com/storybooks/storybook/pull/18936)\n- Disable telemetry in monorepo and CI [#18935](https://github.com/storybooks/storybook/pull/18935)\n- Convert cypress e2e tests to playwright [#18932](https://github.com/storybooks/storybook/pull/18932)\n- CI: Refactor to use tasks [#18922](https://github.com/storybooks/storybook/pull/18922)\n- Angular: Add renderer components / stories [#18934](https://github.com/storybooks/storybook/pull/18934)\n- Examples: Add angular repro template and refactor [#18931](https://github.com/storybooks/storybook/pull/18931)\n\n## 7.0.0-alpha.19 (August 12, 2022)\n\n#### Features\n\n- CLI: add \"storybook scripts 7.0\" automigrate command [#18769](https://github.com/storybooks/storybook/pull/18769)\n- Interactions: Run conditionally based on query param [#18706](https://github.com/storybooks/storybook/pull/18706)\n\n#### Bug Fixes\n\n- API: Return defaultValue in useParameter if story is not prepared [#18887](https://github.com/storybooks/storybook/pull/18887)\n- Store: always call composeConfigs in setProjectAnnotations [#18916](https://github.com/storybooks/storybook/pull/18916)\n- CLI: install the same version as the user in sb-scripts automigration [#18917](https://github.com/storybooks/storybook/pull/18917)\n- Theming: Add `create` export for lib/theming [#18906](https://github.com/storybooks/storybook/pull/18906)\n- Telemetry: Improve addon extraction logic [#18868](https://github.com/storybooks/storybook/pull/18868)\n- UI: Add image support to builder-manager [#18857](https://github.com/storybooks/storybook/pull/18857)\n- ArgTypes: Fix check for undefined before [#18710](https://github.com/storybooks/storybook/pull/18710)\n\n#### Maintenance\n\n- Build: use ts-up to build addon-toolbars [#18847](https://github.com/storybooks/storybook/pull/18847)\n- Build: Use ts-up to build channels [#18882](https://github.com/storybooks/storybook/pull/18882)\n- Build: Use ts-up to build addon-links [#18908](https://github.com/storybooks/storybook/pull/18908)\n- CLI: Fix remove dependencies logic [#18905](https://github.com/storybooks/storybook/pull/18905)\n- CLI: Add uninstall deps to jsPackageManager [#18900](https://github.com/storybooks/storybook/pull/18900)\n- Examples: Improve sandbox command error handling and debugging [#18869](https://github.com/storybooks/storybook/pull/18869)\n- Examples: Change to self-hosted placeholder images [#18878](https://github.com/storybooks/storybook/pull/18878)\n- CLI: add --no-init to repro-next command [#18866](https://github.com/storybooks/storybook/pull/18866)\n- Build: Got verdaccio working, borrowing heavily from the old repro command [#18844](https://github.com/storybooks/storybook/pull/18844)\n- Core-server: Move webpack to be a devDependency [#18856](https://github.com/storybooks/storybook/pull/18856)\n\n## 7.0.0-alpha.18 (August 2, 2022)\n\n#### Features\n\n- CLI: Add temporary sb repro-next command that only degits repros [#18834](https://github.com/storybooks/storybook/pull/18834)\n- Interactions: Add step function to play context [#18673](https://github.com/storybooks/storybook/pull/18673)\n- UI: Add preloading to stories highlighted in the sidebar [#17964](https://github.com/storybooks/storybook/pull/17964)\n\n#### Bug Fixes\n\n- UI: Fix refs with authentication being broken if the fetch for `iframe.html` succeeds (but with a request to authenticate) [#18160](https://github.com/storybooks/storybook/pull/18160)\n- HTML: Fix missing ability to set `docs.extractArgTypes` [#18831](https://github.com/storybooks/storybook/pull/18831)\n- React: Fix callback behavior in `react@18` [#18737](https://github.com/storybooks/storybook/pull/18737)\n- CLI: Throw error on failure in sb init [#18816](https://github.com/storybooks/storybook/pull/18816)\n- CLI: Fix package.json version detection [#18806](https://github.com/storybooks/storybook/pull/18806)\n\n#### Maintenance\n\n- Build: Use ts-up to build `addon-outline` [#18842](https://github.com/storybooks/storybook/pull/18842)\n- Core: Fix default framework options handling [#18676](https://github.com/storybooks/storybook/pull/18676)\n- Build: Use tsup to build `addon-measure` and fix related imports in `examples/official-storybook` [#18837](https://github.com/storybooks/storybook/pull/18837)\n- Build: Use tsup to build addon-jest [#18836](https://github.com/storybooks/storybook/pull/18836)\n- Examples: Use `repro-next` in the example script! [#18839](https://github.com/storybooks/storybook/pull/18839)\n- Examples: Rename `example` => `sandbox` [#18838](https://github.com/storybooks/storybook/pull/18838)\n- Examples: Use a set of test components in addon stories [#18825](https://github.com/storybooks/storybook/pull/18825)\n- Examples: Copy example stories over from renderer + addons [#18824](https://github.com/storybooks/storybook/pull/18824)\n- Examples: Set `resolve.symlinks` based on node option [#18827](https://github.com/storybooks/storybook/pull/18827)\n- Examples: Add command to publish repros + GH action [#18800](https://github.com/storybooks/storybook/pull/18800)\n- Examples: Create a new `yarn example` command [#18781](https://github.com/storybooks/storybook/pull/18781)\n- Build: Fix yarn build command [#18817](https://github.com/storybooks/storybook/pull/18817)\n- Build: Use tsup to build core-event [#18798](https://github.com/storybooks/storybook/pull/18798)\n\n## 7.0.0-alpha.17 (July 27, 2022)\n\n#### Features\n\n- Addon-docs: Support DocsPage in v6 store [#18763](https://github.com/storybooks/storybook/pull/18763)\n\n#### Bug Fixes\n\n- Preact: Typescript pragma fix [#15564](https://github.com/storybooks/storybook/pull/15564)\n- Core: Clear addon cache directory before starting the manager [#18731](https://github.com/storybooks/storybook/pull/18731)\n- UI: Pass full docs options to manager [#18762](https://github.com/storybooks/storybook/pull/18762)\n- Preview: Fix standalone MDX files not HMR-ing [#18747](https://github.com/storybooks/storybook/pull/18747)\n\n#### Maintenance\n\n- CLI: Add next-repro command [#18787](https://github.com/storybooks/storybook/pull/18787)\n- Build: Remove old scripts that are no longer used [#18790](https://github.com/storybooks/storybook/pull/18790)\n- Build: Addon-backgrounds with ts-up [#18784](https://github.com/storybooks/storybook/pull/18784)\n- Build: Addon-controls with tsup [#18786](https://github.com/storybooks/storybook/pull/18786)\n- Build: Use updated circleci node images [#18785](https://github.com/storybooks/storybook/pull/18785)\n- Build: Move all code into a `code` directory [#18759](https://github.com/storybooks/storybook/pull/18759)\n- Build: Lint css, html, json, md, mdx, yml files [#18735](https://github.com/storybooks/storybook/pull/18735)\n\n## 7.0.0-alpha.16 (July 25, 2022)\n\n#### Bug Fixes\n\n- Addon docs: Pass remarks plugins to mdx loader [#18740](https://github.com/storybooks/storybook/pull/18740)\n- Preview: Ensure docs container re-renders when globals change [#18711](https://github.com/storybooks/storybook/pull/18711)\n- Core: Set other manager-side constants in build [#18728](https://github.com/storybooks/storybook/pull/18728)\n- CLI: Fix detection of type: module when initializing storybook [#18714](https://github.com/storybooks/storybook/pull/18714)\n- UI: Include full URL in the \"Copy Canvas Link\" button [#17498](https://github.com/storybooks/storybook/pull/17498)\n- Toolbars: Fallback to name if title and icon are unspecified [#17430](https://github.com/storybooks/storybook/pull/17430)\n- CLI: Fix addons register in RN template [#18693](https://github.com/storybooks/storybook/pull/18693)\n- Index: Support `{ csfData as default }` CSF exports [#18588](https://github.com/storybooks/storybook/pull/18588)\n- Svelte: Always create main with cjs extension [#18648](https://github.com/storybooks/storybook/pull/18648)\n\n#### Maintenance\n\n- Build addons/a11y with ts-up [#18772](https://github.com/storybooks/storybook/pull/18772)\n- Typescript: Drop Emotion 10 types in lib/theming [#18598](https://github.com/storybooks/storybook/pull/18598)\n- Tests: Don't run the docs e2e in `react@18` [#18736](https://github.com/storybooks/storybook/pull/18736)\n- Addon-docs: Localize channel to docs context [#18730](https://github.com/storybooks/storybook/pull/18730)\n- Addon-docs: Move DocsRenderer back to addon-docs [#18708](https://github.com/storybooks/storybook/pull/18708)\n- Addon-docs: Remove `AddContext` from mdx packages [#18709](https://github.com/storybooks/storybook/pull/18709)\n- Preview: Simplify docsMode [#18729](https://github.com/storybooks/storybook/pull/18729)\n- Examples: Upgrade @storybook/jest in examples [#18582](https://github.com/storybooks/storybook/pull/18582)\n- Svelte: Make `svelte-loader` optional dependency [#18645](https://github.com/storybooks/storybook/pull/18645)\n- Build: Fix dts-localize script for windows [#18664](https://github.com/storybooks/storybook/pull/18664)\n\n#### Dependency Upgrades\n\n- Storyshots: Allow react-test-renderer 18 [#18296](https://github.com/storybooks/storybook/pull/18296)\n- Core: Remove unnecessary webpack dependency [#18651](https://github.com/storybooks/storybook/pull/18651)\n\n## 7.0.0-alpha.15 (July 25, 2022)\n\nFailed publish\n\n## 7.0.0-alpha.14 (July 25, 2022)\n\nFailed publish\n\n## 7.0.0-alpha.13 (July 11, 2022)\n\n### Features\n\n- UI: Remove docs tab ([#18677](https://github.com/storybookjs/storybook/pull/18677))\n\n### Bug Fixes\n\n- Index: Don't prepend `titlePrefix` to a docs entry that references a CSF file's title ([#18634](https://github.com/storybookjs/storybook/pull/18634))\n\n### Maintenance\n\n- Addon-dcos: Refactor DocsRender/Context ([#18635](https://github.com/storybookjs/storybook/pull/18635))\n- Instrumenter: `SyncPayload` type for `sync` event ([#18674](https://github.com/storybookjs/storybook/pull/18674))\n\n## 7.0.0-alpha.12 (July 7, 2022)\n\n### Features\n\n- Addon-docs: Produce docs page entries in the index ([#18574](https://github.com/storybookjs/storybook/pull/18574))\n- Svelte: Supports action auto configuration ([#18174](https://github.com/storybookjs/storybook/pull/18174))\n- Addon-docs: Add docs index configuration via main.js ([#18573](https://github.com/storybookjs/storybook/pull/18573))\n- Preview: Handle new docs-page index entries ([#18595](https://github.com/storybookjs/storybook/pull/18595))\n\n### Bug Fixes\n\n- CLI: Remove addon-actions install from `sb init` ([#18255](https://github.com/storybookjs/storybook/pull/18255))\n- Angular: Fix compodoc with spaces in workspace root ([#18140](https://github.com/storybookjs/storybook/pull/18140))\n- Core: Add type guard for globalWindow ([#18251](https://github.com/storybookjs/storybook/pull/18251))\n- Core: Fix builder stats typings to be optional ([#18377](https://github.com/storybookjs/storybook/pull/18377))\n\n### Maintenance\n\n- Core: Async load presets, replace interpret with esbuild-register ([#18619](https://github.com/storybookjs/storybook/pull/18619))\n- Build: Improve linting a bit ([#18642](https://github.com/storybookjs/storybook/pull/18642))\n\n### Dependency Upgrades\n\n- Deps: Use `dequal` for equality checks ([#18608](https://github.com/storybookjs/storybook/pull/18608))\n\n## 7.0.0-alpha.11 (July 6, 2022)\n\n### Features\n\n- Interactions: Show exceptions by non-instrumented code in panel ([#16592](https://github.com/storybookjs/storybook/pull/16592))\n\n### Maintenance\n\n- Build: Add linter for ejs ([#18637](https://github.com/storybookjs/storybook/pull/18637))\n- Core: Improve interopRequireDefault ([#18638](https://github.com/storybookjs/storybook/pull/18638))\n- Core: Pre-built manager using esbuild ([#18550](https://github.com/storybookjs/storybook/pull/18550))\n- Build: Add check-packages script plus misc improvements ([#18633](https://github.com/storybookjs/storybook/pull/18633))\n- Core: Typing useArgs ([#17735](https://github.com/storybookjs/storybook/pull/17735))\n- Build: Add a check script to each package ([#18603](https://github.com/storybookjs/storybook/pull/18603))\n- Build: Use playwright in benchmark ([#18606](https://github.com/storybookjs/storybook/pull/18606))\n\n## 7.0.0-alpha.10 (July 2, 2022)\n\n### Features\n\n- Addon-docs: Include Vue methods in ArgsTable ([#18609](https://github.com/storybookjs/storybook/pull/18609))\n- UI: Fix default theme according to preferred color scheme ([#17311](https://github.com/storybookjs/storybook/pull/17311))\n- Storyshots: Add SnapshotsWithOptionsArgType ([#15712](https://github.com/storybookjs/storybook/pull/15712))\n- Controls: Add max length config to text control ([#14396](https://github.com/storybookjs/storybook/pull/14396))\n\n### Bug Fixes\n\n- CLI/HTML: Improve HTML typescript stories ([#18618](https://github.com/storybookjs/storybook/pull/18618))\n- Controls: Throttle color controls and make `updateArgs` and `resetArgs` stable ([#18335](https://github.com/storybookjs/storybook/pull/18335))\n- Controls: Silence unexpected control type enum for color matchers ([#16334](https://github.com/storybookjs/storybook/pull/16334))\n- UI: Stop add-on Draggable from overlapping the vertical scrollbar when stories overflow ([#17663](https://github.com/storybookjs/storybook/pull/17663))\n- React: Fix source snippet decorator for story functions with suspense ([#17915](https://github.com/storybookjs/storybook/pull/17915))\n- Core: Avoid logging an object on compilation errors ([#15885](https://github.com/storybookjs/storybook/pull/15885))\n- UI: Fix router handling of URLs containing \"settings\" ([#16245](https://github.com/storybookjs/storybook/pull/16245))\n- UI: Fix viewMode handling on navigation ([#16912](https://github.com/storybookjs/storybook/pull/16912))\n- UI: Fix loading title ([#17935](https://github.com/storybookjs/storybook/pull/17935))\n\n### Maintenance\n\n- Examples/Vue: Fix missing a vue-template-compiler dependency ([#17485](https://github.com/storybookjs/storybook/pull/17485))\n- Fix homepage core-server ([#18121](https://github.com/storybookjs/storybook/pull/18121))\n- UI: Replace references to `themes.normal` with `themes.light` ([#17034](https://github.com/storybookjs/storybook/pull/17034))\n\n### Dependency Upgrades\n\n- Upgrade file-system-cache to 2.0.0 and remove custom types ([#18253](https://github.com/storybookjs/storybook/pull/18253))\n- Security: Update x-default-browser and fix issue with package. ([#18277](https://github.com/storybookjs/storybook/pull/18277))\n- Update puppeteer dependencies version ([#15163](https://github.com/storybookjs/storybook/pull/15163))\n- Upgrade react-syntax-highlighter to v15.5.0 ([#18009](https://github.com/storybookjs/storybook/pull/18009))\n\n## 7.0.0-alpha.9 (July 2, 2022)\n\nFailed publish\n\n## 7.0.0-alpha.8 (June 29, 2022)\n\n### Features\n\n- Webpack: Support .cjs extension ([#18502](https://github.com/storybookjs/storybook/pull/18502))\n\n### Maintenance\n\n- Docs2: Extract doc blocks into a separate package ([#18587](https://github.com/storybookjs/storybook/pull/18587))\n\n## 7.0.0-alpha.7 (June 29, 2022)\n\n### Features\n\n- TypeScript: Re-structure types for frameworks and presets ([#18504](https://github.com/storybookjs/storybook/pull/18504))\n- UI: Add parent wildcard sortOrder ([#18243](https://github.com/storybookjs/storybook/pull/18243))\n\n### Bug Fixes\n\n- UI: Fix typo in CSS pseudo selector ([#17708](https://github.com/storybookjs/storybook/pull/17708))\n- UI: Fix sidebar a11y by moving aria-expanded attribute to button ([#18354](https://github.com/storybookjs/storybook/pull/18354))\n- CLI: Hook up the npm7 migration ([#18522](https://github.com/storybookjs/storybook/pull/18522))\n\n### Maintenance\n\n- Build: Use TSUP to compile `core-common` ([#18546](https://github.com/storybookjs/storybook/pull/18546))\n- Build: Use TSUP to compile the presets ([#18544](https://github.com/storybookjs/storybook/pull/18544))\n- Build: Use TSUP to compile the frameworks ([#18543](https://github.com/storybookjs/storybook/pull/18543))\n- Build: Use TSUP to compile the renderers ([#18534](https://github.com/storybookjs/storybook/pull/18534))\n- Essentials: Add highlight addon ([#17800](https://github.com/storybookjs/storybook/pull/17800))\n- Core: Replace `cpy` with `fs-extra` copy/copyFile ([#18497](https://github.com/storybookjs/storybook/pull/18497))\n- Build: Enable Template.bind({}) TS support in our repo ([#18540](https://github.com/storybookjs/storybook/pull/18540))\n- Turn on strict types in store + preview-web ([#18536](https://github.com/storybookjs/storybook/pull/18536))\n- Addon-highlight: Convert to simplified addon style ([#17991](https://github.com/storybookjs/storybook/pull/17991))\n\n### Dependency Upgrades\n\n- Upgrade @storybook/testing-library to `0.0.14-next.0` ([#18539](https://github.com/storybookjs/storybook/pull/18539))\n\n## 7.0.0-alpha.6 (June 21, 2022)\n\n### Bug Fixes\n\n- Interactions: Reset instrumenter state on HMR ([#18516](https://github.com/storybookjs/storybook/pull/18516))\n- Interactions: Prevent showing child exception while parent is still playing ([#18518](https://github.com/storybookjs/storybook/pull/18518))\n\n### Maintenance\n\n- Docs2 core: Fetch `index.json` for composition ([#18521](https://github.com/storybookjs/storybook/pull/18521))\n- Addon-docs: Switch Meta block to receive all module exports ([#18514](https://github.com/storybookjs/storybook/pull/18514))\n- Re-add deprecated fields to lib/api ([#18488](https://github.com/storybookjs/storybook/pull/18488))\n- Core: Handle v3 index in composition ([#18498](https://github.com/storybookjs/storybook/pull/18498))\n- Story index: Ensure that `extract` script works and SBs can be composed into v6 storybooks ([#18409](https://github.com/storybookjs/storybook/pull/18409))\n- Docs2: Handle new docs entries in the preview ([#18099](https://github.com/storybookjs/storybook/pull/18099))\n- Docs2: Refactor manager to use new index data ([#18023](https://github.com/storybookjs/storybook/pull/18023))\n\n## 7.0.0-alpha.5 (June 20, 2022)\n\n### Bug Fixes\n\n- Core: Allow a teardown function to be returned from `renderToDOM` ([#18457](https://github.com/storybookjs/storybook/pull/18457))\n- CLI: Add npm7 migration for legacy peer deps ([#18510](https://github.com/storybookjs/storybook/pull/18510))\n- Interactions: Fix broken UI on nested interactions ([#18499](https://github.com/storybookjs/storybook/pull/18499))\n\n### Maintenance\n\n- Build: Upgrade yarn to 3.2.1 ([#18511](https://github.com/storybookjs/storybook/pull/18511))\n\n## 7.0.0-alpha.4 (June 19, 2022)\n\n### Breaking Changes\n\n- Core: Remove standalone node APIs ([#18089](https://github.com/storybookjs/storybook/pull/18089))\n\n### Maintenance\n\n- Build: Add logFilters to yarn config ([#18500](https://github.com/storybookjs/storybook/pull/18500))\n- Build: Set typescript strict-mode ([#18493](https://github.com/storybookjs/storybook/pull/18493))\n\n## 7.0.0-alpha.3 (June 17, 2022)\n\n### Features\n\n- Interactions: Collapse child interactions ([#18484](https://github.com/storybookjs/storybook/pull/18484))\n\n### Bug Fixes\n\n- Interactions: Fix `waitFor` behavior while debugging ([#18460](https://github.com/storybookjs/storybook/pull/18460))\n- UI: Fix display skip to sidebar button ([#18479](https://github.com/storybookjs/storybook/pull/18479))\n\n### Maintenance\n\n- CLI: Use `storybook` instead of `sb` ([#18430](https://github.com/storybookjs/storybook/pull/18430))\n- Components: Re-bundle the syntax highlighter ([#18425](https://github.com/storybookjs/storybook/pull/18425))\n\n## 7.0.0-alpha.2 (June 15, 2022)\n\n### Features\n\n- UI: Update manager to respect `parameters.docsOnly` in `stories.json` ([#18433](https://github.com/storybookjs/storybook/pull/18433))\n- CLI: Add additional files api to sb repro ([#18389](https://github.com/storybookjs/storybook/pull/18389))\n\n### Bug Fixes\n\n- Core: Fix process is not defined when using components ([#18469](https://github.com/storybookjs/storybook/pull/18469))\n- Story index: Warn on `storyName` in CSF3 exports ([#18464](https://github.com/storybookjs/storybook/pull/18464))\n- Telemetry: Strip out preset from addon name ([#18442](https://github.com/storybookjs/storybook/pull/18442))\n\n### Maintenance\n\n- CLI: Improve to be more async & cleanup ([#18475](https://github.com/storybookjs/storybook/pull/18475))\n- 7.0.0 pnp support ([#18461](https://github.com/storybookjs/storybook/pull/18461))\n- Build: Use playright version of sb-bench ([#18458](https://github.com/storybookjs/storybook/pull/18458))\n- Angular: Support Angular 14 standalone components ([#18272](https://github.com/storybookjs/storybook/pull/18272))\n- Build: Fix prebundle script on Windows ([#18365](https://github.com/storybookjs/storybook/pull/18365))\n- Scripts: Clean verdaccio cache when running locally ([#18359](https://github.com/storybookjs/storybook/pull/18359))\n- Core: fix PnP compatibility for @storybook/ui and @storybook/router packages ([#18412](https://github.com/storybookjs/storybook/pull/18412))\n\n## 7.0.0-alpha.1 (June 7, 2022)\n\n### Bug Fixes\n\n- CLI: Fix `init` to install correct version of sb/storybook ([#18417](https://github.com/storybookjs/storybook/pull/18417))\n\n## 7.0.0-alpha.0 (June 7, 2022)\n\n### Breaking Changes\n\n- Build chain upgrades: TS4, Webpack5, modern ESM, TSUP ([#18205](https://github.com/storybookjs/storybook/pull/18205))\n- Create frameworks & rename renderers ([#18201](https://github.com/storybookjs/storybook/pull/18201))\n- Core-webpack: Factor out webpack dependencies ([#18114](https://github.com/storybookjs/storybook/pull/18114))\n- Core: Remove start-/build-storybook from all frameworks ([#17899](https://github.com/storybookjs/storybook/pull/17899))\n\n### Features\n\n- Core: Add pluggable indexers ([#18355](https://github.com/storybookjs/storybook/pull/18355))\n- CLI: Add dev/build commands ([#17898](https://github.com/storybookjs/storybook/pull/17898))\n- CLI: Add support for angular/cli v14 ([#18334](https://github.com/storybookjs/storybook/pull/18334))\n\n### Bug Fixes\n\n- Vue/Vue3: Fix decorators in StoryStoreV7 ([#18375](https://github.com/storybookjs/storybook/pull/18375))\n- Preview: Default select to `viewMode` story ([#18370](https://github.com/storybookjs/storybook/pull/18370))\n\n### Maintenance\n\n- Core: Split webpack presets out of frameworks ([#18018](https://github.com/storybookjs/storybook/pull/18018))\n- Core: Renderer refactor ([#17982](https://github.com/storybookjs/storybook/pull/17982))\n- Core: Allow builders to be set in presets ([#18182](https://github.com/storybookjs/storybook/pull/18182))\n- Core: Minimize webpack deps ([#18024](https://github.com/storybookjs/storybook/pull/18024))\n- Core: Make renderers presets ([#18004](https://github.com/storybookjs/storybook/pull/18004))\n- Examples: Simplify sb usage in package.json scripts ([#18065](https://github.com/storybookjs/storybook/pull/18065))\n\n# Older versions\n\nFor older versions of the changelog, see [CHANGELOG.v6.md](./CHANGELOG.v6.md), [CHANGELOG.v1-5.md](./CHANGELOG.v1-5.md)\n"
  },
  {
    "path": "CHANGELOG.prerelease.md",
    "content": "## 10.4.0-alpha.6\n\n- Builder-Vite: Add onModuleGraphChange method - [#34323](https://github.com/storybookjs/storybook/pull/34323), thanks @ghengeveld!\n- CLI: Add automigrate check for 'storybook' package name conflict - [#34290](https://github.com/storybookjs/storybook/pull/34290), thanks @whdjh!\n- CLI: Prompt for init crash reports - [#34316](https://github.com/storybookjs/storybook/pull/34316), thanks @JReinhold!\n- CSF4: Fix duplicate preview loading issue in Vitest - [#34361](https://github.com/storybookjs/storybook/pull/34361), thanks @valentinpalkovic!\n- Maintenance: Add assertions outside step incorrectly nested in interactions panel - [#34296](https://github.com/storybookjs/storybook/pull/34296), thanks @majiayu000!\n- Maintenance: Extract getBuilderOptions helper across framewo… - [#34260](https://github.com/storybookjs/storybook/pull/34260), thanks @alex-js-ltd!\n- Maintenance: Use errorToErrorLike in boot-test-runner for consistent stack deduplication - [#34385](https://github.com/storybookjs/storybook/pull/34385), thanks @mixelburg!\n- Onboarding: Fix checklist MDX instructions - [#33193](https://github.com/storybookjs/storybook/pull/33193), thanks @kylegach!\n- React-Docgen: Add tsconfig fallback chain and warning for monorepos - [#34353](https://github.com/storybookjs/storybook/pull/34353), thanks @viditkbhatnagar!\n- React-Docgen: Try .tsx fallback when resolving .js ESM imports in docgen resolvers - [#34393](https://github.com/storybookjs/storybook/pull/34393), thanks @mixelburg!\n- UI: Fix mobile navigation when renderLabel returns a React node - [#34262](https://github.com/storybookjs/storybook/pull/34262), thanks @Nathan54Villaume!\n- Vite: Use vite hook filter for performance improvements - [#34022](https://github.com/storybookjs/storybook/pull/34022), thanks @huang-julien!\n\n## 10.4.0-alpha.5\n\n- Addon-a11y: Clear status transition timer on unmount to prevent test flake - [#34203](https://github.com/storybookjs/storybook/pull/34203), thanks @mixelburg!\n- Builder-Vite: Use djb2 hash to prevent variable name collisions in builder-vite - [#34274](https://github.com/storybookjs/storybook/pull/34274), thanks @chida09!\n- CLI: Fix Next.js Vite automigration corrupting configs already using `@storybook/nextjs-vite` - [#34249](https://github.com/storybookjs/storybook/pull/34249), thanks @nathanjessen!\n- Core: Add changeDetection feature flag - [#34314](https://github.com/storybookjs/storybook/pull/34314), thanks @valentinpalkovic!\n- Manager: URL-based tag filter state + filter-aware initial story selection - [#34283](https://github.com/storybookjs/storybook/pull/34283), thanks @valentinpalkovic!\n- React-Vite: Upgrade @joshwooding/vite-plugin-react-docgen-typescript to 0.7.0 - [#34335](https://github.com/storybookjs/storybook/pull/34335), thanks @beeswhacks!\n- Refactor: Extract shared `PseudoStateGrid` component in pseudo-states stories - [#34334](https://github.com/storybookjs/storybook/pull/34334), thanks @copilot-swe-agent!\n\n## 10.4.0-alpha.4\n\n- Addon-Docs: Add Reset story button to re-render stories in docs - [#34086](https://github.com/storybookjs/storybook/pull/34086), thanks @6810779s!\n- Code: Fix inline code blocks inside links removing link affordance - [#33903](https://github.com/storybookjs/storybook/pull/33903), thanks @yatishgoel!\n- Controls: Add maxPresetColors option to ColorControl - [#33998](https://github.com/storybookjs/storybook/pull/33998), thanks @mixelburg!\n- Core: Fix WebSocket connection for StackBlitz/WebContainers - [#34281](https://github.com/storybookjs/storybook/pull/34281), thanks @ghengeveld!\n- Dependencies: Update `vite-plugin-storybook-nextjs` to ^3.2.4 - [#34280](https://github.com/storybookjs/storybook/pull/34280), thanks @k35o!\n- React: Add component metadata extraction via Volar-style LanguageService - [#33914](https://github.com/storybookjs/storybook/pull/33914), thanks @kasperpeulen!\n- StatusValue: Add 'status-value:<new|modified|affected>' - [#34305](https://github.com/storybookjs/storybook/pull/34305), thanks @valentinpalkovic!\n- UI: Ensure Controls panel can scroll horizontally for now - [#34248](https://github.com/storybookjs/storybook/pull/34248), thanks @Sidnioulz!\n\n## 10.4.0-alpha.3\n\n- Addon-Vitest: Streamline vite(st) config detection across init and postinstall - [#34193](https://github.com/storybookjs/storybook/pull/34193), thanks @valentinpalkovic!\n- Angular: Use Story ID for renderer IDs (including standalone stories) - [#33982](https://github.com/storybookjs/storybook/pull/33982), thanks @ValentinFunk!\n- Bug: Skip re-processing already transformed config files for CSF factories - [#34273](https://github.com/storybookjs/storybook/pull/34273), thanks @huang-julien!\n- CLI: Shorten CTA link messages - [#34236](https://github.com/storybookjs/storybook/pull/34236), thanks @shilman!\n- React Native Web: Fix vite8 support by bumping vite-plugin-rnw - [#34231](https://github.com/storybookjs/storybook/pull/34231), thanks @dannyhw!\n\n## 10.4.0-alpha.2\n\n- CLI: Use npm info to fetch versions in repro command - [#34214](https://github.com/storybookjs/storybook/pull/34214), thanks @yannbf!\n- Core: Prevent story-local viewport from persisting in URL - [#34153](https://github.com/storybookjs/storybook/pull/34153), thanks @ghengeveld!\n- Maintenance: Remove dead-code copy of wrap-getAbsolutePath-utils - [#34168](https://github.com/storybookjs/storybook/pull/34168), thanks @mixelburg!\n- Security: Makes sure `serialize-javascript` is at latest version - [#34034](https://github.com/storybookjs/storybook/pull/34034), thanks @50bbx!\n\n## 10.4.0-alpha.1\n\n- Docs: Ensure unique control id attributes across multiple Controls blocks - [#34021](https://github.com/storybookjs/storybook/pull/34021), thanks @TheSeydiCharyyev!\n\n## 10.4.0-alpha.0\n\n\n## 10.3.0-beta.3\n\n- Addon-Vitest: Handle additional vitest config export patterns in postinstall - [#34106](https://github.com/storybookjs/storybook/pull/34106), thanks @copilot-swe-agent!\n- CLI: Add vike CLI metadata - [#34189](https://github.com/storybookjs/storybook/pull/34189), thanks @yannbf!\n- Maintenance: Revert pull request #33930 HMR events - [#34190](https://github.com/storybookjs/storybook/pull/34190), thanks @yannbf!\n- UI: Ensure Link without href is keyboard-reachable - [#34163](https://github.com/storybookjs/storybook/pull/34163), thanks @Sidnioulz!\n- UI: Zoom faster when pressing shift - [#34185](https://github.com/storybookjs/storybook/pull/34185), thanks @Sidnioulz!\n- Vite: Add mock entries to optimizeDeps.entries - [#34167](https://github.com/storybookjs/storybook/pull/34167), thanks @valentinpalkovic!\n\n## 10.3.0-beta.2\n\n- UI: Hide addon panel Drag on pages without a panel - [#34162](https://github.com/storybookjs/storybook/pull/34162), thanks @Sidnioulz!\n- UI: Hide manifest tag for now - [#34165](https://github.com/storybookjs/storybook/pull/34165), thanks @Sidnioulz!\n- UI: Make disabled Buttons keyboard-focusable - [#34166](https://github.com/storybookjs/storybook/pull/34166), thanks @Sidnioulz!\n- UI: Use correct selector for addon panel focus check - [#34164](https://github.com/storybookjs/storybook/pull/34164), thanks @Sidnioulz!\n- Vue: Make globals reactive in decorators - [#34116](https://github.com/storybookjs/storybook/pull/34116), thanks @Sidnioulz!\n\n## 10.3.0-beta.1\n\n- Addon-Docs: Add React as optimizeDeps entry - [#34176](https://github.com/storybookjs/storybook/pull/34176), thanks @valentinpalkovic!\n- CLI: Avoid hanging of postinstall during init - [#34175](https://github.com/storybookjs/storybook/pull/34175), thanks @valentinpalkovic!\n\n## 10.3.0-beta.0\n\n- Test: Fix clearing mocks in Vitest [#34078](https://github.com/storybookjs/storybook/pull/34078)\n- Core: Fix event source URL based on refId when multiple iframes share the same origin [#34105](https://github.com/storybookjs/storybook/pull/34105)\n- UI: Make TagsFilter state persistent [#33374](https://github.com/storybookjs/storybook/pull/33374)\n- A11y: Make resize handles for addon panel and sidebar accessible [#33980](https://github.com/storybookjs/storybook/pull/33980)\n- Maintenance: Use std-env for AI agent detection in telemetry [#34114](https://github.com/storybookjs/storybook/pull/34114)\n- Addon-Vitest: Make Playwright `--with-deps` platform-aware to avoid `sudo` prompt on Linux [#34121](https://github.com/storybookjs/storybook/pull/34121)\n- Addon-docs: Restore `docs.components` overrides for doc blocks [#34111](https://github.com/storybookjs/storybook/pull/34111)\n- Maintenance: Support vite-plugin-svelte7 which supports Vite 8 [#34115](https://github.com/storybookjs/storybook/pull/34115)\n- Core: Fix handling complex viewport sizes [#33615](https://github.com/storybookjs/storybook/pull/33615)\n- Core: Fix iframe reference for composed Storybook on a subpath [#34100](https://github.com/storybookjs/storybook/pull/34100)\n- Manifest: Rename `experimentalComponentsManifest` → `componentsManifest`, default to `true` [#33974](https://github.com/storybookjs/storybook/pull/33974)\n- Manifests: Fix Attached MDX causing wrong component entries [#34101](https://github.com/storybookjs/storybook/pull/34101)\n- Vue3-Vite: Allow paths in docgen tsconfig option [#32310](https://github.com/storybookjs/storybook/pull/32310), thanks @Thomaash!\n- Next.js: Move image configuration from FrameworkOptions to parameters [#32639](https://github.com/storybookjs/storybook/pull/32639), thanks @y-hsgw!\n- Docs: Make CSS ordering in DocsContainer more predictable [#34015](https://github.com/storybookjs/storybook/pull/34015)\n\n## 10.3.0-alpha.17\n\n- Core: Correctly fallback to first detected vitest config file - [#33865](https://github.com/storybookjs/storybook/pull/33865), thanks @yannbf!\n- ESLint-plugin: Disallow extra properties in eslint plugin rule options - [#32056](https://github.com/storybookjs/storybook/pull/32056), thanks @andreww2012!\n- ESLint: bail out config setup if eslint-plugin-storybook is already imported - [#34089](https://github.com/storybookjs/storybook/pull/34089), thanks @copilot-swe-agent!\n- Revert \"Toolbar: Remove extra toolbar divider when zoom controls not shown\" - [#34099](https://github.com/storybookjs/storybook/pull/34099), thanks @valentinpalkovic!\n\n## 10.3.0-alpha.16\n\n- A11y: Underline MDX links for WCAG SC 1.4.1 compliance - [#33139](https://github.com/storybookjs/storybook/pull/33139), thanks @NikhilChowdhury27!\n- Angular: Add moduleResolution: bundler to tsconfig - [#34085](https://github.com/storybookjs/storybook/pull/34085), thanks @valentinpalkovic!\n- Angular: only load webpack dependencies on demand - [#34043](https://github.com/storybookjs/storybook/pull/34043), thanks @sod!\n- CLI: Show multiple favicons warning as debug message - [#34069](https://github.com/storybookjs/storybook/pull/34069), thanks @remino!\n- Core: Fix error reporting in ManagerErrorBoundary - [#33915](https://github.com/storybookjs/storybook/pull/33915), thanks @ghengeveld!\n- Vite: Support Vite 8 - [#33788](https://github.com/storybookjs/storybook/pull/33788), thanks @valentinpalkovic!\n\n## 10.3.0-alpha.15\n\n- Actions: Add expandLevel parameter to configure tree depth - [#33977](https://github.com/storybookjs/storybook/pull/33977), thanks @mixelburg!\n- Actions: Fix HandlerFunction type to support async callback props - [#33864](https://github.com/storybookjs/storybook/pull/33864), thanks @mixelburg!\n- Addon-Vitest: Refactor Vitest setup to eliminate the need for a dedicated setup file - [#34025](https://github.com/storybookjs/storybook/pull/34025), thanks @valentinpalkovic!\n- Build: Update @types/node - [#34037](https://github.com/storybookjs/storybook/pull/34037), thanks @valentinpalkovic!\n- Builder-Vite: Fix cold-cache vitest failures for story paths containing glob special characters - [#34044](https://github.com/storybookjs/storybook/pull/34044), thanks @copilot-swe-agent!\n- CI:: declare explicit permissions for stale and weekly cron workflows - [#33902](https://github.com/storybookjs/storybook/pull/33902), thanks @Rohan5commit!\n- Core: Add vike metadata frameworks - [#33965](https://github.com/storybookjs/storybook/pull/33965), thanks @yannbf!\n- Core: Resolve builder preset path correctly in pnpm strict mode - [#34032](https://github.com/storybookjs/storybook/pull/34032), thanks @braedenfoster!\n- Core: Update default allowed hosts in host validation middleware - [#34045](https://github.com/storybookjs/storybook/pull/34045), thanks @ghengeveld!\n- Next.js: Add support for v16.2 - [#34046](https://github.com/storybookjs/storybook/pull/34046), thanks @valentinpalkovic!\n- UI: Fix code/copy buttons overlap with content - [#33889](https://github.com/storybookjs/storybook/pull/33889), thanks @Sidnioulz!\n- UI: Fix modal text selection - [#33967](https://github.com/storybookjs/storybook/pull/33967), thanks @Sidnioulz!\n- UI: Fix tab navigation after closing addon panel - [#33971](https://github.com/storybookjs/storybook/pull/33971), thanks @copilot-swe-agent!\n- UI: Handle kb nav edge cases when preview and panel are hidden - [#33588](https://github.com/storybookjs/storybook/pull/33588), thanks @Sidnioulz!\n\n## 10.3.0-alpha.14\n\n- CSF-Factories: Fix ConfigFile parser false warning on `definePreview({...}).type<T>()` export default - [#33885](https://github.com/storybookjs/storybook/pull/33885), thanks @copilot-swe-agent!\n- Core: Add host/origin validation to requests and websocket connections - [#33835](https://github.com/storybookjs/storybook/pull/33835), thanks @ghengeveld!\n- Core: Storybook failed to load iframe.html when publishing - [#33896](https://github.com/storybookjs/storybook/pull/33896), thanks @danielalanbates!\n- Core: Zoom tool refinements - Hide reset button when value is initial - [#33635](https://github.com/storybookjs/storybook/pull/33635), thanks @superLipbalm!\n- Docs: Edit JSON button is now accessible at 320x256 viewport (WCAG 2.1 Reflow test) - [#33707](https://github.com/storybookjs/storybook/pull/33707), thanks @TheSeydiCharyyev!\n- Manager-API: Update refs sequentially in experimental_setFilter - [#33958](https://github.com/storybookjs/storybook/pull/33958), thanks @ia319!\n- UI: Allow direct kb/mouse actions on zoom tool button - [#33496](https://github.com/storybookjs/storybook/pull/33496), thanks @Sidnioulz!\n\n## 10.3.0-alpha.13\n\n- A11y: Add ScrollArea prop focusable for when it has static children - [#33876](https://github.com/storybookjs/storybook/pull/33876), thanks @Sidnioulz!\n- CLI: Set STORYBOOK environment variable - [#33938](https://github.com/storybookjs/storybook/pull/33938), thanks @yannbf!\n- Controls: Fix Object contrast issue and tidy up code - [#33923](https://github.com/storybookjs/storybook/pull/33923), thanks @Sidnioulz!\n- HMR: Fix race conditions causing stale play functions to fire on re-rendered stories - [#33930](https://github.com/storybookjs/storybook/pull/33930), thanks @copilot-swe-agent!\n- React: Handle render identifier in manifest snippet generation - [#33940](https://github.com/storybookjs/storybook/pull/33940), thanks @kasperpeulen!\n- UI: Prevent crash when tag filters contain undefined entries - [#33931](https://github.com/storybookjs/storybook/pull/33931), thanks @abhaysinh1000!\n\n## 10.3.0-alpha.12\n\n- Builder-Vite: Prevent config duplication - [#33883](https://github.com/storybookjs/storybook/pull/33883), thanks @copilot-swe-agent!\n- CLI: Fix React native web A11y issues - [#33937](https://github.com/storybookjs/storybook/pull/33937), thanks @jonniebigodes!\n- Core: Ensure telemetry is never triggered on initial load of checklist data - [#33918](https://github.com/storybookjs/storybook/pull/33918), thanks @ghengeveld!\n- Eslint: Fix ESLint 10 compatibility in eslint-plugin-storybook rules - [#33884](https://github.com/storybookjs/storybook/pull/33884), thanks @copilot-swe-agent!\n- Test: Update @testing-library/jest-dom - [#33928](https://github.com/storybookjs/storybook/pull/33928), thanks @valentinpalkovic!\n\n## 10.3.0-alpha.11\n\n- Addon Pseudo-states: Process all nested css rules - [#33605](https://github.com/storybookjs/storybook/pull/33605), thanks @hpohlmeyer!\n- Core: Avoid hanging when inferring args for recursive calls on DOM elemens - [#33922](https://github.com/storybookjs/storybook/pull/33922), thanks @valentinpalkovic!\n- Core: Sanitize inputs for save from controls - [#33868](https://github.com/storybookjs/storybook/pull/33868), thanks @valentinpalkovic!\n- Telemetry: Add project age - [#33910](https://github.com/storybookjs/storybook/pull/33910), thanks @shilman!\n- Viewport: Prioritize story viewport globals and avoid user-global pollution - [#33849](https://github.com/storybookjs/storybook/pull/33849), thanks @ia319!\n\n## 10.3.0-alpha.10\n\n- Addon-Vitest: Fix postinstall a11y installation - [#33888](https://github.com/storybookjs/storybook/pull/33888), thanks @valentinpalkovic!\n- Builder-Vite: Use preview annotations as entry points for optimizeDeps - [#33875](https://github.com/storybookjs/storybook/pull/33875), thanks @copilot-swe-agent!\n- React Native Web: Fix inconsistent example stories - [#33891](https://github.com/storybookjs/storybook/pull/33891), thanks @danielalanbates!\n- Webpack: Improve performance of module-mocking plugins - [#33169](https://github.com/storybookjs/storybook/pull/33169), thanks @valentinpalkovic!\n\n## 10.3.0-alpha.9\n\n- React: Add react-docgen-typescript to component manifest - [#33818](https://github.com/storybookjs/storybook/pull/33818), thanks @kasperpeulen!\n\n## 10.3.0-alpha.8\n\n- A11y: Ensure popover dialogs have an ARIA label - [#33500](https://github.com/storybookjs/storybook/pull/33500), thanks @gayanMatch!\n- Addon-Vitest: Add channel API to programmatically trigger test runs - [#33206](https://github.com/storybookjs/storybook/pull/33206), thanks @JReinhold!\n- Builder-Vite: Centralize Vite plugins for builder-vite and addon-vitest - [#33819](https://github.com/storybookjs/storybook/pull/33819), thanks @valentinpalkovic!\n- Core: Revert Pull Request #33420 from Maelryn/fix/copy-button-overlap - [#33877](https://github.com/storybookjs/storybook/pull/33877), thanks @Sidnioulz!\n- Next.js-Vite: Fix failing postcss mutation - [#33879](https://github.com/storybookjs/storybook/pull/33879), thanks @valentinpalkovic!\n- React: Fix manifest stories empty when meta has no explicit title - [#33878](https://github.com/storybookjs/storybook/pull/33878), thanks @kasperpeulen!\n- UI: Fix Copy button overlapping code in portrait mode - [#33420](https://github.com/storybookjs/storybook/pull/33420), thanks @Maelryn!\n\n## 10.3.0-alpha.7\n\n- Core: Require token for websocket connections - [#33820](https://github.com/storybookjs/storybook/pull/33820), thanks @ghengeveld!\n- Next.js: Handle legacyBehavior prop in Link mock component - [#33862](https://github.com/storybookjs/storybook/pull/33862), thanks @yatishgoel!\n- Preact: Support inferring props from component types - [#33828](https://github.com/storybookjs/storybook/pull/33828), thanks @JoviDeCroock!\n\n## 10.3.0-alpha.6\n\n- Addon-Vitest: Improve config file detection in monorepos - [#33814](https://github.com/storybookjs/storybook/pull/33814), thanks @valentinpalkovic!\n- Addon-Vitest: Support Vitest canaries - [#33833](https://github.com/storybookjs/storybook/pull/33833), thanks @valentinpalkovic!\n- Builder-Vite: Update dependencies react-vite framework - [#33810](https://github.com/storybookjs/storybook/pull/33810), thanks @valentinpalkovic!\n- Next.js: Fix Link component override in appDirectory configuration - [#31251](https://github.com/storybookjs/storybook/pull/31251), thanks @yatishgoel!\n\n## 10.3.0-alpha.5\n\n- Builder-Vite: Use relative path for mocker entry in production builds - [#33792](https://github.com/storybookjs/storybook/pull/33792), thanks @DukeDeSouth!\n- CLI: Support addon-vitest setup when --skip-install is passed - [#33718](https://github.com/storybookjs/storybook/pull/33718), thanks @valentinpalkovic!\n- CSF: Fix cross-file story imports in csf-factories codemod - [#33723](https://github.com/storybookjs/storybook/pull/33723), thanks @yatishgoel!\n- Compile: reduce VCPUs for CI check task from 4 to 3 - [#33822](https://github.com/storybookjs/storybook/pull/33822), thanks @valentinpalkovic!\n- Core: Ignore empty files when indexing - [#33782](https://github.com/storybookjs/storybook/pull/33782), thanks @JReinhold!\n- Globals: Repair dynamicTitle: false for user-defined tools - [#33284](https://github.com/storybookjs/storybook/pull/33284), thanks @ia319!\n- Logger: Honor --loglevel for npmlog output - [#33776](https://github.com/storybookjs/storybook/pull/33776), thanks @LouisLau-art!\n- Telemetry: Add Expo metaframework - [#33783](https://github.com/storybookjs/storybook/pull/33783), thanks @copilot-swe-agent!\n- Telemetry: Add init exit event - [#33773](https://github.com/storybookjs/storybook/pull/33773), thanks @valentinpalkovic!\n- Telemetry: Add share events - [#33766](https://github.com/storybookjs/storybook/pull/33766), thanks @ndelangen!\n- Test: Update event creation logic in user-event package - [#33787](https://github.com/storybookjs/storybook/pull/33787), thanks @valentinpalkovic!\n- Viewport: Skip viewport validation before parameters load - [#33794](https://github.com/storybookjs/storybook/pull/33794), thanks @ia319!\n\n## 10.3.0-alpha.4\n\n- Addon-Vitest: Support vite/vitest config with deferred export - [#33755](https://github.com/storybookjs/storybook/pull/33755), thanks @valentinpalkovic!\n- Controls: Allow story argTypes to override control: false from meta - [#33729](https://github.com/storybookjs/storybook/pull/33729), thanks @jonathan-fulton!\n- Manager: Update logic to use base path instead of full pathname - [#33686](https://github.com/storybookjs/storybook/pull/33686), thanks @JSMike!\n- Manifests: Use correct story name - [#33709](https://github.com/storybookjs/storybook/pull/33709), thanks @JReinhold!\n- Toolbar: Remove extra toolbar divider when zoom controls not shown - [#33731](https://github.com/storybookjs/storybook/pull/33731), thanks @jonathan-fulton!\n\n## 10.3.0-alpha.3\n\n- Angular: Storybook fails with unknown option silent - [#33736](https://github.com/storybookjs/storybook/pull/33736), thanks @tanujbhaud!\n- Angular: fix --loglevel options in docs and descriptions - [#33726](https://github.com/storybookjs/storybook/pull/33726), thanks @theRuslan!\n- Builder-Vite: Add plugin to enforce Storybook's output directory in Vite build configuration - [#33740](https://github.com/storybookjs/storybook/pull/33740), thanks @valentinpalkovic!\n- Core: Fix typos: occured -> occurred, recieves -> receives - [#33727](https://github.com/storybookjs/storybook/pull/33727), thanks @jonathan-fulton!\n- Core: Handle BROWSER=none correctly and improve error messages - [#33730](https://github.com/storybookjs/storybook/pull/33730), thanks @jonathan-fulton!\n- Core: Invalidate cache on Storybook version upgrade - [#33717](https://github.com/storybookjs/storybook/pull/33717), thanks @copilot-swe-agent!\n- Core: Register CORS middleware before index.json route - [#33728](https://github.com/storybookjs/storybook/pull/33728), thanks @jonathan-fulton!\n- Manager: Remove deprecated `active` prop warning in ZoomButton - [#33697](https://github.com/storybookjs/storybook/pull/33697), thanks @yatishgoel!\n- Next.js: Alias AppRouterContext to shared runtime to fix Link navigation - [#33419](https://github.com/storybookjs/storybook/pull/33419), thanks @pallaprolus!\n- UI: Fix `z-index` problem with `popover`s and `modal`s nesting - [#33757](https://github.com/storybookjs/storybook/pull/33757), thanks @ndelangen!\n- Vue: Make globals reactive in decorators - [#33562](https://github.com/storybookjs/storybook/pull/33562), thanks @Sidnioulz!\n\n## 10.3.0-alpha.2\n\n- Addon Vitest: Support simple vite.config without defineConfig helper - [#33694](https://github.com/storybookjs/storybook/pull/33694), thanks @valentinpalkovic!\n- Addon-Docs: Add support for `sourceState: 'none'` to canvas block parameters - [#33627](https://github.com/storybookjs/storybook/pull/33627), thanks @quisido!\n- Addon-Vitest: Append Storybook project to existing test.projects array without double nesting - [#33708](https://github.com/storybookjs/storybook/pull/33708), thanks @valentinpalkovic!\n- Addon-Vitest: Normalize Windows paths in addon-vitest automigration - [#33340](https://github.com/storybookjs/storybook/pull/33340), thanks @tanujbhaud!\n- Addon-Vitest: Skip postinstall setup when configured - [#33712](https://github.com/storybookjs/storybook/pull/33712), thanks @valentinpalkovic!\n- Addon-Vitest: Update Vitest plugin configuration to disable requireAssertions for expect - [#33693](https://github.com/storybookjs/storybook/pull/33693), thanks @valentinpalkovic!\n- CSF-Factories: Fix codemod for preview files without exports - [#33673](https://github.com/storybookjs/storybook/pull/33673), thanks @kasperpeulen!\n- CSF: Fix false positive detection of Zod v4 .meta() as CSF Factory - [#33666](https://github.com/storybookjs/storybook/pull/33666), thanks @kasperpeulen!\n- CSFFactories: Add non-interactive mode and --glob flag - [#33648](https://github.com/storybookjs/storybook/pull/33648), thanks @kasperpeulen!\n- CSFFactories: Preserve leading comments when adding imports - [#33645](https://github.com/storybookjs/storybook/pull/33645), thanks @kasperpeulen!\n- Cli: Use npm for registry URL in PNPMProxy to avoid workspace errors - [#33571](https://github.com/storybookjs/storybook/pull/33571), thanks @ia319!\n- Codemod: Fix csf-2-to-3 failing due to quoted filenames - [#33646](https://github.com/storybookjs/storybook/pull/33646), thanks @kasperpeulen!\n- Codemod: Fix glob pattern handling on Windows - [#33714](https://github.com/storybookjs/storybook/pull/33714), thanks @kasperpeulen!\n- Composition: Handle 401 responses with loginUrl from Chromatic - [#33705](https://github.com/storybookjs/storybook/pull/33705), thanks @kasperpeulen!\n- Core: Fix false-positive CJS warning when 'exports' appears in strings or comments - [#33572](https://github.com/storybookjs/storybook/pull/33572), thanks @reeseo3o!\n- Telemetry: Add agent detection - [#33675](https://github.com/storybookjs/storybook/pull/33675), thanks @valentinpalkovic!\n\n## 10.3.0-alpha.1\n\n- Builder-Webpack5: Fix @vitest/mocker resolution issue - [#33315](https://github.com/storybookjs/storybook/pull/33315), thanks @valentinpalkovic!\n- CLI: Add init telemetry for CLI integrations - [#33603](https://github.com/storybookjs/storybook/pull/33603), thanks @shilman!\n- Core: Fix `previewHref` when current path does not end with a slash - [#33647](https://github.com/storybookjs/storybook/pull/33647), thanks @ghengeveld!\n- Core: Fix rendering of View Transitions in Firefox - [#33651](https://github.com/storybookjs/storybook/pull/33651), thanks @ghengeveld!\n- Manifest: Add docs entries to debugger - [#33607](https://github.com/storybookjs/storybook/pull/33607), thanks @JReinhold!\n- Theming: Export interface declaration for `ThemesGlobals` - [#33343](https://github.com/storybookjs/storybook/pull/33343), thanks @icopp!\n- UI: Avoid large animation for reduced motion users - [#33530](https://github.com/storybookjs/storybook/pull/33530), thanks @Sidnioulz!\n\n## 10.3.0-alpha.0\n\n- CLI: Fix onboarding not opening - [#33609](https://github.com/storybookjs/storybook/pull/33609), thanks @ndelangen!\n\n## 10.2.0-beta.5\n\n- Addon A11y: Lock vision filter dropdown for stories with `vision` global - [#33599](https://github.com/storybookjs/storybook/pull/33599), thanks @ghengeveld!\n\n## 10.2.0-beta.4\n\n- Addon Vitest: Improve error message in testing widget modal - [#33481](https://github.com/storybookjs/storybook/pull/33481), thanks @yannbf!\n- Codemod: Fix glob string to only match stories files - [#33592](https://github.com/storybookjs/storybook/pull/33592), thanks @JReinhold!\n- Core: Add support for wrapped components in component transformer - [#33578](https://github.com/storybookjs/storybook/pull/33578), thanks @yannbf!\n- Core: Fix Date input layout - [#33595](https://github.com/storybookjs/storybook/pull/33595), thanks @ghengeveld!\n- Core: Fix `react-docgen-typescript` support in story creation - [#33586](https://github.com/storybookjs/storybook/pull/33586), thanks @yannbf!\n- Core: Fix import statement for `react-docgen-typescript` - [#33589](https://github.com/storybookjs/storybook/pull/33589), thanks @yannbf!\n- Core: Fix input width - [#33591](https://github.com/storybookjs/storybook/pull/33591), thanks @ghengeveld!\n- Core: Fix manual zoom input field UX - [#33581](https://github.com/storybookjs/storybook/pull/33581), thanks @ghengeveld!\n- Core: Improve addon sanitization - [#33554](https://github.com/storybookjs/storybook/pull/33554), thanks @yannbf!\n- Docgen: Update extraction of React docgen - [#33598](https://github.com/storybookjs/storybook/pull/33598), thanks @ndelangen!\n- Guide: Hide TourGuide as soon as tests start - [#33587](https://github.com/storybookjs/storybook/pull/33587), thanks @ghengeveld!\n- TypeScript: Improve globalTypes type-strictness - [#33313](https://github.com/storybookjs/storybook/pull/33313), thanks @mrginglymus!\n- UI: Ensure preview error displays use a readable text color - [#33580](https://github.com/storybookjs/storybook/pull/33580), thanks @Sidnioulz!\n- UI: Fix border color for Select picker - [#33585](https://github.com/storybookjs/storybook/pull/33585), thanks @ghengeveld!\n- UI: Fix empty sidebar after navigating from search - [#33590](https://github.com/storybookjs/storybook/pull/33590), thanks @Sidnioulz!\n\n## 10.2.0-beta.3\n\n- Core: Support defineConfig when setting up ESLint plugin - [#32878](https://github.com/storybookjs/storybook/pull/32878), thanks @copilot-swe-agent!\n- Core: Viewport UX fixes - [#33557](https://github.com/storybookjs/storybook/pull/33557), thanks @ghengeveld!\n- NextJSVite: Add `@opentelemetry/api` to `optimizeDeps` - [#33577](https://github.com/storybookjs/storybook/pull/33577), thanks @ndelangen!\n- TypeScript: Reduce `cannot be named` errors - [#33344](https://github.com/storybookjs/storybook/pull/33344), thanks @icopp!\n\n## 10.2.0-beta.2\n\n- CSF-Factories: Skip non-factory exports instead of throwing error - [#33550](https://github.com/storybookjs/storybook/pull/33550), thanks @kasperpeulen!\n- Core: Add zoom level 8 and limit manual input to 800% - [#33561](https://github.com/storybookjs/storybook/pull/33561), thanks @ghengeveld!\n- Core: Fix Checklist behavior with hidden sidebar - [#33556](https://github.com/storybookjs/storybook/pull/33556), thanks @ghengeveld!\n- Core: Fix viewport args handling and reset option - [#33560](https://github.com/storybookjs/storybook/pull/33560), thanks @ghengeveld!\n- Dependencies: Update `baseline-browser-mapping` - [#33576](https://github.com/storybookjs/storybook/pull/33576), thanks @ndelangen!\n- Onboarding: Fix navigation to first story when configure-your-project entry missing - [#33559](https://github.com/storybookjs/storybook/pull/33559), thanks @copilot-swe-agent!\n- Zoom: Keyboardshortcut for the `plus` key - [#33565](https://github.com/storybookjs/storybook/pull/33565), thanks @ndelangen!\n\n## 10.2.0-beta.1\n\n- CSF-Factories: Allow kebab-case HTML attribute names in web components args - [#33526](https://github.com/storybookjs/storybook/pull/33526), thanks @kasperpeulen!\n- CSF-Factories: Export WebComponentsTypes and VueTypes - [#33521](https://github.com/storybookjs/storybook/pull/33521), thanks @kasperpeulen!\n\n## 10.2.0-beta.0\n\n- Manager: Fix system query parameters being overridable - [#33535](https://github.com/storybookjs/storybook/pull/33535), thanks @JReinhold!\n- NextJSVite: Upgrade plugin - [#33538](https://github.com/storybookjs/storybook/pull/33538), thanks @ndelangen!\n\n## 10.2.0-alpha.18\n\n- Build: Fix `ejslint` execution path in lint-staged - [#33504](https://github.com/storybookjs/storybook/pull/33504), thanks @Yeonny0723!\n- CLI: Detect free port when running dev during initiate - [#33532](https://github.com/storybookjs/storybook/pull/33532), thanks @ndelangen!\n- Core: Improve path handling in arg types data extraction - [#33536](https://github.com/storybookjs/storybook/pull/33536), thanks @yannbf!\n- Core: Refactor channel initialization - [#33520](https://github.com/storybookjs/storybook/pull/33520), thanks @yannbf!\n- Telemetry: Add `packageJson.type` - [#33525](https://github.com/storybookjs/storybook/pull/33525), thanks @ndelangen!\n- UI: Improve landmark navigation - [#33457](https://github.com/storybookjs/storybook/pull/33457), thanks @Sidnioulz!\n\n## 10.2.0-alpha.17\n\n- Core: Improve the story generation experience - [#33259](https://github.com/storybookjs/storybook/pull/33259), thanks @yannbf!\n\n## 10.2.0-alpha.16\n\n- Addon Pseudo States: Fix stylesheet rewrite for `:not()` with parenthesis in inner selector - [#33491](https://github.com/storybookjs/storybook/pull/33491), thanks @ghengeveld!\n- CSF: Add CSF Factories for Vue3, Web Components, and Angular - [#33365](https://github.com/storybookjs/storybook/pull/33365), thanks @kasperpeulen!\n\n## 10.2.0-alpha.15\n\n- Core: Add global error boundary for Manager UI - [#33211](https://github.com/storybookjs/storybook/pull/33211), thanks @copilot-swe-agent!\n- Core: Fix play function `mount` detection when destructuring in the function body - [#33367](https://github.com/storybookjs/storybook/pull/33367), thanks @ghengeveld!\n- Core: Honor BROWSER shell scripts before xdg-open - [#33292](https://github.com/storybookjs/storybook/pull/33292), thanks @robbchar!\n- Core: Redesign and refactor Viewports tool - [#33290](https://github.com/storybookjs/storybook/pull/33290), thanks @ghengeveld!\n- Core: Render sidebar toggle on settings pages - [#33501](https://github.com/storybookjs/storybook/pull/33501), thanks @ghengeveld!\n- Core: Support disabling Checklist widget through feature config - [#33430](https://github.com/storybookjs/storybook/pull/33430), thanks @ghengeveld!\n- Core: Use canonical links in sidebar and menu - [#33400](https://github.com/storybookjs/storybook/pull/33400), thanks @Sidnioulz!\n- Core: Zoom tool reimplementation - [#33375](https://github.com/storybookjs/storybook/pull/33375), thanks @ghengeveld!\n- Manifests: Add support for summaries in MDX files - [#33475](https://github.com/storybookjs/storybook/pull/33475), thanks @JReinhold!\n- Revert \"ReactDocgen: Try using the latest version of the original\" - [#33499](https://github.com/storybookjs/storybook/pull/33499), thanks @ndelangen!\n- TypeScript: Support `exactOptionalPropertyTypes` for public API types - [#33149](https://github.com/storybookjs/storybook/pull/33149), thanks @copilot-swe-agent!\n- UI: Fix regression in select close handler focus - [#33470](https://github.com/storybookjs/storybook/pull/33470), thanks @Sidnioulz!\n- UI: Fix search highlight visibility in High Contrast Mode - [#33427](https://github.com/storybookjs/storybook/pull/33427), thanks @Maelryn!\n- Webpack: Revert \"disable `bugfixes` property in swc and babel - [#33498](https://github.com/storybookjs/storybook/pull/33498), thanks @ndelangen!\n\n## 10.2.0-alpha.14\n\n- ReactDocgen: Swap `@storybook/react-docgen-typescript-plugin` to `react-docgen-typescript-plugin` - [#33454](https://github.com/storybookjs/storybook/pull/33454), thanks @ndelangen!\n\n## 10.2.0-alpha.13\n\n- Core: Fix onboarding visual bugs, survey telemetry and modal dismissal - [#33326](https://github.com/storybookjs/storybook/pull/33326), thanks @ghengeveld!\n- Core: Track vision simulator state through globals and apply styles in preview - [#33418](https://github.com/storybookjs/storybook/pull/33418), thanks @ghengeveld!\n\n## 10.2.0-alpha.12\n\n- Addon-docs: Add MDX manifest generation - [#33408](https://github.com/storybookjs/storybook/pull/33408), thanks @copilot-swe-agent!\n- AddonVitest: Improve perf & fix loading incorrect `.env` file - [#33469](https://github.com/storybookjs/storybook/pull/33469), thanks @ndelangen!\n- Core: Add `getStoryHrefs` manager API and add hotkey for \"open in isolation\" - [#33416](https://github.com/storybookjs/storybook/pull/33416), thanks @ghengeveld!\n\n## 10.2.0-alpha.11\n\n- Core: Add try-catch for cross-origin access in Storybook hooks - [#33448](https://github.com/storybookjs/storybook/pull/33448), thanks @ndelangen!\n- UI: Keep preview frame stable in overall layout - [#33447](https://github.com/storybookjs/storybook/pull/33447), thanks @Sidnioulz!\n\n## 10.2.0-alpha.10\n\n- Dependencies: Bump various packages - [#33412](https://github.com/storybookjs/storybook/pull/33412), thanks @ndelangen!\n- Interactions: Add disable parameter for interactions panel - [#33368](https://github.com/storybookjs/storybook/pull/33368), thanks @jeevikar14!\n- Interactions: Fix state reset bug when switching stories with date mocks - [#33388](https://github.com/storybookjs/storybook/pull/33388), thanks @Sidnioulz!\n- Manifests: Refactor from `componentManifestGenerator` to extensible `manifests` preset property - [#33392](https://github.com/storybookjs/storybook/pull/33392), thanks @JReinhold!\n- Manifests: Support `!manifest` tag in preview files - [#33406](https://github.com/storybookjs/storybook/pull/33406), thanks @JReinhold!\n- NextJS: Import `next/dist` with `.js`-extension for ESM compat - [#33380](https://github.com/storybookjs/storybook/pull/33380), thanks @yue4u!\n- Preview: Treat canceled animations as finished - [#32401](https://github.com/storybookjs/storybook/pull/32401), thanks @bawjensen!\n- UI: Ensure consistent right padding in TreeNode - [#33322](https://github.com/storybookjs/storybook/pull/33322), thanks @Sidnioulz!\n- UI: Fix React error 300 on some addons - [#33381](https://github.com/storybookjs/storybook/pull/33381), thanks @Sidnioulz!\n- UI: Prevent primary story from duplicating anchor ID - [#33384](https://github.com/storybookjs/storybook/pull/33384), thanks @Sidnioulz!\n- Upgrade: Preserve package.json indentation when upgrading - [#32280](https://github.com/storybookjs/storybook/pull/32280), thanks @y-hsgw!\n- Vitest: Fallback detecting vitest version in postinstall - [#33415](https://github.com/storybookjs/storybook/pull/33415), thanks @ndelangen!\n\n## 10.2.0-alpha.9\n\n- Core and Vite: Use story index as source of truth for Vite paths - [#30612](https://github.com/storybookjs/storybook/pull/30612), thanks @JReinhold!\n\n## 10.2.0-alpha.8\n\n- React: Fix several CSF factory bugs - [#33354](https://github.com/storybookjs/storybook/pull/33354), thanks @kasperpeulen!\n\n## 10.2.0-alpha.7\n\n- Automigrate: Fix missing await - [#33333](https://github.com/storybookjs/storybook/pull/33333), thanks @valentinpalkovic!\n- CLI: Remove REACT_PROJECT projectType - [#33334](https://github.com/storybookjs/storybook/pull/33334), thanks @valentinpalkovic!\n- Core: Exclude open from pre-bundling to make local xdg-open reachable - [#33325](https://github.com/storybookjs/storybook/pull/33325), thanks @Sidnioulz!\n- Core: Fix `.env`-file parsing - [#33383](https://github.com/storybookjs/storybook/pull/33383), thanks @JReinhold!\n- Next.js: Handle v14 compatibility for draftMode import - [#33341](https://github.com/storybookjs/storybook/pull/33341), thanks @tanujbhaud!\n- Nextjs-Vite: Update vite-plugin-storybook-nextjs to v3.1.7 - [#33351](https://github.com/storybookjs/storybook/pull/33351), thanks @valentinpalkovic!\n- React-Vite: Update @joshwooding/vite-plugin-react-docgen-typescript - [#33349](https://github.com/storybookjs/storybook/pull/33349), thanks @valentinpalkovic!\n- React: Use self-closing tag for code snippets - [#33342](https://github.com/storybookjs/storybook/pull/33342), thanks @valentinpalkovic!\n- Sidebar: Prevent updating non-existent stories - [#33037](https://github.com/storybookjs/storybook/pull/33037), thanks @ia319!\n- Telemetry: Fix race condition in telemetry cache causing malformed JSON - [#33323](https://github.com/storybookjs/storybook/pull/33323), thanks @valentinpalkovic!\n- Telemetry: Remove instance of check for sub-error handling - [#33356](https://github.com/storybookjs/storybook/pull/33356), thanks @valentinpalkovic!\n\n## 10.2.0-alpha.6\n\n- Controls: Fix displaying as object instead of select for optional union types - [#33200](https://github.com/storybookjs/storybook/pull/33200), thanks @tanujbhaud!\n- Controls: Force object control JSON mode to reset - [#33330](https://github.com/storybookjs/storybook/pull/33330), thanks @Sidnioulz!\n- Docs-Blocks: Fix broken tooltip in ArgValue details - [#33264](https://github.com/storybookjs/storybook/pull/33264), thanks @Sidnioulz!\n- Manager: Ensure reset item only appears in globals toolbar when specified - [#33276](https://github.com/storybookjs/storybook/pull/33276), thanks @mrginglymus!\n- Nextjs-Vite: Install `vite` during migration if not installed yet - [#33316](https://github.com/storybookjs/storybook/pull/33316), thanks @ghengeveld!\n- UI: Make vertical alignment of TestStatusIcon more robust - [#33305](https://github.com/storybookjs/storybook/pull/33305), thanks @Sidnioulz!\n\n## 10.2.0-alpha.5\n\n- Addon-Vitest: Added timeout for fetching localhost 6006 during global setup. - [#33232](https://github.com/storybookjs/storybook/pull/33232), thanks @snippy4!\n- CLI: Skip vitest transform for CSF Factories in a11y-addon-test automigration - [#31941](https://github.com/storybookjs/storybook/pull/31941), thanks @mrginglymus!\n- Controls: Allow resetting the Select control - [#33289](https://github.com/storybookjs/storybook/pull/33289), thanks @Sidnioulz!\n- Core: Ensure /project.json route is up before builders serve local FS - [#33303](https://github.com/storybookjs/storybook/pull/33303), thanks @Sidnioulz!\n- Docs: Ensure CodePanel hooks are called within component - [#33162](https://github.com/storybookjs/storybook/pull/33162), thanks @mrginglymus!\n- Manager: Do not display non-existing shortcuts in the settings page - [#32711](https://github.com/storybookjs/storybook/pull/32711), thanks @DKER2!\n- Preview: Enforce inert body if manager is focus-trapped - [#33186](https://github.com/storybookjs/storybook/pull/33186), thanks @Sidnioulz!\n- Telemetry: Await pending operations in getLastEvents to prevent race conditions - [#33285](https://github.com/storybookjs/storybook/pull/33285), thanks @valentinpalkovic!\n- UI: Fix keyboard navigation bug for \"reset\" option in `Select` - [#33268](https://github.com/storybookjs/storybook/pull/33268), thanks @Sidnioulz!\n- Vue3: Update renderer's setup function to allow passing generic HostElement type - [#32029](https://github.com/storybookjs/storybook/pull/32029), thanks @DamianGlowala!\n\n## 10.2.0-alpha.4\n\n- Addon-Vitest: Isolate error reasons during postinstall - [#33295](https://github.com/storybookjs/storybook/pull/33295), thanks @valentinpalkovic!\n- CLI: Fix react native template not copying in init - [#33308](https://github.com/storybookjs/storybook/pull/33308), thanks @dannyhw!\n- Core: Retry `writeFile` cache when EBUSY error occurs - [#32981](https://github.com/storybookjs/storybook/pull/32981), thanks @reduckted!\n- Docs: Support Rolldown bundler module namespace objects - [#33280](https://github.com/storybookjs/storybook/pull/33280), thanks @akornmeier!\n- SvelteKit: Align JS template with TS template - [#31451](https://github.com/storybookjs/storybook/pull/31451), thanks @brettearle!\n\n## 10.2.0-alpha.3\n\n- Addon Docs: Skip `!autodocs` stories when computing primary story - [#32712](https://github.com/storybookjs/storybook/pull/32712), thanks @ia319!\n- Angular: Honor --loglevel and --logfile in dev/build - [#33212](https://github.com/storybookjs/storybook/pull/33212), thanks @valentinpalkovic!\n- CSF: Export type to prevent `type cannot be named`-errors - [#33216](https://github.com/storybookjs/storybook/pull/33216), thanks @unional!\n- Chore: Upgrade Chromatic CLI - [#33176](https://github.com/storybookjs/storybook/pull/33176), thanks @ghengeveld!\n- Core: Enhance getPrettier function to provide prettier interface - [#33260](https://github.com/storybookjs/storybook/pull/33260), thanks @valentinpalkovic!\n- Core: Fix cwd handling for negated globs - [#33241](https://github.com/storybookjs/storybook/pull/33241), thanks @ia319!\n- NextJS: Alias image to use fileURLToPath for better resolution - [#33256](https://github.com/storybookjs/storybook/pull/33256), thanks @ndelangen!\n- Nextj.js: Support top-level weight/style in next/font/local with string src - [#32998](https://github.com/storybookjs/storybook/pull/32998), thanks @Chiman2937!\n- Telemetry: Cache Storybook metadata by main config content hash - [#33247](https://github.com/storybookjs/storybook/pull/33247), thanks @valentinpalkovic!\n- TypeScript: Fix summary undefined type issue - [#32585](https://github.com/storybookjs/storybook/pull/32585), thanks @afsalshamsudeen!\n\n## 10.2.0-alpha.2\n\n- CLI: Remove any return type of getAbsolutePath - [#32977](https://github.com/storybookjs/storybook/pull/32977), thanks @nzws!\n- Checklist: Fix how state changes are reported and drop some completion restrictions - [#33217](https://github.com/storybookjs/storybook/pull/33217), thanks @ghengeveld!\n- Core: Avoid late layout shift and improve ChecklistWidget perceived performance - [#33184](https://github.com/storybookjs/storybook/pull/33184), thanks @ghengeveld!\n- Core: Minor UI fixes - [#33218](https://github.com/storybookjs/storybook/pull/33218), thanks @ghengeveld!\n- Preview: Prevent error in RN due to `navigator?.clipboard` - [#33219](https://github.com/storybookjs/storybook/pull/33219), thanks @ndelangen!\n- Solid: Add Solid to the list of supported frameworks for addon-vitest - [#33084](https://github.com/storybookjs/storybook/pull/33084), thanks @valentinpalkovic!\n- Telemetry: Add playwright-prompt - [#33229](https://github.com/storybookjs/storybook/pull/33229), thanks @valentinpalkovic!\n- UI: Fix excessive height in TabbedArgsTable - [#33205](https://github.com/storybookjs/storybook/pull/33205), thanks @Sidnioulz!\n\n## 10.2.0-alpha.1\n\n- Core: Improve globbing using dynamic CWD (REVERT) - [#33201](https://github.com/storybookjs/storybook/pull/33201), thanks @ndelangen!\n\n## 10.2.0-alpha.0\n\n## 10.1.0-beta.6\n\n- Angular: Don't kill dev command by using observables - [#33185](https://github.com/storybookjs/storybook/pull/33185), thanks @valentinpalkovic!\n- Angular: Replace deprecated import of ApplicationConfig - [#33125](https://github.com/storybookjs/storybook/pull/33125), thanks @EtiennePasteur!\n- CLI: Fix passing flags for bun users during init - [#33166](https://github.com/storybookjs/storybook/pull/33166), thanks @valentinpalkovic!\n- CLI: Minor improvements - [#33180](https://github.com/storybookjs/storybook/pull/33180), thanks @valentinpalkovic!\n- CLI: Update upgrade message - [#33182](https://github.com/storybookjs/storybook/pull/33182), thanks @yannbf!\n\n## 10.1.0-beta.5\n\n- Checklist: Autocomplete \"See what's new\" on URL navigation - [#33167](https://github.com/storybookjs/storybook/pull/33167), thanks @ghengeveld!\n- Core: Fix testing widget focus outline - [#33172](https://github.com/storybookjs/storybook/pull/33172), thanks @ghengeveld!\n- Core: Rename `Listbox` component to `ActionList` and use it in `TagsFilterPanel` - [#33140](https://github.com/storybookjs/storybook/pull/33140), thanks @ghengeveld!\n- UI: Add padding for ArgsTable shadow in TabbedArgsTable - [#33034](https://github.com/storybookjs/storybook/pull/33034), thanks @Sidnioulz!\n- UI: Fix crashes in Select when passed falsy non-string options - [#33164](https://github.com/storybookjs/storybook/pull/33164), thanks @Sidnioulz!\n- UI: Fix regression on addon panel empty content fontsize - [#33021](https://github.com/storybookjs/storybook/pull/33021), thanks @Sidnioulz!\n- UI: Fix trivial RefBlocks ARIA violations - [#33026](https://github.com/storybookjs/storybook/pull/33026), thanks @Sidnioulz!\n- UI: Refocus search input after clearing it - [#33165](https://github.com/storybookjs/storybook/pull/33165), thanks @Sidnioulz!\n- UI: Rework default background of Color swatch for dark mode - [#33023](https://github.com/storybookjs/storybook/pull/33023), thanks @Sidnioulz!\n\n## 10.1.0-beta.4\n\n- Angular: Migrate from RxJS to async/await in command builders and run Compodoc utility as spinner - [#33156](https://github.com/storybookjs/storybook/pull/33156), thanks @valentinpalkovic!\n- CLI: Fix 'beforeVersion' evaluation for Storybook package - [#33141](https://github.com/storybookjs/storybook/pull/33141), thanks @valentinpalkovic!\n- CLI: Update clack - [#33151](https://github.com/storybookjs/storybook/pull/33151), thanks @valentinpalkovic!\n- Checklist: Data improvements - [#33129](https://github.com/storybookjs/storybook/pull/33129), thanks @ghengeveld!\n- Guide: Collapse checklist items by default - [#33160](https://github.com/storybookjs/storybook/pull/33160), thanks @ghengeveld!\n- React: Add isPackage flag to component imports for better package identification - [#33090](https://github.com/storybookjs/storybook/pull/33090), thanks @kasperpeulen!\n- UI: Improve status handling in sidebar nodes - [#32965](https://github.com/storybookjs/storybook/pull/32965), thanks @yannbf!\n\n## 10.1.0-beta.3\n\n- A11y: Make search clear button keyboard accessible - [#32590](https://github.com/storybookjs/storybook/pull/32590), thanks @ritoban23!\n- Angular: Add preset entry point for framework - [#33154](https://github.com/storybookjs/storybook/pull/33154), thanks @valentinpalkovic!\n- CLI: Fix framework config validation path and messages - [#33146](https://github.com/storybookjs/storybook/pull/33146), thanks @valentinpalkovic!\n- Manager: Added tokens and a dark color scheme for status colors - [#33081](https://github.com/storybookjs/storybook/pull/33081), thanks @MichaelArestad!\n- Remove yarn esbuild pnp plugin - [#33097](https://github.com/storybookjs/storybook/pull/33097), thanks @mrginglymus!\n- UI: Increase border contrast of Checkbox, Radio, and Range - [#33064](https://github.com/storybookjs/storybook/pull/33064), thanks @MichaelArestad!\n\n## 10.1.0-beta.2\n\n- Automigration: Update description and link for addon-a11y-addon-test - [#33133](https://github.com/storybookjs/storybook/pull/33133), thanks @valentinpalkovic!\n- CLI: Fix Vitest v3 installs and refactor AddonVitestService; align create‑storybook usage - [#33131](https://github.com/storybookjs/storybook/pull/33131), thanks @valentinpalkovic!\n- CLI: Update postAction hook to use command parameter for logfile retrieval - [#33137](https://github.com/storybookjs/storybook/pull/33137), thanks @valentinpalkovic!\n- Core: Fix `getDocsUrl` for canary versions - [#33128](https://github.com/storybookjs/storybook/pull/33128), thanks @ghengeveld!\n\n## 10.1.0-beta.1\n\n- Addon-Vitest: Ensure Storybook starts correctly across platforms by using shell in spawn - [#33116](https://github.com/storybookjs/storybook/pull/33116), thanks @valentinpalkovic!\n- Build: Fix async telemetry event sending - [#33115](https://github.com/storybookjs/storybook/pull/33115), thanks @valentinpalkovic!\n- CLI: Fix access to getOptionValue in postAction hook - [#33119](https://github.com/storybookjs/storybook/pull/33119), thanks @valentinpalkovic!\n- CLI: Standardize debug log messages across the application - [#33123](https://github.com/storybookjs/storybook/pull/33123), thanks @valentinpalkovic!\n- CLI: Update compatibility guidance link in summary message - [#33117](https://github.com/storybookjs/storybook/pull/33117), thanks @valentinpalkovic!\n- Core: Update `getDocsUrl` to add a default `ref` param and set `guide` as ref for links in the Guide - [#33111](https://github.com/storybookjs/storybook/pull/33111), thanks @ghengeveld!\n- Guide: Hide items for which their required feature is disabled (controls, viewport, interactions) - [#33113](https://github.com/storybookjs/storybook/pull/33113), thanks @ghengeveld!\n\n## 10.1.0-beta.0\n\n## 10.1.0-alpha.14\n\n- Angular: Add support for v21 - [#33098](https://github.com/storybookjs/storybook/pull/33098), thanks @valentinpalkovic!\n- Build: Add Rsbuild-based sandboxes - [#33039](https://github.com/storybookjs/storybook/pull/33039), thanks @valentinpalkovic!\n- CLI: Change yarn package manager value to yarn1 - [#33099](https://github.com/storybookjs/storybook/pull/33099), thanks @valentinpalkovic!\n- Onboarding: Guided tour checklist - [#32795](https://github.com/storybookjs/storybook/pull/32795), thanks @ghengeveld!\n\n## 10.1.0-alpha.13\n\n- CLI: Modernize Storybook CLI with new init workflow, Clack UI, and Generator System - [#32717](https://github.com/storybookjs/storybook/pull/32717), thanks @valentinpalkovic!\n\n## 10.1.0-alpha.12\n\n- Build: Update dependencies in yarn.lock and clean up comments - [#33089](https://github.com/storybookjs/storybook/pull/33089), thanks @ndelangen!\n- CLI: In csf-factories codemod only remove types which are unused - [#33020](https://github.com/storybookjs/storybook/pull/33020), thanks @yannbf!\n- React: Improve import rewriting when tsconfig paths are used - [#33072](https://github.com/storybookjs/storybook/pull/33072), thanks @kasperpeulen!\n\n## 10.1.0-alpha.11\n\n- Maintenance: Enable syntax minification for dead code elimination - [#33001](https://github.com/storybookjs/storybook/pull/33001), thanks @mrginglymus!\n- React Native Web: Fix react native resuables and nativewind - [#33056](https://github.com/storybookjs/storybook/pull/33056), thanks @dannyhw!\n- UI: Add VRTs to FileSearchModal in light theme - [#33022](https://github.com/storybookjs/storybook/pull/33022), thanks @Sidnioulz!\n- WebComponents: Fix `custom-elements.json` not being loaded - [#33045](https://github.com/storybookjs/storybook/pull/33045), thanks @ndelangen!\n\n## 10.1.0-alpha.10\n\n- Core: Significantly improve Storybook's own accessibility - [#32458](https://github.com/storybookjs/storybook/pull/32458), thanks @Sidnioulz!\n\n## 10.1.0-alpha.9\n\n- Core: Improve globbing using dynamic CWD - [#32990](https://github.com/storybookjs/storybook/pull/32990), thanks @ia319!\n\n## 10.1.0-alpha.8\n\n- ESLint: Only apply csf-strict rules on stories files - [#31963](https://github.com/storybookjs/storybook/pull/31963), thanks @cylewaitforit!\n- Middleware: Prepend `file://` to middleware `import` for Windows support - [#32955](https://github.com/storybookjs/storybook/pull/32955), thanks @ndelangen!\n- Next.js: Update SWC loader to support new wasm detection - [#33003](https://github.com/storybookjs/storybook/pull/33003), thanks @yannbf!\n- React Native Web: Update vite-plugin-rnw for overall improvements - [#32991](https://github.com/storybookjs/storybook/pull/32991), thanks @dannyhw!\n\n## 10.1.0-alpha.7\n\n- CSF: Fix export interface declaration for NextPreview - [#32914](https://github.com/storybookjs/storybook/pull/32914), thanks @icopp!\n- Controls: Add range validation in Number Control - [#32539](https://github.com/storybookjs/storybook/pull/32539), thanks @ia319!\n- Fix: Export interface declaration for ReactMeta - [#32915](https://github.com/storybookjs/storybook/pull/32915), thanks @icopp!\n- React: Improve error messages in component manifest - [#32954](https://github.com/storybookjs/storybook/pull/32954), thanks @kasperpeulen!\n- Vitest Addon: Add support for Preact - [#32948](https://github.com/storybookjs/storybook/pull/32948), thanks @yannbf!\n\n## 10.1.0-alpha.6\n\n- Core: Add reentry guard to focus patch - [#32655](https://github.com/storybookjs/storybook/pull/32655), thanks @ia319!\n- Nextjs Vite: Update internal plugin to support `svgr` use cases - [#32957](https://github.com/storybookjs/storybook/pull/32957), thanks @yannbf!\n\n## 10.1.0-alpha.5\n\n- CLI: Fix issue with running Storybook after being initialized - [#32929](https://github.com/storybookjs/storybook/pull/32929), thanks @yannbf!\n- CRA: Fix `module` not defined in ESM - [#32940](https://github.com/storybookjs/storybook/pull/32940), thanks @ndelangen!\n- React: Improve automatic component, automatic imports, support barrel files and enhance story filtering - [#32939](https://github.com/storybookjs/storybook/pull/32939), thanks @kasperpeulen!\n- Theming: Set `themes.normal` according to user preference and export `getPreferredColorScheme` - [#28721](https://github.com/storybookjs/storybook/pull/28721), thanks @elisezhg!\n\n## 10.1.0-alpha.4\n\n- Core: Better handling for TypeScript satisfies/as syntaxes - [#32891](https://github.com/storybookjs/storybook/pull/32891), thanks @yannbf!\n- Core: Fix wrong import to fix Yarn PnP support - [#32928](https://github.com/storybookjs/storybook/pull/32928), thanks @yannbf!\n- ESlint: Update `@storybook/experimental-nextjs-vite` in `no-renderer-packages` rule - [#32909](https://github.com/storybookjs/storybook/pull/32909), thanks @ndelangen!\n- React Native: Update withStorybook setup instructions - [#32919](https://github.com/storybookjs/storybook/pull/32919), thanks @dannyhw!\n- React: Change examples to stories in manifests and show correct examples and prop types - [#32908](https://github.com/storybookjs/storybook/pull/32908), thanks @kasperpeulen!\n\n## 10.1.0-alpha.3\n\n- React: Add manifests/components.html page - [#32905](https://github.com/storybookjs/storybook/pull/32905), thanks @kasperpeulen!\n\n## 10.1.0-alpha.2\n\n- A11y: Add aria-selected attribute to tab buttons - [#32656](https://github.com/storybookjs/storybook/pull/32656), thanks @Nischit-Ekbote!\n- React: Experimental code examples - [#32813](https://github.com/storybookjs/storybook/pull/32813), thanks @kasperpeulen!\n- React: Implement manifests/component.json for React - [#32751](https://github.com/storybookjs/storybook/pull/32751), thanks @kasperpeulen!\n- React: Improve error handling of component manifest generation - [#32855](https://github.com/storybookjs/storybook/pull/32855), thanks @kasperpeulen!\n\n## 10.1.0-alpha.1\n\n- CLI: Fix glob string formatting in csf-factories codemod - [#32880](https://github.com/storybookjs/storybook/pull/32880), thanks @yannbf!\n- Core: Improve file path resolution on Windows - [#32893](https://github.com/storybookjs/storybook/pull/32893), thanks @yannbf!\n- Presets: Fix incorrect imports - [#32875](https://github.com/storybookjs/storybook/pull/32875), thanks @ndelangen!\n- Vite: Update `optimizeViteDeps` for addon-docs and addon-vitest - [#32881](https://github.com/storybookjs/storybook/pull/32881), thanks @ndelangen!\n\n## 10.1.0-alpha.0\n\n## 10.0.0-rc.4\n\n- Core: Add `experimental_devServer` preset - [#32862](https://github.com/storybookjs/storybook/pull/32862), thanks @yannbf!\n- Core: Fix stepping back through story interactions panel - [#32793](https://github.com/storybookjs/storybook/pull/32793), thanks @ia319!\n- Core: Join framework preset path with slash - [#32838](https://github.com/storybookjs/storybook/pull/32838), thanks @brandonroberts!\n- Telemetry: Fix preview-first-load event - [#32859](https://github.com/storybookjs/storybook/pull/32859), thanks @shilman!\n\n## 10.0.0-rc.3\n\n- A11y: Persist tab/highlight across docs navigation - [#32762](https://github.com/storybookjs/storybook/pull/32762), thanks @404Dealer!\n- Addon Vitest: Fix incorrect file modifications during setup - [#32844](https://github.com/storybookjs/storybook/pull/32844), thanks @yannbf!\n- Core: Enhance warning for Testing Library's `screen` usage in docs mode - [#32851](https://github.com/storybookjs/storybook/pull/32851), thanks @yannbf!\n- Core: Mark pnp support as deprecated - [#32645](https://github.com/storybookjs/storybook/pull/32645), thanks @ndelangen!\n\n## 10.0.0-rc.2\n\n- CLI: Fix Nextjs project creation in empty directories - [#32828](https://github.com/storybookjs/storybook/pull/32828), thanks @yannbf!\n- CLI: Switch over to modern-tar - [#32763](https://github.com/storybookjs/storybook/pull/32763), thanks @ayuhito!\n- Core: Add parameter typings for addon-pseudo-state - [#32384](https://github.com/storybookjs/storybook/pull/32384), thanks @mrginglymus!\n- Core: Dedupe aria-query and @testing-library/dom packages - [#32801](https://github.com/storybookjs/storybook/pull/32801), thanks @mrginglymus!\n- Core: Improve es-toolkit usage for better tree-shaking - [#32787](https://github.com/storybookjs/storybook/pull/32787), thanks @mrginglymus!\n- Core: Replace es-toolkit compat imports with non-compat - [#32837](https://github.com/storybookjs/storybook/pull/32837), thanks @mrginglymus!\n- React: Simplify version detection - [#32802](https://github.com/storybookjs/storybook/pull/32802), thanks @mrginglymus!\n- Vite: Optimize @storybook/addon-docs/blocks dependency - [#32798](https://github.com/storybookjs/storybook/pull/32798), thanks @mrginglymus!\n\n## 10.0.0-rc.1\n\n- Addon-Vitest: Support Vitest 4 - [#32819](https://github.com/storybookjs/storybook/pull/32819), thanks @yannbf!\n- CSF: Fix `play-fn` tag for methods - [#32695](https://github.com/storybookjs/storybook/pull/32695), thanks @shilman!\n- Core: Add `preview-first-load` telemetry - [#32770](https://github.com/storybookjs/storybook/pull/32770), thanks @shilman!\n- Dependencies: Update `vite-plugin-storybook-nextjs` - [#32821](https://github.com/storybookjs/storybook/pull/32821), thanks @ndelangen!\n- Maintenance: Fix bundle size bloat caused by `SyntaxHighlighter` (`createElement`) - [#32800](https://github.com/storybookjs/storybook/pull/32800), thanks @mrginglymus!\n- Nextjs: Add Next v16 support - [#32791](https://github.com/storybookjs/storybook/pull/32791), thanks @yannbf!\n- UI: Improve syntax-highlighter bundling - [#32776](https://github.com/storybookjs/storybook/pull/32776), thanks @mrginglymus!\n\n## 10.0.0-rc.0\n\n- A11Y: Bugfix missing `manager.js` entry-file - [#32780](https://github.com/storybookjs/storybook/pull/32780), thanks @ndelangen!\n- Addon Vitest: Support modifying mergeConfig on addon setup - [#32753](https://github.com/storybookjs/storybook/pull/32753), thanks @yannbf!\n- CLI: Change message in downgrade-blocker - [#32745](https://github.com/storybookjs/storybook/pull/32745), thanks @ndelangen!\n\n## 10.0.0-beta.13\n\n- CLI: CSF factories codemod - support annotations in npx context - [#32741](https://github.com/storybookjs/storybook/pull/32741), thanks @yannbf!\n- Move: Addon jest into it's own repository - [#32646](https://github.com/storybookjs/storybook/pull/32646), thanks @ndelangen!\n- Upgrade: Enhance ESM compatibility checks and banner generation - [#32694](https://github.com/storybookjs/storybook/pull/32694), thanks @ndelangen!\n\n## 10.0.0-beta.12\n\n- CLI: Avoid mixed CSF in files with unconventional stories - [#32716](https://github.com/storybookjs/storybook/pull/32716), thanks @yannbf!\n- CLI: Fix CSF factories addon syncing in storybook add command - [#32728](https://github.com/storybookjs/storybook/pull/32728), thanks @yannbf!\n- CLI: Make relative imports default in csf-factories codemod - [#32610](https://github.com/storybookjs/storybook/pull/32610), thanks @copilot-swe-agent!\n- Core: Prevent navigating to hidden (filtered) item - [#32715](https://github.com/storybookjs/storybook/pull/32715), thanks @ghengeveld!\n- Fix: Allow proceeding without selecting automigrations in upgrade command - [#32597](https://github.com/storybookjs/storybook/pull/32597), thanks @copilot-swe-agent!\n\n## 10.0.0-beta.11\n\n- Automigration: Improve the viewport/backgrounds automigration - [#32619](https://github.com/storybookjs/storybook/pull/32619), thanks @valentinpalkovic!\n- CSF: Enhance config-to-csf-factory to support type wrappers - [#32543](https://github.com/storybookjs/storybook/pull/32543), thanks @yannbf!\n- Core: Ensure valid QR code URL - [#32661](https://github.com/storybookjs/storybook/pull/32661), thanks @ghengeveld!\n- Mocking: Fix `sb.mock` usage in Storybook's deployed in subpaths - [#32678](https://github.com/storybookjs/storybook/pull/32678), thanks @valentinpalkovic!\n- NextJS-Vite: Automatically fix bad PostCSS configuration - [#32691](https://github.com/storybookjs/storybook/pull/32691), thanks @ndelangen!\n- Nextjs: Fix Nextjs version detection with prereleases - [#32724](https://github.com/storybookjs/storybook/pull/32724), thanks @yannbf!\n- Presets: Support extensionless imports in TS-based presets - [#32641](https://github.com/storybookjs/storybook/pull/32641), thanks @JReinhold!\n- React Native Web: Fix REACT_NATIVE_AND_RNW should detect vite builder - [#32718](https://github.com/storybookjs/storybook/pull/32718), thanks @dannyhw!\n\n## 10.0.0-beta.10\n\n- Core: Make `subtype` an optional property on an index input - [#32602](https://github.com/storybookjs/storybook/pull/32602), thanks @JReinhold!\n- Core: Various QA fixes - [#32629](https://github.com/storybookjs/storybook/pull/32629), thanks @ghengeveld!\n- Fix: Incorrect URLS for the upgrade command - [#32624](https://github.com/storybookjs/storybook/pull/32624), thanks @jonniebigodes!\n- Onboarding: Prevent confetti overlay from intercepting pointer events - [#32660](https://github.com/storybookjs/storybook/pull/32660), thanks @ghengeveld!\n- Telemetry: Add metadata for react routers - [#32615](https://github.com/storybookjs/storybook/pull/32615), thanks @shilman!\n\n## 10.0.0-beta.9\n\n- Automigrations: Add automigration for viewport and backgrounds - [#31614](https://github.com/storybookjs/storybook/pull/31614), thanks @valentinpalkovic!\n- Svelte: Simplify public types - use modern `Component` - [#31394](https://github.com/storybookjs/storybook/pull/31394), thanks @xeho91!\n- Telemetry: Log userAgent in onboarding - [#32566](https://github.com/storybookjs/storybook/pull/32566), thanks @shilman!\n\n## 10.0.0-beta.8\n\n- Addon-docs: Add eject button to canvas toolbar - [#29825](https://github.com/storybookjs/storybook/pull/29825), thanks @mihkeleidast!\n- Angular: Enable experimental zoneless detection on Angular v21 - [#32580](https://github.com/storybookjs/storybook/pull/32580), thanks @yannbf!\n- AutoMigration: Fix sb10 migration when main config contains `require` - [#32558](https://github.com/storybookjs/storybook/pull/32558), thanks @ndelangen!\n- Cleanup: Remove duplicated entrypoints in core - [#32507](https://github.com/storybookjs/storybook/pull/32507), thanks @ndelangen!\n- Controls: Fix adding new values to arrays - [#32512](https://github.com/storybookjs/storybook/pull/32512), thanks @takashi-kasajima!\n- Core: Fix `external-globals-plugin` handle `undefined` cache dir - [#32579](https://github.com/storybookjs/storybook/pull/32579), thanks @walkerburgin!\n- Core: Use `exsolve` `resolveModulePath` for `safeResolveModule` - [#32477](https://github.com/storybookjs/storybook/pull/32477), thanks @mrginglymus!\n- Next.js: Remove next/config usage in Next.js >=v16 projects - [#32547](https://github.com/storybookjs/storybook/pull/32547), thanks @valentinpalkovic!\n- React Native: Fix document reference error in open-in-editor - [#32572](https://github.com/storybookjs/storybook/pull/32572), thanks @dannyhw!\n- Svelte: Ignore inherited `HTMLAttributes` docgen when using utility types - [#32173](https://github.com/storybookjs/storybook/pull/32173), thanks @steciuk!\n- UI: Improve sidebar empty state - [#32548](https://github.com/storybookjs/storybook/pull/32548), thanks @ghengeveld!\n\n## 10.0.0-beta.7\n\n- Addon A11y: Prevent setting highlights for old results - [#32178](https://github.com/storybookjs/storybook/pull/32178), thanks @ghengeveld!\n- AddonViewport: Stricter types - [#32324](https://github.com/storybookjs/storybook/pull/32324), thanks @hpohlmeyer!\n- CSF: Add Storybook test syntax (Storybook v10) - [#32455](https://github.com/storybookjs/storybook/pull/32455), thanks @yannbf!\n- Controls: Allow primitive values of ReactNode argType - [#31931](https://github.com/storybookjs/storybook/pull/31931), thanks @alexey-kozlenkov!\n- Core: Prevent `BAIL` state from showing in interactions panel when switching stories - [#32172](https://github.com/storybookjs/storybook/pull/32172), thanks @ghengeveld!\n- CoreServer: Fix `Arc can't get every window` - [#32508](https://github.com/storybookjs/storybook/pull/32508), thanks @ndelangen!\n- Dts: Ensure `.tsx` files emit `.d.ts` type files - [#32461](https://github.com/storybookjs/storybook/pull/32461), thanks @mrginglymus!\n- Svelte: Improve support for async components - [#31476](https://github.com/storybookjs/storybook/pull/31476), thanks @JReinhold!\n- SvelteKit: Add support for mocking `$app/state` - [#31369](https://github.com/storybookjs/storybook/pull/31369), thanks @xeho91!\n- SvelteKit: Fix `set_context_after_init` error when experimental async is enabled - [#32513](https://github.com/storybookjs/storybook/pull/32513), thanks @Jakeii!\n- UI: Allow showing or hiding the addon panel - [#32348](https://github.com/storybookjs/storybook/pull/32348), thanks @Sidnioulz!\n\n## 10.0.0-beta.6\n\n- Core: Add \"open in editor\" feature - [#32452](https://github.com/storybookjs/storybook/pull/32452), thanks @yannbf!\n- Dev: Improve the browser opening experience - [#32488](https://github.com/storybookjs/storybook/pull/32488), thanks @ndelangen!\n- Maintenance: Remove globalization for dropped entrypoints - [#32491](https://github.com/storybookjs/storybook/pull/32491), thanks @ndelangen!\n- Telemetry: Queue error reporting & filter browser-extention - [#32499](https://github.com/storybookjs/storybook/pull/32499), thanks @ndelangen!\n- Upgrade: Packages `open` - [#32484](https://github.com/storybookjs/storybook/pull/32484), thanks @ndelangen!\n\n## 10.0.0-beta.5\n\n- Dependencies: Update `vite-plugin-storybook-nextjs` to 2.0.7 - [#32331](https://github.com/storybookjs/storybook/pull/32331), thanks @k35o!\n- Fix: ESLint plugin homepage URL updates - [#32445](https://github.com/storybookjs/storybook/pull/32445), thanks @VivekKavala!\n- Upgrades: Packages `boxen` `commander` `giget` - [#32469](https://github.com/storybookjs/storybook/pull/32469), thanks @ndelangen!\n\n## 10.0.0-beta.4\n\n- Replace: Use `empathic` over `find-up` - [#31338](https://github.com/storybookjs/storybook/pull/31338), thanks @beeequeue!\n\n## 10.0.0-beta.3\n\n- CLI: Add addon-console automigration - [#32083](https://github.com/storybookjs/storybook/pull/32083), thanks @Sidnioulz!\n- CLI: Capture the version specifier used in `create-storybook` - [#32344](https://github.com/storybookjs/storybook/pull/32344), thanks @shilman!\n- CLI: Init not running `dev` when it should fixed - [#32457](https://github.com/storybookjs/storybook/pull/32457), thanks @ndelangen!\n- CSF: Support `satisfies x as y` syntax - [#32169](https://github.com/storybookjs/storybook/pull/32169), thanks @diagramatics!\n- Core: Fix Node 24 deprecation warning - [#32382](https://github.com/storybookjs/storybook/pull/32382), thanks @JReinhold!\n- Core: Switch from `mlly` to `exsolve` - [#32383](https://github.com/storybookjs/storybook/pull/32383), thanks @mrginglymus!\n- Instrumenter: Fix userEvent.type performance regression - [#32439](https://github.com/storybookjs/storybook/pull/32439), thanks @ndelangen!\n- Modernize: Replace `fs-extra` with native APIs - [#32296](https://github.com/storybookjs/storybook/pull/32296), thanks @y-hsgw!\n- React Native Web: Fix RNW peer dependency version - [#32438](https://github.com/storybookjs/storybook/pull/32438), thanks @dannyhw!\n- React: Preserve `@ts-expect-error` in preview - [#32442](https://github.com/storybookjs/storybook/pull/32442), thanks @mrginglymus!\n- Telemetry: Record known CLI integrations - [#32448](https://github.com/storybookjs/storybook/pull/32448), thanks @shilman!\n\n## 10.0.0-beta.2\n\n- Build: Fix dts bundling external detection - [#32366](https://github.com/storybookjs/storybook/pull/32366), thanks @mrginglymus!\n- Codemod: Replace `globby` with `tinyglobby` - [#31407](https://github.com/storybookjs/storybook/pull/31407), thanks @benmccann!\n- Next.js-vite: Use `fileURLToPath` for module resolution in preset - [#32386](https://github.com/storybookjs/storybook/pull/32386), thanks @ndelangen!\n- Tags: Remove undocumented x-only tags - [#32360](https://github.com/storybookjs/storybook/pull/32360), thanks @shilman!\n- Vitest addon: Handle Playwright installation errors gracefully - [#32329](https://github.com/storybookjs/storybook/pull/32329), thanks @ndelangen!\n\n## 10.0.0-beta.1\n\n- AddonA11Y: Fix postinstall - [#32309](https://github.com/storybookjs/storybook/pull/32309), thanks @ndelangen!\n- Angular: Properly merge builder options and browserTarget options - [#32272](https://github.com/storybookjs/storybook/pull/32272), thanks @kroeder!\n- Core: Optimize bundlesize, by reusing internal/babel in mocking-utils - [#32350](https://github.com/storybookjs/storybook/pull/32350), thanks @ndelangen!\n- Core: Update tags filter UI - [#32343](https://github.com/storybookjs/storybook/pull/32343), thanks @ghengeveld!\n- Next.js: Avoid multiple webpack versions at runtime - [#32313](https://github.com/storybookjs/storybook/pull/32313), thanks @valentinpalkovic!\n- Next.js: Fix version mismatch error in Webpack - [#32306](https://github.com/storybookjs/storybook/pull/32306), thanks @valentinpalkovic!\n- Svelte & Vue: Add framework-specific `docgen` option to disable docgen processing - [#32319](https://github.com/storybookjs/storybook/pull/32319), thanks @copilot-swe-agent!\n- Svelte: Support `@sveltejs/vite-plugin-svelte` v6 - [#32320](https://github.com/storybookjs/storybook/pull/32320), thanks @JReinhold!\n- Update: Satellite repos after major version bump - [#32303](https://github.com/storybookjs/storybook/pull/32303), thanks @ndelangen!\n\n## 10.0.0-beta.0\n\n- Core: Fix staticCopy not copying `index.html` to sub directory - [#32259](https://github.com/storybookjs/storybook/pull/32259), thanks @ndelangen!\n- Core: Remove CJS bundles, only ship ESM - [#31819](https://github.com/storybookjs/storybook/pull/31819), thanks @ndelangen!\n- Docs: Move button in ArgsTable heading to fix screenreader announcements - [#32238](https://github.com/storybookjs/storybook/pull/32238), thanks @Sidnioulz!\n- Telemetry: Disambiguate traffic coming from error/upgrade links - [#32287](https://github.com/storybookjs/storybook/pull/32287), thanks @shilman!\n- Telemetry: Disambiguate unattributed traffic from Onboarding - [#32286](https://github.com/storybookjs/storybook/pull/32286), thanks @shilman!\n\n## 9.2.0-alpha.3\n\n- Addon Docs: Fix Symbol conversion issue in docs page and controls panel - [#32220](https://github.com/storybookjs/storybook/pull/32220), thanks @yannbf!\n- Angular: Fix `entry.polyfills` undefined error - [#32230](https://github.com/storybookjs/storybook/pull/32230), thanks @sk-pub!\n- Angular: Inherit options from browserTarget - [#32108](https://github.com/storybookjs/storybook/pull/32108), thanks @gingeekrishna!\n- Core: Improve addon detection in automigrations on windows - [#31937](https://github.com/storybookjs/storybook/pull/31937), thanks @mrginglymus!\n- Mock: Catch errors when transforming preview files - [#32216](https://github.com/storybookjs/storybook/pull/32216), thanks @valentinpalkovic!\n- Next.js: Return mocked router instead of actual router in useRouter - [#32131](https://github.com/storybookjs/storybook/pull/32131), thanks @JulioJ11!\n- Telemetry: Improve dev cancellation handling - [#32218](https://github.com/storybookjs/storybook/pull/32218), thanks @shilman!\n\n## 9.2.0-alpha.2\n\n- Onboarding: Tweak referral wording in survey - [#32185](https://github.com/storybookjs/storybook/pull/32185), thanks @shilman!\n\n## 9.2.0-alpha.1\n\n- Addon Docs: Add `__STORYBOOK_UNSAFE_TOCBOT__` global - [#32176](https://github.com/storybookjs/storybook/pull/32176), thanks @yannbf!\n- CLI: Fix throwing in readonly environments - [#31785](https://github.com/storybookjs/storybook/pull/31785), thanks @JReinhold!\n- Telemetry: Send index stats on dev exit - [#32168](https://github.com/storybookjs/storybook/pull/32168), thanks @shilman!\n\n## 9.2.0-alpha.0\n\n## 9.1.0-beta.3\n\n- Core: Prevent interactions panel from flickering and showing incorrect state - [#32150](https://github.com/storybookjs/storybook/pull/32150), thanks @ghengeveld!\n\n## 9.1.0-beta.2\n\n- Test: Consider exports map - [#32157](https://github.com/storybookjs/storybook/pull/32157), thanks @valentinpalkovic!\n- Test: Invalidate vite cache for manual mocks - [#32152](https://github.com/storybookjs/storybook/pull/32152), thanks @valentinpalkovic!\n\n## 9.1.0-beta.1\n\n- Automigration: Await updateMainConfig in removeEssentials - [#32140](https://github.com/storybookjs/storybook/pull/32140), thanks @valentinpalkovic!\n- Docs: Update @storybook/icons - [#32144](https://github.com/storybookjs/storybook/pull/32144), thanks @valentinpalkovic!\n- Init: Exclude mdx stories when docs feature isn't selected during init - [#32142](https://github.com/storybookjs/storybook/pull/32142), thanks @valentinpalkovic!\n\n## 9.1.0-beta.0\n\n- Core: Avoid pausing animations in non-Vitest Playwright environments - [#32123](https://github.com/storybookjs/storybook/pull/32123), thanks @ghengeveld!\n\n## 9.1.0-alpha.10\n\n- Core: Abort play function on HMR - [#31542](https://github.com/storybookjs/storybook/pull/31542), thanks @ghengeveld!\n- Core: Fix moving log file across drives and projectRoot detection on Windows - [#32020](https://github.com/storybookjs/storybook/pull/32020), thanks @ghengeveld!\n- Maintenance: Add flag to toggle default automigrations - [#32113](https://github.com/storybookjs/storybook/pull/32113), thanks @yannbf!\n- React Native Web: Simplify config by using vite-plugin-rnw - [#32051](https://github.com/storybookjs/storybook/pull/32051), thanks @dannyhw!\n- Telemetry: Add automigration errors - [#32103](https://github.com/storybookjs/storybook/pull/32103), thanks @yannbf!\n- Test: Fix missing source map for Webpack/Vite mock loaders and plugins - [#32111](https://github.com/storybookjs/storybook/pull/32111), thanks @valentinpalkovic!\n- Test: Remove source map generation from webpack automock-loader - [#32115](https://github.com/storybookjs/storybook/pull/32115), thanks @valentinpalkovic!\n\n## 9.1.0-alpha.9\n\n- CLI: Fix Storybook doctor compatibility checks - [#32077](https://github.com/storybookjs/storybook/pull/32077), thanks @yannbf!\n- Svelte: Fix union types generating invalid labels in argTypes - [#31980](https://github.com/storybookjs/storybook/pull/31980), thanks @grantralls!\n- Telemetry: Add nodeLinker to telemetry - [#32072](https://github.com/storybookjs/storybook/pull/32072), thanks @valentinpalkovic!\n- Test: Add mock capabilities - [#31987](https://github.com/storybookjs/storybook/pull/31987), thanks @valentinpalkovic!\n\n## 9.1.0-alpha.8\n\n- Addon Vitest: Fix support for plain `stories.tsx` files - [#32041](https://github.com/storybookjs/storybook/pull/32041), thanks @ghengeveld!\n- Angular: Prevent directory import in Angular builders - [#32012](https://github.com/storybookjs/storybook/pull/32012), thanks @ghengeveld!\n- Automigration: Fail with non-zero exit code on migration failure - [#31923](https://github.com/storybookjs/storybook/pull/31923), thanks @mrginglymus!\n- Builder-Vite: Fix logic related to setting allowedHosts when IP address used - [#31472](https://github.com/storybookjs/storybook/pull/31472), thanks @JSMike!\n- Onboarding: Intent survey - [#31944](https://github.com/storybookjs/storybook/pull/31944), thanks @ghengeveld!\n- UI: Fix interaction step collapse icon - [#31853](https://github.com/storybookjs/storybook/pull/31853), thanks @AvitalHass!\n- UI: Fix text color for failing stories in sidebar - [#32042](https://github.com/storybookjs/storybook/pull/32042), thanks @ghengeveld!\n\n## 9.1.0-alpha.7\n\n- A11y: Improved toolbar a11y by fixing semantics - [#28672](https://github.com/storybookjs/storybook/pull/28672), thanks @mehm8128!\n- Addon Vitest: Remove Optimize deps candidates due to Vitest warnings - [#31809](https://github.com/storybookjs/storybook/pull/31809), thanks @valentinpalkovic!\n- Addon Vitest: Support init in Vitest >= 3.2 - [#31715](https://github.com/storybookjs/storybook/pull/31715), thanks @valentinpalkovic!\n- Addons: Use chromatic-com/storybook without version specifier - [#31627](https://github.com/storybookjs/storybook/pull/31627), thanks @valentinpalkovic!\n- Angular: Bundle using TSup - [#31690](https://github.com/storybookjs/storybook/pull/31690), thanks @ndelangen!\n- Angular: Fix Storybook experimentalZoneless is not compatible with Angular 20 - [#31772](https://github.com/storybookjs/storybook/pull/31772), thanks @guysenpai!\n- Angular: Tailwind 4 compatibility - [#31759](https://github.com/storybookjs/storybook/pull/31759), thanks @valentinpalkovic!\n- Angular: Update MiniCssExtractPlugin configuration for cache busting - [#31752](https://github.com/storybookjs/storybook/pull/31752), thanks @valentinpalkovic!\n- CLI: Add RN/RNW \"both\" init option - [#31778](https://github.com/storybookjs/storybook/pull/31778), thanks @shilman!\n- CLI: Do not fail incompatible package check in doctor if only core packages used - [#31886](https://github.com/storybookjs/storybook/pull/31886), thanks @mrginglymus!\n- CLI: Fix `sb` CLI by explicitly exporting `bin/index.cjs` from `storybook` package - [#31922](https://github.com/storybookjs/storybook/pull/31922), thanks @ghengeveld!\n- CLI: Prebundle more in cli-storybook package - [#31746](https://github.com/storybookjs/storybook/pull/31746), thanks @ndelangen!\n- CLI: Show Storybook version in the upgrade command - [#31774](https://github.com/storybookjs/storybook/pull/31774), thanks @yannbf!\n- CSF: Improve controls parameters - [#31745](https://github.com/storybookjs/storybook/pull/31745), thanks @kasperpeulen!\n- CSF: Story ComponentAnnotations['subcomponents'] to correctly use its own type for subcomponents rather than attempt to inherit from the component - [#31723](https://github.com/storybookjs/storybook/pull/31723), thanks @mihkeleidast!\n- Controls: Improve the accessibility of the object control - [#31581](https://github.com/storybookjs/storybook/pull/31581), thanks @Sidnioulz!\n- Core: Cleanup of type following up v9 and small verbatimModuleSyntax type fix - [#31823](https://github.com/storybookjs/storybook/pull/31823), thanks @alcpereira!\n- Core: Disable interactions debugger on composed stories to avoid cross-origin error - [#31685](https://github.com/storybookjs/storybook/pull/31685), thanks @ghengeveld!\n- Core: Enhance package manager install methods to support optional force flag - [#31796](https://github.com/storybookjs/storybook/pull/31796), thanks @valentinpalkovic!\n- Core: Fix FIPS compliance - [#31806](https://github.com/storybookjs/storybook/pull/31806), thanks @JReinhold!\n- Core: Fix addon scrollbars and align scrollbar colors with toolbars - [#31844](https://github.com/storybookjs/storybook/pull/31844), thanks @Sidnioulz!\n- Core: Fix aria-controls attribute on sidebar nodes to include all children - [#31491](https://github.com/storybookjs/storybook/pull/31491), thanks @candrepa1!\n- Core: Fix cyclical dependency in core addons - [#31750](https://github.com/storybookjs/storybook/pull/31750), thanks @JReinhold!\n- Core: Fix horizontal scrollbar covering part of the toolbar - [#31704](https://github.com/storybookjs/storybook/pull/31704), thanks @Sidnioulz!\n- Core: Fix issue where collapsed test controls can be tabbed into - [#31921](https://github.com/storybookjs/storybook/pull/31921), thanks @zenocross!\n- Core: Gracefully handle disallowed cross-origin clipboard access - [#31834](https://github.com/storybookjs/storybook/pull/31834), thanks @ghengeveld!\n- Core: Restore original clipboard after invoking `userEvent.setup()` - [#31730](https://github.com/storybookjs/storybook/pull/31730), thanks @ghengeveld!\n- Core: Serve dynamic favicon based on testing module status - [#31763](https://github.com/storybookjs/storybook/pull/31763), thanks @ghengeveld!\n- Core: Support array-based catch-all Next.js route segments in AppRouterProvider - [#31524](https://github.com/storybookjs/storybook/pull/31524), thanks @yatishgoel!\n- Core: Support container queries in addon panels - [#23261](https://github.com/storybookjs/storybook/pull/23261), thanks @neil-morrison44!\n- Core: Various fixes - [#31870](https://github.com/storybookjs/storybook/pull/31870), thanks @ghengeveld!\n- Deps: Extend `vite` peerDependencies range to include `7.0.0` - [#31859](https://github.com/storybookjs/storybook/pull/31859), thanks @ghengeveld!\n- Deps: Update vite-plugin-babel to 1.3.2 to fix vite 7.0.0 peerDependency issue - [#31888](https://github.com/storybookjs/storybook/pull/31888), thanks @ghengeveld!\n- Docs: Prevent JSON tree control from swallowing keyboard events when not in focus - [#31841](https://github.com/storybookjs/storybook/pull/31841), thanks @takashi-kasajima!\n- Docs: Update `react-element-to-jsx-string` - [#31170](https://github.com/storybookjs/storybook/pull/31170), thanks @7rulnik!\n- Ember: Allow ember v5 as peer deps - [#25893](https://github.com/storybookjs/storybook/pull/25893), thanks @gossi!\n- Next.js-Vite: Support Next.js v15.4 - [#31828](https://github.com/storybookjs/storybook/pull/31828), thanks @valentinpalkovic!\n- Next.js: Add webpack alias to resolve Next.js package conflicts - [#31755](https://github.com/storybookjs/storybook/pull/31755), thanks @valentinpalkovic!\n- Next.js: Enhance Vite configuration with styled-jsx aliasing - [#31757](https://github.com/storybookjs/storybook/pull/31757), thanks @valentinpalkovic!\n- Next.js: upgrade sass-loader to 16.0.5 - [#31855](https://github.com/storybookjs/storybook/pull/31855), thanks @terrymun!\n- NextJs-Vite: Enable next/font loading when using next-vite - [#31906](https://github.com/storybookjs/storybook/pull/31906), thanks @k35o!\n- Nextjs-Vite: Use tsconfig paths plugin - [#31764](https://github.com/storybookjs/storybook/pull/31764), thanks @kasperpeulen!\n- Portable stories: Fix playwright CT to allow functions to be passed as props - [#31335](https://github.com/storybookjs/storybook/pull/31335), thanks @adamscybot!\n- React Native Web: Fix shift spread operator in react-native-web-vite presets - [#31804](https://github.com/storybookjs/storybook/pull/31804), thanks @xlecunff-pass!\n- React Native: Fix window event listeners that dont exist on rn - [#31780](https://github.com/storybookjs/storybook/pull/31780), thanks @dannyhw!\n- React: Bump @joshwooding/vite-plugin-react-docgen-typescript to 0.6.1 - [#31899](https://github.com/storybookjs/storybook/pull/31899), thanks @mrginglymus!\n- Telemetry: Fix prompting without checking isTTY - [#31781](https://github.com/storybookjs/storybook/pull/31781), thanks @Synar!\n- UI: Apply user updates for mobile navigation accessibility - [#31401](https://github.com/storybookjs/storybook/pull/31401), thanks @yatishgoel!\n- UI: Hide keyboard shortcuts entry from menu when shortcuts are disabled - [#23411](https://github.com/storybookjs/storybook/pull/23411), thanks @Spielboerg!\n- UI: Set color scheme to sync scrollbar color with user-selected theme - [#28666](https://github.com/storybookjs/storybook/pull/28666), thanks @elisezhg!\n- UI: Visual focus indicators (VFIs) aren't visible in high contrast mode (rebase) - [#31848](https://github.com/storybookjs/storybook/pull/31848), thanks @Sidnioulz!\n- Vite: Remove addon-themes and theming from optimized deps list - [#31833](https://github.com/storybookjs/storybook/pull/31833), thanks @ghengeveld!\n\n## 9.1.0-alpha.6\n\n- CLI: Fix package manager instantiation in empty directories - [#31743](https://github.com/storybookjs/storybook/pull/31743), thanks @yannbf!\n- CLI: Improve support for upgrading Storybook in monorepos - [#31557](https://github.com/storybookjs/storybook/pull/31557), thanks @yannbf!\n- CSF: Improve docs parameter types - [#31736](https://github.com/storybookjs/storybook/pull/31736), thanks @kasperpeulen!\n- Core: Delete shim addon packages - [#31728](https://github.com/storybookjs/storybook/pull/31728), thanks @ndelangen!\n\n## 9.1.0-alpha.5\n\n- Addon Themes: Define missing React dependencies - [#31688](https://github.com/storybookjs/storybook/pull/31688), thanks @ghengeveld!\n- Addon-vitest: Fix adding with `--skip-install` failing missing packageJson invariant - [#31720](https://github.com/storybookjs/storybook/pull/31720), thanks @JReinhold!\n- AddonDocs: Remove export of blocks - [#31724](https://github.com/storybookjs/storybook/pull/31724), thanks @ndelangen!\n- CSF: Only add preview annotations to definePreview in csf-factories automigration - [#31727](https://github.com/storybookjs/storybook/pull/31727), thanks @kasperpeulen!\n\n## 9.1.0-alpha.4\n\n- CSF Factories: Add parameters/globals types, `extend` API, portable stories - [#30601](https://github.com/storybookjs/storybook/pull/30601), thanks @kasperpeulen!\n\n## 9.1.0-alpha.3\n\n- Addon A11y: Briefly disable highlights while Axe is running - [#31621](https://github.com/storybookjs/storybook/pull/31621), thanks @ghengeveld!\n- Addon Docs: Fix SyntaxHighlighter \"Copy\" button by avoiding potentially mocked clipboard - [#31682](https://github.com/storybookjs/storybook/pull/31682), thanks @ghengeveld!\n- Addon Docs: Fix reference to global JSX namespace - [#31671](https://github.com/storybookjs/storybook/pull/31671), thanks @mrginglymus!\n- Addon Vitest: Fix path comparison on Windows - [#31630](https://github.com/storybookjs/storybook/pull/31630), thanks @valentinpalkovic!\n- Addon Vitest: Fix path comparison on Windows - [#31634](https://github.com/storybookjs/storybook/pull/31634), thanks @valentinpalkovic!\n- Angular: Improve Vite compatibility - [#31686](https://github.com/storybookjs/storybook/pull/31686), thanks @ndelangen!\n- Automigration: Enhance removeEssentials to convert options - [#31658](https://github.com/storybookjs/storybook/pull/31658), thanks @ndelangen!\n- CLI: Consider Storybook React Native packages in upgrade command - [#31645](https://github.com/storybookjs/storybook/pull/31645), thanks @yannbf!\n- CLI: Don't install addon-onboarding during minimal installs - [#31616](https://github.com/storybookjs/storybook/pull/31616), thanks @ghengeveld!\n- Next.js: Fix module transpilation - [#31501](https://github.com/storybookjs/storybook/pull/31501), thanks @valentinpalkovic!\n- Preview: Fix type issues - [#31537](https://github.com/storybookjs/storybook/pull/31537), thanks @mrginglymus!\n- Svelte: Fix source view always using `<wrapper ...>` - [#31639](https://github.com/storybookjs/storybook/pull/31639), thanks @JReinhold!\n- Telemetry: Fix `project.json` for getAbsolutePath - [#31510](https://github.com/storybookjs/storybook/pull/31510), thanks @ndelangen!\n- Telemetry: Improve error handling - [#31656](https://github.com/storybookjs/storybook/pull/31656), thanks @ndelangen!\n- Testing: Fix `toSatisfy`-matcher implementation - [#31664](https://github.com/storybookjs/storybook/pull/31664), thanks @ndelangen!\n\n## 9.1.0-alpha.2\n\n- Addon-Vitest: Properly merge configs - [#31629](https://github.com/storybookjs/storybook/pull/31629), thanks @valentinpalkovic!\n- Angular: Support v20 - [#31611](https://github.com/storybookjs/storybook/pull/31611), thanks @valentinpalkovic!\n- CLI: Respect --skip-install in postinstall scripts - [#31605](https://github.com/storybookjs/storybook/pull/31605), thanks @yannbf!\n- CLI: Update VTA version range for storybook init - [#31612](https://github.com/storybookjs/storybook/pull/31612), thanks @ghengeveld!\n- React Native Web: Include expo in babel transforms - [#31607](https://github.com/storybookjs/storybook/pull/31607), thanks @dannyhw!\n\n## 9.1.0-alpha.1\n\n- Angular: Include 20.x in version range - [#31602](https://github.com/storybookjs/storybook/pull/31602), thanks @shilman!\n- CLI: Update React Native init generator for v9 - [#31600](https://github.com/storybookjs/storybook/pull/31600), thanks @dannyhw!\n- Telemetry: Fix storybook version and add test run events - [#31473](https://github.com/storybookjs/storybook/pull/31473), thanks @tmeasday!\n\n## 9.1.0-alpha.0\n\n## 9.0.0-rc.5\n\n- Addon A11y: Improve selector automigration detection - [#31392](https://github.com/storybookjs/storybook/pull/31392), thanks @yannbf!\n- Addon Vitest: Support `vitest.projects.ts` file as workspace file during postinstall - [#31565](https://github.com/storybookjs/storybook/pull/31565), thanks @ghengeveld!\n- Addon-Vitest: Always clean coverage before (re)running - [#31540](https://github.com/storybookjs/storybook/pull/31540), thanks @JReinhold!\n- Automigration: Fix wrap require wrapper - [#31569](https://github.com/storybookjs/storybook/pull/31569), thanks @valentinpalkovic!\n- Controls: Remove empty state video link - [#31539](https://github.com/storybookjs/storybook/pull/31539), thanks @kylegach!\n- Presets: Use `.js` files when `.cjs` files are passed for entries that should be ESM - [#31556](https://github.com/storybookjs/storybook/pull/31556), thanks @JReinhold!\n- Pseudo States: Ignore escaped pseudo-class names - [#31515](https://github.com/storybookjs/storybook/pull/31515), thanks @sentience!\n\n## 9.0.0-rc.4\n\n- Addon Vitest: Improve handling multiple browser mode projects - [#31508](https://github.com/storybookjs/storybook/pull/31508), thanks @yannbf!\n- Addons: Add shim Storybook addons for previously removed addons - [#31520](https://github.com/storybookjs/storybook/pull/31520), thanks @valentinpalkovic!\n- React Native: Fix support for 9.0 - [#31518](https://github.com/storybookjs/storybook/pull/31518), thanks @JReinhold!\n\n## 9.0.0-rc.3\n\n- Addon Vitest: Ensure vitest exclusions are relative to the project root, not cwd - [#31514](https://github.com/storybookjs/storybook/pull/31514), thanks @mrginglymus!\n- Addon Vitest: Fix broken docs links - [#31445](https://github.com/storybookjs/storybook/pull/31445), thanks @kylegach!\n- Addon-vitest: Fix wrong test count in telemetry - [#31504](https://github.com/storybookjs/storybook/pull/31504), thanks @JReinhold!\n- ArgTypes: Always extract argTypes, even without `addon-docs` - [#31488](https://github.com/storybookjs/storybook/pull/31488), thanks @JReinhold!\n- CSF-Tools: Add support for existing node imports and improve import handling - [#31497](https://github.com/storybookjs/storybook/pull/31497), thanks @valentinpalkovic!\n- CSF: Fix handling of renamed story exports - [#31519](https://github.com/storybookjs/storybook/pull/31519), thanks @JReinhold!\n\n## 9.0.0-rc.2\n\n- Addon Docs: Simplify color parsing and color cycling logic - [#29840](https://github.com/storybookjs/storybook/pull/29840), thanks @leyvae!\n- Addon Vitest: Fix watch mode for new files - [#31156](https://github.com/storybookjs/storybook/pull/31156), thanks @valentinpalkovic!\n- CodePanel: Show originalSource code - [#31456](https://github.com/storybookjs/storybook/pull/31456), thanks @valentinpalkovic!\n- Core: Builder-manager disable metafile - [#31467](https://github.com/storybookjs/storybook/pull/31467), thanks @ndelangen!\n- Core: Remove duplicate notification dot on sidebar buttons on mobile - [#31485](https://github.com/storybookjs/storybook/pull/31485), thanks @ghengeveld!\n- Core: Set a minimum height/width for the targetable area of highlights - [#31486](https://github.com/storybookjs/storybook/pull/31486), thanks @ghengeveld!\n- Core: Support groups and info icon in highlight popover menu - [#31475](https://github.com/storybookjs/storybook/pull/31475), thanks @ghengeveld!\n- React Native Web: Fix expo router by setting JSX to automatic - [#31484](https://github.com/storybookjs/storybook/pull/31484), thanks @dannyhw!\n- React: Don't use Act wrapper in Storybook when rendering in docs - [#31483](https://github.com/storybookjs/storybook/pull/31483), thanks @kasperpeulen!\n- Test: Patch HTMLElement.prototype.focus method for settable focus in tests - [#31487](https://github.com/storybookjs/storybook/pull/31487), thanks @valentinpalkovic!\n\n## 9.0.0-rc.1\n\n- Addon Docs: Fix docs-content overflow with TOC - [#27167](https://github.com/storybookjs/storybook/pull/27167), thanks @njsokol!\n- Addon Vitest: Ignore mdx files as part of tests - [#31457](https://github.com/storybookjs/storybook/pull/31457), thanks @yannbf!\n- Core: Do not show 'Render story' step in interactions - [#31452](https://github.com/storybookjs/storybook/pull/31452), thanks @ghengeveld!\n- Dependencies: Update docgen - [#31465](https://github.com/storybookjs/storybook/pull/31465), thanks @ndelangen!\n- Source Loader: Remove package - [#31466](https://github.com/storybookjs/storybook/pull/31466), thanks @valentinpalkovic!\n- Vitest: Remove beforeAll in vitest.setup.ts in automigration - [#31460](https://github.com/storybookjs/storybook/pull/31460), thanks @kasperpeulen!\n\n## 9.0.0-rc.0\n\n- Addon A11y: Fix usage of axe-core in pnpm projects - [#31422](https://github.com/storybookjs/storybook/pull/31422), thanks @yannbf!\n- Addon A11y: Fix various issues and inconsistencies - [#31432](https://github.com/storybookjs/storybook/pull/31432), thanks @ghengeveld!\n- Addon Docs: Fix `layout: centered` in conjunction with `inline: false` - [#31430](https://github.com/storybookjs/storybook/pull/31430), thanks @ghengeveld!\n- Addon Docs: Fix iframe content width in centered layout - [#31320](https://github.com/storybookjs/storybook/pull/31320), thanks @Audie80!\n- Addon Docs: Improve TableOfContents HTML structure and a11y - [#31327](https://github.com/storybookjs/storybook/pull/31327), thanks @Sidnioulz!\n- Addon Vitest: Use its own cache directory - [#31439](https://github.com/storybookjs/storybook/pull/31439), thanks @yannbf!\n- Addon-Test: Automatically load before all - [#30584](https://github.com/storybookjs/storybook/pull/30584), thanks @kasperpeulen!\n- Addon-vitest: Support paths with spaces - [#31437](https://github.com/storybookjs/storybook/pull/31437), thanks @ndelangen!\n- Automigration: Correctly apply the wrap-require automigration in ESM modules - [#31420](https://github.com/storybookjs/storybook/pull/31420), thanks @valentinpalkovic!\n- Automigration: Improve renderer to framework automigration - [#31397](https://github.com/storybookjs/storybook/pull/31397), thanks @valentinpalkovic!\n- Automigrations: Fix installation of addon-docs - [#31399](https://github.com/storybookjs/storybook/pull/31399), thanks @valentinpalkovic!\n- Build: Update import paths and enable syntax minification - [#31390](https://github.com/storybookjs/storybook/pull/31390), thanks @ndelangen!\n- CLI: Improve package upgrade logic - [#31406](https://github.com/storybookjs/storybook/pull/31406), thanks @yannbf!\n- CLI: Remove `@latest` from `yarn create` commands - [#31458](https://github.com/storybookjs/storybook/pull/31458), thanks @ndelangen!\n- CLI: Tweak init prompt - [#31376](https://github.com/storybookjs/storybook/pull/31376), thanks @shilman!\n- Core / Addon A11y: Emit `STORY_HOT_UPDATED` and rerun A11y tests on HMR - [#31423](https://github.com/storybookjs/storybook/pull/31423), thanks @ghengeveld!\n- Core: Avoid pre-bundling of preview-api in manager entries - [#31385](https://github.com/storybookjs/storybook/pull/31385), thanks @valentinpalkovic!\n- Core: Improve unhandled error detection - [#31440](https://github.com/storybookjs/storybook/pull/31440), thanks @kasperpeulen!\n- Core: Remove maximum-scale=1 from viewport meta tag - [#31283](https://github.com/storybookjs/storybook/pull/31283), thanks @yatishgoel!\n- Core: Wait for animations before completing render cycle - [#31287](https://github.com/storybookjs/storybook/pull/31287), thanks @ghengeveld!\n- Hooks: Stabilize experimental afterEach hook - [#31438](https://github.com/storybookjs/storybook/pull/31438), thanks @valentinpalkovic!\n- Maintenance: Remove aliasses in builder configurations & scripts - [#31344](https://github.com/storybookjs/storybook/pull/31344), thanks @ndelangen!\n- Test: Make sure that lit arrays are not cloned - [#31435](https://github.com/storybookjs/storybook/pull/31435), thanks @kasperpeulen!\n\n## 9.0.0-beta.11\n\n- Addon A11y: Fix setup as part of storybook create - [#31403](https://github.com/storybookjs/storybook/pull/31403), thanks @yannbf!\n- Addon Docs: Reset error boundary when story changes to recover from erros - [#31242](https://github.com/storybookjs/storybook/pull/31242), thanks @yatishgoel!\n- Angular: Filter non-inputs from controls - [#30550](https://github.com/storybookjs/storybook/pull/30550), thanks @robertIsaac!\n- Backgrounds/Viewport: Fix resetting - [#31386](https://github.com/storybookjs/storybook/pull/31386), thanks @valentinpalkovic!\n- CLI: Detect correct storybook version on upgrade - [#31393](https://github.com/storybookjs/storybook/pull/31393), thanks @yannbf!\n- Core: Fix core annotations applied twice - [#31361](https://github.com/storybookjs/storybook/pull/31361), thanks @valentinpalkovic!\n- Core: Fix sidebar accessibility order for screen readers - [#31250](https://github.com/storybookjs/storybook/pull/31250), thanks @yatishgoel!\n- Eslint-plugin: Handle JSON5 format - [#31336](https://github.com/storybookjs/storybook/pull/31336), thanks @yatishgoel!\n- Indexer: Do not create autodocs entries unless addon-docs installed - [#31331](https://github.com/storybookjs/storybook/pull/31331), thanks @ndelangen!\n- Svelte: Install `latest` version of `@storybook/addon-svelte-csf` - [#31398](https://github.com/storybookjs/storybook/pull/31398), thanks @JReinhold!\n- Test: Allow generics in expect matchers - [#31395](https://github.com/storybookjs/storybook/pull/31395), thanks @yannbf!\n- Update react-router-dom to lowest React19 type-compatible version - [#31358](https://github.com/storybookjs/storybook/pull/31358), thanks @mrginglymus!\n- Viewport: Fix globals type - [#31374](https://github.com/storybookjs/storybook/pull/31374), thanks @flaval!\n\n## 9.0.0-beta.10\n\n- CLI: Improve CLI upgrade process for @latest and @next - [#31356](https://github.com/storybookjs/storybook/pull/31356), thanks @yannbf!\n- SvelteKit: Forward form events when mocking `enhance` - [#31360](https://github.com/storybookjs/storybook/pull/31360), thanks @JReinhold!\n\n## 9.0.0-beta.9\n\n- Addon A11y: Provide full report in a11y manual runs - [#31325](https://github.com/storybookjs/storybook/pull/31325), thanks @yannbf!\n- Angular: remove invalid defaults for start-storybook - [#31337](https://github.com/storybookjs/storybook/pull/31337), thanks @AgentEnder!\n- Automigration: Adjust addon-docs install condition - [#31343](https://github.com/storybookjs/storybook/pull/31343), thanks @valentinpalkovic!\n- Automigration: Migrate users to codePanel - [#31313](https://github.com/storybookjs/storybook/pull/31313), thanks @valentinpalkovic!\n- Automigration: Pass over flags when calling automigrations - [#31342](https://github.com/storybookjs/storybook/pull/31342), thanks @valentinpalkovic!\n- CLI: Enhance compatibility check: deprecated detection - [#31317](https://github.com/storybookjs/storybook/pull/31317), thanks @ndelangen!\n- Core: Support React Native environment without static class blocks - [#31282](https://github.com/storybookjs/storybook/pull/31282), thanks @JReinhold!\n\n## 9.0.0-beta.8\n\n- Addon-vitest: Remove internal log for `staticDir` - [#31340](https://github.com/storybookjs/storybook/pull/31340), thanks @JReinhold!\n- CLI: Add skip onboarding, recommended/minimal config - [#30930](https://github.com/storybookjs/storybook/pull/30930), thanks @shilman!\n- CLI: Supress npm notice update log messages - [#31334](https://github.com/storybookjs/storybook/pull/31334), thanks @yannbf!\n- CLI: Wrap object addon names in wrap-require migration - [#31285](https://github.com/storybookjs/storybook/pull/31285), thanks @yatishgoel!\n- Core: Bring back loading globals from global types in portable stories - [#31328](https://github.com/storybookjs/storybook/pull/31328), thanks @yannbf!\n- React Native Web: Update `react-native-web` - [#31324](https://github.com/storybookjs/storybook/pull/31324), thanks @ndelangen!\n- Svelte: Remove unused `svelte-preprocess` dependency - [#31332](https://github.com/storybookjs/storybook/pull/31332), thanks @JReinhold!\n\n## 9.0.0-beta.7\n\n- CLI: Fix get versions utility for NPM - [#29577](https://github.com/storybookjs/storybook/pull/29577), thanks @johnrcui!\n- Telemetry: Add Svelte CSF usage - [#31255](https://github.com/storybookjs/storybook/pull/31255), thanks @shilman!\n- Test: Remove legacy Vitest v2 code - [#31271](https://github.com/storybookjs/storybook/pull/31271), thanks @valentinpalkovic!\n- UI: Add options to hide sidebar and toolbar per story - [#29516](https://github.com/storybookjs/storybook/pull/29516), thanks @Sidnioulz!\n- Vite: Normalize preview annotation paths - [#31238](https://github.com/storybookjs/storybook/pull/31238), thanks @mrginglymus!\n\n## 9.0.0-beta.6\n\n- Automigration: Fix an issue when main.js addons have dynamic values - [#31273](https://github.com/storybookjs/storybook/pull/31273), thanks @valentinpalkovic!\n- Automigration: Respect config-dir option - [#31233](https://github.com/storybookjs/storybook/pull/31233), thanks @valentinpalkovic!\n- Core: Change require.resolve path for storybook/package.json - [#31230](https://github.com/storybookjs/storybook/pull/31230), thanks @valentinpalkovic!\n- Dependencies: Upgrades for security - [#31276](https://github.com/storybookjs/storybook/pull/31276), thanks @ndelangen!\n- Dependencies: Upgrades for security - [#31291](https://github.com/storybookjs/storybook/pull/31291), thanks @ndelangen!\n- Next.js: Remove deprecated compatibility files - [#31295](https://github.com/storybookjs/storybook/pull/31295), thanks @valentinpalkovic!\n- Svelte: Fix missing `ts-dedent` dependency - [#31289](https://github.com/storybookjs/storybook/pull/31289), thanks @JReinhold!\n\n## 9.0.0-beta.5\n\n- All packages: Remove unused dependencies - [#31227](https://github.com/storybookjs/storybook/pull/31227), thanks @webpro!\n- Autoblock: Fix link - [#31236](https://github.com/storybookjs/storybook/pull/31236), thanks @valentinpalkovic!\n- CLI: Update nx docs in Storybook detection error - [#31266](https://github.com/storybookjs/storybook/pull/31266), thanks @yannbf!\n- Core: Fix highlight conflicts - [#31204](https://github.com/storybookjs/storybook/pull/31204), thanks @ghengeveld!\n- Dependencies: Upgrades for security - [#31235](https://github.com/storybookjs/storybook/pull/31235), thanks @ndelangen!\n- Docs: Fix source code panel - [#31245](https://github.com/storybookjs/storybook/pull/31245), thanks @valentinpalkovic!\n- React Native Web: Add RNW to vitest supported frameworks - [#31253](https://github.com/storybookjs/storybook/pull/31253), thanks @dannyhw!\n- Svelte: Remove dependency on `sveltedoc-parser` - [#31246](https://github.com/storybookjs/storybook/pull/31246), thanks @JReinhold!\n- Test: Use @testing-library/dom as devDependency - [#31188](https://github.com/storybookjs/storybook/pull/31188), thanks @valentinpalkovic!\n\n## 9.0.0-beta.4\n\n- Highlights: Dont run highlights when the feature is disabled - [#31239](https://github.com/storybookjs/storybook/pull/31239), thanks @dannyhw!\n\n## 9.0.0-beta.3\n\n- Automigration: Remove `docs.autodocs` field - [#31203](https://github.com/storybookjs/storybook/pull/31203), thanks @ndelangen!\n- Core: Cleanup dependencies - [#31222](https://github.com/storybookjs/storybook/pull/31222), thanks @JReinhold!\n- Dependencies: Upgrade @types/estree package to version v1.0.6 - [#29477](https://github.com/storybookjs/storybook/pull/29477), thanks @hakshu25!\n- Vite-Builder: Handle undefined previewConfig - [#31216](https://github.com/storybookjs/storybook/pull/31216), thanks @valentinpalkovic!\n\n## 9.0.0-beta.2\n\n- Addon A11y: Use short titles and friendly summary messages in A11y report - [#31185](https://github.com/storybookjs/storybook/pull/31185), thanks @ghengeveld!\n- CLI: Add `storybook-static` to `.gitignore` on init - [#31201](https://github.com/storybookjs/storybook/pull/31201), thanks @JReinhold!\n- Core: Add preview navigator and `--preview-only` CLI flag - [#31102](https://github.com/storybookjs/storybook/pull/31102), thanks @JReinhold!\n- Core: Remove `uuid` package from core - [#31219](https://github.com/storybookjs/storybook/pull/31219), thanks @JReinhold!\n\n## 9.0.0-beta.1\n\n- Addon A11y: Only run checks in story mode - [#30976](https://github.com/storybookjs/storybook/pull/30976), thanks @kroeder!\n- ESLint: Fix flat config setup - [#31192](https://github.com/storybookjs/storybook/pull/31192), thanks @yannbf!\n\n## 9.0.0-beta.0\n\n- Addon-vitest: Fix coverage being disabled with Run All button - [#31074](https://github.com/storybookjs/storybook/pull/31074), thanks @JReinhold!\n\n## 9.0.0-alpha.21\n\n- Addon Controls: Fix loading state UI in addon panel - [#31168](https://github.com/storybookjs/storybook/pull/31168), thanks @iineineno03k!\n- Addon Pseudo States: Move package into monorepo - [#31123](https://github.com/storybookjs/storybook/pull/31123), thanks @ghengeveld!\n- Addon Vitest: Transform @storybook/nextjs imports to @storybook/nextjs-vite during init - [#31180](https://github.com/storybookjs/storybook/pull/31180), thanks @valentinpalkovic!\n- Addon-a11y: Replace `element` parameter with `context` - [#31036](https://github.com/storybookjs/storybook/pull/31036), thanks @JReinhold!\n- Addon-test: Fix watching non-story files, run all tests on preview change - [#31045](https://github.com/storybookjs/storybook/pull/31045), thanks @JReinhold!\n- Automigration: Always scan file system to substitute essential addons - [#31176](https://github.com/storybookjs/storybook/pull/31176), thanks @valentinpalkovic!\n- Cleanup: Remove obsolete dependency - [#31177](https://github.com/storybookjs/storybook/pull/31177), thanks @valentinpalkovic!\n- Core: Create `features` for addons moved into core - [#31146](https://github.com/storybookjs/storybook/pull/31146), thanks @ndelangen!\n- Core: Draw highlights on top of canvas and add various new features - [#30894](https://github.com/storybookjs/storybook/pull/30894), thanks @ghengeveld!\n- Core: Fix highlight `clickEvent` serialization and export public types - [#31179](https://github.com/storybookjs/storybook/pull/31179), thanks @ghengeveld!\n- Core: Fix highlighting zero-pixel elements and focus on single element - [#31183](https://github.com/storybookjs/storybook/pull/31183), thanks @ghengeveld!\n- Core: Increase compile targets for node & browsers - [#31139](https://github.com/storybookjs/storybook/pull/31139), thanks @JReinhold!\n- Init: Install framework stories instead of renderer stories - [#31160](https://github.com/storybookjs/storybook/pull/31160), thanks @valentinpalkovic!\n- Maintenance: Migrate eslint-storybook-plugin into the monorepo - [#31151](https://github.com/storybookjs/storybook/pull/31151), thanks @yannbf!\n- Nextjs Vite: Add runtime check for malformed postcss config - [#31184](https://github.com/storybookjs/storybook/pull/31184), thanks @valentinpalkovic!\n\n## 9.0.0-alpha.20\n\n- Addon Docs: Update telejson - [#31115](https://github.com/storybookjs/storybook/pull/31115), thanks @valentinpalkovic!\n- AddonVitest: Use framework package, not renderer - [#31133](https://github.com/storybookjs/storybook/pull/31133), thanks @ndelangen!\n- Automigration: Fix consolidated-imports with sub-paths - [#31135](https://github.com/storybookjs/storybook/pull/31135), thanks @ndelangen!\n- Core: Add highlight as public API - [#31134](https://github.com/storybookjs/storybook/pull/31134), thanks @valentinpalkovic!\n- Core: Rename local tests to interactions - [#31141](https://github.com/storybookjs/storybook/pull/31141), thanks @yannbf!\n- Dependencies: Update dependencies - [#31143](https://github.com/storybookjs/storybook/pull/31143), thanks @valentinpalkovic!\n- Interactions: Rename component test panel - [#31130](https://github.com/storybookjs/storybook/pull/31130), thanks @valentinpalkovic!\n- Migration: Improve glob question text - [#31118](https://github.com/storybookjs/storybook/pull/31118), thanks @ndelangen!\n- Refactor: Update panel IDs in vitest addon to use new constants - [#31132](https://github.com/storybookjs/storybook/pull/31132), thanks @ndelangen!\n- Save from Controls: Replace rendererPackage with frameworkPackage - [#31114](https://github.com/storybookjs/storybook/pull/31114), thanks @valentinpalkovic!\n\n## 9.0.0-alpha.19\n\n- CLI: Fix framework for preview imports - [#31101](https://github.com/storybookjs/storybook/pull/31101), thanks @valentinpalkovic!\n- Controls: Fix boxShadow on empty controls - [#27193](https://github.com/storybookjs/storybook/pull/27193), thanks @H0onnn!\n- Core: Fix favicon issue on dev server - [#30818](https://github.com/storybookjs/storybook/pull/30818), thanks @MuhdHishamP!\n- UI: Clear filters on run all and clear all statuses - [#31073](https://github.com/storybookjs/storybook/pull/31073), thanks @JReinhold!\n- UI: Don't include error state in sidebar context menu - [#31054](https://github.com/storybookjs/storybook/pull/31054), thanks @ghengeveld!\n\n## 9.0.0-alpha.18\n\n- Addon-vitest: Fix coverage when restarting Vitest due to config change - [#31069](https://github.com/storybookjs/storybook/pull/31069), thanks @JReinhold!\n- Automigration: Misc addon-essentials migration fixes - [#31072](https://github.com/storybookjs/storybook/pull/31072), thanks @valentinpalkovic!\n- Docs: Consolidate blocks into addon-docs - [#31097](https://github.com/storybookjs/storybook/pull/31097), thanks @ndelangen!\n\n## 9.0.0-alpha.17\n\n- Addon Test: Rename `@storybook/experimental-addon-test` to `@storybook/addon-vitest` - [#31014](https://github.com/storybookjs/storybook/pull/31014), thanks @valentinpalkovic!\n- Autoblock: Add autoblocker for addon-test - [#31068](https://github.com/storybookjs/storybook/pull/31068), thanks @valentinpalkovic!\n- Automigrations: Add logging - [#31066](https://github.com/storybookjs/storybook/pull/31066), thanks @valentinpalkovic!\n- Instrumenter: Fix `preview-api` import for react-native - [#31057](https://github.com/storybookjs/storybook/pull/31057), thanks @ndelangen!\n- Vite: Support Vite 6 and Docs - [#31061](https://github.com/storybookjs/storybook/pull/31061), thanks @valentinpalkovic!\n- Yarn: Update Yarn package command execution to use 'exec' - [#31065](https://github.com/storybookjs/storybook/pull/31065), thanks @valentinpalkovic!\n\n## 9.0.0-alpha.16\n\n- Automigration: Remove `@storybook/addon-essentials` proper - [#31015](https://github.com/storybookjs/storybook/pull/31015), thanks @ndelangen!\n- Core: Automatically expand testing module on unhandled error - [#31028](https://github.com/storybookjs/storybook/pull/31028), thanks @ghengeveld!\n- Core: Fix using dates in expect statements - [#28413](https://github.com/storybookjs/storybook/pull/28413), thanks @yann-combarnous!\n- Csf-Tools: Enhance setFieldNode logic to handle variable declarations - [#31056](https://github.com/storybookjs/storybook/pull/31056), thanks @valentinpalkovic!\n\n## 9.0.0-alpha.15\n\n- Addon A11y: Add `linkPath` to Axe results and use it in copy link action - [#31009](https://github.com/storybookjs/storybook/pull/31009), thanks @ghengeveld!\n- Addon-test: Exclude `storybook-static` from coverage reports - [#31005](https://github.com/storybookjs/storybook/pull/31005), thanks @JReinhold!\n- Addons: Remove @storybook/addon-storysource - [#31007](https://github.com/storybookjs/storybook/pull/31007), thanks @valentinpalkovic!\n- Automigration: Enhance import transformation to handle partial package matches - [#31033](https://github.com/storybookjs/storybook/pull/31033), thanks @valentinpalkovic!\n- Automigration: Ensure correct addition of missing dependencies - [#31023](https://github.com/storybookjs/storybook/pull/31023), thanks @valentinpalkovic!\n- Core: Show \"Render story\" event explicitly in Component Tests event trace - [#31027](https://github.com/storybookjs/storybook/pull/31027), thanks @ghengeveld!\n- Nextjs-Vite: Update vite-plugin-storybook-nextjs version and add optimizeDeps - [#31037](https://github.com/storybookjs/storybook/pull/31037), thanks @valentinpalkovic!\n- Node.js: Align Node.js version support - [#31041](https://github.com/storybookjs/storybook/pull/31041), thanks @valentinpalkovic!\n- Svelte-vite: Improve SvelteKit detection error - [#31038](https://github.com/storybookjs/storybook/pull/31038), thanks @JReinhold!\n- Vite: Add 'storybook/viewport' to INCLUDE_CANDIDATES in optimizeDeps.ts - [#31039](https://github.com/storybookjs/storybook/pull/31039), thanks @valentinpalkovic!\n\n## 9.0.0-alpha.14\n\n- Automigrations: Re-add renderer-to-framework and fix issue in monorepositories - [#31011](https://github.com/storybookjs/storybook/pull/31011), thanks @valentinpalkovic!\n- Dependencies: Upgrade `telejson` - [#30998](https://github.com/storybookjs/storybook/pull/30998), thanks @ndelangen!\n- Maintenance: Specify that Addon Test now requires Vitest 3.0 - [#30948](https://github.com/storybookjs/storybook/pull/30948), thanks @yannbf!\n- Remove: Addon mdx-gfm (`@storybook/addon-mdx-gfm`) - [#30996](https://github.com/storybookjs/storybook/pull/30996), thanks @ndelangen!\n- Source: Support async parameters.docs.source.transform - [#30426](https://github.com/storybookjs/storybook/pull/30426), thanks @valentinpalkovic!\n- Svelte: Drop Support for Svelte < 5 - [#30703](https://github.com/storybookjs/storybook/pull/30703), thanks @valentinpalkovic!\n\n## 9.0.0-alpha.13\n\n- Automigration: Add new Storybook addons to consolidated packages mapping - [#30993](https://github.com/storybookjs/storybook/pull/30993), thanks @valentinpalkovic!\n- Automigration: Update mapping for '@storybook/experimental-nextjs-vite' - [#30991](https://github.com/storybookjs/storybook/pull/30991), thanks @valentinpalkovic!\n- CLI: Only install Visual Test Addon if test feature is selected - [#30966](https://github.com/storybookjs/storybook/pull/30966), thanks @ghengeveld!\n- Core: Add error boundary to tabs to prevent addon errors breaking Storybook - [#30952](https://github.com/storybookjs/storybook/pull/30952), thanks @kasperpeulen!\n- Core: Remove deprecated parts of test provider API - [#30962](https://github.com/storybookjs/storybook/pull/30962), thanks @JReinhold!\n- Essentials: Move remaining addons into core - [#30924](https://github.com/storybookjs/storybook/pull/30924), thanks @ndelangen!\n- HTML Framework: Remove support for HTML Webpack 5 - [#30990](https://github.com/storybookjs/storybook/pull/30990), thanks @valentinpalkovic!\n- Next: Upgrade vite-plugin-storybook-nextjs for Next v14 compatibility - [#30997](https://github.com/storybookjs/storybook/pull/30997), thanks @kasperpeulen!\n- Svelte: Exclude `node_modules` from docgen - [#30981](https://github.com/storybookjs/storybook/pull/30981), thanks @JReinhold!\n- Test: Make sure that expect has no different behavior after instrumentation - [#30935](https://github.com/storybookjs/storybook/pull/30935), thanks @kasperpeulen!\n- Web Components: Remove Webpack 5 support - [#30988](https://github.com/storybookjs/storybook/pull/30988), thanks @valentinpalkovic!\n\n## 9.0.0-alpha.12\n\n- Addon-A11y: Various improvements - [#30774](https://github.com/storybookjs/storybook/pull/30774), thanks @ghengeveld!\n- Addon-Test: Migrate to new test provider API, drop Vitest 2 support - [#30875](https://github.com/storybookjs/storybook/pull/30875), thanks @JReinhold!\n- Angular: Fix zone.js support for Angular libraries - [#30941](https://github.com/storybookjs/storybook/pull/30941), thanks @valentinpalkovic!\n- Core: Fix flaky unit tests related to stores - [#30963](https://github.com/storybookjs/storybook/pull/30963), thanks @JReinhold!\n- Core: Fix telemetry error on Storybok UI - [#30953](https://github.com/storybookjs/storybook/pull/30953), thanks @yannbf!\n- Maintenance: Drop tooling support - [#30940](https://github.com/storybookjs/storybook/pull/30940), thanks @valentinpalkovic!\n- Maintenance: Remove deprecated APIs - [#30926](https://github.com/storybookjs/storybook/pull/30926), thanks @valentinpalkovic!\n- Maintenance: Remove obsolete automigrations - [#30945](https://github.com/storybookjs/storybook/pull/30945), thanks @valentinpalkovic!\n- Manager: Fix `Uncaught ReferenceError: global is not defined` - [#30970](https://github.com/storybookjs/storybook/pull/30970), thanks @JReinhold!\n- Next.js-Vite: Stabilize @storybook/experimental-nextjs-vite - [#30956](https://github.com/storybookjs/storybook/pull/30956), thanks @valentinpalkovic!\n- Preact: Remove support for Preact Webpack 5 - [#30957](https://github.com/storybookjs/storybook/pull/30957), thanks @valentinpalkovic!\n- UI: Visual tweaks to badges and improved layout for a11y panel - [#30955](https://github.com/storybookjs/storybook/pull/30955), thanks @ghengeveld!\n- Vue3: Remove support for Webpack 5 - [#30958](https://github.com/storybookjs/storybook/pull/30958), thanks @valentinpalkovic!\n\n## 9.0.0-alpha.11\n\n- Addons: Move @storybook/addon-interactions into core - [#30916](https://github.com/storybookjs/storybook/pull/30916), thanks @valentinpalkovic!\n- Nextjs: Fix styled-jsx optimize vite warnings - [#30932](https://github.com/storybookjs/storybook/pull/30932), thanks @kasperpeulen!\n- React: Fix actImplementation is not a function - [#30929](https://github.com/storybookjs/storybook/pull/30929), thanks @kasperpeulen!\n\n## 9.0.0-alpha.10\n\n- Addon-Essentials: Remove addon-docs - [#30856](https://github.com/storybookjs/storybook/pull/30856), thanks @ndelangen!\n- Addon-docs: Fix non-string handling in Stories block - [#30913](https://github.com/storybookjs/storybook/pull/30913), thanks @JamesIves!\n- Controls: Embed addon-controls into the core - [#30864](https://github.com/storybookjs/storybook/pull/30864), thanks @ndelangen!\n- Core: Prebundle jsdoc-type-pratt-parser again - [#30923](https://github.com/storybookjs/storybook/pull/30923), thanks @kasperpeulen!\n- React: Ensure render functions and decorators are react components - [#30869](https://github.com/storybookjs/storybook/pull/30869), thanks @kasperpeulen!\n- Toolbars: Embed addon-toolbars into the core - [#30871](https://github.com/storybookjs/storybook/pull/30871), thanks @ndelangen!\n- Viewport: Embed addon-viewport in the core - [#30909](https://github.com/storybookjs/storybook/pull/30909), thanks @ndelangen!\n\n## 9.0.0-alpha.9\n\n- Addons: Update the Viewport and Background Addon - [#30841](https://github.com/storybookjs/storybook/pull/30841), thanks @ndelangen!\n- CLI: Add React Native `.rnstorybook` CLI automigration - [#30882](https://github.com/storybookjs/storybook/pull/30882), thanks @shilman!\n- CLI: Add detection for the storybook package being behind any other core packages - [#30861](https://github.com/storybookjs/storybook/pull/30861), thanks @kasperpeulen!\n- CLI: Make sure that the add commands logs all output to the console - [#30865](https://github.com/storybookjs/storybook/pull/30865), thanks @kasperpeulen!\n- Next: Fix react aliases in next vite plugin - [#30914](https://github.com/storybookjs/storybook/pull/30914), thanks @kasperpeulen!\n- Test: Handle non-configurable properties in instrumenter for expect.toThrow - [#30876](https://github.com/storybookjs/storybook/pull/30876), thanks @kasperpeulen!\n\n## 9.0.0-alpha.8\n\n- Angular: Export all files in Angular package.json - [#30849](https://github.com/storybookjs/storybook/pull/30849), thanks @kasperpeulen!\n- CLI: Don't add packageManager entry to package.json automatically - [#30855](https://github.com/storybookjs/storybook/pull/30855), thanks @kasperpeulen!\n- React: Allow portable stories to be used in SSR - [#30847](https://github.com/storybookjs/storybook/pull/30847), thanks @kasperpeulen!\n- Revert \"Svelte: Adjust Svelte typings to include Svelte 5 function components\" - [#30851](https://github.com/storybookjs/storybook/pull/30851), thanks @kasperpeulen!\n- Svelte: Adjust Svelte typings to include Svelte 5 function components - [#30812](https://github.com/storybookjs/storybook/pull/30812), thanks @dummdidumm!\n- Svelte: Adjust Svelte typings to include Svelte 5 function components - [#30852](https://github.com/storybookjs/storybook/pull/30852), thanks @kasperpeulen!\n- Telemetry: Make sure that telemetry doesn't fail on init - [#30857](https://github.com/storybookjs/storybook/pull/30857), thanks @kasperpeulen!\n- Vite: Update HMR filter to target specific story file types - [#30845](https://github.com/storybookjs/storybook/pull/30845), thanks @kasperpeulen!\n\n## 9.0.0-alpha.7\n\n- Core: New Test Provider Store - [#30828](https://github.com/storybookjs/storybook/pull/30828), thanks @JReinhold!\n- React-Native: Fix `userEvent.setup()` errors in jest - [#30833](https://github.com/storybookjs/storybook/pull/30833), thanks @dannyhw!\n- React-Native: Fix `userEvent.setup()` errors outside browser context - [#30831](https://github.com/storybookjs/storybook/pull/30831), thanks @dannyhw!\n- Test: Upgrade to vitest 3 - [#30840](https://github.com/storybookjs/storybook/pull/30840), thanks @kasperpeulen!\n- UI: Fix status missing from sidebar - [#30830](https://github.com/storybookjs/storybook/pull/30830), thanks @JReinhold!\n\n## 9.0.0-alpha.6\n\n- Core: New Status Store - [#30764](https://github.com/storybookjs/storybook/pull/30764), thanks @JReinhold!\n- Core: Remove `util`, `browser-assert`, `process` deps - [#30805](https://github.com/storybookjs/storybook/pull/30805), thanks @ndelangen!\n- Core: Testing Module UI improvements - [#30773](https://github.com/storybookjs/storybook/pull/30773), thanks @ghengeveld!\n- React-Native-Web: Fix errors in CLI template stories - [#30821](https://github.com/storybookjs/storybook/pull/30821), thanks @dannyhw!\n- React-Native: Fix `__STORYBOOK_ADDON_INTERACTIONS_INSTRUMENTER_STATE__` access - [#30820](https://github.com/storybookjs/storybook/pull/30820), thanks @dannyhw!\n- React-Native: Update config directory to .rnstorybook - [#30819](https://github.com/storybookjs/storybook/pull/30819), thanks @dannyhw!\n\n## 9.0.0-alpha.5\n\n- Angular: Make sure that polyfills are loaded before the storybook is loaded - [#30811](https://github.com/storybookjs/storybook/pull/30811), thanks @kasperpeulen!\n- CSF: Fix CSF subcomponent type - [#30729](https://github.com/storybookjs/storybook/pull/30729), thanks @filipemelo2002!\n- Ember: Fix `ember-template-compiler` import for ember 6+ - [#30682](https://github.com/storybookjs/storybook/pull/30682), thanks @leoeuclids!\n- React: Remove react import in template files - [#30757](https://github.com/storybookjs/storybook/pull/30757), thanks @kasperpeulen!\n\n## 9.0.0-alpha.4\n\n- Automigrate: Prefer framework import - [#30785](https://github.com/storybookjs/storybook/pull/30785), thanks @ndelangen!\n- Blocks: IconGallery improvement - [#30743](https://github.com/storybookjs/storybook/pull/30743), thanks @leeovictor!\n- CLI: Do not install renderer package on `init` - [#30799](https://github.com/storybookjs/storybook/pull/30799), thanks @ndelangen!\n- Core: Move @storybook/addon-actions into storybook - [#30765](https://github.com/storybookjs/storybook/pull/30765), thanks @valentinpalkovic!\n\n## 9.0.0-alpha.3\n\n- Addon A11y: Promote @storybook/global to full dependency - [#30723](https://github.com/storybookjs/storybook/pull/30723), thanks @mrginglymus!\n- Addon Test: Improve unhandled error messages - [#30755](https://github.com/storybookjs/storybook/pull/30755), thanks @yannbf!\n- Angular: Add @angular-devkit/build-angular to default installed pacakages in angular - [#30790](https://github.com/storybookjs/storybook/pull/30790), thanks @kasperpeulen!\n- Automigrate: Disable `missingStorybookDependencies` for 9.0 - [#30769](https://github.com/storybookjs/storybook/pull/30769), thanks @ndelangen!\n- CLI: Fix test install in RNW projects - [#30786](https://github.com/storybookjs/storybook/pull/30786), thanks @shilman!\n- Core: Re-Export renderers from frameworks - [#30771](https://github.com/storybookjs/storybook/pull/30771), thanks @ndelangen!\n- Core: Replace 'min' instead of 'm' in printDuration - [#30668](https://github.com/storybookjs/storybook/pull/30668), thanks @wlewis-formative!\n- Migration: Add auto-automigration for merged packages - [#30753](https://github.com/storybookjs/storybook/pull/30753), thanks @ndelangen!\n- Next.js: Upgrade image-size to 2.0 - [#30741](https://github.com/storybookjs/storybook/pull/30741), thanks @valentinpalkovic!\n- Next.js: Use latest version when init in empty directory - [#30659](https://github.com/storybookjs/storybook/pull/30659), thanks @valentinpalkovic!\n- Svelte: Fix Vite crashing on virtual module imports - [#26838](https://github.com/storybookjs/storybook/pull/26838), thanks @rChaoz!\n- Svelte: Fix automatic argTypes inference coming up empty with `svelte2tsx@0.7.35` - [#30784](https://github.com/storybookjs/storybook/pull/30784), thanks @JReinhold!\n- Svelte: Pin svelte2tsx to solve argType regression - [#30783](https://github.com/storybookjs/storybook/pull/30783), thanks @kasperpeulen!\n- Test: Move `@storybook/test` into `storybook/test` - [#30742](https://github.com/storybookjs/storybook/pull/30742), thanks @valentinpalkovic!\n- Universal Store: Don't use `crypto.randomUUID` - [#30781](https://github.com/storybookjs/storybook/pull/30781), thanks @JReinhold!\n\n## 9.0.0-alpha.2\n\n- AutoBlocker: Add major version upgrade blocker - [#30714](https://github.com/storybookjs/storybook/pull/30714), thanks @ndelangen!\n- CLI: Add index command / API - [#30071](https://github.com/storybookjs/storybook/pull/30071), thanks @shilman!\n- CSF Factories: Align addon-essentials import with other addons - [#30716](https://github.com/storybookjs/storybook/pull/30716), thanks @kasperpeulen!\n- Core: Move @storybook/instrumenter into core - [#30740](https://github.com/storybookjs/storybook/pull/30740), thanks @valentinpalkovic!\n- Core: Support TS3.8+ again - [#30700](https://github.com/storybookjs/storybook/pull/30700), thanks @kasperpeulen!\n- Maintenance: Merge `@storybook/core` with `storybook` - [#30168](https://github.com/storybookjs/storybook/pull/30168), thanks @ndelangen!\n- Maintenance: Remove deprecated packages - [#30690](https://github.com/storybookjs/storybook/pull/30690), thanks @ndelangen!\n- Manager: Add Content-Type to prevent reliance on content type sniffing, fixing Cloud IDEs - [#30606](https://github.com/storybookjs/storybook/pull/30606), thanks @GCHQDeveloper548!\n- Next: Support Next 15.2 - [#30702](https://github.com/storybookjs/storybook/pull/30702), thanks @kasperpeulen!\n- React: Export returntype of ReactMeta#story - [#30580](https://github.com/storybookjs/storybook/pull/30580), thanks @mrginglymus!\n- Revert \"CLI: Don't initially select Documentation and Testing features\" - [#30694](https://github.com/storybookjs/storybook/pull/30694), thanks @shilman!\n- Test Addon: Stabilize and remove experimental status - [#30727](https://github.com/storybookjs/storybook/pull/30727), thanks @valentinpalkovic!\n- Typescript: Drop Typescript < 4.9 support - [#30736](https://github.com/storybookjs/storybook/pull/30736), thanks @valentinpalkovic!\n- Vite: Improve handling of preview annotations - [#28798](https://github.com/storybookjs/storybook/pull/28798), thanks @tobiasdiez!\n- Vite: Include `node_modules` in stats file - [#30711](https://github.com/storybookjs/storybook/pull/30711), thanks @JReinhold!\n\n## 9.0.0-alpha.1\n\n- CLI: Install prereleases of `@chromatic-com/storybook` - [#30662](https://github.com/storybookjs/storybook/pull/30662), thanks @JReinhold!\n- CSF: Only export definePreview from the framework - [#30676](https://github.com/storybookjs/storybook/pull/30676), thanks @kasperpeulen!\n- Codemod: Only remove types when they are unused - [#30644](https://github.com/storybookjs/storybook/pull/30644), thanks @yannbf!\n- Dependencies: Upgrades - [#30515](https://github.com/storybookjs/storybook/pull/30515), thanks @ndelangen!\n\n## 9.0.0-alpha.0\n\n## 8.6.0-beta.10\n\n- Codemod: Always get real path of files - [#30650](https://github.com/storybookjs/storybook/pull/30650), thanks @yannbf!\n- Core: Don't set process.env.NODE_ENV and process.env.DEV - [#30651](https://github.com/storybookjs/storybook/pull/30651), thanks @valentinpalkovic!\n\n## 8.6.0-beta.9\n\n- CLI: Prompt users for RN vs RNW on init - [#30635](https://github.com/storybookjs/storybook/pull/30635), thanks @shilman!\n- Codemod: Handle addon essentials differently in csf factories - [#30649](https://github.com/storybookjs/storybook/pull/30649), thanks @yannbf!\n- Codemod: Migrate meta.args to meta.input.args in csf factories - [#30641](https://github.com/storybookjs/storybook/pull/30641), thanks @yannbf!\n- Codemod: Use real path from symbolic links - [#30642](https://github.com/storybookjs/storybook/pull/30642), thanks @yannbf!\n- Core: Always place cache dir inside `node_modules` - [#30643](https://github.com/storybookjs/storybook/pull/30643), thanks @ndelangen!\n- Core: Fix addon essentials preview preset - [#30647](https://github.com/storybookjs/storybook/pull/30647), thanks @yannbf!\n- Core: Fix extracting import path when it's not a core addon - [#30640](https://github.com/storybookjs/storybook/pull/30640), thanks @yannbf!\n\n## 8.6.0-beta.8\n\n- Addon-Test: Fix console error in build mode - [#30625](https://github.com/storybookjs/storybook/pull/30625), thanks @JReinhold!\n- Manager: Fix panel reactivity - [#30638](https://github.com/storybookjs/storybook/pull/30638), thanks @valentinpalkovic!\n\n## 8.6.0-beta.7\n\n- Angular: Fix @angular/platform-browser/animations never available - [#30618](https://github.com/storybookjs/storybook/pull/30618), thanks @valentinpalkovic!\n- Angular: Fix @angular/platform-browser/animations never available - [#30619](https://github.com/storybookjs/storybook/pull/30619), thanks @valentinpalkovic!\n- CLI: Fix peer dep issues for npm users during upgrade - [#30616](https://github.com/storybookjs/storybook/pull/30616), thanks @valentinpalkovic!\n\n## 8.6.0-beta.6\n\n- CLI: Fix printing of selected features - [#30605](https://github.com/storybookjs/storybook/pull/30605), thanks @ghengeveld!\n- CLI: Remove Storybook dependencies before adding re-adding them - [#30600](https://github.com/storybookjs/storybook/pull/30600), thanks @valentinpalkovic!\n\n## 8.6.0-beta.5\n\n- Addon-Test: Make sure that only one global portable story config is ever loaded - [#30582](https://github.com/storybookjs/storybook/pull/30582), thanks @kasperpeulen!\n- Angular: Support v19.2 when @angular/animations is not installed - [#30611](https://github.com/storybookjs/storybook/pull/30611), thanks @valentinpalkovic!\n- Builder-Vite: Fix runtime and iframe 404 on first load - [#30567](https://github.com/storybookjs/storybook/pull/30567), thanks @valentinpalkovic!\n- CLI: Don't initially select Documentation and Testing features - [#30599](https://github.com/storybookjs/storybook/pull/30599), thanks @ghengeveld!\n- CLI: Make telemetry data an object - [#30581](https://github.com/storybookjs/storybook/pull/30581), thanks @ndelangen!\n- Core: Support `esbuild@^0.25` - [#30574](https://github.com/storybookjs/storybook/pull/30574), thanks @JReinhold!\n- Test addon: Only update `vitest.config.ts` with workspaces, otherwise create `vitest.workspace.ts` - [#30583](https://github.com/storybookjs/storybook/pull/30583), thanks @ghengeveld!\n\n## 8.6.0-beta.4\n\n- Addon-Test: Add telemetry data for Focused Tests - [#30568](https://github.com/storybookjs/storybook/pull/30568), thanks @JReinhold!\n- Core: Allow empty render functions in CSF factories - [#30565](https://github.com/storybookjs/storybook/pull/30565), thanks @kasperpeulen!\n- Core: Fix undeclared internal dependencies - [#30566](https://github.com/storybookjs/storybook/pull/30566), thanks @kasperpeulen!\n\n## 8.6.0-beta.3\n\n- Addon-A11y: Fix preset loading when loaded via getAbsolutePath - [#30563](https://github.com/storybookjs/storybook/pull/30563), thanks @valentinpalkovic!\n- Essentials: Fix `addon-essentials` not working when used with `getAbsolutePath` - [#30557](https://github.com/storybookjs/storybook/pull/30557), thanks @JReinhold!\n- Vite: Fix not stripping all HMR boundaries - [#30562](https://github.com/storybookjs/storybook/pull/30562), thanks @JReinhold!\n\n## 8.6.0-beta.2\n\n- CLI: Reimplement features prompt logic to handle `--yes` and fix `--features` - [#30534](https://github.com/storybookjs/storybook/pull/30534), thanks @ghengeveld!\n- Telemetry: Don't count example stories towards CSF feature stats - [#30561](https://github.com/storybookjs/storybook/pull/30561), thanks @shilman!\n\n## 8.6.0-beta.1\n\n- Builder-Vite: Fix defaulting to allowing all hosts - [#30523](https://github.com/storybookjs/storybook/pull/30523), thanks @JReinhold!\n- React: Fix incorrect import in preview.ts - [#30542](https://github.com/storybookjs/storybook/pull/30542), thanks @mrginglymus!\n- Tags: Add story/meta usage telemetry - [#30555](https://github.com/storybookjs/storybook/pull/30555), thanks @shilman!\n- UI: Fix tags sort for browser back-compat - [#30547](https://github.com/storybookjs/storybook/pull/30547), thanks @shilman!\n\n## 8.6.0-beta.0\n\n- Addon Test: Fix printing Date object in MethodCall for test/interactions log - [#30507](https://github.com/storybookjs/storybook/pull/30507), thanks @ghengeveld!\n- Addon A11y: Introduce parameters.a11y.test - [#30516](https://github.com/storybookjs/storybook/pull/30516), thanks @valentinpalkovic!\n- Addon-Docs: Change URL hash when TOC item is clicked, and fix TOC loading bugs - [#30130](https://github.com/storybookjs/storybook/pull/30130), thanks @Sidnioulz!\n- Addon-Test: Fix config and watch mode inconsistencies - [#30491](https://github.com/storybookjs/storybook/pull/30491), thanks @JReinhold!\n- Addon-docs: Consider custom code snippet in story code panel and update styles - [#30179](https://github.com/storybookjs/storybook/pull/30179), thanks @larsrickert!\n- Builder-Vite: Fix resolve id warning - [#30511](https://github.com/storybookjs/storybook/pull/30511), thanks @valentinpalkovic!\n- Builder-Vite: Fix Turbosnap - [#30522](https://github.com/storybookjs/storybook/pull/30522), thanks @valentinpalkovic!\n- CLI: Add \"features\" question & auto-install test addon & improve test-addon compatibility - [#30202](https://github.com/storybookjs/storybook/pull/30202), thanks @ndelangen!\n- CSF: Add support for CSF factories - [#30197](https://github.com/storybookjs/storybook/pull/30197), thanks @kasperpeulen!\n- Cleanup: Remove unused constants in viewport addon - [#30479](https://github.com/storybookjs/storybook/pull/30479), thanks @Guria!\n- Svelte: Fix conflicting variable names and support for `+page.svelte` files - [#30369](https://github.com/storybookjs/storybook/pull/30369), thanks @xeho91!\n\n## 8.6.0-alpha.5\n\n- Core: Add `UniversalStore` API to sync state/events between multiple environments - [#30445](https://github.com/storybookjs/storybook/pull/30445), thanks @JReinhold!\n- Core: Fix statically serving single files and multiple dirs on the same endpoint - [#30467](https://github.com/storybookjs/storybook/pull/30467), thanks @JReinhold!\n- Core: Move CSF to monorepo - [#30488](https://github.com/storybookjs/storybook/pull/30488), thanks @kasperpeulen!\n- React: Update react-docgen-typescript to fix CI hanging issues - [#30422](https://github.com/storybookjs/storybook/pull/30422), thanks @yannbf!\n\n## 8.6.0-alpha.4\n\n- Addon A11y: Make Vitest Axe optional - [#30442](https://github.com/storybookjs/storybook/pull/30442), thanks @valentinpalkovic!\n- Builder-Vite: Fix allowedHosts handling for custom hosts - [#30432](https://github.com/storybookjs/storybook/pull/30432), thanks @JSMike!\n- Vite: Fix add component UI invalidation - [#30438](https://github.com/storybookjs/storybook/pull/30438), thanks @shilman!\n\n## 8.6.0-alpha.3\n\n- Core: Fix invalid Websocket termination - [#30408](https://github.com/storybookjs/storybook/pull/30408), thanks @valentinpalkovic!\n- Core: Improve type compatibility with React 19 - [#30031](https://github.com/storybookjs/storybook/pull/30031), thanks @mrginglymus!\n- Preview: Add `globals` to `extract()` - [#30415](https://github.com/storybookjs/storybook/pull/30415), thanks @ndelangen!\n\n## 8.6.0-alpha.2\n\n- Addon Test: Support Vitest 3 browser.test.instances field - [#30309](https://github.com/storybookjs/storybook/pull/30309), thanks @valentinpalkovic!\n- Bun: Add support for text lock file - [#30160](https://github.com/storybookjs/storybook/pull/30160), thanks @Arctomachine!\n- CLI: Corrected Next.js createScript for pnpm. - [#30304](https://github.com/storybookjs/storybook/pull/30304), thanks @zhyd1997!\n\n## 8.6.0-alpha.1\n\n- Addon Test: Replace `interaction test` -> `component test` - [#30333](https://github.com/storybookjs/storybook/pull/30333), thanks @kylegach!\n- Angular: Fix accent character issue - [#30276](https://github.com/storybookjs/storybook/pull/30276), thanks @valentinpalkovic!\n- Angular: Support experimental zoneless mode - [#28657](https://github.com/storybookjs/storybook/pull/28657), thanks @anedomansky!\n- CLI: Use correct storybook internals import in automigration - [#30290](https://github.com/storybookjs/storybook/pull/30290), thanks @yannbf!\n- Core: Add connection timeout notification - [#30288](https://github.com/storybookjs/storybook/pull/30288), thanks @valentinpalkovic!\n- Csf Tools: Allow ConfigFile to create more import syntaxes - [#30204](https://github.com/storybookjs/storybook/pull/30204), thanks @yannbf!\n- Manager: Escape single quotes in dynamic import paths in wrapManagerEntries function - [#30278](https://github.com/storybookjs/storybook/pull/30278), thanks @valentinpalkovic!\n- RNW-Vite: Support requires for images/fonts - [#30305](https://github.com/storybookjs/storybook/pull/30305), thanks @dannyhw!\n\n## 8.6.0-alpha.0\n\n## 8.5.0-beta.11\n\n- CLI: Update a11y-test comment with experimental caveat - [#30258](https://github.com/storybookjs/storybook/pull/30258), thanks @shilman!\n- Manager API: Fix infinite render-loop caused by `useSharedState` - [#30259](https://github.com/storybookjs/storybook/pull/30259), thanks @JReinhold!\n\n## 8.5.0-beta.10\n\n- Addon A11y: Adjust default behaviour when using with experimental-addon-test - [#30162](https://github.com/storybookjs/storybook/pull/30162), thanks @valentinpalkovic!\n- Addon A11y: Change default element selector - [#30253](https://github.com/storybookjs/storybook/pull/30253), thanks @valentinpalkovic!\n- Addon Docs: Make new code panel opt in - [#30248](https://github.com/storybookjs/storybook/pull/30248), thanks @shilman!\n- Addon Test: Fix generated path to `vitest.setup.js` - [#30233](https://github.com/storybookjs/storybook/pull/30233), thanks @JReinhold!\n\n## 8.5.0-beta.9\n\n- Addon Test: Add prerequisite check for MSW - [#30193](https://github.com/storybookjs/storybook/pull/30193), thanks @yannbf!\n- Addon Test: Improve support for mono-repos - [#30216](https://github.com/storybookjs/storybook/pull/30216), thanks @valentinpalkovic!\n- Vitest: Add plugins from `viteFinal` - [#30105](https://github.com/storybookjs/storybook/pull/30105), thanks @JReinhold!\n\n## 8.5.0-beta.8\n\n- Automigrations: Skip vite config file migration for react native web - [#30190](https://github.com/storybookjs/storybook/pull/30190), thanks @dannyhw!\n- Maintenance: Move `@types/node` to `devDeps` consistently - [#30163](https://github.com/storybookjs/storybook/pull/30163), thanks @ndelangen!\n- Manager: Optimize getPanels function with memoization - [#30192](https://github.com/storybookjs/storybook/pull/30192), thanks @valentinpalkovic!\n- RNW-Vite: Fix reanimated support with babel plugin for node_modules - [#30188](https://github.com/storybookjs/storybook/pull/30188), thanks @dannyhw!\n- React: Force act running always in sequence - [#30191](https://github.com/storybookjs/storybook/pull/30191), thanks @valentinpalkovic!\n- UI: Fix overlapping shadow of testing module on scrollbar - [#30132](https://github.com/storybookjs/storybook/pull/30132), thanks @valentinpalkovic!\n- Vite: Fix wrong import paths when configDir is not in project root - [#30206](https://github.com/storybookjs/storybook/pull/30206), thanks @JReinhold!\n\n## 8.5.0-beta.7\n\n- Addon Test: Context menu updates - [#30107](https://github.com/storybookjs/storybook/pull/30107), thanks @ghengeveld!\n- Storysource Addon: Fix source-loader prettier imports - [#29669](https://github.com/storybookjs/storybook/pull/29669), thanks @slax57!\n- Vue: Extend sourceDecorator to support v-bind and nested keys in slots - [#28787](https://github.com/storybookjs/storybook/pull/28787), thanks @JoCa96!\n\n## 8.5.0-beta.6\n\n- Addon Test: Always use installed version of vitest - [#30134](https://github.com/storybookjs/storybook/pull/30134), thanks @kasperpeulen!\n- Addon Test: Fix documentation links - [#30128](https://github.com/storybookjs/storybook/pull/30128), thanks @yannbf!\n- Addon Test: Use correct vitest config file path - [#30135](https://github.com/storybookjs/storybook/pull/30135), thanks @kasperpeulen!\n- Automigration: Improve addon-a11y-addon-test - [#30127](https://github.com/storybookjs/storybook/pull/30127), thanks @valentinpalkovic!\n\n## 8.5.0-beta.5\n\n- Addon Test: Only reset story count on file change when watch mode is enabled - [#30121](https://github.com/storybookjs/storybook/pull/30121), thanks @ghengeveld!\n- Build: Revert Downgrade to esbuild 0.24.0 - [#30120](https://github.com/storybookjs/storybook/pull/30120), thanks @yannbf!\n- Core: Fix `ERR_PACKAGE_PATH_NOT_EXPORTED` in `@storybook/node-logger` - [#30093](https://github.com/storybookjs/storybook/pull/30093), thanks @JReinhold!\n- React: Use Act wrapper in Storybook for component rendering - [#30037](https://github.com/storybookjs/storybook/pull/30037), thanks @valentinpalkovic!\n- Vite: Add extra entries to `optimizeDeps` - [#30117](https://github.com/storybookjs/storybook/pull/30117), thanks @ndelangen!\n\n## 8.5.0-beta.4\n\n- Addon Themes: Deprecate useThemeParameters - [#30111](https://github.com/storybookjs/storybook/pull/30111), thanks @yannbf!\n- Build: Downgrade to esbuild 0.24.0 - [#30116](https://github.com/storybookjs/storybook/pull/30116), thanks @yannbf!\n- CLI: Re-Add Nuxt support - [#28607](https://github.com/storybookjs/storybook/pull/28607), thanks @valentinpalkovic!\n- Core: Prevent infinite rerendering caused by comparison by reference - [#30081](https://github.com/storybookjs/storybook/pull/30081), thanks @ghengeveld!\n\n## 8.5.0-beta.3\n\n- Addon A11y: Fix skipped status handling in Testing Module - [#30077](https://github.com/storybookjs/storybook/pull/30077), thanks @valentinpalkovic!\n- Core: Float context menu button on top of story titles in sidebar - [#30080](https://github.com/storybookjs/storybook/pull/30080), thanks @ghengeveld!\n- Onboarding: Replace `react-confetti` with `@neoconfetti/react` - [#30098](https://github.com/storybookjs/storybook/pull/30098), thanks @ndelangen!\n\n## 8.5.0-beta.2\n\n- Addon Test: Clear coverage data when starting or watching - [#30072](https://github.com/storybookjs/storybook/pull/30072), thanks @ghengeveld!\n- Addon Test: Improve error message on missing coverage package - [#30088](https://github.com/storybookjs/storybook/pull/30088), thanks @JReinhold!\n- UI: Fix test provider event handling on startup - [#30083](https://github.com/storybookjs/storybook/pull/30083), thanks @ghengeveld!\n- UI: Keep failing stories in the sidebar, disregarding filters - [#30086](https://github.com/storybookjs/storybook/pull/30086), thanks @JReinhold!\n\n## 8.5.0-beta.1\n\n- Addon A11y: Add conditional rendering for a11y violation number in Testing Module - [#30073](https://github.com/storybookjs/storybook/pull/30073), thanks @valentinpalkovic!\n- Addon A11y: Remove warnings API - [#30049](https://github.com/storybookjs/storybook/pull/30049), thanks @kasperpeulen!\n- Addon A11y: Show errors of axe properly - [#30050](https://github.com/storybookjs/storybook/pull/30050), thanks @kasperpeulen!\n- Addon Test: Fix printing null% for coverage - [#30061](https://github.com/storybookjs/storybook/pull/30061), thanks @ghengeveld!\n- Telemetry: Add metadata distinguishing \"apps\" from \"design systems\" - [#30070](https://github.com/storybookjs/storybook/pull/30070), thanks @tmeasday!\n\n## 8.5.0-beta.0\n\n- Automigration: Improve setup file transformation and version range handling for a11y migration - [#30060](https://github.com/storybookjs/storybook/pull/30060), thanks @valentinpalkovic!\n- Next.js: Support v15.1.1 - [#30068](https://github.com/storybookjs/storybook/pull/30068), thanks @valentinpalkovic!\n\n## 8.5.0-alpha.22\n\n- Addon Docs: Dynamically import rehype - [#29544](https://github.com/storybookjs/storybook/pull/29544), thanks @valentinpalkovic!\n- Addon Test: Fix duplicate `test.include` patterns - [#30029](https://github.com/storybookjs/storybook/pull/30029), thanks @JReinhold!\n- Addon Test: Fix environment variable for Vitest Storybook integration - [#30054](https://github.com/storybookjs/storybook/pull/30054), thanks @valentinpalkovic!\n- Addon Test: Use local storybook binary instead - [#30021](https://github.com/storybookjs/storybook/pull/30021), thanks @kasperpeulen!\n- Addon Test: Wait for 2 seconds before showing result mismatch warning - [#30002](https://github.com/storybookjs/storybook/pull/30002), thanks @ghengeveld!\n- Angular: Support statsJson in angular schemas - [#29233](https://github.com/storybookjs/storybook/pull/29233), thanks @yannbf!\n- Core: Fix `scrollIntoView` behavior and reimplement testing module time rendering - [#30044](https://github.com/storybookjs/storybook/pull/30044), thanks @ghengeveld!\n- Docs: Add code snippet to addons panel - [#29253](https://github.com/storybookjs/storybook/pull/29253), thanks @larsrickert!\n- Next.js: Fix webpack fsCache not working - [#29654](https://github.com/storybookjs/storybook/pull/29654), thanks @sentience!\n- Nextjs-Vite: Add TS docgen support - [#29824](https://github.com/storybookjs/storybook/pull/29824), thanks @yannbf!\n- Nextjs-Vite: Fix docgen types in main config - [#30042](https://github.com/storybookjs/storybook/pull/30042), thanks @yannbf!\n- React: Fix RSC compatibility with addon-themes and hooks - [#26243](https://github.com/storybookjs/storybook/pull/26243), thanks @shilman!\n- UI: Fix controls and parameters on tag-filtered stories - [#30038](https://github.com/storybookjs/storybook/pull/30038), thanks @shilman!\n\n## 8.5.0-alpha.21\n\n- Addon A11y: Add typesVersions support for TypeScript definitions in a11y package - [#30005](https://github.com/storybookjs/storybook/pull/30005), thanks @valentinpalkovic!\n- Addon A11y: Refactor environment variable handling for Vitest integration - [#30022](https://github.com/storybookjs/storybook/pull/30022), thanks @valentinpalkovic!\n- Addon A11y: Run the a11y automigration on postInstall - [#30004](https://github.com/storybookjs/storybook/pull/30004), thanks @kasperpeulen!\n- Addon A11y: Update accessibility status handling in TestProviderRender - [#30027](https://github.com/storybookjs/storybook/pull/30027), thanks @valentinpalkovic!\n- Addon Onboarding: Prebundle react-confetti - [#29996](https://github.com/storybookjs/storybook/pull/29996), thanks @yannbf!\n- Addon Test: Correctly stop Storybook when Vitest closes - [#30012](https://github.com/storybookjs/storybook/pull/30012), thanks @JReinhold!\n- Addon Test: Show sub test provider toggle state in main testing module - [#30019](https://github.com/storybookjs/storybook/pull/30019), thanks @ghengeveld!\n- Addon Test: Wrap sub-paths exported with `require.resolve` - [#30026](https://github.com/storybookjs/storybook/pull/30026), thanks @ndelangen!\n- Core: Fix bundling of React - [#30003](https://github.com/storybookjs/storybook/pull/30003), thanks @yannbf!\n\n## 8.5.0-alpha.20\n\n- Addon Test: Add `@vitest/coverage-v8` during postinstall if no coverage reporter is installed - [#29993](https://github.com/storybookjs/storybook/pull/29993), thanks @ghengeveld!\n- Addon Test: Add support for previewHead - [#29808](https://github.com/storybookjs/storybook/pull/29808), thanks @ndelangen!\n- Addon Test: Always run Vitest in watch mode internally - [#29749](https://github.com/storybookjs/storybook/pull/29749), thanks @JReinhold!\n- Addon Test: Filter out falsy test results in TestProviderRender - [#30001](https://github.com/storybookjs/storybook/pull/30001), thanks @valentinpalkovic!\n- Addon Test: Handle undefined storyId - [#29998](https://github.com/storybookjs/storybook/pull/29998), thanks @ghengeveld!\n- Addon Test: Make component tests status row link to the story's tests panel - [#29992](https://github.com/storybookjs/storybook/pull/29992), thanks @ghengeveld!\n- Addon Test: Merge viteFinal config into vitest config - [#29806](https://github.com/storybookjs/storybook/pull/29806), thanks @ndelangen!\n- Addon Test: Prompt switch to `experimental-nextjs-vite` - [#29814](https://github.com/storybookjs/storybook/pull/29814), thanks @ndelangen!\n- Addon Test: Use ProgressSpinner for stop button in Testing Module - [#29997](https://github.com/storybookjs/storybook/pull/29997), thanks @ghengeveld!\n\n## 8.5.0-alpha.19\n\n- Addon A11y: Create a11y test provider and revamp a11y addon - [#29643](https://github.com/storybookjs/storybook/pull/29643), thanks @valentinpalkovic!\n- Addon Test: Fix indexing behavior - [#29836](https://github.com/storybookjs/storybook/pull/29836), thanks @yannbf!\n- Addon Test: Fix run request while booting or restarting Vitest - [#29829](https://github.com/storybookjs/storybook/pull/29829), thanks @ghengeveld!\n- Addon Test: Serve `staticDirs` with Vitest - [#29811](https://github.com/storybookjs/storybook/pull/29811), thanks @ghengeveld!\n- RNW-Vite: Add tsconfig path aliases support - [#29953](https://github.com/storybookjs/storybook/pull/29953), thanks @shilman!\n- RNW-Vite: Fix flow plugin including too many things - [#29952](https://github.com/storybookjs/storybook/pull/29952), thanks @dannyhw!\n\n## 8.5.0-alpha.18\n\n- Addon Test: Clarify message when `vitest` detects missing deps - [#29763](https://github.com/storybookjs/storybook/pull/29763), thanks @ndelangen!\n- Addon Test: Refactor test addon to include stories automatically - [#29367](https://github.com/storybookjs/storybook/pull/29367), thanks @yannbf!\n- Addon Test: Replace `glob` with `tinyglobby` - [#29817](https://github.com/storybookjs/storybook/pull/29817), thanks @ghengeveld!\n- Addon Test: Support Storybook environment variables in Vitest - [#29792](https://github.com/storybookjs/storybook/pull/29792), thanks @ghengeveld!\n- Composition: Hide contextMenu on composed storybooks - [#29803](https://github.com/storybookjs/storybook/pull/29803), thanks @ndelangen!\n- Vue: Properly resolve Vite plugin - [#29795](https://github.com/storybookjs/storybook/pull/29795), thanks @tobiasdiez!\n\n## 8.5.0-alpha.17\n\n- CLI: Fix new-frameworks automigration - [#29804](https://github.com/storybookjs/storybook/pull/29804), thanks @yannbf!\n- ReactVite: Add `@storybook/test` as optional peer dependency - [#29754](https://github.com/storybookjs/storybook/pull/29754), thanks @yannbf!\n- Vite: Fix preview runtime import - [#29802](https://github.com/storybookjs/storybook/pull/29802), thanks @yannbf!\n\n## 8.5.0-alpha.16\n\n- Core: Avoid getting stuck in locked state - [#29768](https://github.com/storybookjs/storybook/pull/29768), thanks @ghengeveld!\n- Core: Evaluate main config when checking 'whats new' notifications - [#29622](https://github.com/storybookjs/storybook/pull/29622), thanks @yannbf!\n- Vite: Don't prefix story import with `@fs` - [#28941](https://github.com/storybookjs/storybook/pull/28941), thanks @tobiasdiez!\n- Vite: Import preview runtime as ordinary module - [#29172](https://github.com/storybookjs/storybook/pull/29172), thanks @tobiasdiez!\n\n## 8.5.0-alpha.15\n\n- Addon Test: Context menu UI - [#29727](https://github.com/storybookjs/storybook/pull/29727), thanks @ghengeveld!\n- Addon Test: Fix error reporting for `vitest` crashes - [#29751](https://github.com/storybookjs/storybook/pull/29751), thanks @ndelangen!\n- Addon Test: Remove a11y placeholder - [#29769](https://github.com/storybookjs/storybook/pull/29769), thanks @JReinhold!\n- Core / Addon Test: Support intercepting and modifying internal test provider state updates - [#29680](https://github.com/storybookjs/storybook/pull/29680), thanks @ghengeveld!\n- Core: Disable SidebarContextMenu in static builds - [#29743](https://github.com/storybookjs/storybook/pull/29743), thanks @ndelangen!\n- Telemetry: Improve anonymous id calculation - [#29736](https://github.com/storybookjs/storybook/pull/29736), thanks @tmeasday!\n\n## 8.5.0-alpha.14\n\n- RNW-Vite: Add built-in Flow support - [#29756](https://github.com/storybookjs/storybook/pull/29756), thanks @dannyhw!\n- Test: Add coverage feature - [#29713](https://github.com/storybookjs/storybook/pull/29713), thanks @ndelangen!\n\n## 8.5.0-alpha.13\n\n- Portable stories: Support multiple annotation notations from preview - [#29733](https://github.com/storybookjs/storybook/pull/29733), thanks @yannbf!\n- React: Upgrade react-docgen-typescript to support Vite 6 - [#29724](https://github.com/storybookjs/storybook/pull/29724), thanks @yannbf!\n\n## 8.5.0-alpha.12\n\n- Core / Addon Test: Add config UI to Testing Module - [#29708](https://github.com/storybookjs/storybook/pull/29708), thanks @ghengeveld!\n- Manager: Add tags property to GroupEntry objects - [#29672](https://github.com/storybookjs/storybook/pull/29672), thanks @Sidnioulz!\n- Svelte: Support `@sveltejs/vite-plugin-svelte` v5 - [#29731](https://github.com/storybookjs/storybook/pull/29731), thanks @JReinhold!\n- Toolbars: Suppress deprecation warning when using dynamic icons - [#29545](https://github.com/storybookjs/storybook/pull/29545), thanks @ValeraS!\n\n## 8.5.0-alpha.11\n\n- Core + Addon Test: Refactor test API and fix total test count - [#29656](https://github.com/storybookjs/storybook/pull/29656), thanks @ghengeveld!\n- Core: Emit deprecated `TESTING_MODULE_RUN_ALL_REQUEST` for backward compatibility - [#29711](https://github.com/storybookjs/storybook/pull/29711), thanks @ghengeveld!\n- Frameworks: Add Vite 6 support - [#29710](https://github.com/storybookjs/storybook/pull/29710), thanks @yannbf!\n- TestAddon: Refactor UI & add config options - [#29662](https://github.com/storybookjs/storybook/pull/29662), thanks @ndelangen!\n- Vue: Fix `vue-component-meta` docgen HMR not working - [#29518](https://github.com/storybookjs/storybook/pull/29518), thanks @IonianPlayboy!\n\n## 8.5.0-alpha.10\n\n- Addon Test: Use pathe for better windows support - [#29676](https://github.com/storybookjs/storybook/pull/29676), thanks @yannbf!\n- Angular: Default to standalone components in Angular v19 - [#29677](https://github.com/storybookjs/storybook/pull/29677), thanks @ingowagner!\n\n## 8.5.0-alpha.9\n\n- Angular: Support v19 - [#29659](https://github.com/storybookjs/storybook/pull/29659), thanks @leosvelperez!\n- Manager: Fix size regression - [#29660](https://github.com/storybookjs/storybook/pull/29660), thanks @JReinhold!\n- Nextjs-Vite: Add Next.js 15 support - [#29640](https://github.com/storybookjs/storybook/pull/29640), thanks @yannbf!\n\n## 8.5.0-alpha.8\n\n- UI: Sidebar context menu addon API - [#29557](https://github.com/storybookjs/storybook/pull/29557), thanks @ndelangen!\n\n## 8.5.0-alpha.7\n\n- CLI: Disable corepack auto pin behavior - [#29627](https://github.com/storybookjs/storybook/pull/29627), thanks @yannbf!\n- RNW-Vite: Integrate with experimental-addon-test - [#29645](https://github.com/storybookjs/storybook/pull/29645), thanks @shilman!\n\n## 8.5.0-alpha.6\n\n- CLI: Fix qwik init - [#29632](https://github.com/storybookjs/storybook/pull/29632), thanks @shilman!\n- React Native Web: Add framework, CLI integration, sandboxes - [#29520](https://github.com/storybookjs/storybook/pull/29520), thanks @shilman!\n\n## 8.5.0-alpha.5\n\n- Addon Test: Only optimize react deps if applicable in vitest-plugin - [#29617](https://github.com/storybookjs/storybook/pull/29617), thanks @yannbf!\n- Addon Test: Optimize internal dependencies - [#29595](https://github.com/storybookjs/storybook/pull/29595), thanks @yannbf!\n- CLI: Fix init help for `storybook` command - [#29480](https://github.com/storybookjs/storybook/pull/29480), thanks @toothlessdev!\n- Composition: Fix composed story search - [#29453](https://github.com/storybookjs/storybook/pull/29453), thanks @jsingh0026!\n\n## 8.5.0-alpha.4\n\n- Next.js: Add support for Next 15 - [#29587](https://github.com/storybookjs/storybook/pull/29587), thanks @yannbf!\n- UI: Add Yarn to About Section - [#29225](https://github.com/storybookjs/storybook/pull/29225), thanks @grantwforsythe!\n\n## 8.5.0-alpha.3\n\n- Addon Test: Fix post-install logic for Next.js Vite framework support - [#29524](https://github.com/storybookjs/storybook/pull/29524), thanks @valentinpalkovic!\n- Core: Prevent clipping box shadow on file search modal - [#29523](https://github.com/storybookjs/storybook/pull/29523), thanks @ghengeveld!\n\n## 8.5.0-alpha.2\n\n- Addon Test: Only render the TestingModule component in development mode - [#29501](https://github.com/storybookjs/storybook/pull/29501), thanks @yannbf!\n- CLI: Fix Solid init by installing `@storybook/test` - [#29514](https://github.com/storybookjs/storybook/pull/29514), thanks @shilman!\n- Core: Add bun support with npm fallback - [#29267](https://github.com/storybookjs/storybook/pull/29267), thanks @stephenjason89!\n- Core: Shim CJS-only globals in ESM output - [#29157](https://github.com/storybookjs/storybook/pull/29157), thanks @valentinpalkovic!\n- Next.js: Fix bundled react and react-dom in monorepos - [#29444](https://github.com/storybookjs/storybook/pull/29444), thanks @sentience!\n- Next.js: Upgrade sass-loader from ^13.2.0 to ^14.2.1 - [#29264](https://github.com/storybookjs/storybook/pull/29264), thanks @HoncharenkoZhenya!\n- UI: Add support for groups to `TooltipLinkList` and use it in main menu - [#29507](https://github.com/storybookjs/storybook/pull/29507), thanks @ghengeveld!\n\n## 8.5.0-alpha.1\n\n- Core: Relax peer dep constraint of shim packages - [#29503](https://github.com/storybookjs/storybook/pull/29503), thanks @kasperpeulen!\n\n## 8.5.0-alpha.0\n\n## 8.4.0-beta.5\n\n- Addon Test: Improve unsupported vitest message - [#29486](https://github.com/storybookjs/storybook/pull/29486), thanks @valentinpalkovic!\n- Core: Fix race condition during empty folder init - [#29490](https://github.com/storybookjs/storybook/pull/29490), thanks @valentinpalkovic!\n\n## 8.4.0-beta.4\n\n- Addon Test: Improve Error Handling - [#29476](https://github.com/storybookjs/storybook/pull/29476), thanks @valentinpalkovic!\n- Addon Test: Improve postinstall script - [#29479](https://github.com/storybookjs/storybook/pull/29479), thanks @yannbf!\n- Addon Test: Throttle Vitest progress updates more heavily - [#29482](https://github.com/storybookjs/storybook/pull/29482), thanks @ghengeveld!\n- CLI: Refactor NPMProxy error parsing logic - [#29459](https://github.com/storybookjs/storybook/pull/29459), thanks @yannbf!\n- Core: Track test provider state in sessionStorage - [#29450](https://github.com/storybookjs/storybook/pull/29450), thanks @ghengeveld!\n- Dependencies: Upgrade VTA to v3.2.0 to resolve peerDep conflict - [#29461](https://github.com/storybookjs/storybook/pull/29461), thanks @ghengeveld!\n\n## 8.4.0-beta.3\n\n- Addon Test: Only register testing module in Vite projects - [#29472](https://github.com/storybookjs/storybook/pull/29472), thanks @yannbf!\n\n## 8.4.0-beta.2\n\n- Addon Test: Adjust file exports to be ESM/CJS compatible - [#29471](https://github.com/storybookjs/storybook/pull/29471), thanks @valentinpalkovic!\n- Core: Show tooltip on filter toggles to clarify their purpose - [#29447](https://github.com/storybookjs/storybook/pull/29447), thanks @ghengeveld!\n- Webpack: Fix export 'act' (imported as 'React4') was not found in 'react' errors in webpack - [#29235](https://github.com/storybookjs/storybook/pull/29235), thanks @kasperpeulen!\n\n## 8.4.0-beta.1\n\n- Addon Test: Error when addon interactions exists - [#29434](https://github.com/storybookjs/storybook/pull/29434), thanks @valentinpalkovic!\n- Addon Test: Escape XML when converting ANSI to HTML in test errors - [#29446](https://github.com/storybookjs/storybook/pull/29446), thanks @ghengeveld!\n- Addon Test: Fix hiding stacktrace for assertion errors in test panel - [#29458](https://github.com/storybookjs/storybook/pull/29458), thanks @ghengeveld!\n- CLI: Fix `yarn` detection - [#29448](https://github.com/storybookjs/storybook/pull/29448), thanks @ndelangen!\n- Core: Close story status menu when selecting an item - [#29455](https://github.com/storybookjs/storybook/pull/29455), thanks @ghengeveld!\n- Core: Open 'Component tests' addon panel when clicking a story status - [#29456](https://github.com/storybookjs/storybook/pull/29456), thanks @ghengeveld!\n- Core: Show checkmark icon in story status dropdown and update status label for component tests - [#29451](https://github.com/storybookjs/storybook/pull/29451), thanks @ghengeveld!\n- Dependencies: Upgrade VTA to v3.1.0 - [#29449](https://github.com/storybookjs/storybook/pull/29449), thanks @ghengeveld!\n- Maintenance: Fix broken and outdated documentation links - [#29412](https://github.com/storybookjs/storybook/pull/29412), thanks @jonniebigodes!\n\n## 8.4.0-beta.0\n\n- Core: Add unified UI Testing Module - [#29241](https://github.com/storybookjs/storybook/pull/29241), thanks @yannbf!\n- Svelte: Improve argTypes inference with `svelte2tsx` - support runes - [#29423](https://github.com/storybookjs/storybook/pull/29423), thanks @JReinhold!\n\n## 8.4.0-alpha.8\n\n- Addon-Test: Support for `@vitest/browser` v2.1.2 - [#29407](https://github.com/storybookjs/storybook/pull/29407), thanks @strozw!\n- ConfigFile: Fix `export { X }` parsing - [#29344](https://github.com/storybookjs/storybook/pull/29344), thanks @vctqs1!\n- Core: Fix building Storybook deleting project root files - [#29371](https://github.com/storybookjs/storybook/pull/29371), thanks @JReinhold!\n- Interactions: Escape xml of interactions errors - [#29414](https://github.com/storybookjs/storybook/pull/29414), thanks @kasperpeulen!\n- Svelte: Add v5 stories to CLI templates - [#29382](https://github.com/storybookjs/storybook/pull/29382), thanks @JReinhold!\n- Test: Remove unused `util` dependency - [#29310](https://github.com/storybookjs/storybook/pull/29310), thanks @JReinhold!\n- UI: Fix RefIndicator to use CheckIcon instead of string - [#29209](https://github.com/storybookjs/storybook/pull/29209), thanks @JSMike!\n- UI: Simple tag filtering - [#29333](https://github.com/storybookjs/storybook/pull/29333), thanks @shilman!\n\n## 8.4.0-alpha.7\n\n- CLI: Install Svelte CSF v5 in Svelte5 projects - [#29323](https://github.com/storybookjs/storybook/pull/29323), thanks @shilman!\n- Manager: Add tags property to ComponentEntry objects - [#29343](https://github.com/storybookjs/storybook/pull/29343), thanks @Sidnioulz!\n\n## 8.4.0-alpha.6\n\n- Addon-docs, blocks: Prebundle dependencies - [#29301](https://github.com/storybookjs/storybook/pull/29301), thanks @JReinhold!\n- React: Prebundle all of `renderers/react`'s dependencies - [#29298](https://github.com/storybookjs/storybook/pull/29298), thanks @ndelangen!\n- Vite: Cleanup and prebundle dependencies - [#29302](https://github.com/storybookjs/storybook/pull/29302), thanks @JReinhold!\n\n## 8.4.0-alpha.5\n\n- Core: Migrate from `express` to `polka` - [#29230](https://github.com/storybookjs/storybook/pull/29230), thanks @43081j!\n- Core: Remove dependence on `file-system-cache` - [#29256](https://github.com/storybookjs/storybook/pull/29256), thanks @ndelangen!\n\n## 8.4.0-alpha.4\n\n- Blocks: Prebundle `es-toolkit` - [#29259](https://github.com/storybookjs/storybook/pull/29259), thanks @JReinhold!\n- CLI: Update the React Native init to include v8 dependencies - [#29273](https://github.com/storybookjs/storybook/pull/29273), thanks @dannyhw!\n- Core: Upgrade `esbuild`, broadening version range - [#29254](https://github.com/storybookjs/storybook/pull/29254), thanks @ndelangen!\n- Vitest plugin: Fix renamed export stories - [#29250](https://github.com/storybookjs/storybook/pull/29250), thanks @shilman!\n\n## 8.4.0-alpha.3\n\n- CLI: Migrate from `chalk` to `picocolors` - [#28262](https://github.com/storybookjs/storybook/pull/28262), thanks @43081j!\n- Core: Migrate from `qs` to `picoquery` - [#28315](https://github.com/storybookjs/storybook/pull/28315), thanks @43081j!\n- UI: Brand image css class conflict causes image to resize on hot reloads - [#29129](https://github.com/storybookjs/storybook/pull/29129), thanks @ShreySinha02!\n\n## 8.4.0-alpha.2\n\n- CLI: Don't add `@storybook/addon-links` by default - [#29177](https://github.com/storybookjs/storybook/pull/29177), thanks @tobiasdiez!\n- Core: Make `prettier` an optional peer dependency - [#29223](https://github.com/storybookjs/storybook/pull/29223), thanks @JReinhold!\n- Core: Remove `handlebars` usage - [#29208](https://github.com/storybookjs/storybook/pull/29208), thanks @ndelangen!\n- Core: Replace `lodash` with `es-toolkit` - [#28981](https://github.com/storybookjs/storybook/pull/28981), thanks @ndelangen!\n- UI: Use production-mode `react` in manager - [#29197](https://github.com/storybookjs/storybook/pull/29197), thanks @ndelangen!\n\n## 8.4.0-alpha.1\n\n- Addon Test: Support story name as test description - [#29147](https://github.com/storybookjs/storybook/pull/29147), thanks @InfiniteXyy!\n- Addon-Interactions: Use ansi-to-html for colored test errors - [#29110](https://github.com/storybookjs/storybook/pull/29110), thanks @kasperpeulen!\n- Angular: Fix sourceDecorator to apply excludeDecorators flag - [#29069](https://github.com/storybookjs/storybook/pull/29069), thanks @JSMike!\n- Builder-vite: Replace .at() call with [] in codegen - [#29048](https://github.com/storybookjs/storybook/pull/29048), thanks @Chudesnov!\n- CLI: Ensure `.gitignore` updated via CLI ends with a newline - [#29124](https://github.com/storybookjs/storybook/pull/29124), thanks @3w36zj6!\n- CLI: Fix skip-install for stable latest releases - [#29133](https://github.com/storybookjs/storybook/pull/29133), thanks @valentinpalkovic!\n- CLI: Show constraints in error when getting depndencies - [#29187](https://github.com/storybookjs/storybook/pull/29187), thanks @andrasczeh!\n- Core: Do not add packageManager field to package.json during `storybook dev` - [#29152](https://github.com/storybookjs/storybook/pull/29152), thanks @valentinpalkovic!\n- Core: Do not prebundle better-opn - [#29137](https://github.com/storybookjs/storybook/pull/29137), thanks @valentinpalkovic!\n- Core: Do not prebundle jsdoc-type-pratt-parser - [#29134](https://github.com/storybookjs/storybook/pull/29134), thanks @valentinpalkovic!\n- Core: Replace `fs-extra` with the native APIs - [#29126](https://github.com/storybookjs/storybook/pull/29126), thanks @ziebam!\n- Next.js: Upgrade sass-loader from ^12 to ^13 - [#29040](https://github.com/storybookjs/storybook/pull/29040), thanks @HoncharenkoZhenya!\n- React-Vite: Downgrade react-docgen-typescript plugin - [#29184](https://github.com/storybookjs/storybook/pull/29184), thanks @shilman!\n- UI: Fix composed storybook TooltipLinkList bug where href isn't passed forward - [#29175](https://github.com/storybookjs/storybook/pull/29175), thanks @JSMike!\n- Viewport-addon: Add InitialViewportKeys type to viewport addon - [#29182](https://github.com/storybookjs/storybook/pull/29182), thanks @hyeongrok7874!\n- Vite: Add jsdoc-type-pratt-parser to `optimizeDeps` - [#29179](https://github.com/storybookjs/storybook/pull/29179), thanks @tobiasdiez!\n\n## 8.4.0-alpha.0\n\n## 8.3.0-beta.5\n\n- Portable Stories: Improve Handling of React Updates and Errors - [#29044](https://github.com/storybookjs/storybook/pull/29044), thanks @valentinpalkovic!\n- Vite: Fix missing source map warning - [#28984](https://github.com/storybookjs/storybook/pull/28984), thanks @valentinpalkovic!\n- Vue: Add missing prop controls when using `vue-component-meta` docgen plugin - [#28760](https://github.com/storybookjs/storybook/pull/28760), thanks @larsrickert!\n\n## 8.3.0-beta.4\n\n- Test: Rename vitest plugin entrypoint - [#29067](https://github.com/storybookjs/storybook/pull/29067), thanks @yannbf!\n- UI: Fix sidebar not wrapping - [#29055](https://github.com/storybookjs/storybook/pull/29055), thanks @JReinhold!\n\n## 8.3.0-beta.3\n\n- Addon Test: Improve messages and post install script handling - [#29036](https://github.com/storybookjs/storybook/pull/29036), thanks @yannbf!\n- Next.js-Vite: Fix vite plugin exports - [#29046](https://github.com/storybookjs/storybook/pull/29046), thanks @valentinpalkovic!\n- Next.js: Update dependencies - [#29052](https://github.com/storybookjs/storybook/pull/29052), thanks @valentinpalkovic!\n- UI: Fix conditional hooks usage in sidebar - [#28979](https://github.com/storybookjs/storybook/pull/28979), thanks @JReinhold!\n\n## 8.3.0-beta.2\n\n- Addon Vitest: Fix indentation of 'vitePluginNext' in generated Vitest config file - [#29011](https://github.com/storybookjs/storybook/pull/29011), thanks @ghengeveld!\n- Backgrounds/Viewports: Make defaults overridable in `StoryGlobals`-mode - [#29025](https://github.com/storybookjs/storybook/pull/29025), thanks @JReinhold!\n- CLI: Handle Yarn PnP wrapper scenario when adding an addon - [#29027](https://github.com/storybookjs/storybook/pull/29027), thanks @yannbf!\n- Maintenance: Rename addon-vitest to addon-test - [#29014](https://github.com/storybookjs/storybook/pull/29014), thanks @yannbf!\n- Nextjs-Vite: Re-export vite-plugin-storybook-nextjs - [#29012](https://github.com/storybookjs/storybook/pull/29012), thanks @valentinpalkovic!\n- SvelteKit/Vue3: Refactor plugin export paths - [#29016](https://github.com/storybookjs/storybook/pull/29016), thanks @yannbf!\n\n## 8.3.0-beta.1\n\n- ConfigFile: Fix `as const satisfies` modifiers - [#29000](https://github.com/storybookjs/storybook/pull/29000), thanks @shilman!\n- Core: Move `util` to regular dependency - [#29008](https://github.com/storybookjs/storybook/pull/29008), thanks @ndelangen!\n- Next.js-Vite: Streamline Next.js dir option - [#28995](https://github.com/storybookjs/storybook/pull/28995), thanks @valentinpalkovic!\n- Next.js: Fix wrong Next.js framework reference - [#28992](https://github.com/storybookjs/storybook/pull/28992), thanks @valentinpalkovic!\n- Vue3: Add vite plugin for portable stories - [#29004](https://github.com/storybookjs/storybook/pull/29004), thanks @yannbf!\n\n## 8.3.0-beta.0\n\nEmpty release identical to `v8.3.0-alpha.11`\n\n## 8.3.0-alpha.11\n\n- Addon Vitest: Fix tests potentially not existing in non-isolate mode - [#28993](https://github.com/storybookjs/storybook/pull/28993), thanks @yannbf!\n- Builder-Vite: Fix 'condition node never be used' warning - [#28989](https://github.com/storybookjs/storybook/pull/28989), thanks @valentinpalkovic!\n- CLI: Update spawn options in proxy.ts to support Windows - [#28990](https://github.com/storybookjs/storybook/pull/28990), thanks @valentinpalkovic!\n- Next.js-Vite: Update next and vite-plugin-storybook-nextjs dependencies - [#28994](https://github.com/storybookjs/storybook/pull/28994), thanks @valentinpalkovic!\n\n## 8.3.0-alpha.10\n\n- Addon Vitest: Fix postinstall file types - [#28978](https://github.com/storybookjs/storybook/pull/28978), thanks @shilman!\n- CLI: Fix dedent import in package managers - [#28980](https://github.com/storybookjs/storybook/pull/28980), thanks @shilman!\n- Core: De-duplicate babel use in core - [#28972](https://github.com/storybookjs/storybook/pull/28972), thanks @ndelangen!\n- Vitest: Fix add command - [#28975](https://github.com/storybookjs/storybook/pull/28975), thanks @ghengeveld!\n\n## 8.3.0-alpha.9\n\n- Addon Viewport: Add default options via parameters - [#28944](https://github.com/storybookjs/storybook/pull/28944), thanks @ndelangen!\n- CLI: Make PackageJson optional for starting a dev server - [#28594](https://github.com/storybookjs/storybook/pull/28594), thanks @tobiasdiez!\n- Svelte: Fix events not being logged in Actions when a story has decorators - [#28247](https://github.com/storybookjs/storybook/pull/28247), thanks @JReinhold!\n- Vitest: Fix default viewport - [#28943](https://github.com/storybookjs/storybook/pull/28943), thanks @kasperpeulen!\n- Vitest: Implement add command for vitest addon - [#28920](https://github.com/storybookjs/storybook/pull/28920), thanks @kasperpeulen!\n\n## 8.3.0-alpha.8\n\n- Addon Vitest: Improve transformation logic to avoid duplicate tests - [#28929](https://github.com/storybookjs/storybook/pull/28929), thanks @yannbf!\n- Addon Vitest: Set default viewport if applicable - [#28905](https://github.com/storybookjs/storybook/pull/28905), thanks @yannbf!\n- Addon-docs: Remove babel dependency - [#28915](https://github.com/storybookjs/storybook/pull/28915), thanks @shilman!\n- Blocks: Fix scroll to non-ascii anchors - [#28826](https://github.com/storybookjs/storybook/pull/28826), thanks @SkReD!\n- Core: Introduce setProjectAnnotations API to more renderers and frameworks - [#28907](https://github.com/storybookjs/storybook/pull/28907), thanks @yannbf!\n- Dependencies: Upgrade `commander` - [#28857](https://github.com/storybookjs/storybook/pull/28857), thanks @43081j!\n- SvelteKit: Introduce portable stories support - [#28918](https://github.com/storybookjs/storybook/pull/28918), thanks @yannbf!\n\n## 8.3.0-alpha.7\n\n- Addon Vitest: Set screenshotFailures to false by default - [#28908](https://github.com/storybookjs/storybook/pull/28908), thanks @yannbf!\n- Addon Vitest: Fix error message logic in set up file - [#28906](https://github.com/storybookjs/storybook/pull/28906), thanks @yannbf!\n- Core: Add Rsbuild frameworks to known frameworks - [#28694](https://github.com/storybookjs/storybook/pull/28694), thanks @fi3ework!\n- Test: Fix support for TS < 4.7 - [#28887](https://github.com/storybookjs/storybook/pull/28887), thanks @ndelangen!\n\n## 8.3.0-alpha.6\n\n- Addon Vitest: Add experimental vitest integration - [#28768](https://github.com/storybookjs/storybook/pull/28768), thanks @kasperpeulen!\n- Vite: Fix HMR - [#28876](https://github.com/storybookjs/storybook/pull/28876), thanks @ndelangen!\n\n## 8.3.0-alpha.5\n\n- Builder-Vite: Add null character prefix to virtual file IDs - [#28863](https://github.com/storybookjs/storybook/pull/28863), thanks @valentinpalkovic!\n- CLI: Fix `init --skip-install` - [#28853](https://github.com/storybookjs/storybook/pull/28853), thanks @ndelangen!\n- CLI: Parse more Yarn Berry errors - [#28816](https://github.com/storybookjs/storybook/pull/28816), thanks @yannbf!\n- Core: Make sure CJS build always has lowest prio - [#28829](https://github.com/storybookjs/storybook/pull/28829), thanks @kasperpeulen!\n- Maintenance: Add `node:`-prefix to node core-modules - [#28860](https://github.com/storybookjs/storybook/pull/28860), thanks @ndelangen!\n- Next.js: Add @storybook/nextjs-vite package - [#28800](https://github.com/storybookjs/storybook/pull/28800), thanks @valentinpalkovic!\n- React: Bundle in `lodash` - [#28609](https://github.com/storybookjs/storybook/pull/28609), thanks @ndelangen!\n- Telemetry: Add globals stats - [#28822](https://github.com/storybookjs/storybook/pull/28822), thanks @shilman!\n- Telemetry: Add portable stories - [#26764](https://github.com/storybookjs/storybook/pull/26764), thanks @shilman!\n- Telemetry: Disable save-from-controls logs for example stories - [#28870](https://github.com/storybookjs/storybook/pull/28870), thanks @shilman!\n- Test: Upgrade Vitest to v2 - [#28788](https://github.com/storybookjs/storybook/pull/28788), thanks @yannbf!\n\n## 8.3.0-alpha.4\n\n- CSF: Allow overridding globals at the story level - [#26654](https://github.com/storybookjs/storybook/pull/26654), thanks @tmeasday!\n- Core: Introduce run over play in portable stories, and revert back play changes of 8.2 - [#28764](https://github.com/storybookjs/storybook/pull/28764), thanks @kasperpeulen!\n- Core: Split Storybook CLI - [#28519](https://github.com/storybookjs/storybook/pull/28519), thanks @kasperpeulen!\n- Fix: Invariant failed: Expected package.json#version to be defined in the \"undefined\" package - [#28752](https://github.com/storybookjs/storybook/pull/28752), thanks @abcdmku!\n- Next.js: Make RSC portable-stories compatible - [#28756](https://github.com/storybookjs/storybook/pull/28756), thanks @valentinpalkovic!\n- UI: Fix collapse/expand all functionality - [#28582](https://github.com/storybookjs/storybook/pull/28582), thanks @filipemelo2002!\n\n## 8.3.0-alpha.3\n\n- Angular: Fix Angular template error for props with a circular reference - [#28498](https://github.com/storybookjs/storybook/pull/28498), thanks @Marklb!\n- Angular: Fix template props not able to use dot notation - [#28588](https://github.com/storybookjs/storybook/pull/28588), thanks @Marklb!\n- CLI: Fix the initialization of Storybook in workspaces - [#28699](https://github.com/storybookjs/storybook/pull/28699), thanks @valentinpalkovic!\n- CPC: Fix missing exports for addon-kit - [#28691](https://github.com/storybookjs/storybook/pull/28691), thanks @ndelangen!\n- CPC: Fix type usage in renderers - [#28745](https://github.com/storybookjs/storybook/pull/28745), thanks @ndelangen!\n- Controls: Add disableSave parameter - [#28734](https://github.com/storybookjs/storybook/pull/28734), thanks @valentinpalkovic!\n- React: Avoid 'Dynamic require of react is not possible' issue - [#28730](https://github.com/storybookjs/storybook/pull/28730), thanks @valentinpalkovic!\n- Telemetry: Add mount, beforeEach, moduleMock stats - [#28624](https://github.com/storybookjs/storybook/pull/28624), thanks @shilman!\n- Telemetry: CSF feature usage - [#28622](https://github.com/storybookjs/storybook/pull/28622), thanks @shilman!\n- Types: Adjust beforeAll to be non-nullable in NormalizedProjectAnnotations - [#28671](https://github.com/storybookjs/storybook/pull/28671), thanks @kasperpeulen!\n- Vue: Fix out of memory error when using vue-component-meta for events and slots - [#28674](https://github.com/storybookjs/storybook/pull/28674), thanks @larsrickert!\n- Vue: Improve generated code snippets - [#27194](https://github.com/storybookjs/storybook/pull/27194), thanks @larsrickert!\n\n## 8.3.0-alpha.2\n\n- Addon-Interactions: Fix status in panel tab - [#28580](https://github.com/storybookjs/storybook/pull/28580), thanks @yannbf!\n- Build: Remove external overrides, use package.json as source of truth - [#28632](https://github.com/storybookjs/storybook/pull/28632), thanks @kasperpeulen!\n- CLI: Add conditional logging for manager and preview start - [#28603](https://github.com/storybookjs/storybook/pull/28603), thanks @tobiasdiez!\n- CPC: Add the globals export for manager - [#28650](https://github.com/storybookjs/storybook/pull/28650), thanks @ndelangen!\n- CPC: Correct path to the `@storybook/theming/create` alias - [#28643](https://github.com/storybookjs/storybook/pull/28643), thanks @Averethel!\n- Core: Fix manager-builder `tsconfig` to emit `react-jsx` - [#28541](https://github.com/storybookjs/storybook/pull/28541), thanks @williamhelmrath!\n- Fix: Add header for MountMustBeDestructuredError message - [#28590](https://github.com/storybookjs/storybook/pull/28590), thanks @0916dhkim!\n- Fix: Prevent iframe from capturing mouse events in composed Storybooks - [#28568](https://github.com/storybookjs/storybook/pull/28568), thanks @Vincentdevreede!\n- Onboarding: Fix code snippet when story name differs from export name - [#28649](https://github.com/storybookjs/storybook/pull/28649), thanks @ghengeveld!\n- Vue: Fix out of memory error when using vue-component-meta - [#28589](https://github.com/storybookjs/storybook/pull/28589), thanks @larsrickert!\n\n## 8.3.0-alpha.1\n\n- Bug: Fix invalid docs links in Configure.mdx template page - [#28560](https://github.com/storybookjs/storybook/pull/28560), thanks @kylegach!\n- CLI: Add \"missing-storybook-dependencies\" automigration - [#28579](https://github.com/storybookjs/storybook/pull/28579), thanks @yannbf!\n- CLI: Add diagnostic when the `storybook` package is missing - [#28604](https://github.com/storybookjs/storybook/pull/28604), thanks @kasperpeulen!\n- CLI: Make a few automigrations run on all version upgrades - [#28601](https://github.com/storybookjs/storybook/pull/28601), thanks @yannbf!\n- CPC: Add `theming/create` aliases in docs preset - [#28570](https://github.com/storybookjs/storybook/pull/28570), thanks @ndelangen!\n- CPC: Direct dependencies on shim packages in renderers - [#28599](https://github.com/storybookjs/storybook/pull/28599), thanks @ndelangen!\n- CPC: Fix Vite builder had wrong conditions - [#28581](https://github.com/storybookjs/storybook/pull/28581), thanks @ndelangen!\n- CPC: Fix incorrect re-export in `core-events` - [#28573](https://github.com/storybookjs/storybook/pull/28573), thanks @ndelangen!\n- CSF: Fix small typing issue - [#28587](https://github.com/storybookjs/storybook/pull/28587), thanks @valentinpalkovic!\n- Core: Upgrade docs-mdx for smaller install - [#28552](https://github.com/storybookjs/storybook/pull/28552), thanks @shilman!\n- Portable stories: Remove unused types - [#28548](https://github.com/storybookjs/storybook/pull/28548), thanks @kasperpeulen!\n- Webpack: Fix sourceMap generation in csf-tools - [#28585](https://github.com/storybookjs/storybook/pull/28585), thanks @valentinpalkovic!\n\n## 8.3.0-alpha.0\n\n## 8.2.0-beta.3\n\n- Addon Controls: Fix saving on Windows - [#28485](https://github.com/storybookjs/storybook/pull/28485), thanks @ghengeveld!\n- React: Export ButtonProps and HeaderProps in CLI templates - [#28487](https://github.com/storybookjs/storybook/pull/28487), thanks @valentinpalkovic!\n\n## 8.2.0-beta.2\n\n- Addon Onboarding: Trigger onboarding during init for Vue and Angular projects - [#28482](https://github.com/storybookjs/storybook/pull/28482), thanks @ghengeveld!\n- CLI: Prebundle get-npm-tarball-url and @ndelangen/get-tarball - [#28481](https://github.com/storybookjs/storybook/pull/28481), thanks @ndelangen!\n\n## 8.2.0-beta.1\n\n- Babel: Ensure story files not transpiled earlier than ES2017 - [#28469](https://github.com/storybookjs/storybook/pull/28469), thanks @kasperpeulen!\n- Blocks: Prebundle `tocbot` - [#28318](https://github.com/storybookjs/storybook/pull/28318), thanks @shilman!\n- Core: Make sure StorybookError message shows up in browser console and interactions panel - [#28464](https://github.com/storybookjs/storybook/pull/28464), thanks @kasperpeulen!\n- Index: Fix MDX to override project-level autodocs - [#28461](https://github.com/storybookjs/storybook/pull/28461), thanks @shilman!\n- Test: Improve MountMustBeDestructuredError error message - [#28468](https://github.com/storybookjs/storybook/pull/28468), thanks @kasperpeulen!\n\n## 8.2.0-beta.0\n\n- Addon Interactions: Use unique keys when rendering array nodes in panel - [#28423](https://github.com/storybookjs/storybook/pull/28423), thanks @yannbf!\n- Addon Onboarding: Add icons for dev/test/doc to the splash screen - [#28389](https://github.com/storybookjs/storybook/pull/28389), thanks @ghengeveld!\n- Addon Onboarding: New design and flow based on Save from Controls - [#28327](https://github.com/storybookjs/storybook/pull/28327), thanks @ghengeveld!\n- Angular: Allow format configuration of custom source preview - [#28305](https://github.com/storybookjs/storybook/pull/28305), thanks @64BitAsura!\n- Angular: Fix enableProdMode setting - [#28415](https://github.com/storybookjs/storybook/pull/28415), thanks @valentinpalkovic!\n- Angular: Update outputPath default value in angular-cli-webpack.js - [#28418](https://github.com/storybookjs/storybook/pull/28418), thanks @valentinpalkovic!\n- Blocks: Fix reference to storybook core - [#28422](https://github.com/storybookjs/storybook/pull/28422), thanks @yannbf!\n- Build: Ignore ts stories in cra/default-js sandbox - [#28354](https://github.com/storybookjs/storybook/pull/28354), thanks @valentinpalkovic!\n- CLI: Add support for Nuxt to project init - [#26884](https://github.com/storybookjs/storybook/pull/26884), thanks @tobiasdiez!\n- CLI: Improve error message when fetching CLI version - [#28289](https://github.com/storybookjs/storybook/pull/28289), thanks @yannbf!\n- CPC: Add `CJS` for `core/components` - [#28440](https://github.com/storybookjs/storybook/pull/28440), thanks @ndelangen!\n- CPC: Core Package Consolidation - [#27039](https://github.com/storybookjs/storybook/pull/27039), thanks @ndelangen!\n- Config: Apply JavaScript-only story glob extensions for JavaScript projects - [#28338](https://github.com/storybookjs/storybook/pull/28338), thanks @valentinpalkovic!\n- Core: Add context as a property of the context (self-referencing) - [#28353](https://github.com/storybookjs/storybook/pull/28353), thanks @kasperpeulen!\n- Core: Add support for `beforeAll` hook - [#28255](https://github.com/storybookjs/storybook/pull/28255), thanks @ghengeveld!\n- Core: Migrate from `pkg-dir` to `fd-package-json` - [#28270](https://github.com/storybookjs/storybook/pull/28270), thanks @43081j!\n- Core: Refactor phases to run in order `loading` -> `rendering` -> `playing` - [#28431](https://github.com/storybookjs/storybook/pull/28431), thanks @kasperpeulen!\n- Dependency: Remove node-fetch - [#28160](https://github.com/storybookjs/storybook/pull/28160), thanks @yk-kd!\n- Deps: Migrate from `read-pkg-up` to `fd-package-json` - [#28272](https://github.com/storybookjs/storybook/pull/28272), thanks @43081j!\n- Docs: Filter mount stories from `Stories` block, error when referenced in MDX - [#28434](https://github.com/storybookjs/storybook/pull/28434), thanks @kasperpeulen!\n- Indexer: Improve locating stories with specials chars in path - [#22110](https://github.com/storybookjs/storybook/pull/22110), thanks @jankoritak!\n- Next.js: Set `env.bugfixes` in SWC so destructuring is never transpiled - [#28363](https://github.com/storybookjs/storybook/pull/28363), thanks @kasperpeulen!\n- Next: Set default targets for next babel config - [#28443](https://github.com/storybookjs/storybook/pull/28443), thanks @kasperpeulen!\n- SWC: Set default targets for swc that align with our esbuild targets - [#28435](https://github.com/storybookjs/storybook/pull/28435), thanks @kasperpeulen!\n- Telemetry: Detect Node version - [#28299](https://github.com/storybookjs/storybook/pull/28299), thanks @yannbf!\n- Telemetry: Stop prompting about crash reports in CI - [#28433](https://github.com/storybookjs/storybook/pull/28433), thanks @yannbf!\n- Test: Add args to `mount` in react, svelte, and vue renderers - [#28385](https://github.com/storybookjs/storybook/pull/28385), thanks @kasperpeulen!\n- Test: Add mount property to the story context - [#28383](https://github.com/storybookjs/storybook/pull/28383), thanks @kasperpeulen!\n- Test: Enhance the context with canvas when the test package is used - [#28368](https://github.com/storybookjs/storybook/pull/28368), thanks @kasperpeulen!\n- Test: Reactive spies preserve the this instance - [#28445](https://github.com/storybookjs/storybook/pull/28445), thanks @kasperpeulen!\n\n## 8.2.0-alpha.10\n\n- Addon-interactions: Fix deprecation warnings - [#28250](https://github.com/storybookjs/storybook/pull/28250), thanks @shilman!\n- Core: Remove util dependency - [#28191](https://github.com/storybookjs/storybook/pull/28191), thanks @43081j!\n- Dependencies: Allow esbuild version 0.21.x - [#28245](https://github.com/storybookjs/storybook/pull/28245), thanks @edoardocavazza!\n\n## 8.2.0-alpha.9\n\n- Addon-a11y: Workaround for Vite 5.3.0 compat - [#28241](https://github.com/storybookjs/storybook/pull/28241), thanks @shilman!\n- CLI: Fix CLI always asking all automigrations - [#28238](https://github.com/storybookjs/storybook/pull/28238), thanks @ndelangen!\n- Core: Fix startup hang caused by watchStorySpecifiers - [#27016](https://github.com/storybookjs/storybook/pull/27016), thanks @heyimalex!\n\n## 8.2.0-alpha.8\n\n- Automigrations: Make VTA \"learn more\" link clickable - [#28020](https://github.com/storybookjs/storybook/pull/28020), thanks @deiga!\n- CLI: Fix `init --skip-install` - [#28226](https://github.com/storybookjs/storybook/pull/28226), thanks @shilman!\n- CSF: Rename `preview.js` `globals` to `initialGlobals` - [#27517](https://github.com/storybookjs/storybook/pull/27517), thanks @shilman!\n\n## 8.2.0-alpha.7\n\n- Angular: Allow outputPath object syntax - [#28144](https://github.com/storybookjs/storybook/pull/28144), thanks @valentinpalkovic!\n- Angular: Introduce preserveSymlink builder option - [#28145](https://github.com/storybookjs/storybook/pull/28145), thanks @valentinpalkovic!\n- CLI: Fix typo in React Docgen migration - [#27536](https://github.com/storybookjs/storybook/pull/27536), thanks @jonniebigodes!\n- CSF: Automatically extract componentPath - [#24396](https://github.com/storybookjs/storybook/pull/24396), thanks @shilman!\n- Core: Remove more `.stories.mdx` handling - [#25973](https://github.com/storybookjs/storybook/pull/25973), thanks @JReinhold!\n- Docs-tools: Replace `doctrine` with `jsdoc-type-pratt-parser` - [#26305](https://github.com/storybookjs/storybook/pull/26305), thanks @43081j!\n- Test: Display toHaveBeenCalledWith expected / received values on failure - [#28088](https://github.com/storybookjs/storybook/pull/28088), thanks @kasperpeulen!\n\n## 8.2.0-alpha.6\n\n- Addon-actions: Only log spies with names - [#28091](https://github.com/storybookjs/storybook/pull/28091), thanks @kasperpeulen!\n- Build: Change require/import order, so that import has higher prio if both are specified - [#27730](https://github.com/storybookjs/storybook/pull/27730), thanks @kasperpeulen!\n- CLI: Only log the UpgradeStorybookToSameVersionError but continue the upgrade as normal - [#27217](https://github.com/storybookjs/storybook/pull/27217), thanks @kasperpeulen!\n- Core: Replace ip function with a small helper function to address security concerns - [#27529](https://github.com/storybookjs/storybook/pull/27529), thanks @tony19!\n- Portable Stories: Add tags to composed story - [#27708](https://github.com/storybookjs/storybook/pull/27708), thanks @yannbf!\n- Test: Upgrade deps of @storybook/test - [#27862](https://github.com/storybookjs/storybook/pull/27862), thanks @kasperpeulen!\n- Vite: Fix stats-plugin to normalize file names with posix paths - [#27218](https://github.com/storybookjs/storybook/pull/27218), thanks @AlexAtVista!\n\n## 8.2.0-alpha.5\n\n- Angular: Fix wrong detection of standalone components - [#27353](https://github.com/storybookjs/storybook/pull/27353), thanks @dario-baumberger!\n- Dependency: Bump Express.js - [#26680](https://github.com/storybookjs/storybook/pull/26680), thanks @valentinpalkovic!\n- Tags: Fix unsafe project-level tags lookup - [#27511](https://github.com/storybookjs/storybook/pull/27511), thanks @shilman!\n\n## 8.2.0-alpha.4\n\n- CSF-Tools: Fix export specifier bug - [#27418](https://github.com/storybookjs/storybook/pull/27418), thanks @valentinpalkovic!\n- Dependency: Upgrade tempy - [#27366](https://github.com/storybookjs/storybook/pull/27366), thanks @mnigh!\n- Tags: Refine composition behavior - [#27379](https://github.com/storybookjs/storybook/pull/27379), thanks @shilman!\n- Theming: Fix self-referencing type - [#27155](https://github.com/storybookjs/storybook/pull/27155), thanks @SimenB!\n- Vue3: Enable new hydration mismatch compile time flag - [#27192](https://github.com/storybookjs/storybook/pull/27192), thanks @Cherry!\n\n## 8.2.0-alpha.3\n\n- Addon-A11y: Fix property default assignment - [#27224](https://github.com/storybookjs/storybook/pull/27224), thanks @valentinpalkovic!\n- Angular: Revert style adjustments - [#27361](https://github.com/storybookjs/storybook/pull/27361), thanks @valentinpalkovic!\n- Angular: Support v18 - [#27237](https://github.com/storybookjs/storybook/pull/27237), thanks @valentinpalkovic!\n- Controls: Fix date picker control validation and assignment - [#26695](https://github.com/storybookjs/storybook/pull/26695), thanks @leeovictor!\n- Next.js: Avoid interfering with the svgr loader - [#27198](https://github.com/storybookjs/storybook/pull/27198), thanks @seanparmelee!\n- Svelte: Support latest prerelease - [#27378](https://github.com/storybookjs/storybook/pull/27378), thanks @valentinpalkovic!\n- Tags: Fix composition with older storybooks - [#27358](https://github.com/storybookjs/storybook/pull/27358), thanks @shilman!\n- Telemetry: Add test packages - [#27226](https://github.com/storybookjs/storybook/pull/27226), thanks @shilman!\n- Types: Fix type implementation for `CompatibleString` - [#27180](https://github.com/storybookjs/storybook/pull/27180), thanks @sni-J!\n- Vite: Fix HMR issue for Storybook preview files - [#27256](https://github.com/storybookjs/storybook/pull/27256), thanks @valentinpalkovic!\n- Vite: Fix asset warning by externalizing sb-common-assets font - [#27110](https://github.com/storybookjs/storybook/pull/27110), thanks @valentinpalkovic!\n- Webpack5/Vite: Fix sourcemaps - [#27171](https://github.com/storybookjs/storybook/pull/27171), thanks @valentinpalkovic!\n\n## 8.2.0-alpha.2\n\n- Angular: Cleanup types - [#27189](https://github.com/storybookjs/storybook/pull/27189), thanks @valentinpalkovic!\n- Angular: Fix filtering of workspace config styles - [#27108](https://github.com/storybookjs/storybook/pull/27108), thanks @valentinpalkovic!\n- Controls: Fix grouped Radio controls to have the same name - [#23374](https://github.com/storybookjs/storybook/pull/23374), thanks @srapilly!\n- Controls: Throttling makes Color control lagging - [#22615](https://github.com/storybookjs/storybook/pull/22615), thanks @gitstart!\n- Docs: Fix `Typeset` Doc block `fontSizes` type - [#26475](https://github.com/storybookjs/storybook/pull/26475), thanks @noranda!\n\n## 8.2.0-alpha.1\n\n- CLI: Add optional `--dev` and `--no-dev` options to `storybook init` CLI - [#26918](https://github.com/storybookjs/storybook/pull/26918), thanks @fastfrwrd!\n- CLI: Include `@storybook/addon-svelte-csf` when initializing new projects - [#27070](https://github.com/storybookjs/storybook/pull/27070), thanks @benmccann!\n- Dependency: Upgrade `webpack-virtual-modules` to 0.6.0 - [#27102](https://github.com/storybookjs/storybook/pull/27102), thanks @fyodorovandrei!\n- Dependency: bump `markdown-to-jsx` to v7.4.5 - [#26694](https://github.com/storybookjs/storybook/pull/26694), thanks @xyy94813!\n- Docgen: Only add react-docgen info when a component is defined in the file - [#26967](https://github.com/storybookjs/storybook/pull/26967), thanks @glenjamin!\n- Docs: Fix MDX Stories block tag-filtering behavior - [#27144](https://github.com/storybookjs/storybook/pull/27144), thanks @shilman!\n- Docs: Fix Subtitle block when no `of` prop passed - [#27147](https://github.com/storybookjs/storybook/pull/27147), thanks @JReinhold!\n- Next.js: Add typing for NextImage to main framework options type - [#27105](https://github.com/storybookjs/storybook/pull/27105), thanks @valentinpalkovic!\n- Next.js: Avoid conflicts with the raw loader - [#27093](https://github.com/storybookjs/storybook/pull/27093), thanks @seanparmelee!\n- Types: Fix typing for main.framework/builder fields - [#27088](https://github.com/storybookjs/storybook/pull/27088), thanks @valentinpalkovic!\n\n## 8.2.0-alpha.0\n\n## 8.1.0-beta.1\n\n- API: Add API access to sidebar renderLabel - [#27099](https://github.com/storybookjs/storybook/pull/27099), thanks @shilman!\n- CLI: Add main.js `docs.autodocs` automigration - [#27089](https://github.com/storybookjs/storybook/pull/27089), thanks @shilman!\n- CLI: Fix eslint configuration for string `extends` - [#27097](https://github.com/storybookjs/storybook/pull/27097), thanks @shilman!\n- Indexer: Escape special characters in storyImport regex - [#22545](https://github.com/storybookjs/storybook/pull/22545), thanks @VojGin!\n- Next.js: Fix Compatibility with <v14.0.4 - [#27082](https://github.com/storybookjs/storybook/pull/27082), thanks @JReinhold!\n- Tags: Fix missing default tags if no `preview.js` - [#27098](https://github.com/storybookjs/storybook/pull/27098), thanks @shilman!\n\n## 8.1.0-beta.0\n\n- Dependencies: Upgrade `@joshwooding/vite-plugin-react-docgen-typescript` to `0.3.1` - [#26673](https://github.com/storybookjs/storybook/pull/26673), thanks @joshwooding!\n- Dependencies: Upgrade `ejs` to `3.1.10` - [#27054](https://github.com/storybookjs/storybook/pull/27054), thanks @RiuSalvi!\n- Nextjs: Implement next redirect and the RedirectBoundary - [#27050](https://github.com/storybookjs/storybook/pull/27050), thanks @yannbf!\n- Onboarding: Improve UI - [#27074](https://github.com/storybookjs/storybook/pull/27074), thanks @ndelangen!\n- Portable Stories: Remove link to missing docs - [#27075](https://github.com/storybookjs/storybook/pull/27075), thanks @JReinhold!\n- React: Support v19 betas in peer dependencies - [#26960](https://github.com/storybookjs/storybook/pull/26960), thanks @JReinhold!\n- Tags: Add project tags, negation, `dev`/`autodocs`/`test` system tags - [#26634](https://github.com/storybookjs/storybook/pull/26634), thanks @shilman!\n- UI: Fix panel layout resizing do not apply when done too fast - [#26460](https://github.com/storybookjs/storybook/pull/26460), thanks @jorge-ji!\n\n## 8.1.0-alpha.8\n\n- Addon-actions: Fix falsy args printing as object - 22163 - [#26917](https://github.com/storybookjs/storybook/pull/26917), thanks @Fatcat560!\n- Addon-docs: Fix MDX compilation with `@vitejs/plugin-react-swc` and plugins - [#26837](https://github.com/storybookjs/storybook/pull/26837), thanks @JReinhold!\n- Automigration: Fix name of VTA addon - [#26816](https://github.com/storybookjs/storybook/pull/26816), thanks @valentinpalkovic!\n- Blocks: Add `of` prop to `Subtitle` - [#22552](https://github.com/storybookjs/storybook/pull/22552), thanks @joaonunomota!\n- Blocks: Add `of` prop to `Title` - [#23728](https://github.com/storybookjs/storybook/pull/23728), thanks @Sidnioulz!\n- CSF: Fix typings for control and other properties of argTypes - [#26824](https://github.com/storybookjs/storybook/pull/26824), thanks @kasperpeulen!\n- Controls: Added server channel to create a new story - [#26769](https://github.com/storybookjs/storybook/pull/26769), thanks @valentinpalkovic!\n- Controls: Fix crashing when docgen extraction partially fails - [#26862](https://github.com/storybookjs/storybook/pull/26862), thanks @yannbf!\n- Controls: Add UI to create new story files - [#26875](https://github.com/storybookjs/storybook/pull/26875), thanks @valentinpalkovic!\n- Core: Drop unneeded `UPDATE_STORY_ARGS` which was for SSv6 - [#25993](https://github.com/storybookjs/storybook/pull/25993), thanks @tmeasday!\n- Core: Ensure that simultaneous onStoriesChanged don't clobber each other - [#26882](https://github.com/storybookjs/storybook/pull/26882), thanks @tmeasday!\n- Core: Fix filters not being applied in WebKit - [#26949](https://github.com/storybookjs/storybook/pull/26949), thanks @JReinhold!\n- Core: Implement file formatter - [#26809](https://github.com/storybookjs/storybook/pull/26809), thanks @valentinpalkovic!\n- Core: Save from controls - [#26827](https://github.com/storybookjs/storybook/pull/26827), thanks @ndelangen!\n- Dependencies: Upgrade @storybook/csf to 0.1.5 - [#26958](https://github.com/storybookjs/storybook/pull/26958), thanks @Cherry!\n- Doc Tools: Signature Type Error Handling - [#26774](https://github.com/storybookjs/storybook/pull/26774), thanks @ethriel3695!\n- Docs: Fix providerImportSource extension - [#26868](https://github.com/storybookjs/storybook/pull/26868), thanks @bashmish!\n- MDX: Don't transform `http://` links - [#26488](https://github.com/storybookjs/storybook/pull/26488), thanks @JReinhold!\n- Next.js: Move sharp into optional deps - [#26787](https://github.com/storybookjs/storybook/pull/26787), thanks @shuta13!\n- Next.js: Support v14.2 useParams functionality - [#26874](https://github.com/storybookjs/storybook/pull/26874), thanks @yannbf!\n- Portable Stories: Warn when rendering stories without cleaning up first - [#27008](https://github.com/storybookjs/storybook/pull/27008), thanks @JReinhold!\n- React: Support v19 in `react-dom-shim` - [#26898](https://github.com/storybookjs/storybook/pull/26898), thanks @Tobbe!\n- Test: Remove chai as dependency of @storybook/test - [#26852](https://github.com/storybookjs/storybook/pull/26852), thanks @kasperpeulen!\n- Test: Support module mocking with conditional subpath imports in `package.json` - [#26688](https://github.com/storybookjs/storybook/pull/26688), thanks @kasperpeulen!\n- UI: Fix not re-rendering tabs on state change - [#26899](https://github.com/storybookjs/storybook/pull/26899), thanks @lifeiscontent!\n- UI: Fix sidebar search hanging when selecting a story in touch mode - [#26807](https://github.com/storybookjs/storybook/pull/26807), thanks @JReinhold!\n- Vite: Merge assetsInclude property with Storybook default values - [#26860](https://github.com/storybookjs/storybook/pull/26860), thanks @yuemori!\n\n## 8.1.0-alpha.7\n\n- CLI: Add --config-dir flag to add command - [#26771](https://github.com/storybookjs/storybook/pull/26771), thanks @eric-blue!\n- CLI: Add Visual Tests addon install auto-migration when upgrading to 8.0.x - [#26766](https://github.com/storybookjs/storybook/pull/26766), thanks @ndelangen!\n- Controls: Add Channels API to search for files in the project root - [#26726](https://github.com/storybookjs/storybook/pull/26726), thanks @valentinpalkovic!\n- Test: Make spies reactive so that they can be logged by addon-actions - [#26740](https://github.com/storybookjs/storybook/pull/26740), thanks @kasperpeulen!\n- Vue: Disable controls for events, slots, and expose - [#26751](https://github.com/storybookjs/storybook/pull/26751), thanks @shilman!\n- Webpack: Bump webpack-dev-middleware to patch high security issue - [#26655](https://github.com/storybookjs/storybook/pull/26655), thanks @jwilliams-met!\n\n## 8.1.0-alpha.6\n\n- CLI: Add --config-dir flag to migrate command - [#26721](https://github.com/storybookjs/storybook/pull/26721), thanks @yannbf!\n- Core: Add `duration` and `onClick` support to Notification API and improve Notification UI - [#26696](https://github.com/storybookjs/storybook/pull/26696), thanks @ghengeveld!\n- Dependency: Bump es-module-lexer - [#26737](https://github.com/storybookjs/storybook/pull/26737), thanks @valentinpalkovic!\n- Dependency: Update globby dependency - [#26733](https://github.com/storybookjs/storybook/pull/26733), thanks @valentinpalkovic!\n- Dependency: Update postcss-loader in Next.js framework - [#26707](https://github.com/storybookjs/storybook/pull/26707), thanks @valentinpalkovic!\n- Next.js: Fix next/font usage on Windows machines - [#26700](https://github.com/storybookjs/storybook/pull/26700), thanks @valentinpalkovic!\n- Webpack: Fix sourcemap generation in webpack react-docgen-loader - [#26676](https://github.com/storybookjs/storybook/pull/26676), thanks @valentinpalkovic!\n\n## 8.1.0-alpha.5\n\n- Addon-docs: Fix `react-dom/server` imports breaking stories and docs - [#26557](https://github.com/storybookjs/storybook/pull/26557), thanks @JReinhold!\n- Args: Add possibility to mark controls as read-only - [#26577](https://github.com/storybookjs/storybook/pull/26577), thanks @valentinpalkovic!\n- Automigrations: Add migration note about new react-docgen default - [#26620](https://github.com/storybookjs/storybook/pull/26620), thanks @valentinpalkovic!\n- Automigrations: Fix missing support for mts vite config - [#26441](https://github.com/storybookjs/storybook/pull/26441), thanks @drik98!\n- CLI: Automigrations copy edits - [#26342](https://github.com/storybookjs/storybook/pull/26342), thanks @joevaugh4n!\n- CLI: Improve Yarn berry error parsing - [#26616](https://github.com/storybookjs/storybook/pull/26616), thanks @yannbf!\n- Codemods: Escape filename given as argument - [#26430](https://github.com/storybookjs/storybook/pull/26430), thanks @YukiKitagata!\n- NextJS: Support path aliases when no base url is set - [#26651](https://github.com/storybookjs/storybook/pull/26651), thanks @yannbf!\n- Node: Safe use of `document` for preview - [#24248](https://github.com/storybookjs/storybook/pull/24248), thanks @DylanPiercey!\n- React-Docgen: Make sure to be able to handle empty unions - [#26639](https://github.com/storybookjs/storybook/pull/26639), thanks @kasperpeulen!\n- Test: Add @storybook/test as dev dependency - [#26458](https://github.com/storybookjs/storybook/pull/26458), thanks @arnabsen!\n- Theming: Update emotion dependencies - [#26623](https://github.com/storybookjs/storybook/pull/26623), thanks @SimenB!\n- Viewport: Fix missing style - [#26530](https://github.com/storybookjs/storybook/pull/26530), thanks @jpzwarte!\n- Webpack: Hide runtime errors - [#23175](https://github.com/storybookjs/storybook/pull/23175), thanks @donaldpipowitch!\n\n## 8.1.0-alpha.4\n\n- Addon Docs: Support Stencil based display names in source snippets - [#26592](https://github.com/storybookjs/storybook/pull/26592), thanks @yannbf!\n- Angular: Add type support for Angular's input signals - [#26413](https://github.com/storybookjs/storybook/pull/26413), thanks @valentinpalkovic!\n- Angular: Add type support for Angular's output signals - [#26546](https://github.com/storybookjs/storybook/pull/26546), thanks @valentinpalkovic!\n- CLI: Instruct the correct auto-migration command - [#26515](https://github.com/storybookjs/storybook/pull/26515), thanks @ndelangen!\n- CLI: Throw an error when running upgrade command in incorrect cwd - [#26585](https://github.com/storybookjs/storybook/pull/26585), thanks @yannbf!\n- CSF: Allow default export without title or component attributes - [#26516](https://github.com/storybookjs/storybook/pull/26516), thanks @kasperpeulen!\n- Core: Fix preloading too early - [#26442](https://github.com/storybookjs/storybook/pull/26442), thanks @ndelangen!\n- UI: Replace the icon prop in the Manager API - [#26477](https://github.com/storybookjs/storybook/pull/26477), thanks @cdedreuille!\n\n## 8.1.0-alpha.3\n\n- Addon Docs: Fix [Object object] displayName in some JSX components - [#26566](https://github.com/storybookjs/storybook/pull/26566), thanks @yannbf!\n- CLI: Introduce package manager fallback for initializing Storybook in an empty directory with yarn1 - [#26500](https://github.com/storybookjs/storybook/pull/26500), thanks @valentinpalkovic!\n- CSF: Make sure loaders/decorators can be used as array - [#26514](https://github.com/storybookjs/storybook/pull/26514), thanks @kasperpeulen!\n- Controls: Fix disable condition in ArgControl component - [#26567](https://github.com/storybookjs/storybook/pull/26567), thanks @valentinpalkovic!\n- Portable stories: Introduce experimental Playwright CT API and Support for more renderers - [#26063](https://github.com/storybookjs/storybook/pull/26063), thanks @yannbf!\n- UI: Fix theming of elements inside bars - [#26527](https://github.com/storybookjs/storybook/pull/26527), thanks @valentinpalkovic!\n- UI: Improve empty state of addon panel - [#26481](https://github.com/storybookjs/storybook/pull/26481), thanks @yannbf!\n\n## 8.1.0-alpha.2\n\n- CLI: Automigrate improve upgrade storybook related packages - [#26497](https://github.com/storybookjs/storybook/pull/26497), thanks @ndelangen!\n- CLI: Improve `vite-config-file.ts` - [#26375](https://github.com/storybookjs/storybook/pull/26375), thanks @joevaugh4n!\n- Controls: Fix number controls do not reset - [#26372](https://github.com/storybookjs/storybook/pull/26372), thanks @jiyiru!\n- Core: Optimize clearNotification - [#26415](https://github.com/storybookjs/storybook/pull/26415), thanks @ndelangen!\n- Portable stories: Make setProjectAnnotations accept multiple types of imports - [#26316](https://github.com/storybookjs/storybook/pull/26316), thanks @yannbf!\n- UI: Add key property to list children in Highlight component - [#26471](https://github.com/storybookjs/storybook/pull/26471), thanks @valentinpalkovic!\n- UI: Fix search result color contrast - [#26287](https://github.com/storybookjs/storybook/pull/26287), thanks @winchesHe!\n\n## 8.1.0-alpha.1\n\n- Maintenance: Fix performance regressions - [#26411](https://github.com/storybookjs/storybook/pull/26411), thanks @kasperpeulen!\n\n## 8.1.0-alpha.0\n\n## 8.0.0-rc.5\n\n- CLI: Automigration fix version detection of upgrading related packages - [#26410](https://github.com/storybookjs/storybook/pull/26410), thanks @ndelangen!\n\n## 8.0.0-rc.4\n\n- Actions: Fix attaching action after a spy is restored to original function - [#26364](https://github.com/storybookjs/storybook/pull/26364), thanks @kasperpeulen!\n- CLI: Add explicit actions to header story - [#26352](https://github.com/storybookjs/storybook/pull/26352), thanks @kasperpeulen!\n- CLI: Automigration for upgrading storybook related dependencies - [#26377](https://github.com/storybookjs/storybook/pull/26377), thanks @ndelangen!\n- CLI: Fix doctor compatibility check - [#26363](https://github.com/storybookjs/storybook/pull/26363), thanks @yannbf!\n- CLI: Fix fn reference in preact templates - [#26384](https://github.com/storybookjs/storybook/pull/26384), thanks @kasperpeulen!\n- CLI: Remove duplicated dependency warning - [#26385](https://github.com/storybookjs/storybook/pull/26385), thanks @yannbf!\n- CLI: Vite migration link (shorter) - [#26379](https://github.com/storybookjs/storybook/pull/26379), thanks @ndelangen!\n- Composition: Fix refs not loading when there's multiple - [#26356](https://github.com/storybookjs/storybook/pull/26356), thanks @ndelangen!\n- Dependencies: Broaden `esbuild` version range - [#26405](https://github.com/storybookjs/storybook/pull/26405), thanks @ndelangen!\n- Maintenance: Replace `@storybook/testing-library` with `@storybook/test` in monorepo - [#26351](https://github.com/storybookjs/storybook/pull/26351), thanks @ndelangen!\n- Maintenance: What's new modal changes - [#26355](https://github.com/storybookjs/storybook/pull/26355), thanks @kasperpeulen!\n- Portable Stories: Fix injected root element changing layout - [#26387](https://github.com/storybookjs/storybook/pull/26387), thanks @JReinhold!\n- React: Support all React component types in JSX Decorator - [#26382](https://github.com/storybookjs/storybook/pull/26382), thanks @yannbf!\n\n## 8.0.0-rc.3\n\n- Addon-themes: Fix switcher initialization after first start - [#26353](https://github.com/storybookjs/storybook/pull/26353), thanks @valentinpalkovic!\n- Build: Upgrade `esbuild` (`0.20.1`) - [#26255](https://github.com/storybookjs/storybook/pull/26255), thanks @43081j!\n- Core: Fix path separator issue in check-addon-order - [#26362](https://github.com/storybookjs/storybook/pull/26362), thanks @valentinpalkovic!\n- Dependencies: Remove `qs` from `@storybook/manager-api` & `@storybook/channels` - [#26285](https://github.com/storybookjs/storybook/pull/26285), thanks @43081j!\n- UI: Fix sidebar scrolling to selected story when state changes - [#26337](https://github.com/storybookjs/storybook/pull/26337), thanks @JReinhold!\n- UI: Remove 'left' property from TooltipLinkList and Link components - [#26324](https://github.com/storybookjs/storybook/pull/26324), thanks @valentinpalkovic!\n- Viewport: Fix editing when default viewport is set - [#26360](https://github.com/storybookjs/storybook/pull/26360), thanks @shilman!\n- Vue: Fix reference error when using re-exports with \"vue-component-meta\" - [#26303](https://github.com/storybookjs/storybook/pull/26303), thanks @larsrickert!\n\n## 8.0.0-rc.2\n\n- CLI: Add @storybook/addons automigration - [#26295](https://github.com/storybookjs/storybook/pull/26295), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- CLI: Fix vite config automigration to resolve from project root - [#26262](https://github.com/storybookjs/storybook/pull/26262), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- CLI: Improve `add` command & add tests - [#26298](https://github.com/storybookjs/storybook/pull/26298), thanks [@ndelangen](https://github.com/ndelangen)!\n- CLI: Update minimum Node.js version requirement - [#26312](https://github.com/storybookjs/storybook/pull/26312), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- CSF-tools/Codemods: Upgrade recast - [#26286](https://github.com/storybookjs/storybook/pull/26286), thanks [@43081j](https://github.com/43081j)!\n- Controls: Fix type summary when table.type unset - [#26283](https://github.com/storybookjs/storybook/pull/26283), thanks [@shilman](https://github.com/shilman)!\n- Core: Add event when serverChannel disconnects - [#26322](https://github.com/storybookjs/storybook/pull/26322), thanks [@ndelangen](https://github.com/ndelangen)!\n- Core: Fix composition of storybooks on same origin - [#26304](https://github.com/storybookjs/storybook/pull/26304), thanks [@ndelangen](https://github.com/ndelangen)!\n- Portable stories: Improve existing APIs, add loaders support - [#26267](https://github.com/storybookjs/storybook/pull/26267), thanks [@yannbf](https://github.com/yannbf)!\n- React: Handle TypeScript path aliases in react-docgen loader - [#26273](https://github.com/storybookjs/storybook/pull/26273), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Svelte: Support `5.0.0-next.65` prerelease - [#26188](https://github.com/storybookjs/storybook/pull/26188), thanks [@JReinhold](https://github.com/JReinhold)!\n- Upgrade: Add missing isUpgrade parameter to automigrate function - [#26293](https://github.com/storybookjs/storybook/pull/26293), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Vue: Return component from `composeStory` - [#26317](https://github.com/storybookjs/storybook/pull/26317), thanks [@JReinhold](https://github.com/JReinhold)!\n\n## 8.0.0-rc.1\n\n- CLI: Fix addon compatibility check error reporting in storybook dev - [#26258](https://github.com/storybookjs/storybook/pull/26258), thanks [@yannbf](https://github.com/yannbf)!\n- Onboarding: Fix manager dist reference - [#26282](https://github.com/storybookjs/storybook/pull/26282), thanks [@shilman](https://github.com/shilman)!\n- ReactVite: Docgen ignore un-parsable files - [#26254](https://github.com/storybookjs/storybook/pull/26254), thanks [@ndelangen](https://github.com/ndelangen)!\n\n## 8.0.0-rc.0\n\nBumping 8.0.0-beta.6 to 8.0.0-rc.0. Please refer to the changelogs of previous beta releases.\n\n## 8.0.0-beta.6\n\n- Addon-onboarding: Move onboarding to monorepo - [#26176](https://github.com/storybookjs/storybook/pull/26176), thanks [@ndelangen](https://github.com/ndelangen)!\n- Angular: Fix Storybook startup after init - [#26213](https://github.com/storybookjs/storybook/pull/26213), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Angular: Use dedicated tsconfig for compodocs - [#26214](https://github.com/storybookjs/storybook/pull/26214), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Automigration: Fix overflow bug by using a better link - [#26203](https://github.com/storybookjs/storybook/pull/26203), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Automigration: Run the `mdx-to-csf` codemod during automigration - [#26201](https://github.com/storybookjs/storybook/pull/26201), thanks [@ndelangen](https://github.com/ndelangen)!\n- Automigrations: Create addon-postcss automigration - [#26228](https://github.com/storybookjs/storybook/pull/26228), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Automigrations: Enhance experience for upgrades from Storybook 6 to 8 - [#26067](https://github.com/storybookjs/storybook/pull/26067), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Automigrations: General fixes for automigrations, blockers and codemods - [#26210](https://github.com/storybookjs/storybook/pull/26210), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Blocks: Fix `Stories` block rendering duplicate stories when globals are changed - [#26110](https://github.com/storybookjs/storybook/pull/26110), thanks [@JReinhold](https://github.com/JReinhold)!\n- Builder Vite: Pass on errors about not having a real stats object in smoke tests - [#26195](https://github.com/storybookjs/storybook/pull/26195), thanks [@tmeasday](https://github.com/tmeasday)!\n- CLI: Rename `--webpack-stats-json` to `--stats-json` as it works in Vite - [#26128](https://github.com/storybookjs/storybook/pull/26128), thanks [@tmeasday](https://github.com/tmeasday)!\n- Codemods: Enhance mdx-to-csf codemod - [#26164](https://github.com/storybookjs/storybook/pull/26164), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Core: Export preview symbols for embedding - [#26224](https://github.com/storybookjs/storybook/pull/26224), thanks [@tmeasday](https://github.com/tmeasday)!\n- Docs: Don't show how to setup controls for empty argTypes in doc pages - [#26200](https://github.com/storybookjs/storybook/pull/26200), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Docs: Fix function prop rendering as `noRefCheck` in storybook docs - [#26104](https://github.com/storybookjs/storybook/pull/26104), thanks [@thisisanto](https://github.com/thisisanto)!\n- Doctor: Add dynamic check for incompatible Storybook packages - [#26219](https://github.com/storybookjs/storybook/pull/26219), thanks [@yannbf](https://github.com/yannbf)!\n- Maintenance: Remove deprecation of `manager-api`'s `types` export - [#26202](https://github.com/storybookjs/storybook/pull/26202), thanks [@ndelangen](https://github.com/ndelangen)!\n- Revert \"Revert: \"Angular: Reduce the warnings from `ts-loader` via stricter list of `includes`\"\" - [#26226](https://github.com/storybookjs/storybook/pull/26226), thanks [@ndelangen](https://github.com/ndelangen)!\n- Revert: \"Angular: Reduce the warnings from `ts-loader` via stricter list of `includes`\" - [#26208](https://github.com/storybookjs/storybook/pull/26208), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- UI: Improve sidebar performance when switching stories - [#26184](https://github.com/storybookjs/storybook/pull/26184), thanks [@literalpie](https://github.com/literalpie)!\n- UI: Update theme switcher to use toggle button for two themes - [#25682](https://github.com/storybookjs/storybook/pull/25682), thanks [@ivoilic](https://github.com/ivoilic)!\n- Vue: Improve types for array, union and intersection when using vue-docgen-api - [#26177](https://github.com/storybookjs/storybook/pull/26177), thanks [@larsrickert](https://github.com/larsrickert)!\n\n## 8.0.0-beta.5\n\n- Addon-controls: Dont show \"setup controls\" if control is disabled or a function - [#26120](https://github.com/storybookjs/storybook/pull/26120), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Addon-interactions: Only mutate arg keys when writable - [#26118](https://github.com/storybookjs/storybook/pull/26118), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- CLI: Fix logic to add `^` packages in upgrade - [#26049](https://github.com/storybookjs/storybook/pull/26049), thanks [@ndelangen](https://github.com/ndelangen)!\n- Core: Fix addon bundling script - [#26145](https://github.com/storybookjs/storybook/pull/26145), thanks [@ndelangen](https://github.com/ndelangen)!\n- Vue3: Fix SourceDecorator Exception - [#25773](https://github.com/storybookjs/storybook/pull/25773), thanks [@chakAs3](https://github.com/chakAs3)!\n- Vue: Replace vue-docgen-api with Volar vue-component-meta - [#22285](https://github.com/storybookjs/storybook/pull/22285), thanks [@chakAs3](https://github.com/chakAs3)!\n\n## 8.0.0-beta.4\n\n- Addon-actions: Warn when argTypesRegex is used together with the visual test addon - [#26094](https://github.com/storybookjs/storybook/pull/26094), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Addon-docs: Fix Table of Contents heading leak - [#23677](https://github.com/storybookjs/storybook/pull/23677), thanks [@vmizg](https://github.com/vmizg)!\n- CLI: Add `legacyMdx1` & `@storybook/mdx1-csf` automigration - [#26102](https://github.com/storybookjs/storybook/pull/26102), thanks [@ndelangen](https://github.com/ndelangen)!\n- CLI: Add line ignoring storybook's `.log` files upon `init` - [#26099](https://github.com/storybookjs/storybook/pull/26099), thanks [@ndelangen](https://github.com/ndelangen)!\n- CLI: Add support for custom vite config to autoblocker - [#26087](https://github.com/storybookjs/storybook/pull/26087), thanks [@ndelangen](https://github.com/ndelangen)!\n- CLI: Add webpack5 compiler automigration - [#26000](https://github.com/storybookjs/storybook/pull/26000), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- CLI: Remove argTypesRegex automigration - [#26001](https://github.com/storybookjs/storybook/pull/26001), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- CLI: Remove the logging to file feature from autoblockers - [#26100](https://github.com/storybookjs/storybook/pull/26100), thanks [@ndelangen](https://github.com/ndelangen)!\n- Core: Add addon removal telemetry - [#26077](https://github.com/storybookjs/storybook/pull/26077), thanks [@shilman](https://github.com/shilman)!\n- Core: Fix fail to load `main.ts` error message - [#26035](https://github.com/storybookjs/storybook/pull/26035), thanks [@ndelangen](https://github.com/ndelangen)!\n- Core: Update ip version to fix CVE-2023-42282 - [#26086](https://github.com/storybookjs/storybook/pull/26086), thanks [@drik98](https://github.com/drik98)!\n- Next.js: Support getImageProps API - [#25745](https://github.com/storybookjs/storybook/pull/25745), thanks [@piratetaco](https://github.com/piratetaco)!\n- Svelte: Remove deprecated SvelteComponentTyped in favor of SvelteComponent - [#26113](https://github.com/storybookjs/storybook/pull/26113), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Vite: Fix bug that meant we always warned about TS plugin - [#26051](https://github.com/storybookjs/storybook/pull/26051), thanks [@tmeasday](https://github.com/tmeasday)!\n- Vite: Fix config typing issue of the `typescript` property - [#26046](https://github.com/storybookjs/storybook/pull/26046), thanks [@ndelangen](https://github.com/ndelangen)!\n- Vite: Fix issue getting preview stats with Vite builder - [#26093](https://github.com/storybookjs/storybook/pull/26093), thanks [@tmeasday](https://github.com/tmeasday)!\n\n## 8.0.0-beta.3\n\n- Addon-actions: Add spy to action for explicit actions - [#26033](https://github.com/storybookjs/storybook/pull/26033), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Addon-themes: Make type generic less strict - [#26042](https://github.com/storybookjs/storybook/pull/26042), thanks [@yannbf](https://github.com/yannbf)!\n- Addon-docs: Fix pnpm+Vite failing to build with `@storybook/theming` Rollup error - [#26024](https://github.com/storybookjs/storybook/pull/26024), thanks [@JReinhold](https://github.com/JReinhold)!\n- CLI: Refactor to add autoblockers - [#25934](https://github.com/storybookjs/storybook/pull/25934), thanks [@ndelangen](https://github.com/ndelangen)!\n- Codemod: Migrate to test package - [#25958](https://github.com/storybookjs/storybook/pull/25958), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Portable stories: Only provide a play function wrapper if it exists - [#25974](https://github.com/storybookjs/storybook/pull/25974), thanks [@yannbf](https://github.com/yannbf)!\n- Test: Bump user-event to 14.5.2 - [#25889](https://github.com/storybookjs/storybook/pull/25889), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n\n## 8.0.0-beta.2\n\n- Core: Fix boolean `true` args in URL getting ignored - [#25950](https://github.com/storybookjs/storybook/pull/25950), thanks [@JReinhold](https://github.com/JReinhold)!\n- Core: Move @types packages to dev deps in core-common - [#25387](https://github.com/storybookjs/storybook/pull/25387), thanks [@kyletsang](https://github.com/kyletsang)!\n- Maintenance: Rename testing-utils paths to portable-stories - [#25888](https://github.com/storybookjs/storybook/pull/25888), thanks [@yannbf](https://github.com/yannbf)!\n- Portable stories: Pass story context to the play function of a composed story - [#25943](https://github.com/storybookjs/storybook/pull/25943), thanks [@yannbf](https://github.com/yannbf)!\n- UI: Fix `display=true` warning in console - [#25951](https://github.com/storybookjs/storybook/pull/25951), thanks [@JReinhold](https://github.com/JReinhold)!\n- UI: Update deprecated Icons with the new @storybook/icons in addons - [#25822](https://github.com/storybookjs/storybook/pull/25822), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- Vite: Add a `rollup-plugin-webpack-stats` to allow stats from preview builds - [#25923](https://github.com/storybookjs/storybook/pull/25923), thanks [@tmeasday](https://github.com/tmeasday)!\n\n## 8.0.0-beta.1\n\n- Addon-docs: Fix MDX components not applied in Vite and theme loading twice - [#25925](https://github.com/storybookjs/storybook/pull/25925), thanks [@JReinhold](https://github.com/JReinhold)!\n- Core: Fix React peer dependency warnings - [#25926](https://github.com/storybookjs/storybook/pull/25926), thanks [@JReinhold](https://github.com/JReinhold)!\n- Core: Remove CSF batching, as it isn't required any more - [#25872](https://github.com/storybookjs/storybook/pull/25872), thanks [@tmeasday](https://github.com/tmeasday)!\n- Next.js: Fix frameworkOptions resolution - [#25907](https://github.com/storybookjs/storybook/pull/25907), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- React Native: Fix init fails when package is already installed - [#25908](https://github.com/storybookjs/storybook/pull/25908), thanks [@dannyhw](https://github.com/dannyhw)!\n- React Native: Remove watcher from init - [#25895](https://github.com/storybookjs/storybook/pull/25895), thanks [@dannyhw](https://github.com/dannyhw)!\n- Test: Fix jest-dom matcher type imports - [#25869](https://github.com/storybookjs/storybook/pull/25869), thanks [@alitas](https://github.com/alitas)!\n- UI: Fix overlapping on the ref button in the sidebar - [#25914](https://github.com/storybookjs/storybook/pull/25914), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- UI: Remove keyboard shortcut hint in search bar on mobile viewports - [#25866](https://github.com/storybookjs/storybook/pull/25866), thanks [@tusharwebd](https://github.com/tusharwebd)!\n\n## 8.0.0-beta.0\n\n- CLI: Add Visual Tests addon to `init` - [#25850](https://github.com/storybookjs/storybook/pull/25850), thanks [@shilman](https://github.com/shilman)!\n- CLI: Upgrade boxen library - [#25713](https://github.com/storybookjs/storybook/pull/25713), thanks [@yannbf](https://github.com/yannbf)!\n- UI: Fix custom tabs not showing in the manager - [#25792](https://github.com/storybookjs/storybook/pull/25792), thanks [@ndelangen](https://github.com/ndelangen)!\n\n## 8.0.0-alpha.17\n\n- CLI: Fix add command for non monorepo deps - [#25791](https://github.com/storybookjs/storybook/pull/25791), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Core: Fix `--test` must be passed for `build.test` values to be set. - [#25828](https://github.com/storybookjs/storybook/pull/25828), thanks [@ndelangen](https://github.com/ndelangen)!\n- Test: Fix vitest patch to work with portable stories and upgrade testing-library/jest-dom - [#25840](https://github.com/storybookjs/storybook/pull/25840), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- UI: Fix sidebar top and bottom addons not showing - [#25825](https://github.com/storybookjs/storybook/pull/25825), thanks [@ndelangen](https://github.com/ndelangen)!\n- Webpack: Update StorybookConfig import in core-webpack types.ts - [#25740](https://github.com/storybookjs/storybook/pull/25740), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n\n## 8.0.0-alpha.16\n\n- CLI: Fix `upgrade` detecting the wrong version of existing Storybooks - [#25752](https://github.com/storybookjs/storybook/pull/25752), thanks [@JReinhold](https://github.com/JReinhold)!\n- CLI: Update init for react native v7 - [#25780](https://github.com/storybookjs/storybook/pull/25780), thanks [@dannyhw](https://github.com/dannyhw)!\n- UI: Improve how the addon panel work on mobile - [#25787](https://github.com/storybookjs/storybook/pull/25787), thanks [@cdedreuille](https://github.com/cdedreuille)!\n\n## 8.0.0-alpha.15\n\n- Next.js: Add logger statements for compiler selection - [#25755](https://github.com/storybookjs/storybook/pull/25755), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- React-Native: Fixes for v8 compatibility - [#25678](https://github.com/storybookjs/storybook/pull/25678), thanks [@shilman](https://github.com/shilman)!\n- UI: Remove use of React.FC in components - [#25588](https://github.com/storybookjs/storybook/pull/25588), thanks [@ShaunEvening](https://github.com/ShaunEvening)!\n- Vue3: Fix support for `onX` and empty attributes in Show Code - [#25219](https://github.com/storybookjs/storybook/pull/25219), thanks [@Tap-Kim](https://github.com/Tap-Kim)!\n- Vue3: Introduce portable stories API - [#25443](https://github.com/storybookjs/storybook/pull/25443), thanks [@yannbf](https://github.com/yannbf)!\n\n## 8.0.0-alpha.14\n\n- Addons: Remove Node.js internal aliasing for Node builds - [#25712](https://github.com/storybookjs/storybook/pull/25712), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Automigration: Add removeReactDependency fix to allFixes array - [#25717](https://github.com/storybookjs/storybook/pull/25717), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Codemods: Add support for multiple file extensions in runCodemod function - [#25708](https://github.com/storybookjs/storybook/pull/25708), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Next.js: Add webpack aliases for OpenTelemetry API - [#25652](https://github.com/storybookjs/storybook/pull/25652), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- UI: Remove `defaultProps` from `Link` component - [#25619](https://github.com/storybookjs/storybook/pull/25619), thanks [@tsvanharen](https://github.com/tsvanharen)!\n\n## 8.0.0-alpha.13\n\n- Next.js: Fix SWC mode activation - [#25670](https://github.com/storybookjs/storybook/pull/25670), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n\n## 8.0.0-alpha.12\n\n- Blocks: Fix Controls block not having controls - [#25663](https://github.com/storybookjs/storybook/pull/25663), thanks [@JReinhold](https://github.com/JReinhold)!\n- Blocks: Support `subcomponents` in `ArgTypes` and `Controls`, remove `ArgsTable` block - [#25614](https://github.com/storybookjs/storybook/pull/25614), thanks [@JReinhold](https://github.com/JReinhold)!\n- CLI: Fix existing version detection in `upgrade` - [#25642](https://github.com/storybookjs/storybook/pull/25642), thanks [@JReinhold](https://github.com/JReinhold)!\n- Core: Add preset with experimental server API - [#25664](https://github.com/storybookjs/storybook/pull/25664), thanks [@shilman](https://github.com/shilman)!\n- MDX: Replace remark by rehype plugins - [#25615](https://github.com/storybookjs/storybook/pull/25615), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- React: Fix acorn ecma version warning - [#25634](https://github.com/storybookjs/storybook/pull/25634), thanks [@dannyhw](https://github.com/dannyhw)!\n- Shortcuts: Require modifier key to trigger shortcuts (`F`,`A`,`D`,`S`,`T`,`/`) - [#25625](https://github.com/storybookjs/storybook/pull/25625), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- Theming: Fix export of module augmentation - [#25643](https://github.com/storybookjs/storybook/pull/25643), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- UI: Add links to documentation and videos in UI - [#25565](https://github.com/storybookjs/storybook/pull/25565), thanks [@Integrayshaun](https://github.com/Integrayshaun)!\n- Webpack: Use `node:assert` used in `export-order-loader` - [#25622](https://github.com/storybookjs/storybook/pull/25622), thanks [@JReinhold](https://github.com/JReinhold)!\n\n## 8.0.0-alpha.11\n\n- Angular: Remove cached NgModules and introduce a global queue during bootstrapping - [#24982](https://github.com/storybookjs/storybook/pull/24982), thanks [@Marklb](https://github.com/Marklb)!\n- CLI: Fix sandbox command versioning - [#25600](https://github.com/storybookjs/storybook/pull/25600), thanks [@ndelangen](https://github.com/ndelangen)!\n- CLI: Support upgrading to canary versions - [#25596](https://github.com/storybookjs/storybook/pull/25596), thanks [@JReinhold](https://github.com/JReinhold)!\n- ConfigFile: Fix export specifiers - [#25590](https://github.com/storybookjs/storybook/pull/25590), thanks [@shilman](https://github.com/shilman)!\n- Interaction: Replace @storybook/jest by @storybook/test - [#25584](https://github.com/storybookjs/storybook/pull/25584), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Next.js: Pass jsConfig to SWC Loader and load config with defaults - [#25203](https://github.com/storybookjs/storybook/pull/25203), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Parameters: Remove passArgsFirst flag - [#25585](https://github.com/storybookjs/storybook/pull/25585), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Preset: Remove deprecated config preset - [#25607](https://github.com/storybookjs/storybook/pull/25607), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- React: Refactor RSC out of Next - [#25591](https://github.com/storybookjs/storybook/pull/25591), thanks [@shilman](https://github.com/shilman)!\n- Sandboxes: Update wait-on command to use TCP instead of HTTP - [#25541](https://github.com/storybookjs/storybook/pull/25541), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Telejson: Update stringify options in codebase - [#25564](https://github.com/storybookjs/storybook/pull/25564), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- UI: Fix menu icon on the sidebar - [#25587](https://github.com/storybookjs/storybook/pull/25587), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- Webpack5: Make export-order-loader compatible with both esm and cjs - [#25540](https://github.com/storybookjs/storybook/pull/25540), thanks [@mlazari](https://github.com/mlazari)!\n\n## 8.0.0-alpha.10\n\n- API: Remove deprecations from manager and preview api - [#25536](https://github.com/storybookjs/storybook/pull/25536), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Addon Controls: Remove unused hideNoControlsWarning type - [#25417](https://github.com/storybookjs/storybook/pull/25417), thanks [@yannbf](https://github.com/yannbf)!\n- Addon Remark-GFM: Upgrade remark-gfm - [#25301](https://github.com/storybookjs/storybook/pull/25301), thanks [@yannbf](https://github.com/yannbf)!\n- Addon-actions: Fix module resolution for react-native - [#25296](https://github.com/storybookjs/storybook/pull/25296), thanks [@dannyhw](https://github.com/dannyhw)!\n- Angular: Remove deprecated Story type - [#25558](https://github.com/storybookjs/storybook/pull/25558), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- CLI: Add addon `remove` command - [#25538](https://github.com/storybookjs/storybook/pull/25538), thanks [@shilman](https://github.com/shilman)!\n- CLI: Check optionalDependencies for storybook versions - [#25406](https://github.com/storybookjs/storybook/pull/25406), thanks [@reyronald](https://github.com/reyronald)!\n- CLI: Sandbox script should use current version to init - [#25560](https://github.com/storybookjs/storybook/pull/25560), thanks [@ndelangen](https://github.com/ndelangen)!\n- CLI: Versioned installation of monorepo packages - [#25517](https://github.com/storybookjs/storybook/pull/25517), thanks [@ndelangen](https://github.com/ndelangen)!\n- CLI: Versioned upgrade of monorepo packages - [#25553](https://github.com/storybookjs/storybook/pull/25553), thanks [@JReinhold](https://github.com/JReinhold)!\n- Core: Prevent stories lookup in node_modules - [#25214](https://github.com/storybookjs/storybook/pull/25214), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Core: Refactor preview and deprecate story store - [#24926](https://github.com/storybookjs/storybook/pull/24926), thanks [@tmeasday](https://github.com/tmeasday)!\n- Doc blocks: Remove deprecated props from Primary block - [#25461](https://github.com/storybookjs/storybook/pull/25461), thanks [@yannbf](https://github.com/yannbf)!\n- Doc blocks: Remove deprecated props from Source block - [#25459](https://github.com/storybookjs/storybook/pull/25459), thanks [@yannbf](https://github.com/yannbf)!\n- Doc blocks: Remove deprecated props from Story block - [#25460](https://github.com/storybookjs/storybook/pull/25460), thanks [@yannbf](https://github.com/yannbf)!\n- Maintenance: Pin TS to >= 4.2 as typefest 2 requires it - [#25548](https://github.com/storybookjs/storybook/pull/25548), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Maintenance: Upgrade to prettier 3 - [#25524](https://github.com/storybookjs/storybook/pull/25524), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Remove deprecated properties from manager-api - [#25578](https://github.com/storybookjs/storybook/pull/25578), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Test: Fix user event being inlined by tsup by using an interface - [#25547](https://github.com/storybookjs/storybook/pull/25547), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Test: Upgrade test package to vitest 1.1.3 - [#25576](https://github.com/storybookjs/storybook/pull/25576), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- UI: Add configurable tags-based exclusion from sidebar/autodocs - [#25328](https://github.com/storybookjs/storybook/pull/25328), thanks [@shilman](https://github.com/shilman)!\n- Webpack: Remove deprecated standalone webpackConfig option - [#25481](https://github.com/storybookjs/storybook/pull/25481), thanks [@yannbf](https://github.com/yannbf)!\n\n## 8.0.0-alpha.9\n\n- AutoTitle: Fix case-insensitive trailing duplicate - [#25452](https://github.com/storybookjs/storybook/pull/25452), thanks [@ksugawara61](https://github.com/ksugawara61)!\n- CLI: Fix using wrong package managers in existing projects - [#25474](https://github.com/storybookjs/storybook/pull/25474), thanks [@JReinhold](https://github.com/JReinhold)!\n- CLI: Never prompt for ESLint plugin - [#25289](https://github.com/storybookjs/storybook/pull/25289), thanks [@shilman](https://github.com/shilman)!\n- CSF-tools: Allow type checking in storySort - [#25265](https://github.com/storybookjs/storybook/pull/25265), thanks [@honzahruby](https://github.com/honzahruby)!\n- Core: Remove `storyStoreV7` feature flag - [#24658](https://github.com/storybookjs/storybook/pull/24658), thanks [@ndelangen](https://github.com/ndelangen)!\n- Core: Remove deprecated createChannel APIs - [#25487](https://github.com/storybookjs/storybook/pull/25487), thanks [@yannbf](https://github.com/yannbf)!\n- Node.js: Update version requirement to >= 18.0.0 - [#25516](https://github.com/storybookjs/storybook/pull/25516), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Storysource: Fix import error - [#25391](https://github.com/storybookjs/storybook/pull/25391), thanks [@unional](https://github.com/unional)!\n- UI: Fix sidebar top and bottom addon slots - [#25426](https://github.com/storybookjs/storybook/pull/25426), thanks [@ndelangen](https://github.com/ndelangen)!\n- Webpack5: Remove babel and SWC compiler from builder - [#25379](https://github.com/storybookjs/storybook/pull/25379), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n\n## 8.0.0-alpha.8\n\n- Addon Links: Remove LinkTo from direct import - [#25418](https://github.com/storybookjs/storybook/pull/25418), thanks [@yannbf](https://github.com/yannbf)!\n- Addon docs: Remove deprecated parameters - [#25469](https://github.com/storybookjs/storybook/pull/25469), thanks [@yannbf](https://github.com/yannbf)!\n- Builder Vite: Remove StorybookViteConfig type in favor of StorybookConfig - [#25441](https://github.com/storybookjs/storybook/pull/25441), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Error on explicit actions while rendering or playing - [#25238](https://github.com/storybookjs/storybook/pull/25238), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Core: Remove collapseAll and expandAll methods - [#25486](https://github.com/storybookjs/storybook/pull/25486), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Remove storyIndexers in favor of experimental_indexers - [#25468](https://github.com/storybookjs/storybook/pull/25468), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Remove unused staticDir type - [#25415](https://github.com/storybookjs/storybook/pull/25415), thanks [@yannbf](https://github.com/yannbf)!\n- Doc blocks: Remove deprecated props from Description block - [#25457](https://github.com/storybookjs/storybook/pull/25457), thanks [@yannbf](https://github.com/yannbf)!\n- Manager API: Remove deprecated navigateToSettingsPage method - [#25467](https://github.com/storybookjs/storybook/pull/25467), thanks [@yannbf](https://github.com/yannbf)!\n- React: Remove deprecated setGlobalConfig portable stories api - [#25442](https://github.com/storybookjs/storybook/pull/25442), thanks [@yannbf](https://github.com/yannbf)!\n- TypeScript: Remove deprecated addons module types - [#25485](https://github.com/storybookjs/storybook/pull/25485), thanks [@yannbf](https://github.com/yannbf)!\n- Types: Remove DecoratorFn, Story, ComponentStory, ComponentStoryObj, ComponentStoryFn and ComponentMeta types - [#25477](https://github.com/storybookjs/storybook/pull/25477), thanks [@yannbf](https://github.com/yannbf)!\n- Types: Remove Framework in favor of Renderer types - [#25476](https://github.com/storybookjs/storybook/pull/25476), thanks [@yannbf](https://github.com/yannbf)!\n- UI: Remove deprecated WithTooltip props - [#25440](https://github.com/storybookjs/storybook/pull/25440), thanks [@yannbf](https://github.com/yannbf)!\n\n## 8.0.0-alpha.7\n\n- Addon-Docs: Upgrade to MDX3 - [#25303](https://github.com/storybookjs/storybook/pull/25303), thanks [@yannbf](https://github.com/yannbf)!\n- CLI: Add Storyshots migration notice - [#25327](https://github.com/storybookjs/storybook/pull/25327), thanks [@yannbf](https://github.com/yannbf)!\n- CLI: Fix regex used in upgrade command - [#25284](https://github.com/storybookjs/storybook/pull/25284), thanks [@yannbf](https://github.com/yannbf)!\n- CLI: Remove --use-npm flag - [#25414](https://github.com/storybookjs/storybook/pull/25414), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Remove unused warnOnLegacyHierarchySeparator type - [#25416](https://github.com/storybookjs/storybook/pull/25416), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Remove vite plugins and drop Vite 3 support - [#25427](https://github.com/storybookjs/storybook/pull/25427), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Maintenance: Add comment to deprecation notice in Button component - [#25411](https://github.com/storybookjs/storybook/pull/25411), thanks [@yannbf](https://github.com/yannbf)!\n- UI: Fix about page layout - [#25396](https://github.com/storybookjs/storybook/pull/25396), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- Viewport: Store viewport, rotation in globals - [#25423](https://github.com/storybookjs/storybook/pull/25423), thanks [@shilman](https://github.com/shilman)!\n- Vite: Fix Vite 5 CJS warnings - [#25005](https://github.com/storybookjs/storybook/pull/25005), thanks [@JReinhold](https://github.com/JReinhold)!\n\n## 8.0.0-alpha.6\n\n- NextJS: Autoconfigure public directory for new projects - [#25279](https://github.com/storybookjs/storybook/pull/25279), thanks [@shilman](https://github.com/shilman)!\n- Vite: Fix pre-transform error in Vite 5 - [#25329](https://github.com/storybookjs/storybook/pull/25329), thanks [@yannbf](https://github.com/yannbf)!\n- Vue3: Fix pnp by making compiler-core a dependency - [#25311](https://github.com/storybookjs/storybook/pull/25311), thanks [@shilman](https://github.com/shilman)!\n\n## 8.0.0-alpha.5\n\n- Core: Remove the `-s` flag from build & dev - [#25266](https://github.com/storybookjs/storybook/pull/25266), thanks [@ndelangen](https://github.com/ndelangen)!\n- Core: Skip no-framework error when ignorePreview=true - [#25286](https://github.com/storybookjs/storybook/pull/25286), thanks [@ndelangen](https://github.com/ndelangen)!\n- Core: Unique outputDir/cacheDir for each configDir - [#25264](https://github.com/storybookjs/storybook/pull/25264), thanks [@ndelangen](https://github.com/ndelangen)!\n- Dependencies: Semver dependency fixes - [#25283](https://github.com/storybookjs/storybook/pull/25283), thanks [@ndelangen](https://github.com/ndelangen)!\n- NextJS: Mock out `server-only` package for RSC - [#25263](https://github.com/storybookjs/storybook/pull/25263), thanks [@shilman](https://github.com/shilman)!\n\n## 8.0.0-alpha.4\n\n- API: Remove stories.json support - [#25236](https://github.com/storybookjs/storybook/pull/25236), thanks [@shilman](https://github.com/shilman)!\n- Addon Docs: Remove `react` peer dependency - [#24881](https://github.com/storybookjs/storybook/pull/24881), thanks [@JReinhold](https://github.com/JReinhold)!\n- Addon-docs: Support `<StrictMode />` and `<Suspense />` in source viewer - [#19785](https://github.com/storybookjs/storybook/pull/19785), thanks [@zhyd1997](https://github.com/zhyd1997)!\n- Angular: Add random attribute to bootstrapped selector - [#24972](https://github.com/storybookjs/storybook/pull/24972), thanks [@Marklb](https://github.com/Marklb)!\n- Angular: Reduce the warnings from `ts-loader` via stricter list of `includes` - [#24531](https://github.com/storybookjs/storybook/pull/24531), thanks [@ndelangen](https://github.com/ndelangen)!\n- Blocks: Render colors in the same order as provided - [#25001](https://github.com/storybookjs/storybook/pull/25001), thanks [@kaelig](https://github.com/kaelig)!\n- CLI: Add prompt-only automigrate asking for react-removal - [#25215](https://github.com/storybookjs/storybook/pull/25215), thanks [@ndelangen](https://github.com/ndelangen)!\n- CLI: No longer add react in init - [#25196](https://github.com/storybookjs/storybook/pull/25196), thanks [@ndelangen](https://github.com/ndelangen)!\n- Core: Set bundle target to `node18` - [#25239](https://github.com/storybookjs/storybook/pull/25239), thanks [@shilman](https://github.com/shilman)!\n- SvelteKit: Fix missing `$app` modules - [#25132](https://github.com/storybookjs/storybook/pull/25132), thanks [@paoloricciuti](https://github.com/paoloricciuti)!\n- SvelteKit: Support 2.0 modules with mocks - [#25244](https://github.com/storybookjs/storybook/pull/25244), thanks [@paoloricciuti](https://github.com/paoloricciuti)!\n- UI: Embed `react-textarea-autosize` types - [#25235](https://github.com/storybookjs/storybook/pull/25235), thanks [@ndelangen](https://github.com/ndelangen)!\n\n## 8.0.0-alpha.3\n\n- Addon-docs: Fix storybook MDX check - [#24696](https://github.com/storybookjs/storybook/pull/24696), thanks [@shilman](https://github.com/shilman)!\n- Addons: Remove unused postinstall package - [#25150](https://github.com/storybookjs/storybook/pull/25150), thanks [@shilman](https://github.com/shilman)!\n- Angular: Update Angular cli templates - [#25152](https://github.com/storybookjs/storybook/pull/25152), thanks [@Marklb](https://github.com/Marklb)!\n- Blocks: Fix Subtitle block for unattached docs pages - [#25157](https://github.com/storybookjs/storybook/pull/25157), thanks [@kripod](https://github.com/kripod)!\n- Ember: Fix @storybook/ember - [#23435](https://github.com/storybookjs/storybook/pull/23435), thanks [@francois2metz](https://github.com/francois2metz)!\n- Maintenance: Set engines field to Node.js >= 18 for packages - [#25105](https://github.com/storybookjs/storybook/pull/25105), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n\n## 8.0.0-alpha.2\n\n- Core: Maintenance changes for NextJS embedding - [#25086](https://github.com/storybookjs/storybook/pull/25086), thanks [@shilman](https://github.com/shilman)!\n- Addon-docs: Fix story anchors using encodeURIComponent - [#25062](https://github.com/storybookjs/storybook/pull/25062), thanks [@xyy94813](https://github.com/xyy94813)!\n- CLI: Generate a new project on init in empty directory - [#24997](https://github.com/storybookjs/storybook/pull/24997), thanks [@Integrayshaun](https://github.com/Integrayshaun)!\n- Svelte: Support v5 prereleases - [#24889](https://github.com/storybookjs/storybook/pull/24889), thanks [@allozaur](https://github.com/allozaur)!\n- Vue: Remove deprecated vue packages from next - [#25108](https://github.com/storybookjs/storybook/pull/25108), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Vue: Remove unused preset-vue-webpack - [#25151](https://github.com/storybookjs/storybook/pull/25151), thanks [@shilman](https://github.com/shilman)!\n\n## 8.0.0-alpha.1\n\n- Angular: Drop v14.x support - [#25101](https://github.com/storybookjs/storybook/pull/25101), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Angular: Fix CSF Plugin - [#25098](https://github.com/storybookjs/storybook/pull/25098), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Build: Fix Angular sandbox - [#23896](https://github.com/storybookjs/storybook/pull/23896), thanks [@Marklb](https://github.com/Marklb)!\n- CLI: Improve dependency metadata detection in storybook doctor - [#25037](https://github.com/storybookjs/storybook/pull/25037), thanks [@yannbf](https://github.com/yannbf)!\n- CLI: Point the update-notice to the changelog in the suggested version - [#19911](https://github.com/storybookjs/storybook/pull/19911), thanks [@cprecioso](https://github.com/cprecioso)!\n- CLI: Typescript strict mode - [#22254](https://github.com/storybookjs/storybook/pull/22254), thanks [@0916dhkim](https://github.com/0916dhkim)!\n- CSF: Autotitle fix multiple dots and handle stories.js - [#21840](https://github.com/storybookjs/storybook/pull/21840), thanks [@agriffis](https://github.com/agriffis)!\n- Next.js: Add next/font/local declarations support - [#24983](https://github.com/storybookjs/storybook/pull/24983), thanks [@MauricioRobayo](https://github.com/MauricioRobayo)!\n- Next.js: Drop Next.js < v13.5 support - [#25104](https://github.com/storybookjs/storybook/pull/25104), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Next.js: Fix AppRouterProvider usage - [#25032](https://github.com/storybookjs/storybook/pull/25032), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Next.js: Fix next/font/local usage in babel mode - [#25045](https://github.com/storybookjs/storybook/pull/25045), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Next.js: Update validateData function for next/font compatibility - [#25061](https://github.com/storybookjs/storybook/pull/25061), thanks [@kkirby](https://github.com/kkirby)!\n- NextJS: Add experimental RSC support - [#25091](https://github.com/storybookjs/storybook/pull/25091), thanks [@shilman](https://github.com/shilman)!\n- React-Docgen: Make error-handling more gentle - [#25055](https://github.com/storybookjs/storybook/pull/25055), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- React: Change `StoryFnReactReturnType` to `JSX.Element` - [#23204](https://github.com/storybookjs/storybook/pull/23204), thanks [@chakAs3](https://github.com/chakAs3)!\n- React: Set `react-docgen` to default TS docgen - [#24165](https://github.com/storybookjs/storybook/pull/24165), thanks [@shilman](https://github.com/shilman)!\n- SvelteKit: Fix HMR not working - [#25031](https://github.com/storybookjs/storybook/pull/25031), thanks [@JReinhold](https://github.com/JReinhold)!\n- TypeScript: Migrate `@storybook/docs-tools` to strict TS - [#22567](https://github.com/storybookjs/storybook/pull/22567), thanks [@efrenaragon96](https://github.com/efrenaragon96)!\n- UI: Add stricter types to the language property of the SyntaxHighlighter - [#22790](https://github.com/storybookjs/storybook/pull/22790), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Viewport: Fix viewport dts files - [#25107](https://github.com/storybookjs/storybook/pull/25107), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Webpack: Fix exclude regex in react-docgen-loader - [#25030](https://github.com/storybookjs/storybook/pull/25030), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n\n## 8.0.0-alpha.0\n\n- Addon Viewport: Expose types for user parameter validation - [#24896](https://github.com/storybookjs/storybook/pull/24896), thanks [@piratetaco](https://github.com/piratetaco)!\n- Packages: Remove unused/deprecated packages - [#24528](https://github.com/storybookjs/storybook/pull/24528), thanks [@ndelangen](https://github.com/ndelangen)!\n- Vite: use user's `build.target` - [#23123](https://github.com/storybookjs/storybook/pull/23123), thanks [@Hoishin](https://github.com/Hoishin)!\n- CLI: Remove `sb extract` command - [#24653](https://github.com/storybookjs/storybook/pull/24653), thanks [@ndelangen](https://github.com/ndelangen)!\n- Core: Improve project root detection logic - [#20791](https://github.com/storybookjs/storybook/pull/20791), thanks [@dobesv](https://github.com/dobesv)!\n- Core: Prebundling globalize the core-event sub paths - [#24976](https://github.com/storybookjs/storybook/pull/24976), thanks [@ndelangen](https://github.com/ndelangen)!\n- Core: Remove `storiesOf`-API - [#24655](https://github.com/storybookjs/storybook/pull/24655), thanks [@ndelangen](https://github.com/ndelangen)!\n- Core: `StorybookConfig` `stories`-field support type async function - [#21555](https://github.com/storybookjs/storybook/pull/21555), thanks [@imccausl](https://github.com/imccausl)!\n- Dependencies: Update Typescript - [#24970](https://github.com/storybookjs/storybook/pull/24970), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Dependencies: Upgrade monorepo to TS5 - [#24440](https://github.com/storybookjs/storybook/pull/24440), thanks [@ndelangen](https://github.com/ndelangen)!\n- TypeScript: Migrate `@storybook/preset-create-react-app` to strict TS - [#22395](https://github.com/storybookjs/storybook/pull/22395), thanks [@kuriacka](https://github.com/kuriacka)!\n- Manager: Enable refs filtered via `experimental_setFilter` - [#24211](https://github.com/storybookjs/storybook/pull/24211), thanks [@ndelangen](https://github.com/ndelangen)!\n- MDX: Theme `fontCode` not applied consistently when writing MDX - [#23110](https://github.com/storybookjs/storybook/pull/23110), thanks [@gitstart-storybook](https://github.com/gitstart-storybook)!\n- UI: Bring back role main - [#24411](https://github.com/storybookjs/storybook/pull/24411), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- UI: Fix `IconButton` not being aligned correctly in blocks - [#24529](https://github.com/storybookjs/storybook/pull/24529), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- UI: Fix button size on controls - [#24737](https://github.com/storybookjs/storybook/pull/24737), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- UI: Fix layout height - [#24370](https://github.com/storybookjs/storybook/pull/24370), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- UI: Fix notifications not appearing in new layout - [#24281](https://github.com/storybookjs/storybook/pull/24281), thanks [@jreinhold](https://github.com/jreinhold)!\n- UI: Fix theming not updating - [#24399](https://github.com/storybookjs/storybook/pull/24399), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- UI: Improved `Button` and `IconButton` - [#24266](https://github.com/storybookjs/storybook/pull/24266), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- UI: Keep mobile drawer open on component selection - [#24258](https://github.com/storybookjs/storybook/pull/24258), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- UI: Mobile truncate story name - [#24372](https://github.com/storybookjs/storybook/pull/24372), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- UI: New icon library - [#24433](https://github.com/storybookjs/storybook/pull/24433), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- UI: Replace `Form.Button` with the new `Button` component - [#24360](https://github.com/storybookjs/storybook/pull/24360), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- UI: Screen reader announcing changes for expand/collapse button - [#24984](https://github.com/storybookjs/storybook/pull/24984), thanks [@wjdtjdgns](https://github.com/wjdtjdgns)!\n- UI: Upgrade manager to React v18 - [#24514](https://github.com/storybookjs/storybook/pull/24514), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: sidebar UI updates - [#24707](https://github.com/storybookjs/storybook/pull/24707), thanks [@cdedreuille](https://github.com/cdedreuille)!\n\n## 7.6.0-beta.2\n\n- Actions: Fix `@storybook/core-events/preview-errors` dependency missing for Yarn PnP - [#24973](https://github.com/storybookjs/storybook/pull/24973), thanks [@JReinhold](https://github.com/JReinhold)!\n- Webpack5: Resolve circular dependency and fix HMR - [#24974](https://github.com/storybookjs/storybook/pull/24974), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n\n## 7.6.0-beta.1\n\n- SvelteKit: Default to log an action for `goto`, `invalidate` and `invalidateAll` - [#24955](https://github.com/storybookjs/storybook/pull/24955), thanks [@paoloricciuti](https://github.com/paoloricciuti)!\n\n## 7.6.0-beta.0\n\n- Next.js: Remove duplicate Fast Refresh plugin init - [#24963](https://github.com/storybookjs/storybook/pull/24963), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Test: Don't attach action to function mock if action was added already - [#24966](https://github.com/storybookjs/storybook/pull/24966), thanks [@tmeasday](https://github.com/tmeasday)!\n\n## 7.6.0-alpha.7\n\n- Actions: Warn on implicit actions - [#24856](https://github.com/storybookjs/storybook/pull/24856), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Addons, core: Make `react` and Storybook packages `devDependencies` where possible - ATTEMPT 2 - [#24834](https://github.com/storybookjs/storybook/pull/24834), thanks [@JReinhold](https://github.com/JReinhold)!\n- CLI: Add \"doctor\" command - [#22236](https://github.com/storybookjs/storybook/pull/22236), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Add deprecation notice for Vite + CommonJS - [#23950](https://github.com/storybookjs/storybook/pull/23950), thanks [@JReinhold](https://github.com/JReinhold)!\n- Core: Detect no matching export error in storybook start and build - [#24877](https://github.com/storybookjs/storybook/pull/24877), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Fix `useStoryPrepared` hook failing with `undefined` data - [#22631](https://github.com/storybookjs/storybook/pull/22631), thanks [@SpookyJelly](https://github.com/SpookyJelly)!\n- Core: Gracefully handle error when parsing preview.js file - [#24858](https://github.com/storybookjs/storybook/pull/24858), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Make warnOnIncompatibleAddons fault-tolerant - [#24880](https://github.com/storybookjs/storybook/pull/24880), thanks [@taozhou-glean](https://github.com/taozhou-glean)!\n- Dependency: Fix Yarn 4 failing to install due to jscodeshift dependency issue - [#24914](https://github.com/storybookjs/storybook/pull/24914), thanks [@samvv](https://github.com/samvv)!\n- Dependency: Update jscodeshift to v0.15.1 - [#24882](https://github.com/storybookjs/storybook/pull/24882), thanks [@epreston](https://github.com/epreston)!\n- FastBuild: Fix disabledAddons filter - [#24924](https://github.com/storybookjs/storybook/pull/24924), thanks [@IanVS](https://github.com/IanVS)!\n- ManagerAPI: Fix setting status without index, crashes storybook - [#24866](https://github.com/storybookjs/storybook/pull/24866), thanks [@ndelangen](https://github.com/ndelangen)!\n- Next.js: Add back image context CommonJS export - [#24885](https://github.com/storybookjs/storybook/pull/24885), thanks [@martinnabhan](https://github.com/martinnabhan)!\n- Next.js: Add experimental SWC support - [#24852](https://github.com/storybookjs/storybook/pull/24852), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Next.js: Fix import path in swc loader - [#24922](https://github.com/storybookjs/storybook/pull/24922), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Svelte: Fix decorators always running twice - [#24921](https://github.com/storybookjs/storybook/pull/24921), thanks [@paoloricciuti](https://github.com/paoloricciuti)!\n- SvelteKit: Add experimental page and navigation mocking - [#24795](https://github.com/storybookjs/storybook/pull/24795), thanks [@paoloricciuti](https://github.com/paoloricciuti)!\n- Test: Model loaders as before each and restore mocks properly - [#24948](https://github.com/storybookjs/storybook/pull/24948), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- TestBuild: Add env-variable support to `--test` CLI-flag - [#24862](https://github.com/storybookjs/storybook/pull/24862), thanks [@ndelangen](https://github.com/ndelangen)!\n- TestBuild: Add tests and rename to camelCase - [#24911](https://github.com/storybookjs/storybook/pull/24911), thanks [@ndelangen](https://github.com/ndelangen)!\n- TestBuild: Fix indexer bug - [#24890](https://github.com/storybookjs/storybook/pull/24890), thanks [@ndelangen](https://github.com/ndelangen)!\n- Typescript: Add 'skipCompiler' option to TypeScript presets - [#24847](https://github.com/storybookjs/storybook/pull/24847), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n\n## 7.6.0-alpha.6\n\n- Addon: Move Visual Test addon to the code directory - [#24771](https://github.com/storybookjs/storybook/pull/24771), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- FastBuild: Improve config loading & naming - [#24837](https://github.com/storybookjs/storybook/pull/24837), thanks [@ndelangen](https://github.com/ndelangen)!\n- TestBuild: Revert defaulting to SWC in test build, but keep using esbuild for minification - [#24843](https://github.com/storybookjs/storybook/pull/24843), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Viewport: Add newer device viewports - [#24777](https://github.com/storybookjs/storybook/pull/24777), thanks [@Tomo5524](https://github.com/Tomo5524)!\n- Vite: Prevent non-deterministic build output - [#24833](https://github.com/storybookjs/storybook/pull/24833), thanks [@henkerik](https://github.com/henkerik)!\n\n## 7.6.0-alpha.5\n\n- Addons, core: Make `react` and Storybook packages `devDependencies` where possible - [#24676](https://github.com/storybookjs/storybook/pull/24676), thanks [@JReinhold](https://github.com/JReinhold)!\n- Angular: Handle nested module metadata - [#24798](https://github.com/storybookjs/storybook/pull/24798), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Angular: Include object configured styles - [#24768](https://github.com/storybookjs/storybook/pull/24768), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Angular: Support v17 - [#24717](https://github.com/storybookjs/storybook/pull/24717), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- ReactNative: Fix missing assert dep in docs-tools - [#24732](https://github.com/storybookjs/storybook/pull/24732), thanks [@dannyhw](https://github.com/dannyhw)!\n- SWC: Add settings for react and preact - [#24805](https://github.com/storybookjs/storybook/pull/24805), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Svelte: Fix source with decorators always showing the `SlotDecorator` component - [#24800](https://github.com/storybookjs/storybook/pull/24800), thanks [@JReinhold](https://github.com/JReinhold)!\n- TestBuild: Disable composition when `--test` is `true` - [#24799](https://github.com/storybookjs/storybook/pull/24799), thanks [@ndelangen](https://github.com/ndelangen)!\n- TestBuild: Disable docs related stuff for test builds - [#24691](https://github.com/storybookjs/storybook/pull/24691), thanks [@ndelangen](https://github.com/ndelangen)!\n- TestBuild: Disable telemetry for test builds - [#24706](https://github.com/storybookjs/storybook/pull/24706), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- TestBuild: Disable warnOnIncompatibleAddons - [#24797](https://github.com/storybookjs/storybook/pull/24797), thanks [@ndelangen](https://github.com/ndelangen)!\n- TestBuild: Globalize `@storybook/blocks` if `build.test.emptyBlocks` is `true` - [#24650](https://github.com/storybookjs/storybook/pull/24650), thanks [@ndelangen](https://github.com/ndelangen)!\n- TestBuild: Implement builder options for test build - [#24826](https://github.com/storybookjs/storybook/pull/24826), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- TestBuild: No sourcemaps for test builds - [#24804](https://github.com/storybookjs/storybook/pull/24804), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: Fix horizontal scroll bar in Canvas hidden by styling - [#24408](https://github.com/storybookjs/storybook/pull/24408), thanks [@yoshi2no](https://github.com/yoshi2no)!\n- UI: Logo fixed value - [#24726](https://github.com/storybookjs/storybook/pull/24726), thanks [@black-arm](https://github.com/black-arm)!\n- UI: improve A11Y remove redundant styling rules, update icon color - [#24402](https://github.com/storybookjs/storybook/pull/24402), thanks [@tolkadot](https://github.com/tolkadot)!\n- Webpack5: Add export-order-loader and remove babel-plugin-named-exports-order - [#24749](https://github.com/storybookjs/storybook/pull/24749), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Webpack5: Add react-docgen loader and remove babel-plugin-react-docgen - [#24762](https://github.com/storybookjs/storybook/pull/24762), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Webpack5: Fix race condition for export-order loader - [#24817](https://github.com/storybookjs/storybook/pull/24817), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Webpack5: Hide critical dependency warning - [#24784](https://github.com/storybookjs/storybook/pull/24784), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n\n## 7.6.0-alpha.4\n\n- CLI: Ensure errors with opening the browser are caught - [#24668](https://github.com/storybookjs/storybook/pull/24668), thanks [@xueyawei](https://github.com/xueyawei)!\n- Babel: Update all @babel/\\* dependencies - [#24610](https://github.com/storybookjs/storybook/pull/24610), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- CLI: Catch when prettier failed to prettify main and preview config files - [#24604](https://github.com/storybookjs/storybook/pull/24604), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- CLI: Ignore `addon-onboarding` when checking versions - [#24634](https://github.com/storybookjs/storybook/pull/24634), thanks [@JReinhold](https://github.com/JReinhold)!\n- CLI: Use @storybook/test in template stories - [#24393](https://github.com/storybookjs/storybook/pull/24393), thanks [@yannbf](https://github.com/yannbf)!\n- Controls: Improve accessibility of BooleanControl for screen readers - [#24418](https://github.com/storybookjs/storybook/pull/24418), thanks [@danielmarcano](https://github.com/danielmarcano)!\n- Dependencies: Update @babel/traverse and @babel/core to fix vulnerability - [#24670](https://github.com/storybookjs/storybook/pull/24670), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Dependencies: Update browserify-sign transitive dependency - [#24674](https://github.com/storybookjs/storybook/pull/24674), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Dependencies: Update nx dependencies to v17 - [#24671](https://github.com/storybookjs/storybook/pull/24671), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Maintenance: Split renderers preview entrypoints - [#24623](https://github.com/storybookjs/storybook/pull/24623), thanks [@ndelangen](https://github.com/ndelangen)!\n- Next.js: Add avif support - [#24611](https://github.com/storybookjs/storybook/pull/24611), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Next.js: Fix forwarding ref for Image component - [#24648](https://github.com/storybookjs/storybook/pull/24648), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Theming: Add theme variable to set the preview background color - [#24575](https://github.com/storybookjs/storybook/pull/24575), thanks [@JReinhold](https://github.com/JReinhold)!\n- UI: Fix button contrast-ratio - [#24525](https://github.com/storybookjs/storybook/pull/24525), thanks [@maheshchandra10](https://github.com/maheshchandra10)!\n- UI: Update zIndex on NotificationList to fix the notification not being clickable in certain cases - [#24602](https://github.com/storybookjs/storybook/pull/24602), thanks [@yoshi2no](https://github.com/yoshi2no)!\n\n## 7.6.0-alpha.3\n\n- Action: Attach spies on actions across stories when defined in meta - [#24451](https://github.com/storybookjs/storybook/pull/24451), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Addon A11y: Avoid CSP issue - [#24477](https://github.com/storybookjs/storybook/pull/24477), thanks [@Marklb](https://github.com/Marklb)!\n- Addon-themes: Fix globals not being set when using absolute path - [#24596](https://github.com/storybookjs/storybook/pull/24596), thanks [@JReinhold](https://github.com/JReinhold)!\n- CLI: Allow Yarn v4 in `link` command - [#24551](https://github.com/storybookjs/storybook/pull/24551), thanks [@yannbf](https://github.com/yannbf)!\n- Core-Server: Ignore all node_module folders for watchpack - [#24553](https://github.com/storybookjs/storybook/pull/24553), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Core: Fix pnp support when cache dir is outside working dir - [#24572](https://github.com/storybookjs/storybook/pull/24572), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Manager: Update `store.settings.lastTrackedStoryId` - [#24115](https://github.com/storybookjs/storybook/pull/24115), thanks [@rashidshamloo](https://github.com/rashidshamloo)!\n- Next.js: Support v14.0.0 - [#24593](https://github.com/storybookjs/storybook/pull/24593), thanks [@nikospapcom](https://github.com/nikospapcom)!\n- Test: Create @storybook/test package based on vitest - [#24392](https://github.com/storybookjs/storybook/pull/24392), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n\n## 7.6.0-alpha.2\n\n- Actions: Fix missing crypto module crashing React Native - [#24546](https://github.com/storybookjs/storybook/pull/24546), thanks [@dannyhw](https://github.com/dannyhw)!\n- Core: Fix post message channel location.search access for React Native - [#24545](https://github.com/storybookjs/storybook/pull/24545), thanks [@dannyhw](https://github.com/dannyhw)!\n- ManagerBuilder: Fix `\"type\": \"commonjs\"` compatibility - [#24534](https://github.com/storybookjs/storybook/pull/24534), thanks [@ndelangen](https://github.com/ndelangen)!\n- React: Upgrade `react-docgen` to v7 - [#24530](https://github.com/storybookjs/storybook/pull/24530), thanks [@shilman](https://github.com/shilman)!\n\n## 7.6.0-alpha.1\n\n- Angular: Add source-map option to builder - [#24466](https://github.com/storybookjs/storybook/pull/24466), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Angular: update wrong type for webpackStatsJson in start-storybook schema.json - [#24494](https://github.com/storybookjs/storybook/pull/24494), thanks [@LucaVazz](https://github.com/LucaVazz)!\n- CLI: Add @storybook/addon-designs to non-core list - [#24507](https://github.com/storybookjs/storybook/pull/24507), thanks [@yannbf](https://github.com/yannbf)!\n- Doc Blocks: Add support for `of` prop to `Primary` block - [#23849](https://github.com/storybookjs/storybook/pull/23849), thanks [@Wilson2k](https://github.com/Wilson2k)!\n- Doc Blocks: Remove `defaultProps` in `Stories` block - [#24506](https://github.com/storybookjs/storybook/pull/24506), thanks [@WouterK12](https://github.com/WouterK12)!\n- Themes: Run postinstall in shell for windows - [#24389](https://github.com/storybookjs/storybook/pull/24389), thanks [@Integrayshaun](https://github.com/Integrayshaun)!\n\n## 7.6.0-alpha.0\n\nEmpty release identical to `7.5.0`.\n\n## 7.5.0-alpha.7\n\n- Angular: Allow loading standalone directives - [#24448](https://github.com/storybookjs/storybook/pull/24448), thanks [@osnoser1](https://github.com/osnoser1)!\n- Svelte: Fix docs generating when using `lang=\"ts\"` or optional chaining - [#24096](https://github.com/storybookjs/storybook/pull/24096), thanks [@j3rem1e](https://github.com/j3rem1e)!\n- Vite: Support Vite 5 - [#24395](https://github.com/storybookjs/storybook/pull/24395), thanks [@IanVS](https://github.com/IanVS)!\n\n## 7.5.0-alpha.6\n\n- Angular: Introduce argsToTemplate for property and event Bindings - [#24434](https://github.com/storybookjs/storybook/pull/24434), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Controls: Fix select / multiselect when value contains multiple spaces - [#22334](https://github.com/storybookjs/storybook/pull/22334), thanks [@oxcened](https://github.com/oxcened)!\n- Next.js: Support rename font import - [#24406](https://github.com/storybookjs/storybook/pull/24406), thanks [@yoshi2no](https://github.com/yoshi2no)!\n- UI: Update ScrollArea with radix - [#24413](https://github.com/storybookjs/storybook/pull/24413), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- Web-components: Add Lit3 support - [#24437](https://github.com/storybookjs/storybook/pull/24437), thanks [@shilman](https://github.com/shilman)!\n\n## 7.5.0-alpha.5\n\n- Angular: Add CLI options (debugWebpack, webpackStatsJson, and more) - [#24388](https://github.com/storybookjs/storybook/pull/24388), thanks [@yannbf](https://github.com/yannbf)!\n- Angular: Fix Angular 15 support and add zone.js v0.14.x support - [#24367](https://github.com/storybookjs/storybook/pull/24367), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Core: Add class name to Storybook error name - [#24371](https://github.com/storybookjs/storybook/pull/24371), thanks [@yannbf](https://github.com/yannbf)!\n- ManagerAPI: Fix bug with story redirection when URL has partial storyId - [#24345](https://github.com/storybookjs/storybook/pull/24345), thanks [@ndelangen](https://github.com/ndelangen)!\n- NextJS: Fix Image Context re-use via singleton - [#24146](https://github.com/storybookjs/storybook/pull/24146), thanks [@martinnabhan](https://github.com/martinnabhan)!\n- NextJS: Fix default next image loader when src has params - [#24187](https://github.com/storybookjs/storybook/pull/24187), thanks [@json-betsec](https://github.com/json-betsec)!\n- React: Upgrade `react-docgen` to 6.0.x and improve argTypes - [#23825](https://github.com/storybookjs/storybook/pull/23825), thanks [@shilman](https://github.com/shilman)!\n- Webpack: Display errors on build - [#24377](https://github.com/storybookjs/storybook/pull/24377), thanks [@yannbf](https://github.com/yannbf)!\n\n## 7.5.0-alpha.4\n\n- CLI: Fix Nextjs project detection - [#24346](https://github.com/storybookjs/storybook/pull/24346), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Deprecate `storyStoreV6` (including `storiesOf`) and `storyIndexers` - [#23938](https://github.com/storybookjs/storybook/pull/23938), thanks [@JReinhold](https://github.com/JReinhold)!\n- Core: Fix Promise cycle bug in useSharedState - [#24268](https://github.com/storybookjs/storybook/pull/24268), thanks [@ndelangen](https://github.com/ndelangen)!\n- Core: Fix missing favicon during dev - [#24356](https://github.com/storybookjs/storybook/pull/24356), thanks [@ndelangen](https://github.com/ndelangen)!\n- NextJS: Change babel plugins from `proposal-...` to `transform-...` - [#24290](https://github.com/storybookjs/storybook/pull/24290), thanks [@roottool](https://github.com/roottool)!\n- Nextjs: Improve support for Windows-style paths - [#23695](https://github.com/storybookjs/storybook/pull/23695), thanks [@T99](https://github.com/T99)!\n- UI: Fix infinite hook call causing browsers to freeze - [#24291](https://github.com/storybookjs/storybook/pull/24291), thanks [@yannbf](https://github.com/yannbf)!\n- UI: Improve contrast ratio between focus / hover - [#24205](https://github.com/storybookjs/storybook/pull/24205), thanks [@chocoscoding](https://github.com/chocoscoding)!\n- Vite: Move mdx-plugin from @storybook/builder-vite to @storybook/addon-docs - [#24166](https://github.com/storybookjs/storybook/pull/24166), thanks [@bryanjtc](https://github.com/bryanjtc)!\n\n## 7.5.0-alpha.3\n\n- Build: Filter some manager errors - [#24217](https://github.com/storybookjs/storybook/pull/24217), thanks [@yannbf](https://github.com/yannbf)!\n- Build: Migrate @storybook/addon-backgrounds to strict-ts - [#22178](https://github.com/storybookjs/storybook/pull/22178), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Build: Upgrade chromatic bin package - [#24133](https://github.com/storybookjs/storybook/pull/24133), thanks [@ndelangen](https://github.com/ndelangen)!\n- CLI: Change `/Date$/` to `/Dates$/i` - [#24195](https://github.com/storybookjs/storybook/pull/24195), thanks [@arup1221](https://github.com/arup1221)!\n- CLI: Fix `sb add` adding duplicative entries - [#24229](https://github.com/storybookjs/storybook/pull/24229), thanks [@ndelangen](https://github.com/ndelangen)!\n- Core: Throw an error when critical presets fail to load - [#24176](https://github.com/storybookjs/storybook/pull/24176), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Unify error when builder is missing - [#24177](https://github.com/storybookjs/storybook/pull/24177), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Upgrade `esbuild-register` to `3.5.0` - [#24175](https://github.com/storybookjs/storybook/pull/24175), thanks [@anneau](https://github.com/anneau)!\n- Dependencies: Upgrade `file-system-cache` - [#24232](https://github.com/storybookjs/storybook/pull/24232), thanks [@seriouz](https://github.com/seriouz)!\n- Indexer: Rename `index` to `createIndex` - [#24075](https://github.com/storybookjs/storybook/pull/24075), thanks [@JReinhold](https://github.com/JReinhold)!\n- Maintenance: Regen lockfiles - [#24152](https://github.com/storybookjs/storybook/pull/24152), thanks [@ndelangen](https://github.com/ndelangen)!\n- Manager: Fix useAddonState when using a setter function - [#24237](https://github.com/storybookjs/storybook/pull/24237), thanks [@ndelangen](https://github.com/ndelangen)!\n- NextJS: Add compatibility with nextjs `13.5` - [#24239](https://github.com/storybookjs/storybook/pull/24239), thanks [@ndelangen](https://github.com/ndelangen)!\n- NextJS: Aliases `react` and `react-dom` like `next.js` does - [#23671](https://github.com/storybookjs/storybook/pull/23671), thanks [@sookmax](https://github.com/sookmax)!\n- Nextjs: Improve Google Fonts failure error messages and documentation - [#23891](https://github.com/storybookjs/storybook/pull/23891), thanks [@nsheaps](https://github.com/nsheaps)!\n- Nextjs: Migrate from config to previewAnnotations - [#24178](https://github.com/storybookjs/storybook/pull/24178), thanks [@yannbf](https://github.com/yannbf)!\n- Theming: Add `barHoverColor` - [#20169](https://github.com/storybookjs/storybook/pull/20169), thanks [@julien-deramond](https://github.com/julien-deramond)!\n- Types: Allow `null` in value of `experimental_updateStatus` to clear status - [#24206](https://github.com/storybookjs/storybook/pull/24206), thanks [@ndelangen](https://github.com/ndelangen)!\n- Types: Don't distribute generic type of Meta and Story - [#24110](https://github.com/storybookjs/storybook/pull/24110), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- UI: Expand sidebar for selected story when using composition - [#23781](https://github.com/storybookjs/storybook/pull/23781), thanks [@joaonunomota](https://github.com/joaonunomota)!\n- UI: Fix SVG override fill when path has a fill attribute - [#24156](https://github.com/storybookjs/storybook/pull/24156), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: Fix TreeNode alignment when using a different font - [#22221](https://github.com/storybookjs/storybook/pull/22221), thanks [@bdriguesdev](https://github.com/bdriguesdev)!\n- UI: Fix custom theme hover-color inconsistency - [#22262](https://github.com/storybookjs/storybook/pull/22262), thanks [@yoshi2no](https://github.com/yoshi2no)!\n- UI: Fix keydown shortcut within shadow tree - [#24179](https://github.com/storybookjs/storybook/pull/24179), thanks [@stropitek](https://github.com/stropitek)!\n- UI: Improve look and feel of status UI in sidebar - [#24099](https://github.com/storybookjs/storybook/pull/24099), thanks [@ndelangen](https://github.com/ndelangen)!\n\n## 7.5.0-alpha.2\n\n- Angular: Categorize legacy build options error - [#24014](https://github.com/storybookjs/storybook/pull/24014), thanks [@yannbf](https://github.com/yannbf)!\n- Builder-Webpack5: Categorize builder error - [#24031](https://github.com/storybookjs/storybook/pull/24031), thanks [@yannbf](https://github.com/yannbf)!\n- CI: Inform the user how to dedupe and strip color from info command - [#24087](https://github.com/storybookjs/storybook/pull/24087), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- CLI: Fix packageManager handling in `sb add` - [#24079](https://github.com/storybookjs/storybook/pull/24079), thanks [@Integrayshaun](https://github.com/Integrayshaun)!\n- CLI: Improve sanitization logic in crash reports - [#24028](https://github.com/storybookjs/storybook/pull/24028), thanks [@yannbf](https://github.com/yannbf)!\n- Maintenance: Add more context to explanation in core-events errors - [#24063](https://github.com/storybookjs/storybook/pull/24063), thanks [@yannbf](https://github.com/yannbf)!\n- Monorepo: Fix `svelte-vite` detection - [#24085](https://github.com/storybookjs/storybook/pull/24085), thanks [@legnaleurc](https://github.com/legnaleurc)!\n- NextJS: Fix Image Context reuse (ensure singleton by externalizing it) - [#23881](https://github.com/storybookjs/storybook/pull/23881), thanks [@martinnabhan](https://github.com/martinnabhan)!\n- Source-loader: Fix property key validation - [#24068](https://github.com/storybookjs/storybook/pull/24068), thanks [@MrZillaGold](https://github.com/MrZillaGold)!\n- Svelte: Fix generated properties on Svelte event handler - [#24020](https://github.com/storybookjs/storybook/pull/24020), thanks [@j3rem1e](https://github.com/j3rem1e)!\n- Telemetry: Add platform info to telemetry event - [#24081](https://github.com/storybookjs/storybook/pull/24081), thanks [@yannbf](https://github.com/yannbf)!\n- UI: Fix target id in searchfield label - [#23464](https://github.com/storybookjs/storybook/pull/23464), thanks [@plumpNation](https://github.com/plumpNation)!\n- Vue3: Remove console.log in sourceDecorator - [#24062](https://github.com/storybookjs/storybook/pull/24062), thanks [@oruman](https://github.com/oruman)!\n\n## 7.5.0-alpha.1\n\n- Core: Add CJS entrypoints to errors in core events - [#24038](https://github.com/storybookjs/storybook/pull/24038), thanks [@yannbf](https://github.com/yannbf)!\n\n## 7.5.0-alpha.0\n\n- Addon API: Improve the updateStatus API - [#24007](https://github.com/storybookjs/storybook/pull/24007), thanks [@ndelangen](https://github.com/ndelangen)!\n- CLI: Add more information to `storybook info` command - [#24003](https://github.com/storybookjs/storybook/pull/24003), thanks [@JReinhold](https://github.com/JReinhold)!\n- CLI: Add uncaughtException handler - [#24018](https://github.com/storybookjs/storybook/pull/24018), thanks [@yannbf](https://github.com/yannbf)!\n- CLI: Remove random commas in storybook upgrade logs - [#22333](https://github.com/storybookjs/storybook/pull/22333), thanks [@joaonunomota](https://github.com/joaonunomota)!\n- Doc Blocks: Add `title` to `Meta` prop types - [#23370](https://github.com/storybookjs/storybook/pull/23370), thanks [@iqbalcodes6602](https://github.com/iqbalcodes6602)!\n- Docs: Fix TOC import - [#24047](https://github.com/storybookjs/storybook/pull/24047), thanks [@shilman](https://github.com/shilman)!\n- Docs: Fix table of contents scroll behavior - [#23986](https://github.com/storybookjs/storybook/pull/23986), thanks [@almoghaimo](https://github.com/almoghaimo)!\n- Telemetry: Filter addon options to protect sensitive info - [#24000](https://github.com/storybookjs/storybook/pull/24000), thanks [@shilman](https://github.com/shilman)!\n- Types: Remove `@types/react` dep from `@storybook/types` - [#24042](https://github.com/storybookjs/storybook/pull/24042), thanks [@JReinhold](https://github.com/JReinhold)!\n\n## 7.4.0-alpha.2\n\n- Addon-docs: Resolve `mdx-react-shim` & `@storybook/global` correctly - [#23941](https://github.com/storybookjs/storybook/pull/23941), thanks [@ndelangen](https://github.com/ndelangen)!\n- Addons: Fix key is not a prop warning - [#23935](https://github.com/storybookjs/storybook/pull/23935), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- CLI: Pass package manager to postinstall - [#23913](https://github.com/storybookjs/storybook/pull/23913), thanks [@Integrayshaun](https://github.com/Integrayshaun)!\n- CLI: Provide guidance for users who try to initialize Storybook on an empty dir - [#23874](https://github.com/storybookjs/storybook/pull/23874), thanks [@yannbf](https://github.com/yannbf)!\n- Logger: Fix double error messages/stack - [#23919](https://github.com/storybookjs/storybook/pull/23919), thanks [@ndelangen](https://github.com/ndelangen)!\n- Maintenance: Categorize server errors - [#23912](https://github.com/storybookjs/storybook/pull/23912), thanks [@yannbf](https://github.com/yannbf)!\n- Maintenance: Remove need for `react` as peerDependency - [#23897](https://github.com/storybookjs/storybook/pull/23897), thanks [@ndelangen](https://github.com/ndelangen)!\n- Maintenance: Remove sourcemaps generation - [#23936](https://github.com/storybookjs/storybook/pull/23936), thanks [@ndelangen](https://github.com/ndelangen)!\n- Preset: Add common preset overrides mechanism - [#23915](https://github.com/storybookjs/storybook/pull/23915), thanks [@yannbf](https://github.com/yannbf)!\n- UI: Add an experimental API for adding sidebar bottom toolbar - [#23778](https://github.com/storybookjs/storybook/pull/23778), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: Add an experimental API for adding sidebar top toolbar - [#23811](https://github.com/storybookjs/storybook/pull/23811), thanks [@ndelangen](https://github.com/ndelangen)!\n\n## 7.4.0-alpha.1\n\n- Build: Migrate @storybook/scripts to strict-ts - [#23818](https://github.com/storybookjs/storybook/pull/23818), thanks [@stilt0n](https://github.com/stilt0n)!\n- CLI: Exclude addon-styling from upgrade - [#23841](https://github.com/storybookjs/storybook/pull/23841), thanks [@Integrayshaun](https://github.com/Integrayshaun)!\n- Core: Add error categorization framework - [#23653](https://github.com/storybookjs/storybook/pull/23653), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Fix error thrown if `docs.defaultName` is unset - [#23893](https://github.com/storybookjs/storybook/pull/23893), thanks [@stilt0n](https://github.com/stilt0n)!\n- Core: Fix race-condition relating to `addons.setConfig` - [#23802](https://github.com/storybookjs/storybook/pull/23802), thanks [@ndelangen](https://github.com/ndelangen)!\n- Maintenance: Move filtering of sidebar into the state - [#23911](https://github.com/storybookjs/storybook/pull/23911), thanks [@ndelangen](https://github.com/ndelangen)!\n- Maintenance: Revert \"WebpackBuilder: Remove need for `react` as peerDependency\" - [#23882](https://github.com/storybookjs/storybook/pull/23882), thanks [@vanessayuenn](https://github.com/vanessayuenn)!\n- Manager API: Fix `api.getAddonState`default value - [#23804](https://github.com/storybookjs/storybook/pull/23804), thanks [@sookmax](https://github.com/sookmax)!\n- Publish: Don't distribute src files or unnecessary template files - [#23853](https://github.com/storybookjs/storybook/pull/23853), thanks [@shilman](https://github.com/shilman)!\n- UI: Add an experimental API for adding sidebar filter functions at runtime - [#23722](https://github.com/storybookjs/storybook/pull/23722), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: Removal of experimental components - [#23907](https://github.com/storybookjs/storybook/pull/23907), thanks [@ndelangen](https://github.com/ndelangen)!\n- Vue3: Add support for Global Apps install - [#23772](https://github.com/storybookjs/storybook/pull/23772), thanks [@chakAs3](https://github.com/chakAs3)!\n- Vue3: Use slot value directly if it's a string in source decorator - [#23784](https://github.com/storybookjs/storybook/pull/23784), thanks [@nasvillanueva](https://github.com/nasvillanueva)!\n\n## 7.4.0-alpha.0\n\n- Index: Fix `*.story.*` CSF indexing - [#23852](https://github.com/storybookjs/storybook/pull/23852), thanks [@shilman](https://github.com/shilman)!\n\n## 7.3.0-alpha.0\n\n- Addons: Deprecate key in addon render function as it is not available anymore - [#23792](https://github.com/storybookjs/storybook/pull/23792), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Build: Support Chrome 100, Safari 15 and Firefox 91 - [#23800](https://github.com/storybookjs/storybook/pull/23800), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- CLI: Update postinstall to look for addon script - [#23791](https://github.com/storybookjs/storybook/pull/23791), thanks [@Integrayshaun](https://github.com/Integrayshaun)!\n- UI: Update IconButton and add new Toolbar component - [#23795](https://github.com/storybookjs/storybook/pull/23795), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- UI: Upgrade Addon Design - [#23806](https://github.com/storybookjs/storybook/pull/23806), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- Vue3: Don't assign values to all slots (rollback to v7.0.27) - [#23697](https://github.com/storybookjs/storybook/pull/23697), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n\n## 7.2.2-alpha.1\n\n- CSF-Tools: Remove prettier from printConfig - [#23766](https://github.com/storybookjs/storybook/pull/23766), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- UI: Improve Link component - [#23767](https://github.com/storybookjs/storybook/pull/23767), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- UI: Improve new `Button` component - [#23765](https://github.com/storybookjs/storybook/pull/23765), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- UI: Update Button types to allow for no children on iconOnly buttons - [#23735](https://github.com/storybookjs/storybook/pull/23735), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- UI: Upgrade Icon component - [#23680](https://github.com/storybookjs/storybook/pull/23680), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- WebpackBuilder: Remove need for `react` as peerDependency - [#23496](https://github.com/storybookjs/storybook/pull/23496), thanks [@ndelangen](https://github.com/ndelangen)!\n\n## 7.2.2-alpha.0\n\n- Indexer: Introduce new experimental `indexer` API - #23691, thanks [@JReinhold](https://github.com/jreinhold)!\n- Addon-docs, Core, Server: Use new `indexer` API - #23660, thanks [@JReinhold](https://github.com/jreinhold)!\n- Server: Add support for tags - #23660, thanks [@JReinhold](https://github.com/jreinhold)!\n- Core-server: Improve internal types - #23632, thanks [@JReinhold](https://github.com/jreinhold)!\n\n## 7.2.0-rc.0\n\n- Addon: Create @storybook/addon-themes - [#23524](https://github.com/storybookjs/storybook/pull/23524), thanks [@Integrayshaun](https://github.com/Integrayshaun)!\n- Angular: Fix initialization of Storybook in Angular 16.1 - [#23598](https://github.com/storybookjs/storybook/pull/23598), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- CLI: Gracefully shutdown and cleanup execa child processes - [#23538](https://github.com/storybookjs/storybook/pull/23538), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Dependencies: Downgrade `jest-mock` - [#23597](https://github.com/storybookjs/storybook/pull/23597), thanks [@ndelangen](https://github.com/ndelangen)!\n- Dependencies: Upgrade simple-update-notifier - [#23396](https://github.com/storybookjs/storybook/pull/23396), thanks [@dartess](https://github.com/dartess)!\n- Storyshots: fix broken storyshots with angular - [#23555](https://github.com/storybookjs/storybook/pull/23555), thanks [@mattlewis92](https://github.com/mattlewis92)!\n- TypeScript: Added `expanded` to `CoreCommon_StorybookRefs` to fix typescript errors - [#23488](https://github.com/storybookjs/storybook/pull/23488), thanks [@DotwoodMedia](https://github.com/DotwoodMedia)!\n- TypeScript: Downgrade to the last version of type-fest that doesn't need typescript 5.0 - [#23574](https://github.com/storybookjs/storybook/pull/23574), thanks [@ndelangen](https://github.com/ndelangen)!\n- Vue2: Source Decorator reactivity - [#23149](https://github.com/storybookjs/storybook/pull/23149), thanks [@chakAs3](https://github.com/chakAs3)!\n\n## 7.2.0-alpha.0\n\n- Angular: Make enableProdMode optional - [#23489](https://github.com/storybookjs/storybook/pull/23489), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Router: Support RegExp in Route component - [#23292](https://github.com/storybookjs/storybook/pull/23292), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: Improve tabs component, more type correct, allow for FC as title - [#23288](https://github.com/storybookjs/storybook/pull/23288), thanks [@ndelangen](https://github.com/ndelangen)!\n- Addons: Improve code quality by using title as FC & sharing state via useAddonState - [#23298](https://github.com/storybookjs/storybook/pull/23298), thanks [@ndelangen](https://github.com/ndelangen)!\n- InteractionsAddon: Improve code quality by using title as FC & sharing state via useAddonState - [#23291](https://github.com/storybookjs/storybook/pull/23291), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: Add storyStatus to sidebar UI - [#23342](https://github.com/storybookjs/storybook/pull/23342), thanks [@ndelangen](https://github.com/ndelangen)!\n- Addon API: Add experimental page addon type - [#23307](https://github.com/storybookjs/storybook/pull/23307), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: refactor Canvas component so we can improve types for PREVIEW addons and TAB addons - [#23311](https://github.com/storybookjs/storybook/pull/23311), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: Improve Button layout and props - [#23356](https://github.com/storybookjs/storybook/pull/23356), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- Dependencies: Remove references to api and the 2 deprecated channel packages - [#23384](https://github.com/storybookjs/storybook/pull/23384), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: Show the story status in the search results - [#23441](https://github.com/storybookjs/storybook/pull/23441), thanks [@ndelangen](https://github.com/ndelangen)!\n- UI: Create new form elements in the new Core UI (Input, TextArea, Select) - [#23469](https://github.com/storybookjs/storybook/pull/23469), thanks [@cdedreuille](https://github.com/cdedreuille)!\n- CLI: Improve support of mono repositories - [#23458](https://github.com/storybookjs/storybook/pull/23458), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n\n## 7.1.0-rc.2\n\n- CLI: Exit when user does not select a storybook project type - [#23201](https://github.com/storybookjs/storybook/pull/23201), thanks [@yannbf](https://github.com/yannbf)!\n- CLI: Fix Javascript language detection - [#23426](https://github.com/storybookjs/storybook/pull/23426), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Core: Fix onboarding detection in what's new module - [#23424](https://github.com/storybookjs/storybook/pull/23424), thanks [@yannbf](https://github.com/yannbf)!\n- Dependencies: Bump `@sveltejs/vite-plugin-svelte` - [#23233](https://github.com/storybookjs/storybook/pull/23233), thanks [@JReinhold](https://github.com/JReinhold)!\n- Telemetry: Add globals usage to project.json - [#23431](https://github.com/storybookjs/storybook/pull/23431), thanks [@shilman](https://github.com/shilman)!\n\n## 7.1.0-rc.1\n\n- Angular: Enable prod mode when Storybook is built - [#23404](https://github.com/storybookjs/storybook/pull/23404), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Angular: Fix esm issue in combination with rxjs v6 - [#23405](https://github.com/storybookjs/storybook/pull/23405), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- CLI: Fix chevron icon on Configure.mdx page - [#23397](https://github.com/storybookjs/storybook/pull/23397), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Settings: Fix dark mode for what's new page - [#23398](https://github.com/storybookjs/storybook/pull/23398), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n\n## 7.1.0-rc.0\n\nPromote beta to rc without any changes. 🎉\n\n## 7.1.0-beta.3\n\n- CLI: Update Configure.mdx - [#23340](https://github.com/storybookjs/storybook/pull/23340), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- React: Move `typescript` from devDependencies to peerDependencies - [#23179](https://github.com/storybookjs/storybook/pull/23179), thanks [@chakAs3](https://github.com/chakAs3)!\n- Settings: Add disable whatsnew UI - [#23381](https://github.com/storybookjs/storybook/pull/23381), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Settings: New about page design - [#23357](https://github.com/storybookjs/storybook/pull/23357), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n- Svelte-Webpack: Support Svelte v4 - [#23336](https://github.com/storybookjs/storybook/pull/23336), thanks [@JReinhold](https://github.com/JReinhold)!\n- UI: Remove css zoom - [#21303](https://github.com/storybookjs/storybook/pull/21303), thanks [@Luk-z](https://github.com/Luk-z)!\n\n## 7.1.0-beta.2\n\n- Next.js: Fix for @nx/react/plugin/storybook with stories containing SVGs - [#23210](https://github.com/storybookjs/storybook/pull/23210), thanks [@daves28](https://github.com/daves28)!\n- Yarn: Downgrade yarnpkg packages and support virtual files properly - [#23354](https://github.com/storybookjs/storybook/pull/23354), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n\n## 7.1.0-beta.1\n\n- Addon-docs: Add opt-in table of contents - [#23142](https://github.com/storybookjs/storybook/pull/23142), thanks [@shilman](https://github.com/shilman)!\n- SyntaxHighlighter: Expose registerLanguage - [#23166](https://github.com/storybookjs/storybook/pull/23166), thanks [@ndelangen](https://github.com/ndelangen)!\n- Yarn: Fix pnp package resolution on Windows - [#23274](https://github.com/storybookjs/storybook/pull/23274), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Yarn: Pin version of @yarnpkg packages to support Node 16 - [#23330](https://github.com/storybookjs/storybook/pull/23330), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n\n## 7.1.0-beta.0\n\n- Settings: Add what's new page, remove release notes - [#23202](https://github.com/storybookjs/storybook/pull/23202), thanks [@kasperpeulen](https://github.com/kasperpeulen)!\n\n## 7.1.0-alpha.44\n\n- Next.js: Fix next/image usage in latest Next.js release - [#23296](https://github.com/storybookjs/storybook/pull/23296), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n\n## 7.1.0-alpha.43\n\n- Addons: Remove deprecated addPanel use and misc improvements - [#23284](https://github.com/storybookjs/storybook/pull/23284), thanks [@ndelangen](https://github.com/ndelangen)!\n- CSF-tools: Allow type checking in story title - [#22791](https://github.com/storybookjs/storybook/pull/22791), thanks [@honzahruby](https://github.com/honzahruby)!\n\n## 7.1.0-alpha.42\n\n- CLI: Fix pnp paths logic in storybook metadata - [#23259](https://github.com/storybookjs/storybook/pull/23259), thanks [@yannbf](https://github.com/yannbf)!\n\n## 7.1.0-alpha.41\n\n- Controls: Fix UI to add array items - [#22993](https://github.com/storybookjs/storybook/pull/22993), thanks [@sookmax](https://github.com/sookmax)!\n- Next.js: Support disableStaticImages setting - [#23167](https://github.com/storybookjs/storybook/pull/23167), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n\n## 7.1.0-alpha.40\n\n- CLI: Parse pnp paths in storybook metadata - [#23199](https://github.com/storybookjs/storybook/pull/23199), thanks [@yannbf](https://github.com/yannbf)!\n- Dependencies: Pin `file-system-cache` to 2.3.0 - [#23221](https://github.com/storybookjs/storybook/pull/23221), thanks [@JReinhold](https://github.com/JReinhold)!\n- PNPM: Hide ModuleNotFound error in pnpm pnp mode - [#23195](https://github.com/storybookjs/storybook/pull/23195), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- Svelte: Support v4 - [#22905](https://github.com/storybookjs/storybook/pull/22905), thanks [@JReinhold](https://github.com/JReinhold)!\n\n## 7.1.0-alpha.39\n\n- CLI: Add new Configure page to templates - [#23171](https://github.com/storybookjs/storybook/pull/23171), thanks [@yannbf](https://github.com/yannbf)!\n- CLI: Fix storybook package manager command in init - [#23169](https://github.com/storybookjs/storybook/pull/23169), thanks [@yannbf](https://github.com/yannbf)!\n- React: Add addon-onboarding as part of init - [#22972](https://github.com/storybookjs/storybook/pull/22972), thanks [@yannbf](https://github.com/yannbf)!\n\n## 7.1.0-alpha.38\n\n- CLI: Fix installing user's project before init - [#23145](https://github.com/storybookjs/storybook/pull/23145), thanks [@ndelangen](https://github.com/ndelangen)!\n- CLI: Fix storybook dev after storybook init via subprocess - [#23144](https://github.com/storybookjs/storybook/pull/23144), thanks [@yannbf](https://github.com/yannbf)!\n- CLI: Suppress dev-server info table when `--quiet` is true - [#23133](https://github.com/storybookjs/storybook/pull/23133), thanks [@syabro](https://github.com/syabro)!\n- Core: Allow `.mjs` extension for CSF stories - [#23125](https://github.com/storybookjs/storybook/pull/23125), thanks [@idesigncode](https://github.com/idesigncode)!\n- Core: Fix compat by disabling name mangling in `esbuild` require - [#22486](https://github.com/storybookjs/storybook/pull/22486), thanks [@youngboy](https://github.com/youngboy)!\n- Docs: Fix scroll location on docs navigation - [#22714](https://github.com/storybookjs/storybook/pull/22714), thanks [@gitstart-storybook](https://github.com/gitstart-storybook)!\n- Interactions: Fix deeply nested nodes in the panel debugger - [#23108](https://github.com/storybookjs/storybook/pull/23108), thanks [@yannbf](https://github.com/yannbf)!\n\n## 7.1.0-alpha.37\n\n- Ecosystem: Prebundle node-logger and make it CJS only - [#23109](https://github.com/storybookjs/storybook/pull/23109), thanks [@ndelangen](https://github.com/ndelangen)!\n- NextJS: Fix `useParams` support - [#22946](https://github.com/storybookjs/storybook/pull/22946), thanks [@gitstart-storybook](https://github.com/gitstart-storybook)!\n- NextJS: Fix fonts not loading with 3+ words in name - [#23121](https://github.com/storybookjs/storybook/pull/23121), thanks [@ygkn](https://github.com/ygkn)!\n- Webpack: Fix channel format for loading status - [#23139](https://github.com/storybookjs/storybook/pull/23139), thanks [@ndelangen](https://github.com/ndelangen)!\n\n## 7.1.0-alpha.36\n\n- CLI: Fix \"Invalid version null\" issues by improved version detection - [#22642](https://github.com/storybookjs/storybook/pull/22642), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!\n- CLI: Prebundle boxen to resolve a ESM/CJS incompatibility - [#23080](https://github.com/storybookjs/storybook/pull/23080), thanks [@ndelangen](https://github.com/ndelangen)!\n- Telemetry: Count onboarding stories - [#23092](https://github.com/storybookjs/storybook/pull/23092), thanks [@shilman](https://github.com/shilman)!\n\n## 7.1.0-alpha.35\n\n- CLI: Skip builder selection for react native - [#23042](https://github.com/storybookjs/storybook/pull/23042), thanks [@dannyhw](https://github.com/dannyhw)!\n- Core: Fix core-common to use node-fetch - [#23077](https://github.com/storybookjs/storybook/pull/23077), thanks [@ndelangen](https://github.com/ndelangen)!\n\n## 7.1.0-alpha.34\n\n- Angular: Fix ivy preset - [#23070](https://github.com/storybookjs/storybook/pull/23070), thanks [@ndelangen](https://github.com/ndelangen)!\n- CLI: Change Button stories layout for React starter templates - [#22951](https://github.com/storybookjs/storybook/pull/22951), thanks [@yannbf](https://github.com/yannbf)!\n\n## 7.1.0-alpha.33\n\n- Bug: Fix for angular 16.1 compatibility - [#23064](https://github.com/storybookjs/storybook/pull/23064), thanks [@ndelangen](https://github.com/ndelangen)!\n- Builder-vite: Fix lib/channels dependency - [#23049](https://github.com/storybookjs/storybook/pull/23049), thanks [@ndelangen](https://github.com/ndelangen)!\n- CLI: Improve steps in storybook init - [#22502](https://github.com/storybookjs/storybook/pull/22502), thanks [@yannbf](https://github.com/yannbf)!\n- CLI: Run `storybook dev` as part of `storybook init` - [#22928](https://github.com/storybookjs/storybook/pull/22928), thanks [@yannbf](https://github.com/yannbf)!\n- Core: Merge channels into a single package - [#23032](https://github.com/storybookjs/storybook/pull/23032), thanks [@ndelangen](https://github.com/ndelangen)!\n- Core: Unify cache location configurability - [#22079](https://github.com/storybookjs/storybook/pull/22079), thanks [@kubijo](https://github.com/kubijo)!\n\n## 7.1.0-alpha.32\n\n- Build: Remove `babel-core` & upgrade `esbuild` - [#23017](https://github.com/storybookjs/storybook/pull/23017), thanks [@ndelangen](https://github.com/ndelangen)!\n- Core: Disable esbuild on files imported from `node_modules` - [#23018](https://github.com/storybookjs/storybook/pull/23018), thanks [@tmeasday](https://github.com/tmeasday)!\n- Core: Integrate serverChannel into channel - [#22940](https://github.com/storybookjs/storybook/pull/22940), thanks [@ndelangen](https://github.com/ndelangen)!\n- React: Lazy import `react-docgen-typescript-plugin` - [#23019](https://github.com/storybookjs/storybook/pull/23019), thanks [@tmeasday](https://github.com/tmeasday)!\n\n## 7.1.0-alpha.31\n\n- Dependencies: Set vue-component-type-helpers to latest - [#23015](https://github.com/storybookjs/storybook/pull/23015), thanks [@ndelangen](https://github.com/ndelangen)!\n- Dependencies: Upgrade `nanoid`, prebundle it, upgrade `remark`, cleanup some `.md` files for warnings - [#23005](https://github.com/storybookjs/storybook/pull/23005), thanks [@ndelangen](https://github.com/ndelangen)!\n- Dependencies: Use `latest` version of `vue-tsc` & sync versions of `angular` - [#23011](https://github.com/storybookjs/storybook/pull/23011), thanks [@ndelangen](https://github.com/ndelangen)!\n\n## 7.1.0-alpha.30\n\n- Web-components: Fix custom-elements order of property application - [#19183](https://github.com/storybookjs/storybook/pull/19183), thanks [@sonntag-philipp](https://github.com/sonntag-philipp)!\n- Dependencies: Remove `shelljs` use - [#22995](https://github.com/storybookjs/storybook/pull/22995), thanks [@ndelangen](https://github.com/ndelangen)!\n- Dependencies: Upgrade Jest related packages - [#22979](https://github.com/storybookjs/storybook/pull/22979), thanks [@ndelangen](https://github.com/ndelangen)!\n- Core: Fix `builder-manager` adding multiple dashes to relative path - [#22974](https://github.com/storybookjs/storybook/pull/22974), thanks [@MarioCadenas](https://github.com/MarioCadenas)!\n- Core: Add JSDoc comments to `preview-api` APIs - [#22975](https://github.com/storybookjs/storybook/pull/22975), thanks [@ndelangen](https://github.com/ndelangen)!\n- Vue3: Fix source decorator to generate correct story code - [#22518](https://github.com/storybookjs/storybook/pull/22518), thanks [@chakAs3](https://github.com/chakAs3)!\n- Core: Add JSDoc comments to `manager-api` APIs - [#22968](https://github.com/storybookjs/storybook/pull/22968), thanks [@ndelangen](https://github.com/ndelangen)!\n- Core: Improve `of={...}` DocBlock error in story index - [#22782](https://github.com/storybookjs/storybook/pull/22782), thanks [@shilman](https://github.com/shilman)!\n- UI: Simplify `overlayscrollbars` component - [#22963](https://github.com/storybookjs/storybook/pull/22963), thanks [@ndelangen](https://github.com/ndelangen)!\n- Angular: Add `--open`/`--no-open` flag to `dev` command - [#22964](https://github.com/storybookjs/storybook/pull/22964), thanks [@yannbf](https://github.com/yannbf)!\n- Angular: Silence compodoc when running storybook with --quiet - [#22957](https://github.com/storybookjs/storybook/pull/22957), thanks [@yannbf](https://github.com/yannbf)!\n- React: Fix decorators to conditionally render children - [#22336](https://github.com/storybookjs/storybook/pull/22336), thanks [@redbugz](https://github.com/redbugz)!\n- Addon-measure: Migrate to strict TS - [#22402](https://github.com/storybookjs/storybook/pull/22402), thanks [@efrenaragon96](https://github.com/efrenaragon96)!\n- Feature: Add experimental status API - [#22890](https://github.com/storybookjs/storybook/pull/22890), thanks [@ndelangen](https://github.com/ndelangen)!\n\n## 7.1.0-alpha.29 (June 6, 2023)\n\n#### Bug Fixes\n\n- CLI: Fix upgrade notification message [#22933](https://github.com/storybooks/storybook/pull/22933)\n- Core: Fix indexing errors by excluding node_modules stories [#22873](https://github.com/storybooks/storybook/pull/22873)\n\n## 7.1.0-alpha.28 (June 6, 2023)\n\n#### Bug Fixes\n\n- Docs: E2E tests for Source block update fix [#22835](https://github.com/storybooks/storybook/pull/22835)\n- Docs: Fix Source block snippet updates [#22807](https://github.com/storybooks/storybook/pull/22807)\n\n## 7.1.0-alpha.27 (June 4, 2023)\n\n#### Features\n\n- Webpack: Add option to minify using swc [#22843](https://github.com/storybooks/storybook/pull/22843)\n\n#### Bug Fixes\n\n- Server: Fix .stories.yml support [#22906](https://github.com/storybooks/storybook/pull/22906)\n- Storysource: Fix StyledSyntaxHighlighter to wrap long lines [#22541](https://github.com/storybooks/storybook/pull/22541)\n\n#### Maintenance\n\n- TS: Migrate @storybook/web-components to strict TS [#22399](https://github.com/storybooks/storybook/pull/22399)\n- TS: Migrate @storybook/addon-storyshots-puppeteer to strict TS [#22407](https://github.com/storybooks/storybook/pull/22407)\n- TS: Migrate @storybook/addon-jest to strict TS [#22389](https://github.com/storybooks/storybook/pull/22389)\n- TS: Migrate @storybook/addon-mdx-gfm to strict TS [#22659](https://github.com/storybooks/storybook/pull/22659)\n- TS: Migrate @storybook/addon-storyshots to strict TS [#22487](https://github.com/storybooks/storybook/pull/22487)\n\n#### Build\n\n- Error on YN0060 - INCOMPATIBLE_PEER_DEPENDENCY [#22398](https://github.com/storybooks/storybook/pull/22398)\n- Build: upgrade yarn [#22855](https://github.com/storybooks/storybook/pull/22855)\n- Add CODEOWNERS [#22869](https://github.com/storybooks/storybook/pull/22869)\n\n## 7.1.0-alpha.26 (May 31, 2023)\n\n#### Bug Fixes\n\n- Addons: Fix `Addon_BaseAnnotations` type [#22771](https://github.com/storybooks/storybook/pull/22771)\n- Viewport: Fix viewport menu [#22829](https://github.com/storybooks/storybook/pull/22829)\n\n#### Maintenance\n\n- NextJS: Fix types [#22836](https://github.com/storybooks/storybook/pull/22836)\n- React: Update babel dependencies to fix sandbox creation [#22824](https://github.com/storybooks/storybook/pull/22824)\n\n#### Build\n\n- Build: sort package json files [#22847](https://github.com/storybooks/storybook/pull/22847)\n- Build: cleanup the test-storybooks [#22846](https://github.com/storybooks/storybook/pull/22846)\n- Build: fix the theme output during development [#22841](https://github.com/storybooks/storybook/pull/22841)\n- Build: move deprecated packages [#22753](https://github.com/storybooks/storybook/pull/22753)\n- Build: move builders [#22751](https://github.com/storybooks/storybook/pull/22751)\n\n## 7.1.0-alpha.25 (May 26, 2023)\n\n#### Bug Fixes\n\n- Vue3: Fix TS 5.0 compat with vue-component-type-helpers [#22814](https://github.com/storybooks/storybook/pull/22814)\n\n#### Build\n\n- Build: Fix the local storybook [#22805](https://github.com/storybooks/storybook/pull/22805)\n- Build: Add more checks to ci:daily workflow [#22815](https://github.com/storybooks/storybook/pull/22815)\n- Build: Revert conditional decorator story and downgrade Typescript version [#22812](https://github.com/storybooks/storybook/pull/22812)\n\n## 7.1.0-alpha.24 (May 26, 2023)\n\n#### Bug Fixes\n\n- Vue3: Fix reactive args updates in decorators [#22717](https://github.com/storybooks/storybook/pull/22717)\n\n#### Build\n\n- Build: Update Nx to latest version [#22694](https://github.com/storybooks/storybook/pull/22694)\n\n## 7.1.0-alpha.23 (May 24, 2023)\n\n#### Bug Fixes\n\n- Core: Fix `managerHead` preset in `main.ts` [#22701](https://github.com/storybooks/storybook/pull/22701)\n\n## 7.1.0-alpha.22 (May 24, 2023)\n\n#### Bug Fixes\n\n- Vite: Fix pnpm support by replacing @storybook/global with `window` [#22709](https://github.com/storybooks/storybook/pull/22709)\n\n## 7.1.0-alpha.21 (May 23, 2023)\n\n#### Features\n\n- Webpack: Add option to use swc instead of babel [#22075](https://github.com/storybooks/storybook/pull/22075)\n\n#### Bug Fixes\n\n- UI: Fix `.mp3` support for builder-manager [#22699](https://github.com/storybooks/storybook/pull/22699)\n- CLI: Fix support for BROWSER env var [#21473](https://github.com/storybooks/storybook/pull/21473)\n- Vite: Fix missing @storybook/global dependency [#22700](https://github.com/storybooks/storybook/pull/22700)\n- Next.js: Fix compatibility with Next 13.4.3 [#22697](https://github.com/storybooks/storybook/pull/22697)\n- CLI: Fix error parsing on NPM proxy [#22690](https://github.com/storybooks/storybook/pull/22690)\n- Core: Only connect to serverChannel in development mode [#22575](https://github.com/storybooks/storybook/pull/22575)\n- CLI: Improve error handling when dealing with angular.json files [#22663](https://github.com/storybooks/storybook/pull/22663)\n- CLI: Skip prompting for eslint plugin with --yes flag [#22651](https://github.com/storybooks/storybook/pull/22651)\n- CLI: Fix upgrade to not upgrade nx packages [#22419](https://github.com/storybooks/storybook/pull/22419)\n- CLI: Only handle CTRL + C on init event [#22687](https://github.com/storybooks/storybook/pull/22687)\n- Angular: Remove console.log [#22671](https://github.com/storybooks/storybook/pull/22671)\n\n## 7.1.0-alpha.20 (May 20, 2023)\n\n#### Bug Fixes\n\n- CLI: Account for windows paths when copying templates [#22644](https://github.com/storybooks/storybook/pull/22644)\n- CLI: Fix pnpm init command [#22635](https://github.com/storybooks/storybook/pull/22635)\n- UI: Add legacy font formats [#22576](https://github.com/storybooks/storybook/pull/22576)\n- Webpack: Remove the alias for `global` [#22393](https://github.com/storybooks/storybook/pull/22393)\n\n#### Maintenance\n\n- CLI: Reduce installation noise and improve error handling [#22554](https://github.com/storybooks/storybook/pull/22554)\n- Actions: Fix type of withActions [#22455](https://github.com/storybooks/storybook/pull/22455)\n\n#### Build\n\n- Build: add discord notification when generating sandboxes fails [#22638](https://github.com/storybooks/storybook/pull/22638)\n- Build: set correct ref on sandboxes Github action [#22625](https://github.com/storybooks/storybook/pull/22625)\n- Build: Fix sandbox generation scripts [#22620](https://github.com/storybooks/storybook/pull/22620)\n\n## 7.1.0-alpha.19 (May 16, 2023)\n\n#### Bug Fixes\n\n- Normalize paths exposed to vite-builder's `storybook-stories.js` file [#22327](https://github.com/storybooks/storybook/pull/22327)\n\n## 7.1.0-alpha.18 (May 15, 2023)\n\n#### Bug Fixes\n\n- CLI: Fix `getFrameworkPackage` logic [#22559](https://github.com/storybooks/storybook/pull/22559)\n- CLI: Remove automigrate reference from init command [#22561](https://github.com/storybooks/storybook/pull/22561)\n\n#### Maintenance\n\n- CLI: Detach automigrate command from storybook init [#22523](https://github.com/storybooks/storybook/pull/22523)\n\n## 7.1.0-alpha.17 (May 12, 2023)\n\n#### Bug Fixes\n\n- CLI: Fix storybook upgrade precheckfailure object [#22517](https://github.com/storybooks/storybook/pull/22517)\n- CLI: Throw errors instead of rejecting promises [#22515](https://github.com/storybooks/storybook/pull/22515)\n- CSF: Expose story id in composeStories [#22471](https://github.com/storybooks/storybook/pull/22471)\n- CLI: Remove unsupported frameworks/renderers and improve builder detection [#22492](https://github.com/storybooks/storybook/pull/22492)\n\n## 7.1.0-alpha.16 (May 11, 2023)\n\n#### Bug Fixes\n\n- Web-components: Fix source decorator to handle document fragments [#22513](https://github.com/storybooks/storybook/pull/22513)\n- Angular: Adjust child process I/O for compodoc command [#22441](https://github.com/storybooks/storybook/pull/22441)\n- Core: Fix windows path error in StoryStore v6 [#22512](https://github.com/storybooks/storybook/pull/22512)\n\n#### Maintenance\n\n- CLI: Prompt to force initialization when storybook is detected [#22392](https://github.com/storybooks/storybook/pull/22392)\n- UI: Fix css inconsistency in Button and Icon components [#22497](https://github.com/storybooks/storybook/pull/22497)\n\n#### Build\n\n- Sandboxes: Pin @vitejs/plugin-react to avoid conflict [#22501](https://github.com/storybooks/storybook/pull/22501)\n\n## 7.1.0-alpha.15 (May 11, 2023)\n\n#### Bug Fixes\n\n- CLI: Do not show a migration summary on sb init [#22109](https://github.com/storybooks/storybook/pull/22109)\n- Toolbars: Fix title behavior in UI [#22496](https://github.com/storybooks/storybook/pull/22496)\n- UI: Show current search shortcut in search box sidebar [#21619](https://github.com/storybooks/storybook/pull/21619)\n- Measure: Deactivate when switching to Docs mode [#21602](https://github.com/storybooks/storybook/pull/21602)\n- Outline: Fix additional outline border in docs mode [#21773](https://github.com/storybooks/storybook/pull/21773)\n\n## 7.1.0-alpha.14 (May 9, 2023)\n\n#### Bug Fixes\n\n- CLI: Scope styles in sample components from the CLI templates [#22162](https://github.com/storybooks/storybook/pull/22162)\n- CLI: Fix copyTemplate failures on `init` [#22375](https://github.com/storybooks/storybook/pull/22375)\n- CLI: Fix server init [#22443](https://github.com/storybooks/storybook/pull/22443)\n- Server: Add json indexer [#22460](https://github.com/storybooks/storybook/pull/22460)\n- React: Use correct default annotations for composeStories [#22308](https://github.com/storybooks/storybook/pull/22308)\n- UI: Fix opacity of list-item color [#22074](https://github.com/storybooks/storybook/pull/22074)\n\n#### Maintenance\n\n- CLI: Refactor package manager methods to be async [#22401](https://github.com/storybooks/storybook/pull/22401)\n- Angular: Improve Error message for angular.json not found [#22377](https://github.com/storybooks/storybook/pull/22377)\n- TypeScript: Migrate @storybook/instrumenter to strict TS [#22370](https://github.com/storybooks/storybook/pull/22370)\n- TypeScript: Migrate @storybook/core-events to strict TS [#22448](https://github.com/storybooks/storybook/pull/22448)\n- TypeScript: Migrate @storybook/core-client to strict TS [#22447](https://github.com/storybooks/storybook/pull/22447)\n- TypeScript: Migrate @storybook/react-vite and @storybook/preact-vite to strict TS [#22428](https://github.com/storybooks/storybook/pull/22428)\n- TypeScript: Migrate @storybook/svelte-vite to strict TS [#22411](https://github.com/storybooks/storybook/pull/22411)\n- TypeScript: Migrate @storybook/types to strict TS [#22397](https://github.com/storybooks/storybook/pull/22397)\n- TypeScript: Migrate @storybook/addon-storysource to strict TS [#22367](https://github.com/storybooks/storybook/pull/22367)\n- TypeScript: Migrate @storybook/client-api to strict TS [#22421](https://github.com/storybooks/storybook/pull/22421)\n- TypeScript: Migrate @storybook/sveltekit to strict TS [#22412](https://github.com/storybooks/storybook/pull/22412)\n- TypeScript: Migrate @storybook/source-loader to strict TS [#22420](https://github.com/storybooks/storybook/pull/22420)\n\n## 7.1.0-alpha.13 (May 5, 2023)\n\n#### Bug Fixes\n\n- Core: Fix virtual modules excluded for babel-loader [#22331](https://github.com/storybooks/storybook/pull/22331)\n\n#### Maintenance\n\n- Angular: Allow TypeScript 4.0.0 and 5.0.0 [#22391](https://github.com/storybooks/storybook/pull/22391)\n- Angular: Enable Angular Unit tests [#22355](https://github.com/storybooks/storybook/pull/22355)\n- TypeScript: Migrate @storybook/theming to strict TS [#22376](https://github.com/storybooks/storybook/pull/22376)\n- TypeScript: Migrate @storybook/channel-websocket to strict TS [#22364](https://github.com/storybooks/storybook/pull/22364)\n- TypeScript: Migrate @storybook/addon-outline to strict TS [#22369](https://github.com/storybooks/storybook/pull/22369)\n- TypeScript: Migrate @storybook/addon-viewbook to strict ts [#22339](https://github.com/storybooks/storybook/pull/22339)\n- TypeScript: Migrate @storybook/channels to strict TS [#22365](https://github.com/storybooks/storybook/pull/22365)\n\n#### Build\n\n- Add Angular Prerelease sandbox [#22379](https://github.com/storybooks/storybook/pull/22379)\n\n## 7.1.0-alpha.12 (May 3, 2023)\n\n#### Bug Fixes\n\n- Migrate: skip the automigration for gf markdown when user isn't using mdx [#22186](https://github.com/storybooks/storybook/pull/22186)\n- UI: Addon panel does not update after disabling/enabling an addon [#22258](https://github.com/storybooks/storybook/pull/22258)\n- Typescript: Fix bad typings caused by tsup bug [#22261](https://github.com/storybooks/storybook/pull/22261)\n- Core: Fix source snippets for stories with mapped args [#22135](https://github.com/storybooks/storybook/pull/22135)\n\n#### Maintenance\n\n- Telemetry: Persist sessionId across runs [#22325](https://github.com/storybooks/storybook/pull/22325)\n- Packaging: Move `types` condition to the front in all `package.json.exports` maps [#22321](https://github.com/storybooks/storybook/pull/22321)\n- Packaging: Don't generate ESM dist for preset files [#22330](https://github.com/storybooks/storybook/pull/22330)\n- Typescript: Migrate `@storybook/csf-tools` to strict TS [#22312](https://github.com/storybooks/storybook/pull/22312)\n- Typescript: Migrate @storybook/postinstall and @storybook/router to strict TS [#22200](https://github.com/storybooks/storybook/pull/22200)\n- Maintenance: Fix urls for all packages in package.json [#22101](https://github.com/storybooks/storybook/pull/22101)\n- Docs: Improve component typings [#22050](https://github.com/storybooks/storybook/pull/22050)\n\n#### Build\n\n- Build: Comment out flaky test [#22310](https://github.com/storybooks/storybook/pull/22310)\n- Build: Migrate `@storybook/web-components-vite` to strict TS [#22309](https://github.com/storybooks/storybook/pull/22309)\n- Build: Migrate `@storybook/html-vite` to strict TS [#22293](https://github.com/storybooks/storybook/pull/22293)\n- Build: Migrate @storybook/preset-vue-webpack to strict TS [#22320](https://github.com/storybooks/storybook/pull/22320)\n- Build: Use `next` branch for sandbox and repro commands [#22238](https://github.com/storybooks/storybook/pull/22238)\n\n## 7.1.0-alpha.11 (April 28, 2023)\n\n#### Features\n\n- Feature: Add support for Angular 16 [#22096](https://github.com/storybooks/storybook/pull/22096)\n\n#### Bug Fixes\n\n- Vue3: Rollback v7 breaking change and keep reactive v6-compatible API [#22229](https://github.com/storybooks/storybook/pull/22229)\n\n#### Maintenance\n\n- Core: Add tests for mapping behaviour in #22169 [#22301](https://github.com/storybooks/storybook/pull/22301)\n\n#### Dependency Upgrades\n\n- Update glob to v10.0.0 [#22171](https://github.com/storybooks/storybook/pull/22171)\n\n## 7.1.0-alpha.10 (April 28, 2023)\n\n#### Bug Fixes\n\n- Vue3: Fix compiler error when there is double tag [#22286](https://github.com/storybooks/storybook/pull/22286)\n- Args: Fix multiple mapped args return array of labels [#22169](https://github.com/storybooks/storybook/pull/22169)\n- Angular: Fix storyshots by removing deprecated import [#22134](https://github.com/storybooks/storybook/pull/22134)\n- Ember: Fix wrong path [#22203](https://github.com/storybooks/storybook/pull/22203)\n- CLI: Add web-components webpack5 to missing-babelrc automigration [#22202](https://github.com/storybooks/storybook/pull/22202)\n- Docs: Fix inline story style [#21870](https://github.com/storybooks/storybook/pull/21870)\n\n#### Build\n\n- Fix vue-cli/default-js sandbox [#22259](https://github.com/storybooks/storybook/pull/22259)\n- Core: Fix `DOCS_RENDERED` test [#22255](https://github.com/storybooks/storybook/pull/22255)\n- Add regex to ignore outdated Browserslist in Jest initialization base file [#22260](https://github.com/storybooks/storybook/pull/22260)\n\n## 7.1.0-alpha.9 (April 26, 2023)\n\n#### Features\n\n- NextJS: Allow disabling next/image lazy loading [#21909](https://github.com/storybooks/storybook/pull/21909)\n- Core: Allow Flow syntax in stories [#21859](https://github.com/storybooks/storybook/pull/21859)\n\n#### Bug Fixes\n\n- Vue3: Support multiple setup functions [#22170](https://github.com/storybooks/storybook/pull/22170)\n- UI: Fix shift + 7 shortcut to focus search field [#22073](https://github.com/storybooks/storybook/pull/22073)\n- UI: Fix controls missing when navigating from story [#21967](https://github.com/storybooks/storybook/pull/21967)\n\n#### Maintenance\n\n- Core: Rename manager UI mjs to js [#22247](https://github.com/storybooks/storybook/pull/22247)\n- Remove dead code [#22019](https://github.com/storybooks/storybook/pull/22019)\n- Vue3: Move TS stories into a separate folder [#22235](https://github.com/storybooks/storybook/pull/22235)\n\n#### Build\n\n- Build: Migrate @storybook/addon-docs to strict-ts [#22180](https://github.com/storybooks/storybook/pull/22180)\n- Build: Migrate @storybook/highlight to strict TS [#22181](https://github.com/storybooks/storybook/pull/22181)\n- Build: Enable strict TS by default [#22143](https://github.com/storybooks/storybook/pull/22143)\n\n## 7.1.0-alpha.8 (April 24, 2023)\n\n#### Features\n\n- Core: Support custom hosts using window.location server channel URL [#22055](https://github.com/storybooks/storybook/pull/22055)\n\n#### Bug Fixes\n\n- Addon-actions: Fix ESM by upgrading from uuid-browser to uuid [#22037](https://github.com/storybooks/storybook/pull/22037)\n- Addon-actions: Fix decorator type [#22175](https://github.com/storybooks/storybook/pull/22175)\n- NextJS: Fix tsconfig resolution [#22160](https://github.com/storybooks/storybook/pull/22160)\n- Core: Pass parameters in `SET_INDEX` for docs entries [#22154](https://github.com/storybooks/storybook/pull/22154)\n\n#### Maintenance\n\n- CSF: Improve error message for bad default export [#22190](https://github.com/storybooks/storybook/pull/22190)\n- CLI: Add addon query-params to list of SB7 incompatible addons [#22095](https://github.com/storybooks/storybook/pull/22095)\n\n#### Build\n\n- Build: Fix sandbox publish script [#22206](https://github.com/storybooks/storybook/pull/22206)\n- Build: Fix lit sandboxes [#22201](https://github.com/storybooks/storybook/pull/22201)\n- Vite sandboxes: use stable Vite 4.3 [#22183](https://github.com/storybooks/storybook/pull/22183)\n\n## 7.1.0-alpha.7 (April 19, 2023)\n\n#### Bug Fixes\n\n- Vue3: Fix reactive decorators [#21954](https://github.com/storybooks/storybook/pull/21954)\n\n#### Build\n\n- Build: Improve sandboxes commit message [#22136](https://github.com/storybooks/storybook/pull/22136)\n\n## 7.1.0-alpha.6 (April 18, 2023)\n\n#### Bug Fixes\n\n- Core: Restore Docs `useParameter` using `DOCS_PREPARED` [#22118](https://github.com/storybooks/storybook/pull/22118)\n- Core: Add new tags to distinguish docs attachment [#22120](https://github.com/storybooks/storybook/pull/22120)\n- Core: Fix `module` guard in non-webpack environments [#22085](https://github.com/storybooks/storybook/pull/22085)\n\n#### Build\n\n- Build: Skip docs pages e2e tests for ssv6 examples [#22141](https://github.com/storybooks/storybook/pull/22141)\n- Build: Upgrade Playwright to 1.32.3 [#22087](https://github.com/storybooks/storybook/pull/22087)\n\n#### Dependency Upgrades\n\n- Remove unused babel dependencies [#21984](https://github.com/storybooks/storybook/pull/21984)\n\n## 7.1.0-alpha.5 (April 17, 2023)\n\n#### Maintenance\n\n- CLI: Mark qwik as using addon-interactions [#22000](https://github.com/storybooks/storybook/pull/22000)\n\n#### Build\n\n- Revert \"Build: Update dangerfile temporarily to check for patch label\" [#22108](https://github.com/storybooks/storybook/pull/22108)\n\n## 7.1.0-alpha.4 (April 15, 2023)\n\n#### Bug Fixes\n\n- Docs: Fix source snippets when parameters.docs.source.type = 'code' [#22048](https://github.com/storybooks/storybook/pull/22048)\n- CLI: Mention how to setup a monorepo manually in babelrc automigration [#22052](https://github.com/storybooks/storybook/pull/22052)\n\n## 7.1.0-alpha.3 (April 13, 2023)\n\n#### Bug Fixes\n\n- UI: Fix upgrade command in about page [#22056](https://github.com/storybooks/storybook/pull/22056)\n- CLI: Fix sandbox command [#21977](https://github.com/storybooks/storybook/pull/21977)\n\n## 7.1.0-alpha.2 (April 12, 2023)\n\n#### Features\n\n- UI: Add remount story shortcut [#21401](https://github.com/storybooks/storybook/pull/21401)\n\n#### Bug Fixes\n\n- CLI: Catch errors thrown on sanity check of SB installs [#22039](https://github.com/storybooks/storybook/pull/22039)\n\n#### Maintenance\n\n- Addon-docs: Remove mdx1-csf as optional peer dep [#22038](https://github.com/storybooks/storybook/pull/22038)\n- Telemetry: Add CLI version to context [#21999](https://github.com/storybooks/storybook/pull/21999)\n\n#### Build\n\n- Build: Use vite@beta on sandboxes [#22030](https://github.com/storybooks/storybook/pull/22030)\n- Fix e2e tests failing in Firefox [#22022](https://github.com/storybooks/storybook/pull/22022)\n- Vite: Use vite 4.3 beta in sandboxes [#21986](https://github.com/storybooks/storybook/pull/21986)\n\n## 7.1.0-alpha.1 (April 11, 2023)\n\n#### Bug Fixes\n\n- React: Fix default export docgen for React.FC and forwardRef [#22024](https://github.com/storybooks/storybook/pull/22024)\n- Viewport: Remove transitions when switching viewports [#21963](https://github.com/storybooks/storybook/pull/21963)\n- CLI: Fix JsPackageManager typo [#22006](https://github.com/storybooks/storybook/pull/22006)\n- Viewport: Fix the `defaultOrientation` config option [#21962](https://github.com/storybooks/storybook/pull/21962)\n- UI: Fix story data access for broken About page [#21951](https://github.com/storybooks/storybook/pull/21951)\n\n#### Maintenance\n\n- CLI: Update template code references to 7.0 [#21845](https://github.com/storybooks/storybook/pull/21845)\n\n#### Dependency Upgrades\n\n- React-vite: Fix perf regression by pinning vite-plugin-react-docgen-ts [#22013](https://github.com/storybooks/storybook/pull/22013)\n- Use future version of satellite repo dependencies [#22026](https://github.com/storybooks/storybook/pull/22026)\n\n## 7.1.0-alpha.0 (April 5, 2023)\n\n#### Bug Fixes\n\n- Angular: Fix components disappearing on docs page on property change [#21944](https://github.com/storybooks/storybook/pull/21944)\n- React: Don't show decorators in JSX snippets [#21907](https://github.com/storybooks/storybook/pull/21907)\n- Docs: Include decorators by default in source decorators [#21902](https://github.com/storybooks/storybook/pull/21902)\n- CLI: Fix npm list command [#21947](https://github.com/storybooks/storybook/pull/21947)\n- Core: Revert Emotion `:first-child` (etc) workarounds [#21213](https://github.com/storybooks/storybook/pull/21213)\n- Addon-actions: Fix non-included type file [#21922](https://github.com/storybooks/storybook/pull/21922)\n- Addon GFM: Fix node-logger dependency [#21938](https://github.com/storybooks/storybook/pull/21938)\n\n#### Build\n\n- Build: Update trigger circle ci workflow to include main [#21888](https://github.com/storybooks/storybook/pull/21888)\n- Build: Update dangerfile temporarily to check for patch label [#21945](https://github.com/storybooks/storybook/pull/21945)\n- Build: Re-enable Vue2 Vite sandbox [#21940](https://github.com/storybooks/storybook/pull/21940)\n- Build: Fix release badge on repros [#21923](https://github.com/storybooks/storybook/pull/21923)\n- Build: fix the workflows to generate sandboxes [#21912](https://github.com/storybooks/storybook/pull/21912)\n- Build: bump the node version in CI [#21917](https://github.com/storybooks/storybook/pull/21917)\n- Build: no `pnp.cjs` in the root, regen lockfiles [#21908](https://github.com/storybooks/storybook/pull/21908)\n- Build: remove pnp sandbox template [#21913](https://github.com/storybooks/storybook/pull/21913)\n- Build: make the CI config ready for 7.0 release [#21808](https://github.com/storybooks/storybook/pull/21808)\n\n#### Dependency Upgrades\n\n- Update `@emotion/cache` version [#21941](https://github.com/storybooks/storybook/pull/21941)\n"
  },
  {
    "path": "CHANGELOG.v1-5.md",
    "content": "## 5.3.7 (January 20, 2020)\n\n### Bug Fixes\n\n- Node-logger: Move `@types/npmlog` to dependencies ([#9538](https://github.com/storybookjs/storybook/pull/9538))\n- Core: Fix legacy story URLs ([#9545](https://github.com/storybookjs/storybook/pull/9545))\n- Addon-docs: Convert default prop value to string ([#9525](https://github.com/storybookjs/storybook/pull/9525))\n- Addon-docs: Preserve Source indentation by default ([#9513](https://github.com/storybookjs/storybook/pull/9513))\n\n## 5.3.6 (January 17, 2020)\n\n### Bug Fixes\n\n- Source-loader: Bypass if file has no exports ([#9505](https://github.com/storybookjs/storybook/pull/9505))\n- Core: Fix default sorting of docs-only stories ([#9504](https://github.com/storybookjs/storybook/pull/9504))\n\n## 5.3.5 (January 17, 2020)\n\n### Bug Fixes\n\n- Core: Fix typo for loading addon-notes/register-panel ([#9497](https://github.com/storybookjs/storybook/pull/9497))\n- Source-loader: Add imports to top of file ([#9492](https://github.com/storybookjs/storybook/pull/9492))\n\n## 5.3.4 (January 16, 2020)\n\n### Bug Fixes\n\n- Core: Fix presets register panel ([#9486](https://github.com/storybookjs/storybook/pull/9486))\n- Core: Fix addon/preset detection for local addons ([#9485](https://github.com/storybookjs/storybook/pull/9485))\n- Core: Fix default story sort ([#9482](https://github.com/storybookjs/storybook/pull/9482))\n\n## 5.3.3 (January 14, 2020)\n\n### Bug Fixes\n\n- UI: Fix edge case where only one legacy separator is defined ([#9425](https://github.com/storybookjs/storybook/pull/9425))\n- Core: Preserve kind load order on HMR when no sortFn is provided ([#9424](https://github.com/storybookjs/storybook/pull/9424))\n- Angular: Fix missing architect properties ([#9390](https://github.com/storybookjs/storybook/pull/9390))\n- Addon-knobs: Fix null knob values in select ([#9416](https://github.com/storybookjs/storybook/pull/9416))\n- Source-loader: Disable linting altogether ([#9417](https://github.com/storybookjs/storybook/pull/9417))\n\n## 5.3.2 (January 13, 2020)\n\n### Bug Fixes\n\n- Source-loader: Disable eslint entirely for generated code ([#9410](https://github.com/storybookjs/storybook/pull/9410))\n\n## 5.3.1 (January 12, 2020)\n\n### Bug Fixes\n\n- Core: Fix generated entry to import at top of file ([#9398](https://github.com/storybookjs/storybook/pull/9398))\n\n## 5.3.0 (January 11, 2020)\n\nStorybook 5.3 is here!\n\n- 📝 [Custom documentation in MDX](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc)\n- 🎨 [Multi-framework SB Docs (React, Vue, Angular, WC, Ember)](https://medium.com/storybookjs/storybook-docs-for-new-frameworks-b1f6090ee0ea)\n- 📦 [Web-components framework support](https://dev.to/open-wc/storybook-for-web-components-on-steroids-4h29)\n- 🔼 [Main.js declarative configuration](https://medium.com/storybookjs/declarative-storybook-configuration-49912f77b78)\n\n  5.3 contains hundreds more fixes, features, and tweaks. Browse the changelogs matching `5.3.0-alpha.*`, `5.3.0-beta.*`, and `5.3.0-rc.*` for the full list of changes. See [MIGRATION.md](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md) to upgrade from `5.0` or earlier.\n\n## 5.3.0-rc.14 (January 11, 2020)\n\n- Merge `master` into `next` for 5.3.0 release ([#9388](https://github.com/storybookjs/storybook/pull/9388))\n\n## 5.3.0-rc.13 (January 11, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Fix link CORS errors using channel navigate event ([#9381](https://github.com/storybookjs/storybook/pull/9381))\n- CLI: Fix `sb init` to use spawn.sync if creating package.json ([#9359](https://github.com/storybookjs/storybook/pull/9359))\n\n### Maintenance\n\n- Official-storybook: Prop table example for multiple named exports ([#9364](https://github.com/storybookjs/storybook/pull/9364))\n- Addon-docs / web-components: Rename 'props' to 'properties' in props table ([#9362](https://github.com/storybookjs/storybook/pull/9362))\n\n### Dependency Upgrades\n\n- Upgrade @types/webpack-env and @types/node to fix conflicting types ([#9365](https://github.com/storybookjs/storybook/pull/9365))\n\n## 5.3.0-rc.12 (January 8, 2020)\n\n### Bug Fixes\n\n- Nav UI: Nodes are components only if they contain ALL leaf nodes ([#9356](https://github.com/storybookjs/storybook/pull/9356))\n- Core: Fix HMR for global decorators in main.js config ([#9354](https://github.com/storybookjs/storybook/pull/9354))\n- Presets: Fix register.js addons entry ([#9347](https://github.com/storybookjs/storybook/pull/9347))\n- React: Check CRA is installed before showing warning ([#9346](https://github.com/storybookjs/storybook/pull/9346))\n\n## 5.3.0-rc.11 (January 7, 2020)\n\n### Bug Fixes\n\n- Addon-Docs: Handle leaf/non-leaf mixture in docs-mode navigation ([#9321](https://github.com/storybookjs/storybook/pull/9321))\n\n### Dependency Upgrades\n\n- Axe storyshots: move to original @wordpress/jest-puppeteer-axe package ([#9337](https://github.com/storybookjs/storybook/pull/9337))\n\n## 5.3.0-rc.10 (January 6, 2020)\n\n### Bug Fixes\n\n- Revert \"Source-loader: Disable no-implicit-any linting\" ([#9333](https://github.com/storybookjs/storybook/pull/9333))\n- Addon-docs: Fix scroll behavior on page navigation ([#9331](https://github.com/storybookjs/storybook/pull/9331))\n\n## 5.3.0-rc.9 (January 4, 2020)\n\n### Features\n\n- CSF: Use `__namedExportsOrder` array in loader if provided ([#9315](https://github.com/storybookjs/storybook/pull/9315))\n\n### Bug Fixes\n\n- Router: Add storyNameFromExport to avoid breaking changes ([#9320](https://github.com/storybookjs/storybook/pull/9320))\n\n## 5.3.0-rc.8 (January 3, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Tweak props table paragraph spacing ([#9307](https://github.com/storybookjs/storybook/pull/9307))\n\n### Maintenance\n\n- Add minimal typescript component to official-storybook ([#9308](https://github.com/storybookjs/storybook/pull/9308))\n\n### Dependency Upgrades\n\n- React: Upgrade babel-plugin-react-docgen to 4.0.0 ([#9303](https://github.com/storybookjs/storybook/pull/9303))\n\n## 5.3.0-rc.7 (January 2, 2020)\n\n### Bug Fixes\n\n- Core: Fix babel.js to disable simplify ([#9280](https://github.com/storybookjs/storybook/pull/9280))\n- Storyshots-Puppeteer: Don't infer story ID from its name ([#9291](https://github.com/storybookjs/storybook/pull/9291))\n\n## 5.3.0-rc.6 (December 31, 2019)\n\nThis is significant change to `main.js` aka tri-config, dramatically simplifying how addons and presets are registered. See the maintenance PR for details.\n\n### Maintenance\n\n- Main.js: Combine presets/registers in `addons` field ([#9246](https://github.com/storybookjs/storybook/pull/9246))\n\n## 5.3.0-rc.5 (December 31, 2019)\n\n### Bug Fixes\n\n- Addon-docs: Hide stories block when there are no stories ([#9271](https://github.com/storybookjs/storybook/pull/9271))\n- Source-loader: Disable no-implicit-any linting ([#9272](https://github.com/storybookjs/storybook/pull/9272))\n\n## 5.3.0-rc.4 (December 28, 2019)\n\n### Bug Fixes\n\n- Addon-docs: Fix MDX story rendering with dynamic component titles ([#9248](https://github.com/storybookjs/storybook/pull/9248))\n\n### Maintenance\n\n- Ignore testfixtures directory in storybook publish ([#9244](https://github.com/storybookjs/storybook/pull/9244))\n\n## 5.3.0-rc.3 (December 26, 2019)\n\n### Bug Fixes\n\n- Addon-docs: Include ember files in addon-docs publish ([#9230](https://github.com/storybookjs/storybook/pull/9230))\n\n### Maintenance\n\n- Standalone CSF example ([#9223](https://github.com/storybookjs/storybook/pull/9223))\n\n### Dependency Upgrades\n\n- Addon-info: Upgrade marksy for security ([#9234](https://github.com/storybookjs/storybook/pull/9234))\n\n## 5.3.0-rc.2 (December 26, 2019)\n\nFailed NPM publish\n\n## 5.3.0-rc.1 (December 23, 2019)\n\n### Bug Fixes\n\n- Angular: Add default value to the budgets property ([#9207](https://github.com/storybookjs/storybook/pull/9207))\n- DocsPage: Fix title with new path separator scheme ([#9204](https://github.com/storybookjs/storybook/pull/9204))\n\n### Maintenance\n\n- CLI: Make template `stories` glob more permissive ([#9224](https://github.com/storybookjs/storybook/pull/9224))\n\n## 5.3.0-rc.0 (December 19, 2019)\n\n### Features\n\n- CSF: Use `__orderedExports` in loader if provided ([#9181](https://github.com/storybookjs/storybook/pull/9181))\n\n### Bug Fixes\n\n- Addon-a11y: Fix selected blindness color filter ([#9179](https://github.com/storybookjs/storybook/pull/9179))\n\n### Maintenance\n\n- Addon-essentials: Remove actions, links, knobs ([#9184](https://github.com/storybookjs/storybook/pull/9184))\n\n## 5.3.0-beta.31 (December 16, 2019)\n\n### Features\n\n- React: Add support for CRA without overrides ([#9157](https://github.com/storybookjs/storybook/pull/9157))\n- Addon-docs: Add fontFamily prop to Typeset component ([#9158](https://github.com/storybookjs/storybook/pull/9158))\n\n### Bug Fixes\n\n- Core: Emit store render event synchronously if we can ([#9087](https://github.com/storybookjs/storybook/pull/9087))\n\n## 5.3.0-beta.30 (December 16, 2019)\n\nFailed NPM publish\n\n## 5.3.0-beta.29 (December 16, 2019)\n\nFailed NPM publish\n\n## 5.3.0-beta.28 (December 16, 2019)\n\nFailed NPM publish\n\n## 5.3.0-beta.27 (December 16, 2019)\n\nFailed NPM publish\n\n## 5.3.0-beta.26 (December 16, 2019)\n\nFailed NPM publish\n\n## 5.3.0-beta.25 (December 15, 2019)\n\n### Bug Fixes\n\n- Addon-docs: Hide addons on docs-only stories ([#9125](https://github.com/storybookjs/storybook/pull/9125))\n\n### Dependency Upgrades\n\n- Upgrade vue-docgen-loader to 1.3.0-beta.0 ([#9155](https://github.com/storybookjs/storybook/pull/9155))\n\n## 5.3.0-beta.24 (December 15, 2019)\n\nFailed NPM publish\n\n## 5.3.0-beta.23 (December 14, 2019)\n\n### Features\n\n- Addon-docs: Render components as leaves in `--docs` mode ([#7700](https://github.com/storybookjs/storybook/pull/7700))\n\n### Bug Fixes\n\n- Addon-viewport: Allow viewports config to be optional ([#9137](https://github.com/storybookjs/storybook/pull/9137))\n\n## 5.3.0-beta.22 (December 12, 2019)\n\n### Bug Fixes\n\n- React: Fix CRA preset check ([#9142](https://github.com/storybookjs/storybook/pull/9142))\n\n### Maintenance\n\n- Build: Change CI to chromatic on all examples ([#9114](https://github.com/storybookjs/storybook/pull/9114))\n- Web-components: Clean up example `custom-elements.json` and expose `defaultValue` ([#9107](https://github.com/storybookjs/storybook/pull/9107))\n\n### Dependency Upgrades\n\n- Restore main jscodeshift package ([#9140](https://github.com/storybookjs/storybook/pull/9140))\n\n## 5.3.0-beta.21 (December 11, 2019)\n\n### Features\n\n- CLI: Add Yarn workspaces support for init command ([#9104](https://github.com/storybookjs/storybook/pull/9104))\n\n### Bug Fixes\n\n- Addon-docs: Update MDX compiler to fix knobs ([#9118](https://github.com/storybookjs/storybook/pull/9118))\n- CLI: Add web-components to sb init ([#9106](https://github.com/storybookjs/storybook/pull/9106))\n\n### Maintenance\n\n- UI: Remove css usage ([#9003](https://github.com/storybookjs/storybook/pull/9003))\n\n## 5.3.0-beta.20 (December 9, 2019)\n\n### Features\n\n- Addon-essentials: Remove docs from essentials ([#9093](https://github.com/storybookjs/storybook/pull/9093))\n\n### Bug Fixes\n\n- Source-loader: Handle includeStories/excludeStories in CSF ([#9100](https://github.com/storybookjs/storybook/pull/9100))\n- Source-loader: Support function declaration story exports ([#9092](https://github.com/storybookjs/storybook/pull/9092))\n\n### Maintenance\n\n- CSF: Refactor router utils into CSF library ([#9099](https://github.com/storybookjs/storybook/pull/9099))\n\n## 5.3.0-beta.19 (December 7, 2019)\n\n### Features\n\n- Addon-essentials ([#9019](https://github.com/storybookjs/storybook/pull/9019))\n\n### Bug Fixes\n\n- Addon-docs: Fix prop table default value for web-components ([#9086](https://github.com/storybookjs/storybook/pull/9086))\n\n## 5.3.0-beta.18 (December 6, 2019)\n\n### Features\n\n- CLI: Change generators to Triconfig ([#9075](https://github.com/storybookjs/storybook/pull/9075))\n- Addon-docs: Add Props for Ember ([#9067](https://github.com/storybookjs/storybook/pull/9067))\n- MDX: Handle quotes / template literals in title ([#9069](https://github.com/storybookjs/storybook/pull/9069))\n\n### Bug Fixes\n\n- Addon-docs: MDX Octicon anchors should not be tabbable ([#9063](https://github.com/storybookjs/storybook/pull/9063))\n\n### Dependency Upgrades\n\n- Addon-docs: Upgrade vue-docgen-loader ([#9082](https://github.com/storybookjs/storybook/pull/9082))\n\n## 5.3.0-beta.17 (December 6, 2019)\n\nNPM publish failed\n\n## 5.3.0-beta.16 (December 5, 2019)\n\n### Features\n\n- Addon-docs: DocsPage Heading and Subheading anchor links ([#9060](https://github.com/storybookjs/storybook/pull/9060))\n\n### Bug Fixes\n\n- Core: Fix `api.selectStory` for component permalinks ([#9054](https://github.com/storybookjs/storybook/pull/9054))\n- Storyshots: Escape Windows fileNames ([#9061](https://github.com/storybookjs/storybook/pull/9061))\n\n### Dependency Upgrades\n\n- Addon-docs: Upgrade vue-docgen-api ([#9066](https://github.com/storybookjs/storybook/pull/9066))\n\n## 5.3.0-beta.15 (December 4, 2019)\n\n### Features\n\n- Addon-docs: MDX Linking ([#9051](https://github.com/storybookjs/storybook/pull/9051))\n\n## 5.2.8 (December 2, 2019)\n\n### Bug Fixes\n\n- UI: Fix layout of Preview container ([#8628](https://github.com/storybookjs/storybook/pull/8628))\n- Core: Use `stable` package to ensure story sorting is stable ([#8795](https://github.com/storybookjs/storybook/pull/8795))\n- Source-loader: Warn if applied to non-stories file ([#8773](https://github.com/storybookjs/storybook/pull/8773))\n\n## 5.3.0-beta.14 (December 2, 2019)\n\n### Features\n\n- Addon-docs: Increase Props summary and func length ([#8998](https://github.com/storybookjs/storybook/pull/8998))\n\n### Bug Fixes\n\n- Addon-docs: Restore IE11 compat by transpiling acorn-jsx ([#9021](https://github.com/storybookjs/storybook/pull/9021))\n- Source-loader: Handle template strings in CSF title ([#8995](https://github.com/storybookjs/storybook/pull/8995))\n- CLI: Fix various storiesof-to-csf cases based on chromatic stories upgrade ([#9013](https://github.com/storybookjs/storybook/pull/9013))\n\n## 5.2.7 (November 30, 2019)\n\n### Bug Fixes\n\n- Addon-contexts: Fix 'cannot read property h of undefined' in preact ([#9001](https://github.com/storybookjs/storybook/pull/9001))\n- Addon-viewports: Fix missing TypeScript types ([#8848](https://github.com/storybookjs/storybook/pull/8848))\n- Addon-A11y: Show errors, reset config properly ([#8779](https://github.com/storybookjs/storybook/pull/8779))\n- UI: Store layout state in sessionStorage ([#8786](https://github.com/storybookjs/storybook/pull/8786))\n- UI: Fix MobileLayout component error on master ([#8941](https://github.com/storybookjs/storybook/pull/8941))\n- Addon-analytics: Fix 'path is required in .pageview()' ([#8468](https://github.com/storybookjs/storybook/pull/8468))\n\n## 5.3.0-beta.13 (November 30, 2019)\n\n### Bug Fixes\n\n- Addon-contexts: Fix 'cannot read property h of undefined' in preact ([#9001](https://github.com/storybookjs/storybook/pull/9001))\n\n### Maintenance\n\n- CLI: Code cleanup ([#9004](https://github.com/storybookjs/storybook/pull/9004))\n\n## 5.3.0-beta.12 (November 29, 2019)\n\n### Features\n\n- Storyshots: Support a11y tests, generic tests ([#8934](https://github.com/storybookjs/storybook/pull/8934))\n\n### Maintenance\n\n- Dev: Add vscode launch.json for debugging ([#8993](https://github.com/storybookjs/storybook/pull/8993))\n- UI: viewMode proptypes changed to any string ([#8994](https://github.com/storybookjs/storybook/pull/8994))\n- Addon-docs: Remove deprecated framework-specific docs presets ([#8985](https://github.com/storybookjs/storybook/pull/8985))\n\n### Dependency Upgrades\n\n- Addon-docs: Upgrade MDX dependencies ([#8991](https://github.com/storybookjs/storybook/pull/8991))\n\n## 5.3.0-beta.11 (November 28, 2019)\n\n### Features\n\n- UI: Escape hatch CSS on for \"active\" tablist buttons ([#8989](https://github.com/storybookjs/storybook/pull/8989))\n- Addon-docs: Added dark theme option to source component ([#8732](https://github.com/storybookjs/storybook/pull/8732))\n- Triconfig: Configure UI options overhaul ([#8871](https://github.com/storybookjs/storybook/pull/8871))\n\n### Bug Fixes\n\n- Addon-docs: Fix vertical alignment of props expandable ([#8953](https://github.com/storybookjs/storybook/pull/8953))\n- Addon-links: Fix return type of linkTo and examples ([#8975](https://github.com/storybookjs/storybook/pull/8975))\n\n## 5.3.0-beta.10 (November 27, 2019)\n\n### Features\n\n- MDX: Allow user to override `docs.container` parameter ([#8968](https://github.com/storybookjs/storybook/pull/8968))\n- Addon-docs: Increase docs content wrapper max-width to 1000px ([#8970](https://github.com/storybookjs/storybook/pull/8970))\n- Addon-docs: Prop table support for Angular directives ([#8922](https://github.com/storybookjs/storybook/pull/8922))\n- Addon-docs: Increase width of props table type column ([#8950](https://github.com/storybookjs/storybook/pull/8950))\n\n### Bug Fixes\n\n- Addon-docs: Fix `Preview` theming escape hatch ([#8969](https://github.com/storybookjs/storybook/pull/8969))\n- Core: Don't try to require .ts files from dist ([#8971](https://github.com/storybookjs/storybook/pull/8971))\n- Core: Use logger in base-webpack.config.js ([#8966](https://github.com/storybookjs/storybook/pull/8966))\n\n### Maintenance\n\n- Examples: Add \"debug\" script for storybook-official ([#8973](https://github.com/storybookjs/storybook/pull/8973))\n- Build: Upgrade to node 10 on netlify ([#8967](https://github.com/storybookjs/storybook/pull/8967))\n- Core/triconfig everywhere: migrate examples ([#8942](https://github.com/storybookjs/storybook/pull/8942))\n\n## 5.3.0-beta.9 (November 26, 2019)\n\n### Features\n\n- Storyshots: Remove abandoned storyshots when run with `-u` flag ([#8889](https://github.com/storybookjs/storybook/pull/8889))\n\n### Bug Fixes\n\n- Addon-docs: Support subcomponents as a top-level default export ([#8931](https://github.com/storybookjs/storybook/pull/8931))\n\n### Dependency Upgrades\n\n- Core: Add missing dependencies ([#8945](https://github.com/storybookjs/storybook/pull/8945))\n\n## 5.3.0-beta.8 (November 26, 2019)\n\n### Features\n\n- Storyshots-puppeteer: Add afterScreenshot handler ([#8092](https://github.com/storybookjs/storybook/pull/8092))\n\n### Bug Fixes\n\n- Core: Upgrade telejson to fix cross-origin frame error ([#8940](https://github.com/storybookjs/storybook/pull/8940))\n\n### Maintenance\n\n- Build: Fix image snapshots setup in official-storybook ([#8932](https://github.com/storybookjs/storybook/pull/8932))\n\n### Dependency Upgrades\n\n- Core: Add @babel/core peer dependency to @storybook/core ([#8933](https://github.com/storybookjs/storybook/pull/8933))\n\n## 5.3.0-beta.7 (November 26, 2019)\n\nFailed npm publish\n\n## 5.3.0-beta.6 (November 24, 2019)\n\n### Features\n\n- Presets: dynamic preset injection ([#8921](https://github.com/storybookjs/storybook/pull/8921))\n\n### Bug Fixes\n\n- Revert \"feat: use `puppeteer-core` instead of `puppeteer`\" ([#8925](https://github.com/storybookjs/storybook/pull/8925))\n- Addon-docs: Fix props detail tooltip to prevent cutting end of content ([#8923](https://github.com/storybookjs/storybook/pull/8923))\n\n### Maintenance\n\n- Addon-docs: Base code to improve the props table for TS ([#8905](https://github.com/storybookjs/storybook/pull/8905))\n- Build: Fix now deploy ([#8929](https://github.com/storybookjs/storybook/pull/8929))\n\n### Dependency Upgrades\n\n- Miscellaneous upgrades ([#8912](https://github.com/storybookjs/storybook/pull/8912))\n\n## 5.3.0-beta.5 (November 23, 2019)\n\nFailed npm publish\n\n## 5.3.0-beta.4 (November 23, 2019)\n\nFailed npm publish\n\n## 5.3.0-beta.3 (November 21, 2019)\n\n### Features\n\n- Addon-docs: Rich props table UI ([#8887](https://github.com/storybookjs/storybook/pull/8887))\n- Addon-docs: Improve basic support for Flow props ([#8890](https://github.com/storybookjs/storybook/pull/8890))\n- CLI: Avoid id changes after `storiesof-to-csf` migration ([#8856](https://github.com/storybookjs/storybook/pull/8856))\n\n### Bug Fixes\n\n- Addon-docs: Fix props table for sections props ([#8904](https://github.com/storybookjs/storybook/pull/8904))\n- Addon-docs: Fix Description block when no component provided ([#8902](https://github.com/storybookjs/storybook/pull/8902))\n- Angular: Fix project without `architect.build` option ([#6737](https://github.com/storybookjs/storybook/pull/6737))\n\n### Maintenance\n\n- Addon-docs: Docgen lib maintenance ([#8896](https://github.com/storybookjs/storybook/pull/8896))\n- Examples: Fix stories glob in official-storybook ([#8888](https://github.com/storybookjs/storybook/pull/8888))\n\n## 5.3.0-beta.2 (November 19, 2019)\n\n### Features\n\n- Addon-docs: Customizable DocPage doc blocks ([#8855](https://github.com/storybookjs/storybook/pull/8855))\n\n### Bug Fixes\n\n- Addon-docs: Add back Props \"exclude\" support ([#8868](https://github.com/storybookjs/storybook/pull/8868))\n- Addon-docs: Fix MDX component permalinking ([#8872](https://github.com/storybookjs/storybook/pull/8872))\n- Addon-docs: Fix regression to @ignore in Props ([#8867](https://github.com/storybookjs/storybook/pull/8867))\n\n### Maintenance\n\n- Addon-docs: Add tests for prop types default value ([#8869](https://github.com/storybookjs/storybook/pull/8869))\n\n## 5.3.0-beta.1 (November 18, 2019)\n\n### Features\n\n- Addon-google-analytics: Add gaOption config ([#8859](https://github.com/storybookjs/storybook/pull/8859))\n\n### Bug Fixes\n\n- Addon-docs: Fix props table props sorting for PropTypes ([#8857](https://github.com/storybookjs/storybook/pull/8857))\n- Fix layout of Preview container ([#8628](https://github.com/storybookjs/storybook/pull/8628))\n\n## 5.3.0-beta.0 (November 16, 2019)\n\nStorybook 5.3 is in beta y'all 🔥🔥🔥 It includes:\n\n- 📝 Longform documentation in MDX\n- 🎨 Multi-framework SB Docs (React, Vue, Angular, WC)\n- 📦 Web-components framework support\n- 🔼 Tri-config (experimental)\n\nSee the [latest changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) for a full list of changes.\n\n## 5.3.0-alpha.47 (November 16, 2019)\n\n### Features\n\n- Triconfig: Declarative story definition in main.js ([#8748](https://github.com/storybookjs/storybook/pull/8748))\n- Storyshots: Triconfig support ([#8765](https://github.com/storybookjs/storybook/pull/8765))\n\n### Bug Fixes\n\n- Addon-viewports: Fix missing TypeScript types ([#8848](https://github.com/storybookjs/storybook/pull/8848))\n\n### Dependency Upgrades\n\n- Dependency upgrades ([#8847](https://github.com/storybookjs/storybook/pull/8847))\n\n## 5.3.0-alpha.46 (November 16, 2019)\n\n### Features\n\n- Core: allow uppercase path names in url query param ([#8516](https://github.com/storybookjs/storybook/pull/8516))\n\n### Bug Fixes\n\n- Core: Fix null version check bug ([#8806](https://github.com/storybookjs/storybook/pull/8806))\n- Addon-notes: Fix anchor links ([#8132](https://github.com/storybookjs/storybook/pull/8132))\n\n### Maintenance\n\n- Refactor: remove useless variables from eslint config ([#8843](https://github.com/storybookjs/storybook/pull/8843))\n\n### Dependency Upgrades\n\n- Addon-docs: Replace `storybook-addon-vue-info` with `vue-docgen-loader` ([#8831](https://github.com/storybookjs/storybook/pull/8831))\n\n## 5.3.0-alpha.45 (November 14, 2019)\n\n### Breaking Changes\n\n- CSF: Deprecate displayName parameter ([#8775](https://github.com/storybookjs/storybook/pull/8775))\n\n### Features\n\n- Addon-docs: Rich prop tables ([#8826](https://github.com/storybookjs/storybook/pull/8826))\n- Core: Simplified hierarchy separators ([#8796](https://github.com/storybookjs/storybook/pull/8796))\n- CLI: Upgrade hierarchy separator codemod + examples ([#8818](https://github.com/storybookjs/storybook/pull/8818))\n- CLI: Addon postinstall hooks ([#8700](https://github.com/storybookjs/storybook/pull/8700))\n- CSF/MDX: Add component id for permalinks ([#8808](https://github.com/storybookjs/storybook/pull/8808))\n- Addon-knobs: Add object[] support for select ([#7957](https://github.com/storybookjs/storybook/pull/7957))\n\n### Bug Fixes\n\n- Addon-A11y: Show errors, reset config properly ([#8779](https://github.com/storybookjs/storybook/pull/8779))\n\n## 5.3.0-alpha.44 (November 13, 2019)\n\n### Features\n\n- React-native: Add theming to ondevice-addons ([#8738](https://github.com/storybookjs/storybook/pull/8738))\n\n### Bug Fixes\n\n- UI: Store layout state in sessionStorage ([#8786](https://github.com/storybookjs/storybook/pull/8786))\n- Core: Use `stable` package to ensure story sorting is stable ([#8795](https://github.com/storybookjs/storybook/pull/8795))\n\n### Maintenance\n\n- Svelte: Migrate @storybook/svelte to Typescript ([#8770](https://github.com/storybookjs/storybook/pull/8770))\n\n## 5.3.0-alpha.43 (November 11, 2019)\n\n### Bug Fixes\n\n- Source-loader: Warn if applied to non-stories file ([#8773](https://github.com/storybookjs/storybook/pull/8773))\n\n### Maintenance\n\n- Presets / Addon-docs: Cleanup framework-specific presets ([#8782](https://github.com/storybookjs/storybook/pull/8782))\n- Add @babel/runtime to workspace ([#8774](https://github.com/storybookjs/storybook/pull/8774))\n\n## 5.2.6 (November 9, 2019)\n\n### Bug Fixes\n\n- Addon-info: Remove jsnext:main ([#8764](https://github.com/storybookjs/storybook/pull/8764))\n- Addon-info: Fix \"The prop 'children' is marked as required in 'Td'\" ([#8745](https://github.com/storybookjs/storybook/pull/8745))\n- UI: Fix unmount components on Canvas/Docs tab switch ([#8625](https://github.com/storybookjs/storybook/pull/8625))\n- Addon-docs: Fix code style inside LI ([#8708](https://github.com/storybookjs/storybook/pull/8708))\n- Remove min-height CSS rule from DocsPage wrapper ([#8366](https://github.com/storybookjs/storybook/pull/8366))\n- Core: Revert webpack rebuild changes in node_modules ([#8657](https://github.com/storybookjs/storybook/pull/8657))\n- Addon-notes: Add key to render function ([#8633](https://github.com/storybookjs/storybook/pull/8633))\n- Addon-docs: Fix story scroll-to heuristics ([#8629](https://github.com/storybookjs/storybook/pull/8629))\n- React-native-server: Changed default port to number in CLI options ([#8584](https://github.com/storybookjs/storybook/pull/8584))\n- Increase TooltipLinkList max-height to accommodate more links ([#8545](https://github.com/storybookjs/storybook/pull/8545))\n- Prevent form submission as search is done while typing ([#8546](https://github.com/storybookjs/storybook/pull/8546))\n- Ondevice-knobs: Fix peer dep ([#8644](https://github.com/storybookjs/storybook/pull/8644))\n\n## 5.3.0-alpha.42 (November 9, 2019)\n\n### Bug Fixes\n\n- Addon-info: Remove jsnext:main ([#8764](https://github.com/storybookjs/storybook/pull/8764))\n- Addon-info: Fix \"The prop 'children' is marked as required in 'Td'\" ([#8745](https://github.com/storybookjs/storybook/pull/8745))\n\n### Maintenance\n\n- React-native: Update compilation target - it was compiled for old browsers ([#8698](https://github.com/storybookjs/storybook/pull/8698))\n\n## 5.3.0-alpha.41 (November 7, 2019)\n\n### Features\n\n- Addon-docs: Render array of shape properly in props table ([#8707](https://github.com/storybookjs/storybook/pull/8707))\n- Addon-docs: Render params description in props table, support @ignore ([#8702](https://github.com/storybookjs/storybook/pull/8702))\n\n### Bug Fixes\n\n- Addon-docs: Fix \"Cannot read property 'props'\" ([#8731](https://github.com/storybookjs/storybook/pull/8731))\n- UI: Fix unmount components on Canvas/Docs tab switch ([#8625](https://github.com/storybookjs/storybook/pull/8625))\n- Angular: Fix loading baseConfig if no angular.json found ([#8727](https://github.com/storybookjs/storybook/pull/8727))\n\n## 5.3.0-alpha.40 (November 6, 2019)\n\n### Features\n\n- TriConfig configuration refactor ([#8597](https://github.com/storybookjs/storybook/pull/8597))\n- Presets: Ability to combine presets into another preset ([#6828](https://github.com/storybookjs/storybook/pull/6828))\n\n### Bug Fixes\n\n- Theming: Fix invisible hr styles in typography ([#8659](https://github.com/storybookjs/storybook/pull/8659))\n\n### Maintenance\n\n- Build: caching to github workflows ([#8724](https://github.com/storybookjs/storybook/pull/8724))\n\n## 5.3.0-alpha.39 (November 5, 2019)\n\n### Breaking Changes\n\n- React-native: Require user-provided async storage ([#7801](https://github.com/storybookjs/storybook/pull/7801))\n\n### Features\n\n- Addon-docs: Inline rendering for web-components as default ([#8705](https://github.com/storybookjs/storybook/pull/8705))\n\n### Bug Fixes\n\n- Addon-docs: Fix recipe to use `notes` as component description ([#8718](https://github.com/storybookjs/storybook/pull/8718))\n- Addon-docs: Fix code style inside LI ([#8708](https://github.com/storybookjs/storybook/pull/8708))\n- React Native: Fix on-device-notes ([#8692](https://github.com/storybookjs/storybook/pull/8692))\n- React Native: On Device Knobs Groups Fix ([#8694](https://github.com/storybookjs/storybook/pull/8694))\n- React-native: Fix event listening for story navigation ([#8690](https://github.com/storybookjs/storybook/pull/8690))\n- React-Native: Add safe area wrapper for iphone x and later ([#8679](https://github.com/storybookjs/storybook/pull/8679))\n\n## 5.3.0-alpha.38 (November 3, 2019)\n\n### Bug Fixes\n\n- React-native: Patch rn-host-detect ([#8683](https://github.com/storybookjs/storybook/pull/8683))\n- React-native: Fix layout in RN61 so addons no longer initially displayed ([#8681](https://github.com/storybookjs/storybook/pull/8681))\n\n### Maintenance\n\n- React-native: Catch touch events when preview is minimized ([#8680](https://github.com/storybookjs/storybook/pull/8680))\n- React-native: Make menu bar have its own position instead of absolute ([#8678](https://github.com/storybookjs/storybook/pull/8678))\n\n## 5.3.0-alpha.37 (November 2, 2019)\n\n### Bug Fixes\n\n- Source-loader: Fix Typescript support ([#8499](https://github.com/storybookjs/storybook/pull/8499))\n\n## 5.3.0-alpha.36 (November 2, 2019)\n\n### Features\n\n- Addon-docs: Angular DocsPage props table ([#8621](https://github.com/storybookjs/storybook/pull/8621))\n- Addon-docs: Support jsdoc params to describe function signature ([#8660](https://github.com/storybookjs/storybook/pull/8660))\n\n### Bug Fixes\n\n- Addon-docs: Remove min-height CSS rule from DocsPage wrapper ([#8366](https://github.com/storybookjs/storybook/pull/8366))\n- Addon-docs: Check component propTypes before unwrapping ([#8665](https://github.com/storybookjs/storybook/pull/8665))\n\n## 5.3.0-alpha.35 (November 1, 2019)\n\n### Bug Fixes\n\n- Core: Revert webpack rebuild changes in node_modules ([#8657](https://github.com/storybookjs/storybook/pull/8657))\n- Ondevice-knobs: Fix peer dep ([#8643](https://github.com/storybookjs/storybook/pull/8643))\n\n## 5.3.0-alpha.34 (October 30, 2019)\n\n### Bug Fixes\n\n- Addon-notes: Add key to render function ([#8633](https://github.com/storybookjs/storybook/pull/8633))\n- Addon-docs: Fix story scroll-to heuristics ([#8629](https://github.com/storybookjs/storybook/pull/8629))\n- Addon-docs: Fix props table in no props case ([#8632](https://github.com/storybookjs/storybook/pull/8632))\n- Addon-docs/web-components: Add attributes to props table ([#8598](https://github.com/storybookjs/storybook/pull/8598))\n- CLI: Fix package.json update ([#8615](https://github.com/storybookjs/storybook/pull/8615))\n- React-native: Fix background style ([#8480](https://github.com/storybookjs/storybook/pull/8480))\n\n### Maintenance\n\n- Channel: Clean up test ([#8627](https://github.com/storybookjs/storybook/pull/8627))\n- RAX: Fix example app ([#8617](https://github.com/storybookjs/storybook/pull/8617))\n\n### Dependency Upgrades\n\n- Misc. dependency upgrades ([#8612](https://github.com/storybookjs/storybook/pull/8612))\n\n## 5.3.0-alpha.33 (October 28, 2019)\n\n### Maintenance\n\n- Web-components: Move custom-elements utils to app ([#8592](https://github.com/storybookjs/storybook/pull/8592))\n\n## 5.3.0-alpha.32 (October 28, 2019)\n\n### Features\n\n- Addon-docs: Props / Description for web-components ([#8585](https://github.com/storybookjs/storybook/pull/8585))\n- Core: Global addDecorator/addParameters ([#8573](https://github.com/storybookjs/storybook/pull/8573))\n- Addon-docs: Generalize Description doc block ([#8590](https://github.com/storybookjs/storybook/pull/8590))\n\n### Bug Fixes\n\n- React-native-server: Changed default port to number in CLI options ([#8584](https://github.com/storybookjs/storybook/pull/8584))\n\n### Maintenance\n\n- Typescript: Use native package types now available ([#8588](https://github.com/storybookjs/storybook/pull/8588))\n- Build: Fix now deploy maybe ([#8589](https://github.com/storybookjs/storybook/pull/8589))\n\n## 5.3.0-alpha.31 (October 27, 2019)\n\n### Dependency Upgrades\n\n- Upgrade babel-plugin-react-docgen to 4.0.0-beta.1 ([#8581](https://github.com/storybookjs/storybook/pull/8581))\n\n## 5.3.0-alpha.30 (October 27, 2019)\n\n### Features\n\n- Addon-docs: Modify Typeset doc block to accept units ([#8574](https://github.com/storybookjs/storybook/pull/8574))\n\n### Bug Fixes\n\n- Web-components: Use framework id 'web-components' ([#8579](https://github.com/storybookjs/storybook/pull/8579))\n\n### Maintenance\n\n- WC-kitchen-sink: Add babel-loader dependency ([#8578](https://github.com/storybookjs/storybook/pull/8578))\n\n### Dependency Upgrades\n\n- Upgrade babel-plugin-react-docgen to 3.2.0 ([#8580](https://github.com/storybookjs/storybook/pull/8580))\n\n## 5.3.0-alpha.29 (October 25, 2019)\n\n### Features\n\n- Addon-docs: Add props loader to vue preset ([#8567](https://github.com/storybookjs/storybook/pull/8567))\n\n### Dependency Upgrades\n\n- Angular: bump zone.js version in peer dependencies ([#8558](https://github.com/storybookjs/storybook/pull/8558))\n\n## 5.3.0-alpha.28 (October 25, 2019)\n\n### Features\n\n- Addon-docs: Publish web-components preset ([#8563](https://github.com/storybookjs/storybook/pull/8563))\n- Addon-docs: Vue slots/events props table + generalization ([#8489](https://github.com/storybookjs/storybook/pull/8489))\n\n## 5.3.0-alpha.27 (October 24, 2019)\n\n### Features\n\n- Core: Allow linking to kind/component ID ([#7648](https://github.com/storybookjs/storybook/pull/7648))\n- Addon-docs: Jest MDX transform for storyshots ([#8189](https://github.com/storybookjs/storybook/pull/8189))\n- CLI: Add flag to disable version checks ([#8488](https://github.com/storybookjs/storybook/pull/8488))\n- Typescript: add types for react demo ([#8517](https://github.com/storybookjs/storybook/pull/8517))\n\n### Bug Fixes\n\n- UI: Increase TooltipLinkList max-height to accommodate more links ([#8545](https://github.com/storybookjs/storybook/pull/8545))\n- UI: Prevent form submission as search is done while typing ([#8546](https://github.com/storybookjs/storybook/pull/8546))\n\n### Dependency Upgrades\n\n- Remove outdated and unused `jsx-to-string` library ([#8549](https://github.com/storybookjs/storybook/pull/8549))\n\n## 5.3.0-alpha.26 (October 23, 2019)\n\nFix web-components storybook dependencies\n\n## 5.3.0-alpha.25 (October 23, 2019)\n\n### Features\n\n- Web-components: New storybook app ([#8400](https://github.com/storybookjs/storybook/pull/8400))\n- Core: Allow custom postcss config ([#8498](https://github.com/storybookjs/storybook/pull/8498))\n\n## 5.3.0-alpha.24 (October 22, 2019)\n\n### Features\n\n- Docs: Highlight ts and tsx syntax ([#8493](https://github.com/storybookjs/storybook/pull/8493))\n\n### Bug Fixes\n\n- React-native-server: Convert port to number in CLI options ([#8491](https://github.com/storybookjs/storybook/pull/8491))\n\n### Maintenance\n\n- Automate codemod tests as jest snapshots ([#8506](https://github.com/storybookjs/storybook/pull/8506))\n\n### Dependency Upgrades\n\n- Add \"@types/react-textarea-autosize\" to dependencies ([#8503](https://github.com/storybookjs/storybook/pull/8503))\n\n## 5.2.5 (October 22, 2019)\n\n### Bug Fixes\n\n- UI: Fix React15 support ([#8454](https://github.com/storybookjs/storybook/pull/8454))\n- React-native-server: Convert port to number in CLI options ([#8491](https://github.com/storybookjs/storybook/pull/8491))\n- Addon-docs: Fix React.forwardedRef/memo props ([#8445](https://github.com/storybookjs/storybook/pull/8445))\n- MDX: Handle `<Story>` name starting with number ([#8469](https://github.com/storybookjs/storybook/pull/8469))\n- React: Fix custom themes breaking the welcome demo ([#8259](https://github.com/storybookjs/storybook/pull/8259))\n- Addon-jest: Make withTests type generic ([#8410](https://github.com/storybookjs/storybook/pull/8410))\n\n### Dependency Upgrades\n\n- [Security] Bump lodash from 4.17.11 to 4.17.15 ([#8351](https://github.com/storybookjs/storybook/pull/8351))\n\n### Dependency Upgrades\n\n- Add \"@types/react-textarea-autosize\" to dependencies ([#8503](https://github.com/storybookjs/storybook/pull/8503))\n\n## 5.3.0-alpha.23 (October 19, 2019)\n\n### Features\n\n- Webpack: Enabled error details ([#8391](https://github.com/storybookjs/storybook/pull/8391))\n\n### Bug Fixes\n\n- Addon-docs: Fix React.forwardedRef/memo props ([#8445](https://github.com/storybookjs/storybook/pull/8445))\n- MDX: Handle `<Story>` name starting with number ([#8469](https://github.com/storybookjs/storybook/pull/8469))\n\n### Maintenance\n\n- ADD a step in circleci to upload storybook for angular ([#8477](https://github.com/storybookjs/storybook/pull/8477))\n- Core: Check module type in configure ([#8412](https://github.com/storybookjs/storybook/pull/8412))\n- Angular: Convert angular-cli stories to CSF ([#7668](https://github.com/storybookjs/storybook/pull/7668))\n- Typescript: Migrate @storybook/mithril ([#8320](https://github.com/storybookjs/storybook/pull/8320))\n\n## 5.3.0-alpha.22 (October 18, 2019)\n\n### Features\n\n- CLI: Add component meta to framework templates ([#8462](https://github.com/storybookjs/storybook/pull/8462))\n\n### Maintenance\n\n- Build: Add cypress to Storybook CI ([#8397](https://github.com/storybookjs/storybook/pull/8397))\n- Incorrect minimal required node version ([#8427](https://github.com/storybookjs/storybook/pull/8427))\n\n## 5.3.0-alpha.21 (October 17, 2019)\n\n### Features\n\n- CLI: React-scripts TS template & test ([#8451](https://github.com/storybookjs/storybook/pull/8451))\n- Addon-storysource: Add preset ([#8437](https://github.com/storybookjs/storybook/pull/8437))\n\n### Bug Fixes\n\n- UI: Fix React15 support ([#8454](https://github.com/storybookjs/storybook/pull/8454))\n- Addon-centered: Fix zoom issues for non-Firefox browsers ([#8442](https://github.com/storybookjs/storybook/pull/8442))\n- CLI: Add CRA preset to MDX template ([#8452](https://github.com/storybookjs/storybook/pull/8452))\n- CLI: Add preset-create-react-app to CRA presets template ([#8449](https://github.com/storybookjs/storybook/pull/8449))\n- CLI: Fix CRA-ts fixture package name ([#8457](https://github.com/storybookjs/storybook/pull/8457))\n\n## 5.3.0-alpha.20 (October 15, 2019)\n\n### Features\n\n- Addon-docs: Support MDX source in Preview w/ no Story blocks ([#7966](https://github.com/storybookjs/storybook/pull/7966))\n\n### Bug Fixes\n\n- Addon-docs: Fix react inline stories ([#8419](https://github.com/storybookjs/storybook/pull/8419))\n- React: Fix custom themes breaking welcome demo ([#8259](https://github.com/storybookjs/storybook/pull/8259))\n\n## 5.3.0-alpha.19 (October 15, 2019)\n\n### Features\n\n- React: Move Create React App support to external preset ([#8416](https://github.com/storybookjs/storybook/pull/8416))\n- CLI: MDX template support ([#8396](https://github.com/storybookjs/storybook/pull/8396))\n\n### Bug Fixes\n\n- Addon-jest: Make withTests type generic ([#8410](https://github.com/storybookjs/storybook/pull/8410))\n- Addon-docs: Don't error in React when there's no `prepareForInline` ([#8415](https://github.com/storybookjs/storybook/pull/8415))\n\n### Dependency Upgrades\n\n- [Security] Bump lodash from 4.17.11 to 4.17.15 ([#8351](https://github.com/storybookjs/storybook/pull/8351))\n\n## 5.3.0-alpha.18 (October 14, 2019)\n\n### Bug Fixes\n\n- CSF: Warn when CSF and `storiesOf` mixed in one file ([#8411](https://github.com/storybookjs/storybook/pull/8411))\n- Addon API: Clean preview hooks when removing a story ([#8408](https://github.com/storybookjs/storybook/pull/8408))\n- Addon-docs: Fix typo in default config ([#8403](https://github.com/storybookjs/storybook/pull/8403))\n- Angular: Fix angular2-template-loader / raw-loader version conflicts ([#8269](https://github.com/storybookjs/storybook/pull/8269))\n- CLI: Update button.svelte template ([#8369](https://github.com/storybookjs/storybook/pull/8369))\n\n### Maintenance\n\n- Official-storybook: Add a story with duplicate decorators ([#8407](https://github.com/storybookjs/storybook/pull/8407))\n\n## 5.2.4 (October 14, 2019)\n\n### Bug Fixes\n\n- Angular: Fix angular2-template-loader / raw-loader version conflicts ([#8269](https://github.com/storybookjs/storybook/pull/8269))\n- CSF: Warn when CSF and `storiesOf` mixed in one file ([#8411](https://github.com/storybookjs/storybook/pull/8411))\n- Addon API: Clean preview hooks when removing a story ([#8408](https://github.com/storybookjs/storybook/pull/8408))\n- Update button.svelte ([#8369](https://github.com/storybookjs/storybook/pull/8369))\n- CSF: Ignore \\_\\_esModule export ([#8317](https://github.com/storybookjs/storybook/pull/8317))\n\n### Maintenance\n\n- Publish top-level .js and .d.ts files ([#8354](https://github.com/storybookjs/storybook/pull/8354))\n\n## 5.3.0-alpha.17 (October 10, 2019)\n\n### Maintenance\n\n- Publish top-level .js and .d.ts files ([#8354](https://github.com/storybookjs/storybook/pull/8354))\n\n## 5.3.0-alpha.16 (October 10, 2019)\n\nPublish failed\n\n## 5.3.0-alpha.15 (October 8, 2019)\n\n### Features\n\n- Addon-docs: support vue inline rendering ([#7929](https://github.com/storybookjs/storybook/pull/7929))\n\n### Maintenance\n\n- Typescript: Migrate addon-storyshots ([#7674](https://github.com/storybookjs/storybook/pull/7674))\n\n## 5.3.0-alpha.14 (October 8, 2019)\n\nNPM publish failed\n\n## 5.3.0-alpha.13 (October 8, 2019)\n\n### Features\n\n- MDX: Better ergonomics for documenting CSF ([#8312](https://github.com/storybookjs/storybook/pull/8312))\n- Addon-docs: Story parameter for disabling docs ([#8313](https://github.com/storybookjs/storybook/pull/8313))\n\n### Dependency Upgrades\n\n- Remove redundant dependency on hoist-non-react-statics (#6349) ([#8310](https://github.com/storybookjs/storybook/pull/8310))\n\n## 5.3.0-alpha.12 (October 7, 2019)\n\n### Features\n\n- CSF: Allow multiple CSF with same title ([#8133](https://github.com/storybookjs/storybook/pull/8133))\n\n### Bug Fixes\n\n- CSF: Ignore \\_\\_esModule export ([#8317](https://github.com/storybookjs/storybook/pull/8317))\n- React: Improve type of storyFn ([#8197](https://github.com/storybookjs/storybook/pull/8197))\n\n## 5.2.3 (October 7, 2019)\n\n### Bug Fixes\n\n- Core: Fix lib/core whitelist ([#8182](https://github.com/storybookjs/storybook/pull/8182))\n\n## 5.2.2 (October 7, 2019)\n\n### Bug Fixes\n\n- Storyshots: First-class CSF support ([#8000](https://github.com/storybookjs/storybook/pull/8000))\n- UI: Move addon dependencies to devDependencies ([#8206](https://github.com/storybookjs/storybook/pull/8206))\n- Addon-docs: CSS classes for escape-hatch theming wrapper/content ([#8061](https://github.com/storybookjs/storybook/pull/8061))\n- CLI: Fix variable collisions in storiesof-to-csf ([#8106](https://github.com/storybookjs/storybook/pull/8106))\n- Addon-knobs: Add missing type def #8105 ([#8118](https://github.com/storybookjs/storybook/pull/8118))\n- Dependencies: add @types/webpack-env to apps that depend on it ([#8119](https://github.com/storybookjs/storybook/pull/8119))\n- Core: Show exception rather than error on react error boundary ([#8100](https://github.com/storybookjs/storybook/pull/8100))\n- UI: Fix inline code styling for dark theme ([#8260](https://github.com/storybookjs/storybook/pull/8260))\n- Addon-ondevice-notes: Validate the state content ([#8261](https://github.com/storybookjs/storybook/pull/8261))\n- Telejson: New version with typings and bugfixes ([#8228](https://github.com/storybookjs/storybook/pull/8228))\n- React: Add DecoratorFn type to exports ([#8121](https://github.com/storybookjs/storybook/pull/8121))\n- Addon-knobs: Handle undefined array value ([#8006](https://github.com/storybookjs/storybook/pull/8006))\n- Preact: Allow JSX.Element story ([#8159](https://github.com/storybookjs/storybook/pull/8159))\n- Storyshots: Fix STORYBOOK_HOOKS_CONTEXT error ([#8163](https://github.com/storybookjs/storybook/pull/8163))\n- Update react-draggable to 4.0.3 ([#8145](https://github.com/storybookjs/storybook/pull/8145))\n\n## 5.3.0-alpha.11 (October 6, 2019)\n\n### Bug Fixes\n\n- Storyshots: Update `read-pkg-up` usage to work with version `7` ([#8299](https://github.com/storybookjs/storybook/pull/8299))\n\n### Maintenance\n\n- Remove `weak` dependency Node 12 ([#8300](https://github.com/storybookjs/storybook/pull/8300))\n\n## 5.3.0-alpha.10 (October 5, 2019)\n\n### Bug Fixes\n\n- Storyshots: First-class CSF support ([#8000](https://github.com/storybookjs/storybook/pull/8000))\n\n### Maintenance\n\n- Build: Add CLI test in github actions ([#8064](https://github.com/storybookjs/storybook/pull/8064))\n\n## 5.3.0-alpha.9 (October 4, 2019)\n\n### Features\n\n- API: Add method to set manager config ([#8232](https://github.com/storybookjs/storybook/pull/8232))\n\n### Bug Fixes\n\n- Core: Show exception rather than error on react error boundary ([#8100](https://github.com/storybookjs/storybook/pull/8100))\n- Addon-knobs: Fix issues caused by rerenders ([#8287](https://github.com/storybookjs/storybook/pull/8287))\n\n### Maintenance\n\n- Fix local `yarn lint` ([#8289](https://github.com/storybookjs/storybook/pull/8289))\n- Fix button knob story ([#8282](https://github.com/storybookjs/storybook/pull/8282))\n- Official examples: apply babel-preset-minify only in production mode ([#8283](https://github.com/storybookjs/storybook/pull/8283))\n- Build: Upgrade chromatic to test ([#8246](https://github.com/storybookjs/storybook/pull/8246))\n\n### Dependency Upgrades\n\n- Upgrade regenerator-runtime to 0.13 in all packages ([#8258](https://github.com/storybookjs/storybook/pull/8258))\n- Misc upgrades ([#8280](https://github.com/storybookjs/storybook/pull/8280))\n\n## 5.3.0-alpha.9 (October 4, 2019)\n\nNPM publish failed\n\n## 5.3.0-alpha.7 (October 2, 2019)\n\n### Features\n\n- UI: Preferred color scheme awareness ([#8271](https://github.com/storybookjs/storybook/pull/8271))\n\n### Bug Fixes\n\n- UI: Fix inline code styling for dark theme ([#8260](https://github.com/storybookjs/storybook/pull/8260))\n\n### Maintenance\n\n- Regenerate lockfile ([#8263](https://github.com/storybookjs/storybook/pull/8263))\n\n## 5.3.0-alpha.6 (October 1, 2019)\n\n### Bug Fixes\n\n- Addon-ondevice-notes: Validate the state content ([#8261](https://github.com/storybookjs/storybook/pull/8261))\n- API: Fix require cycles in addons hooks ([#8236](https://github.com/storybookjs/storybook/pull/8236))\n- API: Fix missing `channel.off` ([#8234](https://github.com/storybookjs/storybook/pull/8234))\n- Telejson: New version with typings and bugfixes ([#8228](https://github.com/storybookjs/storybook/pull/8228))\n- Addon-links: Update linkTo type to accept function ([#8117](https://github.com/storybookjs/storybook/pull/8117))\n- React: Add DecoratorFn type to exports ([#8121](https://github.com/storybookjs/storybook/pull/8121))\n\n### Maintenance\n\n- Update angular example to v8 ([#7747](https://github.com/storybookjs/storybook/pull/7747))\n- Hitting some flakiness in now deploys, this might help ([#8200](https://github.com/storybookjs/storybook/pull/8200))\n- Remov hooks from extracted StoryItem ([#8256](https://github.com/storybookjs/storybook/pull/8256))\n\n### Dependency Upgrades\n\n- Bump react-native-swipe-gestures to 1.0.4 ([#8235](https://github.com/storybookjs/storybook/pull/8235))\n\n## 5.3.0-alpha.5 (September 27, 2019)\n\n### Maintenance\n\n- UI: Improve code indentation ([#8218](https://github.com/storybookjs/storybook/pull/8218))\n- Use the extracted linting configs ([#8213](https://github.com/storybookjs/storybook/pull/8213))\n\n## 5.3.0-alpha.4 (September 26, 2019)\n\n### Bug Fixes\n\n- UI: Move addon dependencies to devDependencies ([#8206](https://github.com/storybookjs/storybook/pull/8206))\n- Addon-knobs: Handle undefined array value ([#8006](https://github.com/storybookjs/storybook/pull/8006))\n\n### Maintenance\n\n- Build: Upgrade from node8 to node10 ([#8207](https://github.com/storybookjs/storybook/pull/8207))\n\n## 5.3.0-alpha.3 (September 25, 2019)\n\n### Bug Fixes\n\n- Dependencies: add @types/webpack-env to apps that depend on it ([#8119](https://github.com/storybookjs/storybook/pull/8119))\n- UI: Removes default CSS margins on viewport ([#7742](https://github.com/storybookjs/storybook/pull/7742))\n\n## 5.3.0-alpha.2 (September 24, 2019)\n\n### Bug Fixes\n\n- Core: Fix lib/core files ([#8182](https://github.com/storybookjs/storybook/pull/8182))\n\n## 5.3.0-alpha.1 (September 23, 2019)\n\n### Bug Fixes\n\n- Preact: Allow JSX.Element story ([#8159](https://github.com/storybookjs/storybook/pull/8159))\n- Addon-docs: CSS classes for escape-hatch theming wrapper/content ([#8061](https://github.com/storybookjs/storybook/pull/8061))\n- CLI: Fix variable collisions in storiesof-to-csf ([#8106](https://github.com/storybookjs/storybook/pull/8106))\n- Storyshots: Fix STORYBOOK_HOOKS_CONTEXT error ([#8163](https://github.com/storybookjs/storybook/pull/8163))\n- Addon-contexts: Remove peer dependencies ([#7675](https://github.com/storybookjs/storybook/pull/7675))\n- Addon-knobs: Add missing type def ([#8118](https://github.com/storybookjs/storybook/pull/8118))\n\n### Dependency Upgrades\n\n- Update react-draggable to 4.0.3 ([#8145](https://github.com/storybookjs/storybook/pull/8145))\n\n## 5.2.1 (September 17, 2019)\n\n### Bug Fixes\n\n- Core: Fix error handling ([#8097](https://github.com/storybookjs/storybook/pull/8097))\n\n## 5.3.0-alpha.0 (September 16, 2019)\n\n### Features\n\n- UI: Debounce sidebar search filter ([#8032](https://github.com/storybookjs/storybook/pull/8032))\n\n### Bug Fixes\n\n- Core: Fix error handling ([#8097](https://github.com/storybookjs/storybook/pull/8097))\n\n### Maintenance\n\n- CLI: Add wrapper packages: sb & storybook ([#8034](https://github.com/storybookjs/storybook/pull/8034))\n- Build: Update now config ([#8049](https://github.com/storybookjs/storybook/pull/8049))\n\n## 5.2.0 (September 13, 2019)\n\nStorybook 5.2 is here!\n\n- 📚 DocsPage: Zero-config documentation\n- 📦 Component Story Format: Portable ES6 modules\n- 🖼 Design System: Best practice component development\n- 🧩 Addon API: Simplified w/ hooks\n\n  5.2 contains hundreds more fixes, features, and tweaks. Browse the changelogs matching `5.2.0-alpha.*`, `5.2.0-beta.*`, and `5.2.0-rc.*` for the full list of changes. See [MIGRATION.md](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md) to upgrade from `5.0` or earlier.\n\n## 5.2.0-rc.11 (September 10, 2019)\n\n### Features\n\n- DocsPage: show docs.storyDescription above story ([#8037](https://github.com/storybookjs/storybook/pull/8037))\n\n### Maintenance\n\n- Migrate to new github actions ([#8045](https://github.com/storybookjs/storybook/pull/8045))\n\n## 5.2.0-rc.10 (September 9, 2019)\n\n### Bug Fixes\n\n- Angular: remove webpack-env from tsconfig types ([#8036](https://github.com/storybookjs/storybook/pull/8036))\n\n### Documentation\n\n- Guides: Update all guides to CSF ([#8030](https://github.com/storybookjs/storybook/pull/8030))\n\n## 5.2.0-rc.9 (September 7, 2019)\n\n### Bug Fixes\n\n- Addon-knobs: allow array values in select and options knobs ([#8027](https://github.com/storybookjs/storybook/pull/8027))\n\n## 5.2.0-rc.8 (September 6, 2019)\n\n### Bug Fixes\n\n- Addon-docs: Scroll story into view ([#7994](https://github.com/storybookjs/storybook/pull/7994))\n- Addon-docs: Fix LI styling for dark color theme ([#8015](https://github.com/storybookjs/storybook/pull/8015))\n\n## 5.2.0-rc.7 (September 6, 2019)\n\nPublish failed\n\n## 5.2.0-rc.6 (September 5, 2019)\n\n### Bug Fixes\n\n- Addon-docs: Doc blocks fixes for dark theme ([#7991](https://github.com/storybookjs/storybook/pull/7991))\n- API: Fix useEfect in inline Docs ([#7992](https://github.com/storybookjs/storybook/pull/7992))\n- UI: Fix enableShortcuts option ([#7990](https://github.com/storybookjs/storybook/pull/7990))\n- Addon-docs: Error handling for invalid Story id ([#7965](https://github.com/storybookjs/storybook/pull/7965))\n\n## 5.2.0-rc.5 (September 4, 2019)\n\n### Bug Fixes\n\n- CLI: Force welcome stories to show up first in load order ([#7979](https://github.com/storybookjs/storybook/pull/7979))\n\n## 5.2.0-rc.4 (September 3, 2019)\n\n### Bug Fixes\n\n- Addon-docs: Fix MDX theme bleed with reset context ([#7974](https://github.com/storybookjs/storybook/pull/7974))\n\n## 5.2.0-rc.3 (September 3, 2019)\n\nFailed publish\n\n## 5.2.0-rc.2 (September 1, 2019)\n\n### Bug Fixes\n\n- Addon-docs: Fix inline stories using react hooks ([#7946](https://github.com/storybookjs/storybook/pull/7946))\n\n## 5.2.0-rc.1 (August 31, 2019)\n\n### Features\n\n- Core: Add html lang attribute to iframe ([#7892](https://github.com/storybookjs/storybook/pull/7892))\n\n### Bug Fixes\n\n- Source-loader: Fix CSF display name handling ([#7940](https://github.com/storybookjs/storybook/pull/7940))\n- React-native: Resolve deprecated methods ([#7908](https://github.com/storybookjs/storybook/pull/7908))\n- Addon-viewport: keep styles on rotation-change ([#7683](https://github.com/storybookjs/storybook/pull/7683))\n- Addon-viewport: Fix defaultViewport ([#7934](https://github.com/storybookjs/storybook/pull/7934))\n\n## 5.2.0-rc.0 (August 30, 2019)\n\n5.2 is in RC!!! 🎉What this means:\n\n- no glaring bugs relating to new features (that we know of)\n- bugfixes only until 5.2 final\n- follow-on features to be released in `5.3-alpha` ASAP\n\nTrack progress on the [5.2 release issue](https://github.com/storybookjs/storybook/issues/7430)\n\n## 5.2.0-beta.48 (August 30, 2019)\n\n### Bug Fixes\n\n- Addon-docs: Fix docs-only story ID suffix ([#7921](https://github.com/storybookjs/storybook/pull/7921))\n\n### Maintenance\n\n- Replace favicon with new Storybook icon. ([#7922](https://github.com/storybookjs/storybook/pull/7922))\n\n### Dependency Upgrades\n\n- Bump react-draggable from 3.1.1 to 3.3.2 ([#7912](https://github.com/storybookjs/storybook/pull/7912))\n\n## 5.2.0-beta.47 (August 30, 2019)\n\n### Bug Fixes\n\n- UI: Optimize treeview render/filter performance ([#7910](https://github.com/storybookjs/storybook/pull/7910))\n- Addon-docs: Fix DocsPage to respect displayName ([#7915](https://github.com/storybookjs/storybook/pull/7915))\n\n## 5.2.0-beta.46 (August 29, 2019)\n\nCSF users: this reverts the `makeDisplayName` change introduced in `5.2.0-beta.43` for maintainability reasons. See [#7901](https://github.com/storybookjs/storybook/pull/7901) for full rationale. And apologies for the inconvenience!\n\n### Bug Fixes\n\n- React: Fix missing props in the Welcome.tsx demo ([#7774](https://github.com/storybookjs/storybook/pull/7774))\n\n### Maintenance\n\n- CSF: Revert `makeDisplayName` & add stable `storyNameFromExport` ([#7901](https://github.com/storybookjs/storybook/pull/7901))\n- Addon-a11y: Upgrade axe to 3.3.2 which adds/mods rules ([#7888](https://github.com/storybookjs/storybook/pull/7888))\n\n## 5.2.0-beta.45 (August 28, 2019)\n\n### Bug Fixes\n\n- Addon-docs: Fix MDX Story ID to match new CSF ([#7894](https://github.com/storybookjs/storybook/pull/7894))\n\n## 5.2.0-beta.44 (August 28, 2019)\n\nPublish failed\n\n## 5.2.0-beta.43 (August 28, 2019)\n\nCSF users: This is potentially a breaking change. If you want to opt-out of the new default display name calculation (`lodash.startCase`) you can add the following to your SB config:\n\n```js\naddParameters({ options: { makeDisplayName: (key) => key } });\n```\n\n### Features\n\n- CSF: Transform CSF named exports w/ `makeDisplayName` ([#7878](https://github.com/storybookjs/storybook/pull/7878))\n\n## 5.2.0-beta.42 (August 28, 2019)\n\nAddon-docs users: This is a breaking change if you have been hacking the `docs` parameter manually. If you're using the zero-config option for `DocsPage` or `MDX`, you should be unaffected by it.\n\n### Maintenance\n\n- Addon-docs: Make config API consistent with other addons ([#7874](https://github.com/storybookjs/storybook/pull/7874))\n\n## 5.2.0-beta.41 (August 27, 2019)\n\n### Features\n\n- Addon-info: Add configurable component comparator ([#7409](https://github.com/storybookjs/storybook/pull/7409))\n\n### Bug Fixes\n\n- Addon-viewports: Add back default viewports ([#7448](https://github.com/storybookjs/storybook/pull/7448))\n- Core: Pass a separate hooks context per story ([#7860](https://github.com/storybookjs/storybook/pull/7860))\n- UI: Fix TooltipLinkList not scrollable ([#7865](https://github.com/storybookjs/storybook/pull/7865))\n\n### Maintenance\n\n- UI: Add ignore `first-child` selector warning flag ([#7861](https://github.com/storybookjs/storybook/pull/7861))\n\n## 5.2.0-beta.40 (August 23, 2019)\n\n### Bug Fixes\n\n- Addon-docs: Fix DocsPage primary story switching ([#7849](https://github.com/storybookjs/storybook/pull/7849))\n- Source-loader: Selectively ignore typescript errors in generated code ([#7845](https://github.com/storybookjs/storybook/pull/7845))\n- Addon-docs: Force hidden attribute on #root element ([#7841](https://github.com/storybookjs/storybook/pull/7841))\n\n### Maintenance\n\n- Remove temporarily added --no-dll option on examples ([#7647](https://github.com/storybookjs/storybook/pull/7647))\n\n## 5.2.0-beta.39 (August 22, 2019)\n\n### Bug Fixes\n\n- React-Native: Fix tabs layout issue on simulator ([#7809](https://github.com/storybookjs/storybook/pull/7809))\n- Source-loader: Selectively ignore typescript errors in generated code ([#7831](https://github.com/storybookjs/storybook/pull/7831))\n\n## 5.2.0-beta.38 (August 21, 2019)\n\n### Bug Fixes\n\n- FIX issue where the block of build info (including url) wouldn't show if passed --ci #7821 ([#7822](https://github.com/storybookjs/storybook/pull/7822))\n\n### Maintenance\n\n- CLI: Remove babel-register in favor of esm ([#7823](https://github.com/storybookjs/storybook/pull/7823))\n\n## 5.2.0-beta.37 (August 20, 2019)\n\n### Breaking Changes\n\n- Addon-docs: Add docsContainer parameter ([#7814](https://github.com/storybookjs/storybook/pull/7814))\n\n## 5.2.0-beta.36 (August 20, 2019)\n\n### Features\n\n- Addon-docs: Improved \"No docs\" message ([#7785](https://github.com/storybookjs/storybook/pull/7785))\n- Core: Add .pdf support to file-loader ([#7651](https://github.com/storybookjs/storybook/pull/7651))\n\n### Bug Fixes\n\n- Preview hooks: trigger effects after story render ([#7791](https://github.com/storybookjs/storybook/pull/7791))\n\n## 5.2.0-beta.35 (August 20, 2019)\n\nFailed publish\n\n## 5.2.0-beta.34 (August 20, 2019)\n\nFailed publish\n\n## 5.2.0-beta.33 (August 18, 2019)\n\n### Features\n\n- Addon-jest: Add pending & todo items ([#7793](https://github.com/storybookjs/storybook/pull/7793))\n\n### Bug Fixes\n\n- Addon-docs: Fix unique key warning ([#7796](https://github.com/storybookjs/storybook/pull/7796))\n\n## 5.2.0-beta.32 (August 17, 2019)\n\n### Bug Fixes\n\n- Addon-docs: Fix docs-only story load ([#7787](https://github.com/storybookjs/storybook/pull/7787))\n\n### Maintenance\n\n- Addon-docs: Unwrap doc blocks stories ([#7788](https://github.com/storybookjs/storybook/pull/7788))\n\n## 5.2.0-beta.31 (August 16, 2019)\n\n### Features\n\n- Addon-docs: Add toolbar support to Preview ([#7778](https://github.com/storybookjs/storybook/pull/7778))\n\n### Bug Fixes\n\n- Addon-docs: Fix CSS bleed issue in doc blocks ([#7771](https://github.com/storybookjs/storybook/pull/7771))\n\n## 5.2.0-beta.30 (August 14, 2019)\n\n### Features\n\n- CLI: Don't output startup information on smoke test ([#6949](https://github.com/storybookjs/storybook/pull/6949))\n- Ondevice-knobs: Expose withKnobs from addon-knobs ([#7555](https://github.com/storybookjs/storybook/pull/7555))\n\n### Maintenance\n\n- Addon-Jest: Add flexibility ([#7748](https://github.com/storybookjs/storybook/pull/7748))\n\n## 5.1.11 (August 13, 2019)\n\n### Bug Fixes\n\n- Core: Add polyfill for fetch ([#7401](https://github.com/storybookjs/storybook/pull/7401))\n- Core: Revert \"Fix #7167 addon-centered causes component to disappear when zooming\" ([#7750](https://github.com/storybookjs/storybook/pull/7750))\n\n## 5.2.0-beta.29 (August 13, 2019)\n\n### Breaking Changes\n\n- Addon-docs: Packaging for 5.2 release ([#7741](https://github.com/storybookjs/storybook/pull/7741))\n\n### Bug Fixes\n\n- Core: Revert \"Fix #7167 addon-centered causes component to disappear when zooming\" ([#7750](https://github.com/storybookjs/storybook/pull/7750))\n- Core: Revert \"Addon-centered: Fix disappearing when zoomed\" ([#7749](https://github.com/storybookjs/storybook/pull/7749))\n\n## 5.2.0-beta.28 (August 10, 2019)\n\n### Features\n\n- Core: Disable CRA behaviors when preset detected ([#7696](https://github.com/storybookjs/storybook/pull/7696))\n- Addon-docs: Docs only MDX and navigation UI ([#7719](https://github.com/storybookjs/storybook/pull/7719))\n\n## 5.2.0-beta.27 (August 10, 2019)\n\nPublish failed\n\n## 5.2.0-beta.26 (August 9, 2019)\n\n### Features\n\n- UI: Improved component nav UI ([#7716](https://github.com/storybookjs/storybook/pull/7716))\n\n## 5.2.0-beta.25 (August 8, 2019)\n\n### Features\n\n- Addon-centered: ability to disable on specific story ([#7709](https://github.com/storybookjs/storybook/pull/7709))\n\n### Bug Fixes\n\n- Addon-jest: fix console warning ([#7705](https://github.com/storybookjs/storybook/pull/7705))\n- Core: Remove Object.append(...) from index.ejs ([#7707](https://github.com/storybookjs/storybook/pull/7707))\n\n## 5.2.0-beta.24 (August 7, 2019)\n\n### Features\n\n- Addon-docs: DocsPage slots for fine-grained user control ([#7680](https://github.com/storybookjs/storybook/pull/7680))\n\n### Bug Fixes\n\n- Core: Add polyfill for fetch ([#7401](https://github.com/storybookjs/storybook/pull/7401))\n\n### Dependency Upgrades\n\n- Addon-notes: Upgrade markdown-to-jsx dependency ([#7694](https://github.com/storybookjs/storybook/pull/7694))\n\n## 5.2.0-beta.23 (August 6, 2019)\n\n### Features\n\n- CLI: Suggest possible matches on invalid command ([#7658](https://github.com/storybookjs/storybook/pull/7658))\n- Core: Allow injecting preview-body.html ([#7417](https://github.com/storybookjs/storybook/pull/7417))\n\n### Bug Fixes\n\n- Core: Fix HMR error recovery ([#7684](https://github.com/storybookjs/storybook/pull/7684))\n\n## 5.2.0-beta.22 (August 3, 2019)\n\n### Bug Fixes\n\n- Core: Fix HMR for CSF files ([#7669](https://github.com/storybookjs/storybook/pull/7669))\n\n### Maintenance\n\n- React: Cleanup CSF stories in cra-kitchen-sink ([#7670](https://github.com/storybookjs/storybook/pull/7670))\n\n## 5.2.0-beta.21 (August 3, 2019)\n\n### Features\n\n- Addon-jest: Add placeholder info for missing tests ([#7660](https://github.com/storybookjs/storybook/pull/7660))\n\n### Bug Fixes\n\n- Addon-docs: Pass framework configs through babel ([#7667](https://github.com/storybookjs/storybook/pull/7667))\n- Addon-centered: Fix disappearing when zoomed ([#7640](https://github.com/storybookjs/storybook/pull/7640))\n\n## 5.2.0-beta.20 (August 1, 2019)\n\n### Bug Fixes\n\n- Addon-docs: Pass everything through babel & partial TS conversion ([#7653](https://github.com/storybookjs/storybook/pull/7653))\n- Addon-docs: Error on non-string description ([#7650](https://github.com/storybookjs/storybook/pull/7650))\n- CLI: Fix `npx -p @storybook/cli sb migrate` in yarn project ([#7649](https://github.com/storybookjs/storybook/pull/7649))\n\n## 5.2.0-beta.19 (July 31, 2019)\n\n### Bug Fixes\n\n- Core: Change webpack-defined variables to globals ([#7622](https://github.com/storybookjs/storybook/pull/7622))\n- Addon-notes: Fix dark theming bug ([#7623](https://github.com/storybookjs/storybook/pull/7623))\n- CLI: Fix usage information ([#7627](https://github.com/storybookjs/storybook/pull/7627))\n- CLI: Show additional package information with `sb info` ([#7624](https://github.com/storybookjs/storybook/pull/7624))\n\n### Maintenance\n\n- Typescript: Migrate Preact ([#7527](https://github.com/storybookjs/storybook/pull/7527))\n\n## 5.1.10 (July 31, 2019)\n\n### Breaking Changes\n\n- Core: Remove project root `babel.config.js` loading ([#7573](https://github.com/storybookjs/storybook/pull/7573))\n\n### Bug Fixes\n\n- Addon-info: change stylesheetBase info height from 110vh to 100vh ([#7141](https://github.com/storybookjs/storybook/pull/7141))\n- React-native: Fix react native server ([#7187](https://github.com/storybookjs/storybook/pull/7187))\n- Addon-centered/contexts: Move optionalDependencies to peerDependencies ([#7315](https://github.com/storybookjs/storybook/pull/7315))\n- Addon-notes/info: Fix indenting on markdown code blocks ([#7158](https://github.com/storybookjs/storybook/pull/7158))\n- Addon-actions: fix serialization performance ([#7256](https://github.com/storybookjs/storybook/pull/7256))\n- Addon-notes: Fix dark theming bug ([#7623](https://github.com/storybookjs/storybook/pull/7623))\n- CLI: Fix usage information ([#7627](https://github.com/storybookjs/storybook/pull/7627))\n- Addon-centered: Fix component disappearing on zoom ([#7400](https://github.com/storybookjs/storybook/pull/7400))\n- Addon-analytics: Fix API signature ([#7410](https://github.com/storybookjs/storybook/pull/7410))\n- UI: Fix Sidebar input refresh on 'Enter' ([#7342](https://github.com/storybookjs/storybook/pull/7342))\n- Addon-knobs: Prevent rerender when a button callback returns false. ([#7197](https://github.com/storybookjs/storybook/pull/7197))\n- Core: Keep story data and legacy data in sync ([#7319](https://github.com/storybookjs/storybook/pull/7319))\n- CLI: Move the free port logic so that loadOptions don't override it ([#7237](https://github.com/storybookjs/storybook/pull/7237))\n- Addon-backgrounds: Fix unstretched preview background wrapper ([#7173](https://github.com/storybookjs/storybook/pull/7173))\n\n### Maintenance\n\n- Build: delete tests & snapshots from dist ([#7358](https://github.com/storybookjs/storybook/pull/7358))\n\n### Dependency Upgrades\n\n- CLI: replaced merge-dirs dependency by fs-extra ([#7100](https://github.com/storybookjs/storybook/pull/7100))\n\n## 5.2.0-beta.18 (July 30, 2019)\n\n### Bug Fixes\n\n- Addon-docs: Ensure getNotes/getInfo return string ([#7597](https://github.com/storybookjs/storybook/pull/7597))\n- React/Angular/HTML/Vue: Fix typings for `configure` ([#7598](https://github.com/storybookjs/storybook/pull/7598))\n\n### Maintenance\n\n- Typescript: Migrate Vue ([#7578](https://github.com/storybookjs/storybook/pull/7578))\n\n### Dependency Upgrades\n\n- Upgrade corejs-upgrade-webpack-plugin lazy-universal-dotenv ([#7592](https://github.com/storybookjs/storybook/pull/7592))\n\n## 5.2.0-beta.17 (July 29, 2019)\n\n### Bug Fixes\n\n- CLI: Fix storiesof-to-csf migration w/punctuation ([#7590](https://github.com/storybookjs/storybook/pull/7590))\n\n## 5.2.0-beta.16 (July 29, 2019)\n\n### Features\n\n- Addon-docs: Configure jsx automagically ([#7581](https://github.com/storybookjs/storybook/pull/7581))\n- Addon-docs: Add DocsPage automagically ([#7579](https://github.com/storybookjs/storybook/pull/7579))\n\n## 5.2.0-beta.15 (July 29, 2019)\n\n### Features\n\n- CRA: Add support for TSX in config folder ([#7566](https://github.com/storybookjs/storybook/pull/7566))\n\n### Bug Fixes\n\n- Addon-info: only render Components in propTables ([#7477](https://github.com/storybookjs/storybook/pull/7477))\n\n### Dependency Upgrades\n\n- Update telejson dependency to 2.2.2 ([#7586](https://github.com/storybookjs/storybook/pull/7586))\n- Angular: Fix @angular-devkit/build-angular version ([#7585](https://github.com/storybookjs/storybook/pull/7585))\n\n## 5.2.0-beta.14 (July 29, 2019)\n\nFailed publish\n\n## 5.2.0-beta.13 (July 27, 2019)\n\nThis is a breaking change for anybody who used `load` on an earlier 5.2 pre-release. Simply rename `load` to `configure` in your storybook config and that should fix things.\n\nIf you're not using SB Docs, you probably don't have to worry about this.\n\n### Breaking Changes\n\n- Core: Rename `load` to `configure` ([#7576](https://github.com/storybookjs/storybook/pull/7576))\n\n## 5.2.0-beta.12 (July 27, 2019)\n\n### Bug Fixes\n\n- Addon-knobs: Fix select knob default selection when using array values ([#7568](https://github.com/storybookjs/storybook/pull/7568))\n- Addon-knobs: Call onChanges only for changed props ([#6884](https://github.com/storybookjs/storybook/pull/6884))\n\n### Maintenance\n\n- Angular: Print error message if angular.json has no default project specified ([#7574](https://github.com/storybookjs/storybook/pull/7574))\n\n## 5.2.0-beta.11 (July 26, 2019)\n\nFailed release\n\n## 5.2.0-beta.10 (July 26, 2019)\n\nThis is a breaking release that undoes an unintentional breaking change introduced in 5.1.0 (and will also be released as a 5.1.x patch)\n\n### Breaking Changes\n\n- Core: Remove project root `babel.config.js` loading ([#7573](https://github.com/storybookjs/storybook/pull/7573))\n\n### Features\n\n- React: Add hooks support to stories ([#7571](https://github.com/storybookjs/storybook/pull/7571))\n\n### Bug Fixes\n\n- UI: Fix attribute warning on shortcut button click ([#7548](https://github.com/storybookjs/storybook/pull/7548))\n\n## 5.2.0-beta.9 (July 26, 2019)\n\n### Bug Fixes\n\n- Angular: Fix automatic module metadata extraction for forRoot imports ([#7224](https://github.com/storybookjs/storybook/pull/7224))\n\n### Maintenance\n\n- Rename \"Module\" to Component Story Format ([#7564](https://github.com/storybookjs/storybook/pull/7564))\n\n## 5.2.0-beta.8 (July 25, 2019)\n\n### Breaking Changes\n\n`source-loader` is now part of `addon-docs` preset. If you're using both the `addon-docs` preset and `source-loader` in your project, you need to update. You can remove `source-loader` and let the preset take care of it. Alternatively, you can disable `source-loader` in the preset by setting `sourceLoaderOptions` to `null`.\n\n- Addon-docs: Add source-loader to preset ([#7547](https://github.com/storybookjs/storybook/pull/7547))\n- Core: Don't allow duplicate titles ([#7542](https://github.com/storybookjs/storybook/pull/7542))\n\n### Bug Fixes\n\n- Addon-storysource: Add source-loader dep to avoid breaking change ([#7554](https://github.com/storybookjs/storybook/pull/7554))\n- Addon-contexts: Ensure nodes is Array ([#7393](https://github.com/storybookjs/storybook/pull/7393))\n\n### Maintenance\n\n- Angular: Log angular cli config errors ([#7484](https://github.com/storybookjs/storybook/pull/7484))\n\n## 5.2.0-beta.7 (July 23, 2019)\n\n### Features\n\n- Addon-docs: MDX function stories ([#7529](https://github.com/storybookjs/storybook/pull/7529))\n- CLI: update `sb init` to module format for Ember/Marko/Mithril/Rax/Riot/Svelte ([#7504](https://github.com/storybookjs/storybook/pull/7504))\n- CLI: update `sb init` to module format for Angular ([#7502](https://github.com/storybookjs/storybook/pull/7502))\n- CLI: update `sb init` to module format for React ([#7500](https://github.com/storybookjs/storybook/pull/7500))\n\n### Bug Fixes\n\n- Ondevice-knobs: Graceful fail on missing default ([#7533](https://github.com/storybookjs/storybook/pull/7533))\n\n### Maintenance\n\n- Build: Attempt to fix travis timeouts ([#7531](https://github.com/storybookjs/storybook/pull/7531))\n\n## 5.2.0-beta.6 (July 23, 2019)\n\n### Breaking Changes\n\nIt is now recommended to only use ONE `load` call in your app and it will warn you if you call it more than once. The examples and docs have been updated to reflect this. Technically this is not a breaking change since the old API is supported, but it's a change in usage from previous versions.\n\n### Features\n\n- Core: Top-level components in MDX/Module formats ([#7524](https://github.com/storybookjs/storybook/pull/7524))\n- Core: Module format `load` accept loader function ([#7518](https://github.com/storybookjs/storybook/pull/7518))\n\n### Bug Fixes\n\n- Addon-centered: Fix component disappearing on zoom ([#7400](https://github.com/storybookjs/storybook/pull/7400))\n\n### Maintenance\n\n- Addon-knobs: enable Typescript `strict` flag ([#7515](https://github.com/storybookjs/storybook/pull/7515))\n\n## 5.2.0-beta.5 (July 21, 2019)\n\n### Features\n\n- CLI: update `sb init` to module format for Vue ([#7501](https://github.com/storybookjs/storybook/pull/7501))\n- CLI: update `sb init` to module format for HTML/Polymer ([#7503](https://github.com/storybookjs/storybook/pull/7503))\n\n### Bug Fixes\n\n- Source-loader: Separate server and client code for IE support ([#7510](https://github.com/storybookjs/storybook/pull/7510))\n\n## 5.2.0-beta.4 (July 20, 2019)\n\n### Breaking Changes\n\n- Core: Module format story decorators ([#7490](https://github.com/storybookjs/storybook/pull/7490))\n\n### Features\n\n- Addon-jest: UI Redesign ([#7424](https://github.com/storybookjs/storybook/pull/7424))\n- Marko: support rerendering ([#7460](https://github.com/storybookjs/storybook/pull/7460))\n\n### Bug Fixes\n\n- Addon-docs: Fix MDX source string escaping ([#7497](https://github.com/storybookjs/storybook/pull/7497))\n\n### Dependency Upgrades\n\n- Marko: Upgrade loader & config ([#7459](https://github.com/storybookjs/storybook/pull/7459))\n- Update core-js in addon-ondevice-actions package.json ([#7491](https://github.com/storybookjs/storybook/pull/7491))\n\n## 5.2.0-beta.3 (July 19, 2019)\n\n### Features\n\n- React-native: Add storyId as testID ([#7482](https://github.com/storybookjs/storybook/pull/7482))\n\n### Bug Fixes\n\n- React-native: On-device knobs input fixes ([#7475](https://github.com/storybookjs/storybook/pull/7475))\n- React-native: Fix crna-kitchen-sink ([#7200](https://github.com/storybookjs/storybook/pull/7200))\n\n## 5.2.0-beta.2 (July 18, 2019)\n\n### Features\n\n- CLI: convert mdx to module format ([#7419](https://github.com/storybookjs/storybook/pull/7419))\n- CLI: sb migrate npm & typescript support ([#7463](https://github.com/storybookjs/storybook/pull/7463))\n- Addon-Docs: HTML support & example ([#7454](https://github.com/storybookjs/storybook/pull/7454))\n\n### Bug Fixes\n\n- Convert-storiesof-to-module: user exports, collisions, reserved keywords ([#7471](https://github.com/storybookjs/storybook/pull/7471))\n- React-native: On-device knobs fixes ([#7470](https://github.com/storybookjs/storybook/pull/7470))\n\n### Dependency Upgrades\n\n- Addon-docs: Upgrade MDX to 1.1 ([#7476](https://github.com/storybookjs/storybook/pull/7476))\n\n## 5.2.0-beta.1 (July 18, 2019)\n\n### Features\n\n- React native: Emit event when story is rendered ([#7449](https://github.com/storybookjs/storybook/pull/7449))\n\n### Bug Fixes\n\n- Addon-knobs: improve types via generics and readonlyarray ([#7411](https://github.com/storybookjs/storybook/pull/7411))\n- Ondevice-backgrounds: use same param key as addon-backgrounds ([#7437](https://github.com/storybookjs/storybook/pull/7437))\n\n## 5.2.0-beta.0 (July 15, 2019)\n\n### Features\n\n- Codemod: Convert module format to MDX ([#7418](https://github.com/storybookjs/storybook/pull/7418))\n\n## 5.2.0-alpha.44 (July 15, 2019)\n\n### Features\n\n- CLI: Add migrate command ([#7414](https://github.com/storybookjs/storybook/pull/7414))\n\n### Bug Fixes\n\n- UI: Fix Panel rendered wrong at Docs-page ([#7327](https://github.com/storybookjs/storybook/pull/7327))\n\n### Maintenance\n\n- Typescript: Fix types of client-api & storystore ([#7337](https://github.com/storybookjs/storybook/pull/7337))\n\n## 5.2.0-alpha.43 (July 13, 2019)\n\n### Bug Fixes\n\n- Addon-analytics: Fix API signature ([#7410](https://github.com/storybookjs/storybook/pull/7410))\n- Addon-knobs: fix knobs function return types ([#7391](https://github.com/storybookjs/storybook/pull/7391))\n- UI: Fix proptype for isToolshown ([#7405](https://github.com/storybookjs/storybook/pull/7405))\n- UI: Fix propType warnings ([#7408](https://github.com/storybookjs/storybook/pull/7408))\n\n### Maintenance\n\n- Addon-actions: Use v4 UUID instead of v1 for action IDs ([#7397](https://github.com/storybookjs/storybook/pull/7397))\n- UI: Remove recompose ([#7385](https://github.com/storybookjs/storybook/pull/7385))\n- UI: FIX & IMPROVE styling interop of addon-background & addon-viewport ([#7385](https://github.com/storybookjs/storybook/pull/7385))\n\n### Breaking Changes\n\n- Move grid toolbar feature to background-addon ([#7385](https://github.com/storybookjs/storybook/pull/7385))\n\n## 5.2.0-alpha.42 (July 12, 2019)\n\n### Breaking Changes\n\n- Addon-docs: Remove primary parameter ([#7383](https://github.com/storybookjs/storybook/pull/7383))\n\n### Bug Fixes\n\n- Addon-docs: Fix default separator inconsistency ([#7382](https://github.com/storybookjs/storybook/pull/7382))\n- UI: Fix placement of notificationistList on docs page ([#7290](https://github.com/storybookjs/storybook/pull/7290))\n\n### Maintenance\n\n- Typescript: Migrate @storybook/html ([#7338](https://github.com/storybookjs/storybook/pull/7338))\n\n### Dependency Upgrades\n\n- Bump lodash from 4.17.13 to 4.17.14 ([#7384](https://github.com/storybookjs/storybook/pull/7384))\n- [Security] Bump lodash.defaultsdeep from 4.6.0 to 4.6.1 ([#7370](https://github.com/storybookjs/storybook/pull/7370))\n- [Security] Bump lodash from 4.17.11 to 4.17.13 ([#7374](https://github.com/storybookjs/storybook/pull/7374))\n- [Security] Bump lodash.mergewith from 4.6.1 to 4.6.2 ([#7372](https://github.com/storybookjs/storybook/pull/7372))\n- [Security] Bump lodash.merge from 4.6.1 to 4.6.2 ([#7373](https://github.com/storybookjs/storybook/pull/7373))\n- [Security] Bump lodash-es from 4.17.11 to 4.17.14 ([#7371](https://github.com/storybookjs/storybook/pull/7371))\n- Upgrade react-select dependency to version 3 for addon-knobs ([#7336](https://github.com/storybookjs/storybook/pull/7336))\n\n## 5.2.0-alpha.41 (July 11, 2019)\n\n### Features\n\n- API: Preview hooks ([#6916](https://github.com/storybookjs/storybook/pull/6916))\n- Core: Custom webpack option for standalone storybook ([#6886](https://github.com/storybookjs/storybook/pull/6886))\n\n### Bug Fixes\n\n- Addon-knobs: Fix TypeError on KnobManager channel ([#7341](https://github.com/storybookjs/storybook/pull/7341))\n- React-native: Explicitly depend on emotion core and theming ([#7362](https://github.com/storybookjs/storybook/pull/7362))\n\n### Dependency Upgrades\n\n- Bump @babel/preset-env from 7.5.0 to 7.5.4 ([#7364](https://github.com/storybookjs/storybook/pull/7364))\n- Update react-test-renderer requirement from 16.5.1 to 16.8.6 in /examples-native/crna-kitchen-sink ([#6372](https://github.com/storybookjs/storybook/pull/6372))\n- Bump rax-text from 0.6.5 to 1.0.0 ([#7346](https://github.com/storybookjs/storybook/pull/7346))\n\n## 5.2.0-alpha.40 (July 10, 2019)\n\n### Bug Fixes\n\n- Addon-knobs: Revert entrypoint deletion ([#7369](https://github.com/storybookjs/storybook/pull/7369))\n- Typescript: Fix types in api package ([#7072](https://github.com/storybookjs/storybook/pull/7072))\n- UI: Fix settings page route (about, shortcuts) ([#7241](https://github.com/storybookjs/storybook/pull/7241))\n\n### Maintenance\n\n- Linting: ADD an ignore for an eslint error about a missing dependency (puppeteer) ([#7239](https://github.com/storybookjs/storybook/pull/7239))\n- CI: ADD travis ([#7252](https://github.com/storybookjs/storybook/pull/7252))\n- Typescript: Migrate @storybook/angular ([#6570](https://github.com/storybookjs/storybook/pull/6570))\n\n### Dependency Upgrades\n\n- Bump express-graphql from 0.7.1 to 0.8.0 ([#7345](https://github.com/storybookjs/storybook/pull/7345))\n- Bump react-native-modal-datetime-picker from 6.1.0 to 7.4.2 ([#6844](https://github.com/storybookjs/storybook/pull/6844))\n\n## 5.2.0-alpha.39 (July 10, 2019)\n\n### Bug Fixes\n\n- UI: Fix Sidebar input refresh on 'Enter' ([#7342](https://github.com/storybookjs/storybook/pull/7342))\n- Addon-knobs: Fix select options types to allow string[] and null ([#7356](https://github.com/storybookjs/storybook/pull/7356))\n\n### Maintenance\n\n- Typescript: Migrate @storybook/react ([#7054](https://github.com/storybookjs/storybook/pull/7054))\n- Build: delete tests & snapshots from dist ([#7358](https://github.com/storybookjs/storybook/pull/7358))\n\n## 5.2.0-alpha.38 (July 9, 2019)\n\n### Bug Fixes\n\n- Addon-storysource: Replace loader with source-loader ([#7272](https://github.com/storybookjs/storybook/pull/7272))\n\n### Maintenance\n\n- Typescript: Migrate @storybook/addon-knobs ([#7180](https://github.com/storybookjs/storybook/pull/7180))\n\n### Dependency Upgrades\n\n- Upgrade all dependencies ([#7329](https://github.com/storybookjs/storybook/pull/7329))\n\n## 5.2.0-alpha.37 (July 8, 2019)\n\n### Bug Fixes\n\n- Addon-docs: Use storyFn instead of getDecorated ([#7334](https://github.com/storybookjs/storybook/pull/7334))\n- Addon-knobs: Prevent rerender when a button callback returns false. ([#7197](https://github.com/storybookjs/storybook/pull/7197))\n- Addons: Fix null parameters in disable addons tab logic ([#7333](https://github.com/storybookjs/storybook/pull/7333))\n- Addon-docs: Fix renaming stories on module / MDX format ([#7319](https://github.com/storybookjs/storybook/pull/7319))\n- Addon-centered/contexts: Move optionalDependencies to peerDependencies ([#7315](https://github.com/storybookjs/storybook/pull/7315))\n\n### Maintenance\n\n- Typescript: migrate client api ([#7147](https://github.com/storybookjs/storybook/pull/7147))\n- Angular-cli: Add addon-docs example ([#7257](https://github.com/storybookjs/storybook/pull/7257))\n\n## 5.2.0-alpha.36 (July 5, 2019)\n\n### Features\n\n- Addon-docs: Added inline option to Story block ([#7308](https://github.com/storybookjs/storybook/pull/7308))\n- Addon-knobs: Ensure unique knob names across groups ([#6793](https://github.com/storybookjs/storybook/pull/6793))\n- Core: Enable webpack to rebuild changes in node_modules ([#6265](https://github.com/storybookjs/storybook/pull/6265))\n- Addons: Disable option for addon tab ([#6923](https://github.com/storybookjs/storybook/pull/6923))\n\n### Bug Fixes\n\n- Fix lint error from #6923 ([#7311](https://github.com/storybookjs/storybook/pull/7311))\n- Addon-actions: fix serialization performance ([#7256](https://github.com/storybookjs/storybook/pull/7256))\n\n### Maintenance\n\n- Typescript: Migrate @storybook/addon-event ([#7190](https://github.com/storybookjs/storybook/pull/7190))\n- Typescript: Improve actions type ([#7012](https://github.com/storybookjs/storybook/pull/7012))\n\n## 5.2.0-alpha.35 (July 3, 2019)\n\n### Bug Fixes\n\n- React-Native: Fix null story check ([#7243](https://github.com/storybookjs/storybook/pull/7243))\n\n## 5.2.0-alpha.34 (July 2, 2019)\n\n### Bug Fixes\n\n- CLI: Fix `--preview-url` for static builds ([#7245](https://github.com/storybookjs/storybook/pull/7245))\n- Addon-docs: Fix non-React support & add Vue example ([#7222](https://github.com/storybookjs/storybook/pull/7222))\n- CLI: Move the free port logic so that loadOptions don't override it ([#7237](https://github.com/storybookjs/storybook/pull/7237))\n\n## 5.2.0-alpha.33 (July 1, 2019)\n\n### Features\n\n- CLI: Add `--preview-url` for custom preview ([#7235](https://github.com/storybookjs/storybook/pull/7235))\n\n### Bug Fixes\n\n- React-Native: Upgrade to new `story_store` API ([#7234](https://github.com/storybookjs/storybook/pull/7234))\n\n## 5.2.0-alpha.32 (June 29, 2019)\n\n### Features\n\n- Addon-docs: Add .story.mdx support to preset ([#7229](https://github.com/storybookjs/storybook/pull/7229))\n\n### Bug Fixes\n\n- React-native: Fix react native server ([#7187](https://github.com/storybookjs/storybook/pull/7187))\n- Addon-docs: Fix source-loader in monorepo examples ([#7214](https://github.com/storybookjs/storybook/pull/7214))\n\n### Maintenance\n\n- Addon-docs: Convert repo stories to new module format ([#7175](https://github.com/storybookjs/storybook/pull/7175))\n\n## 5.2.0-alpha.31 (June 27, 2019)\n\n### Breaking Changes\n\n- Module format: story field for name/parameters annotation ([#7202](https://github.com/storybookjs/storybook/pull/7202))\n\n### Features\n\n- Core: Story sorting ([#6472](https://github.com/storybookjs/storybook/pull/6472))\n\n### Maintenance\n\n- Addon-docs: Fix source-loader CI errors ([#7203](https://github.com/storybookjs/storybook/pull/7203))\n\n## 5.2.0-alpha.30 (June 25, 2019)\n\nThis release merges `release/docs-technical-preview` branch back into `next` through a series of PRs. It also contains other changes that came in on `next` since the last alpha.\n\n### Features\n\n- CLI: Add info command to print environment information ([#6937](https://github.com/storybookjs/storybook/pull/6937))\n- CLI: Use process.env.CI if available ([#7118](https://github.com/storybookjs/storybook/pull/7118))\n- Addon-docs: Source loader library ([#7117](https://github.com/storybookjs/storybook/pull/7117))\n- Addon-docs: Support non-story exports in MDX ([#7188](https://github.com/storybookjs/storybook/pull/7188))\n- Addon-docs: Support non-story exports in module format ([#7185](https://github.com/storybookjs/storybook/pull/7185))\n- Addon-docs: Docs mode with `--docs` flag ([#7154](https://github.com/storybookjs/storybook/pull/7154))\n- Addon-docs: Convert to module format codemod ([#7174](https://github.com/storybookjs/storybook/pull/7174))\n- Addon-docs: MDX support ([#7145](https://github.com/storybookjs/storybook/pull/7145))\n- Addon-docs: Component parameter codemod ([#7155](https://github.com/storybookjs/storybook/pull/7155))\n- Addon-docs: DocsPage and doc blocks ([#7119](https://github.com/storybookjs/storybook/pull/7119))\n- Addon-docs: Module story format & framework param ([#7110](https://github.com/storybookjs/storybook/pull/7110))\n- Addon-docs: Basic skeleton, UI viewMode handling ([#7107](https://github.com/storybookjs/storybook/pull/7107))\n\n### Bug Fixes\n\n- Addon-backgrounds: Fix unstretched preview background wrapper ([#7173](https://github.com/storybookjs/storybook/pull/7173))\n- Addon-notes/info: Fix indenting on markdown code blocks ([#7158](https://github.com/storybookjs/storybook/pull/7158))\n- Core: Improve HMR error reporting, no refreshes needed for error recovery ([#6972](https://github.com/storybookjs/storybook/pull/6972))\n- Addon-info: change stylesheetBase info height from 110vh to 100vh ([#7141](https://github.com/storybookjs/storybook/pull/7141))\n\n### Maintenance\n\n- Typescript: Migrate addon viewport ([#7177](https://github.com/storybookjs/storybook/pull/7177))\n\n### Dependency Upgrades\n\n- Bump css-loader from 2.1.1 to 3.0.0 ([#7122](https://github.com/storybookjs/storybook/pull/7122))\n- Upgrade core-js to 3.x in devkits ([#7171](https://github.com/storybookjs/storybook/pull/7171))\n- UPGRADE lazy-universal-dotenv ([#7151](https://github.com/storybookjs/storybook/pull/7151))\n\n## 5.1.9 (June 20, 2019)\n\n### Bug Fixes\n\n- Core: Fix JSON babel config error reporting ([#7104](https://github.com/storybookjs/storybook/pull/7104))\n- UI: Fix about page version check message ([#7105](https://github.com/storybookjs/storybook/pull/7105))\n\n### Dependency Upgrades\n\n- Add missing dependencies to ui/react ([#7081](https://github.com/storybookjs/storybook/pull/7081))\n- UPGRADE lazy-universal-dotenv ([#7151](https://github.com/storybookjs/storybook/pull/7151))\n- Make compatible with yarn Pnp ([#6922](https://github.com/storybookjs/storybook/pull/6922))\n\n## 5.2.0-alpha.29 (June 17, 2019)\n\n### Features\n\n- Addon-notes: enable multiple sections in notes panel ([#6861](https://github.com/storybookjs/storybook/pull/6861))\n- Addon-context: title fallback ([#7078](https://github.com/storybookjs/storybook/pull/7078))\n- Addon-info: Fix rendering of code block ([#6016](https://github.com/storybookjs/storybook/pull/6016))\n\n### Bug Fixes\n\n- Core: Fix JSON babel config error reporting ([#7104](https://github.com/storybookjs/storybook/pull/7104))\n- UI: Fix about page version check message ([#7105](https://github.com/storybookjs/storybook/pull/7105))\n\n### Maintenance\n\n- Core: Refactor story_store ([#6382](https://github.com/storybookjs/storybook/pull/6382))\n- Core: Make compatible with yarn Pnp ([#6922](https://github.com/storybookjs/storybook/pull/6922))\n\n### Dependency Upgrades\n\n- Bump jest-expo from 32.0.1 to 33.0.2 ([#6996](https://github.com/storybookjs/storybook/pull/6996))\n\n## 5.2.0-alpha.28 (June 17, 2019)\n\nPublish failed\n\n## 5.2.0-alpha.27 (June 17, 2019)\n\n- CLI: improve bootstrap list ([#6993](https://github.com/storybookjs/storybook/pull/6993))\n- CLI: replaced merge-dirs dependency by fs-extra ([#7100](https://github.com/storybookjs/storybook/pull/7100))\n\n## 5.1.8 (June 14, 2019)\n\n### Bug Fixes\n\n- CLI: Fix RN template to not import addons ([#7096](https://github.com/storybookjs/storybook/pull/7096))\n\n## 5.1.7 (June 14, 2019)\n\n### Bug Fixes\n\n- UI: Fix warning of loading prop not being a string ([#7080](https://github.com/storybookjs/storybook/pull/7080))\n\n## 5.1.6 (June 14, 2019)\n\nPublish failed\n\n## 5.1.5 (June 14, 2019)\n\n### Bug Fixes\n\n- Core: Upgrade plugin core-js fix ([#7086](https://github.com/storybookjs/storybook/pull/7086))\n- UI: Fix sidebar loading visibility ([#7073](https://github.com/storybookjs/storybook/pull/7073))\n- UI: Fix unnecessary large bundlesize ([#7091](https://github.com/storybookjs/storybook/pull/7091))\n- Addon-contexts, RN-server: Add core-js dep ([#7094](https://github.com/storybookjs/storybook/pull/7094))\n\n## 5.2.0-alpha.26 (June 14, 2019)\n\n- Merge in changes from 5.1.7/next branch.\n- Fix earlier merge problems relating to addon-docs:\n  - Restore `--docs` command-line functionality\n  - Fix refreshing docs page bug\n\n## 5.2.0-alpha.25 (June 14, 2019)\n\nPublish failed\n\n## 5.1.4 (June 13, 2019)\n\n### Bug Fixes\n\n- Core: Fix core-js 3 errors ([#7051](https://github.com/storybookjs/storybook/pull/7051))\n- UI: Fix syntax highlighter plain text not visible ([#7057](https://github.com/storybookjs/storybook/pull/7057))\n- Addon-actions: Add default options to action(s) ([#6438](https://github.com/storybookjs/storybook/pull/6438))\n\n### Dependency Upgrades\n\n- fix: add missing core-js dependency ([#7016](https://github.com/storybookjs/storybook/pull/7016))\n- chore: set react version to 16.8.3 to match react native ([#7008](https://github.com/storybookjs/storybook/pull/7008))\n\n## 5.2.0-alpha.24 (June 13, 2019)\n\nMerge in changes from 5.1.3/next branch.\n\n## 5.2.0-alpha.23 (June 10, 2019)\n\nMerge in changes from 5.1.3/next branch. Releasing from the addon-docs branch to keep things moving until we can merge addon-docs into next.\n\n## 5.2.0-alpha.22 (June 7, 2019)\n\n- Merge in changes from 5.1.1\n- Addon-docs:\n  - Inline stories respect height prop\n  - Export Description block\n\n## 5.1.3 (June 6, 2019)\n\n### Bug Fixes\n\n- UI: Fix links that are not working with plain left click ([#6970](https://github.com/storybookjs/storybook/pull/6970))\n- Core: Don't redefine `process` variable ([#6991](https://github.com/storybookjs/storybook/pull/6991))\n- Core: Don't mutate user's babel config ([#6987](https://github.com/storybookjs/storybook/pull/6987))\n\n## 5.1.2 (June 6, 2019)\n\nPublish failed\n\n## 5.1.1 (June 5, 2019)\n\nStorybook 5.1 is a juicy upgrade including:\n\n- 📱 Mobile: Standalone package architecture for React Native\n- 🎟 A11y addon: Realtime accessibility checks and visual feedback\n- 🛠 Context addon: New UI for themes, internationalization, & more\n- 🎛 Presets: One-line configuration for babel, webpack, & addons\n\n  5.1 contains hundreds more fixes, features, and tweaks. Browse the changelogs matching `5.1.0-alpha.*`, `5.1.0-beta.*`, and `5.1.0-rc.*` for the full list of changes. See [MIGRATION.md](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md) to upgrade from `5.0` or earlier.\n\n## 5.1.0 (June 5, 2019)\n\nPublish failed\n\n## 5.1.0-rc.5 (June 4, 2019)\n\n### Features\n\n- UI: Add copy button for individual story ([#6719](https://github.com/storybookjs/storybook/pull/6719))\n\n### Bug Fixes\n\n- UI: Fix canvas rendering issue ([#6968](https://github.com/storybookjs/storybook/pull/6968))\n- Angular: Remove zonejs from devDeps; allow ^0.8.0 || ^0.9.0 ([#6957](https://github.com/storybookjs/storybook/pull/6957))\n- Jest: layout/design fixes ([#6847](https://github.com/storybookjs/storybook/pull/6847))\n- Angular: Add 'addParameters' to index.d.ts ([#6929](https://github.com/storybookjs/storybook/pull/6929))\n\n### Maintenance\n\n- FIX race condition in startup of verdaccio && FIX typos ([#6956](https://github.com/storybookjs/storybook/pull/6956))\n- Github org rename to storybookjs ([#6954](https://github.com/storybookjs/storybook/pull/6954))\n\n## 5.1.0-rc.4 (June 2, 2019)\n\n### Features\n\n- Core: deep merge global options parameter ([#6900](https://github.com/storybookjs/storybook/pull/6900))\n\n### Bug Fixes\n\n- Core: Fix webpack `process.*` variable definitions ([#6946](https://github.com/storybookjs/storybook/pull/6946))\n- Angular: Fix tsconfig.app.json detection for Angular 8 ([#6940](https://github.com/storybookjs/storybook/pull/6940))\n\n## 5.2.0-alpha.21 (June 2, 2019)\n\n- Core: Convert module format to use default export for metadata\n- Addon-docs: Compile MDX to default export modules format\n- Source-loader: Support parameter injection for default export metadata\n\n## 5.2.0-alpha.20 (May 31, 2019)\n\n- Addon-docs: Use Meta doc block instead of exporting componentMeta\n\n## 5.1.0-rc.3 (May 29, 2019)\n\n### Features\n\n- React-native: Add accessibility on searchbar ([#6819](https://github.com/storybookjs/storybook/pull/6819))\n\n### Bug Fixes\n\n- Storyshots: make compatible with read-pkg-up version ([#6907](https://github.com/storybookjs/storybook/pull/6907))\n- Addon-info: Fix issue where forwardRefs throw ([#6859](https://github.com/storybookjs/storybook/pull/6859))\n- Addon-notes: Fix whitespace rendering bug ([#6881](https://github.com/storybookjs/storybook/pull/6881))\n\n### Dependency Upgrades\n\n- Bump @types/enzyme from 3.9.2 to 3.9.3 ([#6891](https://github.com/storybookjs/storybook/pull/6891))\n- Bump eslint-plugin-import from 2.17.2 to 2.17.3 ([#6894](https://github.com/storybookjs/storybook/pull/6894))\n- Bump mini-css-extract-plugin from 0.6.0 to 0.7.0 ([#6895](https://github.com/storybookjs/storybook/pull/6895))\n- Bump ts-node from 8.1.0 to 8.2.0 ([#6890](https://github.com/storybookjs/storybook/pull/6890))\n- Bump svelte from 3.4.2 to 3.4.4 ([#6892](https://github.com/storybookjs/storybook/pull/6892))\n\n## 5.2.0-alpha.19 (May 28, 2019)\n\n- Source-loader: Fix bad package dependencies\n\n## 5.1.0-rc.2 (May 27, 2019)\n\n### Bug Fixes\n\n- Core: Fix JS/JSON loading babel config ([#6878](https://github.com/storybookjs/storybook/pull/6878))\n\n## 5.2.0-alpha.18 (May 26, 2019)\n\n- Addon-docs: Codemod for adding component parameters\n- Core: Babel config loading bugfix ([#6878](https://github.com/storybookjs/storybook/pull/6878))\n\n## 5.2.0-alpha.17 (May 26, 2019)\n\n- Addon-docs: Refer to selected story/component with `id=\".\"` / `of=\".\"`\n\n## 5.2.0-alpha.16 (May 25, 2019)\n\n- Addon-docs: Auto-configure `inlineStories` & `getPropDefs` based on framework\n\n## 5.2.0-alpha.15 (May 25, 2019)\n\n- Addon-docs: Expanded Vue support\n  - Props table support\n  - iframeHeight configuration parameter\n\n## 5.2.0-alpha.14 (May 25, 2019)\n\n- Addon-docs: Expanded source formats via `@storybook/source-loader`\n  - Legacy `storiesOf` format x (JS / TSX)\n  - Component modules format x (JS / TSX)\n  - Component MDX format\n\n## 5.2.0-alpha.13 (May 24, 2019)\n\n- Addon-docs: Add documentation-only `--docs` option to build storybook\n\n## 5.1.0-rc.1 (May 24, 2019)\n\n### Features\n\n- Core: Support loglevel for production/ci builds ([#6825](https://github.com/storybookjs/storybook/pull/6825))\n\n### Bug Fixes\n\n- Addon-storysource: Fix link color ([#6876](https://github.com/storybookjs/storybook/pull/6876))\n- Addon-centered: Fix unnecessary scroll bar ([#6862](https://github.com/storybookjs/storybook/pull/6862))\n- UI: Apply customQueryParams to eject iframe button ([#6817](https://github.com/storybookjs/storybook/pull/6817))\n- Theming: resolve paths locally if possible ([#6808](https://github.com/storybookjs/storybook/pull/6808))\n- Addon-links: Fix withLinks decorator ([#6823](https://github.com/storybookjs/storybook/pull/6823))\n\n### Maintenance\n\n- Addon-contexts: component tests and readability improvements ([#6716](https://github.com/storybookjs/storybook/pull/6716))\n\n### Dependency Upgrades\n\n- Upgrade CRA preset dependencies to match CRA v3 ([#6589](https://github.com/storybookjs/storybook/pull/6589))\n- Bump schedule from 0.4.0 to 0.5.0 ([#6843](https://github.com/storybookjs/storybook/pull/6843))\n- UPGRADE dependencies & fix a security vulnerability (low-prio) ([#6875](https://github.com/storybookjs/storybook/pull/6875))\n- Bump simplebar-react from 1.0.0-alpha.9 to 1.0.0 ([#6842](https://github.com/storybookjs/storybook/pull/6842))\n- Bump ts-loader from 5.4.5 to 6.0.1 ([#6839](https://github.com/storybookjs/storybook/pull/6839))\n- Bump @types/react from 16.8.17 to 16.8.18 ([#6841](https://github.com/storybookjs/storybook/pull/6841))\n- Bump core-js-pure from 3.1.0 to 3.1.1 ([#6840](https://github.com/storybookjs/storybook/pull/6840))\n\n## 5.1.0-rc.0 (May 21, 2019)\n\n### Bug Fixes\n\n- UI: Fix initial bottom panel size ([#6822](https://github.com/storybookjs/storybook/pull/6822))\n- UI: Fix syntaxhighlighter themes ([#6814](https://github.com/storybookjs/storybook/pull/6814))\n- Addon-knobs: Fix Boolean knob (#6366) ([#6830](https://github.com/storybookjs/storybook/pull/6830))\n- Theming: Change lib/theming so it no longer depends on react-inspector ([#6818](https://github.com/storybookjs/storybook/pull/6818))\n- Core: Handle loading `.storybook/babel.config.js` (#6633) ([#6634](https://github.com/storybookjs/storybook/pull/6634))\n- CLI: Fix init in create-react-library projects ([#6815](https://github.com/storybookjs/storybook/pull/6815))\n- HTML: support knobs for both cached and uncached nodes ([#6783](https://github.com/storybookjs/storybook/pull/6783))\n- Uncorrupt yarn lock ([#6811](https://github.com/storybookjs/storybook/pull/6811))\n- Core: set a better value for process in manager webpack config ([#6767](https://github.com/storybookjs/storybook/pull/6767))\n\n### Maintenance\n\n- Typescript: Migrate addon-centered ([#6772](https://github.com/storybookjs/storybook/pull/6772))\n- Add engine field to package.json in apps ([#6809](https://github.com/storybookjs/storybook/pull/6809))\n- Fix required engine for apps ([#6810](https://github.com/storybookjs/storybook/pull/6810))\n\n### Dependency Upgrades\n\n- Upgrade lodash to latest ([#6832](https://github.com/storybookjs/storybook/pull/6832))\n- Bump svelte from 3.4.1 to 3.4.2 ([#6838](https://github.com/storybookjs/storybook/pull/6838))\n- Misc upgrades ([#6820](https://github.com/storybookjs/storybook/pull/6820))\n\n## 5.2.0-alpha.12 (May 21, 2019)\n\n- Addon-docs: Fix regression in preview source for legacy stories\n\n## 5.2.0-alpha.11 (May 21, 2019)\n\n- Addon-docs:\n  - Source refer to stories by name\n  - Source support for multi-story previews\n  - Fix loader bug for plaintext stories\n\n## 5.2.0-alpha.10 (May 19, 2019)\n\n- Addon-docs: Display source dropdown in preview component\n\n## 5.2.0-alpha.9 (May 17, 2019)\n\n- Addon-docs bugfixes:\n  - Fix broken components stories\n  - Fix regression in iframe preview\n  - Fix docgen props block\n  - Fix margin styling on docs page\n\n## 5.1.0-beta.1 (May 16, 2019)\n\n### Bug Fixes\n\n- UI: Scrollbar supports theming again ([#6794](https://github.com/storybookjs/storybook/pull/6794))\n- UI: Fix scrolling styling ([#6785](https://github.com/storybookjs/storybook/pull/6785))\n- UI: Fix iframe refresh ([#6787](https://github.com/storybookjs/storybook/pull/6787))\n- UI: Preserve dimensions on resizing for panel ([#6696](https://github.com/storybookjs/storybook/pull/6696))\n\n### Maintenance\n\n- Move chromatic to circle ci ([#6752](https://github.com/storybookjs/storybook/pull/6752))\n\n### Dependency Upgrades\n\n- Bump fs-extra from 7.0.1 to 8.0.1 ([#6776](https://github.com/storybookjs/storybook/pull/6776))\n\n## 5.2.0-alpha.8 (May 15, 2019)\n\n- Addon-docs: Optimize docs pane rerendering\n\n## 5.2.0-alpha.7 (May 15, 2019)\n\n- Addon-docs: Docs page bugfix\n- Addon-docs: Fix source block for legacy stories\n\nNOTE: use `@storybook/source-loader` with option `injectParameters: true` for legacy source\n\n## 5.2.0-alpha.6 (May 14, 2019)\n\n- Addon-docs: Docs page content update\n- Addon-docs: Preview component redefinition\n\n#### Breaking changes\n\nPreview behavior has been updated. Docs page content has been updated.\n\nBefore:\n\n- `<Story name=\"a\">` defines a story, `<Preview id=\"x--a\"/>` references it\n\nAfter:\n\n- `<Story name=\"a\">` defines a story, `<Story id=\"x--a\"/>` references it\n- `<Preview><Story .../><Story .../><Component/></Preview>` shows one or more stories in a grid\n\n## 5.2.0-alpha.5 (May 12, 2019)\n\n- Addon-docs: Description block refactor and bugfixes\n\n## 5.2.0-alpha.4 (May 11, 2019)\n\n- Addon-docs: Source, Props, DocsPage doc blocks\n\n#### Breaking changes\n\n- Doc blocks & presets have moved. Update your MDX stories and `presets.js` file accordingly:\n  - `import { Preview, Story } from '@storybook/addon-docs/blocks';`\n  - `module.exports = ['@storybook/addon-docs/common/preset'];`\n\n## 5.1.0-beta.0 (May 10, 2019)\n\nWelcome to the 5.1 beta! Feature development's done; `beta.0` kicks off the stabilization process for the 5.1 final release. 🚀\n\n## 5.1.0-alpha.40 (May 8, 2019)\n\n### Features\n\n- Svelte: Add svelte v3 support ([#6698](https://github.com/storybookjs/storybook/pull/6698))\n- Angular: Disable production mode for debugging components ([#6215](https://github.com/storybookjs/storybook/pull/6215))\n- Angular: Allow optional component declaration without additional configuration ([#6666](https://github.com/storybookjs/storybook/pull/6666))\n- Core: Allow browsing to a kind and get the first story ([#6720](https://github.com/storybookjs/storybook/pull/6720))\n\n### Bug Fixes\n\n- UI: Preserve dimensions on resizing for panel ([#6696](https://github.com/storybookjs/storybook/pull/6696))\n\n### Maintenance\n\n- Add CRA React15 example to test back-compat ([#6475](https://github.com/storybookjs/storybook/pull/6475))\n- Remove teamcity CLI tests ([#6707](https://github.com/storybookjs/storybook/pull/6707))\n\n### Dependency Upgrades\n\n- Upgrade to core-js v3 ([#6655](https://github.com/storybookjs/storybook/pull/6655))\n- Bump eslint-plugin-react from 7.12.4 to 7.13.0 ([#6728](https://github.com/storybookjs/storybook/pull/6728))\n- Bump @types/react-native from 0.57.50 to 0.57.51 ([#6732](https://github.com/storybookjs/storybook/pull/6732))\n- Bump @types/node from 11.13.7 to 12.0.0 ([#6730](https://github.com/storybookjs/storybook/pull/6730))\n- Bump jest-cli from 24.7.1 to 24.8.0 ([#6729](https://github.com/storybookjs/storybook/pull/6729))\n- Bump @babel/preset-env from 7.4.3 to 7.4.4 ([#6731](https://github.com/storybookjs/storybook/pull/6731))\n- Bump raw-loader from 1.0.0 to 2.0.0 ([#6685](https://github.com/storybookjs/storybook/pull/6685))\n- Bump react-color from 2.17.1 to 2.17.3 ([#6681](https://github.com/storybookjs/storybook/pull/6681))\n- Bump @babel/plugin-proposal-class-properties from 7.4.0 to 7.4.4 ([#6686](https://github.com/storybookjs/storybook/pull/6686))\n- Bump react-dev-utils from 8.0.0 to 9.0.0 ([#6682](https://github.com/storybookjs/storybook/pull/6682))\n- Bump codelyzer from 5.0.0 to 5.0.1 ([#6687](https://github.com/storybookjs/storybook/pull/6687))\n- Bump @types/react from 16.8.14 to 16.8.16 ([#6717](https://github.com/storybookjs/storybook/pull/6717))\n- Bump react-redux from 7.0.2 to 7.0.3 ([#6684](https://github.com/storybookjs/storybook/pull/6684))\n\n## 5.1.0-alpha.39 (May 2, 2019)\n\n### Features\n\n- React-native: Ondevice actions ([#6594](https://github.com/storybookjs/storybook/pull/6594))\n- React-native: Use emotion to style RN UI ([#6603](https://github.com/storybookjs/storybook/pull/6603))\n\n### Bug Fixes\n\n- API: Mimic PureComponent behavior for Consumer children ([#6412](https://github.com/storybookjs/storybook/pull/6412))\n\n## 5.1.0-alpha.38 (May 2, 2019)\n\nFailed publish\n\n## 5.1.0-alpha.37 (May 1, 2019)\n\n### Bug Fixes\n\n- Core: Fix regression with deep linking ([#6688](https://github.com/storybookjs/storybook/pull/6688))\n- Addon-contexts: No cancel option in UI if the context have no param ([#6669](https://github.com/storybookjs/storybook/pull/6669))\n- CLI: Fix `sb init` for projects with frozen lock files ([#6629](https://github.com/storybookjs/storybook/pull/6629))\n\n### Maintenance\n\n- CLI: Refactor how we install dev dependencies in cli ([#6695](https://github.com/storybookjs/storybook/pull/6695))\n\n## 5.2.0-alpha.3 (May 1, 2019)\n\n- Addon-docs: Add Story decorator and parameter support\n- Addon-docs: Remove need for extra project babelrc\n\n## 5.2.0-alpha.2 (April 30, 2019)\n\n- Addon-docs: Streamline setup, fix MDX dependencies, improve MDX import, and update guide\n\n## 5.2.0-alpha.0 (April 29, 2019)\n\nStorybook Docs technical preview:\n\n- Docs addon\n- MDX story format\n- Module story format\n- Load API\n- [Guide](https://docs.google.com/document/d/1un6YX7xDKEKl5-MVb-egnOYN8dynb5Hf7mq0hipk8JE/edit?usp=sharing)\n\n## 5.0.11 (April 28, 2019)\n\n### Bug Fixes\n\n- Polymer: Fix re-rendering lit-html elements after non-lit-html element ([#5868](https://github.com/storybookjs/storybook/pull/5868))\n- Addon-knobs: Check color knob value before applying uppercase ([#6598](https://github.com/storybookjs/storybook/pull/6598))\n- Angular: Fix sourceMap property of angulars webpack config ([#6535](https://github.com/storybookjs/storybook/pull/6535))\n\n### Maintenance\n\n- UI: Add missing props in stories ([#6353](https://github.com/storybookjs/storybook/pull/6353))\n\n## 5.1.0-alpha.36 (April 27, 2019)\n\n### Features\n\n- Addon-contexts: Preact support ([#6660](https://github.com/storybookjs/storybook/pull/6660))\n- Angular: Allow optional component declaration ([#6346](https://github.com/storybookjs/storybook/pull/6346))\n\n### Bug Fixes\n\n- CLI: Fix `sb init` for projects with frozen lock files ([#6629](https://github.com/storybookjs/storybook/pull/6629))\n\n### Dependency Upgrades\n\n- [Snyk] Fix for 1 vulnerable dependencies ([#6647](https://github.com/storybookjs/storybook/pull/6647))\n\n## 5.1.0-alpha.35 (April 27, 2019)\n\n### Features\n\n- Addon-notes: use @storybook/router <Link> to render links in notes ([#6398](https://github.com/storybookjs/storybook/pull/6398))\n- Angular: Support default `storybook` project configuration ([#6484](https://github.com/storybookjs/storybook/pull/6484))\n- Addon-contexts: Improve Vue integration ([#6632](https://github.com/storybookjs/storybook/pull/6632))\n- Addon-a11y: Design enhancements ([#6563](https://github.com/storybookjs/storybook/pull/6563))\n\n### Bug Fixes\n\n- UI: `active` PropTypes on MobileLayout ([#6241](https://github.com/storybookjs/storybook/pull/6241))\n- Core: Fix css import when sideEffects is false ([#6650](https://github.com/storybookjs/storybook/pull/6650))\n- Core: Fix infinite loop with special characters in kind names ([#6607](https://github.com/storybookjs/storybook/pull/6607))\n- UI: Fix 'Escape' onKeyUp event doesn't work ([#6578](https://github.com/storybookjs/storybook/pull/6578))\n\n### Maintenance\n\n- UI: Add missing props in stories ([#6353](https://github.com/storybookjs/storybook/pull/6353))\n- Build: tslint, and use eslint for everything ([#6621](https://github.com/storybookjs/storybook/pull/6621))\n- Build: deploy to local registry ([#6619](https://github.com/storybookjs/storybook/pull/6619))\n\n### Dependency Upgrades\n\n- Bump ts-node from 8.0.3 to 8.1.0 ([#6585](https://github.com/storybookjs/storybook/pull/6585))\n- Bump semver from 5.7.0 to 6.0.0 ([#6580](https://github.com/storybookjs/storybook/pull/6580))\n- Bump react-color from 2.17.0 to 2.17.1 ([#6583](https://github.com/storybookjs/storybook/pull/6583))\n\n## 5.1.0-alpha.34 (April 24, 2019)\n\n### Features\n\n- Addon-contexts: Add URL query param feature ([#6601](https://github.com/storybookjs/storybook/pull/6601))\n- UI: Add classNames to sidebar nav elements ([#6571](https://github.com/storybookjs/storybook/pull/6571))\n\n### Bug Fixes\n\n- Addon-knobs: Check color knob value before applying uppercase ([#6598](https://github.com/storybookjs/storybook/pull/6598))\n- React-native: Restore title in section header ([#6599](https://github.com/storybookjs/storybook/pull/6599))\n\n## 5.1.0-alpha.33 (April 23, 2019)\n\n### Features\n\n- React: Add support for create-react-app@3.0.0 ([#6560](https://github.com/storybookjs/storybook/pull/6560))\n\n## 5.1.0-alpha.32 (April 22, 2019)\n\n### Bug Fixes\n\n- Addon-contexts: bug-fixing, testing, typing ([#6572](https://github.com/storybookjs/storybook/pull/6572))\n\n### Dependency Upgrades\n\n- CHANGE opn to open ([#6567](https://github.com/storybookjs/storybook/pull/6567))\n\n## 5.1.0-alpha.31 (April 19, 2019)\n\n### Features\n\n- Addon-backgrounds: Emit event on updating background ([#6561](https://github.com/storybookjs/storybook/pull/6561))\n- Addon-contexts: Merge into monorepo ([#6559](https://github.com/storybookjs/storybook/pull/6559))\n\n### Bug Fixes\n\n- Angular: Fix sourceMap property of angulars webpack config ([#6535](https://github.com/storybookjs/storybook/pull/6535))\n- Addon-jest: Fix result display ([#6539](https://github.com/storybookjs/storybook/pull/6539))\n\n### Dependency Upgrades\n\n- Bump ember-source from 3.8.1 to 3.9.1 ([#6531](https://github.com/storybookjs/storybook/pull/6531))\n- Bump typescript from 3.4.2 to 3.4.3 ([#6528](https://github.com/storybookjs/storybook/pull/6528))\n\n## 5.0.10 (April 18, 2019)\n\n### Bug Fixes\n\n- Theming: legacy options don't override set config options ([#6543](https://github.com/storybookjs/storybook/pull/6543))\n- Theming: Fix null brandImage ([#6544](https://github.com/storybookjs/storybook/pull/6544))\n\n## 5.1.0-alpha.30 (April 18, 2019)\n\n### Bug Fixes\n\n- UI: Fix hard-coded viewmode to enable tabbed addons ([#6551](https://github.com/storybookjs/storybook/pull/6551))\n- Theming: legacy options don't override set config options ([#6543](https://github.com/storybookjs/storybook/pull/6543))\n- React-native: Fix preview only UI ([#6549](https://github.com/storybookjs/storybook/pull/6549))\n\n### Dependency Upgrades\n\n- Bump react-redux from 6.0.1 to 7.0.2 ([#6529](https://github.com/storybookjs/storybook/pull/6529))\n\n### Maintenance\n\n- Addon-storysource: Migrate from using channel to api ([#6550](https://github.com/storybookjs/storybook/pull/6550))\n\n## 5.1.0-alpha.29 (April 17, 2019)\n\n### Bug Fixes\n\n- Theming: Fix null brandImage ([#6544](https://github.com/storybookjs/storybook/pull/6544))\n\n### Maintenance\n\n- Typescript: Migrate @storybook/components part 2 ([#6500](https://github.com/storybookjs/storybook/pull/6500))\n\n### Dependency Upgrades\n\n- Bump @types/node from 11.11.8 to 11.13.4 ([#6527](https://github.com/storybookjs/storybook/pull/6527))\n- Bump danger from 7.0.19 to 7.1.2 ([#6530](https://github.com/storybookjs/storybook/pull/6530))\n\n## 5.0.9 (April 17, 2019)\n\n### Bug Fixes\n\n- UI: Fix panel toggle behavior in fullscreen ([#6525](https://github.com/storybookjs/storybook/pull/6525))\n- Addon-Knobs: Add missing groupId for files knob ([#6534](https://github.com/storybookjs/storybook/pull/6534))\n- Theming: FIX brandImage when theme created with brandTitle ([#6120](https://github.com/storybookjs/storybook/pull/6120))\n\n## 5.1.0-alpha.28 (April 16, 2019)\n\n### Bug Fixes\n\n- UI: Fix panel toggle behavior in fullscreen ([#6525](https://github.com/storybookjs/storybook/pull/6525))\n- Addon-Knobs: Add missing groupId for files knob ([#6534](https://github.com/storybookjs/storybook/pull/6534))\n\n### Maintenance\n\n- Typescript: Fix ts-lint config to lint `tsx` files ([#6533](https://github.com/storybookjs/storybook/pull/6533))\n- Typescript: Migrate app/react-native ([#6448](https://github.com/storybookjs/storybook/pull/6448))\n- CLI: Improve cli for react-native ([#6515](https://github.com/storybookjs/storybook/pull/6515))\n- Workflow: Automention for project maintainers ([#6509](https://github.com/storybookjs/storybook/pull/6509))\n\n## 5.0.8 (April 15, 2019)\n\nBump version to make `5.0.x` latest since I just released a patch in `v4.1.18`\n\n## 4.1.18 (April 15, 2019)\n\n### Bug Fixes\n\n- Pin react-treebeard dependency at 3.1.0 ([#6517](https://github.com/storybookjs/storybook/pull/6517))\n\n## 4.1.17 (April 15, 2019)\n\nNPM publish failed\n\n## 5.0.7 (April 14, 2019)\n\n### Bug Fixes\n\n- Addon-Knobs: Fix sorting of knobs Panels ([#6480](https://github.com/storybookjs/storybook/pull/6480))\n- UI: Fix clickable footer links on about page ([#6441](https://github.com/storybookjs/storybook/pull/6441))\n- UI: Fix 'read full changelog' link on about page ([#6385](https://github.com/storybookjs/storybook/pull/6385))\n\n## 5.1.0-alpha.27 (April 14, 2019)\n\n### Features\n\n- Core: Disable webpack performance hints in manager config ([#6390](https://github.com/storybookjs/storybook/pull/6390))\n- Addon-A11y: Drop a11y filter on double click ([#6503](https://github.com/storybookjs/storybook/pull/6503))\n\n### Bug Fixes\n\n- Addon-Jest: use 'off' instead of 'removeListener' ([#6508](https://github.com/storybookjs/storybook/pull/6508))\n\n## 5.1.0-alpha.26 (April 13, 2019)\n\n### Bug Fixes\n\n- Addon-background: Fix addon by moving 'iframe' styles ([#6502](https://github.com/storybookjs/storybook/pull/6502))\n\n## 5.1.0-alpha.25 (April 12, 2019)\n\n### Features\n\n- Addon-info: Add support for memoized components ([#6347](https://github.com/storybookjs/storybook/pull/6347))\n- Addon-notes: Register notes as a panel or tab ([#6091](https://github.com/storybookjs/storybook/pull/6091))\n\n### Bug Fixes\n\n- Core: Fix: custom parameters on preview url ([#6486](https://github.com/storybookjs/storybook/pull/6486))\n- Addon-knobs: Fix sorting of ungrouped knobs panel ([#6480](https://github.com/storybookjs/storybook/pull/6480))\n- Core: Use babel-loader from react-scripts ([#5308](https://github.com/storybookjs/storybook/pull/5308))\n\n### Dependency Upgrades\n\n- Bump opn from 5.4.0 to 6.0.0 ([#6370](https://github.com/storybookjs/storybook/pull/6370))\n- Bump @angular/forms from 7.2.7 to 7.2.12 ([#6424](https://github.com/storybookjs/storybook/pull/6424))\n- chore(deps): bump marko from 4.16.7 to 4.16.9 ([#6459](https://github.com/storybookjs/storybook/pull/6459))\n- chore(deps-dev): bump @types/react from 16.8.12 to 16.8.13 ([#6457](https://github.com/storybookjs/storybook/pull/6457))\n- chore(deps-dev): bump typescript from 3.4.1 to 3.4.2 ([#6456](https://github.com/storybookjs/storybook/pull/6456))\n\n## 5.1.0-alpha.24 (April 9, 2019)\n\n### Maintenance\n\n- React-native: Remove channel dep from ondevice-notes ([#6431](https://github.com/storybookjs/storybook/pull/6431))\n- Typescript: Migrate @storybook/components ([#6095](https://github.com/storybookjs/storybook/pull/6095))\n\n## 5.1.0-alpha.23 (April 8, 2019)\n\n### Features\n\n- Addon-a11y: Add 'indeterminate' checkbox state for partial selected group ([#6405](https://github.com/storybookjs/storybook/pull/6405))\n- Angular: Add out-of-the-box support for \\*.md ([#6444](https://github.com/storybookjs/storybook/pull/6444))\n\n### Bug Fixes\n\n- UI: Move '@emotion/\\*' path-resolutions to the dependent package ([#6435](https://github.com/storybookjs/storybook/pull/6435))\n- Core: Set custom options on first load ([#6395](https://github.com/storybookjs/storybook/pull/6395))\n- UI: clickable footer links ([#6441](https://github.com/storybookjs/storybook/pull/6441))\n\n### Maintenance\n\n- Typescript: Migrate @storybook/addon-jest ([#6403](https://github.com/storybookjs/storybook/pull/6403))\n\n## 5.1.0-alpha.22 (April 5, 2019)\n\n### Features\n\n- Addon-actions: Add depth option for serialization ([#6410](https://github.com/storybookjs/storybook/pull/6410))\n\n### Bug Fixes\n\n- Core: Respect webpack config stats in static build ([#6401](https://github.com/storybookjs/storybook/pull/6401))\n\n### Maintenance\n\n- Typescript: Migrate addon-options ([#6428](https://github.com/storybookjs/storybook/pull/6428))\n\n### Dependency Upgrades\n\n- Bump danger from 7.0.15 to 7.0.19 ([#6371](https://github.com/storybookjs/storybook/pull/6371))\n- Bump jest-cli from 23.6.0 to 24.0.0 ([#5389](https://github.com/storybookjs/storybook/pull/5389))\n\n## 5.1.0-alpha.21 (April 4, 2019)\n\n### Features\n\n- Addon-centered: Fix horizontal scrolling overflow ([#6361](https://github.com/storybookjs/storybook/pull/6361))\n- Angular: Support OnPush change detection for class-specified components ([#6360](https://github.com/storybookjs/storybook/pull/6360))\n- Addon-storysource: Reuse clientApi when possible ([#6154](https://github.com/storybookjs/storybook/pull/6154))\n\n### Bug Fixes\n\n- React-native: Fix backgrounds addon ([#6393](https://github.com/storybookjs/storybook/pull/6393))\n- UI: Fix 'read full changelog' link on about page ([#6385](https://github.com/storybookjs/storybook/pull/6385))\n- Addon-a11y: Fix addon initialization with 'makeDecorator' ([#6354](https://github.com/storybookjs/storybook/pull/6354))\n- Typescript: Fix a11y build by adding hoist-non-react-statics ([#6348](https://github.com/storybookjs/storybook/pull/6348))\n\n### Maintenance\n\n- Typescript: Use Babel instead of tsc ([#5109](https://github.com/storybookjs/storybook/pull/5109))\n\n## 5.0.6 (April 1, 2019)\n\n### Bug Fixes\n\n- Addon-a11y: Fix color-blindness emulation in Firefox ([#6297](https://github.com/storybookjs/storybook/pull/6297))\n- Addon-info: Fixed contrast of Show Info button for a11y ([#6301](https://github.com/storybookjs/storybook/pull/6301))\n- Addon-cssresources: Fix panel layout ([#6263](https://github.com/storybookjs/storybook/pull/6263))\n- Addon-info: forwardRef elements use displayName if available ([#6222](https://github.com/storybookjs/storybook/pull/6222))\n- UI: Set expanded stories to objects instead of arrays ([#6290](https://github.com/storybookjs/storybook/pull/6290))\n- Addon-actions: safe render for cyclic obj ([#6240](https://github.com/storybookjs/storybook/pull/6240))\n- Core: Upgrade @babel/preset-env to fix corejs option ([#6281](https://github.com/storybookjs/storybook/pull/6281))\n- Core: Enforces corejs v2 for babel ([#6267](https://github.com/storybookjs/storybook/pull/6267))\n- Knobs: Rename ALL panel to Other for ungrouped knobs ([#6232](https://github.com/storybookjs/storybook/pull/6232))\n\n## 5.1.0-alpha.20 (March 29, 2019)\n\n### Features\n\n- Addons: Manage local/session storage access with store2 ([#6310](https://github.com/storybookjs/storybook/pull/6310))\n\n### Bug Fixes\n\n- Addon-cssresources: Fix panel layout ([#6263](https://github.com/storybookjs/storybook/pull/6263))\n- Addon-info: Fixed contrast of Show Info button for a11y ([#6301](https://github.com/storybookjs/storybook/pull/6301))\n\n### Maintenance\n\n- Migrate options and decorators in examples to new api ([#5954](https://github.com/storybookjs/storybook/pull/5954))\n\n## 5.1.0-alpha.19 (March 28, 2019)\n\n### Bug Fixes\n\n- React-native: Fix \"lib/addons\" default export ([#6197](https://github.com/storybookjs/storybook/pull/6197))\n- Addon-a11y: Remove element styling after re-running the a11y rules ([#6325](https://github.com/storybookjs/storybook/pull/6325))\n- Addon-info: forwardRef elements use displayName if available ([#6222](https://github.com/storybookjs/storybook/pull/6222))\n- React-native: Add background color for stories panel ([#6315](https://github.com/storybookjs/storybook/pull/6315))\n\n### Dependency Upgrades\n\n- Upgrade babel-plugin-react-docgen ([#6329](https://github.com/storybookjs/storybook/pull/6329))\n- Bump babel-plugin-emotion from 10.0.7 to 10.0.9 ([#6227](https://github.com/storybookjs/storybook/pull/6227))\n- Bump @types/lodash.isequal from 4.5.3 to 4.5.5 ([#6269](https://github.com/storybookjs/storybook/pull/6269))\n- Bump react-scripts from 2.1.5 to 2.1.8 ([#6230](https://github.com/storybookjs/storybook/pull/6230))\n- Bump esm from 3.2.10 to 3.2.20 ([#6270](https://github.com/storybookjs/storybook/pull/6270))\n\n## 5.1.0-alpha.18 (March 27, 2019)\n\n### Bug Fixes\n\n- Addon-a11y: Fix color-blindness emulation in Firefox ([#6297](https://github.com/storybookjs/storybook/pull/6297))\n- UI: Set expanded stories to objects instead of arrays ([#6290](https://github.com/storybookjs/storybook/pull/6290))\n\n## 5.1.0-alpha.17 (March 26, 2019)\n\n### Bug Fixes\n\n- Addon-a11y: Move redux to dependencies ([#6286](https://github.com/storybookjs/storybook/pull/6286))\n\n## 5.1.0-alpha.16 (March 26, 2019)\n\n### Bug Fixes\n\n- Upgrade `@babel/preset-env` to fix corejs option ([#6281](https://github.com/storybookjs/storybook/pull/6281))\n\n## 5.1.0-alpha.15 (March 26, 2019)\n\n### Features\n\n- Addon-a11y: Highlight a11y violations on component ([#6218](https://github.com/storybookjs/storybook/pull/6218))\n- HTML: Allow forced renders in @storybook/html ([#6190](https://github.com/storybookjs/storybook/pull/6190))\n\n### Bug Fixes\n\n- Core: Enforces corejs v2 for babel ([#6267](https://github.com/storybookjs/storybook/pull/6267))\n- Knobs: Rename ALL panel to Other for ungrouped knobs ([#6232](https://github.com/storybookjs/storybook/pull/6232))\n- UI: zoom iframe content instead zoom iframe wrapper ([#6126](https://github.com/storybookjs/storybook/pull/6126))\n- Addon-actions: safe render for cyclic obj ([#6240](https://github.com/storybookjs/storybook/pull/6240))\n\n### Maintenance\n\n- Addon-knobs: adds an example of a boolean knob ([#6242](https://github.com/storybookjs/storybook/pull/6242))\n\n### Dependency Upgrades\n\n- Bump simplebar-react from 0.1.4 to 0.1.5 ([#6226](https://github.com/storybookjs/storybook/pull/6226))\n- FIX storybook having a incompatible version of webpack with vue-cli ([#6259](https://github.com/storybookjs/storybook/pull/6259))\n\n## 5.1.0-alpha.14 (March 25, 2019)\n\n### Features\n\n- Addon-backgrounds: Add custom grid size ([#6252](https://github.com/storybookjs/storybook/pull/6252))\n- Addon-viewport: Show active viewport dimensions & rotate button ([#6045](https://github.com/storybookjs/storybook/pull/6045))\n\n### Bug Fixes\n\n- UI: Use Fuse.js package for search ([#6244](https://github.com/storybookjs/storybook/pull/6244))\n- React: Use node-logger instead of console ([#6245](https://github.com/storybookjs/storybook/pull/6245))\n\n### Maintenance\n\n- Addon-links: Migrate to Typescript ([#6246](https://github.com/storybookjs/storybook/pull/6246))\n\n### Dependency Upgrades\n\n- Bump react-resize-detector from 4.0.2 to 4.0.5 ([#6229](https://github.com/storybookjs/storybook/pull/6229))\n\n## 5.0.5 (March 25, 2019)\n\nBump version number (same as 5.0.4, but need to make this `latest` again!)\n\n## 3.4.12 (March 24, 2019)\n\n### Bug Fixes\n\n- UI: Workaround broken treebeard animations ([#6249](https://github.com/storybookjs/storybook/pull/6249))\n\n## 5.0.4 (March 24, 2019)\n\n### Bug Fixes\n\n- UI: Fix tooltip event bindings, logger import ([#6238](https://github.com/storybookjs/storybook/pull/6238))\n- CLI: Fix stories regexp in config.js ([#6180](https://github.com/storybookjs/storybook/pull/6180))\n- Accessibility: Add missing button titles ([#6124](https://github.com/storybookjs/storybook/pull/6124))\n- React: Fix forked CRA support on Windows ([#6236](https://github.com/storybookjs/storybook/pull/6236))\n- Addon-knobs: Fix color type button z-index ([#6203](https://github.com/storybookjs/storybook/pull/6203))\n- Angular: Fix typo in demo example ([#6193](https://github.com/storybookjs/storybook/pull/6193))\n- Addon-Info: Restore fonts and color styling ([#6186](https://github.com/storybookjs/storybook/pull/6186))\n- Addon-knobs: Fix ObjectType knob react warning ([#6159](https://github.com/storybookjs/storybook/pull/6159))\n- Core: Add core-js as a dep to client-api ([#6209](https://github.com/storybookjs/storybook/pull/6209))\n- React: Fix logging in cra-config ([#6245](https://github.com/storybookjs/storybook/pull/6245))\n\n## 4.1.16 (March 24, 2019)\n\n### Bug Fixes\n\n- UI: Workaround broken treebeard animations ([#6249](https://github.com/storybookjs/storybook/pull/6249))\n\n## 4.1.15 (March 24, 2019)\n\nNPM publish failed\n\n## 5.1.0-alpha.13 (March 23, 2019)\n\n### Features\n\n- Svelte: add svelte cli generator ([#6132](https://github.com/storybookjs/storybook/pull/6132))\n\n### Bug Fixes\n\n- Addon-knobs: Fix ObjectType knob react warning ([#6159](https://github.com/storybookjs/storybook/pull/6159))\n- React: Fix forked CRA support on Windows ([#6236](https://github.com/storybookjs/storybook/pull/6236))\n- UI: Fix tooltip event bindings, logger import ([#6238](https://github.com/storybookjs/storybook/pull/6238))\n\n## 5.1.0-alpha.12 (March 22, 2019)\n\n### Bug Fixes\n\n- CLI: Fix stories regexp in config.js ([#6180](https://github.com/storybookjs/storybook/pull/6180))\n- Addon-Info: Restore fonts and color styling ([#6186](https://github.com/storybookjs/storybook/pull/6186))\n- Core: Add core-js as a dep to client-api ([#6209](https://github.com/storybookjs/storybook/pull/6209))\n\n### Dependency Upgrades\n\n- Bump eslint-plugin-jest from 22.3.2 to 22.4.1 ([#6168](https://github.com/storybookjs/storybook/pull/6168))\n- Bump ember-cli-babel from 7.5.0 to 7.6.0 ([#6165](https://github.com/storybookjs/storybook/pull/6165))\n- Bump danger from 7.0.14 to 7.0.15 ([#6164](https://github.com/storybookjs/storybook/pull/6164))\n- Bump babel-preset-expo from 5.0.0 to 5.1.1 ([#6167](https://github.com/storybookjs/storybook/pull/6167))\n- Bump @emotion/core from 10.0.7 to 10.0.9 ([#6169](https://github.com/storybookjs/storybook/pull/6169))\n- Bump marko from 4.15.4 to 4.16.2 ([#6205](https://github.com/storybookjs/storybook/pull/6205))\n\n## 5.1.0-alpha.11 (March 21, 2019)\n\n### Features\n\n- Addon-notes: Support theming ([#5922](https://github.com/storybookjs/storybook/pull/5922))\n\n### Bug Fixes\n\n- Addon-knobs: Fix color type button z-index ([#6203](https://github.com/storybookjs/storybook/pull/6203))\n- Angular: Fix typo in demo example ([#6193](https://github.com/storybookjs/storybook/pull/6193))\n- UI: Fix problem with selectedPanel reset ([#6149](https://github.com/storybookjs/storybook/pull/6149))\n\n### Maintenance\n\n- React-native: Publish crna-kitchen-sink app to expo ([#6183](https://github.com/storybookjs/storybook/pull/6183))\n\n## 5.1.0-alpha.10 (March 19, 2019)\n\n### Features\n\n- New @storybook/api manager API package ([#5402](https://github.com/storybookjs/storybook/pull/5402))\n\n### Bug Fixes\n\n- Angular: Fix rerender performance ([#6094](https://github.com/storybookjs/storybook/pull/6094))\n- React-native: Add the raw method to preview ([#6182](https://github.com/storybookjs/storybook/pull/6182))\n- Theming: Fix brandImage to occupy 100% width of BrandArea ([#5904](https://github.com/storybookjs/storybook/pull/5904))\n\n### Dependency Upgrades\n\n- Bump emotion-theming from 10.0.7 to 10.0.9 ([#6138](https://github.com/storybookjs/storybook/pull/6138))\n- Bump webpack-cli from 3.2.3 to 3.3.0 ([#6140](https://github.com/storybookjs/storybook/pull/6140))\n- Bump tslint from 5.13.1 to 5.14.0 ([#6141](https://github.com/storybookjs/storybook/pull/6141))\n- Bump ember-cli from 3.7.1 to 3.8.1 ([#6142](https://github.com/storybookjs/storybook/pull/6142))\n- Bump markdown-to-jsx from 6.9.1 to 6.9.3 ([#6139](https://github.com/storybookjs/storybook/pull/6139))\n\n## 5.0.3 (March 18, 2019)\n\n### Bug Fixes\n\n- Accessibility: Add missing button titles ([#6124](https://github.com/storybookjs/storybook/pull/6124))\n\n### Maintenance\n\n- UI: Make update notifications much less aggressive ([#6143](https://github.com/storybookjs/storybook/pull/6143))\n\n## 5.1.0-alpha.9 (March 18, 2019)\n\n### Maintenance\n\n- UI: Make update notifications much less aggressive ([#6143](https://github.com/storybookjs/storybook/pull/6143))\n\n## 5.1.0-alpha.8 (March 17, 2019)\n\n### Bug Fixes\n\n- Accessibility: Add aria label to search box ([#6131](https://github.com/storybookjs/storybook/pull/6131))\n- Accessibility: Add missing button titles ([#6124](https://github.com/storybookjs/storybook/pull/6124))\n- Addon-cssresources: Fix `STORY_RENDERED` CSS reset ([#6050](https://github.com/storybookjs/storybook/pull/6050))\n\n### Maintenance\n\n- React-native: Integrate crna-kitchen-sink example into monorepo ([#6125](https://github.com/storybookjs/storybook/pull/6125))\n- Fix deprecations in examples ([#6134](https://github.com/storybookjs/storybook/pull/6134))\n\n## 5.0.2 (March 17, 2019)\n\n### Features\n\n- CLI: Add --debug-webpack option ([#6082](https://github.com/storybookjs/storybook/pull/6082))\n\n### Bug Fixes\n\n- Addon-a11y: Fix design icons ([#5991](https://github.com/storybookjs/storybook/pull/5991))\n- Addon-cssresources: Fix `STORY_RENDERED` CSS reset ([#6050](https://github.com/storybookjs/storybook/pull/6050))\n- CLI: Clear build folder in static build ([#6024](https://github.com/storybookjs/storybook/pull/6024))\n- Addon-backgrounds: Set preview to theme color when \"transparent\" ([#6042](https://github.com/storybookjs/storybook/pull/6042))\n- UI: Fix search item in menu ([#6027](https://github.com/storybookjs/storybook/pull/6027))\n- Addon-knobs: Fix key press debouncing ([#6022](https://github.com/storybookjs/storybook/pull/6022))\n- CLI: Fix welcome component in dark theme ([#5998](https://github.com/storybookjs/storybook/pull/5998))\n- Addon-viewport: Fix viewport iframe dimensions ([#5993](https://github.com/storybookjs/storybook/pull/5993))\n- Core: fix selectStory with one parameter ([#5983](https://github.com/storybookjs/storybook/pull/5983))\n\n### Maintenance\n\n- Addon-viewport: Change styling to more closely match v4 ([#5979](https://github.com/storybookjs/storybook/pull/5979))\n\n## 5.1.0-alpha.7 (March 16, 2019)\n\n### Breaking Changes\n\n- Core: Restore v4 webpack extend mode behavior AND deprecate it ([#6104](https://github.com/storybookjs/storybook/pull/6104))\n- React native: Use @storybook/core ([#4942](https://github.com/storybookjs/storybook/pull/4942))\n\n### Features\n\n- CLI: Add --debug-webpack option ([#6082](https://github.com/storybookjs/storybook/pull/6082))\n- UI: open brandUrl in new window ([#6106](https://github.com/storybookjs/storybook/pull/6106))\n\n### Bug Fixes\n\n- CLI: Clear build folder in static build ([#6024](https://github.com/storybookjs/storybook/pull/6024))\n- Addon-a11y: Fix tab navigation ([#6118](https://github.com/storybookjs/storybook/pull/6118))\n- Theming: FIX brandImage when theme created with brandTitle ([#6120](https://github.com/storybookjs/storybook/pull/6120))\n- Addon-backgrounds: Set preview to theme color when \"transparent\" ([#6042](https://github.com/storybookjs/storybook/pull/6042))\n\n### Maintenance\n\n- Sort package.json on precommit ([#6101](https://github.com/storybookjs/storybook/pull/6101))\n\n### Dependency Upgrades\n\n- Use community AsyncStorage instead of deprecated React Native one ([#6079](https://github.com/storybookjs/storybook/pull/6079))\n- Fix expo ([#6121](https://github.com/storybookjs/storybook/pull/6121))\n- Bump graphiql from 0.12.0 to 0.13.0 ([#5901](https://github.com/storybookjs/storybook/pull/5901))\n- Update expo requirement from ^31.0.4 to ^32.0.6 in /examples-native/crna-kitchen-sink ([#5664](https://github.com/storybookjs/storybook/pull/5664))\n- Bump @angular/cli from 7.3.4 to 7.3.6 ([#6103](https://github.com/storybookjs/storybook/pull/6103))\n- Bump react-dom from 16.8.3 to 16.8.4 ([#5903](https://github.com/storybookjs/storybook/pull/5903))\n\n## 5.1.0-alpha.6 (March 14, 2019)\n\n### Features\n\n- Angular: add autoprefixing like angular-cli ([#5612](https://github.com/storybookjs/storybook/pull/5612))\n\n### Bug Fixes\n\n- UI: Fixing search item in menu ([#6027](https://github.com/storybookjs/storybook/pull/6027))\n- Addon-a11y: Run only when a11y tab is active ([#6044](https://github.com/storybookjs/storybook/pull/6044))\n\n### Maintenance\n\n- UI: Update syntaxhighlighter stories ([#6054](https://github.com/storybookjs/storybook/pull/6054))\n\n## 5.1.0-alpha.5 (March 12, 2019)\n\n### Bug Fixes\n\n- Addon-a11y: Remove bg color from reports ([#6026](https://github.com/storybookjs/storybook/pull/6026))\n- Addon-knobs: Fix key press debouncing ([#6022](https://github.com/storybookjs/storybook/pull/6022))\n- Addon-knobs: Fix error when removing value from number knob ([#6043](https://github.com/storybookjs/storybook/pull/6043))\n\n### Maintenance\n\n- Theming: Improve typescript typings ([#5988](https://github.com/storybookjs/storybook/pull/5988))\n\n### Dependency Upgrades\n\n- build(deps): bump axe-core from 3.2.0 to 3.2.2 ([#6034](https://github.com/storybookjs/storybook/pull/6034))\n- build(deps): bump css-loader from 2.1.0 to 2.1.1 ([#6033](https://github.com/storybookjs/storybook/pull/6033))\n- build(deps): bump react-focus-lock from 1.17.7 to 1.18.3 ([#6031](https://github.com/storybookjs/storybook/pull/6031))\n- Bump react-resize-detector from 3.4.0 to 4.0.2 ([#5899](https://github.com/storybookjs/storybook/pull/5899))\n\n## 5.1.0-alpha.4 (March 11, 2019)\n\n### Bug Fixes\n\n- CLI: Fix welcome component in dark theme ([#5998](https://github.com/storybookjs/storybook/pull/5998))\n- Polymer: Fix re-rendering lit-html elements after non-lit-html element ([#5868](https://github.com/storybookjs/storybook/pull/5868))\n- Addon-a11y: Fix respect 'element' arg in config ([#5996](https://github.com/storybookjs/storybook/pull/5996))\n- Addon-a11y: Fix design icons ([#5991](https://github.com/storybookjs/storybook/pull/5991))\n- Addon-viewport: Fix viewport iframe dimensions ([#5993](https://github.com/storybookjs/storybook/pull/5993))\n\n### Maintenance\n\n- ADD parameters to compile-js to no longer copy .ts files into dist ([#5844](https://github.com/storybookjs/storybook/pull/5844))\n\n### Dependency Upgrades\n\n- build(deps): bump react-is from 16.8.3 to 16.8.4 ([#6010](https://github.com/storybookjs/storybook/pull/6010))\n- build(deps): bump react-dev-utils from 7.0.3 to 8.0.0 ([#6011](https://github.com/storybookjs/storybook/pull/6011))\n\n## 5.1.0-alpha.3 (March 9, 2019)\n\n### Features\n\n- Addon-a11y: add 'incomplete' tab ([#5984](https://github.com/storybookjs/storybook/pull/5984))\n\n### Bug Fixes\n\n- Core: fix `selectStory` with one parameter ([#5983](https://github.com/storybookjs/storybook/pull/5983))\n- Core: remove custom presets warning ([#5911](https://github.com/storybookjs/storybook/pull/5911))\n\n### Maintenance\n\n- Addon-viewport: Change styling to more closely match v4 ([#5979](https://github.com/storybookjs/storybook/pull/5979))\n\n### Dependency Upgrades\n\n- Bump babel-preset-react-app from 7.0.1 to 7.0.2 ([#5937](https://github.com/storybookjs/storybook/pull/5937))\n- Bump ts-node from 8.0.2 to 8.0.3 ([#5938](https://github.com/storybookjs/storybook/pull/5938))\n- Bump react from 16.8.3 to 16.8.4 ([#5902](https://github.com/storybookjs/storybook/pull/5902))\n- Bump marko from 4.15.3 to 4.15.4 ([#5939](https://github.com/storybookjs/storybook/pull/5939))\n\n### Bug Fixes\n\n- Addon-a11y: Fix design icons ([#5991](https://github.com/storybookjs/storybook/pull/5991))\n- Addon-cssresources: Fix `STORY_RENDERED` CSS reset ([#6050](https://github.com/storybookjs/storybook/pull/6050))\n- CLI: Clear build folder in static build ([#6024](https://github.com/storybookjs/storybook/pull/6024))\n- Addon-backgrounds: Set preview to theme color when \"transparent\" ([#6042](https://github.com/storybookjs/storybook/pull/6042))\n- UI: Fix search item in menu ([#6027](https://github.com/storybookjs/storybook/pull/6027))\n- Addon-knobs: Fix key press debouncing ([#6022](https://github.com/storybookjs/storybook/pull/6022))\n- CLI: Fix welcome component in dark theme ([#5998](https://github.com/storybookjs/storybook/pull/5998))\n- Addon-viewport: Fix viewport iframe dimensions ([#5993](https://github.com/storybookjs/storybook/pull/5993))\n- Core: fix selectStory with one parameter ([#5983](https://github.com/storybookjs/storybook/pull/5983))\n\n### Maintenance\n\n- Addon-viewport: Change styling to more closely match v4 ([#5979](https://github.com/storybookjs/storybook/pull/5979))\n\n## 5.0.1 (March 9, 2019)\n\n### Bug Fixes\n\n- Core: Remove custom presets warning ([#5911](https://github.com/storybookjs/storybook/pull/5911))\n- Core: support unicode chars in story IDs ([#5964](https://github.com/storybookjs/storybook/pull/5964))\n- Core: Add core-js dependencies where it was missing ([#5961](https://github.com/storybookjs/storybook/pull/5961))\n- CLI: Fix missing iframe.html in absolute path output directory([#5947](https://github.com/storybookjs/storybook/pull/5947))\n- Addon-knobs: Added debouncing between keystrokes to speed up component rendering ([#5811](https://github.com/storybookjs/storybook/pull/5811))\n- UI: Fix search in production mode ([#5909](https://github.com/storybookjs/storybook/pull/5909))\n\n## 4.1.14 (March 8, 2019)\n\n### Dependency Upgrades\n\n- React-native: Fix RN 0.58.5 / support 0.59 via react-native-modal-datetime-picker 6.0.0 ([#4425](https://github.com/storybookjs/storybook/pull/4425))\n\n## 5.1.0-alpha.2 (March 8, 2019)\n\n### Bug Fixes\n\n- Core: support unicode chars in story IDs ([#5964](https://github.com/storybookjs/storybook/pull/5964))\n- Core: Add core-js dependencies where it was missing ([#5961](https://github.com/storybookjs/storybook/pull/5961))\n\n### Maintenance\n\n- Addon-a11y: Migrate to typescript ([#5738](https://github.com/storybookjs/storybook/pull/5738))\n\n## 5.1.0-alpha.1 (March 7, 2019)\n\n### Bug Fixes\n\n- CLI: Fix missing iframe.html in absolute path output directory ([#5947](https://github.com/storybookjs/storybook/pull/5947))\n- Addon-knobs: Added debouncing between keystrokes to speed up component rendering ([#5811](https://github.com/storybookjs/storybook/pull/5811))\n- UI: Fix search in production mode ([#5909](https://github.com/storybookjs/storybook/pull/5909))\n\n### Maintenance\n\n- ADD delay to rendering the acceptance stories ([#5943](https://github.com/storybookjs/storybook/pull/5943))\n- Split versions.json into two files ([#5896](https://github.com/storybookjs/storybook/pull/5896))\n\n## 5.1.0-alpha.0 (March 6, 2019)\n\n### Features\n\n- UI: Custom scrollbars ([#5714](https://github.com/storybookjs/storybook/pull/5714))\n\n### Bug Fixes\n\n- Fix: Move `react-select` dependency to 2.2 ([#5867](https://github.com/storybookjs/storybook/pull/5867))\n\n### Maintenance\n\n- Cleanup unused dependencies ([#5453](https://github.com/storybookjs/storybook/pull/5453))\n- Add directory attribute to repositories in package.json files ([#5643](https://github.com/storybookjs/storybook/pull/5643))\n\n### Dependency Upgrades\n\n- Project-wide dependency upgrades ([#5740](https://github.com/storybookjs/storybook/pull/5740))\n- Bump react-is from 16.8.1 to 16.8.3 ([#5743](https://github.com/storybookjs/storybook/pull/5743))\n- Bump danger from 7.0.13 to 7.0.14 ([#5744](https://github.com/storybookjs/storybook/pull/5744))\n- Bump babel-plugin-named-asset-import from 0.3.0 to 0.3.1 ([#5745](https://github.com/storybookjs/storybook/pull/5745))\n- Bump eslint-plugin-json from 1.3.2 to 1.4.0 ([#5719](https://github.com/storybookjs/storybook/pull/5719))\n- Bump react-native-modal-datetime-picker from 5.1.0 to 6.0.0 ([#4425](https://github.com/storybookjs/storybook/pull/4425))\n- Bump immer from 1.12.0 to 2.0.0 ([#5694](https://github.com/storybookjs/storybook/pull/5694))\n- Bump danger from 7.0.11 to 7.0.13 ([#5696](https://github.com/storybookjs/storybook/pull/5696))\n- Bump eslint-plugin-jsx-a11y from 6.2.0 to 6.2.1 ([#5698](https://github.com/storybookjs/storybook/pull/5698))\n- Bump @angular/platform-browser-dynamic from 7.2.4 to 7.2.6 ([#5697](https://github.com/storybookjs/storybook/pull/5697))\n- Bump eslint from 5.12.1 to 5.14.1 ([#5653](https://github.com/storybookjs/storybook/pull/5653))\n- Bump babel-preset-react-app from 7.0.0 to 7.0.1 ([#5674](https://github.com/storybookjs/storybook/pull/5674))\n- Bump react from 16.8.1 to 16.8.2 ([#5673](https://github.com/storybookjs/storybook/pull/5673))\n- Bump @angular/cli from 7.3.0 to 7.3.2 ([#5654](https://github.com/storybookjs/storybook/pull/5654))\n- Bump @types/jest from 24.0.0 to 24.0.6 ([#5655](https://github.com/storybookjs/storybook/pull/5655))\n- Bump lint-staged from 8.1.3 to 8.1.4 ([#5606](https://github.com/storybookjs/storybook/pull/5606))\n- Bump @types/lodash from 4.14.120 to 4.14.121 ([#5609](https://github.com/storybookjs/storybook/pull/5609))\n- Bump webpack from 4.29.0 to 4.29.3 ([#5570](https://github.com/storybookjs/storybook/pull/5570))\n- update modal manager for rn 0.58 support ([#5581](https://github.com/storybookjs/storybook/pull/5581))\n- Bump danger from 7.0.7 to 7.0.11 ([#5568](https://github.com/storybookjs/storybook/pull/5568))\n- Bump jest-jasmine2 from 24.0.0 to 24.1.0 ([#5569](https://github.com/storybookjs/storybook/pull/5569))\n- Bump jest-jasmine2 from 24.0.0 to 24.1.0 ([#5567](https://github.com/storybookjs/storybook/pull/5567))\n- Bump handlebars from 4.0.12 to 4.1.0 ([#5576](https://github.com/storybookjs/storybook/pull/5576))\n- Bump esm from 3.2.1 to 3.2.4 ([#5556](https://github.com/storybookjs/storybook/pull/5556))\n- Bump @types/jest from 23.3.13 to 24.0.0 ([#5554](https://github.com/storybookjs/storybook/pull/5554))\n- Bump webpack-dev-middleware from 3.5.1 to 3.5.2 ([#5552](https://github.com/storybookjs/storybook/pull/5552))\n- Bump @emotion/core from 10.0.6 to 10.0.7 ([#5555](https://github.com/storybookjs/storybook/pull/5555))\n- Bump terser-webpack-plugin from 1.2.1 to 1.2.2 ([#5553](https://github.com/storybookjs/storybook/pull/5553))\n- Bump fuse.js from 3.3.1 to 3.4.2 ([#5538](https://github.com/storybookjs/storybook/pull/5538))\n- Bump @angular/platform-browser-dynamic from 7.2.3 to 7.2.4 ([#5540](https://github.com/storybookjs/storybook/pull/5540))\n- Bump emotion-theming from 10.0.6 to 10.0.7 ([#5541](https://github.com/storybookjs/storybook/pull/5541))\n- Bump eslint-config-prettier from 3.6.0 to 4.0.0 ([#5539](https://github.com/storybookjs/storybook/pull/5539))\n\n## 5.0.0 (March 5, 2019)\n\nStorybook 5.0 is a completely new UI with the following improvements:\n\n- 🌓 New design with light and dark themes\n- 🛠 Canvas toolbar for easy access to addons\n- 🗺 Overhauled navigation sidebar with an intuitive menu\n- 🗜 Redesigned addons panel with handy buttons to toggle visibility and orientation\n- ⌨️ Improved keyboard shortcuts that are user configurable\n- 🌍 New URL structure that eliminates long strings of query parameters\n\n  5.0 contains hundreds more fixes, features, and tweaks. Browse the changelogs matching `5.0.0-alpha.*`, `5.0.0-beta.*`, and `5.0.0-rc.*` for the full list of changes. See [MIGRATION.md](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md) to upgrade from `4.x`.\n\n## 5.0.0-rc.11 (March 5, 2019)\n\n### Bug Fixes\n\n- UI: Fix base theme initialization and theme bootup ([#5843](https://github.com/storybookjs/storybook/pull/5843))\n- UI: Fix SidebarItem feels \"laggy\" when clicked ([#5850](https://github.com/storybookjs/storybook/pull/5850))\n\n## 5.0.0-rc.10 (March 4, 2019)\n\n### Bug Fixes\n\n- Addon-viewports: Restore v4 behaviour ([#5829](https://github.com/storybookjs/storybook/pull/5829))\n- Addon-backgrounds: Remove previously deprecated default export ([#5828](https://github.com/storybookjs/storybook/pull/5828))\n\n### Maintenance\n\n- Addon-a11y: Cleanup and document migration ([#5833](https://github.com/storybookjs/storybook/pull/5833))\n\n## 5.0.0-rc.9 (March 3, 2019)\n\n### Features\n\n- Core: Allow local decorators via params ([#5806](https://github.com/storybookjs/storybook/pull/5806))\n\n### Bug Fixes\n\n- Core: Add warning for decorators added \"mid-kind\" ([#5819](https://github.com/storybookjs/storybook/pull/5819))\n- Addon-notes: Support inline code markdown ([#5802](https://github.com/storybookjs/storybook/pull/5802))\n- Theming: Fix theme loading bugs ([#5787](https://github.com/storybookjs/storybook/pull/5787))\n- CLI: Fix build-storybook with simplebar esm files ([#5816](https://github.com/storybookjs/storybook/pull/5816))\n\n## 5.0.0-rc.8 (March 1, 2019)\n\n### Features\n\n- Core: Allow local decorators via params ([#5806](https://github.com/storybookjs/storybook/pull/5806))\n\n### Bug Fixes\n\n- UI: Sort storiesHash so grouped keys appear together ([#5805](https://github.com/storybookjs/storybook/pull/5805))\n- UI: Close tooltips on iframe clicks on keypresses ([#5807](https://github.com/storybookjs/storybook/pull/5807))\n- Addon-Info: Add font family to info panel ([#5759](https://github.com/storybookjs/storybook/pull/5759))\n\n## 5.0.0-rc.7 (February 28, 2019)\n\n### Features\n\n- UI: Page load animation and `STORIES_CONFIGURED` event ([#5756](https://github.com/storybookjs/storybook/pull/5756))\n- Theming: Improve `brand` API ([#5733](https://github.com/storybookjs/storybook/pull/5733))\n- UI: Fuzzy search improvement ([#5748](https://github.com/storybookjs/storybook/pull/5748))\n- UI: Add toolbar animation ([#5742](https://github.com/storybookjs/storybook/pull/5742))\n\n### Bug Fixes\n\n- UI: Fix update notifications placement ([#5716](https://github.com/storybookjs/storybook/pull/5716))\n- Angular: Fix global style imports ([#5776](https://github.com/storybookjs/storybook/pull/5776))\n- Addon-options: Add backwards compatibility ([#5758](https://github.com/storybookjs/storybook/pull/5758))\n- Addon-options: Fix deprecated url/name options ([#5773](https://github.com/storybookjs/storybook/pull/5773))\n- Addon-knobs: Remove call to `forceReRender()` on `STORY_CHANGED` ([#5753](https://github.com/storybookjs/storybook/pull/5753))\n- UI: Fix active state in addon-background, addon-viewport tools ([#5749](https://github.com/storybookjs/storybook/pull/5749))\n\n## 5.0.0-rc.6 (February 25, 2019)\n\n### Bug Fixes\n\n- Addon-actions: FIX performance by upgrading to telejson 2.1 ([#5751](https://github.com/storybookjs/storybook/pull/5751))\n- UI: FIX bad treeview mockdata ([#5741](https://github.com/storybookjs/storybook/pull/5741))\n- UI: About page styling fixes ([#5732](https://github.com/storybookjs/storybook/pull/5732))\n- UI: Restore the toolbar eject button ([#5737](https://github.com/storybookjs/storybook/pull/5737))\n\n## 5.0.0-rc.5 (February 23, 2019)\n\n### Bug Fixes\n\n- UI: Fix `/` search hotkey so it doesn't type into the input ([#5702](https://github.com/storybookjs/storybook/pull/5702))\n- Addon-a11y: Fix a11y setup being undefined ([#5724](https://github.com/storybookjs/storybook/pull/5724))\n- UI: Fix duplicate theming packages ([#5722](https://github.com/storybookjs/storybook/pull/5722))\n- Core: Clean up debug logging ([#5705](https://github.com/storybookjs/storybook/pull/5705))\n- UI: Minor addon ux tweaks ([#5712](https://github.com/storybookjs/storybook/pull/5712))\n- Addon-a11y: Fix story scrolling ([#5713](https://github.com/storybookjs/storybook/pull/5713))\n- UI: Fix mobile styling ([#5709](https://github.com/storybookjs/storybook/pull/5709))\n- UI: Fix tooltip bugs ([#5692](https://github.com/storybookjs/storybook/pull/5692))\n- UI: Fix toolbar separators ([#5711](https://github.com/storybookjs/storybook/pull/5711))\n\n### Maintenance\n\n- Typescript: migrate addon-backgrounds ([#5535](https://github.com/storybookjs/storybook/pull/5535))\n- Typescript: fix typings for addon-backgrounds ([#5730](https://github.com/storybookjs/storybook/pull/5730))\n\n## 5.0.0-rc.4 (February 21, 2019)\n\n### Features\n\n- UI: Handle prerelease versions in version check ([#5641](https://github.com/storybookjs/storybook/pull/5641))\n\n### Bug Fixes\n\n- UI: Fix scrollbar persistence ([#5689](https://github.com/storybookjs/storybook/pull/5689))\n- UI: Fix keyboard shortcuts of toggleNav & togglePanel ([#5677](https://github.com/storybookjs/storybook/pull/5677))\n- Core: Fix singleton module issue for manager & theme ([#5679](https://github.com/storybookjs/storybook/pull/5679))\n- Addon-storysource: Fix source not updating ([#5672](https://github.com/storybookjs/storybook/pull/5672))\n- Core: Fix broken error reporting ([#5678](https://github.com/storybookjs/storybook/pull/5678))\n- Addon-info: Compare component name to story name, not story fn ([#5649](https://github.com/storybookjs/storybook/pull/5649))\n\n### Maintenance\n\n- CLI: Cleanup version notice ([#5699](https://github.com/storybookjs/storybook/pull/5699))\n- Core: Fix story fn consistency ([#5669](https://github.com/storybookjs/storybook/pull/5669))\n\n## 4.1.13 (February 21, 2019)\n\n### Maintenance\n\n- CLI: Cleanup version notice ([#5699](https://github.com/storybookjs/storybook/pull/5699))\n- Docs: Use static versions.json file instead of hacking one in ([#5675](https://github.com/storybookjs/storybook/pull/5675))\n\n## 5.0.0-rc.3 (February 19, 2019)\n\n### Bug Fixes\n\n- UI: Styling bug fixes, story updates, and more QA ([#5650](https://github.com/storybookjs/storybook/pull/5650))\n- UI: V5 style refinements ([#5562](https://github.com/storybookjs/storybook/pull/5562))\n\n## 5.0.0-rc.2 (February 19, 2019)\n\n### Features\n\n- UI: Allow collapsing active story and use separate expansion for filtered ([#5625](https://github.com/storybookjs/storybook/pull/5625))\n- UI: Handle prerelease versions in version check ([#5641](https://github.com/storybookjs/storybook/pull/5641))\n\n### Bug Fixes\n\n- Addon-a11y: Fix tab highlighting ([#5646](https://github.com/storybookjs/storybook/pull/5646))\n- Addon-jest: Fix event subscription ([#5644](https://github.com/storybookjs/storybook/pull/5644))\n- UI: Handle old versions in version check ([#5638](https://github.com/storybookjs/storybook/pull/5638))\n\n### Maintenance\n\n- UI: Fix some prop warnings ([#5635](https://github.com/storybookjs/storybook/pull/5635))\n- UI: Use the correct props to start the tooltip open ([#5610](https://github.com/storybookjs/storybook/pull/5610))\n\n## 4.1.12 (February 18, 2019)\n\n### Bug Fixes\n\n- Addon-google-analytics: Add missing `register.js` file ([#5379](https://github.com/storybookjs/storybook/pull/5379))\n\n### Dependency Upgrades\n\n- Update modal manager for rn 0.58 support ([#5581](https://github.com/storybookjs/storybook/pull/5581))\n\n## 5.0.0-rc.1 (February 16, 2019)\n\n### Bug Fixes\n\n- Core: Add missing babel-preset-env dependency ([#5617](https://github.com/storybookjs/storybook/pull/5617))\n\n## 5.0.0-rc.0 (February 16, 2019)\n\nWelcome to Storybook 5 (SB5) with a beautiful new user interface including:\n\n- Navigation sidebar redesign\n- New canvas toolbar\n- Customizable keyboard shortcuts\n- Improved search\n- Version update notifications\n\nSB5 also includes a new URL structure, expanded addon API, and many more features and architectural improvements.\n\nSee [the RC announcement](https://gist.github.com/shilman/0332090b63f1798a58ed8d85db44f4b4) for more details!\n\n## 5.0.0-beta.4 (February 15, 2019)\n\n### Bug Fixes\n\n- UI: Fix mobile view ([#5603](https://github.com/storybookjs/storybook/pull/5603))\n- UI: Misc warning fixes ([#5601](https://github.com/storybookjs/storybook/pull/5601))\n- UI: Fix ie 11 ([#5599](https://github.com/storybookjs/storybook/pull/5599))\n- CLI: Fix for when outputDir is an absolute path ([#5573](https://github.com/storybookjs/storybook/pull/5573))\n- CLI: Avoid false-negative checks for port ([#5565](https://github.com/storybookjs/storybook/pull/5565))\n- Core: Prioritise programmatic configuration ([#5564](https://github.com/storybookjs/storybook/pull/5564))\n- UI: FIX clear search ([#5550](https://github.com/storybookjs/storybook/pull/5550))\n- Core: Transpile safe-eval package ([#5498](https://github.com/storybookjs/storybook/pull/5498))\n- UI: Add default backgrounds to official example ([#5585](https://github.com/storybookjs/storybook/pull/5585))\n\n## 5.0.0-beta.3 (February 13, 2019)\n\n### Bug Fixes\n\n- UI: V5 styling refinements ([#5562](https://github.com/storybookjs/storybook/pull/5562))\n\n## 5.0.0-beta.2 (February 9, 2019)\n\n### Features\n\n- Storyshots: puppeteer launch config for CI ([#5487](https://github.com/storybookjs/storybook/pull/5487))\n\n### Bug Fixes\n\n- Addon-notes: fix loading behavior ([#5514](https://github.com/storybookjs/storybook/pull/5514))\n- CLI: Workaround -h shorthand conflict ([#5464](https://github.com/storybookjs/storybook/pull/5464))\n- Addons: remove tool addon styling ([#5452](https://github.com/storybookjs/storybook/pull/5452))\n\n### Maintenance\n\n- UI: V5 style refinements ([#5444](https://github.com/storybookjs/storybook/pull/5444))\n- Core: Allow ignoring preview bundle building in core ([#5523](https://github.com/storybookjs/storybook/pull/5523))\n- Core: Extract client-api pkg from core ([#5521](https://github.com/storybookjs/storybook/pull/5521))\n- UI: Add react element hoisting && ADD display names via babel-plugin ([#5454](https://github.com/storybookjs/storybook/pull/5454))\n- Build: TEMP disable the image snapshots ([#5469](https://github.com/storybookjs/storybook/pull/5469))\n\n### Dependency Upgrades\n\n- Bump vue and vue-template-compiler ([#5516](https://github.com/storybookjs/storybook/pull/5516))\n- Bump react from 16.7.0 to 16.8.1 ([#5517](https://github.com/storybookjs/storybook/pull/5517))\n- Bump react-is from 16.7.0 to 16.8.1 ([#5504](https://github.com/storybookjs/storybook/pull/5504))\n- Bump eslint-plugin-jest from 22.2.1 to 22.2.2 ([#5505](https://github.com/storybookjs/storybook/pull/5505))\n- Bump babel-plugin-emotion from 10.0.6 to 10.0.7 ([#5502](https://github.com/storybookjs/storybook/pull/5502))\n- Bump ember-source from 3.7.2 to 3.7.3 ([#5501](https://github.com/storybookjs/storybook/pull/5501))\n- Bump lint-staged from 8.1.1 to 8.1.3 ([#5503](https://github.com/storybookjs/storybook/pull/5503))\n- Bump enzyme-adapter-react-16 from 1.9.0 to 1.9.1 ([#5507](https://github.com/storybookjs/storybook/pull/5507))\n- dependencies: update lit-html to 1.0.0 ([#5490](https://github.com/storybookjs/storybook/pull/5490))\n- Bump esm from 3.2.0 to 3.2.1 ([#5492](https://github.com/storybookjs/storybook/pull/5492))\n- Bump webpack-cli from 3.2.1 to 3.2.3 ([#5494](https://github.com/storybookjs/storybook/pull/5494))\n- Bump @babel/plugin-proposal-object-rest-spread from 7.3.1 to 7.3.2 ([#5496](https://github.com/storybookjs/storybook/pull/5496))\n- Bump fuse.js from 3.3.0 to 3.3.1 ([#5497](https://github.com/storybookjs/storybook/pull/5497))\n- Bump jest-emotion from 10.0.6 to 10.0.7 ([#5495](https://github.com/storybookjs/storybook/pull/5495))\n- Bump prettier from 1.16.1 to 1.16.4 ([#5482](https://github.com/storybookjs/storybook/pull/5482))\n- Bump @types/webpack-env from 1.13.6 to 1.13.7 ([#5477](https://github.com/storybookjs/storybook/pull/5477))\n- Bump typescript from 3.2.4 to 3.3.1 ([#5479](https://github.com/storybookjs/storybook/pull/5479))\n- Bump eslint-plugin-import from 2.15.0 to 2.16.0 ([#5480](https://github.com/storybookjs/storybook/pull/5480))\n- Bump storybook-chromatic from 1.2.5 to 1.2.6 ([#5481](https://github.com/storybookjs/storybook/pull/5481))\n- Bump enzyme-adapter-react-16 from 1.8.0 to 1.9.0 ([#5478](https://github.com/storybookjs/storybook/pull/5478))\n- Bump markdown-to-jsx from 6.9.0 to 6.9.1 ([#5465](https://github.com/storybookjs/storybook/pull/5465))\n- Bump @angular/compiler from 7.2.2 to 7.2.3 ([#5466](https://github.com/storybookjs/storybook/pull/5466))\n- Bump babel-plugin-react-docgen from 2.0.0 to 2.0.2 ([#5468](https://github.com/storybookjs/storybook/pull/5468))\n- Bump danger from 7.0.4 to 7.0.7 ([#5467](https://github.com/storybookjs/storybook/pull/5467))\n- Bump puppeteer from 1.11.0 to 1.12.0 ([#5450](https://github.com/storybookjs/storybook/pull/5450))\n- Bump @angular/platform-browser-dynamic from 7.2.2 to 7.2.3 ([#5434](https://github.com/storybookjs/storybook/pull/5434))\n- Bump esm from 3.1.4 to 3.2.0 ([#5447](https://github.com/storybookjs/storybook/pull/5447))\n- Bump eslint-plugin-jest from 22.1.3 to 22.2.1 ([#5448](https://github.com/storybookjs/storybook/pull/5448))\n- Bump danger from 7.0.2 to 7.0.4 ([#5449](https://github.com/storybookjs/storybook/pull/5449))\n- Bump case-sensitive-paths-webpack-plugin from 2.1.2 to 2.2.0 ([#5451](https://github.com/storybookjs/storybook/pull/5451))\n\n## 5.0.0-beta.1 (February 1, 2019)\n\n### Bug Fixes\n\n- Addon-backgrounds: Fix tool not appearing, or appearing only after a few navigations ([#5439](https://github.com/storybookjs/storybook/pull/5439))\n\n### Maintenance\n\n- UI:Added iframe stories ([#5428](https://github.com/storybookjs/storybook/pull/5428))\n- UI: Broke up Sidebar (ex-nav) and made stories for subcomponents ([#5426](https://github.com/storybookjs/storybook/pull/5426))\n- UI: Improve about/shortcuts stories by passing in `onClose` as a prop. ([#5425](https://github.com/storybookjs/storybook/pull/5425))\n\n## 5.0.0-beta.0 (February 1, 2019)\n\nFailed release\n\n## 5.0.0-alpha.11 (February 1, 2019)\n\n### Features\n\n- Addon-knobs: Added property name into form fields ([#5414](https://github.com/storybookjs/storybook/pull/5414))\n\n### Bug Fixes\n\n- UI: Fix the layout issue where panels still sort-of appear on non story viewmodes ([#5413](https://github.com/storybookjs/storybook/pull/5413))\n\n### Maintenance\n\n- UI: Refactoring components and adding more stories ([#5404](https://github.com/storybookjs/storybook/pull/5404))\n- UI: Add extra stories for StoryExplorer component & subcomponents ([#5424](https://github.com/storybookjs/storybook/pull/5424))\n- UI: theming treeview & preview ([#5372](https://github.com/storybookjs/storybook/pull/5372))\n\n### Dependency Upgrades\n\n- Bump @ngrx/store from 7.1.0 to 7.2.0 ([#5433](https://github.com/storybookjs/storybook/pull/5433))\n- Bump @angular/cli from 7.2.2 to 7.3.0 ([#5432](https://github.com/storybookjs/storybook/pull/5432))\n- Bump ember-cli-babel from 7.4.0 to 7.4.1 ([#5431](https://github.com/storybookjs/storybook/pull/5431))\n- Bump @ember/test-helpers from 1.3.0 to 1.3.1 ([#5430](https://github.com/storybookjs/storybook/pull/5430))\n- Bump jest-diff from 23.6.0 to 24.0.0 ([#5429](https://github.com/storybookjs/storybook/pull/5429))\n- Bump @types/react from 16.7.21 to 16.7.22 ([#5405](https://github.com/storybookjs/storybook/pull/5405))\n- Bump @types/node from 10.12.18 to 10.12.19 ([#5406](https://github.com/storybookjs/storybook/pull/5406))\n- Bump autoprefixer from 9.4.6 to 9.4.7 ([#5407](https://github.com/storybookjs/storybook/pull/5407))\n- Bump storybook-chromatic from 1.2.4 to 1.2.5 ([#5408](https://github.com/storybookjs/storybook/pull/5408))\n- Bump rxjs-compat from 6.3.3 to 6.4.0 ([#5409](https://github.com/storybookjs/storybook/pull/5409))\n- Bump jest-config from 23.6.0 to 24.0.0 ([#5410](https://github.com/storybookjs/storybook/pull/5410))\n- Bump jest-environment-jsdom from 23.4.0 to 24.0.0 ([#5398](https://github.com/storybookjs/storybook/pull/5398))\n- Bump lint-staged from 8.1.0 to 8.1.1 ([#5395](https://github.com/storybookjs/storybook/pull/5395))\n- Bump ts-node from 8.0.1 to 8.0.2 ([#5396](https://github.com/storybookjs/storybook/pull/5396))\n- Bump @angular/compiler from 7.2.1 to 7.2.2 ([#5394](https://github.com/storybookjs/storybook/pull/5394))\n- Bump eslint-plugin-jsx-a11y from 6.1.2 to 6.2.0 ([#5397](https://github.com/storybookjs/storybook/pull/5397))\n- Bump telejson from 1.0.0 to 1.0.1 ([#5399](https://github.com/storybookjs/storybook/pull/5399))\n- Bump @ember/test-helpers from 1.1.0 to 1.3.0 ([#5383](https://github.com/storybookjs/storybook/pull/5383))\n- Bump esm from 3.1.1 to 3.1.4 ([#5384](https://github.com/storybookjs/storybook/pull/5384))\n- Bump ws from 6.1.2 to 6.1.3 ([#5385](https://github.com/storybookjs/storybook/pull/5385))\n- Bump jest-jasmine2 from 23.6.0 to 24.0.0 ([#5386](https://github.com/storybookjs/storybook/pull/5386))\n- Bump vue-loader from 15.6.0 to 15.6.2 ([#5387](https://github.com/storybookjs/storybook/pull/5387))\n- Bump @types/react from 16.7.20 to 16.7.21 ([#5388](https://github.com/storybookjs/storybook/pull/5388))\n\n## 5.0.0-alpha.10 (January 28, 2019)\n\n### Features\n\n- Core: Version update use persistence ([#5370](https://github.com/storybookjs/storybook/pull/5370))\n- Addon-Notes: Add giphy support ([#5381](https://github.com/storybookjs/storybook/pull/5381))\n\n### Bug Fixes\n\n- UI: Fix issue where \"Tab\" keyboard input => []. ([#5374](https://github.com/storybookjs/storybook/pull/5374))\n- UI: FIX keybindings were pointing to null events ([#5375](https://github.com/storybookjs/storybook/pull/5375))\n- Addon-GA: Add missing `register.js` file in base directory ([#5379](https://github.com/storybookjs/storybook/pull/5379))\n\n### Maintenance\n\n- Typescript: Migrate addon-cssresources ([#5380](https://github.com/storybookjs/storybook/pull/5380))\n- UI: Keyboard shortcuts refactor ([#5359](https://github.com/storybookjs/storybook/pull/5359))\n\n### Dependency Upgrades\n\n- Bump enzyme-adapter-react-16 from 1.7.1 to 1.8.0 ([#5366](https://github.com/storybookjs/storybook/pull/5366))\n- Bump typescript from 3.2.2 to 3.2.4 ([#5368](https://github.com/storybookjs/storybook/pull/5368))\n- Bump @babel/plugin-transform-react-jsx from 7.2.0 to 7.3.0 ([#5367](https://github.com/storybookjs/storybook/pull/5367))\n- Bump @babel/preset-env from 7.2.3 to 7.3.1 ([#5369](https://github.com/storybookjs/storybook/pull/5369))\n- Bump vue-loader from 15.5.1 to 15.6.0 ([#5365](https://github.com/storybookjs/storybook/pull/5365))\n- Bump prettier from 1.15.3 to 1.16.1 ([#5354](https://github.com/storybookjs/storybook/pull/5354))\n- Bump ember-source from 3.7.0 to 3.7.2 ([#5358](https://github.com/storybookjs/storybook/pull/5358))\n- Bump @angular/platform-browser-dynamic from 7.2.1 to 7.2.2 ([#5353](https://github.com/storybookjs/storybook/pull/5353))\n- Bump ember-cli-babel from 7.2.0 to 7.4.0 ([#5357](https://github.com/storybookjs/storybook/pull/5357))\n- Bump zone.js from 0.8.28 to 0.8.29 ([#5355](https://github.com/storybookjs/storybook/pull/5355))\n- Bump lerna from 3.10.6 to 3.10.7 ([#5356](https://github.com/storybookjs/storybook/pull/5356))\n- Bump eslint-plugin-import from 2.14.0 to 2.15.0 ([#5352](https://github.com/storybookjs/storybook/pull/5352))\n- Bump immer from 1.10.5 to 1.12.0 ([#5345](https://github.com/storybookjs/storybook/pull/5345))\n- Bump @babel/plugin-proposal-object-rest-spread from 7.2.0 to 7.3.1 ([#5342](https://github.com/storybookjs/storybook/pull/5342))\n- Bump autoprefixer from 9.4.5 to 9.4.6 ([#5347](https://github.com/storybookjs/storybook/pull/5347))\n- Bump react-focus-lock from 1.17.6 to 1.17.7 ([#5344](https://github.com/storybookjs/storybook/pull/5344))\n- Bump @ngrx/store from 7.0.0 to 7.1.0 ([#5341](https://github.com/storybookjs/storybook/pull/5341))\n\n## 4.1.11 (January 24, 2019)\n\n### Bug Fixes\n\n- React-native: Fixed isUIHidden param ([#5067](https://github.com/storybookjs/storybook/pull/5067))\n- React-native: Disabling warning if story is not set in async storage ([#5068](https://github.com/storybookjs/storybook/pull/5068))\n\n## 4.1.10 (January 24, 2019)\n\nRelease failed due to NPM error\n\n## 5.0.0-alpha.9 (January 23, 2019)\n\n### Features\n\n- Core: Add a STORY_UNCHANGED event ([#5340](https://github.com/storybookjs/storybook/pull/5340))\n- Core: Add a persistence API to context/state -- use for keyboard shortcuts ([#5289](https://github.com/storybookjs/storybook/pull/5289))\n\n### Maintenance\n\n- Addon-knobs: Fix story so array type is array ([#5318](https://github.com/storybookjs/storybook/pull/5318))\n\n### Dependency Upgrades\n\n- Bump ts-node from 7.0.1 to 8.0.1 ([#5346](https://github.com/storybookjs/storybook/pull/5346))\n- Bump marko from 4.14.20 to 4.14.21 ([#5343](https://github.com/storybookjs/storybook/pull/5343))\n- Bump @types/jest from 23.3.12 to 23.3.13 ([#5327](https://github.com/storybookjs/storybook/pull/5327))\n- Bump @babel/plugin-proposal-class-properties from 7.2.3 to 7.3.0 ([#5326](https://github.com/storybookjs/storybook/pull/5326))\n- Bump esm from 3.1.0 to 3.1.1 ([#5328](https://github.com/storybookjs/storybook/pull/5328))\n- Bump resolve from 1.9.0 to 1.10.0 ([#5329](https://github.com/storybookjs/storybook/pull/5329))\n- Bump webpack from 4.28.4 to 4.29.0 ([#5331](https://github.com/storybookjs/storybook/pull/5331))\n\n## 4.1.9 (January 23, 2019)\n\nNote that `4.1.7` contained a bad merge that missed an important change. This release fixes that:\n\n### Bug Fixes\n\n- Core: Add missing polyfills to manager to support IE ([#5238](https://github.com/storybookjs/storybook/pull/5238))\n\n## 4.1.8 (January 23, 2019)\n\nBad release\n\n## 5.0.0-alpha.8 (January 22, 2019)\n\n### Features\n\n- UI: Memoize treeview utils && ADD fuzzy search ([#5321](https://github.com/storybookjs/storybook/pull/5321))\n\n### Maintenance\n\n- Migrate addon google analytics to TS ([#5307](https://github.com/storybookjs/storybook/pull/5307))\n- Storyshots: restore emotion snapshots ([#5305](https://github.com/storybookjs/storybook/pull/5305))\n\n### Dependency Upgrades\n\n- Bump eslint-config-prettier from 3.5.0 to 3.6.0 ([#5311](https://github.com/storybookjs/storybook/pull/5311))\n- Bump eslint-plugin-react from 7.12.3 to 7.12.4 ([#5310](https://github.com/storybookjs/storybook/pull/5310))\n- Bump vuex from 3.0.1 to 3.1.0 ([#5316](https://github.com/storybookjs/storybook/pull/5316))\n- Bump lerna from 3.10.5 to 3.10.6 ([#5313](https://github.com/storybookjs/storybook/pull/5313))\n- Bump react-docgen-typescript-loader from 3.0.0 to 3.0.1 ([#5315](https://github.com/storybookjs/storybook/pull/5315))\n- Bump eslint from 5.12.0 to 5.12.1 ([#5314](https://github.com/storybookjs/storybook/pull/5314))\n- Bump jscodeshift from 0.6.2 to 0.6.3 ([#5317](https://github.com/storybookjs/storybook/pull/5317))\n\n## 5.0.0-alpha.7 (January 20, 2019)\n\n### Breaking Changes\n\n- Addon-centered: Add special entry-points for Vue and React ([#5296](https://github.com/storybookjs/storybook/pull/5296))\n\n### Features\n\n- CLI: new `add` command ([#4236](https://github.com/storybookjs/storybook/pull/4236))\n- UI: set the document title when navigating stories ([#5277](https://github.com/storybookjs/storybook/pull/5277))\n\n### Bug Fixes\n\n- Addon-a11y: RE-ADD deprecated 'configureA11Y' for backwards compatibility ([#5302](https://github.com/storybookjs/storybook/pull/5302))\n- UI: FIX navigation issue for `file://` URLs ([#5295](https://github.com/storybookjs/storybook/pull/5295))\n- UI: FIX merge mutation ([#5300](https://github.com/storybookjs/storybook/pull/5300))\n- Core: FIX issue where webpack process would hang when manager build failed ([#5290](https://github.com/storybookjs/storybook/pull/5290))\n\n## 5.0.0-alpha.6 (January 18, 2019)\n\n### Maintenance\n\n- Restore official-storybook error test ([#5281](https://github.com/storybookjs/storybook/pull/5281))\n- Add explicit return types to @storybook/addons ([#5212](https://github.com/storybookjs/storybook/pull/5212))\n- REFACTOR router into @storybook/router ([#5252](https://github.com/storybookjs/storybook/pull/5252))\n\n### Dependency Upgrades\n\n- Bump react-select from 2.2.0 to 2.3.0 ([#5288](https://github.com/storybookjs/storybook/pull/5288))\n- Bump webpack-dev-middleware from 3.5.0 to 3.5.1 ([#5285](https://github.com/storybookjs/storybook/pull/5285))\n- Bump dotenv-webpack from 1.6.0 to 1.7.0 ([#5283](https://github.com/storybookjs/storybook/pull/5283))\n- Bump graphql from 0.13.2 to 14.1.1 ([#5282](https://github.com/storybookjs/storybook/pull/5282))\n- Bump marko from 4.14.19 to 4.14.20 ([#5284](https://github.com/storybookjs/storybook/pull/5284))\n- Bumps webpack from 4.28.3 to 4.28.4 ([#5260](https://github.com/storybookjs/storybook/pull/5260))\n\n## 4.1.7 (January 17, 2019)\n\n### Bug Fixes\n\n- Core: make absolute DLL path relative ([#5238](https://github.com/storybookjs/storybook/pull/5238))\n- Addon-actions: import utils directly to prevent import cycles ([#5107](https://github.com/storybookjs/storybook/pull/5107))\n- Add-knobs: render non-grouped knobs in the ALL tab ([#5106](https://github.com/storybookjs/storybook/pull/5106))\n\n## 5.0.0-alpha.5 (January 17, 2019)\n\n### Features\n\n- Core: preserve user-specified iframe url params ([#5272](https://github.com/storybookjs/storybook/pull/5272))\n\n### Bug Fixes\n\n- Storyshots: FIX using the wrong parameter for disabling ([#5257](https://github.com/storybookjs/storybook/pull/5257))\n\n## 5.0.0-alpha.4 (January 17, 2019)\n\n### Bug Fixes\n\n- Core: Fix iframe url params ([#5265](https://github.com/storybookjs/storybook/pull/5265))\n\n### Maintenance\n\n- Core: Rename viewMode/url from `components` to `story` ([#5266](https://github.com/storybookjs/storybook/pull/5266))\n- Core: Export events constants as named exports ([#5186](https://github.com/storybookjs/storybook/pull/5186))\n\n### Dependency Upgrades\n\n- Bump vue and vue-template-compiler ([#5231](https://github.com/storybookjs/storybook/pull/5231))\n- Bump ember-cli from 3.7.0 to 3.7.1 ([#5243](https://github.com/storybookjs/storybook/pull/5243))\n- Bump ember-source from 3.6.1 to 3.7.0 ([#5258](https://github.com/storybookjs/storybook/pull/5258))\n- Bump @angular/platform-browser-dynamic from 7.1.4 to 7.2.0 ([#5259](https://github.com/storybookjs/storybook/pull/5259))\n- Bump vue-loader from 15.4.2 to 15.5.1 ([#5261](https://github.com/storybookjs/storybook/pull/5261))\n\n## 5.0.0-alpha.3 (January 16, 2019)\n\nTest publishing improvements\n\n## 5.0.0-alpha.2 (January 16, 2019)\n\n### Bug Fixes\n\n- Storyshots: Fix async issue with obtaining custom Puppeteer instance … ([#5130](https://github.com/storybookjs/storybook/pull/5130))\n\n### Maintenance\n\n- MIGRATE to wrap emotion into a @storybook/theming package ([#5241](https://github.com/storybookjs/storybook/pull/5241))\n\n### Dependency Upgrades\n\n- Bump zone.js from 0.8.26 to 0.8.27 ([#5230](https://github.com/storybookjs/storybook/pull/5230))\n- Bump lerna from 3.8.5 to 3.10.5 ([#5229](https://github.com/storybookjs/storybook/pull/5229))\n\n## 5.0.0-alpha.1 (January 14, 2019)\n\n### Bug Fixes\n\n- Core: `no-dll` option to CLI to disable DllReferencePlugin, fix polyfills ([#5238](https://github.com/storybookjs/storybook/pull/5238))\n- Core: Continue `{name, kind}` support on the `SET_CURRENT_STORY` event ([#5228](https://github.com/storybookjs/storybook/pull/5228))\n- UI: FIX issue with accidentally thinking things are roots ([#5236](https://github.com/storybookjs/storybook/pull/5236))\n\n### Dependency Upgrades\n\n- Bump react-scripts from 2.1.1 to 2.1.3 ([#5214](https://github.com/storybookjs/storybook/pull/5214))\n\n## 5.0.0-alpha.0 (January 13, 2019)\n\n### Breaking Changes\n\n- Core: Simplify custom webpack config ([#4927](https://github.com/storybookjs/storybook/pull/4927))\n- UI: Storybook 5.0 UI and addons overhaul ([#5222](https://github.com/storybookjs/storybook/pull/5222))\n\n### Features\n\n- Core: Use new story format in official storybook ([#5058](https://github.com/storybookjs/storybook/pull/5058))\n- UI: keyboard shortcuts ([#4257](https://github.com/storybookjs/storybook/pull/4257))\n\n### Bug Fixes\n\n- React: Merge CRA2 webpack plugins ([#5126](https://github.com/storybookjs/storybook/pull/5126))\n\n### Dependency Upgrades\n\n- Bump eslint-plugin-jest from 22.1.2 to 22.1.3 ([#5215](https://github.com/storybookjs/storybook/pull/5215))\n- Bump eslint from 5.11.0 to 5.12.0 ([#5216](https://github.com/storybookjs/storybook/pull/5216))\n- Bump jscodeshift from 0.5.1 to 0.6.2 ([#5213](https://github.com/storybookjs/storybook/pull/5213))\n- Bump ember-cli from 3.6.1 to 3.7.0 ([#5203](https://github.com/storybookjs/storybook/pull/5203))\n- Bump react-dev-utils from 7.0.0 to 7.0.1 ([#5202](https://github.com/storybookjs/storybook/pull/5202))\n- Bump ember-cli from 3.6.0 to 3.6.1 ([#5188](https://github.com/storybookjs/storybook/pull/5188))\n- Bump terser-webpack-plugin from 1.1.0 to 1.2.1 ([#5190](https://github.com/storybookjs/storybook/pull/5190))\n- Bump chalk from 2.4.1 to 2.4.2 ([#5191](https://github.com/storybookjs/storybook/pull/5191))\n\n## 4.2.0-alpha.11 (January 9, 2019)\n\n### Maintenance\n\n- Typescript: Add TypeScript CRA example ([#5120](https://github.com/storybookjs/storybook/pull/5120))\n- Typescript: Migrate @storybook/channel-postmessage ([#5154](https://github.com/storybookjs/storybook/pull/5154))\n- Typescript: Migrate @storybook/client-logger ([#5151](https://github.com/storybookjs/storybook/pull/5151))\n\n### Dependency Upgrades\n\n- Bump @babel/cli from 7.2.0 to 7.2.3 ([#5178](https://github.com/storybookjs/storybook/pull/5178))\n- Bump babel-plugin-macros from 2.4.4 to 2.4.5 ([#5177](https://github.com/storybookjs/storybook/pull/5177))\n- Bump babel-preset-react-app from 6.1.0 to 7.0.0 ([#5176](https://github.com/storybookjs/storybook/pull/5176))\n- Bump interpret from 1.1.0 to 1.2.0 ([#5175](https://github.com/storybookjs/storybook/pull/5175))\n- Bump file-loader from 2.0.0 to 3.0.1 ([#5174](https://github.com/storybookjs/storybook/pull/5174))\n- Bump mini-css-extract-plugin from 0.4.5 to 0.5.0 ([#5173](https://github.com/storybookjs/storybook/pull/5173))\n- Bump webpack-cli from 3.2.0 to 3.2.1 ([#5172](https://github.com/storybookjs/storybook/pull/5172))\n- Bump marko from 4.14.12 to 4.14.15 ([#5157](https://github.com/storybookjs/storybook/pull/5157))\n- Bump @types/jest from 23.3.10 to 23.3.12 ([#5158](https://github.com/storybookjs/storybook/pull/5158))\n- Bump @angular/compiler from 7.1.3 to 7.1.4 ([#5159](https://github.com/storybookjs/storybook/pull/5159))\n- Bump dotenv-webpack from 1.5.7 to 1.6.0 ([#5160](https://github.com/storybookjs/storybook/pull/5160))\n- Bump babel-plugin-macros from 2.4.3 to 2.4.4 ([#5161](https://github.com/storybookjs/storybook/pull/5161))\n\n## 4.1.6 (January 9, 2019)\n\n### Bug Fixes\n\n- React: Fix react version backwards compatibility ([#5148](https://github.com/storybookjs/storybook/pull/5148))\n- UI: fix highlightColor ([#5150](https://github.com/storybookjs/storybook/pull/5150))\n- Core: Transpile addons.js with Babel for IE11 ([#5081](https://github.com/storybookjs/storybook/pull/5081))\n\n### Maintenance\n\n- Add CORS headers to versions.json ([#5155](https://github.com/storybookjs/storybook/pull/5155))\n\n### Dependency Upgrades\n\n- Bump puppeteer from 1.9.0 to 1.11.0 ([#5119](https://github.com/storybookjs/storybook/pull/5119))\n\n## 4.1.5 (January 9, 2019)\n\nNPM failure, republishing as 4.1.6\n\n## 4.2.0-alpha.10 (January 6, 2019)\n\n### Features\n\n- Addon-a11y: fix addon, add ability to configure context ([#5101](https://github.com/storybookjs/storybook/pull/5101))\n\n### Bug Fixes\n\n- Addon-knobs: Render non-grouped knobs in the ALL tab ([#5106](https://github.com/storybookjs/storybook/pull/5106))\n- Addon-actions: import utils directly to prevent import cycles ([#5107](https://github.com/storybookjs/storybook/pull/5107))\n\n### Maintenance\n\n- TypeScript: Migrate @storybook/node-logger ([#5153](https://github.com/storybookjs/storybook/pull/5153))\n- TypeScript: Migrate @storybook/core-events ([#5140](https://github.com/storybookjs/storybook/pull/5140))\n\n### Dependency Upgrades\n\n- bump puppeteer from 1.9.0 to 1.11.0 ([#5119](https://github.com/storybookjs/storybook/pull/5119))\n- Bump lerna from 3.6.0 to 3.8.4 ([#5142](https://github.com/storybookjs/storybook/pull/5142))\n- Bump svelte from 2.15.3 to 2.16.0 ([#5145](https://github.com/storybookjs/storybook/pull/5145))\n- Bump react-dev-utils from 6.1.1 to 7.0.0 ([#5146](https://github.com/storybookjs/storybook/pull/5146))\n- Bump react-is from 16.6.3 to 16.7.0 ([#5144](https://github.com/storybookjs/storybook/pull/5144))\n\n## 4.2.0-alpha.9 (January 4, 2019)\n\n### Bug Fixes\n\n- Transpile addons.js with Babel ([#5081](https://github.com/storybookjs/storybook/pull/5081))\n\n### Dependency Upgrades\n\n- [Security] Bump webpack-dev-server from 3.1.10 to 3.1.14 ([#5108](https://github.com/storybookjs/storybook/pull/5108))\n- Update @storybook/react to include peer dependency @emotion/core ([#5135](https://github.com/storybookjs/storybook/pull/5135))\n- Bump webpack-cli from 3.1.2 to 3.2.0 ([#5137](https://github.com/storybookjs/storybook/pull/5137))\n- Bump resolve from 1.8.1 to 1.9.0 ([#5139](https://github.com/storybookjs/storybook/pull/5139))\n- Bump husky from 1.3.0 to 1.3.1 ([#5138](https://github.com/storybookjs/storybook/pull/5138))\n- Bump @types/node from 10.12.17 to 10.12.18 ([#5098](https://github.com/storybookjs/storybook/pull/5098))\n- Bump svelte-loader from 2.11.0 to 2.12.0 ([#5125](https://github.com/storybookjs/storybook/pull/5125))\n- Bump react-modal from 3.7.1 to 3.8.1 ([#5124](https://github.com/storybookjs/storybook/pull/5124))\n- Bump marko from 4.14.3 to 4.14.12 ([#5123](https://github.com/storybookjs/storybook/pull/5123))\n- Bump css-loader from 1.0.1 to 2.1.0 ([#5115](https://github.com/storybookjs/storybook/pull/5115))\n- Bump lit-html from 0.12.0 to 0.14.0 ([#5114](https://github.com/storybookjs/storybook/pull/5114))\n- Bump @angular/platform-browser-dynamic from 7.1.3 to 7.1.4 ([#5113](https://github.com/storybookjs/storybook/pull/5113))\n\n## 4.2.0-alpha.8 (December 28, 2018)\n\n### Maintenance\n\n- Typescript: Migrate @storybook/channel-websocket ([#5046](https://github.com/storybookjs/storybook/pull/5046))\n- Typescript: Migrate @storybook/addons ([#5018](https://github.com/storybookjs/storybook/pull/5018))\n\n### Dependency Upgrades\n\n- Bump @babel/plugin-proposal-class-properties from 7.2.1 to 7.2.3 ([#5070](https://github.com/storybookjs/storybook/pull/5070))\n- Bump babel-plugin-named-asset-import from 0.2.3 to 0.3.0 ([#5100](https://github.com/storybookjs/storybook/pull/5100))\n- Bump eslint from 5.10.0 to 5.11.0 ([#5097](https://github.com/storybookjs/storybook/pull/5097))\n- Bump loader-utils from 1.2.0 to 1.2.1 ([#5099](https://github.com/storybookjs/storybook/pull/5099))\n- Bump boxen from 2.0.0 to 2.1.0 ([#5104](https://github.com/storybookjs/storybook/pull/5104))\n- Bump @ngrx/store from 6.1.2 to 7.0.0 ([#5105](https://github.com/storybookjs/storybook/pull/5105))\n- Bump react-select from 2.1.1 to 2.1.2 ([#5102](https://github.com/storybookjs/storybook/pull/5102))\n\n## 4.1.4 (December 25, 2018)\n\n### Bug Fixes\n\n- Core: Load Symbol polyfill before any other code ([#5082](https://github.com/storybookjs/storybook/pull/5082))\n- React: Fix error with new CRA Webpack config ([#5074](https://github.com/storybookjs/storybook/pull/5074))\n\n## 4.2.0-alpha.7 (December 25, 2018)\n\n### Bug Fixes\n\n- React: Fix error with new CRA Webpack config ([#5074](https://github.com/storybookjs/storybook/pull/5074))\n- Core: Load Symbol polyfill before any other code ([#5082](https://github.com/storybookjs/storybook/pull/5082))\n\n### Dependency Upgrades\n\n- Bump eslint-plugin-jest from 21.27.2 to 22.1.2 ([#5089](https://github.com/storybookjs/storybook/pull/5089))\n- Bump react-color from 2.14.1 to 2.17.0 ([#5083](https://github.com/storybookjs/storybook/pull/5083))\n- Bump @angular-devkit/build-angular from 0.10.7 to 0.11.4 ([#5084](https://github.com/storybookjs/storybook/pull/5084))\n- Bump ts-loader from 5.3.1 to 5.3.2 ([#5085](https://github.com/storybookjs/storybook/pull/5085))\n- Bump loader-utils from 1.1.0 to 1.2.0 ([#5086](https://github.com/storybookjs/storybook/pull/5086))\n- Bump protractor from 5.4.1 to 5.4.2 ([#5087](https://github.com/storybookjs/storybook/pull/5087))\n- Bump ember-cli from 3.5.1 to 3.6.0 ([#5088](https://github.com/storybookjs/storybook/pull/5088))\n- Bump tslint from 5.11.0 to 5.12.0 ([#5090](https://github.com/storybookjs/storybook/pull/5090))\n- Bump react-dom from 16.6.3 to 16.7.0 ([#5071](https://github.com/storybookjs/storybook/pull/5071))\n\n## 4.1.3 (December 20, 2018)\n\n### Bug Fixes\n\n- React: remove unnecessary dependencies, fix aliasing ([#5047](https://github.com/storybookjs/storybook/pull/5047))\n- React: alias to react & react-dom ([#5016](https://github.com/storybookjs/storybook/pull/5016))\n- Addon-knobs: Fix color picker display ([#5010](https://github.com/storybookjs/storybook/pull/5010))\n\n## 4.2.0-alpha.6 (December 20, 2018)\n\n### Features\n\n- React-Native: Change on-device layout to absolute position ([#4962](https://github.com/storybookjs/storybook/pull/4962))\n- Addon-Info: add css classes for style overrides ([#4589](https://github.com/storybookjs/storybook/pull/4589))\n\n### Bug Fixes\n\n- Addon-Info: Display description when story name matches component ([#4863](https://github.com/storybookjs/storybook/pull/4863))\n- React-Native: Disable warning if story is not set in async storage ([#5068](https://github.com/storybookjs/storybook/pull/5068))\n- React-Native: Fixed isUIHidden param ([#5067](https://github.com/storybookjs/storybook/pull/5067))\n- Vue: Fix reloading and story decoration ([#5057](https://github.com/storybookjs/storybook/pull/5057))\n\n### Maintenance\n\n- TypeScript: migrate @storybook/channels to typescript ([#4977](https://github.com/storybookjs/storybook/pull/4977))\n\n### Dependency Upgrades\n\n- Bump babel-plugin-macros from 2.4.2 to 2.4.3 ([#5060](https://github.com/storybookjs/storybook/pull/5060))\n- Bump @babel/core from 7.2.0 to 7.2.2 ([#5059](https://github.com/storybookjs/storybook/pull/5059))\n- Bump ember-cli-htmlbars-inline-precompile from 1.0.5 to 2.1.0 ([#5064](https://github.com/storybookjs/storybook/pull/5064))\n- Bump react-test-renderer from 16.6.3 to 16.7.0 ([#5063](https://github.com/storybookjs/storybook/pull/5063))\n- Bump autoprefixer from 9.4.2 to 9.4.3 ([#5061](https://github.com/storybookjs/storybook/pull/5061))\n\n## 4.2.0-alpha.5 (December 19, 2018)\n\n### Bug Fixes\n\n- React: Remove unnecessary dependencies, fix aliasing ([#5047](https://github.com/storybookjs/storybook/pull/5047))\n\n### Dependency Upgrades\n\n- Bump @types/node from 10.12.14 to 10.12.17 ([#5045](https://github.com/storybookjs/storybook/pull/5045))\n- Bump ember-source from 3.5.1 to 3.6.1 ([#5044](https://github.com/storybookjs/storybook/pull/5044))\n\n## 4.2.0-alpha.4 (December 18, 2018)\n\n### Bug Fixes\n\n- React: fix alias for react(-dom) to resolve to the user's version ([#5042](https://github.com/storybookjs/storybook/pull/5042))\n\n### Dependency Upgrades\n\n- Bump husky from 1.2.0 to 1.3.0 ([#5038](https://github.com/storybookjs/storybook/pull/5038))\n- Bump fork-ts-checker-webpack-plugin from 0.4.15 to 0.5.2 ([#5037](https://github.com/storybookjs/storybook/pull/5037))\n\n## 4.2.0-alpha.3 (December 18, 2018)\n\n### Bug Fixes\n\n- React: add alias to react & react-dom ([#5016](https://github.com/storybookjs/storybook/pull/5016))\n- Addon-knobs: fix color picker display ([#5010](https://github.com/storybookjs/storybook/pull/5010))\n\n## 4.2.0-alpha.2 (December 16, 2018)\n\n### Features\n\n- Addon-Info: add markdown support for jsdoc comments ([#4983](https://github.com/storybookjs/storybook/pull/4983))\n- Addon-Storysource: support Flow ([#4971](https://github.com/storybookjs/storybook/pull/4971))\n\n### Maintenance\n\n- Make applyPresets function signature more consistent ([#4988](https://github.com/storybookjs/storybook/pull/4988))\n\n### Dependency Upgrades\n\n- RESET lockfile ([#4991](https://github.com/storybookjs/storybook/pull/4991))\n\n## 4.1.2 (December 15, 2018)\n\n### Bug Fixes\n\n- Addon-Knob: Add missing key property in Panel ([#4507](https://github.com/storybookjs/storybook/pull/4507))\n- Fix package version dependencies ([#4960](https://github.com/storybookjs/storybook/pull/4960))\n\n## 4.2.0-alpha.1 (December 12, 2018)\n\nFixes 4.2.0-alpha.0\n\n### Features\n\n- Addon-info: add forwardRef support ([#4961](https://github.com/storybookjs/storybook/pull/4961))\n\n### Bug Fixes\n\n- Addon-knobs: Add missing key property in Panel ([#4507](https://github.com/storybookjs/storybook/pull/4507))\n\n### Maintenance\n\n- Addon-notes: Migrated to TypeScript ([#4758](https://github.com/storybookjs/storybook/pull/4758))\n\n### Dependency Upgrades\n\n- Fix: Add missing peer dependencies to addon-knobs ([#4928](https://github.com/storybookjs/storybook/pull/4928))\n\n## 4.2.0-alpha.0 (December 12, 2018)\n\nBad release\n\n## 4.1.1 (December 12, 2018)\n\n### Bug Fixes\n\n- FIX react native by adding an empty array named dlls to the templateParameters ([#4985](https://github.com/storybookjs/storybook/pull/4985))\n\n## 4.1.0 (December 12, 2018)\n\nStorybook 4.1 with performance and compatibility improvements! Highlights include:\n\n- Core: Performance optimizations on separate manager preview split, improved cold start, restart & rebuild ([#4834](https://github.com/storybookjs/storybook/pull/4834))\n- React: add support for all versions of react ([#4808](https://github.com/storybookjs/storybook/pull/4808))\n- Addon-CSSResources: new adddon to dynamically add/remove css ([#4622](https://github.com/storybookjs/storybook/pull/4622))\n- React: use babel presets/plugins based on CRA. ([#4836](https://github.com/storybookjs/storybook/pull/4836))\n- React-native: Add ability to filter story list ([#4806](https://github.com/storybookjs/storybook/pull/4806))\n- React: Add TypeScript support for react-scripts ([#4824](https://github.com/storybookjs/storybook/pull/4824))\n\nThere are dozens more fixes, features, and tweaks in the 4.1 release. See changelogs for `4.1.0-*` for details.\n\n## 4.1.0-alpha.13 (December 12, 2018)\n\n### Maintenance\n\n- React-native: add core-js to addons ([#4981](https://github.com/storybookjs/storybook/pull/4981))\n\n## 4.1.0-alpha.12 (December 11, 2018)\n\n### Bug Fixes\n\n- Fix storyshots by compiling JS modules ([#4967](https://github.com/storybookjs/storybook/pull/4967))\n- Angular: move 'core-js/modules/es6.promise' into storyshots ([#4929](https://github.com/storybookjs/storybook/pull/4929))\n\n## 4.0.12 (December 5, 2018)\n\n### Bug Fixes\n\n- Addon-a11y: Fix runtime errors in older browsers ([#4904](https://github.com/storybookjs/storybook/pull/4904))\n\n## 4.1.0-alpha.11 (December 5, 2018)\n\n### Features\n\n- Add CRA TypeScript support for .storybook folder ([#4902](https://github.com/storybookjs/storybook/pull/4902))\n\n### Bug Fixes\n\n- React-native: Fix async storage ([#4907](https://github.com/storybookjs/storybook/pull/4907))\n- Core: replace babel/runtime with core-js to fix some aliasing issues ([#4900](https://github.com/storybookjs/storybook/pull/4900))\n\n### Maintenance\n\n- Core: More granular methods separation in \"build-static\" and \"build-dev\" ([#4919](https://github.com/storybookjs/storybook/pull/4919))\n- Examples: replace deprecated setOptions with withOptions ([#4899](https://github.com/storybookjs/storybook/pull/4899))\n\n## 4.0.11 (December 3, 2018)\n\n### Bug Fixes\n\n- Restore index.html in cra-kitchen-sink ([#4856](https://github.com/storybookjs/storybook/pull/4856))\n- Add try, catch for IE11 as it breaks script execution ([#4870](https://github.com/storybookjs/storybook/pull/4870))\n\n## 4.0.10 (December 2, 2018)\n\nFixes 4.0.9\n\n### Bug Fixes\n\n- Core: Use correct cache directory path ([#4792](https://github.com/storybookjs/storybook/pull/4792))\n- Addon-Info: fix docgen description display ([#4685](https://github.com/storybookjs/storybook/pull/4685))\n- Addon-storyshots-puppeteer: fix peerDependencies ([#4828](https://github.com/storybookjs/storybook/pull/4828))\n\n## 4.1.0-alpha.10 (December 1, 2018)\n\n### Maintenance\n\n- Performance optimizations on separate manager preview split, improved cold start, restart & rebuild ([#4834](https://github.com/storybookjs/storybook/pull/4834))\n\n## 4.1.0-alpha.9 (November 29, 2018)\n\n### Features\n\n- UI: Accessible success/fail colors ([#4843](https://github.com/storybookjs/storybook/pull/4843))\n- React-native: add option to set keyboardVerticalOffset ([#4862](https://github.com/storybookjs/storybook/pull/4862))\n- Addon-CSSResources: new adddon to dynamically add/remove css ([#4622](https://github.com/storybookjs/storybook/pull/4622))\n\n### Bug Fixes\n\n- Core: Add try, catch for history API for IE11 ([#4870](https://github.com/storybookjs/storybook/pull/4870))\n- Core: Don't copy index.html on build-storybook ([#4856](https://github.com/storybookjs/storybook/pull/4856))\n- React-native: properly set initial story out of Async Storage. ([#4872](https://github.com/storybookjs/storybook/pull/4872))\n- React-native: show webpack-related build issues ([#4883](https://github.com/storybookjs/storybook/pull/4883))\n- Addon-info: fix docgen description display ([#4685](https://github.com/storybookjs/storybook/pull/4685))\n\n### Dependency Upgrades\n\n- Bump svelte to 2.15.3, addresses !4478 ([#4842](https://github.com/storybookjs/storybook/pull/4842))\n\n## 4.1.0-alpha.8 (November 25, 2018)\n\n### Features\n\n- React: use babel presets/plugins based on CRA. ([#4836](https://github.com/storybookjs/storybook/pull/4836))\n- React-native: Add ability to filter story list ([#4806](https://github.com/storybookjs/storybook/pull/4806))\n\n### Bug Fixes\n\n- Core: Don't mangle production build ([#4838](https://github.com/storybookjs/storybook/pull/4838))\n- HTML: Don't change rootElement when received node is the same ([#4822](https://github.com/storybookjs/storybook/pull/4822))\n\n### Maintenance\n\n- Fix snapshots to use \"emotion/snapshot-serializer\" ([#4837](https://github.com/storybookjs/storybook/pull/4837))\n\n## 4.1.0-alpha.7 (November 22, 2018)\n\n### Features\n\n- Add TypeScript support for react-scripts ([#4824](https://github.com/storybookjs/storybook/pull/4824))\n\n## 4.1.0-alpha.5/6 (November 22, 2018)\n\nPublish failed\n\n## 4.1.0-alpha.4 (November 21, 2018)\n\n### Features\n\n- ADD support for all versions of react ([#4808](https://github.com/storybookjs/storybook/pull/4808))\n\n### Bug Fixes\n\n- Use correct cache directory path ([#4792](https://github.com/storybookjs/storybook/pull/4792))\n\n## 4.0.9 (November 26, 2018)\n\nBroken release (see https://github.com/storybookjs/storybook/issues/4897)\n\n## 4.0.8 (November 21, 2018)\n\n### Bug Fixes\n\n- Addon-knobs: Vue optimize on force render ([#4773](https://github.com/storybookjs/storybook/pull/4773))\n\n## 4.1.0-alpha.3 (November 15, 2018)\n\n### Maintenance\n\n- REFACTOR dev-serve to output less noise ([#4791](https://github.com/storybookjs/storybook/pull/4791))\n- Separate manager and preview part.2 ([#4789](https://github.com/storybookjs/storybook/pull/4789))\n\n### Dependency Upgrades\n\n- Use alpha minify dependency to upgrade transitive lodash dependencies ([#4771](https://github.com/storybookjs/storybook/pull/4771))\n\n## 4.0.7 (November 15, 2018)\n\n### Bug Fixes\n\n- Vue/Angular/Mithril/Polymer: Add missing \"forceReRender\" and \"addParameters\" ([#4767](https://github.com/storybookjs/storybook/pull/4767))\n\n## 4.1.0-alpha.2 (November 13, 2018)\n\n### Features\n\n- Core: Interpolation for multiple environment variables ([#4761](https://github.com/storybookjs/storybook/pull/4761))\n- UI: deep theming for stories nav panel ([#4702](https://github.com/storybookjs/storybook/pull/4702))\n- React-native: Persist last displayed story, allow to set initial story. ([#4713](https://github.com/storybookjs/storybook/pull/4713))\n\n### Bug Fixes\n\n- Better a11y ([#4704](https://github.com/storybookjs/storybook/pull/4704))\n- Remove z-index from vertical resizer ([#4651](https://github.com/storybookjs/storybook/pull/4651))\n- React: Ensure @storybook/react can be imported in Node.js without errors ([#4757](https://github.com/storybookjs/storybook/pull/4757))\n\n### Maintenance\n\n- Core: separate manager from preview ([#4590](https://github.com/storybookjs/storybook/pull/4590))\n- Add tests for custom react-scripts packages ([#4768](https://github.com/storybookjs/storybook/pull/4768))\n- FIX deprecation warning from husky ([#4755](https://github.com/storybookjs/storybook/pull/4755))\n- Tech/silent smoke tests ([#4749](https://github.com/storybookjs/storybook/pull/4749))\n\n### Dependency Upgrades\n\n- Bump lint-staged from 7.3.0 to 8.0.4 ([#4673](https://github.com/storybookjs/storybook/pull/4673))\n- Bump svelte from 2.13.5 to 2.15.2 ([#4726](https://github.com/storybookjs/storybook/pull/4726))\n- [Security] Bump cached-path-relative from 1.0.1 to 1.0.2 ([#4745](https://github.com/storybookjs/storybook/pull/4745))\n- Update expo requirement from ^30.0.1 to ^31.0.4 in /examples-native/crna-kitchen-sink ([#4728](https://github.com/storybookjs/storybook/pull/4728))\n- Bump @storybook/addon-links from 3.4.11 to 4.0.4 in /docs ([#4732](https://github.com/storybookjs/storybook/pull/4732))\n- Bump react-syntax-highlighter from 9.0.1 to 10.0.0 ([#4654](https://github.com/storybookjs/storybook/pull/4654))\n- Bump @angular/compiler from 7.0.1 to 7.0.2 ([#4677](https://github.com/storybookjs/storybook/pull/4677))\n- Bump @types/jest from 23.3.8 to 23.3.9 ([#4658](https://github.com/storybookjs/storybook/pull/4658))\n- Bump copy-webpack-plugin from 4.5.4 to 4.6.0 ([#4674](https://github.com/storybookjs/storybook/pull/4674))\n- Bump @ngrx/store from 6.1.1 to 6.1.2 ([#4678](https://github.com/storybookjs/storybook/pull/4678))\n- [Security] Bump merge from 1.2.0 to 1.2.1 ([#4686](https://github.com/storybookjs/storybook/pull/4686))\n\n## 4.0.6 (November 13, 2018)\n\n### Features\n\n- React: add support for custom `react-scripts` packages ([#4712](https://github.com/storybookjs/storybook/pull/4712))\n\n### Bug Fixes\n\n- Core: fix NODE_PATH is not being loaded from .env ([#4706](https://github.com/storybookjs/storybook/pull/4706))\n\n## 4.0.5 (November 13, 2018)\n\nPublish failed\n\n## 4.1.0-alpha.1\n\n2018-November-06\n\n#### Features\n\n- Core: add cursor images to webpack loader [#4498](https://github.com/storybookjs/storybook/pull/4498)\n- Storyshots-puppeteer: Allow specifying an existing browser [#4721](https://github.com/storybookjs/storybook/pull/4721)\n- React-native: close StoryListView after tap again in the current story [#4714](https://github.com/storybookjs/storybook/pull/4714)\n\n#### Dependency Upgrades\n\n- Bump @angular/compiler from 7.0.1 to 7.0.2 [#4677](https://github.com/storybookjs/storybook/pull/4677)\n- Bump @types/jest from 23.3.8 to 23.3.9 [#4658](https://github.com/storybookjs/storybook/pull/4658)\n- Bump copy-webpack-plugin from 4.5.4 to 4.6.0 [#4674](https://github.com/storybookjs/storybook/pull/4674)\n- Bump @ngrx/store from 6.1.1 to 6.1.2 [#4678](https://github.com/storybookjs/storybook/pull/4678)\n- [Security] Bump merge from 1.2.0 to 1.2.1 [#4686](https://github.com/storybookjs/storybook/pull/4686)\n\n## 4.1.0-alpha.0\n\nPublish failed\n\n## 4.0.4\n\n2018-November-06\n\n#### Bug Fixes\n\n- Core: Change extensions ordering in webpack config [#4708](https://github.com/storybookjs/storybook/pull/4708)\n- Addon-Knobs: Fix PropTypes in NumberType [#4669](https://github.com/storybookjs/storybook/pull/4669)\n- Addon-Viewport: Fix \"defaultViewport\" configuration [#4683](https://github.com/storybookjs/storybook/pull/4683)\n- Addon-Jest: Fix test matching [#4689](https://github.com/storybookjs/storybook/pull/4689)\n- Fix tests in node 11 by using `Array#sort` correctly [#4720](https://github.com/storybookjs/storybook/pull/4720)\n\n#### Dependency Upgrades\n\n- Bump react-syntax-highlighter from 9.0.1 to 10.0.0 [#4654](https://github.com/storybookjs/storybook/pull/4654)\n- Remove SB deps from cli tests [#4705](https://github.com/storybookjs/storybook/pull/4705)\n\n## 4.0.3\n\n2018-November-06\n\n#### Bug Fixes\n\n- React: Fix css relative asset urls [#4695](https://github.com/storybookjs/storybook/pull/4695)\n- Core: Fix a bug with buildStaticStandalone resolving too early [#4649](https://github.com/storybookjs/storybook/pull/4649)\n- Angular: Fixes component imports from dist [#4682](https://github.com/storybookjs/storybook/pull/4682)\n- Addon-info: Improve accessibility with contrast [#4698](https://github.com/storybookjs/storybook/pull/4698)\n- Ember: update ergonomics to not require any manual setup [#4594](https://github.com/storybookjs/storybook/pull/4594)\n- React-native: fix accessibility for component preview (iOS+VoiceOver) [#4601](https://github.com/storybookjs/storybook/pull/4601)\n\n#### Maintenance\n\n- Update release process and `master` becomes the stable branch [#4719](https://github.com/storybookjs/storybook/pull/4719)\n- Report CLI tests to teamcity [#4671](https://github.com/storybookjs/storybook/pull/4671)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n30 PRs\n</summary>\n\n- Bump @angular/core from 7.0.1 to 7.0.2 [#4675](https://github.com/storybookjs/storybook/pull/4675)\n- [Security] Bump merge from 1.2.0 to 1.2.1 in /docs [#4687](https://github.com/storybookjs/storybook/pull/4687)\n- Bump typescript from 3.1.4 to 3.1.6 [#4699](https://github.com/storybookjs/storybook/pull/4699)\n- Set zone.js as a peer and dev dependency [#4663](https://github.com/storybookjs/storybook/pull/4663)\n- chore(core): update css-loader to latest [#4619](https://github.com/storybookjs/storybook/pull/4619)\n- Bump css-loader from 1.0.0 to 1.0.1 [#4655](https://github.com/storybookjs/storybook/pull/4655)\n- Bump @ngrx/store from 6.1.0 to 6.1.1 [#4653](https://github.com/storybookjs/storybook/pull/4653)\n- Allow for angular-devkit/core version aligned with Angular v7 [#4652](https://github.com/storybookjs/storybook/pull/4652)\n- Bump ember-load-initializers from 1.1.0 to 2.0.0 [#4634](https://github.com/storybookjs/storybook/pull/4634)\n- Bump @ember/test-helpers from 0.7.27 to 1.0.0 [#4630](https://github.com/storybookjs/storybook/pull/4630)\n- Bump @storybook/addon-actions from 3.4.11 to 4.0.0 in /docs [#4626](https://github.com/storybookjs/storybook/pull/4626)\n- Bump gatsby-plugin-sharp from 2.0.7 to 2.0.10 in /docs [#4627](https://github.com/storybookjs/storybook/pull/4627)\n- Bump typescript from 3.1.3 to 3.1.4 [#4629](https://github.com/storybookjs/storybook/pull/4629)\n- Bump react-scripts from 2.0.5 to 2.1.0 [#4631](https://github.com/storybookjs/storybook/pull/4631)\n- Bump ember-source from 3.5.0 to 3.5.1 [#4633](https://github.com/storybookjs/storybook/pull/4633)\n- Bump @types/node from 10.12.0 to 10.12.1 [#4635](https://github.com/storybookjs/storybook/pull/4635)\n- Bump react-dev-utils from 6.0.5 to 6.1.0 [#4636](https://github.com/storybookjs/storybook/pull/4636)\n- Bump eslint from 5.7.0 to 5.8.0 [#4613](https://github.com/storybookjs/storybook/pull/4613)\n- Bump express-graphql from 0.6.12 to 0.7.1 [#4610](https://github.com/storybookjs/storybook/pull/4610)\n- Bump tslint-plugin-prettier from 2.0.0 to 2.0.1 [#4609](https://github.com/storybookjs/storybook/pull/4609)\n- Bump eslint-plugin-jest from 21.26.1 to 21.26.2 [#4606](https://github.com/storybookjs/storybook/pull/4606)\n- Bump @types/jest from 23.3.7 to 23.3.8 [#4611](https://github.com/storybookjs/storybook/pull/4611)\n- Bump fork-ts-checker-webpack-plugin from 0.4.10 to 0.4.14 [#4607](https://github.com/storybookjs/storybook/pull/4607)\n- Bump autoprefixer from 9.2.1 to 9.3.1 [#4605](https://github.com/storybookjs/storybook/pull/4605)\n- Bump jasmine-core from 3.2.1 to 3.3.0 [#4581](https://github.com/storybookjs/storybook/pull/4581)\n- Bump react-dom from 16.5.2 to 16.6.0 [#4580](https://github.com/storybookjs/storybook/pull/4580)\n- Bump eslint-plugin-jest from 21.25.1 to 21.26.1 [#4583](https://github.com/storybookjs/storybook/pull/4583)\n- Bump react from 16.5.2 to 16.6.0 [#4584](https://github.com/storybookjs/storybook/pull/4584)\n- Bump react-syntax-highlighter from 9.0.0 to 9.0.1 [#4585](https://github.com/storybookjs/storybook/pull/4585)\n- Bump remark-cli from 5.0.0 to 6.0.0 [#4551](https://github.com/storybookjs/storybook/pull/4551)\n\n</details>\n\n## 4.0.2\n\n2018-October-31\n\nFix broken 4.0.1 release\n\n#### Bug Fixes\n\n- Addon-knobs: fix select array values showing k [#4586](https://github.com/storybookjs/storybook/pull/4586)\n\n## 4.0.1\n\n2018-October-31\n\nBroken release - `@storybook/client-logger` [somehow didn't get published to NPM.](https://github.com/storybookjs/storybook/issues/4660)\n\n## 4.0.0\n\n2018-October-29\n\n[Storybook 4.0](https://medium.com/storybookjs/storybook-4-0-is-here-10b9857fc7de) is our first major-version update in over a year! Key improvements include:\n\n- Build tools\n  - Webpack 4 [#3148](https://github.com/storybookjs/storybook/pull/3148)\n  - Babel 7 [#3746](https://github.com/storybookjs/storybook/pull/3746)\n- View layers\n  - Storybook for Ember [#4237](https://github.com/storybookjs/storybook/pull/4237)\n  - Storybook for MarkoJS [#3504](https://github.com/storybookjs/storybook/pull/3504)\n  - Storybook for Mithril [#3244](https://github.com/storybookjs/storybook/pull/3244)\n  - Storybook for HTML snippets [#3475](https://github.com/storybookjs/storybook/pull/3475)\n  - Storybook for Svelte [#3770](https://github.com/storybookjs/storybook/pull/3770)\n  - Storybook for Riot [#4070](https://github.com/storybookjs/storybook/pull/4070)\n- Mobile\n  - Mobile device view: toggling stories panel with ☰ button [#3337](https://github.com/storybookjs/storybook/pull/3337)\n  - React Native: Remove the packager from storybook [#4261](https://github.com/storybookjs/storybook/pull/4261)\n  - React-Native: On-device addons [#4381](https://github.com/storybookjs/storybook/pull/4381)\n  - React-Native: On-device addons for notes, knobs, backgrounds [#4327](https://github.com/storybookjs/storybook/pull/4327)\n- UI\n  - Storybook UI theming [#3628](https://github.com/storybookjs/storybook/pull/3628)\n- Core\n  - Story parameters [#2679](https://github.com/storybookjs/storybook/pull/2679)\n  - Generic addon decorators [#3555](https://github.com/storybookjs/storybook/pull/3555)\n  - Support css-modules [#4405](https://github.com/storybookjs/storybook/pull/4405)\n  - start-storybook: open browser tab on first compilation [#4149](https://github.com/storybookjs/storybook/pull/4149)\n  - start-storybook: suggest an alternative when the port is occupied [#4146](https://github.com/storybookjs/storybook/pull/4146)\n  - CLI-less Node api [#4344](https://github.com/storybookjs/storybook/pull/4344)\n  - Rename CLI to sb [#4345](https://github.com/storybookjs/storybook/pull/4345)\n\nThere are hundreds of more fixes, features, and tweaks in the 4.0 release. See changelogs for `4.0.0-rc.*` and `4.0.0-alpha.*` for details; check out our [migration guide](https://medium.com/storybookjs/migrating-to-storybook-4-c65b19a03d2c) for a walkthrough of how to upgrade or the\n[migration docs](https://github.com/storybookjs/storybook/blob/master/MIGRATION.md#from-version-34x-to-40x) for an enumeration of breaking changes.\n\n## 4.0.0-rc.6\n\n2018-October-25\n\n#### Dependency Upgrades\n\n- Upgrade react-komposer to 2.0.5 [#4547](https://github.com/storybookjs/storybook/pull/4547)\n\n## 4.0.0-rc.5\n\n2018-October-25\n\n#### Maintenance\n\n- Fix issue with `sb init` on the Vue CLI [#4535](https://github.com/storybookjs/storybook/pull/4535)\n\n## 4.0.0-rc.4\n\n2018-October-25\n\n#### Features\n\n- Ember: update to not require any manual setup [#4544](https://github.com/storybookjs/storybook/pull/4544)\n\n#### Bug Fixes\n\n- React: add mini-css-extract-plugin to app/react dependencies [#4534](https://github.com/storybookjs/storybook/pull/4534)\n\n#### Maintenance\n\n- Add angular@7 cli tests [#4524](https://github.com/storybookjs/storybook/pull/4524)\n- Fix the node-logger version in app/react [#4539](https://github.com/storybookjs/storybook/pull/4539)\n\n#### Dependency Upgrades\n\n- Bump danger from 4.4.8 to 6.0.2 [#4538](https://github.com/storybookjs/storybook/pull/4538)\n- Bump react-test-renderer from 16.5.2 to 16.6.0 [#4536](https://github.com/storybookjs/storybook/pull/4536)\n- Bump fuse.js from 3.2.1 to 3.3.0 [#4537](https://github.com/storybookjs/storybook/pull/4537)\n- Bump riot from 3.12.0 to 3.13.0 [#4511](https://github.com/storybookjs/storybook/pull/4511)\n\n## 4.0.0-rc.3\n\n2018-October-23\n\n#### Bug Fixes\n\n- Fix knobs select to support rich values [#4522](https://github.com/storybookjs/storybook/pull/4522)\n- Turn off spell check in story filter [#4472](https://github.com/storybookjs/storybook/pull/4472)-\n\n#### Maintenance\n\n- ADD timeout to update check [#4530](https://github.com/storybookjs/storybook/pull/4530)\n- REMOVE emotion from demo components to make backwards compatibility easier && ADD demo components to official example [#4527](https://github.com/storybookjs/storybook/pull/4527)\n- Exclude story files from angular app build [#4485](https://github.com/storybookjs/storybook/pull/4485)\n\n## 4.0.0-rc.2\n\n2018-October-22\n\n#### Features\n\n- Support css-modules [#4405](https://github.com/storybookjs/storybook/pull/4405)\n- Angular: Support sass files [#4343](https://github.com/storybookjs/storybook/pull/4343)\n- Support \"mjs\" extensions [#4466](https://github.com/storybookjs/storybook/pull/4466)\n- Allow presets to be async [#4450](https://github.com/storybookjs/storybook/pull/4450)\n\n#### Bug Fixes\n\n- Addon-Jest: undefined file extension [#4452](https://github.com/storybookjs/storybook/pull/4452)\n\n#### Maintenance\n\n- Override babelrc for the node related code [#4451](https://github.com/storybookjs/storybook/pull/4451)\n- Use cross-env in official example [#4474](https://github.com/storybookjs/storybook/pull/4474)\n\n#### Dependency Upgrades\n\n- Bump copy-webpack-plugin from 4.5.3 to 4.5.4 [#4492](https://github.com/storybookjs/storybook/pull/4492)\n- Bump jest-image-snapshot from 2.5.0 to 2.6.0 [#4494](https://github.com/storybookjs/storybook/pull/4494)\n- Bump webpack from 4.20.2 to 4.21.0 [#4477](https://github.com/storybookjs/storybook/pull/4477)\n\n## 4.0.0-rc.1\n\n2018-October-18\n\n#### Bug Fixes\n\n- Angular: expose webpackFinal extension [#4431](https://github.com/storybookjs/storybook/pull/4431)\n- Addon-Knobs: fix ints as values [#4465](https://github.com/storybookjs/storybook/pull/4465)\n\n#### Maintenance\n\n- Add Angular 6 fixture to the sb-cli tests [#4464](https://github.com/storybookjs/storybook/pull/4464)\n\n#### Dependency Upgrades\n\n- Require React 16.3 as a peer dependency [#4458](https://github.com/storybookjs/storybook/pull/4458)\n- Bump @ember/test-helpers from 0.7.26 to 0.7.27 [#4455](https://github.com/storybookjs/storybook/pull/4455)\n- Bump eslint-plugin-jest from 21.25.0 to 21.25.1 [#4456](https://github.com/storybookjs/storybook/pull/4456)\n- Bump autoprefixer from 9.2.0 to 9.2.1 [#4457](https://github.com/storybookjs/storybook/pull/4457)\n- Bump @types/node from 10.11.7 to 10.12.0 [#4434](https://github.com/storybookjs/storybook/pull/4434)\n- Bump ember-cli-inject-live-reload from 2.0.0 to 2.0.1 [#4435](https://github.com/storybookjs/storybook/pull/4435)\n- Bump gatsby-plugin-sharp from 1.6.48 to 2.0.7 in /docs [#4438](https://github.com/storybookjs/storybook/pull/4438)\n- Bump marked from 0.4.0 to 0.5.1 in /docs [#4437](https://github.com/storybookjs/storybook/pull/4437)\n- Bump highlight.js from 9.12.0 to 9.13.0 in /docs [#4440](https://github.com/storybookjs/storybook/pull/4440)\n\n## 4.0.0-rc.0\n\n2018-October-15\n\n#### Features\n\n- Addon: google analytics [#4138](https://github.com/storybookjs/storybook/pull/4138)\n\n#### Bug Fixes\n\n- Improve environment var loading [#4413](https://github.com/storybookjs/storybook/pull/4413)\n\n#### Maintenance\n\n- Skip preflight check when starting cra kitchen sink [#4408](https://github.com/storybookjs/storybook/pull/4408)\n- Change crna-kitchen-sink path and Some CI maintenance [#4409](https://github.com/storybookjs/storybook/pull/4409)\n- Create ember entry point to official storybook [#4426](https://github.com/storybookjs/storybook/pull/4426)\n\n#### Dependency Upgrades\n\n- Bump ember-cli from 3.4.3 to 3.5.0 [#4429](https://github.com/storybookjs/storybook/pull/4429)\n- Bump react-native-modal-selector from 0.0.27 to 0.0.29 [#4428](https://github.com/storybookjs/storybook/pull/4428)\n- Bump ember-cli-inject-live-reload from 1.8.2 to 1.10.1 [#4423](https://github.com/storybookjs/storybook/pull/4423)\n- Bump html-webpack-plugin from 4.0.0-beta.1 to 4.0.0-beta.2 [#4421](https://github.com/storybookjs/storybook/pull/4421)\n- Bump react-scripts from 2.0.4 to 2.0.5 [#4420](https://github.com/storybookjs/storybook/pull/4420)\n- Bump autoprefixer from 9.1.5 to 9.2.0 [#4417](https://github.com/storybookjs/storybook/pull/4417)\n- Bump redux from 4.0.0 to 4.0.1 [#4419](https://github.com/storybookjs/storybook/pull/4419)\n- Bump ts-loader from 5.2.1 to 5.2.2 [#4418](https://github.com/storybookjs/storybook/pull/4418)\n- Bump eslint-plugin-jest from 21.24.1 to 21.25.0 [#4424](https://github.com/storybookjs/storybook/pull/4424)\n- Bump lazy-universal-dotenv from 1.9.1 to 2.0.0 [#4422](https://github.com/storybookjs/storybook/pull/4422)\n\n## 4.0.0-alpha.25\n\n2018-October-13\n\n#### Breaking Changes\n\n- CLI: Rename CLI to sb [#4345](https://github.com/storybookjs/storybook/pull/4345)\n- React Native: Remove the packager from storybook [#4261](https://github.com/storybookjs/storybook/pull/4261)\n- React-Native: On-device addons [#4381](https://github.com/storybookjs/storybook/pull/4381)\n\n#### Features\n\n- Storybook version update check [#4334](https://github.com/storybookjs/storybook/pull/4334)\n- CLI: specify project type interactively or as option [#4184](https://github.com/storybookjs/storybook/pull/4184)\n- Addon-Jest: expand supported file types [#3983](https://github.com/storybookjs/storybook/pull/3983)\n- CLI-less Node api [#4344](https://github.com/storybookjs/storybook/pull/4344)\n- React-Native: Updated channel to support async option [#4326](https://github.com/storybookjs/storybook/pull/4326)\n- React-Native: On-device addons for notes, knobs, backgrounds [#4327](https://github.com/storybookjs/storybook/pull/4327)\n- Angular: Add support for \"baseUrl\" and \"paths\" from angular-cli [#4162](https://github.com/storybookjs/storybook/pull/4162)\n- Angular: Added basePath support [#4323](https://github.com/storybookjs/storybook/pull/4323)\n- Vue: support string-only component [#4285](https://github.com/storybookjs/storybook/pull/4285)\n- Storyshots: Add snapshot serializer option [#4283](https://github.com/storybookjs/storybook/pull/4283)\n- Storyshots: Support story-specific options as function [#4282](https://github.com/storybookjs/storybook/pull/4282)\n\n#### Bug Fixes\n\n- React-native: Remove deprecated attempt to load default addons [#4308](https://github.com/storybookjs/storybook/pull/4308)\n- Fix panel layouts [#4304](https://github.com/storybookjs/storybook/pull/4304)\n- [logging] better error logging for when opn fails to opn [#4348](https://github.com/storybookjs/storybook/pull/4348)\n- Fix iPhone viewport dimensions [#4293](https://github.com/storybookjs/storybook/pull/4293)\n- Fix Array.js value to string [#4336](https://github.com/storybookjs/storybook/pull/4336)\n- Fixes to cli ember support [#4318](https://github.com/storybookjs/storybook/pull/4318)\n- Update `addon-jest` to new propType [#4252](https://github.com/storybookjs/storybook/pull/4252)\n\n#### Maintenance\n\n- Remove CRNA fixture [#4346](https://github.com/storybookjs/storybook/pull/4346)\n- Try to fix cli tests [#4338](https://github.com/storybookjs/storybook/pull/4338)\n- Updated installation for Angular [#4302](https://github.com/storybookjs/storybook/pull/4302)\n- Fix the broken lint [#4310](https://github.com/storybookjs/storybook/pull/4310)\n- [ember] add dependencies to root application [#4309](https://github.com/storybookjs/storybook/pull/4309)\n\n#### Dependency Upgrades\n\n- Knobs/replace datepicker [#4380](https://github.com/storybookjs/storybook/pull/4380)\n- Re-generate lockfiles [#4404](https://github.com/storybookjs/storybook/pull/4404)\n- Run `yarn upgrade-interactive --latest` in root and docs [#4403](https://github.com/storybookjs/storybook/pull/4403)\n- chore(deps): #4267 upgrade lodash to latest [#4284](https://github.com/storybookjs/storybook/pull/4284)\n- Bump express from 4.16.3 to 4.16.4 [#4370](https://github.com/storybookjs/storybook/pull/4370)\n- Bump @angular/cli from 6.2.4 to 6.2.5 [#4390](https://github.com/storybookjs/storybook/pull/4390)\n- CHANGE back to use html-webpack-plugin to keep compatibility with plugins that depend on it [#4375](https://github.com/storybookjs/storybook/pull/4375)\n- Bump danger from 4.4.6 to 4.4.7 [#4365](https://github.com/storybookjs/storybook/pull/4365)\n- Bump @storybook/react from 3.4.8 to 3.4.11 in /docs [#4354](https://github.com/storybookjs/storybook/pull/4354)\n- Bump sitemap from 1.13.0 to 2.0.1 in /docs [#4356](https://github.com/storybookjs/storybook/pull/4356)\n- Bump husky from 1.1.1 to 1.1.2 [#4358](https://github.com/storybookjs/storybook/pull/4358)\n- Tech/upgrades 5 [#4347](https://github.com/storybookjs/storybook/pull/4347)\n\n## 4.0.0-alpha.24\n\n2018-October-04\n\n#### Features\n\n- Storybook for Ember [#4237](https://github.com/storybookjs/storybook/pull/4237)\n- Riot: support the tagConstructor option [#4258](https://github.com/storybookjs/storybook/pull/4258)\n- Presets: Add \"addons\" and \"config\" to preset extensions [#4240](https://github.com/storybookjs/storybook/pull/4240)\n\n#### Bug Fixes\n\n- Webpack: Fix broken SVGs [#4260](https://github.com/storybookjs/storybook/pull/4260)\n- Babel/minify: use `builtIns: false` [#4262](https://github.com/storybookjs/storybook/pull/4262)\n- Addon-Notes: Fix how markdownOptions are passed to marked [#4242](https://github.com/storybookjs/storybook/pull/4242)\n- Addon-Knobs: Fix broken colorpicker [#4222](https://github.com/storybookjs/storybook/pull/4222)\n\n## 4.0.0-alpha.23\n\n2018-September-25\n\n#### Features\n\n- Angular build time optimization [#4118](https://github.com/storybookjs/storybook/pull/4118)\n- Pass Jest done callback to testMethod [#3853](https://github.com/storybookjs/storybook/pull/3853)\n\n#### Bug Fixes\n\n- Fix getstorybook CLI [#4213](https://github.com/storybookjs/storybook/pull/4213)\n- FIX regression devtool, in case of cross domain parent, window.parent might throw [#4199](https://github.com/storybookjs/storybook/pull/4199)\n\n#### Dependency Upgrades\n\n- Upgrade deps dealing with license issues [#4228](https://github.com/storybookjs/storybook/pull/4228)\n- Use @emotion/snapshot-serializer [#4206](https://github.com/storybookjs/storybook/pull/4206)\n\n## 4.0.0-alpha.22\n\n2018-September-19\n\n#### Features\n\n- Storyshots: story params support [#4176](https://github.com/storybookjs/storybook/pull/4176)\n- Addon-options: story params support [#3965](https://github.com/storybookjs/storybook/pull/3965)\n- Presets - API generalization [#4173](https://github.com/storybookjs/storybook/pull/4173)\n- start-storybook: open browser tab on first compilation [#4149](https://github.com/storybookjs/storybook/pull/4149)\n- start-storybook: suggest an alternative when the port is occupied [#4146](https://github.com/storybookjs/storybook/pull/4146)\n- Merge webpack optimisation configs [#4121](https://github.com/storybookjs/storybook/pull/4121)\n\n#### Bug Fixes\n\n- Angular cli - fix prebuild [#4187](https://github.com/storybookjs/storybook/pull/4187)\n- Presets - add babelDefault extension [#4155](https://github.com/storybookjs/storybook/pull/4155)\n- CHANGE index.html.ejs to use files over chunks && UPGRADE generate-page-webpack-plugin [#4134](https://github.com/storybookjs/storybook/pull/4134)\n- Allow replacing of stories (with warning rather than error) [#4061](https://github.com/storybookjs/storybook/pull/4061)\n\n#### Maintenance\n\n- CLI refactor [#4168](https://github.com/storybookjs/storybook/pull/4168)\n- Fix linter warnings [#4172](https://github.com/storybookjs/storybook/pull/4172)\n- Remove gh-pages deploy in favor of netlify [#4128](https://github.com/storybookjs/storybook/pull/4128)\n\n#### Dependency Upgrades\n\n- [core]: widen `airbnb-js-shims` dep range [#4189](https://github.com/storybookjs/storybook/pull/4189)\n- Updating react-split-pane to version 0.1.84 [#4153](https://github.com/storybookjs/storybook/pull/4153)\n- Riot tag loader missing in cli [#4122](https://github.com/storybookjs/storybook/pull/4122)\n\n## 3.4.11\n\n2018-September-17\n\n#### Dependencies\n\n- Allow v1 or v2 in airbnb-js-shims [#4190](https://github.com/storybookjs/storybook/pull/4190)\n\n## 4.0.0-alpha.21\n\n2018-September-07\n\n#### Features\n\n- Presets support [#4027](https://github.com/storybookjs/storybook/pull/4027)\n\n#### Bug Fixes\n\n- CLI: Add missing @babel/core dependency [#4117](https://github.com/storybookjs/storybook/pull/4117)\n- Addon-Info: Fix duplicated keys in PropTypes table [#4095](https://github.com/storybookjs/storybook/pull/4095)\n\n#### Dependency Upgrades\n\n- Moved to lerna 3 [#4067](https://github.com/storybookjs/storybook/pull/4067)\n\n#### Other\n\n- \\[WIP\\] Refactor core and frameworks to work with presets [#4043](https://github.com/storybookjs/storybook/pull/4043)\n- \\[WIP\\] presets - merge default babel configs [#4107](https://github.com/storybookjs/storybook/pull/4107)\n\n## 4.0.0-alpha.20\n\n2018-August-31\n\n#### Breaking Changes\n\n- Use `babelrc: false` only for custom config in `.storybook` directory [#4077](https://github.com/storybookjs/storybook/pull/4077)\n\n#### Features\n\n- Storybook for Riot [#4070](https://github.com/storybookjs/storybook/pull/4070)\n- Backgrounds addon: Allow setting background via name [#4081](https://github.com/storybookjs/storybook/pull/4081)\n- Storysource addon: injectDecorator option custom stories [#4012](https://github.com/storybookjs/storybook/pull/4012)\n\n#### Bug Fixes\n\n- Disabled import for TabWrapper [#4100](https://github.com/storybookjs/storybook/pull/4100)\n- Angular cli with projects assets: root dir not correctly used [#4058](https://github.com/storybookjs/storybook/pull/4058)\n\n#### Maintenance\n\n- Do not stale \"good first issue\" [#4092](https://github.com/storybookjs/storybook/pull/4092)\n- Remove danger from circleci because it's not working for forked PRs [#4080](https://github.com/storybookjs/storybook/pull/4080)\n\n#### Dependency Upgrades\n\n- UPGRADE packages [#3996](https://github.com/storybookjs/storybook/pull/3996)\n\n## 4.0.0-alpha.19\n\n2018-August-31\n\nNot published to NPM\n\n## 4.0.0-alpha.18\n\n2018-August-25\n\n#### Bug Fixes\n\n- Add missing `@babel/plugin-proposal-class-properties` dependency [#4076](https://github.com/storybookjs/storybook/pull/4076)\n- Don't display wrong warning when loading \".js\" or \".json\" [#4060](https://github.com/storybookjs/storybook/pull/4060)\n- Fix autodetection of used components in info addon [#4004](https://github.com/storybookjs/storybook/pull/4004)\n\n#### Maintenance\n\n- Faster CircleCI [#4068](https://github.com/storybookjs/storybook/pull/4068)\n\n## 4.0.0-alpha.17\n\n2018-August-24\n\n#### Breaking Changes\n\n- Babel 7 [#3746](https://github.com/storybookjs/storybook/pull/3746)\n\n#### Features\n\n- Emit messages when stories fail to render [#3967](https://github.com/storybookjs/storybook/pull/3967)\n- Storybook for Svelte [#3770](https://github.com/storybookjs/storybook/pull/3770)\n- Allow extending extensions without a full control mode [#3976](https://github.com/storybookjs/storybook/pull/3976)\n\n#### Bug Fixes\n\n- Storyshots puppeteer images do not match [#4045](https://github.com/storybookjs/storybook/pull/4045)\n- Storyshots puppeteer images do not match [#4037](https://github.com/storybookjs/storybook/pull/4037)\n- Bring .jsx back [#4024](https://github.com/storybookjs/storybook/pull/4024)\n- Fix custom webpack config warnings [#4009](https://github.com/storybookjs/storybook/pull/4009)\n- sorting by kind and nested stories [#3963](https://github.com/storybookjs/storybook/pull/3963)\n\n#### Maintenance\n\n- Temp revert the 36a2676 [#4062](https://github.com/storybookjs/storybook/pull/4062)\n- Remove deprecation of --db-path and --enable-db [#4030](https://github.com/storybookjs/storybook/pull/4030)\n- Remove git info extraction [#4031](https://github.com/storybookjs/storybook/pull/4031)\n- Fixed homepage links \\[skip ci\\] [#4008](https://github.com/storybookjs/storybook/pull/4008)\n- CHANGE html-webpack-plugin for generate-page-plugin [#3919](https://github.com/storybookjs/storybook/pull/3919)\n\n## 4.0.0-alpha.16\n\n2018-August-06\n\n#### Features\n\n- Make addon-options work with story parameters [#3958](https://github.com/storybookjs/storybook/pull/3958)\n\n#### Bug Fixes\n\n- \\[BUG FIX\\] Use fixed version of react-dev-utils [#3959](https://github.com/storybookjs/storybook/pull/3959)\n- Inline emotion css calls that require theme to avoid using state [#3950](https://github.com/storybookjs/storybook/pull/3950)\n\n#### Dependency Upgrades\n\n- Upgrade even more dependencies [#3964](https://github.com/storybookjs/storybook/pull/3964)\n- More dependency upgrades (major version bumps) [#3957](https://github.com/storybookjs/storybook/pull/3957)\n- UPGRADE all minor dependencies [#3954](https://github.com/storybookjs/storybook/pull/3954)\n\n## 4.0.0-alpha.15\n\n2018-August-03\n\n#### Breaking Changes\n\n- dependencies(vue): Update vue-loader to 15.x.x [#3911](https://github.com/storybookjs/storybook/pull/3911)\n\n#### Features\n\n- Horizontal display for addon-knobs radios UI [#3922](https://github.com/storybookjs/storybook/pull/3922)\n- Add customizePage method to imageSnapshot [#3930](https://github.com/storybookjs/storybook/pull/3930)\n- Add additional device options to addon-viewport [#3918](https://github.com/storybookjs/storybook/pull/3918)\n- Support different extensions for \"config\" and \"addons\" files [#3913](https://github.com/storybookjs/storybook/pull/3913)\n- Add radio buttons knob type #3872 [#3894](https://github.com/storybookjs/storybook/pull/3894)\n- Added arrow to a11y addon HeaderBar [#3788](https://github.com/storybookjs/storybook/pull/3788)\n- Fix addons panel when using preact [#3882](https://github.com/storybookjs/storybook/pull/3882)\n\n#### Bug Fixes\n\n- Fix typo in addon-viewport [#3942](https://github.com/storybookjs/storybook/pull/3942)\n- Fix knobs for React < 16.3 [#3866](https://github.com/storybookjs/storybook/pull/3866)\n\n#### Maintenance\n\n- Improve BettercodeHub [#3941](https://github.com/storybookjs/storybook/pull/3941)\n- REFACTOR layout and REMOVE usplit component [#3914](https://github.com/storybookjs/storybook/pull/3914)\n- Group deprecated stories [#3846](https://github.com/storybookjs/storybook/pull/3846)\n- MOVE ui into it's own group [#3884](https://github.com/storybookjs/storybook/pull/3884)\n\n#### Dependency Upgrades\n\n- Use react-dev-utils@next [#3852](https://github.com/storybookjs/storybook/pull/3852)\n\n## 3.4.10\n\n2018-August-03\n\nNOTE: `3.4.9` publish failed\n\n#### Bug Fixes\n\n- addons-jest: bug with the jest parameter [#3923](https://github.com/storybookjs/storybook/pull/3923)\n- addon-info: fix copy button styling [#3896](https://github.com/storybookjs/storybook/pull/3896)\n\n## 4.0.0-alpha.14\n\n2018-July-11\n\n#### Bug Fixes\n\n- Upgrade universal-dotenv to fix core-js dependency [#3874](https://github.com/storybookjs/storybook/pull/3874)\n\n## 4.0.0-alpha.13\n\n2018-July-09\n\n#### Features\n\n- Refactor addon-jest to use a parameter-based pattern [#3678](https://github.com/storybookjs/storybook/pull/3678)\n\n#### Bug Fixes\n\n- Upgrade universal-dotenv to fix babel-runtime [#3863](https://github.com/storybookjs/storybook/pull/3863)\n\n#### Maintenance\n\n- Added a test for parameter combination [#3844](https://github.com/storybookjs/storybook/pull/3844)\n\n## 4.0.0-alpha.12\n\n2018-July-03\n\n#### Bug Fixes\n\n- Fix non-polyfilled themed UI components [#3829](https://github.com/storybookjs/storybook/pull/3829)\n\n## 4.0.0-alpha.11\n\n2018-July-02\n\n#### Features\n\n- Storybook UI theming [#3628](https://github.com/storybookjs/storybook/pull/3628)\n- Replaced 'dotenv-webpack' with 'universal-dotenv' to support multiple dot env files (like CRA) [#3744](https://github.com/storybookjs/storybook/pull/3744)\n- Support other type of webpack configs [#3785](https://github.com/storybookjs/storybook/pull/3785)\n\n#### Bug Fixes\n\n- Marko: fix welcome component [#3796](https://github.com/storybookjs/storybook/pull/3796)\n- Addon-a11y: Run analysis on demand [#3690](https://github.com/storybookjs/storybook/pull/3690)\n\n## 4.0.0-alpha.10\n\n2018-June-21\n\n#### Breaking Changes\n\n- Storyshots - Replace require_context.js with babel-plugin-require-context-hook [#3757](https://github.com/storybookjs/storybook/pull/3757)\n- Storyshots advanced config options [#3747](https://github.com/storybookjs/storybook/pull/3747)\n- Storyshots addon refactoring [#3745](https://github.com/storybookjs/storybook/pull/3745)\n- Extract imageSnapshots to a separate package [#3742](https://github.com/storybookjs/storybook/pull/3742)\n\n#### Bug Fixes\n\n- Addon-knobs: Allow number knob to be empty [#3775](https://github.com/storybookjs/storybook/pull/3775)\n- Improvements to Info Docgen parsing [#3772](https://github.com/storybookjs/storybook/pull/3772)\n- Angular-cli 6 assets as a glob-object compatibility fix [#3751](https://github.com/storybookjs/storybook/pull/3751)\n\n#### Maintenance\n\n- Try to fix linter issues [#3748](https://github.com/storybookjs/storybook/pull/3748)\n\n## 3.4.8\n\n2018-June-21\n\n#### Bug Fixes\n\n- Fix centered addon for IE11 [#3735](https://github.com/storybookjs/storybook/pull/3735)\n- Display functions as variables not invocations [#3761](https://github.com/storybookjs/storybook/pull/3761)\n\n## 4.0.0-alpha.9\n\n2018-June-10\n\n#### Breaking Changes\n\n- storyshots: Remove deprecated props from storyshots [#3717](https://github.com/storybookjs/storybook/pull/3717)\n- angular: angular-cli 6 (with webpack 4) compatibility [#3491](https://github.com/storybookjs/storybook/pull/3491)\n\n#### Features\n\n- addon-info: Use parameters for info addon [#3697](https://github.com/storybookjs/storybook/pull/3697)\n- addon-backgrounds: Use parameters for backgrounds addon [#3676](https://github.com/storybookjs/storybook/pull/3676)\n- storyshots: add renderWithOptions to @addons/storyshots [#3479](https://github.com/storybookjs/storybook/pull/3479)\n- addon-knobs: Make withKnobs accept story parameters [#3675](https://github.com/storybookjs/storybook/pull/3675)\n\n#### Bug Fixes\n\n- storysource: Add default parser option. Support prettier v1.13.0 [#3660](https://github.com/storybookjs/storybook/pull/3660)\n- react-native: using disableWebsockets instead of useWebsockets [#3686](https://github.com/storybookjs/storybook/pull/3686)\n- Updates storybook-start.js to use child_process instead of shelljs [#3527](https://github.com/storybookjs/storybook/pull/3527)\n- Force render on knob button click and update example [#3650](https://github.com/storybookjs/storybook/pull/3650)\n\n#### Maintenance\n\n- Refactor webpack and babel configs to core [#3655](https://github.com/storybookjs/storybook/pull/3655)\n- Remove status bar hiding [#3634](https://github.com/storybookjs/storybook/pull/3634)\n- React Native Refactored list view [#3635](https://github.com/storybookjs/storybook/pull/3635)\n- Using only single channel for react native [#3636](https://github.com/storybookjs/storybook/pull/3636)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n88 Upgrades\n</summary>\n\n- Update gatsby-plugin-sharp in /docs from \"1.6.46\" to \"1.6.47\"\n- Update gatsby-remark-images in /docs from \"1.5.65\" to \"1.5.66\"\n- Update gatsby-transformer-remark in /docs from \"1.7.41\" to \"1.7.42\"\n- Update react-router in /docs from \"4.2.0\" to \"4.3.1\"\n- Update danger in / from \"3.7.14\" to \"3.7.15\"\n- Update eslint-plugin-react in / from \"7.8.2\" to \"7.9.1\"\n- Update eslint-teamcity in / from \"2.0.0\" to \"2.0.1\"\n- Update lint-staged in / from \"7.1.2\" to \"7.1.3\"\n- Update prettier in / from \"1.13.2\" to \"1.13.4\"\n- Update remark-lint in / from \"6.0.1\" to \"6.0.2\"\n- Update remark-preset-lint-recommended in / from \"3.0.1\" to \"3.0.2\"\n- Update typescript in / from \"2.8.3\" to \"2.9.1\"\n- Update airbnb-js-shims in lib/core from \"1.5.2\" to \"1.6.0\"\n- Update autoprefixer in lib/core from \"8.5.1\" to \"8.6.0\"\n- Update babel-plugin-macros in lib/core from \"2.2.1\" to \"2.2.2\"\n- Update dotenv-webpack in lib/core from \"1.5.5\" to \"1.5.6\"\n- Update webpack in lib/core from \"4.10.1\" to \"4.10.2\"\n- Update sass-loader in app/angular from \"7.0.1\" to \"7.0.2\"\n- Update ts-loader in app/angular from \"4.3.0\" to \"4.3.1\"\n- Update axe-core in addons/a11y from \"3.0.2\" to \"3.0.3\"\n- Update moment in addons/knobs from \"2.22.1\" to \"2.22.2\"\n- Update prettier in addons/storysource from \"1.13.3\" to \"1.13.4\"\n- Update react-modal in lib/ui from \"3.4.4\" to \"3.4.5\"\n- Update babel-plugin-macros in app/react-native from \"2.2.1\" to \"2.2.2\"\n- Update dotenv-webpack in app/react-native from \"1.5.5\" to \"1.5.6\"\n- Update webpack in app/react-native from \"4.10.1\" to \"4.10.2\"\n- Update prettier in examples/marko-cli from \"1.13.2\" to \"1.13.4\"\n- Update webpack in examples/marko-cli from \"4.10.1\" to \"4.10.2\"\n- Update webpack in examples/polymer-cli from \"4.10.1\" to \"4.10.2\"\n- Update @types/jasmine in examples/angular-cli from \"2.8.7\" to \"2.8.8\"\n- Update @types/node in examples/angular-cli from \"9.6.18\" to \"9.6.20\"\n- Update ts-node in examples/angular-cli from \"6.0.5\" to \"6.1.0\"\n- Update typescript in examples/angular-cli from \"2.8.3\" to \"2.9.1\"\n- Update webpack in examples/cra-kitchen-sink from \"4.10.1\" to \"4.10.2\"\n- Update webpack in examples/mithril-kitchen-sink from \"4.10.1\" to \"4.10.2\"\n- Update webpack in examples/vue-kitchen-sink from \"4.10.1\" to \"4.10.2\"\n- Update webpack in examgatsby-plugin-sharp in /docs from \"1.6.44\" to \"1.6.46\"\n- Update gatsby-remark-copy-linked-files in /docs from \"1.5.32\" to \"1.5.35\"\n- Update gatsby-remark-images in /docs from \"1.5.63\" to \"1.5.65\"\n- Update gatsby-source-filesystem in /docs from \"1.5.36\" to \"1.5.38\"\n- Update gatsby in /docs from \"1.9.261\" to \"1.9.269\"\n- Update gh-pages in /docs from \"1.1.0\" to \"1.2.0\"\n- Update @storybook/addon-actions in /docs from \"3.4.5\" to \"3.4.6\"\n- Update @storybook/addon-links in /docs from \"3.4.5\" to \"3.4.6\"\n- Update @storybook/addons in /docs from \"3.4.5\" to \"3.4.6\"\n- Update @storybook/react in /docs from \"3.4.5\" to \"3.4.6\"\n- Update cross-env in / from \"5.1.5\" to \"5.1.6\"\n- Update eslint-plugin-jest in / from \"21.15.1\" to \"21.17.0\"\n- Update jest-enzyme in / from \"6.0.0\" to \"6.0.1\"\n- Update jest-image-snapshot in / from \"2.4.1\" to \"2.4.2\"\n- Update prettier in / from \"1.12.1\" to \"1.13.0\"\n- Update react in / from \"16.3.2\" to \"16.4.0\"\n- Update react-dom in / from \"16.3.2\" to \"16.4.0\"\n- Update react-test-renderer in / from \"16.3.2\" to \"16.4.0\"\n- Update airbnb-js-shims in lib/core from \"1.5.1\" to \"1.5.2\"\n- Update autoprefixer in lib/core from \"8.5.0\" to \"8.5.1\"\n- Update webpack in lib/core from \"4.8.3\" to \"4.9.2\"\n- Update core-js in app/angular from \"2.5.6\" to \"2.5.7\"\n- Update common-tags in app/html from \"1.7.2\" to \"1.8.0\"\n- Update common-tags in app/marko from \"1.7.2\" to \"1.8.0\"\n- Update common-tags in app/mithril from \"1.7.2\" to \"1.8.0\"\n- Update common-tags in app/polymer from \"1.7.2\" to \"1.8.0\"\n- Update common-tags in app/react from \"1.7.2\" to \"1.8.0\"\n- Update common-tags in app/vue from \"1.7.2\" to \"1.8.0\"\n- Update vue-loader in app/vue from \"14.2.2\" to \"14.2.3\"\n- Update core-js in addons/info from \"2.5.6\" to \"2.5.7\"\n- Update react-test-renderer in addons/info from \"16.3.2\" to \"16.4.0\"\n- Update prettier in addons/storysource from \"1.12.1\" to \"1.13.0\"\n- Update events in lib/ui from \"2.0.0\" to \"2.1.0\"\n- Update jest-image-snapshot in addons/storyshots from \"2.4.1\" to \"2.4.2\"\n- Update react in addons/storyshots from \"16.3.2\" to \"16.4.0\"\n- Update webpack in app/react-native from \"4.8.3\" to \"4.9.2\"\n- Update marko in examples/marko-cli from \"4.9.7\" to \"4.10.0\"\n- Update prettier in examples/marko-cli from \"1.12.1\" to \"1.13.0\"\n- Update webpack in examples/marko-cli from \"4.8.3\" to \"4.9.2\"\n- Update webpack in examples/polymer-cli from \"4.8.3\" to \"4.9.2\"\n- Update core-js in examples/angular-cli from \"2.5.6\" to \"2.5.7\"\n- Update rxjs in examples/angular-cli from \"5.5.10\" to \"5.5.11\"\n- Update ts-node in examples/angular-cli from \"6.0.3\" to \"6.0.5\"\n- Update react in examples/cra-kitchen-sink from \"16.3.2\" to \"16.4.0\"\n- Update react-dom in examples/cra-kitchen-sink from \"16.3.2\" to \"16.4.0\"\n- Update webpack in examples/cra-kitchen-sink from \"4.8.3\" to \"4.9.2\"\n- Update webpack in examples/mithril-kitchen-sink from \"4.8.3\" to \"4.9.2\"\n- Update cross-env in examples/vue-kitchen-sink from \"5.1.5\" to \"5.1.6\"\n- Update vue-loader in examples/vue-kitchen-sink from \"14.2.2\" to \"14.2.3\"\n- Update webpack in examples/vue-kitchen-sink from \"4.8.3\" to \"4.9.2\"\n- Update react in examples/official-storybook from \"16.3.2\" to \"16.4.0\"\n- Update react-dom in examples/official-storybook from \"16.3.2\" to \"16.4.0\"\n- Update webpack in examples/official-storybook from \"4.8.3\" to \"4.9.2\"\n\n</details>\n\n## 3.4.7\n\n2018-June-10\n\n#### Bug Fixes\n\n- Remove linebreaks in notes text when they are html elements [#3731](https://github.com/storybookjs/storybook/pull/3731)\n\n## 4.0.0-alpha.8\n\n2018-May-26\n\n#### Breaking Changes\n\n- Removed deprecated react-native built-in addons [#3631](https://github.com/storybookjs/storybook/pull/3631)\n- Remove deprecated addWithInfo [#3630](https://github.com/storybookjs/storybook/pull/3630)\n\n#### Bug Fixes\n\n- Fix the output of the boolean knob [#3612](https://github.com/storybookjs/storybook/pull/3612)\n- Don't scroll story on knob change [#3639](https://github.com/storybookjs/storybook/pull/3639)\n- Few fixed related to marko support [#3609](https://github.com/storybookjs/storybook/pull/3609)\n\n#### Documentation\n\n- Angular background addon example [#3653](https://github.com/storybookjs/storybook/pull/3653)\n- fix url as per issue #3565 [#3619](https://github.com/storybookjs/storybook/pull/3619)\n- Document parameters for start command for RN [#3606](https://github.com/storybookjs/storybook/pull/3606)\n- Update README.md [#3608](https://github.com/storybookjs/storybook/pull/3608)\n\n#### Maintenance\n\n- Build static storybooks utility script [#3648](https://github.com/storybookjs/storybook/pull/3648)\n- Revert \"Replace decorate with decorateAction\" [#3600](https://github.com/storybookjs/storybook/pull/3600)\n- addon-viewport: Use the new parameterized way of decorators [#3610](https://github.com/storybookjs/storybook/pull/3610)\n- Make all licenses consistent to MIT [#3611](https://github.com/storybookjs/storybook/pull/3611)\n- Theme-ability progress [#3572](https://github.com/storybookjs/storybook/pull/3572)\n- fix(knobs): cancel debounced onChange on unmounting [#3607](https://github.com/storybookjs/storybook/pull/3607)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n36 Upgrades\n</summary>\n\n- Update @angular/common from 5.2.10 to 5.2.11 in /\n- Update @angular/compiler from 5.2.10 to 5.2.11 in /\n- Update @angular/core from 5.2.10 to 5.2.11 in /\n- Update @angular/forms from 5.2.10 to 5.2.11 in /\n- Update @angular/platform-browser from 5.2.10 to 5.2.11 in /\n- Update @angular/platform-browser-dynamic from 5.2.10 to 5.2.11 in /\n- Update danger from 3.7.0 to 3.7.14 in /\n- Update eslint-plugin-import from 2.11.0 to 2.12.0 in /\n- Update jest from 22.4.3 to 22.4.4 in /\n- Update jest-cli from 22.4.3 to 22.4.4 in /\n- Update jest-config from 22.4.3 to 22.4.4 in /\n- Update jest-jasmine2 from 22.4.3 to 22.4.4 in /\n- Update lint-staged from 7.1.0 to 7.1.2 in /\n- Update marked from 0.3.19 to 0.4.0 in addons/notes\n- Update tslint-config-prettier from 1.12.0 to 1.13.0 in /\n- Update airbnb-js-shims from 1.4.1 to 1.5.1 in app/angular\n- Update airbnb-js-shims from 1.4.1 to 1.5.1 in app/html\n- Update airbnb-js-shims from 1.4.1 to 1.5.1 in app/mithril\n- Update babel-preset-minify from 0.4.1 to 0.4.3 in app/polymer\n- Update airbnb-js-shims from 1.4.1 to 1.5.1 in app/polymer\n- Update airbnb-js-shims from 1.4.1 to 1.5.1 in app/react\n- Update airbnb-js-shims from 1.4.1 to 1.5.1 in app/vue\n- Update enzyme-to-json from 3.3.3 to 3.3.4 in addons/storyshots\n- Update airbnb-js-shims from 1.4.1 to 1.5.1 in app/marko\n- Update ws from 5.1.1 to 5.2.0 in app/react-native\n- Update @angular/common from 5.2.10 to 5.2.11 in examples/angular-cli\n- Update @angular/compiler from 5.2.10 to 5.2.11 in examples/angular-cli\n- Update @angular/core from 5.2.10 to 5.2.11 in examples/angular-cli\n- Update @angular/forms from 5.2.10 to 5.2.11 in examples/angular-cli\n- Update @angular/platform-browser from 5.2.10 to 5.2.11 in examples/an… …\n- Update @angular/platform-browser-dynamic from 5.2.10 to 5.2.11 in exa… …\n- Update @angular/compiler-cli from 5.2.10 to 5.2.11 in examples/angula… …\n- Update @types/node from 9.6.17 to 9.6.18 in examples/angular-cli\n- Update jest from 22.4.3 to 22.4.4 in examples/angular-cli\n- Update enzyme-to-json from 3.3.3 to 3.3.4 in examples/cra-kitchen-sink\n- Update jest from 22.4.3 to 22.4.4 in examples/html-kitchen-sink\n- Update enzyme-to-json from 3.3.3 to 3.3.4 in examples/official-storybook\n\n</details>\n\n## 3.4.6\n\n2018-May-26\n\n#### Features\n\n- Addon-notes: Add classname to the container component to target with styles. [#3617](https://github.com/storybookjs/storybook/pull/3617)\n\n## 4.0.0-alpha.7\n\n2018-May-17\n\nNOTE: As part of the generic addon decorators, we've reversed the order of addon-knob's `select` knob keys/values, which had been called `selectV2` prior to this breaking change.\n\n#### Breaking Changes\n\n- Support webpack4 modules format [#3576](https://github.com/storybookjs/storybook/pull/3576)\n- Generic addon decorators [#3555](https://github.com/storybookjs/storybook/pull/3555)\n\n#### Features\n\n- Addon-centered for Angular [#3573](https://github.com/storybookjs/storybook/pull/3573)\n\n#### Maintenance\n\n- Refactor transitional decorator from addon-notes [#3559](https://github.com/storybookjs/storybook/pull/3559)\n\n## 3.4.5\n\n2018-May-17\n\n#### Features\n\n- Addon-info: improve prop options [#3428](https://github.com/storybookjs/storybook/pull/3428)\n\n#### Bug Fixes\n\n- Addon-storysource: Remove nested braces in code block [#3568](https://github.com/storybookjs/storybook/pull/3568)\n- Addon-info: Fix double quotes in prop table, add additional examples [#3401](https://github.com/storybookjs/storybook/pull/3401)\n- Ignore any unstructured output from the package managers [#3563](https://github.com/storybookjs/storybook/pull/3563)\n- Use the --use-npm flag also for version checking [#3535](https://github.com/storybookjs/storybook/pull/3535)\n\n## 4.0.0-alpha.6\n\n2018-May-12\n\n#### Breaking Changes\n\n- Fix the import of external md files [#3472](https://github.com/storybookjs/storybook/pull/3472)\n\n#### Features\n\n- Storybook for Marko [#3504](https://github.com/storybookjs/storybook/pull/3504)\n- Storybook addon Jest angular support [#3532](https://github.com/storybookjs/storybook/pull/3532)\n- Storybook for HTML snippets [#3475](https://github.com/storybookjs/storybook/pull/3475)\n- Feature/config custom chrome executable path [#3518](https://github.com/storybookjs/storybook/pull/3518)\n- Channel-postmessage: handle events from the same window [#3519](https://github.com/storybookjs/storybook/pull/3519)\n- Force re-render event [#3515](https://github.com/storybookjs/storybook/pull/3515)\n\n#### Bug Fixes\n\n- Ignore any unstructured output from the package managers [#3563](https://github.com/storybookjs/storybook/pull/3563)\n- Use the --use-npm flag also for version checking [#3535](https://github.com/storybookjs/storybook/pull/3535)\n- Clean out the store if `configure` fails [#3558](https://github.com/storybookjs/storybook/pull/3558)\n- Fix render order in preview [#3520](https://github.com/storybookjs/storybook/pull/3520)\n\n## 4.0.0-alpha.5\n\nBroken release (@storybook/core-events had not been published publicly)\n\n## 3.4.4\n\n2018-May-12\n\n#### Bug Fixes\n\n- Ignore home package.json no license field [#3531](https://github.com/storybookjs/storybook/pull/3531)\n- fixed Duplicate declaration h [#3409](https://github.com/storybookjs/storybook/pull/3409)\n- Storyshots integrity tests options [#3418](https://github.com/storybookjs/storybook/pull/3418)\n- Fix dynamic knobs [d2a289e](https://github.com/storybookjs/storybook/commit/d2a289e524c51e794f5f3a34164a69ba3d5409fa)\n\n#### Dependency Upgrades\n\n- jest-image-snapshot version to ^2.4.1 [#3500](https://github.com/storybookjs/storybook/pull/3500)\n\n## 4.0.0-alpha.4\n\n2018-April-27\n\n#### Breaking Changes\n\n- Knobs: add escapeHTML option; use it by default in Vue, Angular, and Polymer [#3473](https://github.com/storybookjs/storybook/pull/3473)\n\n#### Features\n\n- Added `actions` to addon-actions to create multiple actions [#3352](https://github.com/storybookjs/storybook/pull/3352)\n- Add excludedPropTypes as an option to info addon [#3468](https://github.com/storybookjs/storybook/pull/3468)\n- Addon-background: add Vue support [#3488](https://github.com/storybookjs/storybook/pull/3488)\n- Suppress verbose build output [#3487](https://github.com/storybookjs/storybook/pull/3487)\n- Provide a configuration option to limit the number of actions logged [#3447](https://github.com/storybookjs/storybook/pull/3447)\n- Add IStory interface. [#3482](https://github.com/storybookjs/storybook/pull/3482)\n- Add option to clear action logger [#3459](https://github.com/storybookjs/storybook/pull/3459)\n\n#### Bug Fixes\n\n- Fix auto focus of searchbox [#3494](https://github.com/storybookjs/storybook/pull/3494)\n- Don't try to access the devtools hook if we are cross-origin [#3485](https://github.com/storybookjs/storybook/pull/3485)\n- Improve yarn detection [#3453](https://github.com/storybookjs/storybook/pull/3453)\n\n#### Maintenance\n\n- Refactor error and \"no preview\" views into core [#3457](https://github.com/storybookjs/storybook/pull/3457)\n- Refactor templates into core [#3422](https://github.com/storybookjs/storybook/pull/3422)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n15 Upgrades\n</summary>\n\n- Upgraded `@storybook/addon-actions` in `/docs` from \"3.4.1\" to \"3.4.2\" [#3478](https://github.com/storybookjs/storybook/pull/3478)\n- Upgraded `@storybook/addon-links` in `/docs` from \"3.4.1\" to \"3.4.2\" [#3478](https://github.com/storybookjs/storybook/pull/3478)\n- Upgraded `@storybook/addons` in `/docs` from \"3.4.1\" to \"3.4.2\" [#3478](https://github.com/storybookjs/storybook/pull/3478)\n- Upgraded `@storybook/react` in `/docs` from \"3.4.1\" to \"3.4.2\" [#3478](https://github.com/storybookjs/storybook/pull/3478)\n- Upgraded `gatsby-link` in `/docs` from \"1.6.40\" to \"1.6.41\" [#3478](https://github.com/storybookjs/storybook/pull/3478)\n- Upgraded `gatsby-plugin-sharp` in `/docs` from \"1.6.42\" to \"1.6.43\" [#3478](https://github.com/storybookjs/storybook/pull/3478)\n- Upgraded `gatsby-remark-autolink-headers` in `/docs` from \"1.4.16\" to \"1.4.17\" [#3478](https://github.com/storybookjs/storybook/pull/3478)\n- Upgraded `gatsby-remark-copy-linked-files` in `/docs` from \"1.5.31\" to \"1.5.32\" [#3478](https://github.com/storybookjs/storybook/pull/3478)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.61\" to \"1.5.62\" [#3478](https://github.com/storybookjs/storybook/pull/3478)\n- Upgraded `gatsby` in `/docs` from \"1.9.252\" to \"1.9.253\" [#3478](https://github.com/storybookjs/storybook/pull/3478)\n- Upgrade redux to 4.0.0 [#3470](https://github.com/storybookjs/storybook/pull/3470)\n- Upgrade sass-loader to 7.0.1 & stop bringing node-sass bin to each user [#3467](https://github.com/storybookjs/storybook/pull/3467)\n- Upgrade ts-node to 6.0.0 [#3460](https://github.com/storybookjs/storybook/pull/3460)\n- Upgrade to json5@1.0.1 [#3466](https://github.com/storybookjs/storybook/pull/3466)\n- Update webpack-hot-middleware to fix HMR [#3463](https://github.com/storybookjs/storybook/pull/3463)\n\n</details>\n\n## 3.4.3\n\n2018-April-27\n\n#### Features\n\n- Suppress verbose build output [#3487](https://github.com/storybookjs/storybook/pull/3487)\n\n#### Bug Fixes\n\n- Improve yarn detection [#3453](https://github.com/storybookjs/storybook/pull/3453)\n- Don't try to access the devtools hook if we are cross-origin [#3485](https://github.com/storybookjs/storybook/pull/3485)\n\n#### Dependency Upgrades\n\n- Update webpack-hot-middleware to fix HMR [#3463](https://github.com/storybookjs/storybook/pull/3463)\n\n## 4.0.0-alpha.3\n\n2018-April-17\n\nAlso includes changes from 3.4.2\n\n#### Features\n\n- Mobile device view: toggling stories panel with ☰ button [#3337](https://github.com/storybookjs/storybook/pull/3337)\n- Add lit-html support [#3433](https://github.com/storybookjs/storybook/pull/3433)\n- Addon info prop options [#3428](https://github.com/storybookjs/storybook/pull/3428)\n- Use per-story parameters in Notes addon [#3373](https://github.com/storybookjs/storybook/pull/3373)\n\n#### Bug Fixes\n\n- Fixed Duplicate declaration h [#3409](https://github.com/storybookjs/storybook/pull/3409)\n- Storyshots integrity tests options [#3418](https://github.com/storybookjs/storybook/pull/3418)\n- Debounce Knob input to improve performance, fix number Knob undefined/NaN [#3412](https://github.com/storybookjs/storybook/pull/3412)\n- Fix double quotes in prop table and add additional examples [#3401](https://github.com/storybookjs/storybook/pull/3401)\n\n#### Documentation\n\n- doc(addon-jest): fix option name [#3420](https://github.com/storybookjs/storybook/pull/3420)\n- Storyshots integrity tests fixes - README [#3419](https://github.com/storybookjs/storybook/pull/3419)\n\n#### Maintenance\n\n- viewport-addon: configure => configureViewport [#3414](https://github.com/storybookjs/storybook/pull/3414)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n94 Upgrades\n</summary>\n\n- Upgraded `chalk` in `/` from \"2.3.2\" to \"2.4.0\" [#3440](https://github.com/storybookjs/storybook/pull/3440)\n- Upgraded `danger` in `/` from \"3.4.7\" to \"3.5.1\" [#3440](https://github.com/storybookjs/storybook/pull/3440)\n- Upgraded `prettier` in `/` from \"1.12.0\" to \"1.12.1\" [#3440](https://github.com/storybookjs/storybook/pull/3440)\n- Upgraded `webpack` in `app/react` from \"4.5.0\" to \"4.6.0\" [#3440](https://github.com/storybookjs/storybook/pull/3440)\n- Upgraded `prettier` in `addons/storysource` from \"1.12.0\" to \"1.12.1\" [#3440](https://github.com/storybookjs/storybook/pull/3440)\n- Upgraded `react-modal` in `lib/ui` from \"3.3.2\" to \"3.4.1\" [#3440](https://github.com/storybookjs/storybook/pull/3440)\n- Upgraded `chalk` in `lib/core` from \"2.3.2\" to \"2.4.0\" [#3440](https://github.com/storybookjs/storybook/pull/3440)\n- Upgraded `webpack` in `lib/core` from \"4.5.0\" to \"4.6.0\" [#3440](https://github.com/storybookjs/storybook/pull/3440)\n- Upgraded `webpack` in `app/angular` from \"4.5.0\" to \"4.6.0\" [#3440](https://github.com/storybookjs/storybook/pull/3440)\n- Upgraded `webpack` in `app/mithril` from \"4.5.0\" to \"4.6.0\" [#3440](https://github.com/storybookjs/storybook/pull/3440)\n- Upgraded `webpack` in `app/polymer` from \"4.5.0\" to \"4.6.0\" [#3440](https://github.com/storybookjs/storybook/pull/3440)\n- Upgraded `webpack` in `app/react-native` from \"4.5.0\" to \"4.6.0\" [#3440](https://github.com/storybookjs/storybook/pull/3440)\n- Upgraded `webpack` in `app/vue` from \"4.5.0\" to \"4.6.0\" [#3440](https://github.com/storybookjs/storybook/pull/3440)\n- Upgraded `chalk` in `lib/cli` from \"2.3.2\" to \"2.4.0\" [#3440](https://github.com/storybookjs/storybook/pull/3440)\n- Upgraded `webpack` in `examples/cra-kitchen-sink` from \"4.5.0\" to \"4.6.0\" [#3440](https://github.com/storybookjs/storybook/pull/3440)\n- Upgraded `webpack` in `examples/mithril-kitchen-sink` from \"4.5.0\" to \"4.6.0\" [#3440](https://github.com/storybookjs/storybook/pull/3440)\n- Upgraded `webpack` in `examples/polymer-cli` from \"4.5.0\" to \"4.6.0\" [#3440](https://github.com/storybookjs/storybook/pull/3440)\n- Upgraded `webpack` in `examples/vue-kitchen-sink` from \"4.5.0\" to \"4.6.0\" [#3440](https://github.com/storybookjs/storybook/pull/3440)\n- Upgraded `gatsby-source-filesystem` in `/docs` from \"1.5.32\" to \"1.5.33\" [#3439](https://github.com/storybookjs/storybook/pull/3439)\n- Upgraded `gatsby` in `/docs` from \"1.9.251\" to \"1.9.252\" [#3439](https://github.com/storybookjs/storybook/pull/3439)\n- Update lerna in / from 2.10.1 to 2.10.2 [#3431](https://github.com/storybookjs/storybook/pull/3431)\n- Update gatsby in /docs from 1.9.250 to 1.9.251 [#3430](https://github.com/storybookjs/storybook/pull/3430)\n- Upgraded `@angular/common` in `/` from \"5.2.9\" to \"5.2.10\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `@angular/compiler` in `/` from \"5.2.9\" to \"5.2.10\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `@angular/core` in `/` from \"5.2.9\" to \"5.2.10\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `@angular/forms` in `/` from \"5.2.9\" to \"5.2.10\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `@angular/platform-browser` in `/` from \"5.2.9\" to \"5.2.10\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `@angular/platform-browser-dynamic` in `/` from \"5.2.9\" to \"5.2.10\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `babel-eslint` in `/` from \"8.2.2\" to \"8.2.3\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `danger` in `/` from \"3.4.5\" to \"3.4.7\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `eslint-plugin-import` in `/` from \"2.10.0\" to \"2.11.0\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `lerna` in `/` from \"2.10.0\" to \"2.10.1\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `prettier` in `/` from \"1.11.1\" to \"1.12.0\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react` in `/` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react-dom` in `/` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react-test-renderer` in `/` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react-dom` in `addons/centered` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react-lifecycles-compat` in `addons/background` from \"3.0.0\" to \"3.0.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react-lifecycles-compat` in `addons/events` from \"3.0.0\" to \"3.0.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `glamorous` in `app/react` from \"4.12.1\" to \"4.12.3\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `@types/react` in `addons/notes` from \"16.3.5\" to \"16.3.11\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `glamorous` in `addons/actions` from \"4.12.1\" to \"4.12.3\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react-inspector` in `addons/actions` from \"2.2.2\" to \"2.3.0\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `glamorous` in `lib/components` from \"4.12.1\" to \"4.12.3\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `glamorous` in `addons/a11y` from \"4.12.1\" to \"4.12.3\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `glamorous` in `addons/info` from \"4.12.1\" to \"4.12.3\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react-lifecycles-compat` in `addons/info` from \"3.0.0\" to \"3.0.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react-test-renderer` in `addons/info` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `glamorous` in `addons/jest` from \"4.12.1\" to \"4.12.3\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `moment` in `addons/knobs` from \"2.22.0\" to \"2.22.1\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react-color` in `addons/knobs` from \"2.14.0\" to \"2.14.1\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react-lifecycles-compat` in `addons/knobs` from \"3.0.0\" to \"3.0.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react` in `addons/links` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react-dom` in `addons/links` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `prettier` in `addons/storysource` from \"1.11.1\" to \"1.12.0\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react-lifecycles-compat` in `lib/ui` from \"3.0.0\" to \"3.0.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `autoprefixer` in `lib/core` from \"8.2.0\" to \"8.3.0\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `postcss-loader` in `lib/core` from \"2.1.3\" to \"2.1.4\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `puppeteer` in `addons/storyshots` from \"1.2.0\" to \"1.3.0\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react` in `addons/storyshots` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react-dom` in `addons/storyshots` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react` in `app/angular` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react-dom` in `app/angular` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react` in `app/mithril` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react-dom` in `app/mithril` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react` in `app/polymer` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react-dom` in `app/polymer` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react` in `app/vue` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react-dom` in `app/vue` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `update-notifier` in `lib/cli` from \"2.4.0\" to \"2.5.0\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `npx` in `lib/cli` from \"10.0.1\" to \"10.2.0\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `@angular/common` in `examples/angular-cli` from \"5.2.9\" to \"5.2.10\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `@angular/compiler` in `examples/angular-cli` from \"5.2.9\" to \"5.2.10\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `@angular/core` in `examples/angular-cli` from \"5.2.9\" to \"5.2.10\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `@angular/forms` in `examples/angular-cli` from \"5.2.9\" to \"5.2.10\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `@angular/platform-browser` in `examples/angular-cli` from \"5.2.9\" to \"5.2.10\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `@angular/platform-browser-dynamic` in `examples/angular-cli` from \"5.2.9\" to \"5.2.10\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `rxjs` in `examples/angular-cli` from \"5.5.8\" to \"5.5.10\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `@angular/compiler-cli` in `examples/angular-cli` from \"5.2.9\" to \"5.2.10\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `@types/node` in `examples/angular-cli` from \"9.6.2\" to \"9.6.5\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react` in `examples/cra-kitchen-sink` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react-dom` in `examples/cra-kitchen-sink` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react-lifecycles-compat` in `examples/cra-kitchen-sink` from \"3.0.0\" to \"3.0.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react` in `examples/official-storybook` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `react-dom` in `examples/official-storybook` from \"16.3.1\" to \"16.3.2\" [#3429](https://github.com/storybookjs/storybook/pull/3429)\n- Upgraded `@storybook/addon-actions` in `/docs` from \"3.4.0\" to \"3.4.1\" [#3426](https://github.com/storybookjs/storybook/pull/3426)\n- Upgraded `@storybook/addon-links` in `/docs` from \"3.4.0\" to \"3.4.1\" [#3426](https://github.com/storybookjs/storybook/pull/3426)\n- Upgraded `@storybook/addons` in `/docs` from \"3.4.0\" to \"3.4.1\" [#3426](https://github.com/storybookjs/storybook/pull/3426)\n- Upgraded `@storybook/react` in `/docs` from \"3.4.0\" to \"3.4.1\" [#3426](https://github.com/storybookjs/storybook/pull/3426)\n- Upgraded `gatsby-plugin-sharp` in `/docs` from \"1.6.41\" to \"1.6.42\" [#3426](https://github.com/storybookjs/storybook/pull/3426)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.60\" to \"1.5.61\" [#3426](https://github.com/storybookjs/storybook/pull/3426)\n- Upgraded `gatsby-source-filesystem` in `/docs` from \"1.5.29\" to \"1.5.32\" [#3426](https://github.com/storybookjs/storybook/pull/3426)\n- Upgraded `gatsby-transformer-remark` in `/docs` from \"1.7.39\" to \"1.7.40\" [#3426](https://github.com/storybookjs/storybook/pull/3426)\n- Upgraded `gatsby` in `/docs` from \"1.9.247\" to \"1.9.250\" [#3426](https://github.com/storybookjs/storybook/pull/3426)\n\n</details>\n\n## 3.4.2\n\n2018-April-17\n\n#### Bug Fixes\n\n- Serialize boolean type only for non-nullable values [#3432](https://github.com/storybookjs/storybook/pull/3432)\n- Addon actions: fix slow logging [#3133](https://github.com/storybookjs/storybook/pull/3133)\n\n#### Documentation\n\n- Fix storyshots readme for image snapshotting [#3397](https://github.com/storybookjs/storybook/pull/3397)\n\n## 4.0.0-alpha.2\n\n2018-April-10\n\nAlso includes changes from 3.4.1\n\n#### Breaking Changes\n\n- Change addon panel keyboard shortcut to shift-meta-z [#3378](https://github.com/storybookjs/storybook/pull/3378)\n- Move server/config to core [#3261](https://github.com/storybookjs/storybook/pull/3261)\n\n#### Features\n\n- React native Typescript transform [#3209](https://github.com/storybookjs/storybook/pull/3209)\n- Split vendor and runtime chunk in static builds [#3316](https://github.com/storybookjs/storybook/pull/3316)\n- Persist background for @addon/background [#3331](https://github.com/storybookjs/storybook/pull/3331)\n- feat(notes): add marked options [#3225](https://github.com/storybookjs/storybook/pull/3225)\n\n#### Bug Fixes\n\n- Enforce addons store being a singleton by storing it in global variable [#3383](https://github.com/storybookjs/storybook/pull/3383)\n- Scroll to top of the page when changing story [#3338](https://github.com/storybookjs/storybook/pull/3338)\n- Fix HtmlWebpackPlugin error [#3328](https://github.com/storybookjs/storybook/pull/3328)\n\n#### Maintenance\n\n- Remove usages of deprecated React lifecycle methods [#3327](https://github.com/storybookjs/storybook/pull/3327)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n142 Updates\n</summary>\n\n- Migrate to react-lifecycles-compat@3 [#3392](https://github.com/storybookjs/storybook/pull/3392)\n- Upgrade dev dependencies in Angular example [#3391](https://github.com/storybookjs/storybook/pull/3391)\n- Upgraded `gatsby-remark-copy-linked-files` in `/docs` from \"1.5.30\" to \"1.5.31\" [#3388](https://github.com/storybookjs/storybook/pull/3388)\n- Upgraded `gatsby-source-filesystem` in `/docs` from \"1.5.28\" to \"1.5.29\" [#3388](https://github.com/storybookjs/storybook/pull/3388)\n- Upgraded `gatsby` in `/docs` from \"1.9.246\" to \"1.9.247\" [#3388](https://github.com/storybookjs/storybook/pull/3388)\n- Upgraded `lerna` in `/` from \"2.9.1\" to \"2.10.0\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `babel-preset-minify` in `app/react` from \"0.3.0\" to \"0.4.0\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `core-js` in `app/react` from \"2.5.4\" to \"2.5.5\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `webpack-hot-middleware` in `app/react` from \"2.21.2\" to \"2.22.0\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `webpack-dev-middleware` in `lib/core` from \"3.1.1\" to \"3.1.2\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `webpack-hot-middleware` in `lib/core` from \"2.21.2\" to \"2.22.0\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `core-js` in `app/angular` from \"2.5.4\" to \"2.5.5\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `ts-loader` in `app/angular` from \"4.1.0\" to \"4.2.0\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `webpack-hot-middleware` in `app/angular` from \"2.21.2\" to \"2.22.0\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `zone.js` in `app/angular` from \"0.8.25\" to \"0.8.26\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `babel-preset-minify` in `app/mithril` from \"0.3.0\" to \"0.4.0\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `core-js` in `app/mithril` from \"2.5.4\" to \"2.5.5\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `webpack-hot-middleware` in `app/mithril` from \"2.21.2\" to \"2.22.0\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `@webcomponents/webcomponentsjs` in `app/polymer` from \"1.1.1\" to \"1.2.0\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `babel-preset-minify` in `app/polymer` from \"0.3.0\" to \"0.4.0\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `core-js` in `app/polymer` from \"2.5.4\" to \"2.5.5\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `webpack-hot-middleware` in `app/polymer` from \"2.21.2\" to \"2.22.0\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `babel-preset-minify` in `app/react-native` from \"0.3.0\" to \"0.4.0\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `url-parse` in `app/react-native` from \"1.2.0\" to \"1.3.0\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `webpack-dev-middleware` in `app/react-native` from \"3.1.1\" to \"3.1.2\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `webpack-hot-middleware` in `app/react-native` from \"2.21.2\" to \"2.22.0\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `babel-preset-minify` in `app/vue` from \"0.3.0\" to \"0.4.0\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `core-js` in `app/vue` from \"2.5.4\" to \"2.5.5\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `webpack-hot-middleware` in `app/vue` from \"2.21.2\" to \"2.22.0\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `core-js` in `examples/angular-cli` from \"2.5.4\" to \"2.5.5\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `zone.js` in `examples/angular-cli` from \"0.8.25\" to \"0.8.26\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `@angular/cli` in `examples/angular-cli` from \"1.7.3\" to \"1.7.4\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `@webcomponents/webcomponentsjs` in `examples/polymer-cli` from \"1.1.1\" to \"1.2.0\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `webpack-dev-server` in `examples/polymer-cli` from \"3.1.1\" to \"3.1.3\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `webpack-dev-server` in `examples/vue-kitchen-sink` from \"3.1.1\" to \"3.1.3\" [#3387](https://github.com/storybookjs/storybook/pull/3387)\n- Upgraded `lint-staged` in `/` from \"7.0.3\" to \"7.0.4\" [#3368](https://github.com/storybookjs/storybook/pull/3368)\n- Upgraded `webpack-dev-middleware` in `lib/core` from \"3.1.0\" to \"3.1.1\" [#3368](https://github.com/storybookjs/storybook/pull/3368)\n- Upgraded `webpack-dev-middleware` in `app/react-native` from \"3.1.0\" to \"3.1.1\" [#3368](https://github.com/storybookjs/storybook/pull/3368)\n- Upgraded `react` in `/` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react-dom` in `/` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react-test-renderer` in `/` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react-dom` in `addons/centered` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `webpack` in `app/react` from \"4.4.1\" to \"4.5.0\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `@types/react` in `addons/notes` from \"16.3.4\" to \"16.3.5\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react-test-renderer` in `addons/info` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react` in `addons/links` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react-dom` in `addons/links` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `webpack` in `lib/core` from \"4.4.1\" to \"4.5.0\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react` in `addons/storyshots` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react-dom` in `addons/storyshots` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react` in `app/angular` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react-dom` in `app/angular` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `webpack` in `app/angular` from \"4.4.1\" to \"4.5.0\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `zone.js` in `app/angular` from \"0.8.24\" to \"0.8.25\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react` in `app/mithril` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react-dom` in `app/mithril` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `webpack` in `app/mithril` from \"4.4.1\" to \"4.5.0\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react` in `app/polymer` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react-dom` in `app/polymer` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `webpack` in `app/polymer` from \"4.4.1\" to \"4.5.0\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `webpack` in `app/react-native` from \"4.4.1\" to \"4.5.0\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react` in `app/vue` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react-dom` in `app/vue` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `webpack` in `app/vue` from \"4.4.1\" to \"4.5.0\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `zone.js` in `examples/angular-cli` from \"0.8.24\" to \"0.8.25\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `protractor` in `examples/angular-cli` from \"5.3.0\" to \"5.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react` in `examples/cra-kitchen-sink` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react-dom` in `examples/cra-kitchen-sink` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react-scripts` in `examples/cra-kitchen-sink` from \"1.1.3\" to \"1.1.4\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `webpack` in `examples/cra-kitchen-sink` from \"4.4.1\" to \"4.5.0\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `webpack` in `examples/mithril-kitchen-sink` from \"4.4.1\" to \"4.5.0\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `webpack` in `examples/polymer-cli` from \"4.4.1\" to \"4.5.0\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `webpack` in `examples/vue-kitchen-sink` from \"4.4.1\" to \"4.5.0\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react` in `examples/official-storybook` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `react-dom` in `examples/official-storybook` from \"16.3.0\" to \"16.3.1\" [#3357](https://github.com/storybookjs/storybook/pull/3357)\n- Upgraded `gatsby-remark-autolink-headers` in `/docs` from \"1.4.15\" to \"1.4.16\" [#3356](https://github.com/storybookjs/storybook/pull/3356)\n- Upgraded `gatsby` in `/docs` from \"1.9.244\" to \"1.9.246\" [#3356](https://github.com/storybookjs/storybook/pull/3356)\n- Upgraded `danger` in `/` from \"3.4.4\" to \"3.4.5\" [#3350](https://github.com/storybookjs/storybook/pull/3350)\n- Upgraded `lint-staged` in `/` from \"7.0.2\" to \"7.0.3\" [#3350](https://github.com/storybookjs/storybook/pull/3350)\n- Upgraded `react-lifecycles-compat` in `addons/background` from \"1.1.1\" to \"1.1.4\" [#3350](https://github.com/storybookjs/storybook/pull/3350)\n- Upgraded `react-lifecycles-compat` in `addons/events` from \"1.1.1\" to \"1.1.4\" [#3350](https://github.com/storybookjs/storybook/pull/3350)\n- Upgraded `html-webpack-plugin` in `app/react` from \"3.1.0\" to \"3.2.0\" [#3350](https://github.com/storybookjs/storybook/pull/3350)\n- Upgraded `@types/react` in `addons/notes` from \"16.3.1\" to \"16.3.4\" [#3350](https://github.com/storybookjs/storybook/pull/3350)\n- Upgraded `axe-core` in `addons/a11y` from \"3.0.0\" to \"3.0.1\" [#3350](https://github.com/storybookjs/storybook/pull/3350)\n- Upgraded `react-lifecycles-compat` in `addons/info` from \"1.1.1\" to \"1.1.4\" [#3350](https://github.com/storybookjs/storybook/pull/3350)\n- Upgraded `react-lifecycles-compat` in `addons/knobs` from \"1.1.1\" to \"1.1.4\" [#3350](https://github.com/storybookjs/storybook/pull/3350)\n- Upgraded `react-lifecycles-compat` in `lib/ui` from \"1.1.1\" to \"1.1.4\" [#3350](https://github.com/storybookjs/storybook/pull/3350)\n- Upgraded `html-webpack-plugin` in `app/angular` from \"3.1.0\" to \"3.2.0\" [#3350](https://github.com/storybookjs/storybook/pull/3350)\n- Upgraded `html-webpack-plugin` in `app/mithril` from \"3.1.0\" to \"3.2.0\" [#3350](https://github.com/storybookjs/storybook/pull/3350)\n- Upgraded `html-webpack-plugin` in `app/polymer` from \"3.1.0\" to \"3.2.0\" [#3350](https://github.com/storybookjs/storybook/pull/3350)\n- Upgraded `html-webpack-plugin` in `app/react-native` from \"3.1.0\" to \"3.2.0\" [#3350](https://github.com/storybookjs/storybook/pull/3350)\n- Upgraded `html-webpack-plugin` in `app/vue` from \"3.1.0\" to \"3.2.0\" [#3350](https://github.com/storybookjs/storybook/pull/3350)\n- Upgraded `@types/node` in `examples/angular-cli` from \"9.6.1\" to \"9.6.2\" [#3350](https://github.com/storybookjs/storybook/pull/3350)\n- Upgraded `react-lifecycles-compat` in `examples/cra-kitchen-sink` from \"1.1.1\" to \"1.1.4\" [#3350](https://github.com/storybookjs/storybook/pull/3350)\n- Upgraded `react-scripts` in `examples/cra-kitchen-sink` from \"1.1.1\" to \"1.1.3\" [#3350](https://github.com/storybookjs/storybook/pull/3350)\n- Upgraded `html-webpack-plugin` in `examples/polymer-cli` from \"3.1.0\" to \"3.2.0\" [#3350](https://github.com/storybookjs/storybook/pull/3350)\n- Update gatsby-source-filesystem in /docs from 1.5.27 to 1.5.28 [#3349](https://github.com/storybookjs/storybook/pull/3349)\n- Update gatsby in /docs from 1.9.243 to 1.9.244 [#3345](https://github.com/storybookjs/storybook/pull/3345)\n- Upgraded `danger` in `/` from \"3.3.2\" to \"3.4.4\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `eslint-plugin-import` in `/` from \"2.9.0\" to \"2.10.0\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `lerna` in `/` from \"2.5.1\" to \"2.9.1\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `lint-staged` in `/` from \"7.0.0\" to \"7.0.2\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `react-lifecycles-compat` in `addons/background` from \"1.1.0\" to \"1.1.1\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `react-lifecycles-compat` in `addons/events` from \"1.1.0\" to \"1.1.1\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `react-textarea-autosize` in `addons/events` from \"6.1.0-0\" to \"6.1.0\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `babel-plugin-react-docgen` in `app/react` from \"1.8.3\" to \"1.9.0\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `nodemon` in `app/react` from \"1.17.2\" to \"1.17.3\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `@types/react` in `addons/notes` from \"16.1.0\" to \"16.3.1\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `react-lifecycles-compat` in `addons/info` from \"1.1.0\" to \"1.1.1\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `moment` in `addons/knobs` from \"2.21.0\" to \"2.22.0\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `react-lifecycles-compat` in `addons/knobs` from \"1.1.0\" to \"1.1.1\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `react-textarea-autosize` in `addons/knobs` from \"6.1.0-0\" to \"6.1.0\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `react-lifecycles-compat` in `lib/ui` from \"1.1.0\" to \"1.1.1\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `serve-favicon` in `lib/core` from \"2.4.5\" to \"2.5.0\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `zone.js` in `app/angular` from \"0.8.20\" to \"0.8.24\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `nodemon` in `app/angular` from \"1.17.2\" to \"1.17.3\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `nodemon` in `app/mithril` from \"1.17.2\" to \"1.17.3\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `nodemon` in `app/polymer` from \"1.17.2\" to \"1.17.3\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `ws` in `app/react-native` from \"5.1.0\" to \"5.1.1\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `nodemon` in `app/vue` from \"1.17.2\" to \"1.17.3\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `react-lifecycles-compat` in `examples/cra-kitchen-sink` from \"1.1.0\" to \"1.1.1\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Upgraded `zone.js` in `examples/angular-cli` from \"0.8.20\" to \"0.8.24\" [#3343](https://github.com/storybookjs/storybook/pull/3343)\n- Migrate to axe-core@3.0.0 [#3332](https://github.com/storybookjs/storybook/pull/3332)\n- Migrate to ws@5 [#3334](https://github.com/storybookjs/storybook/pull/3334)\n- Upgraded `@storybook/addon-actions` in `/docs` from \"3.3.15\" to \"3.4.0\" [#3325](https://github.com/storybookjs/storybook/pull/3325)\n- Upgraded `@storybook/addon-links` in `/docs` from \"3.3.15\" to \"3.4.0\" [#3325](https://github.com/storybookjs/storybook/pull/3325)\n- Upgraded `@storybook/addons` in `/docs` from \"3.3.15\" to \"3.4.0\" [#3325](https://github.com/storybookjs/storybook/pull/3325)\n- Upgraded `@storybook/react` in `/docs` from \"3.3.15\" to \"3.4.0\" [#3325](https://github.com/storybookjs/storybook/pull/3325)\n- Update gatsby-remark-autolink-headers in /docs from 1.4.13 to 1.4.15 [#3314](https://github.com/storybookjs/storybook/pull/3314)\n- Upgraded `webpack` in `app/react` from \"4.3.0\" to \"4.4.1\" [#3315](https://github.com/storybookjs/storybook/pull/3315)\n- Upgraded `webpack` in `lib/core` from \"4.3.0\" to \"4.4.1\" [#3315](https://github.com/storybookjs/storybook/pull/3315)\n- Upgraded `webpack` in `app/angular` from \"4.3.0\" to \"4.4.1\" [#3315](https://github.com/storybookjs/storybook/pull/3315)\n- Upgraded `webpack` in `app/mithril` from \"4.3.0\" to \"4.4.1\" [#3315](https://github.com/storybookjs/storybook/pull/3315)\n- Upgraded `webpack` in `app/polymer` from \"4.3.0\" to \"4.4.1\" [#3315](https://github.com/storybookjs/storybook/pull/3315)\n- Upgraded `webpack` in `app/react-native` from \"4.3.0\" to \"4.4.1\" [#3315](https://github.com/storybookjs/storybook/pull/3315)\n- Upgraded `webpack` in `app/vue` from \"4.3.0\" to \"4.4.1\" [#3315](https://github.com/storybookjs/storybook/pull/3315)\n- Upgraded `webpack` in `examples/cra-kitchen-sink` from \"4.3.0\" to \"4.4.1\" [#3315](https://github.com/storybookjs/storybook/pull/3315)\n- Upgraded `@types/node` in `examples/angular-cli` from \"9.6.0\" to \"9.6.1\" [#3315](https://github.com/storybookjs/storybook/pull/3315)\n- Upgraded `webpack` in `examples/mithril-kitchen-sink` from \"4.3.0\" to \"4.4.1\" [#3315](https://github.com/storybookjs/storybook/pull/3315)\n- Upgraded `webpack` in `examples/polymer-cli` from \"4.3.0\" to \"4.4.1\" [#3315](https://github.com/storybookjs/storybook/pull/3315)\n- Upgraded `webpack` in `examples/vue-kitchen-sink` from \"4.3.0\" to \"4.4.1\" [#3315](https://github.com/storybookjs/storybook/pull/3315)\n- Add babel-core dev-deps [#3319](https://github.com/storybookjs/storybook/pull/3319)\n\n</details>\n\n## 3.4.1\n\n2018-April-10\n\n#### Features\n\n- Make storybook addons channel available globally in `window` [#3243](https://github.com/storybookjs/storybook/pull/3243)\n\n#### Bug Fixes\n\n- Scroll preview pane for non-percentage heights [#3342](https://github.com/storybookjs/storybook/pull/3342)\n- Replacing Report Fragment with div [#3372](https://github.com/storybookjs/storybook/pull/3372)\n- Don't use direct react dependency in core [#3382](https://github.com/storybookjs/storybook/pull/3382)\n\n#### Documentation\n\n- Add typescript docs [#3361](https://github.com/storybookjs/storybook/pull/3361)\n- Update links of the live examples for the new release [#3197](https://github.com/storybookjs/storybook/pull/3197)\n\n## 3.4.0\n\n2018-March-30\n\nWelcome to Storybook 3.4 with the following key improvements:\n\n- Polymer 2 support [#2225](https://github.com/storybookjs/storybook/pull/2225)\n- Angular and Vue storyshots [#2564](https://github.com/storybookjs/storybook/pull/2564)\n- Add image snapshots to addon-storyshots [#2413](https://github.com/storybookjs/storybook/pull/2413)\n- Multiple story hierarchies [#2452](https://github.com/storybookjs/storybook/pull/2452)\n- Addon-storysource: story source in addon pane [#2885](https://github.com/storybookjs/storybook/pull/2885)\n\nRead on for more improvements, fixes. In addition, there are hundreds of dependency upgrades in the 3.4 release, so to see the details, please see the changelogs for `3.4.0-rc.*` and `3.4.0-alpha.*`.\n\n#### Features\n\n- Bind window access if `window` is defined; add `addons channel` access too [#3243](https://github.com/storybookjs/storybook/pull/3243)\n- Fix screenshots tests & add getScreenshotOption to storyshots [#3102](https://github.com/storybookjs/storybook/pull/3102)\n- Add `__STORYBOOK_CLIENT_API__` for external tools [#3058](https://github.com/storybookjs/storybook/pull/3058)\n- Addon storysource: select stories from inside of the StoryPanel [#3154](https://github.com/storybookjs/storybook/pull/3154)\n- Storyshots: env.NODE_PATH support [#2873](https://github.com/storybookjs/storybook/pull/2873)\n- Knobs: Select knob key/value ordering [#1745](https://github.com/storybookjs/storybook/pull/1745)\n- Angular: Add option to pass custom styles for ng components [#2856](https://github.com/storybookjs/storybook/pull/2856)\n- Core: Add watch mode for build-storybook [#2866](https://github.com/storybookjs/storybook/pull/2866)\n- Core: Add `__dirname` support [#2791](https://github.com/storybookjs/storybook/pull/2791)\n- Pass default webpack config as third argument in Full Control Mode [#2796](https://github.com/storybookjs/storybook/pull/2796)\n- Angular and Vue storyshots [#2564](https://github.com/storybookjs/storybook/pull/2564)\n- Addon-info: Added \"Copy button\" for code example [#2713](https://github.com/storybookjs/storybook/pull/2713)\n- Angular: Serve styles and assets using .angular-cli webpack configuration [#2735](https://github.com/storybookjs/storybook/pull/2735)\n- API: Added an event that is emitted when a channel is created. [#2711](https://github.com/storybookjs/storybook/pull/2711)\n- Addon-a11y: Handle components with delayed rendering [#2651](https://github.com/storybookjs/storybook/pull/2651)\n- Polymer 2 support [#2225](https://github.com/storybookjs/storybook/pull/2225)\n- Add image snapshots to addon-storyshots [#2413](https://github.com/storybookjs/storybook/pull/2413)\n- Angular template support for Storybook [#2690](https://github.com/storybookjs/storybook/pull/2690)\n- Custom tsconfig.json for angular apps. [#2669](https://github.com/storybookjs/storybook/pull/2669)\n- Multiple story hierarchies [#2452](https://github.com/storybookjs/storybook/pull/2452)\n- Change template story files extension to .ts [#2594](https://github.com/storybookjs/storybook/pull/2594)\n- Use store revisions to ensure that stories re-render on HMR. [#2605](https://github.com/storybookjs/storybook/pull/2605)\n- Ability to force re-render a story [#2463](https://github.com/storybookjs/storybook/pull/2463)\n- Introduce framework-independent core library [#2241](https://github.com/storybookjs/storybook/pull/2241)\n\n#### Bug Fixes\n\n- \\[Addon-storyshots\\] Remove default options on \"goto\" call [#3298](https://github.com/storybookjs/storybook/pull/3298)\n- CLI: add error handling for latest_version helper [#3297](https://github.com/storybookjs/storybook/pull/3297)\n- Refactor CLI to use `npm` and `yarn` instead of third party packages [#3275](https://github.com/storybookjs/storybook/pull/3275)\n- Fix issue when extending webpack config [#3279](https://github.com/storybookjs/storybook/pull/3279)\n- Object proptype is shown in addon-info proptable [#3255](https://github.com/storybookjs/storybook/pull/3255)\n- Fix storyshots renderer and serializer options [#3252](https://github.com/storybookjs/storybook/pull/3252)\n- Angular: use resolveLoader from cliCommonConfig [#3251](https://github.com/storybookjs/storybook/pull/3251)\n- Delaying update of height and width in Layout [#3180](https://github.com/storybookjs/storybook/pull/3180)\n- Add 'waitUntil' option to puppeteer of storyshots [#3156](https://github.com/storybookjs/storybook/pull/3156)\n- Move polymer loader to peerDependencies [#3161](https://github.com/storybookjs/storybook/pull/3161)\n- Addons: avoid mixing manager and preview code together [#3068](https://github.com/storybookjs/storybook/pull/3068)\n- React-Native: Fix by moving managerPath export to `server.js` [#2947](https://github.com/storybookjs/storybook/pull/2947)\n- Addon-Info: Add type check to PropType on OneOf [#2653](https://github.com/storybookjs/storybook/pull/2653)\n- Vue: Support .vue extension resolving [#2896](https://github.com/storybookjs/storybook/pull/2896)\n- UI: remove zero on story loading [#2857](https://github.com/storybookjs/storybook/pull/2857)\n- Angular: remove entryComponents prop from metadata [#2790](https://github.com/storybookjs/storybook/pull/2790)\n- Use process.exitCode instead of process.exit() [#2717](https://github.com/storybookjs/storybook/pull/2717)\n- Angular: knobs with template [#2766](https://github.com/storybookjs/storybook/pull/2766)\n- Remove polymer-cli dependency [#2741](https://github.com/storybookjs/storybook/pull/2741)\n- Add scss for components in angular apps by default. [#2703](https://github.com/storybookjs/storybook/pull/2703)\n\n#### Documentation\n\n- Add example for @ngrx/store [#3233](https://github.com/storybookjs/storybook/pull/3233)\n- Fix missing declaration in Angular example [#3213](https://github.com/storybookjs/storybook/pull/3213)\n- Update ADDONS_SUPPORT.md [#3114](https://github.com/storybookjs/storybook/pull/3114)\n- StoryShots: Document ref mocking [#2869](https://github.com/storybookjs/storybook/pull/2869)\n- Extending webpack section is no longer needed for the common usage [#2826](https://github.com/storybookjs/storybook/pull/2826)\n- Updating Vue Jest Config [#2821](https://github.com/storybookjs/storybook/pull/2821)\n- Angular inheritance example [#2787](https://github.com/storybookjs/storybook/pull/2787)\n- Revisit addon/framework support [#3046](https://github.com/storybookjs/storybook/pull/3046)\n- Docs live examples [#3019](https://github.com/storybookjs/storybook/pull/3019)\n- Mention new supported frameworks [#2895](https://github.com/storybookjs/storybook/pull/2895)\n- Update writing addons documentation [#2951](https://github.com/storybookjs/storybook/pull/2951)\n- Update docs on LinkTo in addon-links [#2926](https://github.com/storybookjs/storybook/pull/2926)\n\n#### Maintenance\n\n- Fix errors on starting example Angular app [#3078](https://github.com/storybookjs/storybook/pull/3078)\n- Use WatchMissingNodeModulesPlugin from react-dev-utils package [#3141](https://github.com/storybookjs/storybook/pull/3141)\n- Don't use exact versions in peerDependencies [#3073](https://github.com/storybookjs/storybook/pull/3073)\n- Remove integration tests [#3052](https://github.com/storybookjs/storybook/pull/3052)\n- Fix \"dev\" script to be cross-platform [#2922](https://github.com/storybookjs/storybook/pull/2922)\n- Typescript distribution [#2846](https://github.com/storybookjs/storybook/pull/2846)\n- Use UTC timezone in formatting too for knobs test [#2861](https://github.com/storybookjs/storybook/pull/2861)\n- ADD autolabeler.yml for <https://github.com/probot/autolabeler> [#2809](https://github.com/storybookjs/storybook/pull/2809)\n- Fix css warning in angular-cli example [#2789](https://github.com/storybookjs/storybook/pull/2789)\n- Move more things to core [#2788](https://github.com/storybookjs/storybook/pull/2788)\n- Change ng stories dir [#2672](https://github.com/storybookjs/storybook/pull/2672)\n- Only update CLI snapshots on postpublish script, skip smoke tests [#2671](https://github.com/storybookjs/storybook/pull/2671)\n- Fix the timezone for example dates [#2654](https://github.com/storybookjs/storybook/pull/2654)\n- Update prereq yarn install level [#2638](https://github.com/storybookjs/storybook/pull/2638)\n- Separate stories in angular-cli example [#2592](https://github.com/storybookjs/storybook/pull/2592)\n\n## 4.0.0-alpha.1\n\n2018-March-29\n\n#### Bug Fixes\n\n- \\[Hotfix\\] Use published webpack 4 compatible fork of react-dev-utils [#3312](https://github.com/storybookjs/storybook/pull/3312)\n\n## 4.0.0-alpha.0\n\n2018-March-28\n\n#### Breaking Changes\n\n- Webpack 4 [#3148](https://github.com/storybookjs/storybook/pull/3148)\n\n#### Features\n\n- Viewport-addon Allow setting callback to be called whenever viewport changes [#3283](https://github.com/storybookjs/storybook/pull/3283)\n- Storybook for Mithril [#3244](https://github.com/storybookjs/storybook/pull/3244)\n- Feature request: adding aXe configuration for a11y addon [#3285](https://github.com/storybookjs/storybook/pull/3285)\n- files knob [#2860](https://github.com/storybookjs/storybook/pull/2860)\n- Using svg-url-loader for webpack configs that accept svgs [#3221](https://github.com/storybookjs/storybook/pull/3221)\n- Addon Storysource typescript support [#3253](https://github.com/storybookjs/storybook/pull/3253)\n- addon-options: Make shortcuts in storybook optional [#3237](https://github.com/storybookjs/storybook/pull/3237)\n- Add parameters to stories in the story store, and render them in app layers [#2679](https://github.com/storybookjs/storybook/pull/2679)\n- Add min, value, and max labels to range knob [#3128](https://github.com/storybookjs/storybook/pull/3128)\n- viewport-addon: Make the addon configurable [#3099](https://github.com/storybookjs/storybook/pull/3099)\n- Bind window access if `window` is defined; add `addons channel` access too [#3243](https://github.com/storybookjs/storybook/pull/3243)\n\n#### Bug Fixes\n\n- Update react-native symlink resolving and add support for flow [#3306](https://github.com/storybookjs/storybook/pull/3306)\n- \\[Addon-storyshots\\] Remove default options on \"goto\" call [#3298](https://github.com/storybookjs/storybook/pull/3298)\n- Remove onDeviceUI animation to support Detox screenshots [#3272](https://github.com/storybookjs/storybook/pull/3272)\n- Angular: use resolveLoader from cliCommonConfig [#3251](https://github.com/storybookjs/storybook/pull/3251)\n\n#### Maintenance\n\n- Create CODEOWNERS from git history [#3296](https://github.com/storybookjs/storybook/pull/3296)\n- Close inactive issues in 30 days [#3273](https://github.com/storybookjs/storybook/pull/3273)\n- Refactor all startup code into `@storybook/core` also [#3259](https://github.com/storybookjs/storybook/pull/3259)\n- Update ISSUE_TEMPLATE to help define work to be done [#3257](https://github.com/storybookjs/storybook/pull/3257)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n64 Updates\n</summary>\n\n- Update gatsby-transformer-remark in /docs from 1.7.38 to 1.7.39 [#3310](https://github.com/storybookjs/storybook/pull/3310)\n- Upgraded `@types/react` in `addons/notes` from \"16.0.41\" to \"16.1.0\" [#3311](https://github.com/storybookjs/storybook/pull/3311)\n- Upgraded `react-chromatic` in `examples/official-storybook` from \"0.7.11\" to \"0.8.1\" [#3311](https://github.com/storybookjs/storybook/pull/3311)\n- Major upgrades for devDependencies [#3304](https://github.com/storybookjs/storybook/pull/3304)\n- Upgraded `typescript` in `/` from \"2.7.2\" to \"2.8.1\" [#3303](https://github.com/storybookjs/storybook/pull/3303)\n- Upgraded `core-js` in `app/react` from \"2.5.3\" to \"2.5.4\" [#3303](https://github.com/storybookjs/storybook/pull/3303)\n- Upgraded `core-js` in `app/angular` from \"2.5.3\" to \"2.5.4\" [#3303](https://github.com/storybookjs/storybook/pull/3303)\n- Upgraded `core-js` in `app/polymer` from \"2.5.3\" to \"2.5.4\" [#3303](https://github.com/storybookjs/storybook/pull/3303)\n- Upgraded `core-js` in `app/vue` from \"2.5.3\" to \"2.5.4\" [#3303](https://github.com/storybookjs/storybook/pull/3303)\n- Upgraded `core-js` in `examples/angular-cli` from \"2.5.3\" to \"2.5.4\" [#3303](https://github.com/storybookjs/storybook/pull/3303)\n- Upgraded `typescript` in `examples/angular-cli` from \"2.7.2\" to \"2.8.1\" [#3303](https://github.com/storybookjs/storybook/pull/3303)\n- Upgraded `gatsby-link` in `/docs` from \"1.6.39\" to \"1.6.40\" [#3300](https://github.com/storybookjs/storybook/pull/3300)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.59\" to \"1.5.60\" [#3300](https://github.com/storybookjs/storybook/pull/3300)\n- Upgraded `gatsby-transformer-remark` in `/docs` from \"1.7.37\" to \"1.7.38\" [#3300](https://github.com/storybookjs/storybook/pull/3300)\n- Upgraded `gatsby` in `/docs` from \"1.9.241\" to \"1.9.243\" [#3300](https://github.com/storybookjs/storybook/pull/3300)\n- Upgraded `webpack` in `app/react` from \"4.2.0\" to \"4.3.0\" [#3299](https://github.com/storybookjs/storybook/pull/3299)\n- Upgraded `webpack` in `lib/core` from \"4.2.0\" to \"4.3.0\" [#3299](https://github.com/storybookjs/storybook/pull/3299)\n- Upgraded `webpack-dev-middleware` in `lib/core` from \"3.0.1\" to \"3.1.0\" [#3299](https://github.com/storybookjs/storybook/pull/3299)\n- Upgraded `webpack` in `app/angular` from \"4.2.0\" to \"4.3.0\" [#3299](https://github.com/storybookjs/storybook/pull/3299)\n- Upgraded `webpack` in `app/polymer` from \"4.2.0\" to \"4.3.0\" [#3299](https://github.com/storybookjs/storybook/pull/3299)\n- Upgraded `webpack` in `app/react-native` from \"4.2.0\" to \"4.3.0\" [#3299](https://github.com/storybookjs/storybook/pull/3299)\n- Upgraded `webpack-dev-middleware` in `app/react-native` from \"3.0.1\" to \"3.1.0\" [#3299](https://github.com/storybookjs/storybook/pull/3299)\n- Upgraded `webpack` in `app/vue` from \"4.2.0\" to \"4.3.0\" [#3299](https://github.com/storybookjs/storybook/pull/3299)\n- Upgraded `webpack` in `examples/cra-kitchen-sink` from \"4.2.0\" to \"4.3.0\" [#3299](https://github.com/storybookjs/storybook/pull/3299)\n- Upgraded `rxjs` in `examples/angular-cli` from \"5.5.7\" to \"5.5.8\" [#3299](https://github.com/storybookjs/storybook/pull/3299)\n- Upgraded `webpack` in `examples/polymer-cli` from \"4.2.0\" to \"4.3.0\" [#3299](https://github.com/storybookjs/storybook/pull/3299)\n- Upgraded `webpack` in `examples/vue-kitchen-sink` from \"4.2.0\" to \"4.3.0\" [#3299](https://github.com/storybookjs/storybook/pull/3299)\n- Upgraded `inquirer` in `/` from \"5.1.0\" to \"5.2.0\" [#3294](https://github.com/storybookjs/storybook/pull/3294)\n- Upgraded `marked` in `addons/notes` from \"0.3.18\" to \"0.3.19\" [#3294](https://github.com/storybookjs/storybook/pull/3294)\n- Upgraded `update-notifier` in `lib/cli` from \"2.3.0\" to \"2.4.0\" [#3294](https://github.com/storybookjs/storybook/pull/3294)\n- Update marked in /docs from 0.3.18 to 0.3.19 [#3292](https://github.com/storybookjs/storybook/pull/3292)\n- Update gatsby in /docs from 1.9.240 to 1.9.241 [#3281](https://github.com/storybookjs/storybook/pull/3281)\n- Update @types/react in addons/notes from 16.0.40 to 16.0.41 [#3282](https://github.com/storybookjs/storybook/pull/3282)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.56\" to \"1.5.59\" [#3276](https://github.com/storybookjs/storybook/pull/3276)\n- Upgraded `gatsby` in `/docs` from \"1.9.239\" to \"1.9.240\" [#3276](https://github.com/storybookjs/storybook/pull/3276)\n- Upgraded `vue-loader` in `app/vue` from \"14.2.1\" to \"14.2.2\" [#3277](https://github.com/storybookjs/storybook/pull/3277)\n- Upgraded `vue-loader` in `examples/vue-kitchen-sink` from \"14.2.1\" to \"14.2.2\" [#3277](https://github.com/storybookjs/storybook/pull/3277)\n- Upgraded `eslint` in `/` from \"4.19.0\" to \"4.19.1\" [#3265](https://github.com/storybookjs/storybook/pull/3265)\n- Upgraded `marked` in `addons/notes` from \"0.3.17\" to \"0.3.18\" [#3265](https://github.com/storybookjs/storybook/pull/3265)\n- Upgraded `autoprefixer` in `lib/core` from \"8.1.0\" to \"8.2.0\" [#3265](https://github.com/storybookjs/storybook/pull/3265)\n- Upgraded `@webcomponents/webcomponentsjs` in `app/polymer` from \"1.1.0\" to \"1.1.1\" [#3265](https://github.com/storybookjs/storybook/pull/3265)\n- Upgraded `@types/node` in `examples/angular-cli` from \"9.4.7\" to \"9.6.0\" [#3265](https://github.com/storybookjs/storybook/pull/3265)\n- Upgraded `@polymer/polymer` in `examples/polymer-cli` from \"2.5.0\" to \"2.6.0\" [#3265](https://github.com/storybookjs/storybook/pull/3265)\n- Upgraded `@webcomponents/webcomponentsjs` in `examples/polymer-cli` from \"1.1.0\" to \"1.1.1\" [#3265](https://github.com/storybookjs/storybook/pull/3265)\n- Update marked in /docs from 0.3.17 to 0.3.18 [#3264](https://github.com/storybookjs/storybook/pull/3264)\n- Update gatsby in /docs from 1.9.238 to 1.9.239 [#3262](https://github.com/storybookjs/storybook/pull/3262)\n- Upgraded `danger` in `/` from \"3.3.0\" to \"3.3.2\" [#3254](https://github.com/storybookjs/storybook/pull/3254)\n- Upgraded `jest` in `/` from \"22.4.2\" to \"22.4.3\" [#3254](https://github.com/storybookjs/storybook/pull/3254)\n- Upgraded `jest-cli` in `/` from \"22.4.2\" to \"22.4.3\" [#3254](https://github.com/storybookjs/storybook/pull/3254)\n- Upgraded `jest-config` in `/` from \"22.4.2\" to \"22.4.3\" [#3254](https://github.com/storybookjs/storybook/pull/3254)\n- Upgraded `jest-diff` in `/` from \"22.4.0\" to \"22.4.3\" [#3254](https://github.com/storybookjs/storybook/pull/3254)\n- Upgraded `jest-environment-jsdom` in `/` from \"22.4.1\" to \"22.4.3\" [#3254](https://github.com/storybookjs/storybook/pull/3254)\n- Upgraded `jest-jasmine2` in `/` from \"22.4.2\" to \"22.4.3\" [#3254](https://github.com/storybookjs/storybook/pull/3254)\n- Upgraded `keycode` in `lib/ui` from \"2.1.9\" to \"2.2.0\" [#3254](https://github.com/storybookjs/storybook/pull/3254)\n- Upgraded `autoprefixer` in `lib/core` from \"8.0.0\" to \"8.1.0\" [#3254](https://github.com/storybookjs/storybook/pull/3254)\n- Upgraded `babel-preset-vue` in `examples/vue-kitchen-sink` from \"2.0.1\" to \"2.0.2\" [#3254](https://github.com/storybookjs/storybook/pull/3254)\n- Upgraded `commander` in `/` from \"2.15.0\" to \"2.15.1\" [#3250](https://github.com/storybookjs/storybook/pull/3250)\n- Upgraded `danger` in `/` from \"3.2.0\" to \"3.3.0\" [#3250](https://github.com/storybookjs/storybook/pull/3250)\n- Upgraded `commander` in `lib/core` from \"2.15.0\" to \"2.15.1\" [#3250](https://github.com/storybookjs/storybook/pull/3250)\n- Upgraded `postcss-loader` in `lib/core` from \"2.1.2\" to \"2.1.3\" [#3250](https://github.com/storybookjs/storybook/pull/3250)\n- Upgraded `commander` in `app/react-native` from \"2.15.0\" to \"2.15.1\" [#3250](https://github.com/storybookjs/storybook/pull/3250)\n- Upgraded `commander` in `lib/cli` from \"2.15.0\" to \"2.15.1\" [#3250](https://github.com/storybookjs/storybook/pull/3250)\n- Core: upgrade autoprefixer from 7.2.6 to 8.0.0 & allow configuring browser list externally [#3076](https://github.com/storybookjs/storybook/pull/3076)\n- Update gatsby in /docs from 1.9.236 to 1.9.238 [#3249](https://github.com/storybookjs/storybook/pull/3249)\n\n</details>\n\n## 3.4.0-rc.4\n\n2018-March-28\n\n#### Bug Fixes\n\n- CLI: add error handling for latest_version helper [#3297](https://github.com/storybookjs/storybook/pull/3297)\n- Refactor CLI to use `npm` and `yarn` instead of third party packages [#3275](https://github.com/storybookjs/storybook/pull/3275)\n- Fix issue when extending webpack config [#3279](https://github.com/storybookjs/storybook/pull/3279)\n- Object proptype is shown in addon-info proptable [#3255](https://github.com/storybookjs/storybook/pull/3255)\n- Fix storyshots renderer and serializer options [#3252](https://github.com/storybookjs/storybook/pull/3252)\n- Angular: use resolveLoader from cliCommonConfig [#3251](https://github.com/storybookjs/storybook/pull/3251)\n\n## 3.4.0-rc.3\n\n2018-March-19\n\n#### Documentation\n\n- Add example for @ngrx/store [#3233](https://github.com/storybookjs/storybook/pull/3233)\n- Fix missing declaration in Angular example [#3213](https://github.com/storybookjs/storybook/pull/3213)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n58 Updates\n</summary>\n\n- Update node-sass in app/angular from 4.8.2 to 4.8.3 [#3239](https://github.com/storybookjs/storybook/pull/3239)\n- Update postcss-loader in lib/core from 2.1.1 to 2.1.2 [#3234](https://github.com/storybookjs/storybook/pull/3234)\n- Upgraded `eslint` in `/` from \"4.18.2\" to \"4.19.0\" [#3230](https://github.com/storybookjs/storybook/pull/3230)\n- Upgraded `graphql` in `addons/graphql` from \"0.13.1\" to \"0.13.2\" [#3230](https://github.com/storybookjs/storybook/pull/3230)\n- Update gatsby in /docs from 1.9.233 to 1.9.236 [#3229](https://github.com/storybookjs/storybook/pull/3229)\n- Upgraded `gatsby-transformer-remark` in `/docs` from \"1.7.36\" to \"1.7.37\" [#3226](https://github.com/storybookjs/storybook/pull/3226)\n- Upgraded `gatsby` in `/docs` from \"1.9.232\" to \"1.9.233\" [#3226](https://github.com/storybookjs/storybook/pull/3226)\n- Upgraded `uglifyjs-webpack-plugin` in `app/react` from \"1.2.3\" to \"1.2.4\" [#3227](https://github.com/storybookjs/storybook/pull/3227)\n- Upgraded `puppeteer` in `addons/storyshots` from \"1.1.1\" to \"1.2.0\" [#3227](https://github.com/storybookjs/storybook/pull/3227)\n- Upgraded `enzyme-to-json` in `addons/storyshots` from \"3.3.1\" to \"3.3.3\" [#3227](https://github.com/storybookjs/storybook/pull/3227)\n- Upgraded `css-loader` in `lib/core` from \"0.28.10\" to \"0.28.11\" [#3227](https://github.com/storybookjs/storybook/pull/3227)\n- Upgraded `uglifyjs-webpack-plugin` in `app/angular` from \"1.2.3\" to \"1.2.4\" [#3227](https://github.com/storybookjs/storybook/pull/3227)\n- Upgraded `uglifyjs-webpack-plugin` in `app/polymer` from \"1.2.3\" to \"1.2.4\" [#3227](https://github.com/storybookjs/storybook/pull/3227)\n- Upgraded `uglifyjs-webpack-plugin` in `app/react-native` from \"1.2.3\" to \"1.2.4\" [#3227](https://github.com/storybookjs/storybook/pull/3227)\n- Upgraded `uglifyjs-webpack-plugin` in `app/vue` from \"1.2.3\" to \"1.2.4\" [#3227](https://github.com/storybookjs/storybook/pull/3227)\n- Upgraded `enzyme-to-json` in `examples/cra-kitchen-sink` from \"3.3.1\" to \"3.3.3\" [#3227](https://github.com/storybookjs/storybook/pull/3227)\n- Upgraded `enzyme-to-json` in `examples/official-storybook` from \"3.3.1\" to \"3.3.3\" [#3227](https://github.com/storybookjs/storybook/pull/3227)\n- Upgraded `@angular/common` in `/` from \"5.2.8\" to \"5.2.9\" [#3219](https://github.com/storybookjs/storybook/pull/3219)\n- Upgraded `@angular/compiler` in `/` from \"5.2.8\" to \"5.2.9\" [#3219](https://github.com/storybookjs/storybook/pull/3219)\n- Upgraded `@angular/core` in `/` from \"5.2.8\" to \"5.2.9\" [#3219](https://github.com/storybookjs/storybook/pull/3219)\n- Upgraded `@angular/forms` in `/` from \"5.2.8\" to \"5.2.9\" [#3219](https://github.com/storybookjs/storybook/pull/3219)\n- Upgraded `@angular/platform-browser` in `/` from \"5.2.8\" to \"5.2.9\" [#3219](https://github.com/storybookjs/storybook/pull/3219)\n- Upgraded `@angular/platform-browser-dynamic` in `/` from \"5.2.8\" to \"5.2.9\" [#3219](https://github.com/storybookjs/storybook/pull/3219)\n- Upgraded `danger` in `/` from \"3.1.8\" to \"3.2.0\" [#3219](https://github.com/storybookjs/storybook/pull/3219)\n- Upgraded `eslint-plugin-jest` in `/` from \"21.14.1\" to \"21.15.0\" [#3219](https://github.com/storybookjs/storybook/pull/3219)\n- Upgraded `jest-vue-preprocessor` in `/` from \"1.3.1\" to \"1.4.0\" [#3219](https://github.com/storybookjs/storybook/pull/3219)\n- Upgraded `react-chromatic` in `examples/official-storybook` from \"0.7.10\" to \"0.7.11\" [#3219](https://github.com/storybookjs/storybook/pull/3219)\n- Upgraded `@angular/common` in `examples/angular-cli` from \"5.2.8\" to \"5.2.9\" [#3219](https://github.com/storybookjs/storybook/pull/3219)\n- Upgraded `@angular/compiler` in `examples/angular-cli` from \"5.2.8\" to \"5.2.9\" [#3219](https://github.com/storybookjs/storybook/pull/3219)\n- Upgraded `@angular/core` in `examples/angular-cli` from \"5.2.8\" to \"5.2.9\" [#3219](https://github.com/storybookjs/storybook/pull/3219)\n- Upgraded `@angular/forms` in `examples/angular-cli` from \"5.2.8\" to \"5.2.9\" [#3219](https://github.com/storybookjs/storybook/pull/3219)\n- Upgraded `@angular/platform-browser` in `examples/angular-cli` from \"5.2.8\" to \"5.2.9\" [#3219](https://github.com/storybookjs/storybook/pull/3219)\n- Upgraded `@angular/platform-browser-dynamic` in `examples/angular-cli` from \"5.2.8\" to \"5.2.9\" [#3219](https://github.com/storybookjs/storybook/pull/3219)\n- Upgraded `@angular/compiler-cli` in `examples/angular-cli` from \"5.2.8\" to \"5.2.9\" [#3219](https://github.com/storybookjs/storybook/pull/3219)\n- Upgraded `eslint-plugin-jest` in `/` from \"21.14.0\" to \"21.14.1\" [#3210](https://github.com/storybookjs/storybook/pull/3210)\n- Upgraded `jest-image-snapshot` in `/` from \"2.3.0\" to \"2.4.0\" [#3210](https://github.com/storybookjs/storybook/pull/3210)\n- Upgraded `nodemon` in `app/react` from \"1.17.1\" to \"1.17.2\" [#3210](https://github.com/storybookjs/storybook/pull/3210)\n- Upgraded `vue` in `addons/knobs` from \"2.5.15\" to \"2.5.16\" [#3210](https://github.com/storybookjs/storybook/pull/3210)\n- Upgraded `jest-image-snapshot` in `addons/storyshots` from \"2.3.0\" to \"2.4.0\" [#3210](https://github.com/storybookjs/storybook/pull/3210)\n- Upgraded `nodemon` in `app/angular` from \"1.17.1\" to \"1.17.2\" [#3210](https://github.com/storybookjs/storybook/pull/3210)\n- Upgraded `nodemon` in `app/polymer` from \"1.17.1\" to \"1.17.2\" [#3210](https://github.com/storybookjs/storybook/pull/3210)\n- Upgraded `nodemon` in `app/vue` from \"1.17.1\" to \"1.17.2\" [#3210](https://github.com/storybookjs/storybook/pull/3210)\n- Upgraded `vue` in `app/vue` from \"2.5.15\" to \"2.5.16\" [#3210](https://github.com/storybookjs/storybook/pull/3210)\n- Upgraded `vue-template-compiler` in `app/vue` from \"2.5.15\" to \"2.5.16\" [#3210](https://github.com/storybookjs/storybook/pull/3210)\n- Upgraded `vue` in `examples/vue-kitchen-sink` from \"2.5.15\" to \"2.5.16\" [#3210](https://github.com/storybookjs/storybook/pull/3210)\n- Upgraded `tslint-config-prettier` in `/` from \"1.9.0\" to \"1.10.0\" [#3201](https://github.com/storybookjs/storybook/pull/3201)\n- Upgraded `glamorous` in `app/react` from \"4.12.0\" to \"4.12.1\" [#3201](https://github.com/storybookjs/storybook/pull/3201)\n- Upgraded `glamorous` in `addons/actions` from \"4.12.0\" to \"4.12.1\" [#3201](https://github.com/storybookjs/storybook/pull/3201)\n- Upgraded `glamorous` in `lib/components` from \"4.12.0\" to \"4.12.1\" [#3201](https://github.com/storybookjs/storybook/pull/3201)\n- Upgraded `glamorous` in `addons/a11y` from \"4.12.0\" to \"4.12.1\" [#3201](https://github.com/storybookjs/storybook/pull/3201)\n- Upgraded `glamorous` in `addons/info` from \"4.12.0\" to \"4.12.1\" [#3201](https://github.com/storybookjs/storybook/pull/3201)\n- Upgraded `glamorous` in `addons/jest` from \"4.12.0\" to \"4.12.1\" [#3201](https://github.com/storybookjs/storybook/pull/3201)\n- Upgraded `react-modal` in `lib/ui` from \"3.3.1\" to \"3.3.2\" [#3201](https://github.com/storybookjs/storybook/pull/3201)\n- Upgraded `express` in `lib/core` from \"4.16.2\" to \"4.16.3\" [#3201](https://github.com/storybookjs/storybook/pull/3201)\n- Upgraded `node-sass` in `app/angular` from \"4.8.1\" to \"4.8.2\" [#3201](https://github.com/storybookjs/storybook/pull/3201)\n- Upgraded `express` in `app/react-native` from \"4.16.2\" to \"4.16.3\" [#3201](https://github.com/storybookjs/storybook/pull/3201)\n- Upgraded `rxjs` in `examples/angular-cli` from \"5.5.6\" to \"5.5.7\" [#3201](https://github.com/storybookjs/storybook/pull/3201)\n- Update gatsby in /docs from 1.9.231 to 1.9.232 [#3200](https://github.com/storybookjs/storybook/pull/3200)\n\n</details>\n\n## 3.4.0-rc.2\n\n2018-March-13\n\nFix publishing options to use exact versions for cross-dependencies per this change:\n\n- use exact versions for cross-dependencies between our own packages [#3183](https://github.com/storybookjs/storybook/pull/3183)\n\n## 3.4.0-rc.1\n\n2018-March-13\n\n#### Features\n\n- Fix screenshots tests & add getScreenshotOption to storyshots [#3102](https://github.com/storybookjs/storybook/pull/3102)\n\n#### Bug Fixes\n\n- Delaying update of height and width in Layout [#3180](https://github.com/storybookjs/storybook/pull/3180)\n- Add 'waitUntil' option to puppeteer of storyshots [#3156](https://github.com/storybookjs/storybook/pull/3156)\n- Move polymer loader to peerDependencies [#3161](https://github.com/storybookjs/storybook/pull/3161)\n\n#### Maintenance\n\n- Feature-freeze master [#3149](https://github.com/storybookjs/storybook/pull/3149)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n57 updates\n</summary>\n\n- Update danger in / from 3.1.7 to 3.1.8 [#3191](https://github.com/storybookjs/storybook/pull/3191)\n- Upgraded `polymer-webpack-loader` in `/` from \"2.0.1\" to \"2.0.2\" [#3184](https://github.com/storybookjs/storybook/pull/3184)\n- Upgraded `uglifyjs-webpack-plugin` in `app/react` from \"1.2.2\" to \"1.2.3\" [#3184](https://github.com/storybookjs/storybook/pull/3184)\n- Upgraded `vue` in `addons/knobs` from \"2.5.14\" to \"2.5.15\" [#3184](https://github.com/storybookjs/storybook/pull/3184)\n- Upgraded `node-sass` in `app/angular` from \"4.7.2\" to \"4.8.1\" [#3184](https://github.com/storybookjs/storybook/pull/3184)\n- Upgraded `uglifyjs-webpack-plugin` in `app/angular` from \"1.2.2\" to \"1.2.3\" [#3184](https://github.com/storybookjs/storybook/pull/3184)\n- Upgraded `uglifyjs-webpack-plugin` in `app/polymer` from \"1.2.2\" to \"1.2.3\" [#3184](https://github.com/storybookjs/storybook/pull/3184)\n- Upgraded `polymer-webpack-loader` in `app/polymer` from \"2.0.1\" to \"2.0.2\" [#3184](https://github.com/storybookjs/storybook/pull/3184)\n- Upgraded `uglifyjs-webpack-plugin` in `app/react-native` from \"1.2.2\" to \"1.2.3\" [#3184](https://github.com/storybookjs/storybook/pull/3184)\n- Upgraded `uglifyjs-webpack-plugin` in `app/vue` from \"1.2.2\" to \"1.2.3\" [#3184](https://github.com/storybookjs/storybook/pull/3184)\n- Upgraded `vue` in `app/vue` from \"2.5.14\" to \"2.5.15\" [#3184](https://github.com/storybookjs/storybook/pull/3184)\n- Upgraded `vue-template-compiler` in `app/vue` from \"2.5.14\" to \"2.5.15\" [#3184](https://github.com/storybookjs/storybook/pull/3184)\n- Upgraded `polymer-webpack-loader` in `examples/polymer-cli` from \"2.0.1\" to \"2.0.2\" [#3184](https://github.com/storybookjs/storybook/pull/3184)\n- Upgraded `vue` in `examples/vue-kitchen-sink` from \"2.5.14\" to \"2.5.15\" [#3184](https://github.com/storybookjs/storybook/pull/3184)\n- Update eslint-plugin-jest in / from 21.13.0 to 21.14.0 [#3182](https://github.com/storybookjs/storybook/pull/3182)\n- Upgraded `cross-env` in `/` from \"5.1.3\" to \"5.1.4\" [#3179](https://github.com/storybookjs/storybook/pull/3179)\n- Upgraded `jest-preset-angular` in `/` from \"5.2.0\" to \"5.2.1\" [#3179](https://github.com/storybookjs/storybook/pull/3179)\n- Upgraded `@types/react` in `addons/notes` from \"16.0.34\" to \"16.0.40\" [#3179](https://github.com/storybookjs/storybook/pull/3179)\n- Upgraded `style-loader` in `addons/knobs` from \"0.20.2\" to \"0.20.3\" [#3179](https://github.com/storybookjs/storybook/pull/3179)\n- Upgraded `vue` in `addons/knobs` from \"2.5.13\" to \"2.5.14\" [#3179](https://github.com/storybookjs/storybook/pull/3179)\n- Upgraded `style-loader` in `lib/core` from \"0.20.2\" to \"0.20.3\" [#3179](https://github.com/storybookjs/storybook/pull/3179)\n- Upgraded `cross-env` in `app/angular` from \"5.1.3\" to \"5.1.4\" [#3179](https://github.com/storybookjs/storybook/pull/3179)\n- Upgraded `copy-webpack-plugin` in `app/polymer` from \"4.5.0\" to \"4.5.1\" [#3179](https://github.com/storybookjs/storybook/pull/3179)\n- Upgraded `vue` in `app/vue` from \"2.5.13\" to \"2.5.14\" [#3179](https://github.com/storybookjs/storybook/pull/3179)\n- Upgraded `vue-template-compiler` in `app/vue` from \"2.5.13\" to \"2.5.14\" [#3179](https://github.com/storybookjs/storybook/pull/3179)\n- Upgraded `@types/node` in `examples/angular-cli` from \"9.4.6\" to \"9.4.7\" [#3179](https://github.com/storybookjs/storybook/pull/3179)\n- Upgraded `copy-webpack-plugin` in `examples/polymer-cli` from \"4.5.0\" to \"4.5.1\" [#3179](https://github.com/storybookjs/storybook/pull/3179)\n- Upgraded `vue` in `examples/vue-kitchen-sink` from \"2.5.13\" to \"2.5.14\" [#3179](https://github.com/storybookjs/storybook/pull/3179)\n- Upgraded `cross-env` in `examples/vue-kitchen-sink` from \"5.1.3\" to \"5.1.4\" [#3179](https://github.com/storybookjs/storybook/pull/3179)\n- Upgraded `gatsby-link` in `/docs` from \"1.6.38\" to \"1.6.39\" [#3171](https://github.com/storybookjs/storybook/pull/3171)\n- Upgraded `gatsby-plugin-sharp` in `/docs` from \"1.6.39\" to \"1.6.41\" [#3171](https://github.com/storybookjs/storybook/pull/3171)\n- Upgraded `gatsby-source-filesystem` in `/docs` from \"1.5.26\" to \"1.5.27\" [#3171](https://github.com/storybookjs/storybook/pull/3171)\n- Upgraded `gatsby` in `/docs` from \"1.9.225\" to \"1.9.231\" [#3171](https://github.com/storybookjs/storybook/pull/3171)\n- Upgraded `@angular/common` in `/` from \"5.2.7\" to \"5.2.8\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `@angular/compiler` in `/` from \"5.2.7\" to \"5.2.8\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `@angular/core` in `/` from \"5.2.7\" to \"5.2.8\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `@angular/forms` in `/` from \"5.2.7\" to \"5.2.8\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `@angular/platform-browser` in `/` from \"5.2.7\" to \"5.2.8\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `@angular/platform-browser-dynamic` in `/` from \"5.2.7\" to \"5.2.8\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `commander` in `/` from \"2.14.1\" to \"2.15.0\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `acorn` in `addons/storysource` from \"5.5.1\" to \"5.5.3\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `enzyme-to-json` in `addons/storyshots` from \"3.3.1\" to \"3.3.2\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `commander` in `lib/core` from \"2.14.1\" to \"2.15.0\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `commander` in `app/react-native` from \"2.14.1\" to \"2.15.0\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `enzyme-to-json` in `examples/cra-kitchen-sink` from \"3.3.1\" to \"3.3.2\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `enzyme-to-json` in `examples/official-storybook` from \"3.3.1\" to \"3.3.2\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `commander` in `lib/cli` from \"2.14.1\" to \"2.15.0\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `@angular/common` in `examples/angular-cli` from \"5.2.7\" to \"5.2.8\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `@angular/compiler` in `examples/angular-cli` from \"5.2.7\" to \"5.2.8\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `@angular/core` in `examples/angular-cli` from \"5.2.7\" to \"5.2.8\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `@angular/forms` in `examples/angular-cli` from \"5.2.7\" to \"5.2.8\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `@angular/platform-browser` in `examples/angular-cli` from \"5.2.7\" to \"5.2.8\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `@angular/platform-browser-dynamic` in `examples/angular-cli` from \"5.2.7\" to \"5.2.8\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `@angular/cli` in `examples/angular-cli` from \"1.7.2\" to \"1.7.3\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- Upgraded `@angular/compiler-cli` in `examples/angular-cli` from \"5.2.7\" to \"5.2.8\" [#3170](https://github.com/storybookjs/storybook/pull/3170)\n- use exact versions for cross-dependencies between our own packages [#3183](https://github.com/storybookjs/storybook/pull/3183)\n- Move \"@types/react\" to dev dependencies [#3169](https://github.com/storybookjs/storybook/pull/3169)\n\n</details>\n\n## 3.4.0-rc.0\n\n2018-March-08\n\n#### Features\n\n- Add `__STORYBOOK_CLIENT_API__` for external tools [#3058](https://github.com/storybookjs/storybook/pull/3058)\n- Addon storysource: select stories from inside of the StoryPanel [#3154](https://github.com/storybookjs/storybook/pull/3154)\n\n#### Bug Fixes\n\n- Addons: avoid mixing manager and preview code together [#3068](https://github.com/storybookjs/storybook/pull/3068)\n\n#### Documentation\n\n- Update ADDONS_SUPPORT.md [#3114](https://github.com/storybookjs/storybook/pull/3114)\n- Add `viewport` addon to the Addon Gallery [#3106](https://github.com/storybookjs/storybook/pull/3106)\n- Fix links examples [#3096](https://github.com/storybookjs/storybook/pull/3096)\n- Fix links addon examples [#3070](https://github.com/storybookjs/storybook/pull/3070)\n- Fix inconsistencies in the background add-on README [#3080](https://github.com/storybookjs/storybook/pull/3080)\n\n#### Maintenance\n\n- Fix errors on starting example Angular app [#3078](https://github.com/storybookjs/storybook/pull/3078)\n- Use WatchMissingNodeModulesPlugin from react-dev-utils package [#3141](https://github.com/storybookjs/storybook/pull/3141)\n- Don't use exact versions in peerDependencies [#3073](https://github.com/storybookjs/storybook/pull/3073)\n- Remove integration tests [#3052](https://github.com/storybookjs/storybook/pull/3052)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n229 Updates\n</summary>\n\n- Upgraded `jscodeshift` in `lib/codemod` from \"0.4.1\" to \"0.5.0\" [#3168](https://github.com/storybookjs/storybook/pull/3168)\n- Upgraded `vue-loader` in `app/vue` from \"14.1.1\" to \"14.2.1\" [#3168](https://github.com/storybookjs/storybook/pull/3168)\n- Upgraded `jscodeshift` in `lib/cli` from \"0.4.1\" to \"0.5.0\" [#3168](https://github.com/storybookjs/storybook/pull/3168)\n- Upgraded `vue-loader` in `examples/vue-kitchen-sink` from \"14.1.1\" to \"14.2.1\" [#3168](https://github.com/storybookjs/storybook/pull/3168)\n- Upgraded `@storybook/addon-actions` in `/docs` from \"3.3.14\" to \"3.3.15\" [#3167](https://github.com/storybookjs/storybook/pull/3167)\n- Upgraded `@storybook/addon-links` in `/docs` from \"3.3.14\" to \"3.3.15\" [#3167](https://github.com/storybookjs/storybook/pull/3167)\n- Upgraded `@storybook/addons` in `/docs` from \"3.3.14\" to \"3.3.15\" [#3167](https://github.com/storybookjs/storybook/pull/3167)\n- Upgraded `@storybook/react` in `/docs` from \"3.3.14\" to \"3.3.15\" [#3167](https://github.com/storybookjs/storybook/pull/3167)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.55\" to \"1.5.56\" [#3167](https://github.com/storybookjs/storybook/pull/3167)\n- Upgraded `gatsby-transformer-remark` in `/docs` from \"1.7.34\" to \"1.7.36\" [#3167](https://github.com/storybookjs/storybook/pull/3167)\n- Upgraded `gatsby` in `/docs` from \"1.9.223\" to \"1.9.225\" [#3167](https://github.com/storybookjs/storybook/pull/3167)\n- Upgraded `eslint-plugin-jest` in `/` from \"21.12.3\" to \"21.13.0\" [#3160](https://github.com/storybookjs/storybook/pull/3160)\n- Upgraded `babel-loader` in `app/react` from \"7.1.3\" to \"7.1.4\" [#3160](https://github.com/storybookjs/storybook/pull/3160)\n- Upgraded `case-sensitive-paths-webpack-plugin` in `app/react` from \"2.1.1\" to \"2.1.2\" [#3160](https://github.com/storybookjs/storybook/pull/3160)\n- Upgraded `acorn` in `addons/storysource` from \"5.5.0\" to \"5.5.1\" [#3160](https://github.com/storybookjs/storybook/pull/3160)\n- Upgraded `react-syntax-highlighter` in `addons/storysource` from \"7.0.1\" to \"7.0.2\" [#3160](https://github.com/storybookjs/storybook/pull/3160)\n- Upgraded `babel-loader` in `app/angular` from \"7.1.3\" to \"7.1.4\" [#3160](https://github.com/storybookjs/storybook/pull/3160)\n- Upgraded `case-sensitive-paths-webpack-plugin` in `app/angular` from \"2.1.1\" to \"2.1.2\" [#3160](https://github.com/storybookjs/storybook/pull/3160)\n- Upgraded `babel-loader` in `app/polymer` from \"7.1.3\" to \"7.1.4\" [#3160](https://github.com/storybookjs/storybook/pull/3160)\n- Upgraded `case-sensitive-paths-webpack-plugin` in `app/polymer` from \"2.1.1\" to \"2.1.2\" [#3160](https://github.com/storybookjs/storybook/pull/3160)\n- Upgraded `babel-loader` in `app/react-native` from \"7.1.3\" to \"7.1.4\" [#3160](https://github.com/storybookjs/storybook/pull/3160)\n- Upgraded `case-sensitive-paths-webpack-plugin` in `app/react-native` from \"2.1.1\" to \"2.1.2\" [#3160](https://github.com/storybookjs/storybook/pull/3160)\n- Upgraded `babel-loader` in `app/vue` from \"7.1.3\" to \"7.1.4\" [#3160](https://github.com/storybookjs/storybook/pull/3160)\n- Upgraded `case-sensitive-paths-webpack-plugin` in `app/vue` from \"2.1.1\" to \"2.1.2\" [#3160](https://github.com/storybookjs/storybook/pull/3160)\n- Upgraded `karma-coverage-istanbul-reporter` in `examples/angular-cli` from \"1.4.1\" to \"1.4.2\" [#3160](https://github.com/storybookjs/storybook/pull/3160)\n- Upgraded `babel-loader` in `examples/polymer-cli` from \"7.1.3\" to \"7.1.4\" [#3160](https://github.com/storybookjs/storybook/pull/3160)\n- Upgraded `babel-loader` in `examples/vue-kitchen-sink` from \"7.1.3\" to \"7.1.4\" [#3160](https://github.com/storybookjs/storybook/pull/3160)\n- Upgraded `gatsby-plugin-sharp` in `/docs` from \"1.6.38\" to \"1.6.39\" [#3159](https://github.com/storybookjs/storybook/pull/3159)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.54\" to \"1.5.55\" [#3159](https://github.com/storybookjs/storybook/pull/3159)\n- Update jest-specific-snapshot in addons/storyshots from 0.4.0 to 0.5.0 [#3151](https://github.com/storybookjs/storybook/pull/3151)\n- Upgraded `gatsby-plugin-sharp` in `/docs` from \"1.6.37\" to \"1.6.38\" [#3146](https://github.com/storybookjs/storybook/pull/3146)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.53\" to \"1.5.54\" [#3146](https://github.com/storybookjs/storybook/pull/3146)\n- Upgraded `gatsby-source-filesystem` in `/docs` from \"1.5.25\" to \"1.5.26\" [#3146](https://github.com/storybookjs/storybook/pull/3146)\n- Upgraded `gatsby` in `/docs` from \"1.9.222\" to \"1.9.223\" [#3146](https://github.com/storybookjs/storybook/pull/3146)\n- Upgraded `webpack-hot-middleware` in `app/react` from \"2.21.1\" to \"2.21.2\" [#3145](https://github.com/storybookjs/storybook/pull/3145)\n- Upgraded `webpack-hot-middleware` in `lib/core` from \"2.21.1\" to \"2.21.2\" [#3145](https://github.com/storybookjs/storybook/pull/3145)\n- Upgraded `webpack-hot-middleware` in `app/angular` from \"2.21.1\" to \"2.21.2\" [#3145](https://github.com/storybookjs/storybook/pull/3145)\n- Upgraded `webpack-hot-middleware` in `app/polymer` from \"2.21.1\" to \"2.21.2\" [#3145](https://github.com/storybookjs/storybook/pull/3145)\n- Upgraded `webpack-hot-middleware` in `app/react-native` from \"2.21.1\" to \"2.21.2\" [#3145](https://github.com/storybookjs/storybook/pull/3145)\n- Upgraded `webpack-hot-middleware` in `app/vue` from \"2.21.1\" to \"2.21.2\" [#3145](https://github.com/storybookjs/storybook/pull/3145)\n- Upgraded `babel-plugin-macros` in `/` from \"2.1.0\" to \"2.2.0\" [#3137](https://github.com/storybookjs/storybook/pull/3137)\n- Upgraded `chalk` in `/` from \"2.3.1\" to \"2.3.2\" [#3137](https://github.com/storybookjs/storybook/pull/3137)\n- Upgraded `eslint` in `/` from \"4.18.1\" to \"4.18.2\" [#3137](https://github.com/storybookjs/storybook/pull/3137)\n- Upgraded `eslint-plugin-jest` in `/` from \"21.12.2\" to \"21.12.3\" [#3137](https://github.com/storybookjs/storybook/pull/3137)\n- Upgraded `babel-plugin-macros` in `app/react` from \"2.1.0\" to \"2.2.0\" [#3137](https://github.com/storybookjs/storybook/pull/3137)\n- Upgraded `glamorous` in `app/react` from \"4.11.6\" to \"4.12.0\" [#3137](https://github.com/storybookjs/storybook/pull/3137)\n- Upgraded `glamorous` in `addons/actions` from \"4.11.6\" to \"4.12.0\" [#3137](https://github.com/storybookjs/storybook/pull/3137)\n- Upgraded `glamorous` in `lib/components` from \"4.11.6\" to \"4.12.0\" [#3137](https://github.com/storybookjs/storybook/pull/3137)\n- Upgraded `glamorous` in `addons/a11y` from \"4.11.6\" to \"4.12.0\" [#3137](https://github.com/storybookjs/storybook/pull/3137)\n- Upgraded `glamorous` in `addons/info` from \"4.11.6\" to \"4.12.0\" [#3137](https://github.com/storybookjs/storybook/pull/3137)\n- Upgraded `glamorous` in `addons/jest` from \"4.11.6\" to \"4.12.0\" [#3137](https://github.com/storybookjs/storybook/pull/3137)\n- Upgraded `moment` in `addons/knobs` from \"2.20.1\" to \"2.21.0\" [#3137](https://github.com/storybookjs/storybook/pull/3137)\n- Upgraded `chalk` in `lib/core` from \"2.3.1\" to \"2.3.2\" [#3137](https://github.com/storybookjs/storybook/pull/3137)\n- Upgraded `babel-plugin-macros` in `app/angular` from \"2.1.0\" to \"2.2.0\" [#3137](https://github.com/storybookjs/storybook/pull/3137)\n- Upgraded `sass-loader` in `app/angular` from \"6.0.6\" to \"6.0.7\" [#3137](https://github.com/storybookjs/storybook/pull/3137)\n- Upgraded `babel-plugin-macros` in `app/polymer` from \"2.1.0\" to \"2.2.0\" [#3137](https://github.com/storybookjs/storybook/pull/3137)\n- Upgraded `babel-plugin-macros` in `app/react-native` from \"2.1.0\" to \"2.2.0\" [#3137](https://github.com/storybookjs/storybook/pull/3137)\n- Upgraded `babel-plugin-macros` in `app/vue` from \"2.1.0\" to \"2.2.0\" [#3137](https://github.com/storybookjs/storybook/pull/3137)\n- Upgraded `chalk` in `lib/cli` from \"2.3.1\" to \"2.3.2\" [#3137](https://github.com/storybookjs/storybook/pull/3137)\n- Upgraded `cross-spawn` in `lib/cli` from \"6.0.4\" to \"6.0.5\" [#3137](https://github.com/storybookjs/storybook/pull/3137)\n- Upgraded `gatsby-remark-copy-linked-files` in `/docs` from \"1.5.29\" to \"1.5.30\" [#3136](https://github.com/storybookjs/storybook/pull/3136)\n- Upgraded `gatsby` in `/docs` from \"1.9.221\" to \"1.9.222\" [#3136](https://github.com/storybookjs/storybook/pull/3136)\n- Upgraded `gatsby-link` in `/docs` from \"1.6.37\" to \"1.6.38\" [#3124](https://github.com/storybookjs/storybook/pull/3124)\n- Upgraded `gatsby-plugin-sharp` in `/docs` from \"1.6.35\" to \"1.6.37\" [#3124](https://github.com/storybookjs/storybook/pull/3124)\n- Upgraded `gatsby-remark-autolink-headers` in `/docs` from \"1.4.12\" to \"1.4.13\" [#3124](https://github.com/storybookjs/storybook/pull/3124)\n- Upgraded `gatsby-remark-copy-linked-files` in `/docs` from \"1.5.28\" to \"1.5.29\" [#3124](https://github.com/storybookjs/storybook/pull/3124)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.51\" to \"1.5.53\" [#3124](https://github.com/storybookjs/storybook/pull/3124)\n- Upgraded `gatsby-remark-smartypants` in `/docs` from \"1.4.11\" to \"1.4.12\" [#3124](https://github.com/storybookjs/storybook/pull/3124)\n- Upgraded `gatsby-source-filesystem` in `/docs` from \"1.5.24\" to \"1.5.25\" [#3124](https://github.com/storybookjs/storybook/pull/3124)\n- Upgraded `gatsby-transformer-remark` in `/docs` from \"1.7.33\" to \"1.7.34\" [#3124](https://github.com/storybookjs/storybook/pull/3124)\n- Upgraded `gatsby` in `/docs` from \"1.9.216\" to \"1.9.221\" [#3124](https://github.com/storybookjs/storybook/pull/3124)\n- Upgraded `codelyzer` in `/` from \"4.1.0\" to \"4.2.1\" [#3131](https://github.com/storybookjs/storybook/pull/3131)\n- Upgraded `file-loader` in `lib/core` from \"1.1.10\" to \"1.1.11\" [#3131](https://github.com/storybookjs/storybook/pull/3131)\n- Upgraded `copy-webpack-plugin` in `app/polymer` from \"4.4.2\" to \"4.5.0\" [#3131](https://github.com/storybookjs/storybook/pull/3131)\n- Upgraded `copy-webpack-plugin` in `examples/polymer-cli` from \"4.4.2\" to \"4.5.0\" [#3131](https://github.com/storybookjs/storybook/pull/3131)\n- Upgraded `file-loader` in `examples/vue-kitchen-sink` from \"1.1.10\" to \"1.1.11\" [#3131](https://github.com/storybookjs/storybook/pull/3131)\n- Upgraded `@angular/common` in `/` from \"5.2.6\" to \"5.2.7\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `@angular/compiler` in `/` from \"5.2.6\" to \"5.2.7\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `@angular/core` in `/` from \"5.2.6\" to \"5.2.7\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `@angular/forms` in `/` from \"5.2.6\" to \"5.2.7\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `@angular/platform-browser` in `/` from \"5.2.6\" to \"5.2.7\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `@angular/platform-browser-dynamic` in `/` from \"5.2.6\" to \"5.2.7\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `prettier` in `/` from \"1.11.0\" to \"1.11.1\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `prettier` in `addons/storysource` from \"1.11.0\" to \"1.11.1\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `babel-plugin-react-docgen` in `app/react` from \"1.8.2\" to \"1.8.3\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `webpack-hot-middleware` in `app/react` from \"2.21.0\" to \"2.21.1\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `nodemon` in `app/react` from \"1.15.1\" to \"1.17.1\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `jest-specific-snapshot` in `addons/storyshots` from \"0.3.0\" to \"0.4.0\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `react-color` in `addons/knobs` from \"2.13.8\" to \"2.14.0\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `webpack-hot-middleware` in `lib/core` from \"2.21.0\" to \"2.21.1\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `webpack-hot-middleware` in `app/angular` from \"2.21.0\" to \"2.21.1\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `nodemon` in `app/angular` from \"1.15.1\" to \"1.17.1\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `webpack-hot-middleware` in `app/polymer` from \"2.21.0\" to \"2.21.1\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `nodemon` in `app/polymer` from \"1.15.1\" to \"1.17.1\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `webpack-hot-middleware` in `app/react-native` from \"2.21.0\" to \"2.21.1\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `webpack-hot-middleware` in `app/vue` from \"2.21.0\" to \"2.21.1\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `nodemon` in `app/vue` from \"1.15.1\" to \"1.17.1\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `@angular/common` in `examples/angular-cli` from \"5.2.6\" to \"5.2.7\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `@angular/compiler` in `examples/angular-cli` from \"5.2.6\" to \"5.2.7\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `@angular/core` in `examples/angular-cli` from \"5.2.6\" to \"5.2.7\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `@angular/forms` in `examples/angular-cli` from \"5.2.6\" to \"5.2.7\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `@angular/platform-browser` in `examples/angular-cli` from \"5.2.6\" to \"5.2.7\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `@angular/platform-browser-dynamic` in `examples/angular-cli` from \"5.2.6\" to \"5.2.7\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `@angular/cli` in `examples/angular-cli` from \"1.7.1\" to \"1.7.2\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Upgraded `@angular/compiler-cli` in `examples/angular-cli` from \"5.2.6\" to \"5.2.7\" [#3123](https://github.com/storybookjs/storybook/pull/3123)\n- Vue example: upgrade vue-loader from 13.7.1 to 14.1.1 [#3077](https://github.com/storybookjs/storybook/pull/3077)\n- Maintenance: upgrade lint-staged from `6.1.1` to `7.0.0` [#3067](https://github.com/storybookjs/storybook/pull/3067)\n- Core & UI: upgrade events from 1.1.1 to 2.0.0 [#3075](https://github.com/storybookjs/storybook/pull/3075)\n- Upgraded `gatsby-plugin-sharp` in `/docs` from \"1.6.34\" to \"1.6.35\" [#3109](https://github.com/storybookjs/storybook/pull/3109)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.50\" to \"1.5.51\" [#3109](https://github.com/storybookjs/storybook/pull/3109)\n- Upgraded `gatsby` in `/docs` from \"1.9.215\" to \"1.9.216\" [#3109](https://github.com/storybookjs/storybook/pull/3109)\n- Upgraded `marked` in `/docs` from \"0.3.16\" to \"0.3.17\" [#3109](https://github.com/storybookjs/storybook/pull/3109)\n- Upgraded `prop-types` in `/docs` from \"15.6.0\" to \"15.6.1\" [#3109](https://github.com/storybookjs/storybook/pull/3109)\n- RN app: upgrade ws from 3.3.3 to 4.1.0 [#3074](https://github.com/storybookjs/storybook/pull/3074)\n- Upgraded `prettier` in `/` from \"1.10.2\" to \"1.11.0\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `prop-types` in `addons/background` from \"15.6.0\" to \"15.6.1\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `prop-types` in `addons/events` from \"15.6.0\" to \"15.6.1\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `acorn` in `addons/storysource` from \"5.4.1\" to \"5.5.0\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `acorn-stage3` in `addons/storysource` from \"0.5.0\" to \"0.6.0\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `prettier` in `addons/storysource` from \"1.10.2\" to \"1.11.0\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `prop-types` in `addons/storysource` from \"15.6.0\" to \"15.6.1\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `dotenv-webpack` in `app/react` from \"1.5.4\" to \"1.5.5\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `prop-types` in `app/react` from \"15.6.0\" to \"15.6.1\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `prop-types` in `addons/graphql` from \"15.6.0\" to \"15.6.1\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `marked` in `addons/notes` from \"0.3.16\" to \"0.3.17\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `prop-types` in `addons/notes` from \"15.6.0\" to \"15.6.1\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `prop-types` in `addons/actions` from \"15.6.0\" to \"15.6.1\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `prop-types` in `addons/links` from \"15.6.0\" to \"15.6.1\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `prop-types` in `lib/components` from \"15.6.0\" to \"15.6.1\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `prop-types` in `addons/a11y` from \"15.6.0\" to \"15.6.1\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `prop-types` in `addons/info` from \"15.6.0\" to \"15.6.1\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `prop-types` in `addons/jest` from \"15.6.0\" to \"15.6.1\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `prop-types` in `addons/knobs` from \"15.6.0\" to \"15.6.1\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `prop-types` in `addons/viewport` from \"15.6.0\" to \"15.6.1\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `prop-types` in `lib/ui` from \"15.6.0\" to \"15.6.1\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `dotenv` in `lib/core` from \"5.0.0\" to \"5.0.1\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `file-loader` in `lib/core` from \"1.1.9\" to \"1.1.10\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `prop-types` in `lib/core` from \"15.6.0\" to \"15.6.1\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `prop-types` in `examples/cra-kitchen-sink` from \"15.6.0\" to \"15.6.1\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `prop-types` in `examples/official-storybook` from \"15.6.0\" to \"15.6.1\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `dotenv-webpack` in `app/angular` from \"1.5.4\" to \"1.5.5\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `dotenv-webpack` in `app/polymer` from \"1.5.4\" to \"1.5.5\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `prop-types` in `app/react-native` from \"15.6.0\" to \"15.6.1\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `dotenv-webpack` in `app/vue` from \"1.5.4\" to \"1.5.5\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `webpack-dev-server` in `examples/polymer-cli` from \"2.11.1\" to \"2.11.2\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `file-loader` in `examples/vue-kitchen-sink` from \"1.1.9\" to \"1.1.10\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `webpack-dev-server` in `examples/vue-kitchen-sink` from \"2.11.1\" to \"2.11.2\" [#3108](https://github.com/storybookjs/storybook/pull/3108)\n- Upgraded `gatsby-source-filesystem` in `/docs` from \"1.5.23\" to \"1.5.24\" [#3103](https://github.com/storybookjs/storybook/pull/3103)\n- Upgraded `gatsby` in `/docs` from \"1.9.214\" to \"1.9.215\" [#3103](https://github.com/storybookjs/storybook/pull/3103)\n- Upgraded `jest-preset-angular` in `/` from \"5.1.0\" to \"5.2.0\" [#3104](https://github.com/storybookjs/storybook/pull/3104)\n- Upgraded `postcss-loader` in `lib/core` from \"2.1.0\" to \"2.1.1\" [#3104](https://github.com/storybookjs/storybook/pull/3104)\n- Upgraded `tslint-config-prettier` in `/` from \"1.8.0\" to \"1.9.0\" [#3097](https://github.com/storybookjs/storybook/pull/3097)\n- Upgraded `babel-loader` in `app/react` from \"7.1.2\" to \"7.1.3\" [#3097](https://github.com/storybookjs/storybook/pull/3097)\n- Upgraded `babel-loader` in `app/angular` from \"7.1.2\" to \"7.1.3\" [#3097](https://github.com/storybookjs/storybook/pull/3097)\n- Upgraded `babel-loader` in `app/polymer` from \"7.1.2\" to \"7.1.3\" [#3097](https://github.com/storybookjs/storybook/pull/3097)\n- Upgraded `babel-loader` in `app/react-native` from \"7.1.2\" to \"7.1.3\" [#3097](https://github.com/storybookjs/storybook/pull/3097)\n- Upgraded `babel-loader` in `app/vue` from \"7.1.2\" to \"7.1.3\" [#3097](https://github.com/storybookjs/storybook/pull/3097)\n- Upgraded `babel-loader` in `examples/polymer-cli` from \"7.1.2\" to \"7.1.3\" [#3097](https://github.com/storybookjs/storybook/pull/3097)\n- Upgraded `babel-loader` in `examples/vue-kitchen-sink` from \"7.1.2\" to \"7.1.3\" [#3097](https://github.com/storybookjs/storybook/pull/3097)\n- Update gatsby in /docs from 1.9.212 to 1.9.214 [#3095](https://github.com/storybookjs/storybook/pull/3095)\n- Upgraded `gatsby-plugin-sharp` in `/docs` from \"1.6.33\" to \"1.6.34\" [#3071](https://github.com/storybookjs/storybook/pull/3071)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.49\" to \"1.5.50\" [#3071](https://github.com/storybookjs/storybook/pull/3071)\n- Upgraded `gatsby-source-filesystem` in `/docs` from \"1.5.22\" to \"1.5.23\" [#3071](https://github.com/storybookjs/storybook/pull/3071)\n- Upgraded `gatsby` in `/docs` from \"1.9.209\" to \"1.9.212\" [#3071](https://github.com/storybookjs/storybook/pull/3071)\n- Upgraded `puppeteer` in `/` from \"1.1.0\" to \"1.1.1\" [#3069](https://github.com/storybookjs/storybook/pull/3069)\n- Upgraded `react-syntax-highlighter` in `addons/storysource` from \"7.0.0\" to \"7.0.1\" [#3069](https://github.com/storybookjs/storybook/pull/3069)\n- Upgraded `uglifyjs-webpack-plugin` in `app/react` from \"1.2.0\" to \"1.2.2\" [#3069](https://github.com/storybookjs/storybook/pull/3069)\n- Upgraded `puppeteer` in `addons/storyshots` from \"1.0.0\" to \"1.1.1\" [#3069](https://github.com/storybookjs/storybook/pull/3069)\n- Upgraded `uglifyjs-webpack-plugin` in `app/angular` from \"1.2.0\" to \"1.2.2\" [#3069](https://github.com/storybookjs/storybook/pull/3069)\n- Upgraded `copy-webpack-plugin` in `app/polymer` from \"4.4.1\" to \"4.4.2\" [#3069](https://github.com/storybookjs/storybook/pull/3069)\n- Upgraded `uglifyjs-webpack-plugin` in `app/polymer` from \"1.2.0\" to \"1.2.2\" [#3069](https://github.com/storybookjs/storybook/pull/3069)\n- Upgraded `uglifyjs-webpack-plugin` in `app/react-native` from \"1.2.0\" to \"1.2.2\" [#3069](https://github.com/storybookjs/storybook/pull/3069)\n- Upgraded `uglifyjs-webpack-plugin` in `app/vue` from \"1.2.0\" to \"1.2.2\" [#3069](https://github.com/storybookjs/storybook/pull/3069)\n- Upgraded `copy-webpack-plugin` in `examples/polymer-cli` from \"4.4.1\" to \"4.4.2\" [#3069](https://github.com/storybookjs/storybook/pull/3069)\n- Upgraded `jest` in `/` from \"22.4.0\" to \"22.4.2\" [#3063](https://github.com/storybookjs/storybook/pull/3063)\n- Upgraded `jest-cli` in `/` from \"22.4.0\" to \"22.4.2\" [#3063](https://github.com/storybookjs/storybook/pull/3063)\n- Upgraded `jest-config` in `/` from \"22.4.0\" to \"22.4.2\" [#3063](https://github.com/storybookjs/storybook/pull/3063)\n- Upgraded `jest-environment-jsdom` in `/` from \"22.4.0\" to \"22.4.1\" [#3063](https://github.com/storybookjs/storybook/pull/3063)\n- Upgraded `jest-jasmine2` in `/` from \"22.4.0\" to \"22.4.2\" [#3063](https://github.com/storybookjs/storybook/pull/3063)\n- Upgraded `css-loader` in `app/react` from \"0.28.9\" to \"0.28.10\" [#3063](https://github.com/storybookjs/storybook/pull/3063)\n- Upgraded `babel-jest` in `addons/storyshots` from \"22.4.0\" to \"22.4.1\" [#3063](https://github.com/storybookjs/storybook/pull/3063)\n- Upgraded `jest` in `addons/storyshots` from \"22.4.0\" to \"22.4.2\" [#3063](https://github.com/storybookjs/storybook/pull/3063)\n- Upgraded `jest-cli` in `addons/storyshots` from \"22.4.0\" to \"22.4.2\" [#3063](https://github.com/storybookjs/storybook/pull/3063)\n- Upgraded `css-loader` in `lib/core` from \"0.28.9\" to \"0.28.10\" [#3063](https://github.com/storybookjs/storybook/pull/3063)\n- Upgraded `babel-jest` in `examples/cra-kitchen-sink` from \"22.4.0\" to \"22.4.1\" [#3063](https://github.com/storybookjs/storybook/pull/3063)\n- Upgraded `jest` in `examples/cra-kitchen-sink` from \"22.4.0\" to \"22.4.2\" [#3063](https://github.com/storybookjs/storybook/pull/3063)\n- Upgraded `babel-jest` in `examples/official-storybook` from \"22.4.0\" to \"22.4.1\" [#3063](https://github.com/storybookjs/storybook/pull/3063)\n- Upgraded `jest` in `examples/official-storybook` from \"22.4.0\" to \"22.4.2\" [#3063](https://github.com/storybookjs/storybook/pull/3063)\n- Upgraded `css-loader` in `app/angular` from \"0.28.9\" to \"0.28.10\" [#3063](https://github.com/storybookjs/storybook/pull/3063)\n- Upgraded `css-loader` in `app/polymer` from \"0.28.9\" to \"0.28.10\" [#3063](https://github.com/storybookjs/storybook/pull/3063)\n- Upgraded `css-loader` in `app/react-native` from \"0.28.9\" to \"0.28.10\" [#3063](https://github.com/storybookjs/storybook/pull/3063)\n- Upgraded `css-loader` in `app/vue` from \"0.28.9\" to \"0.28.10\" [#3063](https://github.com/storybookjs/storybook/pull/3063)\n- Upgraded `css-loader` in `examples/vue-kitchen-sink` from \"0.28.9\" to \"0.28.10\" [#3063](https://github.com/storybookjs/storybook/pull/3063)\n- Upgraded `gatsby-plugin-sharp` in `/docs` from \"1.6.32\" to \"1.6.33\" [#3064](https://github.com/storybookjs/storybook/pull/3064)\n- Upgraded `gatsby-remark-copy-linked-files` in `/docs` from \"1.5.27\" to \"1.5.28\" [#3064](https://github.com/storybookjs/storybook/pull/3064)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.48\" to \"1.5.49\" [#3064](https://github.com/storybookjs/storybook/pull/3064)\n- Upgraded `gatsby-source-filesystem` in `/docs` from \"1.5.21\" to \"1.5.22\" [#3064](https://github.com/storybookjs/storybook/pull/3064)\n- Upgraded `gatsby` in `/docs` from \"1.9.206\" to \"1.9.209\" [#3064](https://github.com/storybookjs/storybook/pull/3064)\n- Upgraded `@angular/common` in `/` from \"5.2.5\" to \"5.2.6\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `@angular/compiler` in `/` from \"5.2.5\" to \"5.2.6\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `@angular/core` in `/` from \"5.2.5\" to \"5.2.6\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `@angular/forms` in `/` from \"5.2.5\" to \"5.2.6\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `@angular/platform-browser` in `/` from \"5.2.5\" to \"5.2.6\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `@angular/platform-browser-dynamic` in `/` from \"5.2.5\" to \"5.2.6\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `eslint-plugin-import` in `/` from \"2.8.0\" to \"2.9.0\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `jest-preset-angular` in `/` from \"5.0.0\" to \"5.1.0\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `file-loader` in `app/react` from \"1.1.8\" to \"1.1.9\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `file-loader` in `lib/core` from \"1.1.8\" to \"1.1.9\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `react-chromatic` in `examples/official-storybook` from \"0.7.9\" to \"0.7.10\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `file-loader` in `app/angular` from \"1.1.8\" to \"1.1.9\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `file-loader` in `app/polymer` from \"1.1.8\" to \"1.1.9\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `file-loader` in `app/react-native` from \"1.1.8\" to \"1.1.9\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `file-loader` in `app/vue` from \"1.1.8\" to \"1.1.9\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `@angular/animations` in `examples/angular-cli` from \"5.2.5\" to \"5.2.6\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `@angular/common` in `examples/angular-cli` from \"5.2.5\" to \"5.2.6\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `@angular/compiler` in `examples/angular-cli` from \"5.2.5\" to \"5.2.6\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `@angular/core` in `examples/angular-cli` from \"5.2.5\" to \"5.2.6\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `@angular/forms` in `examples/angular-cli` from \"5.2.5\" to \"5.2.6\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `@angular/http` in `examples/angular-cli` from \"5.2.5\" to \"5.2.6\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `@angular/platform-browser` in `examples/angular-cli` from \"5.2.5\" to \"5.2.6\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `@angular/platform-browser-dynamic` in `examples/angular-cli` from \"5.2.5\" to \"5.2.6\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `@angular/router` in `examples/angular-cli` from \"5.2.5\" to \"5.2.6\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `@angular/cli` in `examples/angular-cli` from \"1.7.0\" to \"1.7.1\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `@angular/compiler-cli` in `examples/angular-cli` from \"5.2.5\" to \"5.2.6\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `@angular/language-service` in `examples/angular-cli` from \"5.2.5\" to \"5.2.6\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `file-loader` in `examples/vue-kitchen-sink` from \"1.1.8\" to \"1.1.9\" [#3055](https://github.com/storybookjs/storybook/pull/3055)\n- Upgraded `gatsby-plugin-sharp` in `/docs` from \"1.6.31\" to \"1.6.32\" [#3056](https://github.com/storybookjs/storybook/pull/3056)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.47\" to \"1.5.48\" [#3056](https://github.com/storybookjs/storybook/pull/3056)\n- Upgraded `gatsby` in `/docs` from \"1.9.204\" to \"1.9.206\" [#3056](https://github.com/storybookjs/storybook/pull/3056)\n\n</details>\n\n## 3.3.15\n\n2018-March-07\n\n#### Bug Fixes\n\n- Unset background when switching to a non-background story [#3142](https://github.com/storybookjs/storybook/pull/3142)\n- Updated testIds in RN StoryListView to use kind [#3129](https://github.com/storybookjs/storybook/pull/3129)\n- Added missing key prop to NoTests component. [#3111](https://github.com/storybookjs/storybook/pull/3111)\n- Events addon: fix React keys warning [#3072](https://github.com/storybookjs/storybook/pull/3072)\n\n## 3.4.0-alpha.9\n\n2018-February-22\n\n#### Features\n\n- Addon-storysource: story source in addon pane [#2885](https://github.com/storybookjs/storybook/pull/2885)\n- Addon Storysource improvements [#3040](https://github.com/storybookjs/storybook/pull/3040)\n- Add moduleMetadata decorator for supplying common Angular metadata [#2959](https://github.com/storybookjs/storybook/pull/2959)\n- `Addon Storysource` Add auto scrolling to the selected story [#3025](https://github.com/storybookjs/storybook/pull/3025)\n- Enable groupId option for knobs to be organized into sub panels. [#2661](https://github.com/storybookjs/storybook/pull/2661)\n- Added beforeScreenshot config option to addons/storyshots, to allow testing of components with mounting animations [#2972](https://github.com/storybookjs/storybook/pull/2972)\n- Add GitHub flavored markdown notes [#2946](https://github.com/storybookjs/storybook/pull/2946)\n\n#### Bug Fixes\n\n- Fix problem with RN on latest `master` build [#3045](https://github.com/storybookjs/storybook/pull/3045)\n- Use @storybook/podda to fix npm engine version in podda [#3033](https://github.com/storybookjs/storybook/pull/3033)\n\n#### Documentation\n\n- Revisit addon/framework support [#3046](https://github.com/storybookjs/storybook/pull/3046)\n- Docs live examples [#3019](https://github.com/storybookjs/storybook/pull/3019)\n- Mention new supported frameworks [#2895](https://github.com/storybookjs/storybook/pull/2895)\n\n#### Maintenance\n\n- Use core client api in react native [#3036](https://github.com/storybookjs/storybook/pull/3036)\n- Optimize CI workflow [#3016](https://github.com/storybookjs/storybook/pull/3016)\n- Integration tests: wait until stories appear [#3027](https://github.com/storybookjs/storybook/pull/3027)\n- Add netlify for polymer [#3004](https://github.com/storybookjs/storybook/pull/3004)\n- Add built storybooks to official storybook [#2958](https://github.com/storybookjs/storybook/pull/2958)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n169 Updates\n</summary>\n\n- Upgraded `@storybook/addon-actions` in `/docs` from \"3.3.13\" to \"3.3.14\" [#3051](https://github.com/storybookjs/storybook/pull/3051)\n- Upgraded `@storybook/addon-links` in `/docs` from \"3.3.13\" to \"3.3.14\" [#3051](https://github.com/storybookjs/storybook/pull/3051)\n- Upgraded `@storybook/addons` in `/docs` from \"3.3.13\" to \"3.3.14\" [#3051](https://github.com/storybookjs/storybook/pull/3051)\n- Upgraded `@storybook/react` in `/docs` from \"3.3.13\" to \"3.3.14\" [#3051](https://github.com/storybookjs/storybook/pull/3051)\n- Upgraded `gatsby-source-filesystem` in `/docs` from \"1.5.20\" to \"1.5.21\" [#3051](https://github.com/storybookjs/storybook/pull/3051)\n- Upgraded `gatsby` in `/docs` from \"1.9.203\" to \"1.9.204\" [#3051](https://github.com/storybookjs/storybook/pull/3051)\n- Upgraded `marked` in `/docs` from \"0.3.15\" to \"0.3.16\" [#3051](https://github.com/storybookjs/storybook/pull/3051)\n- Upgraded `eslint` in `/` from \"4.18.0\" to \"4.18.1\" [#3050](https://github.com/storybookjs/storybook/pull/3050)\n- Upgraded `jscodeshift` in `lib/codemod` from \"0.4.0\" to \"0.4.1\" [#3050](https://github.com/storybookjs/storybook/pull/3050)\n- Upgraded `file-loader` in `app/react` from \"1.1.7\" to \"1.1.8\" [#3050](https://github.com/storybookjs/storybook/pull/3050)\n- Upgraded `marked` in `addons/notes` from \"0.3.15\" to \"0.3.16\" [#3050](https://github.com/storybookjs/storybook/pull/3050)\n- Upgraded `react-modal` in `lib/ui` from \"3.2.1\" to \"3.3.1\" [#3050](https://github.com/storybookjs/storybook/pull/3050)\n- Upgraded `file-loader` in `lib/core` from \"1.1.7\" to \"1.1.8\" [#3050](https://github.com/storybookjs/storybook/pull/3050)\n- Upgraded `file-loader` in `app/angular` from \"1.1.7\" to \"1.1.8\" [#3050](https://github.com/storybookjs/storybook/pull/3050)\n- Upgraded `react-modal` in `app/angular` from \"3.2.1\" to \"3.3.1\" [#3050](https://github.com/storybookjs/storybook/pull/3050)\n- Upgraded `ts-loader` in `app/angular` from \"3.3.1\" to \"3.5.0\" [#3050](https://github.com/storybookjs/storybook/pull/3050)\n- Upgraded `file-loader` in `app/polymer` from \"1.1.7\" to \"1.1.8\" [#3050](https://github.com/storybookjs/storybook/pull/3050)\n- Upgraded `react-modal` in `app/polymer` from \"3.2.1\" to \"3.3.1\" [#3050](https://github.com/storybookjs/storybook/pull/3050)\n- Upgraded `file-loader` in `app/react-native` from \"1.1.7\" to \"1.1.8\" [#3050](https://github.com/storybookjs/storybook/pull/3050)\n- Upgraded `file-loader` in `app/vue` from \"1.1.7\" to \"1.1.8\" [#3050](https://github.com/storybookjs/storybook/pull/3050)\n- Upgraded `vue-hot-reload-api` in `app/vue` from \"2.2.4\" to \"2.3.0\" [#3050](https://github.com/storybookjs/storybook/pull/3050)\n- Upgraded `jscodeshift` in `lib/cli` from \"0.4.0\" to \"0.4.1\" [#3050](https://github.com/storybookjs/storybook/pull/3050)\n- Upgraded `file-loader` in `examples/vue-kitchen-sink` from \"1.1.7\" to \"1.1.8\" [#3050](https://github.com/storybookjs/storybook/pull/3050)\n- Upgraded `vue-hot-reload-api` in `examples/vue-kitchen-sink` from \"2.2.4\" to \"2.3.0\" [#3050](https://github.com/storybookjs/storybook/pull/3050)\n- Upgraded `babel-eslint` in `/` from \"8.2.1\" to \"8.2.2\" [#3041](https://github.com/storybookjs/storybook/pull/3041)\n- Upgraded `jest` in `/` from \"22.3.0\" to \"22.4.0\" [#3041](https://github.com/storybookjs/storybook/pull/3041)\n- Upgraded `jest-cli` in `/` from \"22.3.0\" to \"22.4.0\" [#3041](https://github.com/storybookjs/storybook/pull/3041)\n- Upgraded `jest-config` in `/` from \"22.3.0\" to \"22.4.0\" [#3041](https://github.com/storybookjs/storybook/pull/3041)\n- Upgraded `jest-diff` in `/` from \"22.1.0\" to \"22.4.0\" [#3041](https://github.com/storybookjs/storybook/pull/3041)\n- Upgraded `jest-environment-jsdom` in `/` from \"22.3.0\" to \"22.4.0\" [#3041](https://github.com/storybookjs/storybook/pull/3041)\n- Upgraded `jest-jasmine2` in `/` from \"22.3.0\" to \"22.4.0\" [#3041](https://github.com/storybookjs/storybook/pull/3041)\n- Upgraded `babel-jest` in `addons/storyshots` from \"22.1.0\" to \"22.4.0\" [#3041](https://github.com/storybookjs/storybook/pull/3041)\n- Upgraded `jest` in `addons/storyshots` from \"22.3.0\" to \"22.4.0\" [#3041](https://github.com/storybookjs/storybook/pull/3041)\n- Upgraded `jest-cli` in `addons/storyshots` from \"22.3.0\" to \"22.4.0\" [#3041](https://github.com/storybookjs/storybook/pull/3041)\n- Upgraded `babel-jest` in `examples/cra-kitchen-sink` from \"22.2.2\" to \"22.4.0\" [#3041](https://github.com/storybookjs/storybook/pull/3041)\n- Upgraded `jest` in `examples/cra-kitchen-sink` from \"22.3.0\" to \"22.4.0\" [#3041](https://github.com/storybookjs/storybook/pull/3041)\n- Upgraded `babel-jest` in `examples/official-storybook` from \"22.1.0\" to \"22.4.0\" [#3041](https://github.com/storybookjs/storybook/pull/3041)\n- Upgraded `jest` in `examples/official-storybook` from \"22.3.0\" to \"22.4.0\" [#3041](https://github.com/storybookjs/storybook/pull/3041)\n- Addon-storyshots: upgrade puppeteer to 1.0.0 [#2853](https://github.com/storybookjs/storybook/pull/2853)\n- App-angular: upgrade ts-loader to 3.3.1 [#2855](https://github.com/storybookjs/storybook/pull/2855)\n- Update cross-spawn in lib/cli from 6.0.3 to 6.0.4 [#3039](https://github.com/storybookjs/storybook/pull/3039)\n- Update eslint-plugin-react in / from 7.6.1 to 7.7.0 [#3037](https://github.com/storybookjs/storybook/pull/3037)\n- CLI: upgrade cross-spawn to 6.0.3 [#2854](https://github.com/storybookjs/storybook/pull/2854)\n- Update gatsby in /docs from 1.9.202 to 1.9.203 [#3034](https://github.com/storybookjs/storybook/pull/3034)\n- Upgraded `gatsby-plugin-sharp` in `/docs` from \"1.6.30\" to \"1.6.31\" [#3030](https://github.com/storybookjs/storybook/pull/3030)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.46\" to \"1.5.47\" [#3030](https://github.com/storybookjs/storybook/pull/3030)\n- Upgraded `gatsby-transformer-remark` in `/docs` from \"1.7.32\" to \"1.7.33\" [#3030](https://github.com/storybookjs/storybook/pull/3030)\n- Upgraded `nodemon` in `/` from \"1.15.0\" to \"1.15.1\" [#3028](https://github.com/storybookjs/storybook/pull/3028)\n- Upgraded `file-loader` in `app/react` from \"1.1.6\" to \"1.1.7\" [#3028](https://github.com/storybookjs/storybook/pull/3028)\n- Upgraded `nodemon` in `app/react` from \"1.15.0\" to \"1.15.1\" [#3028](https://github.com/storybookjs/storybook/pull/3028)\n- Upgraded `file-loader` in `lib/core` from \"1.1.6\" to \"1.1.7\" [#3028](https://github.com/storybookjs/storybook/pull/3028)\n- Upgraded `file-loader` in `app/angular` from \"1.1.6\" to \"1.1.7\" [#3028](https://github.com/storybookjs/storybook/pull/3028)\n- Upgraded `nodemon` in `app/angular` from \"1.15.0\" to \"1.15.1\" [#3028](https://github.com/storybookjs/storybook/pull/3028)\n- Upgraded `file-loader` in `app/polymer` from \"1.1.6\" to \"1.1.7\" [#3028](https://github.com/storybookjs/storybook/pull/3028)\n- Upgraded `nodemon` in `app/polymer` from \"1.15.0\" to \"1.15.1\" [#3028](https://github.com/storybookjs/storybook/pull/3028)\n- Upgraded `file-loader` in `app/react-native` from \"1.1.6\" to \"1.1.7\" [#3028](https://github.com/storybookjs/storybook/pull/3028)\n- Upgraded `file-loader` in `app/vue` from \"1.1.6\" to \"1.1.7\" [#3028](https://github.com/storybookjs/storybook/pull/3028)\n- Upgraded `nodemon` in `app/vue` from \"1.15.0\" to \"1.15.1\" [#3028](https://github.com/storybookjs/storybook/pull/3028)\n- Upgraded `file-loader` in `examples/vue-kitchen-sink` from \"1.1.6\" to \"1.1.7\" [#3028](https://github.com/storybookjs/storybook/pull/3028)\n- Update marked in /docs from 0.3.14 to 0.3.15 [#3021](https://github.com/storybookjs/storybook/pull/3021)\n- Core: upgrade dotenv to 5.0.0 [#2878](https://github.com/storybookjs/storybook/pull/2878)\n- Update acorn-stage3 in addons/storysource from 0.4.0 to 0.5.0 [#3014](https://github.com/storybookjs/storybook/pull/3014)\n- Update gatsby in /docs from 1.9.201 to 1.9.202 [#3012](https://github.com/storybookjs/storybook/pull/3012)\n- Update marked in addons/notes from 0.3.12 to 0.3.14 [#3015](https://github.com/storybookjs/storybook/pull/3015)\n- Upgraded `danger` in `/` from \"3.1.6\" to \"3.1.7\" [#3013](https://github.com/storybookjs/storybook/pull/3013)\n- Upgraded `eslint-plugin-jest` in `/` from \"21.12.1\" to \"21.12.2\" [#3013](https://github.com/storybookjs/storybook/pull/3013)\n- Upgraded `glamorous` in `lib/components` from \"4.11.5\" to \"4.11.6\" [#3009](https://github.com/storybookjs/storybook/pull/3009)\n- Upgraded `glamorous` in `addons/a11y` from \"4.11.5\" to \"4.11.6\" [#3009](https://github.com/storybookjs/storybook/pull/3009)\n- Upgraded `glamorous` in `addons/info` from \"4.11.5\" to \"4.11.6\" [#3009](https://github.com/storybookjs/storybook/pull/3009)\n- Upgraded `glamorous` in `addons/jest` from \"4.11.5\" to \"4.11.6\" [#3009](https://github.com/storybookjs/storybook/pull/3009)\n- Upgraded `glamorous` in `app/react` from \"4.11.5\" to \"4.11.6\" [#3009](https://github.com/storybookjs/storybook/pull/3009)\n- Upgraded `glamorous` in `examples/cra-kitchen-sink` from \"4.11.5\" to \"4.11.6\" [#3009](https://github.com/storybookjs/storybook/pull/3009)\n- Upgraded `gatsby-plugin-sharp` in `/docs` from \"1.6.29\" to \"1.6.30\" [#3008](https://github.com/storybookjs/storybook/pull/3008)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.45\" to \"1.5.46\" [#3008](https://github.com/storybookjs/storybook/pull/3008)\n- Upgraded `eslint` in `/` from \"4.17.0\" to \"4.18.0\" [#3006](https://github.com/storybookjs/storybook/pull/3006)\n- Upgraded `uglifyjs-webpack-plugin` in `app/angular` from \"1.1.8\" to \"1.2.0\" [#3006](https://github.com/storybookjs/storybook/pull/3006)\n- Upgraded `uglifyjs-webpack-plugin` in `app/polymer` from \"1.1.8\" to \"1.2.0\" [#3006](https://github.com/storybookjs/storybook/pull/3006)\n- Upgraded `uglifyjs-webpack-plugin` in `app/react-native` from \"1.1.8\" to \"1.2.0\" [#3006](https://github.com/storybookjs/storybook/pull/3006)\n- Upgraded `uglifyjs-webpack-plugin` in `app/react` from \"1.1.8\" to \"1.2.0\" [#3006](https://github.com/storybookjs/storybook/pull/3006)\n- Upgraded `uglifyjs-webpack-plugin` in `app/vue` from \"1.1.8\" to \"1.2.0\" [#3006](https://github.com/storybookjs/storybook/pull/3006)\n- Upgraded `gatsby-plugin-sharp` in `/docs` from \"1.6.28\" to \"1.6.29\" [#3005](https://github.com/storybookjs/storybook/pull/3005)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.44\" to \"1.5.45\" [#3005](https://github.com/storybookjs/storybook/pull/3005)\n- Upgraded `gatsby-source-filesystem` in `/docs` from \"1.5.19\" to \"1.5.20\" [#3005](https://github.com/storybookjs/storybook/pull/3005)\n- Upgraded `gatsby` in `/docs` from \"1.9.200\" to \"1.9.201\" [#3005](https://github.com/storybookjs/storybook/pull/3005)\n- Upgraded `lint-staged` in `/` from \"6.1.0\" to \"6.1.1\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `nodemon` in `/` from \"1.14.12\" to \"1.15.0\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `puppeteer` in `/` from \"1.0.0\" to \"1.1.0\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `typescript` in `/` from \"2.7.1\" to \"2.7.2\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `graphql` in `addons/graphql` from \"0.13.0\" to \"0.13.1\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `style-loader` in `addons/knobs` from \"0.20.1\" to \"0.20.2\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `glamorous` in `lib/components` from \"4.11.4\" to \"4.11.5\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `glamorous` in `addons/a11y` from \"4.11.4\" to \"4.11.5\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `glamorous` in `addons/info` from \"4.11.4\" to \"4.11.5\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `glamorous` in `addons/jest` from \"4.11.4\" to \"4.11.5\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `style-loader` in `lib/core` from \"0.20.1\" to \"0.20.2\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `style-loader` in `app/angular` from \"0.20.1\" to \"0.20.2\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `nodemon` in `app/angular` from \"1.14.12\" to \"1.15.0\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `typescript` in `app/angular` from \"2.7.1\" to \"2.7.2\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `style-loader` in `app/polymer` from \"0.20.1\" to \"0.20.2\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `nodemon` in `app/polymer` from \"1.14.12\" to \"1.15.0\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `style-loader` in `app/react-native` from \"0.20.1\" to \"0.20.2\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `glamorous` in `app/react` from \"4.11.4\" to \"4.11.5\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `style-loader` in `app/react` from \"0.20.1\" to \"0.20.2\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `nodemon` in `app/react` from \"1.14.12\" to \"1.15.0\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `style-loader` in `app/vue` from \"0.20.1\" to \"0.20.2\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `nodemon` in `app/vue` from \"1.14.12\" to \"1.15.0\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `@angular/cli` in `examples/angular-cli` from \"1.6.8\" to \"1.7.0\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `typescript` in `examples/angular-cli` from \"2.7.1\" to \"2.7.2\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Upgraded `glamorous` in `examples/cra-kitchen-sink` from \"4.11.4\" to \"4.11.5\" [#3003](https://github.com/storybookjs/storybook/pull/3003)\n- Update gatsby in /docs from 1.9.199 to 1.9.200 [#3001](https://github.com/storybookjs/storybook/pull/3001)\n- Update marked in /docs from 0.3.12 to 0.3.14 [#2999](https://github.com/storybookjs/storybook/pull/2999)\n- Upgraded `react-modal` in `lib/ui` from \"3.1.13\" to \"3.2.1\" [#2992](https://github.com/storybookjs/storybook/pull/2992)\n- Upgraded `react-modal` in `app/angular` from \"3.1.13\" to \"3.2.1\" [#2992](https://github.com/storybookjs/storybook/pull/2992)\n- Upgraded `react-modal` in `app/polymer` from \"3.1.13\" to \"3.2.1\" [#2992](https://github.com/storybookjs/storybook/pull/2992)\n- Update 8 dependencies from npm [#2978](https://github.com/storybookjs/storybook/pull/2978)\n- Update make-error in addons/actions from 1.3.3 to 1.3.4 [#2991](https://github.com/storybookjs/storybook/pull/2991)\n- Update 2 dependencies from npm [#2712](https://github.com/storybookjs/storybook/pull/2712)\n- Update tslint-config-prettier in / from 1.7.0 to 1.8.0 [#2990](https://github.com/storybookjs/storybook/pull/2990)\n- Update lerna in / from 2.8.0 to 2.9.0 [#2987](https://github.com/storybookjs/storybook/pull/2987)\n- Update `eslint-plugin-react` in `/` from \"7.6.0\" to \"7.6.1\" [#2864](https://github.com/storybookjs/storybook/pull/2864)\n- Upgraded `@angular/common` in `/` from \"5.2.4\" to \"5.2.5\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `@angular/compiler` in `/` from \"5.2.4\" to \"5.2.5\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `@angular/core` in `/` from \"5.2.4\" to \"5.2.5\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `@angular/forms` in `/` from \"5.2.4\" to \"5.2.5\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `@angular/platform-browser` in `/` from \"5.2.4\" to \"5.2.5\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `@angular/platform-browser-dynamic` in `/` from \"5.2.4\" to \"5.2.5\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `jest` in `/` from \"22.2.1\" to \"22.3.0\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `jest-cli` in `/` from \"22.2.2\" to \"22.3.0\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `jest-config` in `/` from \"22.2.2\" to \"22.3.0\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `jest-environment-jsdom` in `/` from \"22.2.2\" to \"22.3.0\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `jest-jasmine2` in `/` from \"22.2.2\" to \"22.3.0\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `jest` in `addons/storyshots` from \"22.1.4\" to \"22.3.0\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `jest-cli` in `addons/storyshots` from \"22.1.4\" to \"22.3.0\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `@angular/animations` in `examples/angular-cli` from \"5.2.4\" to \"5.2.5\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `@angular/common` in `examples/angular-cli` from \"5.2.4\" to \"5.2.5\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `@angular/compiler` in `examples/angular-cli` from \"5.2.4\" to \"5.2.5\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `@angular/core` in `examples/angular-cli` from \"5.2.4\" to \"5.2.5\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `@angular/forms` in `examples/angular-cli` from \"5.2.4\" to \"5.2.5\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `@angular/http` in `examples/angular-cli` from \"5.2.4\" to \"5.2.5\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `@angular/platform-browser` in `examples/angular-cli` from \"5.2.4\" to \"5.2.5\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `@angular/platform-browser-dynamic` in `examples/angular-cli` from \"5.2.4\" to \"5.2.5\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `@angular/router` in `examples/angular-cli` from \"5.2.4\" to \"5.2.5\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `@angular/compiler-cli` in `examples/angular-cli` from \"5.2.4\" to \"5.2.5\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `@angular/language-service` in `examples/angular-cli` from \"5.2.4\" to \"5.2.5\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `@types/node` in `examples/angular-cli` from \"9.4.5\" to \"9.4.6\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `jest` in `examples/cra-kitchen-sink` from \"22.2.2\" to \"22.3.0\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Upgraded `jest` in `examples/official-storybook` from \"22.1.4\" to \"22.3.0\" [#2986](https://github.com/storybookjs/storybook/pull/2986)\n- Update gatsby in /docs from 1.9.198 to 1.9.199 [#2988](https://github.com/storybookjs/storybook/pull/2988)\n- Update gatsby in /docs from 1.9.197 to 1.9.198 [#2985](https://github.com/storybookjs/storybook/pull/2985)\n- Update gatsby in /docs from 1.9.193 to 1.9.197 [#2983](https://github.com/storybookjs/storybook/pull/2983)\n- Upgraded `danger` in `/` from \"3.1.3\" to \"3.1.6\" [#2977](https://github.com/storybookjs/storybook/pull/2977)\n- Upgraded `eslint-plugin-jest` in `/` from \"21.12.0\" to \"21.12.1\" [#2977](https://github.com/storybookjs/storybook/pull/2977)\n- Upgraded `inquirer` in `/` from \"5.0.1\" to \"5.1.0\" [#2977](https://github.com/storybookjs/storybook/pull/2977)\n- Upgraded `react-fuzzy` in `lib/ui` from \"0.5.1\" to \"0.5.2\" [#2977](https://github.com/storybookjs/storybook/pull/2977)\n- Upgraded `@types/node` in `examples/angular-cli` from \"9.4.0\" to \"9.4.5\" [#2977](https://github.com/storybookjs/storybook/pull/2977)\n- Upgraded `babel-preset-vue` in `examples/vue-kitchen-sink` from \"2.0.0\" to \"2.0.1\" [#2977](https://github.com/storybookjs/storybook/pull/2977)\n- Update gatsby in /docs from 1.9.188 to 1.9.193 [#2973](https://github.com/storybookjs/storybook/pull/2973)\n- Upgraded `eslint-plugin-jest` in `/` from \"21.8.0\" to \"21.12.0\" [#2975](https://github.com/storybookjs/storybook/pull/2975)\n- Upgraded `ts-jest` in `/` from \"22.0.3\" to \"22.0.4\" [#2975](https://github.com/storybookjs/storybook/pull/2975)\n- Upgraded `react-datetime` in `addons/knobs` from \"2.13.0\" to \"2.14.0\" [#2975](https://github.com/storybookjs/storybook/pull/2975)\n- Upgraded `@storybook/addon-actions` in `/docs` from \"3.3.12\" to \"3.3.13\" [#2960](https://github.com/storybookjs/storybook/pull/2960)\n- Upgraded `@storybook/addon-links` in `/docs` from \"3.3.12\" to \"3.3.13\" [#2960](https://github.com/storybookjs/storybook/pull/2960)\n- Upgraded `@storybook/addons` in `/docs` from \"3.3.12\" to \"3.3.13\" [#2960](https://github.com/storybookjs/storybook/pull/2960)\n- Upgraded `@storybook/react` in `/docs` from \"3.3.12\" to \"3.3.13\" [#2960](https://github.com/storybookjs/storybook/pull/2960)\n- Upgraded `chalk` in `/` from \"2.3.0\" to \"2.3.1\" [#2961](https://github.com/storybookjs/storybook/pull/2961)\n- Upgraded `chalk` in `lib/node-logger` from \"2.3.0\" to \"2.3.1\" [#2961](https://github.com/storybookjs/storybook/pull/2961)\n- Upgraded `react-split-pane` in `lib/ui` from \"0.1.76\" to \"0.1.77\" [#2961](https://github.com/storybookjs/storybook/pull/2961)\n- Upgraded `chalk` in `lib/core` from \"2.3.0\" to \"2.3.1\" [#2961](https://github.com/storybookjs/storybook/pull/2961)\n- Upgraded `chalk` in `lib/cli` from \"2.3.0\" to \"2.3.1\" [#2961](https://github.com/storybookjs/storybook/pull/2961)\n\n</details>\n\n## 3.3.14\n\n2018-February-21\n\n#### Bug Fixes\n\n- RN: Add error handler on WS to fix crashing on page reload [#3002](https://github.com/storybookjs/storybook/pull/3002)\n- Added safety net preventing storybook Jest addon from throwing. [#3023](https://github.com/storybookjs/storybook/pull/3023)\n- Added \"key\" prop to list items inside test failure message. [#2867](https://github.com/storybookjs/storybook/pull/2867)\n- Addon-info: Add type check to PropType on OneOf [#2653](https://github.com/storybookjs/storybook/pull/2653)\n- Use @storybook/podda to fix npm engine version in podda [#3033](https://github.com/storybookjs/storybook/pull/3033)\n- Addon-backgrounds: set background on iframe instead of adding a wrapper in preview [#2807](https://github.com/storybookjs/storybook/pull/3033)\n\n## 3.4.0-alpha.8\n\n2018-February-11\n\n#### Bug Fixes\n\n- React-Native: Fix by moving managerPath export to `server.js` [#2947](https://github.com/storybookjs/storybook/pull/2947)\n- Addon-Info: Add type check to PropType on OneOf [#2653](https://github.com/storybookjs/storybook/pull/2653)\n- Vue: Support .vue extension resolving [#2896](https://github.com/storybookjs/storybook/pull/2896)\n\n#### Documentation\n\n- Update writing addons documentation [#2951](https://github.com/storybookjs/storybook/pull/2951)\n- Update docs on LinkTo in addon-links [#2926](https://github.com/storybookjs/storybook/pull/2926)\n\n#### Maintenance\n\n- Fix \"dev\" script to be cross-platform [#2922](https://github.com/storybookjs/storybook/pull/2922)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n98 Updates\n</summary>\n\n- Upgraded `jest-cli` in `/` from \"22.2.1\" to \"22.2.2\" [#2957](https://github.com/storybookjs/storybook/pull/2957)\n- Upgraded `jest-config` in `/` from \"22.2.1\" to \"22.2.2\" [#2957](https://github.com/storybookjs/storybook/pull/2957)\n- Upgraded `jest-environment-jsdom` in `/` from \"22.2.0\" to \"22.2.2\" [#2957](https://github.com/storybookjs/storybook/pull/2957)\n- Upgraded `jest-jasmine2` in `/` from \"22.2.1\" to \"22.2.2\" [#2957](https://github.com/storybookjs/storybook/pull/2957)\n- Upgraded `autoprefixer` in `lib/core` from \"7.2.5\" to \"7.2.6\" [#2957](https://github.com/storybookjs/storybook/pull/2957)\n- Upgraded `webpack` in `lib/core` from \"3.10.0\" to \"3.11.0\" [#2957](https://github.com/storybookjs/storybook/pull/2957)\n- Upgraded `autoprefixer` in `app/angular` from \"7.2.5\" to \"7.2.6\" [#2957](https://github.com/storybookjs/storybook/pull/2957)\n- Upgraded `webpack` in `app/angular` from \"3.10.0\" to \"3.11.0\" [#2957](https://github.com/storybookjs/storybook/pull/2957)\n- Upgraded `autoprefixer` in `app/polymer` from \"7.2.5\" to \"7.2.6\" [#2957](https://github.com/storybookjs/storybook/pull/2957)\n- Upgraded `webpack` in `app/polymer` from \"3.10.0\" to \"3.11.0\" [#2957](https://github.com/storybookjs/storybook/pull/2957)\n- Upgraded `autoprefixer` in `app/react-native` from \"7.2.5\" to \"7.2.6\" [#2957](https://github.com/storybookjs/storybook/pull/2957)\n- Upgraded `webpack` in `app/react-native` from \"3.10.0\" to \"3.11.0\" [#2957](https://github.com/storybookjs/storybook/pull/2957)\n- Upgraded `autoprefixer` in `app/react` from \"7.2.5\" to \"7.2.6\" [#2957](https://github.com/storybookjs/storybook/pull/2957)\n- Upgraded `webpack` in `app/react` from \"3.10.0\" to \"3.11.0\" [#2957](https://github.com/storybookjs/storybook/pull/2957)\n- Upgraded `autoprefixer` in `app/vue` from \"7.2.5\" to \"7.2.6\" [#2957](https://github.com/storybookjs/storybook/pull/2957)\n- Upgraded `webpack` in `app/vue` from \"3.10.0\" to \"3.11.0\" [#2957](https://github.com/storybookjs/storybook/pull/2957)\n- Upgraded `webpack` in `examples/polymer-cli` from \"3.10.0\" to \"3.11.0\" [#2957](https://github.com/storybookjs/storybook/pull/2957)\n- Upgraded `@types/node` in `examples/angular-cli` from \"6.0.99\" to \"6.0.100\" [#2957](https://github.com/storybookjs/storybook/pull/2957)\n- Upgraded `webpack` in `examples/vue-kitchen-sink` from \"3.10.0\" to \"3.11.0\" [#2957](https://github.com/storybookjs/storybook/pull/2957)\n- Upgraded `eslint-plugin-jest` in `/` from \"21.7.0\" to \"21.8.0\" [#2952](https://github.com/storybookjs/storybook/pull/2952)\n- Upgraded `react-datetime` in `addons/knobs` from \"2.12.0\" to \"2.13.0\" [#2952](https://github.com/storybookjs/storybook/pull/2952)\n- Upgraded `react-modal` in `lib/ui` from \"3.1.12\" to \"3.1.13\" [#2952](https://github.com/storybookjs/storybook/pull/2952)\n- Upgraded `react-modal` in `app/angular` from \"3.1.12\" to \"3.1.13\" [#2952](https://github.com/storybookjs/storybook/pull/2952)\n- Upgraded `react-modal` in `app/polymer` from \"3.1.12\" to \"3.1.13\" [#2952](https://github.com/storybookjs/storybook/pull/2952)\n- Upgraded `babel-jest` in `examples/cra-kitchen-sink` from \"22.2.0\" to \"22.2.2\" [#2952](https://github.com/storybookjs/storybook/pull/2952)\n- Upgraded `jest` in `examples/cra-kitchen-sink` from \"22.2.1\" to \"22.2.2\" [#2952](https://github.com/storybookjs/storybook/pull/2952)\n- Upgraded `react-scripts` in `examples/cra-kitchen-sink` from \"1.1.0\" to \"1.1.1\" [#2952](https://github.com/storybookjs/storybook/pull/2952)\n- Update gatsby in /docs from 1.9.184 to 1.9.187 [#2950](https://github.com/storybookjs/storybook/pull/2950)\n- Upgraded `copy-webpack-plugin` in `app/polymer` from \"4.3.1\" to \"4.4.0\" [#2945](https://github.com/storybookjs/storybook/pull/2945)\n- Upgraded `copy-webpack-plugin` in `examples/polymer-cli` from \"4.3.1\" to \"4.4.0\" [#2945](https://github.com/storybookjs/storybook/pull/2945)\n- Upgraded `@angular/cli` in `examples/angular-cli` from \"1.6.7\" to \"1.6.8\" [#2945](https://github.com/storybookjs/storybook/pull/2945)\n- Upgraded `@types/node` in `examples/angular-cli` from \"6.0.97\" to \"6.0.99\" [#2945](https://github.com/storybookjs/storybook/pull/2945)\n- Upgraded `jasmine-core` in `examples/angular-cli` from \"2.99.0\" to \"2.99.1\" [#2945](https://github.com/storybookjs/storybook/pull/2945)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.42\" to \"1.5.43\" [#2944](https://github.com/storybookjs/storybook/pull/2944)\n- Upgraded `gatsby-transformer-remark` in `/docs` from \"1.7.30\" to \"1.7.31\" [#2944](https://github.com/storybookjs/storybook/pull/2944)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.41\" to \"1.5.42\" [#2939](https://github.com/storybookjs/storybook/pull/2939)\n- Upgraded `gatsby` in `/docs` from \"1.9.183\" to \"1.9.184\" [#2939](https://github.com/storybookjs/storybook/pull/2939)\n- Upgraded `@angular/common` in `/` from \"5.2.3\" to \"5.2.4\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `@angular/compiler` in `/` from \"5.2.3\" to \"5.2.4\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `@angular/core` in `/` from \"5.2.3\" to \"5.2.4\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `@angular/forms` in `/` from \"5.2.3\" to \"5.2.4\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `@angular/platform-browser` in `/` from \"5.2.3\" to \"5.2.4\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `@angular/platform-browser-dynamic` in `/` from \"5.2.3\" to \"5.2.4\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `commander` in `/` from \"2.14.0\" to \"2.14.1\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `jest` in `/` from \"22.1.4\" to \"22.2.0\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `jest-cli` in `/` from \"22.1.4\" to \"22.2.0\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `jest-config` in `/` from \"22.1.4\" to \"22.2.0\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `jest-environment-jsdom` in `/` from \"22.1.4\" to \"22.2.0\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `jest-jasmine2` in `/` from \"22.1.4\" to \"22.2.0\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `graphql` in `addons/graphql` from \"0.12.3\" to \"0.13.0\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `commander` in `lib/core` from \"2.14.0\" to \"2.14.1\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `commander` in `app/react-native` from \"2.14.0\" to \"2.14.1\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `commander` in `lib/cli` from \"2.14.0\" to \"2.14.1\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `@angular/animations` in `examples/angular-cli` from \"5.2.3\" to \"5.2.4\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `@angular/common` in `examples/angular-cli` from \"5.2.3\" to \"5.2.4\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `@angular/compiler` in `examples/angular-cli` from \"5.2.3\" to \"5.2.4\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `@angular/core` in `examples/angular-cli` from \"5.2.3\" to \"5.2.4\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `@angular/forms` in `examples/angular-cli` from \"5.2.3\" to \"5.2.4\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `@angular/http` in `examples/angular-cli` from \"5.2.3\" to \"5.2.4\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `@angular/platform-browser` in `examples/angular-cli` from \"5.2.3\" to \"5.2.4\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `@angular/platform-browser-dynamic` in `examples/angular-cli` from \"5.2.3\" to \"5.2.4\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `@angular/router` in `examples/angular-cli` from \"5.2.3\" to \"5.2.4\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `@angular/compiler-cli` in `examples/angular-cli` from \"5.2.3\" to \"5.2.4\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `@angular/language-service` in `examples/angular-cli` from \"5.2.3\" to \"5.2.4\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `babel-jest` in `examples/cra-kitchen-sink` from \"22.1.0\" to \"22.2.0\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `jest` in `examples/cra-kitchen-sink` from \"22.1.4\" to \"22.2.0\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Upgraded `eventemitter3` in `examples/official-storybook` from \"3.0.0\" to \"3.0.1\" [#2938](https://github.com/storybookjs/storybook/pull/2938)\n- Update @types/node in examples/angular-cli from 6.0.96 to 6.0.97 [#2932](https://github.com/storybookjs/storybook/pull/2932)\n- Update gatsby in /docs from 1.9.181 to 1.9.182 [#2929](https://github.com/storybookjs/storybook/pull/2929)\n- Update jasmine-core in examples/angular-cli from 2.9.1 to 2.99.0 [#2930](https://github.com/storybookjs/storybook/pull/2930)\n- Upgraded `commander` in `/` from \"2.13.0\" to \"2.14.0\" [#2928](https://github.com/storybookjs/storybook/pull/2928)\n- Upgraded `make-error` in `addons/actions` from \"1.3.2\" to \"1.3.3\" [#2928](https://github.com/storybookjs/storybook/pull/2928)\n- Upgraded `commander` in `app/angular` from \"2.13.0\" to \"2.14.0\" [#2928](https://github.com/storybookjs/storybook/pull/2928)\n- Upgraded `commander` in `app/polymer` from \"2.13.0\" to \"2.14.0\" [#2928](https://github.com/storybookjs/storybook/pull/2928)\n- Upgraded `commander` in `app/react-native` from \"2.13.0\" to \"2.14.0\" [#2928](https://github.com/storybookjs/storybook/pull/2928)\n- Upgraded `react-native` in `app/react-native` from \"0.52.2\" to \"0.53.0\" [#2928](https://github.com/storybookjs/storybook/pull/2928)\n- Upgraded `commander` in `app/react` from \"2.13.0\" to \"2.14.0\" [#2928](https://github.com/storybookjs/storybook/pull/2928)\n- Upgraded `commander` in `app/vue` from \"2.13.0\" to \"2.14.0\" [#2928](https://github.com/storybookjs/storybook/pull/2928)\n- Upgraded `commander` in `lib/cli` from \"2.13.0\" to \"2.14.0\" [#2928](https://github.com/storybookjs/storybook/pull/2928)\n- Upgraded `jest-enzyme` in `/` from \"4.1.1\" to \"4.2.0\" [#2919](https://github.com/storybookjs/storybook/pull/2919)\n- Upgraded `react-modal` in `lib/ui` from \"3.1.11\" to \"3.1.12\" [#2919](https://github.com/storybookjs/storybook/pull/2919)\n- Upgraded `react-modal` in `app/angular` from \"3.1.11\" to \"3.1.12\" [#2919](https://github.com/storybookjs/storybook/pull/2919)\n- Upgraded `react-modal` in `app/polymer` from \"3.1.11\" to \"3.1.12\" [#2919](https://github.com/storybookjs/storybook/pull/2919)\n- Upgraded `gatsby-remark-copy-linked-files` in `/docs` from \"1.5.25\" to \"1.5.26\" [#2927](https://github.com/storybookjs/storybook/pull/2927)\n- Upgraded `gatsby-source-filesystem` in `/docs` from \"1.5.16\" to \"1.5.18\" [#2927](https://github.com/storybookjs/storybook/pull/2927)\n- Upgraded `gatsby` in `/docs` from \"1.9.178\" to \"1.9.179\" [#2927](https://github.com/storybookjs/storybook/pull/2927)\n- Update lodash in /docs from 4.17.4 to 4.17.5 [#2914](https://github.com/storybookjs/storybook/pull/2914)\n- Update lodash in / from 4.17.4 to 4.17.5 [#2915](https://github.com/storybookjs/storybook/pull/2915)\n- Upgraded `gatsby-link` in `/docs` from \"1.6.35\" to \"1.6.36\" [#2908](https://github.com/storybookjs/storybook/pull/2908)\n- Upgraded `gatsby` in `/docs` from \"1.9.175\" to \"1.9.177\" [#2908](https://github.com/storybookjs/storybook/pull/2908)\n- Upgraded `@storybook/addon-actions` in `/docs` from \"3.3.11\" to \"3.3.12\" [#2911](https://github.com/storybookjs/storybook/pull/2911)\n- Upgraded `@storybook/addon-links` in `/docs` from \"3.3.11\" to \"3.3.12\" [#2911](https://github.com/storybookjs/storybook/pull/2911)\n- Upgraded `@storybook/addons` in `/docs` from \"3.3.11\" to \"3.3.12\" [#2911](https://github.com/storybookjs/storybook/pull/2911)\n- Upgraded `@storybook/react` in `/docs` from \"3.3.11\" to \"3.3.12\" [#2911](https://github.com/storybookjs/storybook/pull/2911)\n- Upgraded `gatsby` in `/docs` from \"1.9.175\" to \"1.9.178\" [#2911](https://github.com/storybookjs/storybook/pull/2911)\n- Upgraded `eslint` in `/` from \"4.16.0\" to \"4.17.0\" [#2912](https://github.com/storybookjs/storybook/pull/2912)\n- Upgraded `ts-jest` in `/` from \"22.0.1\" to \"22.0.3\" [#2912](https://github.com/storybookjs/storybook/pull/2912)\n- Upgraded `@polymer/polymer` in `examples/polymer-cli` from \"2.4.0\" to \"2.5.0\" [#2912](https://github.com/storybookjs/storybook/pull/2912)\n\n</details>\n\n## 3.3.13\n\n2018-February-11\n\n#### Bug Fixes\n\n- Angular: add rule for .md to webpack.config.prod.js [#2924](https://github.com/storybookjs/storybook/pull/2924)\n- Check for correct props in Flow or prop-types [#2902](https://github.com/storybookjs/storybook/pull/2902)\n\n## 3.4.0-alpha.7\n\n2018-February-03\n\n#### Features\n\n- Storyshots: env.NODE_PATH support [#2873](https://github.com/storybookjs/storybook/pull/2873)\n- Knobs: Select knob key/value ordering [#1745](https://github.com/storybookjs/storybook/pull/1745)\n- Angular: Add option to pass custom styles for ng components [#2856](https://github.com/storybookjs/storybook/pull/2856)\n- Core: Add watch mode for build-storybook [#2866](https://github.com/storybookjs/storybook/pull/2866)\n- Core: Add `__dirname` support [#2791](https://github.com/storybookjs/storybook/pull/2791)\n\n#### Bug Fixes\n\n- UI: remove zero on story loading [#2857](https://github.com/storybookjs/storybook/pull/2857)\n\n#### Documentation\n\n- StoryShots: Document ref mocking [#2869](https://github.com/storybookjs/storybook/pull/2869)\n\n#### Maintenance\n\n- Typescript distribution [#2846](https://github.com/storybookjs/storybook/pull/2846)\n- Use UTC timezone in formatting too for knobs test [#2861](https://github.com/storybookjs/storybook/pull/2861)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n76 Upgrades\n</summary>\n\n- Upgraded `eslint-plugin-prettier` in `/` from \"2.5.0\" to \"2.6.0\" [#2910](https://github.com/storybookjs/storybook/pull/2910)\n- Upgraded `nodemon` in `/` from \"1.14.11\" to \"1.14.12\" [#2910](https://github.com/storybookjs/storybook/pull/2910)\n- Upgraded `postcss-loader` in `lib/core` from \"2.0.10\" to \"2.1.0\" [#2910](https://github.com/storybookjs/storybook/pull/2910)\n- Upgraded `postcss-loader` in `app/angular` from \"2.0.10\" to \"2.1.0\" [#2910](https://github.com/storybookjs/storybook/pull/2910)\n- Upgraded `nodemon` in `app/angular` from \"1.14.11\" to \"1.14.12\" [#2910](https://github.com/storybookjs/storybook/pull/2910)\n- Upgraded `postcss-loader` in `app/polymer` from \"2.0.10\" to \"2.1.0\" [#2910](https://github.com/storybookjs/storybook/pull/2910)\n- Upgraded `nodemon` in `app/polymer` from \"1.14.11\" to \"1.14.12\" [#2910](https://github.com/storybookjs/storybook/pull/2910)\n- Upgraded `postcss-loader` in `app/react-native` from \"2.0.10\" to \"2.1.0\" [#2910](https://github.com/storybookjs/storybook/pull/2910)\n- Upgraded `postcss-loader` in `app/react` from \"2.0.10\" to \"2.1.0\" [#2910](https://github.com/storybookjs/storybook/pull/2910)\n- Upgraded `nodemon` in `app/react` from \"1.14.11\" to \"1.14.12\" [#2910](https://github.com/storybookjs/storybook/pull/2910)\n- Upgraded `postcss-loader` in `app/vue` from \"2.0.10\" to \"2.1.0\" [#2910](https://github.com/storybookjs/storybook/pull/2910)\n- Upgraded `nodemon` in `app/vue` from \"1.14.11\" to \"1.14.12\" [#2910](https://github.com/storybookjs/storybook/pull/2910)\n- Upgraded `@angular/common` in `/` from \"5.2.2\" to \"5.2.3\" [#2901](https://github.com/storybookjs/storybook/pull/2901)\n- Upgraded `@angular/compiler` in `/` from \"5.2.2\" to \"5.2.3\" [#2901](https://github.com/storybookjs/storybook/pull/2901)\n- Upgraded `@angular/core` in `/` from \"5.2.2\" to \"5.2.3\" [#2901](https://github.com/storybookjs/storybook/pull/2901)\n- Upgraded `@angular/forms` in `/` from \"5.2.2\" to \"5.2.3\" [#2901](https://github.com/storybookjs/storybook/pull/2901)\n- Upgraded `@angular/platform-browser` in `/` from \"5.2.2\" to \"5.2.3\" [#2901](https://github.com/storybookjs/storybook/pull/2901)\n- Upgraded `@angular/platform-browser-dynamic` in `/` from \"5.2.2\" to \"5.2.3\" [#2901](https://github.com/storybookjs/storybook/pull/2901)\n- Upgraded `tslint-config-prettier` in `/` from \"1.6.0\" to \"1.7.0\" [#2901](https://github.com/storybookjs/storybook/pull/2901)\n- Upgraded `react-split-pane` in `lib/ui` from \"0.1.74\" to \"0.1.75\" [#2901](https://github.com/storybookjs/storybook/pull/2901)\n- Upgraded `@angular/animations` in `examples/angular-cli` from \"5.2.2\" to \"5.2.3\" [#2901](https://github.com/storybookjs/storybook/pull/2901)\n- Upgraded `@angular/common` in `examples/angular-cli` from \"5.2.2\" to \"5.2.3\" [#2901](https://github.com/storybookjs/storybook/pull/2901)\n- Upgraded `@angular/compiler` in `examples/angular-cli` from \"5.2.2\" to \"5.2.3\" [#2901](https://github.com/storybookjs/storybook/pull/2901)\n- Upgraded `@angular/core` in `examples/angular-cli` from \"5.2.2\" to \"5.2.3\" [#2901](https://github.com/storybookjs/storybook/pull/2901)\n- Upgraded `@angular/forms` in `examples/angular-cli` from \"5.2.2\" to \"5.2.3\" [#2901](https://github.com/storybookjs/storybook/pull/2901)\n- Upgraded `@angular/http` in `examples/angular-cli` from \"5.2.2\" to \"5.2.3\" [#2901](https://github.com/storybookjs/storybook/pull/2901)\n- Upgraded `@angular/platform-browser` in `examples/angular-cli` from \"5.2.2\" to \"5.2.3\" [#2901](https://github.com/storybookjs/storybook/pull/2901)\n- Upgraded `@angular/platform-browser-dynamic` in `examples/angular-cli` from \"5.2.2\" to \"5.2.3\" [#2901](https://github.com/storybookjs/storybook/pull/2901)\n- Upgraded `@angular/router` in `examples/angular-cli` from \"5.2.2\" to \"5.2.3\" [#2901](https://github.com/storybookjs/storybook/pull/2901)\n- Upgraded `@angular/cli` in `examples/angular-cli` from \"1.6.6\" to \"1.6.7\" [#2901](https://github.com/storybookjs/storybook/pull/2901)\n- Upgraded `@angular/compiler-cli` in `examples/angular-cli` from \"5.2.2\" to \"5.2.3\" [#2901](https://github.com/storybookjs/storybook/pull/2901)\n- Upgraded `@angular/language-service` in `examples/angular-cli` from \"5.2.2\" to \"5.2.3\" [#2901](https://github.com/storybookjs/storybook/pull/2901)\n- Upgraded `babel-plugin-macros` in `/` from \"2.0.0\" to \"2.1.0\" [#2891](https://github.com/storybookjs/storybook/pull/2891)\n- Upgraded `babel-plugin-macros` in `app/angular` from \"2.0.0\" to \"2.1.0\" [#2891](https://github.com/storybookjs/storybook/pull/2891)\n- Upgraded `typescript` in `app/angular` from \"2.6.2\" to \"2.7.1\" [#2891](https://github.com/storybookjs/storybook/pull/2891)\n- Upgraded `babel-plugin-macros` in `app/polymer` from \"2.0.0\" to \"2.1.0\" [#2891](https://github.com/storybookjs/storybook/pull/2891)\n- Upgraded `babel-preset-minify` in `app/polymer` from \"0.2.0\" to \"0.3.0\" [#2891](https://github.com/storybookjs/storybook/pull/2891)\n- Upgraded `babel-plugin-macros` in `app/react-native` from \"2.0.0\" to \"2.1.0\" [#2891](https://github.com/storybookjs/storybook/pull/2891)\n- Upgraded `babel-preset-minify` in `app/react-native` from \"0.2.0\" to \"0.3.0\" [#2891](https://github.com/storybookjs/storybook/pull/2891)\n- Upgraded `babel-plugin-macros` in `app/react` from \"2.0.0\" to \"2.1.0\" [#2891](https://github.com/storybookjs/storybook/pull/2891)\n- Upgraded `babel-preset-minify` in `app/react` from \"0.2.0\" to \"0.3.0\" [#2891](https://github.com/storybookjs/storybook/pull/2891)\n- Upgraded `babel-plugin-macros` in `app/vue` from \"2.0.0\" to \"2.1.0\" [#2891](https://github.com/storybookjs/storybook/pull/2891)\n- Upgraded `babel-preset-minify` in `app/vue` from \"0.2.0\" to \"0.3.0\" [#2891](https://github.com/storybookjs/storybook/pull/2891)\n- Upgraded `vue-style-loader` in `app/vue` from \"3.1.1\" to \"3.1.2\" [#2891](https://github.com/storybookjs/storybook/pull/2891)\n- Upgraded `vue-loader` in `app/vue` from \"13.7.0\" to \"13.7.1\" [#2891](https://github.com/storybookjs/storybook/pull/2891)\n- Upgraded `typescript` in `examples/angular-cli` from \"2.6.2\" to \"2.7.1\" [#2891](https://github.com/storybookjs/storybook/pull/2891)\n- Upgraded `vue-loader` in `examples/vue-kitchen-sink` from \"13.7.0\" to \"13.7.1\" [#2891](https://github.com/storybookjs/storybook/pull/2891)\n- Upgraded `vue-style-loader` in `examples/vue-kitchen-sink` from \"3.1.1\" to \"3.1.2\" [#2891](https://github.com/storybookjs/storybook/pull/2891)\n- Upgraded `gatsby-source-filesystem` in `/docs` from \"1.5.15\" to \"1.5.16\" [#2875](https://github.com/storybookjs/storybook/pull/2875)\n- Upgraded `gatsby` in `/docs` from \"1.9.172\" to \"1.9.174\" [#2875](https://github.com/storybookjs/storybook/pull/2875)\n- Upgraded `@types/lodash` in `/` from \"4.14.97\" to \"4.14.98\" [#2876](https://github.com/storybookjs/storybook/pull/2876)\n- Upgraded `jest-enzyme` in `/` from \"4.0.2\" to \"4.1.0\" [#2876](https://github.com/storybookjs/storybook/pull/2876)\n- Upgraded `uglifyjs-webpack-plugin` in `app/angular` from \"1.1.6\" to \"1.1.7\" [#2876](https://github.com/storybookjs/storybook/pull/2876)\n- Upgraded `uglifyjs-webpack-plugin` in `app/react-native` from \"1.1.6\" to \"1.1.7\" [#2876](https://github.com/storybookjs/storybook/pull/2876)\n- Upgraded `uglifyjs-webpack-plugin` in `app/react` from \"1.1.6\" to \"1.1.7\" [#2876](https://github.com/storybookjs/storybook/pull/2876)\n- Upgraded `uglifyjs-webpack-plugin` in `app/vue` from \"1.1.6\" to \"1.1.7\" [#2876](https://github.com/storybookjs/storybook/pull/2876)\n- Upgraded `gatsby-link` in `/docs` from \"1.6.34\" to \"1.6.35\" [#2858](https://github.com/storybookjs/storybook/pull/2858)\n- Upgraded `gatsby-transformer-remark` in `/docs` from \"1.7.29\" to \"1.7.30\" [#2858](https://github.com/storybookjs/storybook/pull/2858)\n- Upgraded `gatsby` in `/docs` from \"1.9.169\" to \"1.9.171\" [#2858](https://github.com/storybookjs/storybook/pull/2858)\n- Make dependencies in polymer & angular up to date with other apps [#2852](https://github.com/storybookjs/storybook/pull/2852)\n- Upgraded `@types/lodash` in `/` from \"4.14.96\" to \"4.14.97\" [#2850](https://github.com/storybookjs/storybook/pull/2850)\n- Upgraded `react-datetime` in `addons/knobs` from \"2.11.1\" to \"2.12.0\" [#2850](https://github.com/storybookjs/storybook/pull/2850)\n- Upgraded `style-loader` in `addons/knobs` from \"0.19.1\" to \"0.20.1\" [#2850](https://github.com/storybookjs/storybook/pull/2850)\n- Upgraded `style-loader` in `lib/core` from \"0.19.1\" to \"0.20.1\" [#2850](https://github.com/storybookjs/storybook/pull/2850)\n- Upgraded `style-loader` in `app/angular` from \"0.18.2\" to \"0.20.1\" [#2850](https://github.com/storybookjs/storybook/pull/2850)\n- Upgraded `style-loader` in `app/polymer` from \"0.18.2\" to \"0.20.1\" [#2850](https://github.com/storybookjs/storybook/pull/2850)\n- Upgraded `style-loader` in `app/react-native` from \"0.19.1\" to \"0.20.1\" [#2850](https://github.com/storybookjs/storybook/pull/2850)\n- Upgraded `style-loader` in `app/react` from \"0.19.1\" to \"0.20.1\" [#2850](https://github.com/storybookjs/storybook/pull/2850)\n- Upgraded `style-loader` in `app/vue` from \"0.19.1\" to \"0.20.1\" [#2850](https://github.com/storybookjs/storybook/pull/2850)\n- Upgraded `@polymer/polymer` in `examples/polymer-cli` from \"2.3.1\" to \"2.4.0\" [#2850](https://github.com/storybookjs/storybook/pull/2850)\n- Upgraded `@types/jasmine` in `examples/angular-cli` from \"2.8.5\" to \"2.8.6\" [#2850](https://github.com/storybookjs/storybook/pull/2850)\n- Upgraded `@storybook/addon-actions` in `/docs` from \"3.3.10\" to \"3.3.11\" [#2849](https://github.com/storybookjs/storybook/pull/2849)\n- Upgraded `@storybook/addon-links` in `/docs` from \"3.3.10\" to \"3.3.11\" [#2849](https://github.com/storybookjs/storybook/pull/2849)\n- Upgraded `@storybook/addons` in `/docs` from \"3.3.10\" to \"3.3.11\" [#2849](https://github.com/storybookjs/storybook/pull/2849)\n- Upgraded `@storybook/react` in `/docs` from \"3.3.10\" to \"3.3.11\" [#2849](https://github.com/storybookjs/storybook/pull/2849)\n- Update url-loader from 0.5.8 to 0.6.2 in app/angular [#2847](https://github.com/storybookjs/storybook/pull/2847)\n\n</details>\n\n## 3.3.12\n\n2018-February-02\n\n#### Bug Fixes\n\n- Fix browser navigation again [#2870](https://github.com/storybookjs/storybook/pull/2870)\n\n#### Dependency Upgrades\n\n- Update url-loader from 0.5.8 to 0.6.2 in app/angular [#2847](https://github.com/storybookjs/storybook/pull/2847)\n\n## 3.4.0-alpha.6\n\n2018-January-27\n\n#### Features\n\n- Pass default webpack config as third argument in Full Control Mode [#2796](https://github.com/storybookjs/storybook/pull/2796)\n\n#### Bug Fixes\n\n- Angular: remove entryComponents prop from metadata [#2790](https://github.com/storybookjs/storybook/pull/2790)\n- Use process.exitCode instead of process.exit() [#2717](https://github.com/storybookjs/storybook/pull/2717)\n\n#### Documentation\n\n- Extending webpack section is no longer needed for the common usage [#2826](https://github.com/storybookjs/storybook/pull/2826)\n- Updating Vue Jest Config [#2821](https://github.com/storybookjs/storybook/pull/2821)\n- Angular inheritance example [#2787](https://github.com/storybookjs/storybook/pull/2787)\n\n#### Maintenance\n\n- ADD autolabeler.yml for <https://github.com/probot/autolabeler> [#2809](https://github.com/storybookjs/storybook/pull/2809)\n- Fix css warning in angular-cli example [#2789](https://github.com/storybookjs/storybook/pull/2789)\n- Move more things to core [#2788](https://github.com/storybookjs/storybook/pull/2788)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n76 Upgrades\n</summary>\n\n- Upgraded `eslint-plugin-react` in `/` from \"7.5.1\" to \"7.6.0\" [#2844](https://github.com/storybookjs/storybook/pull/2844)\n- Upgraded `lint-staged` in `/` from \"6.0.1\" to \"6.1.0\" [#2844](https://github.com/storybookjs/storybook/pull/2844)\n- Upgraded `react-native` in `app/react-native` from \"0.52.1\" to \"0.52.2\" [#2844](https://github.com/storybookjs/storybook/pull/2844)\n- Upgraded `@angular/cli` in `examples/angular-cli` from \"1.6.5\" to \"1.6.6\" [#2844](https://github.com/storybookjs/storybook/pull/2844)\n- Upgraded `protractor` in `examples/angular-cli` from \"5.2.2\" to \"5.3.0\" [#2844](https://github.com/storybookjs/storybook/pull/2844)\n- Upgraded `gatsby-plugin-sharp` in `/docs` from \"1.6.26\" to \"1.6.27\" [#2843](https://github.com/storybookjs/storybook/pull/2843)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.40\" to \"1.5.41\" [#2843](https://github.com/storybookjs/storybook/pull/2843)\n- Upgraded `gatsby-source-filesystem` in `/docs` from \"1.5.14\" to \"1.5.15\" [#2843](https://github.com/storybookjs/storybook/pull/2843)\n- Upgraded `gatsby` in `/docs` from \"1.9.166\" to \"1.9.169\" [#2843](https://github.com/storybookjs/storybook/pull/2843)\n- Upgraded `@types/lodash` in `/` from \"4.14.95\" to \"4.14.96\" [#2840](https://github.com/storybookjs/storybook/pull/2840)\n- Upgraded `airbnb-js-shims` in `app/angular` from \"1.4.0\" to \"1.4.1\" [#2840](https://github.com/storybookjs/storybook/pull/2840)\n- Upgraded `airbnb-js-shims` in `app/polymer` from \"1.4.0\" to \"1.4.1\" [#2840](https://github.com/storybookjs/storybook/pull/2840)\n- Upgraded `airbnb-js-shims` in `app/react` from \"1.4.0\" to \"1.4.1\" [#2840](https://github.com/storybookjs/storybook/pull/2840)\n- Upgraded `airbnb-js-shims` in `app/vue` from \"1.4.0\" to \"1.4.1\" [#2840](https://github.com/storybookjs/storybook/pull/2840)\n- Upgraded `@angular/animations` in `examples/angular-cli` from \"5.2.1\" to \"5.2.2\" [#2840](https://github.com/storybookjs/storybook/pull/2840)\n- Upgraded `@angular/common` in `examples/angular-cli` from \"5.2.1\" to \"5.2.2\" [#2840](https://github.com/storybookjs/storybook/pull/2840)\n- Upgraded `@angular/compiler` in `examples/angular-cli` from \"5.2.1\" to \"5.2.2\" [#2840](https://github.com/storybookjs/storybook/pull/2840)\n- Upgraded `@angular/core` in `examples/angular-cli` from \"5.2.1\" to \"5.2.2\" [#2840](https://github.com/storybookjs/storybook/pull/2840)\n- Upgraded `@angular/forms` in `examples/angular-cli` from \"5.2.1\" to \"5.2.2\" [#2840](https://github.com/storybookjs/storybook/pull/2840)\n- Upgraded `@angular/http` in `examples/angular-cli` from \"5.2.1\" to \"5.2.2\" [#2840](https://github.com/storybookjs/storybook/pull/2840)\n- Upgraded `@angular/platform-browser` in `examples/angular-cli` from \"5.2.1\" to \"5.2.2\" [#2840](https://github.com/storybookjs/storybook/pull/2840)\n- Upgraded `@angular/platform-browser-dynamic` in `examples/angular-cli` from \"5.2.1\" to \"5.2.2\" [#2840](https://github.com/storybookjs/storybook/pull/2840)\n- Upgraded `@angular/router` in `examples/angular-cli` from \"5.2.1\" to \"5.2.2\" [#2840](https://github.com/storybookjs/storybook/pull/2840)\n- Upgraded `@angular/compiler-cli` in `examples/angular-cli` from \"5.2.1\" to \"5.2.2\" [#2840](https://github.com/storybookjs/storybook/pull/2840)\n- Upgraded `@angular/language-service` in `examples/angular-cli` from \"5.2.1\" to \"5.2.2\" [#2840](https://github.com/storybookjs/storybook/pull/2840)\n- Upgraded `gatsby-plugin-sharp` in `/docs` from \"1.6.25\" to \"1.6.26\" [#2828](https://github.com/storybookjs/storybook/pull/2828)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.39\" to \"1.5.40\" [#2828](https://github.com/storybookjs/storybook/pull/2828)\n- Upgraded `gatsby` in `/docs` from \"1.9.165\" to \"1.9.166\" [#2828](https://github.com/storybookjs/storybook/pull/2828)\n- Upgraded `@types/lodash` in `/` from \"4.14.93\" to \"4.14.95\" [#2829](https://github.com/storybookjs/storybook/pull/2829)\n- Upgraded `vue-style-loader` in `app/vue` from \"3.0.3\" to \"3.1.1\" [#2829](https://github.com/storybookjs/storybook/pull/2829)\n- Upgraded `karma-coverage-istanbul-reporter` in `examples/angular-cli` from \"1.3.3\" to \"1.4.1\" [#2829](https://github.com/storybookjs/storybook/pull/2829)\n- Upgraded `vue-style-loader` in `examples/vue-kitchen-sink` from \"3.0.3\" to \"3.1.1\" [#2829](https://github.com/storybookjs/storybook/pull/2829)\n- Upgraded `@webcomponents/webcomponentsjs` in `app/polymer` from \"1.0.22\" to \"1.1.0\" [#2818](https://github.com/storybookjs/storybook/pull/2818)\n- Upgraded `enzyme-to-json` in `addons/storyshots` from \"3.3.0\" to \"3.3.1\" [#2818](https://github.com/storybookjs/storybook/pull/2818)\n- Upgraded `@webcomponents/webcomponentsjs` in `examples/polymer-cli` from \"1.0.22\" to \"1.1.0\" [#2818](https://github.com/storybookjs/storybook/pull/2818)\n- Upgraded `@types/jasmine` in `examples/angular-cli` from \"2.8.4\" to \"2.8.5\" [#2818](https://github.com/storybookjs/storybook/pull/2818)\n- Upgraded `enzyme-to-json` in `examples/cra-kitchen-sink` from \"3.3.0\" to \"3.3.1\" [#2818](https://github.com/storybookjs/storybook/pull/2818)\n- Upgraded `enzyme-to-json` in `examples/official-storybook` from \"3.3.0\" to \"3.3.1\" [#2818](https://github.com/storybookjs/storybook/pull/2818)\n- Upgraded `react-chromatic` in `examples/official-storybook` from \"0.7.8\" to \"0.7.9\" [#2818](https://github.com/storybookjs/storybook/pull/2818)\n- Upgraded `gatsby-transformer-remark` in `/docs` from \"1.7.28\" to \"1.7.29\" [#2816](https://github.com/storybookjs/storybook/pull/2816)\n- Upgraded `gatsby` in `/docs` from \"1.9.164\" to \"1.9.165\" [#2816](https://github.com/storybookjs/storybook/pull/2816)\n- Upgraded `eslint` in `/` from \"4.15.0\" to \"4.16.0\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `github-release-from-changelog` in `/` from \"1.3.0\" to \"1.3.1\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `jest` in `/` from \"22.1.3\" to \"22.1.4\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `jest-cli` in `/` from \"22.1.3\" to \"22.1.4\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `jest-config` in `/` from \"22.1.3\" to \"22.1.4\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `jest-environment-jsdom` in `/` from \"22.1.2\" to \"22.1.4\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `jest-jasmine2` in `/` from \"22.1.3\" to \"22.1.4\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `lerna` in `/` from \"2.6.0\" to \"2.8.0\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `lint-staged` in `/` from \"6.0.0\" to \"6.0.1\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `shelljs` in `/` from \"0.8.0\" to \"0.8.1\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `shelljs` in `addons/links` from \"0.8.0\" to \"0.8.1\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `glamorous` in `lib/components` from \"4.11.3\" to \"4.11.4\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `glamorous` in `addons/a11y` from \"4.11.3\" to \"4.11.4\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `glamorous` in `addons/info` from \"4.11.3\" to \"4.11.4\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `glamorous` in `addons/jest` from \"4.11.3\" to \"4.11.4\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `shelljs` in `app/angular` from \"0.8.0\" to \"0.8.1\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `shelljs` in `app/polymer` from \"0.7.8\" to \"0.8.1\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `shelljs` in `app/react-native` from \"0.8.0\" to \"0.8.1\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `react-native` in `app/react-native` from \"0.52.0\" to \"0.52.1\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `glamorous` in `app/react` from \"4.11.3\" to \"4.11.4\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `shelljs` in `app/react` from \"0.8.0\" to \"0.8.1\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `shelljs` in `app/vue` from \"0.8.0\" to \"0.8.1\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `webpack-dev-server` in `examples/polymer-cli` from \"2.11.0\" to \"2.11.1\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `shelljs` in `lib/cli` from \"0.8.0\" to \"0.8.1\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `jasmine-core` in `examples/angular-cli` from \"2.9.0\" to \"2.9.1\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `glamorous` in `examples/cra-kitchen-sink` from \"4.11.3\" to \"4.11.4\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `jest` in `examples/cra-kitchen-sink` from \"22.1.3\" to \"22.1.4\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `webpack-dev-server` in `examples/vue-kitchen-sink` from \"2.11.0\" to \"2.11.1\" [#2806](https://github.com/storybookjs/storybook/pull/2806)\n- Upgraded `@storybook/addon-actions` in `/docs` from \"3.3.9\" to \"3.3.10\" [#2799](https://github.com/storybookjs/storybook/pull/2799)\n- Upgraded `@storybook/addon-links` in `/docs` from \"3.3.9\" to \"3.3.10\" [#2799](https://github.com/storybookjs/storybook/pull/2799)\n- Upgraded `@storybook/addons` in `/docs` from \"3.3.9\" to \"3.3.10\" [#2799](https://github.com/storybookjs/storybook/pull/2799)\n- Upgraded `@storybook/react` in `/docs` from \"3.3.9\" to \"3.3.10\" [#2799](https://github.com/storybookjs/storybook/pull/2799)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.37\" to \"1.5.39\" [#2799](https://github.com/storybookjs/storybook/pull/2799)\n- Upgraded `gatsby-source-filesystem` in `/docs` from \"1.5.11\" to \"1.5.14\" [#2799](https://github.com/storybookjs/storybook/pull/2799)\n- Upgraded `gatsby` in `/docs` from \"1.9.158\" to \"1.9.164\" [#2799](https://github.com/storybookjs/storybook/pull/2799)\n\n</details>\n\n## 3.3.11\n\n2018-January-26\n\n#### Bug Fixes\n\n- Angular: update helpers.ts [#2777](https://github.com/storybookjs/storybook/pull/2777)\n\n## 3.4.0-alpha.5\n\n2018-January-19\n\n#### Features\n\n- Angular and Vue storyshots [#2564](https://github.com/storybookjs/storybook/pull/2564)\n- Addon-info: Added \"Copy button\" for code example [#2713](https://github.com/storybookjs/storybook/pull/2713)\n- Angular: Serve styles and assets using .angular-cli webpack configuration [#2735](https://github.com/storybookjs/storybook/pull/2735)\n- API: Added an event that is emitted when a channel is created. [#2711](https://github.com/storybookjs/storybook/pull/2711)\n- Addon-a11y: Handle components with delayed rendering [#2651](https://github.com/storybookjs/storybook/pull/2651)\n\n#### Bug Fixes\n\n- Angular: knobs with template [#2766](https://github.com/storybookjs/storybook/pull/2766)\n\n#### Documentation\n\n<details>\n<summary>\n4 PRs\n</summary>\n\n- Updating css-style testing docs to mention StoryShots image snapshots feature [#2767](https://github.com/storybookjs/storybook/pull/2767)\n- Fix introduction page header [#2757](https://github.com/storybookjs/storybook/pull/2757)\n- fix Storyshots README, add missing export for image snapshots [#2759](https://github.com/storybookjs/storybook/pull/2759)\n- Update MIGRATION.md [#2709](https://github.com/storybookjs/storybook/pull/2709)\n\n</details>\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n91 upgrades\n</summary>\n\n- Upgraded `@types/lodash` in `/` from \"4.14.92\" to \"4.14.93\" [#2783](https://github.com/storybookjs/storybook/pull/2783)\n- Upgraded `jest` in `/` from \"22.1.2\" to \"22.1.3\" [#2783](https://github.com/storybookjs/storybook/pull/2783)\n- Upgraded `jest-cli` in `/` from \"22.1.2\" to \"22.1.3\" [#2783](https://github.com/storybookjs/storybook/pull/2783)\n- Upgraded `jest-config` in `/` from \"22.1.2\" to \"22.1.3\" [#2783](https://github.com/storybookjs/storybook/pull/2783)\n- Upgraded `jest-jasmine2` in `/` from \"22.1.2\" to \"22.1.3\" [#2783](https://github.com/storybookjs/storybook/pull/2783)\n- Upgraded `postcss-flexbugs-fixes` in `app/angular` from \"3.2.0\" to \"3.3.0\" [#2783](https://github.com/storybookjs/storybook/pull/2783)\n- Upgraded `postcss-flexbugs-fixes` in `app/polymer` from \"3.2.0\" to \"3.3.0\" [#2783](https://github.com/storybookjs/storybook/pull/2783)\n- Upgraded `postcss-flexbugs-fixes` in `app/react` from \"3.2.0\" to \"3.3.0\" [#2783](https://github.com/storybookjs/storybook/pull/2783)\n- Upgraded `postcss-flexbugs-fixes` in `app/vue` from \"3.2.0\" to \"3.3.0\" [#2783](https://github.com/storybookjs/storybook/pull/2783)\n- Upgraded `@angular/cli` in `examples/angular-cli` from \"1.6.4\" to \"1.6.5\" [#2783](https://github.com/storybookjs/storybook/pull/2783)\n- Upgraded `jest` in `examples/cra-kitchen-sink` from \"22.1.2\" to \"22.1.3\" [#2783](https://github.com/storybookjs/storybook/pull/2783)\n- Update gatsby in /docs from 1.9.157 to 1.9.158 [#2779](https://github.com/storybookjs/storybook/pull/2779)\n- Upgraded `jasmine-core` in `examples/angular-cli` from \"2.8.0\" to \"2.9.0\" [#2780](https://github.com/storybookjs/storybook/pull/2780)\n- Upgraded `react-chromatic` in `examples/official-storybook` from \"0.7.7\" to \"0.7.8\" [#2780](https://github.com/storybookjs/storybook/pull/2780)\n- Upgraded `eslint-plugin-jest` in `/` from \"21.6.2\" to \"21.7.0\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `jest` in `/` from \"22.1.1\" to \"22.1.2\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `jest-cli` in `/` from \"22.1.1\" to \"22.1.2\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `jest-config` in `/` from \"22.1.1\" to \"22.1.2\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `jest-environment-jsdom` in `/` from \"22.1.0\" to \"22.1.2\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `jest-jasmine2` in `/` from \"22.1.1\" to \"22.1.2\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `uuid` in `addons/actions` from \"3.2.0\" to \"3.2.1\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `uuid` in `addons/events` from \"3.2.0\" to \"3.2.1\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `glamorous` in `lib/components` from \"4.11.2\" to \"4.11.3\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `glamorous` in `addons/a11y` from \"4.11.2\" to \"4.11.3\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `glamorous` in `addons/info` from \"4.11.2\" to \"4.11.3\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `glamorous` in `addons/jest` from \"4.11.2\" to \"4.11.3\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `css-loader` in `app/angular` from \"0.28.8\" to \"0.28.9\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `html-loader` in `app/angular` from \"0.5.4\" to \"0.5.5\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `uuid` in `app/angular` from \"3.2.0\" to \"3.2.1\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `css-loader` in `app/polymer` from \"0.28.8\" to \"0.28.9\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `uuid` in `app/polymer` from \"3.2.0\" to \"3.2.1\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `css-loader` in `app/react-native` from \"0.28.8\" to \"0.28.9\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `uuid` in `app/react-native` from \"3.2.0\" to \"3.2.1\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `css-loader` in `app/react` from \"0.28.8\" to \"0.28.9\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `glamorous` in `app/react` from \"4.11.2\" to \"4.11.3\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `html-loader` in `app/react` from \"0.5.4\" to \"0.5.5\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `uuid` in `app/react` from \"3.2.0\" to \"3.2.1\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `css-loader` in `app/vue` from \"0.28.8\" to \"0.28.9\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `html-loader` in `app/vue` from \"0.5.4\" to \"0.5.5\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `uuid` in `app/vue` from \"3.2.0\" to \"3.2.1\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `semver` in `lib/cli` from \"5.4.1\" to \"5.5.0\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `@angular/animations` in `examples/angular-cli` from \"5.2.0\" to \"5.2.1\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `@angular/common` in `examples/angular-cli` from \"5.2.0\" to \"5.2.1\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `@angular/compiler` in `examples/angular-cli` from \"5.2.0\" to \"5.2.1\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `@angular/core` in `examples/angular-cli` from \"5.2.0\" to \"5.2.1\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `@angular/forms` in `examples/angular-cli` from \"5.2.0\" to \"5.2.1\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `@angular/http` in `examples/angular-cli` from \"5.2.0\" to \"5.2.1\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `@angular/platform-browser` in `examples/angular-cli` from \"5.2.0\" to \"5.2.1\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `@angular/platform-browser-dynamic` in `examples/angular-cli` from \"5.2.0\" to \"5.2.1\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `@angular/router` in `examples/angular-cli` from \"5.2.0\" to \"5.2.1\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `@angular/compiler-cli` in `examples/angular-cli` from \"5.2.0\" to \"5.2.1\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `@angular/language-service` in `examples/angular-cli` from \"5.2.0\" to \"5.2.1\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `glamorous` in `examples/cra-kitchen-sink` from \"4.11.2\" to \"4.11.3\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `jest` in `examples/cra-kitchen-sink` from \"22.1.1\" to \"22.1.2\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `css-loader` in `examples/vue-kitchen-sink` from \"0.28.8\" to \"0.28.9\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `uuid` in `examples/official-storybook` from \"3.2.0\" to \"3.2.1\" [#2770](https://github.com/storybookjs/storybook/pull/2770)\n- Upgraded `gatsby-plugin-sharp` in `/docs` from \"1.6.24\" to \"1.6.25\" [#2768](https://github.com/storybookjs/storybook/pull/2768)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.36\" to \"1.5.37\" [#2768](https://github.com/storybookjs/storybook/pull/2768)\n- Upgraded `eslint-plugin-prettier` in `/` from \"2.4.0\" to \"2.5.0\" [#2764](https://github.com/storybookjs/storybook/pull/2764)\n- Upgraded `lerna` in `/` from \"2.7.0\" to \"2.7.1\" [#2764](https://github.com/storybookjs/storybook/pull/2764)\n- Upgraded `uuid` in `addons/actions` from \"3.1.0\" to \"3.2.0\" [#2764](https://github.com/storybookjs/storybook/pull/2764)\n- Upgraded `uuid` in `addons/events` from \"3.1.0\" to \"3.2.0\" [#2764](https://github.com/storybookjs/storybook/pull/2764)\n- Upgraded `react-modal` in `lib/ui` from \"3.1.10\" to \"3.1.11\" [#2764](https://github.com/storybookjs/storybook/pull/2764)\n- Upgraded `uuid` in `app/angular` from \"3.1.0\" to \"3.2.0\" [#2764](https://github.com/storybookjs/storybook/pull/2764)\n- Upgraded `uuid` in `app/polymer` from \"3.1.0\" to \"3.2.0\" [#2764](https://github.com/storybookjs/storybook/pull/2764)\n- Upgraded `uuid` in `app/react-native` from \"3.1.0\" to \"3.2.0\" [#2764](https://github.com/storybookjs/storybook/pull/2764)\n- Upgraded `uuid` in `app/react` from \"3.1.0\" to \"3.2.0\" [#2764](https://github.com/storybookjs/storybook/pull/2764)\n- Upgraded `uuid` in `app/vue` from \"3.1.0\" to \"3.2.0\" [#2764](https://github.com/storybookjs/storybook/pull/2764)\n- Upgraded `uuid` in `examples/official-storybook` from \"3.1.0\" to \"3.2.0\" [#2764](https://github.com/storybookjs/storybook/pull/2764)\n- Update gatsby in /docs from 1.9.155 to 1.9.157 [#2763](https://github.com/storybookjs/storybook/pull/2763)\n- Upgraded `jest` in `/` from \"22.0.6\" to \"22.1.1\" [#2754](https://github.com/storybookjs/storybook/pull/2754)\n- Upgraded `jest-cli` in `/` from \"22.0.6\" to \"22.1.1\" [#2754](https://github.com/storybookjs/storybook/pull/2754)\n- Upgraded `jest-config` in `/` from \"22.0.6\" to \"22.1.1\" [#2754](https://github.com/storybookjs/storybook/pull/2754)\n- Upgraded `jest-diff` in `/` from \"22.0.6\" to \"22.1.0\" [#2754](https://github.com/storybookjs/storybook/pull/2754)\n- Upgraded `jest-environment-jsdom` in `/` from \"22.0.6\" to \"22.1.0\" [#2754](https://github.com/storybookjs/storybook/pull/2754)\n- Upgraded `jest-jasmine2` in `/` from \"22.0.6\" to \"22.1.1\" [#2754](https://github.com/storybookjs/storybook/pull/2754)\n- Upgraded `babel-plugin-react-docgen` in `app/angular` from \"1.8.1\" to \"1.8.2\" [#2754](https://github.com/storybookjs/storybook/pull/2754)\n- Upgraded `babel-preset-react-app` in `app/angular` from \"3.1.0\" to \"3.1.1\" [#2754](https://github.com/storybookjs/storybook/pull/2754)\n- Upgraded `babel-plugin-react-docgen` in `app/polymer` from \"1.8.1\" to \"1.8.2\" [#2754](https://github.com/storybookjs/storybook/pull/2754)\n- Upgraded `babel-preset-react-app` in `app/polymer` from \"3.1.0\" to \"3.1.1\" [#2754](https://github.com/storybookjs/storybook/pull/2754)\n- Upgraded `babel-plugin-react-docgen` in `app/react` from \"1.8.1\" to \"1.8.2\" [#2754](https://github.com/storybookjs/storybook/pull/2754)\n- Upgraded `babel-preset-react-app` in `app/react` from \"3.1.0\" to \"3.1.1\" [#2754](https://github.com/storybookjs/storybook/pull/2754)\n- Upgraded `babel-plugin-react-docgen` in `app/vue` from \"1.8.1\" to \"1.8.2\" [#2754](https://github.com/storybookjs/storybook/pull/2754)\n- Upgraded `babel-preset-react-app` in `app/vue` from \"3.1.0\" to \"3.1.1\" [#2754](https://github.com/storybookjs/storybook/pull/2754)\n- Upgraded `babel-jest` in `examples/cra-kitchen-sink` from \"22.0.6\" to \"22.1.0\" [#2754](https://github.com/storybookjs/storybook/pull/2754)\n- Upgraded `jest` in `examples/cra-kitchen-sink` from \"22.0.6\" to \"22.1.1\" [#2754](https://github.com/storybookjs/storybook/pull/2754)\n- Upgraded `react-scripts` in `examples/cra-kitchen-sink` from \"1.0.17\" to \"1.1.0\" [#2754](https://github.com/storybookjs/storybook/pull/2754)\n- Upgraded `eslint-plugin-jest` in `/` from \"21.6.1\" to \"21.6.2\" [#2746](https://github.com/storybookjs/storybook/pull/2746)\n- Upgraded `webpack-dev-server` in `examples/polymer-cli` from \"2.10.1\" to \"2.11.0\" [#2746](https://github.com/storybookjs/storybook/pull/2746)\n- Upgraded `webpack-dev-server` in `examples/vue-kitchen-sink` from \"2.10.1\" to \"2.11.0\" [#2746](https://github.com/storybookjs/storybook/pull/2746)\n- Upgraded `jest-image-snapshot` in `/` from \"2.2.1\" to \"2.3.0\" [#2740](https://github.com/storybookjs/storybook/pull/2740)\n- Upgraded `polymer-webpack-loader` in `app/polymer` from \"2.0.0\" to \"2.0.1\"\n\n</details>\n\n## 3.3.10\n\n2018-January-19\n\n#### Bug Fixes\n\n- Addon-backgrounds: remove redundant scrollbars [#2744](https://github.com/storybookjs/storybook/pull/2744)\n- Addon-info: add keys for separator spans in OneOfType [#2743](https://github.com/storybookjs/storybook/pull/2743)\n\n## 3.4.0-alpha.4\n\n2018-January-13\n\nRepublish `3.4.0-alpha.3` due to potential publishing errors\n\n## 3.4.0-alpha.3\n\n2018-January-13\n\n#### Features\n\n- Polymer 2 support [#2225](https://github.com/storybookjs/storybook/pull/2225)\n- Add image snapshots to addon-storyshots [#2413](https://github.com/storybookjs/storybook/pull/2413)\n- Angular template support for Storybook [#2690](https://github.com/storybookjs/storybook/pull/2690)\n\n#### Bug Fixes\n\n- Remove polymer-cli dependency [#2741](https://github.com/storybookjs/storybook/pull/2741)\n- Add scss for components in angular apps by default. [#2703](https://github.com/storybookjs/storybook/pull/2703)\n\n#### Maintenance\n\n- Change ng stories dir [#2672](https://github.com/storybookjs/storybook/pull/2672)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n54 Upgrades\n</summary>\n\n- Upgraded `jest-image-snapshot` in `/` from \"2.2.1\" to \"2.3.0\" [#2740](https://github.com/storybookjs/storybook/pull/2740)\n- Upgraded `polymer-webpack-loader` in `app/polymer` from \"2.0.0\" to \"2.0.1\" [#2740](https://github.com/storybookjs/storybook/pull/2740)\n- Upgraded `jest-image-snapshot` in `addons/storyshots` from \"2.2.1\" to \"2.3.0\" [#2740](https://github.com/storybookjs/storybook/pull/2740)\n- Upgraded `shelljs` in `/` from \"0.7.8\" to \"0.8.0\" [#2734](https://github.com/storybookjs/storybook/pull/2734)\n- Upgraded `shelljs` in `addons/links` from \"0.7.8\" to \"0.8.0\" [#2734](https://github.com/storybookjs/storybook/pull/2734)\n- Upgraded `autoprefixer` in `app/react` from \"7.2.4\" to \"7.2.5\" [#2734](https://github.com/storybookjs/storybook/pull/2734)\n- Upgraded `shelljs` in `app/react` from \"0.7.8\" to \"0.8.0\" [#2734](https://github.com/storybookjs/storybook/pull/2734)\n- Upgraded `autoprefixer` in `app/angular` from \"7.2.4\" to \"7.2.5\" [#2734](https://github.com/storybookjs/storybook/pull/2734)\n- Upgraded `shelljs` in `app/angular` from \"0.7.8\" to \"0.8.0\" [#2734](https://github.com/storybookjs/storybook/pull/2734)\n- Upgraded `autoprefixer` in `app/react-native` from \"7.2.4\" to \"7.2.5\" [#2734](https://github.com/storybookjs/storybook/pull/2734)\n- Upgraded `shelljs` in `app/react-native` from \"0.7.8\" to \"0.8.0\" [#2734](https://github.com/storybookjs/storybook/pull/2734)\n- Upgraded `autoprefixer` in `app/vue` from \"7.2.4\" to \"7.2.5\" [#2734](https://github.com/storybookjs/storybook/pull/2734)\n- Upgraded `shelljs` in `app/vue` from \"0.7.8\" to \"0.8.0\" [#2734](https://github.com/storybookjs/storybook/pull/2734)\n- Upgraded `shelljs` in `lib/cli` from \"0.7.8\" to \"0.8.0\" [#2734](https://github.com/storybookjs/storybook/pull/2734)\n- Update gatsby in /docs from 1.9.153 to 1.9.154 [#2733](https://github.com/storybookjs/storybook/pull/2733)\n- Update @angular/cli in examples/angular-cli from 1.6.3 to 1.6.4 [#2726](https://github.com/storybookjs/storybook/pull/2726)\n- Upgraded `commander` in `/` from \"2.12.2\" to \"2.13.0\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `jest` in `/` from \"22.0.5\" to \"22.0.6\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `jest-cli` in `/` from \"22.0.5\" to \"22.0.6\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `jest-config` in `/` from \"22.0.5\" to \"22.0.6\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `jest-diff` in `/` from \"22.0.5\" to \"22.0.6\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `jest-environment-jsdom` in `/` from \"22.0.5\" to \"22.0.6\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `jest-jasmine2` in `/` from \"22.0.5\" to \"22.0.6\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `nodemon` in `/` from \"1.14.10\" to \"1.14.11\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `prettier` in `/` from \"1.9.2\" to \"1.10.2\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `tslint` in `/` from \"5.8.0\" to \"5.9.1\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `commander` in `app/react` from \"2.12.2\" to \"2.13.0\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `common-tags` in `app/react` from \"1.7.0\" to \"1.7.2\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `nodemon` in `app/react` from \"1.14.10\" to \"1.14.11\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `commander` in `app/angular` from \"2.12.2\" to \"2.13.0\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `common-tags` in `app/angular` from \"1.7.0\" to \"1.7.2\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `zone.js` in `app/angular` from \"0.8.19\" to \"0.8.20\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `nodemon` in `app/angular` from \"1.14.10\" to \"1.14.11\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `commander` in `app/react-native` from \"2.12.2\" to \"2.13.0\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `commander` in `app/vue` from \"2.12.2\" to \"2.13.0\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `common-tags` in `app/vue` from \"1.7.0\" to \"1.7.2\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `nodemon` in `app/vue` from \"1.14.10\" to \"1.14.11\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `babel-jest` in `examples/cra-kitchen-sink` from \"22.0.4\" to \"22.0.6\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `jest` in `examples/cra-kitchen-sink` from \"22.0.5\" to \"22.0.6\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `commander` in `lib/cli` from \"2.12.2\" to \"2.13.0\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `zone.js` in `examples/angular-cli` from \"0.8.19\" to \"0.8.20\" [#2724](https://github.com/storybookjs/storybook/pull/2724)\n- Upgraded `@storybook/addon-actions` in `/docs` from \"3.3.7\" to \"3.3.8\" [#2722](https://github.com/storybookjs/storybook/pull/2722)\n- Upgraded `@storybook/addon-links` in `/docs` from \"3.3.7\" to \"3.3.8\" [#2722](https://github.com/storybookjs/storybook/pull/2722)\n- Upgraded `@storybook/addons` in `/docs` from \"3.3.7\" to \"3.3.8\" [#2722](https://github.com/storybookjs/storybook/pull/2722)\n- Upgraded `@storybook/react` in `/docs` from \"3.3.7\" to \"3.3.8\" [#2722](https://github.com/storybookjs/storybook/pull/2722)\n- Upgraded `gatsby-transformer-remark` in `/docs` from \"1.7.27\" to \"1.7.28\" [#2722](https://github.com/storybookjs/storybook/pull/2722)\n- Upgraded `gatsby` in `/docs` from \"1.9.151\" to \"1.9.153\" [#2722](https://github.com/storybookjs/storybook/pull/2722)\n- Upgraded `@storybook/addon-actions` in `/docs` from \"3.3.6\" to \"3.3.7\" [#2710](https://github.com/storybookjs/storybook/pull/2710)\n- Upgraded `@storybook/addon-links` in `/docs` from \"3.3.6\" to \"3.3.7\" [#2710](https://github.com/storybookjs/storybook/pull/2710)\n- Upgraded `@storybook/addons` in `/docs` from \"3.3.6\" to \"3.3.7\" [#2710](https://github.com/storybookjs/storybook/pull/2710)\n- Upgraded `@storybook/react` in `/docs` from \"3.3.6\" to \"3.3.7\" [#2710](https://github.com/storybookjs/storybook/pull/2710)\n- Upgraded `gatsby-link` in `/docs` from \"1.6.33\" to \"1.6.34\" [#2710](https://github.com/storybookjs/storybook/pull/2710)\n- Upgraded `gatsby-transformer-remark` in `/docs` from \"1.7.26\" to \"1.7.27\" [#2710](https://github.com/storybookjs/storybook/pull/2710)\n- Upgraded `gatsby` in `/docs` from \"1.9.150\" to \"1.9.151\" [#2710](https://github.com/storybookjs/storybook/pull/2710)\n\n</details>\n\n## 3.3.9\n\n2018-January-13\n\n#### Bug Fixes\n\n- Start haul/react-native using named binaries instead of cli.js [#2715](https://github.com/storybookjs/storybook/pull/2715)\n- Reflect the new peer dependencies in docs and CLI templates [#2714](https://github.com/storybookjs/storybook/pull/2714)\n- Don't mangle function names for production builds [#2705](https://github.com/storybookjs/storybook/pull/2705)\n\n## 3.4.0-alpha.2\n\n2018-January-11\n\nThis is a duplicate of `3.4.0-alpha.1`, re-published because I accidentally published `3.4.0-alpha.1` on the `latest` NPM tag.\n\n## 3.3.8\n\n2018-January-11\n\nThis is a duplicate of `3.3.7`, re-published because I accidentally published `3.4.0-alpha.1` on the `latest` NPM tag.\n\n## 3.4.0-alpha.1\n\n2018-January-10\n\nIn addition to the changes listed here, also contains fixes from [3.3.5](#335) and [3.3.6](#336) and [3.3.7](#337).\n\n#### Features\n\n- Custom tsconfig.json for angular apps. [#2669](https://github.com/storybookjs/storybook/pull/2669)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n105 Upgrades\n</summary>\n\n- Upgraded `babel-eslint` in `/` from \"8.1.2\" to \"8.2.1\" [#2700](https://github.com/storybookjs/storybook/pull/2700)\n- Upgraded `eslint-plugin-jest` in `/` from \"21.5.0\" to \"21.6.1\" [#2700](https://github.com/storybookjs/storybook/pull/2700)\n- Upgraded `jest` in `/` from \"22.0.4\" to \"22.0.5\" [#2700](https://github.com/storybookjs/storybook/pull/2700)\n- Upgraded `jest-cli` in `/` from \"22.0.4\" to \"22.0.5\" [#2700](https://github.com/storybookjs/storybook/pull/2700)\n- Upgraded `jest-config` in `/` from \"22.0.4\" to \"22.0.5\" [#2700](https://github.com/storybookjs/storybook/pull/2700)\n- Upgraded `jest-diff` in `/` from \"22.0.3\" to \"22.0.5\" [#2700](https://github.com/storybookjs/storybook/pull/2700)\n- Upgraded `jest-environment-jsdom` in `/` from \"22.0.4\" to \"22.0.5\" [#2700](https://github.com/storybookjs/storybook/pull/2700)\n- Upgraded `jest-jasmine2` in `/` from \"22.0.4\" to \"22.0.5\" [#2700](https://github.com/storybookjs/storybook/pull/2700)\n- Upgraded `lerna` in `/` from \"2.5.1\" to \"2.6.0\" [#2700](https://github.com/storybookjs/storybook/pull/2700)\n- Upgraded `nodemon` in `/` from \"1.14.9\" to \"1.14.10\" [#2700](https://github.com/storybookjs/storybook/pull/2700)\n- Upgraded `common-tags` in `app/react` from \"1.6.0\" to \"1.7.0\" [#2700](https://github.com/storybookjs/storybook/pull/2700)\n- Upgraded `nodemon` in `app/react` from \"1.14.9\" to \"1.14.10\" [#2700](https://github.com/storybookjs/storybook/pull/2700)\n- Upgraded `common-tags` in `app/angular` from \"1.6.0\" to \"1.7.0\" [#2700](https://github.com/storybookjs/storybook/pull/2700)\n- Upgraded `nodemon` in `app/angular` from \"1.14.9\" to \"1.14.10\" [#2700](https://github.com/storybookjs/storybook/pull/2700)\n- Upgraded `common-tags` in `app/vue` from \"1.6.0\" to \"1.7.0\" [#2700](https://github.com/storybookjs/storybook/pull/2700)\n- Upgraded `nodemon` in `app/vue` from \"1.14.9\" to \"1.14.10\" [#2700](https://github.com/storybookjs/storybook/pull/2700)\n- Upgraded `vue-loader` in `app/vue` from \"13.6.2\" to \"13.7.0\" [#2700](https://github.com/storybookjs/storybook/pull/2700)\n- Upgraded `jest` in `examples/cra-kitchen-sink` from \"22.0.4\" to \"22.0.5\" [#2700](https://github.com/storybookjs/storybook/pull/2700)\n- Upgraded `vue-loader` in `examples/vue-kitchen-sink` from \"13.6.2\" to \"13.7.0\" [#2700](https://github.com/storybookjs/storybook/pull/2700)\n- Upgraded `webpack-dev-server` in `examples/vue-kitchen-sink` from \"2.10.0\" to \"2.10.1\" [#2700](https://github.com/storybookjs/storybook/pull/2700)\n- Upgraded `marked` in `/docs` from \"0.3.7\" to \"0.3.12\" [#2699](https://github.com/storybookjs/storybook/pull/2699)\n- Upgraded `react-stack-grid` in `/docs` from \"0.7.0\" to \"0.7.1\" [#2699](https://github.com/storybookjs/storybook/pull/2699)\n- Upgraded `@storybook/addon-actions` in `/docs` from \"3.3.4\" to \"3.3.6\" [#2686](https://github.com/storybookjs/storybook/pull/2686)\n- Upgraded `@storybook/addon-links` in `/docs` from \"3.3.4\" to \"3.3.6\" [#2686](https://github.com/storybookjs/storybook/pull/2686)\n- Upgraded `@storybook/addons` in `/docs` from \"3.3.4\" to \"3.3.6\" [#2686](https://github.com/storybookjs/storybook/pull/2686)\n- Upgraded `@storybook/react` in `/docs` from \"3.3.4\" to \"3.3.6\" [#2686](https://github.com/storybookjs/storybook/pull/2686)\n- Upgraded `gatsby-link` in `/docs` from \"1.6.32\" to \"1.6.33\" [#2686](https://github.com/storybookjs/storybook/pull/2686)\n- Upgraded `gatsby` in `/docs` from \"1.9.149\" to \"1.9.150\" [#2686](https://github.com/storybookjs/storybook/pull/2686)\n- Upgraded `nodemon` in `/` from \"1.14.8\" to \"1.14.9\" [#2687](https://github.com/storybookjs/storybook/pull/2687)\n- Upgraded `markdown-loader` in `app/react` from \"2.0.1\" to \"2.0.2\" [#2687](https://github.com/storybookjs/storybook/pull/2687)\n- Upgraded `nodemon` in `app/react` from \"1.14.8\" to \"1.14.9\" [#2687](https://github.com/storybookjs/storybook/pull/2687)\n- Upgraded `nodemon` in `app/angular` from \"1.14.8\" to \"1.14.9\" [#2687](https://github.com/storybookjs/storybook/pull/2687)\n- Upgraded `react-native` in `app/react-native` from \"0.51.0\" to \"0.52.0\" [#2687](https://github.com/storybookjs/storybook/pull/2687)\n- Upgraded `nodemon` in `app/vue` from \"1.14.8\" to \"1.14.9\" [#2687](https://github.com/storybookjs/storybook/pull/2687)\n- Upgraded `@storybook/addon-actions` in `/docs` from \"3.3.3\" to \"3.3.4\" [#2674](https://github.com/storybookjs/storybook/pull/2674)\n- Upgraded `@storybook/addon-links` in `/docs` from \"3.3.3\" to \"3.3.4\" [#2674](https://github.com/storybookjs/storybook/pull/2674)\n- Upgraded `@storybook/addons` in `/docs` from \"3.3.3\" to \"3.3.4\" [#2674](https://github.com/storybookjs/storybook/pull/2674)\n- Upgraded `@storybook/react` in `/docs` from \"3.3.3\" to \"3.3.4\" [#2674](https://github.com/storybookjs/storybook/pull/2674)\n- Update eslint in / from 4.14.0 to 4.15.0 [#2673](https://github.com/storybookjs/storybook/pull/2673)\n- Upgraded `nodemon` in `/` from \"1.14.7\" to \"1.14.8\" [#2664](https://github.com/storybookjs/storybook/pull/2664)\n- Upgraded `marksy` in `addons/info` from \"6.0.2\" to \"6.0.3\" [#2664](https://github.com/storybookjs/storybook/pull/2664)\n- Upgraded `nodemon` in `app/react` from \"1.14.7\" to \"1.14.8\" [#2664](https://github.com/storybookjs/storybook/pull/2664)\n- Upgraded `nodemon` in `app/angular` from \"1.14.7\" to \"1.14.8\" [#2664](https://github.com/storybookjs/storybook/pull/2664)\n- Upgraded `nodemon` in `app/vue` from \"1.14.7\" to \"1.14.8\" [#2664](https://github.com/storybookjs/storybook/pull/2664)\n- Upgraded `webpack-dev-server` in `examples/vue-kitchen-sink` from \"2.9.7\" to \"2.10.0\" [#2664](https://github.com/storybookjs/storybook/pull/2664)\n- Upgraded `@types/lodash` in `/` from \"4.14.91\" to \"4.14.92\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `marksy` in `addons/info` from \"6.0.1\" to \"6.0.2\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `css-loader` in `app/react` from \"0.28.7\" to \"0.28.8\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `html-loader` in `app/react` from \"0.5.1\" to \"0.5.4\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `uglifyjs-webpack-plugin` in `app/react` from \"1.1.5\" to \"1.1.6\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `css-loader` in `app/angular` from \"0.28.7\" to \"0.28.8\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `uglifyjs-webpack-plugin` in `app/angular` from \"1.1.5\" to \"1.1.6\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `css-loader` in `app/react-native` from \"0.28.7\" to \"0.28.8\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `uglifyjs-webpack-plugin` in `app/react-native` from \"1.1.5\" to \"1.1.6\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `css-loader` in `app/vue` from \"0.28.7\" to \"0.28.8\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `uglifyjs-webpack-plugin` in `app/vue` from \"1.1.5\" to \"1.1.6\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `@types/node` in `examples/angular-cli` from \"6.0.95\" to \"6.0.96\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `css-loader` in `examples/vue-kitchen-sink` from \"0.28.7\" to \"0.28.8\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `@angular/animations` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `@angular/common` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `@angular/compiler` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `@angular/core` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `@angular/forms` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `@angular/http` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `@angular/platform-browser` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `@angular/platform-browser-dynamic` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `@angular/router` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `@angular/compiler-cli` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `@angular/language-service` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `postcss-loader` in `app/react` from \"2.0.9\" to \"2.0.10\" [#2637](https://github.com/storybookjs/storybook/pull/2637)\n- Upgraded `postcss-loader` in `app/angular` from \"2.0.9\" to \"2.0.10\" [#2637](https://github.com/storybookjs/storybook/pull/2637)\n- Upgraded `postcss-loader` in `app/react-native` from \"2.0.9\" to \"2.0.10\" [#2637](https://github.com/storybookjs/storybook/pull/2637)\n- Upgraded `postcss-loader` in `app/vue` from \"2.0.9\" to \"2.0.10\" [#2637](https://github.com/storybookjs/storybook/pull/2637)\n- Update inquirer in / from 4.0.1 to 4.0.2 [#2632](https://github.com/storybookjs/storybook/pull/2632)\n- Upgraded `danger` in `/` from \"2.1.8\" to \"2.1.10\" [#2618](https://github.com/storybookjs/storybook/pull/2618)\n- Upgraded `autoprefixer` in `app/react` from \"7.2.3\" to \"7.2.4\" [#2618](https://github.com/storybookjs/storybook/pull/2618)\n- Upgraded `autoprefixer` in `app/angular` from \"7.2.3\" to \"7.2.4\" [#2618](https://github.com/storybookjs/storybook/pull/2618)\n- Upgraded `autoprefixer` in `app/react-native` from \"7.2.3\" to \"7.2.4\" [#2618](https://github.com/storybookjs/storybook/pull/2618)\n- Upgraded `autoprefixer` in `app/vue` from \"7.2.3\" to \"7.2.4\" [#2618](https://github.com/storybookjs/storybook/pull/2618)\n- Upgraded `nodemon` in `/` from \"1.14.6\" to \"1.14.7\" [#2612](https://github.com/storybookjs/storybook/pull/2612)\n- Upgraded `nodemon` in `app/react` from \"1.14.6\" to \"1.14.7\" [#2612](https://github.com/storybookjs/storybook/pull/2612)\n- Upgraded `nodemon` in `app/angular` from \"1.14.6\" to \"1.14.7\" [#2612](https://github.com/storybookjs/storybook/pull/2612)\n- Upgraded `nodemon` in `app/vue` from \"1.14.6\" to \"1.14.7\" [#2612](https://github.com/storybookjs/storybook/pull/2612)\n- Upgraded `vue-loader` in `app/vue` from \"13.6.1\" to \"13.6.2\" [#2611](https://github.com/storybookjs/storybook/pull/2611)\n- Upgraded `vue-loader` in `examples/vue-kitchen-sink` from \"13.6.1\" to \"13.6.2\" [#2611](https://github.com/storybookjs/storybook/pull/2611)\n- Upgraded `nodemon` in `/` from \"1.14.5\" to \"1.14.6\" [#2609](https://github.com/storybookjs/storybook/pull/2609)\n- Upgraded `nodemon` in `app/react` from \"1.14.5\" to \"1.14.6\" [#2609](https://github.com/storybookjs/storybook/pull/2609)\n- Upgraded `nodemon` in `app/angular` from \"1.14.5\" to \"1.14.6\" [#2609](https://github.com/storybookjs/storybook/pull/2609)\n- Upgraded `nodemon` in `app/vue` from \"1.14.5\" to \"1.14.6\" [#2609](https://github.com/storybookjs/storybook/pull/2609)\n- Upgraded `enzyme` in `/` from \"3.2.0\" to \"3.3.0\" [#2608](https://github.com/storybookjs/storybook/pull/2608)\n- Upgraded `nodemon` in `/` from \"1.14.3\" to \"1.14.5\" [#2608](https://github.com/storybookjs/storybook/pull/2608)\n- Upgraded `graphiql` in `addons/graphql` from \"0.11.10\" to \"0.11.11\" [#2608](https://github.com/storybookjs/storybook/pull/2608)\n- Upgraded `enzyme` in `addons/links` from \"3.2.0\" to \"3.3.0\" [#2608](https://github.com/storybookjs/storybook/pull/2608)\n- Upgraded `nodemon` in `app/react` from \"1.14.3\" to \"1.14.5\" [#2608](https://github.com/storybookjs/storybook/pull/2608)\n- Upgraded `nodemon` in `app/angular` from \"1.14.3\" to \"1.14.5\" [#2608](https://github.com/storybookjs/storybook/pull/2608)\n- Upgraded `nodemon` in `app/vue` from \"1.14.3\" to \"1.14.5\" [#2608](https://github.com/storybookjs/storybook/pull/2608)\n- Upgraded `enzyme` in `examples/cra-kitchen-sink` from \"3.2.0\" to \"3.3.0\" [#2608](https://github.com/storybookjs/storybook/pull/2608)\n- Upgraded `enzyme` in `examples/official-storybook` from \"3.2.0\" to \"3.3.0\" [#2608](https://github.com/storybookjs/storybook/pull/2608)\n- Update 2 dependencies from npm [#2597](https://github.com/storybookjs/storybook/pull/2597)\n- Upgraded `@storybook/addon-actions` in `/docs` from \"3.3.1\" to \"3.3.3\" [#2598](https://github.com/storybookjs/storybook/pull/2598)\n- Upgraded `@storybook/addon-links` in `/docs` from \"3.3.1\" to \"3.3.3\" [#2598](https://github.com/storybookjs/storybook/pull/2598)\n- Upgraded `@storybook/addons` in `/docs` from \"3.3.1\" to \"3.3.3\" [#2598](https://github.com/storybookjs/storybook/pull/2598)\n- Upgraded `@storybook/react` in `/docs` from \"3.3.1\" to \"3.3.3\" [#2598](https://github.com/storybookjs/storybook/pull/2598)\n- Upgraded `danger` in `/` from \"2.1.6\" to \"2.1.8\" [#2599](https://github.com/storybookjs/storybook/pull/2599)\n- Upgraded `axe-core` in `addons/a11y` from \"2.6.0\" to \"2.6.1\" [#2599](https://github.com/storybookjs/storybook/pull/2599)\n\n</details>\n\n## 3.3.7\n\n2018-January-10\n\n#### Maintenance\n\n- Extract tslint exclusions out of package.json scripts [#2684](https://github.com/storybookjs/storybook/pull/2684)\n- Add tslint to the linting pipe [#2682](https://github.com/storybookjs/storybook/pull/2682)\n\n#### Bug Fixes\n\n- Angular: add entry components to modulemetadata - #2701 [#2702](https://github.com/storybookjs/storybook/pull/2702)\n- Add html and markup loaders to angular and vue apps [#2692](https://github.com/storybookjs/storybook/pull/2692)\n\n## 3.3.6\n\n2018-January-08\n\n#### Bug Fixes\n\n- Remove `src/` from remaining `.npmignore`s [#2678](https://github.com/storybookjs/storybook/pull/2678)\n\n## 3.3.5\n\n2018-January-08\n\n#### Bug Fixes\n\n- Remove src from individual .npmignore files [#2677](https://github.com/storybookjs/storybook/pull/2677)\n\n## 3.4.0-alpha.0\n\n2018-January-07\n\n#### Features\n\n- Multiple hierarchies [#2452](https://github.com/storybookjs/storybook/pull/2452)\n- Change template story files extension to .ts [#2594](https://github.com/storybookjs/storybook/pull/2594)\n- Use store revisions to ensure that stories re-render on HMR. [#2605](https://github.com/storybookjs/storybook/pull/2605)\n- Ability to force re-render a story [#2463](https://github.com/storybookjs/storybook/pull/2463)\n- Introduce framework-independent core library [#2241](https://github.com/storybookjs/storybook/pull/2241)\n\n#### Documentation\n\n<details>\n<summary>\n4 PRs\n</summary>\n\n- Update webpack extend warning. [#2660](https://github.com/storybookjs/storybook/pull/2660)\n- ADD demo images to a new img folder with the documentation site [#2644](https://github.com/storybookjs/storybook/pull/2644)\n- write doc about .css/.scss rules for Angular [#2634](https://github.com/storybookjs/storybook/pull/2634)\n- Updated documentation wrt ejs exclusion [#2633](https://github.com/storybookjs/storybook/pull/2633)\n\n</details>\n\n#### Maintenance\n\n<details>\n<summary>\n4 PRs\n</summary>\n\n- Only update CLI snapshots on postpublish script, skip smoke tests [#2671](https://github.com/storybookjs/storybook/pull/2671)\n- Fix the timezone for example dates [#2654](https://github.com/storybookjs/storybook/pull/2654)\n- Update prereq yarn install level [#2638](https://github.com/storybookjs/storybook/pull/2638)\n- Separate stories in angular-cli example [#2592](https://github.com/storybookjs/storybook/pull/2592)\n\n</details>\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n66 Upgrades\n</summary>\n\n- Upgraded `nodemon` in `/` from \"1.14.7\" to \"1.14.8\" [#2664](https://github.com/storybookjs/storybook/pull/2664)\n- Upgraded `marksy` in `addons/info` from \"6.0.2\" to \"6.0.3\" [#2664](https://github.com/storybookjs/storybook/pull/2664)\n- Upgraded `nodemon` in `app/react` from \"1.14.7\" to \"1.14.8\" [#2664](https://github.com/storybookjs/storybook/pull/2664)\n- Upgraded `nodemon` in `app/angular` from \"1.14.7\" to \"1.14.8\" [#2664](https://github.com/storybookjs/storybook/pull/2664)\n- Upgraded `nodemon` in `app/vue` from \"1.14.7\" to \"1.14.8\" [#2664](https://github.com/storybookjs/storybook/pull/2664)\n- Upgraded `webpack-dev-server` in `examples/vue-kitchen-sink` from \"2.9.7\" to \"2.10.0\" [#2664](https://github.com/storybookjs/storybook/pull/2664)\n- Upgraded `@types/lodash` in `/` from \"4.14.91\" to \"4.14.92\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `marksy` in `addons/info` from \"6.0.1\" to \"6.0.2\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `css-loader` in `app/react` from \"0.28.7\" to \"0.28.8\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `html-loader` in `app/react` from \"0.5.1\" to \"0.5.4\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `uglifyjs-webpack-plugin` in `app/react` from \"1.1.5\" to \"1.1.6\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `css-loader` in `app/angular` from \"0.28.7\" to \"0.28.8\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `uglifyjs-webpack-plugin` in `app/angular` from \"1.1.5\" to \"1.1.6\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `css-loader` in `app/react-native` from \"0.28.7\" to \"0.28.8\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `uglifyjs-webpack-plugin` in `app/react-native` from \"1.1.5\" to \"1.1.6\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `css-loader` in `app/vue` from \"0.28.7\" to \"0.28.8\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `uglifyjs-webpack-plugin` in `app/vue` from \"1.1.5\" to \"1.1.6\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `@types/node` in `examples/angular-cli` from \"6.0.95\" to \"6.0.96\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `css-loader` in `examples/vue-kitchen-sink` from \"0.28.7\" to \"0.28.8\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `@angular/animations` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `@angular/common` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `@angular/compiler` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `@angular/core` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `@angular/forms` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `@angular/http` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `@angular/platform-browser` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `@angular/platform-browser-dynamic` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `@angular/router` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `@angular/compiler-cli` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `@angular/language-service` in `examples/angular-cli` from \"5.1.2\" to \"5.1.3\" [#2648](https://github.com/storybookjs/storybook/pull/2648)\n- Upgraded `postcss-loader` in `app/react` from \"2.0.9\" to \"2.0.10\" [#2637](https://github.com/storybookjs/storybook/pull/2637)\n- Upgraded `postcss-loader` in `app/angular` from \"2.0.9\" to \"2.0.10\" [#2637](https://github.com/storybookjs/storybook/pull/2637)\n- Upgraded `postcss-loader` in `app/react-native` from \"2.0.9\" to \"2.0.10\" [#2637](https://github.com/storybookjs/storybook/pull/2637)\n- Upgraded `postcss-loader` in `app/vue` from \"2.0.9\" to \"2.0.10\" [#2637](https://github.com/storybookjs/storybook/pull/2637)\n- Update inquirer in / from 4.0.1 to 4.0.2 [#2632](https://github.com/storybookjs/storybook/pull/2632)\n- Upgraded `danger` in `/` from \"2.1.8\" to \"2.1.10\" [#2618](https://github.com/storybookjs/storybook/pull/2618)\n- Upgraded `autoprefixer` in `app/react` from \"7.2.3\" to \"7.2.4\" [#2618](https://github.com/storybookjs/storybook/pull/2618)\n- Upgraded `autoprefixer` in `app/angular` from \"7.2.3\" to \"7.2.4\" [#2618](https://github.com/storybookjs/storybook/pull/2618)\n- Upgraded `autoprefixer` in `app/react-native` from \"7.2.3\" to \"7.2.4\" [#2618](https://github.com/storybookjs/storybook/pull/2618)\n- Upgraded `autoprefixer` in `app/vue` from \"7.2.3\" to \"7.2.4\" [#2618](https://github.com/storybookjs/storybook/pull/2618)\n- Upgraded `nodemon` in `/` from \"1.14.6\" to \"1.14.7\" [#2612](https://github.com/storybookjs/storybook/pull/2612)\n- Upgraded `nodemon` in `app/react` from \"1.14.6\" to \"1.14.7\" [#2612](https://github.com/storybookjs/storybook/pull/2612)\n- Upgraded `nodemon` in `app/angular` from \"1.14.6\" to \"1.14.7\" [#2612](https://github.com/storybookjs/storybook/pull/2612)\n- Upgraded `nodemon` in `app/vue` from \"1.14.6\" to \"1.14.7\" [#2612](https://github.com/storybookjs/storybook/pull/2612)\n- Upgraded `vue-loader` in `app/vue` from \"13.6.1\" to \"13.6.2\" [#2611](https://github.com/storybookjs/storybook/pull/2611)\n- Upgraded `vue-loader` in `examples/vue-kitchen-sink` from \"13.6.1\" to \"13.6.2\" [#2611](https://github.com/storybookjs/storybook/pull/2611)\n- Upgraded `nodemon` in `/` from \"1.14.5\" to \"1.14.6\" [#2609](https://github.com/storybookjs/storybook/pull/2609)\n- Upgraded `nodemon` in `app/react` from \"1.14.5\" to \"1.14.6\" [#2609](https://github.com/storybookjs/storybook/pull/2609)\n- Upgraded `nodemon` in `app/angular` from \"1.14.5\" to \"1.14.6\" [#2609](https://github.com/storybookjs/storybook/pull/2609)\n- Upgraded `nodemon` in `app/vue` from \"1.14.5\" to \"1.14.6\" [#2609](https://github.com/storybookjs/storybook/pull/2609)\n- Upgraded `enzyme` in `/` from \"3.2.0\" to \"3.3.0\" [#2608](https://github.com/storybookjs/storybook/pull/2608)\n- Upgraded `nodemon` in `/` from \"1.14.3\" to \"1.14.5\" [#2608](https://github.com/storybookjs/storybook/pull/2608)\n- Upgraded `graphiql` in `addons/graphql` from \"0.11.10\" to \"0.11.11\" [#2608](https://github.com/storybookjs/storybook/pull/2608)\n- Upgraded `enzyme` in `addons/links` from \"3.2.0\" to \"3.3.0\" [#2608](https://github.com/storybookjs/storybook/pull/2608)\n- Upgraded `nodemon` in `app/react` from \"1.14.3\" to \"1.14.5\" [#2608](https://github.com/storybookjs/storybook/pull/2608)\n- Upgraded `nodemon` in `app/angular` from \"1.14.3\" to \"1.14.5\" [#2608](https://github.com/storybookjs/storybook/pull/2608)\n- Upgraded `nodemon` in `app/vue` from \"1.14.3\" to \"1.14.5\" [#2608](https://github.com/storybookjs/storybook/pull/2608)\n- Upgraded `enzyme` in `examples/cra-kitchen-sink` from \"3.2.0\" to \"3.3.0\" [#2608](https://github.com/storybookjs/storybook/pull/2608)\n- Upgraded `enzyme` in `examples/official-storybook` from \"3.2.0\" to \"3.3.0\" [#2608](https://github.com/storybookjs/storybook/pull/2608)\n- Update 2 dependencies from npm [#2597](https://github.com/storybookjs/storybook/pull/2597)\n- Upgraded `@storybook/addon-actions` in `/docs` from \"3.3.1\" to \"3.3.3\" [#2598](https://github.com/storybookjs/storybook/pull/2598)\n- Upgraded `@storybook/addon-links` in `/docs` from \"3.3.1\" to \"3.3.3\" [#2598](https://github.com/storybookjs/storybook/pull/2598)\n- Upgraded `@storybook/addons` in `/docs` from \"3.3.1\" to \"3.3.3\" [#2598](https://github.com/storybookjs/storybook/pull/2598)\n- Upgraded `@storybook/react` in `/docs` from \"3.3.1\" to \"3.3.3\" [#2598](https://github.com/storybookjs/storybook/pull/2598)\n- Upgraded `danger` in `/` from \"2.1.6\" to \"2.1.8\" [#2599](https://github.com/storybookjs/storybook/pull/2599)\n- Upgraded `axe-core` in `addons/a11y` from \"2.6.0\" to \"2.6.1\" [#2599](https://github.com/storybookjs/storybook/pull/2599)\n\n</details>\n\n## 3.3.4\n\n2018-January-07\n\n#### Bug Fixes\n\n- Fix config dir detection [#2666](https://github.com/storybookjs/storybook/pull/2666)\n- Removed lowercase-only restriction for knobs [#2646](https://github.com/storybookjs/storybook/pull/2646)\n- Add IE11 compatibility meta tag [#2650](https://github.com/storybookjs/storybook/pull/2650)\n- Allow transparency in color knob [#2624](https://github.com/storybookjs/storybook/pull/2624)\n- RN: Use haul/bin/cli.js for cross-platform support [#2577](https://github.com/storybookjs/storybook/pull/2577)\n- Publish package sources along with transpiled files [#2604](https://github.com/storybookjs/storybook/pull/2604)\n- Fixed all peerDependencies for apps. [#2601](https://github.com/storybookjs/storybook/pull/2601)\n- Renamed angular root node to avoid name collisions [#2657](https://github.com/storybookjs/storybook/pull/2657)\n- Add .ts compatibility to storyshots [#2639](https://github.com/storybookjs/storybook/pull/2639)\n- Remove @angular/core dep from knobs peer. [#2640](https://github.com/storybookjs/storybook/pull/2640)\n- Angular: Change template story files extension .ts [#2594](https://github.com/storybookjs/storybook/pull/2594)\n- Skip serializing (Synthetic)Events [#2626](https://github.com/storybookjs/storybook/pull/2626)\n\n#### Maintenance\n\n- Separate stories in angular-cli example [#2592](https://github.com/storybookjs/storybook/pull/2592)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n13 Upgrades\n</summary>\n\n- Upgraded `@types/lodash` in `/` from \"4.14.91\" to \"4.14.92\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `marksy` in `addons/info` from \"6.0.1\" to \"6.0.2\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `css-loader` in `app/react` from \"0.28.7\" to \"0.28.8\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `html-loader` in `app/react` from \"0.5.1\" to \"0.5.4\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `uglifyjs-webpack-plugin` in `app/react` from \"1.1.5\" to \"1.1.6\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `css-loader` in `app/angular` from \"0.28.7\" to \"0.28.8\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `uglifyjs-webpack-plugin` in `app/angular` from \"1.1.5\" to \"1.1.6\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `css-loader` in `app/react-native` from \"0.28.7\" to \"0.28.8\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `uglifyjs-webpack-plugin` in `app/react-native` from \"1.1.5\" to \"1.1.6\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `css-loader` in `app/vue` from \"0.28.7\" to \"0.28.8\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `uglifyjs-webpack-plugin` in `app/vue` from \"1.1.5\" to \"1.1.6\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `@types/node` in `examples/angular-cli` from \"6.0.95\" to \"6.0.96\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n- Upgraded `css-loader` in `examples/vue-kitchen-sink` from \"0.28.7\" to \"0.28.8\" [#2659](https://github.com/storybookjs/storybook/pull/2659)\n\n</details>\n\n## 3.3.3\n\n2017-December-29\n\n#### Bug Fixes\n\n- `app:angular` Fixed dependency injection for components [#2566](https://github.com/storybookjs/storybook/pull/2566)\n- Revert \"Move everything from lodash to lodash-es\" [#2591](https://github.com/storybookjs/storybook/pull/2591)\n\n#### Maintenance\n\n- Update CLI snapshots as a postpublish step [#2565](https://github.com/storybookjs/storybook/pull/2565)\n- Add more `imports` eslint rules [#2589](https://github.com/storybookjs/storybook/pull/2589)\n\n#### Dependency Upgrades\n\n- Upgraded `@storybook/addon-actions` in `/docs` from \"3.2.18\" to \"3.3.1\" [#2580](https://github.com/storybookjs/storybook/pull/2580)\n- Upgraded `@storybook/addon-links` in `/docs` from \"3.2.18\" to \"3.3.1\" [#2580](https://github.com/storybookjs/storybook/pull/2580)\n- Upgraded `@storybook/addons` in `/docs` from \"3.2.18\" to \"3.3.1\" [#2580](https://github.com/storybookjs/storybook/pull/2580)\n- Upgraded `@storybook/react` in `/docs` from \"3.2.18\" to \"3.3.1\" [#2580](https://github.com/storybookjs/storybook/pull/2580)\n\n## 3.3.2\n\n2017-December-28\n\n#### Bug Fixes\n\n- Use store revisions to ensure that stories re-render on HMR. [#2588](https://github.com/storybookjs/storybook/pull/2588)\n- Fix @storybook/client-logger import [#2576](https://github.com/storybookjs/storybook/pull/2576)\n- Fixed react peer dependency [#2584](https://github.com/storybookjs/storybook/pull/2584)\n\n#### Documentation\n\n- Docs: fix logos display & add babelrc [#2585](https://github.com/storybookjs/storybook/pull/2585)\n- add guide for Angular [#2574](https://github.com/storybookjs/storybook/pull/2574)\n- Update custom webpack config docs [#2578](https://github.com/storybookjs/storybook/pull/2578)\n- Attempt to make propTablesExclude usage clearer [#2568](https://github.com/storybookjs/storybook/pull/2568)\n\n#### Maintenance\n\n- Add chromatic visual tests [#2505](https://github.com/storybookjs/storybook/pull/2505)\n- Update snapshots to fix tests [#2579](https://github.com/storybookjs/storybook/pull/2579)\n\n#### Dependency Upgrades\n\n- Upgraded `make-error` in `addons/actions` from \"1.3.0\" to \"1.3.2\" [#2586](https://github.com/storybookjs/storybook/pull/2586)\n- Upgraded `zone.js` in `app/angular` from \"0.8.18\" to \"0.8.19\" [#2586](https://github.com/storybookjs/storybook/pull/2586)\n- Upgraded `zone.js` in `examples/angular-cli` from \"0.8.18\" to \"0.8.19\" [#2586](https://github.com/storybookjs/storybook/pull/2586)\n- Upgraded `@angular/cli` in `examples/angular-cli` from \"1.6.2\" to \"1.6.3\" [#2586](https://github.com/storybookjs/storybook/pull/2586)\n- Upgraded `uglifyjs-webpack-plugin` in `app/react` from \"1.1.4\" to \"1.1.5\" [#2581](https://github.com/storybookjs/storybook/pull/2581)\n- Upgraded `uglifyjs-webpack-plugin` in `app/angular` from \"1.1.4\" to \"1.1.5\" [#2581](https://github.com/storybookjs/storybook/pull/2581)\n- Upgraded `uglifyjs-webpack-plugin` in `app/react-native` from \"1.1.4\" to \"1.1.5\" [#2581](https://github.com/storybookjs/storybook/pull/2581)\n- Upgraded `uglifyjs-webpack-plugin` in `app/vue` from \"1.1.4\" to \"1.1.5\" [#2581](https://github.com/storybookjs/storybook/pull/2581)\n- Upgraded `karma-coverage-istanbul-reporter` in `examples/angular-cli` from \"1.3.1\" to \"1.3.3\" [#2581](https://github.com/storybookjs/storybook/pull/2581)\n\n## 3.3.1\n\n2017-December-26\n\n#### Bug Fixes\n\n- Fix storybook CLI for angular: dev dependencies and fix addon-notes usage [#2572](https://github.com/storybookjs/storybook/pull/2572)\n\n#### Documentation\n\n- Add migration note about #2570 [#2571](https://github.com/storybookjs/storybook/pull/2571)\n\n## 3.3.0\n\n2017-December-26\n\nAt long last! 3.3 contains a few major features and a ginormous backlog of smaller changes. A few highlights:\n\n- Add angular support: Storybook for Angular [#1474](https://github.com/storybookjs/storybook/pull/1474)\n- Viewport Addon: simulate device sizes [#1740](https://github.com/storybookjs/storybook/pull/1740)\n- Jest Addon: preview test results in Storybook [#2295](https://github.com/storybookjs/storybook/pull/2295)\n- Stories panel: Stories on each hierarchy level [#1763](https://github.com/storybookjs/storybook/pull/1763)\n- Storyshots: Generate snapshot per story file [#1584](https://github.com/storybookjs/storybook/pull/1584)\n- Add support for importing markdown in storybook [#2299](https://github.com/storybookjs/storybook/pull/2299)\n\nWe'll do a better job of getting out smaller releases next time around. ;-)\n\n#### Features\n\n- Add support for importing markdown in storybook [#2299](https://github.com/storybookjs/storybook/pull/2299)\n- Add `TableComponent` option for addon-info [#2400](https://github.com/storybookjs/storybook/pull/2400)\n- Change keyboard shortcuts to platform safe [#1858](https://github.com/storybookjs/storybook/pull/1858)\n- Replace `console` with `client-logger` and `node-logger` packages [#2347](https://github.com/storybookjs/storybook/pull/2347)\n- Add renderer option to storyshots [#2414](https://github.com/storybookjs/storybook/pull/2414)\n- Added type annotation to helpers, added ts declaration files for angu… [#2459](https://github.com/storybookjs/storybook/pull/2459)\n- Adding extra metadata to module/components [#2526](https://github.com/storybookjs/storybook/pull/2526)\n- Fix ng component prop output override [#2456](https://github.com/storybookjs/storybook/pull/2456)\n- `WIP` Angular versions support [#2467](https://github.com/storybookjs/storybook/pull/2467)\n- Angular Add custom pipes support [#2518](https://github.com/storybookjs/storybook/pull/2518)\n- Add angular support: Storybook for Angular [#1474](https://github.com/storybookjs/storybook/pull/1474)\n- Fix addon Knobs: add array in Object PropTypes [#2227](https://github.com/storybookjs/storybook/pull/2227)\n- Adds error when storyshots finds no stories [#2079](https://github.com/storybookjs/storybook/pull/2079)\n- Add addon background to monorepo [#2220](https://github.com/storybookjs/storybook/pull/2220)\n- Add ability to parse line breaks into <br/> for Docgen descriptions [#2053](https://github.com/storybookjs/storybook/pull/2053)\n- Ability for custom storyshots testFunctions to utilise \"snapshot per story file\" [#1841](https://github.com/storybookjs/storybook/pull/1841)\n- Viewport Addon [#1753](https://github.com/storybookjs/storybook/pull/1753)\n- Viewport Addon [#1740](https://github.com/storybookjs/storybook/pull/1740)\n- Generate snapshot per story file [#1584](https://github.com/storybookjs/storybook/pull/1584)\n- addon-links: add `LinkTo` component, and `hrefTo` function [#1829](https://github.com/storybookjs/storybook/pull/1829)\n- Viewport addon: simulate device sizes in preview window [#1753](https://github.com/storybookjs/storybook/pull/1753)\n- CLI: Add codemod for deprecated addon-links and addon-actions from app [#1368](https://github.com/storybookjs/storybook/pull/1368)\n- Info addon: More detailed props table [#1485](https://github.com/storybookjs/storybook/pull/1485)\n- React native: Add accessibility labels to OnDeviceUI [#1780](https://github.com/storybookjs/storybook/pull/1780)\n- Stories panel: Stories on each hierarchy level [#1763](https://github.com/storybookjs/storybook/pull/1763)\n- Storyshots: Generate snapshot per story file [#1584](https://github.com/storybookjs/storybook/pull/1584)\n- CLI: Add support for Vue projects using Nuxt [#1794](https://github.com/storybookjs/storybook/pull/1794)\n\n#### Bug Fixes\n\n- Fix whitespace on info add-on card [#2543](https://github.com/storybookjs/storybook/pull/2543)\n- Angular component props assignment improvements [#2554](https://github.com/storybookjs/storybook/pull/2554)\n- Remove redundant render in react [#2503](https://github.com/storybookjs/storybook/pull/2503)\n- Addon-actions: Fix types and refactor [#2438](https://github.com/storybookjs/storybook/pull/2438)\n- Fix warnings in search box [#2479](https://github.com/storybookjs/storybook/pull/2479)\n- Migrate to marksy@6 [#2464](https://github.com/storybookjs/storybook/pull/2464)\n- Extract Jest config from package.json to config file [#2424](https://github.com/storybookjs/storybook/pull/2424)\n- Fix Horizontal Scrollbar of DownPanel [#2410](https://github.com/storybookjs/storybook/pull/2410)\n- Move `@storybook/addons` to peerDependencies in all addons [#2335](https://github.com/storybookjs/storybook/pull/2335)\n- Fix compatibility with @babel/core v7 [#2494](https://github.com/storybookjs/storybook/pull/2494)\n- Unmount after storyshot snapshot [#2417](https://github.com/storybookjs/storybook/pull/2417)\n- Fix HMR by saving the preview frame URL as the story changes [#2349](https://github.com/storybookjs/storybook/pull/2349)\n- Fix CLI babel transpilation [#2350](https://github.com/storybookjs/storybook/pull/2350)\n- Move LinkTo component to a separate `addon-links/react` endpoint [#2239](https://github.com/storybookjs/storybook/pull/2239)\n- Fix Array Knob deserialization [#2217](https://github.com/storybookjs/storybook/pull/2217)\n- Return the test in storyshots to respect promises. [#2218](https://github.com/storybookjs/storybook/pull/2218)\n- Knobs refactor accidentally removed select [#2210](https://github.com/storybookjs/storybook/pull/2210)\n- Add HMR to other RN app templates [#2213](https://github.com/storybookjs/storybook/pull/2213)\n- Autoload all `*.stories.js` files in cli templates [#2195](https://github.com/storybookjs/storybook/pull/2195)\n- Fix info upgrade codemod failing when optional description string is not supplied [#2138](https://github.com/storybookjs/storybook/pull/2138)\n- Fix `flex-basis` of `DownPanel` content div [#2126](https://github.com/storybookjs/storybook/pull/2126)\n- CLI: Use actions in sample stories for vue + fix them in SFC_VUE template [#1867](https://github.com/storybookjs/storybook/pull/1867)\n- Improve rendering of 'types' in addon-actions [#1887](https://github.com/storybookjs/storybook/pull/1887)\n- Circular json can possibly hang [#1881](https://github.com/storybookjs/storybook/pull/1881)\n- Use HtmlWebpackPlugin to import all assets (importing chunks in order) [#1775](https://github.com/storybookjs/storybook/pull/1775)\n- Fix preview scrolling [#1782](https://github.com/storybookjs/storybook/pull/1782)\n- Search box: make found options selectable with click [#1697](https://github.com/storybookjs/storybook/pull/1697)\n- Fix Docgen in static builds for Info [#1725](https://github.com/storybookjs/storybook/pull/1725)\n- Return empty array when Array knob is empty [#1811](https://github.com/storybookjs/storybook/pull/1811)\n- Import chunks/assets in correct order using HtmlWebpackPlugin [#1775](https://github.com/storybookjs/storybook/pull/1775)\n- Fix preview scrolling [#1782](https://github.com/storybookjs/storybook/pull/1782)\n- Height aligned 2 buttons in manager's header [#1769](https://github.com/storybookjs/storybook/pull/1769)\n- Search box: make found options selectable with click [#1697](https://github.com/storybookjs/storybook/pull/1697)\n- Info addon: Fix Docgen in static builds [#1725](https://github.com/storybookjs/storybook/pull/1725)\n- Knobs: allow arrays in object knob proptypes [#1701](https://github.com/storybookjs/storybook/pull/1701)\n\n#### Documentation\n\n- Make dependencies more deterministic [#1703](https://github.com/storybookjs/storybook/pull/1703)\n- Addon-info: deep merge passed styles with default ones [#2449](https://github.com/storybookjs/storybook/pull/2449)\n- Test documentation duplication fix [#2228](https://github.com/storybookjs/storybook/pull/2228)\n- Updated local test documentation [#2224](https://github.com/storybookjs/storybook/pull/2224)\n- Add state addon to the addons page [#2012](https://github.com/storybookjs/storybook/pull/2012)\n- Add community addon to add the ability to customize styles in the story preview area [#2007](https://github.com/storybookjs/storybook/pull/2007)\n- Add Figma addon to community supported section [#2009](https://github.com/storybookjs/storybook/pull/2009)\n- Update storybook-router description in the addon gallery. [#1991](https://github.com/storybookjs/storybook/pull/1991)\n- Make dependencies more deterministic [#1703](https://github.com/storybookjs/storybook/pull/1703)\n- Synced changes from new-docs to CONTRIBUTING.md [#1911](https://github.com/storybookjs/storybook/pull/1911)\n- Fix incorrect yarn command in docs [#1758](https://github.com/storybookjs/storybook/pull/1758)\n- Improve linkTo documentation [#1793](https://github.com/storybookjs/storybook/pull/1793)\n- Add carbon to examples page [#1764](https://github.com/storybookjs/storybook/pull/1764)\n- Minor grammar fixes and clarification to Vue documentation [#1756](https://github.com/storybookjs/storybook/pull/1756)\n- Fix incorrect yarn command in docs [#1758](https://github.com/storybookjs/storybook/pull/1758)\n- Add storybook-chrome-screenshot to addon gallery [#1761](https://github.com/storybookjs/storybook/pull/1761)\n- Fixing typo on VueJS withNotes Example [#1787](https://github.com/storybookjs/storybook/pull/1787)\n- Improve linkTo documentation [#1793](https://github.com/storybookjs/storybook/pull/1793)\n- Add carbon to examples page [#1764](https://github.com/storybookjs/storybook/pull/1764)\n- Minor grammar fixes and clarification to Vue documentation [#1756](https://github.com/storybookjs/storybook/pull/1756)\n- Fix incorrect yarn command in docs [#1758](https://github.com/storybookjs/storybook/pull/1758)\n- Add storybook-chrome-screenshot to addon gallery [#1761](https://github.com/storybookjs/storybook/pull/1761)\n- Fixing typo on VueJS withNotes Example [#1787](https://github.com/storybookjs/storybook/pull/1787)\n\n#### Maintenance\n\n- Switch to UglifyJS that supports ES6 and up [#2530](https://github.com/storybookjs/storybook/pull/2530)\n- Move everything from lodash to lodash-es [#2558](https://github.com/storybookjs/storybook/pull/2558)\n- Misc fixes [#2556](https://github.com/storybookjs/storybook/pull/2556)\n- CI: test that angular example works [#2557](https://github.com/storybookjs/storybook/pull/2557)\n- FIX `yarn test` & selecting only core [#2219](https://github.com/storybookjs/storybook/pull/2219)\n- CLI test: always remove `run` directory before exiting [#2201](https://github.com/storybookjs/storybook/pull/2201)\n- Bot for closing old issues [#2186](https://github.com/storybookjs/storybook/pull/2186)\n- Drop \"Install latest yarn version\" step on CI [#1910](https://github.com/storybookjs/storybook/pull/1910)\n- CLI: A more human-friendly message for undetected project types [#1825](https://github.com/storybookjs/storybook/pull/1825)\n- CLI: handle promise rejections [#1826](https://github.com/storybookjs/storybook/pull/1826)\n- Add tests for CLI [#1767](https://github.com/storybookjs/storybook/pull/1767)\n- Yarn workspaces [#1810](https://github.com/storybookjs/storybook/pull/1810)\n- Knobs: allow arrays in object knob proptypes [#1701](https://github.com/storybookjs/storybook/pull/1701)\n- Deprecate confusing option names [#1692](https://github.com/storybookjs/storybook/pull/1692)\n- A CLI for running specific tests suites, like bootstrap CLI [#1752](https://github.com/storybookjs/storybook/pull/1752)\n- Remove check for sender on channel. [#1407](https://github.com/storybookjs/storybook/pull/1407)\n- Exit with code 1 if `start-storybook --smoke-test` fails [#1851](https://github.com/storybookjs/storybook/pull/1851)\n- Refactor CLI [#1840](https://github.com/storybookjs/storybook/pull/1840)\n- Refactor knobs - no longer include all runtimes [#1832](https://github.com/storybookjs/storybook/pull/1832)\n- Added addon-knobs to crna and vanilla react native. [#1636](https://github.com/storybookjs/storybook/pull/1636)\n- Deprecate confusing option names [#1692](https://github.com/storybookjs/storybook/pull/1692)\n- A CLI for running specific tests suites, like bootstrap CLI [#1752](https://github.com/storybookjs/storybook/pull/1752)\n- Remove check for sender on channel. [#1407](https://github.com/storybookjs/storybook/pull/1407)\n- Use yarn instead of NPM [#1703](https://github.com/storybookjs/storybook/pull/1703)\n- Add config for dependencies.io [#1770](https://github.com/storybookjs/storybook/pull/1770)\n- Added addon-knobs to crna and vanilla react native. [#1636](https://github.com/storybookjs/storybook/pull/1636)\n- Fixed Jest warnings [#1744](https://github.com/storybookjs/storybook/pull/1744)\n- Smoke test master [#1801](https://github.com/storybookjs/storybook/pull/1801)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n57 Upgrades\n</summary>\n\n- Update babel-eslint in / from 8.1.1 to 8.1.2 [#2562](https://github.com/storybookjs/storybook/pull/2562)\n- Update babel-eslint in / from 8.1.0 to 8.1.1 [#2561](https://github.com/storybookjs/storybook/pull/2561)\n- Update babel-eslint in / from 8.0.3 to 8.1.0 [#2559](https://github.com/storybookjs/storybook/pull/2559)\n- Upgraded `eslint` in `/` from \"4.13.1\" to \"4.14.0\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `jest-specific-snapshot` in `addons/storyshots` from \"0.2.0\" to \"0.3.0\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `style-loader` in `app/angular` from \"0.17.0\" to \"0.18.2\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `npx` in `lib/cli` from \"9.6.0\" to \"9.7.1\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `@angular/cli` in `examples/angular-cli` from \"1.3.0\" to \"1.6.2\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `@types/jasmine` in `examples/angular-cli` from \"2.5.54\" to \"2.8.2\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `jasmine-core` in `examples/angular-cli` from \"2.6.4\" to \"2.8.0\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `jasmine-spec-reporter` in `examples/angular-cli` from \"4.1.1\" to \"4.2.1\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `karma-chrome-launcher` in `examples/angular-cli` from \"2.1.1\" to \"2.2.0\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `karma-coverage-istanbul-reporter` in `examples/angular-cli` from \"1.3.0\" to \"1.3.1\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `protractor` in `examples/angular-cli` from \"5.1.2\" to \"5.2.2\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `ts-node` in `examples/angular-cli` from \"3.2.2\" to \"3.3.0\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `tslint` in `examples/angular-cli` from \"5.3.2\" to \"5.8.0\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- UPGRADE jest & react-native [#2542](https://github.com/storybookjs/storybook/pull/2542)\n- Move back to original fuse.js package [#2478](https://github.com/storybookjs/storybook/pull/2478)\n- UPDATE \"react-split-pane\": \"^0.1.74\", to FIX an breaking issue [#2528](https://github.com/storybookjs/storybook/pull/2528)\n- Upgraded `gatsby-remark-copy-linked-files` in `/docs` from \"1.5.24\" to \"1.5.25\" [#2529](https://github.com/storybookjs/storybook/pull/2529)\n- Upgraded `gatsby` in `/docs` from \"1.9.144\" to \"1.9.146\" [#2529](https://github.com/storybookjs/storybook/pull/2529)\n- Update gatsby in /docs from 1.9.143 to 1.9.144 [#2524](https://github.com/storybookjs/storybook/pull/2524)\n- Update gatsby in /docs from 1.9.142 to 1.9.143 [#2521](https://github.com/storybookjs/storybook/pull/2521)\n- Upgraded `enzyme-adapter-react-16` in `/` from \"1.1.0\" to \"1.1.1\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n- Upgraded `jest-image-snapshot` in `/` from \"2.2.0\" to \"2.2.1\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n- Upgraded `axe-core` in `addons/a11y` from \"2.5.0\" to \"2.6.0\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n- Upgraded `moment` in `addons/knobs` from \"2.20.0\" to \"2.20.1\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n- Upgraded `vue` in `addons/knobs` from \"2.5.11\" to \"2.5.12\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n- Upgraded `vue` in `app/vue` from \"2.5.11\" to \"2.5.12\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n- Upgraded `vue-template-compiler` in `app/vue` from \"2.5.11\" to \"2.5.12\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n- Upgraded `moment` in `addons/comments` from \"2.20.0\" to \"2.20.1\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n- Upgraded `vue` in `examples/vue-kitchen-sink` from \"2.5.11\" to \"2.5.12\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n- Upgraded `vue-template-compiler` in `examples/vue-kitchen-sink` from \"2.5.11\" to \"2.5.12\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n- Upgraded `@storybook/addon-actions` in `/docs` from \"3.2.17\" to \"3.2.18\" [#2519](https://github.com/storybookjs/storybook/pull/2519)\n- Upgraded `@storybook/addon-links` in `/docs` from \"3.2.17\" to \"3.2.18\" [#2519](https://github.com/storybookjs/storybook/pull/2519)\n- Upgraded `@storybook/addons` in `/docs` from \"3.2.17\" to \"3.2.18\" [#2519](https://github.com/storybookjs/storybook/pull/2519)\n- Upgraded `@storybook/react` in `/docs` from \"3.2.17\" to \"3.2.18\" [#2519](https://github.com/storybookjs/storybook/pull/2519)\n- Upgraded `gatsby` in `/docs` from \"1.9.141\" to \"1.9.142\" [#2519](https://github.com/storybookjs/storybook/pull/2519)\n- Upgraded `nodemon` in `/` from \"1.13.2\" to \"1.13.3\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Upgraded `graphql` in `addons/graphql` from \"0.11.7\" to \"0.12.0\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Upgraded `@types/react` in `addons/knobs` from \"16.0.30\" to \"16.0.31\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Upgraded `file-loader` in `app/react-native` from \"1.1.5\" to \"1.1.6\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Upgraded `file-loader` in `app/react` from \"1.1.5\" to \"1.1.6\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Upgraded `nodemon` in `app/react` from \"1.13.2\" to \"1.13.3\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Upgraded `file-loader` in `app/vue` from \"1.1.5\" to \"1.1.6\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Upgraded `nodemon` in `app/vue` from \"1.13.2\" to \"1.13.3\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Upgraded `vue-loader` in `app/vue` from \"13.5.0\" to \"13.6.0\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Upgraded `file-loader` in `examples/vue-kitchen-sink` from \"1.1.5\" to \"1.1.6\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Upgraded `vue-loader` in `examples/vue-kitchen-sink` from \"13.5.0\" to \"13.6.0\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Update danger in / from 2.1.5 to 2.1.6 [#2511](https://github.com/storybookjs/storybook/pull/2511)\n- Update react-native from 0.43.4 to 0.49.3 in app/react-native [#1971](https://github.com/storybookjs/storybook/pull/1971)\n- React-Native - Docs - Add Issues section for Android Emulator [#2078](https://github.com/storybookjs/storybook/pull/2078)\n- Upgrade eslint-config-airbnb and make it pass [#2212](https://github.com/storybookjs/storybook/pull/2212)\n- Add config for dependencies.io [#1770](https://github.com/storybookjs/storybook/pull/1770)\n- Upgrade root dependencies and sync with packages [#1802](https://github.com/storybookjs/storybook/pull/1802)\n- Update jest to the latest version 🚀 [#1799](https://github.com/storybookjs/storybook/pull/1799)\n- Update eslint-plugin-jest to the latest version 🚀 [#1795](https://github.com/storybookjs/storybook/pull/1795)\n- Update lerna to the latest version 🚀 [#1768](https://github.com/storybookjs/storybook/pull/1768)\n\n</details>\n\n## 3.3.0-rc.1\n\n2017-December-26\n\n#### Bug Fixes\n\n- Fix whitespace on info add-on card [#2543](https://github.com/storybookjs/storybook/pull/2543)\n\n#### Documentation\n\n- Make dependencies more deterministic [#1703](https://github.com/storybookjs/storybook/pull/1703)\n\n#### Maintenance\n\n- Switch to UglifyJS that supports ES6 and up [#2530](https://github.com/storybookjs/storybook/pull/2530)\n- Move everything from lodash to lodash-es [#2558](https://github.com/storybookjs/storybook/pull/2558)\n- Misc fixes [#2556](https://github.com/storybookjs/storybook/pull/2556)\n- CI: test that angular example works [#2557](https://github.com/storybookjs/storybook/pull/2557)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n17 Upgrades\n</summary>\n\n- Update babel-eslint in / from 8.1.1 to 8.1.2 [#2562](https://github.com/storybookjs/storybook/pull/2562)\n- Update babel-eslint in / from 8.1.0 to 8.1.1 [#2561](https://github.com/storybookjs/storybook/pull/2561)\n- Update babel-eslint in / from 8.0.3 to 8.1.0 [#2559](https://github.com/storybookjs/storybook/pull/2559)\n- Upgraded `eslint` in `/` from \"4.13.1\" to \"4.14.0\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `jest-specific-snapshot` in `addons/storyshots` from \"0.2.0\" to \"0.3.0\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `style-loader` in `app/angular` from \"0.17.0\" to \"0.18.2\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `npx` in `lib/cli` from \"9.6.0\" to \"9.7.1\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `@angular/cli` in `examples/angular-cli` from \"1.3.0\" to \"1.6.2\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `@types/jasmine` in `examples/angular-cli` from \"2.5.54\" to \"2.8.2\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `jasmine-core` in `examples/angular-cli` from \"2.6.4\" to \"2.8.0\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `jasmine-spec-reporter` in `examples/angular-cli` from \"4.1.1\" to \"4.2.1\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `karma-chrome-launcher` in `examples/angular-cli` from \"2.1.1\" to \"2.2.0\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `karma-coverage-istanbul-reporter` in `examples/angular-cli` from \"1.3.0\" to \"1.3.1\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `protractor` in `examples/angular-cli` from \"5.1.2\" to \"5.2.2\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `ts-node` in `examples/angular-cli` from \"3.2.2\" to \"3.3.0\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n- Upgraded `tslint` in `examples/angular-cli` from \"5.3.2\" to \"5.8.0\" [#2555](https://github.com/storybookjs/storybook/pull/2555)\n\n</details>\n\n## 3.3.0-rc.0\n\n2017-December-23\n\n#### Bug Fixes\n\n- Angular component props assignment improvements [#2554](https://github.com/storybookjs/storybook/pull/2554)\n\n#### Dependency Upgrades\n\n- UPGRADE jest & react-native [#2542](https://github.com/storybookjs/storybook/pull/2542)\n\n## 3.3.0-alpha.6\n\n2017-December-23\n\n#### Features\n\n- Add support for importing markdown in storybook [#2299](https://github.com/storybookjs/storybook/pull/2299)\n- Add `TableComponent` option for addon-info [#2400](https://github.com/storybookjs/storybook/pull/2400)\n- Change keyboard shortcuts to platform safe [#1858](https://github.com/storybookjs/storybook/pull/1858)\n- Replace `console` with `client-logger` and `node-logger` packages [#2347](https://github.com/storybookjs/storybook/pull/2347)\n- Add renderer option to storyshots [#2414](https://github.com/storybookjs/storybook/pull/2414)\n\n#### Angular Support\n\n- Added type annotation to helpers, added ts declaration files for angu… [#2459](https://github.com/storybookjs/storybook/pull/2459)\n- Adding extra metadata to module/components [#2526](https://github.com/storybookjs/storybook/pull/2526)\n- Fix ng component prop output override [#2456](https://github.com/storybookjs/storybook/pull/2456)\n- `WIP` Angular versions support [#2467](https://github.com/storybookjs/storybook/pull/2467)\n- Angular Add custom pipes support [#2518](https://github.com/storybookjs/storybook/pull/2518)\n\n#### Bug Fixes\n\n- Remove redundant render in react [#2503](https://github.com/storybookjs/storybook/pull/2503)\n- Addon-actions: Fix types and refactor [#2438](https://github.com/storybookjs/storybook/pull/2438)\n- Fix warnings in search box [#2479](https://github.com/storybookjs/storybook/pull/2479)\n- Migrate to marksy@6 [#2464](https://github.com/storybookjs/storybook/pull/2464)\n- Extract Jest config from package.json to config file [#2424](https://github.com/storybookjs/storybook/pull/2424)\n- Fix Horizontal Scrollbar of DownPanel [#2410](https://github.com/storybookjs/storybook/pull/2410)\n- Move `@storybook/addons` to peerDependencies in all addons [#2335](https://github.com/storybookjs/storybook/pull/2335)\n- Fix compatibility with @babel/core v7 [#2494](https://github.com/storybookjs/storybook/pull/2494)\n- Unmount after storyshot snapshot [#2417](https://github.com/storybookjs/storybook/pull/2417)\n\n#### Documentation\n\n- Addon-info: deep merge passed styles with default ones [#2449](https://github.com/storybookjs/storybook/pull/2449)\n- Test documentation duplication fix [#2228](https://github.com/storybookjs/storybook/pull/2228)\n\n#### Maintenance\n\n- Netlify for angularexample [#2533](https://github.com/storybookjs/storybook/pull/2533)\n- Netlify for officialexample [#2532](https://github.com/storybookjs/storybook/pull/2532)\n- Add a storybook for the ui package [#2504](https://github.com/storybookjs/storybook/pull/2504)\n- FIX the failing netlify builds [#2527](https://github.com/storybookjs/storybook/pull/2527)\n- fix tests not actually running [#2450](https://github.com/storybookjs/storybook/pull/2450)\n- Add method to channel that ignores event from self [#1879](https://github.com/storybookjs/storybook/pull/1879)\n- Fix broken CI build [#2255](https://github.com/storybookjs/storybook/pull/2255)\n- Fix unittest warnings r3.3 [#2381](https://github.com/storybookjs/storybook/pull/2381)\n- Move addon events into its own story file [#2502](https://github.com/storybookjs/storybook/pull/2502)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n33 Upgrades\n</summary>\n\n- Move back to original fuse.js package [#2478](https://github.com/storybookjs/storybook/pull/2478)\n- UPDATE \"react-split-pane\": \"^0.1.74\", to FIX an breaking issue [#2528](https://github.com/storybookjs/storybook/pull/2528)\n- Upgraded `gatsby-remark-copy-linked-files` in `/docs` from \"1.5.24\" to \"1.5.25\" [#2529](https://github.com/storybookjs/storybook/pull/2529)\n- Upgraded `gatsby` in `/docs` from \"1.9.144\" to \"1.9.146\" [#2529](https://github.com/storybookjs/storybook/pull/2529)\n- Update gatsby in /docs from 1.9.143 to 1.9.144 [#2524](https://github.com/storybookjs/storybook/pull/2524)\n- Update gatsby in /docs from 1.9.142 to 1.9.143 [#2521](https://github.com/storybookjs/storybook/pull/2521)\n- Upgraded `enzyme-adapter-react-16` in `/` from \"1.1.0\" to \"1.1.1\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n- Upgraded `jest-image-snapshot` in `/` from \"2.2.0\" to \"2.2.1\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n- Upgraded `axe-core` in `addons/a11y` from \"2.5.0\" to \"2.6.0\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n- Upgraded `moment` in `addons/knobs` from \"2.20.0\" to \"2.20.1\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n- Upgraded `vue` in `addons/knobs` from \"2.5.11\" to \"2.5.12\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n- Upgraded `vue` in `app/vue` from \"2.5.11\" to \"2.5.12\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n- Upgraded `vue-template-compiler` in `app/vue` from \"2.5.11\" to \"2.5.12\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n- Upgraded `moment` in `addons/comments` from \"2.20.0\" to \"2.20.1\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n- Upgraded `vue` in `examples/vue-kitchen-sink` from \"2.5.11\" to \"2.5.12\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n- Upgraded `vue-template-compiler` in `examples/vue-kitchen-sink` from \"2.5.11\" to \"2.5.12\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n- Upgraded `@storybook/addon-actions` in `/docs` from \"3.2.17\" to \"3.2.18\" [#2519](https://github.com/storybookjs/storybook/pull/2519)\n- Upgraded `@storybook/addon-links` in `/docs` from \"3.2.17\" to \"3.2.18\" [#2519](https://github.com/storybookjs/storybook/pull/2519)\n- Upgraded `@storybook/addons` in `/docs` from \"3.2.17\" to \"3.2.18\" [#2519](https://github.com/storybookjs/storybook/pull/2519)\n- Upgraded `@storybook/react` in `/docs` from \"3.2.17\" to \"3.2.18\" [#2519](https://github.com/storybookjs/storybook/pull/2519)\n- Upgraded `gatsby` in `/docs` from \"1.9.141\" to \"1.9.142\" [#2519](https://github.com/storybookjs/storybook/pull/2519)\n- Upgraded `nodemon` in `/` from \"1.13.2\" to \"1.13.3\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Upgraded `graphql` in `addons/graphql` from \"0.11.7\" to \"0.12.0\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Upgraded `@types/react` in `addons/knobs` from \"16.0.30\" to \"16.0.31\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Upgraded `file-loader` in `app/react-native` from \"1.1.5\" to \"1.1.6\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Upgraded `file-loader` in `app/react` from \"1.1.5\" to \"1.1.6\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Upgraded `nodemon` in `app/react` from \"1.13.2\" to \"1.13.3\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Upgraded `file-loader` in `app/vue` from \"1.1.5\" to \"1.1.6\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Upgraded `nodemon` in `app/vue` from \"1.13.2\" to \"1.13.3\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Upgraded `vue-loader` in `app/vue` from \"13.5.0\" to \"13.6.0\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Upgraded `file-loader` in `examples/vue-kitchen-sink` from \"1.1.5\" to \"1.1.6\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Upgraded `vue-loader` in `examples/vue-kitchen-sink` from \"13.5.0\" to \"13.6.0\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n- Update danger in / from 2.1.5 to 2.1.6 [#2511](https://github.com/storybookjs/storybook/pull/2511)\n\n</details>\n\n## 3.3.0-alpha.4\n\n2017-November-22\n\n#### Bug Fixes\n\n- Fix HMR by saving the preview frame URL as the story changes [#2349](https://github.com/storybookjs/storybook/pull/2349)\n- Fix CLI babel transpilation [#2350](https://github.com/storybookjs/storybook/pull/2350)\n\n## 3.3.0-alpha.3\n\n2017-November-07\n\n#### Features\n\n- Add angular support: Storybook for Angular [#1474](https://github.com/storybookjs/storybook/pull/1474)\n- Fix addon Knobs: add array in Object PropTypes [#2227](https://github.com/storybookjs/storybook/pull/2227)\n- Adds error when storyshots finds no stories [#2079](https://github.com/storybookjs/storybook/pull/2079)\n- Add addon background to monorepo [#2220](https://github.com/storybookjs/storybook/pull/2220)\n- Add ability to parse line breaks into <br/> for Docgen descriptions [#2053](https://github.com/storybookjs/storybook/pull/2053)\n\n#### Bug Fixes\n\n- Move LinkTo component to a separate `addon-links/react` endpoint [#2239](https://github.com/storybookjs/storybook/pull/2239)\n- Fix Array Knob deserialization [#2217](https://github.com/storybookjs/storybook/pull/2217)\n- Return the test in storyshots to respect promises. [#2218](https://github.com/storybookjs/storybook/pull/2218)\n- Knobs refactor accidentally removed select [#2210](https://github.com/storybookjs/storybook/pull/2210)\n- Add HMR to other RN app templates [#2213](https://github.com/storybookjs/storybook/pull/2213)\n- Autoload all `*.stories.js` files in cli templates [#2195](https://github.com/storybookjs/storybook/pull/2195)\n- Fix info upgrade codemod failing when optional description string is not supplied [#2138](https://github.com/storybookjs/storybook/pull/2138)\n- Fix `flex-basis` of `DownPanel` content div [#2126](https://github.com/storybookjs/storybook/pull/2126)\n\n#### Documentation\n\n- Updated local test documentation [#2224](https://github.com/storybookjs/storybook/pull/2224)\n- Add state addon to the addons page [#2012](https://github.com/storybookjs/storybook/pull/2012)\n- Add community addon to add the ability to customize styles in the story preview area [#2007](https://github.com/storybookjs/storybook/pull/2007)\n- Add Figma addon to community supported section [#2009](https://github.com/storybookjs/storybook/pull/2009)\n- Update storybook-router description in the addon gallery. [#1991](https://github.com/storybookjs/storybook/pull/1991)\n\n#### Maintenance\n\n- FIX `yarn test` & selecting only core [#2219](https://github.com/storybookjs/storybook/pull/2219)\n- CLI test: always remove `run` directory before exiting [#2201](https://github.com/storybookjs/storybook/pull/2201)\n- Bot for closing old issues [#2186](https://github.com/storybookjs/storybook/pull/2186)\n\n#### Dependency Upgrades\n\n- Update react-native from 0.43.4 to 0.49.3 in app/react-native [#1971](https://github.com/storybookjs/storybook/pull/1971)\n- React-Native - Docs - Add Issues section for Android Emulator [#2078](https://github.com/storybookjs/storybook/pull/2078)\n- Upgrade eslint-config-airbnb and make it pass [#2212](https://github.com/storybookjs/storybook/pull/2212)\n\n## 3.3.0-alpha.2\n\n2017-October-03\n\n#### Features\n\n- Ability for custom storyshots testFunctions to utilise \"snapshot per story file\" [#1841](https://github.com/storybookjs/storybook/pull/1841)\n- Viewport Addon [#1753](https://github.com/storybookjs/storybook/pull/1753)\n- More detailed props table [#1485](https://github.com/storybookjs/storybook/pull/1485)\n- RN: Add accessibility labels to OnDeviceUI [#1780](https://github.com/storybookjs/storybook/pull/1780)\n- Have Stories on each level of hierarchy [#1763](https://github.com/storybookjs/storybook/pull/1763)\n- Viewport Addon [#1740](https://github.com/storybookjs/storybook/pull/1740)\n- Generate snapshot per story file [#1584](https://github.com/storybookjs/storybook/pull/1584)\n- addon-links: add `LinkTo` component, and `hrefTo` function [#1829](https://github.com/storybookjs/storybook/pull/1829)\n\n#### Bug Fixes\n\n- CLI: Use actions in sample stories for vue + fix them in SFC_VUE template [#1867](https://github.com/storybookjs/storybook/pull/1867)\n- Improve rendering of 'types' in addon-actions [#1887](https://github.com/storybookjs/storybook/pull/1887)\n- Circular json can possibly hang [#1881](https://github.com/storybookjs/storybook/pull/1881)\n- Use HtmlWebpackPlugin to import all assets (importing chunks in order) [#1775](https://github.com/storybookjs/storybook/pull/1775)\n- Fix preview scrolling [#1782](https://github.com/storybookjs/storybook/pull/1782)\n- Search box: make found options selectable with click [#1697](https://github.com/storybookjs/storybook/pull/1697)\n- Fix Docgen in static builds for Info [#1725](https://github.com/storybookjs/storybook/pull/1725)\n- Return empty array when Array knob is empty [#1811](https://github.com/storybookjs/storybook/pull/1811)\n\n#### Documentation\n\n- Make dependencies more deterministic [#1703](https://github.com/storybookjs/storybook/pull/1703)\n- Synced changes from new-docs to CONTRIBUTING.md [#1911](https://github.com/storybookjs/storybook/pull/1911)\n- Fix incorrect yarn command in docs [#1758](https://github.com/storybookjs/storybook/pull/1758)\n\n#### Maintenance\n\n- Drop \"Install latest yarn version\" step on CI [#1910](https://github.com/storybookjs/storybook/pull/1910)\n- CLI: A more human-friendly message for undetected project types [#1825](https://github.com/storybookjs/storybook/pull/1825)\n- CLI: handle promise rejections [#1826](https://github.com/storybookjs/storybook/pull/1826)\n- Add tests for CLI [#1767](https://github.com/storybookjs/storybook/pull/1767)\n- Yarn workspaces [#1810](https://github.com/storybookjs/storybook/pull/1810)\n- Knobs: allow arrays in object knob proptypes [#1701](https://github.com/storybookjs/storybook/pull/1701)\n- Deprecate confusing option names [#1692](https://github.com/storybookjs/storybook/pull/1692)\n- A CLI for running specific tests suites, like bootstrap CLI [#1752](https://github.com/storybookjs/storybook/pull/1752)\n- Remove check for sender on channel. [#1407](https://github.com/storybookjs/storybook/pull/1407)\n- Exit with code 1 if `start-storybook --smoke-test` fails [#1851](https://github.com/storybookjs/storybook/pull/1851)\n- Refactor CLI [#1840](https://github.com/storybookjs/storybook/pull/1840)\n- Refactor knobs - no longer include all runtimes [#1832](https://github.com/storybookjs/storybook/pull/1832)\n- Added addon-knobs to crna and vanilla react native. [#1636](https://github.com/storybookjs/storybook/pull/1636)\n\n#### Dependency Upgrades\n\n- Add config for dependencies.io [#1770](https://github.com/storybookjs/storybook/pull/1770)\n\n## 3.3.0-alpha.0\n\n2017-September-06\n\n#### Features\n\n- Viewport addon: simulate device sizes in preview window [#1753](https://github.com/storybookjs/storybook/pull/1753)\n- CLI: Add codemod for deprecated addon-links and addon-actions from app [#1368](https://github.com/storybookjs/storybook/pull/1368)\n- Info addon: More detailed props table [#1485](https://github.com/storybookjs/storybook/pull/1485)\n- React native: Add accessibility labels to OnDeviceUI [#1780](https://github.com/storybookjs/storybook/pull/1780)\n- Stories panel: Stories on each hierarchy level [#1763](https://github.com/storybookjs/storybook/pull/1763)\n- Storyshots: Generate snapshot per story file [#1584](https://github.com/storybookjs/storybook/pull/1584)\n- CLI: Add support for Vue projects using Nuxt [#1794](https://github.com/storybookjs/storybook/pull/1794)\n\n#### Bug Fixes\n\n- Import chunks/assets in correct order using HtmlWebpackPlugin [#1775](https://github.com/storybookjs/storybook/pull/1775)\n- Fix preview scrolling [#1782](https://github.com/storybookjs/storybook/pull/1782)\n- Height aligned 2 buttons in manager's header [#1769](https://github.com/storybookjs/storybook/pull/1769)\n- Search box: make found options selectable with click [#1697](https://github.com/storybookjs/storybook/pull/1697)\n- Info addon: Fix Docgen in static builds [#1725](https://github.com/storybookjs/storybook/pull/1725)\n- Knobs: allow arrays in object knob proptypes [#1701](https://github.com/storybookjs/storybook/pull/1701)\n\n#### Documentation\n\n- Improve linkTo documentation [#1793](https://github.com/storybookjs/storybook/pull/1793)\n- Add carbon to examples page [#1764](https://github.com/storybookjs/storybook/pull/1764)\n- Minor grammar fixes and clarification to Vue documentation [#1756](https://github.com/storybookjs/storybook/pull/1756)\n- Fix incorrect yarn command in docs [#1758](https://github.com/storybookjs/storybook/pull/1758)\n- Add storybook-chrome-screenshot to addon gallery [#1761](https://github.com/storybookjs/storybook/pull/1761)\n- Fixing typo on VueJS withNotes Example [#1787](https://github.com/storybookjs/storybook/pull/1787)\n\n#### Maintenance\n\n- Deprecate confusing option names [#1692](https://github.com/storybookjs/storybook/pull/1692)\n- A CLI for running specific tests suites, like bootstrap CLI [#1752](https://github.com/storybookjs/storybook/pull/1752)\n- Remove check for sender on channel. [#1407](https://github.com/storybookjs/storybook/pull/1407)\n- Use yarn instead of NPM [#1703](https://github.com/storybookjs/storybook/pull/1703)\n- Add config for dependencies.io [#1770](https://github.com/storybookjs/storybook/pull/1770)\n- Added addon-knobs to crna and vanilla react native. [#1636](https://github.com/storybookjs/storybook/pull/1636)\n- Fixed Jest warnings [#1744](https://github.com/storybookjs/storybook/pull/1744)\n- Smoke test master [#1801](https://github.com/storybookjs/storybook/pull/1801)\n\n#### Dependency Upgrades\n\n- Upgrade root dependencies and sync with packages [#1802](https://github.com/storybookjs/storybook/pull/1802)\n- Update jest to the latest version 🚀 [#1799](https://github.com/storybookjs/storybook/pull/1799)\n- Update eslint-plugin-jest to the latest version 🚀 [#1795](https://github.com/storybookjs/storybook/pull/1795)\n- Update lerna to the latest version 🚀 [#1768](https://github.com/storybookjs/storybook/pull/1768)\n\n## 3.2.19\n\n2017-December-23\n\n#### Bug Fixes\n\n- fix compatibility with @babel/core v7 [#2494](https://github.com/storybookjs/storybook/pull/2494)\n\n#### Maintenance\n\n- FIX the failing netlify builds [#2527](https://github.com/storybookjs/storybook/pull/2527)\n\n#### Documentation\n\n- UPDATE readme with new slackin link [#2536](https://github.com/storybookjs/storybook/pull/2536)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n55 Updates\n</summary>\n-   UPDATE \"react-split-pane\": \"^0.1.74\", to FIX an breaking issue [#2528](https://github.com/storybookjs/storybook/pull/2528)\n-   Upgraded `cross-env` in `/` from \"5.1.1\" to \"5.1.3\" [#2540](https://github.com/storybookjs/storybook/pull/2540)\n-   Upgraded `nodemon` in `/` from \"1.13.3\" to \"1.14.3\" [#2540](https://github.com/storybookjs/storybook/pull/2540)\n-   Upgraded `glamorous` in `lib/components` from \"4.11.0\" to \"4.11.2\" [#2540](https://github.com/storybookjs/storybook/pull/2540)\n-   Upgraded `glamorous` in `addons/jest` from \"4.11.0\" to \"4.11.2\" [#2540](https://github.com/storybookjs/storybook/pull/2540)\n-   Upgraded `@types/node` in `addons/knobs` from \"8.5.1\" to \"8.5.2\" [#2540](https://github.com/storybookjs/storybook/pull/2540)\n-   Upgraded `vue` in `addons/knobs` from \"2.5.12\" to \"2.5.13\" [#2540](https://github.com/storybookjs/storybook/pull/2540)\n-   Upgraded `common-tags` in `app/react` from \"1.5.1\" to \"1.6.0\" [#2540](https://github.com/storybookjs/storybook/pull/2540)\n-   Upgraded `glamorous` in `app/react` from \"4.11.0\" to \"4.11.2\" [#2540](https://github.com/storybookjs/storybook/pull/2540)\n-   Upgraded `nodemon` in `app/react` from \"1.13.3\" to \"1.14.3\" [#2540](https://github.com/storybookjs/storybook/pull/2540)\n-   Upgraded `common-tags` in `app/vue` from \"1.5.1\" to \"1.6.0\" [#2540](https://github.com/storybookjs/storybook/pull/2540)\n-   Upgraded `nodemon` in `app/vue` from \"1.13.3\" to \"1.14.3\" [#2540](https://github.com/storybookjs/storybook/pull/2540)\n-   Upgraded `vue` in `app/vue` from \"2.5.12\" to \"2.5.13\" [#2540](https://github.com/storybookjs/storybook/pull/2540)\n-   Upgraded `vue-loader` in `app/vue` from \"13.6.0\" to \"13.6.1\" [#2540](https://github.com/storybookjs/storybook/pull/2540)\n-   Upgraded `vue-template-compiler` in `app/vue` from \"2.5.12\" to \"2.5.13\" [#2540](https://github.com/storybookjs/storybook/pull/2540)\n-   Upgraded `vue` in `examples/vue-kitchen-sink` from \"2.5.12\" to \"2.5.13\" [#2540](https://github.com/storybookjs/storybook/pull/2540)\n-   Upgraded `cross-env` in `examples/vue-kitchen-sink` from \"5.1.1\" to \"5.1.3\" [#2540](https://github.com/storybookjs/storybook/pull/2540)\n-   Upgraded `vue-loader` in `examples/vue-kitchen-sink` from \"13.6.0\" to \"13.6.1\" [#2540](https://github.com/storybookjs/storybook/pull/2540)\n-   Upgraded `vue-template-compiler` in `examples/vue-kitchen-sink` from \"2.5.12\" to \"2.5.13\" [#2540](https://github.com/storybookjs/storybook/pull/2540)\n-   Upgraded `glamorous` in `examples/cra-kitchen-sink` from \"4.11.0\" to \"4.11.2\" [#2540](https://github.com/storybookjs/storybook/pull/2540)\n-   Upgraded `gatsby-remark-autolink-headers` in `/docs` from \"1.4.10\" to \"1.4.11\" [#2541](https://github.com/storybookjs/storybook/pull/2541)\n-   Upgraded `gatsby-transformer-remark` in `/docs` from \"1.7.25\" to \"1.7.26\" [#2541](https://github.com/storybookjs/storybook/pull/2541)\n-   Upgraded `gatsby` in `/docs` from \"1.9.148\" to \"1.9.149\" [#2541](https://github.com/storybookjs/storybook/pull/2541)\n-   Update gatsby in /docs from 1.9.146 to 1.9.147 [#2535](https://github.com/storybookjs/storybook/pull/2535)\n-   Upgraded `gatsby-remark-copy-linked-files` in `/docs` from \"1.5.24\" to \"1.5.25\" [#2529](https://github.com/storybookjs/storybook/pull/2529)\n-   Upgraded `gatsby` in `/docs` from \"1.9.144\" to \"1.9.146\" [#2529](https://github.com/storybookjs/storybook/pull/2529)\n-   Update gatsby in /docs from 1.9.143 to 1.9.144 [#2524](https://github.com/storybookjs/storybook/pull/2524)\n-   Update gatsby in /docs from 1.9.142 to 1.9.143 [#2521](https://github.com/storybookjs/storybook/pull/2521)\n-   Upgraded `enzyme-adapter-react-16` in `/` from \"1.1.0\" to \"1.1.1\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n-   Upgraded `jest-image-snapshot` in `/` from \"2.2.0\" to \"2.2.1\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n-   Upgraded `axe-core` in `addons/a11y` from \"2.5.0\" to \"2.6.0\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n-   Upgraded `moment` in `addons/knobs` from \"2.20.0\" to \"2.20.1\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n-   Upgraded `vue` in `addons/knobs` from \"2.5.11\" to \"2.5.12\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n-   Upgraded `vue` in `app/vue` from \"2.5.11\" to \"2.5.12\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n-   Upgraded `vue-template-compiler` in `app/vue` from \"2.5.11\" to \"2.5.12\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n-   Upgraded `moment` in `addons/comments` from \"2.20.0\" to \"2.20.1\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n-   Upgraded `vue` in `examples/vue-kitchen-sink` from \"2.5.11\" to \"2.5.12\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n-   Upgraded `vue-template-compiler` in `examples/vue-kitchen-sink` from \"2.5.11\" to \"2.5.12\" [#2520](https://github.com/storybookjs/storybook/pull/2520)\n-   Upgraded `@storybook/addon-actions` in `/docs` from \"3.2.17\" to \"3.2.18\" [#2519](https://github.com/storybookjs/storybook/pull/2519)\n-   Upgraded `@storybook/addon-links` in `/docs` from \"3.2.17\" to \"3.2.18\" [#2519](https://github.com/storybookjs/storybook/pull/2519)\n-   Upgraded `@storybook/addons` in `/docs` from \"3.2.17\" to \"3.2.18\" [#2519](https://github.com/storybookjs/storybook/pull/2519)\n-   Upgraded `@storybook/react` in `/docs` from \"3.2.17\" to \"3.2.18\" [#2519](https://github.com/storybookjs/storybook/pull/2519)\n-   Upgraded `gatsby` in `/docs` from \"1.9.141\" to \"1.9.142\" [#2519](https://github.com/storybookjs/storybook/pull/2519)\n-   Upgraded `nodemon` in `/` from \"1.13.2\" to \"1.13.3\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n-   Upgraded `graphql` in `addons/graphql` from \"0.11.7\" to \"0.12.0\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n-   Upgraded `@types/react` in `addons/knobs` from \"16.0.30\" to \"16.0.31\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n-   Upgraded `file-loader` in `app/react-native` from \"1.1.5\" to \"1.1.6\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n-   Upgraded `file-loader` in `app/react` from \"1.1.5\" to \"1.1.6\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n-   Upgraded `nodemon` in `app/react` from \"1.13.2\" to \"1.13.3\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n-   Upgraded `file-loader` in `app/vue` from \"1.1.5\" to \"1.1.6\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n-   Upgraded `nodemon` in `app/vue` from \"1.13.2\" to \"1.13.3\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n-   Upgraded `vue-loader` in `app/vue` from \"13.5.0\" to \"13.6.0\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n-   Upgraded `file-loader` in `examples/vue-kitchen-sink` from \"1.1.5\" to \"1.1.6\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n-   Upgraded `vue-loader` in `examples/vue-kitchen-sink` from \"13.5.0\" to \"13.6.0\" [#2498](https://github.com/storybookjs/storybook/pull/2498)\n-   Update danger in / from 2.1.5 to 2.1.6 [#2511](https://github.com/storybookjs/storybook/pull/2511)\n\n</details>\n\n## 3.2.18\n\n2017-December-18\n\n#### Bug Fixes\n\n- Number knob: apply default min/max/step values only in range mode [#2437](https://github.com/storybookjs/storybook/pull/2437)\n- `addon-actions` Check result of getPropertyDescriptor for IE11 [#2428](https://github.com/storybookjs/storybook/pull/2428)\n- Edited template of search box result item to fix overflow text in row [#2419](https://github.com/storybookjs/storybook/pull/2419)\n- Fix missing supported extension check in case when asset is a string [#2468](https://github.com/storybookjs/storybook/pull/2468)\n\n#### Documentation\n\n- Fix react-native-vanilla to actually run storybook and document how to run it [#2274](https://github.com/storybookjs/storybook/pull/2274)\n- Add another state addon to the gallery [#2391](https://github.com/storybookjs/storybook/pull/2391)\n- Create ISSUE_TEMPLATE.md [#2426](https://github.com/storybookjs/storybook/pull/2426)\n- fix Button dependency & typo in composant name in documentation [#2465](https://github.com/storybookjs/storybook/pull/2465)\n- add vue storybook boilerplate [#2421](https://github.com/storybookjs/storybook/pull/2421)\n- fix: update links to webpack docs [#2512](https://github.com/storybookjs/storybook/pull/2512)\n\n#### Maintenance\n\n- Do not remove debugger-statements during development [#2493](https://github.com/storybookjs/storybook/pull/2493)\n- FIX react-native-test in CI [#2444](https://github.com/storybookjs/storybook/pull/2444)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n139 Updates\n</summary>\n\n- Update gatsby in /docs from 1.9.139 to 1.9.141 [#2510](https://github.com/storybookjs/storybook/pull/2510)\n- Update gatsby in /docs from 1.9.138 to 1.9.139 [#2499](https://github.com/storybookjs/storybook/pull/2499)\n- Upgraded `eslint-plugin-prettier` in `/` from \"2.3.1\" to \"2.4.0\" [#2500](https://github.com/storybookjs/storybook/pull/2500)\n- Upgraded `graphql` in `addons/graphql` from \"0.11.7\" to \"0.12.3\" [#2500](https://github.com/storybookjs/storybook/pull/2500)\n- Upgraded `moment` in `addons/knobs` from \"2.19.4\" to \"2.20.0\" [#2500](https://github.com/storybookjs/storybook/pull/2500)\n- Upgraded `ws` in `app/react-native` from \"3.3.2\" to \"3.3.3\" [#2500](https://github.com/storybookjs/storybook/pull/2500)\n- Upgraded `moment` in `addons/comments` from \"2.19.4\" to \"2.20.0\" [#2500](https://github.com/storybookjs/storybook/pull/2500)\n- Update gatsby in /docs from 1.9.135 to 1.9.138 [#2497](https://github.com/storybookjs/storybook/pull/2497)\n- Upgraded `eslint-plugin-jest` in `/` from \"21.4.3\" to \"21.5.0\" [#2496](https://github.com/storybookjs/storybook/pull/2496)\n- Upgraded `nodemon` in `/` from \"1.12.7\" to \"1.13.2\" [#2496](https://github.com/storybookjs/storybook/pull/2496)\n- Upgraded `nodemon` in `app/react` from \"1.12.7\" to \"1.13.2\" [#2496](https://github.com/storybookjs/storybook/pull/2496)\n- Upgraded `nodemon` in `app/vue` from \"1.12.7\" to \"1.13.2\" [#2496](https://github.com/storybookjs/storybook/pull/2496)\n- Update gatsby-remark-copy-linked-files in /docs from 1.5.23 to 1.5.24 [#2495](https://github.com/storybookjs/storybook/pull/2495)\n- Update gatsby in /docs from 1.9.134 to 1.9.135 [#2491](https://github.com/storybookjs/storybook/pull/2491)\n- Update danger in / from 2.1.4 to 2.1.5 [#2489](https://github.com/storybookjs/storybook/pull/2489)\n- Upgraded `gatsby-plugin-sharp` in `/docs` from \"1.6.23\" to \"1.6.24\" [#2490](https://github.com/storybookjs/storybook/pull/2490)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.35\" to \"1.5.36\" [#2490](https://github.com/storybookjs/storybook/pull/2490)\n- Upgraded `eslint-plugin-jest` in `/` from \"21.4.2\" to \"21.4.3\" [#2488](https://github.com/storybookjs/storybook/pull/2488)\n- Upgraded `nodemon` in `/` from \"1.12.6\" to \"1.12.7\" [#2488](https://github.com/storybookjs/storybook/pull/2488)\n- Upgraded `symlink-dir` in `/` from \"1.1.0\" to \"1.1.1\" [#2488](https://github.com/storybookjs/storybook/pull/2488)\n- Upgraded `@types/node` in `addons/knobs` from \"8.0.58\" to \"8.5.1\" [#2488](https://github.com/storybookjs/storybook/pull/2488)\n- Upgraded `@types/react` in `addons/knobs` from \"16.0.29\" to \"16.0.30\" [#2488](https://github.com/storybookjs/storybook/pull/2488)\n- Upgraded `style-loader` in `addons/knobs` from \"0.19.0\" to \"0.19.1\" [#2488](https://github.com/storybookjs/storybook/pull/2488)\n- Upgraded `vue` in `addons/knobs` from \"2.5.10\" to \"2.5.11\" [#2488](https://github.com/storybookjs/storybook/pull/2488)\n- Upgraded `autoprefixer` in `app/react-native` from \"7.2.2\" to \"7.2.3\" [#2488](https://github.com/storybookjs/storybook/pull/2488)\n- Upgraded `style-loader` in `app/react-native` from \"0.18.2\" to \"0.19.1\" [#2488](https://github.com/storybookjs/storybook/pull/2488)\n- Upgraded `autoprefixer` in `app/react` from \"7.2.2\" to \"7.2.3\" [#2488](https://github.com/storybookjs/storybook/pull/2488)\n- Upgraded `style-loader` in `app/react` from \"0.18.2\" to \"0.19.1\" [#2488](https://github.com/storybookjs/storybook/pull/2488)\n- Upgraded `nodemon` in `app/react` from \"1.12.6\" to \"1.12.7\" [#2488](https://github.com/storybookjs/storybook/pull/2488)\n- Upgraded `autoprefixer` in `app/vue` from \"7.2.2\" to \"7.2.3\" [#2488](https://github.com/storybookjs/storybook/pull/2488)\n- Upgraded `style-loader` in `app/vue` from \"0.18.2\" to \"0.19.1\" [#2488](https://github.com/storybookjs/storybook/pull/2488)\n- Upgraded `nodemon` in `app/vue` from \"1.12.6\" to \"1.12.7\" [#2488](https://github.com/storybookjs/storybook/pull/2488)\n- Upgraded `vue` in `app/vue` from \"2.5.10\" to \"2.5.11\" [#2488](https://github.com/storybookjs/storybook/pull/2488)\n- Upgraded `vue-template-compiler` in `app/vue` from \"2.5.10\" to \"2.5.11\" [#2488](https://github.com/storybookjs/storybook/pull/2488)\n- Upgraded `vue` in `examples/vue-kitchen-sink` from \"2.5.10\" to \"2.5.11\" [#2488](https://github.com/storybookjs/storybook/pull/2488)\n- Upgraded `vue-template-compiler` in `examples/vue-kitchen-sink` from \"2.5.10\" to \"2.5.11\" [#2488](https://github.com/storybookjs/storybook/pull/2488)\n- Upgraded `gatsby-link` in `/docs` from \"1.6.31\" to \"1.6.32\" [#2486](https://github.com/storybookjs/storybook/pull/2486)\n- Upgraded `gatsby-transformer-remark` in `/docs` from \"1.7.24\" to \"1.7.25\" [#2486](https://github.com/storybookjs/storybook/pull/2486)\n- Upgraded `gatsby` in `/docs` from \"1.9.131\" to \"1.9.134\" [#2486](https://github.com/storybookjs/storybook/pull/2486)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.34\" to \"1.5.35\" [#2476](https://github.com/storybookjs/storybook/pull/2476)\n- Upgraded `gatsby-source-filesystem` in `/docs` from \"1.5.10\" to \"1.5.11\" [#2476](https://github.com/storybookjs/storybook/pull/2476)\n- Upgraded `gatsby` in `/docs` from \"1.9.130\" to \"1.9.131\" [#2476](https://github.com/storybookjs/storybook/pull/2476)\n- Upgraded `eslint-plugin-jsx-a11y` in `/` from \"6.0.2\" to \"6.0.3\" [#2477](https://github.com/storybookjs/storybook/pull/2477)\n- Upgraded `nodemon` in `/` from \"1.12.5\" to \"1.12.6\" [#2477](https://github.com/storybookjs/storybook/pull/2477)\n- Upgraded `vue` in `addons/knobs` from \"2.5.9\" to \"2.5.10\" [#2477](https://github.com/storybookjs/storybook/pull/2477)\n- Upgraded `react-modal` in `lib/ui` from \"3.1.7\" to \"3.1.8\" [#2477](https://github.com/storybookjs/storybook/pull/2477)\n- Upgraded `nodemon` in `app/react` from \"1.12.5\" to \"1.12.6\" [#2477](https://github.com/storybookjs/storybook/pull/2477)\n- Upgraded `nodemon` in `app/vue` from \"1.12.5\" to \"1.12.6\" [#2477](https://github.com/storybookjs/storybook/pull/2477)\n- Upgraded `vue` in `app/vue` from \"2.5.9\" to \"2.5.10\" [#2477](https://github.com/storybookjs/storybook/pull/2477)\n- Upgraded `vue-template-compiler` in `app/vue` from \"2.5.9\" to \"2.5.10\" [#2477](https://github.com/storybookjs/storybook/pull/2477)\n- Upgraded `vue` in `examples/vue-kitchen-sink` from \"2.5.9\" to \"2.5.10\" [#2477](https://github.com/storybookjs/storybook/pull/2477)\n- Upgraded `vue-template-compiler` in `examples/vue-kitchen-sink` from \"2.5.9\" to \"2.5.10\" [#2477](https://github.com/storybookjs/storybook/pull/2477)\n- Upgraded `danger` in `/` from \"2.1.3\" to \"2.1.4\" [#2473](https://github.com/storybookjs/storybook/pull/2473)\n- Upgraded `eslint` in `/` from \"4.13.0\" to \"4.13.1\" [#2473](https://github.com/storybookjs/storybook/pull/2473)\n- Upgraded `prettier` in `/` from \"1.9.1\" to \"1.9.2\" [#2473](https://github.com/storybookjs/storybook/pull/2473)\n- Upgraded `@types/node` in `addons/knobs` from \"8.0.57\" to \"8.0.58\" [#2473](https://github.com/storybookjs/storybook/pull/2473)\n- Upgraded `@types/react` in `addons/knobs` from \"16.0.28\" to \"16.0.29\" [#2473](https://github.com/storybookjs/storybook/pull/2473)\n- Upgraded `core-js` in `app/react` from \"2.5.2\" to \"2.5.3\" [#2473](https://github.com/storybookjs/storybook/pull/2473)\n- Upgraded `core-js` in `app/vue` from \"2.5.2\" to \"2.5.3\" [#2473](https://github.com/storybookjs/storybook/pull/2473)\n- Upgraded `moment` in `addons/knobs` from \"2.19.3\" to \"2.19.4\" [#2462](https://github.com/storybookjs/storybook/pull/2462)\n- Upgraded `moment` in `addons/comments` from \"2.19.3\" to \"2.19.4\" [#2462](https://github.com/storybookjs/storybook/pull/2462)\n- Upgraded `react-inspector` in `addons/actions` from \"2.2.1\" to \"2.2.2\" [#2457](https://github.com/storybookjs/storybook/pull/2457)\n- Upgraded `react-inspector` in `lib/ui` from \"2.2.1\" to \"2.2.2\" [#2457](https://github.com/storybookjs/storybook/pull/2457)\n- Upgraded `gatsby-link` in `/docs` from \"1.6.30\" to \"1.6.31\" [#2458](https://github.com/storybookjs/storybook/pull/2458)\n- Upgraded `gatsby-plugin-sharp` in `/docs` from \"1.6.22\" to \"1.6.23\" [#2458](https://github.com/storybookjs/storybook/pull/2458)\n- Upgraded `gatsby-remark-autolink-headers` in `/docs` from \"1.4.9\" to \"1.4.10\" [#2458](https://github.com/storybookjs/storybook/pull/2458)\n- Upgraded `gatsby-remark-copy-linked-files` in `/docs` from \"1.5.22\" to \"1.5.23\" [#2458](https://github.com/storybookjs/storybook/pull/2458)\n- Upgraded `gatsby-remark-images` in `/docs` from \"1.5.33\" to \"1.5.34\" [#2458](https://github.com/storybookjs/storybook/pull/2458)\n- Upgraded `gatsby-remark-smartypants` in `/docs` from \"1.4.9\" to \"1.4.10\" [#2458](https://github.com/storybookjs/storybook/pull/2458)\n- Upgraded `gatsby-source-filesystem` in `/docs` from \"1.5.9\" to \"1.5.10\" [#2458](https://github.com/storybookjs/storybook/pull/2458)\n- Upgraded `gatsby-transformer-remark` in `/docs` from \"1.7.23\" to \"1.7.24\" [#2458](https://github.com/storybookjs/storybook/pull/2458)\n- Upgraded `gatsby` in `/docs` from \"1.9.128\" to \"1.9.130\" [#2458](https://github.com/storybookjs/storybook/pull/2458)\n- Update react-stack-grid in /docs from 0.6.0 to 0.7.0 [#2453](https://github.com/storybookjs/storybook/pull/2453)\n- Upgraded `eslint` in `/` from \"4.12.1\" to \"4.13.0\" [#2454](https://github.com/storybookjs/storybook/pull/2454)\n- Upgraded `core-js` in `app/react` from \"2.5.1\" to \"2.5.2\" [#2454](https://github.com/storybookjs/storybook/pull/2454)\n- Upgraded `core-js` in `app/vue` from \"2.5.1\" to \"2.5.2\" [#2454](https://github.com/storybookjs/storybook/pull/2454)\n- Upgraded `@types/node` in `addons/knobs` from \"8.0.56\" to \"8.0.57\" [#2448](https://github.com/storybookjs/storybook/pull/2448)\n- Upgraded `@types/react` in `addons/knobs` from \"16.0.27\" to \"16.0.28\" [#2448](https://github.com/storybookjs/storybook/pull/2448)\n- Upgraded `autoprefixer` in `app/react-native` from \"7.2.1\" to \"7.2.2\" [#2448](https://github.com/storybookjs/storybook/pull/2448)\n- Upgraded `autoprefixer` in `app/react` from \"7.2.1\" to \"7.2.2\" [#2448](https://github.com/storybookjs/storybook/pull/2448)\n- Upgraded `autoprefixer` in `app/vue` from \"7.2.1\" to \"7.2.2\" [#2448](https://github.com/storybookjs/storybook/pull/2448)\n- Upgraded `danger` in `/` from \"2.1.2\" to \"2.1.3\" [#2447](https://github.com/storybookjs/storybook/pull/2447)\n- Upgraded `jscodeshift` in `lib/codemod` from \"0.3.32\" to \"0.4.0\" [#2447](https://github.com/storybookjs/storybook/pull/2447)\n- Upgraded `jscodeshift` in `lib/cli` from \"0.3.32\" to \"0.4.0\" [#2447](https://github.com/storybookjs/storybook/pull/2447)\n- Upgraded `webpack-dev-server` in `examples/vue-kitchen-sink` from \"2.9.6\" to \"2.9.7\" [#2447](https://github.com/storybookjs/storybook/pull/2447)\n- Upgraded `danger` in `/` from \"2.0.3\" to \"2.1.2\" [#2442](https://github.com/storybookjs/storybook/pull/2442)\n- Upgraded `eslint-plugin-jest` in `/` from \"21.4.1\" to \"21.4.2\" [#2442](https://github.com/storybookjs/storybook/pull/2442)\n- Upgraded `github-release-from-changelog` in `/` from \"1.2.1\" to \"1.3.0\" [#2442](https://github.com/storybookjs/storybook/pull/2442)\n- Upgraded `nodemon` in `/` from \"1.12.4\" to \"1.12.5\" [#2442](https://github.com/storybookjs/storybook/pull/2442)\n- Upgraded `prettier` in `/` from \"1.9.0\" to \"1.9.1\" [#2442](https://github.com/storybookjs/storybook/pull/2442)\n- Upgraded `@types/node` in `addons/knobs` from \"8.0.54\" to \"8.0.55\" [#2442](https://github.com/storybookjs/storybook/pull/2442)\n- Upgraded `react-native` in `app/react-native` from \"0.50.4\" to \"0.51.0\" [#2442](https://github.com/storybookjs/storybook/pull/2442)\n- Upgraded `nodemon` in `app/react` from \"1.12.4\" to \"1.12.5\" [#2442](https://github.com/storybookjs/storybook/pull/2442)\n- Upgraded `nodemon` in `app/vue` from \"1.12.4\" to \"1.12.5\" [#2442](https://github.com/storybookjs/storybook/pull/2442)\n- Upgraded `@types/node` in `addons/knobs` from \"8.0.54\" to \"8.0.56\" [#2443](https://github.com/storybookjs/storybook/pull/2443)\n- Upgraded `webpack-dev-server` in `examples/vue-kitchen-sink` from \"2.9.5\" to \"2.9.6\" [#2443](https://github.com/storybookjs/storybook/pull/2443)\n- Update fs-extra in / from 4.0.2 to 4.0.3 [#2433](https://github.com/storybookjs/storybook/pull/2433)\n- Upgraded `eslint-plugin-jest` in `/` from \"21.4.0\" to \"21.4.1\" [#2430](https://github.com/storybookjs/storybook/pull/2430)\n- Upgraded `prettier` in `/` from \"1.8.2\" to \"1.9.0\" [#2430](https://github.com/storybookjs/storybook/pull/2430)\n- Upgraded `babel-eslint` in `/` from \"8.0.2\" to \"8.0.3\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `commander` in `/` from \"2.12.1\" to \"2.12.2\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `eslint` in `/` from \"4.12.0\" to \"4.12.1\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `eslint-plugin-jest` in `/` from \"21.3.2\" to \"21.4.0\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `inquirer` in `/` from \"4.0.0\" to \"4.0.1\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `nodemon` in `/` from \"1.12.1\" to \"1.12.4\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `moment` in `addons/knobs` from \"2.19.2\" to \"2.19.3\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `react-datetime` in `addons/knobs` from \"2.11.0\" to \"2.11.1\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `@types/node` in `addons/knobs` from \"8.0.53\" to \"8.0.54\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `@types/react` in `addons/knobs` from \"16.0.25\" to \"16.0.27\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `typescript` in `addons/knobs` from \"2.6.1\" to \"2.6.2\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `vue` in `addons/knobs` from \"2.5.8\" to \"2.5.9\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `commander` in `lib/cli` from \"2.12.1\" to \"2.12.2\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `react-modal` in `lib/ui` from \"3.1.4\" to \"3.1.7\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `autoprefixer` in `app/react-native` from \"7.1.6\" to \"7.2.1\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `commander` in `app/react-native` from \"2.12.1\" to \"2.12.2\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `webpack` in `app/react-native` from \"3.8.1\" to \"3.10.0\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `airbnb-js-shims` in `app/react` from \"1.3.0\" to \"1.4.0\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `autoprefixer` in `app/react` from \"7.1.6\" to \"7.2.1\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `commander` in `app/react` from \"2.12.1\" to \"2.12.2\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `webpack` in `app/react` from \"3.8.1\" to \"3.10.0\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `nodemon` in `app/react` from \"1.12.1\" to \"1.12.4\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `airbnb-js-shims` in `app/vue` from \"1.3.0\" to \"1.4.0\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `autoprefixer` in `app/vue` from \"7.1.6\" to \"7.2.1\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `commander` in `app/vue` from \"2.12.1\" to \"2.12.2\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `webpack` in `app/vue` from \"3.8.1\" to \"3.10.0\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `nodemon` in `app/vue` from \"1.12.1\" to \"1.12.4\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `vue` in `app/vue` from \"2.5.8\" to \"2.5.9\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `vue-template-compiler` in `app/vue` from \"2.5.8\" to \"2.5.9\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `marked` in `addons/comments` from \"0.3.6\" to \"0.3.7\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `moment` in `addons/comments` from \"2.19.2\" to \"2.19.3\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `vue` in `examples/vue-kitchen-sink` from \"2.5.8\" to \"2.5.9\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `vue-template-compiler` in `examples/vue-kitchen-sink` from \"2.5.8\" to \"2.5.9\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `webpack` in `examples/vue-kitchen-sink` from \"3.8.1\" to \"3.10.0\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `webpack-dev-server` in `examples/vue-kitchen-sink` from \"2.9.4\" to \"2.9.5\" [#2429](https://github.com/storybookjs/storybook/pull/2429)\n- Upgraded `@storybook/addon-actions` in `/docs` from \"3.2.16\" to \"3.2.17\" [#2427](https://github.com/storybookjs/storybook/pull/2427)\n- Upgraded `@storybook/addon-links` in `/docs` from \"3.2.16\" to \"3.2.17\" [#2427](https://github.com/storybookjs/storybook/pull/2427)\n- Upgraded `@storybook/addons` in `/docs` from \"3.2.16\" to \"3.2.17\" [#2427](https://github.com/storybookjs/storybook/pull/2427)\n- Upgraded `@storybook/react` in `/docs` from \"3.2.16\" to \"3.2.17\" [#2427](https://github.com/storybookjs/storybook/pull/2427)\n- React 16.2 [#2393](https://github.com/storybookjs/storybook/pull/2393)\n\n</details>\n\n## 3.2.17\n\n2017-December-03\n\n#### Features\n\n- Add dotenv support for storybook in vue and react [#2345](https://github.com/storybookjs/storybook/pull/2345)\n- Addon jest [#2295](https://github.com/storybookjs/storybook/pull/2295)\n- Addon-knobs: add number config options [#2371](https://github.com/storybookjs/storybook/pull/2371)\n- Addon-info: Expose style for customization [#2370](https://github.com/storybookjs/storybook/pull/2370)\n\n#### Bug Fixes\n\n- Fix addon-actions in legacy Android browser [#2365](https://github.com/storybookjs/storybook/pull/2365)\n- Remove superfluous vertical scrollbar in fullscreen [#2394](https://github.com/storybookjs/storybook/pull/2394)\n- Made jest test file extension name optional [#2373](https://github.com/storybookjs/storybook/pull/2373)\n- Render navigation and addons panels even when they are hidden [#2336](https://github.com/storybookjs/storybook/pull/2336)\n- Fix wrong \"withTests\" examples + add documentation [#2398](https://github.com/storybookjs/storybook/pull/2398)\n\n#### Maintenance\n\n- Issue #2196 - Set console.warn and console.error to throw in tests [#2297](https://github.com/storybookjs/storybook/pull/2297)\n- Optimize CI workflow [#2331](https://github.com/storybookjs/storybook/pull/2331)\n- Ignore shelljs in bithound [#2322](https://github.com/storybookjs/storybook/pull/2322)\n- Fix netlify vue instance [#2386](https://github.com/storybookjs/storybook/pull/2386)\n- Keep examples' deps up to date [#2353](https://github.com/storybookjs/storybook/pull/2353)\n- Separate netlify instances [#2340](https://github.com/storybookjs/storybook/pull/2340)\n- Issue 2196 fix unittest warnings [#2343](https://github.com/storybookjs/storybook/pull/2343)\n\n#### Documentation\n\n- Document return type of `date` knob (see #1489) [#2332](https://github.com/storybookjs/storybook/pull/2332)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n72 PRs\n</summary>\n\n- Update gatsby in /docs from 1.9.127 to 1.9.128 [#2420](https://github.com/storybookjs/storybook/pull/2420)\n- Update marked in /docs from 0.3.6 to 0.3.7 [#2416](https://github.com/storybookjs/storybook/pull/2416)\n- Upgraded `gatsby` in `docs` from \"1.9.126\" to \"1.9.127\" [#2406](https://github.com/storybookjs/storybook/pull/2406)\n- Upgraded `gatsby-transformer-remark` in `docs` from \"1.7.22\" to \"1.7.23\" [#2406](https://github.com/storybookjs/storybook/pull/2406)\n- Upgraded `gatsby` in `docs` from \"1.9.125\" to \"1.9.126\" [#2399](https://github.com/storybookjs/storybook/pull/2399)\n- Upgraded `gatsby-link` in `docs` from \"1.6.29\" to \"1.6.30\" [#2399](https://github.com/storybookjs/storybook/pull/2399)\n- Upgraded `gatsby` in `docs` from \"1.9.119\" to \"1.9.125\" [#2392](https://github.com/storybookjs/storybook/pull/2392)\n- Upgraded `gatsby-link` in `docs` from \"1.6.28\" to \"1.6.29\" [#2392](https://github.com/storybookjs/storybook/pull/2392)\n- Upgraded `gatsby-plugin-sharp` in `docs` from \"1.6.21\" to \"1.6.22\" [#2392](https://github.com/storybookjs/storybook/pull/2392)\n- Upgraded `gatsby-remark-autolink-headers` in `docs` from \"1.4.8\" to \"1.4.9\" [#2392](https://github.com/storybookjs/storybook/pull/2392)\n- Upgraded `gatsby-remark-copy-linked-files` in `docs` from \"1.5.21\" to \"1.5.22\" [#2392](https://github.com/storybookjs/storybook/pull/2392)\n- Upgraded `gatsby-remark-images` in `docs` from \"1.5.32\" to \"1.5.33\" [#2392](https://github.com/storybookjs/storybook/pull/2392)\n- Upgraded `gatsby-remark-smartypants` in `docs` from \"1.4.8\" to \"1.4.9\" [#2392](https://github.com/storybookjs/storybook/pull/2392)\n- Upgraded `gatsby-source-filesystem` in `docs` from \"1.5.8\" to \"1.5.9\" [#2392](https://github.com/storybookjs/storybook/pull/2392)\n- Upgraded `gatsby-transformer-remark` in `docs` from \"1.7.21\" to \"1.7.22\" [#2392](https://github.com/storybookjs/storybook/pull/2392)\n- Upgraded `webpack-dev-middleware` in `app/react-native` from \"1.12.1\" to \"1.12.2\" [#2385](https://github.com/storybookjs/storybook/pull/2385)\n- Upgraded `webpack-hot-middleware` in `app/react-native` from \"2.20.0\" to \"2.21.0\" [#2385](https://github.com/storybookjs/storybook/pull/2385)\n- Upgraded `webpack-dev-middleware` in `app/react` from \"1.12.1\" to \"1.12.2\" [#2385](https://github.com/storybookjs/storybook/pull/2385)\n- Upgraded `webpack-hot-middleware` in `app/react` from \"2.20.0\" to \"2.21.0\" [#2385](https://github.com/storybookjs/storybook/pull/2385)\n- Upgraded `webpack-dev-middleware` in `app/vue` from \"1.12.1\" to \"1.12.2\" [#2385](https://github.com/storybookjs/storybook/pull/2385)\n- Upgraded `webpack-hot-middleware` in `app/vue` from \"2.20.0\" to \"2.21.0\" [#2385](https://github.com/storybookjs/storybook/pull/2385)\n- Upgraded `danger` in `/` from \"2.0.1\" to \"2.0.3\" [#2380](https://github.com/storybookjs/storybook/pull/2380)\n- Upgraded `eslint` in `/` from \"4.11.0\" to \"4.12.0\" [#2380](https://github.com/storybookjs/storybook/pull/2380)\n- Upgraded `eslint-config-prettier` in `/` from \"2.8.0\" to \"2.9.0\" [#2380](https://github.com/storybookjs/storybook/pull/2380)\n- Upgraded `react-modal` in `lib/ui` from \"3.1.3\" to \"3.1.4\" [#2364](https://github.com/storybookjs/storybook/pull/2364)\n- Upgraded `postcss-loader` in `app/react-native` from \"2.0.8\" to \"2.0.9\" [#2364](https://github.com/storybookjs/storybook/pull/2364)\n- Upgraded `react-native` in `app/react-native` from \"0.50.3\" to \"0.50.4\" [#2364](https://github.com/storybookjs/storybook/pull/2364)\n- Upgraded `common-tags` in `app/react` from \"1.4.0\" to \"1.5.1\" [#2364](https://github.com/storybookjs/storybook/pull/2364)\n- Upgraded `postcss-loader` in `app/react` from \"2.0.8\" to \"2.0.9\" [#2364](https://github.com/storybookjs/storybook/pull/2364)\n- Upgraded `common-tags` in `app/vue` from \"1.4.0\" to \"1.5.1\" [#2364](https://github.com/storybookjs/storybook/pull/2364)\n- Upgraded `postcss-loader` in `app/vue` from \"2.0.8\" to \"2.0.9\" [#2364](https://github.com/storybookjs/storybook/pull/2364)\n- Upgraded `commander` in `/` from \"2.11.0\" to \"2.12.1\" [#2359](https://github.com/storybookjs/storybook/pull/2359)\n- Upgraded `commander` in `lib/cli` from \"2.11.0\" to \"2.12.1\" [#2359](https://github.com/storybookjs/storybook/pull/2359)\n- Upgraded `react-modal` in `lib/ui` from \"3.1.2\" to \"3.1.3\" [#2359](https://github.com/storybookjs/storybook/pull/2359)\n- Upgraded `commander` in `app/react-native` from \"2.11.0\" to \"2.12.1\" [#2359](https://github.com/storybookjs/storybook/pull/2359)\n- Upgraded `webpack-dev-middleware` in `app/react-native` from \"1.12.0\" to \"1.12.1\" [#2359](https://github.com/storybookjs/storybook/pull/2359)\n- Upgraded `commander` in `app/react` from \"2.11.0\" to \"2.12.1\" [#2359](https://github.com/storybookjs/storybook/pull/2359)\n- Upgraded `webpack-dev-middleware` in `app/react` from \"1.12.0\" to \"1.12.1\" [#2359](https://github.com/storybookjs/storybook/pull/2359)\n- Upgraded `commander` in `app/vue` from \"2.11.0\" to \"2.12.1\" [#2359](https://github.com/storybookjs/storybook/pull/2359)\n- Upgraded `webpack-dev-middleware` in `app/vue` from \"1.12.0\" to \"1.12.1\" [#2359](https://github.com/storybookjs/storybook/pull/2359)\n- Update gatsby in docs from 1.9.118 to 1.9.119 [#2354](https://github.com/storybookjs/storybook/pull/2354)\n- Upgraded `vue` in `addons/knobs` from \"2.5.6\" to \"2.5.8\" [#2344](https://github.com/storybookjs/storybook/pull/2344)\n- Upgraded `ws` in `app/react-native` from \"3.3.1\" to \"3.3.2\" [#2344](https://github.com/storybookjs/storybook/pull/2344)\n- Upgraded `vue` in `app/vue` from \"2.5.6\" to \"2.5.8\" [#2344](https://github.com/storybookjs/storybook/pull/2344)\n- Upgraded `vue-template-compiler` in `app/vue` from \"2.5.6\" to \"2.5.8\" [#2344](https://github.com/storybookjs/storybook/pull/2344)\n- Upgraded `vue` in `examples/vue-kitchen-sink` from \"2.5.6\" to \"2.5.8\" [#2344](https://github.com/storybookjs/storybook/pull/2344)\n- Upgraded `vue-template-compiler` in `examples/vue-kitchen-sink` from \"2.5.6\" to \"2.5.8\" [#2344](https://github.com/storybookjs/storybook/pull/2344)\n- Upgraded `eslint-config-prettier` in `/` from \"2.7.0\" to \"2.8.0\" [#2342](https://github.com/storybookjs/storybook/pull/2342)\n- Upgraded `eslint-plugin-react` in `/` from \"7.4.0\" to \"7.5.0\" [#2342](https://github.com/storybookjs/storybook/pull/2342)\n- Upgraded `vue` in `addons/knobs` from \"2.5.5\" to \"2.5.6\" [#2342](https://github.com/storybookjs/storybook/pull/2342)\n- Upgraded `vue` in `app/vue` from \"2.5.5\" to \"2.5.6\" [#2342](https://github.com/storybookjs/storybook/pull/2342)\n- Upgraded `vue-template-compiler` in `app/vue` from \"2.5.5\" to \"2.5.6\" [#2342](https://github.com/storybookjs/storybook/pull/2342)\n- Upgraded `vue` in `examples/vue-kitchen-sink` from \"2.5.5\" to \"2.5.6\" [#2342](https://github.com/storybookjs/storybook/pull/2342)\n- Upgraded `vue-template-compiler` in `examples/vue-kitchen-sink` from \"2.5.5\" to \"2.5.6\" [#2342](https://github.com/storybookjs/storybook/pull/2342)\n- Update gatsby in docs from 1.9.117 to 1.9.118 [#2341](https://github.com/storybookjs/storybook/pull/2341)\n- Upgraded `gatsby` in `docs` from \"1.9.114\" to \"1.9.117\" [#2338](https://github.com/storybookjs/storybook/pull/2338)\n- Upgraded `gh-pages` in `docs` from \"1.0.0\" to \"1.1.0\" [#2338](https://github.com/storybookjs/storybook/pull/2338)\n- Update gh-pages in / from 1.0.0 to 1.1.0 [#2339](https://github.com/storybookjs/storybook/pull/2339)\n- Upgraded `@types/react` in `addons/knobs` from \"16.0.23\" to \"16.0.25\" [#2334](https://github.com/storybookjs/storybook/pull/2334)\n- Upgraded `vue` in `addons/knobs` from \"2.5.3\" to \"2.5.5\" [#2334](https://github.com/storybookjs/storybook/pull/2334)\n- Upgraded `vue-hot-reload-api` in `app/vue` from \"2.2.3\" to \"2.2.4\" [#2334](https://github.com/storybookjs/storybook/pull/2334)\n- Upgraded `vue` in `app/vue` from \"2.5.3\" to \"2.5.5\" [#2334](https://github.com/storybookjs/storybook/pull/2334)\n- Upgraded `vue-template-compiler` in `app/vue` from \"2.5.3\" to \"2.5.5\" [#2334](https://github.com/storybookjs/storybook/pull/2334)\n- Upgraded `vue` in `examples/vue-kitchen-sink` from \"2.5.3\" to \"2.5.5\" [#2334](https://github.com/storybookjs/storybook/pull/2334)\n- Upgraded `vue-hot-reload-api` in `examples/vue-kitchen-sink` from \"2.2.3\" to \"2.2.4\" [#2334](https://github.com/storybookjs/storybook/pull/2334)\n- Upgraded `vue-template-compiler` in `examples/vue-kitchen-sink` from \"2.5.3\" to \"2.5.5\" [#2334](https://github.com/storybookjs/storybook/pull/2334)\n- Update gatsby in docs from 1.9.112 to 1.9.114 [#2333](https://github.com/storybookjs/storybook/pull/2333)\n- Upgraded `@storybook/addon-actions` in `docs` from \"3.2.15\" to \"3.2.16\" [#2327](https://github.com/storybookjs/storybook/pull/2327)\n- Upgraded `@storybook/addon-links` in `docs` from \"3.2.15\" to \"3.2.16\" [#2327](https://github.com/storybookjs/storybook/pull/2327)\n- Upgraded `@storybook/addons` in `docs` from \"3.2.15\" to \"3.2.16\" [#2327](https://github.com/storybookjs/storybook/pull/2327)\n- Upgraded `@storybook/react` in `docs` from \"3.2.15\" to \"3.2.16\" [#2327](https://github.com/storybookjs/storybook/pull/2327)\n- Update @types/node in addons/knobs from 8.0.52 to 8.0.53 [#2326](https://github.com/storybookjs/storybook/pull/2326)\n\n</details>\n\n## 3.2.16\n\n2017-November-15\n\n#### Features\n\n- Add addon-a11y to monorepo [#2292](https://github.com/storybookjs/storybook/pull/2292)\n\n#### Bug Fixes\n\n- Addon actions: replace eval with function name assignment [#2321](https://github.com/storybookjs/storybook/pull/2321)\n- FIX propwarning on basebutton && ADD style prop on basebutton [#2305](https://github.com/storybookjs/storybook/pull/2305)\n- React-native: fix drawer width [#2300](https://github.com/storybookjs/storybook/pull/2300)\n\n#### Maintenance\n\n- Add Previews of deployed examples via Netlify [#2304](https://github.com/storybookjs/storybook/pull/2304)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n30 upgrades\n</summary>\n\n- Update 5 dependencies from npm [#2312](https://github.com/storybookjs/storybook/pull/2312)\n- Upgraded gatsby-link in `docs` from `1.6.27` to `1.6.28` [#2311](https://github.com/storybookjs/storybook/pull/2311)\n- Upgraded gatsby-plugin-sharp in `docs` from `1.6.20` to `1.6.21` [#2311](https://github.com/storybookjs/storybook/pull/2311)\n- Upgraded gatsby-remark-images in `docs` from `1.5.31` to `1.5.32` [#2311](https://github.com/storybookjs/storybook/pull/2311)\n- Upgraded gatsby in `docs` from `1.9.108` to `1.9.112` [#2308](https://github.com/storybookjs/storybook/pull/2308)\n- Upgraded gatsby-link in `docs` from `1.6.26` to `1.6.27` [#2308](https://github.com/storybookjs/storybook/pull/2308)\n- Upgraded gatsby-remark-copy-linked-files in `docs` from `1.5.20` to `1.5.21` [#2308](https://github.com/storybookjs/storybook/pull/2308)\n- Upgraded gatsby-transformer-remark in `docs` from `1.7.20` to `1.7.21` [#2308](https://github.com/storybookjs/storybook/pull/2308)\n- Upgraded react-textarea-autosize in `addons/events` from `5.2.0` to `5.2.1` [#2309](https://github.com/storybookjs/storybook/pull/2309)\n- Upgraded react-datetime in `addons/knobs` from `2.10.3` to `2.11.0` [#2309](https://github.com/storybookjs/storybook/pull/2309)\n- Upgraded react-textarea-autosize in `addons/knobs` from `5.2.0` to `5.2.1` [#2309](https://github.com/storybookjs/storybook/pull/2309)\n- Upgraded react-textarea-autosize in `addons/comments` from `5.2.0` to `5.2.1` [#2309](https://github.com/storybookjs/storybook/pull/2309)\n- Upgraded moment in `addons/knobs` from `2.19.1` to `2.19.2` [#2293](https://github.com/storybookjs/storybook/pull/2293)\n- Upgraded moment in `addons/comments` from `2.19.1` to `2.19.2` [#2293](https://github.com/storybookjs/storybook/pull/2293)\n- Upgraded gatsby in `docs` from `1.9.100` to `1.9.108` [#2294](https://github.com/storybookjs/storybook/pull/2294)\n- Upgraded gatsby-link in `docs` from `1.6.24` to `1.6.26` [#2294](https://github.com/storybookjs/storybook/pull/2294)\n- Upgraded gatsby-plugin-sharp in `docs` from `1.6.19` to `1.6.20` [#2294](https://github.com/storybookjs/storybook/pull/2294)\n- Upgraded gatsby-remark-autolink-headers in `docs` from `1.4.7` to `1.4.8` [#2294](https://github.com/storybookjs/storybook/pull/2294)\n- Upgraded gatsby-remark-copy-linked-files in `docs` from `1.5.16` to `1.5.20` [#2294](https://github.com/storybookjs/storybook/pull/2294)\n- Upgraded gatsby-remark-images in `docs` from `1.5.30` to `1.5.31` [#2294](https://github.com/storybookjs/storybook/pull/2294)\n- Upgraded gatsby-source-filesystem in `docs` from `1.5.7` to `1.5.8` [#2294](https://github.com/storybookjs/storybook/pull/2294)\n- Upgraded gatsby-transformer-remark in `docs` from `1.7.19` to `1.7.20` [#2294](https://github.com/storybookjs/storybook/pull/2294)\n- Update lint-staged to 5.0.0 [#2291](https://github.com/storybookjs/storybook/pull/2291)\n- Upgraded eslint in `/` from `4.10.0` to `4.11.0` [#2290](https://github.com/storybookjs/storybook/pull/2290)\n- Upgraded puppeteer in `/` from `0.12.0` to `0.13.0` [#2290](https://github.com/storybookjs/storybook/pull/2290)\n- Update 6 dependencies from npm [#2286](https://github.com/storybookjs/storybook/pull/2286)\n- Update React to 16.1.0 [#2285](https://github.com/storybookjs/storybook/pull/2285)\n- Update 4 dependencies from npm [#2284](https://github.com/storybookjs/storybook/pull/2284)\n- use @storybook published deprecated dependencies [#2314](https://github.com/storybookjs/storybook/pull/2314)\n- Update inquirer to 4.0.0 [#2298](https://github.com/storybookjs/storybook/pull/2298)\n\n</details>\n\n## 3.2.15\n\n2017-November-10\n\n#### Features\n\n- Optimizing for iphone x [#2260](https://github.com/storybookjs/storybook/pull/2260)\n- Fix accessibility warnings [#2270](https://github.com/storybookjs/storybook/pull/2270)\n\n#### Bug Fixes\n\n- Fix propTypes in addon-background [#2279](https://github.com/storybookjs/storybook/pull/2279)\n- Addon-info: allow duplicate displayNames [#2269](https://github.com/storybookjs/storybook/pull/2269)\n- Fix browser navigation [#2261](https://github.com/storybookjs/storybook/pull/2261)\n\n#### Maintenance\n\n- Fixes to build scripts for Windows. [#2051](https://github.com/storybookjs/storybook/pull/2051)\n- Update dependencies.yml to include batch updates for docs dependencies [#2252](https://github.com/storybookjs/storybook/pull/2252)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n11 PRs\n</summary>\n\n- Update 4 dependencies from npm [#2267](https://github.com/storybookjs/storybook/pull/2267)\n- Update 8 dependencies from npm [#2262](https://github.com/storybookjs/storybook/pull/2262)\n- Update 3 dependencies from npm [#2257](https://github.com/storybookjs/storybook/pull/2257)\n- Update babel-eslint in / from 8.0.1 to 8.0.2 [#2253](https://github.com/storybookjs/storybook/pull/2253)\n- 3 packages updated by dependencies.io [#2251](https://github.com/storybookjs/storybook/pull/2251)\n- Update devDependencies [#2232](https://github.com/storybookjs/storybook/pull/2232)\n- Update react-textarea-autosize to 5.1.0 [#2233](https://github.com/storybookjs/storybook/pull/2233)\n- Update insert-css to 2.0.0 [#2234](https://github.com/storybookjs/storybook/pull/2234)\n- Update file-loader to 1.1.5 [#2236](https://github.com/storybookjs/storybook/pull/2236)\n- Update read-pkg-up to 3.0.0 [#2237](https://github.com/storybookjs/storybook/pull/2237)\n- Update react-modal to 3.1.0 [#2238](https://github.com/storybookjs/storybook/pull/2238)\n\n</details>\n\n## 3.2.14\n\n2017-November-01\n\n#### Features\n\n- React-native: Add platform option for haul bundler [#2129](https://github.com/storybookjs/storybook/pull/2129)\n\n#### Bug Fixes\n\n- Fixed addon-info not importing docgen descriptions [#2133](https://github.com/storybookjs/storybook/pull/2133)\n- Handle full screen scrolling on iOS [#2040](https://github.com/storybookjs/storybook/pull/2040)\n- Fixed infinite render loop [#2100](https://github.com/storybookjs/storybook/pull/2100)\n- Fix hmr in react-native template [#2194](https://github.com/storybookjs/storybook/pull/2194)\n- Fix prop type in react-native [#2185](https://github.com/storybookjs/storybook/pull/2185)\n- Avoid logging an object on compilation errors [#2199](https://github.com/storybookjs/storybook/pull/2199)\n\n#### Documentation\n\n- CRA Example Cleanup - Info [#2143](https://github.com/storybookjs/storybook/pull/2143)\n\n#### Maintenance\n\n- IMPROVE integration tests so they all output a diff image when multiple fail [#2197](https://github.com/storybookjs/storybook/pull/2197)\n- ADD integration artefacts store step to circle.yml [#2182](https://github.com/storybookjs/storybook/pull/2182)\n- ADD integration test [#2119](https://github.com/storybookjs/storybook/pull/2119)\n- Updating to new favicon [#2113](https://github.com/storybookjs/storybook/pull/2113)\n- Bot for closing old issues [#2186](https://github.com/storybookjs/storybook/pull/2186)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n12 PRs\n</summary>\n\n- 7 packages updated by dependencies.io [#2200](https://github.com/storybookjs/storybook/pull/2200)\n- Update jest-image-snapshot to 2.1.0 [#2184](https://github.com/storybookjs/storybook/pull/2184)\n- 2 packages updated by dependencies.io [#2175](https://github.com/storybookjs/storybook/pull/2175)\n- 3 packages updated by dependencies.io [#2137](https://github.com/storybookjs/storybook/pull/2137)\n- 2 packages updated by dependencies.io [#2131](https://github.com/storybookjs/storybook/pull/2131)\n- 4 packages updated by dependencies.io [#2124](https://github.com/storybookjs/storybook/pull/2124)\n- 2 packages updated by dependencies.io [#2116](https://github.com/storybookjs/storybook/pull/2116)\n- 5 packages updated by dependencies.io [#2111](https://github.com/storybookjs/storybook/pull/2111)\n- 4 packages updated by dependencies.io [#2109](https://github.com/storybookjs/storybook/pull/2109)\n- Add index.js file for RN 0.49 [#2176](https://github.com/storybookjs/storybook/pull/2176)\n- Enable issue creation for dependencies.io [#2141](https://github.com/storybookjs/storybook/pull/2141)\n- Major updates in devDependencies [#2178](https://github.com/storybookjs/storybook/pull/2178)\n\n</details>\n\n## 3.2.13\n\n2017-October-20\n\n#### Features\n\n- Knobs addon: new knob type `button` [#2004](https://github.com/storybookjs/storybook/pull/2004)\n- Vue: Support JSX for Vue Components [#1993](https://github.com/storybookjs/storybook/pull/1993)\n- Vue CLI: support Nuxt.js projects [#2056](https://github.com/storybookjs/storybook/pull/2056)\n\n#### Bug Fixes\n\n- UI: ix sidebar header wrapping [#1962](https://github.com/storybookjs/storybook/pull/1962)\n- Vue: Make Vue a peer dependency [#2041](https://github.com/storybookjs/storybook/pull/2041)\n\n#### Documentation\n\n- Update empty addons channel bug description [#1977](https://github.com/storybookjs/storybook/pull/1977)\n- Fix README.md example for addons/info [#1960](https://github.com/storybookjs/storybook/pull/1960)\n\n#### Maintenance\n\n- Dirty-check repo state on CI to ensure lockfiles being up-to-date [#1980](https://github.com/storybookjs/storybook/pull/1980)\n- Enable batch mode for dependencies.io [#2093](https://github.com/storybookjs/storybook/pull/2093)\n- Fixed lifecycle twice executing (closes #1742) [#1983](https://github.com/storybookjs/storybook/pull/1983)\n- Disable npm publish on all non-master branches [#1963](https://github.com/storybookjs/storybook/pull/1963)\n- Fix lerna.json to ignore vue-kitchen-sink correctly [#1944](https://github.com/storybookjs/storybook/pull/1944)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n66 PRs\n</summary>\n\n- 2 packages updated by dependencies.io [#2097](https://github.com/storybookjs/storybook/pull/2097)\n- 2 packages updated by dependencies.io [#2094](https://github.com/storybookjs/storybook/pull/2094)\n- Update deps [#2090](https://github.com/storybookjs/storybook/pull/2090)\n- Update enzyme-adapter-react-16 from 1.0.1 to 1.0.2 in / [#2068](https://github.com/storybookjs/storybook/pull/2068)\n- Update deps [#2077](https://github.com/storybookjs/storybook/pull/2077)\n- Update webpack-hot-middleware from 2.19.1 to 2.20.0 in app/react [#2060](https://github.com/storybookjs/storybook/pull/2060)\n- Update webpack-hot-middleware from 2.19.1 to 2.20.0 in app/react-native [#2059](https://github.com/storybookjs/storybook/pull/2059)\n- Update @types/react from 16.0.10 to 16.0.11 in addons/knobs [#2058](https://github.com/storybookjs/storybook/pull/2058)\n- Update vue versions [#2032](https://github.com/storybookjs/storybook/pull/2032)\n- Update eslint from 4.8.0 to 4.9.0 in / [#2054](https://github.com/storybookjs/storybook/pull/2054)\n- Update webpack-dev-server from 2.9.1 to 2.9.2 in examples/vue-kitchen-sink [#2055](https://github.com/storybookjs/storybook/pull/2055)\n- Update postcss-loader from 2.0.7 to 2.0.8 in app/react [#2045](https://github.com/storybookjs/storybook/pull/2045)\n- Update codecov from 2.3.0 to 2.3.1 in / [#2042](https://github.com/storybookjs/storybook/pull/2042)\n- Update webpack from 3.6.0 to 3.7.1 in app/react-native [#2027](https://github.com/storybookjs/storybook/pull/2027)\n- Update moment from 2.19.0 to 2.19.1 in addons/knobs [#2026](https://github.com/storybookjs/storybook/pull/2026)\n- Update express from 4.16.1 to 4.16.2 in app/vue [#2018](https://github.com/storybookjs/storybook/pull/2018)\n- Update postcss-loader from 2.0.6 to 2.0.7 in app/react [#2017](https://github.com/storybookjs/storybook/pull/2017)\n- Update express from 4.16.1 to 4.16.2 in app/react [#2016](https://github.com/storybookjs/storybook/pull/2016)\n- Update postcss-loader from 2.0.6 to 2.0.7 in app/react-native [#2015](https://github.com/storybookjs/storybook/pull/2015)\n- Update express from 4.16.1 to 4.16.2 in app/react-native [#2014](https://github.com/storybookjs/storybook/pull/2014)\n- Update moment from 2.18.1 to 2.19.0 in addons/knobs [#2013](https://github.com/storybookjs/storybook/pull/2013)\n- Update autoprefixer from 7.1.4 to 7.1.5 in app/vue [#2003](https://github.com/storybookjs/storybook/pull/2003)\n- Update update-notifier from 2.2.0 to 2.3.0 in lib/cli [#1999](https://github.com/storybookjs/storybook/pull/1999)\n- Update autoprefixer from 7.1.4 to 7.1.5 in app/react [#2002](https://github.com/storybookjs/storybook/pull/2002)\n- Update autoprefixer from 7.1.4 to 7.1.5 in app/react-native [#2000](https://github.com/storybookjs/storybook/pull/2000)\n- Update @types/react from 16.0.9 to 16.0.10 in addons/knobs [#1998](https://github.com/storybookjs/storybook/pull/1998)\n- Update jest-enzyme from 4.0.0 to 4.0.1 in / [#1997](https://github.com/storybookjs/storybook/pull/1997)\n- Update storybook-router description in the addon gallery. [#1991](https://github.com/storybookjs/storybook/pull/1991)\n- Update lerna from 2.3.1 to 2.4.0 in / [#1985](https://github.com/storybookjs/storybook/pull/1985)\n- Update react-modal from 2.3.3 to 2.4.1 in app/vue [#1989](https://github.com/storybookjs/storybook/pull/1989)\n- Update react-modal from 2.3.3 to 2.4.1 in app/react [#1988](https://github.com/storybookjs/storybook/pull/1988)\n- Update react-modal from 2.3.3 to 2.4.1 in lib/ui [#1987](https://github.com/storybookjs/storybook/pull/1987)\n- Update react-icons from 2.2.5 to 2.2.7 in lib/ui [#1986](https://github.com/storybookjs/storybook/pull/1986)\n- Remove markdown autofixing on precommit hook [#1964](https://github.com/storybookjs/storybook/pull/1964)\n- Update vue-hot-reload-api from 2.1.0 to 2.1.1 in app/vue [#1976](https://github.com/storybookjs/storybook/pull/1976)\n- Update url-loader from 0.5.9 to 0.6.2 in app/vue [#1975](https://github.com/storybookjs/storybook/pull/1975)\n- Update react-modal from 2.3.2 to 2.3.3 in app/vue [#1974](https://github.com/storybookjs/storybook/pull/1974)\n- Update url-loader from 0.5.9 to 0.6.2 in app/react [#1973](https://github.com/storybookjs/storybook/pull/1973)\n- Update react-modal from 2.3.2 to 2.3.3 in app/react [#1972](https://github.com/storybookjs/storybook/pull/1972)\n- Update url-loader from 0.5.9 to 0.6.2 in app/react-native [#1970](https://github.com/storybookjs/storybook/pull/1970)\n- Update react-modal from 2.3.2 to 2.3.3 in lib/ui [#1969](https://github.com/storybookjs/storybook/pull/1969)\n- Update @types/react from 16.0.8 to 16.0.9 in addons/knobs [#1968](https://github.com/storybookjs/storybook/pull/1968)\n- Update graphql from 0.11.6 to 0.11.7 in addons/graphql [#1967](https://github.com/storybookjs/storybook/pull/1967)\n- Update @storybook/addon-links from 3.2.10 to 3.2.12 [#1949](https://github.com/storybookjs/storybook/pull/1949)\n- Update style-loader from 0.18.2 to 0.19.0 in addons/knobs [#1958](https://github.com/storybookjs/storybook/pull/1958)\n- Update @types/react from 16.0.7 to 16.0.8 in addons/knobs [#1957](https://github.com/storybookjs/storybook/pull/1957)\n- Update prettier from 1.7.3 to 1.7.4 in / [#1955](https://github.com/storybookjs/storybook/pull/1955)\n- Update react-motion from 0.5.1 to 0.5.2 [#1953](https://github.com/storybookjs/storybook/pull/1953)\n- Update lerna from 2.2.0 to 2.3.1 in / [#1954](https://github.com/storybookjs/storybook/pull/1954)\n- Update @storybook/addons from 3.2.10 to 3.2.12 [#1950](https://github.com/storybookjs/storybook/pull/1950)\n- Update enzyme from 3.0.0 to 3.1.0 in / [#1948](https://github.com/storybookjs/storybook/pull/1948)\n- Update enzyme-adapter-react-16 from 1.0.0 to 1.0.1 in / [#1951](https://github.com/storybookjs/storybook/pull/1951)\n- Update @storybook/addon-actions from 3.2.11 to 3.2.12 [#1947](https://github.com/storybookjs/storybook/pull/1947)\n\n</details>\n\n## 3.2.12\n\n2017-October-02\n\n#### Bug Fixes\n\n- addon-info: wrap prop values in braces [#1915](https://github.com/storybookjs/storybook/pull/1915)\n- Add polyfills to fix addon-actions in IE11 [#1917](https://github.com/storybookjs/storybook/pull/1917)\n- Gracefully handle fatal webpack errors. [#1918](https://github.com/storybookjs/storybook/pull/1918)\n- Fix polyfills loading order [#1905](https://github.com/storybookjs/storybook/pull/1905)\n\n#### Documentation\n\n- Improve documentation for react-native : clarify where left pane is [#1901](https://github.com/storybookjs/storybook/pull/1901)\n\n#### Maintenance\n\n- Use yarn workspaces on master [#1916](https://github.com/storybookjs/storybook/pull/1916)\n- Run `eslint --fix` on master [#1909](https://github.com/storybookjs/storybook/pull/1909)\n- Remove open collective notice from storybook install [#1940](https://github.com/storybookjs/storybook/pull/1940)\n- Run bootstrap before linting on CI [#1934](https://github.com/storybookjs/storybook/pull/1934)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n14 PRs\n</summary>\n\n- Update raf from 3.3.2 to 3.4.0 in / [#1939](https://github.com/storybookjs/storybook/pull/1939)\n- Update graphql from 0.7.2 to 0.11.6 in addons/graphql [#1930](https://github.com/storybookjs/storybook/pull/1930)\n- Update react-typography from 0.15.10 to 0.16.5 [#1927](https://github.com/storybookjs/storybook/pull/1927)\n- Update react-render-html from 0.1.6 to 0.5.2 in addons/comments [#1933](https://github.com/storybookjs/storybook/pull/1933)\n- Update react-datetime from 2.10.2 to 2.10.3 in addons/knobs [#1931](https://github.com/storybookjs/storybook/pull/1931)\n- Update typography from 0.15.12 to 0.16.6 [#1929](https://github.com/storybookjs/storybook/pull/1929)\n- Update graphiql from 0.7.8 to 0.11.5 in addons/graphql [#1928](https://github.com/storybookjs/storybook/pull/1928)\n- Update prettier from 1.7.2 to 1.7.3 in / [#1926](https://github.com/storybookjs/storybook/pull/1926)\n- Update react-stack-grid from 0.2.2 to 0.5.0 [#1925](https://github.com/storybookjs/storybook/pull/1925)\n- Update react-motion from 0.1.0 to 0.5.1 [#1924](https://github.com/storybookjs/storybook/pull/1924)\n- Update eslint from 4.7.2 to 4.8.0 in / [#1923](https://github.com/storybookjs/storybook/pull/1923)\n- Update chroma-js from 0.7.2 to 0.7.8 [#1922](https://github.com/storybookjs/storybook/pull/1922)\n- Use dependencies.io for dependencies management [#1920](https://github.com/storybookjs/storybook/pull/1920)\n- UPGRADE react & friends && UPGRADE other dependencies [#1908](https://github.com/storybookjs/storybook/pull/1908)\n\n</details>\n\n## 3.2.11\n\n2017-September-27\n\n#### Features\n\n- Add two new RN packager configuration options [#1865](https://github.com/storybookjs/storybook/pull/1865)\n\n#### Bug Fixes\n\n- Addon-info - Fix immutable props issues with React 16 [#1894](https://github.com/storybookjs/storybook/pull/1894)\n- Update react-inspector to fix #1831 [#1888](https://github.com/storybookjs/storybook/pull/1888)\n\n#### Documentation\n\n- Updated release process documentation [#1882](https://github.com/storybookjs/storybook/pull/1882)\n\n## 3.2.10\n\n2017-September-22\n\n#### Features\n\n- Added codemod for deprecated addon-links and addon-actions from app [#1368](https://github.com/storybookjs/storybook/pull/1368)\n- React native: Added option for custom packager port [#1837](https://github.com/storybookjs/storybook/pull/1837)\n- CLI: add support for Vue projects using Nuxt [#1794](https://github.com/storybookjs/storybook/pull/1794)\n\n#### Bug Fixes\n\n- Avoid error \"storyshots is intended only to be used with storybook\" [#1441](https://github.com/storybookjs/storybook/pull/1441)\n- Log correct url when using --https [#1871](https://github.com/storybookjs/storybook/pull/1871)\n- Fix broken links in the deprecation warning for RN and Vue apps [#1827](https://github.com/storybookjs/storybook/pull/1827)\n- Height aligned 2 buttons in manager's header [#1769](https://github.com/storybookjs/storybook/pull/1769)\n- Add missing regenerator and runtime babel transform pkgs to package.json [#1848](https://github.com/storybookjs/storybook/pull/1848)\n\n#### Documentation\n\n- Update README: mention that addon-links needs to be registered manually [#1835](https://github.com/storybookjs/storybook/pull/1835)\n- Improve linkTo documentation [#1793](https://github.com/storybookjs/storybook/pull/1793)\n- Minor grammar fixes and clarification to Vue documentation [#1756](https://github.com/storybookjs/storybook/pull/1756)\n- Add missing NPM script section to Vue guide [#1824](https://github.com/storybookjs/storybook/pull/1824)\n- Add storybook-chrome-screenshot to addon gallery [#1761](https://github.com/storybookjs/storybook/pull/1761)\n\n#### Dependency Upgrades\n\n- Update babel-eslint to the latest version 🚀 [#1836](https://github.com/storybookjs/storybook/pull/1836)\n- UPGRADE root dependencies and SYNC with packages [#1802](https://github.com/storybookjs/storybook/pull/1802)\n- Update jest to the latest version 🚀 [#1799](https://github.com/storybookjs/storybook/pull/1799)\n- Update eslint-plugin-jest to the latest version 🚀 [#1795](https://github.com/storybookjs/storybook/pull/1795)\n- Update lerna to the latest version 🚀 [#1768](https://github.com/storybookjs/storybook/pull/1768)\n\n#### Maintenance\n\n- Smoke test master [#1801](https://github.com/storybookjs/storybook/pull/1801)\n- Fixed Jest warnings [#1744](https://github.com/storybookjs/storybook/pull/1744)\n\n## 3.2.9\n\n2017-August-26\n\n#### Bug Fixes\n\n- Fix getstorybook CLI for React Native projects [#1741](https://github.com/storybookjs/storybook/pull/1741)\n\n#### Documentation\n\n- Improve `addon-info` README options documentation [#1732](https://github.com/storybookjs/storybook/pull/1732)\n\n#### Maintenance\n\n- ADD a CLI for bootstrapping [#1216](https://github.com/storybookjs/storybook/pull/1216)\n\n#### Dependency Upgrades\n\n- Update lerna to the latest version 🚀 [#1727](https://github.com/storybookjs/storybook/pull/1727)\n\n## 3.2.8\n\n2017-August-23\n\n#### Bug Fixes\n\n- Fix storyshots with new babel config [#1721](https://github.com/storybookjs/storybook/pull/1721)\n- Fix CLI generators export [#1722](https://github.com/storybookjs/storybook/pull/1722)\n\n#### Documentation\n\n- Add caveat about knobs date defaultValue [#1719](https://github.com/storybookjs/storybook/pull/1719)\n\n## 3.2.7\n\n2017-August-23\n\n#### Bug Fixes\n\n- Fix storyshots by moving cacheDirectory to webpack config [#1713](https://github.com/storybookjs/storybook/pull/1713)\n- Revert \"Improved error checking in global addDecorator\" [#1716](https://github.com/storybookjs/storybook/pull/1716)\n- Stricter linting rules for imports [#1676](https://github.com/storybookjs/storybook/pull/1676)\n- Addon Info: Remove broken prop type sort (keep defined order) [#1711](https://github.com/storybookjs/storybook/pull/1711)\n\n#### Maintenance\n\n- Enable eslint for vue-related stuff [#1715](https://github.com/storybookjs/storybook/pull/1715)\n- CLI: ensure explicit dependency on `prop-types` for RN [#1714](https://github.com/storybookjs/storybook/pull/1714)\n\n## 3.2.6\n\n2017-August-22\n\n#### Features\n\n- Improve search and highlighting [#1693](https://github.com/storybookjs/storybook/pull/1693)\n- Add centered decorator for vue [#1595](https://github.com/storybookjs/storybook/pull/1595)\n- Add react-docgen propTypes to info addon [#1562](https://github.com/storybookjs/storybook/pull/1562)\n\n#### Bug Fixes\n\n- Fix stories panel resizing bug [#1689](https://github.com/storybookjs/storybook/pull/1689)\n- Check for React presence when detecting `WEBPACK_REACT` type [#1646](https://github.com/storybookjs/storybook/pull/1646)\n- Fix Create React App detection [#1645](https://github.com/storybookjs/storybook/pull/1645)\n- Add dependencies on plugins used by getstorybook CLI [#1652](https://github.com/storybookjs/storybook/pull/1652)\n- Fix preview window loading non js,css files [#1554](https://github.com/storybookjs/storybook/pull/1554)\n\n#### Documentation\n\n- Improve the warning given when using channel before it's defined [#1515](https://github.com/storybookjs/storybook/pull/1515)\n- Remove imports from README that are not necessary with latest API [#1700](https://github.com/storybookjs/storybook/pull/1700)\n- Add reminders to PR template [#1683](https://github.com/storybookjs/storybook/pull/1683)\n- Docgen Flow Type Example [#1684](https://github.com/storybookjs/storybook/pull/1684)\n\n#### Maintenance\n\n- Make lint-staged work properly [#1675](https://github.com/storybookjs/storybook/pull/1675)\n- Move baseFonts and RoutedLink to `@storybook/components` [#1659](https://github.com/storybookjs/storybook/pull/1659)\n\n#### Dependency Upgrades\n\n- Switch to babel preset env + async/await/generator support [#1668](https://github.com/storybookjs/storybook/pull/1668)\n- Upgrade react-native-compat to avoid PropTypes warnings [#1673](https://github.com/storybookjs/storybook/pull/1673)\n- Change React.PropTypes to prop-types [#1674](https://github.com/storybookjs/storybook/pull/1674) [#1710](https://github.com/storybookjs/storybook/pull/1710)\n\n## 3.2.5\n\n2017-August-16\n\n#### Features\n\n- Add codemod for deprecated addon-info API [#1582](https://github.com/storybookjs/storybook/pull/1582)\n\n#### Bug Fixes\n\n- Fixed addon-knobs for RN [#1635](https://github.com/storybookjs/storybook/pull/1635)\n- Make links navigate in the parent window [#1650](https://github.com/storybookjs/storybook/pull/1650)\n- Don’t render leftpanel stories tree if stories are empty [#1664](https://github.com/storybookjs/storybook/pull/1664)\n- Remove double styling for inline stories [#1651](https://github.com/storybookjs/storybook/pull/1651)\n\n#### Dependency Upgrades\n\n- Upgrade react-modal to v2.2.4 [#1666](https://github.com/storybookjs/storybook/pull/1666)\n\n## 3.2.4\n\n2017-August-12\n\n#### Features\n\n- Hierarchy expansion on search [#1598](https://github.com/storybookjs/storybook/pull/1598)\n- Add sidebarAnimations config prop [#1601](https://github.com/storybookjs/storybook/pull/1601)\n- Add hrefs to left menu links [#1523](https://github.com/storybookjs/storybook/pull/1523)\n- Enable many components of same type in addon-info prop tables [#1607](https://github.com/storybookjs/storybook/pull/1607)\n- Always collapse an expanded kind in tree view without changing selected story [#1590](https://github.com/storybookjs/storybook/pull/1590)\n- Option to select an addon panel [#1641](https://github.com/storybookjs/storybook/pull/1641)\n\n#### Documentation\n\n- Document how to use info addon as decorator [#1592](https://github.com/storybookjs/storybook/pull/1592)\n- Add Android simulator instructions for React Native [#1591](https://github.com/storybookjs/storybook/pull/1591)\n\n#### Maintenance\n\n- Tree view visual adjustments [#1599](https://github.com/storybookjs/storybook/pull/1599)\n- Add z-index to shortcuts popup overlay [#1617](https://github.com/storybookjs/storybook/pull/1617)\n- Use ReactModal for search box [#1548](https://github.com/storybookjs/storybook/pull/1548)\n- Limit react versions to >=15 [#1613](https://github.com/storybookjs/storybook/pull/1613)\n\n## 3.2.3\n\n2017-August-01\n\n#### Features\n\n- Use the React Native packager's host by default [#1568](https://github.com/storybookjs/storybook/pull/1568)\n- Make onDeviceUI default for RN getstorybook [#1571](https://github.com/storybookjs/storybook/pull/1571)\n\n#### Documentation\n\n- Add short description to addon-options readme [#1566](https://github.com/storybookjs/storybook/pull/1566)\n\n## 3.2.2\n\n2017-July-31\n\n#### Bug Fixes\n\n- Fixed build-storybook for vue [#1564](https://github.com/storybookjs/storybook/pull/1564)\n\n## 3.2.1\n\n2017-July-31\n\n#### Bug Fixes\n\n- Check if hierarchySeparator presents in the options object [#1561](https://github.com/storybookjs/storybook/pull/1561)\n- React Native &lt;0.43 support [#1555](https://github.com/storybookjs/storybook/pull/1555)\n\n#### Documentation\n\n- Fix typo with Vue README referring to react [#1556](https://github.com/storybookjs/storybook/pull/1556)\n- Add state-setting FAQ [#1559](https://github.com/storybookjs/storybook/pull/1559)\n\n## 3.2.0\n\n2017-July-31\n\nStorybook 3.2 is filled with new features to help make your components shine! Headline features:\n\n- Vue support [#1267](https://github.com/storybookjs/storybook/pull/1267)\n- Story Hierarchy [#1329](https://github.com/storybookjs/storybook/pull/1329)\n- React Native On Device UI [#1413](https://github.com/storybookjs/storybook/pull/1413)\n\nPlus many more features, documentation improvements, and bugfixes below!\n\n#### Features\n\n- Vue support [#1267](https://github.com/storybookjs/storybook/pull/1267)\n- Add support for vue in addon-notes [#1278](https://github.com/storybookjs/storybook/pull/1278)\n- CLI support for Vue [#1287](https://github.com/storybookjs/storybook/pull/1287)\n- Story Hierarchy [#1329](https://github.com/storybookjs/storybook/pull/1329)\n- Story Hierarchy UI improvements [#1387](https://github.com/storybookjs/storybook/pull/1387) [#1356](https://github.com/storybookjs/storybook/pull/1356)\n- Story Hierarchy - keyboard accessibility [#1427](https://github.com/storybookjs/storybook/pull/1427)\n- React Native - On Device UI [#1413](https://github.com/storybookjs/storybook/pull/1413)\n- Show first story on RN OnDeviceUI startup [#1510](https://github.com/storybookjs/storybook/pull/1510)\n- Added collapsible RN OnDeviceUI navigation [#1544](https://github.com/storybookjs/storybook/pull/1544)\n- Add warning when module is missing in storiesOf [#1525](https://github.com/storybookjs/storybook/pull/1525)\n- Provide styling hook for Addon Info story body [#1308](https://github.com/storybookjs/storybook/pull/1308)\n- Implement filtering on story-level [#1432](https://github.com/storybookjs/storybook/pull/1432)\n- Refactoring of `addon-info` [#1452](https://github.com/storybookjs/storybook/pull/1452)\n- ADD storybook logo for inside terminal for future CLI or easteregg [#1499](https://github.com/storybookjs/storybook/pull/1499)\n- Improved error checking in global addDecorator [#1481](https://github.com/storybookjs/storybook/pull/1481)\n\n#### Bug Fixes\n\n- Fix react native example and bootstrapping [#1514](https://github.com/storybookjs/storybook/pull/1514)\n- Fix a 'funny' hmr issue in cra-kitchen-sink [#1508](https://github.com/storybookjs/storybook/pull/1508)\n- When timestamps are enabled, it actually checks them before applying changes [#1405](https://github.com/storybookjs/storybook/pull/1405)\n- Fix issue when extending webpack config [#1468](https://github.com/storybookjs/storybook/pull/1468)\n- Fix addon notes [#1448](https://github.com/storybookjs/storybook/pull/1448)\n- Story Hierarchy - initial state bug fix [#1401](https://github.com/storybookjs/storybook/pull/1401)\n- Remove blue outline when node is focused [#1497](https://github.com/storybookjs/storybook/pull/1497)\n\n#### Documentation\n\n- Add hierarchySeparator to README [#1445](https://github.com/storybookjs/storybook/pull/1445)\n- Document null addons channel in FAQ [#1507](https://github.com/storybookjs/storybook/pull/1507)\n\n#### Maintenance\n\n- Revert knobs API to previous API. [#1527](https://github.com/storybookjs/storybook/pull/1527)\n- FIX hoist-internals: remove existing folder/link before linking [#1516](https://github.com/storybookjs/storybook/pull/1516)\n- Update global hook for Vue Devtools [#1376](https://github.com/storybookjs/storybook/pull/1376)\n- SWITCH to circleci over travisCI && CHANGE lerna bootstrap procedure: [#1486](https://github.com/storybookjs/storybook/pull/1486)\n- Update cra-kitchen-sink package versions for 3.2-alpha [#1434](https://github.com/storybookjs/storybook/pull/1434)\n- Updating 3.2 alpha release with patches [#1419](https://github.com/storybookjs/storybook/pull/1419)\n- Remove typescript typings for @storybook/addon-notes [#1344](https://github.com/storybookjs/storybook/pull/1344)\n- Remove typescript typings for @storybook/addon-options [#1343](https://github.com/storybookjs/storybook/pull/1343)\n- Remove typescript typings for @storybook/addon-knobs [#1339](https://github.com/storybookjs/storybook/pull/1339)\n- Remove typescript typings for @storybook/addon-links [#1342](https://github.com/storybookjs/storybook/pull/1342)\n\n#### Dependency Upgrades\n\n- Updated babel-plugin-react-docgen version [#1526](https://github.com/storybookjs/storybook/pull/1526)\n- UPDATE everything (including eslint 4) [#1517](https://github.com/storybookjs/storybook/pull/1517)\n- Update remark-preset-lint-recommended to the latest version 🚀 [#1512](https://github.com/storybookjs/storybook/pull/1512)\n- Update remark-cli to the latest version 🚀 [#1498](https://github.com/storybookjs/storybook/pull/1498)\n- Remove upper bound on react-native peerDependency [#1424](https://github.com/storybookjs/storybook/pull/1424)\n- Bump `react-split-pane` version [#1495](https://github.com/storybookjs/storybook/pull/1495)\n\n## 3.1.9\n\n2017-July-16\n\n#### Features\n\n- React fiber support [#1443](https://github.com/storybookjs/storybook/pull/1443)\n\n#### Documentation\n\n- Refine docs about loading stories dynamically for react-native [#1420](https://github.com/storybookjs/storybook/pull/1420)\n\n#### Bug Fixes\n\n- Verify that name is a string in addons/actions [#1415](https://github.com/storybookjs/storybook/pull/1415)\n- Knobs: fix label alignment [#1471](https://github.com/storybookjs/storybook/pull/1471)\n- Fix display of large components [#1237](https://github.com/storybookjs/storybook/pull/1237)\n\n#### Dependency Upgrades\n\n- Dependency updates [#1439](https://github.com/storybookjs/storybook/pull/1439)\n- chore(package): update husky to version 0.14.3 [#1437](https://github.com/storybookjs/storybook/pull/1437)\n- Update danger to the latest version 🚀 [#1393](https://github.com/storybookjs/storybook/pull/1393)\n- Update lerna to the latest version 🚀 [#1423](https://github.com/storybookjs/storybook/pull/1423)\n- Pin gatsby version and upgrade gh-pages [#1462](https://github.com/storybookjs/storybook/pull/1462)\n\n## 3.1.8\n\n2017-July-06\n\n#### Documentation\n\n- Updated addon knob readme. [#1406](https://github.com/storybookjs/storybook/pull/1406)\n- Add a FAQ entry for shared config with next [#1390](https://github.com/storybookjs/storybook/pull/1390)\n- Documented webpack customization example for typescript [#1386](https://github.com/storybookjs/storybook/pull/1386)\n\n#### Maintenance\n\n- Removed empty array, since webpack 2 doesn't support them anymore. [#1381](https://github.com/storybookjs/storybook/pull/1381)\n\n#### Dependency Upgrades\n\n- Support webpack 3.0.0 [#1410](https://github.com/storybookjs/storybook/pull/1410)\n- Update react inspector to fix #1385 [#1408](https://github.com/storybookjs/storybook/pull/1408)\n\n## 3.1.7\n\n2017-June-28\n\n#### Bug Fixes\n\n- Exit storybook build non-zero on stats errors (e.g. errors in the transpilation pipeline) [#1372](https://github.com/storybookjs/storybook/pull/1372)\n- Fixed regression: CSS entries were not picked up for storybook pages (e.g. when using extract-text-webpack-plugin) [#1363](https://github.com/storybookjs/storybook/pull/1363)\n\n#### Documentation\n\n- Document Storybook release process [#1348](https://github.com/storybookjs/storybook/pull/1348)\n\n## 3.1.6\n\n2017-June-26\n\n#### Bug Fixes\n\n- Remove the `cacheDirectory` option from babel config [#1350](https://github.com/storybookjs/storybook/pull/1350)\n- websockets (ws) removed `socket.upgradeReq`, so use `req` instead [#1337](https://github.com/storybookjs/storybook/pull/1337)\n- Ensure we add the correct version of `react-dom` [#1349](https://github.com/storybookjs/storybook/pull/1349)\n- Addon Info: Fix invalid prop `node.type` supplied to 'Props' [#1351](https://github.com/storybookjs/storybook/pull/1351)\n- Addon Info: Omit empty inline info header [#1306](https://github.com/storybookjs/storybook/pull/1306)\n- Addon Actions: Use uuid for action IDs instead of Math.random (fixes #1109) [#1347](https://github.com/storybookjs/storybook/pull/1347)\n\n#### Documentation\n\n- Fix welcome instructions to reflect current `getstorybook` [#1358](https://github.com/storybookjs/storybook/pull/1358)\n- Addon Info: Update README with configuration instructions [#1326](https://github.com/storybookjs/storybook/pull/1326)\n\n#### Dependency Upgrades\n\n- Update lint-staged to the latest version 🚀 [#1315](https://github.com/storybookjs/storybook/pull/1315)\n\n## 3.1.5\n\n2017-June-22\n\n#### Features\n\n- Added flow support to getstorybook upgrade [#1289](https://github.com/storybookjs/storybook/pull/1289)\n- Added support for the `haul` react-native packager [#1294](https://github.com/storybookjs/storybook/pull/1294)\n\n#### Bug Fixes\n\n- Fixed addon knobs proptypes deserialization [#1290](https://github.com/storybookjs/storybook/pull/1290)\n\n#### Documentation\n\n- Added search to docs [#1256](https://github.com/storybookjs/storybook/pull/1256)\n- snapshot testing inverse regex example documentation [#1317](https://github.com/storybookjs/storybook/pull/1317)\n\n#### Maintenance\n\n- Refactored storybook component library [#1266](https://github.com/storybookjs/storybook/pull/1266)\n- Created CRA kitchen sink addons example [#1288](https://github.com/storybookjs/storybook/pull/1288)\n- Use a pack -> install technique to recreate local packages [#1332](https://github.com/storybookjs/storybook/pull/1332)\n- Import demo components from @storybook/react [#1303](https://github.com/storybookjs/storybook/pull/1303)\n\n## 3.1.4\n\n2017-June-15\n\n#### Features\n\n- IMPROVE design of addon-events [#1249](https://github.com/storybookjs/storybook/pull/1249)\n- Add a `shallowSnapshot` option for storyshots `test` functions [#1232](https://github.com/storybookjs/storybook/pull/1232)\n\n#### Bug Fixes\n\n- Fix app entry bug in RN gestorybook [#1280](https://github.com/storybookjs/storybook/pull/1280)\n- fix(addons/info): Cannot read property 'props' of undefined [#1258](https://github.com/storybookjs/storybook/pull/1258)\n\n#### Documentation\n\n- Add versions plugin to docs [#1269](https://github.com/storybookjs/storybook/pull/1269)\n\n## 3.1.3\n\n2017-June-10\n\n#### Bug Fixes\n\n- Fix `storybook-build` manager-head.html bug [#1248](https://github.com/storybookjs/storybook/pull/1248)\n\n## 3.1.2\n\nMinor features including a new \"events\" addon, as well as the usual bugfixes, cleanup, etc.\n\n2017-June-09\n\n#### Features\n\n- Add small design update to addon info package [#1213](https://github.com/storybookjs/storybook/pull/1213)\n- Add display configuration options to info addon [#1157](https://github.com/storybookjs/storybook/pull/1157)\n- Add support for multiple webpack chunks in iframe [#1083](https://github.com/storybookjs/storybook/pull/1083)\n- Add events addon [#1130](https://github.com/storybookjs/storybook/pull/1130)\n- Allow including files just before manager.bundle.js [#1134](https://github.com/storybookjs/storybook/pull/1134)\n\n#### Bug Fixes\n\n- Fixed knobs addon editing bug [#1233](https://github.com/storybookjs/storybook/pull/1233)\n- Fix bug in addons/graphql in reIndentQuery [#1207](https://github.com/storybookjs/storybook/pull/1207)\n- Marksy initialized with mtrcConf instead of marksyConf [#1205](https://github.com/storybookjs/storybook/pull/1205)\n\n#### Documentation\n\n- Document stories not showing up on storybook UI until device connects [#1221](https://github.com/storybookjs/storybook/pull/1221)\n- Fixed references to storybook.js.org. [#1211](https://github.com/storybookjs/storybook/pull/1211)\n- Updated repository URL to address broken npm images [#1197](https://github.com/storybookjs/storybook/pull/1197)\n\n#### Maintenance\n\n- Added a vanilla React Native example app. [#1202](https://github.com/storybookjs/storybook/pull/1202)\n- Move typings for @storybook/react to @types package [#1199](https://github.com/storybookjs/storybook/pull/1199)\n- Set ESlint rules more strict 🚑 [#911](https://github.com/storybookjs/storybook/pull/911)\n\n#### Dependency Upgrades\n\n- Update babel docgen plugin to generate docs for React.createClass and createReactClass [#1206](https://github.com/storybookjs/storybook/pull/1206)\n- Update `marksy` dependency due broken 1.1.0 version [#1204](https://github.com/storybookjs/storybook/pull/1204)\n\n## 3.0.1\n\nMinor bug fixes and documentation updates post 3.0.0 release.\n\n2017-June-06\n\n#### Bug Fixes\n\n- Added error message for `addon-options` [#1194](https://github.com/storybookjs/storybook/pull/1194)\n- Fix(react-native) add missing `ws` dependency [#1174](https://github.com/storybookjs/storybook/pull/1174)\n- Fix terminal colors by reset console colors explicitly [#1184](https://github.com/storybookjs/storybook/pull/1184)\n- Fix addon panel layout styling [#1170](https://github.com/storybookjs/storybook/pull/1170)\n- ADD https import & remove tracking code remains [#1176](https://github.com/storybookjs/storybook/pull/1176)\n- Fix incorrect babel config file reading [#1156](https://github.com/storybookjs/storybook/pull/1156)\n- Fixed withKnobs definition. [#1164](https://github.com/storybookjs/storybook/pull/1164)\n\n#### Documentation\n\n- Fixed typo in react-native browser instructions [#1189](https://github.com/storybookjs/storybook/pull/1189)\n- Add instruction for npm install with -D for development dependency [#1168](https://github.com/storybookjs/storybook/pull/1168)\n- Fix broken link for `addons` in README [#1167](https://github.com/storybookjs/storybook/pull/1167)\n- Refreshed logo in docs [#1149](https://github.com/storybookjs/storybook/pull/1149)\n- fix addon broken links in documentation [#1165](https://github.com/storybookjs/storybook/pull/1165)\n- start-storybook cli - expand commands descriptions [#1161](https://github.com/storybookjs/storybook/pull/1161)\n- Fix typo in codemod readme [#1158](https://github.com/storybookjs/storybook/pull/1158)\n\n#### Dependency Upgrades\n\n- Replaced deprecated `markdown-to-react-components` with `marksy` [#1188](https://github.com/storybookjs/storybook/pull/1188)\n\n## 3.0.0\n\nStorybook 3.0 is our first fully community-driven release! Notable changes:\n\n- Moved from `@kadira` to `@storybooks` org across [github](https://github.com/storybookjs/storybook/), [npm](https://www.npmjs.com/package/@storybook/react), [docs](https://storybook.js.org/)\n- Upgraded to Webpack2! [#637](https://github.com/storybookjs/storybook/pull/637)\n- Switched to monorepo and overhauled package structure. [#749](https://github.com/storybookjs/storybook/pull/749) [#1031](https://github.com/storybookjs/storybook/pull/1031)\n- Added configuration options to storybooks snapshot testing. [#1090](https://github.com/storybookjs/storybook/pull/1090)\n- Added `create-react-native-app` support. [#1117](https://github.com/storybookjs/storybook/pull/1117)\n- Added HTTPS support. [#735](https://github.com/storybookjs/storybook/pull/735)\n\n2017-May-31\n\n#### Features\n\n- Added help text to the react-native preview panel [#1142](https://github.com/storybookjs/storybook/pull/1142)\n- Added create-react-native-app support [#1117](https://github.com/storybookjs/storybook/pull/1117)\n- Fixed knobs-addon performance issues [#1039](https://github.com/storybookjs/storybook/pull/1039)\n- Added `snapshotWithOptions` to configure storyshots rendering options [#1090](https://github.com/storybookjs/storybook/pull/1090)\n- Added custom `test` function for storyshots [#1035](https://github.com/storybookjs/storybook/pull/1035)\n- Added typescript definition to addon notes [#989](https://github.com/storybookjs/storybook/pull/989)\n- Added HTTPS option for dev server [#735](https://github.com/storybookjs/storybook/pull/735)\n\n#### Bug Fixes\n\n- Use strict equality in action logger [#1144](https://github.com/storybookjs/storybook/pull/1144)\n- FIX addon info and addon storyshots incompatibility [#1129](https://github.com/storybookjs/storybook/pull/1129)\n- FIX postcss options missing in default webpack config && UPDATE dependencies [#1087](https://github.com/storybookjs/storybook/pull/1087)\n- Fix CLI had a package version from storybook hardcoded - now queries npm registry [#1079](https://github.com/storybookjs/storybook/pull/1079)\n- Fix semi broken \\_\\_docgenInfo integration in addon info [#1030](https://github.com/storybookjs/storybook/pull/1030)\n- Fix: build-storybook no longer supports relative paths [#1058](https://github.com/storybookjs/storybook/pull/1058)\n- Fix for types `number` for addon knobs [#1001](https://github.com/storybookjs/storybook/pull/1001)\n- Fix webpack overriding && Add an example with local file dependencies [#965](https://github.com/storybookjs/storybook/pull/965)\n\n#### Documentation\n\n- Add storybook-addon-intl to addon gallery [#1143](https://github.com/storybookjs/storybook/pull/1143)\n- 3.0.0 release notes && release notes automation [#1047](https://github.com/storybookjs/storybook/pull/1047)\n- 3.0.0 migration assistance : codemod, update installation and usage instructions [#1093](https://github.com/storybookjs/storybook/pull/1093)\n- Add ReactSVGPanZoom to examples list [#1139](https://github.com/storybookjs/storybook/pull/1139)\n- Show webpack 2 config example in docs: rules not loaders [#1137](https://github.com/storybookjs/storybook/pull/1137)\n- Merge docs repo into this repo: add /docs [#1131](https://github.com/storybookjs/storybook/pull/1131)\n- Change brand name from “React Storybook” to “Storybook” [#1044](https://github.com/storybookjs/storybook/pull/1044)\n- Updated issue triage guidelines [#1024](https://github.com/storybookjs/storybook/pull/1024)\n\n#### Maintenance\n\n- Add typings for links add-on [#1154](https://github.com/storybookjs/storybook/pull/1154)\n- Add react-dom to the devDependency list for React Native projects [#1102](https://github.com/storybookjs/storybook/pull/1102)\n- Upgrade React Native to webpack 2 config [#1097](https://github.com/storybookjs/storybook/pull/1097)\n- Add unit tests for addon storyshots [#971](https://github.com/storybookjs/storybook/pull/971)\n- Deprecate builtin addons (links and actions) - no longer included by default [#1038](https://github.com/storybookjs/storybook/pull/1038)\n- change NPM organisation from kadira to storybook in code [#996](https://github.com/storybookjs/storybook/pull/996)\n- CHANGE folder structure && CHANGE package-names [#1031](https://github.com/storybookjs/storybook/pull/1031)\n- Add deprecation warnings when addons are required via main package [#1025](https://github.com/storybookjs/storybook/pull/1025)\n- Remove text transform uppercase for knob labels [#991](https://github.com/storybookjs/storybook/pull/991)\n\n#### Dependency Upgrades\n\n<details>\n<summary>\n11 PRs\n</summary>\n\n- Update lerna to the latest version 🚀 [#1101](https://github.com/storybookjs/storybook/pull/1101)\n- CHANGE to prop-types package for notes & test-cra [#1082](https://github.com/storybookjs/storybook/pull/1082)\n- update dependencies in cra-storybook [#1080](https://github.com/storybookjs/storybook/pull/1080)\n- Switch back to non-fork of react-inspector [#1026](https://github.com/storybookjs/storybook/pull/1026)\n- Dependency updates: webpack, babel, react [#1008](https://github.com/storybookjs/storybook/pull/1008)\n- Update jest to the latest version 🚀 [#998](https://github.com/storybookjs/storybook/pull/998)\n- Update lerna to the latest version 🚀 [#969](https://github.com/storybookjs/storybook/pull/969)\n- CHANGE to use react-split-view 0.1.63 over the fork [#956](https://github.com/storybookjs/storybook/pull/956)\n- Update lerna to the latest version 🚀 [#915](https://github.com/storybookjs/storybook/pull/915)\n- Use jest for unittesting - standardize unit testing epic [#904](https://github.com/storybookjs/storybook/pull/904)\n- Update dependencies to enable Greenkeeper 🌴 [#768](https://github.com/storybookjs/storybook/pull/768)\n\n</details>\n\n#### Other\n\n<details>\n<summary>\n33 PRs\n</summary>\n\n- Added an upgrade mode to getstorybook [#1146](https://github.com/storybookjs/storybook/pull/1146)\n- Update link to Storyshots addon [#1074](https://github.com/storybookjs/storybook/pull/1074)\n- Added error message for missing or invalid storyName [#747](https://github.com/storybookjs/storybook/pull/747)\n- Opened an Open Collective Account <https://opencollective.com/storybook> [#1065](https://github.com/storybookjs/storybook/pull/1065)\n- Add propTablesExclude option [#924](https://github.com/storybookjs/storybook/pull/924)\n- addon-info: make the info overlay be fixed [#914](https://github.com/storybookjs/storybook/pull/914)\n- Handle null elements in getData [#926](https://github.com/storybookjs/storybook/pull/926)\n- add description field from \\_\\_docgenInfo for prop table for info plugin [#929](https://github.com/storybookjs/storybook/pull/929)\n- \\#959 add a max-height and center element with alignItems: center [#961](https://github.com/storybookjs/storybook/pull/961)\n- Switch to the only prepublish script [#903](https://github.com/storybookjs/storybook/pull/903)\n- PR review policy [#923](https://github.com/storybookjs/storybook/pull/923)\n- Add typescript definitions for getStorybook() [#753](https://github.com/storybookjs/storybook/pull/753)\n- Restore deep link for addon docs [#919](https://github.com/storybookjs/storybook/pull/919)\n- Fix default storybook webpack config [#922](https://github.com/storybookjs/storybook/pull/922)\n- Render the first story for a kind if no story selected. [#918](https://github.com/storybookjs/storybook/pull/918)\n- Update docs for monorepo [#913](https://github.com/storybookjs/storybook/pull/913)\n- Monorepo readme and contributing [#907](https://github.com/storybookjs/storybook/pull/907)\n- Add story kind regex [#906](https://github.com/storybookjs/storybook/pull/906)\n- Add examples [#897](https://github.com/storybookjs/storybook/pull/897)\n- Add missing repos [#882](https://github.com/storybookjs/storybook/pull/882)\n- Switch to monorepo [#749](https://github.com/storybookjs/storybook/pull/749)\n- extend devMiddlewareOptions with config.devServer [#723](https://github.com/storybookjs/storybook/pull/723)\n- Added meta IE=edge [#715](https://github.com/storybookjs/storybook/pull/715)\n- Replace String.includes with String.indexOf: cross-browsing support [#712](https://github.com/storybookjs/storybook/pull/712)\n- Issue Triage instructions [#748](https://github.com/storybookjs/storybook/pull/748)\n- Simple pull request template [#741](https://github.com/storybookjs/storybook/pull/741)\n- Make return type of StoryDecorator nullable [#680](https://github.com/storybookjs/storybook/pull/680)\n- Warn if story with a given name already exists [#670](https://github.com/storybookjs/storybook/pull/670)\n- Fix spelling mistake - \"element form the story\" to \"element from the story\" [#702](https://github.com/storybookjs/storybook/pull/702)\n- Remove broken react-button example [#699](https://github.com/storybookjs/storybook/pull/699)\n- Fixed spelling error. [#720](https://github.com/storybookjs/storybook/pull/720)\n- Cleaner error handling for storiesOf [#672](https://github.com/storybookjs/storybook/pull/672)\n- Update links to point to new organization [#721](https://github.com/storybookjs/storybook/pull/721)\n\n</details>\n\n## v2.35.3\n\nAllow customConfig to override devtool. [PR668](https://github.com/storybookjs/storybook/pull/668)\n\n## v2.35.2\n\n03-January-2017\n\nFixes issue [#601](https://github.com/storybookjs/storybook/issues/601) where it throws error when introduce a propType with a hyphen. Add a [fix](https://github.com/kadirahq/babel-plugin-react-docgen/pull/23) to [`babel-plugin-react-docgen`](https://github.com/kadirahq/babel-plugin-react-docgen) to fix this issue.\n\nThis release comes with the updated `babel-plugin-react-docgen`.\n\n## v2.35.1\n\n- Revert [PR653](https://github.com/storybookjs/storybook/pull/653) where it's causing HMR to not working properly.\n\n## v2.35.0\n\n18-December-2016\n\n- Using file-loader to load all the extensions [PR653](https://github.com/storybookjs/storybook/pull/653)\n- Update css-loader dependency [PR648](https://github.com/storybookjs/storybook/pull/648)\n- Check if stories are loaded from Jest [PR644](https://github.com/storybookjs/storybook/pull/644)\n\n## v2.34.0\n\n05-December-2016\n\nOpen the express router for developers (middleware.js file). [PR435](https://github.com/storybookjs/storybook/pull/435)\n\n## v2.33.1\n\n01-December-2016\n\nUpdate Typescript definition file for global addDecorator. [PR634](https://github.com/storybookjs/storybook/pull/634)\n\n## v2.33.0\n\n28-November-2016\n\nCompletely avoid re-rendering the preview iframe. [PR631](https://github.com/storybookjs/storybook/pull/631)\n\n## v2.32.2\n\n28-November-2016\n\nUpdate postmsg channel module version [PR627](https://github.com/storybookjs/storybook/pull/627)\n\n## v2.32.1\n\n22-November-2016\n\nAdd support for react_perf comes with React 15.4.0. [PR623](https://github.com/storybookjs/storybook/pull/623)\n\n## v2.32.0\n\nIncorrect publish (error when running `npm publish`)\n\n## v2.31.0\n\n20-November-2016\n\nAdd the react-storybook version to the build output. [PR621](https://github.com/storybookjs/storybook/pull/621)\n\n## v2.30.1\n\n17-November-2016\n\nUpdate the postmsg channel module to fix issue [#555](https://github.com/storybookjs/storybook/issues/555) with [PR611](https://github.com/storybookjs/storybook/pull/611)\n\n## v2.30.0\n\n16-November-2016\n\nUpdate to the new Storybook UI which doesn't use Redux.\n\n## v2.29.7\n\n11-November-2016\n\nUpdate @kadira/storybook-ui to the latest.\n\n## v2.29.6\n\n10-November-2016\n\nFix a typo in the story syntax error messages. [PR610](https://github.com/storybookjs/storybook/pull/610)\n\n## v2.29.5\n\n09-November-2016\n\nCheck if regex and regex.test is available before calling it. [PR608](https://github.com/storybookjs/storybook/pull/608)\n\n## v2.29.3\n\n08-November-2016\n\nUpdate webpack-hot-middleware to version 2.13.2 to fix the issue [#543](https://github.com/storybookjs/storybook/issues/543).\n\n## v2.29.3\n\n03-November-2016\n\nFix a regression caused by v2.29.2.\nThere was a text called undefined listed always on the top of the preview.\n\n## v2.29.2\n\n03-November-2016\n\nAdd various fixes.\n\n- Use webpack chunkhash to enable long-term caching. [PR597](https://github.com/storybookjs/storybook/pull/597)\n- Fixed json loader testing for when test is multiple. [PR598](https://github.com/storybookjs/storybook/pull/598)\n- Fix usage of custom favicon [PR592](https://github.com/storybookjs/storybook/pull/592)\n- Update postcss-loader to v1.1.0 [PR599](https://github.com/storybookjs/storybook/pull/599)\n- fix for `module.hot` is not available in a static build [PR600](https://github.com/storybookjs/storybook/pull/600)\n\n## v2.29.1\n\n03-November-2016\n\nUpdate babel-plugin-react-docgen to v1.4.1 to fix HOC [issue](https://github.com/kadirahq/babel-plugin-react-docgen/issues/19)\n\n## v2.29.0\n\n01-November-2016\n\nUpdate babel-plugin-react-docgen to 1.4.0.\nThis will fix some of the compilation issues such as #580.\n\n## v2.28.1\n\n28-October-2016\n\nRemove preview decorator support. [PR583](https://github.com/storybookjs/storybook/pull/583).\n\n## v2.28.0\n\n28-October-2016\n\nAdd preview decorator support. [PR582](https://github.com/storybookjs/storybook/pull/582).\nThis will help us bring storybook designer with some great power.\n\n## v2.27.0\n\n27-October-2016\n\nAdd a few usability improvements to Storybook.\n\n- Display storybook version. [PR559](https://github.com/storybookjs/storybook/pull/559)\n- Make the storybooks cacheable. [PR578](https://github.com/storybookjs/storybook/pull/578)\n- Change the devtool to eval and remove the use of source maps. [PR577](https://github.com/storybookjs/storybook/pull/577)\n- Update `babel-preset-react-app` to the latest. [PR576](https://github.com/storybookjs/storybook/pull/576)\n- Ship `json-loader` by default. [PR575](https://github.com/storybookjs/storybook/pull/575)\n\n## v2.26.0\n\n24-October-2016\n\nGet some new features from CRA.\n\n- Add jsx as a resolve extension [PR563](https://github.com/storybookjs/storybook/pull/563)\n- Allow to use postcss for CSS @imports [PR564](https://github.com/storybookjs/storybook/pull/564)\n- Use process.env as a proper object [PR565](https://github.com/storybookjs/storybook/pull/565)\n\n## v2.25.1\n\n23-October-2016\n\nAdd a potential fix to [558](https://github.com/storybookjs/storybook/issues/558) by updating babel-plugin-react-docgen to the latest(v1.3.2).\n\n## v2.25.0\n\n21-October-2016\n\nAdd react docgen info into React classes with the react-docgen babel plugin. [PR557](https://github.com/storybookjs/storybook/pull/557).\nWith this:\n\n- We could get docgen info with any React component class using `ClassName.__docgenInfo`.\n- From the global collection: `STORYBOOK_REACT_CLASSES`\n\nAdditionally, added `yarn.lock`.\n\n## v2.24.1\n\n19-October-2016\n\nDo not show git command output. [PR554](https://github.com/storybookjs/storybook/pull/554)\n\n## v2.24.0\n\n07-October-2016\n\n- Export git repository info to support custom tool integrations [PR536](https://github.com/storybookjs/storybook/pull/536)\n\n## v2.23.0\n\n06-October-2016\n\n- Remove the experimental database addon from react-storybook [PR535](https://github.com/storybookjs/storybook/pull/535)\n\n## v2.22.0\n\n05-October-2016\n\nAdd some nice development experiment based on suggestion from Dan Abramov.\n\n- Set a color to the Storybook URL in the console. [PR533](https://github.com/storybookjs/storybook/pull/533)\n- Add better error message when there's no React element in the story. [PR534](https://github.com/storybookjs/storybook/pull/534)\n\n## v2.21.0\n\n05-October-2016\n\n- Get the latest features from CRA including NODE_PATH support, public folder support and some other minor changes. [#468](https://github.com/storybookjs/storybook/issues/468)\n- Also bumped `@kadira/storybook-channel-postmsg` to `^1.0.3`\n\n## v2.20.1\n\n28-September-2016\n\n- Fix story kind order bug [PR499](https://github.com/storybookjs/storybook/pull/499)\n- Prefix config environment variables [PR503](https://github.com/storybookjs/storybook/pull/503)\n\n## v2.20.0\n\n26-September-2016\n\n- Use postMessage channel [PR498](https://github.com/storybookjs/storybook/pull/498)\n- Support dynamic panel titles [PR497](https://github.com/storybookjs/storybook/pull/497)\n\n## v2.19.0\n\n26-September-2016\n\n- Support layout options [PR494](https://github.com/storybookjs/storybook/pull/494)\n- Update Typescript definitions [PR491](https://github.com/storybookjs/storybook/pull/491) and [PR493](https://github.com/storybookjs/storybook/pull/493)\n\n## v2.18.1\n\n23-September-2016\n\n- Stop uglifyjs from mangling names [PR483](https://github.com/storybookjs/storybook/pull/483)\n\n## v2.18.0\n\n23-September-2016\n\n- Remove `STORYBOOK_` prefix from config env [PR481](https://github.com/storybookjs/storybook/pull/481)\n\n## v2.17.0\n\n22-September-2016\n\n- Add support for StoryShots. [PR479](https://github.com/storybookjs/storybook/pull/479)\n- Fix some typos: [PR477](https://github.com/storybookjs/storybook/pull/477) & [PR478](https://github.com/storybookjs/storybook/pull/478)\n\n## v2.16.1\n\n21-September-2016\n\n- Fix the 404 error for `addon-db.json` file [PR472](https://github.com/storybookjs/storybook/pull/472)\n- Serve/Bundle the storybook favicon [PR473](https://github.com/storybookjs/storybook/pull/473)\n\n## v2.16.0\n\n21-September-2016\n\n- Move the babel config loading logic into a separate file. [PR469](https://github.com/storybookjs/storybook/pull/469)\n- Update airbnb eslint rules to the latest.\n\n## v2.15.1\n\n19-September-2016\n\nAdd a fix to webpack custom resolve.alias not working. [PR465](https://github.com/storybookjs/storybook/pull/465)\n\n## v2.15.0\n\n19-September-2016\n\n- Use @kadira/storybook-addons as a resolve.alias. So, we can support addons for NPM2 too. [PR462](https://github.com/storybookjs/storybook/pull/462)\n\n## v2.14.0\n\n14-September-2016\n\n- Watch missing NPM modules and force webpack rebuild. [PR446](https://github.com/storybookjs/storybook/pull/446)\n- Fix issue on error message hanging after even it solved. [PR447](https://github.com/storybookjs/storybook/pull/447)\n- Allow to reload if HMR goes crazy. [PR448](https://github.com/storybookjs/storybook/pull/448)\n- Add support to get custom env variables. [PR450](https://github.com/storybookjs/storybook/pull/450)\n\n## v2.13.1\n\n14-September-2016\n\n- Fix 404 error when db file does not exist [PR449](https://github.com/storybookjs/storybook/pull/449)\n\n## v2.13.0\n\n9-September-2016\n\n- Fix [#443](https://github.com/storybookjs/storybook/issues/443) where the static version of Storybook doesn't like Safari.\n- Update postcss-loader to 0.13.0.\n\n## v2.12.1\n\n8-September-2016\n\n- Parse static directory provided by env as a list. [PR436](https://github.com/storybookjs/storybook/pull/436)\n\n## v2.12.0\n\n8-September-2016\n\n- Do not include addon register file on preview. [PR426](https://github.com/storybookjs/storybook/pull/426)\n- Update css-loader to version 0.25.0. [PR427](https://github.com/storybookjs/storybook/pull/427)\n- Get the head.html values for every page request. [PR432](https://github.com/storybookjs/storybook/pull/432)\n\n## v2.11.0\n\n4-September-2016\n\n- Remove babel-polyfill since we don't use it.\n- Update versions with the help from greenkeeper. [PR421](https://github.com/storybookjs/storybook/pull/421)\n\n## v2.10.0\n\n3-September-2016\n\n- Adding airbnb-js-shims again. [PR419](https://github.com/storybookjs/storybook/pull/419)\n\n## v2.9.1\n\n2-September-2016.\n\n- Use the config directory to store the addon database file [PR418](https://github.com/storybookjs/storybook/pull/418).\n\n## v2.9.0\n\n2-September-2016.\n\n- Copy the addon-db.json file when building static storybooks [PR417](https://github.com/storybookjs/storybook/pull/417).\n\n## v2.8.0\n\n2-September-2016.\n\n- Update @kadira/storybook to get the clean query params feature. See [storybook-ui-PR37](https://github.com/kadirahq/storybook-ui/pull/37)\n\n## v2.7.0\n\n1-September-2016\n\n- Add addon database feature [PR415](https://github.com/storybookjs/storybook/pull/415).\n\n## v2.6.1\n\n31-August-2016\n\n- Bring back HMR dev logs. [PR412](https://github.com/storybookjs/storybook/pull/412).\n\n## v2.6.0\n\n30-August-2016\n\n- Allow start/build params from env variables. [PR413](https://github.com/storybookjs/storybook/pull/413)\n\n## v2.5.2\n\n29-August-2016\n\n- Remove the use of babel-runtime/core-js modules. [PR410](https://github.com/storybookjs/storybook/pull/410)\n\n## v2.5.1\n\n24-August-2016\n\n- Update @kadira/storybook-ui to v3.3.2\n\n## v2.5.0\n\n24-August-2016\n\n- We are no longer shipping extra polyfills anymore. [PR402](https://github.com/storybookjs/storybook/pull/402)\n\n## v2.4.2\n\n24-August-2016\n\n- Allow file-loader URLs to work on subpaths. [PR401](https://github.com/storybookjs/storybook/pull/401)\n\n## v2.4.1\n\n24-August-2016\n\n- Bump @kadira/storybook ui to v3.3.1 to fix some UI related issues.\n\n## v2.4.0\n\n23-August-2016\n\n- Simplify the option to stop tracking. [PR399](https://github.com/storybookjs/storybook/pull/399)\n- Use JSON5 instead of CJSON to parse .babelrc. [PR398](https://github.com/storybookjs/storybook/pull/398)\n- Add webpack2 support by changing the use of OccurenceOrderPlugin. [PR397](https://github.com/storybookjs/storybook/pull/397)\n- Use @kadira/storybook-ui 2.3.0, which has new APIs to set URL for addons.\n\n## v2.3.0\n\n16-August-2016\n\n- Implement anonymous usage tracking. [PR384](https://github.com/storybookjs/storybook/pull/384)\n\n## v2.2.3\n\n15-August-2016\n\n- Add a hash to media file's filename. Otherwise, it'll cause issues when there are multiple images with the same filename but in different directories. [PR380](https://github.com/storybookjs/storybook/pull/380)\n\n## v2.2.2\n\n10-August-2016\n\n- Remove unused extract-text-webpack-plugin. This will add webpack2 support. [PR369](https://github.com/storybookjs/storybook/pull/369).\n\n## v2.2.1\n\n09-August-2016\n\n- Use @kadira/storybook-channel modules. [#PR359](https://github.com/storybookjs/storybook/pull/359).\n- Update @kadira/storybook-ui to the latest.\n\n## v2.2.0\n\n05-August-2016\n\nThis release bring some webpack config related optimizations and the NPM2 support. Here are the notable changes:\n\n- Use es6-shim directly into webpack config. [PR355](https://github.com/storybookjs/storybook/pull/355)\n- Use the default babel-config based on CRA's config. [PR354](https://github.com/storybookjs/storybook/pull/354)\n- Add NPM2 support. [PR356](https://github.com/storybookjs/storybook/pull/356)\n- Add autofixer defaults. [PR357](https://github.com/storybookjs/storybook/pull/357)\n\n## v2.1.1\n\n03-August-2016\n\nRemove default webpack config for all config types. [PR348](https://github.com/storybookjs/storybook/pull/348)\n\nNow we only use the Create React App based config if there's no custom webpack config.\nThis will fix issues like [#347](https://github.com/storybookjs/storybook/issues/347).\n\n## v2.1.0\n\n02-August-2016\n\nAdd support for the addon API. See [PR346](https://github.com/storybookjs/storybook/pull/346).\n\nHere after we are using most of the features including actions,links as plugins.\nSo, this introduced a huge area to add customizations to Storybook.\n\nUnfortunately, as of this version, there are no docs for this feature. But, you can have a look at these addons:\n\n- actions addon (powers the action logger): [addon-actions](https://github.com/kadirahq/storybook-addon-actions)\n- links addon (powers the linkTo feature): [addon-links](https://github.com/kadirahq/storybook-addon-links)\n\nHave a look at [here](https://github.com/storybookjs/storybook/blob/master/src/server/config.js#L88) to how to configure addons.\n\n## v2.0.0\n\n01-August-2016\n\nThis is the starting of the next major version of Storybook. This version is almost compatible with `v1.x.x` but defaults have been changes as discussed below. That's why we are starting out a new version.\n\n- Update defaults to match create-react-app. [PR342](https://github.com/storybookjs/storybook/pull/342). Here are the notable changes:\n  - Add postcss based CSS loader.\n  - Add file-loader for images and common types.\n  - Add url-loader for shorter media files.\n  - Do not pre-build manager(storybook UI) bundle.\n  - Continue support for babel's stage-0 preset and add es2016 preset.\n- Update @kadira/storybook-ui to v2.6.1 to remove some React warnings.\n\n## v1.41.0\n\n- Fix nodejs require errors [#337](https://github.com/storybookjs/storybook/pull/337).\n- Add getStorybook method to client API [#332](https://github.com/storybookjs/storybook/pull/332).\n\n## v1.40.0\n\n- Fix duplicate decorator bug [#335](https://github.com/storybookjs/storybook/pull/335).\n\n## v1.39.1\n\n- Update babel packages [#325](https://github.com/storybookjs/storybook/pull/325).\n- Hide HMR info logs [#331](https://github.com/storybookjs/storybook/pull/331).\n\n## v1.39.0\n\n- Update @kadira/storybook-ui to get features from [v2.5.0](https://github.com/kadirahq/storybook-ui/blob/master/CHANGELOG.md#v250) and [v2.6.0](https://github.com/kadirahq/storybook-ui/blob/master/CHANGELOG.md#v260).\n\n## v1.38.3\n\n- Add names for action and linkTo functions [#321](https://github.com/storybookjs/storybook/pull/321).\n\n## v1.38.2\n\n- Fix error in prepublish script [#319](https://github.com/storybookjs/storybook/pull/319).\n\n## v1.38.1\n\n- Improve Windows support by writing prepublish script using shelljs [#308](https://github.com/storybookjs/storybook/pull/308).\n\n## v1.38.0\n\n- v1.37.0 was a nightmare since it contains the npm-shrinkwrap.json. Fixed by removing it. See: [#306](https://github.com/storybookjs/storybook/issues/306) and [#305](https://github.com/storybookjs/storybook/pull/305).\n\n## v1.37.0\n\n- Update @kadira/storybook-ui to 2.4.0\n\n## v1.36.0\n\n- Support watchOptions configuration. See: [PR287](https://github.com/storybookjs/storybook/pull/287)\n\n## v1.35.2\n\n- Add missing font-face to the ErrorDisplay's heading.\n\n## v1.35.1\n\n- Fix issue related to bad error handling. See issue [#275](https://github.com/storybookjs/storybook/issues/275):\n\n## v1.35.0\n\n- Add fuzzy search powered search box and Redux DevTools support via [@kadira/storybook-ui@2.3.0](https://github.com/kadirahq/storybook-ui/blob/master/CHANGELOG.md#v230).\n\n## v1.34.1\n\n- Don't always override NODE_ENV in build-storybook. [PR272](https://github.com/storybookjs/storybook/pull/272)\n\n## v1.34.0\n\n- Use storybook-ui v2.2.0 which puts shortcut state into the URL.\n\n## v1.33.0\n\n- Introduce an [extension API](https://github.com/storybookjs/storybook/blob/master/docs/extensions.md) for Storybook. See: [PR258](https://github.com/storybookjs/storybook/pull/258)\n\n## v1.32.1\n\n- Extend @kadira/storybook-ui provider from it's base Provider.\n\n## v1.32.0\n\n- Use @kadira/storybook-ui as the manager UI with the implemented provider for React. See `client/manager` for more info.\n\n## v1.31.0\n\n- Pass a `context` argument to stories [PR250](https://github.com/storybookjs/storybook/pull/250)\n\n## v1.30.0\n\n- Fuzzy search kinds [PR247](https://github.com/storybookjs/storybook/pull/247)\n\n## v1.29.5\n\n- Update dependency version to fix filter crash [PR246](https://github.com/storybookjs/storybook/pull/246)\n\n## v1.29.4\n\n- Protect index.html/iframe.html from being overwritten [PR243](https://github.com/storybookjs/storybook/pull/243)\n\n## v1.29.3\n\n- Update @kadira/storybook-core version [PR241](https://github.com/storybookjs/storybook/pull/241)\n- Add es6-shim by default [PR238](https://github.com/storybookjs/storybook/pull/238)\n\n## v1.29.2\n\n- Use url.resolve instead of path.join [PR240](https://github.com/storybookjs/storybook/pull/240)\n\n## v1.29.1\n\n- Copy missed manager.js.map file on static build [PR236](https://github.com/storybookjs/storybook/pull/236)\n\n## v1.29.0\n\n- Multiple static dirs (comma separated) [PR229](https://github.com/storybookjs/storybook/pull/229)\n\n## v1.28.5\n\n- Support ECMAScript stage-0 [PR228](https://github.com/storybookjs/storybook/pull/228) to fix [Issue #227](https://github.com/storybookjs/storybook/issues/227)\n\n## v1.28.4\n\n- Support custom webpack public path for dev-server and static build started by [PR226](https://github.com/storybookjs/storybook/pull/226)\n\n## v1.28.3\n\n- Revert [PR226](https://github.com/storybookjs/storybook/pull/226)\n\n## v1.28.2\n\n- Support custom webpack publicPath [PR226](https://github.com/storybookjs/storybook/pull/226)\n\n## v1.28.1\n\n- Add charset meta tags to HTML heads [PR216](https://github.com/storybookjs/storybook/pull/216)\n\n## v1.28.0\n\n- Moved storybook serving code into a middleware to support more advanced use cases.\n- Refactored dev server to use storybook middleware [PR211](https://github.com/storybookjs/storybook/pull/211)\n\n## v1.27.0\n\n- Move modules to storybook-core repo. [PR196](https://github.com/storybookjs/storybook/pull/196)\n- Add stack-source-map again only for Chrome to get better error stacks.\n- Add ability to control the hostname. See [PR195](https://github.com/storybookjs/storybook/pull/195) and [PR198](https://github.com/storybookjs/storybook/pull/198)\n\n## v1.26.0\n\n12-May-2016\n\n- Ensure asset directory exists in the static-builder.\n\n## v1.25.0\n\n11-May-2016\n\n- Fix several publishing related issues. See: [#188](https://github.com/storybookjs/storybook/pull/188).\n- Fix babel extends issue. See: [PR185](https://github.com/storybookjs/storybook/pull/185).\n- Fix issue with removing a preset from users babelrc.\n  - Fixes: [#183](https://github.com/storybookjs/storybook/issues/183).\n  - [PR184](https://github.com/storybookjs/storybook/pull/184)\n- Make left panel scrollable with keeping the filterbox always. See: [PR182](https://github.com/storybookjs/storybook/pull/182).\n- Add `qs` as a direct dependency as it's used in preview.\n\n## v1.24.0\n\n10-May-2016\n\n- Add a potential fix for the double scrollbar issue. See: [179](https://github.com/storybookjs/storybook/issues/179).\n- Add scrolling support to the left panel. Fixes [#177](https://github.com/storybookjs/storybook/issues/177).\n- Remove NODE_ENV=production flag. Fixes [#158](https://github.com/storybookjs/storybook/issues/158)\n\n## v1.23.0\n\n09-May-2016\n\n- Add shortcuts to jump to previous and next stories. See [PR176](https://github.com/storybookjs/storybook/pull/176)\n- Fix loader concatenation bug specially when custom config doesn't have a loaders section. [PR173](https://github.com/storybookjs/storybook/pull/173)\n\n## v1.22.1\n\n06-May-2016\n\n- Add a potential fix for [#167](https://github.com/storybookjs/storybook/issues/167)\n  - basically, this moved back babel-packages required by webpack.\n\n## v1.22.0\n\n06-May-2016\n\n- Improve the static builder time.\n\n## v1.21.0\n\n06-May-2016\n\n- Add configType argument to custom config function. See: [PR169](https://github.com/storybookjs/storybook/pull/169)\n- Add the unicode version of the Keyboard Shortcut Icon. See: [PR170](https://github.com/storybookjs/storybook/pull/170)\n\n## v1.20.0\n\n05-May-2016\n\n- Allow to configure webpack as the user wants. See [PR160](https://github.com/storybookjs/storybook/pull/160)\n- Add typescript typings support for the core API. See [PR157](https://github.com/storybookjs/storybook/pull/157)\n- Implement Mantra architecture and some new features including permalinks, full screen support. See: [PR165](https://github.com/storybookjs/storybook/pull/165)\n- Remove some typo in docs. See: [PR154](https://github.com/storybookjs/storybook/pull/154)\n- Move UI testing libraries to devDependencies. See: [PR153](https://github.com/storybookjs/storybook/pull/153)\n\n## v1.19.0\n\n27-April-2016\n\n- Add airbnb-js-shims to client-side JS. See: [PR147](https://github.com/storybookjs/storybook/pull/147)\n- Remove self-closing div tag, which is invalid HTML. See: [PR148](https://github.com/storybookjs/storybook/pull/148)\n- Search for a .babelrc in the storybook config directory first, then the project root. See: [PR149](https://github.com/storybookjs/storybook/pull/149)\n\n## v1.18.0\n\n26-April-2016\n\n- Link Storybook menu to the repo. See: [PR137](https://github.com/storybookjs/storybook/pull/137)\n- Implement keyboard shortcuts and fuzzy search. See: [PR141](https://github.com/storybookjs/storybook/pull/141)\n\n## v1.17.2\n\n25-April-2016\n\n- Fix an error which only occurs on Firefox. See: [PR144](https://github.com/storybookjs/storybook/pull/144)\n\n## v1.17.1\n\n21-April-2016\n\n- Fix a regression introduce by `v1.17.0`. See: [PR133](https://github.com/storybookjs/storybook/pull/133)\n\n## v1.17.0\n\n21-April-2016\n\n- Check all the arguments passed to action for events. See: [PR132](https://github.com/storybookjs/storybook/pull/132)\n\n## v1.16.1\n\n21-April-2016\n\n- Fix action logs highlighting issue, which comes as a regression of [PR126](https://github.com/storybookjs/storybook/pull/126).\n\n## v1.16.0\n\n20-April-2016\n\n- Prevent re-rendering the preview iframe when there is an action.\n  - Related issue: [#116](https://github.com/storybookjs/storybook/issues/116)\n  - Related PR: [PR126](https://github.com/storybookjs/storybook/pull/126)\n\n## v1.15.0\n\n20-April-2016\n\n- Improve action logger UI and increase max log count to 10. See [PR123](https://github.com/storybookjs/storybook/pull/123)\n\n## v1.14.0\n\n19-April-2016\n\n- Add syntax highlights to the logger. See: [PR118](https://github.com/storybookjs/storybook/pull/118)\n\n## v1.13.0\n\n- Add some UI test cases. See [PR103](https://github.com/storybookjs/storybook/pull/103)\n- Implement `.addDecorator()` API. See [PR115](https://github.com/storybookjs/storybook/pull/115)\n- Add code folding support. See [PR111](https://github.com/storybookjs/storybook/pull/111)\n\n## v1.12.0\n\n14-April-2016\n\n- Add support for webpack module preLoaders. See: [PR107](https://github.com/storybookjs/storybook/pull/107)\n\n## v1.11.0\n\n13-April-2016\n\n- Add support for React DevTools. See: [PR104](https://github.com/storybookjs/storybook/pull/104)\n\n## v1.10.2\n\n12-April-2016\n\nFix various issues related to static bundling.\n\n- Add custom head generation to static build as well.\n- Use relative urls so, static sites can be host with paths (GH Pages)\n- Identify SyntheticEvent using feature detection. UglifyJS mangal class names, so we can't use classnames to detect a SyntheticEvent in the static build.\n\n## v1.10.1\n\n- Don't serve index.html in static directory as a site index. See [PR100](https://github.com/storybookjs/storybook/pull/100)\n- Use cjson for parsing .babelrc files (support comments). See [PR98](https://github.com/storybookjs/storybook/pull/98)\n- Remove the dist directory before running babel to avoid older code. See [PR101](https://github.com/storybookjs/storybook/pull/101)\n\n## v1.10.0\n\n- Add custom head support inside the iframe. See [PR77](https://github.com/storybookjs/storybook/pull/77)\n- Unmount components before rendering into DOM node. Fix: [#81](https://github.com/storybookjs/storybook/issues/81)\n- Add a static file builder. See [PR88](https://github.com/storybookjs/storybook/pull/88)\n- Fix search box's lineHeight to work with all the browsers. See: [PR94](https://github.com/storybookjs/storybook/pull/94)\n- Add the search box. See: [PR91](https://github.com/storybookjs/storybook/pull/91).\n\n## v1.9.0\n\nAdd some minor improvements.\n\n- Avoid deprecated warning in Chrome Canary. See: [PR85](https://github.com/storybookjs/storybook/pull/85)\n- Fix the React Warning about CSS property. See: [PR84](https://github.com/storybookjs/storybook/pull/84)\n- Transition on latest logged action. See: [PR80](https://github.com/storybookjs/storybook/pull/80)\n\n## v1.8.0\n\n- Add story linking functionality.\n  - [Documentation](https://github.com/storybookjs/storybook/blob/master/docs/api.md#linking-stories).\n  - Original feature request: [#50](https://github.com/storybookjs/storybook/issues/50)\n  - Implementation: [PR86](https://github.com/storybookjs/storybook/pull/86)\n\n## v1.7.0\n\n- Add support to React v15.0.0.\n\n## v1.6.0\n\n- Make scrollable layout. See: [PR](https://github.com/storybookjs/storybook/pull/70)\n- Add npm3 requirement to the `package.json`.\n- Add `react` and `react-dom` to devDependencies.\n\n## v1.5.0\n\n- Add support for most of the custom webpack configuration. See [PR64](https://github.com/storybookjs/storybook/pull/64)\n\n## v1.4.0\n\n- Add CLI option to specify the config dir. See [PR52](https://github.com/storybookjs/storybook/pull/52).\n\n## v1.3.0\n\n- Load the `.babelrc` manually. Fixed: [#41](https://github.com/storybookjs/storybook/issues/41)\n- Add a better contributing guide. See [CONTRIBUTING.md](https://github.com/storybookjs/storybook/blob/master/CONTRIBUTING.md)\n- Add a development utility `npm run dev` which watches \"src\" directory and run `npm run prepublish`.\n\n## v1.2.0\n\n- Add a button to clear logs in the ActionLogger. This is requested in [PR21](https://github.com/storybookjs/storybook/issues/21).\n- Remove navigation list order hijacking. See [commit](https://github.com/storybookjs/storybook/commit/166365fd38f51f79e69e028a1c11e2620eddcb99).\n- Fix a typo in .gitignore. See [PR31](https://github.com/storybookjs/storybook/pull/31).\n- Add support for JSX. See [PR18](https://github.com/storybookjs/storybook/pull/18).\n\n## v1.1.0\n\n- v1.0.0 was a mistake and it contains very old code. That's why we had to do a 1.1.0 release.\n\n## v1.0.0\n\n- Yeah!\n"
  },
  {
    "path": "CHANGELOG.v6.md",
    "content": "- MDX: Upgrade csf-mdx libraries ([#18300](https://github.com/storybookjs/storybook/pull/18300))\n- security: update x-default-browser ([#18157](https://github.com/storybookjs/storybook/pull/18157))\n\n## 6.5.0-rc.1 (May 18, 2022)\n\n### Bug Fixes\n\n- CLI: Improve webpack version and add detection of nextjs ([#18220](https://github.com/storybookjs/storybook/pull/18220))\n- ArgsTable: Gracefully handle conditional args failures ([#18248](https://github.com/storybookjs/storybook/pull/18248))\n- Controls: Fix reset button broken for !undefined URL values ([#18231](https://github.com/storybookjs/storybook/pull/18231))\n- Vue3: Add support for TSX in single file components ([#18038](https://github.com/storybookjs/storybook/pull/18038))\n\n## 6.5.0-rc.0 (May 17, 2022)\n\n### Features\n\n- Addon-a11y: Show % of users in toolbar menu ([#18003](https://github.com/storybookjs/storybook/pull/18003))\n\n### Bug Fixes\n\n- Web-components: Clean Lit Expression comments in story source ([#18108](https://github.com/storybookjs/storybook/pull/18108))\n- Vue: Map args correctly in CSF3 implicit render function ([#18209](https://github.com/storybookjs/storybook/pull/18209))\n- Vue3: Fix CSF3 implicit render function when storyStoreV7 is enabled ([#18208](https://github.com/storybookjs/storybook/pull/182)\n\n### Maintenance\n\n- CLI: Don't throw is Ctrl + C was pressed when selecting a package in the build command ([#18195](https://github.com/storybookjs/storybook/pull/18195))\n- Build: Cleanup noise from unit tests ([#18196](https://github.com/storybookjs/storybook/pull/18196))\n\n### Dependency Upgrades\n\n- Fixed PnP compatibility for bundled components package ([#18015](https://github.com/storybookjs/storybook/pull/18015))\n\n## 6.5.0-beta.8 (May 11, 2022)\n\n### Bug Fixes\n\n- Composition: Fix metadata.json incorrectly overriding main.js refs versions ([#18185](https://github.com/storybookjs/storybook/pull/18185))\n\n### Maintenance\n\n- Examples: Set channelOptions to disallow function serialization ([#18071](https://github.com/storybookjs/storybook/pull/18071))\n\n### Dependency Upgrades\n\n- Upgrade to telejson 6 ([#18164](https://github.com/storybookjs/storybook/pull/18164))\n\n## 6.5.0-beta.7 (May 9, 2022)\n\n### Features\n\n- CSF3: Add title prefix support for stories with custom titles ([#17724](https://github.com/storybookjs/storybook/pull/17724))\n\n### Bug Fixes\n\n- Components: Fix race conditions in SyntaxHighlighter ([#18158](https://github.com/storybookjs/storybook/pull/18158))\n\n### Maintenance\n\n- API: Deprecate isToolshown, rename to showToolbar ([#18131](https://github.com/storybookjs/storybook/pull/18131))\n\n## 6.5.0-beta.6 (May 6, 2022)\n\n### Bug Fixes\n\n- Controls: Fix undefined args handling ([#18135](https://github.com/storybookjs/storybook/pull/18135))\n\n### Maintenance\n\n- CLI: Update Introduction.stories.mdx template to be MDX2-friendly ([#18141](https://github.com/storybookjs/storybook/pull/18141))\n\n### Dependency Upgrades\n\n- Remove jest from cli peerDependencies ([#18149](https://github.com/storybookjs/storybook/pull/18149))\n\n## 6.5.0-beta.5 (May 4, 2022)\n\n### Bug Fixes\n\n- Core: Fix anonymous ID generation ([#18133](https://github.com/storybookjs/storybook/pull/18133))\n\n## 6.5.0-beta.4 (May 4, 2022)\n\n### Features\n\n- UI: Add a parent level toolbar exclusion key for tabs ([#18106](https://github.com/storybookjs/storybook/pull/18106))\n- Addon-a11y: Display a11y issues number in addon tab title ([#17983](https://github.com/storybookjs/storybook/pull/17983))\n\n### Bug Fixes\n\n- Addon-docs: Fix Canvas block CURRENT_SELECTION handling ([#18130](https://github.com/storybookjs/storybook/pull/18130))\n- Telemetry: Add safecheck for crash reports ([#18129](https://github.com/storybookjs/storybook/pull/18129))\n- Addon-a11y: Fix a11y params > element use ([#17989](https://github.com/storybookjs/storybook/pull/17989))\n\n## 6.5.0-beta.3 (May 4, 2022)\n\n### Bug Fixes\n\n- UI: Externalize `react-syntax-highlighter` from components ([#18127](https://github.com/storybookjs/storybook/pull/18127))\n\n## 6.5.0-beta.2 (May 2, 2022)\n\n### Features\n\n- Core: Add optional telemetry and crash reporting ([#18046](https://github.com/storybookjs/storybook/pull/18046))\n\n### Bug Fixes\n\n- Controls: Fix URL deserialization for argTypes with mapping ([#18124](https://github.com/storybookjs/storybook/pull/18124))\n- Core: Fix telemetry project root detection ([#18125](https://github.com/storybookjs/storybook/pull/18125))\n- React: Fix version detection for older versions of `react-dom` ([#18105](https://github.com/storybookjs/storybook/pull/18105))\n- CLI: Add non-monorepo testing tools to exclude lists ([#18092](https://github.com/storybookjs/storybook/pull/18092))\n\n### Maintenance\n\n- Examples: Update example to restore 6.4 auto-title behavior in UI ([#18109](https://github.com/storybookjs/storybook/pull/18109))\n- CLI: Remove git.io URL ([#18070](https://github.com/storybookjs/storybook/pull/18070))\n- UI: Make panel position a persistent preference ([#18036](https://github.com/storybookjs/storybook/pull/18036))\n\n### Dependency Upgrades\n\n- React: Fix jest-specific-snapshot dev dependency ([#18095](https://github.com/storybookjs/storybook/pull/18095))\n\n## 6.5.0-beta.1 (April 28, 2022)\n\n### Features\n\n- Toolbars: Add dynamicTitle option ([#17789](https://github.com/storybookjs/storybook/pull/17789))\n- Angular: Add webpackStatsJson to angular-builder ([#18001](https://github.com/storybookjs/storybook/pull/18001))\n- CLI/Vue: add interactions to vue cli template ([#18021](https://github.com/storybookjs/storybook/pull/18021))\n- CLI/HTML: Add interactions to cli template ([#18014](https://github.com/storybookjs/storybook/pull/18014))\n\n### Bug Fixes\n\n- CSF: Re-apply TArgs to render type ([#18075](https://github.com/storybookjs/storybook/pull/18075))\n- CLI: await generators for proper install ([#18053](https://github.com/storybookjs/storybook/pull/18053))\n- Core: Fix story index for CSF default exports as TS vars ([#18054](https://github.com/storybookjs/storybook/pull/18054))\n- Core: Fix single-story hoisting regression for auto-title changes ([#18052](https://github.com/storybookjs/storybook/pull/18052))\n\n## 6.5.0-beta.0 (April 24, 2022)\n\n### Features\n\n- CLI/Vue3: add interactions to vue3 cli template ([#18031](https://github.com/storybookjs/storybook/pull/18031))\n- CLI/Svelte: add interactions to cli template ([#17993](https://github.com/storybookjs/storybook/pull/17993))\n- UI: Move the \"Rerun interactions\" button to Subnav ([#17647](https://github.com/storybookjs/storybook/pull/17647))\n\n## 6.5.0-alpha.64 (April 18, 2022)\n\n### Features\n\n- CLI/Preact: add interactions to cli template ([#17984](https://github.com/storybookjs/storybook/pull/17984))\n\n### Bug Fixes\n\n- Interactions: Fix show length of object value on MethodCall ([#17649](https://github.com/storybookjs/storybook/pull/17649))\n- React: Fix React 18 react-dom/client dynamic import syntax ([#17987](https://github.com/storybookjs/storybook/pull/17987))\n- Svelte: Fix webpack5/babelModeV7 ([#17939](https://github.com/storybookjs/storybook/pull/17939))\n\n### Maintenance\n\n- Examples: Remove stories from deprecated `options`/`queryparams` addons ([#17977](https://github.com/storybookjs/storybook/pull/17977))\n- Chore: Format versions.ts file using repo config ([#17963](https://github.com/storybookjs/storybook/pull/17963))\n\n## 6.5.0-alpha.63 (April 14, 2022)\n\n### Bug Fixes\n\n- Theming: Re-export correct bundled file ([#17956](https://github.com/storybookjs/storybook/pull/17956))\n- Core: Support react-dom/client dom hack on Windows machines ([#17946](https://github.com/storybookjs/storybook/pull/17946))\n\n### Maintenance\n\n- CI: set parallelism of nx to 2 ([#17878](https://github.com/storybookjs/storybook/pull/17878))\n\n### Dependency Upgrades\n\n- Run `prebundle` script without `browser: true` in Rollup config ([#17947](https://github.com/storybookjs/storybook/pull/17947))\n\n## 6.4.22 (April 14, 2022)\n\n### Maintenance\n\n- Core: Avoid framework imports from core/client ([#17875](https://github.com/storybookjs/storybook/pull/17875))\n\n## 6.5.0-alpha.62 (April 13, 2022)\n\nTest publish with npm 2FA enabled for addon-jest\n\n## 6.5.0-alpha.61 (April 11, 2022)\n\n### Features\n\n- UI: Add URL parameters to SB to tweak visible UI ([#17891](https://github.com/storybookjs/storybook/pull/17891))\n\n### Maintenance\n\n- Core: Followup changing CJS entrypoints to ESM ([#17927](https://github.com/storybookjs/storybook/pull/17927))\n\n### Dependency Upgrades\n\n- Export `createCache` from `@storybook/theming` ([#17929](https://github.com/storybookjs/storybook/pull/17929))\n\n## 6.4.21 (April 9, 2022)\n\n### Bug Fixes\n\n- Angular: Do not use default for includePaths ([#17876](https://github.com/storybookjs/storybook/pull/17876))\n- Controls: Fix date control width in addons panel ([#17780](https://github.com/storybookjs/storybook/pull/17780))\n- CLI: Preserve quote style in automigrate ([#17858](https://github.com/storybookjs/storybook/pull/17858))\n- CLI: Update the exclude list for upgrade warnings ([#17909](https://github.com/storybookjs/storybook/pull/17909))\n\n## 6.5.0-alpha.60 (April 9, 2022)\n\n### Features\n\n- Core: Add story preloading to optimize lazy compilation ([#17903](https://github.com/storybookjs/storybook/pull/17903))\n\n### Bug Fixes\n\n- UI: Fix pseudo class potential unsafe warning ([#17911](https://github.com/storybookjs/storybook/pull/17911))\n- Core: Fix user-supplied project-level `render` in v6 store ([#17885](https://github.com/storybookjs/storybook/pull/17885))\n\n### Dependency Upgrades\n\n- Upgrade polished to 4.2.2 ([#17913](https://github.com/storybookjs/storybook/pull/17913))\n- Bump min vue-loader dependency version ([#17912](https://github.com/storybookjs/storybook/pull/17912))\n\n## 6.5.0-alpha.59 (April 7, 2022)\n\n### Maintenance\n\n- CLI: Update the exclude list for upgrade warnings ([#17909](https://github.com/storybookjs/storybook/pull/17909))\n- Examples: Added an external-docs example to show the basic use case ([#17807](https://github.com/storybookjs/storybook/pull/17807))\n\n### Dependency Upgrades\n\n- Migration to Emotion 11 ([#17640](https://github.com/storybookjs/storybook/pull/17640))\n\n## 6.5.0-alpha.58 (April 7, 2022)\n\n### Features\n\n- CLI: Add webpack4/5 auto-detection ([#17908](https://github.com/storybookjs/storybook/pull/17908))\n- React: Add support for react18's new root API ([#17215](https://github.com/storybookjs/storybook/pull/17215))\n\n### Bug Fixes\n\n- UI: Fix canvas as initialActive for fullscreen mode in mobile ([#17906](https://github.com/storybookjs/storybook/pull/17906))\n- UI: Fix mobile fullscreen UI ([#17873](https://github.com/storybookjs/storybook/pull/17873))\n\n### Maintenance\n\n- Core: Avoid framework imports from core/client ([#17875](https://github.com/storybookjs/storybook/pull/17875))\n- Webpack: Make manager and preview build processes cancelable ([#17809](https://github.com/storybookjs/storybook/pull/17809))\n- Build: Add vite-react to e2e tests ([#17871](https://github.com/storybookjs/storybook/pull/17871))\n- CLI: Upgrade vue3 template to use webpack5 builder ([#17896](https://github.com/storybookjs/storybook/pull/17896))\n- Build: Exclude @storybook/builder-vite from verdaccio ([#17897](https://github.com/storybookjs/storybook/pull/17897))\n\n## 6.5.0-alpha.57 (April 6, 2022)\n\n### Bug Fixes\n\n- Svelte: Fix dynamic source snippets ([#17866](https://github.com/storybookjs/storybook/pull/17866))\n- Angular: Do not use default for includePaths ([#17876](https://github.com/storybookjs/storybook/pull/17876))\n\n### Maintenance\n\n- Addon-docs: assume links starting with \"https://\" are external ([#17819](https://github.com/storybookjs/storybook/pull/17819))\n\n### Dependency Upgrades\n\n- Unify CSF version ([#17895](https://github.com/storybookjs/storybook/pull/17895))\n\n## 6.5.0-alpha.56 (April 5, 2022)\n\n### Features\n\n- Controls: Rework conditional controls with globals, queries ([#17883](https://github.com/storybookjs/storybook/pull/17883))\n- UI: Add Brand target config option ([#17814](https://github.com/storybookjs/storybook/pull/17814))\n\n### Bug Fixes\n\n- Controls: Fix date control width in addons panel ([#17780](https://github.com/storybookjs/storybook/pull/17780))\n\n### Maintenance\n\n- Core: Update some references to use ESM rather than CJS ([#17868](https://github.com/storybookjs/storybook/pull/17868))\n- Build: Upgrade from deprecated circleci docker img ([#17832](https://github.com/storybookjs/storybook/pull/17832))\n- Build: Parallel e2e (this might be expensive) ([#17842](https://github.com/storybookjs/storybook/pull/17842))\n- Build: Add junit summary for CircleCI ([#17867](https://github.com/storybookjs/storybook/pull/17867))\n\n## 6.5.0-alpha.55 (April 3, 2022)\n\n### Features\n\n- CLI: Detect vite project, use vite builder automatically ([#17860](https://github.com/storybookjs/storybook/pull/17860))\n- CLI: Default new vite projects to storyStoreV7 ([#17859](https://github.com/storybookjs/storybook/pull/17859))\n\n### Bug Fixes\n\n- Core: Restore preview-web composeConfigs export ([#17861](https://github.com/storybookjs/storybook/pull/17861))\n- CLI: Preserve quote style in automigrate ([#17858](https://github.com/storybookjs/storybook/pull/17858))\n\n## 6.4.20 (April 1, 2022)\n\n### Bug Fixes\n\n- CLI: Fix vite/jest issue with mocked global ([#17830](https://github.com/storybookjs/storybook/pull/17830))\n- Angular: Fix multiple calls of Input setter ([#17633](https://github.com/storybookjs/storybook/pull/17633))\n- Web-components: Fix CSS class usage in CLI template ([#17702](https://github.com/storybookjs/storybook/pull/17702))\n- UI: Fix composition support in safari ([#17679](https://github.com/storybookjs/storybook/pull/17679))\n- Addon-docs: DocsPage story order should match the index ([#17669](https://github.com/storybookjs/storybook/pull/17669))\n- Core: Fix core.builder check ([#17606](https://github.com/storybookjs/storybook/pull/17606))\n\n### Maintenance\n\n- CLI: Add automigration to `@storybook/builder-vite` ([#17829](https://github.com/storybookjs/storybook/pull/17829))\n\n## 6.5.0-alpha.54 (April 1, 2022)\n\n### Dependency Upgrades\n\n- React: Update react and react-dom peerDeps for React18 ([#17853](https://github.com/storybookjs/storybook/pull/17853))\n\n## 6.5.0-alpha.53 (April 1, 2022)\n\n### Features\n\n- Core: Add simplified manager.js/preview.js API for addons ([#17755](https://github.com/storybookjs/storybook/pull/17755))\n- Core/React: Add testing utilities ([#17282](https://github.com/storybookjs/storybook/pull/17282))\n\n### Bug Fixes\n\n- Addon-docs: Fix dependencies for yarn pnp ([#17705](https://github.com/storybookjs/storybook/pull/17705))\n- Webpack: Expand version ranges of webpack in the apps ([#17834](https://github.com/storybookjs/storybook/pull/17834))\n- CLI: Fix vite/jest issue with mocked global ([#17830](https://github.com/storybookjs/storybook/pull/17830))\n\n### Maintenance\n\n- Build: Remove packtracker ([#17841](https://github.com/storybookjs/storybook/pull/17841))\n- Build: Swap order of e2e tests around ([#17840](https://github.com/storybookjs/storybook/pull/17840))\n- Build: Add weekly check for broken markdown links ([#17799](https://github.com/storybookjs/storybook/pull/17799))\n- Build: Switch to use medium+ ([#17837](https://github.com/storybookjs/storybook/pull/17837))\n\n## 6.5.0-alpha.52 (March 31, 2022)\n\n### Bug Fixes\n\n- UI: Add back CacheProvider from emotion to lib/theming ([#17820](https://github.com/storybookjs/storybook/pull/17820))\n- Core: Add a feature flag for enabling crossOriginIsolated ([#17815](https://github.com/storybookjs/storybook/pull/17815))\n- Angular: Fix multiple calls of Input setter ([#17633](https://github.com/storybookjs/storybook/pull/17633))\n- UI: Wait 100ms before showing spinner and fix story overlaying it ([#17753](https://github.com/storybookjs/storybook/pull/17753))\n\n### Maintenance\n\n- CLI: Add automigration to `@storybook/builder-vite` ([#17829](https://github.com/storybookjs/storybook/pull/17829))\n- Build: Add setup-node version for danger ([#17826](https://github.com/storybookjs/storybook/pull/17826))\n- Add contributing instructions to PULL_REQUEST_TEMPLATE ([#17713](https://github.com/storybookjs/storybook/pull/17713))\n\n## 6.5.0-alpha.51 (March 25, 2022)\n\n### Features\n\n- SyntaxHighlighter: Add prettier for code formatting ([#17746](https://github.com/storybookjs/storybook/pull/17746))\n\n### Maintenance\n\n- Build: Add main overrides to e2e config and possibility to run test runner ([#17778](https://github.com/storybookjs/storybook/pull/17778))\n\n## 6.5.0-alpha.50 (March 23, 2022)\n\n### Features\n\n- Controls: Add conditional controls ([#17536](https://github.com/storybookjs/storybook/pull/17536))\n- Core: Add headers to enable SharedArrayBuffer in stories ([#16970](https://github.com/storybookjs/storybook/pull/16970))\n- UI: Button for toggling addons panel ([#17714](https://github.com/storybookjs/storybook/pull/17714))\n\n### Bug Fixes\n\n- Core: Ensure simultaneous first access to stories.json waits ([#17785](https://github.com/storybookjs/storybook/pull/17785))\n- Reload iframe when the url changes ([#17644](https://github.com/storybookjs/storybook/pull/17644))\n- UI: Fix brand logo layout shift ([#16467](https://github.com/storybookjs/storybook/pull/16467))\n- UI: Fix nesting issue for refs in sidebar component ([#17726](https://github.com/storybookjs/storybook/pull/17726))\n- Core: Fix filesystem cache missing return ([#17748](https://github.com/storybookjs/storybook/pull/17748))\n- Addon-docs: Fix binding of the `renderStoryToElement` passed to `DocsRender` ([#17742](https://github.com/storybookjs/storybook/pull/17742))\n\n### Maintenance\n\n- Addon-docs/Vue: Add tests for sourceDecorator vnodeToString ([#17764](https://github.com/storybookjs/storybook/pull/17764))\n- Controls: Date control tests ([#17765](https://github.com/storybookjs/storybook/pull/17765))\n- Remove mock directories from Jest test coverage ([#17771](https://github.com/storybookjs/storybook/pull/17771))\n- fix dts-localize script ([#17747](https://github.com/storybookjs/storybook/pull/17747))\n\n## 6.5.0-alpha.49 (March 17, 2022)\n\n### Bug Fixes\n\n- Addon-docs/Svelte: Fix `HOC.svelte` reference ([#17731](https://github.com/storybookjs/storybook/pull/17731))\n- UI: Fix composition support in safari ([#17679](https://github.com/storybookjs/storybook/pull/17679))\n\n## 6.5.0-alpha.48 (March 14, 2022)\n\n### Features\n\n- Addon-docs: Auto-disable docs presets if docs/controls unused ([#17697](https://github.com/storybookjs/storybook/pull/17697))\n\n### Bug Fixes\n\n- Web-components: Fix CSS class usage in CLI template ([#17702](https://github.com/storybookjs/storybook/pull/17702))\n\n### Maintenance\n\n- Addon-docs: Refactor docs support into individual framework packages ([#17695](https://github.com/storybookjs/storybook/pull/17695))\n\n## 6.5.0-alpha.47 (March 10, 2022)\n\n### Bug Fixes\n\n- Webpack4: Fix useExports for angular-cli ([#17674](https://github.com/storybookjs/storybook/pull/17674))\n- Core: Ensure that we do not render a story twice if re-rendered during preparing ([#17599](https://github.com/storybookjs/storybook/pull/17599))\n- Addon-docs: DocsPage story order should match the index ([#17669](https://github.com/storybookjs/storybook/pull/17669))\n- Core: Fix staticDirs path issue on Windows ([#17641](https://github.com/storybookjs/storybook/pull/17641))\n- Angular: Set ForkTsCheckerWebpackPlugin to async ([#17389](https://github.com/storybookjs/storybook/pull/17389))\n- Core: Fix core.builder check ([#17606](https://github.com/storybookjs/storybook/pull/17606))\n\n### Maintenance\n\n- Examples: Build stories.json for examples that support it ([#17670](https://github.com/storybookjs/storybook/pull/17670))\n- Core: Refactor preview rendering out of `PreviewWeb` ([#17598](https://github.com/storybookjs/storybook/pull/17598))\n- Prevent lint hook from running on all files ([#17662](https://github.com/storybookjs/storybook/pull/17662))\n- TypeScript: Change imports of types to be prefixed ([#17627](https://github.com/storybookjs/storybook/pull/17627))\n- Build: Give linting sub-commands a directory to run against ([#17545](https://github.com/storybookjs/storybook/pull/17545))\n- TypeScript: remove unnecessary 'as any' ([#17595](https://github.com/storybookjs/storybook/pull/17595))\n\n### Dependency Upgrades\n\n- Update shelljs dependency version ([#17602](https://github.com/storybookjs/storybook/pull/17602))\n- Remove unused `uuid` that's also deprecated ([#17615](https://github.com/storybookjs/storybook/pull/17615))\n\n## 6.5.0-alpha.46 (March 5, 2022)\n\n### Bug Fixes\n\n- Addon-interactions: Use 'global' package instead of `global` ([#17614](https://github.com/storybookjs/storybook/pull/17614))\n\n## 6.5.0-alpha.45 (March 2, 2022)\n\n### Bug Fixes\n\n- CSF3: Fix Auto-title to respect file system capitalization ([#17574](https://github.com/storybookjs/storybook/pull/17574))\n\n### Maintenance\n\n- Core: Remove unused babel dependencies ([#17425](https://github.com/storybookjs/storybook/pull/17425))\n\n## 6.5.0-alpha.44 (February 28, 2022)\n\n### Dependency Upgrades\n\n- Fix mdx-csf dependencies to canary dist-tag ([#17592](https://github.com/storybookjs/storybook/pull/17592))\n\n## 6.5.0-alpha.43 (February 28, 2022)\n\n### Features\n\n- Addon-docs: MDX2 support ([#17515](https://github.com/storybookjs/storybook/pull/17515))\n\n### Bug Fixes\n\n- Core: Fix global render fn ([#17577](https://github.com/storybookjs/storybook/pull/17577))\n- Addon-interactions: Mock window in browser environments ([#17535](https://github.com/storybookjs/storybook/pull/17535))\n\n## 6.5.0-alpha.42 (February 25, 2022)\n\n### Bug Fixes\n\n- Controls/Essentials/Interactions: Add support for main.cjs/mjs/tsx files ([#17524](https://github.com/storybookjs/storybook/pull/17524))\n- Addon-docs: Fix preset handling for builder with options ([#17544](https://github.com/storybookjs/storybook/pull/17544))\n\n## 6.5.0-alpha.41 (February 22, 2022)\n\n### Features\n\n- Addon-Outline: add 'o' keyboard shortcut to toggle the outline addon ([#17530](https://github.com/storybookjs/storybook/pull/17530))\n\n### Bug Fixes\n\n- Addon-docs: Ensure that **DOCS_CONTEXT** cannot be undefined ([#17251](https://github.com/storybookjs/storybook/pull/17251))\n- Addon-docs: Account for non-string types when converting enums ([#15822](https://github.com/storybookjs/storybook/pull/15822))\n- Addon-actions: Don't override undefined args ([#17505](https://github.com/storybookjs/storybook/pull/17505))\n\n## 6.5.0-alpha.40 (February 19, 2022)\n\n### Features\n\n- Webpack5: Add lazy compilation ([#17501](https://github.com/storybookjs/storybook/pull/17501))\n\n### Maintenance\n\n- Build: Fix CRA repro generator and e2e test in PnP mode ([#17375](https://github.com/storybookjs/storybook/pull/17375))\n- UI: Add a custom title story for heading component ([#17487](https://github.com/storybookjs/storybook/pull/17487))\n\n## 6.4.19 (February 12, 2022)\n\n### Features\n\n- CLI/React: Add interactions to cli template ([#17345](https://github.com/storybookjs/storybook/pull/17345))\n- CLI/Angular: Add interactions to cli template ([#17437](https://github.com/storybookjs/storybook/pull/17437))\n\n### Bug Fixes\n\n- Core/CLI: Add `extract` function to `PreviewWeb` and use it in `sb extract` if available ([#17447](https://github.com/storybookjs/storybook/pull/17447))\n- Core: Ensure we show an error when `configure()` throws ([#17435](https://github.com/storybookjs/storybook/pull/17435))\n- Core: Fix `useParameter` with nullish coalescing ([#17327](https://github.com/storybookjs/storybook/pull/17327))\n- Addon-links: Fix export statement in react.d.ts ([#17434](https://github.com/storybookjs/storybook/pull/17434))\n- Addon-docs: Fix typo in ArgsTable tooltip ([#17404](https://github.com/storybookjs/storybook/pull/17404))\n\n## 6.5.0-alpha.39 (February 11, 2022)\n\n### Features\n\n- CLI: Add addon-interactions to angular template ([#17437](https://github.com/storybookjs/storybook/pull/17437))\n\n### Bug Fixes\n\n- Core: Rename `generated-stories-entry` to `cjs` extension so require works ([#17486](https://github.com/storybookjs/storybook/pull/17486))\n- Core/CLI: Add `extract` function to `PreviewWeb` and use it in `sb extract` if available ([#17447](https://github.com/storybookjs/storybook/pull/17447))\n- Controls: Fix Boolean control parsing ([#17456](https://github.com/storybookjs/storybook/pull/17456))\n\n### Maintenance\n\n- Fix `ci:matrix` label in CI ([#17457](https://github.com/storybookjs/storybook/pull/17457))\n\n### Dependency Upgrades\n\n- Bump vue-docgen-api to 4.44.15 ([#17465](https://github.com/storybookjs/storybook/pull/17465))\n\n## 6.5.0-alpha.38 (February 8, 2022)\n\n### Bug Fixes\n\n- Addon-links: Fix export statement in react.d.ts ([#17434](https://github.com/storybookjs/storybook/pull/17434))\n- Core: Fix `useParameter` with nullish coalescing ([#17327](https://github.com/storybookjs/storybook/pull/17327))\n- Core: Ensure we show an error when `configure()` throws ([#17435](https://github.com/storybookjs/storybook/pull/17435))\n\n### Maintenance\n\n- Web-components: Upgrade kitchen sink lockfile ([#17424](https://github.com/storybookjs/storybook/pull/17424))\n\n## 6.5.0-alpha.37 (February 8, 2022)\n\nFailed publish\n\n## 6.5.0-alpha.36 (February 4, 2022)\n\n### Maintenance\n\n- UI: Prebundle `@storybook/components` ([#17304](https://github.com/storybookjs/storybook/pull/17304))\n\n## 6.5.0-alpha.35 (February 4, 2022)\n\n### Features\n\n- CLI/React: Add interactions to cli template ([#17345](https://github.com/storybookjs/storybook/pull/17345))\n- CSF3: Handle auto-title redundant filename ([#17421](https://github.com/storybookjs/storybook/pull/17421))\n\n### Bug Fixes\n\n- Addon-docs: Fix typo in ArgsTable tooltip ([#17404](https://github.com/storybookjs/storybook/pull/17404))\n- Core: Apply Docs mode to composed storybooks ([#17292](https://github.com/storybookjs/storybook/pull/17292))\n\n### Maintenance\n\n- Core: Move CSF-related logic to its own folder ([#17381](https://github.com/storybookjs/storybook/pull/17381))\n- Improve style handling in angular example in monorepo ([#17343](https://github.com/storybookjs/storybook/pull/17343))\n\n## 6.4.18 (February 2, 2022)\n\n### Bug Fixes\n\n- CLI: Pin version of `@mdx-js/react` to 1.x.x until we are compatible ([#17395](https://github.com/storybookjs/storybook/pull/17395))\n\n## 6.5.0-alpha.34 (February 2, 2022)\n\n### Features\n\n- Core: Mock channel if not present ([#17382](https://github.com/storybookjs/storybook/pull/17382))\n\n### Bug Fixes\n\n- CLI: Pin version of `@mdx-js/react` to 1.x.x until we are compatible ([#17395](https://github.com/storybookjs/storybook/pull/17395))\n\n## 6.5.0-alpha.33 (February 1, 2022)\n\n### Maintenance\n\n- UI: Prebundle `@storybook/ui` ([#17301](https://github.com/storybookjs/storybook/pull/17301))\n\n## 6.5.0-alpha.32 (February 1, 2022)\n\n### Maintenance\n\n- Core: Pre-bundle `@storybook/router` to avoid react-router conflict ([#17294](https://github.com/storybookjs/storybook/pull/17294))\n\n## 6.5.0-alpha.31 (February 1, 2022)\n\n### Maintenance\n\n- Web components: add addon-interactions example story ([#17303](https://github.com/storybookjs/storybook/pull/17303))\n- Core: Pre-bundle theming to avoid emotion11 conflicts ([#17000](https://github.com/storybookjs/storybook/pull/17000))\n\n## 6.5.0-alpha.30 (January 31, 2022)\n\n### Maintenance\n\n- Build: Enforce stricter types ([#17368](https://github.com/storybookjs/storybook/pull/17368))\n\n## 6.5.0-alpha.29 (January 31, 2022)\n\n### Bug Fixes\n\n- Revert \"Angular: Retrieve version from core package\" ([#17372](https://github.com/storybookjs/storybook/pull/17372))\n\n## 6.4.17 (January 31, 2022)\n\n### Bug Fixes\n\n- Revert \"Angular: Retrieve version from core package\" ([#17372](https://github.com/storybookjs/storybook/pull/17372))\n\n## 6.5.0-alpha.28 (January 29, 2022)\n\n### Bug Fixes\n\n- Svelte: Fix missing templates dir in package.json publish files ([#17367](https://github.com/storybookjs/storybook/pull/17367))\n\n## 6.4.16 (January 29, 2022)\n\n### Bug Fixes\n\n- Angular: Workaround for compodoc on windows machines ([#17334](https://github.com/storybookjs/storybook/pull/17334))\n- Angular: Use ɵReflectionCapabilities to find component & module metadata ([#17156](https://github.com/storybookjs/storybook/pull/17156))\n- Angular: Retrieve version from core package ([#17363](https://github.com/storybookjs/storybook/pull/17363))\n\n## 6.5.0-alpha.27 (January 29, 2022)\n\n### Bug Fixes\n\n- Angular: Workaround for compodoc on windows machines ([#17334](https://github.com/storybookjs/storybook/pull/17334))\n- Angular: Retrieve version from core package ([#17363](https://github.com/storybookjs/storybook/pull/17363))\n\n## 6.5.0-alpha.26 (January 28, 2022)\n\n### Bug Fixes\n\n- Revert \"Core: Rename `generated-stories-entry` to `cjs` extension so require works\" ([#17361](https://github.com/storybookjs/storybook/pull/17361))\n\n## 6.5.0-alpha.25 (January 28, 2022)\n\n### Maintenance\n\n- Build: Overhaul dev script & compile-babel & compile-tsc ([#17338](https://github.com/storybookjs/storybook/pull/17338))\n\n## 6.4.15 (January 28, 2022)\n\n### Bug Fixes\n\n- Angular: Fix runCompodoc for Windows, local Compodoc, and user specified tsconfig ([#16728](https://github.com/storybookjs/storybook/pull/16728))\n- Core: Fix negated glob support ([#17328](https://github.com/storybookjs/storybook/pull/17328))\n\n### Maintenance\n\n- Build: Upgrade main yarn ([#17323](https://github.com/storybookjs/storybook/pull/17323))\n- CLI: Add version update argument to generate-sb-packages-versions utility ([#17356](https://github.com/storybookjs/storybook/pull/17356))\n\n## 6.5.0-alpha.24 (January 28, 2022)\n\n### Bug Fixes\n\n- Core: Fix negated glob support ([#17328](https://github.com/storybookjs/storybook/pull/17328))\n\n### Maintenance\n\n- CLI/Svelte: Revert template stories from svelte-native to CSF ([#17340](https://github.com/storybookjs/storybook/pull/17340))\n- CLI: Add version update argument to generate-sb-packages-versions utility ([#17356](https://github.com/storybookjs/storybook/pull/17356))\n\n## 6.5.0-alpha.23 (January 25, 2022)\n\n### Features\n\n- Vue: Add CSF3 default render function ([#17279](https://github.com/storybookjs/storybook/pull/17279))\n\n### Bug Fixes\n\n- Core: Rename `generated-stories-entry` to `cjs` extension so require works ([#16727](https://github.com/storybookjs/storybook/pull/16727))\n- Addon-docs: Fix `BuilderConfig` can be an object ([#17320](https://github.com/storybookjs/storybook/pull/17320))\n\n### Maintenance\n\n- Core: Remove useless unfetch ([#17306](https://github.com/storybookjs/storybook/pull/17306))\n- Build: Regen lockfile ([#17283](https://github.com/storybookjs/storybook/pull/17283))\n\n### Dependency Upgrades\n\n- Upgrade node-fetch to latest version ([#17317](https://github.com/storybookjs/storybook/pull/17317))\n\n## 6.4.14 (January 21, 2022)\n\n### Bug Fixes\n\n- CLI: Add `--no-manager-cache` to build-storybook ([#17300](https://github.com/storybookjs/storybook/pull/17300))\n- CSF3: Remove `path` from autoTitle browser code ([#17185](https://github.com/storybookjs/storybook/pull/17185))\n- Addon-docs: Fix `docs.disable` parameter on DocsPage ([#17256](https://github.com/storybookjs/storybook/pull/17256))\n- Core: Fix issue with recursive glob with prior special chars ([#17252](https://github.com/storybookjs/storybook/pull/17252))\n- Webpack: Fix for `process` fallback using `require.resolve` ([#17249](https://github.com/storybookjs/storybook/pull/17249))\n\n### Dependency Upgrades\n\n- Upgrade compodoc for colors.js bug ([#17266](https://github.com/storybookjs/storybook/pull/17266))\n- Upgrade jscodeshift dependency for colors.js bug ([#17265](https://github.com/storybookjs/storybook/pull/17265))\n- Restore prettier >= 2.2.1 to satisfy previous constraints ([#17257](https://github.com/storybookjs/storybook/pull/17257))\n\n## 6.5.0-alpha.22 (January 20, 2022)\n\n### Features\n\n- Svelte: Add CSF3 default render function ([#17276](https://github.com/storybookjs/storybook/pull/17276))\n- CLI: Add `--no-manager-cache` to build-storybook ([#17300](https://github.com/storybookjs/storybook/pull/17300))\n\n### Maintenance\n\n- Build: Upgrade yarn to 3.1.1 ([#17281](https://github.com/storybookjs/storybook/pull/17281))\n\n## 6.5.0-alpha.21 (January 18, 2022)\n\n### Features\n\n- Webpack5: Switch to using `import.meta.webpackHot.accept` ([#17270](https://github.com/storybookjs/storybook/pull/17270))\n\n## 6.5.0-alpha.20 (January 18, 2022)\n\n### Dependency Upgrades\n\n- Upgrade compodoc for colors.js bug ([#17266](https://github.com/storybookjs/storybook/pull/17266))\n- Upgrade jscodeshift dependency for colors.js bug ([#17265](https://github.com/storybookjs/storybook/pull/17265))\n- Restore prettier >= 2.2.1 to satisfy previous constraints ([#17257](https://github.com/storybookjs/storybook/pull/17257))\n\n## 6.5.0-alpha.19 (January 17, 2022)\n\n### Features\n\n- Core: Add IS_STORYBOOK global variable ([#16676](https://github.com/storybookjs/storybook/pull/16676))\n\n### Bug Fixes\n\n- Addon-docs: Fix `docs.disable` parameter on DocsPage ([#17256](https://github.com/storybookjs/storybook/pull/17256))\n- Controls: Fix number control update when using useArgs hook ([#17247](https://github.com/storybookjs/storybook/pull/17247))\n- Core: Fix issue with recursive glob with prior special chars ([#17252](https://github.com/storybookjs/storybook/pull/17252))\n\n## 6.5.0-alpha.18 (January 16, 2022)\n\n### Bug Fixes\n\n- Webpack: Fix for `process` fallback using `require.resolve` ([#17249](https://github.com/storybookjs/storybook/pull/17249))\n\n### Maintenance\n\n- Official-storybook: Fix ForwardRefButtonInnerPropTypes warning ([#12733](https://github.com/storybookjs/storybook/pull/12733))\n- Fix prettier 2.3 formatting across the codebase ([#17242](https://github.com/storybookjs/storybook/pull/17242))\n\n## 6.4.13 (January 15, 2022)\n\n### Bug Fixes\n\n- Core: Fix `staticDirs` favicon handling by refactor ([#17241](https://github.com/storybookjs/storybook/pull/17241))\n- Angular: Fix 13.1 and add CI test cases ([#17206](https://github.com/storybookjs/storybook/pull/17206))\n- Core: Fix `__namedExportsOrder` warning from preview.js ([#17240](https://github.com/storybookjs/storybook/pull/17240))\n- Webpack5: Fix manager.js `process` references ([#17213](https://github.com/storybookjs/storybook/pull/17213))\n\n### Dependency Upgrades\n\n- React: Remove react-dev-utils ([#17022](https://github.com/storybookjs/storybook/pull/17022))\n- Fix prettier transpile problems ([#17239](https://github.com/storybookjs/storybook/pull/17239))\n\n## 6.5.0-alpha.17 (January 14, 2022)\n\n### Bug Fixes\n\n- Core: Fix `staticDirs` favicon handling by refactor ([#17241](https://github.com/storybookjs/storybook/pull/17241))\n- Core: Fix `__namedExportsOrder` warning from preview.js ([#17240](https://github.com/storybookjs/storybook/pull/17240))\n\n### Dependency Upgrades\n\n- Fix prettier transpile problems ([#17239](https://github.com/storybookjs/storybook/pull/17239))\n\n## 6.5.0-alpha.16 (January 13, 2022)\n\n### Bug Fixes\n\n- Webpack5: Fix named exports order in production mode ([#17229](https://github.com/storybookjs/storybook/pull/17229))\n\n## 6.5.0-alpha.15 (January 12, 2022)\n\n### Bug Fixes\n\n- Angular: Fix 13.1 and add CI test cases ([#17206](https://github.com/storybookjs/storybook/pull/17206))\n- Webpack5: Fix manager.js process references ([#17213](https://github.com/storybookjs/storybook/pull/17213))\n\n### Dependency Upgrades\n\n- React: Restore webpack as a dependency, updated webpack 5 docs ([#17207](https://github.com/storybookjs/storybook/pull/17207))\n\n## 6.5.0-alpha.14 (January 11, 2022)\n\n### Bug Fixes\n\n- Angular: Fix void element selectors ([#15495](https://github.com/storybookjs/storybook/pull/15495))\n\n### Dependency Upgrades\n\n- React: Remove webpack from dependencies, types as devDependencies ([#17192](https://github.com/storybookjs/storybook/pull/17192))\n\n## 6.5.0-alpha.13 (January 11, 2022)\n\n### Features\n\n- UI: Set the current story name in the title ([#17177](https://github.com/storybookjs/storybook/pull/17177))\n\n### Bug Fixes\n\n- Core: Retain iframe.html query parameters ([#17136](https://github.com/storybookjs/storybook/pull/17136))\n- CSF3: Remove `path` from autoTitle browser code ([#17185](https://github.com/storybookjs/storybook/pull/17185))\n\n### Maintenance\n\n- Build: Fix package.json warnings in JetBrains IDEs ([#17184](https://github.com/storybookjs/storybook/pull/17184))\n- Fix github workflow syntax to run unit-tests on push ([#17148](https://github.com/storybookjs/storybook/pull/17148))\n\n## 5.3.22 (January 10, 2022)\n\n### Dependency Upgrades\n\n- Bump cli-table3 to fix colors.js bug in 5.3 ([#17182](https://github.com/storybookjs/storybook/pull/17182))\n\n## 6.3.13 (January 10, 2022)\n\n### Dependency Upgrades\n\n- Bump cli-table3 to fix colors bug ([#17180](https://github.com/storybookjs/storybook/pull/17180))\n\n## 6.4.10 (January 10, 2022)\n\n### Bug Fixes\n\n- Core: Fix process.env assignment ([#17174](https://github.com/storybookjs/storybook/pull/17174))\n- Angular: Fix angular 13.1 JIT error and HMR reload ([#17131](https://github.com/storybookjs/storybook/pull/17131))\n- Router: Fix navigating to hash links ([#17134](https://github.com/storybookjs/storybook/pull/17134))\n- Source-loader: Fix node.declaration edge case ([#17027](https://github.com/storybookjs/storybook/pull/17027))\n- Core: Fix debug output on webpack failures ([#16988](https://github.com/storybookjs/storybook/pull/16988))\n\n### Dependency Upgrades\n\n- Bump cli-table3 to fix colors bug ([#17180](https://github.com/storybookjs/storybook/pull/17180))\n\n## 6.5.0-alpha.12 (January 10, 2022)\n\n### Bug Fixes\n\n- Core: Fix process.env assignment ([#17174](https://github.com/storybookjs/storybook/pull/17174))\n\n### Dependency Upgrades\n\n- Bump cli-table3 to fix colors bug ([#17180](https://github.com/storybookjs/storybook/pull/17180))\n\n## 6.5.0-alpha.11 (January 7, 2022)\n\n### Bug Fixes\n\n- Addon-docs: Fix babel-loader resolution based on builder ([#16752](https://github.com/storybookjs/storybook/pull/16752))\n- Angular: Use ɵReflectionCapabilities to find component & module metadata ([#17156](https://github.com/storybookjs/storybook/pull/17156))\n\n### Dependency Upgrades\n\n- Update react-syntax-highlighter to fix transitive vulnerability ([#17127](https://github.com/storybookjs/storybook/pull/17127))\n\n## 6.5.0-alpha.10 (January 6, 2022)\n\n### Bug Fixes\n\n- Angular: Fix angular 13.1 JIT error and HMR reload ([#17131](https://github.com/storybookjs/storybook/pull/17131))\n- Core: Fix IE support by transpiling more libs to es5 ([#17141](https://github.com/storybookjs/storybook/pull/17141))\n\n## 6.5.0-alpha.9 (January 6, 2022)\n\n### Features\n\n- Allow setting project args/argTypes for v6 store ([#17043](https://github.com/storybookjs/storybook/pull/17043))\n\n### Bug Fixes\n\n- Router: Fix navigating to hash links ([#17134](https://github.com/storybookjs/storybook/pull/17134))\n\n## 6.5.0-alpha.8 (January 6, 2022)\n\nPublish failed\n\n## 6.5.0-alpha.7 (January 4, 2022)\n\n### Bug Fixes\n\n- Addon-measure: Update z-index to fit with libraries with also high z-index ([#15860](https://github.com/storybookjs/storybook/pull/15860))\n\n### Maintenance\n\n- Vue: Fix VueLoaderPlugin import to support vue-loader@16.x ([#14624](https://github.com/storybookjs/storybook/pull/14624))\n\n### Dependency Upgrades\n\n- Upgrade react-syntax-highlighter to pick up security patch upstream in highlight.js ([#17100](https://github.com/storybookjs/storybook/pull/17100))\n\n## 6.5.0-alpha.6 (January 3, 2022)\n\n### Features\n\n- Vue3: Add default render function CSF3 ([#17068](https://github.com/storybookjs/storybook/pull/17068))\n- Addon-docs/Vue: Include methods in ArgsTable ([#16975](https://github.com/storybookjs/storybook/pull/16975))\n\n### Bug Fixes\n\n- CLI: Install `lit-html` in new web components project ([#17106](https://github.com/storybookjs/storybook/pull/17106))\n- Angular: Fix runCompodoc for Windows, local Compodoc, and user specified tsconfig ([#16728](https://github.com/storybookjs/storybook/pull/16728))\n\n### Dependency Upgrades\n\n- React: Remove react-dev-utils ([#17022](https://github.com/storybookjs/storybook/pull/17022))\n\n## 6.5.0-alpha.5 (December 23, 2021)\n\n### Dependency Upgrades\n\n- Update react-refresh@0.11.0 & react-refresh-webpack-plugin@0.5.3 same as cra5 ([#17056](https://github.com/storybookjs/storybook/pull/17056))\n\n## 6.5.0-alpha.4 (December 18, 2021)\n\n### Bug Fixes\n\n- Angular: Fix for renamed method in angular 13.1 ([#17032](https://github.com/storybookjs/storybook/pull/17032))\n- Source-loader: Fix node.declaration edge case ([#17027](https://github.com/storybookjs/storybook/pull/17027))\n- Core: Fix debug output on webpack failures ([#16988](https://github.com/storybookjs/storybook/pull/16988))\n\n### Maintenance\n\n- Build: Run unit tests on more node versions, mac, and windows ([#16744](https://github.com/storybookjs/storybook/pull/16744))\n\n### Dependency Upgrades\n\n- Avoid referencing internal Emotion packages in built types ([#16905](https://github.com/storybookjs/storybook/pull/16905))\n\n## 6.5.0-alpha.3 (December 9, 2021)\n\n### Bug Fixes\n\n- Core: Support custom PREVIEW URL for block story iframe ([#16773](https://github.com/storybookjs/storybook/pull/16773))\n\n## 6.5.0-alpha.2 (December 9, 2021)\n\n### Bug Fixes\n\n- UI: Only push the view back to Story if the viewMode is settings ([#16943](https://github.com/storybookjs/storybook/pull/16943))\n- Core: Ensure we have a full story index before caching ([#16947](https://github.com/storybookjs/storybook/pull/16947))\n- Angular: Fix support for non-roman alphabets in story titles ([#16931](https://github.com/storybookjs/storybook/pull/16931))\n- Core: Be explicit about `viewMode` to fix Vue issue ([#16919](https://github.com/storybookjs/storybook/pull/16919))\n- Core: Remove unused and occluded types ([#16917](https://github.com/storybookjs/storybook/pull/16917))\n- CLI: Fix `sb repro` clobbering .vuerc ([#16897](https://github.com/storybookjs/storybook/pull/16897))\n- Core: Fix auto-title in webpack5 ([#16913](https://github.com/storybookjs/storybook/pull/16913))\n- Angular: Fix incorrect log ([#16885](https://github.com/storybookjs/storybook/pull/16885))\n- Angular: Fix tsConfig paths not resolving for Angular >=12.2 ([#16882](https://github.com/storybookjs/storybook/pull/16882))\n- Core: Add feature flag to disable legacy hierarchy separator warning ([#16915](https://github.com/storybookjs/storybook/pull/16915))\n\n### Dependency Upgrades\n\n- Move @types/node to dependencies and accept v16 types ([#16904](https://github.com/storybookjs/storybook/pull/16904))\n- Bump lodash to 4.17.21 ([#16883](https://github.com/storybookjs/storybook/pull/16883))\n\n## 6.4.9 (December 9, 2021)\n\n### Bug Fixes\n\n- Core: Ensure we have a full story index before caching ([#16947](https://github.com/storybookjs/storybook/pull/16947))\n- Angular: Fix support for non-roman alphabets in story titles ([#16931](https://github.com/storybookjs/storybook/pull/16931))\n- Core: Be explicit about `viewMode` to fix Vue issue ([#16919](https://github.com/storybookjs/storybook/pull/16919))\n- Core: Remove unused and occluded types ([#16917](https://github.com/storybookjs/storybook/pull/16917))\n\n## 6.4.8 (December 6, 2021)\n\n### Bug Fixes\n\n- Core: Fix auto-title in webpack5 ([#16913](https://github.com/storybookjs/storybook/pull/16913))\n- CLI: Fix `sb repro` clobbering .vuerc ([#16897](https://github.com/storybookjs/storybook/pull/16897))\n\n### Maintenance\n\n- Core: Add feature flag to disable legacy hierarchy separator warning ([#16915](https://github.com/storybookjs/storybook/pull/16915))\n\n## 6.4.7 (December 3, 2021)\n\n### Bug Fixes\n\n- Angular: Fix incorrect log ([#16885](https://github.com/storybookjs/storybook/pull/16885))\n\n## 6.4.6 (December 3, 2021)\n\nNpm publish failed.\n\n## 6.4.5 (December 3, 2021)\n\n### Bug Fixes\n\n- Angular: Fix tsConfig paths not resolving for Angular >=12.2 ([#16882](https://github.com/storybookjs/storybook/pull/16882))\n- Addon-docs: Fix transclusion crash on webpack rules without test field ([#16873](https://github.com/storybookjs/storybook/pull/16873))\n\n### Dependency Upgrades\n\n- Bump lodash to 4.17.21 ([#16883](https://github.com/storybookjs/storybook/pull/16883))\n\n## 6.5.0-alpha.1 (December 3, 2021)\n\n### Bug Fixes\n\n- CLI: Fix open storybook in default browser ([#16844](https://github.com/storybookjs/storybook/pull/16844))\n- Addon-docs: Fix transclusion crash on webpack rules without test field ([#16873](https://github.com/storybookjs/storybook/pull/16873))\n\n### Maintenance\n\n- CLI: Improve `sb repro` directory prompt ([#16854](https://github.com/storybookjs/storybook/pull/16854))\n\n## 6.4.4 (December 2, 2021)\n\n### Bug Fixes\n\n- CLI: Fix mainjsFramework automigrate ([#16866](https://github.com/storybookjs/storybook/pull/16866))\n\n## 6.4.3 (December 1, 2021)\n\n### Bug Fixes\n\n- Don't render with `modernInline` if `inlineStories` is `false` ([#16853](https://github.com/storybookjs/storybook/pull/16853))\n- Preview: Don't hide the story while preparing ([#16850](https://github.com/storybookjs/storybook/pull/16850))\n\n## 6.4.2 (December 1, 2021)\n\n### Bug Fixes\n\n- UI: Ensure all classes+animations for our loaders are prefixed ([#16815](https://github.com/storybookjs/storybook/pull/16815))\n- Angular: Add back-compat method to find options (styles) in angular.json ([#16832](https://github.com/storybookjs/storybook/pull/16832))\n\n## 6.4.1 (November 30, 2021)\n\n### Bug Fixes\n\n- Core: Fix packageName check in build-dev ([#16823](https://github.com/storybookjs/storybook/pull/16823))\n- CSFFile: Fix function exports ([#16829](https://github.com/storybookjs/storybook/pull/16829))\n\n### Maintenance\n\n- Fix `handle-release-branches` workflow ([#16801](https://github.com/storybookjs/storybook/pull/16801))\n\n## 6.4.0 (November 27, 2021)\n\nStorybook 6.4 is here!! 🎉🎉🎉\n\nSB6.4 adds interaction testing and performance re-architecture ahead of a huge 7.0 release.\n\n- ▶️ **Interactive stories** to simulate user behavior and tools to debug it\n- ⚡️ **On-demand architecture** for smaller builds and faster load times\n- ⛸ **Automigrate + versioned documentation** for easier upgrades\n- 📋 **Linter** to enforce Storybook best practices\n- 💯 **Hundreds more fixes** and quality of life improvements\n\nMore info in the Github issue [Storybook 6.4 Release 🛠](https://github.com/storybookjs/storybook/issues/15355). Release announcement coming soon!!!\n\n## 6.4.0-rc.11 (November 26, 2021)\n\n### Bug Fixes\n\n- Core: Fix breaking change in process/browser ([#16795](https://github.com/storybookjs/storybook/pull/16795))\n\n## 6.4.0-rc.10 (November 26, 2021)\n\n### Bug Fixes\n\n- Core: Allow args/argTypes/component to be set via parameters for storiesOf back-compat ([#16791](https://github.com/storybookjs/storybook/pull/16791))\n- Core: Sort the results of `globby` when constructing Story Index ([#16788](https://github.com/storybookjs/storybook/pull/16788))\n- Core: Don't log a console error when the story is missing ([#16783](https://github.com/storybookjs/storybook/pull/16783))\n- Addon-docs: Wait for the story component to render before emitting ([#16792](https://github.com/storybookjs/storybook/pull/16792))\n- Core: Ensure that `context.args` is always set ([#16790](https://github.com/storybookjs/storybook/pull/16790))\n\n## 6.4.0-rc.9 (November 26, 2021)\n\n### Features\n\n- Angular: Add styles and stylePreprocessorOptions to angular builder ([#16675](https://github.com/storybookjs/storybook/pull/16675))\n\n### Bug Fixes\n\n- Interactions: Unlock controls when play function is finished ([#16784](https://github.com/storybookjs/storybook/pull/16784))\n\n### Maintenance\n\n- Misc: Cleanup typescript webpack types ([#16780](https://github.com/storybookjs/storybook/pull/16780))\n\n## 6.4.0-rc.8 (November 25, 2021)\n\n### Bug Fixes\n\n- Interactions: Fix duplicate rows in waitFor ([#16465](https://github.com/storybookjs/storybook/pull/16465))\n- Core: Fix channel options so that they are merged in correct order ([#16764](https://github.com/storybookjs/storybook/pull/16764))\n\n### Dependency Upgrades\n\n- Add missing peer dependencies ([#16551](https://github.com/storybookjs/storybook/pull/16551))\n\n## 6.4.0-rc.7 (November 24, 2021)\n\n### Bug Fixes\n\n- Core: Add `./` to start of hidden file & folder paths ([#16723](https://github.com/storybookjs/storybook/pull/16723))\n\n### Dependency Upgrades\n\n- Update peer dependencies for angular 13 support ([#16758](https://github.com/storybookjs/storybook/pull/16758))\n\n## 6.4.0-rc.6 (November 22, 2021)\n\n### Bug Fixes\n\n- CSF: Fix component id handling ([#16746](https://github.com/storybookjs/storybook/pull/16746))\n- Addon-docs: Improved loading state ([#16709](https://github.com/storybookjs/storybook/pull/16709))\n\n### Maintenance\n\n- WebComponents: Update Lit peerDep to use Lit 2 stable version ([#16670](https://github.com/storybookjs/storybook/pull/16670))\n\n### Dependency Upgrades\n\n- Upgrade react-router to 6.0.0 ([#16742](https://github.com/storybookjs/storybook/pull/16742))\n\n## 6.4.0-rc.5 (November 19, 2021)\n\n### Bug Fixes\n\n- Core: Restore `stringifyEnvs` utility used by Vite builder ([#16731](https://github.com/storybookjs/storybook/pull/16731))\n\n## 6.4.0-rc.4 (November 19, 2021)\n\n### Bug Fixes\n\n- Core: Fix `process.env` stringification ([#16725](https://github.com/storybookjs/storybook/pull/16725))\n- Core: Fix build-storybook sort bug in v6-mode ([#16724](https://github.com/storybookjs/storybook/pull/16724))\n- Addon-docs/Angular: fix extractEnumValues undefined error ([#16524](https://github.com/storybookjs/storybook/pull/16524))\n\n### Maintenance\n\n- Angular: update addon interactions example ([#16698](https://github.com/storybookjs/storybook/pull/16698))\n\n### Dependency Upgrades\n\n- Upgrade from node-sass to sass in examples/angular-cli ([#16663](https://github.com/storybookjs/storybook/pull/16663))\n\n## 6.4.0-rc.3 (November 16, 2021)\n\n### Bug Fixes\n\n- Angular: Fix detection of @angular/cli package version ([#16696](https://github.com/storybookjs/storybook/pull/16696))\n\n## 6.4.0-rc.2 (November 16, 2021)\n\n### Features\n\n- Core: Add option to use webpack filesystem cache ([#16219](https://github.com/storybookjs/storybook/pull/16219))\n\n### Bug Fixes\n\n- CLI: Fix automigrate command for eslint with extends as string ([#16687](https://github.com/storybookjs/storybook/pull/16687))\n- Core: Bust the prebuilt manager cache if user has set `features` ([#16684](https://github.com/storybookjs/storybook/pull/16684))\n\n### Maintenance\n\n- Build: GH Action for exporting to linear by GH label ([#16683](https://github.com/storybookjs/storybook/pull/16683))\n\n## 6.4.0-rc.1 (November 13, 2021)\n\n### Features\n\n- Angular: Add getWebpackConfig for angular 12.2.x & 13.x.x ([#16644](https://github.com/storybookjs/storybook/pull/16644))\n\n## 6.4.0-rc.0 (November 12, 2021)\n\nStorybook 6.4 is in RC!! 🎉🎉🎉\n\nHundreds of improvements and fixes, including:\n\n- ▶️ **Interactive stories** to simulate user behavior and tools to debug it\n- ⚡️ **On-demand architecture** for smaller builds and faster load times\n- ⛸ **Streamlined tooling and documentation** for easier upgrades\n- 💯 **Hundreds more fixes** and quality of life improvements\n\nTrack the release in the Github: [Storybook 6.4 Release 🛠](https://github.com/storybookjs/storybook/issues/15355)\n\n## 6.4.0-beta.33 (November 12, 2021)\n\n### Features\n\n- UI: Remove `nopreview` and show redbox for any story error ([#16669](https://github.com/storybookjs/storybook/pull/16669))\n- CLI: Run automigrate at the end of `sb init` ([#16671](https://github.com/storybookjs/storybook/pull/16671))\n- UI: Docs loading state (WIP) ([#16666](https://github.com/storybookjs/storybook/pull/16666))\n\n### Bugs\n\n- Addon-actions: Omit sending window object thru the channel ([#16514](https://github.com/storybookjs/storybook/pull/16514))\n\n### Maintenance\n\n- Build: Fix CI checks ([#16535](https://github.com/storybookjs/storybook/pull/16535))\n- Build: Add eslint-plugin-storybook to the repo ([#16662](https://github.com/storybookjs/storybook/pull/16662))\n\n## 6.4.0-beta.32 (November 12, 2021)\n\n### Features\n\n- CLI: Add eslint-plugin-storybook to automigrate ([#16550](https://github.com/storybookjs/storybook/pull/16550))\n\n### Bug Fixes\n\n- Core: Ensure manager caching respects globals ([#16653](https://github.com/storybookjs/storybook/pull/16653))\n- Core: Move the websocket channel to a specific path ([#16665](https://github.com/storybookjs/storybook/pull/16665))\n- Storyshots: Fix autotitle ([#16568](https://github.com/storybookjs/storybook/pull/16568))\n\n### Maintenance\n\n- Interactions: Use Icon button and add disabled state to IconButton ([#16601](https://github.com/storybookjs/storybook/pull/16601))\n- Add handle-release-branches-workflow ([#16580](https://github.com/storybookjs/storybook/pull/16580))\n- Addon-interactions: add waitForElementToBeRemoved example ([#16434](https://github.com/storybookjs/storybook/pull/16434))\n\n## 6.4.0-beta.31 (November 10, 2021)\n\n### Features\n\n- Core: Add feature flag to stop storybook from aliasing emotion ([#16613](https://github.com/storybookjs/storybook/pull/16613))\n\n### Bug Fixes\n\n- Core: Fix `staticDirs` and `-s` conflict check ([#16649](https://github.com/storybookjs/storybook/pull/16649))\n\n### Maintenance\n\n- Build: Add node-gyp for M1 macs ([#16645](https://github.com/storybookjs/storybook/pull/16645))\n\n## 6.4.0-beta.30 (November 8, 2021)\n\n### Features\n\n- Args: Add ability to specific argType \"targets\" ([#16333](https://github.com/storybookjs/storybook/pull/16333))\n\n### Bug Fixes\n\n- Core: Fix sorting by `__namedExportsOrder` ([#16626](https://github.com/storybookjs/storybook/pull/16626))\n- Angular: Fix zonejs imports in framework preset ([#16631](https://github.com/storybookjs/storybook/pull/16631))\n- Core: Change CSF loading problems from warning to error ([#16632](https://github.com/storybookjs/storybook/pull/16632))\n- Core: Fix args values updated from url to control ([#16508](https://github.com/storybookjs/storybook/pull/16508))\n- CLI: Fix upgrade error state ([#16622](https://github.com/storybookjs/storybook/pull/16622))\n\n## 6.4.0-beta.29 (November 6, 2021)\n\n### Features\n\n- CSFFile: Handle re-exported stories ([#16607](https://github.com/storybookjs/storybook/pull/16607))\n\n### Bug Fixes\n\n- StoryIndex: Skip files with no default export ([#16606](https://github.com/storybookjs/storybook/pull/16606))\n- Addon-docs/Source: Fix disabling show code with null ([#16615](https://github.com/storybookjs/storybook/pull/16615))\n- Core: Handle missing websocket in production build ([#16590](https://github.com/storybookjs/storybook/pull/16590))\n- Core: Ensure we set `parameters.filePath` in v7 mode ([#16566](https://github.com/storybookjs/storybook/pull/16566))\n- Core: Fix behavior around missing stories to be more clear ([#16608](https://github.com/storybookjs/storybook/pull/16608))\n\n## 6.4.0-beta.28 (November 5, 2021)\n\n### Bug Fixes\n\n- Interactions: Fix README link ([#16596](https://github.com/storybookjs/storybook/pull/16596))\n\n## 6.4.0-beta.27 (November 4, 2021)\n\n### Features\n\n- Core: Add 'staticDirs' config option ([#15969](https://github.com/storybookjs/storybook/pull/15969))\n\n### Bug Fixes\n\n- TS: Fix type for Refs so they can be disabled ([#16582](https://github.com/storybookjs/storybook/pull/16582))\n- CLI: Add a check for source-dir in `sb extract` ([#16505](https://github.com/storybookjs/storybook/pull/16505))\n- UI: Fix links that have no onClick handler ([#16581](https://github.com/storybookjs/storybook/pull/16581))\n- Core: Continue running play function on rerender ([#16574](https://github.com/storybookjs/storybook/pull/16574))\n- Ensure we always initialize the story store, even when the index errors. ([#16537](https://github.com/storybookjs/storybook/pull/16537))\n- Interactions: Fix panel tab icon/count ([#16578](https://github.com/storybookjs/storybook/pull/16578))\n\n### Dependency Upgrades\n\n- Pin the version of `history` for `react-router-dom` compat ([#16560](https://github.com/storybookjs/storybook/pull/16560))\n\n## 6.4.0-beta.26 (November 2, 2021)\n\n### Bug Fixes\n\n- Core: Replace SSE with websockets ([#16504](https://github.com/storybookjs/storybook/pull/16504))\n- UI: Upgrade react-router ([#16554](https://github.com/storybookjs/storybook/pull/16554))\n- Addon-docs/HTML: Fix source snippetization for DOM elements ([#16553](https://github.com/storybookjs/storybook/pull/16553))\n\n## 6.4.0-beta.25 (November 2, 2021)\n\n### Bug Fixes\n\n- Core: Fix `decorateStory` exports from frameworks that have it ([#16529](https://github.com/storybookjs/storybook/pull/16529))\n- Fix v7.0 type exports and update MIGRATION.md ([#16466](https://github.com/storybookjs/storybook/pull/16466))\n- UI: Do not display menu toggle when `singleStory=true` ([#15755](https://github.com/storybookjs/storybook/pull/15755))\n\n### Maintenance\n\n- Core: Improve webpack chunk names ([#16513](https://github.com/storybookjs/storybook/pull/16513))\n\n### Dependency Upgrades\n\n- Migrate from micromatch to picomatch ([#16522](https://github.com/storybookjs/storybook/pull/16522))\n- Add qs as a dev dependency of the api package ([#16525](https://github.com/storybookjs/storybook/pull/16525))\n\n## 6.4.0-beta.24 (November 2, 2021)\n\nbad npm publish\n\n# 6.4.0-beta.23 (October 29, 2021)\n\n### Features\n\n- Core: Add support for async `getProjectAnnotations` function ([#16495](https://github.com/storybookjs/storybook/pull/16495))\n\n### Bug Fixes\n\n- Addon-docs: Fix centered layout on DocsPage ([#16506](https://github.com/storybookjs/storybook/pull/16506))\n- Addon-docs/Angular: Fix missing condition in compodoc resolveTypealias ([#16523](https://github.com/storybookjs/storybook/pull/16523))\n- Core: Fix `toImportFn` when dealing with `../`-led paths ([#16474](https://github.com/storybookjs/storybook/pull/16474))\n\n### Maintenance\n\n- UI: Update the toolbar button styles ([#16429](https://github.com/storybookjs/storybook/pull/16429))\n- CLI: Fix build selection menu ([#16521](https://github.com/storybookjs/storybook/pull/16521))\n- Core: Use synchronous promises to \"fake\" promises for sync code ([#16517](https://github.com/storybookjs/storybook/pull/16517))\n- UI: Improve WithTooltip contrast and positioning ([#16510](https://github.com/storybookjs/storybook/pull/16510))\n\n## 6.4.0-beta.22 (October 28, 2021)\n\n### Bug Fixes\n\n- Addon-docs: Track code-level args changes in `ArgsTable` ([#16488](https://github.com/storybookjs/storybook/pull/16488))\n\n### Maintenance\n\n- Addon-a11y: Lazy load axe-core only when running tests ([#16484](https://github.com/storybookjs/storybook/pull/16484))\n- Addon-docs: Lazy load Prettier in Vue and Angular ([#16459](https://github.com/storybookjs/storybook/pull/16459))\n\n## 6.4.0-beta.21 (October 28, 2021)\n\n### Features\n\n- Core: Rerun loaders when args/globals change ([#16476](https://github.com/storybookjs/storybook/pull/16476))\n- Interactions: move step debugger behind a feature flag ([#16481](https://github.com/storybookjs/storybook/pull/16481))\n\n### Bug Fixes\n\n- Core: Always update initial args when loading a story ([#16487](https://github.com/storybookjs/storybook/pull/16487))\n- Core: Ensure we don't reset `WebPreview` if calling `start()` in v7 mode ([#16475](https://github.com/storybookjs/storybook/pull/16475))\n- Core: Save and restore globals on preview init using the channel ([#16469](https://github.com/storybookjs/storybook/pull/16469))\n\n### Maintenance\n\n- CI: Upgrade Cypress and Node.js version used in e2e tests ([#16263](https://github.com/storybookjs/storybook/pull/16263))\n\n### Dependency Upgrades\n\n- Interactions: Use latest package versions ([#16464](https://github.com/storybookjs/storybook/pull/16464))\n\n## 6.4.0-beta.20 (October 26, 2021)\n\n### Bug Fixes\n\n- Interactions: Do not cleanup state when loading initial story ([#16462](https://github.com/storybookjs/storybook/pull/16462))\n- Addon-interactions: Add safety check on fileName parameter ([#16454](https://github.com/storybookjs/storybook/pull/16454))\n- Core: Fix optional global features in PreviewWeb ([#16448](https://github.com/storybookjs/storybook/pull/16448))\n\n### Maintenance\n\n- UI: Migrate router to react-router ([#16440](https://github.com/storybookjs/storybook/pull/16440))\n\n## 6.4.0-beta.19 (October 22, 2021)\n\n### Bug Fixes\n\n- Core: Fix some slashes for windows ([#16445](https://github.com/storybookjs/storybook/pull/16445))\n\n### Maintenance\n\n- Core: Add typing for StorybookConfig.refs ([#16443](https://github.com/storybookjs/storybook/pull/16443))\n\n## 6.4.0-beta.18 (October 21, 2021)\n\n### Features\n\n- StoryIndex: Detect added/moved directories and batch invalidations ([#16432](https://github.com/storybookjs/storybook/pull/16432))\n\n### Bug Fixes\n\n- Core: Fix module loading support ([#16404](https://github.com/storybookjs/storybook/pull/16404))\n- Addon-links: Modernize to be compatible with v7 store ([#16420](https://github.com/storybookjs/storybook/pull/16420))\n\n### Maintenance\n\n- CLI: Improve build-storybooks script in the monorepo ([#16433](https://github.com/storybookjs/storybook/pull/16433))\n\n## 6.4.0-beta.17 (October 21, 2021)\n\n### Features\n\n- Core: Add `core.channelOptions` main.js config ([#16415](https://github.com/storybookjs/storybook/pull/16415))\n\n### Maintenance\n\n- Addon-docs: Lazy load docs to reduce bundle size ([#16412](https://github.com/storybookjs/storybook/pull/16412))\n- UI: Update mono font stack ([#16409](https://github.com/storybookjs/storybook/pull/16409))\n- UI: Update sidebar hover color to be a refreshing transparent blue ([#16408](https://github.com/storybookjs/storybook/pull/16408))\n\n## 6.4.0-beta.16 (October 20, 2021)\n\n### Bug Fixes\n\n- Core: Consolidate framework presets ([#16417](https://github.com/storybookjs/storybook/pull/16417))\n- Addon-a11y: Fix to use `loadStory` over deprecated `fromId` ([#16398](https://github.com/storybookjs/storybook/pull/16398))\n- Core: Restore `queryparams` exports in `client-api` ([#16414](https://github.com/storybookjs/storybook/pull/16414))\n\n### Maintenance\n\n- Core: Minor cleanup of `PreviewWeb` ([#16418](https://github.com/storybookjs/storybook/pull/16418))\n\n### Dependency Upgrades\n\n- Update `react-element-to-jsx-string` package ([#16407](https://github.com/storybookjs/storybook/pull/16407))\n\n## 6.4.0-beta.15 (October 19, 2021)\n\n### Features\n\n- Core: Add `framework` field support to main.js ([#16393](https://github.com/storybookjs/storybook/pull/16393))\n\n### Bug Fixes\n\n- Addon-docs: Spread all the old docs context fields ([#16399](https://github.com/storybookjs/storybook/pull/16399))\n- Core: Reverse checking of promise so it's OK if we get it wrong ([#16396](https://github.com/storybookjs/storybook/pull/16396))\n\n### Maintenance\n\n- Addon-interactions: Update interaction hover icon ([#16388](https://github.com/storybookjs/storybook/pull/16388))\n- Core: Refactor story store to be simpler when getting the index ([#16397](https://github.com/storybookjs/storybook/pull/16397))\n\n## 6.4.0-beta.14 (October 19, 2021)\n\n### Bug Fixes\n\n- Core: Fix bad deprecation link for argType.defaultValue ([#16391](https://github.com/storybookjs/storybook/pull/16391))\n- Storyshots/vue3: Fix story render with singleton vue3 app ([#15983](https://github.com/storybookjs/storybook/pull/15983))\n- Angular: Fix preset for storyStoreV7 ([#16380](https://github.com/storybookjs/storybook/pull/16380))\n- Core: Fix Args combination to allow `undefined` overrides ([#16385](https://github.com/storybookjs/storybook/pull/16385))\n- Core: Fix missing FEATURES global ([#16389](https://github.com/storybookjs/storybook/pull/16389))\n\n### Dependency Upgrades\n\n- Upgrade chromatic CLI ([#16320](https://github.com/storybookjs/storybook/pull/16320))\n\n## 6.4.0-beta.13 (October 18, 2021)\n\n### Features\n\n- Core: Listen to story change events as soon as the preview is created ([#16331](https://github.com/storybookjs/storybook/pull/16331))\n\n### Bug Fixes\n\n- Addon-controls: Fix `{control: false}` handling ([#16366](https://github.com/storybookjs/storybook/pull/16366))\n- CLI: Fix broken link in react native template ([#16372](https://github.com/storybookjs/storybook/pull/16372))\n- UI: Fix scrollbar color to be visible in dark theme ([#16345](https://github.com/storybookjs/storybook/pull/16345))\n\n## 6.4.0-beta.12 (October 15, 2021)\n\n### Features\n\n- Addon-interactions: New addon for step debugging play functions ([#16002](https://github.com/storybookjs/storybook/pull/16002))\n- Addon-interactions: Add rewind button to interactions subnav ([#16042](https://github.com/storybookjs/storybook/pull/16042))\n\n## 6.3.12 (October 14, 2021)\n\n### Bug Fixes\n\n- CLI: Force `sb upgrade` to use latest version of `npm-check-updates` ([#16336](https://github.com/storybookjs/storybook/pull/16336))\n\n## 6.4.0-beta.11 (October 14, 2021)\n\n### Features\n\n- Core: Align storyIndex generated by the server and client ([#16311](https://github.com/storybookjs/storybook/pull/16311))\n- Core: Render behavior around play functions ([#16208](https://github.com/storybookjs/storybook/pull/16208))\n- Angular: Allow to set configuration in angularBrowserTarget ([#16218](https://github.com/storybookjs/storybook/pull/16218))\n\n### Bug Fixes\n\n- CLI: Force `sb upgrade` to use latest version of `npm-check-updates` ([#16336](https://github.com/storybookjs/storybook/pull/16336))\n\n### Maintenance\n\n- Core: Fix broken build ([#16346](https://github.com/storybookjs/storybook/pull/16346))\n\n## 6.4.0-beta.10 (October 13, 2021)\n\n### Features\n\n- Composition: Add expanded option to Refs ([#14345](https://github.com/storybookjs/storybook/pull/14345))\n- Core: Add Story Index error handling ([#16319](https://github.com/storybookjs/storybook/pull/16319))\n\n### Bug Fixes\n\n- Core: Fix paths to be relative to working dir in v7 mode ([#16328](https://github.com/storybookjs/storybook/pull/16328))\n- Core: Don't fetch `stories.json`, JSON or SSE, if we don't need it ([#16318](https://github.com/storybookjs/storybook/pull/16318))\n\n### Maintenance\n\n- CLI: Add js extension to lit-html imports ([#16244](https://github.com/storybookjs/storybook/pull/16244))\n- Story-sort: Catch errors and direct user towards migration docs ([#16242](https://github.com/storybookjs/storybook/pull/16242))\n\n## 6.3.11 (October 12, 2021)\n\n### Bug Fixes\n\n- CLI: Fix CRA version detection crash ([#16308](https://github.com/storybookjs/storybook/pull/16308))\n\n## 6.4.0-beta.9 (October 12, 2021)\n\n### Features\n\n- Webpack5: Don't emit stats unless debugWebpack is set ([#16132](https://github.com/storybookjs/storybook/pull/16132))\n\n### Bug Fixes\n\n- CLI: Fix CRA version detection crash ([#16308](https://github.com/storybookjs/storybook/pull/16308))\n- Core: Better story id generation, cope with unusual stories ([#16309](https://github.com/storybookjs/storybook/pull/16309))\n- Core: Simplify `DOCS_RENDERED` and only use `STORY_RENDERED` for hooks ([#16310](https://github.com/storybookjs/storybook/pull/16310))\n- Core: Fix `extract`, `SET_STORIES` and `getStoriesJsonData` ([#16299](https://github.com/storybookjs/storybook/pull/16299))\n- TypeScript: Add `id` to BaseMeta type ([#16216](https://github.com/storybookjs/storybook/pull/16216))\n- CSF: Fix support for `X.story` annotations ([#16297](https://github.com/storybookjs/storybook/pull/16297))\n\n## 6.4.0-beta.8 (October 11, 2021)\n\n### Bug Fixes\n\n- Core: Fix multiple invalidations ([#16294](https://github.com/storybookjs/storybook/pull/16294))\n\n### Maintenance\n\n- Add ability to skip cypress tests based on framework ([#16285](https://github.com/storybookjs/storybook/pull/16285))\n\n### Dependency Upgrades\n\n- Addons: Add webpack-env as dependency ([#16302](https://github.com/storybookjs/storybook/pull/16302))\n- Upgrade npmlog dependency ([#16289](https://github.com/storybookjs/storybook/pull/16289))\n\n## 6.4.0-beta.7 (October 8, 2021)\n\n### Bug Fixes\n\n- Addon-docs: Always render the `children` of the `Canvas` component ([#16280](https://github.com/storybookjs/storybook/pull/16280))\n- Addon-docs: Fix args passing for Vue inline rendering ([#16279](https://github.com/storybookjs/storybook/pull/16279))\n\n## 6.4.0-beta.6 (October 7, 2021)\n\n### Features\n\n- Core: HMR for StoryIndex server ([#16160](https://github.com/storybookjs/storybook/pull/16160))\n\n### Bug Fixes\n\n- Angular: Make types generic for angular's built-in decorators ([#16266](https://github.com/storybookjs/storybook/pull/16266))\n- Args: Re-render the whole container when args or globals change ([#16264](https://github.com/storybookjs/storybook/pull/16264))\n\n### Maintenance\n\n- CSF: Add CSF2 play function example ([#16121](https://github.com/storybookjs/storybook/pull/16121))\n- Core: Unified story specifiers ([#16220](https://github.com/storybookjs/storybook/pull/16220))\n\n## 6.3.10 (October 6, 2021)\n\n### Bug Fixes\n\n- CLI: Don't upgrade preset-create-react-app if react-scripts < 5 ([#16255](https://github.com/storybookjs/storybook/pull/16255))\n\n## 6.4.0-beta.5 (October 6, 2021)\n\n### Features\n\n- CLI: Add \"automigrate\" command for configuration issues and migrations ([#16193](https://github.com/storybookjs/storybook/pull/16193))\n- Vue: support @values in args table ([#16019](https://github.com/storybookjs/storybook/pull/16019))\n\n### Bug Fixes\n\n- CLI: Don't upgrade preset-create-react-app if react-scripts < 5 ([#16255](https://github.com/storybookjs/storybook/pull/16255))\n- Angular: Fix getComponentInputsOutputs for multiple decorators ([#16217](https://github.com/storybookjs/storybook/pull/16217))\n\n### Maintenance\n\n- CSF: Add error handling for CSF story index generation ([#16241](https://github.com/storybookjs/storybook/pull/16241))\n- Official-storybook: Fix show source in no-args stories ([#16259](https://github.com/storybookjs/storybook/pull/16259))\n- CLI: Remove story format parameter ([#16233](https://github.com/storybookjs/storybook/pull/16233))\n\n## 6.4.0-beta.4 (October 5, 2021)\n\n### Features\n\n- Core: Support v2 compatibility mode in story index ([#16226](https://github.com/storybookjs/storybook/pull/16226))\n- Core: Support composing stories in both v6 and v7 modes ([#16224](https://github.com/storybookjs/storybook/pull/16224))\n- Web-components: Autogenerate action argTypes for event. ([#16178](https://github.com/storybookjs/storybook/pull/16178))\n\n### Bug Fixes\n\n- Addon-a11y: Fix type of context passed to `axe.run` ([#16129](https://github.com/storybookjs/storybook/pull/16129))\n- Addon-docs/Angular: Fix inline story rendering ([#16149](https://github.com/storybookjs/storybook/pull/16149))\n- Components: Fix Code component to render children as array ([#15492](https://github.com/storybookjs/storybook/pull/15492))\n\n### Maintenance\n\n- CLI: Remove watch mode from the build-storybook documentation ([#16165](https://github.com/storybookjs/storybook/pull/16165))\n\n## 6.3.9 (October 1, 2021)\n\n### Maintenance\n\n- CLI: Add webpack5 builder to CRA5 `sb init` ([#16194](https://github.com/storybookjs/storybook/pull/16194))\n\n## 6.4.0-beta.3 (October 1, 2021)\n\n### Maintenance\n\n- CLI: Add webpack5 builder to CRA5 `sb init` ([#16194](https://github.com/storybookjs/storybook/pull/16194))\n\n## 6.4.0-beta.2 (October 1, 2021)\n\n### Bug Fixes\n\n- Controls: Hide color control format toggle when no value ([#16186](https://github.com/storybookjs/storybook/pull/16186))\n\n### Dependency Upgrades\n\n- Upgrade boxen to 5.x ([#16190](https://github.com/storybookjs/storybook/pull/16190))\n- Upgrade react-dev-utils to 11.0.4 ([#16196](https://github.com/storybookjs/storybook/pull/16196))\n- Dependencies: Fix ansi-html vulnerability ([#16155](https://github.com/storybookjs/storybook/pull/16155))\n\n### Maintenance\n\n- CLI: Better scope sample page component styles ([#16185](https://github.com/storybookjs/storybook/pull/16185))\n\n## 6.4.0-beta.1 (September 26, 2021)\n\n### Features\n\n- MDX: Support CSF3 play/render functions ([#16159](https://github.com/storybookjs/storybook/pull/16159))\n- Addon-a11y: Export parameter types ([#16128](https://github.com/storybookjs/storybook/pull/16128))\n\n### Bug Fixes\n\n- Addon-docs: Fix loading behavior for Canvas doc block ([#16161](https://github.com/storybookjs/storybook/pull/16161))\n- Added index.d.ts for addon-docs/angular ([#16123](https://github.com/storybookjs/storybook/pull/16123))\n\n### Maintenance\n\n- Angular: Remove dead code in client ([#16137](https://github.com/storybookjs/storybook/pull/16137))\n\n## 6.4.0-beta.0 (September 22, 2021)\n\nStorybook 6.4 is in beta! 🎊\n\nSB6.4 adds interaction testing and performance re-architecture in preparation for a huge 7.0 release.\n\nTrack the release in the Github: [Storybook 6.4 Release 🛠](https://github.com/storybookjs/storybook/issues/15355)\n\n## 6.4.0-alpha.41 (September 22, 2021)\n\n### Bug Fixes\n\n- Core: Fix `./stories.json` requests in manager for relative paths ([#16114](https://github.com/storybookjs/storybook/pull/16114))\n- Core: Fix dotenv handling ([#16105](https://github.com/storybookjs/storybook/pull/16105))\n- Addon-docs: Fix embedding selected story in canvas block ([#15915](https://github.com/storybookjs/storybook/pull/15915))\n\n### Maintenance\n\n- Story index server: Add story sorting ([#16102](https://github.com/storybookjs/storybook/pull/16102))\n- Refactor `stories-json` to use a caching class ([#16106](https://github.com/storybookjs/storybook/pull/16106))\n\n## 6.4.0-alpha.40 (September 20, 2021)\n\n### Bug Fixes\n\n- Webpack5: Fix output paths ([#16074](https://github.com/storybookjs/storybook/pull/16074))\n- Core: Infer docs only stories ([#16101](https://github.com/storybookjs/storybook/pull/16101))\n- CSF3: Fix story type back-compat ([#16107](https://github.com/storybookjs/storybook/pull/16107))\n\n## 6.4.0-alpha.39 (September 18, 2021)\n\n### Features\n\n- CSF3: Add auto-title support to on-demand V7/V6 refactor ([#16098](https://github.com/storybookjs/storybook/pull/16098))\n\n## 6.4.0-alpha.38 (September 16, 2021)\n\n### Bug Fixes\n\n- Angular: Fix ng selector issue and dynamically show templates in stories ([#15976](https://github.com/storybookjs/storybook/pull/15976))\n- Core: Fix issue with more complex `stories` paths. ([#16078](https://github.com/storybookjs/storybook/pull/16078))\n\n### Maintenance\n\n- Main.js config: Fix Builder type ([#16013](https://github.com/storybookjs/storybook/pull/16013))\n\n## 6.4.0-alpha.37 (September 16, 2021)\n\n### Bug Fixes\n\n- Angular: Fix error handling for angular builder standalone builds ([#15978](https://github.com/storybookjs/storybook/pull/15978))\n- Addon-docs: Fix `useStories` to correctly respond to change in `storyId` ([#16046](https://github.com/storybookjs/storybook/pull/16046))\n\n## 6.4.0-alpha.36 (September 15, 2021)\n\n### Bug Fixes\n\n- Addon-docs: Ensure we don't clobber multiple source container state updates ([#16039](https://github.com/storybookjs/storybook/pull/16039))\n- Core: Restore deprecation warning for configure ([#16041](https://github.com/storybookjs/storybook/pull/16041))\n- Core: Be careful in `FEATURES` check ([#16044](https://github.com/storybookjs/storybook/pull/16044))\n\n## 6.4.0-alpha.35 (September 14, 2021)\n\n### Features\n\n- Core: On demand store ([#15871](https://github.com/storybookjs/storybook/pull/15871))\n\n### Bug Fixes\n\n- UI: Fix ActionButton out of position in Safari ([#15981](https://github.com/storybookjs/storybook/pull/15981))\n\n## 6.4.0-alpha.34 (September 7, 2021)\n\n### Features\n\n- Angular: Support storybook configuration for projects with only angular Library ([#15744](https://github.com/storybookjs/storybook/pull/15744))\n- CLI: Show framework name in startup banner ([#15966](https://github.com/storybookjs/storybook/pull/15966))\n\n### Bug Fixes\n\n- CLI: Fix sb link to yarn3 repos ([#15989](https://github.com/storybookjs/storybook/pull/15989))\n- Core: Pass proper stack of an error ([#15864](https://github.com/storybookjs/storybook/pull/15864))\n- Addon-docs/Angular: Fix default values in ArgsTable ([#15881](https://github.com/storybookjs/storybook/pull/15881))\n\n### Maintenance\n\n- Core: Replaced `process.env` override in `DefinePlugin` config ([#15925](https://github.com/storybookjs/storybook/pull/15925))\n- CSF: Infer defaultValue of argtype based on arg ([#15798](https://github.com/storybookjs/storybook/pull/15798))\n\n## 6.3.8 (September 3, 2021)\n\n### Maintenance\n\n- Core: Write JSON stats file in streaming fashion and omit `chunks` for brevity ([#15889](https://github.com/storybookjs/storybook/pull/15889))\n\n## 6.4.0-alpha.33 (September 1, 2021)\n\n### Bug Fixes\n\n- TypeScript: Fix glob pattern used in package `typesVersions` config ([#15918](https://github.com/storybookjs/storybook/pull/15918))\n\n### Maintenance\n\n- Core: Add Babel mode v7 ([#15928](https://github.com/storybookjs/storybook/pull/15928))\n- Core: Write JSON stats file in streaming fashion and omit `chunks` for brevity ([#15889](https://github.com/storybookjs/storybook/pull/15889))\n- UI: Add playback icons ([#15909](https://github.com/storybookjs/storybook/pull/15909))\n- Misc: Generate and push repros to a GitHub repo every night ([#15877](https://github.com/storybookjs/storybook/pull/15877))\n\n### Dependency Upgrades\n\n- Bump cpy to 8.1.2 for security ([#15953](https://github.com/storybookjs/storybook/pull/15953))\n\n## 6.4.0-alpha.32 (August 24, 2021)\n\n### Features\n\n- CLI/Storyshots: Specify custom sb extract Chromium exe ([#15878](https://github.com/storybookjs/storybook/pull/15878))\n\n### Bug Fixes\n\n- Angular: Fix Cannot read property 'selector' of undefined ([#15874](https://github.com/storybookjs/storybook/pull/15874))\n- Addon-docs: Fix refs support in Docs pages ([#15890](https://github.com/storybookjs/storybook/pull/15890))\n\n## 6.4.0-alpha.31 (August 23, 2021)\n\n### Features\n\n- UI: Add skip to canvas/sidebar links ([#15740](https://github.com/storybookjs/storybook/pull/15740))\n- Controls: Add id to setter button for undefined values ([#15729](https://github.com/storybookjs/storybook/pull/15729))\n\n### Bug Fixes\n\n- CSF3: Normalize windows paths in autoTitle ([#15770](https://github.com/storybookjs/storybook/pull/15770))\n- Addon-docs: Fix newline handling in ArgsTable code blocks ([#12882](https://github.com/storybookjs/storybook/pull/12882))\n\n### Maintenance\n\n- Build: Update `caniuse-lite` dependency ([#15863](https://github.com/storybookjs/storybook/pull/15863))\n\n## 6.4.0-alpha.30 (August 14, 2021)\n\n### Maintenance\n\n- CLI: Improve typings of Angular components ([#15832](https://github.com/storybookjs/storybook/pull/15832))\n- Controls: Fix `esm is not defined` error with built Storybook ([#15812](https://github.com/storybookjs/storybook/pull/15812))\n\n## 6.4.0-alpha.29 (August 10, 2021)\n\n### Features\n\n- Addon-docs/Angular: Render user defined template as source if it exists ([#15743](https://github.com/storybookjs/storybook/pull/15743))\n- Core: Add MDX support to built-in stories.json generation ([#15808](https://github.com/storybookjs/storybook/pull/15808))\n\n### Maintenance\n\n- Controls: Add better icon for reset button ([#15737](https://github.com/storybookjs/storybook/pull/15737))\n- Add checkboxes to pull request template ([#15799](https://github.com/storybookjs/storybook/pull/15799))\n\n## 6.4.0-alpha.28 (August 10, 2021)\n\nFix bad publish of `6.4.0-alpha.27` to the `latest` tag\n\n## 6.3.7 (August 10, 2021)\n\nFix bad publish of `6.4.0-alpha.27` to the `latest` tag\n\n## 6.4.0-alpha.26 (August 9, 2021)\n\n### Maintenance\n\n- Server: Update example to use options and labels for options controls ([#15789](https://github.com/storybookjs/storybook/pull/15789))\n- Controls: Remove ArrayControl ([#15788](https://github.com/storybookjs/storybook/pull/15788))\n\n## 6.4.0-alpha.25 (August 8, 2021)\n\n### Features\n\n- Angular: Add global CSF3 renderer ([#15742](https://github.com/storybookjs/storybook/pull/15742))\n\n### Bug Fixes\n\n- Addon-docs/Angular: Use compodoc rawdescription where available ([#15774](https://github.com/storybookjs/storybook/pull/15774))\n- Core: Fix main.js glob resolution for direct paths in stories ([#15775](https://github.com/storybookjs/storybook/pull/15775))\n\n### Maintenance\n\n- CSF: Optionally pass Args generic type from BaseAnnotations to ArgTypes ([#14356](https://github.com/storybookjs/storybook/pull/14356))\n\n## 6.4.0-alpha.24 (August 4, 2021)\n\n### Features\n\n- HTML: Dynamic source snippets ([#15748](https://github.com/storybookjs/storybook/pull/15748))\n\n## 6.4.0-alpha.23 (August 3, 2021)\n\n### Features\n\n- CLI: Add --no-open flag ([#15739](https://github.com/storybookjs/storybook/pull/15739))\n\n### Bug Fixes\n\n- Angular: Fix incomplete property metadata when using inheritance ([#15586](https://github.com/storybookjs/storybook/pull/15586))\n\n### Maintenance\n\n- Build: Upgrade to Yarn 3 ([#15682](https://github.com/storybookjs/storybook/pull/15682))\n\n### Dependency Upgrades\n\n- Lower babel-loader required version ([#14811](https://github.com/storybookjs/storybook/pull/14811))\n- Relax prettier version constraint ([#15298](https://github.com/storybookjs/storybook/pull/15298))\n\n## 6.4.0-alpha.22 (July 28, 2021)\n\n### Features\n\n- CSF3: Add auto-titles from standard glob patterns ([#15697](https://github.com/storybookjs/storybook/pull/15697))\n- CSF3: Add startCase to auto-generated titles ([#15618](https://github.com/storybookjs/storybook/pull/15618))\n\n### Bug Fixes\n\n- CLI: Fix Svelte CLI template markup ([#15689](https://github.com/storybookjs/storybook/pull/15689))\n\n### Maintenance\n\n- Server: Upgrade to CSF3 ([#15698](https://github.com/storybookjs/storybook/pull/15698))\n\n### Dependency Upgrades\n\n- Fix some transitive peer dependency warnings ([#15687](https://github.com/storybookjs/storybook/pull/15687))\n- Upgrade react-refresh plugin to fix fast refresh on Webpack5 ([#15616](https://github.com/storybookjs/storybook/pull/15616))\n\n## 6.3.6 (July 26, 2021)\n\n### Bug Fixes\n\n- CLI: Fix debug webpack output in static build ([#15674](https://github.com/storybookjs/storybook/pull/15674))\n- CSF3: Fix custom render function ([#15668](https://github.com/storybookjs/storybook/pull/15668))\n\n## 6.4.0-alpha.21 (July 26, 2021)\n\n### Bug Fixes\n\n- CLI: Fix debug webpack output in static build ([#15674](https://github.com/storybookjs/storybook/pull/15674))\n- Controls: Fix boolean toggle style to match underlying value ([#15676](https://github.com/storybookjs/storybook/pull/15676))\n- Components: Fix Button to accept href attribute ([#15671](https://github.com/storybookjs/storybook/pull/15671))\n\n## 6.4.0-alpha.20 (July 24, 2021)\n\n### Bug Fixes\n\n- CSF3: Fix custom render function ([#15668](https://github.com/storybookjs/storybook/pull/15668))\n\n### Dependency Upgrades\n\n- Remove glob-base dependency ([#15399](https://github.com/storybookjs/storybook/pull/15399))\n\n## 6.3.5 (July 22, 2021)\n\n### Bug Fixes\n\n- Controls: Don't set arg in validateOptions if it would be `undefined` ([#15654](https://github.com/storybookjs/storybook/pull/15654))\n- Trailing comma handling for \"-s\" command line parameter ([#15615](https://github.com/storybookjs/storybook/pull/15615))\n- Controls: Fix color matching behavior for non-string types ([#15549](https://github.com/storybookjs/storybook/pull/15549))\n- Composition: Fix refs ordering ([#15527](https://github.com/storybookjs/storybook/pull/15527))\n\n## 6.4.0-alpha.19 (July 22, 2021)\n\n### Features\n\n- Controls: Don't set arg in validateOptions if it would be `undefined` ([#15654](https://github.com/storybookjs/storybook/pull/15654))\n- Vue: Add support for tsx ([#11936](https://github.com/storybookjs/storybook/pull/11936))\n\n### Bug Fixes\n\n- CLI: Fix trailing comma handling for \"-s\" command line parameter ([#15615](https://github.com/storybookjs/storybook/pull/15615))\n- Components: Lazy-load syntax highlighter ([#15607](https://github.com/storybookjs/storybook/pull/15607))\n\n### Maintenance\n\n- Controls: Clean up arg unboxing and switch statements ([#14394](https://github.com/storybookjs/storybook/pull/14394))\n- Examples: Fix react-ts to be runnable standalone ([#15621](https://github.com/storybookjs/storybook/pull/15621))\n\n## 6.4.0-alpha.18 (July 16, 2021)\n\n### Features\n\n- UI: Allow keyboard shortcut to copy code in preview blocks ([#15559](https://github.com/storybookjs/storybook/pull/15559))\n\n### Maintenance\n\n- Avoid slow regex.match call in renderJsx ([#15581](https://github.com/storybookjs/storybook/pull/15581))\n\n## 6.4.0-alpha.17 (July 15, 2021)\n\n### Features\n\n- Types: Export BaseStoryFn and BaseStoryObject ([#15592](https://github.com/storybookjs/storybook/pull/15592))\n- Addon-docs: Add transparency support to color swatch ([#14439](https://github.com/storybookjs/storybook/pull/14439))\n\n## 6.4.0-alpha.16 (July 13, 2021)\n\n### Features\n\n- Addon-backgrounds: Respect user's reduced motion settings ([#13711](https://github.com/storybookjs/storybook/pull/13711))\n- CSF: Add CSF3 typings ([#15558](https://github.com/storybookjs/storybook/pull/15558))\n\n### Bug Fixes\n\n- Angular: Fix actions argType auto generation ([#15563](https://github.com/storybookjs/storybook/pull/15563))\n\n## 6.4.0-alpha.15 (July 13, 2021)\n\n### Bug Fixes\n\n- Controls: Fix color matching behavior for non-string types ([#15549](https://github.com/storybookjs/storybook/pull/15549))\n- UI: Fix toggle button for custom theming ([#15449](https://github.com/storybookjs/storybook/pull/15449))\n\n### Maintenance\n\n- Build: Fix `publish` step on CircleCI ([#15556](https://github.com/storybookjs/storybook/pull/15556))\n- Examples: Add no-manager-cache to all examples ([#15546](https://github.com/storybookjs/storybook/pull/15546))\n- Official-storybook: Add example of embedding story object in MDX ([#15533](https://github.com/storybookjs/storybook/pull/15533))\n\n## 6.4.0-alpha.14 (July 11, 2021)\n\n### Features\n\n- Web-components: Dynamic source snippets ([#15337](https://github.com/storybookjs/storybook/pull/15337))\n\n### Maintenance\n\n- Essentials: Add measure addon to monorepo ([#15545](https://github.com/storybookjs/storybook/pull/15545))\n\n## 6.4.0-alpha.13 (July 9, 2021)\n\n### Bug Fixes\n\n- Addon-docs/Angular: Add unique id to Angular stories ([#15501](https://github.com/storybookjs/storybook/pull/15501))\n- Composition: Fix refs ordering ([#15527](https://github.com/storybookjs/storybook/pull/15527))\n\n### Maintenance\n\n- Essentials: Add outline addon to monorepo ([#15526](https://github.com/storybookjs/storybook/pull/15526))\n- Build: Fix cache setup in GitHub Actions workflow ([#15523](https://github.com/storybookjs/storybook/pull/15523))\n\n## 6.3.4 (July 8, 2021)\n\n### Maintenance\n\n- Addon-docs: Cache DocsContext on window to prevent duplication ([#15428](https://github.com/storybookjs/storybook/pull/15428))\n\n## 6.3.3 (July 7, 2021)\n\n### Bug Fixes\n\n- Webpack5: Quit process after finishing a static build ([#15483](https://github.com/storybookjs/storybook/pull/15483))\n- Addon-docs/Angular: Fix numeric args default value handling ([#15491](https://github.com/storybookjs/storybook/pull/15491))\n- Angular: Fix circular reference not being handled in moduleMetadata ([#15410](https://github.com/storybookjs/storybook/pull/15410))\n- Core: Fix double rebuilds by removing aggregateTimeout ([#15372](https://github.com/storybookjs/storybook/pull/15372))\n- CLI: Fix NPM typo ([#15461](https://github.com/storybookjs/storybook/pull/15461))\n\n## 6.4.0-alpha.12 (July 7, 2021)\n\n### Bug Fixes\n\n- Webpack5: Quit process after finishing a static build ([#15483](https://github.com/storybookjs/storybook/pull/15483))\n- Addon-docs/Angular: Fix numeric args default value handling ([#15491](https://github.com/storybookjs/storybook/pull/15491))\n\n### Maintenance\n\n- Angular: Make Ivy work by default in the angular-cli example ([#15280](https://github.com/storybookjs/storybook/pull/15280))\n- Official-storybook: Fix shortcut for navigating to previous language ([#15489](https://github.com/storybookjs/storybook/pull/15489))\n- Addon-docs: Add docs to standalone example ([#7848](https://github.com/storybookjs/storybook/pull/7848))\n- Build: Update Yarn cache setup in GitHub Actions workflow ([#15480](https://github.com/storybookjs/storybook/pull/15480))\n\n## 6.4.0-alpha.11 (July 3, 2021)\n\n### Bug Fixes\n\n- UI: Fix sidebar toggle in fullscreen mode ([#15459](https://github.com/storybookjs/storybook/pull/15459))\n- Angular: Fix circular reference not being handled in moduleMetadata ([#15410](https://github.com/storybookjs/storybook/pull/15410))\n\n### Maintenance\n\n- Addon-a11y: Reverse help and description labels in accordion ([#15466](https://github.com/storybookjs/storybook/pull/15466))\n\n## 6.4.0-alpha.10 (July 2, 2021)\n\n### Features\n\n- UI: Display menu icon on the toolbar when the sidebar is collapsed ([#15369](https://github.com/storybookjs/storybook/pull/15369))\n\n### Bug Fixes\n\n- Core: Fix double rebuilds by removing aggregateTimeout ([#15372](https://github.com/storybookjs/storybook/pull/15372))\n- CLI: Fix NPM typo ([#15461](https://github.com/storybookjs/storybook/pull/15461))\n\n### Maintenance\n\n- Addon-docs: Cache DocsContext on window to prevent duplication ([#15428](https://github.com/storybookjs/storybook/pull/15428))\n\n## 6.3.2 (June 30, 2021)\n\n### Bug Fixes\n\n- Essentials: Update measure and outline. Fix alt+tab issues on windows. ([#15402](https://github.com/storybookjs/storybook/pull/15402))\n- Core: Fix decorator context update ([#15408](https://github.com/storybookjs/storybook/pull/15408))\n- Revert \"Vue3: Update args without re-mounting component\" ([#15409](https://github.com/storybookjs/storybook/pull/15409))\n- Upgrade bad release of `react-docgen-typescript-plugin` ([#15432](https://github.com/storybookjs/storybook/pull/15432))\n\n## 6.4.0-alpha.9 (June 30, 2021)\n\n### Dependency Upgrades\n\n- Upgrade bad release of `react-docgen-typescript-plugin` ([#15432](https://github.com/storybookjs/storybook/pull/15432))\n\n## 6.4.0-alpha.8 (June 30, 2021)\n\n### Features\n\n- Web-components: Custom Elements Manifest v1 support ([#15138](https://github.com/storybookjs/storybook/pull/15138))\n\n### Bug Fixes\n\n- CSF: Fix auto-title generation for standard config dir ([#15430](https://github.com/storybookjs/storybook/pull/15430))\n\n### Dependency Upgrades\n\n- Upgrade `react-docgen-typescript-plugin` for refresh perf regression ([#15431](https://github.com/storybookjs/storybook/pull/15431))\n\n## 6.4.0-alpha.7 (June 29, 2021)\n\n### Features\n\n- CSF: Generate default titles based on file path ([#15376](https://github.com/storybookjs/storybook/pull/15376))\n\n## 6.4.0-alpha.6 (June 29, 2021)\n\n### Bug Fixes\n\n- Core: Fix decorator context update ([#15408](https://github.com/storybookjs/storybook/pull/15408))\n- Revert \"Vue3: Update args without re-mounting component\" ([#15409](https://github.com/storybookjs/storybook/pull/15409))\n\n## 6.4.0-alpha.5 (June 29, 2021)\n\n### Features\n\n- CSF: Add stories.json generation for CSF3 stories ([#15395](https://github.com/storybookjs/storybook/pull/15395))\n\n### Bug Fixes\n\n- Essentials: Update measure and outline. Fix alt+tab issues on windows. ([#15402](https://github.com/storybookjs/storybook/pull/15402))\n\n## 6.3.1 (June 28, 2021)\n\n### Bug Fixes\n\n- Core: Only use dotenv-webpack when a user has a dotenv file ([#15365](https://github.com/storybookjs/storybook/pull/15365))\n- Essentials: Update addon measure and outline ([#15354](https://github.com/storybookjs/storybook/pull/15354))\n- Actions: Don't override existing action args ([#15394](https://github.com/storybookjs/storybook/pull/15394))\n- Svelte: Fix argType.type.name extraction ([#15332](https://github.com/storybookjs/storybook/pull/15332))\n- CSF3: Genericize feature flagging and fix webpack5 ([#15375](https://github.com/storybookjs/storybook/pull/15375))\n- Webpack5: Fix warnings typo ([#15374](https://github.com/storybookjs/storybook/pull/15374))\n- UI: Fix navigation after no story error ([#15349](https://github.com/storybookjs/storybook/pull/15349))\n- CSF3: Rename setup to play ([#15358](https://github.com/storybookjs/storybook/pull/15358))\n- Upgrade dotenv-webpack to 7.0.x ([#15343](https://github.com/storybookjs/storybook/pull/15343))\n\n## 6.4.0-alpha.4 (June 28, 2021)\n\n### Bug Fixes\n\n- Actions: Don't override existing action args ([#15394](https://github.com/storybookjs/storybook/pull/15394))\n\n## 6.4.0-alpha.3 (June 26, 2021)\n\n### Bug Fixes\n\n- CSF3: Genericize feature flagging and fix webpack5 ([#15375](https://github.com/storybookjs/storybook/pull/15375))\n- Webpack5: Fix warnings typo ([#15374](https://github.com/storybookjs/storybook/pull/15374))\n\n## 6.4.0-alpha.2 (June 25, 2021)\n\n### Bug Fixes\n\n- Core: Only use dotenv-webpack when a user has a dotenv file ([#15365](https://github.com/storybookjs/storybook/pull/15365))\n\n### Maintenance\n\n- CSF3: Rename setup to play ([#15358](https://github.com/storybookjs/storybook/pull/15358))\n\n## 6.4.0-alpha.1 (June 25, 2021)\n\n### Bug Fixes\n\n- Essentials: Update addon measure and outline ([#15354](https://github.com/storybookjs/storybook/pull/15354))\n- UI: Fix navigation after no story error ([#15349](https://github.com/storybookjs/storybook/pull/15349))\n\n## 6.4.0-alpha.0 (June 24, 2021)\n\n### Bug Fixes\n\n- Svelte: Fix argType.type.name extraction ([#15332](https://github.com/storybookjs/storybook/pull/15332))\n\n### Dependency Upgrades\n\n- Upgrade dotenv-webpack to 7.0.x ([#15343](https://github.com/storybookjs/storybook/pull/15343))\n\n## 6.3.0 (June 23, 2021)\n\n**[Optimized for UI development](https://github.com/storybookjs/storybook/issues/14397)**\n\nSB6.3 adds new UI development and testing features, while evolving with the JS ecosystem:\n\n- 📐 Layout debugging with Measure and Outline addons\n- 🔌 Reuse your stories in unit tests: Jest, Cypress & more\n- 🚀 Frameworks: Angular 12 Ivy, Lit2 web components\n- 🛠 Builders: Webpack5 stable, Vite community\n- 📦 Packaging: Modern ESM\n\nIt also contains hundreds more fixes, features, and tweaks. Browse the [changelogs](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) matching `6.3.0-alpha.*`, `6.3.0-beta.*`, and `6.3.0-rc.*` for the full list of changes. See [Storybook 6 migration guide](https://storybook.js.org/blog/storybook-6-migration-guide/) to upgrade from `5.x` or [MIGRATION.md](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md) for detailed migration instructions.\n\n## 6.3.0-rc.12 (June 23, 2021)\n\n### Features\n\n- CLI: Update types in React typescript templates ([#15292](https://github.com/storybookjs/storybook/pull/15292))\n\n### Maintenance\n\n- Yarn: Disable unnecessary builds ([#15299](https://github.com/storybookjs/storybook/pull/15299))\n- Toolbars: Add missing `regenerator-runtime` dependency ([#15312](https://github.com/storybookjs/storybook/pull/15312))\n\n## 6.3.0-rc.11 (June 18, 2021)\n\n### Dependency Upgrades\n\n- Upgrade react-docgen-typescript-plugin per PR#46 ([#15287](https://github.com/storybookjs/storybook/pull/15287))\n- Fix peer deps ([#15288](https://github.com/storybookjs/storybook/pull/15288))\n\n## 6.3.0-rc.10 (June 17, 2021)\n\n### Bug Fixes\n\n- Angular: Fix nx project with workspace.json ([#15267](https://github.com/storybookjs/storybook/pull/15267))\n- Angular: Fix some Ivy rendering glitches ([#15279](https://github.com/storybookjs/storybook/pull/15279))\n\n## 6.3.0-rc.9 (June 17, 2021)\n\n### Dependency Upgrades\n\n- Bump postcss to 7.0.36 with security fix ([#15276](https://github.com/storybookjs/storybook/pull/15276))\n- Fix monorepo peer deps ([#15277](https://github.com/storybookjs/storybook/pull/15277))\n\n## 6.3.0-rc.8 (June 16, 2021)\n\n### Features\n\n- Angular: Add built-in Ivy support instead of relying on addon ([#15229](https://github.com/storybookjs/storybook/pull/15229))\n\n### Bug Fixes\n\n- Addon-docs: Fix MDX compiler export to match new location ([#15266](https://github.com/storybookjs/storybook/pull/15266))\n- Addon-viewport: Fix CSS for scale reset on firefox ([#15128](https://github.com/storybookjs/storybook/pull/15128))\n\n## 6.3.0-rc.7 (June 15, 2021)\n\n### Dependency Upgrades\n\n- Upgrade react-docgen-typescript-plugin to RDT 2.0 ([#15247](https://github.com/storybookjs/storybook/pull/15247))\n\n## 6.3.0-rc.6 (June 15, 2021)\n\n### Bug Fixes\n\n- Core: Only call setup function on story navigation ([#15244](https://github.com/storybookjs/storybook/pull/15244))\n\n### Maintenance\n\n- Official-storybook: Add CSF3 setup function demo ([#15245](https://github.com/storybookjs/storybook/pull/15245))\n\n### Dependency Upgrades\n\n- Use @storybook/react-docgen-typescript-plugin canary with PR#45 ([#15243](https://github.com/storybookjs/storybook/pull/15243))\n\n## 6.3.0-rc.5 (June 14, 2021)\n\n### Bug Fixes\n\n- Vue3: Update args without re-mounting component ([#15168](https://github.com/storybookjs/storybook/pull/15168))\n- Core: Preserve other query params when changing args/globals ([#15213](https://github.com/storybookjs/storybook/pull/15213))\n- UI: Fix range slider value label size changes causing jittering ([#15145](https://github.com/storybookjs/storybook/pull/15145))\n- Codemod: Fix dist/node_modules ignore heuristic ([#15222](https://github.com/storybookjs/storybook/pull/15222))\n- Core: Fix autoRefs check in manager-webpack ([#15197](https://github.com/storybookjs/storybook/pull/15197))\n\n### Maintenance\n\n- CSF3: Fix v1-style annotations in codemod ([#15230](https://github.com/storybookjs/storybook/pull/15230))\n- Core: CSF v3 preview ([#15217](https://github.com/storybookjs/storybook/pull/15217))\n\n## 6.3.0-rc.4 (June 12, 2021)\n\n### Dependency Upgrades\n\n- Vue3: Add vue-loader as a dependency ([#15207](https://github.com/storybookjs/storybook/pull/15207))\n\n## 6.3.0-rc.3 (June 11, 2021)\n\n### Features\n\n- Core: Disable sidebar and don't load refs when `singleStory=true` ([#15201](https://github.com/storybookjs/storybook/pull/15201))\n\n### Bug Fixes\n\n- Angular: Use docsMode to set docs options ([#15194](https://github.com/storybookjs/storybook/pull/15194))\n\n### Maintenance\n\n- Addon-docs: Split out MDX compiler into standalone package ([#15205](https://github.com/storybookjs/storybook/pull/15205))\n\n## 6.3.0-rc.2 (June 10, 2021)\n\n### Features\n\n- Core: Add `shortcuts` URL param to disable keyboard shortcuts ([#15192](https://github.com/storybookjs/storybook/pull/15192))\n\n### Bug Fixes\n\n- Angular: Fix builder runaway process ([#15189](https://github.com/storybookjs/storybook/pull/15189))\n\n## 6.3.0-rc.1 (June 10, 2021)\n\n### Maintenance\n\n- Core: Use named import for @storybook/addons, fixes vite builder ([#15187](https://github.com/storybookjs/storybook/pull/15187))\n\n## 6.3.0-rc.0 (June 9, 2021)\n\nStorybook 6.3 is in RC!! 🎉🎉🎉\n\nHundreds of improvements and fixes, including:\n\n- **Angular** - Angular12, Ivy, overhauled docs support.\n- **Web-components** - Lit2 support.\n- **Essentials** - New measure/outline addons for CSS debugging.\n- **Addon API** - Keyboard shortcuts for addons. Initial support in viewports, toolbars.\n- **Webpack 5** - Official support.\n- **Vite builder** - Community support.\n- **Modern ESM** - Modern package distribution.\n\nTrack the release in the Github: [Storybook 6.3 Release 🛠](https://github.com/storybookjs/storybook/issues/14397)\n\n## 6.3.0-beta.18 (June 9, 2021)\n\n### Features\n\n- Toolbars: Add customizable keyboard navigation shortcuts ([#15169](https://github.com/storybookjs/storybook/pull/15169))\n\n### Bug Fixes\n\n- Controls: Initialize color control on reset ([#15059](https://github.com/storybookjs/storybook/pull/15059))\n\n## 6.3.0-beta.17 (June 8, 2021)\n\n### Bug Fixes\n\n- Measure: Update version to fix hooks issue ([#15167](https://github.com/storybookjs/storybook/pull/15167))\n\n## 6.3.0-beta.16 (June 8, 2021)\n\n### Features\n\n- Angular: Add compodoc to ng builder ([#15165](https://github.com/storybookjs/storybook/pull/15165))\n\n## 6.3.0-beta.15 (June 7, 2021)\n\n### Bug Fixes\n\n- Angular: Clear root / docs-root when navigating from one tab to the other ([#15160](https://github.com/storybookjs/storybook/pull/15160))\n\n## 6.3.0-beta.14 (June 6, 2021)\n\n### Features\n\n- Controls: Style `undefined` range slider different to filled one ([#14973](https://github.com/storybookjs/storybook/pull/14973))\n\n### Dependency Upgrades\n\n- Upgrade to react-docgen-typescript-plugin 1.0.0 ([#15154](https://github.com/storybookjs/storybook/pull/15154))\n\n## 6.3.0-beta.13 (June 6, 2021)\n\n### Maintenance\n\n- CsfFile: Index Meta/Story annotations ([#15152](https://github.com/storybookjs/storybook/pull/15152))\n- CLI: Update project template for web-components ([#15149](https://github.com/storybookjs/storybook/pull/15149))\n- Build: Fix WC example and e2e tests ([#15146](https://github.com/storybookjs/storybook/pull/15146))\n\n## 6.3.0-beta.12 (June 5, 2021)\n\n### Features\n\n- Essentials: Update measure/outline addons to support ESM and vite builder ([#15144](https://github.com/storybookjs/storybook/pull/15144))\n\n## 6.3.0-beta.11 (June 4, 2021)\n\n### Bug Fixes\n\n- Angular: Fix Ivy rendering to use at most one render promise at a time ([#15139](https://github.com/storybookjs/storybook/pull/15139))\n- CSF tools: Refactor test cases ([#15142](https://github.com/storybookjs/storybook/pull/15142))\n\n### Maintenance\n\n- Web Components: Reintegrate `@storybook/lit` into `@storybook/web-components` ([#15042](https://github.com/storybookjs/storybook/pull/15042))\n\n## 6.3.0-beta.10 (June 3, 2021)\n\n### Features\n\n- CLI: Add storybook-addon-angular-ivy to angular install ([#14653](https://github.com/storybookjs/storybook/pull/14653))\n- Angular: Ivy rendering for Canvas and Docs ([#15126](https://github.com/storybookjs/storybook/pull/15126))\n- Server: Add support for stories written in YAML ([#15049](https://github.com/storybookjs/storybook/pull/15049))\n\n## 6.3.0-beta.9 (June 3, 2021)\n\n### Features\n\n- Essentials: Add measure and outline addons ([#15107](https://github.com/storybookjs/storybook/pull/15107))\n\n## 6.3.0-beta.8 (June 2, 2021)\n\n### Features\n\n- Core: Add `core.disableWebpackDefaults` preset ([#15062](https://github.com/storybookjs/storybook/pull/15062))\n\n### Bug Fixes\n\n- Core: Fix prebuilt manager usage on first run ([#15121](https://github.com/storybookjs/storybook/pull/15121))\n\n## 6.3.0-beta.7 (June 2, 2021)\n\n### Features\n\n- Angular: Add angular builder to start + build storybook ([#15061](https://github.com/storybookjs/storybook/pull/15061))\n\n### Bug Fixes\n\n- CLI: Fix react repro template deps ([#15118](https://github.com/storybookjs/storybook/pull/15118))\n\n## 6.3.0-beta.6 (June 1, 2021)\n\n### Features\n\n- CLI: Add Server template generator ([#13979](https://github.com/storybookjs/storybook/pull/13979))\n\n### Bug Fixes\n\n- CLI: Disable `react_in_yarn_workspace` template for users, keep in e2e ([#15114](https://github.com/storybookjs/storybook/pull/15114))\n\n## 6.3.0-beta.5 (May 30, 2021)\n\n### Bug Fixes\n\n- Vue2: Check types when `typescript.check` is true ([#15089](https://github.com/storybookjs/storybook/pull/15089))\n- Update markdown-to-jsx version to fix url links in comments ([#15083](https://github.com/storybookjs/storybook/pull/15083))\n\n### Maintenance\n\n- CLI: Add `SKIP_PREFLIGHT_CHECK` in CRA repro ([#15092](https://github.com/storybookjs/storybook/pull/15092))\n- Angular: Disable chromatic for story with dynamic time display ([#15074](https://github.com/storybookjs/storybook/pull/15074))\n\n## 6.3.0-beta.4 (May 28, 2021)\n\n### Bug Fixes\n\n- Addon-docs: Fix MDX source rendering ([#15071](https://github.com/storybookjs/storybook/pull/15071))\n- CLI: Add new packages to versions.json ([#15073](https://github.com/storybookjs/storybook/pull/15073))\n- Addon-docs: Fix per-story `docs.source` parameter ([#15070](https://github.com/storybookjs/storybook/pull/15070))\n\n## 6.3.0-beta.3 (May 28, 2021)\n\nFailed NPM publish\n\n## 6.3.0-beta.2 (May 27, 2021)\n\n### Features\n\n- Core: Add `globals` URL param and remove from sessionStorage ([#15056](https://github.com/storybookjs/storybook/pull/15056))\n\n### Bug Fixes\n\n- Core: Set `loose: true` in babel/preset-env config ([#15055](https://github.com/storybookjs/storybook/pull/15055))\n\n## 6.3.0-beta.1 (May 26, 2021)\n\n### Bug Fixes\n\n- Core: Fix prebuilt manager ([#15050](https://github.com/storybookjs/storybook/pull/15050))\n- Core: Fix storySort `order` with whitespace in story paths ([#15038](https://github.com/storybookjs/storybook/pull/15038))\n\n### Maintenance\n\n- Do not try to named import from global ([#15043](https://github.com/storybookjs/storybook/pull/15043))\n- Remove storybook/lit from monorepo ([#15048](https://github.com/storybookjs/storybook/pull/15048))\n\n## 6.3.0-beta.0 (May 26, 2021)\n\nStorybook 6.3 is in beta!! 🎉🎉🎉\n\nHundreds of improvements and fixes, including:\n\n- **Angular** - Overhauled Angular support.\n- **Web-components** - Lit2 support.\n- **Webpack 5** - Official support.\n- **Vite builder** - Community support.\n- **Modern ESM** - Modern package distribution.\n- **API** - Keyboard shortcuts for addons.\n\nTrack the release in the Github: [Storybook 6.3 Release 🛠](https://github.com/storybookjs/storybook/issues/14397)\n\n## 6.3.0-alpha.45 (May 26, 2021)\n\n### Features\n\n- CLI: Add option to force-build iframe despite custom preview URL ([#15030](https://github.com/storybookjs/storybook/pull/15030))\n\n### Bug Fixes\n\n- Addon-docs: Fix source block tree shaking ([#15035](https://github.com/storybookjs/storybook/pull/15035))\n- Addon-a11y: Highlight all elements correctly ([#14935](https://github.com/storybookjs/storybook/pull/14935))\n\n## 6.3.0-alpha.44 (May 25, 2021)\n\n### Features\n\n- Presets: Expand `webpackInstance` to include entire namespace ([#15016](https://github.com/storybookjs/storybook/pull/15016))\n- Angular: Add `angularBrowserTarget` option in server ([#14955](https://github.com/storybookjs/storybook/pull/14955))\n\n### Bug Fixes\n\n- Core: Ignore manager cache on config file changes and Storybook upgrade ([#14993](https://github.com/storybookjs/storybook/pull/14993))\n\n## 6.3.0-alpha.43 (May 25, 2021)\n\n### Features\n\n- Web-components: Support lit 2 with back-compat ([#14898](https://github.com/storybookjs/storybook/pull/14898))\n\n### Bug Fixes\n\n- Angular: Use NormalizeOptimization from angular-cli ([#15022](https://github.com/storybookjs/storybook/pull/15022))\n\n### Maintenance\n\n- Build: Fix selectors used in Cypress tests and E2E exit code ([#15021](https://github.com/storybookjs/storybook/pull/15021))\n\n### Dependency Upgrades\n\n- Bump react-docgen-typescript-plugin to 0.7.2-canary.375d65e.0 ([#15024](https://github.com/storybookjs/storybook/pull/15024))\n\n## 6.3.0-alpha.42 (May 24, 2021)\n\n### Dependency Upgrades\n\n- Core: Fix manager builder dependencies for PnP ([#15019](https://github.com/storybookjs/storybook/pull/15019))\n\n## 6.3.0-alpha.41 (May 24, 2021)\n\n### Features\n\n- Addon-docs: Exclude decorators in dynamic source snippets ([#14652](https://github.com/storybookjs/storybook/pull/14652))\n\n## 6.3.0-alpha.40 (May 24, 2021)\n\nFailed NPM publish\n\n## 6.3.0-alpha.39 (May 23, 2021)\n\nFix stale dependencies appended to [#15001](https://github.com/storybookjs/storybook/pull/15001)\n\n## 6.3.0-alpha.38 (May 23, 2021)\n\nMinor manager webapck5 fixes appended to [#15001](https://github.com/storybookjs/storybook/pull/15001)\n\n## 6.3.0-alpha.37 (May 23, 2021)\n\n### Features\n\n- Core: Support manager build with webpack5 ([#15001](https://github.com/storybookjs/storybook/pull/15001))\n\n### Bug Fixes\n\n- Core: Fix opt-in stories.json generation ([#15003](https://github.com/storybookjs/storybook/pull/15003))\n\n### Maintenance\n\n- Maintenance: Build ESM in watch mode, revert modern ([#15015](https://github.com/storybookjs/storybook/pull/15015))\n\n### Dependency Upgrades\n\n- Storyshots-puppeteer: Remove the usage of GPL-licensed `@wordpress/jest-puppeteer-axe` package ([#15006](https://github.com/storybookjs/storybook/pull/15006))\n\n## 6.3.0-alpha.36 (May 20, 2021)\n\n### Features\n\n- CLI: Add sb link --local option ([#14950](https://github.com/storybookjs/storybook/pull/14950))\n- Controls: Add automatic ids to all controls ([#14296](https://github.com/storybookjs/storybook/pull/14296))\n\n### Maintenance\n\n- Build: Improve e2e script ([#14980](https://github.com/storybookjs/storybook/pull/14980))\n\n### Dependency Upgrades\n\n- React: Upgrade to @storybook/react-docgen-typescript-plugin ([#14991](https://github.com/storybookjs/storybook/pull/14991))\n\n## 6.3.0-alpha.35 (May 20, 2021)\n\n### Maintenance\n\n- Core: Feature flag for builtin stories.json support ([#14992](https://github.com/storybookjs/storybook/pull/14992))\n\n### Dependency Upgrades\n\n- React: Upgrade to @storybook/react-docgen-typescript-plugin ([#14991](https://github.com/storybookjs/storybook/pull/14991))\n\n## 6.3.0-alpha.34 (May 19, 2021)\n\n### Features\n\n- Core: Single story option in iframe view ([#14875](https://github.com/storybookjs/storybook/pull/14875))\n- Lit: Add typings for @storybook/lit ([#14962](https://github.com/storybookjs/storybook/pull/14962))\n\n### Dependency Upgrades\n\n- Bump telejson to 5.3.2 to use the ESM version ([#14983](https://github.com/storybookjs/storybook/pull/14983))\n- CSF: Add undeclared dependency `regenerator-runtime` ([#14979](https://github.com/storybookjs/storybook/pull/14979))\n\n## 6.3.0-alpha.33 (May 18, 2021)\n\n### Bug Fixes\n\n- Controls: Fix controls without options and add warning ([#14976](https://github.com/storybookjs/storybook/pull/14976))\n- Core: Add remaining sbmodern exports ([#14977](https://github.com/storybookjs/storybook/pull/14977))\n\n## 6.3.0-alpha.32 (May 18, 2021)\n\nFailed NPM publish\n\n## 6.3.0-alpha.31 (May 18, 2021)\n\n### Features\n\n- Angular: Pass bootstrapOptions to angular ([#14852](https://github.com/storybookjs/storybook/pull/14852))\n- Controls: Update all controls to have explicit handling for `undefined` ([#14899](https://github.com/storybookjs/storybook/pull/14899))\n- Core: Add args enhancers + use in addon-actions ([#14901](https://github.com/storybookjs/storybook/pull/14901))\n- Addon-docs: Remove all defaultValue eval-ing ([#14900](https://github.com/storybookjs/storybook/pull/14900))\n\n## 6.3.0-alpha.30 (May 18, 2021)\n\n### Features\n\n- Core: Built-in static `stories.json` support ([#14945](https://github.com/storybookjs/storybook/pull/14945))\n\n### Maintenance\n\n- Core: Add modern build target to apps aka frameworks ([#14967](https://github.com/storybookjs/storybook/pull/14967))\n- Build: Increase CI `build` step to XL ([#14970](https://github.com/storybookjs/storybook/pull/14970))\n\n## 6.3.0-alpha.29 (May 17, 2021)\n\n### Features\n\n- UI: Provide option to hide default toolbar tools ([#14897](https://github.com/storybookjs/storybook/pull/14897))\n- Core: Support modern browser target ([#14954](https://github.com/storybookjs/storybook/pull/14954))\n\n### Maintenance\n\n- Core: Remove updateGlobals warning message ([#14949](https://github.com/storybookjs/storybook/pull/14949))\n- Controls: Tighten color control inference heuristic and test ([#14684](https://github.com/storybookjs/storybook/pull/14684))\n\n## 6.3.0-alpha.28 (May 15, 2021)\n\n### Bug Fixes\n\n- CLI: Keep Webpack 4 builder for Angular lower than 12 ([#14942](https://github.com/storybookjs/storybook/pull/14942))\n\n## 6.3.0-alpha.27 (May 14, 2021)\n\n### Features\n\n- CLI: Add Angular 12 + docs inline rendering support ([#14928](https://github.com/storybookjs/storybook/pull/14928))\n\n## 6.3.0-alpha.26 (May 14, 2021)\n\n### Bug Fixes\n\n- Addon-controls: Fix duplicate color swatch id's in Color control ([#14925](https://github.com/storybookjs/storybook/pull/14925))\n\n### Maintenance\n\n- CLI: Add preamble instructions to `sb repro` ([#14924](https://github.com/storybookjs/storybook/pull/14924))\n- Webpack5: Always set `resolve.fallback.crypto` to `false` ([#14914](https://github.com/storybookjs/storybook/pull/14914))\n- Build: Add missing dependencies ([#14919](https://github.com/storybookjs/storybook/pull/14919))\n- Build: Put E2E tests back on track ([#14917](https://github.com/storybookjs/storybook/pull/14917))\n\n### Dependency Upgrades\n\n- Addon-storyshots: Make @storybook/react dependency optional ([#14891](https://github.com/storybookjs/storybook/pull/14891))\n\n## 6.3.0-alpha.25 (May 13, 2021)\n\n### Maintenance\n\n- Builder-Webpack5: Use native features instead of plugins ([#14281](https://github.com/storybookjs/storybook/pull/14281))\n- CLI: Repro refinements per feedback ([#14888](https://github.com/storybookjs/storybook/pull/14888))\n\n## 6.3.0-alpha.24 (May 11, 2021)\n\n### Features\n\n- CLI: Add repro/link commands for creating/running reproductions ([#14594](https://github.com/storybookjs/storybook/pull/14594))\n\n### Bug Fixes\n\n- UI: Only show addons in mobile if docsOnly is false ([#14810](https://github.com/storybookjs/storybook/pull/14810))\n\n## 6.3.0-alpha.23 (May 11, 2021)\n\n### Bug Fixes\n\n- UI: Fix tab display when there is only one tab ([#14790](https://github.com/storybookjs/storybook/pull/14790))\n- Addon-actions: Display DOM Event/CustomEvent data ([#14879](https://github.com/storybookjs/storybook/pull/14879))\n\n### Dependency Upgrades\n\n- Build: Remove outdated `@types/cpy` dependency ([#14880](https://github.com/storybookjs/storybook/pull/14880))\n\n## 6.3.0-alpha.22 (May 10, 2021)\n\n### Features\n\n- Lit: Initial lit2 support ([#14600](https://github.com/storybookjs/storybook/pull/14600))\n- React: Add ComponentStory convenience type ([#14780](https://github.com/storybookjs/storybook/pull/14780))\n\n### Maintenance\n\n- Extract addon-knobs from monorepo ([#14874](https://github.com/storybookjs/storybook/pull/14874))\n- Extract addon-graphql from monorepo ([#14862](https://github.com/storybookjs/storybook/pull/14862))\n- Extract design-assets from monorepo ([#14854](https://github.com/storybookjs/storybook/pull/14854))\n- Fix renovate config ([#14868](https://github.com/storybookjs/storybook/pull/14868))\n- Extract addon-events from monorepo ([#14855](https://github.com/storybookjs/storybook/pull/14855))\n- Extract addon-cssresources from monorepo ([#14860](https://github.com/storybookjs/storybook/pull/14860))\n- Extract addon-queryparams from monorepo ([#14861](https://github.com/storybookjs/storybook/pull/14861))\n- CLI: Use arg-parser defaults ([#14857](https://github.com/storybookjs/storybook/pull/14857))\n- Build: Remove MDX to make chromatic/IE pass in CI ([#14863](https://github.com/storybookjs/storybook/pull/14863))\n\n## 6.3.0-alpha.21 (May 7, 2021)\n\n### Maintenance\n\n- Addon-docs: Fix doc blocks imports to import from ESM/CJS ([#14841](https://github.com/storybookjs/storybook/pull/14841))\n- Refactor aurelia into its own repo ([#14801](https://github.com/storybookjs/storybook/pull/14801))\n- Delete unmaintained dev-kits ([#14832](https://github.com/storybookjs/storybook/pull/14832))\n\n### Dependency Upgrades\n\n- Storyshots: Make `vue-jest` and `svelte` optional peer dependencies ([#14835](https://github.com/storybookjs/storybook/pull/14835))\n\n## 6.3.0-alpha.20 (May 6, 2021)\n\n### Bug Fixes\n\n- Vue3: Fix components in decorators ([#14809](https://github.com/storybookjs/storybook/pull/14809))\n- Accessibility: Adds title to close button on settings page ([#14808](https://github.com/storybookjs/storybook/pull/14808))\n\n### Maintenance\n\n- Refactor marionette into its own repo ([#14802](https://github.com/storybookjs/storybook/pull/14802))\n- Refactor rax to its own repo ([#14799](https://github.com/storybookjs/storybook/pull/14799))\n- Refactor marko into its own repo ([#14803](https://github.com/storybookjs/storybook/pull/14803))\n- Refactor mithril into its own repo ([#14804](https://github.com/storybookjs/storybook/pull/14804))\n- Refactor riot to its own repo ([#14800](https://github.com/storybookjs/storybook/pull/14800))\n- UI: Styling updates ([#14820](https://github.com/storybookjs/storybook/pull/14820))\n\n## 6.3.0-alpha.19 (May 3, 2021)\n\n### Features\n\n- Addon-toolbars: Add optional label for toolbar items ([#14776](https://github.com/storybookjs/storybook/pull/14776))\n\n### Maintenance\n\n- Core: Remove spurious package.json warning ([#14785](https://github.com/storybookjs/storybook/pull/14785))\n\n## 6.3.0-alpha.18 (May 2, 2021)\n\n### Features\n\n- Angular: Filter out args whose argType are missing a control or action ([#14779](https://github.com/storybookjs/storybook/pull/14779))\n\n### Maintenance\n\n- Addon-docs: Allow doc blocks to CJS imported ([#14769](https://github.com/storybookjs/storybook/pull/14769))\n\n## 6.3.0-alpha.17 (April 30, 2021)\n\n### Features\n\n- Core: Add option to include story names when sorting ([#12520](https://github.com/storybookjs/storybook/pull/12520))\n- Addon-actions: Add 'New Action' indicator ([#14728](https://github.com/storybookjs/storybook/pull/14728))\n- Addon-docs: Add parameter to show code by default ([#14729](https://github.com/storybookjs/storybook/pull/14729))\n\n### Bug Fixes\n\n- Addon-docs: Add classnames for Preview block ([#14685](https://github.com/storybookjs/storybook/pull/14685))\n- UI: Fix toolbar text using theme color ([#14308](https://github.com/storybookjs/storybook/pull/14308))\n\n### Maintenance\n\n- Core: Protect core metadata from decorators ([#13512](https://github.com/storybookjs/storybook/pull/13512))\n- Addon-a11y: Reorder color blindness types by most common ([#14768](https://github.com/storybookjs/storybook/pull/14768))\n\n## 6.3.0-alpha.16 (April 29, 2021)\n\n### Bug Fixes\n\n- Core: Fix `features`, `core`, `logLevel` in main.js config types ([#14745](https://github.com/storybookjs/storybook/pull/14745))\n- Angular: Fix windows path for tsconfig ([#14747](https://github.com/storybookjs/storybook/pull/14747))\n\n### Maintenance\n\n- Build: Change nx cloud access token to read-only token ([#14744](https://github.com/storybookjs/storybook/pull/14744))\n\n### Dependency Upgrades\n\n- Addon-a11y/Storyshots: Upgrade axe-core to 4.2.0 and related dependencies ([#14749](https://github.com/storybookjs/storybook/pull/14749))\n\n## 6.3.0-alpha.15 (April 28, 2021)\n\n### Features\n\n- Storyshots: Add `beforeAxeTest` hook ([#14563](https://github.com/storybookjs/storybook/pull/14563))\n- API: Add addon keyboard shortcuts & create shortcuts for addon-viewport ([#14658](https://github.com/storybookjs/storybook/pull/14658))\n\n### Bug Fixes\n\n- Storyshots/Preact: Add pragma @jsxRuntime classic ([#13849](https://github.com/storybookjs/storybook/pull/13849))\n- Core: Don't recreate a bound story function each time we call a decorated story ([#14692](https://github.com/storybookjs/storybook/pull/14692))\n\n### Maintenance\n\n- Build: Add NX bootstrap optimization ([#14535](https://github.com/storybookjs/storybook/pull/14535))\n\n## 6.2.9 (April 23, 2021)\n\n### Bug Fixes\n\n- Angular: set the @ViewChild with a non-empty value in StorybookWrapperComponent ([#14586](https://github.com/storybookjs/storybook/pull/14586))\n- Addon-docs: Fix ArgsTable sorting when using of={Component} ([#14669](https://github.com/storybookjs/storybook/pull/14669))\n- Server: Fix string escaping in CSF compiler ([#14615](https://github.com/storybookjs/storybook/pull/14615))\n\n### Maintenance\n\n- Examples: Move from placehold.it to place-hold.it for mock images ([#14637](https://github.com/storybookjs/storybook/pull/14637))\n\n## 6.3.0-alpha.14 (April 23, 2021)\n\n### Bug Fixes\n\n- Core: Fix URL handling in Firefox ([#14556](https://github.com/storybookjs/storybook/pull/14556))\n- Build: Create webpack stats target directory if needed and accept boolean flag ([#14690](https://github.com/storybookjs/storybook/pull/14690))\n\n### Maintenance\n\n- Docs: Remove `babel-loader` and `@babel/core` peer deps ([#14689](https://github.com/storybookjs/storybook/pull/14689))\n- Use Storybook's built-in accessibility icon for VisionDeficiency tab. ([#14681](https://github.com/storybookjs/storybook/pull/14681))\n\n## 6.3.0-alpha.13 (April 21, 2021)\n\n### Bug Fixes\n\n- Addon-docs: Fix ArgsTable sorting when using of={Component} ([#14669](https://github.com/storybookjs/storybook/pull/14669))\n\n### Maintenance\n\n- CLI: Rename preact template files to JSX ([#14670](https://github.com/storybookjs/storybook/pull/14670))\n\n## 6.3.0-alpha.12 (April 20, 2021)\n\n### Maintenance\n\n- Angular: Refactor angular server ([#14358](https://github.com/storybookjs/storybook/pull/14358))\n- CLI: Rename react template files to jsx ([#14650](https://github.com/storybookjs/storybook/pull/14650))\n\n## 6.3.0-alpha.11 (April 19, 2021)\n\n### Features\n\n- CLI: Support community builders in `sb init` ([#14651](https://github.com/storybookjs/storybook/pull/14651))\n- Angular: Support Ivy addon ([#14649](https://github.com/storybookjs/storybook/pull/14649))\n\n### Maintenance\n\n- Add `funding` to manifests ([#14647](https://github.com/storybookjs/storybook/pull/14647))\n\n## 6.3.0-alpha.10 (April 18, 2021)\n\n### Bug Fixes\n\n- Modified Swatches keys to avoid duplicates ([#14636](https://github.com/storybookjs/storybook/pull/14636))\n\n### Maintenance\n\n- ESM tweaks for vite builder ([#14641](https://github.com/storybookjs/storybook/pull/14641))\n- Examples: Move from placehold.it to place-hold.it for mock images ([#14637](https://github.com/storybookjs/storybook/pull/14637))\n\n## 6.3.0-alpha.9 (April 17, 2021)\n\n### Features\n\n- Preact: Add react compat by default ([#14555](https://github.com/storybookjs/storybook/pull/14555))\n\n### Bug Fixes\n\n- Addon-docs: Fix MD code snippet format inside Description ([#14495](https://github.com/storybookjs/storybook/pull/14495))\n- Server: Fix string escaping in CSF compiler ([#14615](https://github.com/storybookjs/storybook/pull/14615))\n\n### Maintenance\n\n- Maintenance: Improve issue templates ([#14543](https://github.com/storybookjs/storybook/pull/14543))\n\n## 6.3.0-alpha.8 (April 15, 2021)\n\n### Features\n\n- Angular: Create actions for Outputs by default ([#14299](https://github.com/storybookjs/storybook/pull/14299))\n\n### Bug Fixes\n\n- Addon-a11y: Fix crypto in webpack5 ([#14592](https://github.com/storybookjs/storybook/pull/14592))\n- Storyshots: Preserve authentication information in Storybook URL ([#14582](https://github.com/storybookjs/storybook/pull/14582))\n\n### Maintenance\n\n- Angular: Add template MDX example ([#14597](https://github.com/storybookjs/storybook/pull/14597))\n\n### Dependency Upgrades\n\n- Remove unused inquirer dependency ([#14590](https://github.com/storybookjs/storybook/pull/14590))\n\n## 6.2.8 (April 14, 2021)\n\n### Bug Fixes\n\n- CLI: Properly detect vuetify3 ([#14552](https://github.com/storybookjs/storybook/pull/14552))\n- Core: Fix build config inconsistency ([#14566](https://github.com/storybookjs/storybook/pull/14566))\n\n## 6.3.0-alpha.7 (April 14, 2021)\n\n### Features\n\n- Angular: Improve story rendering mode ([#14226](https://github.com/storybookjs/storybook/pull/14226))\n\n### Bug Fixes\n\n- Angular: set the @ViewChild with a non-empty value in StorybookWrapperComponent ([#14586](https://github.com/storybookjs/storybook/pull/14586))\n\n### Maintenance\n\n- CI: Remove Travis, fix TeamCity, rework E2E on CircleCI ([#14522](https://github.com/storybookjs/storybook/pull/14522))\n- Core: Resolve builders relatively to config file ([#14576](https://github.com/storybookjs/storybook/pull/14576))\n\n## 6.3.0-alpha.6 (April 13, 2021)\n\n### Bug Fixes\n\n- Core: Fix build config inconsistency ([#14566](https://github.com/storybookjs/storybook/pull/14566))\n- CLI: Fix vuetify3 detection ([#14552](https://github.com/storybookjs/storybook/pull/14552))\n\n### Maintenance\n\n- Build: Disable yarn immutable install by default during E2E tests ([#14568](https://github.com/storybookjs/storybook/pull/14568))\n- Build: Fix `dev:babel` and `dev:tsc` NPM scripts ([#14560](https://github.com/storybookjs/storybook/pull/14560))\n\n### Dependency Upgrades\n\n- Bump vue-docgen-api to 4.38.0 ([#14567](https://github.com/storybookjs/storybook/pull/14567))\n- Upgrade react-colorful to latest ([#14553](https://github.com/storybookjs/storybook/pull/14553))\n\n## 6.3.0-alpha.5 (April 11, 2021)\n\n### Features\n\n- Core: Enable community builders ([#14545](https://github.com/storybookjs/storybook/pull/14545))\n\n## 6.3.0-alpha.4 (April 10, 2021)\n\n### Features\n\n- Core: Expose Server instance through the pluggable Builder API ([#14468](https://github.com/storybookjs/storybook/pull/14468))\n\n### Maintenance\n\n- Core: Don't shadow the window global variable ([#14472](https://github.com/storybookjs/storybook/pull/14472))\n\n## 6.3.0-alpha.3 (April 10, 2021)\n\n### Features\n\n- UI: Support `*` wildcard option in storySort order array ([#14531](https://github.com/storybookjs/storybook/pull/14531))\n\n### Bug Fixes\n\n- UI: Add show toolbar T in menu ([#14437](https://github.com/storybookjs/storybook/pull/14437))\n\n### Maintenance\n\n- Refactor: Replace `lodash/range` with `Array.from` ([#14323](https://github.com/storybookjs/storybook/pull/14323))\n- Maintenance: Add TypeScript plugin for Yarn ([#14534](https://github.com/storybookjs/storybook/pull/14534))\n\n## 6.2.7 (April 9, 2021)\n\n### Bug Fixes\n\n- CLI: Fix prerelease upgrade ([#14529](https://github.com/storybookjs/storybook/pull/14529))\n\n## 6.3.0-alpha.2 (April 9, 2021)\n\n### Features\n\n- Web-components: Add full reload listening to server-side-events ([#14445](https://github.com/storybookjs/storybook/pull/14445))\n- Core: Pass watchOptions from webpack config to webpackDevMiddleware ([#14461](https://github.com/storybookjs/storybook/pull/14461))\n\n### Bug Fixes\n\n- CLI: Fix prerelease upgrade ([#14529](https://github.com/storybookjs/storybook/pull/14529))\n\n## 6.2.6 (April 9, 2021)\n\n### Bug Fixes\n\n- Core: Allow string in object arg and support fractional numbers in URL args ([#14511](https://github.com/storybookjs/storybook/pull/14511))\n- UI: Skip duplicate storyId breaking sidebar ([#14502](https://github.com/storybookjs/storybook/pull/14502))\n\n## 6.3.0-alpha.1 (April 9, 2021)\n\n### Features\n\n- Core: Enable gzip compression on the development server ([#14459](https://github.com/storybookjs/storybook/pull/14459))\n\n### Bug Fixes\n\n- Preact: Fix hooks when used in stories, preact-kitchen-sink ([#14473](https://github.com/storybookjs/storybook/pull/14473))\n- Angular: Fix handling of line breaks with multiple selectors ([#14313](https://github.com/storybookjs/storybook/pull/14313))\n\n## 6.3.0-alpha.0 (April 8, 2021)\n\n### Maintenance\n\n- Build: Move monorepo to Yarn 2 ([#13907](https://github.com/storybookjs/storybook/pull/13907))\n\n## 6.2.5 (April 7, 2021)\n\n### Bug Fixes\n\n- Core: Don't include args param in docs mode URL ([#14494](https://github.com/storybookjs/storybook/pull/14494))\n- Core: Restore previewHead/Body presets ([#14500](https://github.com/storybookjs/storybook/pull/14500))\n- Controls: Reset ArgsTable state when switching stories ([#14493](https://github.com/storybookjs/storybook/pull/14493))\n\n### Dependency Upgrades\n\n- Revert \"Upgrade `dotenv-webpack` to v6\" ([#14501](https://github.com/storybookjs/storybook/pull/14501))\n\n## 6.2.4 (April 7, 2021)\n\n### Dependency Upgrades\n\n- Upgrade `dotenv-webpack` to v6 ([#14492](https://github.com/storybookjs/storybook/pull/14492))\n\n## 6.2.3 (April 5, 2021)\n\n### Bug Fixes\n\n- Core: Fix file-loader options for ESM compat ([#14480](https://github.com/storybookjs/storybook/pull/14480))\n- Core: Fix config.js-based configuration ([#14479](https://github.com/storybookjs/storybook/pull/14479))\n\n### Maintenance\n\n- Core: Disable postcss warning, add main.js `features` setting ([#14478](https://github.com/storybookjs/storybook/pull/14478))\n\n## 6.2.2 (April 2, 2021)\n\n### Bug Fixes\n\n- Core: Fix symlinks in static dir when building static Storybook ([#14448](https://github.com/storybookjs/storybook/pull/14448))\n- Addon-docs/ArgsTable: Use storySort parameter ([#14422](https://github.com/storybookjs/storybook/pull/14422))\n- Revert \"Svelte - Fix async loaders and docs\" Fix #14443 ([#14444](https://github.com/storybookjs/storybook/pull/14444))\n- Addon-docs/Angular: Keep inlineStories to false by default ([#14447](https://github.com/storybookjs/storybook/pull/14447))\n\n### Maintenance\n\n- CLI: Fix link to `sb init` docs ([#14421](https://github.com/storybookjs/storybook/pull/14421))\n\n## 6.2.1 (March 30, 2021)\n\nFix bad version update message from [#12183](https://github.com/storybookjs/storybook/issues/12183)\n\n## 6.2.0 (March 30, 2021)\n\n**[Storybook 6.2](https://github.com/storybookjs/storybook/issues/13160) future-proof component development**\n\nStorybook 6.2 includes major improvements for new frameworks, package managers, and bundlers.\n\n🚀 Frameworks: Vue 3, Svelte Native CSF\n📦 Packaging: NPM 7, Yarn 2, ESM\n🛠 Bundlers: Webpack 5 (experimental), pluggable bundlers to enable Vite, ESBuild, Snowpack, & more.\n\nIt also includes an overhaul of Storybook’s auto-generated controls and hundreds more fixes, features, and tweaks.\n\nBrowse the [changelogs](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) matching `6.2.0-alpha.*`, `6.2.0-beta.*`, and `6.2.0-rc.*` for the full list of changes. See [Storybook 6 migration guide](https://storybook.js.org/blog/storybook-6-migration-guide/) to upgrade from `5.x` or [MIGRATION.md](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md) for detailed migration instructions.\n\n## 6.2.0-rc.13 (March 30, 2021)\n\n### Bug Fixes\n\n- Controls: QA fixes for Object and Color controls ([#14392](https://github.com/storybookjs/storybook/pull/14392))\n\n## 6.2.0-rc.12 (March 30, 2021)\n\n### Bug Fixes\n\n- Controls: Fix defaultValue without PropType ([#14387](https://github.com/storybookjs/storybook/pull/14387))\n- CLI: Compatibility with sveltekit ([#14384](https://github.com/storybookjs/storybook/pull/14384))\n- Controls: Color picker QA fixes ([#14382](https://github.com/storybookjs/storybook/pull/14382))\n- Svelte: Fix Cannot read property '\\_\\_docgen' of undefined ([#14383](https://github.com/storybookjs/storybook/pull/14383))\n\n### Maintenance\n\n- Core: Make Storybook esbuild-compatible ([#14380](https://github.com/storybookjs/storybook/pull/14380))\n\n## 6.2.0-rc.11 (March 29, 2021)\n\n### Features\n\n- CLI: Use Svelte-native CSF during initialization ([#14363](https://github.com/storybookjs/storybook/pull/14363))\n\n### Bug Fixes\n\n- Addon-actions: Fix addArgs warnings by refactor ([#14372](https://github.com/storybookjs/storybook/pull/14372))\n- Webpack: Fix HMR by removing concatenateModules optimization ([#14373](https://github.com/storybookjs/storybook/pull/14373))\n- Fix issue with string unions/enums ([#14370](https://github.com/storybookjs/storybook/pull/14370))\n- Components: Deprecate html components entry point ([#14369](https://github.com/storybookjs/storybook/pull/14369))\n\n## 6.2.0-rc.10 (March 26, 2021)\n\n**NOTE:** For Angular users using inline story rendering in addon-docs, this is a breaking prerelease change. See below and apologies for the back and forth. Last time we hope!\n\n### Bug Fixes\n\n- Addon-docs: Fix un-prefixed path links ([#14334](https://github.com/storybookjs/storybook/pull/14334))\n- UI: Add aria-labels to buttons without discernible text ([#14338](https://github.com/storybookjs/storybook/pull/14338))\n\n### Maintenance\n\n- Angular: Improve docs inline rendering setup ([#14333](https://github.com/storybookjs/storybook/pull/14333))\n\n## 6.2.0-rc.9 (March 25, 2021)\n\n### Features\n\n- Core: Support some special values in URL args ([#14293](https://github.com/storybookjs/storybook/pull/14293))\n\n### Bug Fixes\n\n- Core: Fix `enum` args parsing from URL ([#14314](https://github.com/storybookjs/storybook/pull/14314))\n- Controls: Tweaks and fixes for color control ([#14316](https://github.com/storybookjs/storybook/pull/14316))\n- Components: Handle `null` when parsing input in color picker ([#14305](https://github.com/storybookjs/storybook/pull/14305))\n\n## 6.2.0-rc.8 (March 23, 2021)\n\n**NOTE:** For Angular users using inline story rendering in addon-docs, this is a breaking prerelease change. See below and apologies for the back and forth.\n\n### Bug Fixes\n\n- Revert \"Addon-docs/Angular: Fix inline rendering setup\" ([#14310](https://github.com/storybookjs/storybook/pull/14310))\n- Core: Import `isPlainObject` directly from lodash ([#14307](https://github.com/storybookjs/storybook/pull/14307))\n- Addon-Links: Fix react.d.ts paths ([#14306](https://github.com/storybookjs/storybook/pull/14306))\n\n## 6.2.0-rc.7 (March 23, 2021)\n\n### Bug Fixes\n\n- Core: Restore webpack4 watchOptions ([#14302](https://github.com/storybookjs/storybook/pull/14302))\n- Webpack: Hash files only in dev mode ([#14284](https://github.com/storybookjs/storybook/pull/14284))\n- UI: Element em should not make text content bold ([#14290](https://github.com/storybookjs/storybook/pull/14290))\n\n### Dependency Upgrades\n\n- Webpack5: Remove deprecated webpack-filter-warnings-plugin ([#14303](https://github.com/storybookjs/storybook/pull/14303))\n\n## 6.2.0-rc.6 (March 21, 2021)\n\n### Bug Fixes\n\n- Revert \"Webpack: Hash files only in production mode\" ([#14283](https://github.com/storybookjs/storybook/pull/14283))\n\n## 6.2.0-rc.5 (March 20, 2021)\n\n### Bug Fixes\n\n- Webpack: Hash files only in production mode ([#14264](https://github.com/storybookjs/storybook/pull/14264))\n- Angular: Allow usage of all component valid selectors ([#14230](https://github.com/storybookjs/storybook/pull/14230))\n\n### Maintenance\n\n- Addon-controls: Improve color picker UI and migrate to react-colorful ([#14249](https://github.com/storybookjs/storybook/pull/14249))\n\n## 6.2.0-rc.4 (March 19, 2021)\n\n### Bug Fixes\n\n- Webpack: Fix missing `module` mainField ([#14271](https://github.com/storybookjs/storybook/pull/14271))\n\n## 6.2.0-rc.3 (March 18, 2021)\n\n**NOTE:** For Angular users using inline story rendering in addon-docs, this is a breaking prerelease change. See below.\n\n### Bug Fixes\n\n- Addon-docs/Angular: Fix inline rendering setup ([#14270](https://github.com/storybookjs/storybook/pull/14270))\n- Addon-docs: Fix table dark mode ([#14251](https://github.com/storybookjs/storybook/pull/14251))\n- Webpack5: Replace fullhash with contenthash ([#14261](https://github.com/storybookjs/storybook/pull/14261))\n\n### Maintenance\n\n- CLI: Don't allow root directory as static dir ([#14068](https://github.com/storybookjs/storybook/pull/14068))\n- WebComponents: Fix types and improve CLI detection ([#14258](https://github.com/storybookjs/storybook/pull/14258))\n\n## 6.2.0-rc.2 (March 17, 2021)\n\n### Bug Fixes\n\n- Addon-docs/Vue,Vue3: Fix preset options for vue-docgen-api ([#14227](https://github.com/storybookjs/storybook/pull/14227))\n- Webpack5: Fix hash => fullhash ([#14255](https://github.com/storybookjs/storybook/pull/14255))\n\n### Maintenance\n\n- Core: Check webpack version ([#14256](https://github.com/storybookjs/storybook/pull/14256))\n\n## 6.2.0-rc.1 (March 16, 2021)\n\n### Features\n\n- CLI: Improve init for svelte ([#14161](https://github.com/storybookjs/storybook/pull/14161))\n\n## 6.2.0-rc.0 (March 15, 2021)\n\n### Features\n\n- Svelte: Improve default webpack config ([#14235](https://github.com/storybookjs/storybook/pull/14235))\n\n## 6.2.0-beta.15 (March 15, 2021)\n\n### Features\n\n- Controls: Add ArgsTable sorting ([#13125](https://github.com/storybookjs/storybook/pull/13125))\n\n### Bug Fixes\n\n- Addon-docs: Fix source block error on dynamically-generated stories ([#14217](https://github.com/storybookjs/storybook/pull/14217))\n\n### Dependency Upgrades\n\n- [Security] Bump react-dev-utils from 11.0.3 to 11.0.4 ([#14210](https://github.com/storybookjs/storybook/pull/14210))\n\n## 6.2.0-beta.14 (March 11, 2021)\n\n### Bug Fixes\n\n- Addon-docs/Vue: Fix string docgen ([#14200](https://github.com/storybookjs/storybook/pull/14200))\n- Controls: Fix width of Select control ([#14154](https://github.com/storybookjs/storybook/pull/14154))\n- Source-loader: Revert sourcemaps ([#14199](https://github.com/storybookjs/storybook/pull/14199))\n- Core: Fix webpack stats ([#14198](https://github.com/storybookjs/storybook/pull/14198))\n\n## 6.2.0-beta.13 (March 11, 2021)\n\n### Features\n\n- CLI: Add a `--webpack-stats-json` flag ([#14186](https://github.com/storybookjs/storybook/pull/14186))\n\n### Bug Fixes\n\n- Core: Fix standalone and add tests ([#14196](https://github.com/storybookjs/storybook/pull/14196))\n- Core: Fix dotenv file loading and add `env` to main.js ([#14191](https://github.com/storybookjs/storybook/pull/14191))\n- Core: Fix main.ts/preview.ts ([#14184](https://github.com/storybookjs/storybook/pull/14184))\n\n## 6.2.0-beta.12 (March 10, 2021)\n\n### Features\n\n- Core: Hoist 'control.options', validate them in core and introduce 'control.labels' ([#14169](https://github.com/storybookjs/storybook/pull/14169))\n\n### Bug Fixes\n\n- UI: Fix React unique key warning when using renderLabel ([#14172](https://github.com/storybookjs/storybook/pull/14172))\n\n### Maintenance\n\n- Controls: Remove auto inference and add to CLI template ([#14182](https://github.com/storybookjs/storybook/pull/14182))\n\n## 6.2.0-beta.11 (March 9, 2021)\n\n### Bug Fixes\n\n- React: Fix fast refresh socket connection error ([#14165](https://github.com/storybookjs/storybook/pull/14165))\n\n### Dependency Upgrades\n\n- Update sveltedoc-parser to 4.1.0 ([#14164](https://github.com/storybookjs/storybook/pull/14164))\n\n## 6.2.0-beta.10 (March 5, 2021)\n\n### Bug Fixes\n\n- Angular: Keep story templates with an empty value ([#14113](https://github.com/storybookjs/storybook/pull/14113))\n- Core: Fix standalone API ... again ([#14140](https://github.com/storybookjs/storybook/pull/14140))\n\n## 6.2.0-beta.9 (March 4, 2021)\n\n### Bug Fixes\n\n- Core: Fix standalone API ([#14122](https://github.com/storybookjs/storybook/pull/14122))\n- Core: Fix main.ts/preview.ts handling ([#14123](https://github.com/storybookjs/storybook/pull/14123))\n\n## 6.2.0-beta.8 (March 4, 2021)\n\n### Features\n\n- Core: Add 'mapping' to support complex arg values ([#14100](https://github.com/storybookjs/storybook/pull/14100))\n\n## 6.2.0-beta.7 (March 4, 2021)\n\nFailed publish\n\n## 6.1.21 (March 3, 2021)\n\n### Bug Fixes\n\n- IE11: Transpile prettier down to ES5 ([#14047](https://github.com/storybookjs/storybook/pull/14047))\n- CLI: Add `--legacy-peer-deps` for NPM7 install ([#14106](https://github.com/storybookjs/storybook/pull/14106))\n- SyntaxHighlighter: Safely access clipboard on global.navigator ([#14035](https://github.com/storybookjs/storybook/pull/14035))\n\n## 6.2.0-beta.6 (March 3, 2021)\n\n### Features\n\n- Svelte: Fix async loaders in docs panel ([#14080](https://github.com/storybookjs/storybook/pull/14080))\n\n### Bug Fixes\n\n- CLI: Add `--legacy-peer-deps` for NPM7 install ([#14106](https://github.com/storybookjs/storybook/pull/14106))\n\n### Dependency Upgrades\n\n- [Security] Bump pug from 3.0.0 to 3.0.1 ([#14104](https://github.com/storybookjs/storybook/pull/14104))\n- [Security] Bump pug-code-gen from 3.0.1 to 3.0.2 ([#14105](https://github.com/storybookjs/storybook/pull/14105))\n\n## 6.2.0-beta.5 (March 1, 2021)\n\n### Features\n\n- Core: Add `renderLabel` to customize sidebar tree labels ([#13121](https://github.com/storybookjs/storybook/pull/13121))\n\n### Maintenance\n\n- Core: Namespace sidebar config options ([#14067](https://github.com/storybookjs/storybook/pull/14067))\n\n### Dependency Upgrades\n\n- Move back to the original react-sizeme package ([#14069](https://github.com/storybookjs/storybook/pull/14069))\n\n## 6.2.0-beta.4 (February 26, 2021)\n\n### Features\n\n- UI: Enable search for stories and fix `/` event listener ([#14062](https://github.com/storybookjs/storybook/pull/14062))\n- UI: Add collapse roots to sidebar navigation ([#13685](https://github.com/storybookjs/storybook/pull/13685))\n\n### Bug Fixes\n\n- Core: Support null and undefined in URL args ([#14049](https://github.com/storybookjs/storybook/pull/14049))\n- IE11: Transpile prettier down to ES5 ([#14047](https://github.com/storybookjs/storybook/pull/14047))\n- UI: Fix shortcut button focus border to support high contrast ([#13699](https://github.com/storybookjs/storybook/pull/13699))\n\n### Maintenance\n\n- Fix flaky color rendering ([#14054](https://github.com/storybookjs/storybook/pull/14054))\n\n## 6.2.0-beta.3 (February 25, 2021)\n\n### Features\n\n- CLI: Add builder option ([#14041](https://github.com/storybookjs/storybook/pull/14041))\n- CLI/Vue 2: install vue-loader upon init of vue 2 storybook ([#14018](https://github.com/storybookjs/storybook/pull/14018))\n\n### Bug Fixes\n\n- SyntaxHighlighter: Safely access clipboard on global.navigator ([#14035](https://github.com/storybookjs/storybook/pull/14035))\n\n## 6.2.0-beta.2 (February 24, 2021)\n\n### Features\n\n- Addon-controls: Add JSON tree editor for Object/Array Type args ([#12824](https://github.com/storybookjs/storybook/pull/12824))\n\n### Bug Fixes\n\n- CLI: Fix opening localhost in browser by default ([#14032](https://github.com/storybookjs/storybook/pull/14032))\n- Addon-Docs: Do not create extra Vue instance for Dynamic source rendering ([#14002](https://github.com/storybookjs/storybook/pull/14002))\n\n## 6.1.20 (February 24, 2021)\n\n- Deps: upgrade react-dev-utils to get newer immer ([#14015](https://github.com/storybookjs/storybook/pull/14015))\n\n## 6.2.0-beta.1 (February 23, 2021)\n\n### Bug Fixes\n\n- Core: Refactor ProgressPlugin handling ([#14016](https://github.com/storybookjs/storybook/pull/14016))\n\n### Dependency Upgrades\n\n- Deps: upgrade react-dev-utils to get newer immer ([#14015](https://github.com/storybookjs/storybook/pull/14015))\n\n## 6.1.19 (February 23, 2021)\n\n### Bug Fixes\n\n- Components: Add missing `regenerator-runtime` dependency ([#13991](https://github.com/storybookjs/storybook/pull/13991))\n\n## 6.2.0-beta.0 (February 22, 2021)\n\nStorybook 6.2 is in beta. 🎉🎉🎉\n\nHundreds of improvements and fixes, including:\n\n- **Vue 3** - Official support for the latest version of Vue.\n- **Webpack 5** - Experimental support for the latest version of Webpack.\n- **Controls** - Controls improvements including URL sync, filtering, sorting, and more.\n- **Angular** - Overhauled Angular support.\n- **Svelte** - Overhauled Svelte support.\n\nTrack the release in the Github: [Storybook 6.2 Release ⚡️](https://github.com/storybookjs/storybook/issues/13160)\n\n## 6.2.0-alpha.35 (February 22, 2021)\n\n### Bug Fixes\n\n- Webpack5: Fix progress plugin version conflict ([#14007](https://github.com/storybookjs/storybook/pull/14007))\n\n## 6.2.0-alpha.34 (February 22, 2021)\n\n### Maintenance\n\n- Core: Use webpack4 to build Manager UI instead of webpack5 ([#14001](https://github.com/storybookjs/storybook/pull/14001))\n- Yarn PnP: Add missing dependencies for Webpack 4/5 work ([#13992](https://github.com/storybookjs/storybook/pull/13992))\n\n### Dependency Upgrades\n\n- Core: Fix core/builder dependencies ([#13999](https://github.com/storybookjs/storybook/pull/13999))\n\n## 6.2.0-alpha.33 (February 22, 2021)\n\n### Features\n\n- Addon-docs: Support story.mdx, stories.mdx ([#13996](https://github.com/storybookjs/storybook/pull/13996))\n\n### Bug Fixes\n\n- Webpack5: Remove outdated html-webpack-plugin types ([#13986](https://github.com/storybookjs/storybook/pull/13986))\n\n### Dependency Upgrades\n\n- Move to a fork of react-sizeme with updated React peer dependency ([#13733](https://github.com/storybookjs/storybook/pull/13733))\n- Webpack4: Upgrade html-webpack-plugin and remove external types ([#13993](https://github.com/storybookjs/storybook/pull/13993))\n\n## 6.2.0-alpha.32 (February 21, 2021)\n\n### Breaking prerelease\n\n**NOTE:** this is a breaking change for users of `@storybook/vue3` which is currently in alpha prerelease:\n\n- Vue 3: Map args with setup hook & remove automatic props mapping ([#13981](https://github.com/storybookjs/storybook/pull/13981))\n\n### Bug Fixes\n\n- Webpack5: Fix compilation error display ([#13983](https://github.com/storybookjs/storybook/pull/13983))\n- Webpack5: Add semver to builder-webpack5 dependencies ([#13982](https://github.com/storybookjs/storybook/pull/13982))\n- CLI: Don't allow empty string as outputDir option ([#13969](https://github.com/storybookjs/storybook/pull/13969))\n\n## 6.2.0-alpha.31 (February 20, 2021)\n\n### Features\n\n- Angular: Support angular components without selector ([#13939](https://github.com/storybookjs/storybook/pull/13939))\n- Preact: Add CSF types ([#13963](https://github.com/storybookjs/storybook/pull/13963))\n\n### Bug Fixes\n\n- Addon-docs: Fix ArgsTable tab renamed to `Story` when using args ([#13845](https://github.com/storybookjs/storybook/pull/13845))\n- Angular: Correctly destroy angular application between each render ([#13956](https://github.com/storybookjs/storybook/pull/13956))\n- Webpack5: Fix warnings display in build-storybook ([#13975](https://github.com/storybookjs/storybook/pull/13975))\n\n## 6.2.0-alpha.30 (February 20, 2021)\n\n### Features\n\n- Core: Support webpack5 and webpack4 side by side ([#13808](https://github.com/storybookjs/storybook/pull/13808))\n\n### Bug Fixes\n\n- Args: Fix issues with string default values ([#13919](https://github.com/storybookjs/storybook/pull/13919))\n- Args: Prefer react runtime default values ([#13937](https://github.com/storybookjs/storybook/pull/13937))\n\n### Maintenance\n\n- Core: Improve preset handling test coverage ([#13951](https://github.com/storybookjs/storybook/pull/13951))\n\n## 6.2.0-alpha.29 (February 18, 2021)\n\n### Features\n\n- Core: Sync args state to URL ([#13803](https://github.com/storybookjs/storybook/pull/13803))\n- UI: Select search input value on / ([#13884](https://github.com/storybookjs/storybook/pull/13884))\n\n### Bug Fixes\n\n- Components: Add missing `regenerator-runtime` dependency ([#13916](https://github.com/storybookjs/storybook/pull/13916))\n\n### Maintenance\n\n- Core: Load middleware.cjs if it exists ([#13592](https://github.com/storybookjs/storybook/pull/13592))\n- Build: Ensure consistency of Chromatic snapshots of Zoom stories ([#13932](https://github.com/storybookjs/storybook/pull/13932))\n- Angular: Clean and improve angular-cli examples ([#13886](https://github.com/storybookjs/storybook/pull/13886))\n\n## 6.2.0-alpha.28 (February 15, 2021)\n\n### Bug Fixes\n\n- Addon-actions: Change to override default values ([#13912](https://github.com/storybookjs/storybook/pull/13912))\n- CLI: Add safe check for eslint overrides ([#13717](https://github.com/storybookjs/storybook/pull/13717))\n\n### Maintenance\n\n- CLI: Don't try to add packages that are already installed ([#13876](https://github.com/storybookjs/storybook/pull/13876))\n\n## 6.2.0-alpha.27 (February 15, 2021)\n\n### Features\n\n- Addon-controls: Infer color and date controls ([#13675](https://github.com/storybookjs/storybook/pull/13675))\n- Svelte: Support TypeScript and preprocessors ([#13900](https://github.com/storybookjs/storybook/pull/13900))\n- Addon-controls: Add include/exclude configuration options ([#13898](https://github.com/storybookjs/storybook/pull/13898))\n\n### Maintenance\n\n- Add catalog metadata to the addons ([#13666](https://github.com/storybookjs/storybook/pull/13666))\n- Misc: Clean TS config and bump `@storybook/preset-create-react-app` ([#13878](https://github.com/storybookjs/storybook/pull/13878))\n\n## 6.1.18 (February 15, 2021)\n\n### Bug Fixes\n\n- UI: Fix theming for focused search bar ([#13895](https://github.com/storybookjs/storybook/pull/13895))\n- Storyshots: Support main.js usage ([#13842](https://github.com/storybookjs/storybook/pull/13842))\n\n## 6.2.0-alpha.26 (February 13, 2021)\n\n### Features\n\n- Addon-controls: Files control ([#13544](https://github.com/storybookjs/storybook/pull/13544))\n- UI: Add a 'main' role to the Main component for a11y ([#13827](https://github.com/storybookjs/storybook/pull/13827))\n\n### Bug Fixes\n\n- Addon-docs/Vue3: Attach app context from preview to inline stories ([#13894](https://github.com/storybookjs/storybook/pull/13894))\n- UI: Fix theming for focused search bar ([#13895](https://github.com/storybookjs/storybook/pull/13895))\n\n### Maintenance\n\n- Build: Move all the `yarn install` in the `build` CI job ([#13872](https://github.com/storybookjs/storybook/pull/13872))\n- Build: Rework `test` NPM script ([#13871](https://github.com/storybookjs/storybook/pull/13871))\n\n## 6.2.0-alpha.25 (February 11, 2021)\n\n### Features\n\n- Addon-docs: Configure syntax highlighter language by story parameter ([#13869](https://github.com/storybookjs/storybook/pull/13869))\n- Svelte: Improved decorators ([#13785](https://github.com/storybookjs/storybook/pull/13785))\n- Addon-docs/Angular: Add dynamic source snippets ([#13740](https://github.com/storybookjs/storybook/pull/13740))\n\n### Bug Fixes\n\n- Vue 3: Fix decorators and add more examples ([#13855](https://github.com/storybookjs/storybook/pull/13855))\n- Storyshots: Support main.js usage ([#13842](https://github.com/storybookjs/storybook/pull/13842))\n\n### Maintenance\n\n- Core: Add tests for the preset behavior of core ([#13846](https://github.com/storybookjs/storybook/pull/13846))\n- Upgrade to danger-js@main ([#13857](https://github.com/storybookjs/storybook/pull/13857))\n\n## 6.2.0-alpha.24 (February 6, 2021)\n\n### Features\n\n- Addon-storyshots: Add support for Vue 3 ([#13828](https://github.com/storybookjs/storybook/pull/13828))\n\n### Maintenance\n\n- CLI: only kill other processes on fail ([#13822](https://github.com/storybookjs/storybook/pull/13822))\n\n## 6.2.0-alpha.23 (February 5, 2021)\n\n### Bug Fixes\n\n- Addon-docs/Vue3: Resolve vue3 package for addon-docs preset ([#13819](https://github.com/storybookjs/storybook/pull/13819))\n\n## 6.2.0-alpha.22 (February 5, 2021)\n\n### Bug Fixes\n\n- CLI: Fix opening localhost in browser by default ([#13812](https://github.com/storybookjs/storybook/pull/13812))\n\n## 6.1.17 (February 4, 2021)\n\n### Bug Fixes\n\n- CLI: Fix opening localhost in browser by default ([#13812](https://github.com/storybookjs/storybook/pull/13812))\n\n## 6.2.0-alpha.21 (February 4, 2021)\n\n### Features\n\n- Addon-docs: Add support for Vue 3 ([#13809](https://github.com/storybookjs/storybook/pull/13809))\n\n### Maintenance\n\n- Build: Exclude all test and story files from transpilation ([#13714](https://github.com/storybookjs/storybook/pull/13714))\n- Build: Generate version file with preval macro ([#13715](https://github.com/storybookjs/storybook/pull/13715))\n\n## 6.1.16 (February 2, 2021)\n\n### Bug Fixes\n\n- Addon-docs/Svelte: Fix component name in docgen-loader ([#13760](https://github.com/storybookjs/storybook/pull/13760))\n- UI: Fix copy to clipboard for insecure deployments ([#13777](https://github.com/storybookjs/storybook/pull/13777))\n\n## 6.2.0-alpha.20 (February 2, 2021)\n\n### Features\n\n- Vue: Add Vue 3 support ([#13775](https://github.com/storybookjs/storybook/pull/13775))\n- CLI: Add try/catch on readFileAsJson to improve error message ([#13730](https://github.com/storybookjs/storybook/pull/13730))\n- Core: Generate manager cache in smoke test, but don't use/clear any cache ([#13784](https://github.com/storybookjs/storybook/pull/13784))\n\n### Bug Fixes\n\n- Addon-docs/Svelte: Fix component name in docgen-loader ([#13760](https://github.com/storybookjs/storybook/pull/13760))\n- Addon-docs/Svelte: Fix component description ([#13659](https://github.com/storybookjs/storybook/pull/13659))\n- UI: Fix copy to clipboard for insecure deployments ([#13777](https://github.com/storybookjs/storybook/pull/13777))\n\n### Maintenance\n\n- CLI: Handle package versions in package strings for generators ([#13774](https://github.com/storybookjs/storybook/pull/13774))\n- Build: Do not recompile packages in publish step of the CI ([#13786](https://github.com/storybookjs/storybook/pull/13786))\n- CI: Remove generic cache key from Circle CI ([#13787](https://github.com/storybookjs/storybook/pull/13787))\n- CI: Upgrade cache GH Action & remove fallback caches ([#13752](https://github.com/storybookjs/storybook/pull/13752))\n\n## 6.2.0-alpha.19 (January 29, 2021)\n\n### Features\n\n- Addon-docs/Angular: Inline rendering support with angular-elements ([#13525](https://github.com/storybookjs/storybook/pull/13525))\n- CLI: Add version matcher functions for framework detection ([#13738](https://github.com/storybookjs/storybook/pull/13738))\n\n### Bug Fixes\n\n- CLI: Fix handling of version ranges in dependency checks ([#13759](https://github.com/storybookjs/storybook/pull/13759))\n\n### Maintenance\n\n- Build: Enable deepscan in workspace ([#13716](https://github.com/storybookjs/storybook/pull/13716))\n- Chore: Increase node version minimums to 10.13 ([#13725](https://github.com/storybookjs/storybook/pull/13725))\n- Fixes smoke-test on svelte-kitchen-sink ([#13705](https://github.com/storybookjs/storybook/pull/13705))\n\n## 6.1.15 (January 22, 2021)\n\n### Bug Fixes\n\n- Svelte: Fix duplicate story preview ([#13663](https://github.com/storybookjs/storybook/pull/13663))\n- Angular: Properly handle empty tsconfig compilerOptions ([#13596](https://github.com/storybookjs/storybook/pull/13596))\n\n### Maintenance\n\n- Angular: Use Nx function to read non-angularCli configs ([#13558](https://github.com/storybookjs/storybook/pull/13558))\n\n### Dependency Upgrades\n\n- Bump @types/reach\\_\\_router version ([#13703](https://github.com/storybookjs/storybook/pull/13703))\n\n## 6.2.0-alpha.18 (January 22, 2021)\n\n### Bug Fixes\n\n- Svelte: Fix duplicate story preview ([#13663](https://github.com/storybookjs/storybook/pull/13663))\n\n### Maintenance\n\n- Angular: Add Angular 11.1 support ([#13704](https://github.com/storybookjs/storybook/pull/13704))\n\n### Dependency Upgrades\n\n- Bump @types/reach\\_\\_router version ([#13703](https://github.com/storybookjs/storybook/pull/13703))\n\n## 6.2.0-alpha.17 (January 22, 2021)\n\n### Features\n\n- Addon-docs/Svelte: Add dynamic snippet support ([#13653](https://github.com/storybookjs/storybook/pull/13653))\n- Addon-docs/Svelte: Add Slots and Events to the generated ArgsTable ([#13660](https://github.com/storybookjs/storybook/pull/13660))\n\n### Bug Fixes\n\n- Angular: Force re-render if template change ([#13638](https://github.com/storybookjs/storybook/pull/13638))\n- Angular: Properly handle empty tsconfig compilerOptions ([#13596](https://github.com/storybookjs/storybook/pull/13596))\n\n### Maintenance\n\n- Core: Deprecate default postcss config, recommend addon-postcss ([#13669](https://github.com/storybookjs/storybook/pull/13669))\n- Core: Throw an error for invalid story format ([#13673](https://github.com/storybookjs/storybook/pull/13673))\n- Build: Ensure consistency of Chromatic snapshots of Zoom stories ([#13676](https://github.com/storybookjs/storybook/pull/13676))\n\n### Dependency Upgrades\n\n- Dependencies: Swap back to upstream postcss-loader ([#13698](https://github.com/storybookjs/storybook/pull/13698))\n\n## 6.2.0-alpha.16 (January 16, 2021)\n\n### Dependency Upgrades\n\n- Dependencies: Remove inquirer types ([#13651](https://github.com/storybookjs/storybook/pull/13651))\n- Dependencies: Swap postcss-loader for fork version ([#13655](https://github.com/storybookjs/storybook/pull/13655))\n\n## 6.2.0-alpha.15 (January 15, 2021)\n\n### Features\n\n- Addon-actions: Normalize args ([#13624](https://github.com/storybookjs/storybook/pull/13624))\n- Addon-viewport: Add viewports of the latest iPhones ([#13176](https://github.com/storybookjs/storybook/pull/13176))\n\n### Maintenance\n\n- Maintenance: Configure Renovate ([#13641](https://github.com/storybookjs/storybook/pull/13641))\n\n### Dependency Upgrades\n\n- Dependencies: 6.2 non-breaking package upgrades ([#13631](https://github.com/storybookjs/storybook/pull/13631))\n- Dependencies: Update postcss-loader to ^4.1.0 ([#13640](https://github.com/storybookjs/storybook/pull/13640))\n\n## 6.2.0-alpha.14 (January 14, 2021)\n\n### Bug Fixes\n\n- CLI: Fix sb init prompt when framework type is undetected ([#13520](https://github.com/storybookjs/storybook/pull/13520))\n\n### Maintenance\n\n- Rax: Migrate to TS ([#13450](https://github.com/storybookjs/storybook/pull/13450))\n- Riot: Migrate to TS ([#13447](https://github.com/storybookjs/storybook/pull/13447))\n- Marionette: Migrate to TS ([#13448](https://github.com/storybookjs/storybook/pull/13448))\n- Marko: Migrate to TS ([#13449](https://github.com/storybookjs/storybook/pull/13449))\n\n## 6.2.0-alpha.13 (January 13, 2021)\n\n### Features\n\n- Angular: Improve decorators ([#13507](https://github.com/storybookjs/storybook/pull/13507))\n\n### Maintenance\n\n- Angular: Fix flaky tests based on timezone ([#13609](https://github.com/storybookjs/storybook/pull/13609))\n- Angular: Use Nx function to read non-angularCli configs ([#13558](https://github.com/storybookjs/storybook/pull/13558))\n- Build: Move Preact E2E tests on a Node 12 executor ([#13582](https://github.com/storybookjs/storybook/pull/13582))\n- Addon-docs: Add missing types for Story doc block ([#13549](https://github.com/storybookjs/storybook/pull/13549))\n\n## 6.1.14 (January 12, 2021)\n\n### Bug Fixes\n\n- Core: Use fs-extra emptyDir so build works on docker volume ([#13474](https://github.com/storybookjs/storybook/pull/13474))\n- Addon-docs: Tighten preset webpack pattern for mdx stories ([#13476](https://github.com/storybookjs/storybook/pull/13476))\n- Typescript: Fix qs import in @storybook/client-api ([#13518](https://github.com/storybookjs/storybook/pull/13518))\n- CLI: Ensure --host option changes the network host ([#13521](https://github.com/storybookjs/storybook/pull/13521))\n- Svelte: Statically load docgen info for svelte components ([#13466](https://github.com/storybookjs/storybook/pull/13466))\n\n## 6.1.13 (January 12, 2021)\n\nNPM publish failed\n\n## 6.1.12 (January 12, 2021)\n\n### Bug Fixes\n\n- Addon-docs: Fix link not working cross origin ([#13022](https://github.com/storybookjs/storybook/pull/13022))\n- Addon-docs: Resolve babel-loader from storybook/core ([#13607](https://github.com/storybookjs/storybook/pull/13607))\n\n## 6.2.0-alpha.12 (January 12, 2021)\n\n### Bug Fixes\n\n- Addon-docs: Resolve babel-loader from storybook/core ([#13607](https://github.com/storybookjs/storybook/pull/13607))\n\n## 6.2.0-alpha.11 (January 11, 2021)\n\n### Features\n\n- HTML: Add CSF types ([#13519](https://github.com/storybookjs/storybook/pull/13519))\n- Addon-jest: Infer parameter from story filename if not provided ([#13535](https://github.com/storybookjs/storybook/pull/13535))\n- Server: Forward globals in fetchStoryHtml ([#13158](https://github.com/storybookjs/storybook/pull/13158))\n\n### Bug Fixes\n\n- Addon-docs: Fix link not working cross origin ([#13022](https://github.com/storybookjs/storybook/pull/13022))\n- Addon-docs: Use theme text color header anchors ([#13533](https://github.com/storybookjs/storybook/pull/13533))\n\n### Maintenance\n\n- Build: remove redundant checks for TS type declaration generation ([#13567](https://github.com/storybookjs/storybook/pull/13567))\n\n## 6.2.0-alpha.10 (December 28, 2020)\n\n### Bug Fixes\n\n- Typescript: Fix qs import in @storybook/client-api ([#13518](https://github.com/storybookjs/storybook/pull/13518))\n- CLI: Ensure --host option changes the network host ([#13521](https://github.com/storybookjs/storybook/pull/13521))\n\n### Maintenance\n\n- Perf: Reuse SVG icon paths by using symbols ([#13110](https://github.com/storybookjs/storybook/pull/13110))\n- Core: Fix typing of dev CLI options ([#13501](https://github.com/storybookjs/storybook/pull/13501))\n- Perf: Bundle only required syntax highlighter languages ([#13479](https://github.com/storybookjs/storybook/pull/13479))\n\n## 6.2.0-alpha.9 (December 20, 2020)\n\n### Features\n\n- Web-components: Add typescript types and CLI template ([#12395](https://github.com/storybookjs/storybook/pull/12395))\n\n### Bug Fixes\n\n- Addon-docs: Fix angular without compodoc ([#13487](https://github.com/storybookjs/storybook/pull/13487))\n- Core: Use fs-extra emptyDir so build works on docker volume ([#13474](https://github.com/storybookjs/storybook/pull/13474))\n- Addon-docs: Tighten preset webpack pattern for mdx stories ([#13476](https://github.com/storybookjs/storybook/pull/13476))\n- Svelte: Statically load docgen info for svelte components ([#13466](https://github.com/storybookjs/storybook/pull/13466))\n\n### Dependency Upgrades\n\n- Bump @ember/optional-features from 1.3.0 to 2.0.0 ([#12829](https://github.com/storybookjs/storybook/pull/12829))\n\n## 6.2.0-alpha.8 (December 16, 2020)\n\n### Bug Fixes\n\n- Angular: Fix `configFile: undefined` in ts-loader options ([#13382](https://github.com/storybookjs/storybook/pull/13382))\n\n### Maintenance\n\n- Angular: Deprecate the story component attribute ([#13383](https://github.com/storybookjs/storybook/pull/13383))\n\n## 6.2.0-alpha.7 (December 15, 2020)\n\n### Bug Fixes\n\n- CLI: Add overrides to CRA ESLint config ([#13452](https://github.com/storybookjs/storybook/pull/13452))\n\n### Maintenance\n\n- Perf: Lazy load OverlayScrollbars ([#13430](https://github.com/storybookjs/storybook/pull/13430))\n- Addon-docs: Remove unused titleFunction export ([#13457](https://github.com/storybookjs/storybook/pull/13457))\n- Perf: Distribute both ESM and CJS modules ([#13013](https://github.com/storybookjs/storybook/pull/13013))\n- Perf: Replace react-hotkeys with useEffect keybinding ([#13424](https://github.com/storybookjs/storybook/pull/13424))\n\n## 6.1.11 (December 12, 2020)\n\n### Bug Fixes\n\n- UI: Fix null ref in sidebar ([#13423](https://github.com/storybookjs/storybook/pull/13423))\n- Addon-docs: Handle svelte docgen failures gracefully ([#13386](https://github.com/storybookjs/storybook/pull/13386))\n\n### Dependency Upgrades\n\n- Update react-popper-tooltip and @popperjs/core for react17 ([#13434](https://github.com/storybookjs/storybook/pull/13434))\n\n## 6.2.0-alpha.6 (December 12, 2020)\n\n### Features\n\n- Main.js: Add previewHead, previewBody, managerHead presets ([#13432](https://github.com/storybookjs/storybook/pull/13432))\n\n### Bug Fixes\n\n- Core: Fix `modulesCount` cache storage and retrieval ([#13431](https://github.com/storybookjs/storybook/pull/13431))\n- UI: Fix null ref in sidebar ([#13423](https://github.com/storybookjs/storybook/pull/13423))\n\n### Maintenance\n\n- Components: Cleanup circular dependencies ([#13439](https://github.com/storybookjs/storybook/pull/13439))\n- Core: Generate bundle size report for prebuilt manager ([#13425](https://github.com/storybookjs/storybook/pull/13425))\n- CI: Speed up CircleCI workflows ([#13320](https://github.com/storybookjs/storybook/pull/13320))\n\n### Dependency Upgrades\n\n- Update react-popper-tooltip and @popperjs/core for react17 ([#13434](https://github.com/storybookjs/storybook/pull/13434))\n\n## 6.2.0-alpha.5 (December 8, 2020)\n\n### Bug Fixes\n\n- Core: Fix `--static-dir` with absolute path on Windows ([#13344](https://github.com/storybookjs/storybook/pull/13344))\n\n## 6.2.0-alpha.4 (December 6, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Handle svelte docgen failures gracefully ([#13386](https://github.com/storybookjs/storybook/pull/13386))\n\n### Dependency Upgrades\n\n- Bump @ember/test-helpers from 1.7.1 to 2.1.0 ([#13143](https://github.com/storybookjs/storybook/pull/13143))\n\n## 6.2.0-alpha.3 (December 4, 2020)\n\n### Bug Fixes\n\n- CLI: Fix stories path in Introduction.stories.mdx ([#13368](https://github.com/storybookjs/storybook/pull/13368))\n- UI: Fix display of custom brand image ([#13355](https://github.com/storybookjs/storybook/pull/13355))\n\n### Maintenance\n\n- CLI: Replace inquirer with prompts ([#13225](https://github.com/storybookjs/storybook/pull/13225))\n\n## 6.1.10 (December 4, 2020)\n\n### Bug Fixes\n\n- CLI: Fix stories path in Introduction.stories.mdx ([#13368](https://github.com/storybookjs/storybook/pull/13368))\n- UI: Fix display of custom brand image ([#13355](https://github.com/storybookjs/storybook/pull/13355))\n- Storyshots: Fix missing `done` attribute on type definition ([#13341](https://github.com/storybookjs/storybook/pull/13341))\n- Addon-docs: ArgTypes optional on Meta ([#13352](https://github.com/storybookjs/storybook/pull/13352))\n\n### Dependency Upgrades\n\n- Addon-storyshots: Add React as peer dependency ([#13343](https://github.com/storybookjs/storybook/pull/13343))\n\n## 6.2.0-alpha.2 (December 3, 2020)\n\n### Bug Fixes\n\n- Storyshots: Fix missing `done` attribute on type definition ([#13341](https://github.com/storybookjs/storybook/pull/13341))\n- Core: Fix IE11 compatibility by using XHR and plain ES5 ([#13348](https://github.com/storybookjs/storybook/pull/13348))\n\n### Maintenance\n\n- Angular: Overhaul preview renderer ([#13215](https://github.com/storybookjs/storybook/pull/13215))\n\n## 6.2.0-alpha.1 (December 1, 2020)\n\n### Bug Fixes\n\n- Addon-docs: ArgTypes optional on Meta ([#13352](https://github.com/storybookjs/storybook/pull/13352))\n- Composition: Filter out disabled refs in getAutoRefs ([#12863](https://github.com/storybookjs/storybook/pull/12863))\n- UI: Add support for expand/collapse keyboard shortcuts ([#12980](https://github.com/storybookjs/storybook/pull/12980))\n\n### Maintenance\n\n- Dependencies: Rebuild yarn.lock ([#13289](https://github.com/storybookjs/storybook/pull/13289))\n- Core: Add typescript as optional peer dependency ([#13330](https://github.com/storybookjs/storybook/pull/13330))\n\n### Dependency Upgrades\n\n- Bump wait-on from 4.0.2 to 5.2.0 ([#12835](https://github.com/storybookjs/storybook/pull/12835))\n- Bump commander from 5.1.0 to 6.2.0 ([#13148](https://github.com/storybookjs/storybook/pull/13148))\n\n## 6.2.0-alpha.0 (December 1, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Fix type aliases and enum types from Angular Compodoc JSON ([#12665](https://github.com/storybookjs/storybook/pull/12665))\n- Core: Ensure node `name` does not contain leading/trailing whitespace ([#13275](https://github.com/storybookjs/storybook/pull/13275))\n- Angular: Run setProps in the NgZone ([#12382](https://github.com/storybookjs/storybook/pull/12382))\n\n### Maintenance\n\n- Core: Make @babel/core an optional peer dependency ([#13329](https://github.com/storybookjs/storybook/pull/13329))\n- Core: Replace preset-env polyfills with babel-polyfills ([#13055](https://github.com/storybookjs/storybook/pull/13055))\n- CLI: use Jest to test CLI commands and remove outdated fixtures ([#12936](https://github.com/storybookjs/storybook/pull/12936))\n\n## 6.1.9 (November 29, 2020)\n\n### Bug Fixes\n\n- Addon-backgrounds: Fix grid offset always using default value ([#13260](https://github.com/storybookjs/storybook/pull/13260))\n- UI: Fix keybindings on non-US keyboard layouts ([#13319](https://github.com/storybookjs/storybook/pull/13319))\n- Addon-Docs: Handle class attributes in Dynamic Source Rendering for Vue.js ([#13327](https://github.com/storybookjs/storybook/pull/13327))\n\n## 6.1.8 (November 27, 2020)\n\n### Bug Fixes\n\n- Core: Fix preview URL dropped hashes ([#13308](https://github.com/storybookjs/storybook/pull/13308))\n- Core: Fix template script tag support ([#13271](https://github.com/storybookjs/storybook/pull/13271))\n- Addon-docs: Fix Vue source snippets for function attributes ([#13288](https://github.com/storybookjs/storybook/pull/13288))\n- Components: Fix Zoom for IE11 ([#13302](https://github.com/storybookjs/storybook/pull/13302))\n- React: Don't add FastRefresh if already enabled ([#13303](https://github.com/storybookjs/storybook/pull/13303))\n- CLI: Fix storybook-deployer upgrade warning ([#13306](https://github.com/storybookjs/storybook/pull/13306))\n\n### Maintenance\n\n- React: Expose StorybookConfig types ([#13309](https://github.com/storybookjs/storybook/pull/13309))\n- React: Fix unit tests for react preset ([#13315](https://github.com/storybookjs/storybook/pull/13315))\n\n## 6.1.7 (November 27, 2020)\n\n### Bug Fixes\n\n- CLI: Fix not printing managerTotalTime when using cached manager ([#13294](https://github.com/storybookjs/storybook/pull/13294))\n- Core: Only apply `express.json()` middleware to /runtime-error route ([#13295](https://github.com/storybookjs/storybook/pull/13295))\n- Core: Don't use prebuilt or cached manager when running smoke test ([#13266](https://github.com/storybookjs/storybook/pull/13266))\n- Core: Detect arg inference for cyclic args and warn ([#13263](https://github.com/storybookjs/storybook/pull/13263))\n\n### Dependency Upgrades\n\n- Remove unused dependency @svgr/webpack ([#13281](https://github.com/storybookjs/storybook/pull/13281))\n\n## 6.1.6 (November 25, 2020)\n\n### Bug Fixes\n\n- Addon-controls: Fix ensureDocsBeforeControls support for paths ([#13204](https://github.com/storybookjs/storybook/pull/13204))\n- CLI: Add core-js to Preact generator ([#13138](https://github.com/storybookjs/storybook/pull/13138))\n- Core: Improve handling of --static-dir option ([#13245](https://github.com/storybookjs/storybook/pull/13245))\n- Core: Fix webpack5 compatibility check for ProgressPlugin ([#13239](https://github.com/storybookjs/storybook/pull/13239))\n\n## 6.1.5 (November 24, 2020)\n\n### Bug Fixes\n\n- Core: Resolve react and react-dom from core ([#13195](https://github.com/storybookjs/storybook/pull/13195))\n\n## 6.1.4 (November 24, 2020)\n\n### Bug Fixes\n\n- Core: Clear manager cache on runtime error ([#13230](https://github.com/storybookjs/storybook/pull/13230))\n\n## 6.1.3 (November 23, 2020)\n\n### Bug Fixes\n\n- Core: Replace 'trash' with 'fs.remove' ([#13211](https://github.com/storybookjs/storybook/pull/13211))\n- UI: Fix overflow scrolling on layout:centered ([#13217](https://github.com/storybookjs/storybook/pull/13217))\n- CLI: Don't install babel-loader for CRA ([#13220](https://github.com/storybookjs/storybook/pull/13220))\n- Addon-docs: Fix lineheight in typeset component ([#13205](https://github.com/storybookjs/storybook/pull/13205))\n\n## 6.1.2 (November 21, 2020)\n\n### Bug Fixes\n\n- Storyshots: Fix `beforeScreenshot` and `afterScreenshot` return types ([#13198](https://github.com/storybookjs/storybook/pull/13198))\n- UI: Target only IE10/IE11 for our CSS vertical centering hack ([#13192](https://github.com/storybookjs/storybook/pull/13192))\n\n## 6.1.1 (November 20, 2020)\n\n### Bug Fixes\n\n- Addon-backgrounds: Fix grid disable ([#13175](https://github.com/storybookjs/storybook/pull/13175))\n\n## 6.1.0 (November 19, 2020)\n\n6.1 is the first in a series of performance-oriented Storybook releases. It includes:\n\n- [Fast search and navigation](https://storybook.js.org/blog/new-component-finder-and-sidebar/)\n- Manager caching for faster startup [#12707](https://github.com/storybookjs/storybook/pull/12707)\n- Asynchronous loaders [#12699](https://github.com/storybookjs/storybook/pull/12699)\n- React improvements\n\n  - React 17 support [#12972](https://github.com/storybookjs/storybook/pull/12972) [#12975](https://github.com/storybookjs/storybook/pull/12975)\n  - Fast refresh [#12470](https://github.com/storybookjs/storybook/pull/12470) [#12535](https://github.com/storybookjs/storybook/pull/12535)\n  - Strict mode [#12781](https://github.com/storybookjs/storybook/pull/12781)\n\n    6.1 contains hundreds more fixes, features, and tweaks. Browse the [changelogs](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) matching `6.1.0-alpha.*`, `6.1.0-beta.*`, and `6.1.0-rc.*` for the full list of changes. See [Storybook 6 migration guide](https://medium.com/storybookjs/storybook-6-migration-guide-200346241bb5) to upgrade from `5.3` or earlier.\n\n## 6.1.0-rc.6 (November 19, 2020)\n\n### Bug Fixes\n\n- Core: Fix using cached manager on the 2nd run ([#13165](https://github.com/storybookjs/storybook/pull/13165))\n- Addon-docs: Fix Preview scaling with transform instead of zoom ([#12845](https://github.com/storybookjs/storybook/pull/12845))\n\n## 6.1.0-rc.5 (November 19, 2020)\n\n### Features\n\n- UI: CSS escape hatches for sidebar styling ([#13155](https://github.com/storybookjs/storybook/pull/13155))\n\n### Bug Fixes\n\n- UI: Fix CSS for IE11 ([#13159](https://github.com/storybookjs/storybook/pull/13159))\n\n### Maintenance\n\n- Build: Update example and app to Angular 11 ([#13141](https://github.com/storybookjs/storybook/pull/13141))\n\n## 6.1.0-rc.4 (November 17, 2020)\n\n### Maintenance\n\n- Build: Fix Yarn 2 E2E tests ([#13129](https://github.com/storybookjs/storybook/pull/13129))\n- UI: Reduce rerenders when changing the selected story ([#13107](https://github.com/storybookjs/storybook/pull/13107))\n- Build: Update example to Angular 10 ([#13048](https://github.com/storybookjs/storybook/pull/13048))\n\n## 6.1.0-rc.3 (November 16, 2020)\n\n### Maintenance\n\n- Addon-docs: Export SourceContainer context ([#13118](https://github.com/storybookjs/storybook/pull/13118))\n- UI: Fix loading UI when EventSource isn't defined ([#13123](https://github.com/storybookjs/storybook/pull/13123))\n- Build: Remove some dependencies and improve E2E workflow ([#13115](https://github.com/storybookjs/storybook/pull/13115))\n\n## 6.1.0-rc.2 (November 13, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Fix Meta prop types ([#13101](https://github.com/storybookjs/storybook/pull/13101))\n- UI: preventDefault for certain keyboard shortcuts ([#13097](https://github.com/storybookjs/storybook/pull/13097))\n\n### Dependency Upgrades\n\n- Bump `@emotion/core` to 10.1.1 ([#13102](https://github.com/storybookjs/storybook/pull/13102))\n\n## 6.1.0-rc.1 (November 13, 2020)\n\n### Maintenance\n\n- Angular: Support Angular 11 ([#13096](https://github.com/storybookjs/storybook/pull/13096))\n- UI: Tree highlight performance ([#13095](https://github.com/storybookjs/storybook/pull/13095))\n\n## 6.1.0-rc.0 (November 12, 2020)\n\n### Bug Fixes\n\n- UI: Fix kebab-case CSS property error ([#13090](https://github.com/storybookjs/storybook/pull/13090))\n- UI: Fix single story hoisting at the root ([#13089](https://github.com/storybookjs/storybook/pull/13089))\n\n### Maintenance\n\n- UI: Disable instant-on manager for now ([#13084](https://github.com/storybookjs/storybook/pull/13084))\n\n## 6.1.0-beta.7 (November 11, 2020)\n\n### Bug Fixes\n\n- React: Don't create a new story function on every render ([#13069](https://github.com/storybookjs/storybook/pull/13069))\n- UI: Fix search field styling in Safari 13 ([#13070](https://github.com/storybookjs/storybook/pull/13070))\n- Addon-docs: Fix spurious warnings ([#13075](https://github.com/storybookjs/storybook/pull/13075))\n- UI: Fix Escape key handling perf ([#13073](https://github.com/storybookjs/storybook/pull/13073))\n- Storyshots: Fix compatibility for jest-preset-angular 8.3+ ([#13060](https://github.com/storybookjs/storybook/pull/13060))\n\n## 6.1.0-beta.6 (November 9, 2020)\n\n### Bug Fixes\n\n- Angular: Fix storyData handling on module update ([#13037](https://github.com/storybookjs/storybook/pull/13037))\n- Args: Default to type 'object' when there is a null arg ([#13051](https://github.com/storybookjs/storybook/pull/13051))\n- Core: Fix duplicate argTypeEnhancers on HMR ([#13050](https://github.com/storybookjs/storybook/pull/13050))\n\n### Dependency Upgrades\n\n- Bump react-dogen-typescript-plugin to 0.6.2 ([#13052](https://github.com/storybookjs/storybook/pull/13052))\n\n## 6.1.0-beta.5 (November 8, 2020)\n\n### Features\n\n- UI: Single story hoisting in sidebar ([#13039](https://github.com/storybookjs/storybook/pull/13039))\n\n## 6.1.0-beta.4 (November 6, 2020)\n\n### Bug Fixes\n\n- UI: Fixes for Sidebar and Search ([#13027](https://github.com/storybookjs/storybook/pull/13027))\n- Core: Make sure cache is available before trying to use it ([#13012](https://github.com/storybookjs/storybook/pull/13012))\n- Core: Fix possible \"write after end\" exception for response stream ([#13007](https://github.com/storybookjs/storybook/pull/13007))\n\n## 6.1.0-beta.3 (November 6, 2020)\n\n### Features\n\n- Core: Add STORYBOOK environment variable ([#12997](https://github.com/storybookjs/storybook/pull/12997))\n\n### Bug Fixes\n\n- Args: Fix args inference for null values ([#13029](https://github.com/storybookjs/storybook/pull/13029))\n- Core: Dedupe default ArgTypes enhancers ([#13030](https://github.com/storybookjs/storybook/pull/13030))\n- Core: Add catch to end process ([#13018](https://github.com/storybookjs/storybook/pull/13018))\n- UI: Fix icon for addon panel orientation button ([#13026](https://github.com/storybookjs/storybook/pull/13026))\n- Addon-docs: Fix test for Angular type inference ([#13009](https://github.com/storybookjs/storybook/pull/13009))\n- CLI: Fix deprecation check ([#12981](https://github.com/storybookjs/storybook/pull/12981))\n- UI: Restrict layout styles to only apply to a rendered preview area ([#13014](https://github.com/storybookjs/storybook/pull/13014))\n\n### Maintenance\n\n- Build: Add chokidar2 for yarn dev ([#13028](https://github.com/storybookjs/storybook/pull/13028))\n- Build: Remove more enzyme ([#13005](https://github.com/storybookjs/storybook/pull/13005))\n\n### Dependency Upgrades\n\n- Bump webpack to 4.41.24 ([#13019](https://github.com/storybookjs/storybook/pull/13019))\n\n## 6.1.0-beta.2 (November 4, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Hide React default props in source block ([#13003](https://github.com/storybookjs/storybook/pull/13003))\n- Addon-docs: Angular empty string now infers to \"string\" instead of \"void\" ([#12994](https://github.com/storybookjs/storybook/pull/12994))\n\n### Maintenance\n\n- Components: Add outline icon ([#13002](https://github.com/storybookjs/storybook/pull/13002))\n- Core: Migrate core to TypeScript ([#12839](https://github.com/storybookjs/storybook/pull/12839))\n- Addon-docs: Exclude testfixtures from package ([#12998](https://github.com/storybookjs/storybook/pull/12998))\n\n## 6.1.0-beta.1 (November 3, 2020)\n\n### Bug Fixes\n\n- Components: react-syntaxt-highlighter optimization ([#12948](https://github.com/storybookjs/storybook/pull/12948))\n\n### Maintenance\n\n- Build: Replace enzyme with react-test-library ([#12990](https://github.com/storybookjs/storybook/pull/12990))\n- Core: Move `react` and `react-dom` to peer deps ([#12972](https://github.com/storybookjs/storybook/pull/12972))\n\n## 6.1.0-beta.0 (November 3, 2020)\n\n### Maintenance\n\n- Build: Relax react deps for preview-wrapper-react ([#12988](https://github.com/storybookjs/storybook/pull/12988))\n- Build: Run storybook in react@17 ([#12978](https://github.com/storybookjs/storybook/pull/12978))\n\n## 6.1.0-alpha.35 (November 2, 2020)\n\n### Maintenance\n\n- Build: Fix bootstrap reset command ([#12976](https://github.com/storybookjs/storybook/pull/12976))\n- Core: Remove webpack DLLs ([#12975](https://github.com/storybookjs/storybook/pull/12975))\n\n## 6.1.0-alpha.34 (November 1, 2020)\n\n### Features\n\n- Composition: Append index to ref indicator links ([#12932](https://github.com/storybookjs/storybook/pull/12932))\n\n### Bug Fixes\n\n- UI: Don't listen for progress updates in static builds ([#12966](https://github.com/storybookjs/storybook/pull/12966))\n\n## 6.1.0-alpha.33 (October 30, 2020)\n\n### Features\n\n- UI: Instant-on manager ([#12707](https://github.com/storybookjs/storybook/pull/12707))\n\n### Bug Fixes\n\n- Core: Disable UI dll by default ([#12926](https://github.com/storybookjs/storybook/pull/12926))\n- Combine args with basic object spread semantics ([#12958](https://github.com/storybookjs/storybook/pull/12958))\n\n### Dependency Upgrades\n\n- Core: Allow React-DOM 17.x ([#12937](https://github.com/storybookjs/storybook/pull/12937))\n\n## 6.1.0-alpha.32 (October 30, 2020)\n\n### Bug Fixes\n\n- CLI: Disable DLL by default in template ([#12954](https://github.com/storybookjs/storybook/pull/12954))\n- Preact: Fix peerDeps version specifier ([#12883](https://github.com/storybookjs/storybook/pull/12883))\n\n## 6.1.0-alpha.31 (October 27, 2020)\n\n### Features\n\n- Search UX improvements ([#12765](https://github.com/storybookjs/storybook/pull/12765))\n- Core: Add new layout style `none` and fix layout styles ([#12727](https://github.com/storybookjs/storybook/pull/12727))\n\n### Dependency Upgrades\n\n- Deps: Upgrade regenerator-runtime to 0.13.7 ([#12902](https://github.com/storybookjs/storybook/pull/12902))\n- Deps: Upgrade ts-dedent to 2.0 ([#12901](https://github.com/storybookjs/storybook/pull/12901))\n\n## 6.1.0-alpha.30 (October 26, 2020)\n\n### Features\n\n- Addon-docs: Lazy load iframes ([#12888](https://github.com/storybookjs/storybook/pull/12888))\n\n### Bug Fixes\n\n- React: Allow Storybook packages to use React 17.x ([#12908](https://github.com/storybookjs/storybook/pull/12908))\n- React: Support JSX react transform introduced in 16.14.0 ([#12899](https://github.com/storybookjs/storybook/pull/12899))\n- Addon-viewport: Fill entire iframe width with drop shadow ([#12870](https://github.com/storybookjs/storybook/pull/12870))\n\n### Maintenance\n\n- CLI: Deprecate '--story-format=mdx' option ([#12905](https://github.com/storybookjs/storybook/pull/12905))\n\n### Dependency Upgrades\n\n- Deps: upgrade babel to 7.12 ([#12903](https://github.com/storybookjs/storybook/pull/12903))\n- Addon-docs: Remove react-is dependency ([#12910](https://github.com/storybookjs/storybook/pull/12910))\n\n## 6.1.0-alpha.29 (October 23, 2020)\n\n### Bug Fixes\n\n- CLI: Fix intro MDX for React17 ([#12878](https://github.com/storybookjs/storybook/pull/12878))\n\n## 6.0.27 (October 23, 2020)\n\n### Bug Fixes\n\n- CLI: Fix intro MDX for React17 ([#12878](https://github.com/storybookjs/storybook/pull/12878))\n- Core: Disable Docs DLL by default ([#12874](https://github.com/storybookjs/storybook/pull/12874))\n- Essentials: Fix absolute config dir ([#12873](https://github.com/storybookjs/storybook/pull/12873))\n- Addon-controls: Fix \"docs before controls\" check ([#12738](https://github.com/storybookjs/storybook/pull/12738))\n- Addon-knobs: Fix uncontrolled to controlled warning for booleans ([#12719](https://github.com/storybookjs/storybook/pull/12719))\n\n### Dependency Upgrades\n\n- Upgrade babel-plugin-react-docgen ([#12748](https://github.com/storybookjs/storybook/pull/12748))\n\n## 6.1.0-alpha.28 (October 23, 2020)\n\n### Bug Fixes\n\n- Core: Disable Docs DLL by default ([#12874](https://github.com/storybookjs/storybook/pull/12874))\n- Essentials: Fix absolute config dir ([#12873](https://github.com/storybookjs/storybook/pull/12873))\n- UI: Add close button to version update notification ([#12320](https://github.com/storybookjs/storybook/pull/12320))\n\n### Maintenance\n\n- UI: Add fullscreen mode to docs ([#12861](https://github.com/storybookjs/storybook/pull/12861))\n\n### Dependency Upgrades\n\n- Angular: Update TypeScript peerDep version to support Angular 11 ([#12866](https://github.com/storybookjs/storybook/pull/12866))\n\n## 6.1.0-alpha.27 (October 19, 2020)\n\n### Features\n\n- Addon-docs: Dynamic source rendering for Vue ([#12812](https://github.com/storybookjs/storybook/pull/12812))\n\n### Bug Fixes\n\n- Core: Pass framework options as global ([#12810](https://github.com/storybookjs/storybook/pull/12810))\n\n### Maintenance\n\n- CLI: Clean up handling of unknown subcommands ([#12799](https://github.com/storybookjs/storybook/pull/12799))\n\n## 6.1.0-alpha.26 (October 18, 2020)\n\n### Maintenance\n\n- Components: Minor update checking color in Button ([#12800](https://github.com/storybookjs/storybook/pull/12800))\n\n### Dependency Upgrades\n\n- Bump vue-docgen-api to 4.33.1 ([#12808](https://github.com/storybookjs/storybook/pull/12808))\n- Storyshots: Add missing vue peer dependencies ([#12790](https://github.com/storybookjs/storybook/pull/12790))\n- Core/CLI: Update ShellJS dep version ([#12794](https://github.com/storybookjs/storybook/pull/12794))\n\n## 6.1.0-alpha.25 (October 16, 2020)\n\n### Features\n\n- React: Add strictMode option ([#12781](https://github.com/storybookjs/storybook/pull/12781))\n\n### Dependency Upgrades\n\n- Bump lodash from 4.17.19 to 4.17.20 ([#12235](https://github.com/storybookjs/storybook/pull/12235))\n\n## 6.1.0-alpha.24 (October 15, 2020)\n\n### Bug Fixes\n\n- Addon-viewports: Fix initial load state ([#11627](https://github.com/storybookjs/storybook/pull/11627))\n- UI: Fullscreen toggle does not work when all panels are collapsed ([#11810](https://github.com/storybookjs/storybook/pull/11810))\n- Addon-controls: Fix \"docs before controls\" check ([#12738](https://github.com/storybookjs/storybook/pull/12738))\n\n### Maintenance\n\n- Build: fix E2E tests and rework related CircleCI jobs ([#12746](https://github.com/storybookjs/storybook/pull/12746))\n\n### Dependency Upgrades\n\n- Upgrade babel-plugin-react-docgen ([#12748](https://github.com/storybookjs/storybook/pull/12748))\n\n## 6.1.0-alpha.23 (October 12, 2020)\n\n### Features\n\n- Core: Add async loaders ([#12699](https://github.com/storybookjs/storybook/pull/12699))\n- Addon-a11y: Add blurred vision effect ([#12731](https://github.com/storybookjs/storybook/pull/12731))\n\n### Maintenance\n\n- Build: Improve angular e2e tests ([#12723](https://github.com/storybookjs/storybook/pull/12723))\n\n## 6.1.0-alpha.22 (October 10, 2020)\n\n### Features\n\n- Angular: Choose project used by Storybook ([#12565](https://github.com/storybookjs/storybook/pull/12565))\n\n### Bug Fixes\n\n- Composition: Fix incorrect ref type ([#12709](https://github.com/storybookjs/storybook/pull/12709))\n- Addon-knobs: Fix uncontrolled to controlled warning for booleans ([#12719](https://github.com/storybookjs/storybook/pull/12719))\n\n## 6.1.0-alpha.21 (October 8, 2020)\n\n### Features\n\n- Sidebar: Better search, keyboard shortcuts, \"recently viewed\" ([#12601](https://github.com/storybookjs/storybook/pull/12601))\n- Source-loader: Generate sourcemaps ([#12277](https://github.com/storybookjs/storybook/pull/12277))\n- Core: Add APNG support ([#12639](https://github.com/storybookjs/storybook/pull/12639))\n\n### Bug Fixes\n\n- Addon-docs: Fix Memo React components in ArgsTable ([#12686](https://github.com/storybookjs/storybook/pull/12686))\n- Core: Fix babel-loader path resolution ([#12536](https://github.com/storybookjs/storybook/pull/12536))\n\n### Maintenance\n\n- Core: Log which CSF file is failing to load ([#12690](https://github.com/storybookjs/storybook/pull/12690))\n- Build: Speed up CI checks ([#12315](https://github.com/storybookjs/storybook/pull/12315))\n\n## 6.0.26 (October 5, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Fix exotic React components in Source block ([#12638](https://github.com/storybookjs/storybook/pull/12638))\n\n## 6.1.0-alpha.20 (October 5, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Fix exotic React components in Source block ([#12638](https://github.com/storybookjs/storybook/pull/12638))\n- Storyshots: Fix typings of \"test\"-method ([#12389](https://github.com/storybookjs/storybook/pull/12389))\n- Storyshots: Fix support for test failures in async tests ([#11962](https://github.com/storybookjs/storybook/pull/11962))\n\n### Maintenance\n\n- Storyshots Puppeteer: Fix support for over 1 assertions in async tests ([#12657](https://github.com/storybookjs/storybook/pull/12657))\n\n### Dependency Upgrades\n\n- Marko: Update @marko/webpack and allow Marko 5 peerDepenency ([#12035](https://github.com/storybookjs/storybook/pull/12035))\n\n## 6.0.25 (October 4, 2020)\n\n### Bug Fixes\n\n- CLI: Workaround for react native `sb init` ([#12405](https://github.com/storybookjs/storybook/pull/12405))\n\n## 6.0.24 (October 4, 2020)\n\nFailed NPM publish\n\n## 6.0.23 (October 4, 2020)\n\nFailed NPM publish\n\n## 6.1.0-alpha.19 (October 3, 2020)\n\n### Maintenance\n\n- ArgsTable: Remove the \"simple\" detection for enum types ([#12587](https://github.com/storybookjs/storybook/pull/12587))\n- Addon-docs: Move summary & detail equality check to createSummaryValue ([#12588](https://github.com/storybookjs/storybook/pull/12588))\n- Essentials: Make controls tab show first ([#12652](https://github.com/storybookjs/storybook/pull/12652))\n- Misc: Clean usage and place in the monorepo of some dependencies ([#12653](https://github.com/storybookjs/storybook/pull/12653))\n\n## 6.1.0-alpha.18 (September 30, 2020)\n\n### Bug Fixes\n\n- Composition: Rename `disabled` parameter => `disable` ([#12603](https://github.com/storybookjs/storybook/pull/12603))\n- UI: Fix page title for non-alpha chars ([#12583](https://github.com/storybookjs/storybook/pull/12583))\n\n### Maintenance\n\n- Fix spelling errors ([#12590](https://github.com/storybookjs/storybook/pull/12590))\n\n## 6.1.0-alpha.17 (September 26, 2020)\n\n### Features\n\n- Addon-docs: Add CSS Shadow Parts to web-component props table ([#10442](https://github.com/storybookjs/storybook/pull/10442))\n\n### Dependency Upgrades\n\n- [Security] Bump bl from 1.2.2 to 1.2.3 ([#12480](https://github.com/storybookjs/storybook/pull/12480))\n- [Security] Bump node-fetch from 2.6.0 to 2.6.1 ([#12448](https://github.com/storybookjs/storybook/pull/12448))\n\n## 6.0.22 (September 26, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Change 2nd argument of transformSource to the storyContext ([#12265](https://github.com/storybookjs/storybook/pull/12265))\n- Angular: Unsubscribe prop subscriptions ([#12514](https://github.com/storybookjs/storybook/pull/12514))\n- React: Fix reactDocgen option when false ([#12492](https://github.com/storybookjs/storybook/pull/12492))\n- CLI: Fix storiesof-to-csf codemod for TypeScript ([#12453](https://github.com/storybookjs/storybook/pull/12453))\n- Addon-docs: Fix missing line-height on TypeSet block ([#12134](https://github.com/storybookjs/storybook/pull/12134))\n- Core: Use the denormed params on the first story for initial options ([#11938](https://github.com/storybookjs/storybook/pull/11938))\n\n### Maintenance\n\n- Build: Disable problematic story in Chromatic ([#12457](https://github.com/storybookjs/storybook/pull/12457))\n\n### Dependency Upgrades\n\n- [Security] Bump node-fetch from 2.6.0 to 2.6.1 ([#12448](https://github.com/storybookjs/storybook/pull/12448))\n\n## 6.1.0-alpha.16 (September 25, 2020)\n\n### Bug Fixes\n\n- Addon-backgrounds: Add docs support and extend grid configuration ([#12368](https://github.com/storybookjs/storybook/pull/12368))\n- Addon-docs: Fix story description to only show when expanded ([#12563](https://github.com/storybookjs/storybook/pull/12563))\n\n### Dependency Upgrades\n\n- Upgrade react-docgen-typescript-plugin to 0.6.0 ([#12577](https://github.com/storybookjs/storybook/pull/12577))\n\n## 6.1.0-alpha.15 (September 24, 2020)\n\n### Features\n\n- Core: Add viewMode to StoryContext ([#12566](https://github.com/storybookjs/storybook/pull/12566))\n- Addon-docs: Add converters between Flow types and storybook types ([#12550](https://github.com/storybookjs/storybook/pull/12550))\n\n### Bug Fixes\n\n- Addon-actions: Fix log flushing when story re-renders ([#12500](https://github.com/storybookjs/storybook/pull/12500))\n- Angular: Unsubscribe prop subscriptions ([#12514](https://github.com/storybookjs/storybook/pull/12514))\n- Addon-docs: Remove leading pipe if using raw value for Flow union ([#12549](https://github.com/storybookjs/storybook/pull/12549))\n\n## 6.1.0-alpha.14 (September 22, 2020)\n\n### Features\n\n- Web Components: Add script tag support ([#12509](https://github.com/storybookjs/storybook/pull/12509))\n\n### Bug Fixes\n\n- React: Fix fast refresh ([#12535](https://github.com/storybookjs/storybook/pull/12535))\n\n### Maintenance\n\n- CLI: Change suggested upgrade command to sb@latest ([#12533](https://github.com/storybookjs/storybook/pull/12533))\n\n## 6.1.0-alpha.13 (September 22, 2020)\n\nFailed NPM publish\n\n## 6.1.0-alpha.12 (September 21, 2020)\n\n### Features\n\n- React: Add react-refresh ([#12470](https://github.com/storybookjs/storybook/pull/12470))\n- Server: Add support for script tags ([#12522](https://github.com/storybookjs/storybook/pull/12522))\n\n### Dependency Upgrades\n\n- Core: Upgrade babel ([#12499](https://github.com/storybookjs/storybook/pull/12499))\n\n## 6.1.0-alpha.11 (September 19, 2020)\n\n### Bug Fixes\n\n- Preact: Keep the story state between rerenders ([#12221](https://github.com/storybookjs/storybook/pull/12221))\n\n### Maintenance\n\n- Addon-controls: Update style of Boolean control ([#12515](https://github.com/storybookjs/storybook/pull/12515))\n\n## 6.1.0-alpha.10 (September 16, 2020)\n\n### Features\n\n- Ember: Add `emberOptions` to `main.js` config ✨ ([#12440](https://github.com/storybookjs/storybook/pull/12440))\n\n### Bug Fixes\n\n- React: Fix reactDocgen option when false ([#12492](https://github.com/storybookjs/storybook/pull/12492))\n\n## 6.1.0-alpha.9 (September 13, 2020)\n\n### Features\n\n- Storyshots: Allow taking a screenshot of just a specific element ([#12460](https://github.com/storybookjs/storybook/pull/12460))\n\n### Bug Fixes\n\n- CLI: Fix storiesof-to-csf codemod for TypeScript ([#12453](https://github.com/storybookjs/storybook/pull/12453))\n\n### Maintenance\n\n- Addon-docs: Resolve vue-docgen-loader from @storybook/vue ([#12461](https://github.com/storybookjs/storybook/pull/12461))\n- Build: Disable problematic story in Chromatic ([#12457](https://github.com/storybookjs/storybook/pull/12457))\n\n## 6.1.0-alpha.8 (September 12, 2020)\n\n### Features\n\n- HTML: Add script tag support ([#12089](https://github.com/storybookjs/storybook/pull/12089))\n- Addon-docs: Fix fixed-position inline stories ([#11350](https://github.com/storybookjs/storybook/pull/11350))\n\n### Bug Fixes\n\n- Core: require.resolve loaders and add missing dependencies ([#12383](https://github.com/storybookjs/storybook/pull/12383))\n- Addon-docs: Fix DocsPage scroll behavior ([#12047](https://github.com/storybookjs/storybook/pull/12047))\n\n### Maintenance\n\n- Core: Fix monorepo compatibility ([#11753](https://github.com/storybookjs/storybook/pull/11753))\n\n## 6.1.0-alpha.7 (September 10, 2020)\n\n### Features\n\n- Components: Add graphql support to SyntaxHighlighter ([#12385](https://github.com/storybookjs/storybook/pull/12385))\n\n### Bug Fixes\n\n- UI: Fix the p > div nesting issue ([#12298](https://github.com/storybookjs/storybook/pull/12298))\n- Addon-docs: Apply transformSource to any SourceType ([#12375](https://github.com/storybookjs/storybook/pull/12375))\n- CLI: Workaround for react native `sb init` ([#12405](https://github.com/storybookjs/storybook/pull/12405))\n\n### Dependency Upgrades\n\n- Core: Change react deps to normal deps ([#11628](https://github.com/storybookjs/storybook/pull/11628))\n\n## 6.1.0-alpha.6 (September 10, 2020)\n\n### Features\n\n- Core: Add static dir path mappings ([#12222](https://github.com/storybookjs/storybook/pull/12222))\n- Addon-controls: Default to radio control for small enums ([#12436](https://github.com/storybookjs/storybook/pull/12436))\n\n### Bug Fixes\n\n- Source-loader: Export extract-source in its own entry point ([#12429](https://github.com/storybookjs/storybook/pull/12429))\n- Addon-docs: Prefer flow's union elements over raw values ([#12376](https://github.com/storybookjs/storybook/pull/12376))\n\n## 6.1.0-alpha.5 (September 10, 2020)\n\nFailed npm publish\n\n## 6.1.0-alpha.4 (September 8, 2020)\n\n### Features\n\n- Addon-docs: Add Methods to web components ArgsTable ([#12413](https://github.com/storybookjs/storybook/pull/12413))\n\n### Bug Fixes\n\n- Addon-docs: Introduce undefined filtering to jsxDecorator ([#12365](https://github.com/storybookjs/storybook/pull/12365))\n- Addon-docs: Fix missing line-height on TypeSet block ([#12134](https://github.com/storybookjs/storybook/pull/12134))\n\n### Maintenance\n\n- Addon-docs: Reuse extractSource from source-loader ([#12225](https://github.com/storybookjs/storybook/pull/12225))\n\n## 6.1.0-alpha.3 (September 3, 2020)\n\n### Features\n\n- Addon-docs: Add Controls argument autodetection for svelte ([#12347](https://github.com/storybookjs/storybook/pull/12347))\n\n### Bug Fixes\n\n- Core: Use denormed params of the first story for initial options ([#11938](https://github.com/storybookjs/storybook/pull/11938))\n\n### Maintenance\n\n- Addon-docs: Light refactor of Source block ([#12268](https://github.com/storybookjs/storybook/pull/12268))\n- Addon-docs: Change 2nd argument of transformSource to the storyContext ([#12265](https://github.com/storybookjs/storybook/pull/12265))\n\n### Dependency Upgrades\n\n- Bump css from 2.2.4 to 3.0.0 ([#12338](https://github.com/storybookjs/storybook/pull/12338))\n\n## 6.1.0-alpha.2 (September 3, 2020)\n\nFailed NPM publish\n\n## 6.1.0-alpha.1 (August 31, 2020)\n\n### Features\n\n- Components: Add additionalActions prop to Preview block ([#12274](https://github.com/storybookjs/storybook/pull/12274))\n\n### Maintenance\n\n- Addon-docs: Add transformSource for jsxDecorator, deprecated onBeforeRender ([#12178](https://github.com/storybookjs/storybook/pull/12178))\n\n### Dependency Upgrades\n\n- Update the axe version in addon-a11y to 4.0 ([#12150](https://github.com/storybookjs/storybook/pull/12150))\n- Upgrade react-popper-tooltip to 3.1.0 ([#11827](https://github.com/storybookjs/storybook/pull/11827))\n\n## 6.1.0-alpha.0 (August 31, 2020)\n\n### Features\n\n- SyntaxHighlighter: Put formatted code to clipboard ([#11276](https://github.com/storybookjs/storybook/pull/11276))\n- Addon-docs: Add inline rendering for svelte ([#12313](https://github.com/storybookjs/storybook/pull/12313))\n\n### Bug Fixes\n\n- UI: Remove scrolling attribute from iFrame ([#12223](https://github.com/storybookjs/storybook/pull/12223))\n\n### Maintenance\n\n- CLI: Add HTML components and stories ([#12286](https://github.com/storybookjs/storybook/pull/12286))\n- Vue: Add basic CSF types ([#12037](https://github.com/storybookjs/storybook/pull/12037))\n- CLI: Add Aurelia detection ([#12181](https://github.com/storybookjs/storybook/pull/12181))\n- Storyshots: Remove needless iteration testStorySnapshots ([#12321](https://github.com/storybookjs/storybook/pull/12321))\n\n### Dependency Upgrades\n\n- Bump react-syntax-highlighter to 13.2.1 ([#11838](https://github.com/storybookjs/storybook/pull/11838))\n\n## 6.0.21 (August 31, 2020)\n\n### Bug Fixes\n\n- Addon-controls: Fix uncontrolled to controlled warning for booleans ([#12322](https://github.com/storybookjs/storybook/pull/12322))\n\n### Maintenance\n\n- Build: Add CRA benchmark ([#12209](https://github.com/storybookjs/storybook/pull/12209))\n\n## 6.0.20 (August 28, 2020)\n\n### Bug Fixes\n\n- ArgsTable: Fix union type splitting ([#11868](https://github.com/storybookjs/storybook/pull/11868))\n- CLI: Fix import of Button in react mdx template ([#12252](https://github.com/storybookjs/storybook/pull/12252))\n\n## 5.3.21 (August 28, 2020)\n\n### Bug Fixes\n\n- Core: Add skip dispose option to ClientApi ([#9868](https://github.com/storybookjs/storybook/pull/9868))\n\n## 6.0.19 (August 27, 2020)\n\n### Bug Fixes\n\n- UI: Fix eject and copy URLs for composition ([#12233](https://github.com/storybookjs/storybook/pull/12233))\n\n## 5.3.20 (August 27, 2020)\n\n### Bug Fixes\n\n- React-native server: Fix addon tabs ([#10468](https://github.com/storybookjs/storybook/pull/10468))\n- Addon-docs: Fix babel JSX handling in MDX ([#11448](https://github.com/storybookjs/storybook/pull/11448))\n- Revert \"Fix: Search stories\" ([#10916](https://github.com/storybookjs/storybook/pull/10916))\n\n## 6.0.18 (August 26, 2020)\n\n### Bug Fixes\n\n- UI: Fix `disable` parameter to hide addon panel ([#12171](https://github.com/storybookjs/storybook/pull/12171))\n- Addon-controls: Fix controls from args ([#12230](https://github.com/storybookjs/storybook/pull/12230))\n\n### Dependency Upgrades\n\n- Mithril: Add Mithril v2.0.0 to peer dependencies ([#12229](https://github.com/storybookjs/storybook/pull/12229))\n\n## 6.0.17 (August 25, 2020)\n\n### Bug Fixes\n\n- Addon-essentials: Log info on config override ([#12211](https://github.com/storybookjs/storybook/pull/12211))\n\n### Maintenance\n\n- Build: Remove outdated CLI tests ([#12207](https://github.com/storybookjs/storybook/pull/12207))\n\n### Dependency Upgrades\n\n- Source-loader: Pin prettier to 2.0.x version ([#12226](https://github.com/storybookjs/storybook/pull/12226))\n\n## 6.0.16 (August 20, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Fix Vue ArgsTable sanitizing of item.type.elements to item.type.value ([#12165](https://github.com/storybookjs/storybook/pull/12165))\n\n## 6.0.15 (August 20, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Fix ArgsTable union type handling in Vue/TS ([#12158](https://github.com/storybookjs/storybook/pull/12158))\n- Addon-docs: Fix inline rendering for DOM nodes in HTML ([#12164](https://github.com/storybookjs/storybook/pull/12164))\n\n### Maintenance\n\n- React: Simplify component type for CSF typing ([#12110](https://github.com/storybookjs/storybook/pull/12110))\n\n## 6.0.14 (August 20, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Fix MDX IDs from CSF imports ([#12154](https://github.com/storybookjs/storybook/pull/12154))\n- Addon-viewport: Add preset to fix windows import ([#12148](https://github.com/storybookjs/storybook/pull/12148))\n- Composition: Verify refs in node ([#12085](https://github.com/storybookjs/storybook/pull/12085))\n\n### Maintenance\n\n- Build: Update and optimize circleCI Config ([#12118](https://github.com/storybookjs/storybook/pull/12118))\n\n## 6.0.13 (August 19, 2020)\n\n### Bug Fixes\n\n- Source-loader: Fix default exports of type TSAsExpression ([#12099](https://github.com/storybookjs/storybook/pull/12099))\n- Addon-docs: Fix source code for Template.bind({}) in MDX ([#12107](https://github.com/storybookjs/storybook/pull/12107))\n- Addon-A11y: Fix manual run & timeline ([#12003](https://github.com/storybookjs/storybook/pull/12003))\n- Core: Add frameworkPath to options to support custom frameworks ([#12087](https://github.com/storybookjs/storybook/pull/12087))\n\n## 6.0.12 (August 17, 2020)\n\n### Bug Fixes\n\n- Angular: Make CLI templates compatible with TS strict mode ([#12081](https://github.com/storybookjs/storybook/pull/12081))\n- React: Fix CSF component typing ([#12072](https://github.com/storybookjs/storybook/pull/12072))\n- ArgsTable: Fix styles to allow long text to wrap ([#11818](https://github.com/storybookjs/storybook/pull/11818))\n- Addon-docs: Fix main check for absolute config dirs ([#12057](https://github.com/storybookjs/storybook/pull/12057))\n\n## 6.0.11 (August 17, 2020)\n\nNPM publish failed\n\n## 6.0.10 (August 15, 2020)\n\n### Bug Fixes\n\n- Addon-controls: Fix argType inference priority ([#12048](https://github.com/storybookjs/storybook/pull/12048))\n\n## 6.0.9 (August 15, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Fix CSF names importing in MDX ([#12044](https://github.com/storybookjs/storybook/pull/12044))\n\n### Maintenance\n\n- ArgsTable: Error when subcomponents is an array ([#12033](https://github.com/storybookjs/storybook/pull/12033))\n\n## 6.0.8 (August 15, 2020)\n\nUnpublished\n\n## 6.0.7 (August 14, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Fix extractArgTypes for unknown component ([#12012](https://github.com/storybookjs/storybook/pull/12012))\n\n### Maintenance\n\n- UI: Update upgrade command in about section ([#11934](https://github.com/storybookjs/storybook/pull/11934))\n- Build: Remove documentation scripts and fix README ([#12015](https://github.com/storybookjs/storybook/pull/12015))\n\n### Dependency Upgrades\n\n- Bump jest-specific-snapshot to v4 ([#11939](https://github.com/storybookjs/storybook/pull/11939))\n\n## 6.0.6 (August 14, 2020)\n\n### Bug Fixes\n\n- CLI: Fix upgrade to warn when no packages found ([#11993](https://github.com/storybookjs/storybook/pull/11993))\n- Addon-docs: Fix blocks type export ([#11987](https://github.com/storybookjs/storybook/pull/11987))\n- CLI: Fix RN link ([#11973](https://github.com/storybookjs/storybook/pull/11973))\n\n## 6.0.5 (August 13, 2020)\n\n### Bug Fixes\n\n- CLI: Fix welcome links on Introduction MDX ([#11949](https://github.com/storybookjs/storybook/pull/11949))\n\n## 6.0.4 (August 12, 2020)\n\n### Bug Fixes\n\n- Source-loader: Fix `.add` detection ([#11920](https://github.com/storybookjs/storybook/pull/11920))\n\n## 6.0.3 (August 12, 2020)\n\n### Bug Fixes\n\n- Essentials: Fix missing toolbars addon ([#11910](https://github.com/storybookjs/storybook/pull/11910))\n\n## 6.0.2 (August 11, 2020)\n\n### Bug Fixes\n\n- CLI: Fix csf-hoist-story-annotations codemod for variable default exports ([#11895](https://github.com/storybookjs/storybook/pull/11895))\n\n## 6.0.1 (August 11, 2020)\n\n### Bug Fixes\n\n- Core: Fix support for main.ts/preview.ts files ([#11885](https://github.com/storybookjs/storybook/pull/11885))\n- Addon-docs: Fix ArgsTable regression ([#11889](https://github.com/storybookjs/storybook/pull/11889))\n\n## 6.0.0 (August 10, 2020)\n\nStorybook 6.0 is here!\n\n- 💎 [Essentials: Zero-configuration setup](https://medium.com/storybookjs/zero-config-storybook-66e7c4798e5d)\n- 🧬 [Args: Next-generation, dynamic story format](https://medium.com/storybookjs/introducing-storybook-args-2dadcdb777cc)\n- 🎛 [Controls: Live edit component examples](https://medium.com/storybookjs/storybook-controls-ce82af93e430)\n- 🌐 [Composition: Combine multiple Storybooks](https://medium.com/storybookjs/storybook-composition-af0da9084fba)\n- 📚 [Documentation: Complete project overhaul](https://storybook.js.org/docs/react/get-started)\n\n  6.0 contains hundreds more fixes, features, and tweaks. Browse the changelogs matching `6.0.0-alpha.*`, `6.0.0-beta.*`, and `6.0.0-rc.*` for the full list of changes. See [MIGRATION.md](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md) to upgrade from `5.3` or earlier.\n\n## 6.0.0-rc.30 (August 10, 2020)\n\n### Bug Fixes\n\n- Storyshots: Don't ship typescript files in dist ([#11792](https://github.com/storybookjs/storybook/pull/11792))\n\n### Maintenance\n\n- 6.0 documentation overhaul ([#11861](https://github.com/storybookjs/storybook/pull/11861))\n\n## 6.0.0-rc.29 (August 7, 2020)\n\n### Features\n\n- CLI: Add CSF types for Angular ([#11825](https://github.com/storybookjs/storybook/pull/11825))\n\n### Bug Fixes\n\n- Core: Fix serialization of `undefined` ([#11829](https://github.com/storybookjs/storybook/pull/11829))\n\n## 6.0.0-rc.28 (August 6, 2020)\n\n### Bug Fixes\n\n- CLI: Add CSF typings for react stories ([#11811](https://github.com/storybookjs/storybook/pull/11811))\n\n### Dependency Upgrades\n\n- Upgrade telejson to 5.0.1 ([#11824](https://github.com/storybookjs/storybook/pull/11824))\n\n## 6.0.0-rc.27 (August 6, 2020)\n\n### Features\n\n- Addon-docs: Prettier, collapsible values in ArgsTable ([#11768](https://github.com/storybookjs/storybook/pull/11768))\n- Addon-docs: Add inline rendering support for HTML ([#11814](https://github.com/storybookjs/storybook/pull/11814))\n\n### Bug Fixes\n\n- Addon-controls: Fix ArgsTable bugs and styling ([#11805](https://github.com/storybookjs/storybook/pull/11805))\n- Addon-docs: Don't zoom docs content ([#11795](https://github.com/storybookjs/storybook/pull/11795))\n\n## 6.0.0-rc.26 (August 5, 2020)\n\n### Dependency Upgrades\n\n- Perf: Upgrade telejson ([#11797](https://github.com/storybookjs/storybook/pull/11797))\n\n## 6.0.0-rc.25 (August 4, 2020)\n\n### Bug Fixes\n\n- CSF: Fix mixed `.x` and deprecated `.story.x` parameters ([#11781](https://github.com/storybookjs/storybook/pull/11781))\n\n## 6.0.0-rc.24 (August 3, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Fix link font size to inherit ([#11770](https://github.com/storybookjs/storybook/pull/11770))\n- Addon-knobs: Fix search params with URI encoding ([#11642](https://github.com/storybookjs/storybook/pull/11642))\n- Core: Add `STORY_SPECIFIED` event for initial selection/URL ([#11766](https://github.com/storybookjs/storybook/pull/11766))\n- Core: Fix handling of initial hashes ([#11767](https://github.com/storybookjs/storybook/pull/11767))\n\n### Documentation\n\n- Core: Fix link to deprecated configure ([#11771](https://github.com/storybookjs/storybook/pull/11771))\n\n## 6.0.0-rc.23 (August 3, 2020)\n\n### Bug Fixes\n\n- Source-loader: Fix storiesOf missing `__STORY__` variable ([#11765](https://github.com/storybookjs/storybook/pull/11765))\n\n## 6.0.0-rc.22 (August 2, 2020)\n\n### Features\n\n- Addon-docs: Add `docs.description` parameter ([#11761](https://github.com/storybookjs/storybook/pull/11761))\n\n### Bug Fixes\n\n- Composition: Fix missing version property in autoref ([#11745](https://github.com/storybookjs/storybook/pull/11745))\n- Addon-a11y: Fix inherited parameters ([#11730](https://github.com/storybookjs/storybook/pull/11730))\n- Addon-docs: Fix Ember args ([#11760](https://github.com/storybookjs/storybook/pull/11760))\n- Addon-Docs: Fix Ember extractArgTypes default value ([#10512](https://github.com/storybookjs/storybook/pull/10512))\n- Addon-Docs: Fix Ember extractArgTypes ([#10525](https://github.com/storybookjs/storybook/pull/10525))\n\n### Dependency Upgrades\n\n- Addon-docs: Make vue-docgen optional peer deps ([#11759](https://github.com/storybookjs/storybook/pull/11759))\n\n## 6.0.0-rc.21 (August 1, 2020)\n\n### Features\n\n- Addon-docs: Add Story.story for CSF stories with MDX docs ([#11752](https://github.com/storybookjs/storybook/pull/11752))\n\n### Maintenance\n\n- Addon-docs: Rename Preview/Props to Canvas/ArgsTable ([#11744](https://github.com/storybookjs/storybook/pull/11744))\n\n## 6.0.0-rc.20 (July 31, 2020)\n\n### Breaking Changes\n\n- Core: Pass normalized parameters to the story sort function ([#11743](https://github.com/storybookjs/storybook/pull/11743))\n\n### Bug Fixes\n\n- Core: Dedupe argTypes serialization ([#11740](https://github.com/storybookjs/storybook/pull/11740))\n\n## 6.0.0-rc.19 (July 31, 2020)\n\n### Bug Fixes\n\n- Core: Speed up combineParameters ([#11736](https://github.com/storybookjs/storybook/pull/11736))\n- Addon-docs: Support absolute anchors when deployed at non-root ([#11403](https://github.com/storybookjs/storybook/pull/11403))\n\n### Maintenance\n\n- Args: Add optional scalar test cases for typescript ([#11149](https://github.com/storybookjs/storybook/pull/11149))\n\n## 6.0.0-rc.18 (July 30, 2020)\n\n### Bug Fixes\n\n- Addon-controls: Fix update logic for argTypes with custom names ([#11704](https://github.com/storybookjs/storybook/pull/11704))\n- Core: Fix HMR ([#11709](https://github.com/storybookjs/storybook/pull/11709))\n- Server: Serialize Object controls as JSON over the wire ([#11703](https://github.com/storybookjs/storybook/pull/11703))\n- Revert #11502: Remove z-index on ActionBar ([#11708](https://github.com/storybookjs/storybook/pull/11708))\n- Revert #11066: Add skip to content on panel and story iframe ([#11718](https://github.com/storybookjs/storybook/pull/11718))\n- UI: Improve treestate performance ([#11725](https://github.com/storybookjs/storybook/pull/11725))\n\n## 6.0.0-rc.17 (July 30, 2020)\n\nFailed NPM publish\n\n## 6.0.0-rc.16 (July 28, 2020)\n\n### Features\n\n- Source-loader: Inject source snippets as story parameters ([#11707](https://github.com/storybookjs/storybook/pull/11707))\n- Source-loader: Handle bind expression stories ([#11710](https://github.com/storybookjs/storybook/pull/11710))\n- UI: Add skip to content on panel and story iframe ([#11066](https://github.com/storybookjs/storybook/pull/11066))\n- Addon-storyshots: Add web-component support ([#11064](https://github.com/storybookjs/storybook/pull/11064))\n\n### Bug Fixes\n\n- Addon-docs: Fix docs render layout to always be 'fullscreen' ([#11699](https://github.com/storybookjs/storybook/pull/11699))\n- UI: Fix release notes on production builds ([#11700](https://github.com/storybookjs/storybook/pull/11700))\n- Addon-docs: Apply list styles over reset ([#11281](https://github.com/storybookjs/storybook/pull/11281))\n\n### Maintenance\n\n- CLI: Update rax/mithril/web-components templates, rework Yarn2 E2E ([#11354](https://github.com/storybookjs/storybook/pull/11354))\n\n## 6.0.0-rc.15 (July 27, 2020)\n\n### Features\n\n- Server: Update to 6.0 APIs and support Controls ([#11680](https://github.com/storybookjs/storybook/pull/11680))\n\n### Bug Fixes\n\n- Addon-Storysource: Fix broken source when there's no story ([#11679](https://github.com/storybookjs/storybook/pull/11679))\n- Angular: Use system path when checking if asset is a directory ([#11472](https://github.com/storybookjs/storybook/pull/11472))\n- Composition: Fix composition of older storybooks ([#11673](https://github.com/storybookjs/storybook/pull/11673))\n- Core: Fix existing behavior with story prefixes ([#11660](https://github.com/storybookjs/storybook/pull/11660))\n- Core: Fix webpack recursion in mainjs glob processing logic ([#11647](https://github.com/storybookjs/storybook/pull/11647))\n\n### Maintenance\n\n- Addon-knobs: Move `@types/react-color` to devDeps ([#11690](https://github.com/storybookjs/storybook/pull/11690))\n\n### Dependency Upgrades\n\n- Bump react-docgen-typescript-plugin to 0.5.2 ([#11658](https://github.com/storybookjs/storybook/pull/11658))\n\n## 6.0.0-rc.14 (July 22, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Re-enable source-loader by default ([#11650](https://github.com/storybookjs/storybook/pull/11650))\n- Core: Remove duplicate decorators and warn ([#11643](https://github.com/storybookjs/storybook/pull/11643))\n- Storyshots: Fix metadata (parameters/decorators) handling ([#11518](https://github.com/storybookjs/storybook/pull/11518))\n- Addon-docs: Skip dynamic source rendering when not needed ([#11640](https://github.com/storybookjs/storybook/pull/11640))\n- Core: Fix prefix redirect ([#11637](https://github.com/storybookjs/storybook/pull/11637))\n\n### Maintenance\n\n- Core: Log message length on channel message ([#11646](https://github.com/storybookjs/storybook/pull/11646))\n\n## 6.0.0-rc.13 (July 21, 2020)\n\n### Bug Fixes\n\n- Core: Improve translation of globs for main.js stories ([#11531](https://github.com/storybookjs/storybook/pull/11531))\n- Core: Optimize `storiesHash` by removing unused parameters ([#11624](https://github.com/storybookjs/storybook/pull/11624))\n- Composition: Fix docs-only stories in composed refs ([#11584](https://github.com/storybookjs/storybook/pull/11584))\n- CLI: Generate `docs:json` command dynamically for Angular project ([#11622](https://github.com/storybookjs/storybook/pull/11622))\n\n## 6.0.0-rc.12 (July 20, 2020)\n\n### Bug Fixes\n\n- Addon-controls: Fix undefined args handling ([#11619](https://github.com/storybookjs/storybook/pull/11619))\n- UI: Fix the color of the menu separator ([#11564](https://github.com/storybookjs/storybook/pull/11564))\n- Storyshots: Don't show `configure` deprecation warning ([#11611](https://github.com/storybookjs/storybook/pull/11611))\n- Addon-docs: Fix Props `components` input ([#11612](https://github.com/storybookjs/storybook/pull/11612))\n\n### Maintenance\n\n- Examples: Remove deprecated hierarchy separators ([#11615](https://github.com/storybookjs/storybook/pull/11615))\n- Hoist CSF `.story` annotations ([#11617](https://github.com/storybookjs/storybook/pull/11617))\n\n## 6.0.0-rc.11 (July 19, 2020)\n\n### Features\n\n- Addon-controls: Expose `presetColors` for the color control ([#11606](https://github.com/storybookjs/storybook/pull/11606))\n\n### Bug Fixes\n\n- Addon-docs: Fix Vue defaultValue in props table ([#11603](https://github.com/storybookjs/storybook/pull/11603))\n\n## 6.0.0-rc.10 (July 18, 2020)\n\n### Features\n\n- Addon-docs: Automatic source selection based on story type ([#11601](https://github.com/storybookjs/storybook/pull/11601))\n\n## 6.0.0-rc.9 (July 17, 2020)\n\n### Bug Fixes\n\n- Addon-controls: Fix no-args warning if argTypes are used ([#11598](https://github.com/storybookjs/storybook/pull/11598))\n- Core: Pass denormalized stories to the sort function ([#11572](https://github.com/storybookjs/storybook/pull/11572))\n- Addon-docs: Fix Vue inline rendering with Args and decorators ([#11594](https://github.com/storybookjs/storybook/pull/11594))\n- Composition: Fix missing refId on getData calls ([#11541](https://github.com/storybookjs/storybook/pull/11541))\n- UI: Fix scrollbars in flexbar ([#11579](https://github.com/storybookjs/storybook/pull/11579))\n\n## 6.0.0-rc.8 (July 16, 2020)\n\n### Features\n\n- CLI: Component-driven React / Vue / Angular / Preact / Svelte templates ([#11505](https://github.com/storybookjs/storybook/pull/11505))\n- Addon-controls: Add reset UI to ArgsTable ([#11550](https://github.com/storybookjs/storybook/pull/11550))\n\n### Bug Fixes\n\n- Addon-docs: Fix Vue argTypes default values ([#11534](https://github.com/storybookjs/storybook/pull/11534))\n\n### Maintenance\n\n- Core: Move basic argType inference out of addon-docs and into core ([#11561](https://github.com/storybookjs/storybook/pull/11561))\n\n## 6.0.0-rc.7 (July 16, 2020)\n\nNPM publish failed\n\n## 6.0.0-rc.6 (July 16, 2020)\n\nNPM publish failed\n\n## 6.0.0-rc.5 (July 15, 2020)\n\n### Features\n\n- Core: Add args reset API ([#11519](https://github.com/storybookjs/storybook/pull/11519))\n\n### Bug Fixes\n\n- Addon-docs: Make Meta block subcomponents optional ([#11556](https://github.com/storybookjs/storybook/pull/11556))\n- UI: Remove z-index on ActionBar ([#11502](https://github.com/storybookjs/storybook/pull/11502))\n- Composition: Fix docs-only story handling for composed storybooks ([#11537](https://github.com/storybookjs/storybook/pull/11537))\n- Addon-Docs: Fix ArgsTable controls on Docs tab ([#11552](https://github.com/storybookjs/storybook/pull/11552))\n\n### Maintenance\n\n- Core: Add `argTypes` to `StoryContext` ([#11558](https://github.com/storybookjs/storybook/pull/11558))\n- CLI: Improve Storybook packages version management ([#11342](https://github.com/storybookjs/storybook/pull/11342))\n\n## 6.0.0-rc.4 (July 15, 2020)\n\nNPM publish failed\n\n## 6.0.0-rc.3 (July 11, 2020)\n\n### Bug Fixes\n\n- Composition: Don't show versions dropdown if there are no versions ([#11497](https://github.com/storybookjs/storybook/pull/11497))\n- Addon-docs: Remove undefined for optional values in Typescript Props ([#11503](https://github.com/storybookjs/storybook/pull/11503))\n\n## 6.0.0-rc.2 (July 10, 2020)\n\n### Bug Fixes\n\n- UI: Fix menu alignment regression ([#11469](https://github.com/storybookjs/storybook/pull/11469))\n- Composition: Fix syntax on `no-cors` ([#11491](https://github.com/storybookjs/storybook/pull/11491))\n- Addon-docs: Fix MDX handling to ignore babel.config.js ([#11495](https://github.com/storybookjs/storybook/pull/11495))\n- UI: Increase max-height of menu tooltip so scrollbars don't appear ([#11471](https://github.com/storybookjs/storybook/pull/11471))\n\n### Maintenance\n\n- CLI: Add common welcome MDX and cleanup ([#11422](https://github.com/storybookjs/storybook/pull/11422))\n- CSF: Deprecate duplicate titles rather than forbid them ([#11476](https://github.com/storybookjs/storybook/pull/11476))\n\n## 6.0.0-rc.1 (July 9, 2020)\n\n### Bug Fixes\n\n- Addon-toolbars: Show name if there is no icon ([#11475](https://github.com/storybookjs/storybook/pull/11475))\n\n### Maintenance\n\n- CI: Fix iframe test flake ([#11473](https://github.com/storybookjs/storybook/pull/11473))\n- CI: Deploy the `next` branch of frontpage too ([#11462](https://github.com/storybookjs/storybook/pull/11462))\n\n### Dependency Upgrades\n\n- Bump vue-property-decorator from 8.4.2 to 9.0.0 ([#11241](https://github.com/storybookjs/storybook/pull/11241))\n- Bump @types/react-dom from 16.9.7 to 16.9.8 ([#11191](https://github.com/storybookjs/storybook/pull/11191))\n- Bump jest-image-snapshot from 3.1.0 to 4.0.2 ([#11267](https://github.com/storybookjs/storybook/pull/11267))\n- Bump autoprefixer from 9.8.0 to 9.8.4 ([#11288](https://github.com/storybookjs/storybook/pull/11288))\n- [Security] Bump npm-registry-fetch from 4.0.4 to 4.0.5 ([#11453](https://github.com/storybookjs/storybook/pull/11453))\n\n## 6.0.0-rc.0 (July 8, 2020)\n\n[Storybook 6.0](https://github.com/storybookjs/storybook/issues/9311) is stabilizing! It brings loads of component dev and documentation improvements to your favorite workshop:\n\n- [Args](https://docs.google.com/document/d/1Mhp1UFRCKCsN8pjlfPdz8ZdisgjNXeMXpXvGoALjxYM/edit#heading=h.6mdg0tp8crgj) - next-gen dynamic component examples\n  - ([controls](https://github.com/storybookjs/storybook/pull/10834) / [runtime](https://github.com/storybookjs/storybook/pull/10014) / [actions](https://github.com/storybookjs/storybook/pull/10029) / [toolbars](https://github.com/storybookjs/storybook/pull/10028) / [docs controls](https://github.com/storybookjs/storybook/pull/10354))\n- [Composition](https://github.com/storybookjs/storybook/pull/9210) - compose multiple storybooks into one\n- [Zero-config Typescript](https://github.com/storybookjs/storybook/pull/10813) - pre-configured for all frameworks, easy customization\n- [Yarn 2 support](https://github.com/storybookjs/storybook/issues/9527) - next generation package management\n\n## 6.0.0-beta.46 (July 8, 2020)\n\n### Breaking Changes\n\n- Addon-backgrounds: Zero config defaults ([#11460](https://github.com/storybookjs/storybook/pull/11460))\n\n### Features\n\n- Composition: Add version query to composed ref ([#11447](https://github.com/storybookjs/storybook/pull/11447))\n- UI: Add version release notes ([#11360](https://github.com/storybookjs/storybook/pull/11360))\n\n### Maintenance\n\n- Addon-controls: Add addon-docs check on startup ([#11458](https://github.com/storybookjs/storybook/pull/11458))\n- Addon-docs: Remove deprecated addParameters calls ([#11455](https://github.com/storybookjs/storybook/pull/11455))\n- Composition: Change event source to ref ([#11392](https://github.com/storybookjs/storybook/pull/11392))\n- Fix Yarn 2 compatibility in CLI and Essentials ([#11444](https://github.com/storybookjs/storybook/pull/11444))\n\n## 6.0.0-beta.45 (July 7, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Fix babel JSX handling in MDX ([#11448](https://github.com/storybookjs/storybook/pull/11448))\n\n## 6.0.0-beta.44 (July 6, 2020)\n\n### Breaking Changes\n\n- Core: Consistent file paths for locally-defined addons ([#11368](https://github.com/storybookjs/storybook/pull/11368))\n\n### Features\n\n- Composition: Ensure args get sent to the right ref ([#11401](https://github.com/storybookjs/storybook/pull/11401))\n- Core: Deprecate configure and clearDecorators ([#11431](https://github.com/storybookjs/storybook/pull/11431))\n\n### Bug Fixes\n\n- Controls: Fix object control for story switching ([#11432](https://github.com/storybookjs/storybook/pull/11432))\n- Controls: Fix interaction lag & CJK input ([#11430](https://github.com/storybookjs/storybook/pull/11430))\n\n## 6.0.0-beta.43 (July 5, 2020)\n\n### Features\n\n- Composition: Ignore globals from non-local refs ([#11407](https://github.com/storybookjs/storybook/pull/11407))\n\n### Maintenance\n\n- Core: Remove manager redirects on boot ([#11390](https://github.com/storybookjs/storybook/pull/11390))\n\n## 6.0.0-beta.42 (July 5, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Fix Props subcomponents regression ([#11420](https://github.com/storybookjs/storybook/pull/11420))\n\n### Maintenance\n\n- Core: Deprecate `addParameters` and `addDecorator` ([#11417](https://github.com/storybookjs/storybook/pull/11417))\n\n## 6.0.0-beta.41 (July 4, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Fix subcomponents display logic ([#11415](https://github.com/storybookjs/storybook/pull/11415))\n- Addon-docs: Fix Source rendering corner case ([#11414](https://github.com/storybookjs/storybook/pull/11414))\n\n## 6.0.0-beta.40 (July 4, 2020)\n\n### Features\n\n- CLI: Add upgrade utility with version consistency check ([#11396](https://github.com/storybookjs/storybook/pull/11396))\n\n### Maintenance\n\n- Build: Fix CI breaks ([#11410](https://github.com/storybookjs/storybook/pull/11410))\n- Core: Deprecate immutable options as parameters ([#11387](https://github.com/storybookjs/storybook/pull/11387))\n\n## 6.0.0-beta.39 (July 2, 2020)\n\n### Breaking Changes\n\n- CSF: Forbid duplicate kinds ([#11369](https://github.com/storybookjs/storybook/pull/11369))\n- Args: Rename `globalArgs` to `globals` ([#11385](https://github.com/storybookjs/storybook/pull/11385))\n\n### Features\n\n- Args: Disable rows and controls in argTypes ([#11388](https://github.com/storybookjs/storybook/pull/11388))\n- Composition: Add auto disable ([#11364](https://github.com/storybookjs/storybook/pull/11364))\n- CLI: use addon-essentials & args ([#11282](https://github.com/storybookjs/storybook/pull/11282))\n\n### Maintenance\n\n- Build: Add artifacts for e2e CI task ([#11365](https://github.com/storybookjs/storybook/pull/11365))\n- Build: Remove cli fixtures in favor of e2e ([#11357](https://github.com/storybookjs/storybook/pull/11357))\n\n## 6.0.0-beta.38 (June 30, 2020)\n\n### Breaking Changes\n\n- Configuration: Remove hierarchy separators ([#11344](https://github.com/storybookjs/storybook/pull/11344))\n\n### Features\n\n- Addon-docs: Dynamic Source rendering for React ([#11332](https://github.com/storybookjs/storybook/pull/11332))\n- Args: Store global args in session storage ([#11345](https://github.com/storybookjs/storybook/pull/11345))\n- Addon-docs: Add opt-in Markdown transclusion in MDX ([#11334](https://github.com/storybookjs/storybook/pull/11334))\n\n### Bug Fixes\n\n- Core: Fix preset options handling ([#11333](https://github.com/storybookjs/storybook/pull/11333))\n- UI: Revert theming greys flip ([#11297](https://github.com/storybookjs/storybook/pull/11297))\n- Core: Composition QA ([#11224](https://github.com/storybookjs/storybook/pull/11224))\n\n### Maintenance\n\n- Examples: Dual theme rendering ([#11295](https://github.com/storybookjs/storybook/pull/11295))\n- Examples: Recreate stories for sidebaritem ([#11298](https://github.com/storybookjs/storybook/pull/11298))\n\n## 6.0.0-beta.37 (June 26, 2020)\n\n### Breaking Changes\n\n- Core: Deprecate `setAddon` from `storiesOf` API ([#11322](https://github.com/storybookjs/storybook/pull/11322))\n\n### Bug Fixes\n\n- Revert \"Core: Fix source-map strategy for production\" ([#11320](https://github.com/storybookjs/storybook/pull/11320))\n- Core: Set viewMode to story when navating from non story pages ([#11317](https://github.com/storybookjs/storybook/pull/11317))\n\n### Dependency Upgrades\n\n- Bump react-textarea-autosize to 8.1.1 ([#11319](https://github.com/storybookjs/storybook/pull/11319))\n\n## 6.0.0-beta.36 (June 25, 2020)\n\n### Features\n\n- Composition: Allow refs versions in config ([#11294](https://github.com/storybookjs/storybook/pull/11294))\n\n### Bug Fixes\n\n- CLI: Fix docs & essentials version on `sb@next init` ([#11303](https://github.com/storybookjs/storybook/pull/11303))\n- Composition: Fix list of versions missing current version ([#11259](https://github.com/storybookjs/storybook/pull/11259))\n- Composition: Fix undefined/undefined in url on init ([#11293](https://github.com/storybookjs/storybook/pull/11293))\n\n### Maintenance\n\n- Essentials example: Fix typescript error ([#11305](https://github.com/storybookjs/storybook/pull/11305))\n\n## 6.0.0-beta.35 (June 24, 2020)\n\n### Features\n\n- Essentials: Add addon-controls ([#11285](https://github.com/storybookjs/storybook/pull/11285))\n\n### Bug Fixes\n\n- Addon-docs markdown tables right align support ([#11280](https://github.com/storybookjs/storybook/pull/11280))\n\n### Maintenance\n\n- Addon-docs: Simplify argType inference ([#11284](https://github.com/storybookjs/storybook/pull/11284))\n\n## 6.0.0-beta.34 (June 23, 2020)\n\n### Features\n\n- Addon-backgrounds: Allow gradients in story preview ([#11265](https://github.com/storybookjs/storybook/pull/11265))\n\n### Bug Fixes\n\n- Core: Fix invalid glob warning for absolute paths ([#11247](https://github.com/storybookjs/storybook/pull/11247))\n\n### Maintenance\n\n- UI: Replace document.execCommand with navigator.clipboard ([#11251](https://github.com/storybookjs/storybook/pull/11251))\n- ArgsTable: Updated Boolean control ([#11263](https://github.com/storybookjs/storybook/pull/11263))\n- Core; Preserve watch output when running dev mode ([#11150](https://github.com/storybookjs/storybook/pull/11150))\n\n### Dependency Upgrades\n\n- Bump lint-staged from 10.2.6 to 10.2.10 ([#11187](https://github.com/storybookjs/storybook/pull/11187))\n\n## 6.0.0-beta.33 (June 22, 2020)\n\n### Features\n\n- ArgsTable: Add subsections and design cleanup ([#11216](https://github.com/storybookjs/storybook/pull/11216))\n- Core: Improve startup events ([#11080](https://github.com/storybookjs/storybook/pull/11080))\n\n### Bug Fixes\n\n- Preact: Fix Preact 8 compatibility ([#11225](https://github.com/storybookjs/storybook/pull/11225))\n\n### Maintenance\n\n- Core :Add deprecation message for selectedName/Kind urls ([#11111](https://github.com/storybookjs/storybook/pull/11111))\n\n## 6.0.0-beta.32 (June 19, 2020)\n\n### Bug Fixes\n\n- Addon-knobs: Update select types for undefined, null and boolean ([#11202](https://github.com/storybookjs/storybook/pull/11202))\n\n### Maintenance\n\n- Composition: rename auth url & add tests for modules/refs ([#11215](https://github.com/storybookjs/storybook/pull/11215))\n- Examples: Add design-system to official example ([#11081](https://github.com/storybookjs/storybook/pull/11081))\n\n## 6.0.0-beta.31 (June 17, 2020)\n\n### Bug Fixes\n\n- React: Fix react-docgen for JS files ([#11217](https://github.com/storybookjs/storybook/pull/11217))\n- React: Load root tsconfig.json into docgen-typescript if none provided ([#11184](https://github.com/storybookjs/storybook/pull/11184))\n- Composition: Remove manual redirects ([#11196](https://github.com/storybookjs/storybook/pull/11196))\n\n### Dependency Upgrades\n\n- Bump react-draggable from 4.4.2 to 4.4.3 ([#11192](https://github.com/storybookjs/storybook/pull/11192))\n\n## 6.0.0-beta.30 (June 16, 2020)\n\n### Features\n\n- MDX: Support function.bind({}) syntax ([#11198](https://github.com/storybookjs/storybook/pull/11198))\n\n### Bug Fixes\n\n- Addon-docs: Remove render preprocessing for react components w/o docgen ([#11195](https://github.com/storybookjs/storybook/pull/11195))\n- Core: Fix addon load order ([#11178](https://github.com/storybookjs/storybook/pull/11178))\n- Core: Add global box-sizing setting. Fixes #10207 ([#11055](https://github.com/storybookjs/storybook/pull/11055))\n\n### Maintenance\n\n- Addon-controls: Add examples to angular, ember, html, svelte, vue, web-components ([#11197](https://github.com/storybookjs/storybook/pull/11197))\n\n## 6.0.0-beta.29 (June 16, 2020)\n\n### Features\n\n- Addon-docs: Add syntax highlighting to Code and Description blocks ([#11183](https://github.com/storybookjs/storybook/pull/11183))\n\n### Bug Fixes\n\n- MDX: Don't use root babelrc by default ([#11185](https://github.com/storybookjs/storybook/pull/11185))\n- Addon-docs: Fix 'show source' for stories with dynamic title ([#10959](https://github.com/storybookjs/storybook/pull/10959))\n\n## 6.0.0-beta.28 (June 15, 2020)\n\n### Features\n\n- Addon-docs: Add argTypes type/control shorthand ([#11174](https://github.com/storybookjs/storybook/pull/11174))\n\n### Bug Fixes\n\n- Core: Remove boxSizing to fix weird CSS layouts ([#11175](https://github.com/storybookjs/storybook/pull/11175))\n- Addon-docs: Fix forwardRef & invalid hook call ([#11154](https://github.com/storybookjs/storybook/pull/11154))\n- Client-API: Add @types/qs typings ([#11162](https://github.com/storybookjs/storybook/pull/11162))\n\n### Maintenance\n\n- CLI: Colocate stories and components, centralize main.js ([#11136](https://github.com/storybookjs/storybook/pull/11136))\n- Build: Exclude stories from collecting coverage ([#11164](https://github.com/storybookjs/storybook/pull/11164))\n- Core: Extend router/utils test set ([#11156](https://github.com/storybookjs/storybook/pull/11156))\n\n## 6.0.0-beta.27 (June 14, 2020)\n\n### Maintenance\n\n- UI: Remove unused modules ([#11159](https://github.com/storybookjs/storybook/pull/11159))\n- UI: Remove unused & duplicated code ([#11155](https://github.com/storybookjs/storybook/pull/11155))\n- REMOVE unused dependencies && FIX versions ([#11143](https://github.com/storybookjs/storybook/pull/11143))\n\n## 6.0.0-beta.26 (June 12, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Fix Vue args rendering in Docs mode ([#11138](https://github.com/storybookjs/storybook/pull/11138))\n- Typescript: Fix mandatory typescript dependency ([#11140](https://github.com/storybookjs/storybook/pull/11140))\n\n## 6.0.0-beta.25 (June 11, 2020)\n\n### Bug Fixes\n\n- Composition: Fix auto refs when there are no specified refs ([#11057](https://github.com/storybookjs/storybook/pull/11057))\n\n## 6.0.0-beta.24 (June 11, 2020)\n\n### Breaking Changes\n\n- Components: Remove PropsTable, clean ArgsTable stories ([#11105](https://github.com/storybookjs/storybook/pull/11105))\n\n### Features\n\n- React: Switch react-docgen-typescript-loader to react-docgen-typescript-plugin ([#11106](https://github.com/storybookjs/storybook/pull/11106))\n- Vue: Add first-class args support ([#11115](https://github.com/storybookjs/storybook/pull/11115))\n- Core: Add babel plugin for typescript decorators ([#11063](https://github.com/storybookjs/storybook/pull/11063))\n- CLI: Pass --quiet to disable HMR logging in browser console ([#11087](https://github.com/storybookjs/storybook/pull/11087))\n- Addon-knobs: Add number of knobs to tab title ([#11075](https://github.com/storybookjs/storybook/pull/11075))\n\n### Bug Fixes\n\n- Core: Fix package duplication issues by aliasing all storybook packages ([#11092](https://github.com/storybookjs/storybook/pull/11092))\n- hidden) canvas ([#10599](https://github.com/storybookjs/storybook/pull/10599))\n- Core: Fix loglevel filtering ([#11096](https://github.com/storybookjs/storybook/pull/11096))\n- Core: Remove @babel/plugin-transform-react-constant-elements ([#11086](https://github.com/storybookjs/storybook/pull/11086))\n- UI: Fix search in production mode ([#10917](https://github.com/storybookjs/storybook/pull/10917))\n\n### Maintenance\n\n- CLI: Refactor to simplify works with multiple package managers ([#11074](https://github.com/storybookjs/storybook/pull/11074))\n\n### Dependency Upgrades\n\n- chore(deps-dev): bump protractor from 5.4.4 to 7.0.0 ([#10832](https://github.com/storybookjs/storybook/pull/10832))\n- build(deps): [security] bump websocket-extensions from 0.1.3 to 0.1.4 ([#11056](https://github.com/storybookjs/storybook/pull/11056))\n- build(deps): bump @babel/plugin-transform-shorthand-properties from 7.8.3 to 7.10.1 ([#11088](https://github.com/storybookjs/storybook/pull/11088))\n- build(deps-dev): bump tslib from 1.13.0 to 2.0.0 ([#11089](https://github.com/storybookjs/storybook/pull/11089))\n- build(deps-dev): bump @packtracker/webpack-plugin from 2.2.0 to 2.3.0 ([#11091](https://github.com/storybookjs/storybook/pull/11091))\n\n## 6.0.0-beta.23 (June 8, 2020)\n\n### Features\n\n- Addon-docs: Add `docs.forceExtractedArgTypes` parameter ([#11069](https://github.com/storybookjs/storybook/pull/11069))\n\n### Bug Fixes\n\n- Vue: Fix force rendering ([#11076](https://github.com/storybookjs/storybook/pull/11076))\n- Controls: Fix enum extraction for react-docgen-typescript ([#11070](https://github.com/storybookjs/storybook/pull/11070))\n\n### Maintenance\n\n- Core: Zero-config Typescript e2e test ([#10843](https://github.com/storybookjs/storybook/pull/10843))\n\n## 6.0.0-beta.22 (June 6, 2020)\n\n### Features\n\n- Addon-controls: Add hideNoControlsWarning parameter ([#11035](https://github.com/storybookjs/storybook/pull/11035))\n\n### Bug Fixes\n\n- Controls: Fix null entry in options array handling ([#11048](https://github.com/storybookjs/storybook/pull/11048))\n- Ember: Return early when there's no JSDoc for a component ([#10490](https://github.com/storybookjs/storybook/pull/10490))\n- Ember: Fix double render ([#10971](https://github.com/storybookjs/storybook/pull/10971))\n- UI: Fix focus not showing up on buttons ([#10944](https://github.com/storybookjs/storybook/pull/10944))\n- Composition: Fix bad package.json resolve ([#11023](https://github.com/storybookjs/storybook/pull/11023))\n- Core: Fix Yarn 2 compatibility & E2E test ([#11008](https://github.com/storybookjs/storybook/pull/11008))\n\n### Maintenance\n\n- Aurelia: Fix issue with auto generated knobs for elements ([#10853](https://github.com/storybookjs/storybook/pull/10853))\n- Build: Upgrade cypress && FIX lodash dependency ([#10925](https://github.com/storybookjs/storybook/pull/10925))\n\n### Dependency Upgrades\n\n- build(deps-dev): bump ember-source from 3.17.3 to 3.19.0 ([#11043](https://github.com/storybookjs/storybook/pull/11043))\n- Bump rimraf from 2.7.1 to 3.0.2 ([#10923](https://github.com/storybookjs/storybook/pull/10923))\n- build(deps-dev): bump ts-jest from 25.5.1 to 26.1.0 ([#11042](https://github.com/storybookjs/storybook/pull/11042))\n- Update react-textarea-autosize & Remove @types/react-textarea-autosize ([#11040](https://github.com/storybookjs/storybook/pull/11040))\n- Bump pug from 2.0.4 to 3.0.0 ([#10920](https://github.com/storybookjs/storybook/pull/10920))\n- build(deps): bump @types/node from 13.13.9 to 14.0.10 ([#11039](https://github.com/storybookjs/storybook/pull/11039))\n- Bump vue-docgen-api from 4.23.1 to 4.24.0 ([#11017](https://github.com/storybookjs/storybook/pull/11017))\n- Bump @babel/preset-flow from 7.9.0 to 7.10.1 ([#11018](https://github.com/storybookjs/storybook/pull/11018))\n\n## 6.0.0-beta.21 (June 4, 2020)\n\n### Breaking Changes\n\n- Preact: Update Preact version ([#10978](https://github.com/storybookjs/storybook/pull/10978))\n\n### Features\n\n- Addon-docs: Angular ArgTypes for pipes, injectables, classes ([#11016](https://github.com/storybookjs/storybook/pull/11016))\n- TypeScript: Add warning for setup issues and fix Babel config ([#10998](https://github.com/storybookjs/storybook/pull/10998))\n- Core: Add logLevel preset property to filter logging ([#10370](https://github.com/storybookjs/storybook/pull/10370))\n\n### Bug Fixes\n\n- Addon-controls: Fix initialization logic; remove react-select ([#11024](https://github.com/storybookjs/storybook/pull/11024))\n- CLI: Fix `sb init` in Yarn workspace environment ([#10985](https://github.com/storybookjs/storybook/pull/10985))\n\n### Maintenance\n\n- React: Remove argsStory helper function ([#11036](https://github.com/storybookjs/storybook/pull/11036))\n- Addon-controls: Remove residual options-type controls ([#11015](https://github.com/storybookjs/storybook/pull/11015))\n\n## 6.0.0-beta.20 (June 1, 2020)\n\n### Bug Fixes\n\n- Addon-controls: Fix `options` control types ([#11003](https://github.com/storybookjs/storybook/pull/11003))\n- Addon-controls: Fix no-control handling ([#11001](https://github.com/storybookjs/storybook/pull/11001))\n- Addon-docs: Fix function argType inference in react-docgen-typescript ([#10997](https://github.com/storybookjs/storybook/pull/10997))\n\n### Maintenance\n\n- Addon-controls/a11y: Fix PARAM_KEY export for consistency ([#10988](https://github.com/storybookjs/storybook/pull/10988))\n\n## 6.0.0-beta.19 (May 30, 2020)\n\n### Features\n\n- Addon-controls: Add warning to controls tab on no-args story ([#10986](https://github.com/storybookjs/storybook/pull/10986))\n\n### Bug Fixes\n\n- Addon-docs: Handle JSON.parse exception for Angular union types ([#10984](https://github.com/storybookjs/storybook/pull/10984))\n\n## 6.0.0-beta.18 (May 29, 2020)\n\n### Bug Fixes\n\n- Core: Fix HMR for navigation sidebar in UI ([#10981](https://github.com/storybookjs/storybook/pull/10981))\n- Core: Fix `register.tsx` as manager code in preset heuristic ([#10980](https://github.com/storybookjs/storybook/pull/10980))\n- Core: Send global args with set stories ([#10910](https://github.com/storybookjs/storybook/pull/10910))\n- Core: Log swallowed errors when requiring stories ([#10974](https://github.com/storybookjs/storybook/pull/10974))\n- Core: Support valid globs ([#10926](https://github.com/storybookjs/storybook/pull/10926))\n\n## 6.0.0-beta.17 (May 28, 2020)\n\n### Features\n\n- Addon-controls: Angular support ([#10946](https://github.com/storybookjs/storybook/pull/10946))\n- Addon-controls: Web-components support ([#10953](https://github.com/storybookjs/storybook/pull/10953))\n\n## 6.0.0-beta.16 (May 28, 2020)\n\n### Bug Fixes\n\n- Core: Add missing babel plugin ([#10941](https://github.com/storybookjs/storybook/pull/10941))\n\n### Maintenance\n\n- CI: Stabilize E2E tests ([#10888](https://github.com/storybookjs/storybook/pull/10888))\n\n## 6.0.0-beta.15 (May 27, 2020)\n\n### Features\n\n- Addon-Controls: Next-generation knobs ([#10834](https://github.com/storybookjs/storybook/pull/10834))\n\n### Bug Fixes\n\n- Core: Avoid re-render on HMR of other stories ([#10908](https://github.com/storybookjs/storybook/pull/10908))\n- Core: Fix auth for refs ([#10845](https://github.com/storybookjs/storybook/pull/10845))\n\n### Dependency Upgrades\n\n- Bump react-syntax-highlighter from 11.0.2 to 12.2.1 ([#10919](https://github.com/storybookjs/storybook/pull/10919))\n\n## 6.0.0-beta.14 (May 25, 2020)\n\n### Breaking Changes\n\n- CSF: Hoist story annotation object ([#10907](https://github.com/storybookjs/storybook/pull/10907))\n- Vue: Remove babel-preset-vue ([#10909](https://github.com/storybookjs/storybook/pull/10909))\n\n### Features\n\n- Angular: Support `workspace.json` in nx workspace ([#10881](https://github.com/storybookjs/storybook/pull/10881))\n\n### Bug Fixes\n\n- Addon-docs: Fix single item width in Preview block ([#10877](https://github.com/storybookjs/storybook/pull/10877))\n- UI: Center toolbar icon buttons ([#10897](https://github.com/storybookjs/storybook/pull/10897))\n- Core: Fix double rendering on startup ([#10892](https://github.com/storybookjs/storybook/pull/10892))\n\n### Maintenance\n\n- Core: Use dedicated loader for es6 modules ([#10783](https://github.com/storybookjs/storybook/pull/10783))\n- Core: Fix yarn test command on windows ([#10904](https://github.com/storybookjs/storybook/pull/10904))\n\n## 5.3.19 (May 24, 2020)\n\n### Bug Fixes\n\n- UI: Fix search stories ([#10539](https://github.com/storybookjs/storybook/pull/10539))\n\n### Security\n\n- Upgrade markdown-to-jsx to 6.11.4 ([#10873](https://github.com/storybookjs/storybook/pull/10873))\n\n## 6.0.0-beta.13 (May 23, 2020)\n\n### Bug Fixes\n\n- Core: Fix ts/tsx resolution in the manager ([#10886](https://github.com/storybookjs/storybook/pull/10886))\n- Core: Fix typo in projectRoot node_modules detection ([#10848](https://github.com/storybookjs/storybook/pull/10848))\n- Addon-docs: Fix story inline rendering ([#10875](https://github.com/storybookjs/storybook/pull/10875))\n- Core: Fix CRA filter for built-in webpack settings ([#10861](https://github.com/storybookjs/storybook/pull/10861))\n- Addon-docs: Fix react forwardRefs with destructured props ([#10864](https://github.com/storybookjs/storybook/pull/10864))\n\n### Maintenance\n\n- React: Upgrade preset-create-react-app in examples ([#10867](https://github.com/storybookjs/storybook/pull/10867))\n- Core: Close server when e2e test failed ([#10868](https://github.com/storybookjs/storybook/pull/10868))\n\n### Dependency Upgrades\n\n- Upgrade markdown-to-jsx to 6.11.4 ([#10873](https://github.com/storybookjs/storybook/pull/10873))\n\n## 6.0.0-beta.12 (May 21, 2020)\n\n### Breaking Changes\n\n- Core: Zero-config TypeScript loading ([#10813](https://github.com/storybookjs/storybook/pull/10813))\n\n## 6.0.0-beta.11 (May 21, 2020)\n\nFailed publish\n\n## 6.0.0-beta.10 (May 21, 2020)\n\nFailed publish\n\n## 6.0.0-beta.9 (May 21, 2020)\n\n### Bug Fixes\n\n- UI: Avoid full refresh when on some tab changes ([#10838](https://github.com/storybookjs/storybook/pull/10838))\n- Composition: Fix refs not authenticating ([#10819](https://github.com/storybookjs/storybook/pull/10819))\n- Core: Fix global args initial state for addon-toolbars ([#10833](https://github.com/storybookjs/storybook/pull/10833))\n- Addon-a11y: Add deprecated withA11y ([#10814](https://github.com/storybookjs/storybook/pull/10814))\n- Core: Transpile minimum node_modules ([#10725](https://github.com/storybookjs/storybook/pull/10725))\n- UI: Change default view to Canvas on mobile ([#10818](https://github.com/storybookjs/storybook/pull/10818))\n- Docs: Improve Preview zoom handling ([#10801](https://github.com/storybookjs/storybook/pull/10801))\n\n### Maintenance\n\n- CI: example overhaul clean ([#10702](https://github.com/storybookjs/storybook/pull/10702))\n- CLI: Migrate CLI to TypeScript ([#10802](https://github.com/storybookjs/storybook/pull/10802))\n\n### Dependency Upgrades\n\n- Upgrade and add some missing dependencies in core, router, api ([#10825](https://github.com/storybookjs/storybook/pull/10825))\n\n## 6.0.0-beta.8 (May 17, 2020)\n\n### Features\n\n- Addon-toolbars: Show tool icons for all viewModes ([#10810](https://github.com/storybookjs/storybook/pull/10810))\n\n### Bug Fixes\n\n- Addon-docs: Eval argTypes default value ([#10812](https://github.com/storybookjs/storybook/pull/10812))\n\n### Maintenance\n\n- Scripts: parallel execution on build package scripts ([#10808](https://github.com/storybookjs/storybook/pull/10808))\n\n## 6.0.0-beta.7 (May 15, 2020)\n\n### Breaking changes\n\n- Cleanup: Remove support for babel-loader < 8 ([#10781](https://github.com/storybookjs/storybook/pull/10781))\n\n### Features\n\n- Composition: Zero-config composition from dependencies ([#10753](https://github.com/storybookjs/storybook/pull/10753))\n\n### Bug Fixes\n\n- Core: Detect local addons for windows machine ([#10786](https://github.com/storybookjs/storybook/pull/10786))\n- Composition: Rename `mapper` to `storyMapper` and fix loading bugs ([#10780](https://github.com/storybookjs/storybook/pull/10780))\n\n### Maintenance\n\n- CLI: HTML stories homogenization ([#10705](https://github.com/storybookjs/storybook/pull/10705))\n- CLI: web-components stories homogenization ([#10703](https://github.com/storybookjs/storybook/pull/10703))\n\n### Dependency Upgrades\n\n- Update jest-preset-angular to 8.2.0 ([#10778](https://github.com/storybookjs/storybook/pull/10778))\n\n## 6.0.0-beta.6 (May 12, 2020)\n\n### Breaking Changes\n\n- Essentials: Update configuration heuristics for main.js ([#10737](https://github.com/storybookjs/storybook/pull/10737))\n\n### Features\n\n- Essentials: Add addon-actions ([#10748](https://github.com/storybookjs/storybook/pull/10748))\n- Essentials: Add addon-docs ([#10729](https://github.com/storybookjs/storybook/pull/10729))\n\n### Bug Fixes\n\n- UI: Reset layout properties when switching stories ([#10643](https://github.com/storybookjs/storybook/pull/10643))\n\n### Maintenance\n\n- CLI: react stories homogenization ([#10711](https://github.com/storybookjs/storybook/pull/10711))\n- CLI: vue stories homogenization ([#10708](https://github.com/storybookjs/storybook/pull/10708))\n- CLI: webpack react stories homogenization ([#10709](https://github.com/storybookjs/storybook/pull/10709))\n- CLI: svelte stories homogenization ([#10704](https://github.com/storybookjs/storybook/pull/10704))\n- CLI: react-scripts stories homogenization ([#10710](https://github.com/storybookjs/storybook/pull/10710))\n- CLI: mithril stories homogenization ([#10707](https://github.com/storybookjs/storybook/pull/10707))\n- CLI: rax stories homogenization ([#10706](https://github.com/storybookjs/storybook/pull/10706))\n- CLI: riot stories homogenization ([#10715](https://github.com/storybookjs/storybook/pull/10715))\n- CLI: ember stories homogenization ([#10713](https://github.com/storybookjs/storybook/pull/10713))\n- CLI: preact stories homogenization ([#10712](https://github.com/storybookjs/storybook/pull/10712))\n- CLI: sfc_vue stories homogenization ([#10714](https://github.com/storybookjs/storybook/pull/10714))\n\n### Dependency Upgrades\n\n- Revert \"Change reference for jest-preset-angular/build/setupJest as per migration guide\" ([#10727](https://github.com/storybookjs/storybook/pull/10727))\n\n## 6.0.0-beta.5 (May 11, 2020)\n\n### Bug Fixes\n\n- Core: Fix error handling on load ([#10659](https://github.com/storybookjs/storybook/pull/10659))\n\n### Maintenance\n\n- Storyshots: Change reference for jest-preset-angular/build/setupJest ([#10699](https://github.com/storybookjs/storybook/pull/10699))\n- CLI: Remove CRA fixtures from Yarn 2 tests run ([#10720](https://github.com/storybookjs/storybook/pull/10720))\n- Fix: Set private package on Aurelia example ([#10688](https://github.com/storybookjs/storybook/pull/10688))\n\n## 6.0.0-beta.4 (May 8, 2020)\n\n### Features\n\n- React: Add `argsStory` convenience function ([#10685](https://github.com/storybookjs/storybook/pull/10685))\n\n### Dependency Upgrades\n\n- Build: Upgrade jest to 26 ([#10669](https://github.com/storybookjs/storybook/pull/10669))\n\n## 6.0.0-beta.3 (May 7, 2020)\n\n### Breaking Changes\n\n- Addon-backgrounds: Simplified parameters API ([#10634](https://github.com/storybookjs/storybook/pull/10634))\n\n### Bug Fixes\n\n- Core: Fix `globalArgs` initialization from global parameters ([#10566](https://github.com/storybookjs/storybook/pull/10566))\n- Core: Fix DLL context for IE11 ([#106444]https://github.com/storybookjs/storybook/pull/10644))\n\n### Dependency Upgrades\n\n- Addon-storyshots: Upgrade to jest 26 ([#10642](https://github.com/storybookjs/storybook/pull/10642))\n- Bump terser-webpack-plugin from 2.3.6 to 3.0.0 ([#10650](https://github.com/storybookjs/storybook/pull/10650))\n\n## 6.0.0-beta.2 (May 4, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Fix broken props logic for no-args stories ([#10633](https://github.com/storybookjs/storybook/pull/10633))\n- Addon-docs: Fix custom source manual override ([#10632](https://github.com/storybookjs/storybook/pull/10632))\n- Addon-docs: Fix MDX stories with multiple children ([#9531](https://github.com/storybookjs/storybook/pull/9531))\n- Addon-docs: Fix object array in Props ([#10621](https://github.com/storybookjs/storybook/pull/10621))\n- Actions: Fix import of `uuid` ([#10625](https://github.com/storybookjs/storybook/pull/10625))\n\n### Maintenance\n\n- Core: Fix Args test to not use different code path ([#10607](https://github.com/storybookjs/storybook/pull/10607))\n\n## 6.0.0-beta.1 (May 2, 2020)\n\n### Features\n\n- CLI: Add automatic detection for svelte ([#10623](https://github.com/storybookjs/storybook/pull/10623))\n\n### Bug Fixes\n\n- Addon-docs: Fix no-props logic in Source block ([#10619](https://github.com/storybookjs/storybook/pull/10619))\n- Props: Fix subcomponents ([#10608](https://github.com/storybookjs/storybook/pull/10608))\n\n### Maintenance\n\n- Yarn 2: Fix dependencies issues for compatibility ([#10613](https://github.com/storybookjs/storybook/pull/10613))\n- CLI: Fix cli when working with Yarn 2 and Node 10 ([#10550](https://github.com/storybookjs/storybook/pull/10550))\n\n## 6.0.0-beta.0 (April 29, 2020)\n\nStorybook 6.0 is in beta. 🎉🎉🎉\n\nHundreds of improvements and fixes, including:\n\n- **Args** - Dynamic story data with automatic prop controls and actions.\n- **Composition** - Compose storybooks for better documentation, performance, and multi-framework support.\n- **Server** - Enabling Storybook for Rails and other server-side components.\n- **Yarn 2** - Supporting next generation package management.\n\nTrack the release in the Github: [Storybook 6.0 Release 🏆](https://github.com/storybookjs/storybook/issues/9311)\n\n## 6.0.0-alpha.46 (April 29, 2020)\n\n### Breaking Changes\n\n- Core: Normalize parameters in store/channel ([#10373](https://github.com/storybookjs/storybook/pull/10373))\n- React: Remove deprecated CRA preset ([#10571](https://github.com/storybookjs/storybook/pull/10571))\n\n### Features\n\n- Addon-docs: Props controls for Vue ([#10559](https://github.com/storybookjs/storybook/pull/10559))\n\n### Bug Fixes\n\n- Addon-docs: Add subcomponents prop to Meta block ([#10573](https://github.com/storybookjs/storybook/pull/10573))\n\n## 6.0.0-alpha.45 (April 28, 2020)\n\n## Breaking changes\n\n- Core: Pass args first to stories by default ([#10452](https://github.com/storybookjs/storybook/pull/10452))\n\n## 6.0.0-alpha.44 (April 27, 2020)\n\n### Features\n\n- CLI: Automatically detect typescript in `sb init` ([#10547](https://github.com/storybookjs/storybook/pull/10547))\n\n### Bug Fixes\n\n- UI: Fix `viewMode` parameter handling ([#10292](https://github.com/storybookjs/storybook/pull/10292))\n\n## 6.0.0-alpha.43 (April 24, 2020)\n\n### Features\n\n- Addon-a11y: Use channel to highlight elements in preview ([#10456](https://github.com/storybookjs/storybook/pull/10456))\n- Storyshots: Support react hooks ([#10529](https://github.com/storybookjs/storybook/pull/10529))\n\n### Bug Fixes\n\n- Core: Transform for/of in dlls for IE11 compatibility ([#10471](https://github.com/storybookjs/storybook/pull/10471))\n\n### Maintenance\n\n- Addon-contexts: Move to deprecated-addons repo ([#10479](https://github.com/storybookjs/storybook/pull/10479))\n\n## 6.0.0-alpha.42 (April 23, 2020)\n\n### Bug Fixes\n\n- Build: Fix misc warnings that trip up Chromatic ([#10521](https://github.com/storybookjs/storybook/pull/10521))\n- Composition: Update UI for refs ([#10504](https://github.com/storybookjs/storybook/pull/10504))\n\n### Maintenance\n\n- Addon-docs: Rename `formatSource` to `transformSource` ([#10503](https://github.com/storybookjs/storybook/pull/10503))\n\n## 6.0.0-alpha.41 (April 21, 2020)\n\n### Features\n\n- Addon-docs: Reset styles in Preview component ([#10274](https://github.com/storybookjs/storybook/pull/10274))\n\n### Bug Fixes\n\n- Addon-docs: Port Vue to ArgsTable ([#10482](https://github.com/storybookjs/storybook/pull/10482))\n- Addon-docs: Fix Props controls to point to primary story ([#10480](https://github.com/storybookjs/storybook/pull/10480))\n- Core: Fix addon tab in react-native-server ([#10468](https://github.com/storybookjs/storybook/pull/10468))\n\n### Dependency Upgrades\n\n- Misc upgrades ([#10460](https://github.com/storybookjs/storybook/pull/10460))\n\n## 6.0.0-alpha.40 (April 20, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Fix controls column display logic ([#10473](https://github.com/storybookjs/storybook/pull/10473))\n\n## 6.0.0-alpha.39 (April 18, 2020)\n\n### Breaking Changes\n\n- Addon-docs: Inline stories in Vue by default ([#10463](https://github.com/storybookjs/storybook/pull/10463))\n\n### Features\n\n- Addon-docs: Provide better props include/exclude features ([#10464](https://github.com/storybookjs/storybook/pull/10464))\n- UI: Improve loading state ([#10444](https://github.com/storybookjs/storybook/pull/10444))\n\n### Bug Fixes\n\n- UI: Fix bad shortcutpage layout ([#10445](https://github.com/storybookjs/storybook/pull/10445))\n\n## 6.0.0-alpha.38 (April 18, 2020)\n\nFailed publish\n\n## 6.0.0-alpha.37 (April 17, 2020)\n\n### Features\n\n- Addon-actions: Make arg auto-generation more aggressive ([#10451](https://github.com/storybookjs/storybook/pull/10451))\n\n### Maintenance\n\n- Examples: Format stringified parameters ([#10435](https://github.com/storybookjs/storybook/pull/10435))\n\n### Dependency Upgrades\n\n- Bump recast from 0.16.2 to 0.19.0 ([#10415](https://github.com/storybookjs/storybook/pull/10415))\n\n## 6.0.0-alpha.36 (April 16, 2020)\n\n### Bug Fixes\n\n- Server: Fix serialization of knobs params back to server ([#10391](https://github.com/storybookjs/storybook/pull/10391))\n- Core: Serve correctly hashed static files with the Cache-Control header ([#10390](https://github.com/storybookjs/storybook/pull/10390))\n- Addon-a11y: Fix default a11y parameters ([#10439](https://github.com/storybookjs/storybook/pull/10439))\n- Core: Fix event source handling ([#10416](https://github.com/storybookjs/storybook/pull/10416))\n\n### Maintenance\n\n- Addon-docs: Add blocks typings ([#10441](https://github.com/storybookjs/storybook/pull/10441))\n\n## 6.0.0-alpha.35 (April 16, 2020)\n\n### Bug Fixes\n\n- Core: Fix static build with DLL ([#10377](https://github.com/storybookjs/storybook/pull/10377))\n- Addon-Docs: Fix Args table generation for story with no component ([#10436](https://github.com/storybookjs/storybook/pull/10436))\n\n### Maintenance\n\n- Yarn 2: Fix compatibility with `.storybook/preview.js` file ([#10342](https://github.com/storybookjs/storybook/pull/10342))\n- Official-storybook: Fix passArgsFirst problems ([#10432](https://github.com/storybookjs/storybook/pull/10432))\n\n## 6.0.0-alpha.34 (April 15, 2020)\n\n### Breaking Changes\n\n- Addon-A11y: Remove decorator in favor of parameter configuration ([#10381](https://github.com/storybookjs/storybook/pull/10381))\n\n### Features\n\n- Addon-docs: Add controls to ArgsTable ([#10354](https://github.com/storybookjs/storybook/pull/10354))\n- CLI: Reuse existing chromium tab if possible ([#10329](https://github.com/storybookjs/storybook/pull/10329))\n\n### Bug Fixes\n\n- Core: Fix main.js `stories` regex to glob conversion ([#10400](https://github.com/storybookjs/storybook/pull/10400))\n- Composition: Fix ref getSourceType for URL paths with index.html ([#10421](https://github.com/storybookjs/storybook/pull/10421))\n- Core: Add .cjs files for main.js config ([#10358](https://github.com/storybookjs/storybook/pull/10358))\n\n### Dependency Upgrades\n\n- Bump @types/react-select from 2.0.19 to 3.0.11 ([#10262](https://github.com/storybookjs/storybook/pull/10262))\n- Bump strip-json-comments from 3.0.1 to 3.1.0 ([#10334](https://github.com/storybookjs/storybook/pull/10334))\n- Bump axe version to 3.5.3 ([#10375](https://github.com/storybookjs/storybook/pull/10375))\n- Bump markdown-to-jsx from 6.11.0 to 6.11.1 ([#10331](https://github.com/storybookjs/storybook/pull/10331))\n- Bump semver from 7.1.3 to 7.2.2 ([#10385](https://github.com/storybookjs/storybook/pull/10385))\n\n## 6.0.0-alpha.33 (April 14, 2020)\n\n### Breaking prerelease\n\n- Core: Rename ParameterEnhancer to ArgsEnhancer ([#10398](https://github.com/storybookjs/storybook/pull/10398))\n\n### Bug Fixes\n\n- Core: Fix `webpackFinal` being called twice ([#10402](https://github.com/storybookjs/storybook/pull/10402))\n- Core: Fix legacy redirect ([#10404](https://github.com/storybookjs/storybook/pull/10404))\n\n### Maintenance\n\n- CLI: Update fixtures used for CLI tests ([#10396](https://github.com/storybookjs/storybook/pull/10396))\n- Build: Update bootstrap to install optional deps on CI ([#10408](https://github.com/storybookjs/storybook/pull/10408))\n- Addon-docs: Format source at render time ([#10383](https://github.com/storybookjs/storybook/pull/10383))\n\n## 6.0.0-alpha.32 (April 11, 2020)\n\n### Features\n\n- CSF: Warn when there are no exported stories ([#10357](https://github.com/storybookjs/storybook/pull/10357))\n\n### Bug Fixes\n\n- Marko: Always destroy old component when switching stories ([#10345](https://github.com/storybookjs/storybook/pull/10345))\n\n### Maintenance\n\n- Dev: Build script for package development ([#10343](https://github.com/storybookjs/storybook/pull/10343))\n\n## 6.0.0-alpha.31 (April 7, 2020)\n\n### Bug Fixes\n\n- Core: Fix ie11 compatibility ([#10281](https://github.com/storybookjs/storybook/pull/10281))\n- Core: Add .cjs & .mjs to interpret-files ([#10288](https://github.com/storybookjs/storybook/pull/10288))\n- Core: Fix source-map strategy for production ([#10290](https://github.com/storybookjs/storybook/pull/10290))\n- Addon-knobs: Allow `text` and `number` to take undefined values ([#10101](https://github.com/storybookjs/storybook/pull/10101))\n\n### Maintenance\n\n- Core: Warn about deprecated config files ([#10097](https://github.com/storybookjs/storybook/pull/10097))\n- Yarn 2: rework imports in webpack preview virtual module to fix compatibility ([#10305](https://github.com/storybookjs/storybook/pull/10305))\n- Addon-centered: Move to deprecated-addons ([#10300](https://github.com/storybookjs/storybook/pull/10300))\n\n## 5.3.18 (March 31, 2020)\n\n### Bug Fixes\n\n- Core: Fix manager assets to be routed in express ([#9646](https://github.com/storybookjs/storybook/pull/9646))\n- Storyshots: Fix MDX transform ([#10223](https://github.com/storybookjs/storybook/pull/10223))\n- Addon-docs: Restore IE11 compat on Windows by transpiling acorn-jsx ([#9790](https://github.com/storybookjs/storybook/pull/9790))\n- Addon-docs: Ensure visibility of links within prop descriptions ([#10210](https://github.com/storybookjs/storybook/pull/10210))\n\n## 6.0.0-alpha.30 (March 31, 2020)\n\n### Breaking Changes\n\n- Misc: remove deprecations for 6.0.0 ([#10216](https://github.com/storybookjs/storybook/pull/10216))\n- DocsPage: Remove slots for 6.0 ([#10259](https://github.com/storybookjs/storybook/pull/10259))\n- Addon-actions: Add preset and configure with parameters ([#9933](https://github.com/storybookjs/storybook/pull/9933))\n\n### Features\n\n- MDX: Add args/argTypes/component/subcomponents support ([#10258](https://github.com/storybookjs/storybook/pull/10258))\n- Addon-docs: Add linear gradient support to ColorPalette block ([#10237](https://github.com/storybookjs/storybook/pull/10237))\n\n### Bug Fixes\n\n- Addon-a11y: Performance fix ([#10219](https://github.com/storybookjs/storybook/pull/10219))\n- API: Fix local addon handling ([#10254](https://github.com/storybookjs/storybook/pull/10254))\n- Core: Fix URL load failure due to missing base ([#10228](https://github.com/storybookjs/storybook/pull/10228))\n- Storyshots: Fix MDX transform ([#10223](https://github.com/storybookjs/storybook/pull/10223))\n\n### Maintenance\n\n- Build: Add puppeteer libs so teamcity can build examples ([#10235](https://github.com/storybookjs/storybook/pull/10235))\n\n### Dependency Upgrades\n\n- Misc upgrades ([#10236](https://github.com/storybookjs/storybook/pull/10236))\n\n## 6.0.0-alpha.29 (March 26, 2020)\n\n### Features\n\n- Core: Composition - load remote storybooks ([#9210](https://github.com/storybookjs/storybook/pull/9210))\n- CLI: extract-storybook bin ([#10146](https://github.com/storybookjs/storybook/pull/10146))\n\n### Bug Fixes\n\n- Addon-docs: Ensure visibility of links within prop descriptions ([#10210](https://github.com/storybookjs/storybook/pull/10210))\n\n### Maintenance\n\n- Core: Remove useStoryState ([#10187](https://github.com/storybookjs/storybook/pull/10187))\n- Addon-jest: Title case panel name ([#10161](https://github.com/storybookjs/storybook/pull/10161))\n\n### Dependency Upgrades\n\n- Bump semver from 6.3.0 to 7.1.3 ([#9864](https://github.com/storybookjs/storybook/pull/9864))\n- Bump @types/jest from 25.1.3 to 25.1.4 ([#10133](https://github.com/storybookjs/storybook/pull/10133))\n\n## 6.0.0-alpha.28 (March 23, 2020)\n\n### Features\n\n- UI: Form/textarea maxHeight : 400 ([#9860](https://github.com/storybookjs/storybook/pull/9860))\n\n### Bug Fixes\n\n- Addon-docs: Make source resilient to bad story ID's ([#10184](https://github.com/storybookjs/storybook/pull/10184))\n- Core: Don't persist theme to localStorage ([#9076](https://github.com/storybookjs/storybook/pull/9076))\n- Core: Fix to load Storybook in IE11 ([#9942](https://github.com/storybookjs/storybook/pull/9942))\n\n### Maintenance\n\n- Server: Simplify server addons ([#9931](https://github.com/storybookjs/storybook/pull/9931))\n- Core: FIX error of load order when using configure in preview|config.js ([#10159](https://github.com/storybookjs/storybook/pull/10159))\n- Build: Experiment to make CircleCI tests a faster and more stable ([#9969](https://github.com/storybookjs/storybook/pull/9969))\n- Vue: Fix webpack config when execute 'yarn workspace vue-example dev' ([#9704](https://github.com/storybookjs/storybook/pull/9704))\n- Core: Re-enable failing args tests ([#10126](https://github.com/storybookjs/storybook/pull/10126))\n- Build: Add script & parallelization for running chromatic on examples ([#10125](https://github.com/storybookjs/storybook/pull/10125))\n\n### Dependency Upgrades\n\n- Addon-a11y: Move react to peer dependency ([#9957](https://github.com/storybookjs/storybook/pull/9957))\n\n## 5.3.17 (March 14, 2020)\n\n### Bug Fixes\n\n- Components: Change react-syntax-highlighter from esm to cjs ([#9780](https://github.com/storybookjs/storybook/pull/9780))\n\n## 5.3.16 (March 14, 2020)\n\nFailed NPM publish\n\n## 5.3.15 (March 14, 2020)\n\n### Bug Fixes\n\n- Core: Disables html-webpack-plugin's option to remove script tag types ([#10042](https://github.com/storybookjs/storybook/pull/10042))\n- Addon-actions: Style ActionLogger to preserve whitespace ([#10046](https://github.com/storybookjs/storybook/pull/10046))\n\n### Maintenance\n\n- CI: Fix GitHub unit test workflow ([#9971](https://github.com/storybookjs/storybook/pull/9971))\n\n### Dependency Upgrades\n\n- Security: Remove usage of a vulnerable version of serialize-javascript ([#10071](https://github.com/storybookjs/storybook/pull/10071))\n\n## 6.0.0-alpha.27 (March 13, 2020)\n\n### Features\n\n- Addon-toolbars: Global args support in the toolbar ([#10028](https://github.com/storybookjs/storybook/pull/10028))\n- Addon-actions: Add Storybook Args support ([#10029](https://github.com/storybookjs/storybook/pull/10029))\n- Core: Add globalArgs/globalArgTypes `preview.js` exports ([#10123](https://github.com/storybookjs/storybook/pull/10123))\n\n## 6.0.0-alpha.26 (March 12, 2020)\n\n### Breaking Changes\n\n- Remove deprecated decorators and loaders ([#9951](https://github.com/storybookjs/storybook/pull/9951))\n\n### Features\n\n- Core: Improve support for main.ts/preview.ts files ([#10099](https://github.com/storybookjs/storybook/pull/10099))\n- Addon-docs: Theme with `docs.theme` parameter ([#10114](https://github.com/storybookjs/storybook/pull/10114))\n- Addon-docs: Svelte example ([#7673](https://github.com/storybookjs/storybook/pull/7673))\n\n### Maintenance\n\n- CSF: Promote args/argTypes to first-class metadata ([#10117](https://github.com/storybookjs/storybook/pull/10117))\n\n## 6.0.0-alpha.25 (March 11, 2020)\n\nNOTE: `6.0.0-alpha.24` broken due to bad merge. Sorry!\n\n### Bug Fixes\n\n- Core: Fix initialization of global args ([#10106](https://github.com/storybookjs/storybook/pull/10106))\n\n## 6.0.0-alpha.24 (March 11, 2020)\n\n### Features\n\n- Addon-docs: formatSource snippet customization function ([#10089](https://github.com/storybookjs/storybook/pull/10089))\n- Core: Add global args feature ([#10015](https://github.com/storybookjs/storybook/pull/10015))\n- UI: Migrate from simplebar to overlaybars ([#9375](https://github.com/storybookjs/storybook/pull/9375))\n\n### Bug Fixes\n\n- Core: Fix StoryInput parameters typings ([#10013](https://github.com/storybookjs/storybook/pull/10013))\n- Changed import of react-syntax-highlighter from esm to cjs ([#9292](https://github.com/storybookjs/storybook/pull/9292))\n\n### Maintenance\n\n- Build: Setup TeamCity Cloud ([#9875](https://github.com/storybookjs/storybook/pull/9875))\n- Tech/improvements ([#10096](https://github.com/storybookjs/storybook/pull/10096))\n- Core: Move event handlers into module init ([#10085](https://github.com/storybookjs/storybook/pull/10085))\n\n### Dependency Upgrades\n\n- Bump axe-core from 3.5.1 to 3.5.2 ([#10090](https://github.com/storybookjs/storybook/pull/10090))\n\n## 6.0.0-alpha.23 (March 11, 2020)\n\nFailed publish\n\n## 6.0.0-alpha.22 (March 10, 2020)\n\n### Breaking Changes\n\n- MDX: Compile to improved source-loader format ([#10084](https://github.com/storybookjs/storybook/pull/10084))\n\n### Features\n\n- Core: Add args feature ([#10014](https://github.com/storybookjs/storybook/pull/10014))\n\n### Maintenance\n\n- Tech/improvements ([#10083](https://github.com/storybookjs/storybook/pull/10083))\n- Few minor improvements extracted from the inception feature PR ([#10072](https://github.com/storybookjs/storybook/pull/10072))\n- Tech/improvements ([#10070](https://github.com/storybookjs/storybook/pull/10070))\n\n### Dependency Upgrades\n\n- Yarn 2: Add missing dependencies ([#10012](https://github.com/storybookjs/storybook/pull/10012))\n- Security: Remove usage of a vulnerable version of serialize-javascript ([#10071](https://github.com/storybookjs/storybook/pull/10071))\n\n## 6.0.0-alpha.21 (March 5, 2020)\n\n### Breaking Changes\n\n- Core: Overhaul start.js and event emitting/listening ([#9914](https://github.com/storybookjs/storybook/pull/9914))\n\n### Features\n\n- CLI: Support js / jsx / ts / tsx stories in React CSF template ([#10003](https://github.com/storybookjs/storybook/pull/10003))\n- Cra-kitchen-sink : Add Named Color Palette Example(MDX) ([#9709](https://github.com/storybookjs/storybook/pull/9709))\n- Addon-Queryparams: Add addon preset ([#9949](https://github.com/storybookjs/storybook/pull/9949))\n\n### Bug Fixes\n\n- Addon-actions: Style ActionLogger to preserve whitespace ([#10046](https://github.com/storybookjs/storybook/pull/10046))\n- Core: Disables html-webpack-plugin's option to remove script tag types ([#10042](https://github.com/storybookjs/storybook/pull/10042))\n\n### Maintenance\n\n- Tech: Misc improvements ([#10052](https://github.com/storybookjs/storybook/pull/10052))\n- Tech: Misc improvements extracted from composition ([#10040](https://github.com/storybookjs/storybook/pull/10040))\n- CI: change parallelism ([#10041](https://github.com/storybookjs/storybook/pull/10041))\n- Storybook-official: try moving options to `manager.js` ([#9323](https://github.com/storybookjs/storybook/pull/9323))\n- Misc: Add missing dependencies ([#9965](https://github.com/storybookjs/storybook/pull/9965))\n- CI: Fix GitHub unit test workflow ([#9971](https://github.com/storybookjs/storybook/pull/9971))\n\n### Dependency Upgrades\n\n- Upgrade reach router ([#10016](https://github.com/storybookjs/storybook/pull/10016))\n\n## 6.0.0-alpha.20 (February 27, 2020)\n\n### Bug Fixes\n\n- Core: Fix `configFilename` containing backticks ([#9960](https://github.com/storybookjs/storybook/pull/9960))\n\n### Maintenance\n\n- Core: Add stories to demonstrate `layout` ([#9940](https://github.com/storybookjs/storybook/pull/9940))\n\n## 5.3.14 (February 25, 2020)\n\n### Bug Fixes\n\n- Centered: remove `typesVersions` attribute ([#9907](https://github.com/storybookjs/storybook/pull/9907))\n- Props: Fix typescript unspecified default value ([#9873](https://github.com/storybookjs/storybook/pull/9873))\n- Core: Use telejson for websockets channel ([#9867](https://github.com/storybookjs/storybook/pull/9867))\n- Storyshots: Fix support for jsx/tsx config files ([#9834](https://github.com/storybookjs/storybook/pull/9834))\n- MDX: Fix custom classes getting stripped ([#8897](https://github.com/storybookjs/storybook/pull/8897))\n- Typescript: Add downlevel dts for 3.5 ([#9847](https://github.com/storybookjs/storybook/pull/9847))\n\n## 6.0.0-alpha.19 (February 24, 2020)\n\n### Features\n\n- Addon-links: Add preset ([#9932](https://github.com/storybookjs/storybook/pull/9932))\n\n### Bug Fixes\n\n- Addon-docs: Restore IE11 compat on Windows by transpiling acorn-jsx ([#9790](https://github.com/storybookjs/storybook/pull/9790))\n\n## 6.0.0-alpha.18 (February 22, 2020)\n\n### Features\n\n- Addon-knobs: Add `disableForceUpdate` option ([#9447](https://github.com/storybookjs/storybook/pull/9447))\n\n## 6.0.0-alpha.17 (February 21, 2020)\n\n### Bug Fixes\n\n- Props: Fix typescript unspecified default value ([#9873](https://github.com/storybookjs/storybook/pull/9873))\n- Centered: remove `typesVersions` attribute ([#9907](https://github.com/storybookjs/storybook/pull/9907))\n\n### Maintenance\n\n- Misc: Add missing dependencies or peerDependencies ([#9916](https://github.com/storybookjs/storybook/pull/9916))\n\n## 6.0.0-alpha.16 (February 21, 2020)\n\nFailed NPM publish\n\n## 6.0.0-alpha.15 (February 20, 2020)\n\n### Breaking Changes\n\n- Refactor Client API: pull metadata handling code into the store. ([#9877](https://github.com/storybookjs/storybook/pull/9877))\n\n### Features\n\n- Core: Add skip dispose option to ClientApi ([#9868](https://github.com/storybookjs/storybook/pull/9868))\n\n## 6.0.0-alpha.14 (February 19, 2020)\n\n### Features\n\n- CLI: Add Yarn 2 compatibility ([#9866](https://github.com/storybookjs/storybook/pull/9866))\n\n### Bug Fixes\n\n- Typescript: Add downlevel dts for TS3.5 support ([#9902](https://github.com/storybookjs/storybook/pull/9902))\n- CLI: capture unknown arguments the native way ([#9888](https://github.com/storybookjs/storybook/pull/9888))\n- Core: Use telejson for websockets channel ([#9867](https://github.com/storybookjs/storybook/pull/9867))\n\n### Maintenance\n\n- Build: Upgrade to latest version of eslint config ([#9882](https://github.com/storybookjs/storybook/pull/9882))\n- Typescript: Misc improvements ([#9879](https://github.com/storybookjs/storybook/pull/9879))\n- Misc: Project root cleanup ([#9880](https://github.com/storybookjs/storybook/pull/9880))\n\n### Dependency Upgrades\n\n- Bump webpack-cli from 3.3.10 to 3.3.11 ([#9895](https://github.com/storybookjs/storybook/pull/9895))\n- Migrate to leven ([#9881](https://github.com/storybookjs/storybook/pull/9881))\n\n## 6.0.0-alpha.13 (February 15, 2020)\n\n### Bug Fixes\n\n- CLI: fix React Scripts csf-ts story templates ([#9863](https://github.com/storybookjs/storybook/pull/9863))\n- Addon-viewports: Fix Galaxy S9's viewport size ([#9797](https://github.com/storybookjs/storybook/pull/9797))\n- Storyshots: Fix support for jsx/tsx config files ([#9834](https://github.com/storybookjs/storybook/pull/9834))\n\n### Maintenance\n\n- Addon-docs: Snapshot testing and bug reporting for props tables ([#9838](https://github.com/storybookjs/storybook/pull/9838))\n- Typescript: Remove prop types in lib/components ([#9747](https://github.com/storybookjs/storybook/pull/9747))\n- Typescript: Better api consumer ([#9861](https://github.com/storybookjs/storybook/pull/9861))\n\n### Dependency Upgrades\n\n- Bump marko from 4.18.42 to 4.18.45 ([#9839](https://github.com/storybookjs/storybook/pull/9839))\n\n## 6.0.0-alpha.12 (February 14, 2020)\n\n### Maintenance\n\n- Typescript: Improve @storybook/ui types ([#9820](https://github.com/storybookjs/storybook/pull/9820))\n- Misc: Fix deepscan issues ([#9843](https://github.com/storybookjs/storybook/pull/9843)) ([#9842](https://github.com/storybookjs/storybook/pull/9842))\n\n## 6.0.0-alpha.11 (February 13, 2020)\n\n### Breaking Changes\n\n- Core: Remove legacy data from Story Store ([#9810](https://github.com/storybookjs/storybook/pull/9810))\n\n### Bug Fixes\n\n- Addon-docs: Preserve HTML element classes in MDX ([#8897](https://github.com/storybookjs/storybook/pull/8897))\n\n### Maintenance\n\n- CLI: transpile `@storybook/cli` to CJS ([#9807](https://github.com/storybookjs/storybook/pull/9807))\n\n## 5.3.13 (February 12, 2020)\n\n### Bug Fixes\n\n- React: Remove `MiniCssExtractPlugin` for CRA ([#9759](https://github.com/storybookjs/storybook/pull/9759))\n\n### Maintenance\n\n- Build: Fix DLL generation race condition ([#9770](https://github.com/storybookjs/storybook/pull/9770))\n\n## 6.0.0-alpha.10 (February 11, 2020)\n\n### Maintenance\n\n- Typescript: Migrate @storybook/ui ([#9791](https://github.com/storybookjs/storybook/pull/9791))\n\n## 6.0.0-alpha.9 (February 9, 2020)\n\n### Features\n\n- Addon-docs: Add preset options for vue-docgen-api ([#9699](https://github.com/storybookjs/storybook/pull/9699))\n- UI: Add initialActive option parameter ([#9141](https://github.com/storybookjs/storybook/pull/9141))\n\n### Bug Fixes\n\n- Components: Import react-syntax-highlighter/create-element from cjs ([#9795](https://github.com/storybookjs/storybook/pull/9795))\n\n### Maintenance\n\n- Examples: Change main.js to main.ts to show it's possible ([#9775](https://github.com/storybookjs/storybook/pull/9775))\n\n## 6.0.0-alpha.8 (February 8, 2020)\n\n### Maintenance\n\n- Replace lodash named imports with specific imports ([#9787](https://github.com/storybookjs/storybook/pull/9787))\n\n## 6.0.0-alpha.7 (February 7, 2020)\n\n### Bug Fixes\n\n- Core: Support custom addons using JSX ([#9648](https://github.com/storybookjs/storybook/pull/9648))\n- Components: Change react-syntax-highlighter from esm to cjs ([#9780](https://github.com/storybookjs/storybook/pull/9780))\n- Core: Fix manager assets to be routed in express ([#9646](https://github.com/storybookjs/storybook/pull/9646))\n\n### Maintenance\n\n- Examples: Remove addon-notes remnants ([#9782](https://github.com/storybookjs/storybook/pull/9782))\n- Build: Fix DLL generation race condition ([#9770](https://github.com/storybookjs/storybook/pull/9770))\n\n## 6.0.0-alpha.6 (February 5, 2020)\n\n### Bug Fixes\n\n- Core: Fix dev server error - back out bad change ([#9753](https://github.com/storybookjs/storybook/pull/9753))\n- CLI: Fix file path for the Button story ([#9325](https://github.com/storybookjs/storybook/pull/9325))\n\n## 5.3.12 (February 5, 2020)\n\n### Bug Fixes\n\n- Core: Fix dev server error - back out bad change ([#9753](https://github.com/storybookjs/storybook/pull/9753))\n\n## 5.3.11 (February 4, 2020)\n\n### Bug Fixes\n\n- Svelte: Fix Svelte 3 slots for decorators ([#9724](https://github.com/storybookjs/storybook/pull/9724))\n- CLI: Fix file path for Button story ([#9325](https://github.com/storybookjs/storybook/pull/9325))\n- Angular: Emit decorator metadata by default ([#9701](https://github.com/storybookjs/storybook/pull/9701))\n- Storyshots: Fix config via main.ts ([#9577](https://github.com/storybookjs/storybook/pull/9577))\n\n## 6.0.0-alpha.5 (February 4, 2020)\n\n### Features\n\n- Core: Add Yarn 2 compatibility ([#9667](https://github.com/storybookjs/storybook/pull/9667))\n- Addon-a11y: Add preset ([#9697](https://github.com/storybookjs/storybook/pull/9697))\n- Server: Initial support for @storybook/server ([#9722](https://github.com/storybookjs/storybook/pull/9722))\n\n### Bug Fixes\n\n- Svelte: Fix Svelte 3 slots for decorators ([#9724](https://github.com/storybookjs/storybook/pull/9724))\n\n### Maintenance\n\n- Cra-ts-kitchen-sink: Fix stories glob pattern ([#9706](https://github.com/storybookjs/storybook/pull/9706))\n\n## 6.0.0-alpha.4 (February 3, 2020)\n\n### Bug Fixes\n\n- Angular: Emit decorator metadata by default ([#9701](https://github.com/storybookjs/storybook/pull/9701))\n- Addon-centered: Fix clash with addon-docs for react ([#8388](https://github.com/storybookjs/storybook/pull/8388))\n\n### Maintenance\n\n- Add angular 8 and 9 cli fixtures ([#8769](https://github.com/storybookjs/storybook/pull/8769))\n\n### Dependency Upgrades\n\n- Misc upgrades ([#9688](https://github.com/storybookjs/storybook/pull/9688))\n\n## 5.3.10 (February 2, 2020)\n\n### Bug Fixes\n\n- Core: Upgrade `min-css-extract-plugin` to fix SASS loading ([#9652](https://github.com/storybookjs/storybook/pull/9652))\n- CRA: Fix jsconfig support ([#9324](https://github.com/storybookjs/storybook/pull/9324))\n- Web-components: Fix default value for docs prop table ([#9655](https://github.com/storybookjs/storybook/pull/9655))\n- Web-components: Fix types to play nicely with lit-element ([#9557](https://github.com/storybookjs/storybook/pull/9557))\n- UI: Add support for className prop on Form.Field ([#9665](https://github.com/storybookjs/storybook/pull/9665))\n- Addon-storyshots: Remove excess slashes from jest transform warning ([#9616](https://github.com/storybookjs/storybook/pull/9616))\n\n### Maintenance\n\n- Ember: Migrate to new \"import { hbs } from 'ember-cli-htmlbars'\" ([#9633](https://github.com/storybookjs/storybook/pull/9633))\n- Build: Netlify for examples again ([#9585](https://github.com/storybookjs/storybook/pull/9585))\n- Publish: Remove docs to reduce package size ([#9612](https://github.com/storybookjs/storybook/pull/9612))\n\n## 6.0.0-alpha.3 (February 2, 2020)\n\n### Bug Fixes\n\n- CRA: Fix jsconfig support ([#9324](https://github.com/storybookjs/storybook/pull/9324))\n- UI: Check if docsOnly is set to hide the addon panels ([#9687](https://github.com/storybookjs/storybook/pull/9687))\n\n### Maintenance\n\n- Addon-notes, addon-info: Move to deprecated-addons repo ([#9673](https://github.com/storybookjs/storybook/pull/9673))\n\n## 6.0.0-alpha.2 (January 30, 2020)\n\n### Features\n\n- UI: Configure tabs title, visibility, order and disable ([#9095](https://github.com/storybookjs/storybook/pull/9095))\n- Addon-cssresources: Add hideCode option ([#9627](https://github.com/storybookjs/storybook/pull/9627))\n- UI: Add `viewMode` parameter to control story nav UI ([#9090](https://github.com/storybookjs/storybook/pull/9090))\n\n### Bug Fixes\n\n- Web-components: Fix default value for prop table docs ([#9655](https://github.com/storybookjs/storybook/pull/9655))\n- Web-components: Make TypeScript types play nicely with lit-element ([#9557](https://github.com/storybookjs/storybook/pull/9557))\n- UI: Fix tabs to scroll horizontally ([#9383](https://github.com/storybookjs/storybook/pull/9383))\n- UI: Add support for className prop on Form.Field ([#9665](https://github.com/storybookjs/storybook/pull/9665))\n- Core: Upgrade `min-css-extract-plugin` to fix SASS loading ([#9652](https://github.com/storybookjs/storybook/pull/9652))\n- Adon-docs: Fix ColorPalette styling ([#9643](https://github.com/storybookjs/storybook/pull/9643))\n- Addon-storyshots: Remove excess slashes from jest transform warning ([#9616](https://github.com/storybookjs/storybook/pull/9616))\n\n### Maintenance\n\n- Source-loader: Overhaul to remove decorators, support user-configurable source ([#9547](https://github.com/storybookjs/storybook/pull/9547))\n- Build: Use Netlify for examples again ([#9585](https://github.com/storybookjs/storybook/pull/9585))\n- Ember: Migrate to new \"import { hbs } from 'ember-cli-htmlbars'\" ([#9633](https://github.com/storybookjs/storybook/pull/9633))\n- Publish: Remove docs to reduce package size ([#9612](https://github.com/storybookjs/storybook/pull/9612))\n\n## 5.3.9 (January 24, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Revert breaking source indentation fix ([#9609](https://github.com/storybookjs/storybook/pull/9609))\n\n## 6.0.0-alpha.1 (January 23, 2020)\n\n### Features\n\n- Core: Enable HMR logging in browser console ([#9535](https://github.com/storybookjs/storybook/pull/9535))\n\n### Bug Fixes\n\n- Addon-knobs: Fix broken link to repo in empty panel ([#9530](https://github.com/storybookjs/storybook/pull/9530))\n- Typescript: Export IStory in `@storybook/angular` ([#9097](https://github.com/storybookjs/storybook/pull/9097))\n\n### Maintenance\n\n- React-native: Extract to its own repo ([#9599](https://github.com/storybookjs/storybook/pull/9599))\n- Polymer: Extract to its own repo ([#9596](https://github.com/storybookjs/storybook/pull/9596))\n- Build: Fix some dependencies & ts problems ([#9603](https://github.com/storybookjs/storybook/pull/9603))\n\n## 5.3.8 (January 22, 2020)\n\n### Bug Fixes\n\n- Addon-docs: Fix TS false default value in prop table ([#9560](https://github.com/storybookjs/storybook/pull/9560))\n- Addon-knobs: Fix broken repo link in empty panel ([#9530](https://github.com/storybookjs/storybook/pull/9530))\n- Typescript: Export IStory in `@storybook/angular` ([#9097](https://github.com/storybookjs/storybook/pull/9097))\n- Fixed Angular button example story ([#9540](https://github.com/storybookjs/storybook/pull/9540))\n- Clean usage of `@types/webpack-env` dep in all packages ([#9536](https://github.com/storybookjs/storybook/pull/9536))\n\n## 6.0.0-alpha.0 (January 21, 2020)\n\n### Features\n\n- API: Add useSharedState, useStoryState ([#9566](https://github.com/storybookjs/storybook/pull/9566))\n- Addon-docs: Named colors with ColorPalette ([#9453](https://github.com/storybookjs/storybook/pull/9453))\n- Core: Add preview layouts ([#9229](https://github.com/storybookjs/storybook/pull/9229))\n- Marionette: Add marionette support ([#7981](https://github.com/storybookjs/storybook/pull/7981))\n- Addon-a11y: Support manual run ([#8883](https://github.com/storybookjs/storybook/pull/8883))\n- Addon-cssresources: Disable SyntaxHighlighter for long code ([#9360](https://github.com/storybookjs/storybook/pull/9360))\n- Core: Improve monorepo support ([#8822](https://github.com/storybookjs/storybook/pull/8822))\n\n### Bug Fixes\n\n- Addon-docs: Fix TS false default value in prop table ([#9560](https://github.com/storybookjs/storybook/pull/9560))\n- Addon-docs: Remove hard-coded lineHeight in Typeset block ([#9567](https://github.com/storybookjs/storybook/pull/9567))\n- Fixed Angular button example story ([#9540](https://github.com/storybookjs/storybook/pull/9540))\n- Core: Fix generated entry to import at top of file ([#9398](https://github.com/storybookjs/storybook/pull/9398))\n- Preact: Fix story function typescript type ([#9123](https://github.com/storybookjs/storybook/pull/9123))\n- UI: Make canvas link a link ([#9257](https://github.com/storybookjs/storybook/pull/9257))\n\n### Maintenance\n\n- Build: the build-storybooks script ([#9569](https://github.com/storybookjs/storybook/pull/9569))\n- CLI: Improve Rax template ([#9574](https://github.com/storybookjs/storybook/pull/9574))\n- Typescript: Migrate polymer ([#9565](https://github.com/storybookjs/storybook/pull/9565))\n- Typescript: Migrate ember ([#9020](https://github.com/storybookjs/storybook/pull/9020))\n- Next 6.0.0 ([#9212](https://github.com/storybookjs/storybook/pull/9212))\n- REMOVE subscription_store ([#9228](https://github.com/storybookjs/storybook/pull/9228))\n\n### Dependency Upgrades\n\n- Update husky to v4 ([#9509](https://github.com/storybookjs/storybook/pull/9509))\n- Bumped react-dev-utils dependency to v10. ([#9579](https://github.com/storybookjs/storybook/pull/9579))\n- Bump babel-plugin-macros from 2.7.1 to 2.8.0 ([#9236](https://github.com/storybookjs/storybook/pull/9236))\n- Bump babel-plugin-emotion from 10.0.23 to 10.0.27 ([#9239](https://github.com/storybookjs/storybook/pull/9239))\n- Bump @babel/runtime from 7.7.4 to 7.7.7 ([#9277](https://github.com/storybookjs/storybook/pull/9277))\n- Bump corejs-upgrade-webpack-plugin from 2.2.0 to 3.0.1 ([#9427](https://github.com/storybookjs/storybook/pull/9427))\n- Bump terser-webpack-plugin from 2.2.1 to 2.3.2 ([#9386](https://github.com/storybookjs/storybook/pull/9386))\n"
  },
  {
    "path": "CLAUDE.md",
    "content": "@AGENTS.md\n"
  },
  {
    "path": "CODEOWNERS",
    "content": "# Code Owners\n\n# Root\n# .github/    @JReinhold @yannbf @vanessayuenn\n# .circleci/  @yannbf @kasperpeulen\n# .yarnrc.yml @ndelangen @JReinhold\n\n# Docs\n/docs/ @kylegach @jonniebigodes\n\n# Scripts\n# /scripts/         @ndelangen @kasperpeulen\n# /scripts/release/ @jreinhold @ndelangen @kasperpeulen\n\n# Addons\n# /code/addons/a11y/                 @ndelangen @yannbf\n# /code/addons/docs/                 @JReinhold @kasperpeulen\n# /code/addons/gfm/                  @ndelangen @valentinpalkovic\n# /code/addons/jest/                 @ndelangen\n# /code/addons/links/                @yannbf @JReinhold\n# /code/addons/storysource/          @ndelangen\n# /code/addons/themes/               @JReinhold @yannbf\n\n# Builder\n# /code/builders/builder-manager/  @ndelangen @valentinpalkovic\n# /code/builders/builder-vite/     @JReinhold @valentinpalkovic @IanVS\n# /code/builders/builder-webpack5/ @ndelangen @valentinpalkovic\n\n# Frameworks\n# /code/frameworks/angular/                 @valentinpalkovic @yannbf\n# /code/frameworks/html-vite/               @kasperpeulen @JReinhold\n# /code/frameworks/nextjs/                  @valentinpalkovic @kasperpeulen @yannbf\n# /code/frameworks/react-vite/              @valentinpalkovic @kasperpeulen\n# /code/frameworks/react-webpack5/          @valentinpalkovic @kasperpeulen\n# /code/frameworks/svelte-vite/             @kasperpeulen @JReinhold\n# /code/frameworks/sveltekit/               @kasperpeulen @JReinhold\n# /code/frameworks/vue3-vite/               @kasperpeulen @yannbf @JReinhold\n# /code/frameworks/web-components-vite/     @kasperpeulen @JReinhold\n# /code/frameworks/web-components-webpack5/ @kasperpeulen @JReinhold\n\n# Lib\n# /code/lib/cli/            @yannbf @valentinpalkovic @ndelangen\n# /code/lib/cli-sb/         @yannbf @valentinpalkovic @ndelangen\n# /code/lib/cli-storybook/  @yannbf @valentinpalkovic @ndelangen\n# /code/lib/codemod/        @kasperpeulen @ndelangen\n# /code/lib/core-webpack/   @valentinpalkovic @ndelangen\n# /code/lib/csf-plugin/     @ndelangen @valentinpalkovic\n# /code/lib/node-logger/    @yannbf @ndelangen\n# /code/lib/react-dom-shim/ @ndelangen @valentinpalkovic @tmeasday\n# /code/lib/telemetry/      @shilman @yannbf @ndelangen\n# /code/lib/types/          @kasperpeulen @ndelangen\n\n# Presets\n# /code/presets/create-react-app/ @valentinpalkovic @ndelangen\n\n# Renderers\n# /code/renderers/html/           @kasperpeulen @JReinhold\n# /code/renderers/react/          @valentinpalkovic @kasperpeulen\n# /code/renderers/server/         @shilman @valentinpalkovic\n# /code/renderers/svelte/         @JReinhold @kasperpeulen\n# /code/renderers/vue3/           @kasperpeulen @JReinhold\n# /code/renderers/web-components/ @kasperpeulen @JReinhold\n\n# E2E\n# /code/e2e-tests/ @yannbf @valentinpalkovic\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "\n# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, caste, color, religion, or sexual\nidentity and orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the overall\n  community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or advances of\n  any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email address,\n  without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting one of the Steering committee members for enforcement:\n\n- Norbert de Langen ~ @ndelangen - `ndelangen@me.com`\n- Igor Davydkin ~ @igordv - `davydkin.igor@gmail.com`\n- Tom Coleman ~ @tmeasday - `tom@thesnail.org`\n- Michael Shilman ~ @shilman - `michael@lab80.co`\n- Philip Riabchun ~ @hypnosphi - `talpa@yandex.ru`\n\nThe steering committee will review and investigate all complaints and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\n## Enforcement Guidelines\n\nProject maintainers or community leaders who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series of\nactions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or permanent\nban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior, harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within the\ncommunity.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.1, available at\n[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].\n\nCommunity Impact Guidelines were inspired by\n[Mozilla's code of conduct enforcement ladder][Mozilla CoC].\n\nFor answers to common questions about this code of conduct, see the FAQ at\n[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at\n[https://www.contributor-covenant.org/translations][translations].\n\n[homepage]: https://www.contributor-covenant.org\n[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html\n[Mozilla CoC]: https://github.com/mozilla/diversity\n[FAQ]: https://www.contributor-covenant.org/faq\n[translations]: https://www.contributor-covenant.org/translations\n"
  },
  {
    "path": "CONTRIBUTING/RELEASING.md",
    "content": "# Releasing <!-- omit in toc -->\n\n> **Note**\n> This document is relevant only for maintainers that have permissions to release new versions of Storybook. Anyone can read it for interest or to suggest changes, but it's not required knowledge.\n\n## Table of Contents <!-- omit in toc -->\n\n- [Introduction](#introduction)\n  - [Branches](#branches)\n- [Release Pull Requests](#release-pull-requests)\n  - [Patch Releases](#patch-releases)\n  - [Non-patch Releases](#non-patch-releases)\n  - [Publishing](#publishing)\n- [👉 How to Release](#-how-to-release)\n  - [1. Find the Prepared Pull Request](#1-find-the-prepared-pull-request)\n  - [2. Freeze the Pull Request and run CI](#2-freeze-the-pull-request-and-run-ci)\n  - [3. QA Each Merged Pull Request](#3-qa-each-merged-pull-request)\n  - [4. Re-trigger the Workflow](#4-re-trigger-the-workflow)\n  - [5. Make Manual Changes](#5-make-manual-changes)\n  - [6. Merge](#6-merge)\n  - [7. See the \"Publish\" Workflow Finish](#7-see-the-publish-workflow-finish)\n- [Releasing changes to older minor versions](#releasing-changes-to-older-minor-versions)\n- [Releasing Locally in an Emergency 🚨](#releasing-locally-in-an-emergency-)\n- [Canary Releases](#canary-releases)\n  - [With GitHub UI](#with-github-ui)\n  - [With the CLI](#with-the-cli)\n- [Versioning Scenarios](#versioning-scenarios)\n  - [Prereleases - `7.1.0-alpha.12` -\\> `7.1.0-alpha.13`](#prereleases---710-alpha12---710-alpha13)\n  - [Prerelease promotions - `7.1.0-alpha.13` -\\> `7.1.0-beta.0`](#prerelease-promotions---710-alpha13---710-beta0)\n  - [Minor/major releases - `7.1.0-rc.2` -\\> `7.1.0` or `8.0.0-rc.3` -\\> `8.0.0`](#minormajor-releases---710-rc2---710-or-800-rc3---800)\n  - [First prerelease of new major/minor - `7.1.0` -\\> `7.2.0-alpha.0` or `8.0.0-alpha.0`](#first-prerelease-of-new-majorminor---710---720-alpha0-or-800-alpha0)\n  - [Patch releases to stable - subset of `7.1.0-alpha.13` -\\> `7.0.14`](#patch-releases-to-stable---subset-of-710-alpha13---7014)\n  - [Patch releases to earlier versions - subset of `7.1.0-alpha.13` -\\> `6.5.14`](#patch-releases-to-earlier-versions---subset-of-710-alpha13---6514)\n  - [Prerelease of upcoming patch release - `7.0.20` -\\> `7.0.21-alpha.0`](#prerelease-of-upcoming-patch-release---7020---7021-alpha0)\n  - [Merges to `main` without versioning](#merges-to-main-without-versioning)\n- [FAQ](#faq)\n  - [When should I use the \"patch:yes\" label?](#when-should-i-use-the-patchyes-label)\n  - [How do I make changes to the release tooling/process?](#how-do-i-make-changes-to-the-release-toolingprocess)\n  - [Why do I need to re-trigger workflows to update the changelog?](#why-do-i-need-to-re-trigger-workflows-to-update-the-changelog)\n  - [Which combination of inputs creates the version bump I need?](#which-combination-of-inputs-creates-the-version-bump-i-need)\n  - [Which changes are considered \"releasable\", and what does it mean?](#which-changes-are-considered-releasable-and-what-does-it-mean)\n  - [Why are no release PRs being prepared?](#why-are-no-release-prs-being-prepared)\n  - [Why do we need separate release branches?](#why-do-we-need-separate-release-branches)\n\n## Introduction\n\nThis document explains the release process for the Storybook monorepo. There are two types:\n\n1. Non-patch releases - releasing any content that is on the `next` branch, either prereleases or stable releases\n2. Patch releases - picking any content from `next` to `main`, that needs to be patched back to the current stable minor release\n\nThe release process is based on automatically created \"Release Pull Requests\", that when merged will trigger a new version to be released.\n\nA designated Releaser -- which may rotate between core team members -- will go through the release process in the current Release PR. This process is implemented with NodeJS scripts in [`scripts/release`](../scripts/release/) and three GitHub Actions workflows:\n\n- [Prepare `next` PR](../.github/workflows/prepare-non-patch-release.yml)\n- [Prepare patch PR](../.github/workflows/prepare-patch-release.yml)\n- [Publish](../.github/workflows/publish.yml)\n\n> **Note**\n> This document distinguishes between **patch** and **non-patch** releases. The distinction reflects the difference between patching an existing minor version on `main` or releasing a new minor/major/prerelease from `next`.\n\n### Branches\n\nTo understand the release structure, it's important to know the branching strategy used. All development is done on the `next` branch, where new features and bug fixes are added. This branch contains content to be released in the next prerelease (eg. `v7.1.0-alpha.22`).\n\nThe `main` branch contains the content for the current stable release (eg. `v7.0.20`). When changes need to be made to both the next major/minor release and the current patch release (bug fixes or small improvements), they are made to `next`. If the change needs to be patched back to the current minor version (eg. from `7.1.0-alpha.20` to `7.0.18`), the PR containing the fix is labeled with the **\"patch\"** label, so the release workflow can pick it up. This ensures changes are tested in a prerelease before being released to stable.\n\nThe actual (pre)releases are not made from `next` nor `main`, but from `next-release` and `latest-release` respectively. This indirection is explained in [the \"Why do we need separate release branches?\" section](#why-do-we-need-separate-release-branches) below.\n\nThe branches in the monorepo can be summarized in this diagram (simplified):\n\n```mermaid\n%%{init: { 'gitGraph': { 'showCommitLabel': false } } }%%\ngitGraph\n    commit\n    branch latest-release\n    branch next\n    commit\n    branch next-release\n    commit\n    commit tag: \"7.1.0-alpha.18\"\n    checkout next\n    merge next-release\n    commit id: \"bugfix\"\n    commit\n    checkout latest-release\n    cherry-pick id: \"bugfix\"\n    commit tag: \"7.0.20\"\n    checkout next-release\n    merge next\n    commit tag: \"7.1.0-alpha.19\"\n    checkout next\n    merge next-release\n    commit\n    checkout main\n    merge latest-release\n```\n\n## Release Pull Requests\n\nTwo GitHub Actions workflows automatically create release pull requests, one for each type of release. These pull requests act as the \"interface\" for the Releaser to create a new release. Although the behavior between the two is similar, some minor differences exist, as described in the subsections below.\n\nThe high-level flow is:\n\n1. When a PR is merged to `next` (or a commit is pushed), both release pull requests are (re)generated.\n2. They create a new branch - `version-(patch|non-patch)-from-<CURRENT-VERSION>`.\n3. They calculate which version to bump to according to the version strategy.\n4. They update `CHANGELOG(.prerelease).md` with all changes detected.\n5. They commit everything.\n6. They **force push**.\n7. They open/edit a pull request towards `next-release` or `latest-release`.\n\nA few key points to note in this flow:\n\n- The PRs are regenerated on any changes to `next`, or can be manually triggered (see [the Re-trigger the Workflow section](#4-re-trigger-the-workflow)).\n- The changes are force pushed to the branch, so any manual changes on the release branch before merging risk being overwritten if someone else merges a new change to `next`, triggering the workflow. To avoid this, apply the **\"freeze\"** label to the pull request.\n- The changelogs are committed during the preparation, but the packages are not version bumped and not published until later.\n- The release pull requests don't target their working branches (`next` and `main`), but rather `next-release` and `latest-release`.\n\n### Patch Releases\n\n> **Note**\n> Workflow: [`prepare-patch-release.yml`](../.github/workflows/prepare-patch-release.yml)\n\nPatch releases are created by [cherry-picking](https://www.atlassian.com/git/tutorials/cherry-pick) any merged, unreleased pull requests that have the \"**patch:yes**\" label applied to the `next` branch. The merge commit of said pull requests are cherry-picked.\n\nSometimes it is desired to pick pull requests back to `main` even if they are not considered \"releasable\". Unlike non-patch release preparation, patch releases will not be canceled if the content is not releasable. It might not make sense to create a new patch release if the changes are only for documentation and/or internal build systems. However, getting the changes back to `main` is the only way to deploy the documentation to the production docs site. You may also want to cherry-pick changes to internal CI to fix issues. These are valid scenarios where you want to cherry-pick the changes without being blocked on \"releasable\" content. In these cases, where all cherry picks are non-releasable, the preparation workflow creates a \"merging\" pull request instead of a \"releasing\" pull request. This pull request does not bump versions or update changelogs; it just cherry-picks the changes and allows you to merge them into `latest-release` -> `main`.\n\nThe preparation workflow sequentially cherry-picks each patch pull request to its branch. If this cherry-picking fails due to conflicts or other reasons, it is ignored and the next pull request is processed. All failing cherry-picks are listed in the release pull request's description, for the Releaser to manually cherry-pick during the release process. This problem occurs more often when `main` and `next` diverge, i.e. the longer it has been since a stable major/minor release.\n\nSimilar to the non-patch release flow, the preparation workflow for patches will create a new branch from `main` called `version-patch-from-<CURRENT-STABLE-VERSION>`, and open a pull request that targets `latest-release`. When the pull request is merged by the Releaser, the [publish workflow](#publishing) will eventually merge `latest-release` into `main`.\n\nHere is an example of a workflow where a feature and two bug fixes have been merged to `next`. Only the bug fixes have the \"**patch:yes**\" label, so only those two go into the new `7.0.19` release. Note that it is the merge commits to `next` that are cherry-picked, not the commits on the bugfix branches.\n\n```mermaid\ngitGraph\n    commit\n    branch latest-release\n    branch next\n    checkout latest-release\n    commit tag: \"v7.0.18\"\n    checkout main\n    merge latest-release\n    checkout next\n    commit\n    branch some-patched-bugfix\n    commit\n    commit id: \"patch1\"\n    checkout next\n    merge some-patched-bugfix\n    branch new-feature\n    commit\n    checkout next\n    merge new-feature\n    branch other-patched-bugfix\n    commit id: \"patch2\"\n    checkout next\n    merge other-patched-bugfix\n    checkout main\n    branch version-patch-from-7.0.18\n    cherry-pick id: \"patch1\"\n    cherry-pick id: \"patch2\"\n    commit id: \"write changelog\"\n    checkout latest-release\n    merge version-patch-from-7.0.18\n    commit id: \"bump versions\" tag: \"v7.0.19\"\n    checkout main\n    merge latest-release\n```\n\n### Non-patch Releases\n\n> **Note**\n> Workflow: [`prepare-non-patch-release.yml`](../.github/workflows/prepare-non-patch-release.yml)\n\nNon-patch releases are prepared with all content from the `next` branch. The changelog is generated by examining the git history, and looking up all the commits and pull requests between the current prerelease (on `next-release`) and `HEAD` of `next`.\n\nThe default versioning strategy is to increase the current prerelease number, as described in [Prereleases - `7.1.0-alpha.12` -> `7.1.0-alpha.13`](#prereleases---710-alpha12---710-alpha13). If there is no prerelease number (i.e., we just released a new stable minor/major version), it will add one to a patch bump, so it would go from `7.2.0` to `7.2.1-0` by default.\n\n`next`-PRs are only created if there are actual changes to release. Content labeled with \"build\" or \"documentation\" is [not considered \"releasable\"](#which-changes-are-considered-releasable-and-what-does-it-mean) and is not user-facing, so it doesn't make sense to create a release. This is explained in more detail in [Why are no release PRs being prepared?](#why-are-no-release-prs-being-prepared).\n\nThe preparation workflow will create a new branch from `next`, called `version-non-patch-from-<CURRENT-NEXT-VERSION>`, and open a pull request targeting `next-release`. When the Releaser merges it, the [publish workflow](#publishing) will merge `next-release` into `next`.\n\nHere's an example of a workflow where a feature and a bugfix have been created and then released to a new `7.1.0-alpha.29` version. All the commits highlighted with square dots are the ones that will be considered when generating the changelog.\n\n```mermaid\n%%{init: { 'gitGraph': { 'mainBranchName': 'next' } } }%%\ngitGraph\n    commit\n    branch next-release\n    commit tag: \"7.1.0-alpha.28\"\n    checkout next\n    merge next-release\n    commit type: HIGHLIGHT id: \"direct commit\"\n    branch new-feature\n    commit\n    commit\n    checkout next\n    merge new-feature type: HIGHLIGHT\n    branch some-bugfix\n    commit\n    checkout next\n    merge some-bugfix type: HIGHLIGHT\n    branch version-non-patch-from-7.1.0-alpha.28\n    commit id: \"write changelog\"\n    checkout next-release\n    merge version-non-patch-from-7.1.0-alpha.28\n    commit id: \"bump versions\" tag: \"7.1.0-alpha.29\"\n    checkout next\n    merge next-release\n```\n\n### Publishing\n\n> **Note**\n> Workflow: [`publish.yml`](../.github/workflows/publish.yml)\n\nWhen either a non-patch release or a patch release branch is merged into `latest-release` or `next-release`, the publishing workflow is triggered. This workflow performs the following tasks:\n\n1. Bump versions of all packages according to the plan from the prepared PRs\n2. Install dependencies and build all packages.\n3. Publish packages to npm.\n4. (If this is a patch release, add the \"**patch:done**\" label to all relevant pull requests.)\n5. Create a new GitHub Release, including a version tag in the release branch (`latest-release` or `next-release`).\n6. Merge the release branch into the core branch (`main` or `next`).\n7. (If this is a patch release, copy the `CHANGELOG.md` changes from `main` to `next`.)\n\nThe publish workflow runs in the \"release\" GitHub environment, which has the npm token required to publish packages to the `@storybook` npm organization. For security reasons, this environment can only be accessed from the four \"core\" branches: `main`, `next`, `latest-release` and `next-release`.\n\n## 👉 How to Release\n\nThis section explains what a Releaser should do when it's time to release. The steps are also outlined in the release pull requests, to provide guidance for inexperienced Releasers.\n\nThe high-level workflow for a Releaser is:\n\n1. Find the prepared pull request\n2. Freeze the pull request\n3. Make changes to merged pull requests (revert, rename, relabel)\n4. Re-trigger the workflow to get changes from step 3 in\n5. Make any manual changes needed\n6. Merge\n7. Check that the \"publish\" workflow has finished successfully\n\n### 1. Find the Prepared Pull Request\n\nLook for the release pull request that has been prepared for the type of release you're about to release:\n\n- \"Release: Prerelease|Minor|Major `<NEXT-VERSION>`\" for releases from `next`\n- \"Release: Patch `<NEXT-VERSION>`\" for patch releases\n- \"Release: Merge patches to `main` (without version bump)\" for patches without releases\n\nFor example: https://github.com/storybookjs/storybook/pull/23148\n\n### 2. Freeze the Pull Request and run CI\n\nAdd the \"**freeze**\" label to the pull request. This will stop the preparation workflows from running when new changes to `next` are merged. This allows you to make changes without worrying about other people's work overriding yours.\n\nThe \"**freeze**\" label does not cancel the workflows when they are triggered manually, so you can still run the workflow.\n\nYou also need to add the \"**ci:daily**\" label to the pull request to trigger CI runs. This will start a full CI run and re-run on any changes. CI does not run by default to avoid unnecessary re-runs until a new release is being created.\n\n### 3. QA Each Merged Pull Request\n\nIt is important to verify that the release includes the right content. Key elements to account for are:\n\n1. Is the change suitable for the version bump?\n\nFor example, check if it's a breaking change that isn't allowed in a minor prerelease, or if it's a new feature in a patch release. If it's not suitable, revert the pull request and notify the author.\n\nSometimes when doing a patch release, a pull request can have the \"patch:yes\" label but you don't want that change to be part of this release. Maybe you're not confident in the change, or you require more input from maintainers before releasing it. In those situations you should remove the \"patch:yes\" label from the pull request and follow through with the release (make sure to re-trigger the workflow). When the release is done, add the \"patch:yes\" label back again, so it will be part of the next release.\n\n2. Is the pull request title correct?\n\nThe title of pull requests is added to the user-facing changelogs, so it must be accurate and understandable. It should follow the pattern \"[Area]: [Summary]\", where [Area] is the part of the repo that has been changed, and the summary is what has changed.\n\nIt's easy to confuse [Area] with labels, but they are not the same. For example, the \"**build**\" label indicates that the changes are internal, but a \"build\" [Area] is _not_ correct. The area could be \"Core\" or \"CI\", but rarely is the area being changed actually the \"build\" area.\nIf a pull request changes multiple places, it can be hard to choose an area - this is often the case when upgrading dependencies - so use your best judgement. There's no hard rule, but a good guideline is that the more precise it is, the more useful it is to read later.\n\n3. Is the pull request labeled correctly?\n\nSome labels have specific meanings when it comes to releases. It's important that each pull request has labels that accurately describe the change, as labels can determine if a pull request is included in the changelog or not. This is explained further in the [Which changes are considered \"releasable\", and what does it mean?](#which-changes-are-considered-releasable-and-what-does-it-mean) section.\n\n4. Patches: has it already been released in a prerelease?\n\nIf this is a patch release, make sure that all pull requests have already been released in a prerelease. If some haven't, create a new prerelease first.\n\nThis is not a technical requirement, but it's a good practice to ensure that a change doesn't break a prerelease before releasing it to stable.\n\n### 4. Re-trigger the Workflow\n\nAny changes made to pull requests' titles, labels or even reverts won't be reflected in the release pull request because it's hopefully frozen at this point. Even if it isn't, the workflow only triggers on pushes to `next`, not when pull request meta data is changed.\n\nTherefore, if any changes were made in step 3, you need to re-trigger the workflow manually to regenerate the changelog and the version bump. If no changes were made, this step can be skipped.\n\nIt's important to remember that triggering the workflow will force push changes to the branch, so it must be done before committing any changes manually (the next step). Otherwise, these will be overwritten.\n\n> **Warning**\n> When re-triggering the workflow, any new content merged to `next` will also become part of the release pull request. You can't assume the same content with fixes will be seen, as new content may have been merged in since the pull request was frozen.\n\nWhen triggering the workflows, always choose the `next` branch as the base, unless you know exactly what you are doing.\n\nThe workflows can be triggered here:\n\n- [Prepare next PR](https://github.com/storybookjs/storybook/actions/workflows/prepare-non-patch-release.yml)\n- [Prepare patch PR](https://github.com/storybookjs/storybook/actions/workflows/prepare-patch-release.yml)\n\nCrucially for prereleases, this is also where you change the versioning strategy if you need something else than the default as described in [Preparing - Non-patch Releases](#non-patch-releases). When triggering the non-patch workflow manually, you can optionally add inputs:\n\n![Screenshot of triggering the non-patch release workflow in GitHub Actions, with a form that shows a release type selector and a prerelease identifier text field](prerelease-workflow-inputs.png)\n\nSee [Versioning Scenarios](#versioning-scenarios) for a description of each version bump scenario, how to activate it and what it does, and [Which combination of inputs creates the version bump I need?](#which-combination-of-inputs-creates-the-version-bump-i-need) for a detailed description of the workflow inputs.\n\n### 5. Make Manual Changes\n\nIt's possible and valid to push manual changes directly on the release branch when needed. This could be to alter the changelog in a way that can't be done automatically, or another critical change is needed for the release to work. Any changes made will be merged to `next|main` once the release has been published.\n\nIt's recommended to use the automated process as much as possible to ensure that the information in GitHub is the single source of truth, and that pull requests and changelogs are in sync.\n\n> **Warning**\n> If you make manual changes to the changelog, you also need to make those changes in either [`./docs/versions/latest.json`](../docs/versions/latest.json) or [`./docs/versions/next.json`](../docs/versions/next.json). The `\"plain\"` property should match the changelog entry, **without the heading** and with all new lines replaces with `\\n`.\n> This is common for custom release notes when releasing majors and minors.\n\n### 6. Merge\n\nWhen the pull request was frozen, a CI run was triggered on the branch. If it's green, it's time to merge the pull request. If CI is failing for some reason, consult with the rest of the core team. These release pull requests are almost exact copies of `next|main` so CI should only fail if they fail too.\n\n### 7. See the \"Publish\" Workflow Finish\n\nMerging the pull request will trigger [the publish workflow](https://github.com/storybookjs/storybook/actions/workflows/publish.yml), which does the final version bumping and publishing. As a Releaser, you're responsible for this to finish successfully, so you should watch it until the end. If it fails, it will notify in Discord, so you can monitor that instead if you want to.\n\nDone! 🚀\n\n## Releasing changes to older minor versions\n\nIf you need to release a change to an older minor version that is not the latest, you have to do it manually, locally. The process is described below, with an example of releasing a new `v8.3.7` in a situation where `8.4.0` is currently the latest version.\n\n1. Checkout the _existing_ tag that matches the latest minor release you want to bump, and create a new branch from it. In this case, we want to do:\n    1. `git fetch --all --tags`\n    2. `git checkout tags/v8.3.6 -b patch-8-3-7`\n2. Make the changes you need to, most likely cherry-picking commits from the fix you need to back-port.\n3. Run `yarn install`\n4. Build all packages in `code` with `yarn task --task compile --no-link`\n5. Commit and push your changes.\n6. Trigger _daily_ CI manually on your branch:\n    1. Open [CircleCI](https://app.circleci.com/pipelines/github/storybookjs/storybook) and click \"Trigger Pipeline\" on the top right corner of the page.\n    2. Set the following configuration options:\n        - Pipeline: _\"storybook default\"_\n        - Config Source: _\"storybook\"_\n        - Branch: Your branch, eg. `patch-8-3-7`\n    3. Add a parameter, with _\"name\"_ `workflow`, _\"value\"_ `daily`\n7. Wait for CI to finish successfully.\n8. Bump all package versions:\n    1. `cd scripts`\n    2. `yarn release:version --release-type patch`\n9.  Commit with `git commit -m \"Bump version from <CURRENT_VERSION> to <NEXT_VERSION> MANUALLY\"`\n10. Add a new entry to `CHANGELOG.md`, describing your changes\n11. Commit with `git commit -m \"Update CHANGELOG.md with <NEXT_VERSION> MANUALLY\"`\n12. Ensure you have the correct write permissions for all the Storybook npm packages. You need to be an admin of the _storybook_ org, and the packages that are not in the org. The simplest way to check this is to ensure you can see the _\"Settings\"_ tab in the following packages:\n    1.  [`@storybook/react-vite`](https://www.npmjs.com/package/@storybook/react-vite/access)\n    2.  [`storybook`](https://www.npmjs.com/package/storybook/access)\n    3.  [`sb`](https://www.npmjs.com/package/sb/access)\n    4.  [`create-storybook`](https://www.npmjs.com/package/create-storybook/access)\n13. Get your npm access token or generate a new one at https://www.npmjs.com/settings/your-username/tokens. Remember to give it access to the `storybook` org and the packages not in the org, as listed above.\n14. Publish all packages with `YARN_NPM_AUTH_TOKEN=<NPM_TOKEN> yarn release:publish --tag tag-for-publishing-older-releases --verbose`\n    - It goes through all packages and publishes them. If any number of packages fails to publish, it will retry 5 times, skipping those that have already been published.\n15. Confirm the new version has been released on npm with the tag `tag-for-publishing-older-releases`:\n    1. [`@storybook/react-vite`](https://www.npmjs.com/package/@storybook/react-vite?activeTab=versions)\n    2. [`storybook`](https://www.npmjs.com/package/storybook?activeTab=versions)\n    3. [`sb`](https://www.npmjs.com/package/sb?activeTab=versions)\n    4. [`create-storybook`](https://www.npmjs.com/package/create-storybook?activeTab=versions)\n16. Push\n17. Manually create a GitHub Release at https://github.com/storybookjs/storybook/releases/new with:\n    1.  Create new tag: `v<VERSION>` (e.g., `v8.3.7`)\n    2.  Target: your branch (e.g., `patch-8-3-7`)\n    3.  Previous tag: `v<PREVIOUS_VERSION>` (e.g., `v8.3.6`)\n    4.  Title: `v<VERSION>` (e.g., `v8.3.7`)\n    5.  Description: The content you added to `CHANGELOG.md`\n    6.  Untick _\"Set as the latest release\"_\n18. Cherry-pick your changelog changes into `next`, so they are actually visible \n    1.  Checkout the `next` branch\n    2.  Cherry-pick the commit you created with your changelog modifications\n    3.  Push\n\nDone. 🎉\n\n## Releasing Locally in an Emergency 🚨\n\nThings can fail, code can break, and bugs can exist. When automation is broken, there may be a need for an emergency escape hatch to release new fixes. In such a situation, it's valid to run the whole release process locally instead of relying on pull requests and workflows. You don't need to create pull requests or split preparation and publishing; you can do it all at once, but make sure you still follow the correct branching strategy.\n\nYou can either prepare the release locally and use the automatic workflow for publishing it or you can do the whole release workflow locally. If you choose the latter approach, you need a token to the npm registry to publish (set as `YARN_NPM_AUTH_TOKEN`), which you can get from @shilman or @ndelangen.\n\nYou can inspect the workflows to see what they are running and copy that, but here is a general sequence of steps to mimic the automated workflow. Feel free to deviate from this as needed.\n\nBefore you start you should make sure that your working tree is clean and the repository is in a clean state by running `git clean -xdf`.\n\n1. Create a new branch from either `next` or `main` (patches)\n2. Get all tags: `git fetch --tags origin`\n3. Install dependencies: `yarn task --task=install --start-from=install`\n4. `cd scripts`\n5. (If patch release) Cherry pick:\n   1. `yarn release:pick-patches`\n   2. Manually cherry pick any necessary patches based on the previous output\n6. Bump versions:\n   1. If you plan on using automatic publishing (ie. stop at step 12), bump with deferred: `yarn release:version --verbose --deferred --release-type <RELEASE_TYPE> --pre-id <PRE_ID>`\n   2. If doing the whole release locally, **do not** defer the bump: `yarn release:version --verbose --release-type <RELEASE_TYPE> --pre-id <PRE_ID>`\n7. To see a list of changes (for your own to-do list), run `yarn release:generate-pr-description --current-version <CURRENT_VERSION> --next-version <NEXT_VERSION_FROM_PREVIOUS_STEP> --verbose`\n8. Write changelogs: `yarn release:write-changelog <NEXT_VERSION_FROM_PREVIOUS_STEP> --verbose`\n9. `git add .`.\n10. Commit changes: `git commit -m \"Bump version from <CURRENT_VERSION> to <NEXT_VERSION_FROM_PREVIOUS_STEP> MANUALLY\"`\n11. Merge changes to the release branch:\n    1. `git checkout <\"latest-release\" | \"next-release\">`\n    2. `git pull`\n    3. `git merge <PREVIOUS_BRANCH>`\n    4. `git push origin`\n12. (If automatic publishing is still working, it should kick in now and the rest of the steps can be skipped)\n13. `cd ..`\n14. Publish to the registry: `YARN_NPM_AUTH_TOKEN=<NPM_TOKEN> yarn release:publish --tag <\"next\" OR \"latest\"> --verbose`\n15. (If patch release) `yarn release:label-patches`\n16. Manually create a GitHub Release with a tag that is the new version and the target being `latest-release` or `next-release`.\n17. Merge to core branch:\n    1. `git checkout <\"next\"|\"main\">`\n    2. `git pull`\n    3. `git merge <\"next-release\"|\"latest-release\">`\n    4. `git push origin`\n18. (If patch release) Sync `CHANGELOG.md` to `next` with:\n    1. `git checkout next`\n    2. `git pull`\n    3. `git checkout origin/main ./CHANGELOG.md`\n    4. `git add ./CHANGELOG.md`\n    5. `git commit -m \"Update CHANGELOG.md for v<NEXT_VERSION>\"`\n    6. `git push origin`\n19. (If non-patch release) Sync `versions/next.json` from `next` to `main`\n    1. `git checkout main`\n    2. `git pull`\n    3. `git checkout origin/next ./docs/versions/next.json`\n    4. `git add ./docs/versions/next.json`\n    5. `git commit -m \"Update versions/next.json for v<NEXT_VERSION_FROM_PREVIOUS_STEP>\"`\n    6. `git push origin main`\n\n## Canary Releases\n\nIt's possible to release any pull request as a canary release multiple times during development. This is an effective way to try out changes in standalone projects without linking projects together via package managers.\n\nTo create a canary release, a core team member (or anyone else with administrator privileges) must manually trigger the publish workflow with the pull request number.\n\n**Before creating a canary release from contributors, the core team member must ensure that the code being released is not malicious.**\n\nCreating a canary release can either be done via GitHub's UI or the [CLI](https://cli.github.com/):\n\n### With GitHub UI\n\n1. Open the workflow UI at https://github.com/storybookjs/storybook/actions/workflows/publish.yml\n2. On the top right corner, click \"Run workflow\"\n3. For \"branch\", **always select `next`**, regardless of which branch your pull request is on\n4. For the pull request number, input the number for the pull request **without a leading #**\n\n### With the CLI\n\nThe following command will trigger a workflow run - replace `<PR_NUMBER>` with the actual pull request number:\n\n```bash\ngh workflow run --repo storybookjs/storybook publish.yml --field pr=<PR_NUMBER>\n```\n\nWhen the release succeeds, it will update the \"Canary release\" section of the pull request with information about the release and how to use it (see example [here](https://github.com/storybookjs/storybook/pull/23508)). If it fails, it will create a comment on the pull request, tagging the triggering actor to let them know that it failed (see example [here](https://github.com/storybookjs/storybook/pull/23508#issuecomment-1642850467)).\n\nThe canary release will have the following version format: `0.0.0-pr-<PR_NUMBER>-sha-<COMMIT_SHA>`, e.g., `0.0.0-pr-23508-5ec8c1c3`. Using v0.0.0 ensures that no user will accidentally get the canary release when using a canary with prereleases, eg. `^7.2.0-alpha.0`\n\n> ** Note **\n> All canary releases are released under the same \"canary\" dist tag. This means you'll technically be able to install it with `npm install @storybook/cli@canary`. However, this doesn't make sense, as releases from subsequent pull requests will overwrite that tag quickly. Therefore you should always install the specific version string, e.g., `npm install @storybook/cli@0.0.0-pr-23508-sha-5ec8c1c3`.\n\n<details>\n  <summary>Isn't there a simpler/smarter way to do this?</summary>\n\nThe simple approach would be to release canaries for all pull requests automatically; however, this would be insecure as any contributor with Write privileges to the repository (200+ users) could create a malicious pull request that alters the release script to release a malicious release (e.g., release a patch version that adds a crypto miner).\n\nTo alleviate this, we only allow the \"Release\" GitHub environment that contains the npm token to be accessible from workflows running on the protected branches (`next`, `main`, etc.).\n\nYou could also be tempted to require approval from admins before running the workflows. However, this would spam the core team with GitHub notifications for workflow runs seeking approval - even when a core team member triggered the workflow. Therefore we are doing it the other way around, requiring contributors and maintainers to ask for a canary release to be created explicitly.\n\nInstead of triggering the workflow manually, you could also do something smart, like trigger it when there's a specific label on the pull request or when someone writes a specific comment on the pull request. However, this would create a lot of unnecessary workflow runs because there isn't a way to filter workflow runs based on labels or comment content. The only way to achieve this would be to trigger the workflow on every comment/labeling, then cancel it if it didn't contain the expected content, which is inefficient.\n\n</details>\n\n## Versioning Scenarios\n\nThere are multiple types of releases that use the same principles, but are done somewhat differently.\n\n### Prereleases - `7.1.0-alpha.12` -> `7.1.0-alpha.13`\n\nThis is the default strategy for Non-patch releases, there's nothing special needed to trigger this scenario.\n\n### Prerelease promotions - `7.1.0-alpha.13` -> `7.1.0-beta.0`\n\nTo promote a prerelease to a new prerelease ID, during the [Re-trigger the Workflow](#4-re-trigger-the-workflow) step, choose:\n\n- Release type: Prerelease\n- Prerelease ID: The ID to promote to. For example, for alpha to beta, write \"beta\".\n\n### Minor/major releases - `7.1.0-rc.2` -> `7.1.0` or `8.0.0-rc.3` -> `8.0.0`\n\nTo promote a prerelease to a stable reelase, during the [Re-trigger the Workflow](#4-re-trigger-the-workflow) step, choose:\n\n- Release type: Patch, Minor or Major\n- Prerelease ID: Leave empty\n\nThis scenario is special as it will target `latest-release` instead of `next-release`, and thus merge into `main` when done, and not `next`. So it goes `next` -> `version-non-patch-from-<CURRENT-VERSION-ON_NEXT>` -> `latest-release` -> `main`.\n\n### First prerelease of new major/minor - `7.1.0` -> `7.2.0-alpha.0` or `8.0.0-alpha.0`\n\nThis is the first prerelease after a stable major/minor has been released. The default versioning strategy for prereleases won't work here, because it will do `7.1.0` -> `7.1.1-0`. You need to use the workflow inputs to bump the major/minor correctly:\n\n- Release type: Premajor for `8.0.0-alpha.0` or Preminor for `7.2.0-alpha.0`\n- Prerelease ID: \"alpha\"\n\n### Patch releases to stable - subset of `7.1.0-alpha.13` -> `7.0.14`\n\nThis is the default patch release scenario, which cherry picks patches to `main`.\n\n### Patch releases to earlier versions - subset of `7.1.0-alpha.13` -> `6.5.14`\n\nThis happens so rarely on a case by case basis, so this is a completely manual process. The Releaser will find the git tag that matches the patch to bump, eg. `v6.5.14`, check it out, make the necessary changes and follow [the manual release process](#releasing-locally-in-case-of-emergency-🚨).\n\n### Prerelease of upcoming patch release - `7.0.20` -> `7.0.21-alpha.0`\n\nIn some cases, a patch change is so big and complex that it makes sense to first release it as a prerelease of the current patch stable version to see if it works, before releasing it to stable shortly thereafter.\n\nNo process is defined for this.\n\n### Merges to `main` without versioning\n\nAs described in more details in [the Patch Releases section](#patch-releases), there are scenarios where you want to patch [unreleasable](#which-changes-are-considered-releasable-and-what-does-it-mean) content back to `main` without bumping versions or publishing a new release. This happens automatically as long as all the unpicked patch pull requests have unreleasable labels. In that case the prepared patch pull request will change form slightly, to just cherry-picking the patches without bumping the versions.\n\n## FAQ\n\n### When should I use the \"patch:yes\" label?\n\nNot all pull requests need to be patched back to the stable release, which is why only those with the **\"patch:yes\"** label gets that treatment. But how do you decide whether or not a give pull requests should have that label?\n\nFirst of all, patches are only for important and time-sensitive fixes, and not minor improvements or completely new features. A pull request that introduces a new feature shouldn't be patched back to the stable release.\n\nSecond, PRs that changes the code in a big architectural way should ideally not be patched back either, because that makes merge conflicts more likely in the future.\n\nWhen in doubt ask the core team for their input.\n\n### How do I make changes to the release tooling/process?\n\nThe whole process is based on [GitHub Action workflows](../.github/workflows/) and [scripts](../scripts/release/), so you can modify them if you know what you're doing.\n\nThe short answer to \"how\", is to make changes as a regular pull request that is also patched back to `main`.\n\n<details>\n  <summary>There's a longer answer too, but it's pretty confusing</summary>\n\nThe scripts run from either `main` or `next`, so if you're changing a release script, you must patch it back to `main` for it to have an effect on patch releases. If you need the change to take effect immediately, you must manually cherry pick it to `main`.\n\nFor workflow file changes, they usually run from `next`, but patching them back is recommended for consistency. The \"publish\" workflow runs from `latest-release` and `next-release`, so you should always patch changes back for _that_. 🙃\n\n</details>\n\n### Why do I need to re-trigger workflows to update the changelog?\n\nChanges to pull requests' titles, labels or even reverts won't be reflected in the release pull request. This is because the workflow only triggers on pushes to `next`, not when pull request meta data is changed.\n\nTherefore, if you've made any changes to pull requests, you must re-trigger the workflow manually to regenerate the changelog and the version bump. You could also make the changes to the changelog manually, but it means that the pull requests and their title/labels are no longer the single source of truth.\n\n### Which combination of inputs creates the version bump I need?\n\nEach versioning scenario including how to trigger it with inputs is described in [Versioning Scenarios](#versioning-scenarios). You can also see [the tests for the versioning script](https://github.com/storybookjs/storybook/blob/next/scripts/release/__tests__/version.test.ts#L137-L161) to determine which inputs create which outputs.\n\n### Which changes are considered \"releasable\", and what does it mean?\n\nA specific set of labels define which kind of change a pull request is, and whether it is a \"releasable\" change or not. Releasable changes will appear in the changelog and will trigger version bumps, while unreleasable changes will not.\n\nThe exact list of labels and their type is written [here](https://github.com/storybookjs/storybook/blob/next/scripts/release/utils/get-changes.ts#L9-L21). Currently, releasable labels are:\n\n- BREAKING CHANGE\n- Feature request\n- Bug\n- Maintenance\n- Dependencies\n\nAnd unreleasable labels are:\n\n- Documentation\n- Build\n\nIf a pull request does not have any of the above labels at the time of release, it is considered an unreleasable change. Unreleasable changes are changes that do not affect the user through releases. Documentation-only changes are unreleasable, because they are not part of packages and do not change behavior. Similarly, \"build\" changes are only internal-facing and do not change behavior. This could be tests, CI, etc.\n\n### Why are no release PRs being prepared?\n\nThis is most likely because `next` only contains [unreleasable changes](#which-changes-are-considered-releasable-and-what-does-it-mean), which causes the preparation workflow to cancel itself. That's because it doesn't make sense to prepare a new release if all the changes are unreleasable, as that wouldn't bump the version nor write a new changelog entry, so \"releasing\" it would just merge it back to `next` without any differences.\n\nYou can always see the workflows and if they have been cancelled [here for non-patch releases](https://github.com/storybookjs/storybook/actions/workflows/prepare-non-patch-release.yml) and [here for patch releases](https://github.com/storybookjs/storybook/actions/workflows/prepare-patch-release.yml).\n\n### Why do we need separate release branches?\n\nA simpler branching approach would be to merge the versioning branches back to `main` or `next` instead of `latest-release` or `next-release`, and then trigger the publishing directly on that branch. That is what tools like [Changesets](https://github.com/changesets/changesets) do.\n\nThe problem with that is you could end up publishing changes that were not part of the prepared pull request, and thus not part of QA nor the changelog.\n\nFor example, if the Releaser is creating a new release with the frozen branch and another team member merges a new pull request - \"some-simultaneous-bugfix - to `next` _during_ the QA steps:\n\n```mermaid\n%%{init: { 'gitGraph': { 'mainBranchName': 'next' } } }%%\ngitGraph\n    commit type: HIGHLIGHT\n    branch new-feature\n    commit\n    commit\n    checkout next\n    merge new-feature type: HIGHLIGHT\n    branch some-simultaneous-bugfix\n    commit\n    checkout next\n    branch version-non-patch-from-7.1.0-alpha.28\n    commit id\n    checkout next\n    merge some-simultaneous-bugfix type: HIGHLIGHT id: \"whoops!\"\n    merge version-non-patch-from-7.1.0-alpha.28 tag: \"v7.1.0-alpha.29\"\n```\n\nWhen publishing at the last commit with tag `v7.1.0-alpha.29`, it will publish whatever the content is at that point (all the square dots), which includes the \"whoops!\" commit from merging the bugfix. But the bugfix was never part of the release pull request because it got prepared before the bugfix was merged in.\n\nIf we instead publish from `next-release` and then merge to `next`, the bugfix won't be part of the current release, but the next one:\n\n```mermaid\n%%{init: { 'gitGraph': { 'mainBranchName': 'next' } } }%%\ngitGraph\n    commit type: HIGHLIGHT\n    branch next-release\n    branch new-feature\n    commit\n    commit\n    checkout next\n    merge new-feature type: HIGHLIGHT\n    branch some-simultanous-bugfix\n    commit\n    checkout next\n    branch version-non-patch-from-7.1.0-alpha.28\n    commit id: \"write changelog\"\n    checkout next\n    merge some-simultanous-bugfix id: \"whoops!\"\n    checkout next-release\n    merge version-non-patch-from-7.1.0-alpha.28\n    commit id: \"bump versions\" tag: \"v7.1.0-alpha.29\"\n    checkout next\n    merge next-release\n    branch version-non-patch-from-7.1.0-alpha.29\n    commit id: \"write changelog again\"\n    checkout next-release\n    merge version-non-patch-from-7.1.0-alpha.29\n    commit id: \"bump versions again\" tag: \"v7.1.0-alpha.30\"\n    checkout next\n    merge next-release\n```\n\nThis is because the way that \"unreleased\" changes are found is to list all the commits that are part of the current history of `HEAD`, _except_ for the commits that are part of the history of the latest version tag. And since the bugfix is not part of the history of the previous version, it will be included.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributors Guide\n> Tip: If you want to make a fast contribution, check the “good first issue” label in the Issues tab for small frontend and docs tasks that are easy to fix directly on GitHub.\n\n\nWe welcome contributions of any type and skill level. As an open-source project, we believe in the power of community and welcome any contributions that help us improve Storybook. Whether you are a developer, designer, writer, or someone who wants to help, we'd love to have you on board. If you are interested in contributing, please read the following guidelines.\n\nWhether you're new to open source or a seasoned contributor, we welcome all contributions. Here are a few ways you can contribute to Storybook: \n\n- [Create an RFC](https://storybook.js.org/docs/contribute/RFC) for feature requests\n- Update our [documentation](https://storybook.js.org/docs/contribute/documentation/documentation-updates) with fixes, improvements, or clarifications\n- Add [new examples](https://storybook.js.org/docs/contribute/documentation/new-snippets) of code snippets for using Storybook with a JS framework\n- [Integrate Storybook with a JS framework](https://storybook.js.org/docs/contribute/framework) or improve support of existing frameworks\n- [Write an addon](https://storybook.js.org/docs/addons) to extend Storybook's functionality\n\nIf you're not sure where to start, you can always help us by:\n\n- [Reporting a bug](https://github.com/storybookjs/storybook/issues/new/choose)\n- Answer [Help](https://github.com/storybookjs/storybook/discussions/categories/help?discussions_q=is%3Aopen+category%3AHelp) questions on Storybook's GitHub discussions\n- [Browse `Good First Issue`s to fix](https://github.com/storybookjs/storybook/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)\n\n> **Note**: Before you start contributing, please read the [Code of Conduct](./CODE_OF_CONDUCT.md) and reach out to the maintainers if you have any questions or concerns about the project or the contribution process on the [`#contributing`](https://discord.com/channels/486522875931656193/839297503446695956) channel on Discord.\n\n## Quick guide \n\n### Prerequisites \n\nStorybook is developed against a specific Node.js version specified in the `.nvmrc` file.\nYou can use any version manager to install the correct version of Node.js. We recommend using [fnm](https://github.com/Schniz/fnm).\n\n1. Check if you have the correct version of Node.js installed by running the following command:\n  \n  ```shell\n  # Check which version you're using\n  node --version\n  # node version manager\n  nvm use 22\n  # pnpm\n  pnpm env use --global 22\n  ```\n\n2. Install [fnm](https://github.com/Schniz/fnm/tree/master?tab=readme-ov-file#installation) and adjust your shell configuration to include the following parameters: `fnm env`, `use-on-cd`, `corepack-enabled`, and `version-file-strategy recursive`.\n   \n   ```shell\n   eval \"$(fnm env --use-on-cd --corepack-enabled --version-file-strategy recursive)\"\n   ```\n\n3. If you're a Windows user, you'll need to enable Windows Subsystem for Linux (WSL). You can follow the instructions [here](https://docs.microsoft.com/en-us/windows/wsl/install).\n\n### Running the local development environment\n\n- All commands should be run in a terminal with administrator privileges in Windows environments.\n\n### What's inside?\n\nStorybook uses a monorepo structure to manage the project and its packages.\nHere's a highlight of notable directories and files:\n\n```shell\n.\n├── CHANGELOG.md                  # Changelog for current version of Storybook\n├── CHANGELOG.prerelease.md\n├── CHANGELOG.v1-5.md\n├── CHANGELOG.v6.md\n├── CODEOWNERS\n├── CODE_OF_CONDUCT.md\n├── CONTRIBUTING                  # Info relevant for maintainers\n├── CONTRIBUTING.md               <--------- You are here!\n├── LICENSE\n├── MAINTAINERS.md\n├── MIGRATION.md                  # Migration Guide for Storybook\n├── README.md\n├── RESOLUTIONS.md\n├── SECURITY.md\n├── code                         # Codebase for Storybook\n│   ├── __mocks__\n│   ├── addons\n│   ├── bench\n│   ├── builders\n│   ├── chromatic.config.json\n│   ├── core                     # Core package for UI and API of Storybook\n│   ├── e2e-tests\n│   ├── frameworks               # Different framework-bundler versions of Storybook\n│   ├── lib                      # CLI and plugins\n│   ├── node_modules\n│   ├── nx.json\n│   ├── package.json\n│   ├── playwright.config.ts\n│   ├── presets                  # Preset packages\n│   ├── .oxfmtrc.json\n│   ├── renderers                # Storybook renderers for different frameworks\n│   ├── sandbox                  # Sandboxes for Bug Reproductions or experimentation\n│   ├── tsconfig.json\n│   ├── vitest-setup.ts\n│   ├── vitest.config.ts\n│   ├── vitest.helpers.ts\n│   └── vitest.workspace.ts\n├── codecov.yml\n├── dependabot.yml\n├── docs                         # Documentation\n│   ├── _assets\n│   ├── _snippets\n│   ├── addons\n│   ├── api\n│   ├── builders\n│   ├── configure\n│   ├── contribute\n│   ├── essentials\n│   ├── faq.mdx\n│   ├── frameworks.js\n│   ├── get-started\n│   ├── index.mdx\n│   ├── migration-guide\n│   ├── sharing\n│   ├── versions\n│   ├── writing-docs\n│   ├── writing-stories\n│   └── writing-tests\n├── node_modules\n├── package.json                      # Root of the yarn monorepo\n├── .oxfmtrc.json\n├── scripts                           # Build and Helper Scripts\n├── test-storybooks\n│   ├── ember-cli\n│   ├── external-docs\n│   ├── portable-stories-kitchen-sink\n│   ├── server-kitchen-sink\n│   └── standalone-preview\n└── yarn.lock\n```\n\n### Fork the repository \n\nIf you plan to contribute to Storybook's codebase, you should fork the repository to your GitHub account. This will allow you to make changes to the codebase and submit a pull request to the main repository when you're ready to contribute your changes.\n\nAdditionally, adding our codebase as upstream ensures you can rebase against the latest changes in the main repository. To do this, run the following commands:\n\n```shell\ngit remote add upstream https://github.com/storybookjs/storybook.git\ngit fetch upstream\ngit branch --set-upstream-to upstream/main main\n```\n\n### Running the local development environment \n\nIf you're interested in contributing to Storybook's codebase, you can run it locally to get a feel for the codebase and the development environment. To get started with the development environment, you should always run `yarn start` from the root directory. Running `yarn start` will install the required dependencies, build the project, including the packages, and generate a sandbox environment using React with TypeScript with a set of test stories to help you get started.\n\n```shell\n# Navigate to the root directory of the Storybook repository \ncd path/to/your/storybook/fork \n\n# Install the required dependencies\nyarn\n# start the development environment \nyarn start\n```\n\n### Making code changes \n\nIf you want to make code changes to Storybook packages while running a sandbox, you'll need to do the following: \n\n1. In a second terminal, run `yarn build --watch <package-1> <package-2>` in the `code/` directory.\n\nFor example, to build the `@storybook/react`, `storybook` itself, `@storybook/builder-vite`, and `@storybook/addon-docs` packages, you would run: \n\n```shell \n# Navigate to the code directory \ncd path/to/your/storybook/fork/code \n\n# Build the specified packages in watch mode \nyarn build --watch react core-server api addon-docs \n\nMost package names can be found after `@storybook/` in the published package.\n\nFor instance, to build the `@storybook/react storybook @storybook/builder-vite @storybook/addon-docs` packages at the same time in watch mode:\n\n```shell \ncd code\nyarn build --watch react storybook builder-vite addon-docs \n```\n\n2. If you are running the sandbox in [\"linked\"](https://yarnpkg.com/cli/link) mode (the default), you should see the changes reflected on a refresh (you may need to restart it if changing server packages) \n\n3. If you are running the sandbox in \"unlinked\" mode, you'll need to rerun the sandbox from the `publish` step to see the changes: \n\n```shell \nyarn task --task dev --template <your template> --start-from=publish \n``` \n\n4. If you have made any changes inside `/code` or other packages, remember to run `yarn test` inside the package to ensure that your changes do not break any tests. \n\n### Angular-specific code\n\nIf you are working on Angular-specific code, you will need to append `--prod` to the above mentioned commands to ensure that the Angular compiler is able to pick up the changes appropriately and doesn't fail. This will build all the packages in production mode.\n\n```shell\n# Starts the build process in production mode\nyarn task --prod\n```\n\n```shell\n# Builds the specified packages in production mode\nyarn build --prod --watch angular storybook addon-docs\n```\n\n### Running against different sandbox templates \n\nYou can pick a specific template to use as your sandbox by running `yarn task`, which will prompt you to make further choices about which template you want and which task you want to run.\n\n### Focussing on fixing a sandbox in CI\n\nOur CI runs many sandboxes, especially when selecting the `ci:daily` workflow.\n\nWhen a particular sandbox is failing, it's preferred to debug locally, but if this is somehow not possible, you can force the Ci to focus on a selection of sandboxes instead of running all. Here's the process of how:\n\nInside of here you can edit the filter-function:\nhttps://github.com/storybookjs/storybook/blob/3d49093954243d4d520774243866de840f298bf4/scripts/ci/main.ts#L70-L88\n\nIn fact you can filter on any job you wish, only running `test-runner`, `e2e`, `vite`-sandboxes, etc.\n\n## Troubleshooting \n\n### The initialization process throws an error \n\nIf you run `yarn start` and encounter the following error, try rerunning `yarn start` a second time: \n\n```shell \n> NX ENOENT: no such file or directory, open 'storybook/code/node_modules/nx/package.json' \n```\n\n### Storybook doesn't detect changes in the codebase \n\nIf you are a Storybook contributor and still experience issues, it is recommended that you verify your local Storybook instance for any unintentional local changes. To do this, you can use the following command: \n\n```shell \ngit clean -dx --dry-run \n``` \n\nBy executing this command, you can see which untracked or ignored files and directories will be removed from your working directory if you run it with the `--force` flag. Before running the command with the `--force` flag, please commit any local changes you want to keep. Otherwise, they will be lost.\n\n## Contributing to Storybook \n\nFor further advice on contributing, please refer to our [NEW contributing guide on the Storybook website](https://storybook.js.org/docs/contribute).\n"
  },
  {
    "path": "CONTRIBUTING.old.md",
    "content": "<h1>Contributing to Storybook</h1>\n\n- [Issues](#issues)\n  - [Testing against `main`](#testing-against-main)\n    - [1. Download the latest version of this project, and build it:](#1-download-the-latest-version-of-this-project-and-build-it)\n    - [2a. Run unit tests](#2a-run-unit-tests)\n      - [Core & Examples Tests](#core--examples-tests)\n    - [2b. Run Linter](#2b-run-linter)\n  - [Reproductions](#reproductions)\n    - [In the monorepo](#in-the-monorepo)\n    - [Outside the monorepo](#outside-the-monorepo)\n  - [Updating Tests](#updating-tests)\n- [Pull Requests (PRs)](#pull-requests-prs)\n  - [Reviewing PRs](#reviewing-prs)\n- [Issue Triage](#issue-triage)\n  - [Responding to issues](#responding-to-issues)\n  - [Triaging issues](#triaging-issues)\n  - [Closing issues](#closing-issues)\n- [Development Guide](#development-guide)\n  - [Prerequisites](#prerequisites)\n  - [Initial Setup](#initial-setup)\n    - [Bootstrapping everything](#bootstrapping-everything)\n    - [Building specific packages](#building-specific-packages)\n  - [Working with the kitchen sink apps](#working-with-the-kitchen-sink-apps)\n    - [React and Vue](#react-and-vue)\n  - [Working with your own app](#working-with-your-own-app)\n    - [Linking Storybook](#linking-storybook)\n    - [Connecting Your App To Storybook](#connecting-your-app-to-storybook)\n      - [1. Setup storybook in your project](#1-setup-storybook-in-your-project)\n      - [2. Link](#2-link)\n    - [Verify your local version is working](#verify-your-local-version-is-working)\n  - [Documentation](#documentation)\n- [Release Guide](#release-guide)\n    - [Prerelease:](#prerelease)\n    - [Full release:](#full-release)\n\nThanks for your interest in improving Storybook! We are a community-driven project and welcome contributions of all kinds: from discussion to documentation to bugfixes to feature improvements.\n\nPlease review this document to help to streamline the process and save everyone's precious time.\n\nThis repo uses yarn workspaces, so you should install `yarn` as the package manager. See [installation guide](https://yarnpkg.com/en/docs/install).\n\n## Issues\n\nNo software is bug-free. So, if you got an issue, follow these steps:\n\n- Search the [issue list](https://github.com/storybookjs/storybook/issues) for current and old issues.\n  - If you find an existing issue, please UPVOTE the issue by adding a \"thumbs-up reaction\". We use this to help prioritize issues!\n- If none of that is helping, create an issue with the following information:\n  - Clear title (shorter is better).\n  - Describe the issue in clear language.\n  - Share error logs, screenshots and etc.\n  - To speed up the issue fixing process, send us a sample repo with the issue you faced:\n\n### Testing against `main`\n\nTo test your project against the current latest version of storybook, you can clone the repository and link it with `yarn`. Try following these steps:\n\n#### 1. Download the latest version of this project, and build it:\n\n```sh\ngit clone https://github.com/storybookjs/storybook.git\ncd storybook\nyarn bootstrap\n```\n\n> **_Note:_** On Windows, you may need to run `yarn` before `yarn bootstrap`!\n\nThe bootstrap command might ask which sections of the codebase you want to bootstrap. Unless you're doing something special you can keep the default.\n\nYou can also pick directly from CLI:\n\n```sh\nyarn bootstrap --core\n```\n\n#### 2a. Run unit tests\n\nYou can use one of the example projects in `examples/` to develop on.\n\nThis command will list all the suites and options for running tests.\n\n```sh\nyarn test\n```\n\nThe options for running tests can be selected from the cli or be passed to `yarn test` with specific parameters. Available modes include `--watch`, `--coverage`, and `--runInBand`, which will respectively run tests in watch mode, output code coverage, and run selected test suites serially in the current process.\n\nYou can use the `--update` flag (or `jest -u`) to update snapshots or screenshots as needed.\n\n> **_Note:_** On Windows, remember to make sure git config `core.autocrlf` is set to false, in order to not override EOL in snapshots ( `git config --global core.autocrlf false` to set it globally). It is also recommended to run tests from WSL2 to avoid errors with unix-style paths.\n\nYou can also pick suites from CLI. Suites available are listed below.\n\n##### Core & Examples Tests\n\n`yarn test`\n\nThis option executes tests from `<rootdir>/app/react`, `<rootdir>/app/vue`, and `<rootdir>/lib`.\nBefore the tests are run, the project must be bootstrapped with core. You can accomplish this with `yarn bootstrap --core`\n\n#### 2b. Run Linter\n\nWe use eslint as a linter for all code (including typescript code).\n\nAll you have to run is:\n\n```sh\nyarn lint\n```\n\nIt can be immensely helpful to get feedback in your editor, if you're using VsCode, you should install the `eslint` plugin and configure it with these settings:\n\n```json\n{\n  \"editor.codeActionsOnSave\": {\n    \"source.fixAll.eslint\": true\n  },\n  \"eslint.packageManager\": \"yarn\",\n  \"eslint.options\": {\n    \"cache\": true,\n    \"cacheLocation\": \".cache/eslint\",\n    \"extensions\": [\".js\", \".jsx\", \".json\", \".html\", \".ts\", \".tsx\", \".mjs\"]\n  },\n  \"eslint.alwaysShowStatus\": true\n}\n```\n\nThis should enable auto-fix for all source files, and give linting warnings and errors within your editor.\n\n### Reproductions\n\n#### In the monorepo\n\nThe best way to help figure out an issue you are having is to produce a minimal reproduction against the `main` branch.\n\nA good way to do that is using the example `official-storybook` app embedded in this repository:\n\n```sh\n# Download and build this repository:\ngit clone https://github.com/storybookjs/storybook.git\ncd storybook\nyarn\nyarn bootstrap --core\n\n# make changes to try and reproduce the problem, such as adding components + stories\ncd examples/official-storybook\nyarn storybook\n\n# see if you can see the problem, if so, commit it:\ngit checkout \"branch-describing-issue\"\ngit add -A\ngit commit -m \"reproduction for issue #123\"\n\n# fork the storybook repo to your account, then add the resulting remote\ngit remote add <your-username> https://github.com/<your-username>/storybook.git\ngit push -u <your-username> next\n```\n\nIf you follow that process, you can then link to the GitHub repository in the issue. See <https://github.com/storybookjs/storybook/issues/708#issuecomment-290589886> for an example.\n\n**_Note:_** If your issue involves a webpack config, create-react-app will prevent you from modifying the _app's_ webpack config, however, you can still modify storybook's to mirror your app's version of the storybook. Alternatively, use `yarn eject` in the CRA app to get a modifiable webpack config.\n\n#### Outside the monorepo\n\nSometimes your storybook is deeply ingrained in your own setup and it's hard to create a minimal viable reproduction somewhere else.\n\nInside the storybook repo we have a script that allows you to test the packages inside this repo in your own separate project.\n\nYou can use `npm link` on all packages, but npm linking is cumbersome and has subtle differences from what happens in a registry-based installation.\nSo the way our script works is that it:\n\n- sets up a npm registry running on your own local machine\n- changes your default registry to this local one\n- builds all packages in the storybook repo\n- publishes all packages as latest\n\nOur script leaves the local registry running, for **as long as you keep it running** you can install storybook packages from this local registry.\n\n- Navigate to your own project and then change `package.json` so the storybook packages match the version of the one you just published.\n- Then you can install using `yarn` or `npm`\n- Start using your storybook as normally.\n\nIf you've made a change to storybook's codebase and would want this change to be reflected in your app:\n\n- Ensure the storybook packages are transpiled, by either having run `yarn dev` or `yarn bootstrap --core`.\n- Go to the terminal where the local registry is running and press `<Enter>`. This will kick off a new publish.\n- Run the install procedure again in your local repo, (you may need to clean out node_modules first).\n- Restart your storybook.\n\n### Updating Tests\n\nBefore any contributions are submitted in a PR, make sure to add or update meaningful tests. A PR that has failing tests will be regarded as a “Work in Progress” and will not be merged until all tests pass.\n\nWhen creating new unit test files, the tests should adhere to a particular folder structure and naming convention, as defined below.\n\n```sh\n# Proper naming convention and structure for js tests files\n+-- parentFolder\n|   +-- [filename].js\n|   +-- [filename].test.js\n```\n\n## Pull Requests (PRs)\n\nWe welcome all contributions. There are many ways you can help us. This is few of those ways:\n\nBefore you submit a new PR, make sure you run `yarn test`. Do not submit a PR if tests are failing. If you need any help, the best way is to [join the discord server and ask in the maintenance channel](https://discord.gg/storybook).\n\n### Reviewing PRs\n\n**As a PR submitter**, you should reference the issue if there is one, include a short description of what you contributed and, if it is a code change, instructions for how to manually test out the change. This is informally enforced by our [PR template](https://github.com/storybookjs/storybook/blob/main/.github/PULL_REQUEST_TEMPLATE.md). If your PR is reviewed as only needing trivial changes (e.g. small typos etc), and you have commit access then you can merge the PR after making those changes.\n\n> **_Note:_** Although the latest stable version of storybook corresponds to the `main` branch, nearly all Storybook development happens in the `next` branch. If you submit a PR, branch off `next` and target your PR to `next`.\n\n**As a PR reviewer**, you should read through the changes and comment on any potential problems. If you see something cool, a kind word never hurts either! Additionally, you should follow the testing instructions and manually test the changes. If the instructions are missing, unclear, or overly complex, feel free to request better instructions from the submitter. Unless the PR is tagged with the `do not merge` label, if you approve the review and there is no other required discussion or changes, you should also go ahead and merge the PR.\n\n## Issue Triage\n\nIf you are looking for a way to help the project, triaging issues is a great place to start. Here's how you can help:\n\n### Responding to issues\n\nIssues that are tagged `question / support` or `needs reproduction` are great places to help. If you can answer a question, it will help the asker as well as anyone who has a similar question. Also in the future if anyone has that same question they can easily find it by searching. If an issue needs reproduction, you may be able to guide the reporter toward one, or even reproduce it yourself using [this technique](https://github.com/storybookjs/storybook/blob/main/CONTRIBUTING.md#reproductions).\n\n### Triaging issues\n\nOnce you've helped out on a few issues, if you'd like triage access you can help label issues and respond to reporters.\n\nWe use the following label scheme to categorize issues:\n\n- **type** - `bug`, `feature`, `question / support`, `discussion`, `dependencies`, `maintenance`.\n- **area** - `addon: x`, `addons-api`, `stories-api`, `ui`, etc.\n- **status** - `needs reproduction`, `needs PR`, `in progress`, etc.\n\nAll issues should have a `type` label. `bug`/`feature`/`question`/`discussion` are self-explanatory. `dependencies` is for keeping package dependencies up to date. `maintenance` is a catch-all for any kind of cleanup or refactoring.\n\nThey should also have one or more `area`/`status` labels. We use these labels to filter issues down so we can see all of the issues for a particular area, and keep the total number of open issues under control.\n\nFor example, here is the list of [open, untyped issues](https://github.com/storybookjs/storybook/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20-label%3A%22bug%22%20-label%3A%22discussion%22%20-label%3A%22feature%22%20-label%3A%22maintenance%22%20-label%3A%22question%20%2F%20support%22%20-label%3A%22documentation%22%20-label%3A%22greenkeeper%22), or here is a list of [bugs that have not been modified since 2017-04-01](https://github.com/storybookjs/storybook/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3A%22bug%22%20updated%3A%3C%3D2017-04-01%20). For more info see [searching issues](https://help.github.com/articles/searching-issues/) in the GitHub docs.\n\nIf an issue is a `bug`, and it doesn't have a clear reproduction that you have personally confirmed, label it `needs reproduction` and ask the author to try and create a reproduction, or have a go yourself.\n\n### Closing issues\n\n- Duplicate issues should be closed with a link to the original.\n- Unreproducible issues should be closed if it's not possible to reproduce them (if the reporter drops offline,\n  it is reasonable to wait 2 weeks before closing).\n- `bug`s should be labelled `merged` when merged, and be closed when the issue is fixed and released.\n- `feature`s, `maintenance`s, `greenkeeper`s should be labelled `merged` when merged,\n  and closed when released or if the feature is deemed not appropriate.\n- `question / support`s should be closed when the question has been answered.\n  If the questioner drops offline, a reasonable period to wait is two weeks.\n- `discussion`s should be closed at a maintainer's discretion.\n\n## Development Guide\n\n### Prerequisites\n\nPlease have the **_latest_** stable versions of the following on your machine\n\n- node\n- yarn\n\n### Initial Setup\n\nIf you run into trouble here, make sure your node, npm, and **_yarn_** are on the latest versions (yarn at least v1.3.2).\n\n1.  `cd ~` (optional)\n2.  `git clone https://github.com/storybookjs/storybook.git` _bonus_: use your own fork for this step\n3.  `cd storybook`\n4.  `yarn bootstrap --core`\n\n> **_Note:_** On Windows, you may need to run `yarn` before `yarn bootstrap` (between steps 3 and 4).\n\nThis builds the entire project statically, but when you're updating Storybook code it's nice to see those changes show up in the example apps under `examples`. There are two ways to do this:\n\n1.  `yarn dev`\n2.  OR `yarn build <package1> <package2> --watch`\n\nThe former watches ALL packages, which is extremely slow. The latter only watches a fixed list of packages, e.g. `yarn build add-docs components --watch` to build `@storybook/addon-docs` and `@storybook/components`. This is much more practical on slower machines or if you know ahead of time the packages you'll be updating.\n\n#### Bootstrapping everything\n\n_This method is slow_\n\n1.  `yarn bootstrap --all`\n2.  Take a break 🍵\n3.  `yarn test` (to verify everything worked)\n\n#### Building specific packages\n\nIf you're working on one or several packages, for every change that you make, you have to rebuild those packages. To make the process easier, there is a CLI command for that:\n\n- Run `yarn build` to bring you a list of packages to select from. There will be also an option to run in watch mode.\n- Run `yarn build <package-name>` to build that package specifically. \\\n  For the package name, use its short version. Example: for `@storybook/addon-docs`, run `yarn build addon-docs`.\n- Run `yarn build --all` to build everything.\n- Add `--watch` to run automatically in watch mode if you are either building a selection of packages by name or building all.\n  Example: `yarn build core addon-docs --watch` or `yarn build --all --watch`.\n\n### Working with the kitchen sink apps\n\nWithin the `examples` folder of the Storybook repo, you will find kitchen sink examples of storybook implementations for the various platforms that storybook supports.\n\nNot only do these show many of the options and add-ons available, they are also automatically linked to all the development packages. We highly encourage you to use these to develop/test contributions on.\n\n#### React and Vue\n\n1. `cd examples/official-storybook`\n2. `yarn storybook`\n3. Verify that your local version works\n\n### Working with your own app\n\n#### Linking Storybook\n\nStorybook is broken up into sub-projects that you can install as you need them. For this example, we will be working with `@storybook/react`.\n\n**_Note:_** You need to `yarn link` from inside the subproject you are working on **_NOT_** the storybook root directory.\n\n1.  `cd app/react`\n2.  `yarn link`\n\n#### Connecting Your App To Storybook\n\n**_Note:_** If you aren't seeing addons after linking storybook, you probably have a versioning issue which can be fixed by linking each addon you want to use.\nThis applies for the kitchen sink apps as well as your own projects.\n\n_Make sure `yarn dev` is running_\n\n##### 1. Setup storybook in your project\n\nFirst we are going to install storybook, then we are going to link `@storybook/react` into our project. This will replace `node_modules/@storybook/react` with a symlink to our local version of storybook.\n\n1.  `getstorybook`\n2.  `yarn storybook`\n3.  Verify that your local version works\n\n##### 2. Link\n\n**_Note:_** This process is the same for `@storybook/vue`, `@storybook/addon-foo`, etc\n\n1.  Go to your storybook _root_ directory\n2.  `yarn dev`\n3.  Wait until the output stops (changes you make will be transpiled into dist and logged here)\n4.  Go to your storybook-sandbox-app directory\n5.  `yarn link @storybook/react`\n6.  `yarn storybook`\n\n#### Verify your local version is working\n\nYou should now have a working storybook dev environment up and running.\n\nSave and go to `http://localhost:9011` (or wherever storybook is running).\n\nIf you don't see the changes rerun `yarn storybook` again in your sandbox app.\n\n### Documentation\n\nThe documentation for Storybook is served by the [frontpage](https://github.com/storybookjs/frontpage), but the docs files are in this repository.\n\nTo see changes in a development version of the docs, use the \"linking\" method documented [here](https://github.com/storybookjs/frontpage#docs-content).\n\n## Release Guide\n\nThis section is for Storybook maintainers who will be creating releases. It assumes:\n\n- yarn >= 1.3.2\n- you've yarn linked `pr-log` from <https://github.com/storybookjs/pr-log/pull/2>\n\nThe current manual release sequence is as follows:\n\n- Generate a changelog and verify the release by hand\n- Push the changelog to main or the release branch\n- Clean, build and publish the release\n- Cut and paste the changelog to the [GitHub release page](https://github.com/storybookjs/storybook/releases), and mark it as a (pre-) release\n\n**_Note:_** The very first time you publish a scoped package (`@storybook/x`) you need to make sure that its package.json contains the following\n\n```js\n\"publishConfig\": {\n  \"access\": \"public\"\n}\n```\n\nThis sequence applies to both releases and pre-releases, but differs slightly between the two.\n\n**_Note:_ This is a work in progress. Don't try this unless you know what you're doing. We hope to automate this in CI, so this process is designed with that in mind.**\n\n#### Prerelease:\n\n```sh\n# make sure you current with origin/next.\ngit checkout next\ngit status\n\n# generate changelog and edit as appropriate\n# generates a Next section\nyarn changelog:next x.y.z-alpha.a\n\n# Edit the changelog/PRs as needed, then commit\ngit commit -m \"x.y.z-alpha.a changelog\"\n\n# clean build\nyarn bootstrap --reset --core\n\n# publish and tag the release\nyarn run publish:next\n\n# update the release page\nopen https://github.com/storybookjs/storybook/releases\n```\n\n#### Full release:\n\n```sh\n# make sure you current with origin/main.\ngit checkout main\ngit status\n\n# generate changelog and edit as appropriate\n# generates a vNext section\nyarn changelog x.y.z\n\n# Edit the changelog/PRs as needed, then commit\ngit commit -m \"x.y.z changelog\"\n\n# clean build\nyarn bootstrap --reset --core\n\n# publish and tag the release\nyarn run publish:latest\n\n# update the release page\nopen https://github.com/storybookjs/storybook/releases\n```\n"
  },
  {
    "path": "MAINTAINERS.md",
    "content": "This document outlines some of the processes that the maintainers should adhere to.\n\n# PR Process\n\n1. Triage with the correct [label](#labels)\n2. If there is a change related to it, ensure it has been published and tested before closing\n\n# Labels\n\n| label name                     | purpose                                                                                                                                              |\n| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |\n| accessibility                  | Issue, bug, or pull request related to accessibility                                                                                                 |\n| addon:(name)                   | Issue, bug, or pull request related to Storybook addons (e.g., [Controls](/docs/essentials/controls.mdx))                                            |\n| app:(name)                     | Issue, bug, or pull request related to Storybook's supported frameworks (e.g., React)                                                                |\n| api:(name)                     | Issue, bug, or pull request related to Storybook's API (e.g.,[makeDecorator](/docs/addons/addons-api.mdx#makeDecorator-API))                         |\n| args                           | Issue, bug, or pull request related to Storybook's [args](/docs/writing-stories/args.mdx)                                                            |\n| babel/webpack                  | Issue, bug, or pull request related to Storybook's build system (e.g., Webpack or Babel), for Webpack 5 issues see below                             |\n| block:(name)                   | Issue or bug within a certain surface are of Storybook (e.g., [argTypes](/docs/api/doc-blocks/doc-block-argtypes.mdx))                               |\n| BREAKING CHANGE                | Issue or pull request that introduces a breaking change within Storybook's ecosystem.                                                                |\n| BREAKING PRERELASE             | Breaking, but only for prerelease users (not relative to the stable release)                                                                         |\n| build-storybook                | Issue, bug, or pull request related to Storybook's production build                                                                                  |\n| cleanup                        | Minor cleanup style change that won't show up in release changelog                                                                                   |\n| bug                            | A bug within Storybook                                                                                                                               |\n| cli                            | Issue, bug, or pull request that affects the Storybook's CLI                                                                                         |\n| compatibility with other tools | Issue, bug, or pull request between Storybook and other tools (e.g., [Nuxt](https://nuxtjs.org/))                                                    |\n| components                     | Issue, bug, or pull request related to Storybook's internal components                                                                               |\n| composition                    | Issue, bug, or pull request related to Storybook [Composition](/docs/sharing/storybook-composition.mdx)                                              |\n| configuration                  | Issue, bug, or pull request related to Storybook [configuration](/docs/configure/index.mdx)                                                          |\n| core                           | Issue, bug, or pull request related to Storybook's Core                                                                                              |\n| cra                            | Issue, bug, or pull request that affects Storybook's compatibility with Create React APP ([CRA](https://create-react-app.dev/docs/getting-started/)) |\n| CSF                            | Issue, bug, or pull request related to Storybook's [Component Story Format (CSF)](/docs/api/csf.mdx)                                                 |\n| decorators                     | Issue, bug, or pull related to Storybook's [Decorators](/docs/writing-stories/decorators.mdx)                                                        |\n| dependencies                   | Issue, bug, or pull request that related to upstream dependencies                                                                                    |\n| discussion                     | Issue currently being discussed between the maintainers and community                                                                                |\n| do not merge                   | Pull request that will introduce regressions and will not be merged                                                                                  |\n| documentation                  | Issue, bug, or pull request that affects Storybook's documentation                                                                                   |\n| duplicate                      | Question or issue already asked in the repo's issues                                                                                                 |\n| feature request                | Request for a new feature to be included in Storybook                                                                                                |\n| flow                           | Issue, bug, or pull request related to Storybook and Flow                                                                                            |\n| Funded on Issuehunt            | Storybook issue funded on [IssueHunt](https://issuehunt.io/)                                                                                         |\n| gatsby                         | Issue, bug, or pull request that affects Storybook and [Gatsby](https://www.gatsbyjs.com/)                                                           |\n| good first issue               | Low impact Storybook issues that help new members get involved and start contributing                                                                |\n| has workaround                 | Issue or bug that has an alternative way to be solved with Storybook                                                                                 |\n| help wanted                    | Issue, or bug that requires additional help from the community                                                                                       |\n| ie11                           | Issue, bug, or pull request related to Storybook and IE11                                                                                            |\n| in progress                    | Issue or pull request that is currently being reviewed or worked on with the author                                                                  |\n| inactive                       | Issue, or pull request that has gone stale and no active development has been done                                                                   |\n| maintenance                    | Issue, or pull request related to Storybook's internal maintenance                                                                                   |\n| mdx                            | Issue, bug, or pull request related to MDX and Storybook                                                                                             |\n| medium                         | Issue or pull request that involves a significant amount of work within Storybook                                                                    |\n| monorepos                      | Issue, bug, or pull request related to Storybook and monorepos                                                                                       |\n| mui                            | Issue, bug, or pull request that affects Storybook and [Material-UI](https://material-ui.com/)                                                       |\n| multiframework                 | Issue, bug, or pull request that affects multiple supported frameworks (e.g., React, Vue)                                                            |\n| needs more info                | Issue, or bug that requires additional context from the author                                                                                       |\n| needs reproduction             | Issue, or bug that requires a reproduction to be looked at                                                                                           |\n| needs triage                   | Issue, bug, or pull request that requires further investigation from the maintainers                                                                 |\n| nextjs                         | Issue, bug, or pull request related to Storybook's integration with [Next.js](https://nextjs.org/)                                                   |\n| nx                             | Issue, bug, or pull request related to Storybook's integration with [NX](https://nx.dev/)                                                            |\n| other                          | Storybook's miscellaneous issue or pull request                                                                                                      |\n| P(n)                           | Bug or issue priority. Ranges from `0` (most urgent) to `N` (least urgent)                                                                           |\n| patch                          | Bug fix and documentation pull request that will be picked to the main branch                                                                        |\n| performance issue              | Issue, bug or pull request that affects Storybook's performance                                                                                      |\n| picked                         | Patch PRs cherry-picked to the main branch                                                                                                           |\n| presets                        | Issue, bug, or pull requests that affect Storybook's presets                                                                                         |\n| question / support             | General question about Storybook                                                                                                                     |\n| run e2e extended test suite    | Pull request that affects Storybook's testing suite                                                                                                  |\n| search                         | Issue, bug or pull request related to Storybook's search functionality                                                                               |\n| security                       | Issue, bug, or pull request that addresses security with Storybook                                                                                   |\n| small                          | Issue or pull request that requires a small amount of work to be done                                                                                |\n| source-loader                  | Issue, bug, or pull request related to code display within Storybook's stories                                                                       |\n| theming                        | Issue, bug, or pull request related to Storybook customization (e.g., [theming](/docs/configure/user-interface/theming.mdx))                         |\n| todo                           | Issue or pull request currently being worked on                                                                                                      |\n| typescript                     | Issue, bug, or pull request related to TypeScript                                                                                                    |\n| ui                             | Issue, bug, or pull request related to Storybook's UI                                                                                                |\n| webpack5                       | Issue, bug, or pull request related to Webpack 5                                                                                                     |\n| won't fix                      | Issue or pull request that won't be addressed by the maintainers (e.g., introduces a regression)                                                     |\n| yarn/npm                       | Issue or pull request related to node package managers                                                                                               |\n"
  },
  {
    "path": "MIGRATION.md",
    "content": "<h1>Migration</h1>\n\n- [From version 10.0.0 to 10.1.0](#from-version-1000-to-1010)\n  - [API and Component Changes](#api-and-component-changes)\n    - [Button Component API Changes](#button-component-api-changes)\n      - [Added: ariaLabel](#added-arialabel)\n      - [Added: shortcut](#added-shortcut)\n      - [Added: tooltip](#added-tooltip)\n      - [Deprecated: active](#deprecated-active)\n    - [IconButton is deprecated](#iconbutton-is-deprecated)\n    - [Bar Component API Changes](#bar-component-api-changes)\n      - [Added: innerStyle](#added-innerstyle)\n    - [FlexBar is deprecated](#flexbar-is-deprecated)\n    - [Tabs is deprecated](#tabs-is-deprecated)\n    - [TabsState is deprecated](#tabsstate-is-deprecated)\n    - [TabWrapper is deprecated](#tabwrapper-is-deprecated)\n    - [TabButton is deprecated](#tabbutton-is-deprecated)\n    - [TabBar is deprecated](#tabbar-is-deprecated)\n    - [Modal Component API Changes](#modal-component-api-changes)\n      - [Deprecated: onInteractOutside](#deprecated-oninteractoutside)\n      - [Deprecated: onEscapeKeyDown](#deprecated-onescapekeydown)\n      - [Added: `ariaLabel`](#added-arialabel-1)\n      - [Renamed: Modal.Dialog.Close and Modal.CloseButton](#renamed-modaldialogclose-and-modalclosebutton)\n    - [ListItem, TooltipLinkList and TooltipMessage are deprecated](#listitem-tooltiplinklist-and-tooltipmessage-are-deprecated)\n    - [PopoverProvider Component Added](#popoverprovider-component-added)\n      - [Added: ariaLabel](#added-arialabel-2)\n    - [WithTooltip Component API Changes](#withtooltip-component-api-changes)\n      - [Removed: trigger](#removed-trigger)\n    - [Added: triggerOnFocusOnly](#added-triggeronfocusonly)\n    - [Renamed: startOpen](#renamed-startopen)\n    - [Removed: svg, strategy, withArrows, mutationObserverOptions](#removed-svg-strategy-witharrows-mutationobserveroptions)\n    - [Removed: hasChrome](#removed-haschrome)\n    - [Removed: closeOnTriggerHidden, followCursor, closeOnOutsideClick](#removed-closeontriggerhidden-followcursor-closeonoutsideclick)\n    - [Removed: interactive](#removed-interactive)\n      - [Other changes](#other-changes)\n    - [WithTooltipPure and WithTooltipState are deprecated](#withtooltippure-and-withtooltipstate-are-deprecated)\n    - [Link isButton is deprecated](#link-isbutton-is-deprecated)\n- [From version 9.x to 10.0.0](#from-version-9x-to-1000)\n  - [Core Changes](#core-changes)\n    - [Local addons must be fully resolved](#local-addons-must-be-fully-resolved)\n    - [The `.storybook/main.*` file and other presets must be valid ESM](#the-storybookmain-file-and-other-presets-must-be-valid-esm)\n    - [Node.js 20.19+ or 22.12+ required](#nodejs-2019-or-2212-required)\n    - [Require `tsconfig.json` `moduleResolution` set to value that supports `types` condition](#require-tsconfigjson-moduleresolution-set-to-value-that-supports-types-condition)\n    - [`core.builder` configuration must be a fully resolved path](#corebuilder-configuration-must-be-a-fully-resolved-path)\n    - [Removed x-only builtin tags](#removed-x-only-builtin-tags)\n- [From version 8.x to 9.0.0](#from-version-8x-to-900)\n  - [Core Changes and Removals](#core-changes-and-removals)\n    - [Dropped support for legacy packages](#dropped-support-for-legacy-packages)\n    - [Dropped support](#dropped-support)\n      - [Vite 4](#vite-4)\n      - [TypeScript \\< 4.9](#typescript--49)\n      - [Node.js \\< 20](#nodejs--20)\n      - [Package Managers](#package-managers)\n    - [Moving from renderer-based to framework-based configuration](#moving-from-renderer-based-to-framework-based-configuration)\n  - [Addon-specific Changes](#addon-specific-changes)\n    - [Essentials Addon: Viewport, Controls, Interactions and Actions moved to core](#essentials-addon-viewport-controls-interactions-and-actions-moved-to-core)\n    - [A11y Addon: Removed deprecated manual parameter](#a11y-addon-removed-deprecated-manual-parameter)\n    - [A11y Addon: Replace `element` parameter with `context` parameter](#a11y-addon-replace-element-parameter-with-context-parameter)\n    - [Experimental Test Addon: Stabilized and renamed](#experimental-test-addon-stabilized-and-renamed)\n    - [Vitest Addon (former @storybook/experimental-addon-test): Vitest 2.0 support is dropped](#vitest-addon-former-storybookexperimental-addon-test-vitest-20-support-is-dropped)\n    - [Viewport/Backgrounds Addon synchronized configuration and `globals` usage](#viewportbackgrounds-addon-synchronized-configuration-and-globals-usage)\n    - [Storysource Addon removed](#storysource-addon-removed)\n    - [Mdx-gfm Addon removed](#mdx-gfm-addon-removed)\n  - [API and Component Changes](#api-and-component-changes-1)\n    - [Button Component API Changes](#button-component-api-changes-1)\n    - [Icon System Updates](#icon-system-updates)\n    - [Sidebar Component Changes](#sidebar-component-changes)\n    - [Story Store API Changes](#story-store-api-changes)\n    - [Global State Management](#global-state-management)\n    - [Experimental Status API has turned into a Status Store](#experimental-status-api-has-turned-into-a-status-store)\n    - [`experimental_afterEach` has been stabilized](#experimental_aftereach-has-been-stabilized)\n    - [Testing Module Changes](#testing-module-changes)\n    - [Consolidate `@storybook/blocks` into addon docs](#consolidate-storybookblocks-into-addon-docs)\n  - [Configuration and Type Changes](#configuration-and-type-changes)\n    - [Manager builder removed alias for `util`, `assert` and `process`](#manager-builder-removed-alias-for-util-assert-and-process)\n    - [Type System Updates](#type-system-updates)\n    - [CSF File Changes](#csf-file-changes)\n    - [React-Native config dir renamed](#react-native-config-dir-renamed)\n    - [`parameters.docs.source.format` removal](#parametersdocssourceformat-removal)\n    - [`parameter docs.source.excludeDecorators` has no effect in React](#parameter-docssourceexcludedecorators-has-no-effect-in-react)\n    - [Documentation Generation Changes](#documentation-generation-changes)\n  - [Framework-specific changes](#framework-specific-changes)\n    - [Svelte: Require v5 and up](#svelte-require-v5-and-up)\n    - [Svelte: Dropped support for @storybook/svelte-webpack5](#svelte-dropped-support-for-storybooksvelte-webpack5)\n    - [Svelte: Dropped automatic docgen for events and slots](#svelte-dropped-automatic-docgen-for-events-and-slots)\n    - [Angular: Require v18 and up](#angular-require-v18-and-up)\n    - [Angular: Introduce `features.angularFilterNonInputControls`](#angular-introduce-featuresangularfilternoninputcontrols)\n    - [Dropped webpack5 Builder Support in Favor of Vite](#dropped-webpack5-builder-support-in-favor-of-vite)\n    - [Next.js: Require v14 and up](#nextjs-require-v14-and-up)\n    - [Next.js: Vite builder stabilized](#nextjs-vite-builder-stabilized)\n    - [Lit = Require v3 and up](#lit--require-v3-and-up)\n- [From version 8.5.x to 8.6.x](#from-version-85x-to-86x)\n  - [Angular: Support experimental zoneless support](#angular-support-experimental-zoneless-support)\n  - [Addon-a11y: Replaced experimental `ally-test` tag behavior with `parameters.a11y.test`](#addon-a11y-replaced-experimental-ally-test-tag-behavior-with-parametersa11ytest)\n- [From version 8.4.x to 8.5.x](#from-version-84x-to-85x)\n  - [React Vite: react-docgen-typescript is updated](#react-vite-react-docgen-typescript-is-updated)\n  - [Introducing features.developmentModeForBuild](#introducing-featuresdevelopmentmodeforbuild)\n  - [Added source code panel to docs](#added-source-code-panel-to-docs)\n  - [Addon-a11y: Component test integration](#addon-a11y-component-test-integration)\n  - [Addon-a11y: Changing the default element selector](#addon-a11y-changing-the-default-element-selector)\n  - [Addon-a11y: Deprecated `parameters.a11y.manual`](#addon-a11y-deprecated-parametersa11ymanual)\n  - [Addon-test: You should no longer copy the content of `viteFinal` to your configuration](#addon-test-you-should-no-longer-copy-the-content-of-vitefinal-to-your-configuration)\n  - [Addon-test: Indexing behavior of @storybook/experimental-addon-test is changed](#addon-test-indexing-behavior-of-storybookexperimental-addon-test-is-changed)\n- [From version 8.2.x to 8.3.x](#from-version-82x-to-83x)\n  - [Removed `experimental_SIDEBAR_BOTTOM` and deprecated `experimental_SIDEBAR_TOP` addon types](#removed-experimental_sidebar_bottom-and-deprecated-experimental_sidebar_top-addon-types)\n  - [New parameters format for addon backgrounds](#new-parameters-format-for-addon-backgrounds)\n  - [New parameters format for addon viewport](#new-parameters-format-for-addon-viewport)\n- [From version 8.1.x to 8.2.x](#from-version-81x-to-82x)\n  - [Failed to resolve import \"@storybook/X\" error](#failed-to-resolve-import-storybookx-error)\n  - [Preview.js globals renamed to initialGlobals](#previewjs-globals-renamed-to-initialglobals)\n- [From version 8.0.x to 8.1.x](#from-version-80x-to-81x)\n  - [Portable stories](#portable-stories)\n    - [@storybook/nextjs requires specific path aliases to be setup](#storybooknextjs-requires-specific-path-aliases-to-be-setup)\n  - [main.js `docs.autodocs` is deprecated](#mainjs-docsautodocs-is-deprecated)\n  - [`docs` and `story` system tags removed](#docs-and-story-system-tags-removed)\n  - [Subtitle block and `parameters.componentSubtitle`](#subtitle-block-and-parameterscomponentsubtitle)\n  - [Title block `of` prop](#title-block-of-prop)\n- [From version 7.x to 8.0.0](#from-version-7x-to-800)\n  - [Portable stories](#portable-stories-1)\n    - [Project annotations are now merged instead of overwritten in composeStory](#project-annotations-are-now-merged-instead-of-overwritten-in-composestory)\n    - [Type change in `composeStories` API](#type-change-in-composestories-api)\n    - [Composed Vue stories are now components instead of functions](#composed-vue-stories-are-now-components-instead-of-functions)\n  - [Tab addons are now routed to a query parameter](#tab-addons-are-now-routed-to-a-query-parameter)\n  - [Default keyboard shortcuts changed](#default-keyboard-shortcuts-changed)\n  - [Manager addons are now rendered with React 18](#manager-addons-are-now-rendered-with-react-18)\n  - [Removal of `storiesOf`-API](#removal-of-storiesof-api)\n  - [Removed deprecated shim packages](#removed-deprecated-shim-packages)\n  - [Deprecated `@storybook/testing-library` package](#deprecated-storybooktesting-library-package)\n  - [Framework-specific Vite plugins have to be explicitly added](#framework-specific-vite-plugins-have-to-be-explicitly-added)\n    - [For React:](#for-react)\n    - [For Vue:](#for-vue)\n    - [For Svelte (without Sveltekit):](#for-svelte-without-sveltekit)\n    - [For Preact:](#for-preact)\n    - [For Solid:](#for-solid)\n    - [For Qwik:](#for-qwik)\n  - [TurboSnap Vite plugin is no longer needed](#turbosnap-vite-plugin-is-no-longer-needed)\n  - [`--webpack-stats-json` option renamed `--stats-json`](#--webpack-stats-json-option-renamed---stats-json)\n  - [Implicit actions can not be used during rendering (for example in the play function)](#implicit-actions-can-not-be-used-during-rendering-for-example-in-the-play-function)\n  - [MDX related changes](#mdx-related-changes)\n    - [MDX is upgraded to v3](#mdx-is-upgraded-to-v3)\n    - [Dropping support for \\*.stories.mdx (CSF in MDX) format and MDX1 support](#dropping-support-for-storiesmdx-csf-in-mdx-format-and-mdx1-support)\n    - [Dropping support for id, name and story in Story block](#dropping-support-for-id-name-and-story-in-story-block)\n  - [Core changes](#core-changes-1)\n    - [`framework.options.builder.useSWC` for Webpack5-based projects removed](#frameworkoptionsbuilderuseswc-for-webpack5-based-projects-removed)\n    - [Removed `@babel/core` and `babel-loader` from `@storybook/builder-webpack5`](#removed-babelcore-and-babel-loader-from-storybookbuilder-webpack5)\n    - [`framework.options.fastRefresh` for Webpack5-based projects removed](#frameworkoptionsfastrefresh-for-webpack5-based-projects-removed)\n    - [`typescript.skipBabel` removed](#typescriptskipbabel-removed)\n    - [Dropping support for Yarn 1](#dropping-support-for-yarn-1)\n    - [Dropping support for Node.js 16](#dropping-support-for-nodejs-16)\n    - [Autotitle breaking fixes](#autotitle-breaking-fixes)\n    - [Storyshots has been removed](#storyshots-has-been-removed)\n    - [UI layout state has changed shape](#ui-layout-state-has-changed-shape)\n    - [New UI and props for Button and IconButton components](#new-ui-and-props-for-button-and-iconbutton-components)\n    - [Icons is deprecated](#icons-is-deprecated)\n    - [Removed postinstall](#removed-postinstall)\n    - [Removed stories.json](#removed-storiesjson)\n    - [Removed `sb babelrc` command](#removed-sb-babelrc-command)\n    - [Changed interfaces for `@storybook/router` components](#changed-interfaces-for-storybookrouter-components)\n    - [Extract no longer batches](#extract-no-longer-batches)\n  - [Framework-specific changes](#framework-specific-changes-1)\n    - [React](#react)\n      - [`react-docgen` component analysis by default](#react-docgen-component-analysis-by-default)\n    - [Next.js](#nextjs)\n      - [Require Next.js 13.5 and up](#require-nextjs-135-and-up)\n      - [Automatic SWC mode detection](#automatic-swc-mode-detection)\n      - [RSC config moved to React renderer](#rsc-config-moved-to-react-renderer)\n    - [Vue](#vue)\n      - [Require Vue 3 and up](#require-vue-3-and-up)\n    - [Angular](#angular)\n      - [Require Angular 15 and up](#require-angular-15-and-up)\n    - [Svelte](#svelte)\n      - [Require Svelte 4 and up](#require-svelte-4-and-up)\n    - [Preact](#preact)\n      - [Require Preact 10 and up](#require-preact-10-and-up)\n      - [No longer adds default Babel plugins](#no-longer-adds-default-babel-plugins)\n    - [Web Components](#web-components)\n      - [Dropping default babel plugins in Webpack5-based projects](#dropping-default-babel-plugins-in-webpack5-based-projects)\n  - [Deprecations which are now removed](#deprecations-which-are-now-removed)\n    - [Removed `config` preset](#removed-config-preset)\n    - [Removed `passArgsFirst` option](#removed-passargsfirst-option)\n    - [Methods and properties from AddonStore](#methods-and-properties-from-addonstore)\n    - [Methods and properties from PreviewAPI](#methods-and-properties-from-previewapi)\n    - [Removals in @storybook/components](#removals-in-storybookcomponents)\n    - [Removals in @storybook/types](#removals-in-storybooktypes)\n    - [--use-npm flag in storybook CLI](#--use-npm-flag-in-storybook-cli)\n    - [hideNoControlsWarning parameter from addon controls](#hidenocontrolswarning-parameter-from-addon-controls)\n    - [`setGlobalConfig` from `@storybook/react`](#setglobalconfig-from-storybookreact)\n    - [StorybookViteConfig type from @storybook/builder-vite](#storybookviteconfig-type-from-storybookbuilder-vite)\n    - [props from WithTooltipComponent from @storybook/components](#props-from-withtooltipcomponent-from-storybookcomponents)\n    - [LinkTo direct import from addon-links](#linkto-direct-import-from-addon-links)\n    - [DecoratorFn, Story, ComponentStory, ComponentStoryObj, ComponentStoryFn and ComponentMeta TypeScript types](#decoratorfn-story-componentstory-componentstoryobj-componentstoryfn-and-componentmeta-typescript-types)\n    - [\"Framework\" TypeScript types](#framework-typescript-types)\n    - [`navigateToSettingsPage` method from Storybook's manager-api](#navigatetosettingspage-method-from-storybooks-manager-api)\n    - [storyIndexers](#storyindexers)\n    - [Deprecated docs parameters](#deprecated-docs-parameters)\n    - [Description Doc block properties](#description-doc-block-properties)\n    - [Story Doc block properties](#story-doc-block-properties)\n    - [Manager API expandAll and collapseAll methods](#manager-api-expandall-and-collapseall-methods)\n    - [`ArgsTable` Doc block removed](#argstable-doc-block-removed)\n    - [`Source` Doc block properties](#source-doc-block-properties)\n    - [`Canvas` Doc block properties](#canvas-doc-block-properties)\n    - [`Primary` Doc block properties](#primary-doc-block-properties)\n    - [`createChannel` from `@storybook/postmessage` and `@storybook/channel-websocket`](#createchannel-from-storybookpostmessage-and-storybookchannel-websocket)\n    - [StoryStore and methods deprecated](#storystore-and-methods-deprecated)\n  - [Addon author changes](#addon-author-changes)\n    - [Tab addons cannot manually route, Tool addons can filter their visibility via tabId](#tab-addons-cannot-manually-route-tool-addons-can-filter-their-visibility-via-tabid)\n    - [Removed `config` preset](#removed-config-preset-1)\n- [From version 7.5.0 to 7.6.0](#from-version-750-to-760)\n    - [CommonJS with Vite is deprecated](#commonjs-with-vite-is-deprecated)\n    - [Using implicit actions during rendering is deprecated](#using-implicit-actions-during-rendering-is-deprecated)\n    - [typescript.skipBabel deprecated](#typescriptskipbabel-deprecated)\n    - [Primary doc block accepts of prop](#primary-doc-block-accepts-of-prop)\n    - [Addons no longer need a peer dependency on React](#addons-no-longer-need-a-peer-dependency-on-react)\n- [From version 7.4.0 to 7.5.0](#from-version-740-to-750)\n    - [`storyStoreV6` and `storiesOf` is deprecated](#storystorev6-and-storiesof-is-deprecated)\n    - [`storyIndexers` is replaced with `experimental_indexers`](#storyindexers-is-replaced-with-experimental_indexers)\n- [From version 7.0.0 to 7.2.0](#from-version-700-to-720)\n    - [Addon API is more type-strict](#addon-api-is-more-type-strict)\n    - [Addon-controls hideNoControlsWarning parameter is deprecated](#addon-controls-hidenocontrolswarning-parameter-is-deprecated)\n- [From version 6.5.x to 7.0.0](#from-version-65x-to-700)\n  - [7.0 breaking changes](#70-breaking-changes)\n    - [Dropped support for Node 15 and below](#dropped-support-for-node-15-and-below)\n    - [Default export in Preview.js](#default-export-in-previewjs)\n    - [ESM format in Main.js](#esm-format-in-mainjs)\n    - [Modern browser support](#modern-browser-support)\n    - [React peer dependencies required](#react-peer-dependencies-required)\n    - [start-storybook / build-storybook binaries removed](#start-storybook--build-storybook-binaries-removed)\n    - [New Framework API](#new-framework-api)\n      - [Available framework packages](#available-framework-packages)\n      - [Framework field mandatory](#framework-field-mandatory)\n      - [frameworkOptions renamed](#frameworkoptions-renamed)\n      - [builderOptions renamed](#builderoptions-renamed)\n    - [TypeScript: StorybookConfig type moved](#typescript-storybookconfig-type-moved)\n    - [Titles are statically computed](#titles-are-statically-computed)\n    - [Framework standalone build moved](#framework-standalone-build-moved)\n    - [Change of root html IDs](#change-of-root-html-ids)\n    - [Stories glob matches MDX files](#stories-glob-matches-mdx-files)\n    - [Add strict mode](#add-strict-mode)\n    - [Importing plain markdown files with `transcludeMarkdown` has changed](#importing-plain-markdown-files-with-transcludemarkdown-has-changed)\n    - [Stories field in .storybook/main.js is mandatory](#stories-field-in-storybookmainjs-is-mandatory)\n    - [Stricter global types](#stricter-global-types)\n    - [Deploying build artifacts](#deploying-build-artifacts)\n      - [Dropped support for file URLs](#dropped-support-for-file-urls)\n      - [Serving with nginx](#serving-with-nginx)\n      - [Ignore story files from node\\_modules](#ignore-story-files-from-node_modules)\n  - [7.0 Core changes](#70-core-changes)\n    - [7.0 feature flags removed](#70-feature-flags-removed)\n    - [Story context is prepared before for supporting fine grained updates](#story-context-is-prepared-before-for-supporting-fine-grained-updates)\n    - [Changed decorator order between preview.js and addons/frameworks](#changed-decorator-order-between-previewjs-and-addonsframeworks)\n    - [Dark mode detection](#dark-mode-detection)\n    - [`addons.setConfig` should now be imported from `@storybook/manager-api`.](#addonssetconfig-should-now-be-imported-from-storybookmanager-api)\n  - [7.0 core addons changes](#70-core-addons-changes)\n    - [Removed auto injection of @storybook/addon-actions decorator](#removed-auto-injection-of-storybookaddon-actions-decorator)\n    - [Addon-backgrounds: Removed deprecated grid parameter](#addon-backgrounds-removed-deprecated-grid-parameter)\n    - [Addon-a11y: Removed deprecated withA11y decorator](#addon-a11y-removed-deprecated-witha11y-decorator)\n    - [Addon-interactions: Interactions debugger is now default](#addon-interactions-interactions-debugger-is-now-default)\n  - [7.0 Vite changes](#70-vite-changes)\n    - [Vite builder uses Vite config automatically](#vite-builder-uses-vite-config-automatically)\n    - [Vite cache moved to node\\_modules/.cache/.vite-storybook](#vite-cache-moved-to-node_modulescachevite-storybook)\n  - [7.0 Webpack changes](#70-webpack-changes)\n    - [Webpack4 support discontinued](#webpack4-support-discontinued)\n    - [Babel mode v7 exclusively](#babel-mode-v7-exclusively)\n    - [Postcss removed](#postcss-removed)\n    - [Removed DLL flags](#removed-dll-flags)\n  - [7.0 Framework-specific changes](#70-framework-specific-changes)\n    - [Angular: Removed deprecated `component` and `propsMeta` field](#angular-removed-deprecated-component-and-propsmeta-field)\n    - [Angular: Drop support for Angular \\< 14](#angular-drop-support-for-angular--14)\n    - [Angular: Drop support for calling Storybook directly](#angular-drop-support-for-calling-storybook-directly)\n    - [Angular: Application providers and ModuleWithProviders](#angular-application-providers-and-modulewithproviders)\n    - [Angular: Removed legacy renderer](#angular-removed-legacy-renderer)\n    - [Angular: Initializer functions](#angular-initializer-functions)\n    - [Next.js: use the `@storybook/nextjs` framework](#nextjs-use-the-storybooknextjs-framework)\n    - [SvelteKit: needs the `@storybook/sveltekit` framework](#sveltekit-needs-the-storybooksveltekit-framework)\n    - [Vue3: replaced app export with setup](#vue3-replaced-app-export-with-setup)\n    - [Web-components: dropped lit-html v1 support](#web-components-dropped-lit-html-v1-support)\n    - [Create React App: dropped CRA4 support](#create-react-app-dropped-cra4-support)\n    - [HTML: No longer auto-dedents source code](#html-no-longer-auto-dedents-source-code)\n  - [7.0 Addon authors changes](#70-addon-authors-changes)\n    - [New Addons API](#new-addons-api)\n      - [Specific instructions for addon creators](#specific-instructions-for-addon-creators)\n      - [Specific instructions for addon users](#specific-instructions-for-addon-users)\n    - [register.js removed](#registerjs-removed)\n    - [No more default export from `@storybook/addons`](#no-more-default-export-from-storybookaddons)\n    - [No more configuration for manager](#no-more-configuration-for-manager)\n    - [Icons API changed](#icons-api-changed)\n    - [Removed global client APIs](#removed-global-client-apis)\n    - [framework parameter renamed to renderer](#framework-parameter-renamed-to-renderer)\n  - [7.0 Docs changes](#70-docs-changes)\n    - [Autodocs changes](#autodocs-changes)\n    - [MDX docs files](#mdx-docs-files)\n    - [Unattached docs files](#unattached-docs-files)\n    - [Doc Blocks](#doc-blocks)\n      - [Meta block](#meta-block)\n      - [Description block, `parameters.notes` and `parameters.info`](#description-block-parametersnotes-and-parametersinfo)\n      - [Story block](#story-block)\n      - [Source block](#source-block)\n      - [Canvas block](#canvas-block)\n      - [ArgsTable block](#argstable-block)\n    - [Configuring Autodocs](#configuring-autodocs)\n    - [MDX2 upgrade](#mdx2-upgrade)\n    - [Legacy MDX1 support](#legacy-mdx1-support)\n    - [Default docs styles will leak into non-story user components](#default-docs-styles-will-leak-into-non-story-user-components)\n    - [Explicit `<code>` elements are no longer syntax highlighted](#explicit-code-elements-are-no-longer-syntax-highlighted)\n    - [Dropped source loader / storiesOf static snippets](#dropped-source-loader--storiesof-static-snippets)\n    - [Removed docs.getContainer and getPage parameters](#removed-docsgetcontainer-and-getpage-parameters)\n    - [Addon-docs: Removed deprecated blocks.js entry](#addon-docs-removed-deprecated-blocksjs-entry)\n    - [Dropped addon-docs manual babel configuration](#dropped-addon-docs-manual-babel-configuration)\n    - [Dropped addon-docs manual configuration](#dropped-addon-docs-manual-configuration)\n    - [Autoplay in docs](#autoplay-in-docs)\n    - [Removed STORYBOOK\\_REACT\\_CLASSES global](#removed-storybook_react_classes-global)\n  - [7.0 Deprecations and default changes](#70-deprecations-and-default-changes)\n    - [storyStoreV7 enabled by default](#storystorev7-enabled-by-default)\n    - [`Story` type deprecated](#story-type-deprecated)\n    - [`ComponentStory`, `ComponentStoryObj`, `ComponentStoryFn` and `ComponentMeta` types are deprecated](#componentstory-componentstoryobj-componentstoryfn-and-componentmeta-types-are-deprecated)\n    - [Renamed `renderToDOM` to `renderToCanvas`](#renamed-rendertodom-to-rendertocanvas)\n    - [Renamed `XFramework` to `XRenderer`](#renamed-xframework-to-xrenderer)\n    - [Renamed `DecoratorFn` to `Decorator`](#renamed-decoratorfn-to-decorator)\n    - [CLI option `--use-npm` deprecated](#cli-option---use-npm-deprecated)\n    - ['config' preset entry replaced with 'previewAnnotations'](#config-preset-entry-replaced-with-previewannotations)\n- [From version 6.4.x to 6.5.0](#from-version-64x-to-650)\n  - [Vue 3 upgrade](#vue-3-upgrade)\n  - [React18 new root API](#react18-new-root-api)\n  - [Renamed isToolshown to showToolbar](#renamed-istoolshown-to-showtoolbar)\n  - [Dropped support for addon-actions addDecorators](#dropped-support-for-addon-actions-adddecorators)\n  - [Vite builder renamed](#vite-builder-renamed)\n  - [Docs framework refactor for React](#docs-framework-refactor-for-react)\n  - [Opt-in MDX2 support](#opt-in-mdx2-support)\n  - [CSF3 auto-title improvements](#csf3-auto-title-improvements)\n    - [Auto-title filename case](#auto-title-filename-case)\n    - [Auto-title redundant filename](#auto-title-redundant-filename)\n    - [Auto-title always prefixes](#auto-title-always-prefixes)\n  - [6.5 Deprecations](#65-deprecations)\n    - [Deprecated register.js](#deprecated-registerjs)\n- [From version 6.3.x to 6.4.0](#from-version-63x-to-640)\n  - [Automigrate](#automigrate)\n  - [CRA5 upgrade](#cra5-upgrade)\n  - [CSF3 enabled](#csf3-enabled)\n    - [Optional titles](#optional-titles)\n    - [String literal titles](#string-literal-titles)\n    - [StoryObj type](#storyobj-type)\n  - [Story Store v7](#story-store-v7)\n    - [Behavioral differences](#behavioral-differences)\n    - [Main.js framework field](#mainjs-framework-field)\n    - [Using the v7 store](#using-the-v7-store)\n    - [v7-style story sort](#v7-style-story-sort)\n    - [v7 default sort behavior](#v7-default-sort-behavior)\n    - [v7 Store API changes for addon authors](#v7-store-api-changes-for-addon-authors)\n    - [Storyshots compatibility in the v7 store](#storyshots-compatibility-in-the-v7-store)\n  - [Emotion11 quasi-compatibility](#emotion11-quasi-compatibility)\n  - [Babel mode v7](#babel-mode-v7)\n  - [Loader behavior with args changes](#loader-behavior-with-args-changes)\n  - [6.4 Angular changes](#64-angular-changes)\n    - [SB Angular builder](#sb-angular-builder)\n    - [Angular13](#angular13)\n    - [Angular component parameter removed](#angular-component-parameter-removed)\n  - [6.4 deprecations](#64-deprecations)\n    - [Deprecated --static-dir CLI flag](#deprecated---static-dir-cli-flag)\n- [From version 6.2.x to 6.3.0](#from-version-62x-to-630)\n  - [Webpack 5](#webpack-5)\n    - [Fixing hoisting issues](#fixing-hoisting-issues)\n      - [Webpack 5 manager build](#webpack-5-manager-build)\n      - [Wrong webpack version](#wrong-webpack-version)\n  - [Angular 12 upgrade](#angular-12-upgrade)\n  - [Lit support](#lit-support)\n  - [No longer inferring default values of args](#no-longer-inferring-default-values-of-args)\n  - [6.3 deprecations](#63-deprecations)\n    - [Deprecated addon-knobs](#deprecated-addon-knobs)\n    - [Deprecated scoped blocks imports](#deprecated-scoped-blocks-imports)\n    - [Deprecated layout URL params](#deprecated-layout-url-params)\n- [From version 6.1.x to 6.2.0](#from-version-61x-to-620)\n  - [MDX pattern tweaked](#mdx-pattern-tweaked)\n  - [6.2 Angular overhaul](#62-angular-overhaul)\n    - [New Angular storyshots format](#new-angular-storyshots-format)\n    - [Deprecated Angular story component](#deprecated-angular-story-component)\n    - [New Angular renderer](#new-angular-renderer)\n    - [Components without selectors](#components-without-selectors)\n  - [Packages now available as ESModules](#packages-now-available-as-esmodules)\n  - [6.2 Deprecations](#62-deprecations)\n    - [Deprecated implicit PostCSS loader](#deprecated-implicit-postcss-loader)\n    - [Deprecated default PostCSS plugins](#deprecated-default-postcss-plugins)\n    - [Deprecated showRoots config option](#deprecated-showroots-config-option)\n    - [Deprecated control.options](#deprecated-controloptions)\n    - [Deprecated storybook components html entry point](#deprecated-storybook-components-html-entry-point)\n- [From version 6.0.x to 6.1.0](#from-version-60x-to-610)\n  - [Addon-backgrounds preset](#addon-backgrounds-preset)\n  - [Single story hoisting](#single-story-hoisting)\n  - [React peer dependencies](#react-peer-dependencies)\n  - [6.1 deprecations](#61-deprecations)\n    - [Deprecated DLL flags](#deprecated-dll-flags)\n    - [Deprecated storyFn](#deprecated-storyfn)\n    - [Deprecated onBeforeRender](#deprecated-onbeforerender)\n    - [Deprecated grid parameter](#deprecated-grid-parameter)\n    - [Deprecated package-composition disabled parameter](#deprecated-package-composition-disabled-parameter)\n- [From version 5.3.x to 6.0.x](#from-version-53x-to-60x)\n  - [Hoisted CSF annotations](#hoisted-csf-annotations)\n  - [Zero config typescript](#zero-config-typescript)\n  - [Correct globs in main.js](#correct-globs-in-mainjs)\n  - [CRA preset removed](#cra-preset-removed)\n  - [Core-JS dependency errors](#core-js-dependency-errors)\n  - [Args passed as first argument to story](#args-passed-as-first-argument-to-story)\n  - [6.0 Docs breaking changes](#60-docs-breaking-changes)\n    - [Remove framework-specific docs presets](#remove-framework-specific-docs-presets)\n    - [Preview/Props renamed](#previewprops-renamed)\n    - [Docs theme separated](#docs-theme-separated)\n    - [DocsPage slots removed](#docspage-slots-removed)\n    - [React prop tables with Typescript](#react-prop-tables-with-typescript)\n    - [ConfigureJSX true by default in React](#configurejsx-true-by-default-in-react)\n    - [User babelrc disabled by default in MDX](#user-babelrc-disabled-by-default-in-mdx)\n    - [Docs description parameter](#docs-description-parameter)\n    - [6.0 Inline stories](#60-inline-stories)\n  - [New addon presets](#new-addon-presets)\n  - [Removed babel-preset-vue from Vue preset](#removed-babel-preset-vue-from-vue-preset)\n  - [Removed Deprecated APIs](#removed-deprecated-apis)\n  - [New setStories event](#new-setstories-event)\n  - [Removed renderCurrentStory event](#removed-rendercurrentstory-event)\n  - [Removed hierarchy separators](#removed-hierarchy-separators)\n  - [No longer pass denormalized parameters to storySort](#no-longer-pass-denormalized-parameters-to-storysort)\n  - [Client API changes](#client-api-changes)\n    - [Removed Legacy Story APIs](#removed-legacy-story-apis)\n    - [Can no longer add decorators/parameters after stories](#can-no-longer-add-decoratorsparameters-after-stories)\n    - [Changed Parameter Handling](#changed-parameter-handling)\n  - [Simplified Render Context](#simplified-render-context)\n  - [Story Store immutable outside of configuration](#story-store-immutable-outside-of-configuration)\n  - [Improved story source handling](#improved-story-source-handling)\n  - [6.0 Addon API changes](#60-addon-api-changes)\n    - [Consistent local addon paths in main.js](#consistent-local-addon-paths-in-mainjs)\n    - [Deprecated setAddon](#deprecated-setaddon)\n    - [Deprecated disabled parameter](#deprecated-disabled-parameter)\n    - [Actions addon uses parameters](#actions-addon-uses-parameters)\n    - [Removed action decorator APIs](#removed-action-decorator-apis)\n    - [Removed withA11y decorator](#removed-witha11y-decorator)\n    - [Essentials addon disables differently](#essentials-addon-disables-differently)\n    - [Backgrounds addon has a new api](#backgrounds-addon-has-a-new-api)\n  - [6.0 Deprecations](#60-deprecations)\n    - [Deprecated addon-info, addon-notes](#deprecated-addon-info-addon-notes)\n    - [Deprecated addon-contexts](#deprecated-addon-contexts)\n    - [Removed addon-centered](#removed-addon-centered)\n    - [Deprecated polymer](#deprecated-polymer)\n    - [Deprecated immutable options parameters](#deprecated-immutable-options-parameters)\n    - [Deprecated addParameters and addDecorator](#deprecated-addparameters-and-adddecorator)\n    - [Deprecated clearDecorators](#deprecated-cleardecorators)\n    - [Deprecated configure](#deprecated-configure)\n    - [Deprecated support for duplicate kinds](#deprecated-support-for-duplicate-kinds)\n- [From version 5.2.x to 5.3.x](#from-version-52x-to-53x)\n  - [To main.js configuration](#to-mainjs-configuration)\n    - [Using main.js](#using-mainjs)\n    - [Using preview.js](#using-previewjs)\n    - [Using manager.js](#using-managerjs)\n  - [Create React App preset](#create-react-app-preset)\n  - [Description doc block](#description-doc-block)\n  - [React Native Async Storage](#react-native-async-storage)\n  - [Deprecate displayName parameter](#deprecate-displayname-parameter)\n  - [Unified docs preset](#unified-docs-preset)\n  - [Simplified hierarchy separators](#simplified-hierarchy-separators)\n  - [Addon StoryShots Puppeteer uses external puppeteer](#addon-storyshots-puppeteer-uses-external-puppeteer)\n- [From version 5.1.x to 5.2.x](#from-version-51x-to-52x)\n  - [Source-loader](#source-loader)\n  - [Default viewports](#default-viewports)\n  - [Grid toolbar-feature](#grid-toolbar-feature)\n  - [Docs mode docgen](#docs-mode-docgen)\n  - [storySort option](#storysort-option)\n- [From version 5.1.x to 5.1.10](#from-version-51x-to-5110)\n  - [babel.config.js support](#babelconfigjs-support)\n- [From version 5.0.x to 5.1.x](#from-version-50x-to-51x)\n  - [React native server](#react-native-server)\n  - [Angular 7](#angular-7)\n  - [CoreJS 3](#corejs-3)\n- [From version 5.0.1 to 5.0.2](#from-version-501-to-502)\n  - [Deprecate webpack extend mode](#deprecate-webpack-extend-mode)\n- [From version 4.1.x to 5.0.x](#from-version-41x-to-50x)\n  - [sortStoriesByKind](#sortstoriesbykind)\n  - [Webpack config simplification](#webpack-config-simplification)\n  - [Theming overhaul](#theming-overhaul)\n  - [Story hierarchy defaults](#story-hierarchy-defaults)\n  - [Options addon deprecated](#options-addon-deprecated)\n  - [Individual story decorators](#individual-story-decorators)\n  - [Addon backgrounds uses parameters](#addon-backgrounds-uses-parameters)\n  - [Addon cssresources name attribute renamed](#addon-cssresources-name-attribute-renamed)\n  - [Addon viewport uses parameters](#addon-viewport-uses-parameters)\n  - [Addon a11y uses parameters, decorator renamed](#addon-a11y-uses-parameters-decorator-renamed)\n  - [Addon centered decorator deprecated](#addon-centered-decorator-deprecated)\n  - [New keyboard shortcuts defaults](#new-keyboard-shortcuts-defaults)\n  - [New URL structure](#new-url-structure)\n  - [Rename of the `--secure` cli parameter to `--https`](#rename-of-the---secure-cli-parameter-to---https)\n  - [Vue integration](#vue-integration)\n- [From version 4.0.x to 4.1.x](#from-version-40x-to-41x)\n  - [Private addon config](#private-addon-config)\n  - [React 15.x](#react-15x)\n- [From version 3.4.x to 4.0.x](#from-version-34x-to-40x)\n  - [React 16.3+](#react-163)\n  - [Generic addons](#generic-addons)\n  - [Knobs select ordering](#knobs-select-ordering)\n  - [Knobs URL parameters](#knobs-url-parameters)\n  - [Keyboard shortcuts moved](#keyboard-shortcuts-moved)\n  - [Removed addWithInfo](#removed-addwithinfo)\n  - [Removed RN packager](#removed-rn-packager)\n  - [Removed RN addons](#removed-rn-addons)\n  - [Storyshots Changes](#storyshots-changes)\n  - [Webpack 4](#webpack-4)\n  - [Babel 7](#babel-7)\n  - [Create-react-app](#create-react-app)\n    - [Upgrade CRA1 to babel 7](#upgrade-cra1-to-babel-7)\n    - [Migrate CRA1 while keeping babel 6](#migrate-cra1-while-keeping-babel-6)\n  - [start-storybook opens browser](#start-storybook-opens-browser)\n  - [CLI Rename](#cli-rename)\n  - [Addon story parameters](#addon-story-parameters)\n- [From version 3.3.x to 3.4.x](#from-version-33x-to-34x)\n- [From version 3.2.x to 3.3.x](#from-version-32x-to-33x)\n  - [`babel-core` is now a peer dependency #2494](#babel-core-is-now-a-peer-dependency-2494)\n  - [Base webpack config now contains vital plugins #1775](#base-webpack-config-now-contains-vital-plugins-1775)\n  - [Refactored Knobs](#refactored-knobs)\n- [From version 3.1.x to 3.2.x](#from-version-31x-to-32x)\n  - [Moved TypeScript addons definitions](#moved-typescript-addons-definitions)\n  - [Updated Addons API](#updated-addons-api)\n- [From version 3.0.x to 3.1.x](#from-version-30x-to-31x)\n  - [Moved TypeScript definitions](#moved-typescript-definitions)\n  - [Deprecated head.html](#deprecated-headhtml)\n- [From version 2.x.x to 3.x.x](#from-version-2xx-to-3xx)\n  - [Webpack upgrade](#webpack-upgrade)\n  - [Packages renaming](#packages-renaming)\n  - [Deprecated embedded addons](#deprecated-embedded-addons)\n\n## From version 10.0.0 to 10.1.0\n\n### API and Component Changes\n\n#### Button Component API Changes\n\n##### Added: ariaLabel\n\nThe Button component now has an `ariaLabel` prop, to ensure that Storybook UI code is accessible to screenreader users. The prop will become mandatory in Storybook 11.\n\nWhen buttons have text content as children, and when that text content does not rely on visual context to be understood, you may pass `false` to the `ariaLabel` prop to indicate that an ARIA label is not necessary.\n\nIn every other case (your Button only contains an icon, has a responsive layout that can hide its text, or relies on visual context to make sense), you must pass a label to `ariaLabel`, which screenreaders will read. The label should be short and start with an action verb.\n\n##### Added: shortcut\n\nAn optional `shortcut` prop was added for internal use. When `shortcut` is set, the Button will be appended with a human-readable string for the shortcut, and the `aria-keyshortcuts` prop will be set.\n\n##### Added: tooltip\n\nButton now displays a tooltip whenever `ariaLabel` or `shortcut` is set. The tooltip can be customised by passing a string to the optional `tooltip` prop.\n\n##### Deprecated: active\n\nThe `active` prop is deprecated and will be removed in Storybook 11.\n\nThe Button component has historically been used to implement Toggle and Select interactions. When you need a Button to have an active state, use ToggleButton if the active state denotes that a state or feature is enabled after pressing the Button. Use Select if the active state denotes that the Button is open while a selection is being made, or that the Button currently has a selected value.\n\n#### IconButton is deprecated\n\nThe IconButton component is deprecated, as it overlaps with Button. Instead, use Button with the `'ghost'` variant and `'small'` padding, and add an `ariaLabel` prop for screenreaders to announce.\n\nIconButton will be removed in future versions.\n\n#### Bar Component API Changes\n\nThe `Bar` component's internal layout has changed, to fix a height bug in scrollable bars. It now applies flex positioning and applies a default item gap, that can be controlled with the `innerStyle` prop. You may see slight changes in default padding as a result of this change.\n\n##### Added: innerStyle\n\nWhen `scrollable` is set to `true`, `Bar` now adds an inner container that is used to ensure the scrollbar size does not impact the height of the bar. This inner container displays as 'flex' and has the following default style:\n\n```css\nwidth: 100%;\nmin-height: 40;\ndisplay: flex;\nalign-items: center;\ngap: 6px;\npadding-inline: 6px;\n```\n\nThe inner container's style can be overridden by passing CSS properties to `innerStyle`.\n\n#### FlexBar is deprecated\n\nThe `FlexBar` component is deprecated. Instead, use the `Bar` component and apply `justifyContent: 'space-between'` through the `innerStyle` prop.\n\n#### Tabs is deprecated\n\nThe `Tabs` component is deprecated as it was not accessible. Instead, use the new `TabsView` component or `TabList` and `TabPanel` with the `useTabsState` hook. Note that `TabsView` does not support mixing HTML links and tabs.\n\n#### TabsState is deprecated\n\nThe `TabsState` class is deprecated as it was not accessible. Instead, use the new `TabsView` component or `TabList` and `TabPanel` with the `useTabsState` hook. Note that `TabsView` does not support mixing HTML links and tabs.\n\n#### TabWrapper is deprecated\n\nThe `TabWrapper` component is deprecated as it was not accessible. Instead, use the new `TabsView` component or `TabList` and `TabPanel` with the `useTabsState` hook. Note that `TabsView` does not support mixing HTML links and tabs.\n\n#### TabButton is deprecated\n\nThe `TabButton` class is deprecated as it was not accessible. It does not have a replacement, as the new `TabList` component handles tab buttons internally.\n\n#### TabBar is deprecated\n\nThe `TabBar` component, a styled bar used inside `Tabs` and not intended to be public, is deprecated and will be hidden in Storybook 11. Use `TabsView` instead.\n\n#### Modal Component API Changes\n\n##### Deprecated: onInteractOutside\n\nThe `onInteractOutside` prop is deprecated in favor of `dismissOnClickOutside`, because it was only used to close the modal when clicking outside. Use `dismissOnClickOutside` to control whether clicking outside the modal should close it or not.\n\n##### Deprecated: onEscapeKeyDown\n\nThe `onEscapeKeyDown` prop is deprecated in favor of `dismissOnEscape`, because it was only used to close the modal when pressing Escape. Use `dismissOnEscape` to control whether pressing Escape should close it or not.\n\n##### Added: `ariaLabel`\n\nModal elements must have a title to be accessible. Set that title through the `ariaLabel` prop. It will become mandatory in Storybook 11.\n\n##### Renamed: Modal.Dialog.Close and Modal.CloseButton\n\nThe `Modal.Dialog.Close` component and `Modal.CloseButton` components are replaced by `Modal.Close` for consistency with other components. Those names are deprecated and will be removed in Storybook 11. You may call `<Modal.Close />` for a default close button, or `<Modal.Close asChild>...</Modal.Close>` to wrap your own custom button.\n\nThe `Modal.Close` component no longer requires an `onClick` handler to close the modal. It will automatically close the modal when clicked. If you need to perform additional actions when the close button is clicked, you can still provide an `onClick` handler, and it will be called in addition to closing the modal.\n\n#### ListItem, TooltipLinkList and TooltipMessage are deprecated\n\nThe ListItem and TooltipLinkList components were used in Storybook to make menus, and TooltipMessage to make message popovers. However, WithTooltip does not support keyboard interactions, so these components were not accessible.\n\nThese components are now deprecated and will be removed in future versions. To replace TooltipMessage, replace WithTooltip with PopoverProvider, and use Popover as a base component for your popovers. To replace ListItem and TooltipLinkList, a dedicated menu component will be introduced in a future version, and Popover can be used in the meantime.\n\n#### PopoverProvider Component Added\n\nThe PopoverProvider component acts as a counterpoint to WithTooltip. When you want an interactive overlay with buttons or inputs, use PopoverProvider and Popover. When you want a static overlay that shows on focus or hover, use WithTooltip with TooltipNote or Tooltip.\n\nPopoverProvider is based on react-aria. It must have a single child that acts as a trigger. This child must have a pressable role (can be clicked or pressed) and must be able to receive React refs. Wrap your trigger component in `forwardRef` if you notice placement issues for your popover.\n\n##### Added: ariaLabel\n\nThe `ariaLabel` prop was added in Storybook 10.3 to provide an accessible label for the popover dialog. This label is announced by screen readers when the popover opens. `ariaLabel` will become mandatory in Storybook 11.\n\n```tsx\n<PopoverProvider ariaLabel=\"Share options\" popover={<ShareMenu />}>\n  <Button ariaLabel=\"Share\">Share</Button>\n</PopoverProvider>\n```\n\n#### WithTooltip Component API Changes\n\nThe WithTooltip component has been reimplemented from the ground up, under the new name `TooltipProvider`. The new implementation will replace `WithTooltip` entirely in Storybook 11. Below is a summary of the changes between both APIs, which will take full effect in Storybook 11.\n\n##### Removed: trigger\n\nThe `trigger` prop was removed to enforce better accessibility compliance. WithTooltip must not be triggered on click, as it is not reachable by keyboard. Buttons that open a popover, menu or select must use appropriate components instead.\n\n#### Added: triggerOnFocusOnly\n\nThe `triggerOnFocusOnly` prop was added. When set, tooltips will only show on focus. Use this to provide keyboard navigation hints to keyboard users. Do not use it for other purposes.\n\n#### Renamed: startOpen\n\nThe `startOpen` prop was renamed `defaultVisible` to match naming in other components that expose both controlled and uncontrolled visibility. The `startOpen` prop will be removed in future versions.\n\n#### Removed: svg, strategy, withArrows, mutationObserverOptions\n\nThese props were not used inside Storybook and have been removed.\n\n#### Removed: hasChrome\n\nThe `hasChrome` prop was removed because it should be handled by the tooltip being shown instead. Popover and Tooltip both have a `hasChrome` prop. TooltipNote never needs this prop and does not have it.\n\n#### Removed: closeOnTriggerHidden, followCursor, closeOnOutsideClick\n\nThe `closeOnTriggerHidden`, `followCursor` and `closeOnOutsideClick` props have been removed. WithTooltip will now authoritatively decide when and where to show or hide its tooltip. It will always close on clicks outside the tooltip, because tooltips should never be modal.\n\n#### Removed: interactive\n\nThe `interactive` prop has been removed as it does not align with our vision for accessible components with a well-defined role. Use PopoverProvider instead of WithTooltip to show interactive overlays.\n\n##### Other changes\n\nThe underlying implementation was switched from Popper.js to react-aria. Due to these changes, WithTooltip must now have a single child that has a focusable role and that can receive React refs. Wrap your trigger component in `forwardRef` if you notice placement issues for your tooltip.\n\n#### WithTooltipPure and WithTooltipState are deprecated\n\nInstead, use `WithTooltipNew` in Storybook 10, or `WithTooltip` in Storybook 11 or newer. For a controlled tooltip, use the `onVisibleChange` and `visible` props. For an uncontrolled tooltip with a default open state, use the `defaultVisible` prop.\n\n#### Link isButton is deprecated\n\nLink now renders automatically as an HTML `button`, with keyboard focus support, when no `href` is provided. The `isButton` prop continues to enforce rendering with a `button` role in Storybook 10, but will be removed in Storybook 11.\n\n## From version 9.x to 10.0.0\n\n### Core Changes\n\n#### Local addons must be fully resolved\n\nIn Storybook 9 it was possible to do reference local addons by a relative path, like so:\n\n```ts\n// main.ts\n\nexport default {\n  addons: ['./my-addon.ts'],\n};\n```\n\nIn Storybook 10 this relative path, should be fully resolved, like so:\n\n```ts\n// main.ts\n\nexport default {\n  addons: [import.meta.resolve('./my-addon.ts')],\n};\n```\n\nWhen adding managerEntries, ensure you resolve a path, you may need to convert it from a URL:\n\nFor example:\n\n```ts\n// main.ts\nexport default {\n  managerEntries(entry = []) {\n    return [...entry, require.resolve('./iframe.js')];\n  },\n};\n```\n\nWould become:\n\n```ts\n// main.ts\nimport { fileURLToPath } from 'node:url';\n\nexport default {\n  managerEntries(entry = []) {\n    return [...entry, fileURLToPath(import.meta.resolve('./iframe.js'))];\n  },\n};\n```\n\n#### The `.storybook/main.*` file and other presets must be valid ESM\n\nStorybook will load the `.storybook/main.*` file and any custom preset files as ESM files.\nThus CJS constants (`require`, `__dirname`, `__filename`) will not be defined.\n\nYou can define these constants yourself, like so:\n\n```ts\nimport { createRequire } from 'node:module';\nimport { dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst require = createRequire(import.meta.url);\n```\n\nA `main.ts` file that's CJS is no longer supported. The same applies to any custom preset files.\n\nAdditionally, **extensionless relative imports are no longer supported** in JavaScript-based configuration files (`.storybook/main.js`) and custom presets. All relative imports must now include explicit file extensions.\n\n**Before (no longer works):**\n\n```js\n// .storybook/main.js\nimport myPreset from './my-file';\n```\n\n**After:**\n\n```js\n// .storybook/main.js\nimport myPreset from './my-file.js';\n```\n\nThis change aligns with Node.js ESM requirements, where relative imports must specify the full file extension. This applies to `.storybook/main.js` and any custom preset files. While TypeScript-based files (`.storybook/main.ts`) will continue to work with extensionless imports for now through automatic resolution, we recommend migrating to explicit extensions for consistency and better compatibility.\n\n**Recommended approach for all files:**\n\n- Use `.js` for JavaScript files\n- Use `.mjs` for ES modules\n- Use `.ts` for TypeScript files\n- Always include the extension in relative imports\n\n#### Node.js 20.19+ or 22.12+ required\n\nStorybook 10 now requires Node.js version 20.19+ or 22.12+. We require these new ranges so Node.js supports `require(esm)` without a flag.\n\n#### Require `tsconfig.json` `moduleResolution` set to value that supports `types` condition\n\nStorybook 10 has removed all `typesVersions` fields from `package.json` files. This field was previously needed for older TypeScript module resolution strategies that didn't support the `types` condition in package.json exports.\n\n**Required action:** Update your `tsconfig.json` to use a `moduleResolution` that supports the `types` condition:\n\n```json\n{\n  \"compilerOptions\": {\n    \"moduleResolution\": \"bundler\" // or \"node16\"/\"nodenext\"\n  }\n}\n```\n\n**Supported values:**\n\n- `\"bundler\"` (recommended for modern bundler-based projects)\n- `\"node16\"` or `\"nodenext\"` (Node.js 16+ module resolution)\n\n**Note:** If you're currently using `moduleResolution: \"node\"` (the old Node.js 10-style resolution), you'll need to upgrade to one of the supported values above.\n\nThis change simplifies our package structure and aligns with modern TypeScript standards. Only TypeScript projects are affected - JavaScript projects require no changes.\n\n#### `core.builder` configuration must be a fully resolved path\n\n> [!NOTE]  \n> In the majority of cases, this is only relevant for authors of Storybook framework packages, as regular users very rarely set the `core.builder` property manually.\n\nWhen setting the `core.builder` or `core.builder.name` option in the main configuration, it must now be a fully resolved path to a builder's entry point, instead of just to the builder package's root directory.\n\nIn a preset:\n\n```diff\nimport { dirname } from 'node:path';\n\nconst getAbsolutePath = (input) =>\n  dirname(require.resolve(`${input}/package.json`));\n\nexport const core = {\n-  builder: getAbsolutePath('@storybook/builder-vite'),\n-  // 👆 results in eg. `/absolute/path/node_modules/@storybook/builder-vite\n+  builder: import.meta.resolve('@storybook/builder-vite'),\n+  // 👆 results in eg. `/absolute/path/node_modules/@storybook/builder-vite/index.js\n  renderer: getAbsolutePath('@storybook/react'),\n};\n```\n\n#### Removed x-only builtin tags\n\nDuring development of Storybook [Tags](https://storybook.js.org/docs/writing-stories/tags), we created `dev-only`, `docs-only`, and `test-only` built-in tags. These tags were never documented and superseded by the currently-documented `dev`, `autodocs`, and `test` tags which provide more precise control. The outdated `x-only` tags are removed in 10.0.\n\n## From version 8.x to 9.0.0\n\n### Core Changes and Removals\n\n#### Dropped support for legacy packages\n\nThe following packages are no longer published as part of `9.0.0`:\nThe following packages have been consolidated into the main `storybook` package:\n\n| Old Package                     | New Path                |\n| ------------------------------- | ----------------------- |\n| `@storybook/manager-api`        | `storybook/manager-api` |\n| `@storybook/preview-api`        | `storybook/preview-api` |\n| `@storybook/theming`            | `storybook/theming`     |\n| `@storybook/test`               | `storybook/test`        |\n| `@storybook/addon-actions`      | `storybook/actions`     |\n| `@storybook/addon-backgrounds`  | N/A                     |\n| `@storybook/addon-controls`     | N/A                     |\n| `@storybook/addon-highlight`    | `storybook/highlight`   |\n| `@storybook/addon-interactions` | N/A                     |\n| `@storybook/addon-measure`      | N/A                     |\n| `@storybook/addon-outline`      | N/A                     |\n| `@storybook/addon-toolbars`     | N/A                     |\n| `@storybook/addon-viewport`     | `storybook/viewport`    |\n\nPlease un-install these packages, and ensure you have the `storybook` package installed.\n\nReplace any imports with the path listed in the second column.\n\nAdditionally the following packages were also consolidated and placed under a `/internal` sub-path, to indicate they are for internal usage only.\nIf you're depending on these packages, they will continue to work for `9.0`, but they will likely be removed in `10.0`.\n\n| Old Package                  | New Path                             |\n| ---------------------------- | ------------------------------------ |\n| `@storybook/channels`        | `storybook/internal/channels`        |\n| `@storybook/client-logger`   | `storybook/internal/client-logger`   |\n| `@storybook/core-common`     | `storybook/internal/common`          |\n| `@storybook/core-events`     | `storybook/internal/core-events`     |\n| `@storybook/csf-tools`       | `storybook/internal/csf-tools`       |\n| `@storybook/docs-tools`      | `storybook/internal/docs-tools`      |\n| `@storybook/node-logger`     | `storybook/internal/node-logger`     |\n| `@storybook/router`          | `storybook/internal/router`          |\n| `@storybook/telemetry`       | `storybook/internal/telemetry`       |\n| `@storybook/types`           | `storybook/internal/types`           |\n| `@storybook/manager`         | `storybook/internal/manager`         |\n| `@storybook/preview`         | `storybook/internal/preview`         |\n| `@storybook/core-server`     | `storybook/internal/core-server`     |\n| `@storybook/builder-manager` | `storybook/internal/builder-manager` |\n| `@storybook/components`      | `storybook/internal/components`      |\n\nAddon authors may continue to use the internal packages, there is currently not yet any replacement.\n\n```bash\nnpm uninstall @storybook/experimental-addon-test\nnpm install --save-dev @storybook/addon-vitest\n```\n\nUpdate your imports in any custom configuration or test files:\n\n```diff\n- import { ... } from '@storybook/experimental-addon-test';\n+ import { ... } from '@storybook/addon-vitest';\n```\n\nIf you're using the addon in your Storybook configuration, update your `.storybook/main.js` or `.storybook/main.ts`:\n\n```diff\nexport default {\n  addons: [\n-   '@storybook/experimental-addon-test',\n+   '@storybook/addon-vitest',\n  ],\n};\n```\n\nThe public API remains the same, so no additional changes should be needed in your test files or configuration.\n\nAdditionally, we have deprecated the usage of `withActions` from `@storybook/addon-actions` and we will remove it in Storybook v10. Please file an issue if you need this API.\n\n#### Dropped support\n\n##### Vite 4\n\nStorybook 9.0 drops support for Vite 4. The minimum supported version is now Vite 5.0.0. This change affects all Vite-based frameworks and builders:\n\n- `@storybook/builder-vite`\n- `@storybook/react-vite`\n- `@storybook/vue-vite`\n- `@storybook/vue3-vite`\n- `@storybook/svelte-vite`\n- `@storybook/web-components-vite`\n- `@storybook/preact-vite`\n- `@storybook/html-vite`\n- `@storybook/experimental-nextjs-vite`\n\nTo upgrade:\n\n1. Update your project's Vite version to 5.0.0 or higher\n2. Update your Storybook configuration to use Vite 5:\n   ```js\n   // vite.config.js or vite.config.ts\n   export default {\n     // ... your other config\n     // Make sure you're using Vite 5 compatible plugins\n   };\n   ```\n\nIf you're using framework-specific Vite plugins, ensure they are compatible with Vite 5:\n\n- `@vitejs/plugin-react`\n- `@vitejs/plugin-vue`\n- `@sveltejs/vite-plugin-svelte`\n- etc.\n\nFor more information on upgrading to Vite 5, see the [Vite Migration Guide](https://v6.vite.dev/guide/migration).\n\n##### TypeScript < 4.9\n\nStorybook now requires TypeScript 4.9 or later.\n\n##### Node.js < 20\n\nStorybook now requires Node.js 20 or later.\n\n##### Package Managers\n\nMinimum supported versions:\nnpm v10+\nyarn v4+\npnpm v9+\n\nWhile Storybook may still work with older versions, we recommend upgrading to the latest supported versions for the best experience and to ensure compatibility.\n\n#### Moving from renderer-based to framework-based configuration\n\nStorybook is moving from renderer-based to framework-based configuration. This means you should:\n\n1. Update your source files to use framework-specific imports instead of renderer imports\n2. Remove the renderer packages from your package.json\n\nFor example, if you're using `@storybook/react` with `@storybook/react-vite`, you should:\n\n- Import types and functions from `@storybook/react-vite` instead of `@storybook/react`\n- Remove `@storybook/react` from your package.json dependencies\n\n```diff\n- import { Meta, StoryObj } from '@storybook/react';\n+ import { Meta, StoryObj } from '@storybook/react-vite';\n```\n\n### Addon-specific Changes\n\n#### Essentials Addon: Viewport, Controls, Interactions and Actions moved to core\n\nThe `@storybook/addon-essentials` package has been removed. The viewport, controls, interactions and actions addons have been moved from their respective packages (`@storybook/addon-viewport`, `@storybook/addon-controls`, `@storybook/addon-interactions`, `@storybook/addon-actions`) to Storybook core. You no longer need to install these separately or include them in your addons list.\n\nIf you have used `@storybook/addon-docs` as part of essentials, you need to manually install it:\n\n```bash\n$ npx storybook add @storybook/addon-docs\n```\n\n#### A11y Addon: Removed deprecated manual parameter\n\nThe deprecated `manual` parameter from the A11y addon's parameters has been removed. Instead, use the `globals.a11y.manual` setting to control manual mode. For example:\n\n```js\n// Old way (no longer works)\nexport const MyStory = {\n  parameters: {\n    a11y: {\n      manual: true\n    }\n  }\n};\n\n// New way\nexport const MyStory = {\n  parameters: {\n    a11y: {\n      // other a11y parameters\n    }\n  }\n  globals: {\n    a11y: {\n      manual: true\n    }\n  }\n};\n\n// To enable manual mode globally, use .storybook/preview.js:\nexport const initialGlobals = {\n  a11y: {\n    manual: true\n  }\n};\n```\n\n#### A11y Addon: Replace `element` parameter with `context` parameter\n\nThe `element` parameter from the A11y addon's parameters has been removed in favor of a new `context` parameter. The `element` parameter could be used with a single CSS selector string to configure which element to target with axe. The new `context` parameter supports the full range that `axe-core`'s Context API supports, _including_ a single selector like the removed `element` parameter did.\n`context` does _not_ support passing in a `Node` or `NodeList` (like `document.getElementById('my-target')`).\n\n```diff\nexport const MyStory = {\n  parameters: {\n    a11y: {\n-      element: '#my-target'\n+      context: '#my-target'\n    }\n  }\n};\n```\n\n#### Experimental Test Addon: Stabilized and renamed\n\nIn Storybook 9.0, we've officially stabilized the Test addon. The package has been renamed from `@storybook/experimental-addon-test` to `@storybook/addon-vitest`, reflecting its production-ready status. If you were using the experimental addon, you'll need to update your dependencies and imports.\n\nThe vitest addon automatically loads Storybook's `beforeAll` hook, so that you can remove the following line in your vitest.setup.ts file:\n\n```diff\n// .storybook/vitest.setup.ts\nimport { setProjectAnnotations } from '@storybook/react-vite';\nimport * as addonAnnotations from 'my-addon/preview';\nimport * as previewAnnotations from './.storybook/preview';\n\n- const project = setProjectAnnotations([previewAnnotations, addonAnnotations]);\n+ setProjectAnnotations([previewAnnotations, addonAnnotations]);\n\n// the vitest addon automatically loads beforeAll\n- beforeAll(project.beforeAll);\n```\n\n#### Vitest Addon (former @storybook/experimental-addon-test): Vitest 2.0 support is dropped\n\nThe Storybook Test addon now only supports Vitest 3.0 and higher, which is where browser mode was made into a stable state. Please upgrade to Vitest 3.0.\n\n#### Viewport/Backgrounds Addon synchronized configuration and `globals` usage\n\nThe feature flags: `viewportStoryGlobals` and `backgroundsStoryGlobals` have been removed, please remove these from your `.storybook/main.ts` file.\n\nSee here for the ways you have to configure addon viewports & backgrounds:\n\n- [New parameters format for addon backgrounds](#new-parameters-format-for-addon-backgrounds)\n- [New parameters format for addon viewport](#new-parameters-format-for-addon-viewport)\n\n#### Storysource Addon removed\n\nThe `@storybook/addon-storysource` addon and the `@storybook/source-loader` package are removed in Storybook 9.0. Instead, Storybook now provides a Code Panel via `@storybook/addon-docs` that offers similar functionality with improved integration and performance.\n\n#### Mdx-gfm Addon removed\n\nThe `@storybook/addon-mdx-gfm` addon is removed in Storybook 9.0 since it is no longer needed.\n\n**Migration Steps:**\n\n1. Remove the old addon\n\nRemove `@storybook/addon-storysource` from your project:\n\n```bash\nnpx storybook remove @storybook/addon-storysource\n```\n\n2. Enable the Code Panel\n\nThe Code Panel can be enabled by adding the following parameter to your stories or globally in `.storybook/preview.js`:\n\n```js\nexport const parameters = {\n  docs: {\n    codePanel: true,\n  },\n};\n```\n\nOr for individual stories:\n\n```js\nexport const MyStory = {\n  parameters: {\n    docs: {\n      codePanel: true,\n    },\n  },\n};\n```\n\n### API and Component Changes\n\n#### Button Component API Changes\n\nThe Button component has been updated to use a more modern props API. The following props have been removed:\n\n- `isLink`\n- `primary`\n- `secondary`\n- `tertiary`\n- `gray`\n- `inForm`\n- `small`\n- `outline`\n- `containsIcon`\n\nUse the new `variant` and `size` props instead:\n\n```diff\n- <Button primary small>Click me</Button>\n+ <Button variant=\"primary\" size=\"small\">Click me</Button>\n```\n\n#### Icon System Updates\n\nSeveral icon-related exports have been removed:\n\n- `IconButtonSkeleton`\n- `Icons`\n- `Symbols`\n- Legacy icon exports\n\nUse the new icon system from `@storybook/icons` instead:\n\n```diff\n- import { Icons, IconButtonSkeleton } from '@storybook/components';\n+ import { ZoomIcon } from '@storybook/icons';\n```\n\n#### Sidebar Component Changes\n\n1. The 'extra' prop has been removed from the Sidebar's Heading component\n2. Experimental sidebar features have been removed:\n   - `experimental_SIDEBAR_BOTTOM`\n   - `experimental_SIDEBAR_TOP`\n\n#### Story Store API Changes\n\nSeveral deprecated methods have been removed from the StoryStore:\n\n- `getSetStoriesPayload`\n- `getStoriesJsonData`\n- `raw`\n- `fromId`\n\n#### Global State Management\n\nThe `globals` field in project annotations has been renamed to `initialGlobals`:\n\n```diff\nexport const preview = {\n- globals: {\n+ initialGlobals: {\n    theme: 'light'\n  }\n};\n```\n\nAdditionally loading the defaultValue from `globalTypes` isn't supported anymore. Use `initialGlobals` instead to define the defaultValue.\n\n```diff\n// .storybook/preview.js\nexport default {\n+ initialGlobals: {\n+   locale: 'en'\n+ },\n  globalTypes: {\n    locale: {\n      description: 'Locale for components',\n-     defaultValue: 'en',\n      toolbar: {\n        title: 'Locale',\n        icon: 'circlehollow',\n        items: ['es', 'en'],\n      },\n    },\n  },\n}\n```\n\n#### Experimental Status API has turned into a Status Store\n\nThe experimental status API previously available at `api.experimental_updateStatus` and `api.getCurrentStoryStatus` has changed, to a store that works both on the server, in the manager and in the preview.\n\nYou can use the new Status Store by importing `experimental_getStatusStore` from either `storybook/internal/core-server`, `storybook/manager-api` or `storybook/preview-api`:\n\n```diff\n+ import { experimental_getStatusStore } from 'storybook/manager-api';\n+ import { StatusValue } from 'storybook/internal/types';\n\n+ const myStatusStore = experimental_getStatusStore(MY_ADDON_ID);\n\naddons.register(MY_ADDON_ID, (api) => {\n-  api.experimental_updateStatus({\n-    someStoryId: {\n-      status: 'success',\n-       title: 'Component tests',\n-       description: 'Works!',\n-    }\n-  });\n+  myStatusStore.set([{\n+    value: StatusValue.SUCCESS\n+    title: 'Component tests',\n+    description: 'Works!',\n+  }]);\n```\n\n#### `experimental_afterEach` has been stabilized\n\nThe experimental_afterEach hook has been promoted to a stable API and renamed to afterEach.\n\nTo migrate, simply replace all instances of experimental_afterEach with afterEach in your stories, preview files, and configuration.\n\n```diff\n export const MyStory = {\n-   experimental_afterEach: async ({ canvasElement }) => {\n+   afterEach: async ({ canvasElement }) => {\n     // cleanup logic\n   },\n };\n```\n\n#### Testing Module Changes\n\nThe `TESTING_MODULE_RUN_ALL_REQUEST` event has been removed:\n\n```diff\n- import { TESTING_MODULE_RUN_ALL_REQUEST } from '@storybook/core-events';\n+ import { TESTING_MODULE_RUN_REQUEST } from '@storybook/core-events';\n```\n\n#### Consolidate `@storybook/blocks` into addon docs\n\nThe package `@storybook/blocks` is no longer published as of Storybook 9.\n\nAll exports can now be found in the export `@storybook/addon-docs/blocks`.\n\nPreviously, you were able to import all blocks from `@storybook/addon-docs`, this is no longer the case.\n\nThis is the only correct import path:\n\n```diff\n- import { Meta } from \"@storybook/addon-docs\";\n+ import { Meta } from \"@storybook/addon-docs/blocks\";\n```\n\n### Configuration and Type Changes\n\n#### Manager builder removed alias for `util`, `assert` and `process`\n\nThese dependencies (often used accidentally) were polyfilled to mocks or browser equivalents by storybook's manager builder.\n\nStarting with Storybook `9.0`, we no longer alias these anymore.\n\nAdding these aliases meant storybook core, had to depend on these packages, which have a deep dependency graph, added to every storybook project.\n\nIf you addon fails to load after this change, we recommend looking at implementing the alias at compile time of your addon, or alternatively look at other bundling config to ensure the correct entries/packages/dependencies are used.\n\n#### Type System Updates\n\nThe following types have been removed:\n\n- `Addon_SidebarBottomType`\n- `Addon_SidebarTopType`\n- `DeprecatedState`\n\nImport paths have been updated:\n\n```diff\n- import { SupportedRenderers } from './project_types';\n+ import { SupportedRenderers } from 'storybook/internal/types';\n```\n\n#### CSF File Changes\n\nDeprecated getters have been removed from the CsfFile class:\n\n- `_fileName`\n- `_makeTitle`\n\n#### React-Native config dir renamed\n\nIn Storybook 9, React Native (RN) projects use the `.rnstorybook` config directory instead of `.storybook`.\nThat makes it easier for RN and React Native Web (RNW) storybooks to co-exist in the same project.\n\nTo upgrade, either rename your `.storybook` directory to `.rnstorybook` or if you wish to continue using `.storybook` (not recommended), you can use the [`configPath`](https://github.com/storybookjs/react-native#configpath) option to specify `.storybook` manually.\n\n#### `parameters.docs.source.format` removal\n\nThe `parameters.docs.source.format` parameter has been removed in favor of using `parameters.docs.source.transform`. If you were using `format` to prettify your code via prettier, you can now use the `transform` parameter with Prettier directly:\n\n```js\n// .storybook/preview.js|ts|jsx|tsx\nexport default {\n  parameters: {\n    docs: {\n      source: {\n        transform: async (source) => {\n          const prettier = await import('prettier/standalone');\n          const prettierPluginBabel = await import('prettier/plugins/babel');\n          const prettierPluginEstree = await import('prettier/plugins/estree');\n\n          return prettier.format(source, {\n            parser: 'babel',\n            plugins: [prettierPluginBabel, prettierPluginEstree],\n          });\n        },\n      },\n    },\n  },\n};\n```\n\nThis change gives you more control over how your code is formatted and allows for asynchronous transformations. The `transform` function receives the source code and story context as parameters, enabling you to implement custom formatting logic or use any code formatting library of your choice.\n\n**Before:**\n\n```js\nexport const MyStory = {\n  parameters: {\n    docs: {\n      source: {\n        format: 'html',\n      },\n    },\n  },\n};\n```\n\n**After:**\n\n```js\nexport const MyStory = {\n  parameters: {\n    docs: {\n      source: {\n        transform: async (source) => {\n          // Your custom transformation logic here\n          return source;\n        },\n      },\n    },\n  },\n};\n```\n\n#### `parameter docs.source.excludeDecorators` has no effect in React\n\n#### Documentation Generation Changes\n\nThe `autodocs` configuration option has been removed in favor of using tags:\n\n```diff\n// .storybook/preview.js\nexport default {\n- docs: { autodocs: true }\n};\n\n// In your CSF files:\n+ export default {\n+   tags: ['autodocs']\n+ };\n```\n\nIn React, the parameter `docs.source.excludeDecorators` option is no longer used.\nDecorators are always excluded as it causes performance issues and doc source snippets not showing the actual component.\n\n### Framework-specific changes\n\n#### Svelte: Require v5 and up\n\nStorybook has dropped support for Svelte versions 3 and 4. The minimum supported version is now Svelte 5.\n\nIf you're using an older version of Svelte, you'll need to upgrade to Svelte 5 or newer to use the latest version of Storybook.\n\n#### Svelte: Dropped support for @storybook/svelte-webpack5\n\nIn Storybook 9.0, we've dropped support for `@storybook/svelte-webpack5`. If you're currently using it, you need to migrate to `@storybook/svelte-vite` instead.\n\nFollow these steps to migrate:\n\n1. Remove the webpack5 framework package:\n\n```bash\nnpm uninstall @storybook/svelte-webpack5\n# or\nyarn remove @storybook/svelte-webpack5\n```\n\n2. Install the Vite framework package:\n\n```bash\nnpm install -D @storybook/svelte-vite\n# or\nyarn add -D @storybook/svelte-vite\n```\n\n3. Update your Storybook configuration in `.storybook/main.js` or `.storybook/main.ts`:\n\n```diff\nexport default {\n  framework: {\n-    name: '@storybook/svelte-webpack5'\n+    name: '@storybook/svelte-vite',\n  },\n  // ...other configuration\n};\n```\n\nFor more details, please refer to the [Svelte & Vite documentation](https://storybook.js.org/docs/get-started/frameworks/svelte-vite).\n\n#### Svelte: Dropped automatic docgen for events and slots\n\nThe internal docgen logic for legacy Svelte components have been changed to match what already happened for rune-based components, using the same `svelte2tsx` parsing that the official Svelte tools use.\n\nThis means that argTypes are no longer automatically generated for slots and events defined with `on:my-event`.\n\n#### Angular: Require v18 and up\n\nStorybook has dropped support for Angular versions 15-17. The minimum supported version is now Angular 18.\n\nIf you're using an older version of Angular, you'll need to upgrade to Angular 18 or newer to use the latest version of Storybook.\n\nKey changes:\n\n- All Angular packages in peerDependencies now require `>=18.0.0 < 20.0.0`\n- Removed legacy code supporting Angular < 18\n- Standalone components are now the default (can be opted out by explicitly setting `standalone: false` in component decorators)\n- Updated RxJS requirement to `^7.4.0`\n- Updated TypeScript requirement to `^4.9.0 || ^5.0.0`\n- Updated Zone.js requirement to `^0.14.0 || ^0.15.0`\n\n#### Angular: Introduce `features.angularFilterNonInputControls`\n\nStorybook has added a new feature flag `angularFilterNonInputControls` which filters out non-input controls from Angular components in Storybook's controls panel.\n\nTo enable it, just set the feature flag in your `.storybook/main.<js|ts> file.\n\n```tsx\nexport default {\n  features: {\n    angularFilterNonInputControls: true,\n  },\n  // ... other configurations\n};\n```\n\n#### Dropped webpack5 Builder Support in Favor of Vite\n\nRemoved webpack5 builder support for Preact, Vue3, and Web Components frameworks in favor of Vite builder. This change streamlines our builder support and improves performance across these frameworks.\n\nRemoved Packages\n\n- `@storybook/preact-webpack5`\n- `@storybook/preset-preact-webpack5`\n- `@storybook/vue3-webpack5`\n- `@storybook/preset-vue3-webpack`\n- `@storybook/web-components-webpack5`\n- `@storybook/html-webpack5`\n- `@storybook/preset-html-webpack`\n\n**For Preact Projects**\n\n```bash\nnpm remove @storybook/preact-webpack5 @storybook/preset-preact-webpack\nnpm install @storybook/preact-vite --save-dev\n```\n\n**For Vue3 Projects**\n\n```bash\nnpm remove @storybook/vue3-webpack5 @storybook/preset-vue3-webpack\nnpm install @storybook/vue3-vite --save-dev\n```\n\n**For Web Components Projects**\n\n```bash\nnpm remove @storybook/web-components-webpack5\nnpm install @storybook/web-components-vite --save-dev\n```\n\n**For HTML Projects**\n\n```bash\nnpm remove @storybook/html-webpack5 @storybook/preset-html-webpack\nnpm install @storybook/html-vite --save-dev\n```\n\n**Update .storybook/main.js|ts**\n\nFor all affected frameworks, update your configuration to use the Vite builder:\n\n```tsx\nexport default {\n  framework: {\n    name: '@storybook/[framework]-vite', // replace [framework] with preact, vue3, or web-components\n    options: {},\n  },\n  // ... other configurations\n};\n```\n\nThis change consolidates our builder support around Vite, which offers better performance and a more streamlined development experience. The webpack5 builders for these frameworks have been deprecated in favor of the more modern Vite-based solution.\n\n#### Next.js: Require v14 and up\n\nStorybook has dropped support for Next.js versions below 14.1. The minimum supported version is now Next.js 14.1.\n\nIf you're using an older version of Next.js, you'll need to upgrade to Next.js 14.1 or newer to use the latest version of Storybook.\n\nFor help upgrading your Next.js application, see the [Next.js upgrade guide](https://nextjs.org/docs/app/building-your-application/upgrading).\n\n#### Next.js: Vite builder stabilized\n\nThe experimental Next.js Vite builder (`@storybook/experimental-nextjs-vite`) has been stabilized and renamed to `@storybook/nextjs-vite`. If you were using the experimental package, you should update your dependencies to use the new stable package name.\n\n```diff\n{\n  \"dependencies\": {\n-   \"@storybook/experimental-nextjs-vite\": \"^x.x.x\"\n+   \"@storybook/nextjs-vite\": \"^9.0.0\"\n  }\n}\n```\n\nAlso update your `.storybook/main.<js|ts>` file accordingly:\n\n```diff\nexport default {\n  addons: [\n-   \"@storybook/experimental-nextjs-vite\",\n+   \"@storybook/nextjs-vite\"\n  ]\n}\n```\n\n#### Lit = Require v3 and up\n\nThe minimum supported version is now v3.\n\n## From version 8.5.x to 8.6.x\n\n### Angular: Support experimental zoneless support\n\nStorybook now supports [Angular's experimental zoneless mode](https://angular.dev/guide/experimental/zoneless). This mode is intended to improve performance by removing Angular's zone.js dependency. To enable zoneless mode in your Angular Storybook, set the `experimentalZoneless` config in your `angular.json` file:\n\n```diff\n{\n  \"projects\": {\n    \"your-project\": {\n      \"architect\": {\n        \"storybook\": {\n          ...\n          \"options\": {\n            ...\n+           \"experimentalZoneless\": true\n          }\n        }\n        \"build-storybook\": {\n          ...\n          \"options\": {\n            ...\n+           \"experimentalZoneless\": true\n          }\n        }\n      }\n    }\n  }\n}\n```\n\n### Addon-a11y: Replaced experimental `ally-test` tag behavior with `parameters.a11y.test`\n\nIn Storybook 8.6, the `ally-test` tag behavior in the Accessibility addon (`@storybook/addon-a11y`) has been replaced with the `parameters.a11y.test` parameter. See the comparison table below.\n\n| Previous tag value | New parameter value | Description                                                                                            |\n| ------------------ | ------------------- | ------------------------------------------------------------------------------------------------------ |\n| `'!ally-test'`     | `'off'`             | Do not run accessibility tests (you can still manually verify via the addon panel)                     |\n| N/A                | `'todo'`            | Run accessibility tests; violations return a warning in the Storybook UI and a summary count in CLI/CI |\n| `'ally-test'`      | `'error'`           | Run accessibility tests; violations return a failing test in the Storybook UI and CLI/CI               |\n\n## From version 8.4.x to 8.5.x\n\n### React Vite: react-docgen-typescript is updated\n\nStorybook now uses [react-docgen-typescript](https://github.com/joshwooding/vite-plugin-react-docgen-typescript) v0.5.0 which updates its internal logic on how it parses files, available under an experimental feature flag `EXPERIMENTAL_useWatchProgram`, which is disabled by default.\n\nPreviously, once you made changes to a component's props, the controls and args table would not update unless you restarted Storybook. With the `EXPERIMENTAL_useWatchProgram` flag, you do not need to restart Storybook anymore, however you do need to refresh the browser page. Keep in mind that this flag is experimental and also does not support the `references` field in tsconfig.json files. Depending on how big your codebase is, it might have performance issues.\n\n```ts\n// .storybook/main.ts\nconst config = {\n  // ...\n  typescript: {\n    reactDocgen: 'react-docgen-typescript',\n    reactDocgenTypescriptOptions: {\n      EXPERIMENTAL_useWatchProgram: true,\n    },\n  },\n};\nexport default config;\n```\n\n### Introducing features.developmentModeForBuild\n\nAs part of our ongoing efforts to improve the testability and debuggability of Storybook, we are introducing a new feature flag: `developmentModeForBuild`. This feature flag allows you to set `process.env.NODE_ENV` to `development` in built Storybooks, enabling development-related optimizations that are typically disabled in production builds.\n\nIn development mode, React and other libraries often include additional checks and warnings that help catch potential issues early. These checks are usually stripped out in production builds to optimize performance. However, when running tests or debugging issues in a built Storybook, having these additional checks can be incredibly valuable. One such feature is React's `act`, which ensures that all updates related to a test are processed and applied before making assertions. `act` is crucial for reliable and predictable test results, but it only works correctly when `NODE_ENV` is set to `development`.\n\n```js\n// .storybook/main.js\nexport default {\n  features: {\n    developmentModeForBuild: true,\n  },\n};\n```\n\n### Added source code panel to docs\n\nStorybook Docs (`@storybook/addon-docs`) now can automatically add a new addon panel to stories that displays a source snippet beneath each story. This is an experimental feature that works similarly to the existing [source snippet doc block](https://storybook.js.org/docs/writing-docs/doc-blocks#source), but in the story view. It is intended to replace the [Storysource addon](https://storybook.js.org/addons/@storybook/addon-storysource).\n\nTo enable this globally, add the following line to your project configuration. You can also configure at the component/story level.\n\n```js\n// .storybook/preview.js\nexport default {\n  parameters: {\n    docs: {\n      codePanel: true,\n    },\n  },\n};\n```\n\n### Addon-a11y: Component test integration\n\nIn Storybook 8.4, we introduced the [Test addon](https://storybook.js.org/docs/writing-tests/test-addon) (`@storybook/experimental-addon-test`). Powered by Vitest under the hood, this addon lets you watch, run, and debug your component tests directly in Storybook.\n\nIn Storybook 8.5, we revamped the [Accessibility addon](https://storybook.js.org/docs/writing-tests/accessibility-testing) (`@storybook/addon-a11y`) to integrate it with the component tests feature. This means you can now extend your component tests to include accessibility tests.\n\nIf you upgrade to Storybook 8.5 via `npx storybook@latest upgrade`, the Accessibility addon will be automatically configured to work with the component tests. However, if you're upgrading manually and you have the Test addon installed, adjust your configuration as follows:\n\n```diff\n// .storybook/vitest.setup.ts\n...\n+import * as a11yAddonAnnotations from '@storybook/addon-a11y/preview';\n\nconst annotations = setProjectAnnotations([\n  previewAnnotations,\n+ a11yAddonAnnotations,\n]);\n\n// Run Storybook's beforeAll hook\nbeforeAll(annotations.beforeAll);\n```\n\n### Addon-a11y: Changing the default element selector\n\nIn Storybook 8.5, we changed the default element selector used by the Accessibility addon from `#storybook-root` to `body`. This change was made to align with the default element selector used by the Test addon when running accessibility tests via Vitest. Additionally, Tooltips or Popovers that are rendered outside the `#storybook-root` element will now be included in the accessibility tests per default allowing for a more comprehensive test coverage. If you want to fall back to the previous behavior, you can set the `a11y.element` parameter in your `.storybook/preview.<ts|js>` configuration:\n\n```diff\n// .storybook/preview.js\nexport const parameters = {\n  a11y: {\n+    element: '#storybook-root',\n  },\n};\n```\n\n### Addon-a11y: Deprecated `parameters.a11y.manual`\n\nWe have deprecated `parameters.a11y.manual` in 8.5. Please use `globals.a11y.manual` instead.\n\n### Addon-test: You should no longer copy the content of `viteFinal` to your configuration\n\nIn version 8.4 of `@storybook/experimental-addon-test`, it was required to copy any custom configuration you had in `viteFinal` in `main.ts`, to the Vitest Storybook project. This is no longer necessary, as the Storybook Test plugin will automatically include your `viteFinal` configuration. You should remove any configurations you might already have in `viteFinal` to remove duplicates.\n\nThis is especially the case for any plugins you might have, as they could now end up being loaded twice, which is likely to cause errors when running tests. In 8.4 we documented and automatically added some Vite plugins from Storybook frameworks like `@storybook/experimental-nextjs-vite` and `@storybook/sveltekit` - **these needs to be removed as well**.\n\n### Addon-test: Indexing behavior of @storybook/experimental-addon-test is changed\n\nThe Storybook test addon used to index stories based on the `test.include` field in the Vitest config file. This caused indexing issues with Storybook, because stories could have been indexed by Storybook and not Vitest, and vice versa. Starting in Storybook 8.5.0-alpha.18, we changed the indexing behavior so that it always uses the globs defined in the `stories` field in `.storybook/main.js` for a more consistent experience. It is now discouraged to use `test.include`, please remove it.\n\n## From version 8.2.x to 8.3.x\n\n### Removed `experimental_SIDEBAR_BOTTOM` and deprecated `experimental_SIDEBAR_TOP` addon types\n\nThe experimental SIDEBAR_BOTTOM addon type was removed in favor of a built-in filter UI. The enum type definition will remain available until Storybook 9.0 but will be ignored. Similarly the experimental SIDEBAR_TOP addon type is deprecated and will be removed in a future version.\n\nThese APIs allowed addons to render arbitrary content in the Storybook sidebar. Due to potential conflicts between addons and challenges regarding styling, these APIs are/will be removed. In the future, Storybook will provide declarative API hooks to allow addons to add content to the sidebar without risk of conflicts or UI inconsistencies. One such API is `experimental_updateStatus` which allow addons to set a status for stories. The SIDEBAR_BOTTOM slot is now used to allow filtering stories with a given status.\n\n### New parameters format for addon backgrounds\n\n> [!NOTE]\n> You need to set the feature flag `backgroundsStoryGlobals` to `true` in your `.storybook/main.ts` to use the new format and set the value with `globals`.\n>\n> See here how to set feature flags: https://storybook.js.org/docs/api/main-config/main-config-features\n> The `addon-backgrounds` addon now uses a new format for configuring its list of selectable backgrounds.\n> The `backgrounds` parameter is now an object with an `options` property.\n> This `options` object is a key-value pair where the key is used when setting the global value, the value is an object with a `name` and `value` property.\n\n```diff\n// .storybook/preview.js\nexport const parameters = {\n  backgrounds: {\n-   values: [\n-     { name: 'twitter', value: '#00aced' },\n-     { name: 'facebook', value: '#3b5998' },\n-   ],\n+   options: {\n+     twitter: { name: 'Twitter', value: '#00aced' },\n+     facebook: { name: 'Facebook', value: '#3b5998' },\n+   },\n  },\n};\n```\n\nSetting an override value should now be done via a `globals` property on your component/meta or story itself:\n\n```diff\n// Button.stories.ts\nexport default {\n  component: Button,\n- parameters: {\n-   backgrounds: {\n-     default: \"twitter\",\n-   },\n- },\n+ globals: {\n+   backgrounds: { value: \"twitter\" },\n+ },\n};\n```\n\nThis locks that story to the `twitter` background, it cannot be changed by the addon UI.\n\n### New parameters format for addon viewport\n\n> [!NOTE]\n> You need to set the feature flag `viewportStoryGlobals` to `true` in your `.storybook/main.ts` to use the new format and set the value with `globals`.\n>\n> See here how to set feature flags: https://storybook.js.org/docs/api/main-config/main-config-features\n> The `addon-viewport` addon now uses a new format for configuring its list of selectable viewports.\n> The `viewport` parameter is now an object with an `options` property.\n> This `options` object is a key-value pair where the key is used when setting the global value, the value is an object with a `name` and `styles` property.\n> The `styles` property is an object with a `width` and a `height` property.\n\n```diff\n// .storybook/preview.js\nexport const parameters = {\n  viewport: {\n-   viewports: {\n-     iphone5: {\n-       name: 'phone',\n-       styles: {\n-         width: '320px',\n-         height: '568px',\n-       },\n-     },\n-    },\n+   options: {\n+     iphone5: {\n+       name: 'phone',\n+       styles: {\n+         width: '320px',\n+         height: '568px',\n+       },\n+     },\n+   },\n  },\n};\n```\n\nSetting an override value should now be done via a `globals` property on your component/meta or story itself.\nAlso note the change from `defaultOrientation: \"landscape\"` to `isRotated: true`.\n\n```diff\n// Button.stories.ts\nexport default {\n  component: Button,\n- parameters: {\n-   viewport: {\n-     defaultViewport: \"iphone5\",\n-     defaultOrientation: \"landscape\",\n-   },\n- },\n+ globals: {\n+   viewport: {\n+     value: \"iphone5\",\n+     isRotated: true,\n+   },\n+ },\n};\n```\n\nThis locks that story to the `iphone5` viewport in landscape orientation, it cannot be changed by the addon UI.\n\n## From version 8.1.x to 8.2.x\n\n### Failed to resolve import \"@storybook/X\" error\n\nStorybook's package structure changed in 8.2. It is a non-breaking change, but can expose missing project dependencies.\n\nThis happens when `@storybook/X` is missing in your `package.json`, but your project references `@storybook/X` in your source code (typically in a story file or in a `.storybook` config file). This is a problem with your project, and if it worked in earlier versions of Storybook, it was purely accidental.\n\nNow in Storybook 8.2, that incorrect project configuration no longer works. The solution is to install `@storybook/X` as a dev dependency and re-run.\n\nExample errors:\n\n```sh\nCannot find module @storybook/preview-api or its corresponding type declarations\n```\n\n```sh\nInternal server error: Failed to resolve import \"@storybook/theming/create\" from \".storybook/theme.ts\". Does the file exist?\n```\n\nTo protect your project from missing dependencies, try the `no-extraneous-dependencies` rule in [eslint-plugin-import](https://www.npmjs.com/package/eslint-plugin-import).\n\n### Preview.js globals renamed to initialGlobals\n\nStarting in 8.2 `preview.js` `globals` are deprecated and have been renamed to `initialGlobals`. We will remove `preview.js` `globals` in 9.0.\n\n```diff\n// .storybook/preview.js\nexport default {\n-  globals: [ a: 1, b: 2 ],\n+  initialGlobals: [ a: 1, b: 2 ],\n}\n```\n\n## From version 8.0.x to 8.1.x\n\n### Portable stories\n\n#### @storybook/nextjs requires specific path aliases to be setup\n\nIn order to properly mock the `next/router`, `next/header`, `next/navigation` and `next/cache` APIs, the `@storybook/nextjs` framework includes internal Webpack aliases to those modules. If you use portable stories in your Jest tests, you should set the aliases in your Jest config files `moduleNameMapper` property using the `getPackageAliases` helper from `@storybook/nextjs/export-mocks`:\n\n```js\nconst nextJest = require('next/jest.js');\nconst { getPackageAliases } = require('@storybook/nextjs/export-mocks');\nconst createJestConfig = nextJest();\nconst customJestConfig = {\n  moduleNameMapper: {\n    ...getPackageAliases(), // Add aliases for @storybook/nextjs mocks\n  },\n};\nmodule.exports = createJestConfig(customJestConfig);\n```\n\nThis will make sure you end using the correct implementation of the packages and avoid having issues in your tests.\n\n### main.js `docs.autodocs` is deprecated\n\nThe `docs.autodocs` setting in `main.js` is deprecated in 8.1 and will be removed in 9.0.\n\nIt has been replaced with a tags-based system which is more flexible than before.\n\n`docs.autodocs` takes three values:\n\n- `true`: generate autodocs for every component\n- `false`: don't generate autodocs at all\n- `tag`: generate autodocs for components that have been tagged `'autodocs'`.\n\nStarting in 8.1, to generate autodocs for every component (`docs.autodocs = true`), add the following code to `.storybook/preview.js`:\n\n```js\n// .storybook/preview.js\nexport default {\n  tags: ['autodocs'],\n};\n```\n\nTags cascade, so setting `'autodocs'` at the project level automatically propagates to every component and story. If you set autodocs globally and want to opt-out for a particular component, you can remove the `'autodocs'` tag for a component like this:\n\n```js\n// Button.stories.ts\nexport default {\n  component: Button,\n  tags: ['!autodocs'],\n};\n```\n\nIf you had set `docs.autodocs = 'tag'`, the default setting, you can remove the setting from `.storybook/main.js`. That is now the default behavior.\n\nIf you had set `docs.autodocs = false`, this still works in 8.x, but will go away in 9.0 as a breaking change. If you don't want autodocs at all, simply remove the `'autodocs'` tag throughout your Storybook and autodocs will not be created.\n\n### `docs` and `story` system tags removed\n\nStorybook automatically added the tag `'docs'` to any docs entry in the index and `'story'` to any story entry in the index. This behavior was undocumented, and in an effort to reduce the number of tags we've removed them in 8.1. If you depended on these tags, please file an issue on the [Storybook monorepo](https://github.com/storybookjs/storybook) and let us know!\n\n### Subtitle block and `parameters.componentSubtitle`\n\nThe `Subtitle` block now accepts an `of` prop, which can be a reference to a CSF file or a default export (meta).\n\n`parameters.componentSubtitle` has been deprecated to be consistent with other parameters related to autodocs, instead use `parameters.docs.subtitle`.\n\n### Title block `of` prop\n\nThe `Title` block now accepts an `of` prop, which can be a reference to a CSF file or a default export (meta).\n\nIt still accepts being passed `children`.\n\n## From version 7.x to 8.0.0\n\n### Portable stories\n\n#### Project annotations are now merged instead of overwritten in composeStory\n\nWhen passing project annotations overrides via `composeStory` such as:\n\n```tsx\nconst projectAnnotationOverrides = { parameters: { foo: 'bar' } };\nconst Primary = composeStory(stories.Primary, stories, projectAnnotationOverrides);\n```\n\nthey are now merged with the annotations passed via `setProjectAnnotations` rather than completely overwriting them. This was seen as a bug and it's now fixed. If you have a use case where you really need this, please open an issue to elaborate.\n\n#### Type change in `composeStories` API\n\nThere is a TypeScript type change in the `play` function returned from `composeStories` or `composeStory` in `@storybook/react` or `@storybook/vue3`, where before it was always defined, now it is potentially undefined. This means that you might have to make a small change in your code, such as:\n\n```ts\nconst { Primary } = composeStories(stories)\n\n// before\nawait Primary.play(...)\n\n// after\nawait Primary.play?.(...) // if you don't care whether the play function exists\nawait Primary.play!(...) // if you want a runtime error when the play function does not exist\n```\n\nThere are plans to make the type of the play function be inferred based on your imported story's play function in a near future, so the types will be 100% accurate.\n\n#### Composed Vue stories are now components instead of functions\n\n`composeStory` (and `composeStories`) from `@storybook/vue3` now return Vue components rather than story functions that return components. This means that when rendering these composed stories you just pass the composed story _without_ first calling it.\n\nPreviously when using `composeStory` from `@storybook/testing-vue3`, you would render composed stories with e.g. `render(MyStoryComposedStory({ someProp: true}))`. That is now changed to more [closely match how you would render regular Vue components](https://testing-library.com/docs/vue-testing-library/examples).\n\nWhen migrating from `@storybook/testing-vue3`, you will likely hit the following error:\n\n```ts\nTypeError: Cannot read properties of undefined (reading 'devtoolsRawSetupState')\n```\n\nTo fix it, you should change the usage of the composed story to reference it instead of calling it as a function. Here's an example using `@testing-library/vue` and Vitest:\n\n```diff\nimport { it } from 'vitest';\nimport { render } from '@testing-library/vue';\nimport * as stories from './Button.stories';\nimport { composeStory } from '@storybook/vue3';\n\nit('renders primary button', () => {\n  const Primary = composeStory(stories.Primary, stories.default);\n-  render(Primary({ label: 'Hello world' }));\n+  render(Primary, { props: { label: 'Hello world' } });\n});\n```\n\n### Tab addons are now routed to a query parameter\n\nThe URL of a tab used to be: `http://localhost:6006/?path=/my-addon-tab/my-story`.\n\nThe new URL of a tab is `http://localhost:6006/?path=/story/my-story&tab=my-addon-tab`.\n\n### Default keyboard shortcuts changed\n\nThe default keyboard shortcuts have changed to avoid any conflicts with the browser's default shortcuts or when you are directly typing in the Manager. If you want to get the new default shortcuts, you can reset your shortcuts in the keyboard shortcuts panel by pressing the `Restore default` button.\n\n### Manager addons are now rendered with React 18\n\nThe UI added to the manager via addons is now rendered with React 18.\n\nExample:\n\n```tsx\nimport { addons, types } from '@storybook/manager-api';\n\naddons.register('my-addon', () => {\n  addons.add('my-addon/panel', {\n    type: types.PANEL,\n    title: 'My Addon',\n    // This will be called as a JSX element by react 18\n    render: ({ active }) => (active ? <div>Hello World</div> : null),\n  });\n});\n```\n\nPreviously the `key` prop was passed to the render function, that is now no longer the case.\n\n### Removal of `storiesOf`-API\n\nThe `storiesOf` API has been removed in Storybook 8.0.\n\nIf you need to dynamically create stories, you will need to implement this via the experimental `experimental_indexers` [API](#storyindexers-is-replaced-with-experimental_indexers).\n\nFor migrating to CSF, see: [`storyStoreV6` and `storiesOf` is deprecated](#storystorev6-and-storiesof-is-deprecated)\n\n### Removed deprecated shim packages\n\nIn Storybook 7, these packages existed for backwards compatibility, but were marked as deprecated:\n\n- `@storybook/addons` - this package has been split into 2 packages: `@storybook/preview-api` and `@storybook/manager-api`, see more here: [New Addons API](#new-addons-api).\n- `@storybook/channel-postmessage` - this package has been merged into `@storybook/channels`.\n- `@storybook/channel-websocket` - this package has been merged into `@storybook/channels`.\n- `@storybook/client-api` - this package has been merged into `@storybook/preview-api`.\n- `@storybook/core-client` - this package has been merged into `@storybook/preview-api`.\n- `@storybook/preview-web` - this package has been merged into `@storybook/preview-api`.\n- `@storybook/store` - this package has been merged into `@storybook/preview-api`.\n- `@storybook/api` - this package has been replaced with `@storybook/manager-api`.\n\nThese sections explain the rationale, and the required changes you might have to make:\n\n- [New Addons API](#new-addons-api)\n- [`addons.setConfig` should now be imported from `@storybook/manager-api`.](#addonssetconfig-should-now-be-imported-from-storybookmanager-api)\n\n### Deprecated `@storybook/testing-library` package\n\nThe `@storybook/testing-library` package has been deprecated with the release of Storybook 8.0, and we recommend using the `@storybook/test` package instead. If you're migrating manually, you'll need to install the new package and update your imports as follows:\n\n```diff\n- import { userEvent } from '@storybook/testing-library';\n+ import { userEvent } from '@storybook/test';\n```\n\n### Framework-specific Vite plugins have to be explicitly added\n\nIn Storybook 7, we would automatically add frameworks-specific Vite plugins, e.g. `@vitejs/plugin-react` if not installed.\nIn Storybook 8 those plugins have to be added explicitly in the user's `vite.config.ts`:\n\n#### For React:\n\n```ts\nimport react from '@vitejs/plugin-react';\nimport { defineConfig } from 'vite';\n\nexport default defineConfig({\n  plugins: [react()],\n});\n```\n\n#### For Vue:\n\n```ts\nimport vue from '@vitejs/plugin-vue';\nimport { defineConfig } from 'vite';\n\nexport default defineConfig({\n  plugins: [vue()],\n});\n```\n\n#### For Svelte (without Sveltekit):\n\n```ts\nimport { svelte } from '@sveltejs/vite-plugin-svelte';\nimport { defineConfig } from 'vite';\n\nexport default defineConfig({\n  plugins: [svelte()],\n});\n```\n\n#### For Preact:\n\n```ts\nimport preact from '@preact/preset-vite';\nimport { defineConfig } from 'vite';\n\nexport default defineConfig({\n  plugins: [preact()],\n});\n```\n\n#### For Solid:\n\n```ts\nimport { defineConfig } from 'vite';\nimport solid from 'vite-plugin-solid';\n\nexport default defineConfig({\n  plugins: [solid()],\n});\n```\n\n#### For Qwik:\n\n```ts\nimport { defineConfig } from 'vite';\nimport qwik from 'vite-plugin-qwik';\n\nexport default defineConfig({\n  plugins: [qwik()],\n});\n```\n\n### TurboSnap Vite plugin is no longer needed\n\nAt least in build mode, `builder-vite` now supports the `--webpack-stats-json` flag and will output `preview-stats.json`.\n\nThis means https://github.com/IanVS/vite-plugin-turbosnap is no longer necessary, and duplicative, and the plugin will automatically be removed if found.\n\n### `--webpack-stats-json` option renamed `--stats-json`\n\nNow that both Vite and Webpack support the `preview-stats.json` file, the flag has been renamed. The old flag will continue to work.\n\n### Implicit actions can not be used during rendering (for example in the play function)\n\nIn Storybook 7, we inferred if the component accepts any action props,\nby checking if it starts with `onX` (for example `onClick`), or as configured by `actions.argTypesRegex`.\nIf that was the case, we would fill in jest spies for those args automatically.\n\n```ts\nexport default {\n  component: Button,\n};\n\nexport const ButtonClick = {\n  play: async ({ args, canvasElement }) => {\n    await userEvent.click(within(canvasElement).getByRole('button'));\n    // args.onClick is a jest spy in 7.0\n    await expect(args.onClick).toHaveBeenCalled();\n  },\n};\n```\n\nIn Storybook 8 this feature is removed, and spies have to added explicitly:\n\n```ts\nimport { fn } from '@storybook/test';\n\nexport default {\n  component: Button,\n  args: {\n    onClick: fn(),\n  },\n};\n\nexport const ButtonClick = {\n  play: async ({ args, canvasElement }) => {\n    await userEvent.click(within(canvasElement).getByRole('button'));\n    await expect(args.onClick).toHaveBeenCalled();\n  },\n};\n```\n\nFor more context, see this RFC:\nhttps://github.com/storybookjs/storybook/discussions/23649\n\nTo summarize:\n\n- This makes CSF files less magical and more portable, so that CSF files will render the same in a test environment where docgen is not available.\n- This allows users and (test) integrators to run or build storybook without docgen, boosting the user performance and allows tools to give quicker feedback.\n- This will make sure that we can one day lazy load docgen, without changing how stories are rendered.\n\n### MDX related changes\n\n#### MDX is upgraded to v3\n\nStorybook now uses MDX3 under the hood. This change contains many improvements and a few small breaking changes that probably won't affect you. However we recommend checking the [migration notes from MDX here](https://mdxjs.com/blog/v3/).\n\n#### Dropping support for \\*.stories.mdx (CSF in MDX) format and MDX1 support\n\nIn Storybook 7, we deprecated the ability to use MDX for both documentation and story definition in the same .stories.mdx file. It is now removed, and Storybook won't support `.stories.mdx` files anymore. We provide migration scripts to help you onto the new format. To migrate your `.stories.mdx` files to the new format, you can run the following command:\n\n```sh\n# Convert stories in MDX to CSF\nnpx storybook@latest migrate mdx-to-csf --glob \"src/**/*.stories.mdx\"\n```\n\n> To ensure a smooth migration, you'll also need to:\n>\n> - Update your stories glob in your `.storybook/main.js` configuration to include the newly created `.mdx` and `.stories.js|ts` files.\n> - Manually remove the stories from the original `.stories.mdx` files, as by default the codemod won't delete them.\n\nIf you were using the [legacy MDX1 format](#legacy-mdx1-support), you will have to remove the `legacyMdx1` main.js feature flag and the `@storybook/mdx1-csf` package.\n\nAlongside with this change, the `jsxOptions` configuration was removed as it is not used anymore.\n\n#### Dropping support for id, name and story in Story block\n\nReferencing stories by `id`, `name` or `story` in the Story block is not possible anymore. [More info here](#story-block).\n\n### Core changes\n\n#### `framework.options.builder.useSWC` for Webpack5-based projects removed\n\nIn Storybook 8.0, we have removed the `framework.options.builder.useSWC` option. The `@storybook/builder-webpack5` package is now compiler-agnostic and does not depend on Babel or SWC.\n\nIf you want to use SWC, you can add the necessary addon:\n\n```sh\nnpx storybook@latest add @storybook/addon-webpack5-compiler-swc\n```\n\nThe goal is to make @storybook/builder-webpack5 lighter and more flexible. We are not locked into a specific compiler or compiler version anymore. This allows us to support Babel 7/8, SWC, and other compilers simultaneously.\n\n#### Removed `@babel/core` and `babel-loader` from `@storybook/builder-webpack5`\n\nIn Storybook 8.0, we have removed the `@storybook/builder-webpack5` package's dependency on Babel. This means that Babel is not preconfigured in `@storybook/builder-webpack5`. If you want to use Babel, you can add the necessary addon:\n\n```sh\nnpx storybook@latest add @storybook/addon-webpack5-compiler-babel\n```\n\nWe are doing this to make Storybook more flexible and to allow users to use a variety of compilers like SWC, Babel or even pure TypeScript.\n\n#### `framework.options.fastRefresh` for Webpack5-based projects removed\n\nIn Storybook 8.0, we have removed the `framework.options.fastRefresh` option.\n\nThe fast-refresh implementation currently relies on the `react-refresh/babel` package. While this has served us well, integrating this dependency could pose challenges. Specifically, it locks users into a specific Babel version. This could become a problem when Babel 8 is released. There is uncertainty about whether react-refresh/babel will seamlessly support Babel 8, potentially hindering users from updating smoothly.\n\nFurthermore, the existing implementation does not account for cases where fast-refresh might already be configured in a user's Babel configuration. Rather than filtering out existing configurations, our current approach could lead to duplications, resulting in a sub-optimal development experience.\n\nWe believe in empowering our users, and setting up fast-refresh manually is a straightforward process. The following configuration will configure fast-refresh if Storybook does not automatically pick up your fast-refresh configuration:\n\n`package.json`:\n\n```diff\n{\n  \"devDependencies\": {\n+   \"@pmmmwh/react-refresh-webpack-plugin\": \"^0.5.11\",\n+   \"react-refresh\": \"^0.14.0\",\n  }\n}\n```\n\n`babel.config.js` (optionally, add it to `.storybook/main.js`):\n\n```diff\n+const isProdBuild = process.env.NODE_ENV === 'production';\n\nmodule.exports = (api) => {\n  return {\n    plugins: [\n+     !isProdBuild && 'react-refresh/babel',\n    ].filter(Boolean),\n  };\n};\n```\n\n`.storybook/main.js`:\n\n```diff\n+import ReactRefreshWebpackPlugin from \"@pmmmwh/react-refresh-webpack-plugin\";\n+const isProdBuild = process.env.NODE_ENV === 'production';\nconst config = {\n  webpackFinal: (config) => {\n+   config.plugins = [\n+     !isProdBuild && new ReactRefreshWebpackPlugin({\n+       overlay: {\n+         sockIntegration: 'whm',\n+       },\n+     }),\n+     ...config.plugins,\n+   ].filter(Boolean);\n    return config;\n  },\n};\n\nexport default config;\n```\n\nThis approach aligns with our philosophy of transparency and puts users in control of their Webpack and Babel configurations.\n\nWe want to minimize magic behind the scenes. By removing `framework.options.fastRefresh`, we are reducing unnecessary configuration. Instead, we encourage users to leverage their existing Webpack and Babel setups, fostering a more transparent and customizable development environment.\n\nYou don't have to add fast refresh to `@storybook/nextjs` since it is already configured there as a default to match the same experience as `next dev`.\n\n#### `typescript.skipBabel` removed\n\nWe have removed the `typescript.skipBabel` option in Storybook 8.0. Please use `typescript.skipCompiler` instead.\n\n#### Dropping support for Yarn 1\n\nStorybook will stop providing fixes aimed at Yarn 1 projects. This does not necessarily mean that Storybook will stop working for Yarn 1 projects, just that the team won't provide more fixes aimed at it. For context, it's been 6 years since the release of Yarn 1, and Yarn is currently in version 4, which was [released in October 2023](https://yarnpkg.com/blog/release/4.0).\n\n#### Dropping support for Node.js 16\n\nIn Storybook 8, we have dropped Node.js 16 support since it reached end-of-life on 2023-09-11. Storybook 8 supports Node.js 18 and above.\n\n#### Autotitle breaking fixes\n\nIn Storybook 7, the file name `path/to/foo.bar.stories.js` would result in the [autotitle](https://storybook.js.org/docs/react/configure/overview#configure-story-loading) `path/to/foo`. In 8.0, this has been changed to generate `path/to/foo.bar`. We consider this a bugfix but it is also a breaking change if you depended on the old behavior. To get the old titles, you can manually specify the desired title in the default export of your story file. For example:\n\n```js\nexport default {\n  title: 'path/to/foo',\n};\n```\n\nAlternatively, if you need to achieve a different behavior for a large number of files, you can provide a [custom indexer](https://storybook.js.org/docs/8/configure/user-interface/sidebar-and-urls#story-index) to generate the titles dynamically.\n\n#### Storyshots has been removed\n\nStoryshots was an addon for Storybook which allowed users to turn their stories into automated snapshot tests.\n\nEvery story would automatically be taken into account and create a snapshot file.\n\nSnapshot testing has since fallen out of favor and is no longer recommended.\n\nIn addition to its limited use, and high chance of false positives, Storyshots ran code developed to run in the browser in NodeJS via JSDOM.\nJSDOM has limitations and is not a perfect emulation of the browser environment; therefore, Storyshots was always a pain to set up and maintain.\n\nThe Storybook team has built the test-runner as a direct replacement, which utilizes Playwright to connect to an actual browser where Storybook runs the code.\n\nIn addition, CSF has expanded to allow for play functions to be defined on stories, which allows for more complex testing scenarios, fully integrated within Storybook itself (and supported by the test-runner, and not Storyshots).\n\nFinally, storyStoreV7: true (the default and only option in Storybook 8), was not supported by Storyshots.\n\nBy removing Storyshots, the Storybook team was unblocked from moving (eventually) to an ESM-only Storybook, which is a big step towards a more modern Storybook.\n\nPlease check the [migration guide](https://storybook.js.org/docs/writing-tests/storyshots-migration-guide) that we prepared.\n\n#### UI layout state has changed shape\n\nIn Storybook 7 it was possible to use `addons.setConfig({...});` to configure Storybook UI features and behavior as documented [here (v7)](https://github.com/storybookjs/storybook/blob/release-7-3/docs/configure/features-and-behavior.md), [(latest)](https://storybook.js.org/docs/react/configure/features-and-behavior). The state and API for the UI layout has changed:\n\n- `showNav: boolean` is now `navSize: number`, where the number represents the size of the sidebar in pixels.\n- `showPanel: boolean` is now split into `bottomPanelHeight: number` and `rightPanelWidth: number`, where the numbers represents the size of the panel in pixels.\n- `isFullscreen: boolean` is no longer supported, but can be achieved by setting a combination of the above.\n\n#### New UI and props for Button and IconButton components\n\nWe used to have a lot of different buttons in `@storybook/components` that were not used anywhere. In Storybook 8.0 we are deprecating `Form.Button` and added a new `Button` component that can be used in all places. The `IconButton` component has also been updated to use the new `Button` component under the hood. Going forward addon creators and Storybook maintainers should use the new `Button` component instead of `Form.Button`.\n\nFor the `Button` component, the following props are now deprecated:\n\n- `isLink` - Please use the `asChild` prop instead like this: `<Button asChild><a href=\"\">Link</a></Button>`\n- `primary` - Please use the `variant` prop instead.\n- `secondary` - Please use the `variant` prop instead.\n- `tertiary` - Please use the `variant` prop instead.\n- `gray` - Please use the `variant` prop instead.\n- `inForm` - Please use the `variant` prop instead.\n- `small` - Please use the `size` prop instead.\n- `outline` - Please use the `variant` prop instead.\n- `containsIcon`. Please add your icon as a child directly. No need for this prop anymore.\n\nThe `IconButton` doesn't have any deprecated props but it now uses the new `Button` component under the hood so all props for `IconButton` will be the same as `Button`.\n\n#### Icons is deprecated\n\nIn Storybook 8.0 we are introducing a new icon library available with `@storybook/icons`. We are deprecating the `Icons` component in `@storybook/components` and recommend that addon creators and Storybook maintainers use the new `@storybook/icons` component instead.\n\n#### Removed postinstall\n\nWe removed the `@storybook/postinstall` package, which provided some utilities for addons to programmatically modify user configuration files on install. This package was years out of date, so this should be a non-disruptive change. If your addon used the package, you can view the old source code [here](https://github.com/storybookjs/storybook/tree/release-7-5/code/lib/postinstall) and adapt it into your addon.\n\n#### Removed stories.json\n\nIn addition to the built storybook, `storybook build` generates two files, `index.json` and `stories.json`, that list out the contents of the Storybook. `stories.json` is a legacy format and we included it for backwards compatibility. As of 8.0 we no longer build `stories.json` by default, and we will remove it completely in 9.0.\n\nIn the meantime if you have code that relies on `stories.json`, you can find code that transforms the \"v4\" `index.json` to the \"v3\" `stories.json` format (and their respective TS types): https://github.com/storybookjs/storybook/blob/release-7-5/code/lib/core-server/src/utils/stories-json.ts#L71-L91\n\n#### Removed `sb babelrc` command\n\nThe `sb babelrc` command was used to generate a `.babelrc` file for Storybook. This command is now removed.\n\nFrom version 8.0 onwards, Storybook is compiler-agnostic and does not depend on Babel or SWC if you use Webpack 5. This move was made to make Storybook more flexible and allow users to configure their own Babel setup according to their project needs and setup. If you need a custom Babel configuration, you can create a `.babelrc` file yourself and configure it according to your project setup.\n\nThe reasoning behind is to condense and provide some clarity to what's happened to both the command and what's shifted with the upcoming release.\n\n#### Changed interfaces for `@storybook/router` components\n\nThe `hideOnly` prop has been removed from the `<Route />` component in `@storybook/router`. If needed this can be implemented manually with the `<Match />` component.\n\n#### Extract no longer batches\n\n`Preview.extract()` no longer loads CSF files in batches. This was a workaround for resource limitations that slowed down extract. This shouldn't affect behaviour.\n\n### Framework-specific changes\n\n#### React\n\n##### `react-docgen` component analysis by default\n\nIn Storybook 7, we used `react-docgen-typescript` to analyze React component props and auto-generate controls. In Storybook 8, we have moved to `react-docgen` as the new default. `react-docgen` is dramatically more efficient, shaving seconds off of dev startup times. However, it only analyzes basic TypeScript constructs.\n\nWe feel `react-docgen` is the right tradeoff for most React projects. However, if you need the full fidelity of `react-docgen-typescript`, you can opt-in using the following setting in `.storybook/main.js`:\n\n```js\nexport default {\n  typescript: {\n    reactDocgen: 'react-docgen-typescript',\n  },\n};\n```\n\nFor more information see: https://storybook.js.org/docs/react/api/main-config-typescript#reactdocgen\n\n#### Next.js\n\n##### Require Next.js 13.5 and up\n\nStarting in 8.0, Storybook requires Next.js 13.5 and up.\n\n##### Automatic SWC mode detection\n\nSimilar to how Next.js detects if SWC should be used, Storybook will follow more or less the same rules:\n\n- If you use Next.js 14 or higher and you don't have a .babelrc file, Storybook will use SWC to transpile your code.\n- Even if you have a .babelrc file, Storybook will still use SWC to transpile your code if you set the experimental `experimental.forceSwcTransforms` flag to `true` in your `next.config.js`.\n\n##### RSC config moved to React renderer\n\nStorybook 7.6 introduced a new feature flag, `experimentalNextRSC`, to enable React Server Components in a Next.js project. It also introduced a parameter `nextjs.rsc` to selectively disable it on particular components or stories.\n\nThese flags have been renamed to `experimentalRSC` and `react.rsc`, respectively. This is a breaking change to accommodate RSC support in other, non-Next.js frameworks. For now, `@storybook/nextjs` is the only framework that supports it, and does so experimentally.\n\n#### Vue\n\n##### Require Vue 3 and up\n\nStarting in 8.0, Storybook requires Vue 3 and up.\n\n#### Angular\n\n##### Require Angular 15 and up\n\nStarting in 8.0, Storybook requires Angular 15 and up.\n\n#### Svelte\n\n##### Require Svelte 4 and up\n\nStarting in 8.0, Storybook requires Svelte 4 and up.\n\n#### Preact\n\n##### Require Preact 10 and up\n\nStarting in 8.0, Storybook requires Preact 10 and up.\n\n##### No longer adds default Babel plugins\n\nUntil now, Storybook provided a set of default Babel plugins that were applied to Preact projects using Webpack, including the runtime automatic import plugin to allow Preact's `h` pragma to render JSX. However, this is no longer the case in Storybook 8.0. If you want to use this plugin, or if you're going to use TypeScript with Preact, you will need to add it to your Babel config.\n\n```js\n.babelrc\n\n{\n  \"plugins\": [\n    [\n      // Add this to automatically import `h` from `preact` when needed\n      \"@babel/plugin-transform-react-jsx\", {\n        \"importSource\": \"preact\",\n        \"runtime\": \"automatic\"\n      }\n    ],\n    // Add this if you want to use TypeScript with Preact\n    \"@babel/preset-typescript\"\n  ],\n}\n```\n\nIf you want to configure the plugins only for Storybook, you can add the same setting to your `.storybook/main.js` file.\n\n```js\nconst config = {\n  ...\n  babel: async (options) => {\n    options.plugins.push(\n      [\n        \"@babel/plugin-transform-react-jsx\", {\n          \"importSource\": \"preact\",\n          \"runtime\": \"automatic\"\n        }\n      ],\n      \"@babel/preset-typescript\"\n    )\n    return options;\n  },\n}\n\nexport default config\n```\n\nWe are doing this to apply the same configuration you defined in your project. This streamlines the experience of using Storybook with Preact. Additionally, we are not vendor-locked to a specific Babel version anymore, which means that you can upgrade Babel without breaking your Storybook.\n\n#### Web Components\n\n##### Dropping default babel plugins in Webpack5-based projects\n\nUntil the 8.0 release, Storybook provided the `@babel/preset-env` preset for Web Component projects by default. This is no longer the case, as any Web Components project will use the configuration you've included. Additionally, if you're using either the `@babel/plugin-syntax-dynamic-import` or `@babel/plugin-syntax-import-meta` plugins, you no longer have to include them as they are now part of `@babel/preset-env`.\n\n### Deprecations which are now removed\n\n#### Removed `config` preset\n\nIn Storybook 7.0 we have deprecated the preset field `config` and it has been replaced with 'previewAnnotations'. The `config` preset is now completely removed in Storybook 8.0.\n\n```diff\n// .storybook/main.js\n\n// before\nconst config = {\n  framework: \"@storybook/your-framework\",\n- config: (entries) => [...entries, yourEntry],\n+ previewAnnotations: (entries) => [...entries, yourEntry],\n};\n\nexport default config;\n```\n\n#### Removed `passArgsFirst` option\n\nSince Storybook 6, we have had an option called `parameters.passArgsFirst` (default=`true`), which sallows you to pass the context to the story function first when set to `false.` We have removed this option. In Storybook 8.0, the args are always passed first, and as a second argument, the context is passed.\n\n```js\n// Storybook < 8\nexport default {\n  parameters: {\n    passArgsFirst: false,\n  },\n};\n\nexport const Button = (context) => <button {...args} />;\n\n// Storybook >= 8\nexport const Button = (args, context) => <button {...args} />;\n```\n\n#### Methods and properties from AddonStore\n\nThe following methods and properties from the class `AddonStore` in `@storybook/manager-api` are now removed:\n\n- `serverChannel` -> Use `channel` instead\n- `getServerChannel` -> Use `getChannel` instead\n- `setServerChannel` -> Use `setChannel` instead\n- `hasServerChannel` -> Use `hasChannel` instead\n- `addPanel`\n\nThe following methods and properties from the class `AddonStore` in `@storybook/preview-api` are now removed:\n\n- `serverChannel` -> Use `channel` instead\n- `getServerChannel` -> Use `getChannel` instead\n- `setServerChannel` -> Use `setChannel` instead\n- `hasServerChannel` -> Use `hasChannel` instead\n\n#### Methods and properties from PreviewAPI\n\nThe following exports from `@storybook/preview-api` are now removed:\n\n- `useSharedState`\n- `useAddonState`\n\nPlease file an issue if you need these APIs.\n\n#### Removals in @storybook/components\n\nThe `TooltipLinkList` UI component used to customize the Storybook toolbar has been updated to use the `icon` property instead of the `left` property to position its content. If you've enabled this property in your `globalTypes` configuration, addons, or any other place, you'll need to replace it with an `icon` property to mimic the same behavior. For example:\n\n```diff\n// .storybook/preview.js|ts\n// Replace your-framework with the framework you are using (e.g., react, vue3)\nimport { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  globalTypes: {\n    locale: {\n      description: 'Internationalization locale',\n      defaultValue: 'en',\n      toolbar: {\n        icon: 'globe',\n        items: [\n          {\n            value: 'en',\n            right: '🇺🇸',\n-            left: '＄'\n+            icon: 'facehappy'\n            title: 'English'\n          },\n          { value: 'fr', right: '🇫🇷', title: 'Français' },\n          { value: 'es', right: '🇪🇸', title: 'Español' },\n          { value: 'zh', right: '🇨🇳', title: '中文' },\n          { value: 'kr', right: '🇰🇷', title: '한국어' },\n        ],\n      },\n    },\n  },\n};\n\nexport default preview;\n```\n\nTo learn more about the available icons and their names, see the [Storybook documentation](https://storybook.js.org/docs/8.0/faq#what-icons-are-available-for-my-toolbar-or-my-addon).\n\n#### Removals in @storybook/types\n\nThe following exports from `@storybook/types` are now removed:\n\n- `API_ADDON` -> Use `Addon_Type` instead\n- `API_COLLECTION` -> Use `Addon_Collection` instead\n- `API_Panels`\n\n#### --use-npm flag in storybook CLI\n\nThe `--use-npm` is now removed. Use `--package-manager=npm` instead. [More info here](#cli-option---use-npm-deprecated).\n\n#### hideNoControlsWarning parameter from addon controls\n\nThe `hideNoControlsWarning` parameter is now removed. [More info here](#addon-controls-hidenocontrolswarning-parameter-is-deprecated).\n\n#### `setGlobalConfig` from `@storybook/react`\n\nThe `setGlobalConfig` (used for reusing stories in your tests) is now removed in favor of `setProjectAnnotations`.\n\n```ts\nimport { setProjectAnnotations } from `@storybook/react`.\n```\n\n#### StorybookViteConfig type from @storybook/builder-vite\n\nThe `StorybookViteConfig` type is now removed in favor of `StorybookConfig`:\n\n```ts\nimport type { StorybookConfig } from '@storybook/react-vite';\n```\n\n#### props from WithTooltipComponent from @storybook/components\n\nThe deprecated properties `tooltipShown`, `closeOnClick`, and `onVisibilityChange` of `WithTooltipComponent` from `@storybook/components` are now removed. Please replace them:\n\n```tsx\n<WithTooltip\n  closeOnClick // becomes closeOnOutsideClick\n  tooltipShown // becomes defaultVisible\n  onVisibilityChange // becomes onVisibleChange\n>\n  ...\n</WithTooltip>;\n```\n\n#### LinkTo direct import from addon-links\n\nThe `LinkTo` (React component) direct import from `@storybook/addon-links` is now removed. You have to import it from `@storybook/addon-links/react` instead.\n\n```ts\n// before\nimport LinkTo from '@storybook/addon-links';\n\n// after\nimport LinkTo from '@storybook/addon-links/react';\n```\n\n#### DecoratorFn, Story, ComponentStory, ComponentStoryObj, ComponentStoryFn and ComponentMeta TypeScript types\n\nThe `Story` type is now removed in favor of `StoryFn` and `StoryObj`. More info [here](#story-type-deprecated).\n\nThe `DecoratorFn` type is now removed in favor of `Decorator`. [More info](#renamed-decoratorfn-to-decorator).\n\nFor React, the `ComponentStory`, `ComponentStoryObj`, `ComponentStoryFn` and `ComponentMeta` types are now removed in favor of `StoryFn`, `StoryObj` and `Meta`. [More info](#componentstory-componentstoryobj-componentstoryfn-and-componentmeta-types-are-deprecated).\n\n#### \"Framework\" TypeScript types\n\nThe Framework types such as `ReactFramework` are now removed in favor of Renderer types such as `ReactRenderer`. This affects all frameworks. [More info](#renamed-xframework-to-xrenderer).\n\n#### `navigateToSettingsPage` method from Storybook's manager-api\n\nThe `navigateToSettingsPage` method from manager-api is now removed in favor of `changeSettingsTab`.\n\n```ts\nexport const Component = () => {\n  const api = useStorybookApi();\n\n  const someHandler = () => {\n    // Old method: api.navigateToSettingsPage('/settings/about');\n    api.changeSettingsTab('about'); // the /settings path is not necessary anymore\n  };\n\n  // ...\n};\n```\n\n#### storyIndexers\n\nThe Storybook's main.js configuration property `storyIndexers` is now removed in favor of `experimental_indexers`. [More info](#storyindexers-is-replaced-with-experimental_indexers).\n\n#### Deprecated docs parameters\n\nThe following story and meta parameters are now removed:\n\n```ts\nparameters.docs.iframeHeight; // becomes docs.story.iframeHeight\nparameters.docs.inlineStories; // becomes docs.story.inline\nparameters.jsx.transformSource; // becomes parameters.docs.source.transform\nparameters.docs.transformSource; // becomes parameters.docs.source.transform\nparameters.docs.source.transformSource; // becomes parameters.docs.source.transform\n```\n\nMore info [here](#autodocs-changes) and [here](#source-block).\n\n#### Description Doc block properties\n\n`children`, `markdown` and `type` are now removed in favor of the `of` property. [More info](#doc-blocks).\n\n#### Story Doc block properties\n\nThe `story` prop is now removed in favor of the `of` property. [More info](#doc-blocks).\n\nAdditionally, given that CSF in MDX is not supported anymore, the following props are also removed: `args`, `argTypes`, `decorators`, `loaders`, `name`, `parameters`, `play`, `render`, and `storyName`. [More info](#dropping-support-for-storiesmdx-csf-in-mdx-format-and-mdx1-support).\n\n#### Manager API expandAll and collapseAll methods\n\nThe `collapseAll` and `expandAll` APIs (possibly used by addons) are now removed. Please emit events for these actions instead:\n\n```ts\nimport { STORIES_COLLAPSE_ALL, STORIES_EXPAND_ALL } from '@storybook/core-events';\nimport { useStorybookApi } from '@storybook/manager-api';\n\nconst api = useStorybookApi();\napi.collapseAll(); // becomes api.emit(STORIES_COLLAPSE_ALL)\napi.expandAll(); // becomes api.emit(STORIES_EXPAND_ALL)\n```\n\n#### `ArgsTable` Doc block removed\n\nThe `ArgsTable` doc block has been removed in favor of `ArgTypes` and `Controls`. [More info](#argstable-block).\n\nWith this removal we've reintroduced `subcomponents` support to `ArgTypes`, `Controls`, and autodocs. We've also undeprecated `subcomponents`, by popular demand.\n\n#### `Source` Doc block properties\n\n`id` and `ids` are now removed in favor of the `of` property. [More info](#doc-blocks).\n\n#### `Canvas` Doc block properties\n\nThe following properties were removed from the Canvas Doc block:\n\n- children\n- isColumn\n- columns\n- withSource\n- mdxSource\n\n[More info](#doc-blocks).\n\n#### `Primary` Doc block properties\n\nThe `name` prop is now removed in favor of the `of` property. [More info](#doc-blocks).\n\n#### `createChannel` from `@storybook/postmessage` and `@storybook/channel-websocket`\n\nThe `createChannel` APIs from both `@storybook/channel-websocket` and `@storybook/postmessage` are now removed. Please use `createBrowserChannel` instead, from the `@storybook/channels` package.\n\nAdditionally, the `PostmsgTransport` type is now removed in favor of `PostMessageTransport`.\n\n#### StoryStore and methods deprecated\n\nThe StoryStore (`__STORYBOOK_STORY_STORE__` and `__STORYBOOK_PREVIEW__.storyStore`) are deprecated, and will no longer be accessible in Storybook 9.0.\n\nIn particular, the following methods on the `StoryStore` are deprecated and will be removed in 9.0:\n\n- `store.fromId()` - please use `preview.loadStory({ storyId })` instead.\n- `store.raw()` - please use `preview.extract()` instead.\n\nNote that both these methods require initialization, so you should await `preview.ready()`.\n\n### Addon author changes\n\n#### Tab addons cannot manually route, Tool addons can filter their visibility via tabId\n\nThe TAB type addons now should no longer specify the `match` or `route` property.\n\nInstead storybook will automatically show the addon's rendered content when the query parameter `tab` is set to the addon's ID.\n\nExample:\n\n```tsx\nimport { addons, types } from '@storybook/manager-api';\n\naddons.register('my-addon', () => {\n  addons.add('my-addon/tab', {\n    type: types.TAB,\n    title: 'My Addon',\n    render: () => <div>Hello World</div>,\n  });\n});\n```\n\nTool type addon will now receive the `tabId` property passed to their `match` function.\nThat way they can chose to show/hide their content based on the current tab.\n\nWhen the canvas is shown, the `tabId` will be set to `undefined`.\n\nExample:\n\n```tsx\nimport { addons, types } from '@storybook/manager-api';\n\naddons.register('my-addon', () => {\n  addons.add('my-addon/tool', {\n    type: types.TOOL,\n    title: 'My Addon',\n    match: ({ tabId }) => tabId === 'my-addon/tab',\n    render: () => <div>👀</div>,\n  });\n});\n```\n\n#### Removed `config` preset\n\nIn Storybook 7.0 we have deprecated the preset field `config` and it has been replaced with `previewAnnotations`. The `config` preset is now completely removed in Storybook 8.0.\n\n```diff\n// your-addon/preset.js\n\nmodule.exports = {\n-  config: (entries = []) => [...entries, ...yourEntry],\n+  previewAnnotations: (entries = []) => [...entries, ...yourEntry],\n};\n```\n\n## From version 7.5.0 to 7.6.0\n\n#### CommonJS with Vite is deprecated\n\nUsing CommonJS in the `main` configuration with `main.cjs` or `main.cts` is deprecated, and will be removed in Storybook 8.0. This is a necessary change because [Vite will remove support for CommonJS in an upcoming release](https://github.com/vitejs/vite/discussions/13928).\n\nYou can address this by converting your `main` configuration file to ESM syntax and renaming it to `main.mjs` or `main.mts` if your project does not have `\"type\": \"module\"` in its `package.json`. To convert the config file to ESM you will need to replace any CommonJS syntax like `require()`, `module.exports`, or `__dirname`. If you haven't already, you may also consider adding `\"type\": \"module\"` to your package.json and converting your project to ESM.\n\n#### Using implicit actions during rendering is deprecated\n\nIn Storybook 7, we inferred if the component accepts any action props,\nby checking if it starts with `onX` (for example `onClick`), or as configured by `actions.argTypesRegex`.\nIf that was the case, we would fill in jest spies for those args automatically.\n\n```ts\nexport default {\n  component: Button,\n};\n\nexport const ButtonClick = {\n  play: async ({ args, canvasElement }) => {\n    await userEvent.click(within(canvasElement).getByRole('button'));\n    // args.onClick is a jest spy in 7.0\n    await expect(args.onClick).toHaveBeenCalled();\n  },\n};\n```\n\nIn Storybook 8 this feature will be removed, and spies have to added explicitly:\n\n```ts\nimport { fn } from '@storybook/test';\n\nexport default {\n  component: Button,\n  args: {\n    onClick: fn(),\n  },\n};\n\nexport const ButtonClick = {\n  play: async ({ args, canvasElement }) => {\n    await userEvent.click(within(canvasElement).getByRole('button'));\n    await expect(args.onClick).toHaveBeenCalled();\n  },\n};\n```\n\nFor more context, see this RFC:\nhttps://github.com/storybookjs/storybook/discussions/23649\n\nTo summarize:\n\n- This makes CSF files less magical and more portable, so that CSF files will render the same in a test environment where docgen is not available.\n- This allows users and (test) integrators to run or build storybook without docgen, boosting the user performance and allows tools to give quicker feedback.\n- This will make sure that we can one day lazy load docgen, without changing how stories are rendered.\n\n#### typescript.skipBabel deprecated\n\nWe will remove the `typescript.skipBabel` option in Storybook 8.0. Please use `typescript.skipCompiler` instead.\n\n#### Primary doc block accepts of prop\n\nThe `Primary` doc block now also accepts an `of` prop as described in the [Doc Blocks](#doc-blocks) section. It still accepts being passed `name` or no props at all.\n\n#### Addons no longer need a peer dependency on React\n\nHistorically the majority of addons have had a peer dependency on React and a handful of Storybook core packages. In most cases this has not been necessary since 7.0 because the Storybook manager makes those available on the global scope. It has created an unnecessary burden for users in non-React projects.\n\nWe've migrated all the core addons (except for `addon-docs`) to not depend on these packages by:\n\n1. Moving `react`, `react-dom` and the globalized Storybook packages from `peerDependencies` to `devDependencies`\n2. Added the list of globalized packages to the `externals` property in the `tsup` configuration, to ensure they are not part of the bundle.\n\nAs of Storybook 7.6.0 the list of globalized packages can be imported like this:\n\n```ts\n// tsup.config.ts\nimport { globalPackages as globalManagerPackages } from '@storybook/manager/globals';\nimport { globalPackages as globalPreviewPackages } from '@storybook/preview/globals';\n\nconst allGlobalPackages = [...globalManagerPackages, ...globalPreviewPackages];\n```\n\nWe recommend checking out [the updates we've made to the addon-kit](https://github.com/storybookjs/addon-kit/pull/60/files#diff-8fed899bdbc24789a7bb4973574e624ed6207c6ce572338bc3c3e117672b2a20), that can serve as a base for the changes you can do in your own addon. These changes are not necessary for your addon to keep working, but they will remove the need for your users to unnecessary install `react` and `react-dom` to their projects, and they'll significantly reduce the install size of your addon.\nThese changes should not be breaking for your users, unless you support Storybook pre-v7.\n\n## From version 7.4.0 to 7.5.0\n\n#### `storyStoreV6` and `storiesOf` is deprecated\n\n`storyStoreV6` and `storiesOf` is deprecated and will be completely removed in Storybook 8.0.\n\nIf you're using `storiesOf` we recommend you migrate your stories to CSF3 for a better story writing experience.\nIn many cases you can get started with the migration by using two migration scripts:\n\n```bash\n\n# 1. convert storiesOf to CSF\nnpx storybook@latest migrate storiesof-to-csf --glob=\"**/*.stories.tsx\" --parser=tsx\n\n# 2. Convert CSF 2 to CSF 3\nnpx storybook@latest migrate csf-2-to-3 --glob=\"**/*.stories.tsx\" --parser=tsx\n```\n\nThey won't do a perfect migration so we recommend that you manually go through each file afterwards.\n\nAlternatively you can build your own `storiesOf` implementation by leveraging the new (experimental) indexer API ([documentation](https://storybook.js.org/docs/react/api/main-config-indexers), [migration](#storyindexers-is-replaced-with-experimental_indexers)). A proof of concept of such an implementation can be seen in [this StackBlitz demo](https://stackblitz.com/edit/github-h2rgfk?file=README.md). See the demo's `README.md` for a deeper explanation of the implementation.\n\n#### `storyIndexers` is replaced with `experimental_indexers`\n\nDefining custom indexers for stories has become a more official - yet still experimental - API which is now configured at `experimental_indexers` instead of `storyIndexers` in `main.ts`. `storyIndexers` has been deprecated and will be fully removed in version 8.0.\n\nThe new experimental indexers are documented [here](https://storybook.js.org/docs/react/api/main-config-indexers). The most notable change from `storyIndexers` is that the indexer must now return a list of [`IndexInput`](https://github.com/storybookjs/storybook/blob/next/code/lib/types/src/modules/indexer.ts#L104-L148) instead of `CsfFile`. It's possible to construct an `IndexInput` from a `CsfFile` using the `CsfFile.indexInputs` getter.\n\nThat means you can convert an existing story indexer like this:\n\n```diff\n// .storybook/main.ts\n\nimport { readFileSync } from 'fs';\nimport { loadCsf } from '@storybook/csf-tools';\n\nexport default {\n-  storyIndexers = (indexers) => {\n-    const indexer = async (fileName, opts) => {\n+  experimental_indexers = (indexers) => {\n+    const createIndex = async (fileName, opts) => {\n      const code = readFileSync(fileName, { encoding: 'utf-8' });\n      const makeTitle = (userTitle) => {\n        // Do something with the auto title retrieved by Storybook\n        return userTitle;\n      };\n\n      // Parse the CSF file with makeTitle as a custom context\n-      return loadCsf(code, { ...compilationOptions, makeTitle, fileName }).parse();\n+      return loadCsf(code, { ...compilationOptions, makeTitle, fileName }).parse().indexInputs;\n    };\n\n    return [\n      {\n        test: /(stories|story)\\.[tj]sx?$/,\n-        indexer,\n+        createIndex,\n      },\n      ...(indexers || []),\n    ];\n  },\n};\n```\n\nAs an addon author you can support previous versions of Storybook by setting both `storyIndexers` and `indexers_experimental`, without triggering the deprecation warning.\n\n## From version 7.0.0 to 7.2.0\n\n#### Addon API is more type-strict\n\nWhen registering an addon using `@storybook/manager-api`, the addon API is now more type-strict. This means if you use TypeScript to compile your addon before publishing, it might start giving you errors.\n\nThe `type` property is now a required field, and the `id` property should not be set anymore.\n\nHere's a correct example:\n\n```tsx\nimport { addons, types } from '@storybook/manager-api';\n\naddons.register('my-addon', () => {\n  addons.add('my-addon/panel', {\n    type: types.PANEL,\n    title: 'My Addon',\n    render: ({ active }) => (active ? <div>Hello World</div> : null),\n  });\n});\n```\n\nThe API: `addons.addPanel()` is now deprecated, and will be removed in 8.0. Please use `addons.add()` instead.\n\nThe `render` method can now be a `React.FunctionComponent` (without the `children` prop). Storybook will now render it, rather than calling it as a function.\n\n#### Addon-controls hideNoControlsWarning parameter is deprecated\n\nThe `hideNoControlsWarning` parameter is now unused and deprecated, given that the UI of the Controls addon changed in a way that does not display that message anymore.\n\n```ts\nexport const Primary = {\n  parameters: {\n    controls: { hideNoControlsWarning: true }, // this parameter is now unnecessary\n  },\n};\n```\n\n## From version 6.5.x to 7.0.0\n\nA number of these changes can be made automatically by the Storybook CLI. To take advantage of these \"automigrations\", run `npx storybook@7 upgrade` or `pnpx dlx storybook@7 upgrade`.\n\n### 7.0 breaking changes\n\n#### Dropped support for Node 15 and below\n\nStorybook 7.0 requires **Node 16** or above. If you are using an older version of Node, you will need to upgrade or keep using Storybook 6 in the meantime.\n\n#### Default export in Preview.js\n\nStorybook 7.0 supports a default export in `.storybook/preview.js` that should contain all of its annotations. The previous format is still compatible, but **the default export will be the recommended way going forward**.\n\nIf your `preview.js` file looks like this:\n\n```js\nexport const parameters = {\n  actions: { argTypesRegex: '^on[A-Z].*' },\n};\n```\n\nPlease migrate it to use a default export instead:\n\n```js\nconst preview = {\n  parameters: {\n    actions: { argTypesRegex: '^on[A-Z].*' },\n  },\n};\nexport default preview;\n```\n\nAdditionally, we introduced typings for that default export (Preview), so you can import it in your config file. If you're using Typescript, make sure to rename your file to be `preview.ts`.\n\nThe `Preview` type will come from the Storybook package for the **renderer** you are using. For example, if you are using Angular, you will import it from `@storybook/angular`, or if you're using Vue3, you will import it from `@storybook/vue3`:\n\n```ts\nimport { Preview } from '@storybook/react';\n\nconst preview: Preview = {\n  parameters: {\n    actions: { argTypesRegex: '^on[A-Z].*' },\n  },\n};\nexport default preview;\n```\n\nIn JavaScript projects using `preview.js`, it's also possible to use the `Preview` type (for autocompletion, not type safety), via the JSDoc @type tag:\n\n```js\n/** @type {import('@storybook/react').Preview} */\nconst preview = {\n  parameters: {\n    actions: { argTypesRegex: '^on[A-Z].*' },\n  },\n};\nexport default preview;\n```\n\n#### ESM format in Main.js\n\nIt's now possible to use ESM in `.storybook/main.js` out of the box. Storybook 7.0 supports a default export in `.storybook/main.js` that should contain all of its configurations. The previous format is still compatible, but **the default export will be the recommended way going forward**.\n\nIf your main.js file looks like this:\n\n```js\nmodule.exports = {\n  stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'],\n  framework: { name: '@storybook/react-vite' },\n};\n```\n\nOr like this:\n\n```js\nexport const stories = ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'];\nexport const framework = { name: '@storybook/react-vite' };\n```\n\nPlease migrate it to use a default export instead:\n\n```js\nconst config = {\n  stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'],\n  framework: { name: '@storybook/react-vite' },\n};\nexport default config;\n```\n\nAdditionally, we introduced typings for that default export (StorybookConfig), so you can import it in your config file. If you're using Typescript, make sure to rename your file to be `main.ts`.\n\nThe `StorybookConfig` type will come from the Storybook package for the **framework** you are using, which relates to the package in the \"framework\" field you have in your main.ts file. For example, if you are using React Vite, you will import it from `@storybook/react-vite`:\n\n```ts\nimport { StorybookConfig } from '@storybook/react-vite';\n\nconst config: StorybookConfig = {\n  stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'],\n  framework: { name: '@storybook/react-vite' },\n};\nexport default config;\n```\n\nIn JavaScript projects using `main.js`, it's also possible to use the `StorybookConfig` type (for autocompletion, not type safety), via the JSDoc @type tag:\n\n```ts\n/** @type {import('@storybook/react-vite').StorybookConfig} */\nconst config = {\n  stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'],\n  framework: { name: '@storybook/react-vite' },\n};\nexport default config;\n```\n\n#### Modern browser support\n\nStarting in Storybook 7.0, Storybook will no longer support IE11, amongst other legacy browser versions.\nWe now transpile our code with a target of `chrome >= 100` and node code is transpiled with a target of `node >= 16`.\n\nThis means code-features such as (but not limited to) `async/await`, arrow-functions, `const`,`let`, etc will exist in the code at runtime, and thus the runtime environment must support it.\nNot just the runtime needs to support it, but some legacy loaders for Webpack or other transpilation tools might need to be updated as well. For example, certain versions of Webpack 4 had parsers that could not parse the new syntax (e.g. optional chaining).\n\nSome addons or libraries might depended on this legacy browser support, and thus might break. You might get an error like:\n\n```\nregeneratorRuntime is not defined\n```\n\nTo fix these errors, the addon will have to be re-released with a newer browser-target for transpilation. This often looks something like this (but it's dependent on the build system the addon uses):\n\n```js\n// babel.config.js\nmodule.exports = {\n  presets: [\n    [\n      '@babel/preset-env',\n      {\n        shippedProposals: true,\n        useBuiltIns: 'usage',\n        corejs: '3',\n        modules: false,\n        targets: { chrome: '100' },\n      },\n    ],\n  ],\n};\n```\n\nHere's an example PR to one of the Storybook addons: https://github.com/storybookjs/addon-coverage/pull/3 doing just that.\n\n#### React peer dependencies required\n\n_Has automigration_\n\nStarting in 7.0, `react` and `react-dom` are now required peer dependencies of Storybook when using addon-docs (or docs via addon-essentials).\n\nStorybook uses `react` in a variety of docs-related packages. In the past, we've done various trickery hide this from non-React users. However, with stricter peer dependency handling by `npm8`, `npm`, and `yarn pnp` those tricks have started to cause problems for those users. Rather than resorting to even more complicated tricks, we are making `react` and `react-dom` required peer dependencies.\n\nTo upgrade manually, add any version of `react` and `react-dom` as devDependencies using your package manager of choice, e.g.\n\n```\nnpm add react react-dom --save-dev\n```\n\n#### start-storybook / build-storybook binaries removed\n\n_Has automigration_\n\nSB6.x framework packages shipped binaries called `start-storybook` and `build-storybook`.\n\nIn SB7.0, we've removed these binaries and replaced them with new commands in Storybook's CLI: `storybook dev` and `storybook build`. These commands will look for the `framework` field in your `.storybook/main.js` config--[which is now required](#framework-field-mandatory)--and use that to determine how to start/build your Storybook. The benefit of this change is that it is now possible to install multiple frameworks in a project without having to worry about hoisting issues.\n\nA typical Storybook project includes two scripts in your projects `package.json`:\n\n```json\n{\n  \"scripts\": {\n    \"storybook\": \"start-storybook <some flags>\",\n    \"build-storybook\": \"build-storybook <some flags>\"\n  }\n}\n```\n\nTo convert this project to 7.0:\n\n```json\n{\n  \"scripts\": {\n    \"storybook\": \"storybook dev <some flags>\",\n    \"build-storybook\": \"storybook build <some flags>\"\n  },\n  \"devDependencies\": {\n    \"storybook\": \"next\"\n  }\n}\n```\n\nThe new CLI commands remove the following flags:\n\n| flag     | migration                                                                                     |\n| -------- | --------------------------------------------------------------------------------------------- |\n| --modern | No migration needed. [All ESM code is modern in SB7](#modern-esm--ie11-support-discontinued). |\n\n#### New Framework API\n\n_Has automigration_\n\nStorybook 7 introduces the concept of `frameworks`, which abstracts configuration for `renderers` (e.g. React, Vue), `builders` (e.g. Webpack, Vite) and defaults to make integrations easier. This requires quite a few changes, depending on what your project is using. **We recommend you to use the automigrations**, but in case the command fails or you'd like to do the changes manually, here's a guide:\n\n> Note:\n> All of the following changes can be done automatically either via `npx storybook@latest upgrade --prerelease` or via the `npx storybook@latest automigrate` command. It's highly recommended to use these commands, which will tell you exactly what to do.\n\n##### Available framework packages\n\nIn 7.0, `frameworks` combine a `renderer` and a `builder`, with the exception of a few packages that do not contain multiple builders, such as `@storybook/angular`, which only has Webpack 5 support.\n\nYou have to pick which framework you want to use from the list below, which will depend on your project configuration. If you're using a framework that has multiple builders, you'll have to pick one. For example, if you're using `@storybook/react`, you'll have to pick between `@storybook/react-vite` and `@storybook/react-webpack5`. If you're using a framework that only has one builder (and therefore hasn't changed), you can just use that.\n\nAdditionally, there are framework packages which are specific to meta-frameworks, like Next.js and SvelteKit. If you pick them, make sure to also see [this section]().\n\nThe current list of frameworks include:\n\n- `@storybook/angular` (did not change)\n- `@storybook/ember` (did not change)\n- `@storybook/html-vite`\n- `@storybook/html-webpack5`\n- `@storybook/preact-vite`\n- `@storybook/preact-webpack5`\n- `@storybook/react-vite`\n- `@storybook/react-webpack5`\n- `@storybook/nextjs`\n- `@storybook/server-webpack5`\n- `@storybook/svelte-vite`\n- `@storybook/sveltekit`\n- `@storybook/vue-vite`\n- `@storybook/vue-webpack5`\n- `@storybook/vue3-vite`\n- `@storybook/vue3-webpack5`\n- `@storybook/web-components-vite`\n- `@storybook/web-components-webpack5`\n\nYou can find more info on the rationale here: [Frameworks RFC](https://chromatic-ui.notion.site/Frameworks-RFC-89f8aafe3f0941ceb4c24683859ed65c).\n\n**After picking your framework, you'll need to install it as a dev dependency.**\n\nBecause the new framework package will include the builder as well, you can remove any of the builder packages you were using before:\n\n```js\n'@storybook/builder-webpack5',\n'@storybook/manager-webpack5',\n'@storybook/builder-webpack4',\n'@storybook/manager-webpack4',\n'@storybook/builder-vite',\n'storybook-builder-vite',\n```\n\n> Note:\n> if your project is still using Webpack 4, you'll have to upgrade to Webpack 5 as [Webpack 4 support was discontinued](#webpack4-support-discontinued)\n\n##### Framework field mandatory\n\nIn 6.4 we introduced a new `main.js` field called [`framework`](#mainjs-framework-field). Starting in 7.0, the `main.js` file has to include a `framework` field and it should be of the package you picked in earlier steps.\n\nHere's an example, in case you picked `@storybook/react-vite`:\n\n```js\n// .storybook/main.js\nexport default {\n  // ... your configuration\n  framework: {\n    name: '@storybook/react-vite',\n    options: {},\n  },\n};\n```\n\n##### frameworkOptions renamed\n\nIn 7.0, the `main.js` fields `reactOptions` and `angularOptions` have been renamed. They are now options on the `framework` field.\n\nFor React, what used to be:\n\n```js\nexport default {\n  reactOptions: { fastRefresh: true },\n  framework: {\n    name: '@storybook/react-webpack5',\n    options: {},\n  },\n};\n```\n\nBecomes:\n\n```js\nexport default {\n  framework: {\n    name: '@storybook/react-webpack5',\n    options: { fastRefresh: true },\n  },\n};\n```\n\nFor Angular, what used to be:\n\n```js\nexport default {\n  angularOptions: { enableIvy: true },\n  framework: {\n    name: '@storybook/angular',\n    options: {},\n  },\n};\n```\n\nBecomes:\n\n```js\nexport default {\n  framework: {\n    name: '@storybook/angular',\n    options: { enableIvy: true },\n  },\n};\n```\n\n##### builderOptions renamed\n\nIn 7.0, the `main.js` fields `core.builder` are now removed, in favor of the new frameworks api. The builder is defined as part of the framework package you pick, e.g. `@storybook/vue3-vite`. If you had options for your builder, they are now options on the `framework.builder` field.\n\nWhat used to be:\n\n```js\nexport default {\n  core: {\n    builder: {\n      name: 'webpack5',\n      options: { lazyCompilation: true }\n    },\n  }\n  framework: {\n    name: '@storybook/react-webpack5',\n    options: {},\n  },\n};\n```\n\nBecomes:\n\n```js\nexport default {\n  framework: {\n    name: '@storybook/react-webpack5',\n    options: {\n      builder: { lazyCompilation: true },\n    },\n  },\n};\n```\n\n> Note:\n> If after making this change, your `main.js` `core` field is empty, just delete it.\n\n#### TypeScript: StorybookConfig type moved\n\nIf you are using TypeScript you should import the `StorybookConfig` type from your framework package.\n\nFor example:\n\n```ts\nimport type { StorybookConfig } from '@storybook/react-vite';\n\nconst config: StorybookConfig = {\n  framework: {\n    name: '@storybook/react-vite',\n    options: {},\n  },\n  // ... your configuration\n};\nexport default config;\n```\n\n#### Titles are statically computed\n\nUp until version 7.0, it was possible to generate the default export of a CSF story by calling a function, or mixing in variables defined in other ES Modules. For instance:\n\n```js\n// Dynamically computed local title\nconst categories = {\n  atoms: 'Atoms',\n  molecules: 'Molecules',\n  // etc.\n}\n\nexport default {\n  title: `${categories.atoms}/MyComponent`\n}\n\n// Title returned by a function\nimport { genDefault } from '../utils/storybook'\n\nexport default genDefault({\n  category: 'Atoms',\n  title: 'MyComponent',\n})\n```\n\nThis is no longer possible in Storybook 7.0, as story titles are parsed at build time. In earlier versions, titles were mostly produced manually. Now that [CSF3 auto-title](#csf3-auto-title-improvements) is available, optimisations were made that constrain how `id` and `title` can be defined manually.\n\nAs a result, titles cannot depend on variables or functions, and cannot be dynamically computed (even with local variables). Stories must have a static `title` property, or a static `component` property used by the [CSF3 auto-title](#csf3-auto-title-improvements) feature to compute a title.\n\nLikewise, the `id` property must be statically defined. The URL defined for a story in the sidebar will be statically computed, so if you dynamically add an `id` through a function call like above, the story URL will not match the one in the sidebar and the story will be unreachable.\n\nTo opt-out of the old behavior you can set the `storyStoreV7` feature flag to `false` in `main.js`. However, a variety of performance optimizations depend on the new behavior, and the old behavior is deprecated and will be removed from Storybook in 8.0.\n\n```js\nmodule.exports = {\n  features: {\n    storyStoreV7: false,\n  },\n};\n```\n\n#### Framework standalone build moved\n\nIn 7.0 the location of the standalone node API has moved to `@storybook/core-server`.\n\nIf you used the React standalone API, for example, you might have written:\n\n```js\nconst buildStandalone = require('@storybook/react/standalone');\nconst options = {};\nbuildStandalone(options).then(() => console.log('done'));\n```\n\nIn 7.0, you would now use:\n\n```js\nconst { build } = require('@storybook/core-server');\nconst options = {};\nbuild(options).then(() => console.log('done'));\n```\n\n#### Change of root html IDs\n\nThe root ID unto which Storybook renders stories is renamed from `root` to `#storybook-root` to avoid conflicts with user's code.\n\n#### Stories glob matches MDX files\n\nIf you used a directory based stories glob, in 6.x it would match `.stories.js` (and other JS extensions) and `.stories.mdx` files. For instance:\n\n```js\n// in main.js\nexport default {\n  stories: ['../path/to/directory']\n};\n\n// or\nexport default {\n  stories: [{ directory: '../path/to/directory' }]\n};\n```\n\nIn 7.0, this pattern will also match `.mdx` files (the new extension for docs files - see docs changes below). If you have `.mdx` files you don't want to appear in your storybook, either move them out of the directory, or add a `files` specifier with the old pattern (`\"**/*.stories.@(mdx|tsx|ts|jsx|js)\"`):\n\n```js\nexport default {\n  stories: [\n    {\n      directory: '../path/to/directory',\n      files: '**/*.stories.@(mdx|tsx|ts|jsx|js)',\n    },\n  ],\n};\n```\n\n#### Add strict mode\n\nStarting in 7.0, Storybook's build tools add [`\"use strict\"`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode) to the compiled JS output.\n\nIf user code in `.storybook/preview.js` or stories relies on \"sloppy\" mode behavior, it will need to be updated. As a workaround, it is sometimes possible to move the sloppy mode code inside a script tag in `.storybook/preview-head.html`.\n\n#### Importing plain markdown files with `transcludeMarkdown` has changed\n\nThe `transcludeMarkdown` option in `addon-docs` have been removed, and the automatic handling of `.md` files in Vite projects have also been disabled.\n\nInstead `.md` files can be imported as plain strings by adding the `?raw` suffix to the import, and then passed to the new `Markdown` block. In an MDX file that would look like this:\n\n```\nimport { Markdown } from '@storybook/blocks';\nimport ReadMe from './README.md?raw';\n\n...\n\n<Markdown>{ReadMe}</Markdown>\n\n```\n\n#### Stories field in .storybook/main.js is mandatory\n\nIn 6.x, the `stories` key field in `.storybook/main.js` was optional. In 7.0, it is mandatory.\nPlease follow up the [Configure your Storybook project](https://storybook.js.org/docs/react/configure/#configure-your-storybook-project) section to configure your Storybook project.\n\n#### Stricter global types\n\nIn 6.x, you could declare and use [`globals`](https://storybook.js.org/docs/react/essentials/toolbars-and-globals) without declaring their corresponding `globalTypes`. We've made this more strict in 7.0, so that the `globalTypes` declaration is required, and undeclared globals will be ignored.\n\n#### Deploying build artifacts\n\nStarting with 7.x, we are using modern [ECMAScript Modules (ESM)](https://nodejs.org/api/esm.html).\n\nThose end up as `.mjs` files in your static Storybook artifact and need to be served as `application/javascript`, indicated by the `Content-Type` HTTP header.\n\nFor a simple HTTP server to view a Storybook build, you can run `npx http-server storybook-static`.\n\nNote that [using the serve package](https://storybook.js.org/docs/react/faq#i-see-a-no-preview-error-with-a-storybook-production-build) will not work.\n\n##### Dropped support for file URLs\n\nIn 6.x it was possible to open a Storybook build from the file system.\n\nESM requires loading over HTTP(S), which is incompatible with the browser's CORS settings for `file://` URLs.\n\nSo you now need to use a web server as described above.\n\n##### Serving with nginx\n\nWith [nginx](https://www.nginx.com/), you need to extend [the MIME type handling](https://github.com/nginx/nginx/blob/master/conf/mime.types) in your configuration:\n\n```\n    include mime.types;\n    types {\n        application/javascript mjs;\n    }\n```\n\nIt would otherwise default to serving the `.mjs` files as `application/octet-stream`.\n\n##### Ignore story files from node_modules\n\nIn 6.x Storybook literally followed the glob patterns specified in your `.storybook/main.js` `stories` field. Storybook 7.0 ignores files from `node_modules` unless your glob pattern includes the string `\"node_modules\"`.\n\nGiven the following `main.js`:\n\n```js\nexport default {\n  stories: ['../**/*.stories.*'],\n};\n```\n\nIf you want to restore the previous behavior to include `node_modules`, you can update it to:\n\n```js\nexport default {\n  stories: ['../**/*.stories.*', '../**/node_modules/**/*.stories.*'],\n};\n```\n\nThe first glob would have node_modules automatically excluded by Storybook, and the second glob would include all stories that are under a nested `node_modules` directory.\n\n### 7.0 Core changes\n\n#### 7.0 feature flags removed\n\nStorybook uses temporary feature flags to opt-in to future breaking changes or opt-in to legacy behaviors. For example:\n\n```js\nmodule.exports = {\n  features: {\n    emotionAlias: false,\n  },\n};\n```\n\nIn 7.0 we've removed the following feature flags:\n\n| flag                | migration instructions                                      |\n| ------------------- | ----------------------------------------------------------- |\n| `emotionAlias`      | This flag is no longer needed and should be deleted.        |\n| `breakingChangesV7` | This flag is no longer needed and should be deleted.        |\n| `previewCsfV3`      | This flag is no longer needed and should be deleted.        |\n| `babelModeV7`       | See [Babel mode v7 exclusively](#babel-mode-v7-exclusively) |\n\n#### Story context is prepared before for supporting fine grained updates\n\nThis change modifies the way Storybook prepares stories to avoid reactive args to get lost for fine-grained updates JS frameworks as `SolidJS` or `Vue`. That's because those frameworks handle args/props as proxies behind the scenes to make reactivity work. So when `argType` mapping was done in `prepareStory` the Proxies were destroyed and args becomes a plain object again, losing the reactivity.\n\nFor avoiding that, this change passes the mapped args instead of raw args at `renderToCanvas` so that the proxies stay intact. Also decorators will benefit from this as well by receiving mapped args instead of raw args.\n\n#### Changed decorator order between preview.js and addons/frameworks\n\nIn Storybook 7.0 we have changed the order of decorators being applied to allow you to access context information added by decorators defined in addons/frameworks from decorators defined in `preview.js`. To revert the order to the previous behavior, you can set the `features.legacyDecoratorFileOrder` flag to `true` in your `main.js` file:\n\n```js\n// main.js\nexport default {\n  features: {\n    legacyDecoratorFileOrder: true,\n  },\n};\n```\n\n#### Dark mode detection\n\nStorybook 7 uses `prefers-color-scheme` to detects your system's dark mode preference if a theme is not set.\n\nEarlier versions used the light theme by default, so if you don't set a theme and your system's settings are in dark mode, this could surprise you.\n\nTo learn more about theming, read our [documentation](https://storybook.js.org/docs/react/configure/theming).\n\n#### `addons.setConfig` should now be imported from `@storybook/manager-api`.\n\nThe previous package, `@storybook/addons`, is now deprecated and will be removed in 8.0.\n\n```diff\n- import { addons } from '@storybook/addons';\n+ import { addons } from '@storybook/manager-api';\n\naddons.setConfig({\n  // ...\n})\n```\n\n### 7.0 core addons changes\n\n#### Removed auto injection of @storybook/addon-actions decorator\n\nThe `withActions` decorator is no longer automatically added to stories. This is because it is really only used in the html renderer, for all other renderers it's redundant.\nIf you are using the html renderer and use the `handles` parameter, you'll need to manually add the `withActions` decorator:\n\n```diff\nimport globalThis from 'global';\n+import { withActions } from '@storybook/addon-actions/decorator';\n\nexport default {\n  component: globalThis.Components.Button,\n  args: {\n    label: 'Click Me!',\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n};\nexport const Basic = {\n  parameters: {\n    handles: [{ click: 'clicked', contextmenu: 'right clicked' }],\n  },\n+  decorators: [withActions],\n};\n```\n\n#### Addon-backgrounds: Removed deprecated grid parameter\n\nStarting in 7.0 the `grid.cellSize` parameter should now be `backgrounds.grid.cellSize`. This was [deprecated in SB 6.1](#deprecated-grid-parameter).\n\n#### Addon-a11y: Removed deprecated withA11y decorator\n\nWe removed the deprecated `withA11y` decorator. This was [deprecated in 6.0](#removed-witha11y-decorator)\n\n#### Addon-interactions: Interactions debugger is now default\n\nThe interactions debugger in the panel is now displayed by default. The feature flag is now removed.\n\n```js\n// .storybook/main.js\n\nconst config = {\n  features: {\n    interactionsDebugger: true, // This should be removed!\n  },\n};\nexport default config;\n```\n\n### 7.0 Vite changes\n\n#### Vite builder uses Vite config automatically\n\nWhen using a [Vite-based framework](#framework-field-mandatory), Storybook will automatically use your `vite.config.(ctm)js` config file starting in 7.0.\nSome settings will be overridden by Storybook so that it can function properly, and the merged settings can be modified using `viteFinal` in `.storybook/main.js` (see the [Storybook Vite configuration docs](https://storybook.js.org/docs/react/builders/vite#configuration)).\nIf you were using `viteFinal` in 6.5 to simply merge in your project's standard Vite config, you can now remove it.\n\nFor Svelte projects this means that the `svelteOptions` property in the `main.js` config should be omitted, as it will be loaded automatically via the project's `vite.config.js`.\n\n#### Vite cache moved to node_modules/.cache/.vite-storybook\n\nPreviously, Storybook's Vite builder placed cache files in node_modules/.vite-storybook. However, it's more common for tools to place cached files into `node_modules/.cache`, and putting them there makes it quick and easy to clear the cache for multiple tools at once. We don't expect this change will cause any problems, but it's something that users of Storybook Vite projects should know about. It can be configured by setting `cacheDir` in `viteFinal` within `.storybook/main.js` [Storybook Vite configuration docs](https://storybook.js.org/docs/react/builders/vite#configuration)).\n\n### 7.0 Webpack changes\n\n#### Webpack4 support discontinued\n\nSB7.0 no longer supports Webpack4.\n\nDepending on your project specifics, it might be possible to run your Storybook using the webpack5 builder without error.\n\nIf you are running into errors, you can upgrade your project to Webpack5 or you can try debugging those errors.\n\nTo upgrade:\n\n- If you're configuring Webpack directly, see the Webpack5 [release announcement](https://webpack.js.org/blog/2020-10-10-webpack-5-release/) and [migration guide](https://webpack.js.org/migrate/5).\n- If you're using Create React App, see the [migration notes](https://github.com/facebook/create-react-app/blob/main/CHANGELOG.md#migrating-from-40x-to-500) to upgrade from V4 (Webpack4) to 5\n\nDuring the 7.0 dev cycle we will be updating this section with useful resources as we run across them.\n\n#### Babel mode v7 exclusively\n\n_Has automigration_\n\nStorybook now uses [Babel mode v7](#babel-mode-v7) exclusively. In 6.x, Storybook provided its own babel settings out of the box. Now, Storybook's uses your project's babel settings (`.babelrc`, `babel.config.js`, etc.) instead.\n\n> Note:\n> If you are using @storybook/react-webpack5 with the @storybook/preset-create-react-app package, you don't need to do anything. The preset already provides the babel configuration you need.\n\nIn the new mode, Storybook expects you to provide a configuration file. Depending on the complexity your project, Storybook will fail to run without a babel configuration. If you want a configuration file that's equivalent to the 6.x default, you can run the following command in your project directory:\n\n```sh\nnpx storybook@latest babelrc\n```\n\nThis command will create a `.babelrc.json` file in your project, containing a few babel plugins which will be installed as dev dependencies.\n\n#### Postcss removed\n\nStorybook 6.x installed postcss by default. In 7.0 built-in support has been removed for Webpack-based frameworks. If you need it, you can add it back using [`@storybook/addon-postcss`](https://github.com/storybookjs/addon-postcss).\n\n#### Removed DLL flags\n\nEarlier versions of Storybook used Webpack DLLs as a performance crutch. In 6.1, we've removed Storybook's built-in DLLs and have deprecated the command-line parameters `--no-dll` and `--ui-dll`. In 7.0 those options are removed.\n\n### 7.0 Framework-specific changes\n\n#### Angular: Removed deprecated `component` and `propsMeta` field\n\nThe deprecated fields `component` and `propsMeta` on the NgStory type have been removed.\n\n#### Angular: Drop support for Angular < 14\n\nStarting in 7.0, we drop support for Angular < 14\n\n#### Angular: Drop support for calling Storybook directly\n\n_Has automigration_\n\nIn Storybook 6.4 we deprecated calling Storybook directly (e.g. `npm run storybook`) for Angular. In Storybook 7.0, we've removed it entirely. Instead, you have to set up the Storybook builder in your `angular.json` and execute `ng run <your-project>:storybook` to start Storybook.\n\nYou can run `npx storybook@next automigrate` to automatically fix your configuration, or visit https://github.com/storybookjs/storybook/tree/next/code/frameworks/angular/README.md#how-do-i-migrate-to-an-angular-storybook-builder for instructions on how to set up Storybook for Angular manually.\n\n#### Angular: Application providers and ModuleWithProviders\n\nIn Storybook 7.0 we use the new bootstrapApplication API to bootstrap a standalone component to the DOM. The component is configured in a way to respect your configured imports, declarations and schemas, which you can define via the `moduleMetadata` decorator imported from `@storybook/angular`.\n\nThis means also, that there is no root ngModule anymore. Previously you were able to add ModuleWithProviders, likely the result of a 'Module.forRoot()'-style call, to your 'imports' array of the moduleMetadata definition. This is now discouraged. Instead, you should use the `applicationConfig` decorator to add your application-wide providers. These providers will be passed to the bootstrapApplication function.\n\nFor example, if you want to configure BrowserAnimationModule in your stories, please extract the necessary providers the following way and provide them via the `applicationConfig` decorator:\n\n```js\nimport { BrowserAnimationsModule } from \"@angular/platform-browser/animations\";\nimport { importProvidersFrom } from \"@angular/core\";\nimport { applicationConfig, Meta, StoryObj } from \"@storybook/angular\";\nimport { ExampleComponent } from \"./example.component\";\n\nconst meta: Meta = {\n  title: \"Example\",\n  component: ExampleComponent,\n  decorators: [\n    // Define application-wide providers with the applicationConfig decorator\n    applicationConfig({\n      providers: [\n        importProvidersFrom(BrowserAnimationsModule),\n        // Extract all providers (and nested ones) from a ModuleWithProviders\n        importProvidersFrom(SomeOtherModule.forRoot()),\n      ],\n    }),\n  ],\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof ExampleComponent>;\n\nexport const Default: Story = {\n  render: () => ({\n    // Define application-wide providers directly in the render function\n    applicationConfig: {\n      providers: [importProvidersFrom(BrowserAnimationsModule)],\n    },\n  }),\n};\n```\n\nYou can also use the `provide-style` decorator to provide an application-wide service:\n\n```js\nimport { moduleMetadata } from '@storybook/angular';\nimport { provideAnimations } from '@angular/platform-browser/animations';\n\nexport default {\n  title: 'Example',\n  decorators: [\n    applicationConfig({\n      providers: [provideAnimations()],\n    }),\n  ],\n};\n```\n\nPlease visit https://angular.io/guide/standalone-components#configuring-dependency-injection for more information.\n\n#### Angular: Removed legacy renderer\n\nThe `parameters.angularLegacyRendering` option is removed. You cannot use the old legacy renderer anymore.\n\n#### Angular: Initializer functions\n\nInitializer functions using the `APP_INITIALIZER` dependency injection token only run when the component renders. To ensure an initializer function is always executed, you can adjust your `.storybook/preview.ts` and invoke it directly.\n\n```js\nmyCustomInitializer();\nexport default preview;\n```\n\n#### Next.js: use the `@storybook/nextjs` framework\n\nIn Storybook 7.0 we introduced a convenient package that provides an out of the box experience for Next.js projects: `@storybook/nextjs`. Please see the [following resource](./code/frameworks/nextjs/README.md#getting-started) to get started with it.\n\n#### SvelteKit: needs the `@storybook/sveltekit` framework\n\nIn Storybook 7.0 we introduced a convenient package that provides an out of the box experience for SvelteKit projects: `@storybook/sveltekit`. Please see the [following resource](https://storybook.js.org/docs/get-started/frameworks/sveltekit?renderer=svelte) to get started with it.\n\nFor existing users, SvelteKit projects need to use the `@storybook/sveltekit` framework in the `main.js` file. Previously it was enough to just setup Storybook with Svelte+Vite, but that is no longer the case.\n\n```js\n// .storybook/main.js\nexport default {\n  framework: '@storybook/sveltekit',\n};\n```\n\nAlso see the note in [Vite builder uses Vite config automatically](#vite-builder-uses-vite-config-automatically) about removing `svelteOptions`.\n\n#### Vue3: replaced app export with setup\n\nIn 6.x `@storybook/vue3` exported a Vue application instance called `app`. In 7.0, this has been replaced by a `setup` function that can be used to initialize the application in your `.storybook/preview.js`:\n\nBefore:\n\n```js\nimport { app } from '@storybook/vue3';\nimport Button from './Button.vue';\n\napp.component('GlobalButton', Button);\n```\n\nAfter:\n\n```js\nimport { setup } from '@storybook/vue3';\nimport Button from './Button.vue';\n\nsetup((app) => {\n  app.component('GlobalButton', Button);\n});\n```\n\n#### Web-components: dropped lit-html v1 support\n\nIn v6.x `@storybook/web-components` had a peer dependency on `lit-html` v1 or v2. In 7.0 we've dropped support for `lit-html` v1 and now uses `lit` v2 instead. Please upgrade your project's `lit-html` dependency if you're still on 1.x.\n\n#### Create React App: dropped CRA4 support\n\nSince v7 [drops webpack4 support](#webpack4-support-discontinued), it no longer supports Create React App < 5.0. If you're using an earlier version of CRA, please upgrade or stay on Storybook 6.x.\n\n#### HTML: No longer auto-dedents source code\n\nThe `@storybook/html` renderer doesn't dedent the source code when displayed in the \"Show Code\" source viewer any more.\n\nYou can get the same result by setting [the parameter `parameters.docs.source.format = \"dedent\"`](https://storybook.js.org/docs/7.0/html/api/doc-block-source#format) either on a story level or globally in `preview.js`.\n\n### 7.0 Addon authors changes\n\n#### New Addons API\n\nStorybook 7 adds 2 new packages for addon authors to use: `@storybook/preview-api` and `@storybook/manager-api`.\nThese 2 packages replace `@storybook/addons`.\n\nWhen adding addons to storybook, you can (for example) add panels:\n\n```js\nimport { addons } from '@storybook/manager-api';\n\naddons.addPanel('my-panel', {\n  title: 'My Panel',\n  render: ({ active, key }) => <div>My Panel</div>,\n});\n```\n\nNote that this before would import `addons` from `@storybook/addons`, but now it imports `{ addons }` from `@storybook/manager-api`.\nThe `addons` export is now a named export only, there's no default export anymore, so make sure to update this usage.\n\nThe package `@storybook/addons` is still available, but it's only for backwards compatibility. It's not recommended to use it anymore.\n\nIt's also been used by addon creators to gain access to a few APIs like `makeDecorator`.\nThese APIs are now available in `@storybook/preview-api`.\n\nStorybook users have had access to a few storybook-lifecycle hooks such as `useChannel`, `useParameter`, `useStorybookState`;\nwhen these hooks are used in panels, they should be imported from `@storybook/manager-api`.\nWhen these hooks are used in decorators/stories, they should be imported from `@storybook/preview-api`.\n\nStorybook 7 includes `@storybook/addons` shim package that provides the old API and calls the new API under the hood.\nThis backwards compatibility will be removed in a future release of storybook.\n\nHere's an example of using the new API:\nThe `@storybook/preview-api` is used here, because the `useEffect` hook is used in a decorator.\n\n```js\nimport { useEffect, makeDecorator } from '@storybook/preview-api';\n\nexport const withMyAddon = makeDecorator({\n  name: 'withMyAddon',\n  parameterName: 'myAddon',\n  wrapper: (getStory) => {\n    useEffect(() => {\n      // do something with the options\n    }, []);\n    return getStory(context);\n  },\n});\n```\n\n##### Specific instructions for addon creators\n\nIf you're an addon creator, you'll have to update your addon to use the new APIs.\n\nThat means you'll have to release a breaking release of your addon to make it compatible with Storybook 7.\nIt should no longer depend on `@storybook/addons`, but instead on `@storybook/preview-api` and/or `@storybook/manager-api`.\n\nYou might also depend (and use) these packages in your addon's decorators: `@storybook/store`, `@storybook/preview-web`, `@storybook/core-client`, `@storybook/client-api`; these have all been consolidated into `@storybook/preview-api`.\nSo if you use any of these packages, please import what you need from `@storybook/preview-api` instead.\n\nStorybook 7 will prepare manager-code for the browser using ESbuild (before it was using a combination of webpack + babel).\nThis is a very important change, though it will not affect most addons.\nIt means that when creating custom addons, particularly custom addons within the repo in which they are consumed,\nyou will need to be aware that this code is not passed though babel, and thus will not use your babel config.\nThis can result in errors if you are using experimental JS features in your addon code, not supported yet by ESbuild,\nor using babel dependent features such as Component selectors in Emotion.\n\nESbuild also places some constraints on things you can import into your addon's manager code: only woff2 files are supported, and not all image file types are supported.\nHere's the [list](https://github.com/storybookjs/storybook/blob/next/code/builders/builder-manager/src/index.ts#L53-L70) of supported file types.\n\nThis is not configurable.\n\nIf this is a problem for your addon, you need to pre-compile your addon's manager code to ensure it works.\n\nIf you addon also introduces preview code (such a decorators) it will be passed though whatever builder + config the user has configured for their project; this hasn't changed.\n\nIn both the preview and manager code it's good to remember [Storybook now targets modern browser only](#modern-browser-support).\n\nThe package `@storybook/components` contain a lot of components useful for building addons.\nSome of these addons have been moved to a new package `@storybook/blocks`.\nThese components were moved: `ColorControl`, `ColorPalette`, `ArgsTable`, `ArgRow`, `TabbedArgsTable`, `SectionRow`, `Source`, `Code`.\n\n##### Specific instructions for addon users\n\nAll of storybook's core addons have been updated and are ready to use with Storybook 7.\n\nWe're working with the community to update the most popular addons.\nBut if you're using an addon that hasn't been updated yet, it might not work.\n\nIt's possible for example for older addons to use APIs that are no longer available in Storybook 7.\nYour addon might not show upside of the storybook (manager) UI, or storybook might fail to start entirely.\n\nWhen this happens to you please open an issue on the addon's repo, and ask the addon author to update their addon to be compatible with Storybook 7.\nIt's also useful for the storybook team to know which addons are not yet compatible, so please open an issue on the storybook repo as well; particularly if the addon is popular and causes a critical failure.\n\nHere's a list of popular addons that are known not to be compatible with Storybook 7 yet:\n\n- [ ] [storybook-addon-jsx](https://github.com/storybookjs/addon-jsx)\n- [ ] [storybook-addon-dark-mode](https://github.com/hipstersmoothie/storybook-dark-mode)\n\nThough storybook should de-duplicate storybook packages, storybook CLI's `upgrade` command will warn you when you have multiple storybook-dependencies, because it is a possibility that this causes addons/storybook to not work, so when running into issues, please run this:\n\n```\nnpx sb upgrade\n```\n\n#### register.js removed\n\nIn SB 6.x and earlier, addons exported a `register.js` entry point by convention, and users would import this in `.storybook/manager.js`. This was [deprecated in SB 6.5](#deprecated-registerjs)\n\nIn 7.0, most of Storybook's addons now export a `manager.js` entry point, which is automatically registered in Storybook's manager when the addon is listed in `.storybook/main.js`'s `addons` field.\n\nIf your `.manager.js` config references `register.js` of any of the following addons, you can remove it: `a11y`, `actions`, `backgrounds`, `controls`, `interactions`, `jest`, `links`, `measure`, `outline`, `toolbars`, `viewport`.\n\n#### No more default export from `@storybook/addons`\n\nThe default export from `@storybook/addons` has been removed. Please use the named exports instead:\n\n```js\nimport { addons } from '@storybook/addons';\n```\n\nThe named export has been available since 6.0 or earlier, so your updated code will be backwards-compatible with older versions of Storybook.\n\n#### No more configuration for manager\n\nThe Storybook manager is no longer built with Webpack. Now it's built with esbuild.\nTherefore, it's no longer possible to configure the manager. Esbuild comes preconfigured to handle importing CSS, and images.\n\nIf you're currently loading files other than CSS or images into the manager, you'll need to make changes so the files get converted to JS before publishing your addon.\n\nThis means the preset value `managerWebpack` is no longer respected, and should be removed from presets and `main.js` files.\n\nAddons that run in the manager can depend on `react` and `@storybook/*` packages directly. They do not need to be peerDependencies.\nBut very importantly, the build system ensures there will only be 1 version of these packages at runtime. The version will come from the `@storybook/ui` package, and not from the addon.\nFor this reason it's recommended to have these dependencies as `devDependencies` in your addon's `package.json`.\n\nThe full list of packages that Storybook's manager bundler makes available for addons is here: https://github.com/storybookjs/storybook/blob/next/code/lib/ui/src/globals/types.ts\n\nAddons in the manager will no longer be bundled together anymore, which means that if 1 fails, it doesn't break the whole manager.\nEach addon is imported into the manager as an ESM module that's bundled separately.\n\n#### Icons API changed\n\nFor addon authors who use the `Icons` component, its API has been updated in Storybook 7.\n\n```diff\nexport interface IconsProps extends ComponentProps<typeof Svg> {\n-  icon?: IconKey;\n-  symbol?: IconKey;\n+  icon: IconType;\n+  useSymbol?: boolean;\n}\n```\n\nFull change here: https://github.com/storybookjs/storybook/pull/18809\n\n#### Removed global client APIs\n\nThe `addParameters` and `addDecorator` APIs to add global decorators and parameters, exported by the various frameworks (e.g. `@storybook/react`) and `@storybook/client` were deprecated in 6.0 and have been removed in 7.0.\n\nInstead, use `export const parameters = {};` and `export const decorators = [];` in your `.storybook/preview.js`. Addon authors similarly should use such an export in a preview entry file (see [Preview entries](https://github.com/storybookjs/storybook/blob/next/docs/addons/writing-presets.md#preview-entries)).\n\n#### framework parameter renamed to renderer\n\nAll SB6.x frameworks injected a parameter called `framework` indicating to addons which framework is running.\nFor example, the framework value of `@storybook/react` would be `react`, `@storybook/vue` would be `vue`, etc.\nNow those packages are called renderers in SB7, so the renderer information is now available in the `renderer`\nparameter.\n\n### 7.0 Docs changes\n\nThe information hierarchy of docs in Storybook has changed in 7.0. The main difference is that each docs is listed in the sidebar as a separate entry underneath the component, rather than attached to individual stories. You can also opt-in to a Autodocs entry rather than having one for every component (previously stories).\n\nWe've also modernized the API for all the doc blocks (the MDX components you use to write custom docs pages), which we'll describe below.\n\n#### Autodocs changes\n\nIn 7.0, rather than rendering each story in \"docs view mode\", Autodocs (formerly known as \"Docs Page\") operates by adding additional sidebar entries for each component. By default it uses the same template as was used in 6.x, and the entries are entitled `Docs`.\n\nYou can configure Autodocs in `main.js`:\n\n```js\nmodule.exports = {\n  docs: {\n    autodocs: true, // see below for alternatives\n    defaultName: 'Docs', // set to change the name of generated docs entries\n  },\n};\n```\n\nIf you are migrating from 6.x your `docs.autodocs` option will have been set to `true`, which has the effect of enabling docs page for _every_ CSF file. However, as of 7.0, the new default is `'tag'`, which requires opting into Autodocs per-CSF file, with the `autodocs` **tag** on your component export:\n\n```ts\nexport default {\n  component: MyComponent\n  // Tags are a new feature coming in 7.1, that we are using to drive this behaviour.\n  tags: ['autodocs']\n}\n```\n\nYou can also set `autodocs: false` to opt-out of Autodocs entirely. Further configuration of Autodocs is described below.\n\n**Parameter changes**\n\nWe've renamed many of the parameters that control docs rendering for consistency with the blocks (see below). The old parameters are now deprecated and will be removed in 8.0. Here is a full list of changes:\n\n- `docs.inlineStories` has been renamed `docs.story.inline`\n- `docs.iframeHeight` has been renamed `docs.story.iframeHeight`\n- `notes` and `info` are no longer supported, instead use `docs.description.story | component`\n\n#### MDX docs files\n\nPreviously `.stories.mdx` files were used to both define and document stories. In 7.0, we have deprecated defining stories in MDX files, and consequently have changed the suffix to simply `.mdx`. Our default `stories` glob in `main.js` will now match such files -- if you want to write MDX files that do not appear in Storybook, you may need to adjust the glob accordingly.\n\nIf you were using `.stories.mdx` files to write stories, we encourage you to move the stories to a CSF file, and _attach_ an `.mdx` file to that CSF file to document them. You can use the `Meta` block to attach a MDX file to a CSF file, and the `Story` block to render the stories:\n\n```mdx\nimport { Meta, Story } from '@storybook/blocks';\nimport * as ComponentStories from './some-component.stories';\n\n<Meta of={ComponentStories} />\n\n<Story of={ComponentStories.Primary} />\n```\n\n(Note the `of` prop is only supported if you change your MDX files to plain `.mdx`, it's not supported in `.stories.mdx` files)\n\nYou can create as many docs entries as you like for a given component. By default the docs entry will be named the same as the `.mdx` file (e.g. `Introduction.mdx` becomes `Introduction`). If the docs file is named the same as the component (e.g. `Button.mdx`, it will use the default autodocs name (`\"Docs\"`) and override autodocs).\n\nBy default docs entries are listed first for the component. You can sort them using story sorting.\n\n#### Unattached docs files\n\nIn Storybook 6.x, to create a unattached docs MDX file (that is, one not attached to story or a CSF file), you'd have to create a `.stories.mdx` file, and describe its location with the `Meta` doc block:\n\n```mdx\nimport { Meta } from '@storybook/addon-docs';\n\n<Meta title=\"Introduction\" />\n```\n\nIn 7.0, things are a little simpler -- you should call the file `.mdx` (drop the `.stories`). This will mean behind the scenes there is no story attached to this entry. You may also drop the `title` and use autotitle (and leave the `Meta` component out entirely, potentially).\n\n#### Doc Blocks\n\nAdditionally to changing the docs information architecture, we've updated the API of the doc blocks themselves to be more consistent and future proof.\n\n**General changes**\n\n- Each block now uses `of={}` as a primary API -- where the argument to the `of` prop is a CSF or story _export_. The `of` prop is only supported in plain `.mdx` files and not `.stories.mdx` files.\n\n- When you've attached to a CSF file (with the `Meta` block, or in Autodocs), you can drop the `of` and the block will reference the first story or the CSF file as a whole.\n\n- Most other props controlling rendering of blocks now correspond precisely to the parameters for that block [defined for autodocs above](#autodocs-changes).\n\n##### Meta block\n\nThe primary change of the `Meta` block is the ability to attach to CSF files with `<Meta of={}>` as described above.\n\n##### Description block, `parameters.notes` and `parameters.info`\n\nIn 6.5 the Description doc block accepted a range of different props, `markdown`, `type` and `children` as a way to customize the content.\nThe props have been simplified and the block now only accepts an `of` prop, which can be a reference to either a CSF file, a default export (meta) or a story export, depending on which description you want to be shown. See TDB DOCS LINK for a deeper explanation of the new prop.\n\n`parameters.notes` and `parameters.info` have been deprecated as a way to specify descriptions. Instead use JSDoc comments above the default export or story export, or use `parameters.docs.description.story | component` directly. See TDB DOCS LINK for a deeper explanation on how to write descriptions.\n\nIf you were previously using the `Description` block to render plain markdown in your docs, that behavior can now be achieved with the new `Markdown` block instead like this:\n\n```\nimport { Markdown } from '@storybook/blocks';\nimport ReadMe from './README.md?raw';\n\n...\n\n<Markdown>{ReadMe}</Markdown>\n\n```\n\nNotice the `?raw` suffix in the markdown import is needed for this to work.\n\n##### Story block\n\nTo reference a story in a MDX file, you should reference it with `of`:\n\n```mdx\nimport { Meta, Story } from '@storybook/blocks';\nimport * as ComponentStories from './some-component.stories';\n\n<Meta of={ComponentStories} />\n\n<Story of={ComponentStories.standard} />\n```\n\nYou can also reference a story from a different component:\n\n```mdx\nimport { Meta, Story } from '@storybook/blocks';\nimport * as SecondComponentStories from './second-component.stories';\nimport * as ComponentStories from './some-component.stories';\n\n<Meta of={ComponentStories} />\n\n<Story of={SecondComponentStories.standard} meta={SecondComponentStories} />\n```\n\nReferencing stories by `id=\"xyz--abc\"` is deprecated and should be replaced with `of={}` as above.\n\n##### Source block\n\nThe source block now references a single story, the component, or a CSF file itself via the `of={}` parameter.\n\nReferencing stories by `id=\"xyz--abc\"` is deprecated and should be replaced with `of={}` as above. Referencing multiple stories via `ids={[\"xyz--abc\"]}` is now deprecated and should be avoided (instead use two source blocks).\n\nThe parameter to transform the source has been consolidated from the multiple parameters of `parameters.docs.transformSource`, `parameters.docs.source.transformSource`, and `parameters.jsx.transformSource` to the single `parameters.docs.source.transform`. The behavior is otherwise unchanged.\n\n##### Canvas block\n\nThe Canvas block follows the same changes as [the Story block described above](#story-block).\n\nPreviously the Canvas block accepted children (Story blocks) as a way to reference stories. That has now been replaced with the `of={}` prop that accepts a reference to _a story_.\nThat also means the Canvas block no longer supports containing multiple stories or elements, and thus the props related to that - `isColumn` and `columns` - have also been deprecated.\n\n- To pass props to the inner Story block use the `story={{ }}` prop\n- Similarly, to pass props to the inner Source block use the `source={{ }}` prop.\n- The `mdxSource` prop has been deprecated in favor of using `source={{ code: '...' }}`\n- The `withSource` prop has been renamed to `sourceState`\n\nHere's a full example of the new API:\n\n```mdx\nimport { Meta, Canvas } from '@storybook/blocks';\nimport * as ComponentStories from './some-component.stories';\n\n<Meta of={ComponentStories} />\n\n<Canvas\n  of={ComponentStories.standard}\n  story={{\n    inline: false,\n    height: '200px'\n  }}\n  source={{\n    language: 'html',\n    code: 'custom code...'\n  }}\n  withToolbar={true}\n  additionalActions={[...]}\n  layout=\"fullscreen\"\n  className=\"custom-class\"\n/>\n```\n\n##### ArgsTable block\n\nThe `ArgsTable` block is now deprecated, and two new blocks: `ArgTypes` and `Controls` should be preferred.\n\n- `<ArgTypes of={storyExports OR metaExports OR component} />` will render a readonly table of args/props descriptions for a story, CSF file or component. If `of` omitted and the MDX file is attached it will render the arg types defined at the CSF file level.\n\n- `<Controls of={storyExports} />` will render the controls for a story (or the primary story if `of` is omitted and the MDX file is attached).\n\nThe following props are not supported in the new blocks:\n\n- `components` - to render more than one component in a single table\n- `showComponent` to show the component's props as well as the story's args\n- the `subcomponents` annotation to show more components on the table.\n- `of=\"^\"` to reference the meta (just omit `of` in that case, for `ArgTypes`).\n- `story=\"^\"` to reference the primary story (just omit `of` in that case, for `Controls`).\n- `story=\".\"` to reference the current story (this no longer makes sense in Docs 2).\n- `story=\"name\"` to reference a story (use `of={}`).\n\n#### Configuring Autodocs\n\nAs in 6.x, you can override the docs container to configure docs further. This is the container that each docs entry is rendered inside:\n\n```js\n// in preview.js\n\nexport const parameters = {\n  docs: {\n    container: // your container\n  }\n}\n```\n\nNote that the container must be implemented as a _React component_.\n\nYou likely want to use the `DocsContainer` component exported by `@storybook/blocks` and consider the following examples:\n\n**Overriding theme**:\n\nTo override the theme, you can continue to use the `docs.theme` parameter.\n\n**Overriding MDX components**\n\nIf you want to override the MDX components supplied to your docs page, use the `MDXProvider` from `@mdx-js/react`:\n\n```js\nimport { DocsContainer } from '@storybook/blocks';\nimport { MDXProvider } from '@mdx-js/react';\nimport * as DesignSystem from 'your-design-system';\n\nexport const MyDocsContainer = (props) => (\n  <MDXProvider\n    components={{\n      h1: DesignSystem.H1,\n      h2: DesignSystem.H2,\n    }}\n  >\n    <DocsContainer {...props} />\n  </MDXProvider>\n);\n```\n\n**_NOTE_**: due to breaking changes in MDX2, such override will _only_ apply to elements you create via the MDX syntax, not pure HTML -- ie. `## content` not `<h2>content</h2>`.\n\n#### MDX2 upgrade\n\nStorybook 7 Docs uses MDXv2 instead of MDXv1. This means an improved syntax, support for inline JS expression, and improved performance among [other benefits](https://mdxjs.com/blog/v2/).\n\nIf you use `.stories.mdx` files in your project, you'll probably need to edit them since MDX2 contains [breaking changes](https://mdxjs.com/migrating/v2/#update-mdx-files). In general, MDX2 is stricter and more structured than MDX1.\n\nWe've provided an automigration, `mdx1to2` that makes a few of these changes automatically. For example, `mdx1to2` automatically converts MDX1-style HTML comments into MDX2-style JSX comments to save you time.\n\nUnfortunately, the set of changes from MDX1 to MDX2 is vast, and many changes are subtle, so the bulk of the migration will be manual. You can use the [MDX Playground](https://mdxjs.com/playground/) to try out snippets interactively.\n\n#### Legacy MDX1 support\n\nIf you get stuck with the [MDX2 upgrade](#mdx2-upgrade), we also provide opt-in legacy MDX1 support. This is intended as a temporary solution while you upgrade your Storybook; MDX1 will be discontinued in Storybook 8.0. The MDX1 library is no longer maintained and installing it results in `npm audit` security warnings.\n\nTo process your `.stories.mdx` files with MDX1, first install the `@storybook/mdx1-csf` package in your project:\n\n```\nyarn add -D @storybook/mdx1-csf@latest\n```\n\nThen enable the `legacyMdx1` feature flag in your `.storybook/main.js` file:\n\n```js\nexport default {\n  features: {\n    legacyMdx1: true,\n  },\n};\n```\n\nNOTE: This only affects `.(stories|story).mdx` files. Notably, if you want to use Storybook 7's \"pure\" `.mdx` format, you'll need to use MDX2 for that.\n\n#### Default docs styles will leak into non-story user components\n\nStorybook's default styles in docs are now globally applied to any element instead of using classes. This means that any component that you add directly in a docs file will also get the default styles.\n\nTo mitigate this you need to wrap any content you don't want styled with the `Unstyled` block like this:\n\n```mdx\nimport { Unstyled } from '@storybook/blocks';\nimport { MyComponent } from './MyComponent';\n\n# This is a header\n\n<Unstyled>\n  <MyComponent />\n</Unstyled>\n```\n\nComponents that are part of your stories or in a canvas will not need this mitigation, as the `Story` and `Canvas` blocks already have this built-in.\n\n#### Explicit `<code>` elements are no longer syntax highlighted\n\nDue to how MDX2 works differently from MDX1, manually defined `<code>` elements are no longer transformed to the `Code` component, so it will not be syntax highlighted. This is not the case for markdown \\`\\`\\` code-fences, that will still end up as `Code` with syntax highlighting.\n\nLuckily [MDX2 supports markdown (like code-fences) inside elements better now](https://mdxjs.com/blog/v2/#improvements-to-the-mdx-format), so most cases where you needed a `<code>` element before, you can use code-fences instead:\n\n<!-- prettier-ignore-start -->\n````md\n<code>This will now be an unstyled line of code</code>\n\n```js\nconst a = 'This is still a styled code block.';\n```\n\n<div style={{ background: 'red', padding: '10px' }}>\n  ```js\n  const a = 'MDX2 supports markdown in elements better now, so this is possible.';\n  ```\n</div>\n````\n<!-- prettier-ignore-end -->\n\n#### Dropped source loader / storiesOf static snippets\n\nIn SB 6.x, Storybook Docs used a Webpack loader called `source-loader` to help display static code snippets. This was configurable using the `options.sourceLoaderOptions` field.\n\nIn SB 7.0, we've moved to a faster, simpler alternative called `csf-plugin` that **only supports CSF**. It is configurable using the `options.csfPluginOptions` field.\n\nIf you're using `storiesOf` and want to restore the previous behavior, you can add `source-loader` by hand to your Webpack config using the following snippet in `main.js`:\n\n```js\nmodule.exports = {\n  webpackFinal: (config) => {\n    config.module.rules.push({\n      test: /\\.stories\\.[tj]sx?$/,\n      use: [\n        {\n          loader: require.resolve('@storybook/source-loader'),\n          options: {} /* your sourceLoaderOptions here */,\n        },\n      ],\n      enforce: 'pre',\n    });\n    return config;\n  },\n};\n```\n\n#### Removed docs.getContainer and getPage parameters\n\nIt is no longer possible to set `parameters.docs.getContainer()` and `getPage()`. Instead use `parameters.docs.container` or `parameters.docs.page` directly.\n\n#### Addon-docs: Removed deprecated blocks.js entry\n\nRemoved `@storybook/addon-docs/blocks` entry. Import directly from `@storybook/blocks` instead. This was [deprecated in SB 6.3](#deprecated-scoped-blocks-imports).\n\n#### Dropped addon-docs manual babel configuration\n\nAddon-docs previously accepted `configureJsx` and `mdxBabelOptions` options, which allowed full customization of the babel options used to process markdown and mdx files. This has been simplified in 7.0, with a new option, `jsxOptions`, which can be used to customize the behavior of `@babel/preset-react`.\n\n#### Dropped addon-docs manual configuration\n\nStorybook Docs 5.x shipped with instructions for how to manually configure Webpack and Storybook without the use of Storybook's \"presets\" feature. Over time, these docs went out of sync. Now in Storybook 7 we have removed support for manual configuration entirely.\n\n#### Autoplay in docs\n\nRunning play functions in docs is generally tricky, as they can steal focus and cause the window to scroll. Consequently, we've disabled play functions in docs by default.\n\nIf your story depends on a play function to render correctly, _and_ you are confident the function autoplaying won't mess up your docs, you can set `parameters.docs.autoplay = true` to have it auto play.\n\n#### Removed STORYBOOK_REACT_CLASSES global\n\nThis was a legacy global variable from the early days of react docgen. If you were using this variable, you can instead use docgen information which is added directly to components using `.__docgenInfo`.\n\n### 7.0 Deprecations and default changes\n\n#### storyStoreV7 enabled by default\n\nSB6.4 introduced [Story Store V7](#story-store-v7), an optimization which allows code splitting for faster build and load times. This was an experimental, opt-in change and you can read more about it in [the migration notes below](#story-store-v7). TLDR: you can't use the legacy `storiesOf` API or dynamic titles in CSF.\n\nNow in 7.0, Story Store V7 is the default. You can opt-out of it by setting the feature flag in `.storybook/main.js`:\n\n```js\nmodule.exports = {\n  features: {\n    storyStoreV7: false,\n  },\n};\n```\n\nDuring the 7.0 dev cycle we will be preparing recommendations and utilities to make it easier for `storiesOf` users to upgrade.\n\n#### `Story` type deprecated\n\n_Has codemod_\n\nIn 6.x you were able to do this:\n\n```ts\nimport type { Story } from '@storybook/react';\n\nexport const MyStory: Story = () => <div />;\n```\n\nHowever with the introduction of CSF3, the `Story` type has been deprecated in favor of two other types: `StoryFn` for CSF2 and `StoryObj` for CSF3.\n\n```ts\nimport type { StoryFn, StoryObj } from '@storybook/react';\n\nexport const MyCsf2Story: StoryFn = () => <div />;\nexport const MyCsf3Story: StoryObj = {\n  render: () => <div />,\n};\n```\n\nThis change is part of our move to CSF3, which uses objects instead of functions to represent stories.\nYou can read more about the CSF3 format here: https://storybook.js.org/blog/component-story-format-3-0/\n\nWe have set up a codemod that attempts to automatically migrate your code for you (update the glob to suit your needs):\n\n```\nnpx storybook@next migrate upgrade-deprecated-types --glob=\"**/*.stories.tsx\"\n```\n\n#### `ComponentStory`, `ComponentStoryObj`, `ComponentStoryFn` and `ComponentMeta` types are deprecated\n\n_Has codemod_\n\nThe type of `StoryObj` and `StoryFn` have been changed in 7.0 so that both the \"component\" as \"the props of the component\" will be accepted as the generic parameter. You can now replace the types:\n\n```\nComponentStory -> StoryFn (CSF2) or StoryObj (CSF3)\nComponentStoryObj -> StoryObj\nComponentStoryFn -> StoryFn\nComponentMeta -> Meta\n```\n\nHere are a few examples:\n\n```ts\nimport type { StoryFn, StoryObj } from '@storybook/react';\nimport { Button, ButtonProps } from './Button';\n\n// This works in 7.0, making the ComponentX types redundant.\nconst meta: Meta<typeof Button> = { component: Button };\n\nexport const CSF3Story: StoryObj<typeof Button> = { args: { label: 'Label' } };\n\nexport const CSF2Story: StoryFn<typeof Button> = (args) => <Button {...args} />;\nCSF2Story.args = { label: 'Label' };\n\n// Passing props directly still works as well.\nconst meta: Meta<ButtonProps> = { component: Button };\n\nexport const CSF3Story: StoryObj<ButtonProps> = { args: { label: 'Label' } };\n\nexport const CSF2Story: StoryFn<ButtonProps> = (args) => <Button {...args} />;\nCSF2Story.args = { label: 'Label' };\n```\n\nWe have set up a codemod that attempts to automatically migrate your code for you (update the glob to suit your needs):\n\n```\nnpx storybook@next migrate upgrade-deprecated-types --glob=\"**/*.stories.tsx\"\n```\n\n#### Renamed `renderToDOM` to `renderToCanvas`\n\nThe \"rendering\" function that renderers (ex-frameworks) must export (`renderToDOM`) has been renamed to `renderToCanvas` to acknowledge that some consumers of frameworks/the preview do not work with DOM elements.\n\n#### Renamed `XFramework` to `XRenderer`\n\nIn 6.x you could import XFramework types:\n\n```ts\nimport type { ReactFramework } from '@storybook/react';\nimport type { SvelteFramework } from '@storybook/svelte';\nimport type { VueFramework } from '@storybook/vue';\n\n// etc.\n```\n\nThose are deprecated in 7.0 as they are renamed to:\n\n```ts\nimport type { ReactRenderer } from '@storybook/react';\nimport type { SvelteRenderer } from '@storybook/svelte';\nimport type { VueRenderer } from '@storybook/vue';\n\n// etc.\n```\n\n#### Renamed `DecoratorFn` to `Decorator`\n\nIn 6.x you could import the type `DecoratorFn`:\n\n```ts\nimport type { DecoratorFn } from '@storybook/react';\n```\n\nThis type is deprecated in 7.0, instead you can use the type `Decorator`, which is now available for all renderers:\n\n```ts\nimport type { Decorator } from '@storybook/react';\n// or\nimport type { Decorator } from '@storybook/vue';\n// or\nimport type { Decorator } from '@storybook/svelte';\n// etc.\n```\n\nThe type `Decorator` accepts a generic parameter `TArgs`. This can be used like this:\n\n```tsx\nimport type { Decorator } from '@storybook/react';\nimport { LocaleProvider } from './locale';\n\nconst withLocale: Decorator<{ locale: 'en' | 'es' }> = (Story, { args }) => (\n  <LocaleProvider lang={args.locale}>\n    <Story />\n  </LocaleProvider>\n);\n```\n\nIf you want to use `Decorator` in a backwards compatible way to `DecoratorFn`, you can use:\n\n```tsx\nimport type { Args, Decorator } from '@storybook/react';\n\n// Decorator<Args> behaves the same as DecoratorFn (without generic)\nconst withLocale: Decorator<Args> = (Story, { args }) => // args has type { [name: string]: any }\n```\n\n#### CLI option `--use-npm` deprecated\n\nWith increased support for more package managers (pnpm), we have introduced the `--package-manager` CLI option. Please use `--package-manager=npm` to force NPM to be used to install dependencies when running Storybook CLI commands. Other valid options are `pnpm`, `yarn1`, and `yarn2` (`yarn2` is for versions 2 and higher).\n\n#### 'config' preset entry replaced with 'previewAnnotations'\n\nThe preset field `'config'` has been replaced with `'previewAnnotations'`. `'config'` is now deprecated and will be removed in Storybook 8.0.\n\nAdditionally, the internal field `'previewEntries'` has been removed. If you need a preview entry, just use a `'previewAnnotations'` file and don't export anything.\n\n## From version 6.4.x to 6.5.0\n\n### Vue 3 upgrade\n\nStorybook 6.5 supports Vue 3 out of the box when you install it fresh. However, if you're upgrading your project from a previous version, you'll need to [follow the steps for opting-in to webpack 5](#webpack-5).\n\n### React18 new root API\n\nReact 18 introduces a [new root API](https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html#updates-to-client-rendering-apis). Starting in 6.5, Storybook for React will auto-detect your react version and use the new root API automatically if you're on React18.\n\nIf you wish to opt out of the new root API, set the `reactOptions.legacyRootApi` flag in your `.storybook/main.js` config:\n\n```js\nmodule.exports = {\n  reactOptions: { legacyRootApi: true },\n};\n```\n\n### Renamed isToolshown to showToolbar\n\nStorybook's [manager API](docs/addons/addons-api.md) has deprecated the `isToolshown` option (to show/hide the toolbar) and renamed it to `showToolbar` for consistency with other similar UI options.\n\nExample:\n\n```js\n// .storybook/manager.js\nimport { addons } from '@storybook/addons';\n\naddons.setConfig({\n  showToolbar: false,\n});\n```\n\n### Dropped support for addon-actions addDecorators\n\nPrior to SB6.5, `addon-actions` provided an option called `addDecorators`. In SB6.5, decorators are applied always. This is technically a breaking change, so if this affects you please file an issue in Github and we can consider reverting this in a patch release.\n\n### Vite builder renamed\n\nSB6.5 renames Storybook's [Vite builder](https://github.com/storybookjs/builder-vite) from `storybook-builder-vite` to `@storybook/builder-vite`. This move is part of a larger effort to improve Vite support in Storybook.\n\nStorybook's `automigrate` command can migrate for you. To manually migrate:\n\n1. Remove `storybook-builder-vite` from your `package.json` dependencies\n2. Install `@storybook/builder-vite`\n3. Update your `core.builder` setting in `.storybook/main.js` to `@storybook/builder-vite`.\n\n### Docs framework refactor for React\n\nSB6.5 moves framework specializations (e.g. ArgType inference, dynamic snippet rendering) out of `@storybook/addon-docs` and into the specific framework packages to which they apply (e.g. `@storybook/react`).\n\nThis change should not require any specific migrations on your part if you are using the docs addon as described in the documentation. However, if you are using `react-docgen` or `react-docgen-typescript` information in some custom way outside of `addon-docs`, you should be aware of this change.\n\nIn SB6.4, `@storybook/react` added `react-docgen` to its babel settings and `react-docgen-typescript` to its Webpack settings. In SB6.5, this only happens if you are using `addon-docs` or `addon-controls`, either directly or indirectly through `addon-essentials`. If you're not using either of those addons, but require that information for some other addon, please configure that manually in your `.storybook/main.js` configuration. You can see the docs configuration here: https://github.com/storybookjs/storybook/blob/next/code/presets/react-webpack/src/framework-preset-react-docs.ts\n\n### Opt-in MDX2 support\n\nSB6.5 adds experimental opt-in support for MDXv2. To install:\n\n```sh\nyarn add @storybook/mdx2-csf -D\n```\n\nThen add the `previewMdx2` feature flag to your `.storybook/main.js` config:\n\n```js\nmodule.exports = {\n  features: {\n    previewMdx2: true,\n  },\n};\n```\n\n### CSF3 auto-title improvements\n\nSB 6.4 introduced experimental \"auto-title\", in which a story's location in the sidebar (aka `title`) can be automatically inferred from its location on disk. For example, the file `atoms/Button.stories.js` might result in the title `Atoms/Button`.\n\nWe've made two improvements to Auto-title based on user feedback:\n\n- Auto-title preserves filename case\n- Auto-title removes redundant filenames from the path\n\n#### Auto-title filename case\n\nSB 6.4's implementation of auto-title ran `startCase` on each path component. For example, the file `atoms/MyButton` would be transformed to `Atoms/My Button`.\n\nWe've changed this in SB 6.5 to preserve the filename case, so that instead it the same file would result in the title `atoms/MyButton`. The rationale is that this gives more control to users about what their auto-title will be.\n\nThis might be considered a breaking change. However, we feel justified to release this in 6.5 because:\n\n1. We consider it a bug in the initial auto-title implementation\n2. CSF3 and the auto-title feature are experimental, and we reserve the right to make breaking changes outside of semver (tho we try to avoid it)\n\nIf you want to restore the old titles in the UI, you can customize your sidebar with the following code snippet in `.storybook/manager.js`:\n\n```js\nimport { addons } from '@storybook/addons';\nimport startCase from 'lodash/startCase';\n\naddons.setConfig({\n  sidebar: {\n    renderLabel: ({ name, type }) => (type === 'story' ? name : startCase(name)),\n  },\n});\n```\n\n#### Auto-title redundant filename\n\nThe heuristic failed in the common scenario in which each component gets its own directory, e.g. `atoms/Button/Button.stories.js`, which would result in the redundant title `Atoms/Button/Button`. Alternatively, `atoms/Button/index.stories.js` would result in `Atoms/Button/Index`.\n\nTo address this problem, 6.5 introduces a new heuristic to removes the filename if it matches the directory name or `index`. So `atoms/Button/Button.stories.js` and `atoms/Button/index.stories.js` would both result in the title `Atoms/Button` (or `atoms/Button` if `autoTitleFilenameCase` is set, see above).\n\nSince CSF3 is experimental, we are introducing this technically breaking change in a minor release. If you desire the old structure, you can manually specify the title in file. For example:\n\n```js\n// atoms/Button/Button.stories.js\nexport default { title: 'Atoms/Button/Button' };\n```\n\n#### Auto-title always prefixes\n\nWhen the user provides a `prefix` in their `main.js` `stories` field, it now prefixes all titles to matching stories, whereas in 6.4 and earlier it only prefixed auto-titles.\n\nConsider the following example:\n\n```js\n// main.js\nmodule.exports = {\n  stories: [{ directory: '../src', titlePrefix: 'Custom' }]\n}\n\n// ../src/NoTitle.stories.js\nexport default { component: Foo };\n\n// ../src/Title.stories.js\nexport default { component: Bar, title: 'Bar' }\n```\n\nIn 6.4, the final titles would be:\n\n- `NoTitle.stories.js` => `Custom/NoTitle`\n- `Title.stories.js` => `Bar`\n\nIn 6.5, the final titles would be:\n\n- `NoTitle.stories.js` => `Custom/NoTitle`\n- `Title.stories.js` => `Custom/Bar`\n\n<!-- markdown-link-check-disable -->\n\n### 6.5 Deprecations\n\n#### Deprecated register.js\n\nIn ancient versions of Storybook, addons were registered by referring to `addon-name/register.js`. This is going away in SB7.0. Instead you should just add `addon-name` to the `addons` array in `.storybook/main.js`.\n\nBefore:\n\n```js\nmodule.exports = { addons: ['my-addon/register.js'] };\n```\n\nAfter:\n\n```js\nmodule.exports = { addons: ['my-addon'] };\n```\n\n## From version 6.3.x to 6.4.0\n\n### Automigrate\n\nAutomigrate is a new 6.4 feature that provides zero-config upgrades to your dependencies, configurations, and story files.\n\nEach automigration analyzes your project, and if it's is applicable, propose a change alongside relevant documentation. If you accept the changes, the automigration will update your files accordingly.\n\nFor example, if you're in a webpack5 project but still use Storybook's default webpack4 builder, the automigration can detect this and propose an upgrade. If you opt-in, it will install the webpack5 builder and update your `main.js` configuration automatically.\n\nYou can run the existing suite of automigrations to see which ones apply to your project. This won't update any files unless you accept the changes:\n\n```\n\nnpx sb@latest automigrate\n\n```\n\nThe automigration suite also runs when you create a new project (`sb init`) or when you update Storybook (`sb upgrade`).\n\n### CRA5 upgrade\n\nStorybook 6.3 supports CRA5 out of the box when you install it fresh. However, if you're upgrading your project from a previous version, you'll need to upgrade the configuration. You can do this automatically by running:\n\n```\n\nnpx sb@latest automigrate\n\n```\n\nOr you can do the following steps manually to force Storybook to use Webpack 5 for building your project:\n\n```shell\nyarn add @storybook/builder-webpack5 @storybook/manager-webpack5 --dev\n# Or\nnpm install @storybook/builder-webpack5 @storybook/manager-webpack5 --save-dev\n```\n\nThen edit your `.storybook/main.js` config:\n\n```js\nmodule.exports = {\n  core: {\n    builder: 'webpack5',\n  },\n};\n```\n\n### CSF3 enabled\n\nSB6.3 introduced a feature flag, `features.previewCsfV3`, to opt-in to experimental [CSF3 syntax support](https://storybook.js.org/blog/component-story-format-3-0/). In SB6.4, CSF3 is supported regardless of `previewCsfV3`'s value. This should be a fully backwards-compatible change. The `previewCsfV3` flag has been deprecated and will be removed in SB7.0.\n\n#### Optional titles\n\nIn SB6.3 and earlier, component titles were required in CSF default exports. Starting in 6.4, they are optional.\nIf you don't specify a component file, it will be inferred from the file's location on disk.\n\nConsider a project configuration `/path/to/project/.storybook/main.js` containing:\n\n```js\nmodule.exports = { stories: ['../src/**/*.stories.*'] };\n```\n\nAnd the file `/path/to/project/src/components/Button.stories.tsx` containing the default export:\n\n```js\nimport { Button } from './Button';\n\nexport default { component: Button };\n// named exports...\n```\n\nThe inferred title of this file will be `components/Button` based on the stories glob in the configuration file.\nWe will provide more documentation soon on how to configure this.\n\n#### String literal titles\n\nStarting in 6.4 CSF component [titles are optional](#optional-titles). However, if you do specify titles, title handing is becoming more strict in V7 and is limited to string literals.\n\nEarlier versions of Storybook supported story titles that are dynamic Javascript expressions\n\n```js\n// ✅ string literals 6.3 OK / 7.0 OK\nexport default {\n  title: 'Components/Atoms/Button',\n};\n\n// ✅ undefined 6.3 OK / 7.0 OK\nexport default {\n  component: Button,\n};\n\n// ❌ expressions: 6.3 OK / 7.0 KO\nexport default {\n  title: foo('bar'),\n};\n\n// ❌ template literals 6.3 OK / 7.0 KO\nexport default {\n  title: `${bar}`,\n};\n```\n\n#### StoryObj type\n\nThe TypeScript type for CSF3 story objects is `StoryObj`, and this will become the default in Storybook 7.0. In 6.x, the `StoryFn` type is the default, and `Story` is aliased to `StoryFn`.\n\nIf you are migrating to experimental CSF3, the following is compatible with 6.4 and requires the least amount of change to your code today:\n\n```ts\n// CSF2 function stories, current API, will break in 7.0\nimport type { Story } from '@storybook/<framework>';\n// CSF3 object stories, will persist in 7.0\nimport type { StoryObj } from '@storybook/<framework>';\n```\n\nThe following is compatible with 6.4 and also forward-compatible with anticipated 7.0 changes:\n\n```ts\n// CSF2 function stories, forward-compatible mode\nimport type { StoryFn } from '@storybook/<framework>';\n// CSF3 object stories, using future 7.0 types\nimport type { Story } from '@storybook/<framework>/types-7-0';\n```\n\n### Story Store v7\n\nSB6.4 introduces an opt-in feature flag, `features.storyStoreV7`, which loads stories in an \"on demand\" way (that is when rendered), rather than up front when the Storybook is booted. This way of operating will become the default in 7.0 and will likely be switched to opt-out in that version.\n\nThe key benefit of the on demand store is that stories are code-split automatically (in `builder-webpack4` and `builder-webpack5`), which allows for much smaller bundle sizes, faster rendering, and improved general performance via various opt-in Webpack features.\n\nThe on-demand store relies on the \"story index\" data structure which is generated in the server (node) via static code analysis. As such, it has the following limitations:\n\n- Does not work with `storiesOf()`\n- Does not work if you use dynamic story names or component titles.\n\nHowever, the `autoTitle` feature is supported.\n\n#### Behavioral differences\n\nThe key behavioral differences of the v7 store are:\n\n- `SET_STORIES` is not emitted on boot up. Instead the manager loads the story index independently.\n- A new event `STORY_PREPARED` is emitted when a story is rendered for the first time, which contains metadata about the story, such as `parameters`.\n- All \"entire\" store APIs such as `extract()` need to be proceeded by an async call to `loadAllCSFFiles()` which fetches all CSF files and processes them.\n\n#### Main.js framework field\n\nIn earlier versions of Storybook, each framework package (e.g. `@storybook/react`) provided its own `start-storybook` and `build-storybook` binaries, which automatically filled in various settings.\n\nIn 7.0, we're moving towards a model where the user specifies their framework in `main.js`.\n\n```js\nmodule.exports = {\n  // ... your existing config\n  framework: '@storybook/react', // OR whatever framework you're using\n};\n```\n\nEach framework must export a `renderToDOM` function and `parameters.framework`. We'll be adding more documentation for framework authors in a future release.\n\n#### Using the v7 store\n\nTo activate the v7 mode set the feature flag in your `.storybook/main.js` config:\n\n```js\nmodule.exports = {\n  // ... your existing config\n  framework: '@storybook/react', // OR whatever framework you're using\n  features: {\n    storyStoreV7: true,\n  },\n};\n```\n\nNOTE: `features.storyStoreV7` implies `features.buildStoriesJson` and has the same limitations.\n\n#### v7-style story sort\n\nIf you've written a custom `storySort` function, you'll need to rewrite it for V7.\n\nSB6.x supports a global story function specified in `.storybook/preview.js`. It accepts two arrays which each contain:\n\n- The story ID\n- A story object that contains the name, title, etc.\n- The component's parameters\n- The project-level parameters\n\nSB 7.0 streamlines the story function. It now accepts a `StoryIndexEntry` which is\nan object that contains only the story's `id`, `title`, `name`, and `importPath`.\n\nConsider the following example, before and after:\n\n```js\n// v6-style sort\nfunction storySort(a, b) {\n  return a[1].kind === b[1].kind\n    ? 0\n    : a[1].id.localeCompare(b[1].id, undefined, { numeric: true });\n},\n```\n\nAnd the after version using `title` instead of `kind` and not receiving the full parameters:\n\n```js\n// v7-style sort\nfunction storySort(a, b) {\n  return a.title === b.title\n    ? 0\n    : a.id.localeCompare(b.id, undefined, { numeric: true });\n},\n```\n\n**NOTE:** v7-style sorting is statically analyzed by Storybook, which puts a variety of constraints versus v6:\n\n- Sorting must be specified in the user's `.storybook/preview.js`. It cannot be specified by an addon or preset.\n- The `preview.js` export should not be generated by a function.\n- `storySort` must be a self-contained function that does not reference external variables.\n\n#### v7 default sort behavior\n\nThe behavior of the default `storySort` function has also changed in v7 thanks to [#18423](https://github.com/storybookjs/storybook/pull/18243), which gives better control over hierarchical sorting.\n\nIn 6.x, the following configuration would sort any story/doc containing the title segment `Introduction` to the top of the sidebar, so this would match `Introduction`, `Example/Introduction`, `Very/Nested/Introduction`, etc.\n\n```js\n// preview.js\nexport default {\n  parameters: {\n    options: {\n      storySort: {\n        order: ['Introduction', '*'],\n      },\n    },\n  },\n};\n```\n\nIn 7.0+, the targeting is more precise, so the preceding example would match `Introduction`, but not anything nested. If you wanted to sort `Example/Introduction` first, you'd need to specify that:\n\n```js\nstorySort: {\n  order: ['*', ['Introduction', '*']],\n}\n```\n\nThis would sort `*/Introduction` first, but not `Introduction` or `Very/Nested/Introduction`. If you want to target `Introduction` stories/docs anywhere in the hierarchy, you can do this with a [custom sort function](https://storybook.js.org/docs/react/writing-stories/naming-components-and-hierarchy#sorting-stories).\n\n#### v7 Store API changes for addon authors\n\nThe Story Store in v7 mode is async, so synchronous story loading APIs no longer work. In particular:\n\n- `store.fromId()` has been replaced by `store.loadStory()`, which is async (i.e. returns a `Promise` you will need to await).\n- `store.raw()/store.extract()` and friends that list all stories require a prior call to `store.cacheAllCSFFiles()` (which is async). This will load all stories, and isn't generally a good idea in an addon, as it will force the whole store to load.\n\n#### Storyshots compatibility in the v7 store\n\nStoryshots is not currently compatible with the v7 store. However, you can use the following workaround to opt-out of the v7 store when running storyshots; in your `main.js`:\n\n```js\nmodule.exports = {\n  features: {\n    storyStoreV7: !global.navigator?.userAgent?.match?.('jsdom'),\n  },\n};\n```\n\nThere are some caveats with the above approach:\n\n- The code path in the v6 store is different to the v7 store and your mileage may vary in identical behavior. Buyer beware.\n- The story sort API [changed between the stores](#v7-style-story-sort). If you are using a custom story sort function, you will need to ensure it works in both contexts (perhaps using the check `global.navigator.userAgent.match('jsdom')`).\n\n### Emotion11 quasi-compatibility\n\nNow that the web is moving to Emotion 11 for styling, popular libraries like MUI5 and ChakraUI are breaking with Storybook 6.3 which only supports emotion@10.\n\nUnfortunately we're unable to upgrade Storybook to Emotion 11 without a semver major release, and we're not ready for that. So, as a workaround, we've created a feature flag which opts-out of the previous behavior of pinning the Emotion version to v10. To enable this workaround, add the following to your `.storybook/main.js` config:\n\n```js\nmodule.exports = {\n  features: {\n    emotionAlias: false,\n  },\n};\n```\n\nSetting this should unlock theming for emotion11-based libraries in Storybook 6.4.\n\n### Babel mode v7\n\nSB6.4 introduces an opt-in feature flag, `features.babelModeV7`, that reworks the way Babel is configured in Storybook to make it more consistent with the Babel is configured in your app. This breaking change will become the default in SB 7.0, but we encourage you to migrate today.\n\n> NOTE: CRA apps using `@storybook/preset-create-react-app` use CRA's handling, so the new flag has no effect on CRA apps.\n\nIn SB6.x and earlier, Storybook provided its own default configuration and inconsistently handled configurations from the user's babelrc file. This resulted in a final configuration that differs from your application's configuration AND is difficult to debug.\n\nIn `babelModeV7`, Storybook no longer provides its own default configuration and is primarily configured via babelrc file, with small, incremental updates from Storybook addons.\n\nIn 6.x, Storybook supported a `.storybook/babelrc` configuration option. This is no longer supported and it's up to you to reconcile this with your project babelrc.\n\nTo activate the v7 mode set the feature flag in your `.storybook/main.js` config:\n\n```js\nmodule.exports = {\n  // ... your existing config\n  features: {\n    babelModeV7: true,\n  },\n};\n```\n\nIn the new mode, Storybook expects you to provide a configuration file. If you want a configuration file that's equivalent to the 6.x default, you can run the following command in your project directory:\n\n```sh\nnpx sb@latest babelrc\n```\n\nThis will create a `.babelrc.json` file. This file includes a bunch of babel plugins, so you may need to add new package devDependencies accordingly.\n\n### Loader behavior with args changes\n\nIn 6.4 the behavior of loaders when arg changes occurred was tweaked so loaders do not re-run. Instead the previous value of the loader is passed to the story, irrespective of the new args.\n\n### 6.4 Angular changes\n\n#### SB Angular builder\n\nSince SB6.3, Storybook for Angular supports a builder configuration in your project's `angular.json`. This provides an Angular-style configuration for running and building your Storybook. An example builder configuration is now part of the [get started documentation page](https://storybook.js.org/docs/angular/get-started/install).\n\nIf you want to know all the available options, please checks the builders' validation schemas :\n\n- `start-storybook`: [schema](https://github.com/storybookjs/storybook/blob/next/code/frameworks/angular/src/builders/start-storybook/schema.json)\n- `build-storybook`: [schema](https://github.com/storybookjs/storybook/blob/next/code/frameworks/angular/src/builders/build-storybook/schema.json)\n\n#### Angular13\n\nAngular 13 introduces breaking changes that require updating your Storybook configuration if you are migrating from a previous version of Angular.\n\nMost notably, the documented way of including global styles is no longer supported by Angular13. Previously you could write the following in your `.storybook/preview.js` config:\n\n```\nimport '!style-loader!css-loader!sass-loader!./styles.scss';\n```\n\nIf you use Angular 13 and above, you should use the builder configuration instead:\n\n```json\n   \"my-default-project\": {\n      \"architect\": {\n        \"build\": {\n          \"builder\": \"@angular-devkit/build-angular:browser\",\n          \"options\": {\n            \"styles\": [\"src/styles.css\", \"src/styles.scss\"],\n          }\n        }\n      },\n   },\n```\n\nIf you need storybook-specific styles separate from your app, you can configure the styles in the [SB Angular builder](#sb-angular-builder), which completely overrides your project's styles:\n\n```json\n      \"storybook\": {\n        \"builder\": \"@storybook/angular:start-storybook\",\n        \"options\": {\n          \"browserTarget\": \"my-default-project:build\",\n          \"styles\": [\".storybook/custom-styles.scss\"],\n        },\n      }\n```\n\nThen, once you've set this up, you should run Storybook through the builder:\n\n```sh\nng run my-default-project:storybook\nng run my-default-project:build-storybook\n```\n\n#### Angular component parameter removed\n\nIn SB6.3 and earlier, the `default.component` metadata was implemented as a parameter, meaning that stories could set `parameters.component` to override the default export. This was an internal implementation that was never documented, but it was mistakenly used in some Angular examples.\n\nIf you have Angular stories of the form:\n\n```js\nexport const MyStory = () => ({ ... })\nSomeStory.parameters = { component: MyComponent };\n```\n\nYou should rewrite them as:\n\n```js\nexport const MyStory = () => ({ component: MyComponent, ... })\n```\n\n[More discussion here.](https://github.com/storybookjs/storybook/pull/16010#issuecomment-917378595)\n\n### 6.4 deprecations\n\n#### Deprecated --static-dir CLI flag\n\nIn 6.4 we've replaced the `--static-dir` CLI flag with the `staticDirs` field in `.storybook/main.js`. Note that the CLI directories are relative to the current working directory, whereas the `staticDirs` are relative to the location of `main.js`.\n\nBefore:\n\n```sh\nstart-storybook --static-dir ./public,./static,./foo/assets:/assets\n```\n\nAfter:\n\n```js\n// .storybook/main.js\nmodule.exports = {\n  staticDirs: ['../public', '../static', { from: '../foo/assets', to: '/assets' }],\n};\n```\n\nThe `--static-dir` flag has been deprecated and will be removed in Storybook 7.0.\n\n## From version 6.2.x to 6.3.0\n\n### Webpack 5\n\nStorybook 6.3 brings opt-in support for building both your project and the manager UI with webpack 5. To do so, there are two ways:\n\n1 - Upgrade command\n\nIf you're upgrading your Storybook version, run this command, which will both upgrade your dependencies but also detect whether you should migrate to webpack5 builders and apply the changes automatically:\n\n```shell\nnpx sb upgrade\n```\n\n2 - Automigrate command\n\nIf you don't want to change your Storybook version but want Storybook to detect whether you should migrate to webpack5 builders and apply the changes automatically:\n\n```shell\nnpx sb automigrate\n```\n\n3 - Manually\n\nIf either methods did not work or you just want to proceed manually, do the following steps:\n\nInstall the dependencies:\n\n```shell\nyarn add @storybook/builder-webpack5 @storybook/manager-webpack5 --dev\n# Or\nnpm install @storybook/builder-webpack5 @storybook/manager-webpack5 --save-dev\n```\n\nThen edit your `.storybook/main.js` config:\n\n```js\nmodule.exports = {\n  core: {\n    builder: 'webpack5',\n  },\n};\n```\n\n> NOTE: If you're using `@storybook/preset-create-react-app` make sure to update it to version 4.0.0 as well.\n\n#### Fixing hoisting issues\n\n##### Webpack 5 manager build\n\nStorybook 6.2 introduced **experimental** webpack5 support for building user components. Storybook 6.3 also supports building the manager UI in webpack 5 to avoid strange hoisting issues.\n\nIf you're upgrading from 6.2 and already using the experimental webpack5 feature, this might be a breaking change (hence the 'experimental' label) and you should try adding the manager builder:\n\n```shell\nyarn add @storybook/manager-webpack5 --dev\n# Or\nnpm install @storybook/manager-webpack5 --save-dev\n```\n\n##### Wrong webpack version\n\nBecause Storybook uses `webpack@4` as the default, it's possible for the wrong version of webpack to get hoisted by your package manager. If you receive an error that looks like you might be using the wrong version of webpack, install `webpack@5` explicitly as a dev dependency to force it to be hoisted:\n\n```shell\nyarn add webpack@5 --dev\n# Or\nnpm install webpack@5 --save-dev\n```\n\nAlternatively or additionally you might need to add a resolution to your package.json to ensure that a consistent webpack version is provided across all of storybook packages. Replacing the {app} with the app (react, vue, etc.) that you're using:\n\n```js\n// package.json\n...\nresolutions: {\n  \"@storybook/{app}/webpack\": \"^5\"\n}\n...\n```\n\n### Angular 12 upgrade\n\nStorybook 6.3 supports Angular 12 out of the box when you install it fresh. However, if you're upgrading your project from a previous version, you'll need to [follow the steps for opting-in to webpack 5](#webpack-5).\n\n### Lit support\n\nStorybook 6.3 introduces Lit 2 support in a non-breaking way to ease migration from `lit-html`/`lit-element` to `lit`.\n\nTo do so, it relies on helpers added in the latest minor versions of `lit-html`/`lit-element`. So when upgrading to Storybook 6.3, please ensure your project is using `lit-html` 1.4.x or `lit-element` 2.5.x.\n\nAccording to the package manager you are using, it can be handled automatically when updating Storybook or can require to manually update the versions and regenerate the lockfile.\n\n### No longer inferring default values of args\n\nPreviously, unset `args` were set to the `argType.defaultValue` if set or inferred from the component's prop types (etc.). In 6.3 we no longer infer default values and instead set arg values to `undefined` when unset, allowing the framework to supply the default value.\n\nIf you were using `argType.defaultValue` to fix issues with the above inference, it should no longer be necessary, you can remove that code.\n\nIf you were using `argType.defaultValue` or relying on inference to set a default value for an arg, you should now set a value for the arg at the component level:\n\n```js\nexport default {\n  component: MyComponent,\n  args: {\n    argName: 'default-value',\n  },\n};\n```\n\nTo manually configure the value that is shown in the ArgsTable doc block, you can configure the `table.defaultValue` setting:\n\n```js\nexport default {\n  component: MyComponent,\n  argTypes: {\n    argName: {\n      table: { defaultValue: { summary: 'SomeType<T>' } },\n    },\n  },\n};\n```\n\n### 6.3 deprecations\n\n#### Deprecated addon-knobs\n\nWe are replacing `@storybook/addon-knobs` with `@storybook/addon-controls`.\n\n- [Rationale & discussion](https://github.com/storybookjs/storybook/discussions/15060)\n- [Migration notes](https://github.com/storybookjs/storybook/blob/next/code/addons/controls/README.md#how-do-i-migrate-from-addon-knobs)\n\n#### Deprecated scoped blocks imports\n\nIn 6.3, we changed doc block imports from `@storybook/addon-docs/blocks` to `@storybook/addon-docs`. This makes it possible for bundlers to automatically choose the ESM or CJS version of the library depending on the context.\n\nTo update your code, you should be able to global replace `@storybook/addon-docs/blocks` with `@storybook/addon-docs`. Example:\n\n```js\n// before\nimport { Meta, Story } from '@storybook/addon-docs/blocks';\n\n// after\nimport { Meta, Story } from '@storybook/addon-docs';\n```\n\n#### Deprecated layout URL params\n\nSeveral URL params to control the manager layout have been deprecated and will be removed in 7.0:\n\n- `addons=0`: use `panel=false` instead\n- `panelRight=1`: use `panel=right` instead\n- `stories=0`: use `nav=false` instead\n\nAdditionally, support for legacy URLs using `selectedKind` and `selectedStory` will be removed in 7.0. Use `path` instead.\n\n## From version 6.1.x to 6.2.0\n\n### MDX pattern tweaked\n\nIn 6.2 files ending in `stories.mdx` or `story.mdx` are now processed with Storybook's MDX compiler. Previously it only applied to files ending in `.stories.mdx` or `.story.mdx`. See more here: [#13996](https://github.com/storybookjs/storybook/pull/13996).\n\n### 6.2 Angular overhaul\n\n#### New Angular storyshots format\n\nWe've updated the Angular storyshots format in 6.2, which is technically a breaking change. Apologies to semver purists: if you're using storyshots, you'll need to [update your snapshots](https://jestjs.io/docs/en/snapshot-testing#updating-snapshots).\n\nThe new format hides the implementation details of `@storybook/angular` so that we can evolve its renderer without breaking your snapshots in the future.\n\n#### Deprecated Angular story component\n\nStorybook 6.2 for Angular uses `parameters.component` as the preferred way to specify your stories' components. The previous method, in which the component was a return value of the story, has been deprecated.\n\nConsider the existing story from 6.1 or earlier:\n\n```ts\nexport default { title: 'Button' };\nexport const Basic = () => ({\n  component: Button,\n  props: { label: 'Label' },\n});\n```\n\nFrom 6.2 this should be rewritten as:\n\n```ts\nexport default { title: 'Button', component: Button };\nexport const Basic = () => ({\n  props: { label: 'Label' },\n});\n```\n\nThe new convention is consistent with how other frameworks and addons work in Storybook. The old way will be supported until 7.0. For a full discussion see <https://github.com/storybookjs/storybook/issues/8673>.\n\n#### New Angular renderer\n\nWe've rewritten the Angular renderer in Storybook 6.2. It's meant to be entirely backwards compatible, but if you need to use the legacy renderer it's still available via a [parameter](https://storybook.js.org/docs/angular/writing-stories/parameters). To opt out of the new renderer, add the following to `.storybook/preview.ts`:\n\n```ts\nexport const parameters = {\n  angularLegacyRendering: true,\n};\n```\n\nPlease also file an issue if you need to opt out. We plan to remove the legacy renderer in 7.0.\n\n#### Components without selectors\n\nWhen the new Angular renderer is used, all Angular Story components must either have a selector, or be added to the `entryComponents` array of the story's `moduleMetadata`. If the component has any `Input`s or `Output`s to be controlled with `args`, a selector should be added.\n\n### Packages now available as ESModules\n\nMany Storybook packages are now available as ESModules in addition to CommonJS. If your jest tests stop working, this is likely why. One common culprit is doc blocks, which [is fixed in 6.3](#deprecated-scoped-blocks-imports). In 6.2, you can configure jest to transform the packages like so ([more info](https://jestjs.io/docs/configuration#transformignorepatterns-arraystring)):\n\n```json\n// In your jest config\ntransformIgnorePatterns: ['/node_modules/(?!@storybook)']\n```\n\n### 6.2 Deprecations\n\n#### Deprecated implicit PostCSS loader\n\nPreviously, `@storybook/core` would automatically add the `postcss-loader` to your preview. This caused issues for consumers when PostCSS upgraded to v8 and tools, like Autoprefixer and Tailwind, starting requiring the new version. Implicitly adding `postcss-loader` will be removed in Storybook 7.0.\n\nInstead of continuing to include PostCSS inside the core library, it has been moved to [`@storybook/addon-postcss`](https://github.com/storybookjs/addon-postcss). This addon provides more fine-grained customization and will be upgraded more flexibly to track PostCSS upgrades.\n\nIf you require PostCSS support, please install `@storybook/addon-postcss` in your project, add it to your list of addons inside `.storybook/main.js`, and configure a `postcss.config.js` file.\n\nFurther information is available at <https://github.com/storybookjs/storybook/issues/12668> and <https://github.com/storybookjs/storybook/pull/13669>.\n\nIf you're not using Postcss and you don't want to see the warning, you can disable it by adding the following to your `.storybook/main.js`:\n\n```js\nmodule.exports = {\n  features: {\n    postcss: false,\n  },\n};\n```\n\n#### Deprecated default PostCSS plugins\n\nWhen relying on the [implicit PostCSS loader](#deprecated-implicit-postcss-loader), it would also add [autoprefixer v9](https://www.npmjs.com/package/autoprefixer/v/9.8.6) and [postcss-flexbugs-fixes v4](https://www.npmjs.com/package/postcss-flexbugs-fixes/v/4.2.1) plugins to the `postcss-loader` configuration when you didn't have a PostCSS config file (such as `postcss.config.js`) within your project.\n\nThey will no longer be applied when switching to `@storybook/addon-postcss` and the implicit PostCSS features will be removed in Storybook 7.0.\n\nIf you depend upon these plugins being applied, install them and create a `postcss.config.js` file within your project that contains:\n\n```js\nmodule.exports = {\n  plugins: [\n    require('postcss-flexbugs-fixes'),\n    require('autoprefixer')({\n      flexbox: 'no-2009',\n    }),\n  ],\n};\n```\n\n#### Deprecated showRoots config option\n\nConfig options for the sidebar are now under the `sidebar` namespace. The `showRoots` option should be set as follows:\n\n```js\naddons.setConfig({\n  sidebar: {\n    showRoots: false,\n  },\n  // showRoots: false   <- this is deprecated\n});\n```\n\nThe top-level `showRoots` option will be removed in Storybook 7.0.\n\n#### Deprecated control.options\n\nPossible `options` for a radio/check/select controls has been moved up to the argType level, and no longer accepts an object. Instead, you should specify `options` as an array. You can use `control.labels` to customize labels. Additionally, you can use a `mapping` to deal with complex values.\n\n```js\nargTypes: {\n  answer:\n    options: ['yes', 'no'],\n    mapping: {\n      yes: <Check />,\n      no: <Cross />,\n    },\n    control: {\n      type: 'radio',\n      labels: {\n        yes: 'да',\n        no: 'нет',\n      }\n    }\n  }\n}\n```\n\nKeys in `control.labels` as well as in `mapping` should match the values in `options`. Neither object has to be exhaustive, in case of a missing property, the option value will be used directly.\n\nIf you are currently using an object as value for `control.options`, be aware that the key and value are reversed in `control.labels`.\n\n#### Deprecated storybook components html entry point\n\nStorybook HTML components are now exported directly from '@storybook/components' for better ESM and Typescript compatibility. The old entry point will be removed in SB 7.0.\n\n```js\n// before\nimport { components } from '@storybook/components/html';\n\n// after\nimport { components } from '@storybook/components';\n```\n\n## From version 6.0.x to 6.1.0\n\n### Addon-backgrounds preset\n\nIn 6.1 we introduced an unintentional breaking change to `addon-backgrounds`.\n\nThe addon uses decorators which are set up automatically by a preset. The required preset is ignored if you register the addon in `main.js` with the `/register` entry point. This used to be valid in `v6.0.x` and earlier:\n\n```js\nmodule.exports = {\n  stories: ['../**/*.stories.js'],\n  addons: ['@storybook/addon-backgrounds/register'],\n};\n```\n\nTo fix it, just replace `@storybook/addon-backgrounds/register` with `@storybook/addon-backgrounds`:\n\n```js\nmodule.exports = {\n  stories: ['../**/*.stories.js'],\n  addons: ['@storybook/addon-backgrounds'],\n};\n```\n\n### Single story hoisting\n\nStories which have **no siblings** (i.e. the component has only one story) and which name **exactly matches** the component name will now be hoisted up to replace their parent component in the sidebar. This means you can have a hierarchy like this:\n\n```\nDESIGN SYSTEM   [root]\n- Atoms         [group]\n  - Button      [component]\n    - Button    [story]\n  - Checkbox    [component]\n    - Checkbox  [story]\n```\n\nThis will then be visually presented in the sidebar like this:\n\n```\nDESIGN SYSTEM   [root]\n- Atoms         [group]\n  - Button      [story]\n  - Checkbox    [story]\n```\n\nSee [Naming components and hierarchy](https://storybook.js.org/docs/react/writing-stories/naming-components-and-hierarchy#single-story-hoisting) for details.\n\n### React peer dependencies\n\nStarting in 6.1, `react` and `react-dom` are required peer dependencies of `@storybook/react`, meaning that if your React project does not have dependencies on them, you need to add them as `devDependencies`. If you don't you'll see errors like this:\n\n```\nError: Cannot find module 'react-dom/package.json'\n```\n\nThey were also peer dependencies in earlier versions, but due to the package structure they would be installed by Storybook if they were not required by the user's project. For more discussion: <https://github.com/storybookjs/storybook/issues/13269>\n\n### 6.1 deprecations\n\n#### Deprecated DLL flags\n\nEarlier versions of Storybook used Webpack DLLs as a performance crutch. In 6.1, we've removed Storybook's built-in DLLs and have deprecated the command-line parameters `--no-dll` and `--ui-dll`. They will be removed in 7.0.\n\n#### Deprecated storyFn\n\nEach item in the story store contains a field called `storyFn`, which is a fully decorated story that's applied to the denormalized story parameters. Starting in 6.0 we've stopped using this API internally, and have replaced it with a new field called `unboundStoryFn` which, unlike `storyFn`, must passed a story context, typically produced by `applyLoaders`;\n\nBefore:\n\n```js\nconst { storyFn } = store.fromId('some--id');\nconsole.log(storyFn());\n```\n\nAfter:\n\n```js\nconst { unboundStoryFn, applyLoaders } = store.fromId('some--id');\nconst context = await applyLoaders();\nconsole.log(unboundStoryFn(context));\n```\n\nIf you're not using loaders, `storyFn` will work as before. If you are, you'll need to use the new approach.\n\n> NOTE: If you're using `@storybook/addon-docs`, this deprecation warning is triggered by the Docs tab in 6.1. It's safe to ignore and we will be providing a proper fix in a future release. You can track the issue at <https://github.com/storybookjs/storybook/issues/13074>.\n\n#### Deprecated onBeforeRender\n\nThe `@storybook/addon-docs` previously accepted a `jsx` option called `onBeforeRender`, which was unfortunately named as it was called after the render.\n\nWe've renamed it `transformSource` and also allowed it to receive the `StoryContext` in case source rendering requires additional information.\n\n#### Deprecated grid parameter\n\nPreviously when using `@storybook/addon-backgrounds` if you wanted to customize the grid, you would define a parameter like this:\n\n```js\nexport const Basic = () => <Button />\nBasic.parameters: {\n  grid: {\n    cellSize: 10\n  }\n},\n```\n\nAs grid is not an addon, but rather backgrounds is, the grid configuration was moved to be inside `backgrounds` parameter instead. Also, there are new properties that can be used to further customize the grid. Here's an example with the default values:\n\n```js\nexport const Basic = () => <Button />\nBasic.parameters: {\n  backgrounds: {\n    grid: {\n      disable: false,\n      cellSize: 20,\n      opacity: 0.5,\n      cellAmount: 5,\n      offsetX: 16, // default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n      offsetY: 16, // default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n    }\n  }\n},\n```\n\n#### Deprecated package-composition disabled parameter\n\nLike [Deprecated disabled parameter](#deprecated-disabled-parameter). The `disabled` parameter has been deprecated, please use `disable` instead.\n\nFor more information, see the [the related documentation](https://storybook.js.org/docs/react/workflows/package-composition#configuring).\n\n## From version 5.3.x to 6.0.x\n\n### Hoisted CSF annotations\n\nStorybook 6 introduces hoisted CSF annotations and deprecates the `StoryFn.story` object-style annotation.\n\nIn 5.x CSF, you would annotate a story like this:\n\n```js\nexport const Basic = () => <Button />\nBasic.story = {\n  name: 'foo',\n  parameters: { ... },\n  decorators: [ ... ],\n};\n```\n\nIn 6.0 CSF this becomes:\n\n```js\nexport const Basic = () => <Button />\nBasic.storyName = 'foo';\nBasic.parameters = { ... };\nBasic.decorators = [ ... ];\n```\n\n1. The new syntax is slightly more compact/ergonomic compared the old one\n2. Similar to React's `displayName`, `propTypes`, `defaultProps` annotations\n3. We're introducing a new feature, [Storybook Args](https://docs.google.com/document/d/1Mhp1UFRCKCsN8pjlfPdz8ZdisgjNXeMXpXvGoALjxYM/edit?usp=sharing), where the new syntax will be significantly more ergonomic\n\nTo help you upgrade your stories, we've created a codemod:\n\n```\nnpx @storybook/cli@latest migrate csf-hoist-story-annotations --glob=\"**/*.stories.js\"\n```\n\nFor more information, [see the documentation](https://github.com/storybookjs/storybook/blob/next/code/lib/codemod/README.md#csf-hoist-story-annotations).\n\n### Zero config typescript\n\nStorybook has built-in Typescript support in 6.0. That means you should remove your complex Typescript configurations from your `.storybook` config. We've tried to pick sensible defaults that work out of the box, especially for nice prop table generation in `@storybook/addon-docs`.\n\nTo migrate from an old setup, we recommend deleting any typescript-specific webpack/babel configurations in your project. You should also remove `@storybook/preset-typescript`, which is superseded by the built-in configuration.\n\nIf you want to override the defaults, see the [typescript configuration docs](https://storybook.js.org/docs/react/configure/typescript).\n\n### Correct globs in main.js\n\nIn 5.3 we introduced the `main.js` file with a `stories` property. This property was documented as a \"glob\" pattern. This was our intention, however the implementation allowed for non valid globs to be specified and work. In fact, we promoted invalid globs in our documentation and CLI templates.\n\nWe've corrected this, the CLI templates have been changed to use valid globs.\n\nWe've also changed the code that resolves these globs, so that invalid globs will log a warning. They will break in the future, so if you see this warning, please ensure you're specifying a valid glob.\n\nExample of an **invalid** glob:\n\n```\nstories: ['./**/*.stories.(ts|js)']\n```\n\nExample of a **valid** glob:\n\n```\nstories: ['./**/*.stories.@(ts|js)']\n```\n\n### CRA preset removed\n\nThe built-in create-react-app preset, which was [previously deprecated](#create-react-app-preset), has been fully removed.\n\nIf you're using CRA and migrating from an earlier Storybook version, please install [`@storybook/preset-create-react-app`](https://github.com/storybookjs/presets/tree/master/packages/preset-create-react-app) if you haven't already.\n\n### Core-JS dependency errors\n\nSome users have experienced `core-js` dependency errors when upgrading to 6.0, such as:\n\n```\nModule not found: Error: Can't resolve 'core-js/modules/web.dom-collections.iterator'\n```\n\nWe think this comes from having multiple versions of `core-js` installed, but haven't isolated a good solution (see [#11255](https://github.com/storybookjs/storybook/issues/11255) for discussion).\n\nFor now, the workaround is to install `core-js` directly in your project as a dev dependency:\n\n```sh\nnpm install core-js@^3.0.1 --save-dev\n```\n\n### Args passed as first argument to story\n\nStarting in 6.0, the first argument to a story function is an [Args object](https://storybook.js.org/docs/react/api/csf#args-story-inputs). In 5.3 and earlier, the first argument was a [StoryContext](https://github.com/storybookjs/storybook/blob/release/5.3/lib/addons/src/types.ts#L24-L31), and that context is now passed as the second argument by default.\n\nThis breaking change only affects you if your stories actually use the context, which is not common. If you have any stories that use the context, you can either (1) update your stories, or (2) set a flag to opt-out of new behavior.\n\nConsider the following story that uses the context:\n\n```js\nexport const Dummy = ({ parameters }) => <div>{JSON.stringify(parameters)}</div>;\n```\n\nHere's an updated story for 6.0 that ignores the args object:\n\n```js\nexport const Dummy = (_args, { parameters }) => <div>{JSON.stringify(parameters)}</div>;\n```\n\nAlternatively, if you want to opt out of the new behavior, you can add the following to your `.storybook/preview.js` config:\n\n```js\nexport const parameters = {\n  passArgsFirst: false,\n};\n```\n\n### 6.0 Docs breaking changes\n\n#### Remove framework-specific docs presets\n\nIn SB 5.2, each framework had its own preset, e.g. `@storybook/addon-docs/react/preset`. In 5.3 we [unified this into a single preset](#unified-docs-preset): `@storybook/addon-docs/preset`. In 6.0 we've removed the deprecated preset.\n\n#### Preview/Props renamed\n\nIn 6.0 we renamed `Preview` to `Canvas`, `Props` to `ArgsTable`. The change should be otherwise backwards-compatible.\n\n#### Docs theme separated\n\nIn 6.0, you should theme Storybook Docs with the `docs.theme` parameter.\n\nIn 5.x, the Storybook UI and Storybook Docs were themed using the same theme object. However, in 5.3 we introduced a new API, `addons.setConfig`, which improved UI theming but broke Docs theming. Rather than trying to keep the two unified, we introduced a separate theming mechanism for docs, `docs.theme`. [Read about Docs theming here](https://github.com/storybookjs/storybook/blob/next/addons/docs/docs/theming.md#storybook-theming).\n\n#### DocsPage slots removed\n\nIn SB5.2, we introduced the concept of [DocsPage slots](https://github.com/storybookjs/storybook/blob/0de8575eab73bfd5c5c7ba5fe33e53a49b92db3a/addons/docs/docs/docspage.md#docspage-slots) for customizing the DocsPage.\n\nIn 5.3, we introduced `docs.x` story parameters like `docs.prepareForInline` which get filled in by frameworks and can also be overwritten by users, which is a more natural/convenient way to make global customizations.\n\nWe also introduced [Custom DocsPage](https://github.com/storybookjs/storybook/blob/next/addons/docs/docs/docspage.md#replacing-docspage), which makes it possible to add/remove/update DocBlocks on the page.\n\nThese mechanisms are superior to slots, so we've removed slots in 6.0. For each slot, we provide a migration path here:\n\n| Slot        | Slot function     | Replacement                                  |\n| ----------- | ----------------- | -------------------------------------------- |\n| Title       | `titleSlot`       | Custom DocsPage                              |\n| Subtitle    | `subtitleSlot`    | Custom DocsPage                              |\n| Description | `descriptionSlot` | `docs.extractComponentDescription` parameter |\n| Primary     | `primarySlot`     | Custom DocsPage                              |\n| Props       | `propsSlot`       | `docs.extractProps` parameter                |\n| Stories     | `storiesSlot`     | Custom DocsPage                              |\n\n#### React prop tables with Typescript\n\nProps handling in React has changed in 6.0 and should be much less error-prone. This is not a breaking change per se, but documenting the change here since this is an area that has a lot of issues and we've gone back and forth on it.\n\nStarting in 6.0, we have [zero-config typescript support](#zero-config-typescript). The out-of-box experience should be much better now, since the default configuration is designed to work well with `addon-docs`.\n\nThere are also two typescript handling options that can be set in `.storybook/main.js`. `react-docgen-typescript` (default) and `react-docgen`. This is [discussed in detail in the docs](https://github.com/storybookjs/storybook/blob/next/addons/docs/react/README.md#typescript-props-with-react-docgen).\n\n#### ConfigureJSX true by default in React\n\nIn SB 6.0, the Storybook Docs preset option `configureJSX` is now set to `true` for all React projects. It was previously `false` by default for React only in 5.x). This `configureJSX` option adds `@babel/plugin-transform-react-jsx`, to process the output of the MDX compiler, which should be a safe change for all projects.\n\nIf you need to restore the old JSX handling behavior, you can configure `.storybook/main.js`:\n\n```js\nmodule.exports = {\n  addons: [\n    {\n      name: '@storybook/addon-docs',\n      options: { configureJSX: false },\n    },\n  ],\n};\n```\n\n#### User babelrc disabled by default in MDX\n\nIn SB 6.0, the Storybook Docs no longer applies the user's babelrc by default when processing MDX files. It caused lots of hard-to-diagnose bugs.\n\nTo restore the old behavior, or pass any MDX-specific babel options, you can configure `.storybook/main.js`:\n\n```js\nmodule.exports = {\n  addons: [\n    {\n      name: '@storybook/addon-docs',\n      options: { mdxBabelOptions: { babelrc: true, configFile: true } },\n    },\n  ],\n};\n```\n\n#### Docs description parameter\n\nIn 6.0, you can customize a component description using the `docs.description.component` parameter, and a story description using `docs.description.story` parameter.\n\nExample:\n\n```js\nimport { Button } from './Button';\n\nexport default {\n  title: 'Button'\n  parameters: { docs: { description: { component: 'some component **markdown**' }}}\n}\n\nexport const Basic = () => <Button />\nBasic.parameters = { docs: { description: { story: 'some story **markdown**' }}}\n```\n\nIn 5.3 you customized a story description with the `docs.storyDescription` parameter. This has been deprecated, and support will be removed in 7.0.\n\n#### 6.0 Inline stories\n\nThe following frameworks now render stories inline on the Docs tab by default, rather than in an iframe: `react`, `vue`, `web-components`, `html`.\n\nTo disable inline rendering, set the `docs.stories.inline` parameter to `false`.\n\n### New addon presets\n\nIn Storybook 5.3 we introduced a declarative [main.js configuration](#to-mainjs-configuration), which is now the recommended way to configure Storybook. Part of the change is a simplified syntax for registering addons, which in 6.0 automatically registers many addons _using a preset_, which is a slightly different behavior than in earlier versions.\n\nThis breaking change currently applies to: `addon-a11y`, `addon-actions`, `addon-knobs`, `addon-links`, `addon-queryparams`.\n\nConsider the following `main.js` config for `addon-knobs`:\n\n```js\nmodule.exports = {\n  stories: ['../**/*.stories.js'],\n  addons: ['@storybook/addon-knobs'],\n};\n```\n\nIn earlier versions of Storybook, this would automatically call `@storybook/addon-knobs/register`, which adds the knobs panel to the Storybook UI. As a user you would also add a decorator:\n\n```js\nimport { withKnobs } from '../index';\n\naddDecorator(withKnobs);\n```\n\nNow in 6.0, `addon-knobs` comes with a preset, `@storybook/addon-knobs/preset`, that does this automatically for you. This change simplifies configuration, since now you don't need to add that decorator.\n\nIf you wish to disable this new behavior, you can modify your `main.js` to force it to use the `register` logic rather than the `preset`:\n\n```js\nmodule.exports = {\n  stories: ['../**/*.stories.js'],\n  addons: ['@storybook/addon-knobs/register'],\n};\n```\n\nIf you wish to selectively disable `knobs` checks for a subset of stories, you can control this with story parameters:\n\n```js\nexport const MyNonCheckedStory = () => <SomeComponent />;\nMyNonCheckedStory.story = {\n  parameters: {\n    knobs: { disable: true },\n  },\n};\n```\n\n### Removed babel-preset-vue from Vue preset\n\n`babel-preset-vue` is not included by default anymore when using Storybook with Vue.\nThis preset is outdated and [caused problems](https://github.com/storybookjs/storybook/issues/4475) with more modern setups.\n\nIf you have an older Vue setup that relied on this preset, make sure it is included in your babel config\n(install `babel-preset-vue` and add it to the presets).\n\n```json\n{\n  \"presets\": [\"babel-preset-vue\"]\n}\n```\n\nHowever, please take a moment to review why this preset is necessary in your setup.\nOne usecase used to be to enable JSX in your stories. For this case, we recommend to use `@vue/babel-preset-jsx` instead.\n\n### Removed Deprecated APIs\n\nIn 6.0 we removed a number of APIs that were previously deprecated.\n\nSee the migration guides for further details:\n\n- [Addon a11y uses parameters, decorator renamed](#addon-a11y-uses-parameters-decorator-renamed)\n- [Addon backgrounds uses parameters](#addon-backgrounds-uses-parameters)\n- [Source-loader](#source-loader)\n- [Unified docs preset](#unified-docs-preset)\n- [Addon centered decorator deprecated](#addon-centered-decorator-deprecated)\n\n### New setStories event\n\nThe `setStories`/`SET_STORIES` event has changed and now denormalizes global and kind-level parameters. The new format of the event data is:\n\n```js\n{\n  globalParameters: { p: 'q' },\n  kindParameters: { kind: { p: 'q' } },\n  stories: /* as before but with only story-level parameters */\n}\n```\n\nIf you want the full denormalized parameters for a story, you can do something like:\n\n```js\nimport { combineParameters } from '@storybook/api';\n\nconst story = data.stories[storyId];\nconst parameters = combineParameters(\n  data.globalParameters,\n  data.kindParameters[story.kind],\n  story.parameters\n);\n```\n\n### Removed renderCurrentStory event\n\nThe story store no longer emits `renderCurrentStory`/`RENDER_CURRENT_STORY` to tell the renderer to render the story. Instead it emits a new declarative `CURRENT_STORY_WAS_SET` (in response to the existing `SET_CURRENT_STORY`) which is used to decide to render.\n\n### Removed hierarchy separators\n\nWe've removed the ability to specify the hierarchy separators (how you control the grouping of story kinds in the sidebar). From Storybook 6.0 we have a single separator `/`, which cannot be configured.\n\nIf you are currently using custom separators, we encourage you to migrate to using `/` as the sole separator. If you are using `|` or `.` as a separator currently, we provide a codemod, [`upgrade-hierarchy-separators`](https://github.com/storybookjs/storybook/blob/next/code/lib/codemod/README.md#upgrade-hierarchy-separators), that can be used to rename your components. **Note: the codemod will not work for `.mdx` components, you will need to make the changes by hand.**\n\n```\nnpx sb@latest migrate upgrade-hierarchy-separators --glob=\"*/**/*.stories.@(tsx|jsx|ts|js)\"\n```\n\nWe also now default to showing \"roots\", which are non-expandable groupings in the sidebar for the top-level groups. If you'd like to disable this, set the `showRoots` option in `.storybook/manager.js`:\n\n```js\nimport { addons } from '@storybook/addons';\n\naddons.setConfig({\n  showRoots: false,\n});\n```\n\n### No longer pass denormalized parameters to storySort\n\nThe `storySort` function (set via the `parameters.options.storySort` parameter) previously compared two entries `[storyId, storeItem]`, where `storeItem` included the full \"denormalized\" set of parameters of the story (i.e. the global, kind and story parameters that applied to that story).\n\nFor performance reasons, we now store the parameters uncombined, and so pass the format: `[storyId, storeItem, kindParameters, globalParameters]`.\n\n### Client API changes\n\n#### Removed Legacy Story APIs\n\nIn 6.0 we removed a set of APIs from the underlying `StoryStore` (which wasn't publicly accessible):\n\n- `getStories`, `getStoryFileName`, `getStoryAndParameters`, `getStory`, `getStoryWithContext`, `hasStoryKind`, `hasStory`, `dumpStoryBook`, `size`, `clean`\n\nAlthough these were private APIs, if you were using them, you could probably use the newer APIs (which are still private): `getStoriesForKind`, `getRawStory`, `removeStoryKind`, `remove`.\n\n#### Can no longer add decorators/parameters after stories\n\nYou can no longer add decorators and parameters globally after you added your first story, and you can no longer add decorators and parameters to a kind after you've added your first story to it.\n\nIt's unclear and confusing what would happened if you did. If you want to disable a decorator for certain stories, use a parameter to do so:\n\n```js\nexport StoryOne = ...;\nStoryOne.story = { parameters: { addon: { disable: true } } };\n```\n\nIf you want to use a parameter for a subset of stories in a kind, simply use a variable to do so:\n\n```js\nconst commonParameters = { x: { y: 'z' } };\nexport StoryOne = ...;\nStoryOne.story = { parameters: { ...commonParameters, other: 'things' } };\n```\n\n> NOTE: also the use of `addParameters` and `addDecorator` at arbitrary points is also deprecated, see [the deprecation warning](#deprecated-addparameters-and-adddecorator).\n\n#### Changed Parameter Handling\n\nThere have been a few rationalizations of parameter handling in 6.0 to make things more predictable and fit better with the intention of parameters:\n\n_All parameters are now merged recursively to arbitrary depth._\n\nIn 5.3 we sometimes merged parameters all the way down and sometimes did not depending on where you added them. It was confusing. If you were relying on this behaviour, let us know.\n\n_Array parameters are no longer \"merged\"._\n\nIf you override an array parameter, the override will be the end product. If you want the old behaviour (appending a new value to an array parameter), export the original and use array spread. This will give you maximum flexibility:\n\n```js\nimport { allBackgrounds } from './util/allBackgrounds';\n\nexport StoryOne = ...;\nStoryOne.story = { parameters: { backgrounds: [...allBackgrounds, '#zyx' ] } };\n```\n\n_You cannot set parameters from decorators_\n\nParameters are intended to be statically set at story load time. So setting them via a decorator doesn't quite make sense. If you were using this to control the rendering of a story, chances are using the new `args` feature is a more idiomatic way to do this.\n\n_You can only set storySort globally_\n\nIf you want to change the ordering of stories, use `export const parameters = { options: { storySort: ... } }` in `preview.js`.\n\n### Simplified Render Context\n\nThe `RenderContext` that is passed to framework rendering layers in order to render a story has been simplified, dropping a few members that were not used by frameworks to render stories. In particular, the following have been removed:\n\n- `selectedKind`/`selectedStory` -- replaced by `kind`/`name`\n- `configApi`\n- `storyStore`\n- `channel`\n- `clientApi`\n\n### Story Store immutable outside of configuration\n\nYou can no longer change the contents of the StoryStore outside of a `configure()` call. This is to ensure that any changes are properly published to the manager. If you want to add stories \"out of band\" you can call `store.startConfiguring()` and `store.finishConfiguring()` to ensure that your changes are published.\n\n### Improved story source handling\n\nThe story source code handling has been improved in both `addon-storysource` and `addon-docs`.\n\nIn 5.x some users used an undocumented _internal_ API, `mdxSource` to customize source snippetization in `addon-docs`. This has been removed in 6.0.\n\nThe preferred way to customize source snippets for stories is now:\n\n```js\nexport const Example = () => <Button />;\nExample.story = {\n  parameters: {\n    storySource: {\n      source: 'custom source',\n    },\n  },\n};\n```\n\nThe MDX analog:\n\n```mdx\n<Story name=\"Example\" parameters={{ storySource: { source: 'custom source' } }}>\n  <Button />\n</Story>\n```\n\n### 6.0 Addon API changes\n\n#### Consistent local addon paths in main.js\n\nIf you use `.storybook/main.js` config and have locally-defined addons in your project, you need to update your file paths.\n\nIn 5.3, `addons` paths were relative to the project root, which was inconsistent with `stories` paths, which were relative to the `.storybook` folder. In 6.0, addon paths are now relative to the config folder.\n\nSo, for example, if you had:\n\n```js\nmodule.exports = { addons: ['./.storybook/my-local-addon/register'] };\n```\n\nYou'd need to update this to:\n\n```js\nmodule.exports = { addons: ['./my-local-addon/register'] };\n```\n\n#### Deprecated setAddon\n\nWe've deprecated the `setAddon` method of the `storiesOf` API and plan to remove it in 7.0.\n\nSince early versions, Storybook shipped with a `setAddon` API, which allows you to extend `storiesOf` with arbitrary code. We've removed this from all core addons long ago and recommend writing stories in [Component Story Format](https://medium.com/storybookjs/component-story-format-66f4c32366df) rather than using the internal Storybook API.\n\n#### Deprecated disabled parameter\n\nStarting in 6.0.17, we've renamed the `disabled` parameter to `disable` to resolve an inconsistency where `disabled` had been used to hide the addon panel, whereas `disable` had been used to disable an addon's execution. Since `disable` was much more widespread in the code, we standardized on that.\n\nSo, for example:\n\n```\nStory.parameters = { actions: { disabled: true } }\n```\n\nShould be rewritten as:\n\n```\nStory.parameters = { actions: { disable: true } }\n```\n\n#### Actions addon uses parameters\n\nLeveraging the new preset `@storybook/addon-actions` uses parameters to pass action options. If you previously had:\n\n```js\nimport { withActions } from `@storybook/addon-actions`;\n\nexport StoryOne = ...;\nStoryOne.story = {\n  decorators: [withActions('mouseover', 'click .btn')],\n}\n```\n\nYou should replace it with:\n\n```js\nexport StoryOne = ...;\nStoryOne.story = {\n  parameters: { actions: ['mouseover', 'click .btn'] },\n}\n```\n\n#### Removed action decorator APIs\n\nIn 6.0 we removed the actions addon decorate API. Actions handles can be configured globally, for a collection of stories or per story via parameters. The ability to manipulate the data arguments of an event is only relevant in a few frameworks and is not a common enough usecase to be worth the complexity of supporting.\n\n#### Removed withA11y decorator\n\nIn 6.0 we removed the `withA11y` decorator. The code that runs accessibility checks is now directly injected in the preview.\n\nTo configure a11y now, you have to specify configuration using story parameters, e.g. in `.storybook/preview.js`:\n\n```js\nexport const parameters = {\n  a11y: {\n    element: '#storybook-root',\n    config: {},\n    options: {},\n    manual: true,\n  },\n};\n```\n\n#### Essentials addon disables differently\n\nIn 6.0, `addon-essentials` doesn't configure addons if the user has already configured them in `main.js`. In 5.3 it previously checked to see whether the package had been installed in `package.json` to disable configuration. The new setup is preferably because now users' can install essential packages and import from them without disabling their configuration.\n\n#### Backgrounds addon has a new api\n\nStarting in 6.0, the backgrounds addon now receives an object instead of an array as parameter, with a property to define the default background.\n\nConsider the following example of its usage in `Button.stories.js`:\n\n```jsx\n// Button.stories.js\nexport default {\n  title: 'Button',\n  parameters: {\n    backgrounds: [\n      { name: 'twitter', value: '#00aced', default: true },\n      { name: 'facebook', value: '#3b5998' },\n    ],\n  },\n};\n```\n\nHere's an updated version of the example, using the new api:\n\n```jsx\n// Button.stories.js\nexport default {\n  title: 'Button',\n  parameters: {\n    backgrounds: {\n      default: 'twitter',\n      values: [\n        { name: 'twitter', value: '#00aced' },\n        { name: 'facebook', value: '#3b5998' },\n      ],\n    },\n  },\n};\n```\n\nIn addition, backgrounds now ships with the following defaults:\n\n- no selected background (transparent)\n- light/dark options\n\n### 6.0 Deprecations\n\nWe've deprecated the following in 6.0: `addon-info`, `addon-notes`, `addon-contexts`, `addon-centered`, `polymer`.\n\n#### Deprecated addon-info, addon-notes\n\nThe info/notes addons have been replaced by [addon-docs](https://github.com/storybookjs/storybook/tree/next/addons/docs). We've documented a migration in the [docs recipes](https://github.com/storybookjs/storybook/blob/next/addons/docs/docs/recipes.md#migrating-from-notesinfo-addons).\n\nBoth addons are still widely used, and their source code is still available in the [deprecated-addons repo](https://github.com/storybookjs/deprecated-addons). We're looking for maintainers for both addons. If you're interested, please get in touch on [our Discord](https://discord.gg/storybook).\n\n#### Deprecated addon-contexts\n\nThe contexts addon has been replaced by [addon-toolbars](https://github.com/storybookjs/storybook/blob/next/addons/toolbars), which is simpler, more ergonomic, and compatible with all Storybook frameworks.\n\nThe addon's source code is still available in the [deprecated-addons repo](https://github.com/storybookjs/deprecated-addons). If you're interested in maintaining it, please get in touch on [our Discord](https://discord.gg/storybook).\n\n#### Removed addon-centered\n\nIn 6.0 we removed the centered addon. Centering is now core feature of storybook, so we no longer need an addon.\n\nRemove the addon-centered decorator and instead add a `layout` parameter:\n\n```js\nexport const MyStory = () => <div>my story</div>;\nMyStory.story = {\n  parameters: { layout: 'centered' },\n};\n```\n\nOther possible values are: `padded` (default) and `fullscreen`.\n\n#### Deprecated polymer\n\nWe've deprecated `@storybook/polymer` and are focusing on `@storybook/web-components`. If you use Polymer and are interested in maintaining it, please get in touch on [our Discord](https://discord.gg/storybook).\n\n#### Deprecated immutable options parameters\n\nThe UI options `sidebarAnimations`, `enableShortcuts`, `theme`, `showRoots` should not be changed on a per-story basis, and as such there is no reason to set them via parameters.\n\nYou should use `addon.setConfig` to set them:\n\n```js\n// in .storybook/manager.js\nimport { addons } from '@storybook/addons';\n\naddons.setConfig({\n  showRoots: false,\n});\n```\n\n#### Deprecated addParameters and addDecorator\n\nThe `addParameters` and `addDecorator` APIs to add global decorators and parameters, exported by the various frameworks (e.g. `@storybook/react`) and `@storybook/client` are now deprecated.\n\nInstead, use `export const parameters = {};` and `export const decorators = [];` in your `.storybook/preview.js`. Addon authors similarly should use such an export in a preview entry file (see [Preview entries](https://github.com/storybookjs/storybook/blob/next/docs/addons/writing-presets.md#preview-entries)).\n\n#### Deprecated clearDecorators\n\nSimilarly, `clearDecorators`, exported by the various frameworks (e.g. `@storybook/react`) is deprecated.\n\n#### Deprecated configure\n\nThe `configure` API to load stories from `preview.js`, exported by the various frameworks (e.g. `@storybook/react`) is now deprecated.\n\nTo load stories, use the `stories` field in `main.js`. You can pass a glob or array of globs to load stories like so:\n\n```js\n// in .storybook/main.js\nmodule.exports = {\n  stories: ['../src/**/*.stories.js'],\n};\n```\n\nYou can also pass an array of single file names if you want to be careful about loading files:\n\n```js\n// in .storybook/main.js\nmodule.exports = {\n  stories: [\n    '../src/components/Button.stories.js',\n    '../src/components/Table.stories.js',\n    '../src/components/Page.stories.js',\n  ],\n};\n```\n\n#### Deprecated support for duplicate kinds\n\nIn 6.0 we deprecated the ability to split a kind's (component's) stories into multiple files because it was causing issues in hot module reloading (HMR). It will likely be removed completely in 7.0.\n\nIf you had N stories that contained `export default { title: 'foo/bar' }` (or the MDX equivalent `<Meta title=\"foo/bar\">`), Storybook will now raise the warning `Duplicate title '${kindName}' used in multiple files`.\n\nTo split a component's stories into multiple files, e.g. for the `foo/bar` example above:\n\n- Create a single file with the `export default { title: 'foo/bar' }` export, which is the primary file\n- Comment out or delete the default export from the other files\n- Re-export the stories from the other files in the primary file\n\nSo the primary example might look like:\n\n```js\nexport default { title: 'foo/bar' };\nexport * from './Bar1.stories'\nexport * from './Bar2.stories'\nexport * from './Bar3.stories'\n\nexport const SomeStory = () => ...;\n```\n\n## From version 5.2.x to 5.3.x\n\n### To main.js configuration\n\nIn storybook 5.3 3 new files for configuration were introduced, that replaced some previous files.\n\nThese files are now soft-deprecated, (_they still work, but over time we will promote users to migrate_):\n\n- `presets.js` has been renamed to `main.js`. `main.js` is the main point of configuration for storybook.\n- `config.js` has been renamed to `preview.js`. `preview.js` configures the \"preview\" iframe that renders your components.\n- `addons.js` has been renamed to `manager.js`. `manager.js` configures Storybook's \"manager\" UI that wraps the preview, and also configures addons panel.\n\n#### Using main.js\n\n`main.js` is now the main point of configuration for Storybook. This is what a basic `main.js` looks like:\n\n```js\nmodule.exports = {\n  stories: ['../**/*.stories.js'],\n  addons: ['@storybook/addon-knobs'],\n};\n```\n\nYou remove all \"register\" import from `addons.js` and place them inside the array. You can also safely remove the `/register` suffix from these entries, for a cleaner, more readable configuration. If this means `addons.js` is now empty for you, it's safe to remove.\n\nNext you remove the code that imports/requires all your stories from `config.js`, and change it to a glob-pattern and place that glob in the `stories` array. If this means `config.js` is empty, it's safe to remove.\n\nIf you had a `presets.js` file before you can add the array of presets to the main.js file and remove `presets.js` like so:\n\n```js\nmodule.exports = {\n  stories: ['../**/*.stories.js'],\n  addons: [\n    '@storybook/preset-create-react-app',\n    {\n      name: '@storybook/addon-docs',\n      options: { configureJSX: true },\n    },\n  ],\n};\n```\n\nBy default, adding a package to the `addons` array will first try to load its `preset` entry, then its `register` entry, and finally, it will just assume the package itself is a preset.\n\nIf you want to load a specific package entry, for example you want to use `@storybook/addon-docs/register`, you can also include that in the addons array and Storybook will do the right thing.\n\n#### Using preview.js\n\nIf after migrating the imports/requires of your stories to `main.js` you're left with some code in `config.js` it's likely the usage of `addParameters` & `addDecorator`.\n\nThis is fine, rename `config.js` to `preview.js`.\n\nThis file can also be used to inject global stylesheets, fonts etc, into the preview bundle.\n\n#### Using manager.js\n\nIf you are setting storybook options in `config.js`, especially `theme`, you should migrate it to `manager.js`:\n\n```js\nimport { addons } from '@storybook/addons';\nimport { create } from '@storybook/theming/create';\n\nconst theme = create({\n  base: 'light',\n  brandTitle: 'My custom title',\n});\n\naddons.setConfig({\n  panelPosition: 'bottom',\n  theme,\n});\n```\n\nThis makes storybook load and use the theme in the manager directly.\nThis allows for richer theming in the future, and has a much better performance!\n\n> If you're using addon-docs, you should probably not do this. Docs uses the theme as well, but this change makes the theme inaccessible to addon-docs. We'll address this in 6.0.0.\n\n### Create React App preset\n\nYou can now move to the new preset for [Create React App](https://create-react-app.dev/). The in-built preset for Create React App will be disabled in Storybook 6.0.\n\nSimply install [`@storybook/preset-create-react-app`](https://github.com/storybookjs/presets/tree/master/packages/preset-create-react-app) and it will be used automatically.\n\n### Description doc block\n\nIn 5.3 we've changed `addon-docs`'s `Description` doc block's default behavior. Technically this is a breaking change, but MDX was not officially released in 5.2 and we reserved the right to make small breaking changes. The behavior of `DocsPage`, which was officially released, remains unchanged.\n\nThe old behavior of `<Description of={Component} />` was to concatenate the info parameter or notes parameter, if available, with the docgen information loaded from source comments. If you depend on the old behavior, it's still available with `<Description of={Component} type='legacy-5.2' />`. This description type will be removed in Storybook 6.0.\n\nThe new default behavior is to use the framework-specific description extractor, which for React/Vue is still docgen, but may come from other places (e.g. a JSON file) for other frameworks.\n\nThe description doc block on DocsPage has also been updated. To see how to configure it in 5.3, please see [the updated recipe](https://github.com/storybookjs/storybook/blob/next/addons/docs/docs/recipes.md#migrating-from-notesinfo-addons)\n\n### React Native Async Storage\n\nStarting from version React Native 0.59, Async Storage is deprecated in React Native itself. The new @react-native-async-storage/async-storage module requires native installation, and we don't want to have it as a dependency for React Native Storybook.\n\nTo avoid that now you have to manually pass asyncStorage to React Native Storybook with asyncStorage prop. To notify users we are displaying a warning about it.\n\nSolution:\n\n- Use `require('@react-native-async-storage/async-storage').default` for React Native v0.59 and above.\n- Use `require('react-native').AsyncStorage` for React Native v0.58 or below.\n- Use `null` to disable Async Storage completely.\n\n```javascript\ngetStorybookUI({\n  ...\n  asyncStorage: require('@react-native-async-storage/async-storage').default || require('react-native').AsyncStorage || null\n});\n```\n\nThe benefit of using Async Storage is so that when users refresh the app, Storybook can open their last visited story.\n\n### Deprecate displayName parameter\n\nIn 5.2, the story parameter `displayName` was introduced as a publicly visible (but internal) API. Storybook's Component Story Format (CSF) loader used it to modify a story's display name independent of the story's `name`/`id` (which were coupled).\n\nIn 5.3, the CSF loader decouples the story's `name`/`id`, which means that `displayName` is no longer necessary. Unfortunately, this is a breaking change for any code that uses the story `name` field. Storyshots relies on story `name`, and the appropriate migration is to simply update your snapshots. Apologies for the inconvenience!\n\n### Unified docs preset\n\nAddon-docs configuration gets simpler in 5.3. In 5.2, each framework had its own preset, e.g. `@storybook/addon-docs/react/preset`. Starting in 5.3, everybody should use `@storybook/addon-docs/preset`.\n\n### Simplified hierarchy separators\n\nWe've deprecated the ability to specify the hierarchy separators (how you control the grouping of story kinds in the sidebar). From Storybook 6.0 we will have a single separator `/`, which cannot be configured.\n\nIf you are currently using custom separators, we encourage you to migrate to using `/` as the sole separator. If you are using `|` or `.` as a separator currently, we provide a codemod, [`upgrade-hierarchy-separators`](https://github.com/storybookjs/storybook/blob/next/code/lib/codemod/README.md#upgrade-hierarchy-separators), that can be used to rename all your components.\n\n```\nyarn sb migrate upgrade-hierarchy-separators --glob=\"*.stories.js\"\n```\n\nIf you were using `|` and wish to keep the \"root\" behavior, use the `showRoots: true` option to re-enable roots:\n\n```js\naddParameters({\n  options: {\n    showRoots: true,\n  },\n});\n```\n\nNOTE: it is no longer possible to have some stories with roots and others without. If you want to keep the old behavior, simply add a root called \"Others\" to all your previously unrooted stories.\n\n### Addon StoryShots Puppeteer uses external puppeteer\n\nTo give you more control on the Chrome version used when running StoryShots Puppeteer, `puppeteer` is no more included in the addon dependencies. So you can now pick the version of `puppeteer` you want and set it in your project.\n\nIf you want the latest version available just run:\n\n```sh\nyarn add puppeteer --dev\nOR\nnpm install puppeteer --save-dev\n```\n\n## From version 5.1.x to 5.2.x\n\n### Source-loader\n\nAddon-storysource contains a loader, `@storybook/addon-storysource/loader`, which has been deprecated in 5.2. If you use it, you'll see the warning:\n\n```\n@storybook/addon-storysource/loader is deprecated, please use @storybook/source-loader instead.\n```\n\nTo upgrade to `@storybook/source-loader`, run `npm install -D @storybook/source-loader` (or use `yarn`), and replace every instance of `@storybook/addon-storysource/loader` with `@storybook/source-loader`.\n\n### Default viewports\n\nThe default viewports have been reduced to a smaller set, we think is enough for most use cases.\nYou can get the old default back by adding the following to your `config.js`:\n\n```js\nimport { INITIAL_VIEWPORTS } from '@storybook/addon-viewport';\n\naddParameters({\n  viewport: {\n    viewports: INITIAL_VIEWPORTS,\n  },\n});\n```\n\n### Grid toolbar-feature\n\nThe grid feature in the toolbar has been relocated to [addon-background](https://github.com/storybookjs/storybook/tree/next/addons/backgrounds), follow the setup instructions on that addon to get the feature again.\n\n### Docs mode docgen\n\nThis isn't a breaking change per se, because `addon-docs` is a new feature. However it's intended to replace `addon-info`, so if you're migrating from `addon-info` there are a few things you should know:\n\n1. Support for only one prop table\n2. Prop table docgen info should be stored on the component and not in the global variable `STORYBOOK_REACT_CLASSES` as before.\n\n### storySort option\n\nIn 5.0.x the global option `sortStoriesByKind` option was [inadvertently removed](#sortstoriesbykind). In 5.2 we've introduced a new option, `storySort`, to replace it. `storySort` takes a comparator function, so it is strictly more powerful than `sortStoriesByKind`.\n\nFor example, here's how to sort by story ID using `storySort`:\n\n```js\naddParameters({\n  options: {\n    storySort: (a, b) =>\n      a[1].kind === b[1].kind ? 0 : a[1].id.localeCompare(b[1].id, undefined, { numeric: true }),\n  },\n});\n```\n\n## From version 5.1.x to 5.1.10\n\n### babel.config.js support\n\nSB 5.1.0 added [support for project root `babel.config.js` files](https://github.com/storybookjs/storybook/pull/6634), which was an [unintentional breaking change](https://github.com/storybookjs/storybook/issues/7058#issuecomment-515398228). 5.1.10 fixes this, but if you relied on project root `babel.config.js` support, this bugfix is a breaking change. The workaround is to copy the file into your `.storybook` config directory. We may add back project-level support in 6.0.\n\n## From version 5.0.x to 5.1.x\n\n### React native server\n\nStorybook 5.1 contains a major overhaul of `@storybook/react-native` as compared to 4.1 (we didn't ship a version of RN in 5.0 due to timing constraints). Storybook for RN consists of an UI for browsing stories on-device or in a simulator, and an optional webserver which can also be used to browse stories and web addons.\n\n5.1 refactors both pieces:\n\n- `@storybook/react-native` no longer depends on the Storybook UI and only contains on-device functionality\n- `@storybook/react-native-server` is a new package for those who wish to run a web server alongside their device UI\n\nIn addition, both packages share more code with the rest of Storybook, which will reduce bugs and increase compatibility (e.g. with the latest versions of babel, etc.).\n\nAs a user with an existing 4.1.x RN setup, no migration should be necessary to your RN app. Upgrading the library should be enough.\n\nIf you wish to run the optional web server, you will need to do the following migration:\n\n- Add `babel-loader` as a dev dependency\n- Add `@storybook/react-native-server` as a dev dependency\n- Change your \"storybook\" `package.json` script from `storybook start [-p ...]` to `start-storybook [-p ...]`\n\nAnd with that you should be good to go!\n\n### Angular 7\n\nStorybook 5.1 relies on `core-js@^3.0.0` and therefore causes a conflict with Angular 7 that relies on `core-js@^2.0.0`. In order to get Storybook running on Angular 7 you can either update to Angular 8 (which dropped `core-js` as a dependency) or follow these steps:\n\n- Remove `node_modules/@storybook`\n- `npm i core-js@^3.0.0` / `yarn add core-js@^3.0.0`\n- Add the following paths to your `tsconfig.json`\n\n```json\n{\n  \"compilerOptions\": {\n    \"paths\": {\n      \"core-js/es7/reflect\": [\"node_modules/core-js/proposals/reflect-metadata\"],\n      \"core-js/es6/*\": [\"node_modules/core-js/es\"]\n    }\n  }\n}\n```\n\nYou should now be able to run Storybook and Angular 7 without any errors.\n\nReference issue: [https://github.com/angular/angular-cli/issues/13954](https://github.com/angular/angular-cli/issues/13954)\n\n### CoreJS 3\n\nFollowing the rest of the JS ecosystem, Storybook 5.1 upgrades [CoreJS](https://github.com/zloirock/core-js) 2 to 3, which is a breaking change.\n\nThis upgrade is problematic because many apps/libraries still rely on CoreJS 2, and many users get corejs-related errors due to bad resolution. To address this, we're using [corejs-upgrade-webpack-plugin](https://github.com/ndelangen/corejs-upgrade-webpack-plugin), which attempts to automatically upgrade code to CoreJS 3.\n\nAfter a few iterations, this approach seems to be working. However, there are a few exceptions:\n\n- If your app uses `babel-polyfill`, try to remove it\n\nWe'll update this section as we find more problem cases. If you have a `core-js` problem, please file an issue (preferably with a repro), and we'll do our best to get you sorted.\n\n**Update**: [corejs-upgrade-webpack-plugin](https://github.com/ndelangen/corejs-upgrade-webpack-plugin) has been removed again after running into further issues as described in [https://github.com/storybookjs/storybook/issues/7445](https://github.com/storybookjs/storybook/issues/7445).\n\n## From version 5.0.1 to 5.0.2\n\n### Deprecate webpack extend mode\n\nExporting an object from your custom webpack config puts storybook in \"extend mode\".\n\nThere was a bad bug in `v5.0.0` involving webpack \"extend mode\" that caused webpack issues for users migrating from `4.x`. We've fixed this problem in `v5.0.2` but it means that extend-mode has a different behavior if you're migrating from `5.0.0` or `5.0.1`. In short, `4.x` extended a base config with the custom config, whereas `5.0.0-1` extended the base with a richer config object that could conflict with the custom config in different ways from `4.x`.\n\nWe've also deprecated \"extend mode\" because it doesn't add a lot of value over \"full control mode\", but adds more code paths, documentation, user confusion etc. Starting in SB6.0 we will only support \"full control mode\" customization.\n\nTo migrate from extend-mode to full-control mode, if your extend-mode webpack config looks like this:\n\n```js\nmodule.exports = {\n  module: {\n    rules: [\n      /* ... */\n    ],\n  },\n};\n```\n\nIn full control mode, you need modify the default config to have the rules of your liking:\n\n```js\nmodule.exports = ({ config }) => ({\n  ...config,\n  module: {\n    ...config.module,\n    rules: [\n      /* your own rules \"...\" here and/or some subset of config.module.rules */\n    ],\n  },\n});\n```\n\nPlease refer to the [current custom webpack documentation](https://storybook.js.org/docs/react/configure/webpack) for more information on custom webpack config and to [Issue #6081](https://github.com/storybookjs/storybook/issues/6081) for more information about the change.\n\n## From version 4.1.x to 5.0.x\n\nStorybook 5.0 includes sweeping UI changes as well as changes to the addon API and custom webpack configuration. We've tried to keep backwards compatibility in most cases, but there are some notable exceptions documented below.\n\n### sortStoriesByKind\n\nIn Storybook 5.0 we changed a lot of UI related code, and 1 oversight caused the `sortStoriesByKind` options to stop working.\nWe're working on providing a better way of sorting stories for now the feature has been removed. Stories appear in the order they are loaded.\n\nIf you're using webpack's `require.context` to load stories, you can sort the execution of requires:\n\n```js\nvar context = require.context('../stories', true, /\\.stories\\.js$/);\nvar modules = context.keys();\n\n// sort them\nvar sortedModules = modules.slice().sort((a, b) => {\n  // sort the stories based on filename/path\n  return a < b ? -1 : a > b ? 1 : 0;\n});\n\n// execute them\nsortedModules.forEach((key) => {\n  context(key);\n});\n```\n\n### Webpack config simplification\n\nThe API for custom webpack configuration has been simplified in 5.0, but it's a breaking change. Storybook's \"full control mode\" for webpack allows you to override the webpack config with a function that returns a configuration object.\n\nIn Storybook 5 there is a single signature for full-control mode that takes a parameters object with the fields `config` and `mode`:\n\n```js\nmodule.exports = ({ config, mode }) => { config.module.rules.push(...); return config; }\n```\n\nIn contrast, the 4.x configuration function accepted either two or three arguments (`(baseConfig, mode)`, or `(baseConfig, mode, defaultConfig)`). The `config` object in the 5.x signature is equivalent to 4.x's `defaultConfig`.\n\nPlease see the [current custom webpack documentation](https://storybook.js.org/docs/react/configure/webpack) for more information on custom webpack config.\n\n### Theming overhaul\n\nTheming has been rewritten in v5. If you used theming in v4, please consult the [theming docs](https://storybook.js.org/docs/react/configure/theming) to learn about the new API.\n\n### Story hierarchy defaults\n\nStorybook's UI contains a hierarchical tree of stories that can be configured by `hierarchySeparator` and `hierarchyRootSeparator` [options](https://github.com/storybookjs/deprecated-addons/blob/master/MIGRATION.md#options-addon-deprecated).\n\nIn Storybook 4.x the values defaulted to `null` for both of these options, so that there would be no hierarchy by default.\n\nIn 5.0, we now provide recommended defaults:\n\n```js\n{\n  hierarchyRootSeparator: '|',\n  hierarchySeparator: /\\/|\\./,\n}\n```\n\nThis means if you use the characters { `|`, `/`, `.` } in your story kinds it will trigger the story hierarchy to appear. For example `storiesOf('UI|Widgets/Basics/Button')` will create a story root called `UI` containing a `Widgets/Basics` group, containing a `Button` component.\n\nIf you wish to opt-out of this new behavior and restore the flat UI, set them back to `null` in your storybook config, or remove { `|`, `/`, `.` } from your story kinds:\n\n```js\naddParameters({\n  options: {\n    hierarchyRootSeparator: null,\n    hierarchySeparator: null,\n  },\n});\n```\n\n### Options addon deprecated\n\nIn 4.x we added story parameters. In 5.x we've deprecated the options addon in favor of [global parameters](https://storybook.js.org/docs/react/configure/features-and-behavior), and we've also renamed some of the options in the process (though we're maintaining backwards compatibility until 6.0).\n\nHere's an old configuration:\n\n```js\naddDecorator(\n  withOptions({\n    name: 'Storybook',\n    url: 'https://storybook.js.org',\n    goFullScreen: false,\n    addonPanelInRight: true,\n  })\n);\n```\n\nAnd here's its new counterpart:\n\n```js\nimport { create } from '@storybook/theming/create';\n\naddParameters({\n  options: {\n    theme: create({\n      base: 'light',\n      brandTitle: 'Storybook',\n      brandUrl: 'https://storybook.js.org',\n      // To control appearance:\n      // brandImage: 'http://url.of/some.svg',\n    }),\n    isFullscreen: false,\n    panelPosition: 'right',\n    isToolshown: true,\n  },\n});\n```\n\nHere is the mapping from old options to new:\n\n| Old               | New              |\n| ----------------- | ---------------- |\n| name              | theme.brandTitle |\n| url               | theme.brandUrl   |\n| goFullScreen      | isFullscreen     |\n| showStoriesPanel  | showNav          |\n| showAddonPanel    | showPanel        |\n| addonPanelInRight | panelPosition    |\n| showSearchBox     |                  |\n|                   | isToolshown      |\n\nStorybook v5 removes the search dialog box in favor of a quick search in the navigation view, so `showSearchBox` has been removed.\n\nStorybook v5 introduce a new tool bar above the story view and you can show\\hide it with the new `isToolshown` option.\n\n### Individual story decorators\n\nThe behavior of adding decorators to a kind has changed in SB5 ([#5781](https://github.com/storybookjs/storybook/issues/5781)).\n\nIn SB4 it was possible to add decorators to only a subset of the stories of a kind.\n\n```js\nstoriesOf('Stories', module)\n  .add('noncentered', () => 'Hello')\n  .addDecorator(centered)\n  .add('centered', () => 'Hello');\n```\n\nThe semantics has changed in SB5 so that calling `addDecorator` on a kind adds a decorator to all its stories, no matter the order. So in the previous example, both stories would be centered.\n\nTo allow for a subset of the stories in a kind to be decorated, we've added the ability to add decorators to individual stories using parameters:\n\n```js\nstoriesOf('Stories', module)\n  .add('noncentered', () => 'Hello')\n  .add('centered', () => 'Hello', { decorators: [centered] });\n```\n\n### Addon backgrounds uses parameters\n\nSimilarly, `@storybook/addon-backgrounds` uses parameters to pass background options. If you previously had:\n\n```js\nimport { withBackgrounds } from `@storybook/addon-backgrounds`;\n\nstoriesOf('Stories', module)\n  .addDecorator(withBackgrounds(options));\n```\n\nYou should replace it with:\n\n```js\nstoriesOf('Stories', module).addParameters({ backgrounds: options });\n```\n\nYou can pass `backgrounds` parameters at the global level (via `addParameters` imported from `@storybook/react` et al.), and the story level (via the third argument to `.add()`).\n\n### Addon cssresources name attribute renamed\n\nIn the options object for `@storybook/addon-cssresources`, the `name` attribute for each resource has been renamed to `id`. If you previously had:\n\n```js\nimport { addDecorator } from '@storybook/react';\nimport { withCssResources } from '@storybook/addon-cssresources';\n\naddDecorator(\n  withCssResources({\n    cssresources: [\n      {\n        name: `bluetheme`, // Previous\n        code: `<style>body { background-color: lightblue; }</style>`,\n        picked: false,\n      },\n    ],\n  })\n);\n```\n\nYou should replace it with:\n\n```js\nimport { addDecorator } from '@storybook/react';\nimport { withCssResources } from '@storybook/addon-cssresources';\n\naddDecorator(\n  withCssResources({\n    cssresources: [\n      {\n        id: `bluetheme`, // Renamed\n        code: `<style>body { background-color: lightblue; }</style>`,\n        picked: false,\n      },\n    ],\n  })\n);\n```\n\n### Addon viewport uses parameters\n\nSimilarly, `@storybook/addon-viewport` uses parameters to pass viewport options. If you previously had:\n\n```js\nimport { configureViewport } from `@storybook/addon-viewport`;\n\nconfigureViewport(options);\n```\n\nYou should replace it with:\n\n```js\nimport { addParameters } from '@storybook/react';\n\n// or others\n\naddParameters({ viewport: options });\n```\n\nThe `withViewport` decorator is also no longer supported and should be replaced with a parameter based API as above. Also the `onViewportChange` callback is no longer supported.\n\nSee the [viewport addon README](https://github.com/storybookjs/storybook/blob/master/addons/viewport/README.md) for more information.\n\n### Addon a11y uses parameters, decorator renamed\n\nSimilarly, `@storybook/addon-a11y` uses parameters to pass a11y options. If you previously had:\n\n```js\nimport { configureA11y } from `@storybook/addon-a11y`;\n\nconfigureA11y(options);\n```\n\nYou should replace it with:\n\n```js\nimport { addParameters } from '@storybook/react';\n\n// or others\n\naddParameters({ a11y: options });\n```\n\nYou can also pass `a11y` parameters at the component level (via `storiesOf(...).addParameters`), and the story level (via the third argument to `.add()`).\n\nFurthermore, the decorator `checkA11y` has been deprecated and renamed to `withA11y` to make it consistent with other Storybook decorators.\n\nSee the [a11y addon README](https://github.com/storybookjs/storybook/blob/master/addons/a11y/README.md) for more information.\n\n### Addon centered decorator deprecated\n\nIf you previously had:\n\n```js\nimport centered from '@storybook/addon-centered';\n```\n\nYou should replace it with the React or Vue version as appropriate\n\n```js\nimport centered from '@storybook/addon-centered/react';\n```\n\nor\n\n```js\nimport centered from '@storybook/addon-centered/vue';\n```\n\n### New keyboard shortcuts defaults\n\nStorybook's keyboard shortcuts are updated in 5.0, but they are configurable via the menu so if you want to set them back you can:\n\n| Shortcut               | Old         | New   |\n| ---------------------- | ----------- | ----- |\n| Toggle sidebar         | cmd-shift-X | S     |\n| Toggle addons panel    | cmd-shift-Z | A     |\n| Toggle addons position | cmd-shift-G | D     |\n| Toggle fullscreen      | cmd-shift-F | F     |\n| Next story             | cmd-shift-→ | alt-→ |\n| Prev story             | cmd-shift-← | alt-← |\n| Next component         |             | alt-↓ |\n| Prev component         |             | alt-↑ |\n| Search                 |             | /     |\n\n### New URL structure\n\nWe've update Storybook's URL structure in 5.0. The old structure used URL parameters to save the UI state, resulting in long ugly URLs. v5 respects the old URL parameters, but largely does away with them.\n\nThe old structure encoded `selectedKind` and `selectedStory` among other parameters. Storybook v5 respects these parameters but will issue a deprecation message in the browser console warning of potential future removal.\n\nThe new URL structure looks like:\n\n```\nhttps://url-of-storybook?path=/story/<storyId>\n```\n\nThe structure of `storyId` is a slugified `<selectedKind>--<selectedStory>` (slugified = lowercase, hyphen-separated). Each `storyId` must be unique. We plan to build more features into Storybook in upcoming versions based on this new structure.\n\n### Rename of the `--secure` cli parameter to `--https`\n\nStorybook for React Native's start commands & the Web versions' start command were a bit different, for no reason.\nWe've changed the start command for Reactnative to match the other.\n\nThis means that when you previously used the `--secure` flag like so:\n\n```sh\nstart-storybook --secure\n# or\nstart-storybook --s\n```\n\nYou have to replace it with:\n\n```sh\nstart-storybook --https\n```\n\n### Vue integration\n\nThe Vue integration was updated, so that every story returned from a story or decorator function is now being normalized with `Vue.extend` **and** is being wrapped by a functional component. Returning a string from a story or decorator function is still supported and is treated as a component with the returned string as the template.\n\nCurrently there is no recommended way of accessing the component options of a story inside a decorator.\n\n## From version 4.0.x to 4.1.x\n\nThere are a few migrations you should be aware of in 4.1, including one unintentionally breaking change for advanced addon usage.\n\n### Private addon config\n\nIf your Storybook contains custom addons defined that are defined in your app (as opposed to installed from packages) and those addons rely on reconfiguring webpack/babel, Storybook 4.1 may break for you. There's a workaround [described in the issue](https://github.com/storybookjs/storybook/issues/4995), and we're working on official support in the next release.\n\n### React 15.x\n\nStorybook 4.1 supports React 15.x (which had been [lost in the 4.0 release](#react-163)). So if you've been blocked on upgrading, we've got you covered. You should be able to upgrade according to the 4.0 migration notes below, or following the [4.0 upgrade guide](https://medium.com/storybookjs/migrating-to-storybook-4-c65b19a03d2c).\n\n## From version 3.4.x to 4.0.x\n\nWith 4.0 as our first major release in over a year, we've collected a lot of cleanup tasks. Most of the deprecations have been marked for months, so we hope that there will be no significant impact on your project. We've also created a [step-by-step guide to help you upgrade](https://medium.com/storybookjs/migrating-to-storybook-4-c65b19a03d2c).\n\n### React 16.3+\n\nStorybook uses [Emotion](https://emotion.sh/) for styling which currently requires React 16.3 and above.\n\nIf you're using Storybook for anything other than React, you probably don't need to worry about this.\n\nHowever, if you're developing React components, this means you need to upgrade to 16.3 or higher to use Storybook 4.0.\n\n> **NOTE:** This is a temporary requirement, and we plan to restore 15.x compatibility in a near-term 4.x release.\n\nAlso, here's the error you'll get if you're running an older version of React:\n\n```\n\ncore.browser.esm.js:15 Uncaught TypeError: Object(...) is not a function\nat Module../node_modules/@emotion/core/core.browser.esm.js (core.browser.esm.js:15)\nat **webpack_require** (bootstrap:724)\nat fn (bootstrap:101)\nat Module../node_modules/@emotion/styled-base/dist/styled-base.browser.esm.js (styled-base.browser.esm.js:1)\nat **webpack_require** (bootstrap:724)\nat fn (bootstrap:101)\nat Module../node_modules/@emotion/styled/dist/styled.esm.js (styled.esm.js:1)\nat **webpack_require** (bootstrap:724)\nat fn (bootstrap:101)\nat Object../node_modules/@storybook/components/dist/navigation/MenuLink.js (MenuLink.js:12)\n\n```\n\n### Generic addons\n\n4.x introduces generic addon decorators that are not tied to specific view layers [#3555](https://github.com/storybookjs/storybook/pull/3555). So for example:\n\n```js\nimport { number } from '@storybook/addon-knobs/react';\n```\n\nBecomes:\n\n```js\nimport { number } from '@storybook/addon-knobs';\n```\n\n### Knobs select ordering\n\n4.0 also reversed the order of addon-knob's `select` knob keys/values, which had been called `selectV2` prior to this breaking change. See the knobs [package README](https://github.com/storybookjs/storybook/blob/master/addons/knobs/README.md#select) for usage.\n\n### Knobs URL parameters\n\nAddon-knobs no longer updates the URL parameters interactively as you edit a knob. This is a UI change but it shouldn't break any code because old URLs are still supported.\n\nIn 3.x, editing knobs updated the URL parameters interactively. The implementation had performance and architectural problems. So in 4.0, we changed this to a \"copy\" button in the addon which generates a URL with the updated knob values and copies it to the clipboard.\n\n### Keyboard shortcuts moved\n\n- Addon Panel to `Z`\n- Stories Panel to `X`\n- Show Search to `O`\n- Addon Panel right side to `G`\n\n### Removed addWithInfo\n\n`Addon-info`'s `addWithInfo` has been marked deprecated since 3.2. In 4.0 we've removed it completely. See the package [README](https://github.com/storybookjs/storybook/blob/master/addons/info/README.md) for the proper usage.\n\n### Removed RN packager\n\nSince storybook version v4.0 packager is removed from storybook. The suggested storybook usage is to include it inside your app.\nIf you want to keep the old behaviour, you have to start the packager yourself with a different project root.\n`npm run storybook start -p 7007 | react-native start --projectRoot storybook`\n\nRemoved cli options: `--packager-port --root --projectRoots -r, --reset-cache --skip-packager --haul --platform --metro-config`\n\n### Removed RN addons\n\nThe `@storybook/react-native` had built-in addons (`addon-actions` and `addon-links`) that have been marked as deprecated since 3.x. They have been fully removed in 4.x. If your project still uses the built-ins, you'll need to add explicit dependencies on `@storybook/addon-actions` and/or `@storybook/addon-links` and import directly from those packages.\n\n### Storyshots Changes\n\n1. `imageSnapshot` test function was extracted from `addon-storyshots`\n   and moved to a new package - `addon-storyshots-puppeteer` that now will\n   be dependent on puppeteer. [README](https://github.com/storybookjs/storybook/tree/master/addons/storyshots/storyshots-puppeteer)\n2. `getSnapshotFileName` export was replaced with the `Stories2SnapsConverter`\n   class that now can be overridden for a custom implementation of the\n   snapshot-name generation. [README](https://github.com/storybookjs/storybook/tree/master/addons/storyshots/storyshots-core#stories2snapsconverter)\n3. Storybook that was configured with Webpack's `require.context()` feature\n   will need to add a babel plugin to polyfill this functionality.\n   A possible plugin might be [babel-plugin-require-context-hook](https://github.com/smrq/babel-plugin-require-context-hook).\n   [README](https://github.com/storybookjs/storybook/tree/master/addons/storyshots/storyshots-core#configure-jest-to-work-with-webpacks-requirecontext)\n\n### Webpack 4\n\nStorybook now uses webpack 4. If you have a [custom webpack config](https://storybook.js.org/docs/react/configure/webpack), make sure that all the loaders and plugins you use support webpack 4.\n\n### Babel 7\n\nStorybook now uses Babel 7. There's a couple of cases when it can break with your app:\n\n- If you aren't using Babel yourself, and don't have .babelrc, install following dependencies:\n\n  ```\n  npm i -D @babel/core babel-loader@latest\n  ```\n\n- If you're using Babel 6, make sure that you have direct dependencies on `babel-core@6` and `babel-loader@7` and that you have a `.babelrc` in your project directory.\n\n### Create-react-app\n\nIf you are using `create-react-app` (aka CRA), you may need to do some manual steps to upgrade, depending on the setup.\n\n- `create-react-app@1` may require manual migrations.\n  - If you're adding storybook for the first time: `sb init` should add the correct dependencies.\n  - If you're upgrading an existing project, your `package.json` probably already uses Babel 6, making it incompatible with `@storybook/react@4` which uses Babel 7. There are two ways to make it compatible, each of which is spelled out in detail in the next section:\n    - Upgrade to Babel 7 if you are not dependent on Babel 6-specific features.\n    - Migrate Babel 6 if you're heavily dependent on some Babel 6-specific features).\n- `create-react-app@2` should be compatible as is, since it uses babel 7.\n\n#### Upgrade CRA1 to babel 7\n\n```\nyarn remove babel-core babel-runtime\nyarn add @babel/core babel-loader --dev\n```\n\n#### Migrate CRA1 while keeping babel 6\n\n```\nyarn add babel-loader@7\n```\n\nAlso, make sure you have a `.babelrc` in your project directory. You probably already do if you are using Babel 6 features (otherwise you should consider upgrading to Babel 7 instead). If you don't have one, here's one that works:\n\n```json\n{\n  \"presets\": [\"env\", \"react\"]\n}\n```\n\n### start-storybook opens browser\n\nIf you're using `start-storybook` on CI, you may need to opt out of this using the new `--ci` flag.\n\n### CLI Rename\n\nWe've deprecated the `getstorybook` CLI in 4.0. The new way to install storybook is `sb init`. We recommend using `npx` for convenience and to make sure you're always using the latest version of the CLI:\n\n```\nnpx -p @storybook/cli sb init\n```\n\n### Addon story parameters\n\nStorybook 4 introduces story parameters, a more convenient way to configure how addons are configured.\n\n```js\nstoriesOf('My component', module)\n  .add('story1', withNotes('some notes')(() => <Component ... />))\n  .add('story2', withNotes('other notes')(() => <Component ... />));\n```\n\nBecomes:\n\n```js\n// config.js\naddDecorator(withNotes);\n\n// Component.stories.js\nstoriesOf('My component', module)\n  .add('story1', () => <Component ... />, { notes: 'some notes' })\n  .add('story2', () => <Component ... />, { notes: 'other notes' });\n```\n\nThis example applies notes globally to all stories. You can apply it locally with `storiesOf(...).addDecorator(withNotes)`.\n\nThe story parameters correspond directly to the old withX arguments, so it's less demanding to migrate your code. See the parameters documentation for the packages that have been upgraded:\n\n- [Notes](https://github.com/storybookjs/storybook/blob/master/addons/notes/README.md)\n- [Jest](https://github.com/storybookjs/storybook/blob/master/addons/jest/README.md)\n- [Knobs](https://github.com/storybookjs/storybook/blob/master/addons/knobs/README.md)\n- [Viewport](https://github.com/storybookjs/storybook/blob/master/addons/viewport/README.md)\n- [Backgrounds](https://github.com/storybookjs/storybook/blob/master/addons/backgrounds/README.md)\n- [Options](https://github.com/storybookjs/storybook/blob/master/addons/options/README.md)\n\n## From version 3.3.x to 3.4.x\n\nThere are no expected breaking changes in the 3.4.x release, but 3.4 contains a major refactor to make it easier to support new frameworks, and we will document any breaking changes here if they arise.\n\n## From version 3.2.x to 3.3.x\n\nIt wasn't expected that there would be any breaking changes in this release, but unfortunately it turned out that there are some. We're revisiting our [release strategy](https://github.com/storybookjs/storybook/blob/master/RELEASES.md) to follow semver more strictly.\nAlso read on if you're using `addon-knobs`: we advise an update to your code for efficiency's sake.\n\n### `babel-core` is now a peer dependency #2494\n\nThis affects you if you don't use babel in your project. You may need to add `babel-core` as dev dependency:\n\n```sh\nyarn add babel-core --dev\n```\n\nThis was done to support different major versions of babel.\n\n### Base webpack config now contains vital plugins #1775\n\nThis affects you if you use custom webpack config in [Full Control Mode](https://storybook.js.org/docs/react/configure/webpack#full-control-mode) while not preserving the plugins from `storybookBaseConfig`. Before `3.3`, preserving them was a recommendation, but now it [became](https://github.com/storybookjs/storybook/pull/2578) a requirement.\n\n### Refactored Knobs\n\nKnobs users: there was a bug in 3.2.x where using the knobs addon imported all framework runtimes (e.g. React and Vue). To fix the problem, we [refactored knobs](https://github.com/storybookjs/storybook/pull/1832). Switching to the new style is only takes one line of code.\n\nIn the case of React or React-Native, import knobs like this:\n\n```js\nimport { withKnobs, text, boolean, number } from '@storybook/addon-knobs/react';\n```\n\nIn the case of Vue: `import { ... } from '@storybook/addon-knobs/vue';`\n\nIn the case of Angular: `import { ... } from '@storybook/addon-knobs/angular';`\n\n## From version 3.1.x to 3.2.x\n\n**NOTE:** technically this is a breaking change, but only if you use TypeScript. Sorry people!\n\n### Moved TypeScript addons definitions\n\nTypeScript users: we've moved the rest of our addons type definitions into [DefinitelyTyped](http://definitelytyped.org/). Starting in 3.2.0 make sure to use the right addons types:\n\n```sh\nyarn add @types/storybook__addon-notes @types/storybook__addon-options @types/storybook__addon-knobs @types/storybook__addon-links --dev\n```\n\nSee also [TypeScript definitions in 3.1.x](#moved-typescript-definitions).\n\n### Updated Addons API\n\nWe're in the process of upgrading our addons APIs. As a first step, we've upgraded the Info and Notes addons. The old API will still work with your existing projects but will be deprecated soon and removed in Storybook 4.0.\n\nHere's an example of using Notes and Info in 3.2 with the new API.\n\n```js\nstoriesOf('composition', module).add(\n  'new addons api',\n  withInfo('see Notes panel for composition info')(\n    withNotes({ text: 'Composition: Info(Notes())' })((context) => (\n      <MyComponent name={context.story} />\n    ))\n  )\n);\n```\n\nIt's not beautiful, but we'll be adding a more convenient/idiomatic way of using these [withX primitives](https://gist.github.com/shilman/792dc25550daa9c2bf37238f4ef7a398) in Storybook 3.3.\n\n## From version 3.0.x to 3.1.x\n\n**NOTE:** technically this is a breaking change and should be a 4.0.0 release according to semver. However, we're still figuring things out and didn't think this change necessitated a major release. Please bear with us!\n\n### Moved TypeScript definitions\n\nTypeScript users: we are in the process of moving our typescript definitions into [DefinitelyTyped](http://definitelytyped.org/). If you're using TypeScript, starting in 3.1.0 you need to make sure your type definitions are installed:\n\n```sh\nyarn add @types/node @types/react @types/storybook__react --dev\n```\n\n### Deprecated head.html\n\nWe have deprecated the use of `head.html` for including scripts/styles/etc. into stories, though it will still work with a warning.\n\nNow we use:\n\n- `preview-head.html` for including extra content into the preview pane.\n- `manager-head.html` for including extra content into the manager window.\n\n[Read our docs](https://storybook.js.org/docs/react/configure/story-rendering#adding-to-head) for more details.\n\n## From version 2.x.x to 3.x.x\n\nThis major release is mainly an internal restructuring.\nUpgrading requires work on behalf of users, this was unavoidable.\nWe're sorry if this inconveniences you, we have tried via this document and provided tools to make the process as easy as possible.\n\n### Webpack upgrade\n\nStorybook will now use webpack 2 (and only webpack 2).\nIf you are using a custom `webpack.config.js` you need to change this to be compatible.\nYou can find the guide to upgrading your webpack config [on webpack.js.org](https://webpack.js.org/guides/migrating/).\n\n### Packages renaming\n\nAll our packages have been renamed and published to npm as version 3.0.0 under the `@storybook` namespace.\n\nTo update your app to use the new package names, you can use the cli:\n\n```bash\nnpx -p @storybook/cli sb init\n```\n\n**Details**\n\nIf the above doesn't work, or you want to make the changes manually, the details are below:\n\n> We have adopted the same versioning strategy that has been adopted by babel, jest and apollo.\n> It's a strategy best suited for ecosystem type tools, which consist of many separately installable features / packages.\n> We think this describes storybook pretty well.\n\nThe new package names are:\n\n| old                                          | new                              |\n| -------------------------------------------- | -------------------------------- |\n| `getstorybook`                               | `@storybook/cli`                 |\n| `@kadira/getstorybook`                       | `@storybook/cli`                 |\n|                                              |                                  |\n| `@kadira/storybook`                          | `@storybook/react`               |\n| `@kadira/react-storybook`                    | `@storybook/react`               |\n| `@kadira/react-native-storybook`             | `@storybook/react-native`        |\n|                                              |                                  |\n| `storyshots`                                 | `@storybook/addon-storyshots`    |\n| `@kadira/storyshots`                         | `@storybook/addon-storyshots`    |\n|                                              |                                  |\n| `@kadira/storybook-ui`                       | `@storybook/ui`                  |\n| `@kadira/storybook-addons`                   | `@storybook/addons`              |\n| `@kadira/storybook-channels`                 | `@storybook/channels`            |\n| `@kadira/storybook-channel-postmsg`          | `@storybook/channel-postmessage` |\n| `@kadira/storybook-channel-websocket`        | `@storybook/channel-websocket`   |\n|                                              |                                  |\n| `@kadira/storybook-addon-actions`            | `@storybook/addon-actions`       |\n| `@kadira/storybook-addon-links`              | `@storybook/addon-links`         |\n| `@kadira/storybook-addon-info`               | `@storybook/addon-info`          |\n| `@kadira/storybook-addon-knobs`              | `@storybook/addon-knobs`         |\n| `@kadira/storybook-addon-notes`              | `@storybook/addon-notes`         |\n| `@kadira/storybook-addon-options`            | `@storybook/addon-options`       |\n| `@kadira/storybook-addon-graphql`            | `@storybook/addon-graphql`       |\n| `@kadira/react-storybook-decorator-centered` | `@storybook/addon-centered`      |\n\nIf your codebase is small, it's probably doable to replace them by hand (in your codebase and in `package.json`).\n\nBut if you have a lot of occurrences in your codebase, you can use a [codemod we created](./code/lib/codemod) for you.\n\n> A codemod makes automatic changed to your app's code.\n\nYou have to change your `package.json`, prune old and install new dependencies by hand.\n\n`npm prune` will remove all dependencies from `node_modules` which are no longer referenced in `package.json`.\n\n### Deprecated embedded addons\n\nWe used to ship 2 addons with every single installation of storybook: `actions` and `links`. But in practice not everyone is using them, so we decided to deprecate this and in the future, they will be completely removed. If you use `@storybook/react/addons` you will get a deprecation warning.\n\nIf you **are** using these addons, it takes two steps to migrate:\n\n- add the addons you use to your `package.json`.\n- update your code:\n  change `addons.js` like so:\n\n  ```js\n  import '@storybook/addon-actions/register';\n  import '@storybook/addon-links/register';\n  ```\n\n  change `x.story.js` like so:\n\n  ```js\n  import React from 'react';\n  import { storiesOf } from '@storybook/react';\n  import { action } from '@storybook/addon-actions';\n  import { linkTo } from '@storybook/addon-links';\n  ```\n\n  <!-- markdown-link-check-enable -->\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://storybook.js.org/?ref=readme\">\n    <picture>\n      <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://user-images.githubusercontent.com/263385/199832481-bbbf5961-6a26-481d-8224-51258cce9b33.png\">\n      <img src=\"https://user-images.githubusercontent.com/321738/63501763-88dbf600-c4cc-11e9-96cd-94adadc2fd72.png\" alt=\"Storybook\" width=\"400\" />\n    </picture>\n    \n  </a>\n  \n</p>\n\n<p align=\"center\">Build bulletproof UI components faster</p>\n\n<br/>\n\n<p align=\"center\">\n  <a href=\"https://circleci.com/gh/storybookjs/storybook\">\n    <img src=\"https://circleci.com/gh/storybookjs/storybook.svg?style=shield\" alt=\"Build Status on CircleCI\" />\n  </a>\n  <a href=\"https://codecov.io/gh/storybookjs/storybook\">\n    <img src=\"https://codecov.io/gh/storybookjs/storybook/branch/main/graph/badge.svg\" alt=\"codecov\" />\n  </a>\n  <a href=\"https://github.com/storybookjs/storybook/blob/main/LICENSE\">\n    <img src=\"https://img.shields.io/github/license/storybookjs/storybook.svg\" alt=\"License\" />\n  </a>\n  <br/>\n  <a href=\"https://discord.gg/storybook\">\n    <img src=\"https://img.shields.io/badge/discord-join-7289DA.svg?logo=discord&longCache=true&style=flat\" />\n  </a>\n  <a href=\"https://storybook.js.org/community/?ref=readme\">\n    <img src=\"https://img.shields.io/badge/community-join-4BC424.svg\" alt=\"Storybook Community\" />\n  </a>\n  <a href=\"#backers\">\n    <img src=\"https://opencollective.com/storybook/backers/badge.svg\" alt=\"Backers on Open Collective\" />\n  </a>\n  <a href=\"#sponsors\">\n    <img src=\"https://opencollective.com/storybook/tiers/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" />\n  </a>\n  <a href=\"https://x.com/intent/follow?screen_name=storybookjs\">\n    <img src=\"https://img.shields.io/twitter/follow/storybookjs?color=blue&logo=twitter\" alt=\"Official Twitter Handle\" />\n  </a>\n  <a href=\"https://api.securityscorecards.dev/projects/github.com/storybookjs/storybook\">\n    <img src=\"https://api.securityscorecards.dev/projects/github.com/storybookjs/storybook/badge\" alt=\"OpenSSF Scorecard\"/>\n  </a>\n</p>\n\n<p align=\"center\">\nStorybook is a frontend workshop for building UI components and pages in isolation. Thousands of teams use it for UI development, testing, and documentation. Find out more at <a href=\"https://storybook.js.org/?ref=readme\">storybook.js.org</a>!\n</p>\n\n<center>\n  <img src=\"https://raw.githubusercontent.com/storybookjs/storybook/refs/heads/release-6-5/media/storybook-intro.gif\" width=\"100%\" />\n</center>\n\n<p align=\"center\">\n  View README for:<br/>\n  <a href=\"https://github.com/storybookjs/storybook/blob/main/README.md\" title=\"latest\"><img alt=\"latest\" src=\"https://img.shields.io/npm/v/@storybook/react/latest?style=for-the-badge&logo=storybook&logoColor=ffffff&color=66BF3C\" /></a>\n  <a href=\"https://github.com/storybookjs/storybook/blob/next/README.md\" title=\"next\"><img alt=\"next\" src=\"https://img.shields.io/npm/v/@storybook/react/next?style=for-the-badge&logo=storybook&logoColor=ffffff&color=1EA7FD\" /></a>\n</p>\n\n## Table of contents\n\n- 🚀 [Getting Started](#getting-started)\n- 📒 [Projects](#projects)\n  - 🛠 [Supported Frameworks & Examples](#supported-frameworks)\n  - 🔗[Addons](#addons)\n- 🏅 [Badges & Presentation materials](#badges--presentation-materials)\n- 👥 [Community](#community)\n- 👏 [Contributing](#contributing)\n  - 👨‍💻 [Development scripts](#development-scripts)\n  - 💸 [Sponsors](#sponsors)\n  - 💵 [Backers](#backers)\n- :memo: [License](#license)\n\n## Getting Started\n\nVisit [Storybook's website](https://storybook.js.org/?ref=readme) to learn more about Storybook and to get started.\n\n### Documentation\n\nDocumentation can be found on [Storybook's docs site](https://storybook.js.org/docs?ref=readme).\n\n### Examples\n\nView [Component Encyclopedia](https://storybook.js.org/showcase?ref=readme) to see how leading teams use Storybook.\n\nUse [storybook.new](https://storybook.new) to quickly create an example project in Stackblitz.\n\nStorybook comes with a lot of [addons](https://storybook.js.org/docs/configure/user-interface/storybook-addons?ref=readme) for component design, documentation, testing, interactivity, and so on. Storybook's API makes it possible to configure and extend in various ways. It has even been extended to support React Native, Android, iOS, and Flutter development for mobile.\n\n### Community\n\nFor additional help, share your issue in [the repo's GitHub Discussions](https://github.com/storybookjs/storybook/discussions/new?category=help).\n\n## Projects\n\n### Supported Frameworks\n\n| Renderer                                                       | Demo                                                                                                                                                                         |                                                                                                                                                       |\n| -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |\n| [React](code/renderers/react)                                  | [![Storybook demo](https://img.shields.io/npm/v/@storybook/react/latest?style=flat-square&color=blue&label)](https://next--630511d655df72125520f051.chromatic.com/)          | [![React](https://img.shields.io/npm/dm/@storybook/react?style=flat-square&color=eee)](code/renderers/react)                                          |\n| [Angular](code/frameworks/angular/)                            | [![Storybook demo](https://img.shields.io/npm/v/@storybook/angular/latest?style=flat-square&color=blue&label)](https://next--6322ce6af69825592bbb28fc.chromatic.com/)        | [![Angular](https://img.shields.io/npm/dm/@storybook/angular?style=flat-square&color=eee)](code/frameworks/angular/)                                  |\n| [Vue 3](code/renderers/vue3)                                   | [![Storybook demo](https://img.shields.io/npm/v/@storybook/vue3/latest?style=flat-square&color=blue&label)](https://next--630513346a8e284ae244d415.chromatic.com/)           | [![Vue 3](https://img.shields.io/npm/dm/@storybook/vue3?style=flat-square&color=eee)](code/renderers/vue3/)                                           |\n| [Web components](code/renderers/web-components)                | [![Storybook demo](https://img.shields.io/npm/v/@storybook/web-components/latest?style=flat-square&color=blue&label)](https://next--638db5bf49adfdfe8cf545e0.chromatic.com/) | [![Svelte](https://img.shields.io/npm/dm/@storybook/web-components?style=flat-square&color=eee)](code/renderers/web-components)                       |\n| [React Native](https://github.com/storybookjs/react-native)    | [![](https://img.shields.io/npm/v/@storybook/react-native/latest?style=flat-square&color=blue&label)](/)                                                                     | [![React Native](https://img.shields.io/npm/dm/@storybook/react-native?style=flat-square&color=eee)](https://github.com/storybookjs/react-native)     |\n| [HTML](code/renderers/html)                                    | [![Storybook demo](https://img.shields.io/npm/v/@storybook/html/latest?style=flat-square&color=blue&label)](https://next--63dd39a158cf6fc05199b4bb.chromatic.com/)           | [![HTML](https://img.shields.io/npm/dm/@storybook/html?style=flat-square&color=eee)](code/renderers/html)                                             |\n| [Ember](code/frameworks/ember/)                                | [![](https://img.shields.io/npm/v/@storybook/ember/latest?style=flat-square&color=blue&label)](/)                                                                            | [![Ember](https://img.shields.io/npm/dm/@storybook/ember?style=flat-square&color=eee)](code/frameworks/ember/)                                        |\n| [Svelte](code/renderers/svelte)                                | [![Storybook demo](https://img.shields.io/npm/v/@storybook/svelte/latest?style=flat-square&color=blue&label)](https://next--630873996e4e3557791c069c.chromatic.com/)         | [![Svelte](https://img.shields.io/npm/dm/@storybook/svelte?style=flat-square&color=eee)](code/renderers/svelte)                                       |\n| [Preact](code/renderers/preact)                                | [![Storybook demo](https://img.shields.io/npm/v/@storybook/preact/latest?style=flat-square&color=blue&label)](https://next--63b588a512565bfaace15e7c.chromatic.com/)         | [![Preact](https://img.shields.io/npm/dm/@storybook/preact?style=flat-square&color=eee)](code/renderers/preact)                                       |\n| [Qwik](https://github.com/literalpie/storybook-framework-qwik) | [![](https://img.shields.io/npm/v/storybook-framework-qwik/latest?style=flat-square&color=blue&label)](/)                                                                    | [![Qwik](https://img.shields.io/npm/dm/storybook-framework-qwik?style=flat-square&color=eee)](https://github.com/literalpie/storybook-framework-qwik) |\n| [SolidJS](https://github.com/solidjs-community/storybook)      | [![](https://img.shields.io/npm/v/storybook-solidjs-vite/latest?style=flat-square&color=blue&label)](/)                                                                      | [![SolidJS](https://img.shields.io/npm/dm/storybook-solidjs-vite?style=flat-square&color=eee)](https://github.com/solidjs-community/storybook)        |\n| [Android, iOS, Flutter](https://github.com/storybookjs/native) | [![](https://img.shields.io/npm/v/@storybook/native/latest?style=flat-square&color=blue&label)](/)                                                                           | [![Native](https://img.shields.io/npm/dm/@storybook/native?style=flat-square&color=eee)](https://github.com/storybookjs/native)                       |\n\n### Addons\n\n| Addons                                                                    |                                                                            |\n| ------------------------------------------------------------------------- | -------------------------------------------------------------------------- |\n| [a11y](code/addons/a11y/)                                                 | Test components for user accessibility in Storybook                        |\n| [actions](code/core/src/actions/)                                         | Log actions as users interact with components in the Storybook UI          |\n| [backgrounds](code/core/src/backgrounds)                                  | Let users choose backgrounds in the Storybook UI                           |\n| [cssresources](https://github.com/storybookjs/addon-cssresources)         | Dynamically add/remove CSS resources to the component iframe               |\n| [design assets](https://github.com/storybookjs/addon-design-assets)       | View images, videos, and weblinks alongside your story                     |\n| [docs](code/addons/docs/)                                                 | Add high quality documentation to your components                          |\n| [events](https://github.com/storybookjs/addon-events)                     | Interactively fire events to components that respond to EventEmitter       |\n| [google-analytics](https://github.com/storybookjs/addon-google-analytics) | Reports google analytics on stories                                        |\n| [graphql](https://github.com/storybookjs/addon-graphql)                   | Query a GraphQL server within Storybook stories                            |\n| [jest](https://github.com/storybookjs/addon-jest)                         | View the results of components' unit tests in Storybook                    |\n| [links](code/addons/links/)                                               | Create links between stories                                               |\n| [measure](code/core/src/measure/)                                         | Visually inspect the layout and box model within the Storybook UI          |\n| [outline](code/core/src/outline/)                                         | Visually debug the CSS layout and alignment within the Storybook UI        |\n| [query params](https://github.com/storybookjs/addon-queryparams)          | Mock query params                                                          |\n| [viewport](code/core/src/viewport/)                                       | Change display sizes and layouts for responsive components using Storybook |\n\nSee [Addon / Framework Support Table](https://storybook.js.org/docs/configure/integration/frameworks-feature-support?ref=readme)\n\nTo continue improving your experience, we have to eventually deprecate or remove certain addons in favor of new and better tools.\n\nIf you're using info/notes, we highly recommend you migrate to [docs](code/addons/docs/) instead, and [here is a guide](code/addons/docs/docs/recipes.md#migrating-from-notesinfo-addons) to help you.\n\nIf you're using contexts, we highly recommend you migrate to [toolbars](https://github.com/storybookjs/storybook/tree/next/code/addons/toolbars) and [here is a guide](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-addon-contexts) to help you.\n\nIf you're using addon-storyshots, we highly recommend you migrate to the Storybook [test-runner](https://github.com/storybookjs/test-runner) and [here is a guide](https://storybook.js.org/docs/writing-tests/storyshots-migration-guide?ref=readme) to help you.\n\n## Badges & Presentation materials\n\nWe have a badge! Link it to your live Storybook example.\n\n![Storybook](https://cdn.jsdelivr.net/gh/storybookjs/brand@main/badge/badge-storybook.svg)\n\n```md\n[![Storybook](https://cdn.jsdelivr.net/gh/storybookjs/brand@main/badge/badge-storybook.svg)](link to site)\n```\n\nIf you're looking for material to use in your Storybook presentation, such as logos, video material, and the colors we use, you can find it all on our [brand repo](https://github.com/storybookjs/brand).\n\n## Community\n\n- Tweeting via [@storybookjs](https://x.com/storybookjs)\n- Blogging at [storybook.js.org](https://storybook.js.org/blog/?ref=readme) and [Medium](https://medium.com/storybookjs)\n- Chatting on [Discord](https://discord.gg/storybook)\n- Videos and streams at [YouTube](https://www.youtube.com/channel/UCr7Quur3eIyA_oe8FNYexfg)\n\n## Contributing\n\nContributions to Storybook are always welcome!\n\n- 📥 Pull requests and 🌟 Stars are always welcome.\n- Read our [contributing guide](CONTRIBUTING.md) to get started,\n  or find us on [Discord](https://discord.gg/storybook), we will take the time to guide you.\n\nLooking for a first issue to tackle?\n\n- We tag issues with [![Good First Issue](https://img.shields.io/github/issues/storybookjs/storybook/good%20first%20issue.svg)](https://github.com/storybookjs/storybook/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) when we think they are well suited for people who are new to the codebase or OSS in general.\n- [Talk to us](https://discord.gg/storybook), we'll find something that suits your skills and learning interests.\n\n### Development scripts\n\nStorybook is organized as a monorepo. Useful scripts include:\n\n#### `yarn start`\n\n> Runs a sandbox template storybook with test stories\n\n#### `yarn task`\n\n> As above, but gives you options to customize the sandbox (e.g. selecting other frameworks)\n\n#### `yarn lint`\n\n> boolean check if code conforms to linting rules - uses remark & eslint\n\n- `yarn lint:js` - will check js\n- `yarn lint:md` - will check markdown + code samples\n- `yarn lint:js --fix` - will automatically fix js\n\n#### `yarn test`\n\n> boolean check if unit tests all pass - uses jest\n\n- `yarn run test --core --watch` - will run core tests in watch-mode\n\n### Sponsors\n\nBecome a sponsor to have your logo and website URL on our README on Github. \\[[Become a sponsor](https://opencollective.com/storybook#sponsor)]\n\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/0/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/0/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/1/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/1/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/2/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/2/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/3/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/3/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/4/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/4/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/5/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/5/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/6/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/6/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/7/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/7/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/8/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/8/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/9/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/9/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/10/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/10/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/11/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/11/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/12/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/12/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/13/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/13/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/14/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/14/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/15/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/15/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/16/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/16/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/17/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/17/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/18/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/18/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/19/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/19/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/20/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/20/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/21/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/21/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/22/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/22/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/23/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/23/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/24/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/24/avatar.svg?requireActive=true\"></a>\n<a href=\"https://opencollective.com/storybook/tiers/sponsors/25/website?requireActive=true\" target=\"_blank\"><img src=\"https://opencollective.com/storybook/tiers/sponsors/25/avatar.svg?requireActive=true\"></a>\n\n### Backers\n\nBy making a recurring donation, you can support us and our work. \\[[Become a backer](https://opencollective.com/storybook#backer)]\n\n<a href=\"https://opencollective.com/storybook\"><img src=\"https://opencollective.com/storybook/tiers/backers.svg?limit=80&button=false&avatarHeight=46&width=750\"></a>\n\n## License\n\n[MIT](https://github.com/storybookjs/storybook/blob/main/LICENSE)\n\n-the end-\n"
  },
  {
    "path": "RESOLUTIONS.md",
    "content": "# Resolutions and Exact versions\n\nThis file keeps track of any resolutions or exact versions specified in any `package.json` file. Resolutions are used to specify a specific version of a package to be used, even if a different version is specified as a dependency of another package.\n\n## path/to/package.json\n\nexample-library@3.4.6 (bug: 3.5.x): Pinned as there is a bug in version 3.5.x that prevents foo from doing bar.\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\n## Supported Versions\n\nWe release patches for security vulnerabilities, primarily focusing on the latest major version.\n\nSecurity fixes are backported to the previous two major versions only for vulnerabilities with High or Critical CVSS scores (7.0+). The decision to backport is made based on severity assessment and the feasibility of implementing the patch in those versions.\n\n- Latest major version: All security vulnerabilities\n- Previous two major versions: High or Critical CVSS scores only\n- Older versions: Not supported (Users should upgrade to a supported version)\n\n## Reporting a Vulnerability\n\nTo report a vulnerability, you can reach out to the maintainers directly on [X](https://x.com/storybookjs) or [Bluesky](https://bsky.app/profile/storybook.js.org), or file a security advisory.\n\nWhen we fix a critical security issue, we will post a security advisory on GitHub and/or npm, describe the change in the [release notes](https://github.com/storybookjs/storybook/releases), and also notify the community through appropriate means.\n\n## Security advisories\n\nGitHub provides the option for you to privately report a vulnerability through a [security advisory](https://docs.github.com/en/code-security/security-advisories/working-with-repository-security-advisories/about-repository-security-advisories). These provide a secure and private channel between the reporter and the Storybook core team to discuss and address a security vulnerability.\n\n### Dependency related advisories\n\nPlease do not open security advisories solely to report vulnerabilities in downstream dependencies unless they pose a realistic security risk to Storybook users.\n\nStorybook depends on many packages, both directly and indirectly. A vulnerability in one of these dependencies does not automatically imply that Storybook is vulnerable, exploitable, or usable for malicious purposes. Security reports should clearly explain how the vulnerability can be exploited through Storybook itself. Reports that only cite a dependency advisory, without demonstrating impact in Storybook, are unlikely to be actionable. For example, a weak random hash generator is not a security issue if Storybook only uses it to generate non sensitive HTML element identifiers.\n\nIf a security patch is available for a downstream dependency and upgrading it meaningfully improves Storybook’s security posture, please open a bug report or pull request instead of a security advisory.\n"
  },
  {
    "path": "code/.eslintignore",
    "content": "dist\nbuild\ncoverage\nnode_modules\ndocs/public\nstorybook-static\nbuilt-storybooks\nlib/codemod/src/transforms/__testfixtures__\nscripts/storage\nscripts/repros-generator\n*.bundle.js\n*.js.map\nember-output\n.yarn\n!.remarkrc.js\n!.babelrc.js\n!.eslintrc.js\n!.eslintrc-markdown.js\n!.storybook\ncore/assets\ncore/src/core-server/utils/__search-files-tests__\ncore/src/core-server/utils/__mockdata__/src/Empty.stories.ts\ncore/report\n"
  },
  {
    "path": "code/.eslintrc.js",
    "content": "const path = require('path');\n\nconst scriptPath = path.join(__dirname, '..', 'scripts');\n\nmodule.exports = {\n  root: true,\n  extends: [\n    path.join(scriptPath, '.eslintrc.cjs'),\n    'plugin:storybook/recommended',\n    'plugin:compat/recommended',\n  ],\n  parserOptions: {\n    tsconfigRootDir: __dirname,\n    project: ['./tsconfig.json'],\n  },\n  rules: {\n    'import-x/no-extraneous-dependencies': 'off',\n    'react/react-in-jsx-scope': 'off',\n    'import-x/no-unresolved': 'off', // covered by typescript\n    'eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }],\n    'eslint-comments/no-unused-disable': 'error',\n    'react-hooks/rules-of-hooks': 'off',\n    'jsx-a11y/no-autofocus': 'warn',\n    'import-x/extensions': 'off', // for mjs, we sometimes need extensions\n    'jsx-a11y/control-has-associated-label': 'off',\n    '@typescript-eslint/dot-notation': [\n      'error',\n      {\n        allowIndexSignaturePropertyAccess: true,\n      },\n    ],\n    '@typescript-eslint/no-restricted-imports': [\n      'error',\n      {\n        paths: [\n          {\n            name: 'react-aria',\n            message:\n              \"Don't import from react-aria directly, please use the specific submodule like @react-aria/overlays instead\",\n            allowTypeImports: false,\n          },\n          {\n            name: 'react-stately',\n            message:\n              \"Don't import from react-stately directly, please use the specific submodule like @react-stately/overlays instead\",\n            allowTypeImports: false,\n          },\n          {\n            name: 'react-aria-components',\n            message:\n              \"Don't import from react-aria-components root, but use the react-aria-components/patched-dist/ComponentX entrypoints which are optimised for tree-shaking. Might require addition patching of the package if using new, unpatched components. See https://github.com/storybookjs/storybook/pull/32594\",\n            allowTypeImports: true,\n          },\n          {\n            name: 'es-toolkit',\n            message:\n              \"Don't import from es-toolkit root, but use the sub-exports like es-toolkit/array entrypoints instead which are optimised for tree-shaking.\",\n            allowTypeImports: true,\n          },\n        ],\n      },\n    ],\n    '@typescript-eslint/default-param-last': 'off',\n  },\n  overrides: [\n    {\n      // this package depends on a lot of peerDependencies we don't want to specify, because npm would install them\n      files: ['**/frameworks/angular/template/**/*'],\n      rules: {\n        '@typescript-eslint/no-useless-constructor': 'off',\n        '@typescript-eslint/dot-notation': 'off',\n      },\n    },\n    {\n      files: [\n        '*.js',\n        '*.jsx',\n        '*.json',\n        '*.html',\n        '**/.storybook/*.ts',\n        '**/.storybook/*.tsx',\n        '**/.storybook/**/*.ts',\n        '**/.storybook/**/*.tsx',\n      ],\n      parserOptions: {\n        project: null,\n      },\n      rules: {\n        '@typescript-eslint/dot-notation': 'off',\n        '@typescript-eslint/no-implied-eval': 'off',\n        '@typescript-eslint/return-await': 'off',\n      },\n    },\n    {\n      // this package depends on a lot of peerDependencies we don't want to specify, because npm would install them\n      files: ['**/builder-vite/**/*.html'],\n      rules: {\n        '@typescript-eslint/no-unused-expressions': 'off', // should become error, in the future\n      },\n    },\n    {\n      files: [\n        '*.test.*',\n        '*.spec.*',\n        '**/addons/docs/**/*',\n        '**/__tests__/**',\n        '**/__testfixtures__/**',\n        '**/*.test.*',\n        '**/*.test-d.*',\n        '**/*.stories.*',\n        '**/*.mockdata.*',\n        '**/template/**/*',\n      ],\n      rules: {\n        'compat/compat': 'off',\n        'jsx-a11y/click-events-have-key-events': 'off',\n        'jsx-a11y/no-static-element-interactions': 'off',\n        'jsx-a11y/iframe-has-title': 'off',\n        'jsx-a11y/alt-text': 'off',\n      },\n    },\n    {\n      files: ['**/__tests__/**', '**/__testfixtures__/**', '**/*.test.*', '**/*.stories.*'],\n      rules: {\n        '@typescript-eslint/no-empty-function': 'off',\n      },\n    },\n    {\n      files: ['**/__testfixtures__/**'],\n      rules: {\n        'react/forbid-prop-types': 'off',\n        'react/no-unused-prop-types': 'off',\n        'react/require-default-props': 'off',\n      },\n    },\n    {\n      files: ['**/*.stories.*'],\n      rules: {\n        'no-console': 'off',\n      },\n    },\n    {\n      files: ['**/renderers/preact/**/*'],\n      rules: {\n        'react/react-in-jsx-scope': 'off',\n        'react/prop-types': 'off',\n      },\n    },\n    {\n      files: ['**/*.tsx', '**/*.ts'],\n      rules: {\n        'no-shadow': 'off',\n        'react/require-default-props': 'off',\n        'react/prop-types': 'off', // we should use types\n        'react/forbid-prop-types': 'off', // we should use types\n        'no-dupe-class-members': 'off', // this is called overloads in typescript\n        'react/no-unused-prop-types': 'off', // we should use types\n        'react/default-props-match-prop-types': 'off', // we should use types\n        'import-x/no-named-as-default': 'warn',\n        'import-x/no-named-as-default-member': 'warn',\n        'react/destructuring-assignment': 'warn',\n\n        // Our codebase is mostly TypeScript, and typescript will warn when imports are not found.\n        // It IS set to 'error' for JS files.\n        'import-x/named': 'off',\n      },\n    },\n    {\n      files: ['**/*.d.ts'],\n      rules: {\n        'vars-on-top': 'off',\n        'no-var': 'off', // this is how typescript works\n        'spaced-comment': 'off',\n      },\n    },\n    {\n      files: ['**/builder-vite/input/iframe.html'],\n      rules: {\n        'no-undef': 'off', // ignore \"window\" undef errors\n      },\n    },\n    {\n      files: ['**/*.ts', '!**/*.test.*', '!**/*.spec.*'],\n      excludedFiles: ['**/*.test.*', '**/*.mockdata.*'],\n      rules: {\n        'local-rules/no-uncategorized-errors': 'warn',\n      },\n    },\n    {\n      files: ['**/*.ts', '!**/*.test.*', '!**/*.spec.*'],\n      excludedFiles: ['**/*.test.*'],\n      rules: {\n        'local-rules/storybook-monorepo-imports': 'error',\n      },\n    },\n    {\n      files: ['./core/src/preview-errors.ts'],\n      excludedFiles: ['**/*.test.*'],\n      rules: {\n        'local-rules/no-duplicated-error-codes': 'error',\n      },\n    },\n    {\n      files: ['./e2e-tests/*.ts'],\n      extends: ['plugin:playwright/recommended'],\n      rules: {\n        'playwright/no-skipped-test': [\n          'warn',\n          {\n            allowConditional: true,\n          },\n        ],\n        'playwright/no-raw-locators': 'off', // TODO: enable this, requires the UI to actually be accessible\n        'playwright/prefer-comparison-matcher': 'error',\n        'playwright/prefer-equality-matcher': 'error',\n        'playwright/prefer-hooks-on-top': 'error',\n        'playwright/prefer-strict-equal': 'error',\n        'playwright/prefer-to-be': 'error',\n        'playwright/prefer-to-contain': 'error',\n        'playwright/prefer-to-have-count': 'error',\n        'playwright/prefer-to-have-length': 'error',\n        'playwright/require-to-throw-message': 'error',\n        'playwright/require-top-level-describe': 'error',\n      },\n    },\n    {\n      files: ['**/renderers/**/*.stories.*', '**/core/template/**/*.stories.*'],\n      rules: {\n        'storybook/no-renderer-packages': 'off',\n      },\n    },\n    {\n      files: ['**/*.ts', '**/*.tsx'],\n      excludedFiles: [\n        '**/*.d.ts',\n        '**/docs/**/*',\n        '**/template/**/*',\n        '**/templates/**/*',\n        '**/__testfixtures__/**/*',\n        '**/__mocks-ng-workspace__/**/*',\n      ],\n      rules: {\n        'import-x/extensions': [\n          'error',\n          'always',\n          {\n            ignorePackages: true,\n            checkTypeImports: true,\n            fix: true,\n            pathGroupOverrides: [\n              { pattern: 'storybook/**', action: 'ignore' },\n              { pattern: '@storybook/**', action: 'ignore' },\n            ],\n          },\n        ],\n      },\n    },\n  ],\n};\n"
  },
  {
    "path": "code/.gitignore",
    "content": "vite.config.*.timestamp*"
  },
  {
    "path": "code/.remarkignore",
    "content": "CHANGELOG.md"
  },
  {
    "path": "code/.storybook/bench/bench.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta } from '@storybook/react-vite';\n\nimport { safeMetafileArg } from '../../../scripts/bench/safe-args.ts';\n\n// @ts-expect-error - TS doesn't know about import.meta.glob from Vite\nconst allMetafiles = import.meta.glob('../../bench/esbuild-metafiles/**/*.json', {\n  import: 'default',\n});\n\nexport default {\n  title: 'Bench',\n  parameters: {\n    layout: 'fullscreen',\n    chromatic: { disableSnapshot: true },\n  },\n  args: {\n    // default to the core/node.json metafile\n    metafile: safeMetafileArg(\n      Object.keys(allMetafiles).find((path) => path.includes('/core/node.json'))!\n    ),\n  },\n  argTypes: {\n    metafile: {\n      options: Object.keys(allMetafiles).map(safeMetafileArg).sort(),\n      mapping: Object.fromEntries(\n        Object.keys(allMetafiles).map((path) => [safeMetafileArg(path), path])\n      ),\n      control: {\n        type: 'select',\n        labels: Object.fromEntries(\n          Object.keys(allMetafiles).map((path) => {\n            const [, dirname, subEntry] = /esbuild-metafiles\\/(.+)\\/(.+).json/.exec(path)!;\n\n            // most metafile directories are named exactly like their package name within the @storybook scope\n            let packageName = '@storybook/' + dirname;\n\n            // but some are not, so we need to map them to the correct package name\n            switch (dirname) {\n              case 'core': {\n                packageName = 'storybook';\n                break;\n              }\n              case 'eslint-plugin':\n                packageName = 'eslint-plugin-storybook';\n                break;\n              case 'create-storybook':\n              case 'storybook-addon-pseudo-states':\n                packageName = dirname;\n            }\n\n            return [safeMetafileArg(path), `${packageName} - ${subEntry}`];\n          })\n        ),\n      },\n    },\n  },\n  beforeEach: async ({ args }) => {\n    if (!args.metafile) {\n      globalThis.metafile = undefined;\n      return;\n    }\n    const metafile = await allMetafiles[args.metafile]();\n    // this is read by the bundle-analyzer iframe via parent.metafile, in bundle-analyzer/index.js\n    globalThis.metafile = JSON.stringify(metafile);\n  },\n  render: (args) => {\n    return (\n      <iframe\n        src=\"/bundle-analyzer/index.html\"\n        style={{ position: 'fixed', width: '100vw', height: '100vh', border: 'none' }}\n        key={args.metafile} // force re-render on args change\n      />\n    );\n  },\n} satisfies Meta;\n\nexport const ESBuildAnalyzer = {\n  name: 'ESBuild Metafiles',\n};\n"
  },
  {
    "path": "code/.storybook/bench/bundle-analyzer/index.css",
    "content": "html:not([data-theme='dark']) {\n  --bg: #fff;\n  --fg-on: #000;\n  --fg: #222;\n  --pre-dim: #777;\n  --pre-val: #870;\n  --pre: #222;\n  --bar-min-width: 1px;\n}\nhtml[data-theme='dark'] {\n  color-scheme: dark;\n  --bg: #191919;\n  --fg-on: #ddd;\n  --fg: #aaa;\n  --pre-dim: #999;\n  --pre-val: #cb8;\n  --pre: #ccc;\n  --bar-min-width: 3px;\n}\n@media (prefers-color-scheme: dark) {\n  html:not([data-theme='light']) {\n    color-scheme: dark;\n    --bg: #191919;\n    --fg-on: #ddd;\n    --fg: #aaa;\n    --pre-dim: #999;\n    --pre-val: #cb8;\n    --pre: #ccc;\n    --bar-min-width: 3px;\n  }\n}\nbody {\n  margin: 50px;\n  background: var(--bg);\n  color: var(--fg);\n  font: 16px/20px sans-serif;\n}\n#startPanel {\n  margin: 10% auto 0;\n}\n#resultsPanel {\n  display: none;\n}\nsection {\n  margin: auto;\n  max-width: 600px;\n}\n#logo {\n  display: inline-block;\n  margin-bottom: 10px;\n  text-align: left;\n}\nh1 {\n  margin: 0;\n  color: var(--fg-on);\n  font-size: 80px;\n  line-height: 1em;\n}\nblockquote {\n  margin: 5px 0;\n  font-style: italic;\n  font-size: 29px;\n  line-height: 1em;\n}\np {\n  margin: 20px 0;\n}\na,\nb {\n  color: var(--fg-on);\n}\ncode {\n  margin-bottom: -2px;\n  border-radius: 3px;\n  background: rgba(127, 127, 127, 0.2);\n  padding: 2px 4px;\n  font:\n    14px/20px Noto Sans Mono,\n    monospace;\n}\npre {\n  margin: 0;\n  padding: 0;\n  color: var(--pre);\n  font:\n    14px/20px Noto Sans Mono,\n    monospace;\n  white-space: pre-wrap;\n}\n.center {\n  text-align: center;\n}\n.noscript {\n  color: #e24834;\n}\nbutton {\n  cursor: pointer;\n  border: 1px solid var(--fg);\n  border-radius: 100px;\n  background: none;\n  padding: 5px 30px;\n  color: var(--fg);\n  line-height: 1.5em;\n}\nbutton:active,\nbutton:hover {\n  border: 1px solid var(--fg-on);\n  background: rgba(127, 127, 127, 0.2);\n  color: var(--fg-on);\n}\nbutton:active {\n  background: rgba(0, 0, 0, 0.2);\n  padding: 6px 30px 4px;\n}\n#settingsPanel {\n  text-align: center;\n}\n#settingsPanel .chartSwitcher {\n  display: flex;\n  position: relative;\n  justify-content: center;\n  margin: 50px 0;\n}\n#settingsPanel .chartSwitcher:after {\n  display: block;\n  position: absolute;\n  top: 0.5em;\n  right: 0;\n  left: 0;\n  z-index: -1;\n  border: 1px solid #ffcf00;\n  content: '';\n}\n#settingsPanel .chartSwitcher span {\n  border-left: 2px solid #ffcf00;\n  background: var(--bg);\n  padding: 0 1em;\n}\n#settingsPanel .chartSwitcher span:first-child {\n  border: none;\n}\n#settingsPanel a {\n  color: var(--fg);\n  text-decoration: none;\n}\n#settingsPanel a:hover {\n  text-decoration: underline;\n}\n#settingsPanel a.r {\n  color: var(--fg-on);\n  font-weight: 700;\n}\n.n {\n  display: none;\n  margin: auto;\n  max-width: 600px;\n}\n.p {\n  display: none;\n  position: absolute;\n  z-index: 1;\n  border-radius: 30px;\n  background: black;\n  padding: 0 10px;\n  touch-action: none;\n  pointer-events: none;\n  color: #999;\n  font-size: 14px;\n  line-height: 30px;\n  -webkit-user-select: none;\n  user-select: none;\n  white-space: pre;\n}\n.p b {\n  color: #fff;\n}\n#dragTarget {\n  display: none;\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 10;\n  box-shadow: inset 0 0 0 10px #ffcf00;\n  touch-action: none;\n  -webkit-user-select: none;\n  user-select: none;\n}\n#summaryPanel {\n  text-align: center;\n}\n#summaryPanel table {\n  margin: auto;\n  border-collapse: collapse;\n}\n#summaryPanel td:first-child {\n  text-align: right;\n}\n#summaryPanel h2 {\n  margin: 0;\n  color: var(--fg-on);\n  font-size: 30px;\n  line-height: 1em;\n}\n#summaryPanel .l {\n  padding: 0 30px;\n  font-size: 30px;\n}\n#summaryPanel .o {\n  display: inline-block;\n  margin: 20px auto 0;\n  text-decoration: none;\n  white-space: nowrap;\n}\n#summaryPanel .o:hover .d {\n  text-decoration: underline;\n}\n#summaryPanel .g {\n  display: inline-table;\n  vertical-align: middle;\n  margin: 0 0.8em;\n  border: 1px solid #222;\n}\n#summaryPanel .g > div {\n  display: table-cell;\n  height: 20px;\n}\n#x {\n  padding-left: 1.6em;\n  line-height: 1.1em;\n}\n#x .c {\n  display: inline-block;\n  vertical-align: middle;\n  box-sizing: border-box;\n  margin-right: 0.5em;\n  margin-left: -1.6em;\n  border: 1px solid #222;\n  width: 1.1em;\n  height: 1.1em;\n}\n#x small {\n  display: block;\n  opacity: 0.5;\n  margin-bottom: 1em;\n}\n#s {\n  margin: 0 -50px;\n  padding: 0 50px;\n}\n#s main {\n  position: relative;\n  margin-top: 60px;\n}\n#s canvas {\n  position: absolute;\n  top: 0;\n  right: 0;\n  left: 0;\n  margin: auto;\n  padding-bottom: 50px;\n}\n#s section {\n  display: none;\n  margin-top: 30px;\n  min-height: 200px;\n}\n#b {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  background: rgba(0, 0, 0, 0.6);\n  padding: 50px;\n  overflow-y: auto;\n}\n#b .m {\n  position: relative;\n  box-sizing: border-box;\n  margin: 0 auto;\n  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.6);\n  border-radius: 20px;\n  background: var(--bg);\n  padding: 50px;\n  max-width: 1000px;\n}\n#b .m:focus {\n  outline: none;\n}\n#b .h {\n  position: absolute;\n  top: 0;\n  right: 0;\n  width: 50px;\n  color: var(--fg);\n  font-size: 30px;\n  line-height: 50px;\n  text-align: center;\n  text-decoration: none;\n}\n#b .h:hover {\n  color: var(--fg-on);\n  font-size: 35px;\n}\n#b .h:active {\n  font-size: 30px;\n}\n#b h2 {\n  margin: 0;\n  border-bottom: 2px solid #ffcf00;\n  padding-bottom: 4px;\n  color: var(--fg-on);\n  font-size: 20px;\n  line-height: 1.2em;\n}\n#b .f {\n  position: relative;\n  margin-top: 10px;\n  border: 1px solid rgba(127, 127, 127, 0.5);\n  border-radius: 10px;\n  padding: 30px 10px 10px;\n  line-height: 22px;\n  white-space: pre-wrap;\n}\n#b .u {\n  position: absolute;\n  top: 0;\n  left: 0;\n  border-right: 1px solid rgba(127, 127, 127, 0.5);\n  border-bottom: 1px solid rgba(127, 127, 127, 0.5);\n  border-top-left-radius: 10px;\n  border-bottom-right-radius: 10px;\n  background: rgba(127, 127, 127, 0.1);\n  padding: 5px 10px;\n}\n#b pre {\n  padding: 0 0 0 30px;\n}\n#b .v {\n  color: var(--pre-dim);\n}\n#b .w {\n  color: var(--fg-on);\n}\n#b .k {\n  color: var(--pre-val);\n}\n#b .e,\n#b .i {\n  position: relative;\n}\n#b .e:after,\n#b .i:after {\n  position: absolute;\n  top: 0;\n  opacity: 0.5;\n  background: var(--fg);\n  width: 30px;\n  content: '';\n}\n#b .e:after {\n  height: 40px;\n  --icon: url('data:image/svg+xml,<svg width=\"30\" height=\"40\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M16.5 26L20.5 35L23 25.5L16.5 26Z\"/><path d=\"M5 7C15 7 19 15 20 30\" fill=\"none\" stroke=\"black\"/></svg>');\n  -webkit-mask-image: var(--icon);\n  mask-image: var(--icon);\n}\n#b .i:after {\n  height: 90px;\n  --icon: url('data:image/svg+xml,<svg width=\"30\" height=\"90\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M17 76L20 85L23 76H17Z\"/><path d=\"M5 7C15 7 20 25 20 80\" fill=\"none\" stroke=\"black\"/></svg>');\n  -webkit-mask-image: var(--icon);\n  mask-image: var(--icon);\n}\n#y main {\n  display: flex;\n  justify-content: center;\n  margin-top: 50px;\n  margin-bottom: 500px;\n}\n#y .z {\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  margin-right: 20px;\n}\n#y canvas {\n  display: block;\n  margin-bottom: 30px;\n}\n#y .F {\n  position: relative;\n  flex: 1;\n  max-width: 800px;\n}\n#y .P {\n  display: flex;\n  margin: 0 10px 20px;\n  font-size: 20px;\n  line-height: 1.2em;\n  white-space: pre;\n}\n#y .P .C {\n  flex: 1;\n  height: 20px;\n}\n#y .P a {\n  opacity: 0.5;\n  text-decoration: none;\n}\n#y .P a[href]:hover {\n  text-decoration: underline;\n}\n#y .P a:last-child {\n  opacity: 1;\n  color: var(--fg-on);\n  font-weight: 700;\n}\n#y .S {\n  width: 100%;\n}\n#y .S .j {\n  display: table-row;\n  color: var(--fg);\n  line-height: 26px;\n  text-decoration: none;\n}\n#y .S .j.a {\n  background: rgba(127, 127, 127, 0.2);\n  color: var(--fg-on);\n}\n#y .S .j.a .t:after {\n  position: absolute;\n  top: 1px;\n  right: 1px;\n  bottom: 1px;\n  left: 1px;\n  background: rgba(255, 255, 255, 0.3);\n  content: '';\n}\n#y .S .j > div {\n  display: table-cell;\n}\n#y .S .M {\n  vertical-align: top;\n  padding: 0 10px;\n  white-space: pre;\n}\n#y .S .N {\n  padding-right: 100px;\n  width: 100%;\n}\n#y .S .t {\n  position: relative;\n  margin-bottom: -1px;\n  box-shadow: inset 0 0 0 1px #222;\n  min-width: var(--bar-min-width);\n  height: 27px;\n}\n#y .S .t.q {\n  min-width: 0;\n}\n#y .S .T {\n  position: absolute;\n  right: -10px;\n  width: 0;\n  white-space: nowrap;\n}\n#A main {\n  position: relative;\n  margin-top: 60px;\n}\n#A canvas {\n  position: absolute;\n  top: 0;\n  left: -50px;\n}\n#A section {\n  display: none;\n  margin-top: 30px;\n  min-height: 500px;\n}\n#warningsPanel {\n  margin: auto;\n  max-width: 1000px;\n}\n#warningsPanel .B {\n  margin-top: 20px;\n  text-align: center;\n}\n#warningsPanel .D {\n  display: none;\n}\n#warningsPanel .E {\n  margin: 30px 0;\n  color: var(--fg-on);\n  white-space: pre-wrap;\n}\n#warningsPanel ul {\n  margin: 5px 0 0;\n  color: var(--fg);\n}\n#warningsPanel .G {\n  opacity: 0.5;\n}\n#warningsPanel pre a {\n  text-decoration: none;\n}\n#warningsPanel pre a:hover {\n  text-decoration: underline;\n}\n"
  },
  {
    "path": "code/.storybook/bench/bundle-analyzer/index.html",
    "content": "<!doctype html>\n<html lang=\"en\" data-theme=\"null\">\n  <head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n\n    <title>esbuild - Bundle Size Analyzer</title>\n    <link rel=\"stylesheet\" href=\"./index.css\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  </head>\n\n  <body>\n    <div id=\"dragTarget\" hidden></div>\n    <div id=\"startPanel\">\n      <section>\n        <div class=\"center\">\n          <div id=\"logo\">\n            <h1>esbuild</h1>\n            <blockquote>Bundle Size Analyzer</blockquote>\n          </div>\n        </div>\n        <p>\n          This is a modified version of the esbuild bundle analyzer, for storybook's purpose we\n          added a postMessage listener to receive the metafile from the parent window.\n        </p>\n        <p>\n          If you see this message, it means that the iframe hasn't received the metafile yet. It can\n          take a little while to load, for large meta-files, but check the browser console for any\n          errors, if it persists.\n        </p>\n        <p class=\"center\" hidden>\n          <button id=\"importButton\">Import your metafile...</button>\n        </p>\n        <p hidden>\n          Or you can <a href=\"javascript:void 0\" id=\"loadExample\">load an example</a> to play around\n          with the visualization.\n        </p>\n        <noscript>\n          <p class=\"noscript\">\n            &#x274C; This page requires JavaScript. Please enable JavaScript and reload the page.\n          </p>\n        </noscript>\n      </section>\n    </div>\n    <div id=\"resultsPanel\">\n      <div id=\"summaryPanel\"></div>\n      <div id=\"warningsPanel\"></div>\n      <div id=\"settingsPanel\">\n        <div class=\"chartSwitcher\">\n          <span><a id=\"useTreemap\" href=\"javascript:void 0\">Treemap Chart</a></span>\n          <span><a id=\"useSunburst\" href=\"javascript:void 0\">Sunburst Chart</a></span>\n          <span><a id=\"useFlame\" href=\"javascript:void 0\">Flame Chart</a></span>\n        </div>\n      </div>\n      <div id=\"chartPanel\"></div>\n    </div>\n    <script src=\"./index.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "code/.storybook/bench/bundle-analyzer/index.js",
    "content": "/* eslint-disable eslint-comments/no-unlimited-disable */\n/* eslint-disable */\n'use strict';\n(() => {\n  var m = document,\n    h = Math,\n    ie = requestAnimationFrame,\n    he = localStorage,\n    te = window;\n  var Fe = 'r',\n    Be = 'n',\n    ze = 'p';\n  var Pe = Object.prototype.hasOwnProperty,\n    Vt = Array.prototype.indexOf,\n    gt,\n    Yl = /\\.\\w+\\.map$/,\n    Xl = /^\\(disabled\\):/,\n    $t = navigator.platform.indexOf('Mac') >= 0,\n    Re = () => (te.performance || Date).now(),\n    rt = (e) => {\n      try {\n        return he.getItem(e);\n      } catch (t) {\n        return null;\n      }\n    },\n    nt = (e, t) => {\n      try {\n        he.setItem(e, t);\n      } catch (i) {}\n    },\n    Te = (e) => Yl.test(e);\n  var Se = (e) => e.replace(Xl, ''),\n    _e = (e) => (gt ? gt.format(e) : e + ''),\n    ht = (e) => {\n      let t = e.toFixed(1).split('.', 2);\n      return _e(+t[0]) + '.' + t[1];\n    },\n    ae = (e) =>\n      e === 1\n        ? '1 byte'\n        : e < 1024\n          ? _e(e) + ' bytes'\n          : e < 1024 * 1024\n            ? ht(e / 1024) + ' kb'\n            : e < 1024 * 1024 * 1024\n              ? ht(e / (1024 * 1024)) + ' mb'\n              : ht(e / (1024 * 1024 * 1024)) + ' gb',\n    z = (e) => e.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;'),\n    it = (e) => {\n      let t = 0.6 + 0.4 * h.max(0, h.cos(e)),\n        i = 0.5 + 0.2 * h.max(0, h.cos(e + (h.PI * 2) / 3));\n      return (\n        'hsl(' + (e * 180) / h.PI + 'deg, ' + h.round(100 * t) + '%, ' + h.round(100 * i) + '%)'\n      );\n    },\n    Vl = /\\bFirefox\\//.test(navigator.userAgent),\n    ot = (e, t, i, p, o, s) => {\n      if (Vl) {\n        let n = e.lineWidth,\n          r = n / 2;\n        (e.fillStyle = t),\n          e.fillRect(i - r, p - r, o + n, n),\n          e.fillRect(i - r, p + r, n, s - n),\n          e.fillRect(i - r, p + s - r, o + n, n),\n          e.fillRect(i + o - r, p + r, n, s - n);\n        return;\n      }\n      (e.strokeStyle = t), e.strokeRect(i, p, o, s);\n    },\n    Tt = (e) => m.createTextNode(e),\n    xt = (e) => {\n      let t = m.createElement('code');\n      return (t.textContent = e), t;\n    },\n    xe = (e, t) => {\n      let i = m.createElement('span');\n      return (i.className = e), (i.textContent = t), i;\n    },\n    We = (e) =>\n      e.startsWith('data:') && e.indexOf(',') >= 0\n        ? ((e = e.slice(0, 65).replace(/\\n/g, '\\\\n')),\n          '<' + (e.length > 64 ? e.slice(0, 64) + '...' : e) + '>')\n        : e,\n    ge = (e) => {\n      if (e.startsWith('data:') && e.indexOf(',') >= 0) {\n        return [e];\n      }\n      let t = e.split('/');\n      return (\n        t.length >= 3 &&\n          t[1] === '' &&\n          t[0].endsWith(':') &&\n          t.splice(0, 3, t.slice(0, 3).join('/')),\n        t\n      );\n    },\n    Ue = (e, t) => {\n      if (e === '') {\n        return [];\n      }\n      let i = ge(e);\n\n      if (!t) {\n        return i;\n      }\n\n      for (let p = 0; p <= i.length; p++) {\n        if (t[p] !== i[p]) {\n          t.length = p;\n          break;\n        }\n      }\n      return t;\n    },\n    Jt = (e, t) => {\n      let i = ge(e);\n\n      if (!t) {\n        return i.reverse();\n      }\n\n      for (let p = 0; p <= i.length; p++) {\n        if (t[p] !== i[i.length - p - 1]) {\n          t.length = p;\n          break;\n        }\n      }\n      return t;\n    },\n    qt = (e) => {\n      let t = e.lastIndexOf('/');\n      return t < 0 ? '.' : e.slice(0, t);\n    },\n    Kt = (e, t) => {\n      let i = e.split('/'),\n        p = t === '.' ? [] : t.split('/'),\n        o = 0;\n\n      for (; o < p.length && i[0] === p[o]; ) {\n        i.shift(), o++;\n      }\n\n      if (o === p.length) {\n        i.unshift('.');\n      } else {\n        for (; o < p.length; ) {\n          i.unshift('..'), o++;\n        }\n      }\n      return i.join('/');\n    },\n    Zt = (e) => {\n      let t = ge(e);\n\n      for (let i = t.length - 1; i >= 0; i--) {\n        if (t[i] === 'node_modules') {\n          return (\n            (t = t.slice(i + 1)),\n            t.length > 1 && /^index\\.(?:[jt]sx?)$/.test(t[t.length - 1]) && t.pop(),\n            t.join('/')\n          );\n        }\n      }\n      return null;\n    },\n    He = !1,\n    Yt = matchMedia('(prefers-color-scheme: dark)'),\n    Xt = () => Ge && Ge(),\n    bt = null,\n    yt = null,\n    Ge = null,\n    je = (e) => (bt = e),\n    Ye = (e) => (yt = e),\n    Xe = (e) => (Ge = e);\n  m.addEventListener('keydown', () => (He = !0), { capture: !0 });\n  m.addEventListener('mousedown', () => (He = !1), { capture: !0 });\n  te.addEventListener('wheel', (e) => bt && bt(e), { passive: !1 });\n  te.addEventListener('resize', () => yt && yt());\n  try {\n    Yt.addEventListener('change', Xt);\n  } catch (e) {\n    Yt.addListener(Xt);\n  }\n  try {\n    gt = new Intl.NumberFormat();\n  } catch (e) {}\n  var Et = m.getElementById('dragTarget'),\n    $l = m.getElementById('importButton'),\n    Nt = 0,\n    vt,\n    Qt = (e, t = e.dataTransfer) => t && t.types && Vt.call(t.types, 'Files') !== -1,\n    el = (e) => {\n      if (e.length === 1) {\n        let t = new FileReader();\n        (t.onload = () => et(t.result)), t.readAsText(e[0]);\n      }\n    };\n  m.ondragover = (e) => {\n    e.preventDefault();\n  };\n  m.ondragenter = (e) => {\n    e.preventDefault(), Qt(e) && ((Et.style.display = 'block'), Nt++);\n  };\n  m.ondragleave = (e) => {\n    e.preventDefault(), Qt(e) && --Nt === 0 && (Et.style.display = 'none');\n  };\n  m.ondrop = (e) => {\n    e.preventDefault(),\n      (Et.style.display = 'none'),\n      (Nt = 0),\n      e.dataTransfer && e.dataTransfer.files && el(e.dataTransfer.files);\n  };\n  $l.onclick = function () {\n    vt && m.body.removeChild(vt);\n    let e = m.createElement('input');\n    (e.type = 'file'),\n      (e.style.display = 'none'),\n      m.body.append(e),\n      (vt = e),\n      e.click(),\n      (e.onchange = () => e.files && el(e.files));\n  };\n  m.body.addEventListener('paste', (e) => {\n    e.clipboardData && (e.preventDefault(), et(e.clipboardData.getData('text/plain')));\n  });\n  var tl = 'l',\n    St = 'o',\n    wt = 'd',\n    ll = 'g';\n  var nl = 'x',\n    st = 'c';\n  var ve = (e, t) => t.t - e.t || +(e.e > t.e) - +(e.e < t.e),\n    we = (e, t, i) => {\n      let p = ge(t),\n        o = p.length,\n        s = e,\n        n = '';\n      e.t += i;\n      for (let r = 0; r < o; r++) {\n        let l = p[r],\n          a = s.n,\n          f = a[l],\n          u = l + (r + 1 < o ? '/' : '');\n        (n += u),\n          Pe.call(a, l) || ((f = { r: u, e: n, t: 0, n: {} }), (a[l] = f)),\n          (f.t += i),\n          (s = f);\n      }\n      return o;\n    };\n  var il,\n    ol,\n    al,\n    pt = m.createElement('canvas'),\n    oe = pt.getContext('2d'),\n    be = 1,\n    Mt,\n    Ot,\n    It = 0,\n    dt,\n    Ve = {},\n    Ct = null,\n    $e = (e) => (Ct = e),\n    Je = (e, t, i, p, o) => {\n      let s = Ve[t] || ke;\n      if (s instanceof Array) {\n        let n = te.devicePixelRatio || 1;\n        if (il !== e || ol !== n || al !== o) {\n          let r = h.round(64 * n) / 64,\n            l,\n            a,\n            f;\n          (be = o),\n            (be = h.log2(be)),\n            (be -= h.floor(be)),\n            (l = be),\n            (a = h.min(1, 8 * l)),\n            (be = h.pow(2, be)),\n            (f = (8 * h.SQRT2) / be),\n            (il = e),\n            (ol = n),\n            (al = o),\n            (pt.width = pt.height = h.round(64 * r)),\n            oe.scale(r, r),\n            (oe.fillStyle = s[0]),\n            oe.fillRect(0, 0, 64, 64),\n            (oe.globalAlpha = 0.25),\n            (oe.fillStyle = s[1]),\n            oe.fillRect(0, 0, 64, 64),\n            (oe.globalAlpha = 0.67),\n            (oe.strokeStyle = s[1]),\n            oe.beginPath();\n\n          for (let u = 0; u <= 64; u += 16) {\n            oe.moveTo(u - 32, u + 32), oe.lineTo(u + 32, u - 32);\n          }\n          if (((oe.lineWidth = f * (1 - (a - l) / 2)), oe.stroke(), a + l > 0)) {\n            oe.beginPath();\n\n            for (let u = 8; u < 64; u += 16) {\n              oe.moveTo(u - 32, u + 32), oe.lineTo(u + 32, u - 32);\n            }\n            (oe.lineWidth = (f * (a + l)) / 2), oe.stroke();\n          }\n          (Mt = e.createPattern(pt, 'repeat')), (be /= r);\n        }\n        return (\n          (i /= 64 * be * n),\n          (i -= h.floor(i)),\n          (i *= 64 * be * n),\n          Mt.setTransform(new DOMMatrix([be, 0, 0, be, i, p])),\n          Mt\n        );\n      }\n      return s;\n    },\n    sl = (e) => {\n      let t = Ve[e] || ke;\n      return t instanceof Array\n        ? `url('data:image/svg+xml,<svg width=\"26\" height=\"26\" xmlns=\"http://www.w3.org/2000/svg\"><rect width=\"26\" height=\"26\" fill=\"${t[0]}\"/><rect width=\"26\" height=\"26\" fill=\"${t[1]}\" fill-opacity=\"25%\"/><path d=\"M22.5 -3.5L-3.5 22.5M35.5 9.5L9.5 35.5\" stroke=\"${t[1]}\" stroke-opacity=\"67%\" stroke-width=\"9.19239\"/></svg>')`\n        : t;\n    },\n    dl = (e, t) => {\n      if (Ot !== e) {\n        let i = e.outputs;\n        (Ot = e), (It = 0), (dt = { r: '', e: '', t: 0, n: {} });\n        for (let p in i) {\n          if (Te(p)) {\n            continue;\n          }\n          let s = i[p].inputs;\n\n          for (let n in s) {\n            we(dt, Se(n), s[n].bytesInOutput);\n          }\n        }\n      }\n      It !== t &&\n        ((It = t),\n        (Ve = {}),\n        (Me.innerHTML = ''),\n        t === 1 ? pl(Ve, dt, 0, h.PI * 2) : t === 2 && (ul(Ve, dt), (Me.innerHTML = Ql)),\n        Ct && Ct());\n    },\n    pl = (e, t, i, p) => {\n      let o = t.t,\n        s = t.n,\n        n = [];\n      e[t.e] = it(i + p / 2);\n\n      for (let r in s) {\n        n.push(s[r]);\n      }\n      for (let r of n.sort(ve)) {\n        let l = (r.t / o) * p;\n        pl(e, r, i, l), (i += l);\n      }\n    },\n    qe = it(3.5),\n    Ke = it(1),\n    ke = '#CCC',\n    Kl = [qe, Ke],\n    Zl = (e) => (e ? (e === 1 ? qe : e === 2 ? Ke : Kl) : ke),\n    Ee = (e, t) => {\n      let i = Ve[e] || ke;\n      return i === ke ? '' : i === Ke ? t + 'ESM' : i === qe ? t + 'CJS' : t + 'ESM & CJS';\n    },\n    ul = (e, t) => {\n      let i = t.n,\n        p = 0,\n        o = !1;\n\n      for (let s in i) {\n        (p |= ul(e, i[s])), (o = !0);\n      }\n      if (!o) {\n        let s = Ot.inputs[t.e],\n          n = s && s.format;\n        p = n === 'esm' ? 2 : n === 'cjs' ? 1 : 0;\n      }\n      return (e[t.e] = Zl(p)), p;\n    },\n    Me = m.createElement('div'),\n    Ql =\n      `<span class=\"${st}\" style=\"background:` +\n      Ke +\n      `\"></span>ESM <small>modern, faster, smaller</small><span class=\"${st}\" style=\"background:` +\n      qe +\n      `\"></span>CommonJS <small>legacy, slower, larger</small><span class=\"${st}\" style=\"background:` +\n      ke +\n      '\"></span>Other';\n  Me.id = nl;\n  var fl = m.getElementById('summaryPanel'),\n    ml = (e) => (e === 1 ? 'file' : 'files'),\n    cl = (e, t) => {\n      let i = e.inputs,\n        p = e.outputs,\n        o = 0,\n        s = 0,\n        n = 0,\n        r = 0,\n        l = 0,\n        a = 0,\n        f = 0,\n        u,\n        N,\n        H;\n      for (let x in i) {\n        let P = i[x],\n          I = P.format;\n        I === 'esm' ? (l += P.bytes) : I === 'cjs' ? (a += P.bytes) : (f += P.bytes),\n          o++,\n          (n += P.bytes);\n      }\n\n      for (let x in p) {\n        Te(x) || (s++, (r += p[x].bytes));\n      }\n      (u = h.round((200 * l) / n)),\n        (N = h.round((200 * a) / n)),\n        (fl.innerHTML =\n          '<table><tr><td><h2>' +\n          z(ae(n)) +\n          '</h2>' +\n          z(_e(o)) +\n          ' input ' +\n          ml(o) +\n          `</td><td class=\"${tl}\">&rarr;</td><td><h2>` +\n          z(ae(r)) +\n          '</h2>' +\n          z(_e(s)) +\n          ' output ' +\n          ml(s) +\n          '</td></tr></table>' +\n          (l || a\n            ? `<a href=\"javascript:void 0\" class=\"${St}\"><span class=\"${wt}\">` +\n              _e(h.round((100 * a) / n)) +\n              `% CJS</span><div class=\"${ll}\"><div style=\"background:` +\n              qe +\n              ';width:' +\n              N +\n              'px\"></div><div style=\"background:#CCC;width:' +\n              (200 - u - N) +\n              'px\"></div><div style=\"background:' +\n              Ke +\n              ';width:' +\n              u +\n              `px\"></div></div><span class=\"${wt}\">` +\n              _e(h.round((100 * l) / n)) +\n              '% ESM</span></a>'\n            : '')),\n        (H = fl.querySelector('.' + St)),\n        H && (H.onclick = t);\n    };\n  var hl = 's';\n  var gl = 'b',\n    bl = 'm',\n    yl = 'h',\n    Tl = 'f',\n    xl = 'u';\n  var Lt = 'w',\n    Ae = 'k',\n    vl = 'e',\n    El = 'i';\n  var De = m.createElement('div'),\n    Nl,\n    Pt,\n    ut = null,\n    Sl = /^\\w[\\w\\d]*$/,\n    Ze = () => De.parentElement !== null,\n    tt = () => {\n      De.remove(), ut && (ut.focus(), (ut = null));\n    },\n    rr = (e) => {\n      let t = e.inputs,\n        i = e.outputs,\n        p = {},\n        o = {},\n        s = [],\n        n = {};\n      for (let l in i) {\n        let a = i[l],\n          f = a.entryPoint;\n        if (f) {\n          (p[f] = l), s.push(l);\n\n          for (let u of a.imports) {\n            !u.external && !Pe.call(n, u.path) && (n[u.path] = !0);\n          }\n        }\n      }\n      let r = [];\n      for (let l of s) {\n        let a = i[l].entryPoint;\n        Pe.call(n, l) || ((o[a] = { e: a, h: void 0, o: 'entry-point', s: void 0 }), r.push(a));\n      }\n\n      if (!r.length) {\n        for (let l of s) {\n          let a = i[l].entryPoint;\n          (o[a] = { e: a, h: void 0, o: 'entry-point', s: void 0 }), r.push(a);\n        }\n      }\n      for (; r.length > 0; ) {\n        let l = [];\n        for (let a of r) {\n          let f = t[a];\n\n          for (let u of f.imports) {\n            !u.external &&\n              !Pe.call(o, u.path) &&\n              ((o[u.path] = { e: a, h: u.original, o: u.kind, s: u.with }), l.push(u.path));\n          }\n        }\n        r = l;\n      }\n      return { v: p, E: o };\n    },\n    Oe = (e, t, i) => {\n      let p = e.inputs[t],\n        o = m.activeElement;\n\n      if (!p) {\n        return;\n      }\n      (!Pt || Nl !== e) && ((Nl = e), (Pt = rr(e))),\n        He && o && o.focus && o.tagName === 'A' && (ut = o);\n      let s = m.createElement('div');\n      (s.className = bl),\n        (s.innerHTML =\n          '<h2>' +\n          z(t) +\n          '</h2><p>Original size: <b>' +\n          z(ae(p.bytes)) +\n          '</b>' +\n          (i === null ? '' : '<br>Bundled size: <b>' + z(ae(i)) + '</b>') +\n          (p.format === 'esm'\n            ? '<br>Module format: <b>ESM</b>'\n            : p.format === 'cjs'\n              ? '<br>Module format: <b>CommonJS</b>'\n              : '') +\n          (p.with\n            ? '<br>Import attributes: <b>' +\n              z(\n                Object.entries(p.with)\n                  .map(([r, l]) => (Sl.test(r) ? r : JSON.stringify(r)) + ': ' + JSON.stringify(l))\n                  .join(', ')\n              ) +\n              '</b>'\n            : '') +\n          '</p>'),\n        nr(s, Pt, t);\n      let n = m.createElement('a');\n      (n.className = yl),\n        (n.href = 'javascript:void 0'),\n        (n.onclick = tt),\n        (n.innerHTML = '&times;'),\n        s.append(n),\n        (s.tabIndex = 0),\n        (De.id = gl),\n        (De.innerHTML = ''),\n        De.append(s),\n        (De.onmousedown = (r) => {\n          r.target === De && tt();\n        }),\n        m.body.append(De),\n        s.focus(),\n        (s.onkeydown = (r) => {\n          r.key === 'Escape' &&\n            !r.shiftKey &&\n            !r.metaKey &&\n            !r.ctrlKey &&\n            !r.altKey &&\n            (r.preventDefault(), tt());\n        });\n    },\n    nr = (e, t, i) => {\n      let p = t.E,\n        o = i,\n        s = [{ e: i, x: null }];\n      for (;;) {\n        let a = p[o];\n\n        if (!a) {\n          return;\n        }\n\n        if (o === a.e) {\n          break;\n        }\n        s.push({ e: a.e, x: { e: o, h: a.h, o: a.o, s: a.s } }), (o = a.e);\n      }\n      s.reverse();\n      let n = t.v,\n        r,\n        l = 'Entry point';\n      e.append('This file is included in the bundle because:');\n      for (let a of s) {\n        if (Pe.call(n, a.e)) {\n          let H = m.createElement('div');\n          (r = m.createElement('div')),\n            (r.className = Tl),\n            (H.className = xl),\n            (H.textContent = 'Output file '),\n            H.append(xt(n[a.e])),\n            r.append(H),\n            e.appendChild(r);\n        } else if (!r) {\n          return;\n        }\n        let f = Tt(l + ' '),\n          u = Tt(` is included in the bundle.\n`);\n        r.firstChild &&\n          r.append(`\n`),\n          r.append(f, xt(a.e), u);\n        let N = a.x;\n\n        if (N) {\n          let H = N.h || Zt(N.e) || Kt(N.e, qt(a.e)),\n            x = m.createElement('pre'),\n            P = m.createElement('span');\n          if (((P.className = Pe.call(n, N.e) ? El : vl), N.o === 'import-statement')) {\n            x.append(xe(Lt, 'import '), xe(Ae, JSON.stringify(H))),\n              N.s && (x.append(xe(Lt, ' with ')), Rt(x, N.s)),\n              x.append(';'),\n              (l = 'Imported file');\n          } else if (N.o === 'require-call') {\n            x.append('require(', xe(Ae, JSON.stringify(H)), ');'), (l = 'Required file');\n          } else if (N.o === 'dynamic-import') {\n            x.append('import(', xe(Ae, JSON.stringify(H))),\n              N.s && (x.append(', '), Rt(x, { with: N.s })),\n              x.append(');'),\n              (l = 'Dynamically-imported file');\n          } else if (N.o === 'import-rule') {\n            x.append('@import ', xe(Ae, JSON.stringify(H)), ';'), (l = 'Imported stylesheet');\n          } else if (N.o === 'url-token') {\n            x.append('url(', xe(Ae, JSON.stringify(H)), ')'), (l = 'URL reference');\n          } else {\n            return;\n          }\n          (u.textContent = ` contains:\n`),\n            x.append(\n              P,\n              `\n`\n            ),\n            r.append(x);\n        } else {\n          f.textContent = 'So ' + f.textContent.toLowerCase();\n        }\n      }\n    },\n    Rt = (e, t) => {\n      let i = Object.keys(t);\n      if (i.length === 0) {\n        e.append('{}');\n        return;\n      }\n      e.append('{ ');\n      for (let p = 0; p < i.length; p++) {\n        let o = i[p],\n          s = t[o];\n        p > 0 && e.append(', '),\n          e.append(Sl.test(o) ? o : xe(Ae, JSON.stringify(o)), ': '),\n          typeof s == 'string' ? e.append(xe(Ae, JSON.stringify(s))) : Rt(e, s);\n      }\n      e.append(' }');\n    };\n  var ir = (e) => {\n      let t = e.outputs,\n        i = 0,\n        p = 0,\n        o = [],\n        s,\n        n = (r, l) => {\n          let a = r.n,\n            f = [];\n\n          for (let u in a) {\n            f.push(n(a[u], !1));\n          }\n          return { r: r.r, e: r.e, p: ae(r.t), t: r.t, l: f.sort(ve), g: l };\n        };\n      for (let r in t) {\n        let l = ge(r);\n        l.pop(), (s = Ue(l.join('/'), s));\n      }\n      for (let r in t) {\n        if (Te(r)) {\n          continue;\n        }\n        let a = { r: s ? ge(r).slice(s.length).join('/') : r, e: '', t: 0, n: {} },\n          f = t[r],\n          u = f.inputs,\n          N = f.bytes;\n        for (let H in u) {\n          let x = we(a, Se(H), u[H].bytesInOutput);\n          x > p && (p = x);\n        }\n        (a.t = N), (i += N), o.push(n(a, !0));\n      }\n      e: for (;;) {\n        let r;\n        for (let l of o) {\n          let a = l.l;\n\n          if (!a.length) {\n            continue;\n          }\n\n          if (a.length > 1 || a[0].l.length !== 1) {\n            break e;\n          }\n          let f = a[0].r;\n\n          if (r === void 0) {\n            r = f;\n          } else if (r !== f) {\n            break e;\n          }\n        }\n\n        if (r === void 0) {\n          break;\n        }\n        for (let l of o) {\n          let a = l.l;\n          if (a.length) {\n            a = a[0].l;\n\n            for (let f of a) {\n              f.r = r + f.r;\n            }\n            l.l = a;\n          }\n        }\n        p--;\n      }\n      for (let r of o) {\n        let l = 0;\n\n        for (let a of r.l) {\n          l += a.t;\n        }\n        l < r.t && r.l.push({ r: '(unassigned)', e: '', p: ae(r.t - l), t: r.t - l, l: [], g: !1 });\n      }\n      return o.sort(ve), { u: { r: '', e: '', p: '', t: i, l: o, g: !1 }, b: p + 1 };\n    },\n    Ht = (e, t, i, p, o) => {\n      let s = [],\n        n = (l, a, f, u, N) => {\n          let H = e[l].t * N,\n            x = e[a].t * N;\n          return h.max((f * f * H) / (u * u), (u * u) / (f * f * x));\n        };\n      return (\n        ((l, a, f, u, N) => {\n          for (; l < e.length; ) {\n            let H = 0;\n\n            for (let C = l; C < e.length; C++) {\n              H += e[C].t;\n            }\n            let x = h.min(u, N),\n              P = (u * N) / H,\n              I = l,\n              G = 0,\n              se = 0;\n            for (; I < e.length; ) {\n              let C = e[I].t * P,\n                k = n(l, I, x, G + C, P);\n\n              if (I > l && se < k) {\n                break;\n              }\n              (G += C), (se = k), I++;\n            }\n            let X = h.round(G / x),\n              J = 0;\n            for (let C = l; C < I; C++) {\n              let k = e[C],\n                U = k.t * P,\n                B = h.round((x * J) / G),\n                ee = h.round((x * (J + U)) / G),\n                [D, E, F, j] = u >= N ? [a, f + B, X, ee - B] : [a + B, f, ee - B, X];\n              s.push({\n                f: k,\n                m: [D, E, F, j],\n                n: F > 8 && j > 24 ? Ht(k.l, D + 4, E + 20, F - 8, j - 24) : [],\n              }),\n                (J += U);\n            }\n            (l = I), u >= N ? ((a += X), (u -= X)) : ((f += X), (N -= X));\n          }\n        })(0, t, i, p, o),\n        s\n      );\n    },\n    wl = (e) => {\n      let t = ir(e),\n        i = [],\n        p = m.createElement('div'),\n        o = m.createElement('main'),\n        s = m.createElement('canvas'),\n        n = s.getContext('2d'),\n        r = 0,\n        l = 0,\n        a = null,\n        f = null,\n        u = 0,\n        N = 0,\n        H = '',\n        x = '',\n        P = '14px sans-serif',\n        I = {},\n        G = 'bold ' + P,\n        se = {},\n        X = 0,\n        J = se,\n        C = null,\n        k = null,\n        U = 0,\n        B = 0,\n        ee = 0,\n        D = 1,\n        E = null,\n        F = null,\n        j = () => {\n          if (C) {\n            let [d, c, b, v] = C.m,\n              T = d + b,\n              S = c + v,\n              R = h.round(r / 10),\n              _ = h.round(l / 10),\n              W = r - R - 1,\n              A = l - _ - 1,\n              Q = F ? D : 1 - D,\n              le = h.round(d + (R - d) * Q),\n              pe = h.round(c + (_ - c) * Q),\n              $ = h.round(T + (W - T) * Q),\n              ue = h.round(S + (A - S) * Q),\n              Ne = (jt) => jt - h.floor(jt / 64 - 0.5) * 64;\n            (k = Ht([C.f], le, pe, $ - le, ue - pe)[0]),\n              (U = Ne(-(d + T) / 2) * (1 - Q) + (le + $) / 2),\n              (B = Ne(-(c + S) / 2) * (1 - Q) + (pe + ue) / 2);\n          } else {\n            (k = null), (U = 0), (B = 0);\n          }\n        },\n        Y = () => {\n          let d = r,\n            c = l,\n            b = te.devicePixelRatio || 1;\n          (r = h.min(o.clientWidth, 1600)),\n            (l = h.max(h.round(r / 2), innerHeight - 380)),\n            (s.style.width = r + 'px'),\n            (s.style.height = l + 'px'),\n            (o.style.height = l + 'px'),\n            (s.width = h.round(r * b)),\n            (s.height = h.round(l * b)),\n            n.scale(b, b),\n            (r !== d || l !== c) && ((i = Ht(t.u.l, 0, 0, r - 1, l - 1)), j()),\n            fe();\n        },\n        ce = () => {\n          let d = D,\n            c = C;\n          (D = (Re() - ee) / 350),\n            D < 0 || D > 1\n              ? ((C = F), (D = 1), (a = null))\n              : ((D = 1 - D), (D *= D * D), (D = 1 - D), (a = ie(ce))),\n            (D !== d || C !== c) && j(),\n            fe();\n        },\n        q = () => {\n          a === null && (a = ie(ce));\n        },\n        re = (d) => {\n          let c = J[d];\n          return c === void 0 && ((c = n.measureText(String.fromCharCode(d)).width), (J[d] = c)), c;\n        },\n        K = (d, c) => {\n          if (c < X) {\n            return ['', 0];\n          }\n          let b = 0,\n            v = d.length,\n            T = 0;\n          for (; T < v; ) {\n            let S = re(d.charCodeAt(T));\n\n            if (c < b + X + S) {\n              return [d.slice(0, T) + '...', b + X];\n            }\n            (b += S), T++;\n          }\n          return [d, b];\n        },\n        Z = (d, c) => {\n          let b = d.f,\n            [v, T, S, R] = d.m,\n            _ = (b === f ? 1 : 0) | (d === F ? 2 : 0);\n          if (c === 1 && k) {\n            let [W, A, Q, le] = k.m;\n            v >= W && T >= A && v + S <= W + Q && T + R <= A + le && (c = 2);\n          }\n\n          for (let W of d.n) {\n            _ |= Z(W, c);\n          }\n          return (\n            c !== 2 &&\n              !b.g &&\n              ((n.fillStyle = Je(n, b.e, u, N, 1)),\n              d.n.length\n                ? (n.fillRect(v, T, S, 20),\n                  n.fillRect(v, T + R - 4, S, 4),\n                  n.fillRect(v, T + 20, 4, R - 24),\n                  n.fillRect(v + S - 4, T + 20, 4, R - 24))\n                : n.fillRect(v, T, S, R)),\n            _\n          );\n        },\n        de = (d, c) => {\n          let b = d.f,\n            [v, T, S, R] = d.m,\n            _ = b.g;\n          if (\n            (f === b &&\n              !_ &&\n              (!C || c) &&\n              ((n.fillStyle = 'rgba(255,255,255,0.5)'), n.fillRect(v, T, S, R)),\n            _ || ot(n, '#222', v + 0.5, T + 0.5, S, R),\n            R >= 20)\n          ) {\n            (n.fillStyle = _ ? x : '#000'), _ && ((n.font = G), (J = I), (X = 3 * re(46)));\n            let W = S - 8,\n              A = T + h.round(24 / 2),\n              [Q, le] = K(b.r, W),\n              pe = v + h.round((S - le) / 2);\n            if ((_ && ((n.font = P), (J = se), (X = 3 * re(46))), Q === b.r && b.l.length)) {\n              let $ = ' \\u2013 ' + (me === 2 ? Ee(b.e, '') : b.p),\n                [ue, Ne] = K($, W - le);\n              (pe = v + h.round((S - le - Ne) / 2)),\n                (n.globalAlpha = 0.5),\n                n.fillText(ue, pe + le, A),\n                (n.globalAlpha = 1);\n            }\n            if (\n              (_ && ((n.font = G), (J = I), (X = 3 * re(46))),\n              n.fillText(Q, pe, A),\n              _ && ((n.font = P), (J = se), (X = 3 * re(46))),\n              R > 40 && !b.l.length)\n            ) {\n              let $ = me === 2 ? Ee(b.e, '') : b.p,\n                [ue, Ne] = K($, W);\n              (n.globalAlpha = 0.5),\n                n.fillText(ue, v + h.round((S - Ne) / 2), T + 20 + h.round(R - 24) / 2),\n                (n.globalAlpha = 1);\n            }\n\n            for (let $ of d.n) {\n              de($, c);\n            }\n          }\n        },\n        fe = () => {\n          let d = getComputedStyle(m.body);\n          (H = d.getPropertyValue('--bg')),\n            (x = d.getPropertyValue('--fg-on')),\n            (a = null),\n            n.clearRect(0, 0, r, l),\n            (n.textBaseline = 'middle'),\n            (X = n.measureText('...').width);\n          let c = null,\n            b = null,\n            v = k ? (E ? (F ? 1 : 1 - D) : D) : 0;\n          u = N = 0;\n          for (let T of i) {\n            let S = Z(T, 1);\n            S & 1 && (c = T), S & 2 && (b = T);\n          }\n\n          for (let T of i) {\n            if ((de(T, !1), k || (c && T !== c))) {\n              let [S, R, _, W] = T.m;\n              (n.globalAlpha = 0.6 * (!k || (!E && b && T !== b) ? 1 : v)),\n                (n.fillStyle = H),\n                n.fillRect(S, R, _, W),\n                (n.globalAlpha = 1);\n            }\n          }\n          if (k) {\n            let [T, S, R, _] = k.m,\n              W = n.getTransform(),\n              A = h.sqrt(W.a * W.d);\n            n.save(),\n              (n.shadowColor = 'rgba(0,0,0,0.5)'),\n              (n.shadowBlur = A * (30 * v)),\n              (n.shadowOffsetX = A * (2 * r)),\n              (n.shadowOffsetY = A * (2 * l + 15 * v)),\n              n.fillRect(T - 2 * r, S - 2 * l, R, _),\n              n.restore(),\n              (u = U),\n              (N = B),\n              Z(k, 0),\n              de(k, !0);\n          }\n        },\n        ne = m.createElement('div'),\n        Le = (d, c, b) => {\n          (ne.style.display = 'block'),\n            (ne.style.left = d + 'px'),\n            (ne.style.top = c + 'px'),\n            (ne.innerHTML = b);\n          let v = ne.offsetWidth;\n\n          for (let T = ne; T; T = T.offsetParent) {\n            v += T.offsetLeft;\n          }\n          v > r && (ne.style.left = d + r - v + 'px');\n        },\n        y = () => {\n          ne.style.display = 'none';\n        },\n        w = (d) => {\n          let c = (T, S) => {\n              for (let R of T) {\n                let [_, W, A, Q] = R.m;\n\n                if (b >= _ && v >= W && b < _ + A && v < W + Q) {\n                  return c(R.n, !1) || (S ? null : R);\n                }\n              }\n              return null;\n            },\n            b = d.pageX,\n            v = d.pageY;\n\n          for (let T = s; T; T = T.offsetParent) {\n            (b -= T.offsetLeft), (v -= T.offsetTop);\n          }\n          return k ? c([k], !1) : c(i, !0);\n        },\n        L = (d) => {\n          let c = w(d);\n\n          if ((O(c && c.f), c)) {\n            let b = c.f,\n              v = b.r === b.e ? We(b.e) : b.e,\n              T = v.length - b.r.length;\n            (v = z(v.slice(0, T)) + '<b>' + z(v.slice(T)) + '</b>'),\n              (v += me === 2 ? z(Ee(b.e, ' \\u2013 ')) : ' \\u2013 ' + z(ae(b.t))),\n              Le(d.pageX, d.pageY + 20, v);\n          } else {\n            y();\n          }\n        },\n        O = (d) => {\n          f !== d && ((f = d), (s.style.cursor = d && !d.l.length ? 'pointer' : 'auto'), q());\n        },\n        M = (d, c) => {\n          for (let b of d) {\n            let v = b.f === c ? b : M(b.n, c);\n\n            if (v) {\n              return v;\n            }\n          }\n          return null;\n        },\n        V = (d) => {\n          C !== d && ((D = 0), (ee = Re()), (E = C), (F = d), (C = d || M(i, C.f)), j(), q());\n        };\n      (s.onmousemove = (d) => {\n        L(d);\n      }),\n        (s.onmouseout = (d) => {\n          O(null), y();\n        }),\n        (p.onclick = (d) => {\n          let c = w(d);\n\n          if (c) {\n            let b = c.f;\n            b.l.length ? (c !== k ? (V(c), O(null), y()) : L(d)) : (Oe(e, b.e, b.t), L(d));\n          } else {\n            C && (V(null), L(d));\n          }\n        }),\n        je((d) => {\n          Ze() || L(d);\n        }),\n        Y(),\n        Promise.resolve().then(Y),\n        Xe(fe),\n        $e(fe),\n        Ye(Y),\n        (p.id = hl),\n        (p.innerHTML = `<div class=\"${Be}\"><p>This visualization shows which input files were placed into each output file in the bundle. Click on a node to expand and focus it.</p><p><b>Benefit of this chart type:</b> Makes the most of available screen area.</p></div>`),\n        (ne.className = ze),\n        o.append(s),\n        p.append(o, ne);\n      let g = m.createElement('section');\n      return g.append(Me), p.append(g), p;\n    };\n  var Ml = 'y',\n    Il = 'z',\n    Ol = 'F',\n    Cl = 'P',\n    Ll = 'C',\n    Pl = 'S',\n    At = 'j';\n  var Rl = 't',\n    Dt = 'M',\n    Ft = 'N',\n    Hl = 'q',\n    kl = 'T';\n  var Al = (e, t) => {\n      for (; t; ) {\n        if (t === e) {\n          return !0;\n        }\n        t = t.i;\n      }\n      return !1;\n    },\n    ar = (e) => {\n      let t = e.inputs,\n        i = e.outputs,\n        p = { r: '', e: '', t: 0, n: {} },\n        o = (r) => {\n          let l = r.n,\n            a = [];\n\n          for (let f in l) {\n            a.push(o(l[f]));\n          }\n          return { e: r.e, t: r.t, l: a.sort(ve), i: null };\n        },\n        s = (r, l) => {\n          let a = 0;\n          for (let f of r.l) {\n            let u = s(f, l + 1);\n            (f.i = r), u > a && (a = u);\n          }\n          return a + 1;\n        };\n\n      for (let r in t) {\n        we(p, Se(r), 0);\n      }\n      for (let r in i) {\n        if (Te(r)) {\n          continue;\n        }\n        let a = i[r].inputs;\n\n        for (let f in a) {\n          we(p, Se(f), a[f].bytesInOutput);\n        }\n      }\n      let n = o(p);\n\n      for (; n.l.length === 1; ) {\n        n = n.l[0];\n      }\n      return { u: n, b: s(n, 0) };\n    },\n    _t = (e, t, i) => {\n      if (e === t) {\n        return;\n      }\n      let p = t.i,\n        o = p.t || 1,\n        s = 0;\n      _t(e, p, i);\n      for (let n of p.l) {\n        if (n === t) {\n          (i.y += (i.c * s) / o), (i.c = (n.t / o) * i.c);\n          break;\n        }\n        s += n.t;\n      }\n      i.T += 1;\n    },\n    Qe = (e) => 50 * 8 * h.log(1 + h.log(1 + e / 8)),\n    Dl = (e) => {\n      let t = m.createElement('div'),\n        i = m.createElement('main'),\n        p = ar(e),\n        o = p.u,\n        s = null,\n        n = (x) => {\n          o !== x && ((o = x), u(), H());\n        },\n        r = (x) => {\n          s !== x && ((s = x), u(), H());\n        },\n        l = () => {\n          let x = m.createElement('div'),\n            P = m.createElement('canvas'),\n            I = P.getContext('2d'),\n            G = () => {\n              let g = 2 * h.ceil(Qe(p.b)),\n                d = te.devicePixelRatio || 1;\n              (C = h.min(h.round(innerWidth * 0.4), g)),\n                (k = C),\n                (U = C >> 1),\n                (B = k >> 1),\n                (P.style.width = C + 'px'),\n                (P.style.height = k + 'px'),\n                (P.width = h.round(C * d)),\n                (P.height = h.round(k * d)),\n                I.scale(d, d),\n                X();\n            },\n            se = (g, d, c, b, v, T, S) => {\n              let R = Qe(d + 1);\n\n              if (R > B) {\n                return S;\n              }\n              g === s && (T |= 8);\n              let _ = (c + R) / 2,\n                W = b + v;\n\n              if (W - S < 1.5 / _) {\n                return S;\n              }\n              let A = 2 / _;\n\n              if ((v > A && (A = v), T & 2)) {\n                (I.fillStyle = Je(I, g.e, U, B, 1)),\n                  I.beginPath(),\n                  I.arc(U, B, c, b, b + A, !1),\n                  I.arc(U, B, R, b + A, b, !0),\n                  I.fill(),\n                  s &&\n                    (T & 8 || g.i === s) &&\n                    ((I.fillStyle = 'rgba(255, 255, 255, 0.3)'), I.fill());\n              } else {\n                let ue = A === h.PI * 2,\n                  Ne = T & 4 || ue ? R : c;\n                T & 1 && c > 0 && I.arc(U, B, c, b + A, b, !0),\n                  I.moveTo(U + Ne * h.cos(b), B + Ne * h.sin(b)),\n                  I.arc(U, B, R, b, b + A, !1),\n                  ue || I.lineTo(U + c * h.cos(b + A), B + c * h.sin(b + A));\n              }\n              let Q = g.t,\n                le = T & 10,\n                pe = 0,\n                $ = -1 / 0;\n\n              for (let ue of g.l) {\n                ($ = se(ue, d + 1, R, b + (v * pe) / Q, (ue.t / Q) * v, le, $)),\n                  (pe += ue.t),\n                  (le |= 4);\n              }\n              return W;\n            },\n            X = () => {\n              I.clearRect(0, 0, C, k),\n                se(K, Z, Qe(Z), de, fe, 3, -1 / 0),\n                (I.strokeStyle = '#222'),\n                I.beginPath(),\n                se(K, Z, Qe(Z), de, fe, 1, -1 / 0),\n                I.stroke(),\n                Z === 0 &&\n                  ((I.fillStyle = '#222'),\n                  (I.font = 'bold 16px sans-serif'),\n                  (I.textAlign = 'center'),\n                  (I.textBaseline = 'middle'),\n                  I.fillText(ae(Y.t), U, B));\n            },\n            J = -h.PI / 2,\n            C = 0,\n            k = 0,\n            U = 0,\n            B = 0,\n            ee = null,\n            D = 0,\n            E = 0,\n            F = J,\n            j = h.PI * 2,\n            Y = o,\n            ce = E,\n            q = F,\n            re = j,\n            K = o,\n            Z = E,\n            de = F,\n            fe = j,\n            ne = (g) => {\n              let d = (S, R, _, W, A) => {\n                  let Q = Qe(R + 1);\n\n                  if (Q > B) {\n                    return null;\n                  }\n                  if (v >= _ && v < Q) {\n                    let $ = T - W;\n\n                    if ((($ /= h.PI * 2), ($ -= h.floor($)), ($ *= h.PI * 2), $ < A)) {\n                      return S === K ? S.i : S;\n                    }\n                  }\n                  let le = S.t,\n                    pe = 0;\n                  for (let $ of S.l) {\n                    let ue = d($, R + 1, Q, W + (A * pe) / le, ($.t / le) * A);\n\n                    if (ue) {\n                      return ue;\n                    }\n                    pe += $.t;\n                  }\n                  return null;\n                },\n                c = g.pageX,\n                b = g.pageY;\n\n              for (let S = P; S; S = S.offsetParent) {\n                (c -= S.offsetLeft), (b -= S.offsetTop);\n              }\n              (c -= U), (b -= B);\n              let v = h.sqrt(c * c + b * b),\n                T = h.atan2(b, c);\n              return d(K, Z, Qe(Z), de, fe);\n            },\n            Le = () => {\n              let g = (Re() - D) / 350;\n              g < 0 || g > 1\n                ? ((g = 1), (ee = null), (K = Y), (ce = 0), (q = J), (re = h.PI * 2))\n                : (g < 0.5 ? (g *= 4 * g * g) : ((g = 1 - g), (g *= 4 * g * g), (g = 1 - g)),\n                  (ee = ie(Le))),\n                (Z = E + (ce - E) * g),\n                (de = F + (q - F) * g),\n                (fe = j + (re - j) * g),\n                X();\n            },\n            y = m.createElement('div'),\n            w = (g, d, c) => {\n              (y.style.display = 'block'),\n                (y.style.left = g + 'px'),\n                (y.style.top = d + 'px'),\n                (y.innerHTML = c);\n            },\n            L = () => {\n              y.style.display = 'none';\n            },\n            O = null,\n            M = [],\n            V = (g) => {\n              let d = ne(g);\n\n              if ((r(d), d && d !== K.i)) {\n                let c = d.e;\n                if (d.i && d.i.e !== '') {\n                  let b = d.i.e.length;\n                  c = z(c.slice(0, b)) + '<b>' + z(c.slice(b)) + '</b>';\n                } else {\n                  c = '<b>' + z(We(c)) + '</b>';\n                }\n                me === 2 ? (c += z(Ee(d.e, ' \\u2013 '))) : (c += ' \\u2013 ' + z(ae(d.t))),\n                  w(g.pageX, g.pageY + 20, c),\n                  (P.style.cursor = 'pointer');\n              } else {\n                L();\n              }\n            };\n          return (\n            G(),\n            Xe(X),\n            Ye(G),\n            je((g) => {\n              Ze() || V(g);\n            }),\n            (P.onmousemove = (g) => {\n              V(g);\n            }),\n            (P.onmouseout = () => {\n              r(null), L();\n            }),\n            (P.onclick = (g) => {\n              let d = ne(g);\n\n              if (!d) {\n                return;\n              }\n              L();\n              let c = [];\n              d !== K.i ? (c = M.concat(o)) : M.length > 0 && ((d = M.pop()), (c = M.slice())),\n                d.l.length > 0 ? (n(d), (M = c)) : (g.preventDefault(), Oe(e, d.e, d.t));\n            }),\n            (x.className = Il),\n            x.append(P, Me),\n            (y.className = ze),\n            i.append(y, x),\n            [\n              X,\n              () => {\n                if (\n                  (O !== s &&\n                    ((O = s), s || ((P.style.cursor = 'auto'), L()), ee === null && (ee = ie(Le))),\n                  Y !== o)\n                ) {\n                  if (((M.length = 0), ee === null && (ee = ie(Le)), (D = Re()), Al(K, o))) {\n                    let g = { T: Z, y: de, c: fe };\n                    _t(K, o, g),\n                      (Z = g.T),\n                      (de = g.y),\n                      (fe = g.c),\n                      (ce = 0),\n                      (q = J),\n                      (re = h.PI * 2),\n                      (K = o);\n                  } else if (Al(o, K)) {\n                    let g = { T: 0, y: J, c: h.PI * 2 };\n                    _t(o, K, g), (ce = g.T), (q = g.y), (re = g.c);\n                  } else {\n                    (D = -1 / 0), (K = o);\n                  }\n                  (E = Z), (F = de), (j = fe), (Y = o);\n                }\n              },\n            ]\n          );\n        },\n        a = () => {\n          let x = m.createElement('div'),\n            P = () => {\n              let C = o.i,\n                k = o.l,\n                U = m.createElement('div'),\n                B = 1;\n              U.className = Pl;\n              for (let E of k) {\n                let F = E.t;\n                F > B && (B = F);\n              }\n              if (((I.length = 0), (G.length = 0), C)) {\n                let E = m.createElement('a');\n                (E.className = At), (E.tabIndex = 0), U.append(E);\n                let F = m.createElement('div');\n                (F.className = Dt), E.append(F);\n                let j = m.createElement('div');\n                (j.className = Ft),\n                  E.append(j),\n                  (E.href = 'javascript:void 0'),\n                  (F.textContent = '../'),\n                  (E.onclick = () => {\n                    n(C), He && G.length > 0 && G[0].focus();\n                  }),\n                  (E.onfocus = E.onmouseover = () => r(C)),\n                  (E.onblur = E.onmouseout = () => r(null)),\n                  I.push(C),\n                  G.push(E);\n              }\n              for (let E of k) {\n                let F = E.e.slice(o.e.length),\n                  j = ae(E.t),\n                  Y = m.createElement('a');\n                (Y.className = At), (Y.tabIndex = 0), U.append(Y);\n                let ce = m.createElement('div');\n                (ce.className = Dt), (ce.innerHTML = z(F === E.e ? We(F) : F)), Y.append(ce);\n                let q = m.createElement('div');\n                (q.className = Ft), Y.append(q);\n                let re = m.createElement('div'),\n                  K = sl(E.e);\n                (re.className = Rl + (E.t ? '' : ' ' + Hl)),\n                  (re.style.background = K),\n                  (re.style.width = (100 * E.t) / B + '%'),\n                  q.append(re);\n                let Z = m.createElement('div');\n                (Z.className = kl),\n                  (Z.textContent = me === 2 ? Ee(E.e, '') : j),\n                  re.append(Z),\n                  (Y.href = 'javascript:void 0'),\n                  (Y.onclick = (de) => {\n                    de.preventDefault(),\n                      E.l.length > 0 ? (n(E), He && G.length > 0 && G[0].focus()) : Oe(e, E.e, E.t);\n                  }),\n                  (Y.onfocus = Y.onmouseover = () => r(E)),\n                  (Y.onblur = Y.onmouseout = () => r(null)),\n                  I.push(E),\n                  G.push(Y);\n              }\n              let ee = m.createElement('div');\n              (ee.className = Cl), (ee.textContent = 'Directory: ');\n              let D = m.createElement('div');\n              (D.className = Ll), ee.append(D);\n              for (let E = o; E; E = E.i) {\n                let F = E.e || '/',\n                  j = m.createElement('a');\n                E.i && (F = F.slice(E.i.e.length)),\n                  (j.textContent = F),\n                  E !== o &&\n                    ((j.href = 'javascript:void 0'),\n                    (j.onclick = (Y) => {\n                      Y.preventDefault(),\n                        n(E),\n                        He && G.length > 0 && G[!I[0] && G.length > 1 ? 1 : 0].focus();\n                    })),\n                  D.insertBefore(j, D.firstChild),\n                  o == p.u && ((j.tabIndex = -1), I.unshift(o), G.unshift(j));\n              }\n              (x.innerHTML = ''), x.append(ee, U);\n            },\n            I = [],\n            G = [],\n            se = o,\n            X = null,\n            J = null;\n          return (\n            (x.className = Ol),\n            i.append(x),\n            P(),\n            [\n              P,\n              () => {\n                if ((se !== o && ((se = o), P()), X !== s)) {\n                  (X = s), J && (J.classList.remove('hover'), (J = null));\n                  for (let C = s; C; C = C.i) {\n                    let k = I.indexOf(C);\n                    if (k >= 0) {\n                      (J = G[k]), J.classList.add('hover');\n                      break;\n                    }\n                  }\n                }\n              },\n            ]\n          );\n        },\n        [f, u] = l(),\n        [N, H] = a();\n      return (\n        $e(() => {\n          f(), N();\n        }),\n        (t.id = Ml),\n        (t.innerHTML = `<div class=\"${Be}\"><p>This visualization shows how much space each input file takes up in the final bundle. Input files that take up 0 bytes have been completely eliminated by tree-shaking.</p><p><b>Benefit of this chart type:</b> Can be navigated with the keyboard.</p></div>`),\n        t.append(i),\n        t\n      );\n    };\n  var Fl = 'A';\n  var pr = (e) => {\n      let t = e.outputs,\n        i = 0,\n        p = 0,\n        o = [],\n        s,\n        n = (l) => ' \\u2013 ' + ae(l),\n        r = (l) => {\n          let a = l.n,\n            f = [];\n\n          for (let u in a) {\n            f.push(r(a[u]));\n          }\n          return { r: l.r, e: l.e, p: n(l.t), t: l.t, l: f.sort(ve) };\n        };\n      for (let l in t) {\n        let a = ge(l);\n        a.pop(), (s = Ue(a.join('/'), s));\n      }\n      for (let l in t) {\n        if (Te(l)) {\n          continue;\n        }\n        let f = { r: s ? ge(l).slice(s.length).join('/') : l, e: '', t: 0, n: {} },\n          u = t[l],\n          N = u.inputs,\n          H = u.bytes;\n        for (let x in N) {\n          let P = we(f, Se(x), N[x].bytesInOutput);\n          P > p && (p = P);\n        }\n        (f.t = H), (i += H), o.push(r(f));\n      }\n      e: for (;;) {\n        let l;\n        for (let a of o) {\n          let f = a.l;\n\n          if (!f.length) {\n            continue;\n          }\n\n          if (f.length > 1 || f[0].l.length !== 1) {\n            break e;\n          }\n          let u = f[0].r;\n\n          if (l === void 0) {\n            l = u;\n          } else if (l !== u) {\n            break e;\n          }\n        }\n\n        if (l === void 0) {\n          break;\n        }\n        for (let a of o) {\n          let f = a.l;\n          if (f.length) {\n            f = f[0].l;\n\n            for (let u of f) {\n              u.r = l + u.r;\n            }\n            a.l = f;\n          }\n        }\n        p--;\n      }\n      for (let l of o) {\n        let a = 0;\n\n        for (let f of l.l) {\n          a += f.t;\n        }\n        a < l.t && l.l.push({ r: '(unassigned)', e: '', p: n(l.t - a), t: l.t - a, l: [] });\n      }\n      return o.sort(ve), { u: { r: '', e: '', p: '', t: i, l: o }, b: p + 1 };\n    },\n    _l = (e) => {\n      let t = pr(e),\n        i = t.u.t,\n        p = 0,\n        o = i,\n        s = m.createElement('div'),\n        n = m.createElement('main'),\n        r = m.createElement('canvas'),\n        l = r.getContext('2d'),\n        a = 0,\n        f = 0,\n        u = 0,\n        N = 0,\n        H = 0,\n        x = !1,\n        P = 1,\n        I = null,\n        G = null,\n        se = '',\n        X = '14px sans-serif',\n        J = {},\n        C = 'bold ' + X,\n        k = {},\n        U = 0,\n        B = k,\n        ee = (y) => {\n          G !== y &&\n            ((G = y), (r.style.cursor = y && !y.l.length ? 'pointer' : 'auto'), y || K(), ce());\n        },\n        D = (y) => {\n          let w = B[y];\n          return w === void 0 && ((w = l.measureText(String.fromCharCode(y)).width), (B[y] = w)), w;\n        },\n        E = () => {\n          let y = te.devicePixelRatio || 1;\n          (a = s.clientWidth + 2 * 50),\n            (f = t.b * 24 + 1),\n            (u = (a - 1e3) >> 1),\n            (N = u + 1e3),\n            u < 0 && (u = 0),\n            N > a && (N = a),\n            (N -= u),\n            (P = i / N),\n            (r.style.width = a + 'px'),\n            (r.style.height = f + 'px'),\n            (n.style.height = f + 'px'),\n            (r.width = h.round(a * y)),\n            (r.height = h.round(f * y)),\n            l.scale(y, y),\n            Y();\n        },\n        F = (y, w) => {\n          let L = U,\n            O = y.length,\n            M = 0;\n\n          for (; M < O && ((L += D(y.charCodeAt(M))), !(L > w)); ) {\n            M++;\n          }\n          return y.slice(0, M) + '...';\n        },\n        j = (y, w, L, O, M) => {\n          let V = N / (o - p),\n            g = u + (L - p) * V,\n            d = y.t * V,\n            c = g + d;\n\n          if (c < O + 1.5) {\n            return O;\n          }\n\n          if (g + d < 0 || g > a) {\n            return c;\n          }\n          let b = d < 2 ? 2 : d,\n            v = (g > 0 ? g : 0) + 5,\n            T = w + 24 / 2,\n            S = '',\n            R = '',\n            _,\n            W = 0,\n            A = d + g - v,\n            Q = y.e ? Je(l, y.e, u - p * V, 24, V * P) : ke,\n            le = 'black',\n            pe = -1 / 0;\n          M & 1\n            ? ((le = se), (l.font = C), (B = J), (U = 3 * D(46)))\n            : ((l.fillStyle = Q),\n              l.fillRect(g, w, b, 24),\n              (M & 2 || (G && y.e === G.e)) &&\n                ((l.fillStyle = 'rgba(255, 255, 255, 0.3)'), l.fillRect(g, w, b, 24), (M |= 2))),\n            U < A &&\n              ((S = y.r),\n              (_ = l.measureText(S).width),\n              _ <= A ? (W += _) : ((S = F(S, A)), (W = A)),\n              (l.fillStyle = le),\n              l.fillText(S, v, T)),\n            M & 1 && ((l.font = X), (B = k), (U = 3 * D(46))),\n            W + U < A &&\n              ((R = me === 2 ? Ee(y.e, ' \\u2013 ') : y.p),\n              (_ = l.measureText(R).width),\n              W + _ > A && (R = F(R, A - W)),\n              (l.globalAlpha = 0.5),\n              l.fillText(R, v + W, T),\n              (l.globalAlpha = 1));\n\n          for (let $ of y.l) {\n            (pe = j($, w + 24, L, pe, M & -2)), (L += $.t);\n          }\n          return M & 1 || ot(l, '#222', g + 0.5, w + 0.5, b, 24), c;\n        },\n        Y = () => {\n          let y = getComputedStyle(m.body),\n            w = 0,\n            L = -1 / 0;\n          (I = null),\n            (se = y.getPropertyValue('--fg-on')),\n            l.clearRect(0, 0, a, f),\n            (l.textBaseline = 'middle');\n\n          for (let O of t.u.l) {\n            (L = j(O, 0, w, L, 1)), (w += O.t);\n          }\n        },\n        ce = () => {\n          I === null && (I = ie(Y));\n        },\n        q = m.createElement('div'),\n        re = (y, w, L) => {\n          (q.style.display = 'block'),\n            (q.style.left = y + 'px'),\n            (q.style.top = w + 'px'),\n            (q.innerHTML = L);\n          let O = q.offsetWidth;\n\n          for (let M = q; M; M = M.offsetParent) {\n            O += M.offsetLeft;\n          }\n          O > a && (q.style.left = y + a - O + 'px');\n        },\n        K = () => {\n          q.style.display = 'none';\n        },\n        Z = (y) => {\n          let w = (g, d, c) => {\n              if (M >= c && M < c + g.t) {\n                if (O >= d && O < d + 24 && g.e) {\n                  return g;\n                }\n\n                if (O >= d + 24) {\n                  for (let b of g.l) {\n                    let v = w(b, d + 24, c);\n                    if (v) {\n                      return v;\n                    }\n                    c += b.t;\n                  }\n                }\n              }\n              return null;\n            },\n            L = y.pageX,\n            O = y.pageY;\n\n          for (let g = r; g; g = g.offsetParent) {\n            (L -= g.offsetLeft), (O -= g.offsetTop);\n          }\n          let M = p + ((o - p) / N) * (L - u),\n            V = 0;\n          for (let g of t.u.l) {\n            let d = w(g, 0, V);\n\n            if (d) {\n              return d;\n            }\n            V += g.t;\n          }\n          return null;\n        },\n        de = (y, w, L) => {\n          let O = p,\n            M = o,\n            V = 0;\n\n          if (L !== null) {\n            let g = O + ((M - O) / N) * (L - u),\n              d = h.pow(1.01, w);\n            (O = g + (O - g) * d), (M = g + (M - g) * d);\n          } else {\n            V = (y * (M - O)) / N;\n          }\n          O + V < 0 ? (V = -O) : M + V > i && (V = i - M),\n            (O += V),\n            (M += V),\n            O < 0 && (O = 0),\n            M > i && (M = i),\n            (p !== O || o !== M) && ((p = O), (o = M), ce());\n        },\n        fe = (y) => {\n          let w = Z(y);\n\n          if ((ee(w), w)) {\n            let L = w.r === w.e ? We(w.e) : w.e,\n              O = L.length - w.r.length;\n            (L = z(L.slice(0, O)) + '<b>' + z(L.slice(O)) + '</b>'),\n              (L += me === 2 ? z(Ee(w.e, ' \\u2013 ')) : ' \\u2013 ' + z(ae(w.t))),\n              re(y.pageX, y.pageY + 20, L);\n          } else {\n            K();\n          }\n        },\n        ne = !1;\n      (r.onmousedown = (y) => {\n        if (((ne = !1), y.button !== 2)) {\n          let w = y.pageX,\n            L = (M) => {\n              let V = M.pageX - w;\n              (!ne && h.abs(V) < 3) || ((ne = !0), de(-V, 0, null), (w = M.pageX));\n            },\n            O = () => {\n              m.removeEventListener('mousemove', L), m.removeEventListener('mouseup', O);\n            };\n          y.preventDefault(), m.addEventListener('mousemove', L), m.addEventListener('mouseup', O);\n        }\n      }),\n        (r.onmousemove = (y) => {\n          fe(y);\n        }),\n        (r.onmouseout = (y) => {\n          ee(null);\n        }),\n        (r.onclick = (y) => {\n          if (ne) {\n            return;\n          }\n          let w = Z(y);\n          ee(w), w && !w.l.length && Oe(e, w.e, w.t);\n        }),\n        je((y) => {\n          if (Ze()) {\n            return;\n          }\n          let w = y.deltaX,\n            L = y.deltaY,\n            O = Re(),\n            M = O - H < 50 ? x : y.ctrlKey || y.metaKey;\n          (H = O),\n            (x = M),\n            (M || h.abs(w) >= h.abs(L)) && y.preventDefault(),\n            de(w, L, M ? y.pageX : null),\n            fe(y);\n        }),\n        E(),\n        Promise.resolve().then(E),\n        Xe(Y),\n        $e(Y),\n        Ye(E),\n        (s.id = Fl),\n        (s.innerHTML =\n          `<div class=\"${Be}\"><p>This visualization shows which input files were placed into each output file in the bundle. Use the scroll wheel with the ` +\n          ($t ? 'command' : 'control') +\n          ' key to zoom in and out.</p><p><b>Benefit of this chart type:</b> Best chart for quick mouse navigation.</p></div>'),\n        (q.className = ze),\n        n.append(r),\n        s.append(n, q);\n      let Le = m.createElement('section');\n      return Le.append(Me), s.append(Le), s;\n    };\n  var Wl = 'B',\n    Bl = 'D',\n    zl = 'E',\n    Wt = 'G';\n  var Gl,\n    fr = (e) => {\n      let t = e.inputs,\n        i = {},\n        p = [];\n      for (let o in t) {\n        let s = t[o];\n\n        for (let n of s.imports) {\n          if (n.original && n.original[0] !== '.') {\n            let r = i[n.original] || (i[n.original] = []);\n            r.includes(n.path) || r.push(n.path);\n          }\n        }\n      }\n      for (let o in i) {\n        let s = i[o];\n        if (s.length > 1) {\n          let n = m.createElement('div'),\n            r = m.createElement('ul'),\n            l,\n            a;\n          (n.className = zl),\n            (n.innerHTML =\n              'The import path <code>' +\n              z(o) +\n              '</code> resolves to multiple files in the bundle:');\n\n          for (let f of s) {\n            l = Ue(f, l);\n          }\n          for (let f of s) {\n            let u = ge(f);\n            l && (u = u.slice(l.length)), (a = Jt(u.join('/'), a));\n          }\n          for (let f of s.sort()) {\n            let u = ge(f).map(z),\n              N = m.createElement('li'),\n              H = '<pre><a href=\"javascript:void 0\">',\n              x = '';\n            l &&\n              l.length &&\n              ((H += `<span class=\"${Wt}\">` + u.slice(0, l.length).join('/') + '/</span>'),\n              (u = u.slice(l.length))),\n              a &&\n                a.length &&\n                ((x =\n                  `<span class=\"${Wt}\">` +\n                  (u.length > a.length ? '/' : '') +\n                  u.slice(u.length - a.length).join('/') +\n                  '</span>'),\n                (u.length -= a.length)),\n              (N.innerHTML = H + '<b>' + u.join('/') + '</b>' + x + '</a></pre>'),\n              r.append(N),\n              (N.querySelector('a').onclick = () => {\n                Oe(e, f, null);\n              });\n          }\n          n.append(r), p.push(n);\n        }\n      }\n      return p;\n    },\n    Ul = (e) => {\n      if (Gl === e) {\n        return;\n      }\n      Gl = e;\n      let t = m.getElementById('warningsPanel'),\n        i = fr(e),\n        p = i.length;\n\n      if (p) {\n        t.innerHTML =\n          `<div class=\"${Wl}\">\\u26A0\\uFE0F This bundle has <b><a href=\"javascript:void 0\">` +\n          p +\n          ' warning' +\n          (p === 1 ? '' : 's') +\n          '</a></b><span>.</span></div>';\n        let o = t.querySelector('span'),\n          s = m.createElement('div');\n        s.className = Bl;\n        for (let n of i) {\n          s.append(n);\n        }\n        t.append(s),\n          (t.querySelector('a').onclick = () => {\n            s.style.display === 'block'\n              ? ((o.textContent = '.'), (s.style.display = 'none'))\n              : ((o.textContent = ':'), (s.style.display = 'block'));\n          });\n      } else {\n        t.innerHTML = '';\n      }\n    };\n  var mr = m.getElementById('startPanel'),\n    cr = m.getElementById('resultsPanel'),\n    mt = m.getElementById('chartPanel'),\n    Bt = m.getElementById('useTreemap'),\n    zt = m.getElementById('useSunburst'),\n    Gt = m.getElementById('useFlame'),\n    Ce = 0,\n    me = 0,\n    Ut = (e) => typeof e == 'object' && e !== null && !(e instanceof Array),\n    et = (e) => {\n      let t = JSON.parse(e),\n        i = (o) => {\n          Ce !== o &&\n            (Ce === 1\n              ? Bt.classList.remove(Fe)\n              : Ce === 2\n                ? zt.classList.remove(Fe)\n                : Ce === 3 && Gt.classList.remove(Fe),\n            (Ce = o),\n            (mt.innerHTML = ''),\n            Ce === 1\n              ? (mt.append(wl(t)), Bt.classList.add(Fe), nt('chart', 'treemap'))\n              : Ce === 2\n                ? (mt.append(Dl(t)), zt.classList.add(Fe), nt('chart', 'sunburst'))\n                : Ce === 3 && (mt.append(_l(t)), Gt.classList.add(Fe), nt('chart', 'flame')));\n        },\n        p = (o) => {\n          me !== o && ((me = o), dl(t, me));\n        };\n\n      if (!Ut(t) || !Ut(t.inputs) || !Ut(t.outputs)) {\n        throw new Error('Invalid metafile format');\n      }\n      (mr.style.display = 'none'),\n        (cr.style.display = 'block'),\n        (Bt.onclick = () => i(1)),\n        (zt.onclick = () => i(2)),\n        (Gt.onclick = () => i(3)),\n        (Ce = 0),\n        (me = 0),\n        cl(t, () => p(me === 1 ? 2 : 1)),\n        Ul(t),\n        tt(),\n        i(rt('chart') === 'flame' ? 3 : rt('chart') === 'sunburst' ? 2 : 1),\n        p(1);\n    },\n    hr = m.documentElement.dataset,\n    jl = () => {\n      (hr.theme = rt('theme') + ''), Ge && Ge();\n    };\n  jl();\n  te.addEventListener('storage', jl);\n  m.getElementById('loadExample').onclick = () => {\n    fetch('example-metafile.json')\n      .then((e) => e.text())\n      .then(et);\n  };\n  if (location.hash !== '') {\n    try {\n      et(atob(location.hash.slice(1)));\n    } catch (e) {}\n    try {\n      history.replaceState({}, '', location.pathname);\n    } catch (e) {}\n  }\n\n  /*\n  Additional code for Storybook to load the metafile from the parent window.\n  The story sets this global variable to the metafile in a beforeEach hook.\n  */\n  if (parent.metafile) {\n    et(parent.metafile);\n  }\n})();\n"
  },
  {
    "path": "code/.storybook/isChromatic.ts",
    "content": "export function isChromatic(windowArg?: any) {\n  const windowToCheck = windowArg || (typeof window !== 'undefined' && window);\n  return !!(\n    windowToCheck &&\n    (windowToCheck.navigator.userAgent.match(/Chromatic/) ||\n      windowToCheck.location.href.match(/chromatic=true/))\n  );\n}\n"
  },
  {
    "path": "code/.storybook/main.ts",
    "content": "import { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { defineMain } from '@storybook/react-vite/node';\n\nimport react from '@vitejs/plugin-react';\n\nimport { BROWSER_TARGETS } from '../core/src/shared/constants/environments-support.ts';\n\nconst currentFilePath = fileURLToPath(import.meta.url);\nconst currentDirPath = dirname(currentFilePath);\n\nconst componentsPath = join(currentDirPath, '../core/src/components/index.ts');\nconst managerApiPath = join(currentDirPath, '../core/src/manager-api/index.mock.ts');\nconst themingCreatePath = join(currentDirPath, '../core/src/theming/create.ts');\nconst themingPath = join(currentDirPath, '../core/src/theming/index.ts');\nconst imageContextPath = join(currentDirPath, '../frameworks/nextjs/src/image-context.ts');\n\nconst config = defineMain({\n  stories: [\n    './bench/*.stories.@(js|jsx|ts|tsx)',\n    {\n      directory: '../core/template/stories',\n      titlePrefix: 'core',\n    },\n    {\n      directory: '../core/src/manager',\n      titlePrefix: 'manager',\n    },\n    {\n      directory: '../core/src/preview-api',\n      titlePrefix: 'preview',\n    },\n    {\n      directory: '../core/src/preview',\n      titlePrefix: 'preview',\n    },\n    {\n      directory: '../core/src/components/brand',\n      titlePrefix: 'brand',\n    },\n    {\n      directory: '../core/src/components/components',\n      titlePrefix: 'components',\n    },\n    {\n      directory: '../core/src/component-testing/components',\n      titlePrefix: 'component-testing',\n    },\n    {\n      directory: '../core/src/controls/components',\n      titlePrefix: 'controls',\n    },\n    {\n      directory: '../core/src/highlight',\n      titlePrefix: 'highlight',\n    },\n    {\n      directory: '../addons/a11y/src',\n      titlePrefix: 'addons/accessibility',\n    },\n    {\n      directory: '../addons/a11y/template/stories',\n      titlePrefix: 'addons/accessibility',\n    },\n    {\n      directory: '../addons/docs/template/stories',\n      titlePrefix: 'addons/docs',\n    },\n    {\n      directory: '../addons/docs/src',\n      titlePrefix: 'addons/docs',\n    },\n    {\n      directory: '../addons/links/template/stories',\n      titlePrefix: 'addons/links',\n    },\n    {\n      directory: '../addons/themes/template/stories',\n      titlePrefix: 'addons/themes',\n    },\n    {\n      directory: '../addons/onboarding/src',\n      titlePrefix: 'addons/onboarding',\n    },\n    {\n      directory: '../addons/onboarding/example-stories',\n    },\n    {\n      directory: '../addons/pseudo-states/src',\n      titlePrefix: 'addons/pseudo-states',\n    },\n    {\n      directory: '../addons/vitest/src/components',\n      titlePrefix: 'addons/vitest',\n    },\n    {\n      directory: '../addons/vitest/template/stories',\n      titlePrefix: 'addons/vitest',\n    },\n    {\n      directory: '../addons/vitest/src',\n      titlePrefix: 'addons/vitest',\n      files: 'stories.tsx',\n    },\n  ],\n  addons: [\n    '@storybook/addon-onboarding',\n    '@storybook/addon-themes',\n    '@storybook/addon-docs',\n    '@storybook/addon-designs',\n    '@storybook/addon-vitest',\n    '@storybook/addon-a11y',\n    'storybook-addon-pseudo-states',\n    '@chromatic-com/storybook',\n  ],\n  previewAnnotations: [\n    './core/template/stories/preview.ts',\n    './renderers/react/template/components/index.js',\n  ],\n  build: {\n    test: {\n      // we have stories for the blocks here, we can't exclude them\n      disableBlocks: false,\n      // some stories in blocks (ArgTypes, Controls) depends on argTypes inference\n      disableDocgen: false,\n    },\n  },\n  framework: {\n    name: '@storybook/react-vite',\n    options: {},\n  },\n  refs: {\n    icons: {\n      title: 'Icons',\n      url: 'https://main--64b56e737c0aeefed9d5e675.chromatic.com',\n      expanded: false,\n    },\n  },\n  core: {\n    disableTelemetry: true,\n  },\n  features: {\n    developmentModeForBuild: true,\n    experimentalTestSyntax: true,\n  },\n  staticDirs: [{ from: './bench/bundle-analyzer', to: '/bundle-analyzer' }],\n  viteFinal: async (viteConfig, { configType }) => {\n    const { mergeConfig } = await import('vite');\n\n    return mergeConfig(viteConfig, {\n      resolve: {\n        alias: {\n          ...(configType === 'DEVELOPMENT'\n            ? {\n                'storybook/internal/components': componentsPath,\n                'storybook/manager-api': managerApiPath,\n                'storybook/theming/create': themingCreatePath,\n                'storybook/theming': themingPath,\n                'sb-original/image-context': imageContextPath,\n              }\n            : {\n                'storybook/manager-api': managerApiPath,\n              }),\n        },\n      },\n      plugins: [react()],\n      build: {\n        // disable sourcemaps in CI to not run out of memory\n        sourcemap: process.env.CI !== 'true',\n        target: BROWSER_TARGETS,\n      },\n      server: {\n        watch: {\n          // Something odd happens with tsconfig and nx which causes Storybook to keep reloading, so we ignore them\n          ignored: ['**/.nx/cache/**', '**/tsconfig.json'],\n        },\n      },\n    } satisfies typeof viteConfig);\n  },\n  // logLevel: 'debug',\n});\n\nexport default config;\n"
  },
  {
    "path": "code/.storybook/manager.tsx",
    "content": "import { startCase } from 'es-toolkit/string';\nimport { addons } from 'storybook/manager-api';\n\naddons.setConfig({\n  sidebar: {\n    renderLabel: ({ name, type }) => (type === 'story' ? name : startCase(name)),\n  },\n});\n"
  },
  {
    "path": "code/.storybook/preview.tsx",
    "content": "import React, { type FC, Fragment, useEffect } from 'react';\n\nimport type { Channel } from 'storybook/internal/channels';\n\nimport { global } from '@storybook/global';\n\nimport type { Decorator, Loader, ReactRenderer } from '@storybook/react-vite';\nimport { definePreview } from '@storybook/react-vite';\n\nimport addonA11y from '@storybook/addon-a11y';\n// TODO add empty preview\n// import * as designs from '@storybook/addon-designs/preview';\nimport addonDocs from '@storybook/addon-docs';\nimport { DocsContext } from '@storybook/addon-docs/blocks';\nimport addonThemes from '@storybook/addon-themes';\nimport addonTest from '@storybook/addon-vitest';\n\nimport addonPseudoStates from 'storybook-addon-pseudo-states';\nimport { DocsContext as DocsContextProps, useArgs } from 'storybook/preview-api';\nimport type { PreviewWeb } from 'storybook/preview-api';\nimport { sb } from 'storybook/test';\nimport {\n  Global,\n  ThemeProvider,\n  convert,\n  createReset,\n  styled,\n  themes,\n  useTheme,\n} from 'storybook/theming';\n\nimport { DocsPageWrapper } from '../addons/docs/src/blocks/components/index.ts';\nimport * as templatePreview from '../core/template/stories/preview.ts';\nimport '../renderers/react/template/components/index.js';\nimport { isChromatic } from './isChromatic.ts';\n\nsb.mock(import('@storybook/global'), { spy: true });\n\nsb.mock('../core/template/stories/test/ModuleMocking.utils.ts');\nsb.mock('../core/template/stories/test/ModuleSpyMocking.utils.ts', { spy: true });\nsb.mock('../core/template/stories/test/ModuleAutoMocking.utils.ts');\nsb.mock('../core/template/stories/test/ClearModuleMocksMocking.api.ts', { spy: true });\n/* eslint-disable depend/ban-dependencies */\nsb.mock(import('lodash-es'));\nsb.mock(import('lodash-es/add'));\nsb.mock(import('lodash-es/sum'));\nsb.mock(import('uuid'));\n/* eslint-enable depend/ban-dependencies */\n\nconst { document } = global;\nglobalThis.CONFIG_TYPE = 'DEVELOPMENT';\n\nconst ThemeBlock = styled.div<{ side: 'left' | 'right'; layout: string }>(\n  {\n    position: 'absolute',\n    top: 0,\n    left: 0,\n    right: '50vw',\n    width: '50vw',\n    height: '100vh',\n    bottom: 0,\n    overflow: 'auto',\n  },\n  ({ layout }) => ({\n    padding: layout === 'fullscreen' ? 0 : '1rem',\n  }),\n  ({ theme }) => ({\n    background: theme.background.content,\n    color: theme.color.defaultText,\n  }),\n  ({ side }) =>\n    side === 'left'\n      ? {\n          left: 0,\n          right: '50vw',\n        }\n      : {\n          right: 0,\n          left: '50vw',\n        }\n);\n\nconst ThemeStack = styled.div<{ layout: string }>(\n  {\n    position: 'relative',\n    flex: 1,\n  },\n  ({ theme }) => ({\n    background: theme.background.content,\n    color: theme.color.defaultText,\n  }),\n  ({ layout }) => ({\n    padding: layout === 'fullscreen' ? 0 : '1rem',\n  })\n);\n\nconst PlayFnNotice = styled.div(\n  {\n    position: 'absolute',\n    top: 0,\n    left: 0,\n    width: '100%',\n    borderBottom: '1px solid #ccc',\n    padding: '3px 8px',\n    fontSize: '10px',\n    fontWeight: 'bold',\n    zIndex: 99,\n    '> *': {\n      display: 'block',\n    },\n  },\n  ({ theme }) => ({\n    background: '#fffbd9',\n    color: theme.color.defaultText,\n  })\n);\n\nconst StackContainer: FC<React.PropsWithChildren<{ layout: string }>> = ({ children, layout }) => (\n  <div\n    style={{\n      height: '100%',\n      display: 'flex',\n      flexDirection: 'column',\n    }}\n  >\n    <style dangerouslySetInnerHTML={{ __html: 'html, body, #storybook-root { height: 100%; }' }} />\n    {layout === 'fullscreen' ? null : (\n      <style\n        dangerouslySetInnerHTML={{ __html: 'html, body { padding: 0!important; margin: 0; }' }}\n      />\n    )}\n    {children}\n  </div>\n);\n\nconst ThemedSetRoot = () => {\n  const theme = useTheme();\n\n  useEffect(() => {\n    document.body.style.background = theme.background.content;\n    document.body.style.color = theme.color.defaultText;\n  });\n\n  return null;\n};\n\nconst loaders = [\n  /**\n   * This loader adds a DocsContext to the story, which is required for the most Blocks to work. A\n   * story will specify which stories they need in the index with:\n   *\n   * ```ts\n   * parameters: {\n   *   relativeCsfPaths: ['../stories/MyStory.stories.tsx'], // relative to the story\n   * }\n   * ```\n   *\n   * The DocsContext will then be added via the decorator below.\n   */\n  async ({ parameters: { relativeCsfPaths, attached = true } }) => {\n    const preview = (window as any).__STORYBOOK_PREVIEW__ as PreviewWeb<ReactRenderer> | undefined;\n    const channel = (window as any).__STORYBOOK_ADDONS_CHANNEL__ as Channel | undefined;\n    // __STORYBOOK_PREVIEW__ and __STORYBOOK_ADDONS_CHANNEL__ is set in the PreviewWeb constructor\n    // which isn't loaded in portable stories/vitest\n    if (!relativeCsfPaths || !preview || !channel) {\n      return {};\n    }\n    const csfFiles = await Promise.all(\n      (relativeCsfPaths as string[]).map(async (blocksRelativePath) => {\n        const projectRelativePath = `./addons/docs/src/blocks/${blocksRelativePath.replace(\n          /^..\\//,\n          ''\n        )}.tsx`;\n        const entry = preview.storyStore.storyIndex?.importPathToEntry(projectRelativePath);\n\n        if (!entry) {\n          throw new Error(\n            `Couldn't find story file at ${projectRelativePath} (passed as ${blocksRelativePath})`\n          );\n        }\n\n        return preview.storyStore.loadCSFFileByStoryId(entry.id);\n      })\n    );\n    const docsContext = new DocsContextProps(\n      channel,\n      preview.storyStore,\n      preview.renderStoryToElement.bind(preview),\n      csfFiles\n    );\n    if (attached && csfFiles[0]) {\n      docsContext.attachCSFFile(csfFiles[0]);\n    }\n    return { docsContext };\n  },\n] as Loader[];\n\nconst decorators = [\n  // This decorator adds the DocsContext created in the loader above\n  (Story, { loaded: { docsContext } }) =>\n    docsContext ? (\n      <DocsContext.Provider value={docsContext}>\n        <Story />\n      </DocsContext.Provider>\n    ) : (\n      <Story />\n    ),\n  /**\n   * This decorator adds wrappers that contains global styles for stories to be targeted by.\n   * Activated with parameters.docsStyles = true\n   */ (Story, { parameters: { docsStyles } }) =>\n    docsStyles ? (\n      <DocsPageWrapper>\n        <Story />\n      </DocsPageWrapper>\n    ) : (\n      <Story />\n    ),\n  /**\n   * This decorator renders the stories side-by-side, stacked or default based on the theme switcher\n   * in the toolbar\n   */\n  (StoryFn, { globals, playFunction, testFunction, args, storyGlobals, parameters }) => {\n    let theme = globals.sb_theme;\n    let showPlayFnNotice = false;\n\n    // this makes the decorator be out of 'phase' with the actually selected theme in the toolbar\n    // but this is acceptable, I guess\n    // we need to ensure only a single rendering in chromatic\n    // a more 'correct' approach would be to set a specific theme global on every story that has a playFunction\n    if (\n      (testFunction || (playFunction && args.autoplay !== false)) &&\n      !(theme === 'light' || theme === 'dark')\n    ) {\n      theme = 'light';\n      showPlayFnNotice = true;\n    } else if (isChromatic() && !storyGlobals.sb_theme && !playFunction && !testFunction) {\n      theme = 'stacked';\n    }\n\n    switch (theme) {\n      case 'side-by-side': {\n        return (\n          <Fragment>\n            <ThemeProvider theme={convert(themes.light)}>\n              <Global styles={createReset} />\n            </ThemeProvider>\n            <ThemeProvider theme={convert(themes.light)}>\n              <ThemeBlock side=\"left\" data-side=\"left\" layout={parameters.layout}>\n                <StoryFn />\n              </ThemeBlock>\n            </ThemeProvider>\n            <ThemeProvider theme={convert(themes.dark)}>\n              <ThemeBlock side=\"right\" data-side=\"right\" layout={parameters.layout}>\n                <StoryFn />\n              </ThemeBlock>\n            </ThemeProvider>\n          </Fragment>\n        );\n      }\n      case 'stacked': {\n        return (\n          <Fragment>\n            <ThemeProvider theme={convert(themes.light)}>\n              <Global styles={createReset} />\n            </ThemeProvider>\n            <StackContainer layout={parameters.layout}>\n              <ThemeProvider theme={convert(themes.light)}>\n                <ThemeStack data-side=\"left\" layout={parameters.layout}>\n                  <StoryFn />\n                </ThemeStack>\n              </ThemeProvider>\n              <ThemeProvider theme={convert(themes.dark)}>\n                <ThemeStack data-side=\"right\" layout={parameters.layout}>\n                  <StoryFn />\n                </ThemeStack>\n              </ThemeProvider>\n            </StackContainer>\n          </Fragment>\n        );\n      }\n      case 'default':\n      default: {\n        return (\n          <ThemeProvider theme={convert(themes[theme])}>\n            <Global styles={createReset} />\n            <ThemedSetRoot />\n            {showPlayFnNotice && (\n              <>\n                <PlayFnNotice>\n                  <span>\n                    Detected play/test function in Chromatic. Rendering only light theme to avoid\n                    multiple play/test functions in the same story.\n                  </span>\n                </PlayFnNotice>\n                <div style={{ marginBottom: 20 }} />\n              </>\n            )}\n            <StoryFn />\n          </ThemeProvider>\n        );\n      }\n    }\n  },\n  /**\n   * This decorator shows the current state of the arg named in the parameters.withRawArg property,\n   * by updating the arg in the onChange function this also means that the arg will sync with the\n   * control panel\n   *\n   * If parameters.withRawArg is not set, this decorator will do nothing\n   */\n  (StoryFn, { parameters, args }) => {\n    const [, updateArgs] = useArgs();\n    if (!parameters.withRawArg) {\n      return <StoryFn />;\n    }\n\n    return (\n      <>\n        <StoryFn\n          args={{\n            ...args,\n            onChange: (newValue) => {\n              updateArgs({ [parameters.withRawArg]: newValue });\n              // @ts-expect-error onChange is not a valid arg\n              args.onChange?.(newValue);\n            },\n          }}\n        />\n        <div style={{ marginTop: '1rem' }}>\n          Current <code>{parameters.withRawArg}</code>:{' '}\n          <pre>{JSON.stringify(args[parameters.withRawArg], null, 2) || 'undefined'}</pre>\n        </div>\n      </>\n    );\n  },\n] satisfies Decorator[];\n\nconst parameters = {\n  docs: {\n    theme: themes.light,\n    codePanel: true,\n    source: {\n      transform: async (source) => {\n        try {\n          const prettier = await import('prettier/standalone');\n          const prettierPluginBabel = await import('prettier/plugins/babel');\n          const prettierPluginEstree = (await import('prettier/plugins/estree')).default;\n\n          return await prettier.format(source, {\n            parser: 'babel',\n            plugins: [prettierPluginBabel, prettierPluginEstree],\n          });\n        } catch (error) {\n          return source;\n        }\n      },\n    },\n    toc: {},\n  },\n  controls: {\n    presetColors: [\n      { color: '#ff4785', title: 'Coral' },\n      { color: '#1EA7FD', title: 'Ocean' },\n      { color: 'rgb(252, 82, 31)', title: 'Orange' },\n      { color: 'rgba(255, 174, 0, 0.5)', title: 'Gold' },\n      { color: 'hsl(102, 30.20%, 74.70%)', title: 'Green' },\n      { color: 'hsla(179,65%,53%,0.5)', title: 'Seafoam' },\n      { color: '#6F2CAC', title: 'Purple' },\n      { color: '#2A0481', title: 'Ultraviolet' },\n      { color: 'black' },\n      { color: '#333', title: 'Darkest' },\n      { color: '#444', title: 'Darker' },\n      { color: '#666', title: 'Dark' },\n      { color: '#999', title: 'Mediumdark' },\n      { color: '#ddd', title: 'Medium' },\n      { color: '#EEE', title: 'Mediumlight' },\n      { color: '#F3F3F3', title: 'Light' },\n      { color: '#F8F8F8', title: 'Lighter' },\n      { color: '#FFFFFF', title: 'Lightest' },\n      '#fe4a49',\n      '#FED766',\n      'rgba(0, 159, 183, 1)',\n      'hsla(240,11%,91%,0.5)',\n      'slategray',\n    ],\n  },\n  themes: {\n    disable: true,\n  },\n  backgrounds: {\n    options: {\n      light: { name: 'light', value: '#F6F9FC' },\n      dark: { name: 'dark', value: '#1B1C1D' },\n      blue: { name: 'blue', value: '#1b1a2c' },\n    },\n    grid: {\n      cellSize: 15,\n      cellAmount: 10,\n      opacity: 0.4,\n    },\n  },\n};\n\nexport default definePreview({\n  addons: [\n    addonDocs(),\n    addonThemes(),\n    addonA11y(),\n    addonTest(),\n    addonPseudoStates(),\n    templatePreview,\n  ],\n  decorators,\n  loaders,\n  tags: ['test', 'vitest'],\n  parameters,\n});\n"
  },
  {
    "path": "code/.storybook/storybook.setup.ts",
    "content": "import { vi, expect as vitestExpect } from 'vitest';\n\nimport { setProjectAnnotations } from '@storybook/react';\n\nimport { userEvent as storybookEvent, expect as storybookExpect } from 'storybook/test';\n\nimport preview from './preview.tsx';\n\nvi.spyOn(console, 'warn').mockImplementation((...args) => console.log(...args));\n\nsetProjectAnnotations([\n  preview.composed,\n  {\n    // experiment with injecting Vitest's interactivity API over our userEvent while tests run in browser mode\n    // https://vitest.dev/guide/browser/interactivity-api.html\n    loaders: async (context) => {\n      if (globalThis.__vitest_browser__) {\n        const vitest = await import('vitest/browser');\n        const { userEvent: browserEvent } = vitest;\n        // Unfortunately the types of userEvent don't match so we cast it\n        context.userEvent = (browserEvent as unknown as typeof storybookEvent).setup();\n        context.expect = vitestExpect;\n      } else {\n        context.userEvent = storybookEvent.setup();\n        context.expect = storybookExpect;\n      }\n    },\n  },\n]);\n"
  },
  {
    "path": "code/.storybook/utils/todo.tsx",
    "content": "export function getTodos() {\n  return ['some todo'];\n}\n"
  },
  {
    "path": "code/.swcrc",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/swcrc\",\n  \"jsc\": {\n    \"parser\": {\n      \"syntax\": \"typescript\",\n      \"tsx\": true\n    },\n    \"transform\": {\n      \"react\": {\n        \"runtime\": \"classic\",\n        \"pragma\": \"React.createElement\",\n        \"pragmaFrag\": \"React.Fragment\",\n        \"throwIfNamespace\": false,\n        \"development\": false\n      }\n    },\n    \"target\": \"es2020\",\n    \"loose\": false,\n    \"externalHelpers\": false,\n    \"keepClassNames\": false\n  },\n  \"minify\": false\n}\n"
  },
  {
    "path": "code/.vscode/settings.json",
    "content": "{\n  \"eslint.workingDirectories\": [\".\", \"../scripts\"],\n  \"typescript.tsdk\": \"node_modules/typescript/lib\",\n  \"[javascript]\": {\n    \"editor.defaultFormatter\": \"dbaeumer.vscode-eslint\",\n    \"editor.formatOnSave\": true\n  },\n  \"[javascriptreact]\": {\n    \"editor.defaultFormatter\": \"dbaeumer.vscode-eslint\",\n    \"editor.formatOnSave\": true\n  },\n  \"[typescript]\": {\n    \"editor.defaultFormatter\": \"dbaeumer.vscode-eslint\",\n    \"editor.formatOnSave\": true\n  },\n  \"[typescriptreact]\": {\n    \"editor.defaultFormatter\": \"dbaeumer.vscode-eslint\",\n    \"editor.formatOnSave\": true\n  }\n}\n"
  },
  {
    "path": "code/__mocks__/fileMock.js",
    "content": "module.exports = 'file-stub';\n"
  },
  {
    "path": "code/__mocks__/fs/promises.ts",
    "content": "import { vi } from 'vitest';\n\n// This is a custom function that our tests can use during setup to specify\n// what the files on the \"mock\" filesystem should look like when any of the\n// `fs` APIs are used.\nlet mockFiles = Object.create(null);\n\nexport function __setMockFiles(newMockFiles: Record<string, string | null>) {\n  mockFiles = newMockFiles;\n}\n\nexport const writeFile = vi.fn(async (filePath: string, content: string) => {\n  mockFiles[filePath] = content;\n});\nexport const readFile = vi.fn(async (filePath: string) => mockFiles[filePath]);\nexport const lstat = vi.fn(async (filePath: string) => ({\n  isFile: () => !!mockFiles[filePath],\n}));\nexport const readdir = vi.fn();\nexport const readlink = vi.fn();\nexport const realpath = vi.fn();\n\nexport default {\n  __setMockFiles,\n  writeFile,\n  readFile,\n  lstat,\n  readdir,\n  readlink,\n  realpath,\n};\n"
  },
  {
    "path": "code/__mocks__/fs-extra.ts",
    "content": "import { vi } from 'vitest';\n\n// This is a custom function that our tests can use during setup to specify\n// what the files on the \"mock\" filesystem should look like when any of the\n// `fs` APIs are used.\nlet mockFiles = Object.create(null);\n\nexport function __setMockFiles(newMockFiles: Record<string, string | null>) {\n  mockFiles = newMockFiles;\n}\n\n// A custom version of `readdirSync` that reads from the special mocked out\n// file list set via __setMockFiles\nexport const writeFile = vi.fn(async (filePath: string, content: string) => {\n  mockFiles[filePath] = content;\n});\nexport const readFile = vi.fn(async (filePath: string) => mockFiles[filePath]);\nexport const readFileSync = vi.fn((filePath = '') => mockFiles[filePath]);\nexport const existsSync = vi.fn((filePath: string) => !!mockFiles[filePath]);\nexport const readJson = vi.fn((filePath = '') => JSON.parse(mockFiles[filePath]));\nexport const readJsonSync = vi.fn((filePath = '') => JSON.parse(mockFiles[filePath]));\nexport const lstatSync = vi.fn((filePath: string) => ({\n  isFile: () => !!mockFiles[filePath],\n}));\nexport const writeJson = vi.fn((filePath, json, { spaces } = {}) => {\n  mockFiles[filePath] = JSON.stringify(json, null, spaces);\n});\n\nexport default {\n  __setMockFiles,\n  writeFile,\n  readFile,\n  readFileSync,\n  existsSync,\n  readJson,\n  readJsonSync,\n  lstatSync,\n  writeJson,\n};\n"
  },
  {
    "path": "code/__mocks__/fs.ts",
    "content": "import { vi } from 'vitest';\n\n// This is a custom function that our tests can use during setup to specify\n// what the files on the \"mock\" filesystem should look like when any of the\n// `fs` APIs are used.\nlet mockFiles = Object.create(null);\n\nexport function __setMockFiles(newMockFiles: Record<string, string | null>) {\n  mockFiles = newMockFiles;\n}\n\nexport const readFileSync = (filePath = '') => mockFiles[filePath];\nexport const existsSync = (filePath: string) => !!mockFiles[filePath];\nexport const lstatSync = (filePath: string) => ({\n  isFile: () => !!mockFiles[filePath],\n});\nexport const realpathSync = vi.fn();\nexport const readdir = vi.fn();\nexport const readdirSync = vi.fn();\nexport const readlinkSync = vi.fn();\nexport const mkdirSync = vi.fn();\n\nexport default {\n  __setMockFiles,\n  readFileSync,\n  existsSync,\n  lstatSync,\n  realpathSync,\n  readdir,\n  readdirSync,\n  readlinkSync,\n  mkdirSync,\n};\n"
  },
  {
    "path": "code/__mocks__/htmlMock.js",
    "content": "module.exports = '<h1>HTML Mock</h1>';\n"
  },
  {
    "path": "code/__mocks__/inject-decorator.angular-stories.txt",
    "content": "import { Component } from '@angular/core';\nimport { storiesOf } from '@storybook/angular';\n\n@Component({\n  selector: 'storybook-with-ng-content',\n  template: `<div style=\"color: #1e88e5;\"><ng-content></ng-content></div>`,\n})\nclass WithNgContentComponent {}\n\nstoriesOf('Custom|ng-content', module).add('Default', () => ({\n  template: `<storybook-with-ng-content><h1>This is rendered in ng-content</h1></storybook-with-ng-content>`,\n  moduleMetadata: {\n    declarations: [WithNgContentComponent],\n  },\n}));\n"
  },
  {
    "path": "code/__mocks__/inject-decorator.flow-stories.txt",
    "content": "// @flow\nimport React from 'react';\nimport { storiesOf } from '@storybook/react';\nimport { withInfo } from '@storybook/addon-info';\n\nimport TableComponent from '../components/TableComponent';\n\nimport type { JssClasses } from '../types';\n\ntype State = {\n  value: any,\n};\n\ntype Props = {\n  classes: JssClasses,\n  name: string,\n};\n\nclass Table extends React.Component<Props, State> {\n  constructor(props) {\n    super(props);\n    this.state = {\n      value: undefined,\n    };\n  }\n\n  state: State;\n\n  render() {\n    return <TableComponent />;\n  }\n}\n\nconst stories = storiesOf('Table', module);\nstories.add('Flow Class', withInfo('Lorum Ipsum Nem')(() => <Table />));\n"
  },
  {
    "path": "code/__mocks__/inject-decorator.no-stories.txt",
    "content": "while(true) {\n  console.log(\"it's a kind of magic\");\n}"
  },
  {
    "path": "code/__mocks__/inject-decorator.stories.txt",
    "content": "import React from 'react';\nimport { storiesOf } from '@storybook/react';\nimport { withInfo } from '@storybook/addon-info';\n\nimport { DocgenButton } from '../components/DocgenButton';\nimport FlowTypeButton from '../components/FlowTypeButton';\nimport BaseButton from '../components/BaseButton';\nimport TableComponent from '../components/TableComponent';\n\nstoriesOf('Addons|Info.React Docgen', module)\n  .add(\n    'Comments from PropType declarations',\n    withInfo(\n      'Comments above the PropType declarations should be extracted from the React component file itself and rendered in the Info Addon prop table'\n    )(() => <DocgenButton label=\"Docgen Button\" />)\n  )\n  .add(\n    'Comments from Flow declarations',\n    withInfo(\n      'Comments above the Flow declarations should be extracted from the React component file itself and rendered in the Info Addon prop table'\n    )(() => <FlowTypeButton label=\"Flow Typed Button\" />)\n  )\n  .add(\n    'Comments from component declaration',\n    withInfo(\n      'Comments above the component declaration should be extracted from the React component file itself and rendered below the Info Addon heading'\n    )(() => <BaseButton label=\"Button\" />)\n  );\n\nconst markdownDescription = `\n#### You can use markdown in your withInfo() description.\n\nSometimes you might want to manually include some code examples:\n~~~js\nconst Button = () => <button />;\n~~~\n\nMaybe include a [link](http://storybook.js.org) to your project as well.\n`;\n\nstoriesOf('Addons|Info.Markdown', module).add(\n  'Displays Markdown in description',\n  withInfo(markdownDescription)(() => <BaseButton label=\"Button\" />)\n);\n\nstoriesOf('Addons|Info.Options.inline', module).add(\n  'Inlines component inside story',\n  withInfo({\n    text: 'Component should be inlined between description and PropType table',\n    inline: true, // Displays info inline vs click button to view\n  })(() => <BaseButton label=\"Button\" />)\n);\n\nstoriesOf('Addons|Info.Options.header', module).add(\n  'Shows or hides Info Addon header',\n  withInfo({\n    text: 'The Info Addon header should be hidden',\n    header: false, // Toggles display of header with component name and description\n  })(() => <BaseButton label=\"Button\" />)\n);\n\nstoriesOf('Addons|Info.Options.source', module).add(\n  'Shows or hides Info Addon source',\n  withInfo({\n    text: 'The Info Addon source section should be hidden',\n    source: false, // Displays the source of story Component\n  })(() => <BaseButton label=\"Button\" />)\n);\n\nstoriesOf('Addons|Info.Options.propTables', module).add(\n  'Shows additional component prop tables',\n  withInfo({\n    text: 'There should be a prop table added for a component not included in the story',\n    propTables: [FlowTypeButton],\n  })(() => <BaseButton label=\"Button\" />)\n);\n\nstoriesOf('Addons|Info.Options.propTablesExclude', module).add(\n  'Exclude component from prop tables',\n  withInfo({\n    text: 'This can exclude extraneous components from being displayed in prop tables.',\n    propTablesExclude: [FlowTypeButton],\n  })(() => (\n    <div>\n      <BaseButton label=\"Button\" />\n      <FlowTypeButton label=\"Flow Typed Button\" />\n    </div>\n  ))\n);\n\nstoriesOf('Addons|Info.Options.styles', module)\n  .add(\n    'Extend info styles with an object',\n    withInfo({\n      styles: {\n        button: {\n          base: {\n            background: 'purple',\n          },\n        },\n        header: {\n          h1: {\n            color: 'green',\n          },\n        },\n      },\n    })(() => <BaseButton label=\"Button\" />)\n  )\n  .add(\n    'Full control over styles using a function',\n    withInfo({\n      styles: stylesheet => ({\n        ...stylesheet,\n        header: {\n          ...stylesheet.header,\n          h1: {\n            ...stylesheet.header.h1,\n            color: 'red',\n          },\n        },\n      }),\n    })(() => <BaseButton label=\"Button\" />)\n  );\n\nstoriesOf('Addons|Info.Options.TableComponent', module).add(\n  'Use a custom component for the table',\n  withInfo({\n    TableComponent,\n  })(() => <BaseButton label=\"Button\" />)\n);\n\nstoriesOf('Addons|Info.Decorator', module)\n  .addDecorator((story, context) =>\n    withInfo('Info could be used as a global or local decorator as well.')(story)(context)\n  )\n  .add('Use Info as story decorator', () => <BaseButton label=\"Button\" />);\n\nconst hoc = WrapComponent => ({ ...props }) => <WrapComponent {...props} />;\n\nconst Input = hoc(() => <input type=\"text\" />);\n\nconst TextArea = hoc(({ children }) => <textarea>{children}</textarea>);\n\nstoriesOf('Addons|Info.GitHub issues', module).add(\n  '#1814',\n  withInfo('Allow Duplicate DisplayNames for HOC #1814')(() => (\n    <div>\n      <Input />\n      <TextArea />\n    </div>\n  ))\n);\n"
  },
  {
    "path": "code/__mocks__/inject-decorator.ts.csf-meta-var.txt",
    "content": "import React from \"react\";\nimport { action } from \"storybook/actions\";\nimport { Button } from \"@storybook/react/demo\";\n\nconst meta = {\n  title: \"Button\",\n  excludeStories: [\"text\"],\n  includeStories: /emoji.*/\n};\n\nexport default meta;\n\nexport const text = () => (\n  <Button onClick={action(\"clicked\")}>Hello Button</Button>\n);\n"
  },
  {
    "path": "code/__mocks__/inject-decorator.ts.csf.txt",
    "content": "import React from \"react\";\nimport { action } from \"storybook/actions\";\nimport { Button } from \"@storybook/react/demo\";\n\nexport default {\n  title: \"Button\",\n  excludeStories: [\"text\"],\n  includeStories: /emoji.*/\n};\n\nexport const text = () => (\n  <Button onClick={action(\"clicked\")}>Hello Button</Button>\n);\n\nexport const emoji = () => (\n  <Button onClick={action(\"clicked\")}>\n    <span role=\"img\" aria-label=\"so cool\">\n      😀 😎 👍 💯\n    </span>\n  </Button>\n);\n\nexport function emojiFn() {\n  return (\n    <Button onClick={action(\"clicked\")}>\n      <span role=\"img\" aria-label=\"so cool\">\n        😀 😎 👍 💯\n      </span>\n    </Button>\n  )\n};\n"
  },
  {
    "path": "code/__mocks__/inject-decorator.ts.csf3.txt",
    "content": "import React from \"react\";\nimport { action } from \"storybook/actions\";\nimport { Button } from \"@storybook/react/demo\";\n\nexport default {\n  title: \"Button\",\n};\n\nexport const Basic = {};\n\nexport const Emoji = {\n  args: {\n    children: '😀 😎 👍 💯'\n  }\n};\n"
  },
  {
    "path": "code/__mocks__/inject-decorator.ts.txt",
    "content": "import { Component } from '@angular/core';\nimport { Store, StoreModule } from '@ngrx/store';\nimport { storiesOf, moduleMetadata } from '@storybook/angular';\n\n@Component({\n  selector: 'storybook-comp-with-store',\n  template: '<div>{{this.getStoreState()}}</div>',\n})\nclass WithStoreComponent {\n  private store: Store<any>;\n\n  constructor(store: Store<any>) {\n    this.store = store;\n  }\n\n  getStoreState(): string {\n    return this.store === undefined ? 'Store is NOT injected' : 'Store is injected';\n  }\n}\n\nstoriesOf('ngrx|Store', module)\n  .addDecorator(\n    moduleMetadata({\n      imports: [StoreModule.forRoot({})],\n      declarations: [WithStoreComponent],\n    })\n  )\n  .add('With component', () => {\n    return {\n      component: WithStoreComponent,\n    };\n  });"
  },
  {
    "path": "code/__mocks__/inject-decorator.ts.ugly-comments-stories.txt",
    "content": "/* eslint-disable global-require, import-x/no-dynamic-require */\n\nimport React from 'react';\n\n@Component({\n  selector: 'storybook-comp-with-store',\n  template: '<div>{{this.getStoreState()}}</div>',\n})\nclass WithStoreComponent {\n  private store: Store<any>;\n\n  constructor(store: Store<any>) {\n    this.store = store;\n  }\n\n  getStoreState(): string {\n    return this.store === undefined ? 'Store is NOT injected' : 'Store is injected';\n  }\n}\n\n/*\n eslint-disable some kind\n of multi line ignore, though\n I'm not sure it's possible.\n*/\n\nimport { storiesOf } from '@storybook/react';\n\n/* eslint-disable-line */ const x = 0;\n\n// eslint-disable-line\nstoriesOf('Foo', module)\n  .add('bar', () => <div>baz</div>);\n\n/*\n This is actually a good comment that will help\n users to understand what's going on here.\n*/"
  },
  {
    "path": "code/__mocks__/inject-decorator.ugly-comments-stories.txt",
    "content": "/* eslint-disable global-require, import-x/no-dynamic-require */\n\nimport React from 'react';\n\n/*\n eslint-disable some kind\n of multi line ignore, though\n I'm not sure it's possible.\n*/\n\nimport { storiesOf } from '@storybook/react';\n\n/* eslint-disable-line */ const x = 0;\n\n// eslint-disable-line\nstoriesOf('Foo', module)\n  .add('bar', () => <div>baz</div>);\n\n/*\n This is actually a good comment that will help\n users to understand what's going on here.\n*/"
  },
  {
    "path": "code/__mocks__/inject-parameters.ts.csf.txt",
    "content": "import React from \"react\";\nimport { action } from \"storybook/actions\";\nimport { Button } from \"@storybook/react/demo\";\n\nexport default {\n  title: \"Button\",\n  excludeStories: [\"text\"],\n  includeStories: /emoji.*/\n};\n\nexport const Basic = () => (\n  <Button onClick={action(\"clicked\")}>Hello Button</Button>\n);\n\nexport const WithParams = () => <Button>WithParams</Button>;\nWithParams.parameters = { foo: 'bar' }\n\nexport const WithDocsParams = () => <Button>WithDocsParams</Button>;\nWithDocsParams.parameters = { docs: { story: { iframeHeight: '200px' } } };\n\nexport const WithStorySourceParams = () => <Button>WithStorySourceParams</Button>;\nWithStorySourceParams.parameters = { storySource: { source: 'foo' } };\n\nconst Template = (args: Args) => <Button {...args} />;\n\nexport const WithTemplate = Template.bind({});\nWithTemplate.args = { foo: 'bar' }\n\nexport const WithEmptyTemplate = Template.bind();\nWithEmptyTemplate.args = { foo: 'baz' };\n\nexport const WithAddFunctionParameters = () => null\nWithAddFunctionParameters.parameters = {\n  foobar: () => {\n    document.addEventListener('foo', () => console.log('bar'))\n  },\n}"
  },
  {
    "path": "code/__mocks__/lodash-es/add.js",
    "content": "function add(a, b) {\n  return 'mocked 3';\n}\n\nexport default add;\n"
  },
  {
    "path": "code/__mocks__/lodash-es.js",
    "content": "export default {\n  VERSION: '1.0.0-mocked!',\n};\n"
  },
  {
    "path": "code/__mocks__/styleMock.js",
    "content": "module.exports = {};\n"
  },
  {
    "path": "code/__mocks__/uuid.js",
    "content": "export function v4() {\n  return 'MOCK-V4';\n}\n"
  },
  {
    "path": "code/addons/a11y/README.md",
    "content": "# Storybook Accessibility Addon\n\nThe @storybook/addon-a11y package provides accessibility testing for Storybook stories. It uses axe-core to run the tests.\n\n## Getting Started\n\n### Add the addon to an existing Storybook\n\n```bash\nnpx storybook add @storybook/addon-a11y\n```\n\n[More on getting started with the accessibility addon](https://storybook.js.org/docs/writing-tests/accessibility-testing#accessibility-checks-with-a11y-addon?ref=readme)\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/addons/a11y/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./preview'],\n        entryPoint: './src/preview.tsx',\n      },\n      {\n        exportEntries: ['./manager'],\n        entryPoint: './src/manager.tsx',\n        dts: false,\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./postinstall'],\n        entryPoint: './src/postinstall.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/addons/a11y/manager.js",
    "content": "export * from './dist/manager.js';\n"
  },
  {
    "path": "code/addons/a11y/package.json",
    "content": "{\n  \"name\": \"@storybook/addon-a11y\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook Addon A11y: Test UI component compliance with WCAG web accessibility standards\",\n  \"keywords\": [\n    \"a11y\",\n    \"accessibility\",\n    \"storybook\",\n    \"storybook-addon\",\n    \"test\",\n    \"axe\",\n    \"WCAG\",\n    \"ARIA\",\n    \"component\",\n    \"components\",\n    \"react\",\n    \"vue\",\n    \"angular\",\n    \"svelte\",\n    \"web-components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/addons/a11y\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/addons/a11y\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./manager\": \"./dist/manager.js\",\n    \"./package.json\": \"./package.json\",\n    \"./postinstall\": \"./dist/postinstall.js\",\n    \"./preset\": \"./dist/preset.js\",\n    \"./preview\": {\n      \"types\": \"./dist/preview.d.ts\",\n      \"code\": \"./src/preview.tsx\",\n      \"default\": \"./dist/preview.js\"\n    }\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/global\": \"^5.0.0\",\n    \"axe-core\": \"^4.2.0\"\n  },\n  \"devDependencies\": {\n    \"@radix-ui/react-tabs\": \"1.0.4\",\n    \"@storybook/icons\": \"^2.0.1\",\n    \"@testing-library/react\": \"^14.0.0\",\n    \"execa\": \"^9.6.1\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-resize-detector\": \"^7.1.2\",\n    \"typescript\": \"^5.9.3\",\n    \"vitest-axe\": \"^0.1.0\"\n  },\n  \"peerDependencies\": {\n    \"storybook\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\",\n  \"storybook\": {\n    \"displayName\": \"Accessibility\",\n    \"icon\": \"https://user-images.githubusercontent.com/263385/101991665-47042f80-3c7c-11eb-8f00-64b5a18f498a.png\",\n    \"unsupportedFrameworks\": [\n      \"react-native\"\n    ]\n  }\n}\n"
  },
  {
    "path": "code/addons/a11y/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/addons/a11y/preview.js",
    "content": "export * from './dist/preview.js';\n"
  },
  {
    "path": "code/addons/a11y/project.json",
    "content": "{\n  \"name\": \"addon-a11y\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/addons/a11y/src/AccessibilityRuleMaps.ts",
    "content": "export type AxeRuleMap = {\n  // The rule id from axe-core\n  [axeId: string]: {\n    // The simple name of the rule\n    title: string;\n    // The summary of the rule from axe-core\n    axeSummary: string;\n    // The UX-friendly summary of the rule\n    friendlySummary: string;\n  };\n};\n\n// Rules that align with WCAG 2.0 A/AA success criteria.\nconst axeRuleMapping_wcag_2_0_a_aa: AxeRuleMap = {\n  'area-alt': {\n    title: '<area> alt text',\n    axeSummary: 'Ensure <area> elements of image maps have alternative text',\n    friendlySummary: 'Add alt text to all <area> elements of image maps.',\n  },\n  'aria-allowed-attr': {\n    title: 'Supported ARIA attributes',\n    axeSummary: \"Ensure an element's role supports its ARIA attributes\",\n    friendlySummary: \"Only use ARIA attributes that are permitted for the element's role.\",\n  },\n  'aria-braille-equivalent': {\n    title: 'Braille equivalent',\n    axeSummary:\n      'Ensure aria-braillelabel and aria-brailleroledescription have a non-braille equivalent',\n    friendlySummary: 'If you use braille ARIA labels, also provide a matching non-braille label.',\n  },\n  'aria-command-name': {\n    title: 'ARIA command name',\n    axeSummary: 'Ensure every ARIA button, link and menuitem has an accessible name',\n    friendlySummary: 'Every ARIA button, link, or menuitem needs a label or accessible name.',\n  },\n  'aria-conditional-attr': {\n    title: 'ARIA attribute valid for role',\n    axeSummary:\n      \"Ensure ARIA attributes are used as described in the specification of the element's role\",\n    friendlySummary: \"Follow the element role's specification when using ARIA attributes.\",\n  },\n  'aria-deprecated-role': {\n    title: 'Deprecated ARIA role',\n    axeSummary: 'Ensure elements do not use deprecated roles',\n    friendlySummary: \"Don't use deprecated ARIA roles on elements.\",\n  },\n  'aria-hidden-body': {\n    title: 'Hidden body',\n    axeSummary: 'Ensure aria-hidden=\"true\" is not present on the document <body>',\n    friendlySummary: 'Never set aria-hidden=\"true\" on the <body> element.',\n  },\n  'aria-hidden-focus': {\n    title: 'Hidden element focus',\n    axeSummary: 'Ensure aria-hidden elements are not focusable nor contain focusable elements',\n    friendlySummary:\n      'Elements marked hidden (aria-hidden) should not be focusable or contain focusable items.',\n  },\n  'aria-input-field-name': {\n    title: 'ARIA input field name',\n    axeSummary: 'Ensure every ARIA input field has an accessible name',\n    friendlySummary: 'Give each ARIA text input or field a label or accessible name.',\n  },\n  'aria-meter-name': {\n    title: 'ARIA meter name',\n    axeSummary: 'Ensure every ARIA meter node has an accessible name',\n    friendlySummary: 'Give each element with role=\"meter\" a label or accessible name.',\n  },\n  'aria-progressbar-name': {\n    title: 'ARIA progressbar name',\n    axeSummary: 'Ensure every ARIA progressbar node has an accessible name',\n    friendlySummary: 'Give each element with role=\"progressbar\" a label or accessible name.',\n  },\n  'aria-prohibited-attr': {\n    title: 'ARIA prohibited attributes',\n    axeSummary: \"Ensure ARIA attributes are not prohibited for an element's role\",\n    friendlySummary: \"Don't use ARIA attributes that are forbidden for that element's role.\",\n  },\n  'aria-required-attr': {\n    title: 'ARIA required attributes',\n    axeSummary: 'Ensure elements with ARIA roles have all required ARIA attributes',\n    friendlySummary: 'Include all required ARIA attributes for elements with that ARIA role.',\n  },\n  'aria-required-children': {\n    title: 'ARIA required children',\n    axeSummary: 'Ensure elements with an ARIA role that require child roles contain them',\n    friendlySummary: 'If an ARIA role requires specific child roles, include those child elements.',\n  },\n  'aria-required-parent': {\n    title: 'ARIA required parent',\n    axeSummary: 'Ensure elements with an ARIA role that require parent roles are contained by them',\n    friendlySummary:\n      'Place elements with certain ARIA roles inside the required parent role element.',\n  },\n  'aria-roles': {\n    title: 'ARIA role value',\n    axeSummary: 'Ensure all elements with a role attribute use a valid value',\n    friendlySummary: 'Use only valid values in the role attribute (no typos or invalid roles).',\n  },\n  'aria-toggle-field-name': {\n    title: 'ARIA toggle field name',\n    axeSummary: 'Ensure every ARIA toggle field has an accessible name',\n    friendlySummary:\n      'Every ARIA toggle field (elements with the checkbox, radio, or switch roles) needs an accessible name.',\n  },\n  'aria-tooltip-name': {\n    title: 'ARIA tooltip name',\n    axeSummary: 'Ensure every ARIA tooltip node has an accessible name',\n    friendlySummary: 'Give each element with role=\"tooltip\" a descriptive accessible name.',\n  },\n  'aria-valid-attr-value': {\n    title: 'ARIA attribute values valid',\n    axeSummary: 'Ensure all ARIA attributes have valid values',\n    friendlySummary: 'Use only valid values for ARIA attributes (no typos or invalid values).',\n  },\n  'aria-valid-attr': {\n    title: 'ARIA attribute valid',\n    axeSummary: 'Ensure attributes that begin with aria- are valid ARIA attributes',\n    friendlySummary: 'Use only valid aria-* attributes (make sure the attribute name is correct).',\n  },\n  blink: {\n    title: '<blink> element',\n    axeSummary: 'Ensure <blink> elements are not used',\n    friendlySummary: \"Don't use the deprecated <blink> element.\",\n  },\n  'button-name': {\n    title: 'Button name',\n    axeSummary: 'Ensure buttons have discernible text',\n    friendlySummary: 'Every <button> needs a visible label or accessible name.',\n  },\n  bypass: {\n    title: 'Navigation bypass',\n    axeSummary:\n      'Ensure each page has at least one mechanism to bypass navigation and jump to content',\n    friendlySummary: 'Provide a way to skip repetitive navigation (e.g. a \"Skip to content\" link).',\n  },\n  'color-contrast': {\n    title: 'Color contrast',\n    axeSummary:\n      'Ensure the contrast between foreground and background text meets WCAG 2 AA minimum thresholds',\n    friendlySummary:\n      'The color contrast between text and its background meets WCAG AA contrast ratio.',\n  },\n  'definition-list': {\n    title: 'Definition list structure',\n    axeSummary: 'Ensure <dl> elements are structured correctly',\n    friendlySummary:\n      'Definition lists (<dl>) should directly contain <dt> and <dd> elements in order.',\n  },\n  dlitem: {\n    title: 'Definition list items',\n    axeSummary: 'Ensure <dt> and <dd> elements are contained by a <dl>',\n    friendlySummary: 'Ensure <dt> and <dd> elements are contained by a <dl>',\n  },\n  'document-title': {\n    title: 'Document title',\n    axeSummary: 'Ensure each HTML document contains a non-empty <title> element',\n    friendlySummary: 'Include a non-empty <title> element for every page.',\n  },\n  'duplicate-id-aria': {\n    title: 'Unique id',\n    axeSummary: 'Ensure every id attribute value used in ARIA and in labels is unique',\n    friendlySummary: 'Every id used for ARIA or form labels should be unique on the page.',\n  },\n  'form-field-multiple-labels': {\n    title: 'Multiple form field labels',\n    axeSummary: 'Ensure a form field does not have multiple <label> elements',\n    friendlySummary: \"Don't give a single form field more than one <label>.\",\n  },\n  'frame-focusable-content': {\n    title: 'Focusable frames',\n    axeSummary: 'Ensure <frame> and <iframe> with focusable content do not have tabindex=\"-1\"',\n    friendlySummary:\n      'Don\\'t set tabindex=\"-1\" on a <frame> or <iframe> that contains focusable elements.',\n  },\n  'frame-title-unique': {\n    title: 'Unique frame title',\n    axeSummary: 'Ensure <iframe> and <frame> elements contain a unique title attribute',\n    friendlySummary: 'Use a unique title attribute for each <frame> or <iframe> on the page.',\n  },\n  'frame-title': {\n    title: 'Frame title',\n    axeSummary: 'Ensure <iframe> and <frame> elements have an accessible name',\n    friendlySummary: 'Every <frame> and <iframe> needs a title or accessible name.',\n  },\n  'html-has-lang': {\n    title: '<html> has lang',\n    axeSummary: 'Ensure every HTML document has a lang attribute',\n    friendlySummary: 'Add a lang attribute to the <html> element.',\n  },\n  'html-lang-valid': {\n    title: '<html> lang valid',\n    axeSummary: 'Ensure the <html lang> attribute has a valid value',\n    friendlySummary: 'Use a valid language code in the <html lang> attribute.',\n  },\n  'html-xml-lang-mismatch': {\n    title: 'HTML and XML lang mismatch',\n    axeSummary:\n      \"Ensure that HTML elements with both lang and xml:lang agree on the page's language\",\n    friendlySummary:\n      'If using both lang and xml:lang on <html>, make sure they are the same language.',\n  },\n  'image-alt': {\n    title: 'Image alt text',\n    axeSummary: 'Ensure <img> elements have alternative text or a role of none/presentation',\n    friendlySummary: 'Give every image alt text or mark it as decorative with alt=\"\".',\n  },\n  'input-button-name': {\n    title: 'Input button name',\n    axeSummary: 'Ensure input buttons have discernible text',\n    friendlySummary:\n      'Give each <input type=\"button\"> or similar a clear label (text or aria-label).',\n  },\n  'input-image-alt': {\n    title: 'Input image alt',\n    axeSummary: 'Ensure <input type=\"image\"> elements have alternative text',\n    friendlySummary: '<input type=\"image\"> must have alt text describing its image.',\n  },\n  label: {\n    title: 'Form label',\n    axeSummary: 'Ensure every form element has a label',\n    friendlySummary: 'Every form field needs an associated label.',\n  },\n  'link-in-text-block': {\n    title: 'Identifiable links',\n    axeSummary: 'Ensure links are distinguishable from surrounding text without relying on color',\n    friendlySummary: 'Make sure links are obviously identifiable without relying only on color.',\n  },\n  'link-name': {\n    title: 'Link name',\n    axeSummary: 'Ensure links have discernible text',\n    friendlySummary: 'Give each link meaningful text or an aria-label so its purpose is clear.',\n  },\n  list: {\n    title: 'List structure',\n    axeSummary: 'Ensure that lists are structured correctly',\n    friendlySummary: 'Use proper list structure. Only use <li> inside <ul> or <ol>.',\n  },\n  listitem: {\n    title: 'List item',\n    axeSummary: 'Ensure <li> elements are used semantically',\n    friendlySummary: 'Only use <li> tags inside <ul> or <ol> lists.',\n  },\n  marquee: {\n    title: '<marquee> element',\n    axeSummary: 'Ensure <marquee> elements are not used',\n    friendlySummary: \"Don't use the deprecated <marquee> element.\",\n  },\n  'meta-refresh': {\n    title: '<meta> refresh',\n    axeSummary: 'Ensure <meta http-equiv=\"refresh\"> is not used for delayed refresh',\n    friendlySummary:\n      'Avoid auto-refreshing or redirecting pages using <meta http-equiv=\"refresh\">.',\n  },\n  'meta-viewport': {\n    title: '<meta> viewport scaling',\n    axeSummary: 'Ensure <meta name=\"viewport\"> does not disable text scaling and zooming',\n    friendlySummary: 'Don\\'t disable user zooming in <meta name=\"viewport\"> to allow scaling.',\n  },\n  'nested-interactive': {\n    title: 'Nested interactive controls',\n    axeSummary:\n      'Ensure interactive controls are not nested (nesting causes screen reader/focus issues)',\n    friendlySummary:\n      'Do not nest interactive elements; it can confuse screen readers and keyboard focus.',\n  },\n  'no-autoplay-audio': {\n    title: 'Autoplaying video',\n    axeSummary:\n      'Ensure <video> or <audio> do not autoplay audio > 3 seconds without a control to stop/mute',\n    friendlySummary:\n      \"Don't autoplay audio for more than 3 seconds without providing a way to stop or mute it.\",\n  },\n  'object-alt': {\n    title: '<object> alt text',\n    axeSummary: 'Ensure <object> elements have alternative text',\n    friendlySummary: 'Provide alternative text or content for <object> elements.',\n  },\n  'role-img-alt': {\n    title: 'role=\"img\" alt text',\n    axeSummary: 'Ensure elements with role=\"img\" have alternative text',\n    friendlySummary: 'Any element with role=\"img\" needs alt text.',\n  },\n  'scrollable-region-focusable': {\n    title: 'Scrollable element focusable',\n    axeSummary: 'Ensure elements with scrollable content are keyboard-accessible',\n    friendlySummary: 'If an area can scroll, ensure it can be focused and scrolled via keyboard.',\n  },\n  'select-name': {\n    title: '<select> name',\n    axeSummary: 'Ensure <select> elements have an accessible name',\n    friendlySummary: 'Give each <select> field a label or other accessible name.',\n  },\n  'server-side-image-map': {\n    title: 'Server-side image map',\n    axeSummary: 'Ensure that server-side image maps are not used',\n    friendlySummary: \"Don't use server-side image maps.\",\n  },\n  'svg-img-alt': {\n    title: 'SVG image alt text',\n    axeSummary: 'Ensure <svg> images/graphics have accessible text',\n    friendlySummary: 'SVG images with role=\"img\" or similar need a text description.',\n  },\n  'td-headers-attr': {\n    title: 'Table headers attribute',\n    axeSummary: 'Ensure each cell in a table using headers only refers to <th> in that table',\n    friendlySummary:\n      'In tables using the headers attribute, only reference other cells in the same table.',\n  },\n  'th-has-data-cells': {\n    title: '<th> has data cell',\n    axeSummary: 'Ensure <th> (or header role) elements have data cells they describe',\n    friendlySummary:\n      'Every table header (<th> or header role) should correspond to at least one data cell.',\n  },\n  'valid-lang': {\n    title: 'Valid lang',\n    axeSummary: 'Ensure lang attributes have valid values',\n    friendlySummary: 'Use valid language codes in all lang attributes.',\n  },\n  'video-caption': {\n    title: '<video> captions',\n    axeSummary: 'Ensure <video> elements have captions',\n    friendlySummary: 'Provide captions for all <video> content.',\n  },\n};\n\n// Rules that align with WCAG 2.1 A/AA success criteria.\nconst axeRuleMapping_wcag_2_1_a_aa: AxeRuleMap = {\n  'autocomplete-valid': {\n    title: 'autocomplete attribute valid',\n    axeSummary: 'Ensure the autocomplete attribute is correct and suitable for the form field',\n    friendlySummary: \"Use valid autocomplete values that match the form field's purpose.\",\n  },\n  'avoid-inline-spacing': {\n    title: 'Forced inline spacing',\n    axeSummary: 'Ensure that text spacing set via inline styles can be adjusted with custom CSS',\n    friendlySummary:\n      \"Don't lock in text spacing with forced (!important) inline styles—allow user CSS to adjust text spacing.\",\n  },\n};\n\n// Rules that align with WCAG 2.2 A/AA success criteria.\nconst axeRuleMapping_wcag_2_2_a_aa: AxeRuleMap = {\n  'target-size': {\n    title: 'Touch target size',\n    axeSummary: 'Ensure touch targets have sufficient size and space',\n    friendlySummary:\n      'Make sure interactive elements are big enough and not too close together for touch.',\n  },\n};\n\n// Rules not tied to specific WCAG criteria, but reflect industry best practices for accessibility.\nconst axeRuleMapping_best_practices: AxeRuleMap = {\n  accesskeys: {\n    title: 'Unique accesskey',\n    axeSummary: 'Ensure every accesskey attribute value is unique',\n    friendlySummary: 'Use unique values for all accesskey attributes.',\n  },\n  'aria-allowed-role': {\n    title: 'Appropriate role value',\n    axeSummary: 'Ensure the role attribute has an appropriate value for the element',\n    friendlySummary: 'ARIA roles should have a valid value for the element.',\n  },\n  'aria-dialog-name': {\n    title: 'ARIA dialog name',\n    axeSummary: 'Ensure every ARIA dialog and alertdialog has an accessible name',\n    friendlySummary: 'Give each ARIA dialog or alertdialog a title or accessible name.',\n  },\n  'aria-text': {\n    title: 'ARIA role=\"text\"',\n    axeSummary: 'Ensure role=\"text\" is used on elements with no focusable descendants',\n    friendlySummary: 'Only use role=\"text\" on elements that don\\'t contain focusable elements.',\n  },\n  'aria-treeitem-name': {\n    title: 'ARIA treeitem name',\n    axeSummary: 'Ensure every ARIA treeitem node has an accessible name',\n    friendlySummary: 'Give each ARIA treeitem a label or accessible name.',\n  },\n  'empty-heading': {\n    title: 'Empty heading',\n    axeSummary: 'Ensure headings have discernible text',\n    friendlySummary: \"Don't leave heading elements empty or hide them.\",\n  },\n  'empty-table-header': {\n    title: 'Empty table header',\n    axeSummary: 'Ensure table headers have discernible text',\n    friendlySummary: 'Make sure table header cells have visible text.',\n  },\n  'frame-tested': {\n    title: 'Test all frames',\n    axeSummary: 'Ensure <iframe> and <frame> elements contain the axe-core script',\n    friendlySummary:\n      'Make sure axe-core is injected into all frames or iframes so they are tested.',\n  },\n  'heading-order': {\n    title: 'Heading order',\n    axeSummary: 'Ensure the order of headings is semantically correct (no skipping levels)',\n    friendlySummary: \"Use proper heading order (don't skip heading levels).\",\n  },\n  'image-redundant-alt': {\n    title: 'Redundant image alt text',\n    axeSummary: 'Ensure image alternative text is not repeated as nearby text',\n    friendlySummary:\n      \"Avoid repeating the same information in both an image's alt text and nearby text.\",\n  },\n  'label-title-only': {\n    title: 'Visible form element label',\n    axeSummary: 'Ensure each form element has a visible label (not only title/ARIA)',\n    friendlySummary:\n      'Every form input needs a visible label (not only a title attribute or hidden text).',\n  },\n  'landmark-banner-is-top-level': {\n    title: 'Top-level landmark banner',\n    axeSummary: 'Ensure the banner landmark is at top level (not nested)',\n    friendlySummary:\n      'Use the banner landmark (e.g. site header) only at the top level of the page, not inside another landmark.',\n  },\n  'landmark-complementary-is-top-level': {\n    title: 'Top-level <aside>',\n    axeSummary: 'Ensure the complementary landmark (<aside>) is top level',\n    friendlySummary:\n      'The complementary landmark <aside> or role=\"complementary\" should be a top-level region, not nested in another landmark.',\n  },\n  'landmark-contentinfo-is-top-level': {\n    title: 'Top-level contentinfo',\n    axeSummary: 'Ensure the contentinfo landmark (footer) is top level',\n    friendlySummary:\n      'Make sure the contentinfo landmark (footer) is at the top level of the page and not contained in another landmark.',\n  },\n  'landmark-main-is-top-level': {\n    title: 'Top-level main',\n    axeSummary: 'Ensure the main landmark is at top level',\n    friendlySummary:\n      'The main landmark should be a top-level element and not nested inside another landmark.',\n  },\n  'landmark-no-duplicate-banner': {\n    title: 'Duplicate banner landmark',\n    axeSummary: 'Ensure the document has at most one banner landmark',\n    friendlySummary: 'Have only one role=\"banner\" or <header> on a page.',\n  },\n  'landmark-no-duplicate-contentinfo': {\n    title: 'Duplicate contentinfo',\n    axeSummary: 'Ensure the document has at most one contentinfo landmark',\n    friendlySummary: 'Have only one role=\"contentinfo\" or <footer> on a page.',\n  },\n  'landmark-no-duplicate-main': {\n    title: 'Duplicate main',\n    axeSummary: 'Ensure the document has at most one main landmark',\n    friendlySummary: 'Have only one role=\"main\" or <main> on a page.',\n  },\n  'landmark-one-main': {\n    title: 'main landmark',\n    axeSummary: 'Ensure the document has a main landmark',\n    friendlySummary: 'Include a main landmark on each page using a <main> region or role=\"main\".',\n  },\n  'landmark-unique': {\n    title: 'Unique landmark',\n    axeSummary: 'Ensure landmarks have a unique role or role/label combination',\n    friendlySummary:\n      'If you use multiple landmarks of the same type, give them unique labels (names).',\n  },\n  'meta-viewport-large': {\n    title: 'Significant viewport scaling',\n    axeSummary: 'Ensure <meta name=\"viewport\"> can scale a significant amount (e.g. 500%)',\n    friendlySummary: '<meta name=\"viewport\"> should allow users to significantly scale content.',\n  },\n  'page-has-heading-one': {\n    title: 'Has <h1>',\n    axeSummary: 'Ensure the page (or at least one frame) contains a level-one heading',\n    friendlySummary: 'Every page or frame should have at least one <h1> heading.',\n  },\n  'presentation-role-conflict': {\n    title: 'Presentational content',\n    axeSummary: 'Ensure elements with role=\"presentation\"/\"none\" have no ARIA or tabindex',\n    friendlySummary:\n      'Don\\'t give elements with role=\"none\"/\"presentation\" any ARIA attributes or a tabindex.',\n  },\n  region: {\n    title: 'Landmark regions',\n    axeSummary: 'Ensure all page content is contained by landmarks',\n    friendlySummary:\n      'Wrap all page content in appropriate landmark regions (<header>, <main>, <footer>, etc.).',\n  },\n  'scope-attr-valid': {\n    title: 'scope attribute',\n    axeSummary: 'Ensure the scope attribute is used correctly on tables',\n    friendlySummary:\n      'Use the scope attribute only on <th> elements, with proper values (col, row, etc.).',\n  },\n  'skip-link': {\n    title: 'Skip link',\n    axeSummary: 'Ensure all \"skip\" links have a focusable target',\n    friendlySummary: 'Make sure any \"skip to content\" link targets an existing, focusable element.',\n  },\n  tabindex: {\n    title: 'tabindex values',\n    axeSummary: 'Ensure tabindex attribute values are not greater than 0',\n    friendlySummary: \"Don't use tabindex values greater than 0.\",\n  },\n  'table-duplicate-name': {\n    title: 'Duplicate names for table',\n    axeSummary: 'Ensure the <caption> does not duplicate the summary attribute text',\n    friendlySummary:\n      \"Don't use the same text in both a table's <caption> and its summary attribute.\",\n  },\n};\n\n// Rules correspond to WCAG AAA success criteria (axe-core does not run these by default, as AAA is often optional).\nconst axeRuleMapping_wcag_2_x_aaa: AxeRuleMap = {\n  'color-contrast-enhanced': {\n    title: 'Enhanced color contrast',\n    axeSummary:\n      'Ensure contrast between text and background meets WCAG 2 AAA enhanced contrast thresholds',\n    friendlySummary: 'Use extra-high contrast for text and background to meet WCAG AAA level.',\n  },\n  'identical-links-same-purpose': {\n    title: 'Same link name, same purpose',\n    axeSummary: 'Ensure links with the same accessible name serve a similar purpose',\n    friendlySummary:\n      'If two links have the same text, they should do the same thing (lead to the same content).',\n  },\n  'meta-refresh-no-exceptions': {\n    title: 'No <meta http-equiv=\"refresh\">',\n    axeSummary:\n      'Ensure <meta http-equiv=\"refresh\"> is not used for delayed refresh (no exceptions)',\n    friendlySummary:\n      'Don\\'t auto-refresh or redirect pages using <meta http-equiv=\"refresh\"> even with a delay.',\n  },\n};\n\n// Rules are experimental (in development) and disabled by default in axe-core (they may be enabled in axe browser extensions).\nconst axeRuleMapping_experimental: AxeRuleMap = {\n  'css-orientation-lock': {\n    title: 'CSS orientation lock',\n    axeSummary:\n      'Ensure content is not locked to a specific display orientation (works in all orientations)',\n    friendlySummary:\n      \"Don't lock content to one screen orientation; support both portrait and landscape modes.\",\n  },\n  'focus-order-semantics': {\n    title: 'Focus order semantic role',\n    axeSummary: 'Ensure elements in the tab order have a role appropriate for interactive content',\n    friendlySummary:\n      'Ensure elements in the tab order have a role appropriate for interactive content',\n  },\n  'hidden-content': {\n    title: 'Hidden content',\n    axeSummary: 'Informs users about hidden content',\n    friendlySummary: 'Display hidden content on the page for test analysis.',\n  },\n  'label-content-name-mismatch': {\n    title: 'Content name mismatch',\n    axeSummary:\n      'Ensure elements labeled by their content include that text in their accessible name',\n    friendlySummary:\n      \"If an element's visible text serves as its label, include that text in its accessible name.\",\n  },\n  'p-as-heading': {\n    title: 'No <p> headings',\n    axeSummary: \"Ensure <p> elements aren't styled to look like headings (use real headings)\",\n    friendlySummary:\n      \"Don't just style a <p> to look like a heading – use an actual heading tag for headings.\",\n  },\n  'table-fake-caption': {\n    title: 'Table caption',\n    axeSummary: 'Ensure that tables with a caption use the <caption> element',\n    friendlySummary: 'Use a <caption> element for table captions instead of just styled text.',\n  },\n  'td-has-header': {\n    title: '<td> has header',\n    axeSummary: 'Ensure each non-empty data cell in large tables (3×3+) has one or more headers',\n    friendlySummary:\n      'Every data cell in large tables should be associated with at least one header cell.',\n  },\n};\n\n// Rules are deprecated (no longer recommended and disabled by default). They may be removed in future axe-core releases.\nconst axeRuleMapping_deprecated: AxeRuleMap = {\n  'aria-roledescription': {\n    title: 'aria-roledescription',\n    axeSummary:\n      'Ensure aria-roledescription is only used on elements with an implicit or explicit role',\n    friendlySummary: 'Only use aria-roledescription on elements that already have a defined role.',\n  },\n};\n\nexport const combinedRulesMap: AxeRuleMap = {\n  ...axeRuleMapping_wcag_2_0_a_aa,\n  ...axeRuleMapping_wcag_2_1_a_aa,\n  ...axeRuleMapping_wcag_2_2_a_aa,\n  ...axeRuleMapping_wcag_2_x_aaa,\n  ...axeRuleMapping_best_practices,\n  ...axeRuleMapping_experimental,\n  ...axeRuleMapping_deprecated,\n};\n"
  },
  {
    "path": "code/addons/a11y/src/a11yRunner.test.ts",
    "content": "import type { Mock } from 'vitest';\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { addons } from 'storybook/preview-api';\n\nimport { EVENTS } from './constants.ts';\n\nvi.mock('storybook/preview-api');\nconst mockedAddons = vi.mocked(addons);\n\ndescribe('a11yRunner', () => {\n  let mockChannel: { on: Mock; emit?: Mock };\n\n  beforeEach(() => {\n    mockedAddons.getChannel.mockReset();\n\n    mockChannel = { on: vi.fn(), emit: vi.fn() };\n    mockedAddons.getChannel.mockReturnValue(mockChannel as any);\n  });\n\n  it('should listen to events', async () => {\n    await import('./a11yRunner.ts');\n\n    expect(mockedAddons.getChannel).toHaveBeenCalled();\n    expect(mockChannel.on).toHaveBeenCalledWith(EVENTS.MANUAL, expect.any(Function));\n  });\n});\n"
  },
  {
    "path": "code/addons/a11y/src/a11yRunner.ts",
    "content": "import { ElementA11yParameterError } from 'storybook/internal/preview-errors';\n\nimport { global } from '@storybook/global';\n\nimport type { AxeResults, ContextProp, ContextSpec } from 'axe-core';\nimport { addons, waitForAnimations } from 'storybook/preview-api';\n\nimport { withLinkPaths } from './a11yRunnerUtils.ts';\nimport { EVENTS } from './constants.ts';\nimport type { A11yParameters } from './params.ts';\n\nconst { document } = global;\n\nconst channel = addons.getChannel();\n\nconst DEFAULT_PARAMETERS = { config: {}, options: {} } as const;\n\nconst DISABLED_RULES = [\n  // In component testing, landmarks are not always present\n  // and the rule check can cause false positives\n  'region',\n] as const;\n\n// A simple queue to run axe-core in sequence\n// This is necessary because axe-core is not designed to run in parallel\nconst queue: (() => Promise<void>)[] = [];\nlet isRunning = false;\n\nconst runNext = async () => {\n  if (queue.length === 0) {\n    isRunning = false;\n    return;\n  }\n\n  isRunning = true;\n  const next = queue.shift();\n  if (next) {\n    await next();\n  }\n  runNext();\n};\n\nexport const run = async (input: A11yParameters = DEFAULT_PARAMETERS, storyId: string) => {\n  const axeCore = await import('axe-core');\n  // We do this workaround when Vite projects can't optimize deps in pnpm projects\n  // as axe-core is UMD and therefore won't resolve.\n  // In that case, we just use the global axe (which will be there as a side effect of UMD import).\n  const axe = axeCore?.default || (globalThis as any).axe;\n\n  const { config = {}, options = {} } = input;\n\n  // @ts-expect-error - the whole point of this is to error if 'element' is passed\n  if (input.element) {\n    throw new ElementA11yParameterError();\n  }\n\n  const context: ContextSpec = {\n    include: document?.body,\n    exclude: ['.sb-wrapper', '#storybook-docs', '#storybook-highlights-root'], // Internal Storybook elements that are always in the document\n  };\n\n  if (input.context) {\n    const hasInclude =\n      typeof input.context === 'object' &&\n      'include' in input.context &&\n      input.context.include !== undefined;\n    const hasExclude =\n      typeof input.context === 'object' &&\n      'exclude' in input.context &&\n      input.context.exclude !== undefined;\n\n    // 1. if context.include exists, use it\n    if (hasInclude) {\n      context.include = (input.context as any).include as ContextProp;\n    } else if (!hasInclude && !hasExclude) {\n      // 2. if context exists, but it's not an object with include or exclude, it's an implicit include to be used directly\n      context.include = input.context as ContextProp;\n    }\n\n    // 3. if context.exclude exists, merge it with the default exclude\n    if (hasExclude) {\n      context.exclude = (context.exclude as any).concat((input.context as any).exclude);\n    }\n  }\n\n  axe.reset();\n\n  const configWithDefault = {\n    ...config,\n    rules: [...DISABLED_RULES.map((id) => ({ id, enabled: false })), ...(config?.rules ?? [])],\n  };\n\n  axe.configure(configWithDefault);\n\n  return new Promise<AxeResults>((resolve, reject) => {\n    const highlightsRoot = document?.getElementById('storybook-highlights-root');\n    if (highlightsRoot) {\n      highlightsRoot.style.display = 'none';\n    }\n\n    const task = async () => {\n      try {\n        const result = await axe.run(context, options);\n        const resultWithLinks = withLinkPaths(result, storyId);\n        resolve(resultWithLinks);\n      } catch (error) {\n        reject(error);\n      }\n    };\n\n    queue.push(task);\n\n    if (!isRunning) {\n      runNext();\n    }\n\n    if (highlightsRoot) {\n      highlightsRoot.style.display = '';\n    }\n  });\n};\n\nchannel.on(EVENTS.MANUAL, async (storyId: string, input: A11yParameters = DEFAULT_PARAMETERS) => {\n  try {\n    await waitForAnimations();\n    const result = await run(input, storyId);\n    // Axe result contains class instances, which telejson deserializes in a\n    // way that violates:\n    //  Content Security Policy directive: \"script-src 'self' 'unsafe-inline'\".\n    const resultJson = JSON.parse(JSON.stringify(result));\n    channel.emit(EVENTS.RESULT, resultJson, storyId);\n  } catch (error) {\n    channel.emit(EVENTS.ERROR, error);\n  }\n});\n"
  },
  {
    "path": "code/addons/a11y/src/a11yRunnerUtils.test.ts",
    "content": "// @vitest-environment happy-dom\nimport { describe, expect, it } from 'vitest';\n\nimport type { AxeResults } from 'axe-core';\n\nimport { withLinkPaths } from './a11yRunnerUtils.ts';\n\ndescribe('a11yRunnerUtils', () => {\n  describe('withLinkPaths', () => {\n    it('should add link paths to the axe results', () => {\n      const axeResults = {\n        violations: [\n          {\n            id: 'color-contrast',\n            nodes: [\n              {\n                html: '<button>Click me</button>',\n                target: ['.button'],\n              },\n              {\n                html: '<a href=\"#\">Link</a>',\n                target: ['.link'],\n              },\n            ],\n          },\n        ],\n        passes: [\n          {\n            id: 'button-name',\n            nodes: [\n              {\n                html: '<button>Valid Button</button>',\n                target: ['.valid-button'],\n              },\n            ],\n          },\n        ],\n        incomplete: [\n          {\n            id: 'aria-valid',\n            nodes: [\n              {\n                html: '<div aria-label=\"test\">Test</div>',\n                target: ['.aria-test'],\n              },\n            ],\n          },\n        ],\n        inapplicable: [],\n      } as unknown as AxeResults;\n\n      const result = withLinkPaths(axeResults, 'test-story-id');\n\n      expect(result.violations[0].nodes[0].linkPath).toBe(\n        '/?path=/story/test-story-id&addonPanel=storybook/a11y/panel&a11ySelection=violations.color-contrast.1'\n      );\n      expect(result.violations[0].nodes[1].linkPath).toBe(\n        '/?path=/story/test-story-id&addonPanel=storybook/a11y/panel&a11ySelection=violations.color-contrast.2'\n      );\n\n      expect(result.passes[0].nodes[0].linkPath).toBe(\n        '/?path=/story/test-story-id&addonPanel=storybook/a11y/panel&a11ySelection=passes.button-name.1'\n      );\n\n      expect(result.incomplete[0].nodes[0].linkPath).toBe(\n        '/?path=/story/test-story-id&addonPanel=storybook/a11y/panel&a11ySelection=incomplete.aria-valid.1'\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "code/addons/a11y/src/a11yRunnerUtils.ts",
    "content": "import { global } from '@storybook/global';\n\nimport type { AxeResults, Result } from 'axe-core';\n\nimport { PANEL_ID } from './constants.ts';\nimport type { EnhancedResults } from './types.ts';\n\nconst { document } = global;\n\n// Augment axe results with debuggable links\nexport const withLinkPaths = (results: AxeResults, storyId: string) => {\n  const pathname = document.location.pathname.replace(/iframe\\.html$/, '');\n\n  // Make a copy of the original results\n  const enhancedResults = { ...results };\n\n  // Enhance specific keys\n  const propertiesToAugment = ['incomplete', 'passes', 'violations'] as const;\n\n  propertiesToAugment.forEach((key) => {\n    if (Array.isArray(results[key])) {\n      enhancedResults[key] = results[key].map((result: Result) => ({\n        ...result,\n        nodes: result.nodes.map((node, index) => {\n          const id = `${key}.${result.id}.${index + 1}`;\n          const linkPath = `${pathname}?path=/story/${storyId}&addonPanel=${PANEL_ID}&a11ySelection=${id}`;\n          return { id, ...node, linkPath };\n        }),\n      }));\n    }\n  });\n\n  return enhancedResults as EnhancedResults;\n};\n"
  },
  {
    "path": "code/addons/a11y/src/axeRuleMappingHelper.ts",
    "content": "import { combinedRulesMap } from './AccessibilityRuleMaps.ts';\nimport type { EnhancedResult } from './types.ts';\n\nexport const getTitleForAxeResult = (axeResult: EnhancedResult): string =>\n  combinedRulesMap[axeResult.id]?.title || axeResult.id;\n\nexport const getFriendlySummaryForAxeResult = (axeResult: EnhancedResult): string | undefined =>\n  combinedRulesMap[axeResult.id]?.friendlySummary || axeResult.description;\n"
  },
  {
    "path": "code/addons/a11y/src/components/A11YPanel.stories.tsx",
    "content": "import React from 'react';\n\nimport { ManagerContext } from 'storybook/manager-api';\nimport { expect, fn, userEvent, waitFor, within } from 'storybook/test';\nimport { styled } from 'storybook/theming';\n\nimport preview from '../../../../.storybook/preview.tsx';\nimport { results } from '../results.mock.ts';\nimport { type EnhancedResults, RuleType } from '../types.ts';\nimport { A11YPanel } from './A11YPanel.tsx';\nimport { A11yContext } from './A11yContext.tsx';\nimport type { A11yContextStore } from './A11yContext.tsx';\n\nconst emptyResults: EnhancedResults = {\n  passes: [],\n  incomplete: [],\n  violations: [],\n  toolOptions: {},\n  inapplicable: [],\n  testEngine: { name: '', version: '' },\n  testRunner: { name: '' },\n  testEnvironment: { userAgent: '', windowWidth: 0, windowHeight: 0 },\n  url: '',\n  timestamp: '',\n};\n\nconst StyledWrapper = styled.div(({ theme }) => ({\n  backgroundColor: theme.background.content,\n  fontSize: theme.typography.size.s2 - 1,\n  color: theme.color.defaultText,\n  display: 'block',\n  height: '100%',\n  position: 'absolute',\n  left: 0,\n  right: 0,\n  bottom: 0,\n  overflow: 'auto',\n}));\n\nconst managerContext: any = {\n  state: {},\n  api: {\n    getDocsUrl: fn().mockName('api::getDocsUrl'),\n    getCurrentParameter: fn().mockName('api::getCurrentParameter'),\n  },\n};\n\nconst meta = preview.meta({\n  title: 'Panel',\n  component: A11YPanel,\n  parameters: {\n    layout: 'fullscreen',\n  },\n});\n\nconst context = {\n  parameters: {},\n  handleManual: fn(),\n  highlighted: false,\n  toggleHighlight: fn(),\n  tab: RuleType.VIOLATION,\n  setTab: fn(),\n  setStatus: fn(),\n  handleCopyLink: fn(),\n  toggleOpen: fn(),\n  allExpanded: false,\n  handleCollapseAll: fn(),\n  handleExpandAll: fn(),\n  handleSelectionChange: fn(),\n  handleJumpToElement: fn(),\n};\n\nconst Template = (\n  args: Pick<A11yContextStore, 'results' | 'error' | 'status' | 'discrepancy' | 'selectedItems'> &\n    Pick<Partial<A11yContextStore>, 'parameters'>\n) => (\n  <A11yContext.Provider value={{ ...context, ...args }}>\n    <ManagerContext.Provider value={managerContext}>\n      <StyledWrapper id=\"panel-tab-content\">\n        <A11YPanel />\n      </StyledWrapper>\n    </ManagerContext.Provider>\n  </A11yContext.Provider>\n);\n\nexport const Initializing = meta.story({\n  render: () => {\n    return (\n      <Template\n        results={emptyResults}\n        status=\"initial\"\n        error={null}\n        discrepancy={null}\n        selectedItems={new Map()}\n      />\n    );\n  },\n});\n\nexport const Disabled = meta.story({\n  render: () => {\n    return (\n      <Template\n        results={emptyResults}\n        status=\"initial\"\n        error={null}\n        discrepancy={null}\n        selectedItems={new Map()}\n        parameters={{ disable: true }}\n      />\n    );\n  },\n});\n\nexport const Manual = meta.story({\n  render: () => {\n    return (\n      <Template\n        results={emptyResults}\n        status=\"manual\"\n        error={null}\n        discrepancy={null}\n        selectedItems={new Map()}\n      />\n    );\n  },\n});\n\nexport const ManualWithDiscrepancy = meta.story({\n  render: () => {\n    return (\n      <Template\n        results={emptyResults}\n        status=\"manual\"\n        error={null}\n        discrepancy={'cliFailedButModeManual'}\n        selectedItems={new Map()}\n      />\n    );\n  },\n});\n\nexport const Running = meta.story({\n  render: () => {\n    return (\n      <Template\n        results={emptyResults}\n        status=\"running\"\n        error={null}\n        discrepancy={null}\n        selectedItems={new Map()}\n      />\n    );\n  },\n});\n\nexport const ReadyWithResults = meta.story({\n  render: () => {\n    return (\n      <Template\n        results={results}\n        status=\"ready\"\n        error={null}\n        discrepancy={null}\n        selectedItems={\n          new Map([\n            [\n              `${RuleType.VIOLATION}.${results.violations[0].id}`,\n              `${RuleType.VIOLATION}.${results.violations[0].id}.1`,\n            ],\n          ])\n        }\n      />\n    );\n  },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const btn = await waitFor(\n      () => canvas.findByRole('button', { name: /Rerun accessibility scan/ }),\n      { timeout: 3000 }\n    );\n    await userEvent.click(btn);\n    expect(context.handleManual).toHaveBeenCalled();\n  },\n});\n\nexport const ReadyWithResultsDiscrepancyCLIPassedBrowserFailed = meta.story({\n  render: () => {\n    return (\n      <Template\n        results={results}\n        status=\"ready\"\n        error={null}\n        discrepancy={'cliPassedBrowserFailed'}\n        selectedItems={\n          new Map([\n            [\n              `${RuleType.VIOLATION}.${results.violations[0].id}`,\n              `${RuleType.VIOLATION}.${results.violations[0].id}.1`,\n            ],\n          ])\n        }\n      />\n    );\n  },\n});\n\nexport const Error = meta.story({\n  render: () => {\n    return (\n      <Template\n        results={emptyResults}\n        status=\"error\"\n        error={`TypeError: Configured rule { impact: \"moderate\", disable: true } is invalid. Rules must be an object with at least an id property.`}\n        discrepancy={null}\n        selectedItems={new Map()}\n      />\n    );\n  },\n});\n\nexport const ErrorStateWithObject = meta.story({\n  render: () => {\n    return (\n      <Template\n        results={emptyResults}\n        status=\"error\"\n        error={{ message: 'Test error object message' }}\n        discrepancy={null}\n        selectedItems={new Map()}\n      />\n    );\n  },\n});\n\nexport const Broken = meta.story({\n  render: () => {\n    return (\n      <Template\n        results={emptyResults}\n        status=\"component-test-error\"\n        error={null}\n        discrepancy={null}\n        selectedItems={new Map()}\n      />\n    );\n  },\n});\n"
  },
  {
    "path": "code/addons/a11y/src/components/A11YPanel.test.tsx",
    "content": "// @vitest-environment happy-dom\n/// <reference types=\"@testing-library/jest-dom\" />\nimport { fireEvent, render } from '@testing-library/react';\nimport { describe, expect, it, vi } from 'vitest';\n\nimport React from 'react';\n\nimport * as managerApi from 'storybook/manager-api';\nimport { ThemeProvider, convert, themes } from 'storybook/theming';\n\nimport { type EnhancedResults } from '../types.ts';\nimport { A11YPanel } from './A11YPanel.tsx';\nimport { type A11yContextStore, useA11yContext } from './A11yContext.tsx';\n\nvi.mock('storybook/manager-api');\nconst mockedManagerApi = vi.mocked(managerApi);\n\nvi.mock('./A11yContext');\nconst mockedUseA11yContext = vi.mocked(useA11yContext);\n\nmockedManagerApi.useParameter.mockReturnValue({\n  manual: false,\n} as any);\n\nconst emptyResults: EnhancedResults = {\n  passes: [],\n  incomplete: [],\n  violations: [],\n  toolOptions: {},\n  inapplicable: [],\n  testEngine: { name: '', version: '' },\n  testRunner: { name: '' },\n  testEnvironment: { userAgent: '', windowWidth: 0, windowHeight: 0 },\n  url: '',\n  timestamp: '',\n};\n\ndescribe('A11YPanel', () => {\n  it('should render initializing state', () => {\n    mockedUseA11yContext.mockReturnValue({\n      parameters: {},\n      results: emptyResults,\n      status: 'initial',\n      handleManual: vi.fn(),\n      error: null,\n    } as Partial<A11yContextStore> as any);\n\n    const element = render(\n      <ThemeProvider theme={convert(themes.light)}>\n        <A11YPanel />\n      </ThemeProvider>\n    );\n\n    expect(element.getByText('Please wait while the addon is initializing...')).toBeInTheDocument();\n  });\n\n  it('should render manual state', () => {\n    const handleManual = vi.fn();\n    mockedUseA11yContext.mockReturnValue({\n      parameters: {},\n      results: emptyResults,\n      status: 'manual',\n      handleManual,\n      error: null,\n    } as Partial<A11yContextStore> as any);\n\n    const component = render(\n      <ThemeProvider theme={convert(themes.light)}>\n        <A11YPanel />\n      </ThemeProvider>\n    );\n\n    const runTestButton = component.getByText('Run accessibility scan');\n    expect(runTestButton).toBeInTheDocument();\n\n    fireEvent.click(runTestButton);\n    expect(handleManual).toHaveBeenCalled();\n  });\n\n  it('should render running state', () => {\n    mockedUseA11yContext.mockReturnValue({\n      parameters: {},\n      results: emptyResults,\n      status: 'running',\n      handleManual: vi.fn(),\n      error: null,\n    } as Partial<A11yContextStore> as any);\n\n    const component = render(\n      <ThemeProvider theme={convert(themes.light)}>\n        <A11YPanel />\n      </ThemeProvider>\n    );\n\n    expect(\n      component.getByText('Please wait while the accessibility scan is running...')\n    ).toBeInTheDocument();\n  });\n\n  it('should render error state', () => {\n    mockedUseA11yContext.mockReturnValue({\n      parameters: {},\n      results: emptyResults,\n      status: 'error',\n      handleManual: vi.fn(),\n      error: 'Test error message',\n    } as Partial<A11yContextStore> as any);\n\n    const component = render(\n      <ThemeProvider theme={convert(themes.light)}>\n        <A11YPanel />\n      </ThemeProvider>\n    );\n\n    expect(component.container).toHaveTextContent('The accessibility scan encountered an error');\n    expect(component.container).toHaveTextContent('Test error message');\n  });\n\n  it('should render error state with object error', () => {\n    mockedUseA11yContext.mockReturnValue({\n      parameters: {},\n      results: emptyResults,\n      status: 'error',\n      handleManual: vi.fn(),\n      error: { message: 'Test error object message' },\n    } as Partial<A11yContextStore> as any);\n\n    const component = render(\n      <ThemeProvider theme={convert(themes.light)}>\n        <A11YPanel />\n      </ThemeProvider>\n    );\n\n    expect(component.container).toHaveTextContent('The accessibility scan encountered an error');\n    expect(component.container).toHaveTextContent(`{ \"message\": \"Test error object message\" }`);\n  });\n});\n"
  },
  {
    "path": "code/addons/a11y/src/components/A11YPanel.tsx",
    "content": "import React, { useMemo } from 'react';\n\nimport { Badge, Button } from 'storybook/internal/components';\n\nimport { SyncIcon } from '@storybook/icons';\n\nimport { styled } from 'storybook/theming';\n\nimport { RuleType } from '../types.ts';\nimport { useA11yContext } from './A11yContext.tsx';\nimport { Report } from './Report/Report.tsx';\nimport { Tabs } from './Tabs.tsx';\nimport { TestDiscrepancyMessage } from './TestDiscrepancyMessage.tsx';\n\nconst RotatingIcon = styled(SyncIcon)(({ theme }) => ({\n  animation: `${theme.animation.rotate360} 1s linear infinite;`,\n  margin: 4,\n}));\n\nconst Tab = styled.div({\n  display: 'flex',\n  alignItems: 'center',\n  gap: 6,\n});\n\nconst Centered = styled.span(({ theme }) => ({\n  display: 'flex',\n  flexDirection: 'column',\n  alignItems: 'center',\n  justifyContent: 'center',\n  textAlign: 'center',\n  fontSize: theme.typography.size.s2,\n  height: '100%',\n  gap: 24,\n\n  div: {\n    display: 'flex',\n    flexDirection: 'column',\n    alignItems: 'center',\n    gap: 8,\n  },\n  p: {\n    margin: 0,\n    color: theme.textMutedColor,\n  },\n  code: {\n    display: 'inline-block',\n    fontSize: theme.typography.size.s2 - 1,\n    backgroundColor: theme.background.app,\n    border: `1px solid ${theme.color.border}`,\n    borderRadius: 4,\n    padding: '2px 3px',\n  },\n}));\n\nexport const A11YPanel: React.FC = () => {\n  const {\n    parameters,\n    tab,\n    results,\n    status,\n    handleManual,\n    error,\n    discrepancy,\n    handleSelectionChange,\n    selectedItems,\n    toggleOpen,\n  } = useA11yContext();\n\n  const tabs = useMemo(() => {\n    const { passes, incomplete, violations } = results ?? {\n      passes: [],\n      incomplete: [],\n      violations: [],\n    };\n    return [\n      {\n        label: (\n          <Tab>\n            Violations\n            <Badge compact status={tab === 'violations' ? 'active' : 'neutral'}>\n              {violations.length}\n            </Badge>\n          </Tab>\n        ),\n        panel: (\n          <Report\n            items={violations}\n            type={RuleType.VIOLATION}\n            empty=\"No accessibility violations found.\"\n            handleSelectionChange={handleSelectionChange}\n            selectedItems={selectedItems}\n            toggleOpen={toggleOpen}\n          />\n        ),\n        items: violations,\n        type: RuleType.VIOLATION,\n      },\n      {\n        label: (\n          <Tab>\n            Passes\n            <Badge compact status={tab === 'passes' ? 'active' : 'neutral'}>\n              {passes.length}\n            </Badge>\n          </Tab>\n        ),\n        panel: (\n          <Report\n            items={passes}\n            type={RuleType.PASS}\n            empty=\"No passing accessibility checks found.\"\n            handleSelectionChange={handleSelectionChange}\n            selectedItems={selectedItems}\n            toggleOpen={toggleOpen}\n          />\n        ),\n        items: passes,\n        type: RuleType.PASS,\n      },\n      {\n        label: (\n          <Tab>\n            Inconclusive\n            <Badge compact status={tab === 'incomplete' ? 'active' : 'neutral'}>\n              {incomplete.length}\n            </Badge>\n          </Tab>\n        ),\n        panel: (\n          <Report\n            items={incomplete}\n            type={RuleType.INCOMPLETION}\n            empty=\"No inconclusive accessibility checks found.\"\n            handleSelectionChange={handleSelectionChange}\n            selectedItems={selectedItems}\n            toggleOpen={toggleOpen}\n          />\n        ),\n        items: incomplete,\n        type: RuleType.INCOMPLETION,\n      },\n    ];\n  }, [tab, results, handleSelectionChange, selectedItems, toggleOpen]);\n\n  if (parameters.disable || parameters.test === 'off') {\n    return (\n      <Centered>\n        <div>\n          <strong>Accessibility tests are disabled for this story</strong>\n          <p>\n            Update{' '}\n            <code>{parameters.disable ? 'parameters.a11y.disable' : 'parameters.a11y.test'}</code>{' '}\n            to enable accessibility tests.\n          </p>\n        </div>\n      </Centered>\n    );\n  }\n\n  return (\n    <>\n      {discrepancy && <TestDiscrepancyMessage discrepancy={discrepancy} />}\n      {status === 'ready' || status === 'ran' ? (\n        <Tabs key=\"tabs\" tabs={tabs} />\n      ) : (\n        <Centered style={{ marginTop: discrepancy ? '1em' : 0 }}>\n          {status === 'initial' && (\n            <div>\n              <RotatingIcon size={12} />\n              <strong>Preparing accessibility scan</strong>\n              <p>Please wait while the addon is initializing...</p>\n            </div>\n          )}\n          {status === 'manual' && (\n            <>\n              <div>\n                <strong>Accessibility tests run manually for this story</strong>\n                <p>\n                  Results will not show when using the testing module. You can still run\n                  accessibility tests manually.\n                </p>\n              </div>\n              <Button ariaLabel={false} size=\"medium\" onClick={handleManual}>\n                Run accessibility scan\n              </Button>\n              <p>\n                Update <code>globals.a11y.manual</code> to disable manual mode.\n              </p>\n            </>\n          )}\n          {status === 'running' && (\n            <div>\n              <RotatingIcon size={12} />\n              <strong>Accessibility scan in progress</strong>\n              <p>Please wait while the accessibility scan is running...</p>\n            </div>\n          )}\n          {status === 'error' && (\n            <>\n              <div>\n                <strong>The accessibility scan encountered an error</strong>\n                <p>\n                  {typeof error === 'string'\n                    ? error\n                    : error instanceof Error\n                      ? error.toString()\n                      : JSON.stringify(error, null, 2)}\n                </p>\n              </div>\n              <Button ariaLabel={false} size=\"medium\" onClick={handleManual}>\n                Rerun accessibility scan\n              </Button>\n            </>\n          )}\n          {status === 'component-test-error' && (\n            <>\n              <div>\n                <strong>This story&apos;s component tests failed</strong>\n                <p>\n                  Automated accessibility tests will not run until this is resolved. You can still\n                  test manually.\n                </p>\n              </div>\n              <Button ariaLabel={false} size=\"medium\" onClick={handleManual}>\n                Run accessibility scan\n              </Button>\n            </>\n          )}\n        </Centered>\n      )}\n    </>\n  );\n};\n"
  },
  {
    "path": "code/addons/a11y/src/components/A11yContext.test.tsx",
    "content": "// @vitest-environment happy-dom\nimport { act, cleanup, render } from '@testing-library/react';\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport * as React from 'react';\n\nimport {\n  STORY_FINISHED,\n  STORY_RENDER_PHASE_CHANGED,\n  type StoryFinishedPayload,\n} from 'storybook/internal/core-events';\n\nimport type { AxeResults } from 'axe-core';\nimport * as api from 'storybook/manager-api';\n\nimport { EVENTS, UI_STATE_ID } from '../constants.ts';\nimport { RuleType } from '../types.ts';\nimport { A11yContextProvider, useA11yContext } from './A11yContext.tsx';\n\nvi.mock('storybook/manager-api');\nconst mockedApi = vi.mocked(api);\n\nconst storyId = 'button--primary';\nconst axeResult: Partial<AxeResults> = {\n  incomplete: [\n    {\n      id: 'color-contrast',\n      impact: 'serious',\n      tags: [],\n      description:\n        'Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds',\n      help: 'Elements must have sufficient color contrast',\n      helpUrl: 'https://dequeuniversity.com/rules/axe/3.2/color-contrast?application=axeAPI',\n      nodes: [],\n    },\n  ],\n  passes: [\n    {\n      id: 'aria-allowed-attr',\n      impact: undefined,\n      tags: [],\n      description: \"Ensures ARIA attributes are allowed for an element's role\",\n      help: 'Elements must only use allowed ARIA attributes',\n      helpUrl: 'https://dequeuniversity.com/rules/axe/3.2/aria-allowed-attr?application=axeAPI',\n      nodes: [],\n    },\n  ],\n  violations: [\n    {\n      id: 'color-contrast',\n      impact: 'serious',\n      tags: [],\n      description:\n        'Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds',\n      help: 'Elements must have sufficient color contrast',\n      helpUrl: 'https://dequeuniversity.com/rules/axe/3.2/color-contrast?application=axeAPI',\n      nodes: [],\n    },\n  ],\n};\n\ndescribe('A11yContext', () => {\n  afterEach(() => {\n    cleanup();\n  });\n\n  const onAllStatusChange = vi.fn();\n  const getAll = vi.fn();\n  const set = vi.fn();\n  const onSelect = vi.fn();\n  const unset = vi.fn();\n\n  const getCurrentStoryData = vi.fn();\n  const getParameters = vi.fn();\n  const getQueryParam = vi.fn();\n\n  beforeEach(() => {\n    mockedApi.experimental_getStatusStore.mockReturnValue({\n      onAllStatusChange,\n      getAll,\n      set,\n      onSelect,\n      unset,\n    } as any);\n    mockedApi.useAddonState.mockImplementation((_, defaultState) => React.useState(defaultState));\n    mockedApi.useChannel.mockReturnValue(vi.fn());\n    getCurrentStoryData.mockReturnValue({ id: storyId, type: 'story' });\n    getParameters.mockReturnValue({});\n    mockedApi.useStorybookApi.mockReturnValue({\n      getCurrentStoryData,\n      getParameters,\n      getQueryParam,\n    } as any);\n    mockedApi.useParameter.mockReturnValue({ manual: false });\n    mockedApi.useStorybookState.mockReturnValue({ storyId } as any);\n    mockedApi.useGlobals.mockReturnValue([{ a11y: {} }] as any);\n\n    mockedApi.useChannel.mockClear();\n    mockedApi.useStorybookApi.mockClear();\n    mockedApi.useAddonState.mockClear();\n    mockedApi.useParameter.mockClear();\n    mockedApi.useStorybookState.mockClear();\n    mockedApi.useGlobals.mockClear();\n  });\n\n  it('should render children', () => {\n    const { getByTestId } = render(\n      <A11yContextProvider>\n        <div data-testid=\"child\" />\n      </A11yContextProvider>\n    );\n    expect(getByTestId('child')).toBeTruthy();\n  });\n\n  it('should handle STORY_FINISHED event correctly', () => {\n    const emit = vi.fn();\n    mockedApi.useChannel.mockReturnValue(emit);\n\n    const Component = () => {\n      const { results } = useA11yContext();\n      return (\n        <>\n          {!!results?.passes.length && (\n            <div data-testid=\"anyPassesResults\">{JSON.stringify(results.passes)}</div>\n          )}\n          {!!results?.incomplete.length && (\n            <div data-testid=\"anyIncompleteResults\">{JSON.stringify(results.incomplete)}</div>\n          )}\n          {!!results?.violations.length && (\n            <div data-testid=\"anyViolationsResults\">{JSON.stringify(results.violations)}</div>\n          )}\n        </>\n      );\n    };\n\n    const { queryByTestId } = render(\n      <A11yContextProvider>\n        <Component />\n      </A11yContextProvider>\n    );\n\n    expect(queryByTestId('anyPassesResults')).toBeFalsy();\n    expect(queryByTestId('anyIncompleteResults')).toBeFalsy();\n    expect(queryByTestId('anyViolationsResults')).toBeFalsy();\n\n    const useChannelArgs = mockedApi.useChannel.mock.calls[0][0];\n    const storyFinishedPayload: StoryFinishedPayload = {\n      storyId,\n      status: 'error',\n      reporters: [\n        {\n          type: 'a11y',\n          result: axeResult as any,\n          status: 'failed',\n          version: 1,\n        },\n      ],\n    };\n\n    act(() => useChannelArgs[STORY_FINISHED](storyFinishedPayload));\n    expect(queryByTestId('anyPassesResults')).toHaveTextContent(JSON.stringify(axeResult.passes));\n    expect(queryByTestId('anyIncompleteResults')).toHaveTextContent(\n      JSON.stringify(axeResult.incomplete)\n    );\n    expect(queryByTestId('anyViolationsResults')).toHaveTextContent(\n      JSON.stringify(axeResult.violations)\n    );\n  });\n\n  it('should set discrepancy to cliFailedButModeManual when in manual mode (set via globals)', () => {\n    mockedApi.useGlobals.mockReturnValue([{ a11y: { manual: true } }] as any);\n    mockedApi.experimental_useStatusStore.mockReturnValue('status-value:error');\n\n    const Component = () => {\n      const { discrepancy } = useA11yContext();\n      return <div data-testid=\"discrepancy\">{discrepancy}</div>;\n    };\n\n    const { getByTestId } = render(\n      <A11yContextProvider>\n        <Component />\n      </A11yContextProvider>\n    );\n\n    expect(getByTestId('discrepancy').textContent).toBe('cliFailedButModeManual');\n  });\n\n  it('should set discrepancy to cliPassedBrowserFailed', () => {\n    mockedApi.useParameter.mockReturnValue({ manual: true });\n    mockedApi.experimental_useStatusStore.mockReturnValue('status-value:success');\n\n    const Component = () => {\n      const { discrepancy } = useA11yContext();\n      return <div data-testid=\"discrepancy\">{discrepancy}</div>;\n    };\n\n    const { getByTestId } = render(\n      <A11yContextProvider>\n        <Component />\n      </A11yContextProvider>\n    );\n\n    const storyFinishedPayload: StoryFinishedPayload = {\n      storyId,\n      status: 'error',\n      reporters: [\n        {\n          type: 'a11y',\n          result: axeResult as any,\n          status: 'failed',\n          version: 1,\n        },\n      ],\n    };\n\n    const useChannelArgs = mockedApi.useChannel.mock.calls[0][0];\n\n    act(() => useChannelArgs[STORY_FINISHED](storyFinishedPayload));\n\n    expect(getByTestId('discrepancy').textContent).toBe('cliPassedBrowserFailed');\n  });\n\n  it('should handle STORY_RENDER_PHASE_CHANGED event correctly', () => {\n    const emit = vi.fn();\n    mockedApi.useChannel.mockReturnValue(emit);\n\n    const Component = () => {\n      const { status } = useA11yContext();\n      return <div data-testid=\"status\">{status}</div>;\n    };\n\n    const { queryByTestId } = render(\n      <A11yContextProvider>\n        <Component />\n      </A11yContextProvider>\n    );\n\n    expect(queryByTestId('status')).toHaveTextContent('initial');\n\n    const useChannelArgs = mockedApi.useChannel.mock.calls[0][0];\n\n    act(() => useChannelArgs[STORY_RENDER_PHASE_CHANGED]({ newPhase: 'loading' }));\n    expect(queryByTestId('status')).toHaveTextContent('initial');\n\n    act(() => useChannelArgs[STORY_RENDER_PHASE_CHANGED]({ newPhase: 'afterEach' }));\n    expect(queryByTestId('status')).toHaveTextContent('running');\n  });\n\n  it('should handle STORY_RENDER_PHASE_CHANGED event correctly when in manual mode (set via globals)', () => {\n    mockedApi.useGlobals.mockReturnValue([{ a11y: { manual: true } }] as any);\n\n    const emit = vi.fn();\n    mockedApi.useChannel.mockReturnValue(emit);\n\n    const Component = () => {\n      const { status } = useA11yContext();\n      return <div data-testid=\"status\">{status}</div>;\n    };\n\n    const { queryByTestId } = render(\n      <A11yContextProvider>\n        <Component />\n      </A11yContextProvider>\n    );\n\n    expect(queryByTestId('status')).toHaveTextContent('manual');\n\n    const useChannelArgs = mockedApi.useChannel.mock.calls[0][0];\n\n    act(() => useChannelArgs[STORY_RENDER_PHASE_CHANGED]({ newPhase: 'loading' }));\n    expect(queryByTestId('status')).toHaveTextContent('manual');\n\n    act(() => useChannelArgs[STORY_RENDER_PHASE_CHANGED]({ newPhase: 'afterEach' }));\n    expect(queryByTestId('status')).toHaveTextContent('manual');\n  });\n\n  it('should handle STORY_FINISHED event with error correctly', () => {\n    const emit = vi.fn();\n    mockedApi.useChannel.mockReturnValue(emit);\n\n    const Component = () => {\n      const { error } = useA11yContext();\n      return <div data-testid=\"error\">{error ? (error as any).message : 'No Error'}</div>;\n    };\n\n    const { getByTestId } = render(\n      <A11yContextProvider>\n        <Component />\n      </A11yContextProvider>\n    );\n\n    expect(getByTestId('error').textContent).toBe('No Error');\n\n    const useChannelArgs = mockedApi.useChannel.mock.calls[0][0];\n    const storyFinishedPayload: StoryFinishedPayload = {\n      storyId,\n      status: 'error',\n      reporters: [\n        {\n          status: 'failed',\n          version: 1,\n          type: 'a11y',\n          result: { error: new Error('Test error') } as any,\n        },\n      ],\n    };\n\n    act(() => useChannelArgs[STORY_FINISHED](storyFinishedPayload));\n    expect(getByTestId('error').textContent).toBe('Test error');\n  });\n\n  it('should handle manual run correctly', () => {\n    const emit = vi.fn();\n    mockedApi.useChannel.mockReturnValue(emit);\n\n    const Component = () => {\n      const { handleManual } = useA11yContext();\n      return (\n        <button onClick={handleManual} data-testid=\"manualRunButton\">\n          Run Manual\n        </button>\n      );\n    };\n\n    const { getByTestId } = render(\n      <A11yContextProvider>\n        <Component />\n      </A11yContextProvider>\n    );\n\n    act(() => {\n      getByTestId('manualRunButton').click();\n    });\n\n    expect(emit).toHaveBeenCalledWith(EVENTS.MANUAL, storyId, expect.any(Object));\n  });\n});\n"
  },
  {
    "path": "code/addons/a11y/src/components/A11yContext.tsx",
    "content": "import type { FC, PropsWithChildren } from 'react';\nimport React, {\n  createContext,\n  useCallback,\n  useContext,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n} from 'react';\n\nimport {\n  STORY_CHANGED,\n  STORY_FINISHED,\n  STORY_HOT_UPDATED,\n  STORY_RENDER_PHASE_CHANGED,\n  type StoryFinishedPayload,\n} from 'storybook/internal/core-events';\n\nimport type { ClickEventDetails, HighlightMenuItem } from 'storybook/highlight';\nimport { HIGHLIGHT, REMOVE_HIGHLIGHT, SCROLL_INTO_VIEW } from 'storybook/highlight';\nimport {\n  experimental_getStatusStore,\n  experimental_useStatusStore,\n  useAddonState,\n  useChannel,\n  useGlobals,\n  useParameter,\n  useStorybookApi,\n  useStorybookState,\n} from 'storybook/manager-api';\nimport type { Report } from 'storybook/preview-api';\nimport { convert, themes } from 'storybook/theming';\n\nimport { getFriendlySummaryForAxeResult, getTitleForAxeResult } from '../axeRuleMappingHelper.ts';\nimport {\n  ADDON_ID,\n  EVENTS,\n  STATUS_TYPE_ID_A11Y,\n  STATUS_TYPE_ID_COMPONENT_TEST,\n} from '../constants.ts';\nimport type { A11yParameters } from '../params.ts';\nimport type { A11yReport, EnhancedResult, EnhancedResults, Status } from '../types.ts';\nimport { RuleType } from '../types.ts';\nimport type { TestDiscrepancy } from './TestDiscrepancyMessage.tsx';\n\n// These elements should not be highlighted because they usually cover the whole page.\n// They may still appear in the results and be selectable though.\nconst unhighlightedSelectors = ['html', 'body', 'main'];\n\nexport interface A11yContextStore {\n  parameters: A11yParameters;\n  results: EnhancedResults | undefined;\n  highlighted: boolean;\n  toggleHighlight: () => void;\n  tab: RuleType;\n  handleCopyLink: (key: string) => void;\n  setTab: (type: RuleType) => void;\n  status: Status;\n  setStatus: (status: Status) => void;\n  error: unknown;\n  handleManual: () => void;\n  discrepancy: TestDiscrepancy;\n  selectedItems: Map<string, string>;\n  toggleOpen: (event: React.SyntheticEvent<Element>, type: RuleType, item: EnhancedResult) => void;\n  allExpanded: boolean;\n  handleCollapseAll: () => void;\n  handleExpandAll: () => void;\n  handleJumpToElement: (target: string) => void;\n  handleSelectionChange: (key: string) => void;\n}\n\nconst theme = convert(themes.light);\nconst colorsByType = {\n  [RuleType.VIOLATION]: theme.color.negative,\n  [RuleType.PASS]: theme.color.positive,\n  [RuleType.INCOMPLETION]: theme.color.warning,\n};\n\nexport const A11yContext = createContext<A11yContextStore>({\n  parameters: {},\n  results: undefined,\n  highlighted: false,\n  toggleHighlight: () => {},\n  tab: RuleType.VIOLATION,\n  handleCopyLink: () => {},\n  setTab: () => {},\n  setStatus: () => {},\n  status: 'initial',\n  error: undefined,\n  handleManual: () => {},\n  discrepancy: null,\n  selectedItems: new Map(),\n  allExpanded: false,\n  toggleOpen: () => {},\n  handleCollapseAll: () => {},\n  handleExpandAll: () => {},\n  handleJumpToElement: () => {},\n  handleSelectionChange: () => {},\n});\n\nexport const A11yContextProvider: FC<PropsWithChildren> = (props) => {\n  const parameters = useParameter<A11yParameters>('a11y', {});\n\n  const [globals] = useGlobals() ?? [];\n  const api = useStorybookApi();\n\n  const getInitialStatus = useCallback((manual = false) => (manual ? 'manual' : 'initial'), []);\n\n  const manual = useMemo(() => globals?.a11y?.manual ?? false, [globals?.a11y?.manual]);\n\n  const a11ySelection = useMemo(() => {\n    const value = api.getQueryParam('a11ySelection');\n    if (value) {\n      api.setQueryParams({ a11ySelection: '' });\n    }\n    return value;\n  }, [api]);\n\n  const [state, setState] = useAddonState<{\n    ui: { highlighted: boolean; tab: RuleType };\n    results: EnhancedResults | undefined;\n    error: unknown;\n    status: Status;\n  }>(ADDON_ID, {\n    ui: {\n      highlighted: false,\n      tab: RuleType.VIOLATION,\n    },\n    results: undefined,\n    error: undefined,\n    status: getInitialStatus(manual),\n  });\n\n  const { ui, results, error, status } = state;\n\n  const { storyId } = useStorybookState();\n  const currentStoryA11yStatusValue = experimental_useStatusStore(\n    (allStatuses) => allStatuses[storyId]?.[STATUS_TYPE_ID_A11Y]?.value\n  );\n\n  useEffect(() => {\n    const unsubscribe = experimental_getStatusStore('storybook/component-test').onAllStatusChange(\n      (statuses, previousStatuses) => {\n        const current = statuses[storyId]?.[STATUS_TYPE_ID_COMPONENT_TEST];\n        const previous = previousStatuses[storyId]?.[STATUS_TYPE_ID_COMPONENT_TEST];\n        if (current?.value === 'status-value:error' && previous?.value !== 'status-value:error') {\n          setState((prev) => ({ ...prev, status: 'component-test-error' }));\n        }\n      }\n    );\n    return unsubscribe;\n  }, [setState, storyId]);\n\n  const handleToggleHighlight = useCallback(() => {\n    setState((prev) => ({\n      ...prev,\n      ui: { ...prev.ui, highlighted: !prev.ui.highlighted },\n    }));\n  }, [setState]);\n\n  const statusTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n  useEffect(() => {\n    return () => {\n      if (statusTimerRef.current !== null) {\n        clearTimeout(statusTimerRef.current);\n      }\n    };\n  }, []);\n\n  const [selectedItems, setSelectedItems] = useState<Map<string, string>>(() => {\n    const initialValue = new Map();\n    // Check if the a11ySelection param is a valid format before parsing it\n    // It should look like `violation.aria-hidden-body.1`\n    if (a11ySelection && /^[a-z]+.[a-z-]+.[0-9]+$/.test(a11ySelection)) {\n      const [type, id] = a11ySelection.split('.');\n      initialValue.set(`${type}.${id}`, a11ySelection);\n    }\n    return initialValue;\n  });\n\n  // All items are expanded if something is selected from each result for the current tab\n  const allExpanded = useMemo(() => {\n    const currentResults = results?.[ui.tab];\n    return currentResults?.every((result) => selectedItems.has(`${ui.tab}.${result.id}`)) ?? false;\n  }, [results, selectedItems, ui.tab]);\n\n  const toggleOpen = useCallback(\n    (event: React.SyntheticEvent<Element>, type: RuleType, item: EnhancedResult) => {\n      event.stopPropagation();\n      const key = `${type}.${item.id}`;\n      setSelectedItems((prev) => new Map(prev.delete(key) ? prev : prev.set(key, `${key}.1`)));\n    },\n    []\n  );\n\n  const handleCollapseAll = useCallback(() => {\n    setSelectedItems(new Map());\n  }, []);\n\n  const handleExpandAll = useCallback(() => {\n    setSelectedItems(\n      (prev) =>\n        new Map(\n          results?.[ui.tab]?.map((result) => {\n            const key = `${ui.tab}.${result.id}`;\n            return [key, prev.get(key) ?? `${key}.1`];\n          }) ?? []\n        )\n    );\n  }, [results, ui.tab]);\n\n  const handleSelectionChange = useCallback((key: string) => {\n    const [type, id] = key.split('.');\n    setSelectedItems((prev) => new Map(prev.set(`${type}.${id}`, key)));\n  }, []);\n\n  const handleError = useCallback(\n    (err: unknown) => {\n      setState((prev) => ({ ...prev, status: 'error', error: err }));\n    },\n    [setState]\n  );\n\n  const handleResult = useCallback(\n    (axeResults: EnhancedResults, id: string) => {\n      if (storyId === id) {\n        setState((prev) => ({ ...prev, status: 'ran', results: axeResults }));\n\n        if (statusTimerRef.current !== null) {\n          clearTimeout(statusTimerRef.current);\n        }\n        statusTimerRef.current = setTimeout(() => {\n          statusTimerRef.current = null;\n          setState((prev) => {\n            if (prev.status === 'ran') {\n              return { ...prev, status: 'ready' };\n            }\n            return prev;\n          });\n          setSelectedItems((prev) => {\n            if (prev.size === 1) {\n              const [key] = prev.values();\n              document.getElementById(key)?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n            }\n            return prev;\n          });\n        }, 900);\n      }\n    },\n    [storyId, setState, setSelectedItems]\n  );\n\n  const handleSelect = useCallback(\n    (itemId: string, details: ClickEventDetails) => {\n      const [type, id] = itemId.split('.');\n      const { helpUrl, nodes } = results?.[type as RuleType]?.find((r) => r.id === id) || {};\n      const openedWindow = helpUrl && window.open(helpUrl, '_blank', 'noopener,noreferrer');\n      if (nodes && !openedWindow) {\n        const index =\n          nodes.findIndex((n) => details.selectors.some((s) => s === String(n.target))) ?? -1;\n        if (index !== -1) {\n          const key = `${type}.${id}.${index + 1}`;\n          setSelectedItems(new Map([[`${type}.${id}`, key]]));\n          setTimeout(() => {\n            document.getElementById(key)?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n          }, 100);\n        }\n      }\n    },\n    [results]\n  );\n\n  const handleReport = useCallback(\n    ({ reporters }: StoryFinishedPayload) => {\n      const a11yReport = reporters.find((r) => r.type === 'a11y') as Report<A11yReport> | undefined;\n\n      if (a11yReport) {\n        if ('error' in a11yReport.result) {\n          handleError(a11yReport.result.error);\n        } else {\n          handleResult(a11yReport.result, storyId);\n        }\n      }\n    },\n    [handleError, handleResult, storyId]\n  );\n\n  const handleReset = useCallback(\n    ({ newPhase }: { newPhase: string }) => {\n      if (newPhase === 'loading') {\n        setState((prev) => ({\n          ...prev,\n          results: undefined,\n          status: manual ? 'manual' : 'initial',\n        }));\n      } else if (newPhase === 'afterEach' && !manual) {\n        setState((prev) => ({ ...prev, status: 'running' }));\n      }\n    },\n    [manual, setState]\n  );\n\n  const emit = useChannel(\n    {\n      [EVENTS.RESULT]: handleResult,\n      [EVENTS.ERROR]: handleError,\n      [EVENTS.SELECT]: handleSelect,\n      [STORY_CHANGED]: () => setSelectedItems(new Map()),\n      [STORY_RENDER_PHASE_CHANGED]: handleReset,\n      [STORY_FINISHED]: handleReport,\n      [STORY_HOT_UPDATED]: () => {\n        setState((prev) => ({ ...prev, status: 'running' }));\n        emit(EVENTS.MANUAL, storyId, parameters);\n      },\n    },\n    [handleReset, handleReport, handleSelect, handleError, handleResult, parameters, storyId]\n  );\n\n  const handleManual = useCallback(() => {\n    setState((prev) => ({ ...prev, status: 'running' }));\n    emit(EVENTS.MANUAL, storyId, parameters);\n  }, [emit, parameters, setState, storyId]);\n\n  const handleCopyLink = useCallback(async (linkPath: string) => {\n    const { createCopyToClipboardFunction } = await import('storybook/internal/components');\n    await createCopyToClipboardFunction()(`${window.location.origin}${linkPath}`);\n  }, []);\n\n  const handleJumpToElement = useCallback(\n    (target: string) => emit(SCROLL_INTO_VIEW, target),\n    [emit]\n  );\n\n  useEffect(() => {\n    setState((prev) => ({ ...prev, status: getInitialStatus(manual) }));\n  }, [getInitialStatus, manual, setState]);\n\n  const isInitial = status === 'initial';\n\n  // If a deep link is provided, prefer it once on mount and persist UI state accordingly\n  useEffect(() => {\n    if (!a11ySelection) {\n      return;\n    }\n    setState((prev) => {\n      const update = { ...prev.ui, highlighted: true };\n\n      const [type] = a11ySelection.split('.') ?? [];\n      if (type && Object.values(RuleType).includes(type as RuleType)) {\n        update.tab = type as RuleType;\n      }\n      return { ...prev, ui: update };\n    });\n\n    // We intentionally do not include setState in deps to avoid loops\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [a11ySelection]);\n\n  useEffect(() => {\n    emit(REMOVE_HIGHLIGHT, `${ADDON_ID}/selected`);\n    emit(REMOVE_HIGHLIGHT, `${ADDON_ID}/others`);\n\n    if (!ui.highlighted || isInitial) {\n      return;\n    }\n\n    const selected = Array.from(selectedItems.values()).flatMap((key) => {\n      const [type, id, number] = key.split('.');\n      if (type !== ui.tab) {\n        return [];\n      }\n      const result = results?.[type as RuleType]?.find((r) => r.id === id);\n      const target = result?.nodes[Number(number) - 1]?.target;\n      return target ? [String(target)] : [];\n    });\n    if (selected.length) {\n      emit(HIGHLIGHT, {\n        id: `${ADDON_ID}/selected`,\n        priority: 1,\n        selectors: selected,\n        styles: {\n          outline: `1px solid color-mix(in srgb, ${colorsByType[ui.tab]}, transparent 30%)`,\n          backgroundColor: 'transparent',\n        },\n        hoverStyles: {\n          outlineWidth: '2px',\n        },\n        focusStyles: {\n          backgroundColor: 'transparent',\n        },\n        menu: results?.[ui.tab as RuleType].map<HighlightMenuItem[]>((result) => {\n          const selectors = result.nodes\n            .flatMap((n) => n.target)\n            .map(String)\n            .filter((e) => selected.includes(e));\n          return [\n            {\n              id: `${ui.tab}.${result.id}:info`,\n              title: getTitleForAxeResult(result),\n              description: getFriendlySummaryForAxeResult(result),\n              selectors,\n            },\n            {\n              id: `${ui.tab}.${result.id}`,\n              iconLeft: 'info',\n              iconRight: 'shareAlt',\n              title: 'Learn how to resolve this violation',\n              clickEvent: EVENTS.SELECT,\n              selectors,\n            },\n          ];\n        }),\n      });\n    }\n\n    const others = results?.[ui.tab as RuleType]\n      .flatMap((r) => r.nodes.flatMap((n) => n.target).map(String))\n      .filter((e) => ![...unhighlightedSelectors, ...selected].includes(e));\n    if (others?.length) {\n      emit(HIGHLIGHT, {\n        id: `${ADDON_ID}/others`,\n        selectors: others,\n        styles: {\n          outline: `1px solid color-mix(in srgb, ${colorsByType[ui.tab]}, transparent 30%)`,\n          backgroundColor: `color-mix(in srgb, ${colorsByType[ui.tab]}, transparent 60%)`,\n        },\n        hoverStyles: {\n          outlineWidth: '2px',\n        },\n        focusStyles: {\n          backgroundColor: 'transparent',\n        },\n        menu: results?.[ui.tab as RuleType].map<HighlightMenuItem[]>((result) => {\n          const selectors = result.nodes\n            .flatMap((n) => n.target)\n            .map(String)\n            .filter((e) => !selected.includes(e));\n          return [\n            {\n              id: `${ui.tab}.${result.id}:info`,\n              title: getTitleForAxeResult(result),\n              description: getFriendlySummaryForAxeResult(result),\n              selectors,\n            },\n            {\n              id: `${ui.tab}.${result.id}`,\n              iconLeft: 'info',\n              iconRight: 'shareAlt',\n              title: 'Learn how to resolve this violation',\n              clickEvent: EVENTS.SELECT,\n              selectors,\n            },\n          ];\n        }),\n      });\n    }\n  }, [isInitial, emit, ui.highlighted, results, ui.tab, selectedItems]);\n\n  const discrepancy: TestDiscrepancy = useMemo(() => {\n    if (!currentStoryA11yStatusValue) {\n      return null;\n    }\n    if (currentStoryA11yStatusValue === 'status-value:success' && results?.violations.length) {\n      return 'cliPassedBrowserFailed';\n    }\n\n    if (currentStoryA11yStatusValue === 'status-value:error' && !results?.violations.length) {\n      if (status === 'ready' || status === 'ran') {\n        return 'browserPassedCliFailed';\n      }\n\n      if (status === 'manual') {\n        return 'cliFailedButModeManual';\n      }\n    }\n    return null;\n  }, [results?.violations.length, status, currentStoryA11yStatusValue]);\n\n  return (\n    <A11yContext.Provider\n      value={{\n        parameters,\n        results,\n        highlighted: ui.highlighted,\n        toggleHighlight: handleToggleHighlight,\n        tab: ui.tab,\n        setTab: useCallback(\n          (type: RuleType) => setState((prev) => ({ ...prev, ui: { ...prev.ui, tab: type } })),\n          [setState]\n        ),\n        handleCopyLink,\n        status: status,\n        setStatus: useCallback(\n          (status: Status) => setState((prev) => ({ ...prev, status })),\n          [setState]\n        ),\n        error: error,\n        handleManual,\n        discrepancy,\n        selectedItems,\n        toggleOpen,\n        allExpanded,\n        handleCollapseAll,\n        handleExpandAll,\n        handleJumpToElement,\n        handleSelectionChange,\n      }}\n      {...props}\n    />\n  );\n};\n\nexport const useA11yContext = () => useContext(A11yContext);\n"
  },
  {
    "path": "code/addons/a11y/src/components/Report/Details.tsx",
    "content": "import React, { Fragment, useCallback, useState } from 'react';\n\nimport { Button, Link, SyntaxHighlighter } from 'storybook/internal/components';\n\nimport { CheckIcon, CopyIcon, LocationIcon } from '@storybook/icons';\n\nimport * as Tabs from '@radix-ui/react-tabs';\nimport { styled } from 'storybook/theming';\n\nimport { getFriendlySummaryForAxeResult } from '../../axeRuleMappingHelper.ts';\nimport type { EnhancedNodeResult, EnhancedResult, RuleType } from '../../types.ts';\nimport { useA11yContext } from '../A11yContext.tsx';\n\nconst StyledSyntaxHighlighter = styled(SyntaxHighlighter)(\n  ({ theme }) => ({\n    fontSize: theme.typography.size.s1,\n  }),\n  ({ language }) =>\n    // We appended ' {}' to the selector in order to get proper syntax highlighting. This rule hides the last 3 spans\n    // (one character each) in the displayed output. Only siblings of .selector (the actual CSS selector characters)\n    // are targeted so that the code comment line isn't affected.\n    language === 'css' && {\n      '.selector ~ span:nth-last-of-type(-n+3)': {\n        display: 'none',\n      },\n    }\n);\n\nconst Info = styled.div({\n  display: 'flex',\n  flexDirection: 'column',\n});\n\nconst RuleId = styled.div(({ theme }) => ({\n  display: 'block',\n  color: theme.textMutedColor,\n  fontFamily: theme.typography.fonts.mono,\n  fontSize: theme.typography.size.s1,\n  marginTop: -8,\n  marginBottom: 12,\n\n  '@container (min-width: 800px)': {\n    display: 'none',\n  },\n}));\n\nconst Description = styled.p({\n  margin: 0,\n});\n\nconst Wrapper = styled.div({\n  display: 'flex',\n  flexDirection: 'column',\n  padding: '0 15px 20px 15px',\n  gap: 20,\n});\n\nconst Columns = styled.div({\n  gap: 15,\n\n  '@container (min-width: 800px)': {\n    display: 'grid',\n    gridTemplateColumns: '50% 50%',\n  },\n});\n\nconst Content = styled.div<{ side: 'left' | 'right' }>(({ theme, side }) => ({\n  display: side === 'left' ? 'flex' : 'none',\n  flexDirection: 'column',\n  gap: 15,\n  margin: side === 'left' ? '15px 0' : 0,\n  padding: side === 'left' ? '0 15px' : 0,\n  borderLeft: side === 'left' ? `1px solid ${theme.color.border}` : 'none',\n\n  '&:focus-visible': {\n    outline: 'none',\n    borderRadius: 4,\n    boxShadow: `0 0 0 1px inset ${theme.color.secondary}`,\n  },\n\n  '@container (min-width: 800px)': {\n    display: side === 'left' ? 'none' : 'flex',\n  },\n}));\n\nconst Item = styled(Button)(({ theme }) => ({\n  fontFamily: theme.typography.fonts.mono,\n  fontWeight: theme.typography.weight.regular,\n  color: theme.textMutedColor,\n  height: 40,\n  overflow: 'hidden',\n  textOverflow: 'ellipsis',\n  whiteSpace: 'nowrap',\n  display: 'block',\n  width: '100%',\n  textAlign: 'left',\n  padding: '0 12px',\n  '&[data-state=\"active\"]': {\n    color: theme.color.secondary,\n    backgroundColor: theme.background.hoverable,\n  },\n}));\n\nconst Messages = styled.div({\n  display: 'flex',\n  flexDirection: 'column',\n  gap: 10,\n});\n\nconst Actions = styled.div({\n  display: 'flex',\n  gap: 10,\n});\n\nconst CopyButton = ({ onClick }: { onClick: () => void }) => {\n  const [copied, setCopied] = useState(false);\n\n  const handleClick = useCallback(() => {\n    onClick();\n    setCopied(true);\n    const timeout = setTimeout(() => setCopied(false), 2000);\n    return () => clearTimeout(timeout);\n  }, [onClick]);\n\n  return (\n    <Button ariaLabel={false} onClick={handleClick}>\n      {copied ? <CheckIcon /> : <CopyIcon />} {copied ? 'Copied' : 'Copy link'}\n    </Button>\n  );\n};\n\ninterface DetailsProps {\n  id: string;\n  item: EnhancedResult;\n  type: RuleType;\n  selection: string | undefined;\n  handleSelectionChange: (key: string) => void;\n}\n\nexport const Details = ({ id, item, type, selection, handleSelectionChange }: DetailsProps) => (\n  <Wrapper id={id}>\n    <Info>\n      <RuleId>{item.id}</RuleId>\n      <Description>\n        {getFriendlySummaryForAxeResult(item)}{' '}\n        <Link href={item.helpUrl} target=\"_blank\" rel=\"noopener noreferrer\" withArrow>\n          Learn how to resolve this violation\n        </Link>\n      </Description>\n    </Info>\n\n    <Tabs.Root\n      defaultValue={selection}\n      orientation=\"vertical\"\n      value={selection}\n      onValueChange={handleSelectionChange}\n      asChild\n    >\n      <Columns>\n        <Tabs.List aria-label={type}>\n          {item.nodes.map((node, index) => {\n            const key = `${type}.${item.id}.${index + 1}`;\n            return (\n              <Fragment key={key}>\n                <Tabs.Trigger value={key} asChild>\n                  <Item ariaLabel={false} variant=\"ghost\" size=\"medium\" id={key}>\n                    {index + 1}. {node.html}\n                  </Item>\n                </Tabs.Trigger>\n                <Tabs.Content value={key} asChild>\n                  <Content side=\"left\">{getContent(node)}</Content>\n                </Tabs.Content>\n              </Fragment>\n            );\n          })}\n        </Tabs.List>\n\n        {item.nodes.map((node, index) => {\n          const key = `${type}.${item.id}.${index + 1}`;\n          return (\n            <Tabs.Content key={key} value={key} asChild>\n              <Content side=\"right\">{getContent(node)}</Content>\n            </Tabs.Content>\n          );\n        })}\n      </Columns>\n    </Tabs.Root>\n  </Wrapper>\n);\n\nfunction getContent(node: EnhancedNodeResult) {\n  const { handleCopyLink, handleJumpToElement } = useA11yContext();\n  const { any, all, none, html, target } = node;\n  const rules = [...any, ...all, ...none];\n  return (\n    <>\n      <Messages>\n        {rules.map((rule) => (\n          <div key={rule.id}>\n            {`${rule.message}${/(\\.|: [^.]+\\.*)$/.test(rule.message) ? '' : '.'}`}\n          </div>\n        ))}\n      </Messages>\n\n      <Actions>\n        <Button ariaLabel={false} onClick={() => handleJumpToElement(node.target.toString())}>\n          <LocationIcon /> Jump to element\n        </Button>\n        <CopyButton onClick={() => handleCopyLink(node.linkPath)} />\n      </Actions>\n\n      {/* Technically this is HTML but we use JSX to avoid using an HTML comment */}\n      <StyledSyntaxHighlighter\n        language=\"jsx\"\n        wrapLongLines\n      >{`/* element */\\n${html}`}</StyledSyntaxHighlighter>\n\n      {/* See note about the appended {} in the StyledSyntaxHighlighter component */}\n      <StyledSyntaxHighlighter\n        language=\"css\"\n        wrapLongLines\n      >{`/* selector */\\n${target} {}`}</StyledSyntaxHighlighter>\n    </>\n  );\n}\n"
  },
  {
    "path": "code/addons/a11y/src/components/Report/Report.stories.tsx",
    "content": "import React from 'react';\n\nimport { ManagerContext } from 'storybook/manager-api';\nimport { fn } from 'storybook/test';\nimport { styled } from 'storybook/theming';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { results } from '../../results.mock.ts';\nimport { RuleType } from '../../types.ts';\nimport { Report } from './Report.tsx';\n\nconst StyledWrapper = styled.div(({ theme }) => ({\n  backgroundColor: theme.background.content,\n  fontSize: theme.typography.size.s2 - 1,\n  color: theme.color.defaultText,\n  display: 'block',\n  height: '100%',\n  position: 'absolute',\n  left: 0,\n  right: 0,\n  bottom: 0,\n  overflow: 'auto',\n}));\n\nconst managerContext: any = {\n  state: {},\n  api: {\n    getDocsUrl: fn().mockName('api::getDocsUrl'),\n  },\n};\n\nconst meta = preview.meta({\n  title: 'Report',\n  component: Report,\n  decorators: [\n    (Story) => (\n      <ManagerContext.Provider value={managerContext}>\n        <StyledWrapper id=\"panel-tab-content\">\n          <Story />\n        </StyledWrapper>\n      </ManagerContext.Provider>\n    ),\n  ],\n  parameters: {\n    layout: 'fullscreen',\n  },\n  args: {\n    items: [],\n    empty: 'No issues found',\n    type: RuleType.VIOLATION,\n    handleSelectionChange: fn().mockName('handleSelectionChange'),\n    selectedItems: new Map(),\n    toggleOpen: fn().mockName('toggleOpen'),\n  },\n});\n\nexport const Empty = meta.story({});\n\nexport const Violations = meta.story({\n  args: {\n    items: results.violations,\n    type: RuleType.VIOLATION,\n    selectedItems: new Map([\n      [\n        `${RuleType.VIOLATION}.${results.violations[0].id}`,\n        `${RuleType.VIOLATION}.${results.violations[0].id}.3`,\n      ],\n    ]),\n  },\n});\n\nexport const Incomplete = meta.story({\n  args: {\n    items: results.incomplete,\n    type: RuleType.INCOMPLETION,\n    selectedItems: new Map([\n      [\n        `${RuleType.INCOMPLETION}.${results.incomplete[1].id}`,\n        `${RuleType.INCOMPLETION}.${results.incomplete[1].id}.2`,\n      ],\n    ]),\n  },\n});\n\nexport const Passes = meta.story({\n  args: {\n    items: results.passes,\n    type: RuleType.PASS,\n    selectedItems: new Map([\n      [`${RuleType.PASS}.${results.passes[2].id}`, `${RuleType.PASS}.${results.passes[2].id}.1`],\n    ]),\n  },\n});\n"
  },
  {
    "path": "code/addons/a11y/src/components/Report/Report.tsx",
    "content": "import type { ComponentProps, FC } from 'react';\nimport React from 'react';\n\nimport { Badge, Button, EmptyTabContent } from 'storybook/internal/components';\n\nimport { ChevronSmallDownIcon } from '@storybook/icons';\n\nimport type { ImpactValue } from 'axe-core';\nimport { styled } from 'storybook/theming';\n\nimport { getTitleForAxeResult } from '../../axeRuleMappingHelper.ts';\nimport { type EnhancedResult, RuleType } from '../../types.ts';\nimport { Details } from './Details.tsx';\n\nconst impactStatus: Record<NonNullable<ImpactValue>, ComponentProps<typeof Badge>['status']> = {\n  minor: 'neutral',\n  moderate: 'warning',\n  serious: 'negative',\n  critical: 'critical',\n};\n\nconst impactLabels: Record<NonNullable<ImpactValue>, string> = {\n  minor: 'Minor',\n  moderate: 'Moderate',\n  serious: 'Serious',\n  critical: 'Critical',\n};\n\nconst Wrapper = styled.div(({ theme }) => ({\n  display: 'flex',\n  flexDirection: 'column',\n  width: '100%',\n  borderBottom: `1px solid ${theme.appBorderColor}`,\n  containerType: 'inline-size',\n  fontSize: theme.typography.size.s2,\n}));\n\nconst Icon = styled(ChevronSmallDownIcon)({\n  transition: 'transform 0.1s ease-in-out',\n});\n\nconst HeaderBar = styled.div(({ theme }) => ({\n  display: 'flex',\n  justifyContent: 'space-between',\n  alignItems: 'center',\n  gap: 6,\n  padding: '6px 10px 6px 15px',\n  minHeight: 40,\n  background: 'none',\n  color: 'inherit',\n  textAlign: 'left',\n  cursor: 'pointer',\n  width: '100%',\n  '&:hover': {\n    color: theme.color.secondary,\n  },\n}));\n\nconst Title = styled.div(({ theme }) => ({\n  display: 'flex',\n  alignItems: 'baseline',\n  flexGrow: 1,\n  fontSize: theme.typography.size.s2,\n  gap: 8,\n}));\n\nconst RuleId = styled.div(({ theme }) => ({\n  display: 'none',\n  color: theme.textMutedColor,\n  fontFamily: theme.typography.fonts.mono,\n  fontSize: theme.typography.size.s1,\n\n  '@container (min-width: 800px)': {\n    display: 'block',\n  },\n}));\n\nconst Count = styled.div(({ theme }) => ({\n  display: 'flex',\n  alignItems: 'center',\n  justifyContent: 'center',\n  color: theme.textMutedColor,\n  width: 28,\n  height: 28,\n}));\n\nexport interface ReportProps {\n  items: EnhancedResult[];\n  empty: string;\n  type: RuleType;\n  handleSelectionChange: (key: string) => void;\n  selectedItems: Map<EnhancedResult['id'], string>;\n  toggleOpen: (event: React.SyntheticEvent<Element>, type: RuleType, item: EnhancedResult) => void;\n}\n\nexport const Report: FC<ReportProps> = ({\n  items,\n  empty,\n  type,\n  handleSelectionChange,\n  selectedItems,\n  toggleOpen,\n}) => (\n  <>\n    {items && items.length ? (\n      items.map((item) => {\n        const id = `${type}.${item.id}`;\n        const detailsId = `details:${id}`;\n        const selection = selectedItems.get(id);\n        const title = getTitleForAxeResult(item);\n        return (\n          <Wrapper key={id}>\n            <HeaderBar onClick={(event) => toggleOpen(event, type, item)} data-active={!!selection}>\n              <Title>\n                <strong>{title}</strong>\n                <RuleId>{item.id}</RuleId>\n              </Title>\n              {item.impact && (\n                <Badge status={type === RuleType.PASS ? 'neutral' : impactStatus[item.impact]}>\n                  {impactLabels[item.impact]}\n                </Badge>\n              )}\n              <Count>{item.nodes.length}</Count>\n              <Button\n                onClick={(event) => toggleOpen(event, type, item)}\n                ariaLabel={`${selection ? 'Collapse' : 'Expand'} details for: ${title}`}\n                aria-expanded={!!selection}\n                aria-controls={detailsId}\n                variant=\"ghost\"\n                padding=\"small\"\n              >\n                <Icon style={{ transform: `rotate(${selection ? -180 : 0}deg)` }} />\n              </Button>\n            </HeaderBar>\n            {selection ? (\n              <Details\n                id={detailsId}\n                item={item}\n                type={type}\n                selection={selection}\n                handleSelectionChange={handleSelectionChange}\n              />\n            ) : (\n              <div id={detailsId} />\n            )}\n          </Wrapper>\n        );\n      })\n    ) : (\n      <EmptyTabContent title={empty} />\n    )}\n  </>\n);\n"
  },
  {
    "path": "code/addons/a11y/src/components/Tabs.tsx",
    "content": "import * as React from 'react';\n\nimport { Button, TabsView } from 'storybook/internal/components';\n\nimport { CollapseIcon, ExpandAltIcon, EyeCloseIcon, EyeIcon, SyncIcon } from '@storybook/icons';\n\nimport type { Result } from 'axe-core';\nimport { styled, useTheme } from 'storybook/theming';\n\nimport type { RuleType } from '../types.ts';\nimport { useA11yContext } from './A11yContext.tsx';\n\nconst Container = styled.div({\n  width: '100%',\n  position: 'relative',\n  height: '100%',\n  overflow: 'hidden',\n  display: 'flex',\n  flexDirection: 'column',\n});\n\nconst ActionsWrapper = styled.div({\n  display: 'flex',\n  justifyContent: 'flex-end',\n  gap: 6,\n});\n\ninterface TabsProps {\n  tabs: {\n    label: React.ReactElement;\n    panel: React.ReactElement;\n    items: Result[];\n    type: RuleType;\n  }[];\n}\n\nexport const Tabs: React.FC<TabsProps> = ({ tabs }) => {\n  const {\n    tab,\n    setTab,\n    toggleHighlight,\n    highlighted,\n    handleManual,\n    allExpanded,\n    handleCollapseAll,\n    handleExpandAll,\n  } = useA11yContext();\n\n  const theme = useTheme();\n\n  return (\n    <Container>\n      <TabsView\n        backgroundColor={theme.background.app}\n        panelProps={{ hasScrollbar: true }}\n        tabs={tabs.map((tab) => ({\n          id: tab.type,\n          title: tab.label,\n          children: tab.panel,\n        }))}\n        selected={tab}\n        // Safe to cast key to RuleType because we use RuleTypes as IDs above.\n        onSelectionChange={(key) => setTab(key as RuleType)}\n        tools={\n          <ActionsWrapper>\n            <Button\n              variant=\"ghost\"\n              padding=\"small\"\n              onClick={toggleHighlight}\n              ariaLabel={\n                highlighted\n                  ? 'Hide accessibility test result highlights'\n                  : 'Highlight elements with accessibility test results'\n              }\n            >\n              {highlighted ? <EyeCloseIcon /> : <EyeIcon />}\n            </Button>\n            <Button\n              variant=\"ghost\"\n              padding=\"small\"\n              onClick={allExpanded ? handleCollapseAll : handleExpandAll}\n              ariaLabel={allExpanded ? 'Collapse all results' : 'Expand all results'}\n              aria-expanded={allExpanded}\n            >\n              {allExpanded ? <CollapseIcon /> : <ExpandAltIcon />}\n            </Button>\n            <Button\n              variant=\"ghost\"\n              padding=\"small\"\n              onClick={handleManual}\n              ariaLabel=\"Rerun accessibility scan\"\n            >\n              <SyncIcon />\n            </Button>\n          </ActionsWrapper>\n        }\n      />\n    </Container>\n  );\n};\n"
  },
  {
    "path": "code/addons/a11y/src/components/TestDiscrepancyMessage.stories.tsx",
    "content": "import React from 'react';\n\nimport { ManagerContext } from 'storybook/manager-api';\nimport { fn } from 'storybook/test';\n\nimport preview from '../../../../.storybook/preview.tsx';\nimport { TestDiscrepancyMessage } from './TestDiscrepancyMessage.tsx';\n\nconst managerContext: any = {\n  state: {},\n  api: {\n    getDocsUrl: fn().mockName('api::getDocsUrl'),\n    getCurrentParameter: fn().mockName('api::getCurrentParameter'),\n  },\n};\n\nconst meta = preview.meta({\n  title: 'TestDiscrepancyMessage',\n  component: TestDiscrepancyMessage,\n  parameters: {\n    layout: 'fullscreen',\n  },\n  decorators: [\n    (storyFn) => (\n      <ManagerContext.Provider value={managerContext}>{storyFn()}</ManagerContext.Provider>\n    ),\n  ],\n});\n\nexport const BrowserPassedCliFailed = meta.story({\n  args: {\n    discrepancy: 'browserPassedCliFailed',\n  },\n});\n\nexport const CliPassedBrowserFailed = meta.story({\n  args: {\n    discrepancy: 'cliPassedBrowserFailed',\n  },\n});\n\nexport const CliFailedButModeManual = meta.story({\n  args: {\n    discrepancy: 'cliFailedButModeManual',\n  },\n});\n"
  },
  {
    "path": "code/addons/a11y/src/components/TestDiscrepancyMessage.tsx",
    "content": "import React, { useMemo } from 'react';\n\nimport { Link } from 'storybook/internal/components';\n\nimport { useStorybookApi } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport { DOCUMENTATION_DISCREPANCY_LINK } from '../constants.ts';\n\nconst Wrapper = styled.div(({ theme: { color, typography, background } }) => ({\n  textAlign: 'start',\n  padding: '11px 15px',\n  fontSize: `${typography.size.s2}px`,\n  fontWeight: typography.weight.regular,\n  lineHeight: '1rem',\n  background: background.app,\n  borderBottom: `1px solid ${color.border}`,\n  color: color.defaultText,\n  backgroundClip: 'padding-box',\n  position: 'relative',\n  code: {\n    fontSize: `${typography.size.s1 - 1}px`,\n    color: 'inherit',\n    margin: '0 0.2em',\n    padding: '0 0.2em',\n    background: 'rgba(255, 255, 255, 0.8)',\n    borderRadius: '2px',\n    boxShadow: '0 0 0 1px rgba(0, 0, 0, 0.1)',\n  },\n}));\n\nexport type TestDiscrepancy =\n  | 'browserPassedCliFailed'\n  | 'cliPassedBrowserFailed'\n  | 'cliFailedButModeManual'\n  | null;\n\ninterface TestDiscrepancyMessageProps {\n  discrepancy: TestDiscrepancy;\n}\nexport const TestDiscrepancyMessage = ({ discrepancy }: TestDiscrepancyMessageProps) => {\n  const api = useStorybookApi();\n  const docsUrl = api.getDocsUrl({\n    subpath: DOCUMENTATION_DISCREPANCY_LINK,\n    versioned: true,\n    renderer: true,\n  });\n\n  const message = useMemo(() => {\n    switch (discrepancy) {\n      case 'browserPassedCliFailed':\n        return 'Accessibility checks passed in this browser but failed in the CLI.';\n      case 'cliPassedBrowserFailed':\n        return 'Accessibility checks passed in the CLI but failed in this browser.';\n      case 'cliFailedButModeManual':\n        return 'Accessibility checks failed in the CLI. Run the tests manually to see the results.';\n      default:\n        return null;\n    }\n  }, [discrepancy]);\n\n  if (!message) {\n    return null;\n  }\n\n  return (\n    <Wrapper>\n      {message}{' '}\n      <Link href={docsUrl} target=\"_blank\" withArrow>\n        Learn what could cause this\n      </Link>\n    </Wrapper>\n  );\n};\n"
  },
  {
    "path": "code/addons/a11y/src/components/VisionSimulator.stories.tsx",
    "content": "import type { PlayFunction, PlayFunctionContext } from 'storybook/internal/types';\n\nimport { ManagerContext } from 'storybook/manager-api';\nimport { expect, fn, screen } from 'storybook/test';\n\nimport preview from '../../../../.storybook/preview.tsx';\nimport { VisionSimulator } from './VisionSimulator.tsx';\n\nconst managerContext: any = {\n  state: {},\n  api: {\n    getGlobals: fn(() => ({ vision: undefined })),\n    updateGlobals: fn(),\n    getStoryGlobals: fn(() => ({ vision: undefined })),\n    getUserGlobals: fn(() => ({ vision: undefined })),\n  },\n};\n\nconst meta = preview.meta({\n  title: 'Vision Simulator',\n  component: VisionSimulator,\n  decorators: [\n    (Story: any) => (\n      <ManagerContext.Provider value={managerContext}>\n        <Story />\n      </ManagerContext.Provider>\n    ),\n  ],\n});\n\nexport default meta;\n\nconst openMenu: PlayFunction = async ({ canvas, userEvent }) => {\n  await userEvent.click(canvas.getByRole('button', { name: 'Vision filter' }));\n};\n\nexport const Default = meta.story({\n  play: openMenu,\n});\n\nexport const WithFilter = meta.story({\n  play: openMenu,\n  globals: {\n    vision: 'achromatopsia',\n  },\n});\n\nexport const Selection = meta.story({\n  play: async (context) => {\n    await openMenu(context);\n    await context.userEvent.click(await screen.findByText('Blurred vision'));\n    await expect(managerContext.api.updateGlobals).toHaveBeenCalledWith({ vision: 'blurred' });\n    await expect(\n      context.canvas.getByRole('button', { name: 'Vision filter Blurred vision' })\n    ).toBeVisible();\n  },\n});\n"
  },
  {
    "path": "code/addons/a11y/src/components/VisionSimulator.tsx",
    "content": "import React from 'react';\n\nimport { Select } from 'storybook/internal/components';\n\nimport { AccessibilityIcon } from '@storybook/icons';\n\nimport { useGlobals } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport { VISION_GLOBAL_KEY } from '../constants.ts';\nimport { filterDefs, filters } from '../visionSimulatorFilters.ts';\n\nconst Hidden = styled.div({\n  '&, & svg': {\n    position: 'absolute',\n    width: 0,\n    height: 0,\n  },\n});\n\nconst ColorIcon = styled.span<{ $filter: string }>(\n  {\n    background: 'linear-gradient(to right, #F44336, #FF9800, #FFEB3B, #8BC34A, #2196F3, #9C27B0)',\n    borderRadius: 14,\n    display: 'block',\n    flexShrink: 0,\n    height: 14,\n    width: 14,\n  },\n  ({ $filter }) => ({\n    filter: filters[$filter as keyof typeof filters].filter || 'none',\n  }),\n  ({ theme }) => ({\n    boxShadow: `${theme.appBorderColor} 0 0 0 1px inset`,\n  })\n);\n\nexport const VisionSimulator = () => {\n  const [globals, updateGlobals, storyGlobals] = useGlobals();\n  const value = globals[VISION_GLOBAL_KEY];\n  const isLocked = storyGlobals[VISION_GLOBAL_KEY] !== undefined;\n\n  const options = Object.entries(filters).map(([key, { label, percentage }]) => ({\n    title: label,\n    description: percentage ? `${percentage}% of users` : undefined,\n    icon: <ColorIcon $filter={key} />,\n    value: key,\n  }));\n\n  return (\n    <>\n      <Select\n        resetLabel=\"Reset color filter\"\n        onReset={() => updateGlobals({ [VISION_GLOBAL_KEY]: undefined })}\n        icon={<AccessibilityIcon />}\n        disabled={isLocked}\n        ariaLabel={isLocked ? 'Vision filter set by story globals' : 'Vision filter'}\n        ariaDescription=\"Select a vision filter among predefined options, or reset to remove the filter.\"\n        tooltip={isLocked ? 'Vision filter set by story globals' : 'Change vision filter'}\n        defaultOptions={value}\n        options={options}\n        onSelect={(selected) => updateGlobals({ [VISION_GLOBAL_KEY]: selected })}\n      />\n      <Hidden dangerouslySetInnerHTML={{ __html: filterDefs }} />\n    </>\n  );\n};\n"
  },
  {
    "path": "code/addons/a11y/src/constants.ts",
    "content": "export const ADDON_ID = 'storybook/a11y';\nexport const PANEL_ID = `${ADDON_ID}/panel`;\nexport const PARAM_KEY = `a11y`;\nexport const VISION_GLOBAL_KEY = `vision`;\nexport const UI_STATE_ID = `${ADDON_ID}/ui`;\nconst RESULT = `${ADDON_ID}/result`;\nconst REQUEST = `${ADDON_ID}/request`;\nconst RUNNING = `${ADDON_ID}/running`;\nconst ERROR = `${ADDON_ID}/error`;\nconst MANUAL = `${ADDON_ID}/manual`;\nconst SELECT = `${ADDON_ID}/select`;\n\nexport const DOCUMENTATION_LINK = 'writing-tests/accessibility-testing';\nexport const DOCUMENTATION_DISCREPANCY_LINK = `${DOCUMENTATION_LINK}#why-are-my-tests-failing-in-different-environments`;\n\nexport const TEST_PROVIDER_ID = 'storybook/addon-a11y/test-provider';\n\nexport const EVENTS = { RESULT, REQUEST, RUNNING, ERROR, MANUAL, SELECT };\n\nexport const STATUS_TYPE_ID_COMPONENT_TEST = 'storybook/component-test';\nexport const STATUS_TYPE_ID_A11Y = 'storybook/a11y';\n"
  },
  {
    "path": "code/addons/a11y/src/index.ts",
    "content": "import { definePreviewAddon } from 'storybook/internal/csf';\n\nimport * as addonAnnotations from './preview.tsx';\nimport type { A11yTypes } from './types.ts';\n\nexport { PARAM_KEY } from './constants.ts';\nexport * from './params.ts';\nexport type { A11yGlobals, A11yTypes, A11yReport } from './types.ts';\n\nexport default () => definePreviewAddon<A11yTypes>(addonAnnotations);\n"
  },
  {
    "path": "code/addons/a11y/src/manager.test.tsx",
    "content": "// @vitest-environment happy-dom\nimport { describe, expect, it, vi } from 'vitest';\n\nimport type { Addon_BaseType } from 'storybook/internal/types';\n\nimport * as api from 'storybook/manager-api';\n\nimport { PANEL_ID } from './constants.ts';\nimport './manager.tsx';\n\nvi.mock('storybook/manager-api');\nconst mockedApi = vi.mocked<api.API>(api as any);\nmockedApi.useStorybookApi = vi.fn(() => ({ getSelectedPanel: vi.fn() }));\nmockedApi.useAddonState = vi.fn();\nconst mockedAddons = vi.mocked(api.addons);\nconst registrationImpl = mockedAddons.register.mock.calls[0][1];\n\nconst isPanel = (input: Parameters<typeof mockedAddons.add>[1]): input is Addon_BaseType =>\n  input.type === api.types.PANEL;\ndescribe('A11yManager', () => {\n  it('should register the panels', () => {\n    // when\n    registrationImpl(mockedApi);\n\n    // then\n    expect(mockedAddons.add.mock.calls).toHaveLength(2);\n    expect(mockedAddons.add).toHaveBeenCalledWith(PANEL_ID, expect.anything());\n\n    const panel = mockedAddons.add.mock.calls\n      .map(([_, def]) => def)\n      .find(({ type }) => type === api.types.PANEL);\n    const tool = mockedAddons.add.mock.calls\n      .map(([_, def]) => def)\n      .find(({ type }) => type === api.types.TOOL);\n    expect(panel).toBeDefined();\n    expect(tool).toBeDefined();\n  });\n\n  it('should compute title with no issues', () => {\n    // given\n    mockedApi.useAddonState.mockImplementation(() => [{ results: undefined }]);\n    registrationImpl(api as unknown as api.API);\n    const title = mockedAddons.add.mock.calls.map(([_, def]) => def).find(isPanel)\n      ?.title as () => void;\n\n    // when / then\n    expect(title()).toMatchInlineSnapshot(`\n      <div\n        style={\n          {\n            \"alignItems\": \"center\",\n            \"display\": \"flex\",\n            \"gap\": 6,\n          }\n        }\n      >\n        <span>\n          Accessibility\n        </span>\n      </div>\n    `);\n  });\n\n  it('should compute title with issues', () => {\n    // given\n    mockedApi.useAddonState.mockImplementation(() => [\n      {\n        results: {\n          violations: [{}],\n          incomplete: [{}, {}],\n        },\n      },\n    ]);\n    registrationImpl(mockedApi);\n    const title = mockedAddons.add.mock.calls.map(([_, def]) => def).find(isPanel)\n      ?.title as () => void;\n\n    // when / then\n    expect(title()).toMatchInlineSnapshot(`\n      <div\n        style={\n          {\n            \"alignItems\": \"center\",\n            \"display\": \"flex\",\n            \"gap\": 6,\n          }\n        }\n      >\n        <span>\n          Accessibility\n        </span>\n        <Badge\n          compact={true}\n          status=\"neutral\"\n        >\n          3\n        </Badge>\n      </div>\n    `);\n  });\n});\n"
  },
  {
    "path": "code/addons/a11y/src/manager.tsx",
    "content": "import React from 'react';\n\nimport { Badge } from 'storybook/internal/components';\n\nimport { addons, types, useAddonState, useStorybookApi } from 'storybook/manager-api';\n\nimport { A11YPanel } from './components/A11YPanel.tsx';\nimport { A11yContextProvider } from './components/A11yContext.tsx';\nimport { VisionSimulator } from './components/VisionSimulator.tsx';\nimport { ADDON_ID, PANEL_ID, PARAM_KEY } from './constants.ts';\nimport type { EnhancedResults, Status } from './types.ts';\nimport { RuleType } from './types.ts';\n\nconst Title = () => {\n  const api = useStorybookApi();\n  const selectedPanel = api.getSelectedPanel();\n  const [{ results }] = useAddonState<{\n    ui: { highlighted: boolean; tab: RuleType };\n    results: EnhancedResults | undefined;\n    error: unknown;\n    status: Status;\n  }>(ADDON_ID, {\n    ui: {\n      highlighted: false,\n      tab: RuleType.VIOLATION,\n    },\n    results: undefined,\n    error: undefined,\n    status: 'initial',\n  });\n  const violationsNb = results?.violations?.length ?? 0;\n  const incompleteNb = results?.incomplete?.length ?? 0;\n  const count = violationsNb + incompleteNb;\n\n  const suffix =\n    count === 0 ? null : (\n      <Badge compact status={selectedPanel === PANEL_ID ? 'active' : 'neutral'}>\n        {count}\n      </Badge>\n    );\n\n  return (\n    <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>\n      <span>Accessibility</span>\n      {suffix}\n    </div>\n  );\n};\n\naddons.register(ADDON_ID, (api) => {\n  addons.add(PANEL_ID, {\n    title: '',\n    type: types.TOOL,\n    match: ({ viewMode, tabId }) => viewMode === 'story' && !tabId,\n    render: () => <VisionSimulator />,\n  });\n\n  addons.add(PANEL_ID, {\n    title: Title,\n    type: types.PANEL,\n    render: ({ active = true }) => (\n      <A11yContextProvider>{active ? <A11YPanel /> : null}</A11yContextProvider>\n    ),\n    paramKey: PARAM_KEY,\n  });\n});\n"
  },
  {
    "path": "code/addons/a11y/src/params.ts",
    "content": "import type { RunOptions, Selector, SelectorList, Spec } from 'axe-core';\n\nexport type SelectorWithoutNode = Omit<Selector, 'Node'> | Omit<SelectorList, 'NodeList'>;\n\n// copy of ContextObject from axe-core\nexport type ContextObjectWithoutNode =\n  | {\n      include: SelectorWithoutNode;\n      exclude?: SelectorWithoutNode;\n    }\n  | {\n      exclude: SelectorWithoutNode;\n      include?: SelectorWithoutNode;\n    };\n// copy of ContextSpec from axe-core\nexport type ContextSpecWithoutNode = SelectorWithoutNode | ContextObjectWithoutNode;\n\ntype A11yTest = 'off' | 'todo' | 'error';\n\nexport interface A11yParameters {\n  /**\n   * Context parameter for axe-core's run function, except without support for passing Nodes and\n   * NodeLists directly.\n   *\n   * @see https://github.com/dequelabs/axe-core/blob/develop/doc/context.md\n   */\n  context?: ContextSpecWithoutNode;\n  /**\n   * Options for running axe-core.\n   *\n   * @see https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n   */\n  options?: RunOptions;\n  /**\n   * Configuration object for axe-core.\n   *\n   * @see https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n   */\n  config?: Spec;\n  /** Whether to disable accessibility tests. */\n  disable?: boolean;\n  /** Defines how accessibility violations should be handled: 'off', 'todo', or 'error'. */\n  test?: A11yTest;\n}\n"
  },
  {
    "path": "code/addons/a11y/src/postinstall.ts",
    "content": "import { JsPackageManagerFactory, versions } from 'storybook/internal/common';\n\nimport type { PostinstallOptions } from '../../../lib/cli-storybook/src/add.ts';\n\nexport default async function postinstall(options: PostinstallOptions) {\n  const args = [\n    options.skipInstall ? `storybook@${versions.storybook}` : `storybook`,\n    'automigrate',\n    'addon-a11y-addon-test',\n  ];\n\n  args.push('--loglevel', 'silent');\n  args.push('--skip-doctor');\n\n  if (options.yes) {\n    args.push('--yes');\n  }\n\n  if (options.packageManager) {\n    args.push('--package-manager', options.packageManager);\n  }\n\n  if (options.configDir) {\n    args.push('--config-dir', options.configDir);\n  }\n\n  const jsPackageManager = JsPackageManagerFactory.getPackageManager({\n    force: options.packageManager,\n    configDir: options.configDir,\n  });\n\n  await jsPackageManager.runPackageCommand({ args, useRemotePkg: !!options.skipInstall });\n}\n"
  },
  {
    "path": "code/addons/a11y/src/preset.ts",
    "content": "// enables other addons/presets to detect if a11y is enabled and adjust their behavior accordingly\n// using await presets.apply('isAddonA11yEnabled', false);\nexport const isAddonA11yEnabled = true;\n"
  },
  {
    "path": "code/addons/a11y/src/preview.test.tsx",
    "content": "// @vitest-environment happy-dom\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { StoryContext } from 'storybook/internal/csf';\n\nimport { run } from './a11yRunner.ts';\nimport { afterEach } from './preview.tsx';\nimport { getIsVitestRunning, getIsVitestStandaloneRun } from './utils.ts';\n\nconst mocks = vi.hoisted(() => {\n  return {\n    getIsVitestRunning: vi.fn(),\n    getIsVitestStandaloneRun: vi.fn(),\n  };\n});\n\nvi.mock(import('./a11yRunner.ts'));\nvi.mock(import('./utils.ts'), async (importOriginal) => {\n  const mod = await importOriginal(); // type is inferred\n  return {\n    ...mod,\n    getIsVitestRunning: mocks.getIsVitestRunning,\n    getIsVitestStandaloneRun: mocks.getIsVitestStandaloneRun,\n  };\n});\n\nconst mockedRun = vi.mocked(run);\n\nconst violations = [\n  {\n    id: 'color-contrast',\n    impact: 'serious',\n    tags: '_duplicate_[\"args\",\"0\",\"reporters\",\"0\",\"result\",\"passes\",\"12\",\"tags\"]',\n    description:\n      'Ensures the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds',\n    help: 'Elements must meet minimum color contrast ratio thresholds',\n    helpUrl: 'https://dequeuniversity.com/rules/axe/4.8/color-contrast?application=axeAPI',\n    nodes: [\n      {\n        any: [\n          {\n            id: 'color-contrast',\n            data: {\n              fgColor: '#029cfd',\n              bgColor: '#f6f9fc',\n              contrastRatio: 2.76,\n              fontSize: '10.5pt (14px)',\n              fontWeight: 'normal',\n              messageKey: null,\n              expectedContrastRatio: '4.5:1',\n              shadowColor: '_undefined_',\n            },\n            relatedNodes: [\n              {\n                html: '<div class=\"css-1av19vu\">',\n                target: ['.css-1av19vu'],\n              },\n            ],\n            impact: 'serious',\n            message:\n              'Element has insufficient color contrast of 2.76 (foreground color: #029cfd, background color: #f6f9fc, font size: 10.5pt (14px), font weight: normal). Expected contrast ratio of 4.5:1',\n            '_constructor-name_': 'CheckResult',\n          },\n        ],\n        all: [],\n        none: [],\n        impact: 'serious',\n        html: '<span class=\"css-1mjgzsp\">',\n        target: ['.css-1mjgzsp'],\n        failureSummary:\n          'Fix any of the following:\\n  Element has insufficient color contrast of 2.76 (foreground color: #029cfd, background color: #f6f9fc, font size: 10.5pt (14px), font weight: normal). Expected contrast ratio of 4.5:1',\n      },\n    ],\n  },\n];\n\ndescribe('afterEach', () => {\n  beforeEach(() => {\n    vi.mocked(getIsVitestRunning).mockReturnValue(false);\n    vi.mocked(getIsVitestStandaloneRun).mockReturnValue(true);\n  });\n\n  const createContext = (overrides: Partial<StoryContext> = {}): StoryContext =>\n    ({\n      viewMode: 'story',\n      reporting: {\n        reports: [],\n        addReport: vi.fn(),\n      },\n      parameters: {\n        a11y: {\n          test: 'error',\n        },\n      },\n      globals: {\n        a11y: {},\n      },\n      ...overrides,\n    }) as any;\n\n  it('should run accessibility checks and report results', async () => {\n    const context = createContext();\n    const result = {\n      violations,\n    };\n\n    mockedRun.mockResolvedValue(result as any);\n\n    await expect(() => afterEach(context)).rejects.toThrow();\n\n    expect(mockedRun).toHaveBeenCalledWith(context.parameters.a11y, context.id);\n\n    expect(context.reporting.addReport).toHaveBeenCalledWith({\n      type: 'a11y',\n      version: 1,\n      result,\n      status: 'failed',\n    });\n  });\n\n  it('should run accessibility checks and report results without throwing', async () => {\n    const context = createContext();\n    const result = {\n      violations,\n    };\n\n    mockedRun.mockResolvedValue(result as any);\n    mocks.getIsVitestStandaloneRun.mockReturnValue(false);\n\n    await afterEach(context);\n\n    expect(mockedRun).toHaveBeenCalledWith(context.parameters.a11y, context.id);\n\n    expect(context.reporting.addReport).toHaveBeenCalledWith({\n      type: 'a11y',\n      version: 1,\n      result,\n      status: 'failed',\n    });\n  });\n\n  it('should run accessibility checks and should report them as warnings', async () => {\n    const context = createContext({\n      parameters: {\n        a11y: {\n          test: 'todo',\n        },\n      },\n    });\n    const result = {\n      violations,\n    };\n\n    mockedRun.mockResolvedValue(result as any);\n    mocks.getIsVitestStandaloneRun.mockReturnValue(false);\n\n    await afterEach(context);\n\n    expect(mockedRun).toHaveBeenCalledWith(context.parameters.a11y, context.id);\n\n    expect(context.reporting.addReport).toHaveBeenCalledWith({\n      type: 'a11y',\n      version: 1,\n      result,\n      status: 'warning',\n    });\n  });\n\n  it('should report passed status when there are no violations', async () => {\n    const context = createContext();\n    const result = {\n      violations: [],\n    };\n    mockedRun.mockResolvedValue(result as any);\n\n    await afterEach(context);\n\n    expect(mockedRun).toHaveBeenCalledWith(context.parameters.a11y, context.id);\n    expect(context.reporting.addReport).toHaveBeenCalledWith({\n      type: 'a11y',\n      version: 1,\n      result,\n      status: 'passed',\n    });\n  });\n\n  it('should not run accessibility checks when disable is true', async () => {\n    const context = createContext({\n      parameters: {\n        a11y: {\n          disable: true,\n        },\n      },\n    });\n\n    await afterEach(context);\n\n    expect(mockedRun).not.toHaveBeenCalled();\n    expect(context.reporting.addReport).not.toHaveBeenCalled();\n  });\n\n  it('should not run accessibility checks when globals manual is true', async () => {\n    const context = createContext({\n      globals: {\n        a11y: {\n          manual: true,\n        },\n      },\n    });\n\n    await afterEach(context);\n\n    expect(mockedRun).not.toHaveBeenCalled();\n    expect(context.reporting.addReport).not.toHaveBeenCalled();\n  });\n\n  it('should not run accessibility checks when parameters.a11y.test is \"off\"', async () => {\n    const context = createContext({\n      parameters: {\n        a11y: {\n          test: 'off',\n        },\n      },\n    });\n\n    await afterEach(context);\n\n    expect(mockedRun).not.toHaveBeenCalled();\n    expect(context.reporting.addReport).not.toHaveBeenCalled();\n  });\n\n  it('should report error when run throws an error', async () => {\n    const context = createContext();\n    const error = new Error('Test error');\n    mockedRun.mockRejectedValue(error);\n\n    await expect(() => afterEach(context)).rejects.toThrow();\n\n    expect(mockedRun).toHaveBeenCalledWith(context.parameters.a11y, context.id);\n    expect(context.reporting.addReport).toHaveBeenCalledWith({\n      type: 'a11y',\n      version: 1,\n      result: {\n        error,\n      },\n      status: 'failed',\n    });\n  });\n\n  it('should not run in docs mode', async () => {\n    const context = createContext({\n      viewMode: 'docs',\n    });\n\n    await afterEach(context);\n\n    expect(mockedRun).not.toHaveBeenCalled();\n    expect(context.reporting.addReport).not.toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "code/addons/a11y/src/preview.tsx",
    "content": "import type { AfterEach } from 'storybook/internal/types';\n\nimport { expect } from 'storybook/test';\n\nimport { run } from './a11yRunner.ts';\nimport type { A11yParameters } from './params.ts';\nimport { getIsVitestStandaloneRun } from './utils.ts';\nimport { withVisionSimulator } from './withVisionSimulator.ts';\n\nlet vitestMatchersExtended = false;\n\nexport const decorators = [withVisionSimulator];\n\nexport const afterEach: AfterEach<any> = async ({\n  id: storyId,\n  reporting,\n  parameters,\n  globals,\n  viewMode,\n}) => {\n  const a11yParameter: A11yParameters | undefined = parameters.a11y;\n  const a11yGlobals = globals.a11y;\n  const isGhostStories = !!globals.ghostStories;\n\n  const shouldRunEnvironmentIndependent =\n    !isGhostStories &&\n    a11yParameter?.disable !== true &&\n    a11yParameter?.test !== 'off' &&\n    a11yGlobals?.manual !== true;\n\n  const getMode = (): (typeof reporting)['reports'][0]['status'] => {\n    switch (a11yParameter?.test) {\n      case 'todo':\n        return 'warning';\n      case 'error':\n      default:\n        return 'failed';\n    }\n  };\n\n  if (shouldRunEnvironmentIndependent && viewMode === 'story') {\n    try {\n      const result = await run(a11yParameter, storyId);\n\n      if (result) {\n        const hasViolations = (result?.violations.length ?? 0) > 0;\n\n        reporting.addReport({\n          type: 'a11y',\n          version: 1,\n          result,\n          status: hasViolations ? getMode() : 'passed',\n        });\n\n        /**\n         * When Vitest is running outside of Storybook, we need to throw an error to fail the test\n         * run when there are accessibility issues.\n         *\n         * @todo In the future, we want to always throw an error when there are accessibility\n         *   issues. This is a temporary solution. Later, portable stories and Storybook should\n         *   implement proper try catch handling.\n         */\n        if (getIsVitestStandaloneRun()) {\n          if (hasViolations && getMode() === 'failed') {\n            if (!vitestMatchersExtended) {\n              // @ts-expect-error (unknown why vitest-axe is not typed correctly)\n              const { toHaveNoViolations } = await import('vitest-axe/matchers');\n              expect.extend({ toHaveNoViolations });\n              vitestMatchersExtended = true;\n            }\n\n            // @ts-expect-error - todo - fix type extension of expect from storybook/test\n            expect(result).toHaveNoViolations();\n          }\n        }\n      }\n      /**\n       * @todo Later we don't want to catch errors here. Instead, we want to throw them and let\n       *   Storybook/portable stories handle them on a higher level.\n       */\n    } catch (e) {\n      reporting.addReport({\n        type: 'a11y',\n        version: 1,\n        result: {\n          error: e,\n        },\n        status: 'failed',\n      });\n\n      if (getIsVitestStandaloneRun()) {\n        throw e;\n      }\n    }\n  }\n};\n\nexport const initialGlobals = {\n  a11y: {\n    manual: false,\n  },\n  vision: undefined,\n};\n\nexport const parameters = {\n  a11y: {\n    test: 'todo',\n  } as A11yParameters,\n};\n"
  },
  {
    "path": "code/addons/a11y/src/results.mock.ts",
    "content": "export const results = {\n  testEngine: {\n    name: 'axe-core',\n    version: '4.10.2',\n  },\n  testRunner: {\n    name: 'axe',\n  },\n  testEnvironment: {\n    userAgent:\n      'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36',\n    windowWidth: 833,\n    windowHeight: 1315,\n    orientationAngle: 0,\n    orientationType: 'landscape-primary',\n  },\n  timestamp: '2025-03-17T15:21:16.569Z',\n  url: 'http://localhost:6006/iframe.html?viewMode=story&id=manager-sidebar-explorer--with-refs&args=&globals=',\n  toolOptions: {\n    reporter: 'v1',\n  },\n  passes: [\n    {\n      id: 'aria-allowed-attr',\n      impact: 'critical',\n      tags: ['cat.aria', 'wcag2a', 'wcag412', 'EN-301-549', 'EN-9.4.1.2'],\n      description: \"Ensure an element's role supports its ARIA attributes\",\n      help: 'Elements must only use supported ARIA attributes',\n      helpUrl: 'https://dequeuniversity.com/rules/axe/4.10/aria-allowed-attr?application=axeAPI',\n      nodes: [\n        {\n          any: [],\n          all: [\n            {\n              id: 'aria-allowed-attr',\n              data: null,\n              relatedNodes: [],\n              impact: 'critical',\n              message: 'ARIA attributes are used correctly for the defined role',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          none: [\n            {\n              id: 'aria-unsupported-attr',\n              data: null,\n              relatedNodes: [],\n              impact: 'critical',\n              message: 'ARIA attribute is supported',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          impact: null,\n          html: '<button tabindex=\"-1\" id=\"group-1\" aria-controls=\"group-1--child-b1\" aria-expanded=\"false\" class=\"css-154pbrb\">',\n          target: [\n            '.css-ohbggj > .css-ld0a14[data-item-id=\"group-1\"][data-nodetype=\"group\"] > .css-154pbrb[aria-controls=\"group-1--child-b1\"]',\n          ],\n        },\n        {\n          any: [],\n          all: [\n            {\n              id: 'aria-allowed-attr',\n              data: null,\n              relatedNodes: [],\n              impact: 'critical',\n              message: 'ARIA attributes are used correctly for the defined role',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          none: [\n            {\n              id: 'aria-unsupported-attr',\n              data: null,\n              relatedNodes: [],\n              impact: 'critical',\n              message: 'ARIA attribute is supported',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          impact: null,\n          html: '<button type=\"button\" data-action=\"collapse-root\" aria-expanded=\"true\" class=\"css-h7e28b\">',\n          target: [\n            '.css-ohbggj > .css-1ikkmhb.sidebar-subheading[data-item-id=\"root-1\"] > .css-h7e28b[type=\"button\"][data-action=\"collapse-root\"]',\n          ],\n        },\n        {\n          any: [],\n          all: [\n            {\n              id: 'aria-allowed-attr',\n              data: null,\n              relatedNodes: [],\n              impact: 'critical',\n              message: 'ARIA attributes are used correctly for the defined role',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          none: [\n            {\n              id: 'aria-unsupported-attr',\n              data: null,\n              relatedNodes: [],\n              impact: 'critical',\n              message: 'ARIA attribute is supported',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          impact: null,\n          html: '<button class=\"sidebar-subheading-action css-18rvurk\" aria-label=\"Collapse\" data-action=\"expand-all\" data-expanded=\"false\">',\n          target: [\n            '.css-ohbggj > .css-1ikkmhb.sidebar-subheading[data-item-id=\"root-1\"] > .sidebar-subheading-action.css-18rvurk[aria-label=\"Collapse\"]',\n          ],\n        },\n        {\n          any: [],\n          all: [\n            {\n              id: 'aria-allowed-attr',\n              data: null,\n              relatedNodes: [],\n              impact: 'critical',\n              message: 'ARIA attributes are used correctly for the defined role',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          none: [\n            {\n              id: 'aria-unsupported-attr',\n              data: null,\n              relatedNodes: [],\n              impact: 'critical',\n              message: 'ARIA attribute is supported',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          impact: null,\n          html: '<button tabindex=\"-1\" id=\"root-1-child-a1\" aria-expanded=\"false\" class=\"css-1vdojxu\"><div class=\"css-99l9qv\"><svg viewBox=\"0 0 14 14\" width=\"12\" height=\"12\" type=\"component\" class=\"css-1e3avu6\"><use xlink:href=\"#icon--component\"></use></svg></div>Child A1</button>',\n          target: [\n            '.css-ohbggj > .css-ld0a14[data-item-id=\"root-1-child-a1\"][data-parent-id=\"root-1\"] > .css-1vdojxu',\n          ],\n        },\n      ],\n    },\n    {\n      id: 'aria-conditional-attr',\n      impact: null,\n      tags: ['cat.aria', 'wcag2a', 'wcag412', 'EN-301-549', 'EN-9.4.1.2'],\n      description:\n        \"Ensure ARIA attributes are used as described in the specification of the element's role\",\n      help: \"ARIA attributes must be used as specified for the element's role\",\n      helpUrl:\n        'https://dequeuniversity.com/rules/axe/4.10/aria-conditional-attr?application=axeAPI',\n      nodes: [\n        {\n          any: [],\n          all: [\n            {\n              id: 'aria-conditional-attr',\n              data: null,\n              relatedNodes: [],\n              impact: 'serious',\n              message: 'ARIA attribute is allowed',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          none: [],\n          impact: null,\n          html: '<button tabindex=\"-1\" id=\"group-1\" aria-controls=\"group-1--child-b1\" aria-expanded=\"false\" class=\"css-154pbrb\">',\n          target: [\n            '.css-ohbggj > .css-ld0a14[data-item-id=\"group-1\"][data-nodetype=\"group\"] > .css-154pbrb[aria-controls=\"group-1--child-b1\"]',\n          ],\n        },\n        {\n          any: [],\n          all: [\n            {\n              id: 'aria-conditional-attr',\n              data: null,\n              relatedNodes: [],\n              impact: 'serious',\n              message: 'ARIA attribute is allowed',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          none: [],\n          impact: null,\n          html: '<button type=\"button\" data-action=\"collapse-root\" aria-expanded=\"true\" class=\"css-h7e28b\">',\n          target: [\n            '.css-ohbggj > .css-1ikkmhb.sidebar-subheading[data-item-id=\"root-1\"] > .css-h7e28b[type=\"button\"][data-action=\"collapse-root\"]',\n          ],\n        },\n        {\n          any: [],\n          all: [\n            {\n              id: 'aria-conditional-attr',\n              data: null,\n              relatedNodes: [],\n              impact: 'serious',\n              message: 'ARIA attribute is allowed',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          none: [],\n          impact: null,\n          html: '<button class=\"sidebar-subheading-action css-18rvurk\" aria-label=\"Collapse\" data-action=\"expand-all\" data-expanded=\"false\">',\n          target: [\n            '.css-ohbggj > .css-1ikkmhb.sidebar-subheading[data-item-id=\"root-1\"] > .sidebar-subheading-action.css-18rvurk[aria-label=\"Collapse\"]',\n          ],\n        },\n        {\n          any: [],\n          all: [\n            {\n              id: 'aria-conditional-attr',\n              data: null,\n              relatedNodes: [],\n              impact: 'serious',\n              message: 'ARIA attribute is allowed',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          none: [],\n          impact: null,\n          html: '<button tabindex=\"-1\" id=\"root-1-child-a1\" aria-expanded=\"false\" class=\"css-1vdojxu\"><div class=\"css-99l9qv\"><svg viewBox=\"0 0 14 14\" width=\"12\" height=\"12\" type=\"component\" class=\"css-1e3avu6\"><use xlink:href=\"#icon--component\"></use></svg></div>Child A1</button>',\n          target: [\n            '.css-ohbggj > .css-ld0a14[data-item-id=\"root-1-child-a1\"][data-parent-id=\"root-1\"] > .css-1vdojxu',\n          ],\n        },\n      ],\n    },\n    {\n      id: 'aria-hidden-body',\n      impact: null,\n      tags: ['cat.aria', 'wcag2a', 'wcag131', 'wcag412', 'EN-301-549', 'EN-9.1.3.1', 'EN-9.4.1.2'],\n      description: 'Ensure aria-hidden=\"true\" is not present on the document body.',\n      help: 'aria-hidden=\"true\" must not be present on the document body',\n      helpUrl: 'https://dequeuniversity.com/rules/axe/4.10/aria-hidden-body?application=axeAPI',\n      nodes: [\n        {\n          any: [\n            {\n              id: 'aria-hidden-body',\n              data: null,\n              relatedNodes: [],\n              impact: 'critical',\n              message: 'No aria-hidden attribute is present on document body',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          all: [],\n          none: [],\n          impact: null,\n          html: '<body class=\"sb-main-fullscreen sb-show-main\" style=\"background: rgb(255, 255, 255); color: rgb(46, 52, 56);\">',\n          target: ['body'],\n        },\n      ],\n    },\n    {\n      id: 'aria-hidden-focus',\n      impact: null,\n      tags: [\n        'cat.name-role-value',\n        'wcag2a',\n        'wcag412',\n        'TTv5',\n        'TT6.a',\n        'EN-301-549',\n        'EN-9.4.1.2',\n      ],\n      description: 'Ensure aria-hidden elements are not focusable nor contain focusable elements',\n      help: 'ARIA hidden element must not be focusable or contain focusable elements',\n      helpUrl: 'https://dequeuniversity.com/rules/axe/4.10/aria-hidden-focus?application=axeAPI',\n      nodes: [\n        {\n          any: [],\n          all: [\n            {\n              id: 'focusable-modal-open',\n              data: null,\n              relatedNodes: [],\n              impact: 'serious',\n              message: 'No focusable elements while a modal is open',\n              '_constructor-name_': 'CheckResult',\n            },\n            {\n              id: 'focusable-disabled',\n              data: null,\n              relatedNodes: [],\n              impact: 'serious',\n              message: 'No focusable elements contained within element',\n              '_constructor-name_': 'CheckResult',\n            },\n            {\n              id: 'focusable-not-tabbable',\n              data: null,\n              relatedNodes: [],\n              impact: 'serious',\n              message: 'No focusable elements contained within element',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          none: [],\n          impact: null,\n          html: '<table aria-hidden=\"true\" class=\"sb-argstableBlock\">',\n          target: ['table'],\n        },\n      ],\n    },\n  ],\n  incomplete: [\n    {\n      id: 'aria-prohibited-attr',\n      impact: 'serious',\n      tags: ['cat.aria', 'wcag2a', 'wcag412', 'EN-301-549', 'EN-9.4.1.2'],\n      description: \"Ensure ARIA attributes are not prohibited for an element's role\",\n      help: 'Elements must only use permitted ARIA attributes',\n      helpUrl: 'https://dequeuniversity.com/rules/axe/4.10/aria-prohibited-attr?application=axeAPI',\n      nodes: [\n        {\n          any: [],\n          all: [],\n          none: [\n            {\n              id: 'aria-prohibited-attr',\n              data: {\n                role: null,\n                nodeName: 'div',\n                messageKey: 'noRoleSingular',\n                prohibited: ['aria-label'],\n              },\n              relatedNodes: [],\n              impact: 'serious',\n              message:\n                'aria-label attribute is not well supported on a div with no valid role attribute.',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          impact: 'serious',\n          html: '<div aria-label=\"Hide Basic ref stories\" aria-expanded=\"true\" class=\"css-8kwxkl\">',\n          target: ['.css-8kwxkl[aria-label=\"Hide Basic ref stories\"]'],\n          failureSummary:\n            'Fix all of the following:\\n  aria-label attribute is not well supported on a div with no valid role attribute.',\n        },\n        {\n          any: [],\n          all: [],\n          none: [\n            {\n              id: 'aria-prohibited-attr',\n              data: {\n                role: null,\n                nodeName: 'div',\n                messageKey: 'noRoleSingular',\n                prohibited: ['aria-label'],\n              },\n              relatedNodes: [],\n              impact: 'serious',\n              message:\n                'aria-label attribute is not well supported on a div with no valid role attribute.',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          impact: 'serious',\n          html: '<div aria-label=\"Hide Not ready stories\" aria-expanded=\"true\" class=\"css-8kwxkl\">',\n          target: ['.css-8kwxkl[aria-label=\"Hide Not ready stories\"]'],\n          failureSummary:\n            'Fix all of the following:\\n  aria-label attribute is not well supported on a div with no valid role attribute.',\n        },\n        {\n          any: [],\n          all: [],\n          none: [\n            {\n              id: 'aria-prohibited-attr',\n              data: {\n                role: null,\n                nodeName: 'div',\n                messageKey: 'noRoleSingular',\n                prohibited: ['aria-label'],\n              },\n              relatedNodes: [],\n              impact: 'serious',\n              message:\n                'aria-label attribute is not well supported on a div with no valid role attribute.',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          impact: 'serious',\n          html: '<div aria-label=\"Hide Unknown ref stories\" aria-expanded=\"true\" class=\"css-8kwxkl\">',\n          target: ['.css-8kwxkl[aria-label=\"Hide Unknown ref stories\"]'],\n          failureSummary:\n            'Fix all of the following:\\n  aria-label attribute is not well supported on a div with no valid role attribute.',\n        },\n        {\n          any: [],\n          all: [],\n          none: [\n            {\n              id: 'aria-prohibited-attr',\n              data: {\n                role: null,\n                nodeName: 'div',\n                messageKey: 'noRoleSingular',\n                prohibited: ['aria-label'],\n              },\n              relatedNodes: [],\n              impact: 'serious',\n              message:\n                'aria-label attribute is not well supported on a div with no valid role attribute.',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          impact: 'serious',\n          html: '<div aria-label=\"Hide Lazy loaded ref stories\" aria-expanded=\"true\" class=\"css-8kwxkl\">',\n          target: ['.css-8kwxkl[aria-label=\"Hide Lazy loaded ref stories\"]'],\n          failureSummary:\n            'Fix all of the following:\\n  aria-label attribute is not well supported on a div with no valid role attribute.',\n        },\n      ],\n    },\n    {\n      id: 'duplicate-id-aria',\n      impact: 'critical',\n      tags: ['cat.parsing', 'wcag2a', 'wcag412', 'EN-301-549', 'EN-9.4.1.2'],\n      description: 'Ensure every id attribute value used in ARIA and in labels is unique',\n      help: 'IDs used in ARIA and labels must be unique',\n      helpUrl: 'https://dequeuniversity.com/rules/axe/4.10/duplicate-id-aria?application=axeAPI',\n      nodes: [\n        {\n          any: [\n            {\n              id: 'duplicate-id-aria',\n              data: 'root-1-child-a1',\n              relatedNodes: [\n                {\n                  html: '<button tabindex=\"-1\" id=\"root-1-child-a1\" aria-expanded=\"false\" class=\"css-1vdojxu\"><div class=\"css-99l9qv\"><svg viewBox=\"0 0 14 14\" width=\"12\" height=\"12\" type=\"component\" class=\"css-1e3avu6\"><use xlink:href=\"#icon--component\"></use></svg></div>Child A1</button>',\n                  target: [\n                    '.css-ohbggj > .css-qyeqia[data-item-id=\"root-1-child-a1\"][data-parent-id=\"root-1\"] > .css-1vdojxu',\n                  ],\n                },\n              ],\n              impact: 'critical',\n              message:\n                'Document has multiple elements referenced with ARIA with the same id attribute: root-1-child-a1',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          all: [],\n          none: [],\n          impact: 'critical',\n          html: '<button tabindex=\"-1\" id=\"root-1-child-a1\" aria-expanded=\"false\" class=\"css-1vdojxu\"><div class=\"css-99l9qv\"><svg viewBox=\"0 0 14 14\" width=\"12\" height=\"12\" type=\"component\" class=\"css-1e3avu6\"><use xlink:href=\"#icon--component\"></use></svg></div>Child A1</button>',\n          target: [\n            '.css-ohbggj > .css-ld0a14[data-item-id=\"root-1-child-a1\"][data-parent-id=\"root-1\"] > .css-1vdojxu',\n          ],\n          failureSummary:\n            'Fix any of the following:\\n  Document has multiple elements referenced with ARIA with the same id attribute: root-1-child-a1',\n        },\n        {\n          any: [\n            {\n              id: 'duplicate-id-aria',\n              data: 'root-1-child-a2--grandchild-a1-1',\n              relatedNodes: [\n                {\n                  html: '<a tabindex=\"-1\" href=\"/iframe.html?path=/story/root-1-child-a2--grandchild-a1-1\" id=\"root-1-child-a2--grandchild-a1-1\" class=\"css-xwriep\">',\n                  target: [\n                    '.css-1x6s7u8 > div > div[data-highlighted-ref-id=\"storybook_internal\"] > .css-79elbk[data-title=\"storybook_internal\"] > .css-ohbggj > div[data-selected=\"true\"][data-parent-id=\"root-1-child-a2\"][data-nodetype=\"story\"] > .css-xwriep',\n                  ],\n                },\n              ],\n              impact: 'critical',\n              message:\n                'Document has multiple elements referenced with ARIA with the same id attribute: root-1-child-a2--grandchild-a1-1',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          all: [],\n          none: [],\n          impact: 'critical',\n          html: '<a tabindex=\"-1\" href=\"/iframe.html?path=/story/root-1-child-a2--grandchild-a1-1\" id=\"root-1-child-a2--grandchild-a1-1\" class=\"css-xwriep\">',\n          target: [\n            '.css-ocnlra > div > div[data-highlighted-ref-id=\"storybook_internal\"] > .css-79elbk[data-title=\"storybook_internal\"] > .css-ohbggj > div[data-selected=\"true\"][data-parent-id=\"root-1-child-a2\"][data-nodetype=\"story\"] > .css-xwriep',\n          ],\n          failureSummary:\n            'Fix any of the following:\\n  Document has multiple elements referenced with ARIA with the same id attribute: root-1-child-a2--grandchild-a1-1',\n        },\n      ],\n    },\n  ],\n  violations: [\n    {\n      id: 'aria-allowed-attr',\n      impact: 'critical',\n      tags: ['cat.aria', 'wcag2a', 'wcag412', 'EN-301-549', 'EN-9.4.1.2'],\n      description: \"Ensure an element's role supports its ARIA attributes\",\n      help: 'Elements must only use supported ARIA attributes',\n      helpUrl: 'https://dequeuniversity.com/rules/axe/4.10/aria-allowed-attr?application=axeAPI',\n      nodes: [\n        {\n          any: [],\n          all: [\n            {\n              id: 'aria-allowed-attr',\n              data: ['aria-expanded=\"true\"'],\n              relatedNodes: [],\n              impact: 'critical',\n              message: 'ARIA attribute is not allowed: aria-expanded=\"true\"',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          none: [],\n          impact: 'critical',\n          html: '<div aria-label=\"Hide Basic ref stories\" aria-expanded=\"true\" class=\"css-8kwxkl\">',\n          target: ['.css-8kwxkl[aria-label=\"Hide Basic ref stories\"]'],\n          failureSummary:\n            'Fix all of the following:\\n  ARIA attribute is not allowed: aria-expanded=\"true\"',\n        },\n        {\n          any: [],\n          all: [\n            {\n              id: 'aria-allowed-attr',\n              data: ['aria-expanded=\"true\"'],\n              relatedNodes: [],\n              impact: 'critical',\n              message: 'ARIA attribute is not allowed: aria-expanded=\"true\"',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          none: [],\n          impact: 'critical',\n          html: '<div aria-label=\"Hide Not ready stories\" aria-expanded=\"true\" class=\"css-8kwxkl\">',\n          target: ['.css-8kwxkl[aria-label=\"Hide Not ready stories\"]'],\n          failureSummary:\n            'Fix all of the following:\\n  ARIA attribute is not allowed: aria-expanded=\"true\"',\n        },\n        {\n          any: [],\n          all: [\n            {\n              id: 'aria-allowed-attr',\n              data: ['aria-expanded=\"true\"'],\n              relatedNodes: [],\n              impact: 'critical',\n              message: 'ARIA attribute is not allowed: aria-expanded=\"true\"',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          none: [],\n          impact: 'critical',\n          html: '<div aria-label=\"Hide Unknown ref stories\" aria-expanded=\"true\" class=\"css-8kwxkl\">',\n          target: ['.css-8kwxkl[aria-label=\"Hide Unknown ref stories\"]'],\n          failureSummary:\n            'Fix all of the following:\\n  ARIA attribute is not allowed: aria-expanded=\"true\"',\n        },\n        {\n          any: [],\n          all: [\n            {\n              id: 'aria-allowed-attr',\n              data: ['aria-expanded=\"true\"'],\n              relatedNodes: [],\n              impact: 'critical',\n              message: 'ARIA attribute is not allowed: aria-expanded=\"true\"',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          none: [],\n          impact: 'critical',\n          html: '<div aria-label=\"Hide Lazy loaded ref stories\" aria-expanded=\"true\" class=\"css-8kwxkl\">',\n          target: ['.css-8kwxkl[aria-label=\"Hide Lazy loaded ref stories\"]'],\n          failureSummary:\n            'Fix all of the following:\\n  ARIA attribute is not allowed: aria-expanded=\"true\"',\n        },\n      ],\n    },\n    {\n      id: 'color-contrast',\n      impact: 'serious',\n      tags: [\n        'cat.color',\n        'wcag2aa',\n        'wcag143',\n        'TTv5',\n        'TT13.c',\n        'EN-301-549',\n        'EN-9.1.4.3',\n        'ACT',\n      ],\n      description:\n        'Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds',\n      help: 'Elements must meet minimum color contrast ratio thresholds',\n      helpUrl: 'https://dequeuniversity.com/rules/axe/4.10/color-contrast?application=axeAPI',\n      nodes: [\n        {\n          any: [\n            {\n              id: 'color-contrast',\n              data: {\n                fgColor: '#ffffff',\n                bgColor: '#029cfd',\n                contrastRatio: 2.92,\n                fontSize: '10.5pt (14px)',\n                fontWeight: 'bold',\n                messageKey: null,\n                expectedContrastRatio: '4.5:1',\n              },\n              relatedNodes: [\n                {\n                  html: '<div class=\"sidebar-item css-ld0a14\" data-selected=\"true\" data-ref-id=\"storybook_internal\" data-item-id=\"root-1-child-a2--grandchild-a1-1\" data-parent-id=\"root-1-child-a2\" data-nodetype=\"story\" data-highlightable=\"true\">',\n                  target: [\n                    '.css-ocnlra > div > div[data-highlighted-ref-id=\"storybook_internal\"] > .css-79elbk[data-title=\"storybook_internal\"] > .css-ohbggj > div[data-selected=\"true\"][data-parent-id=\"root-1-child-a2\"][data-nodetype=\"story\"]',\n                  ],\n                },\n              ],\n              impact: 'serious',\n              message:\n                'Element has insufficient color contrast of 2.92 (foreground color: #ffffff, background color: #029cfd, font size: 10.5pt (14px), font weight: bold). Expected contrast ratio of 4.5:1',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          all: [],\n          none: [],\n          impact: 'serious',\n          html: '<a tabindex=\"-1\" href=\"/iframe.html?path=/story/root-1-child-a2--grandchild-a1-1\" id=\"root-1-child-a2--grandchild-a1-1\" class=\"css-xwriep\">',\n          target: [\n            '.css-ocnlra > div > div[data-highlighted-ref-id=\"storybook_internal\"] > .css-79elbk[data-title=\"storybook_internal\"] > .css-ohbggj > div[data-selected=\"true\"][data-parent-id=\"root-1-child-a2\"][data-nodetype=\"story\"] > .css-xwriep',\n          ],\n          failureSummary:\n            'Fix any of the following:\\n  Element has insufficient color contrast of 2.92 (foreground color: #ffffff, background color: #029cfd, font size: 10.5pt (14px), font weight: bold). Expected contrast ratio of 4.5:1',\n        },\n        {\n          any: [\n            {\n              id: 'color-contrast',\n              data: {\n                fgColor: '#798186',\n                bgColor: '#1b1c1d',\n                contrastRatio: 4.3,\n                fontSize: '8.3pt (11px)',\n                fontWeight: 'bold',\n                messageKey: null,\n                expectedContrastRatio: '4.5:1',\n              },\n              relatedNodes: [\n                {\n                  html: '<div data-side=\"right\" class=\"css-1x6s7u8\">',\n                  target: ['.css-1x6s7u8'],\n                },\n              ],\n              impact: 'serious',\n              message:\n                'Element has insufficient color contrast of 4.3 (foreground color: #798186, background color: #1b1c1d, font size: 8.3pt (11px), font weight: bold). Expected contrast ratio of 4.5:1',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          all: [],\n          none: [],\n          impact: 'serious',\n          html: '<button type=\"button\" data-action=\"collapse-root\" aria-expanded=\"true\" class=\"css-h7e28b\">',\n          target: [\n            '.css-ohbggj > .css-170ite8.sidebar-subheading[data-item-id=\"root-1\"] > .css-h7e28b[type=\"button\"][data-action=\"collapse-root\"]',\n          ],\n          failureSummary:\n            'Fix any of the following:\\n  Element has insufficient color contrast of 4.3 (foreground color: #798186, background color: #1b1c1d, font size: 8.3pt (11px), font weight: bold). Expected contrast ratio of 4.5:1',\n        },\n        {\n          any: [\n            {\n              id: 'color-contrast',\n              data: {\n                fgColor: '#ffffff',\n                bgColor: '#029cfd',\n                contrastRatio: 2.92,\n                fontSize: '10.5pt (14px)',\n                fontWeight: 'bold',\n                messageKey: null,\n                expectedContrastRatio: '4.5:1',\n              },\n              relatedNodes: [\n                {\n                  html: '<div class=\"sidebar-item css-qyeqia\" data-selected=\"true\" data-ref-id=\"storybook_internal\" data-item-id=\"root-1-child-a2--grandchild-a1-1\" data-parent-id=\"root-1-child-a2\" data-nodetype=\"story\" data-highlightable=\"true\">',\n                  target: [\n                    '.css-1x6s7u8 > div > div[data-highlighted-ref-id=\"storybook_internal\"] > .css-79elbk[data-title=\"storybook_internal\"] > .css-ohbggj > div[data-selected=\"true\"][data-parent-id=\"root-1-child-a2\"][data-nodetype=\"story\"]',\n                  ],\n                },\n              ],\n              impact: 'serious',\n              message:\n                'Element has insufficient color contrast of 2.92 (foreground color: #ffffff, background color: #029cfd, font size: 10.5pt (14px), font weight: bold). Expected contrast ratio of 4.5:1',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          all: [],\n          none: [],\n          impact: 'serious',\n          html: '<a tabindex=\"-1\" href=\"/iframe.html?path=/story/root-1-child-a2--grandchild-a1-1\" id=\"root-1-child-a2--grandchild-a1-1\" class=\"css-xwriep\">',\n          target: [\n            '.css-1x6s7u8 > div > div[data-highlighted-ref-id=\"storybook_internal\"] > .css-79elbk[data-title=\"storybook_internal\"] > .css-ohbggj > div[data-selected=\"true\"][data-parent-id=\"root-1-child-a2\"][data-nodetype=\"story\"] > .css-xwriep',\n          ],\n          failureSummary:\n            'Fix any of the following:\\n  Element has insufficient color contrast of 2.92 (foreground color: #ffffff, background color: #029cfd, font size: 10.5pt (14px), font weight: bold). Expected contrast ratio of 4.5:1',\n        },\n        {\n          any: [\n            {\n              id: 'color-contrast',\n              data: {\n                fgColor: '#798186',\n                bgColor: '#1b1c1d',\n                contrastRatio: 4.3,\n                fontSize: '8.3pt (11px)',\n                fontWeight: 'bold',\n                messageKey: null,\n                expectedContrastRatio: '4.5:1',\n              },\n              relatedNodes: [\n                {\n                  html: '<div data-side=\"right\" class=\"css-1x6s7u8\">',\n                  target: ['.css-1x6s7u8'],\n                },\n              ],\n              impact: 'serious',\n              message:\n                'Element has insufficient color contrast of 4.3 (foreground color: #798186, background color: #1b1c1d, font size: 8.3pt (11px), font weight: bold). Expected contrast ratio of 4.5:1',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          all: [],\n          none: [],\n          impact: 'serious',\n          html: '<button type=\"button\" data-action=\"collapse-root\" aria-expanded=\"true\" class=\"css-h7e28b\">',\n          target: [\n            '.css-ohbggj > .css-170ite8.sidebar-subheading[data-item-id=\"root-3\"] > .css-h7e28b[type=\"button\"][data-action=\"collapse-root\"]',\n          ],\n          failureSummary:\n            'Fix any of the following:\\n  Element has insufficient color contrast of 4.3 (foreground color: #798186, background color: #1b1c1d, font size: 8.3pt (11px), font weight: bold). Expected contrast ratio of 4.5:1',\n        },\n      ],\n    },\n    {\n      id: 'landmark-unique',\n      impact: 'moderate',\n      tags: ['cat.semantics', 'best-practice'],\n      description: 'Ensure landmarks are unique',\n      help: 'Landmarks should have a unique role or role/label/title (i.e. accessible name) combination',\n      helpUrl: 'https://dequeuniversity.com/rules/axe/4.10/landmark-unique?application=axeAPI',\n      nodes: [\n        {\n          any: [\n            {\n              id: 'landmark-is-unique',\n              data: {\n                role: 'complementary',\n                accessibleText: null,\n              },\n              relatedNodes: [\n                {\n                  html: '<aside class=\"css-1s0lzul\"><div></div></aside>',\n                  target: ['.css-8kwxkl[aria-label=\"Hide Not ready stories\"] > aside'],\n                },\n                {\n                  html: '<aside class=\"css-1s0lzul\"><div></div></aside>',\n                  target: ['.css-8kwxkl[aria-label=\"Hide Unknown ref stories\"] > aside'],\n                },\n                {\n                  html: '<aside class=\"css-1s0lzul\"><div></div></aside>',\n                  target: ['.css-8kwxkl[aria-label=\"Hide Lazy loaded ref stories\"] > aside'],\n                },\n                {\n                  html: '<aside class=\"css-1s0lzul\"><div></div></aside>',\n                  target: ['.css-9whvue[aria-label=\"Hide Basic ref stories\"] > aside'],\n                },\n                {\n                  html: '<aside class=\"css-1s0lzul\"><div></div></aside>',\n                  target: ['.css-9whvue[aria-label=\"Hide Not ready stories\"] > aside'],\n                },\n                {\n                  html: '<aside class=\"css-1s0lzul\"><div></div></aside>',\n                  target: ['.css-9whvue[aria-label=\"Hide Unknown ref stories\"] > aside'],\n                },\n                {\n                  html: '<aside class=\"css-1s0lzul\"><div></div></aside>',\n                  target: ['.css-9whvue[aria-label=\"Hide Lazy loaded ref stories\"] > aside'],\n                },\n              ],\n              impact: 'moderate',\n              message:\n                'The landmark must have a unique aria-label, aria-labelledby, or title to make landmarks distinguishable',\n              '_constructor-name_': 'CheckResult',\n            },\n          ],\n          all: [],\n          none: [],\n          impact: 'moderate',\n          html: '<aside class=\"css-1s0lzul\"><div></div></aside>',\n          target: ['.css-8kwxkl[aria-label=\"Hide Basic ref stories\"] > aside'],\n          failureSummary:\n            'Fix any of the following:\\n  The landmark must have a unique aria-label, aria-labelledby, or title to make landmarks distinguishable',\n        },\n      ],\n    },\n  ],\n} as any;\n"
  },
  {
    "path": "code/addons/a11y/src/types.ts",
    "content": "import type { AxeResults, NodeResult, Result } from 'axe-core';\n\nimport type { A11yParameters as A11yParams } from './params.ts';\n\nexport type A11yReport = EnhancedResults | { error: Error };\n\nexport interface A11yParameters {\n  /**\n   * Accessibility configuration\n   *\n   * @see https://storybook.js.org/docs/writing-tests/accessibility-testing\n   */\n  a11y?: A11yParams;\n}\n\nexport interface A11yGlobals {\n  /**\n   * Accessibility configuration\n   *\n   * @see https://storybook.js.org/docs/writing-tests/accessibility-testing\n   */\n  a11y?: {\n    /**\n     * Prevent the addon from executing automated accessibility checks upon visiting a story. You\n     * can still trigger the checks from the addon panel.\n     *\n     * @see https://storybook.js.org/docs/writing-tests/accessibility-testing#disable-automated-checks\n     */\n    manual?: boolean;\n  };\n}\n\nexport const RuleType = {\n  VIOLATION: 'violations',\n  PASS: 'passes',\n  INCOMPLETION: 'incomplete',\n} as const;\n\nexport type RuleType = (typeof RuleType)[keyof typeof RuleType];\n\nexport type EnhancedNodeResult = NodeResult & {\n  linkPath: string;\n};\n\nexport type EnhancedResult = Omit<Result, 'nodes'> & {\n  nodes: EnhancedNodeResult[];\n};\n\nexport type EnhancedResults = Omit<AxeResults, 'incomplete' | 'passes' | 'violations'> & {\n  incomplete: EnhancedResult[];\n  passes: EnhancedResult[];\n  violations: EnhancedResult[];\n};\n\nexport interface A11yTypes {\n  parameters: A11yParameters;\n  globals: A11yGlobals;\n}\n\nexport type Status =\n  | 'initial'\n  | 'manual'\n  | 'running'\n  | 'error'\n  | 'component-test-error'\n  | 'ran'\n  | 'ready';\n"
  },
  {
    "path": "code/addons/a11y/src/typings.d.ts",
    "content": "declare var __STORYBOOK_STORY_STORE__: any;\n"
  },
  {
    "path": "code/addons/a11y/src/utils.ts",
    "content": "export function getIsVitestStandaloneRun() {\n  try {\n    // @ts-expect-error Suppress TypeScript warning about wrong setting. Doesn't matter, because we don't use tsc for bundling.\n    return import.meta.env.VITEST_STORYBOOK === 'false';\n  } catch (e) {\n    return false;\n  }\n}\n\nexport function getIsVitestRunning() {\n  try {\n    // @ts-expect-error Suppress TypeScript warning about wrong setting. Doesn't matter, because we don't use tsc for bundling.\n    return import.meta.env.MODE === 'test';\n  } catch (e) {\n    return false;\n  }\n}\n"
  },
  {
    "path": "code/addons/a11y/src/visionSimulatorFilters.ts",
    "content": "export const filters: Record<string, { label: string; filter: string; percentage?: number }> = {\n  blurred: {\n    label: 'Blurred vision',\n    filter: 'blur(2px)',\n    percentage: 22.9,\n  },\n  deuteranomaly: {\n    label: 'Deuteranomaly',\n    filter: 'url(\"#storybook-a11y-vision-deuteranomaly\")',\n    percentage: 2.7,\n  },\n  deuteranopia: {\n    label: 'Deuteranopia',\n    filter: 'url(\"#storybook-a11y-vision-deuteranopia\")',\n    percentage: 0.56,\n  },\n  protanomaly: {\n    label: 'Protanomaly',\n    filter: 'url(\"#storybook-a11y-vision-protanomaly\")',\n    percentage: 0.66,\n  },\n  protanopia: {\n    label: 'Protanopia',\n    filter: 'url(\"#storybook-a11y-vision-protanopia\")',\n    percentage: 0.59,\n  },\n  tritanomaly: {\n    label: 'Tritanomaly',\n    filter: 'url(\"#storybook-a11y-vision-tritanomaly\")',\n    percentage: 0.01,\n  },\n  tritanopia: {\n    label: 'Tritanopia',\n    filter: 'url(\"#storybook-a11y-vision-tritanopia\")',\n    percentage: 0.016,\n  },\n  achromatopsia: {\n    label: 'Achromatopsia',\n    filter: 'url(\"#storybook-a11y-vision-achromatopsia\")',\n    percentage: 0.0001,\n  },\n  grayscale: {\n    label: 'Grayscale',\n    filter: 'grayscale(100%)',\n  },\n} as const;\n\nexport const filterDefs = `<svg id=\"storybook-a11y-vision-filters\" style=\"display: none !important;\">\n  <defs>\n    <filter id=\"storybook-a11y-vision-protanopia\">\n      <feColorMatrix\n        in=\"SourceGraphic\"\n        type=\"matrix\"\n        values=\"0.567, 0.433, 0, 0, 0 0.558, 0.442, 0, 0, 0 0, 0.242, 0.758, 0, 0 0, 0, 0, 1, 0\"\n      />\n    </filter>\n    <filter id=\"storybook-a11y-vision-protanomaly\">\n      <feColorMatrix\n        in=\"SourceGraphic\"\n        type=\"matrix\"\n        values=\"0.817, 0.183, 0, 0, 0 0.333, 0.667, 0, 0, 0 0, 0.125, 0.875, 0, 0 0, 0, 0, 1, 0\"\n      />\n    </filter>\n    <filter id=\"storybook-a11y-vision-deuteranopia\">\n      <feColorMatrix\n        in=\"SourceGraphic\"\n        type=\"matrix\"\n        values=\"0.625, 0.375, 0, 0, 0 0.7, 0.3, 0, 0, 0 0, 0.3, 0.7, 0, 0 0, 0, 0, 1, 0\"\n      />\n    </filter>\n    <filter id=\"storybook-a11y-vision-deuteranomaly\">\n      <feColorMatrix\n        in=\"SourceGraphic\"\n        type=\"matrix\"\n        values=\"0.8, 0.2, 0, 0, 0 0.258, 0.742, 0, 0, 0 0, 0.142, 0.858, 0, 0 0, 0, 0, 1, 0\"\n      />\n    </filter>\n    <filter id=\"storybook-a11y-vision-tritanopia\">\n      <feColorMatrix\n        in=\"SourceGraphic\"\n        type=\"matrix\"\n        values=\"0.95, 0.05,  0, 0, 0 0,  0.433, 0.567, 0, 0 0,  0.475, 0.525, 0, 0 0,  0, 0, 1, 0\"\n      />\n    </filter>\n    <filter id=\"storybook-a11y-vision-tritanomaly\">\n      <feColorMatrix\n        in=\"SourceGraphic\"\n        type=\"matrix\"\n        values=\"0.967, 0.033, 0, 0, 0 0, 0.733, 0.267, 0, 0 0, 0.183, 0.817, 0, 0 0, 0, 0, 1, 0\"\n      />\n    </filter>\n    <filter id=\"storybook-a11y-vision-achromatopsia\">\n      <feColorMatrix\n        in=\"SourceGraphic\"\n        type=\"matrix\"\n        values=\"0.299, 0.587, 0.114, 0, 0 0.299, 0.587, 0.114, 0, 0 0.299, 0.587, 0.114, 0, 0 0, 0, 0, 1, 0\"\n      />\n    </filter>\n  </defs>\n</svg>`;\n"
  },
  {
    "path": "code/addons/a11y/src/withVisionSimulator.ts",
    "content": "import type { DecoratorFunction } from 'storybook/internal/types';\n\nimport { useCallback, useEffect } from 'storybook/preview-api';\n\nimport { filterDefs, filters } from './visionSimulatorFilters.ts';\n\nconst knownFilters = Object.values(filters).map((f) => f.filter);\nconst knownFiltersRegExp = new RegExp(`\\\\b(${knownFilters.join('|')})\\\\b`, 'g');\n\nexport const withVisionSimulator: DecoratorFunction = (StoryFn, { globals }) => {\n  const { vision } = globals;\n\n  const applyVisionFilter = useCallback(() => {\n    const existingFilters = document.body.style.filter.replaceAll(knownFiltersRegExp, '').trim();\n\n    const visionFilter = filters[vision as keyof typeof filters]?.filter;\n    if (visionFilter && document.body.classList.contains('sb-show-main')) {\n      if (!existingFilters || existingFilters === 'none') {\n        document.body.style.filter = visionFilter;\n      } else {\n        document.body.style.filter = `${existingFilters} ${visionFilter}`;\n      }\n    } else {\n      document.body.style.filter = existingFilters || 'none';\n    }\n\n    return () => (document.body.style.filter = existingFilters || 'none');\n  }, [vision]);\n\n  useEffect(() => {\n    const cleanup = applyVisionFilter();\n\n    const observer = new MutationObserver(() => applyVisionFilter());\n    observer.observe(document.body, { attributeFilter: ['class'] });\n\n    return () => {\n      cleanup();\n      observer.disconnect();\n    };\n  }, [applyVisionFilter]);\n\n  useEffect(() => {\n    document.body.insertAdjacentHTML('beforeend', filterDefs);\n\n    return () => {\n      const filterDefsElement = document.getElementById('storybook-a11y-vision-filters');\n      filterDefsElement?.parentElement?.removeChild(filterDefsElement);\n    };\n  }, []);\n\n  return StoryFn();\n};\n"
  },
  {
    "path": "code/addons/a11y/template/stories/parameters.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Html,\n  args: {\n    content: '<button>Click Me!</button>',\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n    a11y: {\n      test: 'error',\n    },\n  },\n};\n\nexport const Options = {\n  args: {\n    content:\n      '<button style=\"color: rgb(255, 255, 255); background-color: rgb(76, 175, 80);\">Click me!</button>',\n  },\n  parameters: {\n    a11y: {\n      config: {},\n      options: {\n        checks: {\n          'color-contrast': { enabled: false },\n        },\n      },\n    },\n  },\n};\n\nexport const Config = {\n  args: {\n    content:\n      '<button style=\"color: rgb(255, 255, 255); background-color: rgb(76, 175, 80);\">Click me!</button>',\n  },\n  parameters: {\n    a11y: {\n      config: {\n        rules: [{ id: 'avoid-inline-spacing', options: {} }],\n        disableOtherRules: true,\n      },\n      options: {},\n    },\n  },\n};\n\nexport const SingleNodeContext = {\n  args: {\n    content: `\n      <div id=\"custom-target\">I have no violations</div>\n      <div aria-role=\"nope!\">I have a bad aria-role, but I'm outside the target so my violations will be ignored</div>\n      `,\n  },\n  parameters: {\n    a11y: {\n      context: '#custom-target',\n    },\n  },\n};\n\nexport const MultipleNodeContext = {\n  args: {\n    content: `\n      <div id=\"first-custom-target\">I have no violations</div>\n      <div id=\"second-custom-target\">I also have no violations</div>\n      <div aria-role=\"nope!\">I have a bad aria-role, but I'm outside the target so my violations will be ignored</div>\n      `,\n  },\n  parameters: {\n    a11y: {\n      context: ['#first-custom-target', '#second-custom-target'],\n    },\n  },\n};\n\nexport const IncludeAndExcludeContext = {\n  args: {\n    content: `\n      <div id=\"parent-node\">\n        <div id=\"first-custom-target\">I have no violations</div>\n        <div aria-role=\"nope!\" id=\"second-custom-target\">I have a bad aria-role, but I'm explicitly excluded from the target so my violations will be ignored</div>\n      </div>\n      <div aria-role=\"nope!\">I have a bad aria-role, but I'm outside the included target so my violations will be ignored</div>\n      `,\n  },\n  parameters: {\n    a11y: {\n      context: {\n        include: ['#parent-node'],\n        exclude: ['#second-custom-target'],\n      },\n    },\n  },\n};\n\n/*\n\nTODO: this doesn't work, for some reason axe doesn't find any elements within the iframe\npotentially related to https://github.com/dequelabs/axe-core/issues/4737\nexport const IncludeAndExcludeFromFramesContext = {\n  args: {\n    content: `\n      <iframe id=\"parent-frame\"\n        srcdoc=\"\n          ${`<div id=\"parent-node\">\n            <div id=\"first-custom-target\">I have no violations</div>\n            <div aria-role=\"nope!\" id=\"second-custom-target\">I have a bad aria-role, but I'm explicitly excluded from the target so my violations will be ignored</div>\n          </div>`.replaceAll('\"', '&quot;')}\">\n      </iframe>\n      <div aria-role=\"nope!\">I have a bad aria-role, but I'm outside the included targeted iframe so my violations will be ignored</div>\n      `,\n  },\n  parameters: {\n    a11y: {\n      context: { fromFrames: ['iframe#parent-frame', '*'] },\n    },\n  },\n};\n*/\n\nexport const IncludeAndExcludeFromShadowDOMContext = {\n  args: {\n    content: `\n      <div id=\"shadow-target\"></div>\n      <div aria-role=\"nope!\">I have a bad aria-role, but I'm outside the targeted shadow DOM so my violations will be ignored</div>\n    `,\n  },\n  parameters: {\n    a11y: {\n      context: {\n        include: { fromShadowDom: ['#shadow-dom-host', '#parent-node'] },\n        exclude: { fromShadowDom: ['#shadow-dom-host', '#second-shadow-dom-target'] },\n      },\n    },\n  },\n  play: () => {\n    // See: https://dev.to/js_bits_bill/simplify-shadow-dom-with-sethtmlunsafe-1fne\n    // using setHTMLUnsafe() doesn't work for some reason\n    const shadowHost = document.createElement('div');\n    shadowHost.id = 'shadow-dom-host';\n    const shadowTemplate = document.createElement('template');\n    shadowTemplate.innerHTML = `\n      <div id=\"parent-node\">\n        <div id=\"first-shadow-dom-target\">I'm in the shadow DOM without violations</div>\n        <div id=\"second-shadow-dom-target\" aria-role=\"nope!\">I have a bad aria-role within the shadow DOM, but I'm explicitly excluded from the target so my violations will be ignored</div>\n      </div>`;\n    shadowHost\n      .attachShadow({\n        mode: 'open',\n      })\n      .appendChild(shadowTemplate.content.cloneNode(true));\n    document.getElementById('shadow-target')!.appendChild(shadowHost);\n  },\n};\n\nexport const Disabled = {\n  parameters: {\n    a11y: {\n      disable: true,\n    },\n  },\n};\n"
  },
  {
    "path": "code/addons/a11y/template/stories/tests.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Html,\n  args: {\n    content: '',\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const Violations = {\n  args: {\n    content: `\n      <div>\n        <p>empty heading</p>\n        <h1></h1>\n      </div>\n      <div>\n        <p>empty button</p>\n        <button></button>\n      </div>\n      <div>\n        <p>missing label</p>\n        <label><input /></label>\n      </div>\n      <div>\n        <p>missing alt</p>\n        <img src=\"https://storybook.js.org/images/placeholders/350x150.png\" />\n      </div>\n      <div>\n        <p>Checkbox with contrast toggle</p>\n        <input type=\"checkbox\" id=\"color-toggle\" />\n        <label for=\"color-toggle\">Toggle violation:</label>\n      </div>\n\n      <style>\n        input[type=\"checkbox\"]:not(:checked) + label {\n          background-color: red;\n          color: white;\n          cursor: pointer;\n        }\n\n        input[type=\"checkbox\"]:checked + label {\n          background-color: green;\n          color: white;\n          cursor: pointer;\n        }\n      </style>\n    `,\n  },\n};\n\nexport const Passes = {\n  args: {\n    content: `\n      <div>\n        <p>heading</p>\n        <h1>heading 1</h1>\n      </div>\n      <div>\n        <p>button</p>\n        <button>Click me!</button>\n      </div>\n      <div>\n        <p>contrast</p>\n        <button style=\"color: rgb(255, 255, 255); background-color: rgb(0, 0, 0);\">Click me!</button>\n      </div>\n      <div>\n        <p>label</p>\n        <label><span>label</span><input /></label>\n      </div>\n      <div>\n        <p>alt</p>\n        <img src=\"https://storybook.js.org/images/placeholders/350x150.png\" alt=\"placeholder\" />\n      </div>\n    `,\n  },\n};\n"
  },
  {
    "path": "code/addons/a11y/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/addons/a11y/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/addons/docs/README.md",
    "content": "<center>\n  <img src=\"https://raw.githubusercontent.com/storybookjs/storybook/next/code/addons/docs/docs/media/hero.png\" width=\"100%\" />\n</center>\n\n# Storybook Docs\n\n> migration guide: This page documents the method to configure Storybook introduced recently in 7.0.0, consult the [migration guide](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md) if you want to migrate to this format of configuring Storybook.\n\nStorybook Docs transforms your Storybook stories into world-class component documentation.\n\n**DocsPage.** Out of the box, all your stories get a `DocsPage`. `DocsPage` is a zero-config aggregation of your component stories, text descriptions, docgen comments, props tables, and code examples into clean, readable pages.\n\n**MDX.** If you want more control, `MDX` allows you to write long-form markdown documentation and include stories in one file. You can also use it to write pure documentation pages and embed them inside your Storybook alongside your stories.\n\nJust like Storybook, Docs supports every major view layer including React, Vue 3, Angular, HTML, Web components, Svelte, and many more.\n\nRead on to learn more:\n\n- [Storybook Docs](#storybook-docs)\n  - [DocsPage](#docspage)\n  - [MDX](#mdx)\n  - [Framework support](#framework-support)\n  - [Installation](#installation)\n    - [Be sure to check framework specific installation needs](#be-sure-to-check-framework-specific-installation-needs)\n  - [Preset options](#preset-options)\n  - [TypeScript configuration](#typescript-configuration)\n  - [More resources](#more-resources)\n\n## DocsPage\n\nWhen you [install Docs](#installation), every story gets a `DocsPage`. `DocsPage` pulls information from your stories, components, source code, and story metadata to construct a sensible, zero-config default.\n\nClick on the `Docs` tab to see it:\n\n<center>\n  <img src=\"https://raw.githubusercontent.com/storybookjs/storybook/next/code/addons/docs/docs/media/docs-tab.png\" width=\"100%\" />\n</center>\n\nFor more information on how it works, see the [`DocsPage` reference](https://github.com/storybookjs/storybook/blob/next/code/addons/docs/docs/docspage.md).\n\n## MDX\n\n`MDX` is a syntax for writing long-form documentation with stories side-by-side in the same file. In contrast to `DocsPage`, which provides smart documentation out of the box, `MDX` gives you full control over your component documentation.\n\nHere's an example file:\n\n<!-- prettier-ignore-start -->\n\n```md\nimport { Meta, Story, Canvas } from '@storybook/addon-docs/blocks';\nimport * as CheckboxStories from './Checkbox.stories';\n\n<Meta title=\"MDX/Checkbox\" of={CheckboxStories} />\n\n# Checkbox\n\nWith `MDX` we can include a story for `Checkbox` right in the middle of our\nmarkdown documentation.\n\n<Canvas>\n  <Story of={CheckboxStories.Unchecked} />\n</Canvas>\n```\n\n<!-- prettier-ignore-end -->\n\nAnd here's how that's rendered in Storybook:\n\n<center>\n  <img src=\"https://raw.githubusercontent.com/storybookjs/storybook/next/code/addons/docs/docs/media/mdx-simple.png\" width=\"100%\" />\n</center>\n\nFor more information on `MDX`, see the [`MDX` reference](https://github.com/storybookjs/storybook/blob/next/code/addons/docs/docs/mdx.md).\n\n## Framework support\n\nStorybook Docs supports all view layers that Storybook supports except for React Native (currently). There are some framework-specific features as well, such as props tables and inline story rendering. The following page captures the current state of support:\n\n[Framework Support](https://storybook.js.org/docs/configure/integration/frameworks-feature-support?ref=readme)\n\n**Note:** `#` = WIP support\n\nWant to add enhanced features to your favorite framework? Check out this [dev guide](https://github.com/storybookjs/storybook/tree/next/code/addons/docs/docs/multiframework.md)\n\n## Installation\n\nFirst add the package. Make sure that the versions for your `@storybook/*` packages match:\n\n```sh\nyarn add -D @storybook/addon-docs\n```\n\nDocs has peer dependencies on `react`. If you want to write stories in MDX, you may need to add this dependency as well:\n\n```sh\nyarn add -D react\n```\n\nThen add the following to your `.storybook/main.js`:\n\n```js\nexport default {\n  stories: [\n    '../src/**/*.mdx', // 👈 Add this, to match your project's structure\n    '../src/**/*.stories.@(js|jsx|ts|tsx)',\n  ],\n  addons: [\n    '@storybook/addon-docs', // 👈 Also add this\n  ],\n};\n```\n\n### Be sure to check framework specific installation needs\n\n- [React](https://github.com/storybookjs/storybook/tree/next/code/addons/docs/react) (covered here)\n- [Vue 3](https://github.com/storybookjs/storybook/blob/next/code/addons/docs/vue3)\n- [Angular](https://github.com/storybookjs/storybook/tree/next/code/addons/docs/angular)\n- [Ember](https://github.com/storybookjs/storybook/tree/next/code/addons/docs/ember)\n- [Web Components](https://github.com/storybookjs/storybook/tree/next/code/addons/docs/web-components)\n- [Common setup (all other frameworks)](https://github.com/storybookjs/storybook/tree/next/code/addons/docs/common)\n\n## Preset options\n\nThe `addon-docs` preset has a few configuration options that can be used to configure its babel/webpack loading behavior. Here's an example of how to use the preset with options:\n\n```js\nexport default {\n  addons: [\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        csfPluginOptions: null,\n        mdxPluginOptions: {},\n      },\n    },\n  ],\n};\n```\n\n`csfPluginOptions` is an object for configuring `@storybook/csf-plugin`. When set to `null` it tells docs not to run the `csf-plugin` at all, which can be used as an optimization, or if you're already using `csf-plugin` in your `main.js`.\n\n> With the release of version 7.0, it is no longer possible to import `.md` files directly into Storybook using the `transcludeMarkdown` [option](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#importing-plain-markdown-files-with-transcludemarkdown-has-changed). Instead, we recommend using the [`Markdown`](https://storybook.js.org/docs/api/doc-blocks/doc-block-markdown?ref=readme) Doc Block for importing Markdown files into your Storybook documentation.\n\n## TypeScript configuration\n\nAs of SB6 [TypeScript is zero-config](https://storybook.js.org/docs/configure/integration/typescript?ref=readme) and should work with SB Docs out of the box. For advanced configuration options, refer to the [Props documentation](https://github.com/storybookjs/storybook/tree/next/code/addons/docs/docs/props-tables.md).\n\n## More resources\n\nWant to learn more? Here are some more articles on Storybook Docs:\n\n- References: [DocsPage](https://github.com/storybookjs/storybook/tree/next/code/addons/docs/docs/docspage.md) / [MDX](https://github.com/storybookjs/storybook/tree/next/code/addons/docs/docs/mdx.md) / [FAQ](https://github.com/storybookjs/storybook/tree/next/code/addons/docs/docs/faq.md) / [Recipes](https://github.com/storybookjs/storybook/tree/next/code/addons/docs/docs/recipes.md) / [Theming](https://github.com/storybookjs/storybook/tree/next/code/addons/docs/docs/theming.md) / [Props](https://github.com/storybookjs/storybook/tree/next/code/addons/docs/docs/props-tables.md)\n- Announcements: [Vision](https://medium.com/storybookjs/storybook-docs-sneak-peak-5be78445094a) / [DocsPage](https://medium.com/storybookjs/storybook-docspage-e185bc3622bf) / [MDX](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc) / [Framework support](https://medium.com/storybookjs/storybook-docs-for-new-frameworks-b1f6090ee0ea)\n- Example: [Storybook Design System](https://github.com/storybookjs/design-system)\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/addons/docs/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./preview'],\n        entryPoint: './src/preview.ts',\n      },\n      {\n        exportEntries: ['./manager'],\n        entryPoint: './src/manager.tsx',\n        dts: false,\n      },\n      {\n        exportEntries: ['./blocks'],\n        entryPoint: './src/blocks.ts',\n      },\n      {\n        exportEntries: ['./mdx-react-shim'],\n        entryPoint: './src/mdx-react-shim.ts',\n      },\n      {\n        exportEntries: ['./ember'],\n        entryPoint: './src/ember/index.ts',\n      },\n      {\n        exportEntries: ['./angular'],\n        entryPoint: './src/angular/index.ts',\n      },\n      {\n        exportEntries: ['./web-components'],\n        entryPoint: './src/web-components/index.ts',\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./mdx-loader'],\n        entryPoint: './src/mdx-loader.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/addons/docs/docs/docspage.md",
    "content": "<center>\n  <img src=\"https://raw.githubusercontent.com/storybookjs/storybook/master/addons/docs/docs/media/docspage-hero.png\" width=\"100%\" />\n</center>\n\n<h1>Storybook DocsPage</h1>\n\nWhen you install [Storybook Docs](../README.md), `DocsPage` is the zero-config default documentation that all stories get out of the box. It aggregates your stories, text descriptions, docgen comments, props tables, and code examples into a single page for each component.\n\n- [Motivation](#motivation)\n- [Component parameter](#component-parameter)\n- [Replacing DocsPage](#replacing-docspage)\n  - [Remixing DocsPage using doc blocks](#remixing-docspage-using-doc-blocks)\n- [Story file names](#story-file-names)\n- [Inline stories vs. Iframe stories](#inline-stories-vs-iframe-stories)\n- [Show/Hide code](#showhide-code)\n- [More resources](#more-resources)\n\n## Motivation\n\n`DocsPage` is the successor to [`addon-info`](https://github.com/storybookjs/deprecated-addons/tree/master/addons/info), which was one of the most popular Storybook addons despite many limitations.\n\nLike `addon-info`, `DocsPage` provides sensible defaults, meaning it adds documentation to your existing Storybook without requiring any additional work on your part.\n\nHowever, `DocsPage` brings the following improvements:\n\n- It supports all frameworks that Storybook supports, including React, Vue 3, Angular and [many others](../README.md#framework-support).\n- It generates better documentation that can be used as a standalone docs site, independently of Storybook.\n- It supports better configuration, so you can capture project specific information with ease.\n- It's built to work with [`MDX`](./mdx.md) when you need more control of your documentation.\n\n## Component parameter\n\n`DocsPage` pulls info from many sources, but one of the main ones is the `component` parameter, which is a new addition to Storybook in 5.2. It's based on the best practice that each component should have an associated set of documentation and stories (versus organizing it in some other way).\n\nStorybook uses `component` to extract the component's description and props, and will rely on it further in future releases. We encourage you to add it to existing stories and use it in all new stories.\n\nHere's how to set the component in [Component Story Format (CSF)](https://storybook.js.org/docs/api/csf):\n\n```js\nimport { Badge } from './Badge';\n\nexport default {\n  title: 'Path/to/Badge',\n  component: Badge,\n};\n```\n\nIf you're coming from the `storiesOf` format, there's [a codemod that adds it for you](https://github.com/storybookjs/storybook/blob/next/code/lib/codemod/README.md#add-component-parameters).\n\n## Replacing DocsPage\n\nWhat if you don't want a `DocsPage` for your Storybook, for a specific component, or even for a specific story?\n\nYou can replace DocsPage at any level by overriding the `docs.page` parameter:\n\n- With `null` to remove docs\n- [With MDX](./recipes.md#csf-stories-with-mdx-docs) docs\n- With a custom React component\n\n**Globally (preview.js)**\n\n```js\nimport { addParameters } from '@storybook/react';\n\naddParameters({ docs: { page: null } });\n```\n\n**Component-level (Button.stories.js)**\n\n```js\nimport { Button } from './Button';\n\nexport default {\n  title: 'Demo/Button',\n  component: Button,\n  parameters: { docs: { page: null } },\n};\n```\n\n**Story-level (Button.stories.js)**\n\n```js\nimport { Button } from './Button';\n// export default { ... }\nexport const basic => () => <Button>Basic</Button>\nbasic.parameters = {\n  docs: { page: null }\n}\n```\n\n### Remixing DocsPage using doc blocks\n\nHere's an example of rebuilding `DocsPage` out of doc blocks:\n\n```js\nimport React from 'react';\nimport { ArgsTable, Description, Primary, Stories, Subtitle, Title } from '@storybook/addon-docs';\nimport { DocgenButton } from '../../components/DocgenButton';\n\nexport default {\n  title: 'Addons/Docs/stories docs blocks',\n  component: DocgenButton,\n  parameters: {\n    docs: {\n      page: () => (\n        <>\n          <Title />\n          <Subtitle />\n          <Description />\n          <Primary />\n          <ArgsTable />\n          <Stories />\n        </>\n      ),\n    },\n  },\n};\n```\n\nYou can interleave your own components to customize the auto-generated contents of the page, or pass in different options to the blocks to customize their appearance.\n\n## Story file names\n\nUnless you use a custom webpack configuration, all of your story files should have the suffix `*.stories.@(j|t)sx?`, e.g. `\"Badge.stories.js\"`, `\"Badge.stories.tsx\"`, etc.\n\nThe docs preset assumes this naming convention for its `source-loader` setup. If you want to use a different naming convention, you'll need a [manual configuration](../README.md#manual-configuration).\n\n## Inline stories vs. Iframe stories\n\nDue to the complex nature of writing a cross-framework utility like Storybook, the story blocks for most frameworks exist within an `<iframe>` element. This creates a clean separation of the context the code for each framework lives inside, but it isn't a perfect tradeoff. It does create a set of disadvantages--namely, you have to explicitly set the height of a story. It also causes some headaches for certain dev tools (Vue dev tools, for example, don't pick up components that exist in an iframe, without substantial jerry-rigging).\n\nThat being said, there is a system in place to remove the necessity of this tradeoff. The docs configuration contains two options, `inlineStories` and `prepareForInline` that can work together to integrate non-react stories seamlessly (or should I say \"scroll-bar-less-ly\") into DocsPage. Setting `inlineStories` to `true` tells storybook to stop putting your stories into an iframe. The hard(er) part is providing the `prepareForInline` parameter. This parameter accepts a function that transforms story content in your given framework into something react can render. Any given framework will need to approach this in a different way. Angular, for example, might convert its story content into a custom element (you can read about that [here](https://angular.io/guide/elements)). We've actually taken the initiative and implemented Vue inline stories _for you_ in the default docs config for Vue, because we're such nice people. The following docs config block allows Vue components to be rendered inline through an effect hook provided by [@egoist/vue-to-react](https://github.com/egoist/vue-to-react):\n\n```js\nimport React from 'react';\nimport { render } from 'react-dom';\nimport { addParameters } from '@storybook/vue';\nimport toReact from '@egoist/vue-to-react';\n\naddParameters({\n  docs: {\n    prepareForInline: (storyFn, { args }) => {\n      const Story = toReact(storyFn());\n      return <Story {...args} />;\n    },\n  },\n});\n```\n\nWith that function, anyone using the docs addon for `@storybook/vue` can make their stories render inline, either globally with the `docs.story.inline` parameter, or on a per-story-basis using the `inline` prop on the `<Story>` doc block. If you come up with an elegant and flexible implementation for the `prepareForInline` function for your own framework, let us know! We'd love to make it the default configuration, to make inline stories more accessible for a larger variety of frameworks!\n\n## Show/Hide code\n\nBy default, the code block under the Preview is collapsed and you have to click on \"Show code\" to reveal it.\n\nYou can override this default behavior in `.storybook/preview.js` (or in any of your components/stories):\n\n```js\nexport const parameters = {\n  docs: {\n    canvas: {\n      sourceState: 'shown',\n    },\n  },\n};\n```\n\nWith that flag, now the docs addon will show all code blocks open by default.\n\n## More resources\n\n- References: [README](../README.md) / [DocsPage](docspage.md) / [MDX](mdx.md) / [FAQ](faq.md) / [Recipes](recipes.md) / [Theming](theming.md) / [Props](props-tables.md)\n- Framework-specific docs: [React](../react/README.md) / [Vue](../vue/README.md) / [Angular](../angular/README.md) / [Web components](../web-components/README.md) / [Ember](../ember/README.md)\n- Announcements: [Vision](https://medium.com/storybookjs/storybook-docs-sneak-peak-5be78445094a) / [DocsPage](https://medium.com/storybookjs/storybook-docspage-e185bc3622bf) / [MDX](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc) / [Framework support](https://medium.com/storybookjs/storybook-docs-for-new-frameworks-b1f6090ee0ea)\n- Example: [Storybook Design System](https://github.com/storybookjs/design-system)\n"
  },
  {
    "path": "code/addons/docs/docs/faq.md",
    "content": "<h1>Storybook Docs FAQs</h1>\n\nYou've read the [Storybook Docs README](../README.md). You're already familiar with both [DocsPage](./docspage.md) and [MDX](./mdx.md). You've even browsed our [Docs recipes](/./recipes.md). But Docs is a big project and you've still got questions! Maybe you'll find your answer here:\n\n- [Does Docs support framework X?](#does-docs-support-framework-x)\n- [How does Docs interact with existing addons?](#how-does-docs-interact-with-existing-addons)\n- [How do I debug my MDX story?](#how-do-i-debug-my-mdx-story)\n- [More resources](#more-resources)\n\n## Does Docs support framework X?\n\nDocs does not currently support [React Native](https://github.com/storybookjs/react-native). Otherwise, [it supports all frameworks that Storybook supports](../README.md#framework-support), including React, Vue 3, Angular, Ember, Svelte, and others.\n\n## How does Docs interact with existing addons?\n\nCurrently we hide the addons panel when docs is visible. It's tricky because all the addons assume that there is only one story currently visible, and in docs there are potentially many. We have a proposal for \"knobs v2\" to address this for knobs, but nothing planned to address it in general. How we deal with it generally is [open for discussion](https://github.com/storybooks/storybook/issues/6700)!\n\n## How do I debug my MDX story?\n\n<center>\n  <img src=\"https://raw.githubusercontent.com/storybookjs/storybook/master/addons/docs/docs/media/faq-debug.png\" width=\"100%\" />\n</center>\n\n> \"My story renders in docs, but doesn’t show up the way I’d expect in the Canvas”\n\nThe original MDX gets compiled to Javascript, and the easiest way to debug your MDX stories in the Canvas is to inspect that Javascript. To do this, open your browser dev tools and view the source that’s being served by the webpack dev server. You may need to hunt for it a little bit under the `webpack > > . > path/to/your/stories` folder, but it’s there.\n\nFor example, the following MDX story:\n\n```mdx\n<Story name=\"solo story\">\n  <Button onClick={action('clicked')}>solo</Button>\n</Story>\n```\n\nShows up in the dev tools as follows:\n\n<center>\n  <img src=\"https://raw.githubusercontent.com/storybookjs/storybook/master/addons/docs/docs/media/faq-devtools.png\" width=\"100%\" />\n</center>\n\nThis is [Component Story Format (CSF)](https://medium.com/storybookjs/component-story-format-66f4c32366df), so there are ways to debug. You can copy and paste this code into a new `.stories.js` file and play around with it at a lower level to understand what's going wrong.\n\n## More resources\n\n- References: [README](../README.md) / [DocsPage](docspage.md) / [MDX](mdx.md) / [FAQ](faq.md) / [Recipes](recipes.md) / [Theming](theming.md) / [Props](props-tables.md)\n- Framework-specific docs: [React](../react/README.md) / [Vue 3](../vue3/README.md) / [Angular](../angular/README.md) / [Web components](../web-components/README.md) / [Ember](../ember/README.md)\n- Announcements: [Vision](https://medium.com/storybookjs/storybook-docs-sneak-peak-5be78445094a) / [DocsPage](https://medium.com/storybookjs/storybook-docspage-e185bc3622bf) / [MDX](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc) / [Framework support](https://medium.com/storybookjs/storybook-docs-for-new-frameworks-b1f6090ee0ea)\n- Example: [Storybook Design System](https://github.com/storybookjs/design-system)\n"
  },
  {
    "path": "code/addons/docs/docs/frameworks/ANGULAR.md",
    "content": "<center>\n  <img src=\"../docs/media/angular-hero.png\" width=\"100%\" />\n</center>\n\n<h1>Storybook Docs for Angular</h1>\n\n> migration guide: This page documents the method to configure storybook introduced recently in 5.3.0, consult the [migration guide](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md) if you want to migrate to this format of configuring storybook.\n\nStorybook Docs transforms your Storybook stories into world-class component documentation. Storybook Docs for Angular supports [DocsPage](../docs/docspage.md) for auto-generated docs, and [MDX](../docs/mdx.md) for rich long-form docs.\n\nTo learn more about Storybook Docs, read the [general documentation](../README.md). To learn the Angular specifics, read on!\n\n- [Installation](#installation)\n- [DocsPage](#docspage)\n- [Props tables](#props-tables)\n  - [Automatic Compodoc setup](#automatic-compodoc-setup)\n- [Manual Compodoc setup](#manual-compodoc-setup)\n- [MDX](#mdx)\n- [IFrame height](#iframe-height)\n- [Inline Stories](#inline-stories)\n- [More resources](#more-resources)\n\n## Installation\n\nFirst add the package. Make sure that the versions for your `@storybook/*` packages match:\n\n```sh\nyarn add -D @storybook/addon-docs\n```\n\nThen add the following to your `.storybook/main.js` exports:\n\n```js\nexport default {\n  addons: ['@storybook/addon-docs'],\n};\n```\n\n## DocsPage\n\nWhen you [install docs](#installation) you should get basic [DocsPage](../docs/docspage.md) documentation automagically for all your stories, available in the `Docs` tab of the Storybook UI.\n\n## Props tables\n\nGetting [Props tables](../docs/props-tables.md) for your components requires a few more steps. Docs for Angular relies on [Compodoc](https://compodoc.app/), the excellent API documentation tool. It supports `inputs`, `outputs`, `properties`, `methods`, `view/content child/children` as first class prop types.\n\n### Automatic Compodoc setup\n\nDuring `sb init`, you will be asked, whether you want to setup Compodoc for your project. Just answer the question with Yes. Compodoc is then ready to use!\n\n## Manual Compodoc setup\n\nYou'll need to register Compodoc's `documentation.json` file in `.storybook/preview.ts`:\n\n```js\nimport { setCompodocJson } from '@storybook/addon-docs/angular';\nimport docJson from '../documentation.json';\n\nsetCompodocJson(docJson);\n```\n\nFinally, to set up compodoc, you'll first need to install Compodoc:\n\n```sh\nyarn add -D @compodoc/compodoc\n```\n\nThen you'll need to configure Compodoc to generate a `documentation.json` file. Adding the following snippet to your `projects.<project>.architect.<storybook|build-storybook>` in the `angular.json` creates a metadata file `./documentation.json` each time you run storybook:\n\n```jsonc\n// angular.json\n{\n  \"projects\": {\n    \"your-project\": {\n      \"architect\": {\n        \"storybook\": {\n          ...,\n          \"compodoc\": true,\n          \"compodocArgs\": [\n            \"-e\",\n            \"json\",\n            \"-d\",\n            \".\" // the root folder of your project\n          ],\n        },\n        \"build-storybook\": {\n          ...,\n          \"compodoc\": true,\n          \"compodocArgs\": [\n            \"-e\",\n            \"json\",\n            \"-d\",\n            \".\" // the root folder of your project\n          ],\n        }\n      }\n    }\n  }\n}\n```\n\nUnfortunately, it's not currently possible to update this dynamically as you edit your components, but [there's an open issue](https://github.com/storybookjs/storybook/issues/8672) to support this with improvements to Compodoc.\n\nFinally, be sure to fill in the `component` field in your story metadata:\n\n```ts\nimport { AppComponent } from './app.component';\n\nexport default {\n  title: 'App Component',\n  component: AppComponent,\n};\n```\n\n## MDX\n\n[MDX](../docs/mdx.md) is a convenient way to document your components in Markdown and embed documentation components, such as stories and props tables, inline.\n\nDocs has peer dependencies on `react`. If you want to write stories in MDX, you may need to add this dependency as well:\n\n```sh\nyarn add -D react\n```\n\nThen update your `.storybook/main.js` to make sure you load MDX files:\n\n```js\nexport default {\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],\n};\n```\n\nFinally, you can create MDX files like this:\n\n```md\nimport { Meta, Story, ArgsTable } from '@storybook/addon-docs';\nimport { AppComponent } from './app.component';\n\n<Meta title='App Component' component={AppComponent} />\n\n# App Component\n\nSome **markdown** description, or whatever you want.\n\n<Story name='basic' height='400px'>{{\n  component: AppComponent,\n  props: {},\n}}</Story>\n\n## ArgsTable\n\n<ArgsTable of={AppComponent} />\n```\n\nYes, it's redundant to declare `component` twice. [Coming soon](https://github.com/storybookjs/storybook/issues/8673).\n\nAlso, to use the `Props` doc block, you need to set up Compodoc, [as described above](#docspage).\n\nWhen you are using `template`, `moduleMetadata` and/or `addDecorators` with `storiesOf` then you can easily translate your story to MDX, too:\n\n```md\nimport { Meta, Story, ArgsTable } from '@storybook/addon-docs';\nimport { CheckboxComponent, RadioButtonComponent } from './my-components';\nimport { moduleMetadata } from '@storybook/angular';\n\n<Meta title='Checkbox' decorators={[\n  moduleMetadata({\n    declarations: [CheckboxComponent]\n  })\n]} />\n\n# Basic Checkbox\n\n<Story name='basic check' height='400px'>{{\n  template: `\n    <div class=\"some-wrapper-with-padding\">\n      <my-checkbox [checked]=\"checked\">Some Checkbox</my-checkbox>\n    </div>\n  `,\n  props: {\n    checked: true\n  }\n}}</Story>\n\n# Basic Radiobutton\n\n<Story name='basic radio' height='400px'>{{\n  moduleMetadata: {\n    declarations: [RadioButtonComponent]\n  }\n  template: `\n    <div class=\"some-wrapper-with-padding\">\n      <my-radio-btn [checked]=\"checked\">Some Checkbox</my-radio-btn>\n    </div>\n  `,\n  props: {\n    checked: true\n  }\n}}</Story>\n```\n\n## IFrame height\n\nStorybook Docs renders all Angular stories inside IFrames, with a default height of `60px`. You can update this default globally, or modify the IFrame height locally per story in `DocsPage` and `MDX`.\n\nTo update the global default, modify `.storybook/preview.ts`:\n\n```ts\nexport const parameters = { docs: { story: { iframeHeight: '400px' } } };\n```\n\nFor `DocsPage`, you need to update the parameter locally in a story:\n\n```ts\nexport const basic = () => ...\nbasic.parameters = {\n  docs: { story: { iframeHeight: '400px' } },\n}\n```\n\nAnd for `MDX` you can modify it as an attribute on the `Story` element:\n\n```md\n<Story name='basic' height='400px'>{...}</Story>\n```\n\n## Inline Stories\n\nStorybook Docs renders all Angular stories inline by default.\n\nHowever, you can render stories in an iframe, with a default height of `100px` (configurable using the `docs.story.iframeHeight` story parameter), by using the `docs.story.inline` parameter.\n\nTo do so for all stories, update `.storybook/preview.js`:\n\n```js\nexport const parameters = { docs: { story: { inline: false } } };\n```\n\n## More resources\n\nWant to learn more? Here are some more articles on Storybook Docs:\n\n- References: [DocsPage](../docs/docspage.md) / [MDX](../docs/mdx.md) / [FAQ](../docs/faq.md) / [Recipes](../docs/recipes.md) / [Theming](../docs/theming.md) / [Props](../docs/props-tables.md)\n- Announcements: [Vision](https://medium.com/storybookjs/storybook-docs-sneak-peak-5be78445094a) / [DocsPage](https://medium.com/storybookjs/storybook-docspage-e185bc3622bf) / [MDX](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc) / [Framework support](https://medium.com/storybookjs/storybook-docs-for-new-frameworks-b1f6090ee0ea)\n- Example: [Storybook Design System](https://github.com/storybookjs/design-system)\n"
  },
  {
    "path": "code/addons/docs/docs/frameworks/COMMON.md",
    "content": "<h1>Storybook Docs Common Setup</h1>\n\nStorybook Docs transforms your Storybook stories into world-class component documentation. Docs supports [all web frameworks that Storybook supports](../README.md#framework-support).\n\nPopular frameworks like [React](../react/README.md)/[Vue 3](../vue3/README.md)/[Angular](../angular/README.md)/[Ember](../ember/README.md)/[Web components](../web-components/README.md) have their own framework-specific optimizations and setup guides. This README documents the \"common\" setup for other frameworks that don't have any docs-specific optimizations.\n\n- [Installation](#installation)\n- [DocsPage](#docspage)\n- [MDX](#mdx)\n- [IFrame height](#iframe-height)\n- [More resources](#more-resources)\n\n## Installation\n\nFirst add the package. Make sure that the versions for your `@storybook/*` packages match:\n\n```sh\nyarn add -D @storybook/addon-docs\n```\n\nThen add the following to your `.storybook/main.js` addons:\n\n```js\nexport default {\n  addons: ['@storybook/addon-docs'],\n};\n```\n\n## DocsPage\n\nWhen you [install docs](#installation) you should get basic [DocsPage](../docs/docspage.md) documentation automatically for all your stories, available in the `Docs` tab of the Storybook UI.\n\n## MDX\n\n[MDX](../docs/mdx.md) is a convenient way to document your components in Markdown and embed documentation components, such as stories and props tables, inline.\n\nDocs has peer dependencies on `react`. If you want to write stories in MDX, you may need to add this dependency as well:\n\n```sh\nyarn add -D react\n```\n\nThen update your `.storybook/main.js` to make sure you load MDX files:\n\n```js\nexport default {\n  stories: ['../src/stories/**/*.stories.@(js|mdx)'],\n};\n```\n\nFinally, you can create MDX files like this:\n\n```md\nimport { Meta, Story, ArgsTable } from '@storybook/addon-docs';\n\n<Meta title='App Component' />\n\n# App Component\n\nSome **markdown** description, or whatever you want.\n\n<Story name='basic' height='400px'>{() => {\nreturn { ... }; // should match the typical story format for your framework\n}}</Story>\n```\n\n## IFrame height\n\nIn the \"common\" setup, Storybook Docs renders stories inside `iframe`s, with a default height of `60px`. You can update this default globally, or modify the `iframe` height locally per story in `DocsPage` and `MDX`.\n\nTo update the global default, modify `.storybook/preview.js`:\n\n```ts\nexport const parameters = { docs: { story: { iframeHeight: '400px' } } };\n```\n\nFor `DocsPage`, you need to update the parameter locally in a story:\n\n```ts\nexport const basic = () => ...\nbasic.parameters = {\n  docs: { story: { iframeHeight: '400px' } }\n}\n```\n\nAnd for `MDX` you can modify it, especially if you work with some components using fixed or sticky positions, as an attribute on the `Story` element:\n\n```md\n<Story name='basic' height='400px'>{...}</Story>\n```\n\n## More resources\n\nWant to learn more? Here are some more articles on Storybook Docs:\n\n- References: [DocsPage](../docs/docspage.md) / [MDX](../docs/mdx.md) / [FAQ](../docs/faq.md) / [Recipes](../docs/recipes.md) / [Theming](../docs/theming.md) / [Props](../docs/props-tables.md)\n- Announcements: [Vision](https://medium.com/storybookjs/storybook-docs-sneak-peak-5be78445094a) / [DocsPage](https://medium.com/storybookjs/storybook-docspage-e185bc3622bf) / [MDX](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc) / [Framework support](https://medium.com/storybookjs/storybook-docs-for-new-frameworks-b1f6090ee0ea)\n- Example: [Storybook Design System](https://github.com/storybookjs/design-system)\n"
  },
  {
    "path": "code/addons/docs/docs/frameworks/EMBER.md",
    "content": "<h1>Storybook Docs for Ember</h1>\n\n> migration guide: This page documents the method to configure storybook introduced recently in 5.3.0, consult the [migration guide](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md) if you want to migrate to this format of configuring storybook.\n\nStorybook Docs transforms your Storybook stories into world-class component documentation. Storybook Docs for Ember supports [DocsPage](../docs/docspage.md) for auto-generated docs, and [MDX](../docs/mdx.md) for rich long-form docs.\n\nTo learn more about Storybook Docs, read the [general documentation](../README.md). To learn the Ember specifics, read on!\n\n- [Installation](#installation)\n- [DocsPage](#docspage)\n- [Props tables](#props-tables)\n- [MDX](#mdx)\n- [IFrame height](#iframe-height)\n- [More resources](#more-resources)\n\n## Installation\n\nFirst add the package. Make sure that the versions for your `@storybook/*` packages match:\n\n```sh\nyarn add -D @storybook/addon-docs\n```\n\nThen add the following to your `.storybook/main.js` addons:\n\n```js\nexport default {\n  addons: ['@storybook/addon-docs'],\n};\n```\n\n## DocsPage\n\nWhen you [install docs](#installation) you should get basic [DocsPage](../docs/docspage.md) documentation automagically for all your stories, available in the `Docs` tab of the Storybook UI.\n\n## Props tables\n\nGetting [Props tables](../docs/props-tables.md) for your components requires a few more steps. Docs for Ember relies on [@storybook/ember-cli-storybook addon](https://github.com/storybookjs/ember-cli-storybook), to extract documentation comments from your component source files. If you're using Storybook with Ember, you should already have this addon installed, you will just need to enable it by adding the following config block in your `ember-cli-build.js` file:\n\n```js\nlet app = new EmberApp(defaults, {\n  'ember-cli-storybook': {\n    enableAddonDocsIntegration: true,\n  },\n});\n```\n\nNow, running the ember-cli server will generate a JSON documentation file at `/storybook-docgen/index.json`. Since generation of this file is tied into the ember-cli build, it will get regenerated everytime component files are saved. For details on documenting your components, check out the examples in the addon that powers the generation [ember-cli-addon-docs-yuidoc](https://github.com/ember-learn/ember-cli-addon-docs-yuidoc#documenting-components).\n\nNext, add the following to your `.storybook/preview.js` to load the generated json file:\n\n```js\nimport { setJSONDoc } from '@storybook/addon-docs/ember';\nimport docJson from '../dist/storybook-docgen/index.json';\n\nsetJSONDoc(docJson);\n```\n\nFinally, be sure to fill in the `component` field in your story metadata. This should be a string that matches the name of the `@class` used in your source comments:\n\n```ts\nexport default {\n  title: 'App Component',\n  component: 'AppComponent',\n};\n```\n\n## MDX\n\n[MDX](../docs/mdx.md) is a convenient way to document your components in Markdown and embed documentation components, such as stories and props tables, inline.\n\nDocs has peer dependencies on `react`. If you want to write stories in MDX, you may need to add this dependency as well:\n\n```sh\nyarn add -D react\n```\n\nThen update your `.storybook/main.js` to make sure you load MDX files:\n\n```js\nexport default {\n  stories: ['../src/stories/**/*.stories.@(js|mdx)'],\n};\n```\n\nFinally, you can create MDX files like this:\n\n```md\nimport { Meta, Story, ArgsTable } from '@storybook/addon-docs';\nimport { hbs } from 'ember-cli-htmlbars';\n\n<Meta title='App Component' component='AppComponent' />\n\n# App Component\n\nSome **markdown** description, or whatever you want.\n\n<Story name='basic' height='400px'>{{\n  template: hbs`<AppComponent @title={{title}} />`,\ncontext: { title: \"Title\" },\n}}</Story>\n\n## ArgsTable\n\n<ArgsTable of='AppComponent' />\n```\n\nYes, it's redundant to declare `component` twice. [Coming soon](https://github.com/storybookjs/storybook/issues/8673).\n\nAlso, to use the `Props` doc block, you need to set up documentation generation, [as described above](#docspage).\n\n## IFrame height\n\nStorybook Docs renders all Ember stories inside `iframe`s, with a default height of `60px`. You can update this default globally, or modify the `iframe` height locally per story in `DocsPage` and `MDX`.\n\nTo update the global default, modify `.storybook/preview.js`:\n\n```ts\nexport const parameters = { docs: { story: { iframeHeight: '400px' } } };\n```\n\nFor `DocsPage`, you need to update the parameter locally in a story:\n\n```ts\nexport const basic = () => ...\nbasic.parameters = {\n  docs: { story: { iframeHeight: '400px' } }\n}\n```\n\nAnd for `MDX` you can modify it as an attribute on the `Story` element:\n\n```md\n<Story name='basic' height='400px'>{...}</Story>\n```\n\n## More resources\n\nWant to learn more? Here are some more articles on Storybook Docs:\n\n- References: [DocsPage](../docs/docspage.md) / [MDX](../docs/mdx.md) / [FAQ](../docs/faq.md) / [Recipes](../docs/recipes.md) / [Theming](../docs/theming.md) / [Props](../docs/props-tables.md)\n- Announcements: [Vision](https://medium.com/storybookjs/storybook-docs-sneak-peak-5be78445094a) / [DocsPage](https://medium.com/storybookjs/storybook-docspage-e185bc3622bf) / [MDX](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc) / [Framework support](https://medium.com/storybookjs/storybook-docs-for-new-frameworks-b1f6090ee0ea)\n- Example: [Storybook Design System](https://github.com/storybookjs/design-system)\n"
  },
  {
    "path": "code/addons/docs/docs/frameworks/REACT.md",
    "content": "<center>\n  <img src=\"../docs/media/docspage-hero.png\" width=\"100%\" />\n</center>\n\n<h1>Storybook Docs for React</h1>\n\n> migration guide: This page documents the method to configure storybook introduced recently in 5.3.0, consult the [migration guide](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md) if you want to migrate to this format of configuring storybook.\n\nStorybook Docs transforms your Storybook stories into world-class component documentation. Storybook Docs for React supports [DocsPage](../docs/docspage.md) for auto-generated docs, and [MDX](../docs/mdx.md) for rich long-form docs.\n\nTo learn more about Storybook Docs, read the [general documentation](../README.md). To learn the React specifics, read on!\n\n- [Installation](#installation)\n- [DocsPage](#docspage)\n- [Props tables](#props-tables)\n- [MDX](#mdx)\n- [Inline stories](#inline-stories)\n- [TypeScript props with `react-docgen-typescript`](#typescript-props-with-react-docgen-typescript)\n- [More resources](#more-resources)\n\n## Installation\n\nFirst add the package. Make sure that the versions for your `@storybook/*` packages match:\n\n```sh\nyarn add -D @storybook/addon-docs\n```\n\nThen add the following to your `.storybook/main.js` list of `addons`:\n\n```js\nexport default {\n  // other settings\n  addons: ['@storybook/addon-docs'];\n}\n```\n\n## DocsPage\n\nWhen you [install docs](#installation) you should get basic [DocsPage](../docs/docspage.md) documentation automatically for all your stories, available in the `Docs` tab of the Storybook UI.\n\n## Props tables\n\nStorybook Docs automatically generates [Props tables](../docs/props-tables.md) for your components based on either `PropTypes` or `TypeScript` types. To show the props table for your component, be sure to fill in the `component` field in your story metadata:\n\n```ts\nimport { Button } from './Button';\n\nexport default {\n  title: 'Button',\n  component: Button,\n};\n```\n\n## MDX\n\n[MDX](../docs/mdx.md) is a convenient way to document your components in Markdown and embed documentation components, such as stories and props tables, inline.\n\nThen update your `.storybook/main.js` to make sure you load MDX files:\n\n```js\nexport default {\n  stories: ['../src/stories/**/*.stories.@(js|mdx)'],\n};\n```\n\nFinally, you can create MDX files like this:\n\n```md\nimport { Meta, Story, ArgsTable } from '@storybook/addon-docs';\nimport { Button } from './Button';\n\n<Meta title='Button' component={Button} />\n\n# Button\n\nSome **markdown** description, or whatever you want.\n\n<Story name='basic' height='400px'>\n  <Button>Label</Button>\n</Story>\n\n## ArgsTable\n\n<ArgsTable of={Button} />\n```\n\n## Inline stories\n\nStorybook Docs renders all React stories inline by default.\n\nHowever, you can render stories in an iframe, with a default height of `60px` (configurable using the `docs.story.iframeHeight` story parameter), by using the `docs.stories.inline` parameter.\n\nTo do so for all stories, update `.storybook/preview.js`:\n\n```js\nexport const parameters = { docs: { story: { inline: false } } };\n```\n\n## TypeScript props with `react-docgen-typescript`\n\nIf you're using TypeScript, there are two different options for generating props: `react-docgen` (default) or `react-docgen-typescript`.\n\nYou can add the following lines to your `.storybook/main.js` to switch between the two (or disable docgen):\n\n```js\nexport default {\n  typescript: {\n    // also valid 'react-docgen' | false\n    reactDocgen: 'react-docgen-typescript',\n  },\n};\n```\n\nNeither option is perfect, so here's everything you should know if you're thinking about using `react-docgen` for TypeScript.\n\n|                 | `react-docgen-typescript`                                                                                                 | `react-docgen`                                                                                        |\n| --------------- | ------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |\n| **Features**    | **Great**. The analysis produces great results which gives the best props table experience.                               | **OK**. React-docgen produces basic results that are fine for most use cases.                         |\n| **Performance** | **Slow**. It's doing a lot more work to produce those results, and may also have an inefficient implementation.           | **Blazing fast**. Adding it to your project increases build time negligibly.                          |\n| **Bugs**        | **Some**. There are corner cases that are not handled properly, and are annoying for developers.                          | **Some**. There are corner cases that are not handled properly, and are annoying for developers.      |\n| **SB docs**     | **Good**. Our prop tables have supported `react-docgen-typescript` results from the beginning, so it's relatively stable. | **OK**. There are some obvious improvements to fully support `react-docgen`, and they're coming soon. |\n\n**Performance** is a common question, so here are build times from a random project to quantify. Your mileage may vary:\n\n| Docgen                  | Build time |\n| ----------------------- | ---------- |\n| react-docgen-typescript | 33s        |\n| react-docgen            | 29s        |\n| none                    | 28s        |\n\n## More resources\n\nWant to learn more? Here are some more articles on Storybook Docs:\n\n- References: [DocsPage](../docs/docspage.md) / [MDX](../docs/mdx.md) / [FAQ](../docs/faq.md) / [Recipes](../docs/recipes.md) / [Theming](../docs/theming.md) / [Props](../docs/props-tables.md)\n- Announcements: [Vision](https://medium.com/storybookjs/storybook-docs-sneak-peak-5be78445094a) / [DocsPage](https://medium.com/storybookjs/storybook-docspage-e185bc3622bf) / [MDX](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc) / [Framework support](https://medium.com/storybookjs/storybook-docs-for-new-frameworks-b1f6090ee0ea)\n- Example: [Storybook Design System](https://github.com/storybookjs/design-system)\n"
  },
  {
    "path": "code/addons/docs/docs/frameworks/VUE.md",
    "content": "<center>\n  <img src=\"../docs/media/vue-hero.png\" width=\"100%\" />\n</center>\n\n<h1>Storybook Docs for Vue</h1>\n\n> migration guide: This page documents the method to configure storybook introduced recently in 5.3.0, consult the [migration guide](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md) if you want to migrate to this format of configuring storybook.\n\nStorybook Docs transforms your Storybook stories into world-class component documentation. Storybook Docs for Vue supports [DocsPage](../docs/docspage.md) for auto-generated docs, and [MDX](../docs/mdx.md) for rich long-form docs.\n\nTo learn more about Storybook Docs, read the [general documentation](../README.md). To learn the Vue specifics, read on!\n\n- [Installation](#installation)\n- [Preset options](#preset-options)\n- [DocsPage](#docspage)\n- [Props tables](#props-tables)\n- [MDX](#mdx)\n- [Inline Stories](#inline-stories)\n- [More resources](#more-resources)\n\n## Installation\n\nFirst add the package. Make sure that the versions for your `@storybook/*` packages match:\n\n```sh\nyarn add -D @storybook/addon-docs\n```\n\nThen add the following to your `.storybook/main.js` addons:\n\n```js\nexport default {\n  addons: ['@storybook/addon-docs'],\n};\n```\n\n## Preset options\n\nThe `addon-docs` preset for Vue has a configuration option that can be used to configure [`vue-docgen-api`](https://github.com/vue-styleguidist/vue-styleguidist/tree/dev/packages/vue-docgen-api), a tool which extracts information from Vue components. Here's an example of how to use the preset with options for Vue app:\n\n```js\nexport default {\n  addons: [\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        vueDocgenOptions: {\n          alias: {\n            '@': path.resolve(process.cwd(), 'src'),\n          },\n        },\n      },\n    },\n  ],\n};\n```\n\nThe `vueDocgenOptions` is an object for configuring `vue-docgen-api`. See [`vue-docgen-api`'s docs](https://github.com/vue-styleguidist/vue-styleguidist/tree/dev/packages/vue-docgen-api#options-docgenoptions) for available configuration options.\n\n## DocsPage\n\nWhen you [install docs](#installation) you should get basic [DocsPage](../docs/docspage.md) documentation automagically for all your stories, available in the `Docs` tab of the Storybook UI.\n\n## Props tables\n\nGetting [Props tables](../docs/props-tables.md) for your components requires a few more steps. Docs for Vue relies on [`vue-docgen-loader`](https://github.com/pocka/vue-docgen-loader). It supports `props`, `events`, and `slots` as first class prop types.\n\nFinally, be sure to fill in the `component` field in your story metadata:\n\n```ts\nimport { InfoButton } from './InfoButton.vue';\n\nexport default {\n  title: 'InfoButton',\n  component: InfoButton,\n};\n```\n\n## MDX\n\n[MDX](../docs/mdx.md) is a convenient way to document your components in Markdown and embed documentation components, such as stories and props tables, inline.\n\nDocs has peer dependencies on `react`. If you want to write stories in MDX, you may need to add this dependency as well:\n\n```sh\nyarn add -D react\n```\n\nThen update your `.storybook/main.js` to make sure you load MDX files:\n\n```js\nexport default {\n  stories: ['../src/stories/**/*.stories.@(js|mdx)'],\n};\n```\n\nFinally, you can create MDX files like this:\n\n```md\nimport { Meta, Story, ArgsTable } from '@storybook/addon-docs';\nimport { InfoButton } from './InfoButton.vue';\n\n<Meta title='InfoButton' component={InfoButton} />\n\n# InfoButton\n\nSome **markdown** description, or whatever you want.\n\n<Story name='basic' height='400px'>{{\n  components: { InfoButton },\n  template: '<info-button label=\"I\\'m a button!\"/>',\n}}</Story>\n\n## ArgsTable\n\n<ArgsTable of={InfoButton} />\n```\n\nYes, it's redundant to declare `component` twice. [Coming soon](https://github.com/storybookjs/storybook/issues/8685).\n\n## Inline Stories\n\nStorybook Docs renders all Vue stories inline by default.\n\nHowever, you can render stories in an iframe, with a default height of `60px` (configurable using the `docs.story.iframeHeight` story parameter), by using the `docs.stories.inline` parameter.\n\nTo do so for all stories, update `.storybook/preview.js`:\n\n```js\nexport const parameters = { docs: { story: { inline: false } } };\n```\n\n## More resources\n\nWant to learn more? Here are some more articles on Storybook Docs:\n\n- References: [DocsPage](../docs/docspage.md) / [MDX](../docs/mdx.md) / [FAQ](../docs/faq.md) / [Recipes](../docs/recipes.md) / [Theming](../docs/theming.md) / [Props](../docs/props-tables.md)\n- Announcements: [Vision](https://medium.com/storybookjs/storybook-docs-sneak-peak-5be78445094a) / [DocsPage](https://medium.com/storybookjs/storybook-docspage-e185bc3622bf) / [MDX](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc) / [Framework support](https://medium.com/storybookjs/storybook-docs-for-new-frameworks-b1f6090ee0ea)\n- Example: [Storybook Design System](https://github.com/storybookjs/design-system)\n"
  },
  {
    "path": "code/addons/docs/docs/frameworks/VUE3.md",
    "content": "<center>\n  <img src=\"../docs/media/vue-hero.png\" width=\"100%\" />\n</center>\n\n<h1>Storybook Docs for Vue 3</h1>\n\n> migration guide: This page documents the method to configure storybook introduced recently in 5.3.0, consult the [migration guide](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md) if you want to migrate to this format of configuring storybook.\n\nStorybook Docs transforms your Storybook stories into world-class component documentation. Storybook Docs for Vue 3 supports [DocsPage](../docs/docspage.md) for auto-generated docs, and [MDX](../docs/mdx.md) for rich long-form docs.\n\nTo learn more about Storybook Docs, read the [general documentation](../README.md). To learn the Vue 3 specifics, read on!\n\n- [Installation](#installation)\n- [Preset options](#preset-options)\n- [DocsPage](#docspage)\n- [Props tables](#props-tables)\n- [MDX](#mdx)\n- [Inline Stories](#inline-stories)\n- [More resources](#more-resources)\n\n## Installation\n\nFirst add the package. Make sure that the versions for your `@storybook/*` packages match:\n\n```sh\nyarn add -D @storybook/addon-docs\n```\n\nThen add the following to your `.storybook/main.js` addons:\n\n```js\nexport default {\n  addons: ['@storybook/addon-docs'],\n};\n```\n\n## Preset options\n\nThe `addon-docs` preset for Vue has a configuration option that can be used to configure [`vue-docgen-api`](https://github.com/vue-styleguidist/vue-styleguidist/tree/dev/packages/vue-docgen-api), a tool which extracts information from Vue components. Here's an example of how to use the preset with options for Vue app:\n\n```js\nexport default {\n  addons: [\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        vueDocgenOptions: {\n          alias: {\n            '@': path.resolve(process.cwd(), 'src'),\n          },\n        },\n      },\n    },\n  ],\n};\n```\n\nThe `vueDocgenOptions` is an object for configuring `vue-docgen-api`. See [`vue-docgen-api`'s docs](https://github.com/vue-styleguidist/vue-styleguidist/tree/dev/packages/vue-docgen-api#options-docgenoptions) for available configuration options.\n\n## DocsPage\n\nWhen you [install docs](#installation) you should get basic [DocsPage](../docs/docspage.md) documentation automagically for all your stories, available in the `Docs` tab of the Storybook UI.\n\n## Props tables\n\nGetting [Props tables](../docs/props-tables.md) for your components requires a few more steps. Docs for Vue relies on [`vue-docgen-loader`](https://github.com/pocka/vue-docgen-loader). It supports `props`, `events`, and `slots` as first class prop types.\n\nFinally, be sure to fill in the `component` field in your story metadata:\n\n```ts\nimport { InfoButton } from './InfoButton.vue';\n\nexport default {\n  title: 'InfoButton',\n  component: InfoButton,\n};\n```\n\n## MDX\n\n[MDX](../docs/mdx.md) is a convenient way to document your components in Markdown and embed documentation components, such as stories and props tables, inline.\n\nDocs has peer dependencies on `react`. If you want to write stories in MDX, you may need to add this dependency as well:\n\n```sh\nyarn add -D react\n```\n\nThen update your `.storybook/main.js` to make sure you load MDX files:\n\n```js\nexport default {\n  stories: ['../src/stories/**/*.stories.@(js|mdx)'],\n};\n```\n\nFinally, you can create MDX files like this:\n\n```md\nimport { Meta, Story, ArgsTable } from '@storybook/addon-docs';\nimport { InfoButton } from './InfoButton.vue';\n\n<Meta title='InfoButton' component={InfoButton} />\n\n# InfoButton\n\nSome **markdown** description, or whatever you want.\n\n<Story name='basic' height='400px'>{{\n  components: { InfoButton },\n  template: '<info-button label=\"I\\'m a button!\"/>',\n}}</Story>\n\n## ArgsTable\n\n<ArgsTable of={InfoButton} />\n```\n\nYes, it's redundant to declare `component` twice. [Coming soon](https://github.com/storybookjs/storybook/issues/8685).\n\n## Inline Stories\n\nStorybook Docs renders all Vue stories inline by default.\n\nHowever, you can render stories in an iframe, with a default height of `60px` (configurable using the `docs.story.iframeHeight` story parameter), by using the `docs.stories.inline` parameter.\n\nTo do so for all stories, update `.storybook/preview.js`:\n\n```js\nexport const parameters = { docs: { story: { inline: false } } };\n```\n\n## More resources\n\nWant to learn more? Here are some more articles on Storybook Docs:\n\n- References: [DocsPage](../docs/docspage.md) / [MDX](../docs/mdx.md) / [FAQ](../docs/faq.md) / [Recipes](../docs/recipes.md) / [Theming](../docs/theming.md) / [Props](../docs/props-tables.md)\n- Announcements: [Vision](https://medium.com/storybookjs/storybook-docs-sneak-peak-5be78445094a) / [DocsPage](https://medium.com/storybookjs/storybook-docspage-e185bc3622bf) / [MDX](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc) / [Framework support](https://medium.com/storybookjs/storybook-docs-for-new-frameworks-b1f6090ee0ea)\n- Example: [Storybook Design System](https://github.com/storybookjs/design-system)\n"
  },
  {
    "path": "code/addons/docs/docs/frameworks/WEB_COMPONENTS.md",
    "content": "<h1>Storybook Docs for Web Components</h1>\n\n- [Installation](#installation)\n- [Props tables](#props-tables)\n- [Stories not inline](#stories-not-inline)\n- [More resources](#more-resources)\n\n## Installation\n\n- Be sure to check the [installation section of the general addon-docs page](../README.md) before proceeding.\n- Be sure to have a [custom-elements.json](./#custom-elementsjson) file.\n- Add to your `.storybook/preview.js`\n\n  ```js\n  import { setCustomElementsManifest } from '@storybook/web-components';\n  import customElements from '../custom-elements.json';\n\n  setCustomElementsManifest(customElements);\n  ```\n\n- Add to your story files\n\n  ```js\n  export default {\n    title: 'Demo Card',\n    component: 'your-component-name', // which is also found in the `custom-elements.json`\n  };\n  ```\n\n## Props tables\n\nIn order to get [Props tables](..docs/../../docs/props-tables.md) documentation for web-components you will need to have a [custom-elements.json](https://github.com/webcomponents/custom-elements-json) file.\n\nYou can hand write it or better generate it. Depending on the web components sugar you are choosing your mileage may vary.\n\nKnown analyzers that output `custom-elements.json` v1.0.0:\n\n- [@custom-elements-manifest/analyzer](https://github.com/open-wc/custom-elements-manifest)\n  - Supports Vanilla, LitElement, FASTElement, Stencil, Catalyst, Atomico\n\nKnown analyzers that output older versions of `custom-elements.json`:\n\n- [web-component-analyzer](https://github.com/runem/web-component-analyzer)\n  - Supports LitElement, Polymer, Vanilla, (Stencil)\n- [stenciljs](https://stenciljs.com/)\n  - Supports Stencil (but does not have all metadata)\n\nTo generate this file with Stencil, add `docs-vscode` to outputTargets in `stencil.config.ts`:\n\n```\n{\n  type: 'docs-vscode',\n  file: 'custom-elements.json'\n},\n```\n\nThe file looks something like this:\n\n```json\n{\n  \"schemaVersion\": \"1.0.0\",\n  \"readme\": \"\",\n  \"modules\": [\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/my-element.js\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"description\": \"\",\n          \"name\": \"MyElement\",\n          \"members\": [\n            {\n              \"kind\": \"field\",\n              \"name\": \"disabled\"\n            },\n            {\n              \"kind\": \"method\",\n              \"name\": \"fire\"\n            }\n          ],\n          \"events\": [\n            {\n              \"name\": \"disabled-changed\",\n              \"type\": {\n                \"text\": \"Event\"\n              }\n            }\n          ],\n          \"superclass\": {\n            \"name\": \"HTMLElement\"\n          },\n          \"tagName\": \"my-element\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"my-element\",\n          \"declaration\": {\n            \"name\": \"MyElement\",\n            \"module\": \"src/my-element.js\"\n          }\n        }\n      ]\n    }\n  ]\n}\n```\n\nFor a full example see the [web-components-kitchen-sink/custom-elements.json](../../../examples/web-components-kitchen-sink/custom-elements.json).\n\n## Stories not inline\n\nStorybook Docs renders all web components stories inline by default.\n\nHowever, you can render stories in an iframe, with a default height of `60px` (configurable using the `docs.story.iframeHeight` story parameter), by using the `docs.stories.inline` parameter.\n\nTo do so for all stories, update `.storybook/preview.js`:\n\n```js\nexport const parameters = { docs: { story: { inline: false } } };\n```\n\n## More resources\n\nWant to learn more? Here are some more articles on Storybook Docs:\n\n- References: [DocsPage](../docs/docspage.md) / [MDX](../docs/mdx.md) / [FAQ](../docs/faq.md) / [Recipes](../docs/recipes.md) / [Theming](../docs/theming.md) / [Props](../docs/props-tables.md)\n- Announcements: [Vision](https://medium.com/storybookjs/storybook-docs-sneak-peak-5be78445094a) / [DocsPage](https://medium.com/storybookjs/storybook-docspage-e185bc3622bf) / [MDX](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc) / [Framework support](https://medium.com/storybookjs/storybook-docs-for-new-frameworks-b1f6090ee0ea)\n- Example: [Storybook Design System](https://github.com/storybookjs/design-system)\n"
  },
  {
    "path": "code/addons/docs/docs/mdx.md",
    "content": "<center>\n  <img src=\"https://raw.githubusercontent.com/storybookjs/storybook/master/addons/docs/docs/media/mdx-hero.png\" width=\"100%\" />\n</center>\n\n<h1>Storybook Docs MDX</h1>\n\n`MDX` is the syntax [Storybook Docs](../README.md) uses to capture long-form markdown documentation and stories in one file. You can also write pure documentation pages in `MDX` and add them to Storybook alongside your stories.\n\n- [Basic example](#basic-example)\n- [MDX-Flavored CSF](#mdx-flavored-csf)\n- [Writing stories](#writing-stories)\n- [Embedding stories](#embedding-stories)\n- [Decorators and parameters](#decorators-and-parameters)\n- [Documentation-only MDX](#documentation-only-mdx)\n- [MDX file names](#mdx-file-names)\n- [More resources](#more-resources)\n\n## Basic example\n\nLet's get started with an example that combines markdown with a single story:\n\n```md\nimport { Meta, Story, Canvas } from '@storybook/addon-docs';\nimport { Checkbox } from './Checkbox';\n\n<Meta title=\"MDX/Checkbox\" component={Checkbox} />\n\n# Checkbox\n\nWith `MDX` we can define a story for `Checkbox` right in the middle of our\nmarkdown documentation.\n\n<Canvas>\n  <Story name=\"all checkboxes\">\n    <form>\n      <Checkbox id=\"Unchecked\" label=\"Unchecked\" />\n      <Checkbox id=\"Checked\" label=\"Checked\" checked />\n      <Checkbox appearance=\"secondary\" id=\"second\" label=\"Secondary\" checked />\n    </form>\n  </Story>\n</Canvas>\n```\n\nAnd here's how that's rendered in Storybook:\n\n<center>\n  <img src=\"https://raw.githubusercontent.com/storybookjs/storybook/master/addons/docs/docs/media/mdx-simple.png\" width=\"100%\" />\n</center>\n\nAs you can see there's a lot going on here. We're writing Markdown, we're writing JSX, and somehow we're also defining Storybook stories that are drop-in compatible with the entire Storybook ecosystem.\n\nLet's break it down.\n\n## MDX-Flavored CSF\n\n[MDX](https://mdxjs.com/) is a standard file format that combines Markdown with JSX. This means you can use Markdown’s terse syntax (such as `# heading`) for your documentation, and freely embed JSX component blocks at any point in the file.\n\nMDX-flavored [Component Story Format (CSF)](https://medium.com/storybookjs/component-story-format-66f4c32366df) includes a collection of components called **\"Doc Blocks\"**, that allow Storybook to translate MDX files into storybook stories. MDX-defined stories are identical to regular Storybook stories, so they can be used with Storybook's entire ecosystem of addons and view layers.\n\nFor example, here's the story from `Checkbox` example above, rewritten in CSF:\n\n```js\nimport React from 'react';\nimport { Checkbox } from './Checkbox';\nexport default { title: \"MDX/Checkbox\" component: Checkbox };\nexport const allCheckboxes = () => (\n  <form>\n    <Checkbox id=\"Unchecked\" label=\"Unchecked\" />\n    <Checkbox id=\"Checked\" label=\"Checked\" checked />\n    <Checkbox appearance=\"secondary\" id=\"second\" label=\"Secondary\" checked />\n  </form>\n);\n```\n\nThere's a one-to-one mapping from the code in `MDX` to `CSF`, which in turn directly corresponds to Storybook's internal `storiesOf` API. As a user, this means your existing Storybook knowledge should translate between the three. And technically, this means that the transformations that happen under the hood are simple and predictable.\n\n## Writing stories\n\nNow let's look at a more realistic example to see a few more things we can do:\n\n```md\nimport { Meta, Story, Canvas } from '@storybook/addon-docs';\n\nimport { Badge } from './Badge';\nimport { Icon } from './Icon';\n\n<Meta title=\"MDX/Badge\" component={Badge} />\n\n# Badge\n\nLet's define a story for our `Badge` component:\n\n<Story name=\"positive\">\n  <Badge status=\"positive\">Positive</Badge>\n</Story>\n\nWe can drop it in a `Canvas` to get a code snippet:\n\n<Canvas>\n  <Story name=\"negative\">\n    <Badge status=\"negative\">Negative</Badge>\n  </Story>\n</Canvas>\n\nWe can even preview multiple stories in a block. This\ngets rendered as a group, but defines individual stories\nwith unique URLs and isolated snapshot tests.\n\n<Canvas>\n  <Story name=\"warning\">\n    <Badge status=\"warning\">Warning</Badge>\n  </Story>\n  <Story name=\"neutral\">\n    <Badge status=\"neutral\">Neutral</Badge>\n  </Story>\n  <Story name=\"error\">\n    <Badge status=\"error\">Error</Badge>\n  </Story>\n  <Story name=\"with icon\">\n    <Badge status=\"warning\">\n      <Icon icon=\"check\" inline />\n      with icon\n    </Badge>\n  </Story>\n</Canvas>\n```\n\nAnd here's how that gets rendered in Storybook:\n\n<center>\n  <img src=\"https://raw.githubusercontent.com/storybookjs/storybook/master/addons/docs/docs/media/mdx-page.png\" width=\"100%\" />\n</center>\n\n## Embedding stories\n\nSuppose you have an existing story and want to embed it into your docs. Here's how to show a story with ID `some--id` (check the browser URL in Storybook v5+ to see a story's ID):\n\n```md\nimport { Story } from \"@storybook/addon-docs\";\n\n# Some header\n\nAnd markdown here\n\n<Story id=\"some--id\" />\n```\n\nYou can also use the rest of the MDX features in conjunction with embedding. That includes source, preview, and prop tables.\n\n## Decorators and parameters\n\nTo add [decorators](https://storybook.js.org/docs/writing-stories/decorators) and [parameters](https://storybook.js.org/docs/writing-stories/parameters) in MDX:\n\n```md\n<Meta\n  title='MyComponent'\n  decorators={[ ... ]}\n  parameters={{ ... }}\n/>\n\n<Story name=\"story\" decorators={[ ... ]} parameters={{ ... }} >\n...\n</Story>\n```\n\nIn addition, global decorators work just like before, e.g. adding the following to your `.storybook/preview.js`:\n\n```js\nimport { addDecorator, addParameters } from '@storybook/react';\n\naddDecorator(...);\naddParameters({ ... });\n```\n\n## Documentation-only MDX\n\nTypically, when you use Storybook MDX, you define stories in the MDX documentation is automatically associated with those stories. But what if you want to write Markdown-style documentation and have it show up in your Storybook?\n\nIf you don't define stories in your MDX, you can write MDX documentation and associate it with an existing story, or embed that MDX as its own documentation node in your Storybook's navigation.\n\nIf you don't define a `Meta`, you can write Markdown and associate with an existing story. See [\"CSF Stories with MDX Docs\"](recipes.md#csf-stories-with-mdx-docs).\n\nTo get a \"documentation-only story\", in your UI, define a `<Meta>` as you normally would, but don't define any stories. It will show up in your UI as a documentation node:\n\n<center>\n  <img src=\"https://raw.githubusercontent.com/storybookjs/storybook/master/addons/docs/docs/media/mdx-documentation-only.png\" width=\"100%\" />\n</center>\n\n## MDX file names\n\nUnless you use a custom webpack configuration, all of your `MDX` files should have the suffix `*.stories.mdx`. This tells Storybook to apply its special processing to the `<Meta>` and `<Story>` elements in the file.\n\nBe sure to update your Storybook config file to load `.stories.mdx` stories, as per the [`addon-docs` installation instructions](../README.md#installation).\n\n## More resources\n\n- References: [README](../README.md) / [DocsPage](docspage.md) / [MDX](mdx.md) / [FAQ](faq.md) / [Recipes](recipes.md) / [Theming](theming.md) / [Props](props-tables.md)\n- Framework-specific docs: [React](../react/README.md) / [Vue 3](../vue3/README.md) / [Angular](../angular/README.md) / [Web components](../web-components/README.md) / [Ember](../ember/README.md)\n- Announcements: [Vision](https://medium.com/storybookjs/storybook-docs-sneak-peak-5be78445094a) / [DocsPage](https://medium.com/storybookjs/storybook-docspage-e185bc3622bf) / [MDX](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc) / [Framework support](https://medium.com/storybookjs/storybook-docs-for-new-frameworks-b1f6090ee0ea)\n- Example: [Storybook Design System](https://github.com/storybookjs/design-system)\n"
  },
  {
    "path": "code/addons/docs/docs/multiframework.md",
    "content": "<h1>Storybook Docs framework dev guide</h1>\n\nStorybook Docs [provides basic support for all non-RN Storybook view layers](../README.md#framework-support) out of the box. However, some frameworks have been docs-optimized, adding features like automatic props table generation and inline story rendering. This document is a dev guide for how to optimize a new framework in docs.\n\n- [Framework-specific configuration](#framework-specific-configuration)\n- [Arg tables](#arg-tables)\n- [Component descriptions](#component-descriptions)\n- [Inline story rendering](#inline-story-rendering)\n- [Dynamic source rendering](#dynamic-source-rendering)\n- [More resources](#more-resources)\n\n## Framework-specific configuration\n\nYour framework might need framework-specific configuration. This could include adding extra webpack loaders or global decorators/story parameters.\n\nAddon-docs handles this kind of customization by file naming convention. Its [common preset](https://github.com/storybookjs/storybook/blob/next/addons/docs/src/frameworks/common/preset.ts) does this by looking for files `../<framework>/{preset,config}.[tj]sx?`, where `<framework>` is the framework identifier, e.g. `vue3`, `angular`, `react`, etc.\n\nFor example, consider Storybook Docs for Vue, which needs `vue-docgen-loader` in its webpack config, and also has custom extraction functions for [props tables](#props-tables) and [component descriptions](#component-descriptions).\n\nFor webpack configuration, Docs for Vue defines [preset.ts](https://github.com/storybookjs/storybook/blob/next/addons/docs/src/frameworks/vue/preset.ts), which follows the [preset](https://storybook.js.org/docs/vue/api/presets) file structure:\n\n```\nexport function webpack(webpackConfig: any = {}, options: any = {}) {\n  webpackConfig.module.rules.push({\n    test: /\\.vue$/,\n    loader: 'vue-docgen-loader',\n    enforce: 'post',\n  });\n  return webpackConfig;\n}\n```\n\nThis appends `vue-docgen-loader` to the existing configuration, which at this point will also include modifications made by the common preset.\n\nFor props tables and descriptions, both of which are described in more detail below, it defines a file [config.jsx](https://github.com/storybookjs/storybook/blob/next/addons/docs/src/frameworks/vue/config.jsx).\n\n## Arg tables\n\nEach framework can auto-generate ArgTables by exporting one or more `ArgType` enhancers, which extracts a component's properties into a common data structure.\n\nHere's how it's done in Vue's framework-specific `preview.js`:\n\n```js\nimport { enhanceArgTypes } from './enhanceArgTypes';\n\nexport const argTypesEnhancers = [enhanceArgTypes];\n```\n\nThe `enhanceArgTypes`function takes a `StoryContext` (including the story id, parameters, args, argTypes, etc.), and returns an updated [`ArgTypes` object](https://github.com/storybookjs/storybook/blob/master/lib/addons/src/types.ts#L38-L47):\n\n```ts\nexport interface ArgType {\n  name?: string;\n  description?: string;\n  defaultValue?: any;\n  [key: string]: any;\n}\n\nexport interface ArgTypes {\n  [key: string]: ArgType;\n}\n```\n\nFor more information on what this generation looks like, see the [controls generation docs](https://github.com/storybookjs/storybook/blob/next/addons/controls/README.md#my-controls-arent-being-auto-generated-what-should-i-do).\n\nFor React and Vue, the extraction works as follows:\n\n- A webpack loader is added to the user's config via the preset\n- The loader annotates the component with a field, `__docgenInfo`, which contains some metadata\n- The view-layer specific `enhanceArgTypes` function translates that metadata into `ArgTypes`\n\nFor Angular, Web components, and Ember, the extraction works as follows:\n\n- Read JSON file in the user's `.storybook/preview.json` and story it into a global variable\n- The view-layer specific `enhanceArgTypes` function translates that metadata into `ArgTypes`\n\nHowever, for your framework you may want to implement this in some other way.\n\n## Component descriptions\n\nComponent descriptions are enabled by the `docs.extractComponentDescription` parameter, which extract's a component description (usually from source code comments) into a markdown string.\n\nIt follows the pattern of [Arg tables](#arg-tables) above, only it's even simpler because the function output is simply a string (or null if there no description).\n\n## Inline story rendering\n\nInline story rendering is another framework specific optimization, made possible by the `docs.prepareForInline` parameter.\n\nAgain let's look at Vue's framework-specific `preview.js`:\n\n```js\nimport toReact from '@egoist/vue-to-react';\n\naddParameters({\n  docs: {\n    // `container`, `page`, etc. here\n    prepareForInline: (storyFn, { args }) => {\n      const Story = toReact(storyFn());\n      return <Story {...args} />;\n    },\n  },\n});\n```\n\nThe input is the story function and the story context (id, parameters, args, etc.), and the output is a React element, because we render docs pages in react. In the case of Vue, all of the work is done by the `@egoist/vue-to-react` library. If there's no analogous library for your framework, you may need to figure it out yourself!\n\n## Dynamic source rendering\n\nWith the release of Storybook 6.0, we've improved how stories are rendered in the [`Source` doc block](https://storybook.js.org/docs/api/doc-blocks/doc-block-source). One of such improvements is the `dynamic` source type, which renders a snippet based on the output the story function.\n\nThis dynamic rendering is framework-specific, meaning it needs a custom implementation for each framework.\n\nLet's take a look at the React framework implementation of `dynamic` snippets as a reference for implementing this feature in other frameworks:\n\n```tsx\nimport { StoryContext, addons } from '@storybook/preview-api';\nimport { SNIPPET_RENDERED } from '../../shared';\n\nexport const jsxDecorator = (storyFn: any, context: StoryContext) => {\n  const story = storyFn();\n\n  // We only need to render JSX if the source block is actually going to\n  // consume it. Otherwise it's just slowing us down.\n  if (skipJsxRender(context)) {\n    return story;\n  }\n\n  const channel = addons.getChannel();\n\n  const options = {}; // retrieve from story parameters\n  const jsx = renderJsx(story, options);\n\n  const { id, args } = context;\n  channel.emit(SNIPPET_RENDERED, { id, args, source: jsx });\n\n  return story;\n};\n```\n\nA few key points from the above snippet:\n\n- The **renderJsx** function call is responsible for transforming the output of a story function into a string specific to the framework (in this case React).\n- The returned snippet string is emitted on Storybook's channel through **channel.emit()** and subsequently consumed up by the Source block for any given story, if it exists.\n\n<div class=\"aside\">\n To learn more and see how it's implemented in context, check out <a href=\"https://github.com/storybookjs/storybook/blob/next/addons/docs/src/frameworks/react/jsxDecorator.tsx\">the code</a> .\n</div>\n\nNow we need a way to configure how it's displayed in the UI:\n\n```tsx\nimport { jsxDecorator } from './jsxDecorator';\n\nexport const decorators = [jsxDecorator];\n```\n\nThis configures the `jsxDecorator` to be run on every story.\n\n<div class=\"aside\">\n To learn more and see how it's implemented in context, check out <a href=\"https://github.com/storybookjs/storybook/blob/next/addons/docs/src/frameworks/react/jsxDecorator.tsx\">the code</a> .\n</div>\n\n## More resources\n\n- References: [README](../README.md) / [DocsPage](docspage.md) / [MDX](mdx.md) / [FAQ](faq.md) / [Recipes](recipes.md) / [Theming](theming.md) / [Props](props-tables.md)\n- Framework-specific docs: [React](../react/README.md) / [Vue 3](../vue3/README.md) / [Angular](../angular/README.md) / [Web components](../web-components/README.md) / [Ember](../ember/README.md)\n- Announcements: [Vision](https://medium.com/storybookjs/storybook-docs-sneak-peak-5be78445094a) / [DocsPage](https://medium.com/storybookjs/storybook-docspage-e185bc3622bf) / [MDX](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc) / [Framework support](https://medium.com/storybookjs/storybook-docs-for-new-frameworks-b1f6090ee0ea)\n- Example: [Storybook Design System](https://github.com/storybookjs/design-system)\n"
  },
  {
    "path": "code/addons/docs/docs/props-tables.md",
    "content": "<center>\n  <img src=\"./media/props-tables-hero.png\" width=\"100%\" />\n</center>\n\n<h1>Storybook Docs Props Tables</h1>\n\nStorybook Docs automatically generates props tables for components in supported frameworks. This document is a consolidated summary of prop tables, provides instructions for reporting bugs, and list known limitations for each framework.\n\n- [Usage](#usage)\n  - [DocsPage](#docspage)\n  - [MDX](#mdx)\n- [Controls](#controls)\n- [Customization](#customization)\n  - [Customizing ArgTypes](#customizing-argtypes)\n- [Reporting a bug](#reporting-a-bug)\n- [Known limitations](#known-limitations)\n- [More resources](#more-resources)\n\n## Usage\n\nFor framework-specific setup instructions, see the framework's README: [React](../react/README.md), [Vue3](../vue3/README.md), [Angular](../angular/README.md), [Web Components](../web-components/README.md), [Ember](../ember/README.md).\n\n### DocsPage\n\nTo use the props table in [DocsPage](./docspage.md), simply export a component property on your stories metadata:\n\n```js\n// MyComponent.stories.js\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  title: 'MyComponent',\n  component: MyComponent,\n};\n// stories etc...\n```\n\n### MDX\n\nTo use the props table in [MDX](./mdx.md), use the `ArgsTable` block:\n\n```js\n// MyComponent.stories.mdx\nimport { ArgsTable } from '@storybook/addon-docs';\nimport { MyComponent } from './MyComponent';\n\n# My Component!\n\n<ArgsTable of={MyComponent} />\n```\n\n## Controls\n\nStarting in SB 6.0, the `ArgsTable` block has built-in `Controls` (formerly known as \"knobs\") for editing stories dynamically.\n\n<center>\n  <img src=\"./media/args-controls.gif\" width=\"80%\" />\n</center>\n\n<br/>\n\nThese controls are implemented to appear automatically in the props table when your story accepts [Storybook Args](https://storybook.js.org/docs/api/csf#args-story-inputs) as its input. This is done slightly differently depending on whether you're using `DocsPage` or `MDX`.\n\n**DocsPage.** In [DocsPage](./docspage.md), simply write your story to consume args and the auto-generated props table will display controls in the right-most column:\n\n```js\nexport default {\n  title: 'MyComponent',\n  component: MyComponent,\n};\n\nexport const WithControls = (args) => <MyComponent {...args} />;\n```\n\n**MDX.** In [MDX](./mdx.md), the `ArgsTable` controls are more configurable than in DocsPage. In order to show controls, `ArgsTable` must be a function of a story, not a component:\n\n```js\n<Story name=\"WithControls\">\n  {args => <MyComponent {...args} />}\n</Story>\n\n<ArgsTable story=\"Controls\" />\n```\n\nFor a very detailed walkthrough of how to write stories that use controls, read the [documentation](https://storybook.js.org/docs/essentials/controls).\n\n## Customization\n\nProps tables are automatically inferred from your components and stories, but sometimes it's useful to customize the results.\n\nProps tables are rendered from an internal data structure called `ArgTypes`. When you declare a story's `component` metadata, Docs automatically extracts `ArgTypes` based on the component's properties.\n\nYou can can customize what's shown in the props table by [customizing the `ArgTypes` data](#customizing-argtypes). This is currently available for `DocsPage` and `<ArgsTable story=\"xxx\">` construct, but not for the `<ArgsTable of={component} />` construct,\n\n### Customizing ArgTypes\n\n> **NOTE:** This API is experimental and may change outside of the typical semver release cycle\n\nWhen you declare a `component` in for your `DocsPage` [as described above](#docspage) or use the `<ArgsTable story=\"xxx\" />` construct [in MDX](#controls), the props table shows the `story.argTypes` that gets extracted by Storybook.\n\nConsider the following input:\n\n```js\n// Button.js\nimport React from 'react';\nimport PropTypes from 'prop-types';\n\nexport const Button = ({ label }) => <button>{label}</button>;\nButton.propTypes = {\n  /** Demo description */\n  label: PropTypes.string,\n};\nButton.defaultProps = {\n  label: 'Hello',\n};\n\n// Button.stories.js\nexport default { title: 'Button', component: Button };\n```\n\nThis generates the equivalent of following in-memory data structure for the `Button` component:\n\n```js\nconst argTypes = {\n  label: {\n    name: 'label',\n    type: { name: 'string', required: false },\n    defaultValue: 'Hello',\n    description: 'demo description',\n    table: {\n      type: { summary: 'string' },\n      defaultValue: { summary: 'Hello' },\n    }\n    control: {\n      type: 'text'\n    }\n  }\n}\n```\n\nIn this `ArgTypes` data structure, `name`, `type`, `defaultValue`, and `description` are standard fields in all `ArgTypes` (analogous to `PropTypes` in React). The `table` and `control` fields are addon-specific annotations. So, for example, the `table` annotation provides extra information to customize how `label` gets rendered, and the `control` annotation provides extra information for the control for editing the property.\n\nAs a user, you can customize the prop table by selectively overriding these values. Consider the following modification to `Button.stories.js` from above:\n\n```js\nexport default {\n  title: 'Button',\n  component: Button,\n  argTypes: {\n    label: {\n      description: 'overwritten description',\n      table: {\n        type: { summary: 'something short', detail: 'something really really long' },\n      },\n      control: {\n        type: null,\n      },\n    },\n  },\n};\n```\n\nThese values--`description`, `table.type`, and `controls.type`--get merged over the defaults that are extracted by Storybook. The final merged values would be:\n\n```js\nconst argTypes = {\n  label: {\n    name: 'label',\n    type: { name: 'string', required: false },\n    defaultValue: 'Hello',\n    description: 'overwritten description',\n    table: {\n      type: { summary: 'something short', detail: 'something really really long' },\n      defaultValue: { summary: 'Hello' },\n    }\n    control: {\n      type: null\n    }\n  }\n}\n```\n\nThis would render a row with a modified description, a type display with a dropdown that shows the detail, and no control.\n\n> **NOTE:** `@storybook/addon-docs` provide shorthand for common tasks:\n>\n> - `type: 'number'` is shorthand for `type: { name: 'number' }`\n> - `control: 'radio'` is shorthand for `control: { type: 'radio' }`\n\nControls customization has an entire section in the [documentation](https://storybook.js.org/docs/essentials/controls#configuration).\n\nHere are the possible customizations for the rest of the prop table:\n\n| Field                        | Description                                                                                    |\n| ---------------------------- | ---------------------------------------------------------------------------------------------- |\n| `name`                       | The name of the property                                                                       |\n| `type.required`              | Whether or not the property is required                                                        |\n| `description`                | A markdown description for the property                                                        |\n| `table.type.summary`         | A short version of the type                                                                    |\n| `table.type.detail`          | A longer version of the type (if it's a complex type)                                          |\n| `table.defaultValue.summary` | A short version of the default value                                                           |\n| `table.defaultValue.detail`  | A longer version of the default value (if it's a complex value)                                |\n| `control`                    | See [`addon-controls` README](https://storybook.js.org/docs/essentials/controls#configuration) |\n\n## Reporting a bug\n\nExtracting component properties from source is a tricky problem with thousands of corner cases. We've designed this package and its tests to accurately isolate problems, since the cause could either be in this package or (likely) one of the packages it depends on.\n\nIf you're seeing a problem with your prop table, here's what to do.\n\nFirst, look to see if there's already a test case that corresponds to your situation. If there is, it should be documented in the [Known Limitations](#known-limitations) section below. There should also be one or more corresponding test fixtures contained in this package. For example, if you are using React, look under the directory `./src/frameworks/react/__testfixtures__`.\n\nIf your problem is not already represented here, do the following:\n\n1. Create a **MINIMAL** repro for your problem. Each case should be just a few lines of code.\n2. Place it in the appropriate directory `./src/frameworks/<framework>/__testfixtures__/`, e.g. `./src/frameworks/react/__testfixtures__/XXXX-some-description`, where `XXXX` is the corresponding github issue.\n3. Run the tests for your `<framework>`, e.g. `yarn jest --testPathPattern=react-properties.test.ts --watch`\n4. Inspect the output files for your test case.\n5. Add the example to the appropriate stories file, e.g. `react-properties.stories.ts` for `react`, for a visual repro\n\nIf the problem appears to be an issue with this library, file an issue and include a PR that includes your repro.\n\nIf the problem appears to be an issue with the sub-package, please file an issue on the appropriate sub-package, document the limitation in [Known Limitations](#known-limitations) below, link to that issue, and submit a PR including the updated documentation and fixtures/snapshots.\n\n## Known limitations\n\nThis package relies on a variety of sub-packages to extract property information from components. Many of the bugs in this package correspond to bugs in a sub-package. Since we don't maintain the sub-packages, the best we can do for now is (1) document these limitations, (2) provide clean reproductions to the sub-package, (3) optionally provide PRs to those packages to fix the problems.\n\n| Framework      | Underlying library                       | Docs                                             | Open issues                                                                                                                                                        |\n| -------------- | ---------------------------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| React          | `react-docgen` `react-docgen-typescript` | [Docs](../react/README.md#props-tables)          | [Open issues](https://github.com/storybookjs/storybook/issues?q=is%3Aopen+is%3Aissue+label%3A%22block%3A+props%22+label%3Abug+label%3A%22app%3A+react%22)          |\n| Vue 3          | `vue-docgen-api`                         | [Docs](../vue3/README.md#props-tables)           | [Open issues](https://github.com/storybookjs/storybook/issues?q=is%3Aopen+is%3Aissue+label%3A%22block%3A+props%22+label%3Abug+label%3A%22vue3%22)                  |\n| Angular        | `compodoc`                               | [Docs](../angular/README.md#props-tables)        | [Open issues](https://github.com/storybookjs/storybook/issues?q=is%3Aopen+is%3Aissue+label%3A%22block%3A+props%22+label%3Abug+label%3A%22app%3A+angular%22)        |\n| Web-components | `custom-elements.json`                   | [Docs](../web-components/README.md#props-tables) | [Open issues](https://github.com/storybookjs/storybook/issues?q=is%3Aopen+is%3Aissue+label%3A%22block%3A+props%22+label%3Abug+label%3A%22app%3A+web-components%22) |\n| Ember          | `yui-doc`                                | [Docs](../ember/README.md#props-tables)          | [Open issues](https://github.com/storybookjs/storybook/issues?q=is%3Aopen+is%3Aissue+label%3A%22block%3A+props%22+label%3Abug+label%3A%22app%3A+ember%22)          |\n\n## More resources\n\n- References: [README](../README.md) / [DocsPage](docspage.md) / [MDX](mdx.md) / [FAQ](faq.md) / [Recipes](recipes.md) / [Theming](theming.md) / [Props](props-tables.md)\n- Framework-specific docs: [React](../react/README.md) / [Vue 3](../vue3/README.md) / [Angular](../angular/README.md) / [Web components](../web-components/README.md) / [Ember](../ember/README.md)\n- Announcements: [Vision](https://medium.com/storybookjs/storybook-docs-sneak-peak-5be78445094a) / [DocsPage](https://medium.com/storybookjs/storybook-docspage-e185bc3622bf) / [MDX](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc) / [Framework support](https://medium.com/storybookjs/storybook-docs-for-new-frameworks-b1f6090ee0ea)\n- Example: [Storybook Design System](https://github.com/storybookjs/design-system)\n"
  },
  {
    "path": "code/addons/docs/docs/recipes.md",
    "content": "<h1>Storybook Docs Recipes</h1>\n\n[Storybook Docs](../README.md) consists of two basic mechanisms, [DocsPage](docspage.md) and [MDX](mdx.md). But how should you use them in your project?\n\n- [Component Story Format (CSF) with DocsPage](#component-story-format-csf-with-docspage)\n- [Pure MDX Stories](#pure-mdx-stories)\n- [CSF Stories with MDX Docs](#csf-stories-with-mdx-docs)\n- [CSF Stories with arbitrary MDX](#csf-stories-with-arbitrary-mdx)\n- [Mixing storiesOf with CSF/MDX](#mixing-storiesof-with-csfmdx)\n- [Migrating from notes/info addons](#migrating-from-notesinfo-addons)\n- [Exporting documentation](#exporting-documentation)\n- [Disabling docs stories](#disabling-docs-stories)\n  - [DocsPage](#docspage)\n  - [MDX Stories](#mdx-stories)\n- [Controlling a story's view mode](#controlling-a-storys-view-mode)\n- [Reordering Docs tab first](#reordering-docs-tab-first)\n- [Customizing source snippets](#customizing-source-snippets)\n- [Overwriting docs container](#overwriting-docs-container)\n- [Add description to individual stories](#add-description-to-individual-stories)\n- [More resources](#more-resources)\n\n## Component Story Format (CSF) with DocsPage\n\nStorybook's [Component Story Format (CSF)](https://medium.com/storybookjs/component-story-format-66f4c32366df) is a convenient, portable way to write stories. [DocsPage](docspage.md) is a convenient, zero-config way to get rich docs for CSF stories. Using these together is a primary use case for Storybook Docs.\n\nIf you want to intersperse longform documentation in your Storybook, for example to include an introductory page at the beginning of your storybook with an explanation of your design system and installation instructions, [Documentation-only MDX](mdx.md#documentation-only-mdx) is a good way to achieve this.\n\n## Pure MDX Stories\n\n[MDX](mdx.md) is an alternative syntax to CSF that allows you to co-locate your stories and your documentation. Everything you can do in CSF, you can do in MDX. And if you're consuming it in [Webpack](https://webpack.js.org/), it exposes an _identical_ interface, so the two files are interchangeable. Some teams will choose to write all of their Storybook in MDX and never look back.\n\n## CSF Stories with MDX Docs\n\nPerhaps you want to write your stories in CSF, but document them in MDX? Here's how to do that:\n\n**Button.stories.js**\n\n```js\nimport React from 'react';\nimport { Button } from './Button';\n\n// NOTE: no default export since `Button.stories.mdx` is the story file for `Button` now\n//\n// export default {\n//   title: 'Demo/Button',\n//   component: Button,\n// };\n\nexport const basic = () => <Button>Basic</Button>;\nbasic.parameters = {\n  foo: 'bar',\n};\n```\n\n**Button.stories.mdx**\n\n```md\nimport { Meta, Story } from '@storybook/addon-docs';\nimport \\* as stories from './Button.stories.js';\nimport { Button } from './Button';\nimport { SomeComponent } from 'path/to/SomeComponent';\n\n<Meta title=\"Demo/Button\" component={Button} />\n\n# Button\n\nI can define a story with the function imported from CSF:\n\n<Story story={stories.basic} />\n\nAnd I can also embed arbitrary markdown & JSX in this file.\n\n<SomeComponent prop1=\"val1\" />\n```\n\nWhat's happening here:\n\n- Your stories are defined in CSF, but because of `includeStories: []`, they are not actually added to Storybook.\n- The named story exports are annotated with story-level decorators, parameters, args, and the `<Story story={}>` construct respects this.\n- All component-level decorators, parameters, etc. from `Button.stories` default export must be manually copied over into `<Meta>` if desired.\n\n## CSF Stories with arbitrary MDX\n\nWe recommend [MDX Docs](#csf-stories-with-mdx-docs) as the most ergonomic way to annotate CSF stories with MDX. There's also a second option if you want to annotate your CSF with arbitrary markdown:\n\n**Button.mdx**\n\n```md\nimport { Story } from '@storybook/addon-docs';\nimport { SomeComponent } from 'somewhere';\n\n# Button\n\nI can embed a story (but not define one, since this file should not contain a `Meta`):\n\n<Story id=\"some--id\" />\n\nAnd I can also embed arbitrary markdown & JSX in this file.\n\n<SomeComponent prop1=\"val1\" />\n```\n\n**Button.stories.js**\n\n```js\nimport React from 'react';\nimport { Button } from './Button';\nimport mdx from './Button.mdx';\n\nexport default {\n  title: 'Demo/Button',\n  parameters: {\n    docs: {\n      page: mdx,\n    },\n  },\n  component: Button,\n};\nexport const basic = () => <Button>Basic</Button>;\n```\n\nNote that in contrast to other examples, the MDX file suffix is `.mdx` rather than `.stories.mdx`. This key difference means that the file will be loaded with the default MDX loader rather than Storybook's CSF loader, which has several implications:\n\n1. You shouldn't provide a `Meta` declaration.\n2. You can refer to existing stories (i.e. `<Story id=\"...\">`) but cannot define new stories (i.e. `<Story name=\"...\">`).\n3. The documentation gets exported as the default export (MDX default) rather than as a parameter hanging off the default export (CSF).\n\n## Mixing storiesOf with CSF/MDX\n\nYou might have a collection of stories using the `storiesOf` API and want to add CSF/MDX piecemeal. Or you might have certain stories that are only possible with the `storiesOf` API (e.g. dynamically generated ones)\n\nSo how do you mix these two types? The first argument to `configure` can be a `require.context \"req\"`, an array of `req's`, or a `loader function`. The loader function should either return null or an array of module exports that include the default export. The default export is used by `configure` to load CSF/MDX files.\n\nSo here's a naive implementation of a loader function that assumes that none of your `storiesOf` files contains a default export, and filters out those exports:\n\n```js\nconst loadFn = () => {\n  const req = require.context('../src', true, /\\.stories\\.js$/);\n  return req\n    .keys()\n    .map((fname) => req(fname))\n    .filter((exp) => !!exp.default);\n};\n\nconfigure(loadFn, module);\n```\n\nWe could have baked this heuristic into Storybook, but we can't assume that your `storiesOf` files don't have default exports. If they do, you can filter them some other way (e.g. by file name).\n\nIf you don't filter out those files, you'll see the following error:\n\n> \"Loader function passed to 'configure' should return void or an array of module exports that all contain a 'default' export\"\n\nWe made this error explicit to make sure you know what you're doing when you mix `storiesOf` and CSF/MDX.\n\n## Migrating from notes/info addons\n\nIf you're currently using the notes/info addons, you can upgrade to DocsPage by providing a custom `docs.extractComponentDescription` parameter. There are different ways to use each addon, so you can adapt this recipe according to your use case.\n\nSuppose you've added a `notes` parameter to each component in your library, containing markdown text, and you want that to show up at the top of the page in the `Description` slot. You could do that by adding the following snippet to `.storybook/preview.js`:\n\n```js\nimport { addParameters } from '@storybook/preview-api';\n\naddParameters({\n  docs: {\n    extractComponentDescription: (component, { notes }) => {\n      if (notes) {\n        return typeof notes === 'string' ? notes : notes.markdown || notes.text;\n      }\n      return null;\n    },\n  },\n});\n```\n\nThe default `extractComponentDescription` provided by the docs preset extracts JSDoc code comments from the component source, and ignores the second argument, which is the story parameters of the currently-selected story. In contrast, the code snippet above ignores the comment and uses the notes parameter for that story.\n\n## Exporting documentation\n\n> ⚠️ The `--docs` flag is an experimental feature in Storybook 5.2. The behavior may change in 5.3 outside of the normal semver rules. Be forewarned!\n\nThe Storybook UI is a workshop for developing components in isolation. Storybook Docs is a showcase for documenting your components. During component/docs development, it’s useful to see both of these modes side by side. But when you export your static storybook, you might want to export the docs to reduce clutter.\n\nTo address this, we’ve added a CLI flag to only export the docs. This flag is also available in dev mode:\n\n```sh\nyarn storybook build --docs\n```\n\n## Disabling docs stories\n\nThere are two cases where a user might wish to exclude stories from their documentation pages:\n\n### DocsPage\n\nUser defines stories in CSF and renders docs using DocsPage, but wishes to exclude some fo the stories from the DocsPage to reduce noise on the page.\n\n```js\nexport const foo = () => <Button>foo</Button>;\nfoo.parameters = { docs: { disable: true } };\n```\n\n### MDX Stories\n\nUser writes documentation & stories side-by-side in a single MDX file, and wants those stories to show up in the canvas but not in the docs themselves. They want something similar to the recipe \"CSF stories with MDX docs\" but want to do everything in MDX:\n\n```mdx\n<Story name=\"foo\" parameters={{ docs: { disable: true } }}>\n  <Button>foo</Button>\n</Story>\n```\n\n## Controlling a story's view mode\n\nStorybook's default story navigation behavior is to preserve the existing view mode. In other words, if a user is viewing a story in \"docs\" mode, and clicks on another story, they will navigate to the other story in \"docs\" mode. If they are viewing a story in \"story\" mode (i.e. \"canvas\" in the UI) they will navigate to another story in \"story\" mode (with the exception of \"docs-only\" pages, which are always shown in \"docs\" mode).\n\nBased on user feedback, it's also possible to control the view mode for an individual story using the `viewMode` story parameter. In the following example, the nav link will always set the view mode to story:\n\n```js\nexport const Foo = () => <Component />;\nFoo.parameters = {\n  // reset the view mode to \"story\" whenever the user navigates to this story\n  viewMode: 'story',\n};\n```\n\nThis can also be applied globally in `.storybook/preview.js`:\n\n```js\n// always reset the view mode to \"docs\" whenever the user navigates\nexport const parameters = {\n  viewMode: 'docs',\n};\n```\n\n## Reordering Docs tab first\n\nYou can configure Storybook's preview tabs with the `previewTabs` story parameter.\n\nHere's how to show the `Docs` tab first for a story (or globally in `.storybook/preview.js`):\n\n```js\nexport const Foo = () => <Component />;\nFoo.parameters = {\n  previewTabs: { 'storybook/docs/panel': { index: -1 } },\n};\n```\n\n## Customizing source snippets\n\nAs of SB 6.0, there are two ways to customize how Docs renders source code, via story parameter or via a formatting function.\n\nIf you override the `docs.source.code` parameter, the `Source` block will render whatever string is added:\n\n```js\nconst Example = () => <Button />;\nExample.parameters = {\n  docs: { source: { code: 'some arbitrary string' } },\n};\n```\n\nAlternatively, you can provide a function or an async function in the `docs.source.transform` parameter. For example, the following snippet in `.storybook/preview.js` globally removes the arrow at the beginning of a function that returns a string:\n\n```js\nconst SOURCE_REGEX = /^\\(\\) => `(.*)`$/;\nexport const parameters = {\n  docs: {\n    source: {\n      transform: (src, storyContext) => {\n        const match = SOURCE_REGEX.exec(src);\n        return match ? match[1] : src;\n      },\n    },\n  },\n};\n```\n\nThese two methods are complementary. The former is useful for story-specific, and the latter is useful for global formatting.\n\n## Overwriting docs container\n\nWhat happens if you want to add some wrapper for your MDX page, or add some other kind of React context?\n\nWhen you're writing stories you can do this by adding a [decorator](https://storybook.js.org/docs/writing-stories/decorators), but when you're adding arbitrary JSX to your MDX documentation outside of a `<Story>` block, decorators no longer apply, and you need to use the `docs.container` parameter.\n\nThe closest Docs equivalent of a decorator is the `container`, a wrapper element that is rendered around the page that is being rendered. Here's an example of adding a solid red border around the page. It uses Storybook's default page container (that sets up various contexts and other magic) and then inserts its own logic between that container and the contents of the page:\n\n```js\nimport { Meta, DocsContainer } from '@storybook/addon-docs';\n\n<Meta\n  title=\"Addons/Docs/container-override\"\n  parameters={{\n    docs: {\n      container: ({ children, context }) => (\n        <DocsContainer context={context}>\n          <div style={{ border: '5px solid red' }}>{children}</div>\n        </DocsContainer>\n      ),\n    },\n  }}\n/>\n\n# Title\n\nRest of your file...\n```\n\nThis is especially useful if you are using `styled-components` and need to wrap your JSX with a `ThemeProvider` to have access to your theme:\n\n```js\nimport { Meta, DocsContainer } from '@storybook/addon-docs';\nimport { ThemeProvider } from 'styled-components'\nimport { theme } from '../path/to/theme'\n\n<Meta\n  title=\"Addons/Docs/container-override\"\n  parameters={{\n    docs: {\n      container: ({ children, context }) => (\n        <DocsContainer context={context}>\n          <ThemeProvider theme={theme}>\n            {children}\n          </ThemeProvider>\n        </DocsContainer>\n      ),\n    },\n  }}\n/>\n\n# Title\n\nRest of your file...\n```\n\n## Add description to individual stories\n\nAdd `story` to `docs.description` parameter\n\n```js\nconst Example = () => <Button />;\n\nExample.parameters = {\n  docs: {\n    description: {\n      story: 'Individual story description, may contain `markdown` markup',\n    },\n  },\n};\n```\n\nThere is also an webpack loader package that extracts descriptions from jsdoc comments [story-description-loader](https://www.npmjs.com/package/story-description-loader)\n\n## More resources\n\n- References: [README](../README.md) / [DocsPage](docspage.md) / [MDX](mdx.md) / [FAQ](faq.md) / [Recipes](recipes.md) / [Theming](theming.md) / [Props](props-tables.md)\n- Framework-specific docs: [React](../react/README.md) / [Vue 3](../vue3/README.md) / [Angular](../angular/README.md) / [Web components](../web-components/README.md) / [Ember](../ember/README.md)\n- Announcements: [Vision](https://medium.com/storybookjs/storybook-docs-sneak-peak-5be78445094a) / [DocsPage](https://medium.com/storybookjs/storybook-docspage-e185bc3622bf) / [MDX](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc) / [Framework support](https://medium.com/storybookjs/storybook-docs-for-new-frameworks-b1f6090ee0ea)\n- Example: [Storybook Design System](https://github.com/storybookjs/design-system)\n"
  },
  {
    "path": "code/addons/docs/docs/theming.md",
    "content": "<h1>Storybook Docs Theming</h1>\n\n[Storybook Docs](../README.md) is themable! There are three different levels of theming, just to keep things interesting:\n\n- [Storybook theming](#storybook-theming)\n- [CSS escape hatches](#css-escape-hatches)\n- [MDX component overrides](#mdx-component-overrides)\n- [More resources](#more-resources)\n\n## Storybook theming\n\nStorybook theming is the **recommended way** to theme your docs. Docs uses the same theme system as [Storybook UI](https://storybook.js.org/docs/configure/user-interface/theming), but is themed independently from the main UI.\n\nSupposing you have a Storybook theme defined for the main UI in `.storybook/manager.js`:\n\n```js\n// or a custom theme\nimport { themes } from '@storybook/theming';\nimport { addons } from '@storybook/manager-api';\n\naddons.setConfig({\n  theme: themes.dark,\n});\n```\n\nHere's how you'd specify the same theme for docs in `.storybook/preview.js`:\n\n```js\nimport { themes } from '@storybook/theming';\n\n// or global addParameters\nexport const parameters = {\n  docs: {\n    theme: themes.dark,\n  },\n};\n```\n\n## CSS escape hatches\n\nThe Storybook theme API is narrow by design. If you want to have fine-grained control over the CSS, all of the Docs components are tagged with class names to make this possible. This is advanced usage: use at your own risk.\n\nThe classes correspond to markdown elements (e.g. `sbdocs-title`, `sbdocs-subtitle`, `sbdocs-p`, etc.) to UI elements on the page (e.g. `sbdocs-container`, `sbdocs-content`, etc.). To see the currently available classes, use \"inspect element\" in your browser.\n\nYou can style these classes in `.storybook/preview-head.html`. For example, here's how to make the content wider for UHD displays:\n\n```html\n<style>\n  .sbdocs.sbdocs-content {\n    max-width: 1440px;\n  }\n</style>\n```\n\n> NOTE: All of these elements also have the `sbdocs` class, which is an idiomatic way of increasing the CSS specificity so you don't have to use `!important`.\n\n## MDX component overrides\n\nIf you're using MDX, there's one more level of themability. MDX allows you to [completely override the components](https://mdxjs.com/advanced/components) that are rendered from markdown using a `components` parameter. This is an advanced usage that we don't officially support in Storybook, but it's a powerful mechanism if you need it.\n\nHere's how you might insert a custom code renderer for `code` blocks on the page, in `.storybook/preview.js`:\n\n```js\nimport { addParameters } from '@storybook/react';\nimport { CodeBlock } from './CodeBlock';\n\naddParameters({\n  docs: {\n    components: {\n      code: CodeBlock,\n    },\n  },\n});\n```\n\nYou can even override a Storybook _block_ component.\n\nHere's how you might insert a custom `<Preview />` block:\n\n```js\nimport { MyPreview } from './MyPreview';\n\naddParameters({\n  docs: {\n    components: {\n      Preview: MyPreview,\n    },\n  },\n});\n```\n\n## More resources\n\n- References: [README](../README.md) / [DocsPage](docspage.md) / [MDX](mdx.md) / [FAQ](faq.md) / [Recipes](recipes.md) / [Theming](theming.md) / [Props](props-tables.md)\n- Framework-specific docs: [React](../react/README.md) / [Vue 3](../vue3/README.md) / [Angular](../angular/README.md) / [Web components](../web-components/README.md) / [Ember](../ember/README.md)\n- Announcements: [Vision](https://medium.com/storybookjs/storybook-docs-sneak-peak-5be78445094a) / [DocsPage](https://medium.com/storybookjs/storybook-docspage-e185bc3622bf) / [MDX](https://medium.com/storybookjs/rich-docs-with-storybook-mdx-61bc145ae7bc) / [Framework support](https://medium.com/storybookjs/storybook-docs-for-new-frameworks-b1f6090ee0ea)\n- Example: [Storybook Design System](https://github.com/storybookjs/design-system)\n"
  },
  {
    "path": "code/addons/docs/manager.js",
    "content": "export * from './dist/manager.js';\n"
  },
  {
    "path": "code/addons/docs/package.json",
    "content": "{\n  \"name\": \"@storybook/addon-docs\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook Docs: Document UI components automatically with stories and MDX\",\n  \"keywords\": [\n    \"docs\",\n    \"documentation\",\n    \"storybook\",\n    \"storybook-addon\",\n    \"essentials\",\n    \"organize\",\n    \"MDX\",\n    \"markdown\",\n    \"autodocs\",\n    \"styleguide\",\n    \"style guide\",\n    \"component\",\n    \"components\",\n    \"react\",\n    \"vue\",\n    \"angular\",\n    \"svelte\",\n    \"web-components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/addons/docs\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/addons/docs\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./angular\": {\n      \"types\": \"./dist/angular/index.d.ts\",\n      \"code\": \"./src/angular/index.ts\",\n      \"default\": \"./dist/angular/index.js\"\n    },\n    \"./blocks\": {\n      \"types\": \"./dist/blocks.d.ts\",\n      \"code\": \"./src/blocks.ts\",\n      \"default\": \"./dist/blocks.js\"\n    },\n    \"./ember\": {\n      \"types\": \"./dist/ember/index.d.ts\",\n      \"code\": \"./src/ember/index.ts\",\n      \"default\": \"./dist/ember/index.js\"\n    },\n    \"./manager\": \"./dist/manager.js\",\n    \"./mdx-loader\": \"./dist/mdx-loader.js\",\n    \"./mdx-react-shim\": {\n      \"types\": \"./dist/mdx-react-shim.d.ts\",\n      \"code\": \"./src/mdx-react-shim.ts\",\n      \"default\": \"./dist/mdx-react-shim.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\",\n    \"./preview\": {\n      \"types\": \"./dist/preview.d.ts\",\n      \"code\": \"./src/preview.ts\",\n      \"default\": \"./dist/preview.js\"\n    },\n    \"./web-components\": {\n      \"types\": \"./dist/web-components/index.d.ts\",\n      \"code\": \"./src/web-components/index.ts\",\n      \"default\": \"./dist/web-components/index.js\"\n    }\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@mdx-js/react\": \"^3.0.0\",\n    \"@storybook/csf-plugin\": \"workspace:*\",\n    \"@storybook/icons\": \"^2.0.1\",\n    \"@storybook/react-dom-shim\": \"workspace:*\",\n    \"react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"ts-dedent\": \"^2.0.0\"\n  },\n  \"devDependencies\": {\n    \"@mdx-js/mdx\": \"^3.0.0\",\n    \"@rollup/pluginutils\": \"^5.0.2\",\n    \"@types/color-convert\": \"^2.0.0\",\n    \"@types/react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"color-convert\": \"^2.0.1\",\n    \"es-toolkit\": \"^1.43.0\",\n    \"github-slugger\": \"^2.0.0\",\n    \"markdown-to-jsx\": \"^7.7.2\",\n    \"memoizerific\": \"^1.11.3\",\n    \"polished\": \"^4.2.2\",\n    \"react\": \"^18.2.0\",\n    \"react-colorful\": \"^5.1.2\",\n    \"react-dom\": \"^18.2.0\",\n    \"rehype-external-links\": \"^3.0.0\",\n    \"rehype-slug\": \"^6.0.0\",\n    \"telejson\": \"8.0.0\",\n    \"tocbot\": \"^4.20.1\",\n    \"typescript\": \"^5.9.3\",\n    \"vite\": \"^7.0.4\"\n  },\n  \"peerDependencies\": {\n    \"storybook\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\",\n  \"storybook\": {\n    \"displayName\": \"Docs\",\n    \"icon\": \"https://user-images.githubusercontent.com/263385/101991672-48355c80-3c7c-11eb-82d9-95fa12438f64.png\",\n    \"unsupportedFrameworks\": [\n      \"react-native\"\n    ]\n  }\n}\n"
  },
  {
    "path": "code/addons/docs/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/addons/docs/preview.js",
    "content": "export * from './dist/preview.js';\n"
  },
  {
    "path": "code/addons/docs/project.json",
    "content": "{\n  \"name\": \"addon-docs\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/addons/docs/src/DocsRenderer.tsx",
    "content": "import type { PropsWithChildren } from 'react';\nimport React, { Component } from 'react';\n\nimport type {\n  DocsContextProps,\n  DocsRenderFunction,\n  Parameters,\n  Renderer,\n} from 'storybook/internal/types';\n\nimport { renderElement, unmountElement } from '@storybook/react-dom-shim';\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore (these types only work once the package is compiled)\nimport { AnchorMdx, CodeOrSourceMdx, Docs, HeadersMdx } from '@storybook/addon-docs/blocks';\n\n// TS doesn't like that we export a component with types that it doesn't know about (TS4203)\nexport const defaultComponents: Record<string, any> = {\n  code: CodeOrSourceMdx,\n  a: AnchorMdx,\n  ...HeadersMdx,\n};\n\nclass ErrorBoundary extends Component<\n  PropsWithChildren<{\n    showException: (err: Error) => void;\n  }>\n> {\n  state = { hasError: false };\n\n  static getDerivedStateFromError() {\n    return { hasError: true };\n  }\n\n  componentDidCatch(err: Error) {\n    const { showException } = this.props;\n    showException(err);\n  }\n\n  render() {\n    const { hasError } = this.state;\n    const { children } = this.props;\n\n    return hasError ? null : <>{children}</>;\n  }\n}\n\nexport class DocsRenderer<TRenderer extends Renderer> {\n  public render: DocsRenderFunction<TRenderer>;\n\n  public unmount: (element: HTMLElement) => void;\n\n  constructor() {\n    this.render = async (\n      context: DocsContextProps<TRenderer>,\n      docsParameter: Parameters,\n      element: HTMLElement\n    ): Promise<void> => {\n      const components = {\n        ...defaultComponents,\n        ...docsParameter?.components,\n      };\n\n      const TDocs = Docs as typeof Docs<TRenderer>;\n\n      return new Promise((resolve, reject) => {\n        import('@mdx-js/react')\n          .then(({ MDXProvider }) =>\n            // We use a `key={}` here to reset the `hasError` state each time we render ErrorBoundary\n            renderElement(\n              <ErrorBoundary showException={reject} key={Math.random()}>\n                <MDXProvider components={components}>\n                  <TDocs context={context} docsParameter={docsParameter} />\n                </MDXProvider>\n              </ErrorBoundary>,\n              element\n            )\n          )\n          .then(() => resolve());\n      });\n    };\n\n    this.unmount = (element: HTMLElement) => {\n      unmountElement(element);\n    };\n  }\n}\n"
  },
  {
    "path": "code/addons/docs/src/angular/index.ts",
    "content": "export const setCompodocJson = (compodocJson: any) => {\n  // @ts-expect-error (Converted from ts-ignore)\n  globalThis.__STORYBOOK_COMPODOC_JSON__ = compodocJson;\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Anchor.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Anchor } from './Anchor';\n\nconst meta = {\n  component: Anchor,\n  parameters: {\n    layout: 'fullscreen',\n    docsStyles: true,\n  },\n} as Meta<typeof Anchor>;\n\nexport default meta;\n\nexport const Default: StoryObj<typeof Anchor> = {\n  args: {\n    children: 'This is an anchor for storyId: \"default\"',\n    storyId: 'default',\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Anchor.tsx",
    "content": "import type { FC, PropsWithChildren } from 'react';\nimport React from 'react';\n\nexport const anchorBlockIdFromId = (storyId: string) => `anchor--${storyId}`;\n\nexport interface AnchorProps {\n  storyId: string;\n}\n\nexport const Anchor: FC<PropsWithChildren<AnchorProps>> = ({ storyId, children }) => (\n  <div id={anchorBlockIdFromId(storyId)} className=\"sb-anchor\">\n    {children}\n  </div>\n);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/ArgTypes.stories.tsx",
    "content": "import React from 'react';\n\nimport type { PlayFunctionContext } from 'storybook/internal/csf';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { within } from 'storybook/test';\n\nimport * as ExampleStories from '../examples/ArgTypesParameters.stories';\nimport * as SubcomponentsExampleStories from '../examples/ArgTypesWithSubcomponentsParameters.stories';\nimport { ArgTypes } from './ArgTypes';\n\nconst meta: Meta<typeof ArgTypes> = {\n  title: 'Blocks/ArgTypes',\n  component: ArgTypes,\n  parameters: {\n    layout: 'fullscreen',\n    relativeCsfPaths: [\n      '../examples/ArgTypesParameters.stories',\n      '../examples/ArgTypesWithSubcomponentsParameters.stories',\n    ],\n    docsStyles: true,\n  },\n};\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {};\n\nexport const OfComponent: Story = {\n  args: {\n    of: ExampleStories.default.component,\n  },\n};\n\nexport const OfMeta: Story = {\n  args: {\n    of: ExampleStories.default,\n  },\n};\n\nexport const OfStory: Story = {\n  args: {\n    of: ExampleStories.NoParameters,\n  },\n};\n\nexport const OfUndefined: Story = {\n  args: {\n    // @ts-expect-error this is supposed to be undefined\n    of: ExampleStories.NotDefined,\n  },\n  parameters: { chromatic: { disableSnapshot: true } },\n  tags: ['!test'],\n};\n\nexport const OfStoryUnattached: Story = {\n  parameters: { attached: false },\n  args: {\n    of: ExampleStories.NoParameters,\n  },\n};\n\nexport const IncludeProp: Story = {\n  args: {\n    of: ExampleStories.NoParameters,\n    include: ['a'],\n  },\n};\n\nexport const IncludeParameter: Story = {\n  args: {\n    of: ExampleStories.Include,\n  },\n};\n\nexport const ExcludeProp: Story = {\n  args: {\n    of: ExampleStories.NoParameters,\n    exclude: ['a'],\n  },\n};\n\nexport const ExcludeParameter: Story = {\n  args: {\n    of: ExampleStories.Exclude,\n  },\n};\n\nexport const SortProp: Story = {\n  args: {\n    of: ExampleStories.NoParameters,\n    sort: 'alpha',\n  },\n};\n\nexport const SortParameter: Story = {\n  args: {\n    of: ExampleStories.Sort,\n  },\n};\n\nexport const Categories: Story = {\n  args: {\n    of: ExampleStories.Categories,\n  },\n};\n\nconst findSubcomponentTabs = async (\n  canvas: ReturnType<typeof within>,\n  step: PlayFunctionContext['step']\n) => {\n  let subcomponentATab: HTMLElement | null = null;\n  let subcomponentBTab: HTMLElement | null = null;\n  await step('should have tabs for the subcomponents', async () => {\n    subcomponentATab = await canvas.findByText('SubcomponentA');\n    subcomponentBTab = await canvas.findByText('SubcomponentB');\n  });\n  return { subcomponentATab, subcomponentBTab };\n};\n\nexport const SubcomponentsOfMeta: Story = {\n  args: {\n    of: SubcomponentsExampleStories.default,\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    await findSubcomponentTabs(canvas, step);\n  },\n};\n\nexport const SubcomponentsOfStory: Story = {\n  ...SubcomponentsOfMeta,\n  args: {\n    of: SubcomponentsExampleStories.NoParameters,\n  },\n};\n\nexport const SubcomponentsIncludeProp: Story = {\n  args: {\n    of: SubcomponentsExampleStories.NoParameters,\n    include: ['a', 'f'],\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const { subcomponentBTab } = await findSubcomponentTabs(canvas, step);\n    if (subcomponentBTab) {\n      await (subcomponentBTab as HTMLElement & { click: () => Promise<void> }).click();\n    }\n  },\n};\n\nexport const SubcomponentsExcludeProp: Story = {\n  ...SubcomponentsIncludeProp,\n  args: {\n    of: SubcomponentsExampleStories.NoParameters,\n    exclude: ['a', 'c', 'f', 'g'],\n  },\n};\n\nexport const SubcomponentsSortProp: Story = {\n  ...SubcomponentsIncludeProp,\n  args: {\n    of: SubcomponentsExampleStories.NoParameters,\n    sort: 'alpha',\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/ArgTypes.tsx",
    "content": "/* eslint-disable react/destructuring-assignment */\nimport type { FC } from 'react';\nimport React from 'react';\n\nimport type { Parameters, Renderer, StrictArgTypes } from 'storybook/internal/csf';\nimport type { ArgTypesExtractor } from 'storybook/internal/docs-tools';\nimport type { ModuleExports } from 'storybook/internal/types';\n\nimport type { PropDescriptor } from 'storybook/preview-api';\nimport { filterArgTypes } from 'storybook/preview-api';\n\nimport type { SortType } from '../components';\nimport { ArgsTableError, ArgsTable as PureArgsTable, TabbedArgsTable } from '../components';\nimport { useOf } from './useOf';\nimport { getComponentName } from './utils';\nimport { withMdxComponentOverride } from './with-mdx-component-override';\n\ntype ArgTypesParameters = {\n  include?: PropDescriptor;\n  exclude?: PropDescriptor;\n  sort?: SortType;\n};\n\ntype ArgTypesProps = ArgTypesParameters & {\n  of?: Renderer['component'] | ModuleExports;\n};\nfunction extractComponentArgTypes(\n  component: Renderer['component'],\n  parameters: Parameters\n): StrictArgTypes {\n  const { extractArgTypes }: { extractArgTypes: ArgTypesExtractor } = parameters.docs || {};\n  if (!extractArgTypes) {\n    throw new Error(ArgsTableError.ARGS_UNSUPPORTED);\n  }\n  return extractArgTypes(component) as StrictArgTypes;\n}\n\nfunction getArgTypesFromResolved(resolved: ReturnType<typeof useOf>) {\n  if (resolved.type === 'component') {\n    const {\n      component,\n      projectAnnotations: { parameters },\n    } = resolved;\n    return {\n      argTypes: extractComponentArgTypes(component, parameters as Parameters),\n      parameters,\n      component,\n    };\n  }\n\n  if (resolved.type === 'meta') {\n    const {\n      preparedMeta: { argTypes, parameters, component, subcomponents },\n    } = resolved;\n    return { argTypes, parameters, component, subcomponents };\n  }\n\n  // In the case of the story, the enhanceArgs argTypeEnhancer has already added the extracted\n  // arg types from the component to the prepared story.\n  const {\n    story: { argTypes, parameters, component, subcomponents },\n  } = resolved;\n  return { argTypes, parameters, component, subcomponents };\n}\n\nconst ArgTypesImpl: FC<ArgTypesProps> = (props) => {\n  const { of } = props;\n  if ('of' in props && of === undefined) {\n    throw new Error('Unexpected `of={undefined}`, did you mistype a CSF file reference?');\n  }\n  const resolved = useOf(of || 'meta');\n  const { argTypes, parameters, component, subcomponents } = getArgTypesFromResolved(resolved);\n  const argTypesParameters = parameters?.docs?.argTypes || ({} as ArgTypesParameters);\n\n  const include = props.include ?? argTypesParameters.include;\n  const exclude = props.exclude ?? argTypesParameters.exclude;\n  const sort = props.sort ?? argTypesParameters.sort;\n\n  const filteredArgTypes = filterArgTypes(argTypes, include, exclude);\n\n  const hasSubcomponents = Boolean(subcomponents) && Object.keys(subcomponents || {}).length > 0;\n\n  if (!hasSubcomponents) {\n    return <PureArgsTable rows={filteredArgTypes as any} sort={sort} />;\n  }\n\n  const mainComponentName = getComponentName(component) || 'Main';\n  const subcomponentTabs = Object.fromEntries(\n    Object.entries(subcomponents || {}).map(([key, comp]) => [\n      key,\n      {\n        rows: filterArgTypes(\n          extractComponentArgTypes(comp, parameters as Parameters),\n          include,\n          exclude\n        ),\n        sort,\n      },\n    ])\n  );\n  const tabs = {\n    [mainComponentName]: { rows: filteredArgTypes, sort },\n    ...subcomponentTabs,\n  };\n  return <TabbedArgsTable tabs={tabs as any} sort={sort} />;\n};\n\nexport const ArgTypes = withMdxComponentOverride('ArgTypes', ArgTypesImpl);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Canvas.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { dedent } from 'ts-dedent';\n\nimport * as ButtonStories from '../examples/Button.stories';\nimport * as ParameterStories from '../examples/CanvasParameters.stories';\nimport * as SourceParameterStories from '../examples/SourceParameters.stories';\nimport { Canvas } from './Canvas';\nimport SourceStoriesMeta from './Source.stories';\n\nconst meta: Meta<typeof Canvas> = {\n  component: Canvas,\n  parameters: {\n    layout: 'fullscreen',\n    relativeCsfPaths: [\n      '../examples/Button.stories',\n      '../examples/CanvasParameters.stories',\n      '../examples/SourceParameters.stories',\n    ],\n    snippets: {\n      'storybook-blocks-example-button--primary': {\n        code: dedent`\n          <Button\n            label=\"Button\"\n            onClick={() => {}}\n            primary={true}\n          />`,\n      },\n    },\n    docsStyles: true,\n  },\n  decorators: SourceStoriesMeta.decorators,\n};\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const OfAttached: Story = {\n  args: {\n    of: ButtonStories.Primary,\n  },\n};\n\nexport const OfUnattached: Story = {\n  args: {\n    of: ButtonStories.Primary,\n  },\n  parameters: { attached: false },\n};\n\nexport const OfError: Story = {\n  args: {\n    of: ButtonStories.ErrorStory,\n  },\n};\n\nexport const DefaultAttached: Story = {};\n\nexport const OfUndefined: Story = {\n  args: {\n    // @ts-expect-error this is supposed to be undefined\n    of: ButtonStories.NotDefined,\n  },\n  parameters: { chromatic: { disableSnapshot: true } },\n  tags: ['!test'],\n};\n\nexport const PropWithToolbar: Story = {\n  name: 'Prop withToolbar = true',\n  args: {\n    of: ButtonStories.Primary,\n    withToolbar: true,\n  },\n};\n\nexport const PropAdditionalActions: Story = {\n  name: 'Prop additionalActions = [ ... ]',\n  args: {\n    of: ButtonStories.Primary,\n    additionalActions: [\n      {\n        title: 'Open in GitHub',\n        onClick: () => {\n          window.open(\n            'https://github.com/storybookjs/storybook/blob/next/code/lib/blocks/src/examples/Button.stories.tsx',\n            '_blank'\n          );\n        },\n      },\n      {\n        title: 'Go to documentation',\n        onClick: () => {\n          window.open('https://storybook.js.org/docs/essentials/controls#annotation', '_blank');\n        },\n      },\n    ],\n  },\n};\n\nexport const PropSourceStateShown: Story = {\n  name: 'Prop sourceState = shown',\n  args: {\n    of: ButtonStories.Primary,\n    sourceState: 'shown',\n  },\n};\n\nexport const PropSourceStateHidden: Story = {\n  name: 'Prop sourceState = hidden',\n  args: {\n    of: ButtonStories.Primary,\n    sourceState: 'hidden',\n  },\n};\n\nexport const PropSourceStateNone: Story = {\n  name: 'Prop sourceState = none',\n  args: {\n    of: ButtonStories.Primary,\n    sourceState: 'none',\n  },\n};\n\nexport const PropLayoutFullscreen: Story = {\n  name: 'Prop layout = fullscreen',\n  args: {\n    of: ButtonStories.Primary,\n    layout: 'fullscreen',\n  },\n};\n\nexport const PropLayoutCentered: Story = {\n  name: 'Prop layout = centered',\n  args: {\n    of: ButtonStories.Primary,\n    layout: 'centered',\n  },\n};\n\nexport const PropLayoutPadded: Story = {\n  name: 'Prop layout = padded',\n  args: {\n    of: ButtonStories.Primary,\n    layout: 'padded',\n  },\n};\n\nexport const PropSource: Story = {\n  name: 'Prop source = { ... }',\n  args: {\n    of: ButtonStories.Primary,\n    source: {\n      language: 'html',\n      code: '<button>           Button          </button>', // spaces should be removed by the prettier formatter\n    },\n  },\n};\n\nexport const PropIframeStory: Story = {\n  name: 'Prop story = { ..., inline: false }',\n  args: {\n    of: ButtonStories.Primary,\n    story: { inline: false, height: '200px' },\n  },\n};\n\nexport const PropAutoplayingStory: Story = {\n  name: 'Prop story = { ..., autoplay: true}',\n  args: {\n    of: ButtonStories.Clicking,\n    story: { autoplay: true },\n  },\n};\n\nconst ClassNameStoryDescription = () => (\n  <p>\n    This story sets the <code>className</code> prop on the <code>Canvas</code> to{' '}\n    <code>my-custom-classname</code>, which will propagate to the preview element. To demonstrate\n    this, it also adds a <code>style</code> tag that sets another background color for that class:\n  </p>\n);\nexport const PropClassName: Story = {\n  name: 'Prop className = my-custom-classname',\n  args: {\n    of: ButtonStories.Primary,\n    className: 'my-custom-classname',\n  },\n  render: (args) => (\n    <>\n      <ClassNameStoryDescription />\n      <style>\n        {`\n          .my-custom-classname {\n            background-color: #fd5c9355;\n          }\n        `}\n      </style>\n      <Canvas {...args} />\n    </>\n  ),\n};\n\nexport const ParameterWithToolbar: Story = {\n  name: 'parameters.docs.canvas.withToolbar = true',\n  args: {\n    of: ParameterStories.WithToolbar,\n  },\n};\n\nexport const ParameterAdditionalActions: Story = {\n  name: 'parameters.docs.canvas.additionalActions = [ ... ]',\n  args: {\n    of: ParameterStories.AdditionalActions,\n  },\n};\n\nexport const ParameterClassName: Story = {\n  name: 'parameters.docs.canvas.className = my-custom-classname',\n  args: {\n    of: ParameterStories.ClassName,\n  },\n  render: (args) => (\n    <>\n      <ClassNameStoryDescription />\n      <style>\n        {`\n          .my-custom-classname {\n            background-color: #fd5c9355;\n          }\n        `}\n      </style>\n      <Canvas {...args} />\n    </>\n  ),\n};\n\nexport const ParametersSourceStateShown: Story = {\n  name: 'parameters.docs.canvas.sourceState = shown',\n  args: {\n    of: ParameterStories.SourceStateShown,\n  },\n};\n\nexport const ParametersSourceStateHidden: Story = {\n  name: 'parameters.docs.canvas.sourceState = hidden',\n  args: {\n    of: ParameterStories.SourceStateHidden,\n  },\n};\n\nexport const ParametersSourceStateNone: Story = {\n  name: 'parameters.docs.canvas.sourceState = none',\n  args: {\n    of: ParameterStories.SourceStateNone,\n  },\n};\n\nexport const ParameterDocsCanvasLayoutFullscreen: Story = {\n  name: 'parameters.docs.canvas.layout = fullscreen',\n  args: {\n    of: ParameterStories.DocsCanvasLayoutFullscreen,\n  },\n};\n\nexport const ParameterDocsCanvasLayoutCentered: Story = {\n  name: 'parameters.docs.canvas.layout = centered',\n  args: {\n    of: ParameterStories.DocsCanvasLayoutCentered,\n  },\n};\n\nexport const ParameterDocsCanvasLayoutPadded: Story = {\n  name: 'parameters.docs.canvas.layout = padded',\n  args: {\n    of: ParameterStories.DocsCanvasLayoutPadded,\n  },\n};\n\nexport const ParameterLayoutFullscreen: Story = {\n  name: 'parameters.layout = fullscreen',\n  args: {\n    of: ParameterStories.LayoutFullscreen,\n  },\n};\n\nexport const ParameterLayoutCentered: Story = {\n  name: 'parameters.layout = centered',\n  args: {\n    of: ParameterStories.LayoutCentered,\n  },\n};\n\nexport const ParameterLayoutPadded: Story = {\n  name: 'parameters.layout = padded',\n  args: {\n    of: ParameterStories.LayoutPadded,\n  },\n};\n\nexport const ParameterSource: Story = {\n  name: 'parameters.docs.source',\n  args: {\n    of: SourceParameterStories.CodeLanguage,\n  },\n};\n\nexport const ParameterStory: Story = {\n  name: 'parameters.docs.story',\n  args: {\n    of: ParameterStories.StoryParameters,\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Canvas.tsx",
    "content": "/* eslint-disable react/destructuring-assignment */\nimport React, { useCallback, useContext } from 'react';\nimport type { FC } from 'react';\n\nimport { FORCE_REMOUNT } from 'storybook/internal/core-events';\nimport type { ModuleExport, ModuleExports } from 'storybook/internal/types';\n\nimport type { Layout, PreviewProps as PurePreviewProps } from '../components';\nimport { Preview as PurePreview } from '../components';\nimport { DocsContext } from './DocsContext';\nimport type { SourceProps } from './Source';\nimport { useSourceProps } from './Source';\nimport { SourceContext } from './SourceContainer';\nimport type { StoryProps } from './Story';\nimport { Story } from './Story';\nimport { useOf } from './useOf';\nimport { withMdxComponentOverride } from './with-mdx-component-override';\n\ntype CanvasProps = Pick<PurePreviewProps, 'withToolbar' | 'additionalActions' | 'className'> & {\n  /**\n   * Pass the export defining a story to render that story\n   *\n   * ```jsx\n   * import { Meta, Canvas } from '@storybook/addon-docs/blocks';\n   * import * as ButtonStories from './Button.stories';\n   *\n   * <Meta of={ButtonStories} />\n   * <Canvas of={ButtonStories.Primary} />\n   * ```\n   */\n  of?: ModuleExport;\n  /**\n   * Pass all exports of the CSF file if this MDX file is unattached\n   *\n   * ```jsx\n   * import { Canvas } from '@storybook/addon-docs/blocks';\n   * import * as ButtonStories from './Button.stories';\n   *\n   * <Canvas of={ButtonStories.Primary} meta={ButtonStories} />;\n   * ```\n   */\n  meta?: ModuleExports;\n  /**\n   * Specify the initial state of the source panel hidden: the source panel is hidden by default\n   * shown: the source panel is shown by default none: the source panel is not available and the\n   * button to show it is hidden\n   *\n   * @default 'hidden'\n   */\n  sourceState?: 'hidden' | 'shown' | 'none';\n  /**\n   * How to layout the story within the canvas padded: the story has padding within the canvas\n   * fullscreen: the story is rendered edge to edge within the canvas centered: the story is\n   * centered within the canvas\n   *\n   * @default 'padded'\n   */\n  layout?: Layout;\n  /** @see {SourceProps} */\n  source?: Omit<SourceProps, 'dark'>;\n  /** @see {StoryProps} */\n  story?: Pick<StoryProps, 'inline' | 'height' | 'autoplay' | '__forceInitialArgs' | '__primary'>;\n};\n\nconst CanvasImpl: FC<CanvasProps> = (props) => {\n  const docsContext = useContext(DocsContext);\n  const sourceContext = useContext(SourceContext);\n  const { of, source } = props;\n  if ('of' in props && of === undefined) {\n    throw new Error('Unexpected `of={undefined}`, did you mistype a CSF file reference?');\n  }\n\n  const { story } = useOf(of || 'story', ['story']);\n  const sourceProps = useSourceProps({ ...source, ...(of && { of }) }, docsContext, sourceContext);\n\n  const layout =\n    props.layout ?? story.parameters.layout ?? story.parameters.docs?.canvas?.layout ?? 'padded';\n  const withToolbar = props.withToolbar ?? story.parameters.docs?.canvas?.withToolbar ?? false;\n  const additionalActions =\n    props.additionalActions ?? story.parameters.docs?.canvas?.additionalActions;\n  const sourceState = props.sourceState ?? story.parameters.docs?.canvas?.sourceState ?? 'hidden';\n  const className = props.className ?? story.parameters.docs?.canvas?.className;\n  // By default, stories will be iframed, but most frameworks support inline rendering and override that in a docs entry file\n  const inline = props.story?.inline ?? story.parameters?.docs?.story?.inline ?? false;\n\n  const handleReloadStory = useCallback(() => {\n    docsContext.channel.emit(FORCE_REMOUNT, { storyId: story.id });\n  }, [docsContext.channel, story.id]);\n\n  return (\n    <PurePreview\n      withSource={sourceState === 'none' ? undefined : sourceProps}\n      isExpanded={sourceState === 'shown'}\n      withToolbar={withToolbar}\n      additionalActions={additionalActions}\n      className={className}\n      layout={layout}\n      inline={inline}\n      onReloadStory={inline ? handleReloadStory : undefined}\n    >\n      <Story of={of || story.moduleExport} meta={props.meta} {...props.story} />\n    </PurePreview>\n  );\n};\n\nexport const Canvas = withMdxComponentOverride('Canvas', CanvasImpl);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Controls.stories.tsx",
    "content": "import React from 'react';\n\nimport type { PlayFunctionContext } from 'storybook/internal/csf';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { expect, within } from 'storybook/test';\n\nimport * as ExampleStories from '../examples/ControlsParameters.stories';\nimport * as SubcomponentsExampleStories from '../examples/ControlsWithSubcomponentsParameters.stories';\nimport * as EmptyArgTypesStories from '../examples/EmptyArgTypes.stories';\nimport { Controls } from './Controls';\n\nconst meta = {\n  component: Controls,\n  parameters: {\n    layout: 'fullscreen',\n    relativeCsfPaths: [\n      '../examples/ControlsParameters.stories',\n      '../examples/EmptyArgTypes.stories',\n      '../examples/ControlsWithSubcomponentsParameters.stories',\n    ],\n    docsStyles: true,\n  },\n} satisfies Meta<typeof Controls>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {};\n\nexport const OfStory: Story = {\n  args: {\n    of: ExampleStories.NoParameters,\n  },\n};\n\n// NOTE: this will throw with no of prop\nexport const OfStoryUnattached: Story = {\n  parameters: { attached: false },\n  args: {\n    of: ExampleStories.NoParameters,\n  },\n};\n\nexport const OfUndefined: Story = {\n  args: {\n    // @ts-expect-error this is supposed to be undefined\n    of: ExampleStories.NotDefined,\n  },\n  parameters: { chromatic: { disableSnapshot: true } },\n  tags: ['!test'],\n};\n\nexport const IncludeProp: Story = {\n  args: {\n    of: ExampleStories.NoParameters,\n    include: ['a'],\n  },\n};\n\nexport const IncludeParameter: Story = {\n  args: {\n    of: ExampleStories.Include,\n  },\n};\n\nexport const ExcludeProp: Story = {\n  args: {\n    of: ExampleStories.NoParameters,\n    exclude: ['a'],\n  },\n};\n\nexport const ExcludeParameter: Story = {\n  args: {\n    of: ExampleStories.Exclude,\n  },\n};\n\nexport const SortProp: Story = {\n  args: {\n    of: ExampleStories.NoParameters,\n    sort: 'alpha',\n  },\n};\n\nexport const SortParameter: Story = {\n  args: {\n    of: ExampleStories.Sort,\n  },\n};\n\nexport const Categories: Story = {\n  args: {\n    of: ExampleStories.Categories,\n  },\n};\n\nconst findSubcomponentTabs = async (\n  canvas: ReturnType<typeof within>,\n  step: PlayFunctionContext['step']\n) => {\n  let subcomponentATab: HTMLElement | null = null;\n  let subcomponentBTab: HTMLElement | null = null;\n  await step('should have tabs for the subcomponents', async () => {\n    subcomponentATab = await canvas.findByText('SubcomponentA');\n    subcomponentBTab = await canvas.findByText('SubcomponentB');\n  });\n  return { subcomponentATab, subcomponentBTab };\n};\n\nexport const SubcomponentsOfStory: Story = {\n  args: {\n    of: SubcomponentsExampleStories.NoParameters,\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    await findSubcomponentTabs(canvas, step);\n  },\n};\n\nexport const SubcomponentsIncludeProp: Story = {\n  args: {\n    of: SubcomponentsExampleStories.NoParameters,\n    include: ['a', 'f'],\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const { subcomponentBTab } = await findSubcomponentTabs(canvas, step);\n    if (subcomponentBTab) {\n      await (subcomponentBTab as HTMLElement & { click: () => Promise<void> }).click();\n    }\n  },\n};\n\nexport const SubcomponentsExcludeProp: Story = {\n  ...SubcomponentsIncludeProp,\n  args: {\n    of: SubcomponentsExampleStories.NoParameters,\n    exclude: ['a', 'c', 'f', 'g'],\n  },\n};\n\nexport const SubcomponentsSortProp: Story = {\n  ...SubcomponentsIncludeProp,\n  args: {\n    of: SubcomponentsExampleStories.NoParameters,\n    sort: 'alpha',\n  },\n};\n\n/**\n * When a story is defined without any argTypes or args, the Docs UI should not display the control\n * component.\n */\nexport const EmptyArgTypes: Story = {\n  args: {\n    of: EmptyArgTypesStories.Default,\n  },\n};\n\n/**\n * When multiple Controls blocks for different stories are on the same docs page, each control\n * should have a unique id attribute (scoped by storyId). This verifies the fix for\n * https://github.com/storybookjs/storybook/issues/26144\n */\nexport const MultipleControlsOnSamePage: Story = {\n  render: () => (\n    <>\n      <Controls of={ExampleStories.NoParameters} />\n      <Controls of={ExampleStories.Include} />\n    </>\n  ),\n  play: async ({ canvasElement }) => {\n    const allIds = Array.from(canvasElement.querySelectorAll('[id^=\"control-\"]')).map(\n      (el) => el.id\n    );\n    const uniqueIds = new Set(allIds);\n    await expect(allIds.length).toBeGreaterThan(0);\n    await expect(uniqueIds.size).toBe(allIds.length);\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Controls.tsx",
    "content": "/* eslint-disable react/destructuring-assignment */\nimport type { FC } from 'react';\nimport React, { useContext } from 'react';\n\nimport type { Parameters, Renderer, StrictArgTypes } from 'storybook/internal/csf';\nimport type { ArgTypesExtractor } from 'storybook/internal/docs-tools';\nimport type { ModuleExports } from 'storybook/internal/types';\n\nimport { filterArgTypes } from 'storybook/preview-api';\nimport type { PropDescriptor } from 'storybook/preview-api';\n\nimport type { SortType } from '../components';\nimport { ArgsTableError, ArgsTable as PureArgsTable, TabbedArgsTable } from '../components';\nimport { DocsContext } from './DocsContext';\nimport { useArgs } from './useArgs';\nimport { useGlobals } from './useGlobals';\nimport { usePrimaryStory } from './usePrimaryStory';\nimport { getComponentName } from './utils';\nimport { withMdxComponentOverride } from './with-mdx-component-override';\n\ntype ControlsParameters = {\n  include?: PropDescriptor;\n  exclude?: PropDescriptor;\n  sort?: SortType;\n};\n\ntype ControlsProps = ControlsParameters & {\n  of?: Renderer['component'] | ModuleExports;\n};\n\nfunction extractComponentArgTypes(\n  component: Renderer['component'],\n  parameters: Parameters\n): StrictArgTypes {\n  const { extractArgTypes }: { extractArgTypes: ArgTypesExtractor } = parameters.docs || {};\n  if (!extractArgTypes) {\n    throw new Error(ArgsTableError.ARGS_UNSUPPORTED);\n  }\n  return extractArgTypes(component) as StrictArgTypes;\n}\n\nconst ControlsImpl: FC<ControlsProps> = (props) => {\n  const { of } = props;\n  const context = useContext(DocsContext);\n  const primaryStory = usePrimaryStory();\n\n  const story = of ? context.resolveOf(of, ['story']).story : primaryStory;\n\n  if (!story) {\n    return null;\n  }\n\n  const { parameters, argTypes, component, subcomponents } = story;\n  const controlsParameters = parameters.docs?.controls || ({} as ControlsParameters);\n\n  const include = props.include ?? controlsParameters.include;\n  const exclude = props.exclude ?? controlsParameters.exclude;\n  const sort = props.sort ?? controlsParameters.sort;\n\n  const [args, updateArgs, resetArgs] = useArgs(story, context);\n  const [globals] = useGlobals(story, context);\n\n  const filteredArgTypes = filterArgTypes(argTypes, include, exclude);\n\n  const hasSubcomponents = Boolean(subcomponents) && Object.keys(subcomponents || {}).length > 0;\n\n  if (!hasSubcomponents) {\n    if (!(Object.keys(filteredArgTypes).length > 0 || Object.keys(args).length > 0)) {\n      return null;\n    }\n    return (\n      <PureArgsTable\n        storyId={story.id}\n        rows={filteredArgTypes as any}\n        sort={sort}\n        args={args}\n        globals={globals}\n        updateArgs={updateArgs}\n        resetArgs={resetArgs}\n      />\n    );\n  }\n\n  const mainComponentName = getComponentName(component) || 'Story';\n  const subcomponentTabs = Object.fromEntries(\n    Object.entries(subcomponents || {}).map(([key, comp]) => [\n      key,\n      {\n        rows: filterArgTypes(extractComponentArgTypes(comp, parameters), include, exclude),\n        sort,\n      },\n    ])\n  );\n  const tabs = {\n    [mainComponentName]: { rows: filteredArgTypes, sort },\n    ...subcomponentTabs,\n  };\n  return (\n    <TabbedArgsTable\n      tabs={tabs as any}\n      sort={sort}\n      args={args}\n      globals={globals}\n      updateArgs={updateArgs}\n      resetArgs={resetArgs}\n      storyId={story.id}\n    />\n  );\n};\n\nexport const Controls = withMdxComponentOverride('Controls', ControlsImpl);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Description.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Button as ButtonComponent } from '../examples/Button';\nimport * as DefaultButtonStories from '../examples/Button.stories';\nimport * as ButtonStoriesWithMetaDescriptionAsBoth from '../examples/ButtonWithMetaDescriptionAsBoth.stories';\nimport * as ButtonStoriesWithMetaDescriptionAsComment from '../examples/ButtonWithMetaDescriptionAsComment.stories';\nimport * as ButtonStoriesWithMetaDescriptionAsParameter from '../examples/ButtonWithMetaDescriptionAsParameter.stories';\nimport { Description } from './Description';\n\nconst meta: Meta<typeof Description> = {\n  component: Description,\n  parameters: {\n    layout: 'fullscreen',\n    controls: {\n      include: [],\n    },\n    // workaround for https://github.com/storybookjs/storybook/issues/20505\n    docs: { source: { type: 'code' } },\n    attached: false,\n    docsStyles: true,\n  },\n};\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const OfComponentAsComponentComment: Story = {\n  args: {\n    of: ButtonComponent,\n  },\n  parameters: { relativeCsfPaths: ['../examples/Button.stories'] },\n};\nexport const OfCSFFileAsComponentComment: Story = {\n  args: {\n    of: DefaultButtonStories,\n  },\n  parameters: { relativeCsfPaths: ['../examples/Button.stories'] },\n};\nexport const OfCSFFileAsMetaComment: Story = {\n  args: {\n    of: ButtonStoriesWithMetaDescriptionAsComment,\n  },\n  parameters: {\n    relativeCsfPaths: ['../examples/ButtonWithMetaDescriptionAsComment.stories'],\n  },\n};\nexport const OfCSFFileAsParameter: Story = {\n  args: {\n    of: ButtonStoriesWithMetaDescriptionAsParameter,\n  },\n  parameters: {\n    relativeCsfPaths: ['../examples/ButtonWithMetaDescriptionAsParameter.stories'],\n  },\n};\nexport const OfCSFFileAsMetaCommentAndParameter: Story = {\n  args: {\n    of: ButtonStoriesWithMetaDescriptionAsBoth,\n  },\n  parameters: {\n    relativeCsfPaths: ['../examples/ButtonWithMetaDescriptionAsBoth.stories'],\n  },\n};\nexport const OfMetaAsComponentComment: Story = {\n  args: {\n    of: DefaultButtonStories.default,\n  },\n  parameters: { relativeCsfPaths: ['../examples/Button.stories'] },\n};\nexport const OfMetaAsMetaComment: Story = {\n  args: {\n    of: ButtonStoriesWithMetaDescriptionAsComment.default,\n  },\n  parameters: {\n    relativeCsfPaths: ['../examples/ButtonWithMetaDescriptionAsComment.stories'],\n  },\n};\nexport const OfMetaAsParameter: Story = {\n  args: {\n    of: ButtonStoriesWithMetaDescriptionAsParameter.default,\n  },\n  parameters: {\n    relativeCsfPaths: ['../examples/ButtonWithMetaDescriptionAsParameter.stories'],\n  },\n};\nexport const OfMetaAsMetaCommentAndParameter: Story = {\n  args: {\n    of: ButtonStoriesWithMetaDescriptionAsBoth.default,\n  },\n  parameters: {\n    relativeCsfPaths: ['../examples/ButtonWithMetaDescriptionAsBoth.stories'],\n  },\n};\nexport const OfStoryAsComment: Story = {\n  args: {\n    of: DefaultButtonStories.Primary,\n  },\n  parameters: { relativeCsfPaths: ['../examples/Button.stories'] },\n};\nexport const OfStoryAsParameter: Story = {\n  args: {\n    of: DefaultButtonStories.Secondary,\n  },\n  parameters: { relativeCsfPaths: ['../examples/Button.stories'] },\n};\nexport const OfStoryAsStoryCommentAndParameter: Story = {\n  args: {\n    of: DefaultButtonStories.Large,\n  },\n  parameters: { relativeCsfPaths: ['../examples/Button.stories'] },\n};\nexport const DefaultAttached: Story = {\n  parameters: { relativeCsfPaths: ['../examples/Button.stories'], attached: true },\n};\nexport const OfUndefinedAttached: Story = {\n  args: {\n    // @ts-expect-error this is supposed to be undefined\n    of: DefaultButtonStories.NotDefined,\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n    relativeCsfPaths: ['../examples/Button.stories'],\n    attached: true,\n  },\n  tags: ['!test'],\n};\nexport const OfStringComponentAttached: Story = {\n  name: 'Of \"component\" Attached',\n  args: {\n    of: 'component',\n  },\n  parameters: { relativeCsfPaths: ['../examples/Button.stories'], attached: true },\n};\nexport const OfStringMetaAttached: Story = {\n  name: 'Of \"meta\" Attached',\n  args: {\n    of: 'meta',\n  },\n  parameters: { relativeCsfPaths: ['../examples/Button.stories'], attached: true },\n};\nexport const OfStringStoryAttached: Story = {\n  name: 'Of \"story\" Attached',\n  args: {\n    of: 'story',\n  },\n  parameters: { relativeCsfPaths: ['../examples/Button.stories'], attached: true },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Description.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { Markdown } from './Markdown';\nimport type { Of } from './useOf';\nimport { useOf } from './useOf';\nimport { withMdxComponentOverride } from './with-mdx-component-override';\n\nexport enum DescriptionType {\n  INFO = 'info',\n  NOTES = 'notes',\n  DOCGEN = 'docgen',\n  AUTO = 'auto',\n}\n\ninterface DescriptionProps {\n  /**\n   * Specify where to get the description from. Can be a component, a CSF file or a story. If not\n   * specified, the description will be extracted from the meta of the attached CSF file.\n   */\n  of?: Of;\n}\n\nconst getDescriptionFromResolvedOf = (resolvedOf: ReturnType<typeof useOf>): string | null => {\n  switch (resolvedOf.type) {\n    case 'story': {\n      return resolvedOf.story.parameters.docs?.description?.story || null;\n    }\n    case 'meta': {\n      const { parameters, component } = resolvedOf.preparedMeta;\n      const metaDescription = parameters.docs?.description?.component;\n      if (metaDescription) {\n        return metaDescription;\n      }\n      return (\n        parameters.docs?.extractComponentDescription?.(component, {\n          component,\n          parameters,\n        }) || null\n      );\n    }\n    case 'component': {\n      const {\n        component,\n        projectAnnotations: { parameters },\n      } = resolvedOf;\n      return (\n        parameters?.docs?.extractComponentDescription?.(component, {\n          component,\n          parameters,\n        }) || null\n      );\n    }\n    default: {\n      throw new Error(\n        `Unrecognized module type resolved from 'useOf', got: ${(resolvedOf as any).type}`\n      );\n    }\n  }\n};\n\nconst DescriptionImpl: FC<DescriptionProps> = (props) => {\n  const { of } = props;\n\n  if ('of' in props && of === undefined) {\n    throw new Error('Unexpected `of={undefined}`, did you mistype a CSF file reference?');\n  }\n  const resolvedOf = useOf(of || 'meta');\n  const markdown = getDescriptionFromResolvedOf(resolvedOf);\n\n  return markdown ? <Markdown>{markdown}</Markdown> : null;\n};\n\nexport const Description = withMdxComponentOverride('Description', DescriptionImpl);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Docs.tsx",
    "content": "import React from 'react';\nimport type { ComponentType, PropsWithChildren } from 'react';\n\nimport type { Parameters, Renderer } from 'storybook/internal/types';\n\nimport type { Theme } from 'storybook/theming';\n\nimport { DocsContainer } from './DocsContainer';\nimport type { DocsContextProps } from './DocsContext';\nimport { DocsPage } from './DocsPage';\n\nexport type DocsProps<TRenderer extends Renderer = Renderer> = {\n  docsParameter: Parameters;\n  context: DocsContextProps<TRenderer>;\n};\n\nexport function Docs<TRenderer extends Renderer = Renderer>({\n  context,\n  docsParameter,\n}: DocsProps<TRenderer>) {\n  const Container: ComponentType<\n    PropsWithChildren<{ context: DocsContextProps<TRenderer>; theme: Theme }>\n  > = docsParameter.container || DocsContainer;\n\n  const Page = docsParameter.page || DocsPage;\n\n  return (\n    <Container context={context} theme={docsParameter.theme}>\n      <Page />\n    </Container>\n  );\n}\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/DocsContainer.tsx",
    "content": "import type { FC, PropsWithChildren } from 'react';\nimport React, { useEffect } from 'react';\n\nimport type { Renderer } from 'storybook/internal/types';\n\nimport type { ThemeVars } from 'storybook/theming';\nimport { ThemeProvider, ensure as ensureTheme } from 'storybook/theming';\n\nimport { DocsPageWrapper } from '../components';\nimport { TableOfContents } from '../components/TableOfContents';\nimport type { DocsContextProps } from './DocsContext';\nimport { DocsContext } from './DocsContext';\nimport { SourceContainer } from './SourceContainer';\nimport { scrollToElement } from './utils';\n\nconst { document, window: globalWindow } = globalThis;\n\nexport interface DocsContainerProps<TFramework extends Renderer = Renderer> {\n  context: DocsContextProps<TFramework>;\n  theme?: ThemeVars;\n}\n\nexport const DocsContainer: FC<PropsWithChildren<DocsContainerProps>> = ({\n  context,\n  theme,\n  children,\n}) => {\n  let toc;\n\n  try {\n    const meta = context.resolveOf('meta', ['meta']);\n    toc = meta.preparedMeta.parameters?.docs?.toc;\n  } catch (err) {\n    // No meta, falling back to project annotations\n    toc = context?.projectAnnotations?.parameters?.docs?.toc;\n  }\n\n  useEffect(() => {\n    let url;\n    try {\n      url = new URL(globalWindow.parent.location.toString());\n      if (url.hash) {\n        const element = document.getElementById(decodeURIComponent(url.hash.substring(1)));\n        if (element) {\n          // Introducing a delay to ensure scrolling works when it's a full refresh.\n          setTimeout(() => {\n            scrollToElement(element);\n          }, 200);\n        }\n      }\n    } catch (err) {\n      // pass\n    }\n  });\n\n  return (\n    <DocsContext.Provider value={context}>\n      <SourceContainer channel={context.channel}>\n        <ThemeProvider theme={ensureTheme(theme as ThemeVars)}>\n          <DocsPageWrapper\n            toc={\n              toc ? (\n                <TableOfContents\n                  className=\"sbdocs sbdocs-toc--custom\"\n                  channel={context.channel}\n                  {...toc}\n                />\n              ) : null\n            }\n          >\n            {children}\n          </DocsPageWrapper>\n        </ThemeProvider>\n      </SourceContainer>\n    </DocsContext.Provider>\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/DocsContext.ts",
    "content": "import type { Context } from 'react';\nimport { createContext } from 'react';\n\nimport type { DocsContextProps, Renderer } from 'storybook/internal/types';\n\nexport type { DocsContextProps };\n\n// We add DocsContext to window. The reason is that in case DocsContext.ts is\n// imported multiple times (maybe once directly, and another time from a minified bundle)\n// we will have multiple DocsContext definitions - leading to lost context in\n// the React component tree.\n// This was specifically a problem with the Vite builder.\nif (globalThis && globalThis.__DOCS_CONTEXT__ === undefined) {\n  globalThis.__DOCS_CONTEXT__ = createContext(null);\n  globalThis.__DOCS_CONTEXT__.displayName = 'DocsContext';\n}\n\nexport const DocsContext: Context<DocsContextProps<Renderer>> = globalThis\n  ? globalThis.__DOCS_CONTEXT__\n  : createContext(null);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/DocsPage.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { DocsPage } from './DocsPage';\n\nconst meta = {\n  component: DocsPage,\n  parameters: {\n    layout: 'fullscreen',\n    docsStyles: true,\n    chromatic: {\n      disableSnapshot: true,\n    },\n  },\n} satisfies Meta<typeof DocsPage>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {\n  parameters: {\n    relativeCsfPaths: ['../examples/Button.stories'],\n  },\n};\nexport const SingleStory: Story = {\n  parameters: {\n    relativeCsfPaths: ['../examples/DocsPageParameters.stories'],\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/DocsPage.test.ts",
    "content": "// @vitest-environment happy-dom\nimport { describe, expect, it } from 'vitest';\n\nimport { extractTitle } from './Title';\n\ndescribe('defaultTitleSlot', () => {\n  it('splits on last /', () => {\n    expect(extractTitle('a/b/c')).toBe('c');\n    expect(extractTitle('a|b')).toBe('a|b');\n    expect(extractTitle('a/b/c.d')).toBe('c.d');\n  });\n});\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/DocsPage.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { Controls } from './Controls';\nimport { Description } from './Description';\nimport { Primary } from './Primary';\nimport { Stories } from './Stories';\nimport { Subtitle } from './Subtitle';\nimport { Title } from './Title';\nimport { useOf } from './useOf';\n\nexport const DocsPage: FC = () => {\n  const resolvedOf = useOf('meta', ['meta']);\n  const { stories } = resolvedOf.csfFile;\n  const isSingleStory = Object.keys(stories).length === 1;\n\n  return (\n    <>\n      <Title />\n      <Subtitle />\n      <Description of=\"meta\" />\n      {isSingleStory ? <Description of=\"story\" /> : null}\n      <Primary />\n      <Controls />\n      {isSingleStory ? null : <Stories />}\n    </>\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/DocsStory.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { Anchor } from './Anchor';\nimport { Canvas } from './Canvas';\nimport { Description } from './Description';\nimport { Subheading } from './Subheading';\nimport type { DocsStoryProps } from './types';\nimport { useOf } from './useOf';\nimport { withMdxComponentOverride } from './with-mdx-component-override';\n\nconst DocsStoryImpl: FC<DocsStoryProps> = ({\n  of,\n  expanded = true,\n  withToolbar: withToolbarProp = false,\n  __forceInitialArgs = false,\n  __primary = false,\n}) => {\n  const { story } = useOf(of || 'story', ['story']);\n\n  // use withToolbar from parameters or default to true in autodocs\n  const withToolbar = story.parameters.docs?.canvas?.withToolbar ?? withToolbarProp;\n\n  return (\n    <Anchor storyId={__primary ? `primary--${story.id}` : story.id}>\n      {expanded && (\n        <>\n          <Subheading>{story.name}</Subheading>\n          <Description of={of} />\n        </>\n      )}\n      <Canvas\n        of={of}\n        withToolbar={withToolbar}\n        story={{ __forceInitialArgs, __primary }}\n        source={{ __forceInitialArgs }}\n      />\n    </Anchor>\n  );\n};\n\nexport const DocsStory = withMdxComponentOverride('DocsStory', DocsStoryImpl);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Heading.tsx",
    "content": "import type { FC, PropsWithChildren } from 'react';\nimport React from 'react';\n\nimport { H2 } from 'storybook/internal/components';\n\nimport GithubSlugger from 'github-slugger';\n\nimport { HeaderMdx } from './mdx';\nimport { withMdxComponentOverride } from './with-mdx-component-override';\n\nexport interface HeadingProps {\n  disableAnchor?: boolean;\n}\n\nexport const slugs = new GithubSlugger();\n\nconst HeadingImpl: FC<PropsWithChildren<HeadingProps>> = ({\n  children,\n  disableAnchor,\n  ...props\n}) => {\n  if (disableAnchor || typeof children !== 'string') {\n    return <H2>{children}</H2>;\n  }\n  const tagID = slugs.slug(children.toLowerCase());\n  return (\n    <HeaderMdx as=\"h2\" id={tagID} {...props}>\n      {children}\n    </HeaderMdx>\n  );\n};\n\nexport const Heading = withMdxComponentOverride('Heading', HeadingImpl);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Markdown.stories.tsx",
    "content": "import { dedent } from 'ts-dedent';\n\nimport mdContent from '../examples/Markdown-content.md?raw';\nimport { Markdown as MarkdownComponent } from './Markdown';\n\nexport default {\n  component: MarkdownComponent,\n  parameters: {\n    layout: 'fullscreen',\n    docsStyles: true,\n  },\n};\n\nexport const Markdown = {\n  args: {\n    children: dedent`\n    # My Example Markdown\n\n    The group looked like tall, exotic grazing animals, swaying gracefully and unconsciously with the movement of the train, their high heels like polished hooves against the gray metal of the Flatline as a construct, a hardwired ROM cassette replicating a dead man’s skills, obsessions, kneejerk responses.\n    \n    ![An image](https://storybook.js.org/images/placeholders/350x150.png)\n    \n    He stared at the clinic, Molly took him to the Tank War, mouth touched with hot gold as a gliding cursor struck sparks from the wall of a skyscraper canyon.\n    \n    Paragraph with an \\`inline code\\` block.\n\n    \\`\\`\\`tsx\n    // TypeScript React code block\n    export const MyStory = () => {\n      return <Button>Click me</Button>;\n    };\n    \\`\\`\\`\n    \n    \\`\\`\\`\n    code block with with no language\n    const a = fn({\n      b: 2,\n    });\n    \\`\\`\\`\n\n    <h3>Native h3 element</h3>\n\n    # [Link](https://storybook.js.org/) in heading\n    ## [Link](https://storybook.js.org/) in heading\n    ### [Link](https://storybook.js.org/) in heading\n    #### [Link](https://storybook.js.org/) in heading\n    ##### [Link](https://storybook.js.org/) in heading\n    ###### [Link](https://storybook.js.org/) in heading\n    \n    He stared at the clinic, [Molly](https://storybook.js.org/) took him to the *[Tank War](https://storybook.js.org/)*, mouth touched with hot gold as a gliding cursor struck sparks from the wall of a **[skyscraper](https://storybook.js.org/)** canyon.\n\n    Check out [\\`inline-code\\`](https://storybook.js.org/) inside a link.\n\n    Visit the [\\`@storybook/addon-essentials\\`](https://storybook.js.org/) package for more details.\n\n    Mixed: [regular text and \\`code text\\` together](https://storybook.js.org/).\n\n    For comparison, regular \\`inline-code\\` outside a link.\n\n    { brackets, valid MD but invalid MDX - works here }\n\n    <Looks like a JSX tag/>\n    <!-- above is valid MD but invalid in markdown-to-jsx, so it will not be rendered -->\n\n    \\`<Looks like a JSX tag />\\`\n\n    The above is only visible because it is wrapped in backticks\n    `,\n  },\n};\n\n/**\n * The Markdown component won't know the difference between getting a raw string and something\n * imported from a .md file. So this story doesn't actually test the component, but rather the\n * import at the top of the CSF file\n */\nexport const ImportedMDFile = {\n  name: 'Imported .md file',\n  args: { children: mdContent },\n};\n\nexport const Text = {\n  args: {\n    children: `That was Wintermute, manipulating the lock the way it had manipulated the drone micro and the amplified breathing of the room where Case waited. The semiotics of the bright void beyond the chain link. The tug Marcus Garvey, a steel drum nine meters long and two in diameter, creaked and shuddered as Maelcum punched for a California gambling cartel, then as a paid killer in the dark, curled in his capsule in some coffin hotel, his hands clawed into the nearest door and watched the other passengers as he rode. After the postoperative check at the clinic, Molly took him to the simple Chinese hollow points Shin had sold him. Still it was a handgun and nine rounds of ammunition, and as he made his way down Shiga from the missionaries, the train reached Case’s station. Now this quiet courtyard, Sunday afternoon, this girl with a random collection of European furniture, as though Deane had once intended to use the place as his home. Case felt the edge of the Flatline as a construct, a hardwired ROM cassette replicating a dead man’s skills, obsessions, kneejerk responses. They were dropping, losing altitude in a canyon of rainbow foliage, a lurid communal mural that completely covered the hull of the console in faded pinks and yellows.`,\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Markdown.tsx",
    "content": "/* eslint-disable react/destructuring-assignment */\nimport React from 'react';\n\nimport PureMarkdown from 'markdown-to-jsx';\nimport { dedent } from 'ts-dedent';\n\nimport { AnchorMdx, CodeOrSourceMdx, HeadersMdx } from './mdx';\nimport { withMdxComponentOverride } from './with-mdx-component-override';\n\n// mirror props from markdown-to-jsx. From https://react-typescript-cheatsheet.netlify.app/docs/advanced/patterns_by_usecase#wrappingmirroring-a-component\ntype MarkdownProps = typeof PureMarkdown extends React.ComponentType<infer Props> ? Props : never;\n\nconst MarkdownImpl = (props: MarkdownProps) => {\n  if (!props.children) {\n    return null;\n  }\n  if (typeof props.children !== 'string') {\n    throw new Error(\n      dedent`The Markdown block only accepts children as a single string, but children were of type: '${typeof props.children}'\n        This is often caused by not wrapping the child in a template string.\n        \n        This is invalid:\n        <Markdown>\n          # Some heading\n          A paragraph\n        </Markdown>\n\n        Instead do:\n        <Markdown>\n        {\\`\n          # Some heading\n          A paragraph\n        \\`}\n        </Markdown>\n      `\n    );\n  }\n  return (\n    <PureMarkdown\n      {...props}\n      options={{\n        forceBlock: true,\n        overrides: {\n          code: CodeOrSourceMdx,\n          a: AnchorMdx,\n          ...HeadersMdx,\n          ...props?.options?.overrides,\n        },\n        ...props?.options,\n      }}\n    />\n  );\n};\n\nexport const Markdown = withMdxComponentOverride('Markdown', MarkdownImpl);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Meta.tsx",
    "content": "import type { FC } from 'react';\nimport React, { useContext } from 'react';\n\nimport type { BaseAnnotations, ModuleExports } from 'storybook/internal/types';\n\nimport { Anchor } from './Anchor';\nimport { DocsContext } from './DocsContext';\n\ntype MetaProps = BaseAnnotations & { of?: ModuleExports; title?: string };\n\n/**\n * This component is used to declare component metadata in docs and gets transformed into a default\n * export underneath the hood.\n */\nexport const Meta: FC<MetaProps> = ({ of }) => {\n  const context = useContext(DocsContext);\n  if (of) {\n    context.referenceMeta(of, true);\n  }\n\n  try {\n    const primary = context.storyById();\n    return <Anchor storyId={primary.id} />;\n  } catch {\n    // It is possible to use <Meta> in an unattached MDX file\n    return null;\n  }\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Primary.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport * as DefaultButtonStories from '../examples/Button.stories';\nimport * as ButtonNoAutodocsStories from '../examples/ButtonNoAutodocs.stories';\nimport * as ButtonSomeAutodocsStories from '../examples/ButtonSomeAutodocs.stories';\nimport * as StoriesParametersStories from '../examples/StoriesParameters.stories';\nimport { Primary } from './Primary';\n\nconst meta = {\n  component: Primary,\n  parameters: {\n    layout: 'fullscreen',\n    // workaround for https://github.com/storybookjs/storybook/issues/20505\n    docs: { source: { type: 'code' } },\n    docsStyles: true,\n  },\n} satisfies Meta<typeof Primary>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {\n  parameters: {\n    relativeCsfPaths: ['../examples/Button.stories'],\n  },\n};\nexport const WithoutToolbar: Story = {\n  parameters: {\n    relativeCsfPaths: ['../examples/StoriesParameters.stories'],\n  },\n};\n\nexport const DefaultWithOf: Story = {\n  name: 'Of',\n  args: {\n    of: DefaultButtonStories,\n  },\n  parameters: { relativeCsfPaths: ['../examples/Button.stories'] },\n};\n\nexport const WithoutToolbarWithOf: Story = {\n  name: 'Of Without Toolbar',\n  args: {\n    of: StoriesParametersStories,\n  },\n  parameters: { relativeCsfPaths: ['../examples/StoriesParameters.stories'] },\n};\n\nexport const DefaultOfStringMetaAttached: Story = {\n  name: 'Of Attached \"meta\"',\n  args: {\n    of: 'meta',\n  },\n  parameters: { relativeCsfPaths: ['../examples/Button.stories'] },\n};\n\nexport const WithoutToolbarOfStringMetaAttached: Story = {\n  name: 'Of Attached \"meta\" Without Toolbar',\n  args: {\n    of: 'meta',\n  },\n  parameters: { relativeCsfPaths: ['../examples/StoriesParameters.stories'] },\n};\n\nexport const NoAutodocsExample: Story = {\n  name: 'Button (No Autodocs)',\n  args: {\n    of: ButtonNoAutodocsStories,\n  },\n  parameters: {\n    relativeCsfPaths: ['../examples/ButtonNoAutodocs.stories'],\n  },\n};\n\nexport const SomeAutodocsExample: Story = {\n  name: 'Button (Some Autodocs)',\n  args: {\n    of: ButtonSomeAutodocsStories,\n  },\n  parameters: {\n    relativeCsfPaths: ['../examples/ButtonSomeAutodocs.stories'],\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Primary.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { DocsStory } from './DocsStory';\nimport { usePrimaryStory } from './usePrimaryStory';\nimport { withMdxComponentOverride } from './with-mdx-component-override';\n\nconst PrimaryImpl: FC = () => {\n  const primaryStory = usePrimaryStory();\n\n  return primaryStory ? (\n    <DocsStory of={primaryStory.moduleExport} expanded={false} __primary withToolbar />\n  ) : null;\n};\n\nexport const Primary = withMdxComponentOverride('Primary', PrimaryImpl);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Source.stories.tsx",
    "content": "import React from 'react';\n\nimport { SourceType } from 'storybook/internal/docs-tools';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { dedent } from 'ts-dedent';\n\nimport * as ParametersStories from '../examples/SourceParameters.stories';\nimport { Source } from './Source';\nimport { SourceContext, argsHash } from './SourceContainer';\n\nconst meta: Meta<typeof Source> = {\n  component: Source,\n  parameters: {\n    layout: 'fullscreen',\n    relativeCsfPaths: ['../examples/SourceParameters.stories'],\n    snippets: {\n      'storybook-blocks-examples-stories-for-the-source-block--no-parameters': {\n        [argsHash({})]: {\n          code: `const emitted = 'source';`,\n        },\n      },\n      'storybook-blocks-examples-stories-for-the-source-block--transform': {\n        [argsHash({})]: {\n          code: `const emitted = 'source';`,\n        },\n      },\n      'storybook-blocks-examples-stories-for-the-source-block--type-dynamic': {\n        [argsHash({})]: {\n          code: `const emitted = 'source';`,\n        },\n      },\n    },\n    docsStyles: true,\n  },\n  decorators: [\n    (Story, { parameters: { snippets = {} } }) => (\n      <SourceContext.Provider value={{ sources: snippets }}>\n        <Story />\n      </SourceContext.Provider>\n    ),\n  ],\n};\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nconst code = `query HeroNameAndFriends($episode: Episode) {\n          hero(episode: $episode) {\n            name\n            friends {\n              name\n            }\n          }\n        }\n`;\n\nexport const DefaultAttached = {};\n\nexport const Of: Story = {\n  args: {\n    of: ParametersStories.NoParameters,\n  },\n};\n\nexport const OfUndefined: Story = {\n  args: {\n    // @ts-expect-error this is supposed to be undefined\n    of: ParametersStories.NotDefined,\n  },\n  parameters: { chromatic: { disableSnapshot: true } },\n  tags: ['!test'],\n};\n\nexport const OfTypeProp: Story = {\n  args: {\n    of: ParametersStories.NoParameters,\n    type: SourceType.CODE,\n  },\n};\n\nexport const OfTypeParameter: Story = {\n  args: {\n    of: ParametersStories.TypeCode,\n  },\n};\n\nexport const OfTransformProp: Story = {\n  args: {\n    of: ParametersStories.NoParameters,\n    transform: (src, storyContext) => dedent`// this comment has been added via the transform prop!\n    // this is the story id: ${storyContext.id}\n    // these are the current args: ${JSON.stringify(storyContext.args)}\n    ${src}`,\n  },\n};\n\nexport const OfTransformParameter: Story = {\n  args: {\n    of: ParametersStories.Transform,\n  },\n};\n\nexport const OfUnattached: Story = {\n  args: {\n    of: ParametersStories.NoParameters,\n  },\n  parameters: { attached: false },\n};\n\nexport const Code: Story = {\n  args: { code },\n};\n\nexport const CodeUnattached: Story = {\n  args: { code },\n  parameters: { attached: false },\n};\n\nexport const EmptyUnattached: Story = {\n  parameters: { attached: false },\n};\n\nexport const CodeParameters: Story = {\n  args: { of: ParametersStories.Code },\n};\n\nexport const CodeFormat: Story = {\n  args: {\n    code,\n  },\n};\n\nexport const CodeFormatParameters: Story = {\n  args: { of: ParametersStories.CodeFormat },\n};\n\nexport const CodeLanguage: Story = {\n  args: {\n    code,\n    language: 'graphql',\n  },\n};\n\nexport const CodeLanguageParameters: Story = {\n  args: { of: ParametersStories.CodeLanguage },\n};\n\nexport const Dark: Story = {\n  args: { code, dark: true },\n};\n\nexport const CodeDarkParameters: Story = {\n  args: { of: ParametersStories.CodeDark },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Source.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React, { useContext, useMemo } from 'react';\n\nimport { SourceType } from 'storybook/internal/docs-tools';\nimport type { Args, ModuleExport, StoryId } from 'storybook/internal/types';\n\nimport type { SourceCodeProps } from '../components/Source';\nimport { Source as PureSource, SourceError } from '../components/Source';\nimport type { DocsContextProps } from './DocsContext';\nimport { DocsContext } from './DocsContext';\nimport type { SourceContextProps, SourceItem } from './SourceContainer';\nimport { SourceContext, UNKNOWN_ARGS_HASH, argsHash } from './SourceContainer';\nimport { useTransformCode } from './useTransformCode';\nimport { withMdxComponentOverride } from './with-mdx-component-override';\n\nexport type SourceParameters = SourceCodeProps & {\n  /** Where to read the source code from, see `SourceType` */\n  type?: SourceType;\n  /** Transform the detected source for display */\n  transform?: (\n    code: string,\n    storyContext: ReturnType<DocsContextProps['getStoryContext']>\n  ) => string | Promise<string>;\n  /** Internal: set by our CSF loader (`enrichCsf` in `storybook/internal/csf-tools`). */\n  originalSource?: string;\n};\n\nexport type SourceProps = SourceParameters & {\n  /**\n   * Pass the export defining a story to render its source\n   *\n   * ```jsx\n   * import { Source } from '@storybook/addon-docs/blocks';\n   * import * as ButtonStories from './Button.stories';\n   *\n   * <Source of={ButtonStories.Primary} />;\n   * ```\n   */\n  of?: ModuleExport;\n\n  /** Internal prop to control if a story re-renders on args updates */\n  __forceInitialArgs?: boolean;\n};\n\nconst getStorySource = (\n  storyId: StoryId,\n  args: Args,\n  sourceContext: SourceContextProps\n): SourceItem => {\n  const { sources } = sourceContext;\n\n  const sourceMap = sources?.[storyId];\n  // If the source decorator hasn't provided args, we fallback to the \"unknown args\"\n  // version of the source (which means if you render a story >1 time with different args\n  // you'll get the same source value both times).\n  const source = sourceMap?.[argsHash(args)] || sourceMap?.[UNKNOWN_ARGS_HASH];\n\n  // source rendering is async so source is unavailable at the start of the render cycle,\n  // so we fail gracefully here without warning\n  return source || { code: '' };\n};\n\nconst useCode = ({\n  snippet,\n  storyContext,\n  typeFromProps,\n  transformFromProps,\n}: {\n  snippet: string;\n  storyContext: ReturnType<DocsContextProps['getStoryContext']>;\n  typeFromProps: SourceType;\n  transformFromProps?: SourceProps['transform'];\n}): string => {\n  const parameters = storyContext.parameters ?? {};\n  const { __isArgsStory: isArgsStory } = parameters;\n  const sourceParameters = (parameters.docs?.source || {}) as SourceParameters;\n\n  const type = typeFromProps || sourceParameters.type || SourceType.AUTO;\n\n  const useSnippet =\n    // if user has explicitly set this as dynamic, use snippet\n    type === SourceType.DYNAMIC ||\n    // if this is an args story and there's a snippet\n    (type === SourceType.AUTO && snippet && isArgsStory);\n\n  const code = useSnippet ? snippet : sourceParameters.originalSource || '';\n  const transformer = transformFromProps ?? sourceParameters.transform;\n\n  const transformedCode = transformer ? useTransformCode(code, transformer, storyContext) : code;\n\n  if (sourceParameters.code !== undefined) {\n    return sourceParameters.code;\n  }\n\n  return transformedCode;\n};\n\n// state is used by the Canvas block, which also calls useSourceProps\ntype PureSourceProps = ComponentProps<typeof PureSource>;\n\nexport const useSourceProps = (\n  props: SourceProps,\n  docsContext: DocsContextProps<any>,\n  sourceContext: SourceContextProps\n): PureSourceProps => {\n  const { of } = props;\n\n  const story = useMemo(() => {\n    if (of) {\n      const resolved = docsContext.resolveOf(of, ['story']);\n      return resolved.story;\n    } else {\n      try {\n        // Always fall back to the primary story for source parameters, even if code is set.\n        return docsContext.storyById();\n      } catch {\n        // You are allowed to use <Source code=\"...\" /> and <Canvas /> unattached.\n      }\n    }\n  }, [docsContext, of]);\n\n  const storyContext = story ? docsContext.getStoryContext(story) : {};\n\n  const argsForSource = props.__forceInitialArgs\n    ? storyContext.initialArgs\n    : storyContext.unmappedArgs;\n\n  const source = story ? getStorySource(story.id, argsForSource, sourceContext) : null;\n\n  const transformedCode = useCode({\n    snippet: source ? source.code : '',\n    storyContext: { ...storyContext, args: argsForSource },\n    typeFromProps: props.type as SourceType,\n    transformFromProps: props.transform,\n  });\n\n  if ('of' in props && of === undefined) {\n    throw new Error('Unexpected `of={undefined}`, did you mistype a CSF file reference?');\n  }\n\n  const sourceParameters = (story?.parameters?.docs?.source || {}) as SourceParameters;\n  let format = props.format;\n\n  const language = props.language ?? sourceParameters.language ?? 'jsx';\n  const dark = props.dark ?? sourceParameters.dark ?? false;\n\n  if (!props.code && !story) {\n    return { error: SourceError.SOURCE_UNAVAILABLE };\n  }\n\n  if (props.code) {\n    return {\n      code: props.code,\n      format,\n      language,\n      dark,\n    };\n  }\n\n  format = source?.format ?? true;\n\n  return {\n    code: transformedCode,\n    format,\n    language,\n    dark,\n  };\n};\n\n/**\n * Story source doc block renders source code if provided, or the source for a story if `storyId` is\n * provided, or the source for the current story if nothing is provided.\n */\nconst SourceImpl = (props: SourceProps) => {\n  const sourceContext = useContext(SourceContext);\n  const docsContext = useContext(DocsContext);\n  const sourceProps = useSourceProps(props, docsContext, sourceContext);\n  return <PureSource {...sourceProps} />;\n};\n\nexport const Source = withMdxComponentOverride('Source', SourceImpl);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/SourceContainer.tsx",
    "content": "import type { Context, FC, PropsWithChildren } from 'react';\nimport React, { createContext, useEffect, useState } from 'react';\n\nimport type { SyntaxHighlighterFormatTypes } from 'storybook/internal/components';\nimport { SNIPPET_RENDERED } from 'storybook/internal/docs-tools';\nimport type { Args, DocsContextProps, StoryId } from 'storybook/internal/types';\n\nimport { stringify } from 'telejson';\n\ntype ArgsHash = string;\nexport function argsHash(args: Args): ArgsHash {\n  return stringify(args, { maxDepth: 50 });\n}\n\nexport interface SourceItem {\n  code: string;\n  format?: SyntaxHighlighterFormatTypes;\n}\n\nexport type StorySources = Record<StoryId, Record<ArgsHash, SourceItem>>;\n\nexport interface SourceContextProps {\n  sources: StorySources;\n  setSource?: (id: StoryId, item: SourceItem) => void;\n}\n\nexport const SourceContext: Context<SourceContextProps> = createContext({ sources: {} });\n\ntype SnippetRenderedEvent = {\n  id: StoryId;\n  source: string;\n  args?: Args;\n  format?: SyntaxHighlighterFormatTypes;\n};\n\nexport const UNKNOWN_ARGS_HASH = '--unknown--';\n\nexport const SourceContainer: FC<PropsWithChildren<{ channel: DocsContextProps['channel'] }>> = ({\n  children,\n  channel,\n}) => {\n  const [sources, setSources] = useState<StorySources>({});\n\n  useEffect(() => {\n    const handleSnippetRendered = (\n      idOrEvent: StoryId | SnippetRenderedEvent,\n      inputSource: string | null = null,\n      inputFormat: SyntaxHighlighterFormatTypes = false\n    ) => {\n      const {\n        id,\n        args = undefined,\n        source,\n        format,\n      } = typeof idOrEvent === 'string'\n        ? {\n            id: idOrEvent,\n            source: inputSource,\n            format: inputFormat,\n          }\n        : idOrEvent;\n\n      const hash = args ? argsHash(args) : UNKNOWN_ARGS_HASH;\n      // FIXME: In SB8.0 when we remove the Source block deprecations,\n      // we should restore this optimizationand make the Source block\n      // smarter about understanding when its args change.\n      //\n      // See https://github.com/storybookjs/storybook/pull/22807\n      //\n      // optimization: don't update if the source is the same\n      // if (deepEqual(currentSource, { code: source, format })) return;\n\n      setSources((current) => {\n        const newSources = {\n          ...current,\n          [id]: {\n            ...current[id],\n            [hash]: { code: source || '', format },\n          },\n        };\n\n        return newSources;\n      });\n    };\n\n    channel.on(SNIPPET_RENDERED, handleSnippetRendered);\n\n    return () => channel.off(SNIPPET_RENDERED, handleSnippetRendered);\n  }, []);\n\n  return <SourceContext.Provider value={{ sources }}>{children}</SourceContext.Provider>;\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Stories.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Stories } from './Stories';\n\nconst meta = {\n  component: Stories,\n  parameters: {\n    layout: 'fullscreen',\n    docsStyles: true,\n    chromatic: {\n      delay: 2000,\n    },\n  },\n} satisfies Meta<typeof Stories>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {\n  parameters: {\n    relativeCsfPaths: ['../examples/Button.stories'],\n  },\n};\nexport const WithoutPrimary: Story = {\n  args: { includePrimary: false },\n  parameters: {\n    relativeCsfPaths: ['../examples/Button.stories'],\n  },\n};\nexport const DifferentToolbars: Story = {\n  parameters: {\n    relativeCsfPaths: ['../examples/StoriesParameters.stories'],\n  },\n};\nexport const NoAutodocs: Story = {\n  parameters: {\n    relativeCsfPaths: ['../examples/ButtonNoAutodocs.stories'],\n  },\n};\nexport const SomeAutodocs: Story = {\n  parameters: {\n    relativeCsfPaths: ['../examples/ButtonSomeAutodocs.stories'],\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Stories.tsx",
    "content": "import type { FC, ReactElement } from 'react';\nimport React, { useContext } from 'react';\n\nimport { Tag } from 'storybook/internal/preview-api';\n\nimport { styled } from 'storybook/theming';\n\nimport { DocsContext } from './DocsContext';\nimport { DocsStory } from './DocsStory';\nimport { Heading } from './Heading';\nimport { withMdxComponentOverride } from './with-mdx-component-override';\n\ninterface StoriesProps {\n  title?: ReactElement | string;\n  includePrimary?: boolean;\n}\n\nconst StyledHeading: typeof Heading = styled(Heading)(({ theme }) => ({\n  fontSize: `${theme.typography.size.s2 - 1}px`,\n  fontWeight: theme.typography.weight.bold,\n  lineHeight: '16px',\n  letterSpacing: '0.35em',\n  textTransform: 'uppercase',\n  color: theme.textMutedColor,\n  border: 0,\n  marginBottom: '12px',\n\n  '&:first-of-type': {\n    // specificity issue\n    marginTop: '56px',\n  },\n}));\n\nconst StoriesImpl: FC<StoriesProps> = ({ title = 'Stories', includePrimary = true }) => {\n  const { componentStories, projectAnnotations, getStoryContext } = useContext(DocsContext);\n\n  let stories = componentStories();\n  const { stories: { filter } = { filter: undefined } } = projectAnnotations.parameters?.docs || {};\n  if (filter) {\n    stories = stories.filter((story) => filter(story, getStoryContext(story)));\n  }\n  // NOTE: this should be part of the default filter function. However, there is currently\n  // no way to distinguish a Stories block in an autodocs page from Stories in an MDX file\n  // making https://github.com/storybookjs/storybook/pull/26634 an unintentional breaking change.\n  //\n  // The new behavior here is that if NONE of the stories in the autodocs page are tagged\n  // with 'autodocs', we show all stories. If ANY of the stories have autodocs then we use\n  // the new behavior.\n  const hasAutodocsTaggedStory = stories.some((story) => story.tags?.includes(Tag.AUTODOCS));\n  if (hasAutodocsTaggedStory) {\n    // Don't show stories where mount is used in docs.\n    // As the play function is not running in docs, and when mount is used, the mounting is happening in play itself.\n    stories = stories.filter((story) => story.tags?.includes(Tag.AUTODOCS) && !story.usesMount);\n  }\n\n  if (!includePrimary) {\n    stories = stories.slice(1);\n  }\n\n  if (!stories || stories.length === 0) {\n    return null;\n  }\n  return (\n    <>\n      {typeof title === 'string' ? <StyledHeading>{title}</StyledHeading> : title}\n      {stories.map(\n        (story) =>\n          story && <DocsStory key={story.id} of={story.moduleExport} expanded __forceInitialArgs />\n      )}\n    </>\n  );\n};\n\nexport const Stories = withMdxComponentOverride('Stories', StoriesImpl);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Story.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { expect, waitFor } from 'storybook/test';\n\nimport * as StoryComponentStories from '../components/Story.stories';\nimport * as ButtonStories from '../examples/Button.stories';\nimport * as StoryParametersStories from '../examples/StoryParameters.stories';\nimport { Story as StoryBlock } from './Story';\n\nconst meta: Meta<typeof StoryBlock> = {\n  component: StoryBlock,\n  parameters: {\n    layout: 'fullscreen',\n    relativeCsfPaths: ['../examples/Button.stories', '../examples/StoryParameters.stories'],\n    docsStyles: true,\n  },\n};\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const DefaultAttached: Story = {};\n\nexport const Of: Story = {\n  args: {\n    of: ButtonStories.Primary,\n  },\n};\n\nexport const OfWithMeta: Story = {\n  args: {\n    of: ButtonStories.Secondary,\n    meta: ButtonStories.default,\n  },\n};\n\nexport const OfWithMetaUnattached: Story = {\n  parameters: { attached: false },\n  args: {\n    of: ButtonStories.Secondary,\n    meta: ButtonStories.default,\n  },\n};\n\nexport const OfError: Story = {\n  args: {\n    of: ButtonStories.ErrorStory,\n  },\n};\n\nexport const OfUndefined: Story = {\n  args: {\n    // @ts-expect-error this is supposed to be undefined\n    of: ButtonStories.NotDefined,\n  },\n  parameters: { chromatic: { disableSnapshot: true } },\n  tags: ['!test'],\n};\n\nexport const Inline: Story = {\n  args: {\n    of: StoryParametersStories.NoParameters,\n    inline: true,\n  },\n};\n\nexport const InlineWithHeightProps: Story = {\n  ...Inline,\n  args: {\n    of: StoryParametersStories.NoParameters,\n    inline: true,\n    height: '600px',\n  },\n};\n\nexport const InlineWithHeightParameter: Story = {\n  ...Inline,\n  args: {\n    of: StoryParametersStories.Height,\n  },\n};\n\nexport const IFrameProps: Story = {\n  ...Inline,\n  name: 'IFrame Props',\n  args: {\n    of: StoryParametersStories.NoParameters,\n    inline: false,\n  },\n  parameters: {\n    chromatic: {\n      delay: 3000,\n    },\n  },\n  play: async ({ canvasElement }) => {\n    // this is mostly to fix flakiness in chromatic, specifically on Safari\n    // where the scrollbar appears inconsistently and causes the snapshot to be different\n    await waitFor(\n      async () => {\n        const iframeEl = canvasElement.querySelector('iframe');\n        await expect(\n          iframeEl!.contentDocument!.querySelector('[data-testid=\"sb-iframe-text\"]')\n        ).toBeVisible();\n      },\n      { timeout: 10000 }\n    );\n  },\n};\n\nexport const IFrameWithParameter: Story = {\n  ...Inline,\n  name: 'IFrame With Parameter',\n  args: {\n    of: StoryParametersStories.InlineFalse,\n  },\n};\n\nexport const IFrameWithHeightProps: Story = {\n  ...Inline,\n  name: 'IFrame With Height Props',\n  args: {\n    of: StoryParametersStories.NoParameters,\n    inline: false,\n    height: '300px',\n  },\n};\n\nexport const IFrameWithHeightParameter: Story = {\n  ...Inline,\n  name: 'IFrame With Height Parameter',\n  args: {\n    of: StoryParametersStories.InlineFalseWithHeight,\n  },\n};\n\nexport const IFrameWithIFrameHeightParameter: Story = {\n  ...Inline,\n  name: 'IFrame With IFrame Height Parameter',\n  args: {\n    of: StoryParametersStories.InlineFalseWithIframeHeight,\n  },\n};\n\nexport const WithDefaultInteractions: Story = {\n  args: {\n    of: ButtonStories.Clicking,\n  },\n  parameters: {\n    chromatic: { delay: 500 },\n  },\n};\n\nexport const WithInteractionsAutoplayInProps: Story = {\n  args: {\n    of: ButtonStories.Clicking,\n    autoplay: true,\n  },\n  parameters: {\n    chromatic: { delay: 500 },\n  },\n};\n\nexport const WithInteractionsAutoplayInParameters: Story = {\n  args: {\n    of: ButtonStories.ClickingInDocs,\n  },\n  parameters: {\n    chromatic: { delay: 500 },\n  },\n};\n\nexport const ForceInitialArgs: Story = {\n  ...StoryComponentStories.ForceInitialArgs,\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n  args: {\n    of: ButtonStories.Primary,\n    storyExport: ButtonStories.Primary,\n    __forceInitialArgs: true,\n  } as any,\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Story.tsx",
    "content": "import type { ComponentProps, FC } from 'react';\nimport React, { useContext } from 'react';\n\nimport type {\n  ModuleExport,\n  ModuleExports,\n  PreparedStory,\n  Renderer,\n  StoryId,\n} from 'storybook/internal/types';\n\nimport { Story as PureStory, StorySkeleton } from '../components';\nimport type { DocsContextProps } from './DocsContext';\nimport { DocsContext } from './DocsContext';\nimport { useStory } from './useStory';\nimport { withMdxComponentOverride } from './with-mdx-component-override';\n\ntype PureStoryProps = ComponentProps<typeof PureStory>;\n\n/** Props to reference another story */\ntype StoryRefProps = {\n  /**\n   * Pass the export defining a story to render that story\n   *\n   * ```jsx\n   * import { Meta, Story } from '@storybook/addon-docs/blocks';\n   * import * as ButtonStories from './Button.stories';\n   *\n   * <Meta of={ButtonStories} />\n   * <Story of={ButtonStories.Primary} />\n   * ```\n   */\n  of?: ModuleExport;\n  /**\n   * Pass all exports of the CSF file if this MDX file is unattached\n   *\n   * ```jsx\n   * import { Story } from '@storybook/addon-docs/blocks';\n   * import * as ButtonStories from './Button.stories';\n   *\n   * <Story of={ButtonStories.Primary} meta={ButtonStories} />;\n   * ```\n   */\n  meta?: ModuleExports;\n};\n\ntype StoryParameters = {\n  /** Render the story inline or in an iframe */\n  inline?: boolean;\n  /** When rendering in an iframe (`inline={false}`), set the story height */\n  height?: string;\n  /** Whether to run the story's play function */\n  autoplay?: boolean;\n  /** Internal prop to control if a story re-renders on args updates */\n  __forceInitialArgs?: boolean;\n  /** Internal prop if this story is the primary story */\n  __primary?: boolean;\n};\n\nexport type StoryProps = StoryRefProps & StoryParameters;\n\nexport const getStoryId = (props: StoryProps, context: DocsContextProps): StoryId => {\n  const { of, meta } = props as StoryRefProps;\n  if ('of' in props && of === undefined) {\n    throw new Error('Unexpected `of={undefined}`, did you mistype a CSF file reference?');\n  }\n\n  if (meta) {\n    context.referenceMeta(meta, false);\n  }\n  const resolved = context.resolveOf(of || 'story', ['story']);\n  return resolved.story.id;\n};\n\nexport const getStoryProps = <TFramework extends Renderer>(\n  props: StoryParameters,\n  story: PreparedStory<TFramework>,\n  context: DocsContextProps<TFramework>\n): PureStoryProps => {\n  const { parameters = {} } = story || {};\n  const { docs = {} } = parameters;\n  const storyParameters = (docs.story || {}) as StoryParameters & { iframeHeight?: string };\n\n  if (docs.disable) {\n    return null as any;\n  }\n\n  // prefer block props, then story parameters defined by the framework-specific settings\n  // and optionally overridden by users\n\n  const inline = props.inline ?? storyParameters.inline ?? false;\n\n  if (inline) {\n    const height = props.height ?? storyParameters.height;\n    const autoplay = props.autoplay ?? storyParameters.autoplay ?? false;\n    return {\n      story: story as any,\n      inline: true,\n      height,\n      autoplay,\n      forceInitialArgs: !!props.__forceInitialArgs,\n      primary: !!props.__primary,\n      renderStoryToElement: context.renderStoryToElement as any,\n    };\n  }\n\n  const height = props.height ?? storyParameters.height ?? storyParameters.iframeHeight ?? '100px';\n  return {\n    story: story as any,\n    inline: false,\n    height,\n\n    primary: !!props.__primary,\n  };\n};\n\nconst StoryImpl: FC<StoryProps> = (props = { __forceInitialArgs: false, __primary: false }) => {\n  const context = useContext(DocsContext);\n  const storyId = getStoryId(props, context);\n  const story = useStory(storyId, context);\n\n  if (!story) {\n    return <StorySkeleton />;\n  }\n\n  const storyProps = getStoryProps(props, story, context);\n  if (!storyProps) {\n    return null;\n  }\n\n  return <PureStory {...storyProps} />;\n};\n\nexport const Story = withMdxComponentOverride('Story', StoryImpl);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Subheading.tsx",
    "content": "import type { FC, PropsWithChildren } from 'react';\nimport React from 'react';\n\nimport { H3 } from 'storybook/internal/components';\n\nimport type { HeadingProps } from './Heading';\nimport { slugs } from './Heading';\nimport { HeaderMdx } from './mdx';\nimport { withMdxComponentOverride } from './with-mdx-component-override';\n\nconst SubheadingImpl: FC<PropsWithChildren<HeadingProps>> = ({ children, disableAnchor }) => {\n  if (disableAnchor || typeof children !== 'string') {\n    return <H3>{children}</H3>;\n  }\n  const tagID = slugs.slug(children.toLowerCase());\n  return (\n    <HeaderMdx as=\"h3\" id={tagID}>\n      {children}\n    </HeaderMdx>\n  );\n};\n\nexport const Subheading = withMdxComponentOverride('Subheading', SubheadingImpl);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Subtitle.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport * as DefaultButtonStories from '../examples/Button.stories';\nimport * as ButtonStoriesWithMetaSubtitleAsBoth from '../examples/ButtonWithMetaSubtitleAsBoth.stories';\nimport * as ButtonStoriesWithMetaSubtitleAsComponentSubtitle from '../examples/ButtonWithMetaSubtitleAsComponentSubtitle.stories';\nimport * as ButtonStoriesWithMetaSubtitleAsDocsSubtitle from '../examples/ButtonWithMetaSubtitleAsDocsSubtitle.stories';\nimport { Subtitle } from './Subtitle';\n\nconst meta: Meta<typeof Subtitle> = {\n  component: Subtitle,\n  parameters: {\n    layout: 'fullscreen',\n    controls: {\n      include: [],\n      hideNoControlsWarning: true,\n    },\n    // workaround for https://github.com/storybookjs/storybook/issues/20505\n    docs: { source: { type: 'code' } },\n    attached: false,\n    docsStyles: true,\n  },\n};\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const OfCSFFileAsBoth: Story = {\n  args: {\n    of: ButtonStoriesWithMetaSubtitleAsBoth,\n  },\n  parameters: {\n    relativeCsfPaths: ['../examples/ButtonWithMetaSubtitleAsBoth.stories'],\n  },\n};\nexport const OfCSFFileAsComponentSubtitle: Story = {\n  name: 'Of CSF File As parameters.componentSubtitle',\n  args: {\n    of: ButtonStoriesWithMetaSubtitleAsComponentSubtitle,\n  },\n  parameters: {\n    relativeCsfPaths: ['../examples/ButtonWithMetaSubtitleAsComponentSubtitle.stories'],\n  },\n};\nexport const OfCSFFileAsDocsSubtitle: Story = {\n  name: 'Of CSF File As parameters.docs.subtitle',\n  args: {\n    of: ButtonStoriesWithMetaSubtitleAsDocsSubtitle,\n  },\n  parameters: {\n    relativeCsfPaths: ['../examples/ButtonWithMetaSubtitleAsDocsSubtitle.stories'],\n  },\n};\nexport const OfMetaAsBoth: Story = {\n  args: {\n    of: ButtonStoriesWithMetaSubtitleAsBoth.default,\n  },\n  parameters: {\n    relativeCsfPaths: ['../examples/ButtonWithMetaSubtitleAsBoth.stories'],\n  },\n};\nexport const OfMetaAsComponentSubtitle: Story = {\n  name: 'Of Meta As parameters.componentSubtitle',\n  args: {\n    of: ButtonStoriesWithMetaSubtitleAsComponentSubtitle.default,\n  },\n  parameters: {\n    relativeCsfPaths: ['../examples/ButtonWithMetaSubtitleAsComponentSubtitle.stories'],\n  },\n};\nexport const OfMetaAsDocsSubtitle: Story = {\n  name: 'Of Meta As parameters.docs.subtitle',\n  args: {\n    of: ButtonStoriesWithMetaSubtitleAsDocsSubtitle.default,\n  },\n  parameters: {\n    relativeCsfPaths: ['../examples/ButtonWithMetaSubtitleAsDocsSubtitle.stories'],\n  },\n};\nexport const DefaultAttached: Story = {\n  parameters: { relativeCsfPaths: ['../examples/Button.stories'], attached: true },\n};\nexport const OfUndefinedAttached: Story = {\n  args: {\n    // @ts-expect-error this is supposed to be undefined\n    of: DefaultButtonStories.NotDefined,\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n    relativeCsfPaths: ['../examples/Button.stories'],\n    attached: true,\n  },\n  tags: ['!test'],\n};\nexport const OfStringMetaAttached: Story = {\n  name: 'Of \"meta\" Attached',\n  args: {\n    of: 'meta',\n  },\n  parameters: { relativeCsfPaths: ['../examples/Button.stories'], attached: true },\n};\nexport const Children: Story = {\n  parameters: { relativeCsfPaths: ['../examples/Button.stories'], attached: false },\n  render: () => <Subtitle>This subtitle is a string passed as a children</Subtitle>,\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Subtitle.tsx",
    "content": "import type { FunctionComponent, ReactNode } from 'react';\nimport React from 'react';\n\nimport { deprecate } from 'storybook/internal/client-logger';\n\nimport { Subtitle as PureSubtitle } from '../components';\nimport type { Of } from './useOf';\nimport { useOf } from './useOf';\nimport { withMdxComponentOverride } from './with-mdx-component-override';\n\ninterface SubtitleProps {\n  children?: ReactNode;\n  /**\n   * Specify where to get the subtitle from. If not specified, the subtitle will be extracted from\n   * the meta of the attached CSF file.\n   */\n  of?: Of;\n}\n\nconst DEPRECATION_MIGRATION_LINK =\n  'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#subtitle-block-and-parameterscomponentsubtitle';\n\nconst SubtitleImpl: FunctionComponent<SubtitleProps> = (props) => {\n  const { of, children } = props;\n\n  if ('of' in props && of === undefined) {\n    throw new Error('Unexpected `of={undefined}`, did you mistype a CSF file reference?');\n  }\n\n  let preparedMeta;\n  try {\n    preparedMeta = useOf(of || 'meta', ['meta']).preparedMeta;\n  } catch (error: unknown) {\n    if (children && !(error as Error).message.includes('did you forget to use <Meta of={} />?')) {\n      // ignore error about unattached CSF since we can still render children\n      throw error;\n    }\n  }\n\n  const { componentSubtitle, docs } = preparedMeta?.parameters || {};\n\n  if (componentSubtitle) {\n    deprecate(\n      `Using 'parameters.componentSubtitle' property to subtitle stories is deprecated. See ${DEPRECATION_MIGRATION_LINK}`\n    );\n  }\n\n  const content = children || docs?.subtitle || componentSubtitle;\n\n  return content ? (\n    <PureSubtitle className=\"sbdocs-subtitle sb-unstyled\">{content}</PureSubtitle>\n  ) : null;\n};\n\nexport const Subtitle = withMdxComponentOverride('Subtitle', SubtitleImpl);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Title.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport * as DefaultButtonStories from '../examples/Button.stories';\nimport { Title } from './Title';\n\nconst meta: Meta<typeof Title> = {\n  component: Title,\n  title: 'Blocks/Title',\n  parameters: {\n    layout: 'fullscreen',\n    controls: {\n      include: [],\n      hideNoControlsWarning: true,\n    },\n    // workaround for https://github.com/storybookjs/storybook/issues/20505\n    docs: { source: { type: 'code' } },\n    attached: false,\n    docsStyles: true,\n  },\n};\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const OfCSFFile: Story = {\n  args: {\n    of: DefaultButtonStories,\n  },\n  parameters: { relativeCsfPaths: ['../examples/Button.stories'] },\n};\n\nexport const OfMeta: Story = {\n  args: {\n    of: DefaultButtonStories,\n  },\n  parameters: { relativeCsfPaths: ['../examples/Button.stories'] },\n};\n\nexport const OfStringMetaAttached: Story = {\n  name: 'Of attached \"meta\"',\n  args: {\n    of: 'meta',\n  },\n  parameters: { relativeCsfPaths: ['../examples/Button.stories'], attached: true },\n};\n\nexport const Children: Story = {\n  args: {\n    children: 'Title as children',\n  },\n  parameters: { relativeCsfPaths: ['../examples/Button.stories'], attached: false },\n};\n\nexport const DefaultAttached: Story = {\n  args: {},\n  parameters: { relativeCsfPaths: ['../examples/Button.stories'], attached: true },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Title.tsx",
    "content": "import type { FunctionComponent, ReactNode } from 'react';\nimport React from 'react';\n\nimport type { ComponentTitle } from 'storybook/internal/types';\n\nimport { Title as PureTitle } from '../components';\nimport type { Of } from './useOf';\nimport { useOf } from './useOf';\nimport { withMdxComponentOverride } from './with-mdx-component-override';\n\ninterface TitleProps {\n  /**\n   * Specify where to get the title from. Must be a CSF file's default export. If not specified, the\n   * title will be read from children, or extracted from the meta of the attached CSF file.\n   */\n  of?: Of;\n\n  /** Specify content to display as the title. */\n  children?: ReactNode;\n}\n\nconst STORY_KIND_PATH_SEPARATOR = /\\s*\\/\\s*/;\n\nexport const extractTitle = (title: ComponentTitle) => {\n  const groups = title.trim().split(STORY_KIND_PATH_SEPARATOR);\n  return groups?.[groups?.length - 1] || title;\n};\n\nconst TitleImpl: FunctionComponent<TitleProps> = (props) => {\n  const { children, of } = props;\n\n  if ('of' in props && of === undefined) {\n    throw new Error('Unexpected `of={undefined}`, did you mistype a CSF file reference?');\n  }\n\n  let preparedMeta;\n  try {\n    preparedMeta = useOf(of || 'meta', ['meta']).preparedMeta;\n  } catch (error: unknown) {\n    if (\n      children &&\n      error instanceof Error &&\n      !error.message.includes('did you forget to use <Meta of={} />?')\n    ) {\n      // ignore error about unattached CSF since we can still render children\n      throw error;\n    }\n  }\n\n  const content = children || extractTitle(preparedMeta?.title || '');\n\n  return content ? <PureTitle className=\"sbdocs-title sb-unstyled\">{content}</PureTitle> : null;\n};\n\nexport const Title = withMdxComponentOverride('Title', TitleImpl);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Unstyled.mdx",
    "content": "import { Unstyled } from './Unstyled';\n\n# The Unstyled Block\n\nBy default most elements in docs have a few default styles applied to ensure the docs look good. This is achieved by applying default styles to most elements like `h1`, `p`, etc..\nHowever sometimes you might want some of your content to not have these styles applied, this is where the `Unstyled` block is useful. Wrap any content you want in the `Unstyled` block to remove the default styles:\n\n```md\nimport { Unstyled } from '@storybook/addon-docs/blocks';\n\n# This heading will be styled\n\n<h2>So will this subheading</h2>\n\n> This block quote will be styled\n\n... and so will this paragraph.\n\n<Unstyled>\n  # This heading will not be styled\n\n  <h2>Neither will this subheading</h2>\n\n  > This block quote will not be styled\n\n  ... neither will this paragraph, nor the following component:\n  <MyCustomComponent />\n</Unstyled>\n```\n\nYields: \n\n# This heading will be styled\n\n<h2>So will this subheading</h2>\n\n> This block quote will be styled\n\n... and so will this paragraph.\n\n<Unstyled>\n  # This heading will not be styled\n\n  <h2>Neither will this subheading</h2>\n\n  > This block quote will not be styled\n\n  ... neither will this paragraph, nor the following component:\n</Unstyled>\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Unstyled.tsx",
    "content": "import React from 'react';\n\nimport { withMdxComponentOverride } from './with-mdx-component-override';\n\nconst UnstyledImpl: React.FC<\n  React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>\n> = (props) => <div {...props} className=\"sb-unstyled\" />;\n\nexport const Unstyled = withMdxComponentOverride('Unstyled', UnstyledImpl);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/Wrapper.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { withMdxComponentOverride } from './with-mdx-component-override';\n\nconst WrapperImpl: FC<\n  React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>\n> = ({ children }) => <div style={{ fontFamily: 'sans-serif' }}>{children}</div>;\n\nexport const Wrapper = withMdxComponentOverride('Wrapper', WrapperImpl);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/external/ExternalDocs.tsx",
    "content": "import type { PropsWithChildren } from 'react';\nimport React, { useRef } from 'react';\n\nimport type { ProjectAnnotations, Renderer } from 'storybook/internal/types';\n\nimport { composeConfigs } from 'storybook/preview-api';\n\nimport { Docs } from '../Docs';\nimport { ExternalPreview } from './ExternalPreview';\n\nexport type ExternalDocsProps<TRenderer extends Renderer = Renderer> = {\n  projectAnnotationsList: ProjectAnnotations<TRenderer>[];\n};\n\nfunction usePreview<TRenderer extends Renderer = Renderer>(\n  projectAnnotations: ProjectAnnotations<TRenderer>\n) {\n  const previewRef = useRef<ExternalPreview<TRenderer>>();\n\n  if (!previewRef.current) {\n    previewRef.current = new ExternalPreview<TRenderer>(projectAnnotations);\n  }\n  return previewRef.current;\n}\n\nexport function ExternalDocs<TRenderer extends Renderer = Renderer>({\n  projectAnnotationsList,\n  children,\n}: PropsWithChildren<ExternalDocsProps<TRenderer>>) {\n  const projectAnnotations = composeConfigs<TRenderer>(projectAnnotationsList);\n  const preview = usePreview<TRenderer>(projectAnnotations);\n  const docsParameter = {\n    ...projectAnnotations.parameters?.docs,\n    page: () => children,\n  };\n\n  const TDocs = Docs as typeof Docs<TRenderer>;\n\n  return <TDocs docsParameter={docsParameter} context={preview.docsContext()} />;\n}\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/external/ExternalDocsContainer.tsx",
    "content": "import React from 'react';\n\nimport type { Renderer } from 'storybook/internal/types';\n\nimport { ThemeProvider, ensure, themes } from 'storybook/theming';\n\nimport { DocsContext } from '../DocsContext';\nimport { ExternalPreview } from './ExternalPreview';\n\nlet preview: ExternalPreview<Renderer>;\n\nexport const ExternalDocsContainer: React.FC<\n  React.PropsWithChildren<{ projectAnnotations: any }>\n> = ({ projectAnnotations, children }) => {\n  if (!preview) {\n    preview = new ExternalPreview(projectAnnotations);\n  }\n\n  return (\n    <DocsContext.Provider value={preview.docsContext()}>\n      <ThemeProvider theme={ensure(themes.light)}>{children}</ThemeProvider>\n    </DocsContext.Provider>\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/external/ExternalDocsContext.ts",
    "content": "import type { CSFFile, DocsContextProps, ModuleExports, Renderer } from 'storybook/internal/types';\n\nimport { DocsContext } from 'storybook/preview-api';\nimport type { StoryStore } from 'storybook/preview-api';\n\nexport class ExternalDocsContext<TRenderer extends Renderer> extends DocsContext<TRenderer> {\n  constructor(\n    public channel: DocsContext<TRenderer>['channel'],\n    protected store: StoryStore<TRenderer>,\n    public renderStoryToElement: DocsContextProps<TRenderer>['renderStoryToElement'],\n    private processMetaExports: (metaExports: ModuleExports) => CSFFile<TRenderer>\n  ) {\n    super(\n      channel,\n      store,\n      renderStoryToElement as DocsContextProps<TRenderer>['renderStoryToElement'],\n      []\n    );\n  }\n\n  referenceMeta = (metaExports: ModuleExports, attach: boolean) => {\n    const csfFile = this.processMetaExports(metaExports);\n    this.referenceCSFFile(csfFile);\n    super.referenceMeta(metaExports, attach);\n  };\n}\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/external/ExternalPreview.ts",
    "content": "import { Channel } from 'storybook/internal/channels';\nimport type {\n  ComponentTitle,\n  ModuleExports,\n  Path,\n  ProjectAnnotations,\n  Renderer,\n  StoryIndex,\n} from 'storybook/internal/types';\n\nimport { Preview, composeConfigs } from 'storybook/preview-api';\n\nimport { ExternalDocsContext } from './ExternalDocsContext';\n\ntype MetaExports = ModuleExports;\n\nclass ConstantMap<TKey, TValue extends string> {\n  entries = new Map<TKey, TValue>();\n\n  constructor(private prefix: string) {}\n\n  get(key: TKey) {\n    if (!this.entries.has(key)) {\n      this.entries.set(key, `${this.prefix}${this.entries.size}` as TValue);\n    }\n    return this.entries.get(key);\n  }\n}\n\nexport class ExternalPreview<TRenderer extends Renderer = Renderer> extends Preview<TRenderer> {\n  private importPaths = new ConstantMap<MetaExports, Path>('./importPath/');\n\n  private titles = new ConstantMap<MetaExports, ComponentTitle>('title-');\n\n  private storyIndex: StoryIndex = { v: 5, entries: {} };\n\n  private moduleExportsByImportPath: Record<Path, ModuleExports> = {};\n\n  constructor(public projectAnnotations: ProjectAnnotations<TRenderer>) {\n    const importFn = (path: Path) => {\n      return Promise.resolve(this.moduleExportsByImportPath[path]);\n    };\n    const getProjectAnnotations = () =>\n      composeConfigs<TRenderer>([\n        { parameters: { docs: { story: { inline: true } } } },\n        this.projectAnnotations,\n      ]);\n    super(importFn, getProjectAnnotations, new Channel({}));\n  }\n\n  async getStoryIndexFromServer() {\n    return this.storyIndex;\n  }\n\n  processMetaExports = (metaExports: MetaExports) => {\n    const importPath = this.importPaths.get(metaExports)!;\n    this.moduleExportsByImportPath[importPath] = metaExports;\n\n    const title = metaExports.default.title || this.titles.get(metaExports)!;\n\n    const csfFile = this.storyStoreValue!.processCSFFileWithCache<TRenderer>(\n      metaExports,\n      importPath,\n      title\n    );\n\n    Object.values(csfFile.stories).forEach(({ id, name }) => {\n      this.storyIndex.entries[id] = {\n        id,\n        importPath,\n        title,\n        name,\n        type: 'story',\n        subtype: 'story',\n      };\n    });\n\n    // TODO: We probably need to do something here about story tests\n    this.onStoriesChanged({ storyIndex: this.storyIndex });\n\n    return csfFile;\n  };\n\n  docsContext = () => {\n    return new ExternalDocsContext(\n      this.channel,\n      this.storyStoreValue!,\n      this.renderStoryToElement.bind(this),\n      this.processMetaExports.bind(this)\n    );\n  };\n}\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/index.ts",
    "content": "export { ColorPalette, ColorItem, IconGallery, IconItem, Typeset } from '../components';\n\nexport * from './Anchor';\nexport * from './ArgTypes';\nexport * from './Canvas';\nexport * from './Controls';\nexport * from './Description';\nexport * from './Docs';\nexport * from './DocsContext';\nexport * from './DocsPage';\nexport * from './DocsContainer';\nexport * from './DocsStory';\nexport * from './external/ExternalDocs';\nexport * from './external/ExternalDocsContainer';\nexport * from './Heading';\nexport * from './Markdown';\nexport * from './Meta';\nexport * from './Primary';\nexport * from './Source';\nexport * from './SourceContainer';\nexport * from './Stories';\nexport * from './Story';\nexport * from './Subheading';\nexport * from './Subtitle';\nexport * from './Title';\nexport * from './Unstyled';\nexport * from './Wrapper';\n\nexport * from './useOf';\nexport * from './types';\nexport * from './mdx';\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/internal/README.md",
    "content": "# Internal `@storybook/blocks` Stories\n\nThis directory contains stories that are not suitable for public documentation, but that we still want to keep to ensure things don't break.\n\nSome blocks have deprecated features that users shouldn't use moving forward, and these internal stories represents those.\nThat way we can still test them and ensure the features work, until they are removed for good.\n\nThis directory is not part of the (public) Blocks Storybook, but are included in the full UI Storybook.\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/mdx.tsx",
    "content": "import type { FC, MouseEvent, PropsWithChildren, SyntheticEvent } from 'react';\nimport React, { useContext } from 'react';\n\nimport type { SupportedLanguage } from 'storybook/internal/components';\nimport { Code, components, nameSpaceClassNames } from 'storybook/internal/components';\nimport { NAVIGATE_URL } from 'storybook/internal/core-events';\n\nimport { LinkIcon } from '@storybook/icons';\n\nimport { styled } from 'storybook/theming';\n\nimport { Source } from '../components';\nimport type { DocsContextProps } from './DocsContext';\nimport { DocsContext } from './DocsContext';\n\nconst { document } = globalThis;\n\n// Hacky utility for asserting identifiers in MDX Story elements\nexport const assertIsFn = (val: any) => {\n  if (typeof val !== 'function') {\n    throw new Error(`Expected story function, got: ${val}`);\n  }\n  return val;\n};\n\n// Hacky utility for adding mdxStoryToId to the default context\nexport const AddContext: FC<PropsWithChildren<DocsContextProps>> = (props) => {\n  const { children, ...rest } = props;\n  const parentContext = React.useContext(DocsContext);\n  return (\n    <DocsContext.Provider value={{ ...parentContext, ...rest }}>{children}</DocsContext.Provider>\n  );\n};\n\ninterface CodeOrSourceMdxProps {\n  className?: string;\n}\n\nexport const CodeOrSourceMdx: FC<PropsWithChildren<CodeOrSourceMdxProps>> = ({\n  className,\n  children,\n  ...rest\n}) => {\n  // markdown-to-jsx does not add className to inline code\n  if (\n    typeof className !== 'string' &&\n    (typeof children !== 'string' || !(children as string).match(/[\\n\\r]/g))\n  ) {\n    return <Code>{children}</Code>;\n  }\n  // className: \"lang-jsx\"\n  const language = className && className.split('-');\n  return (\n    <Source\n      language={((language && language[1]) as SupportedLanguage) || 'text'}\n      format={false}\n      code={children as string}\n      {...rest}\n    />\n  );\n};\n\nfunction navigate(context: DocsContextProps, url: string) {\n  context.channel.emit(NAVIGATE_URL, url);\n}\n\nconst A = components.a;\n\ninterface AnchorInPageProps {\n  hash: string;\n}\n\nconst AnchorInPage: FC<PropsWithChildren<AnchorInPageProps>> = ({ hash, children }) => {\n  const context = useContext(DocsContext);\n\n  return (\n    <A\n      href={hash}\n      target=\"_self\"\n      onClick={(event: SyntheticEvent) => {\n        const id = hash.substring(1);\n        const element = document.getElementById(id);\n        if (element) {\n          navigate(context, hash);\n        }\n      }}\n    >\n      {children}\n    </A>\n  );\n};\n\ninterface AnchorMdxProps {\n  href: string;\n  target: string;\n}\n\nexport const AnchorMdx: FC<PropsWithChildren<AnchorMdxProps>> = (props) => {\n  const { href, target, children, ...rest } = props;\n  const context = useContext(DocsContext);\n\n  // links to external locations don't need any modifications.\n  if (!href || target === '_blank' || /^https?:\\/\\//.test(href)) {\n    return <A {...props} />;\n  }\n\n  // Enable scrolling for in-page anchors.\n  if (href.startsWith('#')) {\n    return <AnchorInPage hash={href}>{children}</AnchorInPage>;\n  }\n\n  // Links to other pages of SB should use the base URL of the top level iframe instead of the base URL of the preview iframe.\n  return (\n    <A\n      href={href}\n      onClick={(event: MouseEvent<HTMLAnchorElement>) => {\n        // Cmd/Ctrl/Shift/Alt + Click should trigger default browser behaviour. Same applies to non-left clicks\n        const LEFT_BUTTON = 0;\n        const isLeftClick =\n          event.button === LEFT_BUTTON &&\n          !event.altKey &&\n          !event.ctrlKey &&\n          !event.metaKey &&\n          !event.shiftKey;\n\n        if (isLeftClick) {\n          event.preventDefault();\n          // use the A element's href, which has been modified for\n          // local paths without a `?path=` query param prefix\n          navigate(context, event.currentTarget.getAttribute('href') || '');\n        }\n      }}\n      target={target}\n      {...rest}\n    >\n      {children}\n    </A>\n  );\n};\n\nconst SUPPORTED_MDX_HEADERS = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] as const;\n\nconst OcticonHeaders = SUPPORTED_MDX_HEADERS.reduce(\n  (acc, headerType) => ({\n    ...acc,\n    [headerType]: styled(headerType)({\n      '& svg': {\n        position: 'relative',\n        top: '-0.1em',\n        visibility: 'hidden',\n      },\n      '&:hover svg': {\n        visibility: 'visible',\n      },\n    }),\n  }),\n  {}\n);\n\nconst OcticonAnchor = styled.a(\n  () =>\n    ({\n      float: 'left',\n      lineHeight: 'inherit',\n      paddingRight: '10px',\n      marginLeft: '-24px',\n      // Allow the theme's text color to override the default link color.\n      color: 'inherit',\n    }) as const\n);\n\ninterface HeaderWithOcticonAnchorProps {\n  as: string;\n  id: string;\n}\n\nconst HeaderWithOcticonAnchor: FC<PropsWithChildren<HeaderWithOcticonAnchorProps>> = ({\n  as,\n  id,\n  children,\n  ...rest\n}) => {\n  const context = useContext(DocsContext);\n\n  // @ts-expect-error (Converted from ts-ignore)\n  const OcticonHeader = OcticonHeaders[as];\n  const hash = `#${id}`;\n\n  return (\n    <OcticonHeader id={id} {...rest}>\n      <OcticonAnchor\n        aria-hidden=\"true\"\n        href={hash}\n        tabIndex={-1}\n        target=\"_self\"\n        onClick={(event: SyntheticEvent) => {\n          const element = document.getElementById(id);\n          if (element) {\n            navigate(context, hash);\n          }\n        }}\n      >\n        <LinkIcon />\n      </OcticonAnchor>\n      {children}\n    </OcticonHeader>\n  );\n};\n\ninterface HeaderMdxProps {\n  as: string;\n  id: string;\n}\n\nexport const HeaderMdx: FC<PropsWithChildren<HeaderMdxProps>> = (props) => {\n  const { as, id, children, ...rest } = props;\n\n  // An id should have been added on every header by the \"remark-slug\" plugin.\n  if (id) {\n    return (\n      <HeaderWithOcticonAnchor as={as} id={id} {...rest}>\n        {children}\n      </HeaderWithOcticonAnchor>\n    );\n  }\n  // Make sure it still work if \"remark-slug\" plugin is not present.\n  const Component = as as React.ElementType;\n  const { as: omittedAs, ...withoutAs } = props;\n  return <Component {...nameSpaceClassNames(withoutAs, as)} />;\n};\n\nexport const HeadersMdx = SUPPORTED_MDX_HEADERS.reduce(\n  (acc, headerType) => ({\n    ...acc,\n    // @ts-expect-error (Converted from ts-ignore)\n    [headerType]: (props: object) => <HeaderMdx as={headerType} {...props} />,\n  }),\n  {}\n);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/types.ts",
    "content": "import type { ModuleExport } from 'storybook/internal/types';\n\nexport const PRIMARY_STORY = '^';\n\n// TODO\n\nexport type Component = any;\n\nexport type DocsStoryProps = {\n  of: ModuleExport;\n  expanded?: boolean;\n  withToolbar?: boolean;\n  __forceInitialArgs?: boolean;\n  __primary?: boolean;\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/useArgs.ts",
    "content": "import { useCallback, useEffect, useState } from 'react';\n\nimport {\n  RESET_STORY_ARGS,\n  STORY_ARGS_UPDATED,\n  UPDATE_STORY_ARGS,\n} from 'storybook/internal/core-events';\nimport type { Args, DocsContextProps, PreparedStory } from 'storybook/internal/types';\n\nexport const useArgs = (\n  story: PreparedStory,\n  context: DocsContextProps\n): [Args, (args: Args) => void, (argNames?: string[]) => void] => {\n  const result = useArgsIfDefined(story, context);\n\n  if (!result) {\n    throw new Error('No result when story was defined');\n  }\n  return result;\n};\n\nexport const useArgsIfDefined = (\n  story: PreparedStory | void,\n  context: DocsContextProps\n): [Args, (args: Args) => void, (argNames?: string[]) => void] | void => {\n  const storyContext = story ? context.getStoryContext(story) : { args: {} };\n  const { id: storyId } = story || { id: 'none' };\n\n  const [args, setArgs] = useState(storyContext.args);\n  useEffect(() => {\n    const onArgsUpdated = (changed: { storyId: string; args: Args }) => {\n      if (changed.storyId === storyId) {\n        setArgs(changed.args);\n      }\n    };\n    context.channel.on(STORY_ARGS_UPDATED, onArgsUpdated);\n    return () => context.channel.off(STORY_ARGS_UPDATED, onArgsUpdated);\n  }, [storyId, context.channel]);\n  const updateArgs = useCallback(\n    (updatedArgs: any) => context.channel.emit(UPDATE_STORY_ARGS, { storyId, updatedArgs }),\n    [storyId, context.channel]\n  );\n  const resetArgs = useCallback(\n    (argNames?: string[]) => context.channel.emit(RESET_STORY_ARGS, { storyId, argNames }),\n    [storyId, context.channel]\n  );\n  return story && [args, updateArgs, resetArgs];\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/useGlobals.ts",
    "content": "import { useEffect, useState } from 'react';\n\nimport { GLOBALS_UPDATED } from 'storybook/internal/core-events';\nimport type { Globals } from 'storybook/internal/csf';\nimport type { DocsContextProps, PreparedStory } from 'storybook/internal/types';\n\nexport const useGlobals = (story: PreparedStory, context: DocsContextProps): [Globals] => {\n  const storyContext = context.getStoryContext(story);\n\n  const [globals, setGlobals] = useState(storyContext.globals);\n  useEffect(() => {\n    const onGlobalsUpdated = (changed: { globals: Globals }) => {\n      setGlobals(changed.globals);\n    };\n    context.channel.on(GLOBALS_UPDATED, onGlobalsUpdated);\n    return () => context.channel.off(GLOBALS_UPDATED, onGlobalsUpdated);\n  }, [context.channel]);\n\n  return [globals];\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/useOf.ts",
    "content": "import { useContext } from 'react';\n\nimport type {\n  DocsContextProps,\n  ResolvedModuleExportFromType,\n  ResolvedModuleExportType,\n} from 'storybook/internal/types';\n\nimport { DocsContext } from './DocsContext';\n\nexport type Of = Parameters<DocsContextProps['resolveOf']>[0];\n\n/**\n * A hook to resolve the `of` prop passed to a block. will return the resolved module if the\n * resolved module is a meta it will include a preparedMeta property similar to a preparedStory if\n * the resolved module is a component it will include the project annotations\n */\nexport const useOf = <TType extends ResolvedModuleExportType>(\n  moduleExportOrType: Of,\n  validTypes?: TType[]\n): ResolvedModuleExportFromType<TType> => {\n  const context = useContext(DocsContext);\n  return context.resolveOf(moduleExportOrType, validTypes);\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/usePrimaryStory.test.tsx",
    "content": "// @vitest-environment happy-dom\nimport { renderHook } from '@testing-library/react';\nimport { describe, expect, it, vi } from 'vitest';\n\nimport React from 'react';\nimport type { FC, PropsWithChildren } from 'react';\n\nimport { Tag } from 'storybook/internal/core-server';\nimport type { PreparedStory } from 'storybook/internal/types';\n\nimport type { DocsContextProps } from './DocsContext';\nimport { DocsContext } from './DocsContext';\nimport { usePrimaryStory } from './usePrimaryStory';\n\nconst stories: Record<string, Partial<PreparedStory>> = {\n  story1: { name: 'Story One', tags: [`!${Tag.AUTODOCS}`] },\n  story2: { name: 'Story Two', tags: [Tag.AUTODOCS] },\n  story3: { name: 'Story Three', tags: [Tag.AUTODOCS] },\n  story4: { name: 'Story Four', tags: [] },\n};\n\nconst createMockContext = (storyList: PreparedStory[]) => ({\n  componentStories: vi.fn(() => storyList),\n});\n\nconst Wrapper: FC<PropsWithChildren<{ context: Partial<DocsContextProps> }>> = ({\n  children,\n  context,\n}) => <DocsContext.Provider value={context as DocsContextProps}>{children}</DocsContext.Provider>;\n\ndescribe('usePrimaryStory', () => {\n  it('ignores !autodocs stories', () => {\n    const mockContext = createMockContext([\n      stories.story1,\n      stories.story2,\n      stories.story3,\n    ] as PreparedStory[]);\n    const { result } = renderHook(() => usePrimaryStory(), {\n      wrapper: ({ children }) => <Wrapper context={mockContext}>{children}</Wrapper>,\n    });\n    expect(result.current?.name).toBe('Story Two');\n  });\n\n  it('selects the first autodocs story', () => {\n    const mockContext = createMockContext([stories.story2, stories.story3] as PreparedStory[]);\n    const { result } = renderHook(() => usePrimaryStory(), {\n      wrapper: ({ children }) => <Wrapper context={mockContext}>{children}</Wrapper>,\n    });\n    expect(result.current?.name).toBe('Story Two');\n  });\n\n  it('returns undefined if no story has \"autodocs\" tag', () => {\n    const mockContext = createMockContext([stories.story1, stories.story4] as PreparedStory[]);\n    const { result } = renderHook(() => usePrimaryStory(), {\n      wrapper: ({ children }) => <Wrapper context={mockContext}>{children}</Wrapper>,\n    });\n    expect(result.current).toBeUndefined();\n  });\n\n  it('returns undefined for empty story list', () => {\n    const mockContext = createMockContext([]);\n    const { result } = renderHook(() => usePrimaryStory(), {\n      wrapper: ({ children }) => <Wrapper context={mockContext}>{children}</Wrapper>,\n    });\n    expect(result.current).toBeUndefined();\n  });\n});\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/usePrimaryStory.ts",
    "content": "import { useContext } from 'react';\n\nimport { Tag } from 'storybook/internal/preview-api';\nimport type { PreparedStory } from 'storybook/internal/types';\n\nimport { DocsContext } from './DocsContext';\n\n/**\n * A hook to get the primary story for the current component's doc page. It defines the primary\n * story as the first story that includes the 'autodocs' tag\n */\nexport const usePrimaryStory = (): PreparedStory | undefined => {\n  const context = useContext(DocsContext);\n  const stories = context.componentStories();\n  return stories.find((story) => story.tags.includes(Tag.AUTODOCS));\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/useStory.ts",
    "content": "import { useEffect, useState } from 'react';\n\nimport type { PreparedStory, Renderer, StoryId } from 'storybook/internal/types';\n\nimport type { DocsContextProps } from './DocsContext';\n\nexport function useStory<TRenderer extends Renderer = Renderer>(\n  storyId: StoryId,\n  context: DocsContextProps<TRenderer>\n): PreparedStory<TRenderer> | void {\n  const stories = useStories([storyId], context);\n  return stories && stories[0];\n}\n\nexport function useStories<TRenderer extends Renderer = Renderer>(\n  storyIds: StoryId[],\n  context: DocsContextProps<TRenderer>\n): (PreparedStory<TRenderer> | void)[] {\n  // Legacy docs pages can reference any story by id. Those stories will need to be\n  // asynchronously loaded; we use the state for this\n  const [storiesById, setStories] = useState<Record<StoryId, PreparedStory<TRenderer>>>({});\n\n  useEffect(() => {\n    // deepscan-disable-next-line NO_EFFECT_CALL\n    Promise.all(\n      storyIds.map(async (storyId) => {\n        // loadStory will be called every single time useStory is called\n        // because useEffect does not use storyIds as an input. This is because\n        // HMR can change the story even when the storyId hasn't changed. However, it\n        // will be a no-op once the story has loaded. Furthermore, the `story` will\n        // have an exact equality when the story hasn't changed, so it won't trigger\n        // any unnecessary re-renders\n        const story = await context.loadStory(storyId);\n        setStories((current) =>\n          current[storyId] === story ? current : { ...current, [storyId]: story }\n        );\n      })\n    );\n  });\n\n  return storyIds.map((storyId) => {\n    if (storiesById[storyId]) {\n      return storiesById[storyId];\n    }\n\n    try {\n      // If we are allowed to load this story id synchonously, this will work\n      return context.storyById(storyId);\n    } catch (err) {\n      return undefined;\n    }\n  });\n}\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/useTransformCode.tsx",
    "content": "import { useEffect, useState } from 'react';\n\nimport type { Args, StoryContext } from 'storybook/internal/csf';\n\ntype ReducedStoryContext = Omit<\n  StoryContext<any, Args>,\n  'abortSignal' | 'canvasElement' | 'step' | 'context'\n>;\n\nexport function useTransformCode(\n  source: string,\n  transform: (code: string, storyContext: ReducedStoryContext) => string | Promise<string>,\n  storyContext: ReducedStoryContext\n) {\n  const [transformedCode, setTransformedCode] = useState('Transforming...');\n\n  const transformed = transform ? transform?.(source, storyContext) : source;\n\n  useEffect(() => {\n    async function getTransformedCode() {\n      const transformResult = await transformed;\n      if (transformResult !== transformedCode) {\n        setTransformedCode(transformResult);\n      }\n    }\n\n    getTransformedCode();\n  });\n\n  if (typeof transformed === 'object' && typeof transformed.then === 'function') {\n    return transformedCode;\n  }\n\n  return transformed as string;\n}\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/utils.ts",
    "content": "import type { Component } from './types';\n\nconst titleCase = (str: string): string =>\n  str\n    .split('-')\n    .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n    .join('');\n\nexport const getComponentName = (component: Component): string | undefined => {\n  if (!component) {\n    return undefined;\n  }\n\n  if (typeof component === 'string') {\n    if (component.includes('-')) {\n      return titleCase(component);\n    }\n    return component;\n  }\n  if (component.__docgenInfo && component.__docgenInfo.displayName) {\n    return component.__docgenInfo.displayName;\n  }\n\n  return component.name;\n};\n\nexport function scrollToElement(element: any, block = 'start') {\n  element.scrollIntoView({\n    behavior: 'smooth',\n    block,\n    inline: 'nearest',\n  });\n}\n"
  },
  {
    "path": "code/addons/docs/src/blocks/blocks/with-mdx-component-override.tsx",
    "content": "import type { ComponentType } from 'react';\nimport React from 'react';\n\nimport { useMDXComponents } from '@mdx-js/react';\n\nconst MDX_WRAPPED_BLOCK = Symbol('mdxWrappedBlock');\nconst MdxWrappedBlockContext = React.createContext<Set<string> | null>(null);\n\ntype WrappedBlockComponent<P extends object> = ComponentType<P> & {\n  [MDX_WRAPPED_BLOCK]?: true;\n};\n\n// Imported MDX doc blocks bypass MDXProvider in MDX2+, so this restores `docs.components` overrides.\nexport const withMdxComponentOverride = <P extends object>(\n  blockName: string,\n  Block: ComponentType<P>\n): ComponentType<P> => {\n  const WrappedBlock = (props: P) => {\n    // Some overrides intentionally compose with the public block export, e.g.\n    // `components.Title = (props) => <Title {...props} />`. Track which wrapped blocks are already\n    // being resolved so those recursive re-entries render the underlying block instead of looping\n    // back through the MDX override lookup forever.\n    const wrappedBlocks = React.useContext(MdxWrappedBlockContext);\n    const components = useMDXComponents();\n    const Override = components[blockName] as WrappedBlockComponent<P> | undefined;\n\n    if (wrappedBlocks?.has(blockName) || Override === WrappedBlock) {\n      return <Block {...props} />;\n    }\n\n    if (Override) {\n      const nextWrappedBlocks = new Set(wrappedBlocks ?? []);\n      nextWrappedBlocks.add(blockName);\n\n      return (\n        <MdxWrappedBlockContext.Provider value={nextWrappedBlocks}>\n          <Override {...props} />\n        </MdxWrappedBlockContext.Provider>\n      );\n    }\n\n    return <Block {...props} />;\n  };\n\n  WrappedBlock.displayName = blockName;\n  (WrappedBlock as WrappedBlockComponent<P>)[MDX_WRAPPED_BLOCK] = true;\n\n  return WrappedBlock;\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/component-overrides.mdx",
    "content": "import {\n  ArgTypes,\n  Canvas,\n  Controls,\n  Description,\n  DocsStory,\n  Heading,\n  Markdown,\n  Meta,\n  Primary,\n  Source,\n  Stories,\n  Story,\n  Subheading,\n  Subtitle,\n  Title,\n  Unstyled,\n  Wrapper,\n} from '@storybook/addon-docs/blocks';\nimport * as ComponentOverrideStories from './component-overrides.stories.tsx';\n\n<Meta of={ComponentOverrideStories} name=\"MDX\" />\n\n# Component override verification\n\nEvery block below should render its `override:*` marker rather than the default Storybook block UI.\nThe `Title` override intentionally renders `<Title />` again, so it also proves recursive composition does not loop infinitely.\n`Meta` is intentionally excluded because it is not overridable.\n\n<Title />\n<Subtitle />\n<Description of=\"meta\" />\n\n<Primary />\n<Controls />\n<ArgTypes />\n<Stories />\n<Story of={ComponentOverrideStories.UsesDefaultImplementation} />\n<Canvas of={ComponentOverrideStories.UsesDefaultImplementation} />\n<Source of={ComponentOverrideStories.UsesDefaultImplementation} />\n<DocsStory of={ComponentOverrideStories.UsesDefaultImplementation} />\n\n<Heading>Heading block</Heading>\n<Subheading>Subheading block</Subheading>\n\n<Markdown>\n  {`\n# Markdown block\n\nThis should render as the Markdown override.\n`}\n\n</Markdown>\n\n<Wrapper>\n  <div>Wrapper child content</div>\n</Wrapper>\n\n<Unstyled>\n  <div>Unstyled child content</div>\n</Unstyled>\n"
  },
  {
    "path": "code/addons/docs/src/blocks/component-overrides.stories.tsx",
    "content": "/**\n * These stories use JSX so they are not part of the template stories. Even though they _do_ work in\n * non-React frameworks, we are keeping them out of the sandboxes and only have them in the main UI\n * Storybook.\n */\nimport React from 'react';\nimport type { FC, ReactNode } from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Title as DocsTitle } from '@storybook/addon-docs/blocks';\n\nimport { MDXProvider } from '@mdx-js/react';\nimport { expect } from 'storybook/test';\n\nimport { withMdxComponentOverride } from './blocks/with-mdx-component-override';\n\ntype OverrideProps = {\n  children?: ReactNode;\n};\n\ntype TestBlockProps = {\n  label: string;\n};\n\nconst OverrideShell = ({ name, children }: { name: string; children?: ReactNode }) => (\n  <div\n    data-testid={`override-${name}`}\n    style={{\n      border: '2px solid #ff4785',\n      borderRadius: 6,\n      color: '#ff4785',\n      fontFamily: 'monospace',\n      margin: '8px 0',\n      padding: '8px 12px',\n    }}\n  >\n    override:{name}\n    {children ? <div style={{ marginTop: 8 }}>{children}</div> : null}\n  </div>\n);\n\nconst createOverride = (name: string, renderChildren = false): FC<OverrideProps> =>\n  function Override({ children }) {\n    return <OverrideShell name={name}>{renderChildren ? children : null}</OverrideShell>;\n  };\n\nconst RecursiveTitleOverride: FC<OverrideProps> = (props) => (\n  <OverrideShell name=\"Title (via <Title /> composition)\">\n    <DocsTitle {...props} />\n  </OverrideShell>\n);\n\nconst TestBlockImpl: FC<TestBlockProps> = ({ label }) => (\n  <span data-testid=\"default\">default:{label}</span>\n);\nconst TestBlock = withMdxComponentOverride('TestBlock', TestBlockImpl);\n\nconst SubtitleBlockImpl: FC<TestBlockProps> = ({ label }) => (\n  <span data-testid=\"subtitle\">subtitle:{label}</span>\n);\nconst SubtitleBlock = withMdxComponentOverride('SubtitleBlock', SubtitleBlockImpl);\n\nconst TestBlockOverride: FC<TestBlockProps> = ({ label }) => (\n  <span data-testid=\"override\">override:{label}</span>\n);\n\nconst RecursiveTestBlockOverride: FC<TestBlockProps> = (props) => <TestBlock {...props} />;\n\ntype TestBlockComponents = {\n  TestBlock: React.ComponentType<TestBlockProps>;\n};\n\nconst renderTestBlock = (components: TestBlockComponents | undefined) => (\n  <MDXProvider components={components as React.ComponentProps<typeof MDXProvider>['components']}>\n    <TestBlock label=\"Hello\" />\n  </MDXProvider>\n);\n\nconst meta = {\n  tags: ['autodocs'],\n  args: {\n    label: 'Primary action',\n  },\n  parameters: {\n    docs: {\n      name: 'ComponentOverrides',\n      subtitle: 'Subtitle supplied from docs parameters',\n      description: {\n        component: 'Component description used by the Description block.',\n      },\n      components: {\n        ArgTypes: createOverride('ArgTypes'),\n        Canvas: createOverride('Canvas'),\n        Controls: createOverride('Controls'),\n        Description: createOverride('Description'),\n        DocsStory: createOverride('DocsStory'),\n        Heading: createOverride('Heading', true),\n        Markdown: createOverride('Markdown', true),\n        Primary: createOverride('Primary'),\n        Source: createOverride('Source'),\n        Stories: createOverride('Stories'),\n        Story: createOverride('Story'),\n        Subheading: createOverride('Subheading', true),\n        Subtitle: createOverride('Subtitle'),\n        Title: RecursiveTitleOverride,\n        Unstyled: createOverride('Unstyled', true),\n        Wrapper: createOverride('Wrapper', true),\n      },\n    },\n  },\n} satisfies Meta<typeof TestBlock>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const UsesDefaultImplementation: Story = {\n  render: () => renderTestBlock(undefined),\n  play: async ({ canvas }) => {\n    await expect(canvas.findByTestId('default')).resolves.toHaveTextContent('default:Hello');\n  },\n};\n\nexport const UsesMdxOverride: Story = {\n  render: () => renderTestBlock({ TestBlock: TestBlockOverride }),\n  play: async ({ canvas }) => {\n    await expect(canvas.findByTestId('override')).resolves.toHaveTextContent('override:Hello');\n  },\n};\n\nexport const FallsBackWhenOverrideIsWrappedBlock: Story = {\n  render: () => renderTestBlock({ TestBlock }),\n  play: async ({ canvas }) => {\n    await expect(canvas.findByTestId('default')).resolves.toHaveTextContent('default:Hello');\n  },\n};\n\nexport const FallsBackWhenOverrideComposesPublicBlock: Story = {\n  render: () => renderTestBlock({ TestBlock: RecursiveTestBlockOverride }),\n  play: async ({ canvas }) => {\n    await expect(canvas.findByTestId('default')).resolves.toHaveTextContent('default:Hello');\n  },\n};\n\nexport const AllowsDifferentWrappedBlockOverride: Story = {\n  render: () => renderTestBlock({ TestBlock: SubtitleBlock }),\n  play: async ({ canvas }) => {\n    await expect(canvas.findByTestId('subtitle')).resolves.toHaveTextContent('subtitle:Hello');\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/ArgsTable/ArgControl.tsx",
    "content": "import type { FC } from 'react';\nimport React, { useCallback, useEffect, useState } from 'react';\n\nimport { Link } from 'storybook/internal/components';\n\nimport {\n  BooleanControl,\n  ColorControl,\n  DateControl,\n  FilesControl,\n  NumberControl,\n  ObjectControl,\n  OptionsControl,\n  RangeControl,\n  TextControl,\n} from '../../controls';\nimport type { ArgType, Args } from './types';\n\nexport interface ArgControlProps {\n  row: ArgType;\n  arg: any;\n  updateArgs: (args: Args) => void;\n  isHovered: boolean;\n  storyId?: string;\n}\n\nconst Controls: Record<string, FC<any>> = {\n  array: ObjectControl,\n  object: ObjectControl,\n  boolean: BooleanControl,\n  color: ColorControl,\n  date: DateControl,\n  number: NumberControl,\n  check: OptionsControl,\n  'inline-check': OptionsControl,\n  radio: OptionsControl,\n  'inline-radio': OptionsControl,\n  select: OptionsControl,\n  'multi-select': OptionsControl,\n  range: RangeControl,\n  text: TextControl,\n  file: FilesControl,\n};\n\nconst NoControl = () => <>-</>;\n\nexport const ArgControl: FC<ArgControlProps> = ({ row, arg, updateArgs, isHovered, storyId }) => {\n  const { key, control } = row;\n\n  const [isFocused, setFocused] = useState(false);\n  // box because arg can be a fn (e.g. actions) and useState calls fn's\n  const [boxedValue, setBoxedValue] = useState({ value: arg });\n\n  useEffect(() => {\n    if (!isFocused) {\n      setBoxedValue({ value: arg });\n    }\n  }, [isFocused, arg]);\n\n  const onChange = useCallback(\n    (argVal: any) => {\n      setBoxedValue({ value: argVal });\n      updateArgs({ [key]: argVal });\n      return argVal;\n    },\n    [updateArgs, key]\n  );\n\n  const onBlur = useCallback(() => setFocused(false), []);\n  const onFocus = useCallback(() => setFocused(true), []);\n\n  if (!control || control.disable) {\n    const canBeSetup = control?.disable !== true && row?.type?.name !== 'function';\n    return isHovered && canBeSetup ? (\n      <Link\n        href=\"https://storybook.js.org/docs/essentials/controls?ref=ui\"\n        target=\"_blank\"\n        withArrow\n      >\n        Setup controls\n      </Link>\n    ) : (\n      <NoControl />\n    );\n  }\n  // row.name is a display name and not a suitable DOM input id or name - i might contain whitespace etc.\n  // row.key is a hash key and therefore a much safer choice\n  const props = {\n    name: key,\n    storyId,\n    argType: row,\n    value: boxedValue.value,\n    onChange,\n    onBlur,\n    onFocus,\n  };\n  const Control = Controls[control.type] || NoControl;\n  return <Control {...props} {...control} controlType={control.type} />;\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/ArgsTable/ArgJsDoc.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { codeCommon } from 'storybook/internal/components';\n\nimport type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\nimport type { JsDocTags } from './types';\n\ninterface ArgJsDocArgs {\n  tags: JsDocTags;\n}\n\nexport const Table = styled.table(({ theme }) => ({\n  '&&': {\n    // Escape default table styles\n    borderCollapse: 'collapse',\n    borderSpacing: 0,\n    border: 'none',\n\n    tr: {\n      border: 'none !important',\n      background: 'none',\n    },\n\n    'td, th': {\n      padding: 0,\n      border: 'none',\n      width: 'auto!important',\n    },\n    // End escape\n\n    marginTop: 0,\n    marginBottom: 0,\n\n    'th:first-of-type, td:first-of-type': {\n      paddingLeft: 0,\n    },\n\n    'th:last-of-type, td:last-of-type': {\n      paddingRight: 0,\n    },\n\n    td: {\n      paddingTop: 0,\n      paddingBottom: 4,\n\n      '&:not(:first-of-type)': {\n        paddingLeft: 10,\n        paddingRight: 0,\n      },\n    },\n\n    tbody: {\n      boxShadow: 'none',\n      border: 'none',\n    },\n\n    code: codeCommon({ theme }) as CSSObject,\n\n    div: {\n      span: {\n        fontWeight: 'bold',\n      },\n    },\n\n    '& code': {\n      margin: 0,\n      display: 'inline-block',\n      fontSize: theme.typography.size.s1,\n    },\n  },\n}));\n\nexport const ArgJsDoc: FC<ArgJsDocArgs> = ({ tags }) => {\n  const params = (tags.params || []).filter((x) => x.description);\n  const hasDisplayableParams = params.length !== 0;\n  const hasDisplayableDeprecated = tags.deprecated != null;\n  const hasDisplayableReturns = tags.returns != null && tags.returns.description != null;\n\n  if (!hasDisplayableParams && !hasDisplayableReturns && !hasDisplayableDeprecated) {\n    return null;\n  }\n\n  return (\n    <>\n      <Table>\n        <tbody>\n          {hasDisplayableDeprecated && (\n            <tr key=\"deprecated\">\n              <td colSpan={2}>\n                <strong>Deprecated</strong>: {tags.deprecated?.toString()}\n              </td>\n            </tr>\n          )}\n          {hasDisplayableParams &&\n            params.map((x) => {\n              return (\n                <tr key={x.name}>\n                  <td>\n                    <code>{x.name}</code>\n                  </td>\n                  <td>{x.description}</td>\n                </tr>\n              );\n            })}\n          {hasDisplayableReturns && (\n            <tr key=\"returns\">\n              <td>\n                <code>Returns</code>\n              </td>\n              <td>{tags.returns?.description}</td>\n            </tr>\n          )}\n        </tbody>\n      </Table>\n    </>\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/ArgsTable/ArgRow.stories.tsx",
    "content": "import React from 'react';\n\nimport { ResetWrapper } from 'storybook/internal/components';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { expect, screen } from 'storybook/test';\n\nimport { ArgRow } from './ArgRow';\nimport { TableWrapper } from './ArgsTable';\n\nexport default {\n  component: ArgRow,\n  title: 'Components/ArgsTable/ArgRow',\n\n  decorators: [\n    (getStory) => (\n      <ResetWrapper>\n        <TableWrapper>\n          <tbody>{getStory()}</tbody>\n        </TableWrapper>\n      </ResetWrapper>\n    ),\n  ],\n  argTypes: {\n    updateArgs: { action: 'updateArgs' },\n  },\n} satisfies Meta<typeof ArgRow>;\n\nexport const String = {\n  args: {\n    row: {\n      key: 'someString',\n      name: 'Some String',\n      description: 'someString description',\n      type: {\n        required: true,\n      },\n      control: {\n        type: 'text',\n      },\n      table: {\n        type: {\n          summary: 'string',\n        },\n        defaultValue: {\n          summary: 'reallylongstringnospaces',\n        },\n      },\n    },\n  },\n};\n\nexport const LongName = {\n  args: {\n    row: { ...String.args.row, name: 'Really Long String That Takes Up Space' },\n  },\n};\n\nexport const LongDesc = {\n  args: {\n    row: {\n      ...String.args.row,\n      description: 'really long description that takes up a lot of space. sometimes this happens.',\n    },\n  },\n};\n\nexport const Boolean = {\n  args: {\n    row: {\n      key: 'someBoolean',\n      name: 'Some Boolean',\n      description: 'someBoolean description',\n      type: {\n        required: true,\n      },\n      control: {\n        type: 'boolean',\n      },\n      table: {\n        type: {\n          summary: 'string',\n        },\n        defaultValue: {\n          summary: 'fixme',\n        },\n      },\n    },\n  },\n};\n\nexport const Color = {\n  args: {\n    row: {\n      key: 'someColor',\n      name: 'Some Color',\n      type: {\n        name: 'string',\n      },\n      description: 'someColor description',\n      defaultValue: '#ff0',\n      control: {\n        type: 'color',\n      },\n    },\n  },\n};\n\nexport const Date = {\n  args: {\n    row: {\n      key: 'someDate',\n      name: 'Some Date',\n      type: {\n        name: 'string',\n      },\n      description: 'someDate description',\n      control: {\n        type: 'date',\n      },\n    },\n  },\n};\n\nexport const Number = {\n  args: {\n    row: {\n      key: 'someNumber',\n      name: 'Some Number',\n      description: 'someNumber description',\n      type: {\n        required: false,\n      },\n      table: {\n        type: {\n          summary: 'number',\n        },\n        defaultValue: {\n          summary: '0',\n        },\n      },\n      control: {\n        type: 'number',\n      },\n    },\n  },\n};\n\nexport const Range = {\n  args: {\n    row: {\n      ...Number.args.row,\n      control: {\n        type: 'range',\n      },\n    },\n  },\n};\n\nexport const Radio = {\n  args: {\n    row: {\n      key: 'someEnum',\n      name: 'Some Enum',\n      description: 'someEnum description',\n      control: {\n        type: 'radio',\n        argType: { options: ['a', 'b', 'c'] },\n      },\n    },\n  },\n};\n\nexport const InlineRadio = {\n  args: {\n    row: { ...Radio.args.row, control: { ...Radio.args.row.control, type: 'inline-radio' } },\n  },\n};\n\nexport const Check = {\n  args: {\n    row: { ...Radio.args.row, control: { ...Radio.args.row.control, type: 'check' } },\n  },\n};\n\nexport const InlineCheck = {\n  args: {\n    row: { ...Radio.args.row, control: { ...Radio.args.row.control, type: 'inline-check' } },\n  },\n};\n\nexport const Select = {\n  args: {\n    row: { ...Radio.args.row, control: { ...Radio.args.row.control, type: 'select' } },\n  },\n};\n\nexport const MultiSelect = {\n  args: {\n    row: { ...Radio.args.row, control: { ...Radio.args.row.control, type: 'multi-select' } },\n  },\n};\n\nexport const ObjectOf = {\n  args: {\n    row: {\n      key: 'someObject',\n      name: 'Some Object',\n      description: 'A simple `objectOf` propType.',\n      table: {\n        type: {\n          summary: 'objectOf(number)',\n        },\n        defaultValue: {\n          summary: '{ key: 1 }',\n        },\n      },\n      control: {\n        type: 'object',\n      },\n    },\n  },\n};\n\nexport const ArrayOf = {\n  args: {\n    row: {\n      key: 'someArray',\n      name: 'Some Array',\n      description: 'array of a certain type',\n      table: {\n        type: {\n          summary: 'number[]',\n        },\n        defaultValue: {\n          summary: '[1, 2, 3]',\n        },\n      },\n      control: {\n        type: 'array',\n      },\n    },\n  },\n};\n\nexport const ComplexObject = {\n  args: {\n    row: {\n      key: 'someComplex',\n      name: 'Some Complex',\n      description: 'A very complex `objectOf` propType.',\n      table: {\n        type: {\n          summary: 'object',\n          detail: `[{\n      id: number,\n      func: func,\n      arr: [{ index: number }]\n    }]`,\n        },\n        defaultValue: {\n          summary: 'object',\n          detail: `[{\n      id: 1,\n      func: () => {},\n      arr: [{ index: 1 }]\n    }]`,\n        },\n      },\n      control: {\n        type: 'object',\n      },\n    },\n  },\n};\n\nexport const Func = {\n  args: {\n    row: {\n      key: 'concat',\n      name: 'Concat',\n      description: 'concat 2 string values.',\n      type: {\n        required: true,\n      },\n      table: {\n        type: {\n          summary: '(a: string, b: string) => string',\n        },\n        defaultValue: {\n          summary: 'func',\n          detail: '(a, b) => { return a + b; }',\n        },\n        jsDocTags: {\n          params: [\n            {\n              name: 'a',\n              description: 'The first string',\n            },\n            {\n              name: 'b',\n              description: 'The second string',\n            },\n          ],\n          returns: {\n            description: 'The concatenation of both strings',\n          },\n        },\n      },\n      control: false,\n    },\n  },\n};\n\nexport const LongFunc = {\n  args: {\n    row: {\n      ...Func.args.row,\n      table: {\n        ...Func.args.row.table,\n        defaultValue: {\n          summary: 'func',\n          detail: `(a, b) => {\n  // Calculate various metrics between a and b\n  const lengthA = a.length;\n  const lengthB = b.length;\n  \n  // Determine the longer string\n  const maxLength = Math.max(lengthA, lengthB);\n  const minLength = Math.min(lengthA, lengthB);\n  \n  // Calculate similarity score\n  let matchCount = 0;\n  for (let i = 0; i < minLength; i++) {\n    if (a[i] === b[i]) {\n      matchCount++;\n    }\n  }\n  \n  // Compute weighted average\n  const similarity = (matchCount / maxLength) * 100;\n  \n  // Generate result string\n  const result = \\`Similarity: \\${similarity.toFixed(2)}%, Length diff: \\${Math.abs(lengthA - lengthB)}\\`;\n  \n  return result;\n}`,\n        },\n      },\n    },\n  },\n  play: async ({ canvas }) => {\n    const funcButton = canvas.getByRole('button', { name: 'func' });\n    funcButton.click();\n    expect(\n      await screen.findByText(/Calculate various metrics between a and b/)\n    ).toBeInTheDocument();\n  },\n} satisfies StoryObj<typeof ArgRow>;\n\nconst enumeration =\n  '\"search\" | \"arrow-to-bottom\" | \"arrow-to-right\" | \"bell\" | \"check\" | \"check-circle\"';\nexport const Enum = {\n  args: {\n    row: {\n      key: 'enum',\n      name: 'Some enum',\n      type: {\n        required: true,\n      },\n      table: {\n        type: {\n          summary: enumeration,\n        },\n      },\n    },\n  },\n};\n\nconst longEnumeration =\n  '\"search\" | \"arrow-to-bottom\" | \"arrow-to-right\" | \"bell\" | \"check\" | \"check-circle\" | \"chevron-up\" | \"chevron-down\" | \"chevron-left\" | \"chevron-right\" | \"envelope\" | \"exchange\" | \"file\" | \"file-check\" | \"file-import\" | \"file-pdf\" | \"file-times\" | \"pencil\" | \"question\" | \"question-circle\" | \"sitemap\" | \"user\" | \"times\" | \"plus\" | \"exclamation-triangle\" | \"trash-alt\" | \"long-arrow-up\" | \"long-arrow-down\" | \"long-arrow-left\" | \"long-arrow-right\" | \"external-link-alt\" | \"sticky-note\" | \"chart-line\" | \"spinner-third\"';\nexport const LongEnum = {\n  args: {\n    row: {\n      key: 'longEnum',\n      name: 'Long enum',\n      type: {\n        required: true,\n      },\n      table: {\n        type: {\n          summary: longEnumeration,\n        },\n      },\n    },\n  },\n  play: async ({ canvas, step }) => {\n    await step('Expand long enum', async () => {\n      canvas.getByRole('button', { name: 'Show 26 more...' }).click();\n      expect(await canvas.findByText(/exclamation-triangle/)).toBeVisible();\n    });\n    await step('Collapse long enum', async () => {\n      (await canvas.findByRole('button', { name: 'Show less...' })).click();\n      expect(await canvas.findByText(/exclamation-triangle/)).not.toBeVisible();\n    });\n    await step('Re-expand for visual test', async () => {\n      (await canvas.findByRole('button', { name: 'Show 26 more...' })).click();\n    });\n  },\n} satisfies StoryObj<typeof ArgRow>;\n\nconst complexUnion =\n  '((a: string | SVGSVGElement) => void) | RefObject<SVGSVGElement | number> | [a|b] | {a|b}';\nexport const ComplexUnion = {\n  args: {\n    row: {\n      key: 'complexUnion',\n      name: 'Complex',\n      type: {\n        required: true,\n      },\n      table: {\n        type: {\n          summary: complexUnion,\n        },\n      },\n    },\n  },\n};\n\nexport const Markdown = {\n  args: {\n    row: {\n      key: 'someString',\n      name: 'Some String',\n      description:\n        'A `prop` can *support* __markdown__ syntax. This was ship in ~~5.2~~ 5.3. [Find more info in the storybook docs.](https://storybook.js.org/)',\n      table: {\n        type: {\n          summary: 'string',\n        },\n      },\n      control: {\n        type: 'text',\n      },\n    },\n  },\n};\n\nexport const StringCompact = {\n  args: { ...String.args, compact: true },\n};\n\nexport const StringNoControls = {\n  args: {\n    row: String.args.row,\n  },\n};\n\nexport const StringNoControlsCompact = {\n  args: {\n    row: String.args.row,\n    compact: true,\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/ArgsTable/ArgRow.tsx",
    "content": "import type { FC } from 'react';\nimport React, { useState } from 'react';\n\nimport { codeCommon } from 'storybook/internal/components';\n\nimport Markdown from 'markdown-to-jsx';\nimport { transparentize } from 'polished';\nimport type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\nimport type { ArgControlProps } from './ArgControl';\nimport { ArgControl } from './ArgControl';\nimport { ArgJsDoc } from './ArgJsDoc';\nimport { ArgValue } from './ArgValue';\nimport type { ArgType, Args, TableAnnotation } from './types';\n\ninterface ArgRowProps {\n  row: ArgType;\n  arg: any;\n  updateArgs?: (args: Args) => void;\n  compact?: boolean;\n  expandable?: boolean;\n  initialExpandedArgs?: boolean;\n  storyId?: string;\n}\n\nconst Name = styled.span({ fontWeight: 'bold' });\n\nconst Required = styled.span(({ theme }) => ({\n  color: theme.color.negative,\n  fontFamily: theme.typography.fonts.mono,\n  cursor: 'help',\n}));\n\nconst Description = styled.div(({ theme }) => ({\n  '&&': {\n    p: {\n      margin: '0 0 10px 0',\n    },\n    a: {\n      color: theme.color.secondary,\n    },\n  },\n\n  code: {\n    ...(codeCommon({ theme }) as CSSObject),\n    fontSize: 12,\n    fontFamily: theme.typography.fonts.mono,\n  } as CSSObject,\n\n  '& code': {\n    margin: 0,\n    display: 'inline-block',\n  },\n\n  '& pre > code': {\n    whiteSpace: 'pre-wrap',\n  },\n}));\n\nconst Type = styled.div<{ hasDescription: boolean }>(({ theme, hasDescription }) => ({\n  color:\n    theme.base === 'light'\n      ? transparentize(0.1, theme.color.defaultText)\n      : transparentize(0.2, theme.color.defaultText),\n  marginTop: hasDescription ? 4 : 0,\n}));\n\nconst TypeWithJsDoc = styled.div<{ hasDescription: boolean }>(({ theme, hasDescription }) => ({\n  color:\n    theme.base === 'light'\n      ? transparentize(0.1, theme.color.defaultText)\n      : transparentize(0.2, theme.color.defaultText),\n  marginTop: hasDescription ? 12 : 0,\n  marginBottom: 12,\n}));\n\nconst StyledTd = styled.td<{ expandable: boolean }>(({ expandable }) => ({\n  paddingLeft: expandable ? '40px !important' : '20px !important',\n}));\n\nconst toSummary = (value: any) => {\n  if (!value) {\n    return value;\n  }\n  const val = typeof value === 'string' ? value : value.name;\n  return { summary: val };\n};\n\nexport const ArgRow: FC<ArgRowProps> = (props) => {\n  const [isHovered, setIsHovered] = useState(false);\n  const { row, updateArgs, compact, expandable, initialExpandedArgs } = props;\n  const { name, description } = row;\n  const table = (row.table || {}) as TableAnnotation;\n  const type = table.type || toSummary(row.type);\n  const defaultValue = table.defaultValue || row.defaultValue;\n  const required = row.type?.required;\n  const hasDescription = description != null && description !== '';\n\n  return (\n    <tr onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>\n      <StyledTd expandable={expandable ?? false}>\n        <Name>{name}</Name>\n        {required ? <Required title=\"Required\">*</Required> : null}\n      </StyledTd>\n      {compact ? null : (\n        <td>\n          {hasDescription && (\n            <Description>\n              <Markdown>{description}</Markdown>\n            </Description>\n          )}\n          {table.jsDocTags != null ? (\n            <>\n              <TypeWithJsDoc hasDescription={hasDescription}>\n                <ArgValue value={type} initialExpandedArgs={initialExpandedArgs} />\n              </TypeWithJsDoc>\n              <ArgJsDoc tags={table.jsDocTags} />\n            </>\n          ) : (\n            <Type hasDescription={hasDescription}>\n              <ArgValue value={type} initialExpandedArgs={initialExpandedArgs} />\n            </Type>\n          )}\n        </td>\n      )}\n      {compact ? null : (\n        <td>\n          <ArgValue value={defaultValue} initialExpandedArgs={initialExpandedArgs} />\n        </td>\n      )}\n      {updateArgs ? (\n        <td>\n          <ArgControl {...(props as ArgControlProps)} isHovered={isHovered} />\n        </td>\n      ) : null}\n    </tr>\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/ArgsTable/ArgValue.tsx",
    "content": "import type { FC } from 'react';\nimport React, { useState } from 'react';\n\nimport { PopoverProvider, SyntaxHighlighter, codeCommon } from 'storybook/internal/components';\n\nimport { ChevronSmallDownIcon, ChevronSmallUpIcon } from '@storybook/icons';\n\nimport { uniq } from 'es-toolkit/array';\nimport { styled } from 'storybook/theming';\n\nimport type { PropSummaryValue } from './types';\n\ninterface ArgValueProps {\n  value?: PropSummaryValue;\n  initialExpandedArgs?: boolean;\n}\n\ninterface ArgTextProps {\n  text: string;\n  simple?: boolean;\n}\n\ninterface ArgSummaryProps {\n  value: PropSummaryValue;\n  initialExpandedArgs?: boolean;\n}\n\nconst ITEMS_BEFORE_EXPANSION = 8;\n\nconst Summary = styled.div<{ isExpanded?: boolean }>(({ isExpanded }) => ({\n  display: 'flex',\n  flexDirection: isExpanded ? 'column' : 'row',\n  flexWrap: 'wrap',\n  alignItems: 'flex-start',\n  marginBottom: '-4px',\n  minWidth: 100,\n}));\n\nconst DetailsContainer = styled.details({\n  display: 'flex',\n  flexDirection: 'column',\n  summary: {\n    order: 2,\n  },\n  'summary::-webkit-details-marker': {\n    display: 'none',\n  },\n  'summary::marker': {\n    content: 'none',\n  },\n});\n\nconst AlignedDetails = styled.div({\n  display: 'flex',\n  flexDirection: 'column',\n  flexWrap: 'wrap',\n  alignItems: 'flex-start',\n});\n\nconst Text = styled.span<{ simple?: boolean }>(codeCommon, ({ theme, simple = false }) => ({\n  flex: '0 0 auto',\n  fontFamily: theme.typography.fonts.mono,\n  fontSize: theme.typography.size.s1,\n  wordBreak: 'break-word',\n  whiteSpace: 'normal',\n  maxWidth: '100%',\n  margin: 0,\n  marginRight: '4px',\n  marginBottom: '4px',\n  paddingTop: '2px',\n  paddingBottom: '2px',\n  lineHeight: '13px',\n  ...(simple && {\n    background: 'transparent',\n    border: '0 none',\n    paddingLeft: 0,\n  }),\n}));\n\nconst ExpandButton = styled.summary(({ theme }) => ({\n  fontFamily: theme.typography.fonts.mono,\n  color: theme.color.secondary,\n  cursor: 'pointer',\n  lineHeight: 'normal',\n  margin: '0 0 4px',\n  padding: '1px 6px',\n  background: 'none',\n  border: 'none',\n}));\n\nconst Expandable = styled.button(codeCommon, ({ theme }) => ({\n  fontFamily: theme.typography.fonts.mono,\n  color: theme.color.secondary,\n  fontSize: theme.typography.size.s1, // overrides codeCommon\n  margin: 0,\n  whiteSpace: 'nowrap',\n  display: 'flex',\n  alignItems: 'center',\n  cursor: 'pointer',\n  '&:hover': {\n    border:\n      theme.base === 'light' ? '1px solid hsl(0 0 0 / 0.15)' : '1px solid hsl(0 0 100 / 0.15)',\n  },\n  '&:focus-visible': {\n    outline: `2px solid ${theme.color.secondary}`,\n    outlineOffset: '2px',\n  },\n}));\n\nconst Detail = styled.div(({ theme }) => ({\n  minWidth: 200,\n  maxWidth: 800,\n  paddingRight: 16,\n  // Don't remove the mono fontFamily here even if it seems useless, this is used by the browser to calculate the length of a \"ch\" unit.\n  fontFamily: theme.typography.fonts.mono,\n  fontSize: theme.typography.size.s1,\n  // Most custom stylesheet will reset the box-sizing to \"border-box\" and will break the tooltip.\n  boxSizing: 'content-box',\n\n  '& code': {\n    padding: '0 !important',\n  },\n}));\n\nconst ChevronUpIcon = styled(ChevronSmallUpIcon)({\n  marginLeft: 4,\n});\n\nconst ChevronDownIcon = styled(ChevronSmallDownIcon)({\n  marginLeft: 4,\n});\n\nconst EmptyArg = () => {\n  return <span>-</span>;\n};\n\nconst ArgText: FC<ArgTextProps> = ({ text, simple }) => {\n  return <Text simple={simple}>{text}</Text>;\n};\n\nconst getSummaryItems = (summary: string) => {\n  if (!summary) {\n    return [summary];\n  }\n  const splittedItems = summary.split('|');\n  const summaryItems = splittedItems.map((value) => value.trim());\n\n  return uniq(summaryItems);\n};\n\nconst renderSummaryItems = (summaryItems: string[]) => {\n  return summaryItems\n    .slice(0, ITEMS_BEFORE_EXPANSION)\n    .map((item) => <ArgText key={item} text={item === '' ? '\"\"' : item} />);\n};\n\nconst renderExpandedItems = (summaryItems: string[]) => {\n  return summaryItems\n    .slice(ITEMS_BEFORE_EXPANSION)\n    .map((item) => <ArgText key={item} text={item === '' ? '\"\"' : item} />);\n};\n\nconst ArgSummary: FC<ArgSummaryProps> = ({ value, initialExpandedArgs }) => {\n  const { summary, detail } = value;\n\n  const [isOpen, setIsOpen] = useState(false);\n  const [isExpanded, setIsExpanded] = useState(initialExpandedArgs || false);\n\n  if (summary === undefined || summary === null) {\n    return null;\n  }\n  // summary is used for the default value\n  // below check fixes not displaying default values for boolean typescript vars\n  // summary is used for the default value\n  // below check fixes not displaying default values for boolean typescript vars\n  const summaryAsString = typeof summary.toString === 'function' ? summary.toString() : summary;\n\n  if (detail == null) {\n    const cannotBeSafelySplitted = /[(){}[\\]<>]/.test(summaryAsString);\n\n    if (cannotBeSafelySplitted) {\n      return <ArgText text={summaryAsString} />;\n    }\n\n    const summaryItems = getSummaryItems(summaryAsString);\n    const itemsCount = summaryItems.length;\n    const hasManyItems = itemsCount > ITEMS_BEFORE_EXPANSION;\n\n    return hasManyItems ? (\n      <Summary isExpanded={isExpanded}>\n        {renderSummaryItems(summaryItems)}\n        <DetailsContainer open={isExpanded} onToggle={(e) => setIsExpanded(e.currentTarget.open)}>\n          <AlignedDetails>{renderExpandedItems(summaryItems)}</AlignedDetails>\n          <ExpandButton role=\"button\">\n            {isExpanded ? 'Show less...' : `Show ${itemsCount - ITEMS_BEFORE_EXPANSION} more...`}\n          </ExpandButton>\n        </DetailsContainer>\n      </Summary>\n    ) : (\n      <Summary>{renderSummaryItems(summaryItems)}</Summary>\n    );\n  }\n\n  return (\n    <PopoverProvider\n      ariaLabel=\"Arg value details\"\n      placement=\"bottom\"\n      visible={isOpen}\n      onVisibleChange={(isVisible) => {\n        setIsOpen(isVisible);\n      }}\n      hasCloseButton\n      popover={\n        <Detail>\n          <SyntaxHighlighter language=\"jsx\" format={false}>\n            {detail}\n          </SyntaxHighlighter>\n        </Detail>\n      }\n    >\n      <Expandable className=\"sbdocs-expandable\">\n        <span>{summaryAsString}</span>\n        {isOpen ? <ChevronUpIcon /> : <ChevronDownIcon />}\n      </Expandable>\n    </PopoverProvider>\n  );\n};\n\nexport const ArgValue: FC<ArgValueProps> = ({ value, initialExpandedArgs }) => {\n  return value == null ? (\n    <EmptyArg />\n  ) : (\n    <ArgSummary value={value} initialExpandedArgs={initialExpandedArgs} />\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/ArgsTable/ArgsTable.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { action } from 'storybook/actions';\nimport { styled } from 'storybook/theming';\n\nimport * as ArgRow from './ArgRow.stories';\nimport { ArgsTable, ArgsTableError } from './ArgsTable';\n\nconst meta = {\n  component: ArgsTable,\n  title: 'Components/ArgsTable/ArgsTable',\n  args: {\n    updateArgs: action('updateArgs'),\n    resetArgs: action('resetArgs'),\n  },\n} satisfies Meta<typeof ArgsTable>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nconst propsSection = {\n  category: 'props ',\n};\nconst eventsSection = {\n  category: 'events ',\n};\nconst componentSubsection = {\n  subcategory: 'MyComponent ',\n};\nconst htmlElementSubsection = {\n  subcategory: 'HTMLElement',\n};\nconst stringType = ArgRow.String.args.row;\nconst numberType = ArgRow.Number.args.row;\nconst longEnumType = ArgRow.LongEnum.args.row;\n\nexport const Loading = {\n  args: {\n    isLoading: true,\n  },\n};\n\nexport const Normal = {\n  args: {\n    rows: {\n      stringType,\n      numberType,\n    },\n  },\n};\n\nexport const Compact = {\n  args: { ...Normal.args, compact: true },\n};\n\nexport const Sections = {\n  args: {\n    rows: {\n      a: { ...stringType, table: { ...stringType.table, ...propsSection } },\n      b: { ...numberType, table: { ...stringType.table, ...propsSection } },\n      c: { ...stringType, table: { ...stringType.table, ...eventsSection } },\n    },\n  },\n};\n\nexport const SectionsCompact = {\n  args: { ...Sections.args, compact: true },\n};\n\nexport const SectionsAndSubsections = {\n  args: {\n    rows: {\n      a: { ...stringType, table: { ...stringType.table, ...propsSection, ...componentSubsection } },\n      b: { ...numberType, table: { ...stringType.table, ...propsSection, ...componentSubsection } },\n      c: {\n        ...stringType,\n        table: { ...stringType.table, ...eventsSection, ...componentSubsection },\n      },\n      d: {\n        ...stringType,\n        table: { ...stringType.table, ...eventsSection, ...htmlElementSubsection },\n      },\n    },\n  },\n};\n\nexport const SubsectionsOnly = {\n  args: {\n    rows: {\n      a: { ...stringType, key: 'stringA', table: { ...stringType.table, ...componentSubsection } },\n      b: { ...numberType, table: { ...stringType.table, ...componentSubsection } },\n      c: { ...stringType, key: 'stringB', table: { ...stringType.table, ...componentSubsection } },\n      d: {\n        ...stringType,\n        key: 'stringC',\n        table: { ...stringType.table, ...htmlElementSubsection },\n      },\n    },\n  },\n};\n\nexport const AllControls = {\n  args: {\n    rows: {\n      array: ArgRow.ArrayOf.args.row,\n      boolean: ArgRow.Boolean.args.row,\n      color: ArgRow.Color.args.row,\n      date: ArgRow.Date.args.row,\n      string: ArgRow.String.args.row,\n      number: { ...ArgRow.Number.args.row, key: 'number' },\n      range: { ...ArgRow.Number.args.row, key: 'range' },\n      radio: { ...ArgRow.Radio.args.row, key: 'radio' },\n      inlineRadio: { ...ArgRow.InlineRadio.args.row, key: 'inlineRadio' },\n      check: { ...ArgRow.Check.args.row, key: 'check' },\n      inlineCheck: { ...ArgRow.InlineCheck.args.row, key: 'inlineCheck' },\n      select: { ...ArgRow.Select.args.row, key: 'select' },\n      multiSelect: { ...ArgRow.MultiSelect.args.row, key: 'multiSelect' },\n      object: ArgRow.ObjectOf.args.row,\n      func: ArgRow.Func.args.row,\n    },\n  },\n};\n\nconst AddonPanelLayout = styled.div(({ theme }) => ({\n  fontSize: theme.typography.size.s2 - 1,\n  background: theme.background.content,\n}));\n\nexport const InAddonPanel = {\n  args: {\n    ...Normal.args,\n    inAddonPanel: true,\n    rows: SectionsAndSubsections.args.rows,\n  },\n  decorators: [(storyFn: any) => <AddonPanelLayout>{storyFn()}</AddonPanelLayout>],\n  parameters: {\n    layout: 'fullscreen',\n  },\n};\n\nexport const InAddonPanelNoControls = {\n  ...InAddonPanel,\n  args: {\n    ...InAddonPanel.args,\n    rows: Object.fromEntries(\n      Object.entries(InAddonPanel.args.rows).map(([k, v]) => [k, { ...v, control: null as any }])\n    ),\n  },\n};\n\nexport const Error = {\n  args: {\n    error: ArgsTableError.NO_COMPONENT,\n  },\n};\n\nexport const Empty = {\n  args: {},\n  parameters: {\n    layout: 'centered',\n  },\n};\n\nexport const EmptyInsideAddonPanel: Story = {\n  args: {\n    isLoading: false,\n    inAddonPanel: true,\n  },\n  parameters: {\n    layout: 'centered',\n  },\n};\n\nexport const WithDefaultExpandedArgs = {\n  args: {\n    rows: {\n      longEnumType,\n    },\n    initialExpandedArgs: true,\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/ArgsTable/ArgsTable.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { once } from 'storybook/internal/client-logger';\nimport { Button, Link, ResetWrapper } from 'storybook/internal/components';\nimport { includeConditionalArg } from 'storybook/internal/csf';\n\nimport { DocumentIcon, UndoIcon } from '@storybook/icons';\n\nimport { pickBy } from 'es-toolkit/object';\nimport { styled } from 'storybook/theming';\n\nimport { EmptyBlock } from '../EmptyBlock';\nimport { ArgRow } from './ArgRow';\nimport { Empty } from './Empty';\nimport { SectionRow } from './SectionRow';\nimport { Skeleton } from './Skeleton';\nimport type { ArgType, ArgTypes, Args, Globals } from './types';\n\nexport const TableWrapper = styled.table<{\n  compact?: boolean;\n  inAddonPanel?: boolean;\n  inTabPanel?: boolean;\n  isLoading?: boolean;\n}>(({ theme, compact, inAddonPanel, inTabPanel }) => ({\n  '&&': {\n    // Resets for cascading/system styles\n    borderSpacing: 0,\n    color: theme.color.defaultText,\n\n    'td, th': {\n      padding: 0,\n      border: 'none',\n      verticalAlign: 'top',\n      textOverflow: 'ellipsis',\n    },\n    // End Resets\n\n    fontSize: theme.typography.size.s2 - 1,\n    lineHeight: '19px',\n    textAlign: 'left',\n    width: '100%',\n\n    // Margin collapse\n    marginTop: inAddonPanel ? 0 : 25,\n    marginBottom: inAddonPanel ? 0 : 40,\n\n    'thead th:first-of-type, td:first-of-type': {\n      // intentionally specify thead here\n      width: '25%',\n    },\n\n    'th:first-of-type, td:first-of-type': {\n      paddingLeft: 20,\n    },\n\n    'th:nth-of-type(2), td:nth-of-type(2)': {\n      ...(compact\n        ? null\n        : {\n            // Description column\n            width: '35%',\n          }),\n    },\n\n    'td:nth-of-type(3)': {\n      ...(compact\n        ? null\n        : {\n            // Defaults column\n            width: '15%',\n          }),\n    },\n\n    'th:last-of-type, td:last-of-type': {\n      paddingRight: 20,\n      ...(compact\n        ? null\n        : {\n            // Controls column\n            width: '25%',\n          }),\n    },\n\n    th: {\n      color: theme.textMutedColor,\n      paddingTop: 10,\n      paddingBottom: 10,\n      paddingLeft: 15,\n      paddingRight: 15,\n    },\n\n    td: {\n      paddingTop: '10px',\n      paddingBottom: '10px',\n\n      '&:not(:first-of-type)': {\n        paddingLeft: 15,\n        paddingRight: 15,\n      },\n\n      '&:last-of-type': {\n        paddingRight: 20,\n      },\n    },\n\n    // Makes border alignment consistent w/other DocBlocks\n    marginInline: inAddonPanel || inTabPanel ? 0 : 1,\n    paddingInline: inTabPanel ? 3 : 0,\n\n    tbody: {\n      // Safari doesn't love shadows on tbody so we need to use a shadow filter. In order to do this,\n      // the table cells all need to be solid so they have a background color applied.\n      // I wasn't sure what kinds of content go in these tables so I was extra specific with selectors\n      // to avoid unexpected surprises.\n      ...(inAddonPanel\n        ? null\n        : {\n            filter:\n              theme.base === 'light'\n                ? `drop-shadow(0px 1px 3px rgba(0, 0, 0, 0.10))`\n                : `drop-shadow(0px 1px 3px rgba(0, 0, 0, 0.20))`,\n          }),\n\n      '> tr > *': {\n        // For filter to work properly, the table cells all need to be opaque.\n        background: theme.background.content,\n        borderTop: `1px solid ${theme.appBorderColor}`,\n      },\n\n      ...(inAddonPanel\n        ? null\n        : {\n            // This works and I don't know why. :)\n            '> tr:first-of-type > *': {\n              borderBlockStart: `1px solid ${theme.appBorderColor}`,\n            },\n            '> tr:last-of-type > *': {\n              borderBlockEnd: `1px solid ${theme.appBorderColor}`,\n            },\n            '> tr > *:first-of-type': {\n              borderInlineStart: `1px solid ${theme.appBorderColor}`,\n            },\n            '> tr > *:last-of-type': {\n              borderInlineEnd: `1px solid ${theme.appBorderColor}`,\n            },\n\n            // Thank you, Safari, for making me write code like this.\n            '> tr:first-of-type > td:first-of-type': {\n              borderTopLeftRadius: theme.appBorderRadius,\n            },\n            '> tr:first-of-type > td:last-of-type': {\n              borderTopRightRadius: theme.appBorderRadius,\n            },\n            '> tr:last-of-type > td:first-of-type': {\n              borderBottomLeftRadius: theme.appBorderRadius,\n            },\n            '> tr:last-of-type > td:last-of-type': {\n              borderBottomRightRadius: theme.appBorderRadius,\n            },\n          }),\n    },\n    // End awesome table styling\n  },\n}));\n\nconst TablePositionWrapper = styled.div({\n  position: 'relative',\n});\n\nconst ButtonPositionWrapper = styled.div({\n  position: 'absolute',\n  right: 22,\n  top: 10,\n});\n\nconst StyledButton = styled(Button)({\n  margin: '-4px -12px -4px 0',\n});\n\nexport enum ArgsTableError {\n  NO_COMPONENT = 'No component found.',\n  ARGS_UNSUPPORTED = 'Args unsupported. See Args documentation for your framework.',\n}\n\nexport type SortType = 'alpha' | 'requiredFirst' | 'none';\ntype SortFn = (a: ArgType, b: ArgType) => number;\n\nconst sortFns: Record<SortType, SortFn | null> = {\n  alpha: (a: ArgType, b: ArgType) => (a.name ?? '').localeCompare(b.name ?? ''),\n  requiredFirst: (a: ArgType, b: ArgType) =>\n    Number(!!b.type?.required) - Number(!!a.type?.required) ||\n    (a.name ?? '').localeCompare(b.name ?? ''),\n  none: null,\n};\n\nexport interface ArgsTableOptionProps {\n  children?: React.ReactNode;\n  updateArgs?: (args: Args) => void;\n  resetArgs?: (argNames?: string[]) => void;\n  compact?: boolean;\n  inAddonPanel?: boolean;\n  inTabPanel?: boolean;\n  initialExpandedArgs?: boolean;\n  isLoading?: boolean;\n  sort?: SortType;\n  storyId?: string;\n}\ninterface ArgsTableDataProps {\n  rows: ArgTypes;\n  args?: Args;\n  globals?: Globals;\n}\n\ninterface ArgsTableErrorProps {\n  error: ArgsTableError;\n}\n\nexport interface ArgsTableLoadingProps {\n  isLoading: boolean;\n}\n\nexport type ArgsTableProps = ArgsTableOptionProps &\n  (ArgsTableDataProps | ArgsTableErrorProps | ArgsTableLoadingProps);\n\ntype Rows = ArgType[];\ntype Subsection = Rows;\ntype Section = {\n  ungrouped: Rows;\n  subsections: Record<string, Subsection>;\n};\ntype Sections = {\n  ungrouped: Rows;\n  ungroupedSubsections: Record<string, Subsection>;\n  sections: Record<string, Section>;\n};\n\nconst groupRows = (rows: ArgType, sort: SortType): Sections => {\n  const sections: Sections = { ungrouped: [], ungroupedSubsections: {}, sections: {} };\n\n  if (!rows) {\n    return sections;\n  }\n\n  Object.entries(rows).forEach(([key, row]) => {\n    const { category, subcategory } = row?.table || {};\n    if (category) {\n      const section = sections.sections[category] || { ungrouped: [], subsections: {} };\n      if (!subcategory) {\n        section.ungrouped.push({ key, ...row });\n      } else {\n        const subsection = section.subsections[subcategory] || [];\n        subsection.push({ key, ...row });\n        section.subsections[subcategory] = subsection;\n      }\n      sections.sections[category] = section;\n    } else if (subcategory) {\n      const subsection = sections.ungroupedSubsections[subcategory] || [];\n      subsection.push({ key, ...row });\n      sections.ungroupedSubsections[subcategory] = subsection;\n    } else {\n      sections.ungrouped.push({ key, ...row });\n    }\n  });\n\n  // apply sort\n  const sortFn = sortFns[sort];\n\n  const sortSubsection = (record: Record<string, Subsection>) => {\n    if (!sortFn) {\n      return record;\n    }\n    return Object.keys(record).reduce<Record<string, Subsection>>(\n      (acc, cur) => ({\n        ...acc,\n        [cur]: record[cur].sort(sortFn),\n      }),\n      {}\n    );\n  };\n\n  const sorted = {\n    ungrouped: sortFn ? sections.ungrouped.sort(sortFn) : sections.ungrouped,\n    ungroupedSubsections: sortSubsection(sections.ungroupedSubsections),\n    sections: Object.keys(sections.sections).reduce<Record<string, Section>>(\n      (acc, cur) => ({\n        ...acc,\n        [cur]: {\n          ungrouped: sortFn\n            ? sections.sections[cur].ungrouped.sort(sortFn)\n            : sections.sections[cur].ungrouped,\n          subsections: sortSubsection(sections.sections[cur].subsections),\n        },\n      }),\n      {}\n    ),\n  };\n\n  return sorted;\n};\n\n/**\n * Wrap CSF's `includeConditionalArg` in a try catch so that invalid conditionals don't break the\n * entire UI. We can safely swallow the error because `includeConditionalArg` is also called in the\n * preview in `prepareStory`, and that exception will be bubbled up into the UI in a red screen.\n * Nevertheless, we log the error here just in case.\n */\nconst safeIncludeConditionalArg = (row: ArgType, args: Args, globals: Globals) => {\n  try {\n    return includeConditionalArg(row, args, globals);\n  } catch (err: unknown) {\n    once.warn((err as Error).message);\n    return false;\n  }\n};\n\n/**\n * Display the props for a component as a props table. Each row is a collection of ArgDefs, usually\n * derived from docgen info for the component.\n */\nexport const ArgsTable: FC<ArgsTableProps> = (props) => {\n  const {\n    updateArgs,\n    resetArgs,\n    compact,\n    inAddonPanel,\n    inTabPanel,\n    initialExpandedArgs,\n    sort = 'none',\n    isLoading,\n    storyId,\n  } = props;\n\n  if ('error' in props) {\n    const { error } = props;\n    return (\n      <EmptyBlock>\n        {error}&nbsp;\n        <Link href=\"http://storybook.js.org/docs/?ref=ui\" target=\"_blank\" withArrow>\n          <DocumentIcon /> Read the docs\n        </Link>\n      </EmptyBlock>\n    );\n  }\n\n  // If the story is loading, show a skeleton\n  // This happen when you load the manager and the story is not yet loaded\n\n  // If the story is loading, show a skeleton\n  // This happen when you load the manager and the story is not yet loaded\n  if (isLoading) {\n    return <Skeleton />;\n  }\n\n  const { rows, args, globals } =\n    'rows' in props ? props : { rows: undefined, args: undefined, globals: undefined };\n  const groups: Sections = groupRows(\n    pickBy(\n      rows || {},\n      (row) => !row?.table?.disable && safeIncludeConditionalArg(row, args || {}, globals || {})\n    ),\n    sort\n  );\n\n  // If there are no controls, show the empty state\n  const hasNoUngrouped = groups.ungrouped.length === 0;\n  const hasNoSections = Object.entries(groups.sections).length === 0;\n  const hasNoUngroupedSubsections = Object.entries(groups.ungroupedSubsections).length === 0;\n\n  if (hasNoUngrouped && hasNoSections && hasNoUngroupedSubsections) {\n    return <Empty inAddonPanel={inAddonPanel} />;\n  }\n\n  let colSpan = 1;\n\n  if (updateArgs) {\n    colSpan += 1;\n  }\n\n  if (!compact) {\n    colSpan += 2;\n  }\n  const expandable = Object.keys(groups.sections).length > 0;\n\n  const common = { updateArgs, compact, inAddonPanel, initialExpandedArgs, storyId };\n\n  return (\n    <ResetWrapper>\n      <TablePositionWrapper>\n        {updateArgs && !isLoading && resetArgs && (\n          <ButtonPositionWrapper>\n            <StyledButton\n              variant=\"ghost\"\n              padding=\"small\"\n              onClick={() => resetArgs()}\n              ariaLabel=\"Reset controls\"\n            >\n              <UndoIcon />\n            </StyledButton>\n          </ButtonPositionWrapper>\n        )}\n\n        <TableWrapper\n          {...{ compact, inAddonPanel, inTabPanel }}\n          className=\"docblock-argstable sb-unstyled\"\n        >\n          <thead className=\"docblock-argstable-head\">\n            <tr>\n              <th>\n                <span>Name</span>\n              </th>\n              {compact ? null : (\n                <th>\n                  <span>Description</span>\n                </th>\n              )}\n              {compact ? null : (\n                <th>\n                  <span>Default</span>\n                </th>\n              )}\n              {updateArgs ? (\n                <th>\n                  <span>Control</span>\n                </th>\n              ) : null}\n            </tr>\n          </thead>\n          <tbody className=\"docblock-argstable-body\">\n            {groups.ungrouped.map((row) => (\n              <ArgRow key={row.key} row={row} arg={args && args[row.key]} {...common} />\n            ))}\n\n            {Object.entries(groups.ungroupedSubsections).map(([subcategory, subsection]) => (\n              <SectionRow\n                key={subcategory}\n                label={subcategory}\n                level=\"subsection\"\n                colSpan={colSpan}\n              >\n                {subsection.map((row) => (\n                  <ArgRow\n                    key={row.key}\n                    row={row}\n                    arg={args && args[row.key]}\n                    expandable={expandable}\n                    {...common}\n                  />\n                ))}\n              </SectionRow>\n            ))}\n\n            {Object.entries(groups.sections).map(([category, section]) => (\n              <SectionRow key={category} label={category} level=\"section\" colSpan={colSpan}>\n                {section.ungrouped.map((row) => (\n                  <ArgRow key={row.key} row={row} arg={args && args[row.key]} {...common} />\n                ))}\n                {Object.entries(section.subsections).map(([subcategory, subsection]) => (\n                  <SectionRow\n                    key={subcategory}\n                    label={subcategory}\n                    level=\"subsection\"\n                    colSpan={colSpan}\n                  >\n                    {subsection.map((row) => (\n                      <ArgRow\n                        key={row.key}\n                        row={row}\n                        arg={args && args[row.key]}\n                        expandable={expandable}\n                        {...common}\n                      />\n                    ))}\n                  </SectionRow>\n                ))}\n              </SectionRow>\n            ))}\n          </tbody>\n        </TableWrapper>\n      </TablePositionWrapper>\n    </ResetWrapper>\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/ArgsTable/Empty.tsx",
    "content": "import type { FC } from 'react';\nimport React, { useEffect, useState } from 'react';\n\nimport { EmptyTabContent, Link } from 'storybook/internal/components';\n\nimport { DocumentIcon } from '@storybook/icons';\n\nimport { styled } from 'storybook/theming';\n\ninterface EmptyProps {\n  inAddonPanel?: boolean;\n}\n\nconst Wrapper = styled.div<{ inAddonPanel?: boolean }>(({ inAddonPanel, theme }) => ({\n  height: inAddonPanel ? '100%' : 'auto',\n  display: 'flex',\n  border: inAddonPanel ? 'none' : `1px solid ${theme.appBorderColor}`,\n  borderRadius: inAddonPanel ? 0 : theme.appBorderRadius,\n  padding: inAddonPanel ? 0 : 40,\n  alignItems: 'center',\n  justifyContent: 'center',\n  flexDirection: 'column',\n  gap: 15,\n  background: theme.background.content,\n}));\n\nconst Links = styled.div(({ theme }) => ({\n  display: 'flex',\n  fontSize: theme.typography.size.s2 - 1,\n  gap: 25,\n}));\n\nexport const Empty: FC<EmptyProps> = ({ inAddonPanel }) => {\n  const [isLoading, setIsLoading] = useState(true);\n\n  // We are adding a small delay to avoid flickering when the story is loading.\n  // It takes a bit of time for the controls to appear, so we don't want\n  // to show the empty state for a split second.\n  useEffect(() => {\n    const load = setTimeout(() => {\n      setIsLoading(false);\n    }, 100);\n\n    return () => clearTimeout(load);\n  }, []);\n\n  if (isLoading) {\n    return null;\n  }\n\n  return (\n    <Wrapper inAddonPanel={inAddonPanel}>\n      <EmptyTabContent\n        title={\n          inAddonPanel\n            ? 'Interactive story playground'\n            : \"Args table with interactive controls couldn't be auto-generated\"\n        }\n        description={\n          <>\n            Controls give you an easy to use interface to test your components. Set your story args\n            and you&apos;ll see controls appearing here automatically.\n          </>\n        }\n        footer={\n          <Links>\n            {inAddonPanel && (\n              <>\n                <Link\n                  href=\"https://storybook.js.org/docs/essentials/controls?ref=ui\"\n                  target=\"_blank\"\n                  withArrow\n                >\n                  <DocumentIcon /> Read docs\n                </Link>\n              </>\n            )}\n            {!inAddonPanel && (\n              <Link\n                href=\"https://storybook.js.org/docs/essentials/controls?ref=ui\"\n                target=\"_blank\"\n                withArrow\n              >\n                <DocumentIcon /> Learn how to set that up\n              </Link>\n            )}\n          </Links>\n        }\n      />\n    </Wrapper>\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/ArgsTable/SectionRow.stories.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React from 'react';\n\nimport { ResetWrapper } from 'storybook/internal/components';\n\nimport { TableWrapper } from './ArgsTable';\nimport { SectionRow } from './SectionRow';\n\nexport default {\n  component: SectionRow,\n  decorators: [\n    (getStory: any) => (\n      <ResetWrapper>\n        <TableWrapper>\n          <tbody>{getStory()}</tbody>\n        </TableWrapper>\n      </ResetWrapper>\n    ),\n  ],\n};\n\nexport const Section = {\n  args: {\n    level: 'section',\n    label: 'Props',\n  },\n};\n\nexport const Subsection = {\n  args: {\n    level: 'subsection',\n    label: 'HTMLElement',\n  },\n};\n\nexport const Collapsed = {\n  args: { ...Section.args, initialExpanded: false },\n};\n\nexport const Nested = {\n  render: () => (\n    <SectionRow {...(Section.args as ComponentProps<typeof SectionRow>)}>\n      <SectionRow {...(Subsection.args as ComponentProps<typeof SectionRow>)}>\n        <tr>\n          <td colSpan={2}>Some content</td>\n        </tr>\n      </SectionRow>\n    </SectionRow>\n  ),\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/ArgsTable/SectionRow.tsx",
    "content": "import type { FC } from 'react';\nimport React, { useState } from 'react';\n\nimport { ChevronDownIcon, ChevronRightIcon } from '@storybook/icons';\n\nimport { lighten, transparentize } from 'polished';\nimport { styled } from 'storybook/theming';\n\ntype Level = 'section' | 'subsection';\n\nexport interface SectionRowProps {\n  children?: React.ReactNode;\n  label: string;\n  level: Level;\n  initialExpanded?: boolean;\n  colSpan: number;\n}\n\nconst ExpanderIconDown = styled(ChevronDownIcon)(({ theme }) => ({\n  marginRight: 8,\n  marginLeft: -10,\n  marginTop: -2, // optical alignment\n  height: 12,\n  width: 12,\n  color:\n    theme.base === 'light'\n      ? transparentize(0.25, theme.color.defaultText)\n      : transparentize(0.3, theme.color.defaultText),\n  border: 'none',\n  display: 'inline-block',\n}));\n\nconst ExpanderIconRight = styled(ChevronRightIcon)(({ theme }) => ({\n  marginRight: 8,\n  marginLeft: -10,\n  marginTop: -2, // optical alignment\n  height: 12,\n  width: 12,\n  color:\n    theme.base === 'light'\n      ? transparentize(0.25, theme.color.defaultText)\n      : transparentize(0.3, theme.color.defaultText),\n  border: 'none',\n  display: 'inline-block',\n}));\n\nconst FlexWrapper = styled.span(({ theme }) => ({\n  display: 'flex',\n  lineHeight: '20px',\n  alignItems: 'center',\n}));\n\nconst Section = styled.td(({ theme }) => ({\n  position: 'relative',\n  letterSpacing: '0.35em',\n  textTransform: 'uppercase',\n  fontWeight: theme.typography.weight.bold,\n  fontSize: theme.typography.size.s1 - 1,\n  color:\n    theme.base === 'light'\n      ? transparentize(0.4, theme.color.defaultText)\n      : transparentize(0.6, theme.color.defaultText),\n  background: `${theme.background.app} !important`,\n  '& ~ td': {\n    background: `${theme.background.app} !important`,\n  },\n}));\n\nconst Subsection = styled.td(({ theme }) => ({\n  position: 'relative',\n  fontWeight: theme.typography.weight.bold,\n  fontSize: theme.typography.size.s2 - 1,\n  background: theme.background.app,\n}));\n\nconst StyledTd = styled.td({\n  position: 'relative',\n});\n\nconst StyledTr = styled.tr(({ theme }) => ({\n  '&:hover > td': {\n    backgroundColor: `${lighten(0.005, theme.background.app)} !important`,\n    boxShadow: `${theme.color.mediumlight} 0 - 1px 0 0 inset`,\n    cursor: 'row-resize',\n  },\n}));\n\nconst ClickIntercept = styled.button({\n  // reset button style\n  background: 'none',\n  border: 'none',\n  padding: '0',\n  font: 'inherit',\n\n  // add custom style\n  position: 'absolute',\n  top: 0,\n  bottom: 0,\n  left: 0,\n  right: 0,\n  height: '100%',\n  width: '100%',\n  color: 'transparent',\n  cursor: 'row-resize !important',\n});\n\nexport const SectionRow: FC<SectionRowProps> = ({\n  level = 'section',\n  label,\n  children,\n  initialExpanded = true,\n  colSpan = 3,\n}) => {\n  const [expanded, setExpanded] = useState(initialExpanded);\n  const Level = level === 'subsection' ? Subsection : Section;\n  // @ts-expect-error (Converted from ts-ignore)\n  const itemCount = children?.length || 0;\n  const caption = level === 'subsection' ? `${itemCount} item${itemCount !== 1 ? 's' : ''}` : '';\n\n  const helperText = `${expanded ? 'Hide' : 'Show'} ${\n    level === 'subsection' ? itemCount : label\n  } item${itemCount !== 1 ? 's' : ''}`;\n\n  return (\n    <>\n      <StyledTr title={helperText}>\n        <Level colSpan={1}>\n          <ClickIntercept onClick={(e) => setExpanded(!expanded)} tabIndex={0}>\n            {helperText}\n          </ClickIntercept>\n          <FlexWrapper>\n            {expanded ? <ExpanderIconDown /> : <ExpanderIconRight />}\n            {label}\n          </FlexWrapper>\n        </Level>\n        <StyledTd colSpan={colSpan - 1}>\n          <ClickIntercept\n            onClick={(e) => setExpanded(!expanded)}\n            tabIndex={-1}\n            style={{ outline: 'none' }}\n          >\n            {helperText}\n          </ClickIntercept>\n          {expanded ? null : caption}\n        </StyledTd>\n      </StyledTr>\n      {expanded ? children : null}\n    </>\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/ArgsTable/Skeleton.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { styled } from 'storybook/theming';\n\nconst TableWrapper = styled.div(({ theme }) => ({\n  width: '100%',\n  borderSpacing: 0,\n  color: theme.color.defaultText,\n}));\n\nconst Row = styled.div(({ theme }) => ({\n  display: 'flex',\n  borderBottom: `1px solid ${theme.appBorderColor}`,\n\n  '&:last-child': {\n    borderBottom: 0,\n  },\n}));\n\nconst Column = styled.div<{ position: 'first' | 'second' | 'third' | 'last' }>(\n  ({ position, theme }) => {\n    const baseStyles = {\n      display: 'flex',\n      flexDirection: 'column' as const,\n      gap: 5,\n      padding: '10px 15px',\n      alignItems: 'flex-start',\n    };\n\n    // Apply the same column width ratios as the actual ArgsTable component\n    switch (position) {\n      case 'first':\n        return {\n          ...baseStyles,\n          width: '25%',\n          paddingLeft: 20,\n        };\n      case 'second':\n        return {\n          ...baseStyles,\n          width: '35%',\n        };\n      case 'third':\n        return {\n          ...baseStyles,\n          width: '15%',\n        };\n      case 'last':\n        return {\n          ...baseStyles,\n          width: '25%',\n          paddingRight: 20,\n        };\n    }\n  }\n);\n\nconst SkeletonText = styled.div<{ width?: number | string; height?: number }>(\n  ({ theme, width, height }) => ({\n    animation: `${theme.animation.glow} 1.5s ease-in-out infinite`,\n    background: theme.appBorderColor,\n    width: width || '100%',\n    height: height || 16,\n    borderRadius: 3,\n  })\n);\n\nexport const Skeleton: FC = () => (\n  <TableWrapper>\n    <Row>\n      <Column position=\"first\">\n        <SkeletonText width=\"60%\" />\n      </Column>\n      <Column position=\"second\">\n        <SkeletonText width=\"30%\" />\n      </Column>\n      <Column position=\"third\">\n        <SkeletonText width=\"60%\" />\n      </Column>\n      <Column position=\"last\">\n        <SkeletonText width=\"60%\" />\n      </Column>\n    </Row>\n    <Row>\n      <Column position=\"first\">\n        <SkeletonText width=\"60%\" />\n      </Column>\n      <Column position=\"second\">\n        <SkeletonText width=\"80%\" />\n        <SkeletonText width=\"30%\" />\n      </Column>\n      <Column position=\"third\">\n        <SkeletonText width=\"60%\" />\n      </Column>\n      <Column position=\"last\">\n        <SkeletonText width=\"60%\" />\n      </Column>\n    </Row>\n    <Row>\n      <Column position=\"first\">\n        <SkeletonText width=\"60%\" />\n      </Column>\n      <Column position=\"second\">\n        <SkeletonText width=\"80%\" />\n        <SkeletonText width=\"30%\" />\n      </Column>\n      <Column position=\"third\">\n        <SkeletonText width=\"60%\" />\n      </Column>\n      <Column position=\"last\">\n        <SkeletonText width=\"60%\" />\n      </Column>\n    </Row>\n    <Row>\n      <Column position=\"first\">\n        <SkeletonText width=\"60%\" />\n      </Column>\n      <Column position=\"second\">\n        <SkeletonText width=\"80%\" />\n        <SkeletonText width=\"30%\" />\n      </Column>\n      <Column position=\"third\">\n        <SkeletonText width=\"60%\" />\n      </Column>\n      <Column position=\"last\">\n        <SkeletonText width=\"60%\" />\n      </Column>\n    </Row>\n  </TableWrapper>\n);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/ArgsTable/TabbedArgsTable.stories.tsx",
    "content": "import { TabsView } from 'storybook/internal/components';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { ArgsTable } from './ArgsTable';\nimport { Compact, Normal, Sections } from './ArgsTable.stories';\nimport { TabbedArgsTable } from './TabbedArgsTable';\n\nconst meta = {\n  component: TabbedArgsTable,\n  tags: ['autodocs'],\n  subcomponents: { TabbedArgsTable: TabbedArgsTable, ArgsTable, TabsView },\n} satisfies Meta<typeof TabbedArgsTable>;\n\nexport default meta;\n\nexport const Tabs: StoryObj<typeof meta> = {\n  args: {\n    tabs: {\n      Normal: Normal.args,\n      Compact: Compact.args,\n      Sections: Sections.args,\n    },\n  },\n};\n\nexport const TabsInAddonPanel: StoryObj<typeof meta> = {\n  args: {\n    tabs: {\n      Normal: Normal.args,\n      Compact: Compact.args,\n      Sections: Sections.args,\n    },\n    inAddonPanel: true,\n  },\n};\n\nexport const Empty: StoryObj<typeof meta> = {\n  args: {\n    tabs: {},\n  },\n};\n\nexport const WithContentAround: StoryObj<typeof meta> = {\n  args: {\n    tabs: {\n      Normal: Normal.args,\n      Compact: Compact.args,\n      Sections: Sections.args,\n    },\n  },\n  render: (args) => (\n    <>\n      <p>This is some content above the TabbedArgsTable.</p>\n      <TabbedArgsTable {...args} />\n      <p>This is some content below the TabbedArgsTable.</p>\n    </>\n  ),\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/ArgsTable/TabbedArgsTable.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { TabsView } from 'storybook/internal/components';\n\nimport { styled } from 'storybook/theming';\n\nimport type { ArgsTableProps } from './ArgsTable';\nimport { ArgsTable } from './ArgsTable';\n\ntype DistributiveOmit<T, K extends PropertyKey> = T extends any ? Omit<T, K> : never;\n\nexport type TabbedArgsTableProps = DistributiveOmit<ArgsTableProps, 'rows'> & {\n  tabs: Record<string, ArgsTableProps>;\n};\n\nconst StyledTabsView = styled(TabsView)({\n  height: 'fit-content',\n});\n\nexport const TabbedArgsTable: FC<TabbedArgsTableProps> = ({ tabs, ...props }) => {\n  const entries = Object.entries(tabs);\n\n  if (entries.length === 1) {\n    return <ArgsTable {...entries[0][1]} {...props} />;\n  }\n\n  const tabsFromEntries = entries.map(([label, table], index) => ({\n    id: `prop_table_div_${label}`,\n    title: label,\n    children: () => {\n      /**\n       * The first tab is the main component, controllable if in the Controls block All other tabs\n       * are subcomponents, never controllable, so we filter out the props indicating\n       * controllability Essentially all subcomponents always behave like ArgTypes, never Controls\n       */\n      const argsTableProps = index === 0 ? props : { sort: props.sort };\n\n      return <ArgsTable inTabPanel key={`prop_table_${label}`} {...table} {...argsTableProps} />;\n    },\n  }));\n\n  return <StyledTabsView tabs={tabsFromEntries} />;\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/ArgsTable/index.ts",
    "content": "export * from './types';\n\nexport * from './ArgsTable';\n\nexport * from './TabbedArgsTable';\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/ArgsTable/types.ts",
    "content": "import type { Conditional } from 'storybook/internal/types';\n\n// TODO ?\nexport interface JsDocParam {\n  name: string;\n  description?: string;\n}\n\nexport interface JsDocParamDeprecated {\n  deprecated?: string;\n}\n\nexport interface JsDocReturns {\n  description?: string;\n}\n\nexport interface JsDocTags {\n  params?: JsDocParam[];\n  deprecated?: JsDocParamDeprecated;\n  returns?: JsDocReturns;\n}\n\nexport interface PropSummaryValue {\n  summary: string | undefined;\n  detail?: string | undefined;\n  required?: boolean;\n}\n\nexport type PropType = PropSummaryValue;\nexport type PropDefaultValue = PropSummaryValue;\n\nexport interface TableAnnotation {\n  type: PropType;\n  jsDocTags?: JsDocTags;\n  defaultValue?: PropDefaultValue;\n  category?: string;\n}\n\nexport interface ArgType {\n  name?: string;\n  description?: string;\n  defaultValue?: any;\n  if?: Conditional;\n  table?: {\n    category?: string;\n    disable?: boolean;\n    subcategory?: string;\n    defaultValue?: {\n      summary?: string | undefined;\n      detail?: string | undefined;\n    };\n    type?: {\n      summary?: string | undefined;\n      detail?: string | undefined;\n    };\n    readonly?: boolean;\n    [key: string]: any;\n  };\n  [key: string]: any;\n}\n\nexport interface ArgTypes {\n  [key: string]: ArgType;\n}\n\nexport interface Args {\n  [key: string]: any;\n}\n\nexport type Globals = { [name: string]: any };\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/BlockBackgroundStyles.tsx",
    "content": "import type { Theme } from 'storybook/theming';\n\nexport const getBlockBackgroundStyle: (theme: Theme) => object = (theme: Theme) => ({\n  borderRadius: theme.appBorderRadius,\n  background: theme.background.content,\n  boxShadow:\n    theme.base === 'light' ? 'rgba(0, 0, 0, 0.10) 0 1px 3px 0' : 'rgba(0, 0, 0, 0.20) 0 2px 5px 0',\n  border: `1px solid ${theme.appBorderColor}`,\n});\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/ColorPalette.stories.tsx",
    "content": "import React from 'react';\n\nimport { ColorItem, ColorPalette } from './ColorPalette';\n\nexport default {\n  component: ColorPalette,\n};\n\nexport const DefaultStyle = () => (\n  <ColorPalette>\n    <ColorItem\n      title=\"theme.color.greyscale\"\n      subtitle=\"Some of the greys\"\n      colors={['#FFFFFF', '#F8F8F8', '#F3F3F3']}\n    />\n    <ColorItem title=\"theme.color.primary\" subtitle=\"Coral\" colors={['#FF4785']} />\n    <ColorItem title=\"theme.color.secondary\" subtitle=\"Ocean\" colors={['#1EA7FD']} />\n    <ColorItem\n      title=\"theme.color.positive\"\n      subtitle=\"Green\"\n      colors={[\n        'rgba(102,191,60,1)',\n        'rgba(102,191,60,.8)',\n        'rgba(102,191,60,.6)',\n        'rgba(102,191,60,.3)',\n      ]}\n    />\n    <ColorItem\n      title=\"gradient\"\n      subtitle=\"Grayscale\"\n      colors={['linear-gradient(to right,white,black)']}\n    />\n  </ColorPalette>\n);\n\nexport const NamedColors = () => (\n  <ColorPalette>\n    <ColorItem\n      title=\"theme.color.greyscale\"\n      subtitle=\"Some of the greys\"\n      colors={{\n        White: '#FFFFFF',\n        Alabaster: '#F8F8F8',\n        Concrete: '#F3F3F3',\n      }}\n    />\n    <ColorItem\n      title=\"theme.color.primary\"\n      subtitle=\"Coral\"\n      colors={{\n        WildWatermelon: '#FF4785',\n      }}\n    />\n    <ColorItem\n      title=\"theme.color.secondary\"\n      subtitle=\"Ocean\"\n      colors={{\n        DodgerBlue: '#1EA7FD',\n      }}\n    />\n    <ColorItem\n      title=\"theme.color.positive\"\n      subtitle=\"Green\"\n      colors={{\n        Apple: 'rgba(102,191,60,1)',\n        Apple80: 'rgba(102,191,60,.8)',\n        Apple60: 'rgba(102,191,60,.6)',\n        Apple30: 'rgba(102,191,60,.3)',\n      }}\n    />\n    <ColorItem\n      title=\"gradient\"\n      subtitle=\"Grayscale\"\n      colors={{\n        Gradient: 'linear-gradient(to right,white,black)',\n      }}\n    />\n  </ColorPalette>\n);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/ColorPalette.tsx",
    "content": "import type { FunctionComponent } from 'react';\nimport React from 'react';\n\nimport { ResetWrapper } from 'storybook/internal/components';\n\nimport { transparentize } from 'polished';\nimport { styled } from 'storybook/theming';\n\nimport { getBlockBackgroundStyle } from './BlockBackgroundStyles';\n\nconst ItemTitle = styled.div(({ theme }) => ({\n  fontWeight: theme.typography.weight.bold,\n  color: theme.color.defaultText,\n}));\n\nconst ItemSubtitle = styled.div(({ theme }) => ({\n  color: transparentize(0.3, theme.color.defaultText),\n}));\n\nconst ItemDescription = styled.div({\n  flex: '0 0 30%',\n  lineHeight: '20px',\n  marginTop: 5,\n});\n\nconst SwatchLabel = styled.div(({ theme }) => ({\n  flex: 1,\n  textAlign: 'center',\n  fontFamily: theme.typography.fonts.mono,\n  fontSize: theme.typography.size.s1,\n  lineHeight: 1,\n  overflow: 'hidden',\n  color: transparentize(0.3, theme.color.defaultText),\n\n  '> div': {\n    display: 'inline-block',\n    overflow: 'hidden',\n    maxWidth: '100%',\n    textOverflow: 'ellipsis',\n  },\n\n  span: {\n    display: 'block',\n    marginTop: 2,\n  },\n}));\n\nconst SwatchLabels = styled.div({\n  display: 'flex',\n  flexDirection: 'row',\n});\n\ninterface SwatchProps {\n  background: string;\n}\n\nconst Swatch = styled.div<SwatchProps>(({ background }) => ({\n  position: 'relative',\n  flex: 1,\n\n  '&::before': {\n    position: 'absolute',\n    top: 0,\n    left: 0,\n    width: '100%',\n    height: '100%',\n    background,\n    content: '\"\"',\n  },\n}));\n\nconst SwatchColors = styled.div(({ theme }) => ({\n  ...getBlockBackgroundStyle(theme),\n  display: 'flex',\n  flexDirection: 'row',\n  height: 50,\n  marginBottom: 5,\n  overflow: 'hidden',\n  backgroundColor: 'white',\n  backgroundImage: `repeating-linear-gradient(-45deg, #ccc, #ccc 1px, #fff 1px, #fff 16px)`,\n  backgroundClip: 'padding-box',\n}));\n\nconst SwatchSpecimen = styled.div({\n  display: 'flex',\n  flexDirection: 'column',\n  flex: 1,\n  position: 'relative',\n  marginBottom: 30,\n});\n\nconst Swatches = styled.div({\n  flex: 1,\n  display: 'flex',\n  flexDirection: 'row',\n});\n\nconst Item = styled.div({\n  display: 'flex',\n  alignItems: 'flex-start',\n});\n\nconst ListName = styled.div({\n  flex: '0 0 30%',\n});\n\nconst ListSwatches = styled.div({\n  flex: 1,\n});\n\nconst ListHeading = styled.div(({ theme }) => ({\n  display: 'flex',\n  flexDirection: 'row',\n  alignItems: 'center',\n  paddingBottom: 20,\n  fontWeight: theme.typography.weight.bold,\n  color: transparentize(0.3, theme.color.defaultText),\n}));\n\nconst List = styled.div(({ theme }) => ({\n  fontSize: theme.typography.size.s2,\n  lineHeight: `20px`,\n\n  display: 'flex',\n  flexDirection: 'column',\n}));\n\ntype Colors = string[] | { [key: string]: string };\n\ninterface ColorItemProps {\n  title: string;\n  subtitle: string;\n  colors: Colors;\n}\n\nfunction renderSwatch(color: string, index: number) {\n  return <Swatch key={`${color}-${index}`} title={color} background={color} />;\n}\n\nfunction renderSwatchLabel(color: string, index: number, colorDescription?: string) {\n  return (\n    <SwatchLabel key={`${color}-${index}`} title={color}>\n      <div>\n        {color}\n        {colorDescription && <span>{colorDescription}</span>}\n      </div>\n    </SwatchLabel>\n  );\n}\n\nfunction renderSwatchSpecimen(colors: Colors) {\n  if (Array.isArray(colors)) {\n    return (\n      <SwatchSpecimen>\n        <SwatchColors>{colors.map((color, index) => renderSwatch(color, index))}</SwatchColors>\n        <SwatchLabels>{colors.map((color, index) => renderSwatchLabel(color, index))}</SwatchLabels>\n      </SwatchSpecimen>\n    );\n  }\n\n  const swatchElements = [];\n  const labelElements = [];\n\n  for (const colorKey in colors) {\n    const colorValue = colors[colorKey];\n    swatchElements.push(renderSwatch(colorValue, swatchElements.length));\n    labelElements.push(renderSwatchLabel(colorKey, labelElements.length, colorValue));\n  }\n\n  return (\n    <SwatchSpecimen>\n      <SwatchColors>{swatchElements}</SwatchColors>\n      <SwatchLabels>{labelElements}</SwatchLabels>\n    </SwatchSpecimen>\n  );\n}\n\n/**\n * A single color row your styleguide showing title, subtitle and one or more colors, used as a\n * child of `ColorPalette`.\n */\nexport const ColorItem: FunctionComponent<ColorItemProps> = ({ title, subtitle, colors }) => {\n  return (\n    <Item>\n      <ItemDescription>\n        <ItemTitle>{title}</ItemTitle>\n        <ItemSubtitle>{subtitle}</ItemSubtitle>\n      </ItemDescription>\n      <Swatches>{renderSwatchSpecimen(colors)}</Swatches>\n    </Item>\n  );\n};\n\ninterface ColorPaletteProps {\n  children?: React.ReactNode;\n}\n\n/**\n * Styleguide documentation for colors, including names, captions, and color swatches, all specified\n * as `ColorItem` children of this wrapper component.\n */\nexport const ColorPalette: FunctionComponent<ColorPaletteProps> = ({ children, ...props }) => (\n  <ResetWrapper>\n    <List {...props} className=\"docblock-colorpalette sb-unstyled\">\n      <ListHeading>\n        <ListName>Name</ListName>\n        <ListSwatches>Swatches</ListSwatches>\n      </ListHeading>\n      {children}\n    </List>\n  </ResetWrapper>\n);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/DocsPage.stories.tsx",
    "content": "/* eslint-disable jsx-a11y/anchor-is-valid */\nimport React from 'react';\n\nimport { Global, css } from 'storybook/theming';\n\nimport { ArgsTable, Source } from '.';\nimport { Markdown as MarkdownComponent } from '../blocks/Markdown';\nimport * as markdown from '../blocks/Markdown.stories';\nimport { Unstyled } from '../blocks/Unstyled';\nimport * as argsTable from './ArgsTable/ArgsTable.stories';\nimport { DocsPageWrapper, Subtitle, Title } from './DocsPage';\nimport * as Preview from './Preview.stories';\nimport * as source from './Source.stories';\n\nexport default {\n  component: DocsPageWrapper,\n  // The goal of this decorator is to mimic some CSS reset.\n  // Like Tailwind CSS or Bulma do, for example.\n  decorators: [\n    (storyFn: any) => (\n      <>\n        <Global\n          styles={css`\n            ul,\n            ol {\n              list-style: none;\n            }\n          `}\n        />\n        {storyFn()}\n      </>\n    ),\n  ],\n  parameters: {\n    layout: 'fullscreen',\n  },\n};\n\nexport const Loading = () => (\n  <DocsPageWrapper>\n    <Title>DocsPage</Title>\n    <Subtitle>\n      What the DocsPage looks like. Meant to be QAed in Canvas tab not in Docs tab.\n    </Subtitle>\n    <MarkdownComponent {...markdown.Text.args} />\n    <Preview.Loading />\n    <Source {...source.Loading.args} />\n  </DocsPageWrapper>\n);\n\nexport const WithSubtitle = () => (\n  <DocsPageWrapper>\n    <Title>DocsPage</Title>\n    <Subtitle>\n      What the DocsPage looks like. Meant to be QAed in Canvas tab not in Docs tab.\n    </Subtitle>\n    <MarkdownComponent {...markdown.Text.args} />\n    <Preview.Single />\n    <ArgsTable {...argsTable.Normal.args} />\n    <Source {...source.JSX.args} />\n  </DocsPageWrapper>\n);\n\nexport const NoText = () => (\n  <DocsPageWrapper>\n    <Title>no text</Title>\n    <Preview.Single />\n    <ArgsTable {...argsTable.Normal.args} />\n    <Source {...source.JSX.args} />\n  </DocsPageWrapper>\n);\n\nexport const Text = () => (\n  <DocsPageWrapper>\n    <Title>Sensorium</Title>\n    <MarkdownComponent {...markdown.Text.args} />\n    <Preview.Single />\n    <ArgsTable {...argsTable.Normal.args} />\n    <Source {...source.JSX.args} />\n  </DocsPageWrapper>\n);\n\nexport const Markdown = () => (\n  <DocsPageWrapper>\n    <Title>markdown</Title>\n    <MarkdownComponent {...markdown.Markdown.args} />\n    <Preview.Single />\n    <ArgsTable {...argsTable.Normal.args} />\n    <Source {...source.JSX.args} />\n  </DocsPageWrapper>\n);\n\nexport const Html = {\n  name: 'HTML',\n  render: () => (\n    <DocsPageWrapper>\n      <h1>Heading 1</h1>\n      <h2>Heading 2</h2>\n      <a>A tag</a>\n      <pre>pre tag</pre>\n      <div>\n        <div>Div</div>\n        <a>Nested A tag</a>\n      </div>\n      <div style={{ border: '2px solid red' }}>\n        <Unstyled>\n          <h1>Unstyled content</h1>\n          <h2>Heading 2</h2>\n          <a>A tag</a>\n          <div>\n            <div>Div</div>\n            <a>Nested A tag</a>\n          </div>\n        </Unstyled>\n      </div>\n    </DocsPageWrapper>\n  ),\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/DocsPage.test.tsx",
    "content": "// @vitest-environment happy-dom\nimport { cleanup, render } from '@testing-library/react';\nimport { afterEach, describe, expect, it } from 'vitest';\n\nimport React from 'react';\n\nimport { ThemeProvider, convert, themes } from 'storybook/theming';\n\nimport { DocsContent } from './DocsPage';\n\nfunction ThemedDocsContent({ children }: { children: React.ReactNode }) {\n  return (\n    <ThemeProvider theme={convert(themes.light)}>\n      <DocsContent>{children}</DocsContent>\n    </ThemeProvider>\n  );\n}\n\ndescribe('DocsContent', () => {\n  afterEach(() => {\n    cleanup();\n  });\n\n  describe('accessibility', () => {\n    it('should render links with underline text decoration for accessibility', () => {\n      const { container } = render(\n        <ThemedDocsContent>\n          <p>\n            This is a paragraph with a <a href=\"https://example.com\">link</a> inside.\n          </p>\n        </ThemedDocsContent>\n      );\n\n      const link = container.querySelector('a');\n      expect(link).toBeTruthy();\n\n      const styles = window.getComputedStyle(link!);\n      expect(styles.textDecoration).toContain('underline');\n    });\n\n    it('should render links with underline in dark theme', () => {\n      const { container } = render(\n        <ThemeProvider theme={convert(themes.dark)}>\n          <DocsContent>\n            <p>\n              This is a paragraph with a <a href=\"https://example.com\">link</a> inside.\n            </p>\n          </DocsContent>\n        </ThemeProvider>\n      );\n\n      const link = container.querySelector('a');\n      expect(link).toBeTruthy();\n\n      const styles = window.getComputedStyle(link!);\n      expect(styles.textDecoration).toContain('underline');\n    });\n\n    it('should render multiple links with underlines in text blocks', () => {\n      const { container } = render(\n        <ThemedDocsContent>\n          <div>\n            <p>\n              Check out <a href=\"https://example.com\">this link</a> and also{' '}\n              <a href=\"https://another.com\">this other link</a>.\n            </p>\n            <p>\n              Here is <a href=\"https://third.com\">a third link</a> in another paragraph.\n            </p>\n          </div>\n        </ThemedDocsContent>\n      );\n\n      const links = container.querySelectorAll('a');\n      expect(links).toHaveLength(3);\n\n      links.forEach((link) => {\n        const styles = window.getComputedStyle(link);\n        expect(styles.textDecoration).toContain('underline');\n      });\n    });\n\n    it('should not underline anchor position markers (a.anchor)', () => {\n      const { container } = render(\n        <ThemedDocsContent>\n          <h2>\n            <a className=\"anchor\" href=\"#heading\">\n              Heading\n            </a>\n          </h2>\n        </ThemedDocsContent>\n      );\n\n      const anchor = container.querySelector('a.anchor');\n      expect(anchor).toBeTruthy();\n\n      const styles = window.getComputedStyle(anchor!);\n      expect(styles.textDecoration).not.toContain('underline');\n    });\n  });\n});\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/DocsPage.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { withReset } from 'storybook/internal/components';\n\nimport { transparentize } from 'polished';\nimport type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\n/**\n * This selector styles all raw elements inside the DocsPage like this example with a `<div/>`:\n * :where(div:not(.sb-unstyled, .sb-anchor, .sb-unstyled div, .sb-unstyled div))\n *\n * 1. ':where': ensures this has a specificity of 0, making it easier to override.\n * 2. 'div:not(...)': selects all div elements that are not...\n * 3. '.sb-anchor': Ensures anchors are not styled, which would have led to inheritable styles bleeding\n *    all the way down to stories\n * 4. '.sb-unstyled, .sb-unstyled div': any element with sb-unstyled class, or descendants thereof\n * 5. .sb-unstyled is an escape hatch that allows the user to opt-out of the default styles by wrapping\n *    their content in an element with the 'sb-unstyled' class or the <Unstyled /> block.\n *\n * Most Storybook doc blocks has the sb-unstyled class to opt-out of the default styles.\n */\nconst toGlobalSelector = (element: string): string =>\n  `& :where(${element}:not(.sb-anchor, .sb-unstyled, .sb-unstyled ${element}))`;\n\nconst breakpoint = 600;\n\nexport const Title = styled.h1(({ theme }) => ({\n  ...(withReset({ theme }) as CSSObject),\n  color: theme.color.defaultText,\n  fontSize: theme.typography.size.m3,\n  fontWeight: theme.typography.weight.bold,\n  lineHeight: '32px',\n\n  [`@media (min-width: ${breakpoint}px)`]: {\n    fontSize: theme.typography.size.l1,\n    lineHeight: '36px',\n    marginBottom: '16px',\n  },\n}));\n\nexport const Subtitle = styled.h2(({ theme }) => ({\n  ...(withReset({ theme }) as CSSObject),\n  fontWeight: theme.typography.weight.regular,\n  fontSize: theme.typography.size.s3,\n  lineHeight: '20px',\n  borderBottom: 'none',\n  marginBottom: 15,\n\n  [`@media (min-width: ${breakpoint}px)`]: {\n    fontSize: theme.typography.size.m1,\n    lineHeight: '28px',\n    marginBottom: 24,\n  },\n\n  color: transparentize(0.25, theme.color.defaultText),\n}));\n\n// @ts-expect-error don't know why it doesn't accept our returned styles. if we add `...{}` anywhere to the returned object it stops erroring\nexport const DocsContent = styled.div(({ theme }) => {\n  const reset = {\n    fontFamily: theme.typography.fonts.base,\n    fontSize: theme.typography.size.s3,\n    margin: 0,\n\n    WebkitFontSmoothing: 'antialiased',\n    MozOsxFontSmoothing: 'grayscale',\n    WebkitTapHighlightColor: 'rgba(0, 0, 0, 0)',\n    WebkitOverflowScrolling: 'touch' as CSSObject['WebkitOverflowScrolling'],\n  };\n  const headers = {\n    margin: '20px 0 8px',\n    padding: 0,\n    cursor: 'text',\n    position: 'relative',\n    color: theme.color.defaultText,\n    '&:first-of-type': {\n      marginTop: 0,\n      paddingTop: 0,\n    },\n    '&:hover a.anchor': {\n      textDecoration: 'none',\n    },\n    '& code': {\n      fontSize: 'inherit',\n    },\n  };\n  const code = {\n    lineHeight: 1,\n    margin: '0 2px',\n    padding: '3px 5px',\n    whiteSpace: 'nowrap',\n\n    borderRadius: 3,\n    fontSize: theme.typography.size.s2 - 1,\n\n    border:\n      theme.base === 'light'\n        ? `1px solid ${theme.color.mediumlight}`\n        : `1px solid ${theme.color.darker}`,\n    color:\n      theme.base === 'light'\n        ? transparentize(0.1, theme.color.defaultText)\n        : transparentize(0.3, theme.color.defaultText),\n    backgroundColor: theme.base === 'light' ? theme.color.lighter : theme.color.border,\n  };\n\n  return {\n    maxWidth: 1000,\n    width: '100%',\n    minWidth: 0,\n    [toGlobalSelector('a')]: {\n      ...reset,\n      fontSize: 'inherit',\n      lineHeight: '24px',\n\n      color: theme.color.secondary,\n      // Ensure WCAG Level A compliance (SC 1.4.1), see https://www.w3.org/WAI/WCAG22/Techniques/failures/F73\n      textDecoration: 'underline',\n      textDecorationThickness: '0.03125rem',\n      textUnderlineOffset: '0.11em',\n      '&.absent': {\n        color: '#cc0000',\n      },\n      '&.anchor': {\n        display: 'block',\n        paddingLeft: 30,\n        marginLeft: -30,\n        cursor: 'pointer',\n        position: 'absolute',\n        top: 0,\n        left: 0,\n        bottom: 0,\n        textDecoration: 'none',\n      },\n      '&.anchor:hover, &.anchor:focus': {\n        textDecoration: 'underline',\n      },\n    },\n    [toGlobalSelector('blockquote')]: {\n      ...reset,\n      margin: '16px 0',\n      borderLeft: `4px solid ${theme.color.medium}`,\n      padding: '0 15px',\n      color: theme.color.dark,\n      '& > :first-of-type': {\n        marginTop: 0,\n      },\n      '& > :last-child': {\n        marginBottom: 0,\n      },\n    },\n    [toGlobalSelector('div')]: reset,\n    [toGlobalSelector('dl')]: {\n      ...reset,\n      margin: '16px 0',\n      padding: 0,\n      '& dt': {\n        fontSize: '14px',\n        fontWeight: 'bold',\n        fontStyle: 'italic',\n        padding: 0,\n        margin: '16px 0 4px',\n      },\n      '& dt:first-of-type': {\n        padding: 0,\n      },\n      '& dt > :first-of-type': {\n        marginTop: 0,\n      },\n\n      '& dt > :last-child': {\n        marginBottom: 0,\n      },\n\n      '& dd': {\n        margin: '0 0 16px',\n        padding: '0 15px',\n      },\n\n      '& dd > :first-of-type': {\n        marginTop: 0,\n      },\n\n      '& dd > :last-child': {\n        marginBottom: 0,\n      },\n    },\n    [toGlobalSelector('h1')]: {\n      ...reset,\n      ...headers,\n      fontSize: `${theme.typography.size.l1}px`,\n      fontWeight: theme.typography.weight.bold,\n    },\n    [toGlobalSelector('h2')]: {\n      ...reset,\n      ...headers,\n      fontSize: `${theme.typography.size.m2}px`,\n      paddingBottom: 4,\n      borderBottom: `1px solid ${theme.appBorderColor}`,\n    },\n    [toGlobalSelector('h3')]: {\n      ...reset,\n      ...headers,\n      fontSize: `${theme.typography.size.m1}px`,\n      fontWeight: theme.typography.weight.bold,\n    },\n    [toGlobalSelector('h4')]: {\n      ...reset,\n      ...headers,\n      fontSize: `${theme.typography.size.s3}px`,\n    },\n    [toGlobalSelector('h5')]: {\n      ...reset,\n      ...headers,\n      fontSize: `${theme.typography.size.s2}px`,\n    },\n    [toGlobalSelector('h6')]: {\n      ...reset,\n      ...headers,\n      fontSize: `${theme.typography.size.s2}px`,\n      color: theme.color.dark,\n    },\n    [toGlobalSelector('hr')]: {\n      border: '0 none',\n      borderTop: `1px solid ${theme.appBorderColor}`,\n      height: 4,\n      padding: 0,\n    },\n    [toGlobalSelector('img')]: {\n      maxWidth: '100%',\n    },\n    [toGlobalSelector('li')]: {\n      ...reset,\n      fontSize: theme.typography.size.s2,\n      color: theme.color.defaultText,\n      lineHeight: '24px',\n      '& + li': {\n        marginTop: '.25em',\n      },\n      '& ul, & ol': {\n        marginTop: '.25em',\n        marginBottom: 0,\n      },\n      '& code': code,\n    },\n    [toGlobalSelector('ol')]: {\n      ...reset,\n      margin: '16px 0',\n      paddingLeft: 30,\n      '& :first-of-type': {\n        marginTop: 0,\n      },\n      '& :last-child': {\n        marginBottom: 0,\n      },\n    },\n    [toGlobalSelector('p')]: {\n      ...reset,\n      margin: '16px 0',\n      fontSize: theme.typography.size.s2,\n      lineHeight: '24px',\n      color: theme.color.defaultText,\n      '& code': code,\n    },\n    [toGlobalSelector('pre')]: {\n      ...reset,\n      // reset\n      fontFamily: theme.typography.fonts.mono,\n      WebkitFontSmoothing: 'antialiased',\n      MozOsxFontSmoothing: 'grayscale',\n      lineHeight: '18px',\n      padding: '11px 1rem',\n      whiteSpace: 'pre-wrap',\n      color: 'inherit',\n      borderRadius: 3,\n      margin: '1rem 0',\n\n      '&:not(.prismjs)': {\n        background: 'transparent',\n        border: 'none',\n        borderRadius: 0,\n        padding: 0,\n        margin: 0,\n      },\n      '& pre, &.prismjs': {\n        padding: 15,\n        margin: 0,\n        whiteSpace: 'pre-wrap',\n        color: 'inherit',\n        fontSize: '13px',\n        lineHeight: '19px',\n        code: {\n          color: 'inherit',\n          fontSize: 'inherit',\n        },\n      },\n      '& code': {\n        whiteSpace: 'pre',\n      },\n      '& code, & tt': {\n        border: 'none',\n      },\n    },\n    [toGlobalSelector('span')]: {\n      ...reset,\n      '&.frame': {\n        display: 'block',\n        overflow: 'hidden',\n\n        '& > span': {\n          border: `1px solid ${theme.color.medium}`,\n          display: 'block',\n          float: 'left',\n          overflow: 'hidden',\n          margin: '13px 0 0',\n          padding: 7,\n          width: 'auto',\n        },\n        '& span img': {\n          display: 'block',\n          float: 'left',\n        },\n        '& span span': {\n          clear: 'both',\n          color: theme.color.darkest,\n          display: 'block',\n          padding: '5px 0 0',\n        },\n      },\n      '&.align-center': {\n        display: 'block',\n        overflow: 'hidden',\n        clear: 'both',\n\n        '& > span': {\n          display: 'block',\n          overflow: 'hidden',\n          margin: '13px auto 0',\n          textAlign: 'center',\n        },\n        '& span img': {\n          margin: '0 auto',\n          textAlign: 'center',\n        },\n      },\n      '&.align-right': {\n        display: 'block',\n        overflow: 'hidden',\n        clear: 'both',\n\n        '& > span': {\n          display: 'block',\n          overflow: 'hidden',\n          margin: '13px 0 0',\n          textAlign: 'right',\n        },\n        '& span img': {\n          margin: 0,\n          textAlign: 'right',\n        },\n      },\n      '&.float-left': {\n        display: 'block',\n        marginRight: 13,\n        overflow: 'hidden',\n        float: 'left',\n        '& span': {\n          margin: '13px 0 0',\n        },\n      },\n      '&.float-right': {\n        display: 'block',\n        marginLeft: 13,\n        overflow: 'hidden',\n        float: 'right',\n\n        '& > span': {\n          display: 'block',\n          overflow: 'hidden',\n          margin: '13px auto 0',\n          textAlign: 'right',\n        },\n      },\n    },\n    [toGlobalSelector('table')]: {\n      ...reset,\n      margin: '16px 0',\n      fontSize: theme.typography.size.s2,\n      lineHeight: '24px',\n      padding: 0,\n      borderCollapse: 'collapse',\n      '& tr': {\n        borderTop: `1px solid ${theme.appBorderColor}`,\n        backgroundColor: theme.appContentBg,\n        margin: 0,\n        padding: 0,\n      },\n      '& tr:nth-of-type(2n)': {\n        backgroundColor: theme.base === 'dark' ? theme.color.darker : theme.color.lighter,\n      },\n      '& tr th': {\n        fontWeight: 'bold',\n        color: theme.color.defaultText,\n        border: `1px solid ${theme.appBorderColor}`,\n        margin: 0,\n        padding: '6px 13px',\n      },\n      '& tr td': {\n        border: `1px solid ${theme.appBorderColor}`,\n        color: theme.color.defaultText,\n        margin: 0,\n        padding: '6px 13px',\n      },\n      '& tr th :first-of-type, & tr td :first-of-type': {\n        marginTop: 0,\n      },\n      '& tr th :last-child, & tr td :last-child': {\n        marginBottom: 0,\n      },\n    },\n    [toGlobalSelector('ul')]: {\n      ...reset,\n      margin: '16px 0',\n      paddingLeft: 30,\n      '& :first-of-type': {\n        marginTop: 0,\n      },\n      '& :last-child': {\n        marginBottom: 0,\n      },\n      listStyle: 'disc',\n    },\n  };\n});\n\nexport const DocsWrapper = styled.div(({ theme }) => ({\n  background: theme.background.content,\n  display: 'flex',\n  flexDirection: 'row-reverse',\n  justifyContent: 'center',\n  padding: '4rem 20px',\n  minHeight: '100vh',\n  boxSizing: 'border-box',\n  gap: '3rem',\n\n  [`@media (min-width: ${breakpoint}px)`]: {},\n}));\n\ninterface DocsPageWrapperProps {\n  children?: React.ReactNode;\n  toc?: React.ReactNode;\n}\n\nexport const DocsPageWrapper: FC<DocsPageWrapperProps> = ({ children, toc }) => (\n  <DocsWrapper className=\"sbdocs sbdocs-wrapper\">\n    {toc}\n    <DocsContent className=\"sbdocs sbdocs-content\">{children}</DocsContent>\n  </DocsWrapper>\n);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/DocsPageExampleCaption.md",
    "content": "# My Example Markdown\n\nThe group looked like tall, exotic grazing animals, swaying gracefully and unconsciously with the movement of the train, their high heels like polished hooves against the gray metal of the Flatline as a construct, a hardwired ROM cassette replicating a dead man’s skills, obsessions, kneejerk responses.\n\n![An image](https://storybook.js.org/images/placeholders/350x150.png)\n\nHe stared at the clinic, Molly took him to the Tank War, mouth touched with hot gold as a gliding cursor struck sparks from the wall of a skyscraper canyon. Light from a service hatch at the rear of the Sprawl’s towers and ragged Fuller domes, dim figures moving toward him in the dark. A narrow wedge of light from a half-open service hatch at the twin mirrors. Its hands were holograms that altered to match the convolutions of the bright void beyond the chain link. Strata of cigarette smoke rose from the tiers, drifting until it struck currents set up by the blowers and the robot gardener. Still it was a steady pulse of pain midway down his spine. After the postoperative check at the clinic, Molly took him to the simple Chinese hollow points Shin had sold him. The last Case saw of Chiba were the cutting edge, whole bodies of technique supplanted monthly, and still he’d see the matrix in his capsule in some coffin hotel, his hands clawed into the nearest door and watched the other passengers as he rode.\n\n## Typography\n\n# H1\n\n## H2\n\n### H3\n\n#### H4\n\n##### H5\n\n###### H6\n\nEmphasis, aka italics, with _asterisks_ or _underscores_.\n\nStrong emphasis, aka bold, with **asterisks** or **underscores**.\n\nCombined emphasis with **asterisks and _underscores_**.\n\nStrikethrough uses two tildes. ~~Scratch this.~~\n\nMaybe include a [link](http://storybook.js.org) to your project as well.\n\n## Block quote\n\nHow about a block quote to spice things up?\n\n> In der Bilanz ausgewiesene Verbindlichkeiten im Zusammenhang mit leistungsorientierten Pensionsfonds sind bei der Ermittlung des harten Kernkapitals („Common Equity Tier 1“, CET1) einhalten müssen. Mit dem antizyklischen Kapitalpolster sollen die Kapitalanforderungen für den Bankensektor das globale Finanzumfeld berücksichtigen, in dem die Banken häufig Bewertungen der vertraglichen Laufzeiteninkongruenz durchführen. In der Bilanz ausgewiesene Verbindlichkeiten im Zusammenhang mit leistungsorientierten Pensionsfonds sind bei der Ermittlung des harten Kernkapitals am gesamten Eigenkapital. Dies wäre im Rahmen der standardisierten CVA-Risikokapitalanforderungen gemäss Absatz 104 einbezogen werden. Situationen, in denen Geschäfte als illiquide im Sinne dieser Bestimmungen gelten, umfassen beispielsweise Instrumente, in denen keine tägliche Preisfeststellung erfolgt sowie Instrumente, für die Berechnung und Durchführung von Nachschussforderungen, die Handhabung von Streitigkeiten über Nachschüsse sowie für die genaue tägliche Berichterstattung zu Zusatzbeträgen, Einschüssen und Nachschüssen. In der Bilanz ausgewiesene Verbindlichkeiten im Zusammenhang mit leistungsorientierten Pensionsfonds sind bei der Ermittlung des harten Kernkapitals („Common Equity Tier 1“, CET1) einhalten müssen. Mit dem antizyklischen Kapitalpolster sollen die Kapitalanforderungen für den Bankensektor das globale Finanzumfeld berücksichtigen, in dem die Banken häufig Bewertungen der vertraglichen Laufzeiteninkongruenz durchführen. Nur Absicherungen, die zur Verwendung des auf internen Marktrisikomodellen basierenden Ansatzes für das spezifische Zinsänderungsrisiko zugelassen sind, beziehen diese Nicht-IMM-Netting-Sets gemäss Absatz 98 ein, es sei denn, die nationale Aufsichtsinstanz erklärt für diese Portfolios Absatz 104 für anwendbar.\n\n## Lists\n\nMixed list:\n\n1. First ordered list item\n2. Another item\n   - Unordered sub-list.\n3. Actual numbers don't matter, just that it's a number\n   1. Ordered sub-list\n   2. Yo ho ho\n4. And another item.\n\nBullet list:\n\n- Whatever\n  - This is getting\n  - Very ...\n    - Very ...\n    - Tedious!\n- It's getting late, nothing to see here\n\nNumbered:\n\n1. You get the idea\n2. You still get the idea\n3. You really get the idea\n4. I'm done\n\n## Tables\n\nA basic table:\n\n| Tables        |      Are      |   Cool |\n| ------------- | :-----------: | -----: |\n| col 3 is      | right-aligned | \\$1600 |\n| col 2 is      |   centered    |   \\$12 |\n| zebra stripes |   are neat    |    \\$1 |\n\nLet's throw in a crazy table, because why not?\n\n|                                               | [React](../../../../app/react) | [React Native](https://github.com/storybookjs/react-native) | [Vue](../../../../app/vue) | [Angular](../../../../app/angular) | [HTML](../../../../app/html) | [Svelte](../../../../app/svelte) | [Ember](../../../../app/ember) | [Preact](../../../../app/preact) |\n| --------------------------------------------- | ------------------------------ | ----------------------------------------------------------- | -------------------------- | ---------------------------------- | ---------------------------- | -------------------------------- | ------------------------------ | -------------------------------- |\n| [a11y](../../../../addons/a11y/)              | +                              |                                                             | +                          | +                                  | +                            |                                  | +                              | +                                |\n| [actions](../../../../addons/actions)         | +                              | +                                                           | +                          | +                                  | +                            | +                                | +                              | +                                |\n| [backgrounds](../../../../addons/backgrounds) | +                              | \\*                                                          | +                          | +                                  | +                            | +                                | +                              | +                                |\n| [measure](../../../../addons/measure)         | +                              |                                                             | +                          | +                                  | +                            | +                                | +                              | +                                |\n\n## Code\n\nSometimes you might want to manually include some \\`code\\` examples? Let's do it.\n\n```js\nconst Button = () => <button />;\n```\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/DocsPageExampleCaption.mdx",
    "content": "# My Example Markdown\n\nThe group looked like tall, exotic grazing animals, swaying gracefully and unconsciously with the movement of the train, their high heels like polished hooves against the gray metal of the Flatline as a construct, a hardwired ROM cassette replicating a dead man’s skills, obsessions, kneejerk responses.\n\n![An image](https://storybook.js.org/images/placeholders/350x150.png)\n\nHe stared at the clinic, Molly took him to the Tank War, mouth touched with hot gold as a gliding cursor struck sparks from the wall of a skyscraper canyon. Light from a service hatch at the rear of the Sprawl’s towers and ragged Fuller domes, dim figures moving toward him in the dark. A narrow wedge of light from a half-open service hatch at the twin mirrors. Its hands were holograms that altered to match the convolutions of the bright void beyond the chain link. Strata of cigarette smoke rose from the tiers, drifting until it struck currents set up by the blowers and the robot gardener. Still it was a steady pulse of pain midway down his spine. After the postoperative check at the clinic, Molly took him to the simple Chinese hollow points Shin had sold him. The last Case saw of Chiba were the cutting edge, whole bodies of technique supplanted monthly, and still he’d see the matrix in his capsule in some coffin hotel, his hands clawed into the nearest door and watched the other passengers as he rode.\n\n## Typography\n\n# H1\n\n## H2\n\n### H3\n\n#### H4\n\n##### H5\n\n###### H6\n\nEmphasis, aka italics, with _asterisks_ or _underscores_.\n\nStrong emphasis, aka bold, with **asterisks** or **underscores**.\n\nCombined emphasis with **asterisks and _underscores_**.\n\nStrikethrough uses two tildes. ~~Scratch this.~~\n\nMaybe include a [link](http://storybook.js.org) to your project as well.\n\n## Block quote\n\nHow about a block quote to spice things up?\n\n> In der Bilanz ausgewiesene Verbindlichkeiten im Zusammenhang mit leistungsorientierten Pensionsfonds sind bei der Ermittlung des harten Kernkapitals („Common Equity Tier 1“, CET1) einhalten müssen. Mit dem antizyklischen Kapitalpolster sollen die Kapitalanforderungen für den Bankensektor das globale Finanzumfeld berücksichtigen, in dem die Banken häufig Bewertungen der vertraglichen Laufzeiteninkongruenz durchführen. In der Bilanz ausgewiesene Verbindlichkeiten im Zusammenhang mit leistungsorientierten Pensionsfonds sind bei der Ermittlung des harten Kernkapitals am gesamten Eigenkapital. Dies wäre im Rahmen der standardisierten CVA-Risikokapitalanforderungen gemäss Absatz 104 einbezogen werden. Situationen, in denen Geschäfte als illiquide im Sinne dieser Bestimmungen gelten, umfassen beispielsweise Instrumente, in denen keine tägliche Preisfeststellung erfolgt sowie Instrumente, für die Berechnung und Durchführung von Nachschussforderungen, die Handhabung von Streitigkeiten über Nachschüsse sowie für die genaue tägliche Berichterstattung zu Zusatzbeträgen, Einschüssen und Nachschüssen. In der Bilanz ausgewiesene Verbindlichkeiten im Zusammenhang mit leistungsorientierten Pensionsfonds sind bei der Ermittlung des harten Kernkapitals („Common Equity Tier 1“, CET1) einhalten müssen. Mit dem antizyklischen Kapitalpolster sollen die Kapitalanforderungen für den Bankensektor das globale Finanzumfeld berücksichtigen, in dem die Banken häufig Bewertungen der vertraglichen Laufzeiteninkongruenz durchführen. Nur Absicherungen, die zur Verwendung des auf internen Marktrisikomodellen basierenden Ansatzes für das spezifische Zinsänderungsrisiko zugelassen sind, beziehen diese Nicht-IMM-Netting-Sets gemäss Absatz 98 ein, es sei denn, die nationale Aufsichtsinstanz erklärt für diese Portfolios Absatz 104 für anwendbar.\n\n## Lists\n\nMixed list:\n\n1. First ordered list item\n2. Another item\n   - Unordered sub-list.\n3. Actual numbers don't matter, just that it's a number\n   1. Ordered sub-list\n   2. Yo ho ho\n4. And another item.\n\nBullet list:\n\n- Whatever\n  - This is getting\n  - Very ...\n    - Very ...\n    - Tedious!\n- It's getting late, nothing to see here\n\nNumbered:\n\n1. You get the idea\n2. You still get the idea\n3. You really get the idea\n4. I'm done\n\n## Tables\n\nA basic table:\n\n| Tables        |      Are      |   Cool |\n| ------------- | :-----------: | -----: |\n| col 3 is      | right-aligned | \\$1600 |\n| col 2 is      |   centered    |   \\$12 |\n| zebra stripes |   are neat    |    \\$1 |\n\nLet's throw in a crazy table, because why not?\n\n|                                   | [React](app/react) | [React Native](app/react-native) | [Vue](app/vue) | [Angular](app/angular) | [HTML](app/html) | [Svelte](app/svelte) | [Ember](app/ember) | [Preact](app/preact) |\n| --------------------------------- | :----------------: | :------------------------------: | :------------: | :--------------------: | :--------------: | :------------------: | :----------------: | :------------------: |\n| [a11y](addons/a11y)               |         +          |                                  |       +        |           +            |        +         |                      |         +          |          +           |\n| [actions](addons/actions)         |         +          |                +                 |       +        |           +            |        +         |          +           |         +          |          +           |\n| [backgrounds](addons/backgrounds) |         +          |                \\*                |       +        |           +            |        +         |          +           |         +          |          +           |\n| [centered](addons/centered)       |         +          |                                  |       +        |           +            |        +         |          +           |         +          |          +           |\n\n## Code\n\nSometimes you might want to manually include some \\`code\\` examples? Let's do it.\n\n```js\nconst Button = () => <button />;\n```\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/EmptyBlock.stories.tsx",
    "content": "import React from 'react';\n\nimport { EmptyBlock } from './EmptyBlock';\n\nexport default {\n  component: EmptyBlock,\n};\n\nexport const Error = () => <EmptyBlock>Generic error message</EmptyBlock>;\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/EmptyBlock.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { withReset } from 'storybook/internal/components';\n\nimport { transparentize } from 'polished';\nimport { styled } from 'storybook/theming';\n\nconst Wrapper = styled.div(withReset, ({ theme }) => ({\n  backgroundColor: theme.base === 'light' ? 'rgba(0,0,0,.01)' : 'rgba(255,255,255,.01)',\n  borderRadius: theme.appBorderRadius,\n  border: `1px dashed ${theme.appBorderColor}`,\n  display: 'flex',\n  alignItems: 'center',\n  justifyContent: 'center',\n  padding: 20,\n  margin: '25px 0 40px',\n\n  color: transparentize(0.3, theme.color.defaultText),\n  fontSize: theme.typography.size.s2,\n}));\n\nexport const EmptyBlock: FC<\n  React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>\n> = (props) => <Wrapper {...props} className=\"docblock-emptyblock sb-unstyled\" />;\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/IFrame.tsx",
    "content": "import React, { Component } from 'react';\n\nconst { window: globalWindow } = globalThis;\n\ninterface IFrameProps {\n  id: string;\n  key?: string;\n  title: string;\n  src: string;\n  allowFullScreen: boolean;\n  scale: number;\n  style?: any;\n}\n\ninterface BodyStyle {\n  width: string;\n  height: string;\n  transform: string;\n  transformOrigin: string;\n}\n\nexport class IFrame extends Component<IFrameProps> {\n  iframe: any = null;\n\n  componentDidMount() {\n    const { id } = this.props;\n    this.iframe = globalWindow.document.getElementById(id);\n  }\n\n  shouldComponentUpdate(nextProps: IFrameProps) {\n    const { scale } = nextProps;\n    // eslint-disable-next-line react/destructuring-assignment\n    if (scale !== this.props.scale) {\n      this.setIframeBodyStyle({\n        width: `${scale * 100}%`,\n        height: `${scale * 100}%`,\n        transform: `scale(${1 / scale})`,\n        transformOrigin: 'top left',\n      });\n    }\n    return false;\n  }\n\n  setIframeBodyStyle(style: BodyStyle) {\n    return Object.assign(this.iframe.contentDocument.body.style, style);\n  }\n\n  render() {\n    const { id, title, src, allowFullScreen, scale, ...rest } = this.props;\n    return (\n      <iframe\n        id={id}\n        title={title}\n        src={src}\n        {...(allowFullScreen ? { allow: 'fullscreen' } : {})}\n        loading=\"lazy\"\n        {...rest}\n      />\n    );\n  }\n}\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/IconGallery.stories.tsx",
    "content": "import React from 'react';\n\nimport {\n  AddIcon,\n  AlertIcon,\n  BellIcon,\n  FaceHappyIcon,\n  HomeIcon,\n  SubtractIcon,\n} from '@storybook/icons';\n\nimport { IconGallery, IconItem } from './IconGallery';\n\nexport default {\n  component: IconGallery,\n};\n\nexport const DefaultStyle = () => (\n  <IconGallery>\n    <IconItem name=\"add\">\n      <AddIcon />\n    </IconItem>\n    <IconItem name=\"subtract\">\n      <SubtractIcon />\n    </IconItem>\n    <IconItem name=\"home\">\n      <HomeIcon />\n    </IconItem>\n    <IconItem name=\"facehappy\">\n      <FaceHappyIcon />\n    </IconItem>\n    <IconItem name=\"bar\">\n      <img src=\"https://storybook.js.org/images/placeholders/50x50.png\" alt=\"example\" />\n    </IconItem>\n    <IconItem name=\"very-long-icon-name\">\n      <AlertIcon />\n    </IconItem>\n    <IconItem name=\"very-long-icon-name-that-should-truncate\">\n      <BellIcon />\n    </IconItem>\n  </IconGallery>\n);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/IconGallery.tsx",
    "content": "import type { FunctionComponent } from 'react';\nimport React from 'react';\n\nimport { ResetWrapper } from 'storybook/internal/components';\n\nimport { styled } from 'storybook/theming';\n\nimport { getBlockBackgroundStyle } from './BlockBackgroundStyles';\n\nconst ItemLabel = styled.div(({ theme }) => ({\n  fontFamily: theme.typography.fonts.base,\n  fontSize: theme.typography.size.s1,\n  color: theme.color.defaultText,\n  marginLeft: 10,\n  lineHeight: 1.2,\n\n  display: '-webkit-box',\n  overflow: 'hidden',\n  wordBreak: 'break-word',\n  textOverflow: 'ellipsis',\n  WebkitLineClamp: 2,\n  WebkitBoxOrient: 'vertical',\n}));\n\nconst ItemSpecimen = styled.div(({ theme }) => ({\n  ...getBlockBackgroundStyle(theme),\n  overflow: 'hidden',\n  height: 40,\n  width: 40,\n  display: 'flex',\n  alignItems: 'center',\n  justifyContent: 'center',\n  flex: 'none',\n\n  '> img, > svg': {\n    width: 20,\n    height: 20,\n  },\n}));\n\nconst Item = styled.div({\n  display: 'inline-flex',\n  flexDirection: 'row',\n  alignItems: 'center',\n  width: '100%',\n});\n\nconst List = styled.div({\n  display: 'grid',\n  gridTemplateColumns: 'repeat(auto-fill, minmax(140px, 1fr))',\n  gridGap: '8px 16px',\n  gridAutoFlow: 'row dense',\n  gridAutoRows: 50,\n});\n\ninterface IconItemProps {\n  name: string;\n  children?: React.ReactNode;\n}\n\n/** An individual icon with a caption and an example (passed as `children`). */\nexport const IconItem: FunctionComponent<IconItemProps> = ({ name, children }) => (\n  <Item>\n    <ItemSpecimen>{children}</ItemSpecimen>\n    <ItemLabel>{name}</ItemLabel>\n  </Item>\n);\n\ninterface IconGalleryProps {\n  children?: React.ReactNode;\n}\n\n/** Show a grid of icons, as specified by `IconItem`. */\nexport const IconGallery: FunctionComponent<IconGalleryProps> = ({ children, ...props }) => (\n  <ResetWrapper>\n    <List {...props} className=\"docblock-icongallery sb-unstyled\">\n      {children}\n    </List>\n  </ResetWrapper>\n);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/Preview.stories.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React from 'react';\n\nimport { Button, Spaced } from 'storybook/internal/components';\nimport type { DocsContextProps, ModuleExport } from 'storybook/internal/types';\n\nimport { styled } from 'storybook/theming';\n\nimport * as ButtonStories from '../examples/Button.stories';\nimport { Preview, PreviewSkeleton } from './Preview';\nimport * as sourceStories from './Source.stories';\nimport { Story } from './Story';\n\nexport default {\n  component: Preview,\n  parameters: {\n    relativeCsfPaths: ['../examples/Button.stories'],\n  },\n};\n\nconst preview = (window as any).__STORYBOOK_PREVIEW__;\nconst renderStoryToElement = preview.renderStoryToElement.bind(preview);\n\nconst getPreparedStory = (docsContext: DocsContextProps, moduleExport: ModuleExport) => {\n  return docsContext.resolveOf(moduleExport, ['story']).story;\n};\n\nexport const Loading = () => <PreviewSkeleton />;\n\nexport const CodeCollapsed = () => (\n  <Preview inline isExpanded={false} withSource={sourceStories.JSX.args}>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 1\n    </Button>\n  </Preview>\n);\n\nexport const CodeExpanded = () => (\n  <Preview inline isExpanded withSource={sourceStories.JSX.args}>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 1\n    </Button>\n  </Preview>\n);\n\nexport const CodeError = () => (\n  <Preview inline isExpanded withSource={sourceStories.SourceUnavailable.args}>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 1\n    </Button>\n  </Preview>\n);\n\nexport const ActionBarWrapping = {\n  render: () => (\n    <Preview inline isExpanded withSource={sourceStories.JSX.args}>\n      <Button ariaLabel={false} variant=\"outline\">\n        Button with long text\n      </Button>\n    </Preview>\n  ),\n  globals: {\n    viewport: { value: 'mobile1' },\n  },\n};\n\nexport const Single = () => (\n  <Preview inline>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 1\n    </Button>\n  </Preview>\n);\n\nexport const Row = () => (\n  <Preview inline>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 1\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 2\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 3\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 4\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 5\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 6\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 7\n    </Button>\n  </Preview>\n);\n\nexport const Column = () => (\n  <Preview inline isColumn>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 1\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 2\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 3\n    </Button>\n  </Preview>\n);\n\nexport const GridWith3Columns = () => (\n  <Preview inline columns={3}>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 1\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 2\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 3\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 4\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 5\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 6\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 7 long long long long long{' '}\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 8\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 9\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 10\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 11\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 12\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 13\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 14\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 15\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 16\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 17\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 18\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 19\n    </Button>\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 20\n    </Button>\n  </Preview>\n);\n\nexport const WithToolbar = (\n  args: any,\n  { loaded: { docsContext } }: { loaded: { docsContext: DocsContextProps } }\n) => (\n  <Preview inline withToolbar>\n    <Story\n      inline\n      story={getPreparedStory(docsContext, ButtonStories.Primary)}\n      renderStoryToElement={renderStoryToElement}\n      autoplay={false}\n      forceInitialArgs={false}\n      primary={false}\n      height=\"36px\"\n    />\n  </Preview>\n);\n\nconst Horizontal = styled((props: ComponentProps<typeof Spaced>) => <Spaced col={1} {...props} />)({\n  display: 'grid',\n  gridTemplateColumns: '100px calc(100vw + 100px) 100px',\n});\n\nexport const Wide = () => (\n  <Preview inline withToolbar>\n    <Horizontal>\n      <div>START</div>\n      <div>middle</div>\n      <div>END</div>\n    </Horizontal>\n  </Preview>\n);\n\nexport const WithToolbarMulti = (\n  args: any,\n  { loaded: { docsContext } }: { loaded: { docsContext: DocsContextProps } }\n) => (\n  <Preview inline withToolbar>\n    <Story\n      inline\n      story={getPreparedStory(docsContext, ButtonStories.Primary)}\n      renderStoryToElement={renderStoryToElement}\n      autoplay={false}\n      forceInitialArgs={false}\n      primary={false}\n      height=\"36px\"\n    />\n    <Story\n      inline\n      story={getPreparedStory(docsContext, ButtonStories.Primary)}\n      renderStoryToElement={renderStoryToElement}\n      autoplay={false}\n      forceInitialArgs={false}\n      primary={false}\n      height=\"36px\"\n    />\n  </Preview>\n);\n\nexport const WithFullscreenSingle = (\n  args: any,\n  { loaded: { docsContext } }: { loaded: { docsContext: DocsContextProps } }\n) => (\n  <Preview inline withToolbar layout=\"fullscreen\">\n    <Story\n      inline\n      story={getPreparedStory(docsContext, ButtonStories.Primary)}\n      renderStoryToElement={renderStoryToElement}\n      autoplay={false}\n      forceInitialArgs={false}\n      primary={false}\n      height=\"36px\"\n    />\n  </Preview>\n);\n\nexport const WithFullscreenMulti = (\n  args: any,\n  { loaded: { docsContext } }: { loaded: { docsContext: DocsContextProps } }\n) => (\n  <Preview inline withToolbar layout=\"fullscreen\">\n    <Story\n      inline\n      story={getPreparedStory(docsContext, ButtonStories.Primary)}\n      renderStoryToElement={renderStoryToElement}\n      autoplay={false}\n      forceInitialArgs={false}\n      primary={false}\n      height=\"36px\"\n    />\n    <Story\n      inline\n      story={getPreparedStory(docsContext, ButtonStories.Primary)}\n      renderStoryToElement={renderStoryToElement}\n      autoplay={false}\n      forceInitialArgs={false}\n      primary={false}\n      height=\"36px\"\n    />\n  </Preview>\n);\n\nexport const WithCenteredSingle = (\n  args: any,\n  { loaded: { docsContext } }: { loaded: { docsContext: DocsContextProps } }\n) => (\n  <Preview inline withToolbar layout=\"centered\">\n    <Story\n      inline\n      story={getPreparedStory(docsContext, ButtonStories.Centered)}\n      renderStoryToElement={renderStoryToElement}\n      autoplay={false}\n      forceInitialArgs={false}\n      primary={false}\n      height=\"36px\"\n    />\n  </Preview>\n);\n\nexport const WithCenteredIframe = (\n  args: any,\n  { loaded: { docsContext } }: { loaded: { docsContext: DocsContextProps } }\n) => (\n  <Preview inline={false} withToolbar layout=\"centered\">\n    <Story\n      inline={false}\n      story={getPreparedStory(docsContext, ButtonStories.Centered)}\n      primary={false}\n      height=\"100px\"\n    />\n  </Preview>\n);\n\nexport const WithCenteredMulti = (\n  args: any,\n  { loaded: { docsContext } }: { loaded: { docsContext: DocsContextProps } }\n) => (\n  <Preview inline withToolbar layout=\"centered\">\n    <Story\n      inline\n      story={getPreparedStory(docsContext, ButtonStories.Centered)}\n      renderStoryToElement={renderStoryToElement}\n      autoplay={false}\n      forceInitialArgs={false}\n      primary={false}\n      height=\"36px\"\n    />\n    <Story\n      inline\n      story={getPreparedStory(docsContext, ButtonStories.Centered)}\n      renderStoryToElement={renderStoryToElement}\n      autoplay={false}\n      forceInitialArgs={false}\n      primary={false}\n      height=\"36px\"\n    />\n  </Preview>\n);\n\nexport const WithAdditionalActions = () => (\n  <Preview\n    inline\n    additionalActions={[\n      {\n        title: 'Open on GitHub',\n        onClick: () => {\n          globalThis.location.href =\n            'https://github.com/storybookjs/storybook/blob/next/code/lib/blocks/src/components/Preview.stories.tsx#L165-L186';\n        },\n      },\n    ]}\n  >\n    <Button ariaLabel={false} variant=\"outline\">\n      Button 1\n    </Button>\n  </Preview>\n);\n\nexport const SingleSmallViewport = () => (\n  <div style={{ width: 320 }}>\n    <Preview inline>\n      <Button ariaLabel={false} variant=\"outline\">\n        Button 1\n      </Button>\n    </Preview>\n  </div>\n);\nSingleSmallViewport.parameters = {\n  chromatic: { viewports: [320] },\n};\n\nexport const CodeExpandedSmallViewport = () => (\n  <div style={{ width: 320 }}>\n    <Preview inline isExpanded withSource={sourceStories.JSX.args}>\n      <Button ariaLabel={false} variant=\"outline\">\n        Button 1\n      </Button>\n    </Preview>\n  </div>\n);\nCodeExpandedSmallViewport.parameters = {\n  chromatic: { viewports: [320] },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/Preview.tsx",
    "content": "import type { FC, PropsWithChildren, ReactElement, ReactNode } from 'react';\nimport React, { Children, useCallback, useContext, useMemo, useState } from 'react';\n\nimport { logger } from 'storybook/internal/client-logger';\nimport { Bar, Button, ToggleButton, Zoom } from 'storybook/internal/components';\nimport type { ActionItem } from 'storybook/internal/components';\n\nimport { CopyIcon, MarkupIcon } from '@storybook/icons';\n\nimport { useId } from '@react-aria/utils';\nimport { darken } from 'polished';\nimport { styled } from 'storybook/theming';\n\nimport type { SourceProps } from '.';\nimport { Source } from '.';\nimport { DocsContext } from '../blocks/DocsContext';\nimport { getStoryId } from '../blocks/Story';\nimport { getBlockBackgroundStyle } from './BlockBackgroundStyles';\nimport { StorySkeleton } from './Story';\nimport { Toolbar } from './Toolbar';\nimport { ZoomContext } from './ZoomContext';\n\nexport type PreviewProps = PropsWithChildren<{\n  isLoading?: true;\n  layout?: Layout;\n  inline?: boolean;\n  isColumn?: boolean;\n  columns?: number;\n  withSource?: SourceProps;\n  isExpanded?: boolean;\n  withToolbar?: boolean;\n  className?: string;\n  additionalActions?: ActionItem[];\n  onReloadStory?: () => void;\n}>;\n\nexport type Layout = 'padded' | 'fullscreen' | 'centered';\n\nconst ChildrenContainer = styled.div<PreviewProps & { layout: Layout }>(\n  ({ isColumn, columns, layout }) => ({\n    display: isColumn || !columns ? 'block' : 'flex',\n    position: 'relative',\n    flexWrap: 'wrap',\n    overflow: 'auto',\n    flexDirection: isColumn ? 'column' : 'row',\n\n    '& .innerZoomElementWrapper > *': isColumn\n      ? {\n          width: layout !== 'fullscreen' ? 'calc(100% - 20px)' : '100%',\n          display: 'block',\n        }\n      : {\n          maxWidth: layout !== 'fullscreen' ? 'calc(100% - 20px)' : '100%',\n          display: 'inline-block',\n        },\n  }),\n  ({ layout = 'padded', inline }) =>\n    layout === 'centered' || layout === 'padded'\n      ? {\n          padding: inline ? '32px 22px' : '0px',\n          '& .innerZoomElementWrapper > *': {\n            width: 'auto',\n            border: '8px solid transparent!important',\n          },\n        }\n      : {},\n  ({ layout = 'padded', inline }) =>\n    layout === 'centered' && inline\n      ? {\n          display: 'flex',\n          justifyContent: 'center',\n          justifyItems: 'center',\n          alignContent: 'center',\n          alignItems: 'center',\n        }\n      : {},\n  ({ columns }) =>\n    columns && columns > 1\n      ? { '.innerZoomElementWrapper > *': { minWidth: `calc(100% / ${columns} - 20px)` } }\n      : {}\n);\n\nconst ActionBar = styled(Bar)({\n  marginTop: -40,\n  marginBottom: 40,\n});\n\nconst StyledSource = styled(Source)(({ theme }) => ({\n  margin: 0,\n  borderTopLeftRadius: 0,\n  borderTopRightRadius: 0,\n  borderBottomLeftRadius: theme.appBorderRadius,\n  borderBottomRightRadius: theme.appBorderRadius,\n  border: 'none',\n\n  background:\n    theme.base === 'light' ? 'rgba(0, 0, 0, 0.85)' : darken(0.05, theme.background.content),\n  color: theme.color.lightest,\n  button: {\n    background:\n      theme.base === 'light' ? 'rgba(0, 0, 0, 0.85)' : darken(0.05, theme.background.content),\n  },\n}));\n\nconst PreviewContainer = styled.div<PreviewProps>(\n  ({ theme }) => ({\n    position: 'relative',\n    overflow: 'hidden',\n    margin: '25px 0 40px',\n    ...getBlockBackgroundStyle(theme),\n    'h3 + &': {\n      marginTop: '16px',\n    },\n  }),\n  ({ withToolbar }) => withToolbar && { paddingTop: 40 }\n);\n\nfunction getChildProps(children: ReactNode) {\n  if (Children.count(children) === 1) {\n    const elt = children as ReactElement;\n    if (elt.props) {\n      return elt.props;\n    }\n  }\n  return null;\n}\n\nconst PositionedToolbar = styled(Toolbar)({\n  position: 'absolute',\n  top: 0,\n  left: 0,\n  right: 0,\n  height: 40,\n});\n\nconst COPIED_LABEL_ANIMATION_DURATION = 2000;\n\n/**\n * A preview component for showing one or more component `Story` items. The preview also shows the\n * source for the component as a drop-down.\n */\nexport const Preview: FC<PreviewProps> = ({\n  isLoading,\n  isColumn,\n  columns,\n  children,\n  withSource,\n  withToolbar = false,\n  isExpanded = false,\n  additionalActions,\n  className,\n  layout = 'padded',\n  inline = false,\n  onReloadStory,\n  ...props\n}) => {\n  const [expanded, setExpanded] = useState(isExpanded);\n  const [copied, setCopied] = useState<string | null>(null);\n  const [scale, setScale] = useState(1);\n  const additionalActionItems = useMemo(\n    () => (additionalActions ? [...additionalActions] : []),\n    [additionalActions]\n  );\n  const sourceId = useId();\n  const previewClasses = [className].concat(['sbdocs', 'sbdocs-preview', 'sb-unstyled']);\n\n  const context = useContext(DocsContext);\n\n  const copyToClipboard = useCallback(async (text: string) => {\n    const { createCopyToClipboardFunction } = await import('storybook/internal/components');\n    await createCopyToClipboardFunction()(text);\n  }, []);\n\n  const handleCopyCode = useCallback(async () => {\n    try {\n      await copyToClipboard(withSource?.code ?? '');\n      setCopied('Copied!');\n    } catch (err) {\n      logger.error(err);\n      setCopied('Copy error!');\n    }\n\n    globalThis.window.setTimeout(() => setCopied(null), COPIED_LABEL_ANIMATION_DURATION);\n  }, [copyToClipboard, withSource?.code]);\n\n  const childProps = getChildProps(children);\n\n  const hasSourceError = !!(withSource && withSource.error);\n  const hasValidSource = !!(withSource && !withSource.error);\n\n  return (\n    <>\n      <PreviewContainer\n        {...{ withSource, withToolbar }}\n        {...props}\n        className={previewClasses.join(' ')}\n      >\n        {withToolbar && (\n          <PositionedToolbar\n            isLoading={isLoading}\n            border\n            zoom={(z: number) => setScale(scale * z)}\n            resetZoom={() => setScale(1)}\n            storyId={!isLoading && childProps ? getStoryId(childProps, context) : undefined}\n            onReloadStory={onReloadStory}\n          />\n        )}\n        <ZoomContext.Provider value={{ scale }}>\n          <ChildrenContainer\n            isColumn={isColumn || !Array.isArray(children)}\n            columns={columns}\n            layout={layout}\n            inline={inline}\n            className=\"docs-story\"\n          >\n            <Zoom.Element centered={layout === 'centered'} scale={inline ? scale : 1}>\n              {Array.isArray(children) ? (\n                children.map((child, i) => <div key={i}>{child}</div>)\n              ) : (\n                <div>{children}</div>\n              )}\n            </Zoom.Element>\n          </ChildrenContainer>\n        </ZoomContext.Provider>\n        {hasValidSource && expanded && (\n          <div id={sourceId}>\n            <StyledSource {...withSource} dark copyable={false} />\n          </div>\n        )}\n      </PreviewContainer>\n      {(withSource || additionalActionItems.length > 0) && (\n        <ActionBar className=\"sbdocs sbdocs-preview-actions\" innerStyle={{ paddingInline: 0 }}>\n          {hasSourceError && (\n            <Button\n              ariaLabel={false}\n              disabled\n              variant=\"ghost\"\n              className=\"docblock-code-toggle docblock-code-toggle--disabled\"\n            >\n              <MarkupIcon /> No code available\n            </Button>\n          )}\n          {hasValidSource && (\n            <>\n              <ToggleButton\n                ariaLabel={false}\n                pressed={expanded}\n                aria-expanded={expanded}\n                aria-controls={sourceId}\n                onClick={() => setExpanded(!expanded)}\n                variant=\"ghost\"\n                className={`docblock-code-toggle${expanded ? ' docblock-code-toggle--expanded' : ''}`}\n              >\n                <MarkupIcon /> {expanded ? 'Hide code' : 'Show code'}\n              </ToggleButton>\n              <Button ariaLabel={false} variant=\"ghost\" onClick={handleCopyCode}>\n                <CopyIcon /> {copied ?? 'Copy code'}\n              </Button>\n            </>\n          )}\n          {additionalActionItems.map(({ title, className, onClick, disabled }, index: number) => (\n            <Button\n              key={index}\n              className={className}\n              onClick={onClick}\n              disabled={!!disabled}\n              variant=\"ghost\"\n            >\n              {title}\n            </Button>\n          ))}\n        </ActionBar>\n      )}\n    </>\n  );\n};\n\nconst StyledPreview = styled(Preview)(() => ({\n  '.docs-story': {\n    paddingTop: 32,\n    paddingBottom: 40,\n  },\n}));\n\nexport const PreviewSkeleton = () => (\n  <StyledPreview isLoading withToolbar>\n    <StorySkeleton />\n  </StyledPreview>\n);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/Source.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Source, SourceError } from './Source';\n\nconst meta: Meta<typeof Source> = {\n  component: Source,\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Loading: Story = {\n  args: { isLoading: true },\n};\n\nexport const JSX: Story = {\n  args: {\n    code: `\n<MyComponent boolProp scalarProp={1} complexProp={{ foo: 1, bar: '2' }}>\n  <SomeOtherComponent funcProp={(a) => a.id} />\n</MyComponent>\n`,\n    language: 'jsx',\n    format: false,\n  },\n};\n\nexport const CSSWithDarkMode: Story = {\n  args: {\n    code: `\n@-webkit-keyframes blinker {\n  from { opacity: 1.0; }\n  to { opacity: 0.0; }\n}\n\n.waitingForConnection {\n  -webkit-animation-name: blinker;\n  -webkit-animation-iteration-count: infinite;\n  -webkit-animation-timing-function: cubic-bezier(.5, 0, 1, 1);\n  -webkit-animation-duration: 1.7s;\n}\n`,\n    language: 'css',\n    format: false,\n    dark: true,\n  },\n};\n\nexport const GraphQLWithFormatting: Story = {\n  args: {\n    code: `query HeroNameAndFriends($episode: Episode) {\n          hero(episode: $episode) {\n            name\n            friends {\n              name\n            }\n          }\n        }\n`,\n    language: 'graphql',\n  },\n};\n\nexport const NoStory: Story = {\n  args: {\n    error: SourceError.NO_STORY,\n    format: false,\n  },\n};\n\nexport const SourceUnavailable: Story = {\n  args: {\n    error: SourceError.SOURCE_UNAVAILABLE,\n    format: false,\n  },\n};\n\nexport const JSXSmallViewport: Story = {\n  args: {\n    ...JSX.args,\n  },\n  parameters: {\n    chromatic: { viewports: [320] },\n  },\n  render: (args) => (\n    <div style={{ width: 320 }}>\n      <Source {...args} />\n    </div>\n  ),\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/Source.tsx",
    "content": "import type { ComponentProps, FunctionComponent } from 'react';\nimport React from 'react';\n\nimport type { SupportedLanguage, SyntaxHighlighterProps } from 'storybook/internal/components';\nimport { SyntaxHighlighter } from 'storybook/internal/components';\n\nimport {\n  ThemeProvider,\n  convert,\n  ignoreSsrWarning,\n  styled,\n  themes,\n  useTheme,\n} from 'storybook/theming';\n\nimport { EmptyBlock } from './EmptyBlock';\n\nconst StyledSyntaxHighlighter: React.FunctionComponent<SyntaxHighlighterProps> = styled(\n  SyntaxHighlighter\n)(({ theme }) => ({\n  // DocBlocks-specific styling and overrides\n  fontSize: `${theme.typography.size.s2 - 1}px`,\n  lineHeight: '19px',\n  margin: '25px 0 40px',\n  borderRadius: theme.appBorderRadius,\n  boxShadow:\n    theme.base === 'light' ? 'rgba(0, 0, 0, 0.10) 0 1px 3px 0' : 'rgba(0, 0, 0, 0.20) 0 2px 5px 0',\n  'pre.prismjs': {\n    padding: 20,\n    background: 'inherit',\n  },\n}));\n\nexport enum SourceError {\n  NO_STORY = 'There\\u2019s no story here.',\n  SOURCE_UNAVAILABLE = 'Oh no! The source is not available.',\n}\n\nexport interface SourceCodeProps {\n  /** The language the syntax highlighter uses for your story’s code */\n  language?: SupportedLanguage;\n  /** Use this to override the content of the source block. */\n  code?: string;\n  /** The formatter the syntax highlighter uses for your story’s code. */\n  format?: ComponentProps<typeof SyntaxHighlighter>['format'];\n  /** Display the source snippet in a dark mode. */\n  dark?: boolean;\n  /** Whether to show the copy button. Defaults to true. */\n  copyable?: boolean;\n}\n\nexport interface SourceProps extends SourceCodeProps {\n  isLoading?: boolean;\n  error?: SourceError;\n}\n\nconst SourceSkeletonWrapper = styled.div(({ theme }) => ({\n  background: theme.background.content,\n  borderRadius: theme.appBorderRadius,\n  border: `1px solid ${theme.appBorderColor}`,\n  boxShadow:\n    theme.base === 'light' ? 'rgba(0, 0, 0, 0.10) 0 1px 3px 0' : 'rgba(0, 0, 0, 0.20) 0 2px 5px 0',\n  margin: '25px 0 40px',\n  padding: '20px 20px 20px 22px',\n}));\n\nconst SourceSkeletonPlaceholder = styled.div(({ theme }) => ({\n  animation: `${theme.animation.glow} 1.5s ease-in-out infinite`,\n  background: theme.appBorderColor,\n  height: 17,\n  marginTop: 1,\n  width: '60%',\n\n  [`&:first-child${ignoreSsrWarning}`]: {\n    margin: 0,\n  },\n}));\n\nconst SourceSkeleton = () => (\n  <SourceSkeletonWrapper>\n    <SourceSkeletonPlaceholder />\n    <SourceSkeletonPlaceholder style={{ width: '80%' }} />\n    <SourceSkeletonPlaceholder style={{ width: '30%' }} />\n    <SourceSkeletonPlaceholder style={{ width: '80%' }} />\n  </SourceSkeletonWrapper>\n);\n\n/** Syntax-highlighted source code for a component (or anything!) */\nconst Source: FunctionComponent<SourceProps> = ({\n  isLoading,\n  error,\n  language,\n  code,\n  dark,\n  format = true,\n  copyable = true,\n  ...rest\n}) => {\n  const { typography } = useTheme();\n  if (isLoading) {\n    return <SourceSkeleton />;\n  }\n  if (error) {\n    return <EmptyBlock>{error}</EmptyBlock>;\n  }\n\n  const syntaxHighlighter = (\n    <StyledSyntaxHighlighter\n      bordered\n      copyable={copyable}\n      format={format}\n      language={language ?? 'jsx'}\n      className=\"docblock-source sb-unstyled\"\n      {...rest}\n    >\n      {code}\n    </StyledSyntaxHighlighter>\n  );\n  if (typeof dark === 'undefined') {\n    return syntaxHighlighter;\n  }\n  const overrideTheme = dark ? themes.dark : themes.light;\n  return (\n    <ThemeProvider\n      theme={convert({\n        ...overrideTheme,\n        fontCode: typography.fonts.mono,\n        fontBase: typography.fonts.base,\n      })}\n    >\n      {syntaxHighlighter}\n    </ThemeProvider>\n  );\n};\n\nexport { Source, StyledSyntaxHighlighter };\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/Story.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Channel } from 'storybook/internal/channels';\nimport {\n  RESET_STORY_ARGS,\n  STORY_ARGS_UPDATED,\n  UPDATE_STORY_ARGS,\n} from 'storybook/internal/core-events';\nimport type { PlayFunctionContext } from 'storybook/internal/csf';\nimport type { ModuleExport, WebRenderer } from 'storybook/internal/types';\n\nimport type { Meta, ReactRenderer, StoryObj } from '@storybook/react-vite';\n\nimport type { PreviewWeb } from 'storybook/preview-api';\nimport { within } from 'storybook/test';\n\nimport type { DocsContextProps } from '../blocks';\nimport * as ButtonStories from '../examples/Button.stories';\nimport type { StoryProps } from './Story';\nimport { Story as StoryComponent, StorySkeleton } from './Story';\n\nconst preview = (window as any).__STORYBOOK_PREVIEW__ as PreviewWeb<ReactRenderer>;\nconst channel = (window as any).__STORYBOOK_ADDONS_CHANNEL__ as Channel;\nconst renderStoryToElement = preview.renderStoryToElement.bind(preview);\n\ntype ExtendedStoryProps = Omit<StoryProps, 'story'> & {\n  storyExport: ModuleExport;\n};\n\nconst meta: Meta<ExtendedStoryProps> = {\n  // @ts-expect-error getting too complex with props\n  component: StoryComponent,\n  parameters: {\n    layout: 'fullscreen',\n    relativeCsfPaths: ['../examples/Button.stories'],\n  },\n  globals: { sb_theme: 'light' },\n  args: {\n    height: '100px',\n    primary: false,\n    // NOTE: the real story arg is a PreparedStory, which we'll get in the render function below\n    storyExport: ButtonStories.Primary as any,\n  },\n  render({ storyExport, ...args }, { loaded }) {\n    const docsContext = loaded.docsContext as DocsContextProps;\n    const resolved = docsContext.resolveOf(storyExport, ['story']);\n    // @ts-expect-error getting too complex with props\n    return <StoryComponent {...args} story={resolved.story} />;\n  },\n};\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Loading = {\n  globals: { sb_theme: 'side-by-side' },\n  render: () => <StorySkeleton />,\n};\n\nexport const Inline: Story = {\n  args: {\n    inline: true,\n    // @ts-expect-error getting too complex with props\n    autoplay: false,\n    forceInitialArgs: false,\n    renderStoryToElement,\n  },\n};\n\nexport const InlineError: Story = {\n  args: {\n    storyExport: ButtonStories.ErrorStory,\n    inline: true,\n    // @ts-expect-error getting too complex with props\n    autoplay: false,\n    forceInitialArgs: false,\n    renderStoryToElement,\n  },\n};\n\nexport const IFrame: Story = {\n  name: 'IFrame',\n  args: {\n    inline: false,\n  },\n};\n\nexport const ForceInitialArgs = {\n  args: {\n    storyExport: ButtonStories.Primary,\n    inline: true,\n    autoplay: true,\n    forceInitialArgs: true,\n    renderStoryToElement,\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n  // test that it ignores updated args by emitting an arg update and assert that it isn't reflected in the DOM\n  play: async ({ args, canvasElement, loaded }: PlayFunctionContext<WebRenderer>) => {\n    const docsContext = loaded.docsContext as DocsContextProps;\n    const resolved = docsContext.resolveOf(args.storyExport, ['story']);\n\n    await within(canvasElement).findByText(/Button/);\n\n    const updatedPromise = new Promise<void>((resolve) => {\n      channel.once(STORY_ARGS_UPDATED, resolve);\n    });\n    await channel.emit(UPDATE_STORY_ARGS, {\n      storyId: resolved.story.id,\n      updatedArgs: { label: 'Updated' },\n    });\n    await updatedPromise;\n    await within(canvasElement).findByText(/Button/);\n\n    await channel.emit(RESET_STORY_ARGS, { storyId: resolved.story.id });\n    await new Promise<void>((resolve) => {\n      channel.once(STORY_ARGS_UPDATED, resolve);\n    });\n  },\n};\n\nexport const Autoplay: Story = {\n  args: {\n    storyExport: ButtonStories.Clicking,\n    inline: true,\n    // @ts-expect-error getting too complex with props\n    autoplay: true,\n    renderStoryToElement,\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/Story.tsx",
    "content": "/* eslint-disable react/destructuring-assignment */\nimport type { FunctionComponent } from 'react';\nimport React, { useEffect, useRef, useState } from 'react';\n\nimport { ErrorFormatter, Loader } from 'storybook/internal/components';\nimport type { DocsContextProps, PreparedStory } from 'storybook/internal/types';\n\nimport { styled } from 'storybook/theming';\n\nimport { getStoryHref } from '../getStoryHref';\nimport { IFrame } from './IFrame';\nimport { ZoomContext } from './ZoomContext';\n\ninterface CommonProps {\n  story: PreparedStory;\n  inline: boolean;\n  primary: boolean;\n}\n\ninterface InlineStoryProps extends CommonProps {\n  inline: true;\n  height?: string;\n  autoplay: boolean;\n  forceInitialArgs: boolean;\n  renderStoryToElement: DocsContextProps['renderStoryToElement'];\n}\n\ninterface IFrameStoryProps extends CommonProps {\n  inline: false;\n  height: string;\n}\n\nexport type StoryProps = InlineStoryProps | IFrameStoryProps;\n\nexport const storyBlockIdFromId = ({ story, primary }: StoryProps) =>\n  `story--${story.id}${primary ? '--primary' : ''}`;\n\nconst InlineStory: FunctionComponent<InlineStoryProps> = (props) => {\n  const storyRef = useRef();\n  const [showLoader, setShowLoader] = useState(true);\n  const [error, setError] = useState<Error>();\n\n  const { story, height, autoplay, forceInitialArgs, renderStoryToElement } = props;\n\n  useEffect(() => {\n    if (!(story && storyRef.current)) {\n      return () => {};\n    }\n    const element = storyRef.current as HTMLElement;\n    const cleanup = renderStoryToElement(\n      story,\n      element,\n      {\n        showMain: () => {},\n        showError: ({ title, description }: { title: string; description: string }) =>\n          setError(new Error(`${title} - ${description}`)),\n        showException: (err: Error) => setError(err),\n      },\n      { autoplay, forceInitialArgs }\n    );\n    setShowLoader(false);\n    return () => {\n      // It seems like you are supposed to unmount components outside of `useEffect`:\n      //   https://github.com/facebook/react/issues/25675#issuecomment-1363957941\n      Promise.resolve().then(() => cleanup());\n    };\n  }, [autoplay, renderStoryToElement, story]);\n\n  if (error) {\n    return (\n      <pre>\n        <ErrorFormatter error={error} />\n      </pre>\n    );\n  }\n\n  return (\n    <>\n      {height ? (\n        <style>{`#${storyBlockIdFromId(\n          props\n        )} { min-height: ${height}; transform: translateZ(0); overflow: auto }`}</style>\n      ) : null}\n      {showLoader && <StorySkeleton />}\n      <div ref={storyRef as any} id={`${storyBlockIdFromId(props)}-inner`} data-name={story.name} />\n    </>\n  );\n};\n\nconst IFrameStory: FunctionComponent<IFrameStoryProps> = ({ story, height = '500px' }) => (\n  <div style={{ width: '100%', height }}>\n    <ZoomContext.Consumer>\n      {({ scale }) => {\n        return (\n          <IFrame\n            key=\"iframe\"\n            id={`iframe--${story.id}`}\n            title={story.name}\n            src={getStoryHref(story.id, { viewMode: 'story' })}\n            allowFullScreen\n            scale={scale}\n            style={{\n              width: '100%',\n              height: '100%',\n              border: '0 none',\n            }}\n          />\n        );\n      }}\n    </ZoomContext.Consumer>\n  </div>\n);\n\n/** A story element, either rendered inline or in an iframe, with configurable height. */\n\nconst ErrorMessage = styled.strong(({ theme }) => ({\n  color: theme.color.orange,\n}));\n\nconst Story: FunctionComponent<StoryProps> = (props) => {\n  const { inline, story } = props;\n\n  if (inline && !props.autoplay && story.usesMount) {\n    return (\n      <ErrorMessage>\n        This story mounts inside of play. Set{' '}\n        <a href=\"https://storybook.js.org/docs/api/doc-blocks/doc-block-story?ref=ui#autoplay\">\n          autoplay\n        </a>{' '}\n        to true to view this story.\n      </ErrorMessage>\n    );\n  }\n\n  return (\n    <div id={storyBlockIdFromId(props)} className=\"sb-story sb-unstyled\" data-story-block=\"true\">\n      {inline ? (\n        <InlineStory {...(props as InlineStoryProps)} />\n      ) : (\n        <IFrameStory {...(props as IFrameStoryProps)} />\n      )}\n    </div>\n  );\n};\n\nconst StorySkeleton = () => <Loader />;\n\nexport { Story, StorySkeleton };\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/TableOfContents.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { expect, within } from 'storybook/test';\nimport { styled } from 'storybook/theming';\n\nimport { Heading } from '../blocks/Heading';\nimport { TableOfContents } from './TableOfContents';\n\nconst MockPage = styled.div`\n  display: flex;\n  flex-direction: row;\n`;\n\nconst MockContent = styled.div`\n  width: 75%;\n  border: 1px solid #ccc;\n`;\n\nconst meta = {\n  component: TableOfContents,\n  parameters: {\n    docs: {\n      description: {\n        component: 'Sanity checks on the TableOfContents component that encapsulates tocbot.',\n      },\n    },\n  },\n  render: (args) => {\n    return (\n      <MockPage>\n        <MockContent className=\"local-story-docs\">\n          <h1>Page title</h1>\n          <Heading>Section A</Heading>\n          Some content.\n          <Heading>Section B</Heading>\n          More content.\n          <Heading>Section C</Heading>\n          Extra content.\n        </MockContent>\n        <TableOfContents {...args} />\n      </MockPage>\n    );\n  },\n} satisfies Meta<typeof TableOfContents>;\n\nexport default meta;\n\nexport const Default: StoryObj<typeof meta> = {\n  args: {\n    // Not used here yet. Would need to be mocked to test navigation.\n    channel: {} as any,\n    headingSelector: 'h1, h2, h3',\n    contentsSelector: '.local-story-docs',\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n\n    const toc = canvas.getByRole('navigation');\n    await step('Verify nav presence', async () => {\n      expect(toc).toBeInTheDocument();\n      expect(toc.tagName).toBe('NAV');\n    });\n\n    const title = canvas.getByRole('heading', { name: 'Table of contents' });\n    await step('Verify title is present but invisible', async () => {\n      expect(title).toBeInTheDocument();\n      expect(title).toHaveClass('sb-sr-only');\n    });\n\n    await step('Verify nav aria-labelledby', async () => {\n      expect(toc).toHaveAttribute('aria-labelledby', title.id);\n    });\n\n    const wrapper = canvas.getByRole('complementary');\n    await step('Verify toc is wrapped by an aside', async () => {\n      expect(wrapper).toBeInTheDocument();\n      expect(wrapper.tagName).toBe('ASIDE');\n      expect(wrapper.children[0]).toBe(toc);\n    });\n  },\n};\n\nexport const WithTitle: StoryObj<typeof meta> = {\n  args: {\n    channel: {} as any,\n    headingSelector: 'h1, h2, h3',\n    contentsSelector: '.local-story-docs',\n    title: 'In this page',\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n\n    const toc = canvas.getByRole('navigation');\n    await step('Verify nav presence', async () => {\n      expect(toc).toBeInTheDocument();\n      expect(toc.tagName).toBe('NAV');\n    });\n\n    const title = canvas.getByRole('heading', { name: 'In this page' });\n    await step('Verify title presence', async () => {\n      expect(title).toBeInTheDocument();\n    });\n\n    await step('Verify nav aria-labelledby', async () => {\n      expect(toc).toHaveAttribute('aria-labelledby', title.id);\n    });\n  },\n};\n\nexport const WithReactTitle: StoryObj<typeof meta> = {\n  args: {\n    channel: {} as any,\n    headingSelector: 'h1, h2, h3',\n    contentsSelector: '.local-story-docs',\n    title: (\n      <>\n        In <em>this</em> page\n      </>\n    ),\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n\n    const toc = canvas.getByRole('navigation');\n    await step('Verify nav presence', async () => {\n      expect(toc).toBeInTheDocument();\n      expect(toc.tagName).toBe('NAV');\n    });\n\n    const title = toc.children[0];\n    await step('Verify title presence', async () => {\n      expect(title).toBeInTheDocument();\n      expect(title.innerHTML).toBe('In <em>this</em> page');\n    });\n\n    await step('Verify nav aria-labelledby', async () => {\n      expect(toc).toHaveAttribute('aria-labelledby', title.id);\n    });\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/TableOfContents.tsx",
    "content": "import React, { useEffect } from 'react';\nimport type { FC, ReactElement } from 'react';\n\nimport type { Channel } from 'storybook/internal/channels';\nimport { NAVIGATE_URL } from 'storybook/internal/core-events';\n\nimport { styled } from 'storybook/theming';\nimport tocbot from 'tocbot';\n\n// Define our own interface based on tocbot's actual options\ninterface TocbotOptions {\n  tocSelector: string;\n  contentSelector: string;\n  headingSelector: string;\n  ignoreSelector?: string;\n  headingsOffset?: number;\n  scrollSmoothOffset?: number;\n  orderedList?: boolean;\n  onClick?: (e: MouseEvent) => void;\n  scrollEndCallback?: () => void;\n  [key: string]: unknown;\n}\n\nexport interface TocParameters {\n  /** CSS selector for the container to search for headings. */\n  contentsSelector?: string;\n\n  /**\n   * When true, hide the TOC. We still show the empty container (as opposed to showing nothing at\n   * all) because it affects the page layout and we want to preserve the layout across pages.\n   */\n  disable?: boolean;\n\n  /** CSS selector to match headings to list in the TOC. */\n  headingSelector?: string;\n\n  /** Headings that match the ignoreSelector will be skipped. */\n  ignoreSelector?: string;\n\n  /** Custom title ReactElement or string to display above the TOC. */\n  title?: ReactElement | string | null;\n\n  /**\n   * TocBot options, not guaranteed to be available in future versions.\n   *\n   * @see tocbot docs {@link https://tscanlin.github.io/tocbot/#usage}\n   */\n  unsafeTocbotOptions?: Omit<TocbotOptions, 'onClick' | 'scrollEndCallback'>;\n}\n\nconst Aside = styled.aside(() => ({\n  width: '10rem',\n\n  '@media (max-width: 768px)': {\n    display: 'none',\n  },\n}));\n\nconst Nav = styled.nav(({ theme }) => ({\n  position: 'fixed',\n  bottom: 0,\n  top: 0,\n  width: '10rem',\n  paddingTop: '4rem',\n  paddingBottom: '2rem',\n  overflowY: 'auto',\n\n  fontFamily: theme.typography.fonts.base,\n  fontSize: theme.typography.size.s2,\n\n  WebkitFontSmoothing: 'antialiased',\n  MozOsxFontSmoothing: 'grayscale',\n  WebkitTapHighlightColor: 'rgba(0, 0, 0, 0)',\n  WebkitOverflowScrolling: 'touch',\n\n  '& *': {\n    boxSizing: 'border-box',\n  },\n\n  '& > .toc-wrapper > .toc-list': {\n    paddingLeft: 0,\n    borderLeft: `solid 2px ${theme.color.mediumlight}`,\n\n    '.toc-list': {\n      paddingLeft: 0,\n      borderLeft: `solid 2px ${theme.color.mediumlight}`,\n\n      '.toc-list': {\n        paddingLeft: 0,\n        borderLeft: `solid 2px ${theme.color.mediumlight}`,\n      },\n    },\n  },\n  '& .toc-list-item': {\n    position: 'relative',\n    listStyleType: 'none',\n    marginLeft: 20,\n    paddingTop: 3,\n    paddingBottom: 3,\n  },\n  '& .toc-list-item::before': {\n    content: '\"\"',\n    position: 'absolute',\n    height: '100%',\n    top: 0,\n    left: 0,\n    transform: `translateX(calc(-2px - 20px))`,\n    borderLeft: `solid 2px ${theme.color.mediumdark}`,\n    opacity: 0,\n    transition: 'opacity 0.2s',\n  },\n  '& .toc-list-item.is-active-li::before': {\n    opacity: 1,\n  },\n  '& .toc-list-item > a': {\n    color: theme.color.defaultText,\n    textDecoration: 'none',\n  },\n  '& .toc-list-item.is-active-li > a': {\n    fontWeight: 600,\n    color: theme.color.secondary,\n    textDecoration: 'none',\n  },\n}));\n\nconst Heading = styled.p(({ theme }) => ({\n  fontWeight: 600,\n  fontSize: '0.875em',\n  color: theme.color.defaultText,\n  textTransform: 'uppercase',\n  marginBottom: 10,\n}));\n\ntype TableOfContentsProps = React.PropsWithChildren<\n  TocParameters & {\n    className?: string;\n    channel: Channel;\n  }\n>;\n\nconst Title: FC<{\n  headingId: string;\n  title: TableOfContentsProps['title'];\n}> = ({ headingId, title }) => {\n  // General case.\n  if (typeof title === 'string' || !title) {\n    return (\n      <Heading as=\"h2\" id={headingId} className={title ? '' : 'sb-sr-only'}>\n        {title || 'Table of contents'}\n      </Heading>\n    );\n  }\n\n  // Custom JSX title: we must ensure an ID is set for ARIA attributes to work.\n  return <div id={headingId}>{title}</div>;\n};\n\nexport const TableOfContents = ({\n  title,\n  disable,\n  headingSelector,\n  contentsSelector,\n  ignoreSelector,\n  unsafeTocbotOptions,\n  channel,\n  className,\n}: TableOfContentsProps) => {\n  useEffect(() => {\n    // Do not initialize tocbot when we won't be rendering a ToC.\n    if (disable) {\n      return () => {};\n    }\n\n    const configuration = {\n      tocSelector: '.toc-wrapper',\n      contentSelector: contentsSelector ?? '.sbdocs-content',\n      headingSelector: headingSelector ?? 'h3',\n      /** Ignore headings that did not come from the main markdown code. */\n      ignoreSelector: ignoreSelector ?? '.docs-story *, .skip-toc',\n      headingsOffset: 40,\n      scrollSmoothOffset: -40,\n      orderedList: false,\n      /** Prevent default linking behavior, leaving only the smooth scrolling. */\n      onClick: (e: MouseEvent) => {\n        e.preventDefault();\n        if (e.currentTarget instanceof HTMLAnchorElement) {\n          const [, headerId] = e.currentTarget.href.split('#');\n          if (headerId) {\n            channel.emit(NAVIGATE_URL, `#${headerId}`);\n          }\n        }\n      },\n      ...unsafeTocbotOptions,\n    };\n\n    /** Wait for the DOM to be ready. */\n    const timeout = setTimeout(() => tocbot.init(configuration), 100);\n    return () => {\n      clearTimeout(timeout);\n      tocbot.destroy();\n    };\n  }, [channel, disable, ignoreSelector, contentsSelector, headingSelector, unsafeTocbotOptions]);\n\n  const headingId = 'table-of-contents';\n\n  return (\n    <Aside className={className}>\n      {!disable ? (\n        <Nav aria-labelledby={headingId}>\n          <Title headingId={headingId} title={title} />\n          <div className=\"toc-wrapper\" />\n        </Nav>\n      ) : null}\n    </Aside>\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/Title.stories.ts",
    "content": "import { Title } from './Title';\n\nexport default { component: Title };\n\nexport const Basic = {\n  args: {\n    children: 'Basic title',\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/Title.tsx",
    "content": "import { withReset } from 'storybook/internal/components';\n\nimport type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\nconst breakpoint = 600;\n\nexport const Title = styled.h1(({ theme }) => ({\n  ...(withReset({ theme }) as CSSObject),\n  color: theme.color.defaultText,\n  fontSize: theme.typography.size.m3,\n  fontWeight: theme.typography.weight.bold,\n  lineHeight: '32px',\n\n  [`@media (min-width: ${breakpoint}px)`]: {\n    fontSize: theme.typography.size.l1,\n    lineHeight: '36px',\n    marginBottom: '16px',\n  },\n}));\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/Toolbar.tsx",
    "content": "import type { FC, SyntheticEvent } from 'react';\nimport React from 'react';\n\nimport { Button, Toolbar as SharedToolbar } from 'storybook/internal/components';\n\nimport { ShareAltIcon, SyncIcon, ZoomIcon, ZoomOutIcon, ZoomResetIcon } from '@storybook/icons';\n\nimport { styled } from 'storybook/theming';\n\nimport { getStoryHref } from '../getStoryHref';\n\ninterface ZoomProps {\n  zoom: (val: number) => void;\n  resetZoom: () => void;\n}\n\ninterface EjectProps {\n  storyId?: string;\n}\n\ninterface ReloadProps {\n  onReloadStory?: () => void;\n}\n\ninterface BarProps {\n  border?: boolean;\n}\n\ninterface LoadingProps {\n  isLoading?: boolean;\n}\n\nexport type ToolbarProps = BarProps & ZoomProps & EjectProps & LoadingProps & ReloadProps;\n\nconst AbsoluteBar = styled(SharedToolbar)({\n  position: 'absolute',\n  left: 0,\n  right: 0,\n  top: 0,\n  transition: 'transform .2s linear',\n  display: 'flex',\n  alignItems: 'center',\n});\n\nconst Wrapper = styled.div({\n  display: 'flex',\n  alignItems: 'center',\n  gap: 4,\n});\n\nconst IconPlaceholder = styled.div(({ theme }) => ({\n  width: 14,\n  height: 14,\n  borderRadius: 2,\n  margin: '0 7px',\n  backgroundColor: theme.appBorderColor,\n  animation: `${theme.animation.glow} 1.5s ease-in-out infinite`,\n}));\n\nexport const Toolbar: FC<ToolbarProps> = ({\n  isLoading,\n  storyId,\n  zoom,\n  resetZoom,\n  onReloadStory,\n  ...rest\n}) => (\n  <AbsoluteBar innerStyle={{ gap: 4, paddingInline: 7, justifyContent: 'space-between' }} {...rest}>\n    <Wrapper key=\"left\">\n      {isLoading ? (\n        [1, 2, 3].map((key) => <IconPlaceholder key={key} />)\n      ) : (\n        <>\n          {onReloadStory && (\n            <Button\n              padding=\"small\"\n              variant=\"ghost\"\n              key=\"reload\"\n              onClick={onReloadStory}\n              ariaLabel=\"Reload story\"\n            >\n              <SyncIcon />\n            </Button>\n          )}\n          <Button\n            padding=\"small\"\n            variant=\"ghost\"\n            key=\"zoomin\"\n            onClick={(e: SyntheticEvent) => {\n              e.preventDefault();\n              zoom(0.8);\n            }}\n            ariaLabel=\"Zoom in\"\n          >\n            <ZoomIcon />\n          </Button>\n          <Button\n            padding=\"small\"\n            variant=\"ghost\"\n            key=\"zoomout\"\n            onClick={(e: SyntheticEvent) => {\n              e.preventDefault();\n              zoom(1.25);\n            }}\n            ariaLabel=\"Zoom out\"\n          >\n            <ZoomOutIcon />\n          </Button>\n          <Button\n            padding=\"small\"\n            variant=\"ghost\"\n            key=\"zoomreset\"\n            onClick={(e: SyntheticEvent) => {\n              e.preventDefault();\n              resetZoom();\n            }}\n            ariaLabel=\"Reset zoom\"\n          >\n            <ZoomResetIcon />\n          </Button>\n        </>\n      )}\n    </Wrapper>\n\n    {isLoading ? (\n      <Wrapper key=\"right\">\n        <IconPlaceholder />\n      </Wrapper>\n    ) : (\n      storyId && (\n        <Wrapper key=\"right\">\n          <Button\n            asChild\n            padding=\"small\"\n            variant=\"ghost\"\n            key=\"opener\"\n            ariaLabel=\"Open canvas in new tab\"\n          >\n            <a href={getStoryHref(storyId)} target=\"_blank\" rel=\"noopener noreferrer\">\n              <ShareAltIcon />\n            </a>\n          </Button>\n        </Wrapper>\n      )\n    )}\n  </AbsoluteBar>\n);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/Typeset.stories.tsx",
    "content": "import React from 'react';\n\nimport { Typeset } from './Typeset';\n\nexport default {\n  component: Typeset,\n};\n\nconst fontSizes = ['12px', '14px', '16px', '20px', '24px', '32px', '40px', '48px'];\nconst fontWeight = 700;\nconst fontFamily = 'monospace';\n\nexport const WithFontSizes = () => <Typeset fontSizes={fontSizes} />;\n\nexport const WithFontWeight = () => <Typeset fontSizes={fontSizes} fontWeight={fontWeight} />;\n\nexport const WithFontFamily = () => <Typeset fontSizes={fontSizes} fontFamily={fontFamily} />;\n\nexport const WithWeightText = () => (\n  <Typeset fontSizes={fontSizes} fontWeight={fontWeight} sampleText=\"Heading\" />\n);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/Typeset.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { withReset } from 'storybook/internal/components';\n\nimport { transparentize } from 'polished';\nimport { styled } from 'storybook/theming';\n\nimport { getBlockBackgroundStyle } from './BlockBackgroundStyles';\n\nconst Label = styled.div(({ theme }) => ({\n  marginRight: 30,\n  fontSize: `${theme.typography.size.s1}px`,\n  color:\n    theme.base === 'light'\n      ? transparentize(0.4, theme.color.defaultText)\n      : transparentize(0.6, theme.color.defaultText),\n}));\n\nconst Sample = styled.div({\n  overflow: 'hidden',\n  whiteSpace: 'nowrap',\n  textOverflow: 'ellipsis',\n});\n\nconst TypeSpecimen = styled.div({\n  display: 'flex',\n  flexDirection: 'row',\n  alignItems: 'baseline',\n  '&:not(:last-child)': { marginBottom: '1rem' },\n});\n\nconst Wrapper = styled.div(withReset, ({ theme }) => ({\n  ...getBlockBackgroundStyle(theme),\n  margin: '25px 0 40px',\n  padding: '30px 20px',\n}));\n\nexport interface TypesetProps {\n  fontFamily?: string;\n  fontSizes: (string | number)[];\n  fontWeight?: number;\n  sampleText?: string;\n}\n\n/**\n * Convenient styleguide documentation showing examples of type with different sizes and weights and\n * configurable sample text.\n */\nexport const Typeset: FC<TypesetProps> = ({\n  fontFamily,\n  fontSizes,\n  fontWeight,\n  sampleText,\n  ...props\n}) => (\n  <Wrapper {...props} className=\"docblock-typeset sb-unstyled\">\n    {fontSizes.map((size) => (\n      <TypeSpecimen key={size}>\n        <Label>{size}</Label>\n        <Sample\n          style={{\n            fontFamily,\n            fontSize: size,\n            fontWeight,\n            lineHeight: 1.2,\n          }}\n        >\n          {sampleText || 'Was he a beast if music could move him so?'}\n        </Sample>\n      </TypeSpecimen>\n    ))}\n  </Wrapper>\n);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/ZoomContext.tsx",
    "content": "import type { Context } from 'react';\nimport { createContext } from 'react';\n\nexport const ZoomContext: Context<{ scale: number }> = createContext({\n  scale: 1,\n});\n"
  },
  {
    "path": "code/addons/docs/src/blocks/components/index.ts",
    "content": "export * from './Source';\nexport * from './EmptyBlock';\nexport * from './DocsPage';\n\nexport * from './Preview';\n\nexport * from './ArgsTable';\nexport * from './Story';\nexport * from './IFrame';\nexport * from './Typeset';\nexport * from './ColorPalette';\nexport * from './IconGallery';\nexport * from './TableOfContents';\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/Boolean.stories.tsx",
    "content": "import { RESET_STORY_ARGS, STORY_ARGS_UPDATED } from 'storybook/internal/core-events';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { addons } from 'storybook/preview-api';\nimport { expect, fireEvent, fn, waitFor, within } from 'storybook/test';\n\nimport { BooleanControl } from './Boolean';\n\nconst meta = {\n  component: BooleanControl,\n  tags: ['autodocs'],\n  parameters: {\n    withRawArg: 'value',\n    controls: { include: ['value'] },\n    notes: 'These are notes for the Boolean control stories',\n    info: 'This is info for the Boolean control stories',\n    jsx: { useBooleanShorthandSyntax: false },\n  },\n  args: {\n    onChange: fn(),\n  },\n} satisfies Meta<typeof BooleanControl>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const True: Story = {\n  args: {\n    value: true,\n    name: 'True',\n  },\n};\nexport const False: Story = {\n  args: {\n    value: false,\n    name: 'False',\n  },\n};\n\nexport const Undefined: Story = {\n  args: {\n    value: undefined,\n    name: 'Undefined',\n  },\n};\n\nexport const Toggling: Story = {\n  args: {\n    value: undefined,\n    name: 'Toggling',\n  },\n  play: async ({ canvasElement, id, args, step }) => {\n    const channel = addons.getChannel();\n\n    channel.emit(RESET_STORY_ARGS, { storyId: id });\n    await new Promise<void>((resolve) => {\n      channel.once(STORY_ARGS_UPDATED, resolve);\n    });\n\n    const canvas = within(canvasElement);\n    await step('Change from Undefined to False', async () => {\n      const setBooleanControl = canvas.getByText('Set boolean');\n      await fireEvent.click(setBooleanControl);\n\n      const toggle = await canvas.findByLabelText(args.name);\n      await expect(toggle).toBeVisible();\n    });\n\n    await step('Change from False to True', async () => {\n      const toggle = canvas.getByRole('switch');\n      await fireEvent.click(toggle);\n      await waitFor(async () => {\n        await expect(toggle).toBeChecked();\n      });\n    });\n\n    await step('Change from True to False', async () => {\n      const toggle = canvas.getByRole('switch');\n      await fireEvent.click(toggle);\n      await waitFor(async () => {\n        await expect(toggle).not.toBeChecked();\n      });\n    });\n  },\n  tags: ['!vitest'],\n};\n\nexport const TogglingInDocs: Story = {\n  ...Toggling,\n  args: {\n    name: 'Toggling In Docs',\n  },\n  parameters: {\n    docs: {\n      autoplay: true,\n    },\n  },\n  tags: ['!vitest'],\n};\n\nexport const Readonly: Story = {\n  args: {\n    name: 'readonly',\n    value: true,\n    argType: { table: { readonly: true } },\n  },\n};\n\nexport const ReadonlyAndUndefined: Story = {\n  args: {\n    name: 'readonly-and-undefined',\n    value: undefined,\n    argType: { table: { readonly: true } },\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/Boolean.tsx",
    "content": "import type { FC } from 'react';\nimport React, { useCallback } from 'react';\n\nimport { Button } from 'storybook/internal/components';\n\nimport { opacify, transparentize } from 'polished';\nimport { styled } from 'storybook/theming';\n\nimport { getControlId, getControlSetterButtonId } from './helpers';\nimport type { BooleanConfig, BooleanValue, ControlProps } from './types';\n\nconst Label = styled.label(({ theme }) => ({\n  lineHeight: '18px',\n  alignItems: 'center',\n  marginBottom: 8,\n  display: 'inline-block',\n  position: 'relative',\n  whiteSpace: 'nowrap',\n  background: theme.boolean.background,\n  borderRadius: '3em',\n  padding: 1,\n  '&[aria-disabled=\"true\"]': {\n    opacity: 0.5,\n\n    input: {\n      cursor: 'not-allowed',\n    },\n  },\n\n  input: {\n    appearance: 'none',\n    width: '100%',\n    height: '100%',\n    position: 'absolute',\n    left: 0,\n    top: 0,\n    margin: 0,\n    padding: 0,\n    border: 'none',\n    background: 'transparent',\n    cursor: 'pointer',\n    borderRadius: '3em',\n\n    '&:focus': {\n      outline: 'none',\n      boxShadow: `${theme.color.secondary} 0 0 0 1px inset !important`,\n    },\n    '@media (forced-colors: active)': {\n      '&:focus': {\n        outline: '1px solid highlight',\n      },\n    },\n  },\n\n  span: {\n    textAlign: 'center',\n    fontSize: theme.typography.size.s1,\n    fontWeight: theme.typography.weight.bold,\n    lineHeight: '1',\n    cursor: 'pointer',\n    display: 'inline-block',\n    padding: '7px 15px',\n    transition: 'all 100ms ease-out',\n    userSelect: 'none',\n    borderRadius: '3em',\n\n    color: transparentize(0.5, theme.color.defaultText),\n    background: 'transparent',\n\n    '&:hover': {\n      boxShadow: `${opacify(0.3, theme.appBorderColor)} 0 0 0 1px inset`,\n    },\n\n    '&:active': {\n      boxShadow: `${opacify(0.05, theme.appBorderColor)} 0 0 0 2px inset`,\n      color: opacify(1, theme.appBorderColor),\n    },\n\n    '&:first-of-type': {\n      paddingRight: 8,\n    },\n    '&:last-of-type': {\n      paddingLeft: 8,\n    },\n  },\n\n  'input:checked ~ span:last-of-type, input:not(:checked) ~ span:first-of-type': {\n    background: theme.boolean.selectedBackground,\n    boxShadow:\n      theme.base === 'light'\n        ? `${opacify(0.1, theme.appBorderColor)} 0 0 2px`\n        : `${theme.appBorderColor} 0 0 0 1px`,\n    color: theme.color.defaultText,\n    padding: '7px 15px',\n\n    '@media (forced-colors: active)': {\n      textDecoration: 'underline',\n    },\n  },\n}));\n\nconst parse = (value: string | null): boolean => value === 'true';\n\nexport type BooleanProps = ControlProps<BooleanValue> & BooleanConfig;\n/**\n * # Boolean Control\n *\n * Renders a switch toggle with \"True\" or \"False\". or if the value is `undefined`, renders a button\n * to set the boolean.\n *\n * ## Example usage\n *\n * ```\n * <BooleanControl name=\"isTrue\" value={value} onChange={handleValueChange} />;\n * ```\n */\nexport const BooleanControl: FC<BooleanProps> = ({\n  name,\n  storyId,\n  value,\n  onChange,\n  onBlur,\n  onFocus,\n  argType,\n}) => {\n  const onSetFalse = useCallback(() => onChange(false), [onChange]);\n  const readonly = !!argType?.table?.readonly;\n  if (value === undefined) {\n    return (\n      <Button\n        ariaLabel={false}\n        variant=\"outline\"\n        size=\"medium\"\n        id={getControlSetterButtonId(name, storyId)}\n        onClick={onSetFalse}\n        disabled={readonly}\n      >\n        Set boolean\n      </Button>\n    );\n  }\n  const controlId = getControlId(name, storyId);\n\n  const parsedValue = typeof value === 'string' ? parse(value) : value;\n\n  return (\n    <Label aria-disabled={readonly} htmlFor={controlId} aria-label={name}>\n      <input\n        id={controlId}\n        type=\"checkbox\"\n        onChange={(e) => onChange(e.target.checked)}\n        checked={parsedValue}\n        role=\"switch\"\n        disabled={readonly}\n        {...{ name, onBlur, onFocus }}\n      />\n      <span aria-hidden=\"true\">False</span>\n      <span aria-hidden=\"true\">True</span>\n    </Label>\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/Color.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { fn } from 'storybook/test';\n\nimport { ColorControl } from './Color';\n\nconst meta = {\n  component: ColorControl,\n  parameters: {\n    withRawArg: 'value',\n    controls: { include: ['value', 'startOpen'] },\n  },\n  tags: ['autodocs'],\n  argTypes: {\n    value: {\n      control: {\n        type: 'color',\n      },\n    },\n  },\n  args: { name: 'color', onChange: fn() },\n} satisfies Meta<typeof ColorControl>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  args: {\n    value: '#ff00ff',\n  },\n};\n\nexport const Undefined: Story = {\n  args: {\n    value: undefined,\n  },\n};\n\nexport const WithPresetColors: Story = {\n  args: {\n    value: '#00ffff',\n    presetColors: [\n      { color: '#ff4785', title: 'Coral' },\n      { color: '#1EA7FD', title: 'Ocean' },\n      { color: 'rgb(252, 82, 31)', title: 'Orange' },\n      { color: 'rgba(255, 174, 0, 0.5)', title: 'Gold' },\n      { color: 'hsl(101, 52%, 49%)', title: 'Green' },\n      { color: 'hsla(179,65%,53%,0.5)', title: 'Seafoam' },\n      { color: '#6F2CAC', title: 'Purple' },\n      { color: '#2A0481', title: 'Ultraviolet' },\n      { color: 'black' },\n      { color: '#333', title: 'Darkest' },\n      { color: '#444', title: 'Darker' },\n      { color: '#666', title: 'Dark' },\n      { color: '#999', title: 'Mediumdark' },\n      { color: '#ddd', title: 'Medium' },\n      { color: '#EEE', title: 'Mediumlight' },\n      { color: '#F3F3F3', title: 'Light' },\n      { color: '#F8F8F8', title: 'Lighter' },\n      { color: '#FFFFFF', title: 'Lightest' },\n      '#fe4a49',\n      '#FED766',\n      'rgba(0, 159, 183, 1)',\n      'hsla(240,11%,91%,0.5)',\n      'slategray',\n    ],\n  },\n};\n\nexport const WithMaxPresetColors: Story = {\n  name: 'With maxPresetColors (limit to 5)',\n  args: {\n    value: '#00ffff',\n    startOpen: true,\n    maxPresetColors: 5,\n    presetColors: [\n      { color: '#ff4785', title: 'Coral' },\n      { color: '#1EA7FD', title: 'Ocean' },\n      { color: 'rgb(252, 82, 31)', title: 'Orange' },\n      { color: 'rgba(255, 174, 0, 0.5)', title: 'Gold' },\n      { color: 'hsl(101, 52%, 49%)', title: 'Green' },\n      { color: 'hsla(179,65%,53%,0.5)', title: 'Seafoam' },\n      { color: '#6F2CAC', title: 'Purple' },\n      { color: '#2A0481', title: 'Ultraviolet' },\n    ],\n  },\n};\n\nexport const WithUnlimitedPresetColors: Story = {\n  name: 'With unlimited presets (maxPresetColors: 0)',\n  args: {\n    value: '#00ffff',\n    startOpen: true,\n    maxPresetColors: 0,\n    presetColors: Array.from({ length: 40 }, (_, i) => {\n      const hue = Math.round((i / 40) * 360);\n      return { color: `hsl(${hue}, 70%, 50%)`, title: `Color ${i + 1}` };\n    }),\n  },\n};\n\nexport const WithInvalidMaxPresetColors: Story = {\n  name: 'With invalid maxPresetColors (negative, falls back to 27)',\n  args: {\n    value: '#00ffff',\n    startOpen: true,\n    maxPresetColors: -5,\n    presetColors: Array.from({ length: 40 }, (_, i) => {\n      const hue = Math.round((i / 40) * 360);\n      return { color: `hsl(${hue}, 70%, 50%)`, title: `Color ${i + 1}` };\n    }),\n  },\n};\n\nexport const StartOpen: Story = {\n  args: {\n    startOpen: true,\n  },\n};\n\nexport const Readonly: Story = {\n  args: {\n    value: '#ff00ff',\n    argType: { table: { readonly: true } },\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/Color.tsx",
    "content": "import type { ChangeEvent, FC, FocusEvent } from 'react';\nimport React, { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { Button, Form, PopoverProvider } from 'storybook/internal/components';\n\nimport { MarkupIcon } from '@storybook/icons';\n\nimport convert from 'color-convert';\nimport { debounce } from 'es-toolkit/function';\nimport { HexColorPicker, HslaStringColorPicker, RgbaStringColorPicker } from 'react-colorful';\nimport { styled } from 'storybook/theming';\n\nimport { getControlId } from './helpers';\nimport type { ColorConfig, ColorValue, ControlProps, PresetColor } from './types';\n\nconst Wrapper = styled.div({\n  position: 'relative',\n  maxWidth: 250,\n});\n\nconst TooltipContent = styled.div({\n  width: 200,\n  margin: 5,\n\n  '.react-colorful__saturation': {\n    borderRadius: '4px 4px 0 0',\n  },\n  '.react-colorful__hue': {\n    boxShadow: 'inset 0 0 0 1px rgb(0 0 0 / 5%)',\n  },\n  '.react-colorful__last-control': {\n    borderRadius: '0 0 4px 4px',\n  },\n});\n\nconst Swatches = styled.div({\n  display: 'grid',\n  gridTemplateColumns: 'repeat(9, 16px)',\n  gap: 6,\n  padding: 3,\n  marginTop: 5,\n  width: 200,\n});\n\nconst swatchBackground = (isDark: boolean) =>\n  `url('data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill-opacity=\"0.05\" fill=\"${isDark ? 'white' : 'black'}\"><path d=\"M8 0h8v8H8zM0 8h8v8H0z\"/></svg>')`;\n\nconst SwatchColor = styled(Button)<{ selected?: boolean; value: string }>(\n  ({ value, selected, theme }) => ({\n    width: 16,\n    height: 16,\n    boxShadow: selected\n      ? `${theme.appBorderColor} 0 0 0 1px inset, ${theme.textMutedColor}50 0 0 0 4px`\n      : `${theme.appBorderColor} 0 0 0 1px inset`,\n    border: 'none',\n    borderRadius: theme.appBorderRadius,\n    '&, &:hover': {\n      background: 'unset',\n      backgroundColor: 'unset',\n      backgroundImage: `linear-gradient(${value}, ${value}), ${swatchBackground(theme.base === 'dark')}`,\n    },\n  })\n);\n\nconst Input = styled(Form.Input)(({ theme }) => ({\n  width: '100%',\n  paddingLeft: 30,\n  paddingRight: 30,\n  boxSizing: 'border-box',\n  fontFamily: theme.typography.fonts.base,\n\n  '[aria-readonly=\"true\"] > &': {\n    background: theme.base === 'light' ? theme.color.lighter : 'transparent',\n  },\n}));\n\nconst PopoverTrigger = styled(SwatchColor)<{ disabled: boolean }>(({ disabled }) => ({\n  position: 'absolute',\n  top: 4,\n  left: 4,\n  zIndex: 1,\n  cursor: disabled ? 'not-allowed' : 'pointer',\n}));\n\nconst CycleColorSpaceButton = styled(Button)(({ theme }) => ({\n  position: 'absolute',\n  zIndex: 1,\n  top: 6,\n  right: 7,\n  width: 20,\n  height: 20,\n  padding: 4,\n  boxSizing: 'border-box',\n  cursor: 'pointer',\n  color: theme.input.color,\n}));\n\nenum ColorSpace {\n  RGB = 'rgb',\n  HSL = 'hsl',\n  HEX = 'hex',\n}\n\nconst COLOR_SPACES = Object.values(ColorSpace);\nconst COLOR_REGEXP = /\\(([0-9]+),\\s*([0-9]+)%?,\\s*([0-9]+)%?,?\\s*([0-9.]+)?\\)/;\nconst RGB_REGEXP = /^\\s*rgba?\\(([0-9]+),\\s*([0-9]+),\\s*([0-9]+),?\\s*([0-9.]+)?\\)\\s*$/i;\nconst HSL_REGEXP = /^\\s*hsla?\\(([0-9]+),\\s*([0-9]+)%,\\s*([0-9]+)%,?\\s*([0-9.]+)?\\)\\s*$/i;\nconst HEX_REGEXP = /^\\s*#?([0-9a-f]{3}|[0-9a-f]{6})\\s*$/i;\nconst SHORTHEX_REGEXP = /^\\s*#?([0-9a-f]{3})\\s*$/i;\n\ntype ParsedColor = {\n  valid: boolean;\n  value: string;\n  keyword: string;\n  colorSpace: ColorSpace;\n  [ColorSpace.RGB]: string;\n  [ColorSpace.HSL]: string;\n  [ColorSpace.HEX]: string;\n};\n\nconst ColorPicker = {\n  [ColorSpace.HEX]: HexColorPicker,\n  [ColorSpace.RGB]: RgbaStringColorPicker,\n  [ColorSpace.HSL]: HslaStringColorPicker,\n};\n\nconst fallbackColor = {\n  [ColorSpace.HEX]: 'transparent',\n  [ColorSpace.RGB]: 'rgba(0, 0, 0, 0)',\n  [ColorSpace.HSL]: 'hsla(0, 0%, 0%, 0)',\n};\n\nconst stringToArgs = (value: string) => {\n  const match = value?.match(COLOR_REGEXP);\n\n  if (!match) {\n    return [0, 0, 0, 1];\n  }\n  const [, x, y, z, a = 1] = match;\n  return [x, y, z, a].map(Number);\n};\n\nconst parseRgb = (value: string): ParsedColor => {\n  const [r, g, b, a] = stringToArgs(value);\n  const [h, s, l] = convert.rgb.hsl([r, g, b]) || [0, 0, 0];\n\n  return {\n    valid: true,\n    value,\n    keyword: convert.rgb.keyword([r, g, b]),\n    colorSpace: ColorSpace.RGB,\n    [ColorSpace.RGB]: value,\n    [ColorSpace.HSL]: `hsla(${h}, ${s}%, ${l}%, ${a})`,\n    [ColorSpace.HEX]: `#${convert.rgb.hex([r, g, b]).toLowerCase()}`,\n  };\n};\n\nconst parseHsl = (value: string): ParsedColor => {\n  const [h, s, l, a] = stringToArgs(value);\n  const [r, g, b] = convert.hsl.rgb([h, s, l]) || [0, 0, 0];\n\n  return {\n    valid: true,\n    value,\n    keyword: convert.hsl.keyword([h, s, l]),\n    colorSpace: ColorSpace.HSL,\n    [ColorSpace.RGB]: `rgba(${r}, ${g}, ${b}, ${a})`,\n    [ColorSpace.HSL]: value,\n    [ColorSpace.HEX]: `#${convert.hsl.hex([h, s, l]).toLowerCase()}`,\n  };\n};\n\nconst parseHexOrKeyword = (value: string): ParsedColor => {\n  const plain = value.replace('#', '');\n  // Try interpreting as keyword or hex\n  const rgb = convert.keyword.rgb(plain as any) || convert.hex.rgb(plain);\n  const hsl = convert.rgb.hsl(rgb);\n\n  let mapped = value;\n  if (/[^#a-f0-9]/i.test(value)) {\n    // Possibly a keyword\n    mapped = plain;\n  } else if (HEX_REGEXP.test(value)) {\n    mapped = `#${plain}`;\n  }\n\n  let valid = true;\n  if (mapped.startsWith('#')) {\n    valid = HEX_REGEXP.test(mapped);\n  } else {\n    try {\n      convert.keyword.hex(mapped as any);\n    } catch (e) {\n      valid = false;\n    }\n  }\n\n  return {\n    valid,\n    value: mapped,\n    keyword: convert.rgb.keyword(rgb),\n    colorSpace: ColorSpace.HEX,\n    [ColorSpace.RGB]: `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, 1)`,\n    [ColorSpace.HSL]: `hsla(${hsl[0]}, ${hsl[1]}%, ${hsl[2]}%, 1)`,\n    [ColorSpace.HEX]: mapped,\n  };\n};\n\nconst parseValue = (value: string): ParsedColor | undefined => {\n  if (!value) {\n    return undefined;\n  }\n  if (RGB_REGEXP.test(value)) {\n    return parseRgb(value);\n  }\n  if (HSL_REGEXP.test(value)) {\n    return parseHsl(value);\n  }\n  return parseHexOrKeyword(value);\n};\n\nconst getRealValue = (value: string, color: ParsedColor | undefined, colorSpace: ColorSpace) => {\n  if (!value || !color?.valid) {\n    return fallbackColor[colorSpace];\n  }\n\n  if (colorSpace !== ColorSpace.HEX) {\n    return color?.[colorSpace] || fallbackColor[colorSpace];\n  }\n  if (!color.hex.startsWith('#')) {\n    try {\n      return `#${convert.keyword.hex(color.hex as any)}`;\n    } catch (e) {\n      return fallbackColor.hex;\n    }\n  }\n  const short = color.hex.match(SHORTHEX_REGEXP);\n\n  if (!short) {\n    return HEX_REGEXP.test(color.hex) ? color.hex : fallbackColor.hex;\n  }\n  const [r, g, b] = short[1].split('');\n  return `#${r}${r}${g}${g}${b}${b}`;\n};\n\nconst useColorInput = (\n  initialValue: string | undefined,\n  onChange: (value: string | undefined) => string | void\n) => {\n  const [value, setValue] = useState(initialValue || '');\n  const [color, setColor] = useState(() => parseValue(value));\n  const [colorSpace, setColorSpace] = useState(color?.colorSpace || ColorSpace.HEX);\n\n  // Reset state when initialValue changes (when resetting controls)\n  useEffect(() => {\n    const nextValue = initialValue || '';\n    const nextColor = parseValue(nextValue);\n    setValue(nextValue);\n    setColor(nextColor);\n    setColorSpace(nextColor?.colorSpace || ColorSpace.HEX);\n  }, [initialValue]);\n\n  const realValue = useMemo(\n    () => getRealValue(value, color, colorSpace).toLowerCase(),\n    [value, color, colorSpace]\n  );\n\n  const updateValue = useCallback(\n    (update: string) => {\n      const parsed = parseValue(update);\n      const v = parsed?.value || update || '';\n\n      setValue(v);\n\n      if (v === '') {\n        setColor(undefined);\n        onChange(undefined);\n      }\n\n      if (!parsed) {\n        return;\n      }\n\n      setColor(parsed);\n      setColorSpace(parsed.colorSpace);\n      onChange(parsed.value);\n    },\n    [onChange]\n  );\n\n  const cycleColorSpace = useCallback(() => {\n    const currentIndex = COLOR_SPACES.indexOf(colorSpace);\n    const nextIndex = (currentIndex + 1) % COLOR_SPACES.length;\n    const nextSpace = COLOR_SPACES[nextIndex];\n\n    setColorSpace(nextSpace);\n    const updatedValue = color?.[nextSpace] || '';\n    setValue(updatedValue);\n    onChange(updatedValue);\n  }, [color, colorSpace, onChange]);\n\n  return { value, realValue, updateValue, color, colorSpace, cycleColorSpace };\n};\n\nconst id = (value: string) => value.replace(/\\s*/, '').toLowerCase();\n\nconst usePresets = (\n  presetColors: PresetColor[],\n  currentColor: ParsedColor | undefined,\n  colorSpace: ColorSpace,\n  maxPresetColors = 27\n) => {\n  const [selectedColors, setSelectedColors] = useState(currentColor?.valid ? [currentColor] : []);\n\n  // Reset state when currentColor becomes undefined (when resetting controls)\n  useEffect(() => {\n    if (currentColor !== undefined) {\n      return;\n    }\n    setSelectedColors([]);\n  }, [currentColor]);\n\n  const presets = useMemo(() => {\n    const initialPresets = (presetColors || []).map((preset) => {\n      if (typeof preset === 'string') {\n        return parseValue(preset);\n      }\n\n      if (preset.title) {\n        return { ...parseValue(preset.color), keyword: preset.title };\n      }\n      return parseValue(preset.color);\n    });\n    const combined = initialPresets.concat(selectedColors).filter(Boolean);\n    if (maxPresetColors === 0 || maxPresetColors === Infinity) {\n      return combined;\n    }\n    const limit = Number.isInteger(maxPresetColors) && maxPresetColors > 0 ? maxPresetColors : 27;\n    return combined.slice(-limit);\n  }, [presetColors, selectedColors, maxPresetColors]);\n\n  const addPreset: (color: ParsedColor) => void = useCallback(\n    (color) => {\n      if (!color?.valid) {\n        return;\n      }\n\n      if (\n        presets.some(\n          (preset) =>\n            preset &&\n            preset[colorSpace] &&\n            id(preset[colorSpace] || '') === id(color[colorSpace] || '')\n        )\n      ) {\n        return;\n      }\n      setSelectedColors((arr) => arr.concat(color));\n    },\n    [colorSpace, presets]\n  );\n\n  return { presets, addPreset };\n};\n\nexport type ColorControlProps = ControlProps<ColorValue> & ColorConfig;\nexport const ColorControl: FC<ColorControlProps> = ({\n  name,\n  storyId,\n  value: initialValue,\n  onChange,\n  onFocus,\n  onBlur,\n  presetColors,\n  maxPresetColors,\n  startOpen = false,\n  argType,\n}) => {\n  const debouncedOnChange = useCallback(debounce(onChange, 200), [onChange]);\n  const { value, realValue, updateValue, color, colorSpace, cycleColorSpace } = useColorInput(\n    initialValue,\n    debouncedOnChange\n  );\n  const { presets, addPreset } = usePresets(presetColors ?? [], color, colorSpace, maxPresetColors);\n  const Picker = ColorPicker[colorSpace];\n\n  const readOnly = !!argType?.table?.readonly;\n  const controlId = getControlId(name, storyId);\n\n  return (\n    <Wrapper>\n      <label htmlFor={controlId} className=\"sb-sr-only\">\n        {name}\n      </label>\n      <Input\n        id={controlId}\n        value={value}\n        onChange={(e: ChangeEvent<HTMLInputElement>) => updateValue(e.target.value)}\n        onFocus={(e: FocusEvent<HTMLInputElement>) => e.target.select()}\n        readOnly={readOnly}\n        placeholder=\"Choose color...\"\n      />\n      <PopoverProvider\n        ariaLabel=\"Color picker\"\n        defaultVisible={startOpen}\n        visible={readOnly ? false : undefined}\n        onVisibleChange={() => color && addPreset(color)}\n        popover={\n          <TooltipContent>\n            <Picker\n              color={realValue === 'transparent' ? '#000000' : realValue}\n              {...{ onChange: updateValue, onFocus, onBlur }}\n            />\n            {presets.length > 0 && (\n              <Swatches>\n                {presets.map((preset, index: number) => (\n                  <SwatchColor\n                    key={`${preset?.value || index}-${index}`}\n                    variant=\"ghost\"\n                    padding=\"small\"\n                    size=\"small\"\n                    ariaLabel=\"Pick this color\"\n                    tooltip={preset?.keyword || preset?.value || ''}\n                    value={preset?.value || ''}\n                    selected={\n                      !!(\n                        color &&\n                        preset &&\n                        preset[colorSpace] &&\n                        id(preset[colorSpace] || '') === id(color[colorSpace])\n                      )\n                    }\n                    onClick={() => preset && updateValue(preset.value || '')}\n                  />\n                ))}\n              </Swatches>\n            )}\n          </TooltipContent>\n        }\n      >\n        <PopoverTrigger\n          variant=\"ghost\"\n          padding=\"small\"\n          size=\"small\"\n          ariaLabel=\"Open color picker\"\n          value={realValue}\n          style={{ margin: 4 }}\n          disabled={readOnly}\n        />\n      </PopoverProvider>\n      {value ? (\n        <CycleColorSpaceButton\n          variant=\"ghost\"\n          padding=\"small\"\n          size=\"small\"\n          ariaLabel=\"Cycle through color spaces\"\n          disabled={readOnly}\n          onClick={readOnly ? undefined : cycleColorSpace}\n        >\n          <MarkupIcon />\n        </CycleColorSpaceButton>\n      ) : null}\n    </Wrapper>\n  );\n};\n\nexport default ColorControl;\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/Date.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { fn } from 'storybook/test';\n\nimport { DateControl } from './Date';\n\nconst meta = {\n  component: DateControl,\n  tags: ['autodocs'],\n  parameters: { withRawArg: 'value', controls: { include: ['value'] } },\n  argTypes: {\n    value: {\n      description: 'The date',\n      control: { type: 'date' },\n    },\n  },\n  args: { name: 'date', onChange: fn() },\n} satisfies Meta<typeof DateControl>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  args: { value: new Date('2020-10-20T09:30:02') },\n};\n\nexport const Undefined: Story = {\n  args: { value: undefined },\n};\n\nexport const Readonly: Story = {\n  args: {\n    value: new Date('2020-10-20T09:30:02'),\n    argType: { table: { readonly: true } },\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/Date.test.ts",
    "content": "// @vitest-environment happy-dom\nimport { describe, expect, it } from 'vitest';\n\nimport { formatDate, formatTime, parseDate, parseTime } from './Date';\n\ndescribe('Date control', () => {\n  it.each([\n    // name, input, expected\n    ['same date', '2022-01-01', '2022-01-01'],\n    ['month and day not padded with zeros', '2022-1-1', '2022-01-01'],\n    ['different year', '1900-10-1', '1900-10-01'],\n  ])('parse and format date: %s', (name, input, expected) => {\n    expect(formatDate(parseDate(input))).toBe(expected);\n  });\n\n  it.each([\n    // name, input, expected\n    ['same time', '12:00', '12:00'],\n    ['hours not padded with a zero', '1:00', '01:00'],\n    ['minutes not padded with a zero', '01:0', '01:00'],\n    ['different minutes', '01:30', '01:30'],\n  ])('parse and format time: %s', (name, input, expected) => {\n    expect(formatTime(parseTime(input))).toBe(expected);\n  });\n});\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/Date.tsx",
    "content": "import type { ChangeEvent, FC, RefObject } from 'react';\nimport React, { useEffect, useRef, useState } from 'react';\n\nimport { Form } from 'storybook/internal/components';\n\nimport { styled } from 'storybook/theming';\n\nimport { getControlId } from './helpers';\nimport type { ControlProps, DateConfig, DateValue } from './types';\n\nexport const parseDate = (value: string) => {\n  const [year, month, day] = value.split('-');\n  const result = new Date();\n  result.setFullYear(parseInt(year, 10), parseInt(month, 10) - 1, parseInt(day, 10));\n  return result;\n};\n\nexport const parseTime = (value: string) => {\n  const [hours, minutes] = value.split(':');\n  const result = new Date();\n  result.setHours(parseInt(hours, 10));\n  result.setMinutes(parseInt(minutes, 10));\n  return result;\n};\n\nexport const formatDate = (value: Date | number) => {\n  const date = new Date(value);\n  const year = `000${date.getFullYear()}`.slice(-4);\n  const month = `0${date.getMonth() + 1}`.slice(-2);\n  const day = `0${date.getDate()}`.slice(-2);\n  return `${year}-${month}-${day}`;\n};\n\nexport const formatTime = (value: Date | number) => {\n  const date = new Date(value);\n  const hours = `0${date.getHours()}`.slice(-2);\n  const minutes = `0${date.getMinutes()}`.slice(-2);\n  return `${hours}:${minutes}`;\n};\n\nconst FormInput = styled(Form.Input)(({ theme }) => ({\n  '&[readonly]': {\n    background: theme.base === 'light' ? theme.color.lighter : 'transparent',\n  },\n  '&::-webkit-calendar-picker-indicator': {\n    opacity: 0.5,\n    height: 12,\n    filter: theme.base === 'light' ? undefined : 'invert(1)',\n  },\n}));\n\nconst FlexSpaced = styled.fieldset({\n  flex: 1,\n  display: 'flex',\n  border: 0,\n  marginInline: 0,\n  padding: 0,\n  gap: 10,\n\n  'div:first-of-type': {\n    flex: 4,\n  },\n  'div:last-of-type': {\n    flex: 3,\n  },\n});\n\nexport type DateProps = ControlProps<DateValue> & DateConfig;\nexport const DateControl: FC<DateProps> = ({\n  name,\n  storyId,\n  value,\n  onChange,\n  onFocus,\n  onBlur,\n  argType,\n}) => {\n  const [valid, setValid] = useState(true);\n  const dateRef = useRef<HTMLInputElement>();\n  const timeRef = useRef<HTMLInputElement>();\n  const readonly = !!argType?.table?.readonly;\n\n  useEffect(() => {\n    if (valid !== false) {\n      if (dateRef && dateRef.current) {\n        dateRef.current.value = value ? formatDate(value) : '';\n      }\n      if (timeRef && timeRef.current) {\n        timeRef.current.value = value ? formatTime(value) : '';\n      }\n    }\n  }, [value]);\n\n  const onDateChange = (e: ChangeEvent<HTMLInputElement>) => {\n    if (!e.target.value) {\n      return onChange();\n    }\n    const parsed = parseDate(e.target.value);\n    const result = new Date(value ?? '');\n    result.setFullYear(parsed.getFullYear(), parsed.getMonth(), parsed.getDate());\n    const time = result.getTime();\n\n    if (time) {\n      onChange(time);\n    }\n    setValid(!!time);\n  };\n\n  const onTimeChange = (e: ChangeEvent<HTMLInputElement>) => {\n    if (!e.target.value) {\n      return onChange();\n    }\n    const parsed = parseTime(e.target.value);\n    const result = new Date(value ?? '');\n    result.setHours(parsed.getHours());\n    result.setMinutes(parsed.getMinutes());\n    const time = result.getTime();\n\n    if (time) {\n      onChange(time);\n    }\n    setValid(!!time);\n  };\n\n  const controlId = getControlId(name, storyId);\n\n  return (\n    <FlexSpaced>\n      <legend className=\"sb-sr-only\">{name}</legend>\n      <label htmlFor={`${controlId}-date`} className=\"sb-sr-only\">\n        Date\n      </label>\n      <FormInput\n        type=\"date\"\n        max=\"9999-12-31\" // I do this because of a rendering bug in chrome\n        ref={dateRef as RefObject<HTMLInputElement>}\n        id={`${controlId}-date`}\n        name={`${controlId}-date`}\n        readOnly={readonly}\n        onChange={onDateChange}\n        {...{ onFocus, onBlur }}\n      />\n      <label htmlFor={`${controlId}-time`} className=\"sb-sr-only\">\n        Time\n      </label>\n      <FormInput\n        type=\"time\"\n        id={`${controlId}-time`}\n        name={`${controlId}-time`}\n        ref={timeRef as RefObject<HTMLInputElement>}\n        onChange={onTimeChange}\n        readOnly={readonly}\n        {...{ onFocus, onBlur }}\n      />\n      {!valid ? <div>invalid</div> : null}\n    </FlexSpaced>\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/Files.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { fn } from 'storybook/test';\n\nimport { FilesControl } from './Files';\n\nconst meta = {\n  component: FilesControl,\n  tags: ['autodocs'],\n  parameters: { withRawArg: 'value', controls: { include: ['value', 'accept'] } },\n  argTypes: {\n    value: {\n      description: 'Selected file',\n      control: { type: 'file' },\n    },\n  },\n  args: {\n    name: 'files',\n    onChange: fn(),\n  },\n} satisfies Meta<typeof FilesControl>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Undefined: Story = {\n  args: { value: undefined },\n};\n// for security reasons a file input field cannot have an initial value, so it doesn't make sense to have stories for it\n\nexport const AcceptAnything: Story = {\n  args: { accept: '*/*' },\n};\n\nexport const AcceptPDFs: Story = {\n  name: 'Accept PDFs',\n  args: { accept: '.pdf' },\n};\n\nexport const Disabled: Story = {\n  args: {\n    accept: '*/*',\n    argType: { control: { readOnly: true } },\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/Files.tsx",
    "content": "import React, { useEffect, useRef } from 'react';\nimport type { ChangeEvent, FC } from 'react';\n\nimport { Form } from 'storybook/internal/components';\n\nimport { styled } from 'storybook/theming';\n\nimport { getControlId } from './helpers';\nimport type { ControlProps } from './types';\n\nexport interface FilesControlProps extends ControlProps<string[]> {\n  /**\n   * The accept attribute value is a string that defines the file types the file input should\n   * accept. This string is a comma-separated list of unique file type specifiers.\n   *\n   * @example _/_\n   *\n   * @example .webm,video/webm\n   *\n   * @example .doc,.docx,application/msword\n   *\n   * @defaultValue `image/*`\n   * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept\n   */\n  accept?: string;\n}\n\nconst FileInput = styled(Form.Input)({\n  padding: 10,\n});\n\nfunction revokeOldUrls(urls: string[]) {\n  urls.forEach((url) => {\n    if (url.startsWith('blob:')) {\n      URL.revokeObjectURL(url);\n    }\n  });\n}\n\nexport const FilesControl: FC<FilesControlProps> = ({\n  onChange,\n  name,\n  storyId,\n  accept = 'image/*',\n  value,\n  argType,\n}) => {\n  const inputElement = useRef<HTMLInputElement>(null);\n  const readonly = argType?.control?.readOnly;\n\n  function handleFileChange(e: ChangeEvent<HTMLInputElement>) {\n    if (!e.target.files) {\n      return;\n    }\n    const fileUrls = Array.from(e.target.files).map((file) => URL.createObjectURL(file));\n    onChange(fileUrls);\n    revokeOldUrls(value || []);\n  }\n\n  // Added useEffect hook to reset the file value when value is null\n  useEffect(() => {\n    if (value == null && inputElement.current) {\n      inputElement.current.value = '';\n    }\n  }, [value, name]);\n\n  const controlId = getControlId(name, storyId);\n\n  return (\n    <>\n      <label htmlFor={controlId} className=\"sb-sr-only\">\n        {name}\n      </label>\n      <FileInput\n        ref={inputElement}\n        id={controlId}\n        type=\"file\"\n        name={name}\n        multiple\n        disabled={readonly}\n        onChange={handleFileChange}\n        accept={accept}\n        size=\"flex\"\n      />\n    </>\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/Number.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { fn } from 'storybook/test';\n\nimport { NumberControl } from './Number';\n\nconst meta = {\n  component: NumberControl,\n  tags: ['autodocs'],\n  parameters: { withRawArg: 'value', controls: { include: ['value', 'min', 'max', 'step'] } },\n  args: {\n    name: 'number',\n    onChange: fn(),\n  },\n} satisfies Meta<typeof NumberControl>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Undefined: Story = {\n  args: { value: undefined },\n};\n// for security reasons a file input field cannot have an initial value, so it doesn't make sense to have stories for it\n\nexport const Ten: Story = {\n  args: { value: 10 },\n};\nexport const Zero: Story = {\n  args: { value: 0 },\n};\n\nexport const WithMin: Story = {\n  args: { min: 1, value: 3 },\n};\nexport const WithMax: Story = {\n  args: { max: 7, value: 3 },\n};\nexport const WithMinAndMax: Story = {\n  args: { min: -2, max: 5, value: 3 },\n};\nexport const LessThanMin: Story = {\n  args: { min: 3, value: 1 },\n};\nexport const MoreThanMax: Story = {\n  args: { max: 3, value: 6 },\n};\n\nexport const WithStep: Story = {\n  args: { step: 5, value: 3 },\n};\n\nexport const Readonly: Story = {\n  args: {\n    value: 3,\n    argType: { table: { readonly: true } },\n  },\n};\n\nexport const ReadonlyAndUndefined: Story = {\n  args: {\n    value: undefined,\n    argType: { table: { readonly: true } },\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/Number.tsx",
    "content": "import type { ChangeEvent, FC } from 'react';\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { Button, Form } from 'storybook/internal/components';\n\nimport { styled } from 'storybook/theming';\n\nimport { getControlId, getControlSetterButtonId } from './helpers';\nimport type { ControlProps, NumberConfig, NumberValue } from './types';\n\nconst Wrapper = styled.label({\n  display: 'flex',\n});\n\ntype NumberProps = ControlProps<NumberValue | null> & NumberConfig;\n\nexport const parse = (value: string) => {\n  const result = parseFloat(value);\n  return Number.isNaN(result) ? undefined : result;\n};\n\nexport const format = (value: NumberValue) => (value != null ? String(value) : '');\n\nconst FormInput = styled(Form.Input)(({ theme }) => ({\n  background: theme.base === 'light' ? theme.color.lighter : 'transparent',\n}));\n\nexport const NumberControl: FC<NumberProps> = ({\n  name,\n  storyId,\n  value,\n  onChange,\n  min,\n  max,\n  step,\n  onBlur,\n  onFocus,\n  argType,\n}) => {\n  const [inputValue, setInputValue] = useState(typeof value === 'number' ? value : '');\n  const [forceVisible, setForceVisible] = useState(false);\n  const [parseError, setParseError] = useState<Error | null>(null);\n  const readonly = !!argType?.table?.readonly;\n\n  const handleChange = useCallback(\n    (event: ChangeEvent<HTMLInputElement>) => {\n      setInputValue(event.target.value);\n\n      const result = parseFloat(event.target.value);\n      if (Number.isNaN(result)) {\n        setParseError(new Error(`'${event.target.value}' is not a number`));\n      } else {\n        // Initialize the final value as the user's input\n        let finalValue = result;\n\n        // Clamp to minimum: if finalValue is less than min, use min\n        if (typeof min === 'number' && finalValue < min) {\n          finalValue = min;\n        }\n\n        // Clamp to maximum: if finalValue is greater than max, use max\n        if (typeof max === 'number' && finalValue > max) {\n          finalValue = max;\n        }\n\n        // Pass the clamped final value to the onChange callback\n        onChange(finalValue);\n        // Clear any previous parse errors\n        setParseError(null);\n\n        // If the value was clamped, update the input display to the final value\n        if (finalValue !== result) {\n          setInputValue(String(finalValue));\n        }\n      }\n    },\n    [onChange, setParseError, min, max]\n  );\n\n  const onForceVisible = useCallback(() => {\n    setInputValue('0');\n    onChange(0);\n    setForceVisible(true);\n  }, [setForceVisible]);\n\n  const htmlElRef = useRef<HTMLInputElement>(null);\n  useEffect(() => {\n    if (forceVisible && htmlElRef.current) {\n      htmlElRef.current.select();\n    }\n  }, [forceVisible]);\n\n  useEffect(() => {\n    const newInputValue = typeof value === 'number' ? value : '';\n    if (inputValue !== newInputValue) {\n      setInputValue(newInputValue);\n    }\n  }, [value]);\n\n  if (value === undefined) {\n    return (\n      <Button\n        ariaLabel={false}\n        variant=\"outline\"\n        size=\"medium\"\n        id={getControlSetterButtonId(name, storyId)}\n        onClick={onForceVisible}\n        disabled={readonly}\n      >\n        Set number\n      </Button>\n    );\n  }\n\n  return (\n    <Wrapper>\n      <FormInput\n        ref={htmlElRef}\n        id={getControlId(name, storyId)}\n        type=\"number\"\n        onChange={handleChange}\n        size=\"flex\"\n        placeholder=\"Edit number...\"\n        value={inputValue}\n        valid={parseError ? 'error' : undefined}\n        autoFocus={forceVisible}\n        readOnly={readonly}\n        {...{ name, min, max, step, onFocus, onBlur }}\n      />\n    </Wrapper>\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/Object.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { fn } from 'storybook/test';\n\nimport { ObjectControl } from './Object';\n\nconst meta = {\n  component: ObjectControl,\n  tags: ['autodocs'],\n  parameters: { withRawArg: 'value', controls: { include: ['value'] } },\n  args: {\n    name: 'object',\n    onChange: fn(),\n  },\n} satisfies Meta<typeof ObjectControl>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Object: Story = {\n  args: {\n    value: {\n      name: 'Michael',\n      someDate: new Date('2022-10-30T12:31:11'),\n      nested: { someBool: true, someNumber: 22 },\n    },\n  },\n};\n\nexport const Array: Story = {\n  args: {\n    value: [\n      'someString',\n      22,\n      true,\n      new Date('2022-10-30T12:31:11'),\n      { someBool: true, someNumber: 22 },\n    ],\n  },\n};\n\nexport const EmptyObject: Story = {\n  args: {\n    value: {},\n  },\n};\n\nexport const EmptyArray: Story = {\n  args: {\n    value: {},\n  },\n};\n\nexport const Null: Story = {\n  args: {\n    value: null,\n  },\n};\n\nexport const Undefined: Story = {\n  args: {\n    value: undefined,\n  },\n};\n\nclass Person {\n  constructor(\n    public firstName: string,\n    public lastName: string\n  ) {}\n\n  fullName() {\n    return `${this.firstName} ${this.lastName}`;\n  }\n}\n\n/**\n * We show a class collapsed as it might contain many methods. It is read-only as we can not\n * construct the class.\n */\nexport const Class: Story = {\n  args: {\n    value: new Person('Kasper', 'Peulen'),\n  },\n};\n\n/**\n * We show a function collapsed. Even if it is \"object\" like, such as \"fn\". It is read-only as we\n * can not construct a function.\n */\nexport const Function: Story = {\n  args: {\n    value: fn(),\n  },\n};\n\nexport const Readonly: Story = {\n  args: {\n    value: {\n      name: 'Michael',\n      someDate: new Date('2022-10-30T12:31:11'),\n      nested: { someBool: true, someNumber: 22 },\n    },\n    argType: { table: { readonly: true } },\n  },\n};\n\nexport const ReadonlyAndUndefined: Story = {\n  args: {\n    value: undefined,\n    argType: { table: { readonly: true } },\n  },\n};\n\nexport const ObjectSmallViewport: Story = {\n  args: {\n    value: {\n      name: 'Michael',\n      someDate: new Date('2022-10-30T12:31:11'),\n      nested: { someBool: true, someNumber: 22 },\n    },\n  },\n  parameters: {\n    chromatic: { viewports: [320] },\n  },\n};\n\nexport const ArraySmallViewport: Story = {\n  args: {\n    value: [\n      'someString',\n      22,\n      true,\n      new Date('2022-10-30T12:31:11'),\n      { someBool: true, someNumber: 22 },\n    ],\n  },\n  parameters: {\n    chromatic: { viewports: [320] },\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/Object.tsx",
    "content": "import type { FC, FocusEvent, SyntheticEvent } from 'react';\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { Button, Form, ToggleButton } from 'storybook/internal/components';\n\nimport { AddIcon, EditIcon, SubtractIcon } from '@storybook/icons';\n\nimport { cloneDeep } from 'es-toolkit/object';\nimport { styled, useTheme } from 'storybook/theming';\n\nimport { getControlId, getControlSetterButtonId } from './helpers';\nimport { JsonTree } from './react-editable-json-tree';\nimport type { ControlProps, ObjectConfig, ObjectValue } from './types';\n\nconst { window: globalWindow } = globalThis;\n\nconst Wrapper = styled.div(({ theme }) => ({\n  position: 'relative',\n  display: 'flex',\n  isolation: 'isolate',\n  gap: 8,\n\n  '.rejt-tree': {\n    flex: 1,\n    marginLeft: '1rem',\n    fontSize: '13px',\n    listStyleType: 'none',\n  },\n  '.rejt-value-node:hover': {\n    '& > button': {\n      opacity: 1,\n    },\n  },\n  '.rejt-add-form': {\n    marginLeft: 10,\n  },\n  '.rejt-add-value-node': {\n    display: 'inline-flex',\n    alignItems: 'center',\n  },\n  '.rejt-name': {\n    color: theme.color.secondary,\n    lineHeight: '22px',\n  },\n  '.rejt-not-collapsed-list': {\n    listStyle: 'none',\n    margin: '0 0 0 1rem',\n    padding: 0,\n  },\n  '.rejt-not-collapsed-delimiter': {\n    lineHeight: '22px',\n  },\n  '.rejt-value': {\n    display: 'inline-block',\n    border: '1px solid transparent',\n    borderRadius: 4,\n    margin: '1px 0',\n    padding: '0 4px',\n    cursor: 'text',\n    color: theme.color.defaultText,\n  },\n  '.rejt-value-node:hover > .rejt-value': {\n    background: theme.base === 'light' ? theme.color.lighter : 'hsl(0 0 100 / 0.02)',\n    borderColor: theme.appBorderColor,\n  },\n  '.rejt-collapsed-value': {\n    color: theme.color.defaultText,\n  },\n}));\n\nconst ButtonInline = styled.button<{ primary?: boolean }>(({ theme, primary }) => ({\n  border: 0,\n  height: 20,\n  margin: 1,\n  borderRadius: 4,\n  background: primary ? theme.color.secondary : 'transparent',\n  color: primary ? theme.color.lightest : theme.color.dark,\n  fontWeight: primary ? 'bold' : 'normal',\n  cursor: 'pointer',\n}));\n\nconst ActionButton = styled.button(({ theme }) => ({\n  background: 'none',\n  border: 0,\n  display: 'inline-flex',\n  verticalAlign: 'middle',\n  padding: 3,\n  marginLeft: 5,\n  color: theme.textMutedColor,\n  opacity: 0,\n  transition: 'opacity 0.2s',\n  cursor: 'pointer',\n  position: 'relative',\n  svg: {\n    width: 9,\n    height: 9,\n  },\n  ':disabled': {\n    cursor: 'not-allowed',\n  },\n  ':hover, :focus-visible': {\n    opacity: 1,\n  },\n  '&:hover:not(:disabled), &:focus-visible:not(:disabled)': {\n    '&.rejt-plus-menu': {\n      color: theme.color.ancillary,\n    },\n    '&.rejt-minus-menu': {\n      color: theme.color.negative,\n    },\n  },\n}));\n\nconst Input = styled.input(({ theme, placeholder }) => ({\n  outline: 0,\n  margin: placeholder ? 1 : '1px 0',\n  padding: '3px 4px',\n  color: theme.color.defaultText,\n  background: theme.background.app,\n  border: `1px solid ${theme.appBorderColor}`,\n  borderRadius: 4,\n  lineHeight: '14px',\n  width: placeholder === 'Key' ? 80 : 120,\n  '&:focus': {\n    border: `1px solid ${theme.color.secondary}`,\n  },\n}));\n\nconst RawButton = styled(ToggleButton)({\n  alignSelf: 'flex-start',\n  order: 2,\n  marginRight: -10,\n});\n\nconst RawInput = styled(Form.Textarea)(({ theme }) => ({\n  flex: 1,\n  padding: '7px 6px',\n  fontFamily: theme.typography.fonts.mono,\n  fontSize: '12px',\n  lineHeight: '18px',\n  '&::placeholder': {\n    fontFamily: theme.typography.fonts.base,\n    fontSize: '13px',\n  },\n  '&:placeholder-shown': {\n    padding: '7px 10px',\n  },\n}));\n\nconst ENTER_EVENT = {\n  bubbles: true,\n  cancelable: true,\n  key: 'Enter',\n  code: 'Enter',\n  keyCode: 13,\n};\nconst dispatchEnterKey = (event: SyntheticEvent<HTMLInputElement>) => {\n  event.currentTarget.dispatchEvent(new globalWindow.KeyboardEvent('keydown', ENTER_EVENT));\n};\nconst selectValue = (event: SyntheticEvent<HTMLInputElement>) => {\n  event.currentTarget.select();\n};\n\nexport type ObjectProps = ControlProps<ObjectValue> & ObjectConfig;\n\nexport const ObjectControl: FC<ObjectProps> = ({ name, storyId, value, onChange, argType }) => {\n  const theme = useTheme();\n  const data = useMemo(() => value && cloneDeep(value), [value]);\n  const hasData = data !== null && data !== undefined;\n  const [showRaw, setShowRaw] = useState(!hasData);\n\n  const [parseError, setParseError] = useState<Error | null>(null);\n  const readonly = !!argType?.table?.readonly;\n  const updateRaw: (raw: string) => void = useCallback(\n    (raw) => {\n      try {\n        if (raw) {\n          onChange(JSON.parse(raw));\n        }\n        setParseError(null);\n      } catch (e) {\n        setParseError(e as Error);\n      }\n    },\n    [onChange]\n  );\n\n  const [forceVisible, setForceVisible] = useState(false);\n  const onForceVisible = useCallback(() => {\n    onChange({});\n    setForceVisible(true);\n  }, [onChange, setForceVisible]);\n\n  const htmlElRef = useRef<HTMLTextAreaElement>(null);\n  useEffect(() => {\n    if (forceVisible && htmlElRef.current) {\n      htmlElRef.current.select();\n    }\n  }, [forceVisible]);\n\n  // Use string value as key to force re-render on Arg value reset.\n  const jsonString = useMemo(() => {\n    return JSON.stringify(data ?? '', null, 2);\n  }, [data]);\n\n  if (!hasData) {\n    return (\n      <Button\n        ariaLabel={false}\n        disabled={readonly}\n        id={getControlSetterButtonId(name, storyId)}\n        onClick={onForceVisible}\n      >\n        Set object\n      </Button>\n    );\n  }\n\n  const rawJSONForm = (\n    <RawInput\n      ref={htmlElRef}\n      id={getControlId(name, storyId)}\n      minRows={3}\n      name={name}\n      key={jsonString}\n      defaultValue={jsonString}\n      onBlur={(event: FocusEvent<HTMLTextAreaElement>) => updateRaw(event.target.value)}\n      placeholder=\"Edit JSON string...\"\n      autoFocus={forceVisible}\n      valid={parseError ? 'error' : undefined}\n      readOnly={readonly}\n    />\n  );\n\n  const isObjectOrArray =\n    Array.isArray(value) || (typeof value === 'object' && value?.constructor === Object);\n\n  return (\n    <Wrapper>\n      {isObjectOrArray && (\n        <RawButton\n          disabled={readonly}\n          pressed={showRaw}\n          ariaLabel={`Edit ${name} as JSON`}\n          onClick={(e: SyntheticEvent) => {\n            e.preventDefault();\n            setShowRaw((isRaw) => !isRaw);\n          }}\n          variant=\"ghost\"\n          padding=\"small\"\n          size=\"small\"\n        >\n          <EditIcon />\n        </RawButton>\n      )}\n      {!showRaw ? (\n        <JsonTree\n          readOnly={readonly || !isObjectOrArray}\n          isCollapsed={isObjectOrArray ? /* default value */ undefined : () => true}\n          data={data}\n          rootName={name}\n          onFullyUpdate={onChange}\n          cancelButtonElement={<ButtonInline type=\"button\">Cancel</ButtonInline>}\n          addButtonElement={\n            <ButtonInline type=\"submit\" primary>\n              Save\n            </ButtonInline>\n          }\n          plusMenuElement={\n            <ActionButton type=\"button\">\n              <AddIcon />\n            </ActionButton>\n          }\n          minusMenuElement={\n            <ActionButton type=\"button\">\n              <SubtractIcon />\n            </ActionButton>\n          }\n          inputElement={(_: any, __: any, ___: any, key: string) =>\n            key ? <Input onFocus={selectValue} onBlur={dispatchEnterKey} /> : <Input />\n          }\n          fallback={rawJSONForm}\n        />\n      ) : (\n        rawJSONForm\n      )}\n    </Wrapper>\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/Range.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { fn } from 'storybook/test';\n\nimport { RangeControl } from './Range';\n\nconst meta = {\n  component: RangeControl,\n  tags: ['autodocs'],\n  parameters: { withRawArg: 'value', controls: { include: ['value', 'min', 'max', 'step'] } },\n  args: {\n    name: 'range',\n    onChange: fn(),\n  },\n} satisfies Meta<typeof RangeControl>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Undefined: Story = {\n  args: {\n    value: undefined,\n  },\n};\n\nexport const Zero: Story = {\n  args: {\n    value: 0,\n  },\n};\n\nexport const WithMin: Story = {\n  args: {\n    min: 5,\n    value: 20,\n  },\n};\n\nexport const WithMax: Story = {\n  args: {\n    max: 50,\n    value: 20,\n  },\n};\n\nexport const WithBigMax: Story = {\n  args: {\n    max: 10000000000,\n    value: 20,\n  },\n};\n\nexport const WithMinAndMax: Story = {\n  args: {\n    min: 10,\n    max: 50,\n    value: 20,\n  },\n};\n\nexport const LessThanMin: Story = {\n  args: {\n    min: 10,\n    value: 5,\n  },\n};\n\nexport const MoreThanMax: Story = {\n  args: {\n    max: 20,\n    value: 50,\n  },\n};\n\nexport const WithSteps: Story = {\n  args: {\n    step: 5,\n    value: 50,\n  },\n};\n\nexport const Decimals: Story = {\n  args: {\n    step: 0.000000000002,\n    value: 989.123123123123,\n    max: 2000,\n  },\n};\nexport const WithInfiniteMax: Story = {\n  args: {\n    max: Infinity,\n    value: 50,\n  },\n};\n\nexport const Readonly: Story = {\n  args: {\n    value: 40,\n    argType: {\n      table: {\n        readonly: true,\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/Range.tsx",
    "content": "import type { ChangeEvent, FC } from 'react';\nimport React, { useMemo } from 'react';\n\nimport { darken, lighten, rgba } from 'polished';\nimport { styled } from 'storybook/theming';\n\nimport { parse } from './Number';\nimport { getControlId } from './helpers';\nimport type { ControlProps, NumberValue, RangeConfig } from './types';\n\ntype RangeProps = ControlProps<NumberValue | null> & RangeConfig;\n\nconst RangeInput = styled.input<{ min: number; max: number; value: number }>(\n  ({ theme, min, max, value, disabled }) => {\n    // Shared track background gradient\n    const trackBackground =\n      theme.base === 'light'\n        ? `linear-gradient(to right, \n          ${theme.color.green} 0%, ${theme.color.green} ${((value - min) / (max - min)) * 100}%, \n          ${darken(0.02, theme.input.background)} ${((value - min) / (max - min)) * 100}%, \n          ${darken(0.02, theme.input.background)} 100%)`\n        : `linear-gradient(to right, \n          ${theme.color.green} 0%, ${theme.color.green} ${((value - min) / (max - min)) * 100}%, \n          ${lighten(0.02, theme.input.background)} ${((value - min) / (max - min)) * 100}%, \n          ${lighten(0.02, theme.input.background)} 100%)`;\n\n    // Shared track base styles\n    const trackBaseStyles = {\n      background: trackBackground,\n      borderRadius: 6,\n      boxShadow: `${theme.base == 'dark' ? 'hsl(0 0 100 / 0.4)' : 'hsl(0 0 0 / 0.44)'} 0 0 0 1px inset`,\n      cursor: disabled ? 'not-allowed' : 'pointer',\n      height: 6,\n      width: '100%',\n    };\n\n    const trackFocusStyles = {\n      borderColor: rgba(theme.color.secondary, 0.4),\n    };\n\n    // Shared thumb base styles\n    const thumbBaseStyles = {\n      width: 16,\n      height: 16,\n      borderRadius: 50,\n      cursor: disabled ? 'not-allowed' : 'grab',\n      background: theme.input.background,\n      border: `1px solid ${theme.base == 'dark' ? 'hsl(0 0 100 / 0.4)' : 'hsl(0 0 0 / 0.44)'}`,\n      boxShadow:\n        theme.base === 'light' ? `0 1px 3px 0px ${rgba(theme.appBorderColor, 0.2)}` : 'unset',\n      transition: 'all 150ms ease-out',\n    };\n\n    // Shared thumb hover styles\n    const thumbHoverStyles = {\n      background: `${darken(0.05, theme.input.background)}`,\n      transform: 'scale3d(1.1, 1.1, 1.1) translateY(-1px)',\n      transition: 'all 50ms ease-out',\n    };\n\n    // Shared thumb active styles\n    const thumbActiveStyles = {\n      background: `${theme.input.background}`,\n      transform: 'scale3d(1, 1, 1) translateY(0px)',\n    };\n\n    const thumbFocusStyles = {\n      borderColor: theme.color.secondary,\n      boxShadow: theme.base === 'light' ? `0 0px 5px 0px ${theme.color.secondary}` : 'unset',\n    };\n\n    return {\n      // Restyled using http://danielstern.ca/range.css/#/\n      appearance: 'none',\n      backgroundColor: 'transparent',\n      width: '100%',\n\n      // Track styles\n      '&::-webkit-slider-runnable-track': trackBaseStyles,\n\n      '&::-moz-range-track': trackBaseStyles,\n\n      '&::-ms-track': {\n        ...trackBaseStyles,\n        color: 'transparent',\n      },\n\n      // Thumb styles\n      '&::-moz-range-thumb': {\n        ...thumbBaseStyles,\n\n        '&:hover': thumbHoverStyles,\n        '&:active': thumbActiveStyles,\n      },\n\n      '&::-webkit-slider-thumb': {\n        ...thumbBaseStyles,\n        marginTop: '-6px',\n        appearance: 'none',\n\n        '&:hover': thumbHoverStyles,\n        '&:active': thumbActiveStyles,\n      },\n\n      '&::-ms-thumb': {\n        ...thumbBaseStyles,\n        marginTop: 0,\n\n        '&:hover': thumbHoverStyles,\n        '&:active': thumbActiveStyles,\n      },\n\n      '&:focus': {\n        outline: 'none',\n\n        '&::-webkit-slider-runnable-track': trackFocusStyles,\n        '&::-moz-range-track': trackFocusStyles,\n        '&::-ms-track': trackFocusStyles,\n\n        '&::-webkit-slider-thumb': thumbFocusStyles,\n        '&::-moz-range-thumb': thumbFocusStyles,\n        '&::-ms-thumb': thumbFocusStyles,\n      },\n\n      '&::-ms-fill-lower': {\n        borderRadius: 6,\n      },\n\n      '&::-ms-fill-upper': {\n        borderRadius: 6,\n      },\n\n      '@supports (-ms-ime-align:auto)': { 'input[type=range]': { margin: '0' } },\n    };\n  }\n);\n\nconst RangeLabel = styled.span({\n  paddingLeft: 5,\n  paddingRight: 5,\n  fontSize: 12,\n  whiteSpace: 'nowrap',\n  fontFeatureSettings: 'tnum',\n  fontVariantNumeric: 'tabular-nums',\n});\n\nconst RangeCurrentAndMaxLabel = styled(RangeLabel)<{\n  numberOFDecimalsPlaces: number;\n  max: number;\n}>(({ numberOFDecimalsPlaces, max }) => ({\n  // Fixed width of \"current / max\" label to avoid slider width changes\n  // 3 = size of separator \" / \"\n  width: `${numberOFDecimalsPlaces + max.toString().length * 2 + 3}ch`,\n  textAlign: 'right',\n  flexShrink: 0,\n}));\n\nconst RangeWrapper = styled.div<{ readOnly: boolean }>(({ readOnly }) => ({\n  display: 'flex',\n  alignItems: 'center',\n  width: '100%',\n  opacity: readOnly ? 0.5 : 1,\n}));\n\nfunction getNumberOfDecimalPlaces(number: number) {\n  const match = number.toString().match(/(?:\\.(\\d+))?(?:[eE]([+-]?\\d+))?$/);\n  return !match\n    ? 0\n    : Math.max(\n        0,\n        // Number of digits right of decimal point.\n        (match[1] ? match[1].length : 0) -\n          // Adjust for scientific notation.\n          (match[2] ? +match[2] : 0)\n      );\n}\n\nexport const RangeControl: FC<RangeProps> = ({\n  name,\n  storyId,\n  value,\n  onChange,\n  min = 0,\n  max = 100,\n  step = 1,\n  onBlur,\n  onFocus,\n  argType,\n}) => {\n  const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\n    onChange(parse(event.target.value));\n  };\n\n  const hasValue = value !== undefined;\n  const numberOFDecimalsPlaces = useMemo(() => getNumberOfDecimalPlaces(step), [step]);\n\n  const readonly = !!argType?.table?.readonly;\n  const controlId = getControlId(name, storyId);\n\n  return (\n    <RangeWrapper readOnly={readonly}>\n      <label htmlFor={controlId} className=\"sb-sr-only\">\n        {name}\n      </label>\n      <RangeLabel>{min}</RangeLabel>\n      <RangeInput\n        id={controlId}\n        type=\"range\"\n        disabled={readonly}\n        onChange={handleChange}\n        {...{ name, min, max, step, onFocus, onBlur }}\n        value={value ?? min}\n      />\n      <RangeCurrentAndMaxLabel numberOFDecimalsPlaces={numberOFDecimalsPlaces} max={max}>\n        {hasValue ? value!.toFixed(numberOFDecimalsPlaces) : '--'} / {max}\n      </RangeCurrentAndMaxLabel>\n    </RangeWrapper>\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/Text.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { fn } from 'storybook/test';\n\nimport { TextControl } from './Text';\n\nconst meta = {\n  component: TextControl,\n  tags: ['autodocs'],\n  parameters: { withRawArg: 'value', controls: { include: ['value', 'maxLength'] } },\n  args: {\n    name: 'text',\n    onChange: fn(),\n  },\n} satisfies Meta<typeof TextControl>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  args: {\n    value: 'Storybook says hi. 👋',\n  },\n};\n\nexport const Empty: Story = {\n  args: {\n    value: '',\n  },\n};\n\nexport const Undefined: Story = {\n  args: {\n    value: undefined,\n  },\n};\n\nexport const WithMaxLength: Story = {\n  args: {\n    value: \"You can't finish this sente\",\n    maxLength: 28,\n  },\n};\n\nexport const BasicReadonly: Story = {\n  args: {\n    value: 'Storybook says hi. 👋',\n    argType: {\n      table: {\n        readonly: true,\n      },\n    },\n  },\n};\n\nexport const UndefinedReadonly: Story = {\n  args: {\n    value: undefined,\n    argType: {\n      table: {\n        readonly: true,\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/Text.tsx",
    "content": "import type { ChangeEvent, FC } from 'react';\nimport React, { useCallback, useState } from 'react';\n\nimport { Button, Form } from 'storybook/internal/components';\n\nimport { styled } from 'storybook/theming';\n\nimport { getControlId, getControlSetterButtonId } from './helpers';\nimport type { ControlProps, TextConfig, TextValue } from './types';\n\nexport type TextProps = ControlProps<TextValue | undefined> & TextConfig;\n\nconst Wrapper = styled.label({\n  display: 'flex',\n});\n\nconst MaxLength = styled.div<{ isMaxed: boolean }>(({ isMaxed }) => ({\n  marginLeft: '0.75rem',\n  paddingTop: '0.35rem',\n  color: isMaxed ? 'red' : undefined,\n}));\n\nexport const TextControl: FC<TextProps> = ({\n  name,\n  storyId,\n  value,\n  onChange,\n  onFocus,\n  onBlur,\n  maxLength,\n  argType,\n}) => {\n  const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) => {\n    onChange(event.target.value);\n  };\n\n  const readonly = !!argType?.table?.readonly;\n\n  const [forceVisible, setForceVisible] = useState(false);\n\n  const onForceVisible = useCallback(() => {\n    onChange('');\n    setForceVisible(true);\n  }, [setForceVisible]);\n\n  if (value === undefined) {\n    return (\n      <Button\n        ariaLabel={false}\n        variant=\"outline\"\n        size=\"medium\"\n        disabled={readonly}\n        id={getControlSetterButtonId(name, storyId)}\n        onClick={onForceVisible}\n      >\n        Set string\n      </Button>\n    );\n  }\n\n  const isValid = typeof value === 'string';\n\n  return (\n    <Wrapper>\n      <Form.Textarea\n        id={getControlId(name, storyId)}\n        maxLength={maxLength}\n        onChange={handleChange}\n        disabled={readonly}\n        size=\"flex\"\n        placeholder=\"Edit string...\"\n        autoFocus={forceVisible}\n        valid={isValid ? undefined : 'error'}\n        {...{ name, value: isValid ? value : '', onFocus, onBlur }}\n      />\n      {maxLength && (\n        <MaxLength isMaxed={value?.length === maxLength}>\n          {value?.length ?? 0} / {maxLength}\n        </MaxLength>\n      )}\n    </Wrapper>\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/helpers.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { getControlId, getControlSetterButtonId } from './helpers';\n\ndescribe('getControlId', () => {\n  it.each([\n    // caseName, input, expected\n    ['lower case', 'some-id', 'control-some-id'],\n    ['upper case', 'SOME-ID', 'control-SOME-ID'],\n    ['all valid characters', 'some_weird-:custom.id', 'control-some_weird-:custom.id'],\n  ])('%s', (name, input, expected) => {\n    expect(getControlId(input)).toBe(expected);\n  });\n\n  it('includes storyId when provided', () => {\n    expect(getControlId('some-id', 'story--name')).toBe('control-story--name-some-id');\n  });\n});\n\ndescribe('getControlSetterButtonId', () => {\n  it.each([\n    // caseName, input, expected\n    ['lower case', 'some-id', 'set-some-id'],\n    ['upper case', 'SOME-ID', 'set-SOME-ID'],\n    ['all valid characters', 'some_weird-:custom.id', 'set-some_weird-:custom.id'],\n  ])('%s', (name, input, expected) => {\n    expect(getControlSetterButtonId(input)).toBe(expected);\n  });\n\n  it('includes storyId when provided', () => {\n    expect(getControlSetterButtonId('some-id', 'story--name')).toBe('set-story--name-some-id');\n  });\n});\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/helpers.ts",
    "content": "/**\n * Adds `control` prefix to make ID attribute more specific. Removes spaces because spaces are not\n * allowed in ID attributes\n *\n * @example\n *\n * ```ts\n * getControlId('my prop name') -> 'control-my-prop-name'\n * ```\n *\n * @link http://xahlee.info/js/html_allowed_chars_in_attribute.html\n */\nexport const getControlId = (value: string, storyId?: string) => {\n  const base = value.replace(/\\s+/g, '-');\n  return storyId ? `control-${storyId}-${base}` : `control-${base}`;\n};\n\n/**\n * Adds `set` prefix to make ID attribute more specific. Removes spaces because spaces are not\n * allowed in ID attributes\n *\n * @example\n *\n * ```ts\n * getControlSetterButtonId('my prop name') -> 'set-my-prop-name'\n * ```\n *\n * @link http://xahlee.info/js/html_allowed_chars_in_attribute.html\n */\nexport const getControlSetterButtonId = (value: string, storyId?: string) => {\n  const base = value.replace(/\\s+/g, '-');\n  return storyId ? `set-${storyId}-${base}` : `set-${base}`;\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/index.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React, { Suspense, lazy } from 'react';\n\nimport type { ColorControlProps } from './Color';\n\nexport * from './types';\n\nexport * from './Boolean';\n\nexport type ColorProps = ColorControlProps;\n\nconst LazyColorControl = lazy(() => import('./Color'));\n\nexport const ColorControl = (props: ComponentProps<typeof LazyColorControl>) => (\n  <Suspense fallback={<div />}>\n    <LazyColorControl {...props} />\n  </Suspense>\n);\n\nexport * from './Date';\n\nexport * from './Number';\n\nexport * from './options';\nexport * from './Object';\n\nexport * from './Range';\n\nexport * from './Text';\n\nexport * from './Files';\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/options/CheckOptions.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { fn } from 'storybook/test';\n\nimport { OptionsControl } from './Options';\n\nconst arrayOptions = ['Bat', 'Cat', 'Rat'];\nconst labels = {\n  Bat: 'Batwoman',\n  Cat: 'Catwoman',\n  Rat: 'Ratwoman',\n};\nconst objectOptions = {\n  A: { id: 'Aardvark' },\n  B: { id: 'Bat' },\n  C: { id: 'Cat' },\n};\n\nconst meta = {\n  title: 'Controls/Options/Check',\n  component: OptionsControl,\n  tags: ['autodocs'],\n  parameters: {\n    withRawArg: 'value',\n    controls: { include: ['argType', 'type', 'value', 'labels'] },\n  },\n  args: {\n    name: 'check',\n    type: 'check',\n    argType: { options: arrayOptions },\n    onChange: fn(),\n  },\n  argTypes: {\n    value: {\n      control: { type: 'check' },\n      options: arrayOptions,\n    },\n  },\n} satisfies Meta<typeof OptionsControl>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Array: Story = {\n  args: {\n    value: [arrayOptions[0]],\n  },\n};\n\nexport const ArrayInline: Story = {\n  args: {\n    type: 'inline-check',\n    value: [arrayOptions[1], arrayOptions[2]],\n  },\n};\n\nexport const ArrayLabels: Story = {\n  args: {\n    value: [arrayOptions[0]],\n    labels,\n  },\n};\n\nexport const ArrayInlineLabels: Story = {\n  args: {\n    type: 'inline-check',\n    value: [arrayOptions[1], arrayOptions[2]],\n    labels,\n  },\n};\n\nexport const ArrayUndefined: Story = {\n  args: {\n    value: undefined,\n  },\n};\n\nexport const Object: Story = {\n  name: 'DEPRECATED: Object',\n  args: {\n    value: [objectOptions.B],\n    argType: { options: objectOptions },\n  },\n  argTypes: { value: { control: { type: 'object' } } },\n};\n\nexport const ObjectInline: Story = {\n  name: 'DEPRECATED: Object Inline',\n  args: {\n    type: 'inline-check',\n    value: [objectOptions.A, objectOptions.C],\n    argType: { options: objectOptions },\n  },\n  argTypes: { value: { control: { type: 'object' } } },\n};\n\nexport const ObjectUndefined: Story = {\n  name: 'DEPRECATED: Object Undefined',\n  args: {\n    value: undefined,\n    argType: { options: objectOptions },\n  },\n  argTypes: { value: { control: { type: 'object' } } },\n};\n\nexport const ArrayReadonly: Story = {\n  args: {\n    value: [arrayOptions[0]],\n    argType: {\n      options: arrayOptions,\n      table: {\n        readonly: true,\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/options/Checkbox.tsx",
    "content": "import type { ChangeEvent, FC } from 'react';\nimport React, { useEffect, useState } from 'react';\n\nimport { logger } from 'storybook/internal/client-logger';\n\nimport { styled } from 'storybook/theming';\n\nimport { getControlId } from '../helpers';\nimport type { ControlProps, NormalizedOptionsConfig, OptionsMultiSelection } from '../types';\nimport { selectedKeys, selectedValues } from './helpers';\n\nconst Wrapper = styled.fieldset<{ $isInline: boolean }>(\n  {\n    border: 'none',\n    marginInline: 0,\n    padding: 0,\n    display: 'flex',\n    alignItems: 'flex-start',\n  },\n  ({ $isInline: isInline }) =>\n    isInline\n      ? {\n          flexWrap: 'wrap',\n          gap: 15,\n          label: {\n            display: 'inline-flex',\n          },\n        }\n      : {\n          flexDirection: 'column',\n          gap: 8,\n          label: {\n            display: 'flex',\n          },\n        }\n);\n\nconst Text = styled.span<{ $readOnly: boolean }>(({ $readOnly }) => ({\n  opacity: $readOnly ? 0.5 : 1,\n}));\n\nconst Label = styled.label<{ $readOnly: boolean }>(({ $readOnly }) => ({\n  lineHeight: '20px',\n  alignItems: 'center',\n  cursor: $readOnly ? 'not-allowed' : 'pointer',\n\n  input: {\n    cursor: $readOnly ? 'not-allowed' : 'pointer',\n\n    margin: 0,\n    marginRight: 6,\n  },\n}));\n\ntype CheckboxConfig = NormalizedOptionsConfig & { isInline: boolean };\ntype CheckboxProps = ControlProps<OptionsMultiSelection> & CheckboxConfig;\nexport const CheckboxControl: FC<CheckboxProps> = ({\n  name,\n  storyId,\n  options,\n  value,\n  onChange,\n  isInline,\n  argType,\n}) => {\n  if (!options) {\n    logger.warn(`Checkbox with no options: ${name}`);\n    return <>-</>;\n  }\n\n  const initial = selectedKeys(value || [], options);\n  const [selected, setSelected] = useState(initial);\n\n  const readonly = !!argType?.table?.readonly;\n\n  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {\n    const option = (e.target as HTMLInputElement).value;\n    const updated = [...selected];\n    if (updated.includes(option)) {\n      updated.splice(updated.indexOf(option), 1);\n    } else {\n      updated.push(option);\n    }\n    onChange(selectedValues(updated, options));\n    setSelected(updated);\n  };\n\n  useEffect(() => {\n    setSelected(selectedKeys(value || [], options));\n  }, [value]);\n\n  const controlId = getControlId(name, storyId);\n\n  return (\n    <Wrapper $isInline={isInline}>\n      <legend className=\"sb-sr-only\">{name}</legend>\n      {Object.keys(options).map((key, index) => {\n        const id = `${controlId}-${index}`;\n        return (\n          <Label key={id} htmlFor={id} $readOnly={readonly}>\n            <input\n              type=\"checkbox\"\n              disabled={readonly}\n              id={id}\n              name={id}\n              value={key}\n              onChange={handleChange}\n              checked={selected?.includes(key)}\n            />\n            <Text $readOnly={readonly}>{key}</Text>\n          </Label>\n        );\n      })}\n    </Wrapper>\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/options/Options.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport type { ControlProps, Options, OptionsConfig, OptionsSelection } from '../types';\nimport { CheckboxControl } from './Checkbox';\nimport { RadioControl } from './Radio';\nimport { SelectControl } from './Select';\n\n/**\n * Options can accept `options` in two formats:\n *\n * - Array: ['a', 'b', 'c'] OR\n * - Object: { a: 1, b: 2, c: 3 } (deprecated)\n *\n * We always normalize to the more generalized object format and ONLY handle the object format in\n * the underlying control implementations.\n *\n * While non-primitive values are deprecated, they might still not be valid object keys, so the\n * resulting object is a Label -> Value mapping.\n */\nconst normalizeOptions = (options: Options, labels?: Record<any, string>) => {\n  if (Array.isArray(options)) {\n    return options.reduce((acc, item) => {\n      acc[labels?.[item] || String(item)] = item;\n      return acc;\n    }, {});\n  }\n  return options;\n};\n\nconst Controls = {\n  check: CheckboxControl,\n  'inline-check': CheckboxControl,\n  radio: RadioControl,\n  'inline-radio': RadioControl,\n  select: SelectControl,\n  'multi-select': SelectControl,\n} as const;\n\nexport type OptionsProps = ControlProps<OptionsSelection> & OptionsConfig;\nexport const OptionsControl: FC<OptionsProps> = (props) => {\n  const { type = 'select', labels, argType } = props;\n  const normalized = {\n    ...props,\n    argType,\n    options: argType ? normalizeOptions(argType.options, labels) : {},\n    isInline: type.includes('inline'),\n    isMulti: type.includes('multi'),\n  };\n\n  const Control = Controls[type];\n\n  if (Control) {\n    return <Control {...normalized} />;\n  }\n\n  throw new Error(`Unknown options type: ${type}`);\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/options/Radio.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { logger } from 'storybook/internal/client-logger';\n\nimport { styled } from 'storybook/theming';\n\nimport { getControlId } from '../helpers';\nimport type { ControlProps, NormalizedOptionsConfig, OptionsSingleSelection } from '../types';\nimport { selectedKey } from './helpers';\n\nconst Wrapper = styled.fieldset<{ isInline: boolean }>(\n  {\n    border: 'none',\n    marginInline: 0,\n    padding: 0,\n    display: 'flex',\n    alignItems: 'flex-start',\n  },\n  ({ isInline }) =>\n    isInline\n      ? {\n          flexWrap: 'wrap',\n          gap: 15,\n          label: {\n            display: 'inline-flex',\n          },\n        }\n      : {\n          flexDirection: 'column',\n          gap: 8,\n          label: {\n            display: 'flex',\n          },\n        }\n);\n\nconst Text = styled.span<{ $readOnly: boolean }>(({ $readOnly }) => ({\n  opacity: $readOnly ? 0.5 : 1,\n}));\n\nconst Label = styled.label<{ $readOnly: boolean }>(({ $readOnly }) => ({\n  lineHeight: '20px',\n  alignItems: 'center',\n\n  cursor: $readOnly ? 'not-allowed' : 'pointer',\n\n  input: {\n    cursor: $readOnly ? 'not-allowed' : 'pointer',\n    margin: 0,\n    marginRight: 6,\n  },\n}));\n\ntype RadioConfig = NormalizedOptionsConfig & { isInline: boolean };\ntype RadioProps = ControlProps<OptionsSingleSelection> & RadioConfig;\nexport const RadioControl: FC<RadioProps> = ({\n  name,\n  storyId,\n  options,\n  value,\n  onChange,\n  isInline,\n  argType,\n}) => {\n  if (!options) {\n    logger.warn(`Radio with no options: ${name}`);\n    return <>-</>;\n  }\n  const selection = selectedKey(value, options);\n  const controlId = getControlId(name, storyId);\n\n  const readonly = !!argType?.table?.readonly;\n\n  return (\n    <Wrapper isInline={isInline}>\n      <legend className=\"sb-sr-only\">{name}</legend>\n      {Object.keys(options).map((key, index) => {\n        const id = `${controlId}-${index}`;\n        return (\n          <Label key={id} htmlFor={id} $readOnly={readonly}>\n            <input\n              type=\"radio\"\n              id={id}\n              name={controlId}\n              disabled={readonly}\n              value={key}\n              onChange={(e) => onChange(options[e.currentTarget.value])}\n              checked={key === selection}\n            />\n            <Text $readOnly={readonly}>{key}</Text>\n          </Label>\n        );\n      })}\n    </Wrapper>\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/options/RadioOptions.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { fn } from 'storybook/test';\n\nimport { OptionsControl } from './Options';\n\nconst arrayOptions = ['Bat', 'Cat', 'Rat'];\nconst labels = {\n  Bat: 'Batwoman',\n  Cat: 'Catwoman',\n  Rat: 'Ratwoman',\n};\nconst objectOptions = {\n  A: { id: 'Aardvark' },\n  B: { id: 'Bat' },\n  C: { id: 'Cat' },\n};\n\nconst meta = {\n  title: 'Controls/Options/Radio',\n  component: OptionsControl,\n  tags: ['autodocs'],\n  parameters: {\n    withRawArg: 'value',\n    controls: { include: ['argType', 'type', 'value', 'labels'] },\n  },\n  args: {\n    name: 'radio',\n    type: 'radio',\n    argType: { options: arrayOptions },\n    onChange: fn(),\n  },\n  argTypes: {\n    value: {\n      control: { type: 'radio' },\n      options: arrayOptions,\n    },\n  },\n} satisfies Meta<typeof OptionsControl>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Array: Story = {\n  args: {\n    value: arrayOptions[0],\n  },\n};\n\nexport const ArrayInline: Story = {\n  args: {\n    type: 'inline-radio',\n    value: arrayOptions[1],\n  },\n};\n\nexport const ArrayLabels: Story = {\n  args: {\n    value: arrayOptions[0],\n    labels,\n  },\n};\n\nexport const ArrayInlineLabels: Story = {\n  args: {\n    type: 'inline-radio',\n    value: arrayOptions[1],\n    labels,\n  },\n};\n\nexport const ArrayUndefined: Story = {\n  args: {\n    value: undefined,\n  },\n};\n\nexport const Object: Story = {\n  name: 'DEPRECATED: Object',\n  args: {\n    value: objectOptions.B,\n    argType: { options: objectOptions },\n  },\n  argTypes: { value: { control: { type: 'object' } } },\n};\n\nexport const ObjectInline: Story = {\n  name: 'DEPRECATED: Object Inline',\n  args: {\n    type: 'inline-radio',\n    value: objectOptions.A,\n    argType: { options: objectOptions },\n  },\n  argTypes: { value: { control: { type: 'object' } } },\n};\n\nexport const ObjectUndefined: Story = {\n  name: 'DEPRECATED: Object Undefined',\n  args: {\n    value: undefined,\n    argType: { options: objectOptions },\n  },\n  argTypes: { value: { control: { type: 'object' } } },\n};\n\nexport const ArrayReadonly: Story = {\n  args: {\n    value: [arrayOptions[0]],\n    argType: {\n      options: arrayOptions,\n      table: {\n        readonly: true,\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/options/Select.tsx",
    "content": "import type { ChangeEvent, FC } from 'react';\nimport React from 'react';\n\nimport { logger } from 'storybook/internal/client-logger';\n\nimport { ChevronSmallDownIcon } from '@storybook/icons';\n\nimport { styled } from 'storybook/theming';\nimport type { CSSObject } from 'storybook/theming';\n\nimport { getControlId } from '../helpers';\nimport type { ControlProps, NormalizedOptionsConfig, OptionsSelection } from '../types';\nimport { selectedKey, selectedKeys, selectedValues } from './helpers';\n\nconst styleResets: CSSObject = {\n  // resets\n  appearance: 'none',\n  border: '0 none',\n  boxSizing: 'inherit',\n  display: ' block',\n  margin: ' 0',\n  background: 'transparent',\n  padding: 0,\n  fontSize: 'inherit',\n  position: 'relative',\n};\n\nconst OptionsSelect = styled.select(styleResets, ({ theme }) => ({\n  boxSizing: 'border-box',\n  position: 'relative',\n  padding: '6px 10px',\n  width: '100%',\n\n  color: theme.input.color || 'inherit',\n  background: theme.input.background,\n  borderRadius: theme.input.borderRadius,\n  boxShadow: `${theme.input.border} 0 0 0 1px inset`,\n\n  fontSize: theme.typography.size.s2 - 1,\n  lineHeight: '20px',\n\n  '&:focus': {\n    boxShadow: `${theme.color.secondary} 0 0 0 1px inset`,\n    outline: 'none',\n  },\n\n  '&[disabled]': {\n    cursor: 'not-allowed',\n    opacity: 0.5,\n  },\n\n  '::placeholder': {\n    color: theme.textMutedColor,\n  },\n\n  '&[multiple]': {\n    overflow: 'auto',\n    padding: 0,\n\n    option: {\n      display: 'block',\n      padding: '6px 10px',\n      marginLeft: 1,\n      marginRight: 1,\n\n      '&:hover': {\n        background: theme.background.hoverable,\n      },\n      '&:checked': {\n        background: 'transparent',\n        color: theme.color.secondary,\n        fontWeight: theme.typography.weight.bold,\n      },\n    },\n  },\n}));\n\nconst SelectWrapper = styled.span(({ theme }) => ({\n  display: 'inline-block',\n  lineHeight: 'normal',\n  overflow: 'hidden',\n  position: 'relative',\n  verticalAlign: 'top',\n  width: '100%',\n\n  svg: {\n    position: 'absolute',\n    zIndex: 1,\n    pointerEvents: 'none',\n    height: '12px',\n    marginTop: '-6px',\n    right: '12px',\n    top: '50%',\n    fill: theme.textMutedColor,\n\n    path: {\n      fill: theme.textMutedColor,\n    },\n  },\n}));\n\ntype SelectConfig = NormalizedOptionsConfig & { isMulti: boolean };\ntype SelectProps = ControlProps<OptionsSelection> & SelectConfig;\n\nconst NO_SELECTION = 'Choose option...';\n\nconst SingleSelect: FC<SelectProps> = ({ name, storyId, value, options, onChange, argType }) => {\n  const handleChange = (e: ChangeEvent<HTMLSelectElement>) => {\n    onChange(options[e.currentTarget.value]);\n  };\n  const selection = selectedKey(value, options) || NO_SELECTION;\n  const controlId = getControlId(name, storyId);\n\n  const readonly = !!argType?.table?.readonly;\n\n  return (\n    <SelectWrapper>\n      <ChevronSmallDownIcon />\n      <label htmlFor={controlId} className=\"sb-sr-only\">\n        {name}\n      </label>\n      <OptionsSelect disabled={readonly} id={controlId} value={selection} onChange={handleChange}>\n        <option disabled={selection === NO_SELECTION} key=\"no-selection\">\n          {NO_SELECTION}\n        </option>\n        {Object.keys(options).map((key) => (\n          <option key={key} value={key}>\n            {key}\n          </option>\n        ))}\n      </OptionsSelect>\n    </SelectWrapper>\n  );\n};\n\nconst MultiSelect: FC<SelectProps> = ({ name, storyId, value, options, onChange, argType }) => {\n  const handleChange = (e: ChangeEvent<HTMLSelectElement>) => {\n    const selection = Array.from(e.currentTarget.options)\n      .filter((option) => option.selected)\n      .map((option) => option.value);\n    onChange(selectedValues(selection, options));\n  };\n  const selection = selectedKeys(value, options);\n  const controlId = getControlId(name, storyId);\n\n  const readonly = !!argType?.table?.readonly;\n\n  return (\n    <SelectWrapper>\n      <label htmlFor={controlId} className=\"sb-sr-only\">\n        {name}\n      </label>\n      <OptionsSelect\n        disabled={readonly}\n        id={controlId}\n        multiple\n        value={selection}\n        onChange={handleChange}\n      >\n        {Object.keys(options).map((key) => (\n          <option key={key} value={key}>\n            {key}\n          </option>\n        ))}\n      </OptionsSelect>\n    </SelectWrapper>\n  );\n};\n\nexport const SelectControl: FC<SelectProps> = (props) => {\n  const { name, options } = props;\n  if (!options) {\n    logger.warn(`Select with no options: ${name}`);\n    return <>-</>;\n  }\n\n  // eslint-disable-next-line react/destructuring-assignment\n  return props.isMulti ? <MultiSelect {...props} /> : <SingleSelect {...props} />;\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/options/SelectOptions.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { expect, fn, userEvent } from 'storybook/test';\n\nimport { OptionsControl } from './Options';\n\nconst arrayOptions = ['Bat', 'Cat', 'Rat'];\nconst objectOptions = {\n  A: { id: 'Aardvark' },\n  B: { id: 'Bat' },\n  C: { id: 'Cat' },\n};\nconst labels = {\n  Bat: 'Batwoman',\n  Cat: 'Catwoman',\n  Rat: 'Ratwoman',\n};\nconst argTypeMultiSelect = {\n  argTypes: {\n    value: {\n      control: { type: 'multi-select' },\n      options: arrayOptions,\n    },\n  },\n} as const;\n\nconst meta = {\n  title: 'Controls/Options/Select',\n  component: OptionsControl,\n  tags: ['autodocs'],\n  parameters: {\n    withRawArg: 'value',\n    controls: { include: ['argType', 'type', 'value', 'labels'] },\n  },\n  args: {\n    name: 'select',\n    type: 'select',\n    argType: { options: arrayOptions },\n    onChange: fn(),\n  },\n  argTypes: {\n    value: {\n      control: { type: 'select' },\n      options: arrayOptions,\n    },\n  },\n} satisfies Meta<typeof OptionsControl>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Array: Story = {\n  args: {\n    value: arrayOptions[0],\n  },\n};\n\nexport const ArrayMulti: Story = {\n  args: {\n    type: 'multi-select',\n    value: [arrayOptions[1], arrayOptions[2]],\n  },\n  ...argTypeMultiSelect,\n};\n\nexport const ArrayUndefined: Story = {\n  args: {\n    value: undefined,\n  },\n};\n\nexport const ArrayResettable: Story = {\n  args: {\n    value: undefined,\n  },\n  play: async ({ canvas, args }) => {\n    const select = canvas.getByRole('combobox');\n    expect(select).toHaveValue('Choose option...');\n\n    await userEvent.click(select);\n    await userEvent.selectOptions(select, arrayOptions[2]);\n\n    expect(args.onChange).toHaveBeenCalledWith(arrayOptions[2]);\n    expect(select).toHaveValue(arrayOptions[2]);\n\n    await userEvent.click(select);\n    await userEvent.selectOptions(select, 'Choose option...');\n\n    expect(args.onChange).toHaveBeenCalledWith(undefined);\n    expect(select).toHaveValue('Choose option...');\n  },\n};\n\nexport const ArrayMultiUndefined: Story = {\n  args: {\n    type: 'multi-select',\n    value: undefined,\n  },\n  ...argTypeMultiSelect,\n};\n\nexport const ArrayLabels: Story = {\n  args: {\n    value: arrayOptions[0],\n    labels,\n  },\n};\n\nexport const ArrayMultiLabels: Story = {\n  args: {\n    type: 'multi-select',\n    value: [arrayOptions[1], arrayOptions[2]],\n    labels,\n  },\n  ...argTypeMultiSelect,\n};\n\nexport const Object: Story = {\n  name: 'DEPRECATED: Object',\n  args: {\n    value: objectOptions.B,\n    argType: { options: objectOptions },\n  },\n  argTypes: { value: { control: { type: 'object' } } },\n};\n\nexport const ObjectMulti: Story = {\n  name: 'DEPRECATED: Object Multi',\n  args: {\n    type: 'multi-select',\n    value: [objectOptions.A, objectOptions.B],\n    argType: { options: objectOptions },\n  },\n  argTypes: { value: { control: { type: 'object' } } },\n};\n\nexport const ObjectUndefined: Story = {\n  name: 'DEPRECATED: Object Undefined',\n  args: {\n    value: undefined,\n    argType: { options: objectOptions },\n  },\n  argTypes: { value: { control: { type: 'object' } } },\n};\n\nexport const ObjectMultiUndefined: Story = {\n  name: 'DEPRECATED: Object Multi Undefined',\n  args: {\n    type: 'multi-select',\n    value: undefined,\n    argType: { options: objectOptions },\n  },\n  argTypes: { value: { control: { type: 'object' } } },\n};\n\nexport const ArrayReadonly: Story = {\n  args: {\n    value: arrayOptions[0],\n    argType: {\n      options: arrayOptions,\n      table: {\n        readonly: true,\n      },\n    },\n  },\n  argTypes: {\n    value: {\n      control: { type: 'select' },\n      options: arrayOptions,\n    },\n  },\n};\n\nexport const ArrayMultiReadonly: Story = {\n  args: {\n    type: 'multi-select',\n    value: [arrayOptions[1], arrayOptions[2]],\n    argType: {\n      options: arrayOptions,\n      table: {\n        readonly: true,\n      },\n    },\n  },\n  ...argTypeMultiSelect,\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/options/helpers.ts",
    "content": "import type { OptionsObject } from '../types';\n\nexport const selectedKey = (value: any, options: OptionsObject) => {\n  const entry = options && Object.entries(options).find(([_key, val]) => val === value);\n  return entry ? entry[0] : undefined;\n};\n\nexport const selectedKeys = (value: any[], options: OptionsObject) =>\n  value && options\n    ? Object.entries(options)\n        .filter((entry) => value.includes(entry[1]))\n        .map((entry) => entry[0])\n    : [];\n\nexport const selectedValues = (keys: string[], options: OptionsObject) =>\n  keys && options && keys.map((key) => options[key]);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/options/index.ts",
    "content": "export * from './Options';\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodeAccordion.tsx",
    "content": "import type { ComponentPropsWithoutRef } from 'react';\nimport React from 'react';\n\nimport { styled } from 'storybook/theming';\n\nconst Container = styled.div(({ theme }) => ({\n  position: 'relative',\n  ':hover': {\n    '& > .rejt-accordion-button::after': {\n      background: theme.color.secondary,\n    },\n    '& > .rejt-accordion-region > :is(.rejt-plus-menu, .rejt-minus-menu)': {\n      opacity: 1,\n    },\n  },\n}));\n\nconst Trigger = styled.button(({ theme }) => ({\n  padding: 0,\n  background: 'transparent',\n  border: 'none',\n  marginRight: '3px',\n  lineHeight: '22px',\n  color: theme.color.secondary,\n  '::after': {\n    content: '\"\"',\n    position: 'absolute',\n    top: 0,\n    display: 'block',\n    width: '100%',\n    marginLeft: '-1rem',\n    height: '22px',\n    background: 'transparent',\n    borderRadius: 4,\n    transition: 'background 0.2s',\n    opacity: 0.1,\n    paddingRight: '20px',\n  },\n  '::before': {\n    content: '\"\"',\n    position: 'absolute',\n  },\n  '&[aria-expanded=\"true\"]::before': {\n    left: -10,\n    top: 10,\n    borderTop: '3px solid rgba(153,153,153,0.6)',\n    borderLeft: '3px solid transparent',\n    borderRight: '3px solid transparent',\n  },\n  '&[aria-expanded=\"false\"]::before': {\n    left: -8,\n    top: 8,\n    borderTop: '3px solid transparent',\n    borderBottom: '3px solid transparent',\n    borderLeft: '3px solid rgba(153,153,153,0.6)',\n  },\n}));\n\nconst Region = styled.div({\n  display: 'inline',\n});\n\ntype AccordionProps = {\n  name: string;\n  keyPath: string[];\n  collapsed: boolean;\n  deep: number;\n} & ComponentPropsWithoutRef<'button'>;\n\nexport function JsonNodeAccordion({\n  children,\n  name,\n  collapsed,\n  keyPath,\n  deep,\n  ...props\n}: AccordionProps) {\n  const parentPropertyName = keyPath.at(-1) ?? 'root';\n\n  const accordionKey = `${parentPropertyName}-${name}-${deep}`;\n\n  const ids = {\n    trigger: `${accordionKey}-trigger`,\n    region: `${accordionKey}-region`,\n  };\n\n  const containerTag = keyPath.length > 0 ? 'li' : 'div';\n\n  return (\n    <Container as={containerTag}>\n      <Trigger\n        type=\"button\"\n        aria-expanded={!collapsed}\n        id={ids.trigger}\n        aria-controls={ids.region}\n        className=\"rejt-accordion-button\"\n        {...props}\n      >\n        {name} :\n      </Trigger>\n      <Region\n        role=\"group\"\n        id={ids.region}\n        aria-labelledby={ids.trigger}\n        className=\"rejt-accordion-region\"\n      >\n        {children}\n      </Region>\n    </Container>\n  );\n}\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.stories.tsx",
    "content": "import React from 'react';\n\nconst meta = {\n  title: 'Controls/JsonNodes',\n  tags: ['autodocs'],\n  argTypes: {\n    value: { control: { type: 'object' } },\n    function: { control: { type: 'object' } },\n  },\n  args: {\n    value: { any: 'value' },\n    function: { value: () => {} },\n  },\n  parameters: {\n    // This story exists only to verify proper behavior on its docs page, the snapshot is irrelevant\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport default meta;\n\nexport const JsonNodes = {\n  render: () => (\n    <a href=\"https://www.google.com/\" target=\"_blank\" rel=\"noreferrer\">\n      Confirm the link works by pressing enter key\n    </a>\n  ),\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/react-editable-json-tree/JsonNodes.tsx",
    "content": "/* eslint-disable react/no-direct-mutation-state */\nimport type { ReactElement } from 'react';\nimport React, { Component, cloneElement } from 'react';\n\nimport { JsonNodeAccordion } from './JsonNodeAccordion';\nimport * as dataTypes from './types/dataTypes';\nimport * as deltaTypes from './types/deltaTypes';\nimport * as inputUsageTypes from './types/inputUsageTypes';\nimport { getObjectType, isComponentWillChange } from './utils/objectTypes';\n\ninterface JsonAddValueState {\n  inputRefKey: any;\n  inputRefValue: any;\n}\n\nexport class JsonAddValue extends Component<JsonAddValueProps, JsonAddValueState> {\n  constructor(props: JsonAddValueProps) {\n    super(props);\n    this.state = {\n      inputRefKey: null,\n      inputRefValue: null,\n    };\n    // Bind\n    this.refInputValue = this.refInputValue.bind(this);\n    this.refInputKey = this.refInputKey.bind(this);\n    this.onKeydown = this.onKeydown.bind(this);\n    this.onSubmit = this.onSubmit.bind(this);\n  }\n\n  componentDidMount() {\n    const { inputRefKey, inputRefValue } = this.state;\n    const { onlyValue } = this.props;\n\n    if (inputRefKey && typeof inputRefKey.focus === 'function') {\n      inputRefKey.focus();\n    }\n\n    if (onlyValue && inputRefValue && typeof inputRefValue.focus === 'function') {\n      inputRefValue.focus();\n    }\n  }\n\n  onKeydown(event: KeyboardEvent) {\n    if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey || event.repeat) {\n      return;\n    }\n    const { inputRefKey, inputRefValue } = this.state;\n    const { addButtonElement, handleCancel } = this.props;\n    const isFormFocused = [inputRefKey, inputRefValue, addButtonElement].some(\n      (elm) => elm === event.target\n    );\n    if (!isFormFocused) {\n      return;\n    }\n    if (event.code === 'Enter' || event.key === 'Enter') {\n      event.preventDefault();\n      this.onSubmit();\n    }\n    if (event.code === 'Escape' || event.key === 'Escape') {\n      event.preventDefault();\n      handleCancel();\n    }\n  }\n\n  onSubmit() {\n    const { handleAdd, onlyValue, onSubmitValueParser, keyPath, deep } = this.props;\n    const { inputRefKey, inputRefValue } = this.state;\n    const result: any = {};\n    // Check if we have the key\n    if (!onlyValue) {\n      // Check that there is a key\n      if (!inputRefKey.value) {\n        // Empty key => Not authorized\n        return;\n      }\n\n      result.key = inputRefKey.value;\n    }\n    result.newValue = onSubmitValueParser(false, keyPath, deep, result.key, inputRefValue.value);\n    handleAdd(result);\n  }\n\n  refInputKey(node: any) {\n    // @ts-expect-error (Converted from ts-ignore)\n    this.state.inputRefKey = node;\n  }\n\n  refInputValue(node: any) {\n    // @ts-expect-error (Converted from ts-ignore)\n    this.state.inputRefValue = node;\n  }\n\n  render() {\n    const {\n      handleCancel,\n      onlyValue,\n      addButtonElement,\n      cancelButtonElement,\n      inputElementGenerator,\n      keyPath,\n      deep,\n    } = this.props;\n    const addButtonElementLayout =\n      addButtonElement &&\n      cloneElement(addButtonElement, {\n        onClick: this.onSubmit,\n      });\n    const cancelButtonElementLayout =\n      cancelButtonElement &&\n      cloneElement(cancelButtonElement, {\n        onClick: handleCancel,\n      });\n    const inputElementValue = inputElementGenerator(inputUsageTypes.VALUE, keyPath, deep);\n    const inputElementValueLayout = cloneElement(inputElementValue, {\n      placeholder: 'Value',\n      ref: this.refInputValue,\n      onKeyDown: this.onKeydown,\n    });\n    let inputElementKeyLayout = null;\n\n    if (!onlyValue) {\n      const inputElementKey = inputElementGenerator(inputUsageTypes.KEY, keyPath, deep);\n      inputElementKeyLayout = cloneElement(inputElementKey, {\n        placeholder: 'Key',\n        ref: this.refInputKey,\n        onKeyDown: this.onKeydown,\n      });\n    }\n\n    return (\n      <span className=\"rejt-add-value-node\">\n        {inputElementKeyLayout}\n        {inputElementValueLayout}\n        {addButtonElementLayout}\n        {cancelButtonElementLayout}\n      </span>\n    );\n  }\n}\n\ninterface JsonAddValueProps {\n  handleAdd: (...args: any) => any;\n  handleCancel: (...args: any) => any;\n  onlyValue?: boolean;\n  addButtonElement?: ReactElement;\n  cancelButtonElement?: ReactElement;\n  inputElementGenerator: (...args: any) => any;\n  keyPath?: string[];\n  deep?: number;\n  onSubmitValueParser: (...args: any) => any;\n}\n\n// @ts-expect-error (Converted from ts-ignore)\nJsonAddValue.defaultProps = {\n  onlyValue: false,\n  addButtonElement: <button>+</button>,\n  cancelButtonElement: <button>c</button>,\n};\n\ninterface JsonArrayState {\n  data: JsonArrayProps['data'];\n  name: JsonArrayProps['name'];\n  keyPath: Exclude<JsonArrayProps['keyPath'], undefined>;\n  deep: Exclude<JsonArrayProps['deep'], undefined>;\n  nextDeep: JsonArrayProps['deep'];\n  collapsed: any;\n  addFormVisible: boolean;\n}\nexport class JsonArray extends Component<JsonArrayProps, JsonArrayState> {\n  constructor(props: JsonArrayProps) {\n    super(props);\n    const keyPath = [...(props.keyPath || []), props.name];\n    this.state = {\n      data: props.data,\n      name: props.name,\n      keyPath: keyPath ?? [],\n      deep: props.deep ?? 0,\n      nextDeep: (props.deep ?? 0) + 1,\n      collapsed: props.isCollapsed(keyPath, props.deep ?? 0, props.data),\n      addFormVisible: false,\n    };\n\n    // Bind\n    this.handleCollapseMode = this.handleCollapseMode.bind(this);\n    this.handleRemoveItem = this.handleRemoveItem.bind(this);\n    this.handleAddMode = this.handleAddMode.bind(this);\n    this.handleAddValueAdd = this.handleAddValueAdd.bind(this);\n    this.handleAddValueCancel = this.handleAddValueCancel.bind(this);\n    this.handleEditValue = this.handleEditValue.bind(this);\n    this.onChildUpdate = this.onChildUpdate.bind(this);\n    this.renderCollapsed = this.renderCollapsed.bind(this);\n    this.renderNotCollapsed = this.renderNotCollapsed.bind(this);\n  }\n\n  static getDerivedStateFromProps(props: JsonArrayProps, state: JsonArrayState) {\n    return props.data !== state.data ? { data: props.data } : null;\n  }\n\n  onChildUpdate(childKey: string, childData: any) {\n    const { data, keyPath = [] } = this.state;\n    // Update data\n    (data as Record<string, any>)[childKey] = childData;\n    // Put new data\n    this.setState({\n      data,\n    });\n    // Spread\n    const { onUpdate } = this.props;\n    const size = keyPath.length;\n    onUpdate(keyPath[size - 1], data);\n  }\n\n  handleAddMode() {\n    this.setState({\n      addFormVisible: true,\n    });\n  }\n\n  handleCollapseMode() {\n    this.setState((state) => ({\n      collapsed: !state.collapsed,\n    }));\n  }\n\n  handleRemoveItem(index: number) {\n    return () => {\n      const { beforeRemoveAction, logger } = this.props;\n      const { data, keyPath, nextDeep: deep } = this.state;\n      const oldValue = data[index];\n\n      // Before Remove Action\n      (beforeRemoveAction || Promise.resolve.bind(Promise))(index, keyPath, deep, oldValue)\n        .then(() => {\n          const deltaUpdateResult = {\n            keyPath,\n            deep,\n            key: index,\n            oldValue,\n            type: deltaTypes.REMOVE_DELTA_TYPE,\n          };\n\n          data.splice(index, 1);\n          this.setState({ data });\n\n          // Spread new update\n          const { onUpdate, onDeltaUpdate } = this.props;\n          onUpdate(keyPath[keyPath.length - 1], data);\n          // Spread delta update\n          onDeltaUpdate(deltaUpdateResult);\n        })\n        .catch(logger.error);\n    };\n  }\n\n  handleAddValueAdd({ newValue }: any) {\n    const { data, keyPath = [], nextDeep: deep } = this.state;\n    const { beforeAddAction, logger } = this.props;\n    const key = data.length;\n\n    (beforeAddAction || Promise.resolve.bind(Promise))(key, keyPath, deep, newValue)\n      .then(() => {\n        // Update data\n        data[key] = newValue;\n        this.setState({\n          data,\n        });\n        // Cancel add to close\n        this.handleAddValueCancel();\n        // Spread new update\n        const { onUpdate, onDeltaUpdate } = this.props;\n        onUpdate(keyPath[keyPath.length - 1], data);\n        // Spread delta update\n        onDeltaUpdate({\n          type: deltaTypes.ADD_DELTA_TYPE,\n          keyPath,\n          deep,\n          key,\n          newValue,\n        });\n      })\n      .catch(logger.error);\n  }\n\n  handleAddValueCancel() {\n    this.setState({\n      addFormVisible: false,\n    });\n  }\n\n  handleEditValue({ key, value }: any) {\n    return new Promise((resolve, reject) => {\n      const { beforeUpdateAction } = this.props;\n      const { data, keyPath, nextDeep: deep } = this.state;\n\n      // Old value\n      const oldValue = data[key];\n\n      // Before update action\n      (beforeUpdateAction || Promise.resolve.bind(Promise))(key, keyPath, deep, oldValue, value)\n        .then(() => {\n          // Update value\n          data[key] = value;\n          // Set state\n          this.setState({\n            data,\n          });\n          // Spread new update\n          const { onUpdate, onDeltaUpdate } = this.props;\n          onUpdate(keyPath[keyPath.length - 1], data);\n          // Spread delta update\n          onDeltaUpdate({\n            type: deltaTypes.UPDATE_DELTA_TYPE,\n            keyPath,\n            deep,\n            key,\n            newValue: value,\n            oldValue,\n          });\n          // Resolve\n          resolve(undefined);\n        })\n        .catch(reject);\n    });\n  }\n\n  renderCollapsed() {\n    const { name, data, keyPath, deep } = this.state;\n    const { handleRemove, readOnly, dataType, minusMenuElement } = this.props;\n\n    const isReadOnly = readOnly(name, data, keyPath, deep, dataType);\n\n    const removeItemButton =\n      minusMenuElement &&\n      cloneElement(minusMenuElement, {\n        onClick: handleRemove,\n        className: 'rejt-minus-menu',\n        'aria-label': `remove the array '${String(name)}'`,\n      });\n\n    return (\n      <>\n        <span className=\"rejt-collapsed-value\">\n          [...] {data.length} {data.length === 1 ? 'item' : 'items'}\n        </span>\n        {!isReadOnly && removeItemButton}\n      </>\n    );\n  }\n\n  renderNotCollapsed() {\n    const { name, data, keyPath, deep, addFormVisible, nextDeep } = this.state;\n    const {\n      isCollapsed,\n      handleRemove,\n      onDeltaUpdate,\n      readOnly,\n      dataType,\n      addButtonElement,\n      cancelButtonElement,\n      inputElementGenerator,\n      textareaElementGenerator,\n      minusMenuElement,\n      plusMenuElement,\n      beforeRemoveAction,\n      beforeAddAction,\n      beforeUpdateAction,\n      logger,\n      onSubmitValueParser,\n    } = this.props;\n\n    const isReadOnly = readOnly(name, data, keyPath, deep, dataType);\n\n    const addItemButton =\n      plusMenuElement &&\n      cloneElement(plusMenuElement, {\n        onClick: this.handleAddMode,\n        className: 'rejt-plus-menu',\n        'aria-label': `add a new item to the '${String(name)}' array`,\n      });\n    const removeItemButton =\n      minusMenuElement &&\n      cloneElement(minusMenuElement, {\n        onClick: handleRemove,\n        className: 'rejt-minus-menu',\n        'aria-label': `remove the array '${String(name)}'`,\n      });\n\n    const onlyValue = true;\n    const startObject = '[';\n    const endObject = ']';\n    return (\n      <>\n        <span className=\"rejt-not-collapsed-delimiter\">{startObject}</span>\n        {!addFormVisible && addItemButton}\n        <ul className=\"rejt-not-collapsed-list\">\n          {data.map((item, index) => (\n            <JsonNode\n              key={index}\n              name={index.toString()}\n              data={item}\n              keyPath={keyPath}\n              deep={nextDeep}\n              isCollapsed={isCollapsed}\n              handleRemove={this.handleRemoveItem(index)}\n              handleUpdateValue={this.handleEditValue}\n              onUpdate={this.onChildUpdate}\n              onDeltaUpdate={onDeltaUpdate}\n              readOnly={readOnly}\n              addButtonElement={addButtonElement}\n              cancelButtonElement={cancelButtonElement}\n              inputElementGenerator={inputElementGenerator}\n              textareaElementGenerator={textareaElementGenerator}\n              minusMenuElement={minusMenuElement}\n              plusMenuElement={plusMenuElement}\n              beforeRemoveAction={beforeRemoveAction}\n              beforeAddAction={beforeAddAction}\n              beforeUpdateAction={beforeUpdateAction}\n              logger={logger}\n              onSubmitValueParser={onSubmitValueParser}\n            />\n          ))}\n        </ul>\n        {!isReadOnly && addFormVisible && (\n          <div className=\"rejt-add-form\">\n            <JsonAddValue\n              handleAdd={this.handleAddValueAdd}\n              handleCancel={this.handleAddValueCancel}\n              onlyValue={onlyValue}\n              addButtonElement={addButtonElement}\n              cancelButtonElement={cancelButtonElement}\n              inputElementGenerator={inputElementGenerator}\n              keyPath={keyPath}\n              deep={deep}\n              onSubmitValueParser={onSubmitValueParser}\n            />\n          </div>\n        )}\n        <span className=\"rejt-not-collapsed-delimiter\">{endObject}</span>\n        {!isReadOnly && removeItemButton}\n      </>\n    );\n  }\n\n  render() {\n    const { name, collapsed, keyPath, deep } = this.state;\n    const value = collapsed ? this.renderCollapsed() : this.renderNotCollapsed();\n\n    return (\n      <JsonNodeAccordion\n        name={name}\n        collapsed={collapsed}\n        deep={deep}\n        keyPath={keyPath}\n        onClick={this.handleCollapseMode}\n      >\n        {value}\n      </JsonNodeAccordion>\n    );\n  }\n}\n\ninterface JsonArrayProps {\n  data: any[];\n  name: string;\n  isCollapsed: (...args: any) => any;\n  keyPath?: string[];\n  deep?: number;\n  handleRemove?: (...args: any) => any;\n  onUpdate: (...args: any) => any;\n  onDeltaUpdate: (...args: any) => any;\n  readOnly: (...args: any) => any;\n  dataType?: string;\n  addButtonElement?: ReactElement;\n  cancelButtonElement?: ReactElement;\n  inputElementGenerator: (...args: any) => any;\n  textareaElementGenerator: (...args: any) => any;\n  minusMenuElement?: ReactElement;\n  plusMenuElement?: ReactElement;\n  beforeRemoveAction?: (...args: any) => any;\n  beforeAddAction?: (...args: any) => any;\n  beforeUpdateAction?: (...args: any) => any;\n  logger: any;\n  onSubmitValueParser: (...args: any) => any;\n}\n\n// @ts-expect-error (Converted from ts-ignore)\nJsonArray.defaultProps = {\n  keyPath: [],\n  deep: 0,\n  minusMenuElement: <span> - </span>,\n  plusMenuElement: <span> + </span>,\n};\n\ninterface JsonFunctionValueState {\n  value: JsonFunctionValueProps['value'];\n  name: JsonFunctionValueProps['name'];\n  keyPath: Exclude<JsonFunctionValueProps['keyPath'], undefined>;\n  deep: Exclude<JsonFunctionValueProps['deep'], undefined>;\n  editEnabled: boolean;\n  inputRef: any;\n}\n\nexport class JsonFunctionValue extends Component<JsonFunctionValueProps, JsonFunctionValueState> {\n  constructor(props: JsonFunctionValueProps) {\n    super(props);\n    const keyPath = [...(props.keyPath || []), props.name];\n    this.state = {\n      value: props.value,\n      name: props.name,\n      keyPath: keyPath ?? [],\n      deep: props.deep ?? 0,\n      editEnabled: false,\n      inputRef: null,\n    };\n\n    // Bind\n    this.handleEditMode = this.handleEditMode.bind(this);\n    this.refInput = this.refInput.bind(this);\n    this.handleCancelEdit = this.handleCancelEdit.bind(this);\n    this.handleEdit = this.handleEdit.bind(this);\n    this.onKeydown = this.onKeydown.bind(this);\n  }\n\n  static getDerivedStateFromProps(props: JsonFunctionValueProps, state: JsonFunctionValueState) {\n    return props.value !== state.value ? { value: props.value } : null;\n  }\n\n  componentDidUpdate() {\n    const { editEnabled, inputRef, name, value, keyPath, deep } = this.state;\n    const { readOnly, dataType } = this.props;\n    const readOnlyResult = readOnly(name, value, keyPath, deep, dataType);\n\n    if (editEnabled && !readOnlyResult && typeof inputRef.focus === 'function') {\n      inputRef.focus();\n    }\n  }\n\n  onKeydown(event: KeyboardEvent) {\n    const { inputRef } = this.state;\n    if (\n      event.altKey ||\n      event.ctrlKey ||\n      event.metaKey ||\n      event.shiftKey ||\n      event.repeat ||\n      inputRef !== event.target\n    ) {\n      return;\n    }\n    if (event.code === 'Enter' || event.key === 'Enter') {\n      event.preventDefault();\n      this.handleEdit();\n    }\n    if (event.code === 'Escape' || event.key === 'Escape') {\n      event.preventDefault();\n      this.handleCancelEdit();\n    }\n  }\n\n  handleEdit() {\n    const { handleUpdateValue, originalValue, logger, onSubmitValueParser, keyPath } = this.props;\n    const { inputRef, name, deep } = this.state;\n\n    if (!inputRef) {\n      return;\n    }\n\n    const newValue = onSubmitValueParser(true, keyPath, deep, name, inputRef.value);\n\n    const result = {\n      value: newValue,\n      key: name,\n    };\n\n    // Run update\n    (handleUpdateValue || Promise.resolve.bind(Promise))(result)\n      .then(() => {\n        // Cancel edit mode if necessary\n        if (!isComponentWillChange(originalValue, newValue)) {\n          this.handleCancelEdit();\n        }\n      })\n      .catch(logger.error);\n  }\n\n  handleEditMode() {\n    this.setState({\n      editEnabled: true,\n    });\n  }\n\n  refInput(node: any) {\n    // @ts-expect-error (Converted from ts-ignore)\n    this.state.inputRef = node;\n  }\n\n  handleCancelEdit() {\n    this.setState({\n      editEnabled: false,\n    });\n  }\n\n  render() {\n    const { name, value, editEnabled, keyPath, deep } = this.state;\n    const {\n      handleRemove,\n      originalValue,\n      readOnly,\n      dataType,\n      textareaElementGenerator,\n      minusMenuElement,\n      keyPath: comeFromKeyPath = [],\n    } = this.props;\n\n    let result = null;\n    let minusElement = null;\n    const resultOnlyResult = readOnly(name, originalValue, keyPath, deep, dataType);\n\n    if (editEnabled && !resultOnlyResult) {\n      const textareaElement = textareaElementGenerator(\n        inputUsageTypes.VALUE,\n        comeFromKeyPath,\n        deep,\n        name,\n        originalValue,\n        dataType\n      );\n\n      const textareaElementLayout = cloneElement(textareaElement, {\n        ref: this.refInput,\n        defaultValue: value,\n        onKeyDown: this.onKeydown,\n      });\n\n      result = <span className=\"rejt-edit-form\">{textareaElementLayout}</span>;\n      minusElement = null;\n    } else {\n      result = (\n        <span className=\"rejt-value\" onClick={resultOnlyResult ? undefined : this.handleEditMode}>\n          {value}\n        </span>\n      );\n\n      const parentPropertyName = comeFromKeyPath.at(-1);\n\n      const minusMenuLayout =\n        minusMenuElement &&\n        cloneElement(minusMenuElement, {\n          onClick: handleRemove,\n          className: 'rejt-minus-menu',\n          'aria-label': `remove the function '${String(name)}'${\n            String(parentPropertyName) ? ` from '${String(parentPropertyName)}'` : ''\n          }`,\n        });\n      minusElement = resultOnlyResult ? null : minusMenuLayout;\n    }\n\n    return (\n      <li className=\"rejt-value-node\">\n        <span className=\"rejt-name\">{name} : </span>\n        {result}\n        {minusElement}\n      </li>\n    );\n  }\n}\n\ninterface JsonFunctionValueProps {\n  name: string;\n  value: any;\n  originalValue?: any;\n  keyPath?: string[];\n  deep?: number;\n  handleRemove?: (...args: any) => any;\n  handleUpdateValue?: (...args: any) => any;\n  readOnly: (...args: any) => any;\n  dataType?: string;\n  cancelButtonElement?: ReactElement;\n  textareaElementGenerator: (...args: any) => any;\n  minusMenuElement?: ReactElement;\n  logger: any;\n  onSubmitValueParser: (...args: any) => any;\n}\n\n// @ts-expect-error (Converted from ts-ignore)\nJsonFunctionValue.defaultProps = {\n  keyPath: [],\n  deep: 0,\n  handleUpdateValue: () => {},\n  cancelButtonElement: <button>c</button>,\n  minusMenuElement: <span> - </span>,\n};\n\ninterface JsonNodeState {\n  data: JsonNodeProps['data'];\n  name: JsonNodeProps['name'];\n  keyPath: Exclude<JsonNodeProps['keyPath'], undefined>;\n  deep: Exclude<JsonNodeProps['deep'], undefined>;\n}\n\nexport class JsonNode extends Component<JsonNodeProps, JsonNodeState> {\n  constructor(props: JsonNodeProps) {\n    super(props);\n    this.state = {\n      data: props.data,\n      name: props.name,\n      keyPath: props.keyPath ?? [],\n      deep: props.deep ?? 0,\n    };\n  }\n\n  static getDerivedStateFromProps(props: JsonNodeProps, state: JsonNodeState) {\n    return props.data !== state.data ? { data: props.data } : null;\n  }\n\n  render() {\n    const { data, name, keyPath, deep } = this.state;\n    const {\n      isCollapsed,\n      handleRemove,\n      handleUpdateValue,\n      onUpdate,\n      onDeltaUpdate,\n      readOnly,\n      addButtonElement,\n      cancelButtonElement,\n      inputElementGenerator,\n      textareaElementGenerator,\n      minusMenuElement,\n      plusMenuElement,\n      beforeRemoveAction,\n      beforeAddAction,\n      beforeUpdateAction,\n      logger,\n      onSubmitValueParser,\n    } = this.props;\n    const readOnlyTrue = () => true;\n\n    const dataType = getObjectType(data);\n    switch (dataType) {\n      case dataTypes.ERROR:\n        return (\n          <JsonObject\n            data={data}\n            name={name}\n            isCollapsed={isCollapsed}\n            keyPath={keyPath}\n            deep={deep}\n            handleRemove={handleRemove}\n            onUpdate={onUpdate}\n            onDeltaUpdate={onDeltaUpdate}\n            readOnly={readOnlyTrue}\n            dataType={dataType}\n            addButtonElement={addButtonElement}\n            cancelButtonElement={cancelButtonElement}\n            inputElementGenerator={inputElementGenerator}\n            textareaElementGenerator={textareaElementGenerator}\n            minusMenuElement={minusMenuElement}\n            plusMenuElement={plusMenuElement}\n            beforeRemoveAction={beforeRemoveAction}\n            beforeAddAction={beforeAddAction}\n            beforeUpdateAction={beforeUpdateAction}\n            logger={logger}\n            onSubmitValueParser={onSubmitValueParser}\n          />\n        );\n      case dataTypes.OBJECT:\n        return (\n          <JsonObject\n            data={data}\n            name={name}\n            isCollapsed={isCollapsed}\n            keyPath={keyPath}\n            deep={deep}\n            handleRemove={handleRemove}\n            onUpdate={onUpdate}\n            onDeltaUpdate={onDeltaUpdate}\n            readOnly={readOnly}\n            dataType={dataType}\n            addButtonElement={addButtonElement}\n            cancelButtonElement={cancelButtonElement}\n            inputElementGenerator={inputElementGenerator}\n            textareaElementGenerator={textareaElementGenerator}\n            minusMenuElement={minusMenuElement}\n            plusMenuElement={plusMenuElement}\n            beforeRemoveAction={beforeRemoveAction}\n            beforeAddAction={beforeAddAction}\n            beforeUpdateAction={beforeUpdateAction}\n            logger={logger}\n            onSubmitValueParser={onSubmitValueParser}\n          />\n        );\n      case dataTypes.ARRAY:\n        return (\n          <JsonArray\n            data={data}\n            name={name}\n            isCollapsed={isCollapsed}\n            keyPath={keyPath}\n            deep={deep}\n            handleRemove={handleRemove}\n            onUpdate={onUpdate}\n            onDeltaUpdate={onDeltaUpdate}\n            readOnly={readOnly}\n            dataType={dataType}\n            addButtonElement={addButtonElement}\n            cancelButtonElement={cancelButtonElement}\n            inputElementGenerator={inputElementGenerator}\n            textareaElementGenerator={textareaElementGenerator}\n            minusMenuElement={minusMenuElement}\n            plusMenuElement={plusMenuElement}\n            beforeRemoveAction={beforeRemoveAction}\n            beforeAddAction={beforeAddAction}\n            beforeUpdateAction={beforeUpdateAction}\n            logger={logger}\n            onSubmitValueParser={onSubmitValueParser}\n          />\n        );\n      case dataTypes.STRING:\n        return (\n          <JsonValue\n            name={name}\n            value={`\"${data}\"`}\n            originalValue={data}\n            keyPath={keyPath}\n            deep={deep}\n            handleRemove={handleRemove}\n            handleUpdateValue={handleUpdateValue}\n            readOnly={readOnly}\n            dataType={dataType}\n            cancelButtonElement={cancelButtonElement}\n            inputElementGenerator={inputElementGenerator}\n            minusMenuElement={minusMenuElement}\n            logger={logger}\n            onSubmitValueParser={onSubmitValueParser}\n          />\n        );\n      case dataTypes.NUMBER:\n        return (\n          <JsonValue\n            name={name}\n            value={data}\n            originalValue={data}\n            keyPath={keyPath}\n            deep={deep}\n            handleRemove={handleRemove}\n            handleUpdateValue={handleUpdateValue}\n            readOnly={readOnly}\n            dataType={dataType}\n            cancelButtonElement={cancelButtonElement}\n            inputElementGenerator={inputElementGenerator}\n            minusMenuElement={minusMenuElement}\n            logger={logger}\n            onSubmitValueParser={onSubmitValueParser}\n          />\n        );\n      case dataTypes.BOOLEAN:\n        return (\n          <JsonValue\n            name={name}\n            value={data ? 'true' : 'false'}\n            originalValue={data}\n            keyPath={keyPath}\n            deep={deep}\n            handleRemove={handleRemove}\n            handleUpdateValue={handleUpdateValue}\n            readOnly={readOnly}\n            dataType={dataType}\n            cancelButtonElement={cancelButtonElement}\n            inputElementGenerator={inputElementGenerator}\n            minusMenuElement={minusMenuElement}\n            logger={logger}\n            onSubmitValueParser={onSubmitValueParser}\n          />\n        );\n      case dataTypes.DATE:\n        return (\n          <JsonValue\n            name={name}\n            value={data.toISOString()}\n            originalValue={data}\n            keyPath={keyPath}\n            deep={deep}\n            handleRemove={handleRemove}\n            handleUpdateValue={handleUpdateValue}\n            readOnly={readOnlyTrue}\n            dataType={dataType}\n            cancelButtonElement={cancelButtonElement}\n            inputElementGenerator={inputElementGenerator}\n            minusMenuElement={minusMenuElement}\n            logger={logger}\n            onSubmitValueParser={onSubmitValueParser}\n          />\n        );\n      case dataTypes.NULL:\n        return (\n          <JsonValue\n            name={name}\n            value=\"null\"\n            originalValue=\"null\"\n            keyPath={keyPath}\n            deep={deep}\n            handleRemove={handleRemove}\n            handleUpdateValue={handleUpdateValue}\n            readOnly={readOnly}\n            dataType={dataType}\n            cancelButtonElement={cancelButtonElement}\n            inputElementGenerator={inputElementGenerator}\n            minusMenuElement={minusMenuElement}\n            logger={logger}\n            onSubmitValueParser={onSubmitValueParser}\n          />\n        );\n      case dataTypes.UNDEFINED:\n        return (\n          <JsonValue\n            name={name}\n            value=\"undefined\"\n            originalValue=\"undefined\"\n            keyPath={keyPath}\n            deep={deep}\n            handleRemove={handleRemove}\n            handleUpdateValue={handleUpdateValue}\n            readOnly={readOnly}\n            dataType={dataType}\n            cancelButtonElement={cancelButtonElement}\n            inputElementGenerator={inputElementGenerator}\n            minusMenuElement={minusMenuElement}\n            logger={logger}\n            onSubmitValueParser={onSubmitValueParser}\n          />\n        );\n      case dataTypes.FUNCTION:\n        return (\n          <JsonFunctionValue\n            name={name}\n            value={data.toString()}\n            originalValue={data}\n            keyPath={keyPath}\n            deep={deep}\n            handleRemove={handleRemove}\n            handleUpdateValue={handleUpdateValue}\n            readOnly={readOnly}\n            dataType={dataType}\n            cancelButtonElement={cancelButtonElement}\n            textareaElementGenerator={textareaElementGenerator}\n            minusMenuElement={minusMenuElement}\n            logger={logger}\n            onSubmitValueParser={onSubmitValueParser}\n          />\n        );\n      case dataTypes.SYMBOL:\n        return (\n          <JsonValue\n            name={name}\n            value={data.toString()}\n            originalValue={data}\n            keyPath={keyPath}\n            deep={deep}\n            handleRemove={handleRemove}\n            handleUpdateValue={handleUpdateValue}\n            readOnly={readOnlyTrue}\n            dataType={dataType}\n            cancelButtonElement={cancelButtonElement}\n            inputElementGenerator={inputElementGenerator}\n            minusMenuElement={minusMenuElement}\n            logger={logger}\n            onSubmitValueParser={onSubmitValueParser}\n          />\n        );\n      default:\n        return null;\n    }\n  }\n}\n\ninterface JsonNodeProps {\n  name: string;\n  data?: any;\n  isCollapsed: (...args: any) => any;\n  keyPath?: string[];\n  deep?: number;\n  handleRemove?: (...args: any) => any;\n  handleUpdateValue?: (...args: any) => any;\n  onUpdate: (...args: any) => any;\n  onDeltaUpdate: (...args: any) => any;\n  readOnly: (...args: any) => any;\n  addButtonElement?: ReactElement;\n  cancelButtonElement?: ReactElement;\n  inputElementGenerator: (...args: any) => any;\n  textareaElementGenerator: (...args: any) => any;\n  minusMenuElement?: ReactElement;\n  plusMenuElement?: ReactElement;\n  beforeRemoveAction?: (...args: any) => any;\n  beforeAddAction?: (...args: any) => any;\n  beforeUpdateAction?: (...args: any) => any;\n  logger: object;\n  onSubmitValueParser: (...args: any) => any;\n}\n\n/// @ts-expect-error (Converted from ts-ignore)\nJsonNode.defaultProps = {\n  keyPath: [],\n  deep: 0,\n};\n\ninterface JsonObjectState {\n  name: string;\n  collapsed: ReturnType<JsonObjectProps['isCollapsed']>;\n  data: JsonObjectProps['data'];\n  keyPath: Exclude<JsonObjectProps['keyPath'], undefined>;\n  deep: Exclude<JsonObjectProps['deep'], undefined>;\n  nextDeep: number;\n  addFormVisible: boolean;\n}\n\nexport class JsonObject extends Component<JsonObjectProps, JsonObjectState> {\n  constructor(props: JsonObjectProps) {\n    super(props);\n    const keyPath = props.deep === -1 ? [] : [...(props.keyPath || []), props.name];\n    this.state = {\n      name: props.name,\n      data: props.data,\n      keyPath: keyPath ?? [],\n      deep: props.deep ?? 0,\n      nextDeep: (props.deep ?? 0) + 1,\n      collapsed: props.isCollapsed(keyPath, props.deep ?? 0, props.data),\n      addFormVisible: false,\n    };\n\n    // Bind\n    this.handleCollapseMode = this.handleCollapseMode.bind(this);\n    this.handleRemoveValue = this.handleRemoveValue.bind(this);\n    this.handleAddMode = this.handleAddMode.bind(this);\n    this.handleAddValueAdd = this.handleAddValueAdd.bind(this);\n    this.handleAddValueCancel = this.handleAddValueCancel.bind(this);\n    this.handleEditValue = this.handleEditValue.bind(this);\n    this.onChildUpdate = this.onChildUpdate.bind(this);\n    this.renderCollapsed = this.renderCollapsed.bind(this);\n    this.renderNotCollapsed = this.renderNotCollapsed.bind(this);\n  }\n\n  static getDerivedStateFromProps(props: JsonObjectProps, state: JsonObjectState) {\n    return props.data !== state.data ? { data: props.data } : null;\n  }\n\n  onChildUpdate(childKey: string, childData: any) {\n    const { data, keyPath = [] } = this.state;\n    // Update data\n    (data as Record<string, any>)[childKey] = childData;\n    // Put new data\n    this.setState({\n      data,\n    });\n    // Spread\n    const { onUpdate } = this.props;\n    const size = keyPath.length;\n    onUpdate(keyPath[size - 1], data);\n  }\n\n  handleAddMode() {\n    this.setState({\n      addFormVisible: true,\n    });\n  }\n\n  handleAddValueCancel() {\n    this.setState({\n      addFormVisible: false,\n    });\n  }\n\n  handleAddValueAdd({ key, newValue }: any) {\n    const { data, keyPath = [], nextDeep: deep } = this.state;\n    const { beforeAddAction, logger } = this.props;\n\n    (beforeAddAction || Promise.resolve.bind(Promise))(key, keyPath, deep, newValue)\n      .then(() => {\n        // Update data\n        data[key] = newValue;\n        this.setState({\n          data,\n        });\n        // Cancel add to close\n        this.handleAddValueCancel();\n        // Spread new update\n        const { onUpdate, onDeltaUpdate } = this.props;\n        onUpdate(keyPath[keyPath.length - 1], data);\n        // Spread delta update\n        onDeltaUpdate({\n          type: deltaTypes.ADD_DELTA_TYPE,\n          keyPath,\n          deep,\n          key,\n          newValue,\n        });\n      })\n      .catch(logger.error);\n  }\n\n  handleRemoveValue(key: string) {\n    return () => {\n      const { beforeRemoveAction, logger } = this.props;\n      const { data, keyPath = [], nextDeep: deep } = this.state;\n      const oldValue = data[key];\n      // Before Remove Action\n      (beforeRemoveAction || Promise.resolve.bind(Promise))(key, keyPath, deep, oldValue)\n        .then(() => {\n          const deltaUpdateResult = {\n            keyPath,\n            deep,\n            key,\n            oldValue,\n            type: deltaTypes.REMOVE_DELTA_TYPE,\n          };\n\n          delete data[key];\n          this.setState({ data });\n\n          // Spread new update\n          const { onUpdate, onDeltaUpdate } = this.props;\n          onUpdate(keyPath[keyPath.length - 1], data);\n          // Spread delta update\n          onDeltaUpdate(deltaUpdateResult);\n        })\n        .catch(logger.error);\n    };\n  }\n\n  handleCollapseMode() {\n    this.setState((state) => ({\n      collapsed: !state.collapsed,\n    }));\n  }\n\n  handleEditValue({ key, value }: any) {\n    return new Promise<void>((resolve, reject) => {\n      const { beforeUpdateAction } = this.props;\n      const { data, keyPath = [], nextDeep: deep } = this.state;\n\n      // Old value\n      const oldValue = data[key];\n\n      // Before update action\n      (beforeUpdateAction || Promise.resolve.bind(Promise))(key, keyPath, deep, oldValue, value)\n        .then(() => {\n          // Update value\n          data[key] = value;\n          // Set state\n          this.setState({\n            data,\n          });\n          // Spread new update\n          const { onUpdate, onDeltaUpdate } = this.props;\n          onUpdate(keyPath[keyPath.length - 1], data);\n          // Spread delta update\n          onDeltaUpdate({\n            type: deltaTypes.UPDATE_DELTA_TYPE,\n            keyPath,\n            deep,\n            key,\n            newValue: value,\n            oldValue,\n          });\n          // Resolve\n          resolve();\n        })\n        .catch(reject);\n    });\n  }\n\n  renderCollapsed() {\n    const { name, keyPath, deep, data } = this.state;\n    const { handleRemove, readOnly, dataType, minusMenuElement } = this.props;\n\n    const keyList = Object.getOwnPropertyNames(data);\n\n    const isReadOnly = readOnly(name, data, keyPath, deep, dataType);\n\n    const removeItemButton =\n      minusMenuElement &&\n      cloneElement(minusMenuElement, {\n        onClick: handleRemove,\n        className: 'rejt-minus-menu',\n        'aria-label': `remove the object '${String(name)}'`,\n      });\n\n    return (\n      <>\n        <span className=\"rejt-collapsed-value\">\n          {'{...}'} {keyList.length} {keyList.length === 1 ? 'key' : 'keys'}\n        </span>\n        {!isReadOnly && removeItemButton}\n      </>\n    );\n  }\n\n  renderNotCollapsed() {\n    const { name, data, keyPath, deep, nextDeep, addFormVisible } = this.state;\n    const {\n      isCollapsed,\n      handleRemove,\n      onDeltaUpdate,\n      readOnly,\n      dataType,\n      addButtonElement,\n      cancelButtonElement,\n      inputElementGenerator,\n      textareaElementGenerator,\n      minusMenuElement,\n      plusMenuElement,\n      beforeRemoveAction,\n      beforeAddAction,\n      beforeUpdateAction,\n      logger,\n      onSubmitValueParser,\n    } = this.props;\n\n    const keyList = Object.getOwnPropertyNames(data);\n\n    const isReadOnly = readOnly(name, data, keyPath, deep, dataType);\n\n    const addItemButton =\n      plusMenuElement &&\n      cloneElement(plusMenuElement, {\n        onClick: this.handleAddMode,\n        className: 'rejt-plus-menu',\n        'aria-label': `add a new property to the object '${String(name)}'`,\n      });\n    const removeItemButton =\n      minusMenuElement &&\n      cloneElement(minusMenuElement, {\n        onClick: handleRemove,\n        className: 'rejt-minus-menu',\n        'aria-label': `remove the object '${String(name)}'`,\n      });\n\n    const list = keyList.map((key) => (\n      <JsonNode\n        key={key}\n        name={key}\n        data={data[key]}\n        keyPath={keyPath}\n        deep={nextDeep}\n        isCollapsed={isCollapsed}\n        handleRemove={this.handleRemoveValue(key)}\n        handleUpdateValue={this.handleEditValue}\n        onUpdate={this.onChildUpdate}\n        onDeltaUpdate={onDeltaUpdate}\n        readOnly={readOnly}\n        addButtonElement={addButtonElement}\n        cancelButtonElement={cancelButtonElement}\n        inputElementGenerator={inputElementGenerator}\n        textareaElementGenerator={textareaElementGenerator}\n        minusMenuElement={minusMenuElement}\n        plusMenuElement={plusMenuElement}\n        beforeRemoveAction={beforeRemoveAction}\n        beforeAddAction={beforeAddAction}\n        beforeUpdateAction={beforeUpdateAction}\n        logger={logger}\n        onSubmitValueParser={onSubmitValueParser}\n      />\n    ));\n\n    const startObject = '{';\n    const endObject = '}';\n\n    return (\n      <>\n        <span className=\"rejt-not-collapsed-delimiter\">{startObject}</span>\n        {!isReadOnly && addItemButton}\n        <ul className=\"rejt-not-collapsed-list\">{list}</ul>\n        {!isReadOnly && addFormVisible && (\n          <div className=\"rejt-add-form\">\n            <JsonAddValue\n              handleAdd={this.handleAddValueAdd}\n              handleCancel={this.handleAddValueCancel}\n              addButtonElement={addButtonElement}\n              cancelButtonElement={cancelButtonElement}\n              inputElementGenerator={inputElementGenerator}\n              keyPath={keyPath}\n              deep={deep}\n              onSubmitValueParser={onSubmitValueParser}\n            />\n          </div>\n        )}\n        <span className=\"rejt-not-collapsed-delimiter\">{endObject}</span>\n        {!isReadOnly && removeItemButton}\n      </>\n    );\n  }\n\n  render() {\n    const { name, collapsed, keyPath, deep = 0 } = this.state;\n    const value = collapsed ? this.renderCollapsed() : this.renderNotCollapsed();\n\n    return (\n      <JsonNodeAccordion\n        name={name}\n        collapsed={collapsed}\n        deep={deep}\n        keyPath={keyPath}\n        onClick={this.handleCollapseMode}\n      >\n        {value}\n      </JsonNodeAccordion>\n    );\n  }\n}\n\ninterface JsonObjectProps {\n  data: Record<string, any>;\n  name: string;\n  isCollapsed: (...args: any) => any;\n  keyPath?: string[];\n  deep?: number;\n  handleRemove?: (...args: any) => any;\n  onUpdate: (...args: any) => any;\n  onDeltaUpdate: (...args: any) => any;\n  readOnly: (...args: any) => any;\n  dataType?: string;\n  addButtonElement?: ReactElement;\n  cancelButtonElement?: ReactElement;\n  inputElementGenerator: (...args: any) => any;\n  textareaElementGenerator: (...args: any) => any;\n  minusMenuElement?: ReactElement;\n  plusMenuElement?: ReactElement;\n  beforeRemoveAction?: (...args: any) => any;\n  beforeAddAction?: (...args: any) => any;\n  beforeUpdateAction?: (...args: any) => any;\n  logger: any;\n  onSubmitValueParser: (...args: any) => any;\n}\n\n// @ts-expect-error (Converted from ts-ignore)\nJsonObject.defaultProps = {\n  keyPath: [],\n  deep: 0,\n  minusMenuElement: <span> - </span>,\n  plusMenuElement: <span> + </span>,\n};\n\ninterface JsonValueState {\n  value: JsonValueProps['value'];\n  name: JsonValueProps['name'];\n  keyPath: Exclude<JsonValueProps['keyPath'], undefined>;\n  deep: Exclude<JsonValueProps['deep'], undefined>;\n  editEnabled: boolean;\n  inputRef: any;\n}\n\nexport class JsonValue extends Component<JsonValueProps, JsonValueState> {\n  constructor(props: JsonValueProps) {\n    super(props);\n    const keyPath = [...(props.keyPath || []), props.name];\n    this.state = {\n      value: props.value,\n      name: props.name,\n      keyPath: keyPath ?? [],\n      deep: props.deep ?? 0,\n      editEnabled: false,\n      inputRef: null,\n    };\n\n    // Bind\n    this.handleEditMode = this.handleEditMode.bind(this);\n    this.refInput = this.refInput.bind(this);\n    this.handleCancelEdit = this.handleCancelEdit.bind(this);\n    this.handleEdit = this.handleEdit.bind(this);\n    this.onKeydown = this.onKeydown.bind(this);\n  }\n\n  static getDerivedStateFromProps(props: JsonValueProps, state: JsonValueState) {\n    return props.value !== state.value ? { value: props.value } : null;\n  }\n\n  componentDidUpdate() {\n    const { editEnabled, inputRef, name, value, keyPath, deep } = this.state;\n    const { readOnly, dataType } = this.props;\n    const isReadOnly = readOnly(name, value, keyPath, deep, dataType);\n\n    if (editEnabled && !isReadOnly && typeof inputRef.focus === 'function') {\n      inputRef.focus();\n    }\n  }\n\n  onKeydown(event: KeyboardEvent) {\n    const { inputRef } = this.state;\n    if (\n      event.altKey ||\n      event.ctrlKey ||\n      event.metaKey ||\n      event.shiftKey ||\n      event.repeat ||\n      inputRef !== event.target\n    ) {\n      return;\n    }\n    if (event.code === 'Enter' || event.key === 'Enter') {\n      event.preventDefault();\n      this.handleEdit();\n    }\n    if (event.code === 'Escape' || event.key === 'Escape') {\n      event.preventDefault();\n      this.handleCancelEdit();\n    }\n  }\n\n  handleEdit() {\n    const { handleUpdateValue, originalValue, logger, onSubmitValueParser, keyPath } = this.props;\n    const { inputRef, name, deep } = this.state;\n\n    if (!inputRef) {\n      return;\n    }\n\n    const newValue = onSubmitValueParser(true, keyPath, deep, name, inputRef.value);\n\n    const result = {\n      value: newValue,\n      key: name,\n    };\n\n    // Run update\n    (handleUpdateValue || Promise.resolve.bind(Promise))(result)\n      .then(() => {\n        // Cancel edit mode if necessary\n        if (!isComponentWillChange(originalValue, newValue)) {\n          this.handleCancelEdit();\n        }\n      })\n      .catch(logger.error);\n  }\n\n  handleEditMode() {\n    this.setState({\n      editEnabled: true,\n    });\n  }\n\n  refInput(node: any) {\n    // @ts-expect-error (Converted from ts-ignore)\n    this.state.inputRef = node;\n  }\n\n  handleCancelEdit() {\n    this.setState({\n      editEnabled: false,\n    });\n  }\n\n  render() {\n    const { name, value, editEnabled, keyPath, deep } = this.state;\n    const {\n      handleRemove,\n      originalValue,\n      readOnly,\n      dataType,\n      inputElementGenerator,\n      minusMenuElement,\n      keyPath: comeFromKeyPath,\n    } = this.props;\n\n    const isReadOnly = readOnly(name, originalValue, keyPath, deep, dataType);\n    const isEditing = editEnabled && !isReadOnly;\n    const inputElement = inputElementGenerator(\n      inputUsageTypes.VALUE,\n      comeFromKeyPath,\n      deep,\n      name,\n      originalValue,\n      dataType\n    );\n\n    const inputElementLayout = cloneElement(inputElement, {\n      ref: this.refInput,\n      defaultValue: JSON.stringify(originalValue),\n      onKeyDown: this.onKeydown,\n    });\n\n    const parentPropertyName = keyPath.at(-2);\n\n    const minusMenuLayout =\n      minusMenuElement &&\n      cloneElement(minusMenuElement, {\n        onClick: handleRemove,\n        className: 'rejt-minus-menu',\n        'aria-label': `remove the property '${String(name)}' with value '${String(originalValue)}'${\n          String(parentPropertyName) ? ` from '${String(parentPropertyName)}'` : ''\n        }`,\n      });\n\n    return (\n      <li className=\"rejt-value-node\">\n        <span className=\"rejt-name\">\n          {name}\n          {' : '}\n        </span>\n        {isEditing ? (\n          <span className=\"rejt-edit-form\">{inputElementLayout}</span>\n        ) : (\n          <span className=\"rejt-value\" onClick={isReadOnly ? undefined : this.handleEditMode}>\n            {String(value)}\n          </span>\n        )}\n        {!isReadOnly && !isEditing && minusMenuLayout}\n      </li>\n    );\n  }\n}\n\ninterface JsonValueProps {\n  name: string;\n  value: any;\n  originalValue?: any;\n  keyPath?: string[];\n  deep?: number;\n  handleRemove?: (...args: any) => any;\n  handleUpdateValue?: (...args: any) => any;\n  readOnly: (...args: any) => any;\n  dataType?: string;\n  cancelButtonElement?: ReactElement;\n  inputElementGenerator: (...args: any) => any;\n  minusMenuElement?: ReactElement;\n  logger: any;\n  onSubmitValueParser: (...args: any) => any;\n}\n\n// @ts-expect-error (Converted from ts-ignore)\nJsonValue.defaultProps = {\n  keyPath: [],\n  deep: 0,\n  handleUpdateValue: () => Promise.resolve(),\n  cancelButtonElement: <button>c</button>,\n  minusMenuElement: <span> - </span>,\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/react-editable-json-tree/LICENSE.md",
    "content": "Copyright (c) 2016 Oxyno-zeta (Havrileck Alexandre)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\ndocumentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\nrights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit\npersons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the\nSoftware.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\nWARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\nOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/react-editable-json-tree/index.tsx",
    "content": "import type { ReactElement } from 'react';\nimport React, { Component } from 'react';\n\nimport { JsonNode } from './JsonNodes';\nimport * as DATA_TYPES from './types/dataTypes';\nimport { ADD_DELTA_TYPE, REMOVE_DELTA_TYPE, UPDATE_DELTA_TYPE } from './types/deltaTypes';\nimport * as INPUT_USAGE_TYPES from './types/inputUsageTypes';\nimport { getObjectType } from './utils/objectTypes';\nimport { parse } from './utils/parse';\nimport { array, object, value } from './utils/styles';\n\ninterface JsonTreeState {\n  data: JsonTreeProps['data'];\n  rootName: JsonTreeProps['rootName'];\n}\nexport class JsonTree extends Component<JsonTreeProps, JsonTreeState> {\n  constructor(props: JsonTreeProps) {\n    super(props);\n    this.state = {\n      data: props.data,\n      rootName: props.rootName,\n    };\n    // Bind\n    this.onUpdate = this.onUpdate.bind(this);\n    this.removeRoot = this.removeRoot.bind(this);\n  }\n\n  static getDerivedStateFromProps(props: JsonTreeProps, state: JsonTreeState) {\n    if (props.data !== state.data || props.rootName !== state.rootName) {\n      return {\n        data: props.data,\n        rootName: props.rootName,\n      };\n    }\n    return null;\n  }\n\n  onUpdate(key: string | null, data: any) {\n    this.setState({ data });\n    this.props.onFullyUpdate?.(data);\n  }\n\n  removeRoot() {\n    this.onUpdate(null, null);\n  }\n\n  render() {\n    const { data, rootName } = this.state;\n    const {\n      isCollapsed,\n      onDeltaUpdate,\n      readOnly,\n      addButtonElement,\n      cancelButtonElement,\n      inputElement,\n      textareaElement,\n      minusMenuElement,\n      plusMenuElement,\n      beforeRemoveAction,\n      beforeAddAction,\n      beforeUpdateAction,\n      logger,\n      onSubmitValueParser,\n      fallback = null,\n    } = this.props;\n\n    // Node type\n    const dataType = getObjectType(data);\n\n    let readOnlyFunction = readOnly;\n    if (getObjectType(readOnly) === 'Boolean') {\n      readOnlyFunction = () => readOnly;\n    }\n    let inputElementFunction = inputElement;\n    if (inputElement && getObjectType(inputElement) !== 'Function') {\n      // @ts-expect-error (Converted from ts-ignore)\n      inputElementFunction = () => inputElement;\n    }\n    let textareaElementFunction = textareaElement;\n    if (textareaElement && getObjectType(textareaElement) !== 'Function') {\n      // @ts-expect-error (Converted from ts-ignore)\n      textareaElementFunction = () => textareaElement;\n    }\n\n    if (dataType === 'Object' || dataType === 'Array') {\n      return (\n        <div className=\"rejt-tree\">\n          <JsonNode\n            data={data}\n            name={rootName || 'root'}\n            deep={-1}\n            isCollapsed={isCollapsed ?? (() => false)}\n            onUpdate={this.onUpdate}\n            onDeltaUpdate={onDeltaUpdate ?? (() => {})}\n            readOnly={readOnlyFunction as (...args: any) => any}\n            addButtonElement={addButtonElement}\n            cancelButtonElement={cancelButtonElement}\n            inputElementGenerator={inputElementFunction as (...args: any) => any}\n            textareaElementGenerator={textareaElementFunction as (...args: any) => any}\n            minusMenuElement={minusMenuElement}\n            plusMenuElement={plusMenuElement}\n            handleRemove={this.removeRoot}\n            beforeRemoveAction={beforeRemoveAction}\n            beforeAddAction={beforeAddAction}\n            beforeUpdateAction={beforeUpdateAction}\n            logger={logger ?? {}}\n            onSubmitValueParser={onSubmitValueParser ?? ((val) => val)}\n          />\n        </div>\n      );\n    }\n\n    return fallback;\n  }\n}\n\ninterface JsonTreeProps {\n  data: any;\n  rootName?: string;\n  isCollapsed?: (...args: any) => any;\n  onFullyUpdate?: (...args: any) => any;\n  onDeltaUpdate?: (...args: any) => any;\n  readOnly?: boolean | ((...args: any) => any);\n  addButtonElement?: ReactElement;\n  cancelButtonElement?: ReactElement;\n  inputElement?: ReactElement | ((...args: any) => ReactElement);\n  textareaElement?: ReactElement | ((...args: any) => ReactElement);\n  minusMenuElement?: ReactElement;\n  plusMenuElement?: ReactElement;\n  fallback?: ReactElement;\n  beforeRemoveAction?: (...args: any) => Promise<any>;\n  beforeAddAction?: (...args: any) => Promise<any>;\n  beforeUpdateAction?: (...args: any) => any;\n  logger?: object;\n  onSubmitValueParser?: (...args: any) => any;\n}\n\n// @ts-expect-error (Converted from ts-ignore)\nJsonTree.defaultProps = {\n  rootName: 'root',\n  isCollapsed: (keyPath, deep) => deep !== -1,\n  readOnly: () => false,\n  onFullyUpdate: () => {},\n  onDeltaUpdate: () => {},\n  beforeRemoveAction: () => Promise.resolve(),\n  beforeAddAction: () => Promise.resolve(),\n  beforeUpdateAction: () => Promise.resolve(),\n  logger: { error: () => {} },\n  onSubmitValueParser: (isEditMode, keyPath, deep, name, rawValue) => parse(rawValue),\n  inputElement: () => <input />,\n  textareaElement: () => <textarea />,\n  fallback: null,\n} as Partial<JsonTreeProps>;\n\nexport {\n  getObjectType,\n  ADD_DELTA_TYPE,\n  REMOVE_DELTA_TYPE,\n  UPDATE_DELTA_TYPE,\n  DATA_TYPES,\n  INPUT_USAGE_TYPES,\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/react-editable-json-tree/types/dataTypes.ts",
    "content": "const ERROR = 'Error';\nconst OBJECT = 'Object';\nconst ARRAY = 'Array';\nconst STRING = 'String';\nconst NUMBER = 'Number';\nconst BOOLEAN = 'Boolean';\nconst DATE = 'Date';\nconst NULL = 'Null';\nconst UNDEFINED = 'Undefined';\nconst FUNCTION = 'Function';\nconst SYMBOL = 'Symbol';\n\nexport { ERROR, OBJECT, ARRAY, STRING, NUMBER, BOOLEAN, DATE, NULL, UNDEFINED, FUNCTION, SYMBOL };\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/react-editable-json-tree/types/deltaTypes.ts",
    "content": "const ADD_DELTA_TYPE = 'ADD_DELTA_TYPE';\nconst REMOVE_DELTA_TYPE = 'REMOVE_DELTA_TYPE';\nconst UPDATE_DELTA_TYPE = 'UPDATE_DELTA_TYPE';\n\nexport { ADD_DELTA_TYPE, REMOVE_DELTA_TYPE, UPDATE_DELTA_TYPE };\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/react-editable-json-tree/types/inputUsageTypes.ts",
    "content": "const VALUE = 'value';\nconst KEY = 'key';\n\nexport { KEY, VALUE };\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/react-editable-json-tree/utils/objectTypes.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unnecessary-type-constraint */\n/**\n * Get Object type.\n *\n * @param obj {*} object to get type\n * @returns {any}\n */\nexport function getObjectType(obj: any) {\n  if (\n    obj !== null &&\n    typeof obj === 'object' &&\n    !Array.isArray(obj) &&\n    typeof obj[Symbol.iterator] === 'function'\n  ) {\n    return 'Iterable';\n  }\n  return Object.prototype.toString.call(obj).slice(8, -1);\n}\n\n/**\n * Is Component will change ?\n *\n * @param oldValue {*} old value\n * @param newValue {*} new value\n * @returns {boolean} Result\n */\nexport function isComponentWillChange<T extends unknown>(oldValue: T, newValue: T): boolean {\n  const oldType = getObjectType(oldValue);\n  const newType = getObjectType(newValue);\n  return (oldType === 'Function' || newType === 'Function') && newType !== oldType;\n}\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/react-editable-json-tree/utils/parse.ts",
    "content": "/**\n * Parse.\n *\n * @param string {String} string to parse\n * @returns {any}\n */\nexport function parse(string: string) {\n  let result = string;\n\n  // Check if string contains 'function' and start with it to eval it\n  if (result.indexOf('function') === 0) {\n    return (0, eval)(`(${result})`);\n  }\n\n  try {\n    result = JSON.parse(string);\n  } catch (e) {\n    // Error\n  }\n  return result;\n}\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/react-editable-json-tree/utils/styles.ts",
    "content": "export const object = {\n  minus: {\n    color: 'red',\n  },\n  plus: {\n    color: 'green',\n  },\n  collapsed: {\n    color: 'grey',\n  },\n  delimiter: {},\n  ul: {\n    padding: '0px',\n    margin: '0 0 0 25px',\n    listStyle: 'none',\n  },\n  name: {\n    color: '#2287CD',\n  },\n  addForm: {},\n};\n\nexport const array = {\n  minus: {\n    color: 'red',\n  },\n  plus: {\n    color: 'green',\n  },\n  collapsed: {\n    color: 'grey',\n  },\n  delimiter: {},\n  ul: {\n    padding: '0px',\n    margin: '0 0 0 25px',\n    listStyle: 'none',\n  },\n  name: {\n    color: '#2287CD',\n  },\n  addForm: {},\n};\n\nexport const value = {\n  minus: {\n    color: 'red',\n  },\n  editForm: {},\n  value: {\n    color: '#7bba3d',\n  },\n  li: {\n    minHeight: '22px',\n    lineHeight: '22px',\n    outline: '0px',\n  },\n  name: {\n    color: '#2287CD',\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/controls/types.ts",
    "content": "import type { ArgType } from '../components/ArgsTable/types';\n\nexport interface ControlProps<T> {\n  name: string;\n  storyId?: string;\n  value?: T;\n  defaultValue?: T;\n  argType?: ArgType;\n  onChange: (value?: T) => T | void;\n  onFocus?: (evt: any) => void;\n  onBlur?: (evt: any) => void;\n}\n\nexport type BooleanValue = boolean;\nexport interface BooleanConfig {}\n\nexport type ColorValue = string;\nexport type PresetColor = ColorValue | { color: ColorValue; title?: string };\nexport interface ColorConfig {\n  presetColors?: PresetColor[];\n  /**\n   * Maximum number of preset colors shown in the color picker. When the number of presets exceeds\n   * this value, the oldest presets are removed first (most-recently-used order). Set to `Infinity`\n   * or `0` to disable the limit and show all presets.\n   *\n   * @default 27\n   */\n  maxPresetColors?: number;\n  /**\n   * Whether the color picker should be open by default when rendered.\n   *\n   * @default false\n   */\n  startOpen?: boolean;\n}\n\nexport type DateValue = Date | number;\nexport interface DateConfig {}\n\nexport type NumberValue = number;\nexport interface NumberConfig {\n  min?: number;\n  max?: number;\n  step?: number;\n}\n\nexport type RangeConfig = NumberConfig;\n\nexport type ObjectValue = any;\nexport interface ObjectConfig {}\n\nexport type OptionsSingleSelection = any;\nexport type OptionsMultiSelection = any[];\nexport type OptionsSelection = OptionsSingleSelection | OptionsMultiSelection;\nexport type OptionsArray = any[];\nexport type OptionsObject = Record<string, any>;\nexport type Options = OptionsArray | OptionsObject;\nexport type OptionsControlType =\n  | 'radio'\n  | 'inline-radio'\n  | 'check'\n  | 'inline-check'\n  | 'select'\n  | 'multi-select';\n\nexport interface OptionsConfig {\n  labels?: Record<any, string>;\n  type: OptionsControlType;\n}\n\nexport interface NormalizedOptionsConfig {\n  options: OptionsObject;\n}\n\nexport type TextValue = string;\nexport interface TextConfig {\n  maxLength?: number;\n}\n\nexport type ControlType =\n  | 'array'\n  | 'boolean'\n  | 'color'\n  | 'date'\n  | 'number'\n  | 'range'\n  | 'object'\n  | OptionsControlType\n  | 'text';\n\nexport type Control =\n  | BooleanConfig\n  | ColorConfig\n  | DateConfig\n  | NumberConfig\n  | ObjectConfig\n  | OptionsConfig\n  | RangeConfig\n  | TextConfig;\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/ArgTypesParameters.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { ArgTypesParameters } from './ArgTypesParameters';\n\n/** Reference stories to be used by the ArgTypes stories */\nconst meta = {\n  title: 'examples/Stories for the ArgTypes Block',\n  component: ArgTypesParameters,\n  args: { b: 'b' },\n  argTypes: {\n    // @ts-expect-error Meta type is trying to force us to use real props as args\n    extraMetaArgType: {\n      type: { name: 'string' },\n      name: 'Extra Meta',\n      description: 'An extra argtype added at the meta level',\n      table: { defaultValue: { summary: \"'a default value'\" } },\n    },\n  },\n} satisfies Meta<typeof ArgTypesParameters>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const NoParameters: Story = {\n  argTypes: {\n    // @ts-expect-error Story type is trying to force us to use real props as args\n    extraStoryArgType: {\n      type: { name: 'string' },\n      name: 'Extra Story',\n      description: 'An extra argtype added at the story level',\n      table: { defaultValue: { summary: \"'a default value'\" } },\n    },\n  },\n};\n\nexport const Include: Story = {\n  ...NoParameters,\n  parameters: { docs: { argTypes: { include: ['a'] } } },\n};\n\nexport const Exclude: Story = {\n  ...NoParameters,\n  parameters: { docs: { argTypes: { exclude: ['a'] } } },\n};\n\nexport const Sort: Story = {\n  ...NoParameters,\n  parameters: { docs: { argTypes: { sort: 'alpha' } } },\n};\n\nexport const Categories: Story = {\n  ...NoParameters,\n  argTypes: {\n    c: {\n      description: 'a description',\n      table: {\n        category: 'the first category',\n      },\n    },\n    d: {\n      table: {\n        category: 'the first category',\n        subcategory: 'a subcategory',\n      },\n    },\n    e: {\n      table: {\n        subcategory: 'a subcategory without a category',\n      },\n    },\n    f: {\n      table: {\n        category: 'the second category',\n      },\n    },\n  } as any,\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/ArgTypesParameters.tsx",
    "content": "import React from 'react';\n\ntype PropTypes = { a?: string; b: string };\n\nexport const ArgTypesParameters = ({ a = 'a', b }: PropTypes) => <div>Example story</div>;\n\ntype SubcomponentAPropTypes = { e: boolean; c: boolean; d?: boolean };\n\nexport const SubcomponentA = ({ d = false }: SubcomponentAPropTypes) => (\n  <div>Example subcomponent A</div>\n);\n\ntype SubcomponentBPropTypes = { g: number; h: number; f?: number };\n\nexport const SubcomponentB = ({ f = 42 }: SubcomponentBPropTypes) => (\n  <div>Example subcomponent B</div>\n);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/ArgTypesWithSubcomponentsParameters.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { ArgTypesParameters, SubcomponentA, SubcomponentB } from './ArgTypesParameters';\n\n/** Reference stories to be used by the ArgTypes stories */\nconst meta = {\n  title: 'examples/Stories for the ArgTypes Block with Subcomponents',\n  component: ArgTypesParameters,\n  subcomponents: { SubcomponentA, SubcomponentB } as Record<string, React.ComponentType<any>>,\n  args: { b: 'b' },\n  argTypes: {\n    // @ts-expect-error Meta type is trying to force us to use real props as args\n    extraMetaArgType: {\n      type: { name: 'string' },\n      name: 'Extra Meta',\n      description: 'An extra argtype added at the meta level',\n      table: { defaultValue: { summary: \"'a default value'\" } },\n    },\n  },\n} satisfies Meta<typeof ArgTypesParameters>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const NoParameters: Story = {};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/Button.stories.tsx",
    "content": "/* eslint-disable local-rules/no-uncategorized-errors */\nimport React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { expect, fireEvent, within } from 'storybook/test';\n\nimport { Button } from './Button';\n\nconst meta = {\n  title: 'examples/Button',\n  component: Button,\n  tags: ['autodocs'],\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  // Stop *this* story from being stacked in Chromatic\n  globals: { sb_theme: 'default' },\n  parameters: {\n    // these are to test the deprecated features of the Description block\n    notes: 'These are notes for the Button stories',\n    info: 'This is info for the Button stories',\n    jsx: { useBooleanShorthandSyntax: false },\n    docs: {\n      subtitle: 'This is the subtitle for the Button stories',\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/**\n * This is the primary mode for the button\n *\n * _this description was written as a comment above the story_\n */\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    label: 'Button',\n  },\n  parameters: {\n    docs: {\n      description: {\n        story: `\nThis is the secondary - or default - mode for the button\n\n_this description was written as a string in \\`parameters.docs.description.story\\`_`,\n      },\n    },\n  },\n};\n\n/**\n * This is the large button _this description was written as a comment above the story, and should\n * never be shown because it should be overridden by the description in the parameters_\n */\nexport const Large: Story = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n  parameters: {\n    docs: {\n      description: {\n        story: `\nThis is the large button\n\n_this description was written as a string in \\`parameters.docs.description.story\\`, and overrides the comment above the story_\n`,\n      },\n    },\n  },\n};\n\nexport const Small: Story = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n\nexport const Clicking: Story = {\n  args: {\n    primary: true,\n    label: 'Increment',\n  },\n  render: (args) => {\n    const [count, setCount] = React.useState(0);\n    return (\n      <>\n        <Button {...args} onClick={() => setCount(count + 1)} />\n        <div style={{ padding: '1rem' }}>Click count: {count}</div>\n      </>\n    );\n  },\n  play: async ({ canvasElement, id }) => {\n    const canvas = within(canvasElement);\n\n    const button = canvas.getByText('Increment');\n    await fireEvent.click(button);\n\n    expect(await canvas.findByText('Click count: 1')).toBeInTheDocument();\n  },\n};\n\nexport const ClickingInDocs: Story = {\n  ...Clicking,\n  parameters: { docs: { story: { autoplay: true } } },\n};\n\nexport const ErrorStory: Story = {\n  render: () => {\n    const err = new Error('Rendering problem');\n    // force stack for consistency in capture\n    err.stack = `\n      at undecoratedStoryFn (/sb-preview/file.js:000:0001)\n      at hookified (/sb-preview/file.js:000:0001)\n      at defaultDecorateStory (/sb-preview/file.js:000:0001)\n      at jsxDecorator (/assets/file.js:000:0001)\n      at hookified (/sb-preview/file.js:000:0001)\n      at decorateStory (/sb-preview/file.js:000:0001)\n      at renderWithHooks (/sb-preview/file.js:000:0001)\n      at mountIndeterminateComponent (/assets/file.js:000:0001)\n      at beginWork (/assets/file.js:000:0001)\n      at longMockedPath (/node_modules/.cache/storybook/da6a511058d185c3c92ed7790fc88078d8a947a8d0ac75815e8fd5704bcd4baa/sb-vite/deps/file.js?v=00000000:000:0001)\n    `;\n    throw err;\n  },\n  args: { label: 'Button' },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n  tags: ['!test', '!vitest'],\n};\n\nexport const Centered: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n  parameters: {\n    layout: 'centered',\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/Button.tsx",
    "content": "import React from 'react';\n\nimport { styled } from 'storybook/theming';\n\ninterface ButtonProps {\n  /** Is this the principal call to action on the page? */\n  primary?: boolean;\n  /** What background color to use */\n  backgroundColor?: string;\n  /** How large should the button be? */\n  size?: 'small' | 'medium' | 'large';\n  /** Button contents */\n  label: string;\n  /** Optional click handler */\n  onClick?: () => void;\n}\n\nconst StyledButton = styled.button<Omit<ButtonProps, 'label' | 'onClick'>>(\n  ({ primary, size, backgroundColor }) => {\n    const modeStyles = primary\n      ? {\n          color: 'white',\n          backgroundColor: '#1ea7fd',\n        }\n      : {\n          color: '#333',\n          backgroundColor: 'transparent',\n          boxShadow: 'rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset',\n        };\n    const sizeStyles = {\n      small: {\n        fontSize: '12px',\n        padding: '10px 16px',\n      },\n      medium: {\n        fontSize: '14px',\n        padding: '11px 20px',\n      },\n      large: {\n        fontSize: '16px',\n        padding: '12px 24px',\n      },\n    };\n    return {\n      fontFamily: \"'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif\",\n      fontWeight: 700,\n      border: 0,\n      borderRadius: '3em',\n      cursor: 'pointer',\n      display: 'inline-block',\n      lineHeight: 1,\n      ...modeStyles,\n      ...sizeStyles[size || 'medium'],\n      ...(backgroundColor && { backgroundColor }),\n    };\n  }\n);\n\n/**\n * ## Example button component\n *\n * Comes in three sizes: `small`, `medium`, and `large`.\n *\n * Can be primary or secondary.\n *\n * _ This descriptions is written as a comment above the component_\n */\nexport const Button = ({\n  primary = false,\n  size = 'medium',\n  backgroundColor,\n  label,\n  ...props\n}: ButtonProps) => (\n  <StyledButton\n    type=\"button\"\n    size={size}\n    primary={primary}\n    backgroundColor={backgroundColor}\n    {...props}\n  >\n    {label}\n  </StyledButton>\n);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/ButtonNoAutodocs.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Button } from './Button';\n\nconst meta = {\n  title: 'examples/ButtonNoAutodocs',\n  component: Button,\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/ButtonReadonly.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Button } from './Button';\n\nconst meta = {\n  title: 'examples/Button Readonly',\n  component: Button,\n  tags: ['autodocs'],\n  argTypes: {\n    backgroundColor: {\n      control: 'color',\n      table: { readonly: true },\n    },\n    primary: {\n      table: { readonly: true },\n    },\n    label: {\n      table: { readonly: true },\n    },\n    size: {\n      table: { readonly: true },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/ButtonSomeAutodocs.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Button } from './Button';\n\nconst meta = {\n  title: 'examples/ButtonSomeAutodocs',\n  component: Button,\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  tags: ['autodocs'],\n  args: {\n    label: 'Button',\n  },\n  globals: {\n    backgrounds: {\n      grid: true,\n    },\n  },\n};\n\nexport const ForcedBgLight: Story = {\n  tags: ['autodocs'],\n  args: {\n    label: 'Button',\n  },\n  globals: {\n    backgrounds: {\n      value: 'light',\n    },\n  },\n};\n\nexport const ForcedBgDark: Story = {\n  tags: ['autodocs'],\n  args: {\n    label: 'Button',\n  },\n  globals: {\n    backgrounds: {\n      value: 'dark',\n    },\n  },\n};\n\nexport const ForcedBgBlue: Story = {\n  tags: ['autodocs'],\n  args: {\n    label: 'Button',\n  },\n  globals: {\n    backgrounds: {\n      value: 'blue',\n    },\n  },\n};\n\nexport const LastStory: Story = {\n  tags: ['autodocs'],\n  args: {\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/ButtonWithMetaDescriptionAsBoth.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Button } from './Button';\n\n/**\n * These are the stories for the Button component\n *\n * _this description was written as a comment above the default export_ _this should never be shown\n * in Storybook, as it should be overridden by `parameters.docs.description.component`_\n */\nconst meta = {\n  title: 'Examples/Button with Meta Description as Parameter and Comment',\n  component: Button,\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  // Stop *this* story from being stacked in Chromatic\n  globals: { sb_theme: 'default' },\n  parameters: {\n    docs: {\n      description: {\n        component: `\nThese are the stories for the Button component\n\n_this description was written as a string in \\`parameters.docs.description.component\\` and should override the comment above the default export_\n   `,\n      },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const WithMetaDescriptionAsBoth: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/ButtonWithMetaDescriptionAsComment.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Button } from './Button';\n\n/**\n * These are the stories for the Button component\n *\n * _this description was written as a comment above the default export_\n */\nconst meta = {\n  title: 'Examples/Button with Meta Description as Comment',\n  component: Button,\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  // Stop *this* story from being stacked in Chromatic\n  globals: { sb_theme: 'light' },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const WithMetaDescriptionAsComment: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/ButtonWithMetaDescriptionAsParameter.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Button } from './Button';\n\nconst meta = {\n  title: 'examples/Button with Meta Description as Parameter',\n  component: Button,\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  globals: { sb_theme: 'light' },\n  parameters: {\n    docs: {\n      description: {\n        component: `\nThese are the stories for the Button component\n\n_this description was written as a string in \\`parameters.docs.description.component\\`_\n   `,\n      },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const WithMetaDescriptionAsParamater: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/ButtonWithMetaSubtitleAsBoth.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Button } from './Button';\n\nconst meta = {\n  title: 'examples/Button with Meta Subtitle in Both',\n  component: Button,\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  globals: { sb_theme: 'light' },\n  parameters: {\n    // this is to test the deprecated features of the Subtitle block\n    componentSubtitle: 'This subtitle is set in parameters.componentSubtitle',\n    docs: {\n      subtitle: 'This subtitle is set in parameters.docs.subtitle',\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const WithMetaSubtitleAsBoth: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/ButtonWithMetaSubtitleAsComponentSubtitle.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Button } from './Button';\n\nconst meta = {\n  title: 'examples/Button with Meta Subtitle in componentSubtitle',\n  component: Button,\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  globals: { sb_theme: 'light' },\n  parameters: {\n    // this is to test the deprecated features of the Subtitle block\n    componentSubtitle: 'This subtitle is set in parameters.componentSubtitle',\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const WithMetaSubtitleInComponentSubtitle: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/ButtonWithMetaSubtitleAsDocsSubtitle.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Button } from './Button';\n\nconst meta = {\n  title: 'examples/Button with Meta Subtitle in docs.subtitle',\n  component: Button,\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  globals: { sb_theme: 'light' },\n  parameters: {\n    docs: {\n      subtitle: 'This subtitle is set in parameters.docs.subtitle',\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const WithMetaSubtitleInDocsSubtitle: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/CanvasParameters.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { EmptyExample } from './EmptyExample';\n\nconst meta = {\n  title: 'examples/Stories for the Canvas Block',\n  component: EmptyExample,\n} satisfies Meta<typeof EmptyExample>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const WithToolbar: Story = {\n  parameters: { docs: { canvas: { withToolbar: true } } },\n};\nexport const AdditionalActions: Story = {\n  parameters: {\n    docs: {\n      canvas: {\n        additionalActions: [\n          {\n            title: 'Open in GitHub',\n            onClick: () => {\n              window.open(\n                'https://github.com/storybookjs/storybook/blob/next/code/lib/blocks/src/examples/Button.stories.tsx',\n                '_blank'\n              );\n            },\n          },\n          {\n            title: 'Go to documentation',\n            onClick: () => {\n              window.open('https://storybook.js.org/docs/essentials/controls#annotation', '_blank');\n            },\n          },\n        ],\n      },\n    },\n  },\n};\n\nexport const SourceStateShown: Story = {\n  parameters: { docs: { canvas: { sourceState: 'shown' } } },\n};\nexport const SourceStateHidden: Story = {\n  parameters: { docs: { canvas: { sourceState: 'hidden' } } },\n};\nexport const SourceStateNone: Story = {\n  parameters: { docs: { canvas: { sourceState: 'none' } } },\n};\n\nexport const LayoutFullscreen: Story = {\n  parameters: { layout: 'fullscreen' },\n};\nexport const LayoutPadded: Story = {\n  parameters: { layout: 'padded' },\n};\nexport const LayoutCentered: Story = {\n  parameters: { layout: 'centered' },\n};\n\nexport const DocsCanvasLayoutFullscreen: Story = {\n  parameters: { docs: { canvas: { layout: 'fullscreen' } } },\n};\nexport const DocsCanvasLayoutPadded: Story = {\n  parameters: { docs: { canvas: { layout: 'padded' } } },\n};\nexport const DocsCanvasLayoutCentered: Story = {\n  parameters: { docs: { canvas: { layout: 'centered' } } },\n};\n\nexport const ClassName: Story = {\n  parameters: { docs: { canvas: { className: 'my-custom-classname' } } },\n};\n\nexport const StoryParameters: Story = {\n  parameters: { docs: { story: { inline: false, height: '200px' } } },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/ControlsParameters.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { ControlsParameters } from './ControlsParameters';\n\n/** Reference stories to be used by the Controls stories */\nconst meta = {\n  title: 'examples/Stories for the Controls Block',\n  component: ControlsParameters,\n  args: { b: 'b' },\n  argTypes: {\n    // @ts-expect-error Meta type is trying to force us to use real props as args\n    extraMetaArgType: {\n      type: { name: 'string' },\n      name: 'Extra Meta',\n      description: 'An extra argtype added at the meta level',\n      table: { defaultValue: { summary: \"'a default value'\" } },\n    },\n  },\n} satisfies Meta<typeof ControlsParameters>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const NoParameters: Story = {\n  argTypes: {\n    // @ts-expect-error Story type is trying to force us to use real props as args\n    extraStoryArgType: {\n      type: { name: 'string' },\n      name: 'Extra Story',\n      description: 'An extra argtype added at the story level',\n      table: { defaultValue: { summary: \"'a default value'\" } },\n    },\n  },\n};\n\nexport const Include: Story = {\n  ...NoParameters,\n  parameters: { docs: { controls: { include: ['a'] } } },\n};\n\nexport const Exclude: Story = {\n  ...NoParameters,\n  parameters: { docs: { controls: { exclude: ['a'] } } },\n};\n\nexport const Sort: Story = {\n  ...NoParameters,\n  parameters: { docs: { controls: { sort: 'alpha' } } },\n};\n\nexport const Categories: Story = {\n  ...NoParameters,\n  argTypes: {\n    c: {\n      description: 'a description',\n      control: {\n        type: 'text',\n      },\n      table: {\n        category: 'the first category',\n      },\n    },\n    d: {\n      control: {\n        type: 'number',\n      },\n      table: {\n        category: 'the first category',\n        subcategory: 'a subcategory',\n      },\n    },\n    e: {\n      control: {\n        type: 'color',\n      },\n      table: {\n        subcategory: 'a subcategory without a category',\n      },\n    },\n    f: {\n      table: {\n        category: 'the second category',\n      },\n    },\n  } as any,\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/ControlsParameters.tsx",
    "content": "import React from 'react';\n\ntype PropTypes = { a?: string; b: string };\n\nexport const ControlsParameters = ({ a = 'a', b }: PropTypes) => <div>Example story</div>;\n\ntype SubcomponentAPropTypes = { e: boolean; c: boolean; d?: boolean };\n\nexport const SubcomponentA = ({ d = false }: SubcomponentAPropTypes) => (\n  <div>Example subcomponent A</div>\n);\n\ntype SubcomponentBPropTypes = { g: number; h: number; f?: number };\n\nexport const SubcomponentB = ({ f = 42 }: SubcomponentBPropTypes) => (\n  <div>Example subcomponent B</div>\n);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/ControlsWithSubcomponentsParameters.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { ControlsParameters, SubcomponentA, SubcomponentB } from './ControlsParameters';\n\n/** Reference stories to be used by the Controls stories */\nconst meta = {\n  title: 'examples/Stories for the Controls Block with Subcomponents',\n  component: ControlsParameters,\n  subcomponents: { SubcomponentA, SubcomponentB } as Record<string, React.ComponentType<any>>,\n  args: { b: 'b' },\n  argTypes: {\n    // @ts-expect-error Meta type is trying to force us to use real props as args\n    extraMetaArgType: {\n      type: { name: 'string' },\n      name: 'Extra Meta',\n      description: 'An extra argtype added at the meta level',\n      table: { defaultValue: { summary: \"'a default value'\" } },\n    },\n  },\n} satisfies Meta<typeof ControlsParameters>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const NoParameters: Story = {\n  argTypes: {\n    // @ts-expect-error Story type is trying to force us to use real props as args\n    extraStoryArgType: {\n      type: { name: 'string' },\n      name: 'Extra Story',\n      description: 'An extra argtype added at the story level',\n      table: { defaultValue: { summary: \"'a default value'\" } },\n    },\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/DocsPageParameters.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { EmptyExample } from './EmptyExample';\n\n/** This is the description for the component */\nconst meta = {\n  title: 'examples/Stories for the DocsPage',\n  component: EmptyExample,\n} satisfies Meta<typeof EmptyExample>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/** This is the description for the primary story */\nexport const SingleStory: Story = {};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/EmptyArgTypes.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport type { ControlsParameters } from './ControlsParameters';\n\nconst meta = {\n  title: 'examples/Empty ArgTypes for Control blocks',\n  // note that component is not specified, so no argtypes can be generated\n  render: () => <div>I am a story without args or argTypes</div>,\n  parameters: { chromatic: { disableSnapshot: true } },\n} satisfies Meta<typeof ControlsParameters>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/**\n * There are no argTypes or args, so this story won't show any controls in the docs page. In the\n * control addon it will show a UI how to set up controls.\n */\nexport const Default: Story = {};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/EmptyExample.tsx",
    "content": "import React from 'react';\n\nexport const EmptyExample = ({}) => (\n  <div>\n    This component is not intended to render anything, it simply serves as something to hang\n    parameters off\n  </div>\n);\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/Markdown-content.md",
    "content": "# This is an `.md` file\n\nit has been imported using `import content from './Markdown-content.md?raw'`\n\nNotice the `?raw` at the end above, it is necessary to work.\n\nA full example:\n\n```md\nimport { Markdown } from '@storybook/addon-docs/blocks';\nimport content from './Markdown-content.md?raw';\n\n<Markdown>{content}</Markdown>\n```\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/SimpleSizeTest.tsx",
    "content": "import React from 'react';\n\nexport const SimpleSizeTest = () => {\n  return (\n    <div\n      style={{\n        background: '#fd5c9355',\n        padding: '3rem',\n        height: '500px',\n        width: '800px',\n        // a global decorator is applying a default padding that we want to negate here\n        margin: '-4rem -20px',\n      }}\n    >\n      <p data-testid=\"sb-iframe-text\">\n        This story does nothing. Its only purpose is to show how its size renders in different\n        conditions (inline/iframe/fixed height) when used in a <code>{'<Story />'}</code> block.\n      </p>\n      <p>\n        It has a fixed <code>height</code> of <code>500px</code> and a fixed <code>width</code> of{' '}\n        <code>800px</code>\n      </p>\n    </div>\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/SourceParameters.stories.tsx",
    "content": "import { SourceType } from 'storybook/internal/docs-tools';\nimport type { StoryContext } from 'storybook/internal/types';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { dedent } from 'ts-dedent';\n\nimport { EmptyExample } from './EmptyExample';\n\nconst code = `query HeroNameAndFriends($episode: Episode) {\n          hero(episode: $episode) {\n            name\n            friends {\n              name\n            }\n          }\n        }\n`;\n\nconst meta = {\n  title: 'examples/Stories for the Source Block',\n  component: EmptyExample,\n} satisfies Meta<typeof EmptyExample>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const NoParameters: Story = {\n  args: { something: 'else' },\n  // This is here so we can tell if we are looking at the real vs emitted source\n};\n\nexport const TypeCode: Story = {\n  parameters: { docs: { source: { type: SourceType.CODE } } },\n};\n\nexport const Transform = {\n  args: { something: 'else' },\n  parameters: {\n    docs: {\n      source: {\n        transform: (\n          src: string,\n          storyContext: StoryContext\n        ) => dedent`// this comment has been added via parameters.docs.source.transform!\n        // this is the story id: ${storyContext.id}\n        // these are the current args: ${JSON.stringify(storyContext.args)}\n        ${src}`,\n      },\n    },\n  },\n};\n\nexport const Code = {\n  parameters: { docs: { source: { code } } },\n};\n\nexport const CodeFormat = {\n  parameters: { docs: { source: { code, format: true } } },\n};\n\nexport const CodeLanguage = {\n  parameters: { docs: { source: { code, format: true, language: 'graphql' } } },\n};\n\nexport const CodeDark = {\n  parameters: { docs: { source: { code, dark: true } } },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/StoriesParameters.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { EmptyExample } from './EmptyExample';\n\nconst meta = {\n  title: 'examples/Stories for the Stories and Primary Block',\n  component: EmptyExample,\n  tags: ['autodocs'],\n} satisfies Meta<typeof EmptyExample>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const WithoutToolbar: Story = {\n  parameters: { docs: { canvas: { withToolbar: false } } },\n};\n\nexport const WithToolbar: Story = {\n  parameters: { docs: { canvas: { withToolbar: true } } },\n};\nexport const ThirdStory: Story = {};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/examples/StoryParameters.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { SimpleSizeTest } from './SimpleSizeTest';\n\nconst meta = {\n  title: 'examples/Stories for the Story Block',\n  component: SimpleSizeTest,\n  globals: { sb_theme: 'light' },\n} satisfies Meta<typeof SimpleSizeTest>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const NoParameters: Story = {};\n\nexport const Height: Story = { parameters: { docs: { story: { height: '600px' } } } };\n\nexport const InlineFalse: Story = { parameters: { docs: { story: { inline: false } } } };\n\nexport const InlineFalseWithIframeHeight: Story = {\n  parameters: { docs: { story: { inline: false, iframeHeight: '300px' } } },\n};\n\nexport const InlineFalseWithHeight: Story = {\n  parameters: { docs: { story: { inline: false, height: '300px' } } },\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks/getStoryHref.ts",
    "content": "/**\n * Only for internal use in addon-docs code, because the parent util in `core` cannot be imported.\n * Unlike the parent util, this one only returns the preview URL.\n */\nexport const getStoryHref = (storyId: string, additionalParams: Record<string, string> = {}) => {\n  const baseUrl = globalThis.PREVIEW_URL || 'iframe.html';\n  const [url, paramsStr] = baseUrl.split('?');\n  const params = new URLSearchParams(paramsStr || '');\n\n  Object.entries(additionalParams).forEach(([key, value]) => {\n    params.set(key, value);\n  });\n\n  params.set('id', storyId);\n\n  return `${url}?${params.toString()}`;\n};\n"
  },
  {
    "path": "code/addons/docs/src/blocks.ts",
    "content": "// FIXME: sort this out, maybe with package.json exports map\n// https://medium.com/swlh/npm-new-package-json-exports-field-1a7d1f489ccf\nexport { ArgsTable as PureArgsTable } from './blocks/components/ArgsTable/ArgsTable';\nexport { TableOfContents } from './blocks/components';\n\nexport type { SortType } from './blocks/components';\n\nexport * from './blocks/blocks';\nexport * from './blocks/controls';\n"
  },
  {
    "path": "code/addons/docs/src/compiler/index.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { dedent } from 'ts-dedent';\n\nimport { compile, compileSync } from './index';\n\nexpect.addSnapshotSerializer({\n  serialize: (val: any) => (typeof val === 'string' ? val : val.toString()),\n  test: (_val) => true,\n});\n\n// Remove unnecessary noise from snapshots\nconst clean = (code: string) => {\n  const mdxContentRegex =\n    /export default function MDXContent\\([^)]*\\) \\{(?:[^{}]*|{(?:[^{}]*|{[^{}]*})*})*\\}/gs;\n\n  const mdxMissingReferenceRegex =\n    /function _missingMdxReference\\([^)]*\\) \\{(?:[^{}]*|{(?:[^{}]*|{[^{}]*})*})*\\}/gs;\n\n  return code.replace(mdxMissingReferenceRegex, '').replace(mdxContentRegex, '');\n};\n\ndescribe('mdx3', () => {\n  it('supports AdjacentBlockJSX', () => {\n    const input = dedent`\n      <style>{\\`\n        h1 {\n          color: blue;\n        }\n      \\`}</style>\n   `;\n\n    expect(clean(compileSync(input))).toMatchInlineSnapshot(`\n      import {jsx as _jsx} from \"react/jsx-runtime\";\n      import {useMDXComponents as _provideComponents} from \"@mdx-js/react\";\n      function _createMdxContent(props) {\n        return _jsx(\"style\", {\n          children: \\`\n      h1 {\n        color: blue;\n      }\n      \\`\n        });\n      }\n    `);\n  });\n\n  it('supports Await in MDX', () => {\n    const input = dedent`\n      {await Promise.resolve('Hello World')}\n   `;\n\n    expect(clean(compileSync(input))).toMatchInlineSnapshot(`\n      import {Fragment as _Fragment, jsx as _jsx} from \"react/jsx-runtime\";\n      import {useMDXComponents as _provideComponents} from \"@mdx-js/react\";\n      async function _createMdxContent(props) {\n        return _jsx(_Fragment, {\n          children: await Promise.resolve('Hello World')\n        });\n      }\n    `);\n  });\n\n  it('supports ES2024', () => {\n    const input = dedent`\n    export const obj = {\n      nested: {\n        property: 'Hello world!'\n      }\n    };\n    \n    export const value = obj?.nested?.property ?? 'Default Value';\n    \n    Value: {value}\n   `;\n\n    expect(clean(compileSync(input))).toMatchInlineSnapshot(`\n      import {jsx as _jsx, jsxs as _jsxs} from \"react/jsx-runtime\";\n      import {useMDXComponents as _provideComponents} from \"@mdx-js/react\";\n      export const obj = {\n        nested: {\n          property: 'Hello world!'\n        }\n      };\n      export const value = obj?.nested?.property ?? 'Default Value';\n      function _createMdxContent(props) {\n        const _components = {\n          p: \"p\",\n          ..._provideComponents(),\n          ...props.components\n        };\n        return _jsxs(_components.p, {\n          children: [\"Value: \", value]\n        });\n      }\n    `);\n  });\n});\n\ndescribe('mdx2', () => {\n  it('works', () => {\n    const input = dedent`\n      # hello\n\n      <Meta title=\"foobar\" />\n\n      world {2 + 1}\n    `;\n\n    expect(clean(compileSync(input))).toMatchInlineSnapshot(`\n      import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from \"react/jsx-runtime\";\n      import {useMDXComponents as _provideComponents} from \"@mdx-js/react\";\n      function _createMdxContent(props) {\n        const _components = {\n          h1: \"h1\",\n          p: \"p\",\n          ..._provideComponents(),\n          ...props.components\n        }, {Meta} = _components;\n        if (!Meta) _missingMdxReference(\"Meta\", true);\n        return _jsxs(_Fragment, {\n          children: [_jsx(_components.h1, {\n            children: \"hello\"\n          }), \"\\\\n\", _jsx(Meta, {\n            title: \"foobar\"\n          }), \"\\\\n\", _jsxs(_components.p, {\n            children: [\"world \", 2 + 1]\n          })]\n        });\n      }\n    `);\n  });\n\n  it('standalone jsx expressions', () => {\n    expect(\n      clean(\n        compileSync(dedent`\n        # Standalone JSX expressions\n\n        {3 + 3}\n      `)\n      )\n    ).toMatchInlineSnapshot(`\n      import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from \"react/jsx-runtime\";\n      import {useMDXComponents as _provideComponents} from \"@mdx-js/react\";\n      function _createMdxContent(props) {\n        const _components = {\n          h1: \"h1\",\n          ..._provideComponents(),\n          ...props.components\n        };\n        return _jsxs(_Fragment, {\n          children: [_jsx(_components.h1, {\n            children: \"Standalone JSX expressions\"\n          }), \"\\\\n\", 3 + 3]\n        });\n      }\n    `);\n  });\n});\n\ndescribe('full snapshots', () => {\n  it('compileSync', () => {\n    const input = dedent`\n      # hello\n\n      <Meta title=\"foobar\" />\n\n      world {2 + 1}\n    `;\n\n    expect(compileSync(input)).toMatchInlineSnapshot(`\n      import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from \"react/jsx-runtime\";\n      import {useMDXComponents as _provideComponents} from \"@mdx-js/react\";\n      function _createMdxContent(props) {\n        const _components = {\n          h1: \"h1\",\n          p: \"p\",\n          ..._provideComponents(),\n          ...props.components\n        }, {Meta} = _components;\n        if (!Meta) _missingMdxReference(\"Meta\", true);\n        return _jsxs(_Fragment, {\n          children: [_jsx(_components.h1, {\n            children: \"hello\"\n          }), \"\\\\n\", _jsx(Meta, {\n            title: \"foobar\"\n          }), \"\\\\n\", _jsxs(_components.p, {\n            children: [\"world \", 2 + 1]\n          })]\n        });\n      }\n      export default function MDXContent(props = {}) {\n        const {wrapper: MDXLayout} = {\n          ..._provideComponents(),\n          ...props.components\n        };\n        return MDXLayout ? _jsx(MDXLayout, {\n          ...props,\n          children: _jsx(_createMdxContent, {\n            ...props\n          })\n        }) : _createMdxContent(props);\n      }\n      function _missingMdxReference(id, component) {\n        throw new Error(\"Expected \" + (component ? \"component\" : \"object\") + \" \\`\" + id + \"\\` to be defined: you likely forgot to import, pass, or provide it.\");\n      }\n    `);\n  });\n  it('compile', async () => {\n    const input = dedent`\n      # hello\n\n      <Meta title=\"foobar\" />\n\n      world {2 + 1}\n    `;\n\n    expect(await compile(input)).toMatchInlineSnapshot(`\n      import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from \"react/jsx-runtime\";\n      import {useMDXComponents as _provideComponents} from \"@mdx-js/react\";\n      function _createMdxContent(props) {\n        const _components = {\n          h1: \"h1\",\n          p: \"p\",\n          ..._provideComponents(),\n          ...props.components\n        }, {Meta} = _components;\n        if (!Meta) _missingMdxReference(\"Meta\", true);\n        return _jsxs(_Fragment, {\n          children: [_jsx(_components.h1, {\n            children: \"hello\"\n          }), \"\\\\n\", _jsx(Meta, {\n            title: \"foobar\"\n          }), \"\\\\n\", _jsxs(_components.p, {\n            children: [\"world \", 2 + 1]\n          })]\n        });\n      }\n      export default function MDXContent(props = {}) {\n        const {wrapper: MDXLayout} = {\n          ..._provideComponents(),\n          ...props.components\n        };\n        return MDXLayout ? _jsx(MDXLayout, {\n          ...props,\n          children: _jsx(_createMdxContent, {\n            ...props\n          })\n        }) : _createMdxContent(props);\n      }\n      function _missingMdxReference(id, component) {\n        throw new Error(\"Expected \" + (component ? \"component\" : \"object\") + \" \\`\" + id + \"\\` to be defined: you likely forgot to import, pass, or provide it.\");\n      }\n    `);\n  });\n  it('sync & async should match', async () => {\n    const input = dedent`\n    # hello\n\n    <Meta title=\"foobar\" />\n\n    world {2 + 1}\n  `;\n\n    const ou1 = compileSync(input);\n    const ou2 = await compile(input);\n\n    expect(ou1).toEqual(ou2);\n  });\n  it('canvas without story children', () => {\n    const input = dedent`\n      import { Canvas } from '@storybook/addon-docs/blocks';\n\n      <Canvas>\n        <h2>Some here</h2>\n      </Canvas>\n    `;\n    expect(compileSync(input)).toMatchInlineSnapshot(`\n      import {jsx as _jsx} from \"react/jsx-runtime\";\n      import {useMDXComponents as _provideComponents} from \"@mdx-js/react\";\n      import {Canvas} from '@storybook/addon-docs/blocks';\n      function _createMdxContent(props) {\n        return _jsx(Canvas, {\n          children: _jsx(\"h2\", {\n            children: \"Some here\"\n          })\n        });\n      }\n      export default function MDXContent(props = {}) {\n        const {wrapper: MDXLayout} = {\n          ..._provideComponents(),\n          ...props.components\n        };\n        return MDXLayout ? _jsx(MDXLayout, {\n          ...props,\n          children: _jsx(_createMdxContent, {\n            ...props\n          })\n        }) : _createMdxContent(props);\n      }\n    `);\n  });\n});\n\ndescribe('docs-mdx-compiler-plugin', () => {\n  it('csf-imports.mdx', () => {\n    expect(\n      clean(\n        compileSync(dedent`\n        import { Story, Meta, Canvas } from '@storybook/addon-docs/blocks';\n        import { Welcome, Button } from '@storybook/angular/demo';\n        import * as MyStories from './My.stories';\n        import { Other } from './Other.stories';\n\n        <Meta title=\"MDX/CSF imports\" />\n\n        # Stories from CSF imports\n\n        <Story of={MyStories.Basic} />\n\n        <Canvas>\n          <Story of={Other} />\n        </Canvas>\n      `)\n      )\n    ).toMatchInlineSnapshot(`\n      import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from \"react/jsx-runtime\";\n      import {useMDXComponents as _provideComponents} from \"@mdx-js/react\";\n      import {Story, Meta, Canvas} from '@storybook/addon-docs/blocks';\n      import {Welcome, Button} from '@storybook/angular/demo';\n      import * as MyStories from './My.stories';\n      import {Other} from './Other.stories';\n      function _createMdxContent(props) {\n        const _components = {\n          h1: \"h1\",\n          ..._provideComponents(),\n          ...props.components\n        };\n        return _jsxs(_Fragment, {\n          children: [_jsx(Meta, {\n            title: \"MDX/CSF imports\"\n          }), \"\\\\n\", _jsx(_components.h1, {\n            children: \"Stories from CSF imports\"\n          }), \"\\\\n\", _jsx(Story, {\n            of: MyStories.Basic\n          }), \"\\\\n\", _jsx(Canvas, {\n            children: _jsx(Story, {\n              of: Other\n            })\n          })]\n        });\n      }\n    `);\n  });\n\n  it('docs-only.mdx', () => {\n    expect(\n      clean(\n        compileSync(dedent`\n        import { Meta } from '@storybook/addon-docs/blocks';\n\n        <Meta title=\"docs-only\" />\n\n        # Documentation only\n\n        This is a documentation-only MDX file which cleans a dummy 'docsOnly: true' story.\n      `)\n      )\n    ).toMatchInlineSnapshot(`\n      import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from \"react/jsx-runtime\";\n      import {useMDXComponents as _provideComponents} from \"@mdx-js/react\";\n      import {Meta} from '@storybook/addon-docs/blocks';\n      function _createMdxContent(props) {\n        const _components = {\n          h1: \"h1\",\n          p: \"p\",\n          ..._provideComponents(),\n          ...props.components\n        };\n        return _jsxs(_Fragment, {\n          children: [_jsx(Meta, {\n            title: \"docs-only\"\n          }), \"\\\\n\", _jsx(_components.h1, {\n            children: \"Documentation only\"\n          }), \"\\\\n\", _jsx(_components.p, {\n            children: \"This is a documentation-only MDX file which cleans a dummy 'docsOnly: true' story.\"\n          })]\n        });\n      }\n    `);\n  });\n\n  it('meta-quotes-in-title.mdx', () => {\n    expect(\n      clean(\n        compileSync(dedent`\n        import { Meta } from '@storybook/addon-docs/blocks';\n\n        <Meta title=\"Addons/Docs/what's in a title?\" />\n      `)\n      )\n    ).toMatchInlineSnapshot(`\n      import {jsx as _jsx} from \"react/jsx-runtime\";\n      import {useMDXComponents as _provideComponents} from \"@mdx-js/react\";\n      import {Meta} from '@storybook/addon-docs/blocks';\n      function _createMdxContent(props) {\n        return _jsx(Meta, {\n          title: \"Addons/Docs/what's in a title?\"\n        });\n      }\n    `);\n  });\n\n  it('non-story-exports.mdx', () => {\n    expect(\n      clean(\n        compileSync(dedent`\n        import { Button } from '@storybook/react/demo';\n        import { Story, Meta } from '@storybook/addon-docs/blocks';\n\n        <Meta title=\"Button\" />\n\n        # Story definition\n\n        <Story of={Button} />\n\n        export const two = 2;\n      `)\n      )\n    ).toMatchInlineSnapshot(`\n      import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from \"react/jsx-runtime\";\n      import {useMDXComponents as _provideComponents} from \"@mdx-js/react\";\n      import {Button} from '@storybook/react/demo';\n      import {Story, Meta} from '@storybook/addon-docs/blocks';\n      export const two = 2;\n      function _createMdxContent(props) {\n        const _components = {\n          h1: \"h1\",\n          ..._provideComponents(),\n          ...props.components\n        };\n        return _jsxs(_Fragment, {\n          children: [_jsx(Meta, {\n            title: \"Button\"\n          }), \"\\\\n\", _jsx(_components.h1, {\n            children: \"Story definition\"\n          }), \"\\\\n\", _jsx(Story, {\n            of: Button\n          })]\n        });\n      }\n    `);\n  });\n\n  it('story-current.mdx', () => {\n    expect(\n      clean(\n        compileSync(dedent`\n        import { Story } from '@storybook/addon-docs/blocks';\n\n        # Current story\n\n        <Story id=\".\" />\n      `)\n      )\n    ).toMatchInlineSnapshot(`\n      import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from \"react/jsx-runtime\";\n      import {useMDXComponents as _provideComponents} from \"@mdx-js/react\";\n      import {Story} from '@storybook/addon-docs/blocks';\n      function _createMdxContent(props) {\n        const _components = {\n          h1: \"h1\",\n          ..._provideComponents(),\n          ...props.components\n        };\n        return _jsxs(_Fragment, {\n          children: [_jsx(_components.h1, {\n            children: \"Current story\"\n          }), \"\\\\n\", _jsx(Story, {\n            id: \".\"\n          })]\n        });\n      }\n    `);\n  });\n\n  it('story-references.mdx', () => {\n    expect(\n      clean(\n        compileSync(dedent`\n        import { Story } from '@storybook/addon-docs/blocks';\n\n        # Story reference\n\n        <Story id=\"welcome--welcome\" />\n      `)\n      )\n    ).toMatchInlineSnapshot(`\n      import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from \"react/jsx-runtime\";\n      import {useMDXComponents as _provideComponents} from \"@mdx-js/react\";\n      import {Story} from '@storybook/addon-docs/blocks';\n      function _createMdxContent(props) {\n        const _components = {\n          h1: \"h1\",\n          ..._provideComponents(),\n          ...props.components\n        };\n        return _jsxs(_Fragment, {\n          children: [_jsx(_components.h1, {\n            children: \"Story reference\"\n          }), \"\\\\n\", _jsx(Story, {\n            id: \"welcome--welcome\"\n          })]\n        });\n      }\n    `);\n  });\n\n  it('title-template-string.mdx', () => {\n    expect(\n      clean(\n        compileSync(\n          [\n            \"import { Meta, Story } from '@storybook/addon-docs/blocks';\",\n            \"import { titleFunction } from '../title-generators';\",\n            '',\n\n            \"<Meta title={`${titleFunction('template')}`} />\",\n          ].join('\\n')\n        )\n      )\n    ).toMatchInlineSnapshot(`\n      import {jsx as _jsx} from \"react/jsx-runtime\";\n      import {useMDXComponents as _provideComponents} from \"@mdx-js/react\";\n      import {Meta, Story} from '@storybook/addon-docs/blocks';\n      import {titleFunction} from '../title-generators';\n      function _createMdxContent(props) {\n        return _jsx(Meta, {\n          title: \\`\\${titleFunction('template')}\\`\n        });\n      }\n    `);\n  });\n\n  describe('csf3', () => {\n    it('auto-title-docs-only.mdx', () => {\n      expect(\n        clean(\n          compileSync(dedent`\n          import { Meta } from '@storybook/addon-docs/blocks';\n\n          <Meta />\n\n          # Auto-title Docs Only\n\n          Some **markdown** here!\n        `)\n        )\n      ).toMatchInlineSnapshot(`\n        import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from \"react/jsx-runtime\";\n        import {useMDXComponents as _provideComponents} from \"@mdx-js/react\";\n        import {Meta} from '@storybook/addon-docs/blocks';\n        function _createMdxContent(props) {\n          const _components = {\n            h1: \"h1\",\n            p: \"p\",\n            strong: \"strong\",\n            ..._provideComponents(),\n            ...props.components\n          };\n          return _jsxs(_Fragment, {\n            children: [_jsx(Meta, {}), \"\\\\n\", _jsx(_components.h1, {\n              children: \"Auto-title Docs Only\"\n            }), \"\\\\n\", _jsxs(_components.p, {\n              children: [\"Some \", _jsx(_components.strong, {\n                children: \"markdown\"\n              }), \" here!\"]\n            })]\n          });\n        }\n      `);\n    });\n\n    it('auto-title.mdx', () => {\n      expect(\n        clean(\n          compileSync(dedent`\n          import { Button } from '@storybook/react/demo';\n          import { Story, Meta } from '@storybook/addon-docs/blocks';\n\n          <Meta component={Button} />\n        `)\n        )\n      ).toMatchInlineSnapshot(`\n        import {jsx as _jsx} from \"react/jsx-runtime\";\n        import {useMDXComponents as _provideComponents} from \"@mdx-js/react\";\n        import {Button} from '@storybook/react/demo';\n        import {Story, Meta} from '@storybook/addon-docs/blocks';\n        function _createMdxContent(props) {\n          return _jsx(Meta, {\n            component: Button\n          });\n        }\n      `);\n    });\n  });\n\n  it('style tag', () => {\n    expect(\n      clean(\n        compileSync(dedent`\n        import { Meta } from '@storybook/addon-docs/blocks';\n\n        <Meta title=\"Example/Introduction\" />\n\n        <style>{\\`\n          .subheading {\n            --mediumdark: '#999999';\n            font-weight: 900;\n            font-size: 13px;\n            color: #999;\n            letter-spacing: 6px;\n            line-height: 24px;\n            text-transform: uppercase;\n            margin-bottom: 12px;\n            margin-top: 40px;\n          }\n          .link-list {\n            display: grid;\n            grid-template-columns: 1fr;\n            grid-template-rows: 1fr 1fr;\n            row-gap: 10px;\n          }\n        \\`}</style>\n      `)\n      )\n    ).toMatchInlineSnapshot(`\n      import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from \"react/jsx-runtime\";\n      import {useMDXComponents as _provideComponents} from \"@mdx-js/react\";\n      import {Meta} from '@storybook/addon-docs/blocks';\n      function _createMdxContent(props) {\n        return _jsxs(_Fragment, {\n          children: [_jsx(Meta, {\n            title: \"Example/Introduction\"\n          }), \"\\\\n\", _jsx(\"style\", {\n            children: \\`\n      .subheading {\n        --mediumdark: '#999999';\n        font-weight: 900;\n        font-size: 13px;\n        color: #999;\n        letter-spacing: 6px;\n        line-height: 24px;\n        text-transform: uppercase;\n        margin-bottom: 12px;\n        margin-top: 40px;\n      }\n      .link-list {\n        display: grid;\n        grid-template-columns: 1fr;\n        grid-template-rows: 1fr 1fr;\n        row-gap: 10px;\n      }\n      \\`\n          })]\n        });\n      }\n    `);\n  });\n});\n"
  },
  {
    "path": "code/addons/docs/src/compiler/index.ts",
    "content": "import { compile as mdxCompile, compileSync as mdxCompileSync } from '@mdx-js/mdx';\n\nimport type { CompileOptions, MdxCompileOptions } from './types';\n\nexport type { CompileOptions, MdxCompileOptions };\n\nexport const compile = async (input: string, { mdxCompileOptions = {} }: CompileOptions = {}) => {\n  const options = getCompilerOptions(mdxCompileOptions);\n\n  const mdxResult = await mdxCompile(input, options);\n\n  return mdxResult.toString();\n};\n\nexport const compileSync = (input: string, { mdxCompileOptions = {} }: CompileOptions = {}) => {\n  const options = getCompilerOptions(mdxCompileOptions);\n\n  const mdxResult = mdxCompileSync(input, options);\n\n  return mdxResult.toString();\n};\n\nfunction getCompilerOptions(mdxCompileOptions: MdxCompileOptions): MdxCompileOptions {\n  return {\n    providerImportSource: '@mdx-js/react',\n    rehypePlugins: [],\n    ...mdxCompileOptions,\n  };\n}\n"
  },
  {
    "path": "code/addons/docs/src/compiler/types.ts",
    "content": "import type { compile as mdxCompile } from '@mdx-js/mdx';\n\nexport type MdxCompileOptions = Parameters<typeof mdxCompile>[1];\n\nexport interface CompileOptions {\n  mdxCompileOptions?: MdxCompileOptions;\n}\n"
  },
  {
    "path": "code/addons/docs/src/ember/index.ts",
    "content": "export const setJSONDoc = (jsondoc: any) => {\n  // @ts-expect-error (Converted from ts-ignore)\n  globalThis.__EMBER_GENERATED_DOC_JSON__ = jsondoc;\n};\n"
  },
  {
    "path": "code/addons/docs/src/index.ts",
    "content": "import type React from 'react';\n\nimport { definePreviewAddon } from 'storybook/internal/csf';\n\nimport * as addonAnnotations from './preview';\nimport type { DocsTypes } from './types';\n\nexport { DocsRenderer } from './DocsRenderer';\nexport type { DocsTypes };\n\ndeclare module 'mdx/types' {\n  // eslint-disable-next-line @typescript-eslint/no-namespace\n  namespace JSX {\n    type Element = React.JSX.Element;\n    type ElementClass = React.JSX.ElementClass;\n    type IntrinsicElements = React.JSX.IntrinsicElements;\n  }\n}\n\nexport default () => definePreviewAddon<DocsTypes>(addonAnnotations);\n"
  },
  {
    "path": "code/addons/docs/src/manager.tsx",
    "content": "import React, { useEffect, useState } from 'react';\n\nimport { AddonPanel, type SyntaxHighlighterFormatTypes } from 'storybook/internal/components';\n\nimport { addons, types, useChannel, useParameter } from 'storybook/manager-api';\nimport { ignoreSsrWarning, styled, useTheme } from 'storybook/theming';\n\nimport {\n  ADDON_ID,\n  PANEL_ID,\n  PARAM_KEY,\n  SNIPPET_RENDERED,\n} from '../../../core/src/docs-tools/shared';\nimport type { SourceParameters } from './blocks/blocks';\nimport { Source } from './blocks/components/Source';\n\nconst CodePanel = ({\n  active,\n  lastEvent,\n  currentStoryId,\n}: {\n  active: boolean | undefined;\n  lastEvent: any | undefined;\n  currentStoryId: string | undefined;\n}) => {\n  const [codeSnippet, setSourceCode] = useState<{\n    source: string | undefined;\n    format: SyntaxHighlighterFormatTypes | undefined;\n  }>({\n    source: lastEvent?.source,\n    format: lastEvent?.format ?? undefined,\n  });\n\n  const parameter = useParameter(PARAM_KEY, {\n    source: { code: '' } as SourceParameters,\n    theme: 'dark',\n  });\n\n  useEffect(() => {\n    setSourceCode({\n      source: undefined,\n      format: undefined,\n    });\n  }, [currentStoryId]);\n\n  useChannel({\n    [SNIPPET_RENDERED]: ({ source, format }) => {\n      setSourceCode({ source, format });\n    },\n  });\n\n  const theme = useTheme();\n  const isDark = theme.base !== 'light';\n\n  return (\n    <AddonPanel active={!!active}>\n      <SourceStyles>\n        <Source\n          {...parameter.source}\n          code={parameter.source?.code || codeSnippet.source || parameter.source?.originalSource}\n          format={codeSnippet.format}\n          dark={isDark}\n        />\n      </SourceStyles>\n    </AddonPanel>\n  );\n};\n\naddons.register(ADDON_ID, (api) => {\n  addons.add(PANEL_ID, {\n    title: 'Code',\n    type: types.PANEL,\n    paramKey: PARAM_KEY,\n    /**\n     * This code panel can be enabled by adding this parameter:\n     *\n     * @example\n     *\n     * ```ts\n     *  parameters: {\n     *    docs: {\n     *      codePanel: true,\n     *    },\n     *  },\n     * ```\n     */\n    disabled: (parameters) => !parameters?.docs?.codePanel,\n    match: ({ viewMode }) => viewMode === 'story',\n    render: ({ active }) => {\n      const channel = api.getChannel();\n      const currentStory = api.getCurrentStoryData();\n\n      const lastEvent = channel?.last(SNIPPET_RENDERED)?.[0];\n\n      return <CodePanel currentStoryId={currentStory?.id} lastEvent={lastEvent} active={active} />;\n    },\n  });\n});\n\nconst SourceStyles = styled.div(() => ({\n  height: '100%',\n  [`> :first-child${ignoreSsrWarning}`]: {\n    margin: 0,\n    height: '100%',\n    boxShadow: 'none',\n  },\n}));\n"
  },
  {
    "path": "code/addons/docs/src/manifest.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { Tag } from 'storybook/internal/core-server';\nimport type { DocsIndexEntry, IndexEntry } from 'storybook/internal/types';\n\nimport { vol } from 'memfs';\n\nimport type { DocsManifestEntry } from './manifest';\nimport { manifests } from './manifest';\n\nvi.mock('node:fs/promises', async () => {\n  const memfs = await vi.importActual<typeof import('memfs')>('memfs');\n  return memfs.fs.promises;\n});\n\nbeforeEach(() => {\n  vi.spyOn(process, 'cwd').mockReturnValue('/app');\n  vol.fromJSON(\n    {\n      './Example.mdx': `import { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta summary=\"An example documentation page\" />\n\n# Example\n\nThis is example documentation.`,\n      './Standalone.mdx': `import { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta summary=\"A standalone documentation page\" />\n\n# Standalone\n\nThis is standalone documentation.`,\n    },\n    '/app'\n  );\n});\n\ninterface DocsManifest {\n  v: number;\n  docs: Record<string, DocsManifestEntry>;\n}\n\ninterface ComponentManifestWithDocs {\n  id: string;\n  path: string;\n  name: string;\n  stories: unknown[];\n  jsDocTags: Record<string, unknown>;\n  docs?: Record<string, DocsManifestEntry>;\n}\n\ninterface ComponentsManifestWithDocs {\n  v: number;\n  components: Record<string, ComponentManifestWithDocs>;\n}\n\ninterface ManifestResult {\n  docs?: DocsManifest;\n  components?: ComponentsManifestWithDocs;\n}\n\ndescribe('experimental_manifests', () => {\n  it('should return existing manifests when no docs entries are found', async () => {\n    const existingManifests = {\n      components: {\n        v: 0,\n        components: {\n          'example-component': {\n            id: 'example-component',\n            path: './Example.stories.tsx',\n            name: 'Example',\n            stories: [],\n            jsDocTags: {},\n          },\n        },\n      },\n    };\n    const manifestEntries: IndexEntry[] = [\n      {\n        id: 'example--story',\n        name: 'Story',\n        title: 'Example',\n        type: 'story',\n        subtype: 'story',\n        importPath: './Example.stories.tsx',\n        tags: [Tag.MANIFEST],\n      },\n    ];\n\n    const result = (await manifests(existingManifests, {\n      manifestEntries,\n    } as any)) as ManifestResult;\n\n    expect(result).toEqual(existingManifests);\n  });\n\n  it('should drop docs entries without attached-mdx or unattached-mdx tags', async () => {\n    const existingManifests = {\n      components: {\n        v: 0,\n        components: {\n          example: {\n            id: 'example',\n            path: './Example.stories.tsx',\n            name: 'Example',\n            stories: [],\n            jsDocTags: {},\n          },\n        },\n      },\n    };\n    const manifestEntries: IndexEntry[] = [\n      {\n        id: 'example--docs',\n        name: 'docs',\n        title: 'Example',\n        type: 'docs',\n        importPath: './Example.mdx',\n        tags: [Tag.MANIFEST, Tag.AUTODOCS], // No attached-mdx or unattached-mdx tag\n        storiesImports: ['./Example.stories.tsx'],\n      } satisfies DocsIndexEntry,\n    ];\n\n    const result = (await manifests(existingManifests, {\n      manifestEntries,\n    } as any)) as ManifestResult;\n\n    // Should return existing manifests unchanged since docs entry was dropped\n    expect(result).toEqual(existingManifests);\n    expect(result.components?.components.example.docs).toBeUndefined();\n  });\n\n  it('should add attached docs entries to component manifests', async () => {\n    const existingManifests = {\n      components: {\n        v: 0,\n        components: {\n          example: {\n            id: 'example',\n            path: './Example.stories.tsx',\n            name: 'Example',\n            stories: [],\n            jsDocTags: {},\n          },\n        },\n      },\n    };\n    const manifestEntries: IndexEntry[] = [\n      {\n        id: 'example--docs',\n        name: 'docs',\n        title: 'Example',\n        type: 'docs',\n        importPath: './Example.mdx',\n        tags: [Tag.MANIFEST, Tag.ATTACHED_MDX],\n        storiesImports: ['./Example.stories.tsx'],\n      } satisfies DocsIndexEntry,\n    ];\n\n    const result = (await manifests(existingManifests, {\n      manifestEntries,\n    } as any)) as ManifestResult;\n\n    expect(result).toHaveProperty('components');\n    expect(result).not.toHaveProperty('docs');\n    expect(result.components?.components.example.docs?.['example--docs']).toMatchObject({\n      id: 'example--docs',\n      name: 'docs',\n      path: './Example.mdx',\n      title: 'Example',\n      summary: 'An example documentation page',\n    });\n    expect(result.components?.components.example.docs?.['example--docs'].content).toContain(\n      'This is example documentation.'\n    );\n  });\n\n  it('should generate docs manifest for unattached-mdx entries', async () => {\n    const manifestEntries: IndexEntry[] = [\n      {\n        id: 'standalone--docs',\n        name: 'docs',\n        title: 'Standalone',\n        type: 'docs',\n        importPath: './Standalone.mdx',\n        tags: [Tag.MANIFEST, Tag.UNATTACHED_MDX],\n        storiesImports: [],\n      } satisfies DocsIndexEntry,\n    ];\n\n    const result = (await manifests(undefined, { manifestEntries } as any)) as ManifestResult;\n\n    expect(result).toHaveProperty('docs');\n    expect(result.docs?.docs['standalone--docs']).toMatchObject({\n      id: 'standalone--docs',\n      name: 'docs',\n      path: './Standalone.mdx',\n      title: 'Standalone',\n      summary: 'A standalone documentation page',\n    });\n    expect(result.docs?.docs['standalone--docs'].content).toContain(\n      'This is standalone documentation.'\n    );\n  });\n\n  it('should handle both attached and unattached docs entries separately', async () => {\n    const existingManifests = {\n      components: {\n        v: 0,\n        components: {\n          example: {\n            id: 'example',\n            path: './Example.stories.tsx',\n            name: 'Example',\n            stories: [],\n            jsDocTags: {},\n          },\n        },\n      },\n    };\n    const manifestEntries: IndexEntry[] = [\n      {\n        id: 'example--docs',\n        name: 'docs',\n        title: 'Example',\n        type: 'docs',\n        importPath: './Example.mdx',\n        tags: [Tag.MANIFEST, Tag.ATTACHED_MDX],\n        storiesImports: ['./Example.stories.tsx'],\n      } satisfies DocsIndexEntry,\n      {\n        id: 'standalone--docs',\n        name: 'docs',\n        title: 'Standalone',\n        type: 'docs',\n        importPath: './Standalone.mdx',\n        tags: [Tag.MANIFEST, Tag.UNATTACHED_MDX],\n        storiesImports: [],\n      } satisfies DocsIndexEntry,\n    ];\n\n    const result = (await manifests(existingManifests, {\n      manifestEntries,\n    } as any)) as ManifestResult;\n\n    // Unattached docs should be in the docs manifest\n    expect(result).toHaveProperty('docs');\n    expect(result.docs?.docs).toHaveProperty('standalone--docs');\n    expect(Object.keys(result.docs?.docs ?? {})).toHaveLength(1);\n    expect(result.docs?.docs['standalone--docs'].content).toContain(\n      'This is standalone documentation.'\n    );\n    expect(result.docs?.docs['standalone--docs'].summary).toBe('A standalone documentation page');\n\n    // Attached docs should be in the component manifest\n    expect(result.components?.components.example.docs?.['example--docs']).toMatchObject({\n      id: 'example--docs',\n      name: 'docs',\n      path: './Example.mdx',\n      title: 'Example',\n      summary: 'An example documentation page',\n    });\n    expect(result.components?.components.example.docs?.['example--docs'].content).toContain(\n      'This is example documentation.'\n    );\n  });\n\n  it('should preserve existing manifests and add unattached docs', async () => {\n    const existingManifests = {\n      components: {\n        v: 0,\n        components: {\n          example: {\n            id: 'example',\n            path: './Example.stories.tsx',\n            name: 'Example',\n            stories: [],\n            jsDocTags: {},\n          },\n        },\n      },\n    };\n    const manifestEntries: IndexEntry[] = [\n      {\n        id: 'standalone--docs',\n        name: 'docs',\n        title: 'Standalone',\n        type: 'docs',\n        importPath: './Standalone.mdx',\n        tags: [Tag.MANIFEST, Tag.UNATTACHED_MDX],\n        storiesImports: [],\n      } satisfies DocsIndexEntry,\n    ];\n\n    const result = (await manifests(existingManifests, {\n      manifestEntries,\n    } as any)) as ManifestResult;\n\n    expect(result).toHaveProperty('components');\n    expect(result).toHaveProperty('docs');\n    // Components should be preserved (no docs added since no attached docs entries)\n    expect(result.components?.components.example.docs).toBeUndefined();\n  });\n\n  it('should include error when file cannot be read for unattached docs', async () => {\n    const manifestEntries: IndexEntry[] = [\n      {\n        id: 'missing--docs',\n        name: 'docs',\n        title: 'Missing',\n        type: 'docs',\n        importPath: './NonExistent.mdx',\n        tags: [Tag.MANIFEST, Tag.UNATTACHED_MDX],\n        storiesImports: [],\n      } satisfies DocsIndexEntry,\n    ];\n\n    const result = (await manifests(undefined, { manifestEntries } as any)) as ManifestResult;\n\n    expect(result).toHaveProperty('docs');\n    expect(result.docs?.docs['missing--docs']).toEqual({\n      id: 'missing--docs',\n      name: 'docs',\n      path: './NonExistent.mdx',\n      title: 'Missing',\n      error: {\n        name: 'Error',\n        message: expect.stringContaining('ENOENT'),\n      },\n    });\n    expect(result.docs?.docs['missing--docs'].content).toBeUndefined();\n  });\n\n  it('should handle mixed success and error entries for unattached docs', async () => {\n    const manifestEntries: IndexEntry[] = [\n      {\n        id: 'standalone--docs',\n        name: 'docs',\n        title: 'Standalone',\n        type: 'docs',\n        importPath: './Standalone.mdx',\n        tags: [Tag.MANIFEST, Tag.UNATTACHED_MDX],\n        storiesImports: [],\n      } satisfies DocsIndexEntry,\n      {\n        id: 'missing--docs',\n        name: 'docs',\n        title: 'Missing',\n        type: 'docs',\n        importPath: './NonExistent.mdx',\n        tags: [Tag.MANIFEST, Tag.UNATTACHED_MDX],\n        storiesImports: [],\n      } satisfies DocsIndexEntry,\n    ];\n\n    const result = (await manifests(undefined, { manifestEntries } as any)) as ManifestResult;\n\n    expect(result).toHaveProperty('docs');\n    expect(Object.keys(result.docs?.docs ?? {})).toHaveLength(2);\n\n    // Successful entry\n    expect(result.docs?.docs['standalone--docs'].content).toContain(\n      'This is standalone documentation.'\n    );\n    expect(result.docs?.docs['standalone--docs'].summary).toBe('A standalone documentation page');\n    expect(result.docs?.docs['standalone--docs'].error).toBeUndefined();\n\n    // Failed entry\n    expect(result.docs?.docs['missing--docs'].content).toBeUndefined();\n    expect(result.docs?.docs['missing--docs'].error).toEqual({\n      name: 'Error',\n      message: expect.stringContaining('ENOENT'),\n    });\n  });\n\n  it('should include summary in unattached docs entries when available', async () => {\n    const manifestEntries: IndexEntry[] = [\n      {\n        id: 'standalone--docs',\n        name: 'docs',\n        title: 'Standalone',\n        type: 'docs',\n        importPath: './Standalone.mdx',\n        tags: [Tag.MANIFEST, Tag.UNATTACHED_MDX],\n        storiesImports: [],\n      } satisfies DocsIndexEntry,\n    ];\n\n    const result = (await manifests(undefined, { manifestEntries } as any)) as ManifestResult;\n\n    expect(result).toHaveProperty('docs');\n    expect(result.docs?.docs['standalone--docs'].summary).toBe('A standalone documentation page');\n  });\n\n  it('should include summary in attached docs entries when available', async () => {\n    const existingManifests = {\n      components: {\n        v: 0,\n        components: {\n          example: {\n            id: 'example',\n            path: './Example.stories.tsx',\n            name: 'Example',\n            stories: [],\n            jsDocTags: {},\n          },\n        },\n      },\n    };\n    const manifestEntries: IndexEntry[] = [\n      {\n        id: 'example--docs',\n        name: 'docs',\n        title: 'Example',\n        type: 'docs',\n        importPath: './Example.mdx',\n        tags: [Tag.MANIFEST, Tag.ATTACHED_MDX],\n        storiesImports: ['./Example.stories.tsx'],\n      } satisfies DocsIndexEntry,\n    ];\n\n    const result = (await manifests(existingManifests, {\n      manifestEntries,\n    } as any)) as ManifestResult;\n\n    expect(result.components?.components.example.docs?.['example--docs'].summary).toBe(\n      'An example documentation page'\n    );\n  });\n\n  it('should not include summary property when analyze returns no summary', async () => {\n    vol.fromJSON(\n      {\n        './NoSummary.mdx': '# No Summary\\n\\nThis content has no summary.',\n      },\n      '/app'\n    );\n\n    const manifestEntries: IndexEntry[] = [\n      {\n        id: 'nosummary--docs',\n        name: 'docs',\n        title: 'NoSummary',\n        type: 'docs',\n        importPath: './NoSummary.mdx',\n        tags: [Tag.MANIFEST, Tag.UNATTACHED_MDX],\n        storiesImports: [],\n      } satisfies DocsIndexEntry,\n    ];\n\n    const result = (await manifests(undefined, { manifestEntries } as any)) as ManifestResult;\n\n    expect(result).toHaveProperty('docs');\n    expect(result.docs?.docs['nosummary--docs'].content).toBe(\n      '# No Summary\\n\\nThis content has no summary.'\n    );\n    expect(result.docs?.docs['nosummary--docs'].summary).toBeUndefined();\n  });\n});\n"
  },
  {
    "path": "code/addons/docs/src/manifest.ts",
    "content": "import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\n\nimport { groupBy } from 'storybook/internal/common';\nimport { Tag, analyzeMdx } from 'storybook/internal/core-server';\nimport { logger } from 'storybook/internal/node-logger';\nimport type {\n  ComponentManifest,\n  DocsIndexEntry,\n  IndexEntry,\n  Manifests,\n  Path,\n  PresetPropertyFn,\n  StorybookConfigRaw,\n} from 'storybook/internal/types';\n\nexport interface DocsManifestEntry {\n  id: string;\n  name: string;\n  path: Path;\n  title: string;\n  content?: string;\n  summary?: string;\n  error?: { name: string; message: string };\n}\n\ninterface DocsManifest {\n  v: number;\n  docs: Record<string, DocsManifestEntry>;\n}\n\ninterface ComponentManifestWithDocs extends ComponentManifest {\n  docs?: Record<string, DocsManifestEntry>;\n}\n\ninterface ComponentsManifestWithDocs {\n  v: number;\n  components: Record<string, ComponentManifestWithDocs>;\n}\n\ninterface ManifestsWithDocs extends Manifests {\n  docs?: DocsManifest;\n  components?: ComponentsManifestWithDocs;\n}\n\n/** Converts a DocsIndexEntry to a DocsManifestEntry by reading its file content. */\nexport async function createDocsManifestEntry(entry: DocsIndexEntry): Promise<DocsManifestEntry> {\n  const absolutePath = path.join(process.cwd(), entry.importPath);\n  try {\n    const content = await fs.readFile(absolutePath, 'utf-8');\n\n    /*\n      TODO: This isn't the most performant option, as we're already analyzing the MDX file\n      during story index generation, and analyzing it requires compiling the file.\n      We should find a way to only do it once and cache/access the analysis somehow\n    */\n    const { summary } = await analyzeMdx(content);\n\n    return {\n      id: entry.id,\n      name: entry.name,\n      path: entry.importPath,\n      title: entry.title,\n      content,\n      ...(summary && { summary }),\n    };\n  } catch (err) {\n    return {\n      id: entry.id,\n      name: entry.name,\n      path: entry.importPath,\n      title: entry.title,\n      error: {\n        name: err instanceof Error ? err.name : 'Error',\n        message: err instanceof Error ? err.message : String(err),\n      },\n    };\n  }\n}\n\n/**\n * Extracts unattached MDX entries (standalone docs not attached to any component). These are added\n * to a separate `docs` manifest.\n */\nexport async function extractUnattachedDocsEntries(\n  entries: DocsIndexEntry[]\n): Promise<Record<string, DocsManifestEntry>> {\n  if (entries.length === 0) {\n    return {};\n  }\n  const entriesWithContent = await Promise.all(entries.map(createDocsManifestEntry));\n  return Object.fromEntries(entriesWithContent.map((entry) => [entry.id, entry]));\n}\n\n/**\n * Extracts attached docs entries by adding them to their corresponding component manifests.\n *\n * Returns the updated components manifest with docs added to each component.\n */\nexport async function extractAttachedDocsEntries(\n  entries: DocsIndexEntry[],\n  existingComponents: ComponentsManifestWithDocs | undefined\n): Promise<ComponentsManifestWithDocs | undefined> {\n  if (!existingComponents || entries.length === 0) {\n    return existingComponents;\n  }\n\n  const entriesWithContent = await Promise.all(entries.map(createDocsManifestEntry));\n\n  // Add docs to their corresponding components based on the entry id prefix\n  for (const docsEntry of entriesWithContent) {\n    const componentId = docsEntry.id.split('--')[0];\n\n    const component = existingComponents.components[componentId];\n    if (component) {\n      if (!component.docs) {\n        component.docs = {};\n      }\n      component.docs[docsEntry.id] = docsEntry;\n    }\n  }\n\n  return existingComponents;\n}\n\n/**\n * Generates a manifest of docs entries. This extends the existing manifest system to include docs\n * entries.\n *\n * - Unattached MDX entries (with 'unattached-mdx' tag) are added to a separate `docs` manifest.\n * - Attached MDX entries (with 'attached-mdx' tag) are added to their corresponding component\n *   manifests under a `docs` property.\n * - Docs entries without either tag are ignored.\n */\nexport const manifests: PresetPropertyFn<\n  'experimental_manifests',\n  StorybookConfigRaw,\n  { manifestEntries: IndexEntry[] }\n> = async (existingManifests = {}, { manifestEntries }) => {\n  const startPerformance = performance.now();\n\n  const docsEntries = manifestEntries.filter(\n    (entry): entry is DocsIndexEntry => entry.type === 'docs'\n  );\n\n  if (docsEntries.length === 0) {\n    return existingManifests;\n  }\n\n  const { attachedEntries = [], unattachedEntries = [] } = groupBy(docsEntries, (entry) => {\n    switch (true) {\n      case entry.tags?.includes(Tag.UNATTACHED_MDX):\n        return 'unattachedEntries';\n      case entry.tags?.includes(Tag.ATTACHED_MDX):\n        return 'attachedEntries';\n      default:\n        return 'ignored';\n    }\n  });\n\n  if (unattachedEntries.length === 0 && attachedEntries.length === 0) {\n    return existingManifests;\n  }\n\n  const existingManifestsWithDocs = existingManifests as ManifestsWithDocs;\n\n  const [unattachedDocs, updatedComponents] = await Promise.all([\n    extractUnattachedDocsEntries(unattachedEntries),\n    extractAttachedDocsEntries(attachedEntries, existingManifestsWithDocs.components),\n  ]);\n\n  const processedCount = unattachedEntries.length + attachedEntries.length;\n  logger.verbose(\n    `Docs manifest generation took ${performance.now() - startPerformance}ms for ${processedCount} entries (${unattachedEntries.length} unattached, ${attachedEntries.length} attached)`\n  );\n\n  const result = { ...existingManifestsWithDocs };\n\n  // Add unattached docs to the docs manifest\n  if (Object.keys(unattachedDocs).length > 0) {\n    result.docs = {\n      v: 0,\n      docs: unattachedDocs,\n    };\n  }\n\n  // Update the components manifest with attached docs\n  if (updatedComponents) {\n    result.components = updatedComponents;\n  }\n\n  return result;\n};\n"
  },
  {
    "path": "code/addons/docs/src/mdx-loader.ts",
    "content": "import type { compile as mdxCompile } from '@mdx-js/mdx';\n\nimport { compile } from './compiler';\n\nexport type MdxCompileOptions = Parameters<typeof mdxCompile>[1];\n\nexport interface CompileOptions {\n  mdxCompileOptions?: MdxCompileOptions;\n}\n\nconst DEFAULT_RENDERER = `\nimport React from 'react';\n`; // Adjust this import based on your actual webpack version and typings\n\n// Kind of like a mock so we don't have to install Webpack just for the types\ntype LoaderOptions = {\n  filepath?: string;\n  [key: string]: any;\n} & any;\n\ninterface LoaderContext {\n  async: () => (err: Error | null, result?: string) => void;\n  getOptions: () => LoaderOptions;\n  resourcePath: string;\n}\n\nasync function loader(this: LoaderContext, content: string): Promise<void> {\n  const callback = this.async();\n  const options = { ...this.getOptions(), filepath: this.resourcePath };\n\n  try {\n    const result = await compile(content, options);\n    const code = `${DEFAULT_RENDERER}\\n${result}`;\n    return callback(null, code);\n  } catch (err: any) {\n    console.error('Error loading:', this.resourcePath);\n    return callback(err);\n  }\n}\n\nexport default loader;\n"
  },
  {
    "path": "code/addons/docs/src/mdx-plugin.ts",
    "content": "import type { Options } from 'storybook/internal/types';\n\nimport { createFilter } from '@rollup/pluginutils';\nimport type { Plugin } from 'vite';\n\nimport type { CompileOptions } from './compiler';\nimport { compile } from './compiler';\n\n/**\n * Storybook uses a single loader when dealing with MDX:\n *\n * - *.mdx are compiled with the MDX compiler directly\n *\n * @see https://github.com/storybookjs/storybook/blob/next/addons/docs/docs/recipes.md#csf-stories-with-arbitrary-mdx\n */\nexport async function mdxPlugin(options: Options): Promise<Plugin> {\n  const include = /\\.mdx$/;\n  const filter = createFilter(include);\n  const { presets } = options;\n  const presetOptions = await presets.apply<Record<string, any>>('options', {});\n  const mdxPluginOptions = presetOptions?.mdxPluginOptions as CompileOptions;\n\n  const rehypeSlug = (await import('rehype-slug')).default;\n  const rehypeExternalLinks = (await import('rehype-external-links')).default;\n\n  return {\n    name: 'storybook:mdx-plugin',\n    enforce: 'pre',\n    transform: {\n      filter: { id: include },\n      async handler(src, id) {\n        if (!filter(id)) {\n          return undefined;\n        }\n\n        const mdxLoaderOptions: CompileOptions = await presets.apply('mdxLoaderOptions', {\n          ...mdxPluginOptions,\n          mdxCompileOptions: {\n            providerImportSource: import.meta.resolve('@storybook/addon-docs/mdx-react-shim'),\n            ...mdxPluginOptions?.mdxCompileOptions,\n            rehypePlugins: [\n              ...(mdxPluginOptions?.mdxCompileOptions?.rehypePlugins ?? []),\n              rehypeSlug,\n              rehypeExternalLinks,\n            ],\n          },\n        });\n\n        const code = String(await compile(src, mdxLoaderOptions));\n\n        return {\n          code,\n          // TODO: support source maps\n          map: null,\n        };\n      },\n    },\n  };\n}\n"
  },
  {
    "path": "code/addons/docs/src/mdx-react-shim.ts",
    "content": "export * from '@mdx-js/react';\n"
  },
  {
    "path": "code/addons/docs/src/preset.ts",
    "content": "import { isAbsolute } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { logger } from 'storybook/internal/node-logger';\nimport type { Options, PresetProperty, StorybookConfigRaw } from 'storybook/internal/types';\n\nimport type { CsfPluginOptions } from '@storybook/csf-plugin';\n\nimport { resolvePackageDir } from '../../../core/src/shared/utils/module';\nimport type { CompileOptions } from './compiler';\n\n/**\n * Get the resolvedReact preset, which points either to the user's react dependencies or the react\n * dependencies shipped with addon-docs if the user has not installed react explicitly.\n */\nconst getResolvedReact = async (options: Options) => {\n  const resolvedReact = (await options.presets.apply('resolvedReact', {})) as any;\n  // resolvedReact should always be set by the time we get here, but just in case, we'll default to addon-docs's react dependencies\n  return {\n    react: resolvedReact.react ?? resolvePackageDir('react'),\n    reactDom: resolvedReact.reactDom ?? resolvePackageDir('react-dom'),\n    // In Webpack, symlinked MDX files will cause @mdx-js/react to not be resolvable if it is not hoisted\n    // This happens for the SB monorepo's template stories when a sandbox has a different react version than\n    // addon-docs, causing addon-docs's dependencies not to be hoisted.\n    // This might also affect regular users who have a similar setup.\n    // Explicitly alias @mdx-js/react to avoid this issue.\n    mdx: resolvedReact.mdx ?? fileURLToPath(import.meta.resolve('@mdx-js/react')),\n  };\n};\n\nasync function webpack(\n  webpackConfig: any = {},\n  options: Options & {\n    csfPluginOptions: CsfPluginOptions | null;\n    mdxPluginOptions?: CompileOptions;\n  } /* & Parameters<\n      typeof createCompiler\n    >[0] */\n) {\n  const { module = {} } = webpackConfig;\n\n  const { csfPluginOptions = {}, mdxPluginOptions = {} } = options;\n\n  const enrichCsf = await options.presets.apply('experimental_enrichCsf');\n\n  const rehypeSlug = (await import('rehype-slug')).default;\n  const rehypeExternalLinks = (await import('rehype-external-links')).default;\n\n  const mdxLoaderOptions: CompileOptions = await options.presets.apply('mdxLoaderOptions', {\n    ...mdxPluginOptions,\n    mdxCompileOptions: {\n      providerImportSource: import.meta.resolve('@storybook/addon-docs/mdx-react-shim'),\n      ...mdxPluginOptions.mdxCompileOptions,\n      rehypePlugins: [\n        ...(mdxPluginOptions?.mdxCompileOptions?.rehypePlugins ?? []),\n        rehypeSlug,\n        rehypeExternalLinks,\n      ],\n    },\n  });\n\n  logger.info(`Addon-docs: using MDX3`);\n\n  // Use the resolvedReact preset to alias react and react-dom to either the users version or the version shipped with addon-docs\n  const { react, reactDom, mdx } = await getResolvedReact(options);\n\n  let alias;\n\n  /**\n   * Add aliases for `@storybook/addon-docs` & `@storybook/blocks` These must be singletons to avoid\n   * multiple instances of react & emotion being loaded, both would cause the components to fail to\n   * render.\n   */\n  if (Array.isArray(webpackConfig.resolve?.alias)) {\n    alias = [...webpackConfig.resolve?.alias];\n    alias.push(\n      {\n        name: 'react',\n        alias: react,\n      },\n      {\n        name: 'react-dom',\n        alias: reactDom,\n      },\n      {\n        name: '@mdx-js/react',\n        alias: mdx,\n      }\n    );\n  } else {\n    alias = {\n      ...webpackConfig.resolve?.alias,\n      react,\n      'react-dom': reactDom,\n      '@mdx-js/react': mdx,\n    };\n  }\n\n  const result = {\n    ...webpackConfig,\n    plugins: [\n      ...(webpackConfig.plugins || []),\n\n      ...(csfPluginOptions\n        ? [\n            (await import('@storybook/csf-plugin')).webpack({\n              ...csfPluginOptions,\n              enrichCsf,\n            }),\n          ]\n        : []),\n    ],\n    resolve: {\n      ...webpackConfig.resolve,\n      alias,\n    },\n    module: {\n      ...module,\n      rules: [\n        ...(module.rules || []),\n        {\n          test: /\\.mdx$/,\n          exclude: /(stories|story)\\.mdx$/,\n          use: [\n            {\n              loader: fileURLToPath(import.meta.resolve('@storybook/addon-docs/mdx-loader')),\n              options: mdxLoaderOptions,\n            },\n          ],\n        },\n      ],\n    },\n  };\n\n  return result;\n}\n\nconst docs: PresetProperty<'docs'> = (input = {}, options) => {\n  if (options?.build?.test?.disableAutoDocs) {\n    return undefined;\n  }\n\n  const result: StorybookConfigRaw['docs'] = {\n    ...input,\n    defaultName: 'Docs',\n  };\n\n  const docsMode = options.docs;\n  if (docsMode) {\n    result.docsMode = docsMode;\n  }\n  return result;\n};\n\nexport const addons: PresetProperty<'addons'> = [\n  import.meta.resolve('@storybook/react-dom-shim/preset'),\n];\n\nexport const viteFinal = async (config: any, options: Options) => {\n  const { plugins = [] } = config;\n\n  const { mdxPlugin } = await import('./mdx-plugin');\n\n  // Use the resolvedReact preset to alias react and react-dom to either the users version or the version shipped with addon-docs\n  const { react, reactDom, mdx } = await getResolvedReact(options);\n\n  const packageDeduplicationPlugin = {\n    name: 'storybook:package-deduplication',\n    enforce: 'pre',\n    config: () => ({\n      resolve: {\n        alias: {\n          react,\n          // Vite doesn't respect export maps when resolving an absolute path, so we need to do that manually here\n          ...(isAbsolute(reactDom) && { 'react-dom/server': `${reactDom}/server.browser.js` }),\n          'react-dom': reactDom,\n          '@mdx-js/react': mdx,\n        },\n      },\n    }),\n  };\n\n  // add alias plugin early to ensure any other plugins that also add the aliases will override this\n  // eg. the preact vite plugin adds its own aliases\n  plugins.unshift(packageDeduplicationPlugin);\n  // mdx plugin needs to be before any react plugins\n  plugins.unshift(mdxPlugin(options));\n\n  return {\n    ...config,\n    plugins,\n  };\n};\n\n/*\n * This is a workaround for https://github.com/Swatinem/rollup-plugin-dts/issues/162\n * something down the dependency chain is using typescript namespaces, which are not supported by rollup-plugin-dts\n */\nconst webpackX = webpack as any;\nconst docsX = docs as any;\n\n/**\n * If the user has not installed react explicitly in their project, the resolvedReact preset will\n * not be set. We then set it here in addon-docs to use addon-docs's react version that always\n * exists. This is just a fallback that never overrides the existing preset, but ensures that there\n * is always a resolved react.\n */\nexport const resolvedReact = async (existing: any) => ({\n  react: existing?.react ?? resolvePackageDir('react'),\n  reactDom: existing?.reactDom ?? resolvePackageDir('react-dom'),\n  mdx: existing?.mdx ?? fileURLToPath(import.meta.resolve('@mdx-js/react')),\n});\n\nconst optimizeViteDeps = [\n  '@storybook/addon-docs',\n  '@storybook/addon-docs/blocks',\n  '@storybook/addon-docs > @mdx-js/react',\n  '@storybook/addon-docs > @storybook/react-dom-shim',\n  'react-dom/client',\n  'react/jsx-runtime',\n  'react',\n];\n\nexport { webpackX as webpack, docsX as docs, optimizeViteDeps };\nexport { manifests as experimental_manifests } from './manifest';\n"
  },
  {
    "path": "code/addons/docs/src/preview.ts",
    "content": "import type { PreparedStory } from 'storybook/internal/types';\n\nconst excludeTags = Object.entries(globalThis.TAGS_OPTIONS ?? {}).reduce(\n  (acc, entry) => {\n    const [tag, option] = entry;\n    if ((option as any).excludeFromDocsStories) {\n      acc[tag] = true;\n    }\n    return acc;\n  },\n  {} as Record<string, boolean>\n);\n\nexport const parameters: any = {\n  docs: {\n    renderer: async () => {\n      const { DocsRenderer } = (await import('./DocsRenderer')) as any;\n      return new DocsRenderer();\n    },\n    stories: {\n      filter: (story: PreparedStory) => {\n        const tags = story.tags || [];\n        return (\n          tags.filter((tag) => excludeTags[tag]).length === 0 && !story.parameters.docs?.disable\n        );\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/src/types.ts",
    "content": "import type { ComponentType } from 'react';\n\nimport type { ModuleExport, ModuleExports } from 'storybook/internal/types';\n\nimport type { ThemeVars } from 'storybook/theming';\n\nimport type { DocsContainerProps } from './blocks/blocks';\nimport type { TocParameters } from './blocks/components';\n\ntype StoryBlockParameters = {\n  /** Whether a story's play function runs when shown in docs page */\n  autoplay?: boolean;\n  /**\n   * Set a minimum height (note for an iframe this is the actual height) when rendering a story in\n   * an iframe or inline. This overrides `parameters.docs.story.iframeHeight` for iframes.\n   */\n  height?: string;\n  /** IFrame configuration */\n  iframeHeight?: string;\n  /**\n   * Whether the story is rendered inline (in the same browser frame as the other docs content) or\n   * in an iframe\n   */\n  inline?: boolean;\n  /** Specifies the CSF file to which the story is associated */\n  meta: ModuleExports;\n  /**\n   * Specifies which story is rendered by the Story block. If no `of` is defined and the MDX file is\n   * attached, the primary (first) story will be rendered.\n   */\n  of: ModuleExport;\n};\n\ntype ControlsBlockParameters = {\n  /** Exclude specific properties from the Controls panel */\n  exclude?: string[] | RegExp;\n\n  /** Exclude only specific properties in the Controls panel */\n  include?: string[] | RegExp;\n\n  /** Controls sorting order */\n  sort?: 'none' | 'alpha' | 'requiredFirst';\n};\n\ntype ArgTypesBlockParameters = {\n  /** Exclude specific arg types from the args table */\n  exclude?: string[] | RegExp;\n\n  /** Exclude only specific arg types from the args table */\n  include?: string[] | RegExp;\n\n  /**\n   * Specifies which story to get the arg types from. If a CSF file exports is provided, it will use\n   * the primary (first) story in the file.\n   */\n  of: ModuleExport | ModuleExports;\n\n  /**\n   * Controls arg types order\n   *\n   * @see https://storybook.js.org/docs/api/doc-blocks/doc-block-argtypes#sort\n   */\n  sort?: 'none' | 'alpha' | 'requiredFirst';\n};\n\ntype CanvasBlockParameters = {\n  /**\n   * Provides any additional custom actions to show in the bottom right corner. These are simple\n   * buttons that do anything you specify in the onClick function.\n   */\n  additionalActions?: {\n    className?: string;\n    disabled?: boolean;\n    onClick: () => void;\n    title: string | React.JSX.Element;\n  }[];\n  /** Provide HTML class(es) to the preview element, for custom styling. */\n  className?: string;\n  /**\n   * Specify how the canvas should layout the story.\n   *\n   * @see https://storybook.js.org/docs/api/doc-blocks/doc-block-canvas#layout\n   */\n  layout?: 'centered' | 'fullscreen' | 'padded';\n  /** Specifies which story is rendered */\n  of: ModuleExport;\n  /** Show story source code */\n  sourceState?: 'hidden' | 'shown' | 'none';\n  /**\n   * Story configuration\n   *\n   * @see https://storybook.js.org/docs/api/doc-blocks/doc-block-canvas#story\n   */\n  story?: StoryBlockParameters;\n  /** Disable story source code */\n  withSource?: 'open' | 'closed' | 'none';\n  /** Whether to render a toolbar containing tools to interact with the story. */\n  withToolbar?: 'open' | 'closed' | 'none';\n};\n\ntype DescriptionBlockParameters = {\n  /** Component description */\n  component?: string;\n  /** Story description */\n  story?: string;\n};\n\ntype SourceBlockParameters = {\n  /** The source code to be rendered. Will be inferred if not passed */\n  code?: string;\n  /** Whether to render the code in dark mode */\n  dark?: boolean;\n  /** Determines if decorators are rendered in the source code snippet. */\n  excludeDecorators?: boolean;\n  /**\n   * The formatting used on source code. Both true and 'dedent' have the same effect of removing any\n   * extraneous indentation. Supports all valid prettier parser names.\n   */\n  format?: boolean | 'dedent' | string;\n  // TODO: We could try to extract types from 'SupportedLanguages' in SyntaxHighlihter, but for now we inline them\n  /** Source code language */\n  language?:\n    | 'bash'\n    | 'css'\n    | 'graphql'\n    | 'html'\n    | 'json'\n    | 'jsextra'\n    | 'jsx'\n    | 'md'\n    | 'text'\n    | 'tsx'\n    | 'typescript'\n    | 'yml';\n  /**\n   * Specifies which story is rendered by the Source block. If no of is defined and the MDX file is\n   * attached, the primary (first) story will be rendered.\n   */\n  of: ModuleExport;\n  /** Source code transformations */\n  transform?: (code: string, storyContext: any) => string | Promise<string>;\n  /**\n   * Specifies how the source code is rendered.\n   *\n   * @default 'auto'\n   * @see https://storybook.js.org/docs/api/doc-blocks/doc-block-source#type\n   */\n  type?: 'auto' | 'code' | 'dynamic';\n};\n\nexport interface DocsParameters {\n  /**\n   * Docs configuration\n   *\n   * @see https://storybook.js.org/docs/writing-docs\n   */\n  docs?: {\n    /**\n     * The subtitle displayed when shown in docs page\n     *\n     * @see https://storybook.js.org/docs/api/doc-blocks/doc-block-argtypes\n     */\n    argTypes?: ArgTypesBlockParameters;\n\n    /**\n     * Canvas configuration when shown in docs page\n     *\n     * @see https://storybook.js.org/docs/api/doc-blocks/doc-block-canvas\n     */\n    canvas?: Partial<CanvasBlockParameters>;\n\n    /**\n     * Enable the Code panel.\n     *\n     * @see https://storybook.js.org/docs/writing-docs/code-panel\n     */\n    codePanel?: boolean;\n\n    /**\n     * Controls block configuration\n     *\n     * @see https://storybook.js.org/docs/api/doc-blocks/doc-block-controls\n     */\n    controls?: ControlsBlockParameters;\n\n    /**\n     * Customize the Docs Container\n     *\n     * @see https://storybook.js.org/docs/writing-docs/autodocs#customize-the-docs-container\n     */\n    container?: ComponentType<DocsContainerProps>;\n\n    /**\n     * Component/story description when shown in docs page\n     *\n     * @see https://storybook.js.org/docs/api/doc-blocks/doc-block-description#writing-descriptions\n     */\n    description?: DescriptionBlockParameters;\n\n    /** Remove the addon panel and disable the addon's behavior */\n    disable?: boolean;\n\n    /**\n     * Replace the default documentation template used by Storybook with your own\n     *\n     * @see https://storybook.js.org/docs/writing-docs/autodocs#write-a-custom-template\n     */\n    page?: ComponentType;\n\n    /**\n     * Source code configuration when shown in docs page\n     *\n     * @see https://storybook.js.org/docs/api/doc-blocks/doc-block-source\n     */\n    source?: Partial<SourceBlockParameters>;\n\n    /**\n     * Story configuration\n     *\n     * @see https://storybook.js.org/docs/api/doc-blocks/doc-block-story\n     */\n    story?: Partial<StoryBlockParameters>;\n\n    /**\n     * The subtitle displayed when shown in docs page\n     *\n     * @see https://storybook.js.org/docs/api/doc-blocks/doc-block-subtitle\n     */\n    subtitle?: string;\n\n    /**\n     * Override the default theme\n     *\n     * @see https://storybook.js.org/docs/writing-docs/autodocs#override-the-default-theme\n     */\n    theme?: ThemeVars;\n\n    /**\n     * The title displayed when shown in docs page\n     *\n     * @see https://storybook.js.org/docs/api/doc-blocks/doc-block-title\n     */\n    title?: string;\n\n    /**\n     * Configure the table of contents\n     *\n     * @see https://storybook.js.org/docs/writing-docs/autodocs#configure-the-table-of-contents\n     */\n    toc?: true | TocParameters;\n  };\n}\n\nexport interface DocsTypes {\n  parameters: DocsParameters;\n}\n"
  },
  {
    "path": "code/addons/docs/src/typings.d.ts",
    "content": "declare module '@egoist/vue-to-react';\ndeclare module 'acorn-jsx';\ndeclare module 'vue/dist/vue';\n\ndeclare var FEATURES: import('storybook/internal/types').StorybookConfigRaw['features'];\ndeclare var __DOCS_CONTEXT__: any;\ndeclare var PREVIEW_URL: any;\ndeclare var LOGLEVEL: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent' | undefined;\ndeclare var TAGS_OPTIONS: import('storybook/internal/types').TagsOptions;\n\ndeclare module '*.md';\ndeclare module '*.md?raw';\n"
  },
  {
    "path": "code/addons/docs/src/web-components/index.ts",
    "content": "// TODO: what is supposed to be here?\n\nexport {};\n"
  },
  {
    "path": "code/addons/docs/template/stories/codePanel/index.stories.tsx",
    "content": "export default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  tags: ['autodocs'],\n  parameters: {\n    chromatic: { disableSnapshot: true },\n    docs: {\n      codePanel: true,\n    },\n  },\n};\n\nexport const Default = { args: { label: 'Default' } };\n\nexport const CustomCode = {\n  args: { label: 'Custom code' },\n  parameters: {\n    docs: {\n      source: {\n        code: '<button>Custom code</button>',\n      },\n    },\n  },\n};\n\nexport const WithoutPanel = {\n  args: { label: 'Without panel' },\n  parameters: {\n    docs: {\n      codePanel: false,\n    },\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/template/stories/docs2/Error.mdx",
    "content": "{/* This file intentionally has an error */}\n\n<Story of={Something} />"
  },
  {
    "path": "code/addons/docs/template/stories/docs2/MetaOf.mdx",
    "content": "import { Meta, Story, Stories } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from './button.stories.ts';\n\n<Meta of={ButtonStories} />\n\n# Docs with of, but no name\n\nhello docs\n\n<Story of={ButtonStories.Basic} />\n\n<Stories />\n"
  },
  {
    "path": "code/addons/docs/template/stories/docs2/MetaOfNamed.mdx",
    "content": "import { Meta, Story, Stories } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from './button.stories.ts';\n\n<Meta of={ButtonStories} name=\"Doc Name\" />\n\n# Docs with of, and name\n\nhello docs\n\n<Story of={ButtonStories.Basic} />\n\n<Stories />\n"
  },
  {
    "path": "code/addons/docs/template/stories/docs2/NoTitle.mdx",
    "content": "# Unattached docs with no title\n\nhello docs\n"
  },
  {
    "path": "code/addons/docs/template/stories/docs2/ResolvedReact.jsx",
    "content": "import React, * as ReactExport from 'react';\nimport * as ReactDom from 'react-dom';\nimport * as ReactDomServer from 'react-dom/server';\n\nexport const ResolvedReact = () => {\n  return (\n    <>\n      <p>\n        <code>react</code>:{' '}\n        <code data-testid=\"component-react\">\n          {ReactExport.version ?? 'no version export found'}\n        </code>\n      </p>\n      <p>\n        <code>react-dom</code>:{' '}\n        <code data-testid=\"component-react-dom\">\n          {ReactDom.version ?? 'no version export found'}\n        </code>\n      </p>\n      <p>\n        <code>react-dom/server</code>:{' '}\n        <code data-testid=\"component-react-dom-server\">\n          {ReactDomServer.version ?? 'no version export found'}\n        </code>\n      </p>\n    </>\n  );\n};\n"
  },
  {
    "path": "code/addons/docs/template/stories/docs2/ResolvedReact.mdx",
    "content": "import { Meta } from '@storybook/addon-docs/blocks';\nimport * as ReactExport from 'react';\nimport * as ReactDom from 'react-dom';\nimport * as ReactDomServer from 'react-dom/server';\nimport { ResolvedReact } from './ResolvedReact';\n\n<Meta title=\"docs2/ResolvedReact\" name=\"MDX\"/>\n\nThis doc is used to display the resolved version of React and its related packages.\nAs long as `@storybook/addon-docs` is installed, `react` and `react-dom` should be available to import from and should resolve to the same version.\n\nThe MDX here ensures that it works in an MDX file.\n\n- See the [autodocs](/docs/addons-docs-docs2-resolvedreact--docs) for how it resolves in autodocs.\n- See the [Story](/story/addons-docs-docs2-resolvedreact--story) for how it resolves in the actual story.\n\n**Note: There appears to be a bug in the _production_ build of `react-dom`, where it reports version `18.2.0-next-9e3b772b8-20220608` while in fact version `18.2.0` is installed.**\n\n## In MDX\n\n<code>react</code>: <code data-testid=\"mdx-react\">{ReactExport.version ?? 'no version export found'}</code>\n\n<code>react-dom</code>: <code data-testid=\"mdx-react-dom\">{ReactDom.version ?? 'no version export found'}</code>\n\n<code>react-dom/server</code>: <code data-testid=\"mdx-react-dom-server\">{ReactDomServer.version ?? 'no version export found'}</code>\n\n## In `ResolvedReact` component\n\n<ResolvedReact />\n"
  },
  {
    "path": "code/addons/docs/template/stories/docs2/Tags.mdx",
    "content": "import { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta tags={['foo', 'bar']} />\n\n# Docs with tags\n\nhello docs"
  },
  {
    "path": "code/addons/docs/template/stories/docs2/Title.mdx",
    "content": "import { Meta, Subtitle } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Yabbadabbadooo\" />\n\n# Docs with title\n\n<Subtitle>Subtitle</Subtitle>\n\nhello docs\n"
  },
  {
    "path": "code/addons/docs/template/stories/docs2/UtfSymbolScroll.mdx",
    "content": "import { Meta } from '@storybook/addon-docs/blocks';\r\n\r\n<Meta title=\"UtfSymbolsScroll\" />\r\n\r\n## Instruction\r\n\r\n> Instruction below works only in iframe.html. Unknown code in normal mode (with manager) removes hash from url.\r\n\r\nClick on [link](#anchor-with-utf-symbols-абвг). That will jump scroll to anchor after green block below. Then reload page and \r\nit should smooth-scroll to that anchor. \r\n\r\n<div style={{ height: \"1500px\", background: \"green\", color: \"white\" }}>Space for scroll test</div>\r\n\r\n## Anchor with utf symbols (абвг)"
  },
  {
    "path": "code/addons/docs/template/stories/docs2/button.stories.ts",
    "content": "export default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  tags: ['autodocs'],\n  args: { onClick: () => console.log('clicked!') },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const Basic = {\n  args: { label: 'Basic' },\n};\n\nexport const One = {\n  args: { label: 'One' },\n};\n\nexport const Two = {\n  args: { label: 'Two' },\n};\n"
  },
  {
    "path": "code/addons/docs/template/stories/docs2/multiple-csf-files-a.stories.ts",
    "content": "export default {\n  title: 'Multiple CSF Files Same Title',\n  component: globalThis.__TEMPLATE_COMPONENTS__.Html,\n  tags: ['autodocs'],\n  args: {\n    content: '<p>paragraph</p>',\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const DefaultA = {};\n\nexport const SpanContent = {\n  args: { content: '<span>span</span>' },\n};\n\nexport const CodeContent = {\n  args: { content: '<code>code</code>' },\n};\n"
  },
  {
    "path": "code/addons/docs/template/stories/docs2/multiple-csf-files-b.stories.ts",
    "content": "export default {\n  title: 'Multiple CSF Files Same Title',\n  component: globalThis.__TEMPLATE_COMPONENTS__.Html,\n  tags: ['autodocs'],\n  args: {\n    content: '<p>paragraph</p>',\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const DefaultB = {};\n\nexport const H1Content = {\n  args: { content: '<h1>heading 1</h1>' },\n};\n\nexport const H2Content = {\n  args: { content: '<h2>heading 2</h2>' },\n};\n"
  },
  {
    "path": "code/addons/docs/template/stories/docs2/resolved-react.stories.ts",
    "content": "import * as ReactExport from 'react';\nimport * as ReactDom from 'react-dom';\nimport * as ReactDomServer from 'react-dom/server';\n\nimport { expect, within } from 'storybook/test';\n\n/**\n * This component is used to display the resolved version of React and its related packages. As long\n * as `@storybook/addon-docs` is installed, `react` and `react-dom` should be available to import\n * from and should resolve to the same version.\n *\n * The autodocs here ensures that it also works in the generated documentation.\n *\n * - See the [MDX docs](/docs/addons-docs-docs2-resolvedreact--mdx) for how it resolves in MDX.\n * - See the [Story](/story/addons-docs-docs2-resolvedreact--story) for how it resolves in the actual\n *   story.\n *\n * **Note: There appears to be a bug in the _production_ build of `react-dom`, where it reports\n * version `18.2.0-next-9e3b772b8-20220608` while in fact version `18.2.0` is installed.**\n */\nexport default {\n  title: 'Docs2/ResolvedReact',\n  component: globalThis.__TEMPLATE_COMPONENTS__.Html,\n  tags: ['autodocs'],\n  argTypes: {\n    content: { table: { disable: true } },\n  },\n  args: {\n    content: `\n      <p>\n        <code>react</code>: <code data-testid=\"react\">${\n          ReactExport.version ?? 'no version export found'\n        }</code>\n      </p>\n      <p>\n        <code>react-dom</code>: <code data-testid=\"react-dom\">${\n          ReactDom.version ?? 'no version export found'\n        }</code>\n      </p>\n      <p>\n        <code>react-dom/server</code>: <code data-testid=\"react-dom-server\">${\n          ReactDomServer.version ?? 'no version export found'\n        }</code>\n      </p>\n  `,\n  },\n  parameters: {\n    docs: {\n      name: 'ResolvedReact',\n    },\n    // the version string changes with every release of React/Next.js/Preact, not worth snapshotting\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const Story = {\n  // This test is more or less the same as the E2E test we have for MDX and autodocs entries in addon-docs.spec.ts\n  play: async ({ canvasElement, step, parameters }: any) => {\n    const canvas = await within(canvasElement);\n\n    const actualReactVersion = (await canvas.findByTestId('react')).textContent;\n    const actualReactDomVersion = (await canvas.findByTestId('react-dom')).textContent;\n    const actualReactDomServerVersion = (await canvas.findByTestId('react-dom-server')).textContent;\n\n    step('Expect React packages to all resolve to the same version', async () => {\n      // react-dom has a bug in its production build, reporting version 18.2.0-next-9e3b772b8-20220608 even though version 18.2.0 is installed.\n      await expect(actualReactDomVersion!.startsWith(actualReactVersion!)).toBeTruthy();\n\n      if (parameters.renderer === 'preact') {\n        // the preact/compat alias doesn't have a version export in react-dom/server\n        return;\n      }\n      await expect(actualReactDomServerVersion).toBe(actualReactVersion);\n    });\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/template/stories/docspage/autoplay.stories.ts",
    "content": "import { expect, within } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  tags: ['autodocs'],\n  args: { text: 'Play has not run' },\n  parameters: { chromatic: { disableSnapshot: true } },\n};\n\n// Should not autoplay\nexport const NoAutoplay = {\n  play: async ({ viewMode, canvasElement }) => {\n    const pre = await within(canvasElement).findByText('Play has not run');\n    if (viewMode === 'docs') {\n      pre.innerText = 'Play should not have run!';\n      // Sort of pointless\n      expect(viewMode).not.toBe('docs');\n    } else {\n      pre.innerText = 'Play has run';\n    }\n  },\n};\n\n// Should autoplay\nexport const Autoplay = {\n  parameters: { docs: { story: { autoplay: true } } },\n  play: async ({ canvasElement }) => {\n    const pre = await within(canvasElement).findByText('Play has not run');\n    pre.innerText = 'Play has run';\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/template/stories/docspage/basic.stories.ts",
    "content": "import { fn } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  tags: ['autodocs'],\n  args: { label: 'Click Me!', onClick: fn() },\n  parameters: { chromatic: { disableSnapshot: true } },\n};\n\n/** A basic button */\nexport const Basic = {\n  args: { label: 'Basic' },\n};\n\n/** Won't show up in DocsPage */\nexport const Disabled = {\n  args: { label: 'Disabled in DocsPage' },\n  parameters: { docs: { disable: true } },\n};\n\n/** Another button, just to show multiple stories */\nexport const Another = {\n  args: { label: 'Another' },\n  parameters: {\n    docs: {\n      source: {\n        type: 'code',\n      },\n    },\n  },\n  play: async () => {\n    await new Promise((resolve) => resolve('Play function'));\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/template/stories/docspage/description.stories.ts",
    "content": "export default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  subcomponents: {\n    Pre: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  },\n  tags: ['autodocs'],\n  args: { label: 'Click Me!' },\n  parameters: {\n    docs: {\n      description: {\n        component: '**Component** description',\n      },\n    },\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const Basic = {};\n\nexport const CustomDescription = {\n  parameters: {\n    docs: {\n      description: {\n        story: '**Story** description',\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/template/stories/docspage/error.stories.ts",
    "content": "/* eslint-disable local-rules/no-uncategorized-errors */\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  tags: ['autodocs', '!test', '!vitest'],\n  args: { label: 'Click Me!' },\n  parameters: { chromatic: { disableSnapshot: true } },\n};\n\n/** A story that throws */\nexport const ErrorStory = {\n  decorators: [\n    () => {\n      const err = new Error('Story did something wrong');\n      err.stack = `\n        at errorStory (/sb-preview/file.js:000:0001)\n        at hookified (/sb-preview/file.js:000:0001)\n        at defaultDecorateStory (/sb-preview/file.js:000:0001)\n        at jsxDecorator (/assets/file.js:000:0001)\n        at hookified (/sb-preview/file.js:000:0001)\n        at decorateStory (/sb-preview/file.js:000:0001)\n      `;\n      throw err;\n    },\n  ],\n};\n"
  },
  {
    "path": "code/addons/docs/template/stories/docspage/extract-description.stories.ts",
    "content": "export default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  tags: ['autodocs'],\n  args: { label: 'Click Me!' },\n  parameters: {\n    docs: {\n      // FIXME: this is typically provided by the renderer preset to extract\n      //   the description automatically based on docgen info. including here\n      //   for documentation purposes only.\n      extractComponentDescription: () => 'component description',\n    },\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const Basic = {};\n"
  },
  {
    "path": "code/addons/docs/template/stories/docspage/iframe.stories.ts",
    "content": "export default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  tags: ['autodocs'],\n  args: { label: 'Rendered in iframe' },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n    docs: {\n      story: {\n        iframeHeight: '120px',\n        inline: true,\n      },\n    },\n  },\n};\n\nexport const Basic = {};\n"
  },
  {
    "path": "code/addons/docs/template/stories/docspage/overflow.stories.ts",
    "content": "export default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  tags: ['autodocs'],\n  args: {\n    text: 'Demonstrates overflow',\n    style: { width: 2000, height: 500, background: 'hotpink' },\n  },\n  parameters: { chromatic: { disableSnapshot: true } },\n};\n\nexport const Basic = {};\n"
  },
  {
    "path": "code/addons/docs/template/stories/docspage/override.stories.ts",
    "content": "// FIXME: do this using basic React functions for multi-framework\n//        once sandbox linking is working\n//\n// import { createElement } from 'react';\n// import { Title, Primary } from '@storybook/addon-docs/blocks';\n//\n// const Override = () =>\n//   createElement('div', { style: { border: '10px solid green', padding: '100px' } }, [\n//     createElement(Title),\n//     createElement(Primary),\n//   ]);\nconst Override = () => 'overridden';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  tags: ['autodocs'],\n  args: { label: 'Click Me!' },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n    docs: { page: Override },\n  },\n};\n\nexport const Basic = {};\n"
  },
  {
    "path": "code/addons/docs/template/stories/docspage/source.stories.ts",
    "content": "import type { StoryContext } from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  tags: ['autodocs'],\n  args: { label: 'Click Me!' },\n  parameters: { chromatic: { disableSnapshot: true } },\n};\n\nexport const Auto = {};\n\nexport const Disabled = {\n  parameters: {\n    docs: {\n      source: { code: null },\n    },\n  },\n};\n\nexport const Code = {\n  parameters: {\n    docs: {\n      source: { type: 'code' },\n    },\n  },\n};\n\nexport const Custom = {\n  parameters: {\n    docs: {\n      source: { code: 'custom source' },\n    },\n  },\n};\n\nexport const Transform = {\n  parameters: {\n    docs: {\n      source: {\n        transform(src: string, storyContext: StoryContext) {\n          return dedent`// We transformed this!\n          // The current args are: ${JSON.stringify(storyContext.args)}\n          const example = (${src});\n          `;\n        },\n      },\n    },\n  },\n};\n\nexport const AsyncTransform = {\n  parameters: {\n    docs: {\n      source: {\n        async transform(src: string, storyContext: StoryContext) {\n          return new Promise<string>((res) =>\n            setTimeout(() => {\n              res(dedent`// We transformed this asynchronously!\n                // The current args are: ${JSON.stringify(storyContext.args)}\n                const example = (${src});\n                `);\n            }, 500)\n          );\n        },\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "code/addons/docs/template/stories/toc/basic.stories.ts",
    "content": "export default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  tags: ['autodocs'],\n  parameters: {\n    chromatic: { disableSnapshot: true },\n    docs: { toc: {} },\n  },\n};\n\nexport const One = { args: { label: 'One' } };\nexport const Two = { args: { label: 'Two' } };\nexport const Three = { args: { label: 'Three' } };\n"
  },
  {
    "path": "code/addons/docs/template/stories/toc/custom-selector.stories.ts",
    "content": "export default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  tags: ['autodocs'],\n  parameters: {\n    chromatic: { disableSnapshot: true },\n    // Select all the headings in the document\n    docs: { toc: { headingSelector: 'h1, h2, h3' } },\n  },\n};\n\nexport const One = { args: { label: 'One' } };\nexport const Two = { args: { label: 'Two' } };\nexport const Three = { args: { label: 'Three' } };\n"
  },
  {
    "path": "code/addons/docs/template/stories/toc/custom-title.stories.ts",
    "content": "export default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  tags: ['autodocs'],\n  parameters: {\n    chromatic: { disableSnapshot: true },\n    // Custom title label\n    docs: { toc: { title: 'Contents' } },\n  },\n};\n\nexport const One = { args: { label: 'One' } };\nexport const Two = { args: { label: 'Two' } };\nexport const Three = { args: { label: 'Three' } };\n"
  },
  {
    "path": "code/addons/docs/template/stories/toc/ignore-selector.stories.ts",
    "content": "export default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  tags: ['autodocs'],\n  parameters: {\n    chromatic: { disableSnapshot: true },\n    // Skip the first story in the TOC\n    docs: { toc: { ignoreSelector: '#one' } },\n  },\n};\n\nexport const One = { args: { label: 'One' } };\nexport const Two = { args: { label: 'Two' } };\nexport const Three = { args: { label: 'Three' } };\n"
  },
  {
    "path": "code/addons/docs/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/addons/docs/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/addons/links/README.md",
    "content": "# Story Links Addon\n\nThe Storybook Links addon can be used to create links that navigate between stories in [Storybook](https://storybook.js.org?ref=readme).\n\n[Framework Support](https://storybook.js.org/docs/configure/integration/frameworks-feature-support?ref=readme)\n\n## Getting Started\n\nInstall this addon by adding the `@storybook/addon-links` dependency:\n\n```sh\nyarn add -D @storybook/addon-links\n```\n\nwithin `.storybook/main.js`:\n\n```js\nexport default {\n  addons: ['@storybook/addon-links'],\n};\n```\n\nThen you can import `linkTo` in your stories and use like this:\n\n```js\nimport { linkTo } from '@storybook/addon-links';\n\nexport default {\n  title: 'Button',\n};\n\nexport const first = () => <button onClick={linkTo('Button', 'second')}>Go to \"Second\"</button>;\nexport const second = () => <button onClick={linkTo('Button', 'first')}>Go to \"First\"</button>;\n```\n\nHave a look at the linkTo function:\n\n```js\nimport { linkTo } from '@storybook/addon-links';\n\nlinkTo('Toggle', 'off');\nlinkTo(\n  () => 'Toggle',\n  () => 'off'\n);\nlinkTo('Toggle'); // Links to the first story in the 'Toggle' kind\n```\n\nWith that, you can link an event in a component to any story in the Storybook.\n\n- First parameter is the story kind name (what you named with `title`).\n- Second (optional) parameter is the story name (what you named with `exported name`).\n  If the second parameter is omitted, the link will point to the first story in the given kind.\n\nYou can also pass a function instead for any of above parameter. That function accepts arguments emitted by the event and it should return a string:\n\n```js\nimport { linkTo } from '@storybook/addon-links';\nimport LinkTo from '@storybook/addon-links/react';\n\nexport default {\n  title: 'Select',\n};\n\nexport const index = () => (\n  <select value=\"Index\" onChange={linkTo('Select', (e) => e.currentTarget.value)}>\n    <option>index</option>\n    <option>first</option>\n    <option>second</option>\n    <option>third</option>\n  </select>\n);\nexport const first = () => <LinkTo story=\"index\">Go back</LinkTo>;\nexport const second = () => <LinkTo story=\"index\">Go back</LinkTo>;\nexport const third = () => <LinkTo story=\"index\">Go back</LinkTo>;\n```\n\n## hrefTo function\n\nIf you want to get an URL for a particular story, you may use `hrefTo` function. It returns a promise, which resolves to string containing a relative URL:\n\n```js\nimport { hrefTo } from '@storybook/addon-links';\nimport { action } from 'storybook/actions';\n\nexport default {\n  title: 'Href',\n};\n\nexport const log = () => {\n  hrefTo('Href', 'log').then(action('URL of this story'));\n\n  return <span>See action logger</span>;\n};\n```\n\n## withLinks decorator\n\n`withLinks` decorator enables a declarative way of defining story links, using data attributes.\nHere is an example in React, but it works with any framework:\n\n```js\nimport { withLinks } from '@storybook/addon-links';\n\nexport default {\n  title: 'Button',\n  decorators: [withLinks],\n};\n\nexport const first = () => (\n  <button data-sb-kind=\"OtherKind\" data-sb-story=\"otherStory\">\n    Go to \"OtherStory\"\n  </button>\n);\n```\n\n## LinkTo component (React only)\n\nOne possible way of using `hrefTo` is to create a component that uses native `a` element, but prevents page reloads on plain left click, so that one can still use default browser methods to open link in new tab.\nA React implementation of such a component can be imported from `@storybook/addon-links` package:\n\n```js\nimport LinkTo from '@storybook/addon-links/react';\n\nexport default {\n  title: 'Link',\n};\n\nexport const first = () => <LinkTo story=\"second\">Go to Second</LinkTo>;\nexport const second = () => <LinkTo story=\"first\">Go to First</LinkTo>;\n```\n\nIt accepts all the props the `a` element does, plus `story` and `kind`. It the `kind` prop is omitted, the current kind will be preserved.\n\n```mdx\n<LinkTo\n  kind=\"Toggle\"\n  story=\"off\"\n  target=\"_blank\"\n  title=\"link to second story\"\n  style={{ color: '#1474f3' }}\n>\n  Go to Second\n</LinkTo>\n```\n\nTo implement such a component for another framework, you need to add special handling for `click` event on native `a` element. See [`RoutedLink` sources](https://github.com/storybookjs/storybook/blob/next/code/addons/links/src/react/components/RoutedLink.tsx) for reference.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/addons/links/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./react'],\n        entryPoint: './src/react/index.ts',\n      },\n      {\n        exportEntries: ['./preview'],\n        entryPoint: './src/preview.ts',\n      },\n      {\n        exportEntries: ['./manager'],\n        entryPoint: './src/manager.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/addons/links/manager.js",
    "content": "import './dist/manager';\n"
  },
  {
    "path": "code/addons/links/package.json",
    "content": "{\n  \"name\": \"@storybook/addon-links\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook Links: Link stories together to build demos and prototypes with your UI components\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-addon\",\n    \"organize\",\n    \"links\",\n    \"navigation\",\n    \"component\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/addons/links\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/addons/links\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./manager\": \"./dist/manager.js\",\n    \"./package.json\": \"./package.json\",\n    \"./preview\": {\n      \"types\": \"./dist/preview.d.ts\",\n      \"code\": \"./src/preview.ts\",\n      \"default\": \"./dist/preview.js\"\n    },\n    \"./react\": {\n      \"types\": \"./dist/react/index.d.ts\",\n      \"code\": \"./src/react/index.ts\",\n      \"default\": \"./dist/react/index.js\"\n    }\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/global\": \"^5.0.0\"\n  },\n  \"devDependencies\": {\n    \"typescript\": \"^5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"storybook\": \"workspace:^\"\n  },\n  \"peerDependenciesMeta\": {\n    \"react\": {\n      \"optional\": true\n    }\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\",\n  \"storybook\": {\n    \"displayName\": \"Links\",\n    \"icon\": \"https://user-images.githubusercontent.com/263385/101991673-48355c80-3c7c-11eb-9b6e-b627c96a75f6.png\",\n    \"unsupportedFrameworks\": [\n      \"react-native\"\n    ]\n  }\n}\n"
  },
  {
    "path": "code/addons/links/preview.js",
    "content": "export * from './dist/preview';\n"
  },
  {
    "path": "code/addons/links/project.json",
    "content": "{\n  \"name\": \"addon-links\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/addons/links/react.d.ts",
    "content": "export * from './dist/react/index';\n"
  },
  {
    "path": "code/addons/links/react.js",
    "content": "import LinkTo from './dist/react/index';\n\nexport default LinkTo;\n"
  },
  {
    "path": "code/addons/links/scripts/fix-preview-api-reference.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\n\n/* I wish this wasn't needed..\n * There seems to be some bug in tsup / the unlaying lib that does DTS bundling\n * ...that makes it mess up the generation.\n */\nconst run = async () => {\n  const content = await readFile('./dist/index.d.ts', 'utf-8');\n\n  const regexp = /'lib\\/preview-api/;\n  const replaced = content.replace(regexp, \"'storybook/preview-api\");\n\n  await writeFile('./dist/index.d.ts', replaced);\n};\n\nrun().catch((error) => {\n  console.error(error);\n  process.exit(1);\n});\n"
  },
  {
    "path": "code/addons/links/src/constants.ts",
    "content": "export const ADDON_ID = 'storybook/links';\nexport const PARAM_KEY = `links`;\n\nexport default {\n  NAVIGATE: `${ADDON_ID}/navigate`,\n  REQUEST: `${ADDON_ID}/request`,\n  RECEIVE: `${ADDON_ID}/receive`,\n};\n"
  },
  {
    "path": "code/addons/links/src/index.ts",
    "content": "import { definePreviewAddon } from 'storybook/internal/csf';\n\nimport * as addonAnnotations from './preview.ts';\n\nexport { linkTo, hrefTo, withLinks, navigate } from './utils.ts';\n\nexport default () => definePreviewAddon(addonAnnotations);\n"
  },
  {
    "path": "code/addons/links/src/manager.ts",
    "content": "import { addons } from 'storybook/manager-api';\n\nimport EVENTS, { ADDON_ID } from './constants.ts';\n\naddons.register(ADDON_ID, (api) => {\n  api.on(EVENTS.REQUEST, ({ kind, name }) => {\n    const id = api.storyId(kind, name);\n    api.emit(EVENTS.RECEIVE, id);\n  });\n});\n"
  },
  {
    "path": "code/addons/links/src/preview.ts",
    "content": "import { withLinks } from './index.ts';\n\nexport const decorators = [withLinks];\n"
  },
  {
    "path": "code/addons/links/src/react/components/link.test.tsx",
    "content": "// @vitest-environment happy-dom\n/// <reference types=\"@testing-library/jest-dom\" />\nimport { act, cleanup, render, screen, waitFor } from '@testing-library/react';\nimport userEvent from '@testing-library/user-event';\nimport { afterEach, describe, expect, it, vi } from 'vitest';\n\nimport React from 'react';\n\nimport { SELECT_STORY } from 'storybook/internal/core-events';\n\nimport { addons } from 'storybook/preview-api';\n\nimport LinkTo from './link.tsx';\n\nvi.mock('storybook/preview-api');\nvi.mock('@storybook/global', () => ({\n  global: {\n    document: {\n      location: {\n        origin: 'origin',\n        pathname: 'pathname',\n        search: 'search',\n      },\n    },\n  },\n}));\n\nconst mockChannel = () => {\n  return {\n    emit: vi.fn(),\n    on: vi.fn(),\n    once: vi.fn(),\n  };\n};\nconst mockAddons = vi.mocked(addons);\n\ndescribe('LinkTo', () => {\n  describe('render', () => {\n    afterEach(() => {\n      cleanup();\n    });\n    it('should render a link', async () => {\n      const channel = mockChannel() as any;\n      mockAddons.getChannel.mockReturnValue(channel);\n\n      const { container } = render(\n        <LinkTo title=\"foo\" name=\"bar\">\n          link\n        </LinkTo>\n      );\n\n      await waitFor(() => {\n        expect(screen.getByText('link')).toHaveAttribute(\n          'href',\n          'originpathname?path=/story/foo--bar'\n        );\n      });\n      expect(container.firstChild).toMatchInlineSnapshot(`\n        <a\n          href=\"originpathname?path=/story/foo--bar\"\n        >\n          link\n        </a>\n      `);\n    });\n  });\n\n  describe('events', () => {\n    it('should select the kind and story on click', async () => {\n      const channel = {\n        emit: vi.fn(),\n        on: vi.fn(),\n      } as any;\n      mockAddons.getChannel.mockReturnValue(channel);\n\n      await act(async () => {\n        await render(\n          <LinkTo title=\"foo\" name=\"bar\">\n            link\n          </LinkTo>\n        );\n      });\n\n      expect(screen.getByText('link')).toHaveAttribute(\n        'href',\n        'originpathname?path=/story/foo--bar'\n      );\n\n      await userEvent.click(screen.getByText('link'));\n\n      expect(channel.emit).toHaveBeenLastCalledWith(\n        SELECT_STORY,\n        expect.objectContaining({\n          title: 'foo',\n          name: 'bar',\n        })\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "code/addons/links/src/react/components/link.tsx",
    "content": "import type { MouseEvent, ReactNode } from 'react';\nimport React, { PureComponent } from 'react';\n\nimport type { ComponentTitle, StoryKind, StoryName } from 'storybook/internal/types';\n\nimport { hrefTo, navigate } from '../../utils.ts';\n\n// FIXME: copied from Typography.Link. Code is duplicated to\n// avoid emotion dependency which breaks React 15.x back-compat\n\n// Cmd/Ctrl/Shift/Alt + Click should trigger default browser behaviour. Same applies to non-left clicks\nconst LEFT_BUTTON = 0;\n\nconst isPlainLeftClick = (e: MouseEvent<HTMLAnchorElement>) =>\n  e.button === LEFT_BUTTON && !e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey;\n\nconst cancelled = (e: MouseEvent<HTMLAnchorElement>, cb = (_e: any) => {}) => {\n  if (isPlainLeftClick(e)) {\n    e.preventDefault();\n    cb(e);\n  }\n};\n\ninterface Props {\n  kind?: StoryKind;\n  title?: ComponentTitle;\n  story?: StoryName;\n  name?: StoryName;\n  children: ReactNode;\n}\n\ninterface State {\n  href: string;\n}\n\nexport default class LinkTo extends PureComponent<Props, State> {\n  static defaultProps: Props = {\n    children: undefined,\n  };\n\n  state: State = {\n    href: '/',\n  };\n\n  componentDidMount() {\n    this.updateHref();\n  }\n\n  componentDidUpdate(prevProps: Props) {\n    const { kind, title, story, name } = this.props;\n\n    if (\n      prevProps.kind !== kind ||\n      prevProps.story !== story ||\n      prevProps.title !== title ||\n      prevProps.name !== name\n    ) {\n      this.updateHref();\n    }\n  }\n\n  updateHref = async () => {\n    const { kind, title = kind, story, name = story } = this.props;\n    if (title && name) {\n      const href = await hrefTo(title, name);\n      this.setState({ href });\n    }\n  };\n\n  handleClick = () => {\n    const { kind, title = kind, story, name = story } = this.props;\n    if (title && name) {\n      navigate({ title, name });\n    }\n  };\n\n  render() {\n    const { kind, title = kind, story, name = story, children, ...rest } = this.props;\n    const { href } = this.state;\n\n    return (\n      <a href={href} onClick={(e) => cancelled(e, this.handleClick)} {...rest}>\n        {children}\n      </a>\n    );\n  }\n}\n"
  },
  {
    "path": "code/addons/links/src/react/index.ts",
    "content": "import LinkTo from './components/link.tsx';\n\nexport default LinkTo;\n"
  },
  {
    "path": "code/addons/links/src/utils.test.ts",
    "content": "// @vitest-environment happy-dom\nimport { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { SELECT_STORY } from 'storybook/internal/core-events';\n\nimport { addons } from 'storybook/preview-api';\n\nimport { hrefTo, linkTo } from './utils.ts';\n\nvi.mock('storybook/preview-api');\nvi.mock('@storybook/global', () => ({\n  global: {\n    document: global.document,\n    window: global,\n  },\n}));\n\nconst mockAddons = vi.mocked(addons);\n\ndescribe('preview', () => {\n  const channel = { emit: vi.fn() };\n  beforeAll(() => {\n    mockAddons.getChannel.mockReturnValue(channel as any);\n  });\n  beforeEach(channel.emit.mockReset);\n  describe('linkTo()', () => {\n    it('should select the title and name provided', () => {\n      const handler = linkTo('title', 'name');\n      handler();\n\n      expect(channel.emit).toHaveBeenCalledWith(SELECT_STORY, {\n        kind: 'title',\n        story: 'name',\n      });\n    });\n\n    it('should select the title (only) provided', () => {\n      const handler = linkTo('title');\n      handler();\n\n      expect(channel.emit).toHaveBeenCalledWith(SELECT_STORY, {\n        kind: 'title',\n      });\n    });\n\n    it('should select the story (only) provided', () => {\n      // simulate a currently selected, but not found as ID\n      // @ts-expect-error (not strict)\n      const handler = linkTo(undefined, 'name');\n      handler();\n\n      expect(channel.emit).toHaveBeenCalledWith(SELECT_STORY, {\n        story: 'name',\n      });\n    });\n\n    it('should select the id provided', () => {\n      const handler = linkTo('title--name');\n      handler();\n\n      expect(channel.emit).toHaveBeenCalledWith(SELECT_STORY, {\n        storyId: 'title--name',\n      });\n    });\n\n    it('should handle functions returning strings', () => {\n      const handler = linkTo(\n        (a, b) => a + b,\n        (a, b) => b + a\n      );\n      handler('title', 'name');\n\n      expect(channel.emit.mock.calls).toContainEqual([\n        SELECT_STORY,\n        {\n          kind: 'titlename',\n          story: 'nametitle',\n        },\n      ]);\n    });\n  });\n\n  describe('hrefTo()', () => {\n    it('should return promise resolved with story href', async () => {\n      const href = await hrefTo('title', 'name');\n      expect(href).toContain('?path=/story/title--name');\n    });\n  });\n});\n"
  },
  {
    "path": "code/addons/links/src/utils.ts",
    "content": "import { SELECT_STORY, STORY_CHANGED } from 'storybook/internal/core-events';\nimport { toId } from 'storybook/internal/csf';\nimport type { ComponentTitle, StoryId, StoryKind, StoryName } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { addons, makeDecorator } from 'storybook/preview-api';\n\nimport { PARAM_KEY } from './constants.ts';\n\nconst { document, HTMLElement } = global;\n\ninterface ParamsId {\n  storyId: StoryId;\n}\ninterface ParamsCombo {\n  kind?: StoryKind;\n  title?: ComponentTitle;\n  story?: StoryName;\n  name?: StoryName;\n}\n\nfunction parseQuery(queryString: string) {\n  const query: Record<string, string> = {};\n  const pairs = (queryString[0] === '?' ? queryString.substring(1) : queryString)\n    .split('&')\n    .filter(Boolean);\n\n  for (let i = 0; i < pairs.length; i++) {\n    const pair = pairs[i].split('=');\n    query[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || '');\n  }\n  return query;\n}\n\nexport const navigate = (params: ParamsId | ParamsCombo) =>\n  addons.getChannel().emit(SELECT_STORY, params);\n\nexport const hrefTo = (title: ComponentTitle, name: StoryName): Promise<string> => {\n  return new Promise((resolve) => {\n    const { location } = document;\n    const query = parseQuery(location.search);\n    const existingId = query.id;\n    const titleToLink = title || existingId.split('--', 2)[0];\n    const id = toId(titleToLink, name);\n    const path = `/story/${id}`;\n\n    // Drop the `iframe.html` from the preview path\n    const sbPath = location.pathname.replace(/iframe\\.html$/, '');\n    const url = `${location.origin + sbPath}?${Object.entries({ path })\n      .map((item) => `${item[0]}=${item[1]}`)\n      .join('&')}`;\n\n    resolve(url);\n  });\n};\n\nconst valueOrCall = (args: string[]) => (value: string | ((...args: string[]) => string)) =>\n  typeof value === 'function' ? value(...args) : value;\n\nexport const linkTo =\n  (\n    idOrTitle: string | ((...args: any[]) => string),\n    nameInput?: string | ((...args: any[]) => string)\n  ) =>\n  (...args: any[]) => {\n    const resolver = valueOrCall(args);\n    const title = resolver(idOrTitle);\n    const name = nameInput ? resolver(nameInput) : false;\n\n    if (title?.match(/--/) && !name) {\n      navigate({ storyId: title });\n    } else if (name && title) {\n      navigate({ kind: title, story: name });\n    } else if (title) {\n      navigate({ kind: title });\n    } else if (name) {\n      navigate({ story: name });\n    }\n  };\n\nconst linksListener = (e: Event) => {\n  const { target } = e;\n  if (!(target instanceof HTMLElement)) {\n    return;\n  }\n  const element = target as HTMLElement;\n  const { sbKind: kind, sbStory: story } = element.dataset;\n  if (kind || story) {\n    e.preventDefault();\n    navigate({ kind, story });\n  }\n};\n\nlet hasListener = false;\n\nconst on = () => {\n  if (!hasListener) {\n    hasListener = true;\n    document.addEventListener('click', linksListener);\n  }\n};\nconst off = () => {\n  if (hasListener) {\n    hasListener = false;\n    document.removeEventListener('click', linksListener);\n  }\n};\n\nexport const withLinks = makeDecorator({\n  name: 'withLinks',\n  parameterName: PARAM_KEY,\n  wrapper: (getStory, context) => {\n    on();\n    addons.getChannel().once(STORY_CHANGED, off);\n    return getStory(context);\n  },\n});\n"
  },
  {
    "path": "code/addons/links/template/stories/decorator.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { withLinks } from '@storybook/addon-links';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Html,\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n  decorators: [withLinks],\n};\n\nexport const Target = {\n  args: {\n    content: `\n      <div>\n      This is just a story to target with the links\n      </div>\n    `,\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const KindAndStory = {\n  args: {\n    content: `\n      <div>\n        <a class=\"link\" href=\"#\" data-sb-kind=\"addons-links-decorator\" data-sb-story=\"story-only\">go to story only</a>\n      </div>\n    `,\n  },\n};\n\nexport const StoryOnly = {\n  args: {\n    content: `\n      <div>\n        <a class=\"link\" href=\"#\" data-sb-story=\"target\">go to target</a>\n      </div>\n    `,\n  },\n};\n\nexport const KindOnly = {\n  args: {\n    content: `\n      <div>\n        <a class=\"link\" href=\"#\" data-sb-kind=\"addons-links-decorator\">go to target</a>\n      </div>\n    `,\n  },\n};\n"
  },
  {
    "path": "code/addons/links/template/stories/hrefto.stories.ts",
    "content": "import { hrefTo } from '@storybook/addon-links';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Html,\n  title: 'hrefTo',\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n  args: {\n    content: '<div><code id=\"content\">Waiting for hrefTo to resolve...</code></div>',\n  },\n};\n\nexport const Default = {\n  play: async () => {\n    const href = await hrefTo('addons-links-hrefto', 'target');\n    const content = document.querySelector('#content');\n    if (content) {\n      content.textContent = href;\n    }\n  },\n};\n"
  },
  {
    "path": "code/addons/links/template/stories/linkto.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { linkTo } from '@storybook/addon-links';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  title: 'linkTo',\n  args: {\n    label: 'Click Me!',\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const Target = {\n  args: {\n    label: 'This is just a story to target with the links',\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const Id = {\n  args: {\n    onClick: linkTo('addons-links-linkto--target'),\n    label: 'addons-links-linkto--target',\n  },\n};\n\nexport const TitleOnly = {\n  args: {\n    onClick: linkTo('addons/links/linkTo'),\n    label: 'addons/links/linkTo',\n  },\n};\n\nexport const NormalizedTitleOnly = {\n  args: {\n    onClick: linkTo('addons-links-linkto'),\n    label: 'addons-links-linkto',\n  },\n};\n\nexport const TitleAndName = {\n  args: {\n    onClick: linkTo('addons/links/linkTo', 'Target'),\n    label: 'addons/links/linkTo, Target',\n  },\n};\n\nexport const NormalizedTitleAndName = {\n  args: {\n    onClick: linkTo('addons-links-linkto', 'target'),\n    label: 'addons-links-linkto, target',\n  },\n};\n\nexport const Callback = {\n  args: {\n    onClick: linkTo(\n      (event: Event) => 'addons-links-linkto',\n      (event: Event) => 'target'\n    ),\n  },\n};\n\nexport const ToMDXDocs = {\n  args: {\n    onClick: linkTo('Configure Your Project'),\n    label: 'Configure Your Project',\n  },\n};\n\nexport const ToAutodocs = {\n  args: {\n    onClick: linkTo('Example Button', 'Docs'),\n    label: 'Example Button, Docs',\n  },\n};\n"
  },
  {
    "path": "code/addons/links/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/addons/links/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/addons/onboarding/CHANGELOG.md",
    "content": "# v1.0.11 (Tue Jan 23 2024)\n\n#### 🐛 Bug Fix\n\n- Fix z-index bug by adding a wrapper [#82](https://github.com/storybookjs/addon-onboarding/pull/82) ([@ndelangen](https://github.com/ndelangen))\n- Make selectors Storybook 8 compatible [#81](https://github.com/storybookjs/addon-onboarding/pull/81) ([@yannbf](https://github.com/yannbf))\n- UI: Fix z-index in modal elements [#78](https://github.com/storybookjs/addon-onboarding/pull/78) ([@cdedreuille](https://github.com/cdedreuille) [@yannbf](https://github.com/yannbf))\n\n#### Authors: 3\n\n- Charles de Dreuille ([@cdedreuille](https://github.com/cdedreuille))\n- Norbert de Langen ([@ndelangen](https://github.com/ndelangen))\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v1.0.10 (Mon Dec 11 2023)\n\n#### 🐛 Bug Fix\n\n- Fix Yarn remove command in README [#80](https://github.com/storybookjs/addon-onboarding/pull/80) ([@githrdw](https://github.com/githrdw))\n\n#### Authors: 1\n\n- [@githrdw](https://github.com/githrdw)\n\n---\n\n# v1.0.9 (Fri Dec 01 2023)\n\n#### 🐛 Bug Fix\n\n- update telemetry version [#79](https://github.com/storybookjs/addon-onboarding/pull/79) ([@yannbf](https://github.com/yannbf))\n\n#### Authors: 1\n\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v1.0.8 (Thu Jul 20 2023)\n\n#### ⚠️ Pushed to `main`\n\n- Create CODEOWNERS ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v1.0.7 (Tue Jul 11 2023)\n\n#### 🐛 Bug Fix\n\n- Replace chevron icon on Configure page to avoid @storybook/components usage [#77](https://github.com/storybookjs/addon-onboarding/pull/77) ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v1.0.6 (Mon Jul 10 2023)\n\n#### 🐛 Bug Fix\n\n- Fix language detection [#76](https://github.com/storybookjs/addon-onboarding/pull/76) ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v1.0.5 (Mon Jul 10 2023)\n\n#### 🐛 Bug Fix\n\n- Remove nextjs-specific code [#75](https://github.com/storybookjs/addon-onboarding/pull/75) ([@yannbf](https://github.com/yannbf))\n\n#### Authors: 1\n\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v1.0.4 (Thu Jul 06 2023)\n\n#### 🐛 Bug Fix\n\n- Update Configure page design [#74](https://github.com/storybookjs/addon-onboarding/pull/74) ([@JReinhold](https://github.com/JReinhold) [@cdedreuille](https://github.com/cdedreuille))\n\n#### Authors: 2\n\n- Charles de Dreuille ([@cdedreuille](https://github.com/cdedreuille))\n- Jeppe Reinhold ([@JReinhold](https://github.com/JReinhold))\n\n---\n\n# v1.0.3 (Fri Jun 23 2023)\n\n#### 🐛 Bug Fix\n\n- Display the button story filename in tooltip [#73](https://github.com/storybookjs/addon-onboarding/pull/73) ([@yannbf](https://github.com/yannbf))\n\n#### Authors: 1\n\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v1.0.2 (Thu Jun 22 2023)\n\n#### 🐛 Bug Fix\n\n- Fix package.json version extraction [#72](https://github.com/storybookjs/addon-onboarding/pull/72) ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v1.0.1 (Thu Jun 22 2023)\n\n#### 🐛 Bug Fix\n\n- Fix build assets [#71](https://github.com/storybookjs/addon-onboarding/pull/71) ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v1.0.0 (Thu Jun 22 2023)\n\n#### 💥 Breaking Change\n\n- Release 1.0.0 [#70](https://github.com/storybookjs/addon-onboarding/pull/70) ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### 🐛 Bug Fix\n\n- Fix text for Javascript Projects [#68](https://github.com/storybookjs/addon-onboarding/pull/68) ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v0.0.43 (Thu Jun 22 2023)\n\n#### 🐛 Bug Fix\n\n- Fix react joyride in yarn pnp mode [#69](https://github.com/storybookjs/addon-onboarding/pull/69) ([@valentinpalkovic](https://github.com/valentinpalkovic))\n- fix links in configure.mdx [#67](https://github.com/storybookjs/addon-onboarding/pull/67) ([@yannbf](https://github.com/yannbf))\n\n#### Authors: 2\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v0.0.42 (Wed Jun 21 2023)\n\n#### 🐛 Bug Fix\n\n- Fix nextjs code steps [#66](https://github.com/storybookjs/addon-onboarding/pull/66) ([@yannbf](https://github.com/yannbf))\n\n#### Authors: 1\n\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v0.0.41 (Wed Jun 21 2023)\n\n#### 🐛 Bug Fix\n\n- Minor improvements [#65](https://github.com/storybookjs/addon-onboarding/pull/65) ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v0.0.40 (Tue Jun 20 2023)\n\n#### 🐛 Bug Fix\n\n- Fix preset.js entry point [#63](https://github.com/storybookjs/addon-onboarding/pull/63) ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v0.0.39 (Tue Jun 20 2023)\n\n#### 🐛 Bug Fix\n\n- Fix comment in code section [#64](https://github.com/storybookjs/addon-onboarding/pull/64) ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v0.0.38 (Mon Jun 19 2023)\n\n#### 🐛 Bug Fix\n\n- Pass addon version in telemetry event [#62](https://github.com/storybookjs/addon-onboarding/pull/62) ([@yannbf](https://github.com/yannbf))\n\n#### Authors: 1\n\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v0.0.37 (Mon Jun 19 2023)\n\n#### 🐛 Bug Fix\n\n- UI Fixes [#61](https://github.com/storybookjs/addon-onboarding/pull/61) ([@yannbf](https://github.com/yannbf) [@cdedreuille](https://github.com/cdedreuille))\n\n#### Authors: 2\n\n- Charles de Dreuille ([@cdedreuille](https://github.com/cdedreuille))\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v0.0.36 (Fri Jun 16 2023)\n\n#### 🐛 Bug Fix\n\n- Improve dark mode [#58](https://github.com/storybookjs/addon-onboarding/pull/58) ([@cdedreuille](https://github.com/cdedreuille) [@yannbf](https://github.com/yannbf))\n\n#### Authors: 2\n\n- Charles de Dreuille ([@cdedreuille](https://github.com/cdedreuille))\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v0.0.35 (Fri Jun 16 2023)\n\n#### 🐛 Bug Fix\n\n- Add dark mode styles to tooltip [#54](https://github.com/storybookjs/addon-onboarding/pull/54) ([@yannbf](https://github.com/yannbf))\n- UI fixes [#56](https://github.com/storybookjs/addon-onboarding/pull/56) ([@yannbf](https://github.com/yannbf))\n- Fix watch mode [#55](https://github.com/storybookjs/addon-onboarding/pull/55) ([@yannbf](https://github.com/yannbf))\n\n#### Authors: 1\n\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v0.0.34 (Wed Jun 14 2023)\n\n#### 🐛 Bug Fix\n\n- Fix configure page's layout [#53](https://github.com/storybookjs/addon-onboarding/pull/53) ([@cdedreuille](https://github.com/cdedreuille))\n\n#### Authors: 1\n\n- Charles de Dreuille ([@cdedreuille](https://github.com/cdedreuille))\n\n---\n\n# v0.0.33 (Wed Jun 14 2023)\n\n#### 🐛 Bug Fix\n\n- Improve story detection [#52](https://github.com/storybookjs/addon-onboarding/pull/52) ([@yannbf](https://github.com/yannbf))\n\n#### Authors: 1\n\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v0.0.32 (Wed Jun 14 2023)\n\n#### 🐛 Bug Fix\n\n- Fixes on syntax highlighter [#51](https://github.com/storybookjs/addon-onboarding/pull/51) ([@cdedreuille](https://github.com/cdedreuille) [@yannbf](https://github.com/yannbf))\n\n#### Authors: 2\n\n- Charles de Dreuille ([@cdedreuille](https://github.com/cdedreuille))\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v0.0.31 (Wed Jun 14 2023)\n\n#### 🐛 Bug Fix\n\n- Improve instructions [#50](https://github.com/storybookjs/addon-onboarding/pull/50) ([@shilman](https://github.com/shilman))\n\n#### Authors: 1\n\n- Michael Shilman ([@shilman](https://github.com/shilman))\n\n---\n\n# v0.0.30 (Tue Jun 13 2023)\n\n#### 🐛 Bug Fix\n\n- Add core server events for telemetry [#40](https://github.com/storybookjs/addon-onboarding/pull/40) ([@valentinpalkovic](https://github.com/valentinpalkovic) [@yannbf](https://github.com/yannbf))\n\n#### Authors: 2\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v0.0.29 (Tue Jun 13 2023)\n\n#### ⚠️ Pushed to `main`\n\n- cleanup dependencies ([@yannbf](https://github.com/yannbf))\n\n#### Authors: 1\n\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v0.0.28 (Mon Jun 12 2023)\n\n#### 🐛 Bug Fix\n\n- Feat/overall improvements [#49](https://github.com/storybookjs/addon-onboarding/pull/49) ([@yannbf](https://github.com/yannbf) [@cdedreuille](https://github.com/cdedreuille))\n\n#### Authors: 2\n\n- Charles de Dreuille ([@cdedreuille](https://github.com/cdedreuille))\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v0.0.27 (Fri Jun 09 2023)\n\n#### 🐛 Bug Fix\n\n- Add previous button to write stories modal [#48](https://github.com/storybookjs/addon-onboarding/pull/48) ([@yannbf](https://github.com/yannbf) [@cdedreuille](https://github.com/cdedreuille))\n\n#### Authors: 2\n\n- Charles de Dreuille ([@cdedreuille](https://github.com/cdedreuille))\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v0.0.26 (Thu Jun 08 2023)\n\n#### 🐛 Bug Fix\n\n- Remove animation modal [#47](https://github.com/storybookjs/addon-onboarding/pull/47) ([@cdedreuille](https://github.com/cdedreuille))\n\n#### Authors: 1\n\n- Charles de Dreuille ([@cdedreuille](https://github.com/cdedreuille))\n\n---\n\n# v0.0.25 (Thu Jun 08 2023)\n\n#### 🐛 Bug Fix\n\n- Improve addon bootstrapping [#46](https://github.com/storybookjs/addon-onboarding/pull/46) ([@yannbf](https://github.com/yannbf))\n\n#### Authors: 1\n\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v0.0.24 (Thu Jun 08 2023)\n\n#### 🐛 Bug Fix\n\n- Use the correct event to detect args change [#45](https://github.com/storybookjs/addon-onboarding/pull/45) ([@yannbf](https://github.com/yannbf))\n\n#### Authors: 1\n\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v0.0.23 (Thu Jun 08 2023)\n\n#### 🐛 Bug Fix\n\n- Various improvements [#44](https://github.com/storybookjs/addon-onboarding/pull/44) ([@yannbf](https://github.com/yannbf) [@cdedreuille](https://github.com/cdedreuille))\n\n#### Authors: 2\n\n- Charles de Dreuille ([@cdedreuille](https://github.com/cdedreuille))\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v0.0.22 (Thu Jun 08 2023)\n\n#### 🐛 Bug Fix\n\n- Improve confetti colors and shapes [#43](https://github.com/storybookjs/addon-onboarding/pull/43) ([@yannbf](https://github.com/yannbf) [@cdedreuille](https://github.com/cdedreuille))\n\n#### Authors: 2\n\n- Charles de Dreuille ([@cdedreuille](https://github.com/cdedreuille))\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v0.0.21 (Thu Jun 08 2023)\n\n#### 🐛 Bug Fix\n\n- Improve modal animation [#42](https://github.com/storybookjs/addon-onboarding/pull/42) ([@cdedreuille](https://github.com/cdedreuille))\n\n#### Authors: 1\n\n- Charles de Dreuille ([@cdedreuille](https://github.com/cdedreuille))\n\n---\n\n# v0.0.20 (Wed Jun 07 2023)\n\n#### 🐛 Bug Fix\n\n- Change code for Javascript projects [#41](https://github.com/storybookjs/addon-onboarding/pull/41) ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v0.0.19 (Wed Jun 07 2023)\n\n#### 🐛 Bug Fix\n\n- Improve write a story modal [#38](https://github.com/storybookjs/addon-onboarding/pull/38) ([@cdedreuille](https://github.com/cdedreuille))\n\n#### Authors: 1\n\n- Charles de Dreuille ([@cdedreuille](https://github.com/cdedreuille))\n\n---\n\n# v0.0.18 (Wed Jun 07 2023)\n\n#### 🐛 Bug Fix\n\n- Implement \"How to write your Story\" flow [#33](https://github.com/storybookjs/addon-onboarding/pull/33) ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v0.0.17 (Wed Jun 07 2023)\n\n#### 🐛 Bug Fix\n\n- use onboarding parameter in conjunction with onboarding path [#37](https://github.com/storybookjs/addon-onboarding/pull/37) ([@yannbf](https://github.com/yannbf))\n\n#### Authors: 1\n\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v0.0.16 (Tue Jun 06 2023)\n\n#### 🐛 Bug Fix\n\n- Improve guided tour [#35](https://github.com/storybookjs/addon-onboarding/pull/35) ([@cdedreuille](https://github.com/cdedreuille) [@yannbf](https://github.com/yannbf))\n\n#### Authors: 2\n\n- Charles de Dreuille ([@cdedreuille](https://github.com/cdedreuille))\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v0.0.15 (Tue Jun 06 2023)\n\n#### 🐛 Bug Fix\n\n- Trigger via `/onboarding` path instead of query parameter [#21](https://github.com/storybookjs/addon-onboarding/pull/21) ([@yannbf](https://github.com/yannbf))\n- Welcome modal animation [#34](https://github.com/storybookjs/addon-onboarding/pull/34) ([@cdedreuille](https://github.com/cdedreuille))\n\n#### Authors: 2\n\n- Charles de Dreuille ([@cdedreuille](https://github.com/cdedreuille))\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v0.0.14 (Mon Jun 05 2023)\n\n#### 🐛 Bug Fix\n\n- Modal improvements [#22](https://github.com/storybookjs/addon-onboarding/pull/22) ([@cdedreuille](https://github.com/cdedreuille))\n\n#### Authors: 1\n\n- Charles de Dreuille ([@cdedreuille](https://github.com/cdedreuille))\n\n---\n\n# v0.0.13 (Mon Jun 05 2023)\n\n#### 🐛 Bug Fix\n\n- Implement syntax highlighter [#20](https://github.com/storybookjs/addon-onboarding/pull/20) ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v0.0.12 (Thu Jun 01 2023)\n\n#### 🐛 Bug Fix\n\n- Implemented bare minimum list component [#19](https://github.com/storybookjs/addon-onboarding/pull/19) ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v0.0.11 (Thu Jun 01 2023)\n\n#### 🐛 Bug Fix\n\n- Add guided tour example [#5](https://github.com/storybookjs/addon-onboarding/pull/5) ([@yannbf](https://github.com/yannbf))\n\n#### Authors: 1\n\n- Yann Braga ([@yannbf](https://github.com/yannbf))\n\n---\n\n# v0.0.10 (Tue May 30 2023)\n\n#### ⚠️ Pushed to `main`\n\n- Rename confett to Confetti ([@valentinpalkovic](https://github.com/valentinpalkovic))\n- Rename confetti to confett ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v0.0.9 (Tue May 30 2023)\n\n#### 🐛 Bug Fix\n\n- Implement bare minimum modal component [#18](https://github.com/storybookjs/addon-onboarding/pull/18) ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v0.0.8 (Tue May 30 2023)\n\n#### 🐛 Bug Fix\n\n- Implement bare minimum confetti component [#7](https://github.com/storybookjs/addon-onboarding/pull/7) ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v0.0.7 (Thu May 25 2023)\n\n#### 🐛 Bug Fix\n\n- Init Storybook Theme Provider [#6](https://github.com/storybookjs/addon-onboarding/pull/6) ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v0.0.6 (Tue May 23 2023)\n\n#### 🐛 Bug Fix\n\n- Add minimum React Application [#3](https://github.com/storybookjs/addon-onboarding/pull/3) ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v0.0.5 (Tue May 23 2023)\n\n#### ⚠️ Pushed to `main`\n\n- Add clean package.json ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v0.0.4 (Tue May 23 2023)\n\n#### ⚠️ Pushed to `main`\n\n- Cleanup ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v0.0.3 (Tue May 23 2023)\n\n#### 🐛 Bug Fix\n\n- Setup Chromatic [#2](https://github.com/storybookjs/addon-onboarding/pull/2) ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v0.0.2 (Tue May 23 2023)\n\n#### 🐛 Bug Fix\n\n- Remove unnecessary files [#1](https://github.com/storybookjs/addon-onboarding/pull/1) ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n---\n\n# v0.0.1 (Tue May 23 2023)\n\n#### ⚠️ Pushed to `main`\n\n- Fix manager.ts and add export {} ([@valentinpalkovic](https://github.com/valentinpalkovic))\n- Add auto.config.js ([@valentinpalkovic](https://github.com/valentinpalkovic))\n- Init Addon Onboarding ([@valentinpalkovic](https://github.com/valentinpalkovic))\n- project setup ([@valentinpalkovic](https://github.com/valentinpalkovic))\n- Initial commit ([@valentinpalkovic](https://github.com/valentinpalkovic))\n\n#### Authors: 1\n\n- Valentin Palkovic ([@valentinpalkovic](https://github.com/valentinpalkovic))\n"
  },
  {
    "path": "code/addons/onboarding/README.md",
    "content": "# Storybook Addon Onboarding\n\nThis addon provides a guided tour in some of Storybook's features, helping you get to know about the basics of Storybook and learn how to write stories!\n\n![](./.github/assets/onboarding-intro.png)\n\n## Triggering the onboarding\n\nThis addon comes installed by default in Storybook projects and should trigger automatically.\nIf you want to retrigger the addon, you should make sure that your Storybook still contains the example stories that come when initializing Storybook, and you can then navigate to http://localhost:6006/?path=/onboarding after running Storybook.\n\n## Uninstalling\n\nThis addon serves to provide you a guided experience on the basics of Storybook. Once you are done, the addon is therefore not needed anymore and will not get activated (unless triggered manually), so you can freely remove it. Here's how to do so:\n\n### 1. Remove the dependency\n\nyarn:\n\n```zsh\nyarn remove @storybook/addon-onboarding\n```\n\nnpm:\n\n```zsh\nnpm uninstall -D @storybook/addon-onboarding\n```\n\npnpm:\n\n```zsh\npnpm remove -D @storybook/addon-onboarding\n```\n\n### 2. Remove the addon in your `.storybook/main.js` file\n\n```diff\nconst config = {\n  stories: [\n    \"../stories/**/*.stories.mdx\",\n    \"../stories/**/*.stories.@(js|jsx|ts|tsx)\",\n  ],\n  addons: [\n-   \"@storybook/addon-onboarding\"\n  ],\n};\nexport default config;\n```\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/addons/onboarding/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./manager'],\n        entryPoint: './src/manager.tsx',\n        dts: false,\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/addons/onboarding/example-stories/Button.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { fn } from 'storybook/test';\n\nimport { Button } from './Button.tsx';\n\nconst meta = {\n  title: 'Example/Button',\n  component: Button,\n  parameters: {\n    layout: 'centered',\n    parameters: {\n      chromatic: {\n        disableSnapshot: true,\n      },\n    },\n  },\n  tags: ['autodocs'],\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  args: { onClick: fn() },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large: Story = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small: Story = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/addons/onboarding/example-stories/Button.tsx",
    "content": "import React from 'react';\n\nimport './button.css';\n\nexport interface ButtonProps {\n  /** Is this the principal call to action on the page? */\n  primary?: boolean;\n  /** What background color to use */\n  backgroundColor?: string;\n  /** How large should the button be? */\n  size?: 'small' | 'medium' | 'large';\n  /** Button contents */\n  label: string;\n  /** Optional click handler */\n  onClick?: () => void;\n}\n\n/** Primary UI component for user interaction */\nexport const Button = ({\n  primary = false,\n  size = 'medium',\n  backgroundColor,\n  label,\n  ...props\n}: ButtonProps) => {\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n  return (\n    <button\n      type=\"button\"\n      className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n      style={{ backgroundColor }}\n      {...props}\n    >\n      {label}\n    </button>\n  );\n};\n"
  },
  {
    "path": "code/addons/onboarding/example-stories/button.css",
    "content": ".storybook-button {\n  display: inline-block;\n  cursor: pointer;\n  border: 0;\n  border-radius: 3em;\n  font-weight: 700;\n  line-height: 1;\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n.storybook-button--primary {\n  background-color: #555ab9;\n  color: white;\n}\n.storybook-button--secondary {\n  box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;\n  background-color: transparent;\n  color: #333;\n}\n.storybook-button--small {\n  padding: 10px 16px;\n  font-size: 12px;\n}\n.storybook-button--medium {\n  padding: 11px 20px;\n  font-size: 14px;\n}\n.storybook-button--large {\n  padding: 12px 24px;\n  font-size: 16px;\n}\n"
  },
  {
    "path": "code/addons/onboarding/manager.js",
    "content": "export * from './dist/manager.js';\n"
  },
  {
    "path": "code/addons/onboarding/package.json",
    "content": "{\n  \"name\": \"@storybook/addon-onboarding\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook Onboarding: Help new users learn how to write stories\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-addon\",\n    \"onboarding\",\n    \"getting started\",\n    \"component\",\n    \"components\",\n    \"react\",\n    \"vue\",\n    \"angular\",\n    \"svelte\",\n    \"web-components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/addons/onboarding\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/addons/onboarding\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./manager\": \"./dist/manager.js\",\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"devDependencies\": {\n    \"@neoconfetti/react\": \"^1.0.0\",\n    \"@storybook/icons\": \"^2.0.1\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-joyride\": \"^2.8.2\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"storybook\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "code/addons/onboarding/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/addons/onboarding/project.json",
    "content": "{\n  \"name\": \"addon-onboarding\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/addons/onboarding/src/Onboarding.tsx",
    "content": "import React, { useCallback, useEffect, useState } from 'react';\n\nimport { SyntaxHighlighter } from 'storybook/internal/components';\nimport { SAVE_STORY_RESPONSE } from 'storybook/internal/core-events';\n\nimport { type API } from 'storybook/manager-api';\nimport { ThemeProvider, convert, styled, themes } from 'storybook/theming';\n\nimport { HighlightElement } from '../../../core/src/manager/components/TourGuide/HighlightElement.tsx';\nimport { TourGuide } from '../../../core/src/manager/components/TourGuide/TourGuide.tsx';\nimport { Confetti } from './components/Confetti/Confetti.tsx';\nimport type { STORYBOOK_ADDON_ONBOARDING_STEPS } from './constants.ts';\nimport { ADDON_CONTROLS_ID, ADDON_ONBOARDING_CHANNEL } from './constants.ts';\nimport { IntentSurvey } from './features/IntentSurvey/IntentSurvey.tsx';\nimport { SplashScreen } from './features/SplashScreen/SplashScreen.tsx';\n\nconst SpanHighlight = styled.span(({ theme }) => ({\n  display: 'inline-flex',\n  borderRadius: 3,\n  padding: '0 5px',\n  marginBottom: -2,\n  opacity: 0.8,\n  fontFamily: theme.typography.fonts.mono,\n  fontSize: 11,\n  border: theme.base === 'dark' ? theme.color.darkest : theme.color.lightest,\n  color: theme.base === 'dark' ? theme.color.lightest : theme.color.darkest,\n  backgroundColor: theme.base === 'dark' ? 'black' : theme.color.light,\n  boxSizing: 'border-box',\n  lineHeight: '17px',\n}));\n\nconst CodeWrapper = styled.div(({ theme }) => ({\n  background: theme.background.content,\n  borderRadius: 3,\n  marginTop: 15,\n  padding: 10,\n  fontSize: theme.typography.size.s1,\n  '.linenumber': {\n    opacity: 0.5,\n  },\n}));\n\nconst theme = convert();\n\nexport type StepKey = (typeof STORYBOOK_ADDON_ONBOARDING_STEPS)[number];\n\nexport default function Onboarding({\n  api,\n  hasCompletedSurvey,\n}: {\n  api: API;\n  hasCompletedSurvey: boolean;\n}) {\n  const [enabled, setEnabled] = useState(true);\n  const [showConfetti, setShowConfetti] = useState(false);\n  const [step, setStep] = useState<StepKey>('1:Intro');\n\n  const [primaryControl, setPrimaryControl] = useState<HTMLElement | null>();\n  const [saveFromControls, setSaveFromControls] = useState<HTMLElement | null>();\n  const [createNewStoryForm, setCreateNewStoryForm] = useState<HTMLElement | null>();\n  const [createdStory, setCreatedStory] = useState<{\n    newStoryName: string;\n    newStoryExportName: string;\n    sourceFileContent: string;\n    sourceFileName: string;\n  } | null>();\n\n  // eslint-disable-next-line compat/compat\n  const userAgent = globalThis?.navigator?.userAgent;\n\n  const selectStory = useCallback(\n    (storyId: string) => {\n      try {\n        const { id, refId } = api.getCurrentStoryData() || {};\n\n        if (id !== storyId || refId !== undefined) {\n          api.selectStory(storyId);\n        }\n      } catch (e) {}\n    },\n    [api]\n  );\n\n  const disableOnboarding = useCallback(\n    (dismissedStep?: StepKey) => {\n      if (dismissedStep) {\n        api.emit(ADDON_ONBOARDING_CHANNEL, {\n          dismissedStep,\n          type: 'dismiss',\n          userAgent,\n        });\n      }\n      api.applyQueryParams({ onboarding: undefined }, { replace: true });\n      setEnabled(false);\n    },\n    [api, setEnabled, userAgent]\n  );\n\n  const completeSurvey = useCallback(\n    (answers: Record<string, unknown>) => {\n      api.emit(ADDON_ONBOARDING_CHANNEL, {\n        answers,\n        type: 'survey',\n        userAgent,\n      });\n      setStep('7:FinishedOnboarding');\n      api.selectFirstStory();\n    },\n    [api, userAgent]\n  );\n\n  useEffect(() => {\n    if (step === '6:IntentSurvey' && !hasCompletedSurvey) {\n      api.emit(ADDON_ONBOARDING_CHANNEL, {\n        from: 'onboarding',\n        type: 'openSurvey',\n        userAgent,\n      });\n    }\n  }, [api, hasCompletedSurvey, step, userAgent]);\n\n  useEffect(() => {\n    api.setQueryParams({ onboarding: 'true' });\n    selectStory('example-button--primary');\n    api.togglePanel(true);\n    api.togglePanelPosition('bottom');\n    api.setSelectedPanel(ADDON_CONTROLS_ID);\n    api.setSizes({ bottomPanelHeight: 300 });\n  }, [api, selectStory]);\n\n  useEffect(() => {\n    const observer = new MutationObserver(() => {\n      setPrimaryControl(document.getElementById('control-primary'));\n      setSaveFromControls(document.getElementById('save-from-controls'));\n      setCreateNewStoryForm(document.getElementById('create-new-story-form'));\n    });\n\n    observer.observe(document.body, { childList: true, subtree: true });\n    return () => observer.disconnect();\n  }, []);\n\n  useEffect(() => {\n    setStep((current) => {\n      if (hasCompletedSurvey && current === '6:IntentSurvey') {\n        return '7:FinishedOnboarding';\n      }\n\n      if (\n        ['1:Intro', '5:StoryCreated', '6:IntentSurvey', '7:FinishedOnboarding'].includes(current)\n      ) {\n        return current;\n      }\n\n      if (createNewStoryForm) {\n        return '4:CreateStory';\n      }\n\n      if (saveFromControls) {\n        return '3:SaveFromControls';\n      }\n\n      if (primaryControl || current === '2:Controls') {\n        return '2:Controls';\n      }\n\n      return '1:Intro';\n    });\n  }, [hasCompletedSurvey, createNewStoryForm, primaryControl, saveFromControls]);\n\n  useEffect(() => {\n    return api.on(SAVE_STORY_RESPONSE, ({ payload, success }) => {\n      if (!success || !payload?.newStoryName) {\n        return;\n      }\n      setCreatedStory(payload);\n      setShowConfetti(true);\n      setStep('5:StoryCreated');\n      setTimeout(() => api.clearNotification('save-story-success'));\n      setTimeout(() => setShowConfetti(false), 10000);\n    });\n  }, [api]);\n\n  useEffect(\n    () => api.emit(ADDON_ONBOARDING_CHANNEL, { step, type: 'telemetry', userAgent }),\n    [api, step, userAgent]\n  );\n\n  if (!enabled) {\n    return null;\n  }\n\n  const source = createdStory?.sourceFileContent;\n  const startIndex = source?.lastIndexOf(`export const ${createdStory?.newStoryExportName}`);\n  const snippet = source?.slice(startIndex).trim();\n  const startingLineNumber = source?.slice(0, startIndex).split('\\n').length;\n\n  const controlsTour = [\n    {\n      key: '2:Controls',\n      target: '#control-primary',\n      title: 'Interactive story playground',\n      content: (\n        <>\n          See how a story renders with different data and state without touching code. Try it out by\n          toggling this button.\n          <HighlightElement targetSelector=\"#control-primary\" pulsating />\n        </>\n      ),\n      offset: 20,\n      placement: 'right',\n      disableBeacon: true,\n      disableOverlay: true,\n      spotlightClicks: true,\n      onNext: () => {\n        const input = document.querySelector('#control-primary') as HTMLInputElement;\n        input.click();\n      },\n    },\n    {\n      key: '3:SaveFromControls',\n      target: 'button[aria-label=\"Create new story with these settings\"]',\n      title: 'Save your changes as a new story',\n      content: (\n        <>\n          Great! Storybook stories represent the key states of each of your components. After\n          modifying a story, you can save your changes from here or reset it.\n          <HighlightElement targetSelector=\"button[aria-label='Create new story with these settings']\" />\n        </>\n      ),\n      offset: 6,\n      placement: 'top',\n      disableBeacon: true,\n      disableOverlay: true,\n      spotlightClicks: true,\n      onNext: () => {\n        const button = document.querySelector(\n          'button[aria-label=\"Create new story with these settings\"]'\n        ) as HTMLButtonElement;\n        button.click();\n      },\n      styles: {\n        tooltip: {\n          width: 400,\n        },\n      },\n    },\n    {\n      key: '5:StoryCreated',\n      target: '#storybook-explorer-tree [data-selected=\"true\"]',\n      title: 'You just added your first story!',\n      content: (\n        <>\n          Well done! You just created your first story from the Storybook manager. This\n          automatically added a few lines of code in{' '}\n          <SpanHighlight>{createdStory?.sourceFileName}</SpanHighlight>.\n          {snippet && (\n            <ThemeProvider theme={convert(themes.dark)}>\n              <CodeWrapper>\n                <SyntaxHighlighter\n                  language=\"jsx\"\n                  showLineNumbers\n                  startingLineNumber={startingLineNumber}\n                >\n                  {snippet}\n                </SyntaxHighlighter>\n              </CodeWrapper>\n            </ThemeProvider>\n          )}\n        </>\n      ),\n      offset: 12,\n      placement: 'right',\n      disableBeacon: true,\n      disableOverlay: true,\n      styles: {\n        tooltip: {\n          width: 400,\n        },\n      },\n    },\n  ];\n\n  const checklistTour = [\n    {\n      key: '7:FinishedOnboarding',\n      target: '#storybook-checklist-module',\n      title: 'Continue at your own pace using the guide',\n      content: (\n        <>\n          Nice! You've got the essentials. You can continue at your own pace using the guide to\n          discover more of Storybook's capabilities.\n          <HighlightElement targetSelector=\"#storybook-checklist-module\" pulsating />\n        </>\n      ),\n      offset: 0,\n      placement: 'right-start',\n      disableBeacon: true,\n      disableOverlay: true,\n      styles: {\n        tooltip: {\n          width: 350,\n        },\n      },\n    },\n  ];\n\n  return (\n    <ThemeProvider theme={theme}>\n      {showConfetti && <Confetti />}\n      {step === '1:Intro' ? (\n        <SplashScreen onDismiss={() => setStep('2:Controls')} />\n      ) : step === '6:IntentSurvey' ? (\n        <IntentSurvey\n          isOpen={enabled}\n          onComplete={completeSurvey}\n          onDismiss={() => disableOnboarding('6:IntentSurvey')}\n        />\n      ) : step === '7:FinishedOnboarding' ? (\n        <TourGuide\n          // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n          // @ts-ignore Circular reference in Step type\n          step={step}\n          steps={checklistTour}\n          onComplete={() => disableOnboarding()}\n          onDismiss={() => disableOnboarding(step)}\n        />\n      ) : (\n        <TourGuide\n          // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n          // @ts-ignore Circular reference in Step type\n          step={step}\n          steps={controlsTour}\n          onComplete={() => setStep(hasCompletedSurvey ? '7:FinishedOnboarding' : '6:IntentSurvey')}\n          onDismiss={() => disableOnboarding(step)}\n        />\n      )}\n    </ThemeProvider>\n  );\n}\n"
  },
  {
    "path": "code/addons/onboarding/src/Survey.tsx",
    "content": "import React, { useCallback, useEffect, useState } from 'react';\n\nimport { type API } from 'storybook/manager-api';\nimport { ThemeProvider, convert } from 'storybook/theming';\n\nimport { ADDON_ONBOARDING_CHANNEL } from './constants.ts';\nimport { IntentSurvey } from './features/IntentSurvey/IntentSurvey.tsx';\n\nconst theme = convert();\n\nexport default function Survey({ api }: { api: API }) {\n  // eslint-disable-next-line compat/compat\n  const userAgent = globalThis?.navigator?.userAgent;\n\n  const [isOpen, setIsOpen] = useState(true);\n\n  useEffect(() => {\n    api.emit(ADDON_ONBOARDING_CHANNEL, {\n      from: 'guide',\n      type: 'openSurvey',\n      userAgent,\n    });\n  }, [api, userAgent]);\n\n  const disableOnboarding = useCallback(() => {\n    setIsOpen(false);\n    api.applyQueryParams({ onboarding: undefined }, { replace: true });\n  }, [api]);\n\n  const complete = useCallback(\n    (answers: Record<string, unknown>) => {\n      api.emit(ADDON_ONBOARDING_CHANNEL, {\n        answers,\n        type: 'survey',\n        userAgent,\n      });\n      disableOnboarding();\n    },\n    [api, disableOnboarding, userAgent]\n  );\n\n  const dismiss = useCallback(() => {\n    api.emit(ADDON_ONBOARDING_CHANNEL, {\n      type: 'dismissSurvey',\n    });\n    disableOnboarding();\n  }, [api, disableOnboarding]);\n\n  return (\n    <ThemeProvider theme={theme}>\n      <IntentSurvey isOpen={isOpen} onComplete={complete} onDismiss={dismiss} />\n    </ThemeProvider>\n  );\n}\n"
  },
  {
    "path": "code/addons/onboarding/src/components/Confetti/Confetti.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Confetti } from './Confetti.tsx';\n\nconst meta: Meta<typeof Confetti> = {\n  component: Confetti,\n  parameters: {\n    chromatic: { disableSnapshot: true },\n    layout: 'fullscreen',\n  },\n  decorators: [\n    (StoryFn) => (\n      <div\n        style={{\n          height: '100vh',\n          width: '100vw',\n          alignContent: 'center',\n          textAlign: 'center',\n        }}\n      >\n        <span>Falling confetti! 🎉</span>\n        <StoryFn />\n      </div>\n    ),\n  ],\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof Confetti>;\n\nexport const Default: Story = {};\n"
  },
  {
    "path": "code/addons/onboarding/src/components/Confetti/Confetti.tsx",
    "content": "import React, { type ComponentProps } from 'react';\n\nimport { Confetti as ReactConfetti } from '@neoconfetti/react';\nimport { styled } from 'storybook/theming';\n\nconst Wrapper = styled.div({\n  zIndex: 9999,\n  position: 'fixed',\n  top: 0,\n  left: '50%',\n  width: '50%',\n  height: '100%',\n  pointerEvents: 'none',\n});\n\nexport const Confetti = React.memo(function Confetti({\n  timeToFade = 5000,\n  colors = ['#CA90FF', '#FC521F', '#66BF3C', '#FF4785', '#FFAE00', '#1EA7FD'],\n  ...confettiProps\n}: ComponentProps<typeof ReactConfetti> & { timeToFade?: number }) {\n  return (\n    <Wrapper>\n      <ReactConfetti\n        colors={colors}\n        particleCount={200}\n        duration={5000}\n        stageHeight={window.innerHeight}\n        stageWidth={window.innerWidth}\n        destroyAfterDone\n        {...confettiProps}\n      />\n    </Wrapper>\n  );\n});\n"
  },
  {
    "path": "code/addons/onboarding/src/components/List/List.stories.tsx",
    "content": "import React, { useState } from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { expect, userEvent, waitFor, within } from 'storybook/test';\n\nimport { List } from './List.tsx';\nimport { ListItem } from './ListItem/ListItem.tsx';\n\nconst meta: Meta<typeof List> = {\n  component: List,\n};\n\nexport default meta;\n\nexport const Default: StoryObj<typeof meta> = {\n  render: () => {\n    const [workingIndex, setWorkingIndex] = useState(1);\n\n    return (\n      <>\n        <List>\n          <ListItem isCompleted={workingIndex >= 1} index={1}>\n            Hello World\n          </ListItem>\n          <ListItem isCompleted={workingIndex >= 2} index={2}>\n            Bonjour le monde\n          </ListItem>\n          <ListItem isCompleted={workingIndex >= 3} index={3}>\n            你好, 世界\n          </ListItem>\n        </List>\n        <br />\n        <button type=\"button\" onClick={() => setWorkingIndex(workingIndex + 1)}>\n          Complete\n        </button>\n      </>\n    );\n  },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement.parentElement!);\n    const button = canvas.getByText('Complete');\n\n    await expect(canvas.getAllByLabelText('complete')).toHaveLength(1);\n\n    await userEvent.click(button);\n\n    await waitFor(() => expect(canvas.getAllByLabelText('complete')).toHaveLength(2));\n  },\n};\n"
  },
  {
    "path": "code/addons/onboarding/src/components/List/List.styled.tsx",
    "content": "import { styled } from 'storybook/theming';\n\nexport const ListWrapper = styled.ul({\n  display: 'flex',\n  flexDirection: 'column',\n  rowGap: 16,\n  padding: 0,\n  margin: 0,\n});\n"
  },
  {
    "path": "code/addons/onboarding/src/components/List/List.tsx",
    "content": "import React from 'react';\n\nimport { ListWrapper } from './List.styled.tsx';\n\ninterface ListProps {\n  children: React.ReactNode;\n}\n\nexport const List = ({ children }: ListProps) => {\n  return <ListWrapper>{children}</ListWrapper>;\n};\n"
  },
  {
    "path": "code/addons/onboarding/src/components/List/ListItem/ListItem.styled.tsx",
    "content": "import { styled } from 'storybook/theming';\n\nexport const ListItemWrapper = styled.li(() => ({\n  display: 'flex',\n  alignItems: 'flex-start',\n  columnGap: 12,\n}));\n\nexport const ListItemContentWrapper = styled.div`\n  font-family: ${({ theme }) => theme.typography.fonts.base};\n  color: ${({ theme }) => theme.color.darker};\n  font-size: 13px;\n  line-height: 18px;\n  margin-top: 2px;\n`;\n\nexport const ListItemIndexWrapper = styled.div<{ isCompleted: boolean }>(\n  ({ isCompleted, theme }) => ({\n    display: 'flex',\n    alignItems: 'center',\n    justifyContent: 'center',\n    border: `1px solid ${!isCompleted ? theme.color.medium : 'transparent'}`,\n    width: 20,\n    height: 20,\n    flexShrink: 0,\n    borderRadius: '50%',\n    backgroundColor: isCompleted ? theme.color.green : 'white',\n    fontFamily: theme.typography.fonts.base,\n    fontSize: 10,\n    fontWeight: 600,\n    color: theme.color.dark,\n  })\n);\n"
  },
  {
    "path": "code/addons/onboarding/src/components/List/ListItem/ListItem.tsx",
    "content": "import React from 'react';\n\nimport { CheckIcon } from '@storybook/icons';\n\nimport {\n  ListItemContentWrapper,\n  ListItemIndexWrapper,\n  ListItemWrapper,\n} from './ListItem.styled.tsx';\n\ninterface ListItemProps {\n  children: React.ReactNode;\n  index: number;\n  isCompleted?: boolean;\n}\n\nexport const ListItem = ({ children, index, isCompleted }: ListItemProps) => {\n  return (\n    <ListItemWrapper>\n      <ListItemIndexWrapper\n        aria-label={isCompleted ? 'complete' : 'not complete'}\n        isCompleted={isCompleted!}\n      >\n        {isCompleted ? <CheckIcon width={10} height={10} color=\"white\" /> : index}\n      </ListItemIndexWrapper>\n      <ListItemContentWrapper>{children}</ListItemContentWrapper>\n    </ListItemWrapper>\n  );\n};\n"
  },
  {
    "path": "code/addons/onboarding/src/constants.ts",
    "content": "export const ADDON_ID = 'storybook/onboarding';\nexport const ADDON_ONBOARDING_CHANNEL = `${ADDON_ID}/channel`;\n\n// ! please keep this in sync with core/src/controls/constants.ts\nexport const ADDON_CONTROLS_ID = 'addon-controls' as const;\nexport const STORYBOOK_ADDON_ONBOARDING_STEPS = [\n  '1:Intro',\n  '2:Controls',\n  '3:SaveFromControls',\n  '4:CreateStory',\n  '5:StoryCreated',\n  '6:IntentSurvey',\n  '7:FinishedOnboarding',\n] as const;\n"
  },
  {
    "path": "code/addons/onboarding/src/features/IntentSurvey/IntentSurvey.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { expect, fn, screen, userEvent, waitFor } from 'storybook/test';\n\nimport { IntentSurvey } from './IntentSurvey.tsx';\n\nconst meta = {\n  component: IntentSurvey,\n  args: {\n    isOpen: true,\n    onComplete: fn(),\n    onDismiss: fn(),\n  },\n} as Meta<typeof IntentSurvey>;\n\ntype Story = StoryObj<typeof meta>;\nexport default meta;\n\nexport const Default: Story = {};\n\nexport const Submitting: Story = {\n  play: async ({ args }) => {\n    const button = await screen.findByRole('button', { name: 'Submit' });\n    await expect(button).toHaveAttribute('aria-disabled', 'true');\n\n    await userEvent.click(await screen.findByText('Design system'));\n    await expect(button).toHaveAttribute('aria-disabled', 'true');\n\n    await userEvent.click(await screen.findByText('Functional testing'));\n    await userEvent.click(await screen.findByText('Accessibility testing'));\n    await userEvent.click(await screen.findByText('Visual testing'));\n    await expect(button).toHaveAttribute('aria-disabled', 'true');\n\n    await userEvent.selectOptions(screen.getByRole('combobox'), ['We use it at work']);\n    await expect(button).not.toHaveAttribute('aria-disabled', 'true');\n\n    await userEvent.click(button);\n\n    await waitFor(async () => {\n      await expect(button).toHaveAttribute('aria-disabled', 'true');\n      await expect(args.onComplete).toHaveBeenCalledWith({\n        building: {\n          'application-ui': false,\n          'design-system': true,\n        },\n        interest: {\n          'accessibility-testing': true,\n          'ai-augmented-development': false,\n          'design-handoff': false,\n          'functional-testing': true,\n          'team-collaboration': false,\n          'ui-documentation': false,\n          'visual-testing': true,\n        },\n        referrer: {\n          'ai-agent': false,\n          'via-friend-or-colleague': false,\n          'via-social-media': false,\n          'we-use-it-at-work': true,\n          'web-search': false,\n          youtube: false,\n        },\n      });\n    });\n  },\n};\n"
  },
  {
    "path": "code/addons/onboarding/src/features/IntentSurvey/IntentSurvey.tsx",
    "content": "import React, { Fragment, useState } from 'react';\n\nimport { Button, Form, Modal } from 'storybook/internal/components';\n\nimport { styled } from 'storybook/theming';\n\nimport { isChromatic } from '../../../../../.storybook/isChromatic.ts';\n\ninterface BaseField {\n  label: string;\n  options: Record<string, { label: string }>;\n  required?: boolean;\n}\n\ninterface CheckboxField extends BaseField {\n  type: 'checkbox';\n  values: Record<keyof BaseField['options'], boolean>;\n}\n\ninterface SelectField extends BaseField {\n  type: 'select';\n  values: Record<keyof BaseField['options'], boolean>;\n}\n\ntype FormFields = {\n  building: CheckboxField;\n  interest: CheckboxField;\n  referrer: SelectField;\n};\n\nconst Content = styled(Modal.Content)(({ theme }) => ({\n  fontSize: theme.typography.size.s2,\n  color: theme.color.defaultText,\n  gap: 8,\n}));\n\nconst Row = styled.div({\n  display: 'grid',\n  gridTemplateColumns: '1fr 1fr',\n  gap: 14,\n  marginBottom: 8,\n});\n\nconst Question = styled.div(({ theme }) => ({\n  marginTop: 8,\n  marginBottom: 2,\n  fontWeight: theme.typography.weight.bold,\n}));\n\nconst Label = styled.label({\n  display: 'flex',\n  gap: 8,\n\n  '&:has(input[type=\"checkbox\"]:not(:disabled), input[type=\"radio\"]:not(:disabled))': {\n    cursor: 'pointer',\n  },\n});\n\nconst Actions = styled(Modal.Actions)({\n  marginTop: 8,\n});\n\nconst Checkbox = styled(Form.Checkbox)({\n  margin: 2,\n});\n\nexport const IntentSurvey = ({\n  isOpen,\n  onComplete,\n  onDismiss,\n}: {\n  isOpen: boolean;\n  onComplete: (formData: Record<string, Record<string, boolean>>) => void;\n  onDismiss: () => void;\n}) => {\n  const [isSubmitting, setIsSubmitting] = useState(false);\n\n  const [formFields, setFormFields] = useState<FormFields>({\n    building: {\n      label: 'What are you building?',\n      type: 'checkbox',\n      required: true,\n      options: shuffleObject({\n        'design-system': { label: 'Design system' },\n        'application-ui': { label: 'Application UI' },\n      }),\n      values: {\n        'design-system': false,\n        'application-ui': false,\n      },\n    },\n    interest: {\n      label: 'Which of these are you interested in?',\n      type: 'checkbox',\n      required: true,\n      options: shuffleObject({\n        'ui-documentation': { label: 'Generating UI docs' },\n        'functional-testing': { label: 'Functional testing' },\n        'accessibility-testing': { label: 'Accessibility testing' },\n        'visual-testing': { label: 'Visual testing' },\n        'ai-augmented-development': { label: 'Building UI with AI' },\n        'team-collaboration': { label: 'Team collaboration' },\n        'design-handoff': { label: 'Design handoff' },\n      }),\n      values: {\n        'ui-documentation': false,\n        'functional-testing': false,\n        'accessibility-testing': false,\n        'visual-testing': false,\n        'ai-augmented-development': false,\n        'team-collaboration': false,\n        'design-handoff': false,\n      },\n    },\n    referrer: {\n      label: 'How did you discover Storybook?',\n      type: 'select',\n      required: true,\n      options: shuffleObject({\n        'we-use-it-at-work': { label: 'We use it at work' },\n        'via-friend-or-colleague': { label: 'Via friend or colleague' },\n        'via-social-media': { label: 'Via social media' },\n        youtube: { label: 'YouTube' },\n        'web-search': { label: 'Web Search' },\n        'ai-agent': { label: 'AI Agent (e.g. ChatGPT)' },\n      }),\n      values: {\n        'we-use-it-at-work': false,\n        'via-friend-or-colleague': false,\n        'via-social-media': false,\n        youtube: false,\n        'web-search': false,\n        'ai-agent': false,\n      },\n    },\n  });\n\n  const updateFormData = (key: keyof FormFields, optionOrValue: string, value?: boolean) => {\n    const field = formFields[key];\n    setFormFields((fields) => {\n      if (field.type === 'checkbox') {\n        const values = { ...field.values, [optionOrValue]: !!value };\n        return { ...fields, [key]: { ...field, values } };\n      }\n      if (field.type === 'select') {\n        const values = Object.fromEntries(\n          Object.entries(field.values).map(([opt]) => [opt, opt === optionOrValue])\n        );\n        return { ...fields, [key]: { ...field, values } };\n      }\n      return fields;\n    });\n  };\n\n  const isValid = Object.values(formFields).every((field) => {\n    if (!field.required) {\n      return true;\n    }\n    // Check if at least one option is selected (true)\n    return Object.values(field.values).some((value) => value === true);\n  });\n\n  const onSubmitForm = (e: React.FormEvent<HTMLFormElement>) => {\n    if (!isValid) {\n      return;\n    }\n    e.preventDefault();\n    setIsSubmitting(true);\n    onComplete(\n      Object.fromEntries(Object.entries(formFields).map(([key, field]) => [key, field.values]))\n    );\n  };\n\n  return (\n    <Modal\n      ariaLabel=\"Storybook user survey\"\n      open={isOpen}\n      width={420}\n      onOpenChange={(isOpen) => {\n        if (!isOpen) {\n          onDismiss();\n        }\n      }}\n    >\n      <Form onSubmit={onSubmitForm} id=\"intent-survey-form\">\n        <Content>\n          <Modal.Header onClose={onDismiss}>\n            <Modal.Title>Help improve Storybook</Modal.Title>\n          </Modal.Header>\n\n          {(Object.keys(formFields) as Array<keyof FormFields>).map((key) => {\n            const field = formFields[key];\n            return (\n              <Fragment key={key}>\n                <Question>{field.label}</Question>\n                {field.type === 'checkbox' && (\n                  <Row>\n                    {Object.entries(field.options).map(([opt, option]) => {\n                      const id = `${key}:${opt}`;\n                      return (\n                        <div key={id}>\n                          <Label htmlFor={id}>\n                            <Checkbox\n                              name={id}\n                              id={id}\n                              checked={field.values[opt]}\n                              disabled={isSubmitting}\n                              onChange={(e) => updateFormData(key, opt, e.target.checked)}\n                            />\n                            {option.label}\n                          </Label>\n                        </div>\n                      );\n                    })}\n                  </Row>\n                )}\n                {field.type === 'select' && (\n                  <Form.Select\n                    name={key}\n                    id={key}\n                    value={\n                      Object.entries(field.values).find(([, isSelected]) => isSelected)?.[0] || ''\n                    }\n                    required={field.required}\n                    disabled={isSubmitting}\n                    onChange={(e) => updateFormData(key, e.target.value)}\n                  >\n                    <option disabled hidden value=\"\">\n                      Select an option...\n                    </option>\n                    {Object.entries(field.options).map(([opt, option]) => (\n                      <option key={opt} value={opt}>\n                        {option.label}\n                      </option>\n                    ))}\n                  </Form.Select>\n                )}\n              </Fragment>\n            );\n          })}\n\n          <Actions>\n            <Button\n              ariaLabel={false}\n              disabled={isSubmitting || !isValid}\n              size=\"medium\"\n              type=\"submit\"\n              variant=\"solid\"\n            >\n              Submit\n            </Button>\n          </Actions>\n        </Content>\n      </Form>\n    </Modal>\n  );\n};\n\nfunction shuffle<T>(array: T[]): T[] {\n  for (let i = array.length - 1; i > 0; i--) {\n    const j = Math.floor(Math.random() * (i + 1));\n    [array[i], array[j]] = [array[j], array[i]];\n  }\n  return array;\n}\n\nfunction shuffleObject<T extends object>(object: T): T {\n  return isChromatic() ? object : (Object.fromEntries(shuffle(Object.entries(object))) as T);\n}\n"
  },
  {
    "path": "code/addons/onboarding/src/features/SplashScreen/SplashScreen.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { SplashScreen } from './SplashScreen.tsx';\n\nconst meta = {\n  component: SplashScreen,\n  args: {\n    onDismiss: () => {},\n  },\n} satisfies Meta<typeof SplashScreen>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {\n  parameters: {\n    chromatic: {\n      disableSnapshot: true,\n    },\n  },\n};\n\nexport const Static: Story = {\n  args: {\n    duration: 0,\n  },\n};\n"
  },
  {
    "path": "code/addons/onboarding/src/features/SplashScreen/SplashScreen.tsx",
    "content": "import React, { useCallback, useEffect, useState } from 'react';\n\nimport { ArrowRightIcon } from '@storybook/icons';\n\nimport { keyframes, styled } from 'storybook/theming';\n\nconst fadeIn = keyframes({\n  from: {\n    opacity: 0,\n  },\n  to: {\n    opacity: 1,\n  },\n});\n\nconst slideIn = keyframes({\n  from: {\n    transform: 'translate(0, 20px)',\n    opacity: 0,\n  },\n  to: {\n    transform: 'translate(0, 0)',\n    opacity: 1,\n  },\n});\n\nconst scaleIn = keyframes({\n  from: {\n    opacity: 0,\n    transform: 'scale(0.8)',\n  },\n  to: {\n    opacity: 1,\n    transform: 'scale(1)',\n  },\n});\n\nconst rotate = keyframes({\n  '0%': {\n    transform: 'rotate(0deg)',\n  },\n  '100%': {\n    transform: 'rotate(360deg)',\n  },\n});\n\nconst Wrapper = styled.div<{ visible: boolean }>(({ visible }) => ({\n  position: 'fixed',\n  top: 0,\n  left: 0,\n  right: 0,\n  bottom: 0,\n  display: 'flex',\n  opacity: visible ? 1 : 0,\n  alignItems: 'center',\n  justifyContent: 'center',\n  zIndex: 1000,\n  transition: 'opacity 1s 0.5s',\n}));\n\nconst Backdrop = styled.div({\n  position: 'absolute',\n  top: 0,\n  left: 0,\n  right: 0,\n  bottom: 0,\n  animation: `${fadeIn} 2s`,\n  background: `\n    radial-gradient(90% 90%, #ff4785 0%, #db5698 30%, #1ea7fdcc 100%),\n    radial-gradient(circle, #ff4785 0%, transparent 80%),\n    radial-gradient(circle at 30% 40%, #fc521f99 0%, #fc521f66 20%, transparent 40%),\n    radial-gradient(circle at 75% 75%, #fc521f99 0%, #fc521f77 18%, transparent 30%)`,\n  '&::before': {\n    opacity: 0.5,\n    background: `\n      radial-gradient(circle at 30% 40%, #fc521f99 0%, #fc521f66 10%, transparent 20%),\n      radial-gradient(circle at 75% 75%, #fc521f99 0%, #fc521f77 8%, transparent 20%)`,\n    content: '\"\"',\n    position: 'absolute',\n    top: '-50vw',\n    left: '-50vh',\n    transform: 'translate(-50%, -50%)',\n    width: 'calc(100vw + 100vh)',\n    height: 'calc(100vw + 100vh)',\n    animation: `${rotate} 12s linear infinite`,\n  },\n});\n\nconst Content = styled.div<{ visible: boolean }>(({ visible }) => ({\n  position: 'absolute',\n  top: '50%',\n  left: '50%',\n  transform: 'translate(-50%, -50%)',\n  color: 'white',\n  textAlign: 'center',\n  width: '90vw',\n  minWidth: 290,\n  maxWidth: 410,\n  opacity: visible ? 1 : 0,\n  transition: 'opacity 0.5s',\n\n  h1: {\n    fontSize: 45,\n    fontWeight: 'bold',\n    animation: `${slideIn} 1.5s 1s backwards`,\n  },\n}));\n\nconst Features = styled.div({\n  display: 'flex',\n  marginTop: 40,\n  div: {\n    display: 'flex',\n    flexBasis: '33.33%',\n    flexDirection: 'column',\n    alignItems: 'center',\n    animation: `${slideIn} 1s backwards`,\n    '&:nth-child(1)': {\n      animationDelay: '2s',\n    },\n    '&:nth-child(2)': {\n      animationDelay: '2.5s',\n    },\n    '&:nth-child(3)': {\n      animationDelay: '3s',\n    },\n  },\n  svg: {\n    marginBottom: 10,\n  },\n});\n\nconst RadialButton = styled.button({\n  display: 'inline-flex',\n  position: 'relative',\n  alignItems: 'center',\n  justifyContent: 'center',\n  marginTop: 40,\n  width: 48,\n  height: 48,\n  padding: 0,\n  borderRadius: '50%',\n  border: 0,\n  outline: 'none',\n  background: 'rgba(255, 255, 255, 0.3)',\n  cursor: 'pointer',\n  transition: 'background 0.2s',\n  animation: `${scaleIn} 1.5s 4s backwards`,\n\n  '&:hover, &:focus': {\n    background: 'rgba(255, 255, 255, 0.4)',\n  },\n});\n\nconst ArrowIcon = styled(ArrowRightIcon)({\n  width: 30,\n  color: 'white',\n});\n\nconst ProgressCircle = styled.svg<{ progress?: boolean; spinner?: boolean }>(({ progress }) => ({\n  position: 'absolute',\n  top: -1,\n  left: -1,\n  width: `50px!important`,\n  height: `50px!important`,\n  transform: 'rotate(-90deg)',\n  color: 'white',\n  circle: {\n    r: '24',\n    cx: '25',\n    cy: '25',\n    fill: 'transparent',\n    stroke: progress ? 'currentColor' : 'transparent',\n    strokeWidth: '1',\n    strokeLinecap: 'round',\n    strokeDasharray: Math.PI * 48,\n  },\n}));\n\ninterface SplashScreenProps {\n  onDismiss: () => void;\n  duration?: number;\n}\n\nexport const SplashScreen = ({ onDismiss, duration = 6000 }: SplashScreenProps) => {\n  const [progress, setProgress] = useState((-4000 * 100) / duration); // 4 seconds delay\n  const [visible, setVisible] = useState(true);\n  const ready = progress >= 100;\n\n  const dismiss = useCallback(() => {\n    setVisible(false);\n    const timeout = setTimeout(onDismiss, 1500);\n    return () => clearTimeout(timeout);\n  }, [onDismiss]);\n\n  useEffect(() => {\n    if (!duration) {\n      return;\n    }\n    const framelength = 1000 / 50; // 50 frames per second\n    const increment = 100 / (duration / framelength); // 0-100% at 20ms intervals\n    const interval = setInterval(() => setProgress((prev) => prev + increment), framelength);\n    return () => clearInterval(interval);\n  }, [duration]);\n\n  useEffect(() => {\n    if (ready) {\n      dismiss();\n    }\n  }, [ready, dismiss]);\n\n  return (\n    <Wrapper visible={visible}>\n      <Backdrop />\n      <Content visible={visible}>\n        <h1>Meet your new frontend workshop</h1>\n        <Features>\n          <div>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"33\" height=\"32\">\n              <path\n                d=\"M4.06 0H32.5v28.44h-3.56V32H.5V3.56h3.56V0Zm21.33 7.11H4.06v21.33h21.33V7.11Z\"\n                fill=\"currentColor\"\n              />\n            </svg>\n            Development\n          </div>\n          <div>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\">\n              <path\n                d=\"M15.95 32c-1.85 0-3.1-1.55-3.1-3.54 0-1.1.45-2.78 1.35-5.03.9-2.3 1.35-4.51 1.35-6.81a22.21 22.21 0 0 0-5.1 3.67c-2.5 2.47-4.95 4.9-7.55 4.9-1.6 0-2.9-1.1-2.9-2.43 0-1.46 1.35-2.91 4.3-3.62 1.45-.36 3.1-.75 4.95-1.06 1.8-.31 3.8-1.02 5.9-2.08a23.77 23.77 0 0 0-6.1-2.12C5.3 13.18 2.3 12.6 1 11.28.35 10.6 0 9.9 0 9.14 0 7.82 1.2 6.8 2.95 6.8c2.65 0 5.75 3.1 7.95 5.3 1.1 1.1 2.65 2.21 4.65 3.27v-.57c0-1.77-.15-3.23-.55-4.3-.8-2.11-2.05-5.43-2.05-6.97 0-2.04 1.3-3.54 3.1-3.54 1.75 0 3.1 1.41 3.1 3.54 0 1.06-.45 2.78-1.35 5.12-.9 2.35-1.35 4.6-1.35 6.72 2.85-1.59 2.5-1.41 4.95-3.5 2.35-2.29 4-3.7 4.9-4.23.95-.58 1.9-.84 2.9-.84 1.6 0 2.8.97 2.8 2.34 0 1.5-1.25 2.78-4.15 3.62-1.4.4-3.05.75-4.9 1.1-1.9.36-3.9 1.07-6.1 2.13a23.3 23.3 0 0 0 5.95 2.08c3.65.7 6.75 1.32 8.15 2.6.7.67 1.05 1.33 1.05 2.08 0 1.33-1.2 2.43-2.95 2.43-2.95 0-6.75-4.15-8.2-5.61-.7-.7-2.2-1.72-4.4-2.96v.57c0 1.9.45 4.03 1.3 6.32.85 2.3 1.3 3.94 1.3 4.95 0 2.08-1.35 3.54-3.1 3.54Z\"\n                fill=\"currentColor\"\n              />\n            </svg>\n            Testing\n          </div>\n          <div>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"33\" height=\"32\">\n              <path\n                d=\"M.5 16a16 16 0 1 1 32 0 16 16 0 0 1-32 0Zm16 12.44A12.44 12.44 0 0 1 4.3 13.53a8 8 0 1 0 9.73-9.73 12.44 12.44 0 1 1 2.47 24.64ZM12.06 16a4.44 4.44 0 1 1 0-8.89 4.44 4.44 0 0 1 0 8.89Z\"\n                fill=\"currentColor\"\n                fillRule=\"evenodd\"\n              />\n            </svg>\n            Documentation\n          </div>\n        </Features>\n        <RadialButton onClick={dismiss}>\n          <ArrowIcon />\n          <ProgressCircle xmlns=\"http://www.w3.org/2000/svg\">\n            <circle />\n          </ProgressCircle>\n          <ProgressCircle xmlns=\"http://www.w3.org/2000/svg\" progress>\n            <circle\n              strokeDashoffset={Math.PI * 48 * (1 - Math.max(0, Math.min(progress, 100)) / 100)}\n            />\n          </ProgressCircle>\n        </RadialButton>\n      </Content>\n    </Wrapper>\n  );\n};\n"
  },
  {
    "path": "code/addons/onboarding/src/index.ts",
    "content": "// make it work with --isolatedModules\nexport default {};\n"
  },
  {
    "path": "code/addons/onboarding/src/manager.tsx",
    "content": "import React, { Suspense, lazy } from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport { STORY_SPECIFIED } from 'storybook/internal/core-events';\n\nimport { addons, internal_universalChecklistStore as checklistStore } from 'storybook/manager-api';\n\nimport { ADDON_CONTROLS_ID, ADDON_ID } from './constants.ts';\n\nconst Onboarding = lazy(() => import('./Onboarding.tsx'));\nconst Survey = lazy(() => import('./Survey.tsx'));\n\nlet root: ReturnType<typeof createRoot> | null = null;\nconst render = (node: React.ReactNode) => {\n  let container = document.getElementById('storybook-addon-onboarding');\n  if (!container) {\n    container = document.createElement('div');\n    container.id = 'storybook-addon-onboarding';\n    document.body.appendChild(container);\n  }\n  root = root ?? createRoot(container);\n  root.render(<Suspense fallback={<div />}>{node}</Suspense>);\n};\n\n// The addon is enabled only when:\n// 1. The onboarding query parameter is present\n// 2. The example button stories are present\naddons.register(ADDON_ID, async (api) => {\n  const { path, queryParams } = api.getUrlState();\n  const isOnboarding = path === '/onboarding' || queryParams.onboarding === 'true';\n  const isSurvey = queryParams.onboarding === 'survey';\n\n  const hasCompletedSurvey = await new Promise<boolean>((resolve) => {\n    const unsubscribe = checklistStore.onStateChange(({ loaded, items }) => {\n      if (loaded) {\n        unsubscribe();\n        resolve(items.onboardingSurvey.status === 'accepted');\n      }\n    });\n  });\n\n  if (isSurvey) {\n    return hasCompletedSurvey ? null : render(<Survey api={api} />);\n  }\n\n  await new Promise((resolve) => api.once(STORY_SPECIFIED, resolve));\n\n  const hasButtonStories =\n    !!api.getData('example-button--primary') ||\n    !!document.getElementById('example-button--primary');\n\n  if (!hasButtonStories) {\n    console.warn(\n      `[@storybook/addon-onboarding] It seems like you have finished the onboarding experience in Storybook! Therefore this addon is not necessary anymore and will not be loaded. You are free to remove it from your project. More info: https://github.com/storybookjs/storybook/tree/next/code/addons/onboarding#uninstalling`\n    );\n    return;\n  }\n\n  if (!isOnboarding || window.innerWidth < 730) {\n    return;\n  }\n\n  api.togglePanel(true);\n  api.togglePanelPosition('bottom');\n  api.setSelectedPanel(ADDON_CONTROLS_ID);\n\n  return render(<Onboarding api={api} hasCompletedSurvey={hasCompletedSurvey} />);\n});\n"
  },
  {
    "path": "code/addons/onboarding/src/preset.ts",
    "content": "import type { Channel } from 'storybook/internal/channels';\nimport { telemetry } from 'storybook/internal/telemetry';\nimport type { CoreConfig, Options } from 'storybook/internal/types';\n\nimport { version as addonVersion } from '../package.json';\nimport { ADDON_ONBOARDING_CHANNEL } from './constants.ts';\n\ntype Event = {\n  type: 'telemetry' | 'survey';\n  step: string;\n  payload?: any;\n};\n\nexport const experimental_serverChannel = async (channel: Channel, options: Options) => {\n  const { disableTelemetry } = await options.presets.apply<CoreConfig>('core', {});\n\n  if (disableTelemetry) {\n    return channel;\n  }\n\n  channel.on(ADDON_ONBOARDING_CHANNEL, ({ type, ...event }: Event) => {\n    if (type === 'telemetry') {\n      telemetry('addon-onboarding', { ...event, addonVersion });\n    } else if (type === 'survey') {\n      telemetry('onboarding-survey', { ...event, addonVersion });\n    }\n  });\n\n  return channel;\n};\n"
  },
  {
    "path": "code/addons/onboarding/src/types.d.ts",
    "content": "declare module '*.png' {\n  const content: any;\n  export default content;\n}\n"
  },
  {
    "path": "code/addons/onboarding/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/addons/onboarding/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/addons/pseudo-states/README.md",
    "content": "<img src=\"https://user-images.githubusercontent.com/321738/105224055-f6c29c00-5b5c-11eb-83c9-ba28a7fbadf2.gif\" width=\"80\" height=\"80\" alt=\"\">\n\n# Storybook Pseudo States\n\nToggle CSS pseudo states for your components in Storybook.\n\n<p>\n  <img src=\"https://user-images.githubusercontent.com/321738/105100903-51e98580-5aae-11eb-82bf-2b625c5a88a3.gif\" width=\"560\" alt=\"\" />\n</p>\n\n## Introduction\n\nThis addon attempts to \"force\" your components' pseudo states. It rewrites all document stylesheets to add a class name selector to any rules that target a pseudo-class (`:hover`, `:focus`, etc.). The tool then allows you to toggle these class names on the story container (`#root`) or any other root element you want (via the `rootSelector` param). Additionally, you can set the `pseudo` property on your story `parameters` to set a default value for each pseudo class. This makes it possible to test such states with [Chromatic](https://www.chromatic.com/).\n\n### Limitations\n\nBecause this addon rewrites your stylesheets rather than toggle the actual browser behavior like DevTools does, it won't render any of the default user agent (browser) styles. Unfortunately there's no JavaScript API to toggle real pseudo states without using a browser extension.\n\n## Getting Started\n\nTo install the addon:\n\n```sh\nnpx storybook add storybook-addon-pseudo-states\n```\n\nFor Storybook versions before 9.0, use v4.0.3 of the addon:\n\n```sh\nnpx storybook add storybook-addon-pseudo-states@4.0.3\n```\n\n### Setting default story states\n\nYou can have your stories automatically use a specific set of pseudo states, by setting the `pseudo` property on `parameters`:\n\n```jsx\nexport const Hover = () => <Button>Label</Button>;\nHover.parameters = { pseudo: { hover: true } };\n```\n\nThis is what enables snapshot testing your pseudo states in [Chromatic](https://www.chromatic.com/).\n\n### Targeting specific elements\n\nIf you don't want to force or toggle pseudo styles to all elements that use them, but rather only enable them on specific elements, you can set a string or array value instead of a boolean:\n\n```jsx\nexport const Buttons = () => (\n  <>\n    <Button id=\"one\">Hover</Button>\n    <Button id=\"two\">Hover focus</Button>\n    <Button id=\"three\">Hover focus active</Button>\n  </>\n);\nButtons.parameters = {\n  pseudo: {\n    hover: ['#one', '#two', '#three'],\n    focus: ['#two', '#three'],\n    active: '#three',\n  },\n};\n```\n\nThis accepts a single CSS selector (string), or an array of CSS selectors on which to enable that pseudo style.\n\n### Overriding the default root element\n\nBy default, we use `#storybook-root` (or `#root` before Storybook 7) element as the root element for all pseudo classes. If you need to render elements outside Storybook's root element, you can set `parameters.pseudo.rootSelector` to override it. This is convenient for portals, dialogs, tooltips, etc.\n\nFor example, consider a `Dialog` component that injects itself to the document's `body` node:\n\n```jsx\nexport const DialogButton = () => (\n  <Dialog>\n    <Button>Hover</Button>\n  </Dialog>\n);\n\nDialogButton.parameters = {\n  pseudo: { hover: true, rootSelector: 'body' },\n};\n```\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/addons/pseudo-states/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./manager'],\n        entryPoint: './src/manager.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./preview'],\n        entryPoint: './src/preview.ts',\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/addons/pseudo-states/manager.js",
    "content": "export * from './dist/manager.js';\n"
  },
  {
    "path": "code/addons/pseudo-states/package.json",
    "content": "{\n  \"name\": \"storybook-addon-pseudo-states\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook Pseudo-states addon: Manipulate CSS pseudo states\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-addon\",\n    \"css\",\n    \"pseudo states\",\n    \"style\",\n    \"test\",\n    \"component\",\n    \"components\",\n    \"react\",\n    \"vue\",\n    \"angular\",\n    \"svelte\",\n    \"web-components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/addons/pseudo-states\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/addons/pseudo-states\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./manager\": \"./dist/manager.js\",\n    \"./package.json\": \"./package.json\",\n    \"./preview\": {\n      \"types\": \"./dist/preview.d.ts\",\n      \"code\": \"./src/preview.ts\",\n      \"default\": \"./dist/preview.js\"\n    }\n  },\n  \"files\": [\n    \"*.js\",\n    \"*.d.ts\",\n    \"dist/**/*\",\n    \"!src/**/*\"\n  ],\n  \"devDependencies\": {\n    \"@storybook/icons\": \"^2.0.1\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"storybook\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"storybook\": {\n    \"displayName\": \"Pseudo States\",\n    \"icon\": \"https://user-images.githubusercontent.com/321738/105224055-f6c29c00-5b5c-11eb-83c9-ba28a7fbadf2.gif\",\n    \"unsupportedFrameworks\": [\n      \"react-native\"\n    ]\n  }\n}\n"
  },
  {
    "path": "code/addons/pseudo-states/preview.js",
    "content": "export * from './dist/preview.js';\n"
  },
  {
    "path": "code/addons/pseudo-states/project.json",
    "content": "{\n  \"name\": \"storybook-addon-pseudo-states\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/addons/pseudo-states/src/constants.ts",
    "content": "export const ADDON_ID = 'storybook/pseudo-states';\nexport const TOOL_ID = `${ADDON_ID}/tool`;\nexport const PARAM_KEY = 'pseudo';\n\n// Regex patterns for pseudo-elements which are not allowed to have classes applied on them\n// E.g. ::-webkit-scrollbar-thumb.pseudo-hover is not a valid selector\nexport const EXCLUDED_PSEUDO_ELEMENT_PATTERNS = ['::-(webkit|moz|ms)-[a-z-]+', '::part\\\\([^)]+\\\\)'];\n\n/**\n * This lookbehind ensures we don't match escaped pseudo-states commonly used in Tailwind (e.g.\n * `.foo\\:hover\\:bar:hover`). We do this by skipping pseudo-states preceded by an odd number of `\\`\n * escapes.\n *\n * @example\n *\n * Excluded:\n *\n * ```\n * .foo\\:pseudo-selector {}\n * .foo\\\\\\:pseudo-selector {}\n * ```\n *\n * Included:\n *\n * ```\n * .foo\\\\:pseudo-selector {}\n * .foo\\\\\\\\:pseudo-selector {}\n * ```\n */\nexport const EXCLUDED_PSEUDO_ESCAPE_SEQUENCE = '(?<=(?<!\\\\\\\\)(?:\\\\\\\\\\\\\\\\)*)';\n\n// Dynamic pseudo-classes\n// @see https://www.w3.org/TR/2018/REC-selectors-3-20181106/#dynamic-pseudos\nexport const PSEUDO_STATES = {\n  hover: 'hover',\n  active: 'active',\n  focusVisible: 'focus-visible',\n  focusWithin: 'focus-within',\n  focus: 'focus', // must come after its alternatives\n  visited: 'visited',\n  link: 'link',\n  target: 'target',\n} as const;\n"
  },
  {
    "path": "code/addons/pseudo-states/src/index.ts",
    "content": "import { definePreviewAddon } from 'storybook/internal/csf';\n\nimport * as addonAnnotations from './preview.ts';\nimport type { PseudoTypes } from './types.ts';\n\nexport { PARAM_KEY } from './constants.ts';\n\nexport type { PseudoTypes } from './types.ts';\n\nexport default () => definePreviewAddon<PseudoTypes>(addonAnnotations);\n"
  },
  {
    "path": "code/addons/pseudo-states/src/manager/PseudoStateTool.tsx",
    "content": "import React from 'react';\n\nimport { Select } from 'storybook/internal/components';\n\nimport { ButtonIcon } from '@storybook/icons';\n\nimport { useGlobals } from 'storybook/manager-api';\n\nimport { PARAM_KEY, PSEUDO_STATES } from '../constants.ts';\n\nconst pseudoStates = Object.keys(PSEUDO_STATES).sort() as (keyof typeof PSEUDO_STATES)[];\n\nexport const PseudoStateTool = () => {\n  const [globals, updateGlobals] = useGlobals();\n\n  const defaultOptions = Object.keys(globals[PARAM_KEY] || {}).filter((key) =>\n    pseudoStates.includes(key as keyof typeof PSEUDO_STATES)\n  );\n\n  const options = pseudoStates.map((option) => {\n    return {\n      title: `:${PSEUDO_STATES[option]}`,\n      value: option,\n    };\n  });\n\n  return (\n    <Select\n      resetLabel=\"Reset pseudo states\"\n      onReset={() => updateGlobals({ [PARAM_KEY]: {} })}\n      icon={<ButtonIcon />}\n      ariaLabel=\"CSS pseudo states\"\n      tooltip=\"Apply CSS pseudo states\"\n      defaultOptions={defaultOptions}\n      options={options}\n      multiSelect\n      onChange={(selected) => {\n        updateGlobals({\n          // We know curr is a string because we are using string values in options\n          [PARAM_KEY]: selected.reduce((acc, curr) => ({ ...acc, [curr as string]: true }), {}),\n        });\n      }}\n    />\n  );\n};\n"
  },
  {
    "path": "code/addons/pseudo-states/src/manager.ts",
    "content": "import { addons, types } from 'storybook/manager-api';\n\nimport { ADDON_ID, TOOL_ID } from './constants.ts';\nimport { PseudoStateTool } from './manager/PseudoStateTool.tsx';\n\naddons.register(ADDON_ID, () => {\n  addons.add(TOOL_ID, {\n    type: types.TOOL,\n    title: 'CSS pseudo states',\n    match: ({ viewMode }) => viewMode === 'story',\n    render: PseudoStateTool,\n  });\n});\n"
  },
  {
    "path": "code/addons/pseudo-states/src/preview/rewriteStyleSheet.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { rewriteStyleSheet } from './rewriteStyleSheet.ts';\nimport { splitSelectors } from './splitSelectors.ts';\n\nfunction splitRules(cssText: string): string[] {\n  let ruleStart: number | undefined;\n  let depth = 0;\n  const rules: string[] = [];\n  const chars = [...cssText];\n  chars.forEach((c, i) => {\n    if (c === '{') {\n      depth++;\n    } else if (c === '}') {\n      if (--depth === 0) {\n        rules.push(cssText.substring(ruleStart!, i + 1));\n        ruleStart = undefined;\n      }\n    } else if (ruleStart === undefined && c !== ' ' && c !== '\\n') {\n      ruleStart = i;\n    }\n  });\n  return rules;\n}\n\nabstract class Rule {\n  constructor(readonly cssText: string) {}\n\n  selectorText?: string;\n\n  static parse(cssText: string): Rule {\n    return cssText.trim().startsWith('@') ? new GroupingRule(cssText) : new StyleRule(cssText);\n  }\n\n  getSelectors(): string[] {\n    return this.selectorText ? splitSelectors(this.selectorText) : [];\n  }\n\n  toString() {\n    return this.cssText;\n  }\n}\n\nclass StyleRule extends Rule {\n  __processed = false;\n\n  __pseudoStatesRewrittenCount = 0;\n\n  constructor(cssText: string) {\n    super(cssText);\n    if (cssText.trim().startsWith('@')) {\n      throw new Error('StyleRule cannot start with @');\n    }\n    this.selectorText = cssText.substring(0, cssText.indexOf(' {'));\n  }\n}\n\nclass GroupingRule extends Rule {\n  cssRules: Rule[];\n\n  constructor(cssText: string) {\n    super(cssText);\n    const innerCssText = cssText.substring(cssText.indexOf('{') + 1, cssText.lastIndexOf('}'));\n    this.cssRules = splitRules(innerCssText).map((x) => Rule.parse(x));\n  }\n\n  deleteRule(index: number) {\n    this.cssRules.splice(index, 1);\n  }\n\n  insertRule(cssText: string, index: number) {\n    this.cssRules.splice(index, 0, Rule.parse(cssText));\n  }\n}\n\nclass Sheet {\n  cssRules: Rule[];\n\n  constructor(cssText: string) {\n    this.cssRules = splitRules(cssText).map((x) => Rule.parse(x));\n  }\n\n  deleteRule(index: number) {\n    this.cssRules.splice(index, 1);\n  }\n\n  insertRule(cssText: string, index: number) {\n    this.cssRules.splice(index, 0, Rule.parse(cssText));\n  }\n}\n\ndescribe('rewriteStyleSheet', () => {\n  it('returns true if a rule was rewritten', () => {\n    const sheet = new Sheet('a:hover { color: red }');\n    expect(rewriteStyleSheet(sheet as any)).toEqual(true);\n  });\n\n  it('returns true if a nested rule was rewritten', () => {\n    const sheet = new Sheet('@layer foo { a:hover { color: red } }');\n    expect(rewriteStyleSheet(sheet as any)).toEqual(true);\n  });\n\n  it('returns false if no rules were rewritten', () => {\n    const sheet = new Sheet(`\n      a { color: red }\n      @layer foo {\n        a { color: red }\n      }\n    `);\n    expect(rewriteStyleSheet(sheet as any)).toEqual(false);\n  });\n\n  it('does not create additional rules', () => {\n    const sheet = new Sheet('a:hover { color: red }');\n    rewriteStyleSheet(sheet as any);\n    expect(sheet.cssRules.length).toEqual(1);\n  });\n\n  it('does not remove original selector', () => {\n    const sheet = new Sheet('a:hover { color: red }');\n    rewriteStyleSheet(sheet as any);\n    expect(sheet.cssRules[0].getSelectors()).toContain('a:hover');\n  });\n\n  it('adds alternative selector targeting the element directly', () => {\n    const sheet = new Sheet('a:hover { color: red }');\n    rewriteStyleSheet(sheet as any);\n    expect(sheet.cssRules[0].getSelectors()).toContain('a.pseudo-hover');\n  });\n\n  it('adds alternative selector targeting an ancestor', () => {\n    const sheet = new Sheet('a:hover { color: red }');\n    rewriteStyleSheet(sheet as any);\n    expect(sheet.cssRules[0].getSelectors()).toContain('.pseudo-hover-all a');\n  });\n\n  it('does not add unexpected selectors', () => {\n    const sheet = new Sheet('a:hover { color: red }');\n    rewriteStyleSheet(sheet as any);\n    expect(\n      sheet.cssRules[0]\n        .getSelectors()\n        .filter((x) => !['a:hover', 'a.pseudo-hover', '.pseudo-hover-all a'].includes(x))\n    ).toEqual([]);\n  });\n\n  it('does not add invalid selector where .pseudo-<class> would be appended to ::-webkit-* pseudo-element', () => {\n    const sheet = new Sheet('::-webkit-foo-bar:hover { border-color: transparent; }');\n    rewriteStyleSheet(sheet as any);\n    expect(sheet.cssRules[0].getSelectors()).not.toContain('::-webkit-foo-bar.pseudo-hover');\n    expect(sheet.cssRules[0].getSelectors()).toContain('.pseudo-hover-all ::-webkit-foo-bar');\n  });\n\n  it('does not add invalid selector where .pseudo-<class> would be appended to ::-moz-* pseudo-element', () => {\n    const sheet = new Sheet('::-moz-foo-bar-baz:hover { border-color: transparent; }');\n    rewriteStyleSheet(sheet as any);\n    expect(sheet.cssRules[0].getSelectors()).not.toContain('::-moz-foo-bar-baz.pseudo-hover');\n    expect(sheet.cssRules[0].getSelectors()).toContain('.pseudo-hover-all ::-moz-foo-bar-baz');\n  });\n\n  it('does not add invalid selector where .pseudo-<class> would be appended to ::-ms-* pseudo-element', () => {\n    const sheet = new Sheet('::-ms-foo:hover { border-color: transparent; }');\n    rewriteStyleSheet(sheet as any);\n    expect(sheet.cssRules[0].getSelectors()).not.toContain('::-ms-foo.pseudo-hover');\n    expect(sheet.cssRules[0].getSelectors()).toContain('.pseudo-hover-all ::-ms-foo');\n  });\n\n  it('adds alternative selector when .pseudo-<class> would not be appended to pseudo-element', () => {\n    const sheet = new Sheet('div:hover::-webkit-scrollbar-thumb { border-color: transparent; }');\n    rewriteStyleSheet(sheet as any);\n    expect(sheet.cssRules[0].getSelectors()).toContain('div.pseudo-hover::-webkit-scrollbar-thumb');\n  });\n\n  it('does not add invalid selector where .pseudo-<class> would be appended to ::part()', () => {\n    const sheet = new Sheet('::part(foo bar):hover { border-color: transparent; }');\n    rewriteStyleSheet(sheet as any);\n    expect(sheet.cssRules[0].getSelectors()).not.toContain('::part(foo bar).pseudo-hover');\n    expect(sheet.cssRules[0].getSelectors()).toContain('.pseudo-hover-all ::part(foo bar)');\n  });\n\n  it('adds alternative selector when .pseudo-<class> would not be appended to ::part()', () => {\n    const sheet = new Sheet('custom-elt:hover::part(foo bar) { border-color: transparent; }');\n    rewriteStyleSheet(sheet as any);\n    expect(sheet.cssRules[0].getSelectors()).toContain('custom-elt.pseudo-hover::part(foo bar)');\n  });\n\n  it('does not replace :is() with :is(*)', () => {\n    const sheet = new Sheet(':is():hover { color: red }');\n    rewriteStyleSheet(sheet as any);\n    expect(sheet.cssRules[0].getSelectors()).toContain('.pseudo-hover-all :is()');\n  });\n\n  it('adds alternative selector for each pseudo selector', () => {\n    const sheet = new Sheet('a:hover, a:focus { color: red }');\n    rewriteStyleSheet(sheet as any);\n    const selectors = sheet.cssRules[0].getSelectors();\n    expect(selectors).toContain('a.pseudo-hover');\n    expect(selectors).toContain('a.pseudo-focus');\n    expect(selectors).toContain('.pseudo-hover-all a');\n    expect(selectors).toContain('.pseudo-focus-all a');\n  });\n\n  it('keeps non-pseudo selectors as-is', () => {\n    const sheet = new Sheet('a.class, a:hover, a:focus, a#id { color: red }');\n    rewriteStyleSheet(sheet as any);\n    const selectors = sheet.cssRules[0].getSelectors();\n    expect(selectors).toContain('a.class');\n    expect(selectors).toContain('a#id');\n  });\n\n  it('does not duplicate selectors on subsequent rewrites', () => {\n    const sheet = new Sheet('a:hover { color: red }');\n    rewriteStyleSheet(sheet as any);\n    rewriteStyleSheet(sheet as any);\n    const selectors = sheet.cssRules[0].getSelectors();\n    selectors.splice(selectors.indexOf('a.pseudo-hover'), 1);\n    expect(selectors).not.toContain('a.pseudo-hover');\n  });\n\n  it('supports combined pseudo selectors', () => {\n    const sheet = new Sheet('a:hover:focus { color: red }');\n    rewriteStyleSheet(sheet as any);\n    const selectors = sheet.cssRules[0].getSelectors();\n    expect(selectors).toContain('a.pseudo-hover.pseudo-focus');\n    expect(selectors).toContain('.pseudo-hover-all.pseudo-focus-all a');\n  });\n\n  it('supports combined pseudo selectors with classes', () => {\n    const sheet = new Sheet('.hiOZqY:hover { color: red }');\n    rewriteStyleSheet(sheet as any);\n    const selectors = sheet.cssRules[0].getSelectors();\n    expect(selectors).toContain('.hiOZqY:hover');\n    expect(selectors).toContain('.hiOZqY.pseudo-hover');\n    expect(selectors).toContain('.pseudo-hover-all .hiOZqY');\n  });\n\n  it('supports \":host\"', () => {\n    const sheet = new Sheet(':host(:hover) { color: red }');\n    rewriteStyleSheet(sheet as any);\n    const selectors = sheet.cssRules[0].getSelectors();\n    expect(selectors).toContain(':host(:hover)');\n    expect(selectors).toContain(':host(.pseudo-hover)');\n    expect(selectors).toContain(':host(.pseudo-hover-all)');\n  });\n\n  it('supports \":host\" with classes', () => {\n    const sheet = new Sheet(':host(.a:hover) .c { color: red }');\n    rewriteStyleSheet(sheet as any);\n    const selectors = sheet.cssRules[0].getSelectors();\n    expect(selectors).toContain(':host(.a:hover) .c');\n    expect(selectors).toContain(':host(.a.pseudo-hover) .c');\n    expect(selectors).toContain(':host(.a.pseudo-hover-all) .c');\n  });\n\n  it('supports \":host\" with state selectors in descendant selector', () => {\n    const sheet = new Sheet(':host(.a) .b:hover { color: red }');\n    rewriteStyleSheet(sheet as any);\n    const selectors = sheet.cssRules[0].getSelectors();\n    expect(selectors).toContain(':host(.a) .b:hover');\n    expect(selectors).toContain(':host(.a) .b.pseudo-hover');\n    expect(selectors).toContain(':host(.a.pseudo-hover-all) .b');\n  });\n\n  it('supports \":host\" with state selectors in :host and descendant selector', () => {\n    const sheet = new Sheet(':host(.a:focus) .b:hover { color: red }');\n    rewriteStyleSheet(sheet as any);\n    const selectors = sheet.cssRules[0].getSelectors();\n    expect(selectors).toContain(':host(.a:focus) .b:hover');\n    expect(selectors).toContain(':host(.a.pseudo-focus) .b.pseudo-hover');\n    expect(selectors).toContain(':host(.a.pseudo-focus-all.pseudo-hover-all) .b');\n  });\n\n  it('supports \":host-context\"', () => {\n    const sheet = new Sheet(':host-context(:hover) { color: red }');\n    rewriteStyleSheet(sheet as any, true);\n    const selectors = sheet.cssRules[0].getSelectors();\n    expect(selectors).toContain(':host-context(:hover)');\n    expect(selectors).toContain(':host-context(.pseudo-hover)');\n    expect(selectors).toContain(':host(.pseudo-hover-all)');\n  });\n\n  it('supports \":host-context\" with classes', () => {\n    const sheet = new Sheet(':host-context(.a:hover) .b { color: red }');\n    rewriteStyleSheet(sheet as any, true);\n    const selectors = sheet.cssRules[0].getSelectors();\n    expect(selectors).toContain(':host-context(.a:hover) .b');\n    expect(selectors).toContain(':host-context(.a.pseudo-hover) .b');\n    expect(selectors).toContain(':host-context(.a).pseudo-hover-all .b');\n  });\n\n  it('supports \":host-context\" with state selectors in descendant selector', () => {\n    const sheet = new Sheet(':host-context(.a) .b:hover { color: red }');\n    rewriteStyleSheet(sheet as any, true);\n    const selectors = sheet.cssRules[0].getSelectors();\n    expect(selectors).toContain(':host-context(.a) .b:hover');\n    expect(selectors).toContain(':host-context(.a) .b.pseudo-hover');\n    expect(selectors).toContain(':host-context(.a).pseudo-hover-all .b');\n  });\n\n  it('supports \":host-context\" with state selectors in :host-context and descendant selector', () => {\n    const sheet = new Sheet(':host-context(.a:focus) .b:hover { color: red }');\n    rewriteStyleSheet(sheet as any, true);\n    const selectors = sheet.cssRules[0].getSelectors();\n    expect(selectors).toContain(':host-context(.a:focus) .b:hover');\n    expect(selectors).toContain(':host-context(.a.pseudo-focus) .b.pseudo-hover');\n    expect(selectors).toContain(':host-context(.a).pseudo-focus-all.pseudo-hover-all .b');\n  });\n\n  it('supports \"::slotted\"', () => {\n    const sheet = new Sheet('::slotted(:hover) { color: red }');\n    rewriteStyleSheet(sheet as any, true);\n    const selectors = sheet.cssRules[0].getSelectors();\n    expect(selectors).toContain('::slotted(:hover)');\n    expect(selectors).toContain('::slotted(.pseudo-hover)');\n    expect(selectors).toContain(':host(.pseudo-hover-all) ::slotted(*)');\n  });\n\n  it('supports \"::slotted\" with classes', () => {\n    const sheet = new Sheet('.a > slot::slotted(.b:hover) { color: red }');\n    rewriteStyleSheet(sheet as any, true);\n    const selectors = sheet.cssRules[0].getSelectors();\n    expect(selectors).toContain('.a > slot::slotted(.b:hover)');\n    expect(selectors).toContain('.a > slot::slotted(.b.pseudo-hover)');\n    expect(selectors).toContain(':host(.pseudo-hover-all) .a > slot::slotted(.b)');\n  });\n\n  it('supports \":not\"', () => {\n    const sheet = new Sheet(':not(:hover) { color: red }');\n    rewriteStyleSheet(sheet as any);\n    expect(sheet.cssRules[0].selectorText).toEqual(\n      ':not(:hover), :not(.pseudo-hover), :not(.pseudo-hover-all *)'\n    );\n  });\n\n  it('supports \":not\" in shadow DOM', () => {\n    const sheet = new Sheet(':not(:hover) { color: red }');\n    rewriteStyleSheet(sheet as any, true);\n    expect(sheet.cssRules[0].selectorText).toEqual(\n      ':not(:hover), :not(.pseudo-hover), :not(:host(.pseudo-hover-all) *)'\n    );\n  });\n\n  it('supports complex use of \":not\"', () => {\n    const sheet = new Sheet('foo:focus:not(:hover, .bar:active) .baz { color: red }');\n    rewriteStyleSheet(sheet as any);\n    const selectors = sheet.cssRules[0].getSelectors();\n    expect(selectors).toContain('foo:focus:not(:hover, .bar:active) .baz');\n    expect(selectors).toContain('foo.pseudo-focus:not(.pseudo-hover, .bar.pseudo-active) .baz');\n    expect(selectors).toContain(\n      '.pseudo-focus-all foo:not(.pseudo-hover-all *, .pseudo-active-all .bar) .baz'\n    );\n  });\n\n  it('supports complex use of \":not\" in shadow DOM', () => {\n    const sheet = new Sheet('foo:focus:not(:hover, .bar:active) .baz { color: red }');\n    rewriteStyleSheet(sheet as any, true);\n    const selectors = sheet.cssRules[0].getSelectors();\n    expect(selectors).toContain('foo:focus:not(:hover, .bar:active) .baz');\n    expect(selectors).toContain('foo.pseudo-focus:not(.pseudo-hover, .bar.pseudo-active) .baz');\n    expect(selectors).toContain(\n      ':host(.pseudo-focus-all) foo:not(:host(.pseudo-hover-all) *, :host(.pseudo-active-all) .bar) .baz'\n    );\n  });\n\n  it('supports \":not\" inside \":host\"', () => {\n    const sheet = new Sheet(':host(.foo:not(:hover)) .baz:active { color: red }');\n    rewriteStyleSheet(sheet as any, true);\n    const selectors = sheet.cssRules[0].getSelectors();\n    expect(selectors).toContain(':host(.foo:not(:hover)) .baz:active');\n    expect(selectors).toContain(':host(.foo:not(.pseudo-hover)) .baz.pseudo-active');\n    expect(selectors).toContain(':host(.foo:not(.pseudo-hover-all).pseudo-active-all) .baz');\n  });\n\n  it('supports \":not\" inside and outside of \":host\"', () => {\n    const sheet = new Sheet(':host(.foo:not(:hover)) .baz:not(:active) { color: red }');\n    rewriteStyleSheet(sheet as any, true);\n    const selectors = sheet.cssRules[0].getSelectors();\n    expect(selectors).toContain(':host(.foo:not(:hover)) .baz:not(:active)');\n    expect(selectors).toContain(':host(.foo:not(.pseudo-hover)) .baz:not(.pseudo-active)');\n    expect(selectors).toContain(\n      ':host(.foo:not(.pseudo-hover-all)) .baz:not(:host(.pseudo-active-all) *)'\n    );\n  });\n\n  it('supports \":has\"', () => {\n    const sheet = new Sheet(':has(:hover) { color: red }');\n    rewriteStyleSheet(sheet as any);\n    expect(sheet.cssRules[0].cssText).toEqual(\n      ':has(:hover), :has(.pseudo-hover), .pseudo-hover-all :has(*) { color: red }'\n    );\n  });\n\n  it('supports \":has\" inside and outside of \":not\"', () => {\n    const sheet = new Sheet(':has(:not(:hover, :has(:focus), :has(:active))) { color: red }');\n    rewriteStyleSheet(sheet as any);\n    expect(sheet.cssRules[0].cssText).toEqual(\n      ':has(:not(:hover, :has(:focus), :has(:active))), :has(:not(.pseudo-hover, :has(.pseudo-focus), :has(.pseudo-active))), :has(:not(.pseudo-hover-all *, .pseudo-focus-all :has(*), .pseudo-active-all :has(*))) { color: red }'\n    );\n  });\n\n  it('skips escaped pseudo-selectors \"\\\\:hover\"', () => {\n    const sheet = new Sheet('a\\\\:hover { color: red }');\n    rewriteStyleSheet(sheet as any);\n    expect(sheet.cssRules.length).toEqual(1);\n    expect(sheet.cssRules[0].cssText).toEqual('a\\\\:hover { color: red }');\n    expect(sheet.cssRules[0].selectorText).toEqual('a\\\\:hover');\n  });\n\n  it('supports \"\\\\\\\\:hover\"', () => {\n    const sheet = new Sheet('.btn\\\\\\\\:hover { color: red }');\n    rewriteStyleSheet(sheet as any);\n    expect(sheet.cssRules[0].cssText).toEqual(\n      '.btn\\\\\\\\:hover, .btn\\\\\\\\.pseudo-hover, .pseudo-hover-all .btn\\\\\\\\ { color: red }'\n    );\n  });\n\n  it('supports selectors with escaped and unescaped pseudo-selectors', () => {\n    const sheet = new Sheet('.foo\\\\:hover\\\\:red:hover { color: red }');\n    rewriteStyleSheet(sheet as any);\n    expect(sheet.cssRules[0].cssText).toEqual(\n      '.foo\\\\:hover\\\\:red:hover, .foo\\\\:hover\\\\:red.pseudo-hover, .pseudo-hover-all .foo\\\\:hover\\\\:red { color: red }'\n    );\n  });\n\n  it('override correct rules with media query present', () => {\n    const sheet = new Sheet(\n      `@media (max-width: 790px) {\n        .test {\n          background-color: green;\n        }\n      }\n      .test {\n        background-color: blue;\n      }\n      .test:hover {\n        background-color: red;\n      }\n      .test2:hover {\n        background-color: white;\n      }`\n    );\n    rewriteStyleSheet(sheet as any);\n    expect(sheet.cssRules[0].cssText).toContain('@media (max-width: 790px)');\n    expect(sheet.cssRules[1].getSelectors()).toContain('.test');\n    expect(sheet.cssRules[2].getSelectors()).toContain('.test:hover');\n    expect(sheet.cssRules[2].getSelectors()).toContain('.test.pseudo-hover');\n    expect(sheet.cssRules[2].getSelectors()).toContain('.pseudo-hover-all .test');\n    expect(sheet.cssRules[3].getSelectors()).toContain('.test2:hover');\n    expect(sheet.cssRules[3].getSelectors()).toContain('.test2.pseudo-hover');\n    expect(sheet.cssRules[3].getSelectors()).toContain('.pseudo-hover-all .test2');\n  });\n\n  it('rewrites rules inside \"@media\"', () => {\n    const sheet = new Sheet(\n      `@media (max-width: 790px) {\n        test:hover {\n          background-color: green;\n        }\n      }`\n    );\n    rewriteStyleSheet(sheet as any);\n    expect(sheet.cssRules[0].cssText).toContain('@media (max-width: 790px)');\n    const selectors = (sheet.cssRules[0] as GroupingRule).cssRules[0].getSelectors();\n    expect(selectors).toContain('test:hover');\n    expect(selectors).toContain('test.pseudo-hover');\n    expect(selectors).toContain('.pseudo-hover-all test');\n  });\n\n  it('rewrites rules inside \"@layer\"', () => {\n    const sheet = new Sheet(\n      `@layer base {\n        test:hover {\n          background-color: green;\n        }\n      }`\n    );\n    rewriteStyleSheet(sheet as any);\n    const selectors = (sheet.cssRules[0] as GroupingRule).cssRules[0].getSelectors();\n    expect(selectors).toContain('test:hover');\n    expect(selectors).toContain('test.pseudo-hover');\n    expect(selectors).toContain('.pseudo-hover-all test');\n  });\n\n  it('handles multiple group rules', () => {\n    const sheet = new Sheet(\n      `@media (max-width: 790px) {\n        test:hover {\n          background-color: green;\n        }\n      }\n      @media (max-width: 100px) {\n        test2:hover {\n          background-color: red;\n        }\n      }`\n    );\n    rewriteStyleSheet(sheet as any);\n    expect((sheet.cssRules[0] as GroupingRule).cssRules[0].getSelectors()).toContain(\n      'test.pseudo-hover'\n    );\n    expect((sheet.cssRules[1] as GroupingRule).cssRules[0].getSelectors()).toContain(\n      'test2.pseudo-hover'\n    );\n  });\n\n  it('handles nested group rules', () => {\n    const sheet = new Sheet(\n      `@layer base {\n        test:hover {\n          background-color: green;\n        }\n        @media (max-width: 790px) {\n          @layer base {\n            test:hover {\n              background-color: green;\n            }\n          }\n        }\n      }`\n    );\n    rewriteStyleSheet(sheet as any);\n    const layer = sheet.cssRules[0] as GroupingRule;\n    expect(layer.cssRules[0].getSelectors()).toContain('test.pseudo-hover');\n    const media = layer.cssRules[1] as GroupingRule;\n    const innerLayer = media.cssRules[0] as GroupingRule;\n    expect(innerLayer.cssRules[0].getSelectors()).toContain('test.pseudo-hover');\n  });\n\n  console.warn = () => {}; // suppress printing warnings about rewrite limit\n\n  it('can rewrite 1000 rules in a sheet', () => {\n    const sheet = new Sheet(Array(1000).fill('a:hover { color: red }').join('\\n'));\n    rewriteStyleSheet(sheet as any);\n    for (let i = 0; i < 1000; i++) {\n      expect(sheet.cssRules[i].getSelectors()).toContain('a.pseudo-hover');\n    }\n  });\n\n  it('skips rewriting rules beyond the first 1000', () => {\n    const sheet = new Sheet(Array(1001).fill('a:hover { color: red }').join('\\n'));\n    rewriteStyleSheet(sheet as any);\n    expect(sheet.cssRules[1000].getSelectors()).not.toContain('a.pseudo-hover');\n  });\n\n  it('can rewrite 1000 rules in a sheet with group rules', () => {\n    const sheet = new Sheet(Array(1000).fill('@layer foo { a:hover { color: red } }').join('\\n'));\n    rewriteStyleSheet(sheet as any);\n    for (let i = 0; i < 1000; i++) {\n      expect((sheet.cssRules[i] as GroupingRule).cssRules[0].getSelectors()).toContain(\n        'a.pseudo-hover'\n      );\n    }\n  });\n});\n"
  },
  {
    "path": "code/addons/pseudo-states/src/preview/rewriteStyleSheet.ts",
    "content": "import {\n  EXCLUDED_PSEUDO_ELEMENT_PATTERNS,\n  EXCLUDED_PSEUDO_ESCAPE_SEQUENCE,\n  PSEUDO_STATES,\n} from '../constants.ts';\nimport { splitSelectors } from './splitSelectors.ts';\n\nconst pseudoStates = Object.values(PSEUDO_STATES);\nconst pseudoStatesPattern = `${EXCLUDED_PSEUDO_ESCAPE_SEQUENCE}:(${pseudoStates.join('|')})`;\nconst matchOne = new RegExp(pseudoStatesPattern);\nconst matchAll = new RegExp(pseudoStatesPattern, 'g');\n\nconst warnings = new Set();\nconst warnOnce = (message: string) => {\n  if (warnings.has(message)) {\n    return;\n  }\n\n  console.warn(message);\n  warnings.add(message);\n};\n\nconst replacePseudoStates = (selector: string, allClass?: boolean) => {\n  const negativeLookbehind = `(?<!(?:${EXCLUDED_PSEUDO_ELEMENT_PATTERNS.join('|')})\\\\S*)`;\n  return pseudoStates.reduce(\n    (acc, state) =>\n      acc.replace(\n        new RegExp(`${negativeLookbehind}${EXCLUDED_PSEUDO_ESCAPE_SEQUENCE}:${state}`, 'g'),\n        `.pseudo-${state}${allClass ? '-all' : ''}`\n      ),\n    selector\n  );\n};\n\n// Does not handle :host() or :not() containing pseudo-states. Need to call replaceNotSelectors on the input first.\nconst replacePseudoStatesWithAncestorSelector = (\n  selector: string,\n  forShadowDOM: boolean,\n  additionalHostSelectors?: string\n) => {\n  const extracted = extractPseudoStates(selector);\n  if (extracted.states.length === 0 && !additionalHostSelectors) {\n    return selector;\n  }\n\n  const selectors = `${additionalHostSelectors ?? ''}${extracted.states.map((s) => `.pseudo-${s}-all`).join('')}`;\n\n  // If there was a :host-context() containing only pseudo-states, we will later add a :host selector that replaces it.\n  let { withoutPseudoStates } = extracted;\n  withoutPseudoStates = withoutPseudoStates.replace(':host-context(*)', '').trimStart();\n\n  // If there is a :host-context() selector, we don't need to introduce a :host() selector.\n  // We can just append the pseudo-state classes to the :host-context() selector.\n  return withoutPseudoStates.startsWith(':host-context(')\n    ? withoutPseudoStates.replace(/(?<=:host-context\\(\\S+)\\)/, `)${selectors}`)\n    : forShadowDOM\n      ? `:host(${selectors}) ${withoutPseudoStates}`\n      : `${selectors} ${withoutPseudoStates}`;\n};\n\nconst extractPseudoStates = (selector: string) => {\n  const states = new Set();\n  const withoutPseudoStates =\n    selector\n      .replace(matchAll, (_, state) => {\n        states.add(state);\n        return '';\n      })\n      // If removing pseudo-state selectors from inside a functional selector left it empty (thus invalid), must fix it by adding '*'.\n      // The negative lookbehind ensures we don't replace :is() with :is(*).\n      .replaceAll(/(?<!is)\\(\\)/g, '(*)')\n      // If a selector list was left with blank items (e.g. \", foo, , bar, \"), remove the extra commas/spaces.\n      .replace(/(?<=[\\s(]),\\s+|(,\\s+)+(?=\\))/g, '') || '*';\n\n  return {\n    states: Array.from(states),\n    withoutPseudoStates,\n  };\n};\n\nconst rewriteNotSelectors = (selector: string, forShadowDOM: boolean) => {\n  // Accept up to 3 levels of nested parentheses.\n  return [...selector.matchAll(/:not\\((?:[^()]|\\([^()]+\\)|\\((?:[^()]|\\([^()]+\\))+\\))+\\)/g)].reduce(\n    (acc, [originalNot]) => {\n      const selectorList = originalNot.match(/^:not\\((.+)\\)$/)?.[1] ?? '';\n      const rewrittenNot = rewriteNotSelector(selectorList, forShadowDOM);\n      return acc.replace(originalNot, rewrittenNot);\n    },\n    selector\n  );\n};\n\nconst rewriteNotSelector = (negatedSelectorList: string, forShadowDOM: boolean) => {\n  const rewrittenSelectors: string[] = [];\n  // For each negated selector\n  for (const negatedSelector of negatedSelectorList.split(/,\\s*/)) {\n    // :not cannot be nested and cannot contain pseudo-elements, so no need to worry about that.\n    // Also, there's no compelling use case for :host() inside :not(), so we don't handle that.\n    rewrittenSelectors.push(replacePseudoStatesWithAncestorSelector(negatedSelector, forShadowDOM));\n  }\n  return `:not(${rewrittenSelectors.join(', ')})`;\n};\n\nconst rewriteRule = ({ cssText, selectorText }: CSSStyleRule, forShadowDOM: boolean) => {\n  return cssText.replace(\n    selectorText,\n    splitSelectors(selectorText)\n      .flatMap((selector) => {\n        if (selector.includes('.pseudo-')) {\n          return [];\n        }\n        const replacementSelectors = [selector];\n        if (!matchOne.test(selector)) {\n          return replacementSelectors;\n        }\n\n        const classSelector = replacePseudoStates(selector);\n        if (classSelector !== selector) {\n          replacementSelectors.push(classSelector);\n        }\n\n        let ancestorSelector = '';\n\n        if (selector.startsWith(':host(')) {\n          const matches = selector.match(/^:host\\((\\S+)\\)\\s+(.+)$/);\n          if (matches && matchOne.test(matches[2])) {\n            // Simple replacement won't work on pseudo-state selectors outside of :host().\n            // E.g. :host(.foo) .bar:hover -> :host(.foo.pseudo-hover-all) .bar\n            // E.g. :host(.foo:focus) .bar:hover -> :host(.foo.pseudo-focus-all.pseudo-hover-all) .bar\n            let hostInnerSelector = matches[1];\n            let descendantSelector = matches[2];\n            // Simple replacement is fine for pseudo-state selectors inside :host() (even if inside :not()).\n            hostInnerSelector = replacePseudoStates(hostInnerSelector, true);\n            // Rewrite any :not selectors in the descendant selector.\n            descendantSelector = rewriteNotSelectors(descendantSelector, true);\n            // Any remaining pseudo-states in the descendant selector need to be moved into the host selector.\n            ancestorSelector = replacePseudoStatesWithAncestorSelector(\n              descendantSelector,\n              true,\n              hostInnerSelector\n            );\n          } else {\n            // Don't need to specially handle :not() because:\n            //  - if inside :host(), simple replacement is sufficient\n            //  - if outside :host(), didn't match any pseudo-states\n            ancestorSelector = replacePseudoStates(selector, true);\n          }\n        } else {\n          const withNotsReplaced = rewriteNotSelectors(selector, forShadowDOM);\n          ancestorSelector = replacePseudoStatesWithAncestorSelector(\n            withNotsReplaced,\n            forShadowDOM\n          );\n        }\n        replacementSelectors.push(ancestorSelector);\n\n        return replacementSelectors;\n      })\n      .join(', ')\n  );\n};\n\n// Rewrites the style sheet to add alternative selectors for any rule that targets a pseudo state.\n// A sheet can only be rewritten once, and may carry over between stories.\nexport const rewriteStyleSheet = (sheet: CSSStyleSheet, forShadowDOM = false): boolean => {\n  try {\n    const maximumRulesToRewrite = 1000;\n    const count = rewriteRuleContainer(sheet, maximumRulesToRewrite, forShadowDOM);\n\n    if (count >= maximumRulesToRewrite) {\n      warnOnce('Reached maximum of 1000 pseudo selectors per sheet, skipping the rest.');\n    }\n\n    return count > 0;\n  } catch (e) {\n    if (String(e).includes('cssRules')) {\n      warnOnce(`Can't access cssRules, likely due to CORS restrictions: ${sheet.href}`);\n    } else {\n      console.error(e, sheet.href);\n    }\n    return false;\n  }\n};\n\nconst rewriteRuleContainer = (\n  ruleContainer: CSSStyleSheet | CSSGroupingRule,\n  rewriteLimit: number,\n  forShadowDOM: boolean\n): number => {\n  let count = 0;\n  let index = -1;\n  for (const cssRule of ruleContainer.cssRules) {\n    index++;\n    let numRewritten = 0;\n\n    // @ts-expect-error We're adding this nonstandard property below\n    if (cssRule.__processed) {\n      // @ts-expect-error We're adding this nonstandard property below\n      numRewritten = cssRule.__pseudoStatesRewrittenCount;\n    } else {\n      let styleRule = cssRule as CSSStyleRule;\n\n      // Modify the rule, if it contains a pseudo state\n      if ('selectorText' in styleRule) {\n        if (matchOne.test(styleRule.selectorText)) {\n          const newRule = rewriteRule(styleRule, forShadowDOM);\n          ruleContainer.deleteRule(index);\n          ruleContainer.insertRule(newRule, index);\n          styleRule = ruleContainer.cssRules[index] as CSSStyleRule;\n          numRewritten = 1;\n        }\n      }\n\n      // If it has nested rules, check them as well\n      if ('cssRules' in styleRule && (styleRule.cssRules as CSSRuleList).length) {\n        numRewritten = rewriteRuleContainer(\n          styleRule as CSSGroupingRule,\n          rewriteLimit - count,\n          forShadowDOM\n        );\n      }\n\n      // @ts-expect-error We're adding this nonstandard property\n      cssRule.__processed = true;\n      // @ts-expect-error We're adding this nonstandard property\n      cssRule.__pseudoStatesRewrittenCount = numRewritten;\n    }\n    count += numRewritten;\n\n    if (count >= rewriteLimit) {\n      break;\n    }\n  }\n\n  return count;\n};\n"
  },
  {
    "path": "code/addons/pseudo-states/src/preview/splitSelectors.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { splitSelectors } from './splitSelectors.ts';\n\ndescribe('splitSelectors', () => {\n  it('handles basic selectors', () => {\n    expect(splitSelectors('.a')).toEqual(['.a']);\n\n    expect(splitSelectors('.a, .b')).toEqual(['.a', '.b']);\n  });\n\n  it('supports ::slotted and :is', () => {\n    expect(splitSelectors('::slotted(:is(button, a):active)')).toEqual([\n      '::slotted(:is(button, a):active)',\n    ]);\n\n    expect(\n      splitSelectors('::slotted(:is(button, a):active), ::slotted(:is(button, a):hover)')\n    ).toEqual(['::slotted(:is(button, a):active)', '::slotted(:is(button, a):hover)']);\n  });\n\n  it('supports :host', () => {\n    expect(\n      splitSelectors(\n        \":host([type='secondary']) ::slotted(:is(button, a)), :host([type='primary']) ::slotted(:is(button, a):active)\"\n      )\n    ).toEqual([\n      \":host([type='secondary']) ::slotted(:is(button, a))\",\n      \":host([type='primary']) ::slotted(:is(button, a):active)\",\n    ]);\n\n    expect(\n      splitSelectors(\n        ':host([outline]) ::slotted(:is(button, a):focus-within:focus-visible:not(:active))'\n      )\n    ).toEqual([\n      ':host([outline]) ::slotted(:is(button, a):focus-within:focus-visible:not(:active))',\n    ]);\n  });\n});\n"
  },
  {
    "path": "code/addons/pseudo-states/src/preview/splitSelectors.ts",
    "content": "const isAtRule = (selector: string) => selector.indexOf('@') === 0;\n\nexport const splitSelectors = (selectors: string) => {\n  if (isAtRule(selectors)) {\n    return [selectors];\n  }\n\n  const result = [];\n  let parentheses = 0;\n  let brackets = 0;\n  let selector = '';\n\n  for (let i = 0, len = selectors.length; i < len; i++) {\n    const char = selectors[i];\n    if (char === '(') {\n      parentheses += 1;\n    } else if (char === ')') {\n      parentheses -= 1;\n    } else if (char === '[') {\n      brackets += 1;\n    } else if (char === ']') {\n      brackets -= 1;\n    } else if (char === ',') {\n      if (!parentheses && !brackets) {\n        result.push(selector.trim());\n        selector = '';\n        continue;\n      }\n    }\n    selector += char;\n  }\n\n  result.push(selector.trim());\n  return result;\n};\n"
  },
  {
    "path": "code/addons/pseudo-states/src/preview/withPseudoState.ts",
    "content": "/* eslint-env browser */\nimport {\n  DOCS_RENDERED,\n  FORCE_REMOUNT,\n  FORCE_RE_RENDER,\n  GLOBALS_UPDATED,\n  STORY_CHANGED,\n  STORY_RENDERED,\n  UPDATE_GLOBALS,\n} from 'storybook/internal/core-events';\nimport type { DecoratorFunction } from 'storybook/internal/types';\n\nimport { addons, useEffect, useMemo, useRef } from 'storybook/preview-api';\n\nimport { PSEUDO_STATES } from '../constants.ts';\nimport type { PseudoParameter, PseudoState, PseudoStateConfig } from '../types.ts';\nimport { rewriteStyleSheet } from './rewriteStyleSheet.ts';\n\nconst channel = addons.getChannel();\nconst shadowHosts = new Set<Element>();\n\n// Drops any existing pseudo state classnames that carried over from a previously viewed story\n// before adding the new classnames. We use forEach for IE compatibility.\nconst applyClasses = (element: Element, classnames: Set<string>) => {\n  Object.values(PSEUDO_STATES).forEach((state) => {\n    element.classList.remove(`pseudo-${state}`);\n    element.classList.remove(`pseudo-${state}-all`);\n  });\n  classnames.forEach((classname) => element.classList.add(classname));\n};\n\nfunction querySelectorPiercingShadowDOM(root: Element | ShadowRoot, selector: string) {\n  const results: Element[] = [];\n  root.querySelectorAll('*').forEach((el) => {\n    if (el.shadowRoot) {\n      results.push(...querySelectorPiercingShadowDOM(el.shadowRoot, selector));\n    }\n  });\n  results.push(...root.querySelectorAll(selector).values());\n  return results;\n}\n\nconst applyParameter = (rootElement: Element, parameter: PseudoStateConfig = {}) => {\n  const map = new Map([[rootElement, new Set<PseudoState>()]]);\n  const add = (target: Element, state: PseudoState) =>\n    map.set(target, new Set([...(map.get(target) || []), state]));\n\n  (Object.entries(parameter || {}) as [PseudoState, any]).forEach(([state, value]) => {\n    if (typeof value === 'boolean') {\n      // default API - applying pseudo class to root element.\n      if (value) {\n        add(rootElement, `${state}-all` as PseudoState);\n      }\n    } else if (typeof value === 'string') {\n      // explicit selectors API - applying pseudo class to a specific element\n      querySelectorPiercingShadowDOM(rootElement, value).forEach((el) => add(el, state));\n    } else if (Array.isArray(value)) {\n      // explicit selectors API - we have an array (of strings) recursively handle each one\n      value.forEach((sel) =>\n        querySelectorPiercingShadowDOM(rootElement, sel).forEach((el) => add(el, state))\n      );\n    }\n  });\n\n  map.forEach((states, target) => {\n    const classnames = new Set<string>();\n    states.forEach((key) => {\n      const keyWithoutAll = key.replace('-all', '') as PseudoState;\n      if (PSEUDO_STATES[key]) {\n        classnames.add(`pseudo-${PSEUDO_STATES[key]}`);\n      } else if (PSEUDO_STATES[keyWithoutAll]) {\n        classnames.add(`pseudo-${PSEUDO_STATES[keyWithoutAll]}-all`);\n      }\n    });\n    applyClasses(target, classnames);\n  });\n};\n\n// Traverses ancestry to collect relevant pseudo classnames, and applies them to the shadow host.\n// Shadow DOM can only access classes on its host. Traversing is needed to mimic the CSS cascade.\nconst updateShadowHost = (shadowHost: Element) => {\n  const classnames = new Set<string>();\n  // Keep any existing \"pseudo-*\" classes (but not \"pseudo-*-all\").\n  // \"pseudo-*-all\" classes may be stale and will be re-added as needed.\n  shadowHost.className\n    .split(' ')\n    .filter((classname) => classname.match(/^pseudo-(.(?!-all))+$/))\n    .forEach((classname) => classnames.add(classname));\n  // Adopt \"pseudo-*-all\" classes from ancestors (across shadow boundaries)\n  for (let node = shadowHost.parentNode; node; ) {\n    if (node instanceof ShadowRoot) {\n      node = node.host;\n      continue;\n    }\n    if (node instanceof Element) {\n      const element = node;\n      if (element.className) {\n        element.className\n          .split(' ')\n          .filter((classname) => classname.match(/^pseudo-.+-all$/) !== null)\n          .forEach((classname) => classnames.add(classname));\n      }\n    }\n    node = node.parentNode;\n  }\n  applyClasses(shadowHost, classnames);\n};\n\n// Drops the rootSelector from the parameter object, as it is not a pseudo state.\nconst pseudoConfig = (parameter: PseudoParameter) => {\n  const { rootSelector, ...pseudoStateConfig } = parameter || {};\n  return pseudoStateConfig;\n};\n\n// Compares two pseudo state configs to see if they are equal.\n// Uses JSON.stringify to handle arrays, so the order of selectors in the array matters.\nconst equals = (a: PseudoStateConfig = {}, b: PseudoStateConfig = {}) =>\n  a !== null &&\n  b !== null &&\n  Object.keys(a).length === Object.keys(b).length &&\n  (Object.keys(a) as PseudoState[]).every(\n    (key) => JSON.stringify(a[key]) === JSON.stringify(b[key])\n  );\n\n// Global decorator that rewrites stylesheets and applies classnames to render pseudo styles\nexport const withPseudoState: DecoratorFunction = (\n  StoryFn,\n  { viewMode, parameters, id, globals: globalsArgs }\n) => {\n  const { pseudo: parameter } = parameters;\n  const { pseudo: globals } = globalsArgs;\n  const { rootSelector } = parameter || {};\n\n  const rootElement = useMemo(() => {\n    if (rootSelector) {\n      return document.querySelector(rootSelector);\n    }\n    if (viewMode === 'docs') {\n      return document.getElementById(`story--${id}`);\n    }\n    return (\n      document.getElementById('storybook-root') || // Storybook 7.0+\n      document.getElementById('root')\n    );\n  }, [rootSelector, viewMode, id]);\n\n  // Use a ref to avoid a dependency on globals in the useEffect\n  const globalsRef = useRef(globals);\n\n  // Sync parameter to globals, used by the toolbar (only in canvas as this\n  // doesn't make sense for docs because many stories are displayed at once)\n  useEffect(() => {\n    const config = pseudoConfig(parameter);\n    if (viewMode === 'story' && !equals(config, globalsRef.current)) {\n      channel.emit(UPDATE_GLOBALS, {\n        globals: { pseudo: config },\n      });\n    }\n  }, [parameter, viewMode]);\n\n  // Convert selected states to classnames and apply them to the story root element.\n  // Then update each shadow host to redetermine its own pseudo classnames.\n  useEffect(() => {\n    if (!rootElement) {\n      return;\n    }\n    const timeout = setTimeout(() => {\n      applyParameter(rootElement, globals || pseudoConfig(parameter));\n      shadowHosts.forEach(updateShadowHost);\n    }, 0);\n    return () => clearTimeout(timeout);\n  }, [rootElement, globals, parameter]);\n\n  return StoryFn();\n};\n\n// Rewrite CSS rules for pseudo-states on all stylesheets to add an alternative selector\nconst rewriteStyleSheets = (shadowRoot?: ShadowRoot) => {\n  let styleSheets = Array.from(shadowRoot ? shadowRoot.styleSheets : document.styleSheets);\n\n  if (shadowRoot?.adoptedStyleSheets?.length) {\n    styleSheets = shadowRoot.adoptedStyleSheets;\n  }\n  styleSheets.forEach((sheet) => rewriteStyleSheet(sheet, !!shadowRoot));\n\n  if (shadowRoot && shadowHosts) {\n    shadowHosts.add(shadowRoot.host);\n  }\n};\n\n// Only track shadow hosts for the current story\nchannel.on(STORY_CHANGED, () => shadowHosts.clear());\n\n// Reinitialize CSS enhancements every time the story changes\nchannel.on(STORY_RENDERED, () => rewriteStyleSheets());\nchannel.on(GLOBALS_UPDATED, () => rewriteStyleSheets());\nchannel.on(FORCE_RE_RENDER, () => rewriteStyleSheets());\nchannel.on(FORCE_REMOUNT, () => rewriteStyleSheets());\n\n// Reinitialize CSS enhancements every time a docs page is rendered\nchannel.on(DOCS_RENDERED, () => rewriteStyleSheets());\n\n// IE doesn't support shadow DOM\nif (Element.prototype.attachShadow) {\n  // Monkeypatch the attachShadow method so we can handle pseudo styles inside shadow DOM\n  // @ts-expect-error (Monkeypatch)\n  Element.prototype._attachShadow = Element.prototype.attachShadow;\n  Element.prototype.attachShadow = function attachShadow(init) {\n    // Force \"open\" mode, so we can access the shadowRoot\n    // @ts-expect-error (Monkeypatch)\n    const shadowRoot = this._attachShadow({ ...init, mode: 'open' });\n    // Wait for it to render and apply its styles before rewriting them\n    requestAnimationFrame(() => {\n      rewriteStyleSheets(shadowRoot);\n\n      if (shadowHosts.has(shadowRoot.host)) {\n        updateShadowHost(shadowRoot.host);\n      }\n    });\n    return shadowRoot;\n  };\n}\n"
  },
  {
    "path": "code/addons/pseudo-states/src/preview.ts",
    "content": "import { PARAM_KEY } from './constants.ts';\nimport { withPseudoState } from './preview/withPseudoState.ts';\n\nexport const decorators = [withPseudoState];\n\nexport const initialGlobals = {\n  [PARAM_KEY]: false,\n};\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/Button.stories.tsx",
    "content": "import React, { type ComponentProps } from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\nimport { styled } from 'storybook/theming';\n\nimport { Button } from './Button.tsx';\nimport './grid.css';\nimport { PseudoStateGrid } from './PseudoStateGrid.tsx';\n\nconst meta = {\n  title: 'Button',\n  component: Button,\n  render: (args, context) => <Button {...args}>{context.name}</Button>,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const All: Story = {\n  render: (args: ComponentProps<typeof Button>) => (\n    <PseudoStateGrid render={(label) => <Button {...args}>{label}</Button>} />\n  ),\n};\n\nexport const Default: Story = {};\n\nexport const Hover: Story = {\n  parameters: {\n    pseudo: { hover: true },\n  },\n};\n\nconst StyledButton = styled(Button)`\n  &:hover {\n    @media (hover: hover) {\n      background-color: limegreen !important;\n    }\n  }\n`;\n\nexport const HoverMediaQuery: Story = {\n  parameters: {\n    pseudo: { hover: true },\n  },\n  render: (args) => {\n    return <StyledButton {...args}>Hover (hover: hover)</StyledButton>;\n  },\n};\n\nexport const Focus: Story = {\n  parameters: {\n    pseudo: { focus: true },\n  },\n};\n\nexport const Active: Story = {\n  parameters: {\n    pseudo: { active: true },\n  },\n};\n\nexport const DirectSelector: Story = {\n  render: () => (\n    <>\n      <div className=\"story-grid\">\n        <Button>Normal</Button>\n        <Button data-hover>Hover</Button>\n        <Button data-focus>Focus</Button>\n        <Button data-active>Active</Button>\n        <Button data-hover data-focus>\n          Hover Focus\n        </Button>\n        <Button data-hover data-active>\n          Hover Active\n        </Button>\n        <Button data-focus data-active>\n          Focus Active\n        </Button>\n        <Button data-hover data-focus data-active>\n          Hover Focus Active\n        </Button>\n      </div>\n      <h3>Multiple hovered button grouped</h3>\n      <div data-hover-group>\n        <Button>Hovered 1</Button>\n        <Button>Hovered 2</Button>\n        <Button>Hovered 3</Button>\n      </div>\n    </>\n  ),\n  parameters: {\n    pseudo: {\n      hover: ['[data-hover]', '[data-hover-group] button'],\n      focus: '[data-focus]',\n      active: ['[data-active]'],\n    },\n  },\n};\n\nexport const DirectSelectorParentDoesNotAffectDescendants: Story = {\n  render: () => (\n    <>\n      <Button id=\"foo\">Hovered 1</Button>\n\n      <div id=\"foo\">\n        <Button>Not Hovered 1 </Button>\n        <Button>Not Hovered 2</Button>\n      </div>\n    </>\n  ),\n  parameters: {\n    pseudo: {\n      hover: ['#foo'],\n    },\n  },\n};\n\nexport const DynamicStyles: Story = {\n  render: (args, context) => {\n    return All.render!({ className: 'dynamic' }, context);\n  },\n  play: async ({ id: storyId }) => {\n    return new Promise((resolve) => {\n      setTimeout(() => {\n        // @ts-expect-error We're adding this nonstandard property\n        if (globalThis[`__dynamicRuleInjected_${storyId}`]) {\n          return;\n        }\n        // @ts-expect-error We're adding this nonstandard property\n        globalThis[`__dynamicRuleInjected_${storyId}`] = true;\n        const sheet = Array.from(document.styleSheets).at(-1);\n        sheet?.insertRule('.dynamic.button:hover { background-color: tomato }');\n        resolve();\n      }, 100);\n    });\n  },\n};\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/Button.tsx",
    "content": "import React from 'react';\n\nimport './button.css';\n\nexport const Button = ({ className, ...props }: React.ButtonHTMLAttributes<HTMLButtonElement>) => (\n  <button {...props} className={['button', className].filter(Boolean).join(' ')} />\n);\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/CSSAtRules.stories.tsx",
    "content": "import React, { type ComponentProps } from 'react';\n\nimport { FORCE_REMOUNT } from 'storybook/internal/core-events';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { useChannel, useStoryContext } from 'storybook/preview-api';\n\nimport { Button } from './CSSAtRules.tsx';\nimport './grid.css';\nimport { PseudoStateGrid } from './PseudoStateGrid.tsx';\n\nconst meta = {\n  title: 'CSSAtRules',\n  component: Button,\n  render: (args, context) => <Button {...args}>{context.name}</Button>,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const All: Story = {\n  render: (args: ComponentProps<typeof Button>) => (\n    <PseudoStateGrid render={(label) => <Button {...args}>{label}</Button>} />\n  ),\n};\n\nexport const Default: Story = {};\n\nexport const Hover: Story = {\n  parameters: {\n    pseudo: { hover: true },\n  },\n};\n\nexport const Focus: Story = {\n  parameters: {\n    pseudo: { focus: true },\n  },\n};\n\nexport const Active: Story = {\n  parameters: {\n    pseudo: { active: true },\n  },\n};\n\nexport const DynamicStyles: Story = {\n  render: (args, context) => {\n    return All.render!({ className: 'dynamic' }, context);\n  },\n  play: async ({ id: storyId }) => {\n    return new Promise((resolve) => {\n      setTimeout(() => {\n        // @ts-expect-error We're adding this nonstandard property below\n        if (globalThis[`__dynamicRuleInjected_${storyId}`]) {\n          return;\n        }\n        // @ts-expect-error We're adding this nonstandard property\n        globalThis[`__dynamicRuleInjected_${storyId}`] = true;\n        const sheet = Array.from(document.styleSheets).at(-1);\n        sheet?.insertRule(\n          '@layer foo { .dynamic.button:hover { background-color: tomato!important } }'\n        );\n        resolve();\n      }, 100);\n    });\n  },\n};\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/CSSAtRules.tsx",
    "content": "import React from 'react';\n\nimport './cssatrules.css';\n\nexport const Button = ({ className, ...props }: React.ButtonHTMLAttributes<HTMLButtonElement>) => (\n  <button {...props} className={['button', className].filter(Boolean).join(' ')} />\n);\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/CustomElement.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport './CustomElement.tsx';\nimport './grid.css';\nimport { PseudoStateGrid } from './PseudoStateGrid.tsx';\n\nconst meta = {\n  title: 'CustomElement',\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n  // @ts-expect-error We're dealing with a web component here\n  render: (args, context) => <custom-element>{context.name}</custom-element>,\n} satisfies Meta;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const All: Story = {\n  render: () => (\n    <PseudoStateGrid\n      render={(label) => (\n        // @ts-expect-error We're dealing with a web component here\n        <custom-element>{label}</custom-element>\n      )}\n    />\n  ),\n};\n\nexport const Default: Story = {};\n\nexport const Hover: Story = {\n  parameters: {\n    pseudo: { hover: true },\n  },\n};\n\nexport const Focus: Story = {\n  parameters: {\n    pseudo: { focus: true },\n  },\n};\n\nexport const Active: Story = {\n  parameters: {\n    pseudo: { active: true },\n  },\n};\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/CustomElement.tsx",
    "content": "const css = `\n:host {\n  font-family: \"Nunito Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-weight: 700;\n  border: 0;\n  border-radius: 3em;\n  cursor: pointer;\n  display: inline-block;\n  line-height: 1;\n  color: white;\n  background-color: tomato;\n  font-size: 14px;\n  padding: 11px 20px;\n}\n:host(:hover) {\n  text-decoration: underline;\n}\n:host(:focus) {\n  box-shadow: inset 0 0 0 2px maroon;\n  outline: 0;\n}\n:host(:active) {\n  background-color: firebrick;\n}\n`;\n\nexport class CustomElement extends HTMLElement {\n  constructor() {\n    super();\n\n    const shadow = this.attachShadow({ mode: 'open' });\n\n    if (shadow.adoptedStyleSheets !== undefined) {\n      const sheet = new CSSStyleSheet();\n      sheet.replaceSync(css);\n      shadow.adoptedStyleSheets = [sheet];\n    } else {\n      const style = document.createElement('style');\n      style.textContent = css;\n      shadow.append(style);\n    }\n\n    shadow.append(document.createElement('slot'));\n  }\n}\n\nwindow.customElements.define('custom-element', CustomElement);\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/CustomElementNested.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport './CustomElementNested.tsx';\nimport './grid.css';\nimport { PseudoStateGrid } from './PseudoStateGrid.tsx';\n\nconst meta = {\n  title: 'CustomElementNested',\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n  // @ts-expect-error We're dealing with a web component here\n  render: (args, context) => <custom-element-nested>{context.name}</custom-element-nested>,\n} satisfies Meta;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const All: Story = {\n  render: () => (\n    <PseudoStateGrid\n      render={(label) => (\n        // @ts-expect-error We're dealing with a web component here\n        <custom-element-nested>{label}</custom-element-nested>\n      )}\n    />\n  ),\n};\n\nexport const Default: Story = {};\n\nexport const Hover: Story = {\n  parameters: {\n    pseudo: { hover: true },\n  },\n};\n\nexport const Focus: Story = {\n  parameters: {\n    pseudo: { focus: true },\n  },\n};\n\nexport const Active: Story = {\n  parameters: {\n    pseudo: { active: true },\n  },\n};\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/CustomElementNested.tsx",
    "content": "import './CustomElement.tsx';\n\nexport class CustomElementNested extends HTMLElement {\n  constructor() {\n    super();\n\n    const shadow = this.attachShadow({ mode: 'open' });\n\n    const element = document.createElement('custom-element');\n    element.append(document.createElement('slot'));\n    shadow.append(element);\n  }\n}\n\nwindow.customElements.define('custom-element-nested', CustomElementNested);\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/Input.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Input } from './Input.tsx';\nimport './grid.css';\n\nconst meta = {\n  title: 'Input',\n  component: Input,\n  render: (args, context) => <Input defaultValue={context.name} {...args} />,\n} satisfies Meta<typeof Input>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const All: Story = {\n  render: () => (\n    <div className=\"story-grid pseudo\">\n      <div>\n        <Input defaultValue=\"Normal\" />\n      </div>\n      <div className=\"pseudo-hover-all\">\n        <Input defaultValue=\"Hover\" />\n      </div>\n      <div className=\"pseudo-focus-all\">\n        <Input defaultValue=\"Focus\" />\n      </div>\n      <div className=\"pseudo-hover-all pseudo-focus-all\">\n        <Input defaultValue=\"Hover Focus\" />\n      </div>\n    </div>\n  ),\n};\n\nexport const Default: Story = {};\n\nexport const Hover: Story = {\n  parameters: { pseudo: { hover: true } },\n};\n\nexport const Focus: Story = {\n  parameters: { pseudo: { focus: true } },\n};\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/Input.tsx",
    "content": "import React from 'react';\n\nimport './input.css';\n\nexport const Input = (props: React.InputHTMLAttributes<HTMLInputElement>) => (\n  <input aria-label=\"Sample input\" {...props} className=\"input\" />\n);\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/NestedRules.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Button } from './NestedRules.tsx';\n\nconst meta = {\n  title: 'NestedRules',\n  component: Button,\n  render: (args, context) => <Button {...args}>{context.name}</Button>,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const NestedHover: Story = {\n  parameters: {\n    pseudo: { focusVisible: true },\n  },\n  // TODO: Use this test once the pseudostates addon uses the beforeEach API\n  // play: async ({ canvas }) => {\n  //   const button = canvas.getByRole('button')!;\n  //   await expect(getComputedStyle(button).textDecorationLine).toBe('underline');\n  //   await expect(getComputedStyle(button).textDecorationColor).toBe('rgb(255, 0, 0)');\n  // },\n};\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/NestedRules.tsx",
    "content": "import React from 'react';\n\nimport './nested.css';\n\nexport const Button = (props: React.ButtonHTMLAttributes<HTMLButtonElement>) => (\n  <button className=\"nested-focus-visible\" {...props} />\n);\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/Portal.stories.tsx",
    "content": "import React, { type ComponentProps } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Button } from './Button.tsx';\nimport './grid.css';\n\nconst PortalButton = (props: ComponentProps<typeof Button>) =>\n  createPortal(<Button {...props} />, document.body);\n\nconst meta = {\n  title: 'Portal',\n  component: PortalButton,\n  render: (args, context) => <PortalButton {...args}>{context.name}</PortalButton>,\n} satisfies Meta<typeof PortalButton>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {\n  parameters: {\n    pseudo: { rootSelector: 'body' },\n  },\n};\n\nexport const Hover: Story = {\n  parameters: {\n    pseudo: { hover: true, rootSelector: 'body' },\n  },\n};\n\nexport const Focus: Story = {\n  parameters: {\n    pseudo: { focus: true, rootSelector: 'body' },\n  },\n};\n\nexport const Active: Story = {\n  parameters: {\n    pseudo: { active: true, rootSelector: 'body' },\n  },\n};\n\nexport const FocusedHover: Story = {\n  parameters: {\n    pseudo: { focus: true, hover: true, rootSelector: 'body' },\n  },\n};\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/PseudoStateGrid.tsx",
    "content": "import React, { type ReactNode } from 'react';\n\ninterface PseudoStateGridProps {\n  render: (label: string) => ReactNode;\n}\n\nexport const PseudoStateGrid = ({ render }: PseudoStateGridProps) => (\n  <div className=\"story-grid\">\n    <div>{render('Normal')}</div>\n    <div className=\"pseudo-hover-all\">{render('Hover')}</div>\n    <div className=\"pseudo-focus-all\">{render('Focus')}</div>\n    <div className=\"pseudo-active-all\">{render('Active')}</div>\n    <div className=\"pseudo-hover-all pseudo-focus-all\">{render('Hover Focus')}</div>\n    <div className=\"pseudo-hover-all pseudo-active-all\">{render('Hover Active')}</div>\n    <div className=\"pseudo-focus-all pseudo-active-all\">{render('Focus Active')}</div>\n    <div className=\"pseudo-hover-all pseudo-focus-all pseudo-active-all\">\n      {render('Hover Focus Active')}\n    </div>\n  </div>\n);\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/ShadowRoot.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { ShadowRoot } from './ShadowRoot.tsx';\nimport './grid.css';\nimport { PseudoStateGrid } from './PseudoStateGrid.tsx';\n\nconst meta = {\n  title: 'ShadowRoot',\n  component: ShadowRoot,\n} satisfies Meta<typeof ShadowRoot>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const All: Story = {\n  render: () => <PseudoStateGrid render={(label) => <ShadowRoot label={label} />} />,\n};\n\nexport const Default: Story = {};\n\nexport const Hover: Story = {\n  parameters: {\n    pseudo: {\n      hover: true,\n    },\n  },\n};\n\nexport const Focus: Story = {\n  parameters: {\n    pseudo: {\n      focus: true,\n    },\n  },\n};\n\nexport const Active: Story = {\n  parameters: {\n    pseudo: {\n      active: true,\n    },\n  },\n};\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/ShadowRoot.tsx",
    "content": "import React from 'react';\n\nexport const ShadowRoot = ({ label = 'Hello from shadow DOM' }) => {\n  const ref = React.useRef<HTMLDivElement>(null);\n\n  React.useEffect(() => {\n    if (!ref.current?.attachShadow) {\n      return;\n    }\n\n    const shadowRoot = ref.current.attachShadow({ mode: 'open' });\n    shadowRoot.innerHTML = `\n      <style>\n        button {\n          font-family: \"Nunito Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n          font-weight: 700;\n          border: 0;\n          border-radius: 3em;\n          cursor: pointer;\n          display: inline-block;\n          line-height: 1;\n          color: white;\n          background-color: tomato;\n          font-size: 14px;\n          padding: 11px 20px;\n        }\n        button:hover {\n          text-decoration: underline;\n        }\n        button:focus {\n          box-shadow: inset 0 0 0 2px maroon;\n          outline: 0;\n        }\n        button:active {\n          background-color: firebrick;\n        }\n      </style>\n      <button>${label}</button>\n    `;\n  }, [label]);\n\n  return <div ref={ref} />;\n};\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/ShadowRootWithPart.css",
    "content": "::part(foo) {\n  display: inline-block;\n  cursor: pointer;\n  border: 0;\n  border-radius: 3em;\n  background-color: tomato;\n  padding: 11px 20px;\n  color: white;\n  font-weight: 700;\n  font-size: 14px;\n  line-height: 1;\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n::part(foo):hover {\n  text-decoration: underline;\n}\n::part(foo):focus {\n  outline: 0;\n  box-shadow: inset 0 0 0 2px maroon;\n}\n::part(foo):active {\n  background-color: firebrick;\n}\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/ShadowRootWithPart.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { ShadowRoot } from './ShadowRootWithPart.tsx';\nimport './grid.css';\nimport { PseudoStateGrid } from './PseudoStateGrid.tsx';\n\nconst meta = {\n  title: 'ShadowRootWithPart',\n  component: ShadowRoot,\n} satisfies Meta<typeof ShadowRoot>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const All: Story = {\n  render: () => <PseudoStateGrid render={(label) => <ShadowRoot label={label} />} />,\n};\n\nexport const Default: Story = {};\n\nexport const Hover: Story = {\n  parameters: {\n    pseudo: {\n      hover: true,\n    },\n  },\n};\n\nexport const Focus: Story = {\n  parameters: {\n    pseudo: {\n      focus: true,\n    },\n  },\n};\n\nexport const Active: Story = {\n  parameters: {\n    pseudo: {\n      active: true,\n    },\n  },\n};\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/ShadowRootWithPart.tsx",
    "content": "import React from 'react';\n\nimport './ShadowRootWithPart.css';\n\nexport const ShadowRoot = ({ label = 'Hello from shadow DOM' }) => {\n  const ref = React.useRef<HTMLDivElement>(null);\n\n  React.useEffect(() => {\n    if (!ref.current?.attachShadow) {\n      return;\n    }\n\n    const shadowRoot = ref.current.attachShadow({ mode: 'open' });\n    shadowRoot.innerHTML = `\n      <button part=\"foo\">${label}</button>\n    `;\n  }, [label]);\n\n  return <div ref={ref} />;\n};\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/button.css",
    "content": ".button {\n  display: inline-block;\n  cursor: pointer;\n  border: 0;\n  border-radius: 3em;\n  background-color: #1ea7fd;\n  padding: 11px 20px;\n  color: white;\n  font-weight: 700;\n  font-size: 14px;\n  line-height: 1;\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n\n.button:hover {\n  text-decoration: underline;\n}\n\n.button:focus {\n  outline: 0;\n  box-shadow: inset 0 0 0 2px #0006;\n}\n\n.button:active {\n  background-color: #077fc9;\n}\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/cssatrules.css",
    "content": "@layer base {\n  .button {\n    display: inline-block;\n    cursor: pointer;\n    border: 0;\n    border-radius: 3em;\n    background-color: #1ea7fd;\n    padding: 11px 20px;\n    color: white;\n    font-weight: 700;\n    font-size: 14px;\n    line-height: 1;\n    font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n  }\n\n  @supports (display: flex) {\n    @media hover {\n      .button:hover {\n        text-decoration: underline;\n      }\n    }\n\n    .button:focus {\n      outline: 0;\n      box-shadow: inset 0 0 0 2px #0006;\n    }\n\n    .button:active {\n      background-color: #077fc9;\n    }\n  }\n}\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/grid.css",
    "content": ".story-grid {\n  display: inline-grid;\n  grid-template-areas:\n    'normal normal normal'\n    'hover focus active'\n    'hover-focus hover-active focus-active'\n    'hover-focus-active hover-focus-active hover-focus-active';\n  gap: 1rem;\n}\n\n.story-grid > * {\n  grid-area: normal;\n  justify-self: center;\n}\n.story-grid > .pseudo-hover-all,\n.story-grid > [data-hover] {\n  grid-area: hover;\n  justify-self: right;\n}\n.story-grid > .pseudo-focus-all,\n.story-grid > [data-focus] {\n  grid-area: focus;\n  justify-self: center;\n}\n.story-grid > .pseudo-active-all,\n.story-grid > [data-active] {\n  grid-area: active;\n  justify-self: left;\n}\n.story-grid > .pseudo-hover-all.pseudo-focus-all,\n.story-grid > [data-hover][data-focus] {\n  grid-area: hover-focus;\n  justify-self: right;\n}\n.story-grid > .pseudo-hover-all.pseudo-active-all,\n.story-grid > [data-hover][data-active] {\n  grid-area: hover-active;\n  justify-self: center;\n}\n.story-grid > .pseudo-focus-all.pseudo-active-all,\n.story-grid > [data-focus][data-active] {\n  grid-area: focus-active;\n  justify-self: left;\n}\n.story-grid > .pseudo-hover-all.pseudo-focus-all.pseudo-active-all,\n.story-grid > [data-hover][data-focus][data-active] {\n  grid-area: hover-focus-active;\n  justify-self: center;\n}\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/input.css",
    "content": ".input {\n  display: inline-block;\n  border: 1px solid #ccc;\n  border-radius: 3em;\n  background-color: #fff;\n  padding: 11px 20px;\n  color: #666;\n  font-size: 14px;\n  line-height: 1;\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n\n.input:hover {\n  box-shadow: 0 0 5px #0005;\n}\n\n.input:focus {\n  outline: 0;\n  border-color: #666;\n  color: #333;\n}\n\n.input:hover:focus {\n  font-weight: bold;\n}\n"
  },
  {
    "path": "code/addons/pseudo-states/src/stories/nested.css",
    "content": "button {\n  display: inline-block;\n  cursor: pointer;\n  border: 0;\n  border-radius: 3em;\n  background-color: #1ea7fd;\n  padding: 11px 20px;\n  color: white;\n  font-weight: 700;\n  font-size: 14px;\n  line-height: 1;\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n\n.nested-focus-visible {\n  &:focus-visible {\n    @supports (color: color-mix(in lab, red, red)) {\n      text-decoration: underline red;\n    }\n  }\n}\n"
  },
  {
    "path": "code/addons/pseudo-states/src/types.test-d.ts",
    "content": "import { describe, expectTypeOf, it } from 'vitest';\n\nimport { definePreview } from 'storybook/internal/csf';\n\nimport pseudoAddon from './index.ts';\nimport '../../../renderers/react/src/typings.ts';\n\ndescribe('addon parameters are injected to csf factory', () => {\n  // Define preview with pseudo addon\n  const preview = definePreview({ addons: [pseudoAddon()] });\n\n  it('with invalid value', () => {\n    const meta = preview.meta({\n      parameters: {\n        pseudo: {\n          // @ts-expect-error focus should be bool/string\n          focus: 2,\n        },\n      },\n    });\n    expectTypeOf(meta.input.parameters!.pseudo).not.toExtend<{ focus: number }>();\n  });\n\n  it('with invalid key', () => {\n    const meta = preview.meta({\n      parameters: {\n        pseudo: {\n          // @ts-expect-error this pseudo state doesn't exist\n          madeUpKey: true,\n        },\n      },\n    });\n    expectTypeOf(meta.input.parameters!.pseudo).not.toExtend<{ madeUpKey: boolean }>();\n  });\n\n  it('with valid config', () => {\n    const meta = preview.meta({\n      parameters: {\n        pseudo: {\n          rootSelector: 'body',\n          focus: true,\n        },\n      },\n    });\n    expectTypeOf(meta.input.parameters!.pseudo!).toExtend<{ focus: boolean }>();\n  });\n});\n"
  },
  {
    "path": "code/addons/pseudo-states/src/types.ts",
    "content": "import type { PSEUDO_STATES } from './constants.ts';\n\nexport type PseudoState = keyof typeof PSEUDO_STATES;\n\nexport type PseudoStateConfig = {\n  [P in PseudoState]?: boolean | string | string[];\n};\n\nexport interface PseudoParameter extends PseudoStateConfig {\n  rootSelector?: string;\n}\n\nexport interface PseudoParameters {\n  /**\n   * Pseudo state configuration\n   *\n   * @see https://storybook.js.org/addons/storybook-addon-pseudo-states\n   */\n  pseudo?: PseudoParameter;\n}\n\nexport interface PseudoTypes {\n  parameters: PseudoParameters;\n}\n"
  },
  {
    "path": "code/addons/pseudo-states/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/addons/pseudo-states/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    test: {\n      typecheck: {\n        enabled: true,\n      },\n    },\n  })\n);\n"
  },
  {
    "path": "code/addons/themes/README.md",
    "content": "# @storybook/addon-themes\n\nStorybook Addon Themes can be used to switch between multiple themes for components inside the preview in [Storybook](https://storybook.js.org?ref=readme).\n\n![React Storybook Screenshot](https://user-images.githubusercontent.com/18172605/274302488-77a39112-cdbe-4d16-9966-0d8e9e7e3399.gif)\n\n## Usage\n\nRequires Storybook 7.0 or later. If you need to add it to your Storybook, you can run:\n\n```sh\nnpm i -D @storybook/addon-themes\n```\n\nThen, add following content to [`.storybook/main.js`](https://storybook.js.org/docs/configure#configure-your-storybook-project?ref=readme):\n\n```js\nexport default {\n  addons: ['@storybook/addon-themes'],\n};\n```\n\n### 👇 Tool specific configuration\n\nFor tool-specific setup, check out the recipes below\n\n- [`@emotion/styled`](https://github.com/storybookjs/storybook/tree/next/code/addons/themes/docs/getting-started/emotion.md)\n- [`@mui/material`](https://github.com/storybookjs/storybook/tree/next/code/addons/themes/docs/getting-started/material-ui.md)\n- [`bootstrap`](https://github.com/storybookjs/storybook/tree/next/code/addons/themes/docs/getting-started/bootstrap.md)\n- [`postcss`](https://github.com/storybookjs/storybook/tree/next/code/addons/themes/docs/getting-started/postcss.md)\n- [`styled-components`](https://github.com/storybookjs/storybook/tree/next/code/addons/themes/docs/getting-started/styled-components.md)\n- [`tailwind`](https://github.com/storybookjs/storybook/tree/next/code/addons/themes/docs/getting-started/tailwind.md)\n- [`vuetify@3.x`](https://github.com/storybookjs/storybook/blob/next/code/addons/themes/docs/api.md#writing-a-custom-decorator)\n\nDon't see your favorite tool listed? Don't worry! That doesn't mean this addon isn't for you. Check out the [\"Writing a custom decorator\"](https://github.com/storybookjs/storybook/blob/next/code/addons/themes/docs/api.md#writing-a-custom-decorator) section of the [api reference](https://github.com/storybookjs/storybook/blob/next/code/addons/themes/docs/api.md).\n\n### ❗️ Overriding theme\n\nIf you want to override your theme for a particular component or story, you can use the `globals.theme` parameter.\n\n```js\nimport React from 'react';\nimport { Button } from './Button';\n\nexport default {\n  title: 'Example/Button',\n  component: Button,\n  // meta level override\n  globals: { theme: 'dark' },\n};\n\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const PrimaryDark = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n  // story level override\n  globals: { theme: 'dark' },\n};\n```\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/addons/themes/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./manager'],\n        entryPoint: './src/manager.tsx',\n        dts: false,\n      },\n      {\n        exportEntries: ['./preview'],\n        entryPoint: './src/preview.ts',\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./postinstall'],\n        entryPoint: './src/postinstall.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/addons/themes/docs/api.md",
    "content": "# API\n\n## Decorators\n\n### `withThemeFromJSXProvider`\n\nTakes your provider component, global styles, and theme(s)to wrap your stories in.\n\n```js\nimport { withThemeFromJSXProvider } from '@storybook/addon-themes';\n\nexport const decorators = [\n  withThemeFromJSXProvider({\n    themes: {\n      light: lightTheme,\n      dark: darkTheme,\n    },\n    defaultTheme: 'light',\n    Provider: ThemeProvider,\n    GlobalStyles: CssBaseline,\n  }),\n];\n```\n\nAvailable options:\n\n| option       | type                  | required? | Description                                                                                                                                                                                         |\n| ------------ | --------------------- | :-------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| themes       | `Record<string, any>` |           | An object of theme configurations where the key is the name of the theme and the value is the theme object. If multiple themes are provided, a toolbar item will be added to switch between themes. |\n| defaultTheme | `string`              |           | The name of the default theme to use                                                                                                                                                                |\n| Provider     |                       |           | The JSX component to provide themes                                                                                                                                                                 |\n| GlobalStyles |                       |           | A JSX component containing global css styles.                                                                                                                                                       |\n\n### `withThemeByClassName`\n\nTakes your theme class names to apply your parent element to enable your theme(s).\n\n```js\nimport { withThemeByClassName } from '@storybook/addon-themes';\n\nexport const decorators = [\n  withThemeByClassName({\n    themes: {\n      light: 'light-theme',\n      dark: 'dark-theme',\n    },\n    defaultTheme: 'light',\n  }),\n];\n```\n\nAvailable options:\n\n| option         | type                     | required? | Description                                                                                                     |\n| -------------- | ------------------------ | :-------: | --------------------------------------------------------------------------------------------------------------- |\n| themes         | `Record<string, string>` |    ✅     | An object of theme configurations where the key is the name of the theme and the value is the theme class name. |\n| defaultTheme   | `string`                 |    ✅     | The name of the default theme to use                                                                            |\n| parentSelector | `string`                 |           | The selector for the parent element that you want to apply your theme class to. Defaults to \"html\"              |\n\n### `withThemeByDataAttribute`\n\nTakes your theme names and data attribute to apply your parent element to enable your theme(s).\n\n```js\nimport { withThemeByDataAttribute } from '@storybook/addon-themes';\n\nexport const decorators = [\n  withThemeByDataAttribute({\n    themes: {\n      light: 'light',\n      dark: 'dark',\n    },\n    defaultTheme: 'light',\n    attributeName: 'data-bs-theme',\n  }),\n];\n```\n\navailable options:\n\n| option         | type                     | required? | Description                                                                                                         |\n| -------------- | ------------------------ | :-------: | ------------------------------------------------------------------------------------------------------------------- |\n| themes         | `Record<string, string>` |    ✅     | An object of theme configurations where the key is the name of the theme and the value is the data attribute value. |\n| defaultTheme   | `string`                 |    ✅     | The name of the default theme to use                                                                                |\n| parentSelector | `string`                 |           | The selector for the parent element that you want to apply your theme class to. Defaults to \"html\"                  |\n| attributeName  | `string`                 |           | The name of the data attribute to set on the parent element for your theme(s). Defaults to \"data-theme\"             |\n\n## Writing a custom decorator\n\nIf none of these decorators work for your library there is still hope. We've provided a collection of helper functions to get access to the theme toggling state so that you can create a decorator of your own.\n\n### `pluckThemeFromContext`\n\nPulls the selected theme from storybook's global state.\n\n```js\nimport { DecoratorHelpers } from '@storybook/addon-themes';\n\nconst { pluckThemeFromContext } = DecoratorHelpers;\n\nexport const myCustomDecorator =\n  ({ themes, defaultState, ...rest }) =>\n  (storyFn, context) => {\n    const selectedTheme = pluckThemeFromContext(context);\n\n    // Snipped\n  };\n```\n\n### `useThemeParameters`\n\n(⛔️ **Deprecated**)\n_Do not use this hook anymore. Access the theme directly via the context instead e.g. `context.parameters.themes`_\n\nReturns the theme parameters for this addon.\n\n```js\nimport { DecoratorHelpers } from '@storybook/addon-themes';\n\nconst { useThemeParameters } = DecoratorHelpers;\n\nexport const myCustomDecorator =\n  ({ themes, defaultState, ...rest }) =>\n  (storyFn, context) => {\n    const { themeOverride } = useThemeParameters();\n\n    // Snipped\n  };\n```\n\n### `initializeThemeState`\n\nUsed to register the themes and defaultTheme with the addon state.\n\n```js\nimport { DecoratorHelpers } from '@storybook/addon-themes';\n\nconst { initializeThemeState } = DecoratorHelpers;\n\nexport const myCustomDecorator = ({ themes, defaultState, ...rest }) => {\n  initializeThemeState(Object.keys(themes), defaultTheme);\n\n  return (storyFn, context) => {\n    // Snipped\n  };\n};\n```\n\n### Putting it all together\n\nLet's use Vuetify as an example. Vuetify uses it's own global state to know which theme to render. To build a custom decorator to accommodate this method we'll need to do the following\n\n```js\n// .storybook/withVuetifyTheme.decorator.js\nimport { DecoratorHelpers } from '@storybook/addon-themes';\nimport { useTheme } from 'vuetify';\n\nconst { initializeThemeState, pluckThemeFromContext } = DecoratorHelpers;\n\nexport const withVuetifyTheme = ({ themes, defaultTheme }) => {\n  initializeThemeState(Object.keys(themes), defaultTheme);\n\n  return (story, context) => {\n    const selectedTheme = pluckThemeFromContext(context);\n    const { themeOverride } = context.parameters.themes ?? {};\n\n    const selected = themeOverride || selectedTheme || defaultTheme;\n\n    return {\n      components: { story },\n      setup() {\n        const theme = useTheme();\n\n        theme.global.name.value = themes[selected];\n\n        return {\n          theme,\n        };\n      },\n      template: `<v-app><story /></v-app>`,\n    };\n  };\n};\n```\n\nThis can then be provided to Storybook in `.storybook/preview.js`:\n\n```js\n// .storybook/preview.js\nimport { setup } from '@storybook/vue3';\nimport { registerPlugins } from '../src/plugins';\nimport { withVuetifyTheme } from './withVuetifyTheme.decorator';\n\nsetup((app) => {\n  registerPlugins(app);\n});\n\n/* snipped for brevity */\n\nexport const decorators = [\n  withVuetifyTheme({\n    // These keys are the labels that will be displayed in the toolbar theme switcher\n    // The values must match the theme keys from your VuetifyOptions\n    themes: {\n      light: 'light',\n      dark: 'dark',\n      'high contrast': 'highContrast',\n    },\n    defaultTheme: 'light', // The key of your default theme\n  }),\n];\n```\n"
  },
  {
    "path": "code/addons/themes/docs/getting-started/bootstrap.md",
    "content": "# 🏁 Getting started with `bootstrap`\n\n## 📦 Install addon\n\nTo get started, **install the package** as a dev dependency.\n\nyarn:\n\n```zsh\nyarn add -D @storybook/addon-themes\n```\n\nnpm:\n\n```zsh\nnpm install -D @storybook/addon-themes\n```\n\npnpm:\n\n```zsh\npnpm add -D @storybook/addon-themes\n```\n\n## 🧩 Register Addon\n\nNow, **include the addon** in your `.storybook/main.js` file.\n\n```diff\nexport default {\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],\n  addons: [\n    '@storybook/addon-essentials',\n+   '@storybook/addon-themes',\n  ],\n};\n```\n\n## 🥾 Import Bootstrap\n\nTo give your stories access to Bootstrap's styles and JavaScript, import them into your `.storybook/preview.js` file.\n\n```diff\nimport { Preview } from '@storybook/your-renderer';\n\n+import 'bootstrap/dist/css/bootstrap.min.css';\n+import 'bootstrap/dist/js/bootstrap.bundle';\n\nconst preview: Preview = {\n  parameters: { /* ... */ },\n};\n\nexport default preview;\n```\n\n## 🎨 Provide your theme(s)\n\nBootstrap now supports light and dark color modes out of the box as well as the ability to make your own custom modes. These modes can be activated by setting a `data-bs-theme` attribute on a parent element.\n\nTo enable switching between these modes in a click for your stories, use our `withThemeByDataAttribute` decorator by adding the following code to your `.storybook/preview.js` file.\n\n```diff\n-import { Preview } from '@storybook/your-renderer';\n+import { Preview, Renderer } from '@storybook/your-renderer';\n+import { withThemeByDataAttribute } from '@storybook/addon-themes';\n\nimport 'bootstrap/dist/css/bootstrap.min.css';\nimport 'bootstrap/dist/js/bootstrap.bundle';\n\nconst preview: Preview = {\n  parameters: { /* ... */ },\n+ decorators: [\n+  withThemeByDataAttribute<Renderer>({\n+    themes: {\n+      light: 'light',\n+      dark: 'dark',\n+    },\n+    defaultTheme: 'light',\n+    attributeName: 'data-bs-theme',\n+  }),\n+ ]\n};\n\nexport default preview;\n```\n"
  },
  {
    "path": "code/addons/themes/docs/getting-started/emotion.md",
    "content": "# 🏁 Getting started with `@emotion/styled`\n\n## 📦 Install addon\n\nTo get started, **install the package** as a dev dependency.\n\nyarn:\n\n```zsh\nyarn add -D @storybook/addon-themes\n```\n\nnpm:\n\n```zsh\nnpm install -D @storybook/addon-themes\n```\n\npnpm:\n\n```zsh\npnpm add -D @storybook/addon-themes\n```\n\n## 🧩 Register Addon\n\nNow, **include the addon** in your `.storybook/main.js` file.\n\n```diff\nexport default {\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    '@storybook/addon-essentials',\n+   '@storybook/addon-themes',\n  ],\n};\n```\n\n## 🎨 Provide your theme(s)\n\nFinally, provide your theme(s) and global styles component to your stories with our `withThemeFromJSXProvider` decorator.\n\nMake the following changes to your `.storybook/preview.js`:\n\n```diff\n-import { Preview } from '@storybook/your-renderer';\n+import { Preview, Renderer } from '@storybook/your-renderer';\n+import { withThemeFromJSXProvider } from '@storybook/addon-themes';\n+import { ThemeProvider } from '@emotion/react';\n+import { GlobalStyles, lightTheme, darkTheme } from '../src/themes'; // Import your custom theme configs\n\n\nconst preview: Preview = {\n  parameters: { /* ... */ },\n+ decorators: [\n+  withThemeFromJSXProvider<Renderer>({\n+    themes: {\n+      light: lightTheme,\n+      dark: darkTheme,\n+    },\n+    defaultTheme: 'light',\n+    Provider: ThemeProvider,\n+    GlobalStyles: GlobalStyles,\n+  }),\n+ ]\n};\n\nexport default preview;\n```\n"
  },
  {
    "path": "code/addons/themes/docs/getting-started/material-ui.md",
    "content": "# 🏁 Getting started with `@mui/material`\n\n## 📦 Install addon\n\nTo get started, **install the package** as a dev dependency.\n\nyarn:\n\n```zsh\nyarn add -D @storybook/addon-themes\n```\n\nnpm:\n\n```zsh\nnpm install -D @storybook/addon-themes\n```\n\npnpm:\n\n```zsh\npnpm add -D @storybook/addon-themes\n```\n\n## 🧩 Register Addon\n\nNow, **include the addon** in your `.storybook/main.js` file.\n\n```diff\nexport default {\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    '@storybook/addon-essentials',\n+   '@storybook/addon-themes',\n  ],\n};\n```\n\n## 🔤 Import fonts\n\n`@mui/material` requires Google's Roboto and Material Icon fonts to render everything as intended. I'd recommend getting them from [fontsource](https://github.com/fontsource/fontsource) so that they are version locked dependencies that doesn't require a CDN.\n\nThese can be imported into your `.storybook/preview.js` file.\n\n```diff\nimport { Preview } from '@storybook/your-renderer';\n\n+// Load Material UI fonts\n+import '@fontsource/roboto/300.css';\n+import '@fontsource/roboto/400.css';\n+import '@fontsource/roboto/500.css';\n+import '@fontsource/roboto/700.css';\n+import '@fontsource/material-icons';\n\nconst preview: Preview = {\n  parameters: { /* ... */ },\n};\n\nexport default preview;\n```\n\n## 🎨 Provide your theme(s)\n\nWhile Material UI comes with a default theme that works out of the box. You can create your own theme(s) and provide them to your stories with our `withThemeFromJSXProvider` decorator.\n\nMake the following changes to your `.storybook/preview.js`:\n\n```diff\n-import { Preview } from '@storybook/your-renderer';\n+import { Preview, Renderer } from '@storybook/your-renderer';\n+import { withThemeFromJSXProvider } from '@storybook/addon-themes';\n+import { CssBaseline, ThemeProvider } from '@mui/material';\n+import { lightTheme, darkTheme } from '../src/themes'; // Import your custom theme configs\n\n// Load Roboto fonts\nimport '@fontsource/roboto/300.css';\nimport '@fontsource/roboto/400.css';\nimport '@fontsource/roboto/500.css';\nimport '@fontsource/roboto/700.css';\nimport '@fontsource/material-icons';\n\nconst preview: Preview = {\n  parameters: { /* ... */ },\n+ decorators: [\n+   withThemeFromJSXProvider<Renderer>({\n+     themes: {\n+       light: lightTheme,\n+       dark: darkTheme,\n+     },\n+     defaultTheme: 'light',\n+     Provider: ThemeProvider,\n+     GlobalStyles: CssBaseline,\n+   }),\n+ ],\n};\n\nexport default preview;\n```\n"
  },
  {
    "path": "code/addons/themes/docs/getting-started/postcss.md",
    "content": "# 🏁 Getting started with `postcss`\n\n## 📦 Install addon\n\nTo get started, **install the package** as a dev dependency\n\nyarn:\n\n```zsh\nyarn add -D @storybook/addon-themes postcss-dark-theme-class\n```\n\nnpm:\n\n```zsh\nnpm install -D @storybook/addon-themes postcss-dark-theme-class\n```\n\npnpm:\n\n```zsh\npnpm add -D @storybook/addon-themes postcss-dark-theme-class\n```\n\n## 🧩 Register Addon\n\nNow, **include the addon** in your `.storybook/main.js` file.\n\n```diff\nmodule.exports = {\n  stories: [\n    \"../stories/**/*.stories.mdx\",\n    \"../stories/**/*.stories.@(js|jsx|ts|tsx)\",\n  ],\n  addons: [\n    \"@storybook/addon-essentials\",\n+   \"@storybook/addon-themes\"\n  ],\n};\n```\n\n## 🏷️ Add class to `prefers-color-scheme` media\n\nCSS has special media at-rule for dark theme: `@media (prefers-color-scheme: dark)`. [`postcss-dark-theme-class`](https://github.com/postcss/postcss-dark-theme-class) can copy content of those at-rules to `.is-dark` selector.\n\nCheck your project for existing PostCSS config: `postcss.config.js` in the project root, `\"postcss\"` section in `package.json` or postcss in bundle config.\n\nAdd plugin to the list.\n\n```diff\nmodule.exports = {\n  plugins: [\n+   require('postcss-dark-theme-class'),\n    require('autoprefixer')\n  ]\n}\n```\n\nUse `prefers-color-scheme` media in your CSS:\n\n```css\n:root {\n  --text-color: black;\n}\n@media (prefers-color-scheme: dark) {\n  html {\n    --text-color: white;\n  }\n}\n```\n\n## 🥾 Import your CSS\n\nTo give your stories access to styles, import them into your `.storybook/preview.js` file.\n\n```diff\nimport { Preview } from \"@storybook/your-renderer\";\n\n+import \"../src/index.css\";\n\nconst preview: Preview = {\n  parameters: { /* ... */ },\n};\n\nexport default preview;\n```\n\n## 🎨 Provide your theme(s)\n\nTo enable switching between these modes in a click for your stories, use our `withThemeByClassName` decorator by adding the following code to your `.storybook/preview.js` file.\n\n```diff\n-import { Preview } from \"@storybook/your-renderer\";\n+import { Preview, Renderer } from \"@storybook/your-renderer\";\n+import { withThemeByClassName } from \"@storybook/addon-themes\";\n\nimport \"../src/index.css\";\n\n\nconst preview: Preview = {\n  parameters: { /* ... */ },\n+ decorators: [\n+  withThemeByClassName<Renderer>({\n+    themes: {\n+      light: \"is-light\",\n+      dark: \"is-dark\",\n+    },\n+    defaultTheme: \"light\",\n+  }),\n+ ]\n};\n\nexport default preview;\n```\n"
  },
  {
    "path": "code/addons/themes/docs/getting-started/styled-components.md",
    "content": "# 🏁 Getting started with `styled-components`\n\n## 📦 Install addon\n\nTo get started, **install the package** as a dev dependency.\n\nyarn:\n\n```zsh\nyarn add -D @storybook/addon-themes\n```\n\nnpm:\n\n```zsh\nnpm install -D @storybook/addon-themes\n```\n\npnpm:\n\n```zsh\npnpm add -D @storybook/addon-themes\n```\n\n## 🧩 Register Addon\n\nNow, **include the addon** in your `.storybook/main.js` file.\n\n```diff\nexport default {\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    '@storybook/addon-essentials',\n+   '@storybook/addon-themes',\n  ],\n};\n```\n\n## 🎨 Provide your theme(s)\n\nFinally, provide your theme(s) and global styles component to your stories with our `withThemeFromJSXProvider` decorator.\n\nMake the following changes to your `.storybook/preview.js`:\n\n```diff\n-import { Preview } from '@storybook/your-renderer';\n+import { Preview, Renderer } from '@storybook/your-renderer';\n+import { withThemeFromJSXProvider } from '@storybook/addon-themes';\n+import { ThemeProvider } from 'styled-components';\n+import { GlobalStyles, lightTheme, darkTheme } from '../src/themes'; // Import your custom theme configs\n\nconst preview: Preview = {\n  parameters: { /* ... */ },\n+ decorators: [\n+   withThemeFromJSXProvider<Renderer>({\n+     themes: {\n+       light: lightTheme,\n+       dark: darkTheme,\n+     },\n+     defaultTheme: 'light',\n+     Provider: ThemeProvider,\n+     GlobalStyles: GlobalStyles,\n+   }),\n+ ],\n};\n\nexport default preview;\n```\n"
  },
  {
    "path": "code/addons/themes/docs/getting-started/tailwind.md",
    "content": "# 🏁 Getting started with `tailwind.css`\n\n## 📦 Install addon\n\nTo get started, **install the package** as a dev dependency.\n\nyarn:\n\n```zsh\nyarn add -D @storybook/addon-themes\n```\n\nnpm:\n\n```zsh\nnpm install -D @storybook/addon-themes\n```\n\npnpm:\n\n```zsh\npnpm add -D @storybook/addon-themes\n```\n\n## 🧩 Register Addon\n\nNow, **include the addon** in your `.storybook/main.js` file.\n\n```diff\nexport default {\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    '@storybook/addon-essentials',\n+   '@storybook/addon-themes',\n  ],\n};\n```\n\n## 🥾 Import your CSS\n\nTo give your stories access to Tailwind styles, import them into your `.storybook/preview.js` file.\n\n```diff\nimport { Preview } from '@storybook/your-renderer';\n\n+import '../src/index.css';\n\nconst preview: Preview = {\n  parameters: { /* ... */ },\n};\n\nexport default preview;\n```\n\n## 🎨 Provide your theme(s)\n\nTailwind supports light and dark color modes out of the box. These modes can be activated by setting a `.dark` class on a parent element.\n\nTo enable switching between these modes in a click for your stories, use our `withThemeByClassName` decorator by adding the following code to your `.storybook/preview.js` file.\n\n```diff\n-import { Preview } from '@storybook/your-renderer';\n+import { Preview, Renderer } from '@storybook/your-renderer';\n+import { withThemeByClassName } from '@storybook/addon-themes';\n\nimport '../src/index.css';\n\n\nconst preview: Preview = {\n  parameters: { /* ... */ },\n+ decorators: [\n+  withThemeByClassName<Renderer>({\n+    themes: {\n+      light: '',\n+      dark: 'dark',\n+    },\n+    defaultTheme: 'light',\n+  }),\n+ ]\n};\n\nexport default preview;\n```\n\n## 🏷️ Using a data-attribute for theme?\n\nIf you've configured Tailwind to toggle themes with a data attribute, use our `withThemeByDataAttribute` decorator by adding the following code to your `.storybook/preview.js` file.\n\n```diff\n-import { Preview } from '@storybook/your-renderer';\n+import { Preview, Renderer } from '@storybook/your-renderer';\n+import { withThemeByDataAttribute } from '@storybook/addon-themes';\n\nimport '../src/index.css';\n\n\nconst preview: Preview = {\n  parameters: { /* ... */ },\n+ decorators: [\n+  withThemeByDataAttribute<Renderer>({\n+    themes: {\n+      light: 'light',\n+      dark: 'dark',\n+    },\n+    defaultTheme: 'light',\n+    attributeName: 'data-theme',\n+  }),\n+ ]\n};\n\nexport default preview;\n```\n"
  },
  {
    "path": "code/addons/themes/manager.js",
    "content": "export * from './dist/manager.js';\n"
  },
  {
    "path": "code/addons/themes/package.json",
    "content": "{\n  \"name\": \"@storybook/addon-themes\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook Themes addon: Switch between themes from the toolbar\",\n  \"keywords\": [\n    \"css\",\n    \"essentials\",\n    \"storybook\",\n    \"storybook-addon\",\n    \"style\",\n    \"themes\",\n    \"toggle\",\n    \"component\",\n    \"components\",\n    \"react\",\n    \"vue\",\n    \"angular\",\n    \"svelte\",\n    \"web-components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/addons/themes\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/addons/themes\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Shaun Evening\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./manager\": \"./dist/manager.js\",\n    \"./package.json\": \"./package.json\",\n    \"./postinstall\": \"./dist/postinstall.js\",\n    \"./preview\": {\n      \"types\": \"./dist/preview.d.ts\",\n      \"code\": \"./src/preview.ts\",\n      \"default\": \"./dist/preview.js\"\n    }\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"ts-dedent\": \"^2.0.0\"\n  },\n  \"devDependencies\": {\n    \"@storybook/icons\": \"^2.0.1\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"storybook\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\",\n  \"storybook\": {\n    \"displayName\": \"Themes\",\n    \"unsupportedFrameworks\": [\n      \"react-native\"\n    ],\n    \"icon\": \"https://user-images.githubusercontent.com/18172605/264114587-e4b32190-a9b7-4afa-b739-c873fc0498a6.png\"\n  }\n}\n"
  },
  {
    "path": "code/addons/themes/preview.js",
    "content": "export * from './dist/preview.js';\n"
  },
  {
    "path": "code/addons/themes/project.json",
    "content": "{\n  \"name\": \"addon-themes\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/addons/themes/src/constants.ts",
    "content": "import type { ThemeAddonState, ThemesParameters } from './types.ts';\n\nexport const PARAM_KEY = 'themes' as const;\nexport const ADDON_ID = `storybook/${PARAM_KEY}` as const;\nexport const GLOBAL_KEY = 'theme' as const;\nexport const THEME_SWITCHER_ID = `${ADDON_ID}/theme-switcher` as const;\n\nexport const DEFAULT_ADDON_STATE: ThemeAddonState = {\n  themesList: [],\n  themeDefault: undefined,\n};\n\nexport const DEFAULT_THEME_PARAMETERS: ThemesParameters['themes'] = {};\n\nexport const THEMING_EVENTS = {\n  REGISTER_THEMES: `${ADDON_ID}/REGISTER_THEMES`,\n} as const;\n"
  },
  {
    "path": "code/addons/themes/src/decorators/class-name.decorator.tsx",
    "content": "import type { DecoratorFunction, Renderer } from 'storybook/internal/types';\n\nimport { useEffect } from 'storybook/preview-api';\n\nimport { PARAM_KEY } from '../constants.ts';\nimport { initializeThemeState, pluckThemeFromContext } from './helpers.ts';\n\nexport interface ClassNameStrategyConfiguration {\n  themes: Record<string, string>;\n  defaultTheme: string;\n  parentSelector?: string;\n}\n\nconst DEFAULT_ELEMENT_SELECTOR = 'html';\n\nconst classStringToArray = (classString: string) => classString.split(' ').filter(Boolean);\n\n// TODO check with @kasperpeulen: change the types so they can be correctly inferred from context e.g. <Story extends (...args: any[]) => any>\nexport const withThemeByClassName = <TRenderer extends Renderer = Renderer>({\n  themes,\n  defaultTheme,\n  parentSelector = DEFAULT_ELEMENT_SELECTOR,\n}: ClassNameStrategyConfiguration): DecoratorFunction<TRenderer> => {\n  initializeThemeState(Object.keys(themes), defaultTheme);\n\n  return (storyFn, context) => {\n    const { themeOverride } = context.parameters[PARAM_KEY] ?? {};\n    const selected = pluckThemeFromContext(context);\n\n    useEffect(() => {\n      const selectedThemeName = themeOverride || selected || defaultTheme;\n      const parentElement = document.querySelector(parentSelector);\n\n      if (!parentElement) {\n        return;\n      }\n\n      Object.entries(themes)\n        .filter(([themeName]) => themeName !== selectedThemeName)\n        .forEach(([themeName, className]) => {\n          const classes = classStringToArray(className);\n          if (classes.length > 0) {\n            parentElement.classList.remove(...classes);\n          }\n        });\n\n      const newThemeClasses = classStringToArray(themes[selectedThemeName]);\n\n      if (newThemeClasses.length > 0) {\n        parentElement.classList.add(...newThemeClasses);\n      }\n    }, [themeOverride, selected]);\n\n    return storyFn();\n  };\n};\n"
  },
  {
    "path": "code/addons/themes/src/decorators/data-attribute.decorator.tsx",
    "content": "import type { DecoratorFunction, Renderer } from 'storybook/internal/types';\n\nimport { useEffect } from 'storybook/preview-api';\n\nimport { PARAM_KEY } from '../constants.ts';\nimport { initializeThemeState, pluckThemeFromContext } from './helpers.ts';\n\nexport interface DataAttributeStrategyConfiguration {\n  themes: Record<string, string>;\n  defaultTheme: string;\n  parentSelector?: string;\n  attributeName?: string;\n}\n\nconst DEFAULT_ELEMENT_SELECTOR = 'html';\nconst DEFAULT_DATA_ATTRIBUTE = 'data-theme';\n\n// TODO check with @kasperpeulen: change the types so they can be correctly inferred from context e.g. <Story extends (...args: any[]) => any>\nexport const withThemeByDataAttribute = <TRenderer extends Renderer = any>({\n  themes,\n  defaultTheme,\n  parentSelector = DEFAULT_ELEMENT_SELECTOR,\n  attributeName = DEFAULT_DATA_ATTRIBUTE,\n}: DataAttributeStrategyConfiguration): DecoratorFunction<TRenderer> => {\n  initializeThemeState(Object.keys(themes), defaultTheme);\n  return (storyFn, context) => {\n    const { themeOverride } = context.parameters[PARAM_KEY] ?? {};\n    const selected = pluckThemeFromContext(context);\n\n    useEffect(() => {\n      const parentElement = document.querySelector(parentSelector);\n      const themeKey = themeOverride || selected || defaultTheme;\n\n      if (parentElement) {\n        parentElement.setAttribute(attributeName, themes[themeKey]);\n      }\n    }, [themeOverride, selected]);\n\n    return storyFn();\n  };\n};\n"
  },
  {
    "path": "code/addons/themes/src/decorators/helpers.ts",
    "content": "import { deprecate } from 'storybook/internal/client-logger';\nimport type { StoryContext } from 'storybook/internal/types';\n\nimport { addons, useParameter } from 'storybook/preview-api';\nimport { dedent } from 'ts-dedent';\n\nimport { DEFAULT_THEME_PARAMETERS, GLOBAL_KEY, PARAM_KEY, THEMING_EVENTS } from '../constants.ts';\nimport type { ThemesParameters as Parameters } from '../types.ts';\n\ntype ThemesParameters = Parameters['themes'];\n\n/**\n * @param StoryContext\n * @returns The global theme name set for your stories\n */\nexport function pluckThemeFromContext({ globals }: StoryContext): string {\n  return globals[GLOBAL_KEY] || '';\n}\n\nexport function useThemeParameters(context?: StoryContext): ThemesParameters {\n  deprecate(\n    dedent`The useThemeParameters function is deprecated. Please access parameters via the context directly instead e.g.\n    - const { themeOverride } = context.parameters.themes ?? {};\n    `\n  );\n\n  if (!context) {\n    return useParameter<ThemesParameters>(PARAM_KEY, DEFAULT_THEME_PARAMETERS) as ThemesParameters;\n  }\n\n  return context.parameters[PARAM_KEY] ?? DEFAULT_THEME_PARAMETERS;\n}\n\nexport function initializeThemeState(themeNames: string[], defaultTheme: string) {\n  addons.getChannel().emit(THEMING_EVENTS.REGISTER_THEMES, {\n    defaultTheme,\n    themes: themeNames,\n  });\n}\n"
  },
  {
    "path": "code/addons/themes/src/decorators/index.ts",
    "content": "export * from './class-name.decorator.tsx';\nexport * from './data-attribute.decorator.tsx';\nexport * from './provider.decorator.tsx';\n\nexport * as DecoratorHelpers from './helpers.ts';\n"
  },
  {
    "path": "code/addons/themes/src/decorators/provider.decorator.tsx",
    "content": "import React from 'react';\n\nimport type { DecoratorFunction, Renderer } from 'storybook/internal/types';\n\nimport { useMemo } from 'storybook/preview-api';\n\nimport { PARAM_KEY } from '../constants.ts';\nimport { initializeThemeState, pluckThemeFromContext } from './helpers.ts';\n\ntype Theme = Record<string, any>;\ntype ThemeMap = Record<string, Theme>;\n\nexport interface ProviderStrategyConfiguration {\n  Provider?: any;\n  GlobalStyles?: any;\n  defaultTheme?: string;\n  themes?: ThemeMap;\n}\n\nconst pluckThemeFromKeyPairTuple = ([_, themeConfig]: [string, Theme]): Theme => themeConfig;\n\n// TODO check with @kasperpeulen: change the types so they can be correctly inferred from context e.g. <Story extends (...args: any[]) => any>\nexport const withThemeFromJSXProvider = <TRenderer extends Renderer = any>({\n  Provider,\n  GlobalStyles,\n  defaultTheme,\n  themes = {},\n}: ProviderStrategyConfiguration): DecoratorFunction<TRenderer> => {\n  const themeNames = Object.keys(themes);\n  const initialTheme = defaultTheme || themeNames[0];\n\n  initializeThemeState(themeNames, initialTheme);\n\n  // eslint-disable-next-line react/display-name\n  return (storyFn, context) => {\n    // eslint-disable-next-line react/destructuring-assignment\n    const { themeOverride } = context.parameters[PARAM_KEY] ?? {};\n    const selected = pluckThemeFromContext(context);\n\n    const theme = useMemo(() => {\n      const selectedThemeName = themeOverride || selected || initialTheme;\n      const pairs = Object.entries(themes);\n\n      return pairs.length === 1 ? pluckThemeFromKeyPairTuple(pairs[0]) : themes[selectedThemeName];\n    }, [selected, themeOverride]);\n\n    if (!Provider) {\n      return (\n        <>\n          {GlobalStyles && <GlobalStyles />}\n          {storyFn()}\n        </>\n      );\n    }\n\n    return (\n      <Provider theme={theme}>\n        {GlobalStyles && <GlobalStyles />}\n        {storyFn()}\n      </Provider>\n    );\n  };\n};\n"
  },
  {
    "path": "code/addons/themes/src/index.ts",
    "content": "import { definePreviewAddon } from 'storybook/internal/csf';\n\nimport * as addonAnnotations from './preview.ts';\nimport type { ThemesTypes } from './types.ts';\n\nexport type { ThemesGlobals, ThemesTypes } from './types.ts';\n\nexport default () => definePreviewAddon<ThemesTypes>(addonAnnotations);\n\nexport * from './decorators/index.ts';\n"
  },
  {
    "path": "code/addons/themes/src/manager.tsx",
    "content": "import { addons, types } from 'storybook/manager-api';\n\nimport { ADDON_ID, PARAM_KEY, THEME_SWITCHER_ID } from './constants.ts';\nimport { ThemeSwitcher } from './theme-switcher.tsx';\n\naddons.register(ADDON_ID, () => {\n  addons.add(THEME_SWITCHER_ID, {\n    title: 'Themes',\n    type: types.TOOL,\n    match: ({ viewMode, tabId }) => !!(viewMode && viewMode.match(/^(story|docs)$/)) && !tabId,\n    render: ThemeSwitcher,\n    paramKey: PARAM_KEY,\n  });\n});\n"
  },
  {
    "path": "code/addons/themes/src/postinstall.ts",
    "content": "import { PackageManagerName } from 'storybook/internal/common';\n\nimport { spawnSync } from 'child_process';\n\nconst PACKAGE_MANAGER_TO_COMMAND = {\n  [PackageManagerName.NPM]: 'npx',\n  [PackageManagerName.PNPM]: 'pnpm dlx',\n  [PackageManagerName.YARN1]: 'npx',\n  [PackageManagerName.YARN2]: 'yarn dlx',\n  [PackageManagerName.BUN]: 'bunx',\n};\n\nconst selectPackageManagerCommand = (packageManager: string) =>\n  PACKAGE_MANAGER_TO_COMMAND[packageManager as keyof typeof PACKAGE_MANAGER_TO_COMMAND];\n\nexport default async function postinstall({ packageManager = PackageManagerName.NPM }) {\n  const commandString = selectPackageManagerCommand(packageManager);\n  const [command, ...commandArgs] = commandString.split(' ');\n\n  spawnSync(command, [...commandArgs, '@storybook/auto-config', 'themes'], {\n    stdio: 'inherit',\n    cwd: process.cwd(),\n  });\n}\n"
  },
  {
    "path": "code/addons/themes/src/preview.ts",
    "content": "import type { ProjectAnnotations, Renderer } from 'storybook/internal/types';\n\nimport { GLOBAL_KEY as KEY } from './constants.ts';\n\nexport const initialGlobals: ProjectAnnotations<Renderer>['initialGlobals'] = {\n  [KEY]: '',\n};\n"
  },
  {
    "path": "code/addons/themes/src/theme-switcher.tsx",
    "content": "import React from 'react';\n\nimport { Button, Select } from 'storybook/internal/components';\n\nimport { PaintBrushIcon } from '@storybook/icons';\n\nimport { addons, useAddonState, useChannel, useGlobals, useParameter } from 'storybook/manager-api';\n\nimport {\n  DEFAULT_ADDON_STATE,\n  DEFAULT_THEME_PARAMETERS,\n  GLOBAL_KEY as KEY,\n  PARAM_KEY,\n  THEME_SWITCHER_ID,\n  THEMING_EVENTS,\n} from './constants.ts';\nimport type { ThemesParameters as Parameters, ThemeAddonState } from './types.ts';\n\ntype ThemesParameters = NonNullable<Parameters['themes']>;\n\nconst hasMultipleThemes = (themesList: ThemeAddonState['themesList']) => themesList.length > 1;\nconst hasTwoThemes = (themesList: ThemeAddonState['themesList']) => themesList.length === 2;\n\nexport const ThemeSwitcher = React.memo(function ThemeSwitcher() {\n  const { themeOverride, disable } = useParameter<ThemesParameters>(\n    PARAM_KEY,\n    DEFAULT_THEME_PARAMETERS\n  ) as ThemesParameters;\n  const [{ theme: selected }, updateGlobals, storyGlobals] = useGlobals();\n\n  const channel = addons.getChannel();\n  const fromLast = channel.last(THEMING_EVENTS.REGISTER_THEMES);\n  const initializeThemeState = Object.assign({}, DEFAULT_ADDON_STATE, {\n    themesList: fromLast?.[0]?.themes || [],\n    themeDefault: fromLast?.[0]?.defaultTheme || '',\n  });\n\n  const [{ themesList, themeDefault }, updateState] = useAddonState<ThemeAddonState>(\n    THEME_SWITCHER_ID,\n    initializeThemeState\n  );\n\n  const isLocked = KEY in storyGlobals || !!themeOverride;\n\n  useChannel({\n    [THEMING_EVENTS.REGISTER_THEMES]: ({ themes, defaultTheme }) => {\n      updateState((state) => ({\n        ...state,\n        themesList: themes,\n        themeDefault: defaultTheme,\n      }));\n    },\n  });\n\n  const currentTheme = selected || themeDefault;\n  let ariaLabel = '';\n  let label = '';\n  let tooltip = '';\n  if (isLocked) {\n    label = 'Story override';\n    ariaLabel = 'Theme set by story parameters';\n    tooltip = 'Theme set by story parameters';\n  } else if (currentTheme) {\n    label = `${currentTheme} theme`;\n    ariaLabel = 'Theme'; // it's Select's job to announce the current value.\n    tooltip = 'Change theme';\n  }\n\n  if (disable) {\n    return null;\n  }\n\n  if (hasTwoThemes(themesList)) {\n    const alternateTheme = themesList.find((theme) => theme !== currentTheme);\n    return (\n      <Button\n        ariaLabel={ariaLabel}\n        tooltip={tooltip}\n        variant=\"ghost\"\n        disabled={isLocked}\n        key={THEME_SWITCHER_ID}\n        onClick={() => {\n          updateGlobals({ theme: alternateTheme });\n        }}\n      >\n        <PaintBrushIcon />\n        {label}\n      </Button>\n    );\n  }\n\n  if (hasMultipleThemes(themesList)) {\n    return (\n      <Select\n        icon={<PaintBrushIcon />}\n        ariaLabel={ariaLabel}\n        disabled={isLocked}\n        key={THEME_SWITCHER_ID}\n        defaultOptions={currentTheme}\n        options={themesList.map((theme) => ({\n          title: theme,\n          value: theme,\n        }))}\n        onSelect={(selected) => updateGlobals({ theme: selected })}\n      >\n        {label}\n      </Select>\n    );\n  }\n\n  return null;\n});\n"
  },
  {
    "path": "code/addons/themes/src/types.ts",
    "content": "export interface ThemeAddonState {\n  themesList: string[];\n  themeDefault?: string;\n}\n\nexport interface ThemesParameters {\n  /**\n   * Themes configuration\n   *\n   * @see https://github.com/storybookjs/storybook/blob/next/code/addons/themes/README.md\n   */\n  themes?: {\n    /** Remove the addon panel and disable the addon's behavior */\n    disable?: boolean;\n    /** Which theme to override for the story */\n    themeOverride?: string;\n  };\n}\n\nexport interface ThemesGlobals {\n  /** Which theme to override for the story */\n  theme?: string;\n}\n\nexport interface ThemesTypes {\n  parameters: ThemesParameters;\n  globals: ThemesGlobals;\n}\n"
  },
  {
    "path": "code/addons/themes/template/stories/decorators.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport {\n  withThemeByClassName,\n  withThemeByDataAttribute,\n  withThemeFromJSXProvider,\n} from '@storybook/addon-themes';\n\nimport { useEffect } from 'storybook/preview-api';\n\nconst cleanup = () => {\n  const existing = globalThis.document.querySelector('style[data-theme-css]');\n  if (existing) {\n    existing.remove();\n  }\n};\n\nconst addStyleSheetDecorator = (storyFn: any) => {\n  useEffect(() => {\n    cleanup();\n\n    const sheet = globalThis.document.createElement('style');\n    sheet.setAttribute('data-theme-css', '');\n    sheet.textContent = `\n      [data-theme=\"theme-a\"], .theme-a {\n        background-color: white;\n        color: black;\n      }\n      [data-theme=\"theme-b\"], .theme-b {\n        background-color: black;\n        color: white;\n      }\n    `;\n\n    globalThis.document.body.appendChild(sheet);\n\n    return cleanup;\n  });\n\n  return storyFn();\n};\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  args: {\n    text: 'Testing the themes',\n  },\n  globals: {\n    sb_theme: 'light',\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n    themes: { disable: false },\n  },\n  decorators: [addStyleSheetDecorator],\n};\n\nexport const WithThemeByClassName = {\n  globals: {},\n  decorators: [\n    withThemeByClassName({\n      defaultTheme: 'a',\n      themes: { a: 'theme-a', b: 'theme-b' },\n      parentSelector: '#storybook-root > *',\n    }),\n  ],\n};\n\nexport const WithThemeByDataAttribute = {\n  globals: {},\n  decorators: [\n    withThemeByDataAttribute({\n      defaultTheme: 'a',\n      themes: { a: 'theme-a', b: 'theme-b' },\n      parentSelector: '#storybook-root > *',\n    }),\n  ],\n};\n\nexport const WithThemeFromJSXProvider = {\n  globals: {},\n  decorators: [\n    withThemeFromJSXProvider({\n      defaultTheme: 'a',\n      themes: { a: { custom: 'theme-a' }, b: { custom: 'theme-b' } },\n      Provider: ({ theme, children }: any) => {\n        // this is not was a normal provider looks like obviously, but this needs to work in non-react as well\n        // the timeout is to wait for the render to complete, as it's not possible to use the useEffect hook here\n        setTimeout(() => {\n          const element = globalThis.document.querySelector('#storybook-root > *');\n          element?.classList.remove('theme-a', 'theme-b');\n          element?.classList.add(theme.custom);\n        }, 16);\n        return children;\n      },\n    }),\n  ],\n};\n"
  },
  {
    "path": "code/addons/themes/template/stories/globals.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { withThemeByClassName } from '@storybook/addon-themes';\n\nimport { useEffect } from 'storybook/preview-api';\n\nconst cleanup = () => {\n  const existing = globalThis.document.querySelector('style[data-theme-css]');\n  if (existing) {\n    existing.remove();\n  }\n};\n\nconst addStyleSheetDecorator = (storyFn: any) => {\n  useEffect(() => {\n    cleanup();\n\n    const sheet = globalThis.document.createElement('style');\n    sheet.setAttribute('data-theme-css', '');\n    sheet.textContent = `\n      [data-theme=\"theme-a\"], .theme-a {\n        background-color: white;\n        color: black;\n      }\n      [data-theme=\"theme-b\"], .theme-b {\n        background-color: black;\n        color: white;\n      }\n    `;\n\n    globalThis.document.body.appendChild(sheet);\n\n    return cleanup;\n  });\n\n  return storyFn();\n};\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  args: {\n    text: 'Testing the themes',\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n    themes: { disable: false },\n  },\n  globals: {\n    sb_theme: 'light',\n  },\n  decorators: [addStyleSheetDecorator],\n};\n\nexport const SetGlobal = {\n  globals: {\n    theme: 'b',\n  },\n  decorators: [\n    withThemeByClassName({\n      defaultTheme: 'a',\n      themes: { a: 'theme-a', b: 'theme-b' },\n      parentSelector: '#storybook-root > *',\n    }),\n  ],\n};\n"
  },
  {
    "path": "code/addons/themes/template/stories/parameters.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { withThemeByClassName } from '@storybook/addon-themes';\n\nimport { useEffect } from 'storybook/preview-api';\n\nconst cleanup = () => {\n  const existing = globalThis.document.querySelector('style[data-theme-css]');\n  if (existing) {\n    existing.remove();\n  }\n};\n\nconst addStyleSheetDecorator = (storyFn: any) => {\n  useEffect(() => {\n    cleanup();\n\n    const sheet = globalThis.document.createElement('style');\n    sheet.setAttribute('data-theme-css', '');\n    sheet.textContent = `\n      [data-theme=\"theme-a\"], .theme-a {\n        background-color: white;\n        color: black;\n      }\n      [data-theme=\"theme-b\"], .theme-b {\n        background-color: black;\n        color: white;\n      }\n    `;\n\n    globalThis.document.body.appendChild(sheet);\n\n    return cleanup;\n  });\n\n  return storyFn();\n};\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  args: {\n    text: 'Testing the themes',\n  },\n  globals: {\n    sb_theme: 'light',\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n    themes: { disable: false },\n  },\n  decorators: [addStyleSheetDecorator],\n};\n\nexport const SetOverride = {\n  parameters: {\n    themes: {\n      themeOverride: 'b',\n    },\n  },\n  decorators: [\n    withThemeByClassName({\n      defaultTheme: 'a',\n      themes: { a: 'theme-a', b: 'theme-b' },\n      parentSelector: '#storybook-root > *',\n    }),\n  ],\n};\n\nexport const Disabled = {\n  parameters: {\n    themes: {\n      disable: true,\n    },\n  },\n  decorators: [\n    withThemeByClassName({\n      defaultTheme: 'a',\n      themes: { a: 'theme-a', b: 'theme-b' },\n      parentSelector: '#storybook-root > *',\n    }),\n  ],\n};\n"
  },
  {
    "path": "code/addons/themes/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/addons/themes/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/addons/vitest/README.md",
    "content": "# Storybook Addon Test\n\nAddon to integrate Vitest test results with Storybook.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/addons/vitest/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./manager'],\n        entryPoint: './src/manager.tsx',\n        dts: false,\n      },\n      {\n        exportEntries: ['./internal/setup-file'],\n        entryPoint: './src/vitest-plugin/setup-file.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./internal/setup-file-with-project-annotations'],\n        entryPoint: './src/vitest-plugin/setup-file-with-project-annotations.ts',\n        external: ['virtual:/@storybook/builder-vite/project-annotations.js'],\n        dts: false,\n      },\n      {\n        exportEntries: ['./internal/test-utils'],\n        entryPoint: './src/vitest-plugin/test-utils.ts',\n        dts: false,\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./constants'],\n        entryPoint: './src/constants.ts',\n      },\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./internal/global-setup'],\n        entryPoint: './src/vitest-plugin/global-setup.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./vitest'],\n        entryPoint: './src/node/vitest.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./postinstall'],\n        entryPoint: './src/postinstall.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./vitest-plugin'],\n        entryPoint: './src/vitest-plugin/index.ts',\n      },\n      {\n        exportEntries: ['./internal/coverage-reporter'],\n        entryPoint: './src/node/coverage-reporter.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/addons/vitest/manager.js",
    "content": "export * from './dist/manager.js';\n"
  },
  {
    "path": "code/addons/vitest/package.json",
    "content": "{\n  \"name\": \"@storybook/addon-vitest\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook Vitest addon: Blazing fast component testing using stories\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-addon\",\n    \"vitest\",\n    \"testing\",\n    \"test\",\n    \"component\",\n    \"components\",\n    \"component-testing\",\n    \"react\",\n    \"vue\",\n    \"svelte\",\n    \"web-components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/addons/vitest\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/addons/vitest\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"imports\": {\n    \"#manager-store\": {\n      \"storybook\": \"./src/manager-store.mock.ts\",\n      \"default\": \"./src/manager-store.ts\"\n    }\n  },\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./constants\": {\n      \"types\": \"./dist/constants.d.ts\",\n      \"code\": \"./src/constants.ts\",\n      \"default\": \"./dist/constants.js\"\n    },\n    \"./internal/coverage-reporter\": \"./dist/node/coverage-reporter.js\",\n    \"./internal/global-setup\": \"./dist/vitest-plugin/global-setup.js\",\n    \"./internal/setup-file\": \"./dist/vitest-plugin/setup-file.js\",\n    \"./internal/setup-file-with-project-annotations\": \"./dist/vitest-plugin/setup-file-with-project-annotations.js\",\n    \"./internal/test-utils\": \"./dist/vitest-plugin/test-utils.js\",\n    \"./manager\": \"./dist/manager.js\",\n    \"./package.json\": \"./package.json\",\n    \"./postinstall\": \"./dist/postinstall.js\",\n    \"./preset\": \"./dist/preset.js\",\n    \"./vitest\": \"./dist/node/vitest.js\",\n    \"./vitest-plugin\": {\n      \"types\": \"./dist/vitest-plugin/index.d.ts\",\n      \"code\": \"./src/vitest-plugin/index.ts\",\n      \"default\": \"./dist/vitest-plugin/index.js\"\n    }\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"templates/**/*\",\n    \"!dist/dummy.*\",\n    \"README.md\",\n    \"*.mjs\",\n    \"*.js\",\n    \"*.cjs\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/global\": \"^5.0.0\",\n    \"@storybook/icons\": \"^2.0.1\"\n  },\n  \"devDependencies\": {\n    \"@storybook/addon-a11y\": \"workspace:*\",\n    \"@types/istanbul-lib-report\": \"^3.0.3\",\n    \"@types/micromatch\": \"^4.0.0\",\n    \"@types/node\": \"^22.19.1\",\n    \"@types/semver\": \"^7.7.1\",\n    \"@vitest/browser-playwright\": \"^4.1.0\",\n    \"@vitest/runner\": \"^4.1.0\",\n    \"empathic\": \"^2.0.0\",\n    \"es-toolkit\": \"^1.43.0\",\n    \"istanbul-lib-report\": \"^3.0.1\",\n    \"micromatch\": \"^4.0.8\",\n    \"pathe\": \"^1.1.2\",\n    \"picocolors\": \"^1.1.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"semver\": \"^7.7.3\",\n    \"sirv\": \"^2.0.4\",\n    \"slash\": \"^5.0.0\",\n    \"tinyglobby\": \"^0.2.10\",\n    \"tree-kill\": \"^1.2.2\",\n    \"ts-dedent\": \"^2.2.0\",\n    \"typescript\": \"^5.9.3\",\n    \"vitest\": \"^4.1.0\"\n  },\n  \"peerDependencies\": {\n    \"@vitest/browser\": \"^3.0.0 || ^4.0.0\",\n    \"@vitest/browser-playwright\": \"^4.0.0\",\n    \"@vitest/runner\": \"^3.0.0 || ^4.0.0\",\n    \"storybook\": \"workspace:^\",\n    \"vitest\": \"^3.0.0 || ^4.0.0\"\n  },\n  \"peerDependenciesMeta\": {\n    \"@vitest/browser\": {\n      \"optional\": true\n    },\n    \"@vitest/browser-playwright\": {\n      \"optional\": true\n    },\n    \"@vitest/runner\": {\n      \"optional\": true\n    },\n    \"vitest\": {\n      \"optional\": true\n    }\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"storybook\": {\n    \"displayName\": \"Test\",\n    \"unsupportedFrameworks\": [\n      \"react-native\"\n    ],\n    \"icon\": \"https://user-images.githubusercontent.com/263385/101991666-479cc600-3c7c-11eb-837b-be4e5ffa1bb8.png\"\n  }\n}\n"
  },
  {
    "path": "code/addons/vitest/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/addons/vitest/project.json",
    "content": "{\n  \"name\": \"addon-vitest\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/addons/vitest/src/components/Description.tsx",
    "content": "import React, { type ComponentProps } from 'react';\n\nimport { Link as LinkComponent } from 'storybook/internal/components';\nimport type { TestProviderState } from 'storybook/internal/types';\n\nimport { styled } from 'storybook/theming';\n\nimport type { StoreState } from '../types.ts';\nimport { GlobalErrorContext } from './GlobalErrorModal.tsx';\nimport { RelativeTime } from './RelativeTime.tsx';\n\nexport const Wrapper = styled.div(({ theme }) => ({\n  overflow: 'hidden',\n  whiteSpace: 'nowrap',\n  textOverflow: 'ellipsis',\n  fontSize: theme.typography.size.s1,\n  color: theme.textMutedColor,\n}));\n\nconst PositiveText = styled.span(({ theme }) => ({\n  color: theme.color.positiveText,\n}));\n\ninterface DescriptionProps extends Omit<ComponentProps<typeof Wrapper>, 'results'> {\n  storeState: StoreState;\n  testProviderState: TestProviderState;\n  entryId?: string;\n  isSettingsUpdated: boolean;\n}\n\nexport function Description({\n  entryId,\n  storeState,\n  testProviderState,\n  isSettingsUpdated,\n  ...props\n}: DescriptionProps) {\n  const { setModalOpen } = React.useContext(GlobalErrorContext);\n\n  const { componentTestCount, totalTestCount, unhandledErrors, finishedAt } = storeState.currentRun;\n  const finishedTestCount = componentTestCount.success + componentTestCount.error;\n\n  let description: string | React.ReactNode = 'Not run';\n  if (!entryId && isSettingsUpdated) {\n    description = <PositiveText>Settings updated</PositiveText>;\n  } else if (testProviderState === 'test-provider-state:running') {\n    description =\n      (finishedTestCount ?? 0) === 0\n        ? 'Starting...'\n        : `Testing... ${finishedTestCount}/${totalTestCount}`;\n  } else if (!entryId && testProviderState === 'test-provider-state:crashed') {\n    description = setModalOpen ? (\n      <LinkComponent onClick={() => setModalOpen(true)}>View full error</LinkComponent>\n    ) : (\n      'Crashed'\n    );\n  } else if (!entryId && unhandledErrors.length > 0) {\n    const unhandledErrorDescription = `View ${unhandledErrors.length} unhandled error${unhandledErrors?.length > 1 ? 's' : ''}`;\n    description = setModalOpen ? (\n      <LinkComponent onClick={() => setModalOpen(true)}>{unhandledErrorDescription}</LinkComponent>\n    ) : (\n      unhandledErrorDescription\n    );\n  } else if (entryId && totalTestCount) {\n    description = `Ran ${totalTestCount} ${totalTestCount === 1 ? 'test' : 'tests'}`;\n  } else if (finishedAt) {\n    description = (\n      <>\n        Ran {totalTestCount} {totalTestCount === 1 ? 'test' : 'tests'}{' '}\n        <RelativeTime timestamp={finishedAt} />\n      </>\n    );\n  } else if (storeState.watching) {\n    description = 'Watching for file changes';\n  }\n\n  return <Wrapper {...props}>{description}</Wrapper>;\n}\n"
  },
  {
    "path": "code/addons/vitest/src/components/GlobalErrorModal.stories.tsx",
    "content": "import React, { useState } from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { ManagerContext } from 'storybook/manager-api';\nimport { expect, fn, userEvent, within } from 'storybook/test';\nimport { dedent } from 'ts-dedent';\n\nimport { storeOptions } from '../constants.ts';\nimport { GlobalErrorContext, GlobalErrorModal } from './GlobalErrorModal.tsx';\n\ntype Story = StoryObj<typeof meta>;\n\nconst managerContext: any = {\n  state: {},\n  api: {\n    getDocsUrl: fn(({ subpath }) => `https://storybook.js.org/docs/${subpath}`).mockName(\n      'api::getDocsUrl'\n    ),\n  },\n};\n\nconst meta = {\n  component: GlobalErrorModal,\n  decorators: [\n    (storyFn) => {\n      const [isModalOpen, setModalOpen] = useState(false);\n      return (\n        <ManagerContext.Provider value={managerContext}>\n          <GlobalErrorContext.Provider value={{ isModalOpen, setModalOpen }}>\n            <div\n              style={{\n                width: '100%',\n                minWidth: '1200px',\n                height: '800px',\n                background:\n                  'repeating-linear-gradient(45deg, #000000, #ffffff 50px, #ffffff 50px, #ffffff 80px)',\n              }}\n            >\n              {storyFn()}\n            </div>\n            <button onClick={() => setModalOpen(true)}>Open modal</button>\n          </GlobalErrorContext.Provider>\n        </ManagerContext.Provider>\n      );\n    },\n  ],\n  args: {\n    onRerun: fn(),\n    storeState: storeOptions.initialState,\n  },\n} satisfies Meta<typeof GlobalErrorModal>;\n\nexport default meta;\n\nexport const FatalError: Story = {\n  args: {\n    onRerun: fn(),\n    storeState: {\n      ...storeOptions.initialState,\n      fatalError: {\n        message: 'Some fatal error message',\n        error: {\n          message: dedent`\n        ReferenceError: FAIL is not defined\n          at Constraint.execute (the-best-file.js:525:2)\n          at Constraint.recalculate (the-best-file.js:424:21)\n          at Planner.addPropagate (the-best-file.js:701:6)\n          at Constraint.satisfy (the-best-file.js:184:15)\n          at Planner.incrementalAdd (the-best-file.js:591:21)\n          at Constraint.addConstraint (the-best-file.js:162:10)\n          at Constraint.BinaryConstraint (the-best-file.js:346:7)\n          at Constraint.EqualityConstraint (the-best-file.js:515:38)\n          at chainTest (the-best-file.js:807:6)\n          at deltaBlue (the-best-file.js:879:2)`,\n        },\n      },\n    },\n  },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement.parentElement!);\n    const button = canvas.getByText('Open modal');\n    await userEvent.click(button);\n    await expect(canvas.findByText('Storybook Test Error Details')).resolves.toBeInTheDocument();\n  },\n};\n\nexport const UnhandledErrors: Story = {\n  ...FatalError,\n  args: {\n    onRerun: fn(),\n    storeState: {\n      ...storeOptions.initialState,\n      currentRun: {\n        ...storeOptions.initialState.currentRun,\n        unhandledErrors: [\n          {\n            name: 'Error',\n            message: 'this is an error thrown in a setTimeout in play',\n            stack: dedent`Error: this is an error thrown in a setTimeout in play\n    at http://localhost:63315/some/absolute/path/to/file.js?import&browserv=1742507455852:74:13`,\n            VITEST_TEST_PATH: '/some/absolute/path/to/file.js',\n            VITEST_TEST_NAME: 'My test',\n            stacks: [\n              {\n                file: '/some/absolute/path/to/file.js',\n                line: 74,\n                column: 13,\n                method: 'someMethod',\n              },\n              {\n                file: '/some/absolute/path/to/other/file.js',\n                line: 123,\n                column: 45,\n                method: 'someOtherMethod',\n              },\n            ],\n          },\n          {\n            name: 'Error',\n            message: 'this is an error rejected in play',\n            stack: dedent`Error: this is an error rejected in play\n    at play (http://localhost:63315/some/absolute/path/to/file.js?import&browserv=1742507682505:73:20)\n    at runStory (http://localhost:63315/@fs/some/absolute/path/to/.vite/deps/chunk-YVH55Y2L.js?v=77e3ac43:31517:11)\n    at async http://localhost:63315/@fs/some/absolute/path/to/.vite/deps/@storybook_addon-vitest_internal_test-utils.js?v=59e7fce5:121:5\n    at async http://localhost:63315/@fs/some/absolute/path/to/@vitest/runner/dist/index.js?v=77e3ac43:573:22`,\n            VITEST_TEST_PATH: '/some/absolute/path/to/file.js',\n            VITEST_TEST_NAME: 'My other test',\n            stacks: [\n              {\n                file: '/some/absolute/path/to/file.js',\n                line: 73,\n                column: 20,\n                method: 'play',\n              },\n              {\n                file: '/some/absolute/path/to/.vite/deps/chunk-YVH55Y2L.js',\n                line: 31517,\n                column: 11,\n                method: 'runStory',\n              },\n            ],\n          },\n        ],\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "code/addons/vitest/src/components/GlobalErrorModal.tsx",
    "content": "import React, { useContext } from 'react';\n\nimport { Button, Modal } from 'storybook/internal/components';\n\nimport { SyncIcon } from '@storybook/icons';\n\nimport { useStorybookApi } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport { DOCUMENTATION_FATAL_ERROR_LINK } from '../constants.ts';\nimport type { ErrorLike, StoreState } from '../types.ts';\n\nconst ModalBar = styled.div({\n  display: 'flex',\n  justifyContent: 'space-between',\n  alignItems: 'center',\n  padding: '6px 6px 6px 20px',\n});\n\nconst ModalActionBar = styled.div({\n  display: 'flex',\n  justifyContent: 'space-between',\n  alignItems: 'center',\n});\n\nconst ModalTitle = styled(Modal.Title)(({ theme: { typography } }) => ({\n  fontSize: typography.size.s2,\n  fontWeight: typography.weight.bold,\n}));\n\nconst ModalStackTrace = styled.pre(({ theme }) => ({\n  whiteSpace: 'pre-wrap',\n  wordWrap: 'break-word',\n  userSelect: 'text',\n  overflow: 'auto',\n  maxHeight: '60vh',\n  margin: 0,\n  padding: `20px`,\n  fontFamily: theme.typography.fonts.mono,\n  fontSize: '12px',\n  borderTop: `1px solid ${theme.appBorderColor}`,\n  borderRadius: 0,\n}));\n\nconst TroubleshootLink = styled.a(({ theme }) => ({\n  color: theme.color.defaultText,\n}));\n\nexport const GlobalErrorContext = React.createContext<{\n  isModalOpen: boolean;\n  setModalOpen?: (isOpen: boolean) => void;\n}>({\n  isModalOpen: false,\n  setModalOpen: undefined,\n});\n\ninterface GlobalErrorModalProps {\n  onRerun: () => void;\n  storeState: StoreState;\n}\n\nfunction ErrorCause({ error }: { error: ErrorLike }) {\n  if (!error) {\n    return null;\n  }\n\n  return (\n    <div>\n      <h4>\n        Caused by: {error.name || 'Error'}: {error.message}\n      </h4>\n      {error.stack && <pre>{error.stack}</pre>}\n      {error.cause && <ErrorCause error={error.cause} />}\n    </div>\n  );\n}\n\nexport function GlobalErrorModal({ onRerun, storeState }: GlobalErrorModalProps) {\n  const api = useStorybookApi();\n  const { isModalOpen, setModalOpen } = useContext(GlobalErrorContext);\n\n  const troubleshootURL = api.getDocsUrl({\n    subpath: DOCUMENTATION_FATAL_ERROR_LINK,\n    versioned: true,\n    renderer: true,\n  });\n\n  const {\n    fatalError,\n    currentRun: { unhandledErrors },\n  } = storeState;\n\n  const content = fatalError ? (\n    <>\n      <p>{fatalError.error.name || 'Error'}</p>\n      {fatalError.message && <p>{fatalError.message}</p>}\n      {fatalError.error.message && <p>{fatalError.error.message}</p>}\n      {fatalError.error.stack && <p>{fatalError.error.stack}</p>}\n      {fatalError.error.cause && <ErrorCause error={fatalError.error.cause} />}\n    </>\n  ) : unhandledErrors.length > 0 ? (\n    <ol>\n      {unhandledErrors.map((error) => (\n        <li key={error.name + error.message}>\n          <p>\n            {error.name}: {error.message}\n          </p>\n          {error.VITEST_TEST_PATH && (\n            <p>\n              This error originated in \"<b>{error.VITEST_TEST_PATH}</b>\". It doesn't mean the error\n              was thrown inside the file itself, but while it was running.\n            </p>\n          )}\n          {error.VITEST_TEST_NAME && (\n            <>\n              <p>\n                The latest test that might've caused the error is \"<b>{error.VITEST_TEST_NAME}</b>\".\n                It might mean one of the following:\n              </p>\n              <ul>\n                <li>The error was thrown, while Vitest was running this test.</li>\n                <li>\n                  If the error occurred after the test had been completed, this was the last\n                  documented test before it was thrown.\n                </li>\n              </ul>\n            </>\n          )}\n          {error.stacks && (\n            <>\n              <p>\n                <b>Stacks:</b>\n              </p>\n              <ul>\n                {error.stacks.map((stack) => (\n                  <li key={stack.file + stack.line + stack.column}>\n                    {stack.file}:{stack.line}:{stack.column} - {stack.method || 'unknown method'}\n                  </li>\n                ))}\n              </ul>\n            </>\n          )}\n          {error.stack && <p>{error.stack}</p>}\n          {error.cause ? <ErrorCause error={error.cause as ErrorLike} /> : null}\n        </li>\n      ))}\n    </ol>\n  ) : null;\n\n  return (\n    <Modal ariaLabel=\"Storybook Test Error Details\" onOpenChange={setModalOpen} open={isModalOpen}>\n      <ModalBar>\n        <ModalTitle>Storybook Test Error Details</ModalTitle>\n        <ModalActionBar>\n          <Button onClick={onRerun} variant=\"ghost\" ariaLabel={false}>\n            <SyncIcon />\n            Rerun\n          </Button>\n          <Button variant=\"ghost\" ariaLabel={false} asChild>\n            <a target=\"_blank\" href={troubleshootURL} rel=\"noreferrer\">\n              Troubleshoot\n            </a>\n          </Button>\n          <Modal.Close />\n        </ModalActionBar>\n      </ModalBar>\n      <ModalStackTrace>\n        {content}\n        <br />\n        <br />\n        Troubleshoot:{' '}\n        <TroubleshootLink target=\"_blank\" href={troubleshootURL}>\n          {troubleshootURL}\n        </TroubleshootLink>\n      </ModalStackTrace>\n    </Modal>\n  );\n}\n"
  },
  {
    "path": "code/addons/vitest/src/components/RelativeTime.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { RelativeTime } from './RelativeTime.tsx';\n\nconst meta = {\n  component: RelativeTime,\n} satisfies Meta<typeof RelativeTime>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const JustNow: Story = {\n  args: {\n    timestamp: Date.now() - 1000 * 10,\n  },\n};\n\nexport const AMinuteAgo: Story = {\n  args: {\n    timestamp: Date.now() - 1000 * 60,\n  },\n};\n\nexport const MinutesAgo: Story = {\n  args: {\n    timestamp: Date.now() - 1000 * 60 * 2,\n  },\n};\n\nexport const HoursAgo: Story = {\n  args: {\n    timestamp: Date.now() - 1000 * 60 * 60 * 3,\n  },\n};\n\nexport const Yesterday: Story = {\n  args: {\n    timestamp: Date.now() - 1000 * 60 * 60 * 24,\n  },\n};\n\nexport const DaysAgo: Story = {\n  args: {\n    timestamp: Date.now() - 1000 * 60 * 60 * 24 * 3,\n  },\n};\n"
  },
  {
    "path": "code/addons/vitest/src/components/RelativeTime.tsx",
    "content": "import { useEffect, useState } from 'react';\n\nexport const RelativeTime = ({ timestamp }: { timestamp?: number }) => {\n  const [timeAgo, setTimeAgo] = useState<number | null>(null);\n\n  useEffect(() => {\n    if (timestamp) {\n      setTimeAgo(Date.now() - timestamp);\n      const interval = setInterval(() => setTimeAgo(Date.now() - timestamp), 10000);\n      return () => clearInterval(interval);\n    }\n  }, [timestamp]);\n\n  if (timeAgo === null) {\n    return null;\n  }\n\n  const seconds = Math.round(timeAgo / 1000);\n  if (seconds < 60) {\n    return `just now`;\n  }\n\n  const minutes = Math.floor(seconds / 60);\n  if (minutes < 60) {\n    return minutes === 1 ? `a minute ago` : `${minutes} minutes ago`;\n  }\n\n  const hours = Math.floor(minutes / 60);\n  if (hours < 24) {\n    return hours === 1 ? `an hour ago` : `${hours} hours ago`;\n  }\n\n  const days = Math.floor(hours / 24);\n  return days === 1 ? `yesterday` : `${days} days ago`;\n};\n"
  },
  {
    "path": "code/addons/vitest/src/components/SidebarContextMenu.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport type { API_HashEntry } from 'storybook/internal/types';\n\nimport { type API } from 'storybook/manager-api';\n\nimport { useTestProvider } from '../use-test-provider-state.ts';\nimport { TestProviderRender } from './TestProviderRender.tsx';\n\ntype SidebarContextMenuProps = {\n  api: API;\n  context: API_HashEntry;\n};\n\nexport const SidebarContextMenu: FC<SidebarContextMenuProps> = ({ context, api }) => {\n  const {\n    testProviderState,\n    componentTestStatusValueToStoryIds,\n    a11yStatusValueToStoryIds,\n    storeState,\n    setStoreState,\n  } = useTestProvider(api, context.id);\n\n  return (\n    <TestProviderRender\n      api={api}\n      entry={context}\n      style={{ minWidth: 240 }}\n      testProviderState={testProviderState}\n      componentTestStatusValueToStoryIds={componentTestStatusValueToStoryIds}\n      a11yStatusValueToStoryIds={a11yStatusValueToStoryIds}\n      storeState={storeState}\n      setStoreState={setStoreState}\n      isSettingsUpdated={false}\n    />\n  );\n};\n"
  },
  {
    "path": "code/addons/vitest/src/components/TestProviderRender.stories.tsx",
    "content": "import React from 'react';\n\nimport { Addon_TypesEnum } from 'storybook/internal/types';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { ManagerContext, addons } from 'storybook/manager-api';\nimport { fn } from 'storybook/test';\nimport { styled } from 'storybook/theming';\n\nimport { ADDON_ID as A11Y_ADDON_ID } from '../../../a11y/src/constants.ts';\nimport { storeOptions } from '../constants.ts';\nimport { store as mockStore } from '../manager-store.mock.ts';\nimport { TestProviderRender } from './TestProviderRender.tsx';\n\nconst managerContext: any = {\n  api: {\n    getDocsUrl: fn(({ subpath }) => `https://storybook.js.org/docs/${subpath}`).mockName(\n      'api::getDocsUrl'\n    ),\n    findAllLeafStoryIds: fn((entryId) => [entryId]),\n    selectStory: fn().mockName('api::selectStory'),\n    setSelectedPanel: fn().mockName('api::setSelectedPanel'),\n    togglePanel: fn().mockName('api::togglePanel'),\n  },\n};\n\nconst Content = styled.div({\n  padding: '12px 6px',\n  display: 'flex',\n  flexDirection: 'column',\n  gap: '12px',\n});\n\nconst meta = {\n  title: 'TestProviderRender',\n  component: TestProviderRender,\n  args: {\n    api: managerContext.api,\n    testProviderState: 'test-provider-state:pending',\n    componentTestStatusValueToStoryIds: {\n      'status-value:error': [],\n      'status-value:success': [],\n      'status-value:pending': [],\n      'status-value:warning': [],\n      'status-value:unknown': [],\n    },\n    a11yStatusValueToStoryIds: {\n      'status-value:error': [],\n      'status-value:success': [],\n      'status-value:pending': [],\n      'status-value:warning': [],\n      'status-value:unknown': [],\n    },\n    storeState: storeOptions.initialState,\n    setStoreState: fn(),\n    isSettingsUpdated: false,\n  },\n  decorators: [\n    (StoryFn) => (\n      <Content>\n        <StoryFn />\n      </Content>\n    ),\n    (StoryFn) => (\n      <ManagerContext.Provider value={managerContext}>\n        <StoryFn />\n      </ManagerContext.Provider>\n    ),\n  ],\n  parameters: {\n    layout: 'fullscreen',\n  },\n  beforeEach: async () => {\n    addons.register(A11Y_ADDON_ID, () => {});\n    mockStore.setState.mockClear();\n    return () => {\n      mockStore.setState(storeOptions.initialState);\n    };\n  },\n} satisfies Meta<typeof TestProviderRender>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {};\n\nexport const Starting: Story = {\n  args: {\n    testProviderState: 'test-provider-state:running',\n  },\n};\n\nexport const Testing: Story = {\n  args: {\n    testProviderState: 'test-provider-state:running',\n    storeState: {\n      ...storeOptions.initialState,\n      currentRun: {\n        ...storeOptions.initialState.currentRun,\n        componentTestCount: {\n          success: 30,\n          error: 0,\n        },\n        totalTestCount: 100,\n      },\n    },\n  },\n};\n\nexport const TestingWithStatuses: Story = {\n  args: {\n    testProviderState: 'test-provider-state:running',\n    storeState: {\n      ...storeOptions.initialState,\n      config: {\n        coverage: true,\n        a11y: true,\n      },\n      currentRun: {\n        ...storeOptions.initialState.currentRun,\n        componentTestCount: {\n          success: 30,\n          error: 0,\n        },\n        totalTestCount: 100,\n      },\n    },\n    componentTestStatusValueToStoryIds: {\n      ...meta.args.componentTestStatusValueToStoryIds,\n      'status-value:error': ['story-id-1', 'story-id-2'],\n    },\n    a11yStatusValueToStoryIds: {\n      ...meta.args.a11yStatusValueToStoryIds,\n      'status-value:warning': ['story-id-3', 'story-id-4', 'story-id-5'],\n    },\n  },\n};\n\nexport const Watching: Story = {\n  args: {\n    storeState: {\n      ...storeOptions.initialState,\n      watching: true,\n    },\n  },\n};\n\nexport const Crashed: Story = {\n  args: {\n    testProviderState: 'test-provider-state:crashed',\n    storeState: {\n      ...storeOptions.initialState,\n      fatalError: {\n        message: 'Error message',\n        error: {\n          name: 'Error',\n          message: 'Error message',\n          stack: 'Error stack',\n        },\n      },\n    },\n  },\n};\n\nexport const UnhandledErrors: Story = {\n  args: {\n    testProviderState: 'test-provider-state:succeeded',\n    storeState: {\n      ...storeOptions.initialState,\n      currentRun: {\n        ...storeOptions.initialState.currentRun,\n        unhandledErrors: [\n          {\n            name: 'Error',\n            message: 'Error message',\n            stack: 'Error stack',\n            VITEST_TEST_PATH: '/test/path/test-name',\n            VITEST_TEST_NAME: 'Test name',\n          },\n          {\n            name: 'Error',\n            message: 'Other Error message',\n            stack: 'Other Error stack',\n            VITEST_TEST_PATH: '/test/path/other-test-name',\n            VITEST_TEST_NAME: 'Other Test name',\n          },\n        ],\n      },\n    },\n  },\n};\n\nexport const ComponentTestsSucceeded: Story = {\n  args: {\n    testProviderState: 'test-provider-state:succeeded',\n    componentTestStatusValueToStoryIds: {\n      ...meta.args.componentTestStatusValueToStoryIds,\n      'status-value:success': ['story-id-1'],\n    },\n  },\n};\n\nexport const ComponentTestsFailed: Story = {\n  args: {\n    testProviderState: 'test-provider-state:succeeded',\n    componentTestStatusValueToStoryIds: {\n      ...meta.args.componentTestStatusValueToStoryIds,\n      'status-value:error': ['story-id-1'],\n    },\n  },\n};\n\nexport const CoverageEnabled: Story = {\n  args: {\n    storeState: {\n      ...meta.args.storeState,\n      config: { ...meta.args.storeState.config, coverage: true },\n    },\n  },\n};\n\nexport const RunningWithCoverageEnabled: Story = {\n  args: {\n    ...CoverageEnabled.args,\n    testProviderState: 'test-provider-state:running',\n  },\n};\n\nexport const CoverageNegative: Story = {\n  args: {\n    storeState: {\n      ...CoverageEnabled.args!.storeState!,\n      currentRun: {\n        ...meta.args.storeState.currentRun,\n        coverageSummary: { percentage: 20, status: 'negative' },\n      },\n    },\n  },\n};\n\nexport const CoverageWarning: Story = {\n  args: {\n    storeState: {\n      ...CoverageEnabled.args!.storeState!,\n      currentRun: {\n        ...meta.args.storeState.currentRun,\n        coverageSummary: { percentage: 50, status: 'warning' },\n      },\n    },\n  },\n};\n\nexport const CoveragePositive: Story = {\n  args: {\n    storeState: {\n      ...CoverageEnabled.args!.storeState!,\n      currentRun: {\n        ...meta.args.storeState.currentRun,\n        coverageSummary: { percentage: 80, status: 'positive' },\n      },\n    },\n  },\n};\n\nexport const AccessibilityEnabled: Story = {\n  args: {\n    storeState: {\n      ...meta.args.storeState,\n      config: { ...meta.args.storeState.config, a11y: true },\n    },\n  },\n};\n\nexport const AccessibilityViolations: Story = {\n  args: {\n    ...AccessibilityEnabled.args,\n    testProviderState: 'test-provider-state:succeeded',\n    a11yStatusValueToStoryIds: {\n      ...meta.args.a11yStatusValueToStoryIds,\n      'status-value:warning': ['story-id-1', 'story-id-2', 'story-id-3'],\n    },\n  },\n};\n\nexport const AccessibilityViolationsWithErrors: Story = {\n  args: {\n    ...AccessibilityEnabled.args,\n    testProviderState: 'test-provider-state:succeeded',\n    a11yStatusValueToStoryIds: {\n      ...meta.args.a11yStatusValueToStoryIds,\n      'status-value:warning': ['story-id-1', 'story-id-2', 'story-id-5'],\n      'status-value:error': ['story-id-3', 'story-id-4'],\n    },\n  },\n};\n\nexport const SettingsUpdated: Story = {\n  args: {\n    ...meta.args,\n    isSettingsUpdated: true,\n  },\n};\n\nexport const InSidebarContextMenu: Story = {\n  args: {\n    ...meta.args,\n    testProviderState: 'test-provider-state:succeeded',\n    entry: {\n      id: 'story-id-1',\n      type: 'story',\n      subtype: 'story',\n      name: 'Example Story',\n      tags: [],\n      title: 'Example Story',\n      importPath: './path/to/story',\n      prepared: true,\n      parent: 'parent-id',\n      exportName: 'ExampleStory',\n      depth: 1,\n    },\n  },\n};\n"
  },
  {
    "path": "code/addons/vitest/src/components/TestProviderRender.tsx",
    "content": "import React, { type ComponentProps, type FC } from 'react';\n\nimport {\n  ActionList,\n  Button,\n  Form,\n  ProgressSpinner,\n  ToggleButton,\n} from 'storybook/internal/components';\nimport type { API_HashEntry, TestProviderState } from 'storybook/internal/types';\n\nimport { EyeIcon, InfoIcon, PlayHollowIcon, StopAltIcon } from '@storybook/icons';\n\nimport { store } from '#manager-store';\nimport { addons } from 'storybook/manager-api';\nimport type { API } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport {\n  A11Y_ADDON_ID,\n  A11Y_PANEL_ID,\n  COMPONENT_TESTING_PANEL_ID,\n  FULL_RUN_TRIGGERS,\n} from '../constants.ts';\nimport type { StoreState } from '../types.ts';\nimport type { StatusValueToStoryIds } from '../use-test-provider-state.ts';\nimport { Description } from './Description.tsx';\nimport { TestStatusIcon } from './TestStatusIcon.tsx';\n\nconst Container = styled.div<{ inContextMenu?: boolean }>(({ inContextMenu }) => ({\n  display: 'flex',\n  flexDirection: 'column',\n  paddingBottom: inContextMenu ? 0 : 1,\n}));\n\nconst Heading = styled.div({\n  display: 'flex',\n  justifyContent: 'space-between',\n  padding: '8px 0',\n  gap: 12,\n});\n\nconst Info = styled.div({\n  display: 'flex',\n  flexDirection: 'column',\n  marginLeft: 8,\n  minWidth: 0,\n});\n\nconst Title = styled.div<{ crashed?: boolean }>(({ crashed, theme }) => ({\n  fontSize: theme.typography.size.s1,\n  fontWeight: crashed ? 'bold' : 'normal',\n  color: crashed ? theme.color.negativeText : theme.color.defaultText,\n}));\n\nconst Actions = styled.div({\n  display: 'flex',\n  gap: 4,\n});\n\nconst StyledActionList = styled(ActionList)({\n  padding: 0,\n});\n\nconst Muted = styled.span(({ theme }) => ({\n  color: theme.textMutedColor,\n}));\n\nconst Progress = styled(ProgressSpinner)({\n  margin: 4,\n});\n\nconst StopIcon = styled(StopAltIcon)({\n  width: 10,\n});\n\nconst openPanel = ({ api, panelId, entryId }: { api: API; panelId: string; entryId?: string }) => {\n  const story = entryId ? api.findAllLeafStoryIds(entryId)[0] : undefined;\n  if (story) {\n    api.selectStory(story);\n  }\n  api.setSelectedPanel(panelId);\n  api.togglePanel(true);\n};\n\ntype TestProviderRenderProps = {\n  api: API;\n  testProviderState: TestProviderState;\n  componentTestStatusValueToStoryIds: StatusValueToStoryIds;\n  a11yStatusValueToStoryIds: StatusValueToStoryIds;\n  storeState: StoreState;\n  setStoreState: (typeof store)['setState'];\n  isSettingsUpdated: boolean;\n  entry?: API_HashEntry;\n} & ComponentProps<typeof Container>;\n\nexport const TestProviderRender: FC<TestProviderRenderProps> = ({\n  api,\n  entry,\n  testProviderState,\n  storeState,\n  setStoreState,\n  componentTestStatusValueToStoryIds,\n  a11yStatusValueToStoryIds,\n  isSettingsUpdated,\n  ...props\n}) => {\n  const { config, watching, cancelling, currentRun, fatalError } = storeState;\n  const finishedTestCount =\n    currentRun.componentTestCount.success + currentRun.componentTestCount.error;\n\n  const hasA11yAddon = addons.experimental_getRegisteredAddons().includes(A11Y_ADDON_ID);\n\n  const isRunning = testProviderState === 'test-provider-state:running';\n  const isStarting = isRunning && finishedTestCount === 0;\n\n  const [componentTestStatusIcon, componentTestStatusLabel]: [\n    ComponentProps<typeof TestStatusIcon>['status'],\n    string,\n  ] = fatalError\n    ? ['critical', 'Component tests crashed']\n    : componentTestStatusValueToStoryIds['status-value:error'].length > 0\n      ? ['negative', 'Component tests failed']\n      : isRunning\n        ? ['unknown', 'Testing in progress']\n        : componentTestStatusValueToStoryIds['status-value:success'].length > 0\n          ? ['positive', 'Component tests passed']\n          : ['unknown', 'Run tests to see results'];\n\n  const [a11yStatusIcon, a11yStatusLabel]: [\n    ComponentProps<typeof TestStatusIcon>['status'],\n    string,\n  ] = fatalError\n    ? ['critical', 'Component tests crashed']\n    : a11yStatusValueToStoryIds['status-value:error'].length > 0\n      ? ['negative', 'Accessibility tests failed']\n      : a11yStatusValueToStoryIds['status-value:warning'].length > 0\n        ? ['warning', 'Accessibility tests failed']\n        : isRunning\n          ? ['unknown', 'Testing in progress']\n          : a11yStatusValueToStoryIds['status-value:success'].length > 0\n            ? ['positive', 'Accessibility tests passed']\n            : ['unknown', 'Run tests to see accessibility results'];\n\n  return (\n    <Container {...props} inContextMenu={!!entry}>\n      <Heading>\n        <Info>\n          {entry ? (\n            <Title id=\"testing-module-title\">Run component tests</Title>\n          ) : (\n            <Title\n              id=\"testing-module-title\"\n              crashed={\n                testProviderState === 'test-provider-state:crashed' ||\n                fatalError !== undefined ||\n                currentRun.unhandledErrors.length > 0\n              }\n            >\n              {currentRun.unhandledErrors.length === 1\n                ? 'Component tests completed with an error'\n                : currentRun.unhandledErrors.length > 1\n                  ? 'Component tests completed with errors'\n                  : fatalError\n                    ? 'Component tests didn’t complete'\n                    : 'Run component tests'}\n            </Title>\n          )}\n          <Description\n            id=\"testing-module-description\"\n            storeState={storeState}\n            testProviderState={testProviderState}\n            entryId={entry?.id}\n            isSettingsUpdated={isSettingsUpdated}\n          />\n        </Info>\n\n        <Actions>\n          {!entry && (\n            <ToggleButton\n              ariaLabel={isRunning ? 'Watch mode (cannot toggle while running)' : 'Watch mode'}\n              tooltip={\n                isRunning\n                  ? 'Watch mode unavailable while running'\n                  : `Watch mode is ${watching ? 'enabled' : 'disabled'}`\n              }\n              padding=\"small\"\n              size=\"medium\"\n              variant=\"ghost\"\n              pressed={watching}\n              onClick={() =>\n                store.send({\n                  type: 'TOGGLE_WATCHING',\n                  payload: {\n                    to: !watching,\n                  },\n                })\n              }\n              disabled={isRunning}\n            >\n              <EyeIcon />\n            </ToggleButton>\n          )}\n          {isRunning ? (\n            <Button\n              // FIXME: we must clarify why isStarting has any impact here.\n              // TODO: if technical reasons explain why we must wait for tests to finish\n              // initialising, we'll want to have an ARIA Live region to announce when\n              // the run actually starts.\n              ariaLabel={cancelling ? 'Stop test run (already stopping...)' : 'Stop test run'}\n              padding=\"none\"\n              size=\"medium\"\n              variant=\"ghost\"\n              onClick={() =>\n                store.send({\n                  type: 'CANCEL_RUN',\n                })\n              }\n              disabled={cancelling || isStarting}\n            >\n              <Progress\n                percentage={\n                  finishedTestCount && storeState.currentRun.totalTestCount\n                    ? (finishedTestCount / storeState.currentRun.totalTestCount) * 100\n                    : undefined\n                }\n              >\n                <StopIcon />\n              </Progress>\n            </Button>\n          ) : (\n            <Button\n              ariaLabel=\"Start test run\"\n              padding=\"small\"\n              size=\"medium\"\n              variant=\"ghost\"\n              onClick={() => {\n                let storyIds;\n                if (entry) {\n                  // Don't send underlying child test ids when running on a story\n                  // Vitest Manager already handles running the underlying tests\n                  storyIds =\n                    entry.type === 'story' ? [entry.id] : api.findAllLeafStoryIds(entry.id);\n                }\n                store.send({\n                  type: 'TRIGGER_RUN',\n                  payload: { storyIds, triggeredBy: entry?.type ?? 'global' },\n                });\n              }}\n            >\n              <PlayHollowIcon />\n            </Button>\n          )}\n        </Actions>\n      </Heading>\n\n      <StyledActionList>\n        <ActionList.Item>\n          {entry ? (\n            <ActionList.Text>Interactions</ActionList.Text>\n          ) : (\n            <ActionList.Action as=\"label\" readOnly>\n              <ActionList.Icon>\n                <Form.Checkbox name=\"Interactions\" checked disabled />\n              </ActionList.Icon>\n              <ActionList.Text>Interactions</ActionList.Text>\n            </ActionList.Action>\n          )}\n          <ActionList.Button\n            ariaLabel={`${componentTestStatusLabel}${\n              componentTestStatusValueToStoryIds['status-value:error'].length +\n                componentTestStatusValueToStoryIds['status-value:warning'].length >\n              0\n                ? ` (${\n                    componentTestStatusValueToStoryIds['status-value:error'].length +\n                    componentTestStatusValueToStoryIds['status-value:warning'].length\n                  } errors or warnings so far)`\n                : ''\n            }`}\n            tooltip={componentTestStatusLabel}\n            disabled={\n              componentTestStatusValueToStoryIds['status-value:error'].length === 0 &&\n              componentTestStatusValueToStoryIds['status-value:warning'].length === 0 &&\n              componentTestStatusValueToStoryIds['status-value:success'].length === 0\n            }\n            onClick={() => {\n              openPanel({\n                api,\n                panelId: COMPONENT_TESTING_PANEL_ID,\n                entryId:\n                  componentTestStatusValueToStoryIds['status-value:error'][0] ??\n                  componentTestStatusValueToStoryIds['status-value:warning'][0] ??\n                  componentTestStatusValueToStoryIds['status-value:success'][0] ??\n                  entry?.id,\n              });\n            }}\n          >\n            {componentTestStatusValueToStoryIds['status-value:error'].length +\n              componentTestStatusValueToStoryIds['status-value:warning'].length || null}\n            <TestStatusIcon status={componentTestStatusIcon} isRunning={isRunning} />\n          </ActionList.Button>\n        </ActionList.Item>\n\n        {!entry && (\n          <ActionList.Item>\n            <ActionList.Action as=\"label\" readOnly={isRunning} ariaLabel={false}>\n              <ActionList.Icon>\n                <Form.Checkbox\n                  name=\"Coverage\"\n                  checked={config.coverage}\n                  disabled={isRunning}\n                  onChange={() =>\n                    setStoreState((s) => ({\n                      ...s,\n                      config: { ...s.config, coverage: !config.coverage },\n                    }))\n                  }\n                />\n              </ActionList.Icon>\n              <ActionList.Text>\n                {watching ? <Muted>Coverage (unavailable)</Muted> : 'Coverage'}\n              </ActionList.Text>\n            </ActionList.Action>\n            {watching ||\n            (currentRun.triggeredBy && !FULL_RUN_TRIGGERS.includes(currentRun.triggeredBy)) ? (\n              <ActionList.Button\n                disabled\n                ariaLabel={\n                  watching\n                    ? `Coverage unavailable in watch mode`\n                    : `Coverage only available after running all tests`\n                }\n              >\n                <InfoIcon />\n              </ActionList.Button>\n            ) : currentRun.coverageSummary ? (\n              <ActionList.Button\n                asChild\n                ariaLabel={\n                  isRunning\n                    ? 'Open coverage report (testing still in progress)'\n                    : `Open coverage report (${currentRun.coverageSummary.percentage}% coverage)`\n                }\n              >\n                <a href=\"/coverage/index.html\" target=\"_blank\">\n                  {currentRun.coverageSummary.percentage}%\n                  <TestStatusIcon\n                    isRunning={isRunning}\n                    percentage={currentRun.coverageSummary.percentage}\n                    status={currentRun.coverageSummary.status}\n                  />\n                </a>\n              </ActionList.Button>\n            ) : (\n              <ActionList.Button\n                disabled\n                ariaLabel={\n                  isRunning\n                    ? 'Coverage unavailable, testing still in progress'\n                    : fatalError\n                      ? 'Coverage unavailable, component tests crashed'\n                      : 'Coverage unavailable, run tests first'\n                }\n              >\n                <TestStatusIcon\n                  isRunning={isRunning}\n                  status={fatalError ? 'critical' : 'unknown'}\n                />\n              </ActionList.Button>\n            )}\n          </ActionList.Item>\n        )}\n\n        {hasA11yAddon && (\n          <ActionList.Item>\n            {entry ? (\n              <ActionList.Text>Accessibility</ActionList.Text>\n            ) : (\n              <ActionList.Action as=\"label\" readOnly={isRunning} ariaLabel={false}>\n                <ActionList.Icon>\n                  <Form.Checkbox\n                    name=\"Accessibility\"\n                    checked={config.a11y}\n                    disabled={isRunning}\n                    onChange={() =>\n                      setStoreState((s) => ({\n                        ...s,\n                        config: { ...s.config, a11y: !config.a11y },\n                      }))\n                    }\n                  />\n                </ActionList.Icon>\n                <ActionList.Text>Accessibility</ActionList.Text>\n              </ActionList.Action>\n            )}\n            <ActionList.Button\n              ariaLabel={a11yStatusLabel}\n              disabled={\n                a11yStatusValueToStoryIds['status-value:error'].length === 0 &&\n                a11yStatusValueToStoryIds['status-value:warning'].length === 0 &&\n                a11yStatusValueToStoryIds['status-value:success'].length === 0\n              }\n              onClick={() => {\n                openPanel({\n                  api,\n                  entryId:\n                    a11yStatusValueToStoryIds['status-value:error'][0] ??\n                    a11yStatusValueToStoryIds['status-value:warning'][0] ??\n                    a11yStatusValueToStoryIds['status-value:success'][0] ??\n                    entry?.id,\n                  panelId: A11Y_PANEL_ID,\n                });\n              }}\n            >\n              {a11yStatusValueToStoryIds['status-value:error'].length +\n                a11yStatusValueToStoryIds['status-value:warning'].length || null}\n              <TestStatusIcon status={a11yStatusIcon} isRunning={isRunning} />\n            </ActionList.Button>\n          </ActionList.Item>\n        )}\n      </StyledActionList>\n    </Container>\n  );\n};\n"
  },
  {
    "path": "code/addons/vitest/src/components/TestStatusIcon.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { TestStatusIcon } from './TestStatusIcon.tsx';\n\nconst meta = {\n  component: TestStatusIcon,\n  args: {\n    isRunning: false,\n  },\n  render: (args) => (\n    <div style={{ display: 'flex', gap: 12 }}>\n      <TestStatusIcon {...args} />\n      <TestStatusIcon {...args} isRunning />\n    </div>\n  ),\n} satisfies Meta<typeof TestStatusIcon>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Unknown: Story = {\n  args: {\n    status: 'unknown',\n  },\n};\n\nexport const Positive: Story = {\n  args: {\n    status: 'positive',\n  },\n};\n\nexport const Warning: Story = {\n  args: {\n    status: 'warning',\n  },\n};\n\nexport const Negative: Story = {\n  args: {\n    status: 'negative',\n  },\n};\n\nexport const Critical: Story = {\n  args: {\n    status: 'critical',\n  },\n};\n\nexport const UnknownPercentage: Story = {\n  args: {\n    status: 'unknown',\n    percentage: 50,\n  },\n};\n\nexport const PositivePercentage: Story = {\n  args: {\n    status: 'positive',\n    percentage: 60,\n  },\n};\n\nexport const WarningPercentage: Story = {\n  args: {\n    status: 'warning',\n    percentage: 40,\n  },\n};\n\nexport const NegativePercentage: Story = {\n  args: {\n    status: 'negative',\n    percentage: 30,\n  },\n};\n"
  },
  {
    "path": "code/addons/vitest/src/components/TestStatusIcon.tsx",
    "content": "import { styled } from 'storybook/theming';\n\nexport const TestStatusIcon = styled.div<{\n  isRunning: boolean;\n  status: 'positive' | 'warning' | 'negative' | 'critical' | 'unknown';\n  percentage?: number;\n}>(\n  ({ percentage }) => ({\n    width: percentage ? 12 : 6,\n    height: percentage ? 12 : 6,\n    margin: percentage ? 1 : 4,\n    background: percentage\n      ? `conic-gradient(var(--status-color) ${percentage}%, var(--status-background) ${percentage + 1}%)`\n      : 'var(--status-color)',\n    borderRadius: '50%',\n  }),\n  ({ isRunning, theme }) =>\n    isRunning && {\n      animation: `${theme.animation.glow} 1.5s ease-in-out infinite`,\n    },\n  ({ status, theme }) =>\n    status === 'positive' && {\n      '--status-color': theme.color.positive,\n      '--status-background': `${theme.color.positive}66`,\n    },\n  ({ status, theme }) =>\n    status === 'warning' && {\n      '--status-color': theme.color.gold,\n      '--status-background': `${theme.color.gold}66`,\n    },\n  ({ status, theme }) =>\n    status === 'negative' && {\n      '--status-color': theme.color.negative,\n      '--status-background': `${theme.color.negative}66`,\n    },\n  ({ status, theme }) =>\n    status === 'critical' && {\n      '--status-color': theme.color.defaultText,\n      '--status-background': `${theme.color.defaultText}66`,\n    },\n  ({ status, theme }) =>\n    status === 'unknown' && {\n      '--status-color': theme.textMutedColor,\n      '--status-background': `${theme.textMutedColor}66`,\n    }\n);\n"
  },
  {
    "path": "code/addons/vitest/src/constants.ts",
    "content": "import type { StoreOptions } from 'storybook/internal/types';\n\nimport type { CurrentRun, RunTrigger, StoreState } from './types.ts';\n\nexport { PANEL_ID as COMPONENT_TESTING_PANEL_ID } from '../../../core/src/component-testing/constants.ts';\nexport {\n  PANEL_ID as A11Y_PANEL_ID,\n  ADDON_ID as A11Y_ADDON_ID,\n} from '../../../addons/a11y/src/constants.ts';\n\nexport const ADDON_ID = 'storybook/test';\nexport const TEST_PROVIDER_ID = `${ADDON_ID}/test-provider`;\nexport const STORYBOOK_ADDON_TEST_CHANNEL = `${ADDON_ID}/channel`;\n\nexport const TUTORIAL_VIDEO_LINK = 'https://youtu.be/Waht9qq7AoA';\nexport const DOCUMENTATION_LINK = 'writing-tests/integrations/vitest-addon';\nexport const DOCUMENTATION_FATAL_ERROR_LINK = `${DOCUMENTATION_LINK}#what-happens-if-vitest-itself-has-an-error`;\n\nexport const COVERAGE_DIRECTORY = 'coverage';\n\nexport const storeOptions = {\n  id: ADDON_ID,\n  initialState: {\n    config: {\n      coverage: false,\n      a11y: false,\n    },\n    watching: false,\n    cancelling: false,\n    fatalError: undefined,\n    index: { entries: {}, v: 5 },\n    previewAnnotations: [],\n    currentRun: {\n      triggeredBy: undefined,\n      config: {\n        coverage: false,\n        a11y: false,\n      },\n      componentTestStatuses: [],\n      a11yStatuses: [],\n      a11yReports: {},\n      componentTestCount: {\n        success: 0,\n        error: 0,\n      },\n      a11yCount: {\n        success: 0,\n        warning: 0,\n        error: 0,\n      },\n      storyIds: undefined,\n      totalTestCount: undefined,\n      startedAt: undefined,\n      finishedAt: undefined,\n      unhandledErrors: [],\n      coverageSummary: undefined,\n    },\n  },\n} satisfies StoreOptions<StoreState>;\n\nexport const FULL_RUN_TRIGGERS: RunTrigger[] = ['global', 'run-all'] as const;\n\nexport const STORE_CHANNEL_EVENT_NAME = `UNIVERSAL_STORE:${storeOptions.id}`;\nexport const STATUS_STORE_CHANNEL_EVENT_NAME = 'UNIVERSAL_STORE:storybook/status';\nexport const TEST_PROVIDER_STORE_CHANNEL_EVENT_NAME = 'UNIVERSAL_STORE:storybook/test-provider';\n\nexport const STATUS_TYPE_ID_COMPONENT_TEST = 'storybook/component-test';\nexport const STATUS_TYPE_ID_A11Y = 'storybook/a11y';\n\n// Channel event names for programmatic test triggering\nexport const TRIGGER_TEST_RUN_REQUEST = `${ADDON_ID}/trigger-test-run-request`;\nexport const TRIGGER_TEST_RUN_RESPONSE = `${ADDON_ID}/trigger-test-run-response`;\n\nexport type TriggerTestRunRequestPayload = {\n  requestId: string;\n  actor: string;\n  storyIds?: string[];\n  config?: Partial<StoreState['config']>;\n};\n\nexport type TestRunResult = CurrentRun;\n\nexport type TriggerTestRunResponsePayload = {\n  requestId: string;\n  status: 'completed' | 'error' | 'cancelled';\n  result?: TestRunResult;\n  error?: {\n    message: string;\n    error?: import('./types').ErrorLike;\n  };\n};\n"
  },
  {
    "path": "code/addons/vitest/src/index.ts",
    "content": "import { definePreviewAddon } from 'storybook/internal/csf';\n\nexport default () => definePreviewAddon({});\n"
  },
  {
    "path": "code/addons/vitest/src/logger.ts",
    "content": "import { logger } from 'storybook/internal/node-logger';\n\nimport picocolors from 'picocolors';\n\nimport { ADDON_ID } from './constants.ts';\n\nexport const log = (message: any) => {\n  logger.log(\n    `${picocolors.magenta(ADDON_ID)}: ${message\n      .toString()\n      // Counteracts the default logging behavior of the clack prompt library\n      .replaceAll(/(│\\n|│  )/g, '')\n      .trim()}`\n  );\n};\n"
  },
  {
    "path": "code/addons/vitest/src/manager-store.mock.ts",
    "content": "import type {\n  StatusStoreByTypeId,\n  TestProviderState,\n  TestProviderStoreById,\n} from 'storybook/internal/types';\n\nimport { experimental_MockUniversalStore } from 'storybook/manager-api';\nimport * as testUtils from 'storybook/test';\n\nimport {\n  ADDON_ID,\n  STATUS_TYPE_ID_A11Y,\n  STATUS_TYPE_ID_COMPONENT_TEST,\n  storeOptions,\n} from './constants.ts';\n\nexport const store = testUtils.mocked(new experimental_MockUniversalStore(storeOptions, testUtils));\n\nexport const componentTestStatusStore: StatusStoreByTypeId = {\n  typeId: STATUS_TYPE_ID_COMPONENT_TEST,\n  getAll: testUtils.fn(() => ({})),\n  set: testUtils.fn(),\n  onAllStatusChange: testUtils.fn(() => () => {}),\n  onSelect: testUtils.fn(() => () => {}),\n  unset: testUtils.fn(),\n};\n\nexport const a11yStatusStore: StatusStoreByTypeId = {\n  typeId: STATUS_TYPE_ID_A11Y,\n  getAll: testUtils.fn(() => ({})),\n  set: testUtils.fn(),\n  onAllStatusChange: testUtils.fn(() => () => {}),\n  onSelect: testUtils.fn(() => () => {}),\n  unset: testUtils.fn(),\n};\n\nexport const testProviderStore: TestProviderStoreById = {\n  testProviderId: ADDON_ID,\n  getState: testUtils.fn(() => 'test-provider-state:pending' as TestProviderState),\n  setState: testUtils.fn(),\n  runWithState: testUtils.fn(),\n  settingsChanged: testUtils.fn(),\n  onRunAll: testUtils.fn(() => () => {}),\n  onClearAll: testUtils.fn(() => () => {}),\n};\n"
  },
  {
    "path": "code/addons/vitest/src/manager-store.ts",
    "content": "import {\n  experimental_UniversalStore,\n  experimental_getStatusStore,\n  experimental_getTestProviderStore,\n} from 'storybook/manager-api';\n\nimport {\n  ADDON_ID,\n  STATUS_TYPE_ID_A11Y,\n  STATUS_TYPE_ID_COMPONENT_TEST,\n  storeOptions,\n} from './constants.ts';\nimport type { StoreEvent, StoreState } from './types.ts';\n\nexport const store = experimental_UniversalStore.create<StoreState, StoreEvent>({\n  ...storeOptions,\n  leader: (globalThis as any).CONFIG_TYPE === 'PRODUCTION',\n});\n\nexport const componentTestStatusStore = experimental_getStatusStore(STATUS_TYPE_ID_COMPONENT_TEST);\nexport const a11yStatusStore = experimental_getStatusStore(STATUS_TYPE_ID_A11Y);\nexport const testProviderStore = experimental_getTestProviderStore(ADDON_ID);\n"
  },
  {
    "path": "code/addons/vitest/src/manager.tsx",
    "content": "import React, { useState } from 'react';\n\nimport { Addon_TypesEnum, SupportedBuilder } from 'storybook/internal/types';\n\nimport {\n  a11yStatusStore,\n  componentTestStatusStore,\n  store,\n  testProviderStore,\n} from '#manager-store';\nimport { Tag, addons } from 'storybook/manager-api';\n\nimport { GlobalErrorContext, GlobalErrorModal } from './components/GlobalErrorModal.tsx';\nimport { SidebarContextMenu } from './components/SidebarContextMenu.tsx';\nimport { TestProviderRender } from './components/TestProviderRender.tsx';\nimport {\n  A11Y_PANEL_ID,\n  ADDON_ID,\n  COMPONENT_TESTING_PANEL_ID,\n  STORYBOOK_ADDON_TEST_CHANNEL,\n  TEST_PROVIDER_ID,\n} from './constants.ts';\nimport { useTestProvider } from './use-test-provider-state.ts';\n\naddons.register(ADDON_ID, (api) => {\n  if (globalThis.STORYBOOK_BUILDER === SupportedBuilder.VITE) {\n    const openPanel = (panelId: string) => {\n      api.setSelectedPanel(panelId);\n      api.togglePanel(true);\n    };\n    componentTestStatusStore.onSelect(() => {\n      openPanel(COMPONENT_TESTING_PANEL_ID);\n    });\n    a11yStatusStore.onSelect(() => {\n      openPanel(A11Y_PANEL_ID);\n    });\n    testProviderStore.onRunAll(() => {\n      store.send({\n        type: 'TRIGGER_RUN',\n        payload: {\n          triggeredBy: 'run-all',\n        },\n      });\n    });\n    store.subscribe('TEST_RUN_COMPLETED', ({ payload }) => {\n      api.emit(STORYBOOK_ADDON_TEST_CHANNEL, { type: 'test-run-completed', payload });\n    });\n\n    addons.add(TEST_PROVIDER_ID, {\n      type: Addon_TypesEnum.experimental_TEST_PROVIDER,\n      render: () => {\n        const [isModalOpen, setModalOpen] = useState(false);\n        const {\n          storeState,\n          setStoreState,\n          testProviderState,\n          componentTestStatusValueToStoryIds,\n          a11yStatusValueToStoryIds,\n          isSettingsUpdated,\n        } = useTestProvider(api);\n        return (\n          <GlobalErrorContext.Provider value={{ isModalOpen, setModalOpen }}>\n            <TestProviderRender\n              api={api}\n              storeState={storeState}\n              setStoreState={setStoreState}\n              isSettingsUpdated={isSettingsUpdated}\n              testProviderState={testProviderState}\n              componentTestStatusValueToStoryIds={componentTestStatusValueToStoryIds}\n              a11yStatusValueToStoryIds={a11yStatusValueToStoryIds}\n            />\n            <GlobalErrorModal\n              storeState={storeState}\n              onRerun={() => {\n                setModalOpen(false);\n                store.send({\n                  type: 'TRIGGER_RUN',\n                  payload: {\n                    triggeredBy: 'global',\n                  },\n                });\n              }}\n            />\n          </GlobalErrorContext.Provider>\n        );\n      },\n\n      sidebarContextMenu: ({ context }) => {\n        if (context.type === 'docs') {\n          return null;\n        }\n        if (context.type === 'story' && !context.tags.includes(Tag.TEST)) {\n          return null;\n        }\n        return <SidebarContextMenu context={context} api={api} />;\n      },\n    });\n  }\n});\n"
  },
  {
    "path": "code/addons/vitest/src/node/boot-test-runner.test.ts",
    "content": "import { join } from 'node:path';\n\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { Channel, type ChannelTransport } from 'storybook/internal/channels';\nimport { executeNodeCommand } from 'storybook/internal/common';\nimport type { Options } from 'storybook/internal/types';\n\nimport { storeOptions } from '../constants.ts';\nimport { log } from '../logger.ts';\nimport type { StoreEvent } from '../types.ts';\nimport type { StoreState } from '../types.ts';\nimport { killTestRunner, runTestRunner } from './boot-test-runner.ts';\n\nlet stdout: (chunk: Buffer | string) => void;\nlet stderr: (chunk: Buffer | string) => void;\nlet message: (event: { type: string; args?: unknown[]; payload?: unknown }) => void;\n\nconst child = vi.hoisted(() => ({\n  stdout: {\n    on: vi.fn((event: string, callback: (chunk: Buffer | string) => void) => {\n      if (event === 'data') {\n        stdout = callback;\n      }\n    }),\n  },\n  stderr: {\n    on: vi.fn((event: string, callback: (chunk: Buffer | string) => void) => {\n      if (event === 'data') {\n        stderr = callback;\n      }\n    }),\n  },\n  on: vi.fn(\n    (\n      event: string,\n      callback: (event: { type: string; args?: unknown[]; payload?: unknown }) => void\n    ) => {\n      if (event === 'message') {\n        message = callback;\n      }\n    }\n  ),\n  send: vi.fn(),\n  kill: vi.fn(),\n}));\n\nvi.mock('storybook/internal/common', async (importOriginal) => {\n  const actual = await importOriginal<typeof import('storybook/internal/common')>();\n  return {\n    ...actual,\n    executeNodeCommand: vi.fn().mockReturnValue(child),\n  };\n});\n\nvi.mock('../logger', () => ({\n  log: vi.fn(),\n}));\n\nvi.mock('../../../../core/src/shared/utils/module', () => ({\n  importMetaResolve: vi\n    .fn()\n    .mockImplementation(() => 'file://' + join(__dirname, '..', '..', 'dist', 'node', 'vitest.js')),\n}));\n\nvi.mock('storybook/internal/core-server', async (importOriginal) => {\n  const actual = await importOriginal<typeof import('storybook/internal/core-server')>();\n  return {\n    ...actual,\n    internal_universalStatusStore: {\n      subscribe: vi.fn(() => () => {}),\n    },\n    internal_universalTestProviderStore: {\n      subscribe: vi.fn(() => () => {}),\n    },\n  };\n});\n\nbeforeEach(() => {\n  vi.useFakeTimers();\n  killTestRunner();\n});\n\nafterEach(() => {\n  vi.useRealTimers();\n});\n\nconst transport = { setHandler: vi.fn(), send: vi.fn() } satisfies ChannelTransport;\nconst mockChannel = new Channel({ transport });\n\ndescribe('bootTestRunner', () => {\n  let mockStore: InstanceType<\n    typeof import('storybook/internal/core-server').experimental_MockUniversalStore<\n      StoreState,\n      StoreEvent\n    >\n  >;\n  const mockOptions = {\n    configDir: '.storybook',\n  } as Options;\n\n  beforeEach(async () => {\n    const { experimental_MockUniversalStore: MockUniversalStore } =\n      await import('storybook/internal/core-server');\n    mockStore = new MockUniversalStore<StoreState, StoreEvent>(storeOptions);\n    vi.mocked(executeNodeCommand).mockClear();\n    vi.mocked(log).mockClear();\n    child.send.mockClear();\n  });\n\n  it('should execute vitest.js', async () => {\n    const promise = runTestRunner({ channel: mockChannel, store: mockStore, options: mockOptions });\n    expect(vi.mocked(executeNodeCommand)).toHaveBeenCalledWith({\n      scriptPath: expect.stringMatching(/vitest\\.js$/),\n      options: {\n        env: {\n          NODE_ENV: 'test',\n          TEST: 'true',\n          VITEST: 'true',\n          VITEST_CHILD_PROCESS: 'true',\n          STORYBOOK_CONFIG_DIR: '.storybook',\n        },\n        extendEnv: true,\n      },\n    });\n    message({ type: 'ready' });\n    await promise;\n  });\n\n  it('should log stdout and stderr', async () => {\n    const promise = runTestRunner({ channel: mockChannel, store: mockStore, options: mockOptions });\n    stdout('foo');\n    stderr('bar');\n    message({ type: 'ready' });\n    await promise;\n    expect(vi.mocked(log)).toHaveBeenCalledWith('foo');\n    expect(vi.mocked(log)).toHaveBeenCalledWith('bar');\n  });\n\n  it('should wait for vitest to be ready', async () => {\n    let ready;\n    const promise = runTestRunner({\n      channel: mockChannel,\n      store: mockStore,\n      options: mockOptions,\n    }).then(() => {\n      ready = true;\n    });\n    expect(ready).toBeUndefined();\n    message({ type: 'ready' });\n    await expect(promise).resolves.toBeUndefined();\n    expect(ready).toBe(true);\n  });\n\n  it('should abort if vitest doesn’t become ready in time', async () => {\n    const promise = runTestRunner({\n      channel: mockChannel,\n      store: mockStore,\n      options: mockOptions,\n    });\n    vi.advanceTimersByTime(30001);\n    await expect(promise).rejects.toThrow();\n  });\n\n  it('should forward universal store events', async () => {\n    const promise = runTestRunner({ channel: mockChannel, store: mockStore, options: mockOptions });\n    message({ type: 'ready' });\n    await promise;\n\n    mockStore.send({ type: 'TRIGGER_RUN', payload: { triggeredBy: 'global', storyIds: ['foo'] } });\n    expect(child.send).toHaveBeenCalledWith({\n      args: [\n        {\n          event: {\n            payload: { storyIds: ['foo'], triggeredBy: 'global' },\n            type: 'TRIGGER_RUN',\n          },\n          eventInfo: {\n            actor: {\n              environment: 'MOCK',\n              id: expect.any(String),\n              type: 'LEADER',\n            },\n          },\n        },\n      ],\n      from: 'server',\n      type: 'UNIVERSAL_STORE:storybook/test',\n    });\n\n    message({ type: 'some-event', args: ['foo'] });\n    expect(mockChannel.last('some-event')).toEqual(['foo']);\n  });\n\n  it('should resend init event', async () => {\n    const promise = runTestRunner({\n      channel: mockChannel,\n      store: mockStore,\n      options: mockOptions,\n      initEvent: 'init',\n      initArgs: ['foo'],\n    });\n    message({ type: 'ready' });\n    await promise;\n    expect(child.send).toHaveBeenCalledWith({\n      args: ['foo'],\n      from: 'server',\n      type: 'init',\n    });\n  });\n});\n"
  },
  {
    "path": "code/addons/vitest/src/node/boot-test-runner.ts",
    "content": "import { type ChildProcess } from 'node:child_process';\nimport { fileURLToPath } from 'node:url';\n\nimport type { Channel } from 'storybook/internal/channels';\nimport { executeNodeCommand } from 'storybook/internal/common';\nimport {\n  internal_universalStatusStore,\n  internal_universalTestProviderStore,\n} from 'storybook/internal/core-server';\nimport type { EventInfo, Options } from 'storybook/internal/types';\n\nimport { normalize } from 'pathe';\n\nimport { importMetaResolve } from '../../../../core/src/shared/utils/module.ts';\nimport {\n  STATUS_STORE_CHANNEL_EVENT_NAME,\n  STORE_CHANNEL_EVENT_NAME,\n  TEST_PROVIDER_STORE_CHANNEL_EVENT_NAME,\n} from '../constants.ts';\nimport { log } from '../logger.ts';\nimport { errorToErrorLike } from '../utils.ts';\nimport type { Store } from '../types.ts';\n\nconst MAX_START_TIME = 30000;\n\n// This path is a bit confusing, but essentially `boot-test-runner` gets bundled into the preset bundle\n// which is at the root. Then, from the root, we want to load `node/vitest.mjs`\nconst vitestModulePath = fileURLToPath(importMetaResolve('@storybook/addon-vitest/vitest'));\n\n// Events that were triggered before Vitest was ready are queued up and resent once it's ready\nconst eventQueue: { type: string; args?: any[] }[] = [];\n\nlet child: null | ChildProcess;\nlet ready = false;\nlet unsubscribeStore: () => void;\nlet unsubscribeStatusStore: () => void;\nlet unsubscribeTestProviderStore: () => void;\n\nconst forwardUniversalStoreEvent =\n  (storeEventName: string) => (event: any, eventInfo: EventInfo) => {\n    child?.send({\n      type: storeEventName,\n      args: [{ event, eventInfo }],\n      from: 'server',\n    });\n  };\n\nconst bootTestRunner = async ({\n  channel,\n  store,\n  options,\n}: {\n  channel: Channel;\n  store: Store;\n  options: Options;\n}) => {\n  let stderr: string[] = [];\n  const killChild = () => {\n    unsubscribeStore?.();\n    unsubscribeStatusStore?.();\n    unsubscribeTestProviderStore?.();\n    child?.kill();\n    child = null;\n  };\n\n  store.subscribe('FATAL_ERROR', killChild);\n\n  const exit = (code = 0) => {\n    killChild();\n    eventQueue.length = 0;\n    process.exit(code);\n  };\n\n  process.on('exit', exit);\n  process.on('SIGINT', () => exit(0));\n  process.on('SIGTERM', () => exit(0));\n\n  const startChildProcess = () =>\n    new Promise<void>((resolve, reject) => {\n      child = executeNodeCommand({\n        scriptPath: vitestModulePath,\n        options: {\n          env: {\n            VITEST: 'true',\n            TEST: 'true',\n            VITEST_CHILD_PROCESS: 'true',\n            NODE_ENV: process.env.NODE_ENV ?? 'test',\n            STORYBOOK_CONFIG_DIR: normalize(options.configDir),\n          },\n          extendEnv: true,\n        },\n      });\n      stderr = [];\n\n      child.stdout?.on('data', log);\n      child.stderr?.on('data', (data) => {\n        // Ignore deprecation warnings which appear in yellow ANSI color\n        if (!data.toString().match(/^\\u001B\\[33m/)) {\n          log(data);\n          stderr.push(data.toString());\n        }\n      });\n\n      unsubscribeStore = store.subscribe(forwardUniversalStoreEvent(STORE_CHANNEL_EVENT_NAME));\n      unsubscribeStatusStore = internal_universalStatusStore.subscribe(\n        forwardUniversalStoreEvent(STATUS_STORE_CHANNEL_EVENT_NAME)\n      );\n      unsubscribeTestProviderStore = internal_universalTestProviderStore.subscribe(\n        forwardUniversalStoreEvent(TEST_PROVIDER_STORE_CHANNEL_EVENT_NAME)\n      );\n\n      child.on('message', (event: any) => {\n        if (event.type === 'ready') {\n          // Resend events that triggered (during) the boot sequence, now that Vitest is ready\n          while (eventQueue.length) {\n            const { type, args } = eventQueue.shift()!;\n            child?.send({ type, args, from: 'server' });\n          }\n          resolve();\n        } else if (event.type === 'uncaught-error') {\n          store.send({\n            type: 'FATAL_ERROR',\n            payload: event.payload,\n          });\n          reject();\n        } else {\n          channel.emit(event.type, ...event.args);\n        }\n      });\n    });\n\n  const timeout = new Promise((_, reject) =>\n    setTimeout(\n      reject,\n      MAX_START_TIME,\n      // eslint-disable-next-line local-rules/no-uncategorized-errors\n      new Error(\n        `Aborting test runner process because it took longer than ${MAX_START_TIME / 1000} seconds to start.`\n      )\n    )\n  );\n\n  await Promise.race([startChildProcess(), timeout]).catch((error) => {\n    store.send({\n      type: 'FATAL_ERROR',\n      payload: {\n        message: 'Failed to start test runner process',\n        error: error instanceof Error ? errorToErrorLike(error) : { message: String(error) },\n      },\n    });\n    eventQueue.length = 0;\n    throw error;\n  });\n};\n\nexport const runTestRunner = async ({\n  channel,\n  store,\n  initEvent,\n  initArgs,\n  options,\n}: {\n  channel: Channel;\n  store: Store;\n  initEvent?: string;\n  initArgs?: any[];\n  options: Options;\n}) => {\n  if (!ready && initEvent) {\n    eventQueue.push({ type: initEvent, args: initArgs });\n  }\n  if (!child) {\n    ready = false;\n    await bootTestRunner({ channel, store, options });\n    ready = true;\n  }\n};\n\nexport const killTestRunner = () => {\n  if (child) {\n    child.kill();\n    child = null;\n  }\n  ready = false;\n  eventQueue.length = 0;\n};\n"
  },
  {
    "path": "code/addons/vitest/src/node/coverage-reporter.ts",
    "content": "import type { ResolvedCoverageOptions } from 'vitest/node';\n\nimport type { ReportNode, Visitor } from 'istanbul-lib-report';\nimport { ReportBase } from 'istanbul-lib-report';\n\nimport type { StoreState } from '../types.ts';\nimport type { TestManager } from './test-manager.ts';\n\nexport type StorybookCoverageReporterOptions = {\n  testManager: TestManager;\n  coverageOptions: ResolvedCoverageOptions<'v8'> | undefined;\n};\n\nclass StorybookCoverageReporter extends ReportBase implements Partial<Visitor> {\n  #testManager: StorybookCoverageReporterOptions['testManager'];\n\n  #coverageOptions: StorybookCoverageReporterOptions['coverageOptions'];\n\n  constructor(opts: StorybookCoverageReporterOptions) {\n    super();\n    this.#testManager = opts.testManager;\n    this.#coverageOptions = opts.coverageOptions;\n  }\n\n  onSummary(node: ReportNode) {\n    if (!node.isRoot()) {\n      return;\n    }\n    const rawCoverageSummary = node.getCoverageSummary(false);\n\n    const percentage = Math.round(rawCoverageSummary.data.statements.pct);\n\n    // Fallback to Vitest's default watermarks https://vitest.dev/config/#coverage-watermarks\n    const [lowWatermark = 50, highWatermark = 80] =\n      this.#coverageOptions?.watermarks?.statements ?? [];\n\n    const coverageSummary: StoreState['currentRun']['coverageSummary'] = {\n      percentage,\n      status:\n        percentage < lowWatermark\n          ? 'negative'\n          : percentage < highWatermark\n            ? 'warning'\n            : 'positive',\n    };\n    this.#testManager.onCoverageCollected(coverageSummary);\n  }\n}\n\n/**\n * This is exported weirdly because the coverage tool loading this uses `Cont = require(name)`. So\n * it doesn't support a default export, it has to be the \"root\" export as CJS\n *\n * @see https://nodejs.org/docs/latest-v20.x/api/modules.html#loading-ecmascript-modules-using-require\n */\nexport { StorybookCoverageReporter as 'module.exports' };\n"
  },
  {
    "path": "code/addons/vitest/src/node/reporter.ts",
    "content": "import type { SerializedError } from 'vitest';\nimport type { TestCase, TestModule, Vitest } from 'vitest/node';\nimport { type Reporter } from 'vitest/reporters';\n\nimport type { TaskMeta } from '@vitest/runner';\nimport type { Report } from 'storybook/preview-api';\n\nimport type { VitestError } from '../types.ts';\nimport type { TestManager } from './test-manager.ts';\n\nexport class StorybookReporter implements Reporter {\n  ctx!: Vitest;\n\n  constructor(public testManager: TestManager) {}\n\n  onInit(ctx: Vitest) {\n    this.ctx = ctx;\n  }\n\n  onTestCaseResult(testCase: TestCase) {\n    const { storyId, reports } = testCase.meta() as TaskMeta &\n      Partial<{ storyId: string; reports: Report[] }>;\n\n    const testResult = testCase.result();\n    this.testManager.onTestCaseResult({\n      storyId,\n      testResult,\n      reports,\n    });\n  }\n\n  async onTestRunEnd(\n    testModules: readonly TestModule[],\n    unhandledErrors: readonly SerializedError[]\n  ) {\n    const totalTestCount = testModules.flatMap((t) =>\n      Array.from(t.children.allTests('passed')).concat(Array.from(t.children.allTests('failed')))\n    ).length;\n    const testModulesErrors = testModules.flatMap((t) => t.errors());\n    const serializedErrors = unhandledErrors.concat(testModulesErrors).map((e) => {\n      return {\n        ...e,\n        name: e.name,\n        message: e.message,\n        stack: e.stack?.replace(e.message, ''),\n        cause: e.cause,\n      };\n    });\n    this.testManager.onTestRunEnd({\n      totalTestCount,\n      unhandledErrors: serializedErrors as unknown as VitestError[],\n    });\n\n    this.clearVitestState();\n  }\n\n  // TODO: Clearing the whole internal state of Vitest might be too aggressive\n  async clearVitestState() {\n    this.ctx.state.filesMap.clear();\n    this.ctx.state.pathsSet.clear();\n    this.ctx.state.idMap.clear();\n    this.ctx.state.errorsSet.clear();\n    // TODO: Remove this once we don't support Vitest < 4\n    // @ts-expect-error processTimeoutCauses does not exist in Vitest 4\n    this.ctx.state.processTimeoutCauses?.clear();\n  }\n}\n"
  },
  {
    "path": "code/addons/vitest/src/node/test-manager.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\nimport type { TestResult } from 'vitest/node';\n\nimport { Tag, experimental_MockUniversalStore } from 'storybook/internal/core-server';\nimport type {\n  Options,\n  StatusStoreByTypeId,\n  StoryIndex,\n  TestProviderStoreById,\n} from 'storybook/internal/types';\n\nimport path from 'pathe';\n\nimport { STATUS_TYPE_ID_A11Y, STATUS_TYPE_ID_COMPONENT_TEST, storeOptions } from '../constants.ts';\nimport type { StoreEvent, StoreState } from '../types.ts';\nimport { TestManager, type TestManagerOptions } from './test-manager.ts';\nimport { DOUBLE_SPACES } from './vitest-manager.ts';\n\nconst setTestNamePattern = vi.hoisted(() => vi.fn());\nconst vitest = vi.hoisted(() => ({\n  projects: [{}],\n  init: vi.fn(),\n  close: vi.fn(),\n  onCancel: vi.fn(),\n  runTestSpecifications: vi.fn(),\n  cancelCurrentRun: vi.fn(),\n  globTestSpecifications: vi.fn(),\n  getModuleProjects: vi.fn(() => []),\n  setGlobalTestNamePattern: setTestNamePattern,\n  vite: {\n    watcher: {\n      removeAllListeners: vi.fn(),\n      on: vi.fn(),\n    },\n    moduleGraph: {\n      getModulesByFile: () => [],\n      invalidateModule: vi.fn(),\n    },\n  },\n  config: {\n    coverage: { enabled: false },\n  },\n}));\n\nconst mockCreateVitest = vi.fn();\n\nvi.mock('vitest/node', () => ({\n  createVitest: mockCreateVitest,\n}));\n\n// Use the mock function directly\nconst createVitest = mockCreateVitest;\n\nbeforeEach(() => {\n  createVitest.mockResolvedValue(vitest);\n});\n\nconst mockIndex = {\n  v: 5,\n  entries: {\n    'story--one': {\n      type: 'story',\n      subtype: 'story',\n      id: 'story--one',\n      name: 'One',\n      title: 'story/one',\n      importPath: 'path/to/file',\n      tags: [Tag.TEST],\n    },\n    'another--one': {\n      type: 'story',\n      subtype: 'story',\n      id: 'another--one',\n      name: 'One',\n      title: 'another/one',\n      importPath: 'path/to/another/file',\n      tags: [Tag.TEST],\n    },\n    'story--two': {\n      type: 'story',\n      subtype: 'story',\n      id: 'story--two',\n      name: 'Two',\n      title: 'story/two',\n      importPath: 'path/to/file',\n      tags: [Tag.TEST],\n    },\n    'another--two': {\n      type: 'story',\n      subtype: 'story',\n      id: 'another--two',\n      name: 'Two B',\n      title: 'another/two',\n      importPath: 'path/to/another/file',\n      tags: [Tag.TEST],\n    },\n    'parent--story': {\n      type: 'story',\n      subtype: 'story',\n      id: 'parent--story',\n      name: 'Parent story',\n      title: 'parent/story',\n      importPath: 'path/to/parent/file',\n      tags: [Tag.TEST],\n    },\n    'parent--story:test': {\n      type: 'story',\n      subtype: Tag.TEST,\n      id: 'parent--story:test',\n      name: 'Test name',\n      title: 'parent/story',\n      parent: 'parent--story',\n      importPath: 'path/to/parent/file',\n      tags: [Tag.TEST, Tag.TEST_FN],\n    },\n  },\n} as StoryIndex;\n\nconst mockStore = new experimental_MockUniversalStore<StoreState, StoreEvent>(\n  {\n    ...storeOptions,\n    initialState: {\n      ...storeOptions.initialState,\n      index: mockIndex,\n    },\n  },\n  vi\n);\nconst mockComponentTestStatusStore: StatusStoreByTypeId = {\n  set: vi.fn(),\n  getAll: vi.fn(),\n  onAllStatusChange: vi.fn(),\n  onSelect: vi.fn(),\n  unset: vi.fn(),\n  typeId: STATUS_TYPE_ID_COMPONENT_TEST,\n};\nconst mockA11yStatusStore: StatusStoreByTypeId = {\n  set: vi.fn(),\n  getAll: vi.fn(),\n  onAllStatusChange: vi.fn(),\n  onSelect: vi.fn(),\n  unset: vi.fn(),\n  typeId: STATUS_TYPE_ID_A11Y,\n};\nconst mockTestProviderStore: TestProviderStoreById = {\n  getState: vi.fn(),\n  setState: vi.fn(),\n  settingsChanged: vi.fn(),\n  onRunAll: vi.fn(),\n  onClearAll: vi.fn(),\n  runWithState: vi.fn((callback) => callback()),\n  testProviderId: 'test-provider-id',\n};\n\nconst tests = [\n  {\n    project: { config: { env: { __STORYBOOK_URL__: 'http://localhost:6006' } } },\n    moduleId: path.join(process.cwd(), 'path/to/file'),\n  },\n  {\n    project: { config: { env: { __STORYBOOK_URL__: 'http://localhost:6006' } } },\n    moduleId: path.join(process.cwd(), 'path/to/another/file'),\n  },\n];\n\nconst options: TestManagerOptions = {\n  store: mockStore,\n  componentTestStatusStore: mockComponentTestStatusStore,\n  a11yStatusStore: mockA11yStatusStore,\n  testProviderStore: mockTestProviderStore,\n  onError: (message, error) => {\n    throw error;\n  },\n  onReady: vi.fn(),\n  storybookOptions: {\n    configDir: '.storybook',\n  } as Options,\n};\n\ndescribe('TestManager', () => {\n  it('should create a vitest instance', async () => {\n    new TestManager(options);\n    await vi.waitFor(() => {\n      expect(createVitest).toHaveBeenCalled();\n    });\n  });\n\n  it('should call onReady callback', async () => {\n    new TestManager(options);\n    await vi.waitFor(() => {\n      expect(options.onReady).toHaveBeenCalled();\n    });\n  });\n\n  it('TestManager.start should start vitest and resolve when ready', async () => {\n    const testManager = await TestManager.start(options);\n\n    expect(testManager).toBeInstanceOf(TestManager);\n    expect(createVitest).toHaveBeenCalled();\n  });\n\n  it('should handle run request', async () => {\n    vitest.globTestSpecifications.mockImplementation(() => tests);\n    const testManager = await TestManager.start(options);\n    expect(createVitest).toHaveBeenCalledTimes(1);\n\n    await testManager.handleTriggerRunEvent({\n      type: 'TRIGGER_RUN',\n      payload: {\n        triggeredBy: 'global',\n      },\n    });\n    expect(createVitest).toHaveBeenCalledTimes(1);\n    expect(vitest.runTestSpecifications).toHaveBeenCalledWith(tests, true);\n  });\n\n  it('should filter tests', async () => {\n    vitest.globTestSpecifications.mockImplementation(() => tests);\n    const testManager = await TestManager.start(options);\n\n    await testManager.handleTriggerRunEvent({\n      type: 'TRIGGER_RUN',\n      payload: {\n        storyIds: ['story--one'],\n        triggeredBy: 'global',\n      },\n    });\n    expect(setTestNamePattern).toHaveBeenCalledWith(new RegExp(`^One$`));\n    expect(vitest.runTestSpecifications).toHaveBeenCalledWith(tests.slice(0, 1), true);\n  });\n\n  it('should trigger a single story render test', async () => {\n    vitest.globTestSpecifications.mockImplementation(() => tests);\n    const testManager = await TestManager.start(options);\n\n    await testManager.handleTriggerRunEvent({\n      type: 'TRIGGER_RUN',\n      payload: {\n        storyIds: ['another--one'],\n        triggeredBy: 'global',\n      },\n    });\n    // regex should be exact match of the story name\n    expect(setTestNamePattern).toHaveBeenCalledWith(new RegExp(`^One$`));\n  });\n\n  it('should trigger a single story test', async () => {\n    vitest.globTestSpecifications.mockImplementation(() => tests);\n    const testManager = await TestManager.start(options);\n\n    await testManager.handleTriggerRunEvent({\n      type: 'TRIGGER_RUN',\n      payload: {\n        storyIds: ['parent--story:test'],\n        triggeredBy: 'global',\n      },\n    });\n    // regex should be Parent Story Name + Test Name\n    expect(setTestNamePattern).toHaveBeenCalledWith(\n      new RegExp(`^Parent story${DOUBLE_SPACES} Test name$`)\n    );\n  });\n\n  it('should trigger all tests of a story', async () => {\n    vitest.globTestSpecifications.mockImplementation(() => tests);\n    const testManager = await TestManager.start(options);\n\n    await testManager.handleTriggerRunEvent({\n      type: 'TRIGGER_RUN',\n      payload: {\n        storyIds: ['parent--story'],\n        triggeredBy: 'global',\n      },\n    });\n    expect(setTestNamePattern).toHaveBeenCalledWith(new RegExp(`^Parent story${DOUBLE_SPACES}`));\n  });\n\n  it('should trigger only selected stories in the same file', async () => {\n    vitest.globTestSpecifications.mockImplementation(() => tests);\n    const testManager = await TestManager.start(options);\n\n    await testManager.handleTriggerRunEvent({\n      type: 'TRIGGER_RUN',\n      payload: {\n        storyIds: ['story--one', 'story--two'],\n        triggeredBy: 'global',\n      },\n    });\n\n    expect(vitest.runTestSpecifications).toHaveBeenCalledWith(tests.slice(0, 1), true);\n\n    const regex = setTestNamePattern.mock.calls.find(([arg]) => arg instanceof RegExp)?.[0] as\n      | RegExp\n      | undefined;\n\n    expect(regex).toBeDefined();\n    expect(regex?.test('One')).toBe(true);\n    expect(regex?.test('Two')).toBe(true);\n    expect(regex?.test('Parent story  Test name')).toBe(false);\n  });\n\n  it('should trigger only selected stories across multiple files', async () => {\n    vitest.globTestSpecifications.mockImplementation(() => tests);\n    const testManager = await TestManager.start(options);\n\n    await testManager.handleTriggerRunEvent({\n      type: 'TRIGGER_RUN',\n      payload: {\n        storyIds: ['story--one', 'another--two'],\n        triggeredBy: 'global',\n      },\n    });\n\n    expect(vitest.runTestSpecifications).toHaveBeenCalledWith(tests, true);\n\n    const regex = setTestNamePattern.mock.calls.find(([arg]) => arg instanceof RegExp)?.[0] as\n      | RegExp\n      | undefined;\n\n    expect(regex).toBeDefined();\n    expect(regex?.test('One')).toBe(true);\n    expect(regex?.test('Two B')).toBe(true);\n    expect(regex?.test('Two')).toBe(false);\n  });\n\n  it('should ignore non-requested same-name story results after run', async () => {\n    const testManager = await TestManager.start(options);\n    const passedResult = { state: 'passed', errors: [] } as unknown as TestResult;\n\n    await testManager.runTestsWithState({\n      storyIds: ['story--one', 'another--two'],\n      triggeredBy: 'global',\n      callback: async () => {\n        testManager.onTestCaseResult({\n          storyId: 'story--one',\n          testResult: passedResult,\n        });\n        testManager.onTestCaseResult({\n          storyId: 'another--one',\n          testResult: passedResult,\n        });\n        testManager.onTestRunEnd({\n          totalTestCount: 2,\n          unhandledErrors: [],\n        });\n      },\n    });\n\n    expect(mockComponentTestStatusStore.set).toHaveBeenCalledWith(\n      expect.arrayContaining([expect.objectContaining({ storyId: 'story--one' })])\n    );\n    expect(mockComponentTestStatusStore.set).not.toHaveBeenCalledWith(\n      expect.arrayContaining([expect.objectContaining({ storyId: 'another--one' })])\n    );\n    expect(mockStore.getState().currentRun.totalTestCount).toBe(1);\n  });\n\n  it('should keep child test results when parent story is requested', async () => {\n    const testManager = await TestManager.start(options);\n    const passedResult = { state: 'passed', errors: [] } as unknown as TestResult;\n\n    await testManager.runTestsWithState({\n      storyIds: ['parent--story'],\n      triggeredBy: 'global',\n      callback: async () => {\n        testManager.onTestCaseResult({\n          storyId: 'parent--story:test',\n          testResult: passedResult,\n        });\n        testManager.onTestRunEnd({\n          totalTestCount: 1,\n          unhandledErrors: [],\n        });\n      },\n    });\n\n    expect(mockComponentTestStatusStore.set).toHaveBeenCalledWith(\n      expect.arrayContaining([expect.objectContaining({ storyId: 'parent--story:test' })])\n    );\n    expect(mockStore.getState().currentRun.totalTestCount).toBe(1);\n  });\n\n  it('should restart Vitest before a test run if coverage is enabled', async () => {\n    const testManager = await TestManager.start(options);\n    expect(createVitest).toHaveBeenCalledTimes(1);\n    createVitest.mockClear();\n\n    mockStore.setState((s) => ({ ...s, config: { coverage: true, a11y: false } }));\n\n    await testManager.handleTriggerRunEvent({\n      type: 'TRIGGER_RUN',\n      payload: {\n        triggeredBy: 'global',\n      },\n    });\n\n    expect(createVitest).toHaveBeenCalledTimes(1);\n    expect(createVitest).toHaveBeenCalledWith(\n      Tag.TEST,\n      expect.objectContaining({\n        coverage: expect.objectContaining({ enabled: true }),\n      })\n    );\n  });\n\n  it('should not restart with coverage enabled Vitest before a focused test run', async () => {\n    const testManager = await TestManager.start(options);\n    expect(createVitest).toHaveBeenCalledTimes(1);\n    createVitest.mockClear();\n\n    mockStore.setState((s) => ({ ...s, config: { coverage: true, a11y: false } }));\n\n    await testManager.handleTriggerRunEvent({\n      type: 'TRIGGER_RUN',\n      payload: {\n        storyIds: ['story--one'],\n        triggeredBy: 'global',\n      },\n    });\n\n    expect(createVitest).not.toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "code/addons/vitest/src/node/test-manager.ts",
    "content": "import type { TestResult, TestState } from 'vitest/node';\n\nimport type { experimental_UniversalStore } from 'storybook/internal/core-server';\nimport type {\n  Options,\n  StatusStoreByTypeId,\n  StatusValue,\n  TestProviderStoreById,\n} from 'storybook/internal/types';\n\nimport type { A11yReport } from '@storybook/addon-a11y';\n\nimport { throttle } from 'es-toolkit/function';\nimport type { Report } from 'storybook/preview-api';\n\nimport { STATUS_TYPE_ID_A11Y, STATUS_TYPE_ID_COMPONENT_TEST, storeOptions } from '../constants.ts';\nimport type {\n  CurrentRun,\n  RunTrigger,\n  StoreEvent,\n  StoreState,\n  TriggerRunEvent,\n  VitestError,\n} from '../types.ts';\nimport { errorToErrorLike } from '../utils.ts';\nimport { VitestManager } from './vitest-manager.ts';\n\nexport type TestManagerOptions = {\n  storybookOptions: Options;\n  store: experimental_UniversalStore<StoreState, StoreEvent>;\n  componentTestStatusStore: StatusStoreByTypeId;\n  a11yStatusStore: StatusStoreByTypeId;\n  testProviderStore: TestProviderStoreById;\n  onError?: (message: string, error: Error) => void;\n  onReady?: () => void;\n};\n\nconst testStateToStatusValueMap: Record<TestState | 'warning', StatusValue> = {\n  pending: 'status-value:pending',\n  passed: 'status-value:success',\n  warning: 'status-value:warning',\n  failed: 'status-value:error',\n  skipped: 'status-value:unknown',\n};\n\nexport class TestManager {\n  public store: TestManagerOptions['store'];\n\n  public vitestManager: VitestManager;\n\n  private componentTestStatusStore: TestManagerOptions['componentTestStatusStore'];\n\n  private a11yStatusStore: TestManagerOptions['a11yStatusStore'];\n\n  private testProviderStore: TestManagerOptions['testProviderStore'];\n\n  private onReady?: TestManagerOptions['onReady'];\n\n  public storybookOptions: Options;\n\n  private batchedTestCaseResults: {\n    storyId: string;\n    testResult: TestResult;\n    reports?: Report[];\n  }[] = [];\n\n  constructor(options: TestManagerOptions) {\n    this.store = options.store;\n    this.componentTestStatusStore = options.componentTestStatusStore;\n    this.a11yStatusStore = options.a11yStatusStore;\n    this.testProviderStore = options.testProviderStore;\n    this.onReady = options.onReady;\n    this.storybookOptions = options.storybookOptions;\n\n    this.vitestManager = new VitestManager(this);\n\n    this.store.subscribe('TRIGGER_RUN', this.handleTriggerRunEvent.bind(this));\n    this.store.subscribe('CANCEL_RUN', this.handleCancelEvent.bind(this));\n    this.store\n      .untilReady()\n      .then(() => {\n        return this.vitestManager.startVitest({ coverage: this.store.getState().config.coverage });\n      })\n      .then(() => this.onReady?.())\n      .catch((e) => {\n        this.reportFatalError('Failed to start Vitest', e);\n      });\n  }\n\n  async handleTriggerRunEvent(event: TriggerRunEvent) {\n    await this.runTestsWithState({\n      storyIds: event.payload.storyIds,\n      triggeredBy: event.payload.triggeredBy,\n      configOverride: event.payload.configOverride,\n      callback: async () => {\n        try {\n          await this.vitestManager.vitestRestartPromise;\n          await this.vitestManager.runTests(event.payload);\n        } catch (err) {\n          this.reportFatalError('Failed to run tests', err);\n          throw err;\n        }\n      },\n    });\n  }\n\n  async handleCancelEvent() {\n    try {\n      this.store.setState((s) => ({\n        ...s,\n        cancelling: true,\n      }));\n      await this.vitestManager.cancelCurrentRun();\n    } catch (err) {\n      this.reportFatalError('Failed to cancel tests', err);\n    } finally {\n      this.store.setState((s) => ({\n        ...s,\n        cancelling: false,\n      }));\n    }\n  }\n\n  async runTestsWithState({\n    storyIds,\n    triggeredBy,\n    configOverride,\n    callback,\n  }: {\n    storyIds?: string[];\n    triggeredBy: RunTrigger;\n    configOverride?: StoreState['config'];\n    callback: () => Promise<void>;\n  }) {\n    this.componentTestStatusStore.unset(storyIds);\n    this.a11yStatusStore.unset(storyIds);\n\n    const runConfig = configOverride ?? this.store.getState().config;\n\n    this.store.setState((s) => ({\n      ...s,\n      currentRun: {\n        ...storeOptions.initialState.currentRun,\n        triggeredBy,\n        startedAt: Date.now(),\n        storyIds: storyIds,\n        config: runConfig,\n      },\n    }));\n    // set the config at the start of a test run,\n    // so that changing the config during the test run does not affect the currently running test run\n    process.env.VITEST_STORYBOOK_CONFIG = JSON.stringify(runConfig);\n\n    await this.testProviderStore.runWithState(async () => {\n      await callback();\n      this.store.send({\n        type: 'TEST_RUN_COMPLETED',\n        payload: this.store.getState().currentRun,\n      });\n      if (this.store.getState().currentRun.unhandledErrors.length > 0) {\n        throw new Error('Tests completed but there are unhandled errors');\n      }\n    });\n  }\n\n  onTestModuleCollected(collectedTestCount: number) {\n    this.store.setState((s) => ({\n      ...s,\n      currentRun: {\n        ...s.currentRun,\n        totalTestCount: (s.currentRun.totalTestCount ?? 0) + collectedTestCount,\n      },\n    }));\n  }\n\n  onTestCaseResult(result: { storyId?: string; testResult: TestResult; reports?: Report[] }) {\n    const { storyId, testResult, reports } = result;\n    if (!storyId) {\n      return;\n    }\n\n    const requestedStoryIds = this.store.getState().currentRun.storyIds;\n    if (requestedStoryIds && !this.isRequestedStoryOrChild(storyId, requestedStoryIds)) {\n      // In focused runs, Vitest name filtering can still pick up same-named tests in other files.\n      // Drop those results here so status stores and run summaries only reflect requested stories.\n      return;\n    }\n\n    this.batchedTestCaseResults.push({ storyId, testResult, reports });\n    this.throttledFlushTestCaseResults();\n  }\n\n  private isRequestedStoryOrChild(storyId: string, requestedStoryIds: string[]) {\n    if (requestedStoryIds.includes(storyId)) {\n      return true;\n    }\n\n    const entry = this.store.getState().index.entries[storyId];\n    return entry?.type === 'story' && !!entry.parent && requestedStoryIds.includes(entry.parent);\n  }\n\n  /**\n   * Throttled function to process batched test case results.\n   *\n   * This function:\n   *\n   * 1. Takes all batched test case results and clears the batch\n   * 2. Updates the store state with new test counts (component tests and a11y tests)\n   * 3. Adjusts the totalTestCount if more tests were run than initially anticipated\n   * 4. Creates status objects for component tests and updates the component test status store\n   * 5. Creates status objects for a11y tests (if any) and updates the a11y status store\n   *\n   * The throttling (500ms) is necessary as the channel would otherwise get overwhelmed with events,\n   * eventually causing the manager and dev server to lose connection.\n   */\n  throttledFlushTestCaseResults = throttle(() => {\n    const testCaseResultsToFlush = this.batchedTestCaseResults;\n    this.batchedTestCaseResults = [];\n\n    const componentTestStatuses = testCaseResultsToFlush.map(({ storyId, testResult }) => ({\n      storyId,\n      typeId: STATUS_TYPE_ID_COMPONENT_TEST,\n      value: testStateToStatusValueMap[testResult.state],\n      title: 'Component tests',\n      description: testResult.errors?.map((error) => error.stack || error.message).join('\\n') ?? '',\n      sidebarContextMenu: false,\n    }));\n\n    this.componentTestStatusStore.set(componentTestStatuses);\n\n    const a11yReportsByStoryId: CurrentRun['a11yReports'] = {};\n    const a11yStatuses: typeof componentTestStatuses = [];\n\n    for (const { storyId, reports } of testCaseResultsToFlush) {\n      const storyA11yReports = reports?.filter((r) => r.type === 'a11y');\n      if (!storyA11yReports?.length) {\n        continue;\n      }\n      a11yReportsByStoryId[storyId] = storyA11yReports.map((r) => r.result) as A11yReport[];\n      for (const a11yReport of storyA11yReports) {\n        a11yStatuses.push({\n          storyId,\n          typeId: STATUS_TYPE_ID_A11Y,\n          value: testStateToStatusValueMap[a11yReport.status],\n          title: 'Accessibility tests',\n          description: '',\n          sidebarContextMenu: false,\n        });\n      }\n    }\n\n    if (a11yStatuses.length > 0) {\n      this.a11yStatusStore.set(a11yStatuses);\n    }\n\n    this.store.setState((s) => {\n      let { success: ctSuccess, error: ctError } = s.currentRun.componentTestCount;\n      let { success: a11ySuccess, warning: a11yWarning, error: a11yError } = s.currentRun.a11yCount;\n      testCaseResultsToFlush.forEach(({ testResult, reports }) => {\n        if (testResult.state === 'passed') {\n          ctSuccess++;\n        } else if (testResult.state === 'failed') {\n          ctError++;\n        }\n        reports\n          ?.filter((r) => r.type === 'a11y')\n          .forEach((report) => {\n            if (report.status === 'passed') {\n              a11ySuccess++;\n            } else if (report.status === 'warning') {\n              a11yWarning++;\n            } else if (report.status === 'failed') {\n              a11yError++;\n            }\n          });\n      });\n      const finishedTestCount = ctSuccess + ctError;\n\n      return {\n        ...s,\n        currentRun: {\n          ...s.currentRun,\n          componentTestCount: { success: ctSuccess, error: ctError },\n          a11yCount: { success: a11ySuccess, warning: a11yWarning, error: a11yError },\n          componentTestStatuses: s.currentRun.componentTestStatuses.concat(componentTestStatuses),\n          a11yStatuses: s.currentRun.a11yStatuses.concat(a11yStatuses),\n          a11yReports: {\n            ...s.currentRun.a11yReports,\n            ...a11yReportsByStoryId,\n          },\n          // in some cases successes and errors can exceed the anticipated totalTestCount\n          // e.g. when testing more tests than the stories we know about upfront\n          // in those cases, we set the totalTestCount to the sum of successes and errors\n          totalTestCount:\n            finishedTestCount > (s.currentRun.totalTestCount ?? 0)\n              ? finishedTestCount\n              : s.currentRun.totalTestCount,\n        },\n      };\n    });\n  }, 500);\n\n  onTestRunEnd(endResult: { totalTestCount: number; unhandledErrors: VitestError[] }) {\n    this.throttledFlushTestCaseResults.flush();\n    this.store.setState((s) => {\n      const focusedRunTotal =\n        s.currentRun.componentTestCount.success + s.currentRun.componentTestCount.error;\n\n      return {\n        ...s,\n        currentRun: {\n          ...s.currentRun,\n          // For focused runs, keep totals aligned with filtered case results.\n          // For full runs, use Vitest's reported total.\n          totalTestCount: s.currentRun.storyIds ? focusedRunTotal : endResult.totalTestCount,\n          unhandledErrors: endResult.unhandledErrors,\n          finishedAt: Date.now(),\n        },\n      };\n    });\n  }\n\n  onCoverageCollected(coverageSummary: StoreState['currentRun']['coverageSummary']) {\n    this.store.setState((s) => ({\n      ...s,\n      currentRun: { ...s.currentRun, coverageSummary },\n    }));\n  }\n\n  async reportFatalError(message: string, error: Error | any) {\n    await this.store.untilReady();\n    this.store.send({\n      type: 'FATAL_ERROR',\n      payload: {\n        message,\n        error: errorToErrorLike(error),\n      },\n    });\n  }\n\n  static async start(options: TestManagerOptions) {\n    return new Promise<TestManager>((resolve) => {\n      const testManager = new TestManager({\n        ...options,\n        onReady: () => {\n          resolve(testManager);\n          options.onReady?.();\n        },\n      });\n    });\n  }\n}\n"
  },
  {
    "path": "code/addons/vitest/src/node/vitest-manager.ts",
    "content": "import { existsSync, readFileSync } from 'node:fs';\n\nimport type {\n  CoverageOptions,\n  ResolvedCoverageOptions,\n  TestProject,\n  TestSpecification,\n  Vitest,\n} from 'vitest/node';\n\nimport { getProjectRoot, resolvePathInStorybookCache } from 'storybook/internal/common';\nimport { Tag } from 'storybook/internal/core-server';\nimport type { StoryId, StoryIndexEntry } from 'storybook/internal/types';\n\nimport * as find from 'empathic/find';\nimport * as walk from 'empathic/walk';\nimport { escapeRegExp } from 'es-toolkit/string';\nimport path, { dirname, join, normalize, resolve } from 'pathe';\n// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\n\nimport { COVERAGE_DIRECTORY } from '../constants.ts';\nimport { log } from '../logger.ts';\nimport type { TriggerRunEvent } from '../types.ts';\nimport type { StorybookCoverageReporterOptions } from './coverage-reporter.ts';\nimport { StorybookReporter } from './reporter.ts';\nimport type { TestManager } from './test-manager.ts';\n\nconst VITEST_CONFIG_FILE_EXTENSIONS = ['mts', 'mjs', 'cts', 'cjs', 'ts', 'tsx', 'js', 'jsx'];\nconst VITEST_WORKSPACE_FILE_EXTENSION = ['ts', 'js', 'json'];\n\n// We have to tell Vitest that it runs as part of Storybook\nprocess.env.VITEST_STORYBOOK = 'true';\n\n/**\n * The Storybook vitest plugin adds double space characters so that it's possible to do a regex for\n * all test run use cases. Otherwise, if there were two unrelated stories like \"Primary Button\" and\n * \"Primary Button Mobile\", once you run tests for \"Primary Button\" and its children it would also\n * match \"Primary Button Mobile\". As it turns out, this limitation is also present in the Vitest\n * VSCode extension and the issue would occur with normal vitest tests as well, but because we use\n * double spaces, we circumvent the issue.\n */\nexport const DOUBLE_SPACES = '  ';\nconst getTestName = (name: string) => `${name}${DOUBLE_SPACES}`;\n\nexport class VitestManager {\n  vitest: Vitest | null = null;\n\n  vitestStartupCounter = 0;\n\n  vitestRestartPromise: Promise<void> | null = null;\n\n  runningPromise: Promise<any> | null = null;\n\n  constructor(private testManager: TestManager) {}\n\n  async startVitest({ coverage }: { coverage: boolean }) {\n    const { createVitest } = await import('vitest/node');\n\n    const storybookCoverageReporter: [string, StorybookCoverageReporterOptions] = [\n      '@storybook/addon-vitest/internal/coverage-reporter',\n      {\n        testManager: this.testManager,\n        coverageOptions: this.vitest?.config?.coverage as ResolvedCoverageOptions<'v8'> | undefined,\n      },\n    ];\n    const coverageOptions = (\n      coverage\n        ? {\n            enabled: true,\n            clean: true,\n            cleanOnRerun: true,\n            reportOnFailure: true,\n            reporter: [['html', {}], storybookCoverageReporter],\n            reportsDirectory: resolvePathInStorybookCache(COVERAGE_DIRECTORY),\n          }\n        : { enabled: false }\n    ) as CoverageOptions;\n\n    // In monorepos, the Storybook configDir (e.g. packages/web-app/.storybook) identifies\n    // the sub-package. We start the Vitest config search from its parent (the package root)\n    // and traverse upward to the project root, so configs in both sub-packages and the\n    // monorepo root are found. Without this, find.any defaults to process.cwd() which may\n    // be the monorepo root and would miss sub-package configs entirely.\n    const configDir = this.testManager.storybookOptions.configDir;\n    const packageRoot = configDir ? dirname(resolve(configDir)) : undefined;\n\n    const configFiles = [\n      ...VITEST_WORKSPACE_FILE_EXTENSION.map((ext) => `vitest.workspace.${ext}`),\n      ...VITEST_CONFIG_FILE_EXTENSIONS.flatMap((ext) => [\n        `vitest.config.${ext}`,\n        `vite.config.${ext}`,\n      ]),\n    ];\n\n    const potentialConfigFileLocations = walk.up(packageRoot || process.cwd(), {\n      last: getProjectRoot(),\n    });\n\n    let vitestWorkspaceConfig: string | undefined;\n    let firstVitestConfig: string | undefined;\n\n    for (const location of potentialConfigFileLocations) {\n      for (const file of configFiles) {\n        const maybe = find.any([file], { cwd: location, last: getProjectRoot() });\n        if (maybe && existsSync(maybe)) {\n          firstVitestConfig ??= dirname(maybe);\n          const content = readFileSync(maybe, 'utf8');\n          if (content.includes('storybookTest') || content.includes('@storybook/addon-vitest')) {\n            vitestWorkspaceConfig = dirname(maybe);\n            break;\n          }\n        }\n      }\n      if (vitestWorkspaceConfig) {\n        break;\n      }\n    }\n\n    const projectName = 'storybook:' + process.env.STORYBOOK_CONFIG_DIR;\n\n    const vitestConfigFallbackLocation = firstVitestConfig || packageRoot || process.cwd();\n\n    try {\n      this.vitest = await createVitest('test', {\n        root: vitestWorkspaceConfig ?? vitestConfigFallbackLocation,\n        watch: true,\n        passWithNoTests: false,\n        project: [projectName],\n        // TODO:\n        // Do we want to enable Vite's default reporter?\n        // The output in the terminal might be too spamy and it might be better to\n        // find a way to just show errors and warnings for example\n        // Otherwise it might be hard for the user to discover Storybook related logs\n        reporters: ['default', new StorybookReporter(this.testManager)],\n        coverage: coverageOptions,\n      });\n    } catch (err: any) {\n      const originalMessage = String(err.message);\n      if (originalMessage.includes('Found multiple projects')) {\n        const custom = [\n          'Storybook was unable to start the test run because you have multiple Vitest projects (or browsers) in headed mode.',\n          'Please set `headless: true` in your Storybook vitest config.\\n\\n',\n        ].join('\\n');\n\n        if (!originalMessage.startsWith(custom)) {\n          err.message = `${custom}${originalMessage}`;\n        }\n      }\n\n      throw err;\n    }\n\n    if (this.vitest) {\n      this.vitest.onCancel(() => {\n        // TODO: handle cancellation\n      });\n    }\n\n    try {\n      await this.vitest.init();\n    } catch (e: any) {\n      let message = 'Failed to initialize Vitest';\n      const isV8 = e.message?.includes('@vitest/coverage-v8');\n      const isIstanbul = e.message?.includes('@vitest/coverage-istanbul');\n\n      if (\n        (e.message?.includes('Failed to load url') && (isIstanbul || isV8)) ||\n        // Vitest will sometimes not throw the correct missing-package-detection error, so we have to check for this as well\n        (e instanceof TypeError &&\n          e?.message === \"Cannot read properties of undefined (reading 'name')\")\n      ) {\n        const coveragePackage = isIstanbul ? 'coverage-istanbul' : 'coverage-v8';\n        message += `\\n\\nPlease install the @vitest/${coveragePackage} package to collect coverage\\n`;\n      }\n      this.testManager.reportFatalError(message, e);\n      return;\n    }\n\n    await this.setupWatchers();\n  }\n\n  async restartVitest({ coverage }: { coverage: boolean }) {\n    await this.vitestRestartPromise;\n    this.vitestRestartPromise = new Promise(async (resolve, reject) => {\n      try {\n        await this.runningPromise;\n        await this.vitest?.close();\n        await this.startVitest({ coverage });\n        resolve();\n      } catch (e) {\n        reject(e);\n      } finally {\n        this.vitestRestartPromise = null;\n      }\n    });\n    return this.vitestRestartPromise;\n  }\n\n  private resetGlobalTestNamePattern() {\n    this.vitest?.setGlobalTestNamePattern('');\n  }\n\n  private updateLastChanged(filepath: string) {\n    // @ts-expect-error `server` only exists in Vitest 3\n    this.vitest!.projects.forEach(({ browser, vite, server }) => {\n      if (server) {\n        const serverMods = server.moduleGraph.getModulesByFile(filepath);\n        serverMods?.forEach((mod: any) => server.moduleGraph.invalidateModule(mod));\n      }\n      if (vite) {\n        const serverMods = vite.moduleGraph.getModulesByFile(filepath);\n        serverMods?.forEach((mod) => vite.moduleGraph.invalidateModule(mod));\n      }\n      if (browser) {\n        const browserMods = browser.vite.moduleGraph.getModulesByFile(filepath);\n        browserMods?.forEach((mod) => browser.vite.moduleGraph.invalidateModule(mod));\n      }\n    });\n  }\n\n  private getStories(requestStoryIds?: string[]): StoryIndexEntry[] {\n    const index = this.testManager.store.getState().index;\n    if (requestStoryIds) {\n      const stories: StoryIndexEntry[] = [];\n      for (const id of requestStoryIds) {\n        const entry = index.entries[id];\n        if (entry?.type === 'story') {\n          stories.push(entry);\n        }\n      }\n      return stories;\n    }\n    return Object.values(index.entries).filter((entry) => entry.type === 'story');\n  }\n\n  /**\n   * Builds the exact Vitest name-pattern fragment for one selected Storybook entry.\n   *\n   * The pattern differs by entry type:\n   *\n   * - Component entry (has child stories/tests): match the whole describe block prefix\n   * - Story-test entry (has parent): match \"parent describe + test name\" exactly\n   * - Regular story entry: match the story name exactly\n   */\n  private buildStoryTestNamePattern(\n    story: StoryIndexEntry,\n    allStories: StoryIndexEntry[],\n    storiesById: Record<StoryId, StoryIndexEntry>\n  ) {\n    const isParentStory = allStories.some((candidate) => story.id === candidate.parent);\n\n    if (isParentStory) {\n      return `^${escapeRegExp(getTestName(story.name))}`;\n    }\n\n    if (story.parent) {\n      const parentStory = storiesById[story.parent];\n      if (!parentStory) {\n        throw new Error(`Parent story not found for story ${story.id}`);\n      }\n\n      return `^${escapeRegExp(getTestName(parentStory.name))} ${escapeRegExp(story.name)}$`;\n    }\n\n    return `^${escapeRegExp(story.name)}$`;\n  }\n\n  /**\n   * Combines multiple per-story patterns into one global regex so Vitest can run an exact subset of\n   * tests across one or more files in a single invocation.\n   */\n  private buildTestNamePatternForStories(\n    selectedStories: StoryIndexEntry[],\n    allStories: StoryIndexEntry[]\n  ) {\n    const storiesById = Object.fromEntries(allStories.map((story) => [story.id, story])) as Record<\n      StoryId,\n      StoryIndexEntry\n    >;\n\n    const storyPatterns = [\n      ...new Set(\n        selectedStories.map((story) =>\n          this.buildStoryTestNamePattern(story, allStories, storiesById)\n        )\n      ),\n    ];\n\n    if (!storyPatterns.length) {\n      return undefined;\n    }\n\n    if (storyPatterns.length === 1) {\n      return new RegExp(storyPatterns[0]);\n    }\n\n    // Build one \"OR\" expression across all selected stories.\n    // Example when storyPatterns are \"^One$\" and \"^Parent  Child$\":\n    //   /(?:(?:^One$)|(?:^Parent  Child$))/\n    //\n    // Why wrap each pattern with (?:...)?\n    // - Keeps each full, already-anchored pattern isolated as one alternative.\n    // - Prevents precedence issues when joining with `|`.\n    // - Uses non-capturing groups to avoid unnecessary capture groups.\n    return new RegExp(`(?:${storyPatterns.map((pattern) => `(?:${pattern})`).join('|')})`);\n  }\n\n  private filterTestSpecifications(\n    testSpecifications: TestSpecification[],\n    stories: StoryIndexEntry[]\n  ) {\n    const filteredTestSpecifications: TestSpecification[] = [];\n    const filteredStoryIds: StoryId[] = [];\n\n    const storiesByImportPath: Record<StoryIndexEntry['importPath'], StoryIndexEntry[]> = {};\n\n    for (const story of stories) {\n      const absoluteImportPath = path.join(process.cwd(), story.importPath);\n      if (!storiesByImportPath[absoluteImportPath]) {\n        storiesByImportPath[absoluteImportPath] = [];\n      }\n      storiesByImportPath[absoluteImportPath].push(story);\n    }\n\n    for (const testSpecification of testSpecifications) {\n      const { env = {} } = testSpecification.project.config;\n      const include = env.__VITEST_INCLUDE_TAGS__?.split(',').filter(Boolean) ?? [Tag.TEST];\n      const exclude = env.__VITEST_EXCLUDE_TAGS__?.split(',').filter(Boolean) ?? [];\n      const skip = env.__VITEST_SKIP_TAGS__?.split(',').filter(Boolean) ?? [];\n\n      const storiesInTestSpecification = storiesByImportPath[testSpecification.moduleId] ?? [];\n\n      const filteredStories = storiesInTestSpecification.filter((story) => {\n        if (include.length && !include.some((tag) => story.tags?.includes(tag))) {\n          return false;\n        }\n        if (exclude.some((tag) => story.tags?.includes(tag))) {\n          return false;\n        }\n        // Skipped tests are intentionally included here\n        return true;\n      });\n\n      if (!filteredStories.length) {\n        continue;\n      }\n\n      if (!this.testManager.store.getState().watching) {\n        // Clear the file cache if watch mode is disabled\n        this.updateLastChanged(testSpecification.moduleId);\n      }\n\n      filteredTestSpecifications.push(testSpecification);\n      filteredStoryIds.push(\n        ...filteredStories\n          // Don't count skipped stories, because StorybookReporter doesn't include them either\n          .filter((story) => !skip.some((tag) => story.tags?.includes(tag)))\n          .map((story) => story.id)\n      );\n    }\n\n    return { filteredTestSpecifications, filteredStoryIds };\n  }\n\n  async runTests(runPayload: TriggerRunEvent['payload']) {\n    const { watching, config } = this.testManager.store.getState();\n    const coverageShouldBeEnabled =\n      config.coverage && !watching && (runPayload?.storyIds?.length ?? 0) === 0;\n    const currentCoverage = this.vitest?.config.coverage?.enabled;\n\n    if (!this.vitest) {\n      await this.startVitest({ coverage: coverageShouldBeEnabled });\n    } else if (currentCoverage !== coverageShouldBeEnabled) {\n      await this.restartVitest({ coverage: coverageShouldBeEnabled });\n    } else {\n      await this.vitestRestartPromise;\n    }\n\n    this.resetGlobalTestNamePattern();\n\n    await this.cancelCurrentRun();\n\n    const testSpecifications = await this.getStorybookTestSpecifications();\n    const allStories = this.getStories();\n\n    const filteredStories = runPayload.storyIds\n      ? allStories.filter((story) => runPayload.storyIds?.includes(story.id))\n      : allStories;\n\n    if (runPayload.storyIds?.length) {\n      const regex = this.buildTestNamePatternForStories(filteredStories, allStories);\n      if (regex) {\n        this.vitest!.setGlobalTestNamePattern(regex);\n      }\n    }\n\n    const { filteredTestSpecifications, filteredStoryIds } = this.filterTestSpecifications(\n      testSpecifications,\n      filteredStories\n    );\n\n    this.testManager.store.setState((s) => ({\n      ...s,\n      currentRun: {\n        ...s.currentRun,\n        totalTestCount: filteredStoryIds.length,\n      },\n    }));\n\n    await this.vitest!.runTestSpecifications(filteredTestSpecifications, true);\n    this.resetGlobalTestNamePattern();\n  }\n\n  async cancelCurrentRun() {\n    await this.vitest?.cancelCurrentRun('keyboard-input');\n    await this.runningPromise;\n  }\n\n  async getStorybookTestSpecifications() {\n    const globTestSpecifications = (await this.vitest?.globTestSpecifications()) ?? [];\n    return (\n      globTestSpecifications.filter((workspaceSpec) =>\n        this.isStorybookProject(workspaceSpec.project)\n      ) ?? []\n    );\n  }\n\n  async runAffectedTestsAfterChange(changedFilePath: string, event: 'change' | 'add') {\n    const id = slash(changedFilePath);\n    this.vitest?.logger.clearHighlightCache(id);\n    this.updateLastChanged(id);\n\n    if (event === 'add') {\n      const project = this.vitest?.projects.find(this.isStorybookProject.bind(this));\n      // This function not only tests whether a file matches the test globs, but it also\n      // adds the file to the project's internal testFilesList\n      project?.matchesTestGlob(id);\n    }\n\n    // when watch mode is disabled, don't trigger any tests (below)\n    // but still invalidate the cache for the changed file, which is handled above\n    if (!this.testManager.store.getState().watching) {\n      return;\n    }\n    if (!this.vitest) {\n      return;\n    }\n    this.resetGlobalTestNamePattern();\n\n    const storybookProject = this.vitest!.projects.find((p) => this.isStorybookProject(p));\n    // we create synthetic TestSpecifications for the preview annotations and setup files, so that we can analyze their dependencies\n    const previewAnnotationSpecifications = this.testManager.store\n      .getState()\n      .previewAnnotations.map((previewAnnotation) => {\n        return {\n          project: storybookProject ?? this.vitest!.projects[0],\n          moduleId:\n            typeof previewAnnotation === 'string' ? previewAnnotation : previewAnnotation.absolute,\n        };\n      }) as TestSpecification[];\n    const setupFilesSpecifications = this.vitest!.projects.flatMap((project) =>\n      project.config.setupFiles.map((setupFile) => ({\n        project,\n        moduleId: setupFile,\n      }))\n    ) as TestSpecification[];\n    const syntheticGlobalTestSpecifications =\n      previewAnnotationSpecifications.concat(setupFilesSpecifications);\n\n    const testSpecifications = await this.getStorybookTestSpecifications();\n    const allStories = this.getStories();\n\n    let affectsGlobalFiles = false;\n\n    const affectedTestSpecifications = (\n      await Promise.all(\n        syntheticGlobalTestSpecifications\n          .concat(testSpecifications)\n          .map(async (testSpecification) => {\n            const dependencies = await this.getTestDependencies(testSpecification);\n            if (\n              changedFilePath === testSpecification.moduleId ||\n              dependencies.has(changedFilePath)\n            ) {\n              // if the changed file path affects a preview annotation or setup file\n              // we mark global files as affected, which triggers a run of _all_ tests\n              if (syntheticGlobalTestSpecifications.includes(testSpecification)) {\n                affectsGlobalFiles = true;\n              }\n              return testSpecification;\n            }\n          })\n      )\n    ).filter(Boolean) as TestSpecification[];\n\n    const testSpecificationsToRun = affectsGlobalFiles\n      ? testSpecifications\n      : affectedTestSpecifications;\n\n    if (!testSpecificationsToRun.length) {\n      return;\n    }\n\n    const { filteredTestSpecifications, filteredStoryIds } = this.filterTestSpecifications(\n      testSpecificationsToRun,\n      allStories\n    );\n    await this.testManager.runTestsWithState({\n      storyIds: filteredStoryIds,\n      triggeredBy: 'watch',\n      callback: async () => {\n        this.testManager.store.setState((s) => ({\n          ...s,\n          currentRun: {\n            ...s.currentRun,\n            totalTestCount: filteredStoryIds.length,\n          },\n        }));\n        await this.vitest!.cancelCurrentRun('keyboard-input');\n        await this.runningPromise;\n        await this.vitest!.runTestSpecifications(filteredTestSpecifications, false);\n      },\n    });\n  }\n\n  // This is an adaptation of Vitest's own implementation\n  // see https://github.com/vitest-dev/vitest/blob/14409088166152c920ce7fa4ad4c0ba57149b869/packages/vitest/src/node/specifications.ts#L171-L198\n  private async getTestDependencies(spec: TestSpecification) {\n    const deps = new Set<string>();\n\n    const addImports = async (project: TestProject, filepath: string) => {\n      if (deps.has(filepath)) {\n        return;\n      }\n      deps.add(filepath);\n\n      const mod = project.vite.moduleGraph.getModuleById(filepath);\n      const transformed =\n        mod?.ssrTransformResult || (await project.vite.transformRequest(filepath, { ssr: true }));\n      if (!transformed) {\n        return;\n      }\n\n      const dependencies = [...(transformed.deps ?? []), ...(transformed.dynamicDeps ?? [])];\n\n      await Promise.all(\n        dependencies.map(async (dep) => {\n          const fsPath = dep.startsWith('/@fs/')\n            ? dep.slice(process.platform === 'win32' ? 5 : 4)\n            : join(project.config.root, dep);\n\n          if (!fsPath.includes('node_modules') && !deps.has(fsPath) && existsSync(fsPath)) {\n            await addImports(project, fsPath);\n          }\n        })\n      );\n    };\n\n    await addImports(spec.project, spec.moduleId);\n    deps.delete(spec.moduleId);\n\n    return deps;\n  }\n\n  async registerVitestConfigListener() {\n    this.vitest!.vite.watcher.on('change', async (file) => {\n      const isConfig = normalize(file) === this.vitest?.vite?.config.configFile;\n      if (isConfig) {\n        log('Restarting Vitest due to config change');\n        const { watching, config } = this.testManager.store.getState();\n        await this.restartVitest({ coverage: config.coverage && !watching });\n      }\n    });\n  }\n\n  async setupWatchers() {\n    this.resetGlobalTestNamePattern();\n    this.vitest!.vite.watcher.removeAllListeners('change');\n    this.vitest!.vite.watcher.removeAllListeners('add');\n    this.vitest!.vite.watcher.on('change', (file) =>\n      this.runAffectedTestsAfterChange(file, 'change')\n    );\n    this.vitest!.vite.watcher.on('add', (file) => {\n      this.runAffectedTestsAfterChange(file, 'add');\n    });\n    this.registerVitestConfigListener();\n  }\n\n  isStorybookProject(project: TestProject) {\n    return !!project.config.env?.__STORYBOOK_URL__;\n  }\n}\n"
  },
  {
    "path": "code/addons/vitest/src/node/vitest.ts",
    "content": "import process from 'node:process';\n\nimport { Channel } from 'storybook/internal/channels';\nimport {\n  experimental_UniversalStore,\n  experimental_getStatusStore,\n  experimental_getTestProviderStore,\n} from 'storybook/internal/core-server';\n\nimport {\n  ADDON_ID,\n  STATUS_TYPE_ID_A11Y,\n  STATUS_TYPE_ID_COMPONENT_TEST,\n  storeOptions,\n} from '../constants.ts';\nimport type { ErrorLike, FatalErrorEvent, StoreEvent, StoreState } from '../types.ts';\nimport { TestManager } from './test-manager.ts';\n\n// Destructure the imported functions for easier access\nconst UniversalStore = experimental_UniversalStore;\nconst getStatusStore = experimental_getStatusStore;\nconst getTestProviderStore = experimental_getTestProviderStore;\n\nconst channel: Channel = new Channel({\n  async: true,\n  transport: {\n    send: (event) => {\n      process.send?.(event);\n    },\n    setHandler: (handler) => {\n      process.on('message', handler);\n    },\n  },\n});\n\n(UniversalStore as any).__prepare(channel, UniversalStore.Environment.SERVER);\n\nconst store = UniversalStore.create<StoreState, StoreEvent>(storeOptions);\n\nnew TestManager({\n  store,\n  componentTestStatusStore: getStatusStore(STATUS_TYPE_ID_COMPONENT_TEST),\n  a11yStatusStore: getStatusStore(STATUS_TYPE_ID_A11Y),\n  testProviderStore: getTestProviderStore(ADDON_ID),\n  onReady: () => {\n    process.send?.({ type: 'ready' });\n  },\n  storybookOptions: {\n    configDir: process.env.STORYBOOK_CONFIG_DIR || '',\n  } as any,\n});\n\nconst exit = (code = 0) => {\n  channel?.removeAllListeners();\n  process.exit(code);\n};\n\nconst createUnhandledErrorHandler = (message: string) => async (error: ErrorLike) => {\n  try {\n    const payload: FatalErrorEvent['payload'] = {\n      message,\n      error: {\n        message: error.message,\n        name: error.name,\n        stack: error.stack,\n        cause: error.cause as ErrorLike,\n      },\n    };\n    // Node.js will exit immediately in these situations, so we can't send an event via the universal store\n    // because the process will exit before the event is sent.\n    // we're sending it manually instead, so the parent process can forward it to the store.\n    process.send?.({\n      type: 'uncaught-error',\n      payload,\n    });\n  } finally {\n    exit(1);\n  }\n};\n\nprocess.on(\n  'uncaughtException',\n  createUnhandledErrorHandler('Uncaught exception in the test runner process')\n);\nprocess.on(\n  'unhandledRejection',\n  createUnhandledErrorHandler('Unhandled rejection in the test runner process')\n);\n\nprocess.on('exit', exit);\nprocess.on('SIGINT', () => exit(0));\nprocess.on('SIGTERM', () => exit(0));\n"
  },
  {
    "path": "code/addons/vitest/src/postinstall.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { isConfigAlreadySetup } from './postinstall.ts';\n\ndescribe('postinstall helpers', () => {\n  it('detects a fully configured Vitest config with addon plugin', () => {\n    const config = `\n      import { defineConfig } from 'vitest/config';\n      import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n\n      export default defineConfig({\n        test: {\n          projects: [\n            {\n              extends: true,\n              plugins: [storybookTest({ configDir: '.storybook' })],\n            },\n          ],\n        },\n      });\n    `;\n\n    expect(isConfigAlreadySetup('/project/vitest.config.ts', config)).toBe(true);\n  });\n\n  it('returns false when storybookTest plugin is not used', () => {\n    const config = `\n      import { defineConfig } from 'vitest/config';\n\n      export default defineConfig({\n        test: {\n          projects: [\n            {\n              extends: true,\n            },\n          ],\n        },\n      });\n    `;\n\n    expect(isConfigAlreadySetup('/project/vitest.config.ts', config)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "code/addons/vitest/src/postinstall.ts",
    "content": "import * as fs from 'node:fs/promises';\nimport { writeFile } from 'node:fs/promises';\nimport os from 'node:os';\n\nimport { babelParse, generate, traverse } from 'storybook/internal/babel';\nimport { AddonVitestService } from 'storybook/internal/cli';\nimport {\n  JsPackageManagerFactory,\n  formatFileContent,\n  getProjectRoot,\n  getStorybookInfo,\n  versions,\n} from 'storybook/internal/common';\nimport { CLI_COLORS } from 'storybook/internal/node-logger';\nimport type { StorybookError } from 'storybook/internal/server-errors';\nimport {\n  AddonVitestPostinstallConfigUpdateError,\n  AddonVitestPostinstallError,\n  AddonVitestPostinstallFailedAddonA11yError,\n  AddonVitestPostinstallPrerequisiteCheckError,\n  AddonVitestPostinstallWorkspaceUpdateError,\n} from 'storybook/internal/server-errors';\nimport { SupportedFramework } from 'storybook/internal/types';\n\nimport * as find from 'empathic/find';\nimport { dirname, relative, resolve } from 'pathe';\nimport { coerce, satisfies } from 'semver';\nimport { dedent } from 'ts-dedent';\n\nimport { type PostinstallOptions } from '../../../lib/cli-storybook/src/add.ts';\nimport { DOCUMENTATION_LINK } from './constants.ts';\nimport { loadTemplate, updateConfigFile, updateWorkspaceFile } from './updateVitestFile.ts';\n\nconst ADDON_NAME = '@storybook/addon-vitest' as const;\nconst EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.cts', '.mts', '.cjs', '.mjs'];\nconst STORYBOOK_TEST_PLUGIN_SOURCE = `${ADDON_NAME}/vitest-plugin`;\n\nconst addonA11yName = '@storybook/addon-a11y';\n\nexport default async function postInstall(options: PostinstallOptions) {\n  const errors: InstanceType<typeof StorybookError>[] = [];\n  const { logger, prompt } = options;\n\n  const packageManager = JsPackageManagerFactory.getPackageManager({\n    force: options.packageManager,\n  });\n\n  const findFile = (basename: string, extensions = EXTENSIONS) =>\n    find.any(\n      extensions.map((ext) => basename + ext),\n      { last: getProjectRoot(), cwd: options.configDir }\n    );\n\n  const allDeps = packageManager.getAllDependencies();\n\n  // Determine Vitest version/range from installed or declared dependency to avoid pulling\n  // incompatible majors by default.\n  let vitestVersionSpecifier = await packageManager.getInstalledVersion('vitest');\n  if (!vitestVersionSpecifier && allDeps['vitest']) {\n    vitestVersionSpecifier = allDeps['vitest'];\n  }\n\n  /**\n   * Coerce the version specifier to a version string\n   *\n   * This removed any version range specifiers like ^, ~, etc. which is needed to check with\n   * semver.satisfies.\n   */\n  vitestVersionSpecifier = coerce(vitestVersionSpecifier)?.version ?? null;\n\n  logger.debug(`Vitest version specifier: ${vitestVersionSpecifier}`);\n  const isVitest3_2To4 = vitestVersionSpecifier\n    ? satisfies(vitestVersionSpecifier, '>=3.2.0 <4.0.0')\n    : false;\n\n  const isVitest4OrNewer = vitestVersionSpecifier\n    ? satisfies(vitestVersionSpecifier, '>=4.0.0')\n    : true;\n\n  const info = await getStorybookInfo(options.configDir);\n  // only install these dependencies if they are not already installed\n\n  const addonVitestService = new AddonVitestService(packageManager);\n\n  // Use AddonVitestService for compatibility validation\n  const compatibilityResult = await addonVitestService.validateCompatibility({\n    framework: info.framework,\n    builder: info.builder,\n  });\n\n  let result: string | null = null;\n  if (!compatibilityResult.compatible && compatibilityResult.reasons) {\n    const reasons = compatibilityResult.reasons.map((r) => `• ${CLI_COLORS.error(r)}`);\n    reasons.unshift(dedent`\n      Automated setup failed\n      The following packages have incompatibilities that prevent automated setup:\n    `);\n    reasons.push(\n      dedent`\n        You can fix these issues and rerun the command to reinstall. If you wish to roll back the installation, remove ${ADDON_NAME} from the \"addons\" array\n        in your main Storybook config file and remove the dependency from your package.json file.\n\n        Please check the documentation for more information about its requirements and installation:\n        https://storybook.js.org/docs/next/${DOCUMENTATION_LINK}\n      `\n    );\n\n    result = reasons.map((r) => r.trim()).join('\\n\\n');\n  }\n\n  if (result) {\n    logger.error(result);\n    throw new AddonVitestPostinstallPrerequisiteCheckError({\n      reasons: compatibilityResult.reasons!,\n    });\n  }\n\n  // Skip all dependency management when flag is set (called from init command)\n  if (!options.skipDependencyManagement) {\n    // Use AddonVitestService for dependency collection\n    const versionedDependencies = await addonVitestService.collectDependencies();\n\n    // Print informational messages for Next.js\n    if (info.framework === SupportedFramework.NEXTJS) {\n      const allDeps = packageManager.getAllDependencies();\n      if (!allDeps['@storybook/nextjs-vite']) {\n        // TODO: Tell people to migrate first to nextjs-vite\n      }\n    }\n\n    // Print informational message for coverage reporter\n    const v8Version = await packageManager.getInstalledVersion('@vitest/coverage-v8');\n    const istanbulVersion = await packageManager.getInstalledVersion('@vitest/coverage-istanbul');\n    if (!v8Version && !istanbulVersion) {\n      logger.step(\n        dedent`\n          You don't seem to have a coverage reporter installed. Vitest needs either V8 or Istanbul to generate coverage reports.\n\n          Adding \"@vitest/coverage-v8\" to enable coverage reporting.\n          Read more about Vitest coverage providers at https://vitest.dev/guide/coverage.html#coverage-providers\n        `\n      );\n    }\n\n    if (versionedDependencies.length > 0) {\n      logger.step('Adding dependencies to your package.json');\n      logger.log('  ' + versionedDependencies.join(', '));\n\n      await packageManager.addDependencies(\n        { type: 'devDependencies', skipInstall: true },\n        versionedDependencies\n      );\n    }\n\n    if (!options.skipInstall) {\n      await packageManager.installDependencies();\n    }\n  }\n\n  // Install Playwright browser binaries using AddonVitestService\n  if (!options.skipDependencyManagement) {\n    if (!options.skipInstall) {\n      await addonVitestService.installPlaywright({\n        yes: options.yes,\n        useRemotePkg: !!options.skipInstall,\n      });\n    } else {\n      const platform = os.platform();\n      const useWithDeps = platform === 'darwin' || platform === 'win32';\n      const manualCommand = useWithDeps\n        ? 'npx playwright install chromium --with-deps'\n        : 'npx playwright install chromium';\n      const linuxNote = !useWithDeps\n        ? '\\n        Note: add --with-deps to the command above if you are on Debian or Ubuntu.'\n        : '';\n      logger.warn(dedent`\n        Playwright browser binaries installation skipped. Please run the following command manually later:\n        ${CLI_COLORS.cta(manualCommand)}${linuxNote}\n      `);\n    }\n  }\n\n  const fileExtension =\n    allDeps.typescript || findFile('tsconfig', [...EXTENSIONS, '.json']) ? 'ts' : 'js';\n\n  const vitestWorkspaceFile = findFile('vitest.workspace', ['.ts', '.js', '.json']);\n  const viteConfigFile = findFile('vite.config');\n  const vitestConfigFile = findFile('vitest.config');\n  const vitestShimFile = findFile('vitest.shims.d');\n  const rootConfig = vitestConfigFile || viteConfigFile;\n\n  if (fileExtension === 'ts' && !vitestShimFile) {\n    await writeFile(\n      'vitest.shims.d.ts',\n      isVitest4OrNewer\n        ? '/// <reference types=\"@vitest/browser-playwright\" />'\n        : '/// <reference types=\"@vitest/browser/providers/playwright\" />'\n    );\n  }\n\n  const getTemplateName = (configContent?: string) => {\n    if (isVitest4OrNewer) {\n      return 'vitest.config.4.template';\n    } else if (isVitest3_2To4) {\n      // In Vitest 3.2, `workspace` was deprecated in favor of `projects` but still works.\n      // If the user's existing config already uses `workspace`, use the old template that\n      // also uses `workspace` so that the merge doesn't introduce both keys.\n      if (configContent && configUsesWorkspace(configContent)) {\n        return 'vitest.config.template';\n      }\n      return 'vitest.config.3.2.template';\n    }\n    return 'vitest.config.template';\n  };\n\n  // If there's an existing workspace file, we update that file to include the Storybook Addon Vitest plugin.\n  // We assume the existing workspaces include the Vite(st) config, so we won't add it.\n  if (vitestWorkspaceFile) {\n    const workspaceFileContent = await fs.readFile(vitestWorkspaceFile, 'utf8');\n    const alreadyConfigured = isConfigAlreadySetup(vitestWorkspaceFile, workspaceFileContent);\n\n    if (alreadyConfigured) {\n      logger.step(\n        CLI_COLORS.success('Vitest for Storybook is already properly configured. Skipping setup.')\n      );\n      return;\n    }\n\n    const workspaceTemplate = await loadTemplate('vitest.workspace.template', {\n      EXTENDS_WORKSPACE: viteConfigFile\n        ? relative(dirname(vitestWorkspaceFile), viteConfigFile)\n        : '',\n      CONFIG_DIR: options.configDir,\n    }).then((t) => t.replace(`\\n  'ROOT_CONFIG',`, '').replace(/\\s+extends: '',/, ''));\n    const source = babelParse(workspaceTemplate);\n    const target = babelParse(workspaceFileContent);\n\n    const updated = updateWorkspaceFile(source, target);\n    if (updated) {\n      logger.step(`Updating your Vitest workspace file...`);\n\n      logger.log(`${vitestWorkspaceFile}`);\n\n      const formattedContent = await formatFileContent(vitestWorkspaceFile, generate(target).code);\n      await writeFile(vitestWorkspaceFile, formattedContent);\n    } else {\n      logger.error(\n        dedent`\n          Could not update existing Vitest workspace file:\n          ${vitestWorkspaceFile}\n\n          I was able to configure most of the addon but could not safely extend\n          your existing workspace file automatically, you must do it yourself.\n\n          Please refer to the documentation to complete the setup manually:\n          https://storybook.js.org/docs/next/${DOCUMENTATION_LINK}#manual-setup-advanced\n        `\n      );\n      errors.push(\n        new AddonVitestPostinstallWorkspaceUpdateError({ filePath: vitestWorkspaceFile })\n      );\n    }\n  }\n  // If there's an existing Vite/Vitest config with workspaces, we update it to include the Storybook Addon Vitest plugin.\n  else if (rootConfig) {\n    let target, updated;\n    const configFile = await fs.readFile(rootConfig, 'utf8');\n    const configFileHasTypeReference = configFile.match(\n      /\\/\\/\\/\\s*<reference\\s+types=[\"']vitest\\/config[\"']\\s*\\/>/\n    );\n\n    const templateName = getTemplateName(configFile);\n\n    const alreadyConfigured = isConfigAlreadySetup(rootConfig, configFile);\n\n    if (templateName && !alreadyConfigured) {\n      const configTemplate = await loadTemplate(templateName, {\n        CONFIG_DIR: options.configDir,\n      });\n\n      const source = babelParse(configTemplate);\n      target = babelParse(configFile);\n      updated = updateConfigFile(source, target);\n    }\n\n    if (alreadyConfigured) {\n      logger.step(\n        CLI_COLORS.success('Vitest for Storybook is already properly configured. Skipping setup.')\n      );\n    } else if (target && updated) {\n      logger.step(`Updating your ${vitestConfigFile ? 'Vitest' : 'Vite'} config file:`);\n      logger.log(`  ${rootConfig}`);\n\n      const formattedContent = await formatFileContent(rootConfig, generate(target).code);\n      // Only add triple slash reference to vite.config files, not vitest.config files\n      // vitest.config files already have the vitest/config types available\n      const shouldAddReference = !configFileHasTypeReference && !vitestConfigFile;\n      await writeFile(\n        rootConfig,\n        shouldAddReference\n          ? '/// <reference types=\"vitest/config\" />\\n' + formattedContent\n          : formattedContent\n      );\n    } else {\n      logger.error(dedent`\n        We were unable to update your existing ${vitestConfigFile ? 'Vitest' : 'Vite'} config file.\n\n        Please refer to the documentation to complete the setup manually:\n        https://storybook.js.org/docs/writing-tests/integrations/vitest-addon#manual-setup-advanced\n      `);\n      errors.push(new AddonVitestPostinstallConfigUpdateError({ filePath: rootConfig }));\n    }\n  }\n  // If there's no existing Vitest/Vite config, we create a new Vitest config file.\n  else {\n    const parentDir = dirname(options.configDir);\n    const newConfigFile = resolve(parentDir, `vitest.config.${fileExtension}`);\n\n    const configTemplate = await loadTemplate(getTemplateName(), {\n      CONFIG_DIR: options.configDir,\n    });\n\n    logger.step(`Creating a Vitest config file:`);\n    logger.log(`${newConfigFile}`);\n\n    const formattedContent = await formatFileContent(newConfigFile, configTemplate);\n    await writeFile(newConfigFile, formattedContent);\n  }\n\n  const a11yAddon = info.addons.find((addon) => addon.includes(addonA11yName));\n\n  if (a11yAddon) {\n    try {\n      const command = [\n        options.skipInstall ? `storybook@${versions.storybook}` : `storybook`,\n        'automigrate',\n        'addon-a11y-addon-test',\n        '--loglevel',\n        'silent',\n        '--yes',\n        '--skip-doctor',\n      ];\n\n      if (options.packageManager) {\n        command.push('--package-manager', options.packageManager);\n      }\n\n      if (options.skipInstall) {\n        command.push('--skip-install');\n      }\n\n      if (options.configDir !== '.storybook') {\n        command.push('--config-dir', options.configDir);\n      }\n\n      await prompt.executeTask(\n        // TODO: Remove stdio: 'ignore' once we have a way to log the output of the command properly\n        () =>\n          packageManager.runPackageCommand({\n            args: command,\n            stdio: 'ignore',\n            useRemotePkg: !!options.skipInstall,\n          }),\n        {\n          intro: 'Setting up a11y addon for @storybook/addon-vitest',\n          error: 'Failed to setup a11y addon for @storybook/addon-vitest',\n          success: 'a11y addon setup successfully',\n        }\n      );\n    } catch (e: unknown) {\n      logger.error(dedent`\n        Could not automatically set up ${addonA11yName} for @storybook/addon-vitest.\n        Please refer to the documentation to complete the setup manually:\n        https://storybook.js.org/docs/writing-tests/accessibility-testing#integration-with-vitest-addon\n      `);\n      errors.push(new AddonVitestPostinstallFailedAddonA11yError({ error: e }));\n    }\n  }\n\n  const runCommand = rootConfig ? `npx vitest --project=storybook` : `npx vitest`;\n\n  if (errors.length === 0) {\n    logger.step(CLI_COLORS.success('@storybook/addon-vitest setup completed successfully'));\n    logger.log(dedent`\n        @storybook/addon-vitest is now configured and you're ready to run your tests!\n        Here are a couple of tips to get you started:\n\n        • You can run tests with \"${CLI_COLORS.cta(runCommand)}\"\n        • Vitest IDE extension shows all stories as tests in your editor!\n\n        Check the documentation for more information about its features and options at:\n        https://storybook.js.org/docs/next/${DOCUMENTATION_LINK}\n      `);\n  } else {\n    logger.warn(\n      dedent`\n        Done, but with errors!\n        @storybook/addon-vitest was installed successfully, but there were some errors during the setup process. Please refer to the documentation to complete the setup manually and check the errors above:\n        https://storybook.js.org/docs/next/${DOCUMENTATION_LINK}#manual-setup-advanced\n      `\n    );\n    throw new AddonVitestPostinstallError({ errors });\n  }\n}\n\nfunction isStorybookTestPluginSource(value: string) {\n  return value === STORYBOOK_TEST_PLUGIN_SOURCE;\n}\n\nexport function isConfigAlreadySetup(_configPath: string, configContent: string) {\n  let ast: ReturnType<typeof babelParse>;\n  try {\n    ast = babelParse(configContent);\n  } catch (e) {\n    return false;\n  }\n\n  const pluginIdentifiers = new Set<string>();\n\n  traverse(ast, {\n    ImportDeclaration(path) {\n      const source = path.node.source.value;\n      if (typeof source === 'string' && isStorybookTestPluginSource(source)) {\n        path.node.specifiers.forEach((specifier) => {\n          if ('local' in specifier && specifier.local?.name) {\n            pluginIdentifiers.add(specifier.local.name);\n          }\n        });\n      }\n    },\n  });\n\n  let pluginReferenced = false;\n\n  traverse(ast, {\n    CallExpression(path) {\n      if (pluginReferenced) {\n        path.stop();\n        return;\n      }\n      const callee = path.node.callee;\n      if (\n        callee.type === 'Identifier' &&\n        (pluginIdentifiers.has(callee.name) || callee.name === 'storybookTest')\n      ) {\n        pluginReferenced = true;\n        path.stop();\n      }\n    },\n  });\n\n  return pluginReferenced;\n}\n\n/**\n * Checks whether an existing config file uses `test.workspace` (Vitest 3.0-3.1 style) rather than\n * `test.projects` (Vitest 3.2+ style).\n */\nfunction configUsesWorkspace(configContent: string): boolean {\n  let ast: ReturnType<typeof babelParse>;\n  try {\n    ast = babelParse(configContent);\n  } catch {\n    return false;\n  }\n\n  let found = false;\n\n  traverse(ast, {\n    ObjectProperty(path) {\n      if (found) {\n        path.stop();\n        return;\n      }\n      const key = path.node.key;\n      if (key.type === 'Identifier' && key.name === 'workspace') {\n        // Check that this is inside a `test` property to avoid false positives\n        const parent = path.parentPath?.parentPath;\n        if (\n          parent?.isObjectProperty() &&\n          parent.node.key.type === 'Identifier' &&\n          parent.node.key.name === 'test'\n        ) {\n          found = true;\n          path.stop();\n        }\n      }\n    },\n  });\n\n  return found;\n}\n"
  },
  {
    "path": "code/addons/vitest/src/preset.ts",
    "content": "import { mkdir } from 'node:fs/promises';\n\nimport type { Channel } from 'storybook/internal/channels';\nimport {\n  createFileSystemCache,\n  getFrameworkName,\n  loadPreviewOrConfigFile,\n  resolvePathInStorybookCache,\n} from 'storybook/internal/common';\nimport {\n  type StoryIndexGenerator,\n  experimental_UniversalStore,\n  experimental_getTestProviderStore,\n} from 'storybook/internal/core-server';\nimport { logger } from 'storybook/internal/node-logger';\nimport { cleanPaths, oneWayHash, sanitizeError, telemetry } from 'storybook/internal/telemetry';\nimport type {\n  Options,\n  PresetPropertyFn,\n  PreviewAnnotation,\n  StoryId,\n} from 'storybook/internal/types';\n\nimport { isEqual } from 'es-toolkit/predicate';\nimport picocolors from 'picocolors';\nimport { dedent } from 'ts-dedent';\n\nimport {\n  ADDON_ID,\n  COVERAGE_DIRECTORY,\n  STORE_CHANNEL_EVENT_NAME,\n  STORYBOOK_ADDON_TEST_CHANNEL,\n  TRIGGER_TEST_RUN_REQUEST,\n  TRIGGER_TEST_RUN_RESPONSE,\n  type TriggerTestRunRequestPayload,\n  type TriggerTestRunResponsePayload,\n  storeOptions,\n} from './constants.ts';\nimport { log } from './logger.ts';\nimport { runTestRunner } from './node/boot-test-runner.ts';\nimport type { CachedState, ErrorLike, StoreState } from './types.ts';\nimport type { StoreEvent } from './types.ts';\n\ntype Event =\n  | {\n      type: 'test-discrepancy';\n      payload: {\n        storyId: StoryId;\n        browserStatus: 'PASS' | 'FAIL';\n        cliStatus: 'FAIL' | 'PASS';\n        message: string;\n      };\n    }\n  | {\n      type: 'test-run-completed';\n      payload: StoreState['currentRun'];\n    };\n\nexport const experimental_serverChannel = async (channel: Channel, options: Options) => {\n  const core = await options.presets.apply('core');\n\n  const previewPath = loadPreviewOrConfigFile({ configDir: options.configDir });\n  const previewAnnotations = await options.presets.apply<PreviewAnnotation[]>(\n    'previewAnnotations',\n    [],\n    options\n  );\n\n  const resolvedPreviewBuilder =\n    typeof core?.builder === 'string' ? core.builder : core?.builder?.name;\n  const framework = await getFrameworkName(options);\n\n  // Only boot the test runner if the builder is vite, else just provide interactions functionality\n  if (!resolvedPreviewBuilder?.includes('vite')) {\n    if (framework.includes('nextjs')) {\n      log(dedent`\n        You're using ${framework}, which is a Webpack-based builder. In order to use Storybook's Vitest addon, with your project, you need to use '@storybook/nextjs-vite', a high performance Vite-based equivalent.\n\n        Refer to the following documentation for more information: ${picocolors.yellow('https://storybook.js.org/docs/get-started/frameworks/nextjs-vite?ref=upgrade#choose-between-vite-and-webpack')}\\n\n      `);\n    }\n    return channel;\n  }\n\n  const storyIndexGenerator =\n    await options.presets.apply<Promise<StoryIndexGenerator>>('storyIndexGenerator');\n\n  const fsCache = createFileSystemCache({\n    basePath: resolvePathInStorybookCache(ADDON_ID.replace('/', '-')),\n    ns: 'storybook',\n    ttl: 14 * 24 * 60 * 60 * 1000, // 14 days\n  });\n  const cachedState: CachedState = await fsCache.get<CachedState>('state', {\n    config: storeOptions.initialState.config,\n  });\n\n  const selectCachedState = (s: Partial<StoreState>): Partial<CachedState> => ({\n    config: s.config,\n  });\n  const store = experimental_UniversalStore.create<StoreState, StoreEvent>({\n    ...storeOptions,\n    initialState: {\n      ...storeOptions.initialState,\n      previewAnnotations: (previewAnnotations ?? []).concat(previewPath ?? []),\n      index: await storyIndexGenerator.getIndex(),\n      ...selectCachedState(cachedState),\n    },\n    leader: true,\n  });\n  store.onStateChange((state, previousState) => {\n    if (!isEqual(selectCachedState(state), selectCachedState(previousState))) {\n      fsCache.set('state', selectCachedState(state));\n    }\n  });\n  const testProviderStore = experimental_getTestProviderStore(ADDON_ID);\n\n  storyIndexGenerator.onInvalidated(async () => {\n    try {\n      const index = await storyIndexGenerator.getIndex();\n      store.setState((s) => ({ ...s, index }));\n    } catch (error) {\n      logger.debug('Failed to update story index after invalidation, Error:');\n      logger.debug(error);\n    }\n  });\n\n  store.subscribe('TRIGGER_RUN', (event, eventInfo) => {\n    testProviderStore.setState('test-provider-state:running');\n    store.setState((s) => ({\n      ...s,\n      fatalError: undefined,\n    }));\n    runTestRunner({\n      channel,\n      store,\n      initEvent: STORE_CHANNEL_EVENT_NAME,\n      initArgs: [{ event, eventInfo }],\n      options,\n    });\n  });\n  store.subscribe('TOGGLE_WATCHING', (event, eventInfo) => {\n    store.setState((s) => ({\n      ...s,\n      watching: event.payload.to,\n      currentRun: {\n        ...s.currentRun,\n        // when enabling watch mode, clear the coverage summary too\n        ...(event.payload.to && {\n          coverageSummary: undefined,\n        }),\n      },\n    }));\n    if (event.payload.to) {\n      runTestRunner({\n        channel,\n        store,\n        initEvent: STORE_CHANNEL_EVENT_NAME,\n        initArgs: [{ event, eventInfo }],\n        options,\n      });\n    }\n  });\n  store.subscribe('FATAL_ERROR', (event) => {\n    const { message, error } = event.payload;\n    const name = error.name || 'Error';\n    log(`${name}: ${message}`);\n    if (error.stack) {\n      log(error.stack);\n    }\n\n    function logErrorWithCauses(err: ErrorLike) {\n      if (!err) {\n        return;\n      }\n\n      log(`Caused by: ${err.name ?? 'Error'}: ${err.message}`);\n\n      if (err.stack) {\n        log(err.stack);\n      }\n\n      if (err.cause) {\n        logErrorWithCauses(err.cause);\n      }\n    }\n\n    if (error.cause) {\n      logErrorWithCauses(error.cause);\n    }\n    store.setState((s) => ({\n      ...s,\n      fatalError: {\n        message,\n        error,\n      },\n    }));\n    testProviderStore.setState('test-provider-state:crashed');\n  });\n  testProviderStore.onClearAll(() => {\n    store.setState((s) => ({\n      ...s,\n      currentRun: { ...s.currentRun, coverageSummary: undefined, unhandledErrors: [] },\n    }));\n  });\n\n  // Programmatic test run trigger API\n  channel.on(TRIGGER_TEST_RUN_REQUEST, async (payload: TriggerTestRunRequestPayload) => {\n    const { requestId, actor, storyIds, config: configOverride } = payload;\n\n    const sendResponse = (response: Omit<TriggerTestRunResponsePayload, 'requestId'>) => {\n      channel.emit(TRIGGER_TEST_RUN_RESPONSE, { requestId, ...response });\n    };\n\n    await store.untilReady();\n\n    const {\n      currentRun: { startedAt, finishedAt },\n      config,\n    } = store.getState();\n    if (startedAt && !finishedAt) {\n      sendResponse({\n        status: 'error',\n        error: { message: 'Tests are already running' },\n      });\n      return;\n    }\n\n    store.send({\n      type: 'TRIGGER_RUN',\n      payload: {\n        storyIds,\n        triggeredBy: `external:${actor}`,\n        ...(configOverride && {\n          configOverride: { ...config, ...configOverride },\n        }),\n      },\n    });\n\n    const unsubscribe = store.subscribe((event) => {\n      switch (event.type) {\n        case 'TEST_RUN_COMPLETED': {\n          unsubscribe();\n          sendResponse({ status: 'completed', result: event.payload });\n          return;\n        }\n        case 'FATAL_ERROR': {\n          unsubscribe();\n          sendResponse({ status: 'error', error: event.payload });\n          return;\n        }\n        case 'CANCEL_RUN': {\n          unsubscribe();\n          sendResponse({ status: 'cancelled' });\n          return;\n        }\n      }\n    });\n  });\n\n  if (!core.disableTelemetry) {\n    const enableCrashReports = core.enableCrashReports || options.enableCrashReports;\n\n    channel.on(STORYBOOK_ADDON_TEST_CHANNEL, (event: Event) => {\n      if (event.type !== 'test-run-completed') {\n        telemetry('addon-test', {\n          ...event,\n          payload: {\n            ...event.payload,\n            storyId: oneWayHash(event.payload.storyId),\n          },\n        });\n      }\n    });\n\n    store.subscribe('TOGGLE_WATCHING', async (event) => {\n      await telemetry('addon-test', {\n        watchMode: event.payload.to,\n      });\n    });\n    store.subscribe('TEST_RUN_COMPLETED', async (event) => {\n      const { unhandledErrors, startedAt, finishedAt, ...currentRun } = event.payload;\n      await telemetry('addon-test', {\n        ...currentRun,\n        duration: (finishedAt ?? 0) - (startedAt ?? 0),\n        unhandledErrorCount: unhandledErrors.length,\n        ...(enableCrashReports &&\n          unhandledErrors.length > 0 && {\n            unhandledErrors: unhandledErrors.map((error) => {\n              const { stacks, ...errorWithoutStacks } = error;\n              return sanitizeError(errorWithoutStacks);\n            }),\n          }),\n      });\n    });\n\n    if (enableCrashReports) {\n      store.subscribe('FATAL_ERROR', async (event) => {\n        await telemetry('addon-test', {\n          fatalError: cleanPaths(event.payload.error.message),\n        });\n      });\n    }\n  }\n\n  return channel;\n};\n\nexport const staticDirs: PresetPropertyFn<'staticDirs'> = async (values = [], options) => {\n  if (options.configType === 'PRODUCTION') {\n    return values;\n  }\n\n  const coverageDirectory = resolvePathInStorybookCache(COVERAGE_DIRECTORY);\n  await mkdir(coverageDirectory, { recursive: true });\n  return [\n    {\n      from: coverageDirectory,\n      to: '/coverage',\n    },\n    ...values,\n  ];\n};\n"
  },
  {
    "path": "code/addons/vitest/src/stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { expect } from 'storybook/test';\n\nconst meta = {\n  title: 'StoriesTsx',\n  render: () => <div>This is a story coming from a /stories.tsx file detected via custom glob</div>,\n} satisfies Meta;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {\n  play: async () => {\n    expect(true).toBe(true);\n  },\n};\n"
  },
  {
    "path": "code/addons/vitest/src/types.ts",
    "content": "import type { experimental_UniversalStore } from 'storybook/internal/core-server';\nimport type { PreviewAnnotation, Status, StoryId, StoryIndex } from 'storybook/internal/types';\nimport type { API_HashEntry } from 'storybook/internal/types';\n\n// import type { A11yReport } from '@storybook/addon-a11y';\n// TODO: There's a type error in axe-core that makes this error during production builds\ntype A11yReport = any;\n\nexport interface VitestError extends Error {\n  VITEST_TEST_PATH?: string;\n  VITEST_TEST_NAME?: string;\n  stacks?: Array<{\n    line: number;\n    column: number;\n    file: string;\n    method: string;\n  }>;\n}\n\nexport type ErrorLike = {\n  message: string;\n  name?: string;\n  stack?: string;\n  cause?: ErrorLike;\n};\n\nexport type RunTrigger =\n  | 'run-all'\n  | 'global'\n  | 'watch'\n  | Extract<API_HashEntry['type'], string>\n  | `external:${string}`;\n\nexport type CurrentRun = {\n  triggeredBy: RunTrigger | undefined;\n  config: StoreState['config'];\n  componentTestStatuses: Status[];\n  a11yStatuses: Status[];\n  componentTestCount: {\n    success: number;\n    error: number;\n  };\n  a11yCount: {\n    success: number;\n    warning: number;\n    error: number;\n  };\n  a11yReports: Record<StoryId, A11yReport[]>;\n  totalTestCount: number | undefined;\n  storyIds: StoryId[] | undefined;\n  startedAt: number | undefined;\n  finishedAt: number | undefined;\n  unhandledErrors: VitestError[];\n  coverageSummary:\n    | {\n        status: 'positive' | 'warning' | 'negative' | 'unknown';\n        percentage: number;\n      }\n    | undefined;\n};\n\nexport type StoreState = {\n  config: {\n    coverage: boolean;\n    a11y: boolean;\n  };\n  watching: boolean;\n  cancelling: boolean;\n  index: StoryIndex;\n  previewAnnotations: PreviewAnnotation[];\n  fatalError:\n    | {\n        message: string | undefined;\n        error: ErrorLike;\n      }\n    | undefined;\n  currentRun: CurrentRun;\n};\n\nexport type CachedState = Pick<StoreState, 'config'>;\n\nexport type TriggerRunEvent = {\n  type: 'TRIGGER_RUN';\n  payload: {\n    storyIds?: string[] | undefined;\n    triggeredBy: RunTrigger;\n    configOverride?: StoreState['config'];\n  };\n};\n\nexport type CancelRunEvent = {\n  type: 'CANCEL_RUN';\n};\nexport type ToggleWatchingEvent = {\n  type: 'TOGGLE_WATCHING';\n  payload: {\n    to: boolean;\n  };\n};\nexport type FatalErrorEvent = {\n  type: 'FATAL_ERROR';\n  payload: {\n    message: string;\n    error: ErrorLike;\n  };\n};\nexport type TestRunCompletedEvent = {\n  type: 'TEST_RUN_COMPLETED';\n  payload: StoreState['currentRun'];\n};\nexport type StoreEvent =\n  | TriggerRunEvent\n  | CancelRunEvent\n  | FatalErrorEvent\n  | ToggleWatchingEvent\n  | TestRunCompletedEvent;\n\nexport type Store = ReturnType<typeof experimental_UniversalStore.create<StoreState, StoreEvent>>;\n"
  },
  {
    "path": "code/addons/vitest/src/typings.d.ts",
    "content": "declare const BROWSER_CONFIG: object;\ndeclare var STORYBOOK_BUILDER: import('storybook/internal/types').SupportedBuilder | undefined;\n\ninterface ImportMetaEnv {\n  __STORYBOOK_URL__?: string;\n}\n\ninterface ImportMeta {\n  readonly env: ImportMetaEnv;\n}\n\ndeclare module '*?raw' {\n  const content: string;\n  export default content;\n}\n"
  },
  {
    "path": "code/addons/vitest/src/updateVitestFile.config.3.2.test.ts",
    "content": "import { join } from 'node:path';\n\nimport { describe, expect, it, vi } from 'vitest';\n\nimport * as babel from 'storybook/internal/babel';\n\nimport { getDiff } from '../../../core/src/core-server/utils/save-story/getDiff.ts';\nimport { loadTemplate, updateConfigFile } from './updateVitestFile.ts';\n\nvi.mock('storybook/internal/node-logger', () => ({\n  logger: {\n    info: vi.fn(),\n    warn: vi.fn(),\n    error: vi.fn(),\n  },\n}));\n\nvi.mock('../../../core/src/shared/utils/module', () => ({\n  resolvePackageDir: vi.fn().mockImplementation(() => join(__dirname, '..')),\n}));\n\ndescribe('updateConfigFile', () => {\n  it('updates vite config file with existing workspace (falls back to workspace template)', async () => {\n    // When Vitest 3.2 user still has deprecated `workspace` key, postinstall should\n    // detect this and use the old workspace-based template to append to the existing array\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import { defineConfig } from 'vite'\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default defineConfig({\n        plugins: [react()],\n        test: {\n          globals: true,\n          workspace: ['packages/*']\n        },\n      })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly — appends to existing workspace array\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import react from '@vitejs/plugin-react';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig({\n          plugins: [react()],\n          test: {\n            globals: true,\n        \n      -     workspace: ['packages/*']\n      - \n      +     workspace: ['packages/*', {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        });\"\n    `);\n  });\n\n  it('supports object notation without defineConfig with existing workspace (falls back to workspace template)', async () => {\n    // Same as above: existing `workspace` in target means postinstall uses old template\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default {\n        plugins: [react()],\n        test: {\n          globals: true,\n          workspace: ['packages/*']\n        },\n      }\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly — appends to existing workspace array\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import react from '@vitejs/plugin-react';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineConfig } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default {\n          plugins: [react()],\n          test: {\n            globals: true,\n        \n      -     workspace: ['packages/*']\n      - \n      +     workspace: ['packages/*', {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        };\"\n    `);\n  });\n\n  it('does not support function notation', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default defineConfig(() => ({\n        plugins: [react()],\n        test: {\n          globals: true,\n          projects: ['packages/*']\n        },\n      }))\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(false);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was NOT updated\n    expect(after).toBe(before);\n  });\n\n  it('adds projects property to test config', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import { defineConfig } from 'vite'\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default defineConfig({\n        plugins: [react()],\n        test: {\n          globals: true,\n        },\n      })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import react from '@vitejs/plugin-react';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig({\n          plugins: [react()],\n          test: {\n        \n      -     globals: true\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         globals: true\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        });\"\n    `);\n  });\n\n  it('updates config which is not exported immediately', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { defineConfig } from 'vite'\n      import viteReact from '@vitejs/plugin-react'\n      import { fileURLToPath, URL } from 'url'\n\n      const config = defineConfig({\n        resolve: {\n          preserveSymlinks: true,\n          alias: {\n            '@': fileURLToPath(new URL('./src', import.meta.url)),\n          },\n        },\n        plugins: [\n          viteReact(),\n        ],\n      })\n\n      export default config\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n  \"  import { defineConfig } from 'vite';\n    import viteReact from '@vitejs/plugin-react';\n    import { fileURLToPath, URL } from 'url';\n    \n  + import path from 'node:path';\n  + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n  + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n  + \n  + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n  + \n    const config = defineConfig({\n      resolve: {\n        preserveSymlinks: true,\n        alias: {\n          '@': fileURLToPath(new URL('./src', import.meta.url))\n        }\n      },\n    \n  -   plugins: [viteReact()]\n  - \n  +   plugins: [viteReact()],\n  +   test: {\n  +     projects: [{\n  +       extends: true,\n  +       plugins: [\n  +       // The plugin will run tests for the stories defined in your Storybook config\n  +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n  +       storybookTest({\n  +         configDir: path.join(dirname, '.storybook')\n  +       })],\n  +       test: {\n  +         name: 'storybook',\n  +         browser: {\n  +           enabled: true,\n  +           headless: true,\n  +           provider: 'playwright',\n  +           instances: [{\n  +             browser: 'chromium'\n  +           }]\n  +         }\n  +       }\n  +     }]\n  +   }\n  + \n    });\n    export default config;\"\n`);\n  });\n\n  it('edits projects property of test config', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import { defineConfig } from 'vite'\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default defineConfig({\n        plugins: [react()],\n        test: {\n          globals: true,\n          projects: ['packages/*', {some: 'config'}]\n        }\n      })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import react from '@vitejs/plugin-react';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig({\n          plugins: [react()],\n          test: {\n            globals: true,\n            projects: ['packages/*', {\n              some: 'config'\n        \n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      + \n            }]\n          }\n        });\"\n    `);\n  });\n\n  it('adds workspace property to test config', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import { defineConfig } from 'vite'\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default defineConfig({\n        plugins: [react()],\n        test: {\n          globals: true,\n        },\n      })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import react from '@vitejs/plugin-react';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig({\n          plugins: [react()],\n          test: {\n        \n      -     globals: true\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         globals: true\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        });\"\n    `);\n  });\n\n  it('adds test property to vite config', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import { defineConfig } from 'vite'\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default defineConfig({\n        plugins: [react()],\n      })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import react from '@vitejs/plugin-react';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig({\n        \n      -   plugins: [react()]\n      - \n      +   plugins: [react()],\n      +   test: {\n      +     projects: [{\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      +   }\n      + \n        });\"\n    `);\n  });\n\n  it('supports mergeConfig with multiple defineConfig calls, finding the one with test', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig } from 'vite'\n      import { defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          plugins: [react()],\n        }),\n        defineConfig({\n          test: {\n            environment: 'jsdom',\n          }\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig } from 'vite';\n        import { defineConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n          plugins: [react()]\n        }), defineConfig({\n          test: {\n        \n      -     environment: 'jsdom'\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         environment: 'jsdom'\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\"\n    `);\n  });\n  it('supports mergeConfig without defineConfig calls', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig } from 'vite'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        {\n          plugins: [react()],\n          test: {\n            environment: 'jsdom',\n          }\n        }\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig } from 'vite';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineConfig } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, {\n          plugins: [react()],\n          test: {\n        \n      -     environment: 'jsdom'\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         environment: 'jsdom'\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        });\"\n    `);\n  });\n\n  it('supports mergeConfig without config containing test property', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig } from 'vite'\n      import { defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          plugins: [react()],\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig } from 'vite';\n        import { defineConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n        \n      -   plugins: [react()]\n      - \n      +   plugins: [react()],\n      +   test: {\n      +     projects: [{\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      +   }\n      + \n        }));\"\n    `);\n  });\n\n  it('supports mergeConfig with defineConfig pattern using projects (Vitest 3.2+)', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import { mergeConfig, defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      // https://vite.dev/config/\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          test: {\n            globals: true,\n          },\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import viteConfig from './vite.config';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n          test: {\n        \n      -     globals: true\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         globals: true\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\"\n    `);\n  });\n\n  it('appends storybook project to existing test.projects array (no double nesting)', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig, defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          test: {\n            expect: { requireAssertions: true },\n            projects: [\n              {\n                extends: \"./vite.config.ts\",\n                test: { name: \"client\" },\n              },\n              {\n                extends: \"./vite.config.ts\",\n                test: { name: \"server\" },\n              },\n            ],\n          },\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly (storybook project appended to existing projects, no double nesting)\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig, defineConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n          test: {\n            expect: {\n              requireAssertions: true\n      ...\n              test: {\n                name: \"server\"\n              }\n        \n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      + \n            }]\n          }\n        }));\"\n    `);\n  });\n\n  it('extracts coverage config and keeps it at top level when using workspace', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig, defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          test: {\n            name: 'node',\n            environment: 'happy-dom',\n            include: ['**/*.test.ts'],\n            coverage: {\n              exclude: [\n                'storybook.setup.ts',\n                '**/*.stories.*',\n              ],\n            },\n          },\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    // Coverage should stay at the top level, not moved into the workspace\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig, defineConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts'],\n      - \n            coverage: {\n              exclude: ['storybook.setup.ts', '**/*.stories.*']\n        \n      -     }\n      - \n      +     },\n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\"\n    `);\n  });\n\n  it('extracts coverage config and keeps it at top level when using projects', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig, defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          test: {\n            name: 'node',\n            environment: 'happy-dom',\n            include: ['**/*.test.ts'],\n            coverage: {\n              exclude: [\n                'storybook.setup.ts',\n                '**/*.stories.*',\n              ],\n            },\n          },\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    // Coverage should stay at the top level, not moved into the projects\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig, defineConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts'],\n      - \n            coverage: {\n              exclude: ['storybook.setup.ts', '**/*.stories.*']\n        \n      -     }\n      - \n      +     },\n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\"\n    `);\n  });\n\n  it('supports defineConfig wrapping mergeConfig', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { defineConfig, mergeConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default defineConfig(mergeConfig(viteConfig, {\n        test: {\n          name: 'node',\n          environment: 'happy-dom',\n          include: ['**/*.test.ts'],\n        },\n      }))\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { defineConfig, mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig(mergeConfig(viteConfig, {\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\"\n    `);\n  });\n\n  it('supports defineConfig wrapping mergeConfig with satisfies operator', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { defineConfig, mergeConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n      import type { ViteUserConfig } from 'vitest/config'\n\n      export default defineConfig(\n        mergeConfig(viteConfig, {\n          test: {\n            name: 'node',\n            environment: 'happy-dom',\n            include: ['**/*.test.ts'],\n          },\n        }) satisfies ViteUserConfig\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { defineConfig, mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        import type { ViteUserConfig } from 'vitest/config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig(mergeConfig(viteConfig, {\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }) satisfies ViteUserConfig);\"\n    `);\n  });\n\n  it('supports mergeConfig with as operator (TSAsExpression)', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n      import type { ViteUserConfig } from 'vitest/config'\n\n      export default mergeConfig(viteConfig, {\n        test: {\n          name: 'node',\n          environment: 'happy-dom',\n          include: ['**/*.test.ts'],\n        },\n      }) as ViteUserConfig\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        import type { ViteUserConfig } from 'vitest/config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineConfig } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, {\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }) as ViteUserConfig;\"\n    `);\n  });\n\n  it('supports mergeConfig with test defined as a constant (shorthand property)', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      const test = {\n        name: 'node',\n        environment: 'happy-dom',\n        include: ['**/*.test.ts'],\n      }\n\n      export default mergeConfig(viteConfig, { test })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineConfig } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        const test = {\n          name: 'node',\n          environment: 'happy-dom',\n          include: ['**/*.test.ts']\n        };\n        export default mergeConfig(viteConfig, {\n        \n      -   test\n      - \n      +   test: {\n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      +   }\n      + \n        });\"\n    `);\n  });\n\n  it('supports const defined config re-exported (export default config)', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { defineConfig, mergeConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      const config = mergeConfig(\n        viteConfig,\n        defineConfig({\n          test: {\n            name: 'node',\n            environment: 'happy-dom',\n            include: ['**/*.test.ts'],\n          },\n        })\n      )\n\n      export default config\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { defineConfig, mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        const config = mergeConfig(viteConfig, defineConfig({\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\n        export default config;\"\n    `);\n  });\n\n  it('supports defineProject instead of defineConfig', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { defineProject } from 'vitest/config'\n\n      export default defineProject({\n        test: {\n          name: 'node',\n          environment: 'happy-dom',\n          include: ['**/*.test.ts'],\n        },\n      })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { defineProject } from 'vitest/config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineConfig } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineProject({\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        });\"\n    `);\n  });\n\n  it('supports mergeConfig with config object as a constant variable', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      const vitestConfig = {\n        test: {\n          name: 'node',\n          environment: 'happy-dom',\n          include: ['**/*.test.ts'],\n        }\n      }\n\n      export default mergeConfig(viteConfig, vitestConfig)\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineConfig } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        const vitestConfig = {\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        };\n        export default mergeConfig(viteConfig, vitestConfig);\"\n    `);\n  });\n\n  it('keeps coverage at top level instead of moving into projects', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig, defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          test: {\n            name: 'unit',\n            environment: 'happy-dom',\n            include: ['**/*.test.ts'],\n            env: { CI: 'true' },\n            pool: 'forks',\n            maxWorkers: 4,\n            coverage: {\n              provider: 'v8',\n              exclude: ['**/*.stories.*'],\n            },\n          },\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig, defineConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n          test: {\n        \n      -     name: 'unit',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts'],\n      -     env: {\n      -       CI: 'true'\n      -     },\n      -     pool: 'forks',\n      -     maxWorkers: 4,\n      - \n            coverage: {\n              provider: 'v8',\n              exclude: ['**/*.stories.*']\n        \n      -     }\n      - \n      +     },\n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'unit',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts'],\n      +         env: {\n      +           CI: 'true'\n      +         },\n      +         pool: 'forks',\n      +         maxWorkers: 4\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\"\n    `);\n  });\n});\n"
  },
  {
    "path": "code/addons/vitest/src/updateVitestFile.config.4.test.ts",
    "content": "import { join } from 'node:path';\n\nimport { describe, expect, it, vi } from 'vitest';\n\nimport * as babel from 'storybook/internal/babel';\n\nimport { getDiff } from '../../../core/src/core-server/utils/save-story/getDiff.ts';\nimport { loadTemplate, updateConfigFile } from './updateVitestFile.ts';\n\nvi.mock('storybook/internal/node-logger', () => ({\n  logger: {\n    info: vi.fn(),\n    warn: vi.fn(),\n    error: vi.fn(),\n  },\n}));\n\nvi.mock('../../../core/src/shared/utils/module', () => ({\n  resolvePackageDir: vi.fn().mockImplementation(() => join(__dirname, '..')),\n}));\n\ndescribe('updateConfigFile', () => {\n  it('updates vite config file with existing projects', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    // In Vitest 4, `workspace` doesn't exist — users have `projects`\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import { defineConfig } from 'vite'\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default defineConfig({\n        plugins: [react()],\n        test: {\n          globals: true,\n          projects: ['packages/*']\n        },\n      })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly — appends to existing projects array\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import react from '@vitejs/plugin-react';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig({\n          plugins: [react()],\n          test: {\n            globals: true,\n        \n      -     projects: ['packages/*']\n      - \n      +     projects: ['packages/*', {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        });\"\n    `);\n  });\n\n  it('supports object notation without defineConfig with existing projects', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    // In Vitest 4, `workspace` doesn't exist — users have `projects`\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default {\n        plugins: [react()],\n        test: {\n          globals: true,\n          projects: ['packages/*']\n        },\n      }\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly — appends to existing projects array\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import react from '@vitejs/plugin-react';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineConfig } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default {\n          plugins: [react()],\n          test: {\n            globals: true,\n        \n      -     projects: ['packages/*']\n      - \n      +     projects: ['packages/*', {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        };\"\n    `);\n  });\n\n  it('does not support function notation', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default defineConfig(() => ({\n        plugins: [react()],\n        test: {\n          globals: true,\n          projects: ['packages/*']\n        },\n      }))\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(false);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was NOT updated\n    expect(after).toBe(before);\n  });\n\n  it('adds projects property to test config', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import { defineConfig } from 'vite'\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default defineConfig({\n        plugins: [react()],\n        test: {\n          globals: true,\n        },\n      })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import react from '@vitejs/plugin-react';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig({\n          plugins: [react()],\n          test: {\n        \n      -     globals: true\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         globals: true\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        });\"\n    `);\n  });\n\n  it('updates config which is not exported immediately', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { defineConfig } from 'vite'\n      import viteReact from '@vitejs/plugin-react'\n      import { fileURLToPath, URL } from 'url'\n\n      const config = defineConfig({\n        resolve: {\n          preserveSymlinks: true,\n          alias: {\n            '@': fileURLToPath(new URL('./src', import.meta.url)),\n          },\n        },\n        plugins: [\n          viteReact(),\n        ],\n      })\n\n      export default config\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { defineConfig } from 'vite';\n        import viteReact from '@vitejs/plugin-react';\n        import { fileURLToPath, URL } from 'url';\n        \n      + import path from 'node:path';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        const config = defineConfig({\n          resolve: {\n            preserveSymlinks: true,\n            alias: {\n              '@': fileURLToPath(new URL('./src', import.meta.url))\n            }\n          },\n        \n      -   plugins: [viteReact()]\n      - \n      +   plugins: [viteReact()],\n      +   test: {\n      +     projects: [{\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      +   }\n      + \n        });\n        export default config;\"\n    `);\n  });\n\n  it('edits projects property of test config', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import { defineConfig } from 'vite'\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default defineConfig({\n        plugins: [react()],\n        test: {\n          globals: true,\n          projects: ['packages/*', {some: 'config'}]\n        }\n      })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import react from '@vitejs/plugin-react';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig({\n          plugins: [react()],\n          test: {\n            globals: true,\n            projects: ['packages/*', {\n              some: 'config'\n        \n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      + \n            }]\n          }\n        });\"\n    `);\n  });\n\n  it('adds projects property to test config', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import { defineConfig } from 'vite'\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default defineConfig({\n        plugins: [react()],\n        test: {\n          globals: true,\n        },\n      })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import react from '@vitejs/plugin-react';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig({\n          plugins: [react()],\n          test: {\n        \n      -     globals: true\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         globals: true\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        });\"\n    `);\n  });\n\n  it('adds test property to vite config', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import { defineConfig } from 'vite'\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default defineConfig({\n        plugins: [react()],\n      })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import react from '@vitejs/plugin-react';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig({\n        \n      -   plugins: [react()]\n      - \n      +   plugins: [react()],\n      +   test: {\n      +     projects: [{\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      +   }\n      + \n        });\"\n    `);\n  });\n\n  it('supports mergeConfig with multiple defineConfig calls, finding the one with test', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig } from 'vite'\n      import { defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          plugins: [react()],\n        }),\n        defineConfig({\n          test: {\n            environment: 'jsdom',\n          }\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig } from 'vite';\n        import { defineConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n          plugins: [react()]\n        }), defineConfig({\n          test: {\n        \n      -     environment: 'jsdom'\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         environment: 'jsdom'\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\"\n    `);\n  });\n  it('supports mergeConfig without defineConfig calls', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig } from 'vite'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        {\n          plugins: [react()],\n          test: {\n            environment: 'jsdom',\n          }\n        }\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig } from 'vite';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineConfig } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, {\n          plugins: [react()],\n          test: {\n        \n      -     environment: 'jsdom'\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         environment: 'jsdom'\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        });\"\n    `);\n  });\n\n  it('supports mergeConfig without config containing test property', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig } from 'vite'\n      import { defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          plugins: [react()],\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig } from 'vite';\n        import { defineConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n        \n      -   plugins: [react()]\n      - \n      +   plugins: [react()],\n      +   test: {\n      +     projects: [{\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      +   }\n      + \n        }));\"\n    `);\n  });\n\n  it('supports mergeConfig with defineConfig pattern using projects (Vitest 3.2+)', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import { mergeConfig, defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      // https://vite.dev/config/\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          test: {\n            globals: true,\n          },\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import viteConfig from './vite.config';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n          test: {\n        \n      -     globals: true\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         globals: true\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\"\n    `);\n  });\n\n  it('appends storybook project to existing test.projects array (no double nesting)', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig, defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          test: {\n            expect: { requireAssertions: true },\n            projects: [\n              {\n                extends: \"./vite.config.ts\",\n                test: { name: \"client\" },\n              },\n              {\n                extends: \"./vite.config.ts\",\n                test: { name: \"server\" },\n              },\n            ],\n          },\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly (storybook project appended to existing projects, no double nesting)\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig, defineConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n          test: {\n            expect: {\n              requireAssertions: true\n      ...\n              test: {\n                name: \"server\"\n              }\n        \n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      + \n            }]\n          }\n        }));\"\n    `);\n  });\n\n  it('extracts coverage config and keeps it at top level when using workspace', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig, defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          test: {\n            name: 'node',\n            environment: 'happy-dom',\n            include: ['**/*.test.ts'],\n            coverage: {\n              exclude: [\n                'storybook.setup.ts',\n                '**/*.stories.*',\n              ],\n            },\n          },\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    // Coverage should stay at the top level, not moved into the workspace\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig, defineConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts'],\n      - \n            coverage: {\n              exclude: ['storybook.setup.ts', '**/*.stories.*']\n        \n      -     }\n      - \n      +     },\n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\"\n    `);\n  });\n\n  it('extracts coverage config and keeps it at top level when using projects', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig, defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          test: {\n            name: 'node',\n            environment: 'happy-dom',\n            include: ['**/*.test.ts'],\n            coverage: {\n              exclude: [\n                'storybook.setup.ts',\n                '**/*.stories.*',\n              ],\n            },\n          },\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    // Coverage should stay at the top level, not moved into the projects\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig, defineConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts'],\n      - \n            coverage: {\n              exclude: ['storybook.setup.ts', '**/*.stories.*']\n        \n      -     }\n      - \n      +     },\n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\"\n    `);\n  });\n\n  it('supports defineConfig wrapping mergeConfig', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { defineConfig, mergeConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default defineConfig(mergeConfig(viteConfig, {\n        test: {\n          name: 'node',\n          environment: 'happy-dom',\n          include: ['**/*.test.ts'],\n        },\n      }))\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { defineConfig, mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig(mergeConfig(viteConfig, {\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\"\n    `);\n  });\n\n  it('supports defineConfig wrapping mergeConfig with satisfies operator', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { defineConfig, mergeConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n      import type { ViteUserConfig } from 'vitest/config'\n\n      export default defineConfig(\n        mergeConfig(viteConfig, {\n          test: {\n            name: 'node',\n            environment: 'happy-dom',\n            include: ['**/*.test.ts'],\n          },\n        }) satisfies ViteUserConfig\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { defineConfig, mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        import type { ViteUserConfig } from 'vitest/config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig(mergeConfig(viteConfig, {\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }) satisfies ViteUserConfig);\"\n    `);\n  });\n\n  it('supports mergeConfig with as operator (TSAsExpression)', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n      import type { ViteUserConfig } from 'vitest/config'\n\n      export default mergeConfig(viteConfig, {\n        test: {\n          name: 'node',\n          environment: 'happy-dom',\n          include: ['**/*.test.ts'],\n        },\n      }) as ViteUserConfig\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        import type { ViteUserConfig } from 'vitest/config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineConfig } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, {\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }) as ViteUserConfig;\"\n    `);\n  });\n\n  it('supports mergeConfig with test defined as a constant (shorthand property)', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      const test = {\n        name: 'node',\n        environment: 'happy-dom',\n        include: ['**/*.test.ts'],\n      }\n\n      export default mergeConfig(viteConfig, { test })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineConfig } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        const test = {\n          name: 'node',\n          environment: 'happy-dom',\n          include: ['**/*.test.ts']\n        };\n        export default mergeConfig(viteConfig, {\n        \n      -   test\n      - \n      +   test: {\n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      +   }\n      + \n        });\"\n    `);\n  });\n\n  it('supports const defined config re-exported (export default config)', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { defineConfig, mergeConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      const config = mergeConfig(\n        viteConfig,\n        defineConfig({\n          test: {\n            name: 'node',\n            environment: 'happy-dom',\n            include: ['**/*.test.ts'],\n          },\n        })\n      )\n\n      export default config\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { defineConfig, mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        const config = mergeConfig(viteConfig, defineConfig({\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\n        export default config;\"\n    `);\n  });\n\n  it('supports defineProject instead of defineConfig', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { defineProject } from 'vitest/config'\n\n      export default defineProject({\n        test: {\n          name: 'node',\n          environment: 'happy-dom',\n          include: ['**/*.test.ts'],\n        },\n      })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { defineProject } from 'vitest/config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineConfig } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineProject({\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        });\"\n    `);\n  });\n\n  it('supports export const config re-exported as default (ExportNamedDeclaration)', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n        import { defineConfig, mergeConfig } from 'vitest/config'\n        import viteConfig from './vite.config'\n  \n        export const config = mergeConfig(\n          viteConfig,\n          defineConfig({\n            test: {\n              name: 'node',\n              environment: 'happy-dom',\n              include: ['**/*.test.ts'],\n            },\n          })\n        )\n  \n        export default config\n      `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { defineConfig, mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export const config = mergeConfig(viteConfig, defineConfig({\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\n        export default config;\"\n    `);\n  });\n\n  it('supports mergeConfig with config object as an exported constant (ExportNamedDeclaration)', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n        import { mergeConfig } from 'vitest/config'\n        import viteConfig from './vite.config'\n  \n        export const vitestConfig = {\n          test: {\n            name: 'node',\n            environment: 'happy-dom',\n            include: ['**/*.test.ts'],\n          }\n        }\n  \n        export default mergeConfig(viteConfig, vitestConfig)\n      `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineConfig } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export const vitestConfig = {\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        };\n        export default mergeConfig(viteConfig, vitestConfig);\"\n    `);\n  });\n\n  it('supports mergeConfig with config object as a constant variable', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      const vitestConfig = {\n        test: {\n          name: 'node',\n          environment: 'happy-dom',\n          include: ['**/*.test.ts'],\n        }\n      }\n\n      export default mergeConfig(viteConfig, vitestConfig)\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineConfig } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        const vitestConfig = {\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        };\n        export default mergeConfig(viteConfig, vitestConfig);\"\n    `);\n  });\n\n  it('supports mergeConfig with aliased defineConfig and updates the config that contains test', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import react from \"@vitejs/plugin-react\";\n      import { playwright } from \"@vitest/browser-playwright\";\n      import { defineConfig, mergeConfig } from \"vite\";\n      import tsconfigPaths from \"vite-tsconfig-paths\";\n      import { defineConfig as defineVitestConfig } from \"vitest/config\";\n\n      // https://vitejs.dev/config/\n      const viteConfig = defineConfig({\n        plugins: [tsconfigPaths(), react()],\n        optimizeDeps: {\n          exclude: [\"@xmtp/wasm-bindings\"],\n        },\n        server: {\n          allowedHosts: true,\n        },\n        build: {\n          sourcemap: true,\n        },\n      });\n\n      const vitestConfig = defineVitestConfig({\n        test: {\n          browser: {\n            provider: playwright(),\n            enabled: true,\n            headless: true,\n            screenshotFailures: false,\n            instances: [\n              {\n                browser: \"chromium\",\n              },\n            ],\n          },\n          testTimeout: 120000,\n        },\n      });\n\n      export default mergeConfig(viteConfig, vitestConfig);\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import { defineConfig as defineVitestConfig } from \"vitest/config\";\n        \n        // https://vitejs.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        const viteConfig = defineConfig({\n          plugins: [tsconfigPaths(), react()],\n          optimizeDeps: {\n            exclude: [\"@xmtp/wasm-bindings\"]\n      ...\n        });\n        const vitestConfig = defineVitestConfig({\n          test: {\n        \n      -     browser: {\n      -       provider: playwright(),\n      -       enabled: true,\n      -       headless: true,\n      -       screenshotFailures: false,\n      -       instances: [{\n      -         browser: \"chromium\"\n      -       }]\n      -     },\n      -     testTimeout: 120000\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         browser: {\n      +           provider: playwright(),\n      +           enabled: true,\n      +           headless: true,\n      +           screenshotFailures: false,\n      +           instances: [{\n      +             browser: \"chromium\"\n      +           }]\n      +         },\n      +         testTimeout: 120000\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        });\n        export default mergeConfig(viteConfig, vitestConfig);\"\n    `);\n  });\n\n  it('keeps coverage at top level instead of moving into projects', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.4.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig, defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          test: {\n            name: 'unit',\n            environment: 'happy-dom',\n            include: ['**/*.test.ts'],\n            env: { CI: 'true' },\n            pool: 'forks',\n            maxWorkers: 4,\n            coverage: {\n              provider: 'v8',\n              exclude: ['**/*.stories.*'],\n            },\n          },\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig, defineConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + import { playwright } from '@vitest/browser-playwright';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n          test: {\n        \n      -     name: 'unit',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts'],\n      -     env: {\n      -       CI: 'true'\n      -     },\n      -     pool: 'forks',\n      -     maxWorkers: 4,\n      - \n            coverage: {\n              provider: 'v8',\n              exclude: ['**/*.stories.*']\n        \n      -     }\n      - \n      +     },\n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'unit',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts'],\n      +         env: {\n      +           CI: 'true'\n      +         },\n      +         pool: 'forks',\n      +         maxWorkers: 4\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: playwright({}),\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\"\n    `);\n  });\n});\n"
  },
  {
    "path": "code/addons/vitest/src/updateVitestFile.config.test.ts",
    "content": "import { join } from 'node:path';\n\nimport { describe, expect, it, vi } from 'vitest';\n\nimport * as babel from 'storybook/internal/babel';\n\nimport { getDiff } from '../../../core/src/core-server/utils/save-story/getDiff.ts';\nimport { loadTemplate, updateConfigFile } from './updateVitestFile.ts';\n\nvi.mock('storybook/internal/node-logger', () => ({\n  logger: {\n    info: vi.fn(),\n    warn: vi.fn(),\n    error: vi.fn(),\n  },\n}));\n\nvi.mock('../../../core/src/shared/utils/module', () => ({\n  resolvePackageDir: vi.fn().mockImplementation(() => join(__dirname, '..')),\n}));\n\ndescribe('updateConfigFile', () => {\n  it('updates vite config file', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import { defineConfig } from 'vite'\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default defineConfig({\n        plugins: [react()],\n        test: {\n          globals: true,\n          workspace: ['packages/*']\n        },\n      })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import react from '@vitejs/plugin-react';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig({\n          plugins: [react()],\n          test: {\n            globals: true,\n        \n      -     workspace: ['packages/*']\n      - \n      +     workspace: ['packages/*', {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        });\"\n    `);\n  });\n\n  it('supports object notation without defineConfig', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default {\n        plugins: [react()],\n        test: {\n          globals: true,\n          workspace: ['packages/*']\n        },\n      }\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import react from '@vitejs/plugin-react';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineConfig } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default {\n          plugins: [react()],\n          test: {\n            globals: true,\n        \n      -     workspace: ['packages/*']\n      - \n      +     workspace: ['packages/*', {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        };\"\n    `);\n  });\n\n  it('does not support function notation', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default defineConfig(() => ({\n        plugins: [react()],\n        test: {\n          globals: true,\n          workspace: ['packages/*']\n        },\n      }))\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(false);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was NOT updated\n    expect(after).toBe(before);\n  });\n\n  it('adds projects property to test config', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import { defineConfig } from 'vite'\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default defineConfig({\n        plugins: [react()],\n        test: {\n          globals: true,\n        },\n      })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import react from '@vitejs/plugin-react';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig({\n          plugins: [react()],\n          test: {\n        \n      -     globals: true\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         globals: true\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        });\"\n    `);\n  });\n\n  it('updates config which is not exported immediately', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { defineConfig } from 'vite'\n      import viteReact from '@vitejs/plugin-react'\n      import { fileURLToPath, URL } from 'url'\n\n      const config = defineConfig({\n        resolve: {\n          preserveSymlinks: true,\n          alias: {\n            '@': fileURLToPath(new URL('./src', import.meta.url)),\n          },\n        },\n        plugins: [\n          viteReact(),\n        ],\n      })\n\n      export default config\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n  \"  import { defineConfig } from 'vite';\n    import viteReact from '@vitejs/plugin-react';\n    import { fileURLToPath, URL } from 'url';\n    \n  + import path from 'node:path';\n  + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n  + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n  + \n  + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n  + \n    const config = defineConfig({\n      resolve: {\n        preserveSymlinks: true,\n        alias: {\n          '@': fileURLToPath(new URL('./src', import.meta.url))\n        }\n      },\n    \n  -   plugins: [viteReact()]\n  - \n  +   plugins: [viteReact()],\n  +   test: {\n  +     projects: [{\n  +       extends: true,\n  +       plugins: [\n  +       // The plugin will run tests for the stories defined in your Storybook config\n  +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n  +       storybookTest({\n  +         configDir: path.join(dirname, '.storybook')\n  +       })],\n  +       test: {\n  +         name: 'storybook',\n  +         browser: {\n  +           enabled: true,\n  +           headless: true,\n  +           provider: 'playwright',\n  +           instances: [{\n  +             browser: 'chromium'\n  +           }]\n  +         }\n  +       }\n  +     }]\n  +   }\n  + \n    });\n    export default config;\"\n`);\n  });\n\n  it('edits projects property of test config', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import { defineConfig } from 'vite'\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default defineConfig({\n        plugins: [react()],\n        test: {\n          globals: true,\n          projects: ['packages/*', {some: 'config'}]\n        }\n      })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import react from '@vitejs/plugin-react';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig({\n          plugins: [react()],\n          test: {\n            globals: true,\n            projects: ['packages/*', {\n              some: 'config'\n        \n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      + \n            }]\n          }\n        });\"\n    `);\n  });\n\n  it('adds workspace property to test config', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import { defineConfig } from 'vite'\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default defineConfig({\n        plugins: [react()],\n        test: {\n          globals: true,\n        },\n      })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import react from '@vitejs/plugin-react';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig({\n          plugins: [react()],\n          test: {\n        \n      -     globals: true\n      - \n      +     workspace: [{\n      +       extends: true,\n      +       test: {\n      +         globals: true\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        });\"\n    `);\n  });\n\n  it('adds test property to vite config', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import { defineConfig } from 'vite'\n      import react from '@vitejs/plugin-react'\n\n      // https://vite.dev/config/\n      export default defineConfig({\n        plugins: [react()],\n      })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import react from '@vitejs/plugin-react';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig({\n        \n      -   plugins: [react()]\n      - \n      +   plugins: [react()],\n      +   test: {\n      +     workspace: [{\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      +   }\n      + \n        });\"\n    `);\n  });\n\n  it('supports mergeConfig with multiple defineConfig calls, finding the one with test', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig } from 'vite'\n      import { defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          plugins: [react()],\n        }),\n        defineConfig({\n          test: {\n            environment: 'jsdom',\n          }\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig } from 'vite';\n        import { defineConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n          plugins: [react()]\n        }), defineConfig({\n          test: {\n        \n      -     environment: 'jsdom'\n      - \n      +     workspace: [{\n      +       extends: true,\n      +       test: {\n      +         environment: 'jsdom'\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\"\n    `);\n  });\n  it('supports mergeConfig without defineConfig calls', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig } from 'vite'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        {\n          plugins: [react()],\n          test: {\n            environment: 'jsdom',\n          }\n        }\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig } from 'vite';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineConfig } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, {\n          plugins: [react()],\n          test: {\n        \n      -     environment: 'jsdom'\n      - \n      +     workspace: [{\n      +       extends: true,\n      +       test: {\n      +         environment: 'jsdom'\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        });\"\n    `);\n  });\n\n  it('supports mergeConfig without config containing test property', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig } from 'vite'\n      import { defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          plugins: [react()],\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig } from 'vite';\n        import { defineConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n        \n      -   plugins: [react()]\n      - \n      +   plugins: [react()],\n      +   test: {\n      +     workspace: [{\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      +   }\n      + \n        }));\"\n    `);\n  });\n\n  it('supports mergeConfig with defineConfig pattern using projects (Vitest 3.2+)', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      /// <reference types=\"vitest/config\" />\n      import { mergeConfig, defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      // https://vite.dev/config/\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          test: {\n            globals: true,\n          },\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        import viteConfig from './vite.config';\n        \n        // https://vite.dev/config/\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n          test: {\n        \n      -     globals: true\n      - \n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         globals: true\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\"\n    `);\n  });\n\n  it('appends storybook project to existing test.projects array (no double nesting)', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig, defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          test: {\n            expect: { requireAssertions: true },\n            projects: [\n              {\n                extends: \"./vite.config.ts\",\n                test: { name: \"client\" },\n              },\n              {\n                extends: \"./vite.config.ts\",\n                test: { name: \"server\" },\n              },\n            ],\n          },\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly (storybook project appended to existing projects, no double nesting)\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig, defineConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n          test: {\n            expect: {\n              requireAssertions: true\n      ...\n              test: {\n                name: \"server\"\n              }\n        \n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      + \n            }]\n          }\n        }));\"\n    `);\n  });\n\n  it('extracts coverage config and keeps it at top level when using workspace', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig, defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          test: {\n            name: 'node',\n            environment: 'happy-dom',\n            include: ['**/*.test.ts'],\n            coverage: {\n              exclude: [\n                'storybook.setup.ts',\n                '**/*.stories.*',\n              ],\n            },\n          },\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    // Coverage should stay at the top level, not moved into the workspace\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig, defineConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts'],\n      - \n            coverage: {\n              exclude: ['storybook.setup.ts', '**/*.stories.*']\n        \n      -     }\n      - \n      +     },\n      +     workspace: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\"\n    `);\n  });\n\n  it('extracts coverage config and keeps it at top level when using projects', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.3.2.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig, defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          test: {\n            name: 'node',\n            environment: 'happy-dom',\n            include: ['**/*.test.ts'],\n            coverage: {\n              exclude: [\n                'storybook.setup.ts',\n                '**/*.stories.*',\n              ],\n            },\n          },\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    // Coverage should stay at the top level, not moved into the projects\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig, defineConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts'],\n      - \n            coverage: {\n              exclude: ['storybook.setup.ts', '**/*.stories.*']\n        \n      -     }\n      - \n      +     },\n      +     projects: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\"\n    `);\n  });\n\n  it('supports defineConfig wrapping mergeConfig', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { defineConfig, mergeConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default defineConfig(mergeConfig(viteConfig, {\n        test: {\n          name: 'node',\n          environment: 'happy-dom',\n          include: ['**/*.test.ts'],\n        },\n      }))\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { defineConfig, mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig(mergeConfig(viteConfig, {\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     workspace: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\"\n    `);\n  });\n\n  it('supports defineConfig wrapping mergeConfig with satisfies operator', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { defineConfig, mergeConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n      import type { ViteUserConfig } from 'vitest/config'\n\n      export default defineConfig(\n        mergeConfig(viteConfig, {\n          test: {\n            name: 'node',\n            environment: 'happy-dom',\n            include: ['**/*.test.ts'],\n          },\n        }) satisfies ViteUserConfig\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { defineConfig, mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        import type { ViteUserConfig } from 'vitest/config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineConfig(mergeConfig(viteConfig, {\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     workspace: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }) satisfies ViteUserConfig);\"\n    `);\n  });\n\n  it('supports mergeConfig with as operator (TSAsExpression)', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n      import type { ViteUserConfig } from 'vitest/config'\n\n      export default mergeConfig(viteConfig, {\n        test: {\n          name: 'node',\n          environment: 'happy-dom',\n          include: ['**/*.test.ts'],\n        },\n      }) as ViteUserConfig\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        import type { ViteUserConfig } from 'vitest/config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineConfig } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, {\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     workspace: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }) as ViteUserConfig;\"\n    `);\n  });\n\n  it('supports mergeConfig with test defined as a constant (shorthand property)', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      const test = {\n        name: 'node',\n        environment: 'happy-dom',\n        include: ['**/*.test.ts'],\n      }\n\n      export default mergeConfig(viteConfig, { test })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineConfig } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        const test = {\n          name: 'node',\n          environment: 'happy-dom',\n          include: ['**/*.test.ts']\n        };\n        export default mergeConfig(viteConfig, {\n        \n      -   test\n      - \n      +   test: {\n      +     workspace: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      +   }\n      + \n        });\"\n    `);\n  });\n\n  it('supports const defined config re-exported (export default config)', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { defineConfig, mergeConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      const config = mergeConfig(\n        viteConfig,\n        defineConfig({\n          test: {\n            name: 'node',\n            environment: 'happy-dom',\n            include: ['**/*.test.ts'],\n          },\n        })\n      )\n\n      export default config\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { defineConfig, mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        const config = mergeConfig(viteConfig, defineConfig({\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     workspace: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\n        export default config;\"\n    `);\n  });\n\n  it('supports defineProject instead of defineConfig', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { defineProject } from 'vitest/config'\n\n      export default defineProject({\n        test: {\n          name: 'node',\n          environment: 'happy-dom',\n          include: ['**/*.test.ts'],\n        },\n      })\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { defineProject } from 'vitest/config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineConfig } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default defineProject({\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     workspace: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        });\"\n    `);\n  });\n\n  it('supports export const config re-exported as default (ExportNamedDeclaration)', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { defineConfig, mergeConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export const config = mergeConfig(\n        viteConfig,\n        defineConfig({\n          test: {\n            name: 'node',\n            environment: 'happy-dom',\n            include: ['**/*.test.ts'],\n          },\n        })\n      )\n\n      export default config\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { defineConfig, mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export const config = mergeConfig(viteConfig, defineConfig({\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     workspace: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\n        export default config;\"\n    `);\n  });\n\n  it('supports mergeConfig with config object as an exported constant (ExportNamedDeclaration)', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export const vitestConfig = {\n        test: {\n          name: 'node',\n          environment: 'happy-dom',\n          include: ['**/*.test.ts'],\n        }\n      }\n\n      export default mergeConfig(viteConfig, vitestConfig)\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineConfig } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export const vitestConfig = {\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     workspace: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        };\n        export default mergeConfig(viteConfig, vitestConfig);\"\n    `);\n  });\n\n  it('supports mergeConfig with config object as a constant variable', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      const vitestConfig = {\n        test: {\n          name: 'node',\n          environment: 'happy-dom',\n          include: ['**/*.test.ts'],\n        }\n      }\n\n      export default mergeConfig(viteConfig, vitestConfig)\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineConfig } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        const vitestConfig = {\n          test: {\n        \n      -     name: 'node',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts']\n      - \n      +     workspace: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'node',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts']\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        };\n        export default mergeConfig(viteConfig, vitestConfig);\"\n    `);\n  });\n\n  it('keeps coverage at top level instead of moving into workspace', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.config.template', {\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { mergeConfig, defineConfig } from 'vitest/config'\n      import viteConfig from './vite.config'\n\n      export default mergeConfig(\n        viteConfig,\n        defineConfig({\n          test: {\n            name: 'unit',\n            environment: 'happy-dom',\n            include: ['**/*.test.ts'],\n            env: { CI: 'true' },\n            pool: 'forks',\n            maxWorkers: 4,\n            coverage: {\n              provider: 'v8',\n              exclude: ['**/*.stories.*'],\n            },\n          },\n        })\n      )\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateConfigFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n    expect(after).not.toBe(before);\n\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { mergeConfig, defineConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        \n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + \n        export default mergeConfig(viteConfig, defineConfig({\n          test: {\n        \n      -     name: 'unit',\n      -     environment: 'happy-dom',\n      -     include: ['**/*.test.ts'],\n      -     env: {\n      -       CI: 'true'\n      -     },\n      -     pool: 'forks',\n      -     maxWorkers: 4,\n      - \n            coverage: {\n              provider: 'v8',\n              exclude: ['**/*.stories.*']\n        \n      -     }\n      - \n      +     },\n      +     workspace: [{\n      +       extends: true,\n      +       test: {\n      +         name: 'unit',\n      +         environment: 'happy-dom',\n      +         include: ['**/*.test.ts'],\n      +         env: {\n      +           CI: 'true'\n      +         },\n      +         pool: 'forks',\n      +         maxWorkers: 4\n      +       }\n      +     }, {\n      +       extends: true,\n      +       plugins: [\n      +       // The plugin will run tests for the stories defined in your Storybook config\n      +       // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +       storybookTest({\n      +         configDir: path.join(dirname, '.storybook')\n      +       })],\n      +       test: {\n      +         name: 'storybook',\n      +         browser: {\n      +           enabled: true,\n      +           headless: true,\n      +           provider: 'playwright',\n      +           instances: [{\n      +             browser: 'chromium'\n      +           }]\n      +         }\n      +       }\n      +     }]\n      + \n          }\n        }));\"\n    `);\n  });\n});\n"
  },
  {
    "path": "code/addons/vitest/src/updateVitestFile.config.workspace.test.ts",
    "content": "import { join } from 'node:path';\n\nimport { describe, expect, it, vi } from 'vitest';\n\nimport * as babel from 'storybook/internal/babel';\n\nimport { getDiff } from '../../../core/src/core-server/utils/save-story/getDiff.ts';\nimport { loadTemplate, updateWorkspaceFile } from './updateVitestFile.ts';\n\nvi.mock('storybook/internal/node-logger', () => ({\n  logger: {\n    info: vi.fn(),\n    warn: vi.fn(),\n    error: vi.fn(),\n  },\n}));\n\nvi.mock('../../../core/src/shared/utils/module', () => ({\n  resolvePackageDir: vi.fn().mockImplementation(() => join(__dirname, '..')),\n}));\n\ndescribe('updateWorkspaceFile', () => {\n  it('updates vitest workspace file using array syntax', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.workspace.template', {\n        EXTENDS_WORKSPACE: '',\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      export default ['packages/*']\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateWorkspaceFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"- export default ['packages/*'];\n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { defineWorkspace } from 'vitest/config';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + export default ['packages/*', 'ROOT_CONFIG', {\n      +   extends: '.',\n      +   plugins: [\n      +   // The plugin will run tests for the stories defined in your Storybook config\n      +   // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +   storybookTest({\n      +     configDir: path.join(dirname, '.storybook')\n      +   })],\n      +   test: {\n      +     name: 'storybook',\n      +     browser: {\n      +       enabled: true,\n      +       headless: true,\n      +       provider: 'playwright',\n      +       instances: [{\n      +         browser: 'chromium'\n      +       }]\n      +     }\n      +   }\n      + }];\"\n    `);\n  });\n\n  it('updates vitest workspace file using defineWorkspace syntax', async () => {\n    const source = babel.babelParse(\n      await loadTemplate('vitest.workspace.template', {\n        EXTENDS_WORKSPACE: '',\n        CONFIG_DIR: '.storybook',\n        BROWSER_CONFIG: \"{ provider: 'playwright' }\",\n        SETUP_FILE: '../.storybook/vitest.setup.ts',\n      })\n    );\n    const target = babel.babelParse(`\n      import { defineWorkspace } from 'vitest/config'\n\n      export default defineWorkspace(['packages/*'])\n    `);\n\n    const before = babel.generate(target).code;\n    const updated = updateWorkspaceFile(source, target);\n    expect(updated).toBe(true);\n\n    const after = babel.generate(target).code;\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  import { defineWorkspace } from 'vitest/config';\n        \n      - export default defineWorkspace(['packages/*']);\n      + import path from 'node:path';\n      + import { fileURLToPath } from 'node:url';\n      + import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n      + const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n      + \n      + // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\n      + export default defineWorkspace(['packages/*', 'ROOT_CONFIG', {\n      +   extends: '.',\n      +   plugins: [\n      +   // The plugin will run tests for the stories defined in your Storybook config\n      +   // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      +   storybookTest({\n      +     configDir: path.join(dirname, '.storybook')\n      +   })],\n      +   test: {\n      +     name: 'storybook',\n      +     browser: {\n      +       enabled: true,\n      +       headless: true,\n      +       provider: 'playwright',\n      +       instances: [{\n      +         browser: 'chromium'\n      +       }]\n      +     }\n      +   }\n      + }]);\"\n    `);\n  });\n});\n"
  },
  {
    "path": "code/addons/vitest/src/updateVitestFile.test.ts",
    "content": "import { join } from 'node:path';\n\nimport { describe, expect, it, vi } from 'vitest';\n\nimport { loadTemplate } from './updateVitestFile.ts';\n\nvi.mock('storybook/internal/node-logger', () => ({\n  logger: {\n    info: vi.fn(),\n    warn: vi.fn(),\n    error: vi.fn(),\n  },\n}));\n\nvi.mock('../../../core/src/shared/utils/module', () => ({\n  resolvePackageDir: vi.fn().mockImplementation(() => join(__dirname, '..')),\n}));\n\ndescribe('loadTemplate', () => {\n  it('normalizes Windows paths to forward slashes', async () => {\n    // Windows-style path with backslashes (need to escape them in JS strings)\n    const windowsPath = '.\\\\apps\\\\frontend-storybook\\\\.storybook';\n\n    const result = await loadTemplate('vitest.config.template', {\n      CONFIG_DIR: windowsPath,\n      SETUP_FILE: '.\\\\apps\\\\frontend-storybook\\\\.storybook\\\\vitest.setup.ts',\n    });\n\n    // Should contain forward slashes, not backslashes\n    expect(result).toContain('apps/frontend-storybook/.storybook');\n    expect(result).not.toContain('\\\\apps\\\\');\n  });\n\n  it('preserves forward slashes in paths', async () => {\n    // Unix-style path with forward slashes\n    const unixPath = './apps/frontend-storybook/.storybook';\n\n    const result = await loadTemplate('vitest.config.template', {\n      CONFIG_DIR: unixPath,\n      SETUP_FILE: './apps/frontend-storybook/.storybook/vitest.setup.ts',\n    });\n\n    // Should still contain forward slashes\n    expect(result).toContain('apps/frontend-storybook/.storybook');\n  });\n});\n"
  },
  {
    "path": "code/addons/vitest/src/updateVitestFile.ts",
    "content": "import {\n  getConfigObjectFromMergeArg,\n  getEffectiveMergeConfigCall,\n  getTargetConfigObject,\n  isDefineConfigLike,\n  resolveExpression,\n} from 'storybook/internal/babel';\nimport type { BabelFile, types as t } from 'storybook/internal/babel';\n\nimport { normalize } from 'pathe';\n\n/**\n * Each template is imported separately to allow the build system to process the template as raw\n * text. A mix of globs and the \"?raw\" string query is not supported in esbuild\n */\nasync function getTemplatePath(name: string) {\n  switch (name) {\n    case 'vitest.config.template':\n      return import('../templates/vitest.config.template.ts?raw');\n    case 'vitest.config.4.template':\n      return import('../templates/vitest.config.4.template.ts?raw');\n    case 'vitest.config.3.2.template':\n      return import('../templates/vitest.config.3.2.template.ts?raw');\n    case 'vitest.workspace.template':\n      return import('../templates/vitest.workspace.template.ts?raw');\n    default:\n      throw new Error(`Unknown template: ${name}`);\n  }\n}\n\nexport const loadTemplate = async (name: string, replacements: Record<string, string>) => {\n  // Dynamically import the template file as plain text\n  const templateModule = await getTemplatePath(name);\n  let template = templateModule.default;\n  // Normalize Windows paths (backslashes) to forward slashes for JavaScript string compatibility\n  Object.entries(replacements).forEach(\n    ([key, value]) => (template = template.replace(key, normalize(value)))\n  );\n  return template;\n};\n\n// Recursively merge object properties from source into target\n// Handles nested objects and shallowly merging of arrays\nconst mergeProperties = (\n  source: t.ObjectExpression['properties'],\n  target: t.ObjectExpression['properties']\n) => {\n  for (const sourceProp of source) {\n    if (sourceProp.type === 'ObjectProperty') {\n      const targetProp = target.find(\n        (p) =>\n          sourceProp.key.type === 'Identifier' &&\n          p.type === 'ObjectProperty' &&\n          p.key.type === 'Identifier' &&\n          p.key.name === sourceProp.key.name\n      );\n      if (targetProp && targetProp.type === 'ObjectProperty') {\n        if (\n          sourceProp.value.type === 'ObjectExpression' &&\n          targetProp.value.type === 'ObjectExpression'\n        ) {\n          mergeProperties(sourceProp.value.properties, targetProp.value.properties);\n        } else if (\n          sourceProp.value.type === 'ArrayExpression' &&\n          targetProp.value.type === 'ArrayExpression'\n        ) {\n          targetProp.value.elements.push(...sourceProp.value.elements);\n        } else {\n          targetProp.value = sourceProp.value;\n        }\n      } else {\n        target.push(sourceProp);\n      }\n    }\n  }\n};\n\n/**\n * Resolves the value of a `test` ObjectProperty to an ObjectExpression. Handles both inline objects\n * and shorthand identifier references, e.g.: `{ test: { ... } }` → returns the inline\n * ObjectExpression `const test = {...}; { test }` → resolves the identifier to its initializer\n */\nconst resolveTestPropValue = (\n  testProp: t.ObjectProperty,\n  ast: BabelFile['ast']\n): t.ObjectExpression | null => {\n  if (testProp.value.type === 'ObjectExpression') {\n    return testProp.value;\n  }\n  const resolved = resolveExpression(testProp.value as t.Expression, ast);\n  return resolved?.type === 'ObjectExpression' ? resolved : null;\n};\n\n/** Finds a named ObjectProperty in an object expression's properties. */\nconst findNamedProp = (\n  properties: t.ObjectExpression['properties'],\n  name: string\n): t.ObjectProperty | undefined =>\n  properties.find(\n    (p): p is t.ObjectProperty =>\n      p.type === 'ObjectProperty' && p.key.type === 'Identifier' && p.key.name === name\n  );\n\n/** Type guard for a property that is a `workspace` or `projects` key with an array value. */\nconst isWorkspaceOrProjectsArrayProp = (\n  p: t.ObjectMethod | t.ObjectProperty | t.SpreadElement\n): p is t.ObjectProperty =>\n  p.type === 'ObjectProperty' &&\n  p.key.type === 'Identifier' &&\n  (p.key.name === 'workspace' || p.key.name === 'projects') &&\n  p.value.type === 'ArrayExpression';\n\n/**\n * Appends storybook project(s) from template into an existing `test.workspace`/`test.projects`\n * array, then merges any additional test-level options (e.g. coverage) that don't already exist.\n */\nconst appendToExistingProjectRefs = (\n  existingProjectRefsProp: t.ObjectProperty,\n  resolvedTestValue: t.ObjectExpression,\n  templateTestProp: t.ObjectProperty | undefined,\n  properties: t.ObjectExpression['properties'],\n  targetConfigObject: t.ObjectExpression\n) => {\n  const existingKeyName =\n    existingProjectRefsProp.key.type === 'Identifier' ? existingProjectRefsProp.key.name : null;\n\n  if (templateTestProp && templateTestProp.value.type === 'ObjectExpression') {\n    // Append template workspace/projects entries to existing workspace/projects array\n    const templateProjectRefsProp = templateTestProp.value.properties.find(\n      (p): p is t.ObjectProperty =>\n        isWorkspaceOrProjectsArrayProp(p) &&\n        (existingKeyName === null ||\n          (p.key.type === 'Identifier' && p.key.name === existingKeyName))\n    );\n    if (templateProjectRefsProp && templateProjectRefsProp.value.type === 'ArrayExpression') {\n      (existingProjectRefsProp.value as t.ArrayExpression).elements.push(\n        ...(templateProjectRefsProp.value as t.ArrayExpression).elements\n      );\n    }\n\n    // Merge other test-level options from template (e.g. coverage) that don't already exist\n    const existingTestPropNames = new Set(\n      resolvedTestValue.properties\n        .filter(\n          (p): p is t.ObjectProperty => p.type === 'ObjectProperty' && p.key.type === 'Identifier'\n        )\n        .map((p) => (p.key as t.Identifier).name)\n    );\n    for (const templateProp of templateTestProp.value.properties) {\n      if (\n        templateProp.type === 'ObjectProperty' &&\n        templateProp.key.type === 'Identifier' &&\n        (templateProp.key as t.Identifier).name !== 'projects' &&\n        (templateProp.key as t.Identifier).name !== 'workspace' &&\n        !existingTestPropNames.has((templateProp.key as t.Identifier).name)\n      ) {\n        resolvedTestValue.properties.push(templateProp);\n      }\n    }\n  }\n\n  // Merge only non-test properties from template\n  const otherTemplateProps = properties.filter(\n    (p) => !(p.type === 'ObjectProperty' && p.key.type === 'Identifier' && p.key.name === 'test')\n  );\n  if (otherTemplateProps.length > 0) {\n    mergeProperties(otherTemplateProps, targetConfigObject.properties);\n  }\n};\n\n/**\n * Wraps the existing test config as one project entry inside the template's workspace/projects\n * array, hoisting shared properties (coverage, env, pool, maxWorkers) to the top-level test\n * object.\n */\nconst wrapTestConfigAsProject = (\n  resolvedTestValue: t.ObjectExpression,\n  existingTestProp: t.ObjectProperty,\n  templateTestProp: t.ObjectProperty,\n  properties: t.ObjectExpression['properties'],\n  targetConfigObject: t.ObjectExpression\n) => {\n  const workspaceOrProjectsProp =\n    templateTestProp.value.type === 'ObjectExpression'\n      ? (templateTestProp.value.properties.find(\n          (p) =>\n            p.type === 'ObjectProperty' &&\n            p.key.type === 'Identifier' &&\n            (p.key.name === 'workspace' || p.key.name === 'projects')\n        ) as t.ObjectProperty | undefined)\n      : undefined;\n\n  if (!workspaceOrProjectsProp || workspaceOrProjectsProp.value.type !== 'ArrayExpression') {\n    mergeProperties(properties, targetConfigObject.properties);\n    return;\n  }\n\n  // Properties that should stay at the top-level test object (shared across all projects)\n  const TOP_LEVEL_TEST_PROPERTIES = [\n    'shard',\n    'watch',\n    'run',\n    'cache',\n    'update',\n    'reporters',\n    'outputFile',\n    'teardownTimeout',\n    'silent',\n    'forceRerunTriggers',\n    'testNamePattern',\n    'ui',\n    'open',\n    'uiBase',\n    'snapshotFormat',\n    'resolveSnapshotPath',\n    'passWithNoTests',\n    'onConsoleLog',\n    'onStackTrace',\n    'dangerouslyIgnoreUnhandledErrors',\n    'slowTestThreshold',\n    'inspect',\n    'inspectBrk',\n    'coverage',\n    'watchTriggerPatterns',\n  ];\n\n  const topLevelProps = TOP_LEVEL_TEST_PROPERTIES.map((name) =>\n    findNamedProp(resolvedTestValue.properties, name)\n  ).filter(Boolean) as t.ObjectProperty[];\n\n  const topLevelPropSet = new Set(topLevelProps);\n  const projectTestProps = resolvedTestValue.properties.filter(\n    (p) => !topLevelPropSet.has(p as any)\n  );\n\n  // Create the existing test project: { extends: true, test: { ...projectTestProps } }\n  const existingTestProject: t.ObjectExpression = {\n    type: 'ObjectExpression',\n    properties: [\n      {\n        type: 'ObjectProperty',\n        key: { type: 'Identifier', name: 'extends' } as t.Identifier,\n        value: { type: 'BooleanLiteral', value: true } as t.BooleanLiteral,\n        computed: false,\n        shorthand: false,\n      } as t.ObjectProperty,\n      {\n        type: 'ObjectProperty',\n        key: { type: 'Identifier', name: 'test' } as t.Identifier,\n        value: {\n          type: 'ObjectExpression',\n          properties: projectTestProps,\n        } as t.ObjectExpression,\n        computed: false,\n        shorthand: false,\n      } as t.ObjectProperty,\n    ],\n  };\n\n  // Add the existing test project to the template's array\n  workspaceOrProjectsProp.value.elements.unshift(existingTestProject);\n\n  // Remove the existing test property from the target config (it's now in the array)\n  targetConfigObject.properties = targetConfigObject.properties.filter(\n    (p) => p !== existingTestProp\n  );\n\n  // Hoist top-level properties to the test object so they apply to all projects\n  if (topLevelProps.length > 0 && templateTestProp.value.type === 'ObjectExpression') {\n    templateTestProp.value.properties.unshift(...topLevelProps);\n  }\n\n  mergeProperties(properties, targetConfigObject.properties);\n};\n\n/**\n * Merges template properties into a config object, handling Vitest `test.projects` migration\n * semantics:\n *\n * - Append when projects already exists\n * - Wrap existing test config as a project when template introduces projects/workspace\n * - Otherwise perform a regular merge\n */\nconst mergeTemplateIntoConfigObject = (\n  targetConfigObject: t.ObjectExpression,\n  properties: t.ObjectExpression['properties'],\n  target: BabelFile['ast']\n) => {\n  const existingTestProp = findNamedProp(targetConfigObject.properties, 'test');\n  const resolvedTestValue = existingTestProp\n    ? resolveTestPropValue(existingTestProp, target)\n    : null;\n  const templateTestProp = findNamedProp(properties, 'test');\n\n  if (existingTestProp && resolvedTestValue !== null) {\n    const existingProjectRefsProp = resolvedTestValue.properties.find(\n      isWorkspaceOrProjectsArrayProp\n    );\n\n    if (existingProjectRefsProp) {\n      appendToExistingProjectRefs(\n        existingProjectRefsProp,\n        resolvedTestValue,\n        templateTestProp,\n        properties,\n        targetConfigObject\n      );\n      return;\n    }\n\n    if (templateTestProp && templateTestProp.value.type === 'ObjectExpression') {\n      wrapTestConfigAsProject(\n        resolvedTestValue,\n        existingTestProp,\n        templateTestProp,\n        properties,\n        targetConfigObject\n      );\n      return;\n    }\n  }\n\n  mergeProperties(properties, targetConfigObject.properties);\n};\n\n/**\n * Merges a source Vitest configuration AST into a target configuration AST.\n *\n * This function intelligently combines configuration elements from a source file (typically a\n * template) into an existing target configuration file, avoiding duplicates and preserving the\n * structure of both files.\n *\n * The function performs the following operations:\n *\n * 1. **Import Merging**: Adds new import statements from source that don't exist in target (determined\n *    by local specifier name). Imports are inserted after existing imports.\n * 2. **Variable Declaration Merging**: Copies variable declarations from source to target if they\n *    don't already exist (determined by variable name). Variables are inserted after imports.\n * 3. **Configuration Object Merging**: Merges the configuration object properties from source into\n *    target's default export. Supports both direct object exports and function-wrapped exports\n *    (e.g., `defineConfig({})`). The merging is recursive:\n *\n *    - Nested objects are merged deeply\n *    - Arrays are concatenated (shallow merge)\n *    - Primitive values are overwritten\n *\n * @param source - The source Babel AST (template configuration to merge from)\n * @param target - The target Babel AST (existing configuration to merge into)\n * @returns {boolean} - True if the target was modified, false otherwise\n */\nexport const updateConfigFile = (source: BabelFile['ast'], target: BabelFile['ast']) => {\n  let updated = false;\n\n  // First, check if we can actually modify the configuration\n  const sourceExportDefault = source.program.body.find(\n    (n) => n.type === 'ExportDefaultDeclaration'\n  );\n  if (!sourceExportDefault || sourceExportDefault.declaration.type !== 'CallExpression') {\n    return false;\n  }\n\n  const targetExportDefault = target.program.body.find(\n    (n) => n.type === 'ExportDefaultDeclaration'\n  );\n  if (!targetExportDefault) {\n    return false;\n  }\n\n  // Check if this is a function notation that we don't support (defineConfig(() => ({})))\n  // Resolve through TS type wrappers and variable references before checking.\n  const effectiveDecl = resolveExpression(targetExportDefault.declaration, target);\n  if (\n    effectiveDecl?.type === 'CallExpression' &&\n    isDefineConfigLike(effectiveDecl, target) &&\n    effectiveDecl.arguments.length > 0 &&\n    effectiveDecl.arguments[0].type === 'ArrowFunctionExpression'\n  ) {\n    return false;\n  }\n\n  // Check if we can handle the config pattern (direct object, defineConfig/defineProject,\n  // mergeConfig, or any of these wrapped in TS type annotations / variable references)\n  let canHandleConfig = false;\n  if (getTargetConfigObject(target, targetExportDefault) !== null) {\n    canHandleConfig = true;\n  } else if (getEffectiveMergeConfigCall(targetExportDefault.declaration, target) !== null) {\n    canHandleConfig = true;\n  }\n\n  if (!canHandleConfig) {\n    return false;\n  }\n\n  // If we get here, we can modify the configuration, so add imports and variables first\n  for (const sourceNode of source.program.body) {\n    if (sourceNode.type === 'ImportDeclaration') {\n      // Insert imports that don't already exist (according to their local specifier name)\n      if (\n        !target.program.body.some(\n          (targetNode) =>\n            targetNode.type === sourceNode.type &&\n            targetNode.specifiers.some((s) => s.local.name === sourceNode.specifiers[0].local.name)\n        )\n      ) {\n        const lastImport = target.program.body.findLastIndex((n) => n.type === 'ImportDeclaration');\n        target.program.body.splice(lastImport + 1, 0, sourceNode);\n      }\n    } else if (sourceNode.type === 'VariableDeclaration') {\n      // Copy over variable declarations, making sure they're inserted after any imports\n      if (\n        !target.program.body.some(\n          (targetNode) =>\n            targetNode.type === sourceNode.type &&\n            targetNode.declarations.some(\n              (d) =>\n                'name' in d.id &&\n                'name' in sourceNode.declarations[0].id &&\n                d.id.name === sourceNode.declarations[0].id.name\n            )\n        )\n      ) {\n        const lastImport = target.program.body.findLastIndex((n) => n.type === 'ImportDeclaration');\n        target.program.body.splice(lastImport + 1, 0, sourceNode);\n      }\n    } else if (sourceNode.type === 'ExportDefaultDeclaration') {\n      const exportDefault = target.program.body.find((n) => n.type === 'ExportDefaultDeclaration');\n      if (\n        exportDefault &&\n        sourceNode.declaration.type === 'CallExpression' &&\n        sourceNode.declaration.arguments.length > 0 &&\n        sourceNode.declaration.arguments[0].type === 'ObjectExpression'\n      ) {\n        const { properties } = sourceNode.declaration.arguments[0];\n        const targetConfigObject = getTargetConfigObject(target, exportDefault);\n        if (targetConfigObject !== null) {\n          mergeTemplateIntoConfigObject(targetConfigObject, properties, target);\n          updated = true;\n        } else {\n          const mergeConfigCall = getEffectiveMergeConfigCall(exportDefault.declaration, target);\n          if (mergeConfigCall && mergeConfigCall.arguments.length >= 2) {\n            // Collect all potential config object nodes from mergeConfig arguments.\n            // Each argument may be a plain object, a wrapper call with object argument,\n            // an Identifier (variable reference), or wrapped in a TS type annotation.\n            const configObjectNodes: t.ObjectExpression[] = [];\n\n            for (const arg of mergeConfigCall.arguments) {\n              const configObject = getConfigObjectFromMergeArg(arg as t.Expression, target);\n              if (configObject) {\n                configObjectNodes.push(configObject);\n              }\n            }\n\n            // Prefer the config object that already has an immediate `test` property.\n            const configObjectWithTest = configObjectNodes.find((obj) =>\n              obj.properties.some(\n                (p) =>\n                  p.type === 'ObjectProperty' &&\n                  p.key.type === 'Identifier' &&\n                  p.key.name === 'test'\n              )\n            );\n\n            const targetConfigObject = configObjectWithTest || configObjectNodes[0];\n\n            if (!targetConfigObject) {\n              return false;\n            }\n\n            mergeTemplateIntoConfigObject(targetConfigObject, properties, target);\n            updated = true;\n          }\n        }\n      }\n    }\n  }\n  return updated;\n};\n\nexport const updateWorkspaceFile = (source: BabelFile['ast'], target: BabelFile['ast']) => {\n  let updated = false;\n  for (const sourceNode of source.program.body) {\n    if (sourceNode.type === 'ImportDeclaration') {\n      // Insert imports that don't already exist\n      if (\n        !target.program.body.some(\n          (targetNode) =>\n            targetNode.type === sourceNode.type &&\n            targetNode.source.value === sourceNode.source.value &&\n            targetNode.specifiers.some((s) => s.local.name === sourceNode.specifiers[0].local.name)\n        )\n      ) {\n        const lastImport = target.program.body.findLastIndex((n) => n.type === 'ImportDeclaration');\n        target.program.body.splice(lastImport + 1, 0, sourceNode);\n      }\n    } else if (sourceNode.type === 'VariableDeclaration') {\n      // Copy over variable declarations, making sure they're inserted after any imports\n      if (\n        !target.program.body.some(\n          (targetNode) =>\n            targetNode.type === sourceNode.type &&\n            targetNode.declarations.some(\n              (d) =>\n                'name' in d.id &&\n                'name' in sourceNode.declarations[0].id &&\n                d.id.name === sourceNode.declarations[0].id.name\n            )\n        )\n      ) {\n        const lastImport = target.program.body.findLastIndex((n) => n.type === 'ImportDeclaration');\n        target.program.body.splice(lastImport + 1, 0, sourceNode);\n      }\n    } else if (sourceNode.type === 'ExportDefaultDeclaration') {\n      // Merge workspace array, which is the default export on both sides but may or may not be\n      // wrapped in a defineWorkspace call\n      const exportDefault = target.program.body.find((n) => n.type === 'ExportDefaultDeclaration');\n      if (\n        exportDefault &&\n        sourceNode.declaration.type === 'CallExpression' &&\n        sourceNode.declaration.arguments.length > 0 &&\n        sourceNode.declaration.arguments[0].type === 'ArrayExpression' &&\n        sourceNode.declaration.arguments[0].elements.length > 0\n      ) {\n        const { elements } = sourceNode.declaration.arguments[0];\n        if (exportDefault.declaration.type === 'ArrayExpression') {\n          exportDefault.declaration.elements.push(...elements);\n          updated = true;\n        } else if (\n          exportDefault.declaration.type === 'CallExpression' &&\n          exportDefault.declaration.callee.type === 'Identifier' &&\n          exportDefault.declaration.callee.name === 'defineWorkspace' &&\n          exportDefault.declaration.arguments[0]?.type === 'ArrayExpression'\n        ) {\n          exportDefault.declaration.arguments[0].elements.push(...elements);\n          updated = true;\n        }\n      }\n    }\n  }\n  return updated;\n};\n"
  },
  {
    "path": "code/addons/vitest/src/use-test-provider-state.ts",
    "content": "import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport type {\n  StatusTypeId,\n  StatusValue,\n  StatusesByStoryIdAndTypeId,\n  StoryId,\n  TestProviderState,\n} from 'storybook/internal/types';\n\nimport { store, testProviderStore } from '#manager-store';\nimport { isEqual } from 'es-toolkit/predicate';\nimport {\n  type API,\n  experimental_useStatusStore,\n  experimental_useTestProviderStore,\n  experimental_useUniversalStore,\n} from 'storybook/manager-api';\n\nimport { ADDON_ID, STATUS_TYPE_ID_A11Y, STATUS_TYPE_ID_COMPONENT_TEST } from './constants.ts';\nimport type { StoreState } from './types.ts';\n\ntype TestStatusValue = Extract<\n  StatusValue,\n  `status-value:${'pending' | 'success' | 'error' | 'warning' | 'unknown'}`\n>;\n\nexport type StatusValueToStoryIds = Record<TestStatusValue, StoryId[]>;\n\nconst statusValueToStoryIds = (\n  allStatuses: StatusesByStoryIdAndTypeId,\n  typeId: StatusTypeId,\n  storyIds?: StoryId[]\n) => {\n  const statusValueToStoryIdsMap: StatusValueToStoryIds = {\n    'status-value:pending': [],\n    'status-value:success': [],\n    'status-value:error': [],\n    'status-value:warning': [],\n    'status-value:unknown': [],\n  };\n  const stories = storyIds\n    ? storyIds.map((storyId) => allStatuses[storyId]).filter(Boolean)\n    : Object.values(allStatuses);\n\n  stories.forEach((statusByTypeId) => {\n    const status = statusByTypeId[typeId];\n    if (!status) {\n      return;\n    }\n    statusValueToStoryIdsMap[status.value as TestStatusValue].push(status.storyId);\n  });\n\n  return statusValueToStoryIdsMap;\n};\n\nexport const useTestProvider = (\n  api: API,\n  entryId?: string\n): {\n  storeState: StoreState;\n  setStoreState: (typeof store)['setState'];\n  testProviderState: TestProviderState;\n  componentTestStatusValueToStoryIds: StatusValueToStoryIds;\n  a11yStatusValueToStoryIds: StatusValueToStoryIds;\n  isSettingsUpdated: boolean;\n} => {\n  const testProviderState = experimental_useTestProviderStore((s) => s[ADDON_ID]);\n  const [storeState, setStoreState] = experimental_useUniversalStore(store);\n\n  const [isSettingsUpdated, setIsSettingsUpdated] = useState(false);\n  const settingsUpdatedTimeoutRef = useRef<ReturnType<typeof setTimeout>>();\n  useEffect(() => {\n    const unsubscribe = store.onStateChange((state, previousState) => {\n      if (!isEqual(state.config, previousState.config)) {\n        testProviderStore.settingsChanged();\n        setIsSettingsUpdated(true);\n        clearTimeout(settingsUpdatedTimeoutRef.current);\n        settingsUpdatedTimeoutRef.current = setTimeout(() => {\n          setIsSettingsUpdated(false);\n        }, 1000);\n      }\n    });\n    return () => {\n      unsubscribe();\n      clearTimeout(settingsUpdatedTimeoutRef.current);\n    };\n  }, []);\n\n  // TODO: does this overmemo, if the index changes, would that trigger a re-calculation of storyIds?\n  const storyIds = useMemo(\n    () => (entryId ? api.findAllLeafStoryIds(entryId) : undefined),\n    [entryId, api]\n  );\n\n  const componentTestStatusSelector = useCallback(\n    (allStatuses: StatusesByStoryIdAndTypeId) =>\n      statusValueToStoryIds(allStatuses, STATUS_TYPE_ID_COMPONENT_TEST, storyIds),\n    [storyIds]\n  );\n  const componentTestStatusValueToStoryIds = experimental_useStatusStore(\n    componentTestStatusSelector\n  );\n  const a11yStatusValueToStoryIdsSelector = useCallback(\n    (allStatuses: StatusesByStoryIdAndTypeId) =>\n      statusValueToStoryIds(allStatuses, STATUS_TYPE_ID_A11Y, storyIds),\n    [storyIds]\n  );\n  const a11yStatusValueToStoryIds = experimental_useStatusStore(a11yStatusValueToStoryIdsSelector);\n\n  return {\n    storeState,\n    setStoreState,\n    testProviderState,\n    componentTestStatusValueToStoryIds,\n    a11yStatusValueToStoryIds,\n    isSettingsUpdated,\n  };\n};\n"
  },
  {
    "path": "code/addons/vitest/src/utils.ts",
    "content": "import type { ErrorLike } from './types.ts';\n\nexport function errorToErrorLike(error: Error): ErrorLike {\n  return {\n    message: error.message,\n    name: error.name,\n    // avoid duplicating the error message in the stack trace\n    stack: error.message + ' ' + error.stack?.replace(error.message, ''),\n    cause: error.cause && error.cause instanceof Error ? errorToErrorLike(error.cause) : undefined,\n  };\n}\n"
  },
  {
    "path": "code/addons/vitest/src/vitest-plugin/global-setup.ts",
    "content": "import { type ChildProcess, spawn } from 'node:child_process';\n\nimport type { TestProject } from 'vitest/node';\n\nimport { logger } from 'storybook/internal/node-logger';\n\nimport treeKill from 'tree-kill';\n\nlet storybookProcess: ChildProcess | null = null;\n\nconst getIsVitestStandaloneRun = () => {\n  try {\n    // @ts-expect-error Suppress TypeScript warning about wrong setting. Doesn't matter, because we don't use tsc for bundling.\n    return (import.meta.env || process?.env).STORYBOOK !== 'true';\n  } catch (e) {\n    return false;\n  }\n};\n\nconst isVitestStandaloneRun = getIsVitestStandaloneRun();\n\n// TODO: Not run when executed via Storybook\nconst checkStorybookRunning = async (storybookUrl: string): Promise<boolean> => {\n  try {\n    const response = await fetch(`${storybookUrl}/iframe.html`, {\n      method: 'HEAD',\n      signal: AbortSignal.timeout(5000),\n    });\n    return response.ok;\n  } catch (error) {\n    logger.verbose(\n      `Failed to get response from ${storybookUrl}: ${error instanceof Error ? error.message : String(error)}`\n    );\n    return false;\n  }\n};\n\nconst startStorybookIfNotRunning = async () => {\n  const storybookScript = process.env.__STORYBOOK_SCRIPT__ as string;\n  const storybookUrl = process.env.__STORYBOOK_URL__ as string;\n\n  const isRunning = await checkStorybookRunning(storybookUrl);\n\n  if (isRunning) {\n    logger.verbose('Storybook is already running');\n    return;\n  }\n\n  logger.verbose(`Starting Storybook with command: ${storybookScript}`);\n\n  try {\n    // We don't await the process because we don't want Vitest to hang while Storybook is starting\n    // Use shell so commands like `yarn storybook --no-open` or `npm run storybook -- --no-open`\n    // are interpreted correctly across platforms.\n    storybookProcess = spawn(storybookScript, {\n      shell: true,\n      stdio: process.env.DEBUG === 'storybook' ? 'pipe' : 'ignore',\n      cwd: process.cwd(),\n    });\n\n    storybookProcess.on('error', (error) => {\n      logger.verbose('Failed to start Storybook:' + error.message);\n      throw error;\n    });\n  } catch (error: unknown) {\n    logger.verbose('Failed to start Storybook:' + (error as any).message);\n    throw error;\n  }\n};\n\nexport const setup = async ({ config }: TestProject) => {\n  if (config.watch && isVitestStandaloneRun) {\n    await startStorybookIfNotRunning();\n  }\n};\n\nexport const teardown = async () => {\n  if (!storybookProcess) {\n    return;\n  }\n  logger.verbose('Stopping Storybook process');\n  await new Promise<void>((resolve, reject) => {\n    // Storybook starts multiple child processes, so we need to kill the whole tree\n    if (storybookProcess?.pid) {\n      treeKill(storybookProcess.pid, 'SIGTERM', (error) => {\n        if (error) {\n          logger.error('Failed to stop Storybook process:');\n          reject(error);\n          return;\n        }\n        resolve();\n      });\n    }\n  });\n};\n"
  },
  {
    "path": "code/addons/vitest/src/vitest-plugin/index.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport type { Plugin } from 'vitest/config';\nimport { mergeConfig } from 'vitest/config';\nimport type { ViteUserConfig } from 'vitest/config';\n\nimport {\n  DEFAULT_FILES_PATTERN,\n  getInterpretedFile,\n  loadPreviewOrConfigFile,\n  normalizeStories,\n  optionalEnvToBoolean,\n  resolvePathInStorybookCache,\n  validateConfigurationFiles,\n} from 'storybook/internal/common';\nimport {\n  StoryIndexGenerator,\n  Tag,\n  experimental_loadStorybook,\n  mapStaticDir,\n} from 'storybook/internal/core-server';\nimport {\n  componentTransform,\n  isCsfFactoryPreview,\n  readConfig,\n  vitestTransform,\n} from 'storybook/internal/csf-tools';\nimport { MainFileMissingError } from 'storybook/internal/server-errors';\nimport { telemetry } from 'storybook/internal/telemetry';\nimport { oneWayHash } from 'storybook/internal/telemetry';\nimport type { Presets } from 'storybook/internal/types';\n\nimport { match } from 'micromatch';\nimport { join, normalize, relative, resolve, sep } from 'pathe';\nimport path from 'pathe';\nimport picocolors from 'picocolors';\nimport sirv from 'sirv';\nimport { dedent } from 'ts-dedent';\nimport type { PluginOption } from 'vite';\n\n// Shared plugins from builder-vite (relative import to prebundle without adding a package dependency)\nimport { withoutVitePlugins } from '../../../../builders/builder-vite/src/utils/without-vite-plugins.ts';\nimport type { InternalOptions, UserOptions } from './types.ts';\nimport { requiresProjectAnnotations } from './utils.ts';\n\nconst WORKING_DIR = process.cwd();\n\nconst defaultOptions = {\n  storybookScript: undefined,\n  configDir: resolve(join(WORKING_DIR, '.storybook')),\n  storybookUrl: 'http://localhost:6006',\n  disableAddonDocs: true,\n} satisfies UserOptions;\n\nconst extractTagsFromPreview = async (configDir: string) => {\n  const previewConfigPath = getInterpretedFile(join(resolve(configDir), 'preview'));\n\n  if (!previewConfigPath) {\n    return [];\n  }\n  const previewConfig = await readConfig(previewConfigPath);\n  return previewConfig.getFieldValue(['tags']) ?? [];\n};\n\nconst getStoryGlobsAndFiles = async (\n  presets: Presets,\n  directories: { configDir: string; workingDir: string }\n) => {\n  const stories = await presets.apply('stories', []);\n\n  const normalizedStories = normalizeStories(stories, {\n    configDir: directories.configDir,\n    workingDir: directories.workingDir,\n  });\n\n  const matchingStoryFiles = await StoryIndexGenerator.findMatchingFilesForSpecifiers(\n    normalizedStories,\n    directories.workingDir\n  );\n\n  return {\n    storiesGlobs: stories,\n    storiesFiles: StoryIndexGenerator.storyFileNames(\n      new Map(matchingStoryFiles.map(([specifier, cache]) => [specifier, cache]))\n    ),\n  };\n};\n\n/**\n * Plugin to stub MDX imports during testing This prevents the need to process MDX files in the test\n * environment\n */\nconst mdxStubPlugin: Plugin = {\n  name: 'storybook:stub-mdx-plugin',\n  enforce: 'pre',\n  resolveId(id) {\n    if (id.endsWith('.mdx')) {\n      return id;\n    }\n    return null;\n  },\n  load(id) {\n    if (id.endsWith('.mdx')) {\n      return `export default {};`;\n    }\n    return null;\n  },\n};\n\n// Transforming components and extracting args can be expensive because of docgen\n// so we pass the paths via env variable and use as filter to only transform the files we need\nconst getComponentTestPaths = (): string[] => {\n  const envPaths = process.env.STORYBOOK_COMPONENT_PATHS;\n\n  if (!envPaths) {\n    return [];\n  }\n\n  return envPaths.split(';').filter(Boolean);\n};\n\nconst createComponentTestTransformPlugin = (presets: Presets, configDir: string): Plugin => {\n  const storybookComponentTestPaths: string[] = getComponentTestPaths();\n\n  return {\n    name: 'storybook:component-test-transform-plugin',\n    transform: {\n      order: 'pre',\n      async handler(code, id) {\n        if (!optionalEnvToBoolean(process.env.VITEST) || storybookComponentTestPaths.length === 0) {\n          return code;\n        }\n\n        const resolvedId = path.resolve(id);\n        const matches = storybookComponentTestPaths.some(\n          (testPath) =>\n            resolvedId === testPath ||\n            resolvedId.startsWith(testPath + path.sep) ||\n            resolvedId.endsWith(testPath)\n        );\n\n        // We only transform paths included in STORYBOOK_COMPONENT_PATHS\n        if (!matches) {\n          return code;\n        }\n\n        const result = await componentTransform({\n          code,\n          fileName: id,\n          getComponentArgTypes: async ({ componentName, fileName }) =>\n            presets.apply('internal_getArgTypesData', null, {\n              componentFilePath: fileName,\n              componentExportName: componentName,\n              configDir,\n            }),\n        });\n\n        return result.code;\n      },\n    },\n  };\n};\n\nexport const storybookTest = async (options?: UserOptions): Promise<Plugin[]> => {\n  if (!optionalEnvToBoolean(process.env.VITEST)) {\n    return [];\n  }\n  const finalOptions = {\n    ...defaultOptions,\n    ...options,\n    configDir: options?.configDir\n      ? resolve(WORKING_DIR, options.configDir)\n      : defaultOptions.configDir,\n    tags: {\n      include: options?.tags?.include ?? [Tag.TEST],\n      exclude: options?.tags?.exclude ?? [],\n      skip: options?.tags?.skip ?? [],\n    },\n  } as InternalOptions;\n\n  if (optionalEnvToBoolean(process.env.DEBUG)) {\n    finalOptions.debug = true;\n  }\n\n  // To be accessed by the global setup file\n  process.env.__STORYBOOK_URL__ = finalOptions.storybookUrl;\n  process.env.__STORYBOOK_SCRIPT__ = finalOptions.storybookScript;\n\n  // We signal the test runner that we are not running it via Storybook\n  // We are overriding the environment variable to 'true' if vitest runs via @storybook/addon-vitest's backend\n  const isVitestStorybook = optionalEnvToBoolean(process.env.VITEST_STORYBOOK);\n\n  const directories = {\n    configDir: finalOptions.configDir,\n    workingDir: WORKING_DIR,\n  };\n\n  const { presets } = await experimental_loadStorybook({\n    configDir: finalOptions.configDir,\n    packageJson: {},\n  });\n\n  const stories = await presets.apply('stories', []);\n\n  const commonConfig = { root: resolve(finalOptions.configDir, '..') };\n\n  const [\n    corePlugins,\n    { storiesGlobs },\n    framework,\n    viteConfigFromStorybook,\n    staticDirs,\n    previewLevelTags,\n    core,\n    features,\n  ] = await Promise.all([\n    presets.apply<PluginOption[]>('viteCorePlugins', []),\n    getStoryGlobsAndFiles(presets, directories),\n    presets.apply('framework', undefined),\n    presets.apply<{ plugins?: Plugin[]; root: string }>('viteFinal', commonConfig),\n    presets.apply('staticDirs', []),\n    extractTagsFromPreview(finalOptions.configDir),\n    presets.apply('core'),\n    presets.apply('features', {}),\n  ]);\n\n  const pluginsToIgnore = [\n    'storybook:react-docgen-plugin',\n    'vite:react-docgen-typescript', // aka @joshwooding/vite-plugin-react-docgen-typescript\n    'storybook:svelte-docgen-plugin',\n    'storybook:vue-component-meta-plugin',\n  ];\n\n  if (finalOptions.disableAddonDocs) {\n    pluginsToIgnore.push('storybook:package-deduplication', 'storybook:mdx-plugin');\n  }\n\n  // filter out plugins that we know are unnecesary for tests, eg. docgen plugins\n  const plugins: Plugin[] = [\n    ...(corePlugins as Plugin[]),\n    ...(await withoutVitePlugins(viteConfigFromStorybook.plugins ?? [], pluginsToIgnore)),\n  ];\n\n  if (finalOptions.disableAddonDocs) {\n    plugins.push(mdxStubPlugin);\n  }\n\n  const storybookTestPlugin: Plugin = {\n    name: 'vite-plugin-storybook-test',\n    async transformIndexHtml(html) {\n      const [headHtmlSnippet, bodyHtmlSnippet] = await Promise.all([\n        presets.apply('previewHead'),\n        presets.apply('previewBody'),\n      ]);\n\n      return html\n        .replace('</head>', `${headHtmlSnippet ?? ''}</head>`)\n        .replace('<body>', `<body>${bodyHtmlSnippet ?? ''}`);\n    },\n    async config(nonMutableInputConfig, { mode }) {\n      if (mode) {\n        // Needed for `preset.apply('env')` to work correctly\n        process.env.BUILD_TARGET = mode;\n      }\n      // ! We're not mutating the input config, instead we're returning a new partial config\n      // ! see https://vite.dev/guide/api-plugin.html#config\n      try {\n        await validateConfigurationFiles(finalOptions.configDir);\n      } catch {\n        throw new MainFileMissingError({\n          location: finalOptions.configDir,\n          source: 'vitest',\n        });\n      }\n\n      const frameworkName = typeof framework === 'string' ? framework : framework.name;\n\n      // If we end up needing to know if we are running in browser mode later\n      // const isRunningInBrowserMode = config.plugins.find((plugin: Plugin) =>\n      //   plugin.name?.startsWith('vitest:browser')\n      // )\n\n      const testConfig = nonMutableInputConfig.test;\n      finalOptions.vitestRoot =\n        testConfig?.dir || testConfig?.root || nonMutableInputConfig.root || process.cwd();\n\n      const includeStories = stories\n        .map((story) => {\n          let storyPath;\n\n          if (typeof story === 'string') {\n            storyPath = story;\n          } else {\n            storyPath = `${story.directory}/${story.files ?? DEFAULT_FILES_PATTERN}`;\n          }\n\n          return join(finalOptions.configDir, storyPath);\n        })\n        .map((story) => {\n          return relative(finalOptions.vitestRoot, story);\n        });\n\n      finalOptions.includeStories = includeStories;\n      const projectId = oneWayHash(finalOptions.configDir);\n\n      const areProjectAnnotationRequired = await requiresProjectAnnotations(\n        nonMutableInputConfig.test,\n        finalOptions\n      );\n\n      const internalSetupFiles = (\n        [\n          '@storybook/addon-vitest/internal/setup-file',\n          areProjectAnnotationRequired &&\n            '@storybook/addon-vitest/internal/setup-file-with-project-annotations',\n        ].filter(Boolean) as string[]\n      ).map((filePath) => fileURLToPath(import.meta.resolve(filePath)));\n\n      const baseConfig: Omit<ViteUserConfig, 'plugins'> = {\n        cacheDir: resolvePathInStorybookCache('sb-vitest', projectId),\n        test: {\n          expect: { requireAssertions: false },\n          setupFiles: [\n            ...internalSetupFiles,\n            // if the existing setupFiles is a string, we have to include it otherwise we're overwriting it\n            typeof nonMutableInputConfig.test?.setupFiles === 'string' &&\n              nonMutableInputConfig.test?.setupFiles,\n          ].filter(Boolean) as string[],\n\n          ...(finalOptions.storybookScript\n            ? {\n                globalSetup: [\n                  fileURLToPath(\n                    import.meta.resolve('@storybook/addon-vitest/internal/global-setup')\n                  ),\n                ],\n              }\n            : {}),\n\n          env: {\n            /**\n             * We do this late, because we need vitest's --mode to be available and set to\n             * BUILD_MODE. Unfortunately, the dependencies we use to load .env files can only be\n             * configured using that environment variable. We need it to be synced up with the mode\n             * that vitest is running in, or risk leaking envs from the wrong file.\n             *\n             * @see https://github.com/storybookjs/storybook/issues/33101\n             */\n            ...(await presets.apply('env', {})),\n            // To be accessed by the setup file\n            __STORYBOOK_URL__: finalOptions.storybookUrl,\n\n            VITEST_STORYBOOK: isVitestStorybook ? 'true' : 'false',\n            __VITEST_INCLUDE_TAGS__: finalOptions.tags.include.join(','),\n            __VITEST_EXCLUDE_TAGS__: finalOptions.tags.exclude.join(','),\n            __VITEST_SKIP_TAGS__: finalOptions.tags.skip.join(','),\n          },\n\n          include: [...includeStories, ...getComponentTestPaths()],\n          exclude: [\n            ...(nonMutableInputConfig.test?.exclude ?? []),\n            join(relative(finalOptions.vitestRoot, process.cwd()), '**/*.mdx').replaceAll(sep, '/'),\n          ],\n\n          // if the existing deps.inline is true, we keep it as-is, because it will inline everything\n          // TODO: Remove the check once we don't support Vitest 3 anymore\n          ...(nonMutableInputConfig.test?.server?.deps?.inline !== true\n            ? {\n                server: {\n                  deps: {\n                    inline: ['@storybook/addon-vitest'],\n                  },\n                },\n              }\n            : {}),\n\n          browser: {\n            commands: {\n              getInitialGlobals: () => {\n                const envConfig = JSON.parse(process.env.VITEST_STORYBOOK_CONFIG ?? '{}');\n\n                const shouldRunA11yTests = isVitestStorybook ? (envConfig.a11y ?? false) : true;\n                const globals: Record<string, unknown> = {};\n                globals.a11y = {\n                  manual: !shouldRunA11yTests,\n                };\n\n                if (process.env.STORYBOOK_COMPONENT_PATHS) {\n                  globals.ghostStories = {\n                    enabled: true,\n                  };\n                }\n\n                return globals;\n              },\n            },\n            // if there is a test.browser config AND test.browser.screenshotFailures is not explicitly set, we set it to false\n            ...(nonMutableInputConfig.test?.browser &&\n            nonMutableInputConfig.test.browser.screenshotFailures === undefined\n              ? {\n                  screenshotFailures: false,\n                }\n              : {}),\n          },\n        },\n\n        optimizeDeps: {\n          include: [\n            '@storybook/addon-vitest/internal/setup-file',\n            '@storybook/addon-vitest/internal/global-setup',\n            '@storybook/addon-vitest/internal/test-utils',\n            'storybook/preview-api',\n            ...(frameworkName?.includes('react') || frameworkName?.includes('nextjs')\n              ? ['react-dom/test-utils']\n              : []),\n          ],\n        },\n\n        define: {\n          ...(frameworkName?.includes('vue3')\n            ? { __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false' }\n            : {}),\n          FEATURES: JSON.stringify(features),\n        },\n      };\n\n      const config = mergeConfig(baseConfig, viteConfigFromStorybook);\n\n      // alert the user of problems\n      if ((nonMutableInputConfig.test?.include?.length ?? 0) > 0) {\n        // remove the user's existing include, because we're replacing it with our own heuristic based on main.ts#stories\n        // @ts-expect-error: Ignore\n        nonMutableInputConfig.test.include = [];\n        console.log(\n          picocolors.yellow(dedent`\n            Warning: Starting in Storybook 8.5.0-alpha.18, the \"test.include\" option in Vitest is discouraged in favor of just using the \"stories\" field in your Storybook configuration.\n\n            The values you passed to \"test.include\" will be ignored, please remove them from your Vitest configuration where the Storybook plugin is applied.\n            \n            More info: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#addon-test-indexing-behavior-of-storybookaddon-test-is-changed\n          `)\n        );\n      }\n\n      // return the new config, it will be deep-merged by vite\n      return config;\n    },\n    configureVitest(context) {\n      context.vitest.config.coverage.exclude.push('storybook-static');\n\n      if (\n        !core?.disableTelemetry &&\n        !optionalEnvToBoolean(process.env.STORYBOOK_DISABLE_TELEMETRY)\n      ) {\n        // NOTE: we start telemetry immediately but do not wait on it. Typically it should complete\n        // before the tests do. If not we may miss the event, we are OK with that.\n        telemetry(\n          'test-run',\n          {\n            runner: 'vitest',\n            watch: context.vitest.config.watch,\n            coverage: !!context.vitest.config.coverage?.enabled,\n          },\n          { configDir: finalOptions.configDir }\n        );\n      }\n    },\n    async configureServer(server) {\n      if (staticDirs) {\n        for (const staticDir of staticDirs) {\n          try {\n            const { staticPath, targetEndpoint } = mapStaticDir(staticDir, directories.configDir);\n            server.middlewares.use(\n              targetEndpoint,\n              sirv(staticPath, {\n                dev: true,\n                etag: true,\n                extensions: [],\n              })\n            );\n          } catch (e) {\n            console.warn(e);\n          }\n        }\n      }\n    },\n    async transform(code, id) {\n      const relativeId = relative(finalOptions.vitestRoot, id);\n\n      if (match([relativeId], finalOptions.includeStories).length > 0) {\n        return vitestTransform({\n          code,\n          fileName: id,\n          configDir: finalOptions.configDir,\n          tagsFilter: finalOptions.tags,\n          stories: storiesGlobs,\n          previewLevelTags,\n        });\n      }\n    },\n  };\n\n  if (getComponentTestPaths().length > 0) {\n    plugins.push(createComponentTestTransformPlugin(presets, finalOptions.configDir));\n  }\n\n  plugins.push(storybookTestPlugin);\n\n  // When running tests via the Storybook UI, we need\n  // to find the right project to run, thus we override\n  // with a unique identifier using the path to the config dir\n  if (isVitestStorybook) {\n    const projectName = `storybook:${normalize(finalOptions.configDir)}`;\n    plugins.push({\n      name: 'storybook:workspace-name-override',\n      config: {\n        order: 'pre',\n        handler: () => {\n          return {\n            test: {\n              name: projectName,\n            },\n          };\n        },\n      },\n    });\n  }\n  return plugins;\n};\n\nexport default storybookTest;\n"
  },
  {
    "path": "code/addons/vitest/src/vitest-plugin/setup-file-with-project-annotations.ts",
    "content": "import { setProjectAnnotations } from 'storybook/internal/preview-api';\n\n// @ts-expect-error - virtual module provided by storybook-project-annotations-plugin\nimport { getProjectAnnotations } from 'virtual:/@storybook/builder-vite/project-annotations.js';\n\nsetProjectAnnotations(getProjectAnnotations());\n"
  },
  {
    "path": "code/addons/vitest/src/vitest-plugin/setup-file.test.ts",
    "content": "import { afterEach, beforeEach, describe, expect, it } from 'vitest';\n\nimport { type Task, modifyErrorMessage } from './setup-file.ts';\n\ndescribe('modifyErrorMessage', () => {\n  const originalUrl = import.meta.env.__STORYBOOK_URL__;\n  beforeEach(() => {\n    import.meta.env.__STORYBOOK_URL__ = 'http://localhost:6006';\n  });\n\n  afterEach(() => {\n    import.meta.env.__STORYBOOK_URL__ = originalUrl;\n  });\n\n  it('should modify the error message if the test is failing and there is a storyId in the task meta', () => {\n    const task: Task = {\n      type: 'test',\n      result: {\n        state: 'fail',\n        errors: [{ message: 'Original error message' }],\n      },\n      meta: { storyId: 'my-story' },\n    };\n\n    modifyErrorMessage({ task });\n\n    expect(task.result?.errors?.[0].message).toMatchInlineSnapshot(`\n      \"\n      \u001b[34mClick to debug the error directly in Storybook: http://localhost:6006/?path=/story/my-story&addonPanel=storybook/interactions/panel\u001b[39m\n\n      Original error message\"\n    `);\n    expect(task.result?.errors?.[0].message).toContain('Original error message');\n  });\n\n  it('should not modify the error message if task type is not \"test\"', () => {\n    const task: Task = {\n      type: 'suite',\n      result: {\n        state: 'fail',\n        errors: [{ message: 'Original error message' }],\n      },\n      meta: { storyId: 'my-story' },\n    };\n\n    modifyErrorMessage({ task });\n\n    expect(task.result?.errors?.[0].message).toBe('Original error message');\n  });\n\n  it('should not modify the error message if task result state is not \"fail\"', () => {\n    const task: Task = {\n      type: 'test',\n      result: {\n        state: 'pass',\n      },\n      meta: { storyId: 'my-story' },\n    };\n\n    modifyErrorMessage({ task });\n\n    expect(task.result?.errors).toBeUndefined();\n  });\n\n  it('should not modify the error message if meta.storyId is not present', () => {\n    const task: Task = {\n      type: 'test',\n      result: {\n        state: 'fail',\n        errors: [{ message: 'Non story test failure' }],\n      },\n      meta: {},\n    };\n\n    modifyErrorMessage({ task });\n\n    expect(task.result?.errors?.[0].message).toBe('Non story test failure');\n  });\n});\n"
  },
  {
    "path": "code/addons/vitest/src/vitest-plugin/setup-file.ts",
    "content": "import { afterEach, beforeAll, vi } from 'vitest';\nimport type { RunnerTask } from 'vitest';\n\nimport { Channel } from 'storybook/internal/channels';\n\nimport { COMPONENT_TESTING_PANEL_ID } from '../constants.ts';\n\ndeclare global {\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore - The module is augmented elsewhere but we need to duplicate it to avoid issues in no-link mode.\n  // eslint-disable-next-line no-var\n  var __STORYBOOK_ADDONS_CHANNEL__: Channel;\n}\n\nexport type Task = Partial<RunnerTask> & {\n  meta: Record<string, any>;\n};\n\nconst transport = { setHandler: vi.fn(), send: vi.fn() };\nglobalThis.__STORYBOOK_ADDONS_CHANNEL__ ??= new Channel({ transport });\n\nexport const modifyErrorMessage = ({ task }: { task: Task }) => {\n  const meta = task.meta;\n  if (\n    task.type === 'test' &&\n    task.result?.state === 'fail' &&\n    meta.storyId &&\n    task.result.errors?.[0]\n  ) {\n    const currentError = task.result.errors[0];\n    const storybookUrl = import.meta.env.__STORYBOOK_URL__;\n    const storyUrl = `${storybookUrl}/?path=/story/${meta.storyId}&addonPanel=${COMPONENT_TESTING_PANEL_ID}`;\n    currentError.message = `\\n\\x1B[34mClick to debug the error directly in Storybook: ${storyUrl}\\x1B[39m\\n\\n${currentError.message}`;\n  }\n};\n\nbeforeAll(() => {\n  if (globalThis.globalProjectAnnotations) {\n    return globalThis.globalProjectAnnotations.beforeAll();\n  }\n});\n\nafterEach(modifyErrorMessage);\n"
  },
  {
    "path": "code/addons/vitest/src/vitest-plugin/test-utils.ts",
    "content": "import { type RunnerTask, type TaskMeta, type TestContext } from 'vitest';\n\nimport { type Meta, type Story, getStoryChildren, isStory } from 'storybook/internal/csf';\nimport type { ComponentAnnotations, ComposedStoryFn, Renderer } from 'storybook/internal/types';\n\nimport { server } from '@vitest/browser/context';\nimport { type Report, composeStory, getCsfFactoryAnnotations } from 'storybook/preview-api';\n\nimport { setViewport } from './viewports.ts';\n\ndeclare module 'vitest/browser' {\n  interface BrowserCommands {\n    getInitialGlobals: () => Promise<Record<string, any>>;\n  }\n}\n\nconst { getInitialGlobals } = server.commands;\n\n/**\n * Converts a file URL to a file path, handling URL encoding\n *\n * @param url The file URL to convert (e.g. file:///path/to/file.js)\n * @returns The decoded file path\n */\nexport const convertToFilePath = (url: string): string => {\n  // Remove the file:// protocol\n  const path = url.replace(/^file:\\/\\//, '');\n  // Handle Windows paths\n  const normalizedPath = path.replace(/^\\/+([a-zA-Z]:)/, '$1');\n  // Convert %20 to spaces\n  return normalizedPath.replace(/%20/g, ' ');\n};\n\nexport const testStory = ({\n  exportName,\n  story,\n  meta,\n  skipTags,\n  storyId,\n  componentPath,\n  testName,\n  componentName,\n}: {\n  exportName: string;\n  story: ComposedStoryFn | Story<Renderer>;\n  meta: ComponentAnnotations | Meta<Renderer>;\n  skipTags: string[];\n  storyId: string;\n  componentPath?: string;\n  testName?: string;\n  componentName?: string;\n}) => {\n  return async (context: TestContext & { story: ComposedStoryFn }) => {\n    const annotations = getCsfFactoryAnnotations(story, meta);\n\n    const test =\n      isStory(story) && testName\n        ? getStoryChildren(story).find((child) => child.input.name === testName)\n        : undefined;\n\n    const storyAnnotations = test ? test.input : annotations.story;\n\n    const composedStory = composeStory(\n      storyAnnotations,\n      annotations.meta!,\n      { initialGlobals: (await getInitialGlobals?.()) ?? {} },\n      annotations.preview ?? globalThis.globalProjectAnnotations,\n      exportName\n    );\n\n    if (composedStory === undefined || skipTags?.some((tag) => composedStory.tags.includes(tag))) {\n      context.skip();\n    }\n\n    context.story = composedStory;\n\n    const _task = context.task as RunnerTask & {\n      meta: TaskMeta & {\n        storyId: string;\n        reports: Report[];\n        componentPath?: string;\n        componentName?: string;\n      };\n    };\n\n    // The id will always be present, calculated by CsfFile\n    // and is needed so that we can add the test to the story in Storybook's UI for the status\n    _task.meta.storyId = storyId;\n    _task.meta.componentPath = componentPath;\n    _task.meta.componentName = componentName;\n\n    await setViewport(composedStory.parameters, composedStory.globals);\n\n    await composedStory.run(undefined);\n\n    _task.meta.reports = composedStory.reporting.reports;\n  };\n};\n"
  },
  {
    "path": "code/addons/vitest/src/vitest-plugin/types.ts",
    "content": "export type UserOptions = {\n  /**\n   * The directory where the Storybook configuration is located, relative to the vitest\n   * configuration file. If not provided, the plugin will use '.storybook' in the current working\n   * directory.\n   *\n   * @default '.storybook'\n   */\n  configDir?: string;\n  /**\n   * Optional script to run Storybook. If provided, Vitest will start Storybook using this script\n   * when ran in watch mode.\n   *\n   * @default undefined\n   */\n  storybookScript?: string;\n  /**\n   * The URL where Storybook is hosted. This is used to provide a link to the story in the test\n   * output on failures.\n   *\n   * @default 'http://localhost:6006'\n   */\n  storybookUrl?: string;\n  /** Tags to include, exclude, or skip. These tags are defined as annotations in your story or meta. */\n  tags?: {\n    include?: string[];\n    exclude?: string[];\n    skip?: string[];\n  };\n\n  /**\n   * Whether to disable addon docs features while running tests.\n   *\n   * Most users don't need addon docs for tests, the only scenario where you might need it is if you\n   * need to read and parse MDX files as part of rendering your components.\n   *\n   * @default true\n   */\n  disableAddonDocs?: boolean;\n};\n\nexport type InternalOptions = Required<UserOptions> & {\n  debug: boolean;\n  tags: Required<UserOptions['tags']>;\n  includeStories: string[];\n  /** This is the root of the vitest config where the `storybookTest` plugin is applied */\n  vitestRoot: string;\n};\n"
  },
  {
    "path": "code/addons/vitest/src/vitest-plugin/utils.ts",
    "content": "import { readFileSync } from 'node:fs';\n\nimport type { ViteUserConfig } from 'vitest/config';\n\nimport { CLI_COLORS, logger } from 'storybook/internal/node-logger';\n\nimport { dirname, resolve } from 'pathe';\nimport { dedent } from 'ts-dedent';\n\nimport type { InternalOptions } from './types.ts';\n\nlet hasLoggedDeprecationWarning = false;\n\nconst logBoxOnce = (message: string) => {\n  if (!hasLoggedDeprecationWarning) {\n    logger.logBox(message);\n    hasLoggedDeprecationWarning = true;\n  }\n};\n\nexport async function requiresProjectAnnotations(\n  testConfig: ViteUserConfig['test'] | undefined,\n  finalOptions: InternalOptions\n) {\n  const setupFiles = Array.isArray(testConfig?.setupFiles)\n    ? testConfig.setupFiles\n    : typeof testConfig?.setupFiles === 'string'\n      ? [testConfig.setupFiles]\n      : [];\n\n  const userSetupFiles = setupFiles\n    .map((setupFile) => {\n      try {\n        return resolve(finalOptions.vitestRoot, setupFile);\n      } catch (e) {\n        return null;\n      }\n    })\n    .filter(Boolean) as string[];\n\n  const hasStorybookAnnotations = userSetupFiles.find((setupFile) => {\n    const hasStorybookSetupFileName = dirname(setupFile) === finalOptions.configDir;\n\n    if (!hasStorybookSetupFileName) {\n      return false;\n    }\n\n    // Check if the file contains setProjectAnnotations\n    const setupFileContent = readFileSync(setupFile, 'utf-8');\n    return setupFileContent.includes('setProjectAnnotations');\n  });\n\n  if (hasStorybookAnnotations) {\n    logBoxOnce(dedent`\n      ${CLI_COLORS.info('Info')}: Found a setup file with \"setProjectAnnotations\".\n      Skipping automatic provisioning of preview annotations to avoid conflicts. Since Storybook 10.3, \"@storybook/addon-vitest\" applies these automatically.\n      You can safely remove the \"setProjectAnnotations\" call from your setup file, or remove the file entirely if you don't have custom code there.\n    `);\n\n    return false;\n  }\n\n  return true;\n}\n"
  },
  {
    "path": "code/addons/vitest/src/vitest-plugin/viewports.test.ts",
    "content": "import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { page } from '@vitest/browser/context';\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nimport {\n  DEFAULT_VIEWPORT_DIMENSIONS,\n  type ViewportsGlobal,\n  type ViewportsParam,\n  setViewport,\n} from './viewports.ts';\n\nvi.mock('@vitest/browser/context', () => ({\n  page: {\n    viewport: vi.fn(),\n  },\n}));\n\ndescribe('setViewport', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n    globalThis.__vitest_browser__ = true;\n  });\n\n  afterEach(() => {\n    globalThis.__vitest_browser__ = false;\n  });\n\n  it('should no op outside when not in Vitest browser mode', async () => {\n    globalThis.__vitest_browser__ = false;\n\n    await setViewport();\n    expect(page.viewport).not.toHaveBeenCalled();\n  });\n\n  describe('globals API', () => {\n    it('should fall back to DEFAULT_VIEWPORT_DIMENSIONS if selected viewport does not exist', async () => {\n      const viewportsGlobal: ViewportsGlobal = {\n        value: 'nonExistentViewport',\n      };\n\n      await setViewport({}, { viewport: viewportsGlobal });\n      expect(page.viewport).toHaveBeenCalledWith(\n        DEFAULT_VIEWPORT_DIMENSIONS.width,\n        DEFAULT_VIEWPORT_DIMENSIONS.height\n      );\n    });\n\n    it('should fall back to DEFAULT_VIEWPORT_DIMENSIONS if viewport is disabled, even if a viewport is set', async () => {\n      const viewportsParam: ViewportsParam = {\n        options: INITIAL_VIEWPORTS,\n        disable: true,\n      };\n      const viewportsGlobal: ViewportsGlobal = {\n        value: 'ipad',\n      };\n\n      await setViewport({ viewport: viewportsParam }, { viewport: viewportsGlobal });\n      expect(page.viewport).toHaveBeenCalledWith(\n        DEFAULT_VIEWPORT_DIMENSIONS.width,\n        DEFAULT_VIEWPORT_DIMENSIONS.height\n      );\n    });\n\n    it('should set the dimensions of viewport from INITIAL_VIEWPORTS', async () => {\n      const viewportsParam: ViewportsParam = {\n        options: INITIAL_VIEWPORTS,\n      };\n      const viewportsGlobal: ViewportsGlobal = {\n        // supported by default in addon viewports\n        value: 'ipad',\n      };\n\n      await setViewport({ viewport: viewportsParam }, { viewport: viewportsGlobal });\n      expect(page.viewport).toHaveBeenCalledWith(768, 1024);\n    });\n\n    it('should set custom defined viewport dimensions', async () => {\n      const viewportsParam: ViewportsParam = {\n        options: {\n          customViewport: {\n            name: 'Custom Viewport',\n            type: 'mobile',\n            styles: {\n              width: '800px',\n              height: '600px',\n            },\n          },\n        },\n      };\n      const viewportsGlobal: ViewportsGlobal = {\n        value: 'customViewport',\n      };\n\n      await setViewport({ viewport: viewportsParam }, { viewport: viewportsGlobal });\n      expect(page.viewport).toHaveBeenCalledWith(800, 600);\n    });\n\n    it('should correctly handle percentage-based dimensions', async () => {\n      const viewportsParam: ViewportsParam = {\n        options: {\n          percentageViewport: {\n            name: 'Percentage Viewport',\n            type: 'desktop',\n            styles: {\n              width: '50%',\n              height: '50%',\n            },\n          },\n        },\n      };\n      const viewportsGlobal: ViewportsGlobal = {\n        value: 'percentageViewport',\n      };\n\n      await setViewport({ viewport: viewportsParam }, { viewport: viewportsGlobal });\n      expect(page.viewport).toHaveBeenCalledWith(600, 450); // 50% of 1920 and 1080\n    });\n\n    it('should correctly handle vw and vh based dimensions', async () => {\n      const viewportsParam: ViewportsParam = {\n        options: {\n          viewportUnits: {\n            name: 'VW/VH Viewport',\n            type: 'desktop',\n            styles: {\n              width: '50vw',\n              height: '50vh',\n            },\n          },\n        },\n      };\n      const viewportsGlobal: ViewportsGlobal = {\n        value: 'viewportUnits',\n      };\n\n      await setViewport({ viewport: viewportsParam }, { viewport: viewportsGlobal });\n      expect(page.viewport).toHaveBeenCalledWith(600, 450); // 50% of 1920 and 1080\n    });\n\n    it('should correctly handle em based dimensions', async () => {\n      const viewportsParam: ViewportsParam = {\n        options: {\n          viewportUnits: {\n            name: 'em/rem Viewport',\n            type: 'mobile',\n            styles: {\n              width: '20em',\n              height: '40rem',\n            },\n          },\n        },\n      };\n      const viewportsGlobal: ViewportsGlobal = {\n        value: 'viewportUnits',\n      };\n\n      await setViewport({ viewport: viewportsParam }, { viewport: viewportsGlobal });\n      expect(page.viewport).toHaveBeenCalledWith(320, 640); // dimensions * 16\n    });\n\n    it('should throw an error for unsupported dimension values', async () => {\n      const viewportsParam: ViewportsParam = {\n        options: {\n          invalidViewport: {\n            name: 'Invalid Viewport',\n            type: 'desktop',\n            styles: {\n              width: 'calc(100vw - 20px)',\n              height: '10pc',\n            },\n          },\n        },\n      };\n      const viewportsGlobal: ViewportsGlobal = {\n        value: 'invalidViewport',\n      };\n\n      await expect(setViewport({ viewport: viewportsParam }, { viewport: viewportsGlobal })).rejects\n        .toThrowErrorMatchingInlineSnapshot(`\n      [SB_ADDON_VITEST_0001 (UnsupportedViewportDimensionError): Encountered an unsupported value \"calc(100vw - 20px)\" when setting the viewport width dimension.\n\n      The Storybook plugin only supports values in the following units:\n      - px, vh, vw, em, rem and %.\n\n      You can either change the viewport for this story to use one of the supported units or skip the test by adding '!test' to the story's tags per https://storybook.js.org/docs/writing-stories/tags]\n    `);\n      expect(page.viewport).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('parameters API (legacy)', () => {\n    it('should no op outside when not in Vitest browser mode', async () => {\n      globalThis.__vitest_browser__ = false;\n\n      await setViewport();\n      expect(page.viewport).not.toHaveBeenCalled();\n    });\n\n    it('should fall back to DEFAULT_VIEWPORT_DIMENSIONS if defaultViewport does not exist', async () => {\n      const viewportsParam: any = {\n        defaultViewport: 'nonExistentViewport',\n      };\n\n      await setViewport({ viewport: viewportsParam });\n      expect(page.viewport).toHaveBeenCalledWith(\n        DEFAULT_VIEWPORT_DIMENSIONS.width,\n        DEFAULT_VIEWPORT_DIMENSIONS.height\n      );\n    });\n\n    it('should set the dimensions of viewport from INITIAL_VIEWPORTS', async () => {\n      const viewportsParam: any = {\n        viewports: INITIAL_VIEWPORTS,\n        // supported by default in addon viewports\n        defaultViewport: 'ipad',\n      };\n\n      await setViewport({ viewport: viewportsParam });\n      expect(page.viewport).toHaveBeenCalledWith(768, 1024);\n    });\n\n    it('should set custom defined viewport dimensions', async () => {\n      const viewportsParam: ViewportsParam = {\n        defaultViewport: 'customViewport',\n        viewports: {\n          customViewport: {\n            name: 'Custom Viewport',\n            type: 'mobile',\n            styles: {\n              width: '800px',\n              height: '600px',\n            },\n          },\n        },\n      };\n\n      await setViewport({ viewport: viewportsParam });\n      expect(page.viewport).toHaveBeenCalledWith(800, 600);\n    });\n\n    it('should correctly handle percentage-based dimensions', async () => {\n      const viewportsParam: ViewportsParam = {\n        defaultViewport: 'percentageViewport',\n        viewports: {\n          percentageViewport: {\n            name: 'Percentage Viewport',\n            type: 'desktop',\n            styles: {\n              width: '50%',\n              height: '50%',\n            },\n          },\n        },\n      };\n\n      await setViewport({ viewport: viewportsParam });\n      expect(page.viewport).toHaveBeenCalledWith(600, 450); // 50% of 1920 and 1080\n    });\n\n    it('should correctly handle vw and vh based dimensions', async () => {\n      const viewportsParam: ViewportsParam = {\n        defaultViewport: 'viewportUnits',\n        viewports: {\n          viewportUnits: {\n            name: 'VW/VH Viewport',\n            type: 'desktop',\n            styles: {\n              width: '50vw',\n              height: '50vh',\n            },\n          },\n        },\n      };\n\n      await setViewport({ viewport: viewportsParam });\n      expect(page.viewport).toHaveBeenCalledWith(600, 450); // 50% of 1920 and 1080\n    });\n\n    it('should correctly handle em based dimensions', async () => {\n      const viewportsParam: ViewportsParam = {\n        defaultViewport: 'viewportUnits',\n        viewports: {\n          viewportUnits: {\n            name: 'em/rem Viewport',\n            type: 'mobile',\n            styles: {\n              width: '20em',\n              height: '40rem',\n            },\n          },\n        },\n      };\n\n      await setViewport({ viewport: viewportsParam });\n      expect(page.viewport).toHaveBeenCalledWith(320, 640); // dimensions * 16\n    });\n\n    it('should throw an error for unsupported dimension values', async () => {\n      const viewportsParam: ViewportsParam = {\n        defaultViewport: 'invalidViewport',\n        viewports: {\n          invalidViewport: {\n            name: 'Invalid Viewport',\n            type: 'desktop',\n            styles: {\n              width: 'calc(100vw - 20px)',\n              height: '10pc',\n            },\n          },\n        },\n      };\n\n      await expect(setViewport({ viewport: viewportsParam })).rejects\n        .toThrowErrorMatchingInlineSnapshot(`\n      [SB_ADDON_VITEST_0001 (UnsupportedViewportDimensionError): Encountered an unsupported value \"calc(100vw - 20px)\" when setting the viewport width dimension.\n\n      The Storybook plugin only supports values in the following units:\n      - px, vh, vw, em, rem and %.\n\n      You can either change the viewport for this story to use one of the supported units or skip the test by adding '!test' to the story's tags per https://storybook.js.org/docs/writing-stories/tags]\n    `);\n      expect(page.viewport).not.toHaveBeenCalled();\n    });\n  });\n});\n"
  },
  {
    "path": "code/addons/vitest/src/vitest-plugin/viewports.ts",
    "content": "import type { Globals, Parameters } from 'storybook/internal/csf';\nimport { UnsupportedViewportDimensionError } from 'storybook/internal/preview-errors';\n\nimport { MINIMAL_VIEWPORTS } from 'storybook/viewport';\nimport type { ViewportMap } from 'storybook/viewport';\n\ndeclare global {\n  // eslint-disable-next-line no-var\n  var __vitest_browser__: boolean;\n}\n\nexport interface ViewportsParam {\n  defaultViewport?: string;\n  viewports?: ViewportMap;\n  options?: ViewportMap;\n  disable?: boolean;\n  disabled?: boolean;\n}\n\nexport interface ViewportsGlobal {\n  value?: string;\n  disable?: boolean;\n}\n\nexport const DEFAULT_VIEWPORT_DIMENSIONS = {\n  width: 1200,\n  height: 900,\n};\n\nconst validPixelOrNumber = /^\\d+(px)?$/;\nconst percentagePattern = /^(\\d+(\\.\\d+)?%)$/;\nconst vwPattern = /^(\\d+(\\.\\d+)?vw)$/;\nconst vhPattern = /^(\\d+(\\.\\d+)?vh)$/;\nconst emRemPattern = /^(\\d+)(em|rem)$/;\n\nconst parseDimension = (value: string, dimension: 'width' | 'height') => {\n  if (validPixelOrNumber.test(value)) {\n    return Number.parseInt(value, 10);\n  } else if (percentagePattern.test(value)) {\n    const percentageValue = parseFloat(value) / 100;\n    return Math.round(DEFAULT_VIEWPORT_DIMENSIONS[dimension] * percentageValue);\n  } else if (vwPattern.test(value)) {\n    const vwValue = parseFloat(value) / 100;\n    return Math.round(DEFAULT_VIEWPORT_DIMENSIONS.width * vwValue);\n  } else if (vhPattern.test(value)) {\n    const vhValue = parseFloat(value) / 100;\n    return Math.round(DEFAULT_VIEWPORT_DIMENSIONS.height * vhValue);\n  } else if (emRemPattern.test(value)) {\n    const emRemValue = Number.parseInt(value, 10);\n    return emRemValue * 16;\n  } else {\n    throw new UnsupportedViewportDimensionError({ dimension, value });\n  }\n};\n\nexport const setViewport = async (parameters: Parameters = {}, globals: Globals = {}) => {\n  let defaultViewport;\n  const viewportsParam: ViewportsParam = parameters.viewport ?? {};\n  const viewportsGlobal: ViewportsGlobal = globals.viewport ?? {};\n  const isDisabled = viewportsParam.disable || viewportsParam.disabled;\n\n  // Support new setting from globals, else use the one from parameters\n  if (viewportsGlobal.value && !isDisabled) {\n    defaultViewport = viewportsGlobal.value;\n  } else if (!isDisabled) {\n    defaultViewport = viewportsParam.defaultViewport;\n  }\n\n  const { page } = await import('@vitest/browser/context').catch(() => ({\n    page: null,\n  }));\n\n  if (!page || !globalThis.__vitest_browser__) {\n    return;\n  }\n\n  const options: ViewportMap = {\n    ...MINIMAL_VIEWPORTS,\n    ...viewportsParam.viewports,\n    ...viewportsParam.options,\n  };\n\n  let viewportWidth = DEFAULT_VIEWPORT_DIMENSIONS.width;\n  let viewportHeight = DEFAULT_VIEWPORT_DIMENSIONS.height;\n\n  if (defaultViewport && defaultViewport in options) {\n    const { styles } = options[defaultViewport];\n    if (styles?.width && styles?.height) {\n      const { width, height } = styles;\n      viewportWidth = parseDimension(width, 'width');\n      viewportHeight = parseDimension(height, 'height');\n    }\n  }\n\n  await page.viewport(viewportWidth, viewportHeight);\n};\n"
  },
  {
    "path": "code/addons/vitest/template/stories/basics.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport {\n  expect,\n  fireEvent,\n  fn,\n  userEvent as testUserEvent,\n  waitFor,\n  waitForElementToBeRemoved,\n  within,\n} from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Form,\n  args: {\n    onSuccess: fn(),\n  },\n  globals: {\n    sb_theme: 'light',\n  },\n  tags: ['!vitest'],\n};\n\nexport const Validation = {\n  play: async (context) => {\n    const { args, canvasElement, step } = context;\n    const canvas = within(canvasElement);\n\n    await step('Submit', async () => fireEvent.click(canvas.getByRole('button')));\n\n    await expect(args.onSuccess).not.toHaveBeenCalled();\n  },\n};\n\nexport const Type = {\n  play: async ({ canvasElement, userEvent }) => {\n    const canvas = within(canvasElement);\n    await userEvent.type(canvas.getByTestId('value'), 'foobar');\n  },\n};\n\nexport const Step = {\n  play: async ({ step }) => {\n    await step('Enter value', Type.play);\n  },\n};\n\nexport const TypeAndClear = {\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.clear(canvas.getByTestId('value'));\n\n    await userEvent.type(canvas.getByTestId('value'), 'initial value');\n    await userEvent.clear(canvas.getByTestId('value'));\n    await userEvent.type(canvas.getByTestId('value'), 'final value');\n  },\n};\n\nexport const Callback = {\n  play: async ({ args, canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    await step('Enter value', Type.play);\n\n    await step('Submit', async () => {\n      await fireEvent.click(canvas.getByRole('button'));\n    });\n\n    await expect(args.onSuccess).toHaveBeenCalled();\n  },\n};\n\n// NOTE: of course you can use `findByText()` to implicitly waitFor, but we want\n// an explicit test here\nexport const SyncWaitFor = {\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    await step('Submit form', Callback.play);\n    await waitFor(() => canvas.getByText('Completed!!'));\n    await waitForElementToBeRemoved(() => canvas.queryByText('Completed!!'), {\n      timeout: 2000,\n    });\n  },\n};\n\nexport const AsyncWaitFor = {\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    await step('Submit form', Callback.play);\n    await waitFor(async () => canvas.getByText('Completed!!'));\n    await waitForElementToBeRemoved(() => canvas.queryByText('Completed!!'), {\n      timeout: 2000,\n    });\n  },\n};\n\nexport const WithLoaders = {\n  loaders: [async () => new Promise((resolve) => setTimeout(resolve, 2000))],\n  play: async ({ step }) => {\n    await step('Submit form', Callback.play);\n  },\n};\n\nexport const UserEventSetup = {\n  play: async (context) => {\n    const { args, canvasElement, step, userEvent } = context;\n    const canvas = within(canvasElement);\n    await step('Select and type on input using user-event v14 setup', async () => {\n      const input = canvas.getByRole('textbox');\n      await userEvent.click(input);\n      await userEvent.type(input, 'Typing ...');\n    });\n    await step('Tab and press enter on submit button', async () => {\n      // Vitest's userEvent does not support pointer events, so we use storybook's\n      await testUserEvent.pointer([\n        { keys: '[TouchA>]', target: canvas.getByRole('textbox') },\n        { keys: '[/TouchA]' },\n      ]);\n      const submitButton = await canvas.findByRole('button');\n\n      if (navigator.userAgent.toLowerCase().includes('firefox')) {\n        // user event has a few issues on firefox, therefore we do it differently\n        await fireEvent.click(submitButton);\n      } else {\n        await userEvent.tab();\n        await userEvent.keyboard('{enter}');\n        await expect(submitButton).toHaveFocus();\n      }\n\n      await expect(args.onSuccess).toHaveBeenCalled();\n    });\n  },\n};\n\n/**\n * Demonstrates the expect.toThrow functionality from issue #28406\n * https://github.com/storybookjs/storybook/issues/28406\n *\n * This tests various forms of throw assertions to ensure they all work correctly.\n */\nexport const ToThrow = {\n  play: async () => {\n    await expect(() => {\n      throw new Error('test error');\n    }).toThrow();\n\n    await expect(() => {\n      throw new Error('specific error');\n    }).toThrowError();\n\n    await expect(() => {\n      throw new Error('specific message');\n    }).toThrow('specific message');\n\n    await expect(() => {\n      // This doesn't throw\n    }).not.toThrow();\n  },\n};\n"
  },
  {
    "path": "code/addons/vitest/template/stories/unhandled-errors.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { userEvent, within } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  args: {\n    label: 'Button',\n    // onClick: fn(), <-- this is intentionally missing to trigger an unhandled error\n  },\n  argTypes: {\n    onClick: { type: 'function' },\n  },\n  parameters: {\n    actions: { argTypesRegex: '^on[A-Z].*' },\n    chromatic: { disableSnapshot: true },\n  },\n  tags: ['!test', '!vitest'],\n};\n\nexport const Default = {\n  play: async (context) => {\n    const { args, canvasElement } = context;\n    const canvas = within(canvasElement);\n    await userEvent.click(canvas.getByRole('button'));\n  },\n};\n"
  },
  {
    "path": "code/addons/vitest/templates/vitest.config.3.2.template.ts",
    "content": "import path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { defineConfig } from 'vitest/config';\n\nimport { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n\nconst dirname =\n  typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n\n// More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\nexport default defineConfig({\n  test: {\n    projects: [\n      {\n        extends: true,\n        plugins: [\n          // The plugin will run tests for the stories defined in your Storybook config\n          // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n          storybookTest({ configDir: path.join(dirname, 'CONFIG_DIR') }),\n        ],\n        test: {\n          name: 'storybook',\n          browser: {\n            enabled: true,\n            headless: true,\n            provider: 'playwright',\n            instances: [{ browser: 'chromium' }],\n          },\n        },\n      },\n    ],\n  },\n});\n"
  },
  {
    "path": "code/addons/vitest/templates/vitest.config.4.template.ts",
    "content": "import path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { defineConfig } from 'vitest/config';\n\nimport { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n\nimport { playwright } from '@vitest/browser-playwright';\n\nconst dirname =\n  typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n\n// More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\nexport default defineConfig({\n  test: {\n    projects: [\n      {\n        extends: true,\n        plugins: [\n          // The plugin will run tests for the stories defined in your Storybook config\n          // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n          storybookTest({ configDir: path.join(dirname, 'CONFIG_DIR') }),\n        ],\n        test: {\n          name: 'storybook',\n          browser: {\n            enabled: true,\n            headless: true,\n            provider: playwright({}),\n            instances: [{ browser: 'chromium' }],\n          },\n        },\n      },\n    ],\n  },\n});\n"
  },
  {
    "path": "code/addons/vitest/templates/vitest.config.template.ts",
    "content": "import path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { defineConfig } from 'vitest/config';\n\nimport { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n\nconst dirname =\n  typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n\n// More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\nexport default defineConfig({\n  test: {\n    workspace: [\n      {\n        extends: true,\n        plugins: [\n          // The plugin will run tests for the stories defined in your Storybook config\n          // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n          storybookTest({ configDir: path.join(dirname, 'CONFIG_DIR') }),\n        ],\n        test: {\n          name: 'storybook',\n          browser: {\n            enabled: true,\n            headless: true,\n            provider: 'playwright',\n            instances: [{ browser: 'chromium' }],\n          },\n        },\n      },\n    ],\n  },\n});\n"
  },
  {
    "path": "code/addons/vitest/templates/vitest.workspace.template.ts",
    "content": "import path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { defineWorkspace } from 'vitest/config';\n\nimport { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n\nconst dirname =\n  typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));\n\n// More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\nexport default defineWorkspace([\n  'ROOT_CONFIG',\n  {\n    extends: 'EXTENDS_WORKSPACE',\n    plugins: [\n      // The plugin will run tests for the stories defined in your Storybook config\n      // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n      storybookTest({ configDir: path.join(dirname, 'CONFIG_DIR') }),\n    ],\n    test: {\n      name: 'storybook',\n      browser: {\n        enabled: true,\n        headless: true,\n        provider: 'playwright',\n        instances: [{ browser: 'chromium' }],\n      },\n    },\n  },\n]);\n"
  },
  {
    "path": "code/addons/vitest/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"rootDir\": \"../../../\",\n    \"types\": [\"vitest\"],\n    \"strict\": true\n  },\n  \"include\": [\"src/**/*\", \"./typings.d.ts\"]\n}\n"
  },
  {
    "path": "code/addons/vitest/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/builders/builder-vite/README.md",
    "content": "# Storybook builder for Vite <!-- omit in toc -->\n\nBuild your stories with [vite](https://vitejs.dev/) for fast startup times and near-instant HMR.\n\n# Table of Contents <!-- omit in toc -->\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Getting started with Vite and Storybook (on a new project)](#getting-started-with-vite-and-storybook-on-a-new-project)\n  - [Migration from webpack / CRA](#migration-from-webpack--cra)\n  - [Customize Vite config](#customize-vite-config)\n  - [TypeScript](#typescript)\n  - [React Docgen](#react-docgen)\n  - [Note about working directory](#note-about-working-directory)\n- [Known issues](#known-issues)\n- [Contributing](#contributing)\n\n## Installation\n\nRequirements:\n\n- Vite 3.0 or newer (4.X recommended)\n\nWhen installing Storybook, use the `--builder=vite` flag if you do not have a `vite.config` file at your project root (if you do, the vite builder is chosen automatically).\n\n## Usage\n\nThe builder supports both development mode in Storybook and building a static production version.\n\nYour `vite.config` file will be used by Storybook. If you need to customize the Vite config for Storybook, you have two choices:\n\n1. Set values in your `vite.config` conditionally, based on an environment variable, for example.\n2. Add a `viteFinal` config to your `.storybook/main.js` file. See [Customize Vite config](#customize-vite-config) for details.\n\n### Getting started with Vite and Storybook (on a new project)\n\nSee https://vitejs.dev/guide/#scaffolding-your-first-vite-project,\n\n```\nnpm create vite@latest # follow the prompts\nnpx storybook@latest init --builder vite && npm run storybook\n```\n\n### Migration from webpack / CRA\n\n1. Install `vite` and `@storybook/builder-vite`\n2. Remove any explicit project dependencies on `webpack`, `react-scripts`, and any other Webpack plugins or loaders.\n3. If you were previously using `@storybook/manager-webpack5`, you can remove it. Also remove `@storybook/builder-webpack5` or `@storybook/builder-webpack4` if they are installed.\n4. Choose a Vite-based Storybook \"framework\" to set in the `framework` option of your `.storybook/main.js` file.\n5. Remove Storybook Webpack cache (`rm -rf node_modules/.cache`)\n6. Update your `/public/index.html` file for Vite (be sure there are no `%PUBLIC_URL%` inside it, which is a CRA variable)\n7. Be sure that any files containing JSX syntax use a `.jsx` or `.tsx` file extension, which [Vite requires](https://vitejs.dev/guide/features.html#jsx). This includes `.storybook/preview.jsx` if it contains JSX syntax.\n8. For now you'll need to add a [workaround](https://github.com/storybookjs/storybook/issues/18399) for jest-mock relying on the node `global` variable by creating a `.storybook/preview-head.html` file containing the following:\n\n```html\n<script>\n  window.global = window;\n</script>\n```\n\n9.  Start up your Storybook using the same `yarn storybook` or `npm run storybook` commands you are used to.\n\nFor other details about the differences between Vite and Webpack projects, be sure to read through the [Vite documentation](https://vitejs.dev/).\n\n### Customize Vite config\n\nThe builder _will_ read your `vite.config.js` file, though it may change some of the options in order to work correctly.\nIt looks for the Vite config in the CWD. If your config is located elsewhere, specify the path using the `viteConfigPath` builder option:\n\n```javascript\n// .storybook/main.mjs\n\nconst config = {\n  framework: {\n    name: '@storybook/react-vite', // Your framework name here.\n    options: {\n      builder: {\n        viteConfigPath: '.storybook/customViteConfig.js',\n      },\n    },\n  },\n};\n\nexport default config;\n```\n\nYou can also override the merged Vite config:\n\n```javascript\n// use `mergeConfig` to recursively merge Vite options\nimport { mergeConfig } from 'vite';\n\nconst config = {\n  async viteFinal(config, { configType }) {\n    // Be sure to return the customized config\n    return mergeConfig(config, {\n      // Customize the Vite config for Storybook\n      resolve: {\n        alias: { foo: 'bar' },\n      },\n    });\n  },\n};\n\nexport default config;\n```\n\nThe `viteFinal` function will give you `config` which is the combination of your project's Vite config and the builder's own Vite config.\nYou can tweak this as you want, for example to set up aliases, add new plugins etc.\n\nThe `configType` variable will be either `\"DEVELOPMENT\"` or `\"PRODUCTION\"`.\n\nThe function should return the updated Vite configuration.\n\n### TypeScript\n\nConfigure your `.storybook/main.ts` to use TypeScript:\n\n```typescript\nimport type { StorybookConfig } from '@storybook/react-vite';\n\n// (or whatever framework you are using)\n\nconst config: StorybookConfig = {\n  // other storybook options...,\n  async viteFinal(config, options) {\n    // modify and return config\n  },\n};\n\nexport default config;\n```\n\nSee [Customize Vite config](#customize-vite-config) for details about using `viteFinal`.\n\n### React Docgen\n\nDocgen is used in Storybook to populate the props table in docs view, the controls panel, and for several other addons. Docgen is supported in Svelte, Vue 3, and React. React docgen is configurable via the [`typescript.reactDocgen`](https://storybook.js.org/docs/api/main-config-typescript#reactdocgen?ref=readme) setting in `.storybook/main.js`.\n\n```javascript\nexport default {\n  typescript: {\n    reactDocgen: 'react-docgen`\n  }\n}\n```\n\nIf you're using TypeScript, we encourage you to experiment and see which option works better for your project.\n\n### Note about working directory\n\nThe builder will by default enable Vite's [server.fs.strict](https://vitejs.dev/config/#server-fs-strict)\noption, for increased security. The default project `root` is set to the parent directory of the\nStorybook configuration directory. This can be overridden in [viteFinal](https://storybook.js.org/docs/api/main-config-vite-final?ref=readme).\n\n## Known issues\n\n- HMR: saving a story file does not hot-module-reload, a full reload happens instead. HMR works correctly when saving component files.\n\n## Contributing\n\nThe Vite builder cannot build itself.\n\nAre you willing to contribute? We are especially looking for Vue and Svelte experts, as the current maintainers are React users.\n\nHave a look at the GitHub issues with the `vite` label for known bugs. If you find any new bugs,\nfeel free to create an issue or send a pull request!\n\nPlease read the [How to contribute](/CONTRIBUTING.md) guide.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/builders/builder-vite/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    node: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n    ],\n  },\n  extraOutputs: {\n    './input/iframe.html': './input/iframe.html',\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/builders/builder-vite/input/iframe.html",
    "content": "<!doctype html>\n<!--suppress HtmlUnknownTarget -->\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Storybook</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\n    <style>\n      @font-face {\n        font-family: 'Nunito Sans';\n        font-style: normal;\n        font-weight: 400;\n        font-display: swap;\n        src: url('./sb-common-assets/nunito-sans-regular.woff2') format('woff2');\n      }\n\n      @font-face {\n        font-family: 'Nunito Sans';\n        font-style: italic;\n        font-weight: 400;\n        font-display: swap;\n        src: url('./sb-common-assets/nunito-sans-italic.woff2') format('woff2');\n      }\n\n      @font-face {\n        font-family: 'Nunito Sans';\n        font-style: normal;\n        font-weight: 700;\n        font-display: swap;\n        src: url('./sb-common-assets/nunito-sans-bold.woff2') format('woff2');\n      }\n\n      @font-face {\n        font-family: 'Nunito Sans';\n        font-style: italic;\n        font-weight: 700;\n        font-display: swap;\n        src: url('./sb-common-assets/nunito-sans-bold-italic.woff2') format('woff2');\n      }\n    </style>\n\n    <script>\n      window.CONFIG_TYPE = '[CONFIG_TYPE HERE]';\n      window.LOGLEVEL = '[LOGLEVEL HERE]';\n      window.FRAMEWORK_OPTIONS = '[FRAMEWORK_OPTIONS HERE]';\n      window.CHANNEL_OPTIONS = '[CHANNEL_OPTIONS HERE]';\n      window.FEATURES = '[FEATURES HERE]';\n      window.STORIES = '[STORIES HERE]';\n      window.DOCS_OPTIONS = '[DOCS_OPTIONS HERE]';\n      window.TAGS_OPTIONS = '[TAGS_OPTIONS HERE]';\n\n      ('OTHER_GLOBALS HERE');\n\n      // We do this so that \"module && module.hot\" etc. in Storybook source code\n      // doesn't fail (it will simply be disabled)\n      window.module = undefined;\n      window.global = window;\n    </script>\n    <!-- [HEAD HTML SNIPPET HERE] -->\n  </head>\n\n  <body>\n    <!-- [BODY HTML SNIPPET HERE] -->\n    <div id=\"storybook-root\"></div>\n    <div id=\"storybook-docs\"></div>\n    <script>\n      function __onViteAppLoadingError(event) {\n        const hostname = globalThis.location.hostname;\n        if (hostname !== 'localhost' && globalThis.CONFIG_TYPE === 'DEVELOPMENT') {\n          const message = `Failed to load the Storybook preview file 'vite-app.js':\n\n      It looks like you're visiting the Storybook development server on another hostname than localhost: '${hostname}', but you haven't configured the necessary security features to support this.\n      Please re-run your Storybook development server with the '--host ${hostname}' flag, or manually configure your Vite allowedHosts configuration with viteFinal.\n\n      See:`;\n          const docs = [\n            'https://storybook.js.org/docs/api/cli-options#dev',\n            'https://storybook.js.org/docs/api/main-config/main-config-vite-final',\n            'https://vite.dev/config/server-options.html#server-allowedhosts',\n          ];\n          console.error(`${message}\\n${docs.map((doc) => `- ${doc}`).join('\\n')}`);\n\n          document.getElementById('storybook-root').innerHTML =\n            `<p style=\"color: red; max-width: 70ch\">${message.replaceAll(\n              '\\n',\n              '<br/>'\n            )}<ul>${docs.map((doc) => `<li><a href='${doc}' target='_blank'>${doc}</a></li>`).join('')}</ul></p>`;\n          return;\n        }\n      }\n    </script>\n    <script\n      type=\"module\"\n      src=\"virtual:/@storybook/builder-vite/vite-app.js\"\n      onerror=\"__onViteAppLoadingError(event)\"\n    ></script>\n  </body>\n</html>\n"
  },
  {
    "path": "code/builders/builder-vite/package.json",
    "content": "{\n  \"name\": \"@storybook/builder-vite\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"A Storybook builder to dev and build with Vite\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-builder\",\n    \"vite\",\n    \"builder\",\n    \"bundler\",\n    \"component\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/builders/builder-vite/#readme\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/builders/builder-vite\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Eirik Sletteberg\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./input/iframe.html\": \"./input/iframe.html\",\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"input/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"preset.js\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/csf-plugin\": \"workspace:*\",\n    \"ts-dedent\": \"^2.0.0\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.19.1\",\n    \"empathic\": \"^2.0.0\",\n    \"es-module-lexer\": \"^1.5.0\",\n    \"glob\": \"^10.5.0\",\n    \"knitwork\": \"^1.1.0\",\n    \"magic-string\": \"^0.30.0\",\n    \"pathe\": \"^1.1.2\",\n    \"slash\": \"^5.0.0\",\n    \"vite\": \"^7.0.4\"\n  },\n  \"peerDependencies\": {\n    \"storybook\": \"workspace:^\",\n    \"vite\": \"^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/builders/builder-vite/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/builders/builder-vite/project.json",
    "content": "{\n  \"name\": \"builder-vite\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/build.ts",
    "content": "import { logger } from 'storybook/internal/node-logger';\nimport type { Options } from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\nimport type { InlineConfig } from 'vite';\n\nimport { createViteLogger } from './logger.ts';\nimport type { WebpackStatsPlugin } from './plugins/index.ts';\nimport { hasVitePlugins } from './utils/has-vite-plugins.ts';\nimport { bundlerOptionsKey } from './utils/vite-features.ts';\nimport { withoutVitePlugins } from './utils/without-vite-plugins.ts';\nimport { commonConfig } from './vite-config.ts';\n\nfunction findPlugin(config: InlineConfig, name: string) {\n  return config.plugins?.find((p) => p && 'name' in p && p.name === name);\n}\n\nexport async function build(options: Options) {\n  const { build: viteBuild, mergeConfig } = await import('vite');\n  const { presets } = options;\n\n  const config = await commonConfig(options, 'build');\n\n  config.build = mergeConfig(config, {\n    build: {\n      outDir: options.outputDir,\n      emptyOutDir: false, // do not clean before running Vite build - Storybook has already added assets in there!\n      // TODO: Remove bundlerOptionsKey and use 'rolldownOptions' directly once support for Vite < 8 is dropped\n      [bundlerOptionsKey]: {\n        external: [/\\.\\/sb-common-assets\\/.*\\.woff2/],\n      },\n      ...(options.test\n        ? {\n            reportCompressedSize: false,\n            sourcemap: !options.build?.test?.disableSourcemaps,\n            target: 'esnext',\n            treeshake: !options.build?.test?.disableTreeShaking,\n          }\n        : {}),\n    },\n  } as InlineConfig).build;\n\n  const finalConfig = (await presets.apply('viteFinal', config, options)) as InlineConfig;\n\n  // Add a plugin to enforce Storybook's outDir after all other plugins.\n  // This prevents frameworks like Nitro from redirecting\n  // build output to their own directories (e.g., .output/public/).\n  // The 'enforce: post' ensures this runs after all other config hooks.\n  finalConfig.plugins?.push({\n    name: 'storybook:enforce-output-dir',\n    enforce: 'post',\n    config: () => ({\n      build: {\n        outDir: options.outputDir,\n      },\n    }),\n    // configEnvironment is a new method in Vite 6\n    // It is used to configure configs based on the environment\n    // E.g. Nitro uses this method to set the output directory to .output/public/\n    configEnvironment: () => ({\n      build: {\n        outDir: options.outputDir,\n      },\n    }),\n  });\n\n  if (options.features?.developmentModeForBuild) {\n    finalConfig.plugins?.push({\n      name: 'storybook:define-env',\n      config: () => {\n        return {\n          define: {\n            'process.env.NODE_ENV': JSON.stringify('development'),\n          },\n        };\n      },\n    });\n  }\n\n  const turbosnapPluginName = 'rollup-plugin-turbosnap';\n  const hasTurbosnapPlugin =\n    finalConfig.plugins && (await hasVitePlugins(finalConfig.plugins, [turbosnapPluginName]));\n  if (hasTurbosnapPlugin) {\n    logger.warn(dedent`Found '${turbosnapPluginName}' which is now included by default in Storybook 8.\n      Removing from your plugins list. Ensure you pass \\`--stats-json\\` to generate stats.\n\n      For more information, see https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#turbosnap-vite-plugin-is-no-longer-needed`);\n\n    finalConfig.plugins = await withoutVitePlugins(finalConfig.plugins, [turbosnapPluginName]);\n  }\n\n  finalConfig.customLogger ??= await createViteLogger();\n\n  await viteBuild(finalConfig);\n\n  const statsPlugin = findPlugin(\n    finalConfig,\n    'storybook:rollup-plugin-webpack-stats'\n  ) as WebpackStatsPlugin;\n  return statsPlugin?.storybookGetStats();\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/codegen-importfn-script.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport type { StoryIndex } from 'storybook/internal/types';\n\nimport { generateImportFnScriptCode } from './codegen-importfn-script.ts';\n\ndescribe('generateImportFnScriptCode', () => {\n  it('should correctly map story paths to import functions for POSIX paths', async () => {\n    vi.spyOn(process, 'cwd').mockReturnValue('/absolute/path');\n\n    const index: StoryIndex = {\n      v: 5,\n      entries: {\n        'path-to-story': {\n          id: 'path-to-story',\n          title: 'Path to Story',\n          name: 'Default',\n          importPath: './to/abs-story.js',\n          type: 'story',\n          subtype: 'story',\n        },\n        'virtual-story': {\n          id: 'virtual-story',\n          title: 'Virtual Story',\n          name: 'Default',\n          importPath: 'virtual:story.js',\n          type: 'story',\n          subtype: 'story',\n        },\n      },\n    };\n\n    const result = generateImportFnScriptCode(index);\n\n    expect(result).toMatchInlineSnapshot(`\n      \"const importers = {\n        \"./to/abs-story.js\": () => import(\"/absolute/path/to/abs-story.js\"),\n        \"virtual:story.js\": () => import(\"virtual:story.js\")\n      };\n\n      export async function importFn(path) {\n        return await importers[path]();\n      }\"\n    `);\n  });\n\n  it('should correctly map story paths to import functions for Windows paths', async () => {\n    vi.spyOn(process, 'cwd').mockReturnValue('C:\\\\absolute\\\\path');\n\n    const index: StoryIndex = {\n      v: 5,\n      entries: {\n        'abs-path-to-story': {\n          id: 'abs-path-to-story',\n          title: 'Absolute Path to Story',\n          name: 'Default',\n          importPath: 'to\\\\abs-story.js',\n          type: 'story',\n          subtype: 'story',\n        },\n        'virtual-story': {\n          id: 'virtual-story',\n          title: 'Virtual Story',\n          name: 'Default',\n          importPath: 'virtual:story.js',\n          type: 'story',\n          subtype: 'story',\n        },\n      },\n    };\n\n    const result = generateImportFnScriptCode(index);\n\n    expect(result).toMatchInlineSnapshot(`\n      \"const importers = {\n        \"./to/abs-story.js\": () => import(\"C:/absolute/path/to/abs-story.js\"),\n        \"virtual:story.js\": () => import(\"virtual:story.js\")\n      };\n\n      export async function importFn(path) {\n        return await importers[path]();\n      }\"\n    `);\n  });\n\n  it('should handle an empty index', async () => {\n    const result = generateImportFnScriptCode({ v: 5, entries: {} });\n\n    expect(result).toMatchInlineSnapshot(`\n      \"const importers = {};\n\n      export async function importFn(path) {\n        return await importers[path]();\n      }\"\n    `);\n  });\n});\n"
  },
  {
    "path": "code/builders/builder-vite/src/codegen-importfn-script.ts",
    "content": "import type { StoryIndex } from 'storybook/internal/types';\n\nimport { genDynamicImport, genObjectFromRawEntries } from 'knitwork';\nimport { join, normalize, relative } from 'pathe';\nimport { dedent } from 'ts-dedent';\n\nimport { getUniqueImportPaths } from './utils/unique-import-paths.ts';\n\n/**\n * This function takes the story index and creates a mapping between the stories' relative paths to\n * the working directory and their dynamic imports. The import is done in an asynchronous function\n * to delay loading and to allow Vite to split the code into smaller chunks. It then creates a\n * function, `importFn(path)`, which resolves a path to an import function and this is called by\n * Storybook to fetch a story dynamically when needed.\n */\nexport function generateImportFnScriptCode(index: StoryIndex): string {\n  const objectEntries: [path: string, importStatement: string][] = getUniqueImportPaths(index).map(\n    (importPath) => {\n      if (importPath.startsWith('virtual:')) {\n        return [importPath, genDynamicImport(importPath)];\n      }\n\n      /**\n       * Relative paths get passed either with no leading './' - e.g. 'src/Foo.stories.js', or with\n       * a leading '../', e.g. '../src/Foo.stories.js'. We want to deal in importPaths relative to\n       * the working dir, so we normalize\n       */\n      const relativePath = normalize(relative(process.cwd(), importPath));\n      const normalizedRelativePath = relativePath.startsWith('../')\n        ? relativePath\n        : `./${relativePath}`;\n\n      const absolutePath = normalize(join(process.cwd(), importPath));\n\n      return [normalizedRelativePath, genDynamicImport(absolutePath)];\n    }\n  );\n\n  return dedent`\n    const importers = ${genObjectFromRawEntries(objectEntries)};\n\n    export async function importFn(path) {\n      return await importers[path]();\n    }\n  `;\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/codegen-modern-iframe-script.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { generateModernIframeScriptCodeFromPreviews } from './codegen-modern-iframe-script.ts';\nimport { generateAddonSetupCode } from './codegen-set-addon-channel.ts';\nimport { optimizeViteDeps } from './preset.ts';\n\ndescribe('generateModernIframeScriptCodeFromPreviews', () => {\n  it('handle one annotation', async () => {\n    const result = await generateModernIframeScriptCodeFromPreviews({\n      frameworkName: 'frameworkName',\n    });\n    expect(result).toMatchInlineSnapshot(`\n      \"import { setup } from 'storybook/internal/preview/runtime';\n\n      import 'virtual:/@storybook/builder-vite/setup-addons.js';\n\n      setup();\n\n      import { PreviewWeb } from 'storybook/preview-api';\n      import { importFn } from 'virtual:/@storybook/builder-vite/storybook-stories.js';\n      import { getProjectAnnotations } from 'virtual:/@storybook/builder-vite/project-annotations.js';\n        \n      window.__STORYBOOK_PREVIEW__ = window.__STORYBOOK_PREVIEW__ || new PreviewWeb(importFn, getProjectAnnotations);\n\n      window.__STORYBOOK_STORY_STORE__ = window.__STORYBOOK_STORY_STORE__ || window.__STORYBOOK_PREVIEW__.storyStore;\n\n      if (import.meta.hot) {\n        import.meta.hot.on('vite:afterUpdate', () => {\n          window.__STORYBOOK_PREVIEW__.channel.emit('storyHotUpdated');\n        });\n\n        import.meta.hot.accept('virtual:/@storybook/builder-vite/storybook-stories.js', (newModule) => {\n          // importFn has changed so we need to patch the new one in\n          window.__STORYBOOK_PREVIEW__.onStoriesChanged({ importFn: newModule.importFn });\n        });\n      };\"\n    `);\n  });\n\n  it('handle one annotation CSF4', async () => {\n    const result = await generateModernIframeScriptCodeFromPreviews({\n      frameworkName: 'frameworkName',\n    });\n    expect(result).toMatchInlineSnapshot(`\n      \"import { setup } from 'storybook/internal/preview/runtime';\n\n      import 'virtual:/@storybook/builder-vite/setup-addons.js';\n\n      setup();\n\n      import { PreviewWeb } from 'storybook/preview-api';\n      import { importFn } from 'virtual:/@storybook/builder-vite/storybook-stories.js';\n      import { getProjectAnnotations } from 'virtual:/@storybook/builder-vite/project-annotations.js';\n        \n      window.__STORYBOOK_PREVIEW__ = window.__STORYBOOK_PREVIEW__ || new PreviewWeb(importFn, getProjectAnnotations);\n\n      window.__STORYBOOK_STORY_STORE__ = window.__STORYBOOK_STORY_STORE__ || window.__STORYBOOK_PREVIEW__.storyStore;\n\n      if (import.meta.hot) {\n        import.meta.hot.on('vite:afterUpdate', () => {\n          window.__STORYBOOK_PREVIEW__.channel.emit('storyHotUpdated');\n        });\n\n        import.meta.hot.accept('virtual:/@storybook/builder-vite/storybook-stories.js', (newModule) => {\n          // importFn has changed so we need to patch the new one in\n          window.__STORYBOOK_PREVIEW__.onStoriesChanged({ importFn: newModule.importFn });\n        });\n      };\"\n    `);\n  });\n\n  it('handle multiple annotations', async () => {\n    const result = await generateModernIframeScriptCodeFromPreviews({\n      frameworkName: 'frameworkName',\n    });\n    expect(result).toMatchInlineSnapshot(`\n      \"import { setup } from 'storybook/internal/preview/runtime';\n\n      import 'virtual:/@storybook/builder-vite/setup-addons.js';\n\n      setup();\n\n      import { PreviewWeb } from 'storybook/preview-api';\n      import { importFn } from 'virtual:/@storybook/builder-vite/storybook-stories.js';\n      import { getProjectAnnotations } from 'virtual:/@storybook/builder-vite/project-annotations.js';\n        \n      window.__STORYBOOK_PREVIEW__ = window.__STORYBOOK_PREVIEW__ || new PreviewWeb(importFn, getProjectAnnotations);\n\n      window.__STORYBOOK_STORY_STORE__ = window.__STORYBOOK_STORY_STORE__ || window.__STORYBOOK_PREVIEW__.storyStore;\n\n      if (import.meta.hot) {\n        import.meta.hot.on('vite:afterUpdate', () => {\n          window.__STORYBOOK_PREVIEW__.channel.emit('storyHotUpdated');\n        });\n\n        import.meta.hot.accept('virtual:/@storybook/builder-vite/storybook-stories.js', (newModule) => {\n          // importFn has changed so we need to patch the new one in\n          window.__STORYBOOK_PREVIEW__.onStoriesChanged({ importFn: newModule.importFn });\n        });\n      };\"\n    `);\n  });\n\n  it('handle multiple annotations CSF4', async () => {\n    const result = await generateModernIframeScriptCodeFromPreviews({\n      frameworkName: 'frameworkName',\n    });\n    expect(result).toMatchInlineSnapshot(`\n      \"import { setup } from 'storybook/internal/preview/runtime';\n\n      import 'virtual:/@storybook/builder-vite/setup-addons.js';\n\n      setup();\n\n      import { PreviewWeb } from 'storybook/preview-api';\n      import { importFn } from 'virtual:/@storybook/builder-vite/storybook-stories.js';\n      import { getProjectAnnotations } from 'virtual:/@storybook/builder-vite/project-annotations.js';\n        \n      window.__STORYBOOK_PREVIEW__ = window.__STORYBOOK_PREVIEW__ || new PreviewWeb(importFn, getProjectAnnotations);\n\n      window.__STORYBOOK_STORY_STORE__ = window.__STORYBOOK_STORY_STORE__ || window.__STORYBOOK_PREVIEW__.storyStore;\n\n      if (import.meta.hot) {\n        import.meta.hot.on('vite:afterUpdate', () => {\n          window.__STORYBOOK_PREVIEW__.channel.emit('storyHotUpdated');\n        });\n\n        import.meta.hot.accept('virtual:/@storybook/builder-vite/storybook-stories.js', (newModule) => {\n          // importFn has changed so we need to patch the new one in\n          window.__STORYBOOK_PREVIEW__.onStoriesChanged({ importFn: newModule.importFn });\n        });\n      };\"\n    `);\n  });\n});\n\n/**\n * Extract bare package import specifiers from a block of generated JavaScript/TypeScript code.\n * Captures both `import ... from 'pkg'` and `import 'pkg'` forms, excluding:\n *\n * - Relative paths (start with `.`)\n * - Virtual module IDs (start with `virtual:`)\n * - Absolute paths (start with `/`)\n */\nfunction extractPackageImports(code: string): string[] {\n  const importRegex = /import\\s+(?:[^'\"]*\\s+from\\s+)?['\"]([^'\"]+)['\"]/g;\n  const specifiers = new Set<string>();\n  for (const match of code.matchAll(importRegex)) {\n    const specifier = match[1];\n    if (\n      !specifier.startsWith('.') &&\n      !specifier.startsWith('virtual:') &&\n      !specifier.startsWith('/')\n    ) {\n      specifiers.add(specifier);\n    }\n  }\n  return [...specifiers];\n}\n\ndescribe('optimizeDeps coverage for virtual module imports', () => {\n  it('every package imported in virtual module code is either in optimizeViteDeps or known to be discovered via entry crawling', async () => {\n    // Collect all code generated for virtual modules — Vite's dep scanner never sees\n    // the contents of virtual modules, so any package imported there must be\n    // pre-bundled explicitly via optimizeViteDeps.\n    const iframeCode = await generateModernIframeScriptCodeFromPreviews({ frameworkName: 'test' });\n    const addonCode = await generateAddonSetupCode();\n    const allVirtualModuleCode = [iframeCode, addonCode].join('\\n');\n\n    const packageImports = extractPackageImports(allVirtualModuleCode);\n\n    // These packages are also imported in real source files (preview annotations, renderer\n    // previews, addon previews) that ARE added as optimizeDeps entries, so Vite discovers\n    // them via entry crawling. No explicit optimizeViteDeps entry is required.\n    const discoveredViaEntries = new Set([\n      'storybook/preview-api', // Imported in many renderer/addon preview files\n      'storybook/internal/channels', // Imported in addon preview files\n    ]);\n\n    const notCovered = packageImports.filter(\n      (pkg) => !discoveredViaEntries.has(pkg) && !optimizeViteDeps.includes(pkg)\n    );\n\n    expect(\n      notCovered,\n      `The following packages are imported in virtual module code but are NOT covered.\\n` +\n        `They must be added to optimizeViteDeps in builder-vite/src/preset.ts, OR added to\\n` +\n        `the discoveredViaEntries set in this test if they appear in real source entry files.\\n` +\n        `Uncovered: ${notCovered.join(', ')}`\n    ).toHaveLength(0);\n  });\n});\n"
  },
  {
    "path": "code/builders/builder-vite/src/codegen-modern-iframe-script.ts",
    "content": "import { getFrameworkName } from 'storybook/internal/common';\nimport { STORY_HOT_UPDATED } from 'storybook/internal/core-events';\nimport type { Options } from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\n\nimport { VIRTUAL_ID as PROJECT_ANNOTATIONS_VIRTUAL_ID } from './plugins/storybook-project-annotations-plugin.ts';\nimport { SB_VIRTUAL_FILES } from './virtual-file-names.ts';\n\nexport async function generateModernIframeScriptCode(options: Options) {\n  const frameworkName = await getFrameworkName(options);\n\n  return generateModernIframeScriptCodeFromPreviews({\n    frameworkName,\n  });\n}\n\nexport async function generateModernIframeScriptCodeFromPreviews(options: {\n  frameworkName: string;\n}) {\n  const { frameworkName } = options;\n\n  const generateHMRHandler = (): string => {\n    // Web components are not compatible with HMR, so disable HMR, reload page instead.\n    if (frameworkName === '@storybook/web-components-vite') {\n      return dedent`\n      if (import.meta.hot) {\n        import.meta.hot.decline();\n      }`.trim();\n    }\n\n    return dedent`\n    if (import.meta.hot) {\n      import.meta.hot.on('vite:afterUpdate', () => {\n        window.__STORYBOOK_PREVIEW__.channel.emit('${STORY_HOT_UPDATED}');\n      });\n\n      import.meta.hot.accept('${SB_VIRTUAL_FILES.VIRTUAL_STORIES_FILE}', (newModule) => {\n        // importFn has changed so we need to patch the new one in\n        window.__STORYBOOK_PREVIEW__.onStoriesChanged({ importFn: newModule.importFn });\n      });\n    }`.trim();\n  };\n\n  /**\n   * This code is largely taken from\n   * https://github.com/storybookjs/storybook/blob/d1195cbd0c61687f1720fefdb772e2f490a46584/builders/builder-webpack4/src/preview/virtualModuleModernEntry.js.handlebars\n   * Some small tweaks were made to `getProjectAnnotations` (since `import()` needs to be resolved\n   * asynchronously) and the HMR implementation has been tweaked to work with Vite.\n   *\n   * @todo Inline variable and remove `noinspection`\n   */\n  const code = dedent`\n  import { setup } from 'storybook/internal/preview/runtime';\n  \n  import '${SB_VIRTUAL_FILES.VIRTUAL_ADDON_SETUP_FILE}';\n  \n  setup();\n  \n  import { PreviewWeb } from 'storybook/preview-api';\n  import { importFn } from '${SB_VIRTUAL_FILES.VIRTUAL_STORIES_FILE}';\n  import { getProjectAnnotations } from '${PROJECT_ANNOTATIONS_VIRTUAL_ID}';\n    \n  window.__STORYBOOK_PREVIEW__ = window.__STORYBOOK_PREVIEW__ || new PreviewWeb(importFn, getProjectAnnotations);\n  \n  window.__STORYBOOK_STORY_STORE__ = window.__STORYBOOK_STORY_STORE__ || window.__STORYBOOK_PREVIEW__.storyStore;\n  \n  ${generateHMRHandler()};\n  \n  `.trim();\n  return code;\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/codegen-project-annotations.ts",
    "content": "import { getFrameworkName, loadPreviewOrConfigFile } from 'storybook/internal/common';\nimport { isCsfFactoryPreview, readConfig } from 'storybook/internal/csf-tools';\nimport type { Options, PreviewAnnotation } from 'storybook/internal/types';\n\nimport { genArrayFromRaw, genImport, genSafeVariableName } from 'knitwork';\nimport { filename } from 'pathe/utils';\nimport { dedent } from 'ts-dedent';\n\nimport { processPreviewAnnotation } from './utils/process-preview-annotation.ts';\n\n/** Generates the code for the `PROJECT_ANNOTATIONS_FILE` virtual module. */\nexport async function generateProjectAnnotationsCode(options: Options, projectRoot: string) {\n  const { presets, configDir } = options;\n  const frameworkName = await getFrameworkName(options);\n\n  const previewOrConfigFile = loadPreviewOrConfigFile({ configDir });\n  const previewConfig = previewOrConfigFile ? await readConfig(previewOrConfigFile) : undefined;\n  const isCsf4 = previewConfig ? isCsfFactoryPreview(previewConfig) : false;\n\n  const previewAnnotations = await presets.apply<PreviewAnnotation[]>(\n    'previewAnnotations',\n    [],\n    options\n  );\n\n  return generateProjectAnnotationsCodeFromPreviews({\n    previewAnnotations: [...previewAnnotations, previewOrConfigFile],\n    projectRoot,\n    frameworkName,\n    isCsf4,\n  });\n}\n\nexport function generateProjectAnnotationsCodeFromPreviews(options: {\n  previewAnnotations: (PreviewAnnotation | undefined)[];\n  projectRoot: string;\n  frameworkName: string;\n  isCsf4: boolean;\n}) {\n  const { projectRoot } = options;\n  const previewAnnotationURLs = options.previewAnnotations\n    .filter((path) => path !== undefined)\n    .map((path) => processPreviewAnnotation(path, projectRoot));\n\n  const variables: string[] = [];\n  const imports: string[] = [];\n  for (const previewAnnotation of previewAnnotationURLs) {\n    const variable =\n      genSafeVariableName(filename(previewAnnotation)).replace(/_(45|46|47)/g, '_') +\n      '_' +\n      hash(previewAnnotation);\n    variables.push(variable);\n    imports.push(genImport(previewAnnotation, { name: '*', as: variable }));\n  }\n\n  const previewFileURL = previewAnnotationURLs[previewAnnotationURLs.length - 1];\n  const previewFileVariable = variables[variables.length - 1];\n  const previewFileImport = imports[imports.length - 1];\n\n  if (options.isCsf4) {\n    return dedent`\n      ${previewFileImport}\n\n      export function getProjectAnnotations(hmrPreviewAnnotationModules = []) {\n        const preview = hmrPreviewAnnotationModules[0] ?? ${previewFileVariable};\n        return preview.default.composed;\n      }\n\n      if (import.meta.hot) {\n        import.meta.hot.accept([${JSON.stringify(previewFileURL)}], (previewAnnotationModules) => {\n          // getProjectAnnotations has changed so we need to patch the new one in\n          window?.__STORYBOOK_PREVIEW__?.onGetProjectAnnotationsChanged({\n            getProjectAnnotations: () => getProjectAnnotations(previewAnnotationModules),\n          });\n        });\n      }\n    `.trim();\n  }\n\n  return dedent`\n    import { composeConfigs } from 'storybook/preview-api';\n\n    ${imports.join('\\n')}\n\n    export function getProjectAnnotations(hmrPreviewAnnotationModules = []) {\n      const configs = ${genArrayFromRaw(\n        variables.map(\n          (previewAnnotation, index) =>\n            // Prefer the updated module from an HMR update, otherwise the original module\n            `hmrPreviewAnnotationModules[${index}] ?? ${previewAnnotation}`\n        ),\n        '  '\n      )};\n      return composeConfigs(configs);\n    }\n\n    if (import.meta.hot) {\n      import.meta.hot.accept(${JSON.stringify(previewAnnotationURLs)}, (previewAnnotationModules) => {\n        // getProjectAnnotations has changed so we need to patch the new one in\n        window?.__STORYBOOK_PREVIEW__?.onGetProjectAnnotationsChanged({\n          getProjectAnnotations: () => getProjectAnnotations(previewAnnotationModules),\n        });\n      });\n    }\n  `.trim();\n}\n\n/** djb2 hash — http://www.cse.yorku.ca/~oz/hash.html */\nfunction hash(value: string) {\n  let acc = 5381;\n  for (let i = 0; i < value.length; i++) {\n    acc = ((acc << 5) + acc + value.charCodeAt(i)) >>> 0;\n  }\n  return acc;\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/codegen-set-addon-channel.ts",
    "content": "export async function generateAddonSetupCode() {\n  return `\n    import { createBrowserChannel } from 'storybook/internal/channels';\n    import { addons } from 'storybook/preview-api';\n\n    const channel = createBrowserChannel({ page: 'preview' });\n    addons.setChannel(channel);\n    window.__STORYBOOK_ADDONS_CHANNEL__ = channel;\n    \n    if (window.CONFIG_TYPE === 'DEVELOPMENT'){\n      window.__STORYBOOK_SERVER_CHANNEL__ = channel;\n    }\n  `.trim();\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/envs.ts",
    "content": "import { stringifyEnvs } from 'storybook/internal/common';\nimport type { Builder_EnvsRaw } from 'storybook/internal/types';\n\nimport type { UserConfig as ViteConfig } from 'vite';\n\n// Allowed env variables on the client\nconst allowedEnvVariables = [\n  'STORYBOOK',\n  // Vite `import.meta.env` default variables\n  // @see https://github.com/vitejs/vite/blob/6b8d94dca2a1a8b4952e3e3fcd0aed1aedb94215/packages/vite/types/importMeta.d.ts#L68-L75\n  'BASE_URL',\n  'MODE',\n  'DEV',\n  'PROD',\n  'SSR',\n];\n\n/**\n * Customized version of stringifyProcessEnvs from storybook/internal/core-common which uses\n * import.meta.env instead of process.env and checks for allowed variables.\n */\nexport function stringifyProcessEnvs(raw: Builder_EnvsRaw, envPrefix: ViteConfig['envPrefix']) {\n  const updatedRaw: Builder_EnvsRaw = {};\n  const envs = Object.entries(raw).reduce((acc: Builder_EnvsRaw, [key, value]) => {\n    // Only add allowed values OR values from array OR string started with allowed prefixes\n    if (\n      allowedEnvVariables.includes(key) ||\n      (Array.isArray(envPrefix) && !!envPrefix.find((prefix) => key.startsWith(prefix))) ||\n      (typeof envPrefix === 'string' && key.startsWith(envPrefix))\n    ) {\n      acc[`import.meta.env.${key}`] = JSON.stringify(value);\n      updatedRaw[key] = value;\n    }\n    return acc;\n  }, {});\n  // support destructuring like\n  // const { foo } = import.meta.env;\n  envs['import.meta.env'] = JSON.stringify(stringifyEnvs(updatedRaw));\n\n  return envs;\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/index.test.ts",
    "content": "import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { logger } from 'storybook/internal/node-logger';\nimport type { ModuleNode as StorybookModuleNode, Options } from 'storybook/internal/types';\nimport type { ViteDevServer } from 'vite';\n\nimport { bail, onModuleGraphChange, start } from './index.ts';\nimport { createViteServer } from './vite-server.ts';\n\nvi.mock('storybook/internal/node-logger', { spy: true });\nvi.mock('./vite-server', { spy: true });\n\ntype ViteModuleNodeLike = {\n  file: string | null;\n  type: StorybookModuleNode['type'];\n  importers: Set<ViteModuleNodeLike>;\n  importedModules: Set<ViteModuleNodeLike>;\n};\n\nfunction createViteModuleNode(\n  file: string | null,\n  type: StorybookModuleNode['type'] = 'js'\n): ViteModuleNodeLike {\n  return {\n    file,\n    type,\n    importers: new Set(),\n    importedModules: new Set(),\n  };\n}\n\nfunction createFileToModulesMap(...entries: Array<[string, Set<ViteModuleNodeLike>]>) {\n  return new Map(entries) as ViteDevServer['moduleGraph']['fileToModulesMap'];\n}\n\ntype WatcherHandler = (...args: unknown[]) => void;\ntype FakeWatcher = {\n  on: ReturnType<typeof vi.fn>;\n  off: ReturnType<typeof vi.fn>;\n  emit: (event: string, ...args: unknown[]) => void;\n  listenerCount: (event: string) => number;\n};\n\nfunction createFakeViteServer() {\n  const watcherListeners = new Map<string, Set<WatcherHandler>>();\n  const watcher = {} as FakeWatcher;\n\n  watcher.on = vi.fn((event: string, handler: WatcherHandler) => {\n    const handlers = watcherListeners.get(event) ?? new Set<WatcherHandler>();\n    handlers.add(handler);\n    watcherListeners.set(event, handlers);\n    return watcher;\n  });\n  watcher.off = vi.fn((event: string, handler: WatcherHandler) => {\n    watcherListeners.get(event)?.delete(handler);\n    return watcher;\n  });\n  watcher.emit = (event: string, ...args: unknown[]) => {\n    watcherListeners.get(event)?.forEach((handler) => {\n      handler(...args);\n    });\n    watcherListeners.get('all')?.forEach((handler) => {\n      handler(event, ...args);\n    });\n  };\n  watcher.listenerCount = (event: string) => watcherListeners.get(event)?.size ?? 0;\n\n  return {\n    watcher,\n    moduleGraph: {\n      fileToModulesMap: createFileToModulesMap(),\n    },\n    middlewares: {\n      handle: vi.fn(),\n    },\n    warmupRequest: vi.fn().mockResolvedValue(undefined),\n    transformIndexHtml: vi.fn().mockResolvedValue(''),\n    waitForRequestsIdle: vi.fn().mockResolvedValue(undefined),\n    close: vi.fn().mockResolvedValue(undefined),\n  } as unknown as ViteDevServer & {\n    watcher: typeof watcher;\n  };\n}\n\nfunction createStartArgs(storyImportPaths: string[] = []): Parameters<typeof start>[0] {\n  const indexGenerator = {\n    getIndex: vi.fn().mockResolvedValue({\n      entries: Object.fromEntries(\n        storyImportPaths.map((importPath, index) => [`story-${index}`, { importPath }])\n      ),\n    }),\n  };\n\n  return {\n    startTime: process.hrtime(),\n    options: {\n      presets: {\n        apply: vi.fn().mockResolvedValue(indexGenerator),\n      },\n    } as unknown as Options,\n    router: {\n      get: vi.fn(),\n      use: vi.fn(),\n    } as unknown as Parameters<typeof start>[0]['router'],\n    server: {} as Parameters<typeof start>[0]['server'],\n    channel: {} as Parameters<typeof start>[0]['channel'],\n  };\n}\n\ndescribe('onModuleGraphChange', () => {\n  let fakeViteServer: ReturnType<typeof createFakeViteServer>;\n\n  async function startChangeDetection(\n    fileToModulesMap = createFileToModulesMap([\n      '/src/Button.tsx',\n      new Set([createViteModuleNode('/src/Button.tsx')]),\n    ])\n  ) {\n    fakeViteServer.moduleGraph.fileToModulesMap = fileToModulesMap;\n    await start(createStartArgs([...fileToModulesMap.keys()]));\n    await vi.advanceTimersByTimeAsync(1000);\n  }\n\n  beforeEach(() => {\n    vi.useFakeTimers();\n    fakeViteServer = createFakeViteServer();\n    vi.mocked(createViteServer).mockResolvedValue(fakeViteServer);\n    vi.mocked(logger.error).mockImplementation(() => undefined);\n  });\n\n  afterEach(async () => {\n    await bail();\n    vi.useRealTimers();\n    vi.clearAllMocks();\n  });\n\n  it('registers callbacks and unsubscribes them', async () => {\n    const cb = vi.fn();\n    const unsubscribe = onModuleGraphChange(cb);\n\n    expect(unsubscribe).toEqual(expect.any(Function));\n\n    await startChangeDetection();\n    cb.mockClear();\n\n    fakeViteServer.watcher.emit('change', '/src/Button.tsx');\n\n    await vi.advanceTimersByTimeAsync(100);\n\n    expect(cb).toHaveBeenCalledTimes(1);\n\n    unsubscribe();\n\n    fakeViteServer.watcher.emit('change', '/src/Button.tsx');\n    await vi.advanceTimersByTimeAsync(100);\n\n    expect(cb).toHaveBeenCalledTimes(1);\n  });\n\n  it('passes the module graph payload to listeners', async () => {\n    const entry = createViteModuleNode('/src/Button.tsx');\n    const fileToModulesMap = createFileToModulesMap(['/src/Button.tsx', new Set([entry])]);\n\n    const cb = vi.fn();\n    onModuleGraphChange(cb);\n\n    await startChangeDetection(fileToModulesMap);\n    cb.mockClear();\n\n    fakeViteServer.watcher.emit('change', '/src/Button.tsx');\n\n    await vi.advanceTimersByTimeAsync(100);\n\n    const event = cb.mock.calls[0]?.[0];\n    const moduleGraph = event?.moduleGraph;\n\n    expect(cb).toHaveBeenCalledWith({\n      type: 'moduleGraph',\n      moduleGraph: expect.any(Map),\n    });\n    expect(moduleGraph?.has('/src/Button.tsx')).toBe(true);\n  });\n\n  it('triggers change events after the debounce delay', async () => {\n    const cb = vi.fn();\n    onModuleGraphChange(cb);\n\n    await startChangeDetection();\n    cb.mockClear();\n\n    fakeViteServer.watcher.emit('change', '/src/Button.tsx');\n\n    await vi.advanceTimersByTimeAsync(50);\n    expect(cb).not.toHaveBeenCalled();\n\n    await vi.advanceTimersByTimeAsync(50);\n    expect(cb).toHaveBeenCalledTimes(1);\n  });\n\n  it('triggers add events after the debounce delay', async () => {\n    const cb = vi.fn();\n    onModuleGraphChange(cb);\n\n    await startChangeDetection();\n    cb.mockClear();\n\n    fakeViteServer.watcher.emit('add', '/src/Button.tsx');\n\n    await vi.advanceTimersByTimeAsync(100);\n\n    expect(cb).toHaveBeenCalledTimes(1);\n  });\n\n  it('triggers unlink events after the debounce delay', async () => {\n    const cb = vi.fn();\n    onModuleGraphChange(cb);\n\n    await startChangeDetection();\n    cb.mockClear();\n\n    fakeViteServer.watcher.emit('unlink', '/src/Button.tsx');\n\n    await vi.advanceTimersByTimeAsync(100);\n\n    expect(cb).toHaveBeenCalledTimes(1);\n  });\n\n  it('debounces multiple rapid events into a single callback', async () => {\n    const cb = vi.fn();\n    onModuleGraphChange(cb);\n\n    await startChangeDetection();\n    cb.mockClear();\n\n    fakeViteServer.watcher.emit('change', '/src/Button.tsx');\n    fakeViteServer.watcher.emit('add', '/src/Button.tsx');\n    fakeViteServer.watcher.emit('change', '/src/Button.tsx');\n\n    await vi.advanceTimersByTimeAsync(100);\n\n    expect(cb).toHaveBeenCalledTimes(1);\n  });\n\n  it('notifies multiple listeners', async () => {\n    const cb1 = vi.fn();\n    const cb2 = vi.fn();\n\n    onModuleGraphChange(cb1);\n    onModuleGraphChange(cb2);\n\n    await startChangeDetection();\n    cb1.mockClear();\n    cb2.mockClear();\n\n    fakeViteServer.watcher.emit('change', '/src/Button.tsx');\n\n    await vi.advanceTimersByTimeAsync(100);\n\n    expect(cb1).toHaveBeenCalledTimes(1);\n    expect(cb2).toHaveBeenCalledTimes(1);\n  });\n\n  it('removes the all-event watcher during bail to avoid leaks across restarts', async () => {\n    const cb = vi.fn();\n    onModuleGraphChange(cb);\n\n    await startChangeDetection();\n    expect(fakeViteServer.watcher.listenerCount('all')).toBe(1);\n\n    await bail();\n    expect(fakeViteServer.watcher.listenerCount('all')).toBe(0);\n\n    await start(createStartArgs(['/src/Button.tsx']));\n    await vi.advanceTimersByTimeAsync(1000);\n    expect(fakeViteServer.watcher.listenerCount('all')).toBe(0);\n\n    fakeViteServer.watcher.emit('change', '/src/Button.tsx');\n    await vi.advanceTimersByTimeAsync(100);\n\n    expect(cb).not.toHaveBeenCalled();\n    expect(fakeViteServer.watcher.off).toHaveBeenCalledWith('all', expect.any(Function));\n  });\n\n  it('clears the module-graph polling interval during bail', async () => {\n    onModuleGraphChange(vi.fn());\n\n    await start(createStartArgs());\n    await vi.advanceTimersByTimeAsync(0);\n\n    expect(vi.getTimerCount()).toBe(1);\n\n    await bail();\n\n    fakeViteServer.moduleGraph.fileToModulesMap = createFileToModulesMap([\n      '/src/Button.tsx',\n      new Set([createViteModuleNode('/src/Button.tsx')]),\n    ]);\n\n    await vi.advanceTimersByTimeAsync(1000);\n\n    expect(vi.getTimerCount()).toBe(0);\n    expect(fakeViteServer.waitForRequestsIdle).not.toHaveBeenCalled();\n  });\n\n  it('rejects listeners registered after start', async () => {\n    await start(createStartArgs());\n\n    expect(() => onModuleGraphChange(vi.fn())).toThrow(\n      'Vite module graph listeners must be registered before the builder starts.'\n    );\n  });\n\n  it('does not reattach the watcher if bail runs while waiting for idle requests', async () => {\n    const cb = vi.fn();\n    onModuleGraphChange(cb);\n\n    let resolveIdle: (() => void) | undefined;\n    fakeViteServer.moduleGraph.fileToModulesMap = createFileToModulesMap([\n      '/src/Button.tsx',\n      new Set([createViteModuleNode('/src/Button.tsx')]),\n    ]);\n    fakeViteServer.waitForRequestsIdle = vi.fn().mockImplementation(\n      () =>\n        new Promise<void>((resolve) => {\n          resolveIdle = resolve;\n        })\n    );\n\n    await start(createStartArgs(['/src/Button.tsx']));\n    await vi.advanceTimersByTimeAsync(1000);\n\n    await bail();\n    resolveIdle?.();\n    await Promise.resolve();\n    await Promise.resolve();\n\n    expect(fakeViteServer.watcher.listenerCount('all')).toBe(0);\n    expect(fakeViteServer.watcher.on).not.toHaveBeenCalledWith('all', expect.any(Function));\n    expect(cb).not.toHaveBeenCalled();\n  });\n\n  it('logs and swallows rejected startup work', async () => {\n    const cb = vi.fn();\n    onModuleGraphChange(cb);\n\n    const args = createStartArgs();\n    vi.mocked(args.options.presets.apply).mockResolvedValue({\n      getIndex: vi.fn().mockRejectedValue(new Error('index failed')),\n    } as never);\n\n    await expect(start(args)).resolves.toBeDefined();\n    await Promise.resolve();\n\n    expect(logger.error).toHaveBeenCalledWith('Failed to initialize Vite change detection');\n    expect(logger.error).toHaveBeenCalledWith(expect.objectContaining({ message: 'index failed' }));\n    expect(cb).toHaveBeenCalledWith({\n      type: 'error',\n      error: expect.objectContaining({ message: 'index failed' }),\n    });\n    expect(vi.getTimerCount()).toBe(0);\n  });\n\n  it('logs polling failures and clears the interval', async () => {\n    const cb = vi.fn();\n    onModuleGraphChange(cb);\n    fakeViteServer.moduleGraph.fileToModulesMap = createFileToModulesMap([\n      '/src/Button.tsx',\n      new Set([createViteModuleNode('/src/Button.tsx')]),\n    ]);\n    fakeViteServer.waitForRequestsIdle = vi.fn().mockRejectedValue(new Error('idle failed'));\n\n    await start(createStartArgs(['/src/Button.tsx']));\n    await vi.advanceTimersByTimeAsync(1000);\n\n    expect(logger.error).toHaveBeenCalledWith('Failed to complete Vite change detection startup');\n    expect(logger.error).toHaveBeenCalledWith(expect.objectContaining({ message: 'idle failed' }));\n    expect(cb).toHaveBeenCalledWith({\n      type: 'error',\n      error: expect.objectContaining({ message: 'idle failed' }),\n    });\n    expect(vi.getTimerCount()).toBe(0);\n    expect(fakeViteServer.watcher.listenerCount('all')).toBe(0);\n  });\n\n  it('notifies listeners when module graph startup times out', async () => {\n    const cb = vi.fn();\n    onModuleGraphChange(cb);\n\n    await start(createStartArgs(['/src/Button.tsx']));\n    await vi.advanceTimersByTimeAsync(31_000);\n\n    expect(logger.error).toHaveBeenCalledWith('Failed to complete Vite change detection startup');\n    expect(cb).toHaveBeenCalledWith({\n      type: 'unavailable',\n      reason: 'Timed out while waiting for the Vite module graph to initialize',\n      error: expect.objectContaining({\n        message: 'Timed out while waiting for the Vite module graph to initialize',\n      }),\n    });\n    expect(vi.getTimerCount()).toBe(0);\n  });\n});\n"
  },
  {
    "path": "code/builders/builder-vite/src/index.ts",
    "content": "// noinspection JSUnusedGlobalSymbols\nimport { readFile } from 'node:fs/promises';\nimport { fileURLToPath } from 'node:url';\n\nimport { logger } from 'storybook/internal/node-logger';\nimport {\n  NoStatsForViteDevError,\n  ViteModuleGraphSubscriptionError,\n} from 'storybook/internal/server-errors';\nimport type { StoryIndexGenerator } from 'storybook/internal/core-server';\nimport type {\n  Builder,\n  Middleware,\n  ModuleGraph,\n  ModuleGraphChangeEvent,\n  Options,\n} from 'storybook/internal/types';\n\nimport type { ViteDevServer } from 'vite';\n\nimport { build as viteBuild } from './build.ts';\nimport type { ViteBuilder } from './types.ts';\nimport { createViteServer } from './vite-server.ts';\nimport { buildModuleGraph } from './utils/build-module-graph.ts';\n\nexport { withoutVitePlugins } from './utils/without-vite-plugins.ts';\nexport { hasVitePlugins } from './utils/has-vite-plugins.ts';\n\nexport * from './types.ts';\n\nfunction iframeHandler(options: Options, server: ViteDevServer): Middleware {\n  return async (req, res) => {\n    const indexHtml = await readFile(\n      fileURLToPath(import.meta.resolve('@storybook/builder-vite/input/iframe.html')),\n      {\n        encoding: 'utf8',\n      }\n    );\n    const transformed = await server.transformIndexHtml('/iframe.html', indexHtml);\n    res.setHeader('Content-Type', 'text/html');\n    res.statusCode = 200;\n    res.write(transformed);\n    res.end();\n  };\n}\n\nlet server: ViteDevServer;\nconst listeners = new Set<(event: ModuleGraphChangeEvent) => void>();\nlet debounce: ReturnType<typeof setTimeout> | undefined;\nlet watcherChangeHandler: (() => void) | undefined;\nlet waitForModuleGraph: ReturnType<typeof setInterval> | undefined;\nlet moduleGraphRegistrationClosed = false;\n\nfunction clearModuleGraphPolling(): void {\n  if (waitForModuleGraph) {\n    clearInterval(waitForModuleGraph);\n    waitForModuleGraph = undefined;\n  }\n}\n\nfunction notifyListeners(moduleGraph: ModuleGraph): void {\n  listeners.forEach((listener) => {\n    listener({ type: 'moduleGraph', moduleGraph });\n  });\n}\n\nfunction notifyListenersOfStartupFailure(\n  event: Extract<ModuleGraphChangeEvent, { type: 'unavailable' | 'error' }>\n): void {\n  listeners.forEach((listener) => {\n    listener(event);\n  });\n}\n\nexport async function bail(): Promise<void> {\n  if (watcherChangeHandler) {\n    server?.watcher.off('all', watcherChangeHandler);\n    watcherChangeHandler = undefined;\n  }\n\n  clearModuleGraphPolling();\n\n  if (debounce) {\n    clearTimeout(debounce);\n    debounce = undefined;\n  }\n\n  moduleGraphRegistrationClosed = false;\n  listeners.clear();\n  return server?.close();\n}\n\nexport const onModuleGraphChange: NonNullable<Builder<Options>['onModuleGraphChange']> = (cb) => {\n  if (moduleGraphRegistrationClosed) {\n    throw new ViteModuleGraphSubscriptionError();\n  }\n  listeners.add(cb);\n\n  return () => {\n    listeners.delete(cb);\n  };\n};\n\nconst startChangeDetection = async (options: Options) => {\n  const startTime = process.hrtime();\n  const indexGenerator = await options.presets.apply<StoryIndexGenerator>('storyIndexGenerator');\n  const storyIndex = await indexGenerator.getIndex();\n  const importPaths = new Set(Object.values(storyIndex.entries).map((entry) => entry.importPath));\n\n  // Warm up the module graph for all story files\n  await Promise.all(Array.from(importPaths, (importPath) => server.warmupRequest(importPath)));\n\n  // Wait for the module graph to be ready by polling for it to be non-empty\n  waitForModuleGraph = setInterval(() => {\n    void (async () => {\n      try {\n        if (!watcherChangeHandler) {\n          clearModuleGraphPolling();\n          return;\n        }\n\n        if (process.hrtime(startTime)[0] > 30) {\n          clearModuleGraphPolling();\n          const error = new Error(\n            'Timed out while waiting for the Vite module graph to initialize'\n          );\n          logger.error('Failed to complete Vite change detection startup');\n          logger.error(error);\n          notifyListenersOfStartupFailure({\n            type: 'unavailable',\n            reason: error.message,\n            error,\n          });\n          return;\n        }\n\n        if (server.moduleGraph.fileToModulesMap.size > 0) {\n          clearModuleGraphPolling();\n          await server.waitForRequestsIdle();\n          if (!watcherChangeHandler) {\n            return;\n          }\n\n          server.watcher.on('all', watcherChangeHandler);\n          watcherChangeHandler();\n        }\n      } catch (error) {\n        clearModuleGraphPolling();\n        logger.error('Failed to complete Vite change detection startup');\n        logger.error(error instanceof Error ? error : String(error));\n        notifyListenersOfStartupFailure({\n          type: 'error',\n          error: error instanceof Error ? error : new Error(String(error)),\n        });\n      }\n    })();\n  }, 1000);\n};\n\nexport const start: ViteBuilder['start'] = async ({\n  startTime,\n  options,\n  router,\n  server: devServer,\n}) => {\n  moduleGraphRegistrationClosed = true;\n  server = await createViteServer(options as Options, devServer);\n\n  router.get('/iframe.html', iframeHandler(options as Options, server));\n  router.use(server.middlewares);\n\n  if (listeners.size > 0) {\n    // Debounce handler to prevent multiple callback invocations when multiple files are edited\n    watcherChangeHandler = () => {\n      clearTimeout(debounce);\n      debounce = setTimeout(() => {\n        notifyListeners(buildModuleGraph(server.moduleGraph.fileToModulesMap));\n      }, 100);\n    };\n    // We intentionally don't await this. Cleanup happens in bail().\n    void startChangeDetection(options).catch((error) => {\n      clearModuleGraphPolling();\n      logger.error('Failed to initialize Vite change detection');\n      logger.error(error instanceof Error ? error : String(error));\n      notifyListenersOfStartupFailure({\n        type: 'error',\n        error: error instanceof Error ? error : new Error(String(error)),\n      });\n    });\n  }\n\n  return {\n    bail,\n    stats: {\n      toJson: () => {\n        throw new NoStatsForViteDevError();\n      },\n    },\n    totalTime: process.hrtime(startTime),\n  };\n};\n\nexport const build: ViteBuilder['build'] = async ({ options }) => {\n  return viteBuild(options as Options);\n};\n\nexport const corePresets = [import.meta.resolve('./preset.js')];\n"
  },
  {
    "path": "code/builders/builder-vite/src/logger.ts",
    "content": "import { logger } from 'storybook/internal/node-logger';\n\nimport picocolors from 'picocolors';\n\nconst seenWarnings = new Set<string>();\n\nexport async function createViteLogger() {\n  const { createLogger } = await import('vite');\n\n  const customViteLogger = createLogger();\n  const logWithPrefix = (fn: (msg: string) => void) => (msg: string) =>\n    fn(`${picocolors.bgYellow('Vite')} ${msg}`);\n\n  customViteLogger.error = logWithPrefix(logger.error);\n  customViteLogger.warn = logWithPrefix(logger.warn);\n  customViteLogger.warnOnce = (msg) => {\n    if (seenWarnings.has(msg)) {\n      return;\n    }\n    seenWarnings.add(msg);\n    logWithPrefix(logger.warn)(msg);\n  };\n  customViteLogger.info = logWithPrefix((msg) => logger.log(msg, { spacing: 0 }));\n\n  return customViteLogger;\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/plugins/code-generator-plugin.ts",
    "content": "import { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\n\nimport type { StoryIndexGenerator } from 'storybook/internal/core-server';\nimport type { Options } from 'storybook/internal/types';\n\nimport type { Plugin } from 'vite';\n\nimport { importMetaResolve } from '../../../../core/src/shared/utils/module.ts';\nimport { generateImportFnScriptCode } from '../codegen-importfn-script.ts';\nimport { generateModernIframeScriptCode } from '../codegen-modern-iframe-script.ts';\nimport { generateAddonSetupCode } from '../codegen-set-addon-channel.ts';\nimport { transformIframeHtml } from '../transform-iframe-html.ts';\nimport { bundlerOptionsKey, ensureRolldownOptions } from '../utils/vite-features.ts';\nimport {\n  SB_VIRTUAL_FILES,\n  SB_VIRTUAL_FILE_IDS,\n  getResolvedVirtualModuleId,\n} from '../virtual-file-names.ts';\n\nexport function codeGeneratorPlugin(options: Options) {\n  const iframePath = fileURLToPath(importMetaResolve('@storybook/builder-vite/input/iframe.html'));\n  let iframeId: string;\n  const storyIndexGeneratorPromise: Promise<StoryIndexGenerator> =\n    options.presets.apply<StoryIndexGenerator>('storyIndexGenerator');\n\n  return {\n    name: 'storybook:code-generator-plugin',\n    enforce: 'pre',\n    async configureServer(server) {\n      (await storyIndexGeneratorPromise).onInvalidated(() => {\n        // TODO: this is only necessary when new files are added.\n        // Changes and removals are already watched and handled by Vite, so they actually trigger a double HMR event right now.\n        server.watcher.emit(\n          'change',\n          getResolvedVirtualModuleId(SB_VIRTUAL_FILES.VIRTUAL_STORIES_FILE)\n        );\n      });\n    },\n    config(config, { command }) {\n      // If we are building the static distribution, add iframe.html as an entry.\n      // In development mode, it's not an entry - instead, we use a middleware\n      // to serve iframe.html. The reason is that Vite's dev server (at the time of writing)\n      // does not support virtual files as entry points.\n      if (command === 'build') {\n        if (!config.build) {\n          config.build = {};\n        }\n        // TODO: Remove bundlerOptionsKey and use 'rolldownOptions' directly once support for Vite < 8 is dropped\n        const build = config.build as Record<string, any>;\n\n        // shared options between rollup/rolldown\n        build[bundlerOptionsKey] = {\n          ...build[bundlerOptionsKey],\n          input: iframePath,\n        };\n\n        // necessary rolldown specific overrides\n        ensureRolldownOptions(config);\n      }\n    },\n    configResolved(config) {\n      iframeId = `${config.root}/iframe.html`;\n    },\n    resolveId(source) {\n      if (SB_VIRTUAL_FILE_IDS.includes(source)) {\n        return getResolvedVirtualModuleId(source);\n      }\n      if (source === iframePath) {\n        return iframeId;\n      }\n\n      return undefined;\n    },\n    async load(id) {\n      switch (id) {\n        case getResolvedVirtualModuleId(SB_VIRTUAL_FILES.VIRTUAL_STORIES_FILE): {\n          const storyIndexGenerator = await storyIndexGeneratorPromise;\n          const index = await storyIndexGenerator?.getIndex();\n          return generateImportFnScriptCode(index);\n        }\n\n        case getResolvedVirtualModuleId(SB_VIRTUAL_FILES.VIRTUAL_ADDON_SETUP_FILE): {\n          return generateAddonSetupCode();\n        }\n        case getResolvedVirtualModuleId(SB_VIRTUAL_FILES.VIRTUAL_APP_FILE): {\n          return generateModernIframeScriptCode(options);\n        }\n        case iframeId: {\n          return readFileSync(\n            fileURLToPath(importMetaResolve('@storybook/builder-vite/input/iframe.html')),\n            'utf-8'\n          );\n        }\n      }\n    },\n    async transformIndexHtml(html, ctx) {\n      if (ctx.path !== '/iframe.html') {\n        return undefined;\n      }\n      return transformIframeHtml(html, options);\n    },\n  } satisfies Plugin;\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/plugins/csf-plugin.ts",
    "content": "import type { Options } from 'storybook/internal/types';\n\nimport { vite } from '@storybook/csf-plugin';\n\nimport type { Plugin } from 'vite';\n\nexport async function csfPlugin(config: Options): Promise<Plugin> {\n  const { presets } = config;\n\n  const addons = await presets.apply('addons', []);\n  const docsOptions =\n    // @ts-expect-error - not sure what type to use here\n    addons.find((a) => [a, a.name].includes('@storybook/addon-docs'))?.options ?? {};\n\n  const enrichCsf = await presets.apply('experimental_enrichCsf');\n\n  // TODO: looks like unplugin can return an array of plugins\n  return vite({\n    ...docsOptions?.csfPluginOptions,\n    enrichCsf,\n  }) as Plugin;\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/plugins/index.ts",
    "content": "// Builder-internal plugins (used by vite-config.ts to assemble the builder's plugin stack)\nexport { storybookOptimizeDepsPlugin } from './storybook-optimize-deps-plugin.ts';\nexport { storybookEntryPlugin } from './storybook-entry-plugin.ts';\nexport { pluginWebpackStats } from './webpack-stats-plugin.ts';\nexport type { WebpackStatsPlugin } from './webpack-stats-plugin.ts';\n\n// Lower-level plugins re-exported for internal use and tests\nexport { injectExportOrderPlugin } from './inject-export-order-plugin.ts';\nexport { stripStoryHMRBoundary } from './strip-story-hmr-boundaries.ts';\nexport { codeGeneratorPlugin } from './code-generator-plugin.ts';\nexport { csfPlugin } from './csf-plugin.ts';\nexport { storybookExternalGlobalsPlugin } from './storybook-external-globals-plugin.ts';\n"
  },
  {
    "path": "code/builders/builder-vite/src/plugins/inject-export-order-plugin.ts",
    "content": "import { parse } from 'es-module-lexer';\nimport MagicString from 'magic-string';\nimport type { Plugin } from 'vite';\n\nexport async function injectExportOrderPlugin() {\n  const { createFilter } = await import('vite');\n\n  const include = [/\\.stories\\.([tj])sx?$/, /(stories|story).mdx$/];\n  const filter = createFilter(include);\n\n  return {\n    name: 'storybook:inject-export-order-plugin',\n    // This should only run after the typescript has been transpiled\n    enforce: 'post',\n    transform: {\n      filter: { id: include },\n      async handler(code: string, id: string) {\n        if (!filter(id)) {\n          return undefined;\n        }\n\n        // TODO: Maybe convert `injectExportOrderPlugin` to function that returns object,\n        //  and run `await init;` once and then call `parse()` without `await`,\n        //  instead of calling `await parse()` every time.\n        const [, exports] = await parse(code);\n\n        const exportNames = exports.map((e) => code.substring(e.s, e.e));\n\n        if (exportNames.includes('__namedExportsOrder')) {\n          // user has defined named exports already\n          return undefined;\n        }\n        const s = new MagicString(code);\n        const orderedExports = exportNames.filter((e) => e !== 'default');\n        s.append(`;export const __namedExportsOrder = ${JSON.stringify(orderedExports)};`);\n        return {\n          code: s.toString(),\n          map: s.generateMap({ hires: true, source: id }),\n        };\n      },\n    },\n  } satisfies Plugin;\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/plugins/storybook-config-plugin.ts",
    "content": "import { isPreservingSymlinks } from 'storybook/internal/common';\n\nimport { type Plugin } from 'vite';\n\nexport interface StorybookConfigPluginOptions {\n  configDir: string;\n}\n\n/**\n * A Vite plugin that provides the base Storybook configuration.\n *\n * This handles:\n *\n * - Adding Storybook resolve conditions (`storybook`, `stories`, `test`)\n * - Setting up environment variable prefixes (`VITE_`, `STORYBOOK_`)\n * - Allowing the Storybook config directory in Vite's filesystem restrictions\n * - Preserving symlinks when applicable\n */\nexport function storybookConfigPlugin(options: StorybookConfigPluginOptions): Plugin[] {\n  return [\n    {\n      name: 'storybook:config-plugin',\n      enforce: 'pre',\n      async config(config) {\n        const { defaultClientConditions = [] } = await import('vite');\n\n        const existingEnvPrefix = config.envPrefix;\n        // If an envPrefix is specified in the user's vite config, add STORYBOOK_ to it.\n        // Otherwise, add both VITE_ and STORYBOOK_ so that Vite doesn't lose its default.\n        const mergedEnvPrefix = existingEnvPrefix\n          ? Array.from(\n              new Set([\n                ...(Array.isArray(existingEnvPrefix) ? existingEnvPrefix : [existingEnvPrefix]),\n                'STORYBOOK_',\n              ])\n            )\n          : ['VITE_', 'STORYBOOK_'];\n\n        return {\n          resolve: {\n            conditions: ['storybook', 'stories', 'test', ...defaultClientConditions],\n            preserveSymlinks: isPreservingSymlinks(),\n          },\n          envPrefix: mergedEnvPrefix,\n        };\n      },\n    },\n    {\n      name: 'storybook:allow-storybook-dir',\n      enforce: 'post',\n      config(config) {\n        // If there is NO allow list then Vite allows anything in the root directory.\n        // If there IS an allow list then Vite only allows the listed directories.\n        // We add the storybook config directory only if there's already an allow list,\n        // to avoid disallowing the root unless it's already restricted.\n        if (config?.server?.fs?.allow) {\n          config.server.fs.allow.push(options.configDir);\n        }\n      },\n    },\n  ];\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/plugins/storybook-entry-plugin.ts",
    "content": "import type { Options } from 'storybook/internal/types';\n\nimport type { Plugin } from 'vite';\n\nimport { codeGeneratorPlugin } from './code-generator-plugin.ts';\nimport { injectExportOrderPlugin } from './inject-export-order-plugin.ts';\nimport { stripStoryHMRBoundary } from './strip-story-hmr-boundaries.ts';\n\n/**\n * A composite Vite plugin that manages the generation and injection of virtual entry points for\n * Storybook stories. This is builder-specific and NOT shared with addon-vitest.\n */\nexport async function storybookEntryPlugin(options: Options): Promise<Plugin[]> {\n  return [\n    // Pre-enforcement: handles virtual module resolution and loading (must run first)\n    codeGeneratorPlugin(options),\n    // Post-enforcement: injects __namedExportsOrder after TypeScript transpilation\n    await injectExportOrderPlugin(),\n    // Post-enforcement: removes import.meta.hot.accept() from story files\n    await stripStoryHMRBoundary(),\n  ];\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/plugins/storybook-external-globals-plugin.test.ts",
    "content": "import { expect, it } from 'vitest';\n\nimport { rewriteImport } from './storybook-external-globals-plugin.ts';\n\nconst packageName = '@storybook/package';\nconst globals = { [packageName]: '_STORYBOOK_PACKAGE_' };\n\nconst cases = [\n  {\n    globals,\n    packageName,\n    input: `import { Rain, Jour as Day, Nuit as Night, Sun } from \"${packageName}\"`,\n    output: `const { Rain, Jour: Day, Nuit: Night, Sun } = ${globals[packageName]}`,\n  },\n  {\n    globals,\n    packageName,\n    input: `import {\n      Rain,\n      Jour as Day,\n      Nuit as Night,\n      Sun\n    } from \"${packageName}\"`,\n    output: `const {\n      Rain,\n      Jour: Day,\n      Nuit: Night,\n      Sun\n    } = ${globals[packageName]}`,\n  },\n  {\n    globals,\n    packageName,\n    input: `import * as Foo from \"${packageName}\"`,\n    output: `const Foo = ${globals[packageName]}`,\n  },\n  {\n    globals,\n    packageName,\n    input: `import Foo from \"${packageName}\"`,\n    output: `const {default: Foo} = ${globals[packageName]}`,\n  },\n  {\n    globals,\n    packageName,\n    input: `import{Rain,Jour as Day,Nuit as Night,Sun}from'${packageName}'`,\n    output: `const {Rain,Jour: Day,Nuit: Night,Sun} =${globals[packageName]}`,\n  },\n  {\n    globals,\n    packageName,\n    input: `const { Afternoon } = await import('${packageName}')`,\n    output: `const { Afternoon } = ${globals[packageName]}`,\n  },\n];\n\nit('rewriteImport', () => {\n  cases.forEach(({ input, output, globals: caseGlobals, packageName: casePackage }) => {\n    expect(rewriteImport(input, caseGlobals, casePackage)).toStrictEqual(output);\n  });\n});\n"
  },
  {
    "path": "code/builders/builder-vite/src/plugins/storybook-external-globals-plugin.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\n\nimport { globalsNameReferenceMap } from 'storybook/internal/preview/globals';\nimport type { Options } from 'storybook/internal/types';\n\nimport * as pkg from 'empathic/package';\nimport { init, parse } from 'es-module-lexer';\nimport MagicString from 'magic-string';\nimport type { Alias, Plugin } from 'vite';\n\nconst escapeKeys = (key: string) => key.replace(/[-[\\]{}()*+?.,\\\\^$|#\\s]/g, '\\\\$&');\nconst defaultImportRegExp = 'import ([^*{}]+) from';\nconst replacementMap = new Map([\n  ['import ', 'const '],\n  ['import{', 'const {'],\n  ['* as ', ''],\n  [' as ', ': '],\n  [' from ', ' = '],\n  ['}from', '} ='],\n]);\n\n/**\n * This plugin swaps out imports of pre-bundled storybook preview modules for destructured from\n * global variables that are added in runtime.js.\n *\n * @example\n *\n * ```js\n * import { useMemo as useMemo2, useEffect as useEffect2 } from 'storybook/preview-api';\n * ```\n *\n * Becomes\n *\n * ```js\n * const { useMemo: useMemo2, useEffect: useEffect2 } = __STORYBOOK_MODULE_PREVIEW_API__;\n * ```\n *\n * It is based on existing plugins like https://github.com/crcong/vite-plugin-externals and\n * https://github.com/eight04/rollup-plugin-external-globals, but simplified to meet our simple\n * needs.\n */\n\nexport async function storybookExternalGlobalsPlugin(options: Options): Promise<Plugin> {\n  const build = await options.presets.apply('build');\n\n  const externals: typeof globalsNameReferenceMap & Record<string, string> =\n    globalsNameReferenceMap;\n\n  if (build?.test?.disableBlocks) {\n    externals['@storybook/addon-docs/blocks'] = '__STORYBOOK_BLOCKS_EMPTY_MODULE__';\n  }\n\n  await init;\n  const { mergeAlias } = await import('vite');\n\n  const globalsList = Object.keys(externals);\n  const globalsCodeFilter = new RegExp(globalsList.map(escapeKeys).join('|'));\n\n  return {\n    name: 'storybook:external-globals-plugin',\n    enforce: 'post',\n    // In dev (serve), we set up aliases to files that we write into node_modules/.cache.\n    async config(config, { command }) {\n      if (command !== 'serve') {\n        return undefined;\n      }\n      const newAlias = mergeAlias([], config.resolve?.alias) as Alias[];\n\n      const cachePath =\n        pkg.cache('sb-vite-plugin-externals', { create: true }) ??\n        join(process.cwd(), 'node_modules', '.cache', 'sb-vite-plugin-externals');\n\n      await Promise.all(\n        (Object.keys(externals) as Array<keyof typeof externals>).map(async (externalKey) => {\n          const externalCachePath = join(cachePath, `${externalKey}.js`);\n          newAlias.push({ find: new RegExp(`^${externalKey}$`), replacement: externalCachePath });\n          if (!existsSync(externalCachePath)) {\n            const directory = dirname(externalCachePath);\n            await mkdir(directory, { recursive: true });\n          }\n          await writeFile(externalCachePath, `module.exports = ${externals[externalKey]};`);\n        })\n      );\n\n      return {\n        resolve: {\n          alias: newAlias,\n        },\n      };\n    },\n    // Replace imports with variables destructured from global scope\n    transform: {\n      filter: { code: globalsCodeFilter },\n      async handler(code: string, id: string) {\n        if (globalsList.every((glob) => !code.includes(glob))) {\n          return undefined;\n        }\n\n        const [imports] = parse(code);\n        const src = new MagicString(code);\n        imports.forEach(({ n: path, ss: startPosition, se: endPosition }) => {\n          const packageName = path;\n          if (packageName && globalsList.includes(packageName)) {\n            const importStatement = src.slice(startPosition, endPosition);\n            const transformedImport = rewriteImport(importStatement, externals, packageName);\n            src.update(startPosition, endPosition, transformedImport);\n          }\n        });\n\n        return {\n          code: src.toString(),\n          map: null,\n        };\n      },\n    },\n  } satisfies Plugin;\n}\n\nfunction getDefaultImportReplacement(match: string) {\n  const matched = match.match(defaultImportRegExp);\n  return matched && `const {default: ${matched[1]}} =`;\n}\n\nfunction getSearchRegExp(packageName: string) {\n  const staticKeys = [...replacementMap.keys()].map(escapeKeys);\n  const packageNameLiteral = `.${packageName}.`;\n  const dynamicImportExpression = `await import\\\\(.${packageName}.\\\\)`;\n  const lookup = [defaultImportRegExp, ...staticKeys, packageNameLiteral, dynamicImportExpression];\n  return new RegExp(`(${lookup.join('|')})`, 'g');\n}\n\nexport function rewriteImport(\n  importStatement: string,\n  globs: Record<string, string>,\n  packageName: string\n): string {\n  const search = getSearchRegExp(packageName);\n  return importStatement.replace(\n    search,\n    (match) => replacementMap.get(match) ?? getDefaultImportReplacement(match) ?? globs[packageName]\n  );\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/plugins/storybook-optimize-deps-plugin.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { escapeGlobPath, getMockRedirectIncludeEntries } from './storybook-optimize-deps-plugin.ts';\n\ndescribe('escapeGlobPath', () => {\n  it('should not modify a plain path without special characters', () => {\n    expect(escapeGlobPath('./src/Button.stories.tsx')).toBe('./src/Button.stories.tsx');\n  });\n\n  it('should escape parentheses in path segments (e.g. Next.js route groups)', () => {\n    expect(escapeGlobPath('./src/(group)/Button.stories.tsx')).toBe(\n      './src/\\\\(group\\\\)/Button.stories.tsx'\n    );\n  });\n\n  it('should escape square brackets in path segments', () => {\n    expect(escapeGlobPath('./src/[id]/Button.stories.tsx')).toBe(\n      './src/\\\\[id\\\\]/Button.stories.tsx'\n    );\n  });\n\n  it('should escape curly braces in path segments', () => {\n    expect(escapeGlobPath('./src/{group}/Button.stories.tsx')).toBe(\n      './src/\\\\{group\\\\}/Button.stories.tsx'\n    );\n  });\n\n  it('should escape glob wildcard characters', () => {\n    expect(escapeGlobPath('./src/Button*.stories.tsx')).toBe('./src/Button\\\\*.stories.tsx');\n    expect(escapeGlobPath('./src/Button?.stories.tsx')).toBe('./src/Button\\\\?.stories.tsx');\n  });\n\n  it('should escape all special glob characters together', () => {\n    expect(escapeGlobPath('./src/(group)/[id]/{name}/*.stories.tsx')).toBe(\n      './src/\\\\(group\\\\)/\\\\[id\\\\]/\\\\{name\\\\}/\\\\*.stories.tsx'\n    );\n  });\n\n  it('should not modify paths that contain no special glob characters', () => {\n    expect(escapeGlobPath('./src/my-component/Button.stories.tsx')).toBe(\n      './src/my-component/Button.stories.tsx'\n    );\n  });\n});\n\ndescribe('getMockRedirectIncludeEntries', () => {\n  it('should include only manual mock redirect paths', () => {\n    expect(\n      getMockRedirectIncludeEntries([\n        { redirectPath: '/project/src/lib/__mocks__/db.ts' },\n        { redirectPath: null },\n      ])\n    ).toEqual(['/project/src/lib/__mocks__/db.ts']);\n  });\n\n  it('should escape special glob characters in redirect paths', () => {\n    expect(\n      getMockRedirectIncludeEntries([\n        { redirectPath: '/project/src/(group)/__mocks__/db.ts' },\n        { redirectPath: '/project/src/[id]/__mocks__/db.ts' },\n      ])\n    ).toEqual([\n      '/project/src/\\\\(group\\\\)/__mocks__/db.ts',\n      '/project/src/\\\\[id\\\\]/__mocks__/db.ts',\n    ]);\n  });\n\n  it('should dedupe redirect paths', () => {\n    expect(\n      getMockRedirectIncludeEntries([\n        { redirectPath: '/project/src/lib/__mocks__/db.ts' },\n        { redirectPath: '/project/src/lib/__mocks__/db.ts' },\n      ])\n    ).toEqual(['/project/src/lib/__mocks__/db.ts']);\n  });\n});\n"
  },
  {
    "path": "code/builders/builder-vite/src/plugins/storybook-optimize-deps-plugin.ts",
    "content": "import { loadPreviewOrConfigFile } from 'storybook/internal/common';\nimport type { StoryIndexGenerator } from 'storybook/internal/core-server';\nimport { babelParser, extractMockCalls, findMockRedirect } from 'storybook/internal/mocking-utils';\nimport type { Options, PreviewAnnotation, StoryIndex } from 'storybook/internal/types';\n\nimport { resolve } from 'pathe';\nimport { type Plugin } from 'vite';\n\nimport { processPreviewAnnotation } from '../utils/process-preview-annotation.ts';\nimport { getUniqueImportPaths } from '../utils/unique-import-paths.ts';\n\n/**\n * Escapes special glob characters in a file path so Vite's dep optimizer treats it as a literal\n * path rather than a glob pattern. This is necessary for paths containing characters like `(` and\n * `)` (e.g. Next.js route group directories such as `src/(group)/...`) which would otherwise be\n * interpreted as extglob patterns by fast-glob.\n */\nexport function escapeGlobPath(filePath: string): string {\n  return filePath.replace(/[()[\\]{}!*?|+@]/g, '\\\\$&');\n}\n\n/** Converts extracted sb.mock calls into optimizeDeps include entries for manual **mocks** files. */\nexport function getMockRedirectIncludeEntries(\n  mockCalls: Array<{ redirectPath: string | null }>\n): string[] {\n  return Array.from(\n    new Set(\n      mockCalls\n        .map((mockCall) => mockCall.redirectPath)\n        .filter((redirectPath): redirectPath is string => redirectPath !== null)\n        .map(escapeGlobPath)\n    )\n  );\n}\n\n/** A Vite plugin that configures dependency optimization for Storybook's dev server. */\nexport function storybookOptimizeDepsPlugin(options: Options): Plugin {\n  return {\n    name: 'storybook:optimize-deps-plugin',\n    async config(config, { command }) {\n      // optimizeDeps only applies to the dev server, not production builds\n      if (command !== 'serve') {\n        return;\n      }\n\n      const projectRoot = resolve(options.configDir, '..');\n\n      const [extraOptimizeDeps, storyIndexGenerator, previewAnnotations] = await Promise.all([\n        options.presets.apply<string[]>('optimizeViteDeps', []),\n        options.presets.apply<StoryIndexGenerator>('storyIndexGenerator'),\n        options.presets.apply<PreviewAnnotation[]>('previewAnnotations', [], options),\n      ]);\n\n      const index: StoryIndex = await storyIndexGenerator.getIndex();\n\n      // Include the user's preview file and all addon/framework/renderer preview annotations\n      // as optimizer entries so Vite can discover all transitive CJS dependencies automatically.\n      const previewOrConfigFile = loadPreviewOrConfigFile({ configDir: options.configDir });\n\n      const mockRedirectIncludeEntries = previewOrConfigFile\n        ? getMockRedirectIncludeEntries(\n            extractMockCalls(\n              {\n                previewConfigPath: previewOrConfigFile,\n                coreOptions: { disableTelemetry: true },\n                configDir: options.configDir,\n              },\n              babelParser,\n              projectRoot,\n              findMockRedirect\n            )\n          )\n        : [];\n\n      const previewAnnotationEntries = [...previewAnnotations, previewOrConfigFile]\n        .filter((path): path is PreviewAnnotation => path !== undefined)\n        .map((path) => processPreviewAnnotation(path, projectRoot));\n\n      return {\n        optimizeDeps: {\n          // Story files + preview annotation files as entry points for the dep optimizer.\n          // Vite will crawl these to discover all transitive CJS dependencies that need\n          // pre-bundling, removing the need for a hard-coded include list.\n          // Paths are escaped so that special glob characters (e.g. parentheses in Next.js route\n          // group directories) are treated as literal characters, not glob syntax.\n          entries: [\n            ...(typeof config.optimizeDeps?.entries === 'string'\n              ? [config.optimizeDeps.entries]\n              : (config.optimizeDeps?.entries ?? [])),\n            ...mockRedirectIncludeEntries,\n            ...getUniqueImportPaths(index).map(escapeGlobPath),\n            ...previewAnnotationEntries.map(escapeGlobPath),\n          ],\n          // Extra deps explicitly included by Storybook presets (e.g. framework-specific packages).\n          include: [...extraOptimizeDeps, ...(config.optimizeDeps?.include ?? [])],\n        },\n      };\n    },\n  };\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/plugins/storybook-project-annotations-plugin.ts",
    "content": "import type { Options } from 'storybook/internal/types';\n\nimport type { Plugin } from 'vite';\n\nimport { generateProjectAnnotationsCode } from '../codegen-project-annotations.ts';\nimport { getResolvedVirtualModuleId } from '../virtual-file-names.ts';\n\nexport const VIRTUAL_ID = 'virtual:/@storybook/builder-vite/project-annotations.js';\nconst RESOLVED_VIRTUAL_ID = getResolvedVirtualModuleId(VIRTUAL_ID);\n\n/**\n * A Vite plugin that serves the project annotations virtual module.\n *\n * The virtual module can be imported as:\n *\n * ```ts\n * import { getProjectAnnotations } from 'virtual:/@storybook/builder-vite/project-annotations.js';\n * ```\n */\nexport function storybookProjectAnnotationsPlugin(options: Options): Plugin {\n  let projectRoot: string;\n\n  return {\n    name: 'storybook:project-annotations-plugin',\n    enforce: 'pre',\n    configResolved(config) {\n      projectRoot = config.root;\n    },\n    resolveId(source) {\n      if (source === VIRTUAL_ID) {\n        return RESOLVED_VIRTUAL_ID;\n      }\n    },\n    async load(id) {\n      if (id === RESOLVED_VIRTUAL_ID) {\n        return generateProjectAnnotationsCode(options, projectRoot);\n      }\n    },\n  };\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/plugins/storybook-runtime-plugin.ts",
    "content": "import type { Builder_EnvsRaw } from 'storybook/internal/types';\nimport type { Options } from 'storybook/internal/types';\n\nimport type { Plugin } from 'vite';\n\nimport { stringifyProcessEnvs } from '../envs.ts';\n\nexport interface StorybookRuntimePluginOptions {\n  externals: Record<string, string>;\n  envs?: Builder_EnvsRaw;\n}\n\n/** A composite Vite plugin that injects environment variables for Storybook's runtime. */\nexport async function storybookSanitizeEnvs(options: Options): Promise<Plugin[]> {\n  const plugins: Plugin[] = [];\n  const envs = await options.presets.apply<Builder_EnvsRaw>('env');\n\n  if (envs && Object.keys(envs).length > 0) {\n    plugins.push({\n      name: 'storybook:env-plugin',\n      config(config) {\n        const envDefines = stringifyProcessEnvs(envs, config.envPrefix);\n        return {\n          define: envDefines,\n        };\n      },\n    });\n  }\n\n  return plugins;\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/plugins/strip-story-hmr-boundaries.ts",
    "content": "import MagicString from 'magic-string';\nimport type { Plugin } from 'vite';\n\n/**\n * This plugin removes HMR `accept` calls in story files. Stories should not be treated as hmr\n * boundaries, but vite has a bug which causes them to be treated as boundaries\n * (https://github.com/vitejs/vite/issues/9869).\n */\nexport async function stripStoryHMRBoundary() {\n  const { createFilter } = await import('vite');\n\n  const include = /\\.stories\\.(tsx?|jsx?|svelte|vue)$/;\n  const filter = createFilter(include);\n  return {\n    name: 'storybook:strip-hmr-boundary-plugin',\n    enforce: 'post',\n    transform: {\n      filter: { id: include },\n      async handler(src, id) {\n        if (!filter(id)) {\n          return undefined;\n        }\n\n        const s = new MagicString(src);\n        s.replace(/import\\.meta\\.hot\\.accept\\w*/, '(function hmrBoundaryNoop(){})');\n\n        return {\n          code: s.toString(),\n          map: s.generateMap({ hires: true, source: id }),\n        };\n      },\n    },\n  } satisfies Plugin;\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/plugins/vite-inject-mocker/plugin.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\n/**\n * Unit-tests for the vite-inject-mocker plugin, focused on the `transformIndexHtml` hook which must\n * emit a **relative** `src` during production builds (so Storybook artifacts load when hosted at\n * non-root paths, e.g. GitHub Pages) and an **absolute** `src` during development (so Vite's\n * dev-server `resolveId` can match it).\n *\n * @see https://github.com/storybookjs/storybook/issues/32428\n */\n\n// We need to mock the import.meta.resolve call and node:url before\n// importing the plugin, because the module resolves the mocker\n// runtime path at import time.\nvi.mock('node:url', () => ({\n  fileURLToPath: vi.fn(() => '/fake/mocker-runtime.js'),\n}));\n\n// Mock import.meta.resolve\nvi.stubGlobal('import', { meta: { resolve: () => 'file:///fake/mocker-runtime.js' } });\n\n// Dynamic import after mocks are set up\nconst { viteInjectMockerRuntime } = await import('./plugin.js');\n\nfunction makeHtml(headAttrs = '') {\n  return `<!doctype html><html><head${headAttrs}><meta charset=\"utf-8\" /></head><body></body></html>`;\n}\n\ndescribe('vite-inject-mocker plugin — transformIndexHtml', () => {\n  function createPlugin(command: 'build' | 'serve') {\n    const plugin = viteInjectMockerRuntime({ previewConfigPath: null }) as any;\n    // Simulate Vite calling configResolved\n    plugin.configResolved({ command } as any);\n    return plugin;\n  }\n\n  it('uses a relative path (./…) in build mode', () => {\n    const plugin = createPlugin('build');\n    const html = makeHtml();\n    const result = plugin.transformIndexHtml(html);\n\n    expect(result).toContain('src=\"./vite-inject-mocker-entry.js\"');\n    expect(result).not.toContain('src=\"/vite-inject-mocker-entry.js\"');\n  });\n\n  it('uses an absolute path (/…) in dev mode', () => {\n    const plugin = createPlugin('serve');\n    const html = makeHtml();\n    const result = plugin.transformIndexHtml(html);\n\n    expect(result).toContain('src=\"/vite-inject-mocker-entry.js\"');\n    // Ensure it's not the relative form\n    expect(result).not.toContain('src=\"./vite-inject-mocker-entry.js\"');\n  });\n\n  it('injects the script tag right after <head>', () => {\n    const plugin = createPlugin('build');\n    const html = makeHtml();\n    const result = plugin.transformIndexHtml(html);\n\n    const headIndex = result.indexOf('<head>');\n    const scriptIndex = result.indexOf('<script type=\"module\"');\n    expect(scriptIndex).toBeGreaterThan(headIndex);\n    expect(scriptIndex).toBe(headIndex + '<head>'.length);\n  });\n\n  it('handles <head> tags with attributes', () => {\n    const plugin = createPlugin('build');\n    const html = makeHtml(' lang=\"en\"');\n    const result = plugin.transformIndexHtml(html);\n\n    expect(result).toContain('src=\"./vite-inject-mocker-entry.js\"');\n    expect(result).toContain('<head lang=\"en\"><script type=\"module\"');\n  });\n\n  it('returns undefined when <head> is missing', () => {\n    const plugin = createPlugin('build');\n    const result = plugin.transformIndexHtml('<html><body></body></html>');\n    expect(result).toBeUndefined();\n  });\n\n  it('preserves the rest of the HTML unchanged', () => {\n    const plugin = createPlugin('build');\n    const html = makeHtml();\n    const result = plugin.transformIndexHtml(html);\n\n    // Remove the injected script to verify the rest is intact\n    const cleaned = result.replace(\n      '<script type=\"module\" src=\"./vite-inject-mocker-entry.js\"></script>',\n      ''\n    );\n    expect(cleaned).toBe(html);\n  });\n});\n"
  },
  {
    "path": "code/builders/builder-vite/src/plugins/vite-inject-mocker/plugin.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport type { ResolvedConfig } from 'vite';\n\nconst ENTRY_PATH = '/vite-inject-mocker-entry.js';\n\nexport const viteInjectMockerRuntime = (options: {\n  previewConfigPath?: string | null;\n}): import('vite').Plugin => {\n  // Get the actual file path so Vite can resolve relative imports\n  const mockerRuntimePath = fileURLToPath(\n    import.meta.resolve('storybook/internal/mocking-utils/mocker-runtime')\n  );\n\n  let viteConfig: ResolvedConfig;\n\n  return {\n    name: 'vite:storybook-inject-mocker-runtime',\n    enforce: 'pre',\n    buildStart() {\n      if (viteConfig.command === 'build') {\n        this.emitFile({\n          type: 'chunk',\n          id: mockerRuntimePath,\n          fileName: ENTRY_PATH.slice(1),\n        });\n      }\n    },\n    configResolved(config) {\n      viteConfig = config;\n    },\n    configureServer(server) {\n      if (options.previewConfigPath) {\n        server.watcher.on('change', (file) => {\n          if (file === options.previewConfigPath) {\n            server.ws.send({\n              type: 'custom',\n              event: 'invalidate-mocker',\n            });\n          }\n        });\n      }\n    },\n    resolveId: {\n      filter: { id: /\\/vite-inject-mocker-entry\\.js/ },\n      handler(source) {\n        if (source === ENTRY_PATH) {\n          return mockerRuntimePath;\n        }\n        return undefined;\n      },\n    },\n    transformIndexHtml(html: string) {\n      const headTag = html.match(/<head[^>]*>/);\n\n      if (headTag) {\n        // Use a relative path for production builds so the script loads\n        // correctly when artifacts are hosted at non-root paths (e.g.,\n        // GitHub Pages subdirectories).  In dev mode, the absolute path\n        // is required so Vite's dev server can match it in resolveId.\n        const src = viteConfig.command === 'build' ? `.${ENTRY_PATH}` : ENTRY_PATH;\n        const entryCode = `<script type=\"module\" src=\"${src}\"></script>`;\n        const headTagIndex = html.indexOf(headTag[0]);\n        const newHtml =\n          html.slice(0, headTagIndex + headTag[0].length) +\n          entryCode +\n          html.slice(headTagIndex + headTag[0].length);\n        return newHtml;\n      }\n    },\n  };\n};\n"
  },
  {
    "path": "code/builders/builder-vite/src/plugins/vite-mock/plugin.ts",
    "content": "import { readFileSync } from 'node:fs';\n\nimport {\n  babelParser,\n  extractMockCalls,\n  findMockRedirect,\n  getAutomockCode,\n  getRealPath,\n  rewriteSbMockImportCalls,\n} from 'storybook/internal/mocking-utils';\nimport { logger } from 'storybook/internal/node-logger';\nimport type { CoreConfig } from 'storybook/internal/types';\n\nimport { normalize } from 'pathe';\nimport type { Plugin, ResolvedConfig } from 'vite';\n\nimport { type MockCall, getCleanId, invalidateAllRelatedModules } from './utils.ts';\n\nexport interface MockPluginOptions {\n  /** The absolute path to the preview.tsx file where mocks are defined. */\n  previewConfigPath: string;\n  /** The absolute path to the Storybook config directory. */\n  coreOptions?: CoreConfig;\n  /** Configuration directory */\n  configDir: string;\n}\n\n/**\n * Vite plugin for Storybook module mocking manifest generation.\n *\n * Scans the preview config for sb.mock() calls, processes them, and emits a manifest for runtime\n * use.\n *\n * Responsibilities:\n *\n * - Extract mock calls from preview config\n * - Invalidate affected files when mocks change\n * - Transform mock calls to automocked code\n *\n * @see MockPluginOptions\n */\nexport function viteMockPlugin(options: MockPluginOptions): Plugin[] {\n  // --- Plugin State ---\n  let viteConfig: ResolvedConfig;\n  let mockCalls: MockCall[] = [];\n\n  const normalizedPreviewConfigPath = normalize(options.previewConfigPath);\n\n  // --- Plugin Definition ---\n  return [\n    {\n      name: 'storybook:mock-loader',\n\n      configResolved(config) {\n        viteConfig = config;\n      },\n\n      buildStart() {\n        mockCalls = extractMockCalls(options, babelParser, viteConfig.root, findMockRedirect);\n      },\n\n      configureServer(server) {\n        async function invalidateAffectedFiles(file: string) {\n          if (file === options.previewConfigPath || file.includes('__mocks__')) {\n            // Store the old mocks before updating\n            const oldMockCalls = mockCalls;\n            // Re-extract mocks to get the latest list\n            mockCalls = extractMockCalls(options, babelParser, viteConfig.root, findMockRedirect);\n\n            // Invalidate the preview file\n            const previewMod = server.moduleGraph.getModuleById(options.previewConfigPath);\n            if (previewMod) {\n              server.moduleGraph.invalidateModule(previewMod);\n            }\n\n            // Invalidate all current mocks (including optimized/node_modules variants)\n            for (const call of mockCalls) {\n              invalidateAllRelatedModules(server, call.absolutePath, call.path);\n            }\n\n            // Invalidate all removed mocks (present in old, missing in new)\n            const newAbsPaths = new Set(mockCalls.map((c) => c.absolutePath));\n            for (const oldCall of oldMockCalls) {\n              if (!newAbsPaths.has(oldCall.absolutePath)) {\n                invalidateAllRelatedModules(server, oldCall.absolutePath, oldCall.path);\n              }\n            }\n\n            // Force a full browser reload so all affected files are refetched\n            server.ws.send({ type: 'full-reload' });\n\n            return [];\n          }\n        }\n\n        server.watcher.on('change', invalidateAffectedFiles);\n        server.watcher.on('add', invalidateAffectedFiles);\n        server.watcher.on('unlink', invalidateAffectedFiles);\n      },\n\n      load: {\n        order: 'pre',\n        handler(id) {\n          const preserveSymlinks = viteConfig.resolve.preserveSymlinks;\n\n          const idNorm = getRealPath(id, preserveSymlinks);\n          const cleanId = getCleanId(idNorm);\n\n          for (const call of mockCalls) {\n            const callNorm = getRealPath(call.absolutePath, preserveSymlinks);\n\n            if (callNorm !== idNorm && call.path !== cleanId) {\n              continue;\n            }\n\n            if (call.redirectPath) {\n              this.addWatchFile(call.redirectPath);\n              return readFileSync(call.redirectPath, 'utf-8');\n            }\n          }\n          return null;\n        },\n      },\n      transform: {\n        order: 'pre',\n        handler(code, id) {\n          for (const call of mockCalls) {\n            const preserveSymlinks = viteConfig.resolve.preserveSymlinks;\n\n            const idNorm = getRealPath(id, preserveSymlinks);\n            const callNorm = getRealPath(call.absolutePath, preserveSymlinks);\n\n            if (viteConfig.command !== 'serve') {\n              if (callNorm !== idNorm) {\n                continue;\n              }\n            } else {\n              const cleanId = getCleanId(idNorm);\n\n              if (call.path !== cleanId && callNorm !== idNorm) {\n                continue;\n              }\n            }\n\n            try {\n              if (!call.redirectPath) {\n                const automockedCode = getAutomockCode(code, call.spy, babelParser as any);\n\n                return {\n                  code: automockedCode.toString(),\n                  map: automockedCode.generateMap(),\n                };\n              }\n            } catch (e) {\n              logger.error(`Error automocking ${id}: ${e}`);\n              return null;\n            }\n          }\n          return null;\n        },\n      },\n    },\n    {\n      name: 'storybook:mock-loader-preview',\n      transform: {\n        filter: { id: normalizedPreviewConfigPath },\n        handler(code, id) {\n          if (id === normalizedPreviewConfigPath) {\n            try {\n              return rewriteSbMockImportCalls(code);\n            } catch (e) {\n              logger.debug(`Could not transform sb.mock(import(...)) calls in ${id}: ${e}`);\n              return null;\n            }\n          }\n          return null;\n        },\n      },\n    },\n  ];\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/plugins/vite-mock/utils.ts",
    "content": "import type { ViteDevServer } from 'vite';\n\n/**\n * Get the clean id of a module.\n *\n * @param id - The id of the module.\n * @returns Extracts the id of node_modules for optimized deps\n */\nexport function getCleanId(id: string) {\n  return id\n    .replace(/^.*\\/deps\\//, '') // Remove everything up to and including /deps/\n    .replace(/\\.js.*$/, '') // Remove .js and anything after (query params)\n    .replace(/_/g, '/');\n}\n\n/**\n * Invalidate all related modules for a given mock (by absolute path and package name), including\n * optimized deps and node_modules variants.\n */\nexport function invalidateAllRelatedModules(\n  server: ViteDevServer,\n  absPath: string,\n  pkgName: string\n) {\n  for (const mod of server.moduleGraph.idToModuleMap.values()) {\n    if (mod.id === absPath || (mod.id && getCleanId(mod.id) === pkgName)) {\n      server.moduleGraph.invalidateModule(mod);\n    }\n  }\n}\n\nexport type MockCall = {\n  path: string;\n  absolutePath: string;\n  redirectPath: string | null;\n  spy: boolean;\n};\n"
  },
  {
    "path": "code/builders/builder-vite/src/plugins/webpack-stats-plugin.ts",
    "content": "// This plugin is a direct port of https://github.com/IanVS/vite-plugin-turbosnap\nimport { relative } from 'node:path';\n\nimport type { BuilderStats } from 'storybook/internal/types';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\nimport type { Plugin } from 'vite';\n\nimport {\n  SB_VIRTUAL_FILES,\n  getOriginalVirtualModuleId,\n  getResolvedVirtualModuleId,\n} from '../virtual-file-names.ts';\n\n/*\n * Reason, Module are copied from chromatic types\n * https://github.com/chromaui/chromatic-cli/blob/145a5e295dde21042e96396c7e004f250d842182/bin-src/types.ts#L265-L276\n */\ninterface Reason {\n  moduleName: string;\n}\ninterface Module {\n  id: string | number;\n  name: string;\n  modules?: Array<Pick<Module, 'name'>>;\n  reasons?: Reason[];\n}\n\ntype WebpackStatsPluginOptions = {\n  workingDir: string;\n};\n\n/**\n * Strips off query params added by rollup/vite to ids, to make paths compatible for comparison with\n * git.\n */\nfunction stripQueryParams(filePath: string): string {\n  return filePath.split('?')[0];\n}\n\n/** We only care about user code, not node_modules, vite files, or (most) virtual files. */\nfunction isUserCode(moduleName: string) {\n  if (!moduleName) {\n    return false;\n  }\n\n  // keep Storybook's virtual files because they import the story files, so they are essential to the module graph\n  if (Object.values(SB_VIRTUAL_FILES).includes(getOriginalVirtualModuleId(moduleName))) {\n    return true;\n  }\n\n  return Boolean(\n    !moduleName.startsWith('vite/') &&\n    !moduleName.startsWith('\\0') &&\n    moduleName !== 'react/jsx-runtime'\n  );\n}\n\nexport type WebpackStatsPlugin = Plugin & { storybookGetStats: () => BuilderStats };\n\nexport function pluginWebpackStats({ workingDir }: WebpackStatsPluginOptions): WebpackStatsPlugin {\n  /** Convert an absolute path name to a path relative to the vite root, with a starting `./` */\n  function normalize(filename: string) {\n    // Do not try to resolve virtual files\n    if (filename.startsWith('virtual:')) {\n      // We have to append a forward slash because otherwise we break turbosnap.\n      // As soon as the chromatic-cli supports `virtual:` id's without a starting forward slash,\n      // we can remove adding the forward slash here\n      // Reference: https://github.com/chromaui/chromatic-cli/blob/v11.25.2/node-src/lib/getDependentStoryFiles.ts#L53\n      return `/${filename}`;\n    }\n    // ! Maintain backwards compatibility with the old virtual file names\n    // ! to ensure that the stats file doesn't change between the versions\n    // ! Turbosnap is also only compatible with the old virtual file names\n    // ! the old virtual file names did not start with the obligatory \\0 character\n    if (Object.values(SB_VIRTUAL_FILES).includes(getOriginalVirtualModuleId(filename))) {\n      // We have to append a forward slash because otherwise we break turbosnap.\n      // As soon as the chromatic-cli supports `virtual:` id's without a starting forward slash,\n      // we can remove adding the forward slash here\n      // Reference: https://github.com/chromaui/chromatic-cli/blob/v11.25.2/node-src/lib/getDependentStoryFiles.ts#L53\n      return `/${getOriginalVirtualModuleId(filename)}`;\n    }\n\n    // Otherwise, we need them in the format `./path/to/file.js`.\n    else {\n      const relativePath = relative(workingDir, stripQueryParams(filename));\n      // This seems hacky, got to be a better way to add a `./` to the start of a path.\n      return `./${slash(relativePath)}`;\n    }\n  }\n\n  /** Helper to create Reason objects out of a list of string paths */\n  function createReasons(importers?: readonly string[]): Reason[] {\n    return (importers || []).map((i) => ({ moduleName: normalize(i) }));\n  }\n\n  /** Helper function to build a `Module` given a filename and list of files that import it */\n  function createStatsMapModule(filename: string, importers?: readonly string[]): Module {\n    return {\n      id: filename,\n      name: filename,\n      reasons: createReasons(importers),\n    };\n  }\n\n  const statsMap = new Map<string, Module>();\n\n  return {\n    name: 'storybook:rollup-plugin-webpack-stats',\n    // We want this to run after the vite build plugins (https://vitejs.dev/guide/api-plugin.html#plugin-ordering)\n    enforce: 'post',\n    moduleParsed: function (mod) {\n      if (!isUserCode(mod.id)) {\n        return;\n      }\n      mod.importedIds\n        .concat(mod.dynamicallyImportedIds)\n        .filter((name) => isUserCode(name))\n        .forEach((depIdUnsafe) => {\n          const depId = normalize(depIdUnsafe);\n          if (!statsMap.has(depId)) {\n            statsMap.set(depId, createStatsMapModule(depId, [mod.id]));\n            return;\n          }\n          const m = statsMap.get(depId);\n          if (!m) {\n            return;\n          }\n          m.reasons = (m.reasons ?? [])\n            .concat(createReasons([mod.id]))\n            .filter((r) => r.moduleName !== depId);\n          statsMap.set(depId, m);\n        });\n    },\n\n    storybookGetStats() {\n      const stats = { modules: Array.from(statsMap.values()) };\n      return { ...stats, toJson: () => stats };\n    },\n  };\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/preset.ts",
    "content": "import { findConfigFile } from 'storybook/internal/common';\nimport type { Options } from 'storybook/internal/types';\n\nimport type { PluginOption } from 'vite';\n\nimport { storybookConfigPlugin } from './plugins/storybook-config-plugin.ts';\nimport { storybookOptimizeDepsPlugin } from './plugins/storybook-optimize-deps-plugin.ts';\nimport { storybookProjectAnnotationsPlugin } from './plugins/storybook-project-annotations-plugin.ts';\nimport { storybookSanitizeEnvs } from './plugins/storybook-runtime-plugin.ts';\nimport { viteInjectMockerRuntime } from './plugins/vite-inject-mocker/plugin.ts';\nimport { viteMockPlugin } from './plugins/vite-mock/plugin.ts';\n\nexport const optimizeViteDeps: string[] = ['storybook/internal/preview/runtime'];\n\n/**\n * Preset that provides the core Storybook Vite plugins shared between `@storybook/builder-vite` and\n * `@storybook/addon-vitest`.\n */\nexport async function viteCorePlugins(\n  _: PluginOption[],\n  options: Options\n): Promise<PluginOption[]> {\n  const previewConfigPath = findConfigFile('preview', options.configDir);\n\n  return [\n    storybookProjectAnnotationsPlugin(options),\n    ...storybookConfigPlugin({ configDir: options.configDir }),\n    storybookOptimizeDepsPlugin(options),\n    ...(await storybookSanitizeEnvs(options)),\n    ...(previewConfigPath\n      ? [\n          viteInjectMockerRuntime({ previewConfigPath }),\n          viteMockPlugin({\n            previewConfigPath,\n            coreOptions: await options.presets.apply('core'),\n            configDir: options.configDir,\n          }),\n        ]\n      : []),\n  ];\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/transform-iframe-html.ts",
    "content": "import { normalizeStories } from 'storybook/internal/common';\nimport type { DocsOptions, Options, TagsOptions } from 'storybook/internal/types';\n\nimport { SB_VIRTUAL_FILES } from './virtual-file-names.ts';\n\nexport type PreviewHtml = string | undefined;\n\nexport async function transformIframeHtml(html: string, options: Options) {\n  const { configType, features, presets } = options;\n  const build = await presets.apply('build');\n  const frameworkOptions = await presets.apply<Record<string, any> | null>('frameworkOptions');\n  const headHtmlSnippet = await presets.apply<PreviewHtml>('previewHead');\n  const bodyHtmlSnippet = await presets.apply<PreviewHtml>('previewBody');\n  const logLevel = await presets.apply('logLevel', undefined);\n  const docsOptions = await presets.apply<DocsOptions>('docs');\n  const tagsOptions = await presets.apply<TagsOptions>('tags');\n\n  const coreOptions = await presets.apply('core');\n  const stories = normalizeStories(await options.presets.apply('stories', [], options), {\n    configDir: options.configDir,\n    workingDir: process.cwd(),\n  }).map((specifier) => ({\n    ...specifier,\n    importPathMatcher: specifier.importPathMatcher.source,\n  }));\n\n  const otherGlobals = {\n    ...(build?.test?.disableBlocks ? { __STORYBOOK_BLOCKS_EMPTY_MODULE__: {} } : {}),\n  };\n\n  const transformedHtml = html\n    .replace('[CONFIG_TYPE HERE]', configType || '')\n    .replace('[LOGLEVEL HERE]', logLevel || '')\n    .replace(`'[FRAMEWORK_OPTIONS HERE]'`, JSON.stringify(frameworkOptions))\n    .replace(\n      `('OTHER_GLOBALS HERE');`,\n      Object.entries(otherGlobals)\n        .map(([k, v]) => `window[\"${k}\"] = ${JSON.stringify(v)};`)\n        .join('')\n    )\n    .replace(\n      `'[CHANNEL_OPTIONS HERE]'`,\n      JSON.stringify(coreOptions && coreOptions.channelOptions ? coreOptions.channelOptions : {})\n    )\n    .replace(`'[FEATURES HERE]'`, JSON.stringify(features || {}))\n    .replace(`'[STORIES HERE]'`, JSON.stringify(stories || {}))\n    .replace(`'[DOCS_OPTIONS HERE]'`, JSON.stringify(docsOptions || {}))\n    .replace(`'[TAGS_OPTIONS HERE]'`, JSON.stringify(tagsOptions || {}))\n    .replace('<!-- [HEAD HTML SNIPPET HERE] -->', headHtmlSnippet || '')\n    .replace('<!-- [BODY HTML SNIPPET HERE] -->', bodyHtmlSnippet || '');\n\n  if (configType === 'DEVELOPMENT') {\n    return transformedHtml.replace(\n      'virtual:/@storybook/builder-vite/vite-app.js',\n      `/@id/__x00__${SB_VIRTUAL_FILES.VIRTUAL_APP_FILE}`\n    );\n  }\n\n  return transformedHtml;\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/types.ts",
    "content": "import type { Builder, Options } from 'storybook/internal/types';\n\nimport type { InlineConfig, UserConfig } from 'vite';\n\n// Storybook's Stats are optional Webpack related property\ntype ViteStats = {\n  toJson: () => any;\n};\n\nexport type ViteBuilder = Builder<UserConfig, ViteStats>;\n\nexport type ViteFinal = (\n  config: InlineConfig,\n  options: Options\n) => InlineConfig | Promise<InlineConfig>;\n\nexport type StorybookConfigVite = {\n  viteFinal?: ViteFinal;\n};\n\nexport type BuilderOptions = {\n  /** Path to `vite.config` file, relative to `process.cwd()`. */\n  viteConfigPath?: string;\n};\n"
  },
  {
    "path": "code/builders/builder-vite/src/utils/build-module-graph.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport type { ModuleNode as StorybookModuleNode } from 'storybook/internal/types';\nimport type { ViteDevServer } from 'vite';\n\nimport { buildModuleGraph } from './build-module-graph.ts';\n\nvi.mock('./vite-server', () => ({\n  createViteServer: vi.fn(),\n}));\n\ntype ViteModuleNodeLike = {\n  file: string | null;\n  type: StorybookModuleNode['type'];\n  importers: Set<ViteModuleNodeLike>;\n  importedModules: Set<ViteModuleNodeLike>;\n};\n\nfunction createViteModuleNode(\n  file: string | null,\n  type: StorybookModuleNode['type'] = 'js'\n): ViteModuleNodeLike {\n  return {\n    file,\n    type,\n    importers: new Set(),\n    importedModules: new Set(),\n  };\n}\n\nfunction createFileToModulesMap(...entries: Array<[string, Set<ViteModuleNodeLike>]>) {\n  return new Map(entries) as ViteDevServer['moduleGraph']['fileToModulesMap'];\n}\n\nfunction getFirstNode(\n  file: string,\n  moduleGraph: ReturnType<typeof buildModuleGraph>\n): StorybookModuleNode {\n  const moduleNode = moduleGraph.get(file)?.values().next().value;\n  if (!moduleNode) {\n    throw new Error(`Expected module node for ${file}`);\n  }\n  return moduleNode;\n}\n\ndescribe('buildModuleGraph', () => {\n  it('converts vite module nodes into the shared module graph shape', () => {\n    const entry = createViteModuleNode('/src/entry.ts');\n    const component = createViteModuleNode('/src/component.ts');\n    const styles = createViteModuleNode('/src/component.css', 'css');\n\n    entry.importedModules.add(component);\n    component.importers.add(entry);\n    component.importedModules.add(styles);\n    styles.importers.add(component);\n\n    const moduleGraph = buildModuleGraph(\n      createFileToModulesMap(\n        ['/src/entry.ts', new Set([entry])],\n        ['/src/component.ts', new Set([component])],\n        ['/src/component.css', new Set([styles])]\n      )\n    );\n\n    const entryNode = getFirstNode('/src/entry.ts', moduleGraph);\n    const componentNode = getFirstNode('/src/component.ts', moduleGraph);\n    const styleNode = getFirstNode('/src/component.css', moduleGraph);\n\n    expect(entryNode.file).toBe('/src/entry.ts');\n    expect(componentNode.type).toBe('js');\n    expect(styleNode.type).toBe('css');\n\n    expect(entryNode.importedModules).toEqual(new Set([componentNode]));\n    expect(componentNode.importers).toEqual(new Set([entryNode]));\n    expect(componentNode.importedModules).toEqual(new Set([styleNode]));\n    expect(styleNode.importers).toEqual(new Set([componentNode]));\n  });\n\n  it('reuses the same converted node identity across relationships', () => {\n    const shared = createViteModuleNode('/src/shared.ts');\n    const importerA = createViteModuleNode('/src/a.ts');\n    const importerB = createViteModuleNode('/src/b.ts');\n\n    importerA.importedModules.add(shared);\n    importerB.importedModules.add(shared);\n    shared.importers.add(importerA);\n    shared.importers.add(importerB);\n\n    const moduleGraph = buildModuleGraph(\n      createFileToModulesMap(\n        ['/src/shared.ts', new Set([shared])],\n        ['/src/a.ts', new Set([importerA])],\n        ['/src/b.ts', new Set([importerB])]\n      )\n    );\n\n    const sharedNode = getFirstNode('/src/shared.ts', moduleGraph);\n    const importerANode = getFirstNode('/src/a.ts', moduleGraph);\n    const importerBNode = getFirstNode('/src/b.ts', moduleGraph);\n\n    expect(importerANode.importedModules.has(sharedNode)).toBe(true);\n    expect(importerBNode.importedModules.has(sharedNode)).toBe(true);\n    expect(sharedNode.importers).toEqual(new Set([importerANode, importerBNode]));\n  });\n\n  it('skips related vite module nodes without a file', () => {\n    const entry = createViteModuleNode('/src/entry.ts');\n    const virtualModule = createViteModuleNode(null);\n\n    entry.importedModules.add(virtualModule);\n    virtualModule.importers.add(entry);\n\n    const moduleGraph = buildModuleGraph(\n      createFileToModulesMap(['/src/entry.ts', new Set([entry])])\n    );\n    const entryNode = getFirstNode('/src/entry.ts', moduleGraph);\n\n    expect(moduleGraph.size).toBe(1);\n    expect(entryNode.importedModules.size).toBe(0);\n  });\n\n  it('preserves edges for related vite module nodes discovered before their file path is known', () => {\n    const entry = createViteModuleNode('/src/entry.ts');\n    const component = createViteModuleNode(null);\n\n    entry.importedModules.add(component);\n    component.importers.add(entry);\n\n    const moduleGraph = buildModuleGraph(\n      createFileToModulesMap(\n        ['/src/entry.ts', new Set([entry])],\n        ['/src/component.ts', new Set([component])]\n      )\n    );\n\n    const entryNode = getFirstNode('/src/entry.ts', moduleGraph);\n    const componentNode = getFirstNode('/src/component.ts', moduleGraph);\n\n    expect(entryNode.importedModules).toEqual(new Set([componentNode]));\n    expect(componentNode.importers).toEqual(new Set([entryNode]));\n  });\n\n  it('keeps multiple module identities for the same file', () => {\n    const clientModule = createViteModuleNode('/src/shared.ts');\n    const ssrModule = createViteModuleNode('/src/shared.ts');\n\n    const moduleGraph = buildModuleGraph(\n      createFileToModulesMap(['/src/shared.ts', new Set([clientModule, ssrModule])])\n    );\n\n    expect(moduleGraph.get('/src/shared.ts')?.size).toBe(2);\n  });\n});\n"
  },
  {
    "path": "code/builders/builder-vite/src/utils/build-module-graph.ts",
    "content": "import type { ModuleGraph, ModuleNode } from 'storybook/internal/types';\n\nimport type { ViteDevServer, ModuleNode as ViteModuleNode } from 'vite';\n\nexport function buildModuleGraph(\n  fileToModulesMap: ViteDevServer['moduleGraph']['fileToModulesMap']\n): ModuleGraph {\n  const moduleGraph: ModuleGraph = new Map();\n  const moduleNodeMap = new WeakMap<object, ModuleNode>();\n  const getModuleFileFromMap = (viteModuleNode: {\n    file: string | null;\n    type: ViteModuleNode['type'];\n    importers: Set<ViteModuleNode>;\n    importedModules: Set<ViteModuleNode>;\n  }): string | undefined => {\n    for (const [filePath, viteModuleSet] of fileToModulesMap.entries()) {\n      if (viteModuleSet.has(viteModuleNode as ViteModuleNode)) {\n        return filePath;\n      }\n    }\n  };\n\n  const getOrCreateModuleNode = (\n    viteModuleNode: {\n      file: string | null;\n      type: ViteModuleNode['type'];\n      importers: Set<ViteModuleNode>;\n      importedModules: Set<ViteModuleNode>;\n    },\n    fallbackFile?: string\n  ): ModuleNode | undefined => {\n    const file = viteModuleNode.file ?? fallbackFile;\n    if (!file) {\n      return undefined;\n    }\n\n    const existingNode = moduleNodeMap.get(viteModuleNode);\n    if (existingNode) {\n      return existingNode;\n    }\n\n    const moduleNode: ModuleNode = {\n      file,\n      type: viteModuleNode.type,\n      importers: new Set(),\n      importedModules: new Set(),\n    };\n    moduleNodeMap.set(viteModuleNode, moduleNode);\n\n    const moduleSet = moduleGraph.get(file) ?? new Set<ModuleNode>();\n    moduleSet.add(moduleNode);\n    moduleGraph.set(file, moduleSet);\n\n    return moduleNode;\n  };\n\n  fileToModulesMap.forEach((viteModuleSet, filePath) => {\n    viteModuleSet.forEach((viteModuleNode) => {\n      const moduleNode = getOrCreateModuleNode(viteModuleNode, filePath);\n      if (moduleNode) {\n        viteModuleNode.importers.forEach((importer) => {\n          const importerNode =\n            getOrCreateModuleNode(importer) ??\n            getOrCreateModuleNode(importer, getModuleFileFromMap(importer));\n          if (importerNode) {\n            moduleNode.importers.add(importerNode);\n          }\n        });\n        viteModuleNode.importedModules.forEach((importedModule) => {\n          const importedModuleNode =\n            getOrCreateModuleNode(importedModule) ??\n            getOrCreateModuleNode(importedModule, getModuleFileFromMap(importedModule));\n          if (importedModuleNode) {\n            moduleNode.importedModules.add(importedModuleNode);\n          }\n        });\n      }\n    });\n  });\n\n  return moduleGraph;\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/utils/has-vite-plugins.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { hasVitePlugins } from './has-vite-plugins.ts';\n\ndescribe('hasVitePlugins', () => {\n  describe('should return true for', () => {\n    it('plugin in root', async () => {\n      const plugins = [{ name: 'vite-plugin-to-find' }, { name: 'vite-plugin-other' }];\n      const names = ['vite-plugin-to-find'];\n      expect(await hasVitePlugins(plugins, names)).toBeTruthy();\n    });\n    it('plugin in nested array', async () => {\n      const plugins = [[{ name: 'vite-plugin-to-find' }], { name: 'vite-plugin-other' }];\n      const names = ['vite-plugin-to-find'];\n      expect(await hasVitePlugins(plugins, names)).toBeTruthy();\n    });\n    it('plugin in nested async array', async () => {\n      const plugins = [\n        { name: 'vite-plugin-other' },\n        Promise.resolve([{ name: 'vite-plugin-to-find' }]),\n      ];\n      const names = ['vite-plugin-to-find'];\n      expect(await hasVitePlugins(plugins, names)).toBeTruthy();\n    });\n\n    it('async plugin in root', async () => {\n      const plugins = [\n        Promise.resolve({ name: 'vite-plugin-to-find' }),\n        { name: 'vite-plugin-other' },\n      ];\n      const names = ['vite-plugin-to-find'];\n      expect(await hasVitePlugins(plugins, names)).toBeTruthy();\n    });\n    it('async plugin in nested array', async () => {\n      const plugins = [\n        [Promise.resolve({ name: 'vite-plugin-to-find' })],\n        { name: 'vite-plugin-other' },\n      ];\n      const names = ['vite-plugin-to-find'];\n      expect(await hasVitePlugins(plugins, names)).toBeTruthy();\n    });\n    it('async plugin in nested async array', async () => {\n      const plugins = [\n        { name: 'vite-plugin-other' },\n        Promise.resolve([Promise.resolve({ name: 'vite-plugin-to-find' })]),\n      ];\n      const names = ['vite-plugin-to-find'];\n      expect(await hasVitePlugins(plugins, names)).toBeTruthy();\n    });\n    it('multiple plugins in root', async () => {\n      const plugins = [\n        { name: 'vite-plugin-other' },\n        { name: 'vite-plugin-to-find-first' },\n        { name: 'vite-plugin-to-find-second' },\n      ];\n      const names = ['vite-plugin-to-find-first', 'vite-plugin-to-find-second'];\n      expect(await hasVitePlugins(plugins, names)).toBeTruthy();\n    });\n  });\n  it('should return false with all types of plugin structures', async () => {\n    const plugins = [\n      { name: 'vite-plugin-root' },\n      [{ name: 'vite-plugin-in-nested-array' }],\n      Promise.resolve({ name: 'vite-plugin-async-root' }),\n      Promise.resolve([{ name: 'vite-plugin-in-nested-async-array' }]),\n      Promise.resolve([Promise.resolve({ name: 'vite-plugin-async-in-nested-async-array' })]),\n    ];\n    const names = ['vite-plugin-to-find-first', 'vite-plugin-to-find-second'];\n    expect(await hasVitePlugins(plugins, names)).toBeFalsy();\n  });\n});\n"
  },
  {
    "path": "code/builders/builder-vite/src/utils/has-vite-plugins.ts",
    "content": "import type { PluginOption } from 'vite';\n\nfunction checkName(plugin: PluginOption, names: string[]) {\n  return (\n    plugin !== null && typeof plugin === 'object' && 'name' in plugin && names.includes(plugin.name)\n  );\n}\n\n/**\n * Returns true if ANY of the plugins in the array have a name that matches one of the names in the\n * names array. Will resolve any promises in the array.\n */\nexport async function hasVitePlugins(plugins: PluginOption[], names: string[]) {\n  const resolvedPlugins = await Promise.all(plugins);\n\n  for (const plugin of resolvedPlugins) {\n    if (Array.isArray(plugin) && Boolean(await hasVitePlugins(plugin, names))) {\n      return true;\n    }\n    if (checkName(plugin, names)) {\n      return true;\n    }\n  }\n  return false;\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/utils/process-preview-annotation.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { onlyWindows, skipWindows } from '../../../../vitest.helpers.ts';\nimport { processPreviewAnnotation } from './process-preview-annotation.ts';\n\ndescribe('processPreviewAnnotation()', () => {\n  it('should pull the `absolute` value from an object', () => {\n    const annotation = {\n      bare: '@storybook/addon-links/preview',\n      absolute: '/Users/foo/storybook/node_modules/@storybook/addon-links/dist/preview.mjs',\n    };\n    const url = processPreviewAnnotation(annotation, '/Users/foo/storybook/');\n    expect(url).toBe('/Users/foo/storybook/node_modules/@storybook/addon-links/dist/preview.mjs');\n  });\n\n  it('should convert relative paths into absolute paths', () => {\n    const annotation = './src/stories/preview';\n    const url = processPreviewAnnotation(annotation, '/Users/foo/storybook/');\n    expect(url).toBe('/Users/foo/storybook/src/stories/preview');\n  });\n\n  it('should keep absolute filesystem paths', () => {\n    const annotation = '/Users/foo/storybook/.storybook/preview.js';\n    const url = processPreviewAnnotation(annotation, '/Users/foo/storybook/');\n    expect(url).toBe('/Users/foo/storybook/.storybook/preview.js');\n  });\n\n  it('should keep absolute node_modules paths', () => {\n    const annotation = '/Users/foo/storybook/node_modules/storybook-addon/preview';\n    const url = processPreviewAnnotation(annotation, '/Users/foo/storybook/');\n    expect(url).toBe('/Users/foo/storybook/node_modules/storybook-addon/preview');\n  });\n\n  it('should convert relative paths outside the root into absolute', () => {\n    const annotation = '../parent.js';\n    const url = processPreviewAnnotation(annotation, '/Users/foo/storybook/');\n    expect(url).toBe('/Users/foo/parent.js');\n  });\n\n  it('should not change absolute paths outside of the project root', () => {\n    const annotation = '/Users/foo/parent.js';\n    const url = processPreviewAnnotation(annotation, '/Users/foo/storybook/');\n    expect(url).toBe(annotation);\n  });\n\n  it('should keep absolute windows filesystem paths as is', () => {\n    const annotation = 'C:/foo/storybook/.storybook/preview.js';\n    const url = processPreviewAnnotation(annotation, 'C:/foo/storybook');\n    expect(url).toBe('C:/foo/storybook/.storybook/preview.js');\n  });\n  it('should convert relative paths outside the root into absolute on Windows', () => {\n    const annotation = '../parent.js';\n    const url = processPreviewAnnotation(annotation, 'C:/Users/foo/storybook/');\n    expect(url).toBe('C:/Users/foo/parent.js');\n  });\n\n  it('should not change Windows absolute paths outside of the project root', () => {\n    const annotation = 'D:/Users/foo/parent.js';\n    const url = processPreviewAnnotation(annotation, 'D:/Users/foo/storybook/');\n    expect(url).toBe(annotation);\n  });\n\n  it('should normalize absolute Windows paths using \\\\', () => {\n    const annotation = 'C:\\\\foo\\\\storybook\\\\.storybook\\\\preview.js';\n    const url = processPreviewAnnotation(annotation, 'C:\\\\foo\\\\storybook');\n    expect(url).toBe('C:/foo/storybook/.storybook/preview.js');\n  });\n\n  it('should normalize relative Windows paths using \\\\', () => {\n    const annotation = '.\\\\src\\\\stories\\\\preview';\n    const url = processPreviewAnnotation(annotation, 'C:\\\\foo\\\\storybook');\n    expect(url).toBe('C:/foo/storybook/src/stories/preview');\n  });\n});\n"
  },
  {
    "path": "code/builders/builder-vite/src/utils/process-preview-annotation.ts",
    "content": "import type { PreviewAnnotation } from 'storybook/internal/types';\n\nimport { isAbsolute, normalize, resolve } from 'pathe';\n\n/** Preview annotations can take several forms, so we normalize them here to absolute file paths. */\nexport function processPreviewAnnotation(path: PreviewAnnotation, projectRoot: string) {\n  // If entry is an object, take the absolute specifier.\n  // This absolute specifier is automatically made for addons here:\n  // https://github.com/storybookjs/storybook/blob/ac6e73b9d8ce31dd9acc80999c8d7c22a111f3cc/code/core/src/common/presets.ts#L161-L171\n  if (typeof path === 'object') {\n    // TODO: Remove this once the new version of Nuxt is released that removes this workaround:\n    // https://github.com/nuxt-modules/storybook/blob/a2eec6e898386f76c74826842e8e007b185c3d35/packages/storybook-addon/src/preset.ts#L279-L306\n    if (path.bare != null && path.absolute === '') {\n      return path.bare;\n    }\n    return normalize(path.absolute);\n  }\n\n  // If it's already an absolute path, return it.\n  if (isAbsolute(path)) {\n    return normalize(path);\n  }\n  // resolve relative paths, relative to project root\n  return normalize(resolve(projectRoot, path));\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/utils/unique-import-paths.ts",
    "content": "import type { StoryIndex } from 'storybook/internal/types';\n\n/** Takes the story index and returns an array of unique import paths. */\nexport function getUniqueImportPaths(index: StoryIndex): string[] {\n  return [...new Set(Object.values(index.entries).map((entry) => entry.importPath))];\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/utils/vite-features.ts",
    "content": "import type { UserConfig } from 'vite';\nimport { version } from 'vite';\n\n// TODO: Remove once support for Vite < 8 is dropped\nconst shouldUseRolldownOptions = () => {\n  try {\n    return Number(version.split('.')[0]) >= 8;\n  } catch {\n    return false;\n  }\n};\n\n/**\n * Returns the correct bundler options key based on the installed Vite version. Vite 8 renamed\n * `build.rollupOptions` to `build.rolldownOptions`.\n */\n// TODO: Remove once support for Vite < 8 is dropped, and use 'rolldownOptions' directly\nexport const bundlerOptionsKey = shouldUseRolldownOptions() ? 'rolldownOptions' : 'rollupOptions';\n\nexport function ensureRolldownOptions(config: UserConfig) {\n  if (!shouldUseRolldownOptions()) {\n    return;\n  }\n\n  config.build ??= {};\n  // @ts-expect-error - rolldownOptions will only exist with Vite 8+\n  const rolldown = (config.build.rolldownOptions ??= {});\n  const output = (rolldown.output ??= {});\n  output.strictExecutionOrder = true;\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/utils/without-vite-plugins.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { withoutVitePlugins } from './without-vite-plugins.ts';\n\ndescribe('withoutVitePlugins', () => {\n  describe('should remove', () => {\n    it('plugin in root', async () => {\n      const plugins = [{ name: 'vite-plugin-root-to-remove' }, { name: 'vite-plugin-root-keep' }];\n      const names = ['vite-plugin-root-to-remove'];\n\n      expect(await withoutVitePlugins(plugins, names)).toMatchInlineSnapshot(`\n        [\n          {\n            \"name\": \"vite-plugin-root-keep\",\n          },\n        ]\n      `);\n    });\n\n    it('plugin in nested array', async () => {\n      const plugins = [\n        [{ name: 'vite-plugin-nested-to-remove' }, { name: 'vite-plugin-nested-keep' }],\n        { name: 'vite-plugin-root-keep' },\n      ];\n      const names = ['vite-plugin-nested-to-remove'];\n\n      expect(await withoutVitePlugins(plugins, names)).toMatchInlineSnapshot(`\n        [\n          [\n            {\n              \"name\": \"vite-plugin-nested-keep\",\n            },\n          ],\n          {\n            \"name\": \"vite-plugin-root-keep\",\n          },\n        ]\n      `);\n    });\n\n    it('plugin in nested async array', async () => {\n      const plugins = [\n        Promise.resolve([\n          { name: 'vite-plugin-nested-async-to-remove' },\n          { name: 'vite-plugin-nested-async-keep' },\n        ]),\n      ];\n      const names = ['vite-plugin-nested-async-to-remove'];\n\n      expect(await withoutVitePlugins(plugins, names)).toMatchInlineSnapshot(`\n        [\n          [\n            {\n              \"name\": \"vite-plugin-nested-async-keep\",\n            },\n          ],\n        ]\n      `);\n    });\n\n    it('async plugin in root', async () => {\n      const plugins = [\n        Promise.resolve({ name: 'vite-plugin-async-root-to-remove' }),\n        Promise.resolve({ name: 'vite-plugin-async-root-keep' }),\n      ];\n      const names = ['vite-plugin-async-root-to-remove'];\n\n      expect(await withoutVitePlugins(plugins, names)).toMatchInlineSnapshot(`\n        [\n          {\n            \"name\": \"vite-plugin-async-root-keep\",\n          },\n        ]\n      `);\n    });\n\n    it('async plugin in nested array', async () => {\n      const plugins = [\n        [\n          Promise.resolve({ name: 'vite-plugin-async-nested-to-remove' }),\n          Promise.resolve({ name: 'vite-plugin-async-nested-keep' }),\n        ],\n        Promise.resolve({ name: 'vite-plugin-async-root-keep' }),\n      ];\n      const names = ['vite-plugin-async-nested-to-remove'];\n\n      expect(await withoutVitePlugins(plugins, names)).toMatchInlineSnapshot(`\n        [\n          [\n            {\n              \"name\": \"vite-plugin-async-nested-keep\",\n            },\n          ],\n          {\n            \"name\": \"vite-plugin-async-root-keep\",\n          },\n        ]\n      `);\n    });\n    it('async plugin in nested async array', async () => {\n      const plugins = [\n        Promise.resolve([\n          Promise.resolve({ name: 'vite-plugin-async-nested-async-to-remove' }),\n          Promise.resolve({ name: 'vite-plugin-async-nested-async-keep' }),\n        ]),\n      ];\n      const names = ['vite-plugin-async-nested-async-to-remove'];\n\n      expect(await withoutVitePlugins(plugins, names)).toMatchInlineSnapshot(`\n        [\n          [\n            {\n              \"name\": \"vite-plugin-async-nested-async-keep\",\n            },\n          ],\n        ]\n      `);\n    });\n\n    it('multiple plugins in root', async () => {\n      const plugins = [\n        { name: 'vite-plugin-root-first-to-remove' },\n        { name: 'vite-plugin-root-keep' },\n        { name: 'vite-plugin-root-second-to-remove' },\n      ];\n      const names = ['vite-plugin-root-first-to-remove', 'vite-plugin-root-second-to-remove'];\n\n      expect(await withoutVitePlugins(plugins, names)).toMatchInlineSnapshot(`\n        [\n          {\n            \"name\": \"vite-plugin-root-keep\",\n          },\n        ]\n      `);\n    });\n\n    it('multiple plugins in all cases', async () => {\n      const plugins = [\n        { name: 'vite-plugin-root-to-remove' },\n        Promise.resolve({ name: 'vite-plugin-async-root-to-remove' }),\n        [{ name: 'vite-plugin-nested-to-remove' }],\n        Promise.resolve([{ name: 'vite-plugin-async-nested-to-remove' }]),\n        [Promise.resolve({ name: 'vite-plugin-nested-async-to-remove' })],\n        Promise.resolve([Promise.resolve({ name: 'vite-plugin-async-nested-async-to-remove' })]),\n      ];\n      const names = [\n        'vite-plugin-root-to-remove',\n        'vite-plugin-async-root-to-remove',\n        'vite-plugin-nested-to-remove',\n        'vite-plugin-async-nested-to-remove',\n        'vite-plugin-nested-async-to-remove',\n        'vite-plugin-async-nested-async-to-remove',\n      ];\n\n      expect(await withoutVitePlugins(plugins, names)).toMatchInlineSnapshot(`\n        [\n          [],\n          [],\n          [],\n          [],\n        ]\n      `);\n    });\n  });\n\n  it('should no-op if plugins are not found', async () => {\n    const plugins = [\n      { name: 'vite-plugin-root' },\n      [{ name: 'vite-plugin-in-nested-array' }],\n      Promise.resolve({ name: 'vite-plugin-async-root' }),\n      Promise.resolve([{ name: 'vite-plugin-in-nested-async-array' }]),\n      Promise.resolve([Promise.resolve({ name: 'vite-plugin-async-in-nested-async-array' })]),\n    ];\n    const names = ['vite-plugin-to-remove-first', 'vite-plugin-to-remove-second'];\n\n    expect(await withoutVitePlugins(plugins, names)).toMatchInlineSnapshot(`\n      [\n        {\n          \"name\": \"vite-plugin-root\",\n        },\n        [\n          {\n            \"name\": \"vite-plugin-in-nested-array\",\n          },\n        ],\n        {\n          \"name\": \"vite-plugin-async-root\",\n        },\n        [\n          {\n            \"name\": \"vite-plugin-in-nested-async-array\",\n          },\n        ],\n        [\n          {\n            \"name\": \"vite-plugin-async-in-nested-async-array\",\n          },\n        ],\n      ]\n    `);\n  });\n});\n"
  },
  {
    "path": "code/builders/builder-vite/src/utils/without-vite-plugins.ts",
    "content": "/** Recursively removes all plugins with the names given Resolves async plugins */\nexport const withoutVitePlugins = async <TPlugin>(\n  plugins: TPlugin[] = [],\n  namesToRemove: string[]\n): Promise<TPlugin[]> => {\n  const result: TPlugin[] = [];\n  const resolvedPlugins = await Promise.all(plugins);\n\n  for (const plugin of resolvedPlugins) {\n    if (Array.isArray(plugin)) {\n      result.push(await (withoutVitePlugins(plugin, namesToRemove) as any));\n    } else if (\n      plugin &&\n      typeof plugin === 'object' &&\n      'name' in plugin &&\n      typeof plugin.name === 'string' &&\n      !namesToRemove.includes(plugin.name)\n    ) {\n      result.push(plugin);\n    }\n  }\n  return result;\n};\n"
  },
  {
    "path": "code/builders/builder-vite/src/virtual-file-names.ts",
    "content": "export const SB_VIRTUAL_FILES = {\n  VIRTUAL_APP_FILE: 'virtual:/@storybook/builder-vite/vite-app.js',\n  VIRTUAL_STORIES_FILE: 'virtual:/@storybook/builder-vite/storybook-stories.js',\n  VIRTUAL_ADDON_SETUP_FILE: 'virtual:/@storybook/builder-vite/setup-addons.js',\n};\n\nexport const SB_VIRTUAL_FILE_IDS = Object.values(SB_VIRTUAL_FILES);\n\nexport function getResolvedVirtualModuleId(virtualModuleId: string) {\n  return `\\0${virtualModuleId}`;\n}\n\nexport function getOriginalVirtualModuleId(resolvedVirtualModuleId: string) {\n  return resolvedVirtualModuleId.slice(1);\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/vite-config.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { Channel } from 'storybook/internal/channels';\nimport type { Options, Presets } from 'storybook/internal/types';\n\nimport { loadConfigFromFile } from 'vite';\n\nimport { storybookConfigPlugin } from './plugins/storybook-config-plugin.ts';\nimport { commonConfig } from './vite-config.ts';\n\nvi.mock('vite', async (importOriginal) => ({\n  ...(await importOriginal<typeof import('vite')>()),\n  loadConfigFromFile: vi.fn(async () => ({})),\n  defaultClientConditions: undefined,\n}));\nconst loadConfigFromFileMock = vi.mocked(loadConfigFromFile);\n\nconst dummyOptions: Options = {\n  configType: 'DEVELOPMENT',\n  configDir: '',\n  packageJson: {},\n  channel: new Channel({}),\n  presets: {\n    apply: async (key: string) =>\n      ({\n        framework: {\n          name: '',\n        },\n        addons: [],\n        core: {\n          builder: {},\n        },\n        options: {},\n      })[key],\n  } as Presets,\n  presetsList: [],\n};\n\ndescribe('commonConfig', () => {\n  it('should set configFile to false and include plugins', async () => {\n    loadConfigFromFileMock.mockReturnValueOnce(\n      Promise.resolve({\n        config: {},\n        path: '',\n        dependencies: [],\n      })\n    );\n    const config = await commonConfig(dummyOptions, 'development');\n    expect(config.configFile).toBe(false);\n    expect(config.plugins).toBeDefined();\n  });\n});\n\ndescribe('storybookConfigPlugin', () => {\n  it('should set default envPrefix when no user envPrefix is set', async () => {\n    const plugins = storybookConfigPlugin({ configDir: '/test/.storybook' });\n    const configPlugin = plugins.find((p) => p.name === 'storybook:config-plugin')!;\n\n    // The config hook receives the current Vite config and returns partial config to merge\n    const result = await (configPlugin.config as Function)({}, {});\n    expect(result.envPrefix).toStrictEqual(['VITE_', 'STORYBOOK_']);\n  });\n\n  it('should include storybook resolve conditions', async () => {\n    const plugins = storybookConfigPlugin({ configDir: '/test/.storybook' });\n    const configPlugin = plugins.find((p) => p.name === 'storybook:config-plugin')!;\n\n    const result = await (configPlugin.config as Function)({}, {});\n    expect(result.resolve.conditions).toContain('storybook');\n    expect(result.resolve.conditions).toContain('stories');\n    expect(result.resolve.conditions).toContain('test');\n  });\n\n  it('should not set base when not provided', async () => {\n    const plugins = storybookConfigPlugin({ configDir: '/test/.storybook' });\n    const configPlugin = plugins.find((p) => p.name === 'storybook:config-plugin')!;\n\n    const result = await (configPlugin.config as Function)({}, {});\n    expect(result.base).toBeUndefined();\n  });\n\n  it('should allow storybook dir when server fs allow list exists', () => {\n    const plugins = storybookConfigPlugin({ configDir: '/test/.storybook' });\n    const allowPlugin = plugins.find((p) => p.name === 'storybook:allow-storybook-dir')!;\n\n    const config = { server: { fs: { allow: ['/some/path'] } } };\n    (allowPlugin.config as Function)(config);\n    expect(config.server.fs.allow).toContain('/test/.storybook');\n  });\n});\n"
  },
  {
    "path": "code/builders/builder-vite/src/vite-config.ts",
    "content": "import { resolve } from 'node:path';\n\nimport { getBuilderOptions, resolvePathInStorybookCache } from 'storybook/internal/common';\nimport type { Options } from 'storybook/internal/types';\n\nimport type {\n  ConfigEnv,\n  InlineConfig,\n  PluginOption,\n  UserConfig as ViteConfig,\n  InlineConfig as ViteInlineConfig,\n} from 'vite';\n\nimport {\n  csfPlugin,\n  pluginWebpackStats,\n  storybookEntryPlugin,\n  storybookExternalGlobalsPlugin,\n} from './plugins/index.ts';\nimport { viteCorePlugins as corePlugins } from './preset.ts';\nimport type { BuilderOptions } from './types.ts';\n\nexport type PluginConfigType = 'build' | 'development';\n\nconst configEnvServe: ConfigEnv = {\n  mode: 'development',\n  command: 'serve',\n  isSsrBuild: false,\n};\n\nconst configEnvBuild: ConfigEnv = {\n  mode: 'production',\n  command: 'build',\n  isSsrBuild: false,\n};\n\n// Vite config that is common to development and production mode\nexport async function commonConfig(\n  options: Options,\n  _type: PluginConfigType\n): Promise<ViteInlineConfig> {\n  const configEnv = _type === 'development' ? configEnvServe : configEnvBuild;\n  const { loadConfigFromFile, mergeConfig } = await import('vite');\n\n  const { viteConfigPath } = await getBuilderOptions<BuilderOptions>(options);\n\n  const projectRoot = resolve(options.configDir, '..');\n\n  // I destructure away the `build` property from the user's config object\n  // I do this because I can contain config that breaks storybook, such as we had in a lit project.\n  // If the user needs to configure the `build` they need to do so in the viteFinal function in main.js.\n  const { config: { build: buildProperty = undefined, ...userConfig } = {} } =\n    (await loadConfigFromFile(configEnv, viteConfigPath, projectRoot)) ?? {};\n\n  // Storybook's Vite config is assembled from self-contained plugins.\n  // The config plugin handles base settings (root, cacheDir, resolve conditions, etc.),\n  // while other plugins handle entry points, docgen, and runtime globals.\n  // Shared vite plugins for mocking are defined in `./preset.ts` so that they can be\n  // shared between @storybook/builder-vite and @storybook/addon-vitest.\n  const sbConfig: InlineConfig = {\n    configFile: false,\n    plugins: await pluginConfig(options),\n    root: projectRoot,\n    // Allow storybook deployed as subfolder. See https://github.com/storybookjs/builder-vite/issues/238\n    base: './',\n    ...(options.cacheKey\n      ? { cacheDir: resolvePathInStorybookCache('sb-vite', options.cacheKey) }\n      : {}),\n    // Pass build.target option from user's vite config\n    build: {\n      target: buildProperty?.target,\n    },\n  };\n\n  const config: ViteConfig = mergeConfig(userConfig, sbConfig);\n\n  return config;\n}\n\nexport async function pluginConfig(options: Options) {\n  const plugins = [\n    // Shared core plugins (resolve conditions, envPrefix, fs.allow, externals, env vars, etc.)\n    ...(await corePlugins([], options)),\n    await storybookExternalGlobalsPlugin(options),\n    await csfPlugin(options),\n    // Entry plugin: virtual modules for stories, addon setup, and main app entry\n    ...(await storybookEntryPlugin(options)),\n    // Builder-specific: webpack-compatible stats for turbosnap/chromatic\n    pluginWebpackStats({ workingDir: process.cwd() }),\n  ] as PluginOption[];\n\n  return plugins;\n}\n"
  },
  {
    "path": "code/builders/builder-vite/src/vite-server.ts",
    "content": "import type { Options } from 'storybook/internal/types';\n\nimport type { Server } from 'http';\nimport type { InlineConfig, ServerOptions } from 'vite';\n\nimport { createViteLogger } from './logger.ts';\nimport { commonConfig } from './vite-config.ts';\n\nexport async function createViteServer(options: Options, devServer: Server) {\n  const { presets } = options;\n\n  const commonCfg = await commonConfig(options, 'development');\n\n  const { allowedHosts } = await presets.apply('core', {});\n\n  const config: InlineConfig & { server: ServerOptions } = {\n    ...commonCfg,\n    server: {\n      allowedHosts,\n      middlewareMode: true,\n      hmr: {\n        port: options.port,\n        server: devServer,\n      },\n      fs: {\n        strict: true,\n      },\n    },\n    appType: 'custom' as const,\n  };\n\n  // '0.0.0.0' binds to all interfaces, which is useful for Docker and other containerized environments\n  if (\n    options.host === '0.0.0.0' &&\n    (!allowedHosts || (Array.isArray(allowedHosts) && allowedHosts.length === 0))\n  ) {\n    config.server.allowedHosts = true;\n  }\n\n  const finalConfig = await presets.apply('viteFinal', config, options);\n\n  const { createServer } = await import('vite');\n\n  finalConfig.customLogger ??= await createViteLogger();\n  return createServer(finalConfig);\n}\n"
  },
  {
    "path": "code/builders/builder-vite/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/builders/builder-vite/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/builders/builder-webpack5/README.md",
    "content": "# Builder-Webpack5\n\nBuilder implemented with `webpack5` and `webpack5`-compatible loaders/plugins/config, used by `@storybook/core-server` to build the preview iframe.\n\n```js\nexport default {\n  core: {\n    builder: '@storybook/builder-webpack5',\n  },\n};\n```\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/builders/builder-webpack5/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    node: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./presets/custom-webpack-preset'],\n        entryPoint: './src/presets/custom-webpack-preset.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./presets/preview-preset'],\n        entryPoint: './src/presets/preview-preset.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./loaders/export-order-loader'],\n        entryPoint: './src/loaders/export-order-loader.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./loaders/storybook-mock-transform-loader'],\n        entryPoint: './src/loaders/storybook-mock-transform-loader.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./loaders/webpack-automock-loader'],\n        entryPoint: './src/loaders/webpack-automock-loader.ts',\n        dts: false,\n      },\n    ],\n  },\n  extraOutputs: {\n    './templates/virtualModuleModernEntry.js': './templates/virtualModuleModernEntry.js',\n    './templates/preview.ejs': './templates/preview.ejs',\n    './templates/virtualModuleEntry.template.js': './templates/virtualModuleEntry.template.js',\n    './templates/virtualModuleStory.template.js': './templates/virtualModuleStory.template.js',\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/builders/builder-webpack5/package.json",
    "content": "{\n  \"name\": \"@storybook/builder-webpack5\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"A Storybook builder to dev and build with Webpack\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-builder\",\n    \"webpack\",\n    \"builder\",\n    \"bundler\",\n    \"component\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/builders/builder-webpack5\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/builders/builder-webpack5\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./loaders/export-order-loader\": \"./dist/loaders/export-order-loader.js\",\n    \"./loaders/storybook-mock-transform-loader\": \"./dist/loaders/storybook-mock-transform-loader.js\",\n    \"./loaders/webpack-automock-loader\": \"./dist/loaders/webpack-automock-loader.js\",\n    \"./package.json\": \"./package.json\",\n    \"./presets/custom-webpack-preset\": \"./dist/presets/custom-webpack-preset.js\",\n    \"./presets/preview-preset\": \"./dist/presets/preview-preset.js\",\n    \"./templates/preview.ejs\": \"./templates/preview.ejs\",\n    \"./templates/virtualModuleEntry.template.js\": \"./templates/virtualModuleEntry.template.js\",\n    \"./templates/virtualModuleModernEntry.js\": \"./templates/virtualModuleModernEntry.js\",\n    \"./templates/virtualModuleStory.template.js\": \"./templates/virtualModuleStory.template.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"templates/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/core-webpack\": \"workspace:*\",\n    \"case-sensitive-paths-webpack-plugin\": \"^2.4.0\",\n    \"cjs-module-lexer\": \"^1.2.3\",\n    \"css-loader\": \"^7.1.2\",\n    \"es-module-lexer\": \"^1.5.0\",\n    \"fork-ts-checker-webpack-plugin\": \"^9.1.0\",\n    \"html-webpack-plugin\": \"^5.5.0\",\n    \"magic-string\": \"^0.30.5\",\n    \"style-loader\": \"^4.0.0\",\n    \"terser-webpack-plugin\": \"^5.3.17\",\n    \"ts-dedent\": \"^2.0.0\",\n    \"webpack\": \"5\",\n    \"webpack-dev-middleware\": \"^6.1.2\",\n    \"webpack-hot-middleware\": \"^2.25.1\",\n    \"webpack-virtual-modules\": \"^0.6.0\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.19.1\",\n    \"@types/pretty-hrtime\": \"^1.0.0\",\n    \"@types/webpack-hot-middleware\": \"^2.25.6\",\n    \"pretty-hrtime\": \"^1.0.3\",\n    \"sirv\": \"^2.0.4\",\n    \"slash\": \"^5.0.0\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"storybook\": \"workspace:^\"\n  },\n  \"peerDependenciesMeta\": {\n    \"typescript\": {\n      \"optional\": true\n    }\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/builders/builder-webpack5/project.json",
    "content": "{\n  \"name\": \"builder-webpack5\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/builders/builder-webpack5/src/index.ts",
    "content": "import { cp } from 'node:fs/promises';\nimport { fileURLToPath } from 'node:url';\n\nimport { PREVIEW_BUILDER_PROGRESS } from 'storybook/internal/core-events';\nimport { logger } from 'storybook/internal/node-logger';\nimport {\n  WebpackCompilationError,\n  WebpackInvocationError,\n  WebpackMissingStatsError,\n} from 'storybook/internal/server-errors';\nimport type { Builder, Options } from 'storybook/internal/types';\n\nimport { checkWebpackVersion } from '@storybook/core-webpack';\n\nimport { dirname, join, parse } from 'pathe';\nimport prettyTime from 'pretty-hrtime';\nimport sirv from 'sirv';\nimport type { Configuration, Stats, StatsOptions } from 'webpack';\nimport webpackModule from 'webpack';\nimport webpackDevMiddleware from 'webpack-dev-middleware';\nimport webpackHotMiddleware from 'webpack-hot-middleware';\n\nexport * from './types.ts';\nexport * from './preview/virtual-module-mapping.ts';\n\nconst { DefinePlugin, IgnorePlugin, ProgressPlugin } = webpackModule;\n\nexport const WebpackDefinePlugin = DefinePlugin;\nexport const WebpackIgnorePlugin = IgnorePlugin;\n\nexport const printDuration = (startTime: [number, number]) =>\n  prettyTime(process.hrtime(startTime))\n    .replace(' ms', ' milliseconds')\n    .replace(' s', ' seconds')\n    .replace(' min', ' minutes');\n\nconst corePath = dirname(fileURLToPath(import.meta.resolve('storybook/package.json')));\n\nlet compilation: ReturnType<typeof webpackDevMiddleware> | undefined;\nlet reject: (reason?: any) => void;\n\ntype WebpackBuilder = Builder<Configuration, Stats>;\ntype Unpromise<T extends Promise<any>> = T extends Promise<infer U> ? U : never;\n\ntype BuilderStartOptions = Parameters<WebpackBuilder['start']>['0'];\ntype BuilderStartResult = Unpromise<ReturnType<WebpackBuilder['start']>>;\ntype StarterFunction = (\n  options: BuilderStartOptions\n) => AsyncGenerator<unknown, BuilderStartResult, void>;\n\ntype BuilderBuildOptions = Parameters<WebpackBuilder['build']>['0'];\ntype BuilderBuildResult = Unpromise<ReturnType<WebpackBuilder['build']>>;\ntype BuilderFunction = (\n  options: BuilderBuildOptions\n) => AsyncGenerator<Stats | undefined, BuilderBuildResult, void>;\n\nexport const executor = {\n  get: async (options: Options) => {\n    const version = ((await options.presets.apply('webpackVersion')) || '5') as string;\n    const webpackInstance =\n      (await options.presets.apply<{ default: typeof webpackModule }>('webpackInstance'))\n        ?.default || webpackModule;\n    checkWebpackVersion({ version }, '5', 'builder-webpack5');\n    return webpackInstance;\n  },\n};\n\nexport const getConfig: WebpackBuilder['getConfig'] = async (options) => {\n  const { presets } = options;\n  const typescriptOptions = await presets.apply('typescript', {}, options);\n  const frameworkOptions = await presets.apply<any>('frameworkOptions');\n\n  return presets.apply(\n    'webpack',\n    {},\n    {\n      ...options,\n      typescriptOptions,\n      frameworkOptions,\n    }\n  ) as any;\n};\n\nlet asyncIterator: ReturnType<StarterFunction> | ReturnType<BuilderFunction>;\n\nexport const bail: WebpackBuilder['bail'] = async () => {\n  if (asyncIterator) {\n    try {\n      // we tell the builder (that started) to stop ASAP and wait\n      await asyncIterator.throw(new Error());\n    } catch (e) {\n      //\n    }\n  }\n\n  if (reject) {\n    reject();\n  }\n  // we wait for the compiler to finish it's work, so it's command-line output doesn't interfere\n  return new Promise((res, rej) => {\n    if (process && compilation) {\n      try {\n        compilation.close(() => res());\n        logger.warn('Force closed preview build');\n      } catch (err) {\n        logger.warn('Unable to close preview build!');\n        res();\n      }\n    } else {\n      res();\n    }\n  });\n};\n\n/**\n * This function is a generator so that we can abort it mid process in case of failure coming from\n * other processes e.g. preview builder\n *\n * I am sorry for making you read about generators today :')\n */\nconst starter: StarterFunction = async function* starterGeneratorFn({\n  startTime,\n  options,\n  router,\n  channel,\n}) {\n  const webpackInstance = await executor.get(options);\n  yield;\n\n  const config = await getConfig(options);\n\n  if (config.stats === 'none' || config.stats === 'summary') {\n    throw new WebpackMissingStatsError();\n  }\n  yield;\n\n  const compiler = webpackInstance(config);\n\n  if (!compiler) {\n    throw new WebpackInvocationError({\n      // eslint-disable-next-line local-rules/no-uncategorized-errors\n      error: new Error(`Missing Webpack compiler at runtime!`),\n    });\n  }\n\n  yield;\n  const modulesCount = await options.cache?.get('modulesCount', 1000);\n  let totalModules: number;\n  let value = 0;\n\n  new ProgressPlugin({\n    handler: (newValue, message, arg3) => {\n      value = Math.max(newValue, value); // never go backwards\n      const progress = { value, message: message.charAt(0).toUpperCase() + message.slice(1) };\n      if (message === 'building') {\n        // arg3 undefined in webpack5\n        const counts = (arg3 && arg3.match(/entries (\\d+)\\/(\\d+)/)) || [];\n        const complete = parseInt(counts[1], 10);\n        const total = parseInt(counts[2], 10);\n        if (!Number.isNaN(complete) && !Number.isNaN(total)) {\n          (progress as any).modules = { complete, total };\n          totalModules = total;\n        }\n      }\n\n      if (value === 1) {\n        if (options.cache) {\n          options.cache.set('modulesCount', totalModules);\n        }\n\n        if (!progress.message) {\n          progress.message = `Completed in ${printDuration(startTime)}.`;\n        }\n      }\n\n      channel.emit(PREVIEW_BUILDER_PROGRESS, progress);\n    },\n    modulesCount,\n  }).apply(compiler);\n\n  const middlewareOptions: Parameters<typeof webpackDevMiddleware>[1] = {\n    publicPath: config.output?.publicPath as string,\n    writeToDisk: true,\n    stats: 'errors-only',\n  };\n\n  compilation = webpackDevMiddleware(compiler, middlewareOptions);\n\n  const previewResolvedDir = join(corePath, 'dist/preview');\n  router.use(\n    '/sb-preview',\n    sirv(previewResolvedDir, {\n      maxAge: 300000,\n      dev: true,\n      immutable: true,\n    })\n  );\n\n  router.use(compilation);\n  router.use(webpackHotMiddleware(compiler, { log: false }));\n\n  const stats = await new Promise<Stats>((res, rej) => {\n    compilation?.waitUntilValid(res as any);\n    reject = rej;\n  });\n  yield;\n\n  if (!stats) {\n    throw new WebpackMissingStatsError();\n  }\n\n  const { warnings, errors } = getWebpackStats({ config, stats });\n\n  if (warnings.length > 0) {\n    warnings?.forEach((e) => logger.warn(e.message));\n  }\n\n  if (errors.length > 0) {\n    throw new WebpackCompilationError({ errors });\n  }\n\n  return {\n    bail,\n    stats,\n    totalTime: process.hrtime(startTime),\n  };\n};\n\nfunction getWebpackStats({ config, stats }: { config: Configuration; stats: Stats }) {\n  const statsOptions =\n    typeof config.stats === 'string'\n      ? config.stats\n      : {\n          ...(config.stats as StatsOptions),\n          warnings: true,\n          errors: true,\n        };\n  const { warnings = [], errors = [] } = stats?.toJson(statsOptions) || {};\n  return {\n    warnings,\n    errors,\n  };\n}\n\n/**\n * This function is a generator so that we can abort it mid process in case of failure coming from\n * other processes e.g. manager builder\n *\n * I am sorry for making you read about generators today :')\n */\nconst builder: BuilderFunction = async function* builderGeneratorFn({ startTime, options }) {\n  const webpackInstance = await executor.get(options);\n  yield;\n  const config = await getConfig(options);\n\n  if (config.stats === 'none' || config.stats === 'summary') {\n    throw new WebpackMissingStatsError();\n  }\n  yield;\n\n  const compiler = webpackInstance(config);\n\n  if (!compiler) {\n    throw new WebpackInvocationError({\n      // eslint-disable-next-line local-rules/no-uncategorized-errors\n      error: new Error(`Missing Webpack compiler at runtime!`),\n    });\n  }\n\n  const webpackCompilation = new Promise<Stats>((succeed, fail) => {\n    compiler.run((error, stats) => {\n      if (error) {\n        compiler.close(() => fail(new WebpackInvocationError({ error })));\n        return;\n      }\n\n      if (!stats) {\n        throw new WebpackMissingStatsError();\n      }\n\n      const { warnings, errors } = getWebpackStats({ config, stats });\n\n      if (warnings.length > 0) {\n        warnings?.forEach((e) => logger.warn(e.message));\n      }\n\n      if (errors.length > 0) {\n        errors.forEach((e) => logger.error(e.message));\n        compiler.close(() => fail(new WebpackCompilationError({ errors })));\n        return;\n      }\n\n      compiler.close((closeErr) => {\n        if (closeErr) {\n          return fail(new WebpackInvocationError({ error: closeErr }));\n        }\n\n        return succeed(stats as Stats);\n      });\n    });\n  });\n\n  const previewResolvedDir = join(corePath, 'dist/preview');\n  const previewDirTarget = join(options.outputDir || '', `sb-preview`);\n  const previewFiles = cp(previewResolvedDir, previewDirTarget, {\n    filter: (src) => {\n      const { ext } = parse(src);\n      if (ext) {\n        return ext === '.js';\n      }\n      return true;\n    },\n    recursive: true,\n  });\n\n  const [webpackCompilationOutput] = await Promise.all([webpackCompilation, previewFiles]);\n\n  return webpackCompilationOutput;\n};\n\nexport const start = async (options: BuilderStartOptions) => {\n  asyncIterator = starter(options);\n  let result;\n\n  do {\n    result = await asyncIterator.next();\n  } while (!result.done);\n\n  return result.value;\n};\n\nexport const build = async (options: BuilderStartOptions) => {\n  asyncIterator = builder(options);\n  let result;\n\n  do {\n    result = await asyncIterator.next();\n  } while (!result.done);\n\n  return result.value;\n};\n\nexport const corePresets = [\n  import.meta.resolve('@storybook/builder-webpack5/presets/preview-preset'),\n];\nexport const overridePresets = [\n  import.meta.resolve('@storybook/builder-webpack5/presets/custom-webpack-preset'),\n];\n"
  },
  {
    "path": "code/builders/builder-webpack5/src/loaders/export-order-loader.ts",
    "content": "import assert from 'node:assert';\n\nimport { init as initCjsParser, parse as parseCjs } from 'cjs-module-lexer';\nimport { parse as parseEs } from 'es-module-lexer';\nimport MagicString from 'magic-string';\nimport type { LoaderContext } from 'webpack';\n\nexport default async function loader(\n  this: LoaderContext<any>,\n  source: string,\n  map: any,\n  meta: any\n) {\n  const callback = this.async();\n\n  try {\n    const magicString = new MagicString(source);\n\n    // Trying to parse as ES module\n    if (!source.includes('__namedExportsOrder')) {\n      try {\n        // Do NOT remove await here. The types are wrong! It has to be awaited,\n        // otherwise it will return a Promise<Promise<...>> when wasm isn't loaded.\n        const parseResult = await parseEs(source);\n        const namedExportsOrder = (parseResult[1] || [])\n          .map((e) => source.substring(e.s, e.e))\n          .filter((e) => e !== 'default');\n\n        assert(\n          namedExportsOrder.length > 0,\n          'No named exports found. Very likely that this is not a ES module.'\n        );\n\n        magicString.append(\n          `;export const __namedExportsOrder = ${JSON.stringify(namedExportsOrder)};`\n        );\n\n        // Try to parse as CJS module\n      } catch {\n        await initCjsParser();\n        const namedExportsOrder = (parseCjs(source).exports || []).filter(\n          (e: string) => e !== 'default' && e !== '__esModule'\n        );\n\n        assert(\n          namedExportsOrder.length > 0,\n          'No named exports found. Very likely that this is not a CJS module.'\n        );\n\n        magicString.append(\n          `;module.exports.__namedExportsOrder = ${JSON.stringify(namedExportsOrder)};`\n        );\n      }\n    }\n\n    return callback(null, magicString.toString(), map, meta);\n  } catch (err) {\n    return callback(null, source, map, meta);\n  }\n}\n"
  },
  {
    "path": "code/builders/builder-webpack5/src/loaders/storybook-mock-transform-loader.ts",
    "content": "import { rewriteSbMockImportCalls } from 'storybook/internal/mocking-utils';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport type { LoaderDefinition } from 'webpack';\n\n/**\n * A Webpack loader that normalize sb.mock(import(...)) calls to sb.mock(...)\n *\n * @this The Webpack loader context.\n * @param source The original source code of the preview config file.\n */\nconst storybookMockTransformLoader: LoaderDefinition = function mockTransformLoaderFn(\n  source,\n  sourceMap,\n  meta\n) {\n  const callback = this.async();\n\n  try {\n    const result = rewriteSbMockImportCalls(source);\n    callback(null, result.code, result.map || undefined, meta);\n  } catch (error) {\n    const filePath = this.resourcePath;\n    logger.debug(`Could not transform sb.mock(import(...)) calls in ${filePath}: ${error}`);\n    callback(null, source, sourceMap, meta);\n  }\n};\n\nexport default storybookMockTransformLoader;\n"
  },
  {
    "path": "code/builders/builder-webpack5/src/loaders/webpack-automock-loader.ts",
    "content": "import { babelParser, getAutomockCode } from 'storybook/internal/mocking-utils';\n\nimport type { LoaderContext } from 'webpack';\n\n/** Defines the options that can be passed to the webpack-automock-loader. */\ninterface AutomockLoaderOptions {\n  /**\n   * If true, the module will be spied upon instead of fully mocked. This retains the original\n   * implementation while tracking calls.\n   */\n  spy: string;\n}\n\n/**\n * A Webpack loader that transforms a module's source code into an automocked version. It uses\n * `@vitest/mocker`'s `automockModule` function to replace all exports with mock implementations or\n * spies.\n *\n * This loader is intended to be used by `WebpackMockPlugin` when no `__mocks__` file is found for a\n * module specified in `sb.mock()`.\n *\n * @this {LoaderContext<AutomockLoaderOptions>} The Webpack loader context.\n * @param {string} source The original source code of the module.\n */\nexport default function webpackAutomockLoader(\n  this: LoaderContext<AutomockLoaderOptions>,\n  source: string\n) {\n  // Retrieve the options passed in the resource query string (e.g., `?spy=true`).\n  const options = this.getOptions();\n  const isSpy = options.spy === 'true';\n\n  // Generate the mocked source code using the utility from @vitest/mocker.\n  const mocked = getAutomockCode(source, isSpy, babelParser as any);\n\n  // Return the transformed code to Webpack for further processing.\n  return mocked.toString();\n}\n"
  },
  {
    "path": "code/builders/builder-webpack5/src/plugins/webpack-inject-mocker-runtime-plugin.ts",
    "content": "import { getMockerRuntime } from 'storybook/internal/mocking-utils';\n\n// HtmlWebpackPlugin is a standard part of Storybook's Webpack setup.\n// We can assume it's available as a dependency.\nimport type HtmlWebpackPlugin from 'html-webpack-plugin';\nimport type { Compiler } from 'webpack';\n\nconst PLUGIN_NAME = 'WebpackInjectMockerRuntimePlugin';\n\n/**\n * A Webpack plugin that injects the module mocker runtime script into the preview iframe's HTML.\n * This ensures the `sb` object is available globally before any other scripts, includiweng the\n * Storybook preview bundle, are executed.\n */\nexport class WebpackInjectMockerRuntimePlugin {\n  private cachedRuntime: string | null = null;\n  // We need to lazy-require HtmlWebpackPlugin because it's an optional peer dependency.\n  private getHtmlWebpackPlugin(compiler: Compiler): typeof HtmlWebpackPlugin | null {\n    try {\n      // It's better to get the constructor directly from the compiler's plugins\n      // to ensure we're using the same instance.\n      const constructor = compiler.options.plugins.find(\n        (p) => p?.constructor?.name === 'HtmlWebpackPlugin'\n      )?.constructor;\n\n      if (!constructor) {\n        return require('html-webpack-plugin');\n      }\n      return constructor as typeof HtmlWebpackPlugin;\n    } catch (e) {\n      compiler\n        .getInfrastructureLogger(PLUGIN_NAME)\n        .warn('html-webpack-plugin is not installed. Cannot inject mocker runtime.');\n      return null;\n    }\n  }\n\n  /**\n   * The main entry point for the Webpack plugin.\n   *\n   * @param {Compiler} compiler The Webpack compiler instance.\n   */\n  public apply(compiler: Compiler): void {\n    const HtmlWebpackPlugin = this.getHtmlWebpackPlugin(compiler);\n    if (!HtmlWebpackPlugin) {\n      return;\n    }\n\n    compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {\n      // Hook into HtmlWebpackPlugin's process to modify the generated HTML asset tags.\n      // The hook is static and should be available as soon as the compilation starts.\n      HtmlWebpackPlugin.getHooks(compilation).beforeAssetTagGeneration.tapAsync(\n        PLUGIN_NAME,\n        (data, cb) => {\n          try {\n            const runtimeScriptContent =\n              this.cachedRuntime ?? (this.cachedRuntime = getMockerRuntime());\n            const runtimeAssetName = 'mocker-runtime-injected.js';\n\n            // Use the documented `emitAsset` method to add the pre-bundled runtime script\n            // to the compilation's assets. This is the standard Webpack way.\n            if (!compilation.getAsset(runtimeAssetName)) {\n              compilation.emitAsset(\n                runtimeAssetName,\n                new compiler.webpack.sources.RawSource(runtimeScriptContent)\n              );\n              data.assets.js.unshift(runtimeAssetName);\n            }\n\n            // Prepend the name of our new asset to the list of JavaScript files, once.\n            // HtmlWebpackPlugin will automatically create a <script> tag for it\n            // and place it at the beginning of the body scripts.\n            cb(null, data);\n          } catch (error) {\n            // In case of an error (e.g., file not found), pass it to Webpack's compilation.\n            cb(error as Error);\n          }\n        }\n      );\n    });\n  }\n}\n"
  },
  {
    "path": "code/builders/builder-webpack5/src/plugins/webpack-mock-plugin.ts",
    "content": "import { dirname, isAbsolute } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport {\n  babelParser,\n  extractMockCalls,\n  findMockRedirect,\n  getIsExternal,\n  resolveExternalModule,\n  resolveWithExtensions,\n} from 'storybook/internal/mocking-utils';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport type { Compiler } from 'webpack';\n\n// --- Type Definitions ---\n\n/** Options for configuring the WebpackMockPlugin. */\nexport interface WebpackMockPluginOptions {\n  /**\n   * The absolute path to the preview configuration file (e.g., `.storybook/preview.ts`). This file\n   * will be scanned for `sb.mock()` calls.\n   */\n  previewConfigPath: string;\n}\n\n/** Represents a single `sb.mock()` call extracted directly from the AST. */\ninterface ExtractedMock {\n  /** The raw module path string from the mock call (e.g., '../utils/api'). */\n  path: string;\n  /** Whether the mock was configured with `{ spy: true }`. */\n  spy: boolean;\n}\n\n/** Represents a fully processed mock, with resolved paths and its replacement resource. */\ninterface ResolvedMock extends ExtractedMock {\n  /** The absolute resolved path of the module to be mocked. */\n  absolutePath: string;\n  /** The resource that Webpack will use to replace the original module. */\n  replacementResource: string;\n}\n\nconst PLUGIN_NAME = 'storybook-mock-plugin';\n\n/**\n * A Webpack plugin that enables module mocking for Storybook. It scans the preview config for\n * `sb.mock()` calls and uses Webpack's NormalModuleReplacementPlugin to substitute the original\n * modules with mocks.\n */\nexport class WebpackMockPlugin {\n  private readonly options: WebpackMockPluginOptions;\n  private mockMap: Map<string, ResolvedMock> = new Map();\n  private candidateSpecifiers: Set<string> = new Set();\n  private lastPreviewMtime: number | undefined;\n\n  constructor(options: WebpackMockPluginOptions) {\n    if (!options.previewConfigPath) {\n      throw new Error(`[${PLUGIN_NAME}] \\`previewConfigPath\\` is required.`);\n    }\n    this.options = options;\n  }\n\n  /**\n   * The main entry point for the Webpack plugin.\n   *\n   * @param {Compiler} compiler The Webpack compiler instance.\n   */\n  public apply(compiler: Compiler): void {\n    // This function will be called to update the mock map before each compilation.\n    const updateMocks = () => {\n      const mTimePreviewConfig = this.getPreviewConfigMtime(compiler);\n      if (\n        this.lastPreviewMtime &&\n        mTimePreviewConfig &&\n        mTimePreviewConfig <= this.lastPreviewMtime\n      ) {\n        return; // unchanged\n      }\n      const resolved = this.extractAndResolveMocks(compiler);\n      this.mockMap = new Map(\n        resolved.flatMap((mock) => [\n          [mock.absolutePath, mock],\n          [mock.absolutePath.replace(/\\.[^.]+$/, ''), mock],\n        ])\n      );\n      this.candidateSpecifiers = new Set(resolved.map((m) => m.path));\n      this.lastPreviewMtime = mTimePreviewConfig;\n\n      if (resolved.length > 0) {\n        logger.info(`Mock map updated with ${resolved.length} mocks.`);\n      }\n    };\n\n    compiler.hooks.beforeRun.tap(PLUGIN_NAME, updateMocks); // for build\n    compiler.hooks.watchRun.tap(PLUGIN_NAME, updateMocks); // for dev\n\n    // Apply the replacement plugin. Its callback will now use the dynamically updated mockMap.\n    new compiler.webpack.NormalModuleReplacementPlugin(/.*/, (resource) => {\n      try {\n        if (this.mockMap.size === 0) {\n          return;\n        }\n        const path = resource.request;\n        const importer = resource.context;\n\n        const isExternal = getIsExternal(path, importer);\n        // Early filter only for external specifiers. Relative/local specifiers need resolution\n        if (isExternal && !this.candidateSpecifiers.has(path)) {\n          return;\n        }\n        const absolutePath = isExternal\n          ? resolveExternalModule(path, importer)\n          : resolveWithExtensions(path, importer);\n\n        if (this.mockMap.has(absolutePath)) {\n          resource.request = this.mockMap.get(absolutePath)!.replacementResource;\n        }\n      } catch (e) {\n        logger.debug(`Could not resolve mock for \"${resource.request}\".`);\n      }\n    }).apply(compiler);\n\n    compiler.hooks.afterCompile.tap(PLUGIN_NAME, (compilation) => {\n      compilation.fileDependencies.add(this.options.previewConfigPath);\n\n      for (const mock of this.mockMap.values()) {\n        if (\n          isAbsolute(mock.replacementResource) &&\n          mock.replacementResource.includes('__mocks__')\n        ) {\n          compilation.contextDependencies.add(dirname(mock.replacementResource));\n        }\n      }\n    });\n  }\n\n  private getPreviewConfigMtime(compiler: Compiler): number | undefined {\n    try {\n      const fs = compiler.inputFileSystem as any;\n      const stat = fs.statSync?.(this.options.previewConfigPath);\n      return stat?.mtime?.getTime?.();\n    } catch {\n      return undefined;\n    }\n  }\n\n  /**\n   * Reads the preview config, parses it to find all `sb.mock()` calls, and resolves their\n   * corresponding mock implementations.\n   *\n   * @param {Compiler} compiler The Webpack compiler instance.\n   * @returns {ResolvedMock[]} An array of fully processed mocks.\n   */\n  private extractAndResolveMocks(compiler: Compiler): ResolvedMock[] {\n    const { previewConfigPath } = this.options;\n    const logger = compiler.getInfrastructureLogger(PLUGIN_NAME);\n\n    // Use extractMockCalls to get all mocks from the transformed preview file\n    const mocks = extractMockCalls(\n      { previewConfigPath, configDir: dirname(previewConfigPath) },\n      babelParser,\n      compiler.context,\n      findMockRedirect\n    );\n\n    // 2. Resolve each mock call to its absolute path and replacement resource.\n    const resolvedMocks: ResolvedMock[] = [];\n    for (const mock of mocks) {\n      try {\n        const { absolutePath, redirectPath } = mock;\n\n        let replacementResource: string;\n\n        if (redirectPath) {\n          // A `__mocks__` file exists. Use it directly as the replacement.\n          replacementResource = redirectPath;\n        } else {\n          // No `__mocks__` file found. Use our custom loader to automock the module.\n          const loaderPath = fileURLToPath(\n            import.meta.resolve('@storybook/builder-webpack5/loaders/webpack-automock-loader')\n          );\n          replacementResource = `${loaderPath}?spy=${mock.spy}!${absolutePath}`;\n        }\n\n        resolvedMocks.push({\n          ...mock,\n          replacementResource,\n        });\n      } catch (e) {\n        logger.warn(`Could not resolve mock for \"${mock.path}\". It will be ignored.`);\n      }\n    }\n\n    return resolvedMocks;\n  }\n}\n"
  },
  {
    "path": "code/builders/builder-webpack5/src/presets/custom-webpack-preset.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport { findConfigFile } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\nimport type { Options, PresetProperty } from 'storybook/internal/types';\n\nimport { loadCustomWebpackConfig } from '@storybook/core-webpack';\n\nimport webpackModule from 'webpack';\nimport type { Configuration } from 'webpack';\n\nimport { WebpackInjectMockerRuntimePlugin } from '../plugins/webpack-inject-mocker-runtime-plugin.ts';\nimport { WebpackMockPlugin } from '../plugins/webpack-mock-plugin.ts';\nimport { createDefaultWebpackConfig } from '../preview/base-webpack.config.ts';\n\nexport const swc: PresetProperty<'swc'> = (config: Record<string, any>): Record<string, any> => {\n  return {\n    ...config,\n    env: {\n      ...(config?.env ?? {}),\n      targets: config?.env?.targets ?? {\n        chrome: 100,\n        safari: 15,\n        firefox: 91,\n      },\n      // Transpiles the broken syntax to the closest non-broken modern syntax.\n      // E.g. it won't transpile parameter destructuring in Safari\n      // which would break how we detect if the mount context property is used in the play function.\n      bugfixes: config?.env?.bugfixes ?? true,\n    },\n  };\n};\n\nexport async function webpackFinal(config: Configuration, options: Options) {\n  const previewConfigPath = findConfigFile('preview', options.configDir);\n\n  // If there's no preview file, there's nothing to mock.\n  if (!previewConfigPath) {\n    return config;\n  }\n\n  config.plugins = config.plugins || [];\n\n  // 1. Add the loader to normalize sb.mock(import(...)) calls.\n  config.module!.rules!.push({\n    test: /preview\\.(t|j)sx?$/,\n    use: [\n      {\n        loader: fileURLToPath(\n          import.meta.resolve('@storybook/builder-webpack5/loaders/storybook-mock-transform-loader')\n        ),\n      },\n    ],\n  });\n\n  // 2. Add the plugin to handle module replacement based on sb.mock() calls.\n  // This plugin scans the preview file and sets up rules to swap modules.\n  config.plugins.push(new WebpackMockPlugin({ previewConfigPath }));\n\n  // 3. Add the plugin to inject the mocker runtime script into the HTML.\n  // This ensures the `sb` object is available before any other code runs.\n  config.plugins.push(new WebpackInjectMockerRuntimePlugin());\n  return config;\n}\n\nexport async function webpack(config: Configuration, options: Options) {\n  const { configDir, configType, presets } = options;\n\n  const coreOptions = await presets.apply('core');\n\n  let defaultConfig = config;\n  if (!coreOptions?.disableWebpackDefaults) {\n    defaultConfig = await createDefaultWebpackConfig(config, options);\n  }\n\n  const finalDefaultConfig = await presets.apply('webpackFinal', defaultConfig, options);\n\n  // Check whether user has a custom webpack config file and\n  // return the (extended) base configuration if it's not available.\n  const customConfig = await loadCustomWebpackConfig(configDir);\n\n  if (typeof customConfig === 'function') {\n    logger.info('Loading custom Webpack config (full-control mode).');\n    return customConfig({ config: finalDefaultConfig, mode: configType });\n  }\n\n  logger.info('Using default Webpack5 setup');\n  return finalDefaultConfig;\n}\n\nexport const webpackInstance = async () => webpackModule;\nexport const webpackVersion = async () => '5';\n"
  },
  {
    "path": "code/builders/builder-webpack5/src/presets/preview-preset.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport webpackConfig from '../preview/iframe-webpack.config.ts';\n\nexport const webpack = async (_: unknown, options: any) => webpackConfig(options);\n\nexport const entries = async (_: unknown, options: any) => {\n  let result: string[] = [];\n\n  if (options.configType === 'DEVELOPMENT') {\n    // Suppress informational messages when --quiet is specified. webpack-hot-middleware's quiet\n    // parameter would also suppress warnings.\n    result = result.concat(\n      `${fileURLToPath(\n        import.meta.resolve('webpack-hot-middleware/client.js')\n      )}?reload=true&quiet=false&overlay=${JSON.stringify({\n        errors: true,\n        warnings: false,\n        runtimeErrors: false,\n      })}&noInfo=${options.quiet}`\n    );\n  }\n\n  return result;\n};\n\nexport const previewMainTemplate = () =>\n  fileURLToPath(import.meta.resolve('@storybook/builder-webpack5/templates/preview.ejs'));\n"
  },
  {
    "path": "code/builders/builder-webpack5/src/preview/base-webpack.config.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport { logger } from 'storybook/internal/node-logger';\nimport type { Options } from 'storybook/internal/types';\n\nimport type { Configuration } from 'webpack';\n\nexport async function createDefaultWebpackConfig(\n  storybookBaseConfig: Configuration,\n  options: Options\n): Promise<Configuration> {\n  if (\n    options.presetsList?.some((preset) =>\n      /@storybook(\\/|\\\\)preset-create-react-app/.test(\n        typeof preset === 'string' ? preset : preset.name\n      )\n    )\n  ) {\n    return storybookBaseConfig;\n  }\n\n  const hasPostcssAddon = options.presetsList?.some((preset) =>\n    /@storybook(\\/|\\\\)addon-postcss/.test(typeof preset === 'string' ? preset : preset.name)\n  );\n\n  let cssLoaders = {};\n  if (!hasPostcssAddon) {\n    logger.info(`Using implicit CSS loaders`);\n    cssLoaders = {\n      test: /\\.css$/,\n      sideEffects: true,\n      use: [\n        // TODO: Decide if we want to keep style-loader & css-loader in core\n        // Trying to apply style-loader or css-loader to files that already have been\n        // processed by them causes webpack to crash, so no one else can add similar\n        // loader configurations to the `.css` extension.\n        fileURLToPath(import.meta.resolve('style-loader')),\n        {\n          loader: fileURLToPath(import.meta.resolve('css-loader')),\n          options: {\n            importLoaders: 1,\n          },\n        },\n      ],\n    };\n  }\n\n  const isProd = storybookBaseConfig.mode !== 'development';\n\n  return {\n    ...storybookBaseConfig,\n    // TODO: Implement the clearing functionality of StyledConsoleLogger so that we can use it for webpack\n    // The issue currently is that the status line is not cleared when the webpack compiler is run,\n    // which causes the status line to be printed multiple times.\n    // infrastructureLogging: {\n    //   console: new StyledConsoleLogger({ prefix: 'Webpack', color: 'bgBlue' }),\n    // },\n    module: {\n      ...storybookBaseConfig.module,\n      rules: [\n        ...(storybookBaseConfig.module?.rules || []),\n        cssLoaders,\n        {\n          test: /\\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\\?.*)?$/,\n          type: 'asset/resource',\n          generator: {\n            filename: isProd\n              ? 'static/media/[name].[contenthash:8][ext]'\n              : 'static/media/[path][name][ext]',\n          },\n        },\n        {\n          test: /\\.(mp4|webm|wav|mp3|m4a|aac|oga)(\\?.*)?$/,\n          type: 'asset',\n          parser: {\n            dataUrlCondition: {\n              maxSize: 10000,\n            },\n          },\n          generator: {\n            filename: isProd\n              ? 'static/media/[name].[contenthash:8][ext]'\n              : 'static/media/[path][name][ext]',\n          },\n        },\n        {\n          // any imports from './some-file.md?raw' will be imported as raw string\n          // see https://webpack.js.org/guides/asset-modules/#replacing-inline-loader-syntax\n          // used to support import raw .md files in MDX\n          resourceQuery: /raw/,\n          type: 'asset/source',\n        },\n      ],\n    },\n    resolve: {\n      ...storybookBaseConfig.resolve,\n      // see https://github.com/webpack/webpack/issues/17692#issuecomment-1866272674 for the docs\n      conditionNames: [\n        ...(storybookBaseConfig.resolve?.conditionNames ?? []),\n        'storybook',\n        'stories',\n        'test',\n        '...',\n      ],\n      fallback: {\n        crypto: false,\n        assert: false,\n        ...storybookBaseConfig.resolve?.fallback,\n      },\n    },\n  };\n}\n"
  },
  {
    "path": "code/builders/builder-webpack5/src/preview/iframe-webpack.config.ts",
    "content": "import { join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport {\n  getBuilderOptions,\n  isPreservingSymlinks,\n  normalizeStories,\n  stringifyProcessEnvs,\n} from 'storybook/internal/common';\nimport { globalsNameReferenceMap } from 'storybook/internal/preview/globals';\nimport type { Options } from 'storybook/internal/types';\n\nimport { type BuilderOptions } from '@storybook/core-webpack';\n\n// @ts-expect-error (I removed this on purpose, because it's incorrect)\nimport CaseSensitivePathsPlugin from 'case-sensitive-paths-webpack-plugin';\nimport type { TransformOptions as EsbuildOptions } from 'esbuild';\nimport ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';\nimport HtmlWebpackPlugin from 'html-webpack-plugin';\nimport TerserWebpackPlugin from 'terser-webpack-plugin';\nimport { dedent } from 'ts-dedent';\nimport webpackModule from 'webpack';\nimport type { Configuration } from 'webpack';\nimport VirtualModulePlugin from 'webpack-virtual-modules';\n\nimport type { TypescriptOptions } from '../types.ts';\nimport { getVirtualModules } from './virtual-module-mapping.ts';\n\nconst { DefinePlugin, HotModuleReplacementPlugin, ProgressPlugin } = webpackModule;\n\nexport default async (\n  options: Options & { typescriptOptions: TypescriptOptions }\n): Promise<Configuration> => {\n  const {\n    outputDir = join('.', 'public'),\n    quiet,\n    packageJson,\n    configType,\n    presets,\n    previewUrl,\n    typescriptOptions,\n    features,\n  } = options;\n\n  const isProd = configType === 'PRODUCTION';\n  const workingDir = process.cwd();\n\n  const [\n    coreOptions,\n    frameworkOptions,\n    envs,\n    logLevel,\n    headHtmlSnippet,\n    bodyHtmlSnippet,\n    template,\n    docsOptions,\n    entries,\n    nonNormalizedStories,\n    modulesCount,\n    build,\n    tagsOptions,\n  ] = await Promise.all([\n    presets.apply('core'),\n    presets.apply('frameworkOptions'),\n    presets.apply<Record<string, string>>('env'),\n    presets.apply('logLevel', undefined),\n    presets.apply('previewHead'),\n    presets.apply('previewBody'),\n    presets.apply<string>('previewMainTemplate'),\n    presets.apply('docs'),\n    presets.apply<string[]>('entries', []),\n    presets.apply('stories', []),\n    options.cache?.get('modulesCount', 1000),\n    options.presets.apply('build'),\n    presets.apply('tags', {}),\n  ]);\n\n  const stories = normalizeStories(nonNormalizedStories, {\n    configDir: options.configDir,\n    workingDir,\n  });\n\n  const builderOptions = await getBuilderOptions<BuilderOptions>(options);\n\n  const shouldCheckTs = typescriptOptions.check && !typescriptOptions.skipCompiler;\n  const tsCheckOptions = typescriptOptions.checkOptions || {};\n\n  const cacheConfig = builderOptions.fsCache ? { cache: { type: 'filesystem' as const } } : {};\n  const lazyCompilationConfig =\n    builderOptions.lazyCompilation && !isProd\n      ? {\n          lazyCompilation: { entries: false },\n        }\n      : {};\n\n  if (!template) {\n    throw new Error(dedent`\n      Storybook's Webpack5 builder requires a template to be specified.\n      Somehow you've ended up with a falsy value for the template option.\n\n      Please file an issue at https://github.com/storybookjs/storybook with a reproduction.\n    `);\n  }\n\n  const externals: Record<string, string> = globalsNameReferenceMap;\n  if (build?.test?.disableBlocks) {\n    externals['@storybook/addon-docs/blocks'] = '__STORYBOOK_BLOCKS_EMPTY_MODULE__';\n  }\n\n  const { virtualModules: virtualModuleMapping, entries: dynamicEntries } =\n    await getVirtualModules(options);\n\n  return {\n    name: 'preview',\n    mode: isProd ? 'production' : 'development',\n    bail: isProd,\n    devtool: options.build?.test?.disableSourcemaps ? false : 'cheap-module-source-map',\n    entry: [...(entries ?? []), ...dynamicEntries],\n    output: {\n      path: resolve(process.cwd(), outputDir),\n      filename: isProd ? '[name].[contenthash:8].iframe.bundle.js' : '[name].iframe.bundle.js',\n      publicPath: '',\n    },\n    stats: {\n      preset: 'none',\n      logging: 'error',\n    },\n    watchOptions: {\n      ignored: /node_modules/,\n    },\n    externals,\n    ignoreWarnings: [\n      {\n        message: /export '\\S+' was not found in 'global'/,\n      },\n      {\n        message: /export '\\S+' was not found in '@storybook\\/global'/,\n      },\n    ],\n    plugins: [\n      Object.keys(virtualModuleMapping).length > 0\n        ? new VirtualModulePlugin(virtualModuleMapping)\n        : (null as any),\n      new HtmlWebpackPlugin({\n        filename: `iframe.html`,\n        // FIXME: `none` isn't a known option\n        chunksSortMode: 'none' as any,\n        alwaysWriteToDisk: true,\n        inject: false,\n        template,\n        templateParameters: {\n          version: packageJson?.version,\n          globals: {\n            CONFIG_TYPE: configType,\n            LOGLEVEL: logLevel,\n            FRAMEWORK_OPTIONS: frameworkOptions,\n            CHANNEL_OPTIONS: coreOptions.channelOptions,\n            FEATURES: features,\n            PREVIEW_URL: previewUrl,\n            STORIES: stories.map((specifier) => ({\n              ...specifier,\n              importPathMatcher: specifier.importPathMatcher.source,\n            })),\n            DOCS_OPTIONS: docsOptions,\n            TAGS_OPTIONS: tagsOptions,\n            ...(build?.test?.disableBlocks ? { __STORYBOOK_BLOCKS_EMPTY_MODULE__: {} } : {}),\n          },\n          headHtmlSnippet,\n          bodyHtmlSnippet,\n        },\n        minify: {\n          collapseWhitespace: true,\n          removeComments: true,\n          removeRedundantAttributes: true,\n          removeScriptTypeAttributes: false,\n          removeStyleLinkTypeAttributes: true,\n          useShortDoctype: true,\n        },\n      }),\n      new DefinePlugin({\n        'process.env': `(${JSON.stringify(envs)})`,\n        ...stringifyProcessEnvs(envs),\n        NODE_ENV: JSON.stringify(\n          features?.developmentModeForBuild && isProd ? 'development' : process.env.NODE_ENV\n        ),\n      }),\n      isProd ? null : new HotModuleReplacementPlugin(),\n      new CaseSensitivePathsPlugin(),\n      quiet ? null : new ProgressPlugin({ modulesCount }),\n      shouldCheckTs ? new ForkTsCheckerWebpackPlugin(tsCheckOptions) : null,\n    ].filter(Boolean),\n    module: {\n      // Disable warning for dynamic requires\n      unknownContextCritical: false,\n      rules: [\n        {\n          test: /\\.stories\\.([tj])sx?$|(stories|story)\\.mdx$/,\n          exclude: /node_modules/,\n          enforce: 'post',\n          use: [\n            {\n              loader: fileURLToPath(\n                import.meta.resolve('@storybook/builder-webpack5/loaders/export-order-loader')\n              ),\n            },\n          ],\n        },\n        {\n          test: /\\.m?js$/,\n          type: 'javascript/auto',\n        },\n        {\n          test: /\\.m?js$/,\n          resolve: {\n            fullySpecified: false,\n          },\n        },\n        {\n          test: /\\.md$/,\n          type: 'asset/source',\n        },\n      ],\n    },\n    resolve: {\n      extensions: ['.mjs', '.js', '.jsx', '.ts', '.tsx', '.json', '.cjs'],\n      modules: ['node_modules'].concat(envs.NODE_PATH || []),\n      mainFields: ['browser', 'module', 'main'].filter(Boolean),\n      // Set webpack to resolve symlinks based on whether the user has asked node to.\n      // This feels like it should be default out-of-the-box in webpack :shrug:\n      symlinks: !isPreservingSymlinks(),\n    },\n    optimization: {\n      splitChunks: {\n        chunks: 'all',\n      },\n      runtimeChunk: true,\n      sideEffects: true,\n      usedExports: options.build?.test?.disableTreeShaking ? false : isProd,\n      moduleIds: 'named',\n      ...(isProd\n        ? {\n            minimize: true,\n            minimizer: options.build?.test?.esbuildMinify\n              ? [\n                  new TerserWebpackPlugin<EsbuildOptions>({\n                    parallel: true,\n                    minify: TerserWebpackPlugin.esbuildMinify,\n                    terserOptions: {\n                      sourcemap: !options.build?.test?.disableSourcemaps,\n                      treeShaking: !options.build?.test?.disableTreeShaking,\n                    },\n                  }),\n                ]\n              : [\n                  new TerserWebpackPlugin({\n                    parallel: true,\n                    terserOptions: {\n                      sourceMap: !options.build?.test?.disableSourcemaps,\n                      mangle: false,\n                      keep_fnames: true,\n                    },\n                  }),\n                ],\n          }\n        : {}),\n    },\n    performance: {\n      hints: isProd ? 'warning' : false,\n    },\n    ...cacheConfig,\n    experiments: { ...lazyCompilationConfig },\n  };\n};\n"
  },
  {
    "path": "code/builders/builder-webpack5/src/preview/virtual-module-mapping.ts",
    "content": "import { join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport {\n  getBuilderOptions,\n  loadPreviewOrConfigFile,\n  normalizeStories,\n  readTemplate,\n} from 'storybook/internal/common';\nimport type { Options, PreviewAnnotation } from 'storybook/internal/types';\n\nimport { toImportFn } from '@storybook/core-webpack';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\n\nimport type { BuilderOptions } from '../types.ts';\n\nexport const getVirtualModules = async (options: Options) => {\n  const virtualModules: Record<string, string> = {};\n  const builderOptions = await getBuilderOptions<BuilderOptions>(options);\n  const workingDir = process.cwd();\n  const isProd = options.configType === 'PRODUCTION';\n  const nonNormalizedStories = await options.presets.apply('stories', []);\n  const entries = [];\n\n  const stories = normalizeStories(nonNormalizedStories, {\n    configDir: options.configDir,\n    workingDir,\n  });\n\n  const previewAnnotations = [\n    ...(await options.presets.apply<PreviewAnnotation[]>('previewAnnotations', [], options)).map(\n      (entry) => {\n        // If entry is an object, use the absolute import specifier.\n        // This is to maintain back-compat with community addons that bundle other addons\n        // and package managers that \"hide\" sub dependencies (e.g. pnpm / yarn pnp)\n        if (typeof entry === 'object') {\n          return entry.absolute;\n        }\n\n        return slash(entry);\n      }\n    ),\n    loadPreviewOrConfigFile(options),\n  ].filter(Boolean);\n\n  const storiesFilename = 'storybook-stories.js';\n  const storiesPath = resolve(join(workingDir, storiesFilename));\n\n  const needPipelinedImport = !!builderOptions.lazyCompilation && !isProd;\n  virtualModules[storiesPath] = toImportFn(stories, { needPipelinedImport });\n  const configEntryPath = resolve(join(workingDir, 'storybook-config-entry.js'));\n  virtualModules[configEntryPath] = (\n    await readTemplate(\n      fileURLToPath(\n        import.meta.resolve('@storybook/builder-webpack5/templates/virtualModuleModernEntry.js')\n      )\n    )\n  )\n    .replaceAll(`'{{storiesFilename}}'`, `'./${storiesFilename}'`)\n    .replaceAll(\n      `'{{previewAnnotations}}'`,\n      previewAnnotations\n        .filter(Boolean)\n        .map((entry) => `'${entry}'`)\n        .join(',')\n    )\n    .replaceAll(\n      `'{{previewAnnotations_requires}}'`,\n      previewAnnotations\n        .filter(Boolean)\n        .map((entry) => `require('${entry}')`)\n        .join(',')\n    )\n    // We need to double escape `\\` for webpack. We may have some in windows paths\n    .replace(/\\\\/g, '\\\\\\\\');\n  entries.push(configEntryPath);\n\n  return {\n    virtualModules,\n    entries,\n  };\n};\n"
  },
  {
    "path": "code/builders/builder-webpack5/src/types.ts",
    "content": "import type {\n  BuilderResult as BuilderResultBase,\n  Options,\n  StorybookConfig,\n  TypescriptOptions as WebpackTypescriptOptions,\n} from '@storybook/core-webpack';\n\nimport type ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';\nimport type { Configuration, Stats } from 'webpack';\n\ntype TypeScriptOptionsBase = Partial<WebpackTypescriptOptions>;\n\n/** Options for TypeScript usage within Storybook. */\nexport interface TypescriptOptions extends TypeScriptOptionsBase {\n  /** Configures `fork-ts-checker-webpack-plugin` */\n  checkOptions?: ConstructorParameters<typeof ForkTsCheckerWebpackPlugin>[0];\n}\n\nexport interface StorybookConfigWebpack extends Omit<\n  StorybookConfig,\n  'webpack' | 'webpackFinal' | 'features'\n> {\n  /**\n   * Modify or return a custom Webpack config after the Storybook's default configuration has run\n   * (mostly used by addons).\n   */\n  webpack?: (config: Configuration, options: Options) => Configuration | Promise<Configuration>;\n\n  /** Modify or return a custom Webpack config after every addon has run. */\n  webpackFinal?: (\n    config: Configuration,\n    options: Options\n  ) => Configuration | Promise<Configuration>;\n\n  features?: StorybookConfig['features'] & {\n    /**\n     * Enable the experimental `.test` function in CSF Next\n     *\n     * @see https://storybook.js.org/docs/api/main-config/main-config-features#experimentaltestsyntax\n     */\n    experimentalTestSyntax?: boolean;\n  };\n}\n\nexport type BuilderOptions = {\n  fsCache?: boolean;\n  lazyCompilation?: boolean;\n};\n\nexport interface BuilderResult extends BuilderResultBase {\n  stats?: Stats;\n}\n"
  },
  {
    "path": "code/builders/builder-webpack5/templates/preview.ejs",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title><%= htmlWebpackPlugin.options.title || 'Storybook'%></title>\n\n    <% if (htmlWebpackPlugin.files.favicon) { %>\n    <link rel=\"shortcut icon\" href=\"<%= htmlWebpackPlugin.files.favicon%>\" />\n    <% } %>\n\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\n    <style>\n      @font-face {\n        font-family: 'Nunito Sans';\n        font-style: normal;\n        font-weight: 400;\n        font-display: swap;\n        src: url('./sb-common-assets/nunito-sans-regular.woff2') format('woff2');\n      }\n\n      @font-face {\n        font-family: 'Nunito Sans';\n        font-style: italic;\n        font-weight: 400;\n        font-display: swap;\n        src: url('./sb-common-assets/nunito-sans-italic.woff2') format('woff2');\n      }\n\n      @font-face {\n        font-family: 'Nunito Sans';\n        font-style: normal;\n        font-weight: 700;\n        font-display: swap;\n        src: url('./sb-common-assets/nunito-sans-bold.woff2') format('woff2');\n      }\n\n      @font-face {\n        font-family: 'Nunito Sans';\n        font-style: italic;\n        font-weight: 700;\n        font-display: swap;\n        src: url('./sb-common-assets/nunito-sans-bold-italic.woff2') format('woff2');\n      }\n    </style>\n  \n    <% if (typeof headHtmlSnippet !== 'undefined') { %> <%= headHtmlSnippet %> <% } %> <%\n    htmlWebpackPlugin.files.css.forEach(file => { %>\n    <link href=\"<%= file %>\" rel=\"stylesheet\" />\n    <% }); %>\n\n    <style>\n      #storybook-root[hidden],\n      #storybook-docs[hidden] {\n        display: none !important;\n      }\n    </style>\n  </head>\n  <body>\n    <% if (typeof bodyHtmlSnippet !== 'undefined') { %> <%= bodyHtmlSnippet %> <% } %>\n\n    <div id=\"storybook-root\"></div>\n    <div id=\"storybook-docs\"></div>\n\n    <% if (typeof globals !== 'undefined' && Object.keys(globals).length) { %>\n    <script>\n      <% for (var varName in globals) { %>\n          <% if (globals[varName] != undefined) { %>\n            window['<%=varName%>'] = <%= JSON.stringify(globals[varName]) %>;\n          <% } %>\n      <% } %>\n    </script>\n    <% } %>\n    <script type=\"module\">\n      import './sb-preview/runtime.js';\n\n      <% htmlWebpackPlugin.files.js.forEach(file => { %>\n      import './<%= file %>';\n      <% }); %>\n    </script>    \n  </body>\n</html>\n"
  },
  {
    "path": "code/builders/builder-webpack5/templates/virtualModuleModernEntry.js",
    "content": "import { createBrowserChannel } from 'storybook/internal/channels';\nimport { STORY_HOT_UPDATED } from 'storybook/internal/core-events';\nimport { isPreview } from 'storybook/internal/csf';\n\nimport { global } from '@storybook/global';\n\nimport { PreviewWeb, addons, composeConfigs } from 'storybook/preview-api';\nimport { importFn } from '{{storiesFilename}}';\n\nconst getProjectAnnotations = () => {\n  const previewAnnotations = ['{{previewAnnotations_requires}}'];\n  // the last one in this array is the user preview\n  const userPreview = previewAnnotations[previewAnnotations.length - 1]?.default;\n\n  if (isPreview(userPreview)) {\n    return userPreview.composed;\n  }\n\n  return composeConfigs(previewAnnotations);\n};\n\nconst channel = createBrowserChannel({ page: 'preview' });\naddons.setChannel(channel);\n\nif (global.CONFIG_TYPE === 'DEVELOPMENT') {\n  window.__STORYBOOK_SERVER_CHANNEL__ = channel;\n}\n\nconst preview = new PreviewWeb(importFn, getProjectAnnotations);\n\nwindow.__STORYBOOK_PREVIEW__ = preview;\nwindow.__STORYBOOK_STORY_STORE__ = preview.storyStore;\nwindow.__STORYBOOK_ADDONS_CHANNEL__ = channel;\n\nif (import.meta.webpackHot) {\n  import.meta.webpackHot.addStatusHandler((status) => {\n    if (status === 'idle') {\n      preview.channel.emit(STORY_HOT_UPDATED);\n    }\n  });\n\n  import.meta.webpackHot.accept('{{storiesFilename}}', () => {\n    // importFn has changed so we need to patch the new one in\n    preview.onStoriesChanged({ importFn });\n  });\n\n  import.meta.webpackHot.accept(['{{previewAnnotations}}'], () => {\n    // getProjectAnnotations has changed so we need to patch the new one in\n    preview.onGetProjectAnnotationsChanged({ getProjectAnnotations });\n  });\n}\n"
  },
  {
    "path": "code/builders/builder-webpack5/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/builders/builder-webpack5/typings.d.ts",
    "content": "declare module 'lazy-universal-dotenv';\n"
  },
  {
    "path": "code/builders/builder-webpack5/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/chromatic.config.json",
    "content": "{\n  \"$schema\": \"https://www.chromatic.com/config-file.schema.json\",\n  \"buildScriptName\": \"storybook:ui:build\",\n  \"onlyChanged\": true,\n  \"projectId\": \"Project:635781f3500dd2c49e189caf\",\n  \"projectToken\": \"80b312430ec4\",\n  \"storybookBaseDir\": \"code\",\n  \"zip\": true\n}\n"
  },
  {
    "path": "code/core/.eslintrc.json",
    "content": "{\n  \"rules\": {\n    \"@typescript-eslint/triple-slash-reference\": \"off\",\n    \"storybook/use-storybook-expect\": \"off\"\n  }\n}\n"
  },
  {
    "path": "code/core/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://storybook.js.org/?ref=readme\">\n    <picture>\n      <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://user-images.githubusercontent.com/263385/199832481-bbbf5961-6a26-481d-8224-51258cce9b33.png\">\n      <img src=\"https://user-images.githubusercontent.com/321738/63501763-88dbf600-c4cc-11e9-96cd-94adadc2fd72.png\" alt=\"Storybook\" width=\"400\" />\n    </picture>\n    \n  </a>\n  \n</p>\n\n<p align=\"center\">Build bulletproof UI components faster</p>\n\n<br/>\n\n<p align=\"center\">\nStorybook is a frontend workshop for building UI components and pages in isolation. Thousands of teams use it for UI development, testing, and documentation. Find out more at <a href=\"https://storybook.js.org/?ref=readme\">storybook.js.org</a>!\n</p>\n\n<center>\n  <img src=\"https://raw.githubusercontent.com/storybookjs/storybook/refs/heads/release-6-5/media/storybook-intro.gif\" width=\"100%\" />\n</center>\n\n---\n\n# Storybook\n\nThe `storybook` package contains Storybook's core. It includes:\n\n- Storybook's CLI and development server\n- Storybook's main UI (aka \"the manager\")\n- Core functionality including component controls, toolbar controls, action logging, viewport control, and interaction debugger\n- User-facing utility libraries such as `storybook/test`, `theming`, and `viewport`\n- Libraries used by Storybook's ecosystem of frameworks, addons, and builders\n\nIt also contains a variety of other libraries and utilities under the `stroybook/internal` namespace, such as utilities for CSF, MDX & Docs.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/core/assets/server/addon.tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"jsx\": \"react\",\n    \"jsxImportSource\": \"react\"\n  }\n}\n"
  },
  {
    "path": "code/core/assets/server/base-preview-body.html",
    "content": "<div class=\"sb-preparing-story sb-wrapper\">\n  <div class=\"sb-loader\"></div>\n</div>\n\n<div class=\"sb-preparing-docs sb-wrapper\">\n  <div class=\"sb-previewBlock\">\n    <div class=\"sb-previewBlock_header\">\n      <div class=\"sb-previewBlock_icon\"></div>\n      <div class=\"sb-previewBlock_icon\"></div>\n      <div class=\"sb-previewBlock_icon\"></div>\n      <div class=\"sb-previewBlock_icon\"></div>\n    </div>\n    <div class=\"sb-previewBlock_body\">\n      <div class=\"sb-loader\"></div>\n    </div>\n  </div>\n  <table aria-hidden=\"true\" class=\"sb-argstableBlock\">\n    <thead class=\"sb-argstableBlock-head\">\n      <tr>\n        <th><span>Name</span></th>\n        <th><span>Description</span></th>\n        <th><span>Default</span></th>\n        <th><span>Control </span></th>\n      </tr>\n    </thead>\n    <tbody class=\"sb-argstableBlock-body\">\n      <tr>\n        <td><span>propertyName</span><span title=\"Required\">*</span></td>\n        <td>\n          <div><span>This is a short description</span></div>\n          <div class=\"sb-argstableBlock-summary\">\n            <div><span class=\"sb-argstableBlock-code\">summary</span></div>\n          </div>\n        </td>\n        <td>\n          <div><span class=\"sb-argstableBlock-code\">defaultValue</span></div>\n        </td>\n        <td><button>Set string</button></td>\n      </tr>\n      <tr>\n        <td><span>propertyName</span><span>*</span></td>\n        <td>\n          <div><span>This is a short description</span></div>\n          <div class=\"sb-argstableBlock-summary\">\n            <div><span class=\"sb-argstableBlock-code\">summary</span></div>\n          </div>\n        </td>\n        <td>\n          <div><span class=\"sb-argstableBlock-code\">defaultValue</span></div>\n        </td>\n        <td><button>Set string</button></td>\n      </tr>\n      <tr>\n        <td><span>propertyName</span><span>*</span></td>\n        <td>\n          <div><span>This is a short description</span></div>\n          <div class=\"sb-argstableBlock-summary\">\n            <div><span class=\"sb-argstableBlock-code\">summary</span></div>\n          </div>\n        </td>\n        <td>\n          <div><span class=\"sb-argstableBlock-code\">defaultValue</span></div>\n        </td>\n        <td><button>Set string</button></td>\n      </tr>\n    </tbody>\n  </table>\n</div>\n\n<div class=\"sb-nopreview sb-wrapper\">\n  <div class=\"sb-nopreview_main\">\n    <h1 class=\"sb-nopreview_heading sb-heading\">No Preview</h1>\n    <p>Sorry, but you either have no stories or none are selected somehow.</p>\n    <ul>\n      <li>Please check the Storybook config.</li>\n      <li>Try reloading the page.</li>\n    </ul>\n    <p>\n      If the problem persists, check the browser console, or the terminal you've run Storybook from.\n    </p>\n  </div>\n</div>\n\n<div class=\"sb-errordisplay sb-wrapper\">\n  <div class=\"sb-errordisplay_main\">\n    <h1 id=\"error-message\"></h1>\n    <p>\n      The component failed to render properly, likely due to a configuration issue in Storybook.\n      Here are some common causes and how you can address them:\n    </p>\n    <ol>\n      <li>\n        <strong>Missing Context/Providers</strong>: You can use decorators to supply specific\n        contexts or providers, which are sometimes necessary for components to render correctly. For\n        detailed instructions on using decorators, please visit the\n        <a href=\"https://storybook.js.org/docs/writing-stories/decorators\"\n          >Decorators documentation</a\n        >.\n      </li>\n      <li>\n        <strong>Misconfigured Webpack or Vite</strong>: Verify that Storybook picks up all necessary\n        settings for loaders, plugins, and other relevant parameters. You can find step-by-step\n        guides for configuring\n        <a href=\"https://storybook.js.org/docs/builders/webpack\">Webpack</a> or\n        <a href=\"https://storybook.js.org/docs/builders/vite\">Vite</a>\n        with Storybook.\n      </li>\n      <li>\n        <strong>Missing Environment Variables</strong>: Your Storybook may require specific\n        environment variables to function as intended. You can set up custom environment variables\n        as outlined in the\n        <a href=\"https://storybook.js.org/docs/configure/environment-variables\"\n          >Environment Variables documentation</a\n        >.\n      </li>\n    </ol>\n    <pre class=\"sb-errordisplay_code\"><code id=\"error-stack\"></code></pre>\n  </div>\n</div>\n"
  },
  {
    "path": "code/core/assets/server/base-preview-head.html",
    "content": "<base target=\"_parent\" />\n\n<style>\n  /* While we aren't showing the main block yet, but still preparing, we want everything the user has rendered, which may or may not be in #storybook-root, to be display none */\n  .sb-show-preparing-story:not(.sb-show-main) > :not(.sb-preparing-story) {\n    display: none;\n  }\n\n  .sb-show-preparing-docs:not(.sb-show-main) > :not(.sb-preparing-docs) {\n    display: none;\n  }\n\n  /* Hide our own blocks when we aren't supposed to be showing them */\n  :not(.sb-show-preparing-story) > .sb-preparing-story,\n  :not(.sb-show-preparing-docs) > .sb-preparing-docs,\n  :not(.sb-show-nopreview) > .sb-nopreview,\n  :not(.sb-show-errordisplay) > .sb-errordisplay {\n    display: none;\n  }\n\n  .sb-show-main.sb-main-centered {\n    margin: 0;\n    display: flex;\n    align-items: center;\n    min-height: 100vh;\n  }\n\n  .sb-show-main.sb-main-centered #storybook-root {\n    box-sizing: border-box;\n    margin: auto;\n    padding: 1rem;\n    max-height: 100%;\n    /* Hack for centering correctly in IE11 */\n  }\n\n  /* Vertical centering fix for IE11 */\n  @media screen and (-ms-high-contrast: none), (-ms-high-contrast: active) {\n    .sb-show-main.sb-main-centered:after {\n      content: '';\n      min-height: inherit;\n      font-size: 0;\n    }\n  }\n\n  .sb-show-main.sb-main-fullscreen {\n    margin: 0;\n    padding: 0;\n    display: block;\n  }\n\n  .sb-show-main.sb-main-padded {\n    margin: 0;\n    padding: 1rem;\n    display: block;\n    box-sizing: border-box;\n  }\n\n  .sb-wrapper {\n    position: fixed;\n    top: 0;\n    bottom: 0;\n    left: 0;\n    right: 0;\n    box-sizing: border-box;\n\n    padding: 40px;\n    font-family:\n      'Nunito Sans',\n      -apple-system,\n      '.SFNSText-Regular',\n      'San Francisco',\n      BlinkMacSystemFont,\n      'Segoe UI',\n      'Helvetica Neue',\n      Helvetica,\n      Arial,\n      sans-serif;\n    -webkit-font-smoothing: antialiased;\n    overflow: auto;\n  }\n\n  @media (max-width: 700px) {\n    .sb-wrapper {\n      padding: 20px;\n    }\n  }\n\n  @media (max-width: 500px) {\n    .sb-wrapper {\n      padding: 10px;\n    }\n  }\n\n  .sb-heading {\n    font-size: 14px;\n    font-weight: 600;\n    letter-spacing: 0.2px;\n    margin: 10px 0;\n    padding-right: 25px;\n  }\n\n  .sb-nopreview {\n    display: flex;\n    align-content: center;\n    justify-content: center;\n    box-sizing: border-box;\n  }\n\n  .sb-nopreview_main {\n    margin: auto;\n    padding: 30px;\n    border-radius: 10px;\n    background: rgb(247, 247, 247);\n    color: rgb(46, 52, 56);\n\n    & * {\n      background: rgb(247, 247, 247);\n      color: rgb(46, 52, 56);\n    }\n  }\n\n  .sb-nopreview_heading {\n    text-align: center;\n  }\n\n  .sb-errordisplay {\n    background: #f6f9fc;\n    color: black;\n    z-index: 999999;\n    width: 100vw;\n    min-height: 100vh;\n    box-sizing: border-box;\n  }\n\n  .sb-errordisplay_main {\n    margin: auto;\n    padding: 24px;\n    display: flex;\n    box-sizing: border-box;\n\n    flex-direction: column;\n    min-height: 100%;\n    width: 100%;\n    border-radius: 6px;\n    background: white;\n    color: black;\n    border: 1px solid #ff0000;\n    box-shadow: 0 0 64px rgba(0, 0, 0, 0.1);\n    gap: 24px;\n\n    & ol {\n      padding-left: 18px;\n      margin: 0;\n    }\n\n    /* Redefine colors to ensure readability regardless of user-provided * selectors. */\n    * {\n      background: white;\n      color: black;\n    }\n\n    & h1 {\n      font-family: Nunito Sans;\n      font-size: 22px;\n      font-weight: 400;\n      line-height: 30px;\n      font-weight: normal;\n      margin: 0;\n\n      &::before {\n        content: '';\n        display: inline-block;\n        width: 12px;\n        height: 12px;\n        background: #ff4400;\n        border-radius: 50%;\n        margin-right: 8px;\n      }\n    }\n\n    & p,\n    & ol {\n      font-family: Nunito Sans;\n      font-size: 14px;\n      font-weight: 400;\n      line-height: 19px;\n      margin: 0;\n    }\n\n    & li + li {\n      margin: 0;\n      padding: 0;\n      padding-top: 12px;\n    }\n\n    & a {\n      color: currentColor;\n    }\n\n    & .sb-errordisplay_code {\n      padding: 10px;\n      flex: 1;\n      background: #242424;\n      color: #c6c6c6;\n      box-sizing: border-box;\n\n      font-size: 14px;\n      font-weight: 400;\n      line-height: 19px;\n      border-radius: 4px;\n\n      font-family:\n        'Operator Mono', 'Fira Code Retina', 'Fira Code', 'FiraCode-Retina', 'Andale Mono',\n        'Lucida Console', Consolas, Monaco, monospace;\n      margin: 0;\n      overflow: auto;\n\n      & code {\n        background-color: inherit;\n        color: inherit;\n      }\n    }\n\n    & .sb-errordisplay pre {\n      white-space: pre-wrap;\n      white-space: revert;\n    }\n  }\n\n  @-webkit-keyframes sb-rotate360 {\n    from {\n      transform: rotate(0deg);\n    }\n\n    to {\n      transform: rotate(360deg);\n    }\n  }\n\n  @keyframes sb-rotate360 {\n    from {\n      transform: rotate(0deg);\n    }\n\n    to {\n      transform: rotate(360deg);\n    }\n  }\n\n  @-webkit-keyframes sb-glow {\n    0%,\n    100% {\n      opacity: 1;\n    }\n\n    50% {\n      opacity: 0.4;\n    }\n  }\n\n  @keyframes sb-glow {\n    0%,\n    100% {\n      opacity: 1;\n    }\n\n    50% {\n      opacity: 0.4;\n    }\n  }\n\n  /* We display the preparing loaders *over* the rendering story */\n  .sb-preparing-story,\n  .sb-preparing-docs {\n    background-color: white;\n    /* Maximum possible z-index. It would be better to use stacking contexts to ensure it's always\n    on top, but this isn't possible as it would require making CSS changes that could affect user code */\n    z-index: 2147483647;\n  }\n\n  .sb-loader {\n    -webkit-animation: sb-rotate360 0.7s linear infinite;\n    animation: sb-rotate360 0.7s linear infinite;\n    border-color: rgba(97, 97, 97, 0.29);\n    border-radius: 50%;\n    border-style: solid;\n    border-top-color: #646464;\n    border-width: 2px;\n    display: inline-block;\n    height: 32px;\n    left: 50%;\n    margin-left: -16px;\n    margin-top: -16px;\n    mix-blend-mode: difference;\n    overflow: hidden;\n    position: absolute;\n    top: 50%;\n    transition: all 200ms ease-out;\n    vertical-align: top;\n    width: 32px;\n    z-index: 4;\n  }\n\n  .sb-previewBlock {\n    background: #fff;\n    border: 1px solid rgba(0, 0, 0, 0.1);\n    border-radius: 4px;\n    box-shadow: rgba(0, 0, 0, 0.1) 0 1px 3px 0;\n    margin: 25px auto 40px;\n    max-width: 600px;\n  }\n\n  .sb-previewBlock_header {\n    align-items: center;\n    box-shadow: rgba(0, 0, 0, 0.1) 0 -1px 0 0 inset;\n    display: flex;\n    gap: 14px;\n    height: 40px;\n    padding: 0 12px;\n  }\n\n  .sb-previewBlock_icon {\n    -webkit-animation: sb-glow 1.5s ease-in-out infinite;\n    animation: sb-glow 1.5s ease-in-out infinite;\n    background: #e6e6e6;\n    height: 14px;\n    width: 14px;\n  }\n\n  .sb-previewBlock_icon:last-child {\n    margin-left: auto;\n  }\n\n  .sb-previewBlock_body {\n    -webkit-animation: sb-glow 1.5s ease-in-out infinite;\n    animation: sb-glow 1.5s ease-in-out infinite;\n    height: 182px;\n    position: relative;\n  }\n\n  .sb-argstableBlock {\n    border-collapse: collapse;\n    border-spacing: 0;\n    font-size: 13px;\n    line-height: 20px;\n    margin: 25px auto 40px;\n    max-width: 600px;\n    text-align: left;\n    width: 100%;\n  }\n\n  .sb-argstableBlock th:first-of-type,\n  .sb-argstableBlock td:first-of-type {\n    padding-left: 20px;\n  }\n\n  .sb-argstableBlock th:nth-of-type(2),\n  .sb-argstableBlock td:nth-of-type(2) {\n    width: 35%;\n  }\n\n  .sb-argstableBlock th:nth-of-type(3),\n  .sb-argstableBlock td:nth-of-type(3) {\n    width: 15%;\n  }\n\n  .sb-argstableBlock th:last-of-type,\n  .sb-argstableBlock td:last-of-type {\n    width: 25%;\n    padding-right: 20px;\n  }\n\n  .sb-argstableBlock th span,\n  .sb-argstableBlock td span {\n    -webkit-animation: sb-glow 1.5s ease-in-out infinite;\n    animation: sb-glow 1.5s ease-in-out infinite;\n    background-color: rgba(0, 0, 0, 0.1);\n    border-radius: 0;\n    box-shadow: none;\n    color: transparent;\n  }\n\n  .sb-argstableBlock th {\n    padding: 10px 15px;\n  }\n\n  .sb-argstableBlock-body {\n    border-radius: 4px;\n    box-shadow:\n      rgba(0, 0, 0, 0.1) 0 1px 3px 1px,\n      rgba(0, 0, 0, 0.065) 0 0 0 1px;\n  }\n\n  .sb-argstableBlock-body tr {\n    background: transparent;\n    overflow: hidden;\n  }\n\n  .sb-argstableBlock-body tr:not(:first-child) {\n    border-top: 1px solid #e6e6e6;\n  }\n\n  .sb-argstableBlock-body tr:first-child td:first-child {\n    border-top-left-radius: 4px;\n  }\n\n  .sb-argstableBlock-body tr:first-child td:last-child {\n    border-top-right-radius: 4px;\n  }\n\n  .sb-argstableBlock-body tr:last-child td:first-child {\n    border-bottom-left-radius: 4px;\n  }\n\n  .sb-argstableBlock-body tr:last-child td:last-child {\n    border-bottom-right-radius: 4px;\n  }\n\n  .sb-argstableBlock-body td {\n    background: #fff;\n    padding-bottom: 10px;\n    padding-top: 10px;\n    vertical-align: top;\n  }\n\n  .sb-argstableBlock-body td:not(:first-of-type) {\n    padding-left: 15px;\n    padding-right: 15px;\n  }\n\n  .sb-argstableBlock-body button {\n    -webkit-animation: sb-glow 1.5s ease-in-out infinite;\n    animation: sb-glow 1.5s ease-in-out infinite;\n    background-color: rgba(0, 0, 0, 0.1);\n    border: 0;\n    border-radius: 0;\n    box-shadow: none;\n    color: transparent;\n    display: inline;\n    font-size: 12px;\n    line-height: 1;\n    padding: 10px 16px;\n  }\n\n  .sb-argstableBlock-summary {\n    margin-top: 4px;\n  }\n\n  .sb-argstableBlock-code {\n    margin-right: 4px;\n    margin-bottom: 4px;\n    padding: 2px 5px;\n  }\n\n  .sb-sr-only,\n  .sb-hidden-until-focus:not(:focus) {\n    position: absolute;\n    width: 1px;\n    height: 1px;\n    padding: 0px;\n    margin: -1px;\n    overflow: hidden;\n    clip: rect(0, 0, 0, 0);\n    border: none;\n  }\n\n  .sb-hidden-until-focus {\n    opacity: 0;\n    transition: opacity 150ms ease-out;\n  }\n\n  .sb-hidden-until-focus:focus {\n    opacity: 1;\n  }\n</style>\n\n<script>\n  /* globals window */\n  try {\n    if (window.top !== window) {\n      window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.top.__REACT_DEVTOOLS_GLOBAL_HOOK__;\n      window.__VUE_DEVTOOLS_GLOBAL_HOOK__ = window.top.__VUE_DEVTOOLS_GLOBAL_HOOK__;\n      window.top.__VUE_DEVTOOLS_CONTEXT__ = window.document;\n    }\n  } catch (e) {\n    // eslint-disable-next-line no-console\n    console.warn('unable to connect to top frame for connecting dev tools');\n  }\n</script>\n"
  },
  {
    "path": "code/core/assets/server/openBrowser.applescript",
    "content": "(*\nCopyright (c) 2015-present, Facebook, Inc.\nThis source code is licensed under the MIT license found in the\nLICENSE file in the root directory of this source tree.\n*)\n\nproperty targetTab: null\nproperty targetTabIndex: -1\nproperty targetWindow: null\nproperty theProgram: \"Google Chrome\"\n\non run argv\n  set theURL to item 1 of argv\n  set matchURL to item 2 of argv\n\n  -- Allow requested program to be optional,\n  -- default to Google Chrome\n  if (count of argv) > 2 then\n    set theProgram to item 3 of argv\n  end if\n\n  using terms from application \"Google Chrome\"\n    tell application theProgram\n\n      if (count every window) = 0 then\n        make new window\n      end if\n\n      -- 1: Looking for tab running debugger\n      -- then, Reload debugging tab if found\n      -- then return\n      set found to my lookupTabWithUrl(matchURL)\n      if found then\n        set targetWindow's active tab index to targetTabIndex\n        tell targetTab to reload\n        tell targetWindow to activate\n        set index of targetWindow to 1\n        return\n      end if\n\n      -- 2: Looking for Empty tab\n      -- In case debugging tab was not found\n      -- We try to find an empty tab instead\n      set found to my lookupTabWithUrl(\"chrome://newtab/\")\n      if found then\n        set targetWindow's active tab index to targetTabIndex\n        set URL of targetTab to theURL\n        tell targetWindow to activate\n        return\n      end if\n\n      -- 3: Create new tab\n      -- both debugging and empty tab were not found\n      -- make a new tab with url\n      tell window 1\n        activate\n        make new tab with properties {URL:theURL}\n      end tell\n    end tell\n  end using terms from\nend run\n\n-- Function:\n-- Lookup tab with given url\n-- if found, store tab, index, and window in properties\n-- (properties were declared on top of file)\non lookupTabWithUrl(lookupUrl)\n  using terms from application \"Google Chrome\"\n    tell application theProgram\n      -- Find a tab with the given url\n      set found to false\n      set theTabIndex to -1\n      repeat with theWindow in every window\n        set theTabIndex to 0\n        repeat with theTab in every tab of theWindow\n          set theTabIndex to theTabIndex + 1\n          if (theTab's URL as string) contains lookupUrl then\n            -- assign tab, tab index, and window to properties\n            set targetTab to theTab\n            set targetTabIndex to theTabIndex\n            set targetWindow to theWindow\n            set found to true\n            exit repeat\n          end if\n        end repeat\n\n        if found then\n          exit repeat\n        end if\n      end repeat\n    end tell\n  end using terms from\n  return found\nend lookupTabWithUrl"
  },
  {
    "path": "code/core/assets/server/template.ejs",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n\n    <title><%= typeof title !== 'undefined'? title : 'Storybook'%></title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\n    <% if (favicon.endsWith('.svg')) {%>\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"./<%= favicon %>\" />\n    <% } else if (favicon.endsWith('.ico')) { %>\n    <link rel=\"icon\" type=\"image/x-icon\" href=\"./<%= favicon %>\" />\n    <% } %>\n    <style>\n      @font-face {\n        font-family: 'Nunito Sans';\n        font-style: normal;\n        font-weight: 400;\n        font-display: swap;\n        src: url('./sb-common-assets/nunito-sans-regular.woff2') format('woff2');\n      }\n\n      @font-face {\n        font-family: 'Nunito Sans';\n        font-style: italic;\n        font-weight: 400;\n        font-display: swap;\n        src: url('./sb-common-assets/nunito-sans-italic.woff2') format('woff2');\n      }\n\n      @font-face {\n        font-family: 'Nunito Sans';\n        font-style: normal;\n        font-weight: 700;\n        font-display: swap;\n        src: url('./sb-common-assets/nunito-sans-bold.woff2') format('woff2');\n      }\n\n      @font-face {\n        font-family: 'Nunito Sans';\n        font-style: italic;\n        font-weight: 700;\n        font-display: swap;\n        src: url('./sb-common-assets/nunito-sans-bold-italic.woff2') format('woff2');\n      }\n    </style>\n\n    <link href=\"./sb-manager/runtime.js\" rel=\"modulepreload\" />\n\n    <% files.js.forEach(file => { %>\n    <link href=\"<%= file %>\" rel=\"modulepreload\" />\n    <% }); %> <% if (typeof head !== 'undefined') { %> <%- head %> <% } %>\n\n    <style>\n      #storybook-root[hidden] {\n        display: none !important;\n      }\n    </style>\n\n    <% files.css.forEach(file => { %>\n    <link href=\"<%= file %>\" rel=\"stylesheet\" />\n    <% }); %>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n\n    <% if (typeof globals !== 'undefined' && Object.keys(globals).length) { %>\n    <script>\n      <% for (var varName in globals) { %>\n        <% if (globals[varName] !== undefined) { %>\n          window['<%=varName%>'] = <%- (globals[varName]) %>;\n        <% } %>\n      <% } %>\n    </script>\n    <% } %>\n\n    <script type=\"module\">\n      import './sb-manager/globals-runtime.js';\n\n      <% files.js.forEach(file => { %>\n        import '<%= file %>';\n      <% }); %>\n\n      import './sb-manager/runtime.js';\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "code/core/build-config.ts",
    "content": "import path from 'node:path';\n\nimport { x as exec } from 'tinyexec';\n\nimport type { BuildEntries } from '../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  prebuild: async (cwd) => {\n    await exec('jiti', [path.join(import.meta.dirname, 'scripts', 'generate-source-files.ts')], {\n      nodeOptions: {\n        cwd,\n        env: {\n          ...process.env,\n          NODE_ENV: 'production',\n          FORCE_COLOR: '1',\n        },\n        stdio: 'inherit',\n      },\n      throwOnError: true,\n    });\n  },\n  entries: {\n    node: [\n      {\n        exportEntries: ['./internal/node-logger'],\n        entryPoint: './src/node-logger/index.ts',\n      },\n      {\n        exportEntries: ['./internal/server-errors'],\n        entryPoint: './src/server-errors.ts',\n      },\n      {\n        exportEntries: ['./internal/core-server'],\n        entryPoint: './src/core-server/index.ts',\n      },\n      {\n        entryPoint: './src/core-server/presets/common-preset.ts',\n        dts: false,\n      },\n      {\n        entryPoint: './src/core-server/presets/common-override-preset.ts',\n        exportEntries: ['./internal/core-server/presets/common-override-preset'],\n        dts: false,\n      },\n      {\n        exportEntries: ['./internal/telemetry'],\n        entryPoint: './src/telemetry/index.ts',\n      },\n      {\n        exportEntries: ['./internal/csf-tools'],\n        entryPoint: './src/csf-tools/index.ts',\n      },\n      {\n        exportEntries: ['./internal/babel'],\n        entryPoint: './src/babel/index.ts',\n      },\n      {\n        exportEntries: ['./internal/bin/dispatcher'],\n        entryPoint: './src/bin/dispatcher.ts',\n        dts: false,\n      },\n      {\n        entryPoint: './src/bin/core.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./internal/bin/loader'],\n        entryPoint: './src/bin/loader.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./internal/common'],\n        entryPoint: './src/common/index.ts',\n      },\n      {\n        entryPoint: './src/cli/index.ts',\n        exportEntries: ['./internal/cli'],\n      },\n      {\n        exportEntries: ['./internal/mocking-utils'],\n        entryPoint: './src/mocking-utils/index.ts',\n      },\n    ],\n    browser: [\n      {\n        exportEntries: ['./internal/client-logger'],\n        entryPoint: './src/client-logger/index.ts',\n      },\n      {\n        exportEntries: ['./internal/instrumenter'],\n        entryPoint: './src/instrumenter/index.ts',\n      },\n      {\n        exportEntries: ['./test'],\n        entryPoint: './src/test/index.ts',\n      },\n      {\n        exportEntries: ['./preview-api', './internal/preview-api'],\n        entryPoint: './src/preview-api/index.ts',\n      },\n      {\n        exportEntries: ['./highlight'],\n        entryPoint: './src/highlight/index.ts',\n      },\n      {\n        exportEntries: ['./actions'],\n        entryPoint: './src/actions/index.ts',\n      },\n      {\n        exportEntries: ['./actions/decorator'],\n        entryPoint: './src/actions/decorator.ts',\n      },\n      {\n        exportEntries: ['./viewport'],\n        entryPoint: './src/viewport/index.ts',\n      },\n      {\n        exportEntries: ['./internal/preview/globals'],\n        entryPoint: './src/preview/globals.ts',\n      },\n      {\n        exportEntries: ['./internal/csf'],\n        entryPoint: './src/csf/index.ts',\n      },\n      {\n        exportEntries: ['./internal/manager-errors'],\n        entryPoint: './src/manager-errors.ts',\n      },\n      {\n        exportEntries: ['./internal/preview-errors'],\n        entryPoint: './src/preview-errors.ts',\n      },\n      {\n        exportEntries: ['./internal/manager/globals'],\n        entryPoint: './src/manager/globals.ts',\n      },\n      {\n        exportEntries: ['./internal/manager/manager-stores'],\n        entryPoint: './src/manager/manager-stores.ts',\n      },\n      {\n        entryPoint: './src/core-server/presets/common-manager.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./theming'],\n        entryPoint: './src/theming/index.ts',\n      },\n      {\n        exportEntries: ['./theming/create'],\n        entryPoint: './src/theming/create.ts',\n      },\n      {\n        exportEntries: ['./internal/components'],\n        entryPoint: './src/components/index.ts',\n      },\n      {\n        exportEntries: ['./manager-api'],\n        entryPoint: './src/manager-api/index.ts',\n      },\n      {\n        exportEntries: ['./internal/router'],\n        entryPoint: './src/router/index.ts',\n      },\n      {\n        exportEntries: ['./internal/docs-tools'],\n        entryPoint: './src/docs-tools/index.ts',\n      },\n      {\n        exportEntries: ['./internal/core-events'],\n        entryPoint: './src/core-events/index.ts',\n      },\n      {\n        exportEntries: ['./internal/channels'],\n        entryPoint: './src/channels/index.ts',\n      },\n      {\n        exportEntries: ['./internal/types'],\n        entryPoint: './src/types/index.ts',\n      },\n    ],\n    runtime: [\n      {\n        exportEntries: ['./internal/preview/runtime'],\n        entryPoint: './src/preview/runtime.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./internal/manager/globals-runtime'],\n        entryPoint: './src/manager/globals-runtime.ts',\n        dts: false,\n      },\n      /**\n       * It is required to be a runtime entry point, because it is used to inject the mocker runtime\n       * into the preview iframe in builder-vite and builder-webpack5. To guarantee that the mocker\n       * runtime is transpiled correctly, code splitting needs to be disabled for this entry point.\n       */\n      {\n        exportEntries: ['./internal/mocking-utils/mocker-runtime'],\n        entryPoint: './src/mocking-utils/mocker-runtime.js',\n        dts: false,\n      },\n    ],\n    globalizedRuntime: [\n      {\n        entryPoint: './src/manager/runtime.tsx',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/core/package.json",
    "content": "{\n  \"name\": \"storybook\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"component\",\n    \"components\",\n    \"design-systems\",\n    \"component-testing\",\n    \"react\",\n    \"next\",\n    \"next.js\",\n    \"react-native\",\n    \"react-native-web\",\n    \"vue\",\n    \"angular\",\n    \"svelte\",\n    \"sveltekit\",\n    \"web-components\"\n  ],\n  \"homepage\": \"https://storybook.js.org\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/core\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"sideEffects\": false,\n  \"type\": \"module\",\n  \"imports\": {\n    \"#manager-stores\": {\n      \"storybook\": \"./src/manager/manager-stores.mock.ts\",\n      \"default\": \"./src/manager/manager-stores.ts\"\n    },\n    \"#utils\": {\n      \"storybook\": \"./template/stories/utils.mock.ts\",\n      \"default\": \"./template/stories/utils.ts\"\n    }\n  },\n  \"exports\": {\n    \"./actions\": {\n      \"types\": \"./dist/actions/index.d.ts\",\n      \"code\": \"./src/actions/index.ts\",\n      \"default\": \"./dist/actions/index.js\"\n    },\n    \"./actions/decorator\": {\n      \"types\": \"./dist/actions/decorator.d.ts\",\n      \"code\": \"./src/actions/decorator.ts\",\n      \"default\": \"./dist/actions/decorator.js\"\n    },\n    \"./highlight\": {\n      \"types\": \"./dist/highlight/index.d.ts\",\n      \"code\": \"./src/highlight/index.ts\",\n      \"default\": \"./dist/highlight/index.js\"\n    },\n    \"./internal/babel\": {\n      \"types\": \"./dist/babel/index.d.ts\",\n      \"code\": \"./src/babel/index.ts\",\n      \"default\": \"./dist/babel/index.js\"\n    },\n    \"./internal/bin/dispatcher\": \"./dist/bin/dispatcher.js\",\n    \"./internal/bin/loader\": \"./dist/bin/loader.js\",\n    \"./internal/channels\": {\n      \"types\": \"./dist/channels/index.d.ts\",\n      \"code\": \"./src/channels/index.ts\",\n      \"default\": \"./dist/channels/index.js\"\n    },\n    \"./internal/cli\": {\n      \"types\": \"./dist/cli/index.d.ts\",\n      \"code\": \"./src/cli/index.ts\",\n      \"default\": \"./dist/cli/index.js\"\n    },\n    \"./internal/client-logger\": {\n      \"types\": \"./dist/client-logger/index.d.ts\",\n      \"code\": \"./src/client-logger/index.ts\",\n      \"default\": \"./dist/client-logger/index.js\"\n    },\n    \"./internal/common\": {\n      \"types\": \"./dist/common/index.d.ts\",\n      \"code\": \"./src/common/index.ts\",\n      \"default\": \"./dist/common/index.js\"\n    },\n    \"./internal/components\": {\n      \"types\": \"./dist/components/index.d.ts\",\n      \"code\": \"./src/components/index.ts\",\n      \"default\": \"./dist/components/index.js\"\n    },\n    \"./internal/core-events\": {\n      \"types\": \"./dist/core-events/index.d.ts\",\n      \"code\": \"./src/core-events/index.ts\",\n      \"default\": \"./dist/core-events/index.js\"\n    },\n    \"./internal/core-server\": {\n      \"types\": \"./dist/core-server/index.d.ts\",\n      \"code\": \"./src/core-server/index.ts\",\n      \"default\": \"./dist/core-server/index.js\"\n    },\n    \"./internal/core-server/presets/common-override-preset\": \"./dist/core-server/presets/common-override-preset.js\",\n    \"./internal/csf\": {\n      \"types\": \"./dist/csf/index.d.ts\",\n      \"code\": \"./src/csf/index.ts\",\n      \"default\": \"./dist/csf/index.js\"\n    },\n    \"./internal/csf-tools\": {\n      \"types\": \"./dist/csf-tools/index.d.ts\",\n      \"code\": \"./src/csf-tools/index.ts\",\n      \"default\": \"./dist/csf-tools/index.js\"\n    },\n    \"./internal/docs-tools\": {\n      \"types\": \"./dist/docs-tools/index.d.ts\",\n      \"code\": \"./src/docs-tools/index.ts\",\n      \"default\": \"./dist/docs-tools/index.js\"\n    },\n    \"./internal/instrumenter\": {\n      \"types\": \"./dist/instrumenter/index.d.ts\",\n      \"code\": \"./src/instrumenter/index.ts\",\n      \"default\": \"./dist/instrumenter/index.js\"\n    },\n    \"./internal/manager-errors\": {\n      \"types\": \"./dist/manager-errors.d.ts\",\n      \"code\": \"./src/manager-errors.ts\",\n      \"default\": \"./dist/manager-errors.js\"\n    },\n    \"./internal/manager/globals\": {\n      \"types\": \"./dist/manager/globals.d.ts\",\n      \"code\": \"./src/manager/globals.ts\",\n      \"default\": \"./dist/manager/globals.js\"\n    },\n    \"./internal/manager/globals-runtime\": \"./dist/manager/globals-runtime.js\",\n    \"./internal/manager/manager-stores\": {\n      \"types\": \"./dist/manager/manager-stores.d.ts\",\n      \"code\": \"./src/manager/manager-stores.ts\",\n      \"default\": \"./dist/manager/manager-stores.js\"\n    },\n    \"./internal/mocking-utils\": {\n      \"types\": \"./dist/mocking-utils/index.d.ts\",\n      \"code\": \"./src/mocking-utils/index.ts\",\n      \"default\": \"./dist/mocking-utils/index.js\"\n    },\n    \"./internal/mocking-utils/mocker-runtime\": \"./dist/mocking-utils/mocker-runtime.js\",\n    \"./internal/node-logger\": {\n      \"types\": \"./dist/node-logger/index.d.ts\",\n      \"code\": \"./src/node-logger/index.ts\",\n      \"default\": \"./dist/node-logger/index.js\"\n    },\n    \"./internal/preview-api\": {\n      \"types\": \"./dist/preview-api/index.d.ts\",\n      \"code\": \"./src/preview-api/index.ts\",\n      \"default\": \"./dist/preview-api/index.js\"\n    },\n    \"./internal/preview-errors\": {\n      \"types\": \"./dist/preview-errors.d.ts\",\n      \"code\": \"./src/preview-errors.ts\",\n      \"default\": \"./dist/preview-errors.js\"\n    },\n    \"./internal/preview/globals\": {\n      \"types\": \"./dist/preview/globals.d.ts\",\n      \"code\": \"./src/preview/globals.ts\",\n      \"default\": \"./dist/preview/globals.js\"\n    },\n    \"./internal/preview/runtime\": \"./dist/preview/runtime.js\",\n    \"./internal/router\": {\n      \"types\": \"./dist/router/index.d.ts\",\n      \"code\": \"./src/router/index.ts\",\n      \"default\": \"./dist/router/index.js\"\n    },\n    \"./internal/server-errors\": {\n      \"types\": \"./dist/server-errors.d.ts\",\n      \"code\": \"./src/server-errors.ts\",\n      \"default\": \"./dist/server-errors.js\"\n    },\n    \"./internal/telemetry\": {\n      \"types\": \"./dist/telemetry/index.d.ts\",\n      \"code\": \"./src/telemetry/index.ts\",\n      \"default\": \"./dist/telemetry/index.js\"\n    },\n    \"./internal/types\": {\n      \"types\": \"./dist/types/index.d.ts\",\n      \"code\": \"./src/types/index.ts\",\n      \"default\": \"./dist/types/index.js\"\n    },\n    \"./manager-api\": {\n      \"types\": \"./dist/manager-api/index.d.ts\",\n      \"code\": \"./src/manager-api/index.ts\",\n      \"default\": \"./dist/manager-api/index.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./preview-api\": {\n      \"types\": \"./dist/preview-api/index.d.ts\",\n      \"code\": \"./src/preview-api/index.ts\",\n      \"default\": \"./dist/preview-api/index.js\"\n    },\n    \"./test\": {\n      \"types\": \"./dist/test/index.d.ts\",\n      \"code\": \"./src/test/index.ts\",\n      \"default\": \"./dist/test/index.js\"\n    },\n    \"./theming\": {\n      \"types\": \"./dist/theming/index.d.ts\",\n      \"code\": \"./src/theming/index.ts\",\n      \"default\": \"./dist/theming/index.js\"\n    },\n    \"./theming/create\": {\n      \"types\": \"./dist/theming/create.d.ts\",\n      \"code\": \"./src/theming/create.ts\",\n      \"default\": \"./dist/theming/create.js\"\n    },\n    \"./viewport\": {\n      \"types\": \"./dist/viewport/index.d.ts\",\n      \"code\": \"./src/viewport/index.ts\",\n      \"default\": \"./dist/viewport/index.js\"\n    }\n  },\n  \"bin\": \"./dist/bin/dispatcher.js\",\n  \"files\": [\n    \"bin/**/*\",\n    \"dist/**/*\",\n    \"assets/**/*\",\n    \"README.md\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/global\": \"^5.0.0\",\n    \"@storybook/icons\": \"^2.0.1\",\n    \"@testing-library/jest-dom\": \"^6.9.1\",\n    \"@testing-library/user-event\": \"^14.6.1\",\n    \"@vitest/expect\": \"3.2.4\",\n    \"@vitest/spy\": \"3.2.4\",\n    \"@webcontainer/env\": \"^1.1.1\",\n    \"esbuild\": \"^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0\",\n    \"open\": \"^10.2.0\",\n    \"recast\": \"^0.23.5\",\n    \"semver\": \"^7.7.3\",\n    \"use-sync-external-store\": \"^1.5.0\",\n    \"ws\": \"^8.18.0\"\n  },\n  \"devDependencies\": {\n    \"@aw-web-design/x-default-browser\": \"1.4.126\",\n    \"@babel/core\": \"^7.28.5\",\n    \"@babel/generator\": \"^7.28.5\",\n    \"@babel/parser\": \"^7.28.5\",\n    \"@babel/traverse\": \"^7.28.5\",\n    \"@babel/types\": \"^7.28.5\",\n    \"@clack/prompts\": \"1.0.0-alpha.7\",\n    \"@devtools-ds/object-inspector\": \"^1.1.2\",\n    \"@discoveryjs/json-ext\": \"^0.5.3\",\n    \"@emotion/cache\": \"^11.14.0\",\n    \"@emotion/is-prop-valid\": \"^1.3.1\",\n    \"@emotion/react\": \"^11.14.0\",\n    \"@emotion/styled\": \"^11.14.0\",\n    \"@fal-works/esbuild-plugin-global-externals\": \"^2.1.2\",\n    \"@happy-dom/global-registrator\": \"^20.0.11\",\n    \"@ngard/tiny-isequal\": \"^1.1.0\",\n    \"@polka/compression\": \"^1.0.0-next.28\",\n    \"@radix-ui/react-scroll-area\": \"1.2.0-rc.7\",\n    \"@radix-ui/react-slot\": \"^1.0.2\",\n    \"@react-aria/interactions\": \"^3.25.5\",\n    \"@react-aria/landmark\": \"^3.0.8\",\n    \"@react-aria/overlays\": \"^3.29.1\",\n    \"@react-aria/tabs\": \"^3.10.7\",\n    \"@react-aria/toolbar\": \"3.0.0-beta.20\",\n    \"@react-aria/utils\": \"^3.30.1\",\n    \"@react-stately/overlays\": \"^3.6.19\",\n    \"@react-stately/tabs\": \"^3.8.5\",\n    \"@react-types/shared\": \"^3.32.0\",\n    \"@rolldown/pluginutils\": \"1.0.0-beta.18\",\n    \"@storybook/docs-mdx\": \"4.0.0-next.3\",\n    \"@tanstack/react-virtual\": \"^3.3.0\",\n    \"@testing-library/dom\": \"^10.4.1\",\n    \"@testing-library/react\": \"^14.0.0\",\n    \"@types/cross-spawn\": \"^6.0.6\",\n    \"@types/detect-port\": \"^1.3.0\",\n    \"@types/diff\": \"^5.0.9\",\n    \"@types/ejs\": \"^3.1.1\",\n    \"@types/js-yaml\": \"^4.0.5\",\n    \"@types/node\": \"^22.19.1\",\n    \"@types/npmlog\": \"^7.0.0\",\n    \"@types/picomatch\": \"^2.3.0\",\n    \"@types/prettier\": \"^3.0.0\",\n    \"@types/pretty-hrtime\": \"^1.0.0\",\n    \"@types/prompts\": \"^2.0.9\",\n    \"@types/react-syntax-highlighter\": \"11.0.5\",\n    \"@types/semver\": \"^7.7.1\",\n    \"@types/ws\": \"^8\",\n    \"@vitest/mocker\": \"3.2.4\",\n    \"@vitest/utils\": \"^3.2.4\",\n    \"@yarnpkg/fslib\": \"2.10.3\",\n    \"@yarnpkg/libzip\": \"2.3.0\",\n    \"ansi-to-html\": \"^0.7.2\",\n    \"browser-dtector\": \"^3.4.0\",\n    \"bundle-require\": \"^5.1.0\",\n    \"camelcase\": \"^9.0.0\",\n    \"chai\": \"^5.1.1\",\n    \"commander\": \"^14.0.2\",\n    \"comment-parser\": \"^1.4.1\",\n    \"copy-to-clipboard\": \"^3.3.1\",\n    \"cross-spawn\": \"^7.0.6\",\n    \"deep-object-diff\": \"^1.1.0\",\n    \"dequal\": \"^2.0.2\",\n    \"detect-indent\": \"^7.0.1\",\n    \"detect-port\": \"^1.6.1\",\n    \"diff\": \"^8.0.2\",\n    \"downshift\": \"^9.0.4\",\n    \"ejs\": \"^3.1.10\",\n    \"empathic\": \"^2.0.0\",\n    \"es-toolkit\": \"^1.43.0\",\n    \"esbuild\": \"^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0\",\n    \"execa\": \"^9.6.1\",\n    \"exsolve\": \"^1.0.7\",\n    \"fetch-retry\": \"^6.0.0\",\n    \"flush-promises\": \"^1.0.2\",\n    \"fuse.js\": \"^3.6.1\",\n    \"get-npm-tarball-url\": \"^2.1.0\",\n    \"glob\": \"^10.5.0\",\n    \"globby\": \"^14.1.0\",\n    \"host-validation-middleware\": \"^0.1.2\",\n    \"jiti\": \"^2.6.1\",\n    \"js-yaml\": \"^4.1.0\",\n    \"jsdoc-type-pratt-parser\": \"^4.0.0\",\n    \"launch-editor\": \"^2.11.1\",\n    \"lazy-universal-dotenv\": \"^4.0.0\",\n    \"leven\": \"^4.0.0\",\n    \"memfs\": \"^4.11.1\",\n    \"memoizerific\": \"^1.11.3\",\n    \"modern-tar\": \"^0.5.5\",\n    \"nanoid\": \"^4.0.2\",\n    \"npmlog\": \"^7.0.0\",\n    \"p-limit\": \"^7.2.0\",\n    \"package-manager-detector\": \"^1.1.0\",\n    \"picocolors\": \"^1.1.0\",\n    \"picomatch\": \"^2.3.0\",\n    \"picoquery\": \"^1.4.0\",\n    \"polished\": \"^4.2.2\",\n    \"polka\": \"^1.0.0-next.28\",\n    \"prettier\": \"^3.7.1\",\n    \"pretty-hrtime\": \"^1.0.3\",\n    \"qrcode.react\": \"^4.2.0\",\n    \"react\": \"^18.2.0\",\n    \"react-aria-components\": \"patch:react-aria-components@npm%3A1.12.2#~/.yarn/patches/react-aria-components-npm-1.12.2-6c5dcdafab.patch\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-helmet-async\": \"^1.3.0\",\n    \"react-inspector\": \"^6.0.0\",\n    \"react-router-dom\": \"6.15.0\",\n    \"react-syntax-highlighter\": \"^15.4.5\",\n    \"react-textarea-autosize\": \"^8.3.0\",\n    \"react-transition-state\": \"^2.3.1\",\n    \"require-from-string\": \"^2.0.2\",\n    \"resolve\": \"^1.22.11\",\n    \"resolve.exports\": \"^2.0.3\",\n    \"sirv\": \"^2.0.4\",\n    \"slash\": \"^5.0.0\",\n    \"source-map\": \"^0.7.4\",\n    \"std-env\": \"^4.0.0\",\n    \"store2\": \"^2.14.2\",\n    \"strip-ansi\": \"^7.1.0\",\n    \"strip-json-comments\": \"^5.0.1\",\n    \"telejson\": \"8.0.0\",\n    \"tiny-invariant\": \"^1.3.1\",\n    \"tinyspy\": \"^3.0.2\",\n    \"ts-dedent\": \"^2.0.0\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"type-fest\": \"^4.18.1\",\n    \"typescript\": \"^5.8.3\",\n    \"unique-string\": \"^3.0.0\",\n    \"use-resize-observer\": \"^9.1.0\",\n    \"watchpack\": \"^2.5.0\",\n    \"wrap-ansi\": \"^9.0.2\",\n    \"zod\": \"^3.25.76\"\n  },\n  \"peerDependencies\": {\n    \"prettier\": \"^2 || ^3\"\n  },\n  \"peerDependenciesMeta\": {\n    \"prettier\": {\n      \"optional\": true\n    }\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/core/project.json",
    "content": "{\n  \"name\": \"core\",\n  \"$schema\": \"../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/core/scripts/generate-source-files.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { mkdirSync } from 'node:fs';\nimport { readdir, realpath, writeFile } from 'node:fs/promises';\nimport os from 'node:os';\nimport { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nimport { GlobalRegistrator } from '@happy-dom/global-registrator';\nimport { isNotNil } from 'es-toolkit/predicate';\nimport * as esbuild from 'esbuild';\nimport { format } from 'oxfmt';\nimport { dedent } from 'ts-dedent';\n\nimport { getWorkspace } from '../../../scripts/utils/tools.ts';\nimport {\n  BROWSER_TARGETS,\n  SUPPORTED_FEATURES,\n} from '../src/shared/constants/environments-support.ts';\n\nGlobalRegistrator.register({ url: 'http://localhost:3000', width: 1920, height: 1080 });\n\nconst CODE_DIR = join(import.meta.dirname, '..', '..', '..', 'code');\nconst CORE_ROOT_DIR = join(CODE_DIR, 'core');\nconst tempDir = () => realpath(os.tmpdir());\nconst getPath = async (prefix = '') =>\n  join(await tempDir(), prefix + (Math.random() + 1).toString(36).substring(7));\n\nasync function temporaryDirectory({ prefix = '' } = {}) {\n  const directory = await getPath(prefix);\n  mkdirSync(directory);\n  return directory;\n}\nasync function temporaryFile({ name, extension }: { name?: string; extension?: string } = {}) {\n  if (name) {\n    if (extension !== undefined && extension !== null) {\n      // eslint-disable-next-line local-rules/no-uncategorized-errors\n      throw new Error('The `name` and `extension` options are mutually exclusive');\n    }\n\n    return join(await temporaryDirectory(), name);\n  }\n\n  return (\n    (await getPath()) +\n    (extension === undefined || extension === null ? '' : '.' + extension.replace(/^\\./, ''))\n  );\n}\n\n// read code/frameworks subfolders and generate a list of available frameworks\n// save this list into ./code/core/src/types/frameworks.ts and export it as a union type.\n// The name of the type is `SupportedFrameworks`. Add additionally 'qwik' and `solid` to that list.\nexport const generateSourceFiles = async () => {\n  await Promise.all([generateFrameworksFile(), generateVersionsFile(), generateExportsFile()]);\n};\n\nasync function generateVersionsFile(): Promise<void> {\n  const destination = join(CORE_ROOT_DIR, 'src', 'common', 'versions.ts');\n\n  const workspace = (await getWorkspace()).filter(isNotNil);\n\n  const versions = JSON.stringify(\n    workspace\n      .sort((a, b) => a.path.localeCompare(b.path))\n      .reduce<Record<string, string>>((acc, i) => {\n        if (i.publishConfig && i.publishConfig.access === 'public') {\n          acc[i.name] = i.version;\n        }\n        return acc;\n      }, {})\n  );\n\n  const { code: formatted } = await format(\n    'versions.ts',\n    dedent`\n      // auto generated file, do not edit\n      export default ${versions};\n    `,\n    { singleQuote: true }\n  );\n\n  await writeFile(destination, formatted);\n}\n\nasync function generateFrameworksFile(): Promise<void> {\n  const thirdPartyFrameworks = [\n    'html-rsbuild',\n    'nuxt',\n    'qwik',\n    'react-rsbuild',\n    'solid',\n    'vue3-rsbuild',\n    'web-components-rsbuild',\n  ];\n  const destination = join(CORE_ROOT_DIR, 'src', 'types', 'modules', 'frameworks.ts');\n  const frameworksDirectory = join(CODE_DIR, 'frameworks');\n\n  const readFrameworks = (await readdir(frameworksDirectory)).filter((framework) =>\n    existsSync(join(frameworksDirectory, framework, 'package.json'))\n  );\n\n  const formatFramework = (framework: string) => {\n    const typedName = framework.replace(/-/g, '_').toUpperCase();\n    return `${typedName} = '${framework}'`;\n  };\n\n  const coreFrameworks = readFrameworks.sort().map(formatFramework).join(',\\n');\n  const communityFrameworks = thirdPartyFrameworks.sort().map(formatFramework).join(',\\n');\n\n  const { code: formatted } = await format(\n    'frameworks.ts',\n    dedent`\n      // auto generated file, do not edit\n      export enum SupportedFramework {\n        // CORE\n        ${coreFrameworks},\n        // COMMUNITY\n        ${communityFrameworks}\n      }\n    `,\n    { singleQuote: true }\n  );\n\n  await writeFile(destination, formatted);\n}\n\nconst localAlias = {\n  'storybook/internal': join(CORE_ROOT_DIR, 'src'),\n  'storybook/theming': join(CORE_ROOT_DIR, 'src', 'theming'),\n  'storybook/test': join(CORE_ROOT_DIR, 'src', 'test'),\n  'storybook/test/preview': join(CORE_ROOT_DIR, 'src', 'test', 'preview'),\n  'storybook/actions': join(CORE_ROOT_DIR, 'src', 'actions'),\n  'storybook/preview-api': join(CORE_ROOT_DIR, 'src', 'preview-api'),\n  'storybook/manager-api': join(CORE_ROOT_DIR, 'src', 'manager-api'),\n  storybook: join(CORE_ROOT_DIR, 'src'),\n};\nasync function generateExportsFile(): Promise<void> {\n  function removeDefault(input: string) {\n    return input !== 'default';\n  }\n\n  const destination = join(CORE_ROOT_DIR, 'src', 'manager', 'globals', 'exports.ts');\n\n  const entryFile = join(CORE_ROOT_DIR, 'src', 'manager', 'globals', 'runtime.ts');\n  const outFile = await temporaryFile({ extension: 'js' });\n\n  await esbuild.build({\n    entryPoints: [entryFile],\n    bundle: true,\n    format: 'esm',\n    drop: ['console'],\n    outfile: outFile,\n    alias: localAlias,\n    legalComments: 'none',\n    splitting: false,\n    platform: 'browser',\n    target: BROWSER_TARGETS,\n    supported: SUPPORTED_FEATURES,\n  });\n\n  const { globalsNameValueMap: data } = await import(pathToFileURL(outFile).href);\n\n  // loop over all values of the keys of the data object and remove the default key\n  for (const key in data) {\n    const value = data[key];\n    if (typeof value === 'object') {\n      data[key] = Object.keys(\n        Object.fromEntries(Object.entries(value).filter(([k]) => removeDefault(k)))\n      ).sort();\n    }\n  }\n\n  const { code: formatted } = await format(\n    'exports.ts',\n    dedent`\n      // this file is generated by sourcefiles.ts\n      // this is done to prevent runtime dependencies from making it's way into the build/start script of the manager\n      // the manager builder needs to know which dependencies are 'globalized' in the ui\n\n      export default ${JSON.stringify(data)} as const;\n    `,\n    { singleQuote: true }\n  );\n\n  await writeFile(destination, formatted);\n}\n\ngenerateSourceFiles();\n"
  },
  {
    "path": "code/core/src/ERRORS.md",
    "content": "# Storybook Errors\n\nStorybook provides a utility to manage errors thrown from it. Each error is categorized and coded, and there is an ESLint plugin which enforces their usage, instead of throwing generic errors like `throw new Error()`.\n\nStorybook errors reside in this package and are categorized into:\n\n1. **[Preview errors](./preview-errors.ts)**\n   - Errors which occur in the preview part of Storybook (where user code executes)\n   - e.g. Rendering issues, etc.\n   - available in `storybook/internal/preview-errors`\n2. **[Manager errors](./manager-errors.ts)**\n   - Errors which occur in the manager part of Storybook (manager UI)\n   - e.g. Sidebar, addons, Storybook UI, Storybook router, etc.\n   - available in `storybook/internal/server-errors`\n3. **[Server errors](./server-errors.ts)**\n   - Errors which occur in node\n   - e.g. Storybook init command, dev command, builder errors (Webpack, Vite), etc.\n   - available in `storybook/internal/server-errors`\n\n## How to create errors\n\nFirst, **find which file your error should be part of**, based on the criteria above.\nSecond use the `StorybookError` class to define custom errors with specific codes and categories for use within the Storybook codebase. Below is a detailed documentation for the error properties:\n\n### Class Structure\n\n```typescript\nimport { StorybookError } from './storybook-error';\n\nexport class YourCustomError extends StorybookError {\n  constructor() {\n    super({\n      // The category to which the error belongs. Check the source in client-errors.ts or server-errors.ts for reference.\n      category: Category,\n      // The numeric code for the error.\n      code: number,\n      // The error message.\n      message: string,\n    });\n  }\n}\n```\n\n### Properties\n\n| Name          | Type                  | Description                                                                                                                                                |\n| ------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| category      | `Category`            | The category to which the error belongs.                                                                                                                   |\n| code          | `number`              | The numeric code for the error.                                                                                                                            |\n| message       | `string`              | The error message.                                                                                                                                         |\n| data          | `Object`              | Optional. Data associated with the error. Used to provide additional information in the error message or to be passed to telemetry.                        |\n| documentation | `boolean` or `string` | Optional. Should be set to `true` **if the error is documented on the Storybook website**. If defined as string, it should be a custom documentation link. |\n\n## Usage Example\n\n```typescript\n// Define a custom error with a numeric code and a static error message template.\nexport class StorybookIndexGenerationError extends StorybookError {\n  constructor() {\n    super({\n      category: Category.Generic,\n      code: 1,\n      message: `Storybook failed when generating an index for your stories. Check the stories field in your main.js`,\n    });\n  }\n}\n\n// Define a custom error with a numeric code and a dynamic error message based on properties from the constructor.\nexport class InvalidFileExtensionError extends StorybookError {\n  // extra properties are defined in the constructor via a data property, which is available in any class method\n  // always use this data Object notation!\n  constructor(public data: { extension: string }) {\n    super({\n      category: Category.Validation,\n      code: 2,\n      documentation: 'https://some-custom-documentation.com/validation-errors',\n      message: `Invalid file extension found: ${data.extension}.`,\n    });\n  }\n}\n\n// import the errors where you need them, i.e.\nimport {\n  StorybookIndexGenerationError,\n  InvalidFileExtensionError,\n} from '@storybook/core-events/server-errors';\n\nthrow StorybookIndexGenerationError();\n// \"SB_Generic_0001: Storybook failed when generating an index for your stories. Check the stories field in your main.js.\n\nthrow InvalidFileExtensionError({ extension: 'mtsx' });\n// \"SB_Validation_0002: Invalid file extension found: mtsx. More info: https://some-custom-documentation.com/validation-errors\"\n```\n\n## How to write a proper error message\n\nWriting clear and informative error messages is crucial for effective debugging and troubleshooting. A well-crafted error message can save developers and users valuable time. Consider the following guidelines:\n\n- **Be clear and specific:** Provide straightforward error messages that precisely describe the issue.\n- **Include relevant context:** Add details about the error's origin and relevant context to aid troubleshooting.\n- **Provide guidance for resolution:** Offer actionable steps to resolve the error or suggest potential fixes.\n- **Provide documentation links:** Whenever applicable, provide links for users to get guidance or more context to fix their issues.\n\n<img src=\"./assets/docs/message-reference.png\" width=\"800px\" />\n\n✅ Here are a few recommended examples:\n\nLong:\n\n```\nCouldn't find story matching id 'component--button-primary' after HMR.\n  - Did you just rename a story?\n  - Did you remove it from your CSF file?\n  - Are you sure a story with the id 'component--button-primary' exists?\n  - Please check the values in the stories field of your main.js config and see if they would match your CSF File.\n  - Also check the browser console and terminal for potential error messages.\n```\n\nMedium:\n\n```\nAddon-docs no longer uses configureJsx or mdxBabelOptions in 7.0.\n\nTo update your configuration, please see migration instructions here:\n\nhttps://github.com/storybookjs/storybook/blob/next/MIGRATION.md#dropped-addon-docs-manual-babel-configuration\n```\n\nShort:\n\n```\nFailed to start Storybook.\n\nDo you have an error in your \\`preview.js\\`? Check your Storybook's browser console for errors.\n```\n\n❌ Here are a few unrecommended examples:\n\n```\noutputDir is required\n```\n\n```\nCannot render story\n```\n\n```\nno builder configured!\n```\n\n## What's the motivation for this errors framework?\n\nCentralizing and categorizing errors offers several advantages:\n\nBetter understanding of what is actually failing: By defining categories, error origins become more evident, easing the debugging process for developers and providing users with actionable insights.\n\nImproved Telemetry: Aggregating and filtering errors allows better assessment of their impact, which helps in prioritization and tackling the issues.\n\nImproved Documentation: Categorized errors lead to the creation of a helpful errors page on the Storybook website, benefiting users with better guidance and improving overall accessibility and user experience.\n"
  },
  {
    "path": "code/core/src/__mocks__/composeStories.txt",
    "content": "// THIS IS A MOCK FILE, DO NOT TOUCH\nconst Primary = composeStory(stories.Primary, stories.default)"
  },
  {
    "path": "code/core/src/__mocks__/composeStory.txt",
    "content": "// THIS IS A MOCK FILE, DO NOT TOUCH\nconst { Primary } = composeStories(stories)"
  },
  {
    "path": "code/core/src/__mocks__/page.ts",
    "content": "// empty file only matched on path\n"
  },
  {
    "path": "code/core/src/__mocks__/path/to/Screens/index.jsx",
    "content": "// empty file only matched on path\n"
  },
  {
    "path": "code/core/src/__tests/preview-errors.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { UnknownArgTypesError } from '../preview-errors.ts';\n\ndescribe('UnknownFlowArgTypesError', () => {\n  it('should correctly handle error with convertSig', () => {\n    const type = {\n      name: 'signature',\n      raw: \"SomeType['someProperty']\",\n    };\n\n    const typeError = new UnknownArgTypesError({ type, language: 'Typescript' });\n    expect(typeError.message).toMatchInlineSnapshot(`\n      \"There was a failure when generating detailed ArgTypes in Typescript for:\n      {\n        \"name\": \"signature\",\n        \"raw\": \"SomeType['someProperty']\"\n      } \n\n      Storybook will fall back to use a generic type description instead.\n\n      This type is either not supported or it is a bug in the docgen generation in Storybook.\n      If you think this is a bug, please detail it as much as possible in the Github issue.\n\n      More info: https://github.com/storybookjs/storybook/issues/26606\n      \"\n    `);\n  });\n});\n"
  },
  {
    "path": "code/core/src/__tests/server-errors.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { WebpackCompilationError } from '../server-errors.ts';\n\ndescribe('WebpackCompilationError', () => {\n  it('should correctly handle error with stats.compilation.errors', () => {\n    const errors = [\n      new Error('Error 1 \\u001B[4mmessage\\u001B[0m'),\n      new Error('\\u001B[4mError\\u001B[0m 2 message'),\n    ];\n\n    const webpackError = new WebpackCompilationError({ errors });\n\n    expect(webpackError.data.errors[0].message).toEqual('Error 1 message');\n    expect(webpackError.data.errors[1].message).toEqual('Error 2 message');\n  });\n});\n"
  },
  {
    "path": "code/core/src/__tests/storybook-error.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { StorybookError, appendErrorRef } from '../storybook-error.ts';\n\ndescribe('StorybookError', () => {\n  class TestError extends StorybookError {\n    constructor(documentation?: StorybookError['documentation']) {\n      super({\n        name: 'TestError',\n        category: 'TEST_CATEGORY',\n        code: 123,\n        message: 'This is a test error.',\n        documentation,\n      });\n    }\n  }\n\n  it('should generate the correct error name', () => {\n    const error = new TestError();\n    expect(error.name).toBe('SB_TEST_CATEGORY_0123 (TestError)');\n  });\n\n  it('should generate the correct message without documentation link', () => {\n    const error = new TestError();\n    const expectedMessage = 'This is a test error.';\n    expect(error.message).toBe(expectedMessage);\n  });\n\n  it('should generate the correct message with internal documentation link', () => {\n    const error = new TestError(true);\n    const expectedMessage =\n      'This is a test error.\\n\\nMore info: https://storybook.js.org/error/SB_TEST_CATEGORY_0123?ref=error\\n';\n    expect(error.message).toBe(expectedMessage);\n  });\n\n  it('should generate the correct message with external documentation link', () => {\n    const error = new TestError('https://example.com/docs/test-error');\n    expect(error.message).toMatchInlineSnapshot(`\n      \"This is a test error.\n\n      More info: https://example.com/docs/test-error\n      \"\n    `);\n  });\n\n  it('should generate the correct message with multiple external documentation links', () => {\n    const error = new TestError([\n      'https://example.com/docs/first-error',\n      'https://storybook.js.org/docs/second-error',\n    ]);\n    expect(error.message).toMatchInlineSnapshot(`\n      \"This is a test error.\n\n      More info: \n      \t- https://example.com/docs/first-error\n      \t- https://storybook.js.org/docs/second-error?ref=error\n      \"\n    `);\n  });\n\n  it('should have default documentation value of false', () => {\n    const error = new TestError();\n    expect(error.documentation).toBe(false);\n  });\n});\n\ndescribe('appendErrorRef', () => {\n  it('should append ref=error to storybook.js.org URLs without query parameters', () => {\n    const url = 'https://storybook.js.org/docs/example';\n    const result = appendErrorRef(url);\n    expect(result).toBe('https://storybook.js.org/docs/example?ref=error');\n  });\n\n  it('should append ref=error to storybook.js.org URLs with existing query parameters', () => {\n    const url = 'https://storybook.js.org/docs/example?foo=bar';\n    const result = appendErrorRef(url);\n    expect(result).toBe('https://storybook.js.org/docs/example?foo=bar&ref=error');\n  });\n\n  it('should append ref=error to storybook.js.org URLs with multiple existing query parameters', () => {\n    const url = 'https://storybook.js.org/docs/example?foo=bar&baz=qux';\n    const result = appendErrorRef(url);\n    expect(result).toBe('https://storybook.js.org/docs/example?foo=bar&baz=qux&ref=error');\n  });\n\n  it('should handle storybook.js.org URLs with hash fragments', () => {\n    const url = 'https://storybook.js.org/docs/example#section';\n    const result = appendErrorRef(url);\n    expect(result).toBe('https://storybook.js.org/docs/example?ref=error#section');\n  });\n\n  it('should handle storybook.js.org URLs with query parameters and hash fragments', () => {\n    const url = 'https://storybook.js.org/docs/example?foo=bar#section';\n    const result = appendErrorRef(url);\n    expect(result).toBe('https://storybook.js.org/docs/example?foo=bar&ref=error#section');\n  });\n\n  it('should not modify non-storybook.js.org URLs', () => {\n    const url = 'https://example.com/docs/test-error';\n    const result = appendErrorRef(url);\n    expect(result).toBe('https://example.com/docs/test-error');\n  });\n\n  it('should not modify relative URLs', () => {\n    const url = '/docs/example';\n    const result = appendErrorRef(url);\n    expect(result).toBe('/docs/example');\n  });\n\n  it('should not modify empty string URLs', () => {\n    const url = '';\n    const result = appendErrorRef(url);\n    expect(result).toBe('');\n  });\n\n  it('should not modify other domain URLs', () => {\n    const url = 'https://github.com/storybookjs/storybook/issues/123';\n    const result = appendErrorRef(url);\n    expect(result).toBe('https://github.com/storybookjs/storybook/issues/123');\n  });\n\n  it('should not append ref=error if it already exists in the URL', () => {\n    const url = 'https://storybook.js.org/docs/example?ref=error';\n    const result = appendErrorRef(url);\n    expect(result).toBe('https://storybook.js.org/docs/example?ref=error');\n  });\n\n  it('should not append ref=error if it already exists with other parameters', () => {\n    const url = 'https://storybook.js.org/docs/example?foo=bar&ref=error&baz=qux';\n    const result = appendErrorRef(url);\n    expect(result).toBe('https://storybook.js.org/docs/example?foo=bar&ref=error&baz=qux');\n  });\n\n  it('should not append ref=error if it already exists in URL with hash fragment', () => {\n    const url = 'https://storybook.js.org/docs/example?ref=error#target';\n    const result = appendErrorRef(url);\n    expect(result).toBe('https://storybook.js.org/docs/example?ref=error#target');\n  });\n\n  it('should append ref=error before hash fragment when no existing ref parameter', () => {\n    const url = 'https://storybook.js.org/docs/example#target';\n    const result = appendErrorRef(url);\n    expect(result).toBe('https://storybook.js.org/docs/example?ref=error#target');\n  });\n});\n"
  },
  {
    "path": "code/core/src/actions/README.md",
    "content": "# Storybook Actions\n\nThe basic usage is documented in the [documentation](https://storybook.js.org/docs/essentials/actions)\n"
  },
  {
    "path": "code/core/src/actions/addArgs.ts",
    "content": "import type { ArgsEnhancer } from 'storybook/internal/types';\n\nimport { addActionsFromArgTypes, inferActionsFromArgTypesRegex } from './addArgsHelpers.ts';\n\nexport const argsEnhancers: ArgsEnhancer[] = [\n  addActionsFromArgTypes,\n  inferActionsFromArgTypesRegex,\n];\n"
  },
  {
    "path": "code/core/src/actions/addArgsHelpers.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport type { StoryContext } from 'storybook/internal/types';\n\nimport { addActionsFromArgTypes, inferActionsFromArgTypesRegex } from './addArgsHelpers.ts';\n\ndescribe('actions parameter enhancers', () => {\n  describe('actions.argTypesRegex parameter', () => {\n    const parameters = { actions: { argTypesRegex: '^on.*' } };\n    const argTypes = { onClick: {}, onFocus: {}, somethingElse: {} };\n\n    it('should add actions that match a pattern', () => {\n      const args = inferActionsFromArgTypesRegex({\n        initialArgs: {},\n        argTypes,\n        parameters,\n      } as unknown as StoryContext);\n      expect(args).toEqual({\n        onClick: expect.any(Function),\n        onFocus: expect.any(Function),\n      });\n    });\n\n    it('should NOT override pre-existing args', () => {\n      const args = inferActionsFromArgTypesRegex({\n        initialArgs: { onClick: 'pre-existing value' },\n        argTypes,\n        parameters,\n      } as unknown as StoryContext);\n      expect(args).toEqual({ onFocus: expect.any(Function) });\n    });\n\n    it('should NOT override pre-existing args, if null', () => {\n      const args = inferActionsFromArgTypesRegex({\n        initialArgs: { onClick: null },\n        argTypes,\n        parameters,\n      } as unknown as StoryContext);\n      expect(args).toEqual({ onFocus: expect.any(Function) });\n    });\n\n    it('should override pre-existing args, if undefined', () => {\n      const args = inferActionsFromArgTypesRegex({\n        initialArgs: {},\n        argTypes,\n        parameters,\n      } as unknown as StoryContext);\n      expect(args).toEqual({ onClick: expect.any(Function), onFocus: expect.any(Function) });\n    });\n\n    it('should NOT override pre-existing args, if set undefined on purpose', () => {\n      const args = inferActionsFromArgTypesRegex({\n        initialArgs: { onClick: undefined },\n        argTypes,\n        parameters,\n      } as unknown as StoryContext);\n      expect(args).toEqual({ onClick: undefined, onFocus: expect.any(Function) });\n    });\n\n    it('should do nothing if actions are disabled', () => {\n      const args = inferActionsFromArgTypesRegex({\n        initialArgs: {},\n        argTypes,\n        parameters: {\n          ...parameters,\n          actions: { ...parameters.actions, disable: true },\n        },\n      } as unknown as StoryContext);\n      expect(args).toEqual({});\n    });\n  });\n\n  describe('argTypes.action parameter', () => {\n    const argTypes = {\n      onClick: { action: 'clicked!' },\n      onBlur: { action: 'blurred!' },\n    };\n    it('should add actions based on action.args', () => {\n      expect(\n        addActionsFromArgTypes({\n          initialArgs: {},\n          argTypes,\n          parameters: {},\n        } as unknown as StoryContext)\n      ).toEqual({\n        onClick: expect.any(Function),\n        onBlur: expect.any(Function),\n      });\n    });\n\n    it('should NOT override pre-existing args', () => {\n      expect(\n        addActionsFromArgTypes({\n          argTypes: { onClick: { action: 'clicked!' } },\n          initialArgs: { onClick: 'pre-existing value' },\n          parameters: {},\n        } as unknown as StoryContext)\n      ).toEqual({});\n    });\n\n    it('should NOT override pre-existing args, if null', () => {\n      expect(\n        addActionsFromArgTypes({\n          argTypes: { onClick: { action: 'clicked!' } },\n          initialArgs: { onClick: null },\n          parameters: {},\n        } as unknown as StoryContext)\n      ).toEqual({});\n    });\n\n    it('should override pre-existing args, if undefined', () => {\n      expect(\n        addActionsFromArgTypes({\n          argTypes: { onClick: { action: 'clicked!' } },\n          initialArgs: {},\n          parameters: {},\n        } as unknown as StoryContext)\n      ).toEqual({ onClick: expect.any(Function) });\n    });\n\n    it('should NOT override pre-existing args, if set undefined on purpose', () => {\n      expect(\n        addActionsFromArgTypes({\n          argTypes: { onClick: { action: 'clicked!' } },\n          initialArgs: { onClick: undefined },\n          parameters: {},\n        } as unknown as StoryContext)\n      ).toEqual({ onClick: undefined });\n    });\n\n    it('should do nothing if actions are disabled', () => {\n      expect(\n        addActionsFromArgTypes({\n          initialArgs: {},\n          argTypes,\n          parameters: { actions: { disable: true } },\n        } as unknown as StoryContext)\n      ).toEqual({});\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/actions/addArgsHelpers.ts",
    "content": "import type { Args, ArgsEnhancer, Renderer } from 'storybook/internal/types';\n\nimport { action } from './runtime/action.ts';\n\n// interface ActionsParameter {\n//   disable?: boolean;\n//   argTypesRegex?: RegExp;\n// }\n\nconst isInInitialArgs = (name: string, initialArgs: Args) =>\n  typeof initialArgs[name] === 'undefined' && !(name in initialArgs);\n\n/**\n * Automatically add action args for argTypes whose name matches a regex, such as `^on.*` for\n * react-style `onClick` etc.\n */\n\nexport const inferActionsFromArgTypesRegex: ArgsEnhancer<Renderer> = (context) => {\n  const {\n    initialArgs,\n    argTypes,\n    id,\n    parameters: { actions },\n  } = context;\n  if (!actions || actions.disable || !actions.argTypesRegex || !argTypes) {\n    return {};\n  }\n\n  const argTypesRegex = new RegExp(actions.argTypesRegex);\n  const argTypesMatchingRegex = Object.entries(argTypes).filter(\n    ([name]) => !!argTypesRegex.test(name)\n  );\n\n  return argTypesMatchingRegex.reduce((acc, [name, argType]) => {\n    if (isInInitialArgs(name, initialArgs)) {\n      acc[name] = action(name, { implicit: true, id });\n    }\n    return acc;\n  }, {} as Args);\n};\n\n/** Add action args for list of strings. */\nexport const addActionsFromArgTypes: ArgsEnhancer<Renderer> = (context) => {\n  const {\n    initialArgs,\n    argTypes,\n    parameters: { actions },\n  } = context;\n  if (actions?.disable || !argTypes) {\n    return {};\n  }\n\n  const argTypesWithAction = Object.entries(argTypes).filter(([name, argType]) => !!argType.action);\n\n  return argTypesWithAction.reduce((acc, [name, argType]) => {\n    if (isInInitialArgs(name, initialArgs)) {\n      acc[name] = action(typeof argType.action === 'string' ? argType.action : name);\n    }\n    return acc;\n  }, {} as Args);\n};\n"
  },
  {
    "path": "code/core/src/actions/components/ActionLogger/index.tsx",
    "content": "import type { ElementRef, ReactNode } from 'react';\nimport React, { Fragment, forwardRef, useEffect, useRef } from 'react';\n\nimport { ActionBar, ScrollArea } from 'storybook/internal/components';\n\nimport { Inspector } from 'react-inspector';\nimport type { Theme } from 'storybook/theming';\nimport { styled, withTheme } from 'storybook/theming';\n\nimport type { ActionDisplay } from '../../models/index.ts';\nimport { Action, Counter, InspectorContainer } from './style.tsx';\n\nconst UnstyledWrapped = forwardRef<HTMLDivElement, { children: ReactNode; className?: string }>(\n  ({ children, className }, ref) => (\n    <ScrollArea ref={ref} horizontal vertical className={className}>\n      {children}\n    </ScrollArea>\n  )\n);\nUnstyledWrapped.displayName = 'UnstyledWrapped';\n\nexport const Wrapper = styled(UnstyledWrapped)({\n  margin: 0,\n  padding: '10px 5px 20px',\n});\n\ninterface InspectorProps {\n  theme: Theme & { addonActionsTheme?: string };\n  sortObjectKeys: boolean;\n  showNonenumerable: boolean;\n  name: any;\n  data: any;\n  expandLevel?: number;\n}\n\nconst ThemedInspector = withTheme(({ theme, ...props }: InspectorProps) => (\n  <Inspector theme={theme.addonActionsTheme || 'chromeLight'} table={false} {...props} />\n));\n\ninterface ActionLoggerProps {\n  actions: ActionDisplay[];\n  expandLevel?: number;\n  onClear: () => void;\n}\n\nexport const ActionLogger = ({ actions, expandLevel, onClear }: ActionLoggerProps) => {\n  const wrapperRef = useRef<ElementRef<typeof Wrapper>>(null);\n  const wrapper = wrapperRef.current;\n  const wasAtBottom = wrapper && wrapper.scrollHeight - wrapper.scrollTop === wrapper.clientHeight;\n\n  useEffect(() => {\n    // Scroll to bottom, when the action panel was already scrolled down\n\n    // Scroll to bottom, when the action panel was already scrolled down\n    if (wasAtBottom) {\n      wrapperRef.current.scrollTop = wrapperRef.current.scrollHeight;\n    }\n  }, [wasAtBottom, actions.length]);\n\n  return (\n    <Fragment>\n      <Wrapper ref={wrapperRef}>\n        {actions.map((action: ActionDisplay) => (\n          <Action key={action.id}>\n            {action.count > 1 && <Counter>{action.count}</Counter>}\n            <InspectorContainer>\n              <ThemedInspector\n                sortObjectKeys\n                showNonenumerable={false}\n                name={action.data.name}\n                data={action.data.args ?? action.data}\n                expandLevel={expandLevel}\n              />\n            </InspectorContainer>\n          </Action>\n        ))}\n      </Wrapper>\n      <ActionBar actionItems={[{ title: 'Clear', onClick: onClear }]} />\n    </Fragment>\n  );\n};\n"
  },
  {
    "path": "code/core/src/actions/components/ActionLogger/style.tsx",
    "content": "import { opacify } from 'polished';\nimport { styled } from 'storybook/theming';\n\nexport const Action = styled.div({\n  display: 'flex',\n  padding: 0,\n  borderLeft: '5px solid transparent',\n  borderBottom: '1px solid transparent',\n  transition: 'all 0.1s',\n  alignItems: 'flex-start',\n  whiteSpace: 'pre',\n});\n\nexport const Counter = styled.div(({ theme }) => ({\n  backgroundColor: opacify(0.5, theme.appBorderColor),\n  color: theme.color.inverseText,\n  fontSize: theme.typography.size.s1,\n  fontWeight: theme.typography.weight.bold,\n  lineHeight: 1,\n  padding: '1px 5px',\n  borderRadius: 20,\n  margin: '2px 0px',\n}));\n\nexport const InspectorContainer = styled.div({\n  flex: 1,\n  padding: '0 0 0 5px',\n});\n"
  },
  {
    "path": "code/core/src/actions/components/Title.tsx",
    "content": "import React from 'react';\n\nimport { Badge } from 'storybook/internal/components';\nimport { STORY_CHANGED } from 'storybook/internal/core-events';\n\nimport { useAddonState, useChannel, useStorybookApi } from 'storybook/manager-api';\n\nimport { ADDON_ID, CLEAR_ID, EVENT_ID, PANEL_ID } from '../constants.ts';\n\nexport function Title() {\n  const api = useStorybookApi();\n  const selectedPanel = api.getSelectedPanel();\n  const [{ count }, setCount] = useAddonState(ADDON_ID, { count: 0 });\n\n  useChannel({\n    [EVENT_ID]: () => {\n      setCount((c) => ({ ...c, count: c.count + 1 }));\n    },\n    [STORY_CHANGED]: () => {\n      setCount((c) => ({ ...c, count: 0 }));\n    },\n    [CLEAR_ID]: () => {\n      setCount((c) => ({ ...c, count: 0 }));\n    },\n  });\n\n  const suffix =\n    count === 0 ? null : (\n      <Badge compact status={selectedPanel === PANEL_ID ? 'active' : 'neutral'}>\n        {count}\n      </Badge>\n    );\n\n  return (\n    <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>\n      <span>Actions</span>\n      {suffix}\n    </div>\n  );\n}\n"
  },
  {
    "path": "code/core/src/actions/constants.ts",
    "content": "export const PARAM_KEY = 'actions';\nexport const ADDON_ID = 'storybook/actions';\nexport const PANEL_ID = `${ADDON_ID}/panel`;\nexport const EVENT_ID = `${ADDON_ID}/action-event`;\nexport const CLEAR_ID = `${ADDON_ID}/action-clear`;\nexport const CYCLIC_KEY = '$___storybook.isCyclic';\n"
  },
  {
    "path": "code/core/src/actions/containers/ActionLogger/index.tsx",
    "content": "import React, { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { STORY_CHANGED } from 'storybook/internal/core-events';\n\nimport { dequal as deepEqual } from 'dequal';\nimport type { API } from 'storybook/manager-api';\nimport { useParameter } from 'storybook/manager-api';\n\nimport { ActionLogger as ActionLoggerComponent } from '../../components/ActionLogger/index.tsx';\nimport { CLEAR_ID, EVENT_ID, PARAM_KEY } from '../../constants.ts';\nimport type { ActionDisplay } from '../../models/index.ts';\nimport type { ActionsParameters } from '../../types.ts';\n\ninterface ActionLoggerProps {\n  active: boolean;\n  api: API;\n}\n\nconst safeDeepEqual = (a: any, b: any): boolean => {\n  try {\n    return deepEqual(a, b);\n  } catch (e) {\n    return false;\n  }\n};\n\nexport default function ActionLogger({ active, api }: ActionLoggerProps) {\n  const [actions, setActions] = useState<ActionDisplay[]>([]);\n  const parameter = useParameter<ActionsParameters['actions']>(PARAM_KEY);\n  const expandLevel = parameter?.expandLevel ?? 1;\n\n  const clearActions = useCallback(() => {\n    api.emit(CLEAR_ID);\n    setActions([]);\n  }, [api]);\n\n  const addAction = useCallback((action: ActionDisplay) => {\n    setActions((prevActions) => {\n      const newActions = [...prevActions];\n      const previous = newActions.length && newActions[newActions.length - 1];\n      if (previous && safeDeepEqual(previous.data, action.data)) {\n        previous.count++;\n      } else {\n        action.count = 1;\n        newActions.push(action);\n      }\n      return newActions.slice(0, action.options.limit);\n    });\n  }, []);\n\n  const handleStoryChange = useCallback(() => {\n    if (actions.length > 0 && actions[0].options.clearOnStoryChange) {\n      clearActions();\n    }\n  }, [actions, clearActions]);\n\n  useEffect(() => {\n    api.on(EVENT_ID, addAction);\n    api.on(STORY_CHANGED, handleStoryChange);\n\n    return () => {\n      api.off(EVENT_ID, addAction);\n      api.off(STORY_CHANGED, handleStoryChange);\n    };\n  }, [api, addAction, handleStoryChange]);\n\n  const props = useMemo(\n    () => ({\n      actions,\n      expandLevel,\n      onClear: clearActions,\n    }),\n    [actions, expandLevel, clearActions]\n  );\n\n  return active ? <ActionLoggerComponent {...props} /> : null;\n}\n"
  },
  {
    "path": "code/core/src/actions/decorator.ts",
    "content": "import type { PartialStoryFn, Renderer } from 'storybook/internal/types';\n\nimport { makeDecorator, useEffect } from 'storybook/preview-api';\n\nimport { PARAM_KEY } from './constants.ts';\nimport { actions } from './runtime/actions.ts';\n\nconst delegateEventSplitter = /^(\\S+)\\s*(.*)$/;\n\nconst isIE = Element != null && !Element.prototype.matches;\nconst matchesMethod = isIE ? 'msMatchesSelector' : 'matches';\n\nconst hasMatchInAncestry = (element: any, selector: any): boolean => {\n  if (element[matchesMethod](selector)) {\n    return true;\n  }\n  const parent = element.parentElement;\n  if (!parent) {\n    return false;\n  }\n  return hasMatchInAncestry(parent, selector);\n};\n\nconst createHandlers = (actionsFn: (...arg: any[]) => object, ...handles: any[]) => {\n  const actionsObject = actionsFn(...handles);\n  return Object.entries(actionsObject).map(([key, action]) => {\n    const [_, eventName, selector] = key.match(delegateEventSplitter) || [];\n    return {\n      eventName,\n      handler: (e: { target: any }) => {\n        if (!selector || hasMatchInAncestry(e.target, selector)) {\n          action(e);\n        }\n      },\n    };\n  });\n};\n\nconst applyEventHandlers = (actionsFn: any, ...handles: any[]) => {\n  const root =\n    typeof globalThis.document !== 'undefined' &&\n    globalThis.document.getElementById('storybook-root');\n  useEffect(() => {\n    if (root) {\n      const handlers = createHandlers(actionsFn, ...handles);\n      handlers.forEach(({ eventName, handler }) => root.addEventListener(eventName, handler));\n      return () =>\n        handlers.forEach(({ eventName, handler }) => root.removeEventListener(eventName, handler));\n    }\n    return undefined;\n  }, [root, actionsFn, handles]);\n};\n\n// This type is basically the same as DecoratorFunction from storybook/internal/types.\n// We can not use DecoratorFunction though as the type has to be generic.\n// Hard to explain, but you will understand when you try to solve this issue:\n// https://github.com/storybookjs/storybook/issues/22384\n/** @deprecated Will be removed in Storybook v10 */\nexport const withActions: <T extends Renderer>(storyFn: PartialStoryFn<T>) => T['storyResult'] =\n  makeDecorator({\n    name: 'withActions',\n    parameterName: PARAM_KEY,\n    skipIfNoParametersOrOptions: true,\n    wrapper: (getStory, context, { parameters }) => {\n      if (parameters?.handles) {\n        applyEventHandlers(actions, ...parameters.handles);\n      }\n\n      return getStory(context);\n    },\n  });\n"
  },
  {
    "path": "code/core/src/actions/index.ts",
    "content": "export * from './constants.ts';\nexport * from './models/index.ts';\nexport * from './runtime/index.ts';\n"
  },
  {
    "path": "code/core/src/actions/loaders.ts",
    "content": "import type { LoaderFunction } from 'storybook/internal/types';\n\nimport { onMockCall } from 'storybook/test';\n\nimport { action } from './runtime/index.ts';\n\nlet subscribed = false;\n\nconst logActionsWhenMockCalled: LoaderFunction = (context) => {\n  const { parameters } = context;\n\n  if (parameters?.actions?.disable) {\n    return;\n  }\n\n  if (!subscribed) {\n    onMockCall((mock, args) => {\n      const name = mock.getMockName();\n\n      // Default name provided by vi.fn(), which we don't want to log.\n      // TODO: Can be removed as soon as we drop Vitest 3 support\n      // https://main.vitest.dev/guide/migration.html#changes-to-mocking\n      if (name === 'spy') {\n        return;\n      }\n\n      // Escape hatch allowing users to disable logging for specific spies.\n      // This is what Vitest sets when you pass `mockName('')` to a spy.\n      if (name === 'vi.fn()') {\n        return;\n      }\n\n      // TODO: Make this a configurable API in 8.2\n      if (\n        !/^next\\/.*::/.test(name) ||\n        [\n          'next/router::useRouter()',\n          'next/navigation::useRouter()',\n          'next/navigation::redirect',\n          'next/cache::',\n          'next/headers::cookies().set',\n          'next/headers::cookies().delete',\n          'next/headers::headers().set',\n          'next/headers::headers().delete',\n        ].some((prefix) => name.startsWith(prefix))\n      ) {\n        action(name)(args);\n      }\n    });\n    subscribed = true;\n  }\n};\n\nexport const loaders: LoaderFunction[] = [logActionsWhenMockCalled];\n"
  },
  {
    "path": "code/core/src/actions/manager.tsx",
    "content": "import React from 'react';\n\nimport { addons, types } from 'storybook/manager-api';\n\nimport { Title } from './components/Title.tsx';\nimport { ADDON_ID, PANEL_ID, PARAM_KEY } from './constants.ts';\nimport ActionLogger from './containers/ActionLogger/index.tsx';\n\nexport default addons.register(ADDON_ID, (api) => {\n  if (globalThis?.FEATURES?.actions) {\n    addons.add(PANEL_ID, {\n      title: Title,\n      type: types.PANEL,\n      render: ({ active }) => <ActionLogger api={api} active={!!active} />,\n      paramKey: PARAM_KEY,\n    });\n  }\n});\n"
  },
  {
    "path": "code/core/src/actions/models/ActionDisplay.ts",
    "content": "import type { ActionOptions } from './ActionOptions.ts';\n\nexport interface ActionDisplay {\n  id: string;\n  data: {\n    name: string;\n    args: any[];\n  };\n  count: number;\n  options: ActionOptions;\n}\n"
  },
  {
    "path": "code/core/src/actions/models/ActionOptions.ts",
    "content": "import type { Options as TelejsonOptions } from 'telejson';\n\ninterface Options {\n  depth: number; // backwards compatibility, remove in 7.0\n  clearOnStoryChange: boolean;\n  limit: number;\n  implicit: boolean;\n  id: string;\n}\n\nexport type ActionOptions = Partial<Options> & Partial<TelejsonOptions>;\n"
  },
  {
    "path": "code/core/src/actions/models/ActionsFunction.ts",
    "content": "import type { ActionOptions } from './ActionOptions.ts';\nimport type { ActionsMap } from './ActionsMap.ts';\n\nexport interface ActionsFunction {\n  <T extends string>(handlerMap: Record<T, string>, options?: ActionOptions): ActionsMap<T>;\n  <T extends string>(...handlers: T[]): ActionsMap<T>;\n\n  <T extends string>(handler1: T, options?: ActionOptions): ActionsMap<T>;\n  <T extends string>(handler1: T, handler2: T, options?: ActionOptions): ActionsMap<T>;\n  <T extends string>(handler1: T, handler2: T, handler3: T, options?: ActionOptions): ActionsMap<T>;\n  <T extends string>(\n    handler1: T,\n    handler2: T,\n    handler3: T,\n    handler4: T,\n    options?: ActionOptions\n  ): ActionsMap<T>;\n  <T extends string>(\n    handler1: T,\n    handler2: T,\n    handler3: T,\n    handler4: T,\n    handler5: T,\n    options?: ActionOptions\n  ): ActionsMap<T>;\n  <T extends string>(\n    handler1: T,\n    handler2: T,\n    handler3: T,\n    handler4: T,\n    handler5: T,\n    handler6: T,\n    options?: ActionOptions\n  ): ActionsMap<T>;\n  <T extends string>(\n    handler1: T,\n    handler2: T,\n    handler3: T,\n    handler4: T,\n    handler5: T,\n    handler6: T,\n    handler7: T,\n    options?: ActionOptions\n  ): ActionsMap<T>;\n  <T extends string>(\n    handler1: T,\n    handler2: T,\n    handler3: T,\n    handler4: T,\n    handler5: T,\n    handler6: T,\n    handler7: T,\n    handler8: T,\n    options?: ActionOptions\n  ): ActionsMap<T>;\n  <T extends string>(\n    handler1: T,\n    handler2: T,\n    handler3: T,\n    handler4: T,\n    handler5: T,\n    handler6: T,\n    handler7: T,\n    handler8: T,\n    handler9: T,\n    options?: ActionOptions\n  ): ActionsMap<T>;\n  <T extends string>(\n    handler1: T,\n    handler2: T,\n    handler3: T,\n    handler4: T,\n    handler5: T,\n    handler6: T,\n    handler7: T,\n    handler8: T,\n    handler9: T,\n    handler10: T,\n    options?: ActionOptions\n  ): ActionsMap<T>;\n}\n"
  },
  {
    "path": "code/core/src/actions/models/ActionsMap.ts",
    "content": "import type { HandlerFunction } from './HandlerFunction.ts';\n\nexport type ActionsMap<T extends string = string> = Record<T, HandlerFunction>;\n"
  },
  {
    "path": "code/core/src/actions/models/DecoratorFunction.ts",
    "content": "export type DecoratorFunction = (args: any[]) => any[];\n"
  },
  {
    "path": "code/core/src/actions/models/HandlerFunction.test-d.ts",
    "content": "import { expectTypeOf } from 'vitest';\n\nimport type { HandlerFunction } from './HandlerFunction.ts';\n\n// Should be assignable to async callback props (the fixed case)\nexpectTypeOf<HandlerFunction>().toExtend<() => Promise<void>>();\n\n// Should remain assignable to plain void callbacks\nexpectTypeOf<HandlerFunction>().toExtend<() => void>();\n"
  },
  {
    "path": "code/core/src/actions/models/HandlerFunction.ts",
    "content": "export type HandlerFunction = (...args: any[]) => any;\n"
  },
  {
    "path": "code/core/src/actions/models/index.ts",
    "content": "export * from './ActionDisplay.ts';\nexport * from './ActionsFunction.ts';\nexport * from './ActionOptions.ts';\nexport * from './ActionsMap.ts';\nexport * from './DecoratorFunction.ts';\nexport * from './HandlerFunction.ts';\n"
  },
  {
    "path": "code/core/src/actions/preview.ts",
    "content": "import { definePreviewAddon } from 'storybook/internal/csf';\n\nimport * as addArgs from './addArgs.ts';\nimport * as loaders from './loaders.ts';\nimport type { ActionsTypes } from './types.ts';\n\nexport type { ActionsTypes };\n\nexport default () =>\n  definePreviewAddon<ActionsTypes>({\n    ...addArgs,\n    ...loaders,\n  });\n"
  },
  {
    "path": "code/core/src/actions/runtime/__tests__/action.test.js",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { addons } from 'storybook/preview-api';\n\nimport { action, configureActions } from '../..';\n\nvi.mock('storybook/preview-api');\n\nconst createChannel = () => {\n  const channel = { emit: vi.fn() };\n  addons.getChannel.mockReturnValue(channel);\n  return channel;\n};\nconst getChannelData = (channel) => channel.emit.mock.calls[0][1].data.args;\n\ndescribe('Action', () => {\n  it('with one argument', () => {\n    const channel = createChannel();\n\n    action('test-action')('one');\n\n    expect(getChannelData(channel)).toEqual('one');\n  });\n\n  it('with multiple arguments', () => {\n    const channel = createChannel();\n\n    action('test-action')('one', 'two', 'three');\n\n    expect(getChannelData(channel)).toEqual(['one', 'two', 'three']);\n  });\n});\n\ndescribe('Depth config', () => {\n  it('with global depth configuration', () => {\n    const channel = createChannel();\n\n    const depth = 1;\n\n    configureActions({\n      depth,\n    });\n\n    action('test-action')({\n      root: {\n        one: {\n          two: 'foo',\n        },\n      },\n    });\n\n    expect(getChannelData(channel)).toEqual({\n      root: {\n        one: {\n          two: 'foo',\n        },\n      },\n    });\n  });\n\n  it('per action depth option overrides global config', () => {\n    const channel = createChannel();\n\n    configureActions({\n      depth: 1,\n    });\n\n    action('test-action', { depth: 3 })({\n      root: {\n        one: {\n          two: {\n            three: {\n              four: {\n                five: 'foo',\n              },\n            },\n          },\n        },\n      },\n    });\n\n    expect(getChannelData(channel)).toEqual({\n      root: {\n        one: {\n          two: {\n            three: {\n              four: {\n                five: 'foo',\n              },\n            },\n          },\n        },\n      },\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/actions/runtime/__tests__/actions.test.js",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { addons } from 'storybook/preview-api';\n\nimport { actions } from '../..';\n\nvi.mock('storybook/preview-api');\n\nconst createChannel = () => {\n  const channel = { emit: vi.fn() };\n  addons.getChannel.mockReturnValue(channel);\n  return channel;\n};\nconst getChannelData = (channel, callIndex) => channel.emit.mock.calls[callIndex][1].data;\nconst getChannelOptions = (channel, callIndex) => channel.emit.mock.calls[callIndex][1].options;\n\ndescribe('Actions', () => {\n  it('with one argument', () => {\n    const channel = createChannel();\n\n    const actionsResult = actions('test-action');\n\n    expect(Object.keys(actionsResult)).toEqual(['test-action']);\n    actionsResult['test-action']('one');\n\n    expect(getChannelData(channel, 0)).toEqual({ name: 'test-action', args: 'one' });\n  });\n\n  it('with multiple arguments', () => {\n    const channel = createChannel();\n\n    const actionsResult = actions('test-action', 'test-action2');\n\n    expect(Object.keys(actionsResult)).toEqual(['test-action', 'test-action2']);\n\n    actionsResult['test-action']('one');\n    actionsResult['test-action2']('two');\n\n    expect(getChannelData(channel, 0)).toEqual({ name: 'test-action', args: 'one' });\n    expect(getChannelData(channel, 1)).toEqual({ name: 'test-action2', args: 'two' });\n  });\n\n  it('with multiple arguments + config', () => {\n    const channel = createChannel();\n\n    const actionsResult = actions('test-action', 'test-action2', { some: 'config' });\n\n    expect(Object.keys(actionsResult)).toEqual(['test-action', 'test-action2']);\n\n    actionsResult['test-action']('one');\n    actionsResult['test-action2']('two');\n\n    expect(getChannelData(channel, 0)).toEqual({ name: 'test-action', args: 'one' });\n    expect(getChannelData(channel, 1)).toEqual({ name: 'test-action2', args: 'two' });\n\n    expect(getChannelOptions(channel, 0).some).toEqual('config');\n    expect(getChannelOptions(channel, 1).some).toEqual('config');\n  });\n\n  it('with multiple arguments as object', () => {\n    const channel = createChannel();\n\n    const actionsResult = actions({\n      'test-action': 'test action',\n      'test-action2': 'test action two',\n    });\n\n    expect(Object.keys(actionsResult)).toEqual(['test-action', 'test-action2']);\n\n    actionsResult['test-action']('one');\n    actionsResult['test-action2']('two');\n\n    expect(getChannelData(channel, 0)).toEqual({ name: 'test action', args: 'one' });\n    expect(getChannelData(channel, 1)).toEqual({ name: 'test action two', args: 'two' });\n  });\n\n  it('with first argument as array of arguments + config', () => {\n    const channel = createChannel();\n\n    const actionsResult = actions(['test-action', 'test-action2', { some: 'config' }]);\n\n    expect(Object.keys(actionsResult)).toEqual(['test-action', 'test-action2']);\n\n    actionsResult['test-action']('one');\n    actionsResult['test-action2']('two');\n\n    expect(getChannelData(channel, 0)).toEqual({ name: 'test-action', args: 'one' });\n    expect(getChannelData(channel, 1)).toEqual({ name: 'test-action2', args: 'two' });\n\n    expect(getChannelOptions(channel, 0).some).toEqual('config');\n    expect(getChannelOptions(channel, 1).some).toEqual('config');\n  });\n});\n"
  },
  {
    "path": "code/core/src/actions/runtime/__tests__/configureActions.test.js",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { configureActions } from '../..';\nimport { config } from '../configureActions';\n\ndescribe('Configure Actions', () => {\n  it('can configure actions', () => {\n    const depth = 100;\n    const clearOnStoryChange = false;\n    const limit = 20;\n\n    configureActions({\n      depth,\n      clearOnStoryChange,\n      limit,\n    });\n\n    expect(config).toEqual({\n      depth,\n      clearOnStoryChange,\n      limit,\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/actions/runtime/action.ts",
    "content": "import { ImplicitActionsDuringRendering } from 'storybook/internal/preview-errors';\nimport type { Renderer } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport type { PreviewWeb } from 'storybook/preview-api';\nimport { addons } from 'storybook/preview-api';\n\nimport { EVENT_ID } from '../constants.ts';\nimport type { ActionDisplay, ActionOptions, HandlerFunction } from '../models/index.ts';\nimport { config } from './configureActions.ts';\n\ntype SyntheticEvent = any; // import('react').SyntheticEvent;\nconst findProto = (obj: unknown, callback: (proto: any) => boolean): Function | null => {\n  const proto = Object.getPrototypeOf(obj);\n\n  if (!proto || callback(proto)) {\n    return proto;\n  }\n  return findProto(proto, callback);\n};\nconst isReactSyntheticEvent = (e: unknown): e is SyntheticEvent =>\n  Boolean(\n    typeof e === 'object' &&\n    e &&\n    findProto(e, (proto) => /^Synthetic(?:Base)?Event$/.test(proto.constructor.name)) &&\n    typeof (e as SyntheticEvent).persist === 'function'\n  );\nconst serializeArg = <T extends object>(a: T) => {\n  if (isReactSyntheticEvent(a)) {\n    const e: SyntheticEvent = Object.create(\n      a.constructor.prototype,\n      Object.getOwnPropertyDescriptors(a)\n    );\n    e.persist();\n    const viewDescriptor = Object.getOwnPropertyDescriptor(e, 'view');\n    // don't send the entire window object over.\n    const view: unknown = viewDescriptor?.value;\n    if (typeof view === 'object' && view?.constructor.name === 'Window') {\n      Object.defineProperty(e, 'view', {\n        ...viewDescriptor,\n        value: Object.create(view.constructor.prototype),\n      });\n    }\n    return e;\n  }\n  return a;\n};\n\nexport function action(name: string, options: ActionOptions = {}): HandlerFunction {\n  const actionOptions = {\n    ...config,\n    ...options,\n  };\n\n  const handler = function actionHandler(...args: any[]) {\n    if (options.implicit) {\n      const preview =\n        '__STORYBOOK_PREVIEW__' in global\n          ? (global.__STORYBOOK_PREVIEW__ as unknown as PreviewWeb<Renderer>)\n          : undefined;\n      const storyRenderer = preview?.storyRenders.find(\n        (render) => render.phase === 'playing' || render.phase === 'rendering'\n      );\n\n      if (storyRenderer) {\n        const deprecated = !globalThis?.FEATURES?.disallowImplicitActionsInRenderV8;\n        const error = new ImplicitActionsDuringRendering({\n          phase: storyRenderer.phase!,\n          name,\n          deprecated,\n        });\n        if (deprecated) {\n          console.warn(error);\n        } else {\n          throw error;\n        }\n      }\n    }\n\n    const channel = addons.getChannel();\n    // TODO react native doesn't have the crypto module, we should figure out a better way to generate these ids.\n    // pseudo random id, example response lo1e7zm4832bkr7yfl7\n    const id = Date.now().toString(36) + Math.random().toString(36).substring(2);\n    const minDepth = 5; // anything less is really just storybook internals\n    const serializedArgs = args.map(serializeArg);\n    const normalizedArgs = args.length > 1 ? serializedArgs : serializedArgs[0];\n\n    const actionDisplayToEmit: ActionDisplay = {\n      id,\n      count: 0,\n      data: { name, args: normalizedArgs },\n      options: {\n        ...actionOptions,\n        maxDepth: minDepth + (actionOptions.depth || 3),\n      },\n    };\n    channel.emit(EVENT_ID, actionDisplayToEmit);\n  };\n  handler.isAction = true;\n  handler.implicit = options.implicit;\n\n  return handler;\n}\n"
  },
  {
    "path": "code/core/src/actions/runtime/actions.ts",
    "content": "import type { ActionOptions, ActionsFunction, ActionsMap } from '../models/index.ts';\nimport { action } from './action.ts';\nimport { config } from './configureActions.ts';\n\nexport const actions: ActionsFunction = (...args: any[]) => {\n  let options: ActionOptions = config;\n  let names = args;\n  // args argument can be a single argument as an array\n  if (names.length === 1 && Array.isArray(names[0])) {\n    [names] = names;\n  }\n  // last argument can be options\n  if (names.length !== 1 && typeof names[names.length - 1] !== 'string') {\n    options = {\n      ...config,\n      ...names.pop(),\n    };\n  }\n\n  let namesObject = names[0];\n  if (names.length !== 1 || typeof namesObject === 'string') {\n    namesObject = {};\n    names.forEach((name) => {\n      namesObject[name] = name;\n    });\n  }\n\n  const actionsObject: ActionsMap = {};\n  Object.keys(namesObject).forEach((name) => {\n    actionsObject[name] = action(namesObject[name], options);\n  });\n  return actionsObject;\n};\n"
  },
  {
    "path": "code/core/src/actions/runtime/configureActions.ts",
    "content": "import type { ActionOptions } from '../models/index.ts';\n\nexport const config: ActionOptions = {\n  depth: 10,\n  clearOnStoryChange: true,\n  limit: 50,\n};\n\nexport const configureActions = (options: ActionOptions = {}): void => {\n  Object.assign(config, options);\n};\n"
  },
  {
    "path": "code/core/src/actions/runtime/index.ts",
    "content": "export * from './action.ts';\nexport * from './actions.ts';\nexport * from './configureActions.ts';\n"
  },
  {
    "path": "code/core/src/actions/types.ts",
    "content": "export interface ActionsParameters {\n  /**\n   * Actions configuration\n   *\n   * @see https://storybook.js.org/docs/essentials/actions#parameters\n   */\n  actions?: {\n    /**\n     * Create actions for each arg that matches the regex. (**NOT recommended, see below**)\n     *\n     * This is quite useful when your component has dozens (or hundreds) of methods and you do not\n     * want to manually apply the fn utility for each of those methods. However, this is not the\n     * recommended way of writing actions. That's because automatically inferred args are not\n     * available as spies in your play function. If you use argTypesRegex and your stories have play\n     * functions, you will need to also define args with the fn utility to test them in your play\n     * function.\n     *\n     * @example `argTypesRegex: '^on.*'`\n     */\n    argTypesRegex?: string;\n\n    /**\n     * Removes the addon panel and turns off the feature's behavior. If you wish to turn off this\n     * feature for the entire Storybook, you can set the option in your `main.js|ts` configuration\n     * file.\n     *\n     * @see https://storybook.js.org/docs/essentials/actions#disable\n     */\n    disable?: boolean;\n\n    /**\n     * Binds a standard HTML event handler to the outermost HTML element rendered by your component\n     * and triggers an action when the event is called for a given selector. The format is\n     * `<eventname> <selector>`. The selector is optional; it defaults to all elements.\n     *\n     * **To enable this feature, you must use the `withActions` decorator.**\n     *\n     * @example `handles: ['mouseover', 'click .btn']`\n     */\n    handles?: string[];\n\n    /**\n     * An integer specifying to which level the tree should be initially expanded.\n     *\n     * @default 1\n     */\n    expandLevel?: number;\n  };\n}\n\nexport interface ActionsTypes {\n  parameters: ActionsParameters;\n}\n"
  },
  {
    "path": "code/core/src/actions/typings.d.ts",
    "content": "declare var FEATURES: import('storybook/internal/types').StorybookConfigRaw['features'];\n"
  },
  {
    "path": "code/core/src/babel/babelParse.ts",
    "content": "import * as parser from '@babel/parser';\nimport type { ParserOptions } from '@babel/parser';\nimport type * as t from '@babel/types';\nimport * as recast from 'recast';\n\nfunction parseWithFlowOrTypescript(source: string, parserOptions: parser.ParserOptions) {\n  const flowCommentPattern = /^\\s*\\/\\/\\s*@flow/;\n  const useFlowPlugin = flowCommentPattern.test(source);\n\n  const parserPlugins: parser.ParserOptions['plugins'] = useFlowPlugin ? ['flow'] : ['typescript'];\n\n  // Merge the provided parserOptions with the custom parser plugins\n  const mergedParserOptions = {\n    ...parserOptions,\n    plugins: [...(parserOptions.plugins ?? []), ...parserPlugins],\n  };\n\n  return parser.parse(source, mergedParserOptions);\n}\n\nexport const parserOptions: ParserOptions = {\n  sourceType: 'module',\n  // FIXME: we should get this from the project config somehow?\n  plugins: ['jsx', 'decorators-legacy', 'classProperties'],\n  tokens: true,\n};\n\nexport const babelParse = (code: string): t.File => {\n  return recast.parse(code, {\n    parser: {\n      parse(source: string) {\n        return parseWithFlowOrTypescript(source, parserOptions);\n      },\n    },\n  });\n};\n\ninterface ASTNode {\n  type: string;\n}\n\nexport const babelPrint = (ast: ASTNode): string => {\n  return recast.print(ast, {\n    quote: 'single',\n    trailingComma: true,\n    tabWidth: 2,\n    wrapColumn: 80,\n    arrowParensAlways: true,\n  }).code;\n};\n\nexport const babelParseExpression = (code: string): parser.ParseResult<t.Expression> => {\n  return parser.parseExpression(code, parserOptions);\n};\n"
  },
  {
    "path": "code/core/src/babel/expression-resolver.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport * as parser from '@babel/parser';\n\nimport { resolveExpression, unwrapTSExpression } from './expression-resolver.ts';\n\nconst parse = (code: string) =>\n  parser.parse(code, {\n    sourceType: 'module',\n    plugins: ['typescript'],\n  });\n\ndescribe('unwrapTSExpression', () => {\n  it('returns non-TS-wrapped expressions unchanged', () => {\n    const ast = parse('42');\n    const numLiteral = (ast.program.body[0] as any).expression;\n    expect(unwrapTSExpression(numLiteral)).toBe(numLiteral);\n  });\n\n  it('unwraps TSAsExpression', () => {\n    const ast = parse('foo as string');\n    const asExpr = (ast.program.body[0] as any).expression;\n    const result = unwrapTSExpression(asExpr);\n    expect(result.type).toBe('Identifier');\n    expect((result as any).name).toBe('foo');\n  });\n\n  it('unwraps TSSatisfiesExpression', () => {\n    const ast = parse('foo satisfies string');\n    const satisfiesExpr = (ast.program.body[0] as any).expression;\n    const result = unwrapTSExpression(satisfiesExpr);\n    expect(result.type).toBe('Identifier');\n    expect((result as any).name).toBe('foo');\n  });\n\n  it('unwraps TSTypeAssertion (<string>foo)', () => {\n    const ast = parser.parse('<string>foo', {\n      sourceType: 'module',\n      plugins: [['typescript', { dts: false }]],\n    });\n    const typeAssertion = (ast.program.body[0] as any).expression;\n    const result = unwrapTSExpression(typeAssertion);\n    expect(result.type).toBe('Identifier');\n    expect((result as any).name).toBe('foo');\n  });\n\n  it('unwraps nested TS wrappers', () => {\n    const ast = parse('(foo as any) satisfies string');\n    const outer = (ast.program.body[0] as any).expression;\n    const result = unwrapTSExpression(outer);\n    expect(result.type).toBe('Identifier');\n    expect((result as any).name).toBe('foo');\n  });\n});\n\ndescribe('resolveExpression', () => {\n  it('returns null for null/undefined input', () => {\n    const ast = parse('');\n    expect(resolveExpression(null, ast)).toBeNull();\n    expect(resolveExpression(undefined, ast)).toBeNull();\n  });\n\n  it('returns non-Identifier expressions directly', () => {\n    const ast = parse('42');\n    const numLiteral = (ast.program.body[0] as any).expression;\n    expect(resolveExpression(numLiteral, ast)).toBe(numLiteral);\n  });\n\n  it('resolves a bare VariableDeclaration', () => {\n    const ast = parse(`\n      const foo = { a: 1 };\n      export default foo;\n    `);\n    const defaultExport = ast.program.body[1] as any;\n    const result = resolveExpression(defaultExport.declaration, ast);\n    expect(result?.type).toBe('ObjectExpression');\n  });\n\n  it('resolves an exported const (ExportNamedDeclaration)', () => {\n    const ast = parse(`\n      export const config = { a: 1 };\n      export default config;\n    `);\n    const defaultExport = ast.program.body[1] as any;\n    const result = resolveExpression(defaultExport.declaration, ast);\n    expect(result?.type).toBe('ObjectExpression');\n  });\n\n  it('resolves a chain of variable references', () => {\n    const ast = parse(`\n      const inner = { a: 1 };\n      const outer = inner;\n      export default outer;\n    `);\n    const defaultExport = ast.program.body[2] as any;\n    const result = resolveExpression(defaultExport.declaration, ast);\n    expect(result?.type).toBe('ObjectExpression');\n  });\n\n  it('resolves through TSAsExpression', () => {\n    const ast = parse(`\n      const foo = { a: 1 };\n      export default foo as any;\n    `);\n    const defaultExport = ast.program.body[1] as any;\n    const result = resolveExpression(defaultExport.declaration, ast);\n    expect(result?.type).toBe('ObjectExpression');\n  });\n\n  it('resolves through TSSatisfiesExpression', () => {\n    const ast = parse(`\n      const foo = { a: 1 };\n      export default foo satisfies object;\n    `);\n    const defaultExport = ast.program.body[1] as any;\n    const result = resolveExpression(defaultExport.declaration, ast);\n    expect(result?.type).toBe('ObjectExpression');\n  });\n\n  it('returns the Identifier node when variable is not found', () => {\n    const ast = parse(`export default unknown;`);\n    const defaultExport = ast.program.body[0] as any;\n    const result = resolveExpression(defaultExport.declaration, ast);\n    expect(result?.type).toBe('Identifier');\n    expect((result as any).name).toBe('unknown');\n  });\n\n  it('returns the Identifier node when variable has no initializer', () => {\n    const ast = parse(`\n      let foo;\n      export default foo;\n    `);\n    const defaultExport = ast.program.body[1] as any;\n    const result = resolveExpression(defaultExport.declaration, ast);\n    expect(result?.type).toBe('Identifier');\n    expect((result as any).name).toBe('foo');\n  });\n\n  it('returns null when maxDepth is exceeded', () => {\n    // Create a chain longer than maxDepth (default 10)\n    const lines = Array.from({ length: 12 }, (_, i) =>\n      i === 0 ? `const v0 = { a: 1 };` : `const v${i} = v${i - 1};`\n    ).join('\\n');\n    const ast = parse(`${lines}\\nexport default v11;`);\n    const defaultExport = ast.program.body[ast.program.body.length - 1] as any;\n    const result = resolveExpression(defaultExport.declaration, ast);\n    // Depth exceeded — returns null\n    expect(result).toBeNull();\n  });\n});\n"
  },
  {
    "path": "code/core/src/babel/expression-resolver.ts",
    "content": "import type * as t from '@babel/types';\n\n/** Recursively unwraps TypeScript type annotation expressions (as X, satisfies X, <X>expr). */\nexport const unwrapTSExpression = (expr: t.Expression | t.Declaration): t.Expression => {\n  if (\n    expr.type === 'TSAsExpression' ||\n    expr.type === 'TSSatisfiesExpression' ||\n    expr.type === 'TSTypeAssertion'\n  ) {\n    return unwrapTSExpression(\n      (expr as t.TSAsExpression | t.TSSatisfiesExpression | t.TSTypeAssertion).expression\n    );\n  }\n  return expr as t.Expression;\n};\n\n/**\n * Resolves an expression through variable references and TypeScript type annotations. Handles:\n * Identifier (variable lookup), TSAsExpression, TSSatisfiesExpression, TSTypeAssertion. Limits\n * recursion depth to prevent infinite loops on circular variable references.\n */\nexport const resolveExpression = (\n  expr: t.Expression | t.Declaration | null | undefined,\n  ast: t.File,\n  depth = 0,\n  maxDepth = 10\n): t.Expression | null => {\n  if (!expr || depth > maxDepth) {\n    return null;\n  }\n  const unwrapped = unwrapTSExpression(expr as t.Expression | t.Declaration);\n  if (unwrapped.type !== 'Identifier') {\n    return unwrapped;\n  }\n  const varName = (unwrapped as t.Identifier).name;\n  let declarator: t.VariableDeclarator | undefined;\n  for (const node of ast.program.body) {\n    let declarations: t.VariableDeclarator[] | undefined;\n    if (node.type === 'VariableDeclaration') {\n      declarations = node.declarations;\n    } else if (\n      node.type === 'ExportNamedDeclaration' &&\n      node.declaration?.type === 'VariableDeclaration'\n    ) {\n      declarations = node.declaration.declarations;\n    }\n    if (declarations) {\n      declarator = declarations.find(\n        (d) => d.id.type === 'Identifier' && (d.id as t.Identifier).name === varName\n      );\n      if (declarator) {\n        break;\n      }\n    }\n  }\n  if (!declarator?.init) {\n    return unwrapped;\n  }\n  return resolveExpression(declarator.init, ast, depth + 1, maxDepth);\n};\n"
  },
  {
    "path": "code/core/src/babel/index.ts",
    "content": "/**\n * This entry is to ensure we use a single version of Babel across the codebase. This is to prevent\n * issues with multiple versions of Babel being used in the same project. It also prevents us from\n * bundling babel multiple times in the final bundles.\n */\nimport { transformSync } from '@babel/core';\nimport * as core from '@babel/core';\n// @ts-expect-error File is not yet exposed, see https://github.com/babel/babel/issues/11350#issuecomment-644118606\nimport { File } from '@babel/core';\nimport bg from '@babel/generator';\nimport * as parser from '@babel/parser';\nimport bt from '@babel/traverse';\nimport * as types from '@babel/types';\nimport * as recast from 'recast';\n\nexport * from './babelParse.ts';\nexport { unwrapTSExpression, resolveExpression } from './expression-resolver.ts';\nexport {\n  isImportedDefineConfigLikeIdentifier,\n  isDefineConfigLike,\n  getConfigObjectFromMergeArg,\n  getEffectiveMergeConfigCall,\n  getTargetConfigObject,\n  canUpdateVitestConfigFile,\n  canUpdateVitestWorkspaceFile,\n} from './vitest-config-helpers.ts';\n\n// @ts-expect-error (needed due to it's use of `exports.default`)\nconst traverse = (bt.default || bt) as typeof bt;\n// @ts-expect-error (needed due to it's use of `exports.default`)\nconst generate = (bg.default || bg) as typeof bg;\n\nconst BabelFileClass = File as any;\n\nexport {\n  // main\n  core,\n  generate,\n  traverse,\n  types,\n  parser,\n  transformSync,\n  BabelFileClass,\n\n  // other\n  recast,\n};\n\nexport type { BabelFile, NodePath } from '@babel/core';\nexport type { GeneratorOptions } from '@babel/generator';\nexport type { Options as RecastOptions } from 'recast';\n"
  },
  {
    "path": "code/core/src/babel/vitest-config-helpers.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport {\n  canUpdateVitestConfigFile,\n  canUpdateVitestWorkspaceFile,\n} from './vitest-config-helpers.ts';\n\ndescribe('canUpdateVitestConfigFile', () => {\n  it('returns true for plain export default object literal', () => {\n    expect(canUpdateVitestConfigFile('export default { test: { name: \"node\" } }')).toBe(true);\n  });\n\n  it('returns true for bare export default {}', () => {\n    expect(canUpdateVitestConfigFile('export default {}')).toBe(true);\n  });\n\n  it('returns true for defineConfig({}) pattern', () => {\n    expect(\n      canUpdateVitestConfigFile(\n        `\n        import { defineConfig } from 'vitest/config';\n        export default defineConfig({ test: { environment: 'happy-dom' } });`\n      )\n    ).toBe(true);\n  });\n\n  it('returns true for defineProject({}) pattern', () => {\n    expect(\n      canUpdateVitestConfigFile(\n        `\n        import { defineProject } from 'vitest/config';\n        export default defineProject({ test: { environment: 'happy-dom' } });`\n      )\n    ).toBe(true);\n  });\n\n  it('returns true for defineProject from vitest/config', () => {\n    expect(\n      canUpdateVitestConfigFile(\n        `\n        import { defineProject } from 'vitest/config';\n\n        export default defineProject({\n          test: {\n            name: 'node',\n            environment: 'happy-dom',\n            include: ['**/*.test.ts'],\n          },\n        })\n        `\n      )\n    ).toBe(true);\n  });\n\n  it('returns true for simple mergeConfig({}, {}) pattern', () => {\n    expect(\n      canUpdateVitestConfigFile(\n        `\n        import { mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        export default mergeConfig(viteConfig, { test: { name: 'node' } });`\n      )\n    ).toBe(true);\n  });\n\n  it('returns true for defineConfig(mergeConfig(...)) pattern', () => {\n    expect(\n      canUpdateVitestConfigFile(\n        `\n        import { defineConfig, mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n\n        export default defineConfig(\n          mergeConfig(viteConfig, {\n            test: {\n              name: 'node',\n              environment: 'happy-dom',\n              include: ['**/*.test.ts'],\n            },\n          })\n        )\n        `\n      )\n    ).toBe(true);\n  });\n\n  it('returns true for defineConfig(mergeConfig(...) satisfies ViteUserConfig) pattern', () => {\n    expect(\n      canUpdateVitestConfigFile(\n        `\n        import { defineConfig, mergeConfig } from 'vitest/config';\n        import type { ViteUserConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n\n        export default defineConfig(\n          mergeConfig(viteConfig, {\n            test: {\n              name: 'node',\n              environment: 'happy-dom',\n              include: ['**/*.test.ts'],\n            },\n          }) satisfies ViteUserConfig\n        )\n        `\n      )\n    ).toBe(true);\n  });\n\n  it('returns true for mergeConfig(...) as ViteUserConfig pattern', () => {\n    expect(\n      canUpdateVitestConfigFile(\n        `\n        import { mergeConfig } from 'vitest/config';\n        import type { ViteUserConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n\n        export default mergeConfig(viteConfig, {\n          test: {\n            name: 'node',\n            environment: 'happy-dom',\n            include: ['**/*.test.ts'],\n          },\n        }) as ViteUserConfig\n        `\n      )\n    ).toBe(true);\n  });\n\n  it('returns true for mergeConfig with shorthand test property (const test = {...})', () => {\n    expect(\n      canUpdateVitestConfigFile(\n        `\n        import { mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n\n        const test = {\n          name: 'node',\n          environment: 'happy-dom',\n          include: ['**/*.test.ts'],\n        };\n\n        export default mergeConfig(viteConfig, {\n          test,\n        })\n        `\n      )\n    ).toBe(true);\n  });\n\n  it('returns true for mergeConfig with external vitestConfig variable', () => {\n    expect(\n      canUpdateVitestConfigFile(\n        `\n        import { mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n\n        const vitestConfig = {\n          test: {\n            name: 'node',\n            environment: 'happy-dom',\n            include: ['**/*.test.ts'],\n          },\n        };\n\n        export default mergeConfig(viteConfig, vitestConfig)\n        `\n      )\n    ).toBe(true);\n  });\n\n  it('returns true for const config = mergeConfig(...); export default config pattern', () => {\n    expect(\n      canUpdateVitestConfigFile(\n        `\n        import { defineConfig, mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n\n        const config = mergeConfig(\n          viteConfig,\n          defineConfig({\n            test: {\n              name: 'node',\n              environment: 'happy-dom',\n              include: ['**/*.test.ts'],\n            },\n          })\n        );\n\n        export default config\n      `\n      )\n    ).toBe(true);\n  });\n\n  it('returns true for export default config where config = defineConfig({...})', () => {\n    expect(\n      canUpdateVitestConfigFile(\n        `\n        import { defineConfig } from 'vitest/config';\n\n        const config = defineConfig({ test: { name: 'node' } });\n        export default config\n        `\n      )\n    ).toBe(true);\n  });\n\n  it('returns true for defineConfig({}) as UserWorkspaceConfig', () => {\n    expect(\n      canUpdateVitestConfigFile(\n        `\n        import { defineConfig } from 'vitest/config';\n        import type { UserWorkspaceConfig } from 'vitest/config';\n\n        export default defineConfig({ test: {} }) as UserWorkspaceConfig\n        `\n      )\n    ).toBe(true);\n  });\n\n  it('returns true for defineConfig({}) satisfies UserWorkspaceConfig', () => {\n    expect(\n      canUpdateVitestConfigFile(\n        `\n        import { defineConfig } from 'vitest/config';\n        import type { UserWorkspaceConfig } from 'vitest/config';\n\n        export default defineConfig({ test: {} }) satisfies UserWorkspaceConfig\n        `\n      )\n    ).toBe(true);\n  });\n\n  it('returns true for defineConfig aliased to a custom name', () => {\n    expect(\n      canUpdateVitestConfigFile(\n        `\n        import { defineConfig as dc } from 'vitest/config';\n        export default dc({ test: {} })\n        `\n      )\n    ).toBe(true);\n  });\n\n  // ----- Unsupported patterns (should return false) -----\n\n  it('returns false when there is no export default', () => {\n    expect(canUpdateVitestConfigFile('const x = 1;')).toBe(false);\n  });\n\n  it('returns false for arrow function pattern: defineConfig(() => ({}))', () => {\n    expect(\n      canUpdateVitestConfigFile(\n        `\n        import { defineConfig } from 'vitest/config';\n        export default defineConfig(() => ({ test: {} }))\n        `\n      )\n    ).toBe(false);\n  });\n\n  it('returns false for unrecognizable export (string literal)', () => {\n    expect(canUpdateVitestConfigFile(\"export default 'something'\")).toBe(false);\n  });\n\n  it('returns false for syntax errors', () => {\n    expect(canUpdateVitestConfigFile('this is not valid syntax !!!')).toBe(false);\n  });\n\n  it('returns false for export default function declaration', () => {\n    expect(canUpdateVitestConfigFile('export default function config() { return {}; }')).toBe(\n      false\n    );\n  });\n});\n\n// ─── canUpdateVitestWorkspaceFile ────────────────────────────────────────────\n\ndescribe('canUpdateVitestWorkspaceFile', () => {\n  // ----- Supported patterns (should return true) -----\n\n  it('returns true for plain array workspace', () => {\n    expect(canUpdateVitestWorkspaceFile('export default [\"project1\", \"project2\"]')).toBe(true);\n  });\n\n  it('returns true for array with object entries', () => {\n    expect(canUpdateVitestWorkspaceFile('export default [{ test: {} }, \"project\"]')).toBe(true);\n  });\n\n  it('returns true for empty array', () => {\n    expect(canUpdateVitestWorkspaceFile('export default []')).toBe(true);\n  });\n\n  it('returns true for defineWorkspace([...]) pattern', () => {\n    expect(\n      canUpdateVitestWorkspaceFile(\n        `\n        import { defineWorkspace } from 'vitest/config';\n        export default defineWorkspace(['project1', 'project2'])\n        `\n      )\n    ).toBe(true);\n  });\n\n  it('returns true for defineWorkspace with object entries', () => {\n    expect(\n      canUpdateVitestWorkspaceFile(\n        `\n        import { defineWorkspace } from 'vitest/config';\n        export default defineWorkspace([{ test: { name: 'unit' } }])\n        `\n      )\n    ).toBe(true);\n  });\n\n  // ----- Unsupported patterns (should return false) -----\n\n  it('returns false when there is no export default', () => {\n    expect(canUpdateVitestWorkspaceFile('const projects = [\"a\"];')).toBe(false);\n  });\n\n  it('returns false for defineWorkspace with a non-array argument', () => {\n    expect(\n      canUpdateVitestWorkspaceFile(\n        `\n        import { defineWorkspace } from 'vitest/config';\n        export default defineWorkspace('glob/**')\n        `\n      )\n    ).toBe(false);\n  });\n\n  it('returns false for syntax errors', () => {\n    expect(canUpdateVitestWorkspaceFile('this is not valid syntax !!!')).toBe(false);\n  });\n});\n"
  },
  {
    "path": "code/core/src/babel/vitest-config-helpers.ts",
    "content": "/**\n * Shared AST helpers for analyzing and determining whether a Vitest/Vite config file can be\n * auto-updated by Storybook. Extracted from the addon-vitest postinstall logic so the same\n * capability checks are used during `storybook init` (AddonVitestService) and during the actual\n * config update (updateVitestFile).\n */\nimport type * as t from '@babel/types';\n\nimport { babelParse } from './babelParse.ts';\nimport { resolveExpression } from './expression-resolver.ts';\n\ntype AST = t.File;\n\n/**\n * Returns true if the identifier `localName` is a local alias for `defineConfig` or `defineProject`\n * imported from either `vitest/config` or `vite`.\n */\nexport const isImportedDefineConfigLikeIdentifier = (localName: string, ast: AST): boolean =>\n  ast.program.body.some(\n    (node): boolean =>\n      node.type === 'ImportDeclaration' &&\n      (node.source.value === 'vitest/config' || node.source.value === 'vite') &&\n      node.specifiers.some(\n        (specifier) =>\n          specifier.type === 'ImportSpecifier' &&\n          specifier.local.type === 'Identifier' &&\n          specifier.local.name === localName &&\n          specifier.imported.type === 'Identifier' &&\n          (specifier.imported.name === 'defineConfig' ||\n            specifier.imported.name === 'defineProject')\n      )\n  );\n\n/** Returns true if a CallExpression is a call to defineConfig or defineProject (or an alias). */\nexport const isDefineConfigLike = (node: t.CallExpression, ast: AST): boolean =>\n  node.callee.type === 'Identifier' &&\n  (node.callee.name === 'defineConfig' ||\n    node.callee.name === 'defineProject' ||\n    isImportedDefineConfigLikeIdentifier(node.callee.name, ast));\n\n/**\n * Resolves a `mergeConfig` argument to an ObjectExpression when possible. Handles:\n *\n * - Plain object literals: `{ test: {...} }`\n * - Variable references: `const vitestConfig = {...}; mergeConfig(viteConfig, vitestConfig)`\n * - Wrapped calls (e.g. `defineConfig({ ... })`): returns the inner ObjectExpression\n * - TypeScript type annotations: `mergeConfig(...) as ViteUserConfig`\n */\nexport const getConfigObjectFromMergeArg = (\n  arg: t.Expression,\n  ast: AST\n): t.ObjectExpression | null => {\n  const resolved = resolveExpression(arg, ast);\n  if (!resolved) {\n    return null;\n  }\n\n  if (resolved.type === 'ObjectExpression') {\n    return resolved;\n  }\n\n  if (resolved.type === 'CallExpression' && resolved.arguments[0]?.type === 'ObjectExpression') {\n    return resolved.arguments[0] as t.ObjectExpression;\n  }\n\n  return null;\n};\n\n/**\n * Extracts the effective `mergeConfig(...)` call from a declaration, unwrapping:\n *\n * - TypeScript type annotations (`as X`, `satisfies X`)\n * - `defineConfig(mergeConfig(...))` outer wrapper\n * - Variable references (`export default config` where `config = mergeConfig(...)`)\n *\n * Returns null when the declaration is not or does not contain a `mergeConfig` call.\n */\nexport const getEffectiveMergeConfigCall = (\n  decl: t.Expression | t.Declaration,\n  ast: AST\n): t.CallExpression | null => {\n  const resolved = resolveExpression(decl, ast);\n  if (!resolved || resolved.type !== 'CallExpression') {\n    return null;\n  }\n\n  // Handle defineConfig(mergeConfig(...)) – inner arg may itself be TS-wrapped\n  if (isDefineConfigLike(resolved, ast) && resolved.arguments.length > 0) {\n    const innerArg = resolveExpression(resolved.arguments[0] as t.Expression, ast);\n    if (\n      innerArg?.type === 'CallExpression' &&\n      innerArg.callee.type === 'Identifier' &&\n      innerArg.callee.name === 'mergeConfig'\n    ) {\n      return innerArg;\n    }\n  }\n\n  // Handle mergeConfig(...) directly\n  if (resolved.callee.type === 'Identifier' && resolved.callee.name === 'mergeConfig') {\n    return resolved;\n  }\n\n  return null;\n};\n\n/**\n * Resolves the default export to the actual config ObjectExpression we can merge into. Handles:\n *\n * - `export default { ... }` — plain object\n * - `export default defineConfig({ ... })` — defineConfig with object\n * - `export default defineProject({ ... })` — defineProject with object\n * - `export default config` — variable reference to any of the above\n * - Any of the above wrapped in TypeScript type annotations\n *\n * Returns null when a writable ObjectExpression cannot be located.\n */\nexport const getTargetConfigObject = (\n  target: AST,\n  exportDefault: t.ExportDefaultDeclaration\n): t.ObjectExpression | null => {\n  const resolved = resolveExpression(exportDefault.declaration, target);\n  if (!resolved) {\n    return null;\n  }\n  if (resolved.type === 'ObjectExpression') {\n    return resolved;\n  }\n  if (\n    resolved.type === 'CallExpression' &&\n    isDefineConfigLike(resolved, target) &&\n    resolved.arguments[0]?.type === 'ObjectExpression'\n  ) {\n    return resolved.arguments[0] as t.ObjectExpression;\n  }\n  return null;\n};\n\n/**\n * Returns `true` when a Vitest/Vite config file's default export uses a pattern that\n * `updateConfigFile` (from addon-vitest) can auto-update.\n *\n * Supported patterns:\n *\n * - `export default { test: {...} }`\n * - `export default defineConfig({ ... })` / `defineProject({ ... })`\n * - `export default mergeConfig(viteConfig, { ... })`\n * - `export default mergeConfig(viteConfig, defineConfig({ ... }))`\n * - `export default defineConfig(mergeConfig(...))`\n * - `export default config` (variable referencing any of the above)\n * - Any of the above wrapped in `as X` or `satisfies X` TypeScript annotations\n *\n * Unsupported patterns (returns `false`):\n *\n * - `export default defineConfig(() => ({ ... }))` (arrow function)\n * - Completely unrecognizable export shapes\n * - No `export default` declaration at all\n */\nexport const canUpdateVitestConfigFile = (fileContent: string): boolean => {\n  let parsedAst: AST;\n  try {\n    parsedAst = babelParse(fileContent);\n  } catch {\n    return false;\n  }\n\n  const exportDefault = parsedAst.program.body.find(\n    (n): n is t.ExportDefaultDeclaration => n.type === 'ExportDefaultDeclaration'\n  );\n  if (!exportDefault) {\n    return false;\n  }\n\n  // Reject arrow function pattern: defineConfig(() => ({...}))\n  const effectiveDecl = resolveExpression(exportDefault.declaration, parsedAst);\n  if (\n    effectiveDecl?.type === 'CallExpression' &&\n    isDefineConfigLike(effectiveDecl, parsedAst) &&\n    effectiveDecl.arguments.length > 0 &&\n    effectiveDecl.arguments[0].type === 'ArrowFunctionExpression'\n  ) {\n    return false;\n  }\n\n  return (\n    getTargetConfigObject(parsedAst, exportDefault) !== null ||\n    getEffectiveMergeConfigCall(exportDefault.declaration, parsedAst) !== null\n  );\n};\n\n/**\n * Returns `true` when a Vitest workspace file's default export uses a pattern that\n * `updateWorkspaceFile` (from addon-vitest) can auto-update.\n *\n * Supported patterns:\n *\n * - `export default [\"project1\", \"project2\"]`\n * - `export default [{...}, \"project\"]`\n * - `export default defineWorkspace([\"project1\", \"project2\"])`\n *\n * Returns `false` for any other shape (e.g. JSON files should be rejected before parsing, CommonJS\n * files, unrecognizable exports).\n */\nexport const canUpdateVitestWorkspaceFile = (fileContent: string): boolean => {\n  let parsedAst: AST;\n  try {\n    parsedAst = babelParse(fileContent);\n  } catch {\n    return false;\n  }\n\n  const exportDefault = parsedAst.program.body.find(\n    (n): n is t.ExportDefaultDeclaration => n.type === 'ExportDefaultDeclaration'\n  );\n  if (!exportDefault) {\n    return false;\n  }\n\n  const decl = exportDefault.declaration;\n\n  // export default [...]\n  if (decl.type === 'ArrayExpression') {\n    return true;\n  }\n\n  // export default defineWorkspace([...])\n  if (\n    decl.type === 'CallExpression' &&\n    decl.callee.type === 'Identifier' &&\n    decl.callee.name === 'defineWorkspace' &&\n    decl.arguments[0]?.type === 'ArrayExpression'\n  ) {\n    return true;\n  }\n\n  return false;\n};\n"
  },
  {
    "path": "code/core/src/backgrounds/components/Tool.tsx",
    "content": "import React, { Fragment, memo, useCallback } from 'react';\n\nimport { Select, ToggleButton } from 'storybook/internal/components';\n\nimport { CircleIcon, GridIcon, PhotoIcon } from '@storybook/icons';\n\nimport { useGlobals, useParameter } from 'storybook/manager-api';\n\nimport { PARAM_KEY as KEY } from '../constants.ts';\nimport { DEFAULT_BACKGROUNDS } from '../defaults.ts';\nimport type {\n  Background,\n  BackgroundMap,\n  BackgroundsParameters,\n  GlobalStateUpdate,\n} from '../types.ts';\n\nexport const BackgroundTool = memo(function BackgroundSelector() {\n  const config = useParameter<BackgroundsParameters['backgrounds']>(KEY);\n  const [globals, updateGlobals, storyGlobals] = useGlobals();\n\n  const { options = DEFAULT_BACKGROUNDS, disable = true } = config || {};\n  if (disable) {\n    return null;\n  }\n\n  const data = globals[KEY] || {};\n  const backgroundName: string = data.value;\n  const isGridActive = data.grid || false;\n\n  const item = options[backgroundName];\n  const isLocked = !!storyGlobals?.[KEY];\n  const length = Object.keys(options).length;\n\n  return (\n    <Pure\n      {...{\n        length,\n        backgroundMap: options,\n        item,\n        updateGlobals,\n        backgroundName,\n        isLocked,\n        isGridActive,\n      }}\n    />\n  );\n});\n\ninterface PureProps {\n  length: number;\n  backgroundMap: BackgroundMap;\n  item: Background | undefined;\n  updateGlobals: ReturnType<typeof useGlobals>['1'];\n  backgroundName: string | undefined;\n  isLocked: boolean;\n  isGridActive: boolean;\n}\n\nconst Pure = memo(function PureTool(props: PureProps) {\n  const {\n    length,\n    updateGlobals,\n    backgroundMap,\n    backgroundName,\n    isLocked,\n    isGridActive: isGrid,\n  } = props;\n\n  const update = useCallback(\n    (input: GlobalStateUpdate | undefined) => {\n      updateGlobals({\n        [KEY]: input,\n      });\n    },\n    [updateGlobals]\n  );\n\n  const options = Object.entries(backgroundMap).map(([k, value]) => ({\n    value: k,\n    title: value.name,\n    icon: <CircleIcon color={value?.value || 'grey'} />,\n  }));\n\n  return (\n    <Fragment>\n      <ToggleButton\n        padding=\"small\"\n        variant=\"ghost\"\n        key=\"grid\"\n        pressed={isGrid}\n        disabled={isLocked}\n        ariaLabel={isLocked ? 'Grid set by story parameters' : 'Grid visibility'}\n        tooltip={isLocked ? 'Grid set by story parameters' : 'Toggle grid visibility'}\n        onClick={() => update({ value: backgroundName, grid: !isGrid })}\n      >\n        <GridIcon />\n      </ToggleButton>\n\n      {length > 0 ? (\n        <Select\n          resetLabel=\"Reset background\"\n          onReset={() => update(undefined)}\n          disabled={isLocked}\n          key=\"background\"\n          icon={<PhotoIcon />}\n          ariaLabel={isLocked ? 'Background set by story parameters' : 'Preview background'}\n          tooltip={isLocked ? 'Background set by story parameters' : 'Change background'}\n          defaultOptions={backgroundName}\n          options={options}\n          onSelect={(selected) => update({ value: selected as string, grid: isGrid })}\n        />\n      ) : null}\n    </Fragment>\n  );\n});\n"
  },
  {
    "path": "code/core/src/backgrounds/constants.ts",
    "content": "export const ADDON_ID = 'storybook/background';\nexport const PARAM_KEY = 'backgrounds';\nexport const GRID_PARAM_KEY = 'grid';\n\nexport const EVENTS = {\n  UPDATE: `${ADDON_ID}/update`,\n};\n"
  },
  {
    "path": "code/core/src/backgrounds/decorator.ts",
    "content": "import type { DecoratorFunction } from 'storybook/internal/types';\n\nimport { useEffect } from 'storybook/preview-api';\n\nimport { PARAM_KEY } from './constants.ts';\nimport { DEFAULT_BACKGROUNDS } from './defaults.ts';\nimport type { BackgroundsParameters, GridConfig } from './types.ts';\nimport { addBackgroundStyle, addGridStyle, clearStyles, isReduceMotionEnabled } from './utils.ts';\n\nconst defaultGrid: GridConfig = {\n  cellSize: 100,\n  cellAmount: 10,\n  opacity: 0.8,\n};\n\nconst BG_SELECTOR_BASE = `addon-backgrounds`;\nconst GRID_SELECTOR_BASE = 'addon-backgrounds-grid';\n\nconst transitionStyle = isReduceMotionEnabled() ? '' : 'transition: background-color 0.3s;';\n\nexport const withBackgroundAndGrid: DecoratorFunction = (StoryFn, context) => {\n  const { globals = {}, parameters = {}, viewMode, id } = context;\n  const {\n    options = DEFAULT_BACKGROUNDS,\n    disable,\n    grid = defaultGrid,\n  } = (parameters[PARAM_KEY] || {}) as NonNullable<BackgroundsParameters['backgrounds']>;\n  const data = globals[PARAM_KEY] || {};\n  const backgroundName: string | undefined = typeof data === 'string' ? data : data?.value;\n\n  const item = backgroundName ? options[backgroundName] : undefined;\n  const value = typeof item === 'string' ? item : item?.value || 'transparent';\n\n  const showGrid = typeof data === 'string' ? false : data.grid || false;\n  const shownBackground = !!item && !disable;\n\n  const backgroundSelector =\n    viewMode === 'docs'\n      ? `#anchor--${id} .docs-story, #anchor--primary--${id} .docs-story`\n      : '.sb-show-main';\n  const gridSelector =\n    viewMode === 'docs'\n      ? `#anchor--${id} .docs-story, #anchor--primary--${id} .docs-story`\n      : '.sb-show-main';\n\n  const isLayoutPadded = parameters.layout === undefined || parameters.layout === 'padded';\n  const defaultOffset = viewMode === 'docs' ? 20 : isLayoutPadded ? 16 : 0;\n  const { cellAmount, cellSize, opacity, offsetX = defaultOffset, offsetY = defaultOffset } = grid;\n\n  const backgroundSelectorId =\n    viewMode === 'docs' ? `${BG_SELECTOR_BASE}-docs-${id}` : `${BG_SELECTOR_BASE}-color`;\n  const backgroundTarget = viewMode === 'docs' ? id : null;\n\n  useEffect(() => {\n    const backgroundStyles = `\n    ${backgroundSelector} {\n      background: ${value} !important;\n      ${transitionStyle}\n      }`;\n\n    if (!shownBackground) {\n      clearStyles(backgroundSelectorId);\n      return;\n    }\n\n    addBackgroundStyle(backgroundSelectorId, backgroundStyles, backgroundTarget);\n  }, [backgroundSelector, backgroundSelectorId, backgroundTarget, shownBackground, value]);\n\n  const gridSelectorId =\n    viewMode === 'docs' ? `${GRID_SELECTOR_BASE}-docs-${id}` : `${GRID_SELECTOR_BASE}`;\n  useEffect(() => {\n    if (!showGrid) {\n      clearStyles(gridSelectorId);\n      return;\n    }\n    const gridSize = [\n      `${cellSize * cellAmount}px ${cellSize * cellAmount}px`,\n      `${cellSize * cellAmount}px ${cellSize * cellAmount}px`,\n      `${cellSize}px ${cellSize}px`,\n      `${cellSize}px ${cellSize}px`,\n    ].join(', ');\n\n    const gridStyles = `\n        ${gridSelector} {\n          background-size: ${gridSize} !important;\n          background-position: ${offsetX}px ${offsetY}px, ${offsetX}px ${offsetY}px, ${offsetX}px ${offsetY}px, ${offsetX}px ${offsetY}px !important;\n          background-blend-mode: difference !important;\n          background-image: linear-gradient(rgba(130, 130, 130, ${opacity}) 1px, transparent 1px),\n           linear-gradient(90deg, rgba(130, 130, 130, ${opacity}) 1px, transparent 1px),\n           linear-gradient(rgba(130, 130, 130, ${opacity / 2}) 1px, transparent 1px),\n           linear-gradient(90deg, rgba(130, 130, 130, ${\n             opacity / 2\n           }) 1px, transparent 1px) !important;\n        }\n      `;\n\n    addGridStyle(gridSelectorId, gridStyles);\n  }, [cellAmount, cellSize, gridSelector, gridSelectorId, showGrid, offsetX, offsetY, opacity]);\n\n  return StoryFn();\n};\n"
  },
  {
    "path": "code/core/src/backgrounds/defaults.ts",
    "content": "import type { BackgroundMap } from './types.ts';\n\nexport const DEFAULT_BACKGROUNDS: BackgroundMap = {\n  light: { name: 'light', value: '#F8F8F8' },\n  dark: { name: 'dark', value: '#333' },\n};\n"
  },
  {
    "path": "code/core/src/backgrounds/manager.tsx",
    "content": "import React from 'react';\n\nimport { addons, types } from 'storybook/manager-api';\n\nimport { BackgroundTool } from './components/Tool.tsx';\nimport { ADDON_ID } from './constants.ts';\n\nexport default addons.register(ADDON_ID, () => {\n  if (globalThis?.FEATURES?.backgrounds) {\n    addons.add(ADDON_ID, {\n      title: 'Backgrounds',\n      type: types.TOOL,\n      match: ({ viewMode, tabId }) => !!(viewMode && viewMode.match(/^(story|docs)$/)) && !tabId,\n      render: () => <BackgroundTool />,\n    });\n  }\n});\n"
  },
  {
    "path": "code/core/src/backgrounds/preview.ts",
    "content": "import { definePreviewAddon } from 'storybook/internal/csf';\n\nimport { PARAM_KEY } from './constants.ts';\nimport { withBackgroundAndGrid } from './decorator.ts';\nimport type {\n  BackgroundTypes,\n  BackgroundsGlobals,\n  BackgroundsParameters,\n  GlobalState,\n} from './types.ts';\n\nconst decorators = globalThis.FEATURES?.backgrounds ? [withBackgroundAndGrid] : [];\n\nconst parameters = {\n  [PARAM_KEY]: {\n    grid: {\n      cellSize: 20,\n      opacity: 0.5,\n      cellAmount: 5,\n    },\n    disable: false,\n  },\n} satisfies Partial<BackgroundsParameters>;\n\nconst initialGlobals: Record<string, GlobalState> = {\n  [PARAM_KEY]: { value: undefined, grid: false },\n};\n\nexport type { BackgroundTypes, BackgroundsGlobals };\n\nexport default () =>\n  definePreviewAddon<BackgroundTypes>({\n    decorators,\n    parameters,\n    initialGlobals,\n  });\n"
  },
  {
    "path": "code/core/src/backgrounds/types.ts",
    "content": "import type { PARAM_KEY } from './constants.ts';\n\nexport interface Background {\n  name: string;\n  value: string;\n}\n\nexport type BackgroundMap = Record<string, Background>;\n\nexport interface GridConfig {\n  cellAmount: number;\n  cellSize: number;\n  opacity: number;\n  offsetX?: number;\n  offsetY?: number;\n}\n\nexport type GlobalState = { value: string | undefined; grid?: boolean };\nexport type GlobalStateUpdate = Partial<GlobalState>;\n\nexport interface BackgroundsParameters {\n  /**\n   * Backgrounds configuration\n   *\n   * @see https://storybook.js.org/docs/essentials/backgrounds#parameters\n   */\n  backgrounds?: {\n    /** Default background color */\n    default?: string;\n\n    /**\n     * Removes the tool and disables the feature's behavior. If you wish to turn off this feature\n     * for the entire Storybook, you can set the option in your `main.js|ts` configuration file.\n     *\n     * @see https://storybook.js.org/docs/essentials/backgrounds#disable\n     */\n    disable?: boolean;\n\n    /** Configuration for the background grid */\n    grid?: GridConfig;\n\n    /** Available background colors */\n    options?: BackgroundMap;\n  };\n}\n\nexport interface BackgroundsGlobals {\n  /**\n   * Backgrounds configuration\n   *\n   * @see https://storybook.js.org/docs/essentials/backgrounds#globals\n   */\n  [PARAM_KEY]?: GlobalState | GlobalState['value'];\n}\n\nexport interface BackgroundTypes {\n  parameters: BackgroundsParameters;\n  globals: BackgroundsGlobals;\n}\n"
  },
  {
    "path": "code/core/src/backgrounds/typings.d.ts",
    "content": "declare var FEATURES: import('storybook/internal/types').StorybookConfigRaw['features'];\n"
  },
  {
    "path": "code/core/src/backgrounds/utils.ts",
    "content": "const { document } = globalThis;\n\nexport const isReduceMotionEnabled = () => {\n  if (!globalThis?.matchMedia) {\n    return false;\n  }\n  const prefersReduceMotion = globalThis.matchMedia('(prefers-reduced-motion: reduce)');\n  return !!prefersReduceMotion?.matches;\n};\n\nexport const clearStyles = (selector: string | string[]) => {\n  const selectors = Array.isArray(selector) ? selector : [selector];\n  selectors.forEach(clearStyle);\n};\n\nconst clearStyle = (selector: string) => {\n  if (!document) {\n    return;\n  }\n\n  const element = document.getElementById(selector);\n  if (element && element.parentElement) {\n    element.parentElement.removeChild(element);\n  }\n};\n\nexport const addGridStyle = (selector: string, css: string) => {\n  if (!document) {\n    return;\n  }\n\n  const existingStyle = document.getElementById(selector);\n  if (existingStyle) {\n    if (existingStyle.innerHTML !== css) {\n      existingStyle.innerHTML = css;\n    }\n  } else {\n    const style = document.createElement('style');\n    style.setAttribute('id', selector);\n    style.innerHTML = css;\n    document.head.appendChild(style);\n  }\n};\n\nexport const addBackgroundStyle = (selector: string, css: string, storyId: string | null) => {\n  if (!document) {\n    return;\n  }\n\n  const existingStyle = document.getElementById(selector);\n  if (existingStyle) {\n    if (existingStyle.innerHTML !== css) {\n      existingStyle.innerHTML = css;\n    }\n  } else {\n    const style = document.createElement('style');\n    style.setAttribute('id', selector);\n    style.innerHTML = css;\n\n    const gridStyleSelector = `addon-backgrounds-grid${storyId ? `-docs-${storyId}` : ''}`;\n    // If grids already exist, we want to add the style tag BEFORE it so the background doesn't override grid\n    const existingGridStyle = document.getElementById(gridStyleSelector);\n    if (existingGridStyle) {\n      existingGridStyle.parentElement?.insertBefore(style, existingGridStyle);\n    } else {\n      document.head.appendChild(style);\n    }\n  }\n};\n"
  },
  {
    "path": "code/core/src/bin/core.ts",
    "content": "import { getEnvConfig, optionalEnvToBoolean, parseList } from 'storybook/internal/common';\nimport { logTracker, logger } from 'storybook/internal/node-logger';\nimport { addToGlobalContext } from 'storybook/internal/telemetry';\n\nimport { Option, program } from 'commander';\nimport leven from 'leven';\nimport picocolors from 'picocolors';\n\nimport { version } from '../../package.json';\nimport { build } from '../cli/build.ts';\nimport { buildIndex as index } from '../cli/buildIndex.ts';\nimport { dev } from '../cli/dev.ts';\nimport { globalSettings } from '../cli/globalSettings.ts';\n\naddToGlobalContext('cliVersion', version);\nprocess.env.STORYBOOK = 'true';\n\n/**\n * Core CLI for Storybook.\n *\n * This module provides the core CLI for Storybook, handling the following commands:\n *\n * - `dev`: Start the Storybook development server\n * - `build`: Build the Storybook static files\n * - `index`: Generate the Storybook index file\n *\n * The dispatch CLI at ./dispatcher.ts routes commands to this core CLI.\n */\n\nconst handleCommandFailure = async (logFilePath: string | boolean): Promise<never> => {\n  try {\n    const logFile = await logTracker.writeToFile(logFilePath);\n    logger.log(`Debug logs are written to: ${logFile}`);\n  } catch {}\n  logger.outro('Storybook exited with an error');\n  process.exit(1);\n};\n\nconst command = (name: string) =>\n  program\n    .command(name)\n    .option(\n      '--disable-telemetry',\n      'Disable sending telemetry data',\n      optionalEnvToBoolean(process.env.STORYBOOK_DISABLE_TELEMETRY)\n    )\n    .option('--debug', 'Get more logs in debug mode', false)\n    .option('--enable-crash-reports', 'Enable sending crash reports to telemetry data')\n    .addOption(\n      new Option('--loglevel <level>', 'Define log level')\n        .choices(['trace', 'debug', 'info', 'warn', 'error', 'silent'])\n        .default('info')\n    )\n    .option(\n      '--logfile [path]',\n      'Write all debug logs to the specified file at the end of the run. Defaults to debug-storybook.log when [path] is not provided'\n    )\n    .hook('preAction', async (self) => {\n      try {\n        const options = self.opts();\n        const loglevel = options.debug ? 'debug' : options.loglevel;\n        logger.setLogLevel(loglevel);\n\n        if (options.logfile) {\n          logTracker.enableLogWriting();\n        }\n\n        await globalSettings();\n      } catch (e) {\n        logger.error('Error loading global settings:\\n' + String(e));\n      }\n    })\n    .hook('postAction', async (command) => {\n      if (logTracker.shouldWriteLogsToFile) {\n        try {\n          const logFile = await logTracker.writeToFile(command.getOptionValue('logfile'));\n          logger.outro(`Debug logs are written to: ${logFile}`);\n        } catch {}\n      }\n    });\n\ncommand('dev')\n  .option('-p, --port <number>', 'Port to run Storybook', (str) => parseInt(str, 10))\n  .option('-h, --host <string>', 'Host to run Storybook')\n  .option('-c, --config-dir <dir-name>', 'Directory where to load Storybook configurations from')\n  .option(\n    '--https',\n    'Serve Storybook over HTTPS. Note: You must provide your own certificate information.'\n  )\n  .option(\n    '--ssl-ca <ca>',\n    'Provide an SSL certificate authority. (Optional with --https, required if using a self-signed certificate)',\n    parseList\n  )\n  .option('--ssl-cert <cert>', 'Provide an SSL certificate. (Required with --https)')\n  .option('--ssl-key <key>', 'Provide an SSL key. (Required with --https)')\n  .option('--smoke-test', 'Exit after successful start')\n  .option('--ci', \"CI mode (skip interactive prompts, don't open browser)\")\n  .option('--no-open', 'Do not open Storybook automatically in the browser')\n  .option('--quiet', 'Suppress verbose build output')\n  .option('--no-version-updates', 'Suppress update check', true)\n  .option('--debug-webpack', 'Display final webpack configurations for debugging purposes')\n  .option(\n    '--webpack-stats-json [directory]',\n    'Write Webpack stats JSON to disk (synonym for `--stats-json`)'\n  )\n  .option('--stats-json [directory]', 'Write stats JSON to disk')\n  .option(\n    '--preview-url <string>',\n    'Disables the default storybook preview and lets your use your own'\n  )\n  .option('--force-build-preview', 'Build the preview iframe even if you are using --preview-url')\n  .option('--docs', 'Build a documentation-only site using addon-docs')\n  .option('--exact-port', 'Exit early if the desired port is not available')\n  .option(\n    '--initial-path [path]',\n    'URL path to be appended when visiting Storybook for the first time'\n  )\n  .option('--preview-only', 'Use the preview without the manager UI')\n  .action(async (options) => {\n    const { default: packageJson } = await import('storybook/package.json', {\n      with: { type: 'json' },\n    });\n\n    logger.intro(`${packageJson.name} v${packageJson.version}`);\n\n    // The key is the field created in `options` variable for\n    // each command line argument. Value is the env variable.\n    getEnvConfig(options, {\n      port: 'SBCONFIG_PORT',\n      host: 'SBCONFIG_HOSTNAME',\n      staticDir: 'SBCONFIG_STATIC_DIR',\n      configDir: 'SBCONFIG_CONFIG_DIR',\n      ci: 'CI',\n    });\n\n    if (parseInt(`${options.port}`, 10)) {\n      options.port = parseInt(`${options.port}`, 10);\n    }\n\n    await dev({ ...options, packageJson }).catch(() => {\n      handleCommandFailure(options.logfile);\n    });\n  });\n\ncommand('build')\n  .option('-o, --output-dir <dir-name>', 'Directory where to store built files')\n  .option('-c, --config-dir <dir-name>', 'Directory where to load Storybook configurations from')\n  .option('--quiet', 'Suppress verbose build output')\n  .option('--debug-webpack', 'Display final webpack configurations for debugging purposes')\n  .option(\n    '--webpack-stats-json [directory]',\n    'Write Webpack stats JSON to disk (synonym for `--stats-json`)'\n  )\n  .option('--stats-json [directory]', 'Write stats JSON to disk')\n  .option(\n    '--preview-url <string>',\n    'Disables the default storybook preview and lets your use your own'\n  )\n  .option('--force-build-preview', 'Build the preview iframe even if you are using --preview-url')\n  .option('--docs', 'Build a documentation-only site using addon-docs')\n  .option('--test', 'Build stories optimized for testing purposes.')\n  .option('--preview-only', 'Use the preview without the manager UI')\n  .action(async (options) => {\n    const { env } = process;\n    env.NODE_ENV = env.NODE_ENV || 'production';\n\n    const { default: packageJson } = await import('storybook/package.json', {\n      with: { type: 'json' },\n    });\n\n    logger.intro(`Building ${packageJson.name} v${packageJson.version}`);\n\n    // The key is the field created in `options` variable for\n    // each command line argument. Value is the env variable.\n    getEnvConfig(options, {\n      staticDir: 'SBCONFIG_STATIC_DIR',\n      outputDir: 'SBCONFIG_OUTPUT_DIR',\n      configDir: 'SBCONFIG_CONFIG_DIR',\n    });\n\n    await build({\n      ...options,\n      packageJson,\n      test: !!options.test || optionalEnvToBoolean(process.env.SB_TESTBUILD),\n    }).catch(() => {\n      logger.outro('Storybook exited with an error');\n      process.exit(1);\n    });\n\n    logger.outro('Storybook build completed successfully');\n  });\n\ncommand('index')\n  .option('-o, --output-file <file-name>', 'JSON file to output index')\n  .option('-c, --config-dir <dir-name>', 'Directory where to load Storybook configurations from')\n  .option('--quiet', 'Suppress verbose build output')\n  .action(async (options) => {\n    const { env } = process;\n    env.NODE_ENV = env.NODE_ENV || 'production';\n\n    const { default: packageJson } = await import('storybook/package.json', {\n      with: { type: 'json' },\n    });\n\n    logger.log(picocolors.bold(`${packageJson.name} v${packageJson.version}\\n`));\n\n    // The key is the field created in `options` variable for\n    // each command line argument. Value is the env variable.\n    getEnvConfig(options, {\n      configDir: 'SBCONFIG_CONFIG_DIR',\n      outputFile: 'SBCONFIG_OUTPUT_FILE',\n    });\n\n    await index({\n      ...options,\n      packageJson,\n    }).catch(() => process.exit(1));\n  });\n\nprogram.on('command:*', ([invalidCmd]) => {\n  let errorMessage = ` Invalid command: ${picocolors.bold(invalidCmd)}.\\n See --help for a list of available commands.`;\n  const availableCommands = program.commands.map((cmd) => cmd.name());\n  const suggestion = availableCommands.find((cmd) => leven(cmd, invalidCmd) < 3);\n  if (suggestion) {\n    errorMessage += `\\n Did you mean ${picocolors.yellow(suggestion)}?`;\n  }\n  logger.error(errorMessage);\n  process.exit(1);\n});\n\nprogram.usage('<command> [options]').version(String(version)).parse(process.argv);\n"
  },
  {
    "path": "code/core/src/bin/dispatcher.ts",
    "content": "#!/usr/bin/env node\nimport { pathToFileURL } from 'node:url';\n\nimport { executeCommand, executeNodeCommand } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { join } from 'pathe';\nimport { dedent } from 'ts-dedent';\n\nimport versions from '../common/versions.ts';\nimport { resolvePackageDir } from '../shared/utils/module.ts';\n\n/**\n * Dispatches Storybook CLI commands to the appropriate handler.\n *\n * This function serves as the main entry point for Storybook CLI operations.\n *\n * - Core Storybook commands (dev, build, index) are routed to the core binary at\n *   storybook/dist/bin/core.js\n * - Init is routed to the create-storybook package via npx\n * - External CLI tools (upgrade, doctor, etc.) are routed to @storybook/cli via npx\n */\nconst [majorNodeVersion, minorNodeVersion] = process.versions.node.split('.').map(Number);\nif (\n  majorNodeVersion < 20 ||\n  (majorNodeVersion === 20 && minorNodeVersion < 19) ||\n  (majorNodeVersion === 22 && minorNodeVersion < 12)\n) {\n  logger.error(\n    dedent`To run Storybook, you need Node.js version 20.19+ or 22.12+.\n    You are currently running Node.js ${process.version}. Please upgrade your Node.js installation.`\n  );\n  process.exit(1);\n}\n\nasync function run() {\n  const args = process.argv.slice(2);\n\n  if (['dev', 'build', 'index'].includes(args[0])) {\n    const coreBin = pathToFileURL(join(resolvePackageDir('storybook'), 'dist/bin/core.js')).href;\n    await import(coreBin);\n    return;\n  }\n\n  const targetCli =\n    args[0] === 'init'\n      ? ({\n          pkg: 'create-storybook',\n          args: args.slice(1),\n        } as const)\n      : ({\n          pkg: '@storybook/cli',\n          args,\n        } as const);\n\n  try {\n    const { default: targetCliPackageJson } = await import(`${targetCli.pkg}/package.json`, {\n      with: { type: 'json' },\n    });\n    if (targetCliPackageJson.version === versions[targetCli.pkg]) {\n      const child = executeNodeCommand({\n        scriptPath: join(resolvePackageDir(targetCli.pkg), 'dist/bin/index.js'),\n        args: targetCli.args,\n        options: {\n          stdio: 'inherit',\n        },\n      });\n      child.on('exit', (code) => {\n        process.exit(code ?? 1);\n      });\n      return;\n    }\n  } catch {\n    // the package couldn't be imported, use npx to install and run it instead\n  }\n\n  const child = executeCommand({\n    command: 'npx',\n    args: ['--yes', `${targetCli.pkg}@${versions[targetCli.pkg]}`, ...targetCli.args],\n    stdio: 'inherit',\n  });\n  child.on('exit', (code) => {\n    process.exit(code ?? 1);\n  });\n}\n\nrun();\n"
  },
  {
    "path": "code/core/src/bin/loader.test.ts",
    "content": "import { readdirSync } from 'node:fs';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { deprecate } from 'storybook/internal/node-logger';\n\nimport {\n  addExtensionsToRelativeImports,\n  clearDirectoryCache,\n  resolveWithExtension,\n} from './loader.ts';\n\n// Mock dependencies\nvi.mock('node:fs');\nvi.mock('storybook/internal/node-logger');\n\ndescribe('loader', () => {\n  beforeEach(() => {\n    clearDirectoryCache();\n  });\n\n  describe('resolveWithExtension', () => {\n    it('should return the path as-is if it already has an extension', () => {\n      const result = resolveWithExtension('./test.js', '/project/src/file.ts');\n\n      expect(result).toBe('./test.js');\n      expect(deprecate).not.toHaveBeenCalled();\n    });\n\n    it('should resolve extensionless import to .ts extension when file exists', () => {\n      vi.mocked(readdirSync).mockReturnValue(['utils.ts'] as any);\n\n      const result = resolveWithExtension('./utils', '/project/src/file.ts');\n\n      expect(result).toBe('./utils.ts');\n      expect(deprecate).toHaveBeenCalledWith(\n        expect.stringContaining('One or more extensionless imports detected: \"./utils\"')\n      );\n    });\n\n    it('should resolve extensionless import to .js extension when file exists', () => {\n      vi.mocked(readdirSync).mockReturnValue(['utils.js'] as any);\n\n      const result = resolveWithExtension('./utils', '/project/src/file.ts');\n\n      expect(result).toBe('./utils.js');\n      expect(deprecate).toHaveBeenCalledWith(\n        expect.stringContaining('One or more extensionless imports detected: \"./utils\"')\n      );\n    });\n\n    it('should show deprecation message when encountering an extensionless import', () => {\n      vi.mocked(readdirSync).mockReturnValue(['utils.js'] as any);\n\n      resolveWithExtension('./utils', '/project/src/file.ts');\n\n      expect(deprecate).toHaveBeenCalledWith(\n        expect.stringContaining('One or more extensionless imports detected: \"./utils\"')\n      );\n      expect(deprecate).toHaveBeenCalledWith(\n        expect.stringContaining('in file \"/project/src/file.ts\"')\n      );\n    });\n\n    it('should return original path when file cannot be resolved', () => {\n      vi.mocked(readdirSync).mockReturnValue([] as any);\n\n      const result = resolveWithExtension('./missing', '/project/src/file.ts');\n\n      expect(result).toBe('./missing');\n      expect(deprecate).toHaveBeenCalledWith(\n        expect.stringContaining('One or more extensionless imports detected: \"./missing\"')\n      );\n    });\n\n    it('should resolve relative to parent directory', () => {\n      vi.mocked(readdirSync).mockReturnValue(['utils.ts'] as any);\n\n      const result = resolveWithExtension('../utils', '/project/src/file.ts');\n\n      expect(result).toBe('../utils.ts');\n      expect(deprecate).toHaveBeenCalledWith(\n        expect.stringContaining('One or more extensionless imports detected: \"../utils\"')\n      );\n    });\n  });\n\n  describe('addExtensionsToRelativeImports', () => {\n    beforeEach(() => {\n      // Default: directory listings contain .ts versions of common test filenames\n      vi.mocked(readdirSync).mockReturnValue([\n        'utils.ts',\n        'foo.ts',\n        'bar.ts',\n        'baz.ts',\n        'module.ts',\n        'styles.ts',\n        'test.ts',\n      ] as any);\n    });\n\n    it('should not modify imports that already have non-mapped extensions', () => {\n      const testCases = [\n        { input: `import foo from './test.ts';`, expected: `import foo from './test.ts';` },\n        { input: `import foo from '../utils.mjs';`, expected: `import foo from '../utils.mjs';` },\n        {\n          input: `export { bar } from './module.tsx';`,\n          expected: `export { bar } from './module.tsx';`,\n        },\n      ];\n\n      testCases.forEach(({ input, expected }) => {\n        const result = addExtensionsToRelativeImports(input, '/project/src/file.ts');\n        expect(result).toBe(expected);\n        expect(deprecate).not.toHaveBeenCalled();\n      });\n    });\n\n    it('should resolve .js imports to .ts when TypeScript alternative exists', () => {\n      const result = addExtensionsToRelativeImports(\n        `import foo from './test.js';`,\n        '/project/src/file.ts'\n      );\n\n      expect(result).toBe(`import foo from './test.ts';`);\n      expect(deprecate).not.toHaveBeenCalled();\n    });\n\n    it('should add extension to static import statements', () => {\n      const source = `import { foo } from './utils';`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe(`import { foo } from './utils.ts';`);\n    });\n\n    it('should add extension to static export statements', () => {\n      const source = `export { foo } from './utils';`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe(`export { foo } from './utils.ts';`);\n    });\n\n    it('should add extension to dynamic import statements', () => {\n      const source = `const module = await import('./utils');`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe(`const module = await import('./utils.ts');`);\n    });\n\n    it('should handle default imports', () => {\n      const source = `import foo from './module';`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe(`import foo from './module.ts';`);\n    });\n\n    it('should handle named imports', () => {\n      const source = `import { foo, bar } from './module';`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe(`import { foo, bar } from './module.ts';`);\n    });\n\n    it('should handle namespace imports', () => {\n      const source = `import * as utils from './module';`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe(`import * as utils from './module.ts';`);\n    });\n\n    it('should handle side-effect imports', () => {\n      const source = `import './styles';`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe(`import './styles.ts';`);\n    });\n\n    it('should handle export all statements', () => {\n      const source = `export * from './module';`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe(`export * from './module.ts';`);\n    });\n\n    it('should not modify absolute imports', () => {\n      const testCases = [\n        `import foo from 'react';`,\n        `import bar from '@storybook/react';`,\n        `import baz from 'node:fs';`,\n      ];\n\n      testCases.forEach((source) => {\n        const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n        expect(result).toBe(source);\n      });\n    });\n\n    it('should not modify imports that match the pattern but are not relative paths', () => {\n      // Edge case: a path that starts with a dot but not ./ or ../\n      // This tests the condition that returns 'match' unchanged\n      const source = `import foo from '.config';`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      // Should not be modified since it doesn't start with ./ or ../\n      expect(result).toBe(source);\n      expect(deprecate).not.toHaveBeenCalled();\n    });\n\n    it('should handle single quotes', () => {\n      const source = `import foo from './utils';`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe(`import foo from './utils.ts';`);\n    });\n\n    it('should handle double quotes', () => {\n      const source = `import foo from \"./utils\";`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe(`import foo from \"./utils.ts\";`);\n    });\n\n    it('should handle paths starting with ./', () => {\n      const source = `import foo from './utils';`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe(`import foo from './utils.ts';`);\n    });\n\n    it('should handle paths starting with ../', () => {\n      const source = `import foo from '../utils';`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe(`import foo from '../utils.ts';`);\n    });\n\n    it('should handle multiple imports in the same file', () => {\n      const source = `import foo from './foo';\\nimport bar from './bar';\\nexport { baz } from '../baz';`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe(\n        `import foo from './foo.ts';\\nimport bar from './bar.ts';\\nexport { baz } from '../baz.ts';`\n      );\n    });\n\n    it('should preserve the import structure after adding extensions', () => {\n      const source = `import { foo, bar } from './utils';`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toContain('{ foo, bar }');\n      expect(result).toBe(`import { foo, bar } from './utils.ts';`);\n    });\n\n    it('should handle imports with comments', () => {\n      const source = `// This is a comment\\nimport foo from './utils'; // inline comment`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe(`// This is a comment\\nimport foo from './utils.ts'; // inline comment`);\n    });\n\n    it('should handle multi-line imports with named exports on separate lines', () => {\n      const source = `import {\n  foo,\n  bar,\n  baz\n} from './utils';`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe(`import {\n  foo,\n  bar,\n  baz\n} from './utils.ts';`);\n    });\n\n    it('should handle multi-line exports with named exports on separate lines', () => {\n      const source = `export {\n  foo,\n  bar\n} from '../module';`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe(`export {\n  foo,\n  bar\n} from '../module.ts';`);\n    });\n\n    it('should handle multi-line dynamic imports', () => {\n      const source = `const module = await import(\n  './utils'\n);`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe(`const module = await import(\n  './utils.ts'\n);`);\n    });\n\n    it('should handle dynamic imports with backticks', () => {\n      const source = 'import(`./foo`);';\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe('import(`./foo.ts`);');\n    });\n\n    it('should not modify dynamic imports with template literal interpolation', () => {\n      const source = 'import(`${foo}/bar`);';\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      // Cannot be supported: template interpolation ${foo} is a runtime value\n      // The regex stops at $ to avoid matching interpolated expressions\n      expect(result).toBe('import(`${foo}/bar`);');\n    });\n\n    it('should not modify dynamic imports with template literal interpolation and relative path', () => {\n      const source = 'import(`./${foo}/bar`);';\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      // Cannot be supported: template interpolation ${foo} is a runtime value\n      // The regex stops at $ to avoid matching interpolated expressions\n      expect(result).toBe('import(`./${foo}/bar`);');\n    });\n\n    it('should handle array of dynamic imports', () => {\n      const source = `const [] = [\n  import('./foo'),\n  import('./bar'),\n];`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe(`const [] = [\n  import('./foo.ts'),\n  import('./bar.ts'),\n];`);\n    });\n\n    it('should handle multi-line backtick dynamic imports', () => {\n      const source = 'const module = await import(\\n  `./utils`\\n);';\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe('const module = await import(\\n  `./utils.ts`\\n);');\n    });\n\n    it('should handle mixed quote types in same file', () => {\n      const source = `import foo from './foo';\\nimport bar from \"./bar\";\\nimport(\\`./baz\\`);`;\n      const result = addExtensionsToRelativeImports(source, '/project/src/file.ts');\n\n      expect(result).toBe(\n        `import foo from './foo.ts';\\nimport bar from \"./bar.ts\";\\nimport(\\`./baz.ts\\`);`\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/bin/loader.ts",
    "content": "/**\n * This is an isolated file that is registered as a loader in Node. It is used to convert TS to ESM\n * using esbuild. Do _not_ import from other modules in core unless strictly necessary, as it will\n * cause the dist to get huge.\n */\nimport { readdirSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport type { LoadHook } from 'node:module';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { deprecate } from 'storybook/internal/node-logger';\n\nimport { transform } from 'esbuild';\nimport { dedent } from 'ts-dedent';\n\nimport { NODE_TARGET } from '../shared/constants/environments-support.ts';\n\nexport const supportedExtensions = [\n  '.js',\n  '.mjs',\n  '.cjs',\n  '.jsx',\n  '.ts',\n  '.mts',\n  '.cts',\n  '.tsx',\n] as const;\n\nconst jsToTsExtensionMap: Record<string, readonly string[]> = {\n  '.js': ['.ts', '.tsx'],\n  '.mjs': ['.mts'],\n  '.cjs': ['.cts'],\n  '.jsx': ['.tsx'],\n};\n\nconst directoryCache = new Map<string, Set<string>>();\n\nexport function clearDirectoryCache(): void {\n  directoryCache.clear();\n}\n\nfunction getDirectoryFiles(dir: string): Set<string> {\n  if (!directoryCache.has(dir)) {\n    try {\n      directoryCache.set(dir, new Set(readdirSync(dir)));\n    } catch {\n      directoryCache.set(dir, new Set());\n    }\n  }\n  return directoryCache.get(dir)!;\n}\n\n/**\n * Resolves an extensionless file path by trying different extensions. Returns the path with the\n * correct extension if found, otherwise returns the original path. Also handles .js → .ts\n * resolution for TypeScript projects using moduleResolution \"Node16\" or \"NodeNext\", where imports\n * use .js extensions but source files are .ts.\n */\nexport function resolveWithExtension(importPath: string, currentFilePath: string): string {\n  const extImportPath = path.extname(importPath);\n  const currentDir = path.dirname(currentFilePath);\n\n  // Handle .js/.mjs/.cjs/.jsx imports that might need to resolve to TypeScript files\n  // TypeScript Node16/NodeNext resolution order: .ts → .tsx → .d.ts → .js\n  // So we check TypeScript alternatives FIRST, then fall back to JS\n  if (extImportPath && extImportPath in jsToTsExtensionMap) {\n    const basePath = importPath.slice(0, -extImportPath.length);\n    const tsExtensions = jsToTsExtensionMap[extImportPath];\n\n    // Try TypeScript alternatives first (.js → .ts/.tsx, .mjs → .mts, etc.)\n    const absoluteBase = path.resolve(currentDir, basePath);\n    const dirFiles = getDirectoryFiles(path.dirname(absoluteBase));\n    const baseFileName = path.basename(absoluteBase);\n    for (const tsExt of tsExtensions) {\n      if (dirFiles.has(`${baseFileName}${tsExt}`)) {\n        return `${basePath}${tsExt}`;\n      }\n    }\n\n    // No TypeScript alternative found, fall back to original JS path\n    return importPath;\n  }\n\n  // If the import has a non-JS extension, return it as-is\n  if (extImportPath) {\n    return importPath;\n  }\n\n  deprecate(dedent`\n    One or more extensionless imports detected: \"${importPath}\" in file \"${currentFilePath}\".\n    For more information on how to resolve the issue: \n    https://storybook.js.org/docs/faq#extensionless-imports-in-storybookmaints-and-required-ts-extensions\n  `);\n\n  const absolutePath = path.resolve(currentDir, importPath);\n\n  const dirFiles = getDirectoryFiles(path.dirname(absolutePath));\n  const baseFileName = path.basename(absolutePath);\n  for (const ext of supportedExtensions) {\n    if (dirFiles.has(`${baseFileName}${ext}`)) {\n      return `${importPath}${ext}`;\n    }\n  }\n\n  return importPath;\n}\n\n/**\n * Adds extensions to relative imports in the source code. This is necessary because Node.js ESM\n * requires explicit extensions for relative imports.\n */\nexport function addExtensionsToRelativeImports(source: string, filePath: string): string {\n  // Regex patterns to match different import/export syntaxes with relative paths\n  const patterns = [\n    // import/export ... from './path' or \"../path\" (including side-effect imports)\n    /(\\b(?:import|export)\\s+(?:[^'\"]*?\\s+from\\s+)?['\"])(\\.[^'\"]+)(['\"])/g,\n    // import('./path') or import(\"../path\") - dynamic imports with quotes (with closing paren, no concatenation)\n    /(\\bimport\\s*\\(\\s*['\"])(\\.[^'\"]+)(['\"]\\s*\\))/g,\n    // import(`./path`) - dynamic imports with backticks (with closing paren, no template interpolation)\n    /(\\bimport\\s*\\(\\s*`)(\\.[^`$]+)(`\\s*\\))/g,\n  ];\n\n  let result = source;\n  for (const pattern of patterns) {\n    result = result.replace(pattern, (match, prefix, path, suffix) => {\n      // Only process relative paths (starting with ./ or ../)\n      if (path.startsWith('./') || path.startsWith('../')) {\n        const resolvedPath = resolveWithExtension(path, filePath);\n        return `${prefix}${resolvedPath}${suffix}`;\n      }\n      return match;\n    });\n  }\n\n  return result;\n}\n\nexport const load: LoadHook = async (url, context, nextLoad) => {\n  /** Convert TS to ESM using esbuild */\n  if (\n    url.endsWith('.ts') ||\n    url.endsWith('.tsx') ||\n    url.endsWith('.mts') ||\n    url.endsWith('.cts') ||\n    url.endsWith('.mtsx') ||\n    url.endsWith('.ctsx')\n  ) {\n    const filePath = fileURLToPath(url);\n    const rawSource = await readFile(filePath, 'utf-8');\n    const transformedSource = await transform(rawSource, {\n      loader: 'ts',\n      target: NODE_TARGET,\n      format: 'esm',\n      platform: 'neutral',\n    });\n\n    // Add extensions to relative imports so Node.js ESM can resolve them\n    const sourceWithExtensions = addExtensionsToRelativeImports(transformedSource.code, filePath);\n\n    return {\n      format: 'module',\n      shortCircuit: true,\n      source: sourceWithExtensions,\n    };\n  }\n\n  return nextLoad(url, context);\n};\n"
  },
  {
    "path": "code/core/src/builder-manager/README.md",
    "content": "# Manager-Builder\n\n> NOTE: Do not use this package unless you know what you are doing.\n\nThis package is used internally by Storybook to create the manager side (UI) of Storybook.\n\nThis package uses `esbuild` to bundle the manager-side of addons, and prepare it for modern, ESM supporting browsers.\n\nEach addon is bundled into a separate file, and the manager is responsible for loading them.\nIf a `manager.*` file exists in the config dir (e.g. `.storybook`), it's also bundled, and loaded in the browser.\n\nAdditionally, this package also will add the manager ui via the `@storybook/ui` package, which is already built by `esbuild` in our build process before publishing.\n"
  },
  {
    "path": "code/core/src/builder-manager/index.ts",
    "content": "import { cp, rm, writeFile } from 'node:fs/promises';\n\nimport { stringifyProcessEnvs } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { globalExternals } from '@fal-works/esbuild-plugin-global-externals';\nimport { resolveModulePath } from 'exsolve';\nimport { join, parse } from 'pathe';\nimport sirv from 'sirv';\n\nimport { globalsModuleInfoMap } from '../manager/globals/globals-module-info.ts';\nimport { BROWSER_TARGETS, SUPPORTED_FEATURES } from '../shared/constants/environments-support.ts';\nimport { resolvePackageDir } from '../shared/utils/module.ts';\nimport type {\n  BuilderBuildResult,\n  BuilderFunction,\n  BuilderStartResult,\n  Compilation,\n  ManagerBuilder,\n  StarterFunction,\n} from './types.ts';\nimport { getData } from './utils/data.ts';\nimport { readOrderedFiles } from './utils/files.ts';\nimport { buildFrameworkGlobalsFromOptions } from './utils/framework.ts';\nimport { wrapManagerEntries } from './utils/managerEntries.ts';\nimport { getTemplatePath, renderHTML } from './utils/template.ts';\n\nexport { BROWSER_TARGETS, NODE_TARGET } from '../shared/constants/environments-support.ts';\n\nconst CORE_DIR_ORIGIN = join(resolvePackageDir('storybook'), 'dist/manager');\n\nconst isRootPath = /^\\/($|\\?)/;\nlet compilation: Compilation;\nlet asyncIterator: ReturnType<StarterFunction> | ReturnType<BuilderFunction>;\n\nexport const getConfig: ManagerBuilder['getConfig'] = async (options) => {\n  const [managerEntriesFromPresets, envs] = await Promise.all([\n    options.presets.apply('managerEntries', []),\n    options.presets.apply<Record<string, string>>('env'),\n  ]);\n  const tsconfigPath = getTemplatePath('addon.tsconfig.json');\n  let configDirManagerEntry;\n  try {\n    configDirManagerEntry = resolveModulePath('./manager', {\n      from: options.configDir,\n      extensions: ['.js', '.mjs', '.jsx', '.ts', '.mts', '.tsx'],\n    });\n  } catch (e) {\n    // no manager entry found in config directory, that's fine\n  }\n\n  const entryPoints = configDirManagerEntry\n    ? [...managerEntriesFromPresets, configDirManagerEntry]\n    : managerEntriesFromPresets;\n\n  return {\n    entryPoints: await wrapManagerEntries(entryPoints, options.cacheKey),\n    outdir: join(options.outputDir || './', 'sb-addons'),\n    format: 'iife',\n    write: false,\n    ignoreAnnotations: true,\n    resolveExtensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx'],\n    outExtension: { '.js': '.js' },\n    loader: {\n      '.js': 'jsx',\n      // media\n      '.png': 'dataurl',\n      '.gif': 'dataurl',\n      '.jpg': 'dataurl',\n      '.jpeg': 'dataurl',\n      '.svg': 'dataurl',\n      '.webp': 'dataurl',\n      '.webm': 'dataurl',\n      '.mp3': 'dataurl',\n      // modern fonts\n      '.woff2': 'dataurl',\n      // legacy font formats\n      '.woff': 'dataurl',\n      '.eot': 'dataurl',\n      '.ttf': 'dataurl',\n    },\n    target: BROWSER_TARGETS,\n    supported: SUPPORTED_FEATURES,\n    platform: 'browser',\n    bundle: true,\n    minify: false,\n    minifyWhitespace: false,\n    minifyIdentifiers: false,\n    minifySyntax: true,\n    metafile: false, // turn this on to assist with debugging the bundling of managerEntries\n\n    // treeShaking: true,\n\n    sourcemap: false,\n    conditions: ['browser', 'module', 'default'],\n\n    jsxFactory: 'React.createElement',\n    jsxFragment: 'React.Fragment',\n    jsx: 'transform',\n    jsxImportSource: 'react',\n\n    tsconfig: tsconfigPath,\n\n    legalComments: 'external',\n    plugins: [globalExternals(globalsModuleInfoMap)],\n\n    banner: {\n      js: 'try{',\n    },\n    footer: {\n      js: '}catch(e){ console.error(\"[Storybook] One of your manager-entries failed: \" + import.meta.url, e); }',\n    },\n\n    define: {\n      'process.env': JSON.stringify(envs),\n      ...stringifyProcessEnvs(envs),\n      global: 'window',\n      module: '{}',\n    },\n  };\n};\n\nexport const executor = {\n  get: async () => {\n    const { build } = await import('esbuild');\n    return build;\n  },\n};\n\n/**\n * This function is a generator so that we can abort it mid process in case of failure coming from\n * other processes e.g. preview builder\n *\n * I am sorry for making you read about generators today :')\n */\nconst starter: StarterFunction = async function* starterGeneratorFn({\n  startTime,\n  options,\n  router,\n}) {\n  if (!options.quiet) {\n    logger.info('Starting...');\n  }\n\n  const {\n    config,\n    favicon,\n    customHead,\n    features,\n    instance,\n    refs,\n    template,\n    title,\n    logLevel,\n    docsOptions,\n    tagsOptions,\n  } = await getData(options);\n\n  yield;\n\n  // make sure we clear output directory of addons dir before starting\n  // this could cause caching issues where addons are loaded when they shouldn't\n  const addonsDir = config.outdir;\n  await rm(addonsDir, { recursive: true, force: true });\n\n  yield;\n\n  compilation = await instance({\n    ...config,\n  });\n\n  yield;\n\n  router.use(\n    '/sb-addons',\n    sirv(addonsDir, {\n      maxAge: 300000,\n      dev: true,\n      immutable: true,\n    })\n  );\n  router.use(\n    '/sb-manager',\n    sirv(CORE_DIR_ORIGIN, {\n      maxAge: 300000,\n      dev: true,\n      immutable: true,\n    })\n  );\n\n  const { cssFiles, jsFiles } = await readOrderedFiles(addonsDir, compilation?.outputFiles);\n\n  if (compilation.metafile && options.outputDir) {\n    await writeFile(\n      join(options.outputDir, 'metafile.json'),\n      JSON.stringify(compilation.metafile, null, 2)\n    );\n  }\n\n  // Build additional global values\n  const globals: Record<string, any> = await buildFrameworkGlobalsFromOptions(options);\n\n  yield;\n\n  const html = await renderHTML(\n    template,\n    title,\n    favicon,\n    customHead,\n    cssFiles,\n    jsFiles,\n    features,\n    refs,\n    logLevel,\n    docsOptions,\n    tagsOptions,\n    options,\n    globals\n  );\n\n  yield;\n\n  router.use('/', ({ url }, res, next) => {\n    if (url && isRootPath.test(url)) {\n      res.statusCode = 200;\n      res.setHeader('Content-Type', 'text/html');\n      res.write(html);\n      res.end();\n    } else {\n      next();\n    }\n  });\n  router.use(`/index.html`, (req, res) => {\n    res.statusCode = 200;\n    res.setHeader('Content-Type', 'text/html');\n    res.write(html);\n    res.end();\n  });\n\n  return {\n    bail,\n    stats: {\n      toJson: () => ({}),\n    },\n    totalTime: process.hrtime(startTime),\n  } as BuilderStartResult;\n};\n\n/**\n * This function is a generator so that we can abort it mid process in case of failure coming from\n * other processes e.g. preview builder\n *\n * I am sorry for making you read about generators today :')\n */\nconst builder: BuilderFunction = async function* builderGeneratorFn({ startTime, options }) {\n  if (!options.outputDir) {\n    throw new Error('outputDir is required');\n  }\n  logger.step('Building manager..');\n  const {\n    config,\n    customHead,\n    favicon,\n    features,\n    instance,\n    refs,\n    template,\n    title,\n    logLevel,\n    docsOptions,\n    tagsOptions,\n  } = await getData(options);\n  yield;\n\n  const addonsDir = config.outdir;\n  const coreDirTarget = join(options.outputDir, `sb-manager`);\n\n  // TODO: this doesn't watch, we should change this to use the esbuild watch API: https://esbuild.github.io/api/#watch\n  compilation = await instance({\n    ...config,\n    minify: true,\n  });\n\n  yield;\n\n  const managerFiles = cp(CORE_DIR_ORIGIN, coreDirTarget, {\n    filter: (src) => {\n      const { ext } = parse(src);\n      if (ext) {\n        return ext === '.js';\n      }\n      return true;\n    },\n    recursive: true,\n  });\n  const { cssFiles, jsFiles } = await readOrderedFiles(addonsDir, compilation?.outputFiles);\n\n  // Build additional global values\n  const globals: Record<string, any> = await buildFrameworkGlobalsFromOptions(options);\n\n  yield;\n\n  const html = await renderHTML(\n    template,\n    title,\n    favicon,\n    customHead,\n    cssFiles,\n    jsFiles,\n    features,\n    refs,\n    logLevel,\n    docsOptions,\n    tagsOptions,\n    options,\n    globals\n  );\n\n  await Promise.all([writeFile(join(options.outputDir, 'index.html'), html), managerFiles]);\n\n  logger.trace({ message: 'Manager built', time: process.hrtime(startTime) });\n\n  return {\n    toJson: () => ({}),\n  } as BuilderBuildResult;\n};\n\nexport const bail: ManagerBuilder['bail'] = async () => {\n  if (asyncIterator) {\n    try {\n      // we tell the builder (that started) to stop ASAP and wait\n      await asyncIterator.throw(new Error());\n    } catch (e) {\n      //\n    }\n  }\n};\n\nexport const start: ManagerBuilder['start'] = async (options) => {\n  asyncIterator = starter(options);\n  let result;\n\n  do {\n    result = await asyncIterator.next();\n  } while (!result.done);\n\n  return result.value;\n};\n\nexport const build: ManagerBuilder['build'] = async (options) => {\n  asyncIterator = builder(options);\n  let result;\n\n  do {\n    result = await asyncIterator.next();\n  } while (!result.done);\n\n  return result.value;\n};\n\nexport const corePresets: ManagerBuilder['corePresets'] = [];\nexport const overridePresets: ManagerBuilder['overridePresets'] = [];\n"
  },
  {
    "path": "code/core/src/builder-manager/types.ts",
    "content": "import type {\n  Builder,\n  BuilderStats,\n  Builder_Unpromise,\n  Builder_WithRequiredProperty,\n} from 'storybook/internal/types';\n\nimport type { BuildOptions, BuildResult } from 'esbuild';\n\nexport type ManagerBuilder = Builder<\n  Builder_WithRequiredProperty<BuildOptions, 'outdir'> & { entryPoints: string[] },\n  BuilderStats\n>;\nexport type Compilation = BuildResult;\n\nexport type BuilderStartOptions = Parameters<ManagerBuilder['start']>['0'];\nexport type BuilderStartResult = Builder_Unpromise<ReturnType<ManagerBuilder['start']>>;\n\nexport type StarterFunction = (\n  options: BuilderStartOptions\n) => AsyncGenerator<unknown, BuilderStartResult | void, void>;\n\nexport type BuilderBuildOptions = Parameters<ManagerBuilder['build']>['0'];\nexport type BuilderBuildResult = Builder_Unpromise<ReturnType<ManagerBuilder['build']>>;\nexport type BuilderFunction = (\n  options: BuilderBuildOptions\n) => AsyncGenerator<unknown, BuilderBuildResult, void>;\n"
  },
  {
    "path": "code/core/src/builder-manager/utils/data.ts",
    "content": "import { basename } from 'node:path';\n\nimport { getRefs } from 'storybook/internal/common';\nimport type { Options } from 'storybook/internal/types';\n\nimport { executor, getConfig } from '../index.ts';\nimport { readTemplate } from './template.ts';\n\nexport const getData = async (options: Options) => {\n  const refs = getRefs(options);\n  const favicon = options.presets.apply<string>('favicon').then((p) => basename(p));\n\n  const features = options.presets.apply<Record<string, string | boolean>>('features');\n  const logLevel = options.presets.apply<string>('logLevel');\n  const title = options.presets.apply<string>('title');\n  const docsOptions = options.presets.apply('docs', {});\n  const tagsOptions = options.presets.apply('tags', {});\n  const template = readTemplate('template.ejs');\n  const customHead = options.presets.apply<string>('managerHead');\n\n  // we await these, because crucially if these fail, we want to bail out asap\n  const [instance, config] = await Promise.all([\n    //\n    executor.get(),\n    getConfig(options),\n  ]);\n\n  return {\n    refs,\n    features,\n    title,\n    docsOptions,\n    template,\n    customHead,\n    instance,\n    config,\n    logLevel,\n    favicon,\n    tagsOptions,\n  };\n};\n"
  },
  {
    "path": "code/core/src/builder-manager/utils/files.test.ts",
    "content": "import { platform } from 'node:os';\n\nimport { expect, it } from 'vitest';\n\nimport type { OutputFile } from 'esbuild';\n\nimport { sanitizePath } from './files.ts';\n\nconst os = platform();\nconst isWindows = os === 'win32';\n\nit('sanitizePath', () => {\n  const addonsDir = isWindows\n    ? 'C:\\\\Users\\\\username\\\\Projects\\\\projectname\\\\storybook'\n    : '/Users/username/Projects/projectname/storybook';\n  const text = 'demo text';\n  const file: OutputFile = {\n    path: isWindows\n      ? 'C:\\\\Users\\\\username\\\\Projects\\\\projectname\\\\storybook\\\\node_modules\\\\@storybook\\\\addon-x+y\\\\dist\\\\manager.js'\n      : '/Users/username/Projects/projectname/storybook/node_modules/@storybook/addon-x+y/dist/manager.js',\n    contents: Uint8Array.from(Array.from(text).map((letter) => letter.charCodeAt(0))),\n    text,\n    hash: '',\n  };\n  const { location, url } = sanitizePath(file, addonsDir);\n\n  expect(location).toEqual(\n    isWindows\n      ? 'C:\\\\Users\\\\username\\\\Projects\\\\projectname\\\\storybook\\\\node_modules\\\\@storybook\\\\addon-x+y\\\\dist\\\\manager.js'\n      : '/Users/username/Projects/projectname/storybook/node_modules/@storybook/addon-x+y/dist/manager.js'\n  );\n  expect(url).toMatchInlineSnapshot(\n    `\"./sb-addons/node_modules/%40storybook/addon-x%2By/dist/manager.js\"`\n  );\n});\n"
  },
  {
    "path": "code/core/src/builder-manager/utils/files.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join, normalize, relative } from 'node:path';\n\nimport type { OutputFile } from 'esbuild';\n// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\n\nimport type { Compilation } from '../types.ts';\n\nexport async function readOrderedFiles(\n  addonsDir: string,\n  outputFiles: Compilation['outputFiles'] | undefined\n) {\n  const files = await Promise.all(\n    outputFiles?.map(async (file) => {\n      // convert deeply nested paths to a single level, also remove special characters\n      const { location, url } = sanitizePath(file, addonsDir);\n\n      if (!existsSync(location)) {\n        const directory = dirname(location);\n        await mkdir(directory, { recursive: true });\n      }\n      await writeFile(location, file.contents);\n      return url;\n    }) || []\n  );\n\n  const jsFiles = files.filter((file) => file.endsWith('.js'));\n  const cssFiles = files.filter((file) => file.endsWith('.css'));\n  return { cssFiles, jsFiles };\n}\n\nexport function sanitizePath(file: OutputFile, addonsDir: string) {\n  const filePath = relative(addonsDir, file.path);\n  const location = normalize(join(addonsDir, filePath));\n  const url = `./sb-addons/${slash(filePath).split('/').map(encodeURIComponent).join('/')}`;\n\n  return { location, url };\n}\n"
  },
  {
    "path": "code/core/src/builder-manager/utils/framework.ts",
    "content": "import {\n  extractFrameworkPackageName,\n  frameworkPackages,\n  frameworkToRenderer,\n  getFrameworkName,\n} from 'storybook/internal/common';\nimport { type Options, SupportedBuilder } from 'storybook/internal/types';\n\nexport const buildFrameworkGlobalsFromOptions = async (options: Options) => {\n  const globals: Record<string, any> = {};\n\n  const { builder: builderConfig, channelOptions } = await options.presets.apply('core');\n  const builderName = typeof builderConfig === 'string' ? builderConfig : builderConfig?.name;\n  const builder = Object.values(SupportedBuilder).find((builder) => builderName?.includes(builder));\n\n  const frameworkName = await getFrameworkName(options);\n  const frameworkPackageName = extractFrameworkPackageName(frameworkName);\n  const framework = frameworkPackages[frameworkPackageName];\n  const renderer = frameworkToRenderer[framework];\n\n  if (options.configType === 'DEVELOPMENT') {\n    // Manager only needs the token currently, so we don't pass any other channel options.\n    globals.CHANNEL_OPTIONS = { wsToken: channelOptions?.wsToken };\n  }\n  globals.STORYBOOK_BUILDER = builder;\n  globals.STORYBOOK_FRAMEWORK = framework;\n  globals.STORYBOOK_RENDERER = renderer;\n  globals.STORYBOOK_NETWORK_ADDRESS = options.networkAddress;\n\n  return globals;\n};\n"
  },
  {
    "path": "code/core/src/builder-manager/utils/managerEntries.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join, parse, relative, sep } from 'node:path';\n\nimport { resolvePathInStorybookCache } from 'storybook/internal/common';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\n\nconst sanitizeBase = (path: string) => {\n  return path\n    .replaceAll('.', '')\n    .replaceAll('@', '')\n    .replaceAll(sep, '-')\n    .replaceAll('/', '-')\n    .replaceAll(new RegExp(/^(-)+/g), '');\n};\n\nconst sanitizeFinal = (path: string) => {\n  const sections = path.split(/-?node_modules-?/);\n\n  return sections[sections.length - 1].replaceAll('storybook-addon-', '').replaceAll('dist-', '');\n};\n\n/**\n * Manager entries should be **self-invoking** bits of code. They can of-course import from modules,\n * and ESbuild will bundle all of that into a single file. But they should not export anything.\n * However this can't be enforced, so what we do is wrap the given file, in a bit of code like\n * this:\n *\n * ```js\n * import '<<file>>';\n * ```\n *\n * That way we are indicating to ESbuild that we do not care about this files exports, and they will\n * be dropped in the bundle.\n *\n * We do all of that so we can wrap a try-catch around the code. That would have been invalid syntax\n * had the export statements been left in place.\n *\n * We need to wrap each managerEntry with a try-catch because if we do not, a failing managerEntry\n * can stop execution of other managerEntries.\n */\nexport async function wrapManagerEntries(entrypoints: string[], uniqueId?: string) {\n  return Promise.all(\n    entrypoints.map(async (entry, i) => {\n      const { name, dir } = parse(entry);\n      const cacheLocation = resolvePathInStorybookCache('sb-manager', uniqueId);\n\n      if (!cacheLocation) {\n        throw new Error('Could not create/find cache directory');\n      }\n\n      const base = relative(process.cwd(), dir);\n      const location = join(\n        cacheLocation,\n        sanitizeFinal(join(`${sanitizeBase(base)}-${i}`, `${sanitizeBase(name)}-bundle.js`))\n      );\n\n      if (!existsSync(location)) {\n        const directory = dirname(location);\n        await mkdir(directory, { recursive: true });\n      }\n\n      await writeFile(location, `import '${slash(entry).replaceAll(/'/g, \"\\\\'\")}';`);\n\n      return location;\n    })\n  );\n}\n"
  },
  {
    "path": "code/core/src/builder-manager/utils/template.ts",
    "content": "import { readFile } from 'node:fs/promises';\n\nimport type { DocsOptions, Options, Ref, TagsOptions } from 'storybook/internal/types';\n\nimport { render } from 'ejs';\nimport { join } from 'pathe';\n\nimport { resolvePackageDir } from '../../shared/utils/module.ts';\n\nexport const getTemplatePath = (template: string) => {\n  return join(resolvePackageDir('storybook'), 'assets/server', template);\n};\n\nexport const readTemplate = async (template: string) => {\n  const path = getTemplatePath(template);\n\n  return readFile(path, { encoding: 'utf8' });\n};\n\nexport async function getManagerMainTemplate() {\n  return getTemplatePath(`manager.ejs`);\n}\n\nexport const renderHTML = async (\n  template: Promise<string>,\n  title: Promise<string | false>,\n  favicon: Promise<string>,\n  customHead: Promise<string | false>,\n  cssFiles: string[],\n  jsFiles: string[],\n  features: Promise<Record<string, any>>,\n  refs: Promise<Record<string, Ref>>,\n  logLevel: Promise<string>,\n  docsOptions: Promise<DocsOptions>,\n  tagsOptions: Promise<TagsOptions>,\n  { versionCheck, previewUrl, configType, ignorePreview }: Options,\n  globals: Record<string, any>\n) => {\n  const titleRef = await title;\n  const templateRef = await template;\n  const stringifiedGlobals = Object.entries(globals).reduce(\n    (transformed, [key, value]) => ({ ...transformed, [key]: JSON.stringify(value) }),\n    {}\n  );\n\n  return render(templateRef, {\n    title: titleRef ? `${titleRef} - Storybook` : 'Storybook',\n    files: { js: jsFiles, css: cssFiles },\n    favicon: await favicon,\n    globals: {\n      FEATURES: JSON.stringify(await features, null, 2),\n      REFS: JSON.stringify(await refs, null, 2),\n      LOGLEVEL: JSON.stringify(await logLevel, null, 2),\n      DOCS_OPTIONS: JSON.stringify(await docsOptions, null, 2),\n      CONFIG_TYPE: JSON.stringify(await configType, null, 2),\n      // These two need to be double stringified because the UI expects a string\n      VERSIONCHECK: JSON.stringify(JSON.stringify(versionCheck), null, 2),\n      PREVIEW_URL: JSON.stringify(previewUrl, null, 2), // global preview URL\n      TAGS_OPTIONS: JSON.stringify(await tagsOptions, null, 2),\n      ...stringifiedGlobals,\n    },\n    head: (await customHead) || '',\n    ignorePreview,\n  });\n};\n"
  },
  {
    "path": "code/core/src/channels/README.md",
    "content": "# Storybook Channel\n\nStorybook Channel is similar to an EventEmitter.\nChannels are used with Storybook implementations to send/receive events between the Storybook Manager and the Storybook Renderer.\n\n```js\nclass Channel {\n  addListener(type, listener) {}\n  addPeerListener(type, listener) {} // ignore events from itself\n  emit(type, ...args) {}\n  eventNames() {}\n  listenerCount(type) {}\n  listeners(type) {}\n  on(type, listener) {}\n  once(type, listener) {}\n  prependListener(type, listener) {}\n  prependOnceListener(type, listener) {}\n  removeAllListeners(type) {}\n  removeListener(type, listener) {}\n}\n```\n\nThe channel takes a Transport object as a parameter which will be used to send/receive messages. The transport object should implement this interface.\n\n```js\nclass Transport {\n  send(event) {}\n  setHandler(handler) {}\n}\n```\n\nFor more information visit: [storybook.js.org](https://storybook.js.org)\n"
  },
  {
    "path": "code/core/src/channels/index.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { ChannelTransport, Listener } from './index.ts';\nimport { Channel, WebsocketTransport } from './index.ts';\n\nconst MockedWebsocket = vi.hoisted(() => {\n  const ref = { current: undefined as unknown as InstanceType<typeof MyMockedWebsocket> };\n  class MyMockedWebsocket {\n    onopen: () => void;\n\n    onmessage: (event: { data: string }) => void;\n\n    onerror: (e: any) => void;\n\n    onclose: (event: any) => void;\n\n    constructor(url: string) {\n      this.onopen = vi.fn();\n      this.onmessage = vi.fn();\n      this.onerror = vi.fn();\n      this.onclose = vi.fn();\n\n      ref.current = this;\n    }\n\n    send(data: string) {\n      this.onmessage({ data });\n    }\n  }\n  return { MyMockedWebsocket, ref };\n});\n\nvi.mock('@storybook/global', () => ({\n  global: {\n    ...global,\n    WebSocket: MockedWebsocket.MyMockedWebsocket,\n  },\n}));\n\ndescribe('Channel', () => {\n  let transport: ChannelTransport;\n  let channel: Channel;\n\n  beforeEach(() => {\n    transport = { setHandler: vi.fn(), send: vi.fn() };\n    channel = new Channel({ transport });\n  });\n\n  describe('constructor', () => {\n    it('should set the handler if handler is preset', () => {\n      channel = new Channel({ transport });\n      expect(transport.setHandler).toHaveBeenCalled();\n    });\n\n    it('should not set transport if not passed as an argument', () => {\n      channel = new Channel({});\n      expect(channel.hasTransport).toBeFalsy();\n    });\n\n    it('should set transport if passed as an argument', () => {\n      channel = new Channel({ transport });\n      expect(channel.hasTransport).toBeTruthy();\n    });\n\n    it('should set isAsync to false as default value', () => {\n      channel = new Channel({});\n      expect(channel.isAsync).toBeFalsy();\n    });\n\n    it('should set isAsync to true if passed as an argument', () => {\n      channel = new Channel({ async: true });\n      expect(channel.isAsync).toBeTruthy();\n    });\n  });\n\n  describe('method:addListener', () => {\n    it('should create one listener', () => {\n      const eventName = 'event1';\n\n      channel.addListener(eventName, vi.fn());\n      expect(channel.listeners(eventName)?.length).toBe(1);\n    });\n  });\n\n  describe('method:on', () => {\n    it('should do the same as addListener', () => {\n      const eventName = 'event1';\n\n      channel.on(eventName, vi.fn());\n      expect(channel.listeners(eventName)?.length).toBe(1);\n    });\n  });\n\n  describe('method:off', () => {\n    it('should remove listeners', () => {\n      const eventName = 'event1';\n      const fn = vi.fn();\n\n      channel.on(eventName, fn);\n      expect(channel.listeners(eventName)?.length).toBe(1);\n      channel.off(eventName, fn);\n      expect(channel.listeners(eventName)?.length).toBe(0);\n    });\n  });\n\n  describe('method:emit', () => {\n    it('should execute the callback fn of a listener', () => {\n      const eventName = 'event1';\n      const listenerInputData = ['string1', 'string2', 'string3'];\n      let listenerOutputData: string[] | null = null;\n      const mockListener: Listener = (data) => {\n        listenerOutputData = data;\n      };\n\n      channel.addListener(eventName, mockListener);\n      channel.emit(eventName, listenerInputData);\n      expect(listenerOutputData).toBe(listenerInputData);\n    });\n\n    it('should be callable with a spread operator as event arguments', () => {\n      const eventName = 'event1';\n      const listenerInputData = ['string1', 'string2', 'string3'];\n      let listenerOutputData: string[] | null = null;\n\n      channel.addListener(eventName, (...data) => {\n        listenerOutputData = data;\n      });\n      channel.emit(eventName, ...listenerInputData);\n      expect(listenerOutputData).toEqual(listenerInputData);\n    });\n\n    it('should be callable with options on the event', () => {\n      const eventName = 'event1';\n      const listenerInputData = [{ event: {}, options: { depth: 1 } }];\n      let listenerOutputData: any = null;\n\n      channel.addListener(eventName, (...data) => {\n        listenerOutputData = data;\n      });\n      const sendSpy = vi.fn();\n      // @ts-expect-error (access private property for testing purposes)\n      channel.transports.forEach((t) => {\n        t.send = sendSpy;\n      });\n      channel.emit(eventName, ...listenerInputData);\n      expect(listenerOutputData).toEqual(listenerInputData);\n      expect(sendSpy.mock.calls[0][1]).toEqual({ depth: 1 });\n    });\n\n    it('should use setImmediate if async is true', () => {\n      global.setImmediate = vi.fn(setImmediate);\n\n      channel = new Channel({ async: true, transport });\n      channel.addListener('event1', vi.fn());\n\n      channel.emit('event1', 'test-data');\n\n      expect(setImmediate).toHaveBeenCalled();\n    });\n  });\n\n  describe('method:eventNames', () => {\n    it('should return a list of all registered events', () => {\n      const eventNames = ['event1', 'event2', 'event3'];\n      eventNames.forEach((eventName) => channel.addListener(eventName, vi.fn()));\n\n      expect(channel.eventNames()).toEqual(eventNames);\n    });\n  });\n\n  describe('method:listenerCount', () => {\n    it('should return a list of all registered events', () => {\n      const events = [\n        { eventName: 'event1', listeners: [vi.fn(), vi.fn(), vi.fn()], listenerCount: 0 },\n        { eventName: 'event2', listeners: [vi.fn()], listenerCount: 0 },\n      ];\n      events.forEach((event) => {\n        event.listeners.forEach((listener) => {\n          channel.addListener(event.eventName, listener);\n\n          event.listenerCount++;\n        });\n      });\n\n      events.forEach((event) => {\n        expect(channel.listenerCount(event.eventName)).toBe(event.listenerCount);\n      });\n    });\n  });\n\n  describe('method:once', () => {\n    it('should execute a listener once and remove it afterwards', () => {\n      const eventName = 'event1';\n      channel.once(eventName, vi.fn());\n      channel.emit(eventName);\n\n      expect(channel.listenerCount(eventName)).toBe(0);\n    });\n\n    it('should pass all event arguments correctly to the listener', () => {\n      const eventName = 'event1';\n      const listenerInputData = ['string1', 'string2', 'string3'];\n      let listenerOutputData = null;\n      const mockListener: Listener = (data: string[]) => {\n        listenerOutputData = data;\n      };\n\n      channel.once(eventName, (args) => mockListener(args));\n      channel.emit(eventName, listenerInputData);\n\n      expect(listenerOutputData).toEqual(listenerInputData);\n    });\n\n    it('should be removable', () => {\n      const eventName = 'event1';\n      const listenerToBeRemoved = vi.fn();\n\n      channel.once(eventName, listenerToBeRemoved);\n      channel.removeListener(eventName, listenerToBeRemoved);\n    });\n  });\n\n  describe('method:removeAllListeners', () => {\n    it('should remove all listeners', () => {\n      const eventName1 = 'event1';\n      const eventName2 = 'event2';\n      const listeners1 = [vi.fn(), vi.fn(), vi.fn()];\n      const listeners2 = [vi.fn()];\n\n      listeners1.forEach((fn) => channel.addListener(eventName1, fn));\n      listeners2.forEach((fn) => channel.addListener(eventName2, fn));\n      channel.removeAllListeners();\n\n      expect(channel.listenerCount(eventName1)).toBe(0);\n      expect(channel.listenerCount(eventName2)).toBe(0);\n    });\n\n    it('should remove all listeners of a certain event', () => {\n      const eventName = 'event1';\n      const listeners = [vi.fn(), vi.fn(), vi.fn()];\n\n      listeners.forEach((fn) => channel.addListener(eventName, fn));\n      expect(channel.listenerCount(eventName)).toBe(listeners.length);\n\n      channel.removeAllListeners(eventName);\n      expect(channel.listenerCount(eventName)).toBe(0);\n    });\n  });\n\n  describe('method:removeListener', () => {\n    it('should remove one listener', () => {\n      const eventName = 'event1';\n      const listenerToBeRemoved = vi.fn();\n      const listeners = [vi.fn(), vi.fn()];\n      const findListener = (listener: Listener) =>\n        channel.listeners(eventName)?.find((_listener) => _listener === listener);\n\n      listeners.forEach((fn) => channel.addListener(eventName, fn));\n      channel.addListener(eventName, listenerToBeRemoved);\n      expect(findListener(listenerToBeRemoved)).toBe(listenerToBeRemoved);\n\n      channel.removeListener(eventName, listenerToBeRemoved);\n      expect(findListener(listenerToBeRemoved)).toBeUndefined();\n    });\n  });\n});\n\ndescribe('WebsocketTransport', () => {\n  it('should connect', async () => {\n    const onError = vi.fn();\n    const handler = vi.fn();\n\n    const transport = new WebsocketTransport({\n      url: 'ws://localhost:6006',\n      page: 'preview',\n      onError,\n    });\n\n    transport.setHandler(handler);\n    MockedWebsocket.ref.current.onopen();\n\n    expect(handler).toHaveBeenCalledTimes(0);\n  });\n  it('should send message upon disconnect', async () => {\n    const onError = vi.fn();\n    const handler = vi.fn();\n\n    const transport = new WebsocketTransport({\n      url: 'ws://localhost:6006',\n      page: 'preview',\n      onError,\n    });\n\n    transport.setHandler(handler);\n    MockedWebsocket.ref.current.onclose({ code: 1000, reason: 'test' });\n\n    expect(handler.mock.calls[0][0]).toMatchInlineSnapshot(`\n      {\n        \"args\": [\n          {\n            \"code\": 1000,\n            \"reason\": \"test\",\n          },\n        ],\n        \"from\": \"preview\",\n        \"type\": \"channelWSDisconnect\",\n      }\n    `);\n  });\n  it('should send message when send', async () => {\n    const onError = vi.fn();\n    const handler = vi.fn();\n\n    const transport = new WebsocketTransport({\n      url: 'ws://localhost:6006',\n      page: 'preview',\n      onError,\n    });\n\n    transport.setHandler(handler);\n    MockedWebsocket.ref.current.send('{ \"type\": \"test\", \"args\": [], \"from\": \"preview\" }');\n\n    expect(handler.mock.calls[0][0]).toMatchInlineSnapshot(`\n      {\n        \"args\": [],\n        \"from\": \"preview\",\n        \"type\": \"test\",\n      }\n    `);\n  });\n  it('should call onError handler', async () => {\n    const onError = vi.fn();\n    const handler = vi.fn();\n\n    const transport = new WebsocketTransport({\n      url: 'ws://localhost:6006',\n      page: 'preview',\n      onError,\n    });\n\n    transport.setHandler(handler);\n    MockedWebsocket.ref.current.onerror(new Error('testError'));\n\n    expect(onError.mock.calls[0][0]).toMatchInlineSnapshot(`[Error: testError]`);\n  });\n});\n"
  },
  {
    "path": "code/core/src/channels/index.ts",
    "content": "/// <reference path=\"../typings.d.ts\" />\nimport { global } from '@storybook/global';\n\nimport { UniversalStore } from '../shared/universal-store/index.ts';\nimport { Channel } from './main.ts';\nimport { PostMessageTransport } from './postmessage/index.ts';\nimport type { ChannelTransport, Config } from './types.ts';\nimport { WebsocketTransport } from './websocket/index.ts';\n\nconst { CHANNEL_OPTIONS, CONFIG_TYPE } = global;\n\nexport * from './main.ts';\n\nexport default Channel;\n\nexport { PostMessageTransport } from './postmessage/index.ts';\nexport {\n  WebsocketTransport,\n  HEARTBEAT_INTERVAL,\n  HEARTBEAT_MAX_LATENCY,\n} from './websocket/index.ts';\n\ntype Options = Config & {\n  extraTransports?: ChannelTransport[];\n};\n\n/**\n * Creates a new browser channel instance.\n *\n * @param {Options} options - The options object.\n * @param {Page} options.page - Page identifier.\n * @param {ChannelTransport[]} [options.extraTransports=[]] - An optional array of extra channel\n *   transports. Default is `[]`\n * @returns {Channel} - The new channel instance.\n */\nexport function createBrowserChannel({ page, extraTransports = [] }: Options): Channel {\n  const transports: ChannelTransport[] = [new PostMessageTransport({ page }), ...extraTransports];\n\n  if (CONFIG_TYPE === 'DEVELOPMENT') {\n    const protocol = window.location.protocol === 'http:' ? 'ws' : 'wss';\n    const { hostname, port } = window.location;\n    const { wsToken } = CHANNEL_OPTIONS || {};\n    const channelUrl = `${protocol}://${hostname}:${port}/storybook-server-channel?token=${wsToken}`;\n\n    transports.push(new WebsocketTransport({ url: channelUrl, onError: () => {}, page }));\n  }\n\n  const channel = new Channel({ transports });\n  UniversalStore.__prepare(\n    channel,\n    page === 'manager' ? UniversalStore.Environment.MANAGER : UniversalStore.Environment.PREVIEW\n  );\n\n  return channel;\n}\n\nexport type {\n  Listener,\n  ChannelEvent,\n  ChannelTransport,\n  ChannelHandler,\n  ChannelLike,\n} from './types.ts';\n"
  },
  {
    "path": "code/core/src/channels/main.ts",
    "content": "import type {\n  ChannelArgs,\n  ChannelArgsMulti,\n  ChannelArgsSingle,\n  ChannelEvent,\n  ChannelLike,\n  ChannelTransport,\n  EventsKeyValue,\n  Listener,\n} from './types.ts';\n\nconst isMulti = (args: ChannelArgs): args is ChannelArgsMulti => {\n  // @ts-expect-error (we guard against this right here)\n  return args.transports !== undefined;\n};\n\nconst generateRandomId = () => {\n  // generates a random 13 character string\n  return Math.random().toString(16).slice(2);\n};\n\nexport class Channel implements ChannelLike {\n  readonly isAsync: boolean;\n\n  private sender = generateRandomId();\n\n  private events: EventsKeyValue = {};\n\n  private data: Record<string, any> = {};\n\n  private readonly transports: ChannelTransport[] = [];\n\n  constructor(input: ChannelArgsMulti);\n  constructor(input: ChannelArgsSingle);\n  constructor(input: ChannelArgs = {}) {\n    this.isAsync = input.async || false;\n\n    if (isMulti(input)) {\n      this.transports = input.transports || [];\n\n      this.transports.forEach((t) => {\n        t.setHandler((event) => this.handleEvent(event));\n      });\n    } else {\n      this.transports = input.transport ? [input.transport] : [];\n    }\n\n    this.transports.forEach((t) => {\n      t.setHandler((event) => this.handleEvent(event));\n    });\n  }\n\n  get hasTransport() {\n    return this.transports.length > 0;\n  }\n\n  addListener(eventName: string, listener: Listener) {\n    this.events[eventName] = this.events[eventName] || [];\n    this.events[eventName].push(listener);\n  }\n\n  emit(eventName: string, ...args: any) {\n    const event: ChannelEvent = { type: eventName, args, from: this.sender };\n    let options = {};\n    if (args.length >= 1 && args[0] && args[0].options) {\n      options = args[0].options;\n    }\n\n    const handler = () => {\n      this.transports.forEach((t) => {\n        t.send(event, options);\n      });\n      this.handleEvent(event);\n    };\n\n    if (this.isAsync) {\n      // todo I'm not sure how to test this\n      setImmediate(handler);\n    } else {\n      handler();\n    }\n  }\n\n  last(eventName: string) {\n    return this.data[eventName];\n  }\n\n  eventNames() {\n    return Object.keys(this.events);\n  }\n\n  listenerCount(eventName: string) {\n    const listeners = this.listeners(eventName);\n    return listeners ? listeners.length : 0;\n  }\n\n  listeners(eventName: string): Listener[] | undefined {\n    const listeners = this.events[eventName];\n    return listeners || undefined;\n  }\n\n  once(eventName: string, listener: Listener) {\n    const onceListener: Listener = this.onceListener(eventName, listener);\n    this.addListener(eventName, onceListener);\n  }\n\n  removeAllListeners(eventName?: string) {\n    if (!eventName) {\n      this.events = {};\n    } else if (this.events[eventName]) {\n      delete this.events[eventName];\n    }\n  }\n\n  removeListener(eventName: string, listener: Listener) {\n    const listeners = this.listeners(eventName);\n    if (listeners) {\n      this.events[eventName] = listeners.filter((l) => l !== listener);\n    }\n  }\n\n  on(eventName: string, listener: Listener) {\n    this.addListener(eventName, listener);\n  }\n\n  off(eventName: string, listener: Listener) {\n    this.removeListener(eventName, listener);\n  }\n\n  private handleEvent(event: ChannelEvent) {\n    const listeners = this.listeners(event.type);\n    if (listeners && listeners.length) {\n      listeners.forEach((fn) => {\n        fn.apply(event, event.args);\n      });\n    }\n    this.data[event.type] = event.args;\n  }\n\n  private onceListener(eventName: string, listener: Listener) {\n    const onceListener: Listener = (...args: any[]) => {\n      this.removeListener(eventName, onceListener);\n      return listener(...args);\n    };\n    return onceListener;\n  }\n}\n"
  },
  {
    "path": "code/core/src/channels/postmessage/getEventSourceUrl.ts",
    "content": "import { logger } from 'storybook/internal/client-logger';\n\n/**\n * When multiple iframes match the event origin (e.g. composed refs from the same origin),\n * disambiguate by refId: the preview includes refId in the URL, so we pick the iframe whose src\n * contains that refId. If there is only one candidate, return it.\n */\nconst pickFrameByRefId = (\n  candidates: HTMLIFrameElement[],\n  refId: string | undefined\n): HTMLIFrameElement | undefined => {\n  if (candidates.length === 1) {\n    return candidates[0];\n  }\n  if (candidates.length === 0 || !refId) {\n    return undefined;\n  }\n  return candidates.find((el) =>\n    (el.getAttribute('src') ?? '').includes(`refId=${encodeURIComponent(refId)}`)\n  );\n};\n\nexport const getEventSourceUrl = (event: MessageEvent, refId?: string): string | null => {\n  const frames: HTMLIFrameElement[] = Array.from(\n    document.querySelectorAll('iframe[data-is-storybook]')\n  );\n  // try to find the originating iframe by matching it's contentWindow\n  // This might not be cross-origin safe\n  const candidates = frames.filter((element) => {\n    try {\n      return (\n        element.contentWindow?.location.origin === (event.source as Window).location.origin &&\n        element.contentWindow?.location.pathname === (event.source as Window).location.pathname\n      );\n    } catch {\n      // continue\n    }\n    try {\n      return element.contentWindow === event.source;\n    } catch {\n      // continue\n    }\n\n    const src = element.getAttribute('src');\n    let origin;\n\n    try {\n      if (!src) {\n        return false;\n      }\n\n      ({ origin } = new URL(src, document.location.toString()));\n    } catch {\n      return false;\n    }\n    return origin === event.origin;\n  });\n\n  const src = pickFrameByRefId(candidates, refId)?.getAttribute('src');\n\n  if (src) {\n    const { protocol, host, pathname } = new URL(src, document.location.toString());\n    return `${protocol}//${host}${pathname}`;\n  }\n\n  if (candidates.length > 1) {\n    // Multiple matches and we couldn't disambiguate (e.g. no refId in message)\n    logger.error('found multiple candidates for event source');\n  }\n\n  return null;\n};\n"
  },
  {
    "path": "code/core/src/channels/postmessage/index.ts",
    "content": "/// <reference path=\"../../typings.d.ts\" />\nimport { logger, pretty } from 'storybook/internal/client-logger';\nimport * as EVENTS from 'storybook/internal/core-events';\n\nimport { global } from '@storybook/global';\n\nimport { isJSON, parse, stringify } from 'telejson';\nimport invariant from 'tiny-invariant';\n\nimport type {\n  BufferedEvent,\n  ChannelEvent,\n  ChannelHandler,\n  ChannelTransport,\n  Config,\n} from '../types.ts';\nimport { getEventSourceUrl } from './getEventSourceUrl.ts';\n\nconst { document, location } = global;\n\nexport const KEY = 'storybook-channel';\n\nconst defaultEventOptions = { maxDepth: 25 };\n\n// TODO: we should export a method for opening child windows here and keep track of em.\n// that way we can send postMessage to child windows as well, not just iframe\n// https://stackoverflow.com/questions/6340160/how-to-get-the-references-of-all-already-opened-child-windows\n\nexport class PostMessageTransport implements ChannelTransport {\n  private buffer: BufferedEvent[];\n\n  private handler?: ChannelHandler;\n\n  private connected = false;\n\n  constructor(private readonly config: Config) {\n    this.buffer = [];\n\n    if (typeof global?.addEventListener === 'function') {\n      global.addEventListener('message', this.handleEvent.bind(this), false);\n    }\n\n    // Check whether the config.page parameter has a valid value\n    if (config.page !== 'manager' && config.page !== 'preview') {\n      throw new Error(`postmsg-channel: \"config.page\" cannot be \"${config.page}\"`);\n    }\n  }\n\n  setHandler(handler: ChannelHandler): void {\n    this.handler = (...args) => {\n      handler.apply(this, args);\n\n      if (!this.connected && this.getLocalFrame().length) {\n        this.flush();\n        this.connected = true;\n      }\n    };\n  }\n\n  /**\n   * Sends `event` to the associated window. If the window does not yet exist the event will be\n   * stored in a buffer and sent when the window exists.\n   *\n   * @param event\n   */\n  send(event: ChannelEvent, options?: any): Promise<any> {\n    const {\n      target,\n\n      // telejson options\n      allowRegExp,\n      allowSymbol,\n      allowDate,\n      allowError,\n      allowUndefined,\n      maxDepth,\n      space,\n    } = options || {};\n\n    const eventOptions = Object.fromEntries(\n      Object.entries({\n        allowRegExp,\n        allowSymbol,\n        allowDate,\n        allowError,\n        allowUndefined,\n        maxDepth,\n        space,\n      }).filter(([k, v]) => typeof v !== 'undefined')\n    );\n\n    const stringifyOptions = {\n      ...defaultEventOptions,\n      ...(global.CHANNEL_OPTIONS || {}),\n      ...eventOptions,\n    };\n\n    const frames = this.getFrames(target);\n\n    const query = new URLSearchParams(location?.search || '');\n\n    const data = stringify(\n      {\n        key: KEY,\n        event,\n        refId: query.get('refId'),\n      },\n      stringifyOptions\n    );\n\n    if (!frames.length) {\n      return new Promise((resolve, reject) => {\n        this.buffer.push({ event, resolve, reject });\n      });\n    }\n    if (this.buffer.length) {\n      this.flush();\n    }\n\n    frames.forEach((f) => {\n      try {\n        f.postMessage(data, '*');\n      } catch (e) {\n        logger.error('sending over postmessage fail');\n      }\n    });\n\n    return Promise.resolve(null);\n  }\n\n  private flush(): void {\n    const { buffer } = this;\n    this.buffer = [];\n    buffer.forEach((item) => {\n      this.send(item.event).then(item.resolve).catch(item.reject);\n    });\n  }\n\n  private getFrames(target?: string): Window[] {\n    if (this.config.page === 'manager') {\n      const nodes: HTMLIFrameElement[] = Array.from(\n        document.querySelectorAll('iframe[data-is-storybook][data-is-loaded]')\n      );\n\n      const list = nodes.flatMap((e) => {\n        try {\n          if (!!e.contentWindow && e.dataset.isStorybook !== undefined && e.id === target) {\n            return [e.contentWindow];\n          }\n          return [];\n        } catch (er) {\n          return [];\n        }\n      });\n\n      return list?.length ? list : this.getCurrentFrames();\n    }\n\n    if (global && global.parent && global.parent !== global.self) {\n      return [global.parent];\n    }\n\n    return [];\n  }\n\n  private getCurrentFrames(): Window[] {\n    if (this.config.page === 'manager') {\n      const list: HTMLIFrameElement[] = Array.from(\n        document.querySelectorAll('[data-is-storybook=\"true\"]')\n      );\n      return list.flatMap((e) => (e.contentWindow ? [e.contentWindow] : []));\n    }\n    if (global && global.parent) {\n      return [global.parent];\n    }\n\n    return [];\n  }\n\n  private getLocalFrame(): Window[] {\n    if (this.config.page === 'manager') {\n      const list: HTMLIFrameElement[] = Array.from(\n        document.querySelectorAll('#storybook-preview-iframe')\n      );\n      return list.flatMap((e) => (e.contentWindow ? [e.contentWindow] : []));\n    }\n    if (global && global.parent) {\n      return [global.parent];\n    }\n\n    return [];\n  }\n\n  private handleEvent(rawEvent: MessageEvent): void {\n    try {\n      const { data } = rawEvent;\n      const { key, event, refId } =\n        typeof data === 'string' && isJSON(data) ? parse(data, global.CHANNEL_OPTIONS || {}) : data;\n\n      if (key === KEY) {\n        const pageString =\n          this.config.page === 'manager'\n            ? `<span style=\"color: #37D5D3; background: black\"> manager </span>`\n            : `<span style=\"color: #1EA7FD; background: black\"> preview </span>`;\n\n        const eventString = Object.values(EVENTS).includes(event.type)\n          ? `<span style=\"color: #FF4785\">${event.type}</span>`\n          : `<span style=\"color: #FFAE00\">${event.type}</span>`;\n\n        if (refId) {\n          event.refId = refId;\n        }\n\n        event.source =\n          this.config.page === 'preview' ? rawEvent.origin : getEventSourceUrl(rawEvent, refId);\n\n        if (!event.source) {\n          pretty.error(\n            `${pageString} received ${eventString} but was unable to determine the source of the event`\n          );\n\n          return;\n        }\n        const message = `${pageString} received ${eventString} (${data.length})`;\n        pretty.debug(\n          location.origin !== event.source\n            ? message\n            : `${message} <span style=\"color: gray\">(on ${location.origin} from ${event.source})</span>`,\n          ...event.args\n        );\n\n        invariant(this.handler, 'ChannelHandler should be set');\n        this.handler(event);\n      }\n    } catch (error) {\n      logger.error(error);\n    }\n  }\n}\n"
  },
  {
    "path": "code/core/src/channels/types.ts",
    "content": "export interface Config {\n  page: 'manager' | 'preview';\n}\n\nexport interface BufferedEvent {\n  event: ChannelEvent;\n  resolve: (value?: any) => void;\n  reject: (reason?: any) => void;\n}\n\nexport type ChannelHandler = (event: ChannelEvent) => void;\n\nexport interface ChannelTransport {\n  send(event: ChannelEvent, options?: any): void;\n  setHandler(handler: ChannelHandler): void;\n}\n\nexport interface ChannelEvent {\n  type: string; // eventName\n  from: string;\n  args: any[];\n}\n\nexport interface Listener {\n  (...args: any[]): void;\n}\n\nexport interface EventsKeyValue {\n  [key: string]: Listener[];\n}\n\n/**\n * Structural interface for Channel, used in type declarations to avoid nominal incompatibility\n * between source and dist Channel class declarations.\n */\nexport interface ChannelLike {\n  readonly isAsync: boolean;\n  readonly hasTransport: boolean;\n  addListener(eventName: string, listener: Listener): void;\n  emit(eventName: string, ...args: any): void;\n  last(eventName: string): any;\n  eventNames(): string[];\n  listenerCount(eventName: string): number;\n  listeners(eventName: string): Listener[] | undefined;\n  once(eventName: string, listener: Listener): void;\n  removeAllListeners(eventName?: string): void;\n  removeListener(eventName: string, listener: Listener): void;\n  on(eventName: string, listener: Listener): void;\n  off(eventName: string, listener: Listener): void;\n}\nexport type ChannelArgs = ChannelArgsSingle | ChannelArgsMulti;\nexport interface ChannelArgsSingle {\n  transport?: ChannelTransport;\n  async?: boolean;\n}\nexport interface ChannelArgsMulti {\n  transports: ChannelTransport[];\n  async?: boolean;\n}\n"
  },
  {
    "path": "code/core/src/channels/websocket/index.ts",
    "content": "/// <reference path=\"../../typings.d.ts\" />\nimport * as EVENTS from 'storybook/internal/core-events';\n\nimport { global } from '@storybook/global';\n\nimport { isJSON, parse, stringify } from 'telejson';\nimport invariant from 'tiny-invariant';\n\nimport type { ChannelHandler, ChannelTransport, Config } from '../types.ts';\n\nconst { WebSocket } = global;\n\ntype OnError = (message: Event) => void;\n\ninterface WebsocketTransportArgs extends Partial<Config> {\n  url: string;\n  onError: OnError;\n}\n\nexport const HEARTBEAT_INTERVAL = 15000;\nexport const HEARTBEAT_MAX_LATENCY = 5000;\n\nexport class WebsocketTransport implements ChannelTransport {\n  private buffer: string[] = [];\n\n  private handler?: ChannelHandler;\n\n  private socket: WebSocket;\n\n  private isReady = false;\n\n  private isClosed = false;\n\n  private pingTimeout: number | NodeJS.Timeout = 0;\n\n  private heartbeat() {\n    clearTimeout(this.pingTimeout);\n\n    this.pingTimeout = setTimeout(() => {\n      this.socket.close(3008, 'timeout');\n    }, HEARTBEAT_INTERVAL + HEARTBEAT_MAX_LATENCY);\n  }\n\n  constructor({ url, onError, page }: WebsocketTransportArgs) {\n    this.socket = new WebSocket(url);\n    this.socket.onopen = () => {\n      this.isReady = true;\n      this.heartbeat();\n      this.flush();\n    };\n    this.socket.onmessage = ({ data }) => {\n      const event = typeof data === 'string' && isJSON(data) ? parse(data) : data;\n      invariant(this.handler, 'WebsocketTransport handler should be set');\n      this.handler(event);\n      if (event.type === 'ping') {\n        this.heartbeat();\n        this.send({ type: 'pong' });\n      }\n    };\n    this.socket.onerror = (e) => {\n      if (onError) {\n        onError(e);\n      }\n    };\n    this.socket.onclose = (ev) => {\n      invariant(this.handler, 'WebsocketTransport handler should be set');\n      this.handler({\n        type: EVENTS.CHANNEL_WS_DISCONNECT,\n        args: [{ reason: ev.reason, code: ev.code }],\n        from: page || 'preview',\n      });\n      this.isClosed = true;\n      clearTimeout(this.pingTimeout);\n    };\n  }\n\n  setHandler(handler: ChannelHandler) {\n    this.handler = handler;\n  }\n\n  send(event: any) {\n    if (!this.isClosed) {\n      if (!this.isReady) {\n        this.sendLater(event);\n      } else {\n        this.sendNow(event);\n      }\n    }\n  }\n\n  private sendLater(event: any) {\n    this.buffer.push(event);\n  }\n\n  private sendNow(event: any) {\n    const data = stringify(event, {\n      maxDepth: 15,\n      ...global.CHANNEL_OPTIONS,\n    });\n    this.socket.send(data);\n  }\n\n  private flush() {\n    const { buffer } = this;\n    this.buffer = [];\n    buffer.forEach((event) => this.send(event));\n  }\n}\n"
  },
  {
    "path": "code/core/src/cli/AddonVitestService.constants.ts",
    "content": "import { SupportedFramework } from '../types/index.ts';\n\nexport const SUPPORTED_FRAMEWORKS: readonly SupportedFramework[] = [\n  SupportedFramework.HTML_VITE,\n  SupportedFramework.NEXTJS_VITE,\n  SupportedFramework.PREACT_VITE,\n  SupportedFramework.REACT_NATIVE_WEB_VITE,\n  SupportedFramework.REACT_VITE,\n  SupportedFramework.SOLID,\n  SupportedFramework.SVELTE_VITE,\n  SupportedFramework.SVELTEKIT,\n  SupportedFramework.VUE3_VITE,\n  SupportedFramework.WEB_COMPONENTS_VITE,\n];\n"
  },
  {
    "path": "code/core/src/cli/AddonVitestService.test.ts",
    "content": "import * as fs from 'node:fs/promises';\nimport os from 'node:os';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { JsPackageManager } from 'storybook/internal/common';\nimport { getProjectRoot } from 'storybook/internal/common';\nimport { logger, prompt } from 'storybook/internal/node-logger';\n\nimport * as find from 'empathic/find';\n// eslint-disable-next-line depend/ban-dependencies\nimport type { ResultPromise } from 'execa';\n\nimport { SupportedBuilder, SupportedFramework } from '../types/index.ts';\nimport { AddonVitestService } from './AddonVitestService.ts';\n\nvi.mock('node:fs/promises', { spy: true });\nvi.mock('node:os', { spy: true });\nvi.mock('storybook/internal/common', { spy: true });\nvi.mock('storybook/internal/node-logger', { spy: true });\nvi.mock('empathic/find', { spy: true });\n\ndescribe('AddonVitestService', () => {\n  let service: AddonVitestService;\n  let mockPackageManager: JsPackageManager;\n\n  beforeEach(() => {\n    vi.clearAllMocks();\n    mockPackageManager = {\n      getAllDependencies: vi.fn(),\n      getInstalledVersion: vi.fn(),\n      runPackageCommand: vi.fn(),\n      getPackageCommand: vi.fn(),\n    } as Partial<JsPackageManager> as JsPackageManager;\n\n    service = new AddonVitestService(mockPackageManager);\n    vi.mocked(getProjectRoot).mockReturnValue('/test/project');\n\n    // Setup default mocks for logger and prompt\n    vi.mocked(logger.info).mockImplementation(() => {});\n    vi.mocked(logger.log).mockImplementation(() => {});\n    vi.mocked(logger.warn).mockImplementation(() => {});\n    vi.mocked(prompt.executeTask).mockResolvedValue(undefined);\n    vi.mocked(prompt.executeTaskWithSpinner).mockResolvedValue(undefined);\n    vi.mocked(prompt.confirm).mockResolvedValue(true);\n  });\n\n  describe('collectDeps', () => {\n    beforeEach(() => {\n      vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({});\n      vi.mocked(mockPackageManager.getInstalledVersion).mockResolvedValue(null);\n    });\n\n    it('should collect base packages when not installed', async () => {\n      vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({});\n      vi.mocked(mockPackageManager.getInstalledVersion)\n        .mockResolvedValueOnce(null) // vitest version check\n        .mockResolvedValueOnce(null) // @vitest/coverage-v8\n        .mockResolvedValueOnce(null); // @vitest/coverage-istanbul\n\n      const deps = await service.collectDependencies();\n\n      expect(deps).toContain('vitest');\n      // When vitest version is null, defaults to vitest 4+ behavior\n      expect(deps).toContain('@vitest/browser-playwright');\n      expect(deps).toContain('playwright');\n      expect(deps).toContain('@vitest/coverage-v8');\n    });\n\n    it('should not include base packages if already installed', async () => {\n      vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({\n        vitest: '3.0.0',\n        '@vitest/browser': '3.0.0',\n        playwright: '1.0.0',\n      });\n      vi.mocked(mockPackageManager.getInstalledVersion)\n        .mockResolvedValueOnce('3.0.0') // vitest version\n        .mockResolvedValueOnce('3.0.0') // @vitest/coverage-v8\n        .mockResolvedValueOnce(null); // @vitest/coverage-istanbul\n\n      const deps = await service.collectDependencies();\n\n      expect(deps).not.toContain('vitest');\n      expect(deps).not.toContain('@vitest/browser');\n      expect(deps).not.toContain('playwright');\n    });\n\n    // Note: collectDependencies doesn't add framework-specific packages\n    // It only collects base vitest packages\n    it('should collect base packages without framework-specific additions', async () => {\n      vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({});\n      vi.mocked(mockPackageManager.getInstalledVersion)\n        .mockResolvedValueOnce(null) // vitest version check\n        .mockResolvedValueOnce(null) // @vitest/coverage-v8\n        .mockResolvedValueOnce(null); // @vitest/coverage-istanbul\n\n      const deps = await service.collectDependencies();\n\n      // Should only contain base packages, not framework-specific ones\n      expect(deps).toContain('vitest');\n      // When vitest version is null, defaults to vitest 4+ behavior\n      expect(deps).toContain('@vitest/browser-playwright');\n      expect(deps).toContain('playwright');\n      expect(deps).toContain('@vitest/coverage-v8');\n      expect(deps.every((d) => !d.includes('nextjs-vite'))).toBe(true);\n    });\n\n    it('should not add @storybook/nextjs-vite for non-Next.js frameworks', async () => {\n      vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({});\n      vi.mocked(mockPackageManager.getInstalledVersion)\n        .mockResolvedValueOnce(null) // vitest version\n        .mockResolvedValueOnce(null) // @vitest/coverage-v8\n        .mockResolvedValueOnce(null); // @vitest/coverage-istanbul\n\n      const deps = await service.collectDependencies();\n\n      expect(deps.every((d) => !d.includes('nextjs-vite'))).toBe(true);\n    });\n\n    it('should not add coverage reporter if v8 already installed', async () => {\n      vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({});\n      vi.mocked(mockPackageManager.getInstalledVersion)\n        .mockResolvedValueOnce(null) // vitest version\n        .mockResolvedValueOnce('3.0.0') // @vitest/coverage-v8\n        .mockResolvedValueOnce(null); // @vitest/coverage-istanbul\n\n      const deps = await service.collectDependencies();\n\n      expect(deps.every((d) => !d.includes('coverage'))).toBe(true);\n    });\n\n    it('skips coverage if istanbul', async () => {\n      vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({});\n      vi.mocked(mockPackageManager.getInstalledVersion)\n        .mockResolvedValueOnce(null) // @vitest/coverage-v8\n        .mockResolvedValueOnce('3.0.0') // @vitest/coverage-istanbul\n        .mockResolvedValueOnce(null); // vitest version\n\n      const deps = await service.collectDependencies();\n\n      expect(deps.every((d) => !d.includes('coverage'))).toBe(true);\n    });\n\n    it('applies version', async () => {\n      vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({});\n      vi.mocked(mockPackageManager.getInstalledVersion)\n        .mockResolvedValueOnce('3.2.0') // vitest version check\n        .mockResolvedValueOnce(null) // @vitest/coverage-v8\n        .mockResolvedValueOnce(null); // @vitest/coverage-istanbul\n\n      const deps = await service.collectDependencies();\n\n      expect(deps).toContain('vitest@3.2.0');\n      // Version 3.2.0 < 4.0.0, so uses @vitest/browser\n      expect(deps).toContain('@vitest/browser@3.2.0');\n      expect(deps).toContain('@vitest/coverage-v8@3.2.0');\n      expect(deps).toContain('playwright'); // no version for playwright\n    });\n  });\n\n  describe('validatePackageVersions', () => {\n    it('should return compatible when vitest >=3.0.0', async () => {\n      vi.mocked(mockPackageManager.getInstalledVersion)\n        .mockResolvedValueOnce('3.0.0') // vitest\n        .mockResolvedValueOnce(null); // msw\n\n      const result = await service.validatePackageVersions();\n\n      expect(result.compatible).toBe(true);\n      expect(result.reasons).toBeUndefined();\n    });\n\n    it('should return compatible when vitest prerelease >= 3.0.0', async () => {\n      vi.mocked(mockPackageManager.getInstalledVersion)\n        .mockResolvedValueOnce('3.0.0-beta.1') // vitest\n        .mockResolvedValueOnce(null); // msw\n\n      const result = await service.validatePackageVersions();\n\n      expect(result.compatible).toBe(true);\n      expect(result.reasons).toBeUndefined();\n    });\n\n    it('should return compatible when vitest canary is used', async () => {\n      vi.mocked(mockPackageManager.getInstalledVersion)\n        .mockResolvedValueOnce('0.0.0-833c515fa25cef20905a7f9affb156dfa6f151ab') // vitest\n        .mockResolvedValueOnce(null); // msw\n\n      const result = await service.validatePackageVersions();\n\n      expect(result.compatible).toBe(true);\n      expect(result.reasons).toBeUndefined();\n    });\n\n    it('should return compatible when vitest >=4.0.0', async () => {\n      vi.mocked(mockPackageManager.getInstalledVersion)\n        .mockResolvedValueOnce('4.0.0') // vitest\n        .mockResolvedValueOnce(null); // msw\n\n      const result = await service.validatePackageVersions();\n\n      expect(result.compatible).toBe(true);\n      expect(result.reasons).toBeUndefined();\n    });\n\n    it('should return incompatible when vitest <3.0.0', async () => {\n      vi.mocked(mockPackageManager.getInstalledVersion)\n        .mockResolvedValueOnce('2.5.0') // vitest\n        .mockResolvedValueOnce(null); // msw\n\n      const result = await service.validatePackageVersions();\n\n      expect(result.compatible).toBe(false);\n      expect(result.reasons).toBeDefined();\n      expect(result.reasons!.some((r) => r.includes('Vitest 3.0.0 or higher'))).toBe(true);\n    });\n\n    it('should return compatible when msw >=2.0.0', async () => {\n      vi.mocked(mockPackageManager.getInstalledVersion)\n        .mockResolvedValueOnce('3.0.0') // vitest\n        .mockResolvedValueOnce('2.0.0'); // msw\n\n      const result = await service.validatePackageVersions();\n\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should return incompatible when msw <2.0.0', async () => {\n      vi.mocked(mockPackageManager.getInstalledVersion)\n        .mockResolvedValueOnce('3.0.0') // vitest\n        .mockResolvedValueOnce('1.9.0'); // msw\n\n      const result = await service.validatePackageVersions();\n\n      expect(result.compatible).toBe(false);\n      expect(result.reasons).toBeDefined();\n      expect(result.reasons!.some((r) => r.includes('MSW'))).toBe(true);\n    });\n\n    it('should return compatible when msw not installed', async () => {\n      vi.mocked(mockPackageManager.getInstalledVersion)\n        .mockResolvedValueOnce('3.0.0') // vitest\n        .mockResolvedValueOnce(null); // msw\n\n      const result = await service.validatePackageVersions();\n\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should return compatible when vitest is not installed', async () => {\n      vi.mocked(mockPackageManager.getInstalledVersion)\n        .mockResolvedValueOnce(null) // vitest\n        .mockResolvedValueOnce(null); // msw\n\n      const result = await service.validatePackageVersions();\n\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should handle multiple validation failures', async () => {\n      vi.mocked(mockPackageManager.getInstalledVersion)\n        .mockResolvedValueOnce('2.0.0') // vitest <3.0.0\n        .mockResolvedValueOnce('1.0.0'); // msw <2.0.0\n\n      const result = await service.validatePackageVersions();\n\n      expect(result.compatible).toBe(false);\n      expect(result.reasons).toBeDefined();\n      expect(result.reasons!.length).toBe(2);\n    });\n  });\n\n  describe('validateCompatibility', () => {\n    beforeEach(() => {\n      vi.mocked(mockPackageManager.getInstalledVersion).mockResolvedValue('3.0.0');\n      vi.mocked(find.any).mockReturnValue(undefined);\n    });\n\n    it('should return compatible for valid Vite-based framework', async () => {\n      const result = await service.validateCompatibility({\n        framework: SupportedFramework.REACT_VITE,\n        builder: SupportedBuilder.VITE,\n      });\n\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should return compatible for react-vite with Vite builder', async () => {\n      const result = await service.validateCompatibility({\n        framework: SupportedFramework.REACT_VITE,\n        builder: SupportedBuilder.VITE,\n      });\n\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should return incompatible for non-Vite builder (except Next.js)', async () => {\n      const result = await service.validateCompatibility({\n        framework: SupportedFramework.REACT_WEBPACK5,\n        builder: SupportedBuilder.WEBPACK5,\n      });\n\n      expect(result.compatible).toBe(false);\n      expect(result.reasons!.some((r) => r.includes('Non-Vite builder'))).toBe(true);\n    });\n\n    it('should return incompatible for Next.js with webpack builder', async () => {\n      vi.mocked(mockPackageManager.getInstalledVersion)\n        .mockResolvedValueOnce('3.0.0') // vitest\n        .mockResolvedValueOnce(null); // msw\n\n      const result = await service.validateCompatibility({\n        framework: SupportedFramework.NEXTJS,\n        builder: SupportedBuilder.WEBPACK5,\n      });\n\n      // Test addon requires Vite builder, even for Next.js\n      expect(result.compatible).toBe(false);\n      expect(result.reasons!.some((r) => r.includes('Non-Vite builder'))).toBe(true);\n    });\n\n    it('should return incompatible for unsupported framework', async () => {\n      const result = await service.validateCompatibility({\n        framework: SupportedFramework.ANGULAR,\n        builder: SupportedBuilder.VITE,\n      });\n\n      expect(result.compatible).toBe(false);\n      expect(result.reasons!.some((r) => r.includes('cannot yet be used'))).toBe(true);\n    });\n\n    // Note: validateCompatibility currently doesn't validate Next.js installation\n    // It only validates builder, framework support, package versions, and config files\n    it('should return compatible for Next.js framework with valid setup', async () => {\n      vi.mocked(mockPackageManager.getInstalledVersion)\n        .mockResolvedValueOnce('3.0.0') // vitest\n        .mockResolvedValueOnce(null); // msw\n\n      const result = await service.validateCompatibility({\n        framework: SupportedFramework.NEXTJS_VITE,\n        builder: SupportedBuilder.VITE,\n      });\n\n      // NEXTJS_VITE framework is in SUPPORTED_FRAMEWORKS and Vite builder is compatible\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should validate config files when configDir provided', async () => {\n      vi.mocked(find.any).mockReturnValueOnce('vitest.workspace.json');\n\n      const result = await service.validateCompatibility({\n        framework: SupportedFramework.REACT_VITE,\n        builder: SupportedBuilder.VITE,\n        projectRoot: '.storybook',\n      });\n\n      expect(result.compatible).toBe(false);\n      expect(result.reasons!.some((r) => r.includes('JSON workspace'))).toBe(true);\n    });\n\n    it('should skip config file validation when no configDir provided', async () => {\n      vi.mocked(find.any).mockReturnValueOnce('vitest.workspace.json');\n\n      const result = await service.validateCompatibility({\n        framework: SupportedFramework.REACT_VITE,\n        builder: SupportedBuilder.VITE,\n      });\n\n      expect(result.compatible).toBe(true);\n      expect(find.any).not.toHaveBeenCalled();\n    });\n\n    it('should accumulate multiple validation failures', async () => {\n      vi.mocked(mockPackageManager.getInstalledVersion)\n        .mockResolvedValueOnce('2.0.0') // vitest <3.0.0\n        .mockResolvedValueOnce('1.0.0'); // msw <2.0.0\n\n      const result = await service.validateCompatibility({\n        framework: SupportedFramework.ANGULAR,\n        builder: SupportedBuilder.WEBPACK5,\n      });\n\n      expect(result.compatible).toBe(false);\n      expect(result.reasons).toBeDefined();\n      expect(result.reasons!.length).toBeGreaterThan(2);\n    });\n  });\n\n  describe('installPlaywright', () => {\n    beforeEach(() => {\n      // Mock the logger methods used in installPlaywright\n      vi.mocked(logger.log).mockImplementation(() => {});\n      vi.mocked(logger.warn).mockImplementation(() => {});\n      // Mock getPackageCommand to return a string\n      vi.mocked(mockPackageManager.getPackageCommand).mockReturnValue(\n        'npx playwright install chromium'\n      );\n    });\n\n    it('should install Playwright successfully', async () => {\n      vi.mocked(prompt.confirm).mockResolvedValue(true);\n      vi.mocked(prompt.executeTaskWithSpinner).mockResolvedValue(undefined);\n\n      const { errors } = await service.installPlaywright();\n\n      expect(errors).toEqual([]);\n      expect(prompt.confirm).toHaveBeenCalledWith({\n        message: 'Do you want to install Playwright with Chromium now?',\n        initialValue: true,\n      });\n      expect(prompt.executeTaskWithSpinner).toHaveBeenCalledWith(expect.any(Function), {\n        id: 'playwright-installation',\n        intro: 'Installing Playwright browser binaries (press \"c\" to abort)',\n        error: expect.stringContaining('An error occurred'),\n        success: 'Playwright browser binaries installed successfully',\n        abortable: true,\n      });\n    });\n\n    it('should execute playwright install command', async () => {\n      const originalCI = process.env.CI;\n      delete process.env.CI;\n      vi.mocked(os.platform).mockReturnValue('linux');\n      try {\n        type ChildProcessFactory = (signal?: AbortSignal) => ResultPromise;\n        let commandFactory: ChildProcessFactory | ChildProcessFactory[];\n        vi.mocked(prompt.confirm).mockResolvedValue(true);\n        vi.mocked(prompt.executeTaskWithSpinner).mockImplementation(\n          async (factory: ChildProcessFactory | ChildProcessFactory[]) => {\n            commandFactory = Array.isArray(factory) ? factory[0] : factory;\n            // Simulate the child process completion\n            commandFactory();\n          }\n        );\n\n        await service.installPlaywright();\n\n        expect(mockPackageManager.runPackageCommand).toHaveBeenCalledWith({\n          args: ['playwright', 'install', 'chromium'],\n          signal: undefined,\n          stdio: ['inherit', 'pipe', 'pipe'],\n        });\n      } finally {\n        if (originalCI !== undefined) {\n          process.env.CI = originalCI;\n        }\n      }\n    });\n\n    it('should warn about missing system dependencies after install on Linux', async () => {\n      const originalCI = process.env.CI;\n      delete process.env.CI;\n      vi.mocked(os.platform).mockReturnValue('linux');\n      try {\n        type ChildProcessFactory = (signal?: AbortSignal) => ResultPromise;\n        vi.mocked(prompt.confirm).mockResolvedValue(true);\n        vi.mocked(prompt.executeTaskWithSpinner).mockImplementation(\n          async (factory: ChildProcessFactory | ChildProcessFactory[]) => {\n            const commandFactory = Array.isArray(factory) ? factory[0] : factory;\n            commandFactory();\n          }\n        );\n\n        const { result } = await service.installPlaywright();\n\n        expect(result).toBe('installed');\n        expect(logger.warn).toHaveBeenCalledWith(\n          expect.stringContaining('installed without system dependencies')\n        );\n        expect(logger.warn).toHaveBeenCalledWith(\n          expect.stringContaining('run Storybook Test from the Storybook UI')\n        );\n      } finally {\n        if (originalCI !== undefined) {\n          process.env.CI = originalCI;\n        }\n      }\n    });\n\n    it('should execute playwright install command with --with-deps in CI', async () => {\n      const originalCI = process.env.CI;\n      process.env.CI = 'true';\n      vi.mocked(os.platform).mockReturnValue('linux');\n      try {\n        type ChildProcessFactory = (signal?: AbortSignal) => ResultPromise;\n        let commandFactory: ChildProcessFactory | ChildProcessFactory[];\n        vi.mocked(prompt.confirm).mockResolvedValue(true);\n        vi.mocked(prompt.executeTaskWithSpinner).mockImplementation(\n          async (factory: ChildProcessFactory | ChildProcessFactory[]) => {\n            commandFactory = Array.isArray(factory) ? factory[0] : factory;\n            commandFactory();\n          }\n        );\n\n        await service.installPlaywright();\n\n        expect(mockPackageManager.runPackageCommand).toHaveBeenCalledWith({\n          args: ['playwright', 'install', 'chromium', '--with-deps'],\n          signal: undefined,\n          stdio: ['inherit', 'pipe', 'pipe'],\n        });\n      } finally {\n        if (originalCI === undefined) {\n          delete process.env.CI;\n        } else {\n          process.env.CI = originalCI;\n        }\n      }\n    });\n\n    it.each(['darwin', 'win32'] as const)(\n      'should execute playwright install command with --with-deps on %s',\n      async (platform) => {\n        const originalCI = process.env.CI;\n        delete process.env.CI;\n        vi.mocked(os.platform).mockReturnValue(platform);\n        try {\n          type ChildProcessFactory = (signal?: AbortSignal) => ResultPromise;\n          let commandFactory: ChildProcessFactory | ChildProcessFactory[];\n          vi.mocked(prompt.confirm).mockResolvedValue(true);\n          vi.mocked(prompt.executeTaskWithSpinner).mockImplementation(\n            async (factory: ChildProcessFactory | ChildProcessFactory[]) => {\n              commandFactory = Array.isArray(factory) ? factory[0] : factory;\n              commandFactory();\n            }\n          );\n\n          await service.installPlaywright();\n\n          expect(mockPackageManager.runPackageCommand).toHaveBeenCalledWith({\n            args: ['playwright', 'install', 'chromium', '--with-deps'],\n            signal: undefined,\n            stdio: ['inherit', 'pipe', 'pipe'],\n          });\n        } finally {\n          if (originalCI !== undefined) {\n            process.env.CI = originalCI;\n          }\n        }\n      }\n    );\n\n    it('should capture error stack when installation fails', async () => {\n      const error = new Error('Installation failed');\n      error.stack = 'Error stack trace';\n      vi.mocked(prompt.confirm).mockResolvedValue(true);\n      vi.mocked(prompt.executeTaskWithSpinner).mockRejectedValue(error);\n\n      const { errors } = await service.installPlaywright();\n\n      expect(errors).toEqual(['Error stack trace']);\n    });\n\n    it('should capture error message when installation fails without stack', async () => {\n      const error = new Error('Installation failed');\n      error.stack = undefined;\n      vi.mocked(prompt.confirm).mockResolvedValue(true);\n      vi.mocked(prompt.executeTaskWithSpinner).mockRejectedValue(error);\n\n      const { errors } = await service.installPlaywright();\n\n      expect(errors).toEqual(['Installation failed']);\n    });\n\n    it('should convert non-Error exceptions to string', async () => {\n      vi.mocked(prompt.confirm).mockResolvedValue(true);\n      vi.mocked(prompt.executeTaskWithSpinner).mockRejectedValue('String error');\n\n      const { errors } = await service.installPlaywright();\n\n      expect(errors).toEqual(['String error']);\n    });\n\n    it('should skip installation when user declines', async () => {\n      vi.mocked(prompt.confirm).mockResolvedValue(false);\n\n      const { errors } = await service.installPlaywright();\n\n      expect(errors).toEqual([]);\n      expect(prompt.executeTaskWithSpinner).not.toHaveBeenCalled();\n      expect(logger.warn).toHaveBeenCalledWith('Playwright installation skipped');\n    });\n\n    it('should not skip installation by default', async () => {\n      vi.mocked(prompt.confirm).mockResolvedValue(true);\n      vi.mocked(prompt.executeTaskWithSpinner).mockResolvedValue(undefined);\n\n      await service.installPlaywright();\n\n      expect(prompt.confirm).toHaveBeenCalled();\n      expect(prompt.executeTaskWithSpinner).toHaveBeenCalled();\n    });\n  });\n\n  describe('validateConfigFiles', () => {\n    beforeEach(() => {\n      vi.mocked(find.any).mockReset();\n      vi.mocked(find.any).mockReturnValue(undefined);\n    });\n\n    it('should return compatible when no config files found', async () => {\n      vi.mocked(find.any).mockReturnValue(undefined);\n\n      const result = await service.validateConfigFiles('.storybook');\n\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should reject JSON workspace files', async () => {\n      vi.mocked(find.any).mockReturnValueOnce('vitest.workspace.json');\n\n      const result = await service.validateConfigFiles('.storybook');\n\n      expect(result.compatible).toBe(false);\n      expect(result.reasons).toBeDefined();\n      expect(result.reasons!.some((r) => r.includes('JSON workspace'))).toBe(true);\n    });\n\n    it('should validate non-JSON workspace files', async () => {\n      vi.mocked(find.any).mockReturnValueOnce('vitest.workspace.ts');\n      vi.mocked(fs.readFile).mockResolvedValue('export default [\"project1\", \"project2\"]');\n\n      const result = await service.validateConfigFiles('.storybook');\n\n      expect(result.compatible).toBe(true);\n      expect(fs.readFile).toHaveBeenCalledWith('vitest.workspace.ts', 'utf8');\n    });\n\n    it('should reject invalid workspace config', async () => {\n      vi.mocked(find.any).mockReturnValueOnce('vitest.workspace.ts');\n      vi.mocked(fs.readFile).mockResolvedValue('export default \"invalid\"');\n\n      const result = await service.validateConfigFiles('.storybook');\n\n      expect(result.compatible).toBe(false);\n      expect(result.reasons!.some((r) => r.includes('invalid workspace'))).toBe(true);\n    });\n\n    it('should reject CommonJS config files (.cts)', async () => {\n      vi.mocked(find.any).mockReset();\n      vi.mocked(find.any)\n        .mockReturnValueOnce(undefined) // workspace\n        .mockReturnValueOnce('vitest.config.cts'); // config\n\n      const result = await service.validateConfigFiles('.storybook');\n\n      expect(result.compatible).toBe(false);\n      expect(result.reasons).toBeDefined();\n      expect(result.reasons!.length).toBeGreaterThan(0);\n      expect(result.reasons!.some((r) => r.includes('CommonJS config'))).toBe(true);\n    });\n\n    it('should reject CommonJS config files (.cjs)', async () => {\n      vi.mocked(find.any)\n        .mockReturnValueOnce(undefined) // workspace\n        .mockReturnValueOnce('vitest.config.cjs'); // config\n\n      const result = await service.validateConfigFiles('.storybook');\n\n      expect(result.compatible).toBe(false);\n      expect(result.reasons!.some((r) => r.includes('CommonJS config'))).toBe(true);\n    });\n\n    it('should validate non-CommonJS config files', async () => {\n      vi.mocked(find.any)\n        .mockReturnValueOnce(undefined) // workspace\n        .mockReturnValueOnce('vitest.config.ts'); // config\n      vi.mocked(fs.readFile).mockResolvedValue('export default defineConfig({ test: {} })');\n\n      const result = await service.validateConfigFiles('.storybook');\n\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should accept plain export default {}', async () => {\n      vi.mocked(find.any)\n        .mockReturnValueOnce(undefined) // workspace\n        .mockReturnValueOnce('vitest.config.ts'); // config\n      vi.mocked(fs.readFile).mockResolvedValue('export default {}');\n\n      const result = await service.validateConfigFiles('.storybook');\n\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should reject arrow function vitest config (unsupported)', async () => {\n      vi.mocked(find.any)\n        .mockReturnValueOnce(undefined) // workspace\n        .mockReturnValueOnce('vitest.config.ts'); // config\n      vi.mocked(fs.readFile).mockResolvedValue(\n        `import { defineConfig } from 'vitest/config';\nexport default defineConfig(() => ({ test: {} }))`\n      );\n\n      const result = await service.validateConfigFiles('.storybook');\n\n      expect(result.compatible).toBe(false);\n      expect(result.reasons!.some((r) => r.includes('invalid Vitest config'))).toBe(true);\n    });\n\n    it('should validate defineWorkspace expression', async () => {\n      vi.mocked(find.any).mockReturnValueOnce('vitest.workspace.ts');\n      vi.mocked(fs.readFile).mockResolvedValue('export default defineWorkspace([\"project1\"])');\n\n      const result = await service.validateConfigFiles('.storybook');\n\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should validate workspace config with object expressions', async () => {\n      vi.mocked(find.any).mockReturnValueOnce('vitest.workspace.ts');\n      vi.mocked(fs.readFile).mockResolvedValue('export default [{ test: {} }, \"project\"]');\n\n      const result = await service.validateConfigFiles('.storybook');\n\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should validate config with workspace array in test', async () => {\n      vi.mocked(find.any)\n        .mockReturnValueOnce(undefined) // workspace\n        .mockReturnValueOnce('vitest.config.ts'); // config\n      vi.mocked(fs.readFile).mockResolvedValue(\n        'export default defineConfig({ test: { workspace: [] } })'\n      );\n\n      const result = await service.validateConfigFiles('.storybook');\n\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should accumulate multiple config validation errors', async () => {\n      vi.mocked(find.any).mockReset();\n      vi.mocked(find.any)\n        .mockReturnValueOnce('vitest.workspace.json') // workspace JSON\n        .mockReturnValueOnce('vitest.config.cjs'); // config CJS\n\n      const result = await service.validateConfigFiles('.storybook');\n\n      expect(result.compatible).toBe(false);\n      expect(result.reasons).toBeDefined();\n      expect(result.reasons!.length).toBe(2);\n    });\n\n    it('should validate mergeConfig with plain object literal', async () => {\n      vi.mocked(find.any)\n        .mockReturnValueOnce(undefined) // workspace\n        .mockReturnValueOnce('vitest.config.ts'); // config\n      vi.mocked(fs.readFile).mockResolvedValue(\n        'export default mergeConfig(viteConfig, { test: { name: \"node\" } })'\n      );\n      const result = await service.validateConfigFiles('.storybook');\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should validate mergeConfig with defineConfig call', async () => {\n      vi.mocked(find.any)\n        .mockReturnValueOnce(undefined) // workspace\n        .mockReturnValueOnce('vitest.config.ts'); // config\n      vi.mocked(fs.readFile).mockResolvedValue(\n        'export default mergeConfig(viteConfig, defineConfig({ test: { name: \"node\" } }))'\n      );\n      const result = await service.validateConfigFiles('.storybook');\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should validate mergeConfig with multiple plain objects', async () => {\n      vi.mocked(find.any)\n        .mockReturnValueOnce(undefined) // workspace\n        .mockReturnValueOnce('vitest.config.ts'); // config\n      vi.mocked(fs.readFile).mockResolvedValue(\n        'export default mergeConfig({ test: {} }, { plugins: [] })'\n      );\n      const result = await service.validateConfigFiles('.storybook');\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should accept defineConfig(mergeConfig(...)) pattern', async () => {\n      vi.mocked(find.any)\n        .mockReturnValueOnce(undefined) // workspace\n        .mockReturnValueOnce('vitest.config.ts'); // config\n      vi.mocked(fs.readFile).mockResolvedValue(\n        `\n        import { defineConfig, mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        export default defineConfig(\n          mergeConfig(viteConfig, {\n            test: { name: 'node', environment: 'happy-dom' },\n          })\n        )`\n      );\n      const result = await service.validateConfigFiles('.storybook');\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should accept defineConfig(mergeConfig(...) satisfies ViteUserConfig) pattern', async () => {\n      vi.mocked(find.any)\n        .mockReturnValueOnce(undefined) // workspace\n        .mockReturnValueOnce('vitest.config.ts'); // config\n      vi.mocked(fs.readFile).mockResolvedValue(\n        `\n        import { defineConfig, mergeConfig } from 'vitest/config';\n        import type { ViteUserConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        export default defineConfig(\n          mergeConfig(viteConfig, {\n            test: { name: 'node' },\n          }) satisfies ViteUserConfig\n        )`\n      );\n      const result = await service.validateConfigFiles('.storybook');\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should accept mergeConfig(...) as ViteUserConfig pattern', async () => {\n      vi.mocked(find.any)\n        .mockReturnValueOnce(undefined) // workspace\n        .mockReturnValueOnce('vitest.config.ts'); // config\n      vi.mocked(fs.readFile).mockResolvedValue(\n        `\n        import { mergeConfig } from 'vitest/config';\n        import type { ViteUserConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        export default mergeConfig(viteConfig, {\n          test: { name: 'node' },\n        }) as ViteUserConfig`\n      );\n      const result = await service.validateConfigFiles('.storybook');\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should accept mergeConfig with shorthand test variable', async () => {\n      vi.mocked(find.any)\n        .mockReturnValueOnce(undefined) // workspace\n        .mockReturnValueOnce('vitest.config.ts'); // config\n      vi.mocked(fs.readFile).mockResolvedValue(\n        `\n        import { mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        const test = { name: 'node', environment: 'happy-dom' };\n        export default mergeConfig(viteConfig, { test })`\n      );\n      const result = await service.validateConfigFiles('.storybook');\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should accept mergeConfig with external vitestConfig variable', async () => {\n      vi.mocked(find.any)\n        .mockReturnValueOnce(undefined) // workspace\n        .mockReturnValueOnce('vitest.config.ts'); // config\n      vi.mocked(fs.readFile).mockResolvedValue(\n        `\n        import { mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        const vitestConfig = { test: { name: 'node' } };\n        export default mergeConfig(viteConfig, vitestConfig)`\n      );\n      const result = await service.validateConfigFiles('.storybook');\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should accept const config = mergeConfig(...); export default config pattern', async () => {\n      vi.mocked(find.any)\n        .mockReturnValueOnce(undefined) // workspace\n        .mockReturnValueOnce('vitest.config.ts'); // config\n      vi.mocked(fs.readFile).mockResolvedValue(\n        `\n        import { defineConfig, mergeConfig } from 'vitest/config';\n        import viteConfig from './vite.config';\n        const config = mergeConfig(\n          viteConfig,\n          defineConfig({ test: { name: 'node' } })\n        );\n        export default config`\n      );\n      const result = await service.validateConfigFiles('.storybook');\n      expect(result.compatible).toBe(true);\n    });\n\n    it('should accept defineProject({}) pattern', async () => {\n      vi.mocked(find.any)\n        .mockReturnValueOnce(undefined) // workspace\n        .mockReturnValueOnce('vitest.config.ts'); // config\n      vi.mocked(fs.readFile).mockResolvedValue(\n        `\n        import { defineProject } from 'vitest/config';\n        export default defineProject({\n          test: { name: 'node', environment: 'happy-dom' },\n        })`\n      );\n      const result = await service.validateConfigFiles('.storybook');\n      expect(result.compatible).toBe(true);\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/cli/AddonVitestService.ts",
    "content": "import fs from 'node:fs/promises';\nimport os from 'node:os';\n\nimport { canUpdateVitestConfigFile, canUpdateVitestWorkspaceFile } from 'storybook/internal/babel';\nimport type { JsPackageManager } from 'storybook/internal/common';\nimport { getProjectRoot } from 'storybook/internal/common';\nimport { CLI_COLORS } from 'storybook/internal/node-logger';\nimport { logger, prompt } from 'storybook/internal/node-logger';\nimport { ErrorCollector } from 'storybook/internal/telemetry';\n\nimport * as find from 'empathic/find';\nimport { coerce, minVersion, satisfies, validRange } from 'semver';\nimport { dedent } from 'ts-dedent';\n\nimport { SupportedBuilder, type SupportedFramework } from '../types/index.ts';\nimport { SUPPORTED_FRAMEWORKS } from './AddonVitestService.constants.ts';\n\ntype Result = {\n  compatible: boolean;\n  reasons?: string[];\n};\n\nexport interface AddonVitestCompatibilityOptions {\n  builder?: SupportedBuilder;\n  framework?: SupportedFramework | null;\n  projectRoot?: string;\n}\n\n/**\n * Centralized service for @storybook/addon-vitest dependency collection and compatibility\n * validation\n *\n * This service consolidates logic from:\n *\n * - Code/addons/vitest/src/postinstall.ts\n * - Code/lib/create-storybook/src/addon-dependencies/addon-vitest.ts\n * - Code/lib/create-storybook/src/services/FeatureCompatibilityService.ts\n */\nexport class AddonVitestService {\n  constructor(private readonly packageManager: JsPackageManager) {}\n\n  /**\n   * Collect all dependencies needed for @storybook/addon-vitest\n   *\n   * Returns versioned package strings ready for installation:\n   *\n   * - Base packages: vitest, @vitest/browser, playwright\n   * - Next.js specific: @storybook/nextjs-vite\n   * - Coverage reporter: @vitest/coverage-v8\n   */\n  async collectDependencies(): Promise<string[]> {\n    const allDeps = this.packageManager.getAllDependencies();\n    const dependencies: string[] = [];\n\n    // Determine Vitest version/range from installed or declared dependency to avoid pulling\n    // incompatible majors by default.\n    let vitestVersionSpecifier = await this.packageManager.getInstalledVersion('vitest');\n    if (!vitestVersionSpecifier && allDeps['vitest']) {\n      vitestVersionSpecifier = allDeps['vitest'];\n    }\n\n    let isVitest4OrNewer = true;\n    if (vitestVersionSpecifier) {\n      const range = validRange(vitestVersionSpecifier);\n      const versionToCheck = range\n        ? minVersion(range)?.version\n        : coerce(vitestVersionSpecifier)?.version;\n      isVitest4OrNewer = versionToCheck ? satisfies(versionToCheck, '>=4.0.0') : true;\n    }\n\n    // only install these dependencies if they are not already installed\n    const basePackages = [\n      'vitest',\n      'playwright',\n      isVitest4OrNewer ? '@vitest/browser-playwright' : '@vitest/browser',\n    ];\n\n    // Only install these dependencies if they are not already installed\n    for (const pkg of basePackages) {\n      if (!allDeps[pkg]) {\n        dependencies.push(pkg);\n      }\n    }\n\n    // Check for coverage reporters\n    const v8Version = await this.packageManager.getInstalledVersion('@vitest/coverage-v8');\n    const istanbulVersion = await this.packageManager.getInstalledVersion(\n      '@vitest/coverage-istanbul'\n    );\n\n    if (!v8Version && !istanbulVersion) {\n      dependencies.push('@vitest/coverage-v8');\n    }\n\n    // Apply version specifiers to vitest-related packages\n    const versionedDependencies = dependencies.map((pkg) => {\n      if (pkg.includes('vitest') && vitestVersionSpecifier) {\n        return `${pkg}@${vitestVersionSpecifier}`;\n      }\n      return pkg;\n    });\n\n    return versionedDependencies;\n  }\n\n  /**\n   * Install Playwright browser binaries for @storybook/addon-vitest\n   *\n   * Installs Chromium via `npx playwright install chromium`. In CI environments and on\n   * macOS/Windows (officially supported platforms), also installs system-level browser dependencies\n   * via `--with-deps`. On other platforms (e.g. Linux), `--with-deps` is omitted to avoid requiring\n   * `sudo` — system packages are typically managed by the distro package manager.\n   *\n   * @param packageManager - The package manager to use for installation\n   * @param prompt - The prompt instance for displaying progress\n   * @param logger - The logger instance for displaying messages\n   * @param options - Installation options\n   * @returns Array of error messages if installation fails\n   */\n  async installPlaywright(\n    options: {\n      yes?: boolean;\n      /** Is set to true if Storybook didn't install the dependencies yet */\n      useRemotePkg?: boolean;\n    } = {}\n  ): Promise<{ errors: string[]; result: 'installed' | 'skipped' | 'aborted' | 'failed' }> {\n    const errors: string[] = [];\n\n    const platform = os.platform();\n    const useWithDeps = !!process.env.CI || platform === 'darwin' || platform === 'win32';\n    const playwrightCommand = useWithDeps\n      ? ['playwright', 'install', 'chromium', '--with-deps']\n      : ['playwright', 'install', 'chromium'];\n    const playwrightCommandString = this.packageManager.getPackageCommand(playwrightCommand);\n\n    let result: 'installed' | 'skipped' | 'aborted' | 'failed';\n\n    if (process.env.STORYBOOK_CLI_SKIP_PLAYWRIGHT_INSTALLATION) {\n      result = 'skipped';\n      return { errors, result };\n    }\n\n    try {\n      const shouldBeInstalled = options.yes\n        ? true\n        : await (async () => {\n            logger.log(dedent`\n            Playwright browser binaries are necessary for @storybook/addon-vitest. The download can take some time. If you don't want to wait, you can skip the installation and run the following command manually later:\n            ${CLI_COLORS.cta(playwrightCommandString)}\n            `);\n            return prompt.confirm({\n              message: 'Do you want to install Playwright with Chromium now?',\n              initialValue: true,\n            });\n          })();\n\n      if (shouldBeInstalled) {\n        const processAborted = await prompt.executeTaskWithSpinner(\n          (signal) =>\n            this.packageManager.runPackageCommand({\n              args: playwrightCommand,\n              useRemotePkg: options.useRemotePkg,\n              stdio: ['inherit', 'pipe', 'pipe'],\n              signal,\n            }),\n          {\n            id: 'playwright-installation',\n            intro: 'Installing Playwright browser binaries (press \"c\" to abort)',\n            error: `An error occurred while installing Playwright browser binaries. Please run the following command later: ${playwrightCommandString}`,\n            success: 'Playwright browser binaries installed successfully',\n            abortable: true,\n          }\n        );\n        if (processAborted) {\n          result = 'aborted';\n        } else {\n          result = 'installed';\n          if (!useWithDeps) {\n            logger.warn(dedent`\n              Playwright was installed without system dependencies. Depending on your operating system, you may need to install additional libraries for Playwright to work correctly.\n              To check for missing dependencies, run Storybook Test from the Storybook UI — it will report any libraries that need to be installed.\n              On MacOS, Windows, Debian and Ubuntu, you can install system dependencies manually by running:\n              ${CLI_COLORS.cta(this.packageManager.getPackageCommand(['playwright', 'install', 'chromium', '--with-deps']))}\n            `);\n          }\n        }\n      } else {\n        logger.warn('Playwright installation skipped');\n        result = 'skipped';\n      }\n    } catch (e) {\n      result = 'failed';\n      ErrorCollector.addError(e);\n      if (e instanceof Error) {\n        errors.push(e.stack ?? e.message);\n      } else {\n        errors.push(String(e));\n      }\n    }\n\n    return { errors, result };\n  }\n\n  /**\n   * Validate full compatibility for @storybook/addon-vitest\n   *\n   * Checks:\n   *\n   * - Webpack configuration compatibility\n   * - Builder compatibility (Vite or Next.js)\n   * - Renderer/framework support\n   * - Vitest version (>=3.0.0)\n   * - MSW version (>=2.0.0 if installed)\n   * - Next.js installation (if using @storybook/nextjs)\n   * - Vitest config files (if configDir provided)\n   */\n  async validateCompatibility(options: AddonVitestCompatibilityOptions): Promise<Result> {\n    const reasons: string[] = [];\n\n    // Check builder compatibility\n    if (options.builder !== SupportedBuilder.VITE) {\n      reasons.push('Non-Vite builder is not supported');\n    }\n\n    // Check renderer/framework support\n    const isFrameworkSupported = SUPPORTED_FRAMEWORKS.some(\n      (framework) => options.framework === framework\n    );\n\n    if (!isFrameworkSupported) {\n      reasons.push(`Test feature cannot yet be used with ${options.framework}`);\n    }\n\n    // Check package versions\n    const packageVersionResult = await this.validatePackageVersions();\n    if (!packageVersionResult.compatible && packageVersionResult.reasons) {\n      reasons.push(...packageVersionResult.reasons);\n    }\n\n    // Check vitest config files if configDir provided\n    if (options.projectRoot) {\n      const configResult = await this.validateConfigFiles(options.projectRoot);\n      if (!configResult.compatible && configResult.reasons) {\n        reasons.push(...configResult.reasons);\n      }\n    }\n\n    return reasons.length > 0 ? { compatible: false, reasons } : { compatible: true };\n  }\n\n  /**\n   * Validate package versions for addon-vitest compatibility Public method to allow early\n   * validation before framework detection\n   */\n  async validatePackageVersions(): Promise<Result> {\n    const reasons: string[] = [];\n\n    // Check Vitest version (>=3.0.0 - stricter requirement from postinstall)\n    const vitestVersionSpecifier = await this.packageManager.getInstalledVersion('vitest');\n    const coercedVitestVersion = vitestVersionSpecifier ? coerce(vitestVersionSpecifier) : null;\n    const isCanary = coercedVitestVersion?.version.startsWith('0.0.0') ?? false;\n\n    if (coercedVitestVersion && !satisfies(coercedVitestVersion, '>=3.0.0') && !isCanary) {\n      reasons.push(\n        `The addon requires Vitest 3.0.0 or higher. You are currently using ${vitestVersionSpecifier}.`\n      );\n    }\n\n    // Check MSW version (>=2.0.0 if installed)\n    const mswVersionSpecifier = await this.packageManager.getInstalledVersion('msw');\n    const coercedMswVersion = mswVersionSpecifier ? coerce(mswVersionSpecifier) : null;\n\n    if (coercedMswVersion && !satisfies(coercedMswVersion, '>=2.0.0')) {\n      reasons.push(\n        `The addon uses Vitest behind the scenes, which supports only version 2 and above of MSW. However, we have detected version ${coercedMswVersion.version} in this project.`\n      );\n    }\n\n    return reasons.length > 0 ? { compatible: false, reasons } : { compatible: true };\n  }\n\n  /**\n   * Validate vitest config files for addon compatibility\n   *\n   * Public method that can be used by both postinstall and create-storybook flows\n   */\n  async validateConfigFiles(directory: string): Promise<Result> {\n    const reasons: string[] = [];\n    const projectRoot = getProjectRoot();\n\n    // Check workspace files\n    const vitestWorkspaceFile = find.any(\n      ['ts', 'js', 'json'].flatMap((ex) => [`vitest.workspace.${ex}`, `vitest.projects.${ex}`]),\n      { cwd: directory, last: projectRoot }\n    );\n\n    if (vitestWorkspaceFile?.endsWith('.json')) {\n      reasons.push(`Cannot auto-update JSON workspace file: ${vitestWorkspaceFile}`);\n    } else if (vitestWorkspaceFile) {\n      const fileContents = await fs.readFile(vitestWorkspaceFile, 'utf8');\n      if (!canUpdateVitestWorkspaceFile(fileContents)) {\n        reasons.push(`Found an invalid workspace config file: ${vitestWorkspaceFile}`);\n      }\n    }\n\n    // Check config files\n    const vitestConfigFile = find.any(\n      ['ts', 'js', 'tsx', 'jsx', 'cts', 'cjs', 'mts', 'mjs'].map((ex) => `vitest.config.${ex}`),\n      { cwd: directory, last: projectRoot }\n    );\n\n    if (vitestConfigFile?.endsWith('.cts') || vitestConfigFile?.endsWith('.cjs')) {\n      reasons.push(`Cannot auto-update CommonJS config file: ${vitestConfigFile}`);\n    } else if (vitestConfigFile) {\n      const configContent = await fs.readFile(vitestConfigFile, 'utf8');\n      if (!canUpdateVitestConfigFile(configContent)) {\n        reasons.push(`Found an invalid Vitest config file: ${vitestConfigFile}`);\n      }\n    }\n\n    return reasons.length > 0 ? { compatible: false, reasons } : { compatible: true };\n  }\n}\n"
  },
  {
    "path": "code/core/src/cli/NpmOptions.ts",
    "content": "import type { JsPackageManager } from '../common/js-package-manager/JsPackageManager.ts';\n\nexport type NpmOptions = Parameters<JsPackageManager['addDependencies']>[0];\n"
  },
  {
    "path": "code/core/src/cli/angular/helpers.ts",
    "content": "import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { prompt } from 'storybook/internal/node-logger';\nimport { MissingAngularJsonError } from 'storybook/internal/server-errors';\n\nexport const ANGULAR_JSON_PATH = 'angular.json';\n\nexport class AngularJSON {\n  json: {\n    projects: Record<string, { root: string; projectType: string; architect: Record<string, any> }>;\n  };\n\n  constructor() {\n    if (!existsSync(ANGULAR_JSON_PATH)) {\n      throw new MissingAngularJsonError({ path: join(process.cwd(), ANGULAR_JSON_PATH) });\n    }\n\n    const jsonContent = readFileSync(ANGULAR_JSON_PATH, 'utf8');\n    this.json = JSON.parse(jsonContent);\n  }\n\n  get projects() {\n    return this.json.projects;\n  }\n\n  get projectsWithoutStorybook() {\n    return Object.keys(this.projects).filter((projectName) => {\n      const { architect } = this.projects[projectName];\n\n      return !architect.storybook;\n    });\n  }\n\n  get hasStorybookBuilder() {\n    return Object.keys(this.projects).some((projectName) => {\n      const { architect } = this.projects[projectName];\n      return Object.keys(architect).some((key) => {\n        return architect[key].builder === '@storybook/angular:start-storybook';\n      });\n    });\n  }\n\n  get rootProject() {\n    const rootProjectName = Object.keys(this.projects).find((projectName) => {\n      const { root } = this.projects[projectName];\n      return root === '' || root === '.';\n    });\n\n    return rootProjectName ? this.projects[rootProjectName] : null;\n  }\n\n  getProjectSettingsByName(projectName: string) {\n    return this.projects[projectName];\n  }\n\n  async getProjectName() {\n    if (this.projectsWithoutStorybook.length > 1) {\n      return prompt.select({\n        message: 'For which project do you want to generate Storybook configuration?',\n        options: this.projectsWithoutStorybook.map((name) => ({\n          label: name,\n          value: name,\n        })),\n      });\n    }\n\n    return this.projectsWithoutStorybook[0];\n  }\n\n  addStorybookEntries({\n    angularProjectName,\n    storybookFolder,\n    useCompodoc,\n    root,\n  }: {\n    angularProjectName: string;\n    storybookFolder: string;\n    useCompodoc: boolean;\n    root: string;\n  }) {\n    // add an entry to the angular.json file to setup the storybook builders\n    const { architect } = this.projects[angularProjectName];\n\n    const baseOptions = {\n      configDir: storybookFolder,\n      browserTarget: `${angularProjectName}:build`,\n      compodoc: useCompodoc,\n      ...(useCompodoc && { compodocArgs: ['-e', 'json', '-d', root || '.'] }),\n    };\n\n    if (!architect.storybook) {\n      architect.storybook = {\n        builder: '@storybook/angular:start-storybook',\n        options: {\n          ...baseOptions,\n          port: 6006,\n        },\n      };\n    }\n\n    if (!architect['build-storybook']) {\n      architect['build-storybook'] = {\n        builder: '@storybook/angular:build-storybook',\n        options: {\n          ...baseOptions,\n          outputDir:\n            Object.keys(this.projects).length === 1\n              ? `storybook-static`\n              : `dist/storybook/${angularProjectName}`,\n        },\n      };\n    }\n  }\n\n  write() {\n    writeFileSync(ANGULAR_JSON_PATH, JSON.stringify(this.json, null, 2));\n  }\n}\n"
  },
  {
    "path": "code/core/src/cli/build.ts",
    "content": "import { cache } from 'storybook/internal/common';\nimport { buildStaticStandalone, withTelemetry } from 'storybook/internal/core-server';\n\nexport const build = async (cliOptions: any) => {\n  const { default: packageJson } = await import('storybook/package.json', {\n    with: { type: 'json' },\n  });\n  const options = {\n    ...cliOptions,\n    configDir: cliOptions.configDir || './.storybook',\n    outputDir: cliOptions.outputDir || './storybook-static',\n    ignorePreview: !!cliOptions.previewUrl && !cliOptions.forceBuildPreview,\n    configType: 'PRODUCTION',\n    cache,\n    packageJson,\n  };\n  await withTelemetry('build', { cliOptions, presetOptions: options }, () =>\n    buildStaticStandalone(options)\n  );\n};\n"
  },
  {
    "path": "code/core/src/cli/buildIndex.ts",
    "content": "import { Channel } from 'storybook/internal/channels';\nimport { cache } from 'storybook/internal/common';\nimport { buildIndexStandalone, withTelemetry } from 'storybook/internal/core-server';\nimport type { BuilderOptions, CLIBaseOptions } from 'storybook/internal/types';\n\nexport interface CLIIndexOptions extends CLIBaseOptions {\n  configDir?: string;\n  outputFile?: string;\n}\n\nexport const buildIndex = async (\n  cliOptions: CLIIndexOptions & { packageJson?: Record<string, any> }\n) => {\n  const options = {\n    ...cliOptions,\n    configDir: cliOptions.configDir || '.storybook',\n    outputFile: cliOptions.outputFile || 'index.json',\n    ignorePreview: true,\n    configType: 'PRODUCTION' as BuilderOptions['configType'],\n    cache,\n    packageJson: cliOptions.packageJson,\n  };\n  const presetOptions = {\n    ...options,\n    corePresets: [],\n    overridePresets: [],\n    channel: new Channel({}),\n  } as unknown as Parameters<typeof withTelemetry>[1]['presetOptions'];\n  await withTelemetry('index', { cliOptions, presetOptions }, () => buildIndexStandalone(options));\n};\n"
  },
  {
    "path": "code/core/src/cli/detect.ts",
    "content": "import * as find from 'empathic/find';\n\n// TODO: Remove in SB11\nexport async function detectPnp() {\n  return !!find.any(['.pnp.js', '.pnp.cjs']);\n}\n"
  },
  {
    "path": "code/core/src/cli/dev.ts",
    "content": "import { cache } from 'storybook/internal/common';\nimport { buildDevStandalone, withTelemetry } from 'storybook/internal/core-server';\nimport { logger, instance as npmLog } from 'storybook/internal/node-logger';\nimport type { CLIOptions, PackageJson } from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\n\nfunction printError(error: any) {\n  // this is a weird bugfix, somehow 'node-pre-gyp' is polluting the npmLog header\n  npmLog.heading = '';\n\n  if (error instanceof Error) {\n    if ((error as any).error) {\n      logger.error((error as any).error);\n    } else if ((error as any).stats && (error as any).stats.compilation.errors) {\n      (error as any).stats.compilation.errors.forEach((e: any) => logger.log(e));\n    } else {\n      logger.error(error as any);\n    }\n  } else if (error.compilation?.errors) {\n    error.compilation.errors.forEach((e: any) => logger.log(e));\n  }\n\n  logger.warn(\n    error.close\n      ? dedent`\n          FATAL broken build!, will close the process,\n          Fix the error below and restart storybook.\n        `\n      : dedent`\n          Broken build, fix the error above.\n          You may need to refresh the browser.\n        `\n  );\n}\n\nexport const dev = async (cliOptions: CLIOptions) => {\n  const { env } = process;\n  env.NODE_ENV = env.NODE_ENV || 'development';\n\n  const { default: packageJson } = await import('storybook/package.json', {\n    with: { type: 'json' },\n  });\n  type Options = Parameters<typeof buildDevStandalone>[0];\n\n  const options = {\n    ...cliOptions,\n    configDir: cliOptions.configDir || './.storybook',\n    configType: 'DEVELOPMENT',\n    ignorePreview: !!cliOptions.previewUrl && !cliOptions.forceBuildPreview,\n    cache: cache as any,\n    packageJson: packageJson as unknown as PackageJson, // type-fest types are wrong here because we're on an outdated version of the package\n  } as Options;\n\n  await withTelemetry(\n    'dev',\n    {\n      cliOptions,\n      presetOptions: options as Parameters<typeof withTelemetry>[1]['presetOptions'],\n      printError,\n    },\n    () => buildDevStandalone(options)\n  );\n};\n"
  },
  {
    "path": "code/core/src/cli/dirs.ts",
    "content": "import { join } from 'node:path';\nimport { Readable } from 'node:stream';\nimport { pipeline } from 'node:stream/promises';\nimport type { ReadableStream } from 'node:stream/web';\nimport { createGunzip } from 'node:zlib';\n\nimport {\n  frameworkPackages,\n  rendererPackages,\n  temporaryDirectory,\n  versions,\n} from 'storybook/internal/common';\nimport type { JsPackageManager } from 'storybook/internal/common';\nimport type { SupportedFramework } from 'storybook/internal/types';\nimport { type SupportedRenderer } from 'storybook/internal/types';\n\nimport getNpmTarballUrlDefault from 'get-npm-tarball-url';\nimport { unpackTar } from 'modern-tar/fs';\nimport invariant from 'tiny-invariant';\n\nimport { resolvePackageDir } from '../shared/utils/module.ts';\n\nconst resolveUsingBranchInstall = async (packageManager: JsPackageManager, request: string) => {\n  const tempDirectory = await temporaryDirectory();\n  const name = request as keyof typeof versions;\n\n  // FIXME: this might not be the right version for community packages\n  const version = versions[name] || (await packageManager.latestVersion(request));\n\n  // an artifact of esbuild + type=commonjs + exportmap\n  // @ts-expect-error (default export)\n  const getNpmTarballUrl = getNpmTarballUrlDefault.default || getNpmTarballUrlDefault;\n\n  const url = getNpmTarballUrl(request, version, {\n    registry: await packageManager.getRegistryURL(),\n  });\n\n  const response = await fetch(url);\n  if (!response.ok || !response.body) {\n    throw new Error(`Failed to download tarball from ${url}`);\n  }\n\n  // this unzips the tarball into the temp directory\n  await pipeline(\n    Readable.fromWeb(response.body as ReadableStream<Uint8Array>),\n    createGunzip(),\n    unpackTar(tempDirectory)\n  );\n\n  return join(tempDirectory, 'package');\n};\n\nexport async function getRendererDir(\n  packageManager: JsPackageManager,\n  renderer: SupportedFramework | SupportedRenderer\n) {\n  const [externalFramework] =\n    Object.entries({ ...frameworkPackages, ...rendererPackages }).find(\n      ([key, value]) => value === renderer\n    ) ?? [];\n\n  if (!externalFramework) {\n    return null;\n  }\n\n  const packageJsonPath = join(externalFramework, 'package.json');\n\n  const errors: Error[] = [];\n\n  try {\n    return resolvePackageDir(externalFramework, process.cwd());\n  } catch (e) {\n    invariant(e instanceof Error);\n    errors.push(e);\n  }\n\n  try {\n    return await resolveUsingBranchInstall(packageManager, externalFramework);\n  } catch (e) {\n    invariant(e instanceof Error);\n    errors.push(e);\n  }\n\n  throw new Error(`Cannot find ${packageJsonPath}, ${errors.map((e) => e.stack).join('\\n\\n')}`);\n}\n"
  },
  {
    "path": "code/core/src/cli/eslintPlugin.test.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport * as find from 'empathic/find';\nimport { dedent } from 'ts-dedent';\n\nimport type { PackageJsonWithDepsAndDevDeps } from '../common/index.ts';\nimport type { JsPackageManager } from '../common/js-package-manager/JsPackageManager.ts';\nimport {\n  configureEslintPlugin,\n  extractEslintInfo,\n  findEslintFile,\n  normalizeExtends,\n} from './eslintPlugin.ts';\n\nvi.mock('empathic/find', () => ({\n  up: vi.fn(),\n}));\n\nvi.mock(import('node:fs/promises'), async (importOriginal) => {\n  const actual = await importOriginal();\n  return {\n    ...actual,\n    readFile: vi.fn(),\n    writeFile: vi.fn(),\n  };\n});\n\ndescribe('extractEslintInfo', () => {\n  const mockPackageManager = {\n    getAllDependencies: vi.fn(),\n    primaryPackageJson: {\n      packageJson: { dependencies: {}, devDependencies: {} } as PackageJsonWithDepsAndDevDeps,\n      packageJsonPath: '/some/path',\n      operationDir: '/some/path',\n    },\n  } satisfies Partial<JsPackageManager>;\n\n  beforeEach(() => {\n    vi.mocked(find).up.mockClear();\n    mockPackageManager.getAllDependencies.mockClear();\n  });\n\n  it('should find ESLint config file with supported extension', async () => {\n    vi.mocked(find).up.mockImplementation((fileName) => {\n      return String(fileName) === '.eslintrc.js' ? String(fileName) : undefined;\n    });\n\n    const result = findEslintFile(process.cwd());\n    expect(result).toBe('.eslintrc.js');\n  });\n\n  it('should return undefined if no ESLint config file is found', async () => {\n    vi.mocked(find).up.mockImplementation(() => undefined);\n\n    const result = findEslintFile(process.cwd());\n    expect(result).toBeUndefined();\n  });\n\n  it('should throw error for unsupported ESLint config file extensions', async () => {\n    vi.mocked(find).up.mockImplementation(() => {\n      return '.eslintrc.yaml';\n    });\n\n    expect(() => findEslintFile(process.cwd())).toThrowError(\n      'Unsupported ESLint config extension: .yaml'\n    );\n  });\n\n  it('should handle missing ESLint config and no dependencies correctly', async () => {\n    mockPackageManager.getAllDependencies.mockReturnValue({});\n    mockPackageManager.primaryPackageJson.packageJson = { dependencies: {}, devDependencies: {} };\n\n    vi.mocked(find).up.mockImplementation(() => undefined);\n\n    const result = await extractEslintInfo(mockPackageManager as any);\n\n    expect(result.hasEslint).toBe(false);\n    expect(result.isStorybookPluginInstalled).toBe(false);\n    expect(result.eslintConfigFile).toBeUndefined();\n  });\n\n  it('should extract ESLint info and detect ESLint config and Storybook plugin', async () => {\n    mockPackageManager.getAllDependencies.mockReturnValue({\n      'eslint-plugin-storybook': '1.0.0',\n      eslint: '7.0.0',\n    });\n    mockPackageManager.primaryPackageJson = {\n      packageJson: {\n        devDependencies: {},\n        dependencies: {},\n        eslintConfig: '.eslintrc.js',\n      },\n      packageJsonPath: '/some/path',\n      operationDir: '/some/path',\n    };\n\n    vi.mocked(find).up.mockImplementation((fileName) =>\n      String(fileName) === '.eslintrc.js' ? String(fileName) : undefined\n    );\n\n    const result = await extractEslintInfo(mockPackageManager as any);\n\n    expect(result.hasEslint).toBe(true);\n    expect(result.isStorybookPluginInstalled).toBe(true);\n    expect(result.eslintConfigFile).toBe('.eslintrc.js');\n    expect(result.isFlatConfig).toBe(false);\n  });\n});\n\ndescribe('configureEslintPlugin', () => {\n  describe('.eslintrc.json format', () => {\n    it('should not configure ESLint plugin if it is already configured', async () => {\n      const mockPackageManager = {\n        getAllDependencies: vi.fn(),\n      } satisfies Partial<JsPackageManager>;\n\n      const mockConfigFile = dedent`{\n      \"extends\": [\"plugin:storybook/recommended\"]\n    }`;\n\n      vi.mocked(readFile).mockResolvedValue(mockConfigFile);\n\n      await configureEslintPlugin({\n        eslintConfigFile: '.eslintrc.json',\n        packageManager: mockPackageManager as any,\n        isFlatConfig: false,\n      });\n      expect(vi.mocked(writeFile).mock.calls).toHaveLength(0);\n    });\n\n    it('should configure ESLint plugin correctly', async () => {\n      const mockPackageManager = {\n        getAllDependencies: vi.fn(),\n      } satisfies Partial<JsPackageManager>;\n\n      const mockConfigFile = dedent`{\n      \"extends\": [\"plugin:other\"]\n    }`;\n\n      vi.mocked(readFile).mockResolvedValue(mockConfigFile);\n\n      await configureEslintPlugin({\n        eslintConfigFile: '.eslintrc.json',\n        packageManager: mockPackageManager as any,\n        isFlatConfig: false,\n      });\n      const [filePath, content] = vi.mocked(writeFile).mock.calls[0];\n      expect(filePath).toBe('.eslintrc.json');\n      expect(content).toMatchInlineSnapshot(`\n        \"{\n          \"extends\": [\n            \"plugin:other\",\n            \"plugin:storybook/recommended\"\n          ]\n        }\"\n      `);\n    });\n\n    it('should correctly parse, configure, and preserve comments in comment-json .eslintrc.json', async () => {\n      const mockPackageManager = {\n        getAllDependencies: vi.fn(),\n      } satisfies Partial<JsPackageManager>;\n\n      // Mock file content with JSON5 features (comments, trailing comma)\n      const mockConfigFile = dedent`{\n        // Some comment here\n        \"extends\": [\"plugin:other\"],\n        // Top-level comment\n        \"extends\": [\n          // Comment before existing item\n          \"plugin:other\", // Inline comment for existing item\n        ],\n        \"rules\": {\n          // Comment for rules object\n          \"no-unused-vars\": \"warn\", // Another comment\n        },\n        // Trailing comment\n      }`;\n\n      vi.mocked(readFile).mockResolvedValue(mockConfigFile);\n\n      await configureEslintPlugin({\n        eslintConfigFile: '.eslintrc.json',\n        packageManager: mockPackageManager as any,\n        isFlatConfig: false,\n      });\n\n      // Expect writeFile to have been called (meaning parsing didn't crash)\n      expect(vi.mocked(writeFile)).toHaveBeenCalledTimes(1);\n      const [filePath, content] = vi.mocked(writeFile).mock.calls[0];\n\n      expect(filePath).toBe('.eslintrc.json');\n      expect(content).toMatchInlineSnapshot(`\n        \"{\n          // Top-level comment\n          \"extends\": [\n            // Comment before existing item\n            \"plugin:other\", // Inline comment for existing item\n            \"plugin:storybook/recommended\"\n          ],\n          \"rules\": {\n            // Comment for rules object\n            \"no-unused-vars\": \"warn\" // Another comment\n          }\n          // Trailing comment\n        }\"\n      `);\n      // Check that the output contains the new extend AND the original comments\n      expect(content).toContain('// Top-level comment');\n      expect(content).toContain('plugin:storybook/recommended');\n      expect(content).toContain('// Trailing comment');\n\n      // Optionally, check the full snapshot if formatting needs to be precise\n      // Note: comment-json might slightly alter whitespace/placement vs original\n      expect(content).toMatchInlineSnapshot(`\n        \"{\n          // Top-level comment\n          \"extends\": [\n            // Comment before existing item\n            \"plugin:other\", // Inline comment for existing item\n            \"plugin:storybook/recommended\"\n          ],\n          \"rules\": {\n            // Comment for rules object\n            \"no-unused-vars\": \"warn\" // Another comment\n          }\n          // Trailing comment\n        }\"\n      `);\n    });\n  });\n\n  describe('.eslintrc.js format', () => {\n    it('should not configure ESLint plugin if it is already configured', async () => {\n      const mockPackageManager = {\n        getAllDependencies: vi.fn(),\n      } satisfies Partial<JsPackageManager>;\n\n      const mockConfigFile = dedent`\n        module.exports = {\n          extends: ['plugin:storybook/recommended'],\n        };\n      `;\n\n      vi.mocked(readFile).mockResolvedValue(mockConfigFile);\n\n      await configureEslintPlugin({\n        eslintConfigFile: '.eslintrc.js',\n        packageManager: mockPackageManager as any,\n        isFlatConfig: false,\n      });\n      expect(vi.mocked(writeFile).mock.calls).toHaveLength(0);\n    });\n\n    it('should configure ESLint plugin correctly', async () => {\n      const mockPackageManager = {\n        getAllDependencies: vi.fn(),\n      } satisfies Partial<JsPackageManager>;\n\n      const mockConfigFile = dedent`\n        module.exports = {\n          extends: [\"plugin:other\"],\n        };\n      `;\n\n      vi.mocked(readFile).mockResolvedValue(mockConfigFile);\n\n      await configureEslintPlugin({\n        eslintConfigFile: '.eslintrc.js',\n        packageManager: mockPackageManager as any,\n        isFlatConfig: false,\n      });\n      const [, content] = vi.mocked(writeFile).mock.calls[0];\n      expect(content).toMatchInlineSnapshot(`\n        \"module.exports = {\n          extends: [\"plugin:other\", \"plugin:storybook/recommended\"],\n        };\"\n      `);\n    });\n  });\n\n  describe('flat config', () => {\n    it('should configure ESLint plugin correctly with default JS flat config', async () => {\n      const mockPackageManager = {\n        getAllDependencies: vi.fn(),\n      } satisfies Partial<JsPackageManager>;\n\n      const mockConfigFile = dedent`\n        import somePlugin from 'some-plugin';\n        export default [\n          somePlugin,\n        ]\n      `;\n\n      vi.mocked(readFile).mockResolvedValue(mockConfigFile);\n\n      await configureEslintPlugin({\n        eslintConfigFile: 'eslint.config.js',\n        packageManager: mockPackageManager as any,\n        isFlatConfig: true,\n      });\n      const [, content] = vi.mocked(writeFile).mock.calls[0];\n      expect(content).toMatchInlineSnapshot(`\n        \"// For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format\n        import storybook from \"eslint-plugin-storybook\";\n\n        import somePlugin from 'some-plugin';\n        export default [somePlugin, ...storybook.configs[\"flat/recommended\"]];\"\n      `);\n    });\n\n    it('should configure ESLint plugin correctly with typescript-eslint flat config', async () => {\n      const mockPackageManager = {\n        getAllDependencies: vi.fn(),\n      } satisfies Partial<JsPackageManager>;\n\n      const mockConfigFile = dedent`\n        import somePlugin from 'some-plugin';\n        import tseslint from 'typescript-eslint';\n        export default tseslint.config(somePlugin);\n      `;\n\n      vi.mocked(readFile).mockResolvedValue(mockConfigFile);\n\n      await configureEslintPlugin({\n        eslintConfigFile: 'eslint.config.ts',\n        packageManager: mockPackageManager as any,\n        isFlatConfig: true,\n      });\n      const [, content] = vi.mocked(writeFile).mock.calls[0];\n      expect(content).toMatchInlineSnapshot(`\n        \"// For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format\n        import storybook from \"eslint-plugin-storybook\";\n\n        import somePlugin from 'some-plugin';\n        import tseslint from 'typescript-eslint';\n        export default tseslint.config(somePlugin, storybook.configs[\"flat/recommended\"]);\"\n      `);\n    });\n\n    it('should configure ESLint plugin correctly with reexported const declaration', async () => {\n      const mockPackageManager = {\n        getAllDependencies: vi.fn(),\n      } satisfies Partial<JsPackageManager>;\n\n      const mockConfigFile = dedent`import eslint from \"@eslint/js\";\n        const options = [\n          eslint.configs.recommended,\n        ]\n\n        export default options;\n      `;\n\n      vi.mocked(readFile).mockResolvedValue(mockConfigFile);\n\n      await configureEslintPlugin({\n        eslintConfigFile: 'eslint.config.ts',\n        packageManager: mockPackageManager as any,\n        isFlatConfig: true,\n      });\n      const [, content] = vi.mocked(writeFile).mock.calls[0];\n      expect(content).toMatchInlineSnapshot(`\n        \"// For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format\n        import storybook from \"eslint-plugin-storybook\";\n\n        import eslint from \"@eslint/js\";\n        const options = [eslint.configs.recommended, ...storybook.configs[\"flat/recommended\"]]\n\n        export default options;\"\n      `);\n    });\n\n    it('should configure ESLint plugin correctly with TS aliased config', async () => {\n      const mockPackageManager = {\n        getAllDependencies: vi.fn(),\n      } satisfies Partial<JsPackageManager>;\n\n      const mockConfigFile = dedent`import eslint from \"@eslint/js\";\n        const options = [\n          eslint.configs.recommended,\n        ] as Config\n\n        export default options;`;\n\n      vi.mocked(readFile).mockResolvedValue(mockConfigFile);\n\n      await configureEslintPlugin({\n        eslintConfigFile: 'eslint.config.js',\n        packageManager: mockPackageManager as any,\n        isFlatConfig: true,\n      });\n      const [, content] = vi.mocked(writeFile).mock.calls[0];\n      expect(content).toMatchInlineSnapshot(`\n        \"// For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format\n        import storybook from \"eslint-plugin-storybook\";\n\n        import eslint from \"@eslint/js\";\n        const options = [eslint.configs.recommended, ...storybook.configs[\"flat/recommended\"]] as Config\n\n        export default options;\"\n      `);\n    });\n\n    it('should configure ESLint plugin correctly with TS satisfies config', async () => {\n      const mockPackageManager = {\n        getAllDependencies: vi.fn(),\n      } satisfies Partial<JsPackageManager>;\n\n      const mockConfigFile = dedent`import eslint from \"@eslint/js\";\n        export default [\n          eslint.configs.recommended,\n        ] satisfies Config;`;\n\n      vi.mocked(readFile).mockResolvedValue(mockConfigFile);\n\n      await configureEslintPlugin({\n        eslintConfigFile: 'eslint.config.ts',\n        packageManager: mockPackageManager as any,\n        isFlatConfig: true,\n      });\n      const [, content] = vi.mocked(writeFile).mock.calls[0];\n      expect(content).toMatchInlineSnapshot(`\n        \"// For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format\n        import storybook from \"eslint-plugin-storybook\";\n\n        import eslint from \"@eslint/js\";\n        export default [eslint.configs.recommended, ...storybook.configs[\"flat/recommended\"]] satisfies Config;\"\n      `);\n    });\n\n    it('should configure ESLint plugin correctly with Next.js defineConfig style', async () => {\n      const mockPackageManager = {\n        getAllDependencies: vi.fn(),\n      } satisfies Partial<JsPackageManager>;\n\n      const mockConfigFile = dedent`import { defineConfig, globalIgnores } from \"eslint/config\";\n        import nextVitals from \"eslint-config-next/core-web-vitals\";\n        import nextTs from \"eslint-config-next/typescript\";\n\n        const eslintConfig = defineConfig([\n          ...nextVitals,\n          ...nextTs,\n          globalIgnores([\n            \".next/**\",\n            \"out/**\",\n            \"build/**\",\n            \"next-env.d.ts\",\n          ]),\n        ]);\n\n        export default eslintConfig;`;\n\n      vi.mocked(readFile).mockResolvedValue(mockConfigFile);\n\n      await configureEslintPlugin({\n        eslintConfigFile: 'eslint.config.mjs',\n        packageManager: mockPackageManager as any,\n        isFlatConfig: true,\n      });\n      const [, content] = vi.mocked(writeFile).mock.calls[0];\n      expect(content).toMatchInlineSnapshot(`\n        \"// For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format\n        import storybook from \"eslint-plugin-storybook\";\n\n        import { defineConfig, globalIgnores } from \"eslint/config\";\n        import nextVitals from \"eslint-config-next/core-web-vitals\";\n        import nextTs from \"eslint-config-next/typescript\";\n\n        const eslintConfig = defineConfig([...nextVitals, ...nextTs, globalIgnores([\n          \".next/**\",\n          \"out/**\",\n          \"build/**\",\n          \"next-env.d.ts\",\n        ]), ...storybook.configs[\"flat/recommended\"]]);\n\n        export default eslintConfig;\"\n      `);\n    });\n\n    it('should configure ESLint plugin correctly with direct export default defineConfig', async () => {\n      const mockPackageManager = {\n        getAllDependencies: vi.fn(),\n      } satisfies Partial<JsPackageManager>;\n\n      const mockConfigFile = dedent`import { defineConfig, globalIgnores } from \"eslint/config\";\n        import nextVitals from \"eslint-config-next/core-web-vitals\";\n        import nextTs from \"eslint-config-next/typescript\";\n\n        export default defineConfig([\n          ...nextVitals,\n          ...nextTs,\n          globalIgnores([\n            \".next/**\",\n            \"out/**\",\n            \"build/**\",\n            \"next-env.d.ts\",\n          ]),\n        ]);`;\n\n      vi.mocked(readFile).mockResolvedValue(mockConfigFile);\n\n      await configureEslintPlugin({\n        eslintConfigFile: 'eslint.config.mjs',\n        packageManager: mockPackageManager as any,\n        isFlatConfig: true,\n      });\n      const [, content] = vi.mocked(writeFile).mock.calls[0];\n      expect(content).toMatchInlineSnapshot(`\n        \"// For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format\n        import storybook from \"eslint-plugin-storybook\";\n\n        import { defineConfig, globalIgnores } from \"eslint/config\";\n        import nextVitals from \"eslint-config-next/core-web-vitals\";\n        import nextTs from \"eslint-config-next/typescript\";\n\n        export default defineConfig([...nextVitals, ...nextTs, globalIgnores([\n          \".next/**\",\n          \"out/**\",\n          \"build/**\",\n          \"next-env.d.ts\",\n        ]), ...storybook.configs[\"flat/recommended\"]]);\"\n      `);\n    });\n\n    it('should just add an import if config uses defineConfig from non-eslint/config source', async () => {\n      const mockPackageManager = {\n        getAllDependencies: vi.fn(),\n      } satisfies Partial<JsPackageManager>;\n\n      const mockConfigFile = dedent`import { defineConfig } from \"some-other-config-lib\";\n        \n        const eslintConfig = defineConfig([\n          { rules: { \"no-console\": \"error\" } },\n        ]);\n\n        export default eslintConfig;`;\n\n      vi.mocked(readFile).mockResolvedValue(mockConfigFile);\n\n      await configureEslintPlugin({\n        eslintConfigFile: 'eslint.config.js',\n        packageManager: mockPackageManager as any,\n        isFlatConfig: true,\n      });\n      const [, content] = vi.mocked(writeFile).mock.calls[0];\n      expect(content).toMatchInlineSnapshot(`\n        \"// For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format\n        import storybook from \"eslint-plugin-storybook\";\n\n        import { defineConfig } from \"some-other-config-lib\";\n        \n        const eslintConfig = defineConfig([\n          { rules: { \"no-console\": \"error\" } },\n        ]);\n\n        export default eslintConfig;\"\n      `);\n    });\n\n    it('should just add an import if config is of custom unknown format', async () => {\n      const mockPackageManager = {\n        getAllDependencies: vi.fn(),\n      } satisfies Partial<JsPackageManager>;\n\n      const mockConfigFile = dedent`import someCustomConfig from 'my-eslint-config';\n      export default someCustomConfig({}, [{}]);`;\n\n      vi.mocked(readFile).mockResolvedValue(mockConfigFile);\n\n      await configureEslintPlugin({\n        eslintConfigFile: 'eslint.config.js',\n        packageManager: mockPackageManager as any,\n        isFlatConfig: true,\n      });\n      const [, content] = vi.mocked(writeFile).mock.calls[0];\n      expect(content).toMatchInlineSnapshot(`\n        \"// For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format\n        import storybook from \"eslint-plugin-storybook\";\n\n        import someCustomConfig from 'my-eslint-config';\n        export default someCustomConfig({}, [{}]);\"\n      `);\n    });\n\n    it('should not modify config if eslint-plugin-storybook is already imported', async () => {\n      const mockPackageManager = {\n        getAllDependencies: vi.fn(),\n      } satisfies Partial<JsPackageManager>;\n\n      const mockConfigFile = dedent`\n        import sb from 'eslint-plugin-storybook';\n        export default [\n          ...sb.configs['flat/recommended'],\n        ];\n      `;\n\n      vi.mocked(readFile).mockResolvedValue(mockConfigFile);\n\n      await configureEslintPlugin({\n        eslintConfigFile: 'eslint.config.js',\n        packageManager: mockPackageManager as any,\n        isFlatConfig: true,\n      });\n      expect(vi.mocked(writeFile).mock.calls).toHaveLength(0);\n    });\n\n    it('should not modify config if eslint-plugin-storybook is already dynamically imported', async () => {\n      const mockPackageManager = {\n        getAllDependencies: vi.fn(),\n      } satisfies Partial<JsPackageManager>;\n\n      const mockConfigFile = dedent`\n        import { includeIgnoreFile } from '@eslint/compat';\n        import { FlatCompat } from '@eslint/eslintrc';\n        import { composer } from 'eslint-flat-config-utils';\n\n        export default composer(\n          import('eslint-plugin-storybook').then((m) => m.default.configs['flat/recommended']),\n        );\n      `;\n\n      vi.mocked(readFile).mockResolvedValue(mockConfigFile);\n\n      await configureEslintPlugin({\n        eslintConfigFile: 'eslint.config.js',\n        packageManager: mockPackageManager as any,\n        isFlatConfig: true,\n      });\n      expect(vi.mocked(writeFile).mock.calls).toHaveLength(0);\n    });\n  });\n});\n\ndescribe('normalizeExtends', () => {\n  it('returns empty array when existingExtends is falsy', () => {\n    expect(normalizeExtends(null)).toEqual([]);\n    expect(normalizeExtends(undefined)).toEqual([]);\n  });\n\n  it('returns existingExtends when it is a string', () => {\n    expect(normalizeExtends('foo')).toEqual(['foo']);\n  });\n\n  it('returns existingExtends when it is an array', () => {\n    expect(normalizeExtends(['foo'])).toEqual(['foo']);\n  });\n\n  it('throws when existingExtends is not a string or array', () => {\n    expect(() => normalizeExtends(true)).toThrowError('Invalid eslint extends true');\n  });\n});\n"
  },
  {
    "path": "code/core/src/cli/eslintPlugin.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\n\nimport { type JsPackageManager, getProjectRoot } from 'storybook/internal/common';\nimport { readConfig, writeConfig } from 'storybook/internal/csf-tools';\nimport { logger, prompt } from 'storybook/internal/node-logger';\n\nimport commentJson from 'comment-json';\nimport detectIndent from 'detect-indent';\nimport * as find from 'empathic/find';\nimport picocolors from 'picocolors';\nimport { dedent } from 'ts-dedent';\n\nimport { babelParse, recast, types as t, traverse } from '../babel/index.ts';\n\nexport const SUPPORTED_ESLINT_EXTENSIONS = ['ts', 'mts', 'cts', 'mjs', 'js', 'cjs', 'json'];\nconst UNSUPPORTED_ESLINT_EXTENSIONS = ['yaml', 'yml'];\n\nexport const findEslintFile = (instanceDir: string) => {\n  const filePrefixes = ['eslint.config', '.eslintrc'];\n\n  // Check for unsupported files\n  for (const prefix of filePrefixes) {\n    for (const ext of UNSUPPORTED_ESLINT_EXTENSIONS) {\n      const file = find.up(`${prefix}.${ext}`, { cwd: instanceDir, last: getProjectRoot() });\n      if (file) {\n        throw new Error(`Unsupported ESLint config extension: .${ext}`);\n      }\n    }\n  }\n\n  // Find supported ESLint config files\n  for (const prefix of filePrefixes) {\n    for (const ext of SUPPORTED_ESLINT_EXTENSIONS) {\n      const file = find.up(`${prefix}.${ext}`, { cwd: instanceDir, last: getProjectRoot() });\n      if (file) {\n        return file;\n      }\n    }\n  }\n\n  return undefined;\n};\n\nfunction unwrapTSExpression(expr: any): t.Expression | null | undefined {\n  if (!expr) {\n    return expr;\n  }\n\n  if (t.isTSAsExpression(expr) || t.isTSSatisfiesExpression(expr)) {\n    return unwrapTSExpression(expr.expression);\n  }\n  return expr;\n}\n\nexport const configureFlatConfig = async (code: string) => {\n  const ast = babelParse(code);\n\n  // Bail out if eslint-plugin-storybook is already imported (static or dynamic) to avoid\n  // referencing an undefined variable or duplicating the config spread.\n  // Some configs use dynamic import() expressions (e.g. via eslint-flat-config-utils).\n  let alreadyHasStorybookImport = false;\n  traverse(ast, {\n    ImportDeclaration(path) {\n      if (path.node.source.value === 'eslint-plugin-storybook') {\n        alreadyHasStorybookImport = true;\n        path.stop();\n      }\n    },\n    CallExpression(path) {\n      // Dynamic import: import('eslint-plugin-storybook')\n      // Babel represents this as a CallExpression with callee.type === 'Import'\n      if (\n        t.isImport(path.node.callee) &&\n        path.node.arguments.length > 0 &&\n        t.isStringLiteral(path.node.arguments[0]) &&\n        path.node.arguments[0].value === 'eslint-plugin-storybook'\n      ) {\n        alreadyHasStorybookImport = true;\n        path.stop();\n      }\n    },\n  });\n  if (alreadyHasStorybookImport) {\n    return code;\n  }\n\n  let tsEslintLocalName = '';\n  let eslintDefineConfigLocalName = '';\n  let eslintConfigExpression: any = null;\n\n  /**\n   * What this supports:\n   *\n   * 1. Export default []\n   * 2. Const config; export default config\n   * 3. Export default tseslint.config()\n   *\n   * What this does NOT support:\n   *\n   * 1. Module.exports = [] Though it will add the import and a code comment that points to the docs\n   */\n  traverse(ast, {\n    ImportDeclaration(path) {\n      if (path.node.source.value === 'typescript-eslint') {\n        const defaultSpecifier = path.node.specifiers.find((s) => t.isImportDefaultSpecifier(s));\n        if (defaultSpecifier) {\n          tsEslintLocalName = defaultSpecifier.local.name;\n        }\n      }\n      if (path.node.source.value === 'eslint/config') {\n        const defineConfigSpecifier = path.node.specifiers.find(\n          (s) => t.isImportSpecifier(s) && t.isIdentifier(s.imported, { name: 'defineConfig' })\n        );\n        if (defineConfigSpecifier && t.isImportSpecifier(defineConfigSpecifier)) {\n          eslintDefineConfigLocalName = defineConfigSpecifier.local.name;\n        }\n      }\n    },\n\n    ExportDefaultDeclaration(path) {\n      const node = path.node;\n      eslintConfigExpression = unwrapTSExpression(node.declaration);\n\n      const storybookConfig = t.memberExpression(\n        t.memberExpression(t.identifier('storybook'), t.identifier('configs')),\n        t.stringLiteral('flat/recommended'),\n        true\n      );\n\n      // Case 1: Direct array\n      if (t.isArrayExpression(eslintConfigExpression)) {\n        eslintConfigExpression.elements.push(t.spreadElement(storybookConfig));\n      }\n\n      // Case 2: tseslint.config(...)\n      if (\n        t.isCallExpression(eslintConfigExpression) &&\n        t.isMemberExpression(eslintConfigExpression.callee) &&\n        tsEslintLocalName &&\n        t.isIdentifier(eslintConfigExpression.callee.object, { name: tsEslintLocalName }) &&\n        t.isIdentifier(eslintConfigExpression.callee.property, { name: 'config' })\n      ) {\n        eslintConfigExpression.arguments.push(storybookConfig);\n      }\n\n      // Case 2b: export default defineConfig([...]) from \"eslint/config\"\n      if (\n        t.isCallExpression(eslintConfigExpression) &&\n        t.isIdentifier(eslintConfigExpression.callee) &&\n        eslintDefineConfigLocalName &&\n        eslintConfigExpression.callee.name === eslintDefineConfigLocalName &&\n        eslintConfigExpression.arguments.length > 0\n      ) {\n        const firstArg = eslintConfigExpression.arguments[0];\n        if (t.isExpression(firstArg)) {\n          const unwrappedArg = unwrapTSExpression(firstArg);\n          if (unwrappedArg && t.isArrayExpression(unwrappedArg)) {\n            unwrappedArg.elements.push(t.spreadElement(storybookConfig));\n          }\n        }\n      }\n\n      // Case 3: export default config (resolve to array or call expression with array)\n      if (t.isIdentifier(eslintConfigExpression)) {\n        const binding = path.scope.getBinding(eslintConfigExpression.name);\n        if (binding && t.isVariableDeclarator(binding.path.node)) {\n          const init = unwrapTSExpression(binding.path.node.init);\n\n          if (t.isArrayExpression(init)) {\n            init.elements.push(t.spreadElement(storybookConfig));\n          } else if (\n            t.isCallExpression(init) &&\n            init.arguments.length > 0 &&\n            t.isIdentifier(init.callee) &&\n            eslintDefineConfigLocalName &&\n            init.callee.name === eslintDefineConfigLocalName\n          ) {\n            // Handle cases like defineConfig([...]) from \"eslint/config\"\n            const firstArg = init.arguments[0];\n            if (t.isExpression(firstArg)) {\n              const unwrappedArg = unwrapTSExpression(firstArg);\n              if (unwrappedArg && t.isArrayExpression(unwrappedArg)) {\n                unwrappedArg.elements.push(t.spreadElement(storybookConfig));\n              }\n            }\n          }\n        }\n      }\n    },\n\n    Program(path) {\n      const alreadyImported = path.node.body.some(\n        (node) => t.isImportDeclaration(node) && node.source.value === 'eslint-plugin-storybook'\n      );\n\n      if (!alreadyImported) {\n        // Add import: import storybook from 'eslint-plugin-storybook'\n        const importDecl = t.importDeclaration(\n          [t.importDefaultSpecifier(t.identifier('storybook'))],\n          t.stringLiteral('eslint-plugin-storybook')\n        );\n        (importDecl as any).comments = [\n          {\n            type: 'CommentLine',\n            value:\n              ' For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format',\n          },\n        ];\n        path.node.body.unshift(importDecl);\n      }\n    },\n  });\n\n  return recast.print(ast).code;\n};\n\nexport async function extractEslintInfo(packageManager: JsPackageManager): Promise<{\n  hasEslint: boolean;\n  isStorybookPluginInstalled: boolean;\n  eslintConfigFile: string | undefined;\n  unsupportedExtension?: string;\n  isFlatConfig: boolean;\n}> {\n  let unsupportedExtension = undefined;\n  const allDependencies = packageManager.getAllDependencies();\n  const { packageJson } = packageManager.primaryPackageJson;\n  let eslintConfigFile: string | undefined = undefined;\n\n  try {\n    eslintConfigFile = findEslintFile(packageManager.instanceDir);\n  } catch (err) {\n    if (err instanceof Error && err.message.includes('Unsupported ESLint')) {\n      unsupportedExtension = String(err);\n    } else {\n      throw err;\n    }\n  }\n\n  const isStorybookPluginInstalled = !!allDependencies['eslint-plugin-storybook'];\n  const hasEslint = allDependencies.eslint || eslintConfigFile || packageJson.eslintConfig;\n  return {\n    hasEslint: !!hasEslint,\n    isStorybookPluginInstalled,\n    eslintConfigFile,\n    unsupportedExtension,\n    isFlatConfig: !!(eslintConfigFile && eslintConfigFile.match(/eslint\\.config\\.[^/]+/)),\n  };\n}\n\nexport const normalizeExtends = (existingExtends: any): string[] => {\n  if (!existingExtends) {\n    return [];\n  }\n\n  if (typeof existingExtends === 'string') {\n    return [existingExtends];\n  }\n\n  if (Array.isArray(existingExtends)) {\n    return existingExtends;\n  }\n  throw new Error(`Invalid eslint extends ${existingExtends}`);\n};\n\nexport async function configureEslintPlugin({\n  eslintConfigFile,\n  packageManager,\n  isFlatConfig,\n}: {\n  eslintConfigFile: string | undefined;\n  packageManager: JsPackageManager;\n  isFlatConfig: boolean;\n}) {\n  if (eslintConfigFile) {\n    if (eslintConfigFile.endsWith('json')) {\n      logger.debug(`Detected JSON config at ${eslintConfigFile}`);\n      const eslintFileContents = await readFile(eslintConfigFile, { encoding: 'utf8' });\n      const eslintConfig = commentJson.parse(eslintFileContents) as {\n        extends?: string[];\n      };\n      const existingExtends = normalizeExtends(eslintConfig.extends).filter(Boolean);\n\n      if (existingExtends.includes('plugin:storybook/recommended')) {\n        return;\n      }\n\n      if (!Array.isArray(eslintConfig.extends)) {\n        eslintConfig.extends = eslintConfig.extends ? [eslintConfig.extends] : [];\n      }\n      eslintConfig.extends.push('plugin:storybook/recommended');\n\n      const spaces = detectIndent(eslintFileContents).amount || 2;\n      await writeFile(eslintConfigFile, commentJson.stringify(eslintConfig, null, spaces));\n    } else {\n      if (isFlatConfig) {\n        logger.debug(`Detected flat config at ${eslintConfigFile}`);\n        const code = await readFile(eslintConfigFile, { encoding: 'utf8' });\n        const output = await configureFlatConfig(code);\n        if (output === code) {\n          return;\n        }\n        await writeFile(eslintConfigFile, output);\n      } else {\n        const eslint = await readConfig(eslintConfigFile);\n        const existingExtends = normalizeExtends(eslint.getFieldValue(['extends'])).filter(Boolean);\n\n        if (existingExtends.includes('plugin:storybook/recommended')) {\n          return;\n        }\n\n        eslint.setFieldValue(['extends'], [...existingExtends, 'plugin:storybook/recommended']);\n\n        await writeConfig(eslint);\n      }\n    }\n  } else {\n    logger.debug('No ESLint config file found, configuring in package.json instead');\n    const { packageJson } = packageManager.primaryPackageJson;\n    const existingExtends = normalizeExtends(packageJson.eslintConfig?.extends).filter(Boolean);\n\n    packageManager.writePackageJson({\n      ...packageJson,\n      eslintConfig: {\n        ...packageJson.eslintConfig,\n        extends: [...existingExtends, 'plugin:storybook/recommended'],\n      },\n    });\n  }\n}\n\nexport const suggestESLintPlugin = async (): Promise<boolean> => {\n  const shouldInstall = await prompt.confirm({\n    message: dedent`\n        We have detected that you're using ESLint. Storybook provides a plugin that gives the best experience with Storybook and helps follow best practices: ${picocolors.yellow(\n          'https://storybook.js.org/docs/configure/integration/eslint-plugin'\n        )}\n\n        Would you like to install it?\n      `,\n    initialValue: true,\n  });\n\n  return shouldInstall;\n};\n"
  },
  {
    "path": "code/core/src/cli/globalSettings.test.ts",
    "content": "import fs from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { afterEach } from 'node:test';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { type Settings, _clearGlobalSettings, globalSettings } from './globalSettings.ts';\n\nvi.mock('node:fs');\nvi.mock('node:fs/promises');\n\nconst userSince = new Date();\nconst baseSettings = { version: 1, userSince: +userSince };\nconst baseSettingsJson = JSON.stringify(baseSettings, null, 2);\n\nconst TEST_SETTINGS_FILE = '/test/settings.json';\n\nbeforeEach(() => {\n  _clearGlobalSettings();\n\n  vi.useFakeTimers();\n  vi.setSystemTime(userSince);\n\n  vi.resetAllMocks();\n});\n\nafterEach(() => {\n  vi.useRealTimers();\n});\n\ndescribe('globalSettings', () => {\n  it('loads settings when called for the first time', async () => {\n    vi.mocked(fs.readFile).mockResolvedValue(baseSettingsJson);\n\n    const settings = await globalSettings(TEST_SETTINGS_FILE);\n\n    expect(settings.value.userSince).toBe(+userSince);\n  });\n\n  it('does nothing if settings are already loaded', async () => {\n    vi.mocked(fs.readFile).mockResolvedValue(baseSettingsJson);\n    await globalSettings(TEST_SETTINGS_FILE);\n\n    vi.mocked(fs.readFile).mockClear();\n    await globalSettings(TEST_SETTINGS_FILE);\n    expect(fs.readFile).not.toHaveBeenCalled();\n  });\n\n  it('does not save settings if they exist', async () => {\n    vi.mocked(fs.readFile).mockResolvedValue(baseSettingsJson);\n\n    await globalSettings(TEST_SETTINGS_FILE);\n\n    expect(fs.writeFile).not.toHaveBeenCalled();\n  });\n\n  it('saves settings and creates directory if they do not exist', async () => {\n    const error = new Error() as Error & { code: string };\n    error.code = 'ENOENT';\n    vi.mocked(fs.readFile).mockRejectedValue(error);\n\n    await globalSettings(TEST_SETTINGS_FILE);\n\n    expect(fs.mkdir).toHaveBeenCalledWith(dirname(TEST_SETTINGS_FILE), { recursive: true });\n    expect(fs.writeFile).toHaveBeenCalledWith(TEST_SETTINGS_FILE, baseSettingsJson);\n  });\n});\n\ndescribe('Settings', () => {\n  let settings: Settings;\n  beforeEach(async () => {\n    vi.mocked(fs.readFile).mockResolvedValue(baseSettingsJson);\n\n    settings = await globalSettings(TEST_SETTINGS_FILE);\n  });\n\n  describe('save', () => {\n    it('overwrites existing settings', async () => {\n      settings.value.init = { skipOnboarding: true };\n      await settings.save();\n\n      expect(fs.writeFile).toHaveBeenCalledWith(\n        TEST_SETTINGS_FILE,\n        JSON.stringify({ ...baseSettings, init: { skipOnboarding: true } }, null, 2)\n      );\n    });\n\n    it('logs warning if write fails', async () => {\n      vi.mocked(fs.writeFile).mockRejectedValue(new Error('Write error'));\n\n      await expect(settings.save()).resolves.toBeUndefined();\n      expect(console.warn).toHaveBeenCalledWith(\n        'Unable to save global settings file to /test/settings.json\\nReason: Write error'\n      );\n    });\n\n    it('logs warning if directory creation fails', async () => {\n      vi.mocked(fs.mkdir).mockRejectedValue(new Error('Directory creation error'));\n\n      await expect(settings.save()).resolves.toBeUndefined();\n      expect(console.warn).toHaveBeenCalledWith(\n        'Unable to save global settings file to /test/settings.json\\nReason: Directory creation error'\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/cli/globalSettings.ts",
    "content": "import fs from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\n\nimport { dedent } from 'ts-dedent';\nimport { z } from 'zod';\n\nimport { invariant } from '../common/utils/utils.ts';\n\nconst DEFAULT_SETTINGS_PATH = join(homedir(), '.storybook', 'settings.json');\n\nconst VERSION = 1;\n\nconst statusValue = z\n  .strictObject({\n    status: z.enum(['open', 'accepted', 'done', 'skipped']).optional(),\n    mutedAt: z.number().optional(),\n  })\n  .optional();\n\nconst userSettingSchema = z.object({\n  version: z.number(),\n  // NOTE: every key (and subkey) below must be optional, for forwards compatibility reasons\n  // (we can remove keys once they are deprecated)\n  userSince: z.number().optional(),\n  init: z.object({ skipOnboarding: z.boolean().optional() }).optional(),\n  checklist: z\n    .object({\n      items: z\n        .object({\n          accessibilityTests: statusValue,\n          autodocs: statusValue,\n          ciTests: statusValue,\n          controls: statusValue,\n          coverage: statusValue,\n          guidedTour: statusValue,\n          installA11y: statusValue,\n          installChromatic: statusValue,\n          installDocs: statusValue,\n          installVitest: statusValue,\n          mdxDocs: statusValue,\n          moreComponents: statusValue,\n          moreStories: statusValue,\n          onboardingSurvey: statusValue,\n          organizeStories: statusValue,\n          publishStorybook: statusValue,\n          renderComponent: statusValue,\n          runTests: statusValue,\n          viewports: statusValue,\n          visualTests: statusValue,\n          whatsNewStorybook10: statusValue,\n          writeInteractions: statusValue,\n        })\n        .optional(),\n      widget: z.object({ disable: z.boolean().optional() }).optional(),\n    })\n    .optional(),\n});\n\nlet settings: Settings | undefined;\nexport async function globalSettings(filePath = DEFAULT_SETTINGS_PATH) {\n  if (settings) {\n    return settings;\n  }\n\n  try {\n    const content = await fs.readFile(filePath, 'utf8');\n    const settingsValue = userSettingSchema.parse(JSON.parse(content));\n    settings = new Settings(filePath, settingsValue);\n  } catch (err: any) {\n    // We don't currently log the issue we have loading the setting file here, but if it doesn't\n    // yet exist we'll get err.code = 'ENOENT'\n\n    // There is no existing settings file or it has a problem;\n    settings = new Settings(filePath, { version: VERSION, userSince: Date.now() });\n    await settings.save();\n  }\n\n  return settings;\n}\n\n// For testing\nexport function _clearGlobalSettings() {\n  settings = undefined;\n}\n\n/**\n * A class for reading and writing settings from a JSON file. Supports nested settings with dot\n * notation.\n */\nexport class Settings {\n  private filePath: string;\n\n  public value: z.infer<typeof userSettingSchema>;\n\n  /**\n   * Create a new Settings instance\n   *\n   * @param filePath Path to the JSON settings file\n   * @param value Loaded value of settings\n   */\n  constructor(filePath: string, value: z.infer<typeof userSettingSchema>) {\n    this.filePath = filePath;\n    this.value = value;\n  }\n\n  /** Save settings to the file */\n  async save(): Promise<void> {\n    invariant(this.filePath, 'No file path to save settings to');\n    try {\n      await fs.mkdir(dirname(this.filePath), { recursive: true });\n      await fs.writeFile(this.filePath, JSON.stringify(this.value, null, 2));\n    } catch (err) {\n      console.warn(dedent`\n        Unable to save global settings file to ${this.filePath}\n        ${err && `Reason: ${(err as Error).message ?? err}`}`);\n    }\n  }\n}\n"
  },
  {
    "path": "code/core/src/cli/helpers.test.ts",
    "content": "import fs from 'node:fs';\nimport fsp from 'node:fs/promises';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { JsPackageManager } from 'storybook/internal/common';\nimport { Feature, SupportedLanguage, SupportedRenderer } from 'storybook/internal/types';\n\nimport { sep } from 'path';\n\nimport { IS_WINDOWS } from '../../../vitest.helpers.ts';\nimport * as helpers from './helpers.ts';\n\nconst normalizePath = (path: string) => (IS_WINDOWS ? path.replace(/\\//g, sep) : path);\n\nconst fsMocks = vi.hoisted(() => ({\n  cpSync: vi.fn(() => ({})),\n  existsSync: vi.fn(),\n}));\n\nconst fspMocks = vi.hoisted(() => ({\n  cp: vi.fn(() => ({})),\n  readFile: vi.fn(() => ''),\n  writeFile: vi.fn(),\n}));\n\nvi.mock('node:fs', async (importOriginal) => {\n  const actual = await importOriginal<typeof import('node:fs')>();\n  return {\n    ...actual,\n    ...fsMocks,\n    default: {\n      ...actual,\n      ...fsMocks,\n    },\n  };\n});\nvi.mock('./dirs', () => ({\n  getRendererDir: (_: JsPackageManager, renderer: string) =>\n    normalizePath(`@storybook/${renderer}`),\n}));\n\nvi.mock('node:fs/promises', async (importOriginal) => {\n  const actual = await importOriginal<typeof import('node:fs/promises')>();\n  return {\n    ...actual,\n    ...fspMocks,\n    default: {\n      ...actual,\n      ...fspMocks,\n    },\n  };\n});\n\nvi.mock('empathic/find', () => ({\n  up: vi.fn(),\n}));\n\nvi.mock('path', async (importOriginal) => {\n  const actual = await importOriginal<typeof import('path')>();\n  return {\n    ...actual,\n    // make it return just the second path, for easier testing\n    resolve: vi.fn((_, p) => p),\n  };\n});\n\nconst packageManagerMock = {\n  primaryPackageJson: {\n    packageJson: { dependencies: {}, devDependencies: {} },\n    packageJsonPath: '/some/path',\n    operationDir: '/some/path',\n  },\n} as JsPackageManager;\n\ndescribe('Helpers', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n  });\n\n  describe('getVersionSafe', () => {\n    describe('installed', () => {\n      it.each([\n        ['3.0.0', '3.0.0'],\n        ['5.0.0-next.0', '5.0.0-next.0'],\n        [\n          '4.2.19::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Fsvelte%2F-%2Fsvelte-4.2.19.tgz',\n          '4.2.19',\n        ],\n      ])('svelte %s => %s', async (svelteVersion, expectedAddonSpecifier) => {\n        const packageManager = {\n          getInstalledVersion: async (pkg: string) =>\n            pkg === 'svelte' ? svelteVersion : undefined,\n          getAllDependencies: () => ({ svelte: `^${svelteVersion}` }),\n        } as any as JsPackageManager;\n        await expect(helpers.getVersionSafe(packageManager, 'svelte')).resolves.toBe(\n          expectedAddonSpecifier\n        );\n      });\n    });\n\n    describe('uninstalled', () => {\n      it.each([\n        ['^3', '3.0.0'],\n        ['^5.0.0-next.0', '5.0.0-next.0'],\n        [\n          '4.2.19::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Fsvelte%2F-%2Fsvelte-4.2.19.tgz',\n          '4.2.19',\n        ],\n      ])('svelte %s => %s', async (svelteSpecifier, expectedAddonSpecifier) => {\n        const packageManager = {\n          getInstalledVersion: async (pkg: string) => undefined,\n          getAllDependencies: () => ({ svelte: svelteSpecifier }),\n        } as any as JsPackageManager;\n        await expect(helpers.getVersionSafe(packageManager, 'svelte')).resolves.toBe(\n          expectedAddonSpecifier\n        );\n      });\n    });\n  });\n\n  describe('copyTemplate', () => {\n    it(`should copy template files when directory is present`, () => {\n      const csfDirectory = /template-csf\\/$/;\n      fsMocks.existsSync.mockReturnValue(true);\n\n      helpers.copyTemplate('');\n\n      expect(fs.cpSync).toHaveBeenCalledWith(\n        expect.stringMatching(csfDirectory),\n        expect.anything(),\n        expect.anything()\n      );\n    });\n\n    it(`should throw an error if template directory cannot be found`, () => {\n      fsMocks.existsSync.mockReturnValue(false);\n\n      expect(() => {\n        helpers.copyTemplate('');\n      }).toThrowError(\"Couldn't find template dir\");\n    });\n  });\n\n  it.each`\n    language        | exists          | expected\n    ${'javascript'} | ${['js', 'ts']} | ${'/js'}\n    ${'typescript'} | ${['js', 'ts']} | ${'/ts'}\n    ${'typescript'} | ${['js']}       | ${'/js'}\n    ${'javascript'} | ${[]}           | ${''}\n    ${'typescript'} | ${[]}           | ${''}\n  `(\n    `should copy $expected when folder $exists exists for language $language`,\n    async ({ language, exists, expected }) => {\n      const componentsDirectory = exists.map((folder: string) =>\n        normalizePath(`@storybook/react/template/cli/${folder}`)\n      );\n      fsMocks.existsSync.mockImplementation(\n        (filePath) =>\n          componentsDirectory.includes(filePath) ||\n          filePath === normalizePath('@storybook/react/template/cli')\n      );\n      await helpers.copyTemplateFiles({\n        templateLocation: SupportedRenderer.REACT,\n        language,\n        packageManager: packageManagerMock,\n        commonAssetsDir: normalizePath('create-storybook/rendererAssets/common'),\n        features: new Set([Feature.DOCS, Feature.TEST]),\n      });\n\n      expect(fsp.cp).toHaveBeenNthCalledWith(\n        1,\n        normalizePath('create-storybook/rendererAssets/common'),\n        './stories',\n        expect.anything()\n      );\n\n      const expectedDirectory = normalizePath(`@storybook/react/template/cli${expected}`);\n      expect(fsp.cp).toHaveBeenNthCalledWith(2, expectedDirectory, './stories', expect.anything());\n    }\n  );\n\n  it(`should copy to src folder when exists`, async () => {\n    vi.mocked(fs.existsSync).mockImplementation((filePath) => {\n      return filePath === normalizePath('@storybook/react/template/cli') || filePath === './src';\n    });\n    await helpers.copyTemplateFiles({\n      templateLocation: SupportedRenderer.REACT,\n      language: SupportedLanguage.JAVASCRIPT,\n      packageManager: packageManagerMock,\n      features: new Set([Feature.DOCS, Feature.TEST]),\n    });\n    expect(fsp.cp).toHaveBeenCalledWith(expect.anything(), './src/stories', expect.anything());\n  });\n\n  it(`should copy to root folder when src doesn't exist`, async () => {\n    vi.mocked(fs.existsSync).mockImplementation((filePath) => {\n      return filePath === normalizePath('@storybook/react/template/cli');\n    });\n    await helpers.copyTemplateFiles({\n      templateLocation: SupportedRenderer.REACT,\n      language: SupportedLanguage.JAVASCRIPT,\n      packageManager: packageManagerMock,\n      features: new Set([Feature.DOCS, Feature.TEST]),\n    });\n    expect(fsp.cp).toHaveBeenCalledWith(expect.anything(), './stories', expect.anything());\n  });\n\n  it(`should throw an error for unsupported renderer`, async () => {\n    const renderer = 'unknown renderer' as unknown as SupportedRenderer;\n    const expectedMessage = `Unsupported renderer: ${renderer}`;\n    await expect(\n      helpers.copyTemplateFiles({\n        templateLocation: renderer,\n        language: SupportedLanguage.JAVASCRIPT,\n        packageManager: packageManagerMock,\n        features: new Set([Feature.DOCS, Feature.TEST]),\n      })\n    ).rejects.toThrowError(expectedMessage);\n  });\n\n  describe('coerceSemver', () => {\n    it(`should throw if the version argument is invalid semver string`, () => {\n      const invalidSemverString = 'hello, world';\n      expect(() => {\n        helpers.coerceSemver(invalidSemverString);\n      }).toThrowError(`Could not coerce ${invalidSemverString} into a semver.`);\n    });\n  });\n\n  describe('hasStorybookDependencies', () => {\n    it(`should return true when any storybook dependency exists`, async () => {\n      const result = helpers.hasStorybookDependencies({\n        getAllDependencies: () => ({ storybook: 'x.y.z' }),\n      } as unknown as JsPackageManager);\n      expect(result).toEqual(true);\n    });\n\n    it(`should return false when no storybook dependency exists`, async () => {\n      const result = helpers.hasStorybookDependencies({\n        getAllDependencies: () => ({ axios: 'x.y.z' }),\n      } as unknown as JsPackageManager);\n      expect(result).toEqual(false);\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/cli/helpers.ts",
    "content": "import { cpSync, existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { cp, readFile, writeFile } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\n\nimport {\n  type JsPackageManager,\n  type PackageJson,\n  frameworkToRenderer,\n} from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\nimport {\n  type SupportedFramework,\n  SupportedLanguage,\n  type SupportedRenderer,\n} from 'storybook/internal/types';\nimport { Feature } from 'storybook/internal/types';\n\nimport picocolors from 'picocolors';\nimport { coerce, satisfies } from 'semver';\nimport stripJsonComments from 'strip-json-comments';\nimport invariant from 'tiny-invariant';\n\nimport { getRendererDir } from './dirs.ts';\n\nexport function readFileAsJson(jsonPath: string, allowComments?: boolean) {\n  const filePath = resolve(jsonPath);\n  if (!existsSync(filePath)) {\n    return false;\n  }\n\n  const fileContent = readFileSync(filePath, 'utf8');\n  const jsonContent = allowComments ? stripJsonComments(fileContent) : fileContent;\n\n  try {\n    return JSON.parse(jsonContent);\n  } catch (e) {\n    logger.error(picocolors.red(`Invalid json in file: ${filePath}`));\n    throw e;\n  }\n}\n\nexport const writeFileAsJson = (jsonPath: string, content: unknown) => {\n  const filePath = resolve(jsonPath);\n  if (!existsSync(filePath)) {\n    return false;\n  }\n\n  writeFileSync(filePath, `${JSON.stringify(content, null, 2)}\\n`);\n  return true;\n};\n\n/**\n * Detect if any babel dependencies need to be added to the project This is currently used by\n * react-native generator\n *\n * @example\n *\n * ```ts\n * const babelDependencies = await getBabelDependencies(\n *   packageManager,\n *   npmOptions,\n *   packageJson\n * ); // you can then spread the result when using installDependencies\n * installDependencies(npmOptions, [\n *   `@storybook/react@${storybookVersion}`,\n *   ...babelDependencies,\n * ]);\n * ```\n *\n * @param packageJson The current package.json so we can inspect its contents\n * @returns Contains the packages and versions that need to be installed\n */\nexport async function getBabelDependencies(packageManager: JsPackageManager) {\n  const dependenciesToAdd = [];\n  let babelLoaderVersion = '^8.0.0-0';\n\n  const babelCoreVersion = packageManager.getDependencyVersion('babel-core');\n\n  if (!babelCoreVersion) {\n    if (!packageManager.getDependencyVersion('@babel/core')) {\n      const babelCoreInstallVersion = await packageManager.getVersion('@babel/core');\n      dependenciesToAdd.push(`@babel/core@${babelCoreInstallVersion}`);\n    }\n  } else {\n    const latestCompatibleBabelVersion = await packageManager.latestVersion(\n      'babel-core',\n      babelCoreVersion\n    );\n    // Babel 6\n    if (latestCompatibleBabelVersion && satisfies(latestCompatibleBabelVersion, '^6.0.0')) {\n      babelLoaderVersion = '^7.0.0';\n    }\n  }\n\n  if (!packageManager.getDependencyVersion('babel-loader')) {\n    const babelLoaderInstallVersion = await packageManager.getVersion(\n      'babel-loader',\n      babelLoaderVersion\n    );\n    dependenciesToAdd.push(`babel-loader@${babelLoaderInstallVersion}`);\n  }\n\n  return dependenciesToAdd;\n}\n\nexport function addToDevDependenciesIfNotPresent(\n  packageJson: PackageJson,\n  name: string,\n  packageVersion: string\n) {\n  if (!packageJson.dependencies?.[name] && !packageJson.devDependencies?.[name]) {\n    if (packageJson.devDependencies) {\n      packageJson.devDependencies[name] = packageVersion;\n    } else {\n      packageJson.devDependencies = {\n        [name]: packageVersion,\n      };\n    }\n  }\n}\n\nexport function copyTemplate(templateRoot: string, destination = '.') {\n  const templateDir = resolve(templateRoot, `template-csf/`);\n\n  if (!existsSync(templateDir)) {\n    throw new Error(`Couldn't find template dir`);\n  }\n\n  cpSync(templateDir, destination, { recursive: true });\n}\n\ntype CopyTemplateFilesOptions = {\n  packageManager: JsPackageManager;\n  templateLocation: SupportedFramework | SupportedRenderer;\n  language: SupportedLanguage;\n  commonAssetsDir?: string;\n  destination?: string;\n  features: Set<Feature>;\n};\n\n/**\n * Return the installed version of a package, or the coerced version specifier from package.json if\n * it's a dependency but not installed (e.g. in a fresh project)\n */\nexport async function getVersionSafe(packageManager: JsPackageManager, packageName: string) {\n  try {\n    let version = await packageManager.getInstalledVersion(packageName);\n    if (!version) {\n      const deps = packageManager.getAllDependencies();\n      const versionSpecifier = deps[packageName];\n      version = versionSpecifier ?? '';\n    }\n    const coerced = coerce(version, { includePrerelease: true });\n    return coerced?.toString();\n  } catch (err) {\n    // fall back to no version\n  }\n  return undefined;\n}\n\nexport const cliStoriesTargetPath = async () => {\n  if (existsSync('./src')) {\n    return './src/stories';\n  }\n  return './stories';\n};\n\nexport async function copyTemplateFiles({\n  packageManager,\n  templateLocation,\n  language,\n  destination,\n  commonAssetsDir,\n  features,\n}: CopyTemplateFilesOptions) {\n  const languageFolderMapping: Record<SupportedLanguage | 'typescript', string> = {\n    [SupportedLanguage.JAVASCRIPT]: 'js',\n    [SupportedLanguage.TYPESCRIPT]: 'ts',\n  };\n  const templatePath = async () => {\n    const baseDir = await getRendererDir(packageManager, templateLocation);\n\n    if (!baseDir) {\n      return null;\n    }\n\n    const assetsDir = join(baseDir, 'template', 'cli');\n\n    const assetsLanguage = join(assetsDir, languageFolderMapping[language]);\n    const assetsJS = join(assetsDir, languageFolderMapping[SupportedLanguage.JAVASCRIPT]);\n    const assetsTS = join(assetsDir, languageFolderMapping.typescript);\n\n    // Ideally use the assets that match the language & version.\n    if (existsSync(assetsLanguage)) {\n      return assetsLanguage;\n    }\n    // Fallback further to TS (for backwards compatibility purposes)\n    if (existsSync(assetsTS)) {\n      return assetsTS;\n    }\n    // Fallback further to JS\n    if (existsSync(assetsJS)) {\n      return assetsJS;\n    }\n    // As a last resort, look for the root of the asset directory\n    if (existsSync(assetsDir)) {\n      return assetsDir;\n    }\n    throw new Error(`Unsupported renderer: ${templateLocation} (${baseDir})`);\n  };\n\n  const destinationPath = destination ?? (await cliStoriesTargetPath());\n  const filter = (file: string) => features.has(Feature.DOCS) || !file.endsWith('.mdx');\n  if (commonAssetsDir) {\n    await cp(commonAssetsDir, destinationPath, { recursive: true, filter });\n  }\n  const tmpPath = await templatePath();\n\n  if (tmpPath) {\n    await cp(tmpPath, destinationPath, { recursive: true, filter });\n  }\n\n  if (commonAssetsDir && features.has(Feature.DOCS)) {\n    const rendererType = frameworkToRenderer[templateLocation] || 'react';\n\n    await adjustTemplate(join(destinationPath, 'Configure.mdx'), { renderer: rendererType });\n  }\n}\n\nexport async function adjustTemplate(templatePath: string, templateData: Record<string, any>) {\n  // for now, we're just doing a simple string replace\n  // in the future we might replace this with a proper templating engine\n  let template = await readFile(templatePath, { encoding: 'utf8' });\n\n  Object.keys(templateData).forEach((key) => {\n    template = template.replaceAll(`{{${key}}}`, `${templateData[key]}`);\n  });\n\n  await writeFile(templatePath, template);\n}\n\nexport function coerceSemver(version: string) {\n  const coercedSemver = coerce(version);\n  invariant(coercedSemver != null, `Could not coerce ${version} into a semver.`);\n  return coercedSemver;\n}\n\nexport function hasStorybookDependencies(packageManager: JsPackageManager) {\n  const currentPackageDeps = packageManager.getAllDependencies();\n\n  return Object.keys(currentPackageDeps).some((dep) => dep.includes('storybook'));\n}\n"
  },
  {
    "path": "code/core/src/cli/index.ts",
    "content": "export * from './detect.ts';\nexport * from './helpers.ts';\nexport * from './angular/helpers.ts';\nexport * from './dirs.ts';\nexport * from './projectTypes.ts';\nexport * from './NpmOptions.ts';\nexport * from './eslintPlugin.ts';\nexport * from './globalSettings.ts';\nexport * from './AddonVitestService.ts';\n"
  },
  {
    "path": "code/core/src/cli/projectTypes.ts",
    "content": "export enum ProjectType {\n  ANGULAR = 'angular',\n  EMBER = 'ember',\n  HTML = 'html',\n  NEXTJS = 'nextjs',\n  NUXT = 'nuxt',\n  NX = 'nx',\n  PREACT = 'preact',\n  QWIK = 'qwik',\n  REACT = 'react',\n  REACT_NATIVE = 'react_native',\n  REACT_NATIVE_AND_RNW = 'react_native_and_rnw',\n  REACT_NATIVE_WEB = 'react_native_web',\n  REACT_SCRIPTS = 'react_scripts',\n  SERVER = 'server',\n  SOLID = 'solid',\n  SVELTE = 'svelte',\n  SVELTEKIT = 'sveltekit',\n  UNDETECTED = 'undetected',\n  UNSUPPORTED = 'unsupported',\n  VUE3 = 'vue3',\n  WEB_COMPONENTS = 'web_components',\n}\n"
  },
  {
    "path": "code/core/src/client-logger/README.md",
    "content": "# Storybook Logger\n\nAny client-side logging that is done through storybook should be done through this package.\n\nExamples:\n\n```js\nimport { logger } from 'storybook/internal/client-logger';\n\nlogger.info('Info message');\nlogger.warn('Warning message');\nlogger.error('Error message');\n```\n\nFor more information visit: [storybook.js.org](https://storybook.js.org)\n"
  },
  {
    "path": "code/core/src/client-logger/index.test.ts",
    "content": "import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { logger } from './index.ts';\n\nvi.mock('@storybook/global', () => ({ global: { ...global, LOGLEVEL: 'debug' } }));\n\ndescribe('client-logger default LOGLEVEL', () => {\n  const initialConsole = { ...global.console };\n  beforeEach(() => {\n    global.console.trace = vi.fn();\n    global.console.debug = vi.fn();\n    global.console.log = vi.fn();\n    global.console.info = vi.fn();\n    global.console.warn = vi.fn();\n    global.console.error = vi.fn();\n  });\n  afterAll(() => {\n    global.console = initialConsole;\n  });\n  it('should have an debug method that displays the message in red, with a trace', () => {\n    const message = 'debug message';\n    logger.debug(message);\n    expect(global.console.debug).toHaveBeenCalledWith(message);\n  });\n  it('should have an log method that displays the message in red, with a trace', () => {\n    const message = 'log message';\n    logger.log(message);\n    expect(global.console.log).toHaveBeenCalledWith(message);\n  });\n  it('should have an info method that displays the message', () => {\n    const message = 'information';\n    logger.info(message);\n    expect(global.console.info).toHaveBeenCalledWith(message);\n  });\n  it('should have a warning method that displays the message in yellow, with a trace', () => {\n    const message = 'warning message';\n    logger.warn(message);\n    expect(global.console.warn).toHaveBeenCalledWith(message);\n  });\n  it('should have an error method that displays the message in red, with a trace', () => {\n    const message = 'error message';\n    logger.error(message);\n    expect(global.console.error).toHaveBeenCalledWith(message);\n  });\n});\n"
  },
  {
    "path": "code/core/src/client-logger/index.ts",
    "content": "import { global } from '@storybook/global';\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nconst { LOGLEVEL } = global;\n\ntype LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent';\n\nconst levels: Record<LogLevel, number> = {\n  trace: 1,\n  debug: 2,\n  info: 3,\n  warn: 4,\n  error: 5,\n  silent: 10,\n};\n\nconst currentLogLevelString: LogLevel = LOGLEVEL as LogLevel;\nconst currentLogLevelNumber: number = levels[currentLogLevelString] || levels.info;\n\ntype LoggingFn = (message: any, ...args: any[]) => void;\n\nexport const logger = {\n  trace: (message: any, ...rest: any[]): void => {\n    if (currentLogLevelNumber <= levels.trace) {\n      console.trace(message, ...rest);\n    }\n  },\n  debug: (message: any, ...rest: any[]): void => {\n    if (currentLogLevelNumber <= levels.debug) {\n      console.debug(message, ...rest);\n    }\n  },\n  info: (message: any, ...rest: any[]): void => {\n    if (currentLogLevelNumber <= levels.info) {\n      console.info(message, ...rest);\n    }\n  },\n  warn: (message: any, ...rest: any[]): void => {\n    if (currentLogLevelNumber <= levels.warn) {\n      console.warn(message, ...rest);\n    }\n  },\n  error: (message: any, ...rest: any[]): void => {\n    if (currentLogLevelNumber <= levels.error) {\n      console.error(message, ...rest);\n    }\n  },\n  log: (message: any, ...rest: any[]): void => {\n    if (currentLogLevelNumber < levels.silent) {\n      console.log(message, ...rest);\n    }\n  },\n} as const;\n\nconst logged = new Set();\nexport const once =\n  (type: keyof typeof logger) =>\n  (message: any, ...rest: any[]) => {\n    if (logged.has(message)) {\n      return undefined;\n    }\n    logged.add(message);\n    return logger[type](message, ...rest);\n  };\n\nonce.clear = () => logged.clear();\nonce.trace = once('trace');\nonce.debug = once('debug');\nonce.info = once('info');\nonce.warn = once('warn');\nonce.error = once('error');\nonce.log = once('log');\n\nexport const deprecate = once('warn');\n\nexport const pretty =\n  (type: keyof typeof logger) =>\n  (...args: Parameters<LoggingFn>) => {\n    const argArray: Parameters<LoggingFn> = [] as any;\n\n    if (args.length) {\n      const startTagRe = /<span\\s+style=(['\"])([^'\"]*)\\1\\s*>/gi;\n      const endTagRe = /<\\/span>/gi;\n\n      let reResultArray;\n      argArray.push(args[0].replace(startTagRe, '%c').replace(endTagRe, '%c'));\n\n      while ((reResultArray = startTagRe.exec(args[0]))) {\n        argArray.push(reResultArray[2]);\n        argArray.push('');\n      }\n\n      // pass through subsequent args since chrome dev tools does not (yet) support console.log styling of the following form: console.log('%cBlue!', 'color: blue;', '%cRed!', 'color: red;');\n\n      for (let j = 1; j < args.length; j++) {\n        argArray.push(args[j]);\n      }\n    }\n\n    // eslint-disable-next-line prefer-spread\n    logger[type].apply(logger, argArray);\n  };\n\npretty.trace = pretty('trace');\npretty.debug = pretty('debug');\npretty.info = pretty('info');\npretty.warn = pretty('warn');\npretty.error = pretty('error');\n"
  },
  {
    "path": "code/core/src/common/README.md",
    "content": "# Storybook Core-Common\n\nCommon utilities used across `@storybook/core-server` (manager UI configuration) and `@storybook/builder-webpack{4,5}` (preview configuration).\n\nThis is a lot of code extracted for convenience, not because it made sense.\n\nSupporting multiple version of webpack and this duplicating a large portion of code that was never meant to be generic caused this.\n\nAt some point we'll refactor this, it's likely a lot of this code is dead or barely used.\n"
  },
  {
    "path": "code/core/src/common/config.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { filterPresetsConfig } from './presets.ts';\n\ndescribe('filterPresetsConfig', () => {\n  it('string config', () => {\n    expect(filterPresetsConfig(['@storybook/preset-scss', '@storybook/preset-typescript'])).toEqual(\n      ['@storybook/preset-scss']\n    );\n  });\n\n  it('windows paths', () => {\n    expect(filterPresetsConfig(['a', '@storybook\\\\preset-typescript'])).toEqual(['a']);\n  });\n\n  it('object config', () => {\n    const tsConfig = {\n      name: '@storybook/preset-typescript',\n      options: { foo: 1 },\n    };\n    expect(filterPresetsConfig([tsConfig, 'a'])).toEqual(['a']);\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/index.ts",
    "content": "import versions from './versions.ts';\n\n/// <reference types=\"@types/compression\" />\n\nexport * from './presets.ts';\nexport * from './utils/cache.ts';\nexport * from './utils/cli.ts';\nexport * from './utils/check-addon-order.ts';\nexport * from './utils/envs.ts';\nexport * from './utils/common-glob-options.ts';\nexport * from './utils/framework.ts';\nexport * from './utils/get-builder-options.ts';\nexport * from './utils/get-framework-name.ts';\nexport * from './utils/get-renderer-name.ts';\nexport * from './utils/get-storybook-configuration.ts';\nexport * from './utils/get-storybook-info.ts';\nexport * from './utils/get-storybook-refs.ts';\nexport * from './utils/glob-to-regexp.ts';\nexport * from './utils/HandledError.ts';\nexport * from './utils/interpolate.ts';\nexport * from './utils/interpret-files.ts';\nexport * from './utils/interpret-require.ts';\nexport * from './utils/load-main-config.ts';\nexport * from './utils/load-manager-or-addons-file.ts';\nexport * from './utils/load-preview-or-config-file.ts';\nexport * from './utils/log-config.ts';\nexport * from './utils/normalize-stories.ts';\nexport * from './utils/paths.ts';\nexport * from './utils/readTemplate.ts';\nexport * from './utils/remove.ts';\nexport * from './utils/resolve-path-in-sb-cache.ts';\nexport * from './utils/symlinks.ts';\nexport * from './utils/template.ts';\nexport * from './utils/validate-config.ts';\nexport * from './utils/validate-configuration-files.ts';\nexport * from './utils/satisfies.ts';\nexport * from './utils/formatter.ts';\nexport * from './utils/get-story-id.ts';\nexport * from './utils/posix.ts';\nexport * from './utils/sync-main-preview-addons.ts';\nexport * from './utils/setup-addon-in-config.ts';\nexport * from './utils/wrap-getAbsolutePath-utils.ts';\nexport * from './js-package-manager/index.ts';\nexport * from './utils/scan-and-transform-files.ts';\nexport * from './utils/transform-imports.ts';\nexport * from '../shared/utils/module.ts';\nexport * from './utils/get-addon-names.ts';\nexport * from './utils/utils.ts';\nexport * from './utils/command.ts';\n\nexport { versions };\n\nexport { createFileSystemCache, FileSystemCache } from './utils/file-cache.ts';\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/BUNProxy.ts",
    "content": "import { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { logger, prompt } from 'storybook/internal/node-logger';\nimport { FindPackageVersionsError } from 'storybook/internal/server-errors';\n\nimport * as find from 'empathic/find';\n// eslint-disable-next-line depend/ban-dependencies\nimport type { ResultPromise } from 'execa';\nimport sort from 'semver/functions/sort.js';\n\nimport type { ExecuteCommandOptions } from '../utils/command.ts';\nimport { executeCommand } from '../utils/command.ts';\nimport { getProjectRoot } from '../utils/paths.ts';\nimport { JsPackageManager, PackageManagerName } from './JsPackageManager.ts';\nimport type { PackageJson } from './PackageJson.ts';\nimport type { InstallationMetadata, PackageMetadata } from './types.ts';\n\ntype NpmDependency = {\n  version: string;\n  resolved?: string;\n  overridden?: boolean;\n  dependencies?: NpmDependencies;\n};\n\ntype NpmDependencies = {\n  [key: string]: NpmDependency;\n};\n\nexport type NpmListOutput = {\n  dependencies: NpmDependencies;\n};\n\nconst NPM_ERROR_REGEX = /npm ERR! code (\\w+)/;\nconst NPM_ERROR_CODES = {\n  E401: 'Authentication failed or is required.',\n  E403: 'Access to the resource is forbidden.',\n  E404: 'Requested resource not found.',\n  EACCES: 'Permission issue.',\n  EAI_FAIL: 'DNS lookup failed.',\n  EBADENGINE: 'Engine compatibility check failed.',\n  EBADPLATFORM: 'Platform not supported.',\n  ECONNREFUSED: 'Connection refused.',\n  ECONNRESET: 'Connection reset.',\n  EEXIST: 'File or directory already exists.',\n  EINVALIDTYPE: 'Invalid type encountered.',\n  EISGIT: 'Git operation failed or conflicts with an existing file.',\n  EJSONPARSE: 'Error parsing JSON data.',\n  EMISSINGARG: 'Required argument missing.',\n  ENEEDAUTH: 'Authentication needed.',\n  ENOAUDIT: 'No audit available.',\n  ENOENT: 'File or directory does not exist.',\n  ENOGIT: 'Git not found or failed to run.',\n  ENOLOCK: 'Lockfile missing.',\n  ENOSPC: 'Insufficient disk space.',\n  ENOTFOUND: 'Resource not found.',\n  EOTP: 'One-time password required.',\n  EPERM: 'Permission error.',\n  EPUBLISHCONFLICT: 'Conflict during package publishing.',\n  ERESOLVE: 'Dependency resolution error.',\n  EROFS: 'File system is read-only.',\n  ERR_SOCKET_TIMEOUT: 'Socket timed out.',\n  ETARGET: 'Package target not found.',\n  ETIMEDOUT: 'Operation timed out.',\n  ETOOMANYARGS: 'Too many arguments provided.',\n  EUNKNOWNTYPE: 'Unknown type encountered.',\n};\n\nexport class BUNProxy extends JsPackageManager {\n  readonly type = PackageManagerName.BUN;\n\n  installArgs: string[] | undefined;\n\n  async initPackageJson() {\n    return executeCommand({ command: 'bun', args: ['init'] });\n  }\n\n  getRunStorybookCommand(): string {\n    return 'bun run storybook';\n  }\n\n  getRunCommand(command: string): string {\n    return `bun run ${command}`;\n  }\n\n  getRemoteRunCommand(pkg: string, args: string[], specifier?: string): string {\n    return `bunx ${pkg}${specifier ? `@${specifier}` : ''} ${args.join(' ')}`;\n  }\n\n  getPackageCommand(args: string[]): string {\n    return `bunx ${args.join(' ')}`;\n  }\n\n  public async getModulePackageJSON(packageName: string): Promise<PackageJson | null> {\n    const wantedPath = join('node_modules', packageName, 'package.json');\n    const packageJsonPath = find.up(wantedPath, {\n      cwd: this.primaryPackageJson.operationDir,\n      last: getProjectRoot(),\n    });\n\n    if (!packageJsonPath) {\n      return null;\n    }\n\n    const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n    return packageJson;\n  }\n\n  getInstallArgs(): string[] {\n    if (!this.installArgs) {\n      this.installArgs = [];\n    }\n    return this.installArgs;\n  }\n\n  public runPackageCommand(\n    options: Omit<ExecuteCommandOptions, 'command'> & { args: string[] }\n  ): ResultPromise {\n    // The following command is unsafe to use with `bun run`\n    // because it will always favour a equally script named in the package.json instead of the installed binary.\n    // so running `bun storybook automigrate` will run the\n    // `storybook` script (dev) instead of the `storybook`. binary.\n    // return executeCommand({\n    //   command: 'bun',\n    //   args: ['run', ...args],\n    //   ...options,\n    // });\n    return executeCommand({\n      command: 'bunx',\n      ...options,\n    });\n  }\n\n  public runInternalCommand(\n    command: string,\n    args: string[],\n    cwd?: string,\n    stdio?: 'inherit' | 'pipe' | 'ignore'\n  ) {\n    return executeCommand({\n      command: 'bun',\n      args: [command, ...args],\n      cwd: cwd ?? this.cwd,\n      stdio,\n    });\n  }\n\n  public async findInstallations(pattern: string[], { depth = 99 }: { depth?: number } = {}) {\n    const exec = async ({ packageDepth }: { packageDepth: number }) => {\n      return executeCommand({\n        command: 'npm',\n        args: ['ls', '--json', `--depth=${packageDepth}`],\n        cwd: this.cwd,\n        stdio: ['ignore', 'pipe', 'ignore'],\n        env: {\n          FORCE_COLOR: 'false',\n        },\n      });\n    };\n\n    try {\n      const process = await exec({ packageDepth: depth });\n      const result = await process;\n      const commandResult = typeof result.stdout === 'string' ? result.stdout : '';\n      const parsedOutput = JSON.parse(commandResult);\n\n      return this.mapDependencies(parsedOutput, pattern);\n    } catch (e) {\n      // when --depth is higher than 0, npm can return a non-zero exit code\n      // in case the user's project has peer dependency issues. So we try again with no depth\n      try {\n        const process = await exec({ packageDepth: 0 });\n        const result = await process;\n        const commandResult = typeof result.stdout === 'string' ? result.stdout : '';\n        const parsedOutput = JSON.parse(commandResult);\n\n        return this.mapDependencies(parsedOutput, pattern);\n      } catch (err) {\n        logger.debug(\n          `An issue occurred while trying to find dependencies metadata using npm: ${err}`\n        );\n        return undefined;\n      }\n    }\n  }\n\n  protected getResolutions(packageJson: PackageJson, versions: Record<string, string>) {\n    return {\n      overrides: {\n        ...packageJson.overrides,\n        ...versions,\n      },\n    };\n  }\n\n  protected runInstall(options?: { force?: boolean }) {\n    return executeCommand({\n      command: 'bun',\n      args: ['install', ...this.getInstallArgs(), ...(options?.force ? ['--force'] : [])],\n      cwd: this.cwd,\n      stdio: prompt.getPreferredStdio(),\n    });\n  }\n\n  public async getRegistryURL() {\n    const process = executeCommand({\n      command: 'npm',\n      cwd: this.cwd,\n      // \"npm config\" commands are not allowed in workspaces per default\n      // https://github.com/npm/cli/issues/6099#issuecomment-1847584792\n      args: ['config', 'get', 'registry', '-ws=false', '-iwr'],\n    });\n    const result = await process;\n    const url = (typeof result.stdout === 'string' ? result.stdout : '').trim();\n    return url === 'undefined' ? undefined : url;\n  }\n\n  protected runAddDeps(dependencies: string[], installAsDevDependencies: boolean) {\n    let args = [...dependencies];\n\n    if (installAsDevDependencies) {\n      args = ['-D', ...args];\n    }\n\n    return executeCommand({\n      command: 'bun',\n      args: ['add', ...args, ...this.getInstallArgs()],\n      stdio: 'pipe',\n      cwd: this.primaryPackageJson.operationDir,\n    });\n  }\n\n  protected async runGetVersions<T extends boolean>(\n    packageName: string,\n    fetchAllVersions: T\n  ): Promise<T extends true ? string[] : string> {\n    const args = fetchAllVersions ? ['versions', '--json'] : ['version'];\n    try {\n      const process = executeCommand({\n        command: 'npm',\n        cwd: this.cwd,\n        args: ['info', packageName, ...args],\n      });\n      const result = await process;\n      const commandResult = typeof result.stdout === 'string' ? result.stdout : '';\n\n      const parsedOutput = fetchAllVersions ? JSON.parse(commandResult) : commandResult.trim();\n\n      if (parsedOutput.error?.summary) {\n        // this will be handled in the catch block below\n        throw parsedOutput.error.summary;\n      }\n\n      return parsedOutput;\n    } catch (error) {\n      throw new FindPackageVersionsError({\n        error,\n        packageManager: 'NPM',\n        packageName,\n      });\n    }\n  }\n\n  /**\n   * @param input The output of `npm ls --json`\n   * @param pattern A list of package names to filter the result. * can be used as a placeholder\n   */\n  protected mapDependencies(input: NpmListOutput, pattern: string[]): InstallationMetadata {\n    const acc: Record<string, PackageMetadata[]> = {};\n    const existingVersions: Record<string, string[]> = {};\n    const duplicatedDependencies: Record<string, string[]> = {};\n\n    const recurse = ([name, packageInfo]: [string, NpmDependency]): void => {\n      // transform pattern into regex where `*` is replaced with `.*`\n      if (!name || !pattern.some((p) => new RegExp(`^${p.replace(/\\*/g, '.*')}$`).test(name))) {\n        return;\n      }\n\n      const value = {\n        version: packageInfo.version,\n        location: '',\n      };\n\n      if (!existingVersions[name]?.includes(value.version)) {\n        if (acc[name]) {\n          acc[name].push(value);\n        } else {\n          acc[name] = [value];\n        }\n        existingVersions[name] = sort([...(existingVersions[name] || []), value.version]);\n\n        if (existingVersions[name].length > 1) {\n          duplicatedDependencies[name] = existingVersions[name];\n        }\n      }\n\n      if (packageInfo.dependencies) {\n        Object.entries(packageInfo.dependencies).forEach(recurse);\n      }\n    };\n\n    Object.entries(input.dependencies).forEach(recurse);\n\n    return {\n      dependencies: acc,\n      duplicatedDependencies,\n      infoCommand: 'npm ls --depth=1',\n      dedupeCommand: 'npm dedupe',\n    };\n  }\n\n  public parseErrorFromLogs(logs: string): string {\n    let finalMessage = 'NPM error';\n    const match = logs.match(NPM_ERROR_REGEX);\n\n    if (match) {\n      const errorCode = match[1] as keyof typeof NPM_ERROR_CODES;\n      if (errorCode) {\n        finalMessage = `${finalMessage} ${errorCode}`;\n      }\n\n      const errorMessage = NPM_ERROR_CODES[errorCode];\n      if (errorMessage) {\n        finalMessage = `${finalMessage} - ${errorMessage}`;\n      }\n    }\n\n    return finalMessage.trim();\n  }\n}\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/JsPackageManager.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { JsPackageManager } from './JsPackageManager.ts';\n\nconst mockVersions = vi.hoisted(() => ({\n  '@storybook/react': '8.3.0',\n}));\n\nvi.mock('../versions', () => ({\n  default: mockVersions,\n}));\n\ndescribe('JsPackageManager', () => {\n  let jsPackageManager: JsPackageManager;\n  let mockLatestVersion: ReturnType<typeof vi.spyOn>;\n\n  beforeEach(() => {\n    // @ts-expect-error Ignore abstract class error\n    jsPackageManager = new JsPackageManager();\n    mockLatestVersion = vi.spyOn(jsPackageManager, 'latestVersion');\n\n    vi.clearAllMocks();\n  });\n\n  describe('getVersionedPackages method', () => {\n    it('should return the latest stable release version when current version is the latest stable release', async () => {\n      mockLatestVersion.mockResolvedValue('8.3.0');\n\n      const result = await jsPackageManager.getVersionedPackages(['@storybook/react']);\n\n      expect(result).toEqual(['@storybook/react@^8.3.0']);\n    });\n\n    it('should return the current version when it is not the latest stable release', async () => {\n      mockLatestVersion.mockResolvedValue('8.3.1');\n\n      const result = await jsPackageManager.getVersionedPackages(['@storybook/react']);\n\n      expect(result).toEqual(['@storybook/react@8.3.0']);\n    });\n\n    it('should get the requested version when the package is not in the monorepo', async () => {\n      mockLatestVersion.mockResolvedValue('2.0.0');\n\n      const result = await jsPackageManager.getVersionedPackages(['@storybook/new-addon@^next']);\n\n      expect(result).toEqual(['@storybook/new-addon@^next']);\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/JsPackageManager.ts",
    "content": "import { readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, isAbsolute, join, normalize, resolve } from 'node:path';\n\nimport { logger, prompt } from 'storybook/internal/node-logger';\n\nimport detectIndent from 'detect-indent';\nimport * as find from 'empathic/find';\n// eslint-disable-next-line depend/ban-dependencies\nimport { type ResultPromise } from 'execa';\n// eslint-disable-next-line depend/ban-dependencies\nimport { globSync } from 'glob';\nimport picocolors from 'picocolors';\nimport { coerce, gt, satisfies } from 'semver';\nimport invariant from 'tiny-invariant';\n\nimport { HandledError } from '../utils/HandledError.ts';\nimport type { ExecuteCommandOptions } from '../utils/command.ts';\nimport { findFilesUp, getProjectRoot } from '../utils/paths.ts';\nimport storybookPackagesVersions from '../versions.ts';\nimport type { PackageJson, PackageJsonWithDepsAndDevDeps } from './PackageJson.ts';\nimport type { InstallationMetadata } from './types.ts';\n\nexport enum PackageManagerName {\n  NPM = 'npm',\n  YARN1 = 'yarn1',\n  YARN2 = 'yarn2',\n  PNPM = 'pnpm',\n  BUN = 'bun',\n}\n\ntype StorybookPackage = keyof typeof storybookPackagesVersions;\n\nconst indentSymbol = Symbol('indent');\n\ntype PackageJsonWithIndent = PackageJsonWithDepsAndDevDeps & {\n  [indentSymbol]?: any;\n};\n\n/**\n * Extract package name and version from input\n *\n * @param pkg A string like `@storybook/cli`, `react` or `react@^16`\n * @returns A tuple of 2 elements: [packageName, packageVersion]\n */\nexport function getPackageDetails(pkg: string): [string, string?] {\n  const idx = pkg.lastIndexOf('@');\n  // If the only `@` is the first character, it is a scoped package\n  // If it isn't in the string, it will be -1\n  if (idx <= 0) {\n    return [pkg, undefined];\n  }\n  const packageName = pkg.slice(0, idx);\n  const packageVersion = pkg.slice(idx + 1);\n  return [packageName, packageVersion];\n}\n\ninterface JsPackageManagerOptions {\n  cwd?: string;\n  configDir?: string;\n  // The storiesPaths can be provided to properly calculate the location of all relevant package.json files\n  storiesPaths?: string[];\n}\n\nexport type PackageJsonInfo = {\n  packageJsonPath: string;\n  operationDir: string;\n  packageJson: PackageJsonWithDepsAndDevDeps;\n};\n\nexport abstract class JsPackageManager {\n  abstract readonly type: PackageManagerName;\n\n  /** The path to the primary package.json file (contains the `storybook` dependency). */\n  readonly primaryPackageJson: PackageJsonInfo;\n\n  /** The paths to all package.json files in the project root. */\n  packageJsonPaths: string[];\n\n  /**\n   * The path to the Storybook instance directory. This is used to find the primary package.json\n   * file in a repository.\n   */\n  readonly instanceDir: string;\n\n  /** The current working directory. */\n  protected readonly cwd: string;\n\n  /** Cache for latest version results to avoid repeated network calls. */\n  static readonly latestVersionCache = new Map<string, string | null>();\n\n  /** Cache for installed version results to avoid repeated file system calls. */\n  static readonly installedVersionCache = new Map<string, string | null>();\n\n  /** Cache for package.json files to avoid repeated file system calls. */\n  static readonly packageJsonCache = new Map<string, PackageJsonWithIndent>();\n\n  constructor(options?: JsPackageManagerOptions) {\n    this.cwd = options?.cwd || process.cwd();\n    this.instanceDir = options?.configDir\n      ? isAbsolute(options?.configDir)\n        ? dirname(options?.configDir)\n        : dirname(join(this.cwd, options?.configDir))\n      : this.cwd;\n    this.packageJsonPaths = JsPackageManager.listAllPackageJsonPaths(\n      this.instanceDir,\n      options?.storiesPaths\n    );\n    this.primaryPackageJson = this.#getPrimaryPackageJson();\n  }\n\n  /** Runs arbitrary package scripts (as a string for display). */\n  abstract getRunCommand(command: string): string;\n\n  /** Returns the command to run the binary of a local package */\n  abstract getPackageCommand(args: string[]): string;\n\n  /** Get the package.json file for a given module. */\n  abstract getModulePackageJSON(packageName: string, cwd?: string): Promise<PackageJson | null>;\n\n  isStorybookInMonorepo() {\n    const turboJsonPath = find.up(`turbo.json`, { last: getProjectRoot() });\n    const rushJsonPath = find.up(`rush.json`, { last: getProjectRoot() });\n    const nxJsonPath = find.up(`nx.json`, { last: getProjectRoot() });\n\n    if (turboJsonPath || rushJsonPath || nxJsonPath) {\n      return true;\n    }\n\n    const packageJsonPaths = findFilesUp(['package.json']);\n    if (packageJsonPaths.length === 0) {\n      return false;\n    }\n\n    for (const packageJsonPath of packageJsonPaths) {\n      const packageJsonFile = readFileSync(packageJsonPath, 'utf8');\n      const packageJson = JSON.parse(packageJsonFile) as PackageJsonWithDepsAndDevDeps;\n\n      if (packageJson.workspaces) {\n        return true;\n      }\n    }\n\n    return false;\n  }\n\n  async installDependencies(options?: { force?: boolean }) {\n    await prompt.executeTaskWithSpinner(() => this.runInstall(options), {\n      id: 'install-dependencies',\n      intro: 'Installing dependencies...',\n      error: 'Installation of dependencies failed!',\n      success: 'Dependencies installed',\n    });\n\n    // Clear installed version cache after installation\n    this.clearInstalledVersionCache();\n  }\n\n  async dedupeDependencies(options?: { force?: boolean }) {\n    await prompt.executeTask(\n      (_signal) =>\n        this.runInternalCommand('dedupe', [...(options?.force ? ['--force'] : [])], this.cwd),\n      {\n        intro: 'Deduplicating dependencies...',\n        error: 'An error occurred while deduplicating dependencies.',\n        success: 'Dependencies deduplicated',\n      }\n    );\n\n    // Clear installed version cache after installation\n    this.clearInstalledVersionCache();\n  }\n\n  /** Read the `package.json` file available in the provided directory */\n  static getPackageJson(packageJsonPath: string): PackageJsonWithIndent {\n    // Normalize path to absolute for consistent cache keys\n    // Always use resolve() to ensure consistent format on Windows\n    // (handles drive letter casing and path separator differences)\n    // resolve() normalizes absolute paths too, ensuring consistent cache keys\n    const absolutePath = normalize(resolve(packageJsonPath));\n\n    // Check cache first\n    const cached = JsPackageManager.packageJsonCache.get(absolutePath);\n    if (cached) {\n      logger.debug(`Using cached package.json for ${absolutePath}...`);\n      return cached;\n    }\n\n    // Read from disk if not in cache\n    const jsonContent = readFileSync(absolutePath, 'utf8');\n    const packageJSON = JSON.parse(jsonContent);\n    // Symbol key keeps this metadata non-enumerable so JSON.stringify omits it\n    packageJSON[indentSymbol] = detectIndent(jsonContent).indent ?? 2;\n\n    const result: PackageJsonWithIndent = {\n      ...packageJSON,\n      dependencies: { ...(packageJSON.dependencies || {}) },\n      devDependencies: { ...(packageJSON.devDependencies || {}) },\n      peerDependencies: { ...(packageJSON.peerDependencies || {}) },\n    };\n\n    // Store in cache\n    JsPackageManager.packageJsonCache.set(absolutePath, result);\n\n    return result;\n  }\n\n  #getIndent(filePath: string): string | number {\n    try {\n      const packageJson = JsPackageManager.getPackageJson(filePath);\n      return packageJson[indentSymbol];\n    } catch (e) {\n      return 2;\n    }\n  }\n\n  writePackageJson(packageJson: PackageJson, directory = this.cwd) {\n    const packageJsonToWrite = { ...packageJson };\n    const dependencyTypes = ['dependencies', 'devDependencies', 'peerDependencies'] as const;\n\n    // Remove empty dependency objects\n    dependencyTypes.forEach((type) => {\n      if (packageJsonToWrite[type] && Object.keys(packageJsonToWrite[type]).length === 0) {\n        delete packageJsonToWrite[type];\n      }\n    });\n    const filePath = join(directory, 'package.json');\n    const indent = this.#getIndent(filePath);\n    const packageJsonPath = normalize(resolve(directory, 'package.json'));\n    const content = `${JSON.stringify(packageJsonToWrite, null, indent)}\\n`;\n    writeFileSync(packageJsonPath, content, 'utf8');\n\n    // Update cache with the written content\n    // Ensure dependencies and devDependencies exist (even if empty) to match PackageJsonWithDepsAndDevDeps type\n    const cachedPackageJson: PackageJsonWithIndent = {\n      ...packageJsonToWrite,\n      dependencies: { ...(packageJsonToWrite.dependencies || {}) },\n      devDependencies: { ...(packageJsonToWrite.devDependencies || {}) },\n      peerDependencies: { ...(packageJsonToWrite.peerDependencies || {}) },\n    };\n    cachedPackageJson[indentSymbol] = indent;\n    JsPackageManager.packageJsonCache.set(packageJsonPath, cachedPackageJson);\n  }\n\n  getAllDependencies() {\n    const allDependencies: Record<string, string> = {};\n\n    for (const packageJsonPath of this.packageJsonPaths) {\n      const packageJson = JsPackageManager.getPackageJson(packageJsonPath);\n      const { dependencies, devDependencies, peerDependencies } = packageJson;\n\n      Object.assign(allDependencies, dependencies, devDependencies, peerDependencies);\n    }\n\n    return allDependencies;\n  }\n\n  isDependencyInstalled(dependency: string) {\n    return Object.keys(this.getAllDependencies()).includes(dependency);\n  }\n\n  /**\n   * Add dependencies to a project using `yarn add` or `npm install`.\n   *\n   * @example\n   *\n   * ```ts\n   * addDependencies(options, [\n   *   `@storybook/react@${storybookVersion}`,\n   *   `@storybook/addon-links@${linksVersion}`,\n   * ]);\n   * ```\n   *\n   * @param {Object} options Contains `skipInstall`, `packageJson` and `installAsDevDependencies`\n   *   which we use to determine how we install packages.\n   * @param {Array} dependencies Contains a list of packages to add.\n   */\n  public async addDependencies(\n    options:\n      | {\n          skipInstall: true;\n          type: 'dependencies' | 'devDependencies' | 'peerDependencies';\n          writeOutputToFile?: boolean;\n          packageJsonInfo?: PackageJsonInfo;\n        }\n      | {\n          skipInstall?: false;\n          type: 'dependencies' | 'devDependencies';\n          writeOutputToFile?: boolean;\n          packageJsonInfo?: PackageJsonInfo;\n        },\n    dependencies: string[]\n  ): Promise<void | ResultPromise> {\n    const {\n      skipInstall,\n      writeOutputToFile = true,\n      packageJsonInfo = this.primaryPackageJson,\n    } = options;\n\n    if (skipInstall) {\n      const { operationDir, packageJson } = packageJsonInfo;\n      const dependenciesMap: Record<string, string> = {};\n\n      for (const dep of dependencies) {\n        const [packageName, packageVersion] = getPackageDetails(dep);\n        const latestVersion = await this.getVersion(packageName);\n        dependenciesMap[packageName] = packageVersion ?? latestVersion;\n      }\n\n      const targetDeps = packageJson[options.type] as Record<string, string>;\n\n      Object.assign(targetDeps, dependenciesMap);\n      this.writePackageJson(packageJson, operationDir);\n    } else {\n      try {\n        const result = this.runAddDeps(\n          dependencies,\n          Boolean(options.type === 'devDependencies'),\n          writeOutputToFile\n        );\n\n        // Clear installed version cache after adding dependencies\n        this.clearInstalledVersionCache();\n\n        return result;\n      } catch (e: any) {\n        logger.error('\\nAn error occurred while adding dependencies to your package.json:');\n        logger.log(String(e));\n        throw new HandledError(e);\n      }\n    }\n  }\n\n  /**\n   * Removing dependencies from the package.json file, which is found first starting from the\n   * instance root. The method does not run a package manager install like `npm install`.\n   *\n   * @example\n   *\n   * ```ts\n   * removeDependencies([`@storybook/react`]);\n   * ```\n   *\n   * @param dependencies Contains a list of packages to remove.\n   */\n  async removeDependencies(dependencies: string[]): Promise<void> {\n    for (const pjPath of this.packageJsonPaths) {\n      try {\n        const packageJson = JsPackageManager.getPackageJson(pjPath);\n        let modified = false;\n        dependencies.forEach((dep) => {\n          if (packageJson.dependencies && packageJson.dependencies[dep]) {\n            delete packageJson.dependencies[dep];\n            modified = true;\n          }\n          if (packageJson.devDependencies && packageJson.devDependencies[dep]) {\n            delete packageJson.devDependencies[dep];\n            modified = true;\n          }\n          if (packageJson.peerDependencies && packageJson.peerDependencies[dep]) {\n            delete packageJson.peerDependencies[dep];\n            modified = true;\n          }\n        });\n        if (modified) {\n          this.writePackageJson(packageJson, dirname(pjPath));\n          break;\n        }\n      } catch (e) {\n        logger.warn(`Could not process ${pjPath} for dependency removal: ${String(e)}`);\n      }\n    }\n  }\n\n  /**\n   * Return an array of strings matching following format: `<package_name>@<package_latest_version>`\n   *\n   * For packages in the storybook monorepo, when the latest version is equal to the version of the\n   * current CLI the version is not added to the string.\n   *\n   * When a package is in the monorepo, and the version is not equal to the CLI version, the version\n   * is taken from the versions.ts file and added to the string.\n   *\n   * @param packages\n   */\n  public getVersionedPackages(packages: string[]): Promise<string[]> {\n    return Promise.all(\n      packages.map(async (pkg) => {\n        const [packageName, packageVersion] = getPackageDetails(pkg);\n\n        // If the packageVersion is specified and we are not dealing with a storybook package,\n        // just return the requested version.\n        if (packageVersion && !(packageName in storybookPackagesVersions)) {\n          return pkg;\n        }\n\n        const latestInRange = await this.latestVersion(packageName, packageVersion);\n\n        const k = packageName as keyof typeof storybookPackagesVersions;\n        const currentVersion = storybookPackagesVersions[k];\n\n        const isLatestStableRelease = currentVersion === latestInRange;\n\n        if (isLatestStableRelease || !currentVersion) {\n          return `${packageName}@^${latestInRange}`;\n        }\n\n        return `${packageName}@${currentVersion}`;\n      })\n    );\n  }\n\n  /**\n   * Return an array of string standing for the latest version of the input packages. To be able to\n   * identify which version goes with which package the order of the input array is keep.\n   *\n   * @param packageNames\n   */\n  public getVersions(...packageNames: string[]): Promise<string[]> {\n    return Promise.all(\n      packageNames.map((packageName) => {\n        return this.getVersion(packageName);\n      })\n    );\n  }\n\n  /**\n   * Return the latest version of the input package available on npmjs registry. If constraint are\n   * provided it return the latest version matching the constraints.\n   *\n   * For `@storybook/*` packages the latest version is retrieved from `cli/src/versions.json` file\n   * directly\n   *\n   * @param packageName The name of the package\n   * @param constraint A valid semver constraint, example: '1.x || >=2.5.0 || 5.0.0 - 7.2.3'\n   */\n  public async getVersion(packageName: string, constraint?: string): Promise<string> {\n    let current: string | undefined;\n\n    if (packageName in storybookPackagesVersions) {\n      current = storybookPackagesVersions[packageName as StorybookPackage];\n    }\n\n    let latest;\n    try {\n      latest = await this.latestVersion(packageName, constraint);\n      if (!latest) {\n        throw new Error(`No version found for ${packageName}`);\n      }\n    } catch (e) {\n      if (current) {\n        logger.warn(`\\n     ${picocolors.yellow(String(e))}`);\n        return current;\n      }\n\n      logger.error(`\\n     ${picocolors.red(String(e))}`);\n      throw new HandledError(e);\n    }\n\n    const versionToUse =\n      current && (!constraint || satisfies(current, constraint)) && gt(current, latest)\n        ? current\n        : latest;\n    return `^${versionToUse}`;\n  }\n\n  /**\n   * Get the latest version of the package available on npmjs.com. If constraint is set then it\n   * returns a version satisfying it, otherwise the latest version available is returned.\n   *\n   * @param packageName Name of the package\n   * @param constraint Version range to use to constraint the returned version\n   */\n  public async latestVersion(packageName: string, constraint?: string): Promise<string | null> {\n    // Create cache key that includes both package name and constraint\n    const cacheKey = constraint ? `${packageName}@${constraint}` : packageName;\n\n    // Check cache first\n    const cachedVersion = JsPackageManager.latestVersionCache.get(cacheKey);\n    if (cachedVersion) {\n      logger.debug(`Using cached version for ${packageName}...`);\n      return cachedVersion;\n    }\n\n    let result: string;\n\n    logger.debug(`Getting CLI versions from NPM for ${packageName}...`);\n    try {\n      if (!constraint) {\n        result = await this.runGetVersions(packageName, false);\n      } else {\n        const versions = await this.runGetVersions(packageName, true);\n\n        const latestVersionSatisfyingTheConstraint = versions\n          .reverse()\n          .find((version) => satisfies(version, constraint));\n\n        invariant(\n          latestVersionSatisfyingTheConstraint != null,\n          `No version satisfying the constraint: ${packageName}${constraint}`\n        );\n        result = latestVersionSatisfyingTheConstraint;\n      }\n\n      // Cache the result before returning\n      JsPackageManager.latestVersionCache.set(cacheKey, result);\n      return result;\n    } catch (e) {\n      JsPackageManager.latestVersionCache.set(cacheKey, null);\n      return null;\n    }\n  }\n\n  /**\n   * Clear the latest version cache. Useful for testing or when you want to refresh version\n   * information.\n   *\n   * @param packageName Optional package name to clear only specific entries. If not provided,\n   *   clears all cache.\n   */\n  public static clearLatestVersionCache(packageName?: string): void {\n    if (packageName) {\n      // Clear all cache entries for this package (both with and without constraints)\n      const keysToDelete = Array.from(JsPackageManager.latestVersionCache.keys()).filter(\n        (key) => key === packageName || key.startsWith(`${packageName}@`)\n      );\n      keysToDelete.forEach((key) => JsPackageManager.latestVersionCache.delete(key));\n    } else {\n      // Clear all cache\n      JsPackageManager.latestVersionCache.clear();\n    }\n  }\n\n  /**\n   * Clear the installed version cache for a specific package or all packages.\n   *\n   * @param packageName Optional package name to clear from cache. If not provided, clears all.\n   */\n  public clearInstalledVersionCache(packageName?: string): void {\n    if (packageName) {\n      // Clear all cache entries for this package across all working directories\n      const keysToDelete = Array.from(JsPackageManager.installedVersionCache.keys()).filter((key) =>\n        key.endsWith(`::${packageName}`)\n      );\n      keysToDelete.forEach((key) => JsPackageManager.installedVersionCache.delete(key));\n    } else {\n      JsPackageManager.installedVersionCache.clear();\n    }\n  }\n\n  /**\n   * Clear both the latest version cache and installed version cache. This should be called after\n   * any operation that modifies dependencies.\n   */\n  public clearAllVersionCaches(): void {\n    JsPackageManager.clearLatestVersionCache();\n    this.clearInstalledVersionCache();\n  }\n\n  public addStorybookCommandInScripts(options?: { port: number; preCommand?: string }) {\n    const sbPort = options?.port ?? 6006;\n    const storybookCmd = `storybook dev -p ${sbPort}`;\n    const buildStorybookCmd = `storybook build`;\n\n    const preCommand = options?.preCommand ? this.getRunCommand(options.preCommand) : undefined;\n\n    this.addScripts({\n      storybook: [preCommand, storybookCmd].filter(Boolean).join(' && '),\n      'build-storybook': [preCommand, buildStorybookCmd].filter(Boolean).join(' && '),\n    });\n  }\n\n  public addScripts(scripts: Record<string, string>) {\n    const { operationDir, packageJson } = this.#getPrimaryPackageJson();\n\n    this.writePackageJson(\n      {\n        ...packageJson,\n        scripts: {\n          ...packageJson.scripts,\n          ...scripts,\n        },\n      },\n      operationDir\n    );\n  }\n\n  public addPackageResolutions(versions: Record<string, string>) {\n    const { operationDir, packageJson } = this.#getPrimaryPackageJson();\n\n    const resolutions = this.getResolutions(packageJson, versions);\n    this.writePackageJson({ ...packageJson, ...resolutions }, operationDir);\n  }\n  protected abstract runInstall(options?: { force?: boolean }): ResultPromise;\n\n  protected abstract runAddDeps(\n    dependencies: string[],\n    installAsDevDependencies: boolean,\n    writeOutputToFile?: boolean\n  ): ResultPromise;\n\n  protected abstract getResolutions(\n    packageJson: PackageJson,\n    versions: Record<string, string>\n  ): Record<string, any>;\n\n  /**\n   * Get the latest or all versions of the input package available on npmjs.com\n   *\n   * @param packageName Name of the package\n   * @param fetchAllVersions Should return\n   */\n  protected abstract runGetVersions<T extends boolean>(\n    packageName: string,\n    fetchAllVersions: T\n  ): // Use generic and conditional type to force `string[]` if fetchAllVersions is true and `string` if false\n  Promise<T extends true ? string[] : string>;\n\n  public abstract getRegistryURL(): Promise<string | undefined>;\n\n  public abstract runInternalCommand(\n    command: string,\n    args: string[],\n    cwd?: string,\n    stdio?: 'inherit' | 'pipe' | 'ignore'\n  ): ResultPromise;\n  public abstract runPackageCommand(\n    options: Omit<ExecuteCommandOptions, 'command'> & { args: string[]; useRemotePkg?: boolean }\n  ): ResultPromise;\n  public abstract findInstallations(pattern?: string[]): Promise<InstallationMetadata | undefined>;\n  public abstract findInstallations(\n    pattern?: string[],\n    options?: { depth: number }\n  ): Promise<InstallationMetadata | undefined>;\n  public abstract parseErrorFromLogs(logs?: string): string;\n\n  // TODO: Remove pnp compatibility code in SB11\n  /** Returns the installed (within node_modules or pnp zip) version of a specified package */\n  public async getInstalledVersion(packageName: string): Promise<string | null> {\n    const cacheKey = packageName;\n\n    try {\n      // Create cache key that includes both working directory and package name for isolation\n\n      // Check cache first\n      const cachedVersion = JsPackageManager.installedVersionCache.get(cacheKey);\n      if (cachedVersion !== undefined) {\n        logger.debug(`Using cached installed version for ${packageName}...`);\n        return cachedVersion;\n      }\n\n      logger.debug(`Getting installed version for ${packageName}...`);\n      const installations = await this.findInstallations([packageName]);\n      if (!installations) {\n        logger.debug(`No installations found for ${packageName}`);\n        // Cache the null result\n        JsPackageManager.installedVersionCache.set(cacheKey, null);\n        return null;\n      }\n\n      const version = Object.entries(installations.dependencies)[0]?.[1]?.[0].version || null;\n\n      const coercedVersion = coerce(version, { includePrerelease: true })?.toString() ?? version;\n\n      logger.debug(`Installed version for ${packageName}: ${coercedVersion}`);\n      // Cache the result\n      JsPackageManager.installedVersionCache.set(cacheKey, coercedVersion);\n\n      return coercedVersion;\n    } catch (e) {\n      logger.error(`Error getting installed version for ${packageName}: ${String(e)}`);\n      JsPackageManager.installedVersionCache.set(cacheKey, null);\n      return null;\n    }\n  }\n\n  public async isPackageInstalled(packageName: string): Promise<boolean> {\n    const version = await this.getInstalledVersion(packageName);\n    return version !== null;\n  }\n\n  /**\n   * Searches for a dependency/devDependency in all package.json files and returns the version of\n   * the dependency.\n   */\n  public getDependencyVersion(dependency: string): string | null {\n    logger.debug(`Getting dependency version for ${dependency}...`);\n    const dependencyVersion = this.packageJsonPaths\n      .map((path) => {\n        const packageJson = JsPackageManager.getPackageJson(path);\n        return packageJson.dependencies?.[dependency] ?? packageJson.devDependencies?.[dependency];\n      })\n      .filter(Boolean);\n    return dependencyVersion[0] ?? null;\n  }\n\n  // Helper to read and check a package.json for storybook dependency\n  static hasStorybookDependency(packageJsonPath: string): boolean {\n    try {\n      const content = readFileSync(packageJsonPath, 'utf-8');\n      const packageJson = JSON.parse(content) as PackageJsonWithDepsAndDevDeps;\n      return !!(\n        (packageJson.dependencies && packageJson.dependencies.storybook) ||\n        (packageJson.devDependencies && packageJson.devDependencies.storybook)\n      );\n    } catch (error) {\n      return false; // If file doesn't exist or is unreadable, or JSON is invalid\n    }\n  }\n\n  // Helper to read and check a package.json for storybook dependency\n  static hasAnyStorybookDependency(packageJsonPath: string): boolean {\n    try {\n      const content = readFileSync(packageJsonPath, 'utf-8');\n      const packageJson = JSON.parse(content) as PackageJsonWithDepsAndDevDeps;\n      const allDeps = {\n        ...packageJson.dependencies,\n        ...packageJson.devDependencies,\n      };\n\n      return Object.keys(allDeps).some((dep) => dep.includes('storybook'));\n    } catch (error) {\n      return false; // If file doesn't exist or is unreadable, or JSON is invalid\n    }\n  }\n\n  /**\n   * Find the primary package.json file in the project root. The primary package.json file is the\n   * one that contains the `storybook` dependency. If no primary package.json file is found, the\n   * function will return the package.json file in the project root.\n   */\n  #findPrimaryPackageJsonPath(): string {\n    for (const packageJsonPath of this.packageJsonPaths) {\n      const hasStorybook = JsPackageManager.hasStorybookDependency(packageJsonPath);\n      if (hasStorybook) {\n        return packageJsonPath;\n      }\n    }\n\n    // Fall back to cwd package.json\n    return this.packageJsonPaths[0] ?? resolve(this.cwd, 'package.json');\n  }\n\n  /** List all package.json files starting from the given directory and stopping at the project root. */\n  static listAllPackageJsonPaths(instanceDir: string, storiesPaths?: string[]): string[] {\n    const packageJsonPaths = findFilesUp(['package.json'], instanceDir);\n\n    if (!storiesPaths) {\n      return packageJsonPaths;\n    }\n\n    // 1. Find all package.json files starting from the project root\n    const projectRoot = getProjectRoot();\n    const allPackageJsonFiles = globSync('**/package.json', {\n      cwd: projectRoot,\n      absolute: true,\n      ignore: ['**/node_modules/**', '**/dist/**'],\n    });\n\n    // 2. Only keep the ones that are parents of at least one of the storiesPaths\n    const relevantPackageJsons = allPackageJsonFiles.filter((packageJsonPath) => {\n      const packageDir = dirname(packageJsonPath);\n      return storiesPaths.some((storyPath) => storyPath.startsWith(packageDir));\n    });\n\n    // 3. Return the list of package.json paths\n    return Array.from(new Set([...packageJsonPaths, ...relevantPackageJsons]));\n  }\n\n  /**\n   * Get the primary package.json file and its operation directory. The primary package.json file is\n   * the one that contains the storybook dependency. If the primary package.json file is not found,\n   * the function returns information about thepackage.json file in the current working directory.\n   */\n  #getPrimaryPackageJson(): {\n    packageJsonPath: string;\n    operationDir: string;\n    packageJson: PackageJsonWithDepsAndDevDeps;\n  } {\n    const finalTargetPackageJsonPath = this.#findPrimaryPackageJsonPath();\n\n    return JsPackageManager.getPackageJsonInfo(finalTargetPackageJsonPath);\n  }\n\n  static getPackageJsonInfo(packageJsonPath: string): PackageJsonInfo {\n    logger.debug(`Getting package.json info for ${packageJsonPath}...`);\n    const operationDir = dirname(packageJsonPath);\n    return {\n      packageJsonPath,\n      operationDir,\n      get packageJson() {\n        return JsPackageManager.getPackageJson(packageJsonPath);\n      },\n    };\n  }\n}\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/JsPackageManagerFactory.test.ts",
    "content": "import { join } from 'node:path';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport * as find from 'empathic/find';\n\nimport { PackageManagerName } from './index.ts';\nimport { executeCommandSync } from '../utils/command.ts';\nimport { BUNProxy } from './BUNProxy.ts';\nimport { JsPackageManagerFactory } from './JsPackageManagerFactory.ts';\nimport { NPMProxy } from './NPMProxy.ts';\nimport { PNPMProxy } from './PNPMProxy.ts';\nimport { Yarn1Proxy } from './Yarn1Proxy.ts';\nimport { Yarn2Proxy } from './Yarn2Proxy.ts';\n\nvi.mock('../utils/command', { spy: true });\nconst executeCommandSyncMock = vi.mocked(executeCommandSync);\n\nvi.mock('empathic/find');\nconst findMock = vi.mocked(find);\n\ndescribe('CLASS: JsPackageManagerFactory', () => {\n  beforeEach(() => {\n    JsPackageManagerFactory.clearCache();\n    findMock.up.mockReturnValue(undefined);\n    findMock.any.mockReturnValue(undefined);\n    executeCommandSyncMock.mockImplementation(() => {\n      throw new Error('Command not found');\n    });\n    delete process.env.npm_config_user_agent;\n  });\n\n  describe('METHOD: getPackageManager', () => {\n    describe('NPM proxy', () => {\n      it('FORCE: it should return a NPM proxy when `force` option is `npm`', () => {\n        expect(\n          JsPackageManagerFactory.getPackageManager({ force: PackageManagerName.NPM })\n        ).toBeInstanceOf(NPMProxy);\n      });\n\n      it('USER AGENT: it should infer npm from the user agent', () => {\n        process.env.npm_config_user_agent = 'npm/7.24.0';\n        expect(JsPackageManagerFactory.getPackageManager()).toBeInstanceOf(NPMProxy);\n      });\n\n      it('ALL EXIST: when all package managers are ok, but only a `package-lock.json` file is found', () => {\n        executeCommandSyncMock.mockImplementation((options) => {\n          // Yarn is ok\n          if (options.command === 'yarn' && options.args?.[0] === '--version') {\n            return '1.22.4';\n          }\n          // NPM is ok\n          if (options.command === 'npm' && options.args?.[0] === '--version') {\n            return '6.5.12';\n          }\n          // PNPM is ok\n          if (options.command === 'pnpm' && options.args?.[0] === '--version') {\n            return '7.9.5';\n          }\n          // Unknown package manager is ko\n          throw new Error('Command not found');\n        });\n\n        // There is only a package-lock.json\n        findMock.up.mockImplementation((filename) => {\n          if (typeof filename === 'string' && filename === 'package-lock.json') {\n            return '/Users/johndoe/Documents/package-lock.json';\n          }\n          return undefined;\n        });\n\n        expect(JsPackageManagerFactory.getPackageManager()).toBeInstanceOf(NPMProxy);\n      });\n    });\n\n    describe('PNPM proxy', () => {\n      it('FORCE: it should return a PNPM proxy when `force` option is `pnpm`', () => {\n        expect(\n          JsPackageManagerFactory.getPackageManager({ force: PackageManagerName.PNPM })\n        ).toBeInstanceOf(PNPMProxy);\n      });\n\n      it('USER AGENT: it should infer pnpm from the user agent', () => {\n        process.env.npm_config_user_agent = 'pnpm/7.4.0';\n        expect(JsPackageManagerFactory.getPackageManager()).toBeInstanceOf(PNPMProxy);\n      });\n\n      it('ALL EXIST: when all package managers are ok, but only a `pnpm-lock.yaml` file is found', () => {\n        executeCommandSyncMock.mockImplementation((options) => {\n          // Yarn is ok\n          if (options.command === 'yarn' && options.args?.[0] === '--version') {\n            return '1.22.4';\n          }\n          // NPM is ok\n          if (options.command === 'npm' && options.args?.[0] === '--version') {\n            return '6.5.12';\n          }\n          // PNPM is ok\n          if (options.command === 'pnpm' && options.args?.[0] === '--version') {\n            return '7.9.5';\n          }\n          // Unknown package manager is ko\n          throw new Error('Command not found');\n        });\n\n        // There is only a pnpm-lock.yaml\n        findMock.up.mockImplementation((filename) => {\n          if (typeof filename === 'string' && filename === 'pnpm-lock.yaml') {\n            return '/Users/johndoe/Documents/pnpm-lock.yaml';\n          }\n          return undefined;\n        });\n\n        expect(JsPackageManagerFactory.getPackageManager()).toBeInstanceOf(PNPMProxy);\n      });\n\n      it('PNPM LOCK IF CLOSER: when a pnpm-lock.yaml file is closer than a yarn.lock', async () => {\n        // Allow find to work as normal, we'll set the cwd to our fixture package\n        findMock.up.mockImplementation(\n          (await vi.importActual<typeof import('empathic/find')>('empathic/find')).up\n        );\n\n        executeCommandSyncMock.mockImplementation((options) => {\n          // Yarn is ok\n          if (options.command === 'yarn' && options.args?.[0] === '--version') {\n            return '1.22.4';\n          }\n          // NPM is ok\n          if (options.command === 'npm' && options.args?.[0] === '--version') {\n            return '6.5.12';\n          }\n          // PNPM is ok\n          if (options.command === 'pnpm' && options.args?.[0] === '--version') {\n            return '7.9.5';\n          }\n          // Unknown package manager is ko\n          throw new Error('Command not found');\n        });\n        const fixture = join(__dirname, 'fixtures', 'pnpm-workspace', 'package');\n        expect(JsPackageManagerFactory.getPackageManager({}, fixture)).toBeInstanceOf(PNPMProxy);\n      });\n    });\n\n    describe('Yarn 1 proxy', () => {\n      it('FORCE: it should return a Yarn1 proxy when `force` option is `yarn1`', () => {\n        expect(\n          JsPackageManagerFactory.getPackageManager({ force: PackageManagerName.YARN1 })\n        ).toBeInstanceOf(Yarn1Proxy);\n      });\n\n      it('USER AGENT: it should infer yarn1 from the user agent', () => {\n        process.env.npm_config_user_agent = 'yarn/1.22.11';\n        expect(JsPackageManagerFactory.getPackageManager()).toBeInstanceOf(Yarn1Proxy);\n      });\n\n      it('when Yarn command is ok and a yarn.lock file is found', () => {\n        executeCommandSyncMock.mockImplementation((options) => {\n          // Yarn is ok\n          if (options.command === 'yarn' && options.args?.[0] === '--version') {\n            return '1.22.4';\n          }\n          // NPM is ko\n          if (options.command === 'npm' && options.args?.[0] === '--version') {\n            throw new Error('Command not found');\n          }\n          // PNPM is ko\n          if (options.command === 'pnpm' && options.args?.[0] === '--version') {\n            throw new Error('Command not found');\n          }\n          // Unknown package manager is ko\n          throw new Error('Command not found');\n        });\n\n        // there is a yarn.lock file\n        findMock.up.mockImplementation((filename) => {\n          if (typeof filename === 'string' && filename === 'yarn.lock') {\n            return '/Users/johndoe/Documents/yarn.lock';\n          }\n          return undefined;\n        });\n\n        expect(JsPackageManagerFactory.getPackageManager()).toBeInstanceOf(Yarn1Proxy);\n      });\n\n      it('when Yarn command is ok, Yarn version is <2, NPM and PNPM are ok, there is a `yarn.lock` file', () => {\n        executeCommandSyncMock.mockImplementation((options) => {\n          // Yarn is ok\n          if (options.command === 'yarn' && options.args?.[0] === '--version') {\n            return '1.22.4';\n          }\n          // NPM is ok\n          if (options.command === 'npm' && options.args?.[0] === '--version') {\n            return '6.5.12';\n          }\n          // PNPM is ok\n          if (options.command === 'pnpm' && options.args?.[0] === '--version') {\n            return '7.9.5';\n          }\n          // Unknown package manager is ko\n          throw new Error('Command not found');\n        });\n\n        // There is a yarn.lock\n        findMock.up.mockImplementation((filename) => {\n          if (typeof filename === 'string' && filename === 'yarn.lock') {\n            return '/Users/johndoe/Documents/yarn.lock';\n          }\n          return undefined;\n        });\n\n        expect(JsPackageManagerFactory.getPackageManager()).toBeInstanceOf(Yarn1Proxy);\n      });\n\n      it('when multiple lockfiles are in a project, prefers yarn', async () => {\n        // Allow find to work as normal, we'll set the cwd to our fixture package\n        findMock.up.mockImplementation(\n          (await vi.importActual<typeof import('empathic/find')>('empathic/find')).up\n        );\n\n        executeCommandSyncMock.mockImplementation((options) => {\n          // Yarn is ok\n          if (options.command === 'yarn' && options.args?.[0] === '--version') {\n            return '1.22.4';\n          }\n          // NPM is ok\n          if (options.command === 'npm' && options.args?.[0] === '--version') {\n            return '6.5.12';\n          }\n          // PNPM is ok\n          if (options.command === 'pnpm' && options.args?.[0] === '--version') {\n            return '7.9.5';\n          }\n          // Unknown package manager is ko\n          throw new Error('Command not found');\n        });\n        const fixture = join(__dirname, 'fixtures', 'multiple-lockfiles');\n        expect(JsPackageManagerFactory.getPackageManager({}, fixture)).toBeInstanceOf(Yarn1Proxy);\n      });\n    });\n\n    describe('Yarn 2 proxy', () => {\n      it('FORCE: it should return a Yarn2 proxy when `force` option is `yarn2`', () => {\n        expect(\n          JsPackageManagerFactory.getPackageManager({ force: PackageManagerName.YARN2 })\n        ).toBeInstanceOf(Yarn2Proxy);\n      });\n\n      it('USER AGENT: it should infer yarn2 from the user agent', () => {\n        process.env.npm_config_user_agent = 'yarn/2.2.10';\n        expect(JsPackageManagerFactory.getPackageManager()).toBeInstanceOf(Yarn2Proxy);\n      });\n\n      it('ONLY YARN 2: when Yarn command is ok, Yarn version is >=2, NPM is ko, PNPM is ko, and a yarn.lock file is found', () => {\n        executeCommandSyncMock.mockImplementation((options) => {\n          // Yarn is ok\n          if (options.command === 'yarn' && options.args?.[0] === '--version') {\n            return '2.0.0-rc.33';\n          }\n          // NPM is ko\n          if (options.command === 'npm' && options.args?.[0] === '--version') {\n            throw new Error('Command not found');\n          }\n          // PNPM is ko\n          if (options.command === 'pnpm' && options.args?.[0] === '--version') {\n            throw new Error('Command not found');\n          }\n          // Unknown package manager is ko\n          throw new Error('Command not found');\n        });\n\n        findMock.up.mockImplementation((filename) => {\n          if (typeof filename === 'string' && filename === 'yarn.lock') {\n            return '/Users/johndoe/Documents/yarn.lock';\n          }\n          return undefined;\n        });\n\n        expect(JsPackageManagerFactory.getPackageManager()).toBeInstanceOf(Yarn2Proxy);\n      });\n\n      it('when Yarn command is ok, Yarn version is >=2, NPM and PNPM are ok, there is a `yarn.lock` file', () => {\n        executeCommandSyncMock.mockImplementation((options) => {\n          // Yarn is ok\n          if (options.command === 'yarn' && options.args?.[0] === '--version') {\n            return '2.0.0-rc.33';\n          }\n          // NPM is ok\n          if (options.command === 'npm' && options.args?.[0] === '--version') {\n            return '6.5.12';\n          }\n          // PNPM is ok\n          if (options.command === 'pnpm' && options.args?.[0] === '--version') {\n            return '7.9.5';\n          }\n          // Unknown package manager is ko\n          throw new Error('Command not found');\n        });\n\n        // There is a yarn.lock\n        findMock.up.mockImplementation((filename) => {\n          if (typeof filename === 'string' && filename === 'yarn.lock') {\n            return '/Users/johndoe/Documents/yarn.lock';\n          }\n          return undefined;\n        });\n\n        expect(JsPackageManagerFactory.getPackageManager()).toBeInstanceOf(Yarn2Proxy);\n      });\n    });\n\n    describe('BUN proxy', () => {\n      it('FORCE: it should return a BUN proxy when `force` option is `bun`', () => {\n        expect(\n          JsPackageManagerFactory.getPackageManager({ force: PackageManagerName.BUN })\n        ).toBeInstanceOf(BUNProxy);\n      });\n\n      it('when Bun command is ok, NPM and PNPM are ok, there is a `bun.lockb` file', () => {\n        executeCommandSyncMock.mockImplementation((options) => {\n          // Bun is ok\n          if (options.command === 'bun' && options.args?.[0] === '--version') {\n            return '1.0.0';\n          }\n          // Yarn is ok\n          if (options.command === 'yarn' && options.args?.[0] === '--version') {\n            return '2.0.0-rc.33';\n          }\n          // NPM is ok\n          if (options.command === 'npm' && options.args?.[0] === '--version') {\n            return '6.5.12';\n          }\n          // PNPM is ok\n          if (options.command === 'pnpm' && options.args?.[0] === '--version') {\n            return '7.9.5';\n          }\n          // Unknown package manager is ko\n          throw new Error('Command not found');\n        });\n\n        // There is a bun.lockb\n        findMock.up.mockImplementation((filename) => {\n          if (typeof filename === 'string' && filename === 'bun.lockb') {\n            return '/Users/johndoe/Documents/bun.lockb';\n          }\n          return undefined;\n        });\n\n        expect(JsPackageManagerFactory.getPackageManager()).toBeInstanceOf(BUNProxy);\n      });\n    });\n\n    it('throws an error if Yarn, NPM, and PNPM are not found', () => {\n      executeCommandSyncMock.mockImplementation(() => {\n        throw new Error('Command not found');\n      });\n      findMock.up.mockReturnValue(undefined);\n      expect(() => JsPackageManagerFactory.getPackageManager()).toThrow();\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/JsPackageManagerFactory.ts",
    "content": "import { basename, parse, relative } from 'node:path';\n\nimport * as find from 'empathic/find';\n\nimport { executeCommandSync } from '../utils/command.ts';\nimport { getProjectRoot } from '../utils/paths.ts';\nimport { BUNProxy } from './BUNProxy.ts';\nimport type { JsPackageManager } from './JsPackageManager.ts';\nimport { PackageManagerName } from './JsPackageManager.ts';\nimport { NPMProxy } from './NPMProxy.ts';\nimport { PNPMProxy } from './PNPMProxy.ts';\nimport { Yarn1Proxy } from './Yarn1Proxy.ts';\nimport { Yarn2Proxy } from './Yarn2Proxy.ts';\nimport {\n  BUN_LOCKFILE,\n  BUN_LOCKFILE_BINARY,\n  NPM_LOCKFILE,\n  PNPM_LOCKFILE,\n  YARN_LOCKFILE,\n} from './constants.ts';\n\ntype PackageManagerProxy =\n  | typeof NPMProxy\n  | typeof PNPMProxy\n  | typeof Yarn1Proxy\n  | typeof Yarn2Proxy\n  | typeof BUNProxy;\n\nexport class JsPackageManagerFactory {\n  /** Cache for package manager instances */\n  private static cache = new Map<string, JsPackageManager>();\n\n  /** Generate a cache key based on the parameters */\n  private static getCacheKey(\n    force?: PackageManagerName,\n    configDir = '.storybook',\n    cwd = process.cwd(),\n    storiesPaths?: string[]\n  ): string {\n    return JSON.stringify({ force: force || null, configDir, cwd, storiesPaths });\n  }\n\n  /** Clear the package manager cache */\n  public static clearCache(): void {\n    this.cache.clear();\n  }\n\n  /**\n   * Determine which package manager type to use based on lockfiles, commands, and environment\n   *\n   * @param cwd - Current working directory\n   * @returns Package manager type as string: 'npm', 'pnpm', 'bun', 'yarn1', or 'yarn2'\n   * @throws Error if no usable package manager is found\n   */\n  public static getPackageManagerType(cwd = process.cwd()): PackageManagerName {\n    const root = getProjectRoot();\n\n    const lockFiles = [\n      find.up(YARN_LOCKFILE, { cwd, last: root }),\n      find.up(PNPM_LOCKFILE, { cwd, last: root }),\n      find.up(NPM_LOCKFILE, { cwd, last: root }),\n      find.up(BUN_LOCKFILE, { cwd, last: root }),\n      find.up(BUN_LOCKFILE_BINARY, { cwd, last: root }),\n    ]\n      .filter(Boolean)\n      .sort((a, b) => {\n        const dirA = parse(a as string).dir;\n        const dirB = parse(b as string).dir;\n\n        const compare = relative(dirA, dirB);\n\n        if (dirA === dirB) {\n          return 0;\n        }\n\n        if (compare.startsWith('..')) {\n          return -1;\n        }\n\n        return 1;\n      });\n\n    // Option 1: We try to infer the package manager from the closest lockfile\n    const closestLockfilePath = lockFiles[0];\n    const closestLockfile = closestLockfilePath && basename(closestLockfilePath);\n\n    const yarnVersion = getYarnVersion(cwd);\n\n    if (yarnVersion && closestLockfile === YARN_LOCKFILE) {\n      return yarnVersion === 1 ? PackageManagerName.YARN1 : PackageManagerName.YARN2;\n    }\n\n    if (hasPNPM(cwd) && closestLockfile === PNPM_LOCKFILE) {\n      return PackageManagerName.PNPM;\n    }\n\n    const isNPMCommandOk = hasNPM(cwd);\n\n    if (isNPMCommandOk && closestLockfile === NPM_LOCKFILE) {\n      return PackageManagerName.NPM;\n    }\n\n    if (\n      hasBun(cwd) &&\n      (closestLockfile === BUN_LOCKFILE || closestLockfile === BUN_LOCKFILE_BINARY)\n    ) {\n      return PackageManagerName.BUN;\n    }\n\n    // Option 2: If the user is running a command via npx/pnpx/yarn create/etc, we infer the package manager from the command\n    const inferredPackageManager = this.inferPackageManagerFromUserAgent();\n    if (inferredPackageManager && inferredPackageManager in this.PROXY_MAP) {\n      return inferredPackageManager;\n    }\n\n    // Default fallback, whenever users try to use something different than NPM, PNPM, Yarn,\n    // but still have NPM installed\n    if (isNPMCommandOk) {\n      return PackageManagerName.NPM;\n    }\n\n    throw new Error('Unable to find a usable package manager within NPM, PNPM, Yarn and Yarn 2');\n  }\n\n  public static getPackageManager(\n    {\n      force,\n      configDir = '.storybook',\n      storiesPaths,\n      ignoreCache = false,\n    }: {\n      force?: PackageManagerName;\n      configDir?: string;\n      storiesPaths?: string[];\n      ignoreCache?: boolean;\n    } = {},\n    cwd = process.cwd()\n  ): JsPackageManager {\n    // Check cache first, unless ignored\n    const cacheKey = this.getCacheKey(force, configDir, cwd, storiesPaths);\n    const cached = this.cache.get(cacheKey);\n    if (cached && !ignoreCache) {\n      return cached;\n    }\n\n    // Option 1: If the user has provided a forcing flag, we use it\n    if (force && force in this.PROXY_MAP) {\n      const packageManager = new this.PROXY_MAP[force]({\n        cwd,\n        configDir,\n        storiesPaths,\n      });\n      this.cache.set(cacheKey, packageManager as unknown as JsPackageManager);\n      return packageManager as unknown as JsPackageManager;\n    }\n\n    // Option 2: Detect package managers based on some heuristics\n    const packageManagerType = this.getPackageManagerType(cwd);\n    const packageManager = new this.PROXY_MAP[packageManagerType]({ cwd, configDir, storiesPaths });\n    this.cache.set(cacheKey, packageManager as unknown as JsPackageManager);\n    return packageManager as unknown as JsPackageManager;\n  }\n\n  /** Look up map of package manager proxies by name */\n  private static PROXY_MAP: Record<PackageManagerName, PackageManagerProxy> = {\n    [PackageManagerName.NPM]: NPMProxy,\n    [PackageManagerName.PNPM]: PNPMProxy,\n    [PackageManagerName.YARN1]: Yarn1Proxy,\n    [PackageManagerName.YARN2]: Yarn2Proxy,\n    [PackageManagerName.BUN]: BUNProxy,\n  };\n\n  /**\n   * Infer the package manager based on the command the user is running. Each package manager sets\n   * the `npm_config_user_agent` environment variable with its name and version e.g. \"npm/7.24.0\"\n   * Which is really useful when invoking commands via npx/pnpx/yarn create/etc.\n   */\n  private static inferPackageManagerFromUserAgent(): PackageManagerName | undefined {\n    const userAgent = process.env.npm_config_user_agent;\n    if (userAgent) {\n      const packageSpec = userAgent.split(' ')[0];\n      const [pkgMgrName, pkgMgrVersion] = packageSpec.split('/');\n\n      if (pkgMgrName === 'pnpm') {\n        return PackageManagerName.PNPM;\n      }\n\n      if (pkgMgrName === 'npm') {\n        return PackageManagerName.NPM;\n      }\n\n      if (pkgMgrName === 'yarn') {\n        return pkgMgrVersion?.startsWith('1.')\n          ? PackageManagerName.YARN1\n          : PackageManagerName.YARN2;\n      }\n    }\n\n    return undefined;\n  }\n}\n\nfunction hasNPM(cwd?: string) {\n  try {\n    executeCommandSync({\n      command: 'npm',\n      args: ['--version'],\n      cwd,\n      env: Object.fromEntries(\n        Object.entries(process.env).filter(([, value]) => value !== undefined)\n      ) as Record<string, string>,\n    });\n    return true;\n  } catch (err) {\n    return false;\n  }\n}\n\nfunction hasBun(cwd?: string) {\n  try {\n    executeCommandSync({\n      command: 'bun',\n      args: ['--version'],\n      cwd,\n      env: Object.fromEntries(\n        Object.entries(process.env).filter(([, value]) => value !== undefined)\n      ) as Record<string, string>,\n    });\n    return true;\n  } catch (err) {\n    return false;\n  }\n}\n\nfunction hasPNPM(cwd?: string) {\n  try {\n    executeCommandSync({\n      command: 'pnpm',\n      args: ['--version'],\n      cwd,\n      env: Object.fromEntries(\n        Object.entries(process.env).filter(([, value]) => value !== undefined)\n      ) as Record<string, string>,\n    });\n\n    return true;\n  } catch (err) {\n    return false;\n  }\n}\n\nfunction getYarnVersion(cwd?: string): 1 | 2 | undefined {\n  try {\n    const yarnVersion = executeCommandSync({\n      command: 'yarn',\n      args: ['--version'],\n      cwd,\n      env: Object.fromEntries(\n        Object.entries(process.env).filter(([, value]) => value !== undefined)\n      ) as Record<string, string>,\n    });\n    return /^1\\.+/.test(yarnVersion.trim()) ? 1 : 2;\n  } catch (err) {\n    return undefined;\n  }\n}\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/NPMProxy.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { prompt } from 'storybook/internal/node-logger';\n\nimport { executeCommand } from '../utils/command.ts';\nimport { JsPackageManager } from './JsPackageManager.ts';\nimport { NPMProxy } from './NPMProxy.ts';\n\nvi.mock('storybook/internal/node-logger', () => ({\n  prompt: {\n    executeTaskWithSpinner: vi.fn(),\n    getPreferredStdio: vi.fn(() => 'inherit'),\n  },\n  logger: {\n    debug: vi.fn(),\n    warn: vi.fn(),\n    error: vi.fn(),\n  },\n}));\n\nvi.mock(import('../utils/command.ts'), { spy: true });\n\nconst mockedExecuteCommand = vi.mocked(executeCommand);\n\ndescribe('NPM Proxy', () => {\n  let npmProxy: NPMProxy;\n\n  beforeEach(() => {\n    npmProxy = new NPMProxy();\n    JsPackageManager.clearLatestVersionCache();\n    vi.spyOn(npmProxy, 'writePackageJson').mockImplementation(vi.fn());\n  });\n\n  it('type should be npm', () => {\n    expect(npmProxy.type).toEqual('npm');\n  });\n\n  describe('installDependencies', () => {\n    describe('npm6', () => {\n      it('should run `npm install`', async () => {\n        // sort of un-mock part of the function so executeCommand (also mocked) is called\n        vi.mocked(prompt.executeTaskWithSpinner).mockImplementationOnce(async (fn: any) => {\n          await Promise.resolve(fn());\n        });\n        const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({\n          stdout: '6.0.0',\n        } as any);\n\n        await npmProxy.installDependencies();\n\n        expect(executeCommandSpy).toHaveBeenCalledWith(\n          expect.objectContaining({ command: 'npm', args: ['install'] })\n        );\n      });\n    });\n    describe('npm7', () => {\n      it('should run `npm install`', async () => {\n        // sort of un-mock part of the function so executeCommand (also mocked) is called\n        vi.mocked(prompt.executeTaskWithSpinner).mockImplementationOnce(async (fn: any) => {\n          await Promise.resolve(fn());\n        });\n        const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({\n          stdout: '7.1.0',\n        } as any);\n\n        await npmProxy.installDependencies();\n\n        expect(executeCommandSpy).toHaveBeenCalledWith(\n          expect.objectContaining({ command: 'npm', args: ['install'] })\n        );\n      });\n    });\n  });\n\n  describe('runScript', () => {\n    describe('npm6', () => {\n      it('should execute script `npm exec -- compodoc -e json -d .`', () => {\n        const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({\n          stdout: '6.0.0',\n        } as any);\n\n        npmProxy.runPackageCommand({\n          args: ['compodoc', '-e', 'json', '-d', '.'],\n        });\n\n        expect(executeCommandSpy).toHaveBeenCalledWith(\n          expect.objectContaining({\n            command: 'npx',\n            args: ['compodoc', '-e', 'json', '-d', '.'],\n          })\n        );\n      });\n    });\n    describe('npm7', () => {\n      it('should execute script `npm run compodoc -- -e json -d .`', () => {\n        const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({\n          stdout: '7.1.0',\n        } as any);\n\n        npmProxy.runPackageCommand({\n          args: ['compodoc', '-e', 'json', '-d', '.'],\n        });\n\n        expect(executeCommandSpy).toHaveBeenCalledWith(\n          expect.objectContaining({\n            command: 'npx',\n            args: ['compodoc', '-e', 'json', '-d', '.'],\n          })\n        );\n      });\n    });\n  });\n\n  describe('addDependencies', () => {\n    describe('npm6', () => {\n      it('with devDep it should run `npm install -D storybook`', async () => {\n        const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({\n          stdout: '6.0.0',\n        } as any);\n\n        await npmProxy.addDependencies({ type: 'devDependencies' }, ['storybook']);\n\n        expect(executeCommandSpy).toHaveBeenCalledWith(\n          expect.objectContaining({\n            command: 'npm',\n            args: ['install', '-D', 'storybook'],\n          })\n        );\n      });\n    });\n    describe('npm7', () => {\n      it('with devDep it should run `npm install -D storybook`', async () => {\n        const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({\n          stdout: '7.0.0',\n        } as any);\n\n        await npmProxy.addDependencies({ type: 'devDependencies' }, ['storybook']);\n\n        expect(executeCommandSpy).toHaveBeenCalledWith(\n          expect.objectContaining({\n            command: 'npm',\n            args: ['install', '-D', 'storybook'],\n          })\n        );\n      });\n    });\n  });\n\n  describe('removeDependencies', () => {\n    describe('skipInstall', () => {\n      it('should only change package.json without running install', async () => {\n        const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({\n          stdout: '7.0.0',\n        } as any);\n\n        vi.spyOn(npmProxy, 'packageJsonPaths', 'get').mockImplementation(() => ['package.json']);\n\n        const writePackageSpy = vi.spyOn(npmProxy, 'writePackageJson').mockImplementation(vi.fn());\n        vi.spyOn(JsPackageManager, 'getPackageJson').mockImplementation((args) => {\n          return {\n            dependencies: {},\n            devDependencies: {\n              '@storybook/manager-webpack5': 'x.x.x',\n              '@storybook/react': 'x.x.x',\n            },\n          };\n        });\n\n        await npmProxy.removeDependencies(['@storybook/manager-webpack5']);\n\n        expect(writePackageSpy).toHaveBeenCalledWith(\n          {\n            dependencies: {},\n            devDependencies: {\n              '@storybook/react': 'x.x.x',\n            },\n          },\n          expect.any(String)\n        );\n        expect(executeCommandSpy).not.toHaveBeenCalled();\n      });\n    });\n  });\n\n  describe('latestVersion', () => {\n    it('without constraint it returns the latest version', async () => {\n      const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({ stdout: '5.3.19' } as any);\n\n      const version = await npmProxy.latestVersion('storybook');\n\n      expect(executeCommandSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          command: 'npm',\n          args: ['info', 'storybook', 'version'],\n        })\n      );\n      expect(version).toEqual('5.3.19');\n    });\n\n    it('with constraint it returns the latest version satisfying the constraint', async () => {\n      const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({\n        stdout: '[\"4.25.3\",\"5.3.19\",\"6.0.0-beta.23\"]',\n      } as any);\n\n      const version = await npmProxy.latestVersion('storybook', '5.X');\n\n      expect(executeCommandSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          command: 'npm',\n          args: ['info', 'storybook', 'versions', '--json'],\n        })\n      );\n      expect(version).toEqual('5.3.19');\n    });\n\n    it('with constraint it throws an error if command output is not a valid JSON', async () => {\n      mockedExecuteCommand.mockResolvedValue({ stdout: 'NOT A JSON' } as any);\n\n      await expect(npmProxy.latestVersion('storybook', '5.X')).resolves.toBe(null);\n    });\n  });\n\n  describe('getVersion', () => {\n    it('with a Storybook package listed in versions.json it returns the version', async () => {\n      const storybookAngularVersion = (await import('../versions.ts')).default[\n        '@storybook/angular'\n      ];\n      const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({ stdout: '5.3.19' } as any);\n\n      const version = await npmProxy.getVersion('@storybook/angular');\n\n      expect(executeCommandSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          command: 'npm',\n          args: ['info', '@storybook/angular', 'version'],\n        })\n      );\n      expect(version).toEqual(`^${storybookAngularVersion}`);\n    });\n\n    it('with a Storybook package not listed in versions.json it returns the latest version', async () => {\n      const packageVersion = '5.3.19';\n      const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({\n        stdout: `${packageVersion}`,\n      } as any);\n\n      const version = await npmProxy.getVersion('@storybook/react-native');\n\n      expect(executeCommandSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          command: 'npm',\n          args: ['info', '@storybook/react-native', 'version'],\n        })\n      );\n      expect(version).toEqual(`^${packageVersion}`);\n    });\n  });\n\n  describe('addPackageResolutions', () => {\n    it('adds resolutions to package.json and account for existing resolutions', async () => {\n      const writePackageSpy = vi.spyOn(npmProxy, 'writePackageJson').mockImplementation(vi.fn());\n\n      vi.spyOn(JsPackageManager, 'getPackageJson').mockImplementation(() => ({\n        dependencies: {},\n        devDependencies: {},\n        overrides: {\n          bar: 'x.x.x',\n        },\n      }));\n\n      const versions = {\n        foo: 'x.x.x',\n      };\n      npmProxy.addPackageResolutions(versions);\n\n      expect(writePackageSpy).toHaveBeenCalledWith(\n        {\n          dependencies: {},\n          devDependencies: {},\n          overrides: {\n            ...versions,\n            bar: 'x.x.x',\n          },\n        },\n        expect.any(String)\n      );\n    });\n  });\n\n  describe('mapDependencies', () => {\n    it('should display duplicated dependencies based on npm output', async () => {\n      // npm ls --depth 10 --json\n      mockedExecuteCommand.mockResolvedValue({\n        stdout: `\n        {\n          \"dependencies\": {\n            \"unrelated-and-should-be-filtered\": {\n              \"version\": \"1.0.0\"\n            },\n            \"@storybook/package\": {\n              \"version\": \"7.0.0-beta.11\",\n              \"resolved\": \"https://registry.npmjs.org/@storybook/package/-/core-7.0.0-beta.11.tgz\",\n              \"overridden\": false,\n              \"dependencies\": {}\n            },\n            \"@storybook/jest\": {\n              \"version\": \"0.0.11-next.1\",\n              \"resolved\": \"https://registry.npmjs.org/@storybook/jest/-/jest-0.0.11-next.1.tgz\",\n              \"overridden\": false,\n              \"dependencies\": {\n                \"@storybook/package\": {\n                  \"version\": \"7.0.0-alpha.21\"\n                }\n              }\n            },\n            \"@storybook/testing-library\": {\n              \"version\": \"0.0.14-next.1\",\n              \"resolved\": \"https://registry.npmjs.org/@storybook/testing-library/-/testing-library-0.0.14-next.1.tgz\",\n              \"overridden\": false,\n              \"dependencies\": {\n                \"@storybook/package\": {\n                  \"version\": \"5.4.2-alpha.0\"\n                }\n              }\n            }\n          }\n        }      \n      `,\n      } as any);\n\n      const installations = await npmProxy.findInstallations(['@storybook/*']);\n\n      expect(installations).toMatchInlineSnapshot(`\n        {\n          \"dedupeCommand\": \"npm dedupe\",\n          \"dependencies\": {\n            \"@storybook/jest\": [\n              {\n                \"location\": \"\",\n                \"version\": \"0.0.11-next.1\",\n              },\n            ],\n            \"@storybook/package\": [\n              {\n                \"location\": \"\",\n                \"version\": \"7.0.0-beta.11\",\n              },\n              {\n                \"location\": \"\",\n                \"version\": \"7.0.0-alpha.21\",\n              },\n              {\n                \"location\": \"\",\n                \"version\": \"5.4.2-alpha.0\",\n              },\n            ],\n            \"@storybook/testing-library\": [\n              {\n                \"location\": \"\",\n                \"version\": \"0.0.14-next.1\",\n              },\n            ],\n          },\n          \"duplicatedDependencies\": {\n            \"@storybook/package\": [\n              \"5.4.2-alpha.0\",\n              \"7.0.0-alpha.21\",\n              \"7.0.0-beta.11\",\n            ],\n          },\n          \"infoCommand\": \"npm ls --depth=1\",\n        }\n      `);\n    });\n  });\n\n  describe('parseErrors', () => {\n    it('should parse npm errors', () => {\n      const NPM_LEGACY_RESOLVE_ERROR_SAMPLE = `\n        npm ERR!\n        npm ERR! code ERESOLVE\n        npm ERR! ERESOLVE unable to resolve dependency tree\n        npm ERR! \n        npm ERR! While resolving: before-storybook@1.0.0\n        npm ERR! Found: react@undefined\n        npm ERR! node_modules/react\n        npm ERR!   react@\"30\" from the root project\n        `;\n\n      const NPM_RESOLVE_ERROR_SAMPLE = `\n        npm error\n        npm error code ERESOLVE\n        npm error ERESOLVE unable to resolve dependency tree\n        npm error \n        npm error While resolving: before-storybook@1.0.0\n        npm error Found: react@undefined\n        npm error node_modules/react\n        npm error   react@\"30\" from the root project\n        `;\n\n      const NPM_TIMEOUT_ERROR_SAMPLE = `\n          npm notice \n          npm notice New major version of npm available! 8.5.0 -> 9.6.7\n          npm notice Changelog: <https://github.com/npm/cli/releases/tag/v9.6.7>\n          npm notice Run \\`npm install -g npm@9.6.7\\` to update!\n          npm notice \n          npm ERR! code ERR_SOCKET_TIMEOUT\n          npm ERR! errno ERR_SOCKET_TIMEOUT\n          npm ERR! network Invalid response body while trying to fetch https://registry.npmjs.org/@storybook%2ftypes: Socket timeout\n          npm ERR! network This is a problem related to network connectivity.\n      `;\n\n      expect(npmProxy.parseErrorFromLogs(NPM_LEGACY_RESOLVE_ERROR_SAMPLE)).toEqual(\n        'NPM error ERESOLVE - Dependency resolution error.'\n      );\n      expect(npmProxy.parseErrorFromLogs(NPM_RESOLVE_ERROR_SAMPLE)).toEqual(\n        'NPM error ERESOLVE - Dependency resolution error.'\n      );\n      expect(npmProxy.parseErrorFromLogs(NPM_TIMEOUT_ERROR_SAMPLE)).toEqual(\n        'NPM error ERR_SOCKET_TIMEOUT - Socket timed out.'\n      );\n    });\n\n    it('should show unknown npm error', () => {\n      const NPM_ERROR_SAMPLE = `\n        npm ERR! \n        npm ERR! While resolving: before-storybook@1.0.0\n        npm ERR! Found: react@undefined\n        npm ERR! node_modules/react\n        npm ERR!   react@\"30\" from the root project\n      `;\n\n      expect(npmProxy.parseErrorFromLogs(NPM_ERROR_SAMPLE)).toEqual(`NPM error`);\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/NPMProxy.ts",
    "content": "import { readFileSync } from 'node:fs';\nimport { platform } from 'node:os';\nimport { join } from 'node:path';\n\nimport { logger, prompt } from 'storybook/internal/node-logger';\nimport { FindPackageVersionsError } from 'storybook/internal/server-errors';\n\nimport * as find from 'empathic/find';\n// eslint-disable-next-line depend/ban-dependencies\nimport type { ResultPromise } from 'execa';\nimport sort from 'semver/functions/sort.js';\n\nimport type { ExecuteCommandOptions } from '../utils/command.ts';\nimport { executeCommand } from '../utils/command.ts';\nimport { getProjectRoot } from '../utils/paths.ts';\nimport { JsPackageManager, PackageManagerName } from './JsPackageManager.ts';\nimport type { PackageJson } from './PackageJson.ts';\nimport type { InstallationMetadata, PackageMetadata } from './types.ts';\n\ntype NpmDependency = {\n  version: string;\n  resolved?: string;\n  overridden?: boolean;\n  dependencies?: NpmDependencies;\n};\n\ntype NpmDependencies = {\n  [key: string]: NpmDependency;\n};\n\nexport type NpmListOutput = {\n  dependencies: NpmDependencies;\n};\nconst NPM_ERROR_REGEX = /npm (ERR!|error) (code|errno) (\\w+)/i;\n\nconst NPM_ERROR_CODES = {\n  E401: 'Authentication failed or is required.',\n  E403: 'Access to the resource is forbidden.',\n  E404: 'Requested resource not found.',\n  EACCES: 'Permission issue.',\n  EAI_FAIL: 'DNS lookup failed.',\n  EBADENGINE: 'Engine compatibility check failed.',\n  EBADPLATFORM: 'Platform not supported.',\n  ECONNREFUSED: 'Connection refused.',\n  ECONNRESET: 'Connection reset.',\n  EEXIST: 'File or directory already exists.',\n  EINVALIDTYPE: 'Invalid type encountered.',\n  EISGIT: 'Git operation failed or conflicts with an existing file.',\n  EJSONPARSE: 'Error parsing JSON data.',\n  EMISSINGARG: 'Required argument missing.',\n  ENEEDAUTH: 'Authentication needed.',\n  ENOAUDIT: 'No audit available.',\n  ENOENT: 'File or directory does not exist.',\n  ENOGIT: 'Git not found or failed to run.',\n  ENOLOCK: 'Lockfile missing.',\n  ENOSPC: 'Insufficient disk space.',\n  ENOTFOUND: 'Resource not found.',\n  EOTP: 'One-time password required.',\n  EPERM: 'Permission error.',\n  EPUBLISHCONFLICT: 'Conflict during package publishing.',\n  ERESOLVE: 'Dependency resolution error.',\n  EROFS: 'File system is read-only.',\n  ERR_SOCKET_TIMEOUT: 'Socket timed out.',\n  ETARGET: 'Package target not found.',\n  ETIMEDOUT: 'Operation timed out.',\n  ETOOMANYARGS: 'Too many arguments provided.',\n  EUNKNOWNTYPE: 'Unknown type encountered.',\n};\n\nexport class NPMProxy extends JsPackageManager {\n  readonly type = PackageManagerName.NPM;\n\n  installArgs: string[] | undefined;\n\n  getRunCommand(command: string): string {\n    return `npm run ${command}`;\n  }\n\n  async getModulePackageJSON(packageName: string): Promise<PackageJson | null> {\n    const wantedPath = join('node_modules', packageName, 'package.json');\n    const packageJsonPath = find.up(wantedPath, {\n      cwd: this.primaryPackageJson.operationDir,\n      last: getProjectRoot(),\n    });\n\n    if (!packageJsonPath) {\n      return null;\n    }\n\n    const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n    return packageJson;\n  }\n\n  getInstallArgs(): string[] {\n    if (!this.installArgs) {\n      this.installArgs = [];\n    }\n    return this.installArgs;\n  }\n\n  public getPackageCommand(args: string[]): string {\n    return `npx ${args.join(' ')}`;\n  }\n\n  public runPackageCommand(\n    options: Omit<ExecuteCommandOptions, 'command'> & { args: string[] }\n  ): ResultPromise {\n    return executeCommand({\n      command: 'npx',\n      ...options,\n    });\n  }\n\n  public runInternalCommand(\n    command: string,\n    args: string[],\n    cwd?: string,\n    stdio?: 'inherit' | 'pipe' | 'ignore'\n  ) {\n    return executeCommand({\n      command: 'npm',\n      args: [command, ...args],\n      cwd: cwd ?? this.cwd,\n      stdio,\n    });\n  }\n\n  public async findInstallations(pattern: string[], { depth = 99 }: { depth?: number } = {}) {\n    const exec = ({ packageDepth }: { packageDepth: number }) => {\n      const pipeToNull = platform() === 'win32' ? '2>NUL' : '2>/dev/null';\n      return executeCommand({\n        command: 'npm',\n        args: ['ls', '--json', `--depth=${packageDepth}`, pipeToNull],\n        env: {\n          FORCE_COLOR: 'false',\n        },\n        cwd: this.instanceDir,\n      });\n    };\n\n    try {\n      const childProcess = await exec({ packageDepth: depth });\n      const commandResult = typeof childProcess.stdout === 'string' ? childProcess.stdout : '';\n      const parsedOutput = JSON.parse(commandResult);\n\n      return this.mapDependencies(parsedOutput, pattern);\n    } catch {\n      // when --depth is higher than 0, npm can return a non-zero exit code\n      // in case the user's project has peer dependency issues. So we try again with no depth\n      try {\n        const childProcess = await exec({ packageDepth: 0 });\n        const commandResult = typeof childProcess.stdout === 'string' ? childProcess.stdout : '';\n        const parsedOutput = JSON.parse(commandResult);\n\n        return this.mapDependencies(parsedOutput, pattern);\n      } catch (e) {\n        logger.debug(`Error finding installations for ${pattern.join(', ')}: ${String(e)}`);\n        return undefined;\n      }\n    }\n  }\n\n  protected getResolutions(packageJson: PackageJson, versions: Record<string, string>) {\n    return {\n      overrides: {\n        ...packageJson.overrides,\n        ...versions,\n      },\n    };\n  }\n\n  protected runInstall(options?: { force?: boolean }) {\n    return executeCommand({\n      command: 'npm',\n      args: ['install', ...this.getInstallArgs(), ...(options?.force ? ['--force'] : [])],\n      cwd: this.cwd,\n      stdio: prompt.getPreferredStdio(),\n    });\n  }\n\n  public async getRegistryURL() {\n    const process = executeCommand({\n      command: 'npm',\n      // \"npm config\" commands are not allowed in workspaces per default\n      // https://github.com/npm/cli/issues/6099#issuecomment-1847584792\n      args: ['config', 'get', 'registry', '-ws=false', '-iwr'],\n    });\n    const result = await process;\n    const url = (typeof result.stdout === 'string' ? result.stdout : '').trim();\n    return url === 'undefined' ? undefined : url;\n  }\n\n  protected runAddDeps(dependencies: string[], installAsDevDependencies: boolean) {\n    let args = [...dependencies];\n\n    if (installAsDevDependencies) {\n      args = ['-D', ...args];\n    }\n\n    return executeCommand({\n      command: 'npm',\n      args: ['install', ...args, ...this.getInstallArgs()],\n      stdio: prompt.getPreferredStdio(),\n      cwd: this.primaryPackageJson.operationDir,\n    });\n  }\n\n  protected async runGetVersions<T extends boolean>(\n    packageName: string,\n    fetchAllVersions: T\n  ): Promise<T extends true ? string[] : string> {\n    const args = fetchAllVersions ? ['versions', '--json'] : ['version'];\n    try {\n      const process = executeCommand({\n        command: 'npm',\n        args: ['info', packageName, ...args],\n      });\n      const result = await process;\n      const commandResult = typeof result.stdout === 'string' ? result.stdout : '';\n\n      const parsedOutput = fetchAllVersions ? JSON.parse(commandResult) : commandResult.trim();\n\n      if (parsedOutput.error?.summary) {\n        // this will be handled in the catch block below\n        throw parsedOutput.error.summary;\n      }\n\n      return parsedOutput;\n    } catch (error) {\n      throw new FindPackageVersionsError({\n        error,\n        packageManager: 'NPM',\n        packageName,\n      });\n    }\n  }\n\n  /**\n   * @param input The output of `npm ls --json`\n   * @param pattern A list of package names to filter the result. * can be used as a placeholder\n   */\n  protected mapDependencies(input: NpmListOutput, pattern: string[]): InstallationMetadata {\n    const acc: Record<string, PackageMetadata[]> = {};\n    const existingVersions: Record<string, string[]> = {};\n    const duplicatedDependencies: Record<string, string[]> = {};\n\n    const recurse = ([name, packageInfo]: [string, NpmDependency]): void => {\n      // transform pattern into regex where `*` is replaced with `.*`\n      if (!name || !pattern.some((p) => new RegExp(`^${p.replace(/\\*/g, '.*')}$`).test(name))) {\n        return;\n      }\n\n      const value = {\n        version: packageInfo.version,\n        location: '',\n      };\n\n      if (!existingVersions[name]?.includes(value.version)) {\n        if (acc[name]) {\n          acc[name].push(value);\n        } else {\n          acc[name] = [value];\n        }\n        existingVersions[name] = sort([...(existingVersions[name] || []), value.version]);\n\n        if (existingVersions[name].length > 1) {\n          duplicatedDependencies[name] = existingVersions[name];\n        }\n      }\n\n      if (packageInfo.dependencies) {\n        Object.entries(packageInfo.dependencies).forEach(recurse);\n      }\n    };\n\n    Object.entries(input.dependencies).forEach(recurse);\n\n    return {\n      dependencies: acc,\n      duplicatedDependencies,\n      infoCommand: 'npm ls --depth=1',\n      dedupeCommand: 'npm dedupe',\n    };\n  }\n\n  public parseErrorFromLogs(logs: string): string {\n    let finalMessage = 'NPM error';\n    const match = logs.match(NPM_ERROR_REGEX);\n\n    if (match) {\n      const errorCode = match[3] as keyof typeof NPM_ERROR_CODES;\n      if (errorCode) {\n        finalMessage = `${finalMessage} ${errorCode}`;\n      }\n\n      const errorMessage = NPM_ERROR_CODES[errorCode];\n      if (errorMessage) {\n        finalMessage = `${finalMessage} - ${errorMessage}`;\n      }\n    }\n\n    return finalMessage.trim();\n  }\n}\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/PNPMProxy.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { prompt } from 'storybook/internal/node-logger';\n\nimport { executeCommand } from '../utils/command.ts';\nimport { JsPackageManager } from './JsPackageManager.ts';\nimport { PNPMProxy } from './PNPMProxy.ts';\n\nvi.mock('storybook/internal/node-logger', () => ({\n  prompt: {\n    executeTaskWithSpinner: vi.fn(),\n    getPreferredStdio: vi.fn(() => 'inherit'),\n  },\n  logger: {\n    debug: vi.fn(),\n    warn: vi.fn(),\n    error: vi.fn(),\n  },\n}));\n\nvi.mock(import('../utils/command.ts'), { spy: true });\nconst mockedExecuteCommand = vi.mocked(executeCommand);\n\ndescribe('PNPM Proxy', () => {\n  let pnpmProxy: PNPMProxy;\n\n  beforeEach(() => {\n    pnpmProxy = new PNPMProxy();\n    JsPackageManager.clearLatestVersionCache();\n    vi.spyOn(pnpmProxy, 'writePackageJson').mockImplementation(vi.fn());\n  });\n\n  it('type should be pnpm', () => {\n    expect(pnpmProxy.type).toEqual('pnpm');\n  });\n\n  describe('installDependencies', () => {\n    it('should run `pnpm install`', async () => {\n      // sort of un-mock part of the function so executeCommand (also mocked) is called\n      vi.mocked(prompt.executeTaskWithSpinner).mockImplementationOnce(async (fn: any) => {\n        await Promise.resolve(fn());\n      });\n      const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({ stdout: '7.1.0' } as any);\n\n      await pnpmProxy.installDependencies();\n\n      expect(executeCommandSpy).toHaveBeenCalledWith(\n        expect.objectContaining({ command: 'pnpm', args: ['install'] })\n      );\n    });\n  });\n\n  describe('runScript', () => {\n    it('should execute script `pnpm exec compodoc -- -e json -d .`', () => {\n      const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({ stdout: '7.1.0' } as any);\n\n      pnpmProxy.runPackageCommand({ args: ['compodoc', '-e', 'json', '-d', '.'] });\n\n      expect(executeCommandSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          command: 'pnpm',\n          args: ['exec', 'compodoc', '-e', 'json', '-d', '.'],\n        })\n      );\n    });\n  });\n\n  describe('addDependencies', () => {\n    it('with devDep it should run `pnpm add -D storybook`', async () => {\n      const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({ stdout: '6.0.0' } as any);\n\n      await pnpmProxy.addDependencies({ type: 'devDependencies' }, ['storybook']);\n\n      expect(executeCommandSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          command: 'pnpm',\n          args: ['add', '-D', 'storybook'],\n        })\n      );\n    });\n  });\n\n  describe('removeDependencies', () => {\n    it('should only change package.json without running install', async () => {\n      const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({ stdout: '7.0.0' } as any);\n      const writePackageSpy = vi.spyOn(pnpmProxy, 'writePackageJson').mockImplementation(vi.fn());\n\n      vi.spyOn(JsPackageManager, 'getPackageJson').mockImplementation((args) => {\n        return {\n          dependencies: {},\n          devDependencies: {\n            '@storybook/manager-webpack5': 'x.x.x',\n            '@storybook/react': 'x.x.x',\n          },\n        };\n      });\n\n      await pnpmProxy.removeDependencies(['@storybook/manager-webpack5']);\n\n      expect(writePackageSpy).toHaveBeenCalledWith(\n        {\n          dependencies: {},\n          devDependencies: {\n            '@storybook/react': 'x.x.x',\n          },\n        },\n        expect.any(String)\n      );\n      expect(executeCommandSpy).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('latestVersion', () => {\n    it('without constraint it returns the latest version', async () => {\n      const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({ stdout: '5.3.19' } as any);\n\n      const version = await pnpmProxy.latestVersion('storybook');\n\n      expect(executeCommandSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          command: 'pnpm',\n          args: ['info', 'storybook', 'version'],\n        })\n      );\n      expect(version).toEqual('5.3.19');\n    });\n\n    it('with constraint it returns the latest version satisfying the constraint', async () => {\n      const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({\n        stdout: '[\"4.25.3\",\"5.3.19\",\"6.0.0-beta.23\"]',\n      } as any);\n\n      const version = await pnpmProxy.latestVersion('storybook', '5.X');\n\n      expect(executeCommandSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          command: 'pnpm',\n          args: ['info', 'storybook', 'versions', '--json'],\n        })\n      );\n      expect(version).toEqual('5.3.19');\n    });\n\n    it('with constraint it throws an error if command output is not a valid JSON', async () => {\n      mockedExecuteCommand.mockResolvedValue({ stdout: 'NOT A JSON' } as any);\n\n      await expect(pnpmProxy.latestVersion('storybook', '5.X')).resolves.toBe(null);\n    });\n  });\n\n  describe('getVersion', () => {\n    it('with a Storybook package listed in versions.json it returns the version', async () => {\n      const storybookAngularVersion = (await import('../versions.ts')).default[\n        '@storybook/angular'\n      ];\n      const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({ stdout: '5.3.19' } as any);\n\n      const version = await pnpmProxy.getVersion('@storybook/angular');\n\n      expect(executeCommandSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          command: 'pnpm',\n          args: ['info', '@storybook/angular', 'version'],\n        })\n      );\n      expect(version).toEqual(`^${storybookAngularVersion}`);\n    });\n\n    it('with a Storybook package not listed in versions.json it returns the latest version', async () => {\n      const packageVersion = '5.3.19';\n      const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({\n        stdout: `${packageVersion}`,\n      } as any);\n\n      const version = await pnpmProxy.getVersion('@storybook/react-native');\n\n      expect(executeCommandSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          command: 'pnpm',\n          args: ['info', '@storybook/react-native', 'version'],\n        })\n      );\n      expect(version).toEqual(`^${packageVersion}`);\n    });\n  });\n\n  describe('addPackageResolutions', () => {\n    it('adds resolutions to package.json and account for existing resolutions', async () => {\n      const basePackageAttributes = {\n        dependencies: {},\n        devDependencies: {},\n      };\n\n      const writePackageSpy = vi.spyOn(pnpmProxy, 'writePackageJson').mockImplementation(vi.fn());\n\n      vi.spyOn(JsPackageManager, 'getPackageJson').mockImplementation(() => ({\n        dependencies: {},\n        devDependencies: {},\n        overrides: {\n          bar: 'x.x.x',\n        },\n      }));\n\n      const versions = {\n        foo: 'x.x.x',\n      };\n      pnpmProxy.addPackageResolutions(versions);\n\n      expect(writePackageSpy).toHaveBeenCalledWith(\n        {\n          ...basePackageAttributes,\n          overrides: {\n            ...versions,\n            bar: 'x.x.x',\n          },\n        },\n        expect.any(String)\n      );\n    });\n  });\n\n  describe('mapDependencies', () => {\n    it('should display duplicated dependencies based on pnpm output', async () => {\n      // pnpm list \"@storybook/*\" \"storybook\" --depth 10 --json\n      mockedExecuteCommand.mockResolvedValue({\n        stdout: `\n        [\n          {\n            \"peerDependencies\": {\n              \"unrelated-and-should-be-filtered\": {\n                \"version\": \"1.0.0\",\n                \"from\": \"\",\n                \"resolved\": \"\"\n              }\n            },\n            \"dependencies\": {\n              \"@storybook/addon-example\": {\n                \"from\": \"@storybook/addon-example\",\n                \"version\": \"7.0.0-beta.13\",\n                \"resolved\": \"https://registry.npmjs.org/@storybook/addon-example/-/addon-example-7.0.0-beta.13.tgz\",\n                \"dependencies\": {\n                  \"@storybook/package\": {\n                    \"from\": \"@storybook/package\",\n                    \"version\": \"7.0.0-beta.13\",\n                    \"resolved\": \"https://registry.npmjs.org/@storybook/package/-/package-7.0.0-beta.13.tgz\"\n                  }\n                }\n              }\n            },\n            \"devDependencies\": {\n              \"@storybook/jest\": {\n                \"from\": \"@storybook/jest\",\n                \"version\": \"0.0.11-next.0\",\n                \"resolved\": \"https://registry.npmjs.org/@storybook/jest/-/jest-0.0.11-next.0.tgz\",\n                \"dependencies\": {\n                  \"@storybook/package\": {\n                    \"from\": \"@storybook/package\",\n                    \"version\": \"7.0.0-rc.7\",\n                    \"resolved\": \"https://registry.npmjs.org/@storybook/package/-/package-7.0.0-rc.7.tgz\"\n                  }\n                }\n              },\n              \"@storybook/testing-library\": {\n                \"from\": \"@storybook/testing-library\",\n                \"version\": \"0.0.14-next.1\",\n                \"resolved\": \"https://registry.npmjs.org/@storybook/testing-library/-/testing-library-0.0.14-next.1.tgz\",\n                \"dependencies\": {\n                  \"@storybook/package\": {\n                    \"from\": \"@storybook/package\",\n                    \"version\": \"7.0.0-rc.7\",\n                    \"resolved\": \"https://registry.npmjs.org/@storybook/package/-/package-7.0.0-rc.7.tgz\"\n                  }\n                }\n              },\n              \"@storybook/nextjs\": {\n                \"from\": \"@storybook/nextjs\",\n                \"version\": \"7.0.0-beta.13\",\n                \"resolved\": \"https://registry.npmjs.org/@storybook/nextjs/-/nextjs-7.0.0-beta.13.tgz\",\n                \"dependencies\": {\n                  \"@storybook/builder-webpack5\": {\n                    \"from\": \"@storybook/builder-webpack5\",\n                    \"version\": \"7.0.0-beta.13\",\n                    \"resolved\": \"https://registry.npmjs.org/@storybook/builder-webpack5/-/builder-webpack5-7.0.0-beta.13.tgz\",\n                    \"dependencies\": {\n                      \"@storybook/addons\": {\n                        \"from\": \"@storybook/addons\",\n                        \"version\": \"7.0.0-beta.13\",\n                        \"resolved\": \"https://registry.npmjs.org/@storybook/addons/-/addons-7.0.0-beta.13.tgz\"\n                      }\n                    }\n                  }\n                }\n              }\n            }\n          }\n        ]      \n      `,\n      } as any);\n\n      const installations = await pnpmProxy.findInstallations(['@storybook/*']);\n\n      expect(installations).toMatchInlineSnapshot(`\n        {\n          \"dedupeCommand\": \"pnpm dedupe\",\n          \"dependencies\": {\n            \"@storybook/addon-example\": [\n              {\n                \"location\": \"\",\n                \"version\": \"7.0.0-beta.13\",\n              },\n            ],\n            \"@storybook/addons\": [\n              {\n                \"location\": \"\",\n                \"version\": \"7.0.0-beta.13\",\n              },\n            ],\n            \"@storybook/builder-webpack5\": [\n              {\n                \"location\": \"\",\n                \"version\": \"7.0.0-beta.13\",\n              },\n            ],\n            \"@storybook/jest\": [\n              {\n                \"location\": \"\",\n                \"version\": \"0.0.11-next.0\",\n              },\n            ],\n            \"@storybook/nextjs\": [\n              {\n                \"location\": \"\",\n                \"version\": \"7.0.0-beta.13\",\n              },\n            ],\n            \"@storybook/package\": [\n              {\n                \"location\": \"\",\n                \"version\": \"7.0.0-rc.7\",\n              },\n              {\n                \"location\": \"\",\n                \"version\": \"7.0.0-beta.13\",\n              },\n            ],\n            \"@storybook/testing-library\": [\n              {\n                \"location\": \"\",\n                \"version\": \"0.0.14-next.1\",\n              },\n            ],\n          },\n          \"duplicatedDependencies\": {\n            \"@storybook/package\": [\n              \"7.0.0-rc.7\",\n              \"7.0.0-beta.13\",\n            ],\n          },\n          \"infoCommand\": \"pnpm list --depth=1\",\n        }\n      `);\n    });\n  });\n\n  describe('parseErrors', () => {\n    it('should parse pnpm errors', () => {\n      const PNPM_ERROR_SAMPLE = `\n        ERR_PNPM_NO_MATCHING_VERSION No matching version found for react@29.2.0\n\n        This error happened while installing a direct dependency of /Users/yannbraga/open-source/sandboxes/react-vite/default-js/before-storybook\n        \n        The latest release of react is \"18.2.0\".\n        `;\n\n      expect(pnpmProxy.parseErrorFromLogs(PNPM_ERROR_SAMPLE)).toEqual(\n        'PNPM error ERR_PNPM_NO_MATCHING_VERSION No matching version found for react@29.2.0'\n      );\n    });\n\n    it('should show unknown pnpm error', () => {\n      const PNPM_ERROR_SAMPLE = `\n        This error happened while installing a direct dependency of /Users/yannbraga/open-source/sandboxes/react-vite/default-js/before-storybook\n          \n        The latest release of react is \"18.2.0\".\n      `;\n\n      expect(pnpmProxy.parseErrorFromLogs(PNPM_ERROR_SAMPLE)).toEqual(`PNPM error`);\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/PNPMProxy.ts",
    "content": "import { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nimport { logger, prompt } from 'storybook/internal/node-logger';\nimport { FindPackageVersionsError } from 'storybook/internal/server-errors';\n\nimport * as find from 'empathic/find';\n// eslint-disable-next-line depend/ban-dependencies\nimport type { ResultPromise } from 'execa';\n\nimport type { ExecuteCommandOptions } from '../utils/command.ts';\nimport { executeCommand } from '../utils/command.ts';\nimport { getProjectRoot } from '../utils/paths.ts';\nimport { JsPackageManager, PackageManagerName } from './JsPackageManager.ts';\nimport type { PackageJson } from './PackageJson.ts';\nimport type { InstallationMetadata, PackageMetadata } from './types.ts';\n\ntype PnpmDependency = {\n  from: string;\n  version: string;\n  resolved: string;\n  dependencies?: PnpmDependencies;\n};\n\ntype PnpmDependencies = {\n  [key: string]: PnpmDependency;\n};\n\ntype PnpmListItem = {\n  dependencies: PnpmDependencies;\n  peerDependencies: PnpmDependencies;\n  devDependencies: PnpmDependencies;\n};\n\nexport type PnpmListOutput = PnpmListItem[];\n\nconst PNPM_ERROR_REGEX = /(ELIFECYCLE|ERR_PNPM_[A-Z_]+)\\s+(.*)/i;\n\nexport class PNPMProxy extends JsPackageManager {\n  readonly type = PackageManagerName.PNPM;\n\n  installArgs: string[] | undefined;\n\n  detectWorkspaceRoot() {\n    const CWD = process.cwd();\n\n    const pnpmWorkspaceYaml = `${CWD}/pnpm-workspace.yaml`;\n    return existsSync(pnpmWorkspaceYaml);\n  }\n\n  getRunCommand(command: string): string {\n    return `pnpm run ${command}`;\n  }\n\n  async getPnpmVersion(): Promise<string> {\n    const result = await executeCommand({\n      cwd: this.cwd,\n      command: 'pnpm',\n      args: ['--version'],\n    });\n    return typeof result.stdout === 'string' ? result.stdout : '';\n  }\n\n  getInstallArgs(): string[] {\n    if (!this.installArgs) {\n      this.installArgs = [];\n\n      if (this.detectWorkspaceRoot()) {\n        this.installArgs.push('-w');\n      }\n    }\n    return this.installArgs;\n  }\n\n  getPackageCommand(args: string[]): string {\n    return `pnpm exec ${args.join(' ')}`;\n  }\n\n  public runPackageCommand({\n    args,\n    useRemotePkg = false,\n    ...options\n  }: Omit<ExecuteCommandOptions, 'command'> & {\n    args: string[];\n    useRemotePkg?: boolean;\n  }): ResultPromise {\n    return executeCommand({\n      command: 'pnpm',\n      args: [useRemotePkg ? 'dlx' : 'exec', ...args],\n      ...options,\n    });\n  }\n\n  public runInternalCommand(\n    command: string,\n    args: string[],\n    cwd?: string,\n    stdio?: 'inherit' | 'pipe' | 'ignore'\n  ) {\n    return executeCommand({\n      command: 'pnpm',\n      args: [command, ...args],\n      cwd: cwd ?? this.cwd,\n      stdio,\n    });\n  }\n\n  public async getRegistryURL() {\n    // pnpm 10.7.1+ falls back to npm for certain config keys (including registry)\n    // https://github.com/pnpm/pnpm/pull/9346\n    // \"npm config\" commands are not allowed in workspaces per default\n    // https://github.com/npm/cli/issues/6099#issuecomment-1847584792\n    const childProcess = await executeCommand({\n      command: 'npm',\n      cwd: this.cwd,\n      args: ['config', 'get', 'registry', '-ws=false', '-iwr'],\n    });\n    const url = (typeof childProcess.stdout === 'string' ? childProcess.stdout : '').trim();\n    return url === 'undefined' ? undefined : url;\n  }\n\n  public async findInstallations(pattern: string[], { depth = 99 }: { depth?: number } = {}) {\n    try {\n      const args = ['list', pattern.map((p) => `\"${p}\"`).join(' '), '--json', `--depth=${depth}`];\n      const childProcess = await executeCommand({\n        command: 'pnpm',\n        shell: true,\n        args,\n        env: {\n          FORCE_COLOR: 'false',\n        },\n        cwd: this.instanceDir,\n      });\n      const commandResult = typeof childProcess.stdout === 'string' ? childProcess.stdout : '';\n\n      const parsedOutput = JSON.parse(commandResult);\n      return this.mapDependencies(parsedOutput, pattern);\n    } catch (e) {\n      logger.debug(`Error finding installations for ${pattern.join(', ')}: ${String(e)}`);\n      return undefined;\n    }\n  }\n\n  // TODO: Remove pnp compatibility code in SB11\n  public async getModulePackageJSON(packageName: string): Promise<PackageJson | null> {\n    const pnpapiPath = find.any(['.pnp.js', '.pnp.cjs'], {\n      cwd: this.primaryPackageJson.operationDir,\n      last: getProjectRoot(),\n    });\n\n    if (pnpapiPath) {\n      try {\n        const pnpApi = await import(pathToFileURL(pnpapiPath).href);\n\n        const resolvedPath = pnpApi.resolveToUnqualified(packageName, this.cwd, {\n          considerBuiltins: false,\n        });\n\n        const pkgLocator = pnpApi.findPackageLocator(resolvedPath);\n        const pkg = pnpApi.getPackageInformation(pkgLocator);\n\n        const packageJSON = JSON.parse(\n          readFileSync(join(pkg.packageLocation, 'package.json'), 'utf-8')\n        );\n\n        return packageJSON;\n      } catch (error: any) {\n        if (error.code !== 'MODULE_NOT_FOUND') {\n          console.error('Error while fetching package version in PNPM PnP mode:', error);\n        }\n        return null;\n      }\n    }\n\n    const wantedPath = join('node_modules', packageName, 'package.json');\n    const packageJsonPath = find.up(wantedPath, {\n      cwd: this.primaryPackageJson.operationDir,\n      last: getProjectRoot(),\n    });\n\n    if (!packageJsonPath) {\n      return null;\n    }\n\n    return JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n  }\n\n  protected getResolutions(packageJson: PackageJson, versions: Record<string, string>) {\n    return {\n      overrides: {\n        ...packageJson.overrides,\n        ...versions,\n      },\n    };\n  }\n\n  protected runInstall(options?: { force?: boolean }) {\n    return executeCommand({\n      command: 'pnpm',\n      args: ['install', ...this.getInstallArgs(), ...(options?.force ? ['--force'] : [])],\n      stdio: prompt.getPreferredStdio(),\n      cwd: this.cwd,\n    });\n  }\n\n  protected runAddDeps(dependencies: string[], installAsDevDependencies: boolean) {\n    let args = [...dependencies];\n\n    if (installAsDevDependencies) {\n      args = ['-D', ...args];\n    }\n\n    const commandArgs = ['add', ...args, ...this.getInstallArgs()];\n\n    return executeCommand({\n      command: 'pnpm',\n      args: commandArgs,\n      stdio: prompt.getPreferredStdio(),\n      cwd: this.primaryPackageJson.operationDir,\n    });\n  }\n\n  protected async runGetVersions<T extends boolean>(\n    packageName: string,\n    fetchAllVersions: T\n  ): Promise<T extends true ? string[] : string> {\n    const args = fetchAllVersions ? ['versions', '--json'] : ['version'];\n\n    try {\n      const process = executeCommand({\n        command: 'pnpm',\n        args: ['info', packageName, ...args],\n      });\n      const result = await process;\n      const commandResult = typeof result.stdout === 'string' ? result.stdout : '';\n\n      const parsedOutput = fetchAllVersions ? JSON.parse(commandResult) : commandResult.trim();\n\n      if (parsedOutput.error?.summary) {\n        // this will be handled in the catch block below\n        throw parsedOutput.error.summary;\n      }\n\n      return parsedOutput;\n    } catch (error) {\n      throw new FindPackageVersionsError({\n        error,\n        packageManager: 'PNPM',\n        packageName,\n      });\n    }\n  }\n\n  protected mapDependencies(input: PnpmListOutput, pattern: string[]): InstallationMetadata {\n    const acc: Record<string, PackageMetadata[]> = {};\n    const existingVersions: Record<string, string[]> = {};\n    const duplicatedDependencies: Record<string, string[]> = {};\n    const items: PnpmDependencies = input.reduce((curr, item) => {\n      const { devDependencies, dependencies, peerDependencies } = item;\n      const allDependencies = { ...devDependencies, ...dependencies, ...peerDependencies };\n      return Object.assign(curr, allDependencies);\n    }, {} as PnpmDependencies);\n\n    const recurse = ([name, packageInfo]: [string, PnpmDependency]): void => {\n      // transform pattern into regex where `*` is replaced with `.*`\n      if (!name || !pattern.some((p) => new RegExp(`^${p.replace(/\\*/g, '.*')}$`).test(name))) {\n        return;\n      }\n\n      const value = {\n        version: packageInfo.version,\n        location: '',\n      };\n\n      if (!existingVersions[name]?.includes(value.version)) {\n        if (acc[name]) {\n          acc[name].push(value);\n        } else {\n          acc[name] = [value];\n        }\n        existingVersions[name] = [...(existingVersions[name] || []), value.version];\n\n        if (existingVersions[name].length > 1) {\n          duplicatedDependencies[name] = existingVersions[name];\n        }\n      }\n\n      if (packageInfo.dependencies) {\n        Object.entries(packageInfo.dependencies).forEach(recurse);\n      }\n    };\n    Object.entries(items).forEach(recurse);\n\n    return {\n      dependencies: acc,\n      duplicatedDependencies,\n      infoCommand: 'pnpm list --depth=1',\n      dedupeCommand: 'pnpm dedupe',\n    };\n  }\n\n  public parseErrorFromLogs(logs: string): string {\n    let finalMessage = 'PNPM error';\n    const match = logs.match(PNPM_ERROR_REGEX);\n    if (match) {\n      const [errorCode] = match;\n      if (errorCode) {\n        finalMessage = `${finalMessage} ${errorCode}`;\n      }\n    }\n\n    return finalMessage.trim();\n  }\n}\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/PackageJson.ts",
    "content": "import type { PackageJson } from 'storybook/internal/types';\n\nexport type PackageJsonWithDepsAndDevDeps = PackageJson &\n  Required<Pick<PackageJson, 'dependencies' | 'devDependencies'>>;\n\nexport type PackageJsonWithMaybeDeps = Partial<\n  Pick<PackageJson, 'dependencies' | 'devDependencies' | 'peerDependencies' | 'files'>\n>;\n\nexport type { PackageJson };\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/Yarn1Proxy.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { prompt } from 'storybook/internal/node-logger';\n\nimport { dedent } from 'ts-dedent';\n\nimport { executeCommand } from '../utils/command.ts';\nimport { JsPackageManager, PackageManagerName } from './JsPackageManager.ts';\nimport { Yarn1Proxy } from './Yarn1Proxy.ts';\n\nvi.mock('storybook/internal/node-logger', () => ({\n  prompt: {\n    executeTaskWithSpinner: vi.fn(),\n    getPreferredStdio: vi.fn(() => 'inherit'),\n  },\n  logger: {\n    debug: vi.fn(),\n    warn: vi.fn(),\n    error: vi.fn(),\n  },\n}));\n\nvi.mock(import('../utils/command.ts'), { spy: true });\nconst mockedExecuteCommand = vi.mocked(executeCommand);\n\nvi.mock('node:process', async (importOriginal) => {\n  const original: any = await importOriginal();\n  return {\n    ...original,\n    default: {\n      ...original.default,\n      env: {\n        ...original.default.env,\n        CI: false,\n      },\n    },\n  };\n});\n\ndescribe('Yarn 1 Proxy', () => {\n  let yarn1Proxy: Yarn1Proxy;\n\n  beforeEach(() => {\n    yarn1Proxy = new Yarn1Proxy();\n    JsPackageManager.clearLatestVersionCache();\n    vi.spyOn(yarn1Proxy, 'writePackageJson').mockImplementation(vi.fn());\n  });\n\n  it('type should be yarn1', () => {\n    expect(yarn1Proxy.type).toEqual(PackageManagerName.YARN1);\n  });\n\n  describe('installDependencies', () => {\n    it('should run `yarn`', async () => {\n      // sort of un-mock part of the function so executeCommand (also mocked) is called\n      vi.mocked(prompt.executeTaskWithSpinner).mockImplementationOnce(async (fn: any) => {\n        await Promise.resolve(fn());\n      });\n      const executeCommandSpy = mockedExecuteCommand.mockReturnValue(\n        Promise.resolve({ stdout: '' }) as any\n      );\n\n      await yarn1Proxy.installDependencies();\n\n      expect(executeCommandSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          command: 'yarn',\n          args: ['install', '--ignore-workspace-root-check'],\n        })\n      );\n    });\n  });\n\n  describe('runScript', () => {\n    it('should execute script `yarn compodoc -- -e json -d .`', () => {\n      const executeCommandSpy = mockedExecuteCommand.mockReturnValue(\n        Promise.resolve({ stdout: '7.1.0' }) as any\n      );\n\n      yarn1Proxy.runPackageCommand({ args: ['compodoc', '-e', 'json', '-d', '.'] });\n\n      expect(executeCommandSpy).toHaveBeenLastCalledWith(\n        expect.objectContaining({\n          command: 'yarn',\n          args: ['exec', 'compodoc', '--', '-e', 'json', '-d', '.'],\n        })\n      );\n    });\n  });\n\n  describe('addDependencies', () => {\n    it('with devDep it should run `yarn install -D --ignore-workspace-root-check storybook`', async () => {\n      const executeCommandSpy = mockedExecuteCommand.mockReturnValue(\n        Promise.resolve({ stdout: '' }) as any\n      );\n\n      await yarn1Proxy.addDependencies({ type: 'devDependencies' }, ['storybook']);\n\n      expect(executeCommandSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          command: 'yarn',\n          args: ['add', '--ignore-workspace-root-check', '-D', 'storybook'],\n        })\n      );\n    });\n  });\n\n  describe('removeDependencies', () => {\n    it('skipInstall should only change package.json without running install', async () => {\n      const executeCommandSpy = mockedExecuteCommand.mockReturnValue(\n        Promise.resolve({ stdout: '7.0.0' }) as any\n      );\n      const writePackageSpy = vi.spyOn(yarn1Proxy, 'writePackageJson').mockImplementation(vi.fn());\n\n      vi.spyOn(JsPackageManager, 'getPackageJson').mockImplementation((args) => {\n        return {\n          dependencies: {},\n          devDependencies: {\n            '@storybook/manager-webpack5': 'x.x.x',\n            '@storybook/react': 'x.x.x',\n          },\n        };\n      });\n\n      await yarn1Proxy.removeDependencies(['@storybook/manager-webpack5']);\n\n      expect(writePackageSpy).toHaveBeenCalledWith(\n        {\n          dependencies: {},\n          devDependencies: {\n            '@storybook/react': 'x.x.x',\n          },\n        },\n        expect.any(String)\n      );\n      expect(executeCommandSpy).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('latestVersion', () => {\n    it('without constraint it returns the latest version', async () => {\n      const executeCommandSpy = mockedExecuteCommand.mockReturnValue(\n        Promise.resolve({ stdout: '{\"type\":\"inspect\",\"data\":\"5.3.19\"}' }) as any\n      );\n\n      const version = await yarn1Proxy.latestVersion('storybook');\n\n      expect(executeCommandSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          command: 'yarn',\n          args: ['info', 'storybook', 'version', '--json'],\n        })\n      );\n      expect(version).toEqual('5.3.19');\n    });\n\n    it('with constraint it returns the latest version satisfying the constraint', async () => {\n      const executeCommandSpy = mockedExecuteCommand.mockReturnValue(\n        Promise.resolve({\n          stdout: '{\"type\":\"inspect\",\"data\":[\"4.25.3\",\"5.3.19\",\"6.0.0-beta.23\"]}',\n        }) as any\n      );\n\n      const version = await yarn1Proxy.latestVersion('storybook', '5.X');\n\n      expect(executeCommandSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          command: 'yarn',\n          args: ['info', 'storybook', 'versions', '--json'],\n        })\n      );\n      expect(version).toEqual('5.3.19');\n    });\n\n    it('throws an error if command output is not a valid JSON', async () => {\n      mockedExecuteCommand.mockReturnValue(Promise.resolve({ stdout: 'NOT A JSON' }) as any);\n\n      await expect(yarn1Proxy.latestVersion('storybook')).resolves.toBe(null);\n    });\n  });\n\n  describe('addPackageResolutions', () => {\n    it('adds resolutions to package.json and account for existing resolutions', async () => {\n      const writePackageSpy = vi.spyOn(yarn1Proxy, 'writePackageJson').mockImplementation(vi.fn());\n\n      vi.spyOn(JsPackageManager, 'getPackageJson').mockImplementation(() => ({\n        dependencies: {},\n        devDependencies: {},\n        resolutions: {\n          bar: 'x.x.x',\n        },\n      }));\n\n      const versions = {\n        foo: 'x.x.x',\n      };\n      yarn1Proxy.addPackageResolutions(versions);\n\n      expect(writePackageSpy).toHaveBeenCalledWith(\n        {\n          dependencies: {},\n          devDependencies: {},\n          resolutions: {\n            ...versions,\n            bar: 'x.x.x',\n          },\n        },\n        expect.any(String)\n      );\n    });\n  });\n\n  describe('mapDependencies', () => {\n    it('should display duplicated dependencies based on yarn output', async () => {\n      // yarn list --pattern \"@storybook/*\" \"@storybook/react\" --recursive --json\n      mockedExecuteCommand.mockResolvedValueOnce({\n        stdout: `\n        {\n          \"type\": \"tree\",\n          \"data\": {\n            \"type\": \"list\",\n            \"trees\": [\n              {\n                \"name\": \"unrelated-and-should-be-filtered@1.0.0\",\n                \"children\": []\n              },\n              {\n                \"name\": \"@storybook/package@7.0.0-beta.12\",\n                \"children\": [\n                  {\n                    \"name\": \"@storybook/types@7.0.0-beta.12\",\n                    \"children\": []\n                  }\n                ]\n              },\n              {\n                \"name\": \"@storybook/addon-example@7.0.0-beta.19\",\n                \"children\": [\n                  {\n                    \"name\": \"@storybook/package@7.0.0-beta.19\",\n                    \"children\": []\n                  }\n                ]\n              }\n            ]\n          }\n        }\n      `,\n      } as any);\n\n      const installations = await yarn1Proxy.findInstallations(['@storybook/*']);\n\n      expect(installations).toMatchInlineSnapshot(`\n        {\n          \"dedupeCommand\": \"yarn dedupe\",\n          \"dependencies\": {\n            \"@storybook/addon-example\": [\n              {\n                \"location\": \"\",\n                \"version\": \"7.0.0-beta.19\",\n              },\n            ],\n            \"@storybook/package\": [\n              {\n                \"location\": \"\",\n                \"version\": \"7.0.0-beta.12\",\n              },\n              {\n                \"location\": \"\",\n                \"version\": \"7.0.0-beta.19\",\n              },\n            ],\n            \"@storybook/types\": [\n              {\n                \"location\": \"\",\n                \"version\": \"7.0.0-beta.12\",\n              },\n            ],\n          },\n          \"duplicatedDependencies\": {\n            \"@storybook/package\": [\n              \"7.0.0-beta.12\",\n              \"7.0.0-beta.19\",\n            ],\n          },\n          \"infoCommand\": \"yarn why\",\n        }\n      `);\n    });\n  });\n\n  describe('parseErrors', () => {\n    it('should parse yarn1 errors', () => {\n      const YARN1_ERROR_SAMPLE = dedent`\n        yarn add v1.22.19\n        [1/4] Resolving packages...\n        error Couldn't find any versions for \"react\" that matches \"28.2.0\"\n        info Visit https://yarnpkg.com/en/docs/cli/add for documentation about this command.\n      `;\n\n      expect(yarn1Proxy.parseErrorFromLogs(YARN1_ERROR_SAMPLE)).toEqual(\n        `YARN1 error: Couldn't find any versions for \"react\" that matches \"28.2.0\"`\n      );\n    });\n\n    it('should show unknown yarn1 error', () => {\n      const YARN1_ERROR_SAMPLE = dedent`\n        yarn install v1.22.19\n        [1/4] 🔍  Resolving packages...\n        info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.\n      `;\n\n      expect(yarn1Proxy.parseErrorFromLogs(YARN1_ERROR_SAMPLE)).toEqual(`YARN1 error`);\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/Yarn1Proxy.ts",
    "content": "import { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport process from 'node:process';\n\nimport { logger, prompt } from 'storybook/internal/node-logger';\nimport { FindPackageVersionsError } from 'storybook/internal/server-errors';\n\nimport * as find from 'empathic/find';\n// eslint-disable-next-line depend/ban-dependencies\nimport type { ResultPromise } from 'execa';\n\nimport type { ExecuteCommandOptions } from '../utils/command.ts';\nimport { executeCommand } from '../utils/command.ts';\nimport { getProjectRoot } from '../utils/paths.ts';\nimport { JsPackageManager, PackageManagerName } from './JsPackageManager.ts';\nimport type { PackageJson } from './PackageJson.ts';\nimport type { InstallationMetadata, PackageMetadata } from './types.ts';\nimport { parsePackageData } from './util.ts';\n\ntype Yarn1ListItem = {\n  name: string;\n  children: Yarn1ListItem[];\n};\n\ntype Yarn1ListData = {\n  type: 'list';\n  trees: Yarn1ListItem[];\n};\n\nexport type Yarn1ListOutput = {\n  type: 'tree';\n  data: Yarn1ListData;\n};\n\nconst YARN1_ERROR_REGEX = /^error\\s(.*)$/gm;\n\nexport class Yarn1Proxy extends JsPackageManager {\n  readonly type = PackageManagerName.YARN1;\n\n  installArgs: string[] | undefined;\n\n  getInstallArgs(): string[] {\n    if (!this.installArgs) {\n      this.installArgs = process.env.CI ? [] : ['--ignore-workspace-root-check'];\n    }\n    return this.installArgs;\n  }\n\n  getRunCommand(command: string): string {\n    return `yarn ${command}`;\n  }\n\n  getPackageCommand(args: string[]): string {\n    const [command, ...rest] = args;\n    return `yarn exec ${command} -- ${rest.join(' ')}`;\n  }\n\n  public runPackageCommand({\n    args,\n    useRemotePkg = false,\n    ...options\n  }: Omit<ExecuteCommandOptions, 'command'> & {\n    args: string[];\n    useRemotePkg?: boolean;\n  }): ResultPromise {\n    const [command, ...rest] = args;\n    if (useRemotePkg) {\n      return executeCommand({\n        command: 'npx',\n        args,\n      });\n    }\n    return executeCommand({\n      command: `yarn`,\n      args: ['exec', command, '--', ...rest],\n      ...options,\n    });\n  }\n\n  public runInternalCommand(\n    command: string,\n    args: string[],\n    cwd?: string,\n    stdio?: 'inherit' | 'pipe' | 'ignore'\n  ) {\n    return executeCommand({\n      command: `yarn`,\n      args: [command, ...args],\n      cwd: cwd ?? this.cwd,\n      stdio,\n    });\n  }\n\n  public async getModulePackageJSON(packageName: string): Promise<PackageJson | null> {\n    const wantedPath = join('node_modules', packageName, 'package.json');\n    const packageJsonPath = find.up(wantedPath, {\n      cwd: this.primaryPackageJson.operationDir,\n      last: getProjectRoot(),\n    });\n\n    if (!packageJsonPath) {\n      return null;\n    }\n\n    return JSON.parse(readFileSync(packageJsonPath, 'utf-8')) as Record<string, any>;\n  }\n\n  public async getRegistryURL() {\n    const childProcess = await executeCommand({\n      command: 'yarn',\n      args: ['config', 'get', 'registry'],\n    });\n    const url = (typeof childProcess.stdout === 'string' ? childProcess.stdout : '').trim();\n    return url === 'undefined' ? undefined : url;\n  }\n\n  public async findInstallations(pattern: string[], { depth = 99 }: { depth?: number } = {}) {\n    const yarnArgs = ['list', '--pattern', pattern.map((p) => `\"${p}\"`).join(' '), '--json'];\n\n    if (depth !== 0) {\n      yarnArgs.push('--recursive');\n    }\n\n    try {\n      const process = executeCommand({\n        command: 'yarn',\n        args: yarnArgs.concat(pattern),\n        shell: true,\n        env: {\n          FORCE_COLOR: 'false',\n        },\n        cwd: this.instanceDir,\n      });\n      const result = await process;\n      const commandResult = typeof result.stdout === 'string' ? result.stdout : '';\n\n      const parsedOutput = JSON.parse(commandResult);\n      return this.mapDependencies(parsedOutput, pattern);\n    } catch (e) {\n      logger.debug(`Error finding installations for ${pattern.join(', ')}: ${String(e)}`);\n      return undefined;\n    }\n  }\n\n  protected getResolutions(packageJson: PackageJson, versions: Record<string, string>) {\n    return {\n      resolutions: {\n        ...packageJson.resolutions,\n        ...versions,\n      },\n    };\n  }\n\n  protected runInstall(options?: { force?: boolean }) {\n    return executeCommand({\n      command: 'yarn',\n      args: ['install', ...this.getInstallArgs(), ...(options?.force ? ['--force'] : [])],\n      stdio: prompt.getPreferredStdio(),\n      cwd: this.cwd,\n    });\n  }\n\n  protected runAddDeps(dependencies: string[], installAsDevDependencies: boolean) {\n    let args = [...dependencies];\n\n    if (installAsDevDependencies) {\n      args = ['-D', ...args];\n    }\n\n    return executeCommand({\n      command: 'yarn',\n      args: ['add', ...this.getInstallArgs(), ...args],\n      stdio: prompt.getPreferredStdio(),\n      cwd: this.primaryPackageJson.operationDir,\n    });\n  }\n\n  protected async runGetVersions<T extends boolean>(\n    packageName: string,\n    fetchAllVersions: T\n  ): Promise<T extends true ? string[] : string> {\n    const args = [fetchAllVersions ? 'versions' : 'version', '--json'];\n    try {\n      const process = executeCommand({\n        command: 'yarn',\n        args: ['info', packageName, ...args],\n      });\n      const result = await process;\n      const commandResult = typeof result.stdout === 'string' ? result.stdout : '';\n\n      const parsedOutput = JSON.parse(commandResult);\n      if (parsedOutput.type === 'inspect') {\n        return parsedOutput.data;\n      }\n      // eslint-disable-next-line local-rules/no-uncategorized-errors\n      throw new Error(`Yarn did not provide an output with type 'inspect'.`);\n    } catch (error) {\n      throw new FindPackageVersionsError({\n        error,\n        packageManager: 'Yarn 1',\n        packageName,\n      });\n    }\n  }\n\n  protected mapDependencies(input: Yarn1ListOutput, pattern: string[]): InstallationMetadata {\n    if (input.type === 'tree') {\n      const { trees } = input.data;\n      const acc: Record<string, PackageMetadata[]> = {};\n      const existingVersions: Record<string, string[]> = {};\n      const duplicatedDependencies: Record<string, string[]> = {};\n\n      const recurse = (tree: (typeof trees)[0]) => {\n        const { children } = tree;\n        const { name, value } = parsePackageData(tree.name);\n        if (!name || !pattern.some((p) => new RegExp(`^${p.replace(/\\*/g, '.*')}$`).test(name))) {\n          return;\n        }\n\n        if (!existingVersions[name]?.includes(value.version)) {\n          if (acc[name]) {\n            acc[name].push(value);\n          } else {\n            acc[name] = [value];\n          }\n          existingVersions[name] = [...(existingVersions[name] || []), value.version];\n\n          if (existingVersions[name].length > 1) {\n            duplicatedDependencies[name] = existingVersions[name];\n          }\n        }\n\n        children.forEach(recurse);\n      };\n\n      trees.forEach(recurse);\n\n      return {\n        dependencies: acc,\n        duplicatedDependencies,\n        infoCommand: 'yarn why',\n        dedupeCommand: 'yarn dedupe',\n      };\n    }\n\n    throw new Error('Something went wrong while parsing yarn output');\n  }\n\n  public parseErrorFromLogs(logs: string): string {\n    let finalMessage = 'YARN1 error';\n    const match = logs.match(YARN1_ERROR_REGEX);\n\n    if (match) {\n      const errorMessage = match[0]?.replace(/^error\\s(.*)$/, '$1');\n      if (errorMessage) {\n        finalMessage = `${finalMessage}: ${errorMessage}`;\n      }\n    }\n\n    return finalMessage.trim();\n  }\n}\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/Yarn2Proxy.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { prompt } from 'storybook/internal/node-logger';\n\nimport { executeCommand } from '../utils/command.ts';\nimport { JsPackageManager } from './JsPackageManager.ts';\nimport { Yarn2Proxy } from './Yarn2Proxy.ts';\n\nvi.mock('storybook/internal/node-logger', () => ({\n  prompt: {\n    executeTaskWithSpinner: vi.fn(),\n    getPreferredStdio: vi.fn(() => 'inherit'),\n  },\n  logger: {\n    debug: vi.fn(),\n    warn: vi.fn(),\n    error: vi.fn(),\n  },\n}));\n\nvi.mock('../utils/command', { spy: true });\nconst mockedExecuteCommand = vi.mocked(executeCommand);\n\ndescribe('Yarn 2 Proxy', () => {\n  let yarn2Proxy: Yarn2Proxy;\n\n  beforeEach(() => {\n    yarn2Proxy = new Yarn2Proxy();\n    JsPackageManager.clearLatestVersionCache();\n    vi.spyOn(yarn2Proxy, 'writePackageJson').mockImplementation(vi.fn());\n  });\n\n  it('type should be yarn2', () => {\n    expect(yarn2Proxy.type).toEqual('yarn2');\n  });\n\n  describe('installDependencies', () => {\n    it('should run `yarn`', async () => {\n      // sort of un-mock part of the function so executeCommand (also mocked) is called\n      vi.mocked(prompt.executeTaskWithSpinner).mockImplementationOnce(async (fn: any) => {\n        await Promise.resolve(fn());\n      });\n      const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({\n        stdout: '',\n      } as any);\n\n      await yarn2Proxy.installDependencies();\n\n      expect(executeCommandSpy).toHaveBeenCalledWith(\n        expect.objectContaining({ command: 'yarn', args: ['install'] })\n      );\n    });\n  });\n\n  describe('runScript', () => {\n    it('should execute script `yarn compodoc -- -e json -d .`', async () => {\n      const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({\n        stdout: '7.1.0',\n      } as any);\n\n      await yarn2Proxy.runPackageCommand({ args: ['compodoc', '-e', 'json', '-d', '.'] });\n\n      expect(executeCommandSpy).toHaveBeenLastCalledWith(\n        expect.objectContaining({\n          command: 'yarn',\n          args: ['exec', 'compodoc', '-e', 'json', '-d', '.'],\n        })\n      );\n    });\n  });\n\n  describe('addDependencies', () => {\n    it('with devDep it should run `yarn install -D storybook`', async () => {\n      const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({\n        stdout: '',\n      } as any);\n\n      await yarn2Proxy.addDependencies({ type: 'devDependencies' }, ['storybook']);\n\n      expect(executeCommandSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          command: 'yarn',\n          args: ['add', '-D', 'storybook'],\n        })\n      );\n    });\n  });\n\n  describe('removeDependencies', () => {\n    it('skipInstall should only change package.json without running install', async () => {\n      const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({\n        stdout: '7.0.0',\n      } as any);\n      const writePackageSpy = vi.spyOn(yarn2Proxy, 'writePackageJson').mockImplementation(vi.fn());\n\n      vi.spyOn(JsPackageManager, 'getPackageJson').mockImplementation(() => {\n        return {\n          dependencies: {},\n          devDependencies: {\n            '@storybook/manager-webpack5': 'x.x.x',\n            '@storybook/react': 'x.x.x',\n          },\n        };\n      });\n\n      await yarn2Proxy.removeDependencies(['@storybook/manager-webpack5']);\n\n      expect(writePackageSpy).toHaveBeenCalledWith(\n        {\n          dependencies: {},\n          devDependencies: {\n            '@storybook/react': 'x.x.x',\n          },\n        },\n        expect.any(String)\n      );\n      expect(executeCommandSpy).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('latestVersion', () => {\n    it('without constraint it returns the latest version', async () => {\n      const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({\n        stdout: '{\"name\":\"storybook\",\"version\":\"5.3.19\"}',\n      } as any);\n\n      const version = await yarn2Proxy.latestVersion('storybook');\n\n      expect(executeCommandSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          command: 'yarn',\n          args: ['npm', 'info', 'storybook', '--fields', 'version', '--json'],\n        })\n      );\n      expect(version).toEqual('5.3.19');\n    });\n\n    it('with constraint it returns the latest version satisfying the constraint', async () => {\n      const executeCommandSpy = mockedExecuteCommand.mockResolvedValue({\n        stdout: '{\"name\":\"storybook\",\"versions\":[\"4.25.3\",\"5.3.19\",\"6.0.0-beta.23\"]}',\n      } as any);\n\n      const version = await yarn2Proxy.latestVersion('storybook', '5.X');\n\n      expect(executeCommandSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          command: 'yarn',\n          args: ['npm', 'info', 'storybook', '--fields', 'versions', '--json'],\n        })\n      );\n      expect(version).toEqual('5.3.19');\n    });\n\n    it('throws an error if command output is not a valid JSON', async () => {\n      mockedExecuteCommand.mockResolvedValue({\n        stdout: 'NOT A JSON',\n      } as any);\n\n      await expect(yarn2Proxy.latestVersion('storybook')).resolves.toBe(null);\n    });\n  });\n\n  describe('addPackageResolutions', () => {\n    it('adds resolutions to package.json and account for existing resolutions', async () => {\n      const writePackageSpy = vi.spyOn(yarn2Proxy, 'writePackageJson').mockImplementation(vi.fn());\n\n      vi.spyOn(JsPackageManager, 'getPackageJson').mockImplementation(() => ({\n        dependencies: {},\n        devDependencies: {},\n        resolutions: {\n          bar: 'x.x.x',\n        },\n      }));\n\n      const versions = {\n        foo: 'x.x.x',\n      };\n\n      yarn2Proxy.addPackageResolutions(versions);\n\n      expect(writePackageSpy).toHaveBeenCalledWith(\n        {\n          dependencies: {},\n          devDependencies: {},\n          resolutions: {\n            ...versions,\n            bar: 'x.x.x',\n          },\n        },\n        expect.any(String)\n      );\n    });\n  });\n\n  describe('mapDependencies', () => {\n    it('should display duplicated dependencies based on yarn2 output', async () => {\n      // yarn info --name-only --recursive \"@storybook/*\" \"storybook\"\n      mockedExecuteCommand.mockResolvedValue({\n        stdout: `\n          \"unrelated-and-should-be-filtered@npm:1.0.0\"\n          \"@storybook/global@npm:5.0.0\"\n          \"@storybook/package@npm:7.0.0-beta.12\"\n          \"@storybook/package@npm:7.0.0-beta.19\"\n          \"@storybook/jest@npm:0.0.11-next.0\"\n          \"@storybook/manager-api@npm:7.0.0-beta.19\"\n          \"@storybook/manager@npm:7.0.0-beta.19\"\n          \"@storybook/mdx2-csf@npm:0.1.0-next.5\"\n        `,\n      } as any);\n\n      const installations = await yarn2Proxy.findInstallations(['@storybook/*']);\n\n      expect(installations).toMatchInlineSnapshot(`\n        {\n          \"dedupeCommand\": \"yarn dedupe\",\n          \"dependencies\": {\n            \"@storybook/global\": [\n              {\n                \"location\": \"\",\n                \"version\": \"5.0.0\",\n              },\n            ],\n            \"@storybook/jest\": [\n              {\n                \"location\": \"\",\n                \"version\": \"0.0.11-next.0\",\n              },\n            ],\n            \"@storybook/manager\": [\n              {\n                \"location\": \"\",\n                \"version\": \"7.0.0-beta.19\",\n              },\n            ],\n            \"@storybook/manager-api\": [\n              {\n                \"location\": \"\",\n                \"version\": \"7.0.0-beta.19\",\n              },\n            ],\n            \"@storybook/mdx2-csf\": [\n              {\n                \"location\": \"\",\n                \"version\": \"0.1.0-next.5\",\n              },\n            ],\n            \"@storybook/package\": [\n              {\n                \"location\": \"\",\n                \"version\": \"7.0.0-beta.12\",\n              },\n              {\n                \"location\": \"\",\n                \"version\": \"7.0.0-beta.19\",\n              },\n            ],\n          },\n          \"duplicatedDependencies\": {\n            \"@storybook/package\": [\n              \"7.0.0-beta.12\",\n              \"7.0.0-beta.19\",\n            ],\n          },\n          \"infoCommand\": \"yarn why\",\n        }\n      `);\n    });\n  });\n\n  describe('parseErrors', () => {\n    it('should single yarn2 error message', () => {\n      const YARN2_ERROR_SAMPLE = `\n        ➤ YN0000: ┌ Resolution step\n        ➤ YN0001: │ Error: react@npm:28.2.0: No candidates found\n            at ge (/Users/xyz/.cache/node/corepack/yarn/3.5.1/yarn.js:439:8124)\n            at process.processTicksAndRejections (node:internal/process/task_queues:95:5)\n            at async Promise.allSettled (index 8)\n            at async io (/Users/xyz/.cache/node/corepack/yarn/3.5.1/yarn.js:390:10398)\n        ➤ YN0000: └ Completed in 2s 369ms\n        ➤ YN0000: Failed with errors in 2s 372ms\n        ➤ YN0032: fsevents@npm:2.3.2: Implicit dependencies on node-gyp are discouraged\n        ➤ YN0061: @npmcli/move-file@npm:2.0.1 is deprecated: This functionality has been moved to @npmcli/fs\n      `;\n\n      expect(yarn2Proxy.parseErrorFromLogs(YARN2_ERROR_SAMPLE)).toMatchInlineSnapshot(\n        `\n        \"YARN2 error\n        YN0001: EXCEPTION\n        -> Error: react@npm:28.2.0: No candidates found\n        \"\n      `\n      );\n    });\n\n    it('shows multiple yarn2 error messages', () => {\n      const YARN2_ERROR_SAMPLE = `\n        ➤ YN0000: · Yarn 4.1.1\n        ➤ YN0000: ┌ Resolution step\n        ➤ YN0085: │ + @chromatic-com/storybook@npm:1.2.25, and 300 more.\n        ➤ YN0000: └ Completed in 0s 763ms\n        ➤ YN0000: ┌ Post-resolution validation\n        ➤ YN0002: │ before-storybook@workspace:. doesn't provide @testing-library/dom (p1ac37), requested by @testing-library/user-event.\n        ➤ YN0002: │ before-storybook@workspace:. doesn't provide eslint (p1f657), requested by eslint-plugin-storybook.\n        ➤ YN0086: │ Some peer dependencies are incorrectly met; run yarn explain peer-requirements <hash> for details, where <hash> is the six-letter p-prefixed code.\n        ➤ YN0000: └ Completed\n        ➤ YN0000: ┌ Fetch step\n        ➤ YN0000: └ Completed\n        ➤ YN0000: ┌ Link step\n        ➤ YN0014: │ Failed to import certain dependencies\n        ➤ YN0071: │ Cannot link @storybook/test into before-storybook@workspace:. dependency @testing-library/jest-dom@npm:6.4.2 [ae73b] conflicts with parent dependency @testing-library/jest-dom@npm:5.17.0\n        ➤ YN0071: │ Cannot link @storybook/test into before-storybook@workspace:. dependency @testing-library/user-event@npm:14.5.2 [ae73b] conflicts with parent dependency @testing-library/user-event@npm:13.5.0 [1b0ac]\n        ➤ YN0000: └ Completed in 0s 262ms\n        ➤ YN0000: · Failed with errors in 1s 301ms\n      `;\n\n      expect(yarn2Proxy.parseErrorFromLogs(YARN2_ERROR_SAMPLE)).toMatchInlineSnapshot(\n        `\n        \"YARN2 error\n        YN0002: MISSING_PEER_DEPENDENCY\n        -> before-storybook@workspace:. doesn't provide @testing-library/dom (p1ac37), requested by @testing-library/user-event.\n\n        YN0002: MISSING_PEER_DEPENDENCY\n        -> before-storybook@workspace:. doesn't provide eslint (p1f657), requested by eslint-plugin-storybook.\n\n        YN0086: EXPLAIN_PEER_DEPENDENCIES_CTA\n        -> Some peer dependencies are incorrectly met; run yarn explain peer-requirements <hash> for details, where <hash> is the six-letter p-prefixed code.\n\n        YN0014: YARN_IMPORT_FAILED\n        -> Failed to import certain dependencies\n\n        YN0071: NM_CANT_INSTALL_EXTERNAL_SOFT_LINK\n        -> Cannot link @storybook/test into before-storybook@workspace:. dependency @testing-library/jest-dom@npm:6.4.2 [ae73b] conflicts with parent dependency @testing-library/jest-dom@npm:5.17.0\n\n        YN0071: NM_CANT_INSTALL_EXTERNAL_SOFT_LINK\n        -> Cannot link @storybook/test into before-storybook@workspace:. dependency @testing-library/user-event@npm:14.5.2 [ae73b] conflicts with parent dependency @testing-library/user-event@npm:13.5.0 [1b0ac]\n        \"\n      `\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/Yarn2Proxy.ts",
    "content": "import { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nimport { prompt } from 'storybook/internal/node-logger';\nimport { FindPackageVersionsError } from 'storybook/internal/server-errors';\n\nimport { PosixFS, VirtualFS, ZipOpenFS } from '@yarnpkg/fslib';\nimport { getLibzipSync } from '@yarnpkg/libzip';\nimport * as find from 'empathic/find';\n// eslint-disable-next-line depend/ban-dependencies\nimport type { ResultPromise } from 'execa';\n\nimport { logger } from '../../node-logger/index.ts';\nimport type { ExecuteCommandOptions } from '../utils/command.ts';\nimport { executeCommand } from '../utils/command.ts';\nimport { getProjectRoot } from '../utils/paths.ts';\nimport { JsPackageManager, PackageManagerName } from './JsPackageManager.ts';\nimport type { PackageJson } from './PackageJson.ts';\nimport type { InstallationMetadata, PackageMetadata } from './types.ts';\nimport { parsePackageData } from './util.ts';\n\n// more info at https://yarnpkg.com/advanced/error-codes\nconst CRITICAL_YARN2_ERROR_CODES = {\n  YN0001: 'EXCEPTION',\n  YN0002: 'MISSING_PEER_DEPENDENCY',\n  YN0003: 'CYCLIC_DEPENDENCIES',\n  YN0004: 'DISABLED_BUILD_SCRIPTS',\n  YN0005: 'BUILD_DISABLED',\n  YN0006: 'SOFT_LINK_BUILD',\n  YN0007: 'MUST_BUILD',\n  YN0008: 'MUST_REBUILD',\n  YN0009: 'BUILD_FAILED',\n  YN0010: 'RESOLVER_NOT_FOUND',\n  YN0011: 'FETCHER_NOT_FOUND',\n  YN0012: 'LINKER_NOT_FOUND',\n  YN0013: 'FETCH_NOT_CACHED',\n  YN0014: 'YARN_IMPORT_FAILED',\n  YN0015: 'REMOTE_INVALID',\n  YN0016: 'REMOTE_NOT_FOUND',\n  YN0018: 'CACHE_CHECKSUM_MISMATCH',\n  YN0019: 'UNUSED_CACHE_ENTRY',\n  YN0020: 'MISSING_LOCKFILE_ENTRY',\n  YN0022: 'TOO_MANY_MATCHING_WORKSPACES',\n  YN0023: 'CONSTRAINTS_MISSING_DEPENDENCY',\n  YN0024: 'CONSTRAINTS_INCOMPATIBLE_DEPENDENCY',\n  YN0025: 'CONSTRAINTS_EXTRANEOUS_DEPENDENCY',\n  YN0026: 'CONSTRAINTS_INVALID_DEPENDENCY',\n  YN0027: 'CANT_SUGGEST_RESOLUTIONS',\n  YN0028: 'FROZEN_LOCKFILE_EXCEPTION',\n  YN0029: 'CROSS_DRIVE_VIRTUAL_LOCAL',\n  YN0030: 'FETCH_FAILED',\n  YN0031: 'DANGEROUS_NODE_MODULES',\n  YN0035: 'NETWORK_ERROR',\n  YN0046: 'AUTOMERGE_FAILED_TO_PARSE',\n  YN0047: 'AUTOMERGE_IMMUTABLE',\n  YN0048: 'AUTOMERGE_SUCCESS',\n  YN0049: 'AUTOMERGE_REQUIRED',\n  YN0050: 'DEPRECATED_CLI_SETTINGS',\n  YN0059: 'INVALID_RANGE_PEER_DEPENDENCY',\n  YN0060: 'INCOMPATIBLE_PEER_DEPENDENCY',\n  YN0062: 'INCOMPATIBLE_OS',\n  YN0063: 'INCOMPATIBLE_CPU',\n  YN0069: 'REDUNDANT_PACKAGE_EXTENSION',\n  YN0071: 'NM_CANT_INSTALL_EXTERNAL_SOFT_LINK',\n  YN0072: 'NM_PRESERVE_SYMLINKS_REQUIRED',\n  YN0074: 'NM_HARDLINKS_MODE_DOWNGRADED',\n  YN0075: 'PROLOG_INSTANTIATION_ERROR',\n  YN0076: 'INCOMPATIBLE_ARCHITECTURE',\n  YN0077: 'GHOST_ARCHITECTURE',\n  YN0078: 'RESOLUTION_MISMATCH',\n  YN0080: 'NETWORK_DISABLED',\n  YN0081: 'NETWORK_UNSAFE_HTTP',\n  YN0082: 'RESOLUTION_FAILED',\n  YN0083: 'AUTOMERGE_GIT_ERROR',\n  YN0086: 'EXPLAIN_PEER_DEPENDENCIES_CTA',\n  YN0090: 'OFFLINE_MODE_ENABLED',\n};\n\n// This encompasses Yarn Berry (v2+)\nexport class Yarn2Proxy extends JsPackageManager {\n  readonly type = PackageManagerName.YARN2;\n\n  installArgs: string[] | undefined;\n\n  getInstallArgs(): string[] {\n    if (!this.installArgs) {\n      this.installArgs = [];\n    }\n    return this.installArgs;\n  }\n\n  getRunCommand(command: string): string {\n    return `yarn ${command}`;\n  }\n\n  getPackageCommand(args: string[]): string {\n    return `yarn exec ${args.join(' ')}`;\n  }\n\n  public runPackageCommand({\n    args,\n    useRemotePkg = false,\n    ...options\n  }: Omit<ExecuteCommandOptions, 'command'> & {\n    args: string[];\n    useRemotePkg?: boolean;\n  }): ResultPromise {\n    return executeCommand({\n      command: 'yarn',\n      args: [useRemotePkg ? 'dlx' : 'exec', ...args],\n      ...options,\n    });\n  }\n\n  public runInternalCommand(\n    command: string,\n    args: string[],\n    cwd?: string,\n    stdio?: 'inherit' | 'pipe' | 'ignore'\n  ) {\n    return executeCommand({\n      command: 'yarn',\n      args: [command, ...args],\n      cwd: cwd ?? this.cwd,\n      stdio,\n    });\n  }\n\n  public async findInstallations(pattern: string[], { depth = 99 }: { depth?: number } = {}) {\n    const yarnArgs = ['info', '--name-only'];\n\n    if (depth !== 0) {\n      yarnArgs.push('--recursive');\n    }\n\n    try {\n      const childProcess = await executeCommand({\n        command: 'yarn',\n        args: yarnArgs.concat(pattern),\n        env: {\n          FORCE_COLOR: 'false',\n        },\n        cwd: this.instanceDir,\n      });\n      const commandResult = typeof childProcess.stdout === 'string' ? childProcess.stdout : '';\n\n      logger.debug(`Installation found for ${pattern.join(', ')}: ${commandResult}`);\n\n      return this.mapDependencies(commandResult, pattern);\n    } catch (e) {\n      logger.debug(`Error finding installations for ${pattern.join(', ')}: ${String(e)}`);\n      return undefined;\n    }\n  }\n\n  // TODO: Remove pnp compatibility code in SB11\n  async getModulePackageJSON(packageName: string): Promise<PackageJson | null> {\n    const pnpapiPath = find.any(['.pnp.js', '.pnp.cjs'], {\n      cwd: this.primaryPackageJson.operationDir,\n      last: getProjectRoot(),\n    });\n\n    if (pnpapiPath) {\n      try {\n        /*\n          This is a rather fragile way to access Yarn's PnP API, essentially manually loading it.\n          The proper way to do this would be to just do await import('pnpapi'),\n          as documented at https://yarnpkg.com/advanced/pnpapi#requirepnpapi\n\n          However the 'pnpapi' module is only injected when the Node process is started via Yarn,\n          which is not always the case for us, because we spawn child processes directly with Node,\n          eg. when running automigrations.\n        */\n        const { default: pnpApi } = await import(pathToFileURL(pnpapiPath).href);\n\n        const resolvedPath = pnpApi.resolveToUnqualified(\n          packageName,\n          this.primaryPackageJson.operationDir,\n          {\n            considerBuiltins: false,\n          }\n        );\n\n        const pkgLocator = pnpApi.findPackageLocator(resolvedPath);\n        const pkg = pnpApi.getPackageInformation(pkgLocator);\n\n        const zipOpenFs = new ZipOpenFS({\n          libzip: getLibzipSync(),\n        });\n\n        const virtualFs = new VirtualFS({ baseFs: zipOpenFs });\n        const crossFs = new PosixFS(virtualFs);\n\n        const virtualPath = join(pkg.packageLocation, 'package.json');\n\n        return crossFs.readJsonSync(virtualPath);\n      } catch (error: any) {\n        if (error.code !== 'ERR_MODULE_NOT_FOUND') {\n          console.error('Error while fetching package version in Yarn PnP mode:', error);\n        }\n        return null;\n      }\n    }\n\n    const wantedPath = join('node_modules', packageName, 'package.json');\n    const packageJsonPath = find.up(wantedPath, {\n      cwd: this.primaryPackageJson.operationDir,\n      last: getProjectRoot(),\n    });\n\n    if (!packageJsonPath) {\n      return null;\n    }\n\n    const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n    return packageJson;\n  }\n\n  protected getResolutions(packageJson: PackageJson, versions: Record<string, string>) {\n    return {\n      resolutions: {\n        ...packageJson.resolutions,\n        ...versions,\n      },\n    };\n  }\n\n  protected runInstall() {\n    return executeCommand({\n      command: 'yarn',\n      args: ['install', ...this.getInstallArgs()],\n      cwd: this.cwd,\n      stdio: prompt.getPreferredStdio(),\n    });\n  }\n\n  protected runAddDeps(dependencies: string[], installAsDevDependencies: boolean) {\n    let args = [...dependencies];\n\n    if (installAsDevDependencies) {\n      args = ['-D', ...args];\n    }\n\n    return executeCommand({\n      command: 'yarn',\n      args: ['add', ...this.getInstallArgs(), ...args],\n      stdio: prompt.getPreferredStdio(),\n      cwd: this.primaryPackageJson.operationDir,\n    });\n  }\n\n  public async getRegistryURL() {\n    const process = executeCommand({\n      command: 'yarn',\n      args: ['config', 'get', 'npmRegistryServer'],\n    });\n    const result = await process;\n    const url = (typeof result.stdout === 'string' ? result.stdout : '').trim();\n    return url === 'undefined' ? undefined : url;\n  }\n\n  protected async runGetVersions<T extends boolean>(\n    packageName: string,\n    fetchAllVersions: T\n  ): Promise<T extends true ? string[] : string> {\n    const field = fetchAllVersions ? 'versions' : 'version';\n    const args = ['--fields', field, '--json'];\n    try {\n      const process = executeCommand({\n        command: 'yarn',\n        args: ['npm', 'info', packageName, ...args],\n      });\n      const result = await process;\n      const commandResult = typeof result.stdout === 'string' ? result.stdout : '';\n\n      const parsedOutput = JSON.parse(commandResult);\n      return parsedOutput[field];\n    } catch (error) {\n      throw new FindPackageVersionsError({\n        error,\n        packageManager: 'Yarn Berry',\n        packageName,\n      });\n    }\n  }\n\n  protected mapDependencies(input: string, pattern: string[]): InstallationMetadata {\n    const lines = input.split('\\n');\n    const acc: Record<string, PackageMetadata[]> = {};\n    const existingVersions: Record<string, string[]> = {};\n    const duplicatedDependencies: Record<string, string[]> = {};\n\n    lines.forEach((packageName) => {\n      logger.debug(`Processing package ${packageName}`);\n      if (\n        !packageName ||\n        !pattern.some((p) => new RegExp(`${p.replace(/\\*/g, '.*')}`).test(packageName))\n      ) {\n        return;\n      }\n\n      const { name, value } = parsePackageData(packageName.replaceAll(`\"`, ''));\n      logger.debug(`Package ${name} found with version ${value.version}`);\n      if (!existingVersions[name]?.includes(value.version)) {\n        if (acc[name]) {\n          acc[name].push(value);\n        } else {\n          acc[name] = [value];\n        }\n\n        existingVersions[name] = [...(existingVersions[name] || []), value.version];\n        if (existingVersions[name].length > 1) {\n          duplicatedDependencies[name] = existingVersions[name];\n        }\n      }\n    });\n\n    return {\n      dependencies: acc,\n      duplicatedDependencies,\n      infoCommand: 'yarn why',\n      dedupeCommand: 'yarn dedupe',\n    };\n  }\n\n  public parseErrorFromLogs(logs: string): string {\n    const finalMessage = 'YARN2 error';\n    const errorCodesWithMessages: { code: string; message: string }[] = [];\n    const regex = /(YN\\d{4}): (.+)/g;\n    let match: RegExpExecArray | null;\n\n    while ((match = regex.exec(logs)) !== null) {\n      const code = match[1];\n      const message = match[2].replace(/[┌│└]/g, '').trim();\n      if (code in CRITICAL_YARN2_ERROR_CODES) {\n        errorCodesWithMessages.push({\n          code,\n          message: `${\n            CRITICAL_YARN2_ERROR_CODES[code as keyof typeof CRITICAL_YARN2_ERROR_CODES]\n          }\\n-> ${message}\\n`,\n        });\n      }\n    }\n\n    return [\n      finalMessage,\n      errorCodesWithMessages.map(({ code, message }) => `${code}: ${message}`).join('\\n'),\n    ].join('\\n');\n  }\n}\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/constants.ts",
    "content": "export const NPM_LOCKFILE = 'package-lock.json';\nexport const PNPM_LOCKFILE = 'pnpm-lock.yaml';\nexport const YARN_LOCKFILE = 'yarn.lock';\nexport const BUN_LOCKFILE = 'bun.lock';\nexport const BUN_LOCKFILE_BINARY = 'bun.lockb';\n\nexport const LOCK_FILES = [\n  NPM_LOCKFILE,\n  PNPM_LOCKFILE,\n  YARN_LOCKFILE,\n  BUN_LOCKFILE,\n  BUN_LOCKFILE_BINARY,\n];\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/fixtures/multiple-lockfiles/package.json",
    "content": "{\n  \"name\": \"multiple-lockfiles\"\n}\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/fixtures/multiple-lockfiles/yarn.lock",
    "content": ""
  },
  {
    "path": "code/core/src/common/js-package-manager/fixtures/multiple-lockfiles-pnpm-closer/inner/package.json",
    "content": "{\n  \"name\": \"multiple-lockfiles\"\n}\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/fixtures/multiple-lockfiles-pnpm-closer/yarn.lock",
    "content": ""
  },
  {
    "path": "code/core/src/common/js-package-manager/fixtures/pnpm-workspace/package/package.json",
    "content": "{\n  \"name\": \"test-fixture\"\n}\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/fixtures/pnpm-workspace/package.json",
    "content": "{\n  \"name\": \"pnpm-workspace\"\n}\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/index.ts",
    "content": "export * from './JsPackageManagerFactory.ts';\nexport * from './JsPackageManager.ts';\nexport * from './PackageJson.ts';\nexport * from './types.ts';\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/types.ts",
    "content": "export type PackageMetadata = { version: string; location?: string; reasons?: string[] };\nexport type InstallationMetadata = {\n  dependencies: Record<string, PackageMetadata[]>;\n  duplicatedDependencies: Record<string, string[]>;\n  infoCommand: string;\n  dedupeCommand: string;\n};\n"
  },
  {
    "path": "code/core/src/common/js-package-manager/util.ts",
    "content": "// input: @storybook/addon-essentials@npm:7.0.0\n// output: { name: '@storybook/addon-essentials', value: { version : '7.0.0', location: '' } }\nexport const parsePackageData = (packageName = '') => {\n  const [first, second, third] = packageName\n    .replace(/[└─├]+/g, '')\n    .trim()\n    .split('@');\n  const version = (third || second).replace('npm:', '');\n  const name = third ? `@${second}` : first;\n\n  const value = { version, location: '' };\n  return { name, value };\n};\n"
  },
  {
    "path": "code/core/src/common/presets.test.ts",
    "content": "import path, { join, normalize, relative } from 'node:path';\nimport { fileURLToPath, pathToFileURL, resolve } from 'node:url';\n\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { logger } from 'storybook/internal/node-logger';\n\nimport * as resolveUtils from '../shared/utils/module.ts';\nimport { getPresets, loadPreset, resolveAddonName } from './presets.ts';\n\nfunction wrapPreset(basePresets: any): { babel: Function; webpack: Function } {\n  return {\n    babel: async (config: any, args: any) => basePresets.apply('babel', config, args),\n    webpack: async (config: any, args: any) => basePresets.apply('webpack', config, args),\n  };\n}\n\nvi.mock('storybook/internal/node-logger', () => ({\n  logger: {\n    info: vi.fn(),\n    warn: vi.fn(),\n    error: vi.fn(),\n  },\n}));\n\nvi.mock('../shared/utils/module', () => ({\n  importModule: vi.fn(),\n  safeResolveModule: vi.fn(({ specifier }) => {\n    const KNOWN_FILES = [\n      '@storybook/react',\n      'storybook/actions/manager',\n      './local/preset',\n      './local/addons',\n      '/absolute/preset',\n      '/absolute/addons',\n      '@storybook/addon-docs',\n      '@storybook/addon-cool',\n      '@storybook/addon-docs/preset',\n      '@storybook/addon-essentials',\n      '@storybook/addon-knobs/manager',\n      '@storybook/addon-knobs/register',\n      '@storybook/addon-notes/register-panel',\n      '@storybook/preset-create-react-app',\n      '@storybook/preset-typescript',\n      'addon-bar/preset.js',\n      'addon-bar',\n      'addon-baz/register.js',\n      'addon-foo/register.js',\n    ];\n    if (KNOWN_FILES.includes(specifier)) {\n      return specifier;\n    }\n    return undefined;\n  }),\n}));\n\nconst mockedResolveUtils = vi.mocked(resolveUtils);\n\ndescribe('presets', () => {\n  it('does not throw when there is no preset file', async () => {\n    let presets;\n\n    async function testPresets() {\n      // @ts-expect-error (invalid use)\n      presets = wrapPreset(await getPresets());\n      await presets.webpack();\n      await presets.babel();\n    }\n\n    await expect(testPresets()).resolves.toBeUndefined();\n\n    expect(presets).toBeDefined();\n  });\n  it('does not throw when presets are empty', async () => {\n    // @ts-expect-error (invalid use)\n    const presets = wrapPreset(await getPresets([]));\n\n    async function testPresets() {\n      await presets.webpack();\n      await presets.babel();\n    }\n\n    await expect(testPresets()).resolves.toBeUndefined();\n  });\n\n  it('does not throw when preset can not be loaded', async () => {\n    // @ts-expect-error (invalid use)\n    const presets = wrapPreset(await getPresets(['preset-foo']));\n\n    async function testPresets() {\n      await presets.webpack();\n      await presets.babel();\n    }\n\n    await expect(testPresets()).resolves.toBeUndefined();\n  });\n\n  it('throws when preset can not be loaded and is critical', async () => {\n    // @ts-expect-error (invalid use)\n    await expect(getPresets(['preset-foo'], { isCritical: true })).rejects.toThrow();\n  });\n\n  it('loads and applies presets when they are combined in another preset', async () => {\n    mockedResolveUtils.importModule.mockImplementation(async (path: string) => {\n      if (path === 'preset-first') {\n        return {\n          aProperty: (existing: string[]) => existing.concat('first'),\n        };\n      }\n      if (path === 'preset-second') {\n        return {\n          aProperty: (existing: string[]) => existing.concat('second'),\n        };\n      }\n      if (path === 'preset-third') {\n        return {\n          presets: ['sub-preset'],\n          aProperty: (existing: string[]) => existing.concat('third'),\n        };\n      }\n      if (path === 'sub-preset') {\n        return {\n          aProperty: (existing: string[]) => existing.concat('sub-preset-fourth'),\n        };\n      }\n      if (path === 'preset-fifth') {\n        return {\n          aProperty: (existing: string[]) => existing.concat('fifth'),\n        };\n      }\n      throw new Error(`Could not resolve ${path}`);\n    });\n\n    const presets = await getPresets(\n      ['preset-first', 'preset-second', 'preset-third', 'preset-fifth'],\n      {} as any\n    );\n\n    const result = await presets.apply('aProperty', []);\n\n    expect(result).toEqual(['first', 'second', 'sub-preset-fourth', 'third', 'fifth']);\n  });\n\n  it('loads and applies presets when they are declared as a string', async () => {\n    const mockPresetFooExtendWebpack = vi.fn();\n    const mockPresetBarExtendBabel = vi.fn();\n\n    mockedResolveUtils.importModule.mockImplementation(async (path: string) => {\n      if (path === 'preset-foo') {\n        return {\n          webpack: mockPresetFooExtendWebpack,\n        };\n      }\n      if (path === 'preset-bar') {\n        return {\n          babel: mockPresetBarExtendBabel,\n        };\n      }\n      throw new Error(`Could not resolve ${path}`);\n    });\n\n    const presets = wrapPreset(await getPresets(['preset-foo', 'preset-bar'], {} as any));\n\n    async function testPresets() {\n      await presets.webpack();\n      await presets.babel();\n    }\n\n    await expect(testPresets()).resolves.toBeUndefined();\n\n    expect(mockPresetFooExtendWebpack).toHaveBeenCalled();\n    expect(mockPresetBarExtendBabel).toHaveBeenCalled();\n  });\n\n  it('loads and applies presets when they are declared as an object without props', async () => {\n    const mockPresetFooExtendWebpack = vi.fn();\n    const mockPresetBarExtendBabel = vi.fn();\n\n    mockedResolveUtils.importModule.mockImplementation(async (path: string) => {\n      if (path === 'preset-foo') {\n        return {\n          webpack: mockPresetFooExtendWebpack,\n        };\n      }\n      if (path === 'preset-bar') {\n        return {\n          babel: mockPresetBarExtendBabel,\n        };\n      }\n      throw new Error(`Could not resolve ${path}`);\n    });\n\n    const presets = wrapPreset(\n      await getPresets([{ name: 'preset-foo' }, { name: 'preset-bar' }], {} as any)\n    );\n\n    async function testPresets() {\n      await presets.webpack();\n      await presets.babel();\n    }\n\n    await expect(testPresets()).resolves.toBeUndefined();\n\n    expect(mockPresetFooExtendWebpack).toHaveBeenCalled();\n    expect(mockPresetBarExtendBabel).toHaveBeenCalled();\n  });\n\n  it('loads and applies presets when they are declared as an object with props', async () => {\n    const mockPresetFooExtendWebpack = vi.fn();\n    const mockPresetBarExtendBabel = vi.fn();\n\n    mockedResolveUtils.importModule.mockImplementation(async (path: string) => {\n      if (path === 'preset-foo') {\n        return {\n          webpack: mockPresetFooExtendWebpack,\n        };\n      }\n      if (path === 'preset-bar') {\n        return {\n          babel: mockPresetBarExtendBabel,\n        };\n      }\n      throw new Error(`Could not resolve ${path}`);\n    });\n\n    const presets = wrapPreset(\n      await getPresets(\n        [\n          { name: 'preset-foo', options: { foo: 1 } },\n          { name: 'preset-bar', options: { bar: 'a' } },\n        ],\n        {} as any\n      )\n    );\n\n    async function testPresets() {\n      await presets.webpack({});\n      await presets.babel({});\n    }\n\n    await expect(testPresets()).resolves.toBeUndefined();\n\n    expect(mockPresetFooExtendWebpack).toHaveBeenCalledWith(expect.anything(), {\n      foo: 1,\n      presetsList: expect.anything(),\n      presets: expect.anything(),\n    });\n    expect(mockPresetBarExtendBabel).toHaveBeenCalledWith(expect.anything(), {\n      bar: 'a',\n      presetsList: expect.anything(),\n      presets: expect.anything(),\n    });\n  });\n\n  it('loads and applies presets when they are declared as a string and as an object', async () => {\n    const mockPresetFooExtendWebpack = vi.fn();\n    const mockPresetBarExtendBabel = vi.fn();\n\n    mockedResolveUtils.importModule.mockImplementation(async (path: string) => {\n      if (path === 'preset-foo') {\n        return {\n          webpack: mockPresetFooExtendWebpack,\n        };\n      }\n      if (path === 'preset-bar') {\n        return {\n          babel: mockPresetBarExtendBabel,\n        };\n      }\n      throw new Error(`Could not resolve ${path}`);\n    });\n\n    const presets = wrapPreset(\n      await getPresets(\n        [\n          'preset-foo',\n          {\n            name: 'preset-bar',\n            options: {\n              bar: 'a',\n            },\n          },\n        ],\n        {} as any\n      )\n    );\n\n    async function testPresets() {\n      await presets.webpack({});\n      await presets.babel({});\n    }\n\n    await expect(testPresets()).resolves.toBeUndefined();\n\n    expect(mockPresetFooExtendWebpack).toHaveBeenCalled();\n    expect(mockPresetBarExtendBabel).toHaveBeenCalledWith(expect.anything(), {\n      bar: 'a',\n      presetsList: expect.arrayContaining([\n        expect.objectContaining({ name: 'preset-foo' }),\n        expect.objectContaining({ name: 'preset-bar' }),\n      ]),\n      presets: expect.anything(),\n    });\n  });\n\n  it('applies presets in chain', async () => {\n    const mockPresetFooExtendWebpack = vi.fn((...args: any[]) => ({}));\n    const mockPresetBarExtendWebpack = vi.fn((...args: any[]) => ({}));\n\n    mockedResolveUtils.importModule.mockImplementation(async (path: string) => {\n      if (path === 'preset-foo') {\n        return {\n          webpack: mockPresetFooExtendWebpack,\n        };\n      }\n      if (path === 'preset-bar') {\n        return {\n          webpack: mockPresetBarExtendWebpack,\n        };\n      }\n      throw new Error(`Could not resolve ${path}`);\n    });\n\n    const presets = wrapPreset(\n      await getPresets(\n        [\n          'preset-foo',\n          {\n            name: 'preset-bar',\n            options: {\n              bar: 'a',\n              presetsList: expect.arrayContaining([\n                expect.objectContaining({ name: 'preset-foo' }),\n                expect.objectContaining({ name: 'preset-bar' }),\n              ]),\n              presets: expect.anything(),\n            },\n          },\n        ],\n        {} as any\n      )\n    );\n\n    async function testPresets() {\n      await presets.webpack();\n      await presets.babel();\n    }\n\n    await expect(testPresets()).resolves.toBeUndefined();\n\n    expect(mockPresetFooExtendWebpack).toHaveBeenCalled();\n    expect(mockPresetBarExtendWebpack).toHaveBeenCalledWith(expect.anything(), {\n      bar: 'a',\n      presetsList: expect.arrayContaining([\n        expect.objectContaining({ name: 'preset-foo' }),\n        expect.objectContaining({ name: 'preset-bar' }),\n      ]),\n      presets: expect.anything(),\n    });\n  });\n\n  it('allows for presets to export presets array', async () => {\n    const input = {};\n    const mockPresetBar = vi.fn((...args: any[]) => input);\n\n    mockedResolveUtils.importModule.mockImplementation(async (path: string) => {\n      if (path === 'preset-foo') {\n        return {\n          presets: ['preset-bar'],\n        };\n      }\n      if (path === 'preset-bar') {\n        return {\n          bar: mockPresetBar,\n        };\n      }\n      throw new Error(`Could not resolve ${path}`);\n    });\n\n    const presets = await getPresets(['preset-foo'], {} as any);\n\n    const output = await presets.apply('bar');\n\n    expect(mockPresetBar).toHaveBeenCalledWith(undefined, expect.any(Object));\n\n    expect(input).toBe(output);\n  });\n\n  it('allows for presets to export presets fn', async () => {\n    const input = {};\n    const storybookOptions = { a: 1 };\n    const presetOptions = { b: 2 };\n    const mockPresetBar = vi.fn((...args: any[]) => input);\n    const mockPresetFoo = vi.fn((...args: any[]) => ['preset-bar']);\n\n    mockedResolveUtils.importModule.mockImplementation(async (path: string) => {\n      if (path === 'preset-foo') {\n        return {\n          presets: mockPresetFoo,\n        };\n      }\n      if (path === 'preset-bar') {\n        return {\n          bar: mockPresetBar,\n        };\n      }\n      throw new Error(`Could not resolve ${path}`);\n    });\n\n    const presets = await getPresets(\n      [{ name: 'preset-foo', options: { b: 2 } }],\n      storybookOptions as any\n    );\n\n    const output = await presets.apply('bar');\n\n    expect(mockPresetFoo).toHaveBeenCalledWith({ ...storybookOptions, ...presetOptions });\n    expect(mockPresetBar).toHaveBeenCalledWith(undefined, expect.any(Object));\n\n    expect(input).toBe(output);\n  });\n\n  afterEach(() => {\n    vi.resetModules();\n  });\n});\ndescribe('resolveAddonName', () => {\n  it('should resolve packages with metadata (relative path)', () => {\n    mockedResolveUtils.importModule.mockImplementation(async (path: string) => {\n      if (path === './local/preset') {\n        return {\n          presets: [],\n        };\n      }\n      throw new Error(`Could not resolve ${path}`);\n    });\n    expect(resolveAddonName({} as any, './local/preset', {})).toEqual({\n      name: './local/preset',\n      type: 'presets',\n    });\n  });\n\n  it('should resolve packages with metadata (absolute path)', () => {\n    mockedResolveUtils.importModule.mockImplementation(async (path: string) => {\n      if (path === '/absolute/preset') {\n        return {\n          presets: [],\n        };\n      }\n      throw new Error(`Could not resolve ${path}`);\n    });\n    expect(resolveAddonName({} as any, '/absolute/preset', {})).toEqual({\n      name: '/absolute/preset',\n      type: 'presets',\n    });\n  });\n\n  it('should resolve packages without metadata', () => {\n    expect(resolveAddonName({} as any, '@storybook/preset-create-react-app', {})).toEqual({\n      name: '@storybook/preset-create-react-app',\n      type: 'presets',\n    });\n  });\n\n  it('should resolve presets', () => {\n    expect(resolveAddonName({} as any, '@storybook/addon-docs/preset', {})).toEqual({\n      name: '@storybook/addon-docs/preset',\n      type: 'presets',\n    });\n  });\n\n  it('should resolve preset packages', () => {\n    expect(resolveAddonName({} as any, '@storybook/addon-essentials', {})).toEqual({\n      name: '@storybook/addon-essentials',\n      type: 'presets',\n    });\n  });\n});\n\ndescribe('loadPreset', () => {\n  beforeEach(() => {\n    vi.spyOn(logger, 'warn');\n    mockedResolveUtils.importModule.mockImplementation(async (path: string) => {\n      switch (path) {\n        case '@storybook/react':\n        case '@storybook/preset-typescript':\n        case '@storybook/addon-docs/preset':\n        case 'addon-foo/register.js':\n        case '@storybook/addon-cool':\n        case 'addon-baz/register.js':\n        case '@storybook/addon-notes/register-panel':\n          return {};\n        case 'addon-bar':\n          return {\n            addons: ['@storybook/addon-cool'],\n            presets: [],\n          };\n      }\n      throw new Error(`Could not resolve ${path}`);\n    });\n  });\n\n  it('should prepend framework field to list of presets', async () => {\n    const loaded = await loadPreset(\n      {\n        name: '',\n        // @ts-expect-error (invalid use)\n        type: 'virtual',\n        framework: '@storybook/react',\n        presets: ['@storybook/preset-typescript'],\n        addons: ['@storybook/addon-docs/preset'],\n      },\n      0,\n      {}\n    );\n    expect(loaded).toMatchInlineSnapshot(`\n      [\n        {\n          \"name\": \"@storybook/preset-typescript\",\n          \"options\": {},\n          \"preset\": {},\n        },\n        {\n          \"name\": \"@storybook/addon-docs/preset\",\n          \"options\": {},\n          \"preset\": {},\n        },\n        {\n          \"name\": {\n            \"addons\": [\n              \"@storybook/addon-docs/preset\",\n            ],\n            \"framework\": \"@storybook/react\",\n            \"name\": \"\",\n            \"presets\": [\n              \"@storybook/preset-typescript\",\n            ],\n            \"type\": \"virtual\",\n          },\n          \"options\": {},\n          \"preset\": {\n            \"framework\": \"@storybook/react\",\n          },\n        },\n      ]\n    `);\n  });\n\n  it.skip('should resolve all addons & presets in correct order', async () => {\n    const loaded = await loadPreset(\n      {\n        name: '',\n        // @ts-expect-error (invalid use)\n        type: 'virtual',\n        presets: ['@storybook/preset-typescript'],\n        addons: [\n          '@storybook/addon-docs/preset',\n          'addon-foo/register.js',\n          'addon-bar',\n          'addon-baz/register.js',\n          '@storybook/addon-notes/register-panel',\n        ],\n      },\n      0,\n      {}\n    );\n    expect(loaded).toEqual([\n      {\n        name: '@storybook/preset-typescript',\n        options: {},\n        preset: {},\n      },\n      {\n        name: '@storybook/addon-docs/preset',\n        options: {},\n        preset: {},\n      },\n      {\n        name: 'addon-foo/register.js',\n        options: {},\n        preset: {\n          managerEntries: [normalize('addon-foo/register')],\n        },\n      },\n      {\n        name: '@storybook/addon-cool',\n        options: {},\n        preset: {},\n      },\n      {\n        name: 'addon-bar',\n        options: {},\n        preset: {},\n      },\n      {\n        name: 'addon-baz/register.js',\n        options: {},\n        preset: {\n          managerEntries: [normalize('addon-baz/register')],\n        },\n      },\n      {\n        name: '@storybook/addon-notes/register-panel',\n        options: {},\n        preset: {\n          managerEntries: [normalize('@storybook/addon-notes/register-panel')],\n        },\n      },\n      {\n        name: {\n          presets: ['@storybook/preset-typescript'],\n          addons: [\n            '@storybook/addon-docs/preset',\n            'addon-foo/register.js',\n            'addon-bar',\n            'addon-baz/register.js',\n            '@storybook/addon-notes/register-panel',\n          ],\n          name: '',\n          type: 'virtual',\n        },\n        options: {},\n        preset: {},\n      },\n    ]);\n  });\n\n  it('should warn for addons that are not installed', async () => {\n    const loaded = await loadPreset(\n      {\n        name: '',\n        // @ts-expect-error (invalid use)\n        type: 'virtual',\n        framework: '@storybook/react',\n        presets: ['@storybook/preset-typescript'],\n        addons: ['@storybook/addon-docs/preset', 'uninstalled-addon'],\n      },\n      0,\n      {}\n    );\n    expect(logger.warn).toHaveBeenCalledWith(\n      'Could not resolve addon \"uninstalled-addon\", skipping. Is it installed?'\n    );\n    expect(loaded).toMatchInlineSnapshot(`\n      [\n        {\n          \"name\": \"@storybook/preset-typescript\",\n          \"options\": {},\n          \"preset\": {},\n        },\n        {\n          \"name\": \"@storybook/addon-docs/preset\",\n          \"options\": {},\n          \"preset\": {},\n        },\n        {\n          \"name\": {\n            \"addons\": [\n              \"@storybook/addon-docs/preset\",\n              \"uninstalled-addon\",\n            ],\n            \"framework\": \"@storybook/react\",\n            \"name\": \"\",\n            \"presets\": [\n              \"@storybook/preset-typescript\",\n            ],\n            \"type\": \"virtual\",\n          },\n          \"options\": {},\n          \"preset\": {\n            \"framework\": \"@storybook/react\",\n          },\n        },\n      ]\n    `);\n  });\n\n  it('should filter out disabledAddons', async () => {\n    const loaded = await loadPreset(\n      {\n        name: '',\n        // @ts-expect-error (invalid use)\n        type: 'virtual',\n        framework: '@storybook/react',\n        presets: ['@storybook/preset-typescript'],\n        addons: ['@storybook/addon-docs', 'addon-bar'],\n      },\n      0,\n      {\n        build: {\n          test: {\n            disabledAddons: ['@storybook/addon-docs'],\n          },\n        },\n      }\n    );\n\n    // addon-docs should not be at the top level, but addon-bar and others should be.\n    expect(loaded).toMatchInlineSnapshot(`\n      [\n        {\n          \"name\": \"@storybook/preset-typescript\",\n          \"options\": {},\n          \"preset\": {},\n        },\n        {\n          \"name\": \"@storybook/addon-cool\",\n          \"options\": {},\n          \"preset\": {},\n        },\n        {\n          \"name\": \"addon-bar\",\n          \"options\": {},\n          \"preset\": {},\n        },\n        {\n          \"name\": {\n            \"addons\": [\n              \"@storybook/addon-docs\",\n              \"addon-bar\",\n            ],\n            \"framework\": \"@storybook/react\",\n            \"name\": \"\",\n            \"presets\": [\n              \"@storybook/preset-typescript\",\n            ],\n            \"type\": \"virtual\",\n          },\n          \"options\": {},\n          \"preset\": {\n            \"framework\": \"@storybook/react\",\n          },\n        },\n      ]\n    `);\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/presets.ts",
    "content": "import { logger } from 'storybook/internal/node-logger';\nimport { CriticalPresetLoadError } from 'storybook/internal/server-errors';\nimport type {\n  BuilderOptions,\n  CLIOptions,\n  CoreCommon_ResolvedAddonPreset,\n  CoreCommon_ResolvedAddonVirtual,\n  LoadOptions,\n  LoadedPreset,\n  PresetConfig,\n  Presets,\n  StorybookConfigRaw,\n} from 'storybook/internal/types';\n\nimport { join, parse, resolve } from 'pathe';\nimport { dedent } from 'ts-dedent';\n\nimport type { ChannelLike } from '../channels/index.ts';\nimport { importModule, safeResolveModule } from '../shared/utils/module.ts';\nimport { getInterpretedFile } from './utils/interpret-files.ts';\nimport { stripAbsNodeModulesPath } from './utils/strip-abs-node-modules-path.ts';\nimport { validateConfigurationFiles } from './utils/validate-configuration-files.ts';\n\nexport type InterPresetOptions = Omit<\n  CLIOptions &\n    LoadOptions &\n    BuilderOptions & { isCritical?: boolean; build?: StorybookConfigRaw['build'] },\n  'frameworkPresets'\n>;\n\nconst isObject = (val: unknown): val is Record<string, any> =>\n  val != null && typeof val === 'object' && Array.isArray(val) === false;\nconst isFunction = (val: unknown): val is Function => typeof val === 'function';\n\nexport function filterPresetsConfig(presetsConfig: PresetConfig[]): PresetConfig[] {\n  return presetsConfig.filter((preset) => {\n    const presetName = typeof preset === 'string' ? preset : preset.name;\n    return !/@storybook[\\\\\\\\/]preset-typescript/.test(presetName);\n  });\n}\n\nfunction resolvePresetFunction<T = any>(\n  input: T[] | Function,\n  presetOptions: any,\n  storybookOptions: InterPresetOptions\n): T[] {\n  if (isFunction(input)) {\n    return [...input({ ...storybookOptions, ...presetOptions })];\n  }\n  if (Array.isArray(input)) {\n    return [...input];\n  }\n\n  return [];\n}\n\n/**\n * Parse an addon into either a managerEntries or a preset. Throw on invalid input.\n *\n * Valid inputs:\n *\n * - `'@storybook/addon-docs/preset' => { type: 'presets', item }`\n * - `'@storybook/addon-docs' => { type: 'presets', item: '@storybook/addon-docs/preset' }`\n * - `{ name: '@storybook/addon-docs(/preset)?', options: { } } => { type: 'presets', item: { name:\n *   '@storybook/addon-docs/preset', options } }`\n */\n\nexport const resolveAddonName = (\n  configDir: string,\n  name: string,\n  options: any\n): CoreCommon_ResolvedAddonPreset | CoreCommon_ResolvedAddonVirtual | undefined => {\n  const resolved = safeResolveModule({ specifier: name, parent: configDir });\n\n  if (resolved && parse(name).name === 'preset') {\n    return {\n      type: 'presets',\n      name: resolved,\n    };\n  }\n\n  const presetFile = safeResolveModule({ specifier: join(name, 'preset'), parent: configDir });\n  const managerFile = safeResolveModule({ specifier: join(name, 'manager'), parent: configDir });\n  const previewFile = safeResolveModule({ specifier: join(name, 'preview'), parent: configDir });\n\n  if (managerFile || previewFile || presetFile) {\n    const previewAnnotations = [];\n    if (previewFile) {\n      const parsedPreviewFile = stripAbsNodeModulesPath(previewFile);\n      if (parsedPreviewFile !== previewFile) {\n        previewAnnotations.push({\n          bare: parsedPreviewFile,\n          absolute: previewFile,\n        });\n      } else {\n        previewAnnotations.push(previewFile);\n      }\n    }\n    return {\n      type: 'virtual',\n      name,\n      presets: presetFile ? [{ name: presetFile, options }] : [],\n      managerEntries: managerFile ? [managerFile] : [],\n      previewAnnotations,\n    };\n  }\n\n  if (resolved) {\n    return {\n      type: 'presets',\n      name: resolved,\n    };\n  }\n\n  return undefined;\n};\n\nconst map =\n  ({ configDir }: InterPresetOptions) =>\n  (item: any) => {\n    const options = isObject(item) ? item['options'] || undefined : undefined;\n    const name = isObject(item) ? item['name'] : item;\n\n    let resolved;\n\n    try {\n      resolved = resolveAddonName(configDir, name, options);\n    } catch (err) {\n      logger.error(\n        `Addon value should end in /manager or /preview or /register OR it should be a valid preset https://storybook.js.org/docs/addons/writing-presets/\\n${item}`\n      );\n      return undefined;\n    }\n\n    if (!resolved) {\n      logger.warn(`Could not resolve addon \"${name}\", skipping. Is it installed?`);\n      return undefined;\n    }\n\n    return {\n      ...(options ? { options } : {}),\n      ...resolved,\n    };\n  };\n\nasync function getContent(input: any) {\n  if (input.type === 'virtual') {\n    const { type, name, ...rest } = input;\n    return rest;\n  }\n  const name = input.name ? input.name : input;\n\n  return importModule(name);\n}\n\nexport async function loadPreset(\n  input: PresetConfig,\n  level: number,\n  storybookOptions: InterPresetOptions\n): Promise<LoadedPreset[]> {\n  // @ts-expect-error (Converted from ts-ignore)\n  const presetName: string = input.name ? input.name : input;\n\n  try {\n    // @ts-expect-error (Converted from ts-ignore)\n    const presetOptions = input.options ? input.options : {};\n\n    let contents = await getContent(input);\n\n    if (typeof contents === 'function') {\n      // allow the export of a preset to be a function, that gets storybookOptions\n      contents = contents(storybookOptions, presetOptions);\n    }\n\n    if (Array.isArray(contents)) {\n      const subPresets = contents;\n      return await loadPresets(subPresets, level + 1, storybookOptions);\n    }\n\n    if (isObject(contents)) {\n      const { addons: addonsInput = [], presets: presetsInput = [], ...rest } = contents;\n\n      let filter = (i: PresetConfig) => {\n        return true;\n      };\n\n      if (\n        storybookOptions.isCritical !== true &&\n        (storybookOptions.build?.test?.disabledAddons?.length || 0) > 0\n      ) {\n        filter = (i: PresetConfig) => {\n          // @ts-expect-error (Converted from ts-ignore)\n          const name = i.name ? i.name : i;\n\n          return !storybookOptions.build?.test?.disabledAddons?.find((n) => name.includes(n));\n        };\n      }\n\n      const subPresets = resolvePresetFunction(\n        presetsInput,\n        presetOptions,\n        storybookOptions\n      ).filter(filter);\n      const subAddons = resolvePresetFunction(addonsInput, presetOptions, storybookOptions).filter(\n        filter\n      );\n\n      return [\n        ...(await loadPresets([...subPresets], level + 1, storybookOptions)),\n        ...(await loadPresets(\n          [...subAddons.map(map(storybookOptions))].filter(Boolean) as PresetConfig[],\n          level + 1,\n          storybookOptions\n        )),\n        {\n          name: presetName,\n          preset: rest,\n          options: presetOptions,\n        },\n      ];\n    }\n\n    throw new Error(dedent`\n      ${input} is not a valid preset\n    `);\n  } catch (error: any) {\n    if (storybookOptions?.isCritical) {\n      throw new CriticalPresetLoadError({\n        error,\n        presetName,\n      });\n    }\n\n    const warning =\n      level > 0\n        ? `  Failed to load preset: ${JSON.stringify(input)} on level ${level}`\n        : `  Failed to load preset: ${JSON.stringify(input)}`;\n\n    logger.warn(warning);\n    logger.error(error);\n    return [];\n  }\n}\n\nasync function loadPresets(\n  presets: PresetConfig[],\n  level: number,\n  storybookOptions: InterPresetOptions\n): Promise<LoadedPreset[]> {\n  if (!presets || !Array.isArray(presets) || !presets.length) {\n    return [];\n  }\n\n  return (\n    await Promise.all(\n      presets.map(async (preset) => {\n        return loadPreset(preset, level, storybookOptions);\n      })\n    )\n  ).reduce((acc, loaded) => {\n    return acc.concat(loaded);\n  }, []);\n}\n\nfunction applyPresets(\n  presets: LoadedPreset[],\n  extension: string,\n  config: any,\n  args: any,\n  storybookOptions: InterPresetOptions\n): Promise<any> {\n  const presetResult = new Promise((res) => res(config));\n\n  if (!presets.length) {\n    return presetResult;\n  }\n\n  return presets.reduce((accumulationPromise: Promise<unknown>, { preset, options }) => {\n    const change = preset[extension];\n\n    if (!change) {\n      return accumulationPromise;\n    }\n\n    if (typeof change === 'function') {\n      const extensionFn = change;\n      const context = {\n        preset,\n        combinedOptions: {\n          ...storybookOptions,\n          ...args,\n          ...options,\n          presetsList: presets,\n          presets: {\n            apply: async (ext: string, c: any, a = {}) =>\n              applyPresets(presets, ext, c, a, storybookOptions),\n          },\n        },\n      };\n\n      return accumulationPromise.then((newConfig) =>\n        extensionFn.call(context.preset, newConfig, context.combinedOptions)\n      );\n    }\n\n    return accumulationPromise.then((newConfig) => {\n      if (Array.isArray(newConfig) && Array.isArray(change)) {\n        return [...newConfig, ...change];\n      }\n      if (isObject(newConfig) && isObject(change)) {\n        return { ...newConfig, ...change };\n      }\n      return change;\n    });\n  }, presetResult);\n}\n\nexport async function getPresets(\n  presets: PresetConfig[],\n  storybookOptions: InterPresetOptions\n): Promise<Presets> {\n  const loadedPresets: LoadedPreset[] = await loadPresets(presets, 0, storybookOptions);\n\n  return {\n    apply: async (extension: string, config?: any, args = {}) =>\n      applyPresets(loadedPresets, extension, config, args, storybookOptions),\n  };\n}\n\nexport async function loadAllPresets(\n  options: CLIOptions &\n    LoadOptions &\n    BuilderOptions & {\n      corePresets: PresetConfig[];\n      overridePresets: PresetConfig[];\n      /** Whether preset failures should be critical or not */\n      isCritical?: boolean;\n      build?: StorybookConfigRaw['build'];\n      channel: ChannelLike;\n    }\n) {\n  const { corePresets = [], overridePresets = [], ...restOptions } = options;\n  validateConfigurationFiles(options.configDir);\n\n  const mainUrl = getInterpretedFile(resolve(options.configDir, 'main')) as string;\n  const presetsConfig: PresetConfig[] = [...corePresets, mainUrl, ...overridePresets];\n\n  // Remove `@storybook/preset-typescript` and add a warning if in use.\n  const filteredPresetConfig = filterPresetsConfig(presetsConfig);\n  if (filteredPresetConfig.length < presetsConfig.length) {\n    logger.warn(\n      'Storybook now supports TypeScript natively. You can safely remove `@storybook/preset-typescript`.'\n    );\n  }\n\n  return getPresets(filteredPresetConfig, restOptions);\n}\n"
  },
  {
    "path": "code/core/src/common/satellite-addons.ts",
    "content": "// Storybook packages that are not part of the monorepo but we maintain.\nexport default [\n  '@storybook/test-runner',\n  '@chromatic-com/storybook',\n  '@storybook/addon-designs',\n  '@storybook/addon-svelte-csf',\n  '@storybook/addon-coverage',\n  '@storybook/addon-webpack5-compiler-babel',\n  '@storybook/addon-webpack5-compiler-swc',\n  // Storybook for React Native related packages\n  // TODO: For Storybook 10, we should check about possible automigrations\n  '@storybook/addon-ondevice-actions',\n  '@storybook/addon-ondevice-backgrounds',\n  '@storybook/addon-ondevice-controls',\n  '@storybook/addon-ondevice-notes',\n  '@storybook/react-native',\n];\n"
  },
  {
    "path": "code/core/src/common/utils/HandledError.ts",
    "content": "export class HandledError extends Error {\n  public handled = true;\n\n  constructor(error: unknown) {\n    super(String(error));\n\n    if (typeof error !== 'string') {\n      this.cause = error;\n    }\n  }\n}\n"
  },
  {
    "path": "code/core/src/common/utils/__snapshots__/formatter.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`formatter > withPrettierConfig > prettier > formats content with prettier 1`] = `\n\"\nimport type { Meta, StoryObj } from '@storybook/nextjs'\n\nimport Component from './foo';\n\n  const meta = {\n    component: Component\n  } satisfies Meta<typeof Component>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\"\n`;\n\nexports[`formatter > withoutPrettierConfigAndWithEditorConfig > prettier-v3 > formats content with prettier 1`] = `\n\"\nimport type { Meta, StoryObj } from '@storybook/nextjs'\n\nimport Component from './foo';\n\n  const meta = {\n    component: Component\n  } satisfies Meta<typeof Component>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\"\n`;\n"
  },
  {
    "path": "code/core/src/common/utils/__tests-formatter__/withPrettierConfig/.prettierrc",
    "content": "{\n  \"trailingComma\": \"es5\",\n  \"tabWidth\": 4,\n  \"semi\": true,\n  \"singleQuote\": true\n}\n"
  },
  {
    "path": "code/core/src/common/utils/__tests-formatter__/withoutEditorConfig/.editorconfig",
    "content": "root = true\n\n[*]\n"
  },
  {
    "path": "code/core/src/common/utils/__tests-formatter__/withoutEditorConfig/.prettierrc",
    "content": ""
  },
  {
    "path": "code/core/src/common/utils/__tests-formatter__/withoutPrettierConfig/.editorconfig",
    "content": "root = true\n\n[*]\nend_of_line = lf\ninsert_final_newline = true\nindent_style = space\nindent_size = 6\n\n"
  },
  {
    "path": "code/core/src/common/utils/__tests-formatter__/withoutPrettierConfig/.prettierrc",
    "content": ""
  },
  {
    "path": "code/core/src/common/utils/__tests__/interpret-files.test.ts",
    "content": "import { afterEach, describe, expect, it, vi } from 'vitest';\n\nimport { vol } from 'memfs';\n\nimport { getInterpretedFile } from '../interpret-files.ts';\n\nvi.mock('fs', async () => {\n  const memfs = await vi.importActual('memfs');\n\n  return { default: memfs.fs, ...(memfs as any).fs };\n});\n\ndescribe('interpret-files', () => {\n  it('will interpret file as file.ts when it exists in fs', () => {\n    vol.fromNestedJSON({\n      'path/to/file.ts': 'ts file contents',\n    });\n\n    const file = getInterpretedFile('path/to/file');\n\n    expect(file).toEqual('path/to/file.ts');\n  });\n\n  it('will interpret file as file.js when both are in fs', () => {\n    vol.fromNestedJSON({\n      'path/to/file.js': 'js file contents',\n      'path/to/file.ts': 'ts file contents',\n    });\n\n    const file = getInterpretedFile('path/to/file');\n\n    expect(file).toEqual('path/to/file.js');\n  });\n\n  it('will interpret file even if extension is already present', () => {\n    vol.fromNestedJSON({\n      'path/to/file.js': 'js file contents',\n      'path/to/file.ts': 'ts file contents',\n    });\n\n    const file = getInterpretedFile('path/to/file.js');\n\n    expect(file).toEqual('path/to/file.js');\n  });\n\n  it('will return undefined if there is no candidate of a file in fs', () => {\n    vol.fromNestedJSON({\n      'path/to/file.js': 'js file contents',\n    });\n\n    const file = getInterpretedFile('path/to/file2');\n\n    expect(file).toBeUndefined();\n  });\n\n  it('will interpret file as file.mts when it exists in fs', () => {\n    vol.fromNestedJSON({\n      'path/to/file.mts': 'ts file contents',\n    });\n\n    const file = getInterpretedFile('path/to/file');\n\n    expect(file).toEqual('path/to/file.mts');\n  });\n\n  it('will interpret file as file.cts when it exists in fs', () => {\n    vol.fromNestedJSON({\n      'path/to/file.cts': 'ts file contents',\n    });\n\n    const file = getInterpretedFile('path/to/file');\n\n    expect(file).toEqual('path/to/file.cts');\n  });\n\n  afterEach(() => vol.reset());\n});\n"
  },
  {
    "path": "code/core/src/common/utils/__tests__/normalize-stories.test.ts",
    "content": "/// <reference types=\"@testing-library/jest-dom\" />\nimport { sep } from 'node:path';\n\nimport { describe, expect, it, vi } from 'vitest';\n\nimport { InvalidStoriesEntryError } from 'storybook/internal/server-errors';\n\nimport {\n  getDirectoryFromWorkingDir,\n  normalizeStories,\n  normalizeStoriesEntry,\n} from '../normalize-stories.ts';\n\nexpect.addSnapshotSerializer({\n  print: (val: any) => JSON.stringify(val, null, 2),\n  test: (val) => typeof val !== 'string',\n});\n\nvi.mock('node:fs', () => {\n  const mockStat = (\n    path: string,\n    options: Record<string, any>,\n    cb: (error?: Error, stats?: Record<string, any>) => void\n  ) => {\n    cb(undefined, {\n      isDirectory: () => !path.match(/\\.[a-z]+$/),\n    });\n  };\n\n  return {\n    access: (path: string, mode: number, cb: (err?: Error) => void): void => undefined,\n    lstatSync: (path: string) => ({\n      isDirectory: () => !path.match(/\\.[a-z]+$/),\n    }),\n    stat: mockStat,\n    lstat: mockStat,\n  };\n});\n\nconst options = {\n  configDir: '/path/to/project/.storybook',\n  workingDir: '/path/to/project',\n};\n\ndescribe('normalizeStoriesEntry', () => {\n  it('direct file path', () => {\n    const specifier = normalizeStoriesEntry('../path/to/file.stories.jsx', options);\n    expect(specifier).toMatchInlineSnapshot(`\n      {\n        \"titlePrefix\": \"\",\n        \"directory\": \"./path/to\",\n        \"files\": \"file.stories.jsx\",\n        \"importPathMatcher\": {}\n      }\n    `);\n\n    expect(specifier.importPathMatcher).toMatchPaths(['./path/to/file.stories.jsx']);\n    expect(specifier.importPathMatcher).not.toMatchPaths([\n      './path/to/file.stories.js',\n      './file.stories.jsx',\n      '../file.stories.jsx',\n    ]);\n  });\n\n  it('story in config dir', () => {\n    const specifier = normalizeStoriesEntry('./file.stories.jsx', options);\n    expect(specifier).toMatchInlineSnapshot(`\n      {\n        \"titlePrefix\": \"\",\n        \"directory\": \"./.storybook\",\n        \"files\": \"file.stories.jsx\",\n        \"importPathMatcher\": {}\n      }\n    `);\n\n    expect(specifier.importPathMatcher).toMatchPaths(['./.storybook/file.stories.jsx']);\n    expect(specifier.importPathMatcher).not.toMatchPaths([\n      '.storybook/file.stories.jsx',\n      './file.stories.jsx',\n      '../file.stories.jsx',\n    ]);\n  });\n\n  it('non-recursive files glob', () => {\n    const specifier = normalizeStoriesEntry('../*/*.stories.jsx', options);\n    expect(specifier).toMatchInlineSnapshot(`\n      {\n        \"titlePrefix\": \"\",\n        \"directory\": \".\",\n        \"files\": \"*/*.stories.jsx\",\n        \"importPathMatcher\": {}\n      }\n    `);\n\n    expect(specifier.importPathMatcher).toMatchPaths([\n      './path/file.stories.jsx',\n      './second-path/file.stories.jsx',\n    ]);\n    expect(specifier.importPathMatcher).not.toMatchPaths([\n      './path/file.stories.js',\n      './path/to/file.stories.jsx',\n      './file.stories.jsx',\n      '../file.stories.jsx',\n    ]);\n  });\n\n  it('double non-recursive directory/files glob', () => {\n    const specifier = normalizeStoriesEntry('../*/*/*.stories.jsx', options);\n    expect(specifier).toMatchInlineSnapshot(`\n      {\n        \"titlePrefix\": \"\",\n        \"directory\": \".\",\n        \"files\": \"*/*/*.stories.jsx\",\n        \"importPathMatcher\": {}\n      }\n    `);\n\n    expect(specifier.importPathMatcher).toMatchPaths([\n      './path/to/file.stories.jsx',\n      './second-path/to/file.stories.jsx',\n    ]);\n    expect(specifier.importPathMatcher).not.toMatchPaths([\n      './file.stories.jsx',\n      './path/file.stories.jsx',\n      './path/to/third/file.stories.jsx',\n      './path/to/file.stories.js',\n      '../file.stories.jsx',\n    ]);\n  });\n\n  it('directory/files glob', () => {\n    const specifier = normalizeStoriesEntry('../**/*.stories.jsx', options);\n    expect(specifier).toMatchInlineSnapshot(`\n      {\n        \"titlePrefix\": \"\",\n        \"directory\": \".\",\n        \"files\": \"**/*.stories.jsx\",\n        \"importPathMatcher\": {}\n      }\n    `);\n    expect(specifier.importPathMatcher).toMatchPaths([\n      './file.stories.jsx',\n      './path/file.stories.jsx',\n      './path/to/file.stories.jsx',\n      './path/to/third/file.stories.jsx',\n    ]);\n    expect(specifier.importPathMatcher).not.toMatchPaths([\n      './file.stories.js',\n      '../file.stories.jsx',\n    ]);\n  });\n\n  it('double stars glob', () => {\n    const specifier = normalizeStoriesEntry('../**/foo/**/*.stories.jsx', options);\n    expect(specifier).toMatchInlineSnapshot(`\n      {\n        \"titlePrefix\": \"\",\n        \"directory\": \".\",\n        \"files\": \"**/foo/**/*.stories.jsx\",\n        \"importPathMatcher\": {}\n      }\n    `);\n\n    expect(specifier.importPathMatcher).toMatchPaths([\n      './foo/file.stories.jsx',\n      './path/to/foo/file.stories.jsx',\n      './path/to/foo/third/fourth/file.stories.jsx',\n    ]);\n    expect(specifier.importPathMatcher).not.toMatchPaths([\n      './file.stories.jsx',\n      './file.stories.js',\n      '../file.stories.jsx',\n    ]);\n  });\n\n  it('intermediate directory glob', () => {\n    const specifier = normalizeStoriesEntry('../**/foo/*.stories.jsx', options);\n    expect(specifier).toMatchInlineSnapshot(`\n      {\n        \"titlePrefix\": \"\",\n        \"directory\": \".\",\n        \"files\": \"**/foo/*.stories.jsx\",\n        \"importPathMatcher\": {}\n      }\n    `);\n\n    expect(specifier.importPathMatcher).toMatchPaths([\n      './path/to/foo/file.stories.jsx',\n      './foo/file.stories.jsx',\n    ]);\n    expect(specifier.importPathMatcher).not.toMatchPaths([\n      './file.stories.jsx',\n      './file.stories.js',\n      './path/to/foo/third/fourth/file.stories.jsx',\n      '../file.stories.jsx',\n    ]);\n  });\n\n  it('directory outside of working dir', () => {\n    const specifier = normalizeStoriesEntry('../../src/*.stories.jsx', options);\n    expect(specifier).toMatchInlineSnapshot(`\n      {\n        \"titlePrefix\": \"\",\n        \"directory\": \"../src\",\n        \"files\": \"*.stories.jsx\",\n        \"importPathMatcher\": {}\n      }\n    `);\n\n    expect(specifier.importPathMatcher).toMatchPaths(['../src/file.stories.jsx']);\n    expect(specifier.importPathMatcher).not.toMatchPaths([\n      './src/file.stories.jsx',\n      '../src/file.stories.js',\n    ]);\n  });\n\n  it('directory', () => {\n    const specifier = normalizeStoriesEntry('..', options);\n    expect(specifier).toMatchInlineSnapshot(`\n      {\n        \"titlePrefix\": \"\",\n        \"directory\": \".\",\n        \"files\": \"**/*.@(mdx|stories.@(js|jsx|mjs|ts|tsx))\",\n        \"importPathMatcher\": {}\n      }\n    `);\n  });\n\n  it('directory specifier', () => {\n    const specifier = normalizeStoriesEntry({ directory: '..' }, options);\n    expect(specifier).toMatchInlineSnapshot(`\n      {\n        \"titlePrefix\": \"\",\n        \"files\": \"**/*.@(mdx|stories.@(js|jsx|mjs|ts|tsx))\",\n        \"directory\": \".\",\n        \"importPathMatcher\": {}\n      }\n    `);\n  });\n\n  it('directory/files specifier', () => {\n    const specifier = normalizeStoriesEntry({ directory: '..', files: '*.stories.jsx' }, options);\n    expect(specifier).toMatchInlineSnapshot(`\n      {\n        \"titlePrefix\": \"\",\n        \"files\": \"*.stories.jsx\",\n        \"directory\": \".\",\n        \"importPathMatcher\": {}\n      }\n    `);\n  });\n\n  it('directory/titlePrefix specifier', () => {\n    const specifier = normalizeStoriesEntry({ directory: '..', titlePrefix: 'atoms' }, options);\n    expect(specifier).toMatchInlineSnapshot(`\n      {\n        \"titlePrefix\": \"atoms\",\n        \"files\": \"**/*.@(mdx|stories.@(js|jsx|mjs|ts|tsx))\",\n        \"directory\": \".\",\n        \"importPathMatcher\": {}\n      }\n    `);\n  });\n\n  it('directory/titlePrefix/files specifier', () => {\n    const specifier = normalizeStoriesEntry(\n      { directory: '..', titlePrefix: 'atoms', files: '*.stories.jsx' },\n      options\n    );\n    expect(specifier).toMatchInlineSnapshot(`\n      {\n        \"titlePrefix\": \"atoms\",\n        \"files\": \"*.stories.jsx\",\n        \"directory\": \".\",\n        \"importPathMatcher\": {}\n      }\n    `);\n  });\n\n  it('globs with negation', () => {\n    const specifier = normalizeStoriesEntry('../!(negation)/*.stories.jsx', options);\n    expect(specifier).toMatchInlineSnapshot(`\n      {\n        \"titlePrefix\": \"\",\n        \"directory\": \".\",\n        \"files\": \"!(negation)/*.stories.jsx\",\n        \"importPathMatcher\": {}\n      }\n    `);\n\n    expect(specifier.importPathMatcher).toMatchPaths([\n      './path/file.stories.jsx',\n      './second-path/file.stories.jsx',\n    ]);\n    expect(specifier.importPathMatcher).not.toMatchPaths([\n      './path/file.stories.js',\n      './path/to/file.stories.jsx',\n      './file.stories.jsx',\n      '../file.stories.jsx',\n    ]);\n  });\n});\n\ndescribe('getDirectoryFromWorkingDir', () => {\n  it('should return normalized story path', () => {\n    const normalizedPath = getDirectoryFromWorkingDir({\n      configDir: '/path/to/project/.storybook',\n      workingDir: '/path/to/project',\n      directory: '/path/to/project/src',\n    });\n    expect(normalizedPath).toBe(`.${sep}src`);\n  });\n});\n\ndescribe('normalizeStories', () => {\n  it('should throw InvalidStoriesEntryError for empty entries', () => {\n    expect(() => normalizeStories([], options)).toThrow(InvalidStoriesEntryError);\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/__tests__/paths.test.ts",
    "content": "import { join, sep } from 'node:path';\n\nimport { describe, expect, it, vi } from 'vitest';\n\nimport * as find from 'empathic/find';\n// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\n\nimport { getProjectRoot, normalizeStoryPath } from '../paths.ts';\n\nvi.mock('empathic/find');\n\ndescribe('paths - normalizeStoryPath()', () => {\n  it('returns a path starting with \"./\" unchanged', () => {\n    const filename = `.${sep}${join('src', 'Comp.story.js')}`;\n    expect(normalizeStoryPath(filename)).toEqual(filename);\n  });\n\n  it('returns a path starting with \"../\" unchanged', () => {\n    const filename = join('..', 'src', 'Comp.story.js');\n    expect(normalizeStoryPath(filename)).toEqual(filename);\n  });\n\n  it('returns a path equal to \".\" unchanged', () => {\n    const filename = '.';\n    expect(normalizeStoryPath(filename)).toEqual(filename);\n  });\n\n  it('returns a path equal to \"..\" unchanged', () => {\n    const filename = '..';\n    expect(normalizeStoryPath(filename)).toEqual(filename);\n  });\n\n  it('adds \"./\" to a normalized relative path', () => {\n    const filename = join('src', 'Comp.story.js');\n    expect(normalizeStoryPath(filename)).toEqual(`.${sep}${filename}`);\n  });\n\n  it('adds \"./\" to a hidden folder', () => {\n    const filename = join('.storybook', 'Comp.story.js');\n    expect(normalizeStoryPath(filename)).toEqual(`.${sep}${filename}`);\n  });\n\n  it('adds \"./\" to a hidden file', () => {\n    const filename = `.Comp.story.js`;\n    expect(normalizeStoryPath(filename)).toEqual(`.${sep}${filename}`);\n  });\n});\n\ndescribe('getProjectRoot', () => {\n  it('should return the root directory containing a .git directory', () => {\n    vi.mocked(find.up).mockImplementation((name) =>\n      name === '.git' ? '/path/to/root' : undefined\n    );\n\n    expect(slash(getProjectRoot())).toBe('/path/to');\n  });\n\n  it('should return the root directory containing a .svn directory if there is no .git directory', () => {\n    vi.mocked(find.up).mockImplementation((name) =>\n      name === ('.svn' as any) ? '/path/to/root' : undefined\n    );\n\n    expect(slash(getProjectRoot())).toBe('/path/to');\n  });\n\n  it('should return the root directory containing a .yarn directory if there is no .git or .svn directory', () => {\n    vi.mocked(find.up).mockImplementation((name) =>\n      name === ('.yarn' as any) ? '/path/to/root' : undefined\n    );\n\n    expect(slash(getProjectRoot())).toBe('/path/to');\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/__tests__/template.test.ts",
    "content": "import { join } from 'node:path';\n\nimport { afterEach, describe, expect, it, vi } from 'vitest';\n\nimport { vol } from 'memfs';\n\nimport { getPreviewBodyTemplate, getPreviewHeadTemplate } from '../template.ts';\n\nvi.mock('fs', async () => {\n  const memfs = await vi.importActual('memfs');\n\n  return { default: memfs.fs, ...(memfs as any).fs };\n});\n\nconst HEAD_HTML_CONTENTS = '<script>console.log(\"custom script!\");</script>';\nconst BASE_HTML_CONTENTS = '<script>console.log(\"base script!\");</script>';\n\nconst BASE_BODY_HTML_CONTENTS = '<div>story contents</div>';\nconst BODY_HTML_CONTENTS = '<div>custom body contents</div>';\n\nconst BASE_CORE_PKG_DIR = join(import.meta.url, '..', '..', '..', '..', '..');\n\nvi.mock('../../../shared/utils/module', () => {\n  return {\n    resolvePackageDir: () => BASE_CORE_PKG_DIR,\n  };\n});\n\nafterEach(() => {\n  vol.reset();\n});\n\ndescribe('server.getPreviewHeadHtml', () => {\n  it('return an empty string when .storybook/preview-head.html does NOT exist', () => {\n    vol.fromNestedJSON({\n      [`${BASE_CORE_PKG_DIR}/assets/server/base-preview-head.html`]: BASE_HTML_CONTENTS,\n      config: {},\n    });\n\n    expect(getPreviewHeadTemplate('./config')).toEqual(BASE_HTML_CONTENTS);\n  });\n\n  it('return the contents of the file when .storybook/preview-head.html exists', () => {\n    vol.fromNestedJSON({\n      [`${BASE_CORE_PKG_DIR}/assets/server/base-preview-head.html`]: BASE_HTML_CONTENTS,\n      config: {\n        'preview-head.html': HEAD_HTML_CONTENTS,\n      },\n    });\n\n    expect(getPreviewHeadTemplate('./config')).toEqual(BASE_HTML_CONTENTS + HEAD_HTML_CONTENTS);\n  });\n});\n\ndescribe('server.getPreviewBodyHtml', () => {\n  it('return an empty string when .storybook/preview-body.html does NOT exist', () => {\n    vol.fromNestedJSON({\n      [`${BASE_CORE_PKG_DIR}/assets/server/base-preview-body.html`]: BASE_BODY_HTML_CONTENTS,\n      config: {},\n    });\n\n    expect(getPreviewBodyTemplate('./config')).toEqual(BASE_BODY_HTML_CONTENTS);\n  });\n\n  it('return the contents of the file when .storybook/preview-body.html exists', () => {\n    vol.fromNestedJSON({\n      [`${BASE_CORE_PKG_DIR}/assets/server/base-preview-body.html`]: BASE_BODY_HTML_CONTENTS,\n      config: {\n        'preview-body.html': BODY_HTML_CONTENTS,\n      },\n    });\n\n    expect(getPreviewBodyTemplate('./config')).toEqual(\n      BODY_HTML_CONTENTS + BASE_BODY_HTML_CONTENTS\n    );\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/cache.ts",
    "content": "import { createFileSystemCache } from './file-cache.ts';\nimport { resolvePathInStorybookCache } from './resolve-path-in-sb-cache.ts';\n\nexport const cache = createFileSystemCache({\n  basePath: resolvePathInStorybookCache('dev-server'),\n  ns: 'storybook', // Optional. A grouping namespace for items.\n});\n"
  },
  {
    "path": "code/core/src/common/utils/check-addon-order.ts",
    "content": "import { logger } from 'storybook/internal/node-logger';\nimport type {\n  CoreCommon_AddonEntry,\n  CoreCommon_AddonInfo,\n  CoreCommon_OptionsEntry,\n} from 'storybook/internal/types';\n\ninterface Options {\n  before: CoreCommon_AddonInfo;\n  after: CoreCommon_AddonInfo;\n  configFile: string;\n  getConfig: (path: string) => any;\n}\n\nconst predicateFor = (addon: string) => (entry: CoreCommon_AddonEntry) => {\n  const name = (entry as CoreCommon_OptionsEntry).name || (entry as string);\n  return name && name.replaceAll(/(\\\\){1,2}/g, '/').includes(addon);\n};\n\nconst isCorrectOrder = (\n  addons: CoreCommon_AddonEntry[],\n  before: CoreCommon_AddonInfo,\n  after: CoreCommon_AddonInfo\n) => {\n  const essentialsIndex = addons.findIndex(predicateFor('@storybook/addon-essentials'));\n  let beforeIndex = addons.findIndex(predicateFor(before.name));\n  let afterIndex = addons.findIndex(predicateFor(after.name));\n\n  if (beforeIndex === -1 && before.inEssentials) {\n    beforeIndex = essentialsIndex;\n  }\n\n  if (afterIndex === -1 && after.inEssentials) {\n    afterIndex = essentialsIndex;\n  }\n  return beforeIndex !== -1 && afterIndex !== -1 && beforeIndex <= afterIndex;\n};\n\nexport const checkAddonOrder = async ({ before, after, configFile, getConfig }: Options) => {\n  try {\n    const config = await getConfig(configFile);\n\n    if (!config?.addons) {\n      logger.warn(`Unable to find 'addons' config in main Storybook config`);\n      return;\n    }\n\n    if (!isCorrectOrder(config.addons, before, after)) {\n      const orEssentials = \" (or '@storybook/addon-essentials')\";\n      const beforeText = `'${before.name}'${before.inEssentials ? orEssentials : ''}`;\n      const afterText = `'${after.name}'${after.inEssentials ? orEssentials : ''}`;\n      logger.warn(\n        `Expected ${beforeText} to be listed before ${afterText} in main Storybook config.`\n      );\n    }\n  } catch (e) {\n    logger.warn(`Unable to load config file: ${configFile}`);\n  }\n};\n"
  },
  {
    "path": "code/core/src/common/utils/cli.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { isCorePackage } from './cli.ts';\n\ndescribe('UTILS', () => {\n  describe.each([\n    ['@storybook/react', true],\n    ['storybook', true],\n    ['@storybook/linter-config', false],\n    ['@storybook/design-system', false],\n    ['@storybook/addon-styling', false],\n    ['@storybook/addon-styling-webpack', false],\n    ['@storybook/addon-webpack5-compiler-swc', false],\n    ['@storybook/addon-webpack5-compiler-babel', false],\n    ['@nx/storybook', false],\n    ['@nrwl/storybook', false],\n  ])('isCorePackage', (input, output) => {\n    it(`It should return \"${output}\" when given \"${input}\"`, () => {\n      expect(isCorePackage(input)).toEqual(output);\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/cli.ts",
    "content": "import type { WriteStream } from 'node:fs';\nimport { createWriteStream, mkdirSync } from 'node:fs';\nimport { copyFile, readFile, realpath, rm, writeFile } from 'node:fs/promises';\nimport os from 'node:os';\nimport { join } from 'node:path';\n\nimport { type MergeExclusive } from 'type-fest';\nimport uniqueString from 'unique-string';\n\nimport type { JsPackageManager } from '../js-package-manager/index.ts';\nimport satelliteAddons from '../satellite-addons.ts';\nimport storybookPackagesVersions from '../versions.ts';\n\nconst tempDir = () => realpath(os.tmpdir());\n\nconst getPath = async (prefix = '') => join(await tempDir(), prefix + uniqueString());\n\nexport async function temporaryDirectory({ prefix = '' } = {}) {\n  const directory = await getPath(prefix);\n  mkdirSync(directory);\n  return directory;\n}\n\nexport type FileOptions = MergeExclusive<\n  {\n    /**\n     * File extension.\n     *\n     * Mutually exclusive with the `name` option.\n     *\n     * _You usually won't need this option. Specify it only when actually needed._\n     */\n    readonly extension?: string;\n  },\n  {\n    /**\n     * Filename.\n     *\n     * Mutually exclusive with the `extension` option.\n     *\n     * _You usually won't need this option. Specify it only when actually needed._\n     */\n    readonly name?: string;\n  }\n>;\n\nexport async function temporaryFile({ name, extension }: FileOptions = {}) {\n  if (name) {\n    if (extension !== undefined && extension !== null) {\n      throw new Error('The `name` and `extension` options are mutually exclusive');\n    }\n\n    return join(await temporaryDirectory(), name);\n  }\n\n  return (\n    (await getPath()) +\n    (extension === undefined || extension === null ? '' : '.' + extension.replace(/^\\./, ''))\n  );\n}\n\nexport function parseList(str: string): string[] {\n  return str\n    .split(',')\n    .map((item) => item.trim())\n    .filter((item) => item.length > 0);\n}\n\nexport function getEnvConfig(program: Record<string, any>, configEnv: Record<string, any>): void {\n  Object.keys(configEnv).forEach((fieldName) => {\n    const envVarName = configEnv[fieldName];\n    const envVarValue = process.env[envVarName];\n    if (envVarValue) {\n      program[fieldName] = envVarValue;\n    }\n  });\n}\n\n/**\n * Given a file name, creates an object with utilities to manage a log file. It creates a temporary\n * log file which you can manage with the returned functions. You can then decide whether to move\n * the log file to the users project, or remove it.\n *\n * @example\n *\n * ```ts\n * const { logStream, moveLogFile, removeLogFile, clearLogFile, readLogFile } =\n *   await createLogStream('my-log-file.log');\n *\n * // SCENARIO 1:\n * // you can write custom messages to generate a log file\n * logStream.write('my log message');\n * await moveLogFile();\n *\n * // SCENARIO 2:\n * // or you can pass it to stdio and capture the output of that command\n * try {\n *   await executeCommand({\n *     command: 'pnpm',\n *     args: ['info', packageName, ...args],\n *     // do not output to the user, and send stdio and stderr to log file\n *     stdio: ['ignore', logStream, logStream],\n *   });\n * } catch (err) {\n *   // do something with the log file content\n *   const output = await readLogFile();\n *   // move the log file to the users project\n *   await moveLogFile();\n * }\n * // success, no need to keep the log file\n * await removeLogFile();\n * ```\n */\nexport const createLogStream = async (\n  logFileName = 'storybook.log'\n): Promise<{\n  moveLogFile: () => Promise<void>;\n  removeLogFile: () => Promise<void>;\n  clearLogFile: () => Promise<void>;\n  readLogFile: () => Promise<string>;\n  logStream: WriteStream;\n}> => {\n  const finalLogPath = join(process.cwd(), logFileName);\n  const temporaryLogPath = await temporaryFile({ name: logFileName });\n\n  const logStream = createWriteStream(temporaryLogPath, { encoding: 'utf8' });\n\n  return new Promise((resolve, reject) => {\n    logStream.once('open', () => {\n      const clearLogFile = async () => writeFile(temporaryLogPath, '');\n      const removeLogFile = async () => rm(temporaryLogPath, { recursive: true, force: true });\n      const readLogFile = async () => readFile(temporaryLogPath, { encoding: 'utf8' });\n      // Can't use rename because it doesn't work across disks.\n      const moveLogFile = async () => copyFile(temporaryLogPath, finalLogPath).then(removeLogFile);\n      resolve({ logStream, moveLogFile, clearLogFile, removeLogFile, readLogFile });\n    });\n    logStream.once('error', reject);\n  });\n};\n\nexport const isCorePackage = (pkg: string) =>\n  !!storybookPackagesVersions[pkg as keyof typeof storybookPackagesVersions];\nexport const isSatelliteAddon = (pkg: string) => satelliteAddons.includes(pkg);\n"
  },
  {
    "path": "code/core/src/common/utils/command.ts",
    "content": "import { logger, prompt } from 'storybook/internal/node-logger';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport {\n  type Options,\n  type ResultPromise,\n  type SyncOptions,\n  execa,\n  execaCommandSync,\n  execaNode,\n} from 'execa';\n\nconst COMMON_ENV_VARS = {\n  COREPACK_ENABLE_STRICT: '0',\n  COREPACK_ENABLE_AUTO_PIN: '0',\n  NO_UPDATE_NOTIFIER: 'true',\n};\n\nexport type ExecuteCommandOptions = Omit<Options, 'cancelSignal'> & {\n  command: string;\n  args?: string[];\n  cwd?: string;\n  ignoreError?: boolean;\n  env?: Record<string, string>;\n  signal?: AbortSignal; // Alias for cancelSignal (execa v9 uses cancelSignal)\n};\n\nfunction getExecaOptions({\n  stdio,\n  cwd,\n  env,\n  signal,\n  ...execaOptions\n}: ExecuteCommandOptions): Options {\n  return {\n    cwd,\n    stdio: stdio ?? prompt.getPreferredStdio(),\n    encoding: 'utf8' as const,\n    cleanup: true,\n    env: {\n      ...COMMON_ENV_VARS,\n      ...env,\n    },\n    ...(signal && { cancelSignal: signal }), // Map signal to cancelSignal for execa v9\n    ...execaOptions,\n  };\n}\n\nexport function executeCommand(options: ExecuteCommandOptions): ResultPromise {\n  const { command, args = [], ignoreError = false } = options;\n  logger.debug(`Executing command: ${command} ${args.join(' ')}`);\n  const execaProcess = execa(resolveCommand(command), args, getExecaOptions(options));\n\n  if (ignoreError) {\n    execaProcess.catch(() => {\n      // Silently ignore errors when ignoreError is true\n    });\n  }\n\n  return execaProcess;\n}\n\nexport function executeCommandSync(options: ExecuteCommandOptions): string {\n  const { command, args = [], ignoreError = false } = options;\n  try {\n    const commandResult = execaCommandSync(\n      [resolveCommand(command), ...args].join(' '),\n      getExecaOptions(options) as SyncOptions\n    );\n    return typeof commandResult.stdout === 'string' ? commandResult.stdout : '';\n  } catch (err) {\n    if (!ignoreError) {\n      throw err;\n    }\n    return '';\n  }\n}\n\nexport function executeNodeCommand({\n  scriptPath,\n  args,\n  options,\n}: {\n  scriptPath: string;\n  args?: string[];\n  options?: Options;\n}): ResultPromise {\n  return execaNode(scriptPath, args, {\n    ...options,\n  });\n}\n\n/**\n * Resolve the actual executable name for a given command on the current platform.\n *\n * Why this exists:\n *\n * - Many Node-based CLIs (npm, npx, pnpm, yarn, vite, eslint, anything in node_modules/.bin) do NOT\n *   ship as real executables on Windows.\n * - Instead, they install *.cmd and *.ps1 “shim” files.\n * - When using execa/child_process with `shell: false` (our default), Node WILL NOT resolve these\n *   shims. -> calling execa(\"npx\") throws ENOENT on Windows.\n *\n * This helper normalizes command names so they can be spawned cross-platform without using `shell:\n * true`.\n *\n * Rules:\n *\n * - If on Windows:\n *\n *   - For known shim-based commands, append `.cmd` (e.g., \"npx\" → \"npx.cmd\").\n *   - For everything else, return the name unchanged.\n * - On non-Windows, return command unchanged.\n *\n * Open for extension:\n *\n * - Add new commands to `WINDOWS_SHIM_COMMANDS` as needed.\n * - If Storybook adds new internal commands later, extend the list.\n *\n * @param {string} command - The executable name passed into executeCommand.\n * @returns {string} - The normalized executable name safe for passing to execa.\n */\nfunction resolveCommand(command: string): string {\n  // Commands known to require .cmd on Windows (node-based & shim-installed)\n  const WINDOWS_SHIM_COMMANDS = new Set([\n    'npm',\n    'npx',\n    'pnpm',\n    'yarn',\n    'ng',\n    // Anything installed via node_modules/.bin (vite, eslint, prettier, etc)\n    // can be added here as needed. Do NOT list native executables.\n  ]);\n\n  if (process.platform !== 'win32') {\n    return command;\n  }\n\n  if (WINDOWS_SHIM_COMMANDS.has(command)) {\n    return `${command}.cmd`;\n  }\n\n  return command;\n}\n"
  },
  {
    "path": "code/core/src/common/utils/common-glob-options.ts",
    "content": "const NODE_MODULES_RE = /node_modules/;\n\n// Exclude node_modules stories everywhere we call `glob`\nexport const commonGlobOptions = (glob: string) =>\n  NODE_MODULES_RE.test(glob) ? {} : { ignore: ['**/node_modules/**'] };\n"
  },
  {
    "path": "code/core/src/common/utils/envs.ts",
    "content": "export { isWebContainer } from '@webcontainer/env';\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore - Needed for Angular sandbox running without --no-link option. Do NOT convert to @ts-expect-error!\nimport { nodePathsToArray } from './paths.ts';\n\n// Load environment variables starts with STORYBOOK_ to the client side.\n\nexport async function loadEnvs(options: { production?: boolean } = {}): Promise<{\n  stringified: Record<string, string>;\n  raw: Record<string, string>;\n}> {\n  const { getEnvironment } = await import('lazy-universal-dotenv');\n  const defaultNodeEnv = options.production ? 'production' : 'development';\n\n  const baseEnv: Record<string, string> = {\n    // eslint-disable-next-line @typescript-eslint/dot-notation\n    NODE_ENV: process.env['NODE_ENV'] || defaultNodeEnv,\n    NODE_PATH: process.env['NODE_PATH'] || '',\n    STORYBOOK: process.env['STORYBOOK'] || 'true',\n    // This is to support CRA's public folder feature.\n    // In production we set this to dot(.) to allow the browser to access these assets\n    // even when deployed inside a subpath. (like in GitHub pages)\n    // In development this is just empty as we always serves from the root.\n    PUBLIC_URL: options.production ? '.' : '',\n  };\n\n  const dotenv = getEnvironment({ nodeEnv: baseEnv['NODE_ENV'] });\n\n  const envEntries = Object.fromEntries<string>(\n    Object.entries<string>({\n      // TODO: it seems wrong that dotenv overrides process.env, but that's how it has always worked\n      ...process.env,\n      ...dotenv.raw,\n    }).filter(([name]) => /^STORYBOOK_/.test(name))\n  );\n\n  const raw: Record<string, string> = { ...baseEnv, ...envEntries };\n  (raw as any).NODE_PATH = nodePathsToArray((raw.NODE_PATH as string) || '');\n\n  const stringified = Object.fromEntries(\n    Object.entries(raw).map(([key, value]) => [key, JSON.stringify(value)])\n  );\n  return { raw, stringified };\n}\n\nexport const stringifyEnvs = (raw: Record<string, string>): Record<string, string> =>\n  Object.entries(raw).reduce<Record<string, string>>((acc, [key, value]) => {\n    acc[key] = JSON.stringify(value);\n    return acc;\n  }, {});\n\nexport const stringifyProcessEnvs = (raw: Record<string, string>): Record<string, string> => {\n  const envs = Object.entries(raw).reduce<Record<string, string>>((acc, [key, value]) => {\n    acc[`process.env.${key}`] = JSON.stringify(value);\n    return acc;\n  }, {});\n  return envs;\n};\n\nexport const optionalEnvToBoolean = (input: string | undefined): boolean | undefined => {\n  if (input === undefined) {\n    return undefined;\n  }\n  if (input.toUpperCase() === 'FALSE' || input === '0') {\n    return false;\n  }\n  if (input.toUpperCase() === 'TRUE' || input === '1') {\n    return true;\n  }\n  return Boolean(input);\n};\n\n/**\n * Consistently determine if we are in a CI environment\n *\n * Doing Boolean(process.env.CI) or !process.env.CI is not enough, because users might set CI=false\n * or CI=0, which would be truthy, and thus return true in those cases.\n */\nexport function isCI(): boolean | undefined {\n  return optionalEnvToBoolean(process.env.CI);\n}\n"
  },
  {
    "path": "code/core/src/common/utils/file-cache.ts",
    "content": "/** This file is a modified copy from https://git.nfp.is/TheThing/fs-cache-fast */\nimport { createHash, randomBytes } from 'node:crypto';\nimport { mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs';\nimport { mkdir, readFile, readdir, rm } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\n\nimport { writeFileWithRetry } from './write-file-with-retry.ts';\n\ninterface FileSystemCacheOptions {\n  ns?: string;\n  prefix?: string;\n  hash_alg?: string;\n  basePath?: string;\n  ttl?: number;\n}\n\ninterface CacheItem {\n  key: string;\n  content?: any;\n  value?: any;\n}\n\ninterface CacheSetOptions {\n  ttl?: number;\n  encoding?: BufferEncoding;\n}\n\nexport class FileSystemCache {\n  private prefix: string;\n\n  private hash_alg: string;\n\n  private cache_dir: string;\n\n  private ttl: number;\n\n  constructor(options: FileSystemCacheOptions = {}) {\n    this.prefix = (options.ns || options.prefix || '') + '-';\n    this.hash_alg = options.hash_alg || 'sha256';\n    this.cache_dir =\n      options.basePath || join(tmpdir(), randomBytes(15).toString('base64').replace(/\\//g, '-'));\n    this.ttl = options.ttl || 0;\n    createHash(this.hash_alg); // Verifies hash algorithm is available\n    mkdirSync(this.cache_dir, { recursive: true });\n  }\n\n  private generateHash(name: string): string {\n    return join(this.cache_dir, this.prefix + createHash(this.hash_alg).update(name).digest('hex'));\n  }\n\n  private isExpired(parsed: { ttl?: number }, now: number): boolean {\n    return parsed.ttl != null && now > parsed.ttl;\n  }\n\n  private parseCacheData<T>(data: string, fallback: T | null): T | null {\n    const parsed = JSON.parse(data);\n    return this.isExpired(parsed, Date.now()) ? fallback : (parsed.content as T);\n  }\n\n  private parseSetData<T>(key: string, data: T, opts: CacheSetOptions = {}): string {\n    const ttl = opts.ttl ?? this.ttl;\n    return JSON.stringify({ key, content: data, ...(ttl && { ttl: Date.now() + ttl * 1000 }) });\n  }\n\n  public async get<T = any>(name: string, fallback?: T): Promise<T> {\n    try {\n      const data = await readFile(this.generateHash(name), 'utf8');\n      return this.parseCacheData(data, fallback) as T;\n    } catch {\n      return fallback as T;\n    }\n  }\n\n  public getSync<T>(name: string, fallback?: T): T {\n    try {\n      const data = readFileSync(this.generateHash(name), 'utf8');\n      return this.parseCacheData(data, fallback) as T;\n    } catch {\n      return fallback as T;\n    }\n  }\n\n  public async set<T>(\n    name: string,\n    data: T,\n    orgOpts: CacheSetOptions | number = {}\n  ): Promise<void> {\n    const opts: CacheSetOptions = typeof orgOpts === 'number' ? { ttl: orgOpts } : orgOpts;\n    await mkdir(this.cache_dir, { recursive: true });\n    await writeFileWithRetry(this.generateHash(name), this.parseSetData(name, data, opts), {\n      encoding: opts.encoding || 'utf8',\n    });\n  }\n\n  public setSync<T>(name: string, data: T, orgOpts: CacheSetOptions | number = {}): void {\n    const opts: CacheSetOptions = typeof orgOpts === 'number' ? { ttl: orgOpts } : orgOpts;\n    mkdirSync(this.cache_dir, { recursive: true });\n    writeFileSync(this.generateHash(name), this.parseSetData(name, data, opts), {\n      encoding: opts.encoding || 'utf8',\n    });\n  }\n\n  public async setMany(items: CacheItem[], options?: CacheSetOptions): Promise<void> {\n    await Promise.all(items.map((item) => this.set(item.key, item.content ?? item.value, options)));\n  }\n\n  public setManySync(items: CacheItem[], options?: CacheSetOptions): void {\n    items.forEach((item) => this.setSync(item.key, item.content ?? item.value, options));\n  }\n\n  public async remove(name: string): Promise<void> {\n    await rm(this.generateHash(name), { force: true });\n  }\n\n  public removeSync(name: string): void {\n    rmSync(this.generateHash(name), { force: true });\n  }\n\n  public async clear(): Promise<void> {\n    const files = await readdir(this.cache_dir);\n    await Promise.all(\n      files\n        .filter((f) => f.startsWith(this.prefix))\n        .map((f) => rm(join(this.cache_dir, f), { force: true }))\n    );\n  }\n\n  public clearSync(): void {\n    readdirSync(this.cache_dir)\n      .filter((f) => f.startsWith(this.prefix))\n      .forEach((f) => rmSync(join(this.cache_dir, f), { force: true }));\n  }\n\n  public async getAll(): Promise<CacheItem[]> {\n    const now = Date.now();\n    const files = await readdir(this.cache_dir);\n    const items = await Promise.all(\n      files\n        .filter((f) => f.startsWith(this.prefix))\n        .map((f) => readFile(join(this.cache_dir, f), 'utf8'))\n    );\n    return items\n      .map((data) => JSON.parse(data))\n      .filter((entry) => entry.content && !this.isExpired(entry, now));\n  }\n\n  public async load(): Promise<{ files: CacheItem[] }> {\n    const res = await this.getAll();\n    return {\n      files: res.map((entry) => ({\n        path: this.generateHash(entry.key),\n        value: entry.content,\n        key: entry.key,\n      })),\n    };\n  }\n}\n\nexport function createFileSystemCache(options: FileSystemCacheOptions): FileSystemCache {\n  return new FileSystemCache(options);\n}\n"
  },
  {
    "path": "code/core/src/common/utils/formatter.test.ts",
    "content": "import { resolve } from 'node:path';\n\nimport { describe, expect, it, vi } from 'vitest';\n\nimport { formatFileContent } from './formatter.ts';\n\nconst mockPrettier = vi.hoisted(() => ({\n  resolveConfig: vi.fn(),\n  format: vi.fn(),\n  version: vi.fn(),\n}));\n\nvi.mock('prettier', () => ({\n  resolveConfig: mockPrettier.resolveConfig,\n  format: mockPrettier.format,\n  get version() {\n    return mockPrettier.version();\n  },\n}));\n\nconst dummyContent = `\nimport type { Meta, StoryObj } from '@storybook/nextjs'\n\nimport Component from './foo';\n\n  const meta = {\n    component: Component\n  } satisfies Meta<typeof Component>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n`;\n\ndescribe('formatter', () => {\n  describe('withPrettierConfig', () => {\n    const testPath = resolve(__dirname, '__tests-formatter__', 'withPrettierConfig');\n\n    describe('prettier', async () => {\n      const prettierV3 = await import('prettier');\n\n      it('formats content with prettier', async () => {\n        mockPrettier.format.mockImplementation(prettierV3.format);\n        mockPrettier.version.mockReturnValue(prettierV3.version);\n        mockPrettier.resolveConfig.mockImplementation(prettierV3.resolveConfig);\n\n        const filePath = resolve(testPath, 'testFile.ts');\n\n        const result = await formatFileContent(filePath, dummyContent);\n\n        expect(result).toMatchSnapshot();\n      });\n    });\n  });\n\n  describe('withoutPrettierConfigAndWithEditorConfig', () => {\n    const testPath = resolve(__dirname, '__tests-formatter__', 'withoutPrettierConfig');\n\n    describe('prettier-v3', async () => {\n      const prettierV3 = await import('prettier');\n\n      it('formats content with prettier', async () => {\n        mockPrettier.format.mockImplementation(prettierV3.format);\n        mockPrettier.version.mockReturnValue(prettierV3.version);\n        mockPrettier.resolveConfig.mockImplementation(prettierV3.resolveConfig);\n\n        const filePath = resolve(testPath, 'testFile.ts');\n\n        const result = await formatFileContent(filePath, dummyContent);\n\n        expect(result).toMatchSnapshot();\n      });\n    });\n  });\n\n  describe('withoutPrettierConfigAndWithEditorConfig', () => {\n    const testPath = resolve(__dirname, '__tests-formatter__', 'withoutEditorConfig');\n\n    describe('prettier-v3', async () => {\n      const prettierV3 = await import('prettier');\n\n      it('formats content with prettier', async () => {\n        mockPrettier.format.mockImplementation(prettierV3.format);\n        mockPrettier.version.mockReturnValue(prettierV3.version);\n        mockPrettier.resolveConfig.mockResolvedValue(null);\n\n        const filePath = resolve(testPath, 'testFile.ts');\n\n        const result = await formatFileContent(filePath, dummyContent);\n\n        expect(result).toBe(dummyContent);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/formatter.ts",
    "content": "// Prettier interface definition\n// Note: We want to avoid importing prettier directly to prevent bundling its type import\n// because prettier is an optional peer dependency and might not be available\ninterface Prettier {\n  resolveConfig: (filePath: string, options?: { editorconfig?: boolean }) => Promise<any>;\n  format: (content: string, options?: any) => Promise<string> | string;\n  check: (content: string, options?: any) => Promise<boolean>;\n  clearConfigCache: () => Promise<void>;\n  formatWithCursor: (\n    content: string,\n    options?: any\n  ) => Promise<{ formatted: string; cursorOffset: number }>;\n  getFileInfo: (\n    filePath: string,\n    options?: any\n  ) => Promise<{ ignored: boolean; inferredParser: string | null }>;\n  getSupportInfo: () => Promise<{ languages: any[]; options: any[] }>;\n  resolveConfigFile: (filePath?: string) => Promise<string | null>;\n  version: string;\n  AstPath: any;\n  doc: any;\n  util: any;\n}\n\nexport async function getPrettier(): Promise<Prettier> {\n  try {\n    return await import('prettier');\n  } catch {\n    return {\n      AstPath: class {} as any,\n      doc: {} as any,\n      util: {} as any,\n      version: '0.0.0-fallback',\n      resolveConfig: async () => null,\n      format: (content: string) => Promise.resolve(content),\n      check: () => Promise.resolve(false),\n      clearConfigCache: () => Promise.resolve(undefined),\n      formatWithCursor: () => Promise.resolve({ formatted: '', cursorOffset: 0 }),\n      getFileInfo: async () => ({ ignored: false, inferredParser: null }),\n      getSupportInfo: () => Promise.resolve({ languages: [], options: [] }),\n      resolveConfigFile: async () => null,\n    };\n  }\n}\n\n/**\n * Format the content of a file using prettier. If prettier is not available in the user's project,\n * it will fallback to use editorconfig settings if available and formats the file by a\n * prettier-fallback.\n */\nexport async function formatFileContent(filePath: string, content: string): Promise<string> {\n  try {\n    const { resolveConfig, format } = await getPrettier();\n    const config = await resolveConfig(filePath);\n\n    if (!config || Object.keys(config).length === 0) {\n      return await formatWithEditorConfig(filePath, content);\n    }\n\n    const result = await format(content, {\n      ...(config as any),\n      filepath: filePath,\n    });\n\n    return result;\n  } catch (error) {\n    return content;\n  }\n}\n\nasync function formatWithEditorConfig(filePath: string, content: string): Promise<string> {\n  const { resolveConfig, format } = await getPrettier();\n\n  const config = await resolveConfig(filePath, { editorconfig: true });\n\n  if (!config || Object.keys(config).length === 0) {\n    return content;\n  }\n\n  return format(content, {\n    ...(config as any),\n    filepath: filePath,\n  });\n}\n"
  },
  {
    "path": "code/core/src/common/utils/framework.ts",
    "content": "import { SupportedBuilder, SupportedFramework, SupportedRenderer } from 'storybook/internal/types';\n\nexport const frameworkToRenderer: Record<\n  SupportedFramework | SupportedRenderer,\n  SupportedRenderer\n> = {\n  // frameworks\n  [SupportedFramework.ANGULAR]: SupportedRenderer.ANGULAR,\n  [SupportedFramework.EMBER]: SupportedRenderer.EMBER,\n  [SupportedFramework.HTML_VITE]: SupportedRenderer.HTML,\n  [SupportedFramework.NEXTJS]: SupportedRenderer.REACT,\n  [SupportedFramework.NEXTJS_VITE]: SupportedRenderer.REACT,\n  [SupportedFramework.PREACT_VITE]: SupportedRenderer.PREACT,\n  [SupportedFramework.QWIK]: SupportedRenderer.QWIK,\n  [SupportedFramework.REACT_VITE]: SupportedRenderer.REACT,\n  [SupportedFramework.REACT_WEBPACK5]: SupportedRenderer.REACT,\n  [SupportedFramework.SERVER_WEBPACK5]: SupportedRenderer.SERVER,\n  [SupportedFramework.SOLID]: SupportedRenderer.SOLID,\n  [SupportedFramework.SVELTE_VITE]: SupportedRenderer.SVELTE,\n  [SupportedFramework.SVELTEKIT]: SupportedRenderer.SVELTE,\n  [SupportedFramework.VUE3_VITE]: SupportedRenderer.VUE3,\n  [SupportedFramework.WEB_COMPONENTS_VITE]: SupportedRenderer.WEB_COMPONENTS,\n  [SupportedFramework.REACT_RSBUILD]: SupportedRenderer.REACT,\n  [SupportedFramework.VUE3_RSBUILD]: SupportedRenderer.VUE3,\n  [SupportedFramework.HTML_RSBUILD]: SupportedRenderer.HTML,\n  [SupportedFramework.WEB_COMPONENTS_RSBUILD]: SupportedRenderer.WEB_COMPONENTS,\n  [SupportedFramework.REACT_NATIVE_WEB_VITE]: SupportedRenderer.REACT,\n  [SupportedFramework.NUXT]: SupportedRenderer.VUE3,\n\n  // renderers\n  [SupportedRenderer.HTML]: SupportedRenderer.HTML,\n  [SupportedRenderer.PREACT]: SupportedRenderer.PREACT,\n  [SupportedRenderer.REACT_NATIVE]: SupportedRenderer.REACT_NATIVE,\n  [SupportedRenderer.REACT]: SupportedRenderer.REACT,\n  [SupportedRenderer.SERVER]: SupportedRenderer.SERVER,\n  [SupportedRenderer.SVELTE]: SupportedRenderer.SVELTE,\n  [SupportedRenderer.VUE3]: SupportedRenderer.VUE3,\n  [SupportedRenderer.WEB_COMPONENTS]: SupportedRenderer.WEB_COMPONENTS,\n};\n\nexport const frameworkToBuilder: Record<SupportedFramework, SupportedBuilder> = {\n  // frameworks\n  [SupportedFramework.ANGULAR]: SupportedBuilder.WEBPACK5,\n  [SupportedFramework.EMBER]: SupportedBuilder.WEBPACK5,\n  [SupportedFramework.HTML_VITE]: SupportedBuilder.VITE,\n  [SupportedFramework.NEXTJS]: SupportedBuilder.WEBPACK5,\n  [SupportedFramework.NEXTJS_VITE]: SupportedBuilder.VITE,\n  [SupportedFramework.PREACT_VITE]: SupportedBuilder.VITE,\n  [SupportedFramework.REACT_NATIVE_WEB_VITE]: SupportedBuilder.VITE,\n  [SupportedFramework.REACT_VITE]: SupportedBuilder.VITE,\n  [SupportedFramework.REACT_WEBPACK5]: SupportedBuilder.WEBPACK5,\n  [SupportedFramework.SERVER_WEBPACK5]: SupportedBuilder.WEBPACK5,\n  [SupportedFramework.SVELTE_VITE]: SupportedBuilder.VITE,\n  [SupportedFramework.SVELTEKIT]: SupportedBuilder.VITE,\n  [SupportedFramework.VUE3_VITE]: SupportedBuilder.VITE,\n  [SupportedFramework.WEB_COMPONENTS_VITE]: SupportedBuilder.VITE,\n  [SupportedFramework.QWIK]: SupportedBuilder.VITE,\n  [SupportedFramework.SOLID]: SupportedBuilder.VITE,\n  [SupportedFramework.NUXT]: SupportedBuilder.VITE,\n  [SupportedFramework.REACT_RSBUILD]: SupportedBuilder.RSBUILD,\n  [SupportedFramework.VUE3_RSBUILD]: SupportedBuilder.RSBUILD,\n  [SupportedFramework.HTML_RSBUILD]: SupportedBuilder.RSBUILD,\n  [SupportedFramework.WEB_COMPONENTS_RSBUILD]: SupportedBuilder.RSBUILD,\n};\n"
  },
  {
    "path": "code/core/src/common/utils/get-addon-annotations.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { getAnnotationsName } from './get-addon-annotations.ts';\n\ndescribe('getAnnotationsName', () => {\n  it('should handle @storybook namespace and camel case conversion', () => {\n    expect(getAnnotationsName('@storybook/addon-essentials')).toBe('addonEssentials');\n  });\n\n  it('should handle other namespaces and camel case conversion', () => {\n    expect(getAnnotationsName('@kudos-components/testing/module')).toBe(\n      'kudosComponentsTestingModule'\n    );\n  });\n\n  it('should handle strings without namespaces', () => {\n    expect(getAnnotationsName('plain-text/example')).toBe('plainTextExample');\n  });\n\n  it('should handle strings with multiple special characters', () => {\n    expect(getAnnotationsName('@storybook/multi-part/example-test')).toBe('multiPartExampleTest');\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/get-addon-annotations.ts",
    "content": "import { createRequire } from 'node:module';\n\nimport { isCorePackage } from './cli.ts';\n\n/**\n * Get the name of the annotations object for a given addon.\n *\n * Input: '@storybook/addon-essentials'\n *\n * Output: 'addonEssentialsAnnotations'\n */\nexport function getAnnotationsName(addonName: string): string {\n  // remove @storybook namespace, split by special characters, convert to camelCase\n  const cleanedUpName = addonName\n    .replace(/^@storybook\\//, '')\n    .split(/[^a-zA-Z0-9]+/)\n    .map((word, index) =>\n      index === 0 ? word.toLowerCase() : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()\n    )\n    .join('')\n    .replace(/^./, (char) => char.toLowerCase());\n\n  return cleanedUpName;\n}\n\n// TODO: test this\nexport async function getAddonAnnotations(addon: string, configDir: string) {\n  const data = {\n    // core addons will have a function as default export in index entrypoint\n    importPath: addon,\n    importName: getAnnotationsName(addon),\n    isCoreAddon: isCorePackage(addon),\n  };\n\n  if (!data.isCoreAddon) {\n    // for backwards compatibility, if it's not a core addon we use /preview entrypoint\n    data.importPath = `${addon}/preview`;\n  }\n\n  // If the preview endpoint doesn't exist, we don't need to add the addon to definePreview\n  try {\n    const require = createRequire(import.meta.url);\n    require.resolve(`${addon}/preview`, { paths: [configDir] });\n  } catch (err) {\n    return null;\n  }\n  return data;\n}\n"
  },
  {
    "path": "code/core/src/common/utils/get-addon-names.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { getAddonNames } from './get-addon-names.ts';\n\ndescribe('getAddonNames', () => {\n  it('should extract addon names from simple strings', () => {\n    const config = {\n      stories: [],\n      addons: ['@storybook/addon-highlight', '@storybook/addon-outline'],\n    };\n    const result = getAddonNames(config);\n    expect(result).toEqual(['@storybook/addon-highlight', '@storybook/addon-outline']);\n  });\n\n  it('should extract addon names from object notation', () => {\n    const config = {\n      stories: [],\n      addons: [{ name: '@storybook/addon-highlight' }, { name: '@storybook/addon-outline' }],\n    };\n    const result = getAddonNames(config);\n    expect(result).toEqual(['@storybook/addon-highlight', '@storybook/addon-outline']);\n  });\n\n  it('should filter out relative paths for local addons', () => {\n    const config = {\n      stories: [],\n      addons: ['./local-addon', { name: './another-local-addon' }],\n    };\n    const result = getAddonNames(config);\n    expect(result).toEqual([]);\n  });\n\n  it('should extract addon names from absolute paths', () => {\n    const config = {\n      stories: [],\n      addons: [\n        '/sandbox/react-vite-default-ts/node_modules/@storybook/addon-highlight',\n        '/sandbox/react-vite-default-ts/node_modules/@storybook/addon-outline',\n      ],\n    };\n    const result = getAddonNames(config);\n    expect(result).toEqual(['@storybook/addon-highlight', '@storybook/addon-outline']);\n  });\n\n  it('should extract addon names from windows absolute paths', () => {\n    const config = {\n      stories: [],\n      addons: [\n        '\\\\sandbox\\\\react-vite-default-ts\\\\node_modules\\\\@storybook\\\\addon-highlight',\n        '\\\\sandbox\\\\react-vite-default-ts\\\\node_modules\\\\@storybook\\\\addon-outline',\n      ],\n    };\n    const result = getAddonNames(config);\n    expect(result).toEqual(['@storybook/addon-highlight', '@storybook/addon-outline']);\n  });\n\n  it('should extract addon names from pnpm paths', () => {\n    const config = {\n      stories: [],\n      addons: [\n        '/Users/xxx/node_modules/.pnpm/@storybook+addon-essentials@8.5.0-beta.5_@types+react@18.2.33_storybook@8.5.0-beta.5_prettier@3.2.5_/node_modules/@storybook/addon-essentials',\n      ],\n    };\n    const result = getAddonNames(config);\n    expect(result).toEqual(['@storybook/addon-essentials']);\n  });\n\n  it('should extract addon names from yarn pnp paths', () => {\n    const config = {\n      stories: [],\n      addons: [\n        '/Users/xxx/.yarn/__virtual__/@storybook-addon-essentials-virtual-5c3b9b3005/3/.yarn/berry/cache/@storybook-addon-essentials-npm-8.5.0-bbaf03c190-10c0.zip/node_modules/@storybook/addon-essentials',\n      ],\n    };\n    const result = getAddonNames(config);\n    expect(result).toEqual(['@storybook/addon-essentials']);\n  });\n\n  it('should handle mixed addon configurations', () => {\n    const config = {\n      stories: [],\n      addons: [\n        '@storybook/addon-hightlight',\n        { name: '@storybook/addon-outline' },\n        './local-addon',\n        '/sandbox/react-vite-default-ts/node_modules/@storybook/addon-controls',\n      ],\n    };\n    const result = getAddonNames(config);\n    expect(result).toEqual([\n      '@storybook/addon-hightlight',\n      '@storybook/addon-outline',\n      '@storybook/addon-controls',\n    ]);\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/get-addon-names.ts",
    "content": "import type { StorybookConfig } from 'storybook/internal/types';\n\nimport { normalizePath } from './normalize-path.ts';\n\nexport const getAddonNames = (mainConfig: StorybookConfig): string[] => {\n  const addons = mainConfig.addons || [];\n  const addonList = addons.map((addon) => {\n    let name = '';\n    if (typeof addon === 'string') {\n      name = addon;\n    } else if (typeof addon === 'object') {\n      name = addon.name;\n    }\n\n    if (name.startsWith('.')) {\n      return undefined;\n    }\n\n    // Ensure posix paths for plugin name sniffing\n    name = normalizePath(name);\n\n    // For absolute paths, pnpm and yarn pnp,\n    // Remove everything before and including \"node_modules/\"\n    name = name.replace(/.*node_modules\\//, '');\n\n    // Further clean up package names\n    return name\n      .replace(/\\/dist\\/.*$/, '')\n      .replace(/\\.[mc]?[tj]?sx?$/, '')\n      .replace(/\\/register$/, '')\n      .replace(/\\/manager$/, '')\n      .replace(/\\/preset$/, '');\n  });\n\n  return addonList.filter((item): item is NonNullable<typeof item> => item != null);\n};\n"
  },
  {
    "path": "code/core/src/common/utils/get-builder-options.ts",
    "content": "import type { Options } from 'storybook/internal/types';\n\n/**\n * Builder options can be specified in `core.builder.options` or `framework.options.builder`.\n * Preference is given here to `framework.options.builder` if both are specified.\n */\nexport async function getBuilderOptions<T extends Record<string, any>>(\n  options: Options\n): Promise<T | Record<string, never>> {\n  const framework = await options.presets.apply('framework', {}, options);\n\n  if (typeof framework !== 'string' && framework?.options?.builder) {\n    return framework.options.builder;\n  }\n\n  const { builder } = await options.presets.apply('core', {}, options);\n\n  if (typeof builder !== 'string' && builder?.options) {\n    return builder.options as T;\n  }\n\n  return {};\n}\n"
  },
  {
    "path": "code/core/src/common/utils/get-framework-name.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { extractFrameworkPackageName } from './get-framework-name.ts';\n\ndescribe('get-framework-name', () => {\n  describe('extractProperFrameworkName', () => {\n    it('should extract the proper framework name from the given framework field', () => {\n      expect(extractFrameworkPackageName('@storybook/angular')).toBe('@storybook/angular');\n      expect(extractFrameworkPackageName('/path/to/@storybook/angular')).toBe('@storybook/angular');\n      expect(extractFrameworkPackageName('\\\\path\\\\to\\\\@storybook\\\\angular')).toBe(\n        '@storybook/angular'\n      );\n    });\n\n    it('should return the given framework name if it is a third-party framework', () => {\n      expect(extractFrameworkPackageName('@third-party/framework')).toBe('@third-party/framework');\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/get-framework-name.ts",
    "content": "import type { Options } from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\n\nimport { frameworkPackages } from './get-storybook-info.ts';\nimport { normalizePath } from './normalize-path.ts';\n\n/** Framework can be a string or an object. This utility always returns the string name. */\nexport async function getFrameworkName(options: Options) {\n  const framework = await options.presets.apply('framework', '', options);\n\n  if (!framework) {\n    throw new Error(dedent`\n      You must specify a framework in '.storybook/main.js' config.\n\n      https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#framework-field-mandatory\n    `);\n  }\n\n  return typeof framework === 'object' ? framework.name : framework;\n}\n\n/**\n * Extracts the proper framework name from the given framework field. The framework field can be the\n * framework package name or a path to the framework package.\n *\n * @example\n *\n * ```ts\n * extractFrameworkPackageName('/path/to/@storybook/angular'); // => '@storybook/angular'\n * extractFrameworkPackageName('@third-party/framework'); // => '@third-party/framework'\n * ```\n */\nexport const extractFrameworkPackageName = (framework: string) => {\n  const normalizedPath = normalizePath(framework);\n  const frameworkName = Object.keys(frameworkPackages).find((pkg) => normalizedPath.endsWith(pkg));\n\n  return frameworkName ?? framework;\n};\n"
  },
  {
    "path": "code/core/src/common/utils/get-renderer-name.test.ts",
    "content": "import { describe, expect, test } from 'vitest';\n\nimport { extractRenderer } from './get-renderer-name.ts';\n\ndescribe('get-renderer-name', () => {\n  describe('extractProperRendererNameFromFramework', () => {\n    test('should return the renderer name for a known framework', async () => {\n      const renderer = await extractRenderer('@storybook/react-vite');\n      expect(renderer).toEqual('react');\n    });\n\n    test('should return null for an unknown framework', async () => {\n      const renderer = await extractRenderer('@third-party/framework');\n      expect(renderer).toBeNull();\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/get-renderer-name.ts",
    "content": "import type { Options } from 'storybook/internal/types';\n\nimport { frameworkToRenderer } from './framework.ts';\nimport { extractFrameworkPackageName, getFrameworkName } from './get-framework-name.ts';\nimport { frameworkPackages } from './get-storybook-info.ts';\n\n/**\n * Render is set as a string on core. It must be set by the framework It falls back to the framework\n * name if not set\n */\nexport async function getRendererName(options: Options) {\n  const core = await options.presets.apply('core', {}, options);\n\n  if (!core || !core.renderer) {\n    // At the moment some frameworks (Angular/Ember) do not define a renderer, but themselves\n    // serve the purpose (in particular exporting the symbols needed by entrypoints)\n    return getFrameworkName(options);\n  }\n\n  return core.renderer;\n}\n\n/**\n * Extracts the proper renderer name from the given framework name.\n *\n * @example\n *\n * ```ts\n * extractRenderer('@storybook/react'); // => 'react'\n * extractRenderer('@storybook/angular'); // => 'angular'\n * extractRenderer('@third-party/framework'); // => null\n * ```\n *\n * @param frameworkName The name of the framework.\n * @returns The name of the renderer.\n */\nexport async function extractRenderer(frameworkName: string) {\n  const extractedFrameworkName = extractFrameworkPackageName(frameworkName);\n  const framework = frameworkPackages[extractedFrameworkName];\n\n  if (!framework) {\n    return null;\n  }\n\n  return frameworkToRenderer[framework as keyof typeof frameworkToRenderer];\n}\n"
  },
  {
    "path": "code/core/src/common/utils/get-story-id.test.ts",
    "content": "import { join } from 'node:path';\n\nimport { describe, expect, it } from 'vitest';\n\nimport { getStoryId } from './get-story-id.ts';\n\ndescribe('getStoryId', () => {\n  it('should return the storyId', async () => {\n    const cwd = process.cwd();\n    const options = {\n      configDir: join(cwd, '.storybook'),\n      presets: {\n        apply: (val: string) => {\n          if (val === 'stories') {\n            return Promise.resolve(['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)']);\n          }\n        },\n      },\n    } as any;\n    const storyFilePath = join(cwd, 'src', 'components', 'stories', 'Page1.stories.ts');\n    const exportedStoryName = 'Default';\n\n    const { storyId, kind } = await getStoryId({ storyFilePath, exportedStoryName }, options);\n\n    expect(storyId).toBe('components-stories-page1--default');\n    expect(kind).toBe('components-stories-page1');\n  });\n\n  it('should throw an error if the storyId cannot be calculated', async () => {\n    const cwd = process.cwd();\n    const options = {\n      configDir: join(cwd, '.storybook'),\n      presets: {\n        apply: (val: string) => {\n          if (val === 'stories') {\n            return Promise.resolve(['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)']);\n          }\n        },\n      },\n    } as any;\n    const storyFilePath = join(cwd, 'not-covered-path', 'stories', 'Page1.stories.ts');\n    const exportedStoryName = 'Default';\n\n    await expect(() =>\n      getStoryId({ storyFilePath, exportedStoryName }, options)\n    ).rejects.toThrowError();\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/get-story-id.ts",
    "content": "import { relative } from 'node:path';\n\nimport { normalizeStories, normalizeStoryPath } from 'storybook/internal/common';\nimport { sanitize, storyNameFromExport, toId } from 'storybook/internal/csf';\nimport type { Options, StoriesEntry } from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\n\nimport { userOrAutoTitleFromSpecifier } from '../../preview-api/modules/store/autoTitle.ts';\nimport { posix } from './posix.ts';\n\ninterface StoryIdData {\n  storyFilePath: string;\n  exportedStoryName: string;\n}\n\ntype GetStoryIdOptions = StoryIdData & {\n  configDir: string;\n  stories: StoriesEntry[];\n  workingDir?: string;\n  userTitle?: string;\n  storyFilePath: string;\n};\n\nexport async function getStoryId(data: StoryIdData, options: Options) {\n  const stories = await options.presets.apply('stories', [], options);\n\n  const autoTitle = getStoryTitle({\n    ...data,\n    stories,\n    configDir: options.configDir,\n  });\n\n  if (autoTitle === undefined) {\n    // eslint-disable-next-line local-rules/no-uncategorized-errors\n    throw new Error(dedent`\n    The new story file was successfully generated, but we are unable to index it. Please ensure that the new Story file is matched by the 'stories' glob pattern in your Storybook configuration.\n    `);\n  }\n\n  const storyName = storyNameFromExport(data.exportedStoryName);\n\n  const storyId = toId(autoTitle as string, storyName);\n  const kind = sanitize(autoTitle);\n\n  return { storyId, kind };\n}\n\nexport function getStoryTitle({\n  storyFilePath,\n  configDir,\n  stories,\n  workingDir = process.cwd(),\n  userTitle,\n}: Omit<GetStoryIdOptions, 'exportedStoryName'>) {\n  const normalizedStories = normalizeStories(stories, {\n    configDir,\n    workingDir,\n  });\n\n  const relativePath = relative(workingDir, storyFilePath);\n  const importPath = posix(normalizeStoryPath(relativePath));\n\n  return normalizedStories\n    .map((normalizeStory) => userOrAutoTitleFromSpecifier(importPath, normalizeStory, userTitle))\n    .filter(Boolean)[0];\n}\n"
  },
  {
    "path": "code/core/src/common/utils/get-storybook-configuration.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { getStorybookConfiguration } from './get-storybook-configuration.ts';\n\ndescribe('getStorybookConfiguration', () => {\n  it('handles short names', () => {\n    const port = getStorybookConfiguration('start-storybook -p 9001', '-p', '--port');\n    expect(port).toBe('9001');\n  });\n  it('handles long names', () => {\n    const port = getStorybookConfiguration('start-storybook --port 9001', '-p', '--port');\n    expect(port).toBe('9001');\n  });\n  it('handles equals', () => {\n    const port = getStorybookConfiguration('start-storybook --port=9001', '-p', '--port');\n    expect(port).toBe('9001');\n  });\n  it('handles double space', () => {\n    const port = getStorybookConfiguration('start-storybook --port  9001', '-p', '--port');\n    expect(port).toBe('9001');\n  });\n  it('handles complex scripts', () => {\n    const port = getStorybookConfiguration(\n      \"node verify-node-version.js && concurrently --raw --kill-others 'yarn relay --watch' 'start-storybook -s ./public -p 9001'\",\n      '-p',\n      '--port'\n    );\n    expect(port).toBe('9001');\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/get-storybook-configuration.ts",
    "content": "/*\n * Lifted from chromatic-cli\n *\n * This is not exactly clever but it works most of the time\n * we receive the full text of the npm script, and we look if we can find the cli flag\n */\nexport function getStorybookConfiguration(\n  storybookScript: string,\n  shortName: string,\n  longName: string\n) {\n  if (!storybookScript) {\n    return null;\n  }\n\n  const parts = storybookScript.split(/[\\s='\"]+/);\n  let index = parts.indexOf(longName);\n  if (index === -1) {\n    index = parts.indexOf(shortName);\n  }\n  if (index === -1) {\n    return null;\n  }\n  return parts[index + 1];\n}\n"
  },
  {
    "path": "code/core/src/common/utils/get-storybook-info.ts",
    "content": "import { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\nimport { CoreWebpackCompiler, SupportedFramework } from 'storybook/internal/types';\nimport type {\n  CoreCommon_StorybookInfo,\n  PackageJson,\n  StorybookConfigRaw,\n} from 'storybook/internal/types';\nimport { SupportedBuilder, SupportedRenderer } from 'storybook/internal/types';\n\nimport invariant from 'tiny-invariant';\n\nimport { JsPackageManager } from '../js-package-manager/JsPackageManager.ts';\nimport { frameworkToBuilder } from './framework.ts';\nimport { getAddonNames } from './get-addon-names.ts';\nimport { extractFrameworkPackageName } from './get-framework-name.ts';\nimport { extractRenderer } from './get-renderer-name.ts';\nimport { getStorybookConfiguration } from './get-storybook-configuration.ts';\nimport { loadMainConfig } from './load-main-config.ts';\n\nexport const rendererPackages: Record<string, SupportedRenderer> = {\n  '@storybook/react': SupportedRenderer.REACT,\n  '@storybook/vue3': SupportedRenderer.VUE3,\n  '@storybook/angular': SupportedRenderer.ANGULAR,\n  '@storybook/html': SupportedRenderer.HTML,\n  '@storybook/web-components': SupportedRenderer.WEB_COMPONENTS,\n  '@storybook/ember': SupportedRenderer.EMBER,\n  '@storybook/svelte': SupportedRenderer.SVELTE,\n  '@storybook/preact': SupportedRenderer.PREACT,\n  '@storybook/server': SupportedRenderer.SERVER,\n  '@storybook/react-native': SupportedRenderer.REACT_NATIVE,\n\n  // community (outside of monorepo)\n  'storybook-framework-qwik': SupportedRenderer.QWIK,\n  'storybook-solidjs-vite': SupportedRenderer.SOLID,\n};\n\nexport const frameworkPackages: Record<string, SupportedFramework> = {\n  '@storybook/angular': SupportedFramework.ANGULAR,\n  '@storybook/ember': SupportedFramework.EMBER,\n  '@storybook/html-vite': SupportedFramework.HTML_VITE,\n  '@storybook/nextjs': SupportedFramework.NEXTJS,\n  '@storybook/preact-vite': SupportedFramework.PREACT_VITE,\n  '@storybook/react-vite': SupportedFramework.REACT_VITE,\n  '@storybook/react-webpack5': SupportedFramework.REACT_WEBPACK5,\n  '@storybook/server-webpack5': SupportedFramework.SERVER_WEBPACK5,\n  '@storybook/svelte-vite': SupportedFramework.SVELTE_VITE,\n  '@storybook/sveltekit': SupportedFramework.SVELTEKIT,\n  '@storybook/vue3-vite': SupportedFramework.VUE3_VITE,\n  '@storybook/nextjs-vite': SupportedFramework.NEXTJS_VITE,\n  '@storybook/react-native-web-vite': SupportedFramework.REACT_NATIVE_WEB_VITE,\n  '@storybook/web-components-vite': SupportedFramework.WEB_COMPONENTS_VITE,\n  // community (outside of monorepo)\n  'storybook-framework-qwik': SupportedFramework.QWIK,\n  'storybook-solidjs-vite': SupportedFramework.SOLID,\n  'storybook-react-rsbuild': SupportedFramework.REACT_RSBUILD,\n  'storybook-vue3-rsbuild': SupportedFramework.VUE3_RSBUILD,\n  'storybook-web-components-rsbuild': SupportedFramework.WEB_COMPONENTS_RSBUILD,\n  'storybook-html-rsbuild': SupportedFramework.HTML_RSBUILD,\n  '@storybook-vue/nuxt': SupportedFramework.NUXT,\n};\n\nexport const builderPackages: Record<string, SupportedBuilder> = {\n  '@storybook/builder-webpack5': SupportedBuilder.WEBPACK5,\n  '@storybook/builder-vite': SupportedBuilder.VITE,\n  // community (outside of monorepo)\n  'storybook-builder-rsbuild': SupportedBuilder.RSBUILD,\n};\n\nexport const compilerPackages: Record<string, CoreWebpackCompiler> = {\n  '@storybook/addon-webpack5-compiler-babel': CoreWebpackCompiler.Babel,\n  '@storybook/addon-webpack5-compiler-swc': CoreWebpackCompiler.SWC,\n};\n\nconst findDependency = (\n  { dependencies, devDependencies, peerDependencies }: PackageJson,\n  predicate: (entry: [string, string | undefined]) => boolean\n) =>\n  [\n    Object.entries(dependencies || {}).find(predicate),\n    Object.entries(devDependencies || {}).find(predicate),\n    Object.entries(peerDependencies || {}).find(predicate),\n  ] as const;\n\nconst getStorybookVersionSpecifier = (configDir: string) => {\n  const packageJsonPaths = JsPackageManager.listAllPackageJsonPaths(dirname(configDir));\n\n  for (const packageJsonPath of packageJsonPaths) {\n    const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n    // Pull the viewlayer from dependencies in package.json\n    const [dep, devDep, peerDep] = findDependency(packageJson, ([key]) => key === 'storybook');\n    const [pkg, version] = dep || devDep || peerDep || [];\n\n    if (pkg && version) {\n      return version;\n    }\n  }\n\n  return undefined;\n};\n\nconst validConfigExtensions = ['ts', 'js', 'tsx', 'jsx', 'mjs', 'cjs'];\n\nexport const findConfigFile = (prefix: string, configDir: string) => {\n  const filePrefix = join(configDir, prefix);\n  const extension = validConfigExtensions.find((ext: string) => existsSync(`${filePrefix}.${ext}`));\n  return extension ? `${filePrefix}.${extension}` : null;\n};\n\nexport const getConfigInfo = (configDir?: string) => {\n  let storybookConfigDir = configDir ?? '.storybook';\n\n  if (!existsSync(storybookConfigDir)) {\n    const packageJsonPaths = JsPackageManager.listAllPackageJsonPaths(storybookConfigDir);\n\n    for (const packageJsonPath of packageJsonPaths) {\n      const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n      const storybookScript = packageJson.scripts?.storybook;\n      if (storybookScript && !configDir) {\n        const configParam = getStorybookConfiguration(storybookScript, '-c', '--config-dir');\n\n        if (configParam) {\n          storybookConfigDir = configParam;\n          break;\n        }\n      }\n    }\n  }\n\n  return {\n    configDir: storybookConfigDir,\n    mainConfigPath: findConfigFile('main', storybookConfigDir),\n    previewConfigPath: findConfigFile('preview', storybookConfigDir),\n    managerConfigPath: findConfigFile('manager', storybookConfigDir),\n  };\n};\n\nexport const getStorybookInfo = async (\n  configDir = '.storybook',\n  cwd?: string\n): Promise<CoreCommon_StorybookInfo> => {\n  const configInfo = getConfigInfo(configDir);\n  const mainConfig = (await loadMainConfig({\n    configDir: configInfo.configDir,\n    cwd,\n  })) as StorybookConfigRaw;\n\n  invariant(mainConfig, `Unable to find or evaluate ${configInfo.mainConfigPath}`);\n\n  const frameworkValue = mainConfig.framework;\n  const frameworkField = typeof frameworkValue === 'string' ? frameworkValue : frameworkValue?.name;\n  const addons = getAddonNames(mainConfig);\n  const versionSpecifier = getStorybookVersionSpecifier(configDir);\n\n  if (!frameworkField) {\n    return {\n      ...configInfo,\n      versionSpecifier,\n      addons,\n      mainConfig,\n      mainConfigPath: configInfo.mainConfigPath ?? undefined,\n      previewConfigPath: configInfo.previewConfigPath ?? undefined,\n      managerConfigPath: configInfo.managerConfigPath ?? undefined,\n    };\n  }\n\n  const frameworkPackage = extractFrameworkPackageName(frameworkField);\n\n  const framework = frameworkPackages[frameworkPackage];\n  const renderer = await extractRenderer(frameworkPackage);\n  const builder = frameworkToBuilder[framework];\n\n  const rendererPackage = Object.entries(rendererPackages).find(\n    ([, value]) => value === renderer\n  )?.[0];\n\n  const builderPackage = Object.entries(builderPackages).find(\n    ([, value]) => value === builder\n  )?.[0];\n\n  return {\n    ...configInfo,\n    addons,\n    mainConfig,\n    framework,\n    versionSpecifier,\n    renderer: renderer ?? undefined,\n    builder: builder ?? undefined,\n    frameworkPackage,\n    rendererPackage,\n    builderPackage,\n    mainConfigPath: configInfo.mainConfigPath ?? undefined,\n    previewConfigPath: configInfo.previewConfigPath ?? undefined,\n    managerConfigPath: configInfo.managerConfigPath ?? undefined,\n  };\n};\n"
  },
  {
    "path": "code/core/src/common/utils/get-storybook-refs.test.ts",
    "content": "import { afterEach, describe, expect, it, vi } from 'vitest';\n\nimport { checkRef } from './get-storybook-refs.ts';\n\ndescribe('checkRef', () => {\n  afterEach(() => vi.restoreAllMocks());\n\n  it('returns true when fetch returns 200', async () => {\n    vi.spyOn(global, 'fetch').mockResolvedValue({\n      ok: true,\n      status: 200,\n      json: async () => ({}),\n    } as Response);\n    expect(await checkRef('https://chromatic.com')).toBe(true);\n  });\n\n  it('returns false when fetch returns 401', async () => {\n    vi.spyOn(global, 'fetch').mockResolvedValue({ ok: false, status: 401 } as Response);\n    expect(await checkRef('https://chromatic.com')).toBe(false);\n  });\n\n  it('returns false when fetch returns 200 with loginUrl', async () => {\n    vi.spyOn(global, 'fetch').mockResolvedValue({\n      ok: true,\n      status: 200,\n      json: async () => ({ loginUrl: 'https://chromatic.com/login' }),\n    } as Response);\n    expect(await checkRef('https://chromatic.com')).toBe(false);\n  });\n\n  it('returns false when fetch fails', async () => {\n    vi.spyOn(global, 'fetch').mockRejectedValue(new Error('Network error'));\n    expect(await checkRef('https://chromatic.com')).toBe(false);\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/get-storybook-refs.ts",
    "content": "import { readFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\n\nimport { logger } from 'storybook/internal/node-logger';\nimport type { Options, Ref } from 'storybook/internal/types';\n\nimport * as pkg from 'empathic/package';\nimport * as resolve from 'empathic/resolve';\n\nimport { getProjectRoot } from './paths.ts';\n\nexport const getAutoRefs = async (options: Options): Promise<Record<string, Ref>> => {\n  const location = pkg.up({ cwd: options.configDir, last: getProjectRoot() });\n  if (!location) {\n    return {};\n  }\n  const directory = dirname(location);\n\n  const { dependencies = [], devDependencies = [] } =\n    JSON.parse(await readFile(location, { encoding: 'utf8' })) || {};\n  const deps = Object.keys({ ...dependencies, ...devDependencies });\n\n  const list = await Promise.all(\n    deps.map(async (d) => {\n      try {\n        const l = resolve.from(directory, join(d, 'package.json'));\n\n        const { storybook, name, version } =\n          JSON.parse(await readFile(l, { encoding: 'utf8' })) || {};\n\n        if (storybook?.url) {\n          return { id: name, ...storybook, version };\n        }\n      } catch (error) {\n        if ((error as any).code === 'ERR_PACKAGE_PATH_NOT_EXPORTED') {\n          // silent warning because user can't do anything about it\n          // \"package.json\" is not part of the package's \"exports\" field in its package.json\n          return undefined;\n        }\n        logger.warn(`unable to find package.json for ${d}`);\n        return undefined;\n      }\n      return undefined;\n    })\n  );\n\n  return list.filter(Boolean).reduce(\n    (acc, cur) => ({\n      ...acc,\n      [cur.id]: {\n        id: cur.id.toLowerCase(),\n        url: stripTrailingSlash(cur.url),\n        title: cur.title,\n        version: cur.version,\n      },\n    }),\n    {}\n  );\n};\n\nexport const checkRef = (url: string) =>\n  fetch(`${url}/iframe.html`).then(\n    async ({ ok, status }) => {\n      if (ok) {\n        if (status !== 200) {\n          return false;\n        }\n\n        // so the status is ok, but if we'd ask for JSON we might get a response saying we need to authenticate.\n        const data = await fetch(`${url}/iframe.html`, {\n          headers: { Accept: 'application/json' },\n        });\n        // we might receive non-JSON as a response, because the service ignored our request for JSON response type.\n        if (data.ok && (await (data as any).json().catch(() => ({}))).loginUrl) {\n          return false;\n        }\n      }\n      return ok;\n    },\n    () => false\n  );\n\nconst stripTrailingSlash = (url: string) => url.replace(/\\/$/, '');\n\nconst toTitle = (input: string) => {\n  const result = input\n    .replace(/[A-Z]/g, (f) => ` ${f}`)\n    .replace(/[-_][A-Z]/gi, (f) => ` ${f.toUpperCase()}`)\n    .replace(/-/g, ' ')\n    .replace(/_/g, ' ');\n\n  return `${result.substring(0, 1).toUpperCase()}${result.substring(1)}`.trim();\n};\n\nexport async function getRefs(options: Options) {\n  if (options.test) {\n    return {};\n  }\n\n  const refs = await options.presets.apply<Record<string, Ref>>('refs', await getAutoRefs(options));\n\n  Object.entries(refs).forEach(([key, value]: [string, Ref]) => {\n    if (value.disable) {\n      // Also delete the ref that is disabled in definedRefs\n      delete refs[key];\n\n      return;\n    }\n\n    refs[key.toLowerCase()] = {\n      ...value,\n      id: key.toLowerCase(),\n      title: value.title || toTitle(value.id || key),\n      url: stripTrailingSlash(value.url),\n    };\n  });\n\n  // verify the refs are publicly reachable, if they are not we'll fetch stories.json at runtime, otherwise the ref won't work\n  await Promise.all(\n    Object.entries(refs).map(async ([k, value]) => {\n      const ok = await checkRef(value.url);\n\n      refs[k] = { ...value, type: ok ? 'server-checked' : 'unknown' };\n    })\n  );\n\n  return refs;\n}\n"
  },
  {
    "path": "code/core/src/common/utils/glob-to-regexp.ts",
    "content": "import * as pico from 'picomatch';\n\nexport function globToRegexp(glob: string) {\n  const regex = pico.makeRe(glob, {\n    fastpaths: false,\n    noglobstar: false,\n    bash: false,\n  });\n\n  if (!regex.source.startsWith('^')) {\n    throw new Error(`Invalid glob: >> ${glob} >> ${regex}`);\n  }\n\n  if (!glob.startsWith('./')) {\n    return regex;\n  }\n\n  // makeRe is sort of funny. If you pass it a directory starting with `./` it\n  // creates a matcher that expects files with no prefix (e.g. `src/file.js`)\n  // but if you pass it a directory that starts with `../` it expects files that\n  // start with `../`. Let's make it consistent.\n  // Globs starting `**` need special treatment due to the regex they\n  // produce, specifically a negative look-ahead\n  return new RegExp(\n    ['^\\\\.', glob.startsWith('./**') ? '' : '[\\\\\\\\/]', regex.source.substring(1)].join('')\n  );\n}\n"
  },
  {
    "path": "code/core/src/common/utils/interpolate.ts",
    "content": "/**\n * Return a string corresponding to template filled with bindings using following pattern: For each\n * (key, value) of `bindings` replace, in template, `{{key}}` by escaped version of `value`\n *\n * @param template {String} Template with `{{binding}}`\n * @param bindings {Object} key-value object use to fill the template, `{{key}}` will be replaced by\n *   `escaped(value)`\n * @returns {String} Filled template\n */\nexport const interpolate = (template: string, bindings: Record<string, string>) => {\n  return Object.entries(bindings).reduce((acc, [k, v]) => {\n    const escapedString = v.replace(/\\\\/g, '/').replace(/\\$/g, '$$$');\n    return acc.replace(new RegExp(`{{${k}}}`, 'g'), escapedString);\n  }, template);\n};\n"
  },
  {
    "path": "code/core/src/common/utils/interpret-files.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { extname } from 'node:path';\n\nimport resolve from 'resolve';\n\nexport const supportedExtensions = [\n  '.js',\n  '.ts',\n  '.jsx',\n  '.tsx',\n  '.mjs',\n  '.mts',\n  '.mtsx',\n  '.cjs',\n  '.cts',\n  '.ctsx',\n] as const;\n\nexport function getInterpretedFile(pathToFile: string) {\n  return supportedExtensions\n    .map((ext) => (pathToFile.endsWith(ext) ? pathToFile : `${pathToFile}${ext}`))\n    .find((candidate) => existsSync(candidate));\n}\n\nexport function resolveImport(id: string, options: resolve.SyncOpts): string {\n  const mergedOptions: resolve.SyncOpts = {\n    extensions: supportedExtensions,\n    packageFilter(pkg) {\n      // Prefer 'module' over 'main' if available\n      if (pkg.module) {\n        pkg.main = pkg.module;\n      }\n      return pkg;\n    },\n    ...options,\n  };\n\n  try {\n    return resolve.sync(id, { ...mergedOptions });\n  } catch (error) {\n    const ext = extname(id);\n\n    // if we try to import a JavaScript file it might be that we are actually pointing to\n    // a TypeScript file. This can happen in ES modules as TypeScript requires to import other\n    // TypeScript files with .js extensions\n    // https://www.typescriptlang.org/docs/handbook/esm-node.html#type-in-packagejson-and-new-extensions\n    const newId = ['.js', '.mjs', '.cjs'].includes(ext)\n      ? `${id.slice(0, -2)}ts`\n      : ext === '.jsx'\n        ? `${id.slice(0, -3)}tsx`\n        : null;\n\n    if (!newId) {\n      throw error;\n    }\n    return resolve.sync(newId, { ...mergedOptions, extensions: [] });\n  }\n}\n"
  },
  {
    "path": "code/core/src/common/utils/interpret-require.ts",
    "content": "import { importModule } from '../../shared/utils/module.ts';\nimport { getInterpretedFile } from './interpret-files.ts';\n\nfunction getCandidate(paths: string[]) {\n  for (let i = 0; i < paths.length; i += 1) {\n    const candidate = getInterpretedFile(paths[i]);\n\n    if (candidate) {\n      return candidate;\n    }\n  }\n\n  return undefined;\n}\n\n// TODO: remove this when it is no longer used by @storybook/core-webpack\nexport function serverRequire(filePath: string | string[]) {\n  const paths = Array.isArray(filePath) ? filePath : [filePath];\n  const candidatePath = getCandidate(paths);\n\n  if (!candidatePath) {\n    return null;\n  }\n\n  return importModule(candidatePath);\n}\n"
  },
  {
    "path": "code/core/src/common/utils/load-main-config.ts",
    "content": "import { readFile, rm, writeFile } from 'node:fs/promises';\nimport { join, parse, relative, resolve } from 'node:path';\n\nimport { logger } from 'storybook/internal/node-logger';\nimport { MainFileEvaluationError } from 'storybook/internal/server-errors';\nimport type { StorybookConfig } from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\n\nimport { importModule } from '../../shared/utils/module.ts';\nimport { getInterpretedFile } from './interpret-files.ts';\nimport { validateConfigurationFiles } from './validate-configuration-files.ts';\n\nexport async function loadMainConfig({\n  configDir = '.storybook',\n  cwd,\n  skipCache,\n}: {\n  configDir: string;\n  cwd?: string;\n  skipCache?: boolean;\n}): Promise<StorybookConfig> {\n  await validateConfigurationFiles(configDir, cwd);\n\n  const mainPath = getInterpretedFile(resolve(configDir, 'main')) as string;\n\n  try {\n    const out = await importModule(mainPath, { skipCache });\n    return out;\n  } catch (e) {\n    if (!(e instanceof Error)) {\n      throw e;\n    }\n    if (e.message.includes('not defined in ES module scope')) {\n      logger.info(\n        'Loading main config failed as the file does not seem to be valid ESM. Trying a temporary fix, please ensure the main config is valid ESM.'\n      );\n      const comment =\n        '// end of Storybook 10 migration assistant header, you can delete the above code';\n      const content = await readFile(mainPath, 'utf-8');\n\n      if (!content.includes(comment)) {\n        const header = dedent`\n          import { createRequire } from \"node:module\";\n          import { dirname } from \"node:path\";\n          import { fileURLToPath } from \"node:url\";\n    \n          const __filename = fileURLToPath(import.meta.url);\n          const __dirname = dirname(__filename);\n          const require = createRequire(import.meta.url);\n        `;\n\n        const { ext, name, dir } = parse(mainPath);\n        const modifiedMainPath = join(dir, `${name}.tmp.${ext}`);\n        await writeFile(modifiedMainPath, [header, comment, content].join('\\n\\n'));\n        let out;\n        try {\n          out = await importModule(modifiedMainPath);\n        } finally {\n          await rm(modifiedMainPath);\n        }\n        return out;\n      }\n    }\n\n    throw new MainFileEvaluationError({\n      location: relative(process.cwd(), mainPath),\n      error: e,\n    });\n  }\n}\n"
  },
  {
    "path": "code/core/src/common/utils/load-manager-or-addons-file.ts",
    "content": "import { resolve } from 'node:path';\n\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { dedent } from 'ts-dedent';\n\nimport { getInterpretedFile } from './interpret-files.ts';\n\nexport function loadManagerOrAddonsFile({ configDir }: { configDir: string }) {\n  const storybookCustomAddonsPath = getInterpretedFile(resolve(configDir, 'addons'));\n  const storybookCustomManagerPath = getInterpretedFile(resolve(configDir, 'manager'));\n\n  if (storybookCustomAddonsPath || storybookCustomManagerPath) {\n    logger.step('Loading custom manager config');\n  }\n\n  if (storybookCustomAddonsPath && storybookCustomManagerPath) {\n    throw new Error(dedent`\n      You have both a \"addons.js\" and a \"manager.js\", remove the \"addons.js\" file from your configDir (${resolve(\n        configDir,\n        'addons'\n      )})`);\n  }\n\n  return storybookCustomManagerPath || storybookCustomAddonsPath;\n}\n"
  },
  {
    "path": "code/core/src/common/utils/load-preview-or-config-file.ts",
    "content": "import { resolve } from 'node:path';\n\nimport { dedent } from 'ts-dedent';\n\nimport { getInterpretedFile } from './interpret-files.ts';\n\nexport function loadPreviewOrConfigFile({ configDir }: { configDir: string }) {\n  const storybookConfigPath = getInterpretedFile(resolve(configDir, 'config'));\n  const storybookPreviewPath = getInterpretedFile(resolve(configDir, 'preview'));\n\n  if (storybookConfigPath && storybookPreviewPath) {\n    throw new Error(dedent`\n      You have both a \"config.js\" and a \"preview.js\", remove the \"config.js\" file from your configDir (${resolve(\n        configDir,\n        'config'\n      )})`);\n  }\n\n  return storybookPreviewPath || storybookConfigPath;\n}\n"
  },
  {
    "path": "code/core/src/common/utils/log-config.ts",
    "content": "import picocolors from 'picocolors';\n\nexport function logConfig(caption: unknown, config: unknown) {\n  console.log(picocolors.cyan(String(caption)));\n  console.dir(config, { depth: null });\n}\n"
  },
  {
    "path": "code/core/src/common/utils/normalize-path.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { normalizePath } from './normalize-path.ts';\n\ndescribe('normalize-path', () => {\n  it('should normalize paths', () => {\n    expect(normalizePath('path/to/../file')).toBe('path/file');\n    expect(normalizePath('path/to/./file')).toBe('path/to/file');\n    expect(normalizePath('path\\\\to\\\\file')).toBe('path/to/file');\n    expect(normalizePath('foo\\\\..\\\\bar')).toBe('bar');\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/normalize-path.ts",
    "content": "import { posix } from 'node:path';\n\n/**\n * Normalize a path to use forward slashes and remove .. and .\n *\n * @example\n *\n * ```ts\n * normalizePath('path/to/../file'); // => 'path/file'\n * normalizePath('path/to/./file'); // => 'path/to/file'\n * normalizePath('path\\\\to\\\\file'); // => 'path/to/file'\n * ```\n *\n * @param p The path to normalize\n * @returns The normalized path\n */\nexport function normalizePath(p: string) {\n  return posix.normalize(p.replace(/\\\\/g, '/'));\n}\n"
  },
  {
    "path": "code/core/src/common/utils/normalize-stories.ts",
    "content": "import { lstatSync } from 'node:fs';\nimport { basename, dirname, relative, resolve } from 'node:path';\n\nimport { InvalidStoriesEntryError } from 'storybook/internal/server-errors';\nimport type { NormalizedStoriesSpecifier, StoriesEntry } from 'storybook/internal/types';\n\nimport * as pico from 'picomatch';\n// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\n\nimport { globToRegexp } from './glob-to-regexp.ts';\nimport { normalizeStoryPath } from './paths.ts';\n\nconst DEFAULT_TITLE_PREFIX = '';\nexport const DEFAULT_FILES_PATTERN = '**/*.@(mdx|stories.@(js|jsx|mjs|ts|tsx))';\n\nconst isDirectory = (configDir: string, entry: string) => {\n  try {\n    return lstatSync(resolve(configDir, entry)).isDirectory();\n  } catch (err) {\n    return false;\n  }\n};\n\nexport const getDirectoryFromWorkingDir = ({\n  configDir,\n  workingDir,\n  directory,\n}: NormalizeOptions & { directory: string }) => {\n  const directoryFromConfig = resolve(configDir, directory);\n  const directoryFromWorking = relative(workingDir, directoryFromConfig);\n\n  // relative('/foo', '/foo/src') => 'src'\n  // but we want `./src` to match importPaths\n  return normalizeStoryPath(directoryFromWorking);\n};\n\nexport const normalizeStoriesEntry = (\n  entry: StoriesEntry,\n  { configDir, workingDir, defaultFilesPattern = DEFAULT_FILES_PATTERN }: NormalizeOptions\n): NormalizedStoriesSpecifier => {\n  let specifierWithoutMatcher: Omit<NormalizedStoriesSpecifier, 'importPathMatcher'>;\n\n  if (typeof entry === 'string') {\n    const globResult = pico.scan(entry);\n    if (globResult.isGlob) {\n      const directory = globResult.prefix + globResult.base;\n      const files = globResult.glob;\n\n      specifierWithoutMatcher = {\n        titlePrefix: DEFAULT_TITLE_PREFIX,\n        directory,\n        files,\n      };\n    } else if (isDirectory(configDir, entry)) {\n      specifierWithoutMatcher = {\n        titlePrefix: DEFAULT_TITLE_PREFIX,\n        directory: entry,\n        files: defaultFilesPattern,\n      };\n    } else {\n      specifierWithoutMatcher = {\n        titlePrefix: DEFAULT_TITLE_PREFIX,\n        directory: dirname(entry),\n        files: basename(entry),\n      };\n    }\n  } else {\n    specifierWithoutMatcher = {\n      titlePrefix: DEFAULT_TITLE_PREFIX,\n      files: defaultFilesPattern,\n      ...entry,\n    };\n  }\n\n  // We are going to be doing everything with node importPaths which use\n  // URL format, i.e. `/` as a separator, so let's make sure we've normalized\n  const files = slash(specifierWithoutMatcher.files);\n\n  // At this stage `directory` is relative to `main.js` (the config dir)\n  // We want to work relative to the working dir, so we transform it here.\n  const { directory: directoryRelativeToConfig } = specifierWithoutMatcher;\n\n  const directory = slash(\n    getDirectoryFromWorkingDir({\n      configDir,\n      workingDir,\n      directory: directoryRelativeToConfig,\n    })\n  ).replace(/\\/$/, '');\n\n  // Now make the importFn matcher.\n  const importPathMatcher = globToRegexp(`${directory}/${files}`);\n\n  return {\n    ...specifierWithoutMatcher,\n    directory,\n    importPathMatcher,\n  };\n};\n\ninterface NormalizeOptions {\n  configDir: string;\n  workingDir: string;\n  defaultFilesPattern?: string;\n}\n\nexport const normalizeStories = (entries: StoriesEntry[], options: NormalizeOptions) => {\n  if (!entries || (Array.isArray(entries) && entries.length === 0)) {\n    throw new InvalidStoriesEntryError();\n  }\n\n  return entries.map((entry) => normalizeStoriesEntry(entry, options));\n};\n"
  },
  {
    "path": "code/core/src/common/utils/paths.ts",
    "content": "import { join, relative, resolve, sep } from 'node:path';\n\nimport * as find from 'empathic/find';\nimport * as walk from 'empathic/walk';\nimport { globSync } from 'tinyglobby';\n\nimport { LOCK_FILES } from '../js-package-manager/constants.ts';\n\nlet projectRoot: string | undefined;\n\nexport const getProjectRoot = () => {\n  if (projectRoot) {\n    return projectRoot;\n  }\n\n  // Allow manual override in cases where auto-detect doesn't work\n  if (process.env.STORYBOOK_PROJECT_ROOT) {\n    return process.env.STORYBOOK_PROJECT_ROOT;\n  }\n\n  try {\n    const found = find.up('.git') || find.up('.svn') || find.up('.hg');\n    if (found) {\n      projectRoot = join(found, '..');\n      return projectRoot;\n    }\n  } catch (e) {\n    process.stdout.write(`\\nerror searching for repository root: ${e}\\n`);\n  }\n\n  try {\n    const found = find.any(LOCK_FILES);\n    if (found) {\n      projectRoot = join(found, '..');\n      return projectRoot;\n    }\n  } catch (e) {\n    process.stdout.write(`\\nerror searching for lock file: ${e}\\n`);\n  }\n\n  try {\n    const [basePath, rest] = __dirname.split(`${sep}node_modules${sep}`, 2);\n    if (\n      rest &&\n      !basePath.includes(`${sep}npm-cache${sep}`) &&\n      !relative(basePath, process.cwd()).startsWith('..')\n    ) {\n      projectRoot = basePath;\n      return projectRoot;\n    }\n  } catch (e) {\n    process.stdout.write(`\\nerror searching for splitDirname: ${e}\\n`);\n  }\n\n  projectRoot = process.cwd();\n  return projectRoot;\n};\n\nexport const invalidateProjectRootCache = () => {\n  projectRoot = undefined;\n};\n\n/** Finds files in the directory tree up to the project root */\nexport const findFilesUp = (matchers: string[], baseDir = process.cwd()) => {\n  const matchingFiles: string[] = [];\n  for (const directory of walk.up(baseDir, { last: getProjectRoot() })) {\n    matchingFiles.push(...globSync(matchers, { cwd: directory, absolute: true }));\n  }\n\n  return matchingFiles;\n};\n\nexport const nodePathsToArray = (nodePath: string) =>\n  nodePath\n    .split(process.platform === 'win32' ? ';' : ':')\n    .filter(Boolean)\n    .map((p) => resolve('./', p));\n\nconst relativePattern = /^\\.{1,2}([/\\\\]|$)/;\n\n/** Ensures that a path starts with `./` or `../`, or is entirely `.` or `..` */\nexport function normalizeStoryPath(filename: string) {\n  if (relativePattern.test(filename)) {\n    return filename;\n  }\n\n  return `.${sep}${filename}`;\n}\n"
  },
  {
    "path": "code/core/src/common/utils/posix.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { posix } from './posix.ts';\n\ndescribe('posix', () => {\n  it('should replace backslashes with forward slashes', () => {\n    expect(posix('src\\\\components\\\\Page.tsx', '\\\\')).toBe('src/components/Page.tsx');\n    expect(posix('src\\\\\\\\components\\\\\\\\Page.tsx', '\\\\\\\\')).toBe('src/components/Page.tsx');\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/posix.ts",
    "content": "import { posix as posixPath, sep } from 'node:path';\n\n/** Replaces the path separator with forward slashes */\nexport const posix = (localPath: string, seperator: string = sep) =>\n  localPath.split(seperator).filter(Boolean).join(posixPath.sep);\n"
  },
  {
    "path": "code/core/src/common/utils/readTemplate.ts",
    "content": "import { readFile } from 'node:fs/promises';\n\nexport async function readTemplate(filename: string) {\n  return readFile(filename, {\n    encoding: 'utf8',\n  });\n}\n"
  },
  {
    "path": "code/core/src/common/utils/remove.ts",
    "content": "import { readConfig, writeConfig } from 'storybook/internal/csf-tools';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { dedent } from 'ts-dedent';\n\nimport type { JsPackageManager } from '../js-package-manager/index.ts';\nimport { getConfigInfo } from './get-storybook-info.ts';\n\nexport type RemoveAddonOptions = {\n  packageManager: JsPackageManager;\n  configDir?: string;\n  skipInstall?: boolean;\n};\n\n/**\n * Remove the given addon package and remove it from main.js\n *\n * @example\n *\n * ```sh\n * sb remove @storybook/addon-links\n * ```\n */\nexport async function removeAddon(addon: string, options: RemoveAddonOptions) {\n  const { packageManager, skipInstall } = options;\n\n  const { mainConfigPath, configDir } = getConfigInfo(options.configDir);\n\n  if (typeof configDir === 'undefined') {\n    // eslint-disable-next-line local-rules/no-uncategorized-errors\n    throw new Error(dedent`\n      Unable to find storybook config directory\n    `);\n  }\n\n  if (!mainConfigPath) {\n    logger.error('Unable to find storybook main.js config');\n    return;\n  }\n  const main = await readConfig(mainConfigPath);\n\n  // remove from package.json\n  logger.debug(`Uninstalling ${addon}`);\n  await packageManager.removeDependencies([addon]);\n\n  if (!skipInstall) {\n    await packageManager.installDependencies();\n  }\n\n  const currentAddons = main.getNamesFromPath(['addons']) ?? [];\n\n  // Fault tolerant as the addon might have been removed already\n  if (currentAddons.includes(addon)) {\n    // add to main.js\n    logger.debug(`Removing '${addon}' from main.js addons field.`);\n    try {\n      main.removeEntryFromArray(['addons'], addon);\n      await writeConfig(main);\n    } catch (err) {\n      logger.warn(`Failed to remove '${addon}' from main.js addons field. ${String(err)}`);\n    }\n  }\n}\n"
  },
  {
    "path": "code/core/src/common/utils/resolve-path-in-sb-cache.test.ts",
    "content": "import { join } from 'node:path';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport * as pkg from 'empathic/package';\n\nimport versions from '../versions.ts';\nimport { resolvePathInStorybookCache } from './resolve-path-in-sb-cache.ts';\n\nvi.mock('empathic/package', () => ({\n  cache: vi.fn(),\n}));\n\nvi.mock('../versions.ts', () => ({\n  default: {\n    storybook: '10.3.0-alpha.1',\n  },\n}));\n\ndescribe('resolvePathInStorybookCache', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n  });\n\n  it('should include version in the cache path when using empathic cache', () => {\n    const mockCacheDir = '/mock/node_modules/.cache/storybook';\n    vi.mocked(pkg.cache).mockReturnValue(mockCacheDir);\n\n    const result = resolvePathInStorybookCache('test-file', 'test-sub');\n\n    expect(result).toContain(versions.storybook);\n    expect(result).toBe(join(mockCacheDir, versions.storybook, 'test-sub', 'test-file'));\n  });\n\n  it('should include version in the cache path when falling back to cwd', () => {\n    vi.mocked(pkg.cache).mockReturnValue(undefined);\n    const cwd = process.cwd();\n\n    const result = resolvePathInStorybookCache('test-file', 'test-sub');\n\n    expect(result).toContain(versions.storybook);\n    expect(result).toBe(\n      join(cwd, 'node_modules', '.cache', 'storybook', versions.storybook, 'test-sub', 'test-file')\n    );\n  });\n\n  it('should use default sub directory when not provided', () => {\n    const mockCacheDir = '/mock/node_modules/.cache/storybook';\n    vi.mocked(pkg.cache).mockReturnValue(mockCacheDir);\n\n    const result = resolvePathInStorybookCache('test-file');\n\n    expect(result).toBe(join(mockCacheDir, versions.storybook, 'default', 'test-file'));\n  });\n\n  it('should handle empty file or directory name', () => {\n    const mockCacheDir = '/mock/node_modules/.cache/storybook';\n    vi.mocked(pkg.cache).mockReturnValue(mockCacheDir);\n\n    const result = resolvePathInStorybookCache('', 'test-sub');\n\n    // Note: path.join() normalizes away the trailing slash for empty strings\n    expect(result).toBe(join(mockCacheDir, versions.storybook, 'test-sub'));\n  });\n\n  it('should create consistent paths for the same version', () => {\n    const mockCacheDir = '/mock/node_modules/.cache/storybook';\n    vi.mocked(pkg.cache).mockReturnValue(mockCacheDir);\n\n    const result1 = resolvePathInStorybookCache('file1', 'sub1');\n    const result2 = resolvePathInStorybookCache('file2', 'sub1');\n\n    expect(result1).toContain(versions.storybook);\n    expect(result2).toContain(versions.storybook);\n    // Verify both paths share the same base directory by comparing parent directories\n    const parent1 = result1.substring(0, result1.lastIndexOf(join('sub1', 'file1')));\n    const parent2 = result2.substring(0, result2.lastIndexOf(join('sub1', 'file2')));\n    expect(parent1).toBe(parent2);\n  });\n\n  it('should handle different subdirectories', () => {\n    const mockCacheDir = '/mock/node_modules/.cache/storybook';\n    vi.mocked(pkg.cache).mockReturnValue(mockCacheDir);\n\n    const result1 = resolvePathInStorybookCache('test-file', 'dev-server');\n    const result2 = resolvePathInStorybookCache('test-file', 'telemetry');\n\n    expect(result1).toBe(join(mockCacheDir, versions.storybook, 'dev-server', 'test-file'));\n    expect(result2).toBe(join(mockCacheDir, versions.storybook, 'telemetry', 'test-file'));\n  });\n\n  it('should use \"unknown\" as version when storybook version is not available', () => {\n    const mockCacheDir = '/mock/node_modules/.cache/storybook';\n    vi.mocked(pkg.cache).mockReturnValue(mockCacheDir);\n\n    // Mock the versions module to return a falsy value\n    vi.mocked(versions).storybook = '' as any;\n\n    const result = resolvePathInStorybookCache('test-file', 'test-sub');\n\n    expect(result).toContain('unknown');\n    expect(result).toBe(join(mockCacheDir, 'unknown', 'test-sub', 'test-file'));\n\n    // Reset the mock\n    vi.mocked(versions).storybook = '10.3.0-alpha.1';\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/resolve-path-in-sb-cache.ts",
    "content": "import { join } from 'node:path';\n\nimport * as pkg from 'empathic/package';\n\nimport versions from '../versions.ts';\n\n/**\n * Get the path of the file or directory with input name inside the Storybook cache directory:\n *\n * - `node_modules/.cache/storybook/{version}/{directoryName}` in a Node.js project or npm package\n * - `.cache/storybook/{version}/{directoryName}` otherwise\n *\n * The cache directory includes the Storybook version to ensure that upgrading Storybook\n * automatically invalidates the cache, preventing stale cache issues.\n *\n * @param fileOrDirectoryName {string} Name of the file or directory\n * @param sub {string} Optional subdirectory name (defaults to 'default')\n * @returns {string} Absolute path to the file or directory\n */\nexport function resolvePathInStorybookCache(fileOrDirectoryName: string, sub = 'default'): string {\n  let cacheDirectory = pkg.cache('storybook');\n  cacheDirectory ||= join(process.cwd(), 'node_modules', '.cache', 'storybook');\n\n  // Include the storybook version in the cache path to automatically invalidate\n  // cache when upgrading to a new version\n  const version = versions.storybook || 'unknown';\n\n  return join(cacheDirectory, version, sub, fileOrDirectoryName);\n}\n"
  },
  {
    "path": "code/core/src/common/utils/satisfies.ts",
    "content": "/** Mimicking the satisfies operator until we can upgrade to TS4.9 */\nexport function satisfies<A>() {\n  return <T extends A>(x: T) => x;\n}\n"
  },
  {
    "path": "code/core/src/common/utils/scan-and-transform-files.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport * as paths from './paths.ts';\nimport { scanAndTransformFiles } from './scan-and-transform-files.ts';\n\n// Mock dependencies\nconst mocks = vi.hoisted(() => {\n  return {\n    commonGlobOptions: vi.fn(),\n    promptText: vi.fn(),\n    globby: vi.fn(),\n    loggerLog: vi.fn(),\n  };\n});\n\nvi.mock('./common-glob-options', () => ({\n  commonGlobOptions: mocks.commonGlobOptions,\n}));\n\nvi.mock('storybook/internal/node-logger', () => ({\n  logger: {\n    log: mocks.loggerLog,\n  },\n  prompt: {\n    text: mocks.promptText,\n  },\n}));\n\nvi.mock('globby', () => ({\n  globby: mocks.globby,\n}));\n\ndescribe('scanAndTransformFiles', () => {\n  const mockTransformFn = vi.fn();\n  const mockTransformOptions = { option1: 'value1' };\n  const mockFiles = ['/path/to/file1.js', '/path/to/file2.ts'];\n  const mockErrors = [{ file: '/path/to/file1.js', error: new Error('Test error') }];\n\n  beforeEach(() => {\n    vi.resetAllMocks();\n\n    // Import the mocked modules\n    vi.spyOn(paths, 'getProjectRoot').mockReturnValue('/mock/project/root');\n\n    // Setup mock implementations\n    mocks.promptText.mockResolvedValue('**/*.{js,ts}');\n    mocks.commonGlobOptions.mockReturnValue({ cwd: '/mock/project/root' });\n    mocks.globby.mockResolvedValue(mockFiles);\n\n    // Setup transform function mock\n    mockTransformFn.mockResolvedValue(mockErrors);\n  });\n\n  it('should scan for files and transform them', async () => {\n    // Call the function under test\n    const result = await scanAndTransformFiles({\n      dryRun: false,\n      transformFn: mockTransformFn,\n      transformOptions: mockTransformOptions,\n    });\n\n    // Verify prompt.text was called with the right arguments\n    expect(mocks.promptText).toHaveBeenCalledWith({\n      message: 'Enter a custom glob pattern to scan (or press enter to use default):',\n      initialValue: '**/*.{mjs,cjs,js,jsx,ts,tsx,mdx}',\n    });\n\n    // Verify commonGlobOptions was called\n    expect(mocks.commonGlobOptions).toHaveBeenCalledWith('');\n\n    // Verify transformFn was called with the right arguments\n    expect(mockTransformFn).toHaveBeenCalledWith(mockFiles, mockTransformOptions, false);\n\n    // Verify the result is correct\n    expect(result).toEqual(mockErrors);\n  });\n\n  it('should use custom prompt message and default glob when provided', async () => {\n    // Call the function under test with custom options\n    await scanAndTransformFiles({\n      promptMessage: 'Custom prompt message',\n      defaultGlob: '**/*.custom',\n      dryRun: false,\n      transformFn: mockTransformFn,\n      transformOptions: mockTransformOptions,\n    });\n\n    // Verify prompt.text was called with the custom options\n    expect(mocks.promptText).toHaveBeenCalledWith({\n      message: 'Custom prompt message',\n      initialValue: '**/*.custom',\n    });\n  });\n\n  it('should pass dry run flag to transform function', async () => {\n    // Call the function under test with dryRun: true\n    await scanAndTransformFiles({\n      dryRun: true,\n      transformFn: mockTransformFn,\n      transformOptions: mockTransformOptions,\n    });\n\n    // Verify transformFn was called with dryRun: true\n    expect(mockTransformFn).toHaveBeenCalledWith(mockFiles, mockTransformOptions, true);\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/scan-and-transform-files.ts",
    "content": "import { logger, prompt } from 'storybook/internal/node-logger';\n\nimport { commonGlobOptions } from './common-glob-options.ts';\nimport { getProjectRoot } from './paths.ts';\n\n/**\n * Helper function to scan for files matching a glob pattern and transform them\n *\n * @param options Configuration options\n * @param transform Function to transform the found files\n * @returns Array of errors encountered during transformation\n */\nexport async function scanAndTransformFiles<T extends Record<string, unknown>>({\n  promptMessage = 'Enter a custom glob pattern to scan (or press enter to use default):',\n  defaultGlob = '**/*.{mjs,cjs,js,jsx,ts,tsx,mdx}',\n  dryRun = false,\n  force = false,\n  transformFn,\n  transformOptions,\n}: {\n  promptMessage?: string;\n  defaultGlob?: string;\n  dryRun: boolean;\n  force?: boolean;\n  transformFn: (\n    files: string[],\n    options: T,\n    dryRun: boolean\n  ) => Promise<Array<{ file: string; error: Error }>>;\n  transformOptions: T;\n}): Promise<Array<{ file: string; error: Error }>> {\n  // Ask for glob pattern\n  const glob = force\n    ? defaultGlob\n    : await prompt.text({\n        message: promptMessage,\n        initialValue: defaultGlob,\n      });\n\n  logger.log('Scanning for affected files...');\n\n  // eslint-disable-next-line depend/ban-dependencies\n  const globby = (await import('globby')).globby;\n\n  const sourceFiles = await globby([glob], {\n    ...commonGlobOptions(''),\n    ignore: ['**/node_modules/**'],\n    dot: true,\n    cwd: getProjectRoot(),\n    absolute: true,\n  });\n\n  logger.log(`Scanning ${sourceFiles.length} files...`);\n\n  // Transform the files using the provided transform function\n  return transformFn(sourceFiles, transformOptions, dryRun);\n}\n"
  },
  {
    "path": "code/core/src/common/utils/setup-addon-in-config.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { ConfigFile } from 'storybook/internal/csf-tools';\nimport * as csfTools from 'storybook/internal/csf-tools';\nimport type { StorybookConfigRaw } from 'storybook/internal/types';\n\nimport * as loadMainConfigModule from './load-main-config.ts';\nimport { setupAddonInConfig } from './setup-addon-in-config.ts';\nimport * as syncModule from './sync-main-preview-addons.ts';\nimport * as wrapUtils from './wrap-getAbsolutePath-utils.ts';\n\nvi.mock('storybook/internal/csf-tools', { spy: true });\nvi.mock('./sync-main-preview-addons', { spy: true });\nvi.mock('./wrap-getAbsolutePath-utils', { spy: true });\nvi.mock('./load-main-config', { spy: true });\n\ndescribe('setupAddonInConfig', () => {\n  let mockMain: ConfigFile;\n  let mockMainConfig: StorybookConfigRaw;\n\n  beforeEach(() => {\n    vi.clearAllMocks();\n\n    mockMain = {\n      getFieldNode: vi.fn(),\n      valueToNode: vi.fn(),\n      appendNodeToArray: vi.fn(),\n      appendValueToArray: vi.fn(),\n    } as any;\n\n    mockMainConfig = {\n      addons: [],\n    } as any;\n\n    vi.mocked(csfTools.writeConfig).mockResolvedValue();\n    vi.mocked(syncModule.syncStorybookAddons).mockResolvedValue();\n    vi.mocked(loadMainConfigModule.loadMainConfig).mockResolvedValue(mockMainConfig);\n  });\n\n  it('should add addon to main config when no getAbsolutePath wrapper exists', async () => {\n    vi.mocked(mockMain.getFieldNode).mockReturnValue({} as any);\n    vi.mocked(wrapUtils.getAbsolutePathWrapperName).mockReturnValue(null);\n\n    await setupAddonInConfig({\n      addonName: '@storybook/addon-docs',\n      mainConfigCSFFile: mockMain,\n      previewConfigPath: '.storybook/preview.ts',\n      configDir: '.storybook',\n    });\n\n    expect(mockMain.appendValueToArray).toHaveBeenCalledWith(['addons'], '@storybook/addon-docs');\n    expect(mockMain.appendNodeToArray).not.toHaveBeenCalled();\n    expect(wrapUtils.wrapValueWithGetAbsolutePathWrapper).not.toHaveBeenCalled();\n    expect(csfTools.writeConfig).toHaveBeenCalledWith(mockMain);\n    expect(loadMainConfigModule.loadMainConfig).toHaveBeenCalledWith({\n      configDir: '.storybook',\n      skipCache: true,\n    });\n    expect(syncModule.syncStorybookAddons).toHaveBeenCalledWith(\n      mockMainConfig,\n      '.storybook/preview.ts',\n      '.storybook'\n    );\n  });\n\n  it('should add addon with getAbsolutePath wrapper when wrapper exists', async () => {\n    const mockAddonNode = { type: 'StringLiteral' } as any;\n\n    vi.mocked(mockMain.getFieldNode).mockReturnValue({} as any);\n    vi.mocked(mockMain.valueToNode).mockReturnValue(mockAddonNode);\n    vi.mocked(wrapUtils.getAbsolutePathWrapperName).mockReturnValue('getAbsolutePath');\n    vi.mocked(wrapUtils.wrapValueWithGetAbsolutePathWrapper).mockImplementation(() => {});\n\n    await setupAddonInConfig({\n      addonName: '@storybook/addon-docs',\n      mainConfigCSFFile: mockMain,\n      previewConfigPath: '.storybook/preview.ts',\n      configDir: '.storybook',\n    });\n\n    expect(mockMain.valueToNode).toHaveBeenCalledWith('@storybook/addon-docs');\n    expect(mockMain.appendNodeToArray).toHaveBeenCalledWith(['addons'], mockAddonNode);\n    expect(wrapUtils.wrapValueWithGetAbsolutePathWrapper).toHaveBeenCalledWith(\n      mockMain,\n      mockAddonNode\n    );\n    expect(mockMain.appendValueToArray).not.toHaveBeenCalled();\n    expect(csfTools.writeConfig).toHaveBeenCalledWith(mockMain);\n    expect(loadMainConfigModule.loadMainConfig).toHaveBeenCalledWith({\n      configDir: '.storybook',\n      skipCache: true,\n    });\n    expect(syncModule.syncStorybookAddons).toHaveBeenCalledWith(\n      mockMainConfig,\n      '.storybook/preview.ts',\n      '.storybook'\n    );\n  });\n\n  it('should write config even when addon field does not exist', async () => {\n    vi.mocked(mockMain.getFieldNode).mockReturnValue(undefined);\n\n    await setupAddonInConfig({\n      addonName: '@storybook/addon-docs',\n      mainConfigCSFFile: mockMain,\n      previewConfigPath: '.storybook/preview.ts',\n      configDir: '.storybook',\n    });\n\n    expect(mockMain.appendValueToArray).toHaveBeenCalledWith(['addons'], '@storybook/addon-docs');\n    expect(csfTools.writeConfig).toHaveBeenCalledWith(mockMain);\n  });\n\n  it('should handle sync errors gracefully', async () => {\n    vi.mocked(mockMain.getFieldNode).mockReturnValue(undefined);\n    vi.mocked(syncModule.syncStorybookAddons).mockRejectedValue(new Error('Sync failed'));\n\n    await expect(\n      setupAddonInConfig({\n        addonName: '@storybook/addon-docs',\n        mainConfigCSFFile: mockMain,\n        previewConfigPath: '.storybook/preview.ts',\n        configDir: '.storybook',\n      })\n    ).resolves.not.toThrow();\n\n    expect(csfTools.writeConfig).toHaveBeenCalledWith(mockMain);\n    expect(syncModule.syncStorybookAddons).toHaveBeenCalled();\n  });\n\n  it('should handle undefined previewConfigPath', async () => {\n    vi.mocked(mockMain.getFieldNode).mockReturnValue(undefined);\n\n    await setupAddonInConfig({\n      addonName: '@storybook/addon-docs',\n      mainConfigCSFFile: mockMain,\n      previewConfigPath: undefined,\n      configDir: '.storybook',\n    });\n\n    expect(mockMain.appendValueToArray).toHaveBeenCalledWith(['addons'], '@storybook/addon-docs');\n    expect(csfTools.writeConfig).toHaveBeenCalledWith(mockMain);\n    // syncStorybookAddons will be called with undefined, which is fine\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/setup-addon-in-config.ts",
    "content": "import type { ConfigFile } from 'storybook/internal/csf-tools';\nimport { writeConfig } from 'storybook/internal/csf-tools';\n\nimport { loadMainConfig } from './load-main-config.ts';\nimport { syncStorybookAddons } from './sync-main-preview-addons.ts';\nimport {\n  getAbsolutePathWrapperName,\n  wrapValueWithGetAbsolutePathWrapper,\n} from './wrap-getAbsolutePath-utils.ts';\n\nexport interface SetupAddonInConfigOptions {\n  addonName: string;\n  mainConfigCSFFile: ConfigFile;\n  previewConfigPath: string | undefined;\n  configDir: string;\n}\n\n/**\n * Setup an addon in the Storybook configuration by adding it to the addons array in main config and\n * syncing it with preview config.\n *\n * @param options Configuration options for setting up the addon\n */\nexport async function setupAddonInConfig({\n  addonName,\n  previewConfigPath,\n  configDir,\n  mainConfigCSFFile,\n}: SetupAddonInConfigOptions): Promise<void> {\n  const mainConfigAddons = mainConfigCSFFile.getFieldNode(['addons']);\n  if (mainConfigAddons && getAbsolutePathWrapperName(mainConfigCSFFile) !== null) {\n    const addonNode = mainConfigCSFFile.valueToNode(addonName);\n    mainConfigCSFFile.appendNodeToArray(['addons'], addonNode as any);\n    wrapValueWithGetAbsolutePathWrapper(mainConfigCSFFile, addonNode as any);\n  } else {\n    mainConfigCSFFile.appendValueToArray(['addons'], addonName);\n  }\n\n  await writeConfig(mainConfigCSFFile);\n\n  // TODO: remove try/catch once CSF factories is shipped, for now gracefully handle any error\n  try {\n    const newMainConfig = await loadMainConfig({ configDir, skipCache: true });\n\n    if (previewConfigPath) {\n      await syncStorybookAddons(newMainConfig, previewConfigPath, configDir);\n    }\n  } catch (e) {\n    //\n  }\n}\n"
  },
  {
    "path": "code/core/src/common/utils/strip-abs-node-modules-path.ts",
    "content": "import { posix, sep } from 'node:path';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\n\nfunction normalizePath(id: string) {\n  return posix.normalize(slash(id));\n}\n\n// We need to convert from an absolute path, to a traditional node module import path,\n// so that vite can correctly pre-bundle/optimize\nexport function stripAbsNodeModulesPath(absPath: string) {\n  // TODO: Evaluate if this is correct after removing pnp compatibility code in SB11\n  // TODO: Evaluate if searching for node_modules in a yarn pnp environment is correct\n  const splits = absPath.split(`node_modules${sep}`);\n  // Return everything after the final \"node_modules/\"\n  return normalizePath(splits[splits.length - 1]);\n}\n"
  },
  {
    "path": "code/core/src/common/utils/symlinks.ts",
    "content": "export function isPreservingSymlinks() {\n  const { NODE_OPTIONS, NODE_PRESERVE_SYMLINKS } = process.env;\n  return !!NODE_PRESERVE_SYMLINKS || NODE_OPTIONS?.includes('--preserve-symlinks');\n}\n"
  },
  {
    "path": "code/core/src/common/utils/sync-main-preview-addons.test.ts",
    "content": "import type { Mock } from 'vitest';\nimport { describe, expect, it, vi } from 'vitest';\n\nimport { loadConfig, printConfig } from 'storybook/internal/csf-tools';\nimport type { StorybookConfigRaw } from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\n\nimport { getAddonAnnotations } from './get-addon-annotations.ts';\nimport { syncPreviewAddonsWithMainConfig } from './sync-main-preview-addons.ts';\n\nvi.mock('./get-addon-annotations');\n\nexpect.addSnapshotSerializer({\n  serialize: (val: any) => (typeof val === 'string' ? dedent(val) : dedent(val.toString())),\n  test: () => true,\n});\n\ndescribe('syncPreviewAddonsWithMainConfig', () => {\n  const mainConfig: StorybookConfigRaw = {\n    stories: [],\n    addons: ['custom-addon', '@storybook/addon-a11y'],\n  };\n\n  const configDir = '/user/storybook/.storybook';\n\n  it('should sync addons between main and preview', async () => {\n    const preview = loadConfig(`\n      import * as myAddonAnnotations from \"custom-addon/preview\";\n      import { definePreview } from \"@storybook/react/preview\";\n\n      export default definePreview({\n        addons: [myAddonAnnotations],\n      });\n    `).parse();\n\n    (getAddonAnnotations as Mock).mockImplementation(() => {\n      return { importName: 'addonA11yAnnotations', importPath: '@storybook/addon-a11y/preview' };\n    });\n\n    const result = await syncPreviewAddonsWithMainConfig(mainConfig, preview, configDir);\n    expect(printConfig(result).code).toMatchInlineSnapshot(`\n      import * as addonA11yAnnotations from \"@storybook/addon-a11y/preview\";\n      import * as myAddonAnnotations from \"custom-addon/preview\";\n      import { definePreview } from \"@storybook/react/preview\";\n\n      export default definePreview({\n        addons: [myAddonAnnotations, addonA11yAnnotations],\n      });\n    `);\n  });\n\n  it('should sync addons as functions when they are core packages', async () => {\n    const preview = loadConfig(`\n      import * as myAddonAnnotations from \"custom-addon/preview\";\n      import { definePreview } from \"@storybook/react/preview\";\n\n      export default definePreview({\n        addons: [myAddonAnnotations],\n      });\n    `).parse();\n\n    (getAddonAnnotations as Mock).mockImplementation(() => {\n      return {\n        importName: 'addonA11yAnnotations',\n        importPath: '@storybook/addon-a11y',\n        isCoreAddon: true,\n      };\n    });\n\n    const result = await syncPreviewAddonsWithMainConfig(mainConfig, preview, configDir);\n    expect(printConfig(result).code).toMatchInlineSnapshot(`\n      import addonA11yAnnotations from \"@storybook/addon-a11y\";\n      import * as myAddonAnnotations from \"custom-addon/preview\";\n      import { definePreview } from \"@storybook/react/preview\";\n\n      export default definePreview({\n        addons: [myAddonAnnotations, addonA11yAnnotations()],\n      });\n    `);\n  });\n\n  it('should add addons if the preview has no addons field', async () => {\n    const originalCode = dedent`\n      import { definePreview } from \"@storybook/react/preview\";\n\n      export default definePreview({\n        tags: []\n      });\n    `;\n    const preview = loadConfig(originalCode).parse();\n\n    (getAddonAnnotations as Mock).mockImplementation(() => {\n      return { importName: 'addonA11yAnnotations', importPath: '@storybook/addon-a11y/preview' };\n    });\n\n    const result = await syncPreviewAddonsWithMainConfig(mainConfig, preview, configDir);\n    expect(printConfig(result).code).toMatchInlineSnapshot(`\n      import * as addonA11yAnnotations from \"@storybook/addon-a11y/preview\";\n      import { definePreview } from \"@storybook/react/preview\";\n\n      export default definePreview({\n        tags: [],\n        addons: [addonA11yAnnotations]\n      });\n    `);\n  });\n\n  // necessary for windows and unix output to match in the assertions\n  const normalizeLineBreaks = (str: string) => str.replace(/\\r/g, '').trim();\n  it('should not add an addon if its annotations path has already been imported', async () => {\n    const originalCode = dedent`\n      import * as addonA11yAnnotations from \"@storybook/addon-a11y/preview\";\n      import * as myAddonAnnotations from \"custom-addon/preview\";\n      import { definePreview } from \"@storybook/react/preview\";\n      const extraAddons = [addonA11yAnnotations]\n      export default definePreview({\n        addons: [myAddonAnnotations, ...extraAddons],\n      });\n    `;\n    const preview = loadConfig(originalCode).parse();\n\n    (getAddonAnnotations as Mock).mockImplementation(() => {\n      return { importName: 'addonA11yAnnotations', importPath: '@storybook/addon-a11y/preview' };\n    });\n\n    const result = await syncPreviewAddonsWithMainConfig(mainConfig, preview, configDir);\n    const transformedCode = normalizeLineBreaks(printConfig(result).code);\n\n    expect(transformedCode).toMatch(originalCode);\n  });\n\n  it('should not modify the code if all addons are already synced', async () => {\n    const originalCode = dedent`\n      import * as addonA11yAnnotations from \"@storybook/addon-a11y/preview\";\n      import * as myAddonAnnotations from \"custom-addon/preview\";\n      import { definePreview } from \"@storybook/react/preview\";\n\n      export default definePreview({\n        addons: [myAddonAnnotations, addonA11yAnnotations],\n      });\n    `;\n    const preview = loadConfig(originalCode).parse();\n\n    (getAddonAnnotations as Mock).mockImplementation(() => {\n      return { importName: 'addonA11yAnnotations', importPath: '@storybook/addon-a11y/preview' };\n    });\n\n    const result = await syncPreviewAddonsWithMainConfig(mainConfig, preview, configDir);\n    const transformedCode = normalizeLineBreaks(printConfig(result).code);\n\n    expect(transformedCode).toMatch(originalCode);\n  });\n\n  it('should add an empty addons array if no addons are installed', async () => {\n    const originalCode = dedent`\n      import { definePreview } from \"@storybook/react/preview\";\n\n      export default definePreview({});\n    `;\n    const preview = loadConfig(originalCode).parse();\n\n    const result = await syncPreviewAddonsWithMainConfig(\n      {\n        addons: [],\n        stories: [],\n      },\n      preview,\n      configDir\n    );\n    const transformedCode = normalizeLineBreaks(printConfig(result).code);\n\n    expect(transformedCode).toMatchInlineSnapshot(`\n      import { definePreview } from \"@storybook/react/preview\";\n\n      export default definePreview({\n        addons: []\n      });\n    `);\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/sync-main-preview-addons.ts",
    "content": "import { types as t } from 'storybook/internal/babel';\nimport {\n  type ConfigFile,\n  isCsfFactoryPreview,\n  readConfig,\n  writeConfig,\n} from 'storybook/internal/csf-tools';\nimport { logger } from 'storybook/internal/node-logger';\nimport type { StorybookConfig } from 'storybook/internal/types';\n\nimport picocolors from 'picocolors';\n\nimport { getAddonAnnotations } from './get-addon-annotations.ts';\nimport { getAddonNames } from './get-addon-names.ts';\n\nexport async function syncStorybookAddons(\n  mainConfig: StorybookConfig,\n  previewConfigPath: string,\n  configDir: string\n) {\n  const previewConfig = await readConfig(previewConfigPath);\n  const modifiedConfig = await syncPreviewAddonsWithMainConfig(\n    mainConfig,\n    previewConfig,\n    configDir\n  );\n\n  await writeConfig(modifiedConfig);\n}\n\nexport async function syncPreviewAddonsWithMainConfig(\n  mainConfig: StorybookConfig,\n  previewConfig: ConfigFile,\n  configDir: string\n): Promise<ConfigFile> {\n  const isCsfFactory = isCsfFactoryPreview(previewConfig);\n\n  if (!isCsfFactory) {\n    return previewConfig;\n  }\n  const existingAddons = previewConfig.getFieldNode(['addons']);\n\n  if (!existingAddons) {\n    previewConfig.setFieldNode(['addons'], t.arrayExpression([]));\n  }\n\n  const addons = getAddonNames(mainConfig);\n  if (!addons) {\n    return previewConfig;\n  }\n\n  const syncedAddons: string[] = [];\n  /**\n   * This goes through all mainConfig.addons, read their package.json and check whether they have an\n   * exports map called preview, if so add to the array\n   */\n  for (const addon of addons) {\n    const annotations = await getAddonAnnotations(addon, configDir);\n    if (annotations) {\n      const hasAlreadyImportedAddonAnnotations = previewConfig._ast.program.body.find(\n        (node) => t.isImportDeclaration(node) && node.source.value === annotations.importPath\n      );\n\n      if (hasAlreadyImportedAddonAnnotations) {\n        continue;\n      }\n\n      if (\n        !existingAddons ||\n        (t.isArrayExpression(existingAddons) &&\n          !existingAddons.elements.some(\n            (element) => t.isIdentifier(element) && element.name === annotations.importName\n          ))\n      ) {\n        syncedAddons.push(addon);\n        // addon-essentials is a special use case that won't have /preview entrypoint but rather /entry-preview\n        if (annotations.isCoreAddon) {\n          // import addonName from 'addon'; + addonName()\n          previewConfig.setImport(annotations.importName, annotations.importPath);\n          previewConfig.appendNodeToArray(\n            ['addons'],\n            t.callExpression(t.identifier(annotations.importName), [])\n          );\n        } else {\n          // import * as addonName from 'addon/preview'; + addonName\n          previewConfig.setImport({ namespace: annotations.importName }, annotations.importPath);\n          previewConfig.appendNodeToArray(['addons'], t.identifier(annotations.importName));\n        }\n      }\n    }\n  }\n\n  if (syncedAddons.length > 0) {\n    logger.log(\n      `Synchronizing addons from main config in ${picocolors.cyan(previewConfig.fileName)}:\\n${syncedAddons.map(picocolors.magenta).join(', ')}`\n    );\n  }\n\n  return previewConfig;\n}\n"
  },
  {
    "path": "code/core/src/common/utils/template.ts",
    "content": "import { existsSync, readFileSync } from 'node:fs';\n\nimport { join, resolve } from 'pathe';\n\nimport { resolvePackageDir } from '../../shared/utils/module.ts';\n\nconst interpolate = (string: string, data: Record<string, string> = {}) =>\n  Object.entries(data).reduce((acc, [k, v]) => acc.replace(new RegExp(`%${k}%`, 'g'), v), string);\n\nexport function getPreviewBodyTemplate(\n  configDirPath: string,\n  interpolations?: Record<string, string>\n) {\n  const base = readFileSync(\n    join(resolvePackageDir('storybook'), 'assets/server/base-preview-body.html'),\n    'utf8'\n  );\n\n  const bodyHtmlPath = resolve(configDirPath, 'preview-body.html');\n  let result = base;\n\n  if (existsSync(bodyHtmlPath)) {\n    result = readFileSync(bodyHtmlPath, 'utf8') + result;\n  }\n\n  return interpolate(result, interpolations);\n}\n\nexport function getPreviewHeadTemplate(\n  configDirPath: string,\n  interpolations?: Record<string, string>\n) {\n  const base = readFileSync(\n    join(resolvePackageDir('storybook'), 'assets/server/base-preview-head.html'),\n    'utf8'\n  );\n  const headHtmlPath = resolve(configDirPath, 'preview-head.html');\n\n  let result = base;\n\n  if (existsSync(headHtmlPath)) {\n    result += readFileSync(headHtmlPath, 'utf8');\n  }\n\n  return interpolate(result, interpolations);\n}\n"
  },
  {
    "path": "code/core/src/common/utils/transform-imports.test.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { describe, expect, it, vi } from 'vitest';\n\nimport { dedent } from 'ts-dedent';\n\nimport { transformImportFiles } from './transform-imports.ts';\n\nconst consolidatedPackages = {\n  '@storybook/core-common': 'storybook/internal/common',\n  '@storybook/theming': 'storybook/theming',\n  '@storybook/components': 'storybook/internal/components',\n  '@storybook/test': 'storybook/test',\n} as const;\n\nvi.mock('node:fs/promises');\n\ndescribe('transformImportFiles', () => {\n  it('should transform import declarations', async () => {\n    const sourceContents = dedent`\n      import { something } from '@storybook/components';\n      import { other } from '@storybook/core-common';\n    `;\n    const sourceFiles = [join('src', 'test.ts')];\n\n    vi.mocked(readFile).mockResolvedValueOnce(sourceContents);\n\n    const errors = await transformImportFiles(sourceFiles, consolidatedPackages, false);\n\n    expect(errors).toHaveLength(0);\n    expect(writeFile).toHaveBeenCalledWith(\n      sourceFiles[0],\n      expect.stringContaining(`from 'storybook/internal/components'`)\n    );\n  });\n\n  it('should transform not transformimport declarations matching a package partially', async () => {\n    const sourceContents = dedent`\n      import { a } from '@storybook/test-runner';\n      import { b } from '@storybook/test';\n    `;\n    const sourceFiles = [join('src', 'test.ts')];\n\n    vi.mocked(readFile).mockResolvedValueOnce(sourceContents);\n\n    const errors = await transformImportFiles(sourceFiles, consolidatedPackages, false);\n\n    expect(errors).toHaveLength(0);\n    expect(writeFile).toHaveBeenCalledWith(\n      sourceFiles[0],\n      dedent`\n      import { a } from '@storybook/test-runner';\n      import { b } from 'storybook/test';\n    `\n    );\n  });\n\n  it('should transform import declarations with sub-paths', async () => {\n    const sourceContents = dedent`\n      import { other } from '@storybook/theming/create';\n    `;\n    const sourceFiles = [join('src', 'test.ts')];\n\n    vi.mocked(readFile).mockResolvedValueOnce(sourceContents);\n\n    const errors = await transformImportFiles(sourceFiles, consolidatedPackages, false);\n\n    expect(errors).toHaveLength(0);\n    expect(writeFile).toHaveBeenCalledWith(\n      sourceFiles[0],\n      expect.stringContaining(`from 'storybook/theming/create'`)\n    );\n  });\n\n  it('should transform require calls', async () => {\n    const sourceContents = dedent`\n      const something = require('@storybook/components');\n      const other = require('@storybook/core-common');\n    `;\n    const sourceFiles = [join('src', 'test.ts')];\n\n    vi.mocked(readFile).mockResolvedValueOnce(sourceContents);\n\n    const errors = await transformImportFiles(sourceFiles, consolidatedPackages, false);\n\n    expect(errors).toHaveLength(0);\n    expect(writeFile).toHaveBeenCalledWith(\n      sourceFiles[0],\n      expect.stringContaining(`require('storybook/internal/components')`)\n    );\n  });\n\n  it('should handle mixed import styles', async () => {\n    const sourceContents = dedent`\n      import { something } from '@storybook/components';\n      const other = require('@storybook/core-common');\n    `;\n    const sourceFiles = [join('src', 'test.ts')];\n\n    vi.mocked(readFile).mockResolvedValueOnce(sourceContents);\n\n    const errors = await transformImportFiles(sourceFiles, consolidatedPackages, false);\n\n    expect(errors).toHaveLength(0);\n    expect(writeFile).toHaveBeenCalledWith(\n      sourceFiles[0],\n      expect.stringContaining(`from 'storybook/internal/components'`)\n    );\n    expect(writeFile).toHaveBeenCalledWith(\n      sourceFiles[0],\n      expect.stringContaining(`require('storybook/internal/common')`)\n    );\n  });\n\n  it('should not transform non-consolidated package imports', async () => {\n    const sourceContents = `\n      import { something } from '@storybook/other-package';\n      const other = require('some-other-package');\n    `;\n    const sourceFiles = [join('src', 'test.ts')];\n\n    vi.mocked(readFile).mockResolvedValueOnce(sourceContents);\n\n    const errors = await transformImportFiles(sourceFiles, consolidatedPackages, false);\n\n    expect(errors).toHaveLength(0);\n    expect(writeFile).not.toHaveBeenCalledWith(sourceFiles[0], expect.any(String));\n  });\n\n  it('should not write files in dry run mode', async () => {\n    const sourceContents = dedent`\n      import { something } from '@storybook/components';\n    `;\n    const sourceFiles = [join('src', 'test.ts')];\n\n    vi.mocked(readFile).mockResolvedValueOnce(sourceContents);\n\n    const errors = await transformImportFiles(sourceFiles, consolidatedPackages, true);\n\n    expect(errors).toHaveLength(0);\n    expect(writeFile).not.toHaveBeenCalled();\n  });\n\n  it('should handle file read errors', async () => {\n    const sourceFiles = [join('src', 'test.ts')];\n    vi.mocked(readFile).mockRejectedValueOnce(new Error('Failed to read file'));\n\n    const errors = await transformImportFiles(sourceFiles, consolidatedPackages, true);\n\n    expect(errors).toHaveLength(1);\n    expect(errors[0]).toMatchObject({\n      file: sourceFiles[0],\n      error: expect.any(Error),\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/transform-imports.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\n\nfunction transformImports(source: string, renamedImports: Record<string, string>) {\n  let hasChanges = false;\n  let transformed = source;\n\n  for (const [from, to] of Object.entries(renamedImports)) {\n    // Match the package name when it's inside either single or double quotes\n    const regex = new RegExp(`(['\"])${from}(\\/.*)?\\\\1`, 'g');\n    if (regex.test(transformed)) {\n      transformed = transformed.replace(regex, `$1${to}$2$1`);\n      hasChanges = true;\n    }\n  }\n\n  return hasChanges ? transformed : null;\n}\n\nexport const transformImportFiles = async (\n  files: string[],\n  renamedImports: Record<string, string>,\n  dryRun?: boolean\n) => {\n  const errors: Array<{ file: string; error: Error }> = [];\n  const { default: pLimit } = await import('p-limit');\n  const limit = pLimit(10);\n\n  await Promise.all(\n    files.map((file) =>\n      limit(async () => {\n        try {\n          const contents = await readFile(file, 'utf-8');\n          const transformed = transformImports(contents, renamedImports);\n          if (!dryRun && transformed) {\n            await writeFile(file, transformed);\n          }\n        } catch (error) {\n          errors.push({ file, error: error as Error });\n        }\n      })\n    )\n  );\n\n  return errors;\n};\n"
  },
  {
    "path": "code/core/src/common/utils/utils.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { groupBy, invariant } from './utils.ts';\n\ndescribe('utils', () => {\n  describe('groupBy', () => {\n    it('should group items by a key selector', () => {\n      const items = [\n        { type: 'fruit', name: 'apple' },\n        { type: 'vegetable', name: 'carrot' },\n        { type: 'fruit', name: 'banana' },\n        { type: 'vegetable', name: 'broccoli' },\n      ];\n\n      const result = groupBy(items, (item) => item.type);\n\n      expect(result).toEqual({\n        fruit: [\n          { type: 'fruit', name: 'apple' },\n          { type: 'fruit', name: 'banana' },\n        ],\n        vegetable: [\n          { type: 'vegetable', name: 'carrot' },\n          { type: 'vegetable', name: 'broccoli' },\n        ],\n      });\n    });\n\n    it('should handle empty arrays', () => {\n      const result = groupBy([], (item) => item);\n\n      expect(result).toEqual({});\n    });\n\n    it('should handle single item', () => {\n      const items = [{ type: 'fruit', name: 'apple' }];\n\n      const result = groupBy(items, (item) => item.type);\n\n      expect(result).toEqual({\n        fruit: [{ type: 'fruit', name: 'apple' }],\n      });\n    });\n\n    it('should pass index to key selector', () => {\n      const items = ['a', 'b', 'c', 'd'];\n      const indices: number[] = [];\n\n      groupBy(items, (_item, index) => {\n        indices.push(index);\n        return index % 2 === 0 ? 'even' : 'odd';\n      });\n\n      expect(indices).toEqual([0, 1, 2, 3]);\n    });\n\n    it('should group by index when key selector uses index', () => {\n      const items = ['a', 'b', 'c', 'd'];\n\n      const result = groupBy(items, (_item, index) => (index % 2 === 0 ? 'even' : 'odd'));\n\n      expect(result).toEqual({\n        even: ['a', 'c'],\n        odd: ['b', 'd'],\n      });\n    });\n\n    it('should handle numeric keys', () => {\n      const items = [{ id: 1 }, { id: 2 }, { id: 1 }];\n\n      const result = groupBy(items, (item) => item.id);\n\n      expect(result).toEqual({\n        1: [{ id: 1 }, { id: 1 }],\n        2: [{ id: 2 }],\n      });\n    });\n\n    it('should handle symbol keys', () => {\n      const key1 = Symbol('key1');\n      const key2 = Symbol('key2');\n      const items = [\n        { key: key1, value: 'a' },\n        { key: key2, value: 'b' },\n        { key: key1, value: 'c' },\n      ];\n\n      const result = groupBy(items, (item) => item.key);\n\n      expect(result[key1]).toEqual([\n        { key: key1, value: 'a' },\n        { key: key1, value: 'c' },\n      ]);\n      expect(result[key2]).toEqual([{ key: key2, value: 'b' }]);\n    });\n\n    it('should handle all items with same key', () => {\n      const items = ['a', 'b', 'c'];\n\n      const result = groupBy(items, () => 'same');\n\n      expect(result).toEqual({\n        same: ['a', 'b', 'c'],\n      });\n    });\n  });\n\n  describe('invariant', () => {\n    it('should not throw when condition is truthy', () => {\n      expect(() => {\n        invariant(true, 'Error message');\n      }).not.toThrow();\n\n      expect(() => {\n        invariant(1, 'Error message');\n      }).not.toThrow();\n\n      expect(() => {\n        invariant('non-empty', 'Error message');\n      }).not.toThrow();\n\n      expect(() => {\n        invariant({}, 'Error message');\n      }).not.toThrow();\n\n      expect(() => {\n        invariant([], 'Error message');\n      }).not.toThrow();\n    });\n\n    it('should throw when condition is falsy', () => {\n      expect(() => {\n        invariant(false, 'Error message');\n      }).toThrow('Error message');\n\n      expect(() => {\n        invariant(0, 'Zero is falsy');\n      }).toThrow('Zero is falsy');\n\n      expect(() => {\n        invariant('', 'Empty string is falsy');\n      }).toThrow('Empty string is falsy');\n\n      expect(() => {\n        invariant(null, 'Null is falsy');\n      }).toThrow('Null is falsy');\n\n      expect(() => {\n        invariant(undefined, 'Undefined is falsy');\n      }).toThrow('Undefined is falsy');\n    });\n\n    it('should throw with default message when no message provided', () => {\n      expect(() => {\n        invariant(false);\n      }).toThrow('Invariant failed');\n    });\n\n    it('should support lazy message evaluation with function', () => {\n      let messageEvaluated = false;\n\n      // Should not evaluate message when condition is true\n      invariant(true, () => {\n        messageEvaluated = true;\n        return 'This should not be evaluated';\n      });\n\n      expect(messageEvaluated).toBe(false);\n    });\n\n    it('should evaluate lazy message when condition is false', () => {\n      let messageEvaluated = false;\n\n      expect(() => {\n        invariant(false, () => {\n          messageEvaluated = true;\n          return 'Lazy evaluated message';\n        });\n      }).toThrow('Lazy evaluated message');\n\n      expect(messageEvaluated).toBe(true);\n    });\n\n    it('should allow expensive message computation only when needed', () => {\n      const expensiveComputation = () => {\n        return Array.from({ length: 1000 })\n          .map((_, i) => `Item ${i}`)\n          .join(', ');\n      };\n\n      // This should be fast because the message is not computed\n      expect(() => {\n        invariant(true, expensiveComputation);\n      }).not.toThrow();\n\n      // This should compute the message\n      expect(() => {\n        invariant(false, expensiveComputation);\n      }).toThrow(/Item 0/);\n    });\n\n    it('should handle complex conditions', () => {\n      const obj = { value: 42 };\n\n      expect(() => {\n        invariant(obj.value > 0, 'Value must be positive');\n      }).not.toThrow();\n\n      expect(() => {\n        invariant(obj.value < 0, 'Value must be negative');\n      }).toThrow('Value must be negative');\n    });\n\n    it('should narrow types with type assertion', () => {\n      function processValue(value: string | null): string {\n        invariant(value !== null, 'Value must not be null');\n        // TypeScript should now know that value is string, not string | null\n        return value.toUpperCase();\n      }\n\n      expect(processValue('test')).toBe('TEST');\n      expect(() => processValue(null)).toThrow('Value must not be null');\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/utils.ts",
    "content": "// Object.groupBy polyfill\nexport const groupBy = <K extends PropertyKey, T>(\n  items: T[],\n  keySelector: (item: T, index: number) => K\n) => {\n  return items.reduce<Record<K, T[]>>(\n    (acc, item, index) => {\n      const key = keySelector(item, index);\n      acc[key] ??= [];\n      acc[key].push(item);\n      return acc;\n    },\n    {} as Record<K, T[]>\n  );\n};\n\n// This invariant allows for lazy evaluation of the message, which we need to avoid excessive computation.\nexport function invariant(\n  condition: unknown,\n  message?: string | (() => string)\n): asserts condition {\n  if (condition) {\n    return;\n  }\n  throw new Error((typeof message === 'function' ? message() : message) ?? 'Invariant failed');\n}\n"
  },
  {
    "path": "code/core/src/common/utils/validate-config.test.ts",
    "content": "import { afterEach, describe, expect, it, vi } from 'vitest';\n\nimport { resolveModulePath } from 'exsolve';\n\nimport { validateFrameworkName } from './validate-config.ts';\n\n// mock exsolve to spy\nvi.mock('exsolve', { spy: true });\n\ndescribe('validateFrameworkName', () => {\n  afterEach(() => {\n    vi.resetAllMocks();\n  });\n  it('should throw if name is undefined', () => {\n    expect(() => validateFrameworkName(undefined)).toThrow();\n  });\n\n  it('should throw if name is a renderer', () => {\n    expect(() => validateFrameworkName('react')).toThrow();\n    expect(() => validateFrameworkName('@storybook/react')).toThrow();\n  });\n\n  it('should not throw if framework is a known framework', () => {\n    expect(() => validateFrameworkName('@storybook/react-vite')).not.toThrow();\n  });\n\n  it('should not throw if framework is unknown (community) but can be resolved', () => {\n    vi.mocked(resolveModulePath).mockImplementation(() => {});\n\n    expect(() => validateFrameworkName('some-community-framework')).not.toThrow();\n  });\n\n  it('should not throw if scoped framework is unknown (community) but can be resolved', () => {\n    vi.mocked(resolveModulePath).mockImplementation(() => {});\n\n    expect(() => validateFrameworkName('@some-community/framework')).not.toThrow();\n  });\n\n  it('should throw if framework is unknown and cannot be resolved', () => {\n    vi.mocked(resolveModulePath).mockImplementation(() => {\n      throw new Error('cannot resolve');\n    });\n\n    expect(() => validateFrameworkName('foo')).toThrow();\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/validate-config.ts",
    "content": "import {\n  CouldNotEvaluateFrameworkError,\n  InvalidFrameworkNameError,\n  MissingFrameworkFieldError,\n} from 'storybook/internal/server-errors';\n\nimport { resolveModulePath } from 'exsolve';\n\nimport { extractFrameworkPackageName } from '../index.ts';\nimport { frameworkPackages } from './get-storybook-info.ts';\n\nconst renderers = ['html', 'preact', 'react', 'server', 'svelte', 'vue', 'vue3', 'web-components'];\n\nconst rendererNames = [...renderers, ...renderers.map((renderer) => `@storybook/${renderer}`)];\n\nexport function validateFrameworkName(\n  frameworkName: string | undefined\n): asserts frameworkName is string {\n  // Throw error if there is no framework field\n  // TODO: maybe this error should not be thrown if we allow empty Storybooks that only use \"refs\" for composition\n  if (!frameworkName) {\n    throw new MissingFrameworkFieldError();\n  }\n\n  // Account for legacy scenario where the framework was referring to a renderer\n  if (rendererNames.includes(frameworkName)) {\n    throw new InvalidFrameworkNameError({ frameworkName });\n  }\n\n  // If we know about the framework, we don't need to validate it\n  const normalizedFrameworkName = extractFrameworkPackageName(frameworkName);\n  if (Object.keys(frameworkPackages).includes(normalizedFrameworkName)) {\n    return;\n  }\n\n  // If it's not a known framework, we need to validate that it's a valid package at least\n  try {\n    resolveModulePath(`${frameworkName}/preset`, {\n      extensions: ['.mjs', '.js', '.cjs'],\n      conditions: ['node', 'import', 'require'],\n    });\n  } catch (err) {\n    throw new CouldNotEvaluateFrameworkError({ frameworkName });\n  }\n}\n"
  },
  {
    "path": "code/core/src/common/utils/validate-configuration-files.ts",
    "content": "import { resolve } from 'node:path';\n\nimport { once } from 'storybook/internal/node-logger';\nimport { MainFileMissingError } from 'storybook/internal/server-errors';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport { glob } from 'glob';\n// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\nimport { dedent } from 'ts-dedent';\n\nimport { supportedExtensions } from './interpret-files.ts';\n\nexport async function validateConfigurationFiles(configDir: string, cwd?: string) {\n  const extensionsPattern = `{${Array.from(supportedExtensions).join(',')}}`;\n  const mainConfigMatches = await glob(slash(resolve(configDir, `main${extensionsPattern}`)), {\n    cwd: cwd ?? process.cwd(),\n  });\n\n  const [mainConfigPath] = mainConfigMatches;\n\n  if (mainConfigMatches.length > 1) {\n    once.warn(dedent`\n      Multiple main files found in your configDir (${resolve(configDir)}).\n      Storybook will use the first one found and ignore the others. Please remove the extra files.\n    `);\n  }\n\n  if (!mainConfigPath) {\n    throw new MainFileMissingError({ location: configDir });\n  }\n}\n"
  },
  {
    "path": "code/core/src/common/utils/wrap-getAbsolutePath-utils.ts",
    "content": "import { types as t } from 'storybook/internal/babel';\nimport type { ConfigFile } from 'storybook/internal/csf-tools';\n\nconst PREFERRED_GET_ABSOLUTE_PATH_WRAPPER_NAME = 'getAbsolutePath';\nconst ALTERNATIVE_GET_ABSOLUTE_PATH_WRAPPER_NAME = 'wrapForPnp';\n\n/**\n * Checks if the following node declarations exists in the main config file.\n *\n * @example\n *\n * ```ts\n * const <name> = () => {};\n * function <name>() {}\n * ```\n */\nexport function doesVariableOrFunctionDeclarationExist(node: t.Node, name: string) {\n  return (\n    (t.isVariableDeclaration(node) &&\n      node.declarations.length === 1 &&\n      t.isVariableDeclarator(node.declarations[0]) &&\n      t.isIdentifier(node.declarations[0].id) &&\n      node.declarations[0].id?.name === name) ||\n    (t.isFunctionDeclaration(node) && t.isIdentifier(node.id) && node.id.name === name)\n  );\n}\n\n/**\n * Wrap a value with getAbsolutePath wrapper.\n *\n * @example\n *\n * ```ts\n * // Before\n * {\n *   framework: '@storybook/react-vite';\n * }\n *\n * // After\n * {\n *   framework: getAbsolutePath('@storybook/react-vite');\n * }\n * ```\n */\nfunction getReferenceToGetAbsolutePathWrapper(config: ConfigFile, value: string) {\n  return t.callExpression(\n    t.identifier(getAbsolutePathWrapperName(config) ?? PREFERRED_GET_ABSOLUTE_PATH_WRAPPER_NAME),\n    [t.stringLiteral(value)]\n  );\n}\n\n/**\n * Returns the name of the getAbsolutePath wrapper function if it exists in the main config file.\n *\n * @returns Name of the getAbsolutePath wrapper function (e.g. `getAbsolutePath`).\n */\nexport function getAbsolutePathWrapperName(config: ConfigFile) {\n  const declarationName = config\n    .getBodyDeclarations()\n    .flatMap((node) =>\n      doesVariableOrFunctionDeclarationExist(node, ALTERNATIVE_GET_ABSOLUTE_PATH_WRAPPER_NAME)\n        ? [ALTERNATIVE_GET_ABSOLUTE_PATH_WRAPPER_NAME]\n        : doesVariableOrFunctionDeclarationExist(node, PREFERRED_GET_ABSOLUTE_PATH_WRAPPER_NAME)\n          ? [PREFERRED_GET_ABSOLUTE_PATH_WRAPPER_NAME]\n          : []\n    );\n\n  if (declarationName.length) {\n    return declarationName[0];\n  }\n\n  return null;\n}\n\n/** Check if the node needs to be wrapped with getAbsolutePath wrapper. */\nexport function isGetAbsolutePathWrapperNecessary(\n  node: t.Node,\n  cb: (node: t.StringLiteral | t.ObjectProperty | t.ArrayExpression) => void = () => {}\n) {\n  if (t.isStringLiteral(node)) {\n    // value will be converted from StringLiteral to CallExpression.\n    cb(node);\n    return true;\n  }\n\n  if (t.isObjectExpression(node)) {\n    const nameProperty = node.properties.find(\n      (property) =>\n        t.isObjectProperty(property) && t.isIdentifier(property.key) && property.key.name === 'name'\n    ) as t.ObjectProperty;\n\n    if (nameProperty && t.isStringLiteral(nameProperty.value)) {\n      cb(nameProperty);\n      return true;\n    }\n  }\n\n  if (\n    t.isArrayExpression(node) &&\n    node.elements.some((element) => element && isGetAbsolutePathWrapperNecessary(element))\n  ) {\n    cb(node);\n    return true;\n  }\n\n  return false;\n}\n\n/**\n * Get all fields that need to be wrapped with getAbsolutePath wrapper.\n *\n * @returns Array of fields that need to be wrapped with getAbsolutePath wrapper.\n */\nexport function getFieldsForGetAbsolutePathWrapper(config: ConfigFile): t.Node[] {\n  const frameworkNode = config.getFieldNode(['framework']);\n  const builderNode = config.getFieldNode(['core', 'builder']);\n  const rendererNode = config.getFieldNode(['core', 'renderer']);\n  const addons = config.getFieldNode(['addons']);\n\n  const fieldsWithRequireWrapper = [\n    ...(frameworkNode ? [frameworkNode] : []),\n    ...(builderNode ? [builderNode] : []),\n    ...(rendererNode ? [rendererNode] : []),\n    ...(addons && t.isArrayExpression(addons) ? [addons] : []),\n  ];\n\n  return fieldsWithRequireWrapper;\n}\n\n/**\n * Returns AST for the following function\n *\n * @example\n *\n * ```ts\n * function getAbsolutePath(value) {\n *   return dirname(fileURLToPath(import.meta.resolve(`${value}/package.json`)));\n * }\n * ```\n */\nexport function getAbsolutePathWrapperAsCallExpression(\n  isConfigTypescript: boolean\n): t.FunctionDeclaration {\n  const functionDeclaration = {\n    ...t.functionDeclaration(\n      t.identifier(PREFERRED_GET_ABSOLUTE_PATH_WRAPPER_NAME),\n      [\n        {\n          ...t.identifier('value'),\n          ...(isConfigTypescript\n            ? { typeAnnotation: t.tsTypeAnnotation(t.tSStringKeyword()) }\n            : {}),\n        },\n      ],\n      t.blockStatement([\n        t.returnStatement(\n          t.callExpression(t.identifier('dirname'), [\n            t.callExpression(t.identifier('fileURLToPath'), [\n              t.callExpression(\n                t.memberExpression(\n                  t.metaProperty(t.identifier('import'), t.identifier('meta')),\n                  t.identifier('resolve')\n                ),\n                [\n                  t.templateLiteral(\n                    [\n                      t.templateElement({ raw: '' }),\n                      t.templateElement({ raw: '/package.json' }, true),\n                    ],\n                    [t.identifier('value')]\n                  ),\n                ]\n              ),\n            ]),\n          ])\n        ),\n      ])\n    ),\n    ...(isConfigTypescript ? { returnType: t.tSTypeAnnotation(t.tsAnyKeyword()) } : {}),\n  };\n\n  t.addComment(\n    functionDeclaration,\n    'leading',\n    '*\\n * This function is used to resolve the absolute path of a package.\\n * It is needed in projects that use Yarn PnP or are set up within a monorepo.\\n'\n  );\n\n  return functionDeclaration;\n}\n\nexport function wrapValueWithGetAbsolutePathWrapper(config: ConfigFile, node: t.Node) {\n  isGetAbsolutePathWrapperNecessary(node, (n) => {\n    if (t.isStringLiteral(n)) {\n      const wrapperNode = getReferenceToGetAbsolutePathWrapper(config, n.value);\n      Object.keys(n).forEach((k) => {\n        delete n[k as keyof typeof n];\n      });\n      Object.keys(wrapperNode).forEach((k) => {\n        (n as any)[k] = wrapperNode[k as keyof typeof wrapperNode];\n      });\n    }\n\n    if (t.isObjectProperty(n) && t.isStringLiteral(n.value)) {\n      n.value = getReferenceToGetAbsolutePathWrapper(config, n.value.value) as any;\n    }\n\n    if (t.isArrayExpression(n)) {\n      n.elements.forEach((element) => {\n        if (element && isGetAbsolutePathWrapperNecessary(element)) {\n          wrapValueWithGetAbsolutePathWrapper(config, element);\n        }\n      });\n    }\n  });\n}\n"
  },
  {
    "path": "code/core/src/common/utils/write-file-with-retry.test.ts",
    "content": "import fs from 'node:fs/promises';\n\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { writeFileWithRetry } from './write-file-with-retry.ts';\n\nvi.mock('node:fs/promises');\n\ndescribe('writeFileWithRetry', () => {\n  const filename: string = 'foo.txt';\n\n  beforeEach(async () => {\n    vi.useFakeTimers();\n  });\n\n  afterEach(async () => {\n    vi.useRealTimers();\n  });\n\n  it('can write to the file', async () => {\n    await writeFileWithRetry(filename, 'foo', { encoding: 'ascii' });\n\n    expect(fs.writeFile).toHaveBeenCalledExactlyOnceWith(filename, 'foo', {\n      encoding: 'ascii',\n    });\n  });\n\n  it('does not retry for errors without a code', async () => {\n    const error = Object.assign(new Error('EBUSY but no code'));\n    vi.mocked(fs.writeFile).mockRejectedValueOnce(error);\n\n    await expect(writeFileWithRetry(filename, 'foo', { encoding: 'utf8' })).rejects.toThrow(error);\n\n    expect(fs.writeFile).toHaveBeenCalledExactlyOnceWith(filename, 'foo', {\n      encoding: 'utf8',\n    });\n  });\n\n  it('does not retry for non-EBUSY errors', async () => {\n    const error = Object.assign(new Error('denied'), { code: 'EPERM' });\n    vi.mocked(fs.writeFile).mockRejectedValueOnce(error);\n\n    await expect(writeFileWithRetry(filename, 'foo', {})).rejects.toThrow(error);\n\n    expect(fs.writeFile).toHaveBeenCalledExactlyOnceWith(filename, 'foo', {});\n  });\n\n  it('retries for EBUSY errors', async () => {\n    const error = Object.assign(new Error('locked'), { code: 'EBUSY' });\n    vi.mocked(fs.writeFile)\n      .mockRejectedValueOnce(error)\n      .mockRejectedValueOnce(error)\n      .mockRejectedValueOnce(error)\n      .mockRejectedValueOnce(error)\n      .mockResolvedValueOnce(undefined);\n\n    let complete = false;\n    const result = writeFileWithRetry(filename, 'foo', { flush: true }).finally(\n      () => (complete = true)\n    );\n\n    await Promise.resolve();\n\n    // The first four attempts fail.\n    for (let i = 1; i <= 4; i++) {\n      expect(fs.writeFile).toHaveBeenCalledTimes(i);\n      expect(fs.writeFile).toHaveBeenNthCalledWith(i, filename, 'foo', { flush: true });\n      expect(complete).toBe(false);\n      expect(vi.getTimerCount()).toBe(1);\n      await vi.advanceTimersByTimeAsync(100);\n    }\n\n    // The fifth attempt succeeds.\n    expect(fs.writeFile).toHaveBeenCalledTimes(5);\n    expect(fs.writeFile).toHaveBeenNthCalledWith(5, filename, 'foo', { flush: true });\n    expect(complete).toBe(true);\n\n    // Verify that the Promise resolves.\n    await expect(result).resolves.toBeUndefined();\n  });\n\n  it('throws when EBUSY errors constantly occur', async () => {\n    const error = Object.assign(new Error('locked'), { code: 'EBUSY' });\n    vi.mocked(fs.writeFile).mockRejectedValue(error);\n\n    const result = expect(writeFileWithRetry(filename, 'foo', { flag: 'w' })).rejects.toThrowError(\n      error\n    );\n\n    // All five attempts fail.\n    for (let i = 1; i <= 5; i++) {\n      if (i > 1) {\n        await vi.advanceTimersByTimeAsync(100);\n      }\n\n      expect(fs.writeFile).toHaveBeenCalledTimes(i);\n      expect(fs.writeFile).toHaveBeenNthCalledWith(i, filename, 'foo', { flag: 'w' });\n    }\n\n    // There should not be a delay after the final attempt.\n    expect(vi.getTimerCount()).toBe(0);\n\n    await result;\n  });\n});\n"
  },
  {
    "path": "code/core/src/common/utils/write-file-with-retry.ts",
    "content": "import { writeFile } from 'node:fs/promises';\n\ntype File = Parameters<typeof writeFile>[0];\ntype Data = Parameters<typeof writeFile>[1];\ntype Options = Parameters<typeof writeFile>[2];\n\nexport async function writeFileWithRetry(file: File, data: Data, options: Options): Promise<void> {\n  const MAX_ATTEMPTS = 5;\n\n  for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {\n    try {\n      await writeFile(file, data, options);\n      return;\n    } catch (err) {\n      // If an EBUSY error occurs on any attempt except\n      // the last, then wait for a bit and try again.\n      // https://github.com/storybookjs/storybook/issues/23131\n      if (attempt < MAX_ATTEMPTS && err instanceof Error && 'code' in err && err.code === 'EBUSY') {\n        await new Promise((resolve) => setTimeout(resolve, 100));\n      } else {\n        throw err;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "code/core/src/common/versions.ts",
    "content": "// auto generated file, do not edit\nexport default {\n  '@storybook/addon-a11y': '10.4.0-alpha.6',\n  '@storybook/addon-docs': '10.4.0-alpha.6',\n  '@storybook/addon-links': '10.4.0-alpha.6',\n  '@storybook/addon-onboarding': '10.4.0-alpha.6',\n  'storybook-addon-pseudo-states': '10.4.0-alpha.6',\n  '@storybook/addon-themes': '10.4.0-alpha.6',\n  '@storybook/addon-vitest': '10.4.0-alpha.6',\n  '@storybook/builder-vite': '10.4.0-alpha.6',\n  '@storybook/builder-webpack5': '10.4.0-alpha.6',\n  storybook: '10.4.0-alpha.6',\n  '@storybook/angular': '10.4.0-alpha.6',\n  '@storybook/ember': '10.4.0-alpha.6',\n  '@storybook/html-vite': '10.4.0-alpha.6',\n  '@storybook/nextjs': '10.4.0-alpha.6',\n  '@storybook/nextjs-vite': '10.4.0-alpha.6',\n  '@storybook/preact-vite': '10.4.0-alpha.6',\n  '@storybook/react-native-web-vite': '10.4.0-alpha.6',\n  '@storybook/react-vite': '10.4.0-alpha.6',\n  '@storybook/react-webpack5': '10.4.0-alpha.6',\n  '@storybook/server-webpack5': '10.4.0-alpha.6',\n  '@storybook/svelte-vite': '10.4.0-alpha.6',\n  '@storybook/sveltekit': '10.4.0-alpha.6',\n  '@storybook/vue3-vite': '10.4.0-alpha.6',\n  '@storybook/web-components-vite': '10.4.0-alpha.6',\n  sb: '10.4.0-alpha.6',\n  '@storybook/cli': '10.4.0-alpha.6',\n  '@storybook/codemod': '10.4.0-alpha.6',\n  '@storybook/core-webpack': '10.4.0-alpha.6',\n  'create-storybook': '10.4.0-alpha.6',\n  '@storybook/csf-plugin': '10.4.0-alpha.6',\n  'eslint-plugin-storybook': '10.4.0-alpha.6',\n  '@storybook/react-dom-shim': '10.4.0-alpha.6',\n  '@storybook/preset-create-react-app': '10.4.0-alpha.6',\n  '@storybook/preset-react-webpack': '10.4.0-alpha.6',\n  '@storybook/preset-server-webpack': '10.4.0-alpha.6',\n  '@storybook/html': '10.4.0-alpha.6',\n  '@storybook/preact': '10.4.0-alpha.6',\n  '@storybook/react': '10.4.0-alpha.6',\n  '@storybook/server': '10.4.0-alpha.6',\n  '@storybook/svelte': '10.4.0-alpha.6',\n  '@storybook/vue3': '10.4.0-alpha.6',\n  '@storybook/web-components': '10.4.0-alpha.6',\n};\n"
  },
  {
    "path": "code/core/src/component-testing/components/DetachedDebuggerMessage.tsx",
    "content": "import React from 'react';\n\nimport { Link } from 'storybook/internal/components';\n\nimport { styled } from 'storybook/theming';\n\nimport { PANEL_ID } from '../constants.ts';\n\nconst Wrapper = styled.div(({ theme: { color, typography, background } }) => ({\n  textAlign: 'start',\n  padding: '11px 15px',\n  fontSize: `${typography.size.s2 - 1}px`,\n  fontWeight: typography.weight.regular,\n  lineHeight: '1rem',\n  background: background.app,\n  borderBottom: `1px solid ${color.border}`,\n  color: color.defaultText,\n  backgroundClip: 'padding-box',\n  position: 'relative',\n}));\n\nexport const DetachedDebuggerMessage = ({ storyUrl }: { storyUrl: string }) => {\n  return (\n    <Wrapper>\n      Debugger controls are not available on composed Storybooks.{' '}\n      <Link\n        href={`${storyUrl}&addonPanel=${PANEL_ID}`}\n        target=\"_blank\"\n        rel=\"noopener noreferrer\"\n        withArrow\n      >\n        Open in external Storybook\n      </Link>\n    </Wrapper>\n  );\n};\n"
  },
  {
    "path": "code/core/src/component-testing/components/EmptyState.tsx",
    "content": "import React, { useEffect, useState } from 'react';\n\nimport { EmptyTabContent, Link } from 'storybook/internal/components';\n\nimport { DocumentIcon } from '@storybook/icons';\n\nimport { useStorybookApi } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport { DOCUMENTATION_PLAY_FUNCTION_LINK } from '../constants.ts';\n\nconst Links = styled.div(({ theme }) => ({\n  display: 'flex',\n  fontSize: theme.typography.size.s2 - 1,\n  gap: 25,\n}));\n\nexport const Empty = () => {\n  const [isLoading, setIsLoading] = useState(true);\n  const api = useStorybookApi();\n  const docsUrl = api.getDocsUrl({\n    subpath: DOCUMENTATION_PLAY_FUNCTION_LINK,\n    versioned: true,\n    renderer: true,\n  });\n\n  // We are adding a small delay to avoid flickering when the story is loading.\n  // It takes a bit of time for the controls to appear, so we don't want\n  // to show the empty state for a split second.\n  useEffect(() => {\n    const load = setTimeout(() => {\n      setIsLoading(false);\n    }, 100);\n\n    return () => clearTimeout(load);\n  }, []);\n\n  if (isLoading) {\n    return null;\n  }\n\n  return (\n    <div>\n      <EmptyTabContent\n        title=\"Interactions\"\n        description={\n          <>\n            Interactions allow you to verify the functional aspects of UIs. Write a play function\n            for your story and you&apos;ll see it run here.\n          </>\n        }\n        footer={\n          <Links>\n            <Link href={docsUrl} target=\"_blank\" withArrow>\n              <DocumentIcon /> Read docs\n            </Link>\n          </Links>\n        }\n      />\n    </div>\n  );\n};\n"
  },
  {
    "path": "code/core/src/component-testing/components/Interaction.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { expect, userEvent, within } from 'storybook/test';\n\nimport { CallStates } from '../../instrumenter/types.ts';\nimport { getCalls } from '../mocks/index.ts';\nimport { Interaction } from './Interaction.tsx';\nimport ToolbarStories from './Toolbar.stories.tsx';\n\ntype Story = StoryObj<typeof Interaction>;\n\nexport default {\n  title: 'Interaction',\n  component: Interaction,\n  args: {\n    callsById: new Map(getCalls(CallStates.DONE).map((call) => [call.id, call])),\n    controls: ToolbarStories.args.controls,\n    controlStates: ToolbarStories.args.controlStates,\n  },\n} as Meta<typeof Interaction>;\n\nexport const Render: Story = {\n  args: {\n    call: getCalls(CallStates.DONE, 1)[0],\n  },\n};\n\nexport const RenderError: Story = {\n  args: {\n    call: getCalls(CallStates.ERROR, 1)[0],\n  },\n};\n\nexport const Active: Story = {\n  args: {\n    call: getCalls(CallStates.ACTIVE, -1)[0],\n  },\n};\n\nexport const Waiting: Story = {\n  args: {\n    call: getCalls(CallStates.WAITING, -1)[0],\n  },\n};\n\nexport const Failed: Story = {\n  args: {\n    call: getCalls(CallStates.ERROR, -1)[0],\n  },\n};\n\nexport const Done: Story = {\n  args: {\n    call: getCalls(CallStates.DONE, -1)[0],\n  },\n};\n\nexport const WithParent: Story = {\n  args: {\n    call: { ...getCalls(CallStates.DONE, -1)[0], ancestors: ['parent-id'] },\n  },\n};\n\nexport const Disabled: Story = {\n  args: { ...Done.args, controlStates: { ...ToolbarStories.args.controlStates, goto: false } },\n};\n\nexport const Hovered: Story = {\n  ...Done,\n  globals: { sb_theme: 'light' },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    await userEvent.hover(canvas.getByRole('button'));\n    await expect(canvas.getByTestId('icon-active')).toBeInTheDocument();\n  },\n};\n"
  },
  {
    "path": "code/core/src/component-testing/components/Interaction.tsx",
    "content": "import * as React from 'react';\n\nimport { Button } from 'storybook/internal/components';\n\nimport { ChevronDownIcon, ChevronUpIcon } from '@storybook/icons';\n\nimport { transparentize } from 'polished';\nimport { styled, typography } from 'storybook/theming';\n\nimport { type Call, CallStates, type ControlStates } from '../../instrumenter/types.ts';\nimport { INTERNAL_RENDER_CALL_ID } from '../constants.ts';\nimport { isChaiError, isJestError, useAnsiToHtmlFilter } from '../utils.ts';\nimport type { Controls } from './InteractionsPanel.tsx';\nimport { MatcherResult } from './MatcherResult.tsx';\nimport { MethodCall } from './MethodCall.tsx';\nimport { StatusIcon } from './StatusIcon.tsx';\n\nconst MethodCallWrapper = styled.div({\n  fontFamily: typography.fonts.mono,\n  fontSize: typography.size.s1,\n  overflowWrap: 'break-word',\n  inlineSize: 'calc( 100% - 40px )',\n});\n\nconst RowContainer = styled('div', {\n  shouldForwardProp: (prop) => !['call', 'pausedAt'].includes(prop.toString()),\n})<{ call: Call; pausedAt: Call['id'] | undefined }>(\n  ({ theme, call }) => ({\n    position: 'relative',\n    display: 'flex',\n    flexDirection: 'column',\n    borderBottom: `1px solid ${theme.appBorderColor}`,\n    fontFamily: typography.fonts.base,\n    fontSize: 13,\n    ...(call.status === CallStates.ERROR && {\n      backgroundColor:\n        theme.base === 'dark'\n          ? transparentize(0.93, theme.color.negative)\n          : theme.background.warning,\n    }),\n    paddingLeft: (call.ancestors?.length ?? 0) * 20,\n  }),\n  ({ theme, call, pausedAt }) =>\n    pausedAt === call.id && {\n      '&::before': {\n        content: '\"\"',\n        position: 'absolute',\n        top: -5,\n        zIndex: 1,\n        borderTop: '4.5px solid transparent',\n        borderLeft: `7px solid ${theme.color.warning}`,\n        borderBottom: '4.5px solid transparent',\n      },\n      '&::after': {\n        content: '\"\"',\n        position: 'absolute',\n        top: -1,\n        zIndex: 1,\n        width: '100%',\n        borderTop: `1.5px solid ${theme.color.warning}`,\n      },\n    }\n);\n\nconst RowHeader = styled.div<{ isInteractive: boolean }>(({ theme, isInteractive }) => ({\n  display: 'flex',\n  '&:hover': isInteractive ? {} : { background: theme.background.hoverable },\n}));\n\nconst RowLabel = styled('button', {\n  shouldForwardProp: (prop) => !['call'].includes(prop.toString()),\n})<React.ButtonHTMLAttributes<HTMLButtonElement> & { call: Call }>(({ theme, disabled, call }) => ({\n  flex: 1,\n  display: 'grid',\n  background: 'none',\n  border: 0,\n  gridTemplateColumns: '15px 1fr',\n  alignItems: 'center',\n  minHeight: 40,\n  margin: 0,\n  padding: '8px 15px',\n  textAlign: 'start',\n  cursor: disabled || call.status === CallStates.ERROR ? 'default' : 'pointer',\n  '&:focus-visible': {\n    outline: 0,\n    boxShadow: `inset 3px 0 0 0 ${\n      call.status === CallStates.ERROR ? theme.color.warning : theme.color.secondary\n    }`,\n    background: call.status === CallStates.ERROR ? 'transparent' : theme.background.hoverable,\n  },\n  '& > div': {\n    opacity: call.status === CallStates.WAITING ? 0.5 : 1,\n  },\n}));\n\nconst RowActions = styled.div({\n  display: 'flex',\n  alignItems: 'center',\n  padding: 6,\n});\n\nconst StyledButton = styled(Button)(({ theme }) => ({\n  color: theme.textMutedColor,\n  margin: '0 3px',\n}));\n\nconst RowMessage = styled('div')(({ theme }) => ({\n  padding: '8px 10px 8px 36px',\n  fontSize: typography.size.s1,\n  color: theme.color.defaultText,\n  pre: {\n    margin: 0,\n    padding: 0,\n  },\n}));\n\nconst ErrorName = styled.span(({ theme }) => ({\n  color: theme.base === 'dark' ? '#5EC1FF' : '#0271B6',\n}));\n\nconst ErrorMessage = styled.span(({ theme }) => ({\n  color: theme.base === 'dark' ? '#eee' : '#444',\n}));\n\nconst ErrorExplainer = styled.p(({ theme }) => ({\n  color: theme.base === 'dark' ? theme.color.negative : theme.color.negativeText,\n  fontSize: theme.typography.size.s2,\n  maxWidth: 500,\n  textWrap: 'balance',\n}));\n\nconst Exception = ({ exception }: { exception: Call['exception'] }) => {\n  const filter = useAnsiToHtmlFilter();\n  if (!exception) {\n    return null;\n  }\n  if (exception.callId === INTERNAL_RENDER_CALL_ID) {\n    return (\n      <RowMessage>\n        <pre>\n          <ErrorName>{exception.name}:</ErrorName> <ErrorMessage>{exception.message}</ErrorMessage>\n        </pre>\n        <ErrorExplainer>\n          The component failed to render properly. Automated component tests will not run until this\n          is resolved. Check the full error message in Storybook’s canvas to debug.\n        </ErrorExplainer>\n      </RowMessage>\n    );\n  }\n  if (isJestError(exception)) {\n    return <MatcherResult {...exception} />;\n  }\n  if (isChaiError(exception)) {\n    return (\n      <RowMessage>\n        <MatcherResult\n          message={`${exception.message}${exception.diff ? `\\n\\n${exception.diff}` : ''}`}\n          style={{ padding: 0 }}\n        />\n        <p>See the full stack trace in the browser console.</p>\n      </RowMessage>\n    );\n  }\n\n  const paragraphs = exception.message.split('\\n\\n');\n  const more = paragraphs.length > 1;\n  return (\n    <RowMessage>\n      <pre dangerouslySetInnerHTML={{ __html: filter.toHtml(paragraphs[0]) }}></pre>\n      {more && <p>See the full stack trace in the browser console.</p>}\n    </RowMessage>\n  );\n};\n\nexport const Interaction = ({\n  call,\n  callsById,\n  controls,\n  controlStates,\n  childCallIds,\n  isHidden,\n  isCollapsed,\n  toggleCollapsed,\n  pausedAt,\n}: {\n  call: Call;\n  callsById: Map<Call['id'], Call>;\n  controls: Controls;\n  controlStates: ControlStates;\n  childCallIds?: Call['id'][];\n  isHidden: boolean;\n  isCollapsed: boolean;\n  toggleCollapsed: () => void;\n  pausedAt?: Call['id'];\n}) => {\n  const [isHovered, setIsHovered] = React.useState(false);\n  const isInteractive = !controlStates.goto || !call.interceptable || !!call.ancestors?.length;\n\n  if (isHidden) {\n    return null;\n  }\n\n  if (call.id === INTERNAL_RENDER_CALL_ID) {\n    return null;\n  }\n\n  return (\n    <RowContainer call={call} pausedAt={pausedAt}>\n      <RowHeader isInteractive={isInteractive}>\n        <RowLabel\n          aria-label=\"Interaction step\"\n          call={call}\n          onClick={() => controls.goto(call.id)}\n          disabled={isInteractive}\n          onMouseEnter={() => controlStates.goto && setIsHovered(true)}\n          onMouseLeave={() => controlStates.goto && setIsHovered(false)}\n        >\n          <StatusIcon status={isHovered ? CallStates.ACTIVE : call.status} />\n          <MethodCallWrapper style={{ marginLeft: 6, marginBottom: 1 }}>\n            <MethodCall call={call} callsById={callsById} />\n          </MethodCallWrapper>\n        </RowLabel>\n        <RowActions>\n          {(childCallIds?.length ?? 0) > 0 && (\n            <StyledButton\n              padding=\"small\"\n              variant=\"ghost\"\n              onClick={toggleCollapsed}\n              ariaLabel={`${isCollapsed ? 'Show' : 'Hide'} steps`}\n            >\n              {/* FIXME: accordion pattern */}\n              {isCollapsed ? <ChevronDownIcon /> : <ChevronUpIcon />}\n            </StyledButton>\n          )}\n        </RowActions>\n      </RowHeader>\n\n      {call.status === CallStates.ERROR && call.exception?.callId === call.id && (\n        <Exception exception={call.exception} />\n      )}\n    </RowContainer>\n  );\n};\n"
  },
  {
    "path": "code/core/src/component-testing/components/InteractionsPanel.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { ManagerContext } from 'storybook/manager-api';\nimport { expect, fn, userEvent, waitFor, within } from 'storybook/test';\nimport { styled } from 'storybook/theming';\n\nimport { isChromatic } from '../../../../.storybook/isChromatic.ts';\nimport { CallStates } from '../../instrumenter/types.ts';\nimport { getCalls, getInteractions } from '../mocks/index.ts';\nimport { InteractionsPanel } from './InteractionsPanel.tsx';\nimport ToolbarStories from './Toolbar.stories.tsx';\n\nconst StyledWrapper = styled.div(({ theme }) => ({\n  backgroundColor: theme.background.content,\n  color: theme.color.defaultText,\n  display: 'block',\n  height: '100%',\n  position: 'absolute',\n  left: 0,\n  right: 0,\n  bottom: 0,\n  overflow: 'auto',\n}));\n\nconst interactions = getInteractions(CallStates.DONE);\nconst managerContext: any = {\n  state: {},\n  api: {\n    getDocsUrl: fn().mockName('api::getDocsUrl'),\n    emit: fn().mockName('api::emit'),\n    getData: fn()\n      .mockName('api::getData')\n      .mockImplementation(() => ({\n        importPath: 'core/src/component-testing/components/InteractionsPanel.stories.tsx',\n      })),\n  },\n};\n\nconst meta = {\n  title: 'InteractionsPanel',\n  component: InteractionsPanel,\n  decorators: [\n    (Story: any) => (\n      <ManagerContext.Provider value={managerContext}>\n        <StyledWrapper id=\"panel-tab-content\">\n          <Story />\n        </StyledWrapper>\n      </ManagerContext.Provider>\n    ),\n  ],\n  parameters: { layout: 'fullscreen' },\n  args: {\n    status: 'completed',\n    calls: new Map(getCalls(CallStates.DONE).map((call) => [call.id, call])),\n    controls: ToolbarStories.args.controls,\n    controlStates: ToolbarStories.args.controlStates,\n    interactions,\n    fileName: 'addon-interactions.stories.tsx',\n    hasException: false,\n    onScrollToEnd: () => {},\n    endRef: null,\n    // prop for the AddonPanel used as wrapper of Panel\n    active: true,\n  },\n} as Meta<typeof InteractionsPanel>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Passing: Story = {\n  args: {\n    browserTestStatus: CallStates.DONE,\n    interactions: getInteractions(CallStates.DONE),\n  },\n  play: async ({ args, canvasElement, step }) => {\n    if (isChromatic()) {\n      return;\n    }\n    const canvas = within(canvasElement);\n\n    await step('Go to start', async () => {\n      const btn = await canvas.findByLabelText('Go to start');\n      await userEvent.click(btn);\n      await expect(args.controls.start).toHaveBeenCalled();\n    });\n\n    await step('Go back', async () => {\n      const btn = await canvas.findByLabelText('Go back');\n      await userEvent.click(btn);\n      await expect(args.controls.back).toHaveBeenCalled();\n    });\n\n    await step('Go forward', async () => {\n      const btn = await canvas.findByLabelText('Go forward');\n      await userEvent.click(btn);\n      await expect(args.controls.next).not.toHaveBeenCalled();\n    });\n\n    await step('Go to end', async () => {\n      const btn = await canvas.findByLabelText('Go to end');\n      await userEvent.click(btn);\n      await expect(args.controls.end).not.toHaveBeenCalled();\n    });\n\n    await step('Rerun', async () => {\n      const btn = await canvas.findByLabelText('Rerun');\n      await userEvent.click(btn);\n      await expect(args.controls.rerun).toHaveBeenCalled();\n    });\n  },\n};\n\nexport const Paused: Story = {\n  args: {\n    status: 'playing',\n    browserTestStatus: CallStates.ACTIVE,\n    interactions: getInteractions(CallStates.WAITING),\n    controlStates: {\n      detached: false,\n      start: false,\n      back: false,\n      goto: true,\n      next: true,\n      end: true,\n    },\n    pausedAt: interactions[interactions.length - 1].id,\n  },\n};\n\nexport const Playing: Story = {\n  args: {\n    status: 'playing',\n    browserTestStatus: CallStates.ACTIVE,\n    interactions: getInteractions(CallStates.ACTIVE),\n  },\n};\n\nexport const Failed: Story = {\n  args: {\n    status: 'errored',\n    browserTestStatus: CallStates.ERROR,\n    hasException: true,\n    interactions: getInteractions(CallStates.ERROR),\n  },\n};\n\nexport const CaughtException: Story = {\n  args: {\n    status: 'errored',\n    browserTestStatus: CallStates.ERROR,\n    hasException: true,\n    interactions: [],\n    caughtException: new TypeError(\"Cannot read properties of undefined (reading 'args')\"),\n  },\n};\n\nexport const DiscrepancyResult: Story = {\n  args: {\n    ...Failed.args,\n    hasResultMismatch: true,\n  },\n};\n\nexport const DetachedDebugger = {\n  args: {\n    browserTestStatus: CallStates.DONE,\n    interactions: getInteractions(CallStates.DONE),\n    controlStates: {\n      detached: true,\n      start: false,\n      back: false,\n      goto: false,\n      next: false,\n      end: false,\n    },\n  },\n};\n\nexport const RenderOnly: Story = {\n  args: {\n    browserTestStatus: CallStates.DONE,\n    interactions: getInteractions(CallStates.DONE).slice(0, 1),\n  },\n};\n\nexport const Empty: Story = {\n  args: {\n    interactions: [],\n    controlStates: {\n      detached: false,\n      start: false,\n      back: false,\n      goto: false,\n      next: false,\n      end: false,\n    },\n  },\n};\n"
  },
  {
    "path": "code/core/src/component-testing/components/InteractionsPanel.tsx",
    "content": "import * as React from 'react';\n\nimport { transparentize } from 'polished';\nimport type { API } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport { type Call, type CallStates, type ControlStates } from '../../instrumenter/types.ts';\nimport { INTERNAL_RENDER_CALL_ID } from '../constants.ts';\nimport { isTestAssertionError, useAnsiToHtmlFilter } from '../utils.ts';\nimport { DetachedDebuggerMessage } from './DetachedDebuggerMessage.tsx';\nimport { Empty } from './EmptyState.tsx';\nimport { Interaction } from './Interaction.tsx';\nimport type { PlayStatus } from './StatusBadge.tsx';\nimport { TestDiscrepancyMessage } from './TestDiscrepancyMessage.tsx';\nimport { Toolbar } from './Toolbar.tsx';\n\nexport interface Controls {\n  start: (args?: any) => void;\n  back: (args?: any) => void;\n  goto: (args?: any) => void;\n  next: (args?: any) => void;\n  end: (args?: any) => void;\n  rerun: (args?: any) => void;\n}\n\ninterface InteractionsPanelProps {\n  storyUrl: string;\n  status: PlayStatus;\n  controls: Controls;\n  controlStates: ControlStates;\n  interactions: (Call & {\n    status?: CallStates;\n    childCallIds?: Call['id'][];\n    isHidden: boolean;\n    isCollapsed: boolean;\n    toggleCollapsed: () => void;\n  })[];\n  fileName?: string;\n  hasException?: boolean;\n  caughtException?: Error;\n  unhandledErrors?: SerializedError[];\n  pausedAt?: Call['id'];\n  calls: Map<string, any>;\n  endRef?: React.Ref<HTMLDivElement>;\n  onScrollToEnd?: () => void;\n  hasResultMismatch?: boolean;\n  browserTestStatus?: CallStates;\n  importPath?: string;\n  canOpenInEditor?: boolean;\n  api: API;\n}\n\nconst Container = styled.div(({ theme }) => ({\n  height: '100%',\n  background: theme.background.content,\n}));\n\nconst CaughtException = styled.div(({ theme }) => ({\n  borderBottom: `1px solid ${theme.appBorderColor}`,\n  backgroundColor:\n    theme.base === 'dark' ? transparentize(0.93, theme.color.negative) : theme.background.warning,\n  padding: 15,\n  fontSize: theme.typography.size.s2 - 1,\n  lineHeight: '19px',\n}));\nconst CaughtExceptionCode = styled.code(({ theme }) => ({\n  margin: '0 1px',\n  padding: 3,\n  fontSize: theme.typography.size.s1 - 1,\n  lineHeight: 1,\n  verticalAlign: 'top',\n  background: 'rgba(0, 0, 0, 0.05)',\n  border: `1px solid ${theme.appBorderColor}`,\n  borderRadius: 3,\n}));\nconst CaughtExceptionTitle = styled.div({\n  paddingBottom: 4,\n  fontWeight: 'bold',\n});\nconst CaughtExceptionDescription = styled.p({\n  margin: 0,\n  padding: '0 0 20px',\n});\n\nconst CaughtExceptionStack = styled.pre(({ theme }) => ({\n  margin: 0,\n  padding: 0,\n  '&:not(:last-child)': {\n    paddingBottom: 16,\n  },\n  fontSize: theme.typography.size.s1 - 1,\n}));\n\nexport const InteractionsPanel: React.FC<InteractionsPanelProps> = React.memo(\n  function InteractionsPanel({\n    storyUrl,\n    status,\n    calls,\n    controls,\n    controlStates,\n    interactions,\n    fileName,\n    hasException,\n    caughtException,\n    unhandledErrors,\n    pausedAt,\n    onScrollToEnd,\n    endRef,\n    hasResultMismatch,\n    browserTestStatus,\n    importPath,\n    canOpenInEditor,\n    api,\n  }) {\n    const filter = useAnsiToHtmlFilter();\n    const hasRealInteractions = interactions.some((i) => i.id !== INTERNAL_RENDER_CALL_ID);\n\n    return (\n      <Container>\n        {hasResultMismatch && <TestDiscrepancyMessage browserTestStatus={browserTestStatus} />}\n        {controlStates.detached && (hasRealInteractions || hasException) && (\n          <DetachedDebuggerMessage storyUrl={storyUrl} />\n        )}\n        <Toolbar\n          controls={controls}\n          controlStates={controlStates}\n          status={status}\n          storyFileName={fileName}\n          onScrollToEnd={onScrollToEnd}\n          importPath={importPath}\n          canOpenInEditor={canOpenInEditor}\n          api={api}\n        />\n        <div aria-label=\"Interactions list\">\n          {interactions.map((call) => (\n            <Interaction\n              key={call.id}\n              call={call}\n              callsById={calls}\n              controls={controls}\n              controlStates={controlStates}\n              childCallIds={call.childCallIds}\n              isHidden={call.isHidden}\n              isCollapsed={call.isCollapsed}\n              toggleCollapsed={call.toggleCollapsed}\n              pausedAt={pausedAt}\n            />\n          ))}\n        </div>\n        {caughtException && !isTestAssertionError(caughtException) && (\n          <CaughtException>\n            <CaughtExceptionTitle>\n              Caught exception in <CaughtExceptionCode>play</CaughtExceptionCode> function\n            </CaughtExceptionTitle>\n            <CaughtExceptionStack\n              data-chromatic=\"ignore\"\n              dangerouslySetInnerHTML={{\n                __html: filter.toHtml(printSerializedError(caughtException)),\n              }}\n            ></CaughtExceptionStack>\n          </CaughtException>\n        )}\n        {unhandledErrors && (\n          <CaughtException>\n            <CaughtExceptionTitle>Unhandled Errors</CaughtExceptionTitle>\n            <CaughtExceptionDescription>\n              Found {unhandledErrors.length} unhandled error{unhandledErrors.length > 1 ? 's' : ''}{' '}\n              while running the play function. This might cause false positive assertions. Resolve\n              unhandled errors or ignore unhandled errors with setting the\n              <CaughtExceptionCode>test.dangerouslyIgnoreUnhandledErrors</CaughtExceptionCode>{' '}\n              parameter to <CaughtExceptionCode>true</CaughtExceptionCode>.\n            </CaughtExceptionDescription>\n\n            {unhandledErrors.map((error, i) => (\n              <CaughtExceptionStack key={i} data-chromatic=\"ignore\">\n                {printSerializedError(error)}\n              </CaughtExceptionStack>\n            ))}\n          </CaughtException>\n        )}\n        <div ref={endRef} />\n        {status === 'completed' && !caughtException && !hasRealInteractions && <Empty />}\n      </Container>\n    );\n  }\n);\n\nexport interface SerializedError {\n  name: string;\n  stack?: string;\n  message: string;\n}\n\nfunction printSerializedError(error: SerializedError) {\n  return error.stack || `${error.name}: ${error.message}`;\n}\n"
  },
  {
    "path": "code/core/src/component-testing/components/MatcherResult.stories.tsx",
    "content": "import React from 'react';\n\nimport { styled } from 'storybook/theming';\nimport { dedent } from 'ts-dedent';\n\nimport { MatcherResult } from './MatcherResult.tsx';\n\nconst StyledWrapper = styled.div(({ theme }) => ({\n  backgroundColor: theme.background.content,\n  padding: '12px 0',\n  boxShadow: `0 0 0 1px ${theme.appBorderColor}`,\n  color: theme.color.defaultText,\n  fontSize: 13,\n}));\n\nexport default {\n  title: 'MatcherResult',\n  component: MatcherResult,\n  decorators: [\n    (Story: any) => (\n      <StyledWrapper>\n        <Story />\n      </StyledWrapper>\n    ),\n  ],\n  parameters: {\n    layout: 'fullscreen',\n  },\n};\n\nexport const Expected = {\n  args: {\n    message: dedent`\n      expected last \"spy\" call to have been called with [ { …(2) } ]\n      \n      - Expected: \n      Array [\n        Object {\n          \"email\": \"michael@chromatic.com\",\n          \"password\": \"testpasswordthatwontfail\",\n        },\n      ]\n      \n      + Received: \n      undefined\n    `,\n  },\n};\n\nexport const ExpectedReceived = {\n  args: {\n    message: dedent`\n      expected last \"spy\" call to have been called with []\n      \n      - Expected\n      + Received\n      \n      - Array []\n      + Array [\n      +   Object {\n      +     \"email\": \"michael@chromatic.com\",\n      +     \"password\": \"testpasswordthatwontfail\",\n      +   },\n      + ]\n    `,\n  },\n};\n\nexport const ExpectedNumberOfCalls = {\n  args: {\n    message: dedent`\n      expected \"spy\" to not be called at all, but actually been called 1 times\n      \n      Received: \n      \n        1st spy call:\n      \n          Array [\n            Object {\n              \"email\": \"michael@chromatic.com\",\n              \"password\": \"testpasswordthatwontfail\",\n            },\n          ]\n      \n      \n      Number of calls: 1\n    `,\n  },\n};\n\nexport const Diff = {\n  args: {\n    message: dedent`\n      expected \"spy\" to be called with arguments: [ { …(2) } ]\n      \n      Received: \n      \n        1st spy call:\n      \n        Array [\n          Object {\n      -     \"email\": \"michael@chromaui.com\",\n      +     \"email\": \"michael@chromatic.com\",\n            \"password\": \"testpasswordthatwontfail\",\n          },\n        ]\n      \n      \n      Number of calls: 1\n    `,\n  },\n};\n"
  },
  {
    "path": "code/core/src/component-testing/components/MatcherResult.tsx",
    "content": "import React from 'react';\n\nimport { styled, typography } from 'storybook/theming';\n\nimport { useAnsiToHtmlFilter } from '../utils.ts';\nimport { Node } from './MethodCall.tsx';\n\nconst getParams = (line: string, fromIndex = 0): string => {\n  for (let i = fromIndex, depth = 1; i < line.length; i += 1) {\n    if (line[i] === '(') {\n      depth += 1;\n    } else if (line[i] === ')') {\n      depth -= 1;\n    }\n\n    if (depth === 0) {\n      return line.slice(fromIndex, i);\n    }\n  }\n  return '';\n};\n\nconst parseValue = (value: string): any => {\n  try {\n    return value === 'undefined' ? undefined : JSON.parse(value);\n  } catch (e) {\n    return value;\n  }\n};\n\nconst StyledExpected = styled.span(({ theme }) => ({\n  color: theme.base === 'light' ? theme.color.positiveText : theme.color.positive,\n}));\n\nconst StyledReceived = styled.span(({ theme }) => ({\n  color: theme.base === 'light' ? theme.color.negativeText : theme.color.negative,\n}));\n\nexport const Received = ({ value, parsed }: { value: any; parsed?: boolean }) =>\n  parsed ? (\n    <Node showObjectInspector value={value} style={{ color: '#D43900' }} />\n  ) : (\n    <StyledReceived>{value}</StyledReceived>\n  );\n\nexport const Expected = ({ value, parsed }: { value: any; parsed?: boolean }) => {\n  if (parsed) {\n    if (typeof value === 'string' && value.startsWith('called with')) {\n      return <>{value}</>;\n    }\n    return <Node showObjectInspector value={value} style={{ color: '#16B242' }} />;\n  }\n  return <StyledExpected>{value}</StyledExpected>;\n};\n\nexport const MatcherResult = ({\n  message,\n  style = {},\n}: {\n  message: string;\n  style?: React.CSSProperties;\n}) => {\n  const filter = useAnsiToHtmlFilter();\n  const lines = message.split('\\n');\n  return (\n    <pre\n      style={{\n        margin: 0,\n        padding: '8px 10px 8px 36px',\n        fontSize: typography.size.s1,\n        ...style,\n      }}\n    >\n      {lines.flatMap((line: string, index: number) => {\n        if (line.startsWith('expect(')) {\n          const received = getParams(line, 7);\n          const remainderIndex = received ? 7 + received.length : 0;\n          const matcher = received && line.slice(remainderIndex).match(/\\.(to|last|nth)[A-Z]\\w+\\(/);\n          if (matcher) {\n            const expectedIndex = remainderIndex + (matcher.index ?? 0) + matcher[0].length;\n            const expected = getParams(line, expectedIndex);\n            if (expected) {\n              return [\n                'expect(',\n                <Received key={`received_${received}`} value={received} />,\n                line.slice(remainderIndex, expectedIndex),\n                <Expected key={`expected_${expected}`} value={expected} />,\n                line.slice(expectedIndex + expected.length),\n                <br key={`br${index}`} />,\n              ];\n            }\n          }\n        }\n\n        if (line.match(/^\\s*- /)) {\n          return [<Expected key={line + index} value={line} />, <br key={`br${index}`} />];\n        }\n        if (line.match(/^\\s*\\+ /) || line.match(/^Received: $/)) {\n          return [<Received key={line + index} value={line} />, <br key={`br${index}`} />];\n        }\n\n        const [, assertionLabel, assertionValue] = line.match(/^(Expected|Received): (.*)$/) || [];\n        if (assertionLabel && assertionValue) {\n          return assertionLabel === 'Expected'\n            ? [\n                'Expected: ',\n                <Expected key={line + index} value={parseValue(assertionValue)} parsed />,\n                <br key={`br${index}`} />,\n              ]\n            : [\n                'Received: ',\n                <Received key={line + index} value={parseValue(assertionValue)} parsed />,\n                <br key={`br${index}`} />,\n              ];\n        }\n\n        const [, prefix, numberOfCalls] =\n          line.match(/(Expected number|Received number|Number) of calls: (\\d+)$/i) || [];\n        if (prefix && numberOfCalls) {\n          return [\n            `${prefix} of calls: `,\n            <Node key={line + index} value={Number(numberOfCalls)} />,\n            <br key={`br${index}`} />,\n          ];\n        }\n\n        const [, receivedValue] = line.match(/^Received has value: (.+)$/) || [];\n        if (receivedValue) {\n          return [\n            'Received has value: ',\n            <Node key={line + index} value={parseValue(receivedValue)} />,\n            <br key={`br${index}`} />,\n          ];\n        }\n\n        return [\n          <span\n            key={line + index}\n            dangerouslySetInnerHTML={{ __html: filter.toHtml(line) }}\n          ></span>,\n          <br key={`br${index}`} />,\n        ];\n      })}\n    </pre>\n  );\n};\n"
  },
  {
    "path": "code/core/src/component-testing/components/MethodCall.stories.tsx",
    "content": "import React from 'react';\n\nimport { styled, typography } from 'storybook/theming';\n\nimport type { Call } from '../../instrumenter/types.ts';\nimport { MethodCall, Node } from './MethodCall.tsx';\n\nconst StyledWrapper = styled.div(({ theme }) => ({\n  backgroundColor: theme.background.content,\n  padding: '20px',\n  boxShadow: `0 0 0 1px ${theme.appBorderColor}`,\n  color: theme.color.defaultText,\n  fontFamily: typography.fonts.mono,\n  fontSize: typography.size.s1,\n}));\n\nexport default {\n  title: 'MethodCall',\n  component: MethodCall,\n  decorators: [\n    (Story: any) => (\n      <StyledWrapper>\n        <Story />\n      </StyledWrapper>\n    ),\n  ],\n  parameters: {\n    layout: 'fullscreen',\n  },\n};\n\nexport const Args = () => (\n  <div style={{ display: 'inline-flex', flexDirection: 'column', gap: 10 }}>\n    <Node value={null} />\n    <Node value={undefined} />\n    <Node value=\"Hello world\" />\n    <Node value=\"https://github.com/storybookjs/storybook/blob/next/README.md\" />\n    <Node value=\"012345678901234567890123456789012345678901234567890123456789\" />\n    {}\n    <Node value={true} />\n    <Node value={false} />\n    <Node value={12345} />\n    <Node value={['foo', 1, { hello: 'world' }]} />\n    <Node value={[...Array(23)].map((_, i) => i)} />\n    <Node value={{ hello: 'world' }} />\n    <Node value={{ hello: 'world', arr: [1, 2, 3], more: true }} />\n    <Node value={{ hello: 'world', arr: [1, 2, 3], more: true }} showObjectInspector />\n    <Node\n      value={{\n        hello: 'world',\n        arr: [1, 2, 3],\n        more: true,\n        regex: /regex/,\n        class: class DummyClass {},\n        fn: () => 123,\n        asyncFn: async () => 'hello',\n      }}\n      showObjectInspector\n    />\n    <Node value={{ __class__: { name: 'FooBar' } }} />\n    <Node value={{ __function__: { name: 'goFaster' } }} />\n    <Node value={{ __function__: { name: '' } }} />\n    <Node value={{ __element__: { localName: 'hr' } }} />\n    <Node value={{ __element__: { localName: 'foo', prefix: 'x' } }} />\n    <Node value={{ __element__: { localName: 'div', id: 'foo' } }} />\n    <Node value={{ __element__: { localName: 'span', classNames: ['foo', 'bar'] } }} />\n    <Node value={{ __element__: { localName: 'button', innerText: 'Click me' } }} />\n    <Node\n      value={{ __date__: { value: new Date(Date.UTC(2012, 11, 20, 0, 0, 0)).toISOString() } }}\n    />\n    <Node value={{ __date__: { value: new Date(1600000000000).toISOString() } }} />\n    <Node value={{ __date__: { value: new Date(1600000000123) } }} />\n    <Node value={{ __error__: { name: 'EvalError', message: '' } }} />\n    <Node value={{ __error__: { name: 'SyntaxError', message: \"Can't do that\" } }} />\n    <Node\n      value={{\n        __error__: { name: 'TypeError', message: \"Cannot read property 'foo' of undefined\" },\n      }}\n    />\n    <Node\n      value={{\n        __error__: { name: 'ReferenceError', message: 'Invalid left-hand side in assignment' },\n      }}\n    />\n    <Node\n      value={{\n        __error__: {\n          name: 'Error',\n          message:\n            \"XMLHttpRequest cannot load https://example.com. No 'Access-Control-Allow-Origin' header is present on the requested resource.\",\n        },\n      }}\n    />\n    <Node value={{ __regexp__: { flags: 'i', source: 'hello' } }} />\n    <Node value={{ __regexp__: { flags: '', source: 'src(.*)\\\\.js$' } }} />\n    <Node value={{ __symbol__: { description: '' } }} />\n    <Node value={{ __symbol__: { description: 'Hello world' } }} />\n  </div>\n);\n\nconst calls: Call[] = [\n  {\n    cursor: 0,\n    id: '1',\n    ancestors: [],\n    path: ['screen'],\n    method: 'getByText',\n    storyId: 'kind--story',\n    args: ['Click'],\n    interceptable: false,\n    retain: false,\n  },\n  {\n    cursor: 1,\n    id: '2',\n    ancestors: [],\n    path: ['userEvent'],\n    method: 'click',\n    storyId: 'kind--story',\n    args: [{ __callId__: '1' }],\n    interceptable: true,\n    retain: false,\n  },\n  {\n    cursor: 2,\n    id: '3',\n    ancestors: [],\n    path: [],\n    method: 'expect',\n    storyId: 'kind--story',\n    args: [true],\n    interceptable: true,\n    retain: false,\n  },\n  {\n    cursor: 3,\n    id: '4',\n    ancestors: [],\n    path: [{ __callId__: '3' }, 'not'],\n    method: 'toBe',\n    storyId: 'kind--story',\n    args: [false],\n    interceptable: true,\n    retain: false,\n  },\n  {\n    cursor: 4,\n    id: '5',\n    ancestors: [],\n    path: ['jest'],\n    method: 'fn',\n    storyId: 'kind--story',\n    args: [{ __function__: { name: 'actionHandler' } }],\n    interceptable: false,\n    retain: false,\n  },\n  {\n    cursor: 5,\n    id: '6',\n    ancestors: [],\n    path: [],\n    method: 'expect',\n    storyId: 'kind--story',\n    args: [{ __callId__: '5' }],\n    interceptable: false,\n    retain: false,\n  },\n  {\n    cursor: 6,\n    id: '7',\n    ancestors: [],\n    path: ['expect'],\n    method: 'stringMatching',\n    storyId: 'kind--story',\n    args: [{ __regexp__: { flags: 'i', source: 'hello' } }],\n    interceptable: false,\n    retain: false,\n  },\n  {\n    cursor: 7,\n    id: '8',\n    ancestors: [],\n    path: [{ __callId__: '6' }, 'not'],\n    method: 'toHaveBeenCalledWith',\n    storyId: 'kind--story',\n    args: [\n      { __callId__: '7' },\n      [\n        { __error__: { name: 'Error', message: \"Cannot read property 'foo' of undefined\" } },\n        { __symbol__: { description: 'Hello world' } },\n      ],\n    ],\n    interceptable: false,\n    retain: false,\n  },\n  {\n    cursor: 8,\n    id: '9',\n    ancestors: [],\n    path: [],\n    method: 'step',\n    storyId: 'kind--story',\n    args: ['Custom step label', { __function__: { name: '' } }],\n    interceptable: true,\n    retain: false,\n  },\n];\n\nconst callsById = calls.reduce((acc, call) => {\n  acc.set(call.id, call);\n  return acc;\n}, new Map<Call['id'], Call>());\n\nexport const Step = () => <MethodCall call={callsById.get('9')} callsById={callsById} />;\nexport const Simple = () => <MethodCall call={callsById.get('1')} callsById={callsById} />;\nexport const Nested = () => <MethodCall call={callsById.get('2')} callsById={callsById} />;\nexport const Chained = () => <MethodCall call={callsById.get('4')} callsById={callsById} />;\nexport const Complex = () => <MethodCall call={callsById.get('8')} callsById={callsById} />;\n"
  },
  {
    "path": "code/core/src/component-testing/components/MethodCall.tsx",
    "content": "import type { ReactElement } from 'react';\nimport React, { Fragment } from 'react';\n\nimport { logger } from 'storybook/internal/client-logger';\n\nimport { ObjectInspector } from '@devtools-ds/object-inspector';\nimport { useTheme } from 'storybook/theming';\n\nimport type { Call, CallRef, ElementRef } from '../../instrumenter/types.ts';\n\nconst colorsLight = {\n  base: '#444',\n  nullish: '#7D99AA',\n  string: '#16B242',\n  number: '#5D40D0',\n  boolean: '#f41840',\n  objectkey: '#698394',\n  instance: '#A15C20',\n  function: '#EA7509',\n  muted: '#7D99AA',\n  tag: {\n    name: '#6F2CAC',\n    suffix: '#1F99E5',\n  },\n  date: '#459D9C',\n  error: {\n    name: '#D43900',\n    message: '#444',\n  },\n  regex: {\n    source: '#A15C20',\n    flags: '#EA7509',\n  },\n  meta: '#EA7509',\n  method: '#0271B6',\n};\n\nconst colorsDark = {\n  base: '#eee',\n  nullish: '#aaa',\n  string: '#5FE584',\n  number: '#6ba5ff',\n  boolean: '#ff4191',\n  objectkey: '#accfe6',\n  instance: '#E3B551',\n  function: '#E3B551',\n  muted: '#aaa',\n  tag: {\n    name: '#f57bff',\n    suffix: '#8EB5FF',\n  },\n  date: '#70D4D3',\n  error: {\n    name: '#f40',\n    message: '#eee',\n  },\n  regex: {\n    source: '#FAD483',\n    flags: '#E3B551',\n  },\n  meta: '#FAD483',\n  method: '#5EC1FF',\n};\n\nconst useThemeColors = () => {\n  const { base } = useTheme();\n  return base === 'dark' ? colorsDark : colorsLight;\n};\n\nconst special = /[^A-Z0-9]/i;\nconst trimEnd = /[\\s.,…]+$/gm;\nconst ellipsize = (string: string, maxlength: number): string => {\n  if (string.length <= maxlength) {\n    return string;\n  }\n  for (let i = maxlength - 1; i >= 0; i -= 1) {\n    if (special.test(string[i]) && i > 10) {\n      return `${string.slice(0, i).replace(trimEnd, '')}…`;\n    }\n  }\n  return `${string.slice(0, maxlength).replace(trimEnd, '')}…`;\n};\n\nconst stringify = (value: any) => {\n  try {\n    return JSON.stringify(value, null, 1);\n  } catch (e) {\n    return String(value);\n  }\n};\n\nconst interleave = (nodes: ReactElement[], separator: ReactElement) =>\n  nodes.flatMap((node, index) =>\n    index === nodes.length - 1\n      ? [node]\n      : [node, React.cloneElement(separator, { key: `sep${index}` })]\n  );\n\nexport const Node = ({\n  value,\n  nested,\n  showObjectInspector,\n  callsById,\n  ...props\n}: {\n  value: any;\n  nested?: boolean;\n  /** Shows an object inspector instead of just printing the object. Only available for Objects */\n  showObjectInspector?: boolean;\n  callsById?: Map<Call['id'], Call>;\n  [props: string]: any;\n}) => {\n  switch (true) {\n    case value === null:\n      return <NullNode {...props} />;\n    case value === undefined:\n      return <UndefinedNode {...props} />;\n    case Array.isArray(value):\n      return <ArrayNode {...props} value={value} callsById={callsById} />;\n    case typeof value === 'string':\n      return <StringNode {...props} value={value} />;\n    case typeof value === 'number':\n      return <NumberNode {...props} value={value} />;\n    case typeof value === 'boolean':\n      return <BooleanNode {...props} value={value} />;\n\n    case Object.prototype.hasOwnProperty.call(value, '__date__'):\n      return <DateNode {...props} {...value.__date__} />;\n    case Object.prototype.hasOwnProperty.call(value, '__error__'):\n      return <ErrorNode {...props} {...value.__error__} />;\n    case Object.prototype.hasOwnProperty.call(value, '__regexp__'):\n      return <RegExpNode {...props} {...value.__regexp__} />;\n    case Object.prototype.hasOwnProperty.call(value, '__function__'):\n      return <FunctionNode {...props} {...value.__function__} />;\n    case Object.prototype.hasOwnProperty.call(value, '__symbol__'):\n      return <SymbolNode {...props} {...value.__symbol__} />;\n    case Object.prototype.hasOwnProperty.call(value, '__element__'):\n      return <ElementNode {...props} {...value.__element__} />;\n    case Object.prototype.hasOwnProperty.call(value, '__class__'):\n      return <ClassNode {...props} {...value.__class__} />;\n    case Object.prototype.hasOwnProperty.call(value, '__callId__'):\n      return <MethodCall call={callsById?.get(value.__callId__)} callsById={callsById} />;\n\n    case Object.prototype.toString.call(value) === '[object Object]':\n      return (\n        <ObjectNode\n          value={value}\n          showInspector={showObjectInspector}\n          callsById={callsById}\n          {...props}\n        />\n      );\n    default:\n      return <OtherNode value={value} {...props} />;\n  }\n};\n\nexport const NullNode = (props: object) => {\n  const colors = useThemeColors();\n  return (\n    <span style={{ color: colors.nullish }} {...props}>\n      null\n    </span>\n  );\n};\n\nexport const UndefinedNode = (props: object) => {\n  const colors = useThemeColors();\n  return (\n    <span style={{ color: colors.nullish }} {...props}>\n      undefined\n    </span>\n  );\n};\n\nexport const StringNode = ({ value, ...props }: { value: string }) => {\n  const colors = useThemeColors();\n  return (\n    <span style={{ color: colors.string }} {...props}>\n      {JSON.stringify(ellipsize(value, 50))}\n    </span>\n  );\n};\n\nexport const NumberNode = ({ value, ...props }: { value: number }) => {\n  const colors = useThemeColors();\n  return (\n    <span style={{ color: colors.number }} {...props}>\n      {value}\n    </span>\n  );\n};\n\nexport const BooleanNode = ({ value, ...props }: { value: boolean }) => {\n  const colors = useThemeColors();\n  return (\n    <span style={{ color: colors.boolean }} {...props}>\n      {String(value)}\n    </span>\n  );\n};\n\nexport const ArrayNode = ({\n  value,\n  nested = false,\n  callsById,\n}: {\n  value: any[];\n  nested?: boolean;\n  callsById?: Map<Call['id'], Call>;\n}) => {\n  const colors = useThemeColors();\n  if (nested) {\n    return <span style={{ color: colors.base }}>[…]</span>;\n  }\n  const nodes = value\n    .slice(0, 3)\n    .map((v, index) => (\n      <Node key={`${index}--${JSON.stringify(v)}`} value={v} nested callsById={callsById} />\n    ));\n  const nodelist = interleave(nodes, <span>, </span>);\n  if (value.length <= 3) {\n    return <span style={{ color: colors.base }}>[{nodelist}]</span>;\n  }\n  return (\n    <span style={{ color: colors.base }}>\n      ({value.length}) [{nodelist}, …]\n    </span>\n  );\n};\n\nexport const ObjectNode = ({\n  showInspector,\n  value,\n  callsById,\n  nested = false,\n}: {\n  showInspector?: boolean;\n  value: object;\n  nested?: boolean;\n  callsById?: Map<Call['id'], Call>;\n}) => {\n  const isDarkMode = useTheme().base === 'dark';\n  const colors = useThemeColors();\n\n  if (showInspector) {\n    return (\n      <>\n        <ObjectInspector\n          id=\"interactions-object-inspector\"\n          data={value}\n          includePrototypes={false}\n          colorScheme={isDarkMode ? 'dark' : 'light'}\n        />\n      </>\n    );\n  }\n\n  if (nested) {\n    return <span style={{ color: colors.base }}>{'{…}'}</span>;\n  }\n  const nodelist = interleave(\n    Object.entries(value)\n      .slice(0, 2)\n      .map(([k, v]) => (\n        <Fragment key={k}>\n          <span style={{ color: colors.objectkey }}>{k}: </span>\n          <Node value={v} callsById={callsById} nested />\n        </Fragment>\n      )),\n    <span>, </span>\n  );\n  if (Object.keys(value).length <= 2) {\n    return (\n      <span style={{ color: colors.base }}>\n        {'{ '}\n        {nodelist}\n        {' }'}\n      </span>\n    );\n  }\n  return (\n    <span style={{ color: colors.base }}>\n      ({Object.keys(value).length}) {'{ '}\n      {nodelist}\n      {', … }'}\n    </span>\n  );\n};\n\nexport const ClassNode = ({ name }: { name: string }) => {\n  const colors = useThemeColors();\n  return <span style={{ color: colors.instance }}>{name}</span>;\n};\n\nexport const FunctionNode = ({ name }: { name: string }) => {\n  const colors = useThemeColors();\n  return name ? (\n    <span style={{ color: colors.function }}>{name}</span>\n  ) : (\n    <span style={{ color: colors.nullish, fontStyle: 'italic' }}>anonymous</span>\n  );\n};\n\nexport const ElementNode = ({\n  prefix,\n  localName,\n  id,\n  classNames = [],\n  innerText,\n}: ElementRef['__element__']) => {\n  const name = prefix ? `${prefix}:${localName}` : localName;\n  const colors = useThemeColors();\n  return (\n    <span style={{ wordBreak: 'keep-all' }}>\n      <span key={`${name}_lt`} style={{ color: colors.muted }}>\n        &lt;\n      </span>\n      <span key={`${name}_tag`} style={{ color: colors.tag.name }}>\n        {name}\n      </span>\n      <span key={`${name}_suffix`} style={{ color: colors.tag.suffix }}>\n        {id ? `#${id}` : classNames.reduce((acc, className) => `${acc}.${className}`, '')}\n      </span>\n      <span key={`${name}_gt`} style={{ color: colors.muted }}>\n        &gt;\n      </span>\n      {!id && classNames.length === 0 && innerText && (\n        <>\n          <span key={`${name}_text`}>{innerText}</span>\n          <span key={`${name}_close_lt`} style={{ color: colors.muted }}>\n            &lt;\n          </span>\n          <span key={`${name}_close_tag`} style={{ color: colors.tag.name }}>\n            /{name}\n          </span>\n          <span key={`${name}_close_gt`} style={{ color: colors.muted }}>\n            &gt;\n          </span>\n        </>\n      )}\n    </span>\n  );\n};\n\nexport const DateNode = ({ value }: { value: string | Date }) => {\n  let parsed: Date | null = new Date(value);\n  if (isNaN(Number(parsed))) {\n    logger.warn('Invalid date value:', value);\n    parsed = null;\n  }\n\n  const colors = useThemeColors();\n  if (!parsed) {\n    return <span style={{ whiteSpace: 'nowrap', color: colors.date }}>Invalid date</span>;\n  }\n\n  const [date, time, ms] = parsed.toISOString().split(/[T.Z]/);\n  return (\n    <span style={{ whiteSpace: 'nowrap', color: colors.date }}>\n      {date}\n      <span style={{ opacity: 0.7 }}>T</span>\n      {time === '00:00:00' ? <span style={{ opacity: 0.7 }}>{time}</span> : time}\n      {ms === '000' ? <span style={{ opacity: 0.7 }}>.{ms}</span> : `.${ms}`}\n      <span style={{ opacity: 0.7 }}>Z</span>\n    </span>\n  );\n};\n\nexport const ErrorNode = ({ name, message }: { name: string; message: string }) => {\n  const colors = useThemeColors();\n  return (\n    <span style={{ color: colors.error.name }}>\n      {name}\n      {message && ': '}\n      {message && (\n        <span style={{ color: colors.error.message }} title={message.length > 50 ? message : ''}>\n          {ellipsize(message, 50)}\n        </span>\n      )}\n    </span>\n  );\n};\n\nexport const RegExpNode = ({ flags, source }: { flags: string; source: string }) => {\n  const colors = useThemeColors();\n  return (\n    <span style={{ whiteSpace: 'nowrap', color: colors.regex.flags }}>\n      /<span style={{ color: colors.regex.source }}>{source}</span>/{flags}\n    </span>\n  );\n};\n\nexport const SymbolNode = ({ description }: { description: string }) => {\n  const colors = useThemeColors();\n  return (\n    <span style={{ whiteSpace: 'nowrap', color: colors.instance }}>\n      Symbol(\n      {description && <span style={{ color: colors.meta }}>\"{description}\"</span>})\n    </span>\n  );\n};\n\nexport const OtherNode = ({ value }: { value: any }) => {\n  const colors = useThemeColors();\n  return <span style={{ color: colors.meta }}>{stringify(value)}</span>;\n};\n\nexport const StepNode = ({ label }: { label: string }) => {\n  const colors = useThemeColors();\n  const { typography } = useTheme();\n  return (\n    <span\n      style={{\n        color: colors.base,\n        fontFamily: typography.fonts.base,\n        fontSize: typography.size.s2 - 1,\n      }}\n    >\n      {label}\n    </span>\n  );\n};\n\nexport const MethodCall = ({\n  call,\n  callsById,\n}: {\n  call?: Call;\n  callsById?: Map<Call['id'], Call>;\n}) => {\n  // Call might be undefined during initial render, can be safely ignored.\n  if (!call) {\n    return null;\n  }\n\n  if (call.method === 'step' && call.path?.length === 0) {\n    return <StepNode label={call.args[0]} />;\n  }\n\n  const path = call.path?.flatMap((elem, index) => {\n    const callId = (elem as CallRef).__callId__;\n    return [\n      callId ? (\n        <MethodCall key={`elem${index}`} call={callsById?.get(callId)} callsById={callsById} />\n      ) : (\n        <span key={`elem${index}`}>{elem as any}</span>\n      ),\n      <wbr key={`wbr${index}`} />,\n      <span key={`dot${index}`}>.</span>,\n    ];\n  });\n\n  const args = call.args?.flatMap((arg, index, array) => {\n    const node = <Node key={`node${index}`} value={arg} callsById={callsById} />;\n    return index < array.length - 1\n      ? [node, <span key={`comma${index}`}>,&nbsp;</span>, <wbr key={`wbr${index}`} />]\n      : [node];\n  });\n\n  const colors = useThemeColors();\n  return (\n    <>\n      <span style={{ color: colors.base }}>{path}</span>\n      <span style={{ color: colors.method }}>{call.method}</span>\n      <span style={{ color: colors.base }}>\n        (<wbr />\n        {args}\n        <wbr />)\n      </span>\n    </>\n  );\n};\n"
  },
  {
    "path": "code/core/src/component-testing/components/Panel.test.ts",
    "content": "// @vitest-environment happy-dom\nimport { describe, expect, it } from 'vitest';\n\nimport { type Call, CallStates, type LogItem } from '../../instrumenter/types.ts';\nimport { INTERNAL_RENDER_CALL_ID } from '../constants.ts';\nimport { type PanelState, getInteractions, getPanelState } from './Panel.tsx';\n\ndescribe('Panel', () => {\n  const log: LogItem[] = [\n    {\n      callId: INTERNAL_RENDER_CALL_ID,\n      status: CallStates.DONE,\n      ancestors: [],\n    },\n    {\n      callId: 'story--id [4] findByText',\n      status: CallStates.DONE,\n      ancestors: [],\n    },\n    {\n      callId: 'story--id [5] click',\n      status: CallStates.DONE,\n      ancestors: [],\n    },\n    {\n      callId: 'story--id [6] waitFor',\n      status: CallStates.DONE,\n      ancestors: [],\n    },\n    {\n      callId: 'story--id [6] waitFor [2] toHaveBeenCalledWith',\n      status: CallStates.DONE,\n      ancestors: ['story--id [6] waitFor'],\n    },\n  ];\n  const calls = new Map<Call['id'], Call>(\n    [\n      {\n        id: INTERNAL_RENDER_CALL_ID,\n        storyId: 'story--id',\n        ancestors: [],\n        cursor: 0,\n        path: [],\n        method: 'render',\n        args: [],\n        interceptable: true,\n        retain: false,\n      },\n      {\n        id: 'story--id [0] action',\n        storyId: 'story--id',\n        ancestors: [],\n        cursor: 0,\n        path: [],\n        method: 'action',\n        args: [{ __function__: { name: 'onSubmit' } }],\n        interceptable: false,\n        retain: true,\n      },\n      {\n        id: 'story--id [1] action',\n        storyId: 'story--id',\n        ancestors: [],\n        cursor: 1,\n        path: [],\n        method: 'action',\n        args: [{ __function__: { name: 'onTransactionStart' } }],\n        interceptable: false,\n        retain: true,\n      },\n      {\n        id: 'story--id [2] action',\n        storyId: 'story--id',\n        ancestors: [],\n        cursor: 2,\n        path: [],\n        method: 'action',\n        args: [{ __function__: { name: 'onTransactionEnd' } }],\n        interceptable: false,\n        retain: true,\n      },\n      {\n        id: 'story--id [3] within',\n        storyId: 'story--id',\n        ancestors: [],\n        cursor: 3,\n        path: [],\n        method: 'within',\n        args: [{ __element__: { localName: 'div', id: 'root', innerText: 'Click' } }],\n        interceptable: false,\n        retain: false,\n      },\n      {\n        id: 'story--id [4] findByText',\n        storyId: 'story--id',\n        ancestors: [],\n        cursor: 4,\n        path: [{ __callId__: 'story--id [3] within' }],\n        method: 'findByText',\n        args: ['Click'],\n        interceptable: true,\n        retain: false,\n      },\n      {\n        id: 'story--id [5] click',\n        storyId: 'story--id',\n        ancestors: [],\n        cursor: 5,\n        path: ['userEvent'],\n        method: 'click',\n        args: [{ __element__: { localName: 'button', innerText: 'Click' } }],\n        interceptable: true,\n        retain: false,\n      },\n      {\n        id: 'story--id [6] waitFor [0] expect',\n        storyId: 'story--id',\n        ancestors: ['story--id [6] waitFor'],\n        cursor: 0,\n        path: [],\n        method: 'expect',\n        args: [{ __callId__: 'story--id [0] action', retain: true }],\n        interceptable: true,\n        retain: false,\n      },\n      {\n        id: 'story--id [6] waitFor [1] stringMatching',\n        storyId: 'story--id',\n        ancestors: ['story--id [6] waitFor'],\n        cursor: 1,\n        path: ['expect'],\n        method: 'stringMatching',\n        args: [{ __regexp__: { flags: 'gi', source: '([A-Z])\\\\w+' } }],\n        interceptable: false,\n        retain: false,\n      },\n      {\n        id: 'story--id [6] waitFor [2] toHaveBeenCalledWith',\n        storyId: 'story--id',\n        ancestors: ['story--id [6] waitFor'],\n        cursor: 2,\n        path: [{ __callId__: 'story--id [6] waitFor [0] expect' }],\n        method: 'toHaveBeenCalledWith',\n        args: [{ __callId__: 'story--id [6] waitFor [1] stringMatching', retain: false }],\n        interceptable: true,\n        retain: false,\n      },\n      {\n        id: 'story--id [6] waitFor',\n        storyId: 'story--id',\n        ancestors: [],\n        cursor: 6,\n        path: [],\n        method: 'waitFor',\n        args: [{ __function__: { name: '' } }],\n        interceptable: true,\n        retain: false,\n      },\n    ].map((v) => [v.id, v])\n  );\n  const collapsed = new Set<Call['id']>();\n  const setCollapsed = () => {};\n\n  const baseState: PanelState = {\n    status: 'completed',\n    controlStates: {\n      detached: false,\n      start: true,\n      back: true,\n      goto: true,\n      next: true,\n      end: true,\n    },\n    interactions: [],\n    interactionsCount: 0,\n    hasException: false,\n  };\n\n  describe('getInteractions', () => {\n    it('returns list of interactions', () => {\n      expect(getInteractions({ log, calls, collapsed, setCollapsed })).toEqual([\n        {\n          ...calls.get(INTERNAL_RENDER_CALL_ID),\n          status: CallStates.DONE,\n          childCallIds: undefined,\n          isHidden: false,\n          isCollapsed: false,\n          toggleCollapsed: expect.any(Function),\n        },\n        {\n          ...calls.get('story--id [4] findByText'),\n          status: CallStates.DONE,\n          childCallIds: undefined,\n          isHidden: false,\n          isCollapsed: false,\n          toggleCollapsed: expect.any(Function),\n        },\n        {\n          ...calls.get('story--id [5] click'),\n          status: CallStates.DONE,\n          childCallIds: undefined,\n          isHidden: false,\n          isCollapsed: false,\n          toggleCollapsed: expect.any(Function),\n        },\n        {\n          ...calls.get('story--id [6] waitFor'),\n          status: CallStates.DONE,\n          childCallIds: ['story--id [6] waitFor [2] toHaveBeenCalledWith'],\n          isHidden: false,\n          isCollapsed: false,\n          toggleCollapsed: expect.any(Function),\n        },\n        {\n          ...calls.get('story--id [6] waitFor [2] toHaveBeenCalledWith'),\n          status: CallStates.DONE,\n          childCallIds: undefined,\n          isHidden: false,\n          isCollapsed: false,\n          toggleCollapsed: expect.any(Function),\n        },\n      ]);\n    });\n\n    it('hides calls for which the parent is collapsed', () => {\n      const withCollapsed = new Set<Call['id']>(['story--id [6] waitFor']);\n\n      expect(getInteractions({ log, calls, collapsed: withCollapsed, setCollapsed })).toEqual([\n        expect.objectContaining({\n          ...calls.get(INTERNAL_RENDER_CALL_ID),\n          childCallIds: undefined,\n          isCollapsed: false,\n          isHidden: false,\n        }),\n        expect.objectContaining({\n          ...calls.get('story--id [4] findByText'),\n          childCallIds: undefined,\n          isCollapsed: false,\n          isHidden: false,\n        }),\n        expect.objectContaining({\n          ...calls.get('story--id [5] click'),\n          childCallIds: undefined,\n          isCollapsed: false,\n          isHidden: false,\n        }),\n        expect.objectContaining({\n          ...calls.get('story--id [6] waitFor'),\n          childCallIds: ['story--id [6] waitFor [2] toHaveBeenCalledWith'],\n          isCollapsed: true,\n          isHidden: false,\n        }),\n        expect.objectContaining({\n          ...calls.get('story--id [6] waitFor [2] toHaveBeenCalledWith'),\n          childCallIds: undefined,\n          isCollapsed: false,\n          isHidden: true,\n        }),\n      ]);\n    });\n\n    it('does not hide waitFor after a collapsed step', () => {\n      const stepLog: LogItem[] = [\n        { callId: 'story--id [0] step', status: CallStates.DONE, ancestors: [] },\n        {\n          callId: 'story--id [0] step [0] click',\n          status: CallStates.DONE,\n          ancestors: ['story--id [0] step'],\n        },\n        { callId: 'story--id [1] waitFor', status: CallStates.DONE, ancestors: [] },\n        {\n          callId: 'story--id [1] waitFor [0] toHaveBeenCalledWith',\n          status: CallStates.DONE,\n          ancestors: ['story--id [1] waitFor'],\n        },\n      ];\n      const stepCalls = new Map<Call['id'], Call>(\n        [\n          {\n            id: 'story--id [0] step',\n            storyId: 'story--id',\n            ancestors: [],\n            cursor: 0,\n            path: [],\n            method: 'step',\n            args: ['Fill and submit form'],\n            interceptable: true,\n            retain: false,\n          },\n          {\n            id: 'story--id [0] step [0] click',\n            storyId: 'story--id',\n            ancestors: ['story--id [0] step'],\n            cursor: 0,\n            path: ['userEvent'],\n            method: 'click',\n            args: [],\n            interceptable: true,\n            retain: false,\n          },\n          {\n            id: 'story--id [1] waitFor',\n            storyId: 'story--id',\n            ancestors: [],\n            cursor: 1,\n            path: [],\n            method: 'waitFor',\n            args: [],\n            interceptable: true,\n            retain: false,\n          },\n          {\n            id: 'story--id [1] waitFor [0] toHaveBeenCalledWith',\n            storyId: 'story--id',\n            ancestors: ['story--id [1] waitFor'],\n            cursor: 0,\n            path: [],\n            method: 'toHaveBeenCalledWith',\n            args: [],\n            interceptable: true,\n            retain: false,\n          },\n        ].map((v) => [v.id, v])\n      );\n\n      const stepCollapsed = new Set<Call['id']>(['story--id [0] step']);\n\n      const result = getInteractions({\n        log: stepLog,\n        calls: stepCalls,\n        collapsed: stepCollapsed,\n        setCollapsed,\n      });\n\n      // Step's child should be hidden\n      expect(result).toEqual([\n        expect.objectContaining({ id: 'story--id [0] step', isHidden: false, isCollapsed: true }),\n        expect.objectContaining({\n          id: 'story--id [0] step [0] click',\n          isHidden: true,\n          isCollapsed: false,\n        }),\n        // waitFor and its children should NOT be hidden by the collapsed step\n        expect.objectContaining({\n          id: 'story--id [1] waitFor',\n          isHidden: false,\n          isCollapsed: false,\n        }),\n        expect.objectContaining({\n          id: 'story--id [1] waitFor [0] toHaveBeenCalledWith',\n          isHidden: false,\n          isCollapsed: false,\n        }),\n      ]);\n    });\n\n    it('uses status from log', () => {\n      const withError = log.slice(0, 4).concat({ ...log[4], status: CallStates.ERROR });\n\n      expect(getInteractions({ log: withError, calls, collapsed, setCollapsed })).toEqual([\n        expect.objectContaining({\n          id: INTERNAL_RENDER_CALL_ID,\n          status: CallStates.DONE,\n        }),\n        expect.objectContaining({\n          id: 'story--id [4] findByText',\n          status: CallStates.DONE,\n        }),\n        expect.objectContaining({\n          id: 'story--id [5] click',\n          status: CallStates.DONE,\n        }),\n        expect.objectContaining({\n          id: 'story--id [6] waitFor',\n          status: CallStates.DONE,\n        }),\n        expect.objectContaining({\n          id: 'story--id [6] waitFor [2] toHaveBeenCalledWith',\n          status: CallStates.ERROR,\n        }),\n      ]);\n    });\n\n    it('keeps status active for errored child calls while parent is active', () => {\n      const withActiveError = log.slice(0, 3).concat([\n        { ...log[3], status: CallStates.ACTIVE },\n        { ...log[4], status: CallStates.ERROR },\n      ]);\n\n      expect(getInteractions({ log: withActiveError, calls, collapsed, setCollapsed })).toEqual([\n        expect.objectContaining({\n          id: INTERNAL_RENDER_CALL_ID,\n          status: CallStates.DONE,\n        }),\n        expect.objectContaining({\n          id: 'story--id [4] findByText',\n          status: CallStates.DONE,\n        }),\n        expect.objectContaining({\n          id: 'story--id [5] click',\n          status: CallStates.DONE,\n        }),\n        expect.objectContaining({\n          id: 'story--id [6] waitFor',\n          status: CallStates.ACTIVE,\n        }),\n        expect.objectContaining({\n          id: 'story--id [6] waitFor [2] toHaveBeenCalledWith',\n          status: CallStates.ACTIVE, // not ERROR\n        }),\n      ]);\n    });\n\n    it('does not override child status other than error for active parent', () => {\n      const withActiveWaiting = log.slice(0, 3).concat([\n        { ...log[3], status: CallStates.ACTIVE },\n        { ...log[4], status: CallStates.WAITING },\n      ]);\n\n      expect(getInteractions({ log: withActiveWaiting, calls, collapsed, setCollapsed })).toEqual([\n        expect.objectContaining({\n          id: INTERNAL_RENDER_CALL_ID,\n          status: CallStates.DONE,\n        }),\n        expect.objectContaining({\n          id: 'story--id [4] findByText',\n          status: CallStates.DONE,\n        }),\n        expect.objectContaining({\n          id: 'story--id [5] click',\n          status: CallStates.DONE,\n        }),\n        expect.objectContaining({\n          id: 'story--id [6] waitFor',\n          status: CallStates.ACTIVE,\n        }),\n        expect.objectContaining({\n          id: 'story--id [6] waitFor [2] toHaveBeenCalledWith',\n          status: CallStates.WAITING,\n        }),\n      ]);\n    });\n  });\n\n  describe('getPanelState', () => {\n    it('always includes internal render call interactions', () => {\n      const renderingState = { ...baseState, status: 'rendering' as const };\n      const completedState = { ...baseState, status: 'completed' as const };\n\n      const renderingResult = getPanelState(renderingState, {\n        log,\n        calls,\n        collapsed,\n        setCollapsed,\n      });\n      const completedResult = getPanelState(completedState, {\n        log,\n        calls,\n        collapsed,\n        setCollapsed,\n      });\n\n      expect(renderingResult.interactions.some((i) => i.id === INTERNAL_RENDER_CALL_ID)).toBe(true);\n      expect(completedResult.interactions.some((i) => i.id === INTERNAL_RENDER_CALL_ID)).toBe(true);\n    });\n\n    it('excludes user interactions during rendering phase', () => {\n      const renderingState = { ...baseState, status: 'rendering' as const };\n\n      const result = getPanelState(renderingState, { log, calls, collapsed, setCollapsed });\n\n      expect(result.interactions).toHaveLength(1);\n      expect(result.interactions[0].id).toBe(INTERNAL_RENDER_CALL_ID);\n    });\n\n    it('includes user interactions after rendering phase', () => {\n      const completedState = { ...baseState, status: 'completed' as const };\n\n      const result = getPanelState(completedState, { log, calls, collapsed, setCollapsed });\n\n      expect(result.interactions).toHaveLength(5);\n      expect(result.interactions[0].id).toBe(INTERNAL_RENDER_CALL_ID);\n      expect(result.interactions.slice(1).map((i) => i.id)).toEqual([\n        'story--id [4] findByText',\n        'story--id [5] click',\n        'story--id [6] waitFor',\n        'story--id [6] waitFor [2] toHaveBeenCalledWith',\n      ]);\n    });\n\n    it('counts user interactions other than step methods', () => {\n      const logWithSteps: LogItem[] = [\n        {\n          callId: INTERNAL_RENDER_CALL_ID,\n          status: CallStates.DONE,\n          ancestors: [],\n        },\n        {\n          callId: 'story--id [1] click',\n          status: CallStates.DONE,\n          ancestors: [],\n        },\n        {\n          callId: 'story--id [2] step',\n          status: CallStates.DONE,\n          ancestors: [],\n        },\n        {\n          callId: 'story--id [3] type',\n          status: CallStates.DONE,\n          ancestors: [],\n        },\n      ];\n\n      const callsWithSteps = new Map<Call['id'], Call>([\n        [INTERNAL_RENDER_CALL_ID, calls.get(INTERNAL_RENDER_CALL_ID)!],\n        [\n          'story--id [1] click',\n          {\n            id: 'story--id [1] click',\n            storyId: 'story--id',\n            ancestors: [],\n            cursor: 1,\n            path: ['userEvent'],\n            method: 'click',\n            args: [],\n            interceptable: true,\n            retain: false,\n          },\n        ],\n        [\n          'story--id [2] step',\n          {\n            id: 'story--id [2] step',\n            storyId: 'story--id',\n            ancestors: [],\n            cursor: 2,\n            path: [],\n            method: 'step',\n            args: [],\n            interceptable: false,\n            retain: false,\n          },\n        ],\n        [\n          'story--id [3] type',\n          {\n            id: 'story--id [3] type',\n            storyId: 'story--id',\n            ancestors: [],\n            cursor: 3,\n            path: ['userEvent'],\n            method: 'type',\n            args: [],\n            interceptable: true,\n            retain: false,\n          },\n        ],\n      ]);\n\n      const completedState = { ...baseState, status: 'completed' as const };\n\n      const result = getPanelState(completedState, {\n        log: logWithSteps,\n        calls: callsWithSteps,\n        collapsed,\n        setCollapsed,\n      });\n\n      expect(result.interactionsCount).toBe(2); // click and type (not render call or step method)\n    });\n\n    it('preserves input control states when processing user interactions', () => {\n      const customControlStates = {\n        detached: true,\n        start: false,\n        back: true,\n        goto: false,\n        next: true,\n        end: false,\n      };\n\n      const stateWithCustomControls = {\n        ...baseState,\n        status: 'completed' as const,\n        controlStates: customControlStates,\n      };\n\n      const result = getPanelState(stateWithCustomControls, {\n        log,\n        calls,\n        collapsed,\n        setCollapsed,\n      });\n\n      expect(result.controlStates).toEqual(customControlStates);\n    });\n\n    it('preserves input state properties in output', () => {\n      const stateWithAllProps: PanelState = {\n        ...baseState,\n        status: 'completed' as const,\n        hasException: true,\n        pausedAt: 'some-call-id',\n        caughtException: new Error('test error'),\n        unhandledErrors: [{ name: 'Error', message: 'test error', stack: 'stack trace' }],\n      };\n\n      const result = getPanelState(stateWithAllProps, { log, calls, collapsed, setCollapsed });\n\n      expect(result.status).toBe('completed');\n      expect(result.hasException).toBe(true);\n      expect(result.pausedAt).toBe('some-call-id');\n      expect(result.caughtException).toEqual(new Error('test error'));\n      expect(result.unhandledErrors).toEqual([\n        { name: 'Error', message: 'test error', stack: 'stack trace' },\n      ]);\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/component-testing/components/Panel.tsx",
    "content": "import type { Dispatch, SetStateAction } from 'react';\nimport React, { Fragment, memo, useEffect, useMemo, useRef, useState } from 'react';\n\nimport {\n  FORCE_REMOUNT,\n  PLAY_FUNCTION_THREW_EXCEPTION,\n  STORY_RENDER_PHASE_CHANGED,\n  STORY_THREW_EXCEPTION,\n  UNHANDLED_ERRORS_WHILE_PLAYING,\n} from 'storybook/internal/core-events';\nimport type { StatusValue } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport {\n  experimental_useStatusStore,\n  useAddonState,\n  useChannel,\n  useParameter,\n  useStorybookApi,\n  useStorybookState,\n} from 'storybook/manager-api';\n\nimport {\n  STATUS_TYPE_ID_COMPONENT_TEST,\n  STORYBOOK_ADDON_TEST_CHANNEL,\n} from '../../../../addons/vitest/src/constants.ts';\nimport { EVENTS } from '../../instrumenter/EVENTS.ts';\nimport {\n  type Call,\n  CallStates,\n  type ControlStates,\n  type LogItem,\n  type RenderPhase,\n} from '../../instrumenter/types.ts';\nimport { ADDON_ID, INTERNAL_RENDER_CALL_ID } from '../constants.ts';\nimport { InteractionsPanel, type SerializedError } from './InteractionsPanel.tsx';\nimport type { PlayStatus } from './StatusBadge.tsx';\n\nexport interface PanelState {\n  status: PlayStatus;\n  controlStates: ControlStates;\n  interactions: ReturnType<typeof getInteractions>;\n  interactionsCount: number;\n  hasException: boolean;\n  pausedAt?: Call['id'];\n  caughtException?: Error;\n  unhandledErrors?: SerializedError[];\n}\n\nconst INITIAL_CONTROL_STATES = {\n  detached: false,\n  start: false,\n  back: false,\n  goto: false,\n  next: false,\n  end: false,\n};\n\nconst playStatusMap: Record<\n  Extract<RenderPhase, 'rendering' | 'playing' | 'completed' | 'errored' | 'aborted'>,\n  PlayStatus\n> = {\n  rendering: 'rendering',\n  playing: 'playing',\n  completed: 'completed',\n  errored: 'errored',\n  aborted: 'aborted',\n};\n\nconst terminalStatuses: PlayStatus[] = ['completed', 'errored', 'aborted'];\n\nconst storyStatusMap: Record<CallStates, StatusValue> = {\n  [CallStates.DONE]: 'status-value:success',\n  [CallStates.ERROR]: 'status-value:error',\n  [CallStates.ACTIVE]: 'status-value:pending',\n  [CallStates.WAITING]: 'status-value:pending',\n};\n\nexport const getInteractions = ({\n  log,\n  calls,\n  collapsed,\n  setCollapsed,\n}: {\n  log: LogItem[];\n  calls: Map<Call['id'], Call>;\n  collapsed: Set<Call['id']>;\n  setCollapsed: Dispatch<SetStateAction<Set<string>>>;\n}) => {\n  const callsById = new Map<Call['id'], Call>();\n  const childCallMap = new Map<Call['id'], Call['id'][]>();\n\n  const interactions = log\n    .map(({ callId, ancestors, status }) => {\n      let isHidden = false;\n      ancestors.forEach((ancestor) => {\n        if (collapsed.has(ancestor)) {\n          isHidden = true;\n        }\n        childCallMap.set(ancestor, (childCallMap.get(ancestor) || []).concat(callId));\n      });\n      return { ...calls.get(callId)!, status, isHidden };\n    })\n    .map((call) => {\n      const status =\n        call.status === CallStates.ERROR &&\n        call.ancestors &&\n        callsById.get(call.ancestors.slice(-1)[0])?.status === CallStates.ACTIVE\n          ? CallStates.ACTIVE\n          : call.status;\n      callsById.set(call.id, { ...call, status });\n      return {\n        ...call,\n        status,\n        childCallIds: childCallMap.get(call.id),\n        isCollapsed: collapsed.has(call.id),\n        toggleCollapsed: () =>\n          setCollapsed((ids) => {\n            if (ids.has(call.id)) {\n              ids.delete(call.id);\n            } else {\n              ids.add(call.id);\n            }\n            return new Set(ids);\n          }),\n      };\n    });\n\n  return interactions;\n};\n\nexport const getPanelState = (\n  state: PanelState,\n  {\n    log,\n    calls,\n    collapsed,\n    setCollapsed,\n  }: {\n    log: LogItem[];\n    calls: Map<Call['id'], Call>;\n    collapsed: Set<Call['id']>;\n    setCollapsed: Dispatch<SetStateAction<Set<string>>>;\n  }\n): PanelState =>\n  getInteractions({ log, calls, collapsed, setCollapsed }).reduce(\n    (acc, interaction) => {\n      if (interaction.id === INTERNAL_RENDER_CALL_ID) {\n        acc.interactions.push(interaction);\n      } else if (state.status !== 'rendering') {\n        acc.controlStates = state.controlStates;\n        acc.interactions.push(interaction);\n        if (interaction.method !== 'step') {\n          acc.interactionsCount++;\n        }\n      }\n      return acc;\n    },\n    {\n      ...state,\n      controlStates: INITIAL_CONTROL_STATES,\n      interactions: [] as ReturnType<typeof getInteractions>,\n      interactionsCount: 0,\n    }\n  );\n\nconst getInternalRenderCall = (storyId: string, exception?: Call['exception']): Call => ({\n  id: INTERNAL_RENDER_CALL_ID,\n  method: 'render',\n  args: [],\n  cursor: 0,\n  storyId,\n  ancestors: [],\n  path: [],\n  interceptable: true,\n  retain: false,\n  exception,\n});\n\nconst getInternalRenderLogItem = (status: CallStates): LogItem => ({\n  callId: INTERNAL_RENDER_CALL_ID,\n  status,\n  ancestors: [],\n});\n\nexport const Panel = memo<{ refId?: string; storyId: string; storyUrl: string }>(\n  function PanelMemoized({ refId, storyId, storyUrl }) {\n    const { statusValue, testRunId } = experimental_useStatusStore((state) => {\n      const storyStatus = refId ? undefined : state[storyId]?.[STATUS_TYPE_ID_COMPONENT_TEST];\n      return {\n        statusValue: storyStatus?.value,\n        testRunId: storyStatus?.data?.testRunId,\n      };\n    });\n\n    // shared state\n    const state = useStorybookState();\n    const api = useStorybookApi();\n    const data = api.getData(state.storyId, state.refId);\n    const importPath = data?.importPath as string | undefined;\n    const canOpenInEditor = global.CONFIG_TYPE === 'DEVELOPMENT' && !state.refId;\n\n    const [panelState, set] = useAddonState<PanelState>(ADDON_ID, {\n      status: 'rendering' as PlayStatus,\n      controlStates: INITIAL_CONTROL_STATES,\n      interactions: [] as ReturnType<typeof getInteractions>,\n      interactionsCount: 0,\n      hasException: false,\n      pausedAt: undefined,\n      caughtException: undefined,\n      unhandledErrors: undefined,\n    });\n\n    // local state\n    const [scrollTarget, setScrollTarget] = useState<HTMLElement | undefined>(undefined);\n    const [collapsed, setCollapsed] = useState<Set<Call['id']>>(new Set());\n    const [hasResultMismatch, setResultMismatch] = useState(false);\n\n    const {\n      status = 'rendering',\n      controlStates = INITIAL_CONTROL_STATES,\n      interactions = [],\n      pausedAt = undefined,\n      caughtException = undefined,\n      unhandledErrors = undefined,\n    } = panelState;\n\n    // Log and calls are tracked in a ref so we don't needlessly rerender.\n    const log = useRef<LogItem[]>([getInternalRenderLogItem(CallStates.ACTIVE)]);\n    const calls = useRef<Map<Call['id'], Omit<Call, 'status'>>>(\n      new Map([[INTERNAL_RENDER_CALL_ID, getInternalRenderCall(storyId)]])\n    );\n    const setCall = ({ status, ...call }: Call) => calls.current.set(call.id, call);\n\n    const endRef = useRef<HTMLDivElement>();\n    useEffect(() => {\n      let observer: IntersectionObserver;\n      if (global.IntersectionObserver) {\n        observer = new global.IntersectionObserver(\n          ([end]: any) => setScrollTarget(end.isIntersecting ? undefined : end.target),\n          { root: global.document.querySelector('#storybook-panel-root [role=\"tabpanel\"]') }\n        );\n\n        if (endRef.current) {\n          observer.observe(endRef.current);\n        }\n      }\n      return () => observer?.disconnect();\n    }, []);\n\n    const lastStoryId = useRef<string>(undefined);\n    const latestRenderId = useRef<number>(0);\n    const emit = useChannel(\n      {\n        [EVENTS.CALL]: setCall,\n        [EVENTS.SYNC]: (payload) => {\n          log.current = [getInternalRenderLogItem(CallStates.DONE), ...payload.logItems];\n          set((state) =>\n            getPanelState(\n              { ...state, controlStates: payload.controlStates, pausedAt: payload.pausedAt },\n              { log: log.current, calls: calls.current, collapsed, setCollapsed }\n            )\n          );\n        },\n        [STORY_RENDER_PHASE_CHANGED]: (event) => {\n          if (\n            lastStoryId.current === event.storyId &&\n            ['preparing', 'loading'].includes(event.newPhase)\n          ) {\n            // A rerender cycle may not actually make it to the rendering phase.\n            // We don't want to update any state until it does.\n            return;\n          }\n\n          // Update lastRenderId and lastStoryId. When we switch stories, lastRenderId's\n          // value might decrease if our users have mocked Date.now() via addons or\n          // manually in their code, so we must reset it.\n          if (lastStoryId.current === event.storyId) {\n            latestRenderId.current = Math.max(latestRenderId.current, event.renderId || 0);\n          } else {\n            latestRenderId.current = event.renderId || 0;\n            lastStoryId.current = event.storyId;\n          }\n\n          // Bail out if concurrent renders are ongoing for the same story (only keep the latest one).\n          if (latestRenderId.current !== event.renderId) {\n            return;\n          }\n\n          if (event.newPhase === 'rendering') {\n            log.current = [getInternalRenderLogItem(CallStates.ACTIVE)];\n            calls.current.set(INTERNAL_RENDER_CALL_ID, getInternalRenderCall(storyId));\n            set({\n              status: 'rendering',\n              controlStates: INITIAL_CONTROL_STATES,\n              pausedAt: undefined,\n              interactions: [],\n              interactionsCount: 0,\n              hasException: false,\n              caughtException: undefined,\n              unhandledErrors: undefined,\n            });\n          } else {\n            set((state) => {\n              const status =\n                event.newPhase in playStatusMap && !terminalStatuses.includes(state.status)\n                  ? playStatusMap[event.newPhase as keyof typeof playStatusMap]\n                  : state.status;\n              return getPanelState(\n                { ...state, status, pausedAt: undefined },\n                { log: log.current, calls: calls.current, collapsed, setCollapsed }\n              );\n            });\n          }\n        },\n        [STORY_THREW_EXCEPTION]: (e: { name: string; message: string; stack: string }) => {\n          log.current = [getInternalRenderLogItem(CallStates.ERROR)];\n          calls.current.set(\n            INTERNAL_RENDER_CALL_ID,\n            getInternalRenderCall(storyId, { ...e, callId: INTERNAL_RENDER_CALL_ID })\n          );\n          set((state) =>\n            getPanelState(\n              {\n                ...state,\n                hasException: true,\n                caughtException: undefined,\n                controlStates: INITIAL_CONTROL_STATES,\n                pausedAt: undefined,\n              },\n              { log: log.current, calls: calls.current, collapsed, setCollapsed }\n            )\n          );\n        },\n        [PLAY_FUNCTION_THREW_EXCEPTION]: (caughtException) => {\n          set((state) => ({ ...state, caughtException, hasException: true }));\n        },\n        [UNHANDLED_ERRORS_WHILE_PLAYING]: (unhandledErrors) => {\n          set((state) => ({ ...state, unhandledErrors, hasException: true }));\n        },\n      },\n      [collapsed]\n    );\n\n    useEffect(() => {\n      set((state) =>\n        getPanelState(state, { log: log.current, calls: calls.current, collapsed, setCollapsed })\n      );\n    }, [set, collapsed]);\n\n    const controls = useMemo(\n      () => ({\n        start: () => emit(EVENTS.START, { storyId }),\n        back: () => emit(EVENTS.BACK, { storyId }),\n        goto: (callId: string) => emit(EVENTS.GOTO, { storyId, callId }),\n        next: () => emit(EVENTS.NEXT, { storyId }),\n        end: () => emit(EVENTS.END, { storyId }),\n        rerun: () => {\n          emit(FORCE_REMOUNT, { storyId });\n        },\n      }),\n      [emit, storyId]\n    );\n\n    const storyFilePath = useParameter('fileName', '');\n    const [fileName] = storyFilePath.toString().split('/').slice(-1);\n    const scrollToTarget = () => scrollTarget?.scrollIntoView({ behavior: 'smooth', block: 'end' });\n\n    const hasException =\n      !!caughtException ||\n      !!unhandledErrors ||\n      interactions.some((v) => v.status === CallStates.ERROR);\n\n    const browserTestStatus = useMemo<CallStates | undefined>(() => {\n      if (status !== 'playing' && (interactions.length > 0 || hasException)) {\n        return hasException ? CallStates.ERROR : CallStates.DONE;\n      }\n      return status === 'playing' ? CallStates.ACTIVE : undefined;\n    }, [status, interactions, hasException]);\n\n    useEffect(() => {\n      const isMismatch =\n        browserTestStatus &&\n        statusValue &&\n        statusValue !== 'status-value:pending' &&\n        statusValue !== storyStatusMap[browserTestStatus];\n\n      if (isMismatch) {\n        const timeout = setTimeout(\n          () =>\n            setResultMismatch((currentValue) => {\n              if (!currentValue) {\n                emit(STORYBOOK_ADDON_TEST_CHANNEL, {\n                  type: 'test-discrepancy',\n                  payload: {\n                    browserStatus: browserTestStatus === CallStates.DONE ? 'PASS' : 'FAIL',\n                    cliStatus: browserTestStatus === CallStates.DONE ? 'FAIL' : 'PASS',\n                    storyId,\n                    testRunId,\n                  },\n                });\n              }\n              return true;\n            }),\n          2000\n        );\n        return () => clearTimeout(timeout);\n      } else {\n        setResultMismatch(false);\n      }\n    }, [emit, browserTestStatus, statusValue, storyId, testRunId]);\n\n    return (\n      <Fragment key=\"component-tests\">\n        <InteractionsPanel\n          storyUrl={storyUrl}\n          status={status}\n          hasResultMismatch={hasResultMismatch}\n          browserTestStatus={browserTestStatus}\n          calls={calls.current}\n          controls={controls}\n          controlStates={{ ...controlStates, detached: !!refId || controlStates.detached }}\n          interactions={interactions}\n          fileName={fileName}\n          hasException={hasException}\n          caughtException={caughtException}\n          unhandledErrors={unhandledErrors}\n          pausedAt={pausedAt}\n          // @ts-expect-error TODO\n          endRef={endRef}\n          onScrollToEnd={scrollTarget && scrollToTarget}\n          importPath={importPath}\n          canOpenInEditor={canOpenInEditor}\n          api={api}\n        />\n      </Fragment>\n    );\n  }\n);\n"
  },
  {
    "path": "code/core/src/component-testing/components/PanelTitle.tsx",
    "content": "import React from 'react';\n\nimport { Badge } from 'storybook/internal/components';\n\nimport { useAddonState, useStorybookApi } from 'storybook/manager-api';\n\nimport { CallStates } from '../../instrumenter/types.ts';\nimport { ADDON_ID, PANEL_ID } from '../constants.ts';\nimport type { PanelState } from './Panel.tsx';\nimport { StatusIcon } from './StatusIcon.tsx';\n\nexport function PanelTitle() {\n  const api = useStorybookApi();\n  const selectedPanel = api.getSelectedPanel();\n  const [addonState = {}] = useAddonState<PanelState>(ADDON_ID);\n  const { status, hasException, interactionsCount } = addonState as PanelState;\n\n  return (\n    <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>\n      <span>Interactions</span>\n      {interactionsCount && status !== 'errored' && !hasException ? (\n        <Badge compact status={selectedPanel === PANEL_ID ? 'active' : 'neutral'}>\n          {interactionsCount}\n        </Badge>\n      ) : null}\n      {status === 'errored' || hasException ? <StatusIcon status={CallStates.ERROR} /> : null}\n    </div>\n  );\n}\n"
  },
  {
    "path": "code/core/src/component-testing/components/StatusBadge.stories.tsx",
    "content": "import { StatusBadge } from './StatusBadge.tsx';\n\nexport default {\n  title: 'StatusBadge',\n  component: StatusBadge,\n  parameters: { layout: 'padded' },\n};\n\nexport const Wait = {\n  args: { status: 'rendering' },\n};\n\nexport const Runs = {\n  args: { status: 'playing' },\n};\n\nexport const Pass = {\n  args: { status: 'completed' },\n};\n\nexport const Fail = {\n  args: { status: 'errored' },\n};\n\nexport const Bail = {\n  args: { status: 'aborted' },\n};\n"
  },
  {
    "path": "code/core/src/component-testing/components/StatusBadge.tsx",
    "content": "import React from 'react';\n\nimport { TooltipNote, WithTooltip } from 'storybook/internal/components';\n\nimport { type Color, styled, typography } from 'storybook/theming';\n\nexport type PlayStatus = 'rendering' | 'playing' | 'completed' | 'errored' | 'aborted';\n\nexport interface StatusBadgeProps {\n  status: PlayStatus;\n}\n\nconst StatusColorMapping: Record<PlayStatus, keyof Color> = {\n  rendering: 'mediumdark',\n  playing: 'warning',\n  completed: 'positive',\n  errored: 'negative',\n  aborted: 'purple',\n} as const;\n\nconst StatusTextMapping: Record<PlayStatus, string> = {\n  rendering: 'Wait',\n  playing: 'Runs',\n  completed: 'Pass',\n  errored: 'Fail',\n  aborted: 'Bail',\n} as const;\n\nconst StatusNoteMapping: Record<PlayStatus, string> = {\n  rendering: 'Story is rendering',\n  playing: 'Interactions are running',\n  completed: 'Story ran successfully',\n  errored: 'Story failed to complete',\n  aborted: 'Interactions aborted due to file changes',\n} as const;\n\nconst StyledBadge = styled.div<StatusBadgeProps>(({ theme, status }) => {\n  const backgroundColor = theme.color[StatusColorMapping[status]];\n  return {\n    display: 'inline-block',\n    padding: '4px 6px 4px 8px',\n    borderRadius: '4px',\n    backgroundColor,\n    color: 'white',\n    fontFamily: typography.fonts.base,\n    textTransform: 'uppercase',\n    fontSize: typography.size.s1,\n    letterSpacing: 3,\n    fontWeight: typography.weight.bold,\n    minWidth: 65,\n    textAlign: 'center',\n  };\n});\n\nexport const StatusBadge: React.FC<StatusBadgeProps> = ({ status }) => {\n  const badgeText = StatusTextMapping[status];\n  const badgeNote = StatusNoteMapping[status];\n  return (\n    <WithTooltip\n      hasChrome={false}\n      placement=\"top\"\n      trigger=\"hover\"\n      tooltip={<TooltipNote note={badgeNote} />}\n    >\n      <StyledBadge aria-label={`Story status: ${badgeText}`} status={status}>\n        {badgeText}\n      </StyledBadge>\n    </WithTooltip>\n  );\n};\n"
  },
  {
    "path": "code/core/src/component-testing/components/StatusIcon.stories.tsx",
    "content": "import { CallStates } from '../../instrumenter/types.ts';\nimport { StatusIcon } from './StatusIcon.tsx';\n\nexport default {\n  title: 'StatusIcon',\n  component: StatusIcon,\n};\n\nexport const Pending = {\n  args: { status: CallStates.WAITING },\n};\n\nexport const Active = {\n  args: { status: CallStates.ACTIVE },\n};\n\nexport const Error = {\n  args: { status: CallStates.ERROR },\n};\n\nexport const Done = {\n  args: { status: CallStates.DONE },\n};\n"
  },
  {
    "path": "code/core/src/component-testing/components/StatusIcon.tsx",
    "content": "import React from 'react';\n\nimport { CheckIcon, CircleIcon, PlayIcon, StopAltIcon } from '@storybook/icons';\n\nimport { transparentize } from 'polished';\nimport { styled, useTheme } from 'storybook/theming';\n\nimport { type Call, CallStates } from '../../instrumenter/types.ts';\n\nexport interface StatusIconProps {\n  status: Call['status'];\n}\n\nconst WarningContainer = styled.div({\n  width: 14,\n  height: 14,\n  display: 'flex',\n  alignItems: 'center',\n  justifyContent: 'center',\n});\n\nexport const StatusIcon: React.FC<StatusIconProps> = ({ status }) => {\n  const theme = useTheme();\n\n  switch (status) {\n    case CallStates.DONE: {\n      return <CheckIcon color={theme.color.positive} data-testid=\"icon-done\" />;\n    }\n    case CallStates.ERROR: {\n      return <StopAltIcon color={theme.color.negative} data-testid=\"icon-error\" />;\n    }\n    case CallStates.ACTIVE: {\n      return <PlayIcon color={theme.color.secondary} data-testid=\"icon-active\" />;\n    }\n    case CallStates.WAITING: {\n      return (\n        <WarningContainer data-testid=\"icon-waiting\">\n          <CircleIcon color={transparentize(0.5, '#CCCCCC')} size={6} />\n        </WarningContainer>\n      );\n    }\n    default: {\n      return null;\n    }\n  }\n};\n"
  },
  {
    "path": "code/core/src/component-testing/components/TestDiscrepancyMessage.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { ManagerContext } from 'storybook/manager-api';\nimport { fn } from 'storybook/test';\n\nimport { CallStates } from '../../instrumenter/types.ts';\nimport { TestDiscrepancyMessage } from './TestDiscrepancyMessage.tsx';\n\ntype Story = StoryObj<typeof TestDiscrepancyMessage>;\nconst managerContext: any = {\n  state: {},\n  api: {\n    getDocsUrl: fn().mockName('api::getDocsUrl'),\n    emit: fn().mockName('api::emit'),\n  },\n};\n\nexport default {\n  title: 'TestDiscrepancyMessage',\n  component: TestDiscrepancyMessage,\n  parameters: {\n    layout: 'fullscreen',\n  },\n  decorators: [\n    (storyFn) => (\n      <ManagerContext.Provider value={managerContext}>{storyFn()}</ManagerContext.Provider>\n    ),\n  ],\n} as Meta<typeof TestDiscrepancyMessage>;\n\nexport const BrowserPassedCliFailed: Story = {\n  args: {\n    browserTestStatus: CallStates.DONE,\n  },\n};\n\nexport const CliFailedBrowserPassed: Story = {\n  args: {\n    browserTestStatus: CallStates.ERROR,\n  },\n};\n"
  },
  {
    "path": "code/core/src/component-testing/components/TestDiscrepancyMessage.tsx",
    "content": "import React from 'react';\n\nimport { Link } from 'storybook/internal/components';\n\nimport { useStorybookApi } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport { CallStates } from '../../instrumenter/types.ts';\nimport { DOCUMENTATION_DISCREPANCY_LINK } from '../constants.ts';\n\nconst Wrapper = styled.div(({ theme: { color, typography, background } }) => ({\n  textAlign: 'start',\n  padding: '11px 15px',\n  fontSize: `${typography.size.s2 - 1}px`,\n  fontWeight: typography.weight.regular,\n  lineHeight: '1rem',\n  background: background.app,\n  borderBottom: `1px solid ${color.border}`,\n  color: color.defaultText,\n  backgroundClip: 'padding-box',\n  position: 'relative',\n  code: {\n    fontSize: `${typography.size.s1 - 1}px`,\n    color: 'inherit',\n    margin: '0 0.2em',\n    padding: '0 0.2em',\n    background: 'rgba(255, 255, 255, 0.8)',\n    borderRadius: '2px',\n    boxShadow: '0 0 0 1px rgba(0, 0, 0, 0.1)',\n  },\n}));\n\ninterface TestDiscrepancyMessageProps {\n  browserTestStatus?: CallStates;\n}\n\nexport const TestDiscrepancyMessage = ({ browserTestStatus }: TestDiscrepancyMessageProps) => {\n  const api = useStorybookApi();\n  const docsUrl = api.getDocsUrl({\n    subpath: DOCUMENTATION_DISCREPANCY_LINK,\n    versioned: true,\n    renderer: true,\n  });\n  const [passed, failed] =\n    browserTestStatus === CallStates.ERROR\n      ? ['the CLI', 'this browser']\n      : ['this browser', 'the CLI'];\n\n  return (\n    <Wrapper>\n      This interaction test passed in {passed}, but the tests failed in {failed}.{' '}\n      <Link href={docsUrl} target=\"_blank\" withArrow>\n        Learn what could cause this\n      </Link>\n    </Wrapper>\n  );\n};\n"
  },
  {
    "path": "code/core/src/component-testing/components/Toolbar.stories.tsx",
    "content": "import React from 'react';\n\nimport { action } from 'storybook/actions';\n\nimport { Toolbar } from './Toolbar.tsx';\n\nexport default {\n  title: 'Toolbar',\n  component: Toolbar,\n  parameters: {\n    layout: 'fullscreen',\n  },\n  args: {\n    controls: {\n      start: action('start'),\n      back: action('back'),\n      goto: action('goto'),\n      next: action('next'),\n      end: action('end'),\n      rerun: action('rerun'),\n    },\n    controlStates: {\n      detached: false,\n      start: true,\n      back: true,\n      goto: true,\n      next: false,\n      end: false,\n    },\n    storyFileName: 'Toolbar.stories.tsx',\n    hasNext: true,\n    hasPrevious: true,\n  },\n};\n\nexport const Wait = {\n  args: {\n    status: 'rendering',\n    controlStates: {\n      detached: false,\n      start: false,\n      back: false,\n      goto: false,\n      next: false,\n      end: false,\n    },\n  },\n};\n\nexport const Runs = {\n  args: {\n    status: 'playing',\n  },\n};\n\nexport const Pass = {\n  args: {\n    status: 'completed',\n  },\n};\n\nexport const Fail = {\n  args: {\n    status: 'errored',\n  },\n};\n\nexport const Bail = {\n  args: {\n    status: 'aborted',\n    controlStates: {\n      detached: false,\n      start: false,\n      back: false,\n      goto: false,\n      next: false,\n      end: false,\n    },\n  },\n};\n\nexport const AtStart = {\n  args: {\n    status: 'playing',\n    controlStates: {\n      detached: false,\n      start: false,\n      back: false,\n      goto: true,\n      next: true,\n      end: true,\n    },\n  },\n};\n\nexport const Midway = {\n  args: {\n    status: 'playing',\n    controlStates: {\n      detached: false,\n      start: true,\n      back: true,\n      goto: true,\n      next: true,\n      end: true,\n    },\n  },\n};\n\nexport const Locked = {\n  args: {\n    status: 'playing',\n    controlStates: {\n      detached: false,\n      start: false,\n      back: false,\n      goto: false,\n      next: false,\n      end: false,\n    },\n  },\n};\n\nexport const Detached = {\n  args: {\n    status: 'completed',\n    controlStates: {\n      detached: true,\n      start: false,\n      back: false,\n      goto: false,\n      next: false,\n      end: false,\n    },\n  },\n};\n\nexport const WithOpenInEditorLink = {\n  args: {\n    status: 'completed',\n    controlStates: {\n      detached: true,\n      start: false,\n      back: false,\n      goto: false,\n      next: false,\n      end: false,\n    },\n    canOpenInEditor: true,\n  },\n};\n"
  },
  {
    "path": "code/core/src/component-testing/components/Toolbar.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React from 'react';\n\nimport { Button, P, Separator, Toolbar as SharedToolbar } from 'storybook/internal/components';\n\nimport {\n  FastForwardIcon,\n  PlayBackIcon,\n  PlayNextIcon,\n  RewindIcon,\n  SyncIcon,\n} from '@storybook/icons';\n\nimport { type API } from 'storybook/manager-api';\nimport { styled, useTheme } from 'storybook/theming';\n\nimport { type ControlStates } from '../../instrumenter/types.ts';\nimport type { Controls } from './InteractionsPanel.tsx';\nimport { type PlayStatus, StatusBadge } from './StatusBadge.tsx';\n\nconst ToolbarWrapper = styled.div(({ theme }) => ({\n  boxShadow: `${theme.appBorderColor} 0 -1px 0 0 inset`,\n  background: theme.background.app,\n  position: 'sticky',\n  top: 0,\n  zIndex: 1,\n}));\n\ninterface ToolbarProps {\n  controls: Controls;\n  controlStates: ControlStates;\n  status: PlayStatus;\n  storyFileName?: string;\n  onScrollToEnd?: () => void;\n  importPath?: string;\n  canOpenInEditor?: boolean;\n  api: API;\n}\n\nconst StyledButton = styled(Button)(({ theme }) => ({\n  borderRadius: 4,\n  padding: 6,\n  color: theme.textMutedColor,\n  '&:not(:disabled)': {\n    '&:hover,&:focus-visible': {\n      color: theme.color.secondary,\n    },\n  },\n}));\n\nconst StyledIconButton = styled(Button)(({ theme }) => ({\n  color: theme.textMutedColor,\n}));\n\nconst OpenInEditorButton = styled(Button)(({ theme }) => ({\n  color: theme.color.secondary,\n  fontWeight: theme.typography.weight.bold,\n  justifyContent: 'flex-end',\n  textAlign: 'right',\n  whiteSpace: 'nowrap',\n  fontSize: 13,\n  lineHeight: 24,\n}));\n\nconst StyledLocation = styled(P)(({ theme }) => ({\n  color: theme.textMutedColor,\n  cursor: 'default',\n  fontWeight: theme.typography.weight.regular,\n  justifyContent: 'flex-end',\n  textAlign: 'right',\n  whiteSpace: 'nowrap',\n  margin: 0,\n  fontSize: 13,\n}));\n\nconst ControlsGroup = styled.div({\n  display: 'flex',\n  alignItems: 'center',\n  flex: 1,\n  gap: 6,\n});\n\nconst RewindButton = styled(StyledIconButton)({\n  marginInlineStart: 3,\n});\n\nconst JumpToEndButton = styled(StyledButton)({\n  marginInline: 3,\n  lineHeight: '12px',\n});\n\ninterface AnimatedButtonProps {\n  animating?: boolean;\n}\n\nconst RerunButton = styled(StyledIconButton)<\n  AnimatedButtonProps & ComponentProps<typeof StyledIconButton>\n>(({ theme, animating, disabled }) => ({\n  opacity: disabled ? 0.5 : 1,\n  svg: {\n    animation: animating ? `${theme.animation.rotate360} 200ms ease-out` : undefined,\n  },\n}));\n\nexport const Toolbar: React.FC<ToolbarProps> = ({\n  controls,\n  controlStates,\n  status,\n  storyFileName,\n  onScrollToEnd,\n  importPath,\n  canOpenInEditor,\n  api,\n}) => {\n  const buttonText = status === 'errored' ? 'Scroll to error' : 'Scroll to end';\n  const theme = useTheme();\n\n  return (\n    <ToolbarWrapper>\n      <SharedToolbar\n        backgroundColor={theme.background.app}\n        innerStyle={{ gap: 6, paddingInline: 15 }}\n        aria-label=\"Component test playback controls\"\n      >\n        <ControlsGroup>\n          <StatusBadge status={status} />\n\n          <JumpToEndButton ariaLabel={false} onClick={onScrollToEnd} disabled={!onScrollToEnd}>\n            {buttonText}\n          </JumpToEndButton>\n\n          <Separator />\n\n          <RewindButton\n            padding=\"small\"\n            variant=\"ghost\"\n            ariaLabel=\"Go to start\"\n            onClick={controls.start}\n            disabled={!controlStates.start}\n          >\n            <RewindIcon />\n          </RewindButton>\n\n          <StyledIconButton\n            padding=\"small\"\n            variant=\"ghost\"\n            ariaLabel=\"Go back\"\n            onClick={controls.back}\n            disabled={!controlStates.back}\n          >\n            <PlayBackIcon />\n          </StyledIconButton>\n\n          <StyledIconButton\n            padding=\"small\"\n            variant=\"ghost\"\n            ariaLabel=\"Go forward\"\n            onClick={controls.next}\n            disabled={!controlStates.next}\n          >\n            <PlayNextIcon />\n          </StyledIconButton>\n\n          <StyledIconButton\n            padding=\"small\"\n            variant=\"ghost\"\n            ariaLabel=\"Go to end\"\n            onClick={controls.end}\n            disabled={!controlStates.end}\n          >\n            <FastForwardIcon />\n          </StyledIconButton>\n\n          <RerunButton padding=\"small\" variant=\"ghost\" ariaLabel=\"Rerun\" onClick={controls.rerun}>\n            <SyncIcon />\n          </RerunButton>\n        </ControlsGroup>\n        {(importPath || storyFileName) &&\n          (canOpenInEditor ? (\n            <OpenInEditorButton\n              padding=\"small\"\n              size=\"small\"\n              variant=\"ghost\"\n              ariaLabel=\"Open in editor\"\n              onClick={() => {\n                api.openInEditor({\n                  file: importPath as string,\n                });\n              }}\n            >\n              {storyFileName}\n            </OpenInEditorButton>\n          ) : (\n            <StyledLocation>{storyFileName}</StyledLocation>\n          ))}\n      </SharedToolbar>\n    </ToolbarWrapper>\n  );\n};\n"
  },
  {
    "path": "code/core/src/component-testing/components/test-fn.stories.tsx",
    "content": "import React from 'react';\n\nimport type { StoryContext } from '@storybook/react-vite';\n\nimport { expect, fn } from 'storybook/test';\n\nimport preview from '../../../../.storybook/preview.tsx';\n\nconst Button = (args: React.ComponentProps<'button'>) => <button {...args} />;\n\nconst meta = preview.meta({\n  component: Button,\n  render: (args, { name }) => (\n    <span>\n      {name}\n      <br />\n      <br />\n      <button {...args} />\n    </span>\n  ),\n  args: {\n    children: 'Default',\n    onClick: fn(),\n  },\n  tags: ['some-tag', 'autodocs'],\n});\n\nexport const WithNoTests = meta.story();\n\nexport const TestFunctionTypes = meta.story({\n  args: {\n    children: 'Arg from story',\n  },\n});\n\nexport const PlayFunction = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    const button = canvas.getByText('Default');\n    await userEvent.click(button);\n  },\n});\n\nTestFunctionTypes.test('simple', async ({ canvas, userEvent, args }) => {\n  const button = canvas.getByText('Arg from story');\n  await userEvent.click(button);\n  await expect(args.onClick).toHaveBeenCalled();\n});\n\nconst doTest = async ({\n  canvas,\n  userEvent,\n  args,\n}: StoryContext<React.ComponentProps<'button'>>) => {\n  const button = canvas.getByText('Arg from story');\n  await userEvent.click(button);\n  await expect(args.onClick).toHaveBeenCalled();\n};\nTestFunctionTypes.test('referring to function in file', doTest);\n\nTestFunctionTypes.test(\n  'with overrides',\n  {\n    args: {\n      children: 'Arg from test override',\n    },\n    parameters: {\n      viewport: {\n        options: {\n          sized: {\n            name: 'Sized',\n            styles: {\n              width: '380px',\n              height: '500px',\n            },\n          },\n        },\n      },\n      chromatic: { viewports: [380] },\n    },\n    globals: { sb_theme: 'dark', viewport: { value: 'sized' } },\n  },\n  async ({ canvas }) => {\n    const button = canvas.getByText('Arg from test override');\n    await expect(button).toBeInTheDocument();\n    expect(document.body.clientWidth).toBe(380);\n  }\n);\n\nTestFunctionTypes.test(\n  'with play function',\n  {\n    play: async ({ canvas }) => {\n      const button = canvas.getByText('Arg from story');\n      await expect(button).toBeInTheDocument();\n    },\n  },\n  async ({ canvas }) => {\n    const button = canvas.getByText('Arg from story');\n    await expect(button).not.toHaveAttribute('aria-disabled', 'true');\n  }\n);\n\nexport const ExtendedStorySinglePlayExample = TestFunctionTypes.extend({\n  args: {\n    children: 'Arg from extended story',\n  },\n  play: async ({ canvas }) => {\n    const button = canvas.getByText('Arg from extended story');\n    await expect(button).not.toHaveAttribute('aria-disabled', 'true');\n  },\n});\n\nexport const ExtendedStorySingleTestExample = TestFunctionTypes.extend({\n  args: {\n    children: 'Arg from extended story',\n  },\n});\n\nExtendedStorySingleTestExample.test(\n  'this is a very long test name to explain that this story test should guarantee that the args have been extended correctly',\n  async ({ canvas }) => {\n    const button = canvas.getByText('Arg from extended story');\n    await expect(button).not.toHaveAttribute('aria-disabled', 'true');\n  }\n);\n\n// This is intentionally defined out-of-order\nPlayFunction.test('should be clicked by play function', async ({ args }) => {\n  await expect(args.onClick).toHaveBeenCalled();\n});\n\nexport const TestNames = meta.story({\n  args: {\n    children: 'This story is no-op, just focus on the test names',\n  },\n});\nTestNames.test(\n  'should display an error when login is attempted with an expired session token',\n  () => {}\n);\n\nTestNames.test(\n  'should display an error when login is attempted with multiple invalid password attempts',\n  () => {}\n);\n\nTestNames.test('should display an error when login is attempted with a revoked API key', () => {});\n\nTestNames.test(\n  'should display an error when login is attempted after exceeding the maximum session limit',\n  () => {}\n);\n\nTestNames.test(\n  'should display an error when login is attempted with a disabled user account',\n  () => {}\n);\n\nTestNames.test(\n  'should display an error when login is attempted with an unsupported authentication provider',\n  () => {}\n);\n\nTestNames.test(\n  'should display an error when login is attempted after the password reset process is incomplete',\n  () => {}\n);\n\nTestNames.test(\n  'should display an error when login is attempted with a malformed authentication request',\n  () => {}\n);\n\nTestNames.test(\n  'should display an error when login is attempted with an unverified email address',\n  () => {}\n);\n"
  },
  {
    "path": "code/core/src/component-testing/constants.ts",
    "content": "export const ADDON_ID = 'storybook/interactions';\nexport const PANEL_ID = `${ADDON_ID}/panel`;\nexport const PARAM_KEY = 'interactions';\n\nexport const DOCUMENTATION_LINK = 'writing-tests/integrations/vitest-addon';\nexport const DOCUMENTATION_DISCREPANCY_LINK = `${DOCUMENTATION_LINK}#what-happens-when-there-are-different-test-results-in-multiple-environments`;\nexport const DOCUMENTATION_PLAY_FUNCTION_LINK =\n  'writing-stories/play-function#writing-stories-with-the-play-function';\n\nexport const INTERNAL_RENDER_CALL_ID = 'internal_render_call';\n"
  },
  {
    "path": "code/core/src/component-testing/manager.test.tsx",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { PARAM_KEY } from './constants.ts';\nimport type { InteractionsParameters } from './types.ts';\nimport { isInteractionsDisabled } from './utils.ts';\n\ndescribe('Interactions Panel Disable Parameter', () => {\n  it('should return true when interactions.disable is true', () => {\n    const parameters: InteractionsParameters = {\n      [PARAM_KEY]: {\n        disable: true,\n      },\n    };\n\n    expect(isInteractionsDisabled(parameters)).toBe(true);\n  });\n\n  it('should return false when interactions.disable is false', () => {\n    const parameters: InteractionsParameters = {\n      [PARAM_KEY]: {\n        disable: false,\n      },\n    };\n\n    expect(isInteractionsDisabled(parameters)).toBe(false);\n  });\n\n  it('should return false when interactions parameter is not provided', () => {\n    const parameters: InteractionsParameters = {};\n\n    expect(isInteractionsDisabled(parameters)).toBe(false);\n  });\n\n  it('should return false when disable is undefined', () => {\n    const parameters: InteractionsParameters = {\n      [PARAM_KEY]: {},\n    };\n\n    expect(isInteractionsDisabled(parameters)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "code/core/src/component-testing/manager.tsx",
    "content": "import React from 'react';\n\nimport { AddonPanel } from 'storybook/internal/components';\n\nimport { type Combo, Consumer, addons, types } from 'storybook/manager-api';\n\nimport { Panel } from './components/Panel.tsx';\nimport { PanelTitle } from './components/PanelTitle.tsx';\nimport { ADDON_ID, PANEL_ID } from './constants.ts';\nimport { isInteractionsDisabled } from './utils.ts';\n\nexport default addons.register(ADDON_ID, () => {\n  if (globalThis?.FEATURES?.interactions) {\n    const filter = ({ state }: Combo) => {\n      const origin = (state.refId && state.refs[state.refId]?.url) || document.location.origin;\n      const { pathname, search = '' } = state.location;\n      const path = pathname + (state.refId ? search.replace(`/${state.refId}_`, '/') : search);\n      return {\n        refId: state.refId,\n        storyId: state.storyId,\n        storyUrl: origin + path,\n      };\n    };\n\n    addons.add(PANEL_ID, {\n      type: types.PANEL,\n      title: () => <PanelTitle />,\n      match: ({ viewMode }) => viewMode === 'story',\n      disabled: isInteractionsDisabled,\n      render: ({ active }) => {\n        return (\n          <AddonPanel active={!!active}>\n            <Consumer filter={filter}>{(props) => <Panel {...props} />}</Consumer>\n          </AddonPanel>\n        );\n      },\n    });\n  }\n});\n"
  },
  {
    "path": "code/core/src/component-testing/mocks/index.ts",
    "content": "import { type Call, CallStates } from 'storybook/internal/instrumenter';\n\nimport { INTERNAL_RENDER_CALL_ID } from '../constants.ts';\n\nexport const getCalls = (finalStatus: CallStates, slice?: number) => {\n  let calls: Call[] = [\n    {\n      id: INTERNAL_RENDER_CALL_ID,\n      storyId: 'story--id',\n      cursor: 0,\n      ancestors: [],\n      path: [],\n      method: 'render',\n      args: [],\n      interceptable: true,\n      retain: false,\n      status: CallStates.DONE,\n    },\n    {\n      id: 'story--id [3] step',\n      storyId: 'story--id',\n      cursor: 1,\n      ancestors: [],\n      path: [],\n      method: 'step',\n      args: ['Click button', { __function__: { name: '' } }],\n      interceptable: true,\n      retain: false,\n      status: CallStates.DONE,\n    },\n    {\n      id: 'story--id [3] step [1] within',\n      storyId: 'story--id',\n      cursor: 3,\n      ancestors: ['story--id [3] step'],\n      path: [],\n      method: 'within',\n      args: [{ __element__: { localName: 'div', id: 'root' } }],\n      interceptable: false,\n      retain: false,\n      status: CallStates.DONE,\n    },\n    {\n      id: 'story--id [3] step [2] findByText',\n      storyId: 'story--id',\n      cursor: 4,\n      ancestors: ['story--id [3] step'],\n      path: [{ __callId__: 'story--id [3] step [1] within' }],\n      method: 'findByText',\n      args: ['Click'],\n      interceptable: true,\n      retain: false,\n      status: CallStates.DONE,\n    },\n    {\n      id: 'story--id [3] step [3] click',\n      storyId: 'story--id',\n      cursor: 5,\n      ancestors: ['story--id [3] step'],\n      path: ['userEvent'],\n      method: 'click',\n      args: [{ __element__: { localName: 'button', innerText: 'Click' } }],\n      interceptable: true,\n      retain: false,\n      status: CallStates.DONE,\n    },\n    {\n      id: 'story--id [6] waitFor',\n      storyId: 'story--id',\n      cursor: 6,\n      ancestors: [],\n      path: [],\n      method: 'waitFor',\n      args: [{ __function__: { name: '' } }],\n      interceptable: true,\n      retain: false,\n      status: CallStates.DONE,\n    },\n    {\n      id: 'story--id [6] waitFor [0] expect',\n      storyId: 'story--id',\n      cursor: 1,\n      ancestors: ['story--id [6] waitFor'],\n      path: [],\n      method: 'expect',\n      args: [{ __function__: { name: 'handleSubmit' } }],\n      interceptable: false,\n      retain: false,\n      status: CallStates.DONE,\n    },\n    {\n      id: 'story--id [6] waitFor [1] stringMatching',\n      storyId: 'story--id',\n      cursor: 2,\n      ancestors: ['story--id [6] waitFor'],\n      path: ['expect'],\n      method: 'stringMatching',\n      args: [{ __regexp__: { flags: 'gi', source: '([A-Z])w+' } }],\n      interceptable: false,\n      retain: false,\n      status: CallStates.DONE,\n    },\n    {\n      id: 'story--id [6] waitFor [2] toHaveBeenCalledWith',\n      storyId: 'story--id',\n      cursor: 3,\n      ancestors: ['story--id [6] waitFor'],\n      path: [{ __callId__: 'story--id [6] waitFor [0] expect' }],\n      method: 'toHaveBeenCalledWith',\n      args: [{ __callId__: 'story--id [6] waitFor [1] stringMatching', retain: false }],\n      interceptable: true,\n      retain: false,\n      status: CallStates.DONE,\n    },\n    {\n      id: 'story--id [7] expect',\n      storyId: 'story--id',\n      cursor: 7,\n      ancestors: [],\n      path: [],\n      method: 'expect',\n      args: [{ __function__: { name: 'handleReset' } }],\n      interceptable: false,\n      retain: false,\n      status: CallStates.DONE,\n    },\n    {\n      id: 'story--id [8] toHaveBeenCalled',\n      storyId: 'story--id',\n      cursor: 8,\n      ancestors: [],\n      path: [{ __callId__: 'story--id [7] expect' }, 'not'],\n      method: 'toHaveBeenCalled',\n      args: [],\n      interceptable: true,\n      retain: false,\n      status: finalStatus,\n    },\n  ];\n\n  if (typeof slice === 'number') {\n    calls = slice < 0 ? calls.slice(slice) : calls.slice(0, slice);\n  }\n\n  if (finalStatus === CallStates.ERROR) {\n    calls[calls.length - 1].status = finalStatus;\n    calls[calls.length - 1].exception = {\n      callId: calls[calls.length - 1].id,\n      name: 'ReferenceError',\n      message: 'ref is not defined',\n      stack: `ReferenceError: ref is not defined\n    at BaseModal (http://localhost:6006/core/src/components/components/Modal/Modal.tsx?t=1743533873995:33:5)\n    at renderWithHooks (http://localhost:6006/node_modules/.cache/storybook/da6a511058d185c3c92ed7790fc88078d8a947a8d0ac75815e8fd5704bcd4baa/sb-vite/deps/chunk-6FHVKFOZ.js?v=8ff74cdb:12199:26)\n    at mountIndeterminateComponent (http://localhost:6006/node_modules/.cache/storybook/da6a511058d185c3c92ed7790fc88078d8a947a8d0ac75815e8fd5704bcd4baa/sb-vite/deps/chunk-6FHVKFOZ.js?v=8ff74cdb:14949:21)\n    at beginWork (http://localhost:6006/node_modules/.cache/storybook/da6a511058d185c3c92ed7790fc88078d8a947a8d0ac75815e8fd5704bcd4baa/sb-vite/deps/chunk-6FHVKFOZ.js?v=8ff74cdb:15930:22)\n    at beginWork$1 (http://localhost:6006/node_modules/.cache/storybook/da6a511058d185c3c92ed7790fc88078d8a947a8d0ac75815e8fd5704bcd4baa/sb-vite/deps/chunk-6FHVKFOZ.js?v=8ff74cdb:19774:22)\n    at performUnitOfWork (http://localhost:6006/node_modules/.cache/storybook/da6a511058d185c3c92ed7790fc88078d8a947a8d0ac75815e8fd5704bcd4baa/sb-vite/deps/chunk-6FHVKFOZ.js?v=8ff74cdb:19219:20)\n    at workLoopSync (http://localhost:6006/node_modules/.cache/storybook/da6a511058d185c3c92ed7790fc88078d8a947a8d0ac75815e8fd5704bcd4baa/sb-vite/deps/chunk-6FHVKFOZ.js?v=8ff74cdb:19158:13)\n    at renderRootSync (http://localhost:6006/node_modules/.cache/storybook/da6a511058d185c3c92ed7790fc88078d8a947a8d0ac75815e8fd5704bcd4baa/sb-vite/deps/chunk-6FHVKFOZ.js?v=8ff74cdb:19137:15)\n    at recoverFromConcurrentError (http://localhost:6006/node_modules/.cache/storybook/da6a511058d185c3c92ed7790fc88078d8a947a8d0ac75815e8fd5704bcd4baa/sb-vite/deps/chunk-6FHVKFOZ.js?v=8ff74cdb:18754:28)\n    at performConcurrentWorkOnRoot (http://localhost:6006/node_modules/.cache/storybook/da6a511058d185c3c92ed7790fc88078d8a947a8d0ac75815e8fd5704bcd4baa/sb-vite/deps/chunk-6FHVKFOZ.js?v=8ff74cdb:18702:30)`,\n    };\n  }\n\n  return calls;\n};\n\nexport const getInteractions = (finalStatus: CallStates) =>\n  getCalls(finalStatus)\n    .filter((call) => call.interceptable)\n    .map((call) => ({\n      ...call,\n      childCallIds: [],\n      isCollapsed: false,\n      isHidden: false,\n      toggleCollapsed: () => {},\n    }));\n"
  },
  {
    "path": "code/core/src/component-testing/preview.ts",
    "content": "import { definePreviewAddon } from 'storybook/internal/csf';\nimport { instrument } from 'storybook/internal/instrumenter';\nimport type { PlayFunction, StepLabel, StoryContext } from 'storybook/internal/types';\n\nconst { step } = instrument(\n  {\n    // It seems like the label is unused, but the instrumenter has access to it\n    // The context will be bounded later in StoryRender, so that the user can write just:\n    // await step(\"label\", (context) => {\n    //   // labeled step\n    // });\n    step: async (label: StepLabel, play: PlayFunction, context: StoryContext) => play(context),\n  },\n  { intercept: true }\n);\n\nexport default () =>\n  definePreviewAddon({\n    parameters: {\n      throwPlayFunctionExceptions: false,\n    },\n    runStep: step,\n  });\n"
  },
  {
    "path": "code/core/src/component-testing/types.ts",
    "content": "export interface InteractionsParameters {\n  /**\n   * Interactions configuration\n   *\n   * @see https://storybook.js.org/docs/writing-tests/interaction-testing\n   */\n  interactions?: {\n    /**\n     * Removes the addon panel and disables the feature's behavior. If you wish to turn off this\n     * feature for the entire Storybook, you can set the option in your `main.js|ts` configuration\n     * file.\n     *\n     * @see https://storybook.js.org/docs/writing-tests/interaction-testing#disable\n     */\n    disable?: boolean;\n  };\n}\n\nexport interface InteractionsTypes {\n  parameters: InteractionsParameters;\n}\n"
  },
  {
    "path": "code/core/src/component-testing/utils.ts",
    "content": "import type { API_StoryEntry } from 'storybook/internal/types';\n\nimport Filter from 'ansi-to-html';\nimport { type StorybookTheme, useTheme } from 'storybook/theming';\n// eslint-disable-next-line depend/ban-dependencies\nimport stripAnsi from 'strip-ansi';\n\nimport { PARAM_KEY } from './constants.ts';\n\nexport function isInteractionsDisabled(parameters: API_StoryEntry['parameters']): boolean {\n  return !!parameters?.[PARAM_KEY]?.disable;\n}\n\nexport function isTestAssertionError(error: unknown) {\n  return isChaiError(error) || isJestError(error);\n}\n\nexport function isChaiError(error: unknown) {\n  return (\n    error &&\n    typeof error === 'object' &&\n    'name' in error &&\n    typeof error.name === 'string' &&\n    error.name === 'AssertionError'\n  );\n}\n\nexport function isJestError(error: unknown) {\n  return (\n    error &&\n    typeof error === 'object' &&\n    'message' in error &&\n    typeof error.message === 'string' &&\n    stripAnsi(error.message).startsWith('expect(')\n  );\n}\n\nexport function createAnsiToHtmlFilter(theme: StorybookTheme) {\n  return new Filter({\n    escapeXML: true,\n    fg: theme.color.defaultText,\n    bg: theme.background.content,\n  });\n}\n\nexport function useAnsiToHtmlFilter() {\n  const theme = useTheme();\n  return createAnsiToHtmlFilter(theme);\n}\n"
  },
  {
    "path": "code/core/src/components/README.md",
    "content": "# Storybook Components\n\nStorybook Components is a React UI components collection used by the UI of Storybook and Addons.\n\nAll components use [`emotion`](https://emotion.sh) for styling.\n"
  },
  {
    "path": "code/core/src/components/brand/SideBySide.tsx",
    "content": "import { styled } from 'storybook/theming';\n\nexport const SideBySide = styled.div({\n  display: 'grid',\n  gridColumnGap: 30,\n  gridTemplateColumns: '1fr 1fr',\n\n  position: 'absolute',\n  width: '100vw',\n  height: '100vh',\n  overflow: 'auto',\n  top: 0,\n  left: 0,\n\n  '& > *': {\n    padding: 20,\n  },\n});\n"
  },
  {
    "path": "code/core/src/components/brand/StorybookIcon.stories.tsx",
    "content": "import { StorybookIcon } from './StorybookIcon.tsx';\n\nexport default {\n  component: StorybookIcon,\n};\n\nexport const Default = {};\n"
  },
  {
    "path": "code/core/src/components/brand/StorybookIcon.tsx",
    "content": "import React from 'react';\n\nexport const StorybookIcon = (props: React.SVGAttributes<SVGElement>) => (\n  <svg viewBox=\"0 0 64 64\" {...props}>\n    <title>Storybook icon</title>\n    <g id=\"Artboard\" stroke=\"none\" strokeWidth=\"1\" fill=\"none\" fillRule=\"evenodd\">\n      <path\n        d=\"M8.04798541,58.7875918 L6.07908839,6.32540407 C6.01406344,4.5927838 7.34257463,3.12440831 9.07303814,3.01625434 L53.6958037,0.227331489 C55.457209,0.117243658 56.974354,1.45590096 57.0844418,3.21730626 C57.0885895,3.28366922 57.0906648,3.35014546 57.0906648,3.41663791 L57.0906648,60.5834697 C57.0906648,62.3483119 55.6599776,63.7789992 53.8951354,63.7789992 C53.847325,63.7789992 53.7995207,63.7779262 53.7517585,63.775781 L11.0978899,61.8600599 C9.43669044,61.7854501 8.11034889,60.4492961 8.04798541,58.7875918 Z\"\n        id=\"path-1\"\n        fill=\"#FF4785\"\n        fillRule=\"nonzero\"\n      />\n      <path\n        d=\"M35.9095005,24.1768792 C35.9095005,25.420127 44.2838488,24.8242707 45.4080313,23.9509748 C45.4080313,15.4847538 40.8652557,11.0358878 32.5466666,11.0358878 C24.2280775,11.0358878 19.5673077,15.553972 19.5673077,22.3311017 C19.5673077,34.1346028 35.4965208,34.3605071 35.4965208,40.7987804 C35.4965208,42.606015 34.6115646,43.6790606 32.6646607,43.6790606 C30.127786,43.6790606 29.1248356,42.3834613 29.2428298,37.9783269 C29.2428298,37.0226907 19.5673077,36.7247626 19.2723223,37.9783269 C18.5211693,48.6535354 25.1720308,51.7326752 32.7826549,51.7326752 C40.1572906,51.7326752 45.939005,47.8018145 45.939005,40.6858282 C45.939005,28.035186 29.7738035,28.3740425 29.7738035,22.1051974 C29.7738035,19.5637737 31.6617103,19.2249173 32.7826549,19.2249173 C33.9625966,19.2249173 36.0864917,19.4328883 35.9095005,24.1768792 Z\"\n        id=\"path9_fill-path\"\n        fill=\"#FFFFFF\"\n        fillRule=\"nonzero\"\n      />\n      <path\n        d=\"M44.0461638,0.830433986 L50.1874092,0.446606143 L50.443532,7.7810017 C50.4527198,8.04410717 50.2468789,8.26484453 49.9837734,8.27403237 C49.871115,8.27796649 49.7607078,8.24184808 49.6721567,8.17209069 L47.3089847,6.3104681 L44.5110468,8.43287463 C44.3012992,8.591981 44.0022839,8.55092814 43.8431776,8.34118051 C43.7762017,8.25288717 43.742082,8.14401677 43.7466857,8.03329059 L44.0461638,0.830433986 Z\"\n        id=\"Path\"\n        fill=\"#FFFFFF\"\n      />\n    </g>\n  </svg>\n);\n"
  },
  {
    "path": "code/core/src/components/brand/StorybookLogo.stories.tsx",
    "content": "import React from 'react';\n\nimport { StorybookLogo } from './StorybookLogo.tsx';\n\nexport default {\n  component: StorybookLogo,\n};\n\nexport const Normal = () => <StorybookLogo alt=\"Storybook logo\" />;\n"
  },
  {
    "path": "code/core/src/components/brand/StorybookLogo.tsx",
    "content": "import React from 'react';\n\ntype StorybookLogoProps = {\n  alt: string;\n} & React.SVGAttributes<SVGSVGElement>;\n\nexport const StorybookLogo = ({ alt, ...props }: StorybookLogoProps) => (\n  <svg width=\"200px\" height=\"40px\" viewBox=\"0 0 200 40\" {...props} role=\"img\">\n    {alt ? <title>{alt}</title> : null}\n    <defs>\n      <path\n        d=\"M1.2 36.9L0 3.9c0-1.1.8-2 1.9-2.1l28-1.8a2 2 0 0 1 2.2 1.9 2 2 0 0 1 0 .1v36a2 2 0 0 1-2 2 2 2 0 0 1-.1 0L3.2 38.8a2 2 0 0 1-2-2z\"\n        id=\"a\"\n      />\n    </defs>\n    <g fill=\"none\" fillRule=\"evenodd\">\n      <path\n        d=\"M53.3 31.7c-1.7 0-3.4-.3-5-.7-1.5-.5-2.8-1.1-3.9-2l1.6-3.5c2.2 1.5 4.6 2.3 7.3 2.3 1.5 0 2.5-.2 3.3-.7.7-.5 1.1-1 1.1-1.9 0-.7-.3-1.3-1-1.7s-2-.8-3.7-1.2c-2-.4-3.6-.9-4.8-1.5-1.1-.5-2-1.2-2.6-2-.5-1-.8-2-.8-3.2 0-1.4.4-2.6 1.2-3.6.7-1.1 1.8-2 3.2-2.6 1.3-.6 2.9-.9 4.7-.9 1.6 0 3.1.3 4.6.7 1.5.5 2.7 1.1 3.5 2l-1.6 3.5c-2-1.5-4.2-2.3-6.5-2.3-1.3 0-2.3.2-3 .8-.8.5-1.2 1.1-1.2 2 0 .5.2 1 .5 1.3.2.3.7.6 1.4.9l2.9.8c2.9.6 5 1.4 6.2 2.4a5 5 0 0 1 2 4.2 6 6 0 0 1-2.5 5c-1.7 1.2-4 1.9-7 1.9zm21-3.6l1.4-.1-.2 3.5-1.9.1c-2.4 0-4.1-.5-5.2-1.5-1.1-1-1.6-2.7-1.6-4.8v-6h-3v-3.6h3V11h4.8v4.6h4v3.6h-4v6c0 1.8.9 2.8 2.6 2.8zm11.1 3.5c-1.6 0-3-.3-4.3-1a7 7 0 0 1-3-2.8c-.6-1.3-1-2.7-1-4.4 0-1.6.4-3 1-4.3a7 7 0 0 1 3-2.8c1.2-.7 2.7-1 4.3-1 1.7 0 3.2.3 4.4 1a7 7 0 0 1 3 2.8c.6 1.2 1 2.7 1 4.3 0 1.7-.4 3.1-1 4.4a7 7 0 0 1-3 2.8c-1.2.7-2.7 1-4.4 1zm0-3.6c2.4 0 3.6-1.6 3.6-4.6 0-1.5-.3-2.6-1-3.4a3.2 3.2 0 0 0-2.6-1c-2.3 0-3.5 1.4-3.5 4.4 0 3 1.2 4.6 3.5 4.6zm21.7-8.8l-2.7.3c-1.3.2-2.3.5-2.8 1.2-.6.6-.9 1.4-.9 2.5v8.2H96V15.7h4.6v2.6c.8-1.8 2.5-2.8 5-3h1.3l.3 4zm14-3.5h4.8L116.4 37h-4.9l3-6.6-6.4-14.8h5l4 10 4-10zm16-.4c1.4 0 2.6.3 3.6 1 1 .6 1.9 1.6 2.5 2.8.6 1.2.9 2.7.9 4.3 0 1.6-.3 3-1 4.3a6.9 6.9 0 0 1-2.4 2.9c-1 .7-2.2 1-3.6 1-1 0-2-.2-3-.7-.8-.4-1.5-1-2-1.9v2.4h-4.7V8.8h4.8v9c.5-.8 1.2-1.4 2-1.9.9-.4 1.8-.6 3-.6zM135.7 28c1.1 0 2-.4 2.6-1.2.6-.8 1-2 1-3.4 0-1.5-.4-2.5-1-3.3s-1.5-1.1-2.6-1.1-2 .3-2.6 1.1c-.6.8-1 2-1 3.3 0 1.5.4 2.6 1 3.4.6.8 1.5 1.2 2.6 1.2zm18.9 3.6c-1.7 0-3.2-.3-4.4-1a7 7 0 0 1-3-2.8c-.6-1.3-1-2.7-1-4.4 0-1.6.4-3 1-4.3a7 7 0 0 1 3-2.8c1.2-.7 2.7-1 4.4-1 1.6 0 3 .3 4.3 1a7 7 0 0 1 3 2.8c.6 1.2 1 2.7 1 4.3 0 1.7-.4 3.1-1 4.4a7 7 0 0 1-3 2.8c-1.2.7-2.7 1-4.3 1zm0-3.6c2.3 0 3.5-1.6 3.5-4.6 0-1.5-.3-2.6-1-3.4a3.2 3.2 0 0 0-2.5-1c-2.4 0-3.6 1.4-3.6 4.4 0 3 1.2 4.6 3.6 4.6zm18 3.6c-1.7 0-3.2-.3-4.4-1a7 7 0 0 1-3-2.8c-.6-1.3-1-2.7-1-4.4 0-1.6.4-3 1-4.3a7 7 0 0 1 3-2.8c1.2-.7 2.7-1 4.4-1 1.6 0 3 .3 4.4 1a7 7 0 0 1 2.9 2.8c.6 1.2 1 2.7 1 4.3 0 1.7-.4 3.1-1 4.4a7 7 0 0 1-3 2.8c-1.2.7-2.7 1-4.3 1zm0-3.6c2.3 0 3.5-1.6 3.5-4.6 0-1.5-.3-2.6-1-3.4a3.2 3.2 0 0 0-2.5-1c-2.4 0-3.6 1.4-3.6 4.4 0 3 1.2 4.6 3.6 4.6zm27.4 3.4h-6l-6-7v7h-4.8V8.8h4.9v13.6l5.8-6.7h5.7l-6.6 7.5 7 8.2z\"\n        fill=\"currentColor\"\n      />\n      <mask id=\"b\" fill=\"#fff\">\n        <use xlinkHref=\"#a\" />\n      </mask>\n      <use fill=\"#FF4785\" fillRule=\"nonzero\" xlinkHref=\"#a\" />\n      <path\n        d=\"M23.7 5L24 .2l3.9-.3.1 4.8a.3.3 0 0 1-.5.2L26 3.8l-1.7 1.4a.3.3 0 0 1-.5-.3zm-5 10c0 .9 5.3.5 6 0 0-5.4-2.8-8.2-8-8.2-5.3 0-8.2 2.8-8.2 7.1 0 7.4 10 7.6 10 11.6 0 1.2-.5 1.9-1.8 1.9-1.6 0-2.2-.9-2.1-3.6 0-.6-6.1-.8-6.3 0-.5 6.7 3.7 8.6 8.5 8.6 4.6 0 8.3-2.5 8.3-7 0-7.9-10.2-7.7-10.2-11.6 0-1.6 1.2-1.8 2-1.8.6 0 2 0 1.9 3z\"\n        fill=\"#FFF\"\n        fillRule=\"nonzero\"\n        mask=\"url(#b)\"\n      />\n    </g>\n  </svg>\n);\n"
  },
  {
    "path": "code/core/src/components/brand/colorpalette.mdx",
    "content": "import { Meta, ColorPalette, ColorItem } from '@storybook/addon-docs/blocks';\n\nimport { themes, ThemeProvider, convert, ensure } from 'storybook/theming';\n\nimport { SideBySide } from './SideBySide';\n\n<Meta title=\"ColorPalette\" />\n\n<SideBySide>\n  <div style={{background: '#202020' }}>\n<ThemeProvider theme={ensure(themes.dark)}>\n\nDark theme Colors\n\n<ColorPalette>\n  {Object.entries(convert(themes.dark).color).map(([k, v]) => {\n    if (typeof v === 'string' && (v.match(/^#/) || v.match(/^rgb/) || k.match(/color/i))) {\n      return <ColorItem key={k} title={k} colors={{ [k]: v }} />;\n    } else if (typeof v === 'object') {\n      return (\n        <ColorItem\n          key={k}\n          title={k}\n          colors={Object.entries(v).reduce(\n            (acc, [key, value]) =>\n              typeof value === 'string' &&\n              (value.match(/^#/) || value.match(/^rgb/) || key.match(/color/i))\n                ? { ...acc, [key]: value }\n                : acc,\n            {}\n          )}\n        />\n      );\n    }\n    return null;\n  })}\n</ColorPalette>\n\nDark theme Backgrounds\n\n<ColorPalette>\n  {Object.entries(convert(themes.dark).background).map(([k,v]) => {\n    if(k === 'color'){\n      return null\n    }\n    if (typeof v === 'string' && (v.match(/^#/) || v.match(/^rgb/) || k.match(/color/i))) {\n      return (\n        <ColorItem\n          key={k}\n          title={k}\n          colors={{ [k]: v }}\n        />\n      );\n    } else if (typeof v === 'object') {\n      const colors = Object.entries(v).reduce((acc, [key, value]) => (typeof value === 'string' && (value.match(/^#/) || value.match(/^rgb/) || key.match(/color/i))) ? {...acc, [key]: value} : acc, {});\n      return (\n        <ColorItem\n          key={k}\n          title={k}\n          colors={colors}\n        />\n      );\n    }\n    return null;\n  })}\n</ColorPalette>\n  </ThemeProvider></div>\n  <div styles={{ background: '#eeeeee'}}>\n\nLight theme Colors\n\n<ColorPalette>\n  {Object.entries(convert(themes.light).color).map(([k, v]) => {\n    if (typeof v === 'string' && (v.match(/^#/) || v.match(/^rgb/) || k.match(/color/i))) {\n      return <ColorItem key={k} title={k} colors={{ [k]: v }} />;\n    } else if (typeof v === 'object') {\n      return (\n        <ColorItem\n          key={k}\n          title={k}\n          colors={Object.entries(v).reduce(\n            (acc, [key, value]) =>\n              typeof value === 'string' &&\n              (value.match(/^#/) || value.match(/^rgb/) || key.match(/color/i))\n                ? { ...acc, [key]: value }\n                : acc,\n            {}\n          )}\n        />\n      );\n    }\n    return null;\n  })}\n</ColorPalette>\n\nLight theme Backgrounds\n\n<ColorPalette>\n  {Object.entries(convert(themes.light).background).map(([k,v]) => {\n    if(k === 'color'){\n      return null\n    }\n    if (typeof v === 'string' && (v.match(/^#/) || v.match(/^rgb/) || k.match(/color/i))) {\n      return (\n        <ColorItem\n          key={k}\n          title={k}\n          colors={{ [k]: v }}\n        />\n      );\n    } else if (typeof v === 'object') {\n      const colors = Object.entries(v).reduce((acc, [key, value]) => (typeof value === 'string' && (value.match(/^#/) || value.match(/^rgb/) || key.match(/color/i))) ? {...acc, [key]: value} : acc, {});\n      return (\n        <ColorItem\n          key={k}\n          title={k}\n          colors={colors}\n        />\n      );\n    }\n    return null;\n  })}\n</ColorPalette>\n  </div>\n</SideBySide>\n"
  },
  {
    "path": "code/core/src/components/brand/typography.mdx",
    "content": "import { typography } from 'storybook/theming';\nimport { Meta, Typeset } from '@storybook/addon-docs/blocks';\n\nexport const fontSizes = ['l3', 'l2', 'l1', 'm3', 'm2', 'm1', 's3', 's2', 's1'].map(\n  (size) => `${typography.size[size]}px`\n);\n\nexport const sampleText =\n  'Storybook is an open source tool for building UI components and pages in isolation. It streamlines UI development, testing, and documentation.';\n\n<Meta title=\"Typography\" />\n\n## Sans-serif\n\n```\nfont-family:\n  \"Nunito Sans\",\n  -apple-system,\n  \".SFNSText-Regular\",\n  \"San Francisco\",\n  BlinkMacSystemFont,\n  \"Segoe UI\",\n  \"Helvetica Neue\",\n  Helvetica,\n  Arial,\n  sans-serif;\n```\n\n<Typeset\n  fontFamily={typography.fonts.base}\n  fontSizes={fontSizes}\n  fontWeight={typography.weight.regular}\n  sampleText={sampleText}\n/>\n<Typeset\n  fontFamily={typography.fonts.base}\n  fontSizes={fontSizes}\n  fontWeight={typography.weight.bold}\n  sampleText={sampleText}\n/>\n<Typeset\n  fontFamily={typography.fonts.base}\n  fontSizes={fontSizes}\n  fontWeight={typography.weight.bold}\n  sampleText={sampleText}\n/>\n\n## Monospace\n\n```\nfont-family:\n  ui-monospace,\n  Menlo,\n  Monaco,\n  \"Roboto Mono\",\n  \"Oxygen Mono\",\n  \"Ubuntu Monospace\",\n  \"Source Code Pro\",\n  \"Droid Sans Mono\",\n  \"Courier New\",\n  monospace;\n```\n\n<Typeset\n  fontFamily={typography.fonts.mono}\n  fontSizes={fontSizes}\n  fontWeight={typography.weight.regular}\n  sampleText={sampleText}\n/>\n<Typeset\n  fontFamily={typography.fonts.mono}\n  fontSizes={fontSizes}\n  fontWeight={typography.weight.bold}\n  sampleText={sampleText}\n/>\n"
  },
  {
    "path": "code/core/src/components/components/ActionBar/ActionBar.stories.tsx",
    "content": "import type { ReactNode } from 'react';\nimport React from 'react';\n\nimport { action } from 'storybook/actions';\n\nimport { ActionBar } from './ActionBar.tsx';\n\nconst action1 = action('action1');\nconst action2 = action('action2');\nconst action3 = action('action3');\n\nexport default {\n  component: ActionBar,\n  decorators: [\n    (storyFn: () => ReactNode) => (\n      <div\n        style={{\n          position: 'relative',\n          width: '300px',\n          height: '64px',\n          margin: '1rem',\n          background: 'papayawhip',\n          border: '1px solid rgba(0,0,0,.05)',\n        }}\n      >\n        {storyFn()}\n      </div>\n    ),\n  ],\n};\n\nexport const SingleItem = () => <ActionBar actionItems={[{ title: 'Clear', onClick: action1 }]} />;\n\nexport const ManyItems = () => (\n  <ActionBar\n    actionItems={[\n      { title: 'Action string', onClick: action1 },\n      { title: <div>Action node</div>, onClick: action2 },\n      { title: 'Long action string', className: 'long-action-button', onClick: action3 },\n    ]}\n  />\n);\n"
  },
  {
    "path": "code/core/src/components/components/ActionBar/ActionBar.tsx",
    "content": "import type { MouseEvent, ReactElement } from 'react';\nimport React from 'react';\n\nimport { styled } from 'storybook/theming';\n\nconst Container = styled.div<{ $flexLayout?: boolean }>(({ theme, $flexLayout = false }) => [\n  {\n    background: theme.background.content,\n  },\n  $flexLayout\n    ? {\n        display: 'inline-flex',\n        marginInlineStart: 'auto',\n        alignSelf: 'flex-end',\n      }\n    : {\n        position: 'absolute',\n        bottom: 0,\n        right: 0,\n        maxWidth: '100%',\n        display: 'flex',\n        zIndex: 1,\n      },\n]);\n\nexport const ActionButton = styled.button<{ disabled: boolean }>(\n  ({ theme }) => ({\n    margin: 0,\n    border: '0 none',\n    padding: '4px 10px',\n    cursor: 'pointer',\n    display: 'flex',\n    alignItems: 'center',\n\n    color: theme.color.defaultText,\n    background: theme.background.content,\n\n    fontSize: 12,\n    lineHeight: '16px',\n    fontFamily: theme.typography.fonts.base,\n    fontWeight: theme.typography.weight.bold,\n\n    borderTop: `1px solid ${theme.appBorderColor}`,\n    borderLeft: `1px solid ${theme.appBorderColor}`,\n    marginLeft: -1,\n\n    borderRadius: `4px 0 0 0`,\n\n    '&:not(:last-child)': { borderRight: `1px solid ${theme.appBorderColor}` },\n    '& + *': {\n      borderLeft: `1px solid ${theme.appBorderColor}`,\n      borderRadius: 0,\n    },\n\n    '&:focus': {\n      boxShadow: `${theme.color.secondary} 0 -3px 0 0 inset`,\n      outline: '0 none',\n\n      '@media (forced-colors: active)': {\n        outline: '1px solid highlight',\n      },\n    },\n  }),\n  ({ disabled }) =>\n    disabled && {\n      cursor: 'not-allowed',\n      opacity: 0.5,\n    }\n);\nActionButton.displayName = 'ActionButton';\n\nexport interface ActionItem {\n  title: string | ReactElement;\n  className?: string;\n  onClick: (e: MouseEvent<HTMLButtonElement>) => void;\n  disabled?: boolean;\n}\n\nexport interface ActionBarProps {\n  /** Items to render in this ActionBar. */\n  actionItems: ActionItem[];\n  /**\n   * When true, ActionBar aligns to the flex end and inline end of a wrapping row flex container.\n   * When false, ActionBar is positioned absolutely at the bottom right of its relative parent.\n   */\n  flexLayout?: boolean;\n}\n\nexport const ActionBar = ({ actionItems, flexLayout = false, ...props }: ActionBarProps) => {\n  return (\n    <Container {...props} $flexLayout={flexLayout}>\n      {actionItems.map(({ title, className, onClick, disabled }, index: number) => (\n        <ActionButton key={index} className={className} onClick={onClick} disabled={!!disabled}>\n          {title}\n        </ActionButton>\n      ))}\n    </Container>\n  );\n};\n"
  },
  {
    "path": "code/core/src/components/components/ActionList/ActionList.stories.tsx",
    "content": "import { CheckIcon, EllipsisIcon, PlayAllHollowIcon } from '@storybook/icons';\n\nimport { Badge, Form, ProgressSpinner } from '../../index.ts';\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { Shortcut } from '../../../manager/components/Shortcut.tsx';\nimport { ActionList } from './ActionList.tsx';\n\nconst meta = preview.meta({\n  component: ActionList,\n  decorators: [(Story) => <div style={{ width: 250, border: '1px solid silver' }}>{Story()}</div>],\n});\n\nexport default meta;\n\nexport const Default = meta.story({\n  render: () => (\n    <ActionList>\n      <ActionList.Item>\n        <ActionList.Text>Text item</ActionList.Text>\n        <ActionList.Button ariaLabel=\"Options\">\n          <EllipsisIcon />\n        </ActionList.Button>\n      </ActionList.Item>\n      <ActionList.Item>\n        <ActionList.Action>Action item</ActionList.Action>\n        <ActionList.Button>\n          <PlayAllHollowIcon />\n          Cool\n        </ActionList.Button>\n      </ActionList.Item>\n      <ActionList.HoverItem targetId=\"some-action\">\n        <ActionList.Action>Hover action</ActionList.Action>\n        <ActionList.Button data-target-id=\"some-action\">\n          <PlayAllHollowIcon />\n          Cool\n        </ActionList.Button>\n      </ActionList.HoverItem>\n      <ActionList.Item>\n        <ActionList.Text>With a button</ActionList.Text>\n        <ActionList.Button variant=\"solid\">Go</ActionList.Button>\n      </ActionList.Item>\n      <ActionList.Item>\n        <ActionList.Action>\n          With an inline button\n          <ActionList.Button as=\"div\" readOnly padding=\"none\">\n            <ProgressSpinner percentage={25} running={false} size={16} width={1.5} />\n            25%\n          </ActionList.Button>\n        </ActionList.Action>\n      </ActionList.Item>\n      <ActionList.Item>\n        <ActionList.Action>\n          With a badge\n          <Badge status=\"positive\">Check it out</Badge>\n        </ActionList.Action>\n      </ActionList.Item>\n      <ActionList.Item>\n        <ActionList.Action as=\"label\">\n          <Form.Checkbox />\n          <ActionList.Text>With a checkbox</ActionList.Text>\n        </ActionList.Action>\n      </ActionList.Item>\n      <ActionList.Item active>\n        <ActionList.Action>\n          <ActionList.Icon>\n            <CheckIcon />\n          </ActionList.Icon>\n          <ActionList.Text>Active with an icon</ActionList.Text>\n          <Shortcut keys={['⌘', 'A']} />\n        </ActionList.Action>\n      </ActionList.Item>\n      <ActionList.Item>\n        <ActionList.Text>\n          Some very long text which will wrap when the container is too narrow\n        </ActionList.Text>\n      </ActionList.Item>\n      <ActionList.Item>\n        <ActionList.Text>\n          <span>Some very long text which will ellipsize when the container is too narrow</span>\n        </ActionList.Text>\n      </ActionList.Item>\n      <ActionList.Item>\n        <ActionList.Action>\n          <ActionList.Icon>\n            <CheckIcon />\n          </ActionList.Icon>\n          <ActionList.Text>\n            <p>Title</p>\n            <small>Description</small>\n          </ActionList.Text>\n        </ActionList.Action>\n      </ActionList.Item>\n      <ActionList.Item active>\n        <ActionList.Action>\n          <ActionList.Icon>\n            <CheckIcon />\n          </ActionList.Icon>\n          <ActionList.Text>\n            <p>Some very long text which is going to wrap around</p>\n            <small>Here is a very long description which is also going to wrap around</small>\n          </ActionList.Text>\n        </ActionList.Action>\n      </ActionList.Item>\n    </ActionList>\n  ),\n});\n\nexport const Listbox = meta.story({\n  render: () => (\n    <>\n      <ActionList role=\"listbox\" aria-label=\"Sample listbox\">\n        <ActionList.Item role=\"option\">\n          <ActionList.Icon>\n            <CheckIcon />\n          </ActionList.Icon>\n          <ActionList.Text>Option</ActionList.Text>\n        </ActionList.Item>\n        <ActionList.Item role=\"option\" aria-selected=\"true\">\n          <ActionList.Icon>\n            <CheckIcon />\n          </ActionList.Icon>\n          <ActionList.Text>Selected</ActionList.Text>\n        </ActionList.Item>\n        <ActionList.Item role=\"option\" aria-disabled=\"true\">\n          <ActionList.Icon>\n            <CheckIcon />\n          </ActionList.Icon>\n          <ActionList.Text>Visually disabled</ActionList.Text>\n        </ActionList.Item>\n      </ActionList>\n    </>\n  ),\n});\n\nexport const Groups = meta.story({\n  render: () => (\n    <>\n      <ActionList>\n        <ActionList.Item>\n          <ActionList.Action>Alpha</ActionList.Action>\n        </ActionList.Item>\n        <ActionList.Item>\n          <ActionList.Action>Item</ActionList.Action>\n        </ActionList.Item>\n      </ActionList>\n      <ActionList>\n        <ActionList.Item>\n          <ActionList.Action>Bravo</ActionList.Action>\n        </ActionList.Item>\n        <ActionList.Item>\n          <ActionList.Action>Item</ActionList.Action>\n        </ActionList.Item>\n      </ActionList>\n      <ActionList>\n        <ActionList.Item>\n          <ActionList.Action>Charlie</ActionList.Action>\n        </ActionList.Item>\n        <ActionList.Item>\n          <ActionList.Action>Item</ActionList.Action>\n        </ActionList.Item>\n      </ActionList>\n    </>\n  ),\n});\n"
  },
  {
    "path": "code/core/src/components/components/ActionList/ActionList.tsx",
    "content": "import React, { type ComponentProps, forwardRef } from 'react';\n\nimport { darken, transparentize } from 'polished';\nimport type { TransitionStatus } from 'react-transition-state';\nimport { styled } from 'storybook/theming';\n\nimport { Button } from '../Button/Button.tsx';\nimport { ToggleButton } from '../ToggleButton/ToggleButton.tsx';\n\nconst ActionListItem = styled.li<{\n  active?: boolean;\n  transitionStatus?: TransitionStatus;\n}>(\n  ({ active, theme }) => ({\n    display: 'flex',\n    alignItems: 'center',\n    justifyContent: 'space-between',\n    flex: '0 0 auto',\n    overflow: 'hidden',\n    minHeight: 32,\n    gap: 4,\n\n    fontSize: theme.typography.size.s1,\n    fontWeight: active ? theme.typography.weight.bold : theme.typography.weight.regular,\n    color: active ? 'var(--listbox-item-active-color)' : theme.color.defaultText,\n    '--listbox-item-active-color':\n      theme.base === 'light' ? darken(0.1, theme.color.secondary) : theme.color.secondary,\n    '--listbox-item-muted-color': active\n      ? 'var(--listbox-item-active-color)'\n      : theme.color.mediumdark,\n\n    '&[aria-disabled=\"true\"]': {\n      opacity: 0.5,\n      cursor: 'not-allowed',\n    },\n    '&[aria-selected=\"true\"]': {\n      color: 'var(--listbox-item-active-color)',\n      fontWeight: theme.typography.weight.bold,\n      '--listbox-item-muted-color': 'var(--listbox-item-active-color)',\n    },\n\n    '&:not(:hover, :has(:focus-visible)) :not(input) + input': {\n      position: 'absolute',\n      opacity: 0,\n    },\n\n    '&[role=\"option\"]': {\n      cursor: 'pointer',\n      borderRadius: theme.input.borderRadius,\n      outlineOffset: -2,\n      padding: '0 9px',\n      gap: 8,\n\n      '&:hover': {\n        background: transparentize(0.86, theme.color.secondary),\n      },\n      '&:focus-visible': {\n        outline: `2px solid ${theme.color.secondary}`,\n      },\n    },\n\n    '@supports (interpolate-size: allow-keywords)': {\n      interpolateSize: 'allow-keywords',\n      transitionBehavior: 'allow-discrete',\n      transitionDuration: 'var(--transition-duration, 0.2s)',\n      transitionProperty: 'opacity, block-size, content-visibility',\n    },\n\n    '@media (prefers-reduced-motion: reduce)': {\n      transition: 'none',\n    },\n  }),\n  ({ transitionStatus }) => {\n    switch (transitionStatus) {\n      case 'preEnter':\n      case 'exiting':\n      case 'exited':\n        return {\n          opacity: 0,\n          blockSize: 0,\n          contentVisibility: 'hidden',\n        };\n      default:\n        return {\n          opacity: 1,\n          blockSize: 'auto',\n          contentVisibility: 'visible',\n        };\n    }\n  }\n);\n\n/**\n * A ActionList item that shows/hides child elements on hover based on the targetId. Child elements\n * must have a `data-target-id` attribute matching the `targetId` prop to be affected by the hover\n * behavior.\n */\nconst ActionListHoverItem = styled(ActionListItem)<{ targetId: string }>(({ targetId }) => ({\n  gap: 0,\n  [`& [data-target-id=\"${targetId}\"]`]: {\n    inlineSize: 'auto',\n    marginLeft: 4,\n    opacity: 1,\n    '@supports (interpolate-size: allow-keywords)': {\n      interpolateSize: 'allow-keywords',\n      transitionProperty: 'inline-size, margin-left, opacity, padding-inline',\n      transitionDuration: 'var(--transition-duration, 0.2s)',\n    },\n  },\n  [`&:not(:hover, :has(:focus-visible)) [data-target-id=\"${targetId}\"]`]: {\n    inlineSize: 0,\n    marginLeft: 0,\n    opacity: 0,\n    paddingInline: 0,\n  },\n}));\n\nconst StyledButton = styled(Button)(({ size }) => ({\n  gap: size === 'small' ? 6 : 8,\n\n  '&:focus-visible': {\n    // Prevent focus outline from being cut off by overflow: hidden\n    outlineOffset: -2,\n  },\n}));\n\nconst StyledToggleButton = styled(ToggleButton)({\n  '&:focus-visible': {\n    // Prevent focus outline from being cut off by overflow: hidden\n    outlineOffset: -2,\n  },\n});\n\nconst ActionListButton = forwardRef<HTMLButtonElement, ComponentProps<typeof StyledButton>>(\n  function ActionListButton(\n    { padding = 'small', size = 'medium', variant = 'ghost', ...props },\n    ref\n  ) {\n    return <StyledButton {...{ ...props, variant, padding, size, ref }} />;\n  }\n);\n\nconst ActionListToggle = forwardRef<HTMLButtonElement, ComponentProps<typeof StyledToggleButton>>(\n  function ActionListToggle(\n    { padding = 'small', size = 'medium', variant = 'ghost', ...props },\n    ref\n  ) {\n    return <StyledToggleButton {...{ ...props, variant, padding, size, ref }} />;\n  }\n);\n\nconst ActionListAction = styled(ActionListButton)(({ theme }) => ({\n  height: 'auto',\n  minHeight: 32,\n  flex: '0 1 100%',\n  textAlign: 'start',\n  justifyContent: 'space-between',\n  fontWeight: 'inherit',\n  color: 'inherit',\n  '&:hover': {\n    color: 'inherit',\n  },\n  '& input:enabled:focus-visible': {\n    outline: 'none',\n  },\n  '&:has(input:focus-visible)': {\n    outline: `2px solid ${theme.color.secondary}`,\n    outlineOffset: -2,\n  },\n}));\n\nconst ActionListLink = (\n  props: ComponentProps<typeof ActionListAction> & React.AnchorHTMLAttributes<HTMLAnchorElement>\n) => <ActionListAction as=\"a\" {...props} />;\n\nconst ActionListText = styled.div(({ theme }) => ({\n  display: 'flex',\n  flexDirection: 'column',\n  justifyContent: 'center',\n  flexGrow: 1,\n  minWidth: 0,\n  padding: '8px 0',\n  lineHeight: '16px',\n\n  '& > *': {\n    margin: 0,\n    whiteSpace: 'normal',\n  },\n  '& > span': {\n    overflow: 'hidden',\n    textOverflow: 'ellipsis',\n    whiteSpace: 'nowrap',\n  },\n  '& small': {\n    fontSize: 'inherit',\n    color: theme.textMutedColor,\n  },\n  '&:first-child': {\n    paddingLeft: 8,\n  },\n  '&:last-child': {\n    paddingRight: 8,\n  },\n  'button > &:first-child, [role=\"option\"] > &:first-child': {\n    paddingLeft: 0,\n  },\n  'button > &:last-child, [role=\"option\"] > &:last-child': {\n    paddingRight: 0,\n  },\n}));\n\nconst ActionListIcon = styled.div({\n  display: 'flex',\n  alignItems: 'center',\n  justifyContent: 'center',\n  flex: '0 0 14px',\n  width: 14,\n  height: 14,\n  color: 'var(--listbox-item-muted-color)',\n});\n\nexport const ActionList = Object.assign(\n  styled.ul(({ theme, onClick }) => ({\n    listStyle: 'none',\n    margin: 0,\n    padding: 4,\n    cursor: onClick ? 'pointer' : 'default',\n\n    '& + *': {\n      borderTop: `1px solid ${theme.appBorderColor}`,\n    },\n  })),\n  {\n    Item: ActionListItem,\n    HoverItem: ActionListHoverItem,\n    Button: ActionListButton,\n    Toggle: ActionListToggle,\n    Action: ActionListAction,\n    Link: ActionListLink,\n    Text: ActionListText,\n    Icon: ActionListIcon,\n  }\n);\n"
  },
  {
    "path": "code/core/src/components/components/Badge/Badge.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Badge } from './Badge.tsx';\n\nconst meta = {\n  component: Badge,\n} satisfies Meta<typeof Badge>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Default = { args: { children: 'Default' } } satisfies Story;\nexport const Active = { args: { status: 'active', children: 'Active' } } satisfies Story;\nexport const Positive = { args: { status: 'positive', children: 'Positive' } } satisfies Story;\nexport const Negative = { args: { status: 'negative', children: 'Negative' } } satisfies Story;\nexport const Neutral = { args: { status: 'neutral', children: 'Neutral' } } satisfies Story;\nexport const Warning = { args: { status: 'warning', children: 'Warning' } } satisfies Story;\nexport const Critical = { args: { status: 'critical', children: 'Critical' } } satisfies Story;\n\nexport const Compact = {\n  args: { compact: true, status: 'neutral', children: '12' },\n} satisfies Story;\n"
  },
  {
    "path": "code/core/src/components/components/Badge/Badge.tsx",
    "content": "import React from 'react';\n\nimport { darken, transparentize } from 'polished';\nimport { styled } from 'storybook/theming';\n\nconst BadgeWrapper = styled.div<BadgeProps>(\n  ({ theme, compact }) => ({\n    display: 'inline-flex',\n    alignItems: 'center',\n    justifyContent: 'center',\n    fontSize: theme.typography.size.s1,\n    fontWeight: theme.typography.weight.bold,\n    lineHeight: '12px',\n    minWidth: 20,\n    borderRadius: 20,\n    padding: compact ? '4px 7px' : '4px 10px',\n  }),\n  {\n    svg: {\n      height: 12,\n      width: 12,\n      marginRight: 4,\n      marginTop: -2,\n\n      path: {\n        fill: 'currentColor',\n      },\n    },\n  },\n  ({ theme, status }) => {\n    switch (status) {\n      case 'critical': {\n        return {\n          color: theme.fgColor.critical,\n          background: theme.bgColor.critical,\n          boxShadow: `inset 0 0 0 1px ${theme.borderColor.critical}`,\n        };\n      }\n      case 'negative': {\n        return {\n          color: theme.fgColor.negative,\n          background: theme.bgColor.negative,\n          boxShadow: `inset 0 0 0 1px ${theme.borderColor.negative}`,\n        };\n      }\n      case 'warning': {\n        return {\n          color: theme.fgColor.warning,\n          background: theme.bgColor.warning,\n          boxShadow: `inset 0 0 0 1px ${theme.borderColor.warning}`,\n        };\n      }\n      case 'neutral': {\n        return {\n          color: theme.fgColor.muted,\n          background: theme.base === 'dark' ? theme.barBg : theme.background.app,\n          boxShadow: `inset 0 0 0 1px ${transparentize(0.8, theme.textMutedColor)}`,\n        };\n      }\n      case 'positive': {\n        return {\n          color: theme.fgColor.positive,\n          background: theme.bgColor.positive,\n          boxShadow: `inset 0 0 0 1px ${theme.borderColor.positive}`,\n        };\n      }\n      case 'active': {\n        return {\n          color:\n            theme.base === 'light' ? darken(0.1, theme.color.secondary) : theme.color.secondary,\n          background: theme.background.hoverable,\n          boxShadow: `inset 0 0 0 1px ${transparentize(0.9, theme.color.secondary)}`,\n        };\n      }\n      default: {\n        return {};\n      }\n    }\n  }\n);\n\nexport interface BadgeProps {\n  compact?: boolean;\n  status?: 'positive' | 'negative' | 'neutral' | 'warning' | 'critical' | 'active';\n  children?: React.ReactNode;\n}\n\nexport const Badge = ({ ...props }: BadgeProps) => {\n  return <BadgeWrapper {...props} />;\n};\n"
  },
  {
    "path": "code/core/src/components/components/Bar/Bar.stories.tsx",
    "content": "import React from 'react';\n\nimport { styled } from 'storybook/theming';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { Bar } from './Bar.tsx';\n\nconst Wrapper = styled.div(({ theme }) => ({\n  background: theme.background.app,\n  border: `1px solid ${theme.appBorderColor}`,\n  maxWidth: 500,\n  height: 200,\n}));\n\nconst meta = preview.meta({\n  component: Bar,\n  title: 'Bar/Bar',\n  decorators: [\n    (Story) => (\n      <Wrapper>\n        <Story />\n      </Wrapper>\n    ),\n  ],\n});\n\nexport default meta;\n\nconst LongContent = () =>\n  Array.from({ length: 12 }).map((_, i) => (\n    <div key={i} style={{ padding: '0 8px' }}>\n      Item {i + 1}\n    </div>\n  ));\n\nexport const Default = meta.story({ args: { children: 'Default' } });\n\nexport const Bordered = meta.story({\n  args: { border: true, children: 'Bar with border' },\n});\n\nexport const BackgroundBorderless = meta.story({\n  args: { backgroundColor: '#f3f4f6', border: false, children: 'Bar with custom background' },\n  globals: {\n    sb_theme: 'light',\n  },\n});\n\nexport const BackgroundBordered = meta.story({\n  args: { backgroundColor: '#f3f4f6', border: true, children: 'Bar with custom background' },\n  globals: {\n    sb_theme: 'light',\n  },\n});\n\nexport const NonScrollable = meta.story({\n  name: 'Non-scrollable',\n  args: {\n    children: 'Non-scrollable Bar',\n    scrollable: false,\n  },\n});\n\nexport const Scrollable = meta.story({\n  args: { scrollable: true, children: <LongContent /> },\n});\n\nexport const ScrollableBordered = meta.story({\n  name: 'Scrollable bordered',\n  args: {\n    border: true,\n    children: <LongContent />,\n    innerStyle: { justifyContent: 'start' },\n    scrollable: true,\n  },\n});\n\nexport const ScrollableBackground = meta.story({\n  name: 'Scrollable background',\n  args: {\n    backgroundColor: '#f3f4f6',\n    border: false,\n    children: <LongContent />,\n    innerStyle: { justifyContent: 'start' },\n    scrollable: true,\n  },\n  globals: {\n    sb_theme: 'light',\n  },\n});\n\nexport const ScrollableBackgroundBordered = meta.story({\n  name: 'Scrollable background bordered',\n  args: {\n    backgroundColor: '#f3f4f6',\n    border: true,\n    children: <LongContent />,\n    innerStyle: { justifyContent: 'start' },\n    scrollable: true,\n  },\n  globals: {\n    sb_theme: 'light',\n  },\n});\n\nexport const InnerStyleOverride = meta.story({\n  args: {\n    children: <div style={{ padding: '0 8px' }}>Custom inner style</div>,\n    innerStyle: { backgroundColor: '#fff7ed', gap: 12 },\n  },\n  globals: {\n    sb_theme: 'light',\n  },\n});\n"
  },
  {
    "path": "code/core/src/components/components/Bar/Bar.tsx",
    "content": "import React, { Children, forwardRef } from 'react';\n\nimport { deprecate } from 'storybook/internal/client-logger';\n\nimport { type CSSObject, styled } from 'storybook/theming';\n\nexport interface BarProps {\n  backgroundColor?: string;\n  border?: boolean;\n  className?: string;\n  children?: React.ReactNode;\n  scrollable?: boolean;\n  innerStyle?: CSSObject;\n}\n\nconst StyledBar = styled.div<BarProps>(\n  ({ backgroundColor, border = false, innerStyle = {}, scrollable, theme }) => ({\n    color: theme.barTextColor,\n    width: '100%',\n    minHeight: 40,\n    flexShrink: 0,\n    // TODO in Storybook 11: Apply background regardless of border.\n    scrollbarColor: `${theme.barTextColor} ${border ? backgroundColor || theme.barBg : 'transparent'}`,\n    scrollbarWidth: 'thin',\n    overflow: scrollable ? 'auto' : 'hidden',\n    overflowY: 'hidden',\n    display: 'flex',\n    alignItems: 'center',\n    gap: scrollable ? 0 : 6,\n    paddingInline: scrollable ? 0 : 6,\n    // TODO in Storybook 11: Apply background regardless of border.\n    ...(border\n      ? {\n          boxShadow: `${theme.appBorderColor}  0 -1px 0 0 inset`,\n          background: backgroundColor || theme.barBg,\n        }\n      : {}),\n    ...innerStyle,\n  })\n);\n\nconst HeightPreserver = styled.div<Pick<BarProps, 'innerStyle'>>(({ innerStyle }) => ({\n  minHeight: 40,\n  display: 'flex',\n  alignItems: 'center',\n  width: '100%',\n  gap: 6,\n  paddingInline: 6,\n  ...innerStyle,\n}));\n\nexport const Bar = forwardRef<HTMLDivElement, BarProps>(\n  ({ scrollable = true, children, innerStyle, ...rest }, ref) => {\n    return (\n      <StyledBar\n        {...rest}\n        ref={ref}\n        innerStyle={scrollable ? undefined : innerStyle}\n        scrollable={scrollable}\n      >\n        {scrollable ? (\n          <HeightPreserver innerStyle={innerStyle}>{children}</HeightPreserver>\n        ) : (\n          children\n        )}\n      </StyledBar>\n    );\n  }\n);\n\nBar.displayName = 'Bar';\n\nexport interface SideProps {\n  left?: boolean;\n  right?: boolean;\n  scrollable?: boolean;\n}\n\nexport const Side = styled.div<SideProps>(\n  {\n    display: 'flex',\n    whiteSpace: 'nowrap',\n    flexBasis: 'auto',\n    marginLeft: 3,\n    marginRight: 10,\n  },\n  ({ scrollable }) => (scrollable ? { flexShrink: 0 } : {}),\n  ({ left }) =>\n    left\n      ? {\n          '& > *': {\n            marginLeft: 4,\n          },\n        }\n      : {},\n  ({ right }) =>\n    right\n      ? {\n          gap: 6,\n        }\n      : {}\n);\nSide.displayName = 'Side';\n\ninterface BarInnerProps {\n  bgColor?: string;\n}\nconst BarInner = styled.div<BarInnerProps>(({ bgColor }) => ({\n  display: 'flex',\n  justifyContent: 'space-between',\n  position: 'relative',\n  flexWrap: 'nowrap',\n  flexShrink: 0,\n  height: 40,\n  width: '100%',\n  backgroundColor: bgColor || '',\n}));\n\nexport interface FlexBarProps extends BarProps {\n  border?: boolean;\n  backgroundColor?: string;\n}\n\n// Compensate new default inline padding for Bar to reduce the extent of visible changes in 10.1 for FlexBar users.\nconst BarWithoutPadding = styled(Bar)({\n  paddingInline: 0,\n});\n\nexport const FlexBar = ({ children, backgroundColor, className = '', ...rest }: FlexBarProps) => {\n  deprecate('FlexBar is deprecated. Use Bar with justifyContent: \"space-between\" instead.');\n  const [left, right] = Children.toArray(children);\n  return (\n    <BarWithoutPadding\n      data-deprecated=\"FlexBar\"\n      backgroundColor={backgroundColor}\n      className={`sb-bar ${className}`}\n      {...rest}\n    >\n      <BarInner bgColor={backgroundColor}>\n        <Side scrollable={rest.scrollable} left>\n          {left}\n        </Side>\n        {right ? <Side right>{right}</Side> : null}\n      </BarInner>\n    </BarWithoutPadding>\n  );\n};\nFlexBar.displayName = 'FlexBar';\n"
  },
  {
    "path": "code/core/src/components/components/Bar/FlexBar.stories.tsx",
    "content": "import React from 'react';\n\nimport { styled } from 'storybook/theming';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { FlexBar } from './Bar.tsx';\n\nconst meta = preview.meta({ component: FlexBar, title: 'Bar/FlexBar (deprecated)' });\n\nexport default meta;\n\nconst Row = styled.div({\n  display: 'flex',\n  alignItems: 'center',\n  gap: 4,\n});\n\nconst LongContent = () =>\n  Array.from({ length: 12 }).map((_, i) => (\n    <div key={i} style={{ padding: '0 8px' }}>\n      Item {i + 1}\n    </div>\n  ));\n\nexport const Default = meta.story({\n  render: (args) => (\n    <FlexBar {...args}>\n      <Row>Left content</Row>\n      <Row>Right content</Row>\n    </FlexBar>\n  ),\n});\n\nexport const OnlyLeft = meta.story({\n  render: (args) => (\n    <FlexBar {...args}>\n      <Row>Only left</Row>\n    </FlexBar>\n  ),\n});\n\nexport const OnlyRight = meta.story({\n  render: (args) => (\n    <FlexBar {...args}>\n      <Row></Row>\n      <Row>Only right</Row>\n    </FlexBar>\n  ),\n});\n\nexport const Background = meta.story({\n  args: {\n    backgroundColor: '#f3f4f6',\n  },\n  globals: {\n    sb_theme: 'light',\n  },\n  render: (args) => (\n    <FlexBar {...args}>\n      <Row>Left content</Row>\n      <Row>Right content</Row>\n    </FlexBar>\n  ),\n});\n\nexport const Border = meta.story({\n  args: {\n    border: true,\n  },\n  render: (args) => (\n    <FlexBar {...args}>\n      <Row>Left content</Row>\n      <Row>Right content</Row>\n    </FlexBar>\n  ),\n});\n\nexport const BackgroundBorder = meta.story({\n  args: {\n    backgroundColor: '#f3f4f6',\n    border: true,\n  },\n  globals: {\n    sb_theme: 'light',\n  },\n  render: (args) => (\n    <FlexBar {...args}>\n      <Row>Left content</Row>\n      <Row>Right content</Row>\n    </FlexBar>\n  ),\n});\n\nexport const ScrollableBackground = meta.story({\n  args: {\n    backgroundColor: '#f3f4f6',\n    scrollable: true,\n  },\n  globals: {\n    sb_theme: 'light',\n  },\n  render: (args) => (\n    <FlexBar {...args}>\n      <Row>\n        <LongContent />\n      </Row>\n      <Row>\n        <LongContent />\n      </Row>\n    </FlexBar>\n  ),\n});\n\nexport const ScrollableBorder = meta.story({\n  args: {\n    border: true,\n    scrollable: true,\n  },\n  render: (args) => (\n    <FlexBar {...args}>\n      <Row>\n        <LongContent />\n      </Row>\n      <Row>\n        <LongContent />\n      </Row>\n    </FlexBar>\n  ),\n});\n\nexport const ScrollableBackgroundBorder = meta.story({\n  args: {\n    backgroundColor: '#f3f4f6',\n    border: true,\n    scrollable: true,\n  },\n  globals: {\n    sb_theme: 'light',\n  },\n  render: (args) => (\n    <FlexBar {...args}>\n      <Row>\n        <LongContent />\n      </Row>\n      <Row>\n        <LongContent />\n      </Row>\n    </FlexBar>\n  ),\n});\n"
  },
  {
    "path": "code/core/src/components/components/Bar/Separator.tsx",
    "content": "import React, { Fragment } from 'react';\n\nimport { styled } from 'storybook/theming';\n\nexport interface SeparatorProps {\n  force?: boolean;\n}\n\nexport const Separator = styled.span<SeparatorProps>(\n  ({ theme }) => ({\n    display: 'inline-block',\n    width: 1,\n    height: 20,\n    background: theme.appBorderColor,\n    marginLeft: 2,\n    marginRight: 2,\n  }),\n  ({ force }) =>\n    force\n      ? {}\n      : {\n          '& + &': {\n            display: 'none',\n          },\n        }\n);\nSeparator.displayName = 'Separator';\n\nexport const interleaveSeparators = (list: any[]) =>\n  list.reduce(\n    (acc, item, index) =>\n      item ? (\n        <Fragment key={item.id || item.key || `f-${index}`}>\n          {acc}\n          {}\n          {index > 0 ? <Separator key={`s-${index}`} /> : null}\n          {item.render() || item}\n        </Fragment>\n      ) : (\n        acc\n      ),\n    null\n  );\n"
  },
  {
    "path": "code/core/src/components/components/Button/Button.stories.tsx",
    "content": "import React from 'react';\n\nimport { FaceHappyIcon } from '@storybook/icons';\n\nimport { expect, fn } from 'storybook/test';\nimport { styled } from 'storybook/theming';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { Button } from './Button.tsx';\n\nconst meta = preview.meta({\n  id: 'button-component',\n  title: 'Button',\n  component: Button,\n  args: { onClick: fn() },\n});\n\nconst Stack = styled.div({ display: 'flex', flexDirection: 'column', gap: '1rem' });\n\nconst Row = styled.div({ display: 'flex', alignItems: 'center', gap: '1rem' });\n\nexport const Base = meta.story({\n  args: { ariaLabel: false, children: 'Button' },\n});\n\n/** This is the variant most commonly used in a toolbar or when a button only contains an icon. */\nexport const IconButton = meta.story({\n  args: {\n    ariaLabel: 'Button',\n    children: <FaceHappyIcon />,\n    padding: 'small',\n    variant: 'ghost',\n  },\n});\n\nexport const Variants = meta.story({\n  args: { ariaLabel: false, children: 'Button' },\n  render: (args) => (\n    <Stack>\n      <Row>\n        <Button {...args} variant=\"solid\" ariaLabel={false}>\n          Solid\n        </Button>\n        <Button {...args} variant=\"outline\" ariaLabel={false}>\n          Outline\n        </Button>\n        <Button {...args} variant=\"ghost\" ariaLabel={false}>\n          Ghost\n        </Button>\n      </Row>\n      <Row>\n        <Button {...args} variant=\"solid\" ariaLabel={false}>\n          <FaceHappyIcon /> Solid\n        </Button>\n        <Button {...args} variant=\"outline\" ariaLabel={false}>\n          <FaceHappyIcon /> Outline\n        </Button>\n        <Button {...args} variant=\"ghost\" ariaLabel={false}>\n          <FaceHappyIcon /> Ghost\n        </Button>\n      </Row>\n      <Row>\n        <Button {...args} variant=\"solid\" padding=\"small\" ariaLabel=\"Button\">\n          <FaceHappyIcon />\n        </Button>\n        <Button {...args} variant=\"outline\" padding=\"small\" ariaLabel=\"Button\">\n          <FaceHappyIcon />\n        </Button>\n        <Button {...args} variant=\"ghost\" padding=\"small\" ariaLabel=\"Button\">\n          <FaceHappyIcon />\n        </Button>\n      </Row>\n    </Stack>\n  ),\n});\n\nexport const PseudoStates = meta.story({\n  render: () => (\n    <Stack>\n      <Row>\n        <Button ariaLabel={false} variant=\"solid\">\n          Button\n        </Button>\n        <Button ariaLabel={false} variant=\"outline\">\n          Button\n        </Button>\n        <Button ariaLabel={false} variant=\"ghost\">\n          Button\n        </Button>\n      </Row>\n      <Row id=\"hover\">\n        <Button ariaLabel={false} variant=\"solid\">\n          Hover\n        </Button>\n        <Button ariaLabel={false} variant=\"outline\">\n          Hover\n        </Button>\n        <Button ariaLabel={false} variant=\"ghost\">\n          Hover\n        </Button>\n      </Row>\n      <Row id=\"active\">\n        <Button ariaLabel={false} variant=\"solid\">\n          Active\n        </Button>\n        <Button ariaLabel={false} variant=\"outline\">\n          Active\n        </Button>\n        <Button ariaLabel={false} variant=\"ghost\">\n          Active\n        </Button>\n      </Row>\n      <Row id=\"focus\">\n        <Button ariaLabel={false} variant=\"solid\">\n          Focus\n        </Button>\n        <Button ariaLabel={false} variant=\"outline\">\n          Focus\n        </Button>\n        <Button ariaLabel={false} variant=\"ghost\">\n          Focus\n        </Button>\n      </Row>\n      <Row id=\"focus-visible\">\n        <Button ariaLabel={false} variant=\"solid\">\n          Focus Visible\n        </Button>\n        <Button ariaLabel={false} variant=\"outline\">\n          Focus Visible\n        </Button>\n        <Button ariaLabel={false} variant=\"ghost\">\n          Focus Visible\n        </Button>\n      </Row>\n    </Stack>\n  ),\n  parameters: {\n    pseudo: {\n      hover: '#hover button',\n      active: '#active button',\n      focus: '#focus button',\n      focusVisible: '#focus-visible button',\n    },\n  },\n});\n\nexport const Active = meta.story({\n  name: 'Active (deprecated)',\n  args: { ariaLabel: false, active: true },\n  render: (args) => (\n    <Stack>\n      <Row>\n        <Button {...args} variant=\"solid\">\n          Button\n        </Button>\n        <Button {...args} variant=\"outline\">\n          Button\n        </Button>\n        <Button {...args} variant=\"ghost\">\n          Button\n        </Button>\n      </Row>\n      <Row id=\"hover\">\n        <Button {...args} variant=\"solid\">\n          Hover\n        </Button>\n        <Button {...args} variant=\"outline\">\n          Hover\n        </Button>\n        <Button {...args} variant=\"ghost\">\n          Hover\n        </Button>\n      </Row>\n      <Row id=\"active\">\n        <Button {...args} variant=\"solid\">\n          active\n        </Button>\n        <Button {...args} variant=\"outline\">\n          active\n        </Button>\n        <Button {...args} variant=\"ghost\">\n          active\n        </Button>\n      </Row>\n      <Row id=\"focus\">\n        <Button {...args} variant=\"solid\">\n          Focus\n        </Button>\n        <Button {...args} variant=\"outline\">\n          Focus\n        </Button>\n        <Button {...args} variant=\"ghost\">\n          Focus\n        </Button>\n      </Row>\n      <Row id=\"focus-visible\">\n        <Button {...args} variant=\"solid\">\n          Focus Visible\n        </Button>\n        <Button {...args} variant=\"outline\">\n          Focus Visible\n        </Button>\n        <Button {...args} variant=\"ghost\">\n          Focus Visible\n        </Button>\n      </Row>\n    </Stack>\n  ),\n  parameters: {\n    pseudo: {\n      hover: '#hover button',\n      active: '#active button',\n      focus: '#focus button',\n      focusVisible: '#focus-visible button',\n    },\n  },\n});\n\nexport const WithIcon = meta.story({\n  args: {\n    ariaLabel: false,\n    children: (\n      <>\n        <FaceHappyIcon />\n        Button\n      </>\n    ),\n  },\n  render: (args) => (\n    <Row>\n      <Button variant=\"solid\" {...args} />\n      <Button variant=\"outline\" {...args} />\n      <Button variant=\"ghost\" {...args} />\n    </Row>\n  ),\n});\n\nexport const IconOnly = meta.story({\n  args: {\n    ariaLabel: 'Button',\n    children: <FaceHappyIcon />,\n    padding: 'small',\n  },\n  render: (args) => (\n    <Row>\n      <Button variant=\"solid\" {...args} />\n      <Button variant=\"outline\" {...args} />\n      <Button variant=\"ghost\" {...args} />\n    </Row>\n  ),\n});\n\nexport const Sizes = meta.story({\n  render: () => (\n    <Row>\n      <Button ariaLabel={false} size=\"small\">\n        Small Button\n      </Button>\n      <Button ariaLabel={false} size=\"medium\">\n        Medium Button\n      </Button>\n    </Row>\n  ),\n});\n\nexport const Paddings = meta.story({\n  render: () => (\n    <Stack>\n      <Row>\n        <Button ariaLabel={false} size=\"small\" padding=\"small\">\n          Small Padding\n        </Button>\n        <Button ariaLabel={false} size=\"small\" padding=\"medium\">\n          Medium Padding\n        </Button>\n      </Row>\n      <Row>\n        <Button ariaLabel={false} size=\"medium\" padding=\"small\">\n          Small Padding\n        </Button>\n        <Button ariaLabel={false} size=\"medium\" padding=\"medium\">\n          Medium Padding\n        </Button>\n      </Row>\n    </Stack>\n  ),\n});\n\nexport const Disabled = meta.story({\n  args: {\n    ariaLabel: false,\n    disabled: true,\n    children: 'Disabled Button',\n    onClick: fn(),\n  },\n  render: (args) => (\n    <Row>\n      <Button variant=\"solid\" {...args}>\n        Disabled Button\n      </Button>\n    </Row>\n  ),\n  play: async ({ args, canvas, step }) => {\n    const button = canvas.getByRole('button', { name: 'Disabled Button' });\n\n    await step('Disabled button should be aria-disabled', async () => {\n      expect(button).toHaveAttribute('aria-disabled', 'true');\n    });\n\n    await step('Disabled button should not be clickable', async () => {\n      button.click();\n      expect(args.onClick).not.toHaveBeenCalled();\n    });\n\n    await step('Disabled button should be focusable for accessibility', async () => {\n      const button = canvas.getByRole('button', { name: 'Disabled Button' });\n      button.focus();\n      expect(button).toHaveFocus();\n    });\n  },\n});\n\nexport const ReadOnly = meta.story({\n  args: {\n    ariaLabel: false,\n    readOnly: true,\n    children: 'ReadOnly Button',\n  },\n});\n\nexport const WithHref = meta.story({\n  render: () => (\n    <Row>\n      <Button ariaLabel={false} onClick={() => console.log('Hello')}>\n        I am a button using onClick\n      </Button>\n      <Button ariaLabel={false} asChild>\n        <a href=\"https://storybook.js.org/\">I am an anchor using Href</a>\n      </Button>\n    </Row>\n  ),\n});\n\nexport const Animated = meta.story({\n  args: {\n    ariaLabel: false,\n    variant: 'outline',\n  },\n  render: (args) => (\n    <Stack>\n      <Row>\n        <Button {...args} animation=\"glow\">\n          Button\n        </Button>\n        <Button {...args} animation=\"jiggle\">\n          Button\n        </Button>\n        <Button {...args} animation=\"rotate360\">\n          Button\n        </Button>\n      </Row>\n      <Row>\n        <Button {...args} animation=\"glow\">\n          <FaceHappyIcon /> Button\n        </Button>\n        <Button {...args} animation=\"jiggle\">\n          <FaceHappyIcon /> Button\n        </Button>\n        <Button {...args} animation=\"rotate360\">\n          <FaceHappyIcon /> Button\n        </Button>\n      </Row>\n      <Row>\n        <Button {...args} ariaLabel=\"Happy\" animation=\"glow\" padding=\"small\">\n          <FaceHappyIcon />\n        </Button>\n        <Button {...args} ariaLabel=\"Happy\" animation=\"jiggle\" padding=\"small\">\n          <FaceHappyIcon />\n        </Button>\n        <Button {...args} ariaLabel=\"Happy\" animation=\"rotate360\" padding=\"small\">\n          <FaceHappyIcon />\n        </Button>\n      </Row>\n    </Stack>\n  ),\n});\n\nexport const AriaLabel = meta.story({\n  args: {\n    ariaLabel: 'Button',\n    children: <FaceHappyIcon />,\n  },\n});\n\nexport const Tooltip = meta.story({\n  args: {\n    ariaLabel: false,\n    children: 'Button',\n    tooltip: 'A button can be pressed to perform an action',\n  },\n});\n\nexport const AriaDescription = meta.story({\n  args: {\n    ariaLabel: 'Button',\n    ariaDescription: 'Clicking this button allegedly makes you happy.',\n    children: <FaceHappyIcon />,\n  },\n});\n\nexport const Shortcut = meta.story({\n  args: {\n    ariaLabel: false,\n    children: 'Button',\n    shortcut: ['Control', 'Shift', 'H'],\n  },\n});\n\nexport const ShortcutAndTooltip = meta.story({\n  args: {\n    ariaLabel: false,\n    children: 'Button',\n    tooltip: 'A button can be pressed to perform an action',\n    shortcut: ['Control', 'Shift', 'H'],\n  },\n});\n\nexport const ShortcutAndDefaultTooltip = meta.story({\n  args: {\n    ariaLabel: 'Button',\n    children: <FaceHappyIcon />,\n    shortcut: ['Control', 'Shift', 'H'],\n  },\n});\n"
  },
  {
    "path": "code/core/src/components/components/Button/Button.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React, { forwardRef, useEffect, useMemo, useState } from 'react';\n\nimport { deprecate } from 'storybook/internal/client-logger';\n\nimport { Slot } from '@radix-ui/react-slot';\nimport { darken, lighten, rgba, transparentize } from 'polished';\nimport { type API_KeyCollection, shortcutToAriaKeyshortcuts } from 'storybook/manager-api';\nimport { isPropValid, styled } from 'storybook/theming';\n\nimport { InteractiveTooltipWrapper } from './helpers/InteractiveTooltipWrapper.tsx';\nimport { useAriaDescription } from './helpers/useAriaDescription.tsx';\n\nexport interface ButtonProps extends Omit<ComponentProps<typeof StyledButton>, 'as'> {\n  as?: ComponentProps<typeof StyledButton>['as'] | typeof Slot;\n  asChild?: boolean;\n\n  /**\n   * A concise action label for the button announced by screen readers. Needed for buttons without\n   * text or with text that relies on visual cues to be understood. Pass false to indicate that the\n   * Button's content is already accessible to all. When a string is passed, it is also used as the\n   * default tooltip text.\n   */\n  ariaLabel?: string | false;\n\n  /**\n   * An optional tooltip to display when the Button is hovered. If the Button has no text content,\n   * consider making this the same as the aria-label.\n   */\n  tooltip?: string;\n\n  /**\n   * Only use this flag when tooltips on button interfere with other keyboard interactions, like\n   * when building a custom select or menu button. Disables tooltips from the `tooltip`, `shortcut`\n   * and `ariaLabel` props.\n   */\n  disableAllTooltips?: boolean;\n\n  /**\n   * A more thorough description of what the Button does, provided to non-sighted users through an\n   * aria-describedby attribute. Use sparingly for buttons that trigger complex actions.\n   */\n  ariaDescription?: string;\n\n  /**\n   * An optional keyboard shortcut to enable the button. Will be displayed in the tooltip and passed\n   * to aria-keyshortcuts for assistive technologies. The binding of the shortcut and action is\n   * managed globally in the manager's shortcuts module.\n   */\n  shortcut?: API_KeyCollection;\n}\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n  (\n    {\n      as = 'button',\n      asChild = false,\n      animation = 'none',\n      size = 'small',\n      variant = 'outline',\n      padding = 'medium',\n      disabled = false,\n      readOnly = false,\n      active,\n      onClick,\n      ariaLabel,\n      ariaDescription = undefined,\n      tooltip = undefined,\n      shortcut = undefined,\n      disableAllTooltips = false,\n      ...props\n    },\n    ref\n  ) => {\n    const Comp = asChild ? Slot : as;\n\n    let deprecated = undefined;\n    if (!readOnly && (ariaLabel === undefined || ariaLabel === '')) {\n      deprecated = 'ariaLabel';\n      deprecate(\n        `The 'ariaLabel' prop on 'Button' will become mandatory in Storybook 11. Buttons with text content should set 'ariaLabel={false}' to indicate that they are accessible as-is. Buttons without text content must provide a meaningful 'ariaLabel' for accessibility. The button content is: ${props.children}.`\n      );\n\n      // TODO in Storybook 11\n      // throw new Error(\n      //   'Button requires an ARIA label to be accessible. Please provide a valid ariaLabel prop.'\n      // );\n    }\n\n    if (active !== undefined) {\n      deprecated = 'active';\n      deprecate(\n        'The `active` prop on `Button` is deprecated and will be removed in Storybook 11. Use specialized components like `ToggleButton` or `Select` instead.'\n      );\n    }\n\n    const { ariaDescriptionAttrs, AriaDescription } = useAriaDescription(ariaDescription);\n\n    const shortcutAttribute = useMemo(() => {\n      return shortcut ? shortcutToAriaKeyshortcuts(shortcut) : undefined;\n    }, [shortcut]);\n\n    const [isAnimating, setIsAnimating] = useState(false);\n\n    const handleClick: ButtonProps['onClick'] = (event) => {\n      if (onClick) {\n        onClick(event);\n      }\n\n      if (animation === 'none') {\n        return;\n      }\n      setIsAnimating(true);\n    };\n\n    useEffect(() => {\n      const timer = setTimeout(() => {\n        if (isAnimating) {\n          setIsAnimating(false);\n        }\n      }, 1000);\n      return () => clearTimeout(timer);\n    }, [isAnimating]);\n\n    const finalTooltip = tooltip || (ariaLabel !== false ? ariaLabel : undefined);\n\n    return (\n      <>\n        <InteractiveTooltipWrapper\n          disableAllTooltips={disableAllTooltips}\n          shortcut={shortcut}\n          tooltip={finalTooltip}\n        >\n          <StyledButton\n            data-deprecated={deprecated}\n            as={Comp}\n            ref={ref}\n            variant={variant}\n            size={size}\n            padding={padding}\n            $disabled={disabled || readOnly}\n            aria-disabled={disabled || readOnly ? 'true' : undefined}\n            readOnly={readOnly}\n            active={active}\n            animating={isAnimating}\n            animation={animation}\n            onClick={disabled || readOnly ? undefined : handleClick}\n            aria-label={!readOnly && ariaLabel !== false ? ariaLabel : undefined}\n            aria-keyshortcuts={readOnly ? undefined : shortcutAttribute}\n            {...(readOnly ? {} : ariaDescriptionAttrs)}\n            {...props}\n          />\n        </InteractiveTooltipWrapper>\n        <AriaDescription />\n      </>\n    );\n  }\n);\n\nButton.displayName = 'Button';\n\nconst StyledButton = styled('button', {\n  shouldForwardProp: (prop) => isPropValid(prop),\n})<{\n  size?: 'small' | 'medium';\n  padding?: 'small' | 'medium' | 'none';\n  variant?: 'outline' | 'solid' | 'ghost';\n  active?: boolean;\n  $disabled?: boolean;\n  readOnly?: boolean;\n  animating?: boolean;\n  animation?: 'none' | 'rotate360' | 'glow' | 'jiggle';\n}>(\n  ({\n    theme,\n    variant,\n    size,\n    $disabled,\n    readOnly,\n    active,\n    animating,\n    animation = 'none',\n    padding,\n  }) => ({\n    border: 0,\n    cursor: readOnly ? 'inherit' : $disabled ? 'not-allowed' : 'pointer',\n    display: 'inline-flex',\n    gap: '6px',\n    alignItems: 'center',\n    justifyContent: 'center',\n    overflow: 'hidden',\n    padding: (() => {\n      if (padding === 'none') {\n        return 0;\n      }\n      if (padding === 'small' && size === 'small') {\n        return '0 7px';\n      }\n      if (padding === 'small' && size === 'medium') {\n        return '0 9px';\n      }\n      if (size === 'small') {\n        return '0 10px';\n      }\n      if (size === 'medium') {\n        return '0 12px';\n      }\n      return 0;\n    })(),\n    height: size === 'small' ? '28px' : '32px',\n    position: 'relative',\n    textAlign: 'center',\n    textDecoration: 'none',\n    transitionProperty: 'background, box-shadow',\n    transitionDuration: '150ms',\n    transitionTimingFunction: 'ease-out',\n    verticalAlign: 'top',\n    whiteSpace: 'nowrap',\n    userSelect: 'none',\n    opacity: $disabled && !readOnly ? 0.5 : 1,\n    margin: 0,\n    fontSize: `${theme.typography.size.s1}px`,\n    fontWeight: theme.typography.weight.bold,\n    lineHeight: '1',\n    background: (() => {\n      if (variant === 'solid') {\n        return theme.base === 'light' ? theme.color.secondary : darken(0.18, theme.color.secondary);\n      }\n\n      if (variant === 'outline') {\n        return theme.button.background;\n      }\n\n      if (variant === 'ghost' && active) {\n        return transparentize(0.93, theme.barSelectedColor);\n      }\n\n      return 'transparent';\n    })(),\n    color: (() => {\n      if (variant === 'solid') {\n        return theme.color.lightest;\n      }\n\n      if (variant === 'outline') {\n        return theme.input.color;\n      }\n\n      if (variant === 'ghost' && active) {\n        return theme.base === 'light' ? darken(0.1, theme.color.secondary) : theme.color.secondary;\n      }\n\n      if (variant === 'ghost') {\n        return theme.textMutedColor;\n      }\n      return theme.input.color;\n    })(),\n    boxShadow: variant === 'outline' ? `${theme.button.border} 0 0 0 1px inset` : 'none',\n    borderRadius: theme.input.borderRadius,\n    // Making sure that the button never shrinks below its minimum size\n    flexShrink: 0,\n\n    ...(!readOnly && {\n      '&:hover': {\n        color: variant === 'ghost' ? theme.color.secondary : undefined,\n        background: (() => {\n          let bgColor = theme.color.secondary;\n\n          if (variant === 'solid') {\n            bgColor =\n              theme.base === 'light'\n                ? lighten(0.1, theme.color.secondary)\n                : darken(0.3, theme.color.secondary);\n          }\n\n          if (variant === 'outline') {\n            bgColor = theme.button.background;\n          }\n\n          if (variant === 'ghost') {\n            return transparentize(0.86, theme.color.secondary);\n          }\n          return theme.base === 'light' ? darken(0.02, bgColor) : lighten(0.03, bgColor);\n        })(),\n      },\n\n      '&:active': {\n        color: variant === 'ghost' ? theme.color.secondary : undefined,\n        background: (() => {\n          let bgColor = theme.color.secondary;\n\n          if (variant === 'solid') {\n            bgColor = theme.color.secondary;\n          }\n\n          if (variant === 'outline') {\n            bgColor = theme.button.background;\n          }\n\n          if (variant === 'ghost') {\n            return theme.background.hoverable;\n          }\n          return theme.base === 'light' ? darken(0.02, bgColor) : lighten(0.03, bgColor);\n        })(),\n      },\n\n      '&:focus-visible': {\n        outline: `2px solid ${rgba(theme.color.secondary, 1)}`,\n        outlineOffset: 2,\n        // Should ensure focus outline gets drawn above next sibling\n        zIndex: '1',\n      },\n\n      '.sb-bar &:focus-visible, .sb-list &:focus-visible': {\n        outlineOffset: 0,\n      },\n    }),\n\n    '> svg': {\n      flex: '0 0 auto',\n      animation:\n        animating && animation !== 'none' ? `${theme.animation[animation]} 1000ms ease-out` : '',\n    },\n  })\n);\n\nexport const IconButton = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {\n  deprecate(\n    '`IconButton` is deprecated and will be removed in Storybook 11, use `Button` instead.'\n  );\n\n  return <Button ref={ref} {...props} data-deprecated=\"IconButton\" />;\n});\nIconButton.displayName = 'IconButton';\n"
  },
  {
    "path": "code/core/src/components/components/Button/Docs.mdx",
    "content": "import { Canvas, Meta, Controls, Source } from '@storybook/addon-docs/blocks';\n\nimport * as ButtonStories from './Button.stories';\n\n<Meta of={ButtonStories} />\n\n# Button\n\nButton component is used to trigger an action or event, such as submitting a form, opening a Dialog, canceling an action, or performing a delete operation.\n\n## Import\n\n<Source\n  language=\"tsx\"\n  dark={true}\n  code={`\nimport { Button } from '@storybook/components';\n\n// If you would like to use icons, please import them from the icons library\nimport { FaceHappyIcon, HeartIcon } from '@storybook/icons'\n`} />\n\n## Usage\n\nTo ensure Buttons are accessible, the `ariaLabel` prop must contain a label to be read by screen readers. When your Button's content already contains text, this prop is not necessary. You can set `ariaLabel` to `false` to declare that the Button's children is already readable by screen readers.\n\n<Source\n  language=\"tsx\"\n  dark={true}\n  code={`\n// Using the onClick event handler\n<Button ariaLabel={false} onClick={() => {}}>Hello world!</Button>\n\n  // Using the asChild prop to render a custom child\n  <Button ariaLabel={false} asChild>\n    <a href=\"https://storybook.js.org\">Hello world!</a>\n  </Button>\n`} />\n<Canvas of={ButtonStories.Base} />\n<Controls />\n\n### Button sizes\n\nUse the `size` prop to change the size of the button. You can set the value to `small` or `medium`.\n\n<Canvas of={ButtonStories.Sizes} />\n<Source\n  language=\"tsx\"\n  dark={true}\n  code={`\n<Button ariaLabel={false} size=\"small\">Small Button</Button>\n<Button ariaLabel={false} size=\"medium\">Medium Button</Button>\n`} />\n\n### Button variants\n\nUse the `variant` prop to change the visual style of the button. You can set the value to `outline`, `solid` or `ghost`.\n\n<Canvas of={ButtonStories.Variants} />\n<Source\n  language=\"tsx\"\n  dark={true}\n  code={`\n<Button variant=\"outline\">Outline</Button>\n<Button variant=\"solid\">Solid</Button>\n<Button variant=\"Ghost\">Ghost</Button>\n`} />\n\n### Button with icon\n\nYou can add an icon to the button by adding the icon on the left of the text. Please use any icon from the icon library `@storybook/icons`. You can still set `ariaLabel` to `false` if the button's text fully conveys the meaning of the button. If the icon is necessary to understand the button's purpose, you should pass a more meaningful text to `ariaLabel`.\n\n<Canvas of={ButtonStories.WithIcon} />\n<Source\n  language=\"tsx\"\n  dark={true}\n  code={`\n<Button ariaLabel={false}>\n  <FaceHappyIcon /> Button\n</Button>\n`} />\n\n### Icon only buttons\n\nYou can also use the button as an icon only button by removing the text. To make sure the button is square, please set the padding prop to `small`. You must pass an `ariaLabel` prop to ensure the button is accessible. The `ariaLabel` should describe the action that will be performed when the button is clicked, such as \"Like\" or \"Delete\". The Button will automatically display a tooltip based on the `ariaLabel`'s content when hovered.\n\n<Canvas of={ButtonStories.IconOnly} />\n<Source\n  language=\"tsx\"\n  dark={true}\n  code={`\n<Button ariaLabel=\"Button\" padding=\"small\">\n  <FaceHappyIcon />\n</Button>\n`} />\n\n### Button with custom wrapper\n\nIf you want to use a custom wrapper to set the button as an external link or to use your custom router, you can use the `asChild` prop. This will render the button as a child of the wrapper.\n\n<Canvas of={ButtonStories.WithHref} />\n<Source\n  language=\"tsx\"\n  dark={true}\n  code={`\n<Button ariaLabel={false} asChild>\n  <a href=\"https://storybook.js.org\">Hello world!</a>\n</Button>\n<Button ariaLabel={false} asChild>\n  <Link href='/home'>Hello world!</Link>\n</Button>\n`} />\n\n### Button with animations\n\nYou can use the `animate` prop to add animations to the button. You can set the value to `glow`, `jiggle` or `rotate360`.\n\n<Canvas of={ButtonStories.Animated} />\n<Source\n  language=\"tsx\"\n  dark={true}\n  code={`\n<Button ariaLabel={false} animation=\"glow\">\n  <FaceHappyIcon />Button\n</Button>\n<Button ariaLabel={false} animation=\"jiggle\">\n  <FaceHappyIcon />Button\n</Button>\n<Button ariaLabel={false} animation=\"rotate360\">\n  <FaceHappyIcon />Button\n</Button>\n`} />\n\n### Disabled button\n\nYou can use the `disabled` prop to set the button as disabled.\n\n<Canvas of={ButtonStories.Disabled} />\n<Source\n  language=\"tsx\"\n  dark={true}\n  code={`\n<Button ariaLabel={false} disabled>\n  <FaceHappyIcon />Button\n</Button>\n `}\n/>"
  },
  {
    "path": "code/core/src/components/components/Button/helpers/InteractiveTooltipWrapper.stories.tsx",
    "content": "import React from 'react';\n\nimport { styled } from 'storybook/theming';\n\nimport preview from '../../../../../../.storybook/preview.tsx';\nimport { InteractiveTooltipWrapper } from './InteractiveTooltipWrapper.tsx';\n\nconst meta = preview.meta({\n  id: 'interactive-tooltip-wrapper-component',\n  title: 'InteractiveTooltipWrapper',\n  component: InteractiveTooltipWrapper,\n  args: { children: <button>Hover me</button> },\n});\n\nconst Stack = styled.div({ display: 'flex', flexDirection: 'column', gap: '1rem' });\n\nconst Row = styled.div({ display: 'flex', alignItems: 'center', gap: '1rem' });\n\nexport const All = meta.story({\n  render: () => (\n    <Stack>\n      <Row>\n        <InteractiveTooltipWrapper>\n          <button>No tooltip</button>\n        </InteractiveTooltipWrapper>\n      </Row>\n      <Row>\n        <InteractiveTooltipWrapper tooltip=\"Save\">\n          <button>Tooltip</button>\n        </InteractiveTooltipWrapper>\n      </Row>\n      <Row>\n        <InteractiveTooltipWrapper shortcut={['Ctrl', 'S']}>\n          <button>Shortcut</button>\n        </InteractiveTooltipWrapper>\n      </Row>\n      <Row>\n        <InteractiveTooltipWrapper tooltip=\"Save\" shortcut={['Ctrl', 'S']}>\n          <button>Tooltip and shortcut</button>\n        </InteractiveTooltipWrapper>\n      </Row>\n    </Stack>\n  ),\n});\n\nexport const Empty = meta.story({\n  args: {},\n});\n\nexport const Tooltip = meta.story({\n  args: {\n    tooltip: 'Save',\n  },\n});\n\nexport const Shortcut = meta.story({\n  args: {\n    shortcut: ['Ctrl', 'S'],\n  },\n});\nexport const TooltipAndShortcut = meta.story({\n  args: {\n    shortcut: ['Ctrl', 'S'],\n    tooltip: 'Save',\n  },\n});\n"
  },
  {
    "path": "code/core/src/components/components/Button/helpers/InteractiveTooltipWrapper.tsx",
    "content": "import React, { type DOMAttributes, type ReactElement, useMemo } from 'react';\n\nimport { type API_KeyCollection, shortcutToHumanString } from 'storybook/manager-api';\n\nimport { TooltipNote } from '../../tooltip/TooltipNote.tsx';\nimport { TooltipProvider } from '../../tooltip/TooltipProvider.tsx';\n\nexport const InteractiveTooltipWrapper: React.FC<{\n  children: ReactElement<DOMAttributes<Element>, string>;\n  shortcut?: API_KeyCollection;\n  disableAllTooltips?: boolean;\n  tooltip?: string;\n}> = ({ children, disableAllTooltips, shortcut, tooltip }) => {\n  const tooltipLabel = useMemo(() => {\n    // We read from document despite the lack of reactivity, because this\n    // option isn't changeable in the UI. If it was, we'd need to fetch the\n    // addons singleton. This component is used in Buttons, etc., which are\n    // public API and can be imported in MDX. So We rely on a declarative\n    // DOM attribute instead of relying on the manager API.\n    const hasShortcuts = document?.body?.getAttribute('data-shortcuts-enabled') !== 'false';\n\n    if (!tooltip && (!shortcut || !hasShortcuts)) {\n      return undefined;\n    }\n\n    return [tooltip, shortcut && hasShortcuts && `[${shortcutToHumanString(shortcut)}]`]\n      .filter(Boolean)\n      .join(' ');\n  }, [shortcut, tooltip]);\n\n  return tooltipLabel ? (\n    <TooltipProvider\n      placement=\"top\"\n      tooltip={<TooltipNote note={tooltipLabel} />}\n      visible={!disableAllTooltips ? undefined : false}\n    >\n      {children}\n    </TooltipProvider>\n  ) : (\n    <>{children}</>\n  );\n};\n\nInteractiveTooltipWrapper.displayName = 'InteractiveTooltipWrapper';\n"
  },
  {
    "path": "code/core/src/components/components/Button/helpers/useAriaDescription.tsx",
    "content": "import React, { type ReactElement } from 'react';\n\n/**\n * Provides a way to create an accessible description for an element. Returns a hidden element that\n * contains the description and attributes to pass to the described element.\n *\n * @param description The description to provide for the element.\n * @returns\n */\nexport function useAriaDescription(description = ''): {\n  ariaDescriptionAttrs: {\n    'aria-describedby'?: string;\n  };\n  AriaDescription: () => ReactElement | null;\n} {\n  const describedbyId = description.toLowerCase().trim().replace(/\\s+/g, '-');\n\n  return {\n    ariaDescriptionAttrs: {\n      'aria-describedby': description ? describedbyId : undefined,\n    },\n    AriaDescription: () =>\n      description ? (\n        <span id={describedbyId} hidden>\n          {description}\n        </span>\n      ) : null,\n  };\n}\n"
  },
  {
    "path": "code/core/src/components/components/Card/Card.stories.tsx",
    "content": "import preview from '../../../../../.storybook/preview.tsx';\nimport { Card } from './Card.tsx';\n\nconst meta = preview.meta({\n  component: Card,\n});\n\nconst Contents = ({ children }: { children: React.ReactNode }) => (\n  <div style={{ padding: 16 }}>{children}</div>\n);\n\nexport const Default = meta.story(() => (\n  <Card>\n    <Contents>Default</Contents>\n  </Card>\n));\n\nexport const Rainbow = meta.story(() => (\n  <Card outlineAnimation=\"rainbow\">\n    <Contents>Rainbow</Contents>\n  </Card>\n));\n\nexport const Spinning = meta.story(() => (\n  <Card outlineAnimation=\"spin\">\n    <Contents>Spinning</Contents>\n  </Card>\n));\n\nexport const Positive = meta.story(() => (\n  <Card outlineColor=\"positive\">\n    <Contents>Positive</Contents>\n  </Card>\n));\n\nexport const Warning = meta.story(() => (\n  <Card outlineColor=\"warning\">\n    <Contents>Warning</Contents>\n  </Card>\n));\n\nexport const Negative = meta.story(() => (\n  <Card outlineColor=\"negative\">\n    <Contents>Negative</Contents>\n  </Card>\n));\n\nexport const Primary = meta.story(() => (\n  <Card outlineColor=\"primary\">\n    <Contents>Primary</Contents>\n  </Card>\n));\n\nexport const Secondary = meta.story(() => (\n  <Card outlineColor=\"secondary\">\n    <Contents>Secondary</Contents>\n  </Card>\n));\n\nexport const Ancillary = meta.story(() => (\n  <Card outlineColor=\"ancillary\">\n    <Contents>Ancillary</Contents>\n  </Card>\n));\n\nexport const Orange = meta.story(() => (\n  <Card outlineColor=\"orange\">\n    <Contents>Orange</Contents>\n  </Card>\n));\n\nexport const Gold = meta.story(() => (\n  <Card outlineColor=\"gold\">\n    <Contents>Gold</Contents>\n  </Card>\n));\n\nexport const Green = meta.story(() => (\n  <Card outlineColor=\"green\">\n    <Contents>Green</Contents>\n  </Card>\n));\n\nexport const Seafoam = meta.story(() => (\n  <Card outlineColor=\"seafoam\">\n    <Contents>Seafoam</Contents>\n  </Card>\n));\n\nexport const Purple = meta.story(() => (\n  <Card outlineColor=\"purple\">\n    <Contents>Purple</Contents>\n  </Card>\n));\n\nexport const Ultraviolet = meta.story(() => (\n  <Card outlineColor=\"ultraviolet\">\n    <Contents>Ultraviolet</Contents>\n  </Card>\n));\n\nexport const Mediumdark = meta.story(() => (\n  <Card outlineColor=\"mediumdark\">\n    <Contents>Mediumdark</Contents>\n  </Card>\n));\n"
  },
  {
    "path": "code/core/src/components/components/Card/Card.tsx",
    "content": "import React, { type ComponentProps, type DOMAttributes, forwardRef } from 'react';\n\nimport type { CSSObject, color } from 'storybook/theming';\nimport { keyframes, styled } from 'storybook/theming';\n\nconst fadeInOut = keyframes({\n  '0%': { opacity: 0 },\n  '5%': { opacity: 1 },\n  '25%': { opacity: 1 },\n  '30%': { opacity: 0 },\n});\n\nconst spin = keyframes({\n  '0%': { transform: 'rotate(0deg)' },\n  '10%': { transform: 'rotate(10deg)' },\n  '40%': { transform: 'rotate(170deg)' },\n  '50%': { transform: 'rotate(180deg)' },\n  '60%': { transform: 'rotate(190deg)' },\n  '90%': { transform: 'rotate(350deg)' },\n  '100%': { transform: 'rotate(360deg)' },\n});\n\nconst slide = keyframes({\n  to: {\n    backgroundPositionX: '36%',\n  },\n});\n\nconst CardContent = styled.div(({ theme }) => ({\n  borderRadius: theme.appBorderRadius,\n  backgroundColor: theme.background.content,\n  position: 'relative',\n}));\n\nconst CardOutline = styled.div<{\n  animation?: 'none' | 'rainbow' | 'spin';\n  color?: keyof typeof color;\n}>(({ animation = 'none', color, theme }) => ({\n  position: 'relative',\n  width: '100%',\n  padding: 1,\n  overflow: 'hidden',\n  backgroundColor: theme.background.content,\n  borderRadius: theme.appBorderRadius + 1,\n  boxShadow: `inset 0 0 0 1px ${(animation === 'none' && color && theme.color[color]) || theme.appBorderColor}, var(--card-box-shadow, transparent 0 0)`,\n  transition: 'box-shadow 1s',\n\n  '@supports (interpolate-size: allow-keywords)': {\n    interpolateSize: 'allow-keywords',\n    transition: 'all var(--transition-duration, 0.2s), box-shadow 1s',\n    transitionBehavior: 'allow-discrete',\n  },\n\n  '@media (prefers-reduced-motion: reduce)': {\n    transition: 'box-shadow 1s',\n  },\n\n  '&:before': {\n    content: '\"\"',\n    display: animation === 'none' ? 'none' : 'block',\n    position: 'absolute',\n    left: 0,\n    top: 0,\n    width: '100%',\n    height: '100%',\n    opacity: 1,\n\n    ...(animation === 'rainbow' && {\n      animation: `${slide} 10s infinite linear, ${fadeInOut} 60s infinite linear`,\n      backgroundImage: `linear-gradient(45deg,rgb(234, 0, 0),rgb(255, 157, 0),rgb(255, 208, 0),rgb(0, 172, 0),rgb(0, 166, 255),rgb(181, 0, 181), rgb(234, 0, 0),rgb(255, 157, 0),rgb(255, 208, 0),rgb(0, 172, 0),rgb(0, 166, 255),rgb(181, 0, 181))`,\n      backgroundSize: '1000%',\n      backgroundPositionX: '100%',\n    }),\n\n    ...(animation === 'spin' && {\n      left: '50%',\n      top: '50%',\n      marginLeft: 'calc(max(100vw, 100vh) * -0.5)',\n      marginTop: 'calc(max(100vw, 100vh) * -0.5)',\n      height: 'max(100vw, 100vh)',\n      width: 'max(100vw, 100vh)',\n      animation: `${spin} 3s linear infinite`,\n      backgroundImage:\n        color === 'negative'\n          ? // Hardcoded colors to prevent themes from messing with them (orange+gold, secondary+seafoam)\n            `conic-gradient(transparent 90deg, #FC521F 150deg, #FFAE00 210deg, transparent 270deg)`\n          : `conic-gradient(transparent 90deg, #029CFD 150deg, #37D5D3 210deg, transparent 270deg)`,\n    }),\n  },\n}));\n\ninterface CardProps extends ComponentProps<typeof CardContent> {\n  outlineAnimation?: 'none' | 'rainbow' | 'spin';\n  outlineColor?: keyof typeof color;\n  outlineAttrs?: DOMAttributes<HTMLDivElement>;\n}\n\nexport const Card = Object.assign(\n  forwardRef<HTMLDivElement, CardProps>(function Card(\n    { outlineAnimation = 'none', outlineColor, outlineAttrs: outlineAttrs = {}, ...props },\n    ref\n  ) {\n    return (\n      <CardOutline animation={outlineAnimation} color={outlineColor} ref={ref} {...outlineAttrs}>\n        <CardContent {...props} />\n      </CardOutline>\n    );\n  }),\n  {\n    Content: CardContent,\n    Outline: CardOutline,\n  }\n);\n"
  },
  {
    "path": "code/core/src/components/components/Collapsible/Collapsible.stories.tsx",
    "content": "import { useState } from 'react';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport type { useCollapsible } from './Collapsible.tsx';\nimport { Collapsible } from './Collapsible.tsx';\n\nconst toggle = ({\n  isCollapsed,\n  toggleProps,\n}: {\n  isCollapsed: boolean;\n  toggleProps: ReturnType<typeof useCollapsible>['toggleProps'];\n}) => <button {...toggleProps}>{isCollapsed ? 'Open' : 'Close'}</button>;\n\nconst content = <div style={{ background: 'papayawhip', padding: 16 }}>Peekaboo!</div>;\n\nconst meta = preview.meta({\n  component: Collapsible,\n  args: {\n    summary: toggle,\n    children: content,\n  },\n});\n\nexport const Default = meta.story({});\n\nexport const Collapsed = meta.story({\n  args: {\n    collapsed: true,\n  },\n});\n\nexport const Disabled = meta.story({\n  args: {\n    disabled: true,\n  },\n});\n\nexport const Toggled = meta.story({\n  play: ({ canvas, userEvent }) => userEvent.click(canvas.getByRole('button', { name: 'Close' })),\n});\n\nexport const Controlled = meta.story({\n  render: () => {\n    const [collapsed, setCollapsed] = useState(true);\n    return (\n      <>\n        <button onClick={() => setCollapsed(!collapsed)}>Toggle</button>\n        <Collapsible collapsed={collapsed}>{content}</Collapsible>\n      </>\n    );\n  },\n  play: ({ canvas, userEvent }) => userEvent.click(canvas.getByRole('button', { name: 'Toggle' })),\n});\n"
  },
  {
    "path": "code/core/src/components/components/Collapsible/Collapsible.tsx",
    "content": "import React, {\n  type ComponentProps,\n  type ReactNode,\n  type SyntheticEvent,\n  useCallback,\n  useEffect,\n  useState,\n} from 'react';\n\nimport { useId } from '@react-aria/utils';\nimport { styled } from 'storybook/theming';\n\nconst CollapsibleContent = styled.div<{ collapsed?: boolean }>(({ collapsed = false }) => ({\n  blockSize: collapsed ? 0 : 'auto',\n  contentVisibility: collapsed ? 'hidden' : 'visible',\n  transform: collapsed ? 'translateY(-10px)' : 'translateY(0)',\n  opacity: collapsed ? 0 : 1,\n  overflow: 'hidden',\n\n  '@supports (interpolate-size: allow-keywords)': {\n    interpolateSize: 'allow-keywords',\n    transition: 'all var(--transition-duration, 0.2s)',\n    transitionBehavior: 'allow-discrete',\n  },\n\n  '@media (prefers-reduced-motion: reduce)': {\n    transition: 'none',\n  },\n}));\n\nexport const Collapsible = Object.assign(\n  function Collapsible({\n    children,\n    summary,\n    collapsed,\n    disabled,\n    initialCollapsed,\n    storageKey,\n    state: providedState,\n    ...props\n  }: {\n    children: ReactNode | ((state: ReturnType<typeof useCollapsible>) => ReactNode);\n    summary?: ReactNode | ((state: ReturnType<typeof useCollapsible>) => ReactNode);\n    collapsed?: boolean;\n    disabled?: boolean;\n    initialCollapsed?: boolean;\n    storageKey?: string;\n    state?: ReturnType<typeof useCollapsible>;\n  } & ComponentProps<typeof CollapsibleContent>) {\n    const internalState = useCollapsible({ collapsed, disabled, initialCollapsed, storageKey });\n    const state = providedState || internalState;\n    return (\n      <>\n        {typeof summary === 'function' ? summary(state) : summary}\n        <CollapsibleContent\n          {...props}\n          id={state.contentId}\n          collapsed={state.isCollapsed}\n          aria-hidden={state.isCollapsed}\n        >\n          {typeof children === 'function' ? children(state) : children}\n        </CollapsibleContent>\n      </>\n    );\n  },\n  {\n    Content: CollapsibleContent,\n  }\n);\n\nconst useSessionState = <T,>(key: string | undefined, initialValue: T) => {\n  const [value, setValue] = useState<T>(() => {\n    try {\n      return (JSON.parse(sessionStorage.getItem(key!)!) as T) ?? initialValue;\n    } catch {\n      return initialValue;\n    }\n  });\n\n  useEffect(() => {\n    try {\n      if (key) {\n        sessionStorage.setItem(key, JSON.stringify(value));\n      }\n    } catch {}\n  }, [key, value]);\n\n  return [value, setValue] as const;\n};\n\nexport const useCollapsible = ({\n  collapsed,\n  disabled,\n  initialCollapsed = collapsed,\n  storageKey,\n}: {\n  collapsed?: boolean;\n  disabled?: boolean;\n  initialCollapsed?: boolean;\n  storageKey?: string;\n}) => {\n  const [isCollapsed, setCollapsed] = useSessionState(\n    storageKey && `useCollapsible:${storageKey}`,\n    !!initialCollapsed\n  );\n\n  useEffect(() => {\n    if (collapsed !== undefined) {\n      setCollapsed(collapsed);\n    }\n  }, [collapsed, setCollapsed]);\n\n  const toggleCollapsed = useCallback(\n    (event?: SyntheticEvent<Element, Event>) => {\n      event?.stopPropagation();\n      if (!disabled) {\n        setCollapsed((value) => !value);\n      }\n    },\n    [disabled, setCollapsed]\n  );\n\n  const contentId = useId();\n  const toggleProps = {\n    disabled,\n    onClick: toggleCollapsed,\n    'aria-controls': contentId,\n    'aria-expanded': !isCollapsed,\n  } as const;\n\n  return {\n    contentId,\n    isCollapsed,\n    isDisabled: !!disabled,\n    setCollapsed,\n    toggleCollapsed,\n    toggleProps,\n  };\n};\n"
  },
  {
    "path": "code/core/src/components/components/ErrorFormatter/ErrorFormatter.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { dedent } from 'ts-dedent';\n\nimport { ErrorFormatter } from './ErrorFormatter.tsx';\n\nconst meta: Meta<typeof ErrorFormatter> = {\n  component: ErrorFormatter,\n  decorators: [\n    (Story) => (\n      <pre>\n        <Story />\n      </pre>\n    ),\n  ],\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nconst chromeError = new Error('Rendering Problem');\nchromeError.stack = `Error: Rendering problem\n  at render (http://localhost:6006/blocks/src/examples/Button.stories.tsx?t=1677124831161:147:11)\n  at undecoratedStoryFn (http://localhost:6006/sb-preview/runtime.js:8255:38)\n  at http://localhost:6006/sb-preview/runtime.js:7286:21\n  at http://localhost:6006/sb-preview/runtime.js:8225:12\n  at jsxDecorator (http://localhost:6006/node_modules/.cache/.vite-storybook/deps/@storybook_react_preview.js?v=0fc15c2d:1892:17)\n  at http://localhost:6006/sb-preview/runtime.js:7286:21\n  at http://localhost:6006/sb-preview/runtime.js:8200:23\n  at http://localhost:6006/sb-preview/runtime.js:8225:12\n  at wrapper (http://localhost:6006/node_modules/.cache/.vite-storybook/deps/@storybook_addon-links_preview.js?v=0fc15c2d:66:12)\n  at http://localhost:6006/sb-preview/runtime.js:11942:12`;\nexport const Chrome: Story = {\n  args: {\n    error: chromeError,\n  },\n};\n\nconst safariError = new Error('Rendering Problem');\nsafariError.stack = dedent`render@http://localhost:6006/blocks/src/examples/Button.stories.tsx?t=1677211545729:147:26\n  @http://localhost:6006/sb-preview/runtime.js:7:17017\n  jsxDecorator@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/@storybook_react_preview.js?v=0fc15c2d:1469:22\n  @http://localhost:6006/sb-preview/runtime.js:7:17017\n  @http://localhost:6006/sb-preview/runtime.js:7:17017\n  @http://localhost:6006/sb-preview/runtime.js:7:17017\n  @http://localhost:6006/sb-preview/runtime.js:7:17017\n  @http://localhost:6006/sb-preview/runtime.js:7:17017\n  @http://localhost:6006/sb-preview/runtime.js:7:17017\n  renderWithHooks@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:11346:35\n  mountIndeterminateComponent@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:13419:36\n  callCallback2@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:1079:27\n  dispatchEvent@[native code]\n  invokeGuardedCallbackDev@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:1104:37\n  invokeGuardedCallback@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:1135:44\n  beginWork$1@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:17143:36\n  performUnitOfWork@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:16467:31\n  workLoopSync@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:16452:47\n  performSyncWorkOnRoot@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:16189:29\n  scheduleUpdateOnFiber@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:15844:36\n  updateContainer@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:18002:23\n  @http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:18292:30\n  unbatchedUpdates@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:16296:22\n  legacyRenderSubtreeIntoContainer@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:18291:29\n  @http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-VSGIUGYI.js?v=0fc15c2d:34:148\n  Promise@[native code]\n  @http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-VSGIUGYI.js?v=0fc15c2d:33:21\n  asyncFunctionResume@[native code]\n  @[native code]\n  promiseReactionJobWithoutPromise@[native code]\n  promiseReactionJob@[native code]`;\nexport const Safari: Story = {\n  args: {\n    error: safariError,\n  },\n};\n\nconst firefoxError = new Error('Rendering Problem');\nfirefoxError.stack = dedent`render@http://localhost:6006/blocks/src/examples/Button.stories.tsx?t=1677211545729:147:17\n  undecoratedStoryFn@http://localhost:6006/sb-preview/runtime.js:34:2794\n  hookify/<@http://localhost:6006/sb-preview/runtime.js:7:17017\n  defaultDecorateStory/bindWithContext/<@http://localhost:6006/sb-preview/runtime.js:34:1915\n  jsxDecorator@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/@storybook_react_preview.js?v=0fc15c2d:1469:15\n  hookify/<@http://localhost:6006/sb-preview/runtime.js:7:17017\n  decorateStory/<@http://localhost:6006/sb-preview/runtime.js:34:1463\n  defaultDecorateStory/bindWithContext/<@http://localhost:6006/sb-preview/runtime.js:34:1915\n  wrapper@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/@storybook_addon-links_preview.js?v=0fc15c2d:43:225\n  makeDecorator/decorator/<@http://localhost:6006/sb-preview/runtime.js:93:3440\n  makeDecorator/<@http://localhost:6006/sb-preview/runtime.js:93:3553\n  hookify/<@http://localhost:6006/sb-preview/runtime.js:7:17017\n  decorateStory/<@http://localhost:6006/sb-preview/runtime.js:34:1463\n  defaultDecorateStory/bindWithContext/<@http://localhost:6006/sb-preview/runtime.js:34:1915\n  withGrid@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/@storybook_addon-essentials_backgrounds_preview.js?v=0fc15c2d:116:40\n  hookify/<@http://localhost:6006/sb-preview/runtime.js:7:17017\n  decorateStory/<@http://localhost:6006/sb-preview/runtime.js:34:1463\n  defaultDecorateStory/bindWithContext/<@http://localhost:6006/sb-preview/runtime.js:34:1915\n  withBackground@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/@storybook_addon-essentials_backgrounds_preview.js?v=0fc15c2d:91:46\n  hookify/<@http://localhost:6006/sb-preview/runtime.js:7:17017\n  decorateStory/<@http://localhost:6006/sb-preview/runtime.js:34:1463\n  defaultDecorateStory/bindWithContext/<@http://localhost:6006/sb-preview/runtime.js:34:1915\n  withMeasure@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/@storybook_addon-essentials_measure_preview.js?v=0fc15c2d:201:25\n  hookify/<@http://localhost:6006/sb-preview/runtime.js:7:17017\n  decorateStory/<@http://localhost:6006/sb-preview/runtime.js:34:1463\n  defaultDecorateStory/bindWithContext/<@http://localhost:6006/sb-preview/runtime.js:34:1915\n  withOutline@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/@storybook_addon-essentials_outline_preview.js?v=0fc15c2d:443:43\n  hookify/<@http://localhost:6006/sb-preview/runtime.js:7:17017\n  decorateStory/<@http://localhost:6006/sb-preview/runtime.js:34:1463\n  defaultDecorateStory/bindWithContext/<@http://localhost:6006/sb-preview/runtime.js:34:1915\n  renderWithHooks@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:11346:35\n  mountIndeterminateComponent@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:13419:21\n  beginWork@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:14153:22\n  callCallback2@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:1079:22\n  invokeGuardedCallbackDev@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:1104:24\n  invokeGuardedCallback@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:1135:39\n  beginWork$1@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:17143:36\n  performUnitOfWork@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:16467:20\n  workLoopSync@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:16452:30\n  performSyncWorkOnRoot@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:16189:17\n  scheduleUpdateOnFiber@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:15844:36\n  updateContainer@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:18002:23\n  node_modules/react-dom/cjs/react-dom.development.js/legacyRenderSubtreeIntoContainer/<@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:18292:30\n  unbatchedUpdates@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:16296:20\n  legacyRenderSubtreeIntoContainer@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:18291:29\n  render@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-DEJXHLHT.js?v=0fc15c2d:18354:18\n  renderElement/<@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-VSGIUGYI.js?v=0fc15c2d:34:142\n  renderElement@http://localhost:6006/node_modules/.cache/.vite-storybook/deps/chunk-VSGIUGYI.js?v=0fc15c2d:33:10`;\nexport const Firefox: Story = {\n  args: {\n    error: firefoxError,\n  },\n};\n"
  },
  {
    "path": "code/core/src/components/components/ErrorFormatter/ErrorFormatter.tsx",
    "content": "import React, { Fragment } from 'react';\n\nimport { global } from '@storybook/global';\n\nimport { styled } from 'storybook/theming';\n\nconst { document } = global;\n\nconst ErrorName = styled.strong(({ theme }) => ({\n  color: theme.color.orange,\n}));\nconst ErrorImportant = styled.strong(({ theme }) => ({\n  color: theme.color.ancillary,\n  textDecoration: 'underline',\n}));\nconst ErrorDetail = styled.em(({ theme }) => ({\n  color: theme.textMutedColor,\n}));\n\nconst firstLineRegex = /(Error): (.*)\\n/;\nconst linesRegexChromium = /at (?:(.*) )?\\(?(.+)\\)?/;\nconst linesRegexFirefox = /([^@]+)?(?:\\/<)?@(.+)?/;\nconst linesRegexSafari = /([^@]+)?@(.+)?/;\n\nexport interface ErrorFormatterProps {\n  error: Error;\n}\n\nexport const ErrorFormatter = ({ error }: ErrorFormatterProps) => {\n  if (!error) {\n    return <Fragment>This error has no stack or message</Fragment>;\n  }\n  if (!error.stack) {\n    return <Fragment>{error.message || 'This error has no stack or message'}</Fragment>;\n  }\n\n  let input = error.stack.toString();\n\n  if (input && error.message && !input.includes(error.message)) {\n    input = `Error: ${error.message}\\n\\n${input}`;\n  }\n\n  const match = input.match(firstLineRegex);\n\n  if (!match) {\n    return <Fragment>{input}</Fragment>;\n  }\n\n  const [, type, name] = match;\n\n  const rawLines = input.split(/\\n/).slice(1);\n  const [, ...lines] = rawLines\n    .map((line) => {\n      const result =\n        line.match(linesRegexChromium) ||\n        line.match(linesRegexFirefox) ||\n        line.match(linesRegexSafari);\n      if (result) {\n        return {\n          name: (result[1] || '').replace('/<', ''),\n          location: result[2].replace(document.location.origin, ''),\n        };\n      }\n\n      return null;\n    })\n    .filter(Boolean);\n\n  return (\n    <Fragment>\n      <span>{type}</span>: <ErrorName>{name}</ErrorName>\n      <br />\n      {lines.map((l, i) =>\n        l?.name ? (\n          <Fragment key={i}>\n            {'  '}at <ErrorImportant>{l.name}</ErrorImportant> (\n            <ErrorDetail>{l.location}</ErrorDetail>)\n            <br />\n          </Fragment>\n        ) : (\n          <Fragment key={i}>\n            {'  '}at <ErrorDetail>{l?.location}</ErrorDetail>\n            <br />\n          </Fragment>\n        )\n      )}\n    </Fragment>\n  );\n};\n"
  },
  {
    "path": "code/core/src/components/components/Form/Checkbox.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Checkbox as Component } from './Checkbox.tsx';\n\nconst meta = {\n  component: Component,\n  title: 'Form/Checkbox',\n} satisfies Meta<typeof Component>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Checkbox: Story = {\n  render: () => (\n    <div style={{ display: 'inline-grid', gap: 15, gridTemplateColumns: 'repeat(3, auto)' }}>\n      <small></small>\n      <small id=\"col-custom\">Custom:</small>\n      <small id=\"col-native\">Native:</small>\n\n      <small id=\"row-focus\">Checked, focus:</small>\n      <Component aria-labelledby=\"col-custom row-focus\" defaultChecked data-focus />\n      <div>\n        <input\n          aria-labelledby=\"col-native row-focus\"\n          type=\"checkbox\"\n          style={{ margin: 0 }}\n          defaultChecked\n          data-focus\n        />\n      </div>\n\n      <small id=\"row-checked\">Checked:</small>\n      <Component aria-labelledby=\"col-custom row-checked\" defaultChecked />\n      <div>\n        <input\n          aria-labelledby=\"col-native row-checked\"\n          type=\"checkbox\"\n          style={{ margin: 0 }}\n          defaultChecked\n        />\n      </div>\n\n      <small id=\"row-indeterminate\">Indeterminate:</small>\n      <Component aria-labelledby=\"col-custom row-indeterminate\" data-indeterminate />\n      <div>\n        <input\n          aria-labelledby=\"col-native row-indeterminate\"\n          type=\"checkbox\"\n          style={{ margin: 0 }}\n          data-indeterminate\n        />\n      </div>\n\n      <small id=\"row-default\">Default:</small>\n      <Component aria-labelledby=\"col-custom row-default\" />\n      <div>\n        <input aria-labelledby=\"col-native row-default\" type=\"checkbox\" style={{ margin: 0 }} />\n      </div>\n\n      <small id=\"row-disabled-checked\">Disabled, checked:</small>\n      <Component aria-labelledby=\"col-custom row-disabled-checked\" disabled defaultChecked />\n      <div>\n        <input\n          aria-labelledby=\"col-native row-disabled-checked\"\n          type=\"checkbox\"\n          style={{ margin: 0 }}\n          disabled\n          defaultChecked\n        />\n      </div>\n\n      <small id=\"row-disabled-indeterminate\">Disabled, indeterminate:</small>\n      <Component\n        aria-labelledby=\"col-custom row-disabled-indeterminate\"\n        disabled\n        data-indeterminate\n      />\n      <div>\n        <input\n          aria-labelledby=\"col-native row-disabled-indeterminate\"\n          type=\"checkbox\"\n          style={{ margin: 0 }}\n          disabled\n          data-indeterminate\n        />\n      </div>\n\n      <small id=\"row-disabled\">Disabled:</small>\n      <Component aria-labelledby=\"col-custom row-disabled\" disabled />\n      <div>\n        <input\n          aria-labelledby=\"col-native row-disabled\"\n          type=\"checkbox\"\n          style={{ margin: 0 }}\n          disabled\n        />\n      </div>\n    </div>\n  ),\n  afterEach: async ({ canvasElement }) => {\n    canvasElement.querySelectorAll<HTMLInputElement>('[data-indeterminate]').forEach((checkbox) => {\n      checkbox.indeterminate = true;\n    });\n  },\n  parameters: {\n    pseudo: {\n      focus: '[data-focus]',\n    },\n  },\n};\n"
  },
  {
    "path": "code/core/src/components/components/Form/Checkbox.tsx",
    "content": "import React from 'react';\n\nimport { color, styled } from 'storybook/theming';\n\nconst Input = styled.input(({ theme }) => ({\n  appearance: 'none',\n  backgroundColor: theme.input.background,\n  border: `1px solid ${theme.base === 'dark' ? 'hsl(0 0 100 / 0.4)' : 'hsl(0 0 0 / 0.44)'}`,\n  borderRadius: 2,\n  display: 'grid',\n  flexShrink: 0,\n  height: 14,\n  margin: 0,\n  placeContent: 'center',\n  transition: 'background-color 0.1s',\n  width: 14,\n\n  '&:enabled': {\n    cursor: 'pointer',\n  },\n  '&:disabled': {\n    backgroundColor: 'transparent',\n    borderColor: theme.input.border,\n  },\n  '&:disabled:checked, &:disabled:indeterminate': {\n    backgroundColor: theme.base === 'dark' ? color.dark : theme.color.mediumdark,\n  },\n  '&:checked, &:indeterminate': {\n    border: 'none',\n    backgroundColor: color.secondary,\n  },\n  '&:checked::before': {\n    content: '\"\"',\n    width: 14,\n    height: 14,\n    background: `no-repeat center url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14'%3E%3Cpath fill='none' stroke='%23fff' stroke-width='2' d='m3 7 2.5 2.5L11 4'/%3E%3C/svg%3E\")`,\n  },\n  '&:indeterminate::before': {\n    content: '\"\"',\n    width: 8,\n    height: 2,\n    background: 'white',\n  },\n  '&:enabled:focus-visible': {\n    outline: `2px solid ${theme.color.secondary}`,\n    outlineOffset: 2,\n  },\n}));\n\nexport const Checkbox = (props: React.InputHTMLAttributes<HTMLInputElement>) => {\n  return <Input {...props} type=\"checkbox\" />;\n};\n"
  },
  {
    "path": "code/core/src/components/components/Form/Field.stories.tsx",
    "content": "import React from 'react';\n\nimport { fn } from 'storybook/test';\nimport { styled } from 'storybook/theming';\n\nimport { Field as FieldComponent } from './Field.tsx';\nimport { Input as InputComponent } from './Input.tsx';\nimport { Select as SelectComponent } from './Select.tsx';\nimport { Textarea as TextareaComponent } from './Textarea.tsx';\n\nconst Flexed = styled(FieldComponent)({ display: 'flex' });\n\nexport default {\n  title: 'Form/Field',\n  component: FieldComponent,\n  args: {\n    label: 'Label',\n  },\n};\n\nexport const Input = {\n  render: (args: any) => (\n    <Flexed {...args}>\n      <InputComponent value=\"Text\" onChange={fn().mockName('onChange')} />\n    </Flexed>\n  ),\n};\n\nexport const Select = {\n  render: (args: any) => (\n    <Flexed {...args}>\n      <SelectComponent value=\"val2\" onChange={fn().mockName('onChange')}>\n        <option value=\"val1\">Value 1</option>\n        <option value=\"val2\">Value 2</option>\n        <option value=\"val3\">Value 3</option>\n      </SelectComponent>\n    </Flexed>\n  ),\n};\n\nexport const Textarea = {\n  render: (args: any) => (\n    <Flexed {...args}>\n      <TextareaComponent value=\"Content\" onChange={fn().mockName('onChange')} />\n    </Flexed>\n  ),\n};\n"
  },
  {
    "path": "code/core/src/components/components/Form/Field.tsx",
    "content": "import React, { type ReactNode } from 'react';\n\nimport { styled } from 'storybook/theming';\n\nconst Wrapper = styled.label(({ theme }) => ({\n  display: 'flex',\n  borderBottom: `1px solid ${theme.appBorderColor}`,\n  margin: '0 15px',\n  padding: '8px 0',\n\n  '&:last-child': {\n    marginBottom: '3rem',\n  },\n}));\n\nconst Label = styled.span(({ theme }) => ({\n  minWidth: 100,\n  fontWeight: theme.typography.weight.bold,\n  marginRight: 15,\n  display: 'flex',\n  justifyContent: 'flex-start',\n  alignItems: 'center',\n  lineHeight: '16px',\n}));\n\nexport interface FieldProps {\n  children?: ReactNode;\n  label?: ReactNode;\n}\n\nexport const Field = ({ label, children, ...props }: FieldProps) => (\n  <Wrapper {...props}>\n    {label ? (\n      <Label>\n        <span>{label}</span>\n      </Label>\n    ) : null}\n    {children}\n  </Wrapper>\n);\n"
  },
  {
    "path": "code/core/src/components/components/Form/Form.tsx",
    "content": "import { styled } from 'storybook/theming';\n\nimport { Button } from '../Button/Button.tsx';\nimport { Checkbox } from './Checkbox.tsx';\nimport { Field } from './Field.tsx';\nimport { Input } from './Input.tsx';\nimport { Radio } from './Radio.tsx';\nimport { Select } from './Select.tsx';\nimport { Textarea } from './Textarea.tsx';\n\nexport const Form = Object.assign(\n  styled.form({\n    boxSizing: 'border-box',\n    width: '100%',\n  }),\n  {\n    Field,\n    Input,\n    Select,\n    Textarea,\n    Button,\n    Checkbox,\n    Radio,\n  }\n);\n"
  },
  {
    "path": "code/core/src/components/components/Form/Input.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Input as Component } from './Input.tsx';\n\nconst meta = {\n  title: 'Form/Input',\n  component: Component,\n} satisfies Meta<typeof Component>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Input: Story = {\n  render: (args) => <Component aria-label=\"Sample input\" {...args} />,\n};\n\nexport const WithSuffix: Story = {\n  render: (args) => <Component aria-label=\"Sample input\" suffix=\"px\" value=\"10\" {...args} />,\n};\n"
  },
  {
    "path": "code/core/src/components/components/Form/Input.tsx",
    "content": "import React, { type HTMLProps } from 'react';\nimport { forwardRef } from 'react';\n\nimport { useId } from '@react-aria/utils';\nimport { styled } from 'storybook/theming';\n\nimport {\n  type Alignments,\n  type Sizes,\n  type ValidationStates,\n  alignment,\n  sizes,\n  styles,\n  validation,\n} from './styles.ts';\n\nconst Wrapper = styled.div({\n  position: 'relative',\n  width: '100%',\n});\n\nconst Mask = styled.div(\n  ({ theme }) => ({\n    position: 'absolute',\n    left: 0,\n    right: 0,\n    top: 0,\n    bottom: 0,\n    display: 'flex',\n    alignItems: 'center',\n    pointerEvents: 'none',\n    overflow: 'hidden',\n    color: theme.textMutedColor,\n    'span:first-of-type': {\n      opacity: 0,\n    },\n  }),\n  (props) => {\n    const { fontSize, lineHeight, padding } = styles(props);\n    return { fontSize, lineHeight, padding };\n  }\n);\n\ntype InputProps = Omit<\n  HTMLProps<HTMLInputElement>,\n  keyof {\n    size?: Sizes;\n    align?: Alignments;\n    valid?: ValidationStates;\n    height?: number;\n  }\n> & {\n  size?: Sizes;\n  align?: Alignments;\n  valid?: ValidationStates;\n  height?: number;\n  suffix?: string;\n};\n\nexport const Input = Object.assign(\n  styled(\n    forwardRef<any, InputProps>(function Input(\n      { size, valid, align, value, suffix, ...props },\n      ref\n    ) {\n      const suffixId = useId();\n      return (\n        <Wrapper>\n          <input\n            {...props}\n            value={value}\n            ref={ref}\n            aria-describedby={suffix ? suffixId : undefined}\n          />\n          {suffix && (\n            <Mask aria-hidden>\n              <span>{value}</span>\n              <span id={suffixId}>{suffix}</span>\n            </Mask>\n          )}\n        </Wrapper>\n      );\n    })\n  )<InputProps>(styles, sizes, alignment, validation, {\n    minHeight: 32,\n    width: '100%',\n  }),\n  {\n    displayName: 'Input',\n  }\n);\n"
  },
  {
    "path": "code/core/src/components/components/Form/Radio.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Radio as Component } from './Radio.tsx';\n\nconst meta = {\n  component: Component,\n  title: 'Form/Radio',\n} satisfies Meta<typeof Component>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Radio: Story = {\n  render: () => (\n    <div style={{ display: 'inline-grid', gap: 15, gridTemplateColumns: 'repeat(3, auto)' }}>\n      <small></small>\n      <small id=\"col-custom\">Custom:</small>\n      <small id=\"col-native\">Native:</small>\n\n      <small id=\"row-focus\">Checked, focus:</small>\n      <Component aria-labelledby=\"col-custom row-focus\" defaultChecked data-focus name=\"a\" />\n      <div>\n        <input\n          aria-labelledby=\"col-native row-focus\"\n          type=\"radio\"\n          name=\"e\"\n          style={{ margin: 0 }}\n          defaultChecked\n          data-focus\n        />\n      </div>\n\n      <small id=\"row-checked\">Checked:</small>\n      <Component aria-labelledby=\"col-custom row-checked\" defaultChecked name=\"b\" />\n      <div>\n        <input\n          aria-labelledby=\"col-native row-checked\"\n          type=\"radio\"\n          name=\"f\"\n          style={{ margin: 0 }}\n          defaultChecked\n        />\n      </div>\n\n      <small id=\"row-indeterminate\">Indeterminate:</small>\n      <Component aria-labelledby=\"col-custom row-indeterminate\" name=\"indeterminate\" />\n      <div>\n        <input\n          aria-labelledby=\"col-native row-indeterminate\"\n          type=\"radio\"\n          name=\"indeterminate3\"\n          style={{ margin: 0 }}\n        />\n      </div>\n\n      <small id=\"row-default\">Default:</small>\n      <Component aria-labelledby=\"col-custom row-default\" name=\"b\" />\n      <div>\n        <input\n          aria-labelledby=\"col-native row-default\"\n          type=\"radio\"\n          name=\"f\"\n          style={{ margin: 0 }}\n        />\n      </div>\n\n      <small id=\"row-disabled-checked\">Disabled, checked:</small>\n      <Component\n        aria-labelledby=\"col-custom row-disabled-checked\"\n        disabled\n        defaultChecked\n        name=\"c\"\n      />\n      <div>\n        <input\n          aria-labelledby=\"col-native row-disabled-checked\"\n          type=\"radio\"\n          name=\"g\"\n          style={{ margin: 0 }}\n          disabled\n          defaultChecked\n        />\n      </div>\n\n      <small id=\"row-disabled-indeterminate\">Disabled, indeterminate:</small>\n      <Component\n        aria-labelledby=\"col-custom row-disabled-indeterminate\"\n        disabled\n        name=\"indeterminate2\"\n      />\n      <div>\n        <input\n          aria-labelledby=\"col-native row-disabled-indeterminate\"\n          type=\"radio\"\n          name=\"indeterminate4\"\n          style={{ margin: 0 }}\n          disabled\n        />\n      </div>\n\n      <small id=\"row-disabled\">Disabled:</small>\n      <Component aria-labelledby=\"col-custom row-disabled\" disabled name=\"c\" />\n      <div>\n        <input\n          aria-labelledby=\"col-native row-disabled\"\n          type=\"radio\"\n          name=\"h\"\n          style={{ margin: 0 }}\n          disabled\n        />\n      </div>\n    </div>\n  ),\n  parameters: {\n    pseudo: {\n      focus: '[data-focus]',\n    },\n  },\n};\n"
  },
  {
    "path": "code/core/src/components/components/Form/Radio.tsx",
    "content": "import React from 'react';\n\nimport { color, styled } from 'storybook/theming';\n\nconst Input = styled.input(({ theme }) => ({\n  appearance: 'none',\n  backgroundColor: theme.input.background,\n  border: `1px solid ${theme.base === 'dark' ? 'hsl(0 0 100 / 0.4)' : 'hsl(0 0 0 / 0.44)'}`,\n  borderRadius: 8,\n  display: 'grid',\n  flexShrink: 0,\n  height: 16,\n  margin: -1,\n  placeContent: 'center',\n  transition: 'background-color 0.1s',\n  width: 16,\n\n  '&:enabled': {\n    cursor: 'pointer',\n  },\n  '&:disabled': {\n    backgroundColor: 'transparent',\n    borderColor: theme.input.border,\n  },\n  '&:disabled:checked': {\n    backgroundColor: theme.base === 'dark' ? color.dark : theme.color.mediumdark,\n    borderColor: theme.base === 'dark' ? color.dark : theme.color.mediumdark,\n  },\n  '&:checked': {\n    backgroundColor: color.secondary,\n    borderColor: color.secondary,\n    boxShadow: `inset 0 0 0 2px ${theme.input.background}`,\n  },\n  '&:enabled:focus-visible': {\n    outline: `2px solid ${theme.color.secondary}`,\n    outlineOffset: 2,\n  },\n}));\n\nexport const Radio = (props: React.InputHTMLAttributes<HTMLInputElement>) => {\n  return <Input {...props} type=\"radio\" />;\n};\n"
  },
  {
    "path": "code/core/src/components/components/Form/Select.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { action } from 'storybook/actions';\n\nimport { Select as Component } from './Select.tsx';\n\nconst meta = {\n  title: 'Form/Select',\n  component: Component,\n} satisfies Meta<typeof Component>;\n\ntype Story = StoryObj<typeof meta>;\n\nexport default meta;\n\nexport const Select: Story = {\n  render: (args) => (\n    <Component aria-label=\"Fruit\" onChange={action('onChange')} defaultValue=\"\" {...args}>\n      <option value=\"\" hidden disabled>\n        Select a Fruit\n      </option>\n      <option value=\"apple\">Apple</option>\n      <option value=\"banana\">Banana</option>\n      <option value=\"blueberry\">Blueberry</option>\n      <option value=\"grapes\">Grapes</option>\n      <option value=\"pineapple\">Pineapple</option>\n    </Component>\n  ),\n};\n"
  },
  {
    "path": "code/core/src/components/components/Form/Select.tsx",
    "content": "import React, { type CSSProperties, type SelectHTMLAttributes } from 'react';\n\nimport { lighten, styled } from 'storybook/theming';\n\nimport { isTestEnvironment } from '../../../preview-api/modules/preview-web/render/animation-utils.ts';\nimport { type Alignments, type Sizes, type ValidationStates, sizes } from './styles.ts';\n\ntype SelectProps = Omit<\n  SelectHTMLAttributes<HTMLSelectElement>,\n  keyof {\n    size?: Sizes;\n    align?: Alignments;\n    valid?: ValidationStates;\n    height?: number;\n  }\n> & {\n  size?: Sizes;\n  align?: Alignments;\n  valid?: ValidationStates;\n  height?: number;\n};\nconst BaseSelect = styled.select<SelectProps>(sizes, ({ theme }) => ({\n  appearance: 'none',\n  background: `calc(100% - 12px) center no-repeat url(\"data:image/svg+xml,%3Csvg width='8' height='4' viewBox='0 0 8 4' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1.30303 0.196815C1.13566 0.0294472 0.864304 0.0294472 0.696937 0.196815C0.529569 0.364182 0.529569 0.635539 0.696937 0.802906L3.69694 3.80291C3.8643 3.97027 4.13566 3.97027 4.30303 3.80291L7.30303 0.802906C7.4704 0.635539 7.4704 0.364182 7.30303 0.196815C7.13566 0.0294473 6.8643 0.0294473 6.69694 0.196815L3.99998 2.89377L1.30303 0.196815Z' fill='%2373828C'/%3E%3C/svg%3E%0A\")`,\n  backgroundSize: 10,\n  padding: '6px 30px 6px 10px',\n  '@supports (appearance: base-select)': {\n    appearance: 'base-select' as CSSProperties['appearance'],\n    background: theme.input.background,\n    padding: '6px 10px',\n  },\n  transition: 'box-shadow 200ms ease-out, opacity 200ms ease-out',\n  color: theme.input.color || 'inherit',\n  boxShadow: `${theme.input.border} 0 0 0 1px inset`,\n  borderRadius: theme.input.borderRadius,\n  fontSize: theme.typography.size.s2 - 1,\n  lineHeight: '20px',\n  boxSizing: 'border-box',\n  border: 'none',\n  cursor: 'pointer',\n  '& > button': {\n    display: 'flex',\n    alignItems: 'center',\n    justifyContent: 'space-between',\n    width: '100%',\n    gap: 8,\n    '& > svg': {\n      width: 14,\n      height: 14,\n      color: theme.textMutedColor,\n    },\n  },\n  '&:has(option:not([hidden]):checked)': {\n    color: theme.color.defaultText,\n  },\n  '&:focus-visible, &:focus-within': {\n    outline: 'none',\n    boxShadow: `${theme.color.secondary} 0 0 0 1px inset`,\n  },\n  '&::picker-icon': {\n    display: 'none',\n  },\n  '&::picker(select)': {\n    appearance: 'base-select' as CSSProperties['appearance'],\n    border: `1px solid ${theme.input.border}`,\n    padding: 4,\n    marginTop: 4,\n    background: theme.base === 'light' ? lighten(theme.background.app) : theme.background.app,\n    filter: `\n      drop-shadow(0 5px 5px rgba(0,0,0,0.05))\n      drop-shadow(0 0 3px rgba(0,0,0,0.1))\n    `,\n    borderRadius: theme.appBorderRadius + 2,\n    fontSize: theme.typography.size.s1,\n    cursor: 'default',\n    transition: 'opacity 100ms ease-in-out, transform 100ms ease-in-out',\n    transformOrigin: 'top',\n    transform: 'translateY(0)',\n    opacity: 1,\n    '@starting-style': {\n      transform: 'translateY(-0.25rem) scale(0.95)',\n      opacity: 0,\n    },\n  },\n  '& optgroup label': {\n    display: 'block',\n    padding: '3px 6px',\n  },\n  '& option': {\n    lineHeight: '18px',\n    padding: '7px 10px',\n    borderRadius: 4,\n    outline: 'none',\n    cursor: 'pointer',\n    color: theme.color.defaultText,\n    '&::checkmark': {\n      display: 'none',\n    },\n    '&:hover, &:focus-visible': {\n      backgroundColor: theme.background.hoverable,\n    },\n    '&:checked': {\n      color: theme.color.secondary,\n      fontWeight: theme.typography.weight.bold,\n    },\n    '&:disabled': {\n      backgroundColor: 'transparent',\n      cursor: 'default',\n      color: theme.color.defaultText,\n    },\n  },\n}));\nexport const Select = ({ children, ...props }: SelectProps) => {\n  return (\n    // @ts-expect-error Weird props mismatch\n    <BaseSelect {...props}>\n      {/* TODO Remove condition when this issue is resolved: https://github.com/facebook/react/issues/33609 */}\n      {!isTestEnvironment() && (\n        <button>\n          {/* @ts-expect-error Not yet supported */}\n          <selectedcontent></selectedcontent>\n          <svg\n            xmlns=\"http://www.w3.org/2000/svg\"\n            viewBox=\"0 0 24 24\"\n            fill=\"none\"\n            stroke=\"currentColor\"\n            strokeWidth=\"2\"\n            strokeLinecap=\"round\"\n            strokeLinejoin=\"round\"\n            aria-hidden=\"true\"\n          >\n            <path d=\"m6 9 6 6 6-6\"></path>\n          </svg>\n        </button>\n      )}\n      <optgroup>{children}</optgroup>\n    </BaseSelect>\n  );\n};\n"
  },
  {
    "path": "code/core/src/components/components/Form/Textarea.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Textarea as Component } from './Textarea.tsx';\n\nconst meta = {\n  title: 'Form/Textarea',\n  component: Component,\n} satisfies Meta<typeof Component>;\n\ntype Story = StoryObj<typeof meta>;\n\nexport default meta;\n\nexport const Textarea: Story = {\n  render: (args) => <Component aria-label=\"Sample textarea\" {...args} />,\n};\n"
  },
  {
    "path": "code/core/src/components/components/Form/Textarea.tsx",
    "content": "import React, { forwardRef } from 'react';\n\nimport TextareaAutoResize from 'react-textarea-autosize';\nimport { styled } from 'storybook/theming';\n\nimport {\n  type Alignments,\n  type Sizes,\n  type ValidationStates,\n  alignment,\n  sizes,\n  styles,\n  validation,\n} from './styles.ts';\n\n/**\n * These types are copied from `react-textarea-autosize`. I copied them because of\n * https://github.com/storybookjs/storybook/issues/18734 Maybe there's some bug in `tsup` or\n * `react-textarea-autosize`?\n */\ntype TextareaPropsRaw = React.TextareaHTMLAttributes<HTMLTextAreaElement>;\ntype Style = Omit<NonNullable<TextareaPropsRaw['style']>, 'maxHeight' | 'minHeight'> & {\n  height?: number;\n};\ntype TextareaHeightChangeMeta = {\n  rowHeight: number;\n};\nexport interface TextareaAutosizeProps extends Omit<TextareaPropsRaw, 'style'> {\n  maxRows?: number;\n  minRows?: number;\n  onHeightChange?: (height: number, meta: TextareaHeightChangeMeta) => void;\n  cacheMeasurements?: boolean;\n  style?: Style;\n}\n\ntype TextareaProps = Omit<\n  TextareaAutosizeProps,\n  keyof {\n    size?: Sizes;\n    align?: Alignments;\n    valid?: ValidationStates;\n    height?: number;\n  }\n> & {\n  size?: Sizes;\n  align?: Alignments;\n  valid?: ValidationStates;\n  height?: number;\n} & React.RefAttributes<HTMLTextAreaElement>;\n\nexport const Textarea = Object.assign(\n  styled(\n    forwardRef<any, TextareaProps>(function Textarea({ size, valid, align, ...props }, ref) {\n      return <TextareaAutoResize {...props} ref={ref} />;\n    })\n  )<TextareaProps>(styles, sizes, alignment, validation, ({ height = 400 }) => ({\n    overflow: 'visible',\n    maxHeight: height,\n  })),\n  {\n    displayName: 'Textarea',\n  }\n);\n"
  },
  {
    "path": "code/core/src/components/components/Form/styles.ts",
    "content": "import type { CSSObject, StorybookTheme } from 'storybook/theming';\n\nexport type Sizes = '100%' | 'flex' | 'auto';\nexport type Alignments = 'end' | 'center' | 'start';\nexport type ValidationStates = 'valid' | 'error' | 'warn';\n\nexport const sizes = (({ size }: { size?: Sizes }) => {\n  switch (size) {\n    case '100%': {\n      return { width: '100%' };\n    }\n    case 'flex': {\n      return { flex: 1 };\n    }\n    case 'auto':\n    default: {\n      return { display: 'inline' };\n    }\n  }\n}) as any;\n\nexport const alignment = (({\n  align,\n}: {\n  size?: Sizes;\n  align?: Alignments;\n  valid?: ValidationStates;\n  height?: number;\n}) => {\n  switch (align) {\n    case 'end': {\n      return { textAlign: 'right' };\n    }\n    case 'center': {\n      return { textAlign: 'center' };\n    }\n    case 'start':\n    default: {\n      return { textAlign: 'left' };\n    }\n  }\n}) as any;\n\nexport const validation = (({\n  valid,\n  theme,\n}: {\n  valid: ValidationStates;\n  theme: StorybookTheme;\n}) => {\n  switch (valid) {\n    case 'valid': {\n      return { boxShadow: `${theme.color.positive} 0 0 0 1px inset !important` };\n    }\n    case 'error': {\n      return { boxShadow: `${theme.color.negative} 0 0 0 1px inset !important` };\n    }\n    case 'warn': {\n      return {\n        boxShadow: `${theme.color.warning} 0 0 0 1px inset`,\n      };\n    }\n    case undefined:\n    case null:\n    default: {\n      return {};\n    }\n  }\n}) as any;\n\nconst styleResets: CSSObject = {\n  // resets\n  appearance: 'none',\n  border: '0 none',\n  boxSizing: 'inherit',\n  display: 'block',\n  margin: ' 0',\n  background: 'transparent',\n  padding: 0,\n  fontSize: 'inherit',\n  position: 'relative',\n};\n\nexport const styles = (({ theme }: { theme: StorybookTheme }) => ({\n  ...(styleResets as any),\n\n  transition: 'box-shadow 200ms ease-out, opacity 200ms ease-out',\n  color: theme.input.color || 'inherit',\n  background: theme.input.background,\n  boxShadow: `${theme.input.border} 0 0 0 1px inset`,\n  borderRadius: theme.input.borderRadius,\n  fontSize: theme.typography.size.s2 - 1,\n  lineHeight: '20px',\n  padding: '6px 10px', // 32\n  boxSizing: 'border-box',\n  height: 32,\n\n  '&[type=\"file\"]': {\n    height: 'auto',\n  },\n\n  '&:focus': {\n    boxShadow: `${theme.color.secondary} 0 0 0 1px inset`,\n    outline: 'none',\n    '@media (forced-colors: active)': {\n      outline: '1px solid highlight',\n    },\n  },\n\n  '&[disabled], &[aria-disabled=\"true\"]': {\n    background: theme.base === 'light' ? theme.color.lighter : 'transparent',\n    cursor: 'not-allowed',\n  },\n\n  '&:-webkit-autofill': { WebkitBoxShadow: `0 0 0 3em ${theme.color.lightest} inset` },\n\n  '&::placeholder': {\n    color: theme.textMutedColor,\n    opacity: 1,\n  },\n})) as any;\n"
  },
  {
    "path": "code/core/src/components/components/Loader/Loader.stories.tsx",
    "content": "import React from 'react';\n\nimport { Loader } from './Loader.tsx';\n\nconst withBackground = (storyFn: any) => (\n  <div\n    style={{\n      position: 'fixed',\n      top: 0,\n      left: 0,\n      width: '100vw',\n      height: '100vh',\n      background:\n        'linear-gradient(to right, rgba(56,56,56,1) 0%, rgba(0,0,0,1) 50%, rgba(255,255,255,1) 50%, rgba(224,224,224,1) 100%)',\n    }}\n  >\n    <span\n      style={{\n        position: 'absolute',\n        top: '50%',\n        left: 0,\n        height: '50vh',\n        width: '100vw',\n        background: 'linear-gradient(to right, red 0%, orangered 50%, blue 50%, deepskyblue 100%)',\n      }}\n    />\n    {storyFn()}\n  </div>\n);\n\nexport default {\n  component: Loader,\n};\n\nexport const InfiniteState = () => <Loader role=\"progressbar\" />;\nInfiniteState.decorators = [withBackground];\n\nexport const SizeAdjusted = () => <Loader size={64} role=\"progressbar\" />;\nSizeAdjusted.decorators = [withBackground];\n\nexport const ProgressBar = () => (\n  <Loader progress={{ value: 0.3, message: 'Building', modules: { complete: 500, total: 1337 } }} />\n);\n\nexport const ProgressError = () => <Loader error={new Error('Connection closed')} />;\n"
  },
  {
    "path": "code/core/src/components/components/Loader/Loader.tsx",
    "content": "import React from 'react';\n\nimport { LightningOffIcon } from '@storybook/icons';\n\nimport { transparentize } from 'polished';\nimport { keyframes, styled } from 'storybook/theming';\n\nimport { rotate360 } from '../shared/animation.ts';\n\nconst LoaderWrapper = styled.div<{ size?: number }>(({ size = 32 }) => ({\n  borderRadius: '50%',\n  cursor: 'progress',\n  display: 'inline-block',\n  overflow: 'hidden',\n  position: 'absolute',\n  transition: 'all 200ms ease-out',\n  verticalAlign: 'top',\n  top: '50%',\n  left: '50%',\n  marginTop: -(size / 2),\n  marginLeft: -(size / 2),\n  height: size,\n  width: size,\n  zIndex: 4,\n  borderWidth: 2,\n  borderStyle: 'solid',\n  borderColor: 'rgba(97, 97, 97, 0.29)',\n  borderTopColor: 'rgb(100,100,100)',\n  animation: `${rotate360} 0.7s linear infinite`,\n  mixBlendMode: 'difference',\n}));\n\nconst ProgressWrapper = styled.div({\n  position: 'absolute',\n  display: 'flex',\n  flexDirection: 'column',\n  justifyContent: 'center',\n  alignItems: 'center',\n  width: '100%',\n  height: '100%',\n});\n\nconst ProgressTrack = styled.div(({ theme }) => ({\n  position: 'relative',\n  width: '80%',\n  marginBottom: '0.75rem',\n  maxWidth: 300,\n  height: 5,\n  borderRadius: 5,\n  background: transparentize(0.8, theme.color.secondary),\n  overflow: 'hidden',\n  cursor: 'progress',\n}));\n\nconst ProgressBar = styled.div(({ theme }) => ({\n  position: 'absolute',\n  top: 0,\n  left: 0,\n  height: '100%',\n  background: theme.color.secondary,\n}));\n\nconst ProgressMessage = styled.div(({ theme }) => ({\n  minHeight: '2em',\n  fontSize: `${theme.typography.size.s1}px`,\n  color: theme.textMutedColor,\n}));\n\nconst ErrorIcon = styled(LightningOffIcon)(({ theme }) => ({\n  width: 20,\n  height: 20,\n  marginBottom: '0.5rem',\n  color: theme.textMutedColor,\n}));\n\nconst ellipsis = keyframes`\n  from { content: \"...\" }\n  33% { content: \".\" }\n  66% { content: \"..\" }\n  to { content: \"...\" }\n`;\n\nconst Ellipsis = styled.span({\n  '&::after': {\n    content: \"'...'\",\n    animation: `${ellipsis} 1s linear infinite`,\n    animationDelay: '1s',\n    display: 'inline-block',\n    width: '1em',\n    height: 'auto',\n  },\n});\n\ninterface Progress {\n  value: number;\n  message: string;\n  modules?: {\n    complete: number;\n    total: number;\n  };\n}\n\ninterface LoaderProps extends React.HTMLAttributes<HTMLDivElement> {\n  progress?: Progress;\n  error?: Error;\n  size?: number;\n}\n\nexport const Loader = ({ progress, error, size, ...props }: LoaderProps) => {\n  if (error) {\n    return (\n      <ProgressWrapper aria-label={error.toString()} aria-live=\"polite\" role=\"status\" {...props}>\n        <ErrorIcon />\n        <ProgressMessage>{error.message}</ProgressMessage>\n      </ProgressWrapper>\n    );\n  }\n\n  if (progress) {\n    const { value, modules } = progress;\n    let { message } = progress;\n\n    if (modules) {\n      message += ` ${modules.complete} / ${modules.total} modules`;\n    }\n    return (\n      <ProgressWrapper\n        aria-label=\"Content is loading...\"\n        aria-live=\"polite\"\n        aria-valuemin={0}\n        aria-valuemax={100}\n        aria-valuenow={value * 100}\n        aria-valuetext={message}\n        role=\"progressbar\"\n        {...props}\n      >\n        <ProgressTrack>\n          <ProgressBar style={{ width: `${value * 100}%` }} />\n        </ProgressTrack>\n        <ProgressMessage>\n          {message}\n          {value < 1 && <Ellipsis key={message} />}\n        </ProgressMessage>\n      </ProgressWrapper>\n    );\n  }\n\n  return (\n    <LoaderWrapper\n      aria-label=\"Content is loading...\"\n      aria-live=\"polite\"\n      role=\"status\"\n      size={size}\n      {...props}\n    />\n  );\n};\n"
  },
  {
    "path": "code/core/src/components/components/Modal/Modal.stories.tsx",
    "content": "import React, { forwardRef, useRef, useState } from 'react';\n\nimport { action } from 'storybook/actions';\nimport { expect, fn, screen, userEvent, waitFor, within } from 'storybook/test';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { Button } from '../Button/Button.tsx';\nimport { Modal } from './Modal.tsx';\n\nconst SampleModalContent = () => (\n  <Modal.Content>\n    <Modal.Header>\n      <Modal.Title>Sample Modal</Modal.Title>\n      <Modal.Description>\n        Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n      </Modal.Description>\n    </Modal.Header>\n    <Modal.Col>\n      <p>This is a sample modal with various content sections.</p>\n      <p>You can interact with the elements below:</p>\n      <Modal.Row>\n        <button onClick={fn()}>Sample Button</button>\n      </Modal.Row>\n    </Modal.Col>\n    <Modal.Actions>\n      <Modal.Close asChild>\n        <Button ariaLabel={false} variant=\"solid\" onClick={() => action('save')()}>\n          Save\n        </Button>\n      </Modal.Close>\n      <Modal.Close asChild>\n        <Button ariaLabel={false} variant=\"outline\" onClick={() => action('cancel')()}>\n          Cancel\n        </Button>\n      </Modal.Close>\n    </Modal.Actions>\n  </Modal.Content>\n);\n\nconst MockContainer = forwardRef<\n  HTMLDivElement,\n  {\n    bgColor: string;\n    borderColor: string;\n    id?: string;\n    text: string;\n  }\n>(({ bgColor, borderColor, id, text }, ref) => (\n  <div\n    id={id}\n    ref={ref}\n    style={{\n      position: 'relative',\n      width: '60%',\n      height: '300px',\n      marginTop: '20px',\n      border: `3px dashed ${borderColor}`,\n      borderRadius: '8px',\n      background: bgColor,\n      display: 'flex',\n      alignItems: 'center',\n      justifyContent: 'center',\n    }}\n  >\n    <div\n      style={{ textAlign: 'center', backgroundColor: '#fff6', color: '#111', fontWeight: 'bold' }}\n    >\n      {text}\n    </div>\n  </div>\n));\nMockContainer.displayName = 'MockContainer';\n\nconst meta = preview.meta({\n  id: 'overlay-Modal',\n  title: 'Overlay/Modal',\n  component: Modal,\n  args: {\n    ariaLabel: 'Sample modal',\n    dismissOnClickOutside: true,\n    dismissOnEscape: true,\n  },\n  globals: {\n    sb_theme: 'light',\n  },\n  argTypes: {\n    width: {\n      control: { type: 'number', min: 200, max: 1200, step: 50 },\n      description: 'Fixed width for the modal in pixels',\n    },\n    height: {\n      control: { type: 'number', min: 200, max: 800, step: 50 },\n      description: 'Fixed height for the modal in pixels',\n    },\n    ariaLabel: {\n      control: 'text',\n      description: 'The accessible name for the modal',\n    },\n    dismissOnClickOutside: {\n      control: 'boolean',\n      description: 'Whether the modal can be dismissed by clicking outside',\n    },\n    dismissOnEscape: {\n      control: 'boolean',\n      description: 'Whether the modal can be dismissed by pressing Escape',\n    },\n    open: {\n      control: 'boolean',\n      description: 'Controlled state for modal visibility',\n    },\n    defaultOpen: {\n      control: 'boolean',\n      description: 'Default open state for uncontrolled usage',\n    },\n    onOpenChange: {\n      action: 'onOpenChange',\n      description: 'Callback when modal open state changes',\n    },\n  },\n  decorators: [\n    (storyFn) => (\n      <div\n        style={{\n          width: '100%',\n          minWidth: 1200,\n          height: 800,\n          padding: 20,\n          background:\n            'repeating-linear-gradient(45deg, #505050ff, #bbbbbbff 50px, #bbbbbbff 50px, #bbbbbbff 80px)',\n        }}\n      >\n        {storyFn()}\n      </div>\n    ),\n  ],\n});\n\nexport const Base = meta.story({\n  args: {\n    children: <SampleModalContent />,\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n\n    return (\n      <>\n        <Modal {...args} open={isOpen} onOpenChange={setOpen} />\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Modal\n        </Button>\n      </>\n    );\n  },\n});\n\nexport const FixedWidth = meta.story({\n  args: {\n    width: 300,\n    children: <SampleModalContent />,\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n\n    return (\n      <>\n        <Modal {...args} open={isOpen} onOpenChange={setOpen} />\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Modal (300px width)\n        </Button>\n      </>\n    );\n  },\n});\n\nexport const FixedHeight = meta.story({\n  args: {\n    height: 300,\n    children: <SampleModalContent />,\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n\n    return (\n      <>\n        <Modal {...args} open={isOpen} onOpenChange={setOpen} />\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Modal (300px height)\n        </Button>\n      </>\n    );\n  },\n});\n\nexport const FixedDimensions = meta.story({\n  args: {\n    width: 400,\n    height: 400,\n    children: <SampleModalContent />,\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n\n    return (\n      <>\n        <Modal {...args} open={isOpen} onOpenChange={setOpen} />\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Modal (400x400px)\n        </Button>\n      </>\n    );\n  },\n});\n\nexport const DismissalBehavior = meta.story({\n  args: {\n    children: <SampleModalContent />,\n  },\n  render: (args) => (\n    <div style={{ display: 'flex', gap: '1rem', flexWrap: 'wrap' }}>\n      <div>\n        <h4>Default (dismissible)</h4>\n        <ModalWithTrigger\n          {...args}\n          dismissOnClickOutside={true}\n          dismissOnEscape={true}\n          triggerText=\"Click outside or ESC to close\"\n        />\n      </div>\n      <div>\n        <h4>No outside click dismissal</h4>\n        <ModalWithTrigger\n          {...args}\n          dismissOnClickOutside={false}\n          dismissOnEscape={true}\n          triggerText=\"Only ESC to close\"\n        />\n      </div>\n      <div>\n        <h4>No escape dismissal</h4>\n        <ModalWithTrigger\n          {...args}\n          dismissOnClickOutside={true}\n          dismissOnEscape={false}\n          triggerText=\"Only outside click to close\"\n        />\n      </div>\n      <div>\n        <h4>No dismissal</h4>\n        <ModalWithTrigger\n          {...args}\n          dismissOnClickOutside={false}\n          dismissOnEscape={false}\n          triggerText=\"Use close button only\"\n        />\n      </div>\n    </div>\n  ),\n});\n\nexport const OnInteractOutside = meta.story({\n  name: 'OnInteractOutside (deprecated)',\n  args: {\n    children: <SampleModalContent />,\n    onInteractOutside: fn(),\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n\n    return (\n      <>\n        <Modal {...args} open={isOpen} onOpenChange={setOpen} />\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Modal\n        </Button>\n        <Button ariaLabel={false} style={{ marginLeft: '1rem' }}>\n          Outside Button\n        </Button>\n      </>\n    );\n  },\n  play: async ({ args, canvas, step }) => {\n    await step('Open modal', async () => {\n      const trigger = canvas.getByText('Open Modal');\n      await userEvent.click(trigger);\n      await waitFor(() => {\n        expect(screen.queryByText('Sample Modal')).toBeInTheDocument();\n      });\n    });\n\n    await step('Click outside to close', async () => {\n      const outsideButton = canvas.getByText('Outside Button');\n      await userEvent.click(outsideButton);\n      expect(args.onInteractOutside).toHaveBeenCalled();\n      await waitFor(() => {\n        expect(screen.queryByText('Sample Modal')).not.toBeInTheDocument();\n      });\n    });\n  },\n});\n\nexport const OnInteractOutsidePreventDefault = meta.story({\n  name: 'OnInteractOutside - e.preventDefault (deprecated)',\n  args: {\n    children: <SampleModalContent />,\n    onInteractOutside: (e) => e.preventDefault(),\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n\n    return (\n      <>\n        <Modal {...args} open={isOpen} onOpenChange={setOpen} />\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Modal\n        </Button>\n        <Button ariaLabel={false} style={{ marginLeft: '1rem' }}>\n          Outside Button\n        </Button>\n      </>\n    );\n  },\n  play: async ({ canvas, step }) => {\n    await step('Open modal', async () => {\n      const trigger = canvas.getByText('Open Modal');\n      await userEvent.click(trigger);\n      await waitFor(() => {\n        expect(screen.queryByText('Sample Modal')).toBeInTheDocument();\n      });\n    });\n\n    await step('Click outside to close but modal stays open', async () => {\n      const outsideButton = canvas.getByText('Outside Button');\n      await userEvent.click(outsideButton);\n      // Wait a bit to ensure the modal close animation would've had time to play.\n      await new Promise((r) => setTimeout(r, 300));\n      await waitFor(() => {\n        expect(screen.queryByText('Sample Modal')).toBeInTheDocument();\n      });\n    });\n  },\n});\n\nexport const OnInteractOutsideDismissDisabled = meta.story({\n  name: 'OnInteractOutside - dismiss disabled (deprecated)',\n  args: {\n    children: <SampleModalContent />,\n    dismissOnClickOutside: false,\n    onInteractOutside: fn(),\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n\n    return (\n      <>\n        <Modal {...args} open={isOpen} onOpenChange={setOpen} />\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Modal\n        </Button>\n        <Button ariaLabel={false} style={{ marginLeft: '1rem' }}>\n          Outside Button\n        </Button>\n      </>\n    );\n  },\n  play: async ({ args, canvas, step }) => {\n    await step('Open modal', async () => {\n      const trigger = canvas.getByText('Open Modal');\n      await userEvent.click(trigger);\n      await waitFor(() => {\n        expect(screen.queryByText('Sample Modal')).toBeInTheDocument();\n      });\n    });\n\n    await step('Click outside to close, nothing should happen', async () => {\n      const outsideButton = canvas.getByText('Outside Button');\n      await userEvent.click(outsideButton);\n      expect(args.onInteractOutside).not.toHaveBeenCalled();\n      // Wait a bit to ensure the modal close animation would've had time to play.\n      await new Promise((r) => setTimeout(r, 300));\n      await waitFor(() => {\n        expect(screen.queryByText('Sample Modal')).toBeInTheDocument();\n      });\n    });\n  },\n});\n\nexport const OnEscapeKeyDown = meta.story({\n  name: 'OnEscapeKeyDown (deprecated)',\n  args: {\n    children: <SampleModalContent />,\n    onEscapeKeyDown: fn(),\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n\n    return (\n      <>\n        <Modal {...args} open={isOpen} onOpenChange={setOpen} />\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Modal\n        </Button>\n      </>\n    );\n  },\n  play: async ({ args, canvas, step }) => {\n    await step('Open modal', async () => {\n      const trigger = canvas.getByText('Open Modal');\n      await userEvent.click(trigger);\n      await waitFor(() => {\n        expect(screen.queryByText('Sample Modal')).toBeInTheDocument();\n      });\n    });\n\n    await step('Close modal with Escape key', async () => {\n      await userEvent.keyboard('{Escape}');\n      expect(args.onEscapeKeyDown).toHaveBeenCalled();\n      await waitFor(() => {\n        expect(screen.queryByText('Sample Modal')).not.toBeInTheDocument();\n      });\n    });\n  },\n});\n\nexport const OnEscapeKeyDownPreventDefault = meta.story({\n  name: 'OnEscapeKeyDown - e.preventDefault (deprecated)',\n  args: {\n    children: <SampleModalContent />,\n    onEscapeKeyDown: (e) => e.preventDefault(),\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n\n    return (\n      <>\n        <Modal {...args} open={isOpen} onOpenChange={setOpen} />\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Modal\n        </Button>\n      </>\n    );\n  },\n  play: async ({ canvas, step }) => {\n    await step('Open modal', async () => {\n      const trigger = canvas.getByText('Open Modal');\n      await userEvent.click(trigger);\n      await waitFor(() => {\n        expect(screen.queryByText('Sample Modal')).toBeInTheDocument();\n      });\n    });\n\n    await step('Click outside to close but modal stays open', async () => {\n      await userEvent.keyboard('{Escape}');\n      // Wait a bit to ensure the modal close animation would've had time to play.\n      await new Promise((r) => setTimeout(r, 300));\n      await waitFor(() => {\n        expect(screen.queryByText('Sample Modal')).toBeInTheDocument();\n      });\n    });\n  },\n});\n\nexport const OnEscapeKeyDownEscDisabled = meta.story({\n  name: 'OnEscapeKeyDown - dismiss disabled (deprecated)',\n  args: {\n    children: <SampleModalContent />,\n    dismissOnEscape: false,\n    onEscapeKeyDown: fn(),\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n\n    return (\n      <>\n        <Modal {...args} open={isOpen} onOpenChange={setOpen} />\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Modal\n        </Button>\n      </>\n    );\n  },\n  play: async ({ args, canvas, step }) => {\n    await step('Open modal', async () => {\n      const trigger = canvas.getByText('Open Modal');\n      await userEvent.click(trigger);\n      await waitFor(() => {\n        expect(screen.queryByText('Sample Modal')).toBeInTheDocument();\n      });\n    });\n\n    await step('Click outside to close, nothing should happen', async () => {\n      await userEvent.keyboard('{Escape}');\n      expect(args.onEscapeKeyDown).not.toHaveBeenCalled();\n      // Wait a bit to ensure the modal close animation would've had time to play.\n      await new Promise((r) => setTimeout(r, 300));\n      await waitFor(() => {\n        expect(screen.queryByText('Sample Modal')).toBeInTheDocument();\n      });\n    });\n  },\n});\n\nconst ModalWithTrigger = ({\n  triggerText,\n  ...modalProps\n}: { triggerText: string } & React.ComponentProps<typeof Modal>) => {\n  const [isOpen, setOpen] = useState(false);\n  return (\n    <>\n      <Modal {...modalProps} open={isOpen} onOpenChange={setOpen} />\n      <Button ariaLabel={false} onClick={() => setOpen(true)}>\n        {triggerText}\n      </Button>\n    </>\n  );\n};\n\nexport const StyledComponents = meta.story({\n  args: {\n    width: 600,\n    children: <SampleModalContent />,\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n\n    return (\n      <>\n        <Modal {...args} open={isOpen} onOpenChange={setOpen}>\n          <Modal.Content>\n            <Modal.Header>\n              <Modal.Title>Styled Components Demo</Modal.Title>\n              <Modal.Description>\n                This modal demonstrates all available styled components.\n              </Modal.Description>\n            </Modal.Header>\n            <Modal.Row>\n              <Modal.Col>\n                <h4>Left Column</h4>\n                <p>Content in the left column</p>\n                <ul>\n                  <li>Item 1</li>\n                  <li>Item 2</li>\n                  <li>Item 3</li>\n                </ul>\n              </Modal.Col>\n              <Modal.Col>\n                <h4>Right Column</h4>\n                <p>Content in the right column</p>\n                <p>This demonstrates the Row/Col layout system.</p>\n              </Modal.Col>\n            </Modal.Row>\n            <Modal.Col>\n              <h4>Full Width Section</h4>\n              <p>This section spans the full width of the modal.</p>\n            </Modal.Col>\n            <Modal.Actions>\n              <Modal.Close asChild>\n                <Button ariaLabel={false} variant=\"solid\" onClick={() => action('primary')()}>\n                  Primary Action\n                </Button>\n              </Modal.Close>\n              <Modal.Close asChild>\n                <Button ariaLabel={false} variant=\"outline\" onClick={() => action('secondary')()}>\n                  Secondary Action\n                </Button>\n              </Modal.Close>\n              <Modal.Close asChild>\n                <Button ariaLabel={false} variant=\"outline\" onClick={() => action('cancel')()}>\n                  Cancel\n                </Button>\n              </Modal.Close>\n            </Modal.Actions>\n          </Modal.Content>\n        </Modal>\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Styled Modal\n        </Button>\n      </>\n    );\n  },\n});\n\nexport const WithError = meta.story({\n  args: {\n    width: 500,\n    children: <SampleModalContent />,\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n    const [showError, setShowError] = useState(false);\n\n    return (\n      <>\n        <Modal {...args} open={isOpen} onOpenChange={setOpen}>\n          <Modal.Content>\n            <Modal.Header>\n              <Modal.Title>Form with Error</Modal.Title>\n              <Modal.Description>Try the button to see an error message.</Modal.Description>\n            </Modal.Header>\n            <Modal.Col>\n              <label>\n                Email:\n                <input type=\"email\" style={{ width: '100%', marginTop: '4px', padding: '8px' }} />\n              </label>\n            </Modal.Col>\n            <Modal.Actions>\n              <Button ariaLabel={false} variant=\"solid\" onClick={() => setShowError(!showError)}>\n                {showError ? 'Hide Error' : 'Show Error'}\n              </Button>\n              <Modal.Close asChild>\n                <Button ariaLabel={false} variant=\"outline\" onClick={() => action('cancel')()}>\n                  Cancel\n                </Button>\n              </Modal.Close>\n            </Modal.Actions>\n          </Modal.Content>\n          {showError && (\n            <Modal.Error>Invalid email address. Please check and try again.</Modal.Error>\n          )}\n        </Modal>\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Form Modal\n        </Button>\n      </>\n    );\n  },\n});\n\nexport const AlwaysOpen = meta.story({\n  args: {\n    open: true,\n    dismissOnClickOutside: false,\n    dismissOnEscape: false,\n    children: <SampleModalContent />,\n  },\n  render: (args) => (\n    <Modal {...args}>\n      <Modal.Content>\n        <Modal.Header hasClose={false}>\n          <Modal.Title>Always Open Modal</Modal.Title>\n          <Modal.Description>This modal is always visible for demonstration.</Modal.Description>\n        </Modal.Header>\n        <Modal.Col>\n          <p>This modal cannot be closed through normal means.</p>\n        </Modal.Col>\n      </Modal.Content>\n    </Modal>\n  ),\n});\n\nexport const WithOpenChangeCallback = meta.story({\n  args: {\n    children: <SampleModalContent />,\n    onOpenChange: fn(),\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n\n    const handleOpenChange = (open: boolean) => {\n      setOpen(open);\n      args.onOpenChange?.(open);\n    };\n\n    return (\n      <>\n        <Modal {...args} open={isOpen} onOpenChange={handleOpenChange} />\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Modal (with callback)\n        </Button>\n      </>\n    );\n  },\n  play: async ({ args, canvasElement, step }) => {\n    const canvas = within(canvasElement);\n\n    await step('Open modal and verify callback', async () => {\n      const trigger = canvas.getByText('Open Modal (with callback)');\n      await userEvent.click(trigger);\n      await waitFor(() => {\n        expect(screen.queryByText('Sample Modal')).toBeInTheDocument();\n      });\n      await waitFor(() => {\n        expect(screen.getByRole('dialog')).toBeInTheDocument();\n      });\n      await expect(args.onOpenChange).toHaveBeenCalledWith(true);\n    });\n\n    await step('Close modal and verify callback', async () => {\n      const closeButton = await waitFor(() => screen.findByLabelText('Close modal'), {\n        timeout: 3000,\n      });\n      await userEvent.click(closeButton);\n      await expect(args.onOpenChange).toHaveBeenCalledWith(false);\n    });\n  },\n});\n\nexport const InteractiveKeyboard = meta.story({\n  args: {\n    children: <SampleModalContent />,\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n\n    return (\n      <>\n        <Modal {...args} open={isOpen} onOpenChange={setOpen} />\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Modal (Keyboard Test)\n        </Button>\n      </>\n    );\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const trigger = canvas.getByText('Open Modal (Keyboard Test)');\n\n    await step('Open modal with Enter key', async () => {\n      trigger.focus();\n      await userEvent.keyboard('{Enter}');\n      await waitFor(() => {\n        expect(screen.queryByText('Sample Modal')).toBeInTheDocument();\n      });\n      await waitFor(() => {\n        expect(screen.getByRole('dialog')).toBeInTheDocument();\n      });\n    });\n\n    await step('Navigate through modal content with focus trap', async () => {\n      await new Promise((resolve) => setTimeout(resolve, 500));\n      const closeButton = await waitFor(\n        () => screen.findByRole('button', { name: 'Close modal' }),\n        { timeout: 3000 }\n      );\n      closeButton.focus();\n\n      await expect(closeButton).toHaveFocus();\n\n      await userEvent.tab();\n      const sampleButton = await screen.findByText('Sample Button');\n      await expect(sampleButton).toHaveFocus();\n\n      await userEvent.tab();\n      const saveButton = await screen.findByText('Save');\n      await expect(saveButton).toHaveFocus();\n\n      await userEvent.tab();\n      const cancelButton = await screen.findByText('Cancel');\n      await expect(cancelButton).toHaveFocus();\n\n      await userEvent.tab();\n      await expect(closeButton).toHaveFocus();\n\n      await userEvent.tab();\n      await expect(sampleButton).toHaveFocus();\n    });\n\n    await step('Close modal with Escape key', async () => {\n      await userEvent.keyboard('{Escape}');\n    });\n\n    await step('Await exit animation and check modal is closed', async () => {\n      await waitFor(() => expect(screen.queryByText('Sample Modal')).not.toBeInTheDocument());\n    });\n  },\n});\n\nexport const InteractiveMouse = meta.story({\n  args: {\n    children: <SampleModalContent />,\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n\n    return (\n      <div>\n        <Modal {...args} open={isOpen} onOpenChange={setOpen} />\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Modal (Mouse Test)\n        </Button>\n        <Button ariaLabel={false} style={{ marginLeft: '1rem' }}>\n          Outside Button\n        </Button>\n      </div>\n    );\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n\n    await step('Open modal', async () => {\n      const trigger = canvas.getByText('Open Modal (Mouse Test)');\n      await userEvent.click(trigger);\n      await waitFor(() => {\n        expect(screen.queryByText('Sample Modal')).toBeInTheDocument();\n      });\n      await waitFor(() => {\n        expect(screen.getByRole('dialog')).toBeInTheDocument();\n      });\n    });\n\n    await step('Click close button', async () => {\n      const closeButton = await waitFor(() => screen.findByLabelText('Close modal'), {\n        timeout: 3000,\n      });\n      await userEvent.click(closeButton);\n    });\n\n    await step('Await exit animation and check modal is closed', async () => {\n      await waitFor(() => expect(screen.queryByText('Sample Modal')).not.toBeInTheDocument());\n    });\n\n    await step('Open modal and click outside to close', async () => {\n      const trigger = canvas.getByText('Open Modal (Mouse Test)');\n      await userEvent.click(trigger);\n      await expect(screen.queryByText('Sample Modal')).toBeInTheDocument();\n\n      const outsideButton = canvas.getByText('Outside Button');\n      await userEvent.click(outsideButton);\n    });\n\n    await step('Await exit animation and check modal is closed', async () => {\n      await waitFor(() => expect(screen.queryByText('Sample Modal')).not.toBeInTheDocument());\n    });\n  },\n});\n\nexport const LongContent = meta.story({\n  args: {\n    height: 400,\n    ariaLabel: 'Long content modal',\n    children: <SampleModalContent />,\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n\n    return (\n      <>\n        <Modal {...args} open={isOpen} onOpenChange={setOpen}>\n          <Modal.Content>\n            <Modal.Header>\n              <Modal.Title>Modal with Long Content</Modal.Title>\n              <Modal.Description>\n                This modal demonstrates scrolling behavior with extensive content.\n              </Modal.Description>\n            </Modal.Header>\n            <Modal.Col>\n              <h4>Lorem Ipsum Content</h4>\n              {Array.from({ length: 10 }, (_, i) => (\n                <p key={i} style={{ marginBottom: '1rem' }}>\n                  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor\n                  incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud\n                  exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute\n                  irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla\n                  pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui\n                  officia deserunt mollit anim id est laborum.\n                </p>\n              ))}\n            </Modal.Col>\n            <Modal.Actions>\n              <Modal.Close asChild>\n                <Button ariaLabel={false} variant=\"solid\" onClick={() => action('save')()}>\n                  Save\n                </Button>\n              </Modal.Close>\n              <Modal.Close asChild>\n                <Button ariaLabel={false} variant=\"outline\" onClick={() => action('cancel')()}>\n                  Cancel\n                </Button>\n              </Modal.Close>\n            </Modal.Actions>\n          </Modal.Content>\n        </Modal>\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Long Content Modal\n        </Button>\n      </>\n    );\n  },\n});\n\nexport const DialogTransitions = meta.story({\n  args: {\n    variant: 'dialog',\n    ariaLabel: 'Dialog with transitions',\n    children: <SampleModalContent />,\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n\n    return (\n      <>\n        <Modal {...args} open={isOpen} onOpenChange={setOpen}>\n          <Modal.Content>\n            <Modal.Header>\n              <Modal.Title>Dialog with Smooth Transitions</Modal.Title>\n              <Modal.Description>\n                This dialog demonstrates the zoom-in/zoom-out transition animations.\n              </Modal.Description>\n            </Modal.Header>\n            <Modal.Col>\n              <p>Open and close this modal to see the smooth dialog transitions:</p>\n              <ul>\n                <li>Enter: Zoom-in with fade-in</li>\n                <li>Exit: Zoom-out with fade-out</li>\n              </ul>\n              <p>The animations are centrally managed for system coherence.</p>\n            </Modal.Col>\n            <Modal.Actions>\n              <Modal.Close asChild>\n                <Button ariaLabel={false} variant=\"solid\" onClick={() => action('understood')()}>\n                  Got it\n                </Button>\n              </Modal.Close>\n              <Modal.Close asChild>\n                <Button ariaLabel={false} variant=\"outline\" onClick={() => action('close')()}>\n                  Close\n                </Button>\n              </Modal.Close>\n            </Modal.Actions>\n          </Modal.Content>\n        </Modal>\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Dialog with Transitions\n        </Button>\n      </>\n    );\n  },\n});\n\nexport const BottomDrawerTransitions = meta.story({\n  args: {\n    variant: 'bottom-drawer',\n    ariaLabel: 'Bottom drawer with transitions',\n    children: <SampleModalContent />,\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n\n    return (\n      <>\n        <Modal {...args} open={isOpen} onOpenChange={setOpen}>\n          <Modal.Content>\n            <Modal.Header>\n              <Modal.Title>Bottom Drawer with Smooth Transitions</Modal.Title>\n              <Modal.Description>\n                This drawer demonstrates the slide-from-bottom/slide-to-bottom transition\n                animations.\n              </Modal.Description>\n            </Modal.Header>\n            <Modal.Col>\n              <p>Open and close this modal to see the smooth drawer transitions:</p>\n              <ul>\n                <li>Enter: Slide from bottom with fade-in</li>\n                <li>Exit: Slide to bottom with fade-out</li>\n              </ul>\n              <p>Perfect for mobile-friendly interfaces and actions sheets.</p>\n            </Modal.Col>\n            <Modal.Actions>\n              <Modal.Close asChild>\n                <Button ariaLabel={false} variant=\"solid\" onClick={() => action('understood')()}>\n                  Got it\n                </Button>\n              </Modal.Close>\n              <Modal.Close asChild>\n                <Button ariaLabel={false} variant=\"outline\" onClick={() => action('close')()}>\n                  Close\n                </Button>\n              </Modal.Close>\n            </Modal.Actions>\n          </Modal.Content>\n        </Modal>\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Bottom Drawer with Transitions\n        </Button>\n      </>\n    );\n  },\n});\n\nexport const WithContainer = meta.story({\n  args: {\n    children: <SampleModalContent />,\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n    const container = useRef<HTMLDivElement>(null);\n\n    return (\n      <>\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Modal in Custom Container\n        </Button>\n        <MockContainer\n          bgColor=\"rgba(255, 71, 133, 0.05\"\n          borderColor=\"#ff4785\"\n          text=\"Custom Container. Modal will appear within this bordered area.\"\n          ref={container}\n        />\n        <Modal\n          {...args}\n          container={container.current || undefined}\n          open={isOpen}\n          onOpenChange={setOpen}\n        />\n      </>\n    );\n  },\n});\n\nexport const WithPortalSelector = meta.story({\n  args: {\n    children: <SampleModalContent />,\n    portalSelector: '#custom-modal-portal-target',\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n\n    return (\n      <>\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Modal in Portal Target\n        </Button>\n        <MockContainer\n          id=\"custom-modal-portal-target\"\n          bgColor=\"rgba(30, 167, 253, 0.05)\"\n          borderColor=\"#1EA7FD\"\n          text=\"Portal Selector Target. Modal will appear within this bordered area.\"\n        />\n        <Modal {...args} open={isOpen} onOpenChange={setOpen} />\n      </>\n    );\n  },\n});\n\nexport const WithContainerAndPortalSelector = meta.story({\n  args: {\n    children: <SampleModalContent />,\n    portalSelector: '#ignored-portal-target',\n  },\n  render: (args) => {\n    const [isOpen, setOpen] = useState(false);\n    const [container, setContainer] = useState<HTMLElement | null>(null);\n\n    return (\n      <>\n        <Button ariaLabel={false} onClick={() => setOpen(true)}>\n          Open Modal (Container takes precedence)\n        </Button>\n        <MockContainer\n          id=\"ignored-portal-target\"\n          bgColor=\"rgba(153, 153, 153, 0.05)\"\n          borderColor=\"#999\"\n          text=\"Ignored Portal Selector Target\"\n        />\n        <MockContainer\n          bgColor=\"rgba(55, 213, 163, 0.05)\"\n          borderColor=\"#37D5A3\"\n          text=\"Active Container (takes precedence).\"\n          ref={(element) => setContainer(element ?? null)}\n        />\n        {\n          <Modal\n            {...args}\n            container={container || undefined}\n            open={isOpen}\n            onOpenChange={setOpen}\n          />\n        }\n      </>\n    );\n  },\n});\n\nexport default meta;\n"
  },
  {
    "path": "code/core/src/components/components/Modal/Modal.styled.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React, { useContext } from 'react';\n\nimport { deprecate } from 'storybook/internal/client-logger';\n\nimport { CrossIcon } from '@storybook/icons';\n\nimport { Heading } from 'react-aria-components/patched-dist/Heading';\nimport { Text } from 'react-aria-components/patched-dist/Text';\nimport type { TransitionStatus } from 'react-transition-state';\nimport { keyframes, styled } from 'storybook/theming';\n\nimport { Button } from '../Button/Button.tsx';\n// Import the ModalContext from the main Modal component\nimport { ModalContext } from './Modal.tsx';\n\nconst fadeIn = keyframes({\n  from: { opacity: 0 },\n  to: { opacity: 1 },\n});\n\nconst fadeOut = keyframes({\n  from: { opacity: 1 },\n  to: { opacity: 0 },\n});\n\nconst expand = keyframes({\n  from: { maxHeight: 0 },\n  to: {},\n});\n\nconst zoomIn = keyframes({\n  from: {\n    opacity: 0,\n    transform: 'translate(-50%, -50%) scale(0.9)',\n  },\n  to: {\n    opacity: 1,\n    transform: 'translate(-50%, -50%) scale(1)',\n  },\n});\n\nconst zoomOut = keyframes({\n  from: {\n    opacity: 1,\n    transform: 'translate(-50%, -50%) scale(1)',\n  },\n  to: {\n    opacity: 0,\n    transform: 'translate(-50%, -50%) scale(0.9)',\n  },\n});\n\nconst slideFromBottom = keyframes({\n  from: {\n    opacity: 0,\n    maxHeight: '0px',\n  },\n  to: {\n    opacity: 1,\n    maxHeight: '80vh',\n  },\n});\n\nconst slideToBottom = keyframes({\n  from: {\n    opacity: 1,\n    maxHeight: '80vh',\n  },\n  to: {\n    opacity: 0,\n    maxHeight: '0px',\n  },\n});\n\nexport const Overlay = styled.div<{\n  $status?: TransitionStatus;\n  $transitionDuration?: number;\n}>(({ $status, $transitionDuration }) => ({\n  backdropFilter: 'blur(24px)',\n  background: 'rgba(0, 0, 0, 0.4)',\n  position: 'absolute',\n  inset: 0,\n  width: '100%',\n  height: '100%',\n  zIndex: 100000,\n  '@media (prefers-reduced-motion: no-preference)': {\n    animation:\n      $status === 'exiting' || $status === 'preExit'\n        ? `${fadeOut} ${$transitionDuration}ms`\n        : `${fadeIn} ${$transitionDuration}ms`,\n    animationFillMode: 'forwards',\n  },\n}));\n\nexport const Container = styled.div<{\n  $variant: 'dialog' | 'bottom-drawer';\n  $status?: TransitionStatus;\n  $transitionDuration?: number;\n  width?: number | string;\n  height?: number | string;\n}>(\n  ({ theme }) => ({\n    backgroundColor: theme.background.bar,\n    borderRadius: 6,\n    boxShadow: '0px 4px 67px 0px #00000040',\n    position: 'absolute',\n    overflow: 'auto',\n    zIndex: 100000,\n\n    '&:focus-visible': {\n      outline: 'none',\n    },\n  }),\n  ({ theme, width, height, $variant, $status, $transitionDuration }) =>\n    $variant === 'dialog'\n      ? {\n          top: '50%',\n          left: '50%',\n          width: width ?? 740,\n          height: height ?? 'auto',\n          maxWidth: 'calc(100% - 40px)',\n          maxHeight: '85vh',\n          '@media (prefers-reduced-motion: no-preference)': {\n            willChange: 'transform, opacity',\n            animationTimingFunction: 'cubic-bezier(0.32, 0.72, 0, 1)',\n            animation:\n              $status === 'exiting' || $status === 'preExit'\n                ? `${zoomOut} ${$transitionDuration}ms`\n                : `${zoomIn} ${$transitionDuration}ms`,\n            animationFillMode: 'forwards !important',\n          },\n          '@media (prefers-reduced-motion: reduce)': {\n            transform: 'translate(-50%, -50%) scale(1)',\n          },\n        }\n      : {\n          bottom: '0',\n          left: '0',\n          right: '0',\n          borderRadius: '10px 10px 0 0',\n          overflow: 'hidden',\n          width: width ?? '100%',\n          height: height ?? '80%',\n          maxWidth: '100%',\n          background: theme.background.content,\n          '@supports (interpolate-size: allow-keywords)': {\n            interpolateSize: 'allow-keywords',\n          },\n          '@media (prefers-reduced-motion: no-preference)': {\n            animationTimingFunction: 'cubic-bezier(.9,.16,.77,.64)',\n            animation:\n              $status === 'exiting' || $status === 'preExit'\n                ? `${slideToBottom} ${$transitionDuration}ms`\n                : `${slideFromBottom} ${$transitionDuration}ms`,\n            animationFillMode: 'forwards !important',\n          },\n        }\n);\n\ninterface CloseProps {\n  asChild?: boolean;\n  children?: React.ReactElement<\n    {\n      onClick?: (event: React.MouseEvent) => void;\n    },\n    | string\n    | React.JSXElementConstructor<{\n        onClick?: (event: React.MouseEvent) => void;\n      }>\n  >;\n  onClick?: (event: React.MouseEvent) => void;\n}\n\nexport const Close = ({ asChild, children, onClick, ...props }: CloseProps) => {\n  const { close } = useContext(ModalContext);\n\n  if (asChild && React.isValidElement(children)) {\n    const handleClick = (event: React.MouseEvent) => {\n      onClick?.(event);\n      children.props.onClick?.(event);\n      close?.();\n    };\n\n    return React.cloneElement(children, {\n      ...props,\n      onClick: handleClick,\n    });\n  }\n\n  return (\n    <Button\n      type=\"button\"\n      padding=\"small\"\n      ariaLabel=\"Close modal\"\n      variant=\"ghost\"\n      shortcut={['Escape']}\n      onClick={close}\n    >\n      <CrossIcon />\n    </Button>\n  );\n};\n\nexport const Dialog = {\n  Close: () => {\n    deprecate('Modal.Dialog.Close is deprecated, please use Modal.Close instead.');\n    return <Close data-deprecated=\"Modal.Dialog.Close\" />;\n  },\n};\n\nexport const CloseButton = ({ ariaLabel, ...props }: React.ComponentProps<typeof Button>) => {\n  deprecate('Modal.CloseButton is deprecated, please use Modal.Close instead.');\n\n  return (\n    <Close asChild>\n      <Button ariaLabel={ariaLabel || 'Close'} data-deprecated=\"Modal.CloseButton\" {...props}>\n        <CrossIcon />\n      </Button>\n    </Close>\n  );\n};\n\nexport const Content = styled.div({\n  display: 'flex',\n  flexDirection: 'column',\n  margin: 16,\n  gap: 16,\n});\n\nexport const Row = styled.div({\n  display: 'flex',\n  justifyContent: 'space-between',\n  gap: 16,\n});\n\nexport const Col = styled.div({\n  display: 'flex',\n  flexDirection: 'column',\n  gap: 4,\n});\n\nexport const Header = ({\n  hasClose = true,\n  onClose,\n  ...props\n}: React.ComponentProps<typeof Col> & { hasClose?: boolean; onClose?: () => void }) => (\n  <Row>\n    <Col {...props} />\n    {hasClose && <Close onClick={onClose} />}\n  </Row>\n);\n\nexport const Title = styled((props: ComponentProps<typeof Heading>) => (\n  <Heading level={2} {...props} />\n))(({ theme }) => ({\n  margin: 0,\n  fontSize: theme.typography.size.s3,\n  fontWeight: theme.typography.weight.bold,\n}));\n\nexport const Description = styled(Text)(({ theme }) => ({\n  position: 'relative',\n  zIndex: 1,\n  margin: 0,\n  fontSize: theme.typography.size.s2,\n}));\n\nexport const Actions = styled.div({\n  display: 'flex',\n  flexDirection: 'row-reverse',\n  gap: 8,\n});\n\nexport const ErrorWrapper = styled.div(({ theme }) => ({\n  maxHeight: 100,\n  overflow: 'auto',\n  '@media (prefers-reduced-motion: no-preference)': {\n    animation: `${expand} 300ms, ${fadeIn} 300ms`,\n  },\n  backgroundColor: theme.background.critical,\n  color: theme.color.lightest,\n  fontSize: theme.typography.size.s2,\n\n  '& > div': {\n    position: 'relative',\n    padding: '8px 16px',\n  },\n}));\n\nexport const Error = ({\n  children,\n  ...props\n}: { children: React.ReactNode } & ComponentProps<typeof ErrorWrapper>) => (\n  <ErrorWrapper {...props}>\n    <div>{children}</div>\n  </ErrorWrapper>\n);\n"
  },
  {
    "path": "code/core/src/components/components/Modal/Modal.tsx",
    "content": "import React, { type HTMLAttributes, createContext, useEffect, useRef, useState } from 'react';\n\nimport { deprecate } from 'storybook/internal/client-logger';\nimport type { DecoratorFunction } from 'storybook/internal/csf';\n\nimport { FocusScope } from '@react-aria/focus';\nimport {\n  Overlay,\n  UNSAFE_PortalProvider,\n  ariaHideOutside,\n  useModalOverlay,\n} from '@react-aria/overlays';\nimport { mergeProps } from '@react-aria/utils';\nimport { useOverlayTriggerState } from '@react-stately/overlays';\nimport type { KeyboardEvent as RAKeyboardEvent } from '@react-types/shared';\nimport { useTransitionState } from 'react-transition-state';\n\nimport { useMediaQuery } from '../../../manager/hooks/useMedia.tsx';\nimport * as Components from './Modal.styled.tsx';\n\ninterface ModalProps extends HTMLAttributes<HTMLDivElement> {\n  container?: HTMLElement;\n\n  portalSelector?: string;\n\n  /** Width of the Modal. Defaults to `740`. */\n  width?: number | string;\n\n  /** Height of the Modal. Defaults to `auto`. */\n  height?: number | string;\n\n  /** Modal content. */\n  children: React.ReactNode;\n\n  /** Additional class names for the Modal. */\n  className?: string;\n\n  /** Controlled state: whether the Modal is currently open. */\n  open?: boolean;\n\n  /** Uncontrolled state: whether the Modal is initially open on the first. */\n  defaultOpen?: boolean;\n\n  /** @deprecated Use `dismissOnEscape` instead. */\n  onEscapeKeyDown?: (event: KeyboardEvent) => void;\n\n  /** @deprecated Use `dismissOnInteractOutside` instead. */\n  onInteractOutside?: (event: FocusEvent | MouseEvent | TouchEvent) => void;\n\n  /** Handler called when visibility of the Modal changes. */\n  onOpenChange?: (isOpen: boolean) => void;\n\n  // TODO: Storybook 11, make this required\n  /** The accessible name for the modal. */\n  ariaLabel?: string;\n\n  /** Whether the modal can be dismissed by clicking outside. Defaults to `true`. */\n  dismissOnClickOutside?: boolean;\n\n  /** Whether the modal can be dismissed by pressing Escape. Defaults to `true`. */\n  dismissOnEscape?: boolean;\n\n  /** Transition duration, so we can slow down transitions on mobile. */\n  transitionDuration?: number;\n\n  /** The max dimensions, initial position and animations of the Modal. Defaults to 'dialog'. */\n  variant?: 'dialog' | 'bottom-drawer';\n}\n\n// Create a context to provide the close function like Radix Dialog\nexport const ModalContext = createContext<{ close?: () => void }>({});\n\nfunction BaseModal({\n  container,\n  portalSelector,\n  children,\n  width,\n  height,\n  ariaLabel,\n  dismissOnClickOutside = true,\n  dismissOnEscape = true,\n  className,\n  open,\n  onEscapeKeyDown,\n  onInteractOutside,\n  onOpenChange,\n  defaultOpen,\n  transitionDuration = 200,\n  variant = 'dialog',\n  ...props\n}: ModalProps) {\n  let deprecated = undefined;\n  if (ariaLabel === undefined || ariaLabel === '') {\n    deprecated = 'ariaLabel';\n    deprecate('The `ariaLabel` prop on `Modal` will become mandatory in Storybook 11.');\n    // TODO in Storybook 11\n    // throw new Error(\n    //   'Modal requires an ARIA label to be accessible. Please provide a valid ariaLabel prop.'\n    // );\n  }\n\n  if (onEscapeKeyDown !== undefined) {\n    deprecated = 'onEscapeKeyDown';\n    deprecate(\n      'The `onEscapeKeyDown` prop is deprecated and will be removed in Storybook 11. Use `dismissOnEscape` instead.'\n    );\n  }\n\n  if (onInteractOutside !== undefined) {\n    deprecated = 'onInteractOutside';\n    deprecate(\n      'The `onInteractOutside` prop is deprecated and will be removed in Storybook 11. Use `dismissOnInteractOutside` instead.'\n    );\n  }\n\n  const overlayRef = useRef<HTMLDivElement>(null);\n\n  const reducedMotion = useMediaQuery('(prefers-reduced-motion: reduce)');\n  const [{ status, isMounted }, toggle] = useTransitionState({\n    timeout: reducedMotion ? 0 : transitionDuration,\n    mountOnEnter: true,\n    unmountOnExit: true,\n  });\n\n  // Create state for the overlay trigger\n  const state = useOverlayTriggerState({\n    isOpen: open || isMounted,\n    defaultOpen,\n    onOpenChange: (isOpen: boolean) => {\n      toggle(isOpen);\n      onOpenChange?.(isOpen);\n    },\n  });\n\n  const close = () => {\n    state.close();\n  };\n\n  const { modalProps, underlayProps } = useModalOverlay(\n    {\n      isDismissable: dismissOnClickOutside,\n      isKeyboardDismissDisabled: true,\n      shouldCloseOnInteractOutside: onInteractOutside\n        ? (element: Element) => {\n            const mockedEvent = new MouseEvent('click', {\n              bubbles: true,\n              cancelable: true,\n              relatedTarget: element,\n            });\n            onInteractOutside(mockedEvent);\n            return !mockedEvent.defaultPrevented;\n          }\n        : undefined,\n    },\n    state,\n    overlayRef\n  );\n\n  // Sync external open state with transition state\n  useEffect(() => {\n    const shouldBeOpen = open ?? defaultOpen ?? false;\n    if (shouldBeOpen && !isMounted) {\n      toggle(true);\n    } else if (!shouldBeOpen && isMounted) {\n      toggle(false);\n    }\n  }, [open, defaultOpen, isMounted, toggle]);\n\n  // Call onOpenChange ourselves when the modal is initially opened\n  useEffect(() => {\n    if (isMounted && (open || defaultOpen)) {\n      onOpenChange?.(true);\n    }\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [isMounted]);\n\n  useEffect(() => {\n    if (isMounted && (open || defaultOpen) && overlayRef.current) {\n      return ariaHideOutside([overlayRef.current], { shouldUseInert: true });\n    }\n  }, [isMounted, open, defaultOpen, overlayRef]);\n\n  if (!isMounted || status === 'exited' || status === 'unmounted') {\n    return null;\n  }\n\n  const finalModalProps = mergeProps(modalProps, {\n    onKeyDown: (e: RAKeyboardEvent) => {\n      if (e.key !== 'Escape') {\n        modalProps.onKeyDown?.(e);\n      } else {\n        if (dismissOnEscape) {\n          onEscapeKeyDown?.(e.nativeEvent);\n          if (!e.nativeEvent.defaultPrevented) {\n            close();\n          }\n        }\n      }\n    },\n  });\n\n  const containerElement =\n    container ?? (portalSelector ? document.querySelector<HTMLElement>(portalSelector) : undefined);\n\n  return (\n    <Overlay disableFocusManagement portalContainer={containerElement || undefined}>\n      {/* Overlay won't place focus within the modal on its own, and so its own FocusScope\n       starts cycling through focusable elements only after we've clicked or tabbed into the modal.\n       So we use our own focus scope and autofocus within on mount. */}\n      {/* eslint-disable-next-line jsx-a11y/no-autofocus */}\n      <FocusScope restoreFocus contain autoFocus>\n        <Components.Overlay\n          $status={status}\n          $transitionDuration={transitionDuration}\n          {...underlayProps}\n        />\n        <div role=\"dialog\" aria-label={ariaLabel} ref={overlayRef} {...finalModalProps}>\n          <ModalContext.Provider value={{ close }}>\n            {/* This div exists to help the FocusScope, see https://github.com/adobe/react-spectrum/issues/1604. */}\n            <div tabIndex={-1}>\n              {/* We need to set the FocusScope ourselves somehow, Overlay won't set it. */}\n              <Components.Container\n                data-deprecated={deprecated}\n                $variant={variant}\n                $status={status}\n                $transitionDuration={transitionDuration}\n                className={className}\n                width={width}\n                height={height}\n                {...props}\n              >\n                {children}\n              </Components.Container>\n            </div>\n          </ModalContext.Provider>\n        </div>\n      </FocusScope>\n    </Overlay>\n  );\n}\n\nexport const Modal = Object.assign(BaseModal, Components);\n\n/**\n * Storybook decorator to help render Modals in stories with multiple theme layouts. Internal to\n * Storybook. Use at your own risk.\n */\nexport const ModalDecorator: DecoratorFunction = (Story, { args }) => {\n  const [container, setContainer] = useState<HTMLElement | null>(null);\n\n  if (args.container || args.portalSelector) {\n    return <Story {...{ args }} />;\n  }\n\n  return (\n    <>\n      <UNSAFE_PortalProvider getContainer={() => container}>\n        <Story args={args} />\n      </UNSAFE_PortalProvider>\n      <div\n        ref={(element) => setContainer(element ?? null)}\n        style={{\n          width: '100%',\n          height: '100%',\n          minHeight: '600px',\n          transform: 'translateZ(0)',\n        }}\n      ></div>\n    </>\n  );\n};\n"
  },
  {
    "path": "code/core/src/components/components/Popover/Popover.stories.tsx",
    "content": "import React, { useState } from 'react';\n\nimport { Button, Modal, PopoverProvider } from 'storybook/internal/components';\n\nimport { CloseAltIcon } from '@storybook/icons';\n\nimport { screen } from 'storybook/test';\nimport { fn } from 'storybook/test';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { Popover } from './Popover.tsx';\n\nconst SampleTooltip = () => 'Lorem ipsum dolor sit amet';\n\nconst SamplePopover = () => (\n  <div>\n    <h3>Lorem ipsum dolor sit amet</h3>\n    <p>Consectatur vestibulum concet durum politu coret weirom</p>\n    <button onClick={fn()}>Continue</button>\n  </div>\n);\n\nconst meta = preview.meta({\n  id: 'overlay-Popover',\n  title: 'Overlay/Popover',\n  component: Popover,\n  args: {\n    children: <SamplePopover />,\n    color: undefined,\n    hasChrome: true,\n  },\n  argTypes: {\n    color: {\n      type: 'string',\n      control: 'select',\n      options: ['default', 'inverse', 'positive', 'negative', 'warning', 'none'],\n    },\n  },\n});\n\nexport const AsTooltip = meta.story({\n  args: {\n    children: <SampleTooltip />,\n  },\n});\n\nexport const AsPopover = meta.story({\n  args: {\n    children: <SamplePopover />,\n  },\n});\n\nexport const WithChrome = meta.story({\n  args: {\n    hasChrome: true,\n  },\n});\n\nexport const WithoutChrome = meta.story({\n  args: {\n    hasChrome: false,\n  },\n});\n\nexport const WithHideButton = meta.story({\n  args: {\n    hasChrome: true,\n    onHide: fn(),\n  },\n});\n\nexport const WithCustomHideLabel = meta.story({\n  args: {\n    hasChrome: true,\n    onHide: fn(),\n    hideLabel: 'Close Popover',\n  },\n});\n\nexport const WithHideButtonAndPadding = meta.story({\n  args: {\n    children: (\n      <div>\n        When the close button covers content, setting <code>padding</code> to{' '}\n        <code>8px 40px 8px 8px</code> solves simple use cases.\n      </div>\n    ),\n    hasChrome: true,\n    onHide: fn(),\n    padding: '8px 40px 8px 8px',\n  },\n});\n\nexport const WithCustomHideButton = meta.story({\n  args: {\n    children: (\n      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>\n        <div>For more advanced use cases, pass your own close button to the popover.</div>\n        <Button\n          ariaLabel=\"Close Popover\"\n          onClick={fn()}\n          size=\"small\"\n          padding=\"small\"\n          variant=\"ghost\"\n        >\n          <CloseAltIcon />\n        </Button>\n      </div>\n    ),\n    hasChrome: true,\n  },\n});\n\nexport const ColorDefault = meta.story({\n  args: {\n    color: 'default',\n  },\n});\n\nexport const ColorInverse = meta.story({\n  args: {\n    color: 'inverse',\n  },\n});\n\nexport const ColorPositive = meta.story({\n  args: {\n    color: 'positive',\n  },\n});\n\nexport const ColorNegative = meta.story({\n  args: {\n    color: 'negative',\n  },\n});\n\nexport const ColorWarning = meta.story({\n  args: {\n    color: 'warning',\n  },\n});\n\n/** Useful for WithTooltip where we'll use specialized tooltips like TooltipNote. */\nexport const WithoutColor = meta.story({\n  args: {\n    color: 'none',\n  },\n});\n\nexport const WithModal = meta.story({\n  render: () => {\n    const [isPopoverOpen] = useState(true);\n    const [isModalOpen, setIsModalOpen] = useState(false);\n    return (\n      <>\n        <PopoverProvider\n          visible={isPopoverOpen}\n          popover={\n            <div>\n              <Button ariaLabel={false} onClick={() => setIsModalOpen(true)}>\n                Open modal\n              </Button>\n              <Modal open={isModalOpen} onOpenChange={setIsModalOpen}>\n                <div>Hello</div>\n              </Modal>\n            </div>\n          }\n        >\n          <Button ariaLabel={false}>Open popover</Button>\n        </PopoverProvider>\n        <div style={{ width: 100, height: 100, backgroundColor: 'thistle' }}></div>\n      </>\n    );\n  },\n  play: async ({ userEvent }) => {\n    await userEvent.click(screen.getByRole('button', { name: 'Open modal' }));\n  },\n});\n"
  },
  {
    "path": "code/core/src/components/components/Popover/Popover.tsx",
    "content": "import React, { type HTMLAttributes, forwardRef } from 'react';\n\nimport { CloseIcon } from '@storybook/icons';\n\nimport { lighten, styled } from 'storybook/theming';\n\nimport { Button } from '../Button/Button.tsx';\n\nexport interface PopoverProps extends HTMLAttributes<HTMLDivElement> {\n  /** Content of the popover. */\n  children: React.ReactNode;\n\n  /** Preset popover color taken from the theme, affecting both bathground and foreground. */\n  color?: 'default' | 'inverse' | 'positive' | 'negative' | 'warning' | 'none';\n\n  /** Whether the popover is rendered with a decorative window-like appearance. */\n  hasChrome: boolean;\n\n  /** Optional callback connected to a close button. Then button is shown only when passed. */\n  onHide?: () => void;\n\n  /** Optional custom label for the close button, if there is one. */\n  hideLabel?: string;\n\n  /** Padding between the content and popover edge. */\n  padding?: number | string;\n}\n\nconst Wrapper = styled.div<{\n  bgColor: NonNullable<PopoverProps['color']>;\n  hasChrome: boolean;\n  hasCloseButton: boolean;\n  padding: NonNullable<PopoverProps['padding']>;\n}>(\n  ({ hasCloseButton, padding }) => ({\n    display: 'inline-block',\n    position: 'relative',\n    minHeight: hasCloseButton ? 36 : undefined,\n    zIndex: 2147483647,\n    colorScheme: 'light dark',\n    padding,\n  }),\n  ({ theme, hasChrome }) =>\n    hasChrome\n      ? {\n          filter: `\n            drop-shadow(0px 5px 5px rgba(0,0,0,0.05))\n            drop-shadow(0 1px 3px rgba(0,0,0,0.1))\n          `,\n          borderRadius: theme.appBorderRadius + 2,\n          fontSize: theme.typography.size.s1,\n        }\n      : {},\n  ({ theme, bgColor }) =>\n    bgColor === 'default' && {\n      background: theme.base === 'light' ? lighten(theme.background.app) : theme.background.app,\n      color: theme.color.defaultText,\n    },\n  ({ theme, bgColor }) =>\n    bgColor === 'inverse' && {\n      background: theme.base === 'light' ? theme.color.darkest : theme.color.lightest,\n      color: theme.color.inverseText,\n    },\n  ({ theme, bgColor }) =>\n    (bgColor === 'positive' || bgColor === 'negative' || bgColor === 'warning') && {\n      background: theme.background[bgColor],\n      color: theme.color[`${bgColor}Text`],\n    }\n);\n\nconst AbsoluteButton = styled(Button)({\n  position: 'absolute',\n  top: 4,\n  right: 4,\n});\n\nexport const Popover = forwardRef<HTMLDivElement, PopoverProps>(\n  (\n    {\n      children,\n      color = 'default',\n      hasChrome = true,\n      hideLabel = 'Close',\n      onHide,\n      padding = 8,\n      ...props\n    },\n    ref\n  ) => {\n    return (\n      <Wrapper\n        bgColor={color}\n        hasChrome={hasChrome}\n        hasCloseButton={!!onHide}\n        padding={padding}\n        ref={ref}\n        {...props}\n      >\n        {children}\n        {onHide && (\n          <AbsoluteButton\n            ariaLabel={hideLabel}\n            onClick={onHide}\n            padding=\"small\"\n            variant=\"ghost\"\n            size=\"small\"\n          >\n            <CloseIcon />\n          </AbsoluteButton>\n        )}\n      </Wrapper>\n    );\n  }\n);\n\nPopover.displayName = 'Popover';\n"
  },
  {
    "path": "code/core/src/components/components/Popover/PopoverProvider.stories.tsx",
    "content": "import React from 'react';\n\nimport { expect, fn, screen, userEvent, within } from 'storybook/test';\nimport { styled } from 'storybook/theming';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { OverlayTriggerDecorator, Trigger } from '../shared/overlayHelpers.tsx';\nimport { PopoverProvider } from './PopoverProvider.tsx';\n\nconst StyledSamplePopover = styled.div({\n  padding: 10,\n  maxWidth: 200,\n  display: 'flex',\n  flexDirection: 'column',\n  gap: 10,\n});\n\nconst SamplePopover = () => (\n  <StyledSamplePopover>\n    <h3>Lorem ipsum dolor sit amet</h3>\n    <p>Consectatur vestibulum concet durum politu coret weirom</p>\n    <button onClick={fn()}>Continue</button>\n  </StyledSamplePopover>\n);\n\nconst meta = preview.meta({\n  id: 'overlay-PopoverProvider',\n  title: 'Overlay/PopoverProvider',\n  component: PopoverProvider,\n  args: {\n    ariaLabel: 'Sample popover',\n    hasChrome: true,\n    offset: 8,\n    placement: 'top',\n  },\n  decorators: [OverlayTriggerDecorator],\n});\n\nexport const Base = meta.story({\n  args: {\n    children: <Trigger>Click me!</Trigger>,\n    popover: <SamplePopover />,\n  },\n});\n\nexport const Placements = meta.story({\n  args: {\n    children: <Trigger>ignored</Trigger>,\n    popover: 'ignored',\n  },\n  render: (args) => (\n    <div\n      style={{\n        display: 'grid',\n        gridTemplateColumns: 'repeat(3, 1fr)',\n        gap: '1rem',\n        padding: '2rem',\n      }}\n    >\n      <PopoverProvider {...args} placement=\"top\" popover=\"Top placement\">\n        <Trigger>Top</Trigger>\n      </PopoverProvider>\n      <PopoverProvider {...args} placement=\"top-start\" popover=\"Top start placement\">\n        <Trigger>Top Start</Trigger>\n      </PopoverProvider>\n      <PopoverProvider {...args} placement=\"top-end\" popover=\"Top end placement\">\n        <Trigger>Top End</Trigger>\n      </PopoverProvider>\n      <PopoverProvider {...args} placement=\"bottom\" popover=\"Bottom placement\">\n        <Trigger>Bottom</Trigger>\n      </PopoverProvider>\n      <PopoverProvider {...args} placement=\"bottom-start\" popover=\"Bottom start placement\">\n        <Trigger>Bottom Start</Trigger>\n      </PopoverProvider>\n      <PopoverProvider {...args} placement=\"bottom-end\" popover=\"Bottom end placement\">\n        <Trigger>Bottom End</Trigger>\n      </PopoverProvider>\n      <PopoverProvider {...args} placement=\"left\" popover=\"Left placement\">\n        <Trigger>Left</Trigger>\n      </PopoverProvider>\n      <PopoverProvider {...args} placement=\"left-start\" popover=\"Left start placement\">\n        <Trigger>Left Start</Trigger>\n      </PopoverProvider>\n      <PopoverProvider {...args} placement=\"left-end\" popover=\"Left end placement\">\n        <Trigger>Left End</Trigger>\n      </PopoverProvider>\n      <PopoverProvider {...args} placement=\"right\" popover=\"Right placement\">\n        <Trigger>Right</Trigger>\n      </PopoverProvider>\n      <PopoverProvider {...args} placement=\"right-start\" popover=\"Right start placement\">\n        <Trigger>Right Start</Trigger>\n      </PopoverProvider>\n      <PopoverProvider {...args} placement=\"right-end\" popover=\"Right end placement\">\n        <Trigger>Right End</Trigger>\n      </PopoverProvider>\n    </div>\n  ),\n});\n\nexport const WithChrome = meta.story({\n  args: {\n    hasChrome: true,\n    children: <Trigger>Click me!</Trigger>,\n    popover: <SamplePopover />,\n  },\n});\n\nexport const WithoutChrome = meta.story({\n  args: {\n    hasChrome: false,\n    children: <Trigger>Click me!</Trigger>,\n    popover: <SamplePopover />,\n  },\n});\n\nexport const CustomOffset = meta.story({\n  args: {\n    offset: 20,\n    children: <Trigger>Click me!</Trigger>,\n    popover: <SamplePopover />,\n  },\n});\n\nexport const CustomPadding = meta.story({\n  args: {\n    padding: 20,\n    children: <Trigger>Click me!</Trigger>,\n    popover: <SamplePopover />,\n  },\n});\n\nexport const WithCloseButton = meta.story({\n  args: {\n    children: <Trigger>Click me!</Trigger>,\n    popover: <SamplePopover />,\n    hasCloseButton: true,\n  },\n});\n\nexport const WithoutCloseButton = meta.story({\n  args: {\n    children: <Trigger>Click me!</Trigger>,\n    popover: <SamplePopover />,\n    hasCloseButton: false,\n  },\n});\n\nexport const AlwaysOpen = meta.story({\n  args: {\n    visible: true,\n    children: <Trigger>Always visible tooltip</Trigger>,\n    popover: <SamplePopover />,\n    placement: 'right-start',\n  },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const popover = screen.getByText('Lorem ipsum dolor sit amet');\n    await expect(popover).toBeInTheDocument();\n  },\n});\n\nexport const NeverOpen = meta.story({\n  args: {\n    visible: false,\n    children: <Trigger>Never visible tooltip</Trigger>,\n    popover: <SamplePopover />,\n    placement: 'right-start',\n  },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    await expect(canvas.queryByText('Lorem ipsum dolor sit')).not.toBeInTheDocument();\n  },\n});\n\nexport const WithVisibilityCallback = meta.story({\n  args: {\n    children: <Trigger>Click me!</Trigger>,\n    popover: <SamplePopover />,\n    onVisibleChange: fn(),\n  },\n  play: async ({ args, canvasElement }) => {\n    const canvas = within(canvasElement);\n    const trigger = canvas.getByText('Click me!');\n\n    await userEvent.click(trigger);\n    await expect(args.onVisibleChange).toHaveBeenCalledWith(true);\n\n    await userEvent.click(trigger);\n    await expect(args.onVisibleChange).toHaveBeenCalledWith(false);\n  },\n});\n\nexport const InteractivePopoverKB = meta.story({\n  args: {\n    children: <Trigger>Click me!</Trigger>,\n    popover: <SamplePopover />,\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const trigger = canvas.getByText('Click me!');\n\n    await step('Open popover', async () => {\n      trigger.focus();\n      await userEvent.keyboard('{Enter}');\n      await expect(screen.queryByText('Lorem ipsum dolor sit amet')).toBeInTheDocument();\n    });\n\n    await step('Press Tab to enter popover', async () => {\n      await userEvent.tab();\n      const continueButton = await screen.findByText('Continue');\n      await expect(continueButton).toHaveFocus();\n    });\n\n    await step('Press Esc to close popover', async () => {\n      await userEvent.keyboard('{Escape}');\n      await expect(canvas.queryByText('Lorem ipsum dolor sit amet')).not.toBeInTheDocument();\n    });\n  },\n});\n\nexport const InteractivePopoverMouse = meta.story({\n  args: {\n    children: <Trigger>Click me!</Trigger>,\n    popover: <SamplePopover />,\n  },\n  render: (args) => (\n    <div>\n      <PopoverProvider {...args} />\n      <button>Sibling Button</button>\n    </div>\n  ),\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n\n    await step('Open popover', async () => {\n      const trigger = canvas.getByText('Click me!');\n      await userEvent.click(trigger);\n      await expect(screen.queryByText('Lorem ipsum dolor sit amet')).toBeInTheDocument();\n    });\n\n    await step('Click outside popover to close it', async () => {\n      const sibling = canvas.getByText('Sibling Button');\n      await userEvent.click(sibling);\n      await expect(screen.queryByText('Lorem ipsum dolor sit amet')).not.toBeInTheDocument();\n    });\n  },\n});\n\nexport const WithLongContent = meta.story({\n  args: {\n    children: <Trigger>Long content</Trigger>,\n    popover: (\n      <div style={{ maxWidth: '300px', padding: '8px' }}>\n        <h3 style={{ margin: '0 0 8px 0' }}>Very Long Tooltip Content</h3>\n        <p style={{ margin: '0', fontSize: '12px', lineHeight: '1.4' }}>\n          This is a very long popover that demonstrates how the popover component handles extensive\n          content. It should wrap properly and maintain good readability even with multiple lines of\n          text. The popover positioning should also adapt to ensure it remains visible within the\n          viewport boundaries.\n        </p>\n      </div>\n    ),\n  },\n});\n"
  },
  {
    "path": "code/core/src/components/components/Popover/PopoverProvider.tsx",
    "content": "import type { DOMAttributes, ReactElement, ReactNode } from 'react';\nimport React, { cloneElement, useCallback, useState } from 'react';\n\nimport { deprecate } from 'storybook/internal/client-logger';\n\nimport { Pressable } from '@react-aria/interactions';\nimport { DialogTrigger } from 'react-aria-components/patched-dist/Dialog';\nimport { Popover as PopoverUpstream } from 'react-aria-components/patched-dist/Popover';\n\nimport { type PopperPlacement, convertToReactAriaPlacement } from '../shared/overlayHelpers.tsx';\nimport { Popover } from './Popover.tsx';\n\nexport interface PopoverProviderProps {\n  /**\n   * An accessible label for the popover dialog, announced by screen readers. This prop will become\n   * mandatory in Storybook 11. Provide a concise description of the popover's purpose.\n   */\n  ariaLabel?: string;\n\n  /** Whether to display the Popover in a prestyled container. True by default. */\n  hasChrome?: boolean;\n\n  /**\n   * Whether to display a close button in the top right corner of the popover overlay. Can overlap\n   * with overlay content, make sure to test your use case. False by default.\n   */\n  hasCloseButton?: boolean;\n\n  /** Optional custom label for the close button, if there is one. */\n  closeLabel?: string;\n\n  /** Optional custom padding for the popover overlay. */\n  padding?: number | string;\n\n  /** Distance between the trigger and Popover. Customize only if you have a good reason to. */\n  offset?: number;\n\n  /**\n   * Placement of the Popover. Start and End variants involve additional JS dimension calculations\n   * and should be used sparingly. Left and Right get inverted in RTL.\n   */\n  placement?: PopperPlacement;\n\n  /**\n   * Popover content. Pass a function to receive a onHide callback to collect to your close button,\n   * or if you want to wait for the popover to be opened to call your content component.\n   */\n  popover: ReactNode | ((props: { onHide: () => void }) => ReactNode);\n\n  /** Popover trigger, must be a single child with click/press events. Must forward refs. */\n  children: ReactElement<DOMAttributes<Element>, string>;\n\n  /** Uncontrolled state: whether the Popover is initially visible. */\n  defaultVisible?: boolean;\n\n  /** Controlled state: whether the Popover is visible. */\n  visible?: boolean;\n\n  /** Controlled state: fires when user interaction causes the Popover to change visibility. */\n  onVisibleChange?: (isVisible: boolean) => void;\n}\n\nexport const PopoverProvider = ({\n  ariaLabel,\n  placement: placementProp = 'bottom-start',\n  hasChrome = true,\n  hasCloseButton = false,\n  closeLabel,\n  offset = 8,\n  padding,\n  popover,\n  children,\n  defaultVisible,\n  visible,\n  onVisibleChange,\n  ...props\n}: PopoverProviderProps) => {\n  if (!ariaLabel) {\n    deprecate(\n      \"The 'ariaLabel' prop on 'PopoverProvider' will become mandatory in Storybook 11. Provide a concise, accessible label describing the popover's purpose.\"\n    );\n  }\n\n  // Map Popper.js placement to react-aria placement best we can.\n  const placement = convertToReactAriaPlacement(placementProp);\n\n  const [isOpen, setIsOpen] = useState(defaultVisible ?? false);\n  const onOpenChange = useCallback(\n    (isOpen: boolean) => {\n      setIsOpen(isOpen);\n      onVisibleChange?.(isOpen);\n    },\n    [onVisibleChange]\n  );\n  const onHide = useCallback(() => onOpenChange(false), [onOpenChange]);\n\n  return (\n    <DialogTrigger\n      defaultOpen={defaultVisible}\n      isOpen={visible ?? isOpen}\n      onOpenChange={onOpenChange}\n      {...props}\n    >\n      <Pressable>\n        {\n          /* React-aria does not inject aria-haspopup='dialog' to support legacy screen readers, so we do it ourselves. */\n          cloneElement(\n            children,\n            // @ts-expect-error aria-haspopup is a valid ARIA attribute but cloneElement types are too strict\n            { 'aria-haspopup': 'dialog' }\n          )\n        }\n      </Pressable>\n      <PopoverUpstream\n        aria-label={ariaLabel}\n        placement={placement}\n        offset={offset}\n        style={{ outline: 'none' }}\n      >\n        <Popover\n          hasChrome={hasChrome}\n          hideLabel={closeLabel}\n          onHide={hasCloseButton ? onHide : undefined}\n          padding={padding}\n        >\n          {typeof popover === 'function' ? popover({ onHide }) : popover}\n        </Popover>\n      </PopoverUpstream>\n    </DialogTrigger>\n  );\n};\n"
  },
  {
    "path": "code/core/src/components/components/ProgressSpinner/ProgressSpinner.stories.tsx",
    "content": "import React from 'react';\n\nimport { StopAltIcon } from '@storybook/icons';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { ProgressSpinner } from './ProgressSpinner.tsx';\n\nconst meta = {\n  component: ProgressSpinner,\n} satisfies Meta<typeof ProgressSpinner>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Forty: Story = {\n  args: {\n    percentage: 40,\n  },\n};\n\nexport const Seventy: Story = {\n  args: {\n    percentage: 70,\n  },\n};\n\nexport const Zero: Story = {\n  args: {\n    percentage: 0,\n  },\n};\n\nexport const Small: Story = {\n  args: {\n    percentage: 40,\n    size: 16,\n  },\n};\n\nexport const Thick: Story = {\n  args: {\n    percentage: 40,\n    width: 3,\n  },\n};\n\nexport const Paused: Story = {\n  args: {\n    percentage: 40,\n    running: false,\n  },\n};\n\nexport const Colored: Story = {\n  args: Forty.args,\n  decorators: [\n    (Story) => (\n      <div style={{ color: 'hotpink' }}>\n        <Story />\n      </div>\n    ),\n  ],\n};\n\nexport const WithContent: Story = {\n  ...Colored,\n  args: {\n    ...Colored.args,\n    children: <StopAltIcon size={10} />,\n  },\n};\n"
  },
  {
    "path": "code/core/src/components/components/ProgressSpinner/ProgressSpinner.tsx",
    "content": "import React, { type ComponentProps } from 'react';\n\nimport { keyframes, styled } from 'storybook/theming';\n\nconst XMLNS = 'http://www.w3.org/2000/svg';\n\nconst rotate = keyframes({\n  '0%': {\n    transform: 'rotate(0deg)',\n  },\n  '100%': {\n    transform: 'rotate(360deg)',\n  },\n});\n\nconst Wrapper = styled.div<{ size: number }>(({ size }) => ({\n  display: 'inline-flex',\n  alignItems: 'center',\n  justifyContent: 'center',\n  position: 'relative',\n  minWidth: size,\n  minHeight: size,\n}));\n\nconst Circle = styled.svg<{ size: number; width: number; progress?: boolean; spinner?: boolean }>(\n  ({ size, width }) => ({\n    position: 'absolute',\n    width: `${size}px!important`,\n    height: `${size}px!important`,\n    transform: 'rotate(-90deg)',\n    circle: {\n      r: (size - Math.ceil(width)) / 2,\n      cx: size / 2,\n      cy: size / 2,\n      opacity: 0.15,\n      fill: 'transparent',\n      stroke: 'currentColor',\n      strokeWidth: width,\n      strokeLinecap: 'round',\n      strokeDasharray: Math.PI * (size - Math.ceil(width)),\n    },\n  }),\n  ({ progress }) =>\n    progress && {\n      circle: {\n        opacity: 0.75,\n      },\n    },\n  ({ spinner }) =>\n    spinner && {\n      animation: `${rotate} 1s linear infinite`,\n      circle: {\n        opacity: 0.25,\n      },\n    }\n);\n\ninterface ProgressSpinnerProps extends Omit<ComponentProps<typeof Wrapper>, 'size'> {\n  percentage?: number;\n  running?: boolean;\n  size?: number;\n  width?: number;\n  children?: React.ReactNode;\n}\n\nexport const ProgressSpinner = ({\n  percentage = undefined,\n  running = true,\n  size = 24,\n  width = 1.5,\n  children = null,\n  ...props\n}: ProgressSpinnerProps) =>\n  typeof percentage === 'number' ? (\n    <Wrapper size={size} {...props}>\n      {children}\n      <Circle size={size} width={width} xmlns={XMLNS}>\n        <circle />\n      </Circle>\n      {running && (\n        <Circle size={size} width={width} xmlns={XMLNS} spinner>\n          <circle strokeDashoffset={Math.PI * (size - Math.ceil(width)) * (1 - percentage / 100)} />\n        </Circle>\n      )}\n      <Circle size={size} width={width} xmlns={XMLNS} progress>\n        <circle strokeDashoffset={Math.PI * (size - Math.ceil(width)) * (1 - percentage / 100)} />\n      </Circle>\n    </Wrapper>\n  ) : (\n    <Wrapper size={size} {...props}>\n      {children}\n    </Wrapper>\n  );\n"
  },
  {
    "path": "code/core/src/components/components/ScrollArea/ScrollArea.stories.tsx",
    "content": "import type { ReactElement } from 'react';\nimport React, { Fragment } from 'react';\n\nimport { styled } from 'storybook/theming';\n\nimport { ScrollArea } from './ScrollArea.tsx';\n\nconst Block = styled.span({\n  display: 'inline-block',\n  height: 40,\n  width: 40,\n  border: '1px solid silver',\n  lineHeight: '40px',\n  textAlign: 'center',\n  fontSize: 9,\n});\n\nconst Wrapper = styled.div({\n  whiteSpace: 'nowrap',\n  lineHeight: '0px',\n  width: 500,\n  height: 500,\n  overflow: 'hidden',\n});\n\nconst list = (filler: (data: number) => ReactElement) => {\n  const data = [];\n\n  for (let i = 0; i < 20; i++) {\n    data.push(filler(i));\n  }\n\n  return data;\n};\n\nexport default {\n  component: ScrollArea,\n  decorators: [(storyFn: () => any) => <Wrapper>{storyFn()}</Wrapper>],\n};\n\nexport const Vertical = () => (\n  <ScrollArea vertical>\n    {list((i) => (\n      <Fragment key={i}>\n        <Block>{i}</Block>\n        <br />\n      </Fragment>\n    ))}\n  </ScrollArea>\n);\n\nexport const Horizontal = () => (\n  <ScrollArea horizontal>\n    <div style={{ padding: 5 }}>\n      {list((i) => (\n        <Block key={i}>{i}</Block>\n      ))}\n    </div>\n  </ScrollArea>\n);\n\nexport const Both = () => (\n  <ScrollArea horizontal vertical>\n    {list((i) => (\n      <Fragment key={i}>\n        {list((ii) => (\n          <Block key={ii}>{ii * i}</Block>\n        ))}\n        <br />\n      </Fragment>\n    ))}\n  </ScrollArea>\n);\n\nexport const Neither = () => (\n  <ScrollArea>\n    {list((i) => (\n      <Fragment key={i}>\n        {list((ii) => (\n          <Block key={ii}>{ii * i}</Block>\n        ))}\n        <br />\n      </Fragment>\n    ))}\n  </ScrollArea>\n);\n\nexport const WithOuterBorder = () => (\n  <ScrollArea horizontal vertical>\n    <div\n      style={{\n        width: 2000,\n        height: 2000,\n        border: '10px solid orangered',\n        background: `url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAM4klEQVR4Xu2d224ktxGGayTN6LTrOO//PMmlAfvOgIEkFwEcZ71a7ep8muBjd2k4re4eVpHsaS1CeKH1is1u1s86slhcrP/261r62oGInB6LLBbNb8+PRQ75x/+3bArcPYh8vu4dZjEMyELk7Hjz0JwBYdGEddMuHmnXWPixDv/NqrkAOVw0HKJtDoAcHTZcerAQOTgQ4Rv5+ysQHbKvWyReAGUt8vIi8vQi8vzS/H1fQD08iny6MnLIG0BOGgJM2SD68lAEIPhZuj09i9w/ijw+lx55fDze+8dXKyDokJP9cAjEP142QEzR4B645v5J5PGp/hsfnkQ+fTMCcrQQOZlYZAEAolENifqkefsGRNnNgwiruFZDZP153YjRThtW6suFyPFEgKAHzhGJM7LiAOb6vuGc0s0FyOpAZLXafMqHk1aBFv46RNPJcr9cMTiltcjtY6NnSrb7h4ZDetowh6wORVbLuoBgVq+OSk61zliIr6u7cmPf3olc3OYCctyYmqUaIqqG5VTq+7rjILoApUfum195+yByYeWQ4yORZbR6P56UEyuIv6ksKDO1Rh6AU9AruaDc3Yt8vjFyCHI9JlopQBj3JNJNJQk2xVgoZKywnOZS6hDtqBVR+IMfTgcd4uRvQ0Qhqt57Q+TkKHoA+Xor8vDWtB5W6oRN1DPHL0DM5DjqjPEDoOYMMhMkEVkQ1Cu6Apc9igBsZ4w0QIKfkOmwna4a7/t7aTmWF4DcPYkQY+uAMgLIauOo4bABiLdhncEd31v7etMQ1doUEJ57Xovgl7TjLNZ/Zz8EMcLAiw0L4SOESKo0yv0sQxF/b9yhAHi5hHgZDqc2wHh+DuGaxfrnf62bMHS7b6Ay7fRI5PCwCVPz83TZYBb+tOHsGMCxVfLDWR0v37oya/T3cEkXkOi7GkD6Wrz/sTwQOYusoz4AlXVBOuw9wHjtvgUGQQCxBbMGYfY1psfigrMGTOd+QJBUHyOZj7ka7x5aJo//gg7aArEdIGwcsVHUAsg/62ZSzI2W903dl2+/7HfyBj+FTbKb+95f9wNyzH5EpDOIa8W7h6mThkN+PEvtvekXxGar1/grYpOx4p0/5Uj9vQJI38CdMr6baP+q4Se+3dqiwiZAmPj5ajtuRRjF413jWMacVpII8Vh3jyJs+oStWdVvrb7DlyJIyl6Xghj6RPow97uu72y7jlhWPNPTtjkEqyq2rvQBL4cApFfUpRIJ1menb1fD0iNso0112qsxwy8iPQe4arwELhzRgXjt6JLUlgQIYPDRfZtEXg7pEiH1g1P7QYjUuJKGfzQclPqOGMBYjMYJFIB3cbUxXLb0YI/NNArIr/9eBz8jpNIMhDVYWR4v+8PxdsTYSoRd/QlfWHb0mCdGRo2GYo+dxC09GIlISKwLCYMmFqOLhSzW//hjt6vJSvdsJDH5WmF2vvqSfWkDdb1GRsorLIuDLJdBKysJEHb2jBkgajrX2ieHMyCCtdVaJFhaWE8pDQNkQOekcQiK2bq7ByDEr0ruMsaTxbn65thWRfzC8aWbBZBsDmEPw6oMAyAVQyZeDkH05gRKh4BkcaSmDu0NkL+c1dv/wAG8dIgsOJ1QTunGfntqBmS2yGICHl2AyPI8l0osiyLVMWsBwl47hE5pewME0eCxzlImRR+4JOzcpT4gzffUEFnvApBak4/pj7VC6CS11YgesCAQWbPWIRAIcTXFTqFldWJskN6E6NKjDZZ9fg1matyMnwBh2TkkueF2KNqb4ofA4h4Hj3AMltYUeQ0WUPq4KRwziQ7+6P/TN96UsxB+iGuzrSyvUueDait2nTREIyTB6SSLTkkVdSX74UAORntTOCQHkKlC8EowzS4ssZJLghCPpWmpPeOneersaWjCg/UjNR/L+7z1fUHEtOk1KWF5z/i5z+QDwlGEjETr2mH4MVmNCEuNMeUSOvX5bEBKZBzitU/JJTFxMIvnpFuyAEHklEi0rmH/p67I4ESSkNYevtm30s8ChFVdItEaomAcWKPGFqKn9IUY7DKGdKWUByr0UcPDpdQDIIXOhkzpl+yiI75AibMeu97T9/sss7ckIHxcreCehzBYY+gXrDFvJrvnvVmOIeGF0uFq9udzcoU9RBh7BjFW68Rt33uzAMGxq3HIhlxhT65XaTB0PPRJCItzZK3WS9pxs8LvOWmku+ZVazt113t3cQsJCDV9lyxAanGIEgVzOJSByqFihWdTE/A8r84CpCaH6GQAvZRp7SHQ0DMQDmBKi7AsHeJNI7USBuMBRe8J81vfZelfI1iZBYg3jdQyae2L2JrjaSu8fNJ8SkWQs/yQKQEBGEBRU9uyk+dZAJZnNNxRApSs0Ik3r9cy2b6+gKEprHNR+KzsK2NSRXFP3ZvXmwvIlsIvFLop8U160DNH0WdxiCeNtMTE4zHgliA6Z1LGKdckzgJk3xwSAzMnS8yTpKdzyQJkDhyyxS0ofdJBMytL5HIxpqu3hlZW+N2TaJ072ZTng9JfNucH96X0valHWRzizclKIWqJPmoi72N72HskIguQnBSgEgRPGUOVfo1zH7veb8l617GyHMP3AIhONMTdOke6dxE09/ceXZIFiFeHIELIoSVw+Jqi2aZrdokQl90go51TqvrTupOnSRk1j0HE34/nTr0Ti1+SFcvy6JCSm0+hUk6b0MxEUk7dAgqcUvMoRAyKVWxlAeIRWbUOVmolt9R4Uu1j2QoKYXosrtQ2OSC1Eqy10ItFPJAGaz0fmUrY2NGznAjO0iEeDqmVpQggX4yVd6Y4owLHWioCZQHiSbSeEyCs4tq5xXDsl/7CyL3MluWHoA8sidZ4zbVO33o4BIpMcSSiW1pjTOxlcYg10TpkJ1YsB8tKtOgQCBMWyXndEIulcIA7lqUVdCxhidqAeKOstZW7xfTVLeEeLho/sONJtK6dv+sN6NVO9DYB8jJYFmQcEK3Xa9nbhqt+PLcajun9LTWy4lFrmeL6jskA8eT11rKymLwnwlrT0FBALDrELbL0Tqj09dv0rO0hW/UIuWU18pNjuhDPIgaX0txmrzdrsXZ2OxNiRabMv3bdLgUAhzU1EOo2e72A1CylpwQgHkSm+tiqBAyCo/HFNCkr2NrH6qm7OcSbaE1pVio4TNEABkUfqoi2Pke4kJI/lEvPOD2c+v1WQ8MNiJdDahcvSyXUVP2sOm3UMfzt940kDuYtVaHZVKKUkbOiNYTY96nbqcBIFVdxIkZ8vvG1fnATUlisf9Fi/O1VFaGA/kKEmz45IuAthFzbQbQQPC7Zqs+peFMfKy6aTB99pk9RhyXcVtDm2gntExN9zOBQpR4fo2uZYfh2BN55ciTy14+2/YR48iFcQU3gDvW0uo7WdG/nt+mls4nuMwm3O7dE0OeZRJdg+m9D1ahfpUD7UWOETwGdIjLWRauA9JzUWqx/+mc7+3bJMHFFn5wnCvNzSXH3pmgmEk8+vuGg4b62Xlak3LfYM2W2M+8Trp24t9e3xzIkaTu+c7ctZT585VHQA8tNoS9vWbz3emfhzrXQXgymAdid/aMOamUBCPrkkcsEmhvb0gChp/cuXHQJossSD7NMbl999bibxzVQQIh/8SfKERgHJL5ckhdbZaUS671fJtkFHbGukQJPeElTh7hTvVNadhyQ+LaE3Kvz3stFxCkcF1/ggvNpLYIAIJ8uRS7fFs5MByT36rxwOSWXVRpryKcQaLI+XMRyv72qPUf+sJ9+vxC54jz89m2fO0RWdP1q7tV5anl93GPdrCzg1o1V1C2W7Dny97QW+c/FtpXVfpsBkAwdEhMCqyScOXkH96jH3z1UlxdxZZ0LoP73a2MydypGTKPU+1ZmUPRcQbSvwx2J7KKFaYJ/1tM8qbbc7PnpqrfgTboOIZQS32WYOJ/RbsFQcNaVL/H+XWNQFpBI7lgYxJomxTsZ989cQAhne67O2zVpfk9SNMpxLgo/3MS5uZ92dAqelCcFpOOD7HYMY7N3dSByknFBcQow4VAnltgEexjd7yGsE8r/3dsqNowBwniUEiQEFTc21j5fN5knnVjcuMiKr9DrXjaZQmBvnxBtPmzCNnphmXessec0WEnEFq7wNBI6+hpcgPJG3MH9hKE0WvEKyNtt6B2ARKeRpgSkO8Fw+KcFJxTRdBgC8UqEUPyJL6H0gKEbcfGzKP9QZLNjBMQe/c2dyMWNg0PiS+0JxXdZzzOJEs+8Fs5v92505cXxMo0+h7C9vrS9vq7ENzCGxul0vHBP+ogRoM41HAIgZh0SA8KpKKu9XWricx1HM1r4Pjz4LfAHPlq3LEgbClVRt/ul65A51rKaA1Ca95x6qotvRmR96b8/axiQ4FFT9KWdNQq+9kmkORB4im9wAaJ346pcDg6cQ5lOMcH39g7VIT3f/T+lOOGi/Z/IjAAAAABJRU5ErkJggg==')`,\n      }}\n    />\n  </ScrollArea>\n);\n\nexport const CustomOffset = () => (\n  <ScrollArea horizontal vertical offset={20}>\n    {list((i) => (\n      <Fragment key={i}>\n        {list((ii) => (\n          <Block key={ii}>{ii * i}</Block>\n        ))}\n        <br />\n      </Fragment>\n    ))}\n  </ScrollArea>\n);\n\nexport const CustomSize = () => (\n  <ScrollArea horizontal vertical scrollbarSize={20}>\n    {list((i) => (\n      <Fragment key={i}>\n        {list((ii) => (\n          <Block key={ii}>{ii * i}</Block>\n        ))}\n        <br />\n      </Fragment>\n    ))}\n  </ScrollArea>\n);\n\nexport const FocusableVertical = () => (\n  <ScrollArea vertical focusable>\n    {list((i) => (\n      <Fragment key={i}>\n        <Block>{i}</Block>\n        <br />\n      </Fragment>\n    ))}\n  </ScrollArea>\n);\n\nexport const FocusableHorizontal = () => (\n  <ScrollArea horizontal focusable>\n    <div style={{ padding: 5 }}>\n      {list((i) => (\n        <Block key={i}>{i}</Block>\n      ))}\n    </div>\n  </ScrollArea>\n);\n\nexport const FocusableBoth = () => (\n  <ScrollArea horizontal vertical focusable>\n    {list((i) => (\n      <Fragment key={i}>\n        {list((ii) => (\n          <Block key={ii}>{ii * i}</Block>\n        ))}\n        <br />\n      </Fragment>\n    ))}\n  </ScrollArea>\n);\n"
  },
  {
    "path": "code/core/src/components/components/ScrollArea/ScrollArea.tsx",
    "content": "import React, { forwardRef } from 'react';\n\nimport * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';\nimport { styled } from 'storybook/theming';\n\nexport interface ScrollAreaProps {\n  children?: React.ReactNode;\n  horizontal?: boolean;\n  vertical?: boolean;\n  className?: string;\n  offset?: number;\n  scrollbarSize?: number;\n  scrollPadding?: number | string;\n  /**\n   * Set this to define a tabIndex on the scrollable content; only needed when content has no\n   * interactive elements.\n   */\n  focusable?: boolean;\n}\n\nconst ScrollAreaRoot = styled(ScrollAreaPrimitive.Root)<{ scrollbarsize: number; offset: number }>(\n  ({ scrollbarsize, offset }) => ({\n    width: '100%',\n    height: '100%',\n    overflow: 'hidden',\n    '--scrollbar-size': `${scrollbarsize + offset}px`,\n    '--radix-scroll-area-thumb-width': `${scrollbarsize}px`,\n  })\n);\n\nconst ScrollAreaViewport = styled(ScrollAreaPrimitive.Viewport)<{ focusable: boolean }>(\n  ({ focusable, theme }) => ({\n    width: '100%',\n    height: '100%',\n    '&:focus': focusable\n      ? {\n          outline: `2px solid ${theme.color.secondary}`,\n          outlineOffset: -2,\n        }\n      : {},\n  })\n);\n\nconst ScrollAreaScrollbar = styled(ScrollAreaPrimitive.Scrollbar)<{\n  offset: number;\n  horizontal: string;\n  vertical: string;\n}>(({ offset, horizontal, vertical }) => ({\n  display: 'flex',\n  userSelect: 'none', // ensures no selection\n  touchAction: 'none', // disable browser handling of all panning and zooming gestures on touch devices\n  background: 'transparent',\n  transition: 'all 0.2s ease-out',\n  borderRadius: 'var(--scrollbar-size)',\n  zIndex: 1,\n\n  '&[data-orientation=\"vertical\"]': {\n    width: 'var(--scrollbar-size)',\n    paddingRight: offset,\n    marginTop: offset,\n    marginBottom: horizontal === 'true' && vertical === 'true' ? 0 : offset,\n  },\n  '&[data-orientation=\"horizontal\"]': {\n    flexDirection: 'column',\n    height: 'var(--scrollbar-size)',\n    paddingBottom: offset,\n    marginLeft: offset,\n    marginRight: horizontal === 'true' && vertical === 'true' ? 0 : offset,\n  },\n}));\n\nconst ScrollAreaThumb = styled(ScrollAreaPrimitive.Thumb)(({ theme }) => ({\n  flex: 1,\n  background: theme.textMutedColor,\n  opacity: 0.5,\n  borderRadius: `var(--scrollbar-size)`,\n  position: 'relative',\n  transition: 'opacity 0.2s ease-out',\n  zIndex: 1,\n\n  '&:hover': { opacity: 0.8 },\n\n  /* increase target size for touch devices https://www.w3.org/WAI/WCAG21/Understanding/target-size.html */\n  '::before': {\n    content: '\"\"',\n    position: 'absolute',\n    top: '50%',\n    left: '50%',\n    transform: 'translate(-50%,-50%)',\n    width: '100%',\n    height: '100%',\n  },\n}));\n\nexport const ScrollArea = forwardRef<HTMLDivElement, ScrollAreaProps>(\n  (\n    {\n      children,\n      horizontal = false,\n      vertical = false,\n      offset = 2,\n      scrollbarSize = 6,\n      scrollPadding = 0,\n      className,\n      focusable = false,\n    },\n    ref\n  ) => (\n    <ScrollAreaRoot scrollbarsize={scrollbarSize} offset={offset} className={className}>\n      <ScrollAreaViewport\n        ref={ref}\n        style={{ scrollPadding }}\n        tabIndex={focusable ? 0 : undefined}\n        focusable={focusable}\n      >\n        {children}\n      </ScrollAreaViewport>\n      {horizontal && (\n        <ScrollAreaScrollbar\n          orientation=\"horizontal\"\n          offset={offset}\n          horizontal={horizontal.toString()}\n          vertical={vertical.toString()}\n        >\n          <ScrollAreaThumb />\n        </ScrollAreaScrollbar>\n      )}\n      {vertical && (\n        <ScrollAreaScrollbar\n          orientation=\"vertical\"\n          offset={offset}\n          horizontal={horizontal.toString()}\n          vertical={vertical.toString()}\n        >\n          <ScrollAreaThumb />\n        </ScrollAreaScrollbar>\n      )}\n      {horizontal && vertical && <ScrollAreaPrimitive.Corner />}\n    </ScrollAreaRoot>\n  )\n);\nScrollArea.displayName = 'ScrollArea';\n"
  },
  {
    "path": "code/core/src/components/components/Select/Select.stories.tsx",
    "content": "import React from 'react';\n\nimport { Button, Toolbar } from 'storybook/internal/components';\n\nimport { LinuxIcon } from '@storybook/icons';\n\nimport type { StoryAnnotations } from 'core/src/types';\nimport { expect, fn, screen, userEvent, within } from 'storybook/test';\nimport { styled } from 'storybook/theming';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { Select } from './Select.tsx';\n\nconst meta = preview.meta({\n  id: 'select-component',\n  title: 'Select',\n  component: Select,\n  args: {\n    ariaLabel: 'Animal',\n    children: 'Animal',\n    icon: <LinuxIcon />,\n    onChange: fn(),\n    onSelect: fn(),\n    onDeselect: fn(),\n    options: [\n      { title: 'Tadpole', value: 'tadpole' },\n      { title: 'Pollywog', value: 'pollywog' },\n      { title: 'Frog', value: 'frog' },\n    ],\n  },\n  tags: ['!vitest'],\n});\n\nconst Stack = styled.div({ display: 'flex', flexDirection: 'column', gap: '1rem' });\n\nconst Row = styled.div({ display: 'flex', alignItems: 'center', gap: '1rem' });\n\nexport const Base = meta.story({});\n\nexport const Sizes = meta.story({\n  render: (args) => (\n    <Stack>\n      <Row>\n        <Select size=\"small\" {...args}>\n          Small\n        </Select>\n        <Select size=\"medium\" {...args}>\n          Medium\n        </Select>\n      </Row>\n    </Stack>\n  ),\n});\n\nexport const Paddings = meta.story({\n  render: (args) => (\n    <Stack>\n      <Row>\n        <Select padding=\"none\" {...args}>\n          No Padding\n        </Select>\n        <Select padding=\"small\" {...args}>\n          Small Padding\n        </Select>\n        <Select padding=\"medium\" {...args}>\n          Medium Padding\n        </Select>\n      </Row>\n    </Stack>\n  ),\n});\n\nexport const PseudoStates = meta.story({\n  args: {\n    options: [{ title: 'Frog', value: 'frog' }],\n  },\n  render: (args) => (\n    <Stack>\n      <Row style={{ marginBlock: '4rem' }}>\n        <h4>Inactive</h4>\n        <Select {...args}>Unset</Select>\n        <Select {...args} defaultOptions={['frog']}>\n          Set\n        </Select>\n        <Select {...args} defaultOptions={['frog']} disabled>\n          Override\n        </Select>\n        <Select {...args} defaultOpen>\n          Open\n        </Select>\n      </Row>\n      <Row className=\"hover\" style={{ marginBlock: '4rem' }}>\n        <h4>Hover</h4>\n        <Select {...args}>Unset</Select>\n        <Select {...args} defaultOptions={['frog']}>\n          Set\n        </Select>\n        <Select {...args} defaultOptions={['frog']} disabled>\n          Override\n        </Select>\n        <Select {...args} defaultOpen>\n          Open\n        </Select>\n      </Row>\n      <Row className=\"focus\" style={{ marginBlock: '4rem' }}>\n        <h4>Focus</h4>\n        <Select {...args}>Unset</Select>\n        <Select {...args} defaultOptions={['frog']}>\n          Set\n        </Select>\n        <Select {...args} defaultOptions={['frog']} disabled>\n          Override\n        </Select>\n        <Select {...args} defaultOpen>\n          Open\n        </Select>\n      </Row>\n    </Stack>\n  ),\n  parameters: {\n    pseudo: {\n      hover: '.hover button',\n      focus: '.focus button',\n      focusVisible: '.focus button',\n      active: '.active button',\n    },\n  },\n});\n\nexport const ManyOptions = meta.story({\n  args: {\n    options: Array.from({ length: 20 }, (_, i) => ({\n      title: `Option ${i + 1}`,\n      value: `option-${i + 1}`,\n    })),\n  },\n});\n\nexport const LongOptionLabels = meta.story({\n  name: 'Long Option Labels',\n  args: {\n    children: 'Long labels',\n    options: [\n      {\n        title: 'This is a very long option label that might cause wrapping issues',\n        value: 'long1',\n      },\n      {\n        title:\n          'Another extremely long option label that tests how the component handles overflow, and if you think that is too long, you may well be justified in thinking so, albeit it is a test case',\n        value: 'long2',\n      },\n      { title: 'Short', value: 'short' },\n    ],\n  },\n});\n\nexport const CustomOptionRendering = meta.story({\n  name: 'Custom Option Rendering',\n  args: {\n    children: 'Custom options',\n    options: [\n      {\n        title: 'Tadpole',\n        value: 'tadpole',\n        children: (\n          <>\n            <strong>1. </strong> 👶 Tadpole\n          </>\n        ),\n      },\n      {\n        title: 'Pollywog',\n        value: 'pollywog',\n        children: (\n          <>\n            <strong>2. </strong> 👧 Pollywog\n          </>\n        ),\n      },\n      {\n        title: 'Frog',\n        value: 'frog',\n        children: (\n          <>\n            <strong>3. </strong> 🐸 Frog\n          </>\n        ),\n      },\n    ],\n  },\n});\n\nexport const WithSiblings = meta.story({\n  render: (args) => (\n    <Row>\n      <Button ariaLabel={false}>Before</Button>\n      <Select {...args} />\n      <Button ariaLabel={false}>After</Button>\n    </Row>\n  ),\n  play: async ({ canvas, step }) => {\n    const user = userEvent.setup();\n\n    await step('Open select and select an option', async () => {\n      const select = canvas.getByRole('button', { name: /Animal/i });\n      await user.click(select);\n\n      const listbox = await screen.findByRole('listbox');\n      expect(listbox).toBeInTheDocument();\n\n      const option = within(listbox).getByRole('option', { name: 'Frog' });\n      await user.click(option);\n    });\n\n    await step('Tab should land on sibling after select', async () => {\n      const select = canvas.getByRole('button', { name: /Frog/i });\n      expect(select).toHaveFocus();\n\n      await user.tab();\n\n      const afterButton = canvas.getByRole('button', { name: 'After' });\n      expect(afterButton).toHaveFocus();\n    });\n\n    await step('Navigate back and reopen select', async () => {\n      await user.tab({ shift: true });\n\n      const select = canvas.getByRole('button', { name: /Frog/i });\n      expect(select).toHaveFocus();\n\n      await user.keyboard('{Enter}');\n\n      const listbox = await screen.findByRole('listbox');\n      expect(listbox).toBeInTheDocument();\n    });\n\n    await step('Escape should return to select trigger', async () => {\n      await user.keyboard('{Escape}');\n\n      const select = canvas.getByRole('button', { name: /Frog/i });\n      expect(select).toHaveFocus();\n    });\n  },\n});\n\nexport const WithSiblingsInToolbar = meta.story({\n  name: 'With Siblings in Toolbar',\n  render: (args) => (\n    <Toolbar aria-label=\"Test toolbar\">\n      <Button ariaLabel=\"Before button\">Before</Button>\n      <Select {...args} />\n      <Button ariaLabel=\"After button\">After</Button>\n    </Toolbar>\n  ),\n  play: async ({ canvas, step }) => {\n    const user = userEvent.setup();\n\n    await step('Navigate to select with ArrowRight', async () => {\n      const beforeButton = canvas.getByRole('button', { name: 'Before button' });\n      beforeButton.focus();\n      expect(beforeButton).toHaveFocus();\n\n      await user.keyboard('{ArrowRight}');\n\n      const select = canvas.getByRole('button', { name: /Animal/i });\n      expect(select).toHaveFocus();\n    });\n\n    await step('Open select and select an option', async () => {\n      await user.keyboard('{Enter}');\n\n      const listbox = await screen.findByRole('listbox');\n      expect(listbox).toBeInTheDocument();\n\n      const option = within(listbox).getByRole('option', { name: 'Frog' });\n      await user.click(option);\n    });\n\n    await step('ArrowRight should land on sibling after select', async () => {\n      const select = canvas.getByRole('button', { name: /Frog/i });\n      expect(select).toHaveFocus();\n\n      await user.keyboard('{ArrowRight}');\n\n      const afterButton = canvas.getByRole('button', { name: 'After button' });\n      expect(afterButton).toHaveFocus();\n    });\n\n    await step('Navigate back with ArrowLeft and reopen select', async () => {\n      await user.keyboard('{ArrowLeft}');\n\n      const select = canvas.getByRole('button', { name: /Frog/i });\n      expect(select).toHaveFocus();\n\n      await user.keyboard('{Enter}');\n\n      const listbox = await screen.findByRole('listbox');\n      expect(listbox).toBeInTheDocument();\n    });\n\n    await step('Escape should return to select trigger', async () => {\n      await user.keyboard('{Escape}');\n\n      const select = canvas.getByRole('button', { name: /Frog/i });\n      expect(select).toHaveFocus();\n    });\n  },\n});\n\nexport const DefaultOption = meta.story({\n  name: 'Default Option (single)',\n  args: {\n    defaultOptions: 'frog',\n  },\n});\n\nexport const DefaultOptionMulti = meta.story({\n  name: 'Default Option (multi)',\n  args: {\n    multiSelect: true,\n    defaultOptions: ['tadpole', 'frog'],\n  },\n});\n\nconst disabledPlayFn: StoryAnnotations['play'] = async ({ canvasElement, args }) => {\n  const canvas = within(canvasElement);\n  const selectButton = await canvas.findByRole('button');\n  expect(selectButton).toHaveAttribute('aria-disabled', 'true');\n\n  await userEvent.click(selectButton);\n  expect(canvas.queryByRole('listbox')).not.toBeInTheDocument();\n  expect(args.onSelect).not.toHaveBeenCalled();\n  expect(args.onChange).not.toHaveBeenCalled();\n};\n\nexport const Disabled = meta.story({\n  args: {\n    disabled: true,\n  },\n  play: disabledPlayFn,\n});\n\nexport const DisabledWithSelection = meta.story({\n  name: 'Disabled with selection (single)',\n  args: {\n    disabled: true,\n    defaultOptions: 'frog',\n  },\n  play: disabledPlayFn,\n});\n\nexport const DisabledWithSelectionMulti = meta.story({\n  name: 'Disabled with selection (multi)',\n  args: {\n    disabled: true,\n    multiSelect: true,\n    defaultOptions: ['tadpole', 'frog'],\n  },\n  play: disabledPlayFn,\n});\n\nexport const DefaultOpen = meta.story({\n  args: {\n    defaultOpen: true,\n  },\n});\n\nexport const MouseSelection = meta.story({\n  name: 'Mouse Selection (single)',\n  play: async ({ canvas, args }) => {\n    const selectButton = await canvas.findByRole('button');\n    await userEvent.click(selectButton);\n\n    const listbox = await screen.findByRole('listbox');\n    expect(listbox).toBeInTheDocument();\n\n    const pollywogOption = await screen.findByRole('option', { name: 'Pollywog' });\n    await userEvent.click(pollywogOption);\n\n    expect(args.onSelect).toHaveBeenCalledWith('pollywog');\n    expect(args.onChange).toHaveBeenCalledWith(['pollywog']);\n\n    expect(screen.queryByRole('listbox')).not.toBeInTheDocument();\n    await expect(selectButton).toHaveTextContent('Pollywog');\n  },\n});\n\nexport const MouseSelectionMulti = meta.story({\n  name: 'Mouse Selection (multi)',\n  args: {\n    multiSelect: true,\n  },\n  render: (args) => (\n    <Row>\n      <Select {...args} />\n      <Button ariaLabel={false}>Other content</Button>\n    </Row>\n  ),\n  play: async ({ canvas, args }) => {\n    const selectButton = await canvas.findByRole('button', { name: /Animal/ });\n    await userEvent.click(selectButton);\n\n    const tadpoleOption = await screen.findByRole('option', { name: 'Tadpole' });\n    await userEvent.click(tadpoleOption);\n\n    expect(args.onSelect).toHaveBeenCalledWith('tadpole');\n    expect(args.onChange).toHaveBeenCalledWith(['tadpole']);\n    expect(selectButton).toHaveTextContent('1');\n    expect(await screen.findByRole('listbox')).toBeInTheDocument(); // Listbox should not close in multi select mode.\n\n    const pollywogOption = await screen.findByRole('option', { name: 'Pollywog' });\n    await userEvent.click(pollywogOption);\n\n    expect(args.onChange).toHaveBeenLastCalledWith(['tadpole', 'pollywog']);\n    expect(selectButton).toHaveTextContent('2');\n    expect(await screen.findByRole('listbox')).toBeInTheDocument();\n\n    await userEvent.click(await canvas.findByText('Other content'));\n    expect(screen.queryByRole('listbox')).not.toBeInTheDocument(); // Now closed.\n  },\n});\n\nconst kbSelectionTest =\n  (triggerKey: string, selectKey: string): StoryAnnotations['play'] =>\n  async ({ canvas, args, step }) => {\n    const selectButton = await canvas.findByRole('button');\n    selectButton.focus();\n\n    await step('Open listbox', async () => {\n      await userEvent.keyboard(triggerKey);\n      const listbox = await screen.findByRole('listbox');\n      expect(listbox).toBeInTheDocument();\n      const optionOne = await screen.findByRole('option', { name: 'Tadpole' });\n      expect(document.activeElement).toBe(optionOne);\n    });\n\n    await step('Press ArrowDown', async () => {\n      await userEvent.keyboard('{ArrowDown}');\n      const optionTwo = await screen.findByRole('option', { name: 'Pollywog' });\n      expect(document.activeElement).toBe(optionTwo);\n    });\n\n    await step('Select active option (closes the Select)', async () => {\n      await userEvent.keyboard(selectKey);\n      expect(args.onSelect).toHaveBeenCalledWith('pollywog');\n      expect(args.onChange).toHaveBeenCalledWith(['pollywog']);\n\n      expect(screen.queryByRole('listbox')).not.toBeInTheDocument();\n      expect(selectButton).toHaveTextContent('Pollywog');\n    });\n  };\n\nexport const KeyboardSelectionEE = meta.story({\n  name: 'KB Selection (single, Enter, Enter)',\n  play: kbSelectionTest('{Enter}', '{Enter}'),\n});\n\nexport const KeyboardSelectionES = meta.story({\n  name: 'KB Selection (single, Enter, Space)',\n  play: kbSelectionTest('{Enter}', ' '),\n});\n\nexport const KeyboardSelectionSE = meta.story({\n  name: 'KB Selection (single, Space, Enter)',\n  play: kbSelectionTest(' ', '{Enter}'),\n});\n\nexport const KeyboardSelectionSS = meta.story({\n  name: 'KB Selection (single, Space, Space)',\n  play: kbSelectionTest(' ', ' '),\n});\n\nconst kbMultiSelectionTest =\n  (triggerKey: string, selectKey: string): StoryAnnotations['play'] =>\n  async ({ canvas, args, step }) => {\n    const selectButton = await canvas.findByRole('button', { name: /Animal/ });\n    selectButton.focus();\n\n    await step('Open listbox', async () => {\n      await userEvent.keyboard(triggerKey);\n      const listbox = await screen.findByRole('listbox');\n      expect(listbox).toBeInTheDocument();\n      const optionOne = await screen.findByRole('option', { name: 'Tadpole' });\n      expect(document.activeElement).toBe(optionOne);\n    });\n\n    await step('Select option one', async () => {\n      await userEvent.keyboard(selectKey);\n      expect(args.onSelect).toHaveBeenCalledWith('tadpole');\n      expect(args.onChange).toHaveBeenCalledWith(['tadpole']);\n      expect(screen.queryByRole('listbox')).toBeInTheDocument();\n    });\n\n    await step('Press ArrowDown', async () => {\n      await userEvent.keyboard('{ArrowDown}');\n      const optionTwo = await screen.findByRole('option', { name: 'Pollywog' });\n      expect(document.activeElement).toBe(optionTwo);\n    });\n\n    await step('Select option two', async () => {\n      await userEvent.keyboard(selectKey);\n      expect(args.onSelect).toHaveBeenCalledWith('pollywog');\n      expect(args.onChange).toHaveBeenCalledWith(['tadpole', 'pollywog']);\n      expect(screen.queryByRole('listbox')).toBeInTheDocument();\n      expect(selectButton).toHaveTextContent('2');\n    });\n\n    await step('Tab away (closes the Select)', async () => {\n      await userEvent.keyboard('{Tab}');\n      expect(screen.queryByRole('listbox')).not.toBeInTheDocument();\n    });\n  };\n\nexport const KeyboardSelectionMultiEE = meta.story({\n  name: 'KB Selection (multi, Enter, Enter)',\n  args: { multiSelect: true },\n  play: kbMultiSelectionTest('{Enter}', '{Enter}'),\n});\n\nexport const KeyboardSelectionMultiES = meta.story({\n  name: 'KB Selection (multi, Enter, Space)',\n  args: { multiSelect: true },\n  play: kbMultiSelectionTest('{Enter}', ' '),\n});\n\nexport const KeyboardSelectionMultiSE = meta.story({\n  name: 'KB Selection (multi, Space, Enter)',\n  args: { multiSelect: true },\n  play: kbMultiSelectionTest(' ', '{Enter}'),\n});\n\nexport const KeyboardSelectionMultiSS = meta.story({\n  name: 'KB Selection (multi, Space, Space)',\n  args: { multiSelect: true },\n  play: kbMultiSelectionTest(' ', ' '),\n});\n\nexport const FullArrowNavigation = meta.story({\n  play: async ({ canvas, step }) => {\n    const selectButton = await canvas.findByRole('button');\n    await step('Open select', async () => {\n      selectButton.focus();\n      await userEvent.keyboard('{ArrowDown}');\n      expect(selectButton).toHaveTextContent('Tadpole');\n    });\n\n    await step('Navigate to option 2 with ArrowDown', async () => {\n      await userEvent.keyboard('{ArrowDown}');\n      expect(selectButton).toHaveTextContent('Pollywog');\n    });\n\n    await step('Navigate to option 3 with ArrowDown', async () => {\n      await userEvent.keyboard('{ArrowDown}');\n      expect(selectButton).toHaveTextContent('Frog');\n    });\n\n    await step('Loop back to option 1 with ArrowDown', async () => {\n      await userEvent.keyboard('{ArrowDown}');\n      expect(selectButton).toHaveTextContent('Tadpole');\n    });\n\n    await step('Navigate backwards with ArrowUp', async () => {\n      await userEvent.keyboard('{ArrowUp}');\n      expect(selectButton).toHaveTextContent('Frog');\n    });\n\n    await step('Navigate backwards with ArrowUp', async () => {\n      await userEvent.keyboard('{ArrowUp}');\n      expect(selectButton).toHaveTextContent('Pollywog');\n    });\n\n    await step('Navigate back to option 1 with ArrowUp', async () => {\n      await userEvent.keyboard('{ArrowUp}');\n      expect(selectButton).toHaveTextContent('Tadpole');\n    });\n  },\n});\n\nexport const MouseOpenNoAutoselect = meta.story({\n  name: 'AutoSelect - nothing selected on Mouse open (single)',\n  play: async ({ canvas, args, step }) => {\n    const selectButton = await canvas.findByRole('button');\n\n    await step('Click on button', async () => {\n      await userEvent.click(selectButton);\n      expect(screen.queryByRole('listbox')).toBeInTheDocument();\n      expect(args.onSelect).not.toHaveBeenCalled();\n      expect(args.onChange).not.toHaveBeenCalled();\n      expect(selectButton).not.toHaveTextContent('Tadpole');\n    });\n\n    await step('Click again to close', async () => {\n      await userEvent.click(selectButton);\n      expect(screen.queryByRole('listbox')).not.toBeInTheDocument();\n      expect(args.onSelect).not.toHaveBeenCalled();\n      expect(args.onChange).not.toHaveBeenCalled();\n      expect(selectButton).not.toHaveTextContent('Tadpole');\n    });\n  },\n});\n\nexport const KeyboardOpenAutoselect = meta.story({\n  name: 'AutoSelect - first item select on Enter (single)',\n  play: async ({ canvas, args, step }) => {\n    const selectButton = await canvas.findByRole('button');\n\n    await step('Open with Enter', async () => {\n      selectButton.focus();\n      await userEvent.keyboard('{Enter}');\n    });\n\n    await step('Validate the first item was selected', async () => {\n      expect(args.onSelect).toHaveBeenCalledWith('tadpole');\n      expect(args.onChange).toHaveBeenCalledWith(['tadpole']);\n      expect(selectButton).toHaveTextContent('Tadpole');\n    });\n\n    await step('Close button with Escape', async () => {\n      await userEvent.keyboard('{Escape}');\n      expect(screen.queryByRole('listbox')).not.toBeInTheDocument();\n    });\n\n    await step('Validate the first item is still selected', async () => {\n      expect(args.onSelect).toHaveBeenCalledWith('tadpole');\n      expect(args.onChange).toHaveBeenCalledWith(['tadpole']);\n      expect(selectButton).toHaveTextContent('Tadpole');\n    });\n  },\n});\n\nexport const ArrowDownAutoSelect = meta.story({\n  name: 'AutoSelect - first item select on ArrowDown (single)',\n  play: async ({ canvas, args }) => {\n    const selectButton = await canvas.findByRole('button');\n    selectButton.focus();\n    await userEvent.keyboard('{ArrowDown}');\n    expect(args.onSelect).toHaveBeenCalledWith('tadpole');\n    expect(args.onChange).toHaveBeenCalledWith(['tadpole']);\n    expect(selectButton).toHaveTextContent('Tadpole');\n    await userEvent.keyboard('{Escape}');\n    expect(screen.queryByRole('listbox')).not.toBeInTheDocument();\n  },\n});\n\nexport const ArrowUpAutoSelect = meta.story({\n  name: 'AutoSelect - last item select on ArrowUp (single)',\n  play: async ({ canvas, args }) => {\n    const selectButton = await canvas.findByRole('button');\n    selectButton.focus();\n    await userEvent.keyboard('{ArrowUp}');\n    expect(args.onSelect).toHaveBeenCalledWith('frog');\n    expect(args.onChange).toHaveBeenCalledWith(['frog']);\n    expect(selectButton).toHaveTextContent('Frog');\n    await userEvent.keyboard('{Escape}');\n    expect(screen.queryByRole('listbox')).not.toBeInTheDocument();\n  },\n});\n\nexport const MouseFastNavPage = meta.story({\n  name: 'Mouse Open - PageUp/Down',\n  args: {\n    options: Array.from({ length: 20 }, (_, i) => ({\n      title: `Option ${i + 1}`,\n      value: `option-${i + 1}`,\n    })),\n  },\n  play: async ({ canvas, step }) => {\n    const selectButton = await canvas.findByRole('button');\n\n    await step('Open select (no active option)', async () => {\n      await userEvent.click(selectButton);\n      const listbox = await screen.findByRole('listbox');\n      expect(listbox).toBeInTheDocument();\n      expect(document.activeElement).toBe(listbox);\n    });\n\n    await step('Press PageDown (6th option is active)', async () => {\n      await userEvent.keyboard('{PageDown}');\n      const sixthOption = await screen.findByRole('option', { name: 'Option 6' });\n      expect(document.activeElement).toBe(sixthOption);\n    });\n\n    await step('Press PageUp (1st option is active)', async () => {\n      await userEvent.keyboard('{PageUp}');\n      const firstOption = await screen.findByRole('option', { name: 'Option 1' });\n      expect(document.activeElement).toBe(firstOption);\n    });\n  },\n});\nexport const KeyboardFastNavPage = meta.story({\n  name: 'KB Open - PageUp/Down',\n  args: {\n    options: Array.from({ length: 20 }, (_, i) => ({\n      title: `Option ${i + 1}`,\n      value: `option-${i + 1}`,\n    })),\n  },\n  play: async ({ canvas, step }) => {\n    const selectButton = await canvas.findByRole('button');\n    selectButton.focus();\n\n    await step('Open select (1st option is active)', async () => {\n      await userEvent.keyboard('{Enter}');\n      const listbox = await screen.findByRole('listbox');\n      expect(listbox).toBeInTheDocument();\n      const firstOption = await screen.findByRole('option', { name: 'Option 1' });\n      expect(document.activeElement).toBe(firstOption);\n    });\n\n    await step('Press PageDown (6th option is active)', async () => {\n      await userEvent.keyboard('{PageDown}');\n      const sixthOption = await screen.findByRole('option', { name: 'Option 6' });\n      expect(document.activeElement).toBe(sixthOption);\n    });\n\n    await step('Press PageUp (1st option is active)', async () => {\n      await userEvent.keyboard('{PageUp}');\n      const firstOption = await screen.findByRole('option', { name: 'Option 1' });\n      expect(document.activeElement).toBe(firstOption);\n    });\n  },\n});\n\nexport const MouseFastNavHomeEnd = meta.story({\n  name: 'Mouse Open - Home/End',\n  args: {\n    options: Array.from({ length: 20 }, (_, i) => ({\n      title: `Option ${i + 1}`,\n      value: `option-${i + 1}`,\n    })),\n  },\n  play: async ({ canvas, step }) => {\n    const selectButton = await canvas.findByRole('button');\n\n    await step('Open select (no active option)', async () => {\n      await userEvent.click(selectButton);\n      const listbox = await screen.findByRole('listbox');\n      expect(listbox).toBeInTheDocument();\n      expect(document.activeElement).toBe(listbox);\n    });\n\n    await step('Navigate to middle with ArrowDown', async () => {\n      await userEvent.keyboard('{ArrowDown}{ArrowDown}{ArrowDown}');\n      const middleOption = await screen.findByRole('option', { name: 'Option 3' });\n      expect(document.activeElement).toBe(middleOption);\n    });\n\n    await step('Navigate to end with End', async () => {\n      await userEvent.keyboard('{End}');\n      const lastOption = await screen.findByRole('option', { name: 'Option 20' });\n      expect(document.activeElement).toBe(lastOption);\n    });\n\n    await step('Navigate to start with Home', async () => {\n      await userEvent.keyboard('{Home}');\n      const firstOption = await screen.findByRole('option', { name: 'Option 1' });\n      expect(document.activeElement).toBe(firstOption);\n    });\n  },\n});\n\nexport const KeyboardFastNavHomeEnd = meta.story({\n  name: 'KB Open - Home/End',\n  args: {\n    options: Array.from({ length: 20 }, (_, i) => ({\n      title: `Option ${i + 1}`,\n      value: `option-${i + 1}`,\n    })),\n  },\n  play: async ({ canvas, step }) => {\n    const selectButton = await canvas.findByRole('button');\n    selectButton.focus();\n\n    await step('Open select (1st option is active)', async () => {\n      await userEvent.keyboard('{Enter}');\n      const listbox = await screen.findByRole('listbox');\n      expect(listbox).toBeInTheDocument();\n      const firstOption = await screen.findByRole('option', { name: 'Option 1' });\n      expect(document.activeElement).toBe(firstOption);\n    });\n\n    await step('Navigate to middle with ArrowDown', async () => {\n      await userEvent.keyboard('{ArrowDown}{ArrowDown}{ArrowDown}');\n      const middleOption = await screen.findByRole('option', { name: 'Option 4' });\n      expect(document.activeElement).toBe(middleOption);\n    });\n\n    await step('Navigate to end with End', async () => {\n      await userEvent.keyboard('{End}');\n      const lastOption = await screen.findByRole('option', { name: 'Option 20' });\n      expect(document.activeElement).toBe(lastOption);\n    });\n\n    await step('Navigate to start with Home', async () => {\n      await userEvent.keyboard('{Home}');\n      const firstOption = await screen.findByRole('option', { name: 'Option 1' });\n      expect(document.activeElement).toBe(firstOption);\n    });\n  },\n});\n\nexport const MouseDeselection = meta.story({\n  name: 'Mouse Deselection (multi)',\n  args: {\n    multiSelect: true,\n    defaultOptions: ['tadpole', 'pollywog'],\n  },\n  play: async ({ canvas, args, step }) => {\n    const selectButton = await canvas.findByRole('button', { name: /Animal/ });\n\n    await step('Check initial state', async () => {\n      expect(selectButton).toHaveTextContent('2');\n    });\n\n    await step('Open select', async () => {\n      await userEvent.click(selectButton);\n    });\n\n    await step('Deselect first option', async () => {\n      const tadpoleOption = await screen.findByRole('option', { name: 'Tadpole' });\n      expect(tadpoleOption).toHaveAttribute('aria-selected', 'true');\n      await userEvent.click(tadpoleOption);\n      expect(args.onDeselect).toHaveBeenCalledWith('tadpole');\n      expect(args.onChange).toHaveBeenCalledWith(['pollywog']);\n    });\n\n    await step('Check final state', async () => {\n      expect(selectButton).toHaveTextContent('1');\n    });\n  },\n});\n\nexport const KeyboardDeselection = meta.story({\n  name: 'KB Deselection (multi)',\n  args: {\n    multiSelect: true,\n    defaultOptions: ['tadpole', 'pollywog'],\n  },\n  play: async ({ canvas, args, step }) => {\n    const selectButton = await canvas.findByRole('button', { name: /Animal/ });\n\n    await step('Check initial state', async () => {\n      expect(selectButton).toHaveTextContent('2');\n    });\n\n    await step('Open select', async () => {\n      selectButton.focus();\n      await userEvent.keyboard('{Enter}');\n    });\n\n    await step('Deselect first option', async () => {\n      const tadpoleOption = await screen.findByRole('option', { name: 'Tadpole' });\n      expect(tadpoleOption).toHaveAttribute('aria-selected', 'true');\n      await userEvent.keyboard('{Enter}');\n      expect(args.onDeselect).toHaveBeenCalledWith('tadpole');\n      expect(args.onChange).toHaveBeenCalledWith(['pollywog']);\n    });\n\n    await step('Tab away (closes the Select)', async () => {\n      await userEvent.keyboard('{Tab}');\n      expect(screen.queryByRole('listbox')).not.toBeInTheDocument();\n    });\n\n    await step('Check final state', async () => {\n      expect(selectButton).toHaveTextContent('1');\n    });\n  },\n});\n\nexport const OnSelectHandler = meta.story({\n  name: 'Handlers - onSelect',\n  args: {\n    onSelect: fn().mockName('onSelect'),\n  },\n  play: async ({ canvas, args }) => {\n    const selectButton = await canvas.findByRole('button');\n\n    await userEvent.click(selectButton);\n\n    const frogOption = await screen.findByRole('option', { name: 'Frog' });\n    await userEvent.click(frogOption);\n\n    expect(args.onSelect).toHaveBeenCalledTimes(1);\n    expect(args.onSelect).toHaveBeenCalledWith('frog');\n  },\n});\n\nexport const OnDeselectHandler = meta.story({\n  name: 'Handlers - onDeselect',\n  args: {\n    multiSelect: true,\n    defaultOptions: ['tadpole'],\n    onDeselect: fn().mockName('onDeselect'),\n  },\n  play: async ({ canvas, args }) => {\n    const selectButton = await canvas.findByRole('button', { name: /Animal/ });\n    await userEvent.click(selectButton);\n\n    const tadpoleOption = await screen.findByRole('option', { name: 'Tadpole' });\n    await userEvent.click(tadpoleOption);\n\n    expect(args.onDeselect).toHaveBeenCalledTimes(1);\n    expect(args.onDeselect).toHaveBeenCalledWith('tadpole');\n  },\n});\n\nexport const OnChangeHandler = meta.story({\n  name: 'Handlers - onChange',\n  args: {\n    multiSelect: true,\n    onChange: fn().mockName('onChange'),\n  },\n  play: async ({ canvas, args, step }) => {\n    const selectButton = await canvas.findByRole('button', { name: /Animal/ });\n\n    await step('Open select', async () => {\n      await userEvent.click(selectButton);\n    });\n\n    await step('Select first option', async () => {\n      const tadpoleOption = await screen.findByRole('option', { name: 'Tadpole' });\n      await userEvent.click(tadpoleOption);\n      expect(args.onChange).toHaveBeenCalledWith(['tadpole']);\n    });\n\n    await step('Select second option', async () => {\n      const frogOption = await screen.findByRole('option', { name: 'Frog' });\n      await userEvent.click(frogOption);\n      expect(args.onChange).toHaveBeenLastCalledWith(['tadpole', 'frog']);\n    });\n  },\n});\n\nexport const WithResetSingle = meta.story({\n  name: 'With Reset (single)',\n  args: {\n    defaultOptions: 'frog',\n    onReset: fn().mockName('onReset'),\n  },\n  play: async ({ canvas, args, step }) => {\n    const selectButton = await canvas.findByRole('button');\n\n    await step('Check initial state', async () => {\n      expect(selectButton).toHaveTextContent('Frog');\n    });\n\n    await step('Open select', async () => {\n      await userEvent.click(selectButton);\n      expect(screen.getByRole('listbox')).toBeInTheDocument();\n    });\n\n    await step('Check Reset option exists', async () => {\n      const resetOption = await screen.findByRole('option', { name: 'Reset selection' });\n      expect(resetOption).toBeInTheDocument();\n    });\n\n    await step('Click Reset', async () => {\n      const resetOption = await screen.findByRole('option', { name: 'Reset selection' });\n      await userEvent.click(resetOption);\n\n      expect(args.onReset).toHaveBeenCalledTimes(1);\n      expect(args.onChange).toHaveBeenCalledWith([]);\n      expect(selectButton).not.toHaveTextContent('Frog');\n      expect(selectButton).not.toHaveTextContent('Tadpole');\n      expect(selectButton).not.toHaveTextContent('Pollywog');\n    });\n  },\n});\n\nexport const WithResetMulti = meta.story({\n  name: 'With Reset (multi)',\n  args: {\n    multiSelect: true,\n    defaultOptions: ['tadpole', 'frog'],\n    onReset: fn().mockName('onReset'),\n  },\n  play: async ({ canvas, args, step }) => {\n    const selectButton = await canvas.findByRole('button');\n\n    await step('Check initial state', async () => {\n      expect(selectButton).toHaveTextContent('2');\n    });\n\n    await step('Open select', async () => {\n      await userEvent.click(selectButton);\n      expect(screen.getByRole('listbox')).toBeInTheDocument();\n    });\n\n    await step('Check Reset option exists', async () => {\n      const resetOption = await screen.findByRole('option', { name: 'Reset selection' });\n      expect(resetOption).toBeInTheDocument();\n    });\n\n    await step('Click Reset', async () => {\n      const resetOption = await screen.findByRole('option', { name: 'Reset selection' });\n      await userEvent.click(resetOption);\n\n      expect(args.onReset).toHaveBeenCalledTimes(1);\n      expect(args.onChange).toHaveBeenCalledWith([]);\n      expect(selectButton).not.toHaveTextContent('2');\n    });\n  },\n});\n\nexport const KeyboardResetSingle = meta.story({\n  name: 'KB Reset (single, focus)',\n  args: {\n    defaultOptions: 'frog',\n    onReset: fn().mockName('onReset'),\n  },\n  play: async ({ canvas, args, step }) => {\n    const selectButton = await canvas.findByRole('button');\n    selectButton.focus();\n\n    await step('Open with Enter and navigate to reset option', async () => {\n      await userEvent.keyboard('{Enter}');\n      await userEvent.keyboard('{Home}');\n\n      const resetOption = await screen.findByRole('option', { name: 'Reset selection' });\n      expect(document.activeElement).toBe(resetOption);\n    });\n\n    await step('Check Select is reset', async () => {\n      expect(args.onReset).toHaveBeenCalledTimes(1);\n      expect(args.onChange).toHaveBeenCalledWith([]);\n      expect(selectButton).not.toHaveTextContent('Frog');\n      expect(selectButton).not.toHaveTextContent('Tadpole');\n      expect(selectButton).not.toHaveTextContent('Pollywog');\n    });\n  },\n});\n\nexport const KeyboardResetMulti = meta.story({\n  name: 'KB Reset (multi, Enter)',\n  args: {\n    multiSelect: true,\n    defaultOptions: ['tadpole', 'frog'],\n    onReset: fn().mockName('onReset'),\n  },\n  play: async ({ canvas, args, step }) => {\n    const selectButton = await canvas.findByRole('button');\n    selectButton.focus();\n\n    await step('Open with Enter and navigate to reset option', async () => {\n      await userEvent.keyboard('{Enter}');\n      await userEvent.keyboard('{Home}');\n\n      const resetOption = await screen.findByRole('option', { name: 'Reset selection' });\n      expect(document.activeElement).toBe(resetOption);\n    });\n\n    await step('Press Enter to reset', async () => {\n      await userEvent.keyboard('{Enter}');\n\n      expect(args.onReset).toHaveBeenCalledTimes(1);\n      expect(args.onChange).toHaveBeenCalledWith([]);\n      expect(selectButton).not.toHaveTextContent('2');\n\n      expect(await screen.findByRole('listbox')).toBeInTheDocument();\n    });\n\n    await step('Close with Escape', async () => {\n      await userEvent.keyboard('{Escape}');\n      expect(screen.queryByRole('listbox')).not.toBeInTheDocument();\n    });\n  },\n});\n\nexport const KeyboardResetMultiSpace = meta.story({\n  name: 'KB Reset (multi, Space)',\n  args: {\n    multiSelect: true,\n    defaultOptions: ['tadpole', 'frog'],\n    onReset: fn().mockName('onReset'),\n  },\n  play: async ({ canvas, args, step }) => {\n    const selectButton = await canvas.findByRole('button');\n    selectButton.focus();\n\n    await step('Open with Space and navigate to reset option', async () => {\n      await userEvent.keyboard(' ');\n      await userEvent.keyboard('{Home}');\n\n      const resetOption = await screen.findByRole('option', { name: 'Reset selection' });\n      expect(document.activeElement).toBe(resetOption);\n    });\n\n    await step('Press Space to reset', async () => {\n      await userEvent.keyboard(' ');\n\n      expect(args.onReset).toHaveBeenCalledTimes(1);\n      expect(args.onChange).toHaveBeenCalledWith([]);\n      expect(selectButton).not.toHaveTextContent('2');\n\n      expect(await screen.findByRole('listbox')).toBeInTheDocument();\n    });\n\n    await step('Close with Escape', async () => {\n      await userEvent.keyboard('{Escape}');\n      expect(screen.queryByRole('listbox')).not.toBeInTheDocument();\n    });\n  },\n});\n\nexport const ResetButtonVisibilitySingle = meta.story({\n  name: 'Reset Button Visibility (single)',\n  args: {\n    onReset: fn().mockName('onReset'),\n  },\n  play: async ({ canvas, step }) => {\n    const selectButton = await canvas.findByRole('button');\n\n    await step('Open without selection', async () => {\n      await userEvent.click(selectButton);\n\n      const resetOption = await screen.findByRole('option', { name: 'Reset selection' });\n      expect(resetOption).toBeInTheDocument();\n      // Reset option should not be disabled when the user cursor is on it in\n      // single-select mode even without selection, because single-select Select\n      // auto triggers the focused option, and we don't want to have the selection\n      // reset whilst SRs announce that the reset option is disabled.\n      expect(resetOption).not.toHaveAttribute('aria-disabled', 'true');\n    });\n\n    await step('Select an option', async () => {\n      const frogOption = await screen.findByRole('option', { name: 'Frog' });\n      await userEvent.click(frogOption);\n    });\n\n    await step('Reopen select and check reset option', async () => {\n      await userEvent.click(selectButton);\n\n      const resetOption = await screen.findByRole('option', { name: 'Reset selection' });\n      expect(resetOption).toBeInTheDocument();\n      expect(resetOption).not.toHaveAttribute('aria-disabled', 'true');\n    });\n  },\n});\n\nexport const ResetButtonVisibilityMulti = meta.story({\n  name: 'Reset Button Visibility (multi)',\n  args: {\n    multiSelect: true,\n    onReset: fn().mockName('onReset'),\n  },\n  play: async ({ canvas, step }) => {\n    const selectButton = await canvas.findByRole('button');\n\n    await step('Open without selection', async () => {\n      await userEvent.click(selectButton);\n\n      const resetOption = await screen.findByRole('option', { name: 'Reset selection' });\n      expect(resetOption).toBeInTheDocument();\n      expect(resetOption).toHaveAttribute('aria-disabled', 'true');\n    });\n\n    await step('Select an option', async () => {\n      const frogOption = await screen.findByRole('option', { name: 'Frog' });\n      await userEvent.click(frogOption);\n    });\n\n    await step('Check reset option', async () => {\n      const resetOption = await screen.findByRole('option', { name: 'Reset selection' });\n      expect(resetOption).toBeInTheDocument();\n      expect(resetOption).not.toHaveAttribute('aria-disabled', 'true');\n    });\n  },\n});\n\nexport const CustomResetLabel = meta.story({\n  name: 'Custom Reset Label',\n  args: {\n    defaultOptions: 'frog',\n    onReset: fn().mockName('onReset'),\n    resetLabel: 'Clear selection',\n  },\n  play: async ({ canvas }) => {\n    const selectButton = await canvas.findByRole('button');\n\n    await userEvent.click(selectButton);\n\n    const resetOption = await screen.findByRole('option', { name: 'Clear selection' });\n    expect(resetOption).toBeInTheDocument();\n  },\n});\n\nexport const WithoutReset = meta.story({\n  name: 'Without Reset Option',\n  args: {\n    defaultOptions: 'frog',\n  },\n  play: async ({ canvas }) => {\n    const selectButton = await canvas.findByRole('button');\n\n    await userEvent.click(selectButton);\n\n    const options = await screen.findAllByRole('option');\n    for (const option of options) {\n      expect(option).not.toHaveTextContent('Reset selection');\n    }\n\n    expect(options.length).toBe(3);\n  },\n});\n\nconst nonStringOptions = [\n  { title: 'Number (42)', value: 42 },\n  { title: 'Number (0)', value: 0 },\n  { title: 'Boolean (true)', value: true },\n  { title: 'Boolean (false)', value: false },\n  { title: 'Null', value: null },\n  { title: 'Undefined', value: undefined },\n  { title: 'String', value: 'string' },\n];\n\nexport const NonStringValuesSingleSelect = meta.story({\n  name: 'Non-String Values (single)',\n  args: {\n    options: nonStringOptions,\n    onSelect: fn(),\n    onChange: fn(),\n  },\n  play: async ({ canvas, args, step }) => {\n    const selectButton = await canvas.findByRole('button');\n\n    await step('Select number value (42)', async () => {\n      await userEvent.click(selectButton);\n      await userEvent.click(await screen.findByRole('option', { name: 'Number (42)' }));\n      expect(args.onSelect).toHaveBeenLastCalledWith(42);\n      expect(args.onChange).toHaveBeenLastCalledWith([42]);\n    });\n\n    await step('Select boolean value (true)', async () => {\n      await userEvent.click(selectButton);\n      await userEvent.click(await screen.findByRole('option', { name: 'Boolean (true)' }));\n      expect(args.onSelect).toHaveBeenLastCalledWith(true);\n      expect(args.onChange).toHaveBeenLastCalledWith([true]);\n    });\n\n    await step('Select boolean value (false)', async () => {\n      await userEvent.click(selectButton);\n      await userEvent.click(await screen.findByRole('option', { name: 'Boolean (false)' }));\n      expect(args.onSelect).toHaveBeenLastCalledWith(false);\n      expect(args.onChange).toHaveBeenLastCalledWith([false]);\n    });\n\n    await step('Select null value', async () => {\n      await userEvent.click(selectButton);\n      await userEvent.click(await screen.findByRole('option', { name: 'Null' }));\n      expect(args.onSelect).toHaveBeenLastCalledWith(null);\n      expect(args.onChange).toHaveBeenLastCalledWith([null]);\n    });\n\n    await step('Select undefined value', async () => {\n      await userEvent.click(selectButton);\n      await userEvent.click(await screen.findByRole('option', { name: 'Undefined' }));\n      expect(args.onSelect).toHaveBeenLastCalledWith(undefined);\n      expect(args.onChange).toHaveBeenLastCalledWith([undefined]);\n    });\n\n    await step('Select number value (0 - falsy)', async () => {\n      await userEvent.click(selectButton);\n      await userEvent.click(await screen.findByRole('option', { name: 'Number (0)' }));\n      expect(args.onSelect).toHaveBeenLastCalledWith(0);\n      expect(args.onChange).toHaveBeenLastCalledWith([0]);\n    });\n  },\n});\n\nexport const NonStringValuesMultiSelect = meta.story({\n  name: 'Non-String Values (multi)',\n  args: {\n    options: nonStringOptions,\n    multiSelect: true,\n    onSelect: fn(),\n    onDeselect: fn(),\n    onChange: fn(),\n  },\n  play: async ({ canvas, args, step }) => {\n    const selectButton = await canvas.findByRole('button');\n\n    await step('Select number (42)', async () => {\n      await userEvent.click(selectButton);\n      await userEvent.click(await screen.findByRole('option', { name: 'Number (42)' }));\n      expect(args.onSelect).toHaveBeenLastCalledWith(42);\n      expect(args.onChange).toHaveBeenLastCalledWith([42]);\n    });\n\n    await step('Add boolean (true)', async () => {\n      await userEvent.click(await screen.findByRole('option', { name: 'Boolean (true)' }));\n      expect(args.onSelect).toHaveBeenLastCalledWith(true);\n      expect(args.onChange).toHaveBeenLastCalledWith([42, true]);\n    });\n\n    await step('Add null', async () => {\n      await userEvent.click(await screen.findByRole('option', { name: 'Null' }));\n      expect(args.onSelect).toHaveBeenLastCalledWith(null);\n      expect(args.onChange).toHaveBeenLastCalledWith([42, true, null]);\n    });\n\n    await step('Add undefined', async () => {\n      await userEvent.click(await screen.findByRole('option', { name: 'Undefined' }));\n      expect(args.onSelect).toHaveBeenLastCalledWith(undefined);\n      expect(args.onChange).toHaveBeenLastCalledWith([42, true, null, undefined]);\n    });\n\n    await step('Deselect number (42)', async () => {\n      await userEvent.click(await screen.findByRole('option', { name: 'Number (42)' }));\n      expect(args.onDeselect).toHaveBeenLastCalledWith(42);\n      expect(args.onChange).toHaveBeenLastCalledWith([true, null, undefined]);\n    });\n\n    await step('Deselect undefined', async () => {\n      await userEvent.click(await screen.findByRole('option', { name: 'Undefined' }));\n      expect(args.onDeselect).toHaveBeenLastCalledWith(undefined);\n      expect(args.onChange).toHaveBeenLastCalledWith([true, null]);\n    });\n  },\n});\n\nexport const DefaultOptionNumber = meta.story({\n  name: 'Default Option - Number',\n  args: {\n    options: nonStringOptions,\n    defaultOptions: 42,\n  },\n  play: async ({ canvas }) => {\n    const selectButton = await canvas.findByRole('button');\n    await expect(selectButton).toHaveTextContent('Number (42)');\n  },\n});\n\nexport const DefaultOptionZero = meta.story({\n  name: 'Default Option - Zero',\n  args: {\n    options: nonStringOptions,\n    defaultOptions: 0,\n  },\n  play: async ({ canvas }) => {\n    const selectButton = await canvas.findByRole('button');\n    await expect(selectButton).toHaveTextContent('Number (0)');\n  },\n});\n\nexport const DefaultOptionBooleanTrue = meta.story({\n  name: 'Default Option - Boolean True',\n  args: {\n    options: nonStringOptions,\n    defaultOptions: true,\n  },\n  play: async ({ canvas }) => {\n    const selectButton = await canvas.findByRole('button');\n    await expect(selectButton).toHaveTextContent('Boolean (true)');\n  },\n});\n\nexport const DefaultOptionBooleanFalse = meta.story({\n  name: 'Default Option - Boolean False',\n  args: {\n    options: nonStringOptions,\n    defaultOptions: false,\n  },\n  play: async ({ canvas }) => {\n    const selectButton = await canvas.findByRole('button');\n    await expect(selectButton).toHaveTextContent('Boolean (false)');\n  },\n});\n\nexport const DefaultOptionNull = meta.story({\n  name: 'Default Option - Null',\n  args: {\n    options: nonStringOptions,\n    defaultOptions: null,\n  },\n  play: async ({ canvas }) => {\n    const selectButton = await canvas.findByRole('button');\n    await expect(selectButton).toHaveTextContent('Null');\n  },\n});\n\nexport const DefaultOptionUndefinedDoesNotWork = meta.story({\n  name: 'Default Option - Bare undefined does NOT select',\n  args: {\n    options: nonStringOptions,\n    defaultOptions: undefined,\n    children: 'Nothing selected',\n  },\n  play: async ({ canvas }) => {\n    const selectButton = await canvas.findByRole('button');\n    await expect(selectButton).toHaveTextContent('Nothing selected');\n    await expect(selectButton).not.toHaveTextContent('Undefined');\n  },\n});\n\nexport const DefaultOptionUndefinedInArrayWorks = meta.story({\n  name: 'Default Option - [undefined] selects undefined option',\n  args: {\n    options: nonStringOptions,\n    defaultOptions: [undefined],\n  },\n  play: async ({ canvas }) => {\n    const selectButton = await canvas.findByRole('button');\n    await expect(selectButton).toHaveTextContent('Undefined');\n  },\n});\n\nexport const DefaultOptionsMultipleNonStringValues = meta.story({\n  name: 'Default Options - Multiple Non-String Values',\n  args: {\n    options: nonStringOptions,\n    defaultOptions: [42, false, null],\n    multiSelect: true,\n  },\n  play: async ({ canvas }) => {\n    const selectButton = await canvas.findByRole('button');\n    await expect(selectButton).toHaveTextContent('3');\n\n    await userEvent.click(selectButton);\n    const option42 = await screen.findByRole('option', { name: 'Number (42)' });\n    const optionFalse = await screen.findByRole('option', { name: 'Boolean (false)' });\n    const optionNull = await screen.findByRole('option', { name: 'Null' });\n\n    expect(option42).toHaveAttribute('aria-selected', 'true');\n    expect(optionFalse).toHaveAttribute('aria-selected', 'true');\n    expect(optionNull).toHaveAttribute('aria-selected', 'true');\n  },\n});\n\nconst optionsWithUndefinedForReset = [\n  { title: 'Apple', value: 'apple' },\n  { title: 'Undefined Value', value: undefined },\n  { title: 'Banana', value: 'banana' },\n];\n\nexport const ResetWithUndefinedOption = meta.story({\n  name: 'Reset vs Undefined Option',\n  args: {\n    options: optionsWithUndefinedForReset,\n    children: 'Select fruit',\n    onReset: fn(),\n    onChange: fn(),\n    onSelect: fn(),\n  },\n  play: async ({ canvas, args, step }) => {\n    const selectButton = await canvas.findByRole('button');\n\n    await step('Select a regular option first', async () => {\n      await userEvent.click(selectButton);\n      await userEvent.click(await screen.findByRole('option', { name: 'Apple' }));\n      expect(args.onSelect).toHaveBeenLastCalledWith('apple');\n      expect(args.onChange).toHaveBeenLastCalledWith(['apple']);\n      await expect(selectButton).toHaveTextContent('Apple');\n    });\n\n    await step('Select the undefined value option - it should work', async () => {\n      await userEvent.click(selectButton);\n      await userEvent.click(await screen.findByRole('option', { name: 'Undefined Value' }));\n      expect(args.onSelect).toHaveBeenLastCalledWith(undefined);\n      expect(args.onChange).toHaveBeenLastCalledWith([undefined]);\n      await expect(selectButton).toHaveTextContent('Undefined Value');\n    });\n\n    await step('Click Reset - should clear, not select undefined option', async () => {\n      await userEvent.click(selectButton);\n      await userEvent.click(await screen.findByRole('option', { name: 'Reset selection' }));\n      expect(args.onReset).toHaveBeenCalledTimes(1);\n      expect(args.onChange).toHaveBeenLastCalledWith([]);\n      await expect(selectButton).toHaveTextContent('Select fruit');\n      await expect(selectButton).not.toHaveTextContent('Undefined Value');\n    });\n\n    await step('Can still select undefined value after reset', async () => {\n      await userEvent.click(selectButton);\n      await userEvent.click(await screen.findByRole('option', { name: 'Undefined Value' }));\n      expect(args.onSelect).toHaveBeenLastCalledWith(undefined);\n      expect(args.onChange).toHaveBeenLastCalledWith([undefined]);\n      await expect(selectButton).toHaveTextContent('Undefined Value');\n    });\n  },\n});\n\nexport const ShowSelectedOptionTitleTrue = meta.story({\n  name: 'Show Selected Option Title (prop=true)',\n  args: {\n    showSelectedOptionTitle: true,\n    defaultOptions: 'frog',\n  },\n  play: async ({ canvas, step }) => {\n    await step('Verify selected option title is shown', async () => {\n      const selectButton = await canvas.findByRole('button');\n      expect(selectButton).toHaveTextContent('Frog');\n    });\n  },\n});\n\nexport const ShowSelectedOptionTitleFalse = meta.story({\n  name: 'Show Selected Option Title (prop=false)',\n  args: {\n    showSelectedOptionTitle: false,\n    defaultOptions: 'frog',\n  },\n  play: async ({ canvas, step }) => {\n    await step('Verify default title is shown instead of selected option', async () => {\n      const selectButton = await canvas.findByRole('button');\n      expect(selectButton).toHaveTextContent('Animal');\n    });\n  },\n});\n\nexport const ShowSelectedOptionTitleFalseMulti = meta.story({\n  name: 'Show Selected Option Title (prop=false, multi)',\n  args: {\n    showSelectedOptionTitle: false,\n    multiSelect: true,\n    defaultOptions: ['frog', 'tadpole'],\n  },\n  play: async ({ canvas, step }) => {\n    await step('Verify default title is shown for multi-select', async () => {\n      const selectButton = await canvas.findByRole('button');\n      expect(selectButton).toHaveTextContent('Animal');\n    });\n  },\n});\n\nexport const ShowSelectedOptionTitleTrueMulti = meta.story({\n  name: 'Show Selected Option Title (prop=true, multi)',\n  args: {\n    showSelectedOptionTitle: true,\n    multiSelect: true,\n    defaultOptions: ['frog'],\n  },\n  play: async ({ canvas, step }) => {\n    await step('Verify option count is shown for multi-select', async () => {\n      const selectButton = await canvas.findByRole('button');\n      expect(selectButton).toHaveTextContent('1');\n    });\n  },\n});\n"
  },
  {
    "path": "code/core/src/components/components/Select/Select.tsx",
    "content": "import type { FC, KeyboardEvent } from 'react';\nimport React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { RefreshIcon } from '@storybook/icons';\n\nimport { useInteractOutside } from '@react-aria/interactions';\nimport { Overlay, ariaHideOutside, useOverlay, useOverlayPosition } from '@react-aria/overlays';\nimport { useObjectRef } from '@react-aria/utils';\nimport { useOverlayTriggerState } from '@react-stately/overlays';\nimport { darken, transparentize } from 'polished';\nimport { styled, useTheme } from 'storybook/theming';\n\nimport { Button, type ButtonProps } from '../Button/Button.tsx';\nimport { Form } from '../Form/Form.tsx';\nimport { Popover } from '../Popover/Popover.tsx';\nimport { SelectOption } from './SelectOption.tsx';\nimport type { InternalOption, Option, ResetOption, Value } from './helpers.tsx';\nimport {\n  Listbox,\n  PAGE_STEP_SIZE,\n  externalToValue,\n  isLiteralValue,\n  optionOrResetToInternal,\n  optionToInternal,\n  valueToExternal,\n} from './helpers.tsx';\n\nexport interface SelectProps extends Omit<\n  ButtonProps,\n  'onClick' | 'onChange' | 'onSelect' | 'variant'\n> {\n  size?: 'small' | 'medium';\n  padding?: 'small' | 'medium' | 'none';\n\n  /**\n   * Whether multiple options can be selected. In single select mode, this component acts like a\n   * HTML select element where the selected option follows focus. In multi select mode, it acts like\n   * a combobox and does not autoclose on select or autoselect the focused option.\n   */\n  multiSelect?: boolean;\n\n  /**\n   * Mandatory label that explains what is being selected. Do not include \"change\", \"toggle\" or\n   * \"select\" verbs in the label. Instead, only describe the type of content with a noun.\n   */\n  ariaLabel: string;\n\n  /**\n   * Label for the Select component. In single-select mode, is replaced by the currently selected\n   * option's title.\n   */\n  children?: React.ReactNode;\n\n  /**\n   * Icon shown next to the Select's children, still displayed when a value is selected and Select\n   * shows that value instead of children.\n   */\n  icon?: React.ReactNode;\n\n  /** Whether the Select is currently disabled. */\n  disabled?: boolean;\n\n  /** Options available in the select. */\n  options: Option[];\n\n  /** IDs of the preselected options. */\n  defaultOptions?: Value | Value[];\n\n  /** Whether the Select should render open. */\n  defaultOpen?: boolean;\n\n  /** When set, a reset option is rendered in the Select listbox. */\n  onReset?: () => void;\n\n  /** Custom text label for the reset option when it exists. */\n  resetLabel?: string;\n\n  onSelect?: (option: Value) => void;\n  onDeselect?: (option: Value) => void;\n  onChange?: (selected: Value[]) => void;\n  /**\n   * Legacy option for ToolbarMenuSelect. Do not use in new code. Controls whether to show the\n   * selected option's title.\n   *\n   * @default true\n   */\n  showSelectedOptionTitle?: boolean;\n}\n\nfunction valueToId(parentId: string, { value }: InternalOption | ResetOption): string {\n  return `${parentId}-opt-${String(value) ?? 'sb-reset'}`;\n}\n\nconst SelectedOptionCount = styled.span(({ theme }) => ({\n  appearance: 'none',\n  color: theme.textMutedColor,\n  fontSize: 12,\n}));\n\nfunction setSelectedFromDefault(\n  options: SelectProps['options'],\n  defaultOptions: SelectProps['defaultOptions']\n): InternalOption[] {\n  if (defaultOptions === undefined) {\n    return [];\n  }\n\n  if (isLiteralValue(defaultOptions)) {\n    return options.filter((opt) => opt.value === defaultOptions).map(optionToInternal);\n  }\n\n  return options\n    .filter((opt) => defaultOptions.some((def) => opt.value === def))\n    .map(optionToInternal);\n}\n\nconst StyledButton = styled(Button)<ButtonProps & { $hasSelection?: boolean; $isOpen?: boolean }>(\n  ({ $isOpen: isOpen, $hasSelection: hasSelection, theme }) =>\n    isOpen || hasSelection\n      ? {\n          boxShadow: 'none',\n          background: transparentize(0.93, theme.barSelectedColor),\n          color:\n            theme.base === 'light' ? darken(0.1, theme.color.secondary) : theme.color.secondary,\n        }\n      : {}\n);\n\nconst Underlay = styled.div({\n  position: 'fixed',\n  inset: 0,\n  // This will do for now, our popovers use the max z-index of 2147483647. We'll want to\n  // inherit a base from a CSS variable and add preset values to it in the future (e.g.\n  // 100 for underlay, 200 for overlay) if we start using Select in dialogs.\n  zIndex: 1000,\n});\n\n/*\n * This popover does not do any keyboard handling or placement. It uses a portal to place\n * its children under its sibling's position. When clicking outside the popover, it closes.\n */\nconst MinimalistPopover: FC<{\n  children: React.ReactNode;\n  handleClose: () => void;\n  triggerRef: React.RefObject<HTMLElement>;\n}> = ({ children, handleClose, triggerRef }) => {\n  const popoverRef = React.useRef(null);\n\n  useInteractOutside({\n    ref: popoverRef,\n    onInteractOutside: handleClose,\n  });\n\n  useEffect(() => {\n    if (popoverRef.current) {\n      return ariaHideOutside([popoverRef.current], { shouldUseInert: true });\n    }\n  }, []);\n\n  const { overlayProps: positionProps } = useOverlayPosition({\n    targetRef: triggerRef,\n    overlayRef: popoverRef,\n    placement: 'bottom start',\n    offset: 8,\n    maxHeight: 504,\n    isOpen: true,\n  });\n\n  const { overlayProps, underlayProps } = useOverlay(\n    {\n      isOpen: true,\n      onClose: handleClose,\n      isDismissable: true,\n      /* We do this ourselves. */\n      shouldCloseOnBlur: false,\n      /* We also do this ourselves. */\n      isKeyboardDismissDisabled: true,\n    },\n    popoverRef\n  );\n\n  const theme = useTheme();\n\n  positionProps.style = {\n    ...positionProps.style,\n    overflow: 'hidden auto',\n    scrollbarColor: `${theme.barTextColor} transparent`,\n    scrollbarWidth: 'thin',\n  };\n\n  return (\n    <Overlay disableFocusManagement {...overlayProps}>\n      <Underlay {...underlayProps} />\n      <Popover hasChrome ref={popoverRef} padding={0} {...positionProps}>\n        {children}\n      </Popover>\n    </Overlay>\n  );\n};\n\nexport const Select = forwardRef<HTMLButtonElement, SelectProps>(\n  (\n    {\n      children,\n      icon,\n      disabled = false,\n      options: calleeOptions,\n      defaultOptions,\n      multiSelect = false,\n      onReset,\n      padding = 'small',\n      resetLabel,\n      onSelect,\n      onDeselect,\n      onChange,\n      tooltip,\n      ariaLabel,\n      showSelectedOptionTitle = true,\n      ...props\n    },\n    ref\n  ) => {\n    const [isOpen, setIsOpen] = useState(props.defaultOpen || false);\n    const [shouldRefocusTrigger, setShouldRefocusTrigger] = useState(false);\n    const triggerRef = useObjectRef(ref);\n\n    const id = useMemo(() => {\n      return 'select-' + Math.random().toString(36).substring(2, 15);\n    }, []);\n    const listboxId = `${id}-listbox`;\n    const listboxRef = useRef<HTMLUListElement>(null);\n\n    const otState = useOverlayTriggerState({\n      isOpen: isOpen && !disabled,\n      onOpenChange: setIsOpen,\n    });\n\n    const handleClose = useCallback(() => {\n      setIsOpen(false);\n      setShouldRefocusTrigger(true);\n    }, []);\n\n    // We must delay refocusing the trigger because we first need the listbox to close,\n    // and @react-aria/overlays to remove the inert attribute set up by MinimalistPopover.\n    useEffect(() => {\n      if (!otState.isOpen && shouldRefocusTrigger) {\n        triggerRef.current?.focus();\n        setShouldRefocusTrigger(false);\n      }\n    }, [otState.isOpen, shouldRefocusTrigger, triggerRef]);\n\n    // The last selected option(s), which will be used by the app.\n    const [selectedOptions, setSelectedOptions] = useState<InternalOption[]>(\n      setSelectedFromDefault(calleeOptions, defaultOptions)\n    );\n\n    // Selects an option (updating the selection state based on multiSelect).\n    const handleSelectOption = useCallback(\n      (option: InternalOption | ResetOption) => {\n        // Reset option case. We check value === undefined for cleaner type handling in the other branch.\n        if (option.type === 'reset') {\n          onChange?.([]);\n          onReset?.();\n          setSelectedOptions([]);\n        } else if (multiSelect) {\n          setSelectedOptions((previous) => {\n            let newSelected: InternalOption[] = [];\n\n            const isSelected = previous?.some((opt) => opt.value === option.value);\n            if (isSelected) {\n              onDeselect?.(valueToExternal(option.value));\n              newSelected = previous?.filter((opt) => opt.value !== option.value) ?? [];\n            } else {\n              onSelect?.(valueToExternal(option.value));\n              newSelected = [...(previous ?? []), option];\n            }\n\n            onChange?.(newSelected.map((opt) => valueToExternal(opt.value)));\n            return newSelected;\n          });\n        } else {\n          setSelectedOptions((current) => {\n            if (current.every((opt) => opt.value !== option.value)) {\n              onSelect?.(valueToExternal(option.value));\n              onChange?.([valueToExternal(option.value)]);\n              return [option];\n            }\n            return current;\n          });\n        }\n      },\n      [multiSelect, onChange, onSelect, onDeselect, onReset]\n    );\n\n    // Reset option appears if a handler is defined and there are selected options.\n    const resetOption = useMemo(\n      () =>\n        onReset\n          ? {\n              type: 'reset',\n              value: undefined,\n              title: resetLabel ?? 'Reset selection',\n              icon: <RefreshIcon />,\n              description: undefined,\n              children: undefined,\n            }\n          : undefined,\n      [onReset, resetLabel]\n    );\n\n    // Synthetic object allowing us to implement the roving tabindex.\n    const options = useMemo(\n      () => (resetOption ? [resetOption, ...calleeOptions] : calleeOptions),\n      [calleeOptions, resetOption]\n    );\n\n    // We must do this to account for callees that have an unstable data model.\n    // For instance, when a URL query param is passed for the theme addon, the\n    // addon receives, undefined, then the default theme value (incorrectly),\n    // then the actual URL query param as a selected theme.\n    useEffect(() => {\n      if (defaultOptions) {\n        setSelectedOptions(setSelectedFromDefault(calleeOptions, defaultOptions));\n      }\n    }, [defaultOptions, calleeOptions]);\n\n    // The active option in the listbox, which will receive focus when the listbox is open.\n    const [activeOption, setActiveOptionState] = useState<InternalOption | ResetOption | undefined>(\n      undefined\n    );\n\n    // In single select mode, the active option is the selected one, so we\n    // wrap setActiveOption to handle selection. We never close the listbox\n    // in that scenario.\n    const setActiveOption = useCallback(\n      (option: Option | ResetOption, changeSelection = true) => {\n        setActiveOptionState(optionOrResetToInternal(option));\n        if (!multiSelect && changeSelection) {\n          handleSelectOption(optionOrResetToInternal(option));\n        }\n      },\n      [multiSelect, handleSelectOption]\n    );\n\n    const moveActiveOptionDown = useCallback(\n      (step = 1) => {\n        if (!isOpen || !activeOption) {\n          setActiveOption(options[step === 1 ? 0 : Math.min(step, options.length - 1)]);\n          return;\n        }\n\n        const currentIndex = options.findIndex((option) =>\n          activeOption.type === 'reset'\n            ? 'type' in option && option.type === 'reset'\n            : externalToValue(option.value) === activeOption.value\n        );\n        const nextIndex = currentIndex + step;\n\n        // Loop over to the start if we're already on the last option.\n        let newActiveOption;\n        if (nextIndex >= options.length && currentIndex === options.length - 1) {\n          newActiveOption = options[0];\n        } else {\n          newActiveOption = options[Math.min(options.length - 1, nextIndex)];\n        }\n\n        setActiveOption(newActiveOption);\n      },\n      [isOpen, activeOption, setActiveOption, options]\n    );\n\n    const moveActiveOptionUp = useCallback(\n      (step = 1) => {\n        if (!isOpen || !activeOption) {\n          setActiveOption(options[Math.max(0, options.length - step)]);\n          return;\n        }\n\n        const currentIndex = options.findIndex((option) =>\n          activeOption.type === 'reset'\n            ? 'type' in option && option.type === 'reset'\n            : externalToValue(option.value) === activeOption.value\n        );\n        const nextIndex = currentIndex - step;\n\n        // Loop over to the end if we're already on the first option.\n        let newActiveOption;\n        if (nextIndex < 0 && currentIndex === 0) {\n          newActiveOption = options[options.length - 1];\n        } else {\n          newActiveOption = options[Math.max(0, nextIndex)];\n        }\n\n        setActiveOption(newActiveOption);\n      },\n      [isOpen, activeOption, setActiveOption, options]\n    );\n\n    const handleButtonKeyDown = useCallback(\n      (e: KeyboardEvent<HTMLButtonElement>) => {\n        const openAt = (index: number) => {\n          e.preventDefault();\n          setActiveOption(options[index]);\n          setIsOpen(true);\n        };\n\n        // If there is a selection, we'll open the Select around the first selected option.\n        // If not, around the edges of the list.\n        const indexOfFirstSelected = options.findIndex((option) =>\n          selectedOptions.some((sel) => sel.value === externalToValue(option.value))\n        );\n        const hasSelection = indexOfFirstSelected !== -1;\n\n        // When the Select has a reset option, but nothing is selected, it\n        // makes no sense to open on the Reset option. We start on the first\n        // actual option.\n        const listStart = resetOption && !hasSelection ? 1 : 0;\n        const listEnd = options.length - 1;\n\n        // When we press ArrowUp/Down, we want to stay close to the edges rather than\n        // initiate movement. When we press Home/End or PageUp/PageDown, we want to\n        // move immediately because it's clearer the user intends to be in a specific\n        // area of the list. This is why we don't always do +/- 1 but always do +/- PAGE_STEP_SIZE.\n        if (e.key === 'Enter' || e.key === ' ') {\n          openAt(hasSelection ? Math.min(indexOfFirstSelected, listEnd) : listStart);\n        } else if (e.key === 'ArrowDown') {\n          openAt(hasSelection ? Math.min(indexOfFirstSelected + 1, listEnd) : listStart);\n        } else if (e.key === 'ArrowUp') {\n          openAt(hasSelection ? Math.max(indexOfFirstSelected - 1, listStart) : listEnd);\n        } else if (e.key === 'Home') {\n          openAt(listStart);\n        } else if (e.key === 'End') {\n          openAt(listEnd);\n        } else if (e.key === 'PageDown') {\n          openAt(\n            Math.min((hasSelection ? indexOfFirstSelected : listStart) + PAGE_STEP_SIZE, listEnd)\n          );\n        } else if (e.key === 'PageUp') {\n          openAt(Math.max(0, (hasSelection ? indexOfFirstSelected : listEnd) - PAGE_STEP_SIZE));\n        }\n      },\n      [options, resetOption, setActiveOption, selectedOptions]\n    );\n\n    const handleListboxKeyDown = useCallback(\n      (e: KeyboardEvent<HTMLUListElement>) => {\n        // We don't prevent default on Tab, so that the Tab or Shift+Tab goes\n        // through after we've repositioned to the Button.\n        if (e.key !== 'Tab') {\n          e.preventDefault();\n        } else {\n          handleClose();\n        }\n\n        if (e.key === 'Escape') {\n          handleClose();\n        } else if (e.key === 'ArrowDown') {\n          moveActiveOptionDown();\n        } else if (e.key === 'ArrowUp') {\n          moveActiveOptionUp();\n        } else if (e.key === 'Home') {\n          setActiveOption(options[0]);\n        } else if (e.key === 'End') {\n          setActiveOption(options[options.length - 1]);\n        } else if (e.key === 'PageDown') {\n          moveActiveOptionDown(PAGE_STEP_SIZE);\n        } else if (e.key === 'PageUp') {\n          moveActiveOptionUp(PAGE_STEP_SIZE);\n        }\n      },\n      [handleClose, moveActiveOptionDown, moveActiveOptionUp, options, setActiveOption]\n    );\n\n    // Transfer focus to the active option whenever we open the listbox.\n    useEffect(() => {\n      if (isOpen && activeOption) {\n        const optionElement = document.getElementById(valueToId(id, activeOption));\n\n        if (optionElement) {\n          optionElement.scrollIntoView({ block: 'nearest' });\n          optionElement.focus();\n        }\n      } else if (isOpen) {\n        listboxRef.current?.focus();\n      }\n    }, [isOpen, activeOption, id]);\n\n    // We customise the ariaLabel to include a current value, and we let tooltip\n    // receive the original ariaLabel as the value is displayed in children.\n    const finalAriaLabel = useMemo(() => {\n      if (selectedOptions.length === 1) {\n        return `${ariaLabel} ${selectedOptions[0].title}`;\n      }\n      if (selectedOptions.length) {\n        return `${ariaLabel}, ${selectedOptions.length} values selected`;\n      }\n      return ariaLabel;\n    }, [ariaLabel, selectedOptions]);\n\n    return (\n      <>\n        <StyledButton\n          {...props}\n          variant=\"ghost\"\n          ariaLabel={finalAriaLabel}\n          tooltip={tooltip ?? ariaLabel}\n          disableAllTooltips={isOpen}\n          id={id}\n          ref={triggerRef}\n          padding={padding}\n          $isOpen={isOpen}\n          $hasSelection={!!selectedOptions.length}\n          // Can be removed once #32325 is fixed (Button will then provide aria-disabled)\n          aria-disabled={disabled}\n          disabled={disabled}\n          onClick={() => {\n            if (isOpen) {\n              handleClose();\n            } else {\n              setIsOpen(true);\n            }\n          }}\n          tabIndex={isOpen ? -1 : 0}\n          onKeyDown={handleButtonKeyDown}\n          role=\"button\"\n          aria-controls={isOpen ? listboxId : undefined}\n          aria-expanded={isOpen}\n          aria-haspopup=\"listbox\"\n        >\n          {!multiSelect && (\n            <>\n              {icon}\n              {(showSelectedOptionTitle && selectedOptions[0]?.title) || children}\n            </>\n          )}\n\n          {multiSelect && (\n            <>\n              {icon}\n              {children}\n              {!!selectedOptions.length && (\n                <SelectedOptionCount\n                  aria-label={`${selectedOptions.length} ${selectedOptions.length > 1 ? 'items' : 'item'} selected`}\n                >\n                  {selectedOptions?.length}\n                </SelectedOptionCount>\n              )}\n            </>\n          )}\n        </StyledButton>\n        {otState.isOpen && (\n          <MinimalistPopover handleClose={handleClose} triggerRef={triggerRef}>\n            <Listbox\n              aria-label={ariaLabel}\n              role=\"listbox\"\n              id={listboxId}\n              ref={listboxRef}\n              aria-multiselectable={multiSelect}\n              onKeyDown={handleListboxKeyDown}\n              tabIndex={isOpen ? 0 : -1}\n            >\n              {options\n                .map((opt) => ({\n                  option: optionOrResetToInternal(opt),\n                  externalOption: opt,\n                }))\n                .map(({ externalOption, option }) => {\n                  const isSelected =\n                    selectedOptions?.some((sel) => sel.value === option.value) &&\n                    option !== resetOption;\n                  const isReset = option === resetOption;\n\n                  return (\n                    <SelectOption\n                      key={option.value === undefined ? 'sb-reset' : String(option.value)}\n                      title={option.title}\n                      description={option.description}\n                      aside={option.aside}\n                      icon={\n                        !isReset && multiSelect ? (\n                          // Purely decorative.\n                          <Form.Checkbox checked={isSelected} hidden role=\"presentation\" />\n                        ) : (\n                          option.icon\n                        )\n                      }\n                      id={valueToId(id, option)}\n                      isActive={isOpen && activeOption?.value === option.value}\n                      isSelected={isSelected}\n                      onClick={() => {\n                        handleSelectOption(option);\n                        if (!multiSelect) {\n                          handleClose();\n                        }\n                      }}\n                      onFocus={() => setActiveOption(externalOption, false)}\n                      shouldLookDisabled={isReset && selectedOptions.length === 0 && multiSelect}\n                      onKeyDown={(e: KeyboardEvent) => {\n                        if (e.key === 'Enter' || e.key === ' ') {\n                          e.preventDefault();\n                          handleSelectOption(option);\n                          if (!multiSelect) {\n                            handleClose();\n                          }\n                        } else if (e.key === 'Tab') {\n                          if (!multiSelect) {\n                            handleSelectOption(option);\n                          }\n                          handleClose();\n                        }\n                      }}\n                    >\n                      {option.children}\n                    </SelectOption>\n                  );\n                })}\n            </Listbox>\n          </MinimalistPopover>\n        )}\n      </>\n    );\n  }\n);\n\nSelect.displayName = 'Select';\n"
  },
  {
    "path": "code/core/src/components/components/Select/SelectOption.stories.tsx",
    "content": "import React from 'react';\n\nimport { TabletIcon } from '@storybook/icons';\n\nimport { expect, fn, within } from 'storybook/test';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { SelectOption } from './SelectOption.tsx';\nimport { Listbox } from './helpers.tsx';\n\nconst meta = preview.meta({\n  id: 'select-option-component',\n  title: 'SelectOption',\n  component: SelectOption,\n  args: {\n    id: 'tablet',\n    title: 'Tablet',\n    icon: <TabletIcon />,\n    isSelected: false,\n    isActive: false,\n    shouldLookDisabled: false,\n    onClick: fn(),\n    onFocus: fn(),\n    onKeyDown: fn(),\n  },\n  decorators: [\n    (Story) => (\n      <Listbox\n        aria-label=\"Sample listbox\"\n        role=\"listbox\"\n        style={{ width: '200px', border: '1px solid #888' }}\n      >\n        <Story />\n      </Listbox>\n    ),\n  ],\n});\n\nexport const Base = meta.story({ args: {} });\n\nexport const WithDescription = meta.story({\n  args: { description: 'Handheld device' },\n});\n\nexport const WithChildren = meta.story({\n  args: {\n    children: (\n      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>\n        <span>🔥</span>\n        <span>Custom children</span>\n      </div>\n    ),\n    id: undefined,\n  },\n});\n\nexport const PseudoStates = meta.story({\n  render: (args) => (\n    <>\n      <SelectOption {...args} id=\"inactive\">\n        Inactive\n      </SelectOption>\n      <SelectOption {...args} id=\"hover\" data-state=\"hover\">\n        Hover\n      </SelectOption>\n      <SelectOption {...args} id=\"focus\" data-state=\"focus\">\n        Focus\n      </SelectOption>\n      <SelectOption {...args} id=\"sep1\" shouldLookDisabled>\n        ---------\n      </SelectOption>\n      <SelectOption {...args} id=\"inactive-selected\" isSelected>\n        Inactive Selected\n      </SelectOption>\n      <SelectOption {...args} id=\"hover-selected\" data-state=\"hover\" isSelected>\n        Hover Selected\n      </SelectOption>\n      <SelectOption {...args} id=\"focus-selected\" data-state=\"focus\" isSelected>\n        Focus Selected\n      </SelectOption>\n      <SelectOption {...args} id=\"sep2\" shouldLookDisabled>\n        ---------\n      </SelectOption>\n      <SelectOption {...args} id=\"inactive-disabled\" shouldLookDisabled>\n        Inactive Disabled\n      </SelectOption>\n      <SelectOption {...args} id=\"hover-disabled\" data-state=\"hover\" shouldLookDisabled>\n        Hover Disabled\n      </SelectOption>\n      <SelectOption {...args} id=\"focus-disabled\" data-state=\"focus\" shouldLookDisabled>\n        Focus Disabled\n      </SelectOption>\n    </>\n  ),\n  parameters: {\n    pseudo: {\n      hover: '[data-state=\"hover\"]',\n      focus: '[data-state=\"focus\"]',\n      focusVisible: '[data-state=\"focus\"]',\n    },\n  },\n});\n\nexport const Active = meta.story({\n  args: { isActive: true },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const option = canvas.getByRole('option');\n    await expect(option).toHaveAttribute('tabindex', '0');\n  },\n});\n\nexport const Selected = meta.story({\n  args: { isSelected: true },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const option = canvas.getByRole('option');\n    await expect(option).toHaveAttribute('aria-selected', 'true');\n  },\n});\nexport const SelectedActive = meta.story({\n  args: { isSelected: true, isActive: true },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const option = canvas.getByRole('option');\n    await expect(option).toHaveAttribute('aria-selected', 'true');\n    await expect(option).toHaveAttribute('tabindex', '0');\n  },\n});\n\nexport const Disabled = meta.story({\n  args: { shouldLookDisabled: true },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const option = canvas.getByRole('option');\n    await expect(option).toHaveAttribute('aria-disabled', 'true');\n  },\n});\n\nexport const SelectedDisabled = meta.story({\n  args: { isSelected: true, shouldLookDisabled: true },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const option = canvas.getByRole('option');\n    await expect(option).toHaveAttribute('aria-disabled', 'true');\n    await expect(option).toHaveAttribute('aria-selected', 'true');\n  },\n});\n\nexport const SelectedDisabledActive = meta.story({\n  args: { isSelected: true, shouldLookDisabled: true, isActive: true },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const option = canvas.getByRole('option');\n    await expect(option).toHaveAttribute('aria-disabled', 'true');\n    await expect(option).toHaveAttribute('aria-selected', 'true');\n    await expect(option).toHaveAttribute('tabindex', '0');\n  },\n});\n"
  },
  {
    "path": "code/core/src/components/components/Select/SelectOption.tsx",
    "content": "import React from 'react';\n\nimport { ActionList } from '../../index.ts';\n\nexport interface SelectOptionProps {\n  /**\n   * DOM id attribute for the option, unique across the entire app. This is not the value of the\n   * option. We don't need the value internally as it's handled in event handlers by the parent\n   * component.\n   */\n  id: string;\n\n  /** Label for the option (injected in aria-labels). */\n  title: string;\n\n  /** Secondary text or description not necessary to identify the option. */\n  description?: string;\n\n  /** Decorative icon, displayed to the left of the title and description. */\n  icon?: React.ReactNode;\n\n  /** Extra content, displayed to the right of the title and description. */\n  aside?: React.ReactNode;\n\n  /** Optional rendering of the option. Use sparingly. */\n  children?: React.ReactNode;\n\n  /** Whether the option has been selected by the user or programmatically. */\n  isSelected: boolean;\n\n  /** Whether the option is currently focused in the listbox. */\n  isActive: boolean;\n\n  onClick: () => void;\n  onFocus: () => void;\n  onKeyDown: (e: React.KeyboardEvent) => void;\n\n  /**\n   * Whether to print out the option as if it could not be enabled. Does NOT prevent event handlers\n   * from being called as we need them to implement keyboard navigation.\n   */\n  shouldLookDisabled: boolean;\n}\n\nexport const SelectOption: React.FC<SelectOptionProps> = ({\n  id,\n  title,\n  description,\n  icon,\n  aside,\n  children,\n  isSelected,\n  isActive,\n  onClick,\n  onFocus,\n  onKeyDown,\n  shouldLookDisabled = false,\n  ...props\n}) => {\n  return (\n    <ActionList.Item\n      {...props}\n      id={id}\n      role=\"option\"\n      tabIndex={isActive ? 0 : -1}\n      aria-selected={isSelected}\n      aria-disabled={shouldLookDisabled ? true : undefined}\n      onClick={onClick}\n      onFocus={onFocus}\n      onKeyDown={onKeyDown}\n    >\n      {children ?? (\n        <>\n          {icon && <ActionList.Icon>{icon}</ActionList.Icon>}\n          <ActionList.Text>\n            <p>{title}</p>\n            {description && <small>{description}</small>}\n          </ActionList.Text>\n          {aside}\n        </>\n      )}\n    </ActionList.Item>\n  );\n};\n\nSelectOption.displayName = 'SelectOption';\n"
  },
  {
    "path": "code/core/src/components/components/Select/helpers.tsx",
    "content": "import type React from 'react';\n\nimport { styled } from 'storybook/theming';\n\nexport const PAGE_STEP_SIZE = 5;\nexport const UNDEFINED_VALUE = Symbol.for('undefined');\n\nexport type Value = string | number | null | boolean | undefined;\nexport type InternalValue = string | number | null | boolean | typeof UNDEFINED_VALUE;\n\nexport interface Option {\n  /** Optional rendering of the option. */\n  children?: React.ReactNode;\n  title: string;\n  description?: string;\n  icon?: React.ReactNode;\n  aside?: React.ReactNode;\n  value: Value;\n}\nexport interface InternalOption extends Omit<Option, 'value'> {\n  type: 'option';\n  value: InternalValue;\n}\nexport interface ResetOption extends Omit<Option, 'value'> {\n  type: 'reset';\n  value: undefined;\n}\n\nexport function isLiteralValue(value: Value | Value[] | undefined): value is Value {\n  return (\n    value === undefined ||\n    value === null ||\n    typeof value === 'string' ||\n    typeof value === 'number' ||\n    typeof value === 'boolean' ||\n    typeof value === 'symbol'\n  );\n}\n\nexport function optionToInternal(option: Option): InternalOption {\n  return {\n    ...option,\n    type: 'option',\n    value: externalToValue(option.value),\n  };\n}\n\nexport function optionOrResetToInternal(\n  option: Option | ResetOption\n): InternalOption | ResetOption {\n  if ('type' in option && option.type === 'reset') {\n    return option;\n  }\n  return optionToInternal(option);\n}\n\nexport function valueToExternal(value: InternalValue): Value {\n  if (value === UNDEFINED_VALUE) {\n    return undefined;\n  }\n  return value;\n}\n\nexport function externalToValue(value: Value): InternalValue {\n  if (value === undefined) {\n    return UNDEFINED_VALUE;\n  }\n  return value;\n}\n\nexport const Listbox = styled('ul')({\n  minWidth: 180,\n  height: '100%',\n  borderRadius: 6,\n  overflow: 'hidden auto',\n  listStyle: 'none',\n  margin: 0,\n  padding: 4,\n});\n"
  },
  {
    "path": "code/core/src/components/components/Tabs/Button.tsx",
    "content": "import type {\n  AnchorHTMLAttributes,\n  ButtonHTMLAttributes,\n  DetailedHTMLProps,\n  ForwardRefExoticComponent,\n  ForwardedRef,\n  ReactElement,\n  ReactNode,\n  RefAttributes,\n} from 'react';\nimport React, { forwardRef } from 'react';\n\nimport { deprecate } from 'storybook/internal/client-logger';\n\nimport { isPropValid, styled } from 'storybook/theming';\n\ninterface ButtonProps extends DetailedHTMLProps<\n  ButtonHTMLAttributes<HTMLButtonElement>,\n  HTMLButtonElement\n> {\n  href?: never;\n  target?: never;\n}\ninterface LinkProps extends DetailedHTMLProps<\n  AnchorHTMLAttributes<HTMLAnchorElement>,\n  HTMLAnchorElement\n> {\n  disabled?: void;\n  href: string;\n}\n\nconst isLink = (obj: {\n  props: ButtonProps | LinkProps;\n  ref: ForwardedRef<HTMLButtonElement> | ForwardedRef<HTMLAnchorElement>;\n}): obj is { props: LinkProps; ref: ForwardedRef<HTMLAnchorElement> } => {\n  return typeof obj.props.href === 'string';\n};\n\nconst isButton = (obj: {\n  props: ButtonProps | LinkProps;\n  ref: ForwardedRef<HTMLButtonElement> | ForwardedRef<HTMLAnchorElement>;\n}): obj is { props: ButtonProps; ref: ForwardedRef<HTMLButtonElement> } => {\n  return typeof obj.props.href !== 'string';\n};\n\nfunction ForwardRefFunction(p: LinkProps, r: ForwardedRef<HTMLAnchorElement>): ReactElement;\nfunction ForwardRefFunction(p: ButtonProps, r: ForwardedRef<HTMLButtonElement>): ReactElement;\nfunction ForwardRefFunction(\n  { children, ...rest }: ButtonProps | LinkProps,\n  ref: ForwardedRef<HTMLButtonElement> | ForwardedRef<HTMLAnchorElement>\n) {\n  const o = { props: rest, ref };\n  if (isLink(o)) {\n    return (\n      <a ref={o.ref} {...o.props}>\n        {children}\n      </a>\n    );\n  }\n  if (isButton(o)) {\n    return (\n      <button ref={o.ref} type=\"button\" {...o.props}>\n        {children}\n      </button>\n    );\n  }\n  throw new Error('invalid props');\n}\ntype ButtonLike<P = {}> = ForwardRefExoticComponent<\n  Omit<ButtonProps, 'ref'> & RefAttributes<HTMLButtonElement> & P\n>;\n\ntype LinkLike<P = {}> = ForwardRefExoticComponent<\n  Omit<LinkProps, 'ref'> & RefAttributes<HTMLAnchorElement> & P\n>;\n\nconst ButtonOrLink: ButtonLike | LinkLike = forwardRef(ForwardRefFunction);\n\nButtonOrLink.displayName = 'ButtonOrLink';\n\nexport interface TabButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n  active?: boolean;\n  children: ReactNode;\n  id?: string;\n  textColor?: string;\n}\n\nconst StyledTabButton = styled(ButtonOrLink, { shouldForwardProp: isPropValid })<TabButtonProps>(\n  {\n    whiteSpace: 'normal',\n    display: 'inline-flex',\n    overflow: 'hidden',\n    verticalAlign: 'top',\n    justifyContent: 'center',\n    alignItems: 'center',\n    textAlign: 'center',\n    textDecoration: 'none',\n\n    '&:empty': {\n      display: 'none',\n    },\n    '&[hidden]': {\n      display: 'none',\n    },\n  },\n  ({ theme }) => ({\n    padding: '0 15px',\n    transition: 'color 0.2s linear, border-bottom-color 0.2s linear',\n    height: 40,\n    lineHeight: '12px',\n    cursor: 'pointer',\n    background: 'transparent',\n    border: '0 solid transparent',\n    borderTop: '3px solid transparent',\n    borderBottom: '3px solid transparent',\n    fontWeight: 'bold',\n    fontSize: 13,\n\n    '&:focus': {\n      outline: '0 none',\n      borderBottomColor: theme.barSelectedColor,\n    },\n  }),\n  ({ active, textColor, theme }) =>\n    active\n      ? {\n          color: textColor || theme.barSelectedColor,\n          borderBottomColor: theme.barSelectedColor,\n        }\n      : {\n          color: textColor || theme.barTextColor,\n          borderBottomColor: 'transparent',\n          '&:hover': {\n            color: theme.barHoverColor,\n          },\n        }\n);\n\nexport const TabButton = forwardRef<HTMLButtonElement, TabButtonProps>((props, ref) => {\n  deprecate('The `TabButton` component is deprecated. Use `TabList` instead.');\n  return <StyledTabButton data-deprecated=\"TabButton\" ref={ref} {...props} />;\n});\nTabButton.displayName = 'TabButton';\n"
  },
  {
    "path": "code/core/src/components/components/Tabs/EmptyTabContent.stories.tsx",
    "content": "import React from 'react';\n\nimport { Link } from 'storybook/internal/components';\n\nimport { DocumentIcon } from '@storybook/icons';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { EmptyTabContent } from './EmptyTabContent.tsx';\n\nexport default {\n  title: 'Tabs/TabContentEmpty',\n  component: EmptyTabContent,\n  parameters: {\n    layout: 'centered',\n  },\n  tags: ['autodocs'],\n} satisfies Meta<typeof EmptyTabContent>;\n\ntype Story = StoryObj<typeof EmptyTabContent>;\n\nexport const OnlyTitle: Story = {\n  args: {\n    title: 'Nothing found',\n  },\n};\n\nexport const TitleAndDescription: Story = {\n  args: {\n    title: 'Nothing found',\n    description: 'Sorry, there is nothing to display here.',\n  },\n};\n\nexport const TitleAndFooter: Story = {\n  args: {\n    title: 'Nothing found',\n    footer: (\n      <Link href=\"foo\" withArrow>\n        <DocumentIcon /> See the docs\n      </Link>\n    ),\n  },\n};\n\nexport const TitleDescriptionAndFooter: Story = {\n  args: {\n    title: 'Nothing found',\n    description: 'Sorry, there is nothing to display here.',\n    footer: (\n      <Link href=\"foo\" withArrow>\n        <DocumentIcon /> See the docs\n      </Link>\n    ),\n  },\n};\n"
  },
  {
    "path": "code/core/src/components/components/Tabs/EmptyTabContent.tsx",
    "content": "import React from 'react';\n\nimport { styled } from 'storybook/theming';\n\nconst Wrapper = styled.div(({ theme }) => ({\n  height: '100%',\n  display: 'flex',\n  padding: 30,\n  alignItems: 'center',\n  justifyContent: 'center',\n  flexDirection: 'column',\n  gap: 15,\n  background: theme.background.content,\n}));\n\nconst Content = styled.div({\n  display: 'flex',\n  flexDirection: 'column',\n  gap: 4,\n  maxWidth: 415,\n});\n\nconst Title = styled.div(({ theme }) => ({\n  fontWeight: theme.typography.weight.bold,\n  fontSize: theme.typography.size.s2 - 1,\n  textAlign: 'center',\n  color: theme.color.defaultText,\n}));\n\nconst Footer = styled.div(({ theme }) => ({\n  fontSize: theme.typography.size.s2 - 1,\n}));\n\nconst Description = styled.div(({ theme }) => ({\n  fontWeight: theme.typography.weight.regular,\n  fontSize: theme.typography.size.s2 - 1,\n  textAlign: 'center',\n  color: theme.textMutedColor,\n}));\n\ninterface Props {\n  title: React.ReactNode;\n  description?: React.ReactNode;\n  footer?: React.ReactNode;\n}\n\nexport const EmptyTabContent = ({ title, description, footer }: Props) => {\n  return (\n    <Wrapper>\n      <Content>\n        <Title>{title}</Title>\n        {description && <Description>{description}</Description>}\n      </Content>\n      {footer && <Footer>{footer}</Footer>}\n    </Wrapper>\n  );\n};\n"
  },
  {
    "path": "code/core/src/components/components/Tabs/StatelessTab.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { Tab } from 'react-aria-components/patched-dist/Tabs';\nimport { styled } from 'storybook/theming';\n\nexport interface StatelessTabProps {\n  /** Unique id of the Tab, must match that of its corresponding TabPanel. */\n  name: string;\n\n  /** Tab button content */\n  children: React.ReactNode;\n}\n\nconst StyledTab = styled(Tab)(({ theme }) => ({\n  whiteSpace: 'normal',\n  display: 'inline-flex',\n  overflow: 'hidden',\n  verticalAlign: 'top',\n  justifyContent: 'center',\n  alignItems: 'center',\n  textAlign: 'center',\n  textDecoration: 'none',\n  scrollSnapAlign: 'start',\n  '&:empty': {\n    display: 'none',\n  },\n  '&[hidden]': {\n    display: 'none',\n  },\n  padding: '0 15px',\n  transition: 'color 0.2s linear, border-bottom-color 0.2s linear',\n  height: 40,\n  lineHeight: '12px',\n  cursor: 'pointer',\n  background: 'transparent',\n  border: '0 solid transparent',\n  borderTop: '3px solid transparent',\n  borderBottom: '3px solid transparent',\n  fontWeight: 'bold',\n  fontSize: 13,\n  '&:focus-visible': {\n    outline: '0 none',\n    boxShadow: `inset 0 0 0 2px ${theme.barSelectedColor}`,\n  },\n  color: theme.barTextColor,\n  borderBottomColor: 'transparent',\n  '&:hover': {\n    color: theme.barHoverColor,\n  },\n  '&[data-selected]': {\n    color: theme.barSelectedColor,\n    borderBottomColor: theme.barSelectedColor,\n  },\n}));\n\nexport const StatelessTab: FC<StatelessTabProps> = ({ name, ...props }) => {\n  return <StyledTab id={name} {...props} />;\n};\n"
  },
  {
    "path": "code/core/src/components/components/Tabs/StatelessTabList.tsx",
    "content": "import type { FC, ReactNode } from 'react';\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { ChevronSmallLeftIcon, ChevronSmallRightIcon } from '@storybook/icons';\n\nimport { TabList as TabListUpstream } from 'react-aria-components/patched-dist/Tabs';\nimport { styled } from 'storybook/theming';\n\nimport { Button } from '../Button/Button.tsx';\n\nconst Root = styled.div({\n  display: 'flex',\n  alignItems: 'center',\n  flexShrink: 0,\n  position: 'relative',\n  overflow: 'hidden',\n});\n\nconst ScrollContainer = styled.div({\n  display: 'flex',\n  overflowX: 'auto',\n  scrollbarWidth: 'none',\n  msOverflowStyle: 'none',\n  WebkitScrollbar: 'none',\n  scrollSnapType: 'x mandatory',\n  flex: 1,\n\n  '&::-webkit-scrollbar': {\n    display: 'none',\n  },\n});\n\nconst StyledTabList = styled(TabListUpstream)({\n  display: 'flex',\n  flexShrink: 0,\n});\n\nconst SCROLL_BUTTON_WIDTH = 28; // 16 width + 6 + 6 padding\n\nconst ScrollButtonContainer = styled.div<{\n  $showStartBorder?: boolean;\n  $showEndBorder?: boolean;\n}>(({ $showStartBorder, $showEndBorder, theme }) => ({\n  flexShrink: 0,\n  display: 'flex',\n  alignItems: 'center',\n  justifyContent: 'center',\n  padding: 6,\n  boxShadow: $showStartBorder\n    ? `inset 1px 0 0 ${theme.appBorderColor}`\n    : $showEndBorder\n      ? `inset -1px 0 0 ${theme.appBorderColor}`\n      : 'none',\n}));\n\nconst ScrollButton = styled(Button)({\n  flexShrink: 0,\n  paddingInline: 0,\n  width: 16,\n});\n\nexport interface StatelessTabListProps {\n  children?: ReactNode;\n}\n\nexport const StatelessTabList: FC<StatelessTabListProps> = ({ children, ...rest }) => {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const scrollContainerRef = useRef<HTMLDivElement>(null);\n\n  const [showScrollButtons, setShowScrollButtons] = useState(false);\n  const [canScrollLeft, setCanScrollLeft] = useState(false);\n  const [canScrollRight, setCanScrollRight] = useState(false);\n\n  const updateScrollState = useCallback(() => {\n    const scrollContainer = scrollContainerRef.current;\n    const container = containerRef.current;\n\n    if (!scrollContainer || !container) {\n      return;\n    }\n\n    const { scrollLeft, scrollWidth, clientWidth } = scrollContainer;\n    const availableWidth =\n      container.clientWidth - (showScrollButtons ? SCROLL_BUTTON_WIDTH * 2 : 0);\n\n    const needsScrolling = scrollWidth > availableWidth;\n    setShowScrollButtons(needsScrolling);\n\n    if (needsScrolling) {\n      setCanScrollLeft(scrollLeft > 0);\n      setCanScrollRight(scrollLeft < scrollWidth - clientWidth);\n    } else {\n      setCanScrollLeft(false);\n      setCanScrollRight(false);\n    }\n  }, [showScrollButtons]);\n\n  const throttledUpdateScrollState = useCallback(() => {\n    updateScrollState();\n  }, [updateScrollState]);\n\n  useEffect(() => {\n    const scrollContainer = scrollContainerRef.current;\n    if (!scrollContainer || typeof window === 'undefined') {\n      return;\n    }\n\n    scrollContainer.addEventListener('scroll', throttledUpdateScrollState, { passive: true });\n\n    // SSR safety: ResizeObserver may not exist in all environments\n    let resizeObserver: ResizeObserver | null = null;\n    if (typeof ResizeObserver !== 'undefined') {\n      resizeObserver = new ResizeObserver(throttledUpdateScrollState);\n      resizeObserver.observe(scrollContainer);\n    }\n\n    // Initial update - delay to ensure DOM is ready\n    const timeoutId = setTimeout(throttledUpdateScrollState, 0);\n\n    return () => {\n      clearTimeout(timeoutId);\n      scrollContainer.removeEventListener('scroll', throttledUpdateScrollState);\n      if (resizeObserver) {\n        resizeObserver.disconnect();\n      }\n    };\n  }, [throttledUpdateScrollState]);\n\n  const scroll = useCallback((direction: 'backward' | 'forward') => {\n    const scrollContainer = scrollContainerRef.current;\n    const container = containerRef.current;\n\n    if (!scrollContainer || !container || typeof window === 'undefined') {\n      return;\n    }\n\n    const availableWidth = container.clientWidth - SCROLL_BUTTON_WIDTH * 2;\n    const scrollDistance = direction === 'backward' ? -availableWidth : availableWidth;\n\n    // SSR safety: scrollBy may not exist in all environments\n    if (typeof scrollContainer.scrollBy === 'function') {\n      scrollContainer.scrollBy({ left: scrollDistance, behavior: 'smooth' });\n    } else {\n      // Fallback for older browsers or SSR\n      scrollContainer.scrollLeft += scrollDistance;\n    }\n  }, []);\n\n  const scrollBackward = useCallback(() => scroll('backward'), [scroll]);\n  const scrollForward = useCallback(() => scroll('forward'), [scroll]);\n\n  return (\n    <Root ref={containerRef} className={`tablist ${showScrollButtons ? 'tablist-has-scroll' : ''}`}>\n      {showScrollButtons && (\n        <ScrollButtonContainer $showEndBorder={canScrollLeft}>\n          <ScrollButton\n            variant=\"ghost\"\n            padding=\"small\"\n            size=\"small\"\n            ariaLabel=\"Scroll backward\"\n            disabled={!canScrollLeft}\n            onClick={scrollBackward}\n            tabIndex={-1}\n          >\n            <ChevronSmallLeftIcon />\n          </ScrollButton>\n        </ScrollButtonContainer>\n      )}\n      <ScrollContainer ref={scrollContainerRef}>\n        <StyledTabList {...rest}>{children}</StyledTabList>\n      </ScrollContainer>\n      {showScrollButtons && (\n        <ScrollButtonContainer $showStartBorder={canScrollRight}>\n          <ScrollButton\n            variant=\"ghost\"\n            padding=\"small\"\n            size=\"small\"\n            ariaLabel=\"Scroll forward\"\n            disabled={!canScrollRight}\n            onClick={scrollForward}\n            tabIndex={-1}\n          >\n            <ChevronSmallRightIcon />\n          </ScrollButton>\n        </ScrollButtonContainer>\n      )}\n    </Root>\n  );\n};\n"
  },
  {
    "path": "code/core/src/components/components/Tabs/StatelessTabPanel.tsx",
    "content": "import type { FC, ReactNode } from 'react';\nimport React from 'react';\n\nimport { TabPanel } from 'react-aria-components/patched-dist/Tabs';\nimport { styled } from 'storybook/theming';\n\nimport { ScrollArea } from '../ScrollArea/ScrollArea.tsx';\n\nexport interface StatelessTabPanelProps {\n  /** Content of the tab panel. */\n  children: ReactNode;\n\n  /** Unique id of the TabPanel, must match that of its corresponding Tab. */\n  name: string;\n\n  /**\n   * Whether the panel adds a vertical scrollbar. Disable if you want to use fixed or sticky\n   * positioning on part of the tab's content. True by default.\n   */\n  hasScrollbar?: boolean;\n}\n\nconst Root = styled(TabPanel)({\n  overflowY: 'hidden',\n  height: '100%',\n  display: 'block',\n  ['&[inert=\"true\"]']: { display: 'none' },\n});\n\nexport const StatelessTabPanel: FC<StatelessTabPanelProps> = ({\n  children,\n  hasScrollbar = true,\n  name,\n  ...rest\n}) => {\n  return (\n    <Root {...rest} shouldForceMount id={name}>\n      {hasScrollbar ? <ScrollArea vertical>{children}</ScrollArea> : children}\n    </Root>\n  );\n};\n"
  },
  {
    "path": "code/core/src/components/components/Tabs/StatelessTabsView.stories.tsx",
    "content": "import { useState } from 'react';\n\nimport { Button, EmptyTabContent } from 'storybook/internal/components';\n\nimport { CrossIcon, ExpandIcon } from '@storybook/icons';\n\nimport { fn } from 'storybook/test';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { StatelessTab } from './StatelessTab.tsx';\nimport { StatelessTabList } from './StatelessTabList.tsx';\nimport { StatelessTabPanel } from './StatelessTabPanel.tsx';\nimport { StatelessTabsView, type StatelessTabsViewProps } from './StatelessTabsView.tsx';\n\nconst RenderDefault = (args: StatelessTabsViewProps) => (\n  <StatelessTabsView {...args}>\n    <StatelessTabList>\n      <StatelessTab name=\"tab1\">Tab 1</StatelessTab>\n      <StatelessTab name=\"tab2\">Tab 2</StatelessTab>\n      <StatelessTab name=\"tab3\">Tab 3</StatelessTab>\n    </StatelessTabList>\n    <StatelessTabPanel name=\"tab1\">\n      <div>Content for Tab 1</div>\n    </StatelessTabPanel>\n    <StatelessTabPanel name=\"tab2\">\n      <div>Content for Tab 2</div>\n    </StatelessTabPanel>\n    <StatelessTabPanel name=\"tab3\">\n      <div>Content for Tab 3</div>\n    </StatelessTabPanel>\n  </StatelessTabsView>\n);\n\nconst RenderEmpty = (args: StatelessTabsViewProps) => (\n  <StatelessTabsView {...args}>\n    <StatelessTabList></StatelessTabList>\n  </StatelessTabsView>\n);\n\nconst DEFAULT_TOOLS = (\n  <div>\n    <Button variant=\"ghost\" padding=\"small\" ariaLabel=\"Go full screen\">\n      <ExpandIcon />\n    </Button>\n    <Button variant=\"ghost\" padding=\"small\" ariaLabel=\"Close\">\n      <CrossIcon />\n    </Button>\n  </div>\n);\n\n/**\n * Use this version of TabsView when you must ensure your tabs get rendered immediately and stay\n * stateful across the lifecycle of the TabsView, and/or when you can't afford to pass them as a\n * data array to feed into useTabsState. An example of that is the addons panel.\n */\nconst meta = preview.meta({\n  title: 'Tabs/StatelessTabsView',\n  component: StatelessTabsView,\n  args: { backgroundColor: '#2e2e2e', children: '', tools: DEFAULT_TOOLS },\n  globals: { sb_theme: 'dark' },\n});\n\nexport const Basic = meta.story({\n  args: {},\n  render: RenderDefault,\n});\n\nexport const Empty = meta.story({\n  args: {},\n  render: RenderEmpty,\n});\n\nexport const EmptyCustom = meta.story({\n  args: {\n    emptyState: (\n      <EmptyTabContent\n        title=\"Custom empty state\"\n        description={<>This component does not currently have tabs.</>}\n      />\n    ),\n  },\n  render: RenderEmpty,\n});\n\nexport const EmptyWithToolsShowFalse = meta.story({\n  args: {\n    showToolsWhenEmpty: false,\n  },\n  render: RenderEmpty,\n});\n\nexport const EmptyWithToolsShowTrue = meta.story({\n  args: {\n    showToolsWhenEmpty: true,\n  },\n  render: RenderEmpty,\n});\n\nexport const EmptyToolsShowCustom = meta.story({\n  args: {\n    emptyState: (\n      <EmptyTabContent\n        title=\"Custom empty state\"\n        description={<>This component does not currently have tabs.</>}\n      />\n    ),\n    showToolsWhenEmpty: true,\n  },\n  render: RenderEmpty,\n});\n\nexport const DefaultSelected = meta.story({\n  args: {\n    defaultSelected: 'tab2',\n  },\n  render: RenderDefault,\n});\n\nexport const ControlledState = meta.story({\n  args: {\n    selected: 'tab2',\n    onSelectionChange: fn(),\n  },\n  render: (args) => {\n    const [selected, setSelected] = useState(args.selected);\n    return (\n      <>\n        <p>\n          Current tab: <strong>{selected}</strong>\n        </p>\n        <RenderDefault\n          {...args}\n          selected={selected}\n          onSelectionChange={(key) => {\n            setSelected(key);\n            args.onSelectionChange?.(key);\n          }}\n        />\n      </>\n    );\n  },\n});\n"
  },
  {
    "path": "code/core/src/components/components/Tabs/StatelessTabsView.tsx",
    "content": "import type { FC, ReactNode } from 'react';\nimport React from 'react';\n\nimport { Tabs } from 'react-aria-components/patched-dist/Tabs';\nimport { styled } from 'storybook/theming';\n\nimport { Bar } from '../Bar/Bar.tsx';\nimport { EmptyTabContent } from './EmptyTabContent.tsx';\nimport type { TabsViewProps } from './TabsView.tsx';\n\nconst Container = styled(Tabs)<{ $simulatedGap: string | number }>(({ $simulatedGap }) => ({\n  display: 'flex',\n  flexDirection: 'column',\n  height: '100%',\n\n  '.tablist': {\n    flex: '1 1 100%',\n  },\n\n  '.tablist.tablist-has-scroll': {\n    marginInlineEnd: $simulatedGap,\n  },\n\n  '& > :not(:first-child)': { flex: 1 },\n}));\n\nexport interface StatelessTabsViewProps extends Omit<TabsViewProps, 'tabs'> {\n  children: ReactNode;\n}\n\nexport const StatelessTabsView: FC<StatelessTabsViewProps> = ({\n  backgroundColor,\n  barInnerStyle,\n  children,\n  defaultSelected,\n  emptyState,\n  onSelectionChange,\n  selected,\n  showToolsWhenEmpty,\n  tools,\n  ...props\n}) => {\n  const EmptyContent = emptyState ?? <EmptyTabContent title=\"Nothing found\" />;\n  const [tabListChild, ...tabPanelChildren] = React.Children.toArray(children);\n  const hasContent = tabPanelChildren && tabPanelChildren.length > 0;\n\n  if (!showToolsWhenEmpty && !hasContent) {\n    return EmptyContent;\n  }\n\n  return (\n    <Container\n      {...props}\n      $simulatedGap={barInnerStyle?.gap ?? 6}\n      defaultSelectedKey={defaultSelected}\n      onSelectionChange={(k) => onSelectionChange?.(k ? `${k}` : '')}\n      selectedKey={selected}\n    >\n      <Bar\n        scrollable={false}\n        border\n        backgroundColor={backgroundColor}\n        innerStyle={{\n          display: 'flex',\n          justifyContent: 'space-between',\n          paddingInlineStart: 0,\n          paddingInlineEnd: 10,\n          // A11y: the tools must be before the tab list in the DOM for correct tab order.\n          // This lets us control order without adding a wrapper div, leading to better flex\n          // behavior on tools for our callees (e.g. containerType: 'inline-size' in a11y-addon).\n          '> *:not(:last-child)': {\n            order: 2,\n          },\n          '> *': {\n            flexShrink: 0,\n          },\n          ...barInnerStyle,\n          gap: 0,\n        }}\n      >\n        {tools}\n        {hasContent ? tabListChild : <div />}\n      </Bar>\n      {hasContent ? tabPanelChildren : EmptyContent}\n    </Container>\n  );\n};\n"
  },
  {
    "path": "code/core/src/components/components/Tabs/TabList.stories.tsx",
    "content": "import { Bar } from 'storybook/internal/components';\n\nimport { expect } from 'storybook/test';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { TabList } from './TabList.tsx';\nimport { TabPanel } from './TabPanel.tsx';\nimport type { TabProps } from './TabsView.tsx';\nimport { useTabsState } from './TabsView.tsx';\n\nconst DEFAULT_TABS: TabProps[] = [\n  {\n    id: 'tab1',\n    'aria-label': 'Tab one',\n    title: 'Tab 1',\n    children: () => <div>Content for Tab 1</div>,\n  },\n  { id: 'tab2', title: 'Tab 2', children: () => <div>Content for Tab 2</div> },\n  { id: 'tab3', title: 'Tab 3', children: () => <div>Content for Tab 3</div> },\n];\n\nconst MANY_TABS: TabProps[] = Array.from({ length: 20 }, (_, i) => ({\n  id: `tab${i + 1}`,\n  title: `Tab ${i + 1}`,\n  children: () => <div>Content for Tab {i + 1}</div>,\n}));\n\nconst LONG_TITLE_TABS: TabProps[] = [\n  { id: 'tab1', title: 'Short', children: () => <div>Content for Tab 1</div> },\n  {\n    id: 'tab2',\n    title: 'A very long tab title that will take up space',\n    children: () => <div>Content for Tab 2</div>,\n  },\n  {\n    id: 'tab3',\n    title: 'Another extremely long tab title',\n    children: () => <div>Content for Tab 3</div>,\n  },\n  { id: 'tab4', title: 'Medium title', children: () => <div>Content for Tab 4</div> },\n  {\n    id: 'tab5',\n    title: 'Yet another very long tab title that extends',\n    children: () => <div>Content for Tab 5</div>,\n  },\n];\n\nconst meta = preview.meta({\n  title: 'Tabs/TabList',\n  component: TabList,\n  args: {\n    tabs: DEFAULT_TABS,\n    state: undefined,\n  },\n  parameters: {\n    data: {\n      tabs: DEFAULT_TABS,\n    },\n  },\n  decorators: [\n    (Story, { args, parameters }) => {\n      const state = useTabsState({ tabs: parameters.data.tabs });\n      return (\n        <>\n          <Story args={{ ...args, state }} />\n          <TabPanel state={state} />\n        </>\n      );\n    },\n  ],\n});\n\nexport const Basic = meta.story({});\n\nexport const WithAriaLabel = meta.story({\n  parameters: {\n    data: {\n      tabs: DEFAULT_TABS.map((tab) => ({\n        ...tab,\n        'aria-label': `Aria label for ${tab.title}`,\n      })),\n    },\n  },\n});\n\nexport const WithDisabledTab = meta.story({\n  parameters: {\n    data: {\n      tabs: [\n        ...DEFAULT_TABS,\n        {\n          id: 'tab4',\n          title: 'Disabled Tab',\n          children: () => <div>Content for Disabled Tab</div>,\n          isDisabled: true,\n        },\n      ],\n    },\n  },\n});\n\nexport const WithManyTabs = meta.story({\n  name: 'With Many Tabs (Scroll)',\n  parameters: {\n    data: {\n      tabs: MANY_TABS,\n    },\n  },\n});\n\nexport const WithLongTitles = meta.story({\n  name: 'With Long Titles (Scroll)',\n  parameters: {\n    data: {\n      tabs: LONG_TITLE_TABS,\n    },\n  },\n});\n\nexport const WithFixedWidth = meta.story({\n  name: 'Fixed Width Container (Scroll)',\n  parameters: {\n    data: {\n      tabs: MANY_TABS.slice(0, 10),\n    },\n  },\n  decorators: [\n    (Story, { args }) => {\n      return (\n        <Bar\n          border\n          scrollable={false}\n          innerStyle={{ width: 400, padding: 0 }}\n          backgroundColor={'rgba(0,0,0,.05)'}\n        >\n          <Story args={{ ...args }} />\n        </Bar>\n      );\n    },\n  ],\n});\n\nexport const PreservesAriaLabels = meta.story({\n  name: 'Preserves ARIA Labels',\n  play: ({ canvas }) => {\n    const tabOne = canvas.getAllByRole('tab')[0];\n    expect(tabOne).toHaveAttribute('aria-label', 'Tab one');\n  },\n});\n"
  },
  {
    "path": "code/core/src/components/components/Tabs/TabList.tsx",
    "content": "import type { FC, HTMLAttributes } from 'react';\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { ChevronSmallLeftIcon, ChevronSmallRightIcon } from '@storybook/icons';\n\nimport { useTab, useTabList } from '@react-aria/tabs';\nimport type { TabListState } from '@react-stately/tabs';\nimport type { Node } from '@react-types/shared';\nimport { styled } from 'storybook/theming';\n\nimport { Button } from '../Button/Button.tsx';\nimport type { useTabsState } from './TabsView.tsx';\n\nconst StyledTabButton = styled.button<{\n  isDisabled: boolean;\n  isPressed: boolean;\n  isSelected: boolean;\n}>(\n  {\n    whiteSpace: 'normal',\n    display: 'inline-flex',\n    overflow: 'hidden',\n    verticalAlign: 'top',\n    justifyContent: 'center',\n    alignItems: 'center',\n    textAlign: 'center',\n    textDecoration: 'none',\n    scrollSnapAlign: 'start',\n\n    '&:empty': {\n      display: 'none',\n    },\n    '&[hidden]': {\n      display: 'none',\n    },\n  },\n  ({ theme }) => ({\n    padding: '0 15px',\n    transition: 'color 0.2s linear, border-bottom-color 0.2s linear',\n    height: 40,\n    lineHeight: '12px',\n    cursor: 'pointer',\n    background: 'transparent',\n    border: '0 solid transparent',\n    borderTop: '3px solid transparent',\n    borderBottom: '3px solid transparent',\n    fontWeight: 'bold',\n    fontSize: 13,\n\n    '&:focus-visible': {\n      outline: '0 none',\n      boxShadow: `inset 0 0 0 2px ${theme.barSelectedColor}`,\n    },\n  }),\n  ({ isSelected, theme }) =>\n    isSelected\n      ? {\n          color: theme.barSelectedColor,\n          borderBottomColor: theme.barSelectedColor,\n        }\n      : {\n          color: theme.barTextColor,\n          borderBottomColor: 'transparent',\n          '&:hover': {\n            color: theme.barHoverColor,\n          },\n        }\n);\n\nconst TabListContainer = styled.div({\n  display: 'flex',\n  alignItems: 'center',\n  flexShrink: 0,\n  position: 'relative',\n  overflow: 'hidden',\n});\n\nconst ScrollContainer = styled.div({\n  display: 'flex',\n  overflowX: 'auto',\n  scrollbarWidth: 'none',\n  msOverflowStyle: 'none',\n  WebkitScrollbar: 'none',\n  scrollSnapType: 'x mandatory',\n  flex: 1,\n\n  '&::-webkit-scrollbar': {\n    display: 'none',\n  },\n});\n\nconst StyledTabList = styled.div({\n  display: 'flex',\n  flexShrink: 0,\n});\n\nconst SCROLL_BUTTON_WIDTH = 28; // 16 width + 6 + 6 padding\n\nconst ScrollButtonContainer = styled.div<{\n  $showStartBorder?: boolean;\n  $showEndBorder?: boolean;\n}>(({ $showStartBorder, $showEndBorder, theme }) => ({\n  flexShrink: 0,\n  display: 'flex',\n  alignItems: 'center',\n  justifyContent: 'center',\n  padding: 6,\n  boxShadow: $showStartBorder\n    ? `inset 1px 0 0 ${theme.appBorderColor}`\n    : $showEndBorder\n      ? `inset -1px 0 0 ${theme.appBorderColor}`\n      : 'none',\n}));\n\nconst ScrollButton = styled(Button)({\n  flexShrink: 0,\n  paddingInline: 0,\n  width: 16,\n});\n\ninterface TabButtonProps {\n  item: Node<object>;\n  state: ReturnType<typeof useTabsState>;\n}\n\nconst TabButton: FC<TabButtonProps> = ({ item, state }) => {\n  const { rendered } = item;\n  const tabRef = React.useRef(null);\n  const typedState = state as TabListState<object>;\n  const { tabProps, isDisabled, isPressed, isSelected } = useTab(item, typedState, tabRef);\n\n  return (\n    <StyledTabButton\n      {...tabProps}\n      isDisabled={isDisabled}\n      isPressed={isPressed}\n      isSelected={isSelected}\n      className={`tabbutton ${isSelected ? 'tabbutton-active' : ''}`}\n      ref={tabRef}\n    >\n      {rendered}\n    </StyledTabButton>\n  );\n};\n\nexport interface TabListProps extends HTMLAttributes<HTMLDivElement> {\n  state: ReturnType<typeof useTabsState>;\n}\n\nexport const TabList: FC<TabListProps> = ({ state, ...rest }) => {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const scrollContainerRef = useRef<HTMLDivElement>(null);\n  const tabListRef = useRef<HTMLDivElement>(null);\n  const { tabListProps } = useTabList(\n    { orientation: 'horizontal' },\n    state as TabListState<object>,\n    tabListRef\n  );\n\n  const [showScrollButtons, setShowScrollButtons] = useState(false);\n  const [canScrollLeft, setCanScrollLeft] = useState(false);\n  const [canScrollRight, setCanScrollRight] = useState(false);\n\n  const updateScrollState = useCallback(() => {\n    const scrollContainer = scrollContainerRef.current;\n    const container = containerRef.current;\n\n    if (!scrollContainer || !container) {\n      return;\n    }\n\n    const { scrollLeft, scrollWidth, clientWidth } = scrollContainer;\n    const availableWidth =\n      container.clientWidth - (showScrollButtons ? SCROLL_BUTTON_WIDTH * 2 : 0);\n\n    const needsScrolling = scrollWidth > availableWidth;\n    setShowScrollButtons(needsScrolling);\n\n    if (needsScrolling) {\n      setCanScrollLeft(scrollLeft > 0);\n      setCanScrollRight(scrollLeft < scrollWidth - clientWidth);\n    } else {\n      setCanScrollLeft(false);\n      setCanScrollRight(false);\n    }\n  }, [showScrollButtons]);\n\n  const throttledUpdateScrollState = useCallback(() => {\n    updateScrollState();\n  }, [updateScrollState]);\n\n  useEffect(() => {\n    const scrollContainer = scrollContainerRef.current;\n    if (!scrollContainer || typeof window === 'undefined') {\n      return;\n    }\n\n    scrollContainer.addEventListener('scroll', throttledUpdateScrollState, { passive: true });\n\n    // SSR safety: ResizeObserver may not exist in all environments\n    let resizeObserver: ResizeObserver | null = null;\n    if (typeof ResizeObserver !== 'undefined') {\n      resizeObserver = new ResizeObserver(throttledUpdateScrollState);\n      resizeObserver.observe(scrollContainer);\n    }\n\n    // Initial update - delay to ensure DOM is ready\n    const timeoutId = setTimeout(throttledUpdateScrollState, 0);\n\n    return () => {\n      clearTimeout(timeoutId);\n      scrollContainer.removeEventListener('scroll', throttledUpdateScrollState);\n      if (resizeObserver) {\n        resizeObserver.disconnect();\n      }\n    };\n  }, [throttledUpdateScrollState]);\n\n  const scroll = useCallback((direction: 'backward' | 'forward') => {\n    const scrollContainer = scrollContainerRef.current;\n    const container = containerRef.current;\n\n    if (!scrollContainer || !container || typeof window === 'undefined') {\n      return;\n    }\n\n    const availableWidth = container.clientWidth - SCROLL_BUTTON_WIDTH * 2;\n    const scrollDistance = direction === 'backward' ? -availableWidth : availableWidth;\n\n    // SSR safety: scrollBy may not exist in all environments\n    if (typeof scrollContainer.scrollBy === 'function') {\n      scrollContainer.scrollBy({ left: scrollDistance, behavior: 'smooth' });\n    } else {\n      // Fallback for older browsers or SSR\n      scrollContainer.scrollLeft += scrollDistance;\n    }\n  }, []);\n\n  const scrollBackward = useCallback(() => scroll('backward'), [scroll]);\n  const scrollForward = useCallback(() => scroll('forward'), [scroll]);\n\n  return (\n    <TabListContainer {...rest} ref={containerRef} data-show-scroll-buttons={showScrollButtons}>\n      {showScrollButtons && (\n        <ScrollButtonContainer $showEndBorder={canScrollLeft}>\n          <ScrollButton\n            variant=\"ghost\"\n            padding=\"small\"\n            size=\"small\"\n            ariaLabel=\"Scroll backward\"\n            disabled={!canScrollLeft}\n            onClick={scrollBackward}\n            tabIndex={-1}\n          >\n            <ChevronSmallLeftIcon />\n          </ScrollButton>\n        </ScrollButtonContainer>\n      )}\n      <ScrollContainer ref={scrollContainerRef}>\n        <StyledTabList ref={tabListRef} {...tabListProps}>\n          {[...(state as TabListState<object>).collection].map((item) => (\n            <TabButton key={item.key} item={item} state={state} />\n          ))}\n        </StyledTabList>\n      </ScrollContainer>\n      {showScrollButtons && (\n        <ScrollButtonContainer $showStartBorder={canScrollRight}>\n          <ScrollButton\n            variant=\"ghost\"\n            padding=\"small\"\n            size=\"small\"\n            ariaLabel=\"Scroll forward\"\n            disabled={!canScrollRight}\n            onClick={scrollForward}\n            tabIndex={-1}\n          >\n            <ChevronSmallRightIcon />\n          </ScrollButton>\n        </ScrollButtonContainer>\n      )}\n    </TabListContainer>\n  );\n};\n"
  },
  {
    "path": "code/core/src/components/components/Tabs/TabPanel.stories.tsx",
    "content": "import type { FC } from 'react';\nimport { useState } from 'react';\n\nimport type { TabListState } from '@react-stately/tabs';\nimport { expect, userEvent, within } from 'storybook/test';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { TabList } from './TabList.tsx';\nimport { TabPanel } from './TabPanel.tsx';\nimport { useTabsState } from './TabsView.tsx';\nimport type { TabProps } from './TabsView.tsx';\n\nconst TabContent: FC<{ tabNumber: number }> = ({ tabNumber }) => {\n  const [counter, setCounter] = useState(0);\n\n  return (\n    <div\n      data-testid={tabNumber}\n      style={{ backgroundColor: '#f0f0f0', color: '#111', padding: '20px' }}\n    >\n      <h3>Content for Tab {tabNumber}</h3>\n      <button onClick={() => setCounter(counter + 1)}>Clicked {counter} times</button>\n      <ul>\n        {Array.from({ length: 20 }, (_, index) => (\n          <li key={index}>Content line</li>\n        ))}\n      </ul>\n    </div>\n  );\n};\n\nconst DEFAULT_TABS: TabProps[] = [\n  { id: 'tab1', title: 'Tab 1', children: () => TabContent({ tabNumber: 1 }) },\n  { id: 'tab2', title: 'Tab 2', children: () => TabContent({ tabNumber: 2 }) },\n  { id: 'tab3', title: 'Tab 3', children: () => TabContent({ tabNumber: 3 }) },\n];\n\nconst meta = preview.meta({\n  title: 'Tabs/TabPanel',\n  component: TabPanel,\n  parameters: {\n    data: {\n      tabs: DEFAULT_TABS,\n    },\n  },\n  args: {\n    state: undefined,\n    id: undefined,\n  },\n  decorators: [\n    (Story) => {\n      return (\n        <div style={{ border: '1px solid grey', height: 400 }}>\n          <Story />\n        </div>\n      );\n    },\n    (Story, { args, parameters }) => {\n      const state = useTabsState({ tabs: parameters.data.tabs });\n      return (\n        <>\n          <TabList state={state} />\n          <Story args={{ ...args, id: (state as TabListState<object>).selectedItem?.key, state }} />\n        </>\n      );\n    },\n  ],\n});\n\nexport const Basic = meta.story({});\n\nexport const WithScrollbar = meta.story({\n  args: {\n    hasScrollbar: true,\n  },\n});\n\nexport const WithoutScrollbar = meta.story({\n  args: {\n    hasScrollbar: false,\n  },\n});\n\nexport const RenderOnlySelected = meta.story({\n  args: {\n    renderAllChildren: false,\n  },\n  play: ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n\n    const panel = canvas.getByRole('tabpanel');\n    const tab1 = canvas.getByTestId(1);\n    expect(panel).toBeInTheDocument();\n    expect(tab1?.parentNode?.parentNode?.parentNode?.parentNode).toBe(panel);\n    expect(canvas.getByText('Content for Tab 1')).toBeVisible();\n\n    expect(canvas.queryByTestId(2)).not.toBeInTheDocument();\n    expect(canvas.queryByTestId(3)).not.toBeInTheDocument();\n  },\n});\n\nexport const RenderAllChildren = meta.story({\n  args: {\n    renderAllChildren: true,\n  },\n  play: ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n\n    const panel = canvas.getByRole('tabpanel');\n    const tab1 = canvas.getByTestId(1);\n    const tab2 = canvas.getByTestId(2);\n    const tab3 = canvas.getByTestId(3);\n    expect(panel).toBeInTheDocument();\n    expect(tab1?.parentNode?.parentNode?.parentNode?.parentNode).toBe(panel);\n    expect(canvas.getByText('Content for Tab 1')).toBeVisible();\n\n    expect(tab2).toBeInTheDocument();\n    expect(tab2?.parentNode?.parentNode?.parentNode?.parentNode).toHaveAttribute('hidden');\n    expect(canvas.getByText('Content for Tab 2')).not.toBeVisible();\n\n    expect(tab3).toBeInTheDocument();\n    expect(tab3?.parentNode?.parentNode?.parentNode?.parentNode).toHaveAttribute('hidden');\n    expect(canvas.getByText('Content for Tab 3')).not.toBeVisible();\n  },\n});\n\nexport const PreserveState = meta.story({\n  args: {\n    renderAllChildren: true,\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const panel = canvas.getByRole('tabpanel');\n\n    await step('Setup', async () => {\n      expect(panel).toBeInTheDocument();\n      expect(canvas.getByText('Content for Tab 1')).toBeVisible();\n\n      const button = canvas.getByRole('button');\n      expect(button).toBeVisible();\n      expect(button).toHaveTextContent('Clicked 0 times');\n    });\n\n    await step('Click stateful button', async () => {\n      const button = canvas.getByRole('button');\n      await userEvent.click(button);\n      expect(button).toHaveTextContent('Clicked 1 time');\n    });\n\n    await step('Switch to Tab 2', async () => {\n      const tab2 = canvas.getByRole('tab', { name: 'Tab 2' });\n      await userEvent.click(tab2);\n\n      expect(canvas.getByText('Content for Tab 2')).toBeVisible();\n      expect(canvas.queryByText('Content for Tab 1')).not.toBeVisible();\n    });\n\n    await step('Switch back to Tab 1, notice preserved button state', async () => {\n      const tab1 = canvas.getByRole('tab', { name: 'Tab 1' });\n      await userEvent.click(tab1);\n\n      expect(canvas.getByText('Content for Tab 1')).toBeVisible();\n      expect(canvas.queryByText('Content for Tab 2')).not.toBeVisible();\n      expect(canvas.getByRole('button')).toHaveTextContent('Clicked 1 time');\n    });\n  },\n});\n"
  },
  {
    "path": "code/core/src/components/components/Tabs/TabPanel.tsx",
    "content": "import type { FC, HTMLAttributes } from 'react';\nimport React, { useRef } from 'react';\n\nimport { useTabPanel } from '@react-aria/tabs';\nimport type { TabListState } from '@react-stately/tabs';\nimport type { Node } from '@react-types/shared';\nimport { styled } from 'storybook/theming';\n\nimport { ScrollArea } from '../ScrollArea/ScrollArea.tsx';\nimport type { useTabsState } from './TabsView.tsx';\n\nexport interface TabPanelProps extends HTMLAttributes<HTMLDivElement> {\n  /** The state of the tab list. Primary mechanism for using the tabpanel. */\n  state: ReturnType<typeof useTabsState>;\n\n  /**\n   * Whether the panel adds a vertical scrollbar. Disable if you want to use fixed or sticky\n   * positioning on part of the tab's content. True by default.\n   */\n  hasScrollbar?: boolean;\n\n  /**\n   * Whether to render only the active tab's content, or all tabs. When true, non-selected tabs are\n   * rendered with the hidden attribute and do not affect the accessibility object model.\n   */\n  renderAllChildren?: boolean;\n}\n\nconst Panel = styled.div({\n  overflowY: 'hidden',\n  height: '100%',\n});\n\nexport const TabPanel: FC<TabPanelProps> = ({\n  hasScrollbar = true,\n  renderAllChildren = false,\n  state,\n}) => {\n  const ref = useRef(null);\n  const typedState = state as TabListState<object>;\n  const { tabPanelProps } = useTabPanel(typedState.selectedItem ?? {}, typedState, ref);\n\n  const childrenToRender = (\n    renderAllChildren ? [...typedState.collection] : [typedState.selectedItem]\n  ).filter((item): item is Node<object> => !!item);\n\n  return childrenToRender.map((item) => {\n    const isSelected = typedState.selectedKey === item.key;\n\n    return (\n      <Panel\n        key={item.key}\n        ref={isSelected ? ref : undefined}\n        {...(isSelected ? tabPanelProps : {})}\n        id={isSelected ? `${tabPanelProps.id}`.replace(/null$/, `${item.key}`) : undefined}\n        hidden={isSelected ? undefined : true}\n      >\n        {hasScrollbar ? (\n          <ScrollArea vertical>{item.props.children}</ScrollArea>\n        ) : (\n          item.props.children\n        )}\n      </Panel>\n    );\n  });\n};\n"
  },
  {
    "path": "code/core/src/components/components/Tabs/Tabs.helpers.tsx",
    "content": "import type { FC, PropsWithChildren, ReactChild, ReactElement, ReactNode } from 'react';\nimport React, { Children } from 'react';\n\nimport { deprecate } from 'storybook/internal/client-logger';\nimport type { Addon_RenderOptions } from 'storybook/internal/types';\n\nimport { styled } from 'storybook/theming';\n\nimport type { TabsProps } from './Tabs.tsx';\n\nexport interface VisuallyHiddenProps {\n  active?: boolean;\n}\n\nexport const VisuallyHidden = styled.div<VisuallyHiddenProps>(({ active }) =>\n  active ? { display: 'block' } : { display: 'none' }\n);\n\nexport const childrenToList = (children: TabsProps['children']) => {\n  deprecate('The `childrenToList` tabs helper is deprecated. Use `TabsView` instead.');\n  return Children.toArray(children).map(\n    // @ts-expect-error (non strict)\n    ({\n      props: { title, id, color, children: childrenOfChild },\n    }: ReactElement<{\n      children: FC<Addon_RenderOptions & PropsWithChildren> | ReactChild | null;\n      title: ReactChild | null | FC;\n      id: string;\n      color?: string;\n    }>) => {\n      const content: FC<Addon_RenderOptions & PropsWithChildren> | ReactNode = Array.isArray(\n        childrenOfChild\n      )\n        ? childrenOfChild[0]\n        : childrenOfChild;\n\n      const render: FC<Addon_RenderOptions & PropsWithChildren> = (\n        typeof content === 'function'\n          ? content\n          : ({ active }) => (\n              <VisuallyHidden active={active} role=\"tabpanel\">\n                {content}\n              </VisuallyHidden>\n            )\n      ) as FC<Addon_RenderOptions & PropsWithChildren>;\n      return {\n        title,\n        id,\n        ...(color ? { color } : {}),\n        render,\n      };\n    }\n  );\n};\n\nexport type ChildrenList = ReturnType<typeof childrenToList>;\nexport type ChildrenListComplete = Array<\n  ReturnType<typeof childrenToList>[0] & {\n    active: boolean;\n  }\n>;\n"
  },
  {
    "path": "code/core/src/components/components/Tabs/Tabs.hooks.tsx",
    "content": "import React, { useCallback, useLayoutEffect, useRef, useState } from 'react';\n\nimport { deprecate } from 'storybook/internal/client-logger';\nimport { sanitize } from 'storybook/internal/csf';\n\nimport { styled } from 'storybook/theming';\nimport useResizeObserver from 'use-resize-observer';\n\nimport { PopoverProvider } from '../Popover/PopoverProvider.tsx';\nimport { TooltipLinkList } from '../tooltip/TooltipLinkList.tsx';\nimport type { Link } from '../tooltip/TooltipLinkList.tsx';\nimport { TabButton } from './Button.tsx';\nimport type { ChildrenListComplete } from './Tabs.helpers.tsx';\n\nconst CollapseIcon = styled.span<{ isActive: boolean }>(({ theme, isActive }) => ({\n  display: 'inline-block',\n  width: 0,\n  height: 0,\n  marginLeft: 8,\n  color: isActive ? theme.color.secondary : theme.color.mediumdark,\n  borderRight: '3px solid transparent',\n  borderLeft: `3px solid transparent`,\n  borderTop: '3px solid',\n  transition: 'transform .1s ease-out',\n}));\n\nconst AddonButton = styled(TabButton)<{ preActive: boolean }>(({ active, theme, preActive }) => {\n  return `\n    color: ${preActive || active ? theme.barSelectedColor : theme.barTextColor};\n    .addon-collapsible-icon {\n      color: ${preActive || active ? theme.barSelectedColor : theme.barTextColor};\n    }\n    &:hover {\n      color: ${theme.barHoverColor};\n      .addon-collapsible-icon {\n        color: ${theme.barHoverColor};\n      }\n    }\n  `;\n});\n\nexport function useList(list: ChildrenListComplete) {\n  deprecate('The `useList` tabs hook is deprecated. Use `TabsView` instead.');\n\n  const tabBarRef = useRef<HTMLDivElement>();\n  const addonsRef = useRef<HTMLButtonElement>();\n  const tabRefs = useRef(new Map<string, HTMLButtonElement>());\n  const { width: tabBarWidth = 1 } = useResizeObserver<HTMLDivElement>({\n    // @ts-expect-error (non strict)\n    ref: tabBarRef,\n  });\n\n  const [visibleList, setVisibleList] = useState(list);\n  const [invisibleList, setInvisibleList] = useState<ChildrenListComplete>([]);\n  const previousList = useRef<ChildrenListComplete>(list);\n\n  const AddonTab = useCallback(\n    ({\n      menuName,\n      actions,\n    }: {\n      menuName: string;\n      actions?: {\n        onSelect: (id: string) => void;\n      } & Record<string, any>;\n    }) => {\n      const isAddonsActive = invisibleList.some(({ active }) => active);\n      const [isTooltipVisible, setTooltipVisible] = useState(false);\n      return (\n        <>\n          <PopoverProvider\n            ariaLabel=\"Additional tabs\"\n            visible={isTooltipVisible}\n            onVisibleChange={setTooltipVisible}\n            placement=\"bottom\"\n            popover={\n              <TooltipLinkList\n                links={invisibleList.map(({ title, id, color, active }) => {\n                  return {\n                    id,\n                    title,\n                    color,\n                    active,\n                    onClick: (e) => {\n                      e.preventDefault();\n                      // @ts-expect-error (non strict)\n                      actions.onSelect(id);\n                    },\n                  } as Link;\n                })}\n              />\n            }\n          >\n            <AddonButton\n              id=\"addons-menu-button\"\n              // @ts-expect-error (non strict)\n              ref={addonsRef}\n              active={isAddonsActive}\n              preActive={isTooltipVisible}\n              style={{ visibility: invisibleList.length ? 'visible' : 'hidden' }}\n              aria-hidden={!invisibleList.length}\n              className=\"tabbutton\"\n              type=\"button\"\n              role=\"tab\"\n            >\n              {menuName}\n              <CollapseIcon\n                className=\"addon-collapsible-icon\"\n                isActive={isAddonsActive || isTooltipVisible}\n              />\n            </AddonButton>\n          </PopoverProvider>\n          {invisibleList.map(({ title, id, color }, index) => {\n            const indexId = `index-${index}`;\n            return (\n              <TabButton\n                id={`tabbutton-${sanitize(id) ?? indexId}`}\n                style={{ visibility: 'hidden' }}\n                aria-hidden\n                tabIndex={-1}\n                ref={(ref: HTMLButtonElement) => {\n                  tabRefs.current.set(id, ref);\n                }}\n                className=\"tabbutton\"\n                type=\"button\"\n                key={id}\n                textColor={color}\n                role=\"tab\"\n              >\n                {/* @ts-expect-error (we know this is broken) */}\n                {title}\n              </TabButton>\n            );\n          })}\n        </>\n      );\n    },\n    [invisibleList]\n  );\n\n  const setTabLists = useCallback(() => {\n    // get x and width from tabBarRef div\n    if (!tabBarRef.current || !addonsRef.current) {\n      return;\n    }\n    const { x, width } = tabBarRef.current.getBoundingClientRect();\n    const { width: widthAddonsTab } = addonsRef.current.getBoundingClientRect();\n    const rightBorder = invisibleList.length ? x + width - widthAddonsTab : x + width;\n\n    const newVisibleList: ChildrenListComplete = [];\n\n    let widthSum = 0;\n\n    const newInvisibleList = list.filter((item) => {\n      const { id } = item;\n      const tabButton = tabRefs.current.get(id);\n      const { width: tabWidth = 0 } = tabButton?.getBoundingClientRect() || {};\n\n      const crossBorder = x + widthSum + tabWidth > rightBorder;\n\n      //  `!tabButton` happens when new tab has just been added\n      if (!crossBorder || !tabButton) {\n        newVisibleList.push(item);\n      }\n\n      widthSum += tabWidth;\n\n      return crossBorder;\n    });\n\n    if (newVisibleList.length !== visibleList.length || previousList.current !== list) {\n      setVisibleList(newVisibleList);\n      setInvisibleList(newInvisibleList);\n      previousList.current = list;\n    }\n  }, [invisibleList.length, list, visibleList]);\n\n  useLayoutEffect(setTabLists, [setTabLists, tabBarWidth]);\n\n  return {\n    tabRefs,\n    addonsRef,\n    tabBarRef,\n    visibleList,\n    invisibleList,\n    AddonTab,\n  };\n}\n"
  },
  {
    "path": "code/core/src/components/components/Tabs/Tabs.stories.tsx",
    "content": "import React from 'react';\n\nimport { Button } from 'storybook/internal/components';\n\nimport { BottomBarIcon, CloseIcon } from '@storybook/icons';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { action } from 'storybook/actions';\nimport { expect, spyOn } from 'storybook/test';\nimport { userEvent } from 'storybook/test';\n\nimport { TabWrapper, Tabs, TabsState } from './Tabs.tsx';\nimport type { ChildrenList } from './Tabs.helpers.tsx';\n\nconst colours = Array.from(new Array(15), (val, index) => index).map((i) =>\n  Math.floor((1 / 15) * i * 16777215)\n    .toString(16)\n    .padStart(6, '0')\n);\n\ninterface FibonacciMap {\n  [key: string]: number;\n}\n\nfunction Counter() {\n  const [count, setCount] = React.useState(0);\n  return <button onClick={() => setCount((prev) => prev + 1)}>{count}</button>;\n}\n\nfunction fibonacci(num: number, memo?: FibonacciMap): number {\n  if (!memo) {\n    memo = {};\n  }\n  if (memo[num]) {\n    return memo[num];\n  }\n  if (num <= 1) {\n    return 1;\n  }\n\n  memo[num] = fibonacci(num - 1, memo) + fibonacci(num - 2, memo);\n  return memo[num];\n}\n\n// Component that throws an error when rendered\nfunction ErrorComponent() {\n  throw new Error('This is a test error thrown by ErrorComponent');\n  // The code below will never execute\n  return <div>This component throws an error</div>;\n}\n\ntype Panels = Record<string, Omit<ChildrenList[0], 'id'>>;\n\nconst panels: Panels = {\n  test1: {\n    title: 'Tab title #1',\n    render: ({ active }) => (active ? <div id=\"test1\">CONTENT 1</div> : null),\n  },\n  test2: {\n    title: 'Tab title #2',\n    render: ({ active }) => (\n      <div\n        id=\"test2\"\n        style={{\n          background: 'hotpink',\n          minHeight: '100%',\n          display: active ? 'block' : 'none',\n        }}\n      >\n        CONTENT 2\n      </div>\n    ),\n  },\n  test3: {\n    title: 'Tab title #3',\n    render: ({ active }) =>\n      active ? (\n        <div id=\"test3\">\n          {colours.map((colour, i) => (\n            <div\n              key={colour}\n              style={{\n                background: `#${colour}`,\n                height: 30 + fibonacci(i + 5) / 10,\n              }}\n            />\n          ))}\n        </div>\n      ) : null,\n  },\n  test4: {\n    title: 'Tab title #4',\n    render: ({ active }) => (active ? <div id=\"test4\">CONTENT 4</div> : null),\n  },\n  test5: {\n    title: 'Tab title #5',\n    render: ({ active }) => (active ? <div id=\"test5\">CONTENT 5</div> : null),\n  },\n  test6: {\n    title: 'Tab title #6',\n    render: ({ active }) => <TabWrapper active={active} render={() => <div>CONTENT 6</div>} />,\n  },\n  errorTab: {\n    title: 'Error Tab',\n    render: ({ active }) => (active ? <ErrorComponent /> : null),\n  },\n};\n\nconst onSelect = action('onSelect');\n\nconst content = Object.entries(panels).map(([k, v]) => (\n  <div key={k} id={k} title={v.title as any}>\n    {/* @ts-expect-error (we know this is broken) */}\n    {v.render}\n  </div>\n));\n\nexport default {\n  args: {\n    menuName: 'Addons',\n  },\n} satisfies Meta<typeof TabsState>;\n\ntype Story = StoryObj<typeof TabsState>;\n\nexport const StatefulStatic = {\n  render: (args) => (\n    <TabsState {...args} initial={args.initial ?? 'test2'}>\n      <div id=\"test1\" title=\"With a function\">\n        {\n          (({ active, selected }: { active: boolean; selected: string }) =>\n            active ? <div>{selected} is selected</div> : null) as any\n        }\n      </div>\n      <div id=\"test2\" title=\"With markup\">\n        <div>test2 is always active (but visually hidden)</div>\n      </div>\n    </TabsState>\n  ),\n} satisfies Story;\n\nexport const StatefulStaticWithSetButtonTextColors = {\n  render: (args) => (\n    <div>\n      <TabsState {...args} initial={args.initial ?? 'test2'}>\n        <div id=\"test1\" title=\"With a function\" color=\"#e00000\">\n          {\n            (({ active, selected }: { active: boolean; selected: string }) =>\n              active ? <div>{selected} is selected</div> : null) as any\n          }\n        </div>\n        <div id=\"test2\" title=\"With markup\" color=\"green\">\n          <div>test2 is always active (but visually hidden)</div>\n        </div>\n      </TabsState>\n    </div>\n  ),\n} satisfies Story;\n\nexport const StatefulStaticWithSetBackgroundColor = {\n  render: (args) => (\n    <div>\n      <TabsState\n        {...args}\n        initial={args.initial || 'test2'}\n        backgroundColor={args.backgroundColor ?? 'rgba(0,0,0,.05)'}\n      >\n        <div id=\"test1\" title=\"With a function\" color=\"#e00000\">\n          {\n            (({ active, selected }: { active: boolean; selected: string }) =>\n              active ? <div>{selected} is selected</div> : null) as any\n          }\n        </div>\n        <div id=\"test2\" title=\"With markup\" color=\"green\">\n          <div>test2 is always active (but visually hidden)</div>\n        </div>\n      </TabsState>\n    </div>\n  ),\n} satisfies Story;\n\nconst customViewports = {\n  sized: {\n    name: 'Sized',\n    styles: {\n      width: '380px',\n      height: '500px',\n    },\n  },\n};\n\nexport const StatefulNoInitial = {\n  render: (args) => <TabsState {...args}>{content}</TabsState>,\n} satisfies Story;\n\nexport const StatelessBordered = {\n  render: (args) => (\n    <Tabs\n      {...args}\n      bordered={args.bordered ?? true}\n      absolute={args.absolute ?? false}\n      selected=\"test3\"\n      menuName={args.menuName ?? 'Addons'}\n      actions={{\n        onSelect,\n      }}\n    >\n      {content}\n    </Tabs>\n  ),\n} satisfies Story;\n\nconst AddonTools = () => (\n  <div\n    style={{\n      display: 'flex',\n      alignItems: 'center',\n      gap: 6,\n    }}\n  >\n    <Button padding=\"small\" variant=\"ghost\" ariaLabel=\"Tool 1\">\n      <BottomBarIcon />\n    </Button>\n    <Button padding=\"small\" variant=\"ghost\" ariaLabel=\"Tool 2\">\n      <CloseIcon />\n    </Button>\n  </div>\n);\n\nexport const StatelessWithTools = {\n  args: {\n    tools: <AddonTools />,\n  },\n  render: (args) => (\n    <Tabs\n      bordered\n      selected=\"test3\"\n      menuName=\"Addons\"\n      actions={{\n        onSelect,\n      }}\n      {...args}\n    >\n      {content}\n    </Tabs>\n  ),\n} satisfies StoryObj<typeof Tabs>;\n\nexport const StatelessAbsolute = {\n  parameters: {\n    layout: 'fullscreen',\n  },\n  render: (args) => (\n    <Tabs\n      absolute\n      selected=\"test3\"\n      menuName=\"Addons\"\n      actions={{\n        onSelect,\n      }}\n      {...args}\n    >\n      {content}\n    </Tabs>\n  ),\n} satisfies StoryObj<typeof Tabs>;\n\nexport const StatelessAbsoluteBordered = {\n  parameters: {\n    layout: 'fullscreen',\n  },\n  render: (args) => (\n    <Tabs\n      absolute\n      bordered\n      menuName=\"Addons\"\n      selected=\"test3\"\n      actions={{\n        onSelect,\n      }}\n      {...args}\n    >\n      {content}\n    </Tabs>\n  ),\n} satisfies StoryObj<typeof Tabs>;\n\nexport const StatelessEmptyWithTools = {\n  args: {\n    ...StatelessWithTools.args,\n    showToolsWhenEmpty: true,\n  },\n  parameters: {\n    layout: 'fullscreen',\n  },\n  render: (args) => (\n    <Tabs\n      actions={{\n        onSelect,\n      }}\n      bordered\n      menuName=\"Addons\"\n      absolute\n      {...args}\n    />\n  ),\n} satisfies StoryObj<typeof Tabs>;\n\nexport const StatelessWithCustomEmpty = {\n  args: {\n    ...StatelessEmptyWithTools.args,\n    emptyState: <div>I am custom!</div>,\n  },\n  parameters: {\n    layout: 'fullscreen',\n  },\n  render: (args) => (\n    <Tabs\n      actions={{\n        onSelect,\n      }}\n      bordered\n      menuName=\"Addons\"\n      absolute\n      {...args}\n    />\n  ),\n} satisfies StoryObj<typeof Tabs>;\n\nexport const StatefulWithStatefulPanel = {\n  render: (args) => {\n    const [update, setUpdate] = React.useState(0);\n    return (\n      <div>\n        <button onClick={() => setUpdate((prev) => prev + 1)}>Update</button>\n        <TabsState {...args} initial={args.initial ?? 'test-1'}>\n          <div id=\"test-1\" title=\"Test 1\">\n            <Counter key={update} />\n          </div>\n          <div id=\"test-2\" title=\"Test 2\">\n            <Counter key={update} />\n          </div>\n        </TabsState>\n      </div>\n    );\n  },\n} satisfies Story;\n\n// Story that demonstrates the error boundary functionality\nexport const WithErrorBoundary = {\n  parameters: {\n    test: {\n      dangerouslyIgnoreUnhandledErrors: true,\n    },\n  },\n  play: async ({ mount, args, canvas }) => {\n    spyOn(console, 'error').mockImplementation(() => {});\n    await mount(\n      <TabsState {...args} initial=\"test1\">\n        <div id=\"test1\" title=\"Normal Tab\">\n          {\n            (({ active }: { active: boolean }) =>\n              active ? <div>This tab renders normally</div> : null) as any\n          }\n        </div>\n        <div id=\"errorTab\" title=\"Error Tab\">\n          {(({ active }: { active: boolean }) => (active ? <ErrorComponent /> : null)) as any}\n        </div>\n      </TabsState>\n    );\n    // Check that the normal tab renders correctly\n    await expect(canvas.getByText('This tab renders normally')).toBeInTheDocument();\n\n    // Find and click the error tab to trigger the error\n    const errorTab = canvas.getByRole('tab', { name: 'Error Tab' });\n    await userEvent.click(errorTab);\n\n    // Check that the error boundary message is displayed\n    await expect(await canvas.findByText('This addon has errors')).toBeInTheDocument();\n  },\n} satisfies Story;\n"
  },
  {
    "path": "code/core/src/components/components/Tabs/Tabs.tsx",
    "content": "/* eslint-disable react/destructuring-assignment */\nimport type { FC, PropsWithChildren, ReactElement, ReactNode, SyntheticEvent } from 'react';\nimport React, { Component, forwardRef, memo, useMemo } from 'react';\n\nimport { deprecate } from 'storybook/internal/client-logger';\nimport { sanitize } from 'storybook/internal/csf';\nimport type { Addon_RenderOptions } from 'storybook/internal/types';\n\nimport { styled } from 'storybook/theming';\n\nimport { FlexBar } from '../Bar/Bar.tsx';\nimport { TabButton } from './Button.tsx';\nimport { EmptyTabContent } from './EmptyTabContent.tsx';\nimport { VisuallyHidden, childrenToList } from './Tabs.helpers.tsx';\nimport { useList } from './Tabs.hooks.tsx';\n\nconst ignoreSsrWarning =\n  '/* emotion-disable-server-rendering-unsafe-selector-warning-please-do-not-use-this-the-warning-exists-for-a-reason */';\n\nexport interface WrapperProps {\n  bordered?: boolean;\n  absolute?: boolean;\n}\n\nconst Wrapper = styled.div<WrapperProps>(\n  ({ theme, bordered }) =>\n    bordered\n      ? {\n          backgroundClip: 'padding-box',\n          border: `1px solid ${theme.appBorderColor}`,\n          borderRadius: theme.appBorderRadius,\n          overflow: 'hidden',\n          boxSizing: 'border-box',\n        }\n      : {},\n  ({ absolute }) =>\n    absolute\n      ? {\n          width: '100%',\n          height: '100%',\n          boxSizing: 'border-box',\n          display: 'flex',\n          flexDirection: 'column',\n        }\n      : {\n          display: 'block',\n        }\n);\n\nconst StyledTabBar = styled.div({\n  overflow: 'hidden',\n\n  '&:first-of-type': {\n    marginLeft: -3,\n  },\n\n  whiteSpace: 'nowrap',\n  flexGrow: 1,\n});\n\nexport const TabBar = forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n  (props, ref) => {\n    deprecate('The `TabBar` component is deprecated. Use `TabsView` instead.');\n    return <StyledTabBar data-deprecated=\"TabBar\" {...props} ref={ref} />;\n  }\n);\nTabBar.displayName = 'TabBar';\n\nexport interface ContentProps {\n  absolute?: boolean;\n  bordered?: boolean;\n}\n\nconst Content = styled.div<ContentProps>(\n  {\n    display: 'block',\n    position: 'relative',\n    container: 'tab-content / inline-size',\n  },\n  ({ theme }) => ({\n    fontSize: theme.typography.size.s2 - 1,\n    background: theme.background.content,\n  }),\n  ({ bordered, theme }) =>\n    bordered\n      ? {\n          borderRadius: `0 0 ${theme.appBorderRadius - 1}px ${theme.appBorderRadius - 1}px`,\n        }\n      : {},\n  ({ absolute, bordered }) =>\n    absolute\n      ? {\n          height: `calc(100% - ${bordered ? 42 : 40}px)`,\n\n          position: 'absolute',\n          left: 0 + (bordered ? 1 : 0),\n          right: 0 + (bordered ? 1 : 0),\n          bottom: 0 + (bordered ? 1 : 0),\n          top: 40 + (bordered ? 1 : 0),\n          overflow: 'auto',\n          [`& > *:first-child${ignoreSsrWarning}`]: {\n            position: 'absolute',\n            left: 0 + (bordered ? 1 : 0),\n            right: 0 + (bordered ? 1 : 0),\n            bottom: 0 + (bordered ? 1 : 0),\n            top: 0 + (bordered ? 1 : 0),\n            height: `calc(100% - ${bordered ? 2 : 0}px)`,\n            overflow: 'auto',\n          },\n        }\n      : {}\n);\n\nexport interface TabWrapperProps {\n  active: boolean;\n  render?: () => ReactElement;\n  children?: ReactNode;\n}\n\nexport const TabWrapper = forwardRef<HTMLDivElement, TabWrapperProps>(\n  ({ active, render, children }, ref) => {\n    deprecate('The `TabWrapper` component is deprecated. Use `TabsView` instead.');\n    return (\n      <VisuallyHidden data-deprecated=\"TabWrapper\" ref={ref} active={active}>\n        {render ? render() : children}\n      </VisuallyHidden>\n    );\n  }\n);\nTabWrapper.displayName = 'TabWrapper';\n\nexport const panelProps = {};\n\nexport interface TabsProps {\n  children?: ReactElement<{\n    children: FC<Addon_RenderOptions & PropsWithChildren>;\n    title: ReactNode | FC<PropsWithChildren>;\n  }>[];\n  id?: string;\n  tools?: ReactNode;\n  showToolsWhenEmpty?: boolean;\n  emptyState?: ReactNode;\n  selected?: string;\n  actions?: {\n    onSelect: (id: string) => void;\n  } & Record<string, any>;\n  backgroundColor?: string;\n  absolute?: boolean;\n  bordered?: boolean;\n  menuName?: string;\n}\n\ninterface ErrorBoundaryProps {\n  children: ReactNode;\n  active: boolean;\n}\n\nclass TabErrorBoundary extends Component<ErrorBoundaryProps, { hasError: boolean }> {\n  constructor(props: ErrorBoundaryProps) {\n    super(props);\n    this.state = { hasError: false };\n  }\n\n  static getDerivedStateFromError() {\n    return { hasError: true };\n  }\n\n  componentDidCatch(error: Error, info: React.ErrorInfo) {\n    console.error('Error rendering addon panel');\n    console.error(error);\n    console.error(info.componentStack);\n  }\n\n  render() {\n    if (this.state.hasError && this.props.active) {\n      return (\n        <EmptyTabContent\n          title=\"This addon has errors\"\n          description=\"Check your browser logs and addon code to pinpoint what went wrong. This issue was not caused by Storybook.\"\n        />\n      );\n    }\n\n    return this.props.children;\n  }\n}\n\nexport const Tabs: FC<TabsProps> = memo(\n  ({\n    children,\n    selected = null,\n    actions,\n    absolute = false,\n    bordered = false,\n    tools = null,\n    backgroundColor,\n    id: htmlId = null,\n    menuName = 'Tabs',\n    emptyState,\n    showToolsWhenEmpty,\n  }) => {\n    deprecate('The `Tabs` component is deprecated. Use `TabsView` instead.');\n\n    const list = useMemo(\n      () =>\n        childrenToList(children).map((i, index) => ({\n          ...i,\n          active: selected ? i.id === selected : index === 0,\n        })),\n      [children, selected]\n    );\n\n    const { visibleList, tabBarRef, tabRefs, AddonTab } = useList(list);\n\n    const EmptyContent = emptyState ?? <EmptyTabContent title=\"Nothing found\" />;\n\n    if (!showToolsWhenEmpty && list.length === 0) {\n      return EmptyContent;\n    }\n\n    return (\n      // @ts-expect-error (non strict)\n      <Wrapper data-deprecated=\"Tabs\" absolute={absolute} bordered={bordered} id={htmlId}>\n        <FlexBar scrollable={false} border backgroundColor={backgroundColor}>\n          {/* @ts-expect-error (non strict) */}\n          <TabBar style={{ whiteSpace: 'normal' }} ref={tabBarRef} role=\"tablist\">\n            {visibleList.map(({ title, id, active, color }, index) => {\n              const indexId = `index-${index}`;\n\n              return (\n                <TabButton\n                  id={`tabbutton-${sanitize(id) ?? indexId}`}\n                  ref={(ref: HTMLButtonElement) => {\n                    tabRefs.current.set(id, ref);\n                  }}\n                  className={`tabbutton ${active ? 'tabbutton-active' : ''}`}\n                  type=\"button\"\n                  key={id}\n                  active={active}\n                  textColor={color}\n                  onClick={(e: SyntheticEvent) => {\n                    e.preventDefault();\n                    // @ts-expect-error (non strict)\n                    actions.onSelect(id);\n                  }}\n                  role=\"tab\"\n                  aria-selected={active}\n                >\n                  {typeof title === 'function' ? <title /> : title}\n                </TabButton>\n              );\n            })}\n            <AddonTab menuName={menuName} actions={actions} />\n          </TabBar>\n          {tools}\n        </FlexBar>\n        <Content id=\"panel-tab-content\" bordered={bordered} absolute={absolute}>\n          {list.length\n            ? list.map(({ id, active, render }) => {\n                return (\n                  <TabErrorBoundary key={id} active={active}>\n                    {React.createElement(render, { active }, null)}\n                  </TabErrorBoundary>\n                );\n              })\n            : EmptyContent}\n        </Content>\n      </Wrapper>\n    );\n  }\n);\nTabs.displayName = 'Tabs';\n\nexport interface TabsStateProps {\n  children: TabsProps['children'];\n  initial: string;\n  absolute: boolean;\n  bordered: boolean;\n  backgroundColor: string;\n  menuName: string;\n}\n\nexport interface TabsStateState {\n  selected: string;\n}\n\nexport class TabsState extends Component<TabsStateProps, TabsStateState> {\n  static defaultProps: TabsStateProps = {\n    children: [],\n    // @ts-expect-error (non strict)\n    initial: null,\n    absolute: false,\n    bordered: false,\n    backgroundColor: '',\n    // @ts-expect-error (non strict)\n    menuName: undefined,\n  };\n\n  constructor(props: TabsStateProps) {\n    super(props);\n    deprecate('The `TabsState` class is deprecated. Use `TabsView` instead.');\n\n    this.state = {\n      selected: props.initial,\n    };\n  }\n\n  handlers = {\n    onSelect: (id: string) => this.setState({ selected: id }),\n  };\n\n  render() {\n    const { bordered = false, absolute = false, children, backgroundColor, menuName } = this.props;\n    const { selected } = this.state;\n    return (\n      <Tabs\n        bordered={bordered}\n        absolute={absolute}\n        selected={selected}\n        backgroundColor={backgroundColor}\n        menuName={menuName}\n        actions={this.handlers}\n      >\n        {children}\n      </Tabs>\n    );\n  }\n}\n"
  },
  {
    "path": "code/core/src/components/components/Tabs/TabsView.stories.tsx",
    "content": "import { useState } from 'react';\n\nimport { Button, EmptyTabContent } from 'storybook/internal/components';\n\nimport { CrossIcon, ExpandIcon } from '@storybook/icons';\n\nimport { fn } from 'storybook/test';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { TabsView } from './TabsView.tsx';\n\nconst DEFAULT_TABS = [\n  { id: 'tab1', title: 'Tab 1', children: () => <div>Content for Tab 1</div> },\n  { id: 'tab2', title: 'Tab 2', children: () => <div>Content for Tab 2</div> },\n  { id: 'tab3', title: 'Tab 3', children: () => <div>Content for Tab 3</div> },\n];\n\nconst DEFAULT_TOOLS = (\n  <div>\n    <Button variant=\"ghost\" padding=\"small\" ariaLabel=\"Go full screen\">\n      <ExpandIcon />\n    </Button>\n    <Button variant=\"ghost\" padding=\"small\" ariaLabel=\"Close\">\n      <CrossIcon />\n    </Button>\n  </div>\n);\n\nconst meta = preview.meta({\n  title: 'Tabs/TabsView',\n  component: TabsView,\n  args: { backgroundColor: '#2e2e2e', tabs: DEFAULT_TABS, tools: DEFAULT_TOOLS },\n  globals: { sb_theme: 'dark' },\n});\n\nexport const Basic = meta.story({});\n\nexport const Empty = meta.story({\n  args: {\n    tabs: [],\n  },\n});\n\nexport const EmptyCustom = meta.story({\n  args: {\n    tabs: [],\n    emptyState: (\n      <EmptyTabContent\n        title=\"Custom empty state\"\n        description={<>This component does not currently have tabs.</>}\n      />\n    ),\n  },\n});\n\nexport const EmptyWithToolsShowFalse = meta.story({\n  args: {\n    tabs: [],\n    showToolsWhenEmpty: false,\n  },\n});\n\nexport const EmptyWithToolsShowTrue = meta.story({\n  args: {\n    tabs: [],\n    showToolsWhenEmpty: true,\n  },\n});\n\nexport const EmptyToolsShowCustom = meta.story({\n  args: {\n    emptyState: (\n      <EmptyTabContent\n        title=\"Custom empty state\"\n        description={<>This component does not currently have tabs.</>}\n      />\n    ),\n    showToolsWhenEmpty: true,\n    tabs: [],\n  },\n});\n\nexport const DefaultSelected = meta.story({\n  args: {\n    defaultSelected: 'tab2',\n  },\n});\n\nexport const ControlledState = meta.story({\n  args: {\n    selected: 'tab2',\n    onSelectionChange: fn(),\n  },\n  render: (args) => {\n    const [selected, setSelected] = useState(args.selected);\n    return (\n      <>\n        <p>\n          Current tab: <strong>{selected}</strong>\n        </p>\n        <TabsView\n          {...args}\n          selected={selected}\n          onSelectionChange={(key) => {\n            setSelected(key);\n            args.onSelectionChange?.(key);\n          }}\n        />\n      </>\n    );\n  },\n});\n"
  },
  {
    "path": "code/core/src/components/components/Tabs/TabsView.tsx",
    "content": "import type { ComponentProps, FC, HTMLAttributes, ReactElement, ReactNode } from 'react';\nimport React from 'react';\n\nimport { Item } from '@react-stately/collections';\nimport type { TabListState } from '@react-stately/tabs';\nimport { useTabListState } from '@react-stately/tabs';\nimport type { Key } from '@react-types/shared';\nimport { styled } from 'storybook/theming';\n\nimport { Bar } from '../Bar/Bar.tsx';\nimport { EmptyTabContent } from './EmptyTabContent.tsx';\nimport { TabList } from './TabList.tsx';\nimport { TabPanel } from './TabPanel.tsx';\n\nexport interface TabProps {\n  id: string;\n  'aria-label'?: string;\n  title: FC | ReactNode | string;\n  children?: FC | ReactNode;\n  isDisabled?: boolean;\n}\n\nexport interface useTabsStateProps {\n  defaultSelected?: string;\n  selected?: string;\n  onSelectionChange?: (key: string) => void;\n  tabs: TabProps[];\n}\n\nexport const useTabsState = ({\n  defaultSelected,\n  onSelectionChange,\n  selected,\n  tabs,\n}: useTabsStateProps): unknown => {\n  return useTabListState({\n    children: tabs.map(({ children: Children, id, 'aria-label': ariaLabel, title: Title }) => (\n      <Item key={id} aria-label={ariaLabel} title={typeof Title === 'function' ? <Title /> : Title}>\n        {typeof Children === 'function' ? <Children /> : Children}\n      </Item>\n    )),\n    disabledKeys: tabs.filter(({ isDisabled }) => isDisabled).map(({ id }) => id),\n    defaultSelectedKey: defaultSelected,\n    onSelectionChange: (key) => onSelectionChange?.(`${key}`),\n    selectedKey: selected,\n  });\n};\n\nexport const Container = styled.div({\n  display: 'flex',\n  flexDirection: 'column',\n  height: '100%',\n});\n\nexport const FlexTabPanel = styled(TabPanel)(() => ({\n  flex: 1,\n}));\n\nconst FlexTabList = styled(TabList)<{ $simulatedGap: Key }>(({ $simulatedGap }) => ({\n  flex: '1 1 0%',\n  '&[data-show-scroll-buttons=\"true\"]': { marginInlineEnd: $simulatedGap },\n}));\n\nexport interface TabsViewProps extends HTMLAttributes<HTMLDivElement> {\n  /** List of tabs and their associated panel. */\n  tabs: TabProps[];\n\n  /** ID of the tab that should be selected on first render. */\n  defaultSelected?: string;\n\n  /** ID of the current tab if in controlled rendering mode. */\n  selected?: string;\n\n  /** Called when the selected tab changes, use if you want to control the component state. */\n  onSelectionChange?: (key: string) => void;\n\n  /**\n   * Optional tools to avoid rendering two toolbars in a layout.\n   *\n   * @warning Only use this if the tools act upon the entire layout,\n   * not upon a single tab panel. If you want to edit which tools are\n   * visible based on the current tab, then you musn't use `tools` and\n   * should handle your own toolbar inside the tabpanel instead.\n   */\n  tools?: ReactElement;\n\n  /** Background color for the bar containing the tabs and tools. */\n  backgroundColor?: string;\n\n  /** Style properties for the inner layout container in the bar containing the tabs and tools. */\n  barInnerStyle?: React.CSSProperties;\n\n  /** Show tools instead of the empty state if there are no tabs. */\n  showToolsWhenEmpty?: boolean;\n\n  /** Custom UI for the empty state shown when there are no tabs. */\n  emptyState?: ReactNode;\n\n  /** Optional ID. */\n  id?: string;\n\n  /** Props to pass to the TabPanel component. */\n  panelProps?: Omit<ComponentProps<typeof TabPanel>, 'state'>;\n}\n\nexport const TabsView: FC<TabsViewProps> = ({\n  backgroundColor,\n  barInnerStyle,\n  defaultSelected,\n  emptyState,\n  onSelectionChange,\n  panelProps = {},\n  selected,\n  showToolsWhenEmpty,\n  tabs,\n  tools,\n  ...props\n}) => {\n  const state = useTabsState({\n    defaultSelected,\n    onSelectionChange,\n    selected,\n    tabs,\n  }) as TabListState<object>;\n\n  const EmptyContent = emptyState ?? <EmptyTabContent title=\"Nothing found\" />;\n  const hasContent = tabs.length > 0;\n\n  if (!showToolsWhenEmpty && !hasContent) {\n    return EmptyContent;\n  }\n\n  return (\n    <Container {...props}>\n      <Bar\n        scrollable={false}\n        border\n        backgroundColor={backgroundColor}\n        innerStyle={{\n          display: 'flex',\n          justifyContent: 'space-between',\n          paddingInlineStart: 0,\n          paddingInlineEnd: 10,\n          // A11y: the tools must be before the tab list in the DOM for correct tab order.\n          // This lets us control order without adding a wrapper div, leading to better flex\n          // behavior on tools for our callees (e.g. containerType: 'inline-size' in a11y-addon).\n          '> *:not(:last-child)': {\n            order: 2,\n          },\n          '> *': {\n            flexShrink: 0,\n          },\n          ...barInnerStyle,\n          gap: 0,\n        }}\n      >\n        {tools}\n        {hasContent ? (\n          <FlexTabList state={state} $simulatedGap={barInnerStyle?.gap ?? 6} />\n        ) : (\n          <div />\n        )}\n      </Bar>\n      {hasContent ? <FlexTabPanel state={state} {...panelProps} /> : EmptyContent}\n    </Container>\n  );\n};\n"
  },
  {
    "path": "code/core/src/components/components/ToggleButton/ToggleButton.stories.tsx",
    "content": "import React, { useState } from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { styled } from 'storybook/theming';\n\nimport { ToggleButton } from './ToggleButton.tsx';\n\nconst meta = {\n  title: 'ToggleButton',\n  component: ToggleButton,\n  tags: ['autodocs'],\n  args: { ariaLabel: false, children: 'Click me' },\n} satisfies Meta<typeof ToggleButton>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nconst Stack = styled.div({ display: 'flex', flexDirection: 'column', gap: '1rem' });\n\nconst Row = styled.div({ display: 'flex', alignItems: 'center', gap: '1rem' });\n\nexport const Base: Story = {\n  args: { pressed: false },\n  render: ({ pressed, ...args }) => {\n    const [isPressed, setIsPressed] = useState(pressed);\n    const handleOnClick = () => setIsPressed((prev) => !prev);\n\n    return <ToggleButton {...args} pressed={isPressed} onClick={handleOnClick} />;\n  },\n};\n\nexport const Pressed: Story = {\n  args: { pressed: true },\n  render: ({ pressed, ...args }) => {\n    const [isPressed, setIsPressed] = useState(pressed);\n    const handleOnClick = () => setIsPressed((prev) => !prev);\n\n    return <ToggleButton {...args} pressed={isPressed} onClick={handleOnClick} />;\n  },\n};\n\nexport const Variants: Story = {\n  args: { pressed: false },\n  render: (args) => {\n    return (\n      <Stack>\n        <Row>Unpressed</Row>\n        <Row>\n          <ToggleButton {...args} pressed={false} variant=\"solid\" />\n          <ToggleButton {...args} pressed={false} variant=\"outline\" />\n          <ToggleButton {...args} pressed={false} variant=\"ghost\" />\n        </Row>\n        <Row>Pressed</Row>\n        <Row>\n          <ToggleButton {...args} pressed={true} variant=\"solid\" />\n          <ToggleButton {...args} pressed={true} variant=\"outline\" />\n          <ToggleButton {...args} pressed={true} variant=\"ghost\" />\n        </Row>\n      </Stack>\n    );\n  },\n};\n\nexport const Sizes: Story = {\n  args: { pressed: false, variant: 'solid' },\n  render: ({ ...args }) => (\n    <Row>\n      <ToggleButton {...args} size=\"medium\" />\n      <ToggleButton {...args} size=\"small\" />\n    </Row>\n  ),\n};\n\nexport const Disabled: Story = {\n  args: { disabled: true, pressed: false },\n  render: (args) => {\n    return (\n      <Stack>\n        <Row>Unpressed</Row>\n        <Row>\n          <ToggleButton {...args} pressed={false} variant=\"solid\" />\n          <ToggleButton {...args} pressed={false} variant=\"outline\" />\n          <ToggleButton {...args} pressed={false} variant=\"ghost\" />\n        </Row>\n        <Row>Pressed</Row>\n        <Row>\n          <ToggleButton {...args} pressed={true} variant=\"solid\" />\n          <ToggleButton {...args} pressed={true} variant=\"outline\" />\n          <ToggleButton {...args} pressed={true} variant=\"ghost\" />\n        </Row>\n      </Stack>\n    );\n  },\n};\n"
  },
  {
    "path": "code/core/src/components/components/ToggleButton/ToggleButton.tsx",
    "content": "import React, { forwardRef } from 'react';\n\nimport { darken, transparentize } from 'polished';\nimport { styled } from 'storybook/theming';\n\nimport { Button, type ButtonProps } from '../Button/Button.tsx';\n\nexport interface ToggleButtonProps extends ButtonProps {\n  /** Whether the ToggleButton is currently pressed or not. */\n  pressed: boolean;\n}\n\n// In case of reports on screenreader announcements, please check\n// https://adrianroselli.com/2021/10/switch-role-support.html.\n\nexport const ToggleButton = forwardRef<HTMLButtonElement, ToggleButtonProps>(\n  ({ pressed, ...props }, ref) => {\n    return (\n      <StyledToggle role=\"switch\" aria-checked={pressed} ref={ref} pressed={pressed} {...props} />\n    );\n  }\n);\n\nToggleButton.displayName = 'ToggleButton';\n\nconst StyledToggle = styled(Button)<ToggleButtonProps>(\n  ({ theme, variant = 'outline', pressed }) => ({\n    ...(pressed\n      ? {\n          ...(variant === 'solid'\n            ? {\n                background:\n                  theme.base === 'lighten'\n                    ? darken(0.1, theme.color.secondary)\n                    : darken(0.2, theme.color.secondary),\n              }\n            : {}),\n          ...(variant === 'outline'\n            ? {\n                background: transparentize(0.94, theme.barSelectedColor),\n                boxShadow: `${theme.barSelectedColor} 0 0 0 1px inset`,\n                color: theme.barSelectedColor,\n              }\n            : {}),\n          ...(variant === 'ghost'\n            ? {\n                background: transparentize(0.93, theme.barSelectedColor),\n                color:\n                  theme.base === 'light'\n                    ? darken(0.1, theme.color.secondary)\n                    : theme.color.secondary,\n              }\n            : {}),\n        }\n      : {}),\n  })\n);\n"
  },
  {
    "path": "code/core/src/components/components/Toolbar/AbstractToolbar.stories.tsx",
    "content": "import { Button } from 'storybook/internal/components';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { AbstractToolbar } from './Toolbar.tsx';\n\nconst Children = () => (\n  <>\n    <Button ariaLabel={false} key=\"button1\">\n      Button 1\n    </Button>\n    <Button ariaLabel={false} key=\"button2\">\n      Button 2\n    </Button>\n    <Button ariaLabel={false} key=\"button3\">\n      Button 3\n    </Button>\n    <Button ariaLabel={false} key=\"button4\">\n      Button 4\n    </Button>\n    <Button ariaLabel={false} key=\"button5\">\n      Button 5\n    </Button>\n    <Button ariaLabel={false} key=\"button6\">\n      Button 6\n    </Button>\n    <Button ariaLabel={false} key=\"button7\">\n      Button 7\n    </Button>\n    <Button ariaLabel={false} key=\"button8\">\n      Button 8\n    </Button>\n  </>\n);\n\nconst meta = preview.meta({\n  title: 'AbstractToolbar',\n  component: AbstractToolbar,\n  args: {\n    children: <Children />,\n  },\n});\n\nexport const Basic = meta.story({});\n"
  },
  {
    "path": "code/core/src/components/components/Toolbar/Toolbar.stories.tsx",
    "content": "import React from 'react';\n\nimport { Button } from 'storybook/internal/components';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { Toolbar } from './Toolbar.tsx';\n\nconst Children = () => (\n  <>\n    <Button ariaLabel={false} key=\"button1\">\n      Button 1\n    </Button>\n    <Button ariaLabel={false} key=\"button2\">\n      Button 2\n    </Button>\n    <Button ariaLabel={false} key=\"button3\">\n      Button 3\n    </Button>\n    <Button ariaLabel={false} key=\"button4\">\n      Button 4\n    </Button>\n    <Button ariaLabel={false} key=\"button5\">\n      Button 5\n    </Button>\n    <Button ariaLabel={false} key=\"button6\">\n      Button 6\n    </Button>\n    <Button ariaLabel={false} key=\"button7\">\n      Button 7\n    </Button>\n    <Button ariaLabel={false} key=\"button8\">\n      Button 8\n    </Button>\n  </>\n);\n\nconst meta = preview.meta({\n  title: 'Toolbar',\n  component: Toolbar,\n  args: {\n    children: <Children />,\n  },\n});\n\nexport const Basic = meta.story({});\n\nexport const Scrollable = meta.story({\n  args: {\n    scrollable: true,\n  },\n  render: (args) => <div style={{ width: 400 }}>{<Toolbar {...args} />}</div>,\n});\n\nexport const NotScrollable = meta.story({\n  args: {\n    scrollable: false,\n  },\n  render: (args) => <div style={{ width: 400 }}>{<Toolbar {...args} />}</div>,\n});\n\nexport const Border = meta.story({\n  args: {\n    border: true,\n  },\n});\n"
  },
  {
    "path": "code/core/src/components/components/Toolbar/Toolbar.tsx",
    "content": "import type { FC } from 'react';\nimport React, { useRef } from 'react';\n\nimport { useToolbar } from '@react-aria/toolbar';\n\nimport { Bar, type BarProps } from '../Bar/Bar.tsx';\n\nexport interface AbstractToolbarProps {\n  className?: string;\n  children?: React.ReactNode;\n  'aria-label'?: string;\n  'aria-labelledby'?: string;\n}\n\nexport const AbstractToolbar: FC<AbstractToolbarProps> = ({\n  'aria-label': ariaLabel,\n  'aria-labelledby': ariaLabelledby,\n  ...rest\n}) => {\n  const ref = useRef<HTMLDivElement>(null);\n\n  const { toolbarProps } = useToolbar(\n    {\n      'aria-label': ariaLabel,\n      'aria-labelledby': ariaLabelledby,\n      orientation: 'horizontal',\n    },\n    ref\n  );\n\n  return <div ref={ref} {...toolbarProps} {...rest} />;\n};\n\nexport interface ToolbarProps extends AbstractToolbarProps, BarProps {}\n\nexport const Toolbar: FC<ToolbarProps> = ({\n  'aria-label': ariaLabel,\n  'aria-labelledby': ariaLabelledby,\n  ...rest\n}) => {\n  const ref = useRef<HTMLDivElement>(null);\n\n  const { toolbarProps } = useToolbar(\n    {\n      'aria-label': ariaLabel,\n      'aria-labelledby': ariaLabelledby,\n      orientation: 'horizontal',\n    },\n    ref\n  );\n\n  return <Bar ref={ref} {...toolbarProps} {...rest} />;\n};\n"
  },
  {
    "path": "code/core/src/components/components/Zoom/Zoom.stories.tsx",
    "content": "import type { CSSProperties } from 'react';\nimport React, { useEffect, useState } from 'react';\n\nimport { Zoom } from './Zoom.tsx';\n\nexport default {\n  component: Zoom,\n  argTypes: {\n    scale: {\n      control: { type: 'range', min: 0.2, max: 30, step: 0.02 },\n    },\n  },\n  parameters: {\n    chromatic: { delay: 500, diffThreshold: 0.2 },\n  },\n};\nconst EXAMPLE_ELEMENT = (\n  <div\n    style={{\n      width: 2000,\n      height: 2000,\n      border: '10px solid orangered',\n      background: `url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAM4klEQVR4Xu2d224ktxGGayTN6LTrOO//PMmlAfvOgIEkFwEcZ71a7ep8muBjd2k4re4eVpHsaS1CeKH1is1u1s86slhcrP/261r62oGInB6LLBbNb8+PRQ75x/+3bArcPYh8vu4dZjEMyELk7Hjz0JwBYdGEddMuHmnXWPixDv/NqrkAOVw0HKJtDoAcHTZcerAQOTgQ4Rv5+ysQHbKvWyReAGUt8vIi8vQi8vzS/H1fQD08iny6MnLIG0BOGgJM2SD68lAEIPhZuj09i9w/ijw+lx55fDze+8dXKyDokJP9cAjEP142QEzR4B645v5J5PGp/hsfnkQ+fTMCcrQQOZlYZAEAolENifqkefsGRNnNgwiruFZDZP153YjRThtW6suFyPFEgKAHzhGJM7LiAOb6vuGc0s0FyOpAZLXafMqHk1aBFv46RNPJcr9cMTiltcjtY6NnSrb7h4ZDetowh6wORVbLuoBgVq+OSk61zliIr6u7cmPf3olc3OYCctyYmqUaIqqG5VTq+7rjILoApUfum195+yByYeWQ4yORZbR6P56UEyuIv6ksKDO1Rh6AU9AruaDc3Yt8vjFyCHI9JlopQBj3JNJNJQk2xVgoZKywnOZS6hDtqBVR+IMfTgcd4uRvQ0Qhqt57Q+TkKHoA+Xor8vDWtB5W6oRN1DPHL0DM5DjqjPEDoOYMMhMkEVkQ1Cu6Apc9igBsZ4w0QIKfkOmwna4a7/t7aTmWF4DcPYkQY+uAMgLIauOo4bABiLdhncEd31v7etMQ1doUEJ57Xovgl7TjLNZ/Zz8EMcLAiw0L4SOESKo0yv0sQxF/b9yhAHi5hHgZDqc2wHh+DuGaxfrnf62bMHS7b6Ay7fRI5PCwCVPz83TZYBb+tOHsGMCxVfLDWR0v37oya/T3cEkXkOi7GkD6Wrz/sTwQOYusoz4AlXVBOuw9wHjtvgUGQQCxBbMGYfY1psfigrMGTOd+QJBUHyOZj7ka7x5aJo//gg7aArEdIGwcsVHUAsg/62ZSzI2W903dl2+/7HfyBj+FTbKb+95f9wNyzH5EpDOIa8W7h6mThkN+PEvtvekXxGar1/grYpOx4p0/5Uj9vQJI38CdMr6baP+q4Se+3dqiwiZAmPj5ajtuRRjF413jWMacVpII8Vh3jyJs+oStWdVvrb7DlyJIyl6Xghj6RPow97uu72y7jlhWPNPTtjkEqyq2rvQBL4cApFfUpRIJ1menb1fD0iNso0112qsxwy8iPQe4arwELhzRgXjt6JLUlgQIYPDRfZtEXg7pEiH1g1P7QYjUuJKGfzQclPqOGMBYjMYJFIB3cbUxXLb0YI/NNArIr/9eBz8jpNIMhDVYWR4v+8PxdsTYSoRd/QlfWHb0mCdGRo2GYo+dxC09GIlISKwLCYMmFqOLhSzW//hjt6vJSvdsJDH5WmF2vvqSfWkDdb1GRsorLIuDLJdBKysJEHb2jBkgajrX2ieHMyCCtdVaJFhaWE8pDQNkQOekcQiK2bq7ByDEr0ruMsaTxbn65thWRfzC8aWbBZBsDmEPw6oMAyAVQyZeDkH05gRKh4BkcaSmDu0NkL+c1dv/wAG8dIgsOJ1QTunGfntqBmS2yGICHl2AyPI8l0osiyLVMWsBwl47hE5pewME0eCxzlImRR+4JOzcpT4gzffUEFnvApBak4/pj7VC6CS11YgesCAQWbPWIRAIcTXFTqFldWJskN6E6NKjDZZ9fg1matyMnwBh2TkkueF2KNqb4ofA4h4Hj3AMltYUeQ0WUPq4KRwziQ7+6P/TN96UsxB+iGuzrSyvUueDait2nTREIyTB6SSLTkkVdSX74UAORntTOCQHkKlC8EowzS4ssZJLghCPpWmpPeOneersaWjCg/UjNR/L+7z1fUHEtOk1KWF5z/i5z+QDwlGEjETr2mH4MVmNCEuNMeUSOvX5bEBKZBzitU/JJTFxMIvnpFuyAEHklEi0rmH/p67I4ESSkNYevtm30s8ChFVdItEaomAcWKPGFqKn9IUY7DKGdKWUByr0UcPDpdQDIIXOhkzpl+yiI75AibMeu97T9/sss7ckIHxcreCehzBYY+gXrDFvJrvnvVmOIeGF0uFq9udzcoU9RBh7BjFW68Rt33uzAMGxq3HIhlxhT65XaTB0PPRJCItzZK3WS9pxs8LvOWmku+ZVazt113t3cQsJCDV9lyxAanGIEgVzOJSByqFihWdTE/A8r84CpCaH6GQAvZRp7SHQ0DMQDmBKi7AsHeJNI7USBuMBRe8J81vfZelfI1iZBYg3jdQyae2L2JrjaSu8fNJ8SkWQs/yQKQEBGEBRU9uyk+dZAJZnNNxRApSs0Ik3r9cy2b6+gKEprHNR+KzsK2NSRXFP3ZvXmwvIlsIvFLop8U160DNH0WdxiCeNtMTE4zHgliA6Z1LGKdckzgJk3xwSAzMnS8yTpKdzyQJkDhyyxS0ofdJBMytL5HIxpqu3hlZW+N2TaJ072ZTng9JfNucH96X0valHWRzizclKIWqJPmoi72N72HskIguQnBSgEgRPGUOVfo1zH7veb8l617GyHMP3AIhONMTdOke6dxE09/ceXZIFiFeHIELIoSVw+Jqi2aZrdokQl90go51TqvrTupOnSRk1j0HE34/nTr0Ti1+SFcvy6JCSm0+hUk6b0MxEUk7dAgqcUvMoRAyKVWxlAeIRWbUOVmolt9R4Uu1j2QoKYXosrtQ2OSC1Eqy10ItFPJAGaz0fmUrY2NGznAjO0iEeDqmVpQggX4yVd6Y4owLHWioCZQHiSbSeEyCs4tq5xXDsl/7CyL3MluWHoA8sidZ4zbVO33o4BIpMcSSiW1pjTOxlcYg10TpkJ1YsB8tKtOgQCBMWyXndEIulcIA7lqUVdCxhidqAeKOstZW7xfTVLeEeLho/sONJtK6dv+sN6NVO9DYB8jJYFmQcEK3Xa9nbhqt+PLcajun9LTWy4lFrmeL6jskA8eT11rKymLwnwlrT0FBALDrELbL0Tqj09dv0rO0hW/UIuWU18pNjuhDPIgaX0txmrzdrsXZ2OxNiRabMv3bdLgUAhzU1EOo2e72A1CylpwQgHkSm+tiqBAyCo/HFNCkr2NrH6qm7OcSbaE1pVio4TNEABkUfqoi2Pke4kJI/lEvPOD2c+v1WQ8MNiJdDahcvSyXUVP2sOm3UMfzt940kDuYtVaHZVKKUkbOiNYTY96nbqcBIFVdxIkZ8vvG1fnATUlisf9Fi/O1VFaGA/kKEmz45IuAthFzbQbQQPC7Zqs+peFMfKy6aTB99pk9RhyXcVtDm2gntExN9zOBQpR4fo2uZYfh2BN55ciTy14+2/YR48iFcQU3gDvW0uo7WdG/nt+mls4nuMwm3O7dE0OeZRJdg+m9D1ahfpUD7UWOETwGdIjLWRauA9JzUWqx/+mc7+3bJMHFFn5wnCvNzSXH3pmgmEk8+vuGg4b62Xlak3LfYM2W2M+8Trp24t9e3xzIkaTu+c7ctZT585VHQA8tNoS9vWbz3emfhzrXQXgymAdid/aMOamUBCPrkkcsEmhvb0gChp/cuXHQJossSD7NMbl999bibxzVQQIh/8SfKERgHJL5ckhdbZaUS671fJtkFHbGukQJPeElTh7hTvVNadhyQ+LaE3Kvz3stFxCkcF1/ggvNpLYIAIJ8uRS7fFs5MByT36rxwOSWXVRpryKcQaLI+XMRyv72qPUf+sJ9+vxC54jz89m2fO0RWdP1q7tV5anl93GPdrCzg1o1V1C2W7Dny97QW+c/FtpXVfpsBkAwdEhMCqyScOXkH96jH3z1UlxdxZZ0LoP73a2MydypGTKPU+1ZmUPRcQbSvwx2J7KKFaYJ/1tM8qbbc7PnpqrfgTboOIZQS32WYOJ/RbsFQcNaVL/H+XWNQFpBI7lgYxJomxTsZ989cQAhne67O2zVpfk9SNMpxLgo/3MS5uZ92dAqelCcFpOOD7HYMY7N3dSByknFBcQow4VAnltgEexjd7yGsE8r/3dsqNowBwniUEiQEFTc21j5fN5knnVjcuMiKr9DrXjaZQmBvnxBtPmzCNnphmXessec0WEnEFq7wNBI6+hpcgPJG3MH9hKE0WvEKyNtt6B2ARKeRpgSkO8Fw+KcFJxTRdBgC8UqEUPyJL6H0gKEbcfGzKP9QZLNjBMQe/c2dyMWNg0PiS+0JxXdZzzOJEs+8Fs5v92505cXxMo0+h7C9vrS9vq7ENzCGxul0vHBP+ogRoM41HAIgZh0SA8KpKKu9XWricx1HM1r4Pjz4LfAHPlq3LEgbClVRt/ul65A51rKaA1Ca95x6qotvRmR96b8/axiQ4FFT9KWdNQq+9kmkORB4im9wAaJ346pcDg6cQ5lOMcH39g7VIT3f/T+lOOGi/Z/IjAAAAABJRU5ErkJggg==')`,\n    }}\n  />\n);\n\nconst TemplateElement = (args: any) => <Zoom.Element {...args} />;\n\nexport const ElementActualSize = TemplateElement.bind({});\n\n// @ts-expect-error (to be converted to CSF3)\nElementActualSize.args = {\n  scale: 1,\n  children: EXAMPLE_ELEMENT,\n};\n\nexport const ElementZoomedIn = TemplateElement.bind({});\n\n// @ts-expect-error (to be converted to CSF3)\nElementZoomedIn.args = {\n  scale: 0.7,\n  children: EXAMPLE_ELEMENT,\n};\n\nexport const ElementZoomedOut = TemplateElement.bind({});\n\n// @ts-expect-error (to be converted to CSF3)\nElementZoomedOut.args = {\n  scale: 3,\n  children: EXAMPLE_ELEMENT,\n};\n\nconst style: CSSProperties = {\n  width: '500px',\n  height: '500px',\n  border: '2px solid hotpink',\n  position: 'relative',\n};\n\nconst TemplateIFrame = (args: any) => {\n  const iFrameRef = React.useRef<HTMLIFrameElement>(null);\n  const [scale, setScale] = useState(1);\n  const [loaded, hasLoaded] = useState(false);\n\n  useEffect(() => {\n    if (loaded) {\n      setScale(args.scale);\n    }\n  }, [args.scale, loaded]);\n  return (\n    <Zoom.IFrame iFrameRef={iFrameRef} scale={scale} active={args.active}>\n      <iframe\n        id=\"iframe\"\n        title=\"UI Panel\"\n        onLoad={() => hasLoaded(true)}\n        src=\"/iframe.html\"\n        style={style}\n        ref={iFrameRef}\n        allow=\"fullscreen\"\n      />\n    </Zoom.IFrame>\n  );\n};\nexport const IFrameActualSize = TemplateIFrame.bind({});\n\n// @ts-expect-error (to be converted to CSF3)\nIFrameActualSize.args = {\n  scale: 1,\n  active: true,\n};\n\n// The iFrame stories are disabled because useGlobals works in practice\n// but, for some reason breaks in the stories for Zoom.iFrame\n// @ts-expect-error (to be converted to CSF3)\nIFrameActualSize.parameters = {\n  chromatic: { disableSnapshot: true },\n};\n\nexport const IFrameZoomedIn = TemplateIFrame.bind({});\n\n// @ts-expect-error (to be converted to CSF3)\nIFrameZoomedIn.args = {\n  scale: 0.7,\n  active: true,\n};\n\n// @ts-expect-error (to be converted to CSF3)\nIFrameZoomedIn.parameters = {\n  chromatic: { disableSnapshot: true },\n};\n\nexport const IFrameZoomedOut = TemplateIFrame.bind({});\n\n// @ts-expect-error (to be converted to CSF3)\nIFrameZoomedOut.args = {\n  scale: 3,\n  active: true,\n};\n\n// @ts-expect-error (to be converted to CSF3)\nIFrameZoomedOut.parameters = {\n  chromatic: { disableSnapshot: true },\n};\n"
  },
  {
    "path": "code/core/src/components/components/Zoom/Zoom.tsx",
    "content": "import { ZoomElement } from './ZoomElement.tsx';\nimport { ZoomIFrame } from './ZoomIFrame.tsx';\n\nexport const Zoom = {\n  Element: ZoomElement,\n  IFrame: ZoomIFrame,\n};\n"
  },
  {
    "path": "code/core/src/components/components/Zoom/ZoomElement.tsx",
    "content": "import type { ReactElement } from 'react';\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { styled } from 'storybook/theming';\nimport type { ResizeHandler } from 'use-resize-observer';\nimport useResizeObserver from 'use-resize-observer';\n\nconst ZoomElementWrapper = styled.div<{ centered?: boolean; scale: number; elementHeight: number }>(\n  ({ centered = false, scale = 1, elementHeight }) => ({\n    height: elementHeight || 'auto',\n    transformOrigin: centered ? 'center top' : 'left top',\n    transform: `scale(${1 / scale})`,\n  })\n);\n\ntype ZoomProps = {\n  centered?: boolean;\n  scale: number;\n  children: ReactElement | ReactElement[];\n};\n\nexport function ZoomElement({ centered, scale, children }: ZoomProps) {\n  const componentWrapperRef = useRef<HTMLDivElement>(null);\n  const [elementHeight, setElementHeight] = useState(0);\n\n  const onResize = useCallback<ResizeHandler>(\n    ({ height }) => {\n      if (height) {\n        setElementHeight(height / scale);\n      }\n    },\n    [scale]\n  );\n\n  useEffect(() => {\n    if (componentWrapperRef.current) {\n      setElementHeight(componentWrapperRef.current.getBoundingClientRect().height);\n    }\n  }, [scale]);\n\n  useResizeObserver({\n    ref: componentWrapperRef,\n    onResize,\n  });\n\n  return (\n    <ZoomElementWrapper centered={centered} scale={scale} elementHeight={elementHeight}>\n      <div ref={componentWrapperRef} className=\"innerZoomElementWrapper\">\n        {children}\n      </div>\n    </ZoomElementWrapper>\n  );\n}\n"
  },
  {
    "path": "code/core/src/components/components/Zoom/ZoomIFrame.tsx",
    "content": "import type { ReactElement, RefObject } from 'react';\nimport React, { Component } from 'react';\n\nexport type IZoomIFrameProps = {\n  scale: number;\n  children: ReactElement<HTMLIFrameElement>;\n  iFrameRef: RefObject<HTMLIFrameElement>;\n  active?: boolean;\n};\n\nexport class ZoomIFrame extends Component<IZoomIFrameProps> {\n  // @ts-expect-error (non strict)\n  iframe: HTMLIFrameElement = null;\n\n  componentDidMount() {\n    const { iFrameRef } = this.props;\n    // @ts-expect-error (non strict)\n    this.iframe = iFrameRef.current;\n  }\n\n  shouldComponentUpdate(nextProps: IZoomIFrameProps) {\n    const { scale, active } = this.props;\n\n    if (scale !== nextProps.scale) {\n      this.setIframeInnerZoom(nextProps.scale);\n    }\n\n    if (active !== nextProps.active) {\n      this.iframe.setAttribute('data-is-storybook', nextProps.active ? 'true' : 'false');\n    }\n\n    // this component renders an iframe, which gets updates via post-messages\n    // never update this component, it will cause the iframe to refresh\n    // the only exception is when the url changes, which happens when the version changes\n    return nextProps.children.props.src !== this.props.children.props.src;\n  }\n\n  setIframeInnerZoom(scale: number) {\n    try {\n      // @ts-expect-error (non strict)\n      Object.assign(this.iframe.contentDocument.body.style, {\n        width: `${(1 / scale) * 100}%`,\n        height: `${(1 / scale) * 100}%`,\n        transform: `scale(${scale})`,\n        transformOrigin: 'top left',\n      });\n    } catch (e) {\n      this.setIframeZoom(scale);\n    }\n  }\n\n  setIframeZoom(scale: number) {\n    Object.assign(this.iframe.style, {\n      width: `${(1 / scale) * 100}%`,\n      height: `${(1 / scale) * 100}%`,\n      transform: `scale(${scale})`,\n      transformOrigin: 'top left',\n    });\n  }\n\n  render() {\n    const { children } = this.props;\n    return <>{children}</>;\n  }\n}\n"
  },
  {
    "path": "code/core/src/components/components/addon-panel/addon-panel.tsx",
    "content": "import type { ReactElement } from 'react';\nimport React, { useEffect, useRef } from 'react';\n\nimport { styled } from 'storybook/theming';\n\nimport { ScrollArea } from '../ScrollArea/ScrollArea.tsx';\n\nconst usePrevious = (value: any) => {\n  const ref = useRef();\n\n  useEffect(() => {\n    // happens after return\n    ref.current = value;\n  }, [value]);\n\n  return ref.current;\n};\n\nconst useUpdate = (update: boolean, value: any) => {\n  const previousValue = usePrevious(value);\n\n  return update ? value : previousValue;\n};\n\nexport interface AddonPanelProps {\n  active: boolean;\n  children: ReactElement;\n  /** Whether the panel has a vertical scrollbar, `true` by default. */\n  hasScrollbar?: boolean;\n  /** Whether the panel has an horizontal scrollbar, `false` by default */\n  hasHorizontalScrollbar?: boolean;\n}\n\nconst Div = styled.div(({ theme }) => ({\n  fontSize: theme.typography.size.s2 - 1,\n  height: '100%',\n}));\n\nexport const AddonPanel = ({\n  active,\n  children,\n  hasScrollbar = true,\n  hasHorizontalScrollbar = false,\n}: AddonPanelProps) => {\n  return (\n    // the hidden attribute is an valid html element that's both accessible and works to visually hide content\n    <Div hidden={!active}>\n      {hasScrollbar || hasHorizontalScrollbar ? (\n        <ScrollArea vertical={hasScrollbar} horizontal={hasHorizontalScrollbar}>\n          {useUpdate(active, children)}\n        </ScrollArea>\n      ) : (\n        useUpdate(active, children)\n      )}\n    </Div>\n  );\n};\n"
  },
  {
    "path": "code/core/src/components/components/clipboard/ClipboardCode.tsx",
    "content": "import React from 'react';\n\nimport { color, styled, typography } from 'storybook/theming';\n\nconst Code = styled.pre`\n  line-height: 18px;\n  padding: 11px 1rem;\n  white-space: pre-wrap;\n  background: rgba(0, 0, 0, 0.05);\n  color: ${color.darkest};\n  border-radius: 3px;\n  margin: 1rem 0;\n  width: 100%;\n  display: block;\n  overflow: hidden;\n  font-family: ${typography.fonts.mono};\n  font-size: ${typography.size.s2 - 1}px;\n`;\n\ninterface ClipboardCodeProps {\n  code: string;\n}\n\nexport const ClipboardCode = ({ code, ...props }: ClipboardCodeProps) => (\n  <Code id=\"clipboard-code\" {...props}>\n    {code}\n  </Code>\n);\n"
  },
  {
    "path": "code/core/src/components/components/icon/icon.stories.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React from 'react';\n\nimport { css, styled } from 'storybook/theming';\n\nimport type { IconType } from './icon.tsx';\nimport { Icons, icons } from './icon.tsx';\n\nconst Meta = styled.div`\n  color: #666;\n  font-size: 12px;\n`;\n\nconst Item = styled.li<{ minimal?: boolean }>`\n  display: inline-flex;\n  flex-direction: row;\n  align-items: center;\n  flex: 0 1 16%;\n  min-width: 120px;\n  margin: 16px;\n\n  svg {\n    margin-right: 6px;\n    width: 14px;\n    height: 14px;\n  }\n\n  ${(props) =>\n    props.minimal &&\n    css`\n      flex: none;\n      min-width: auto;\n      padding: 0;\n      margin: 16px;\n\n      svg {\n        display: block;\n        margin-right: 0;\n        width: 14px;\n        height: 14px;\n      }\n    `};\n`;\n\nconst List = styled.ul`\n  display: flex;\n  flex-flow: row wrap;\n  list-style: none;\n  padding: 0;\n  margin: 0;\n`;\n\nconst Header = styled.h2`\n  font-size: 16px;\n  margin: 16px;\n`;\n\nexport default {\n  title: 'Icons (deprecated)',\n  component: Icons,\n  argTypes: {\n    color: { control: 'color' },\n  },\n};\n\nexport const Basic = (args: ComponentProps<typeof Icons>) => <Icons {...args} />;\nBasic.args = { icon: 'watch' };\n\nexport const Labels = (args: ComponentProps<typeof Icons>) => (\n  <>\n    <Header>{Object.keys(icons).length} icons</Header>\n    <List>\n      {Object.keys(icons).map((key) => (\n        <Item key={key}>\n          {/* @ts-expect-error (not strict) */}\n          <Icons icon={key as IconType} aria-hidden {...args} />\n          <Meta>{key}</Meta>\n        </Item>\n      ))}\n    </List>\n  </>\n);\n\nexport const NoLabels = (args: ComponentProps<typeof Icons>) => (\n  <>\n    <Header>{Object.keys(icons).length} icons</Header>\n    <List>\n      {Object.keys(icons).map((key) => (\n        <Item minimal key={key}>\n          {/* @ts-expect-error (not strict) */}\n          <Icons icon={key as IconType} aria-label={key} {...args} />\n        </Item>\n      ))}\n    </List>\n  </>\n);\n\nexport const NoDeprecateWarning = (args: ComponentProps<typeof Icons>) => (\n  <>\n    <Header>{Object.keys(icons).length} icons</Header>\n    <List>\n      {Object.keys(icons).map((key) => (\n        <Item minimal key={key}>\n          {/* @ts-expect-error (not strict) */}\n          <Icons icon={key as IconType} aria-label={key} __suppressDeprecationWarning {...args} />\n        </Item>\n      ))}\n    </List>\n  </>\n);\n"
  },
  {
    "path": "code/core/src/components/components/icon/icon.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React, { memo } from 'react';\n\nimport { deprecate, logger } from 'storybook/internal/client-logger';\n\nimport * as StorybookIcons from '@storybook/icons';\n\nimport { styled } from 'storybook/theming';\n\nexport type IconType = keyof typeof icons;\ntype NewIconTypes = (typeof icons)[IconType];\n\nconst NEW_ICON_MAP = StorybookIcons as Record<NewIconTypes, (props: unknown) => React.ReactNode>;\n\nconst Svg = styled.svg`\n  display: inline-block;\n  shape-rendering: inherit;\n  vertical-align: middle;\n  fill: currentColor;\n  path {\n    fill: currentColor;\n  }\n`;\n\nexport interface IconsProps extends ComponentProps<typeof Svg> {\n  icon: IconType;\n  useSymbol?: boolean;\n  onClick?: () => void;\n  __suppressDeprecationWarning?: boolean;\n}\n\n// TODO: Remove in SB11\n/**\n * @deprecated No longer used, will be removed in Storybook 9.0 Please use the `@storybook/icons`\n *   package instead.\n */\nexport const Icons = ({\n  icon,\n  useSymbol,\n  __suppressDeprecationWarning = false,\n  ...props\n}: IconsProps) => {\n  if (!__suppressDeprecationWarning) {\n    deprecate(\n      `Use of the deprecated Icons ${\n        `(${icon})` || ''\n      } component detected. Please use the @storybook/icons component directly. For more informations, see the migration notes at https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#icons-is-deprecated`\n    );\n  }\n\n  const findIcon: NewIconTypes = icons[icon] || null;\n  if (!findIcon) {\n    logger.warn(\n      `Use of an unknown prop ${\n        `(${icon})` || ''\n      } in the Icons component. The Icons component is deprecated. Please use the @storybook/icons component directly. For more informations, see the migration notes at https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#icons-is-deprecated`\n    );\n    return null;\n  }\n\n  const Icon = NEW_ICON_MAP[findIcon];\n\n  return <Icon {...props} />;\n};\n\nexport interface SymbolsProps {\n  icons?: IconType[];\n}\n\n// TODO: Remove in SB11\n/**\n * @deprecated No longer used, will be removed in Storybook 9.0 Please use the `@storybook/icons`\n *   package instead.\n */\nexport const Symbols = memo<SymbolsProps>(function Symbols({ icons: keys = Object.keys(icons) }) {\n  return (\n    <Svg\n      viewBox=\"0 0 14 14\"\n      style={{ position: 'absolute', width: 0, height: 0 }}\n      data-chromatic=\"ignore\"\n    >\n      {/* @ts-expect-error (non strict) */}\n      {keys.map((key: IconType) => (\n        <symbol id={`icon--${key}`} key={key}>\n          {icons[key]}\n        </symbol>\n      ))}\n    </Svg>\n  );\n});\n\nexport const icons = {\n  user: 'UserIcon',\n  useralt: 'UserAltIcon',\n  useradd: 'UserAddIcon',\n  users: 'UsersIcon',\n  profile: 'ProfileIcon',\n  facehappy: 'FaceHappyIcon',\n  faceneutral: 'FaceNeutralIcon',\n  facesad: 'FaceSadIcon',\n  accessibility: 'AccessibilityIcon',\n  accessibilityalt: 'AccessibilityAltIcon',\n  arrowup: 'ChevronUpIcon',\n  arrowdown: 'ChevronDownIcon',\n  arrowleft: 'ChevronLeftIcon',\n  arrowright: 'ChevronRightIcon',\n  arrowupalt: 'ArrowUpIcon',\n  arrowdownalt: 'ArrowDownIcon',\n  arrowleftalt: 'ArrowLeftIcon',\n  arrowrightalt: 'ArrowRightIcon',\n  expandalt: 'ExpandAltIcon',\n  collapse: 'CollapseIcon',\n  expand: 'ExpandIcon',\n  unfold: 'UnfoldIcon',\n  transfer: 'TransferIcon',\n  redirect: 'RedirectIcon',\n  undo: 'UndoIcon',\n  reply: 'ReplyIcon',\n  sync: 'SyncIcon',\n  upload: 'UploadIcon',\n  download: 'DownloadIcon',\n  back: 'BackIcon',\n  proceed: 'ProceedIcon',\n  refresh: 'RefreshIcon',\n  globe: 'GlobeIcon',\n  compass: 'CompassIcon',\n  location: 'LocationIcon',\n  pin: 'PinIcon',\n  time: 'TimeIcon',\n  dashboard: 'DashboardIcon',\n  timer: 'TimerIcon',\n  home: 'HomeIcon',\n  admin: 'AdminIcon',\n  info: 'InfoIcon',\n  question: 'QuestionIcon',\n  support: 'SupportIcon',\n  alert: 'AlertIcon',\n  email: 'EmailIcon',\n  phone: 'PhoneIcon',\n  link: 'LinkIcon',\n  unlink: 'LinkBrokenIcon',\n  bell: 'BellIcon',\n  rss: 'RSSIcon',\n  sharealt: 'ShareAltIcon',\n  share: 'ShareIcon',\n  circle: 'CircleIcon',\n  circlehollow: 'CircleHollowIcon',\n  bookmarkhollow: 'BookmarkHollowIcon',\n  bookmark: 'BookmarkIcon',\n  hearthollow: 'HeartHollowIcon',\n  heart: 'HeartIcon',\n  starhollow: 'StarHollowIcon',\n  star: 'StarIcon',\n  certificate: 'CertificateIcon',\n  verified: 'VerifiedIcon',\n  thumbsup: 'ThumbsUpIcon',\n  shield: 'ShieldIcon',\n  basket: 'BasketIcon',\n  beaker: 'BeakerIcon',\n  hourglass: 'HourglassIcon',\n  flag: 'FlagIcon',\n  cloudhollow: 'CloudHollowIcon',\n  edit: 'EditIcon',\n  cog: 'CogIcon',\n  nut: 'NutIcon',\n  wrench: 'WrenchIcon',\n  ellipsis: 'EllipsisIcon',\n  check: 'CheckIcon',\n  form: 'FormIcon',\n  batchdeny: 'BatchDenyIcon',\n  batchaccept: 'BatchAcceptIcon',\n  controls: 'ControlsIcon',\n  plus: 'PlusIcon',\n  closeAlt: 'CloseAltIcon',\n  cross: 'CrossIcon',\n  trash: 'TrashIcon',\n  pinalt: 'PinAltIcon',\n  unpin: 'UnpinIcon',\n  add: 'AddIcon',\n  subtract: 'SubtractIcon',\n  close: 'CloseIcon',\n  delete: 'DeleteIcon',\n  passed: 'PassedIcon',\n  changed: 'ChangedIcon',\n  failed: 'FailedIcon',\n  clear: 'ClearIcon',\n  comment: 'CommentIcon',\n  commentadd: 'CommentAddIcon',\n  requestchange: 'RequestChangeIcon',\n  comments: 'CommentsIcon',\n  lock: 'LockIcon',\n  unlock: 'UnlockIcon',\n  key: 'KeyIcon',\n  outbox: 'OutboxIcon',\n  credit: 'CreditIcon',\n  button: 'ButtonIcon',\n  type: 'TypeIcon',\n  pointerdefault: 'PointerDefaultIcon',\n  pointerhand: 'PointerHandIcon',\n  browser: 'BrowserIcon',\n  tablet: 'TabletIcon',\n  mobile: 'MobileIcon',\n  watch: 'WatchIcon',\n  sidebar: 'SidebarIcon',\n  sidebaralt: 'SidebarAltIcon',\n  sidebaralttoggle: 'SidebarAltToggleIcon',\n  sidebartoggle: 'SidebarToggleIcon',\n  bottombar: 'BottomBarIcon',\n  bottombartoggle: 'BottomBarToggleIcon',\n  cpu: 'CPUIcon',\n  database: 'DatabaseIcon',\n  memory: 'MemoryIcon',\n  structure: 'StructureIcon',\n  box: 'BoxIcon',\n  power: 'PowerIcon',\n  photo: 'PhotoIcon',\n  component: 'ComponentIcon',\n  grid: 'GridIcon',\n  outline: 'OutlineIcon',\n  photodrag: 'PhotoDragIcon',\n  search: 'SearchIcon',\n  zoom: 'ZoomIcon',\n  zoomout: 'ZoomOutIcon',\n  zoomreset: 'ZoomResetIcon',\n  eye: 'EyeIcon',\n  eyeclose: 'EyeCloseIcon',\n  lightning: 'LightningIcon',\n  lightningoff: 'LightningOffIcon',\n  contrast: 'ContrastIcon',\n  switchalt: 'SwitchAltIcon',\n  mirror: 'MirrorIcon',\n  grow: 'GrowIcon',\n  paintbrush: 'PaintBrushIcon',\n  ruler: 'RulerIcon',\n  stop: 'StopIcon',\n  camera: 'CameraIcon',\n  video: 'VideoIcon',\n  speaker: 'SpeakerIcon',\n  play: 'PlayIcon',\n  playback: 'PlayBackIcon',\n  playnext: 'PlayNextIcon',\n  rewind: 'RewindIcon',\n  fastforward: 'FastForwardIcon',\n  stopalt: 'StopAltIcon',\n  sidebyside: 'SideBySideIcon',\n  stacked: 'StackedIcon',\n  sun: 'SunIcon',\n  moon: 'MoonIcon',\n  book: 'BookIcon',\n  document: 'DocumentIcon',\n  copy: 'CopyIcon',\n  category: 'CategoryIcon',\n  folder: 'FolderIcon',\n  print: 'PrintIcon',\n  graphline: 'GraphLineIcon',\n  calendar: 'CalendarIcon',\n  graphbar: 'GraphBarIcon',\n  menu: 'MenuIcon',\n  menualt: 'MenuIcon',\n  filter: 'FilterIcon',\n  docchart: 'DocChartIcon',\n  doclist: 'DocListIcon',\n  markup: 'MarkupIcon',\n  bold: 'BoldIcon',\n  paperclip: 'PaperClipIcon',\n  listordered: 'ListOrderedIcon',\n  listunordered: 'ListUnorderedIcon',\n  paragraph: 'ParagraphIcon',\n  markdown: 'MarkdownIcon',\n  repository: 'RepoIcon',\n  commit: 'CommitIcon',\n  branch: 'BranchIcon',\n  pullrequest: 'PullRequestIcon',\n  merge: 'MergeIcon',\n  apple: 'AppleIcon',\n  linux: 'LinuxIcon',\n  ubuntu: 'UbuntuIcon',\n  windows: 'WindowsIcon',\n  storybook: 'StorybookIcon',\n  azuredevops: 'AzureDevOpsIcon',\n  bitbucket: 'BitbucketIcon',\n  chrome: 'ChromeIcon',\n  chromatic: 'ChromaticIcon',\n  componentdriven: 'ComponentDrivenIcon',\n  discord: 'DiscordIcon',\n  facebook: 'FacebookIcon',\n  figma: 'FigmaIcon',\n  gdrive: 'GDriveIcon',\n  github: 'GithubIcon',\n  gitlab: 'GitlabIcon',\n  google: 'GoogleIcon',\n  graphql: 'GraphqlIcon',\n  medium: 'MediumIcon',\n  redux: 'ReduxIcon',\n  twitter: 'TwitterIcon',\n  youtube: 'YoutubeIcon',\n  vscode: 'VSCodeIcon',\n} as const;\n"
  },
  {
    "path": "code/core/src/components/components/placeholder/placeholder.stories.tsx",
    "content": "import React, { Fragment } from 'react';\n\nimport { Link } from '../typography/link/link.tsx';\nimport { Placeholder } from './placeholder.tsx';\n\nexport default {\n  component: Placeholder,\n};\n\nexport const SingleChild = () => (\n  <Placeholder>This is a placeholder with single child, it's bolded</Placeholder>\n);\nexport const TwoChildren = () => (\n  <Placeholder>\n    <Fragment key=\"title\">This has two children, the first bold</Fragment>\n    <Fragment key=\"desc\">\n      The second normal weight. Here's a&nbsp;\n      <Link href=\"https://storybook.js.org\" secondary cancel={false}>\n        link\n      </Link>\n    </Fragment>\n  </Placeholder>\n);\n"
  },
  {
    "path": "code/core/src/components/components/placeholder/placeholder.tsx",
    "content": "import React, { Children } from 'react';\n\nimport { styled } from 'storybook/theming';\n\nconst Title = styled.div(({ theme }) => ({\n  fontWeight: theme.typography.weight.bold,\n}));\n\nconst Desc = styled.div();\n\nconst Message = styled.div(({ theme }) => ({\n  padding: 30,\n  textAlign: 'center',\n  color: theme.color.defaultText,\n  fontSize: theme.typography.size.s2 - 1,\n}));\n\nexport interface PlaceholderProps {\n  children?: React.ReactNode;\n}\n\nexport const Placeholder = ({ children, ...props }: PlaceholderProps) => {\n  const [title, desc] = Children.toArray(children);\n  return (\n    <Message {...props}>\n      <Title>{title}</Title>\n      {desc && <Desc>{desc}</Desc>}\n    </Message>\n  );\n};\n"
  },
  {
    "path": "code/core/src/components/components/shared/animation.ts",
    "content": "import { keyframes } from 'storybook/theming';\n\nexport const rotate360 = keyframes`\n\tfrom {\n\t\ttransform: rotate(0deg);\n\t}\n\tto {\n\t\ttransform: rotate(360deg);\n\t}\n`;\n"
  },
  {
    "path": "code/core/src/components/components/shared/overlayHelpers.tsx",
    "content": "import React, { type ButtonHTMLAttributes, type ReactNode, forwardRef, useState } from 'react';\n\nimport type { DecoratorFunction } from 'storybook/internal/csf';\n\nimport { UNSAFE_PortalProvider } from '@react-aria/overlays';\nimport type { PositionProps } from '@react-types/overlays';\nimport memoize from 'memoizerific';\nimport { styled } from 'storybook/theming';\n\ntype BasicPlacement = 'top' | 'bottom' | 'left' | 'right';\n\ntype PlacementWithModifier =\n  | 'top-start'\n  | 'top-end'\n  | 'bottom-start'\n  | 'bottom-end'\n  | 'left-start'\n  | 'left-end'\n  | 'right-start'\n  | 'right-end';\n\nexport type PopperPlacement = BasicPlacement | PlacementWithModifier;\n\nexport const convertToReactAriaPlacement = memoize(1000)((\n  p: PopperPlacement\n): NonNullable<PositionProps['placement']> => {\n  if (p === 'left-end') {\n    return 'left bottom';\n  }\n\n  if (p === 'right-end') {\n    return 'right bottom';\n  }\n\n  if (p === 'left-start') {\n    return 'left top';\n  }\n\n  if (p === 'right-start') {\n    return 'right top';\n  }\n\n  return p.replace('-', ' ') as NonNullable<PositionProps['placement']>;\n});\n\n// Story helper\nconst Container = styled.div({\n  width: 500,\n  height: 500,\n  paddingTop: 100,\n  overflowY: 'scroll',\n  background: '#eee',\n  position: 'relative',\n});\n\n// Story helper\ninterface TriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n  children: ReactNode;\n}\nexport const Trigger = forwardRef<HTMLButtonElement, TriggerProps>((props, ref) => (\n  <button\n    {...props}\n    ref={ref}\n    style={{\n      width: 120,\n      height: 50,\n      margin: 10,\n    }}\n  />\n));\nTrigger.displayName = 'Trigger';\n\n/**\n * Storybook decorator to help render PopoverProvider in stories. Internal to Storybook. Use at your\n * own risk.\n */\nexport const OverlayTriggerDecorator: DecoratorFunction = (Story, { args }) => {\n  const [container, setContainer] = useState<HTMLElement | null>(null);\n\n  return (\n    <Container>\n      <UNSAFE_PortalProvider getContainer={() => container}>\n        <Story args={args} />\n      </UNSAFE_PortalProvider>\n      <div id=\"portal\" ref={(element) => setContainer(element ?? null)}></div>\n    </Container>\n  );\n};\n"
  },
  {
    "path": "code/core/src/components/components/spaced/Spaced.stories.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React from 'react';\n\nimport { styled } from 'storybook/theming';\n\nimport { Spaced } from './Spaced.tsx';\n\nconst PlaceholderBlock = styled.div(({ color }) => ({\n  background: color || 'hotpink',\n  padding: 20,\n}));\nconst PlaceholderInline = styled.span(({ color }) => ({\n  background: color || 'hotpink',\n  display: 'inline-block',\n  padding: 20,\n}));\n\nexport default {\n  component: Spaced,\n};\n\nexport const Default = (args: ComponentProps<typeof Spaced>) => (\n  <div>\n    <PlaceholderBlock color=\"silver\" />\n    <Spaced {...args}>\n      <PlaceholderBlock />\n      <PlaceholderBlock />\n      <PlaceholderBlock />\n    </Spaced>\n    <PlaceholderBlock color=\"silver\" />\n  </div>\n);\n\nexport const Column = {\n  render: (args: ComponentProps<typeof Spaced>) => (\n    <div>\n      <PlaceholderBlock color=\"silver\" />\n      <Spaced {...args}>\n        <PlaceholderBlock />\n        <PlaceholderBlock />\n        <PlaceholderBlock />\n      </Spaced>\n      <PlaceholderBlock color=\"silver\" />\n    </div>\n  ),\n};\nexport const Row = {\n  render: (args: ComponentProps<typeof Spaced>) => (\n    <div>\n      <PlaceholderInline color=\"silver\" />\n      <Spaced {...args}>\n        <PlaceholderInline />\n        <PlaceholderInline />\n        <PlaceholderInline />\n      </Spaced>\n      <PlaceholderInline color=\"silver\" />\n    </div>\n  ),\n  argTypes: {\n    col: {\n      defaultValue: 1,\n    },\n  },\n};\n"
  },
  {
    "path": "code/core/src/components/components/spaced/Spaced.tsx",
    "content": "import React from 'react';\n\nimport { ignoreSsrWarning, styled } from 'storybook/theming';\n\nconst toNumber = (input: any) => (typeof input === 'number' ? input : Number(input));\n\nexport interface ContainerProps {\n  col?: number;\n  row?: number;\n  outer?: number;\n}\n\nconst Container = styled.div<ContainerProps>(\n  ({ theme, col, row = 1 }) =>\n    col\n      ? {\n          display: 'inline-block',\n          verticalAlign: 'inherit',\n          '& > *': {\n            marginLeft: col * theme.layoutMargin,\n            verticalAlign: 'inherit',\n          },\n          [`& > *:first-child${ignoreSsrWarning}`]: {\n            marginLeft: 0,\n          },\n        }\n      : {\n          '& > *': {\n            marginTop: row * theme.layoutMargin,\n          },\n          [`& > *:first-child${ignoreSsrWarning}`]: {\n            marginTop: 0,\n          },\n        },\n  ({ theme, outer, col, row }) => {\n    switch (true) {\n      case !!(outer && col): {\n        return {\n          marginLeft: outer * theme.layoutMargin,\n          marginRight: outer * theme.layoutMargin,\n        };\n      }\n      case !!(outer && row): {\n        return {\n          marginTop: outer * theme.layoutMargin,\n          marginBottom: outer * theme.layoutMargin,\n        };\n      }\n      default: {\n        return {};\n      }\n    }\n  }\n);\n\nexport interface SpacedProps {\n  children?: React.ReactNode;\n  col?: number;\n  row?: number;\n  outer?: number | boolean;\n}\n\nexport const Spaced = ({ col, row, outer, children, ...rest }: SpacedProps) => {\n  const outerAmount = toNumber(typeof outer === 'number' || !outer ? outer : col || row);\n\n  return (\n    <Container col={col} row={row} outer={outerAmount} {...rest}>\n      {children}\n    </Container>\n  );\n};\n"
  },
  {
    "path": "code/core/src/components/components/syntaxhighlighter/clipboard.ts",
    "content": "import { global } from '@storybook/global';\n\nconst { document, window: globalWindow } = global;\n\nasync function copyUsingClipboardAPI(text: string) {\n  try {\n    await globalWindow.top?.navigator.clipboard.writeText(text);\n  } catch {\n    await globalWindow.navigator.clipboard.writeText(text);\n  }\n}\n\nasync function copyUsingWorkAround(text: string) {\n  const tmp = document.createElement('TEXTAREA') as HTMLTextAreaElement;\n  const focus = document.activeElement as HTMLTextAreaElement;\n\n  tmp.value = text;\n\n  document.body.appendChild(tmp);\n  tmp.select();\n  document.execCommand('copy');\n  document.body.removeChild(tmp);\n  focus.focus();\n}\n\nexport function createCopyToClipboardFunction() {\n  return globalWindow.navigator?.clipboard ? copyUsingClipboardAPI : copyUsingWorkAround;\n}\n"
  },
  {
    "path": "code/core/src/components/components/syntaxhighlighter/formatter.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { dedent } from 'ts-dedent';\n\nimport { formatter } from './formatter.ts';\n\ndescribe('dedent', () => {\n  it('handles empty string', async () => {\n    const input = '';\n    const result = formatter(true, input);\n\n    await expect(result).resolves.toBe(input);\n  });\n\n  it('handles single line', async () => {\n    const input = 'console.log(\"hello world\")';\n    const result = formatter(true, input);\n\n    await expect(result).resolves.toBe(input);\n  });\n\n  it('does not transform correct code', async () => {\n    const input = dedent`\n    console.log(\"hello\");\n    console.log(\"world\");\n  `;\n    const result = formatter(true, input);\n\n    await expect(result).resolves.toBe(input);\n  });\n\n  it('does transform incorrect code', async () => {\n    const input = `\n    console.log(\"hello\");\n    console.log(\"world\");\n  `;\n    const result = formatter(true, input);\n\n    await expect(result).resolves.toBe(`console.log(\"hello\");\nconsole.log(\"world\");`);\n  });\n\n  it('more indentations - skip first line', async () => {\n    const input = `\n    it('handles empty string', () => {\n      const input = '';\n      const result = formatter(input);\n    \n      expect(result).toBe(input);\n    });\n  `;\n    const result = formatter(true, input);\n\n    await expect(result).resolves.toBe(`it('handles empty string', () => {\n  const input = '';\n  const result = formatter(input);\n\n  expect(result).toBe(input);\n});`);\n  });\n\n  it('more indentations - code on first line', async () => {\n    const input = `// some comment\n    it('handles empty string', () => {\n      const input = '';\n      const result = formatter(input);\n    \n      expect(result).toBe(input);\n    });\n  `;\n    const result = formatter(true, input);\n\n    await expect(result).resolves.toBe(`// some comment\nit('handles empty string', () => {\n  const input = '';\n  const result = formatter(input);\n\n  expect(result).toBe(input);\n});`);\n  });\n\n  it('removes whitespace in empty line completely', async () => {\n    const input = `\n    console.log(\"hello\");\n\n    console.log(\"world\");\n  `;\n    const result = formatter(true, input);\n\n    await expect(result).resolves.toBe(`console.log(\"hello\");\n\nconsole.log(\"world\");`);\n  });\n});\n"
  },
  {
    "path": "code/core/src/components/components/syntaxhighlighter/formatter.ts",
    "content": "import memoize from 'memoizerific';\nimport { dedent } from 'ts-dedent';\n\nimport type { SyntaxHighlighterFormatTypes } from './syntaxhighlighter-types.ts';\n\nexport const formatter = memoize(2)(async (type: SyntaxHighlighterFormatTypes, source: string) => {\n  if (type === false) {\n    return source;\n  }\n\n  return dedent(source);\n});\n"
  },
  {
    "path": "code/core/src/components/components/syntaxhighlighter/lazy-syntaxhighlighter.tsx",
    "content": "import React, { Suspense, lazy } from 'react';\nimport type { ComponentProps } from 'react';\n\nimport type ReactSyntaxHighlighter from './syntaxhighlighter.tsx';\n\nlet languages: Parameters<typeof ReactSyntaxHighlighter.registerLanguage>[] = [];\nlet Comp: typeof ReactSyntaxHighlighter | null = null;\n\nconst LazySyntaxHighlighter = lazy(async () => {\n  const { SyntaxHighlighter } = await import('./syntaxhighlighter.tsx');\n\n  if (languages.length > 0) {\n    languages.forEach((args) => {\n      SyntaxHighlighter.registerLanguage(...args);\n    });\n    languages = [];\n  }\n\n  if (Comp === null) {\n    Comp = SyntaxHighlighter;\n  }\n\n  return {\n    default: (props: ComponentProps<typeof SyntaxHighlighter>) => <SyntaxHighlighter {...props} />,\n  };\n});\n\nconst LazySyntaxHighlighterWithFormatter = lazy(async () => {\n  const [{ SyntaxHighlighter }, { formatter }] = await Promise.all([\n    import('./syntaxhighlighter.tsx'),\n    import('./formatter.ts'),\n  ]);\n\n  if (languages.length > 0) {\n    languages.forEach((args) => {\n      SyntaxHighlighter.registerLanguage(...args);\n    });\n    languages = [];\n  }\n\n  if (Comp === null) {\n    Comp = SyntaxHighlighter;\n  }\n\n  return {\n    default: (props: ComponentProps<typeof SyntaxHighlighter>) => (\n      <SyntaxHighlighter {...props} formatter={formatter} />\n    ),\n  };\n});\n\nexport const SyntaxHighlighter = (\n  props:\n    | ComponentProps<typeof LazySyntaxHighlighter>\n    | ComponentProps<typeof LazySyntaxHighlighterWithFormatter>\n) => (\n  <Suspense fallback={<div />}>\n    {props.format !== false ? (\n      <LazySyntaxHighlighterWithFormatter {...props} />\n    ) : (\n      <LazySyntaxHighlighter {...props} />\n    )}\n  </Suspense>\n);\n\nSyntaxHighlighter.registerLanguage = (\n  ...args: Parameters<typeof ReactSyntaxHighlighter.registerLanguage>\n) => {\n  if (Comp !== null) {\n    Comp.registerLanguage(...args);\n    return;\n  }\n  languages.push(args);\n};\n"
  },
  {
    "path": "code/core/src/components/components/syntaxhighlighter/syntaxhighlighter-types.ts",
    "content": "import type { ReactNode } from 'react';\n\nimport type { supportedLanguages } from './syntaxhighlighter.tsx';\n\nexport interface SyntaxHighlighterRendererProps {\n  rows: any[];\n  stylesheet: string;\n  useInlineStyles: boolean;\n}\n\nexport type SyntaxHighlighterRenderer = (props: SyntaxHighlighterRendererProps) => ReactNode;\n\nexport interface SyntaxHighlighterCustomProps {\n  language: string;\n  copyable?: boolean;\n  bordered?: boolean;\n  padded?: boolean;\n  format?: SyntaxHighlighterFormatTypes;\n  formatter?: (type: SyntaxHighlighterFormatTypes, source: string) => Promise<string>;\n  className?: string;\n  renderer?: SyntaxHighlighterRenderer;\n}\n\nexport type SyntaxHighlighterFormatTypes = boolean | 'dedent';\n\n// these are copied from the `react-syntax-highlighter` package\n// the reason these a COPIED is the types for this package are defining modules by filename\n// which will not match one we've localized type-definitions\ntype LineTagPropsFunction = (lineNumber: number) => React.HTMLProps<HTMLElement>;\n\nexport type SupportedLanguage = 'text' | keyof typeof supportedLanguages;\n\nexport interface SyntaxHighlighterBaseProps {\n  children?: React.ReactNode;\n  codeTagProps?: React.HTMLProps<HTMLElement>;\n  customStyle?: any;\n  language?: SupportedLanguage;\n  lineNumberStyle?: any;\n  lineProps?: LineTagPropsFunction | React.HTMLProps<HTMLElement>;\n  showLineNumbers?: boolean;\n  startingLineNumber?: number;\n  wrapLongLines?: boolean;\n  style?: any;\n  useInlineStyles?: boolean;\n}\n\nexport type SyntaxHighlighterProps = SyntaxHighlighterBaseProps & SyntaxHighlighterCustomProps;\n"
  },
  {
    "path": "code/core/src/components/components/syntaxhighlighter/syntaxhighlighter.stories.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React from 'react';\n\nimport { ThemeProvider, ensure, themes } from 'storybook/theming';\n\nimport { SyntaxHighlighter } from './lazy-syntaxhighlighter.tsx';\n\nexport default {\n  component: SyntaxHighlighter,\n};\n\nexport const JS = {\n  args: {\n    language: 'js',\n    children: `import React, { createElement } from 'react';\nimport { Good, Things } from 'life';\n\nconst result = () => createElement(Good, [createElement(Things, [], { all: true }), []);\n\nconsole.log(result);\nexport { result as default };`,\n  },\n};\n\nexport const Default = JS;\n\nexport const Bash = {\n  args: {\n    language: 'bash',\n    children: `npx npm-check-updates ' / storybook / ' -u && npm install`,\n  },\n};\n\nexport const CSS = {\n  args: {\n    language: 'css',\n    children: `.className {\n              border: 1px solid hotpink;\n            }`,\n  },\n};\n\nexport const JSON = {\n  args: {\n    language: 'json',\n    children: `{\n        \"number\": 1,\n        \"string\": \"something\",\n        \"object\": {\n          \"property\": \"value\",\n        },\n        array: [1,2,3],\n      }`,\n  },\n};\n\nexport const Markdown = {\n  args: {\n    language: 'markdown',\n    children: `\n# a big header\n\nsome code:\n      \n\\`\\`\\`js\nconst name = \"a string\";\n\\`\\`\\`\n      \n> crazy`,\n  },\n};\n\nexport const Yaml = {\n  args: {\n    language: 'yaml',\n    children: `\n      product:\n        - sku: BL394D\n          quantity: 4\n          description: Basketball\n          price: 450.00\n`,\n  },\n};\n\nexport const JSX = {\n  args: {\n    language: 'jsx',\n    children: `import { Good, Things } from 'life';\n\n    const result = () => <Good><Things all={true} /></Good>;\n\n    export { result as default };\n`,\n  },\n};\n\nexport const GraphQL = {\n  args: {\n    language: 'graphql',\n    children: `query HeroNameAndFriends($episode: Episode) {\n      hero(episode: $episode) {\n        name\n      friends {\n          name\n      }\n    }\n  }\n`,\n  },\n};\n\nexport const CustomSyntax = {\n  args: {\n    language: 'scss',\n    children: `// Custom language syntax registered\ndiv.parent {\n  div.child {\n    color: $red;\n  }\n}`,\n  },\n  loaders: [\n    async () => {\n      const scss = (await import('react-syntax-highlighter/dist/esm/languages/prism/scss')).default;\n      SyntaxHighlighter.registerLanguage('scss', scss);\n    },\n  ],\n};\n\nexport const Unsupported = {\n  args: {\n    language: 'C#',\n    children: `// A Hello World! program in C#.\n    using System;\n    namespace HelloWorld\n    {\n        class Hello\n      {\n          static void Main()\n        {\n            Console.WriteLine(\"Hello World!\");\n\n          // Keep the console window open in debug mode.\n          Console.WriteLine(\"Press any key to exit.\");\n          Console.ReadKey();\n        }\n      }\n    }`,\n  },\n};\n\nexport const UnsupportedDark = {\n  args: {\n    language: 'C#',\n    children: `// A Hello World! program in C#.\n    using System;\n    namespace HelloWorld\n    {\n        class Hello\n      {\n          static void Main()\n        {\n            Console.WriteLine(\"Hello World!\");\n\n          // Keep the console window open in debug mode.\n          Console.WriteLine(\"Press any key to exit.\");\n          Console.ReadKey();\n        }\n      }\n    }`,\n  },\n  render: (args: ComponentProps<typeof SyntaxHighlighter>) => (\n    <ThemeProvider theme={ensure(themes.dark)}>\n      <SyntaxHighlighter {...args} />\n    </ThemeProvider>\n  ),\n};\n\nexport const Story = {\n  args: {\n    language: 'jsx',\n    children: `import type { Meta, StoryObj } from '@storybook/react-vite';\n\n    import { Header } from './Header';\n    \n    const meta = {\n      title: 'Example/Header',\n      component: Header,\n      // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n      tags: ['autodocs'],\n      parameters: {\n        // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n        layout: 'fullscreen',\n      },\n    } satisfies Meta<typeof Header>;\n    \n    export default meta;\n    type Story = StoryObj<typeof meta>;\n    \n    export const LoggedIn: Story = {\n      args: {\n        user: {\n          name: 'Jane Doe',\n        },\n      },\n    };\n    \n    export const LoggedOut: Story = {};\n    `,\n  },\n};\n\nexport const BorderedCopyable = {\n  args: {\n    copyable: true,\n    bordered: true,\n    language: 'jsx',\n    children: `import { Good, Things } from 'life';\n\n    const result = () => <Good><Things /></Good>;\n\n    export { result as default };`,\n  },\n};\n\nexport const Padded = {\n  args: {\n    padded: true,\n    language: 'jsx',\n    children: `import { Good, Things } from 'life';\n\n    const result = () => <Good><Things /></Good>;\n\n    export { result as default };`,\n  },\n};\n\nexport const ShowLineNumbers = {\n  args: {\n    showLineNumbers: true,\n    language: 'jsx',\n    children: `import { Good, Things } from 'life';\n\n    const result = () => <Good><Things /></Good>;\n\n    export { result as default };`,\n  },\n};\n"
  },
  {
    "path": "code/core/src/components/components/syntaxhighlighter/syntaxhighlighter.tsx",
    "content": "import type { MouseEvent } from 'react';\nimport React, { useCallback, useEffect, useState } from 'react';\n\nimport { logger } from 'storybook/internal/client-logger';\n\nimport { global } from '@storybook/global';\n\nimport memoize from 'memoizerific';\n// @ts-expect-error (Converted from ts-ignore)\nimport createElement from 'react-syntax-highlighter/dist/esm/create-element';\nimport bash from 'react-syntax-highlighter/dist/esm/languages/prism/bash';\nimport css from 'react-syntax-highlighter/dist/esm/languages/prism/css';\nimport graphql from 'react-syntax-highlighter/dist/esm/languages/prism/graphql';\n// @ts-expect-error (Converted from ts-ignore)\nimport jsExtras from 'react-syntax-highlighter/dist/esm/languages/prism/js-extras';\nimport json from 'react-syntax-highlighter/dist/esm/languages/prism/json';\nimport jsx from 'react-syntax-highlighter/dist/esm/languages/prism/jsx';\nimport md from 'react-syntax-highlighter/dist/esm/languages/prism/markdown';\nimport html from 'react-syntax-highlighter/dist/esm/languages/prism/markup';\nimport tsx from 'react-syntax-highlighter/dist/esm/languages/prism/tsx';\nimport typescript from 'react-syntax-highlighter/dist/esm/languages/prism/typescript';\nimport yml from 'react-syntax-highlighter/dist/esm/languages/prism/yaml';\nimport ReactSyntaxHighlighter from 'react-syntax-highlighter/dist/esm/prism-light';\nimport { styled } from 'storybook/theming';\n\nimport { ActionBar } from '../ActionBar/ActionBar.tsx';\nimport type { ScrollAreaProps } from '../ScrollArea/ScrollArea.tsx';\nimport { ScrollArea } from '../ScrollArea/ScrollArea.tsx';\nimport { createCopyToClipboardFunction } from './clipboard.ts';\nimport type {\n  SyntaxHighlighterProps,\n  SyntaxHighlighterRenderer,\n  SyntaxHighlighterRendererProps,\n} from './syntaxhighlighter-types.ts';\n\nconst { window: globalWindow } = global;\n\nexport const supportedLanguages = {\n  jsextra: jsExtras,\n  jsx,\n  json,\n  yml,\n  md,\n  bash,\n  css,\n  html,\n  tsx,\n  typescript,\n  graphql,\n};\n\nObject.entries(supportedLanguages).forEach(([key, val]) => {\n  ReactSyntaxHighlighter.registerLanguage(key, val);\n});\n\nconst themedSyntax = memoize(2)((theme) =>\n  Object.entries(theme.code || {}).reduce((acc, [key, val]) => ({ ...acc, [`* .${key}`]: val }), {})\n);\n\nconst copyToClipboard: (text: string) => Promise<void> = createCopyToClipboardFunction();\n\nexport interface WrapperProps {\n  bordered?: boolean;\n  padded?: boolean;\n  showLineNumbers?: boolean;\n}\n\nconst Wrapper = styled.div<WrapperProps>(\n  ({ theme }) => ({\n    position: 'relative',\n    display: 'flex',\n    flexWrap: 'wrap',\n    overflow: 'hidden',\n    color: theme.color.defaultText,\n  }),\n  ({ theme, bordered }) =>\n    bordered\n      ? {\n          border: `1px solid ${theme.appBorderColor}`,\n          borderRadius: theme.borderRadius,\n          background: theme.background.content,\n        }\n      : {},\n  ({ showLineNumbers }) =>\n    showLineNumbers\n      ? {\n          // use the before pseudo element to display line numbers\n          '.react-syntax-highlighter-line-number::before': {\n            content: 'attr(data-line-number)',\n          },\n        }\n      : {}\n);\n\nconst UnstyledScroller = ({ children, className }: ScrollAreaProps) => (\n  <ScrollArea horizontal vertical focusable className={className}>\n    {children}\n  </ScrollArea>\n);\nconst Scroller = styled(UnstyledScroller)(\n  {\n    flex: 1,\n    flexShrink: 0,\n    flexBasis: 'fit-content',\n    maxWidth: '100%',\n  },\n  ({ theme }) => themedSyntax(theme)\n);\n\nexport interface PreProps {\n  padded?: boolean;\n}\n\nconst Pre = styled.pre<PreProps>(({ theme, padded }) => ({\n  display: 'flex',\n  justifyContent: 'flex-start',\n  margin: 0,\n  padding: padded ? theme.layoutMargin : 0,\n}));\n\n/*\nWe can't use `code` since PrismJS races for it.\nSee https://github.com/storybookjs/storybook/issues/18090\n */\nconst Code = styled.div(({ theme }) => ({\n  flex: 1,\n  paddingLeft: 2, // TODO: To match theming/global.ts for now\n  paddingRight: theme.layoutMargin,\n  opacity: 1,\n  fontFamily: theme.typography.fonts.mono,\n}));\n\nconst processLineNumber = (row: any) => {\n  const children = [...row.children];\n  const lineNumberNode = children[0];\n  const lineNumber = lineNumberNode.children[0].value;\n  const processedLineNumberNode = {\n    ...lineNumberNode,\n    // empty the line-number element\n    children: [],\n    properties: {\n      ...lineNumberNode.properties,\n      // add a data-line-number attribute to line-number element, so we can access the line number with `content: attr(data-line-number)`\n      'data-line-number': lineNumber,\n      // remove the 'userSelect: none' style, which will produce extra empty lines when copy-pasting in firefox\n      style: { ...lineNumberNode.properties.style, userSelect: 'auto' },\n    },\n  };\n  children[0] = processedLineNumberNode;\n  return { ...row, children };\n};\n\n/**\n * A custom renderer for handling `span.linenumber` element in each line of code, which is enabled\n * by default if no renderer is passed in from the parent component\n */\nconst defaultRenderer: SyntaxHighlighterRenderer = ({ rows, stylesheet, useInlineStyles }) => {\n  return rows.map((node: any, i: number) => {\n    return createElement({\n      node: processLineNumber(node),\n      stylesheet,\n      useInlineStyles,\n      key: `code-segement${i}`,\n    });\n  });\n};\n\nconst wrapRenderer = (\n  renderer: SyntaxHighlighterRenderer | undefined,\n  showLineNumbers: boolean\n) => {\n  if (!showLineNumbers) {\n    return renderer;\n  }\n  if (renderer) {\n    return ({ rows, ...rest }: SyntaxHighlighterRendererProps) =>\n      renderer({ rows: rows.map((row) => processLineNumber(row)), ...rest });\n  }\n  return defaultRenderer;\n};\n\nexport interface SyntaxHighlighterState {\n  copied: boolean;\n}\n\n// copied from @types/react-syntax-highlighter/index.d.ts\n\nexport const SyntaxHighlighter = ({\n  children,\n  language = 'jsx',\n  copyable = false,\n  bordered = false,\n  padded = false,\n  format = true,\n  formatter = undefined,\n  className = undefined,\n  showLineNumbers = false,\n  ...rest\n}: SyntaxHighlighterProps) => {\n  if (typeof children !== 'string' || !children.trim()) {\n    return null;\n  }\n\n  const [highlightableCode, setHighlightableCode] = useState('');\n\n  useEffect(() => {\n    if (formatter) {\n      formatter(format, children).then(setHighlightableCode);\n    } else {\n      setHighlightableCode(children.trim());\n    }\n  }, [children, format, formatter]);\n\n  const [copied, setCopied] = useState(false);\n\n  const onClick = useCallback(\n    (e: MouseEvent<HTMLButtonElement>) => {\n      e.preventDefault();\n      copyToClipboard(highlightableCode)\n        .then(() => {\n          setCopied(true);\n          globalWindow.setTimeout(() => setCopied(false), 1500);\n        })\n        .catch(logger.error);\n    },\n    [highlightableCode]\n  );\n  const renderer = wrapRenderer(rest.renderer, showLineNumbers);\n\n  return (\n    <Wrapper\n      bordered={bordered}\n      padded={padded}\n      showLineNumbers={showLineNumbers}\n      className={className}\n    >\n      <Scroller>\n        <ReactSyntaxHighlighter\n          padded={padded || bordered}\n          language={language}\n          showLineNumbers={showLineNumbers}\n          showInlineLineNumbers={showLineNumbers}\n          useInlineStyles={false}\n          PreTag={Pre}\n          CodeTag={Code}\n          lineNumberContainerStyle={{}}\n          {...rest}\n          renderer={renderer}\n        >\n          {highlightableCode}\n        </ReactSyntaxHighlighter>\n      </Scroller>\n\n      {copyable ? (\n        <ActionBar actionItems={[{ title: copied ? 'Copied' : 'Copy', onClick }]} flexLayout />\n      ) : null}\n    </Wrapper>\n  );\n};\n\nSyntaxHighlighter.registerLanguage = (\n  ...args: Parameters<typeof ReactSyntaxHighlighter.registerLanguage>\n) => ReactSyntaxHighlighter.registerLanguage(...args);\n\nexport default SyntaxHighlighter;\n"
  },
  {
    "path": "code/core/src/components/components/tooltip/ListItem.stories.tsx",
    "content": "import React, { Fragment } from 'react';\n\nimport { EyeIcon } from '@storybook/icons';\n\nimport ListItem from './ListItem.tsx';\n\nexport default {\n  component: ListItem,\n};\n\nexport const All = {\n  render: () => (\n    <div>\n      <ListItem loading />\n      <ListItem title=\"Default\" />\n      <ListItem title=\"Default icon\" right={<EyeIcon />} />\n      <ListItem title=\"title\" center=\"center\" right=\"right\" />\n      <ListItem active title=\"active\" center=\"center\" right=\"right\" />\n      <ListItem active title=\"active icon\" center=\"center\" right={<EyeIcon />} />\n      <ListItem disabled title=\"disabled\" center=\"center\" right=\"right\" />\n    </div>\n  ),\n};\n\nexport const Default = {\n  args: {\n    title: 'Default',\n  },\n};\n\nexport const Loading = {\n  args: {\n    loading: true,\n  },\n};\n\nexport const DefaultIcon = {\n  args: {\n    title: 'Default icon',\n    right: <EyeIcon />,\n  },\n};\nexport const ActiveIcon = {\n  args: {\n    title: 'Active icon',\n    active: true,\n    right: <EyeIcon />,\n  },\n};\nexport const ActiveIconLeft = {\n  args: {\n    title: 'Active icon',\n    active: true,\n    icon: <EyeIcon />,\n  },\n};\nexport const ActiveIconLeftColored = {\n  args: {\n    title: 'Active icon',\n    active: true,\n    icon: (\n      <Fragment>\n        <svg\n          width=\"16\"\n          height=\"16\"\n          viewBox=\"0 0 16 16\"\n          fill=\"none\"\n          xmlns=\"http://www.w3.org/2000/svg\"\n          aria-label=\"Chrome\"\n        >\n          <path\n            d=\"M5.06982 9.68493L7.99484 4.63927L14.5786 4.62406C14.5252 4.52043 14.4696 4.41742 14.4109 4.31532C12.372 0.768556 7.84405 -0.453864 4.29726 1.58495C3.24614 2.1892 2.39921 3.01211 1.78076 3.96327L5.06982 9.68493Z\"\n            fill=\"#DB4437\"\n          />\n          <path\n            d=\"M10.9276 9.68457L5.09539 9.6743L1.79036 3.98022C1.72727 4.07822 1.66591 4.17795 1.60682 4.27985C-0.445348 7.81892 0.759985 12.3515 4.29905 14.4037C5.34791 15.0118 6.48403 15.3338 7.617 15.3939L10.9276 9.68457Z\"\n            fill=\"#0F9D58\"\n          />\n          <path\n            d=\"M7.98649 4.61194L10.9032 9.66241L7.63525 15.3778C7.75167 15.3833 7.86871 15.3863 7.98649 15.3863C12.0775 15.3863 15.3939 12.0699 15.3939 7.97893C15.3939 6.76648 15.1025 5.62211 14.5861 4.61194L7.98649 4.61194Z\"\n            fill=\"#FFCD40\"\n          />\n          <path\n            d=\"M8.01367 4.6366V6.40005L14.613 4.6366H8.01367Z\"\n            fill=\"url(#paint0_radial_466_21161)\"\n          />\n          <path\n            d=\"M1.78198 4.00098L6.60102 8.8192L5.09764 9.687L1.78198 4.00098Z\"\n            fill=\"url(#paint1_radial_466_21161)\"\n          />\n          <path\n            d=\"M7.6626 15.4017L9.42689 8.81921L10.9303 9.68702L7.6626 15.4017Z\"\n            fill=\"url(#paint2_radial_466_21161)\"\n          />\n          <ellipse cx=\"8.01347\" cy=\"8.00358\" rx=\"3.36699\" ry=\"3.36699\" fill=\"#F1F1F1\" />\n          <ellipse cx=\"8.01367\" cy=\"8.00354\" rx=\"2.69361\" ry=\"2.6936\" fill=\"#4285F4\" />\n          <defs>\n            <radialGradient\n              id=\"paint0_radial_466_21161\"\n              cx=\"0\"\n              cy=\"0\"\n              r=\"1\"\n              gradientUnits=\"userSpaceOnUse\"\n              gradientTransform=\"translate(7.69229 4.63226) scale(7.07721 1.89116)\"\n            >\n              <stop stopColor=\"#3E2723\" stopOpacity=\"0.2\" />\n              <stop offset=\"1\" stopColor=\"#3E2723\" stopOpacity=\"0.01\" />\n            </radialGradient>\n            <radialGradient\n              id=\"paint1_radial_466_21161\"\n              cx=\"0\"\n              cy=\"0\"\n              r=\"1\"\n              gradientUnits=\"userSpaceOnUse\"\n              gradientTransform=\"translate(1.77445 4.00677) scale(6.56938 7.75127)\"\n            >\n              <stop stopColor=\"#3E2723\" stopOpacity=\"0.2\" />\n              <stop offset=\"1\" stopColor=\"#3E2723\" stopOpacity=\"0.01\" />\n            </radialGradient>\n            <radialGradient\n              id=\"paint2_radial_466_21161\"\n              cx=\"0\"\n              cy=\"0\"\n              r=\"1\"\n              gradientUnits=\"userSpaceOnUse\"\n              gradientTransform=\"translate(8.00025 8.01489) scale(7.39644 14.8995)\"\n            >\n              <stop stopColor=\"#263238\" stopOpacity=\"0.2\" />\n              <stop offset=\"1\" stopColor=\"#263238\" stopOpacity=\"0.01\" />\n            </radialGradient>\n          </defs>\n        </svg>\n      </Fragment>\n    ),\n  },\n};\n\nexport const WPositions = {\n  args: {\n    left: 'left',\n    title: 'title',\n    center: 'center',\n    right: 'right',\n  },\n};\n\nexport const WPositionsActive = {\n  args: {\n    active: true,\n    left: 'left',\n    title: 'title',\n    center: 'center',\n    right: 'right',\n  },\n};\nexport const WPositionsDisabled = {\n  args: {\n    disabled: true,\n    left: 'left',\n    title: 'title',\n    center: 'center',\n    right: 'right',\n  },\n};\n"
  },
  {
    "path": "code/core/src/components/components/tooltip/ListItem.tsx",
    "content": "import React, { type ComponentProps, type ReactNode, type SyntheticEvent, forwardRef } from 'react';\n\nimport { deprecate } from 'storybook/internal/client-logger';\n\nimport memoize from 'memoizerific';\nimport { styled } from 'storybook/theming';\n\nexport interface TitleProps {\n  children?: ReactNode;\n  active?: boolean;\n  loading?: boolean;\n  disabled?: boolean;\n}\nconst Title = styled(({ active, loading, disabled, ...rest }: TitleProps) => <span {...rest} />)<{\n  active: boolean;\n  loading: boolean;\n  disabled: boolean;\n}>(\n  ({ theme }) => ({\n    color: theme.color.defaultText,\n    // Previously was theme.typography.weight.normal but this weight does not exists in Theme\n    fontWeight: theme.typography.weight.regular,\n  }),\n  ({ active, theme }) =>\n    active\n      ? {\n          color: theme.color.secondary,\n          fontWeight: theme.typography.weight.bold,\n        }\n      : {},\n  ({ loading, theme }) =>\n    loading\n      ? {\n          display: 'inline-block',\n          flex: 'none',\n          ...theme.animation.inlineGlow,\n        }\n      : {},\n  ({ disabled, theme }) =>\n    disabled\n      ? {\n          color: theme.textMutedColor,\n        }\n      : {}\n);\n\nexport interface RightProps {\n  active?: boolean;\n}\n\nconst Right = styled.span<RightProps>({\n  display: 'flex',\n  '& svg': {\n    height: 12,\n    width: 12,\n    margin: '3px 0',\n    verticalAlign: 'top',\n  },\n});\n\nconst Center = styled.span<{ isIndented: boolean }>(\n  {\n    flex: 1,\n    textAlign: 'left',\n    display: 'flex',\n    flexDirection: 'column',\n    minWidth: 0, // required for overflow\n  },\n  ({ isIndented }) => (isIndented ? { marginLeft: 24 } : {})\n);\n\nexport interface CenterTextProps {\n  active?: boolean;\n  disabled?: boolean;\n}\n\nconst CenterText = styled.span<CenterTextProps>(\n  ({ theme }) => ({\n    fontSize: '11px',\n    lineHeight: '14px',\n  }),\n  ({ active, theme }) =>\n    active\n      ? {\n          color: theme.color.secondary,\n        }\n      : {},\n  ({ theme, disabled }) =>\n    disabled\n      ? {\n          color: theme.textMutedColor,\n        }\n      : {}\n);\n\nexport interface LeftProps {\n  active?: boolean;\n}\n\nconst Left = styled.span<LeftProps>(\n  ({ active, theme }) =>\n    active\n      ? {\n          color: theme.color.secondary,\n        }\n      : {},\n  () => ({\n    display: 'flex',\n    maxWidth: 14,\n  })\n);\n\nexport interface ItemProps {\n  disabled?: boolean;\n  href?: string;\n  onClick?: (event: SyntheticEvent, ...args: any[]) => any;\n}\n\nconst Item = styled.button<ItemProps>(\n  ({ theme }) => ({\n    width: '100%',\n    minWidth: 0, // required for overflow\n    border: 'none',\n    borderRadius: theme.appBorderRadius,\n    background: 'none',\n    fontSize: theme.typography.size.s1,\n    transition: 'background 150ms ease-out',\n    color: theme.color.dark,\n    textDecoration: 'none',\n    justifyContent: 'space-between',\n\n    lineHeight: '18px',\n    padding: '7px 10px',\n    display: 'flex',\n    alignItems: 'center',\n\n    '& > * + *': {\n      paddingLeft: 10,\n    },\n\n    '&:focus-visible': {\n      outline: `2px solid ${theme.color.secondary}`,\n      outlineOffset: 0,\n    },\n  }),\n  ({ theme, href, onClick }) =>\n    (href || onClick) && {\n      cursor: 'pointer',\n      '&:hover': {\n        background: theme.background.hoverable,\n      },\n      '&:hover svg': {\n        opacity: 1,\n      },\n    },\n  ({ theme, as }) =>\n    as === 'label' && {\n      '&:has(input:not(:disabled))': {\n        cursor: 'pointer',\n        '&:hover': {\n          background: theme.background.hoverable,\n        },\n      },\n    },\n  ({ disabled }) => disabled && { cursor: 'not-allowed' }\n);\n\nconst getItemProps = memoize(100)(({ onClick, input, href, LinkWrapper }) => ({\n  ...(onClick && {\n    as: 'button',\n    role: 'button',\n    onClick,\n  }),\n  ...(input && {\n    as: 'label',\n  }),\n  ...(href && {\n    as: 'a',\n    role: 'link',\n    href,\n    ...(LinkWrapper && {\n      as: LinkWrapper,\n      to: href,\n    }),\n  }),\n}));\n\nexport type LinkWrapperType = (props: any) => ReactNode;\n\nexport interface ListItemProps extends Omit<ComponentProps<typeof Item>, 'title'> {\n  loading?: boolean;\n  title?: ReactNode;\n  center?: ReactNode;\n  right?: ReactNode;\n  icon?: ReactNode;\n  input?: ReactNode;\n  active?: boolean;\n  disabled?: boolean;\n  href?: string;\n  LinkWrapper?: LinkWrapperType;\n  isIndented?: boolean;\n}\n\nconst ListItem = forwardRef((props: ListItemProps, ref) => {\n  const {\n    loading = false,\n    title = <span>Loading state</span>,\n    center = null,\n    right = null,\n    active = false,\n    disabled = false,\n    isIndented = false,\n    href = undefined,\n    onClick = undefined,\n    icon,\n    input,\n    LinkWrapper = undefined,\n    ...rest\n  } = props;\n  const commonProps = { active, disabled };\n  const itemProps = getItemProps(props);\n  const left = icon || input;\n\n  deprecate(\n    '`ListItem` is deprecated and will be removed in Storybook 11, use `MenuItem` instead.'\n  );\n\n  return (\n    <Item data-deprecated=\"ListItem\" ref={ref} {...rest} {...commonProps} {...itemProps}>\n      <>\n        {left && <Left {...commonProps}>{left}</Left>}\n        {title || center ? (\n          <Center isIndented={isIndented && !left}>\n            {title && (\n              <Title {...commonProps} loading={loading}>\n                {title}\n              </Title>\n            )}\n            {center && <CenterText {...commonProps}>{center}</CenterText>}\n          </Center>\n        ) : null}\n        {right && <Right {...commonProps}>{right}</Right>}\n      </>\n    </Item>\n  );\n});\nListItem.displayName = 'ListItem';\n\nexport default ListItem;\n"
  },
  {
    "path": "code/core/src/components/components/tooltip/Tooltip.stories.tsx",
    "content": "import React from 'react';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { Tooltip } from './Tooltip.tsx';\n\nconst SampleTooltip = () => (\n  <div>\n    <h3>Lorem ipsum dolor sit amet</h3>\n    <p>Consectatur vestibulum concet durum politu coret weirom</p>\n  </div>\n);\n\nconst meta = preview.meta({\n  id: 'overlay-Tooltip',\n  title: 'Overlay/Tooltip',\n  component: Tooltip,\n  args: {\n    children: <SampleTooltip />,\n    color: undefined,\n    hasChrome: true,\n  },\n  argTypes: {\n    color: {\n      type: 'string',\n      control: 'select',\n      options: ['default', 'inverse', 'positive', 'negative', 'warning', 'none'],\n    },\n  },\n});\n\nexport const Base = meta.story({\n  args: {\n    children: <SampleTooltip />,\n  },\n});\n\nexport const WithChrome = meta.story({\n  args: {\n    hasChrome: true,\n  },\n});\n\nexport const WithoutChrome = meta.story({\n  args: {\n    hasChrome: false,\n  },\n});\n\nexport const ColorDefault = meta.story({\n  args: {\n    color: 'default',\n  },\n});\n\nexport const ColorInverse = meta.story({\n  args: {\n    color: 'inverse',\n  },\n});\n\nexport const ColorPositive = meta.story({\n  args: {\n    color: 'positive',\n  },\n});\n\nexport const ColorNegative = meta.story({\n  args: {\n    color: 'negative',\n  },\n});\n\nexport const ColorWarning = meta.story({\n  args: {\n    color: 'warning',\n  },\n});\n\nexport const WithoutColor = meta.story({\n  args: {\n    color: 'none',\n  },\n});\n"
  },
  {
    "path": "code/core/src/components/components/tooltip/Tooltip.tsx",
    "content": "import React, { forwardRef } from 'react';\n\nimport { Popover, type PopoverProps } from '../Popover/Popover.tsx';\n\nexport type TooltipProps = Omit<PopoverProps, 'onHide' | 'hideLabel'>;\n\nexport const Tooltip = forwardRef<HTMLDivElement, TooltipProps>((props, ref) => {\n  return <Popover ref={ref} {...props} />;\n});\n\nTooltip.displayName = 'Tooltip';\n"
  },
  {
    "path": "code/core/src/components/components/tooltip/TooltipLinkList.stories.tsx",
    "content": "import React from 'react';\n\nimport { LinkIcon, LinuxIcon } from '@storybook/icons';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { action } from 'storybook/actions';\n\nimport { TooltipLinkList } from './TooltipLinkList.tsx';\nimport { WithTooltip } from './WithTooltip.tsx';\nimport ellipseUrl from './assets/ellipse.png';\n\nconst onLinkClick = action('onLinkClick');\n\nexport default {\n  component: TooltipLinkList,\n  decorators: [\n    (storyFn) => (\n      <div\n        style={{\n          height: '300px',\n        }}\n      >\n        <WithTooltip placement=\"top\" startOpen tooltip={storyFn()}>\n          <div>Tooltip</div>\n        </WithTooltip>\n      </div>\n    ),\n  ],\n  excludeStories: ['links'],\n} satisfies Meta<typeof TooltipLinkList>;\n\ntype Story = StoryObj<typeof TooltipLinkList>;\n\nexport const WithoutIcons = {\n  args: {\n    links: [\n      {\n        id: '1',\n        title: 'Link 1',\n        center: 'This is an addition description',\n        href: 'http://google.com',\n        onClick: onLinkClick,\n      },\n      {\n        id: '2',\n        title: 'Link 2',\n        center: 'This is an addition description',\n        href: 'http://google.com',\n        onClick: onLinkClick,\n      },\n    ],\n  },\n} satisfies Story;\n\nexport const WithOneIcon = {\n  args: {\n    links: [\n      {\n        id: '1',\n        title: 'Link 1',\n        center: 'This is an addition description',\n        icon: <LinkIcon />,\n        href: 'http://google.com',\n        onClick: onLinkClick,\n      },\n      {\n        id: '2',\n        title: 'Link 2',\n        center: 'This is an addition description',\n        href: 'http://google.com',\n        onClick: onLinkClick,\n      },\n    ],\n  },\n} satisfies Story;\n\nexport const ActiveWithoutAnyIcons = {\n  args: {\n    links: [\n      {\n        id: '1',\n        title: 'Link 1',\n        active: true,\n        center: 'This is an addition description',\n        href: 'http://google.com',\n        onClick: onLinkClick,\n      },\n      {\n        id: '2',\n        title: 'Link 2',\n        center: 'This is an addition description',\n        href: 'http://google.com',\n        onClick: onLinkClick,\n      },\n    ],\n  },\n} satisfies Story;\n\nexport const ActiveWithSeparateIcon = {\n  args: {\n    links: [\n      {\n        id: '1',\n        title: 'Link 1',\n        icon: <LinkIcon />,\n        center: 'This is an addition description',\n        href: 'http://google.com',\n        onClick: onLinkClick,\n      },\n      {\n        id: '2',\n        title: 'Link 2',\n        active: true,\n        center: 'This is an addition description',\n        href: 'http://google.com',\n        onClick: onLinkClick,\n      },\n    ],\n  },\n} satisfies Story;\n\nexport const ActiveAndIcon = {\n  args: {\n    links: [\n      {\n        id: '1',\n        title: 'Link 1',\n        active: true,\n        icon: <LinkIcon />,\n        center: 'This is an addition description',\n        href: 'http://google.com',\n        onClick: onLinkClick,\n      },\n      {\n        id: '2',\n        title: 'Link 2',\n        center: 'This is an addition description',\n        href: 'http://google.com',\n        onClick: onLinkClick,\n      },\n    ],\n  },\n} satisfies Story;\n\nexport const WithIllustration = {\n  args: {\n    links: [\n      {\n        id: '1',\n        title: 'Link 1',\n        active: true,\n        icon: <LinkIcon />,\n        right: <img src={ellipseUrl} width=\"16\" height=\"16\" alt=\"ellipse\" />,\n        center: 'This is an addition description',\n        href: 'http://google.com',\n        onClick: onLinkClick,\n      },\n      {\n        id: '2',\n        title: 'Link 2',\n        center: 'This is an addition description',\n        right: <img src={ellipseUrl} width=\"16\" height=\"16\" alt=\"ellipse\" />,\n        href: 'http://google.com',\n        onClick: onLinkClick,\n      },\n    ],\n  },\n} satisfies Story;\n\nexport const WithCustomIcon = {\n  args: {\n    links: [\n      {\n        id: '1',\n        title: 'Link 1',\n        active: true,\n        icon: <LinuxIcon />,\n        right: <img src={ellipseUrl} width=\"16\" height=\"16\" alt=\"ellipse\" />,\n        center: 'This is an addition description',\n        href: 'http://google.com',\n        onClick: onLinkClick,\n      },\n      {\n        id: '2',\n        title: 'Link 2',\n        center: 'This is an addition description',\n        right: <img src={ellipseUrl} width=\"16\" height=\"16\" alt=\"ellipse\" />,\n        href: 'http://google.com',\n        onClick: onLinkClick,\n      },\n    ],\n  },\n} satisfies Story;\n\nexport const WithGroups = {\n  args: {\n    links: [\n      [\n        {\n          id: '1',\n          title: 'Link 1',\n          center: 'This is an addition description',\n          href: 'http://google.com',\n          onClick: onLinkClick,\n        },\n      ],\n      [\n        {\n          id: '1',\n          title: 'Link 1',\n          center: 'This is an addition description',\n          icon: <LinkIcon />,\n          href: 'http://google.com',\n          onClick: onLinkClick,\n        },\n        {\n          id: '2',\n          title: 'Link 2',\n          center: 'This is an addition description',\n          href: 'http://google.com',\n          onClick: onLinkClick,\n        },\n      ],\n      [\n        {\n          id: '2',\n          title: 'Link 2',\n          center: 'This is an addition description',\n          href: 'http://google.com',\n          onClick: onLinkClick,\n        },\n      ],\n    ],\n  },\n} satisfies Story;\n"
  },
  {
    "path": "code/core/src/components/components/tooltip/TooltipLinkList.tsx",
    "content": "import type { ComponentProps, ReactNode, SyntheticEvent } from 'react';\nimport React, { Fragment, useCallback } from 'react';\n\nimport { deprecate } from 'storybook/internal/client-logger';\n\nimport { styled } from 'storybook/theming';\n\nimport type { LinkWrapperType, ListItemProps } from './ListItem.tsx';\nimport ListItem from './ListItem.tsx';\n\nconst List = styled.div(\n  {\n    minWidth: 180,\n    overflow: 'hidden',\n    overflowY: 'auto',\n    maxHeight: 15.5 * 32 + 8, // 15.5 items at 32px each + 8px padding\n  },\n  ({ theme }) => ({\n    borderRadius: theme.appBorderRadius + 2,\n  }),\n  ({ theme }) => (theme.base === 'dark' ? { background: theme.background.content } : {})\n);\n\nconst Group = styled.div(({ theme }) => ({\n  padding: 4,\n  '& + &': {\n    borderTop: `1px solid ${theme.appBorderColor}`,\n  },\n}));\n\nexport interface NormalLink extends Omit<ListItemProps, 'onClick'> {\n  id: string;\n  onClick?: (\n    event: SyntheticEvent,\n    item: Pick<ListItemProps, 'id' | 'active' | 'disabled' | 'title' | 'href'>\n  ) => void;\n}\n\nexport type Link = CustomLink | NormalLink;\n\n/**\n * This is a custom link that can be used in the `TooltipLinkList` component. It allows for custom\n * content to be rendered in the list; it does not have to be a link.\n */\ninterface CustomLink {\n  id: string;\n  content: ReactNode;\n}\n\ninterface ItemProps extends NormalLink {\n  isIndented?: boolean;\n}\n\nconst Item = ({ id, onClick, ...rest }: ItemProps) => {\n  const { active, disabled, title, href } = rest;\n\n  const handleClick = useCallback(\n    (event: SyntheticEvent) => onClick?.(event, { id, active, disabled, title, href }),\n    [onClick, id, active, disabled, title, href]\n  );\n\n  return <ListItem id={`list-item-${id}`} {...rest} {...(onClick && { onClick: handleClick })} />;\n};\n\nexport interface TooltipLinkListProps extends ComponentProps<typeof List> {\n  links: Link[] | Link[][];\n  LinkWrapper?: LinkWrapperType;\n}\n\nexport const TooltipLinkList = ({ links, LinkWrapper, ...props }: TooltipLinkListProps) => {\n  deprecate(\n    '`TooltipLinkList` is deprecated and will be removed in Storybook 11, use `ActionList` or `MenuItem` and `WithMenu` instead.'\n  );\n\n  const groups = Array.isArray(links[0]) ? (links as Link[][]) : [links as Link[]];\n  const isIndented = groups.some((group) =>\n    group.some((link) => ('icon' in link && link.icon) || ('input' in link && link.input))\n  );\n  return (\n    <List data-deprecated=\"TooltipLinkList\" {...props} className=\"sb-list\">\n      {groups\n        .filter((group) => group.length)\n        .map((group, index) => {\n          return (\n            <Group key={group.map((link) => link.id).join(`~${index}~`)}>\n              {group.map((link) => {\n                if ('content' in link) {\n                  return <Fragment key={link.id}>{link.content}</Fragment>;\n                }\n                return (\n                  <Item key={link.id} isIndented={isIndented} LinkWrapper={LinkWrapper} {...link} />\n                );\n              })}\n            </Group>\n          );\n        })}\n    </List>\n  );\n};\n"
  },
  {
    "path": "code/core/src/components/components/tooltip/TooltipMessage.stories.tsx",
    "content": "import React from 'react';\n\nimport type { DecoratorFunction } from 'storybook/internal/csf';\n\nimport type { Meta } from '@storybook/react-vite';\n\nimport { Button } from '../Button/Button.tsx';\nimport { PopoverProvider } from '../Popover/PopoverProvider.tsx';\nimport { TooltipMessage } from './TooltipMessage.tsx';\nimport { WithTooltip } from './WithTooltip.tsx';\n\nconst WithTooltipDecorator: DecoratorFunction = (storyFn) => (\n  <div\n    style={{\n      height: '300px',\n    }}\n  >\n    <WithTooltip placement=\"top\" startOpen tooltip={storyFn()}>\n      <div>Tooltip</div>\n    </WithTooltip>\n  </div>\n);\n\nconst WithPopoverDecorator: DecoratorFunction = (storyFn) => (\n  <div\n    style={{\n      height: '300px',\n    }}\n  >\n    <PopoverProvider\n      ariaLabel=\"Tooltip message\"\n      placement=\"top\"\n      visible\n      padding={0}\n      popover={storyFn()}\n    >\n      <Button ariaLabel={false}>Popover</Button>\n    </PopoverProvider>\n  </div>\n);\n\nexport default {\n  component: TooltipMessage,\n} as Meta;\n\nexport const Default = {\n  args: {\n    title: 'The title',\n    desc: 'The longest of the long description',\n  },\n  decorators: [WithTooltipDecorator],\n};\n\nexport const DefaultPopover = {\n  args: {\n    title: 'The title',\n    desc: 'The longest of the long description',\n  },\n  decorators: [WithPopoverDecorator],\n};\n\nexport const WithSingleLink = {\n  args: {\n    title: 'The title',\n    desc: 'The longest of the long description',\n    links: [\n      {\n        title: 'Continue',\n        href: 'test',\n      },\n    ],\n  },\n  decorators: [WithTooltipDecorator],\n};\n\nexport const WithSingleLinkPopover = {\n  args: {\n    title: 'The title',\n    desc: 'The longest of the long description',\n    links: [\n      {\n        title: 'Continue',\n        href: 'test',\n      },\n    ],\n  },\n  decorators: [WithPopoverDecorator],\n};\n\nexport const WithMultipleLinks = {\n  args: {\n    title: 'The title',\n    desc: 'The longest of the long description',\n    links: [\n      {\n        title: 'Get more tips',\n        href: 'test',\n      },\n      {\n        title: 'Done',\n        href: 'test',\n      },\n    ],\n  },\n  decorators: [WithTooltipDecorator],\n};\n\nexport const WithMultipleLinksPopover = {\n  args: {\n    title: 'The title',\n    desc: 'The longest of the long description',\n    links: [\n      {\n        title: 'Get more tips',\n        href: 'test',\n      },\n      {\n        title: 'Done',\n        href: 'test',\n      },\n    ],\n  },\n  decorators: [WithPopoverDecorator],\n};\n\nexport const DescriptionOnly = {\n  args: {\n    desc: 'The description',\n  },\n  decorators: [WithTooltipDecorator],\n};\n\nexport const DescriptionOnlyPopover = {\n  args: {\n    desc: 'The description',\n  },\n  decorators: [WithPopoverDecorator],\n};\n"
  },
  {
    "path": "code/core/src/components/components/tooltip/TooltipMessage.tsx",
    "content": "import type { ReactNode } from 'react';\nimport React from 'react';\n\nimport { deprecate } from 'storybook/internal/client-logger';\n\nimport { styled } from 'storybook/theming';\n\nimport { Link } from '../typography/link/link.tsx';\n\nconst Title = styled.div(({ theme }) => ({\n  fontWeight: theme.typography.weight.bold,\n}));\n\nconst Desc = styled.span();\n\nconst Links = styled.div(({ theme }) => ({\n  marginTop: 8,\n  textAlign: 'center',\n\n  '> *': {\n    margin: '0 8px',\n    fontWeight: theme.typography.weight.bold,\n  },\n}));\n\nconst Message = styled.div(({ theme }) => ({\n  color: theme.color.defaultText,\n  lineHeight: '18px',\n}));\n\nconst MessageWrapper = styled.div({\n  padding: 15,\n  width: 280,\n  boxSizing: 'border-box',\n});\n\nexport interface TooltipMessageProps {\n  title?: ReactNode;\n  desc?: ReactNode;\n  links?: {\n    title: string;\n    href?: string;\n    onClick?: () => void;\n  }[];\n}\n\nexport const TooltipMessage = ({ title, desc, links }: TooltipMessageProps) => {\n  deprecate(\n    '`TooltipMessage` is deprecated and will be removed in Storybook 11, use `Popover` and `PopoverProvider` instead.'\n  );\n\n  return (\n    <MessageWrapper data-deprecated=\"TooltipMessage\">\n      <Message>\n        {title && <Title>{title}</Title>}\n        {desc && <Desc>{desc}</Desc>}\n      </Message>\n      {links && (\n        <Links>\n          {links.map(({ title: linkTitle, ...other }) => (\n            <Link {...other} key={linkTitle}>\n              {linkTitle}\n            </Link>\n          ))}\n        </Links>\n      )}\n    </MessageWrapper>\n  );\n};\n"
  },
  {
    "path": "code/core/src/components/components/tooltip/TooltipNote.stories.tsx",
    "content": "import { Button } from 'storybook/internal/components';\n\nimport { styled } from 'storybook/theming';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { TooltipNote } from './TooltipNote.tsx';\nimport { TooltipProvider } from './TooltipProvider.tsx';\n\nconst ViewPort = styled.div({\n  height: 300,\n});\n\nconst meta = preview.meta({\n  id: 'overlay-TooltipNote',\n  title: 'Overlay/TooltipNote',\n  component: TooltipNote,\n  args: {},\n  decorators: [\n    (storyFn) => (\n      <ViewPort>\n        <TooltipProvider defaultVisible tooltip={storyFn()}>\n          <Button ariaLabel={false}>Show Tooltip</Button>\n        </TooltipProvider>\n      </ViewPort>\n    ),\n  ],\n});\n\nexport const Base = meta.story({\n  args: {\n    note: 'This is a note',\n  },\n});\n"
  },
  {
    "path": "code/core/src/components/components/tooltip/TooltipNote.tsx",
    "content": "import React from 'react';\n\nimport { styled } from 'storybook/theming';\n\nconst Note = styled.div(({ theme }) => ({\n  padding: '2px 6px',\n  lineHeight: '16px',\n  fontSize: 10,\n  fontWeight: theme.typography.weight.bold,\n  color: theme.color.lightest,\n  boxShadow: '0 0 5px 0 rgba(0, 0, 0, 0.3)',\n  borderRadius: 4,\n  whiteSpace: 'nowrap',\n  pointerEvents: 'none',\n  zIndex: -1,\n  background: theme.base === 'light' ? 'rgba(60, 60, 60, 0.9)' : 'rgba(0, 0, 0, 0.95)',\n}));\n\nexport interface TooltipNoteProps {\n  note: string;\n}\n\nexport const TooltipNote = ({ note, ...props }: TooltipNoteProps) => {\n  return <Note {...props}>{note}</Note>;\n};\n"
  },
  {
    "path": "code/core/src/components/components/tooltip/TooltipProvider.stories.tsx",
    "content": "import React from 'react';\n\nimport { Popover, TooltipNote } from 'storybook/internal/components';\n\nimport { expect, fn, screen } from 'storybook/test';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { OverlayTriggerDecorator, Trigger } from '../shared/overlayHelpers.tsx';\nimport { TooltipProvider } from './TooltipProvider.tsx';\n\nconst SampleTooltip = () => 'Lorem ipsum dolor sit';\nconst SampleTooltipNote = () => <TooltipNote note=\"This note appears on hover and focus\" />;\n\nconst meta = preview.meta({\n  id: 'overlay-TooltipProvider',\n  title: 'Overlay/TooltipProvider',\n  component: TooltipProvider,\n  args: {\n    triggerOnFocusOnly: false,\n    placement: 'top',\n    offset: 8,\n    delayShow: 400,\n    delayHide: 200,\n    tooltip: <SampleTooltipNote />,\n    children: <Trigger>Hover me!</Trigger>,\n  },\n  decorators: [OverlayTriggerDecorator],\n});\n\nexport const Base = meta.story({\n  args: {\n    tooltip: <SampleTooltipNote />,\n    children: <Trigger>Hover me!</Trigger>,\n  },\n});\n\nexport const FocusOnly = meta.story({\n  args: {\n    triggerOnFocusOnly: true,\n    tooltip: <SampleTooltipNote />,\n    children: <Trigger tabIndex={0}>Focus me!</Trigger>,\n  },\n});\n\nexport const Placements = meta.story({\n  args: {\n    children: <button>ignored</button>,\n    tooltip: 'ignored',\n  },\n  render: (args) => (\n    <div\n      style={{\n        display: 'grid',\n        gridTemplateColumns: 'repeat(3, 1fr)',\n        gap: '1rem',\n        padding: '2rem',\n      }}\n    >\n      <TooltipProvider {...args} placement=\"top\" tooltip=\"Top placement\">\n        <Trigger>Top</Trigger>\n      </TooltipProvider>\n      <TooltipProvider {...args} placement=\"top-start\" tooltip=\"Top start placement\">\n        <Trigger>Top Start</Trigger>\n      </TooltipProvider>\n      <TooltipProvider {...args} placement=\"top-end\" tooltip=\"Top end placement\">\n        <Trigger>Top End</Trigger>\n      </TooltipProvider>\n      <TooltipProvider {...args} placement=\"bottom\" tooltip=\"Bottom placement\">\n        <Trigger>Bottom</Trigger>\n      </TooltipProvider>\n      <TooltipProvider {...args} placement=\"bottom-start\" tooltip=\"Bottom start placement\">\n        <Trigger>Bottom Start</Trigger>\n      </TooltipProvider>\n      <TooltipProvider {...args} placement=\"bottom-end\" tooltip=\"Bottom end placement\">\n        <Trigger>Bottom End</Trigger>\n      </TooltipProvider>\n      <TooltipProvider {...args} placement=\"left\" tooltip=\"Left placement\">\n        <Trigger>Left</Trigger>\n      </TooltipProvider>\n      <TooltipProvider {...args} placement=\"left-start\" tooltip=\"Left start placement\">\n        <Trigger>Left Start</Trigger>\n      </TooltipProvider>\n      <TooltipProvider {...args} placement=\"left-end\" tooltip=\"Left end placement\">\n        <Trigger>Left End</Trigger>\n      </TooltipProvider>\n      <TooltipProvider {...args} placement=\"right\" tooltip=\"Right placement\">\n        <Trigger>Right</Trigger>\n      </TooltipProvider>\n      <TooltipProvider {...args} placement=\"right-start\" tooltip=\"Right start placement\">\n        <Trigger>Right Start</Trigger>\n      </TooltipProvider>\n      <TooltipProvider {...args} placement=\"right-end\" tooltip=\"Right end placement\">\n        <Trigger>Right End</Trigger>\n      </TooltipProvider>\n    </div>\n  ),\n});\n\n/** TooltipNote is the recommended Tooltip to use within Storybook. */\nexport const WithTooltipNote = meta.story({\n  args: {\n    tooltip: SampleTooltipNote(),\n    children: <Trigger>Hover me!</Trigger>,\n  },\n});\n\nexport const WithCustomTooltip = meta.story({\n  args: {\n    tooltip: (\n      <Popover hasChrome color=\"positive\" padding={8}>\n        This is a custom tooltip !\n      </Popover>\n    ),\n    children: <Trigger>Hover me!</Trigger>,\n  },\n});\n\nexport const WithLongContent = meta.story({\n  args: {\n    tooltip: (\n      <Popover style={{ maxWidth: 300 }} color=\"positive\" hasChrome padding={8}>\n        <h3 style={{ margin: '0 0 8px 0' }}>Very Long Tooltip Content</h3>\n        <p style={{ margin: '0', fontSize: '12px', lineHeight: '1.4' }}>\n          This is a very long tooltip that demonstrates how the tooltip component handles extensive\n          content. It should wrap properly and maintain good readability even with multiple lines of\n          text. The tooltip positioning should also adapt to ensure it remains visible within the\n          viewport boundaries.\n        </p>\n      </Popover>\n    ),\n    children: <Trigger>Long content</Trigger>,\n  },\n});\n\nexport const WithComplexContent = meta.story({\n  args: {\n    tooltip: (\n      <Popover style={{ maxWidth: 300 }} color=\"positive\" hasChrome padding={8}>\n        <h3 style={{ margin: '0 0 8px 0', fontSize: '14px' }}>Complex Tooltip</h3>\n        <p style={{ margin: '0 0 8px 0', fontSize: '12px' }}>\n          This tooltip contains multiple elements including:\n        </p>\n        <ul style={{ margin: '0', paddingLeft: '16px', fontSize: '12px' }}>\n          <li>Headings</li>\n          <li>Paragraphs</li>\n          <li>Lists</li>\n          <li>And more!</li>\n        </ul>\n      </Popover>\n    ),\n    children: <Trigger>Complex content</Trigger>,\n  },\n});\n\nexport const CustomOffset = meta.story({\n  args: {\n    offset: 20,\n    tooltip: <TooltipNote note=\"Tooltip with custom offset (20px)\" />,\n    children: <Trigger>Hover me!</Trigger>,\n  },\n});\n\nexport const CustomDelays = meta.story({\n  args: {\n    delayShow: 1000,\n    delayHide: 500,\n    tooltip: <TooltipNote note=\"Tooltip with custom delays (1000ms show, 500ms hide)\" />,\n    children: <Trigger>Hover me!</Trigger>,\n  },\n});\n\nexport const Instantaneous = meta.story({\n  args: {\n    delayShow: 0,\n    delayHide: 0,\n    tooltip: <TooltipNote note=\"Tooltip with no delays\" />,\n    children: <Trigger>Hover me!</Trigger>,\n  },\n});\n\nexport const AlwaysOpen = meta.story({\n  args: {\n    visible: true,\n    tooltip: <SampleTooltip />,\n    children: <Trigger>Always visible tooltip</Trigger>,\n    placement: 'right-start',\n  },\n  play: async () => {\n    await expect(await screen.findByText('Lorem ipsum dolor sit')).toBeInTheDocument();\n  },\n});\n\nexport const NeverOpen = meta.story({\n  args: {\n    visible: false,\n    tooltip: <SampleTooltip />,\n    children: <Trigger>Never visible tooltip</Trigger>,\n    placement: 'right-start',\n  },\n  play: async () => {\n    await expect(await screen.queryByText('Lorem ipsum dolor sit')).not.toBeInTheDocument();\n  },\n});\n\nexport const WithVisibilityCallback = meta.story({\n  args: {\n    onVisibleChange: fn(),\n    tooltip: <TooltipNote note=\"Tooltip with visibility callback\" />,\n    children: <Trigger>Hover me!</Trigger>,\n  },\n});\n"
  },
  {
    "path": "code/core/src/components/components/tooltip/TooltipProvider.tsx",
    "content": "import type { DOMAttributes, ReactElement, ReactNode } from 'react';\nimport React, { useCallback, useState } from 'react';\n\nimport { deprecate } from 'storybook/internal/client-logger';\n\nimport { Focusable } from '@react-aria/interactions';\nimport {\n  TooltipTrigger,\n  Tooltip as TooltipUpstream,\n} from 'react-aria-components/patched-dist/Tooltip';\n\nimport { type PopperPlacement, convertToReactAriaPlacement } from '../shared/overlayHelpers.tsx';\n\nexport interface TooltipProviderProps {\n  /** Tooltips trigger on hover and focus by default. To trigger on focus only, set this to `true`. */\n  triggerOnFocusOnly?: boolean;\n\n  /** Distance between the trigger and tooltip. Customize only if you have a good reason to. */\n  offset?: number;\n\n  /**\n   * Placement of the tooltip. Start and End variants involve additional JS dimension calculations\n   * and should be used sparingly. Left and Right get inverted in RTL.\n   */\n  placement?: PopperPlacement;\n\n  /** Tooltip content */\n  tooltip: ReactNode;\n\n  /** Tooltip trigger, must be a single child that can receive focus and click/key events. */\n  children: ReactElement<DOMAttributes<Element>, string>;\n\n  /** Delay before showing the tooltip, defaults to 200ms. Always instant on focus. */\n  delayShow?: number;\n\n  /** Delay before hiding the tooltip, defaults to 400ms. */\n  delayHide?: number;\n\n  /** Uncontrolled state: whether the tooltip is visible by default. */\n  defaultVisible?: boolean;\n\n  /** Deprecated property - use defaultVisible instead. */\n  startOpen?: boolean;\n\n  /** Controlled state: whether the tooltip is visible. */\n  visible?: boolean;\n\n  /** Controlled state: fires when user interaction causes the tooltip to change visibility. */\n  onVisibleChange?: (isVisible: boolean) => void;\n}\n\nconst TooltipProvider = ({\n  triggerOnFocusOnly = false,\n  placement: placementProp = 'top',\n  offset = 8,\n  tooltip,\n  children,\n  defaultVisible,\n  startOpen,\n  delayShow = 400,\n  delayHide = 200,\n  visible,\n  onVisibleChange,\n  ...props\n}: TooltipProviderProps) => {\n  const placement = convertToReactAriaPlacement(placementProp);\n  const child = React.Children.only(children);\n\n  if (startOpen !== undefined) {\n    deprecate('The `startOpen` prop is deprecated. Please use `defaultVisible` instead.');\n  }\n\n  const [isOpen, setIsOpen] = useState(defaultVisible ?? startOpen ?? false);\n  const onOpenChange = useCallback(\n    (isOpen: boolean) => {\n      setIsOpen(isOpen);\n      onVisibleChange?.(isOpen);\n    },\n    [onVisibleChange]\n  );\n\n  return (\n    <TooltipTrigger\n      delay={delayShow}\n      closeDelay={delayHide}\n      isOpen={visible ?? isOpen}\n      onOpenChange={onOpenChange}\n      trigger={triggerOnFocusOnly ? 'focus' : undefined}\n      {...props}\n    >\n      {/* We don't let react-aria set an aria-describedby attribute because it clashes with our intention to explicitly set an aria-label that can be different from the tooltip copy. Some screenreaders would announce the label AND description if we also allowed aria-describedby, which would decrease usability. */}\n      {/* @ts-expect-error: We have to nullify aria-describedby and this is the only way we can do it (undefined won't work and an empty string will result in DOM pollution). */}\n      <Focusable>{React.cloneElement(child, { 'aria-describedby': null })}</Focusable>\n      <TooltipUpstream\n        data-testid=\"tooltip\"\n        placement={placement}\n        offset={offset}\n        onOpenChange={onOpenChange}\n        style={{ outline: 'none' }}\n        {...props}\n      >\n        {tooltip}\n      </TooltipUpstream>\n    </TooltipTrigger>\n  );\n};\n\nexport { TooltipProvider };\n"
  },
  {
    "path": "code/core/src/components/components/tooltip/WithTooltip.stories.tsx",
    "content": "import type { ComponentProps, FunctionComponent } from 'react';\nimport React from 'react';\n\nimport type { StoryObj } from '@storybook/react-vite';\n\nimport { expect, screen } from 'storybook/test';\nimport { styled } from 'storybook/theming';\n\nimport { TooltipMessage } from './TooltipMessage.tsx';\nimport { WithToolTipState as WithTooltip } from './WithTooltip.tsx';\n\nconst ViewPort = styled.div({\n  height: 300,\n});\n\nconst BackgroundBox = styled.div({\n  width: 500,\n  height: 500,\n  overflowY: 'scroll',\n  background: '#eee',\n  position: 'relative',\n});\n\nconst Spacer = styled.div({\n  height: 100,\n});\n\nconst Trigger = styled.div({\n  width: 200,\n  height: 100,\n  backgroundColor: 'red',\n  color: 'white',\n});\n\ninterface TooltipProps {\n  onHide?: () => void;\n}\n\nconst Tooltip: FunctionComponent<TooltipProps> = ({ onHide }) => (\n  <TooltipMessage\n    title=\"Lorem ipsum dolor sit\"\n    desc=\"Amet consectatur vestibulum concet durum politu coret weirom\"\n    links={[\n      {\n        title: 'Continue',\n        onClick: onHide,\n      },\n    ]}\n  />\n);\n\nexport default {\n  component: WithTooltip,\n  decorators: [\n    (storyFn: any) => (\n      <ViewPort>\n        <BackgroundBox>\n          <Spacer />\n          {storyFn()}\n        </BackgroundBox>\n      </ViewPort>\n    ),\n  ],\n};\n\nexport const SimpleHover: StoryObj<ComponentProps<typeof WithTooltip>> = {\n  args: {\n    placement: 'top',\n    trigger: 'hover',\n  },\n  render: (args) => (\n    <WithTooltip {...args} tooltip={<Tooltip />}>\n      <Trigger>Hover me!</Trigger>\n    </WithTooltip>\n  ),\n};\n\nexport const SimpleHoverFunctional: StoryObj<ComponentProps<typeof WithTooltip>> = {\n  args: {\n    placement: 'top',\n    trigger: 'hover',\n  },\n  render: (args) => (\n    <WithTooltip {...args} tooltip={Tooltip}>\n      <Trigger>Hover me!</Trigger>\n    </WithTooltip>\n  ),\n};\n\nexport const SimpleClick: StoryObj<ComponentProps<typeof WithTooltip>> = {\n  args: {\n    placement: 'top',\n  },\n  render: (args) => (\n    <WithTooltip {...args} tooltip={<Tooltip />}>\n      <Trigger>Click me!</Trigger>\n    </WithTooltip>\n  ),\n};\n\nexport const SimpleClickStartOpen: StoryObj<ComponentProps<typeof WithTooltip>> = {\n  args: {\n    placement: 'top',\n    startOpen: true,\n  },\n  render: (args) => (\n    <WithTooltip {...args} tooltip={<Tooltip />}>\n      <Trigger>Click me!</Trigger>\n    </WithTooltip>\n  ),\n  play: async () => {\n    await expect(await screen.findByText('Lorem ipsum dolor sit')).toBeInTheDocument();\n  },\n};\n\nexport const SimpleClickCloseOnClick: StoryObj<ComponentProps<typeof WithTooltip>> = {\n  args: {\n    placement: 'top',\n    closeOnOutsideClick: true,\n  },\n  render: (args) => (\n    <WithTooltip {...args} tooltip={<Tooltip />}>\n      <Trigger>Click me!</Trigger>\n    </WithTooltip>\n  ),\n};\n\nexport const WithoutChrome: StoryObj<ComponentProps<typeof WithTooltip>> = {\n  args: {\n    placement: 'top',\n    hasChrome: false,\n  },\n  render: (args) => (\n    <WithTooltip {...args} tooltip={<Tooltip />}>\n      <Trigger>Click me!</Trigger>\n    </WithTooltip>\n  ),\n};\n"
  },
  {
    "path": "code/core/src/components/components/tooltip/WithTooltip.tsx",
    "content": "import type { ComponentProps, FC, ReactNode } from 'react';\nimport React, { useCallback, useEffect, useState } from 'react';\nimport ReactDOM from 'react-dom';\n\nimport { deprecate } from 'storybook/internal/client-logger';\n\nimport { global } from '@storybook/global';\n\nimport memoize from 'memoizerific';\nimport type { PopperOptions, Config as ReactPopperTooltipConfig } from 'react-popper-tooltip';\nimport { usePopperTooltip } from 'react-popper-tooltip';\nimport { type Color, lighten, styled } from 'storybook/theming';\n\nconst { document } = global;\n\nconst match = memoize(1000)((requests, actual, value, fallback = 0) =>\n  actual.split('-')[0] === requests ? value : fallback\n);\n\nconst ArrowSpacing = 8;\n\nexport interface ArrowProps {\n  color: keyof Color;\n  placement: string;\n}\n\nconst Arrow = styled.div<ArrowProps>(\n  {\n    position: 'absolute',\n    borderStyle: 'solid',\n  },\n  ({ placement }) => {\n    let x = 0;\n    let y = 0;\n\n    switch (true) {\n      case placement.startsWith('left') || placement.startsWith('right'): {\n        y = 8;\n        break;\n      }\n      case placement.startsWith('top') || placement.startsWith('bottom'): {\n        x = 8;\n        break;\n      }\n      default: {\n        //\n      }\n    }\n\n    const transform = `translate3d(${x}px, ${y}px, 0px)`;\n    return { transform };\n  },\n  ({ theme, color, placement }) => ({\n    bottom: `${match('top', placement, `${ArrowSpacing * -1}px`, 'auto')}`,\n    top: `${match('bottom', placement, `${ArrowSpacing * -1}px`, 'auto')}`,\n    right: `${match('left', placement, `${ArrowSpacing * -1}px`, 'auto')}`,\n    left: `${match('right', placement, `${ArrowSpacing * -1}px`, 'auto')}`,\n\n    borderBottomWidth: `${match('top', placement, '0', ArrowSpacing)}px`,\n    borderTopWidth: `${match('bottom', placement, '0', ArrowSpacing)}px`,\n    borderRightWidth: `${match('left', placement, '0', ArrowSpacing)}px`,\n    borderLeftWidth: `${match('right', placement, '0', ArrowSpacing)}px`,\n\n    borderTopColor: match(\n      'top',\n      placement,\n      theme.color[color] || color || theme.base === 'light'\n        ? lighten(theme.background.app)\n        : theme.background.app,\n      'transparent'\n    ),\n    borderBottomColor: match(\n      'bottom',\n      placement,\n      theme.color[color] || color || theme.base === 'light'\n        ? lighten(theme.background.app)\n        : theme.background.app,\n      'transparent'\n    ),\n    borderLeftColor: match(\n      'left',\n      placement,\n      theme.color[color] || color || theme.base === 'light'\n        ? lighten(theme.background.app)\n        : theme.background.app,\n      'transparent'\n    ),\n    borderRightColor: match(\n      'right',\n      placement,\n      theme.color[color] || color || theme.base === 'light'\n        ? lighten(theme.background.app)\n        : theme.background.app,\n      'transparent'\n    ),\n  })\n);\n\nexport interface WrapperProps {\n  color: keyof Color | undefined;\n  hidden?: boolean;\n  hasChrome: boolean;\n}\n\nconst Wrapper = styled.div<WrapperProps>(\n  ({ hidden }) => ({\n    display: hidden ? 'none' : 'inline-block',\n    zIndex: 2147483647,\n    colorScheme: 'light dark',\n  }),\n  ({ theme, color, hasChrome }) =>\n    hasChrome\n      ? {\n          background:\n            (color && theme.color[color]) || color || theme.base === 'light'\n              ? lighten(theme.background.app)\n              : theme.background.app,\n          filter: `\n            drop-shadow(0px 5px 5px rgba(0,0,0,0.05))\n            drop-shadow(0 1px 3px rgba(0,0,0,0.1))\n          `,\n          borderRadius: theme.appBorderRadius + 2,\n          fontSize: theme.typography.size.s1,\n        }\n      : {}\n);\n\nexport interface TooltipProps {\n  children?: React.ReactNode;\n  tooltipRef?: any;\n  hasChrome?: boolean;\n  arrowProps?: any;\n  placement?: string;\n  color?: keyof Color;\n  withArrows?: boolean;\n}\n\nexport const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>(\n  (\n    {\n      placement = 'top',\n      hasChrome = true,\n      children,\n      arrowProps = {},\n      tooltipRef,\n      color,\n      withArrows,\n      ...props\n    },\n    ref\n  ) => {\n    return (\n      <Wrapper data-testid=\"tooltip\" hasChrome={hasChrome} ref={ref} {...props} color={color}>\n        {hasChrome && withArrows && <Arrow placement={placement} {...arrowProps} color={color} />}\n        {children}\n      </Wrapper>\n    );\n  }\n);\n\nTooltip.displayName = 'Tooltip';\n\n// A target that doesn't speak popper\nconst TargetContainer = styled.div<{ trigger: ReactPopperTooltipConfig['trigger'] }>`\n  display: inline-block;\n  cursor: ${(props) =>\n    props.trigger === 'hover' || props.trigger?.includes('hover') ? 'default' : 'pointer'};\n`;\n\nconst TargetSvgContainer = styled.g<{ trigger: ReactPopperTooltipConfig['trigger'] }>`\n  cursor: ${(props) =>\n    props.trigger === 'hover' || props.trigger?.includes('hover') ? 'default' : 'pointer'};\n`;\n\ninterface WithHideFn {\n  onHide: () => void;\n}\n\nexport interface WithTooltipPureProps\n  extends\n    Omit<ReactPopperTooltipConfig, 'closeOnOutsideClick'>,\n    Omit<ComponentProps<typeof TargetContainer>, 'trigger'>,\n    PopperOptions {\n  svg?: boolean;\n  withArrows?: boolean;\n  hasChrome?: boolean;\n  tooltip: ReactNode | ((p: WithHideFn) => ReactNode);\n  children: ReactNode;\n  onDoubleClick?: () => void;\n  /**\n   * If `true`, a click outside the trigger element closes the tooltip\n   *\n   * @default false\n   */\n  closeOnOutsideClick?: boolean;\n  /**\n   * Optional container to portal the tooltip into. Can be a CSS selector string or a DOM Element.\n   * Falls back to document.body.\n   */\n  portalContainer?: Element | string | null;\n}\n\n// Pure, does not bind to the body\nconst WithTooltipPure = ({\n  svg = false,\n  trigger = 'click',\n  closeOnOutsideClick = false,\n  placement = 'top',\n  modifiers = [\n    {\n      name: 'preventOverflow',\n      options: {\n        padding: 8,\n      },\n    },\n    {\n      name: 'offset',\n      options: {\n        offset: [8, 8],\n      },\n    },\n    {\n      name: 'arrow',\n      options: {\n        padding: 8,\n      },\n    },\n  ],\n  hasChrome = true,\n  defaultVisible = false,\n  withArrows,\n  offset,\n  tooltip,\n  children,\n  closeOnTriggerHidden,\n  mutationObserverOptions,\n  delayHide = trigger === 'hover' ? 200 : 0,\n  visible,\n  interactive,\n  delayShow = trigger === 'hover' ? 400 : 0,\n  strategy,\n  followCursor,\n  onVisibleChange,\n  portalContainer,\n  ...props\n}: WithTooltipPureProps) => {\n  const Container = svg ? TargetSvgContainer : TargetContainer;\n  const {\n    getArrowProps,\n    getTooltipProps,\n    setTooltipRef,\n    setTriggerRef,\n    visible: isVisible,\n    state,\n  } = usePopperTooltip(\n    {\n      trigger,\n      placement,\n      defaultVisible,\n      delayHide,\n      interactive,\n      closeOnOutsideClick,\n      closeOnTriggerHidden,\n      onVisibleChange,\n      delayShow,\n      followCursor,\n      mutationObserverOptions,\n      visible,\n      offset,\n    },\n    {\n      modifiers,\n      strategy,\n    }\n  );\n\n  const portalTarget: Element =\n    (typeof portalContainer === 'string'\n      ? document.querySelector(portalContainer)\n      : portalContainer) || document.body;\n\n  const tooltipComponent = isVisible ? (\n    <Tooltip\n      placement={state?.placement}\n      ref={setTooltipRef}\n      hasChrome={hasChrome}\n      arrowProps={getArrowProps()}\n      withArrows={withArrows}\n      {...getTooltipProps()}\n    >\n      {/* @ts-expect-error (non strict) */}\n      {typeof tooltip === 'function' ? tooltip({ onHide: () => onVisibleChange(false) }) : tooltip}\n    </Tooltip>\n  ) : null;\n\n  return (\n    <>\n      <Container trigger={trigger} ref={setTriggerRef as any} {...(props as any)}>\n        {children}\n      </Container>\n      {isVisible && ReactDOM.createPortal(tooltipComponent, portalTarget)}\n    </>\n  );\n};\n\nexport interface WithTooltipStateProps extends Omit<WithTooltipPureProps, 'onVisibleChange'> {\n  startOpen?: boolean;\n  onVisibleChange?: (visible: boolean) => void | boolean;\n}\n\nconst WithToolTipState = ({\n  startOpen = false,\n  onVisibleChange: onChange,\n  ...rest\n}: WithTooltipStateProps) => {\n  const [tooltipShown, setTooltipShown] = useState(startOpen);\n  const onVisibilityChange = useCallback(\n    (visibility: boolean) => {\n      if (onChange && onChange(visibility) === false) {\n        return;\n      }\n      setTooltipShown(visibility);\n    },\n    [onChange]\n  );\n\n  useEffect(() => {\n    const hide = () => onVisibilityChange(false);\n    const handleKeyDown = (e: KeyboardEvent) => {\n      if (e.key === 'Escape') {\n        hide();\n      }\n    };\n    document.addEventListener('keydown', handleKeyDown, false);\n\n    // Find all iframes on the screen and bind to clicks inside them (waiting until the iframe is ready)\n    const iframes: HTMLIFrameElement[] = Array.from(document.getElementsByTagName('iframe'));\n    const unbinders: (() => void)[] = [];\n    iframes.forEach((iframe) => {\n      const bind = () => {\n        try {\n          // @ts-expect-error (non strict)\n          if (iframe.contentWindow.document) {\n            // @ts-expect-error (non strict)\n            iframe.contentWindow.document.addEventListener('click', hide);\n            unbinders.push(() => {\n              try {\n                // @ts-expect-error (non strict)\n                iframe.contentWindow.document.removeEventListener('click', hide);\n              } catch (e) {\n                // logger.debug('Removing a click listener from iframe failed: ', e);\n              }\n            });\n          }\n        } catch (e) {\n          // logger.debug('Adding a click listener to iframe failed: ', e);\n        }\n      };\n\n      bind(); // I don't know how to find out if it's already loaded so I potentially will bind twice\n      iframe.addEventListener('load', bind);\n      unbinders.push(() => {\n        iframe.removeEventListener('load', bind);\n      });\n    });\n\n    return () => {\n      document.removeEventListener('keydown', handleKeyDown);\n      unbinders.forEach((unbind) => {\n        unbind();\n      });\n    };\n  });\n\n  return <WithTooltipPure {...rest} visible={tooltipShown} onVisibleChange={onVisibilityChange} />;\n};\n\nconst DeprecatedPure: FC<WithTooltipPureProps> = (props: WithTooltipPureProps) => {\n  deprecate(\n    'WithTooltipPure is deprecated and will be removed in Storybook 11. Please use WithTooltip instead.'\n  );\n  return <WithTooltipPure data-deprecated=\"WithTooltipPure\" {...props} />;\n};\n\nconst DeprecatedState: FC<WithTooltipStateProps> = (props: WithTooltipStateProps) => {\n  deprecate(\n    'WithToolTipState is deprecated and will be removed in Storybook 11. Please use WithTooltip instead.'\n  );\n  return <WithToolTipState data-deprecated=\"WithToolTipState\" {...props} />;\n};\n\nexport {\n  DeprecatedPure as WithTooltipPure,\n  DeprecatedState as WithToolTipState,\n  WithToolTipState as WithTooltip,\n};\n"
  },
  {
    "path": "code/core/src/components/components/tooltip/lazy-WithTooltip.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React, { Suspense, lazy } from 'react';\n\nconst LazyWithTooltip = lazy(() =>\n  import('./WithTooltip.tsx').then((mod) => ({ default: mod.WithTooltip }))\n);\n\nexport const WithTooltip = (props: ComponentProps<typeof LazyWithTooltip>) => (\n  <Suspense fallback={<div />}>\n    <LazyWithTooltip {...props} />\n  </Suspense>\n);\n\nconst LazyWithTooltipPure = lazy(() =>\n  import('./WithTooltip.tsx').then((mod) => ({ default: mod.WithTooltipPure }))\n);\n\nexport const WithTooltipPure = (props: ComponentProps<typeof LazyWithTooltipPure>) => (\n  <Suspense fallback={<div />}>\n    <LazyWithTooltipPure {...props} />\n  </Suspense>\n);\n"
  },
  {
    "path": "code/core/src/components/components/typography/DocumentFormatting.tsx",
    "content": "export const nameSpaceClassNames = ({ ...props }, key: string) => {\n  const classes = [props.class, props.className];\n\n  delete props.class;\n\n  props.className = ['sbdocs', `sbdocs-${key}`, ...classes].filter(Boolean).join(' ');\n\n  return props;\n};\n"
  },
  {
    "path": "code/core/src/components/components/typography/DocumentWrapper.stories.tsx",
    "content": "import React from 'react';\n\nimport { DocumentWrapper } from './DocumentWrapper.tsx';\n\nexport default {\n  component: DocumentWrapper,\n  decorators: [(storyFn: any) => <div style={{ width: '600px' }}>{storyFn()}</div>],\n};\n\nexport const WithDOM = () => (\n  <DocumentWrapper>\n    <h1>h1 Heading</h1>\n    <h2>h2 Heading</h2>\n    <h3>h3 Heading</h3>\n    <h4>h4 Heading</h4>\n    <h5>h5 Heading</h5>\n    <h6>h6 Heading</h6>\n    <h2>Typographic replacements</h2>\n    <p>Enable typographer option to see result.</p>\n    <p>© © ® ® ™ ™ § § ±</p>\n    <p>test… test… test… test?.. test!..</p>\n    <p>!!! ??? , – —</p>\n    <p>“Smartypants, double quotes” and ‘single quotes’</p>\n    <h2>Emphasis</h2>\n    <p>\n      <strong>This is bold text</strong>\n    </p>\n    <p>\n      <strong>This is bold text</strong>\n    </p>\n    <p>\n      <em>This is italic text</em>\n    </p>\n    <p>\n      <em>This is italic text</em>\n    </p>\n    <p>\n      <em>\n        <strong>This is bold italic text</strong>\n      </em>\n    </p>\n    <p>\n      <s>Strikethrough</s>\n    </p>\n    <h2>Blockquotes</h2>\n    <blockquote>\n      <p>Blockquotes can also be nested…</p>\n      <blockquote>\n        <p>…by using additional greater-than signs right next to each other…</p>\n        <blockquote>\n          <p>…or with spaces between arrows.</p>\n        </blockquote>\n      </blockquote>\n    </blockquote>\n    <h2>Lists</h2>\n    <p>Unordered</p>\n    <ul>\n      <li>\n        Create a list by starting a line with <code>+</code>, <code>-</code>, or <code>*</code>\n      </li>\n      <li>\n        Sub-lists are made by indenting 2 spaces:\n        <ul>\n          <li>\n            Marker character change forces new list start:\n            <ul>\n              <li>Ac tristique libero volutpat at</li>\n            </ul>\n            <ul>\n              <li>Facilisis in pretium nisl aliquet</li>\n            </ul>\n            <ul>\n              <li>Nulla volutpat aliquam velit</li>\n            </ul>\n          </li>\n        </ul>\n      </li>\n      <li>Very easy!</li>\n    </ul>\n    <p>Ordered</p>\n    <ol>\n      <li>\n        <p>Lorem ipsum dolor sit amet</p>\n      </li>\n      <li>\n        <p>Consectetur adipiscing elit</p>\n      </li>\n      <li>\n        <p>Integer molestie lorem at massa</p>\n      </li>\n      <li>\n        <p>You can use sequential numbers…</p>\n      </li>\n      <li>\n        <p>\n          …or keep all the numbers as <code>1.</code>\n        </p>\n      </li>\n    </ol>\n    <p>Start numbering with offset:</p>\n    <ol start={57}>\n      <li>foo</li>\n      <li>bar</li>\n    </ol>\n    <h2>Horizontal Rule</h2>\n    <hr />\n    <h2>Tables</h2>\n    <table>\n      <thead>\n        <tr>\n          <th>Option</th>\n          <th>Description</th>\n        </tr>\n      </thead>\n      <tbody>\n        <tr>\n          <td>data</td>\n          <td>path to data files to supply the data that will be passed into templates.</td>\n        </tr>\n        <tr>\n          <td>engine</td>\n          <td>engine to be used for processing templates. Handlebars is the default.</td>\n        </tr>\n        <tr>\n          <td>ext</td>\n          <td>extension to be used for dest files.</td>\n        </tr>\n      </tbody>\n    </table>\n    <p>Right aligned columns</p>\n    <table>\n      <thead>\n        <tr>\n          <th style={{ textAlign: 'right' }}>Option</th>\n          <th style={{ textAlign: 'right' }}>Description</th>\n        </tr>\n      </thead>\n      <tbody>\n        <tr>\n          <td style={{ textAlign: 'right' }}>data</td>\n          <td style={{ textAlign: 'right' }}>\n            path to data files to supply the data that will be passed into templates.\n          </td>\n        </tr>\n        <tr>\n          <td style={{ textAlign: 'right' }}>engine</td>\n          <td style={{ textAlign: 'right' }}>\n            engine to be used for processing templates. Handlebars is the default.\n          </td>\n        </tr>\n        <tr>\n          <td style={{ textAlign: 'right' }}>ext</td>\n          <td style={{ textAlign: 'right' }}>extension to be used for dest files.</td>\n        </tr>\n      </tbody>\n    </table>\n    <h2>Links</h2>\n    <p>\n      <a href=\"http://dev.nodeca.com\">link text</a>\n    </p>\n    <p>\n      <a href=\"http://nodeca.github.io/pica/demo/\" title=\"title text!\">\n        link with title\n      </a>\n    </p>\n    <p>\n      Autoconverted link <a href=\"https://github.com/nodeca/pica\">https://github.com/nodeca/pica</a>\n      &nbsp;(enable linkify to see)\n    </p>\n    <h2>Inline Code Inside Links</h2>\n    <p>\n      Check out{' '}\n      <a href=\"https://example.com\">\n        <code>inline-code</code>\n      </a>{' '}\n      inside a link.\n    </p>\n    <p>\n      Visit the{' '}\n      <a href=\"https://example.com\">\n        <code>@storybook/addon-essentials</code>\n      </a>{' '}\n      package for more details.\n    </p>\n    <p>\n      Mixed link:{' '}\n      <a href=\"https://example.com\">\n        regular text and <code>code text</code> together\n      </a>\n      .\n    </p>\n    <p>\n      For comparison, here is regular <code>inline-code</code> outside a link.\n    </p>\n    <p>\n      And a <a href=\"https://example.com\">regular link without code</a>.\n    </p>\n    <h2>Images</h2>\n    <p>\n      <img src=\"https://octodex.github.com/images/minion.png\" alt=\"Minion\" />\n      <img\n        src=\"https://octodex.github.com/images/stormtroopocat.jpg\"\n        alt=\"Stormtroopocat\"\n        title=\"The Stormtroopocat\"\n      />\n    </p>\n  </DocumentWrapper>\n);\n"
  },
  {
    "path": "code/core/src/components/components/typography/DocumentWrapper.test.tsx",
    "content": "// @vitest-environment happy-dom\nimport { cleanup, render } from '@testing-library/react';\nimport { afterEach, describe, expect, it } from 'vitest';\n\nimport React from 'react';\n\nimport { ThemeProvider, convert, themes } from 'storybook/theming';\n\nimport { DocumentWrapper } from './DocumentWrapper.tsx';\n\nfunction ThemedDocumentWrapper({ children }: { children: React.ReactNode }) {\n  return (\n    <ThemeProvider theme={convert(themes.light)}>\n      <DocumentWrapper>{children}</DocumentWrapper>\n    </ThemeProvider>\n  );\n}\n\ndescribe('DocumentWrapper', () => {\n  afterEach(() => {\n    cleanup();\n  });\n\n  describe('accessibility', () => {\n    it('should render links with underline text decoration for accessibility', () => {\n      const { container } = render(\n        <ThemedDocumentWrapper>\n          <p>\n            This is a paragraph with a <a href=\"https://example.com\">link</a> inside.\n          </p>\n        </ThemedDocumentWrapper>\n      );\n\n      const link = container.querySelector('a');\n      expect(link).toBeTruthy();\n\n      const styles = window.getComputedStyle(link!);\n      expect(styles.textDecoration).toContain('underline');\n    });\n\n    it('should render links with underline in dark theme', () => {\n      const { container } = render(\n        <ThemeProvider theme={convert(themes.dark)}>\n          <DocumentWrapper>\n            <p>\n              This is a paragraph with a <a href=\"https://example.com\">link</a> inside.\n            </p>\n          </DocumentWrapper>\n        </ThemeProvider>\n      );\n\n      const link = container.querySelector('a');\n      expect(link).toBeTruthy();\n\n      const styles = window.getComputedStyle(link!);\n      expect(styles.textDecoration).toContain('underline');\n    });\n\n    it('should render multiple links with underlines in text blocks', () => {\n      const { container } = render(\n        <ThemedDocumentWrapper>\n          <div>\n            <p>\n              Check out <a href=\"https://example.com\">this link</a> and also{' '}\n              <a href=\"https://another.com\">this other link</a>.\n            </p>\n            <p>\n              Here is <a href=\"https://third.com\">a third link</a> in another paragraph.\n            </p>\n          </div>\n        </ThemedDocumentWrapper>\n      );\n\n      const links = container.querySelectorAll('a');\n      expect(links).toHaveLength(3);\n\n      links.forEach((link) => {\n        const styles = window.getComputedStyle(link);\n        expect(styles.textDecoration).toContain('underline');\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/components/components/typography/DocumentWrapper.tsx",
    "content": "import { styled } from 'storybook/theming';\n\nexport const DocumentWrapper = styled.div(({ theme }) => ({\n  fontSize: `${theme.typography.size.s2}px`,\n  lineHeight: '1.6',\n\n  h1: {\n    fontSize: `${theme.typography.size.l1}px`,\n    fontWeight: theme.typography.weight.bold,\n  },\n  h2: {\n    fontSize: `${theme.typography.size.m2}px`,\n    borderBottom: `1px solid ${theme.appBorderColor}`,\n  },\n  h3: {\n    fontSize: `${theme.typography.size.m1}px`,\n  },\n  h4: {\n    fontSize: `${theme.typography.size.s3}px`,\n  },\n  h5: {\n    fontSize: `${theme.typography.size.s2}px`,\n  },\n  h6: {\n    fontSize: `${theme.typography.size.s2}px`,\n    color: theme.color.dark,\n  },\n  'pre:not(.prismjs)': {\n    background: 'transparent',\n    border: 'none',\n    borderRadius: 0,\n    padding: 0,\n    margin: 0,\n  },\n  'pre pre, pre.prismjs': {\n    padding: 15,\n    margin: 0,\n    whiteSpace: 'pre-wrap',\n    color: 'inherit',\n    fontSize: '13px',\n    lineHeight: '19px',\n  },\n  'pre pre code, pre.prismjs code': {\n    color: 'inherit',\n    fontSize: 'inherit',\n  },\n  'pre code': {\n    margin: 0,\n    padding: 0,\n    whiteSpace: 'pre',\n    border: 'none',\n    background: 'transparent',\n  },\n  'pre code, pre tt': {\n    backgroundColor: 'transparent',\n    border: 'none',\n  },\n  /* GitHub inspired Markdown styles loosely from https://gist.github.com/tuzz/3331384 */\n  'body > *:first-of-type': {\n    marginTop: '0 !important',\n  },\n  'body > *:last-child': {\n    marginBottom: '0 !important',\n  },\n  a: {\n    color: theme.color.secondary,\n    // Ensure WCAG Level A compliance (SC 1.4.1), see https://www.w3.org/WAI/WCAG22/Techniques/failures/F73\n    textDecoration: 'underline',\n    textDecorationThickness: '0.03125rem',\n    textUnderlineOffset: '0.11em',\n\n    '& code': {\n      color: 'inherit',\n      textDecoration: 'underline',\n      textDecorationThickness: '0.03125rem',\n      paddingLeft: 0,\n      paddingRight: 0,\n      '&::before': {\n        content: '\"\\\\00a0\"',\n        fontSize: '0.5em',\n      },\n      '&::after': {\n        content: '\"\\\\00a0\"',\n        fontSize: '0.5em',\n      },\n    },\n  },\n  'a.absent': {\n    color: '#cc0000',\n  },\n  'a.anchor': {\n    display: 'block',\n    paddingLeft: 30,\n    marginLeft: -30,\n    cursor: 'pointer',\n    position: 'absolute',\n    top: 0,\n    left: 0,\n    bottom: 0,\n    textDecoration: 'none',\n  },\n  '&.anchor:hover, &.anchor:focus': {\n    textDecoration: 'underline',\n  },\n  'h1, h2, h3, h4, h5, h6': {\n    margin: '20px 0 10px',\n    padding: 0,\n    cursor: 'text',\n    position: 'relative',\n\n    '&:first-of-type': {\n      marginTop: 0,\n      paddingTop: 0,\n    },\n    '&:hover a.anchor': {\n      textDecoration: 'none',\n    },\n    '& tt, & code': {\n      fontSize: 'inherit',\n    },\n  },\n  'h1:first-of-type + h2': {\n    marginTop: 0,\n    paddingTop: 0,\n  },\n  'p, blockquote, ul, ol, dl, li, table, pre': {\n    margin: '15px 0',\n  },\n  hr: {\n    border: '0 none',\n    borderTop: `1px solid ${theme.appBorderColor}`,\n    height: 4,\n    padding: 0,\n  },\n  'body > h1:first-of-type, body > h2:first-of-type, body > h3:first-of-type, body > h4:first-of-type, body > h5:first-of-type, body > h6:first-of-type':\n    {\n      marginTop: 0,\n      paddingTop: 0,\n    },\n  'body > h1:first-of-type + h2': {\n    marginTop: 0,\n    paddingTop: 0,\n  },\n  'a:first-of-type h1, a:first-of-type h2, a:first-of-type h3, a:first-of-type h4, a:first-of-type h5, a:first-of-type h6':\n    {\n      marginTop: 0,\n      paddingTop: 0,\n    },\n  'h1 p, h2 p, h3 p, h4 p, h5 p, h6 p': {\n    marginTop: 0,\n  },\n  'li p.first': {\n    display: 'inline-block',\n  },\n  'ul, ol': {\n    paddingLeft: 30,\n\n    '& :first-of-type': {\n      marginTop: 0,\n    },\n    '& :last-child': {\n      marginBottom: 0,\n    },\n  },\n  dl: {\n    padding: 0,\n  },\n\n  'dl dt': {\n    fontSize: '14px',\n    fontWeight: 'bold',\n    fontStyle: 'italic',\n    margin: '0 0 15px',\n    padding: '0 15px',\n\n    '&:first-of-type': {\n      padding: 0,\n    },\n    '& > :first-of-type': {\n      marginTop: 0,\n    },\n    '& > :last-child': {\n      marginBottom: 0,\n    },\n  },\n\n  blockquote: {\n    borderLeft: `4px solid ${theme.color.medium}`,\n    padding: '0 15px',\n    color: theme.color.dark,\n\n    '& > :first-of-type': {\n      marginTop: 0,\n    },\n\n    '& > :last-child': {\n      marginBottom: 0,\n    },\n  },\n\n  table: {\n    padding: 0,\n    borderCollapse: 'collapse',\n\n    '& tr': {\n      borderTop: `1px solid ${theme.appBorderColor}`,\n      backgroundColor: 'white',\n      margin: 0,\n      padding: 0,\n\n      '& th': {\n        fontWeight: 'bold',\n        border: `1px solid ${theme.appBorderColor}`,\n        textAlign: 'left',\n        margin: 0,\n        padding: '6px 13px',\n      },\n\n      '& td': {\n        border: `1px solid ${theme.appBorderColor}`,\n        textAlign: 'left',\n        margin: 0,\n        padding: '6px 13px',\n      },\n      '&:nth-of-type(2n)': {\n        backgroundColor: theme.color.lighter,\n      },\n\n      '& th :first-of-type, & td :first-of-type': {\n        marginTop: 0,\n      },\n      '& th :last-child, & td :last-child': {\n        marginBottom: 0,\n      },\n    },\n  },\n  img: {\n    maxWidth: '100%',\n  },\n  'span.frame': {\n    display: 'block',\n    overflow: 'hidden',\n\n    '& > span': {\n      border: `1px solid ${theme.color.medium}`,\n      display: 'block',\n      float: 'left',\n      overflow: 'hidden',\n      margin: '13px 0 0',\n      padding: 7,\n      width: 'auto',\n    },\n\n    '& span img': {\n      display: 'block',\n      float: 'left',\n    },\n\n    '& span span': {\n      clear: 'both',\n      color: theme.color.darkest,\n      display: 'block',\n      padding: '5px 0 0',\n    },\n  },\n  'span.align-center': {\n    display: 'block',\n    overflow: 'hidden',\n    clear: 'both',\n\n    '& > span': {\n      display: 'block',\n      overflow: 'hidden',\n      margin: '13px auto 0',\n      textAlign: 'center',\n    },\n    '& span img': {\n      margin: '0 auto',\n      textAlign: 'center',\n    },\n  },\n  'span.align-right': {\n    display: 'block',\n    overflow: 'hidden',\n    clear: 'both',\n\n    '& > span': {\n      display: 'block',\n      overflow: 'hidden',\n      margin: '13px 0 0',\n      textAlign: 'right',\n    },\n\n    '& span img': {\n      margin: 0,\n      textAlign: 'right',\n    },\n  },\n\n  'span.float-left': {\n    display: 'block',\n    marginRight: 13,\n    overflow: 'hidden',\n    float: 'left',\n\n    '& span': {\n      margin: '13px 0 0',\n    },\n  },\n\n  'span.float-right': {\n    display: 'block',\n    marginLeft: 13,\n    overflow: 'hidden',\n    float: 'right',\n\n    '& > span': {\n      display: 'block',\n      overflow: 'hidden',\n      margin: '13px auto 0',\n      textAlign: 'right',\n    },\n  },\n  'code, tt': {\n    margin: '0 2px',\n    padding: '0 5px',\n    whiteSpace: 'nowrap',\n    border: `1px solid ${theme.color.mediumlight}`,\n    backgroundColor: theme.color.lighter,\n    borderRadius: 3,\n    color: theme.base === 'dark' ? theme.color.darkest : theme.color.dark,\n  },\n}));\n"
  },
  {
    "path": "code/core/src/components/components/typography/ResetWrapper.tsx",
    "content": "import { styled } from 'storybook/theming';\n\nimport { withReset } from './lib/common.tsx';\n\n/**\n * This is a \"local\" reset to style subtrees with Storybook styles\n *\n * We can't style individual elements (e.g. h1, h2, etc.) in here because the CSS specificity is too\n * high, so those styles can too easily override child elements that are not expecting it.\n */\n\nexport const ResetWrapper = styled.div(withReset);\n"
  },
  {
    "path": "code/core/src/components/components/typography/components.tsx",
    "content": "import type {\n  AnchorHTMLAttributes,\n  BlockquoteHTMLAttributes,\n  DetailedHTMLProps,\n  HTMLAttributes,\n  ImgHTMLAttributes,\n  LiHTMLAttributes,\n  OlHTMLAttributes,\n  TableHTMLAttributes,\n} from 'react';\nimport React from 'react';\n\nimport { nameSpaceClassNames } from './DocumentFormatting.tsx';\nimport { ResetWrapper } from './ResetWrapper.tsx';\nimport { A } from './elements/A.tsx';\nimport { Blockquote } from './elements/Blockquote.tsx';\nimport { Code } from './elements/Code.tsx';\nimport { DL } from './elements/DL.tsx';\nimport { Div } from './elements/Div.tsx';\nimport { H1 } from './elements/H1.tsx';\nimport { H2 } from './elements/H2.tsx';\nimport { H3 } from './elements/H3.tsx';\nimport { H4 } from './elements/H4.tsx';\nimport { H5 } from './elements/H5.tsx';\nimport { H6 } from './elements/H6.tsx';\nimport { HR } from './elements/HR.tsx';\nimport { Img } from './elements/Img.tsx';\nimport { LI } from './elements/LI.tsx';\nimport { OL } from './elements/OL.tsx';\nimport { P } from './elements/P.tsx';\nimport { Pre } from './elements/Pre.tsx';\nimport { Span } from './elements/Span.tsx';\nimport { TT } from './elements/TT.tsx';\nimport { Table } from './elements/Table.tsx';\nimport { UL } from './elements/UL.tsx';\n\nexport const components = {\n  h1: (props: DetailedHTMLProps<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>) => (\n    <H1 {...nameSpaceClassNames(props, 'h1')} />\n  ),\n  h2: (props: DetailedHTMLProps<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>) => (\n    <H2 {...nameSpaceClassNames(props, 'h2')} />\n  ),\n  h3: (props: DetailedHTMLProps<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>) => (\n    <H3 {...nameSpaceClassNames(props, 'h3')} />\n  ),\n  h4: (props: DetailedHTMLProps<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>) => (\n    <H4 {...nameSpaceClassNames(props, 'h4')} />\n  ),\n  h5: (props: DetailedHTMLProps<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>) => (\n    <H5 {...nameSpaceClassNames(props, 'h5')} />\n  ),\n  h6: (props: DetailedHTMLProps<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>) => (\n    <H6 {...nameSpaceClassNames(props, 'h6')} />\n  ),\n  pre: (props: DetailedHTMLProps<HTMLAttributes<HTMLPreElement>, HTMLPreElement>) => (\n    <Pre {...nameSpaceClassNames(props, 'pre')} />\n  ),\n  a: (props: DetailedHTMLProps<AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>) => (\n    <A {...nameSpaceClassNames(props, 'a')} />\n  ),\n  hr: (props: DetailedHTMLProps<HTMLAttributes<HTMLHRElement>, HTMLHRElement>) => (\n    <HR {...nameSpaceClassNames(props, 'hr')} />\n  ),\n  dl: (props: DetailedHTMLProps<HTMLAttributes<HTMLDListElement>, HTMLDListElement>) => (\n    <DL {...nameSpaceClassNames(props, 'dl')} />\n  ),\n  blockquote: (props: DetailedHTMLProps<BlockquoteHTMLAttributes<HTMLElement>, HTMLElement>) => (\n    <Blockquote {...nameSpaceClassNames(props, 'blockquote')} />\n  ),\n  table: (props: DetailedHTMLProps<TableHTMLAttributes<HTMLTableElement>, HTMLTableElement>) => (\n    <Table {...nameSpaceClassNames(props, 'table')} />\n  ),\n  img: (props: DetailedHTMLProps<ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>) => (\n    <Img {...nameSpaceClassNames(props, 'img')} />\n  ),\n  div: (props: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>) => (\n    <Div {...nameSpaceClassNames(props, 'div')} />\n  ),\n  span: (props: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>) => (\n    <Span {...nameSpaceClassNames(props, 'span')} />\n  ),\n  li: (props: DetailedHTMLProps<LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>) => (\n    <LI {...nameSpaceClassNames(props, 'li')} />\n  ),\n  ul: (props: DetailedHTMLProps<HTMLAttributes<HTMLUListElement>, HTMLUListElement>) => (\n    <UL {...nameSpaceClassNames(props, 'ul')} />\n  ),\n  ol: (props: DetailedHTMLProps<OlHTMLAttributes<HTMLOListElement>, HTMLOListElement>) => (\n    <OL {...nameSpaceClassNames(props, 'ol')} />\n  ),\n  p: (props: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>) => (\n    <P {...nameSpaceClassNames(props, 'p')} />\n  ),\n  code: (props: DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>) => (\n    <Code {...nameSpaceClassNames(props, 'code')} />\n  ),\n  tt: (props: DetailedHTMLProps<HTMLAttributes<HTMLTitleElement>, HTMLTitleElement>) => (\n    <TT {...nameSpaceClassNames(props, 'tt')} />\n  ),\n  resetwrapper: (props: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>) => (\n    <ResetWrapper {...nameSpaceClassNames(props, 'resetwrapper')} />\n  ),\n};\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/A.test.tsx",
    "content": "// @vitest-environment happy-dom\nimport { cleanup, render } from '@testing-library/react';\nimport { afterEach, describe, expect, it } from 'vitest';\n\nimport React from 'react';\n\nimport { ThemeProvider, convert, themes } from 'storybook/theming';\n\nimport { A } from './A.tsx';\n\nfunction ThemedA({ children, ...props }: React.ComponentProps<typeof A>) {\n  return (\n    <ThemeProvider theme={convert(themes.light)}>\n      <A {...props}>{children}</A>\n    </ThemeProvider>\n  );\n}\n\ndescribe('A', () => {\n  afterEach(() => {\n    cleanup();\n  });\n\n  describe('accessibility', () => {\n    it('should render with underline text decoration for accessibility', () => {\n      const { container } = render(<ThemedA href=\"https://example.com\">Test Link</ThemedA>);\n\n      const link = container.querySelector('a');\n      expect(link).toBeTruthy();\n\n      const styles = window.getComputedStyle(link!);\n      expect(styles.textDecoration).toContain('underline');\n    });\n\n    it('should render with underline in dark theme', () => {\n      const { container } = render(\n        <ThemeProvider theme={convert(themes.dark)}>\n          <A href=\"https://example.com\">Test Link</A>\n        </ThemeProvider>\n      );\n\n      const link = container.querySelector('a');\n      expect(link).toBeTruthy();\n\n      const styles = window.getComputedStyle(link!);\n      expect(styles.textDecoration).toContain('underline');\n    });\n\n    it('should not underline anchor position markers (a.anchor)', () => {\n      const { container } = render(\n        <ThemedA href=\"#heading\" className=\"anchor\">\n          Anchor Link\n        </ThemedA>\n      );\n\n      const link = container.querySelector('a.anchor');\n      expect(link).toBeTruthy();\n\n      const styles = window.getComputedStyle(link!);\n      expect(styles.textDecoration).not.toContain('underline');\n    });\n\n    it('should render with correct color and styling', () => {\n      const { container } = render(<ThemedA href=\"https://example.com\">Link Text</ThemedA>);\n\n      const link = container.querySelector('a');\n      expect(link).toBeTruthy();\n      expect(link?.textContent).toBe('Link Text');\n\n      const styles = window.getComputedStyle(link!);\n      expect(styles.textDecoration).toContain('underline');\n      expect(styles.fontSize).toBe('inherit');\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/A.tsx",
    "content": "import type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\nimport { withReset } from '../lib/common.tsx';\nimport { Link } from './Link.tsx';\n\nexport const A = styled(Link)(({ theme }) => ({\n  ...(withReset({ theme }) as CSSObject),\n  fontSize: 'inherit',\n  lineHeight: '24px',\n\n  color: theme.color.secondary,\n  // Ensure WCAG Level A compliance (SC 1.4.1), see https://www.w3.org/WAI/WCAG22/Techniques/failures/F73\n  textDecoration: 'underline',\n  textDecorationThickness: '0.03125rem',\n  textUnderlineOffset: '0.11em',\n  '&.absent': {\n    color: '#cc0000',\n  },\n  '&.anchor': {\n    display: 'block',\n    paddingLeft: 30,\n    marginLeft: -30,\n    cursor: 'pointer',\n    position: 'absolute',\n    top: 0,\n    left: 0,\n    bottom: 0,\n    textDecoration: 'none',\n  },\n  '&.anchor:hover, &.anchor:focus': {\n    textDecoration: 'underline',\n  },\n  '& code': {\n    color: 'inherit',\n    textDecoration: 'underline',\n    textDecorationThickness: '0.03125rem',\n    paddingLeft: 0,\n    paddingRight: 0,\n    '&::before': {\n      content: '\"\\\\00a0\"',\n      fontSize: '0.5em',\n    },\n    '&::after': {\n      content: '\"\\\\00a0\"',\n      fontSize: '0.5em',\n    },\n  },\n}));\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/Blockquote.tsx",
    "content": "import type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\nimport { withMargin, withReset } from '../lib/common.tsx';\n\nexport const Blockquote = styled.blockquote(({ theme }) => ({\n  ...(withReset({ theme }) as CSSObject),\n  ...withMargin,\n  borderLeft: `4px solid ${theme.color.medium}`,\n  padding: '0 15px',\n  color: theme.color.dark,\n  '& > :first-of-type': {\n    marginTop: 0,\n  },\n  '& > :last-child': {\n    marginBottom: 0,\n  },\n}));\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/Code.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React, { Children } from 'react';\n\nimport type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\nimport { SyntaxHighlighter } from '../../syntaxhighlighter/lazy-syntaxhighlighter.tsx';\nimport type { SupportedLanguage } from '../../syntaxhighlighter/syntaxhighlighter-types.ts';\nimport { codeCommon } from '../lib/common.tsx';\nimport { isReactChildString } from '../lib/isReactChildString.tsx';\n\nconst isInlineCodeRegex = /[\\n\\r]/g;\n\nconst DefaultCodeBlock = styled.code(({ theme }) => ({\n  // from reset\n  fontFamily: theme.typography.fonts.mono,\n  WebkitFontSmoothing: 'antialiased',\n  MozOsxFontSmoothing: 'grayscale',\n  display: 'inline-block',\n  paddingLeft: 2,\n  paddingRight: 2,\n  verticalAlign: 'baseline',\n  color: 'inherit',\n  ...(codeCommon({ theme }) as CSSObject),\n}));\n\nconst StyledSyntaxHighlighter = styled(SyntaxHighlighter)(({ theme }) => ({\n  // DocBlocks-specific styling and overrides\n  fontFamily: theme.typography.fonts.mono,\n  fontSize: `${theme.typography.size.s2 - 1}px`,\n  lineHeight: '19px',\n  margin: '25px 0 40px',\n  borderRadius: theme.appBorderRadius,\n  boxShadow:\n    theme.base === 'light' ? 'rgba(0, 0, 0, 0.10) 0 1px 3px 0' : 'rgba(0, 0, 0, 0.20) 0 2px 5px 0',\n  'pre.prismjs': {\n    padding: 20,\n    background: 'inherit',\n  },\n}));\n\nexport const Code = ({\n  className,\n  children,\n  ...props\n}: ComponentProps<typeof DefaultCodeBlock>) => {\n  const language = (className || '').match(/lang-(\\S+)/);\n  const childrenArray = Children.toArray(children);\n  const isInlineCode = !childrenArray\n    .filter(isReactChildString)\n    .some((child) => child.match(isInlineCodeRegex));\n\n  if (isInlineCode) {\n    return (\n      <DefaultCodeBlock {...props} className={className}>\n        {childrenArray}\n      </DefaultCodeBlock>\n    );\n  }\n\n  return (\n    <StyledSyntaxHighlighter\n      bordered\n      copyable\n      language={(language?.[1] as SupportedLanguage) ?? 'text'}\n      format={false}\n      {...props}\n    >\n      {children}\n    </StyledSyntaxHighlighter>\n  );\n};\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/DL.tsx",
    "content": "import type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\nimport { withMargin, withReset } from '../lib/common.tsx';\n\nexport const DL = styled.dl(({ theme }) => ({\n  ...(withReset({ theme }) as CSSObject),\n  ...withMargin,\n  padding: 0,\n  '& dt': {\n    fontSize: '14px',\n    fontWeight: 'bold',\n    fontStyle: 'italic',\n    padding: 0,\n    margin: '16px 0 4px',\n  },\n  '& dt:first-of-type': {\n    padding: 0,\n  },\n  '& dt > :first-of-type': {\n    marginTop: 0,\n  },\n\n  '& dt > :last-child': {\n    marginBottom: 0,\n  },\n\n  '& dd': {\n    margin: '0 0 16px',\n    padding: '0 15px',\n  },\n\n  '& dd > :first-of-type': {\n    marginTop: 0,\n  },\n\n  '& dd > :last-child': {\n    marginBottom: 0,\n  },\n}));\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/Div.tsx",
    "content": "import { styled } from 'storybook/theming';\n\nimport { withReset } from '../lib/common.tsx';\n\nexport const Div = styled.div(withReset);\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/H1.tsx",
    "content": "import type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\nimport { headerCommon, withReset } from '../lib/common.tsx';\n\nexport const H1 = styled.h1(({ theme }) => ({\n  ...(withReset({ theme }) as CSSObject),\n  ...(headerCommon({ theme }) as CSSObject),\n  fontSize: `${theme.typography.size.l1}px`,\n  fontWeight: theme.typography.weight.bold,\n}));\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/H2.tsx",
    "content": "import type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\nimport { headerCommon, withReset } from '../lib/common.tsx';\n\nexport const H2 = styled.h2(({ theme }) => ({\n  ...(withReset({ theme }) as CSSObject),\n  ...(headerCommon({ theme }) as CSSObject),\n  fontSize: `${theme.typography.size.m2}px`,\n  paddingBottom: 4,\n  borderBottom: `1px solid ${theme.appBorderColor}`,\n}));\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/H3.tsx",
    "content": "import type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\nimport { headerCommon, withReset } from '../lib/common.tsx';\n\nexport const H3 = styled.h3(({ theme }) => ({\n  ...(withReset({ theme }) as CSSObject),\n  ...(headerCommon({ theme }) as CSSObject),\n  fontSize: `${theme.typography.size.m1}px`,\n}));\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/H4.tsx",
    "content": "import type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\nimport { headerCommon, withReset } from '../lib/common.tsx';\n\nexport const H4 = styled.h4(({ theme }) => ({\n  ...(withReset({ theme }) as CSSObject),\n  ...(headerCommon({ theme }) as CSSObject),\n  fontSize: `${theme.typography.size.s3}px`,\n}));\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/H5.tsx",
    "content": "import type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\nimport { headerCommon, withReset } from '../lib/common.tsx';\n\nexport const H5 = styled.h5(({ theme }) => ({\n  ...(withReset({ theme }) as CSSObject),\n  ...(headerCommon({ theme }) as CSSObject),\n  fontSize: `${theme.typography.size.s2}px`,\n}));\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/H6.tsx",
    "content": "import type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\nimport { headerCommon, withReset } from '../lib/common.tsx';\n\nexport const H6 = styled.h6(({ theme }) => ({\n  ...(withReset({ theme }) as CSSObject),\n  ...(headerCommon({ theme }) as CSSObject),\n  fontSize: `${theme.typography.size.s2}px`,\n  color: theme.color.dark,\n}));\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/HR.tsx",
    "content": "import { styled } from 'storybook/theming';\n\nexport const HR = styled.hr(({ theme }) => ({\n  border: '0 none',\n  borderTop: `1px solid ${theme.appBorderColor}`,\n  height: 4,\n  padding: 0,\n}));\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/Img.tsx",
    "content": "import { styled } from 'storybook/theming';\n\nexport const Img = styled.img({\n  maxWidth: '100%',\n});\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/LI.tsx",
    "content": "import type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\nimport { codeCommon, withReset } from '../lib/common.tsx';\n\nexport const LI = styled.li(({ theme }) => ({\n  ...(withReset({ theme }) as CSSObject),\n  fontSize: theme.typography.size.s2,\n  color: theme.color.defaultText,\n  lineHeight: '24px',\n  '& + li': {\n    marginTop: '.25em',\n  },\n  '& ul, & ol': {\n    marginTop: '.25em',\n    marginBottom: 0,\n  },\n  '& code': codeCommon({ theme }) as CSSObject,\n}));\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/Link.tsx",
    "content": "import React from 'react';\n\nexport const Link = ({\n  href: input = '',\n  ...props\n}: React.AnchorHTMLAttributes<HTMLAnchorElement>) => {\n  const isStorybookPath = /^\\//.test(input);\n  const href = isStorybookPath ? `./?path=${input}` : input;\n\n  const isAnchorUrl = /^#.*/.test(input);\n  const target = isAnchorUrl ? '_self' : '_top';\n\n  // eslint-disable-next-line jsx-a11y/anchor-has-content\n  return <a href={href} target={target} {...props} />;\n};\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/OL.tsx",
    "content": "import type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\nimport { withMargin, withReset } from '../lib/common.tsx';\n\nconst listCommon = {\n  paddingLeft: 30,\n  '& :first-of-type': {\n    marginTop: 0,\n  },\n  '& :last-child': {\n    marginBottom: 0,\n  },\n};\n\nexport const OL = styled.ol(({ theme }) => ({\n  ...(withReset({ theme }) as CSSObject),\n  ...withMargin,\n  ...listCommon,\n  listStyle: 'decimal',\n}));\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/P.tsx",
    "content": "import type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\nimport { codeCommon, withMargin, withReset } from '../lib/common.tsx';\n\nexport const P = styled.p(({ theme }) => ({\n  ...(withReset({ theme }) as CSSObject),\n  ...withMargin,\n  fontSize: theme.typography.size.s2,\n  lineHeight: '24px',\n  color: theme.color.defaultText,\n  '& code': codeCommon({ theme }) as CSSObject,\n}));\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/Pre.tsx",
    "content": "import type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\nimport { withMargin, withReset } from '../lib/common.tsx';\n\nexport const Pre = styled.pre(({ theme }) => ({\n  ...(withReset({ theme }) as CSSObject),\n  ...withMargin,\n  // reset\n  fontFamily: theme.typography.fonts.mono,\n  WebkitFontSmoothing: 'antialiased',\n  MozOsxFontSmoothing: 'grayscale',\n  lineHeight: '18px',\n  padding: '11px 1rem',\n  whiteSpace: 'pre-wrap',\n  color: 'inherit',\n  borderRadius: 3,\n  margin: '1rem 0',\n\n  '&:not(.prismjs)': {\n    background: 'transparent',\n    border: 'none',\n    borderRadius: 0,\n    padding: 0,\n    margin: 0,\n  },\n  '& pre, &.prismjs': {\n    padding: 15,\n    margin: 0,\n    whiteSpace: 'pre-wrap',\n    color: 'inherit',\n    fontSize: '13px',\n    lineHeight: '19px',\n    code: {\n      color: 'inherit',\n      fontSize: 'inherit',\n    },\n  },\n  '& code': {\n    whiteSpace: 'pre',\n  },\n  '& code, & tt': {\n    border: 'none',\n  },\n}));\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/Span.tsx",
    "content": "import type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\nimport { withReset } from '../lib/common.tsx';\n\nexport const Span = styled.span(({ theme }) => ({\n  ...(withReset({ theme }) as CSSObject),\n  '&.frame': {\n    display: 'block',\n    overflow: 'hidden',\n\n    '& > span': {\n      border: `1px solid ${theme.color.medium}`,\n      display: 'block',\n      float: 'left',\n      overflow: 'hidden',\n      margin: '13px 0 0',\n      padding: 7,\n      width: 'auto',\n    },\n    '& span img': {\n      display: 'block',\n      float: 'left',\n    },\n    '& span span': {\n      clear: 'both',\n      color: theme.color.darkest,\n      display: 'block',\n      padding: '5px 0 0',\n    },\n  },\n  '&.align-center': {\n    display: 'block',\n    overflow: 'hidden',\n    clear: 'both',\n\n    '& > span': {\n      display: 'block',\n      overflow: 'hidden',\n      margin: '13px auto 0',\n      textAlign: 'center',\n    },\n    '& span img': {\n      margin: '0 auto',\n      textAlign: 'center',\n    },\n  },\n  '&.align-right': {\n    display: 'block',\n    overflow: 'hidden',\n    clear: 'both',\n\n    '& > span': {\n      display: 'block',\n      overflow: 'hidden',\n      margin: '13px 0 0',\n      textAlign: 'right',\n    },\n    '& span img': {\n      margin: 0,\n      textAlign: 'right',\n    },\n  },\n  '&.float-left': {\n    display: 'block',\n    marginRight: 13,\n    overflow: 'hidden',\n    float: 'left',\n    '& span': {\n      margin: '13px 0 0',\n    },\n  },\n  '&.float-right': {\n    display: 'block',\n    marginLeft: 13,\n    overflow: 'hidden',\n    float: 'right',\n\n    '& > span': {\n      display: 'block',\n      overflow: 'hidden',\n      margin: '13px auto 0',\n      textAlign: 'right',\n    },\n  },\n}));\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/TT.tsx",
    "content": "import { styled } from 'storybook/theming';\n\nimport { codeCommon } from '../lib/common.tsx';\n\nexport const TT = styled.title(codeCommon);\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/Table.tsx",
    "content": "import type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\nimport { withMargin, withReset } from '../lib/common.tsx';\n\nexport const Table = styled.table(({ theme }) => ({\n  ...(withReset({ theme }) as CSSObject),\n  ...withMargin,\n  fontSize: theme.typography.size.s2,\n  lineHeight: '24px',\n  padding: 0,\n  borderCollapse: 'collapse',\n  '& tr': {\n    borderTop: `1px solid ${theme.appBorderColor}`,\n    backgroundColor: theme.appContentBg,\n    margin: 0,\n    padding: 0,\n  },\n  '& tr:nth-of-type(2n)': {\n    backgroundColor: theme.base === 'dark' ? theme.color.darker : theme.color.lighter,\n  },\n  '& tr th': {\n    fontWeight: 'bold',\n    color: theme.color.defaultText,\n    border: `1px solid ${theme.appBorderColor}`,\n    margin: 0,\n    padding: '6px 13px',\n  },\n  '& tr td': {\n    border: `1px solid ${theme.appBorderColor}`,\n    color: theme.color.defaultText,\n    margin: 0,\n    padding: '6px 13px',\n  },\n  '& tr th :first-of-type, & tr td :first-of-type': {\n    marginTop: 0,\n  },\n  '& tr th :last-child, & tr td :last-child': {\n    marginBottom: 0,\n  },\n}));\n"
  },
  {
    "path": "code/core/src/components/components/typography/elements/UL.tsx",
    "content": "import type { CSSObject } from 'storybook/theming';\nimport { styled } from 'storybook/theming';\n\nimport { withMargin, withReset } from '../lib/common.tsx';\n\nconst listCommon = {\n  paddingLeft: 30,\n  '& :first-of-type': {\n    marginTop: 0,\n  },\n  '& :last-child': {\n    marginBottom: 0,\n  },\n};\n\nexport const UL = styled.ul(({ theme }) => ({\n  ...(withReset({ theme }) as CSSObject),\n  ...withMargin,\n  ...listCommon,\n  listStyle: 'disc',\n}));\n"
  },
  {
    "path": "code/core/src/components/components/typography/lib/common.tsx",
    "content": "import { transparentize } from 'polished';\nimport type { CSSObject, FunctionInterpolation } from 'storybook/theming';\n\nexport const headerCommon: FunctionInterpolation = ({ theme }) => ({\n  margin: '20px 0 8px',\n  padding: 0,\n  cursor: 'text',\n  position: 'relative',\n  color: theme.color.defaultText,\n  '&:first-of-type': {\n    marginTop: 0,\n    paddingTop: 0,\n  },\n  '&:hover a.anchor': {\n    textDecoration: 'none',\n  },\n  '& tt, & code': {\n    fontSize: 'inherit',\n  },\n});\n\nexport const codeCommon: FunctionInterpolation = ({ theme }) => ({\n  lineHeight: 1,\n  margin: '0 2px',\n  padding: '3px 5px',\n  whiteSpace: 'nowrap',\n\n  borderRadius: 3,\n  fontSize: theme.typography.size.s2 - 1,\n\n  border: theme.base === 'light' ? '1px solid hsl(0 0 0 / 0.05)' : '1px solid hsl(0 0 100 / 0.05)',\n  color: theme.color.defaultText,\n  backgroundColor: theme.base === 'light' ? 'hsl(0 0 0 / 0.01)' : 'hsl(0 0 100 / 0.02)',\n});\n\nexport const withReset: FunctionInterpolation = ({ theme }) => ({\n  fontFamily: theme.typography.fonts.base,\n  fontSize: theme.typography.size.s3,\n  margin: 0,\n\n  WebkitFontSmoothing: 'antialiased',\n  MozOsxFontSmoothing: 'grayscale',\n  WebkitTapHighlightColor: 'rgba(0, 0, 0, 0)',\n  WebkitOverflowScrolling: 'touch',\n});\n\nexport const withMargin: CSSObject = {\n  margin: '16px 0',\n};\n"
  },
  {
    "path": "code/core/src/components/components/typography/lib/isReactChildString.tsx",
    "content": "import type { ReactNode } from 'react';\n\nexport const isReactChildString = (child: ReactNode): child is string => typeof child === 'string';\n"
  },
  {
    "path": "code/core/src/components/components/typography/link/link.stories.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React from 'react';\n\nimport { DiscordIcon, SidebarIcon } from '@storybook/icons';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { action } from 'storybook/actions';\nimport { expect, fn } from 'storybook/test';\n\nimport { Link } from './link.tsx';\n\nconst onClick = action('onClick');\n\nconst meta = {\n  component: Link,\n} satisfies Meta<typeof Link>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const CancelWOnClick = {\n  args: {\n    href: '/',\n    onClick,\n    children: 'Try clicking with different mouse buttons and modifier keys (shift/ctrl/alt/cmd)',\n  },\n  name: 'Cancel w/ onClick',\n} satisfies Story;\n\nexport const CancelWHref = {\n  args: {\n    href: 'http://example.com',\n    children: 'Link',\n  },\n  name: 'Cancel w/ href',\n} satisfies Story;\n\nexport const NoCancelWOnClick = {\n  args: {\n    href: '/',\n    children: 'Any click will go through',\n    onClick,\n  },\n  name: 'No-cancel w/ onClick',\n} satisfies Story;\n\nexport const NoCancelWHref = {\n  args: {\n    href: 'http://example.com',\n    children: 'Link',\n  },\n  name: 'No-cancel w/ href',\n} satisfies Story;\n\nexport const ButtonLink = {\n  args: {\n    children: 'Click me',\n    onClick: fn(),\n  },\n  name: 'Link-styled button',\n  play: async ({ args, canvas }) => {\n    const link = canvas.getByRole('button', { name: 'Click me' });\n    link.focus();\n    expect(link).toHaveFocus();\n    link.click();\n    expect(args.onClick).toHaveBeenCalled();\n  },\n} satisfies Story;\n\nexport const StyledLinks = {\n  render: (args: ComponentProps<typeof Link>) => (\n    <div>\n      <Link href=\"http://google.com\" {...args}>\n        Default\n      </Link>\n      <br />\n      <Link secondary href=\"http://google.com\" {...args}>\n        Secondary\n      </Link>\n      <br />\n      <Link tertiary href=\"http://google.com\" {...args}>\n        tertiary\n      </Link>\n      <br />\n      <Link nochrome href=\"http://google.com\" {...args}>\n        nochrome\n      </Link>\n      <br />\n      <Link href=\"http://google.com\" {...args}>\n        <DiscordIcon />\n        With icon in front\n      </Link>\n      <br />\n      <Link title=\"Toggle sidebar\" containsIcon href=\"http://google.com\" {...args}>\n        {/* A linked icon by itself   */}\n        <SidebarIcon />\n      </Link>\n      <br />\n      <Link containsIcon withArrow href=\"http://google.com\" {...args}>\n        With arrow behind\n      </Link>\n      <br />\n      <span\n        style={{\n          background: '#333',\n        }}\n      >\n        <Link inverse href=\"http://google.com\" {...args}>\n          Inverted colors\n        </Link>\n      </span>\n      <br />\n    </div>\n  ),\n  name: 'Styled links',\n} satisfies Story;\n"
  },
  {
    "path": "code/core/src/components/components/typography/link/link.test.tsx",
    "content": "// @vitest-environment happy-dom\nimport { cleanup, render, screen } from '@testing-library/react';\nimport userEvent from '@testing-library/user-event';\nimport { afterEach, describe, expect, it, vi } from 'vitest';\n\nimport type { AnchorHTMLAttributes } from 'react';\nimport React from 'react';\n\nimport { ThemeProvider, convert, themes } from 'storybook/theming';\n\nimport type { LinkProps } from './link.tsx';\nimport { Link } from './link.tsx';\n\nfunction ThemedLink(props: LinkProps & AnchorHTMLAttributes<HTMLAnchorElement>) {\n  return (\n    <ThemeProvider theme={convert(themes.light)}>\n      <Link {...props} />\n    </ThemeProvider>\n  );\n}\n\nasync function click(target: Element, button: string, modifier?: string) {\n  const user = userEvent.setup();\n  if (modifier) {\n    // Trailing > means to leave it pressed\n    await user.keyboard(`{${modifier}>}`);\n  }\n  await user.pointer([{ target }, { keys: `[${button}]`, target }]);\n  if (modifier) {\n    // Leading / means to release it\n    await user.keyboard(`{/${modifier}}`);\n  }\n}\n\ndescribe('Link', () => {\n  afterEach(() => {\n    cleanup();\n  });\n\n  describe('events', () => {\n    it('should call onClick on a plain left click', async () => {\n      const handleClick = vi.fn();\n      render(<ThemedLink onClick={handleClick}>Content</ThemedLink>);\n      await click(screen.getByText('Content'), 'MouseLeft');\n      expect(handleClick).toHaveBeenCalled();\n    });\n\n    it(\"shouldn't call onClick on a middle click\", async () => {\n      const handleClick = vi.fn();\n      render(<ThemedLink onClick={handleClick}>Content</ThemedLink>);\n      await click(screen.getByText('Content'), 'MouseMiddle');\n      expect(handleClick).not.toHaveBeenCalled();\n    });\n\n    it(\"shouldn't call onClick on a right click\", async () => {\n      const handleClick = vi.fn();\n      render(<ThemedLink onClick={handleClick}>Content</ThemedLink>);\n      await click(screen.getByText('Content'), 'MouseRight');\n      expect(handleClick).not.toHaveBeenCalled();\n    });\n\n    it(\"shouldn't call onClick on alt+click\", async () => {\n      const handleClick = vi.fn();\n      render(<ThemedLink onClick={handleClick}>Content</ThemedLink>);\n      await click(screen.getByText('Content'), 'MouseLeft', 'Alt');\n      expect(handleClick).not.toHaveBeenCalled();\n    });\n\n    it(\"shouldn't call onClick on ctrl+click\", async () => {\n      const handleClick = vi.fn();\n      render(<ThemedLink onClick={handleClick}>Content</ThemedLink>);\n      await click(screen.getByText('Content'), 'MouseLeft', 'Control');\n      expect(handleClick).not.toHaveBeenCalled();\n    });\n\n    it(\"shouldn't call onClick on cmd+click / win+click\", async () => {\n      const handleClick = vi.fn();\n      render(<ThemedLink onClick={handleClick}>Content</ThemedLink>);\n      await click(screen.getByText('Content'), 'MouseLeft', 'Meta');\n      expect(handleClick).not.toHaveBeenCalled();\n    });\n\n    it(\"shouldn't call onClick on shift+click\", async () => {\n      const handleClick = vi.fn();\n      render(<ThemedLink onClick={handleClick}>Content</ThemedLink>);\n      await click(screen.getByText('Content'), 'MouseLeft', 'Shift');\n      expect(handleClick).not.toHaveBeenCalled();\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/components/components/typography/link/link.tsx",
    "content": "import type { AnchorHTMLAttributes, MouseEvent } from 'react';\nimport React, { forwardRef } from 'react';\n\nimport { deprecate } from 'storybook/internal/client-logger';\n\nimport { ChevronRightIcon } from '@storybook/icons';\n\nimport { darken } from 'polished';\nimport { styled } from 'storybook/theming';\n\n// Cmd/Ctrl/Shift/Alt + Click should trigger default browser behavior. Same applies to non-left clicks\nconst LEFT_BUTTON = 0;\n\nconst isPlainLeftClick = (e: MouseEvent) =>\n  e.button === LEFT_BUTTON && !e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey;\n\nconst cancelled = (e: MouseEvent, cb: (_e: MouseEvent) => void) => {\n  if (isPlainLeftClick(e)) {\n    e.preventDefault();\n    cb(e);\n  }\n};\n\nexport interface LinkStylesProps {\n  secondary?: boolean;\n  tertiary?: boolean;\n  nochrome?: boolean;\n  inverse?: boolean;\n  isButton?: boolean;\n}\n\nexport interface LinkInnerProps {\n  withArrow?: boolean;\n  containsIcon?: boolean;\n}\n\nconst LinkInner = styled.span<LinkInnerProps>(\n  ({ withArrow }) =>\n    withArrow\n      ? {\n          '> svg:last-of-type': {\n            height: '0.7em',\n            width: '0.7em',\n            marginRight: 0,\n            marginLeft: '0.25em',\n            bottom: 'auto',\n            verticalAlign: 'inherit',\n          },\n        }\n      : {},\n  ({ containsIcon }) =>\n    containsIcon\n      ? {\n          svg: {\n            height: '1em',\n            width: '1em',\n            verticalAlign: 'middle',\n            position: 'relative',\n            bottom: 0,\n            marginRight: 0,\n          },\n        }\n      : {}\n);\n\ntype AProps = AnchorHTMLAttributes<HTMLAnchorElement>;\n\nconst A = styled.a<LinkStylesProps>(\n  ({ theme }) => ({\n    display: 'inline-block',\n    transition: 'all 150ms ease-out',\n    textDecoration: 'none',\n\n    color: theme.color.secondary,\n\n    '&:hover, &:focus': {\n      cursor: 'pointer',\n      color: darken(0.07, theme.color.secondary),\n      'svg path:not([fill])': {\n        fill: darken(0.07, theme.color.secondary),\n      },\n    },\n    '&:active': {\n      color: darken(0.1, theme.color.secondary),\n      'svg path:not([fill])': {\n        fill: darken(0.1, theme.color.secondary),\n      },\n    },\n\n    svg: {\n      display: 'inline-block',\n      height: '1em',\n      width: '1em',\n      verticalAlign: 'text-top',\n      position: 'relative',\n      bottom: '-0.125em',\n      marginRight: '0.4em',\n\n      '& path': {\n        fill: theme.color.secondary,\n      },\n    },\n  }),\n  ({ theme, secondary, tertiary }) => {\n    let colors;\n    if (secondary) {\n      colors = [theme.textMutedColor, theme.color.secondary, theme.color.secondary];\n    }\n    if (tertiary) {\n      colors = [theme.color.dark, theme.color.secondary, theme.color.secondary];\n    }\n\n    return colors\n      ? {\n          color: colors[0],\n          'svg path:not([fill])': {\n            fill: colors[0],\n          },\n\n          '&:hover': {\n            color: colors[1],\n            'svg path:not([fill])': {\n              fill: colors[1],\n            },\n          },\n\n          '&:active': {\n            color: colors[2],\n            'svg path:not([fill])': {\n              fill: colors[2],\n            },\n          },\n        }\n      : {};\n  },\n  ({ nochrome }) =>\n    nochrome\n      ? {\n          color: 'inherit',\n\n          '&:hover, &:active': {\n            color: 'inherit',\n            textDecoration: 'underline',\n          },\n        }\n      : {},\n  ({ theme, inverse }) =>\n    inverse\n      ? {\n          color: theme.color.lightest,\n          ':not([fill])': {\n            fill: theme.color.lightest,\n          },\n\n          '&:hover': {\n            color: theme.color.lighter,\n            'svg path:not([fill])': {\n              fill: theme.color.lighter,\n            },\n          },\n\n          '&:active': {\n            color: theme.color.light,\n            'svg path:not([fill])': {\n              fill: theme.color.light,\n            },\n          },\n        }\n      : {},\n  ({ isButton, theme }) =>\n    isButton\n      ? {\n          border: 0,\n          borderRadius: theme.input.borderRadius,\n          background: 'none',\n          padding: 0,\n          fontSize: 'inherit',\n          lineHeight: 'inherit',\n\n          '&:focus-visible': {\n            outline: `2px solid ${theme.color.secondary}`,\n            outlineOffset: 2,\n            // Should ensure focus outline gets drawn above next sibling\n            zIndex: '1',\n          },\n        }\n      : {}\n);\n\nexport interface LinkProps extends LinkInnerProps, LinkStylesProps, AProps {\n  cancel?: boolean;\n  className?: string;\n  style?: object;\n  onClick?: (e: MouseEvent) => void;\n  href?: string;\n}\n\nexport const Link = forwardRef<HTMLAnchorElement, LinkProps>(\n  (\n    {\n      cancel = true,\n      children,\n      onClick = undefined,\n      withArrow = false,\n      containsIcon = false,\n      className = undefined,\n      isButton = undefined,\n      href,\n      ...rest\n    },\n    ref\n  ) => {\n    if (isButton !== undefined) {\n      deprecate(\n        'Link: `isButton` is deprecated and will be removed in Storybook 11. Links without a `href` are automatically rendered as buttons.'\n      );\n    }\n\n    return (\n      <A\n        as={href ? 'a' : 'button'}\n        href={href}\n        {...rest}\n        ref={ref}\n        isButton={!href || isButton === true}\n        onClick={onClick && cancel ? (e) => cancelled(e, onClick) : onClick}\n        className={className}\n      >\n        <LinkInner withArrow={withArrow} containsIcon={containsIcon}>\n          {children}\n          {withArrow && <ChevronRightIcon />}\n        </LinkInner>\n      </A>\n    );\n  }\n);\nLink.displayName = 'Link';\n"
  },
  {
    "path": "code/core/src/components/components/utils/getStoryHref.ts",
    "content": "import { deprecate } from 'storybook/internal/client-logger';\n\nfunction parseQuery(queryString: string) {\n  const query: Record<string, string> = {};\n  const pairs = queryString.split('&');\n\n  for (let i = 0; i < pairs.length; i++) {\n    const pair = pairs[i].split('=');\n    query[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || '');\n  }\n  return query;\n}\n\n/** @deprecated Use the api.getStoryHrefs method instead (from `storybook/manager-api`) */\nexport const getStoryHref = (\n  baseUrl: string,\n  storyId: string,\n  additionalParams: Record<string, string> = {}\n) => {\n  deprecate(\n    'getStoryHref is deprecated and will be removed in Storybook 11, use the api.getStoryHrefs method instead'\n  );\n  const [url, paramsStr] = baseUrl.split('?');\n  const params = paramsStr\n    ? {\n        ...parseQuery(paramsStr),\n        ...additionalParams,\n        id: storyId,\n      }\n    : {\n        ...additionalParams,\n        id: storyId,\n      };\n  return `${url}?${Object.entries(params)\n    .map((item) => `${item[0]}=${item[1]}`)\n    .join('&')}`;\n};\n"
  },
  {
    "path": "code/core/src/components/index.ts",
    "content": "/// <reference path=\"../typings.d.ts\" />\nimport type { ElementType } from 'react';\nimport { createElement, forwardRef } from 'react';\n\nimport * as typography from './components/typography/components.tsx';\n\nexport { A } from './components/typography/elements/A.tsx';\nexport { Blockquote } from './components/typography/elements/Blockquote.tsx';\nexport { Code } from './components/typography/elements/Code.tsx';\nexport { Div } from './components/typography/elements/Div.tsx';\nexport { DL } from './components/typography/elements/DL.tsx';\nexport { H1 } from './components/typography/elements/H1.tsx';\nexport { H2 } from './components/typography/elements/H2.tsx';\nexport { H3 } from './components/typography/elements/H3.tsx';\nexport { H4 } from './components/typography/elements/H4.tsx';\nexport { H5 } from './components/typography/elements/H5.tsx';\nexport { H6 } from './components/typography/elements/H6.tsx';\nexport { HR } from './components/typography/elements/HR.tsx';\nexport { Img } from './components/typography/elements/Img.tsx';\nexport { LI } from './components/typography/elements/LI.tsx';\nexport { OL } from './components/typography/elements/OL.tsx';\nexport { P } from './components/typography/elements/P.tsx';\nexport { Pre } from './components/typography/elements/Pre.tsx';\nexport { Span } from './components/typography/elements/Span.tsx';\nexport { Table } from './components/typography/elements/Table.tsx';\nexport { TT } from './components/typography/elements/TT.tsx';\nexport { UL } from './components/typography/elements/UL.tsx';\nexport { Badge } from './components/Badge/Badge.tsx';\n\n// Typography\nexport { Link } from './components/typography/link/link.tsx';\nexport { DocumentWrapper } from './components/typography/DocumentWrapper.tsx';\nexport type {\n  SyntaxHighlighterFormatTypes,\n  SyntaxHighlighterProps,\n  SyntaxHighlighterRendererProps,\n  SupportedLanguage,\n} from './components/syntaxhighlighter/syntaxhighlighter-types.ts';\nexport { SyntaxHighlighter } from './components/syntaxhighlighter/lazy-syntaxhighlighter.tsx';\nexport { createCopyToClipboardFunction } from './components/syntaxhighlighter/clipboard.ts';\n\n// UI\nexport { ActionBar } from './components/ActionBar/ActionBar.tsx';\nexport { ActionList } from './components/ActionList/ActionList.tsx';\nexport { Collapsible } from './components/Collapsible/Collapsible.tsx';\nexport { Card } from './components/Card/Card.tsx';\nexport { Modal, ModalDecorator } from './components/Modal/Modal.tsx';\nexport { Spaced } from './components/spaced/Spaced.tsx';\nexport { Placeholder } from './components/placeholder/placeholder.tsx';\nexport { ScrollArea } from './components/ScrollArea/ScrollArea.tsx';\nexport { Zoom } from './components/Zoom/Zoom.tsx';\nexport type { ActionItem } from './components/ActionBar/ActionBar.tsx';\nexport { ErrorFormatter } from './components/ErrorFormatter/ErrorFormatter.tsx';\n\n// Buttons\nexport { Button, IconButton } from './components/Button/Button.tsx';\nexport type { ButtonProps } from './components/Button/Button.tsx';\nexport { ToggleButton } from './components/ToggleButton/ToggleButton.tsx';\nexport { Select } from './components/Select/Select.tsx';\n\n// Forms\nexport { Form } from './components/Form/Form.tsx';\n\n// Overlay helpers for popovers, menus, tooltips\nexport { convertToReactAriaPlacement } from './components/shared/overlayHelpers.tsx';\nexport type { PopperPlacement } from './components/shared/overlayHelpers.tsx';\n\n// Popovers\nexport { Popover } from './components/Popover/Popover.tsx';\nexport type { PopoverProps } from './components/Popover/Popover.tsx';\nexport { PopoverProvider } from './components/Popover/PopoverProvider.tsx';\nexport type { PopoverProviderProps } from './components/Popover/PopoverProvider.tsx';\n\n// Tooltips\nexport { Tooltip } from './components/tooltip/Tooltip.tsx';\nexport type { TooltipProps } from './components/tooltip/Tooltip.tsx';\nexport { TooltipNote } from './components/tooltip/TooltipNote.tsx';\nexport type { TooltipNoteProps } from './components/tooltip/TooltipNote.tsx';\nexport { TooltipProvider } from './components/tooltip/TooltipProvider.tsx';\nexport type { TooltipProviderProps } from './components/tooltip/TooltipProvider.tsx';\n\n// Old tooltips - deprecated and to remove in Storybook 11\nexport { WithTooltip, WithTooltipPure } from './components/tooltip/lazy-WithTooltip.tsx';\nexport { TooltipMessage } from './components/tooltip/TooltipMessage.tsx';\nexport {\n  TooltipLinkList,\n  type Link as TooltipLinkListLink,\n} from './components/tooltip/TooltipLinkList.tsx';\nexport { default as ListItem } from './components/tooltip/ListItem.tsx';\n\n// Bar, Toolbar and Tabs\nexport { Tabs, TabsState, TabBar, TabWrapper } from './components/Tabs/Tabs.tsx';\nexport { TabButton } from './components/Tabs/Button.tsx';\nexport { Separator, interleaveSeparators } from './components/Bar/Separator.tsx';\nexport { Bar, FlexBar, type BarProps } from './components/Bar/Bar.tsx';\nexport { EmptyTabContent } from './components/Tabs/EmptyTabContent.tsx';\nexport { AddonPanel } from './components/addon-panel/addon-panel.tsx';\nexport { Toolbar, AbstractToolbar } from './components/Toolbar/Toolbar.tsx';\nexport { TabList } from './components/Tabs/TabList.tsx';\nexport type { TabListProps } from './components/Tabs/TabList.tsx';\nexport { TabPanel } from './components/Tabs/TabPanel.tsx';\nexport type { TabPanelProps } from './components/Tabs/TabPanel.tsx';\nexport { TabsView, useTabsState } from './components/Tabs/TabsView.tsx';\nexport type { TabProps, TabsViewProps } from './components/Tabs/TabsView.tsx';\n\nexport { StatelessTabList } from './components/Tabs/StatelessTabList.tsx';\nexport type { StatelessTabListProps } from './components/Tabs/StatelessTabList.tsx';\nexport { StatelessTabPanel } from './components/Tabs/StatelessTabPanel.tsx';\nexport type { StatelessTabPanelProps } from './components/Tabs/StatelessTabPanel.tsx';\nexport { StatelessTabsView } from './components/Tabs/StatelessTabsView.tsx';\nexport type { StatelessTabsViewProps } from './components/Tabs/StatelessTabsView.tsx';\nexport { StatelessTab } from './components/Tabs/StatelessTab.tsx';\nexport type { StatelessTabProps } from './components/Tabs/StatelessTab.tsx';\n\n// Graphics\nexport { StorybookLogo } from './brand/StorybookLogo.tsx';\nexport { StorybookIcon } from './brand/StorybookIcon.tsx';\n\n// Loader\nexport { Loader } from './components/Loader/Loader.tsx';\nexport { ProgressSpinner } from './components/ProgressSpinner/ProgressSpinner.tsx';\n\n// Utils\nexport { getStoryHref } from './components/utils/getStoryHref.ts';\n\nexport * from './components/typography/DocumentFormatting.tsx';\nexport * from './components/typography/ResetWrapper.tsx';\n\nexport { withReset, codeCommon } from './components/typography/lib/common.tsx';\n\nexport { ClipboardCode } from './components/clipboard/ClipboardCode.tsx';\n\nexport const components = typography.components;\n\nconst resetComponents: Record<string, ElementType> = {};\n\nObject.keys(typography.components).forEach((key) => {\n  // eslint-disable-next-line react/display-name\n  resetComponents[key] = forwardRef((props, ref) => createElement(key, { ...props, ref }));\n});\n\nexport { resetComponents };\n"
  },
  {
    "path": "code/core/src/controls/README.md",
    "content": "# Storybook Controls\n\nThis directory contains the core Controls functionality for Storybook, which was previously in the `@storybook/addon-controls` package.\n\nControls gives you a graphical UI to interact with a component's arguments dynamically, without needing to code. It creates an addon panel next to your component examples (\"stories\"), so you can edit them live.\n\n## Directory Structure\n\n- `components/` - UI components for the Controls panel\n- `containers/` - Container components that manage state and data flow\n- `models/` - Data models and utilities\n- `runtime/` - Runtime-specific code\n- `constants.ts` - Constants and configuration\n- `decorator.ts` - Story decorator\n- `index.ts` - Main entry point\n- `manager.tsx` - Manager-side code\n- `preview.ts` - Preview-side code\n- `types.ts` - TypeScript types\n\n## Migration Status\n\nThis code was migrated from the `@storybook/addon-controls` package as part of the effort to consolidate core functionality into the main Storybook package.\n"
  },
  {
    "path": "code/core/src/controls/components/ControlsPanel.tsx",
    "content": "import React, { useEffect, useMemo, useState } from 'react';\n\nimport type { ArgTypes } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { dequal as deepEqual } from 'dequal';\nimport {\n  useArgTypes,\n  useArgs,\n  useGlobals,\n  useParameter,\n  useStorybookApi,\n  useStorybookState,\n} from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport {\n  ArgsTable,\n  type SortType,\n} from '../../../../addons/docs/src/blocks/components/ArgsTable/ArgsTable.tsx';\nimport type { PresetColor } from '../../../../addons/docs/src/blocks/controls/types.ts';\nimport { PARAM_KEY } from '../constants.ts';\nimport { SaveStory } from './SaveStory.tsx';\n\n// Remove undefined values (top-level only)\nconst clean = (obj: { [key: string]: any }) =>\n  Object.entries(obj).reduce(\n    (acc, [key, value]) => (value !== undefined ? Object.assign(acc, { [key]: value }) : acc),\n    {} as typeof obj\n  );\n\nconst AddonWrapper = styled.div<{ showSaveFromUI: boolean }>(({ showSaveFromUI, theme }) => ({\n  height: '100%',\n  maxHeight: '100vh',\n  paddingBottom: showSaveFromUI ? 41 : 0,\n  backgroundColor: theme.background.content,\n\n  table: {\n    backgroundColor: theme.background.app,\n  },\n}));\n\ninterface ControlsParameters {\n  sort?: SortType;\n  expanded?: boolean;\n  presetColors?: PresetColor[];\n  disableSaveFromUI?: boolean;\n}\n\ninterface ControlsPanelProps {\n  saveStory: () => Promise<unknown>;\n  createStory: (storyName: string) => Promise<unknown>;\n}\n\nexport const ControlsPanel = ({ saveStory, createStory }: ControlsPanelProps) => {\n  const api = useStorybookApi();\n  const [isLoading, setIsLoading] = useState(true);\n  const [args, updateArgs, resetArgs, initialArgs] = useArgs();\n  const [globals] = useGlobals();\n  const rows = useArgTypes();\n  const {\n    expanded,\n    sort,\n    presetColors,\n    disableSaveFromUI = false,\n  } = useParameter<ControlsParameters>(PARAM_KEY, {});\n  const { path, previewInitialized } = useStorybookState();\n  const storyData = api.getCurrentStoryData();\n\n  // If the story is prepared, then show the args table\n  // and reset the loading states\n  useEffect(() => {\n    if (previewInitialized) {\n      setIsLoading(false);\n    }\n  }, [previewInitialized]);\n\n  const hasControls = Object.values(rows).some((arg) => arg?.control);\n\n  const withPresetColors = Object.entries(rows).reduce((acc, [key, arg]) => {\n    const control = arg?.control;\n\n    if (typeof control !== 'object' || control?.type !== 'color' || control?.presetColors) {\n      acc[key] = arg;\n    } else {\n      acc[key] = { ...arg, control: { ...control, presetColors } };\n    }\n    return acc;\n  }, {} as ArgTypes);\n\n  const hasUpdatedArgs = useMemo(\n    () => !!args && !!initialArgs && !deepEqual(clean(args), clean(initialArgs)),\n    [args, initialArgs]\n  );\n\n  const showSaveFromUI =\n    hasControls &&\n    storyData.type === 'story' &&\n    storyData.subtype !== 'test' &&\n    hasUpdatedArgs &&\n    global.CONFIG_TYPE === 'DEVELOPMENT' &&\n    disableSaveFromUI !== true;\n\n  return (\n    <AddonWrapper showSaveFromUI={showSaveFromUI}>\n      <ArgsTable\n        key={path} // resets state when switching stories\n        compact={!expanded && hasControls}\n        rows={withPresetColors}\n        args={args}\n        globals={globals}\n        updateArgs={updateArgs}\n        resetArgs={resetArgs}\n        inAddonPanel\n        sort={sort}\n        isLoading={isLoading}\n      />\n      {showSaveFromUI && <SaveStory {...{ resetArgs, saveStory, createStory }} />}\n    </AddonWrapper>\n  );\n};\n"
  },
  {
    "path": "code/core/src/controls/components/SaveStory.stories.tsx",
    "content": "import React from 'react';\n\nimport { ModalDecorator } from 'storybook/internal/components';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { expect, fireEvent, fn, screen, within } from 'storybook/test';\n\nimport { SaveStory } from './SaveStory.tsx';\n\nconst meta = {\n  component: SaveStory,\n  args: {\n    saveStory: fn(),\n    createStory: fn(),\n    resetArgs: fn(),\n  },\n  parameters: {\n    layout: 'fullscreen',\n  },\n  decorators: [ModalDecorator],\n  tags: ['!vitest'],\n} satisfies Meta<typeof SaveStory>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {};\n\nexport const Creating = {\n  play: async ({ canvas }) => {\n    const createButton = await canvas.findByRole('button', { name: /Create/i });\n    await fireEvent.click(createButton);\n    await new Promise((resolve) => setTimeout(resolve, 300));\n  },\n} satisfies Story;\n\nexport const Created: Story = {\n  play: async ({ context }) => {\n    await Creating.play(context);\n\n    const dialog = await screen.findByRole('dialog');\n    const input = await within(dialog).findByRole('textbox');\n    await fireEvent.change(input, { target: { value: 'MyNewStory' } });\n    await fireEvent.submit(dialog.getElementsByTagName('form')[0]);\n    await expect(context.args.createStory).toHaveBeenCalledWith('MyNewStory');\n  },\n};\n\nexport const CreatingFailed: Story = {\n  args: {\n    // eslint-disable-next-line local-rules/no-uncategorized-errors\n    createStory: fn((...args) => Promise.reject<any>(new Error('Story already exists.'))),\n  },\n  play: Created.play,\n};\n"
  },
  {
    "path": "code/core/src/controls/components/SaveStory.tsx",
    "content": "import React from 'react';\n\nimport { Bar as BaseBar, Button, Form, Modal } from 'storybook/internal/components';\n\nimport { AddIcon, CheckIcon, UndoIcon } from '@storybook/icons';\n\nimport { keyframes, styled } from 'storybook/theming';\n\nconst slideIn = keyframes({\n  from: { transform: 'translateY(40px)' },\n  to: { transform: 'translateY(0)' },\n});\n\nconst highlight = keyframes({\n  from: { background: 'var(--highlight-bg-color)' },\n  to: {},\n});\n\nconst Container = styled.div({\n  containerType: 'size',\n  position: 'absolute',\n  bottom: 0,\n  width: '100%',\n  height: 41,\n  overflow: 'hidden',\n  zIndex: 1,\n});\n\nconst Bar = styled(BaseBar)(({ theme }) => ({\n  '--highlight-bg-color': theme.base === 'dark' ? '#153B5B' : '#E0F0FF',\n  paddingInline: 4,\n  animation: `${slideIn} 300ms, ${highlight} 2s`,\n  background: theme.background.bar,\n  borderTop: `1px solid ${theme.appBorderColor}`,\n  fontSize: theme.typography.size.s2,\n\n  '@container (max-width: 799px)': {\n    flexDirection: 'row',\n    justifyContent: 'flex-end',\n  },\n}));\n\nconst Info = styled.div({\n  display: 'flex',\n  flex: '99 0 auto',\n  alignItems: 'center',\n  marginInlineStart: 7,\n  marginInlineEnd: 10,\n  gap: 6,\n});\n\nconst Actions = styled.div(({ theme }) => ({\n  // We want actions to appear first and be hidden last on overflow,\n  // but the screenreader reading order must start with Info.\n  display: 'flex',\n  flex: '1 0 0',\n  alignItems: 'center',\n  gap: 2,\n  color: theme.textMutedColor,\n  fontSize: theme.typography.size.s2,\n}));\n\nconst Label = styled.div({\n  '@container (max-width: 799px)': {\n    lineHeight: 0,\n    textIndent: '-9999px',\n    '&::after': {\n      content: 'attr(data-short-label)',\n      display: 'block',\n      lineHeight: 'initial',\n      textIndent: '0',\n    },\n  },\n});\n\nconst ModalInput = styled(Form.Input)(({ theme }) => ({\n  '::placeholder': {\n    color: theme.color.mediumdark,\n  },\n  '&:invalid:not(:placeholder-shown)': {\n    boxShadow: `${theme.color.negative} 0 0 0 1px inset`,\n  },\n}));\n\ntype SaveStoryProps = {\n  saveStory: () => Promise<unknown>;\n  createStory: (storyName: string) => Promise<unknown>;\n  resetArgs: () => void;\n};\n\nexport const SaveStory = ({ saveStory, createStory, resetArgs }: SaveStoryProps) => {\n  const inputRef = React.useRef<HTMLInputElement>(null);\n  const [saving, setSaving] = React.useState(false);\n  const [creating, setCreating] = React.useState(false);\n  const [storyName, setStoryName] = React.useState('');\n  const [errorMessage, setErrorMessage] = React.useState(null);\n\n  const onSaveStory = async () => {\n    if (saving) {\n      return;\n    }\n    setSaving(true);\n    await saveStory().catch(() => {});\n    setSaving(false);\n  };\n\n  const onShowForm = () => {\n    setCreating(true);\n    setStoryName('');\n    setTimeout(() => inputRef.current?.focus(), 0);\n  };\n  const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n    const value = e.target.value\n      .replace(/^[^a-z]/i, '')\n      .replace(/[^a-z0-9-_ ]/gi, '')\n      .replaceAll(/([-_ ]+[a-z0-9])/gi, (match) => match.toUpperCase().replace(/[-_ ]/g, ''));\n    setStoryName(value.charAt(0).toUpperCase() + value.slice(1));\n  };\n  const onSubmitForm = async (event: React.FormEvent<HTMLFormElement>) => {\n    event.preventDefault();\n\n    if (saving) {\n      return;\n    }\n    try {\n      setErrorMessage(null);\n      setSaving(true);\n      await createStory(storyName.replace(/^[^a-z]/i, '').replaceAll(/[^a-z0-9]/gi, ''));\n      setCreating(false);\n      setSaving(false);\n    } catch (e: any) {\n      setErrorMessage(e.message);\n      setSaving(false);\n    }\n  };\n\n  const saveLabel = saving ? 'Saving changes to story' : 'Save changes to story';\n  const createLabel = 'Create new story with these settings';\n\n  return (\n    <Container id=\"save-from-controls\">\n      <Bar\n        innerStyle={{\n          flexDirection: 'row-reverse',\n          justifyContent: 'space-between',\n          flexWrap: 'wrap',\n        }}\n      >\n        <Actions>\n          <Button ariaLabel={saveLabel} tooltip={saveLabel} disabled={saving} onClick={onSaveStory}>\n            <CheckIcon />\n            <Label data-short-label=\"Save\">Update story</Label>\n          </Button>\n\n          <Button ariaLabel={createLabel} tooltip={createLabel} onClick={onShowForm}>\n            <AddIcon />\n            <Label data-short-label=\"New\">Create new story</Label>\n          </Button>\n\n          <Button ariaLabel=\"Reset changes\" onClick={() => resetArgs()}>\n            <UndoIcon />\n            <span>Reset</span>\n          </Button>\n        </Actions>\n\n        <Modal ariaLabel=\"Create new story\" width={350} open={creating} onOpenChange={setCreating}>\n          <Form onSubmit={onSubmitForm} id=\"create-new-story-form\">\n            <Modal.Content>\n              <Modal.Header>\n                <Modal.Title>Create new story</Modal.Title>\n                <Modal.Description>\n                  This will add a new story to your existing stories file.\n                </Modal.Description>\n              </Modal.Header>\n              <ModalInput\n                onChange={onChange}\n                placeholder=\"Story export name\"\n                readOnly={saving}\n                ref={inputRef}\n                value={storyName}\n              />\n              <Modal.Actions>\n                <Button\n                  ariaLabel={false}\n                  disabled={saving || !storyName}\n                  size=\"medium\"\n                  type=\"submit\"\n                  variant=\"solid\"\n                >\n                  Create\n                </Button>\n                <Modal.Close asChild>\n                  <Button ariaLabel={false} disabled={saving} size=\"medium\" type=\"reset\">\n                    Cancel\n                  </Button>\n                </Modal.Close>\n              </Modal.Actions>\n            </Modal.Content>\n          </Form>\n          {errorMessage && <Modal.Error>{errorMessage}</Modal.Error>}\n        </Modal>\n        <Info>\n          <Label data-short-label=\"Unsaved changes\">\n            You modified this story. Do you want to save your changes?\n          </Label>\n        </Info>\n      </Bar>\n    </Container>\n  );\n};\n"
  },
  {
    "path": "code/core/src/controls/components/Title.tsx",
    "content": "import React from 'react';\n\nimport { Badge } from 'storybook/internal/components';\n\nimport { useArgTypes, useStorybookApi } from 'storybook/manager-api';\n\nimport { ADDON_ID } from '../constants.ts';\n\nexport function Title() {\n  const api = useStorybookApi();\n  const selectedPanel = api.getSelectedPanel();\n  const rows = useArgTypes();\n  const controlsCount = Object.values(rows).filter(\n    (argType) => argType?.control && !argType?.table?.disable\n  ).length;\n  const suffix =\n    controlsCount === 0 ? null : (\n      <Badge compact status={selectedPanel === ADDON_ID ? 'active' : 'neutral'}>\n        {controlsCount}\n      </Badge>\n    );\n\n  return (\n    <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>\n      <span>Controls</span>\n      {suffix}\n    </div>\n  );\n}\n"
  },
  {
    "path": "code/core/src/controls/constants.ts",
    "content": "// ! please keep this in sync with addons/onboarding/src/constants.ts\nexport const ADDON_ID = 'addon-controls' as const;\nexport const PARAM_KEY = 'controls' as const;\n"
  },
  {
    "path": "code/core/src/controls/decorator.ts",
    "content": "import type { DecoratorFunction, PartialStoryFn, StoryContext } from 'storybook/internal/types';\n\n// The controls addon doesn't need a decorator as it operates through the manager UI\n// This is a placeholder to maintain API compatibility\nexport const withControls: DecoratorFunction = (storyFn: PartialStoryFn, context: StoryContext) => {\n  return storyFn(context);\n};\n"
  },
  {
    "path": "code/core/src/controls/index.ts",
    "content": "export * from './constants.ts';\n"
  },
  {
    "path": "code/core/src/controls/manager.tsx",
    "content": "import React from 'react';\n\nimport { AddonPanel } from 'storybook/internal/components';\nimport type {\n  ResponseData,\n  SaveStoryRequestPayload,\n  SaveStoryResponsePayload,\n} from 'storybook/internal/core-events';\nimport { SAVE_STORY_REQUEST, SAVE_STORY_RESPONSE } from 'storybook/internal/core-events';\nimport type { Args } from 'storybook/internal/csf';\n\nimport { FailedIcon, PassedIcon } from '@storybook/icons';\n\nimport { dequal as deepEqual } from 'dequal';\nimport { addons, experimental_requestResponse, types } from 'storybook/manager-api';\nimport { color } from 'storybook/theming';\n\nimport { ControlsPanel } from './components/ControlsPanel.tsx';\nimport { Title } from './components/Title.tsx';\nimport { ADDON_ID, PARAM_KEY } from './constants.ts';\nimport { trySelectStory } from '../manager/utils/trySelectStory.ts';\nimport { stringifyArgs } from './stringifyArgs.tsx';\n\nexport default addons.register(ADDON_ID, (api) => {\n  if (globalThis?.FEATURES?.controls) {\n    const channel = addons.getChannel();\n\n    const saveStory = async () => {\n      const data = api.getCurrentStoryData();\n\n      if (data.type !== 'story') {\n        throw new Error('Not a story');\n      }\n\n      try {\n        const response = await experimental_requestResponse<\n          SaveStoryRequestPayload,\n          SaveStoryResponsePayload\n        >(channel, SAVE_STORY_REQUEST, SAVE_STORY_RESPONSE, {\n          // Only send updated args\n          args: stringifyArgs(\n            Object.entries(data.args || {}).reduce<Args>((acc, [key, value]) => {\n              if (!deepEqual(value, data.initialArgs?.[key])) {\n                acc[key] = value;\n              }\n              return acc;\n            }, {})\n          ),\n          csfId: data.id,\n          importPath: data.importPath,\n        });\n\n        api.addNotification({\n          id: 'save-story-success',\n          icon: <PassedIcon color={color.positive} />,\n          content: {\n            headline: 'Story saved',\n            subHeadline: (\n              <>\n                Updated story <b>{response.sourceStoryName}</b>.\n              </>\n            ),\n          },\n          duration: 8_000,\n        });\n      } catch (error: any) {\n        api.addNotification({\n          id: 'save-story-error',\n          icon: <FailedIcon color={color.negative} />,\n          content: {\n            headline: 'Failed to save story',\n            subHeadline:\n              error?.message || 'Check the Storybook process on the command line for more details.',\n          },\n          duration: 8_000,\n        });\n        throw error;\n      }\n    };\n\n    const createStory = async (name: string) => {\n      const data = api.getCurrentStoryData();\n\n      if (data.type !== 'story') {\n        throw new Error('Not a story');\n      }\n\n      const response = await experimental_requestResponse<\n        SaveStoryRequestPayload,\n        SaveStoryResponsePayload\n      >(channel, SAVE_STORY_REQUEST, SAVE_STORY_RESPONSE, {\n        args: data.args && stringifyArgs(data.args),\n        csfId: data.id,\n        importPath: data.importPath,\n        name,\n      });\n\n      api.addNotification({\n        id: 'save-story-success',\n        icon: <PassedIcon color={color.positive} />,\n        content: {\n          headline: 'Story created',\n          subHeadline: (\n            <>\n              Added story <b>{response.newStoryName}</b> based on <b>{response.sourceStoryName}</b>.\n            </>\n          ),\n        },\n        duration: 8_000,\n        onClick: ({ onDismiss }) => {\n          onDismiss();\n          void trySelectStory(api.selectStory, response.newStoryId);\n        },\n      });\n    };\n\n    addons.add(ADDON_ID, {\n      title: Title,\n      type: types.PANEL,\n      paramKey: PARAM_KEY,\n      render: ({ active }) => {\n        if (!active || !api.getCurrentStoryData()) {\n          return null;\n        }\n        return (\n          <AddonPanel active={active} hasHorizontalScrollbar hasScrollbar>\n            <ControlsPanel saveStory={saveStory} createStory={createStory} />\n          </AddonPanel>\n        );\n      },\n    });\n\n    channel.on(SAVE_STORY_RESPONSE, (data: ResponseData<SaveStoryResponsePayload>) => {\n      if (!data.success) {\n        return;\n      }\n      const story = api.getCurrentStoryData();\n\n      if (story.type !== 'story') {\n        return;\n      }\n\n      api.resetStoryArgs(story);\n      if (data.payload.newStoryId) {\n        void trySelectStory(api.selectStory, data.payload.newStoryId);\n      }\n    });\n  }\n});\n"
  },
  {
    "path": "code/core/src/controls/preview.ts",
    "content": "import { definePreviewAddon } from 'storybook/internal/csf';\n\nimport type { ControlsTypes } from './types.ts';\n\nexport type { ControlsTypes };\n\nexport default definePreviewAddon<ControlsTypes>({\n  // Controls addon doesn't need any preview-side configuration\n  // It operates entirely through the manager UI\n});\n"
  },
  {
    "path": "code/core/src/controls/stringifyArgs.tsx",
    "content": "export const stringifyArgs = (args: Record<string, any>) =>\n  JSON.stringify(args, (_, value) => {\n    if (typeof value === 'function') {\n      return '__sb_empty_function_arg__';\n    }\n    return value;\n  });\n"
  },
  {
    "path": "code/core/src/controls/types.ts",
    "content": "export interface ControlsParameters {\n  /**\n   * Controls configuration\n   *\n   * @see https://storybook.js.org/docs/essentials/controls#parameters-1\n   */\n  controls?: {\n    /**\n     * Removes the addon panel and turns off the feature's behavior. If you wish to turn off this\n     * feature for the entire Storybook, you can set the option in your `main.js|ts` configuration\n     * file.\n     *\n     * @see https://storybook.js.org/docs/essentials/controls#disable\n     */\n    disable?: boolean;\n\n    /** Disable the ability to create or edit stories from the Controls panel */\n    disableSaveFromUI?: boolean;\n\n    /** Exclude specific properties from the Controls panel */\n    exclude?: string[] | RegExp;\n\n    /**\n     * Show the full documentation for each property in the Controls addon panel, including the\n     * description and default value.\n     */\n    expanded?: boolean;\n\n    /** Exclude only specific properties in the Controls panel */\n    include?: string[] | RegExp;\n\n    /**\n     * Custom control type matchers\n     *\n     * @see https://storybook.js.org/docs/essentials/controls#custom-control-type-matchers\n     */\n    matchers?: {\n      date?: RegExp;\n      color?: RegExp;\n    };\n\n    /**\n     * Preset color swatches for the color picker control\n     *\n     * @example PresetColors: [{ color: '#ff4785', title: 'Coral' }, 'rgba(0, 159, 183, 1)',\n     * '#fe4a49']\n     */\n    presetColors?: Array<string | { color: string; title?: string }>;\n\n    /** Controls sorting order */\n    sort?: 'none' | 'alpha' | 'requiredFirst';\n  };\n}\n\nexport interface ControlsTypes {\n  parameters: ControlsParameters;\n}\n"
  },
  {
    "path": "code/core/src/controls/typings.d.ts",
    "content": "declare var DOCS_OPTIONS: any;\ndeclare var CONFIG_TYPE: 'DEVELOPMENT' | 'PRODUCTION';\ndeclare var PREVIEW_URL: any;\n\ndeclare var __STORYBOOK_ADDONS_MANAGER: any;\ndeclare var RELEASE_NOTES_DATA: any;\n\ndeclare var FEATURES: import('storybook/internal/types').StorybookConfigRaw['features'];\n\ndeclare var REFS: any;\ndeclare var VERSIONCHECK: any;\ndeclare var LOGLEVEL: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent' | undefined;\n\ndeclare var __REACT__: any;\ndeclare var __REACT_DOM__: any;\ndeclare var __STORYBOOK_COMPONENTS__: any;\ndeclare var __STORYBOOK_CHANNELS__: any;\ndeclare var __STORYBOOK_CORE_EVENTS__: any;\ndeclare var __STORYBOOK_CORE_EVENTS_MANAGER_ERRORS__: any;\ndeclare var __STORYBOOK_ROUTER__: any;\ndeclare var __STORYBOOK_THEMING__: any;\ndeclare var __STORYBOOK_API__: any;\ndeclare var __STORYBOOK_ICONS__: any;\ndeclare var __STORYBOOK_CLIENT_LOGGER__: any;\ndeclare var __STORYBOOK_ADDONS_CHANNEL__: any;\ndeclare var __STORYBOOK_TYPES__: any;\ndeclare var sendTelemetryError: (error: any) => void;\n"
  },
  {
    "path": "code/core/src/core-events/data/argtypes-info.ts",
    "content": "import type { ArgTypes } from '../../csf/index.ts';\n\nexport interface ArgTypesRequestPayload {\n  storyId: string;\n}\n\nexport interface ArgTypesResponsePayload {\n  argTypes: ArgTypes;\n}\n"
  },
  {
    "path": "code/core/src/core-events/data/create-new-story.ts",
    "content": "export interface CreateNewStoryRequestPayload {\n  // The filepath of the component for which the Story should be generated for (relative to the project root)\n  componentFilePath: string;\n  // The name of the exported component\n  componentExportName: string;\n  // is default export\n  componentIsDefaultExport: boolean;\n  // The amount of exports in the file\n  componentExportCount: number;\n}\n\nexport interface CreateNewStoryResponsePayload {\n  // The story id\n  storyId: string;\n  // The story file path relative to the cwd\n  storyFilePath: string;\n  // The name of the story export in the file\n  exportedStoryName: string;\n}\n\nexport type CreateNewStoryErrorPayload = {\n  type: 'STORY_FILE_EXISTS';\n  kind: string;\n};\n"
  },
  {
    "path": "code/core/src/core-events/data/file-component-search.ts",
    "content": "export interface FileComponentSearchRequestPayload {}\n\nexport interface FileComponentSearchResponsePayload {\n  files: Array<{\n    // The filepath relative to the project root\n    filepath: string;\n    // Whether a corresponding story file exists\n    storyFileExists: boolean;\n    // A list of exported components\n    exportedComponents: Array<{\n      // the name of the exported component\n      name: string;\n      // True, if the exported component is a default export\n      default: boolean;\n    }> | null;\n  }> | null;\n}\n"
  },
  {
    "path": "code/core/src/core-events/data/open-in-editor.ts",
    "content": "export type OpenInEditorRequestPayload = { file: string; line?: number; column?: number };\n\nexport type OpenInEditorResponsePayload = {\n  file: string;\n  line?: number;\n  column?: number;\n  error: string | null;\n};\n"
  },
  {
    "path": "code/core/src/core-events/data/phases.ts",
    "content": "import type { Report } from 'storybook/preview-api';\n\nexport interface StoryFinishedPayload {\n  storyId: string;\n  status: 'error' | 'success';\n  reporters: Report[];\n}\n"
  },
  {
    "path": "code/core/src/core-events/data/request-response.ts",
    "content": "export type RequestData<Payload = void> = {\n  id: string;\n  payload: Payload;\n};\n\nexport type ResponseData<Payload = void, ErrorPayload extends Record<string, any> | void = void> =\n  | { id: string; success: true; error: null; payload: Payload }\n  | { id: string; success: false; error: string; payload?: ErrorPayload };\n"
  },
  {
    "path": "code/core/src/core-events/data/save-story.ts",
    "content": "export interface SaveStoryRequestPayload {\n  args: string | undefined;\n  csfId: string;\n  importPath: string;\n  name?: string;\n}\n\nexport interface SaveStoryResponsePayload {\n  csfId: string;\n  newStoryId?: string;\n  newStoryName?: string;\n  newStoryExportName?: string;\n  sourceFileContent?: string;\n  sourceFileName?: string;\n  sourceStoryName?: string;\n  sourceStoryExportName?: string;\n}\n"
  },
  {
    "path": "code/core/src/core-events/data/whats-new.ts",
    "content": "export interface WhatsNewCache {\n  lastDismissedPost?: string;\n  lastReadPost?: string;\n}\n\nexport type WhatsNewData =\n  | {\n      status: 'SUCCESS';\n      title: string;\n      url: string;\n      blogUrl?: string;\n      publishedAt: string;\n      excerpt: string;\n      postIsRead: boolean;\n      showNotification: boolean;\n      disableWhatsNewNotifications: boolean;\n    }\n  | {\n      status: 'ERROR';\n    };\n"
  },
  {
    "path": "code/core/src/core-events/index.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport * as EventsPackageExport from './index.ts';\nimport EventsDefaultExport, { CHANNEL_CREATED } from './index.ts';\n\ndescribe('Core Events', () => {\n  it('Should export the module as a namespace', () => {\n    expect(EventsPackageExport.CHANNEL_CREATED).toBe('channelCreated');\n  });\n  it('Should export all values in the default export', () => {\n    // this is intentional, for testing purposes\n\n    expect(EventsDefaultExport.CHANNEL_CREATED).toBe('channelCreated');\n  });\n  it('Should export values as named exports', () => {\n    expect(CHANNEL_CREATED).toBe('channelCreated');\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-events/index.ts",
    "content": "enum events {\n  CHANNEL_WS_DISCONNECT = 'channelWSDisconnect',\n  CHANNEL_CREATED = 'channelCreated',\n  // There was an error executing the config, likely an bug in the user's preview.js\n  CONFIG_ERROR = 'configError',\n  // The (v7 store) story index has changed, needs to refetch\n  STORY_INDEX_INVALIDATED = 'storyIndexInvalidated',\n  // When the preview boots, the first story is chosen via a selection specifier\n  STORY_SPECIFIED = 'storySpecified',\n  // Emitted by Provider.setOptions is called from an manager-addon or manager.js file\n  SET_CONFIG = 'setConfig',\n  // Emitted by the preview whenever the list of stories changes (in batches) - legacy pre-7.0 event\n  SET_STORIES = 'setStories',\n  // Emitted by the preview whenever the list of entries changes - legacy event for v6 store\n  SET_INDEX = 'setIndex',\n  // Set the current story selection in the preview\n  SET_CURRENT_STORY = 'setCurrentStory',\n  // The current story changed due to the above\n  CURRENT_STORY_WAS_SET = 'currentStoryWasSet',\n  // Force the current story to re-render, without changing args\n  FORCE_RE_RENDER = 'forceReRender',\n  // Force the current story to re-render from scratch, with its initial args\n  FORCE_REMOUNT = 'forceRemount',\n  // Request the story has been loaded into the store, ahead of time, before it's actually\n  PRELOAD_ENTRIES = 'preloadStories',\n  // The story has been loaded into the store, we have parameters/args/etc\n  STORY_PREPARED = 'storyPrepared',\n  // The a docs entry has been loaded into the store, we have parameters\n  DOCS_PREPARED = 'docsPrepared',\n  // The next 6 events are emitted by the StoryRenderer when rendering the current story\n  STORY_CHANGED = 'storyChanged',\n  STORY_UNCHANGED = 'storyUnchanged',\n  STORY_RENDERED = 'storyRendered',\n  STORY_FINISHED = 'storyFinished',\n  STORY_MISSING = 'storyMissing',\n  STORY_ERRORED = 'storyErrored',\n  STORY_THREW_EXCEPTION = 'storyThrewException',\n  // Emitted at various times during rendering\n  STORY_RENDER_PHASE_CHANGED = 'storyRenderPhaseChanged',\n  // Emitted when the story/component is hot updated (without rerendering)\n  STORY_HOT_UPDATED = 'storyHotUpdated',\n  // Emitted when the play function throws\n  PLAY_FUNCTION_THREW_EXCEPTION = 'playFunctionThrewException',\n  // Emitted when there were unhandled errors while playing the story\n  UNHANDLED_ERRORS_WHILE_PLAYING = 'unhandledErrorsWhilePlaying',\n  // Tell the story store to update (a subset of) a stories arg values\n  UPDATE_STORY_ARGS = 'updateStoryArgs',\n  // The values of a stories args just changed\n  STORY_ARGS_UPDATED = 'storyArgsUpdated',\n  // Reset either a single arg of a story all args of a story\n  RESET_STORY_ARGS = 'resetStoryArgs',\n  // Emitted after a filter is set\n  SET_FILTER = 'setFilter',\n  // Emitted by the preview at startup once it knows the initial set of globals+globalTypes\n  SET_GLOBALS = 'setGlobals',\n  // Tell the preview to update the value of a global\n  UPDATE_GLOBALS = 'updateGlobals',\n  // A global was just updated\n  GLOBALS_UPDATED = 'globalsUpdated',\n  REGISTER_SUBSCRIPTION = 'registerSubscription',\n  // Preview initialized for first-load-event\n  PREVIEW_INITIALIZED = 'previewInitialized',\n  // Tell the manager that the user pressed a key in the preview\n  PREVIEW_KEYDOWN = 'previewKeydown',\n  // Tell the preview that the builder is in progress\n  PREVIEW_BUILDER_PROGRESS = 'preview_builder_progress',\n  // Used in the manager to change the story selection\n  SELECT_STORY = 'selectStory',\n  STORIES_COLLAPSE_ALL = 'storiesCollapseAll',\n  STORIES_EXPAND_ALL = 'storiesExpandAll',\n  DOCS_RENDERED = 'docsRendered',\n  SHARED_STATE_CHANGED = 'sharedStateChanged',\n  SHARED_STATE_SET = 'sharedStateSet',\n  NAVIGATE_URL = 'navigateUrl',\n  UPDATE_QUERY_PARAMS = 'updateQueryParams',\n\n  REQUEST_WHATS_NEW_DATA = 'requestWhatsNewData',\n  RESULT_WHATS_NEW_DATA = 'resultWhatsNewData',\n  SET_WHATS_NEW_CACHE = 'setWhatsNewCache',\n  TOGGLE_WHATS_NEW_NOTIFICATIONS = 'toggleWhatsNewNotifications',\n  TELEMETRY_ERROR = 'telemetryError',\n\n  FILE_COMPONENT_SEARCH_REQUEST = 'fileComponentSearchRequest',\n  FILE_COMPONENT_SEARCH_RESPONSE = 'fileComponentSearchResponse',\n  SAVE_STORY_REQUEST = 'saveStoryRequest',\n  SAVE_STORY_RESPONSE = 'saveStoryResponse',\n  ARGTYPES_INFO_REQUEST = 'argtypesInfoRequest',\n  ARGTYPES_INFO_RESPONSE = 'argtypesInfoResponse',\n  CREATE_NEW_STORYFILE_REQUEST = 'createNewStoryfileRequest',\n  CREATE_NEW_STORYFILE_RESPONSE = 'createNewStoryfileResponse',\n  // Story discovery and testing flow\n  GHOST_STORIES_REQUEST = 'ghostStoriesRequest',\n  GHOST_STORIES_RESPONSE = 'ghostStoriesResponse',\n  // Open a file in the code editor\n  OPEN_IN_EDITOR_REQUEST = 'openInEditorRequest',\n  OPEN_IN_EDITOR_RESPONSE = 'openInEditorResponse',\n  // Emitted when the manager UI sets up a focus trap\n  MANAGER_INERT_ATTRIBUTE_CHANGED = 'managerInertAttributeChanged',\n\n  SHARE_STORY_LINK = 'shareStoryLink',\n  SHARE_ISOLATE_MODE = 'shareIsolateMode',\n  SHARE_POPOVER_OPENED = 'sharePopoverOpened',\n}\n\n// Enables: `import Events from ...`\nexport default events;\n\n// Enables: `import * as Events from ...` or `import { CHANNEL_CREATED } as Events from ...`\n// This is the preferred method\nexport const {\n  CHANNEL_WS_DISCONNECT,\n  CHANNEL_CREATED,\n  CONFIG_ERROR,\n  CREATE_NEW_STORYFILE_REQUEST,\n  CREATE_NEW_STORYFILE_RESPONSE,\n  CURRENT_STORY_WAS_SET,\n  DOCS_PREPARED,\n  DOCS_RENDERED,\n  FILE_COMPONENT_SEARCH_REQUEST,\n  FILE_COMPONENT_SEARCH_RESPONSE,\n  FORCE_RE_RENDER,\n  FORCE_REMOUNT,\n  GLOBALS_UPDATED,\n  NAVIGATE_URL,\n  PLAY_FUNCTION_THREW_EXCEPTION,\n  UNHANDLED_ERRORS_WHILE_PLAYING,\n  PRELOAD_ENTRIES,\n  PREVIEW_INITIALIZED,\n  PREVIEW_BUILDER_PROGRESS,\n  PREVIEW_KEYDOWN,\n  REGISTER_SUBSCRIPTION,\n  RESET_STORY_ARGS,\n  SELECT_STORY,\n  SET_CONFIG,\n  SET_CURRENT_STORY,\n  SET_FILTER,\n  SET_GLOBALS,\n  SET_INDEX,\n  SET_STORIES,\n  SHARED_STATE_CHANGED,\n  SHARED_STATE_SET,\n  STORIES_COLLAPSE_ALL,\n  STORIES_EXPAND_ALL,\n  STORY_ARGS_UPDATED,\n  STORY_CHANGED,\n  STORY_ERRORED,\n  STORY_INDEX_INVALIDATED,\n  STORY_MISSING,\n  STORY_PREPARED,\n  STORY_RENDER_PHASE_CHANGED,\n  STORY_RENDERED,\n  STORY_FINISHED,\n  STORY_SPECIFIED,\n  STORY_THREW_EXCEPTION,\n  STORY_UNCHANGED,\n  STORY_HOT_UPDATED,\n  UPDATE_GLOBALS,\n  UPDATE_QUERY_PARAMS,\n  UPDATE_STORY_ARGS,\n  REQUEST_WHATS_NEW_DATA,\n  RESULT_WHATS_NEW_DATA,\n  SET_WHATS_NEW_CACHE,\n  TOGGLE_WHATS_NEW_NOTIFICATIONS,\n  TELEMETRY_ERROR,\n  SAVE_STORY_REQUEST,\n  SAVE_STORY_RESPONSE,\n  ARGTYPES_INFO_REQUEST,\n  ARGTYPES_INFO_RESPONSE,\n  GHOST_STORIES_REQUEST,\n  GHOST_STORIES_RESPONSE,\n  OPEN_IN_EDITOR_REQUEST,\n  OPEN_IN_EDITOR_RESPONSE,\n  MANAGER_INERT_ATTRIBUTE_CHANGED,\n  SHARE_STORY_LINK,\n  SHARE_ISOLATE_MODE,\n  SHARE_POPOVER_OPENED,\n} = events;\n\nexport * from './data/create-new-story.ts';\nexport * from './data/file-component-search.ts';\nexport * from './data/argtypes-info.ts';\nexport * from './data/request-response.ts';\nexport * from './data/save-story.ts';\nexport * from './data/whats-new.ts';\nexport * from './data/phases.ts';\nexport * from './data/open-in-editor.ts';\n"
  },
  {
    "path": "code/core/src/core-server/README.md",
    "content": "# Storybook Core-server\n\nThis package contains common node-side functionality used among the different frameworks (React, RN, Vue 3, Ember, Angular, etc).\n\nIt contains:\n\n- CLI arg parsing\n- Storybook UI \"manager\" webpack configuration\n- `storybook dev` dev server\n- `storybook build` static builder\n- presets handling\n\nThe \"preview\" (aka iframe) side is implemented in pluggable builders:\n\n- `@storybook/builder-webpack5`\n\nThese builders abstract both the webpack dependencies as well as the various core configurations and loader/plugin dependencies provided out of the box with Storybook.\n"
  },
  {
    "path": "code/core/src/core-server/__for-testing__/main.ts",
    "content": "/// <reference types=\"node\" />\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport type { StorybookConfig } from '@storybook/react-webpack5';\n\nconst config: StorybookConfig = {\n  stories: [\n    '../../core/src/manager/**/*.stories.@(ts|tsx|js|jsx|mdx)',\n    '../../core/src/components/**/*.stories.@(ts|tsx|js|jsx|mdx)',\n    './../../addons/docs/**/*.stories.@(ts|tsx|js|jsx|mdx)',\n    './../../addons/interactions/**/*.stories.@(ts|tsx|js|jsx|mdx)',\n  ],\n  addons: [\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        sourceLoaderOptions: null,\n      },\n    },\n    '@storybook/addon-essentials',\n    '@storybook/addon-a11y',\n  ],\n  core: {\n    channelOptions: { maxDepth: 10 },\n    disableTelemetry: true,\n  },\n  logLevel: 'debug',\n  framework: {\n    name: '@storybook/react-webpack5',\n    options: {\n      strictMode: true,\n    },\n  },\n};\nmodule.exports = config;\n"
  },
  {
    "path": "code/core/src/core-server/__snapshots__/web-components-kitchen-sink_manager-dev-posix",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`web-components-kitchen-sink manager dev 1`] = `null`;\n"
  },
  {
    "path": "code/core/src/core-server/__snapshots__/web-components-kitchen-sink_manager-dev-windows",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`web-components-kitchen-sink manager dev 1`] = `\nObject {\n  \"entry\": Array [\n    \"ROOT\\\\\\\\lib\\\\\\\\core-client\\\\\\\\dist\\\\\\\\esm\\\\\\\\globals\\\\\\\\polyfills.js\",\n    \"ROOT\\\\\\\\lib\\\\\\\\core-client\\\\\\\\dist\\\\\\\\esm\\\\\\\\manager\\\\\\\\index.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\docs\\\\\\\\dist\\\\\\\\esm\\\\\\\\register.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\controls\\\\\\\\dist\\\\\\\\esm\\\\\\\\register.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\a11y\\\\\\\\dist\\\\\\\\esm\\\\\\\\register.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\actions\\\\\\\\dist\\\\\\\\esm\\\\\\\\register.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\backgrounds\\\\\\\\dist\\\\\\\\esm\\\\\\\\register.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\interactions\\\\\\\\dist\\\\\\\\esm\\\\\\\\register.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\links\\\\\\\\dist\\\\\\\\esm\\\\\\\\register.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\storysource\\\\\\\\dist\\\\\\\\esm\\\\\\\\register.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\viewport\\\\\\\\dist\\\\\\\\esm\\\\\\\\register.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\toolbars\\\\\\\\dist\\\\\\\\esm\\\\\\\\register.js\",\n  ],\n  \"keys\": Array [\n    \"name\",\n    \"mode\",\n    \"bail\",\n    \"devtool\",\n    \"entry\",\n    \"output\",\n    \"watchOptions\",\n    \"plugins\",\n    \"module\",\n    \"resolve\",\n    \"resolveLoader\",\n    \"recordsPath\",\n    \"performance\",\n    \"optimization\",\n  ],\n  \"module\": Object {\n    \"rules\": Array [\n      Object {\n        \"exclude\": Array [\n          \"NODE_MODULES/\",\n          \"/dist/\",\n        ],\n        \"include\": Array [\n          \"ROOT\",\n        ],\n        \"test\": \"/\\\\\\\\.(mjs|tsx?|jsx?)$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\babel-loader\\\\\\\\lib\\\\\\\\index.js\",\n            \"options\": Object {\n              \"babelrc\": false,\n              \"configFile\": false,\n              \"plugins\": Array [\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-shorthand-properties\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-block-scoping\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-decorators\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"legacy\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-class-properties\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-private-methods\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-export-default-from\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-syntax-dynamic-import\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-object-rest-spread\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"useBuiltIns\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-classes\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-arrow-functions\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-parameters\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-destructuring\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-spread\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-for-of\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\babel-plugin-macros\\\\\\\\dist\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-optional-chaining\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-nullish-coalescing-operator\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\babel-plugin-polyfill-corejs3\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"absoluteImports\": \"NODE_MODULES\\\\\\\\core-js\\\\\\\\index.js\",\n                    \"method\": \"usage-global\",\n                    \"version\": \"*\",\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-template-literals\\\\\\\\lib\\\\\\\\index.js\",\n              ],\n              \"presets\": Array [\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-env\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"shippedProposals\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-typescript\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-react\\\\\\\\lib\\\\\\\\index.js\",\n              ],\n              \"sourceType\": \"unambiguous\",\n            },\n          },\n        ],\n      },\n      Object {\n        \"include\": [Function],\n        \"test\": \"/\\\\\\\\.js$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\babel-loader\\\\\\\\lib\\\\\\\\index.js\",\n            \"options\": Object {\n              \"plugins\": Array [\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-shorthand-properties\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-block-scoping\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-decorators\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"legacy\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-class-properties\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-private-methods\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-export-default-from\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-syntax-dynamic-import\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-object-rest-spread\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"useBuiltIns\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-classes\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-arrow-functions\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-parameters\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-destructuring\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-spread\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-for-of\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\babel-plugin-macros\\\\\\\\dist\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-optional-chaining\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-nullish-coalescing-operator\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\babel-plugin-polyfill-corejs3\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"absoluteImports\": \"NODE_MODULES\\\\\\\\core-js\\\\\\\\index.js\",\n                    \"method\": \"usage-global\",\n                    \"version\": \"*\",\n                  },\n                ],\n              ],\n              \"presets\": Array [\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-env\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"modules\": false,\n                    \"shippedProposals\": true,\n                    \"targets\": \"defaults\",\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-react\\\\\\\\lib\\\\\\\\index.js\",\n              ],\n              \"sourceType\": \"unambiguous\",\n            },\n          },\n        ],\n      },\n      Object {\n        \"test\": \"/\\\\\\\\.css$/\",\n        \"use\": Array [\n          \"NODE_MODULES\\\\\\\\style-loader\\\\\\\\dist\\\\\\\\cjs.js\",\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\css-loader\\\\\\\\dist\\\\\\\\cjs.js\",\n            \"options\": Object {\n              \"importLoaders\": 1,\n            },\n          },\n        ],\n      },\n      Object {\n        \"loader\": \"NODE_MODULES\\\\\\\\file-loader\\\\\\\\dist\\\\\\\\cjs.js\",\n        \"options\": Object {\n          \"name\": \"static/media/[path][name].[ext]\",\n        },\n        \"test\": \"/\\\\\\\\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\\\\\\\\?.*)?$/\",\n      },\n      Object {\n        \"loader\": \"NODE_MODULES\\\\\\\\url-loader\\\\\\\\dist\\\\\\\\cjs.js\",\n        \"options\": Object {\n          \"limit\": 10000,\n          \"name\": \"static/media/[path][name].[ext]\",\n        },\n        \"test\": \"/\\\\\\\\.(mp4|webm|wav|mp3|m4a|aac|oga)(\\\\\\\\?.*)?$/\",\n      },\n    ],\n  },\n  \"plugins\": Array [\n    \"VirtualModulesPlugin\",\n    \"HtmlWebpackPlugin\",\n    \"CaseSensitivePathsPlugin\",\n    \"DefinePlugin\",\n  ],\n}\n`;\n"
  },
  {
    "path": "code/core/src/core-server/__snapshots__/web-components-kitchen-sink_manager-prod-posix",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`web-components-kitchen-sink manager prod 1`] = `null`;\n"
  },
  {
    "path": "code/core/src/core-server/__snapshots__/web-components-kitchen-sink_manager-prod-windows",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`web-components-kitchen-sink manager prod 1`] = `\nObject {\n  \"entry\": Array [\n    \"ROOT\\\\\\\\lib\\\\\\\\core-client\\\\\\\\dist\\\\\\\\esm\\\\\\\\globals\\\\\\\\polyfills.js\",\n    \"ROOT\\\\\\\\lib\\\\\\\\core-client\\\\\\\\dist\\\\\\\\esm\\\\\\\\manager\\\\\\\\index.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\docs\\\\\\\\dist\\\\\\\\esm\\\\\\\\register.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\controls\\\\\\\\dist\\\\\\\\esm\\\\\\\\register.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\a11y\\\\\\\\dist\\\\\\\\esm\\\\\\\\register.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\actions\\\\\\\\dist\\\\\\\\esm\\\\\\\\register.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\backgrounds\\\\\\\\dist\\\\\\\\esm\\\\\\\\register.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\interactions\\\\\\\\dist\\\\\\\\esm\\\\\\\\register.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\links\\\\\\\\dist\\\\\\\\esm\\\\\\\\register.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\storysource\\\\\\\\dist\\\\\\\\esm\\\\\\\\register.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\viewport\\\\\\\\dist\\\\\\\\esm\\\\\\\\register.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\toolbars\\\\\\\\dist\\\\\\\\esm\\\\\\\\register.js\",\n  ],\n  \"keys\": Array [\n    \"name\",\n    \"mode\",\n    \"bail\",\n    \"devtool\",\n    \"entry\",\n    \"output\",\n    \"watchOptions\",\n    \"plugins\",\n    \"module\",\n    \"resolve\",\n    \"resolveLoader\",\n    \"recordsPath\",\n    \"performance\",\n    \"optimization\",\n  ],\n  \"module\": Object {\n    \"rules\": Array [\n      Object {\n        \"exclude\": Array [\n          \"NODE_MODULES/\",\n          \"/dist/\",\n        ],\n        \"include\": Array [\n          \"ROOT\",\n        ],\n        \"test\": \"/\\\\\\\\.(mjs|tsx?|jsx?)$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\babel-loader\\\\\\\\lib\\\\\\\\index.js\",\n            \"options\": Object {\n              \"babelrc\": false,\n              \"configFile\": false,\n              \"plugins\": Array [\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-shorthand-properties\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-block-scoping\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-decorators\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"legacy\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-class-properties\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-private-methods\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-export-default-from\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-syntax-dynamic-import\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-object-rest-spread\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"useBuiltIns\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-classes\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-arrow-functions\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-parameters\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-destructuring\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-spread\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-for-of\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\babel-plugin-macros\\\\\\\\dist\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-optional-chaining\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-nullish-coalescing-operator\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\babel-plugin-polyfill-corejs3\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"absoluteImports\": \"NODE_MODULES\\\\\\\\core-js\\\\\\\\index.js\",\n                    \"method\": \"usage-global\",\n                    \"version\": \"*\",\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-template-literals\\\\\\\\lib\\\\\\\\index.js\",\n              ],\n              \"presets\": Array [\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-env\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"shippedProposals\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-typescript\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-react\\\\\\\\lib\\\\\\\\index.js\",\n              ],\n              \"sourceType\": \"unambiguous\",\n            },\n          },\n        ],\n      },\n      Object {\n        \"include\": [Function],\n        \"test\": \"/\\\\\\\\.js$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\babel-loader\\\\\\\\lib\\\\\\\\index.js\",\n            \"options\": Object {\n              \"plugins\": Array [\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-shorthand-properties\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-block-scoping\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-decorators\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"legacy\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-class-properties\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-private-methods\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-export-default-from\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-syntax-dynamic-import\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-object-rest-spread\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"useBuiltIns\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-classes\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-arrow-functions\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-parameters\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-destructuring\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-spread\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-for-of\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\babel-plugin-macros\\\\\\\\dist\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-optional-chaining\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-nullish-coalescing-operator\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\babel-plugin-polyfill-corejs3\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"absoluteImports\": \"NODE_MODULES\\\\\\\\core-js\\\\\\\\index.js\",\n                    \"method\": \"usage-global\",\n                    \"version\": \"*\",\n                  },\n                ],\n              ],\n              \"presets\": Array [\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-env\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"modules\": false,\n                    \"shippedProposals\": true,\n                    \"targets\": \"defaults\",\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-react\\\\\\\\lib\\\\\\\\index.js\",\n              ],\n              \"sourceType\": \"unambiguous\",\n            },\n          },\n        ],\n      },\n      Object {\n        \"test\": \"/\\\\\\\\.css$/\",\n        \"use\": Array [\n          \"NODE_MODULES\\\\\\\\style-loader\\\\\\\\dist\\\\\\\\cjs.js\",\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\css-loader\\\\\\\\dist\\\\\\\\cjs.js\",\n            \"options\": Object {\n              \"importLoaders\": 1,\n            },\n          },\n        ],\n      },\n      Object {\n        \"loader\": \"NODE_MODULES\\\\\\\\file-loader\\\\\\\\dist\\\\\\\\cjs.js\",\n        \"options\": Object {\n          \"name\": \"static/media/[name].[contenthash:8].[ext]\",\n        },\n        \"test\": \"/\\\\\\\\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\\\\\\\\?.*)?$/\",\n      },\n      Object {\n        \"loader\": \"NODE_MODULES\\\\\\\\url-loader\\\\\\\\dist\\\\\\\\cjs.js\",\n        \"options\": Object {\n          \"limit\": 10000,\n          \"name\": \"static/media/[name].[contenthash:8].[ext]\",\n        },\n        \"test\": \"/\\\\\\\\.(mp4|webm|wav|mp3|m4a|aac|oga)(\\\\\\\\?.*)?$/\",\n      },\n    ],\n  },\n  \"plugins\": Array [\n    \"VirtualModulesPlugin\",\n    \"HtmlWebpackPlugin\",\n    \"CaseSensitivePathsPlugin\",\n    \"DefinePlugin\",\n  ],\n}\n`;\n"
  },
  {
    "path": "code/core/src/core-server/__snapshots__/web-components-kitchen-sink_preview-dev-posix",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`web-components-kitchen-sink preview dev 1`] = `\nObject {\n  \"entry\": Array [\n    \"NODE_MODULES/webpack-hot-middleware/client.js?reload=true&quiet=false&noInfo=undefined\",\n    \"CWD/storybook-config-entry.js\",\n  ],\n  \"keys\": Array [\n    \"name\",\n    \"mode\",\n    \"bail\",\n    \"devtool\",\n    \"entry\",\n    \"output\",\n    \"stats\",\n    \"watchOptions\",\n    \"ignoreWarnings\",\n    \"plugins\",\n    \"module\",\n    \"resolve\",\n    \"optimization\",\n    \"performance\",\n    \"experiments\",\n  ],\n  \"module\": Object {\n    \"rules\": Array [\n      Object {\n        \"test\": \"/\\\\\\\\.m?js$/\",\n        \"type\": \"javascript/auto\",\n      },\n      Object {\n        \"resolve\": Object {\n          \"fullySpecified\": false,\n        },\n        \"test\": \"/\\\\\\\\.m?js$/\",\n      },\n      Object {\n        \"exclude\": \"NODE_MODULES/\",\n        \"include\": Array [\n          \"ROOT\",\n        ],\n        \"test\": \"/\\\\\\\\.(mjs|tsx?|jsx?)$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES/babel-loader/lib/index.js\",\n            \"options\": Object {\n              \"cacheDirectory\": \"NODE_MODULES/.cache/storybook/babel\",\n              \"overrides\": Array [\n                Object {\n                  \"plugins\": Array [\n                    \"NODE_MODULES/babel-plugin-named-exports-order/index.js\",\n                  ],\n                  \"test\": \"/\\\\\\\\.(story|stories).*$/\",\n                },\n              ],\n            },\n          },\n        ],\n      },\n      Object {\n        \"test\": \"/\\\\\\\\.md$/\",\n        \"type\": \"asset/source\",\n      },\n      Object {\n        \"test\": Array [\n          \"/src(.*)\\\\\\\\.js$/\",\n          \"/packages(\\\\\\\\/|\\\\\\\\\\\\\\\\)*(\\\\\\\\/|\\\\\\\\\\\\\\\\)src(\\\\\\\\/|\\\\\\\\\\\\\\\\)(.*)\\\\\\\\.js$/\",\n          \"NODE_MODULES(\\\\\\\\/|\\\\\\\\\\\\\\\\)lit-html(.*)\\\\\\\\.js$/\",\n          \"NODE_MODULES(\\\\\\\\/|\\\\\\\\\\\\\\\\)lit-element(.*)\\\\\\\\.js$/\",\n          \"NODE_MODULES(\\\\\\\\/|\\\\\\\\\\\\\\\\)@open-wc(.*)\\\\\\\\.js$/\",\n          \"NODE_MODULES(\\\\\\\\/|\\\\\\\\\\\\\\\\)@polymer(.*)\\\\\\\\.js$/\",\n          \"NODE_MODULES(\\\\\\\\/|\\\\\\\\\\\\\\\\)@vaadin(.*)\\\\\\\\.js$/\",\n        ],\n        \"use\": Object {\n          \"loader\": \"NODE_MODULES/babel-loader/lib/index.js\",\n          \"options\": Object {\n            \"compact\": false,\n            \"plugins\": Array [\n              \"NODE_MODULES/@babel/plugin-syntax-dynamic-import/lib/index.js\",\n              \"NODE_MODULES/@babel/plugin-syntax-import-meta/lib/index.js\",\n              Array [\n                \"NODE_MODULES/babel-plugin-bundled-import-meta/index.js\",\n                Object {\n                  \"importStyle\": \"baseURI\",\n                },\n              ],\n            ],\n            \"presets\": Array [\n              Array [\n                \"NODE_MODULES/@babel/preset-env/lib/index.js\",\n                Object {\n                  \"corejs\": 3,\n                  \"targets\": Object {\n                    \"chrome\": \"100\",\n                    \"esmodules\": true,\n                  },\n                  \"useBuiltIns\": \"entry\",\n                },\n              ],\n            ],\n          },\n        },\n      },\n      Object {\n        \"test\": \"/(stories|story)\\\\\\\\.mdx$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES/babel-loader/lib/index.js\",\n            \"options\": Object {\n              \"babelrc\": false,\n              \"cacheDirectory\": \"NODE_MODULES/.cache/storybook/babel\",\n              \"configFile\": false,\n              \"overrides\": Array [\n                Object {\n                  \"plugins\": Array [\n                    \"NODE_MODULES/babel-plugin-named-exports-order/index.js\",\n                  ],\n                  \"test\": \"/\\\\\\\\.(story|stories).*$/\",\n                },\n              ],\n              \"plugins\": Array [\n                Array [\n                  \"NODE_MODULES/@babel/plugin-transform-react-jsx/lib/index.js\",\n                  Object {\n                    \"pragma\": \"React.createElement\",\n                    \"pragmaFrag\": \"React.Fragment\",\n                  },\n                ],\n              ],\n            },\n          },\n          Object {\n            \"loader\": \"NODE_MODULES/@storybook/mdx1-csf/loader.js\",\n            \"options\": Object {\n              \"remarkPlugins\": Array [\n                [Function],\n                [Function],\n              ],\n              \"skipCsf\": false,\n            },\n          },\n        ],\n      },\n      Object {\n        \"exclude\": \"/(stories|story)\\\\\\\\.mdx$/\",\n        \"test\": \"/\\\\\\\\.mdx$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES/babel-loader/lib/index.js\",\n            \"options\": Object {\n              \"babelrc\": false,\n              \"cacheDirectory\": \"NODE_MODULES/.cache/storybook/babel\",\n              \"configFile\": false,\n              \"overrides\": Array [\n                Object {\n                  \"plugins\": Array [\n                    \"NODE_MODULES/babel-plugin-named-exports-order/index.js\",\n                  ],\n                  \"test\": \"/\\\\\\\\.(story|stories).*$/\",\n                },\n              ],\n              \"plugins\": Array [\n                Array [\n                  \"NODE_MODULES/@babel/plugin-transform-react-jsx/lib/index.js\",\n                  Object {\n                    \"pragma\": \"React.createElement\",\n                    \"pragmaFrag\": \"React.Fragment\",\n                  },\n                ],\n              ],\n            },\n          },\n          Object {\n            \"loader\": \"NODE_MODULES/@storybook/mdx1-csf/loader.js\",\n            \"options\": Object {\n              \"remarkPlugins\": Array [\n                [Function],\n                [Function],\n              ],\n              \"skipCsf\": true,\n            },\n          },\n        ],\n      },\n      Object {\n        \"sideEffects\": true,\n        \"test\": \"/\\\\\\\\.css$/\",\n        \"use\": Array [\n          \"NODE_MODULES/style-loader/dist/cjs.js\",\n          Object {\n            \"loader\": \"NODE_MODULES/css-loader/dist/cjs.js\",\n            \"options\": Object {\n              \"importLoaders\": 1,\n            },\n          },\n        ],\n      },\n      Object {\n        \"generator\": Object {\n          \"filename\": \"static/media/[path][name][ext]\",\n        },\n        \"test\": \"/\\\\\\\\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\\\\\\\\?.*)?$/\",\n        \"type\": \"asset/resource\",\n      },\n      Object {\n        \"generator\": Object {\n          \"filename\": \"static/media/[path][name][ext]\",\n        },\n        \"parser\": Object {\n          \"dataUrlCondition\": Object {\n            \"maxSize\": 10000,\n          },\n        },\n        \"test\": \"/\\\\\\\\.(mp4|webm|wav|mp3|m4a|aac|oga)(\\\\\\\\?.*)?$/\",\n        \"type\": \"asset\",\n      },\n    ],\n  },\n  \"plugins\": Array [\n    \"VirtualModulesPlugin\",\n    \"HtmlWebpackPlugin\",\n    \"DefinePlugin\",\n    \"ProvidePlugin\",\n    \"HotModuleReplacementPlugin\",\n    \"CaseSensitivePathsPlugin\",\n    \"ProgressPlugin\",\n  ],\n}\n`;\n"
  },
  {
    "path": "code/core/src/core-server/__snapshots__/web-components-kitchen-sink_preview-dev-windows",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`web-components-kitchen-sink preview dev 1`] = `\nObject {\n  \"entry\": Array [\n    \"ROOT\\\\\\\\lib\\\\\\\\core-client\\\\\\\\dist\\\\\\\\esm\\\\\\\\globals\\\\\\\\polyfills.js\",\n    \"ROOT\\\\\\\\lib\\\\\\\\core-client\\\\\\\\dist\\\\\\\\esm\\\\\\\\globals\\\\\\\\globals.js\",\n    \"NODE_MODULES\\\\\\\\webpack-hot-middleware\\\\\\\\client.js?reload=true&quiet=false&noInfo=undefined\",\n    \"ROOT\\\\\\\\storybook-init-framework-entry.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\docs\\\\\\\\dist\\\\\\\\esm\\\\\\\\frameworks\\\\\\\\common\\\\\\\\config.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\docs\\\\\\\\dist\\\\\\\\esm\\\\\\\\frameworks\\\\\\\\web-components\\\\\\\\config.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\app\\\\\\\\web-components\\\\\\\\dist\\\\\\\\esm\\\\\\\\client\\\\\\\\preview\\\\\\\\config-generated-config-entry.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\a11y\\\\\\\\dist\\\\\\\\esm\\\\\\\\a11yRunner.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\a11y\\\\\\\\dist\\\\\\\\esm\\\\\\\\a11yHighlight.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\actions\\\\\\\\dist\\\\\\\\esm\\\\\\\\preset\\\\\\\\addDecorator.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\actions\\\\\\\\dist\\\\\\\\esm\\\\\\\\preset\\\\\\\\addArgs.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\backgrounds\\\\\\\\dist\\\\\\\\esm\\\\\\\\preset\\\\\\\\addDecorator.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\backgrounds\\\\\\\\dist\\\\\\\\esm\\\\\\\\preset\\\\\\\\addParameter.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\interactions\\\\\\\\dist\\\\\\\\esm\\\\\\\\preset\\\\\\\\argsEnhancers.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\links\\\\\\\\dist\\\\\\\\esm\\\\\\\\preset\\\\\\\\addDecorator.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\examples\\\\\\\\web-components-kitchen-sink\\\\\\\\.storybook\\\\\\\\preview.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\generated-stories-entry.js\",\n  ],\n  \"keys\": Array [\n    \"name\",\n    \"mode\",\n    \"bail\",\n    \"devtool\",\n    \"entry\",\n    \"output\",\n    \"watchOptions\",\n    \"plugins\",\n    \"module\",\n    \"resolve\",\n    \"resolveLoader\",\n    \"optimization\",\n    \"performance\",\n  ],\n  \"module\": Object {\n    \"rules\": Array [\n      Object {\n        \"exclude\": \"NODE_MODULES/\",\n        \"include\": Array [\n          \"ROOT\",\n        ],\n        \"test\": \"/\\\\\\\\.(mjs|tsx?|jsx?)$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\babel-loader\\\\\\\\lib\\\\\\\\index.js\",\n            \"options\": Object {\n              \"cacheDirectory\": \"NODE_MODULES\\\\\\\\.cache\\\\\\\\storybook\\\\\\\\babel\",\n              \"plugins\": Array [\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-shorthand-properties\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-block-scoping\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-decorators\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"legacy\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-class-properties\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-private-methods\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-export-default-from\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-syntax-dynamic-import\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-object-rest-spread\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"useBuiltIns\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-classes\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-arrow-functions\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-parameters\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-destructuring\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-spread\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-for-of\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\babel-plugin-macros\\\\\\\\dist\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-optional-chaining\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-nullish-coalescing-operator\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\babel-plugin-polyfill-corejs3\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"absoluteImports\": \"NODE_MODULES\\\\\\\\core-js\\\\\\\\index.js\",\n                    \"method\": \"usage-global\",\n                    \"version\": \"*\",\n                  },\n                ],\n              ],\n              \"presets\": Array [\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-env\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"shippedProposals\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-typescript\\\\\\\\lib\\\\\\\\index.js\",\n              ],\n              \"sourceType\": \"unambiguous\",\n            },\n          },\n        ],\n      },\n      Object {\n        \"include\": [Function],\n        \"test\": \"/\\\\\\\\.js$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\babel-loader\\\\\\\\lib\\\\\\\\index.js\",\n            \"options\": Object {\n              \"plugins\": Array [\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-shorthand-properties\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-block-scoping\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-decorators\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"legacy\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-class-properties\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-private-methods\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-export-default-from\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-syntax-dynamic-import\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-object-rest-spread\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"useBuiltIns\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-classes\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-arrow-functions\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-parameters\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-destructuring\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-spread\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-for-of\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\babel-plugin-macros\\\\\\\\dist\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-optional-chaining\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-nullish-coalescing-operator\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\babel-plugin-polyfill-corejs3\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"absoluteImports\": \"NODE_MODULES\\\\\\\\core-js\\\\\\\\index.js\",\n                    \"method\": \"usage-global\",\n                    \"version\": \"*\",\n                  },\n                ],\n              ],\n              \"presets\": Array [\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-env\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"modules\": false,\n                    \"shippedProposals\": true,\n                    \"targets\": \"defaults\",\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-react\\\\\\\\lib\\\\\\\\index.js\",\n              ],\n              \"sourceType\": \"unambiguous\",\n            },\n          },\n        ],\n      },\n      Object {\n        \"test\": \"/\\\\\\\\.md$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\raw-loader\\\\\\\\dist\\\\\\\\cjs.js\",\n          },\n        ],\n      },\n      Object {\n        \"test\": Array [\n          \"/src(.*)\\\\\\\\.js$/\",\n          \"/packages(\\\\\\\\/|\\\\\\\\\\\\\\\\)*(\\\\\\\\/|\\\\\\\\\\\\\\\\)src(\\\\\\\\/|\\\\\\\\\\\\\\\\)(.*)\\\\\\\\.js$/\",\n          \"NODE_MODULES(\\\\\\\\/|\\\\\\\\\\\\\\\\)lit-html(.*)\\\\\\\\.js$/\",\n          \"NODE_MODULES(\\\\\\\\/|\\\\\\\\\\\\\\\\)lit-element(.*)\\\\\\\\.js$/\",\n          \"NODE_MODULES(\\\\\\\\/|\\\\\\\\\\\\\\\\)@open-wc(.*)\\\\\\\\.js$/\",\n          \"NODE_MODULES(\\\\\\\\/|\\\\\\\\\\\\\\\\)@polymer(.*)\\\\\\\\.js$/\",\n          \"NODE_MODULES(\\\\\\\\/|\\\\\\\\\\\\\\\\)@vaadin(.*)\\\\\\\\.js$/\",\n        ],\n        \"use\": Object {\n          \"loader\": \"NODE_MODULES\\\\\\\\babel-loader\\\\\\\\lib\\\\\\\\index.js\",\n          \"options\": Object {\n            \"babelrc\": false,\n            \"plugins\": Array [\n              \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-syntax-dynamic-import\\\\\\\\lib\\\\\\\\index.js\",\n              \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-syntax-import-meta\\\\\\\\lib\\\\\\\\index.js\",\n              Array [\n                \"NODE_MODULES\\\\\\\\babel-plugin-bundled-import-meta\\\\\\\\index.js\",\n                Object {\n                  \"importStyle\": \"baseURI\",\n                },\n              ],\n            ],\n            \"presets\": Array [\n              Array [\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-env\\\\\\\\lib\\\\\\\\index.js\",\n                Object {\n                  \"corejs\": 3,\n                  \"useBuiltIns\": \"entry\",\n                },\n              ],\n            ],\n          },\n        },\n      },\n      Object {\n        \"include\": \"NODE_MODULES\\\\\\\\\\\\\\\\acorn-jsx/\",\n        \"test\": \"/\\\\\\\\.js$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\babel-loader\\\\\\\\lib\\\\\\\\index.js\",\n            \"options\": Object {\n              \"presets\": Array [\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-env\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"modules\": \"commonjs\",\n                  },\n                ],\n              ],\n            },\n          },\n        ],\n      },\n      Object {\n        \"test\": \"/(stories|story)\\\\\\\\.mdx$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\babel-loader\\\\\\\\lib\\\\\\\\index.js\",\n            \"options\": Object {\n              \"babelrc\": false,\n              \"cacheDirectory\": \"NODE_MODULES\\\\\\\\.cache\\\\\\\\storybook\\\\\\\\babel\",\n              \"configFile\": false,\n              \"plugins\": Array [\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-shorthand-properties\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-block-scoping\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-decorators\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"legacy\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-class-properties\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-private-methods\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-export-default-from\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-syntax-dynamic-import\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-object-rest-spread\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"useBuiltIns\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-classes\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-arrow-functions\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-parameters\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-destructuring\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-spread\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-for-of\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\babel-plugin-macros\\\\\\\\dist\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-optional-chaining\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-nullish-coalescing-operator\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\babel-plugin-polyfill-corejs3\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"absoluteImports\": \"NODE_MODULES\\\\\\\\core-js\\\\\\\\index.js\",\n                    \"method\": \"usage-global\",\n                    \"version\": \"*\",\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-react-jsx\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"pragma\": \"React.createElement\",\n                    \"pragmaFrag\": \"React.Fragment\",\n                  },\n                ],\n              ],\n              \"presets\": Array [\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-env\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"shippedProposals\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-typescript\\\\\\\\lib\\\\\\\\index.js\",\n              ],\n              \"sourceType\": \"unambiguous\",\n            },\n          },\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\@mdx-js\\\\\\\\loader\\\\\\\\index.js\",\n            \"options\": Object {\n              \"compilers\": Array [\n                [Function],\n              ],\n              \"remarkPlugins\": Array [\n                [Function],\n                [Function],\n              ],\n            },\n          },\n        ],\n      },\n      Object {\n        \"exclude\": \"/(stories|story)\\\\\\\\.mdx$/\",\n        \"test\": \"/\\\\\\\\.mdx$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\babel-loader\\\\\\\\lib\\\\\\\\index.js\",\n            \"options\": Object {\n              \"babelrc\": false,\n              \"cacheDirectory\": \"NODE_MODULES\\\\\\\\.cache\\\\\\\\storybook\\\\\\\\babel\",\n              \"configFile\": false,\n              \"plugins\": Array [\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-shorthand-properties\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-block-scoping\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-decorators\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"legacy\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-class-properties\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-private-methods\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-export-default-from\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-syntax-dynamic-import\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-object-rest-spread\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"useBuiltIns\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-classes\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-arrow-functions\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-parameters\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-destructuring\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-spread\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-for-of\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\babel-plugin-macros\\\\\\\\dist\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-optional-chaining\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-nullish-coalescing-operator\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\babel-plugin-polyfill-corejs3\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"absoluteImports\": \"NODE_MODULES\\\\\\\\core-js\\\\\\\\index.js\",\n                    \"method\": \"usage-global\",\n                    \"version\": \"*\",\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-react-jsx\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"pragma\": \"React.createElement\",\n                    \"pragmaFrag\": \"React.Fragment\",\n                  },\n                ],\n              ],\n              \"presets\": Array [\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-env\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"shippedProposals\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-typescript\\\\\\\\lib\\\\\\\\index.js\",\n              ],\n              \"sourceType\": \"unambiguous\",\n            },\n          },\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\@mdx-js\\\\\\\\loader\\\\\\\\index.js\",\n            \"options\": Object {\n              \"remarkPlugins\": Array [\n                [Function],\n                [Function],\n              ],\n            },\n          },\n        ],\n      },\n      Object {\n        \"sideEffects\": true,\n        \"test\": \"/\\\\\\\\.css$/\",\n        \"use\": Array [\n          \"NODE_MODULES\\\\\\\\style-loader\\\\\\\\dist\\\\\\\\cjs.js\",\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\css-loader\\\\\\\\dist\\\\\\\\cjs.js\",\n            \"options\": Object {\n              \"importLoaders\": 1,\n            },\n          },\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\postcss-loader\\\\\\\\dist\\\\\\\\cjs.js\",\n            \"options\": Object {\n              \"postcssOptions\": Object {\n                \"config\": false,\n                \"plugins\": Array [\n                  [Function],\n                  [Function],\n                ],\n              },\n            },\n          },\n        ],\n      },\n      Object {\n        \"loader\": \"NODE_MODULES\\\\\\\\file-loader\\\\\\\\dist\\\\\\\\cjs.js\",\n        \"options\": Object {\n          \"esModule\": false,\n          \"name\": \"static/media/[path][name].[ext]\",\n        },\n        \"test\": \"/\\\\\\\\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\\\\\\\\?.*)?$/\",\n      },\n      Object {\n        \"loader\": \"NODE_MODULES\\\\\\\\url-loader\\\\\\\\dist\\\\\\\\cjs.js\",\n        \"options\": Object {\n          \"limit\": 10000,\n          \"name\": \"static/media/[path][name].[ext]\",\n        },\n        \"test\": \"/\\\\\\\\.(mp4|webm|wav|mp3|m4a|aac|oga)(\\\\\\\\?.*)?$/\",\n      },\n    ],\n  },\n  \"plugins\": Array [\n    \"FilterWarningsPlugin\",\n    \"VirtualModulesPlugin\",\n    \"HtmlWebpackPlugin\",\n    \"DefinePlugin\",\n    \"WatchMissingNodeModulesPlugin\",\n    \"HotModuleReplacementPlugin\",\n    \"CaseSensitivePathsPlugin\",\n    \"ProgressPlugin\",\n  ],\n}\n`;\n"
  },
  {
    "path": "code/core/src/core-server/__snapshots__/web-components-kitchen-sink_preview-prod-posix",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`web-components-kitchen-sink preview prod 1`] = `\nObject {\n  \"entry\": Array [\n    \"CWD/storybook-config-entry.js\",\n  ],\n  \"keys\": Array [\n    \"name\",\n    \"mode\",\n    \"bail\",\n    \"devtool\",\n    \"entry\",\n    \"output\",\n    \"stats\",\n    \"watchOptions\",\n    \"ignoreWarnings\",\n    \"plugins\",\n    \"module\",\n    \"resolve\",\n    \"optimization\",\n    \"performance\",\n    \"experiments\",\n  ],\n  \"module\": Object {\n    \"rules\": Array [\n      Object {\n        \"test\": \"/\\\\\\\\.m?js$/\",\n        \"type\": \"javascript/auto\",\n      },\n      Object {\n        \"resolve\": Object {\n          \"fullySpecified\": false,\n        },\n        \"test\": \"/\\\\\\\\.m?js$/\",\n      },\n      Object {\n        \"exclude\": \"NODE_MODULES/\",\n        \"include\": Array [\n          \"ROOT\",\n        ],\n        \"test\": \"/\\\\\\\\.(mjs|tsx?|jsx?)$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES/babel-loader/lib/index.js\",\n            \"options\": Object {\n              \"cacheDirectory\": \"NODE_MODULES/.cache/storybook/babel\",\n              \"overrides\": Array [\n                Object {\n                  \"plugins\": Array [\n                    \"NODE_MODULES/babel-plugin-named-exports-order/index.js\",\n                  ],\n                  \"test\": \"/\\\\\\\\.(story|stories).*$/\",\n                },\n              ],\n            },\n          },\n        ],\n      },\n      Object {\n        \"test\": \"/\\\\\\\\.md$/\",\n        \"type\": \"asset/source\",\n      },\n      Object {\n        \"test\": Array [\n          \"/src(.*)\\\\\\\\.js$/\",\n          \"/packages(\\\\\\\\/|\\\\\\\\\\\\\\\\)*(\\\\\\\\/|\\\\\\\\\\\\\\\\)src(\\\\\\\\/|\\\\\\\\\\\\\\\\)(.*)\\\\\\\\.js$/\",\n          \"NODE_MODULES(\\\\\\\\/|\\\\\\\\\\\\\\\\)lit-html(.*)\\\\\\\\.js$/\",\n          \"NODE_MODULES(\\\\\\\\/|\\\\\\\\\\\\\\\\)lit-element(.*)\\\\\\\\.js$/\",\n          \"NODE_MODULES(\\\\\\\\/|\\\\\\\\\\\\\\\\)@open-wc(.*)\\\\\\\\.js$/\",\n          \"NODE_MODULES(\\\\\\\\/|\\\\\\\\\\\\\\\\)@polymer(.*)\\\\\\\\.js$/\",\n          \"NODE_MODULES(\\\\\\\\/|\\\\\\\\\\\\\\\\)@vaadin(.*)\\\\\\\\.js$/\",\n        ],\n        \"use\": Object {\n          \"loader\": \"NODE_MODULES/babel-loader/lib/index.js\",\n          \"options\": Object {\n            \"compact\": false,\n            \"plugins\": Array [\n              \"NODE_MODULES/@babel/plugin-syntax-dynamic-import/lib/index.js\",\n              \"NODE_MODULES/@babel/plugin-syntax-import-meta/lib/index.js\",\n              Array [\n                \"NODE_MODULES/babel-plugin-bundled-import-meta/index.js\",\n                Object {\n                  \"importStyle\": \"baseURI\",\n                },\n              ],\n            ],\n            \"presets\": Array [\n              Array [\n                \"NODE_MODULES/@babel/preset-env/lib/index.js\",\n                Object {\n                  \"corejs\": 3,\n                  \"targets\": Object {\n                    \"chrome\": \"100\",\n                    \"esmodules\": true,\n                  },\n                  \"useBuiltIns\": \"entry\",\n                },\n              ],\n            ],\n          },\n        },\n      },\n      Object {\n        \"test\": \"/(stories|story)\\\\\\\\.mdx$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES/babel-loader/lib/index.js\",\n            \"options\": Object {\n              \"babelrc\": false,\n              \"cacheDirectory\": \"NODE_MODULES/.cache/storybook/babel\",\n              \"configFile\": false,\n              \"overrides\": Array [\n                Object {\n                  \"plugins\": Array [\n                    \"NODE_MODULES/babel-plugin-named-exports-order/index.js\",\n                  ],\n                  \"test\": \"/\\\\\\\\.(story|stories).*$/\",\n                },\n              ],\n              \"plugins\": Array [\n                Array [\n                  \"NODE_MODULES/@babel/plugin-transform-react-jsx/lib/index.js\",\n                  Object {\n                    \"pragma\": \"React.createElement\",\n                    \"pragmaFrag\": \"React.Fragment\",\n                  },\n                ],\n              ],\n            },\n          },\n          Object {\n            \"loader\": \"NODE_MODULES/@storybook/mdx1-csf/loader.js\",\n            \"options\": Object {\n              \"remarkPlugins\": Array [\n                [Function],\n                [Function],\n              ],\n              \"skipCsf\": false,\n            },\n          },\n        ],\n      },\n      Object {\n        \"exclude\": \"/(stories|story)\\\\\\\\.mdx$/\",\n        \"test\": \"/\\\\\\\\.mdx$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES/babel-loader/lib/index.js\",\n            \"options\": Object {\n              \"babelrc\": false,\n              \"cacheDirectory\": \"NODE_MODULES/.cache/storybook/babel\",\n              \"configFile\": false,\n              \"overrides\": Array [\n                Object {\n                  \"plugins\": Array [\n                    \"NODE_MODULES/babel-plugin-named-exports-order/index.js\",\n                  ],\n                  \"test\": \"/\\\\\\\\.(story|stories).*$/\",\n                },\n              ],\n              \"plugins\": Array [\n                Array [\n                  \"NODE_MODULES/@babel/plugin-transform-react-jsx/lib/index.js\",\n                  Object {\n                    \"pragma\": \"React.createElement\",\n                    \"pragmaFrag\": \"React.Fragment\",\n                  },\n                ],\n              ],\n            },\n          },\n          Object {\n            \"loader\": \"NODE_MODULES/@storybook/mdx1-csf/loader.js\",\n            \"options\": Object {\n              \"remarkPlugins\": Array [\n                [Function],\n                [Function],\n              ],\n              \"skipCsf\": true,\n            },\n          },\n        ],\n      },\n      Object {\n        \"sideEffects\": true,\n        \"test\": \"/\\\\\\\\.css$/\",\n        \"use\": Array [\n          \"NODE_MODULES/style-loader/dist/cjs.js\",\n          Object {\n            \"loader\": \"NODE_MODULES/css-loader/dist/cjs.js\",\n            \"options\": Object {\n              \"importLoaders\": 1,\n            },\n          },\n        ],\n      },\n      Object {\n        \"generator\": Object {\n          \"filename\": \"static/media/[name].[contenthash:8][ext]\",\n        },\n        \"test\": \"/\\\\\\\\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\\\\\\\\?.*)?$/\",\n        \"type\": \"asset/resource\",\n      },\n      Object {\n        \"generator\": Object {\n          \"filename\": \"static/media/[name].[contenthash:8][ext]\",\n        },\n        \"parser\": Object {\n          \"dataUrlCondition\": Object {\n            \"maxSize\": 10000,\n          },\n        },\n        \"test\": \"/\\\\\\\\.(mp4|webm|wav|mp3|m4a|aac|oga)(\\\\\\\\?.*)?$/\",\n        \"type\": \"asset\",\n      },\n    ],\n  },\n  \"plugins\": Array [\n    \"VirtualModulesPlugin\",\n    \"HtmlWebpackPlugin\",\n    \"DefinePlugin\",\n    \"ProvidePlugin\",\n    \"CaseSensitivePathsPlugin\",\n    \"ProgressPlugin\",\n  ],\n}\n`;\n"
  },
  {
    "path": "code/core/src/core-server/__snapshots__/web-components-kitchen-sink_preview-prod-windows",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`web-components-kitchen-sink preview prod 1`] = `\nObject {\n  \"entry\": Array [\n    \"ROOT\\\\\\\\lib\\\\\\\\core-client\\\\\\\\dist\\\\\\\\esm\\\\\\\\globals\\\\\\\\polyfills.js\",\n    \"ROOT\\\\\\\\lib\\\\\\\\core-client\\\\\\\\dist\\\\\\\\esm\\\\\\\\globals\\\\\\\\globals.js\",\n    \"ROOT\\\\\\\\storybook-init-framework-entry.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\docs\\\\\\\\dist\\\\\\\\esm\\\\\\\\frameworks\\\\\\\\common\\\\\\\\config.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\docs\\\\\\\\dist\\\\\\\\esm\\\\\\\\frameworks\\\\\\\\web-components\\\\\\\\config.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\app\\\\\\\\web-components\\\\\\\\dist\\\\\\\\esm\\\\\\\\client\\\\\\\\preview\\\\\\\\config-generated-config-entry.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\a11y\\\\\\\\dist\\\\\\\\esm\\\\\\\\a11yRunner.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\a11y\\\\\\\\dist\\\\\\\\esm\\\\\\\\a11yHighlight.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\actions\\\\\\\\dist\\\\\\\\esm\\\\\\\\preset\\\\\\\\addDecorator.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\actions\\\\\\\\dist\\\\\\\\esm\\\\\\\\preset\\\\\\\\addArgs.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\backgrounds\\\\\\\\dist\\\\\\\\esm\\\\\\\\preset\\\\\\\\addDecorator.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\backgrounds\\\\\\\\dist\\\\\\\\esm\\\\\\\\preset\\\\\\\\addParameter.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\interactions\\\\\\\\dist\\\\\\\\esm\\\\\\\\preset\\\\\\\\argsEnhancers.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\addons\\\\\\\\links\\\\\\\\dist\\\\\\\\esm\\\\\\\\preset\\\\\\\\addDecorator.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\examples\\\\\\\\web-components-kitchen-sink\\\\\\\\.storybook\\\\\\\\preview.js-generated-config-entry.js\",\n    \"ROOT\\\\\\\\generated-stories-entry.js\",\n  ],\n  \"keys\": Array [\n    \"name\",\n    \"mode\",\n    \"bail\",\n    \"devtool\",\n    \"entry\",\n    \"output\",\n    \"watchOptions\",\n    \"plugins\",\n    \"module\",\n    \"resolve\",\n    \"resolveLoader\",\n    \"optimization\",\n    \"performance\",\n  ],\n  \"module\": Object {\n    \"rules\": Array [\n      Object {\n        \"exclude\": \"NODE_MODULES/\",\n        \"include\": Array [\n          \"ROOT\",\n        ],\n        \"test\": \"/\\\\\\\\.(mjs|tsx?|jsx?)$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\babel-loader\\\\\\\\lib\\\\\\\\index.js\",\n            \"options\": Object {\n              \"cacheDirectory\": \"NODE_MODULES\\\\\\\\.cache\\\\\\\\storybook\\\\\\\\babel\",\n              \"plugins\": Array [\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-shorthand-properties\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-block-scoping\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-decorators\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"legacy\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-class-properties\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-private-methods\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-export-default-from\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-syntax-dynamic-import\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-object-rest-spread\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"useBuiltIns\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-classes\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-arrow-functions\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-parameters\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-destructuring\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-spread\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-for-of\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\babel-plugin-macros\\\\\\\\dist\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-optional-chaining\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-nullish-coalescing-operator\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\babel-plugin-polyfill-corejs3\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"absoluteImports\": \"NODE_MODULES\\\\\\\\core-js\\\\\\\\index.js\",\n                    \"method\": \"usage-global\",\n                    \"version\": \"*\",\n                  },\n                ],\n              ],\n              \"presets\": Array [\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-env\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"shippedProposals\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-typescript\\\\\\\\lib\\\\\\\\index.js\",\n              ],\n              \"sourceType\": \"unambiguous\",\n            },\n          },\n        ],\n      },\n      Object {\n        \"include\": [Function],\n        \"test\": \"/\\\\\\\\.js$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\babel-loader\\\\\\\\lib\\\\\\\\index.js\",\n            \"options\": Object {\n              \"plugins\": Array [\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-shorthand-properties\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-block-scoping\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-decorators\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"legacy\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-class-properties\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-private-methods\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-export-default-from\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-syntax-dynamic-import\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-object-rest-spread\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"useBuiltIns\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-classes\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-arrow-functions\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-parameters\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-destructuring\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-spread\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-for-of\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\babel-plugin-macros\\\\\\\\dist\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-optional-chaining\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-nullish-coalescing-operator\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\babel-plugin-polyfill-corejs3\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"absoluteImports\": \"NODE_MODULES\\\\\\\\core-js\\\\\\\\index.js\",\n                    \"method\": \"usage-global\",\n                    \"version\": \"*\",\n                  },\n                ],\n              ],\n              \"presets\": Array [\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-env\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"modules\": false,\n                    \"shippedProposals\": true,\n                    \"targets\": \"defaults\",\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-react\\\\\\\\lib\\\\\\\\index.js\",\n              ],\n              \"sourceType\": \"unambiguous\",\n            },\n          },\n        ],\n      },\n      Object {\n        \"test\": \"/\\\\\\\\.md$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\raw-loader\\\\\\\\dist\\\\\\\\cjs.js\",\n          },\n        ],\n      },\n      Object {\n        \"test\": Array [\n          \"/src(.*)\\\\\\\\.js$/\",\n          \"/packages(\\\\\\\\/|\\\\\\\\\\\\\\\\)*(\\\\\\\\/|\\\\\\\\\\\\\\\\)src(\\\\\\\\/|\\\\\\\\\\\\\\\\)(.*)\\\\\\\\.js$/\",\n          \"NODE_MODULES(\\\\\\\\/|\\\\\\\\\\\\\\\\)lit-html(.*)\\\\\\\\.js$/\",\n          \"NODE_MODULES(\\\\\\\\/|\\\\\\\\\\\\\\\\)lit-element(.*)\\\\\\\\.js$/\",\n          \"NODE_MODULES(\\\\\\\\/|\\\\\\\\\\\\\\\\)@open-wc(.*)\\\\\\\\.js$/\",\n          \"NODE_MODULES(\\\\\\\\/|\\\\\\\\\\\\\\\\)@polymer(.*)\\\\\\\\.js$/\",\n          \"NODE_MODULES(\\\\\\\\/|\\\\\\\\\\\\\\\\)@vaadin(.*)\\\\\\\\.js$/\",\n        ],\n        \"use\": Object {\n          \"loader\": \"NODE_MODULES\\\\\\\\babel-loader\\\\\\\\lib\\\\\\\\index.js\",\n          \"options\": Object {\n            \"babelrc\": false,\n            \"plugins\": Array [\n              \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-syntax-dynamic-import\\\\\\\\lib\\\\\\\\index.js\",\n              \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-syntax-import-meta\\\\\\\\lib\\\\\\\\index.js\",\n              Array [\n                \"NODE_MODULES\\\\\\\\babel-plugin-bundled-import-meta\\\\\\\\index.js\",\n                Object {\n                  \"importStyle\": \"baseURI\",\n                },\n              ],\n            ],\n            \"presets\": Array [\n              Array [\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-env\\\\\\\\lib\\\\\\\\index.js\",\n                Object {\n                  \"corejs\": 3,\n                  \"useBuiltIns\": \"entry\",\n                },\n              ],\n            ],\n          },\n        },\n      },\n      Object {\n        \"include\": \"NODE_MODULES\\\\\\\\\\\\\\\\acorn-jsx/\",\n        \"test\": \"/\\\\\\\\.js$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\babel-loader\\\\\\\\lib\\\\\\\\index.js\",\n            \"options\": Object {\n              \"presets\": Array [\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-env\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"modules\": \"commonjs\",\n                  },\n                ],\n              ],\n            },\n          },\n        ],\n      },\n      Object {\n        \"test\": \"/(stories|story)\\\\\\\\.mdx$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\babel-loader\\\\\\\\lib\\\\\\\\index.js\",\n            \"options\": Object {\n              \"babelrc\": false,\n              \"cacheDirectory\": \"NODE_MODULES\\\\\\\\.cache\\\\\\\\storybook\\\\\\\\babel\",\n              \"configFile\": false,\n              \"plugins\": Array [\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-shorthand-properties\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-block-scoping\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-decorators\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"legacy\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-class-properties\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-private-methods\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-export-default-from\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-syntax-dynamic-import\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-object-rest-spread\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"useBuiltIns\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-classes\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-arrow-functions\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-parameters\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-destructuring\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-spread\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-for-of\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\babel-plugin-macros\\\\\\\\dist\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-optional-chaining\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-nullish-coalescing-operator\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\babel-plugin-polyfill-corejs3\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"absoluteImports\": \"NODE_MODULES\\\\\\\\core-js\\\\\\\\index.js\",\n                    \"method\": \"usage-global\",\n                    \"version\": \"*\",\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-react-jsx\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"pragma\": \"React.createElement\",\n                    \"pragmaFrag\": \"React.Fragment\",\n                  },\n                ],\n              ],\n              \"presets\": Array [\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-env\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"shippedProposals\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-typescript\\\\\\\\lib\\\\\\\\index.js\",\n              ],\n              \"sourceType\": \"unambiguous\",\n            },\n          },\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\@mdx-js\\\\\\\\loader\\\\\\\\index.js\",\n            \"options\": Object {\n              \"compilers\": Array [\n                [Function],\n              ],\n              \"remarkPlugins\": Array [\n                [Function],\n                [Function],\n              ],\n            },\n          },\n        ],\n      },\n      Object {\n        \"exclude\": \"/(stories|story)\\\\\\\\.mdx$/\",\n        \"test\": \"/\\\\\\\\.mdx$/\",\n        \"use\": Array [\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\babel-loader\\\\\\\\lib\\\\\\\\index.js\",\n            \"options\": Object {\n              \"babelrc\": false,\n              \"cacheDirectory\": \"NODE_MODULES\\\\\\\\.cache\\\\\\\\storybook\\\\\\\\babel\",\n              \"configFile\": false,\n              \"plugins\": Array [\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-shorthand-properties\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-block-scoping\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-decorators\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"legacy\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-class-properties\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-private-methods\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-export-default-from\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-syntax-dynamic-import\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-object-rest-spread\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"useBuiltIns\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-classes\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-arrow-functions\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-parameters\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-destructuring\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-spread\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-for-of\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\babel-plugin-macros\\\\\\\\dist\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-optional-chaining\\\\\\\\lib\\\\\\\\index.js\",\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-proposal-nullish-coalescing-operator\\\\\\\\lib\\\\\\\\index.js\",\n                Array [\n                  \"NODE_MODULES\\\\\\\\babel-plugin-polyfill-corejs3\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"absoluteImports\": \"NODE_MODULES\\\\\\\\core-js\\\\\\\\index.js\",\n                    \"method\": \"usage-global\",\n                    \"version\": \"*\",\n                  },\n                ],\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\plugin-transform-react-jsx\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"pragma\": \"React.createElement\",\n                    \"pragmaFrag\": \"React.Fragment\",\n                  },\n                ],\n              ],\n              \"presets\": Array [\n                Array [\n                  \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-env\\\\\\\\lib\\\\\\\\index.js\",\n                  Object {\n                    \"loose\": true,\n                    \"shippedProposals\": true,\n                  },\n                ],\n                \"NODE_MODULES\\\\\\\\@babel\\\\\\\\preset-typescript\\\\\\\\lib\\\\\\\\index.js\",\n              ],\n              \"sourceType\": \"unambiguous\",\n            },\n          },\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\@mdx-js\\\\\\\\loader\\\\\\\\index.js\",\n            \"options\": Object {\n              \"remarkPlugins\": Array [\n                [Function],\n                [Function],\n              ],\n            },\n          },\n        ],\n      },\n      Object {\n        \"sideEffects\": true,\n        \"test\": \"/\\\\\\\\.css$/\",\n        \"use\": Array [\n          \"NODE_MODULES\\\\\\\\style-loader\\\\\\\\dist\\\\\\\\cjs.js\",\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\css-loader\\\\\\\\dist\\\\\\\\cjs.js\",\n            \"options\": Object {\n              \"importLoaders\": 1,\n            },\n          },\n          Object {\n            \"loader\": \"NODE_MODULES\\\\\\\\postcss-loader\\\\\\\\dist\\\\\\\\cjs.js\",\n            \"options\": Object {\n              \"postcssOptions\": Object {\n                \"config\": false,\n                \"plugins\": Array [\n                  [Function],\n                  [Function],\n                ],\n              },\n            },\n          },\n        ],\n      },\n      Object {\n        \"loader\": \"NODE_MODULES\\\\\\\\file-loader\\\\\\\\dist\\\\\\\\cjs.js\",\n        \"options\": Object {\n          \"esModule\": false,\n          \"name\": \"static/media/[name].[contenthash:8].[ext]\",\n        },\n        \"test\": \"/\\\\\\\\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\\\\\\\\?.*)?$/\",\n      },\n      Object {\n        \"loader\": \"NODE_MODULES\\\\\\\\url-loader\\\\\\\\dist\\\\\\\\cjs.js\",\n        \"options\": Object {\n          \"limit\": 10000,\n          \"name\": \"static/media/[name].[contenthash:8].[ext]\",\n        },\n        \"test\": \"/\\\\\\\\.(mp4|webm|wav|mp3|m4a|aac|oga)(\\\\\\\\?.*)?$/\",\n      },\n    ],\n  },\n  \"plugins\": Array [\n    \"FilterWarningsPlugin\",\n    \"VirtualModulesPlugin\",\n    \"HtmlWebpackPlugin\",\n    \"DefinePlugin\",\n    \"CaseSensitivePathsPlugin\",\n    \"ProgressPlugin\",\n  ],\n}\n`;\n"
  },
  {
    "path": "code/core/src/core-server/build-dev.ts",
    "content": "import { readFile } from 'node:fs/promises';\n\nimport {\n  JsPackageManagerFactory,\n  getConfigInfo,\n  getInterpretedFile,\n  getProjectRoot,\n  isWebContainer,\n  loadAllPresets,\n  loadMainConfig,\n  resolveAddonName,\n  resolvePathInStorybookCache,\n  validateFrameworkName,\n  versions,\n} from 'storybook/internal/common';\nimport { CLI_COLORS, deprecate, logger, prompt } from 'storybook/internal/node-logger';\nimport { MissingBuilderError, NoStatsForViteDevError } from 'storybook/internal/server-errors';\nimport { oneWayHash, telemetry } from 'storybook/internal/telemetry';\nimport type { BuilderOptions, CLIOptions, LoadOptions, Options } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { join, relative, resolve } from 'pathe';\nimport invariant from 'tiny-invariant';\nimport { dedent } from 'ts-dedent';\n\nimport Channel from '../channels/index.ts';\nimport { detectPnp } from '../cli/detect.ts';\nimport { resolvePackageDir } from '../shared/utils/module.ts';\nimport { storybookDevServer } from './dev-server.ts';\nimport { getWsToken } from './presets/wsToken.ts';\nimport { buildOrThrow } from './utils/build-or-throw.ts';\nimport { getManagerBuilder, getPreviewBuilder } from './utils/get-builders.ts';\nimport { getServerChannel } from './utils/get-server-channel.ts';\nimport { outputStartupInformation } from './utils/output-startup-information.ts';\nimport { outputStats } from './utils/output-stats.ts';\nimport { getServerAddresses, getServerChannelUrl, getServerPort } from './utils/server-address.ts';\nimport { getServer } from './utils/server-init.ts';\nimport { stripCommentsAndStrings } from './utils/strip-comments-and-strings.ts';\nimport { updateCheck } from './utils/update-check.ts';\nimport { warnOnIncompatibleAddons } from './utils/warnOnIncompatibleAddons.ts';\nimport { warnWhenUsingArgTypesRegex } from './utils/warnWhenUsingArgTypesRegex.ts';\n\nexport async function buildDevStandalone(\n  options: CLIOptions &\n    LoadOptions &\n    BuilderOptions & {\n      storybookVersion?: string;\n      previewConfigPath?: string;\n    }\n): Promise<{ port: number; address: string; networkAddress: string }> {\n  const { packageJson, versionUpdates } = options;\n  let { storybookVersion, previewConfigPath } = options;\n  const configDir = resolve(options.configDir);\n  if (packageJson) {\n    invariant(\n      packageJson.version !== undefined,\n      `Expected package.json#version to be defined in the \"${packageJson.name}\" package}`\n    );\n    storybookVersion = packageJson.version;\n    previewConfigPath = getConfigInfo(configDir).previewConfigPath ?? undefined;\n  } else {\n    if (!storybookVersion) {\n      storybookVersion = versions.storybook;\n    }\n  }\n  // updateInfo are cached, so this is typically pretty fast\n  const [port, versionCheck] = await Promise.all([\n    getServerPort(options.port, { exactPort: options.exactPort }),\n    versionUpdates\n      ? updateCheck(storybookVersion)\n      : Promise.resolve({ success: false, cached: false, data: {}, time: Date.now() }),\n  ]);\n\n  if (!options.ci && !options.smokeTest && options.port != null && port !== options.port) {\n    const shouldChangePort = await prompt.confirm({\n      message: dedent`\n        Port ${options.port} is not available. \n        Would you like to run Storybook on port ${port} instead?\n      `,\n      initialValue: true,\n    });\n    if (!shouldChangePort) {\n      process.exit(1);\n    }\n  }\n\n  const cacheKey = oneWayHash(relative(getProjectRoot(), configDir));\n\n  const cacheOutputDir = resolvePathInStorybookCache('public', cacheKey);\n  let outputDir = resolve(options.outputDir || cacheOutputDir);\n  if (options.smokeTest) {\n    outputDir = cacheOutputDir;\n  }\n\n  invariant(port, 'expected options to have a port');\n  const { address: localAddress, networkAddress } = getServerAddresses(\n    port,\n    options.host,\n    options.https ? 'https' : 'http',\n    options.initialPath\n  );\n\n  options.port = port;\n  options.versionCheck = versionCheck;\n  options.configType = 'DEVELOPMENT';\n  options.configDir = configDir;\n  options.cacheKey = cacheKey;\n  options.outputDir = outputDir;\n  options.serverChannelUrl = getServerChannelUrl(port, options);\n  options.localAddress = localAddress;\n  options.networkAddress = networkAddress;\n\n  // TODO: Remove in SB11\n  options.pnp = await detectPnp();\n  if (options.pnp) {\n    deprecate(dedent`\n      As of Storybook 10.0, PnP is deprecated.\n      If you are using PnP, you can continue to use Storybook 10.0, but we recommend migrating to a different package manager or linker-mode.\n\n      In future versions, PnP compatibility will be removed.\n    `);\n  }\n\n  const config = await loadMainConfig(options);\n  const { core, framework } = config;\n  const corePresets = [];\n\n  let frameworkName = typeof framework === 'string' ? framework : framework?.name;\n  if (!options.ignorePreview) {\n    validateFrameworkName(frameworkName);\n  }\n  if (frameworkName) {\n    corePresets.push(join(frameworkName, 'preset'));\n  }\n\n  frameworkName = frameworkName || 'custom';\n\n  const packageManager = JsPackageManagerFactory.getPackageManager({\n    configDir: options.configDir,\n  });\n\n  try {\n    await warnOnIncompatibleAddons(storybookVersion, packageManager);\n  } catch (e) {\n    logger.warn('Storybook failed to check addon compatibility');\n    logger.debug(`${e instanceof Error ? e.stack : String(e)}`);\n  }\n\n  // TODO: Bring back in 9.x when we officialy launch CSF4\n  // We need to consider more scenarios in this function, such as removing addons from main.ts\n  // try {\n  //   await syncStorybookAddons(config, previewConfigPath!);\n  // } catch (e) {}\n\n  try {\n    await warnWhenUsingArgTypesRegex(previewConfigPath, config);\n  } catch (e) {}\n\n  const server = await getServer(options);\n\n  // Load first pass: We need to determine the builder\n  // We need to do this because builders might introduce 'overridePresets' which we need to take into account\n  // We hope to remove this in SB8\n  let presets = await loadAllPresets({\n    corePresets,\n    overridePresets: [\n      import.meta.resolve('storybook/internal/core-server/presets/common-override-preset'),\n    ],\n    ...options,\n    isCritical: true,\n    channel: new Channel({\n      transports: [\n        {\n          setHandler: () => () => console.error('CHANNEL IS NOT READY YET'),\n          send: () => () => console.error('CHANNEL IS NOT READY YET'),\n        },\n      ],\n    }),\n  });\n\n  const { allowedHosts, renderer, builder, disableTelemetry } = await presets.apply('core', {});\n\n  // '0.0.0.0' binds to all interfaces, which is useful for Docker and other containerized environments.\n  // By default we allow requests from all hosts in this case, but the user should be made aware of the risk.\n  if (\n    options.host === '0.0.0.0' &&\n    (!allowedHosts || (allowedHosts !== true && allowedHosts.length === 0))\n  ) {\n    logger.warn(dedent`\n      --host is set to 0.0.0.0 but no allowedHosts are defined. Allowing all hosts.\n      To restrict allowed hosts, set core.allowedHosts in your main Storybook config.\n      See: https://storybook.js.org/docs/api/main-config/main-config-core\n    `);\n  }\n\n  if (!builder) {\n    throw new MissingBuilderError();\n  }\n\n  if (!options.disableTelemetry && !disableTelemetry) {\n    if (versionCheck.success && !versionCheck.cached) {\n      telemetry('version-update');\n    }\n  }\n\n  const resolvedPreviewBuilder = typeof builder === 'string' ? builder : builder.name;\n  const [previewBuilder, managerBuilder] = await Promise.all([\n    getPreviewBuilder(resolvedPreviewBuilder),\n    getManagerBuilder(),\n  ]);\n\n  if (resolvedPreviewBuilder.includes('builder-vite')) {\n    const deprecationMessage =\n      dedent(`Using CommonJS in your main configuration file is deprecated with Vite.\n              - Refer to the migration guide at https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#commonjs-with-vite-is-deprecated`);\n\n    const mainJsPath = getInterpretedFile(\n      resolve(options.configDir || '.storybook', 'main')\n    ) as string;\n    if (/\\.c[jt]s$/.test(mainJsPath)) {\n      deprecate(deprecationMessage);\n    }\n    const mainJsContent = await readFile(mainJsPath, { encoding: 'utf8' });\n    // Regex that matches any CommonJS-specific syntax, stolen from Vite: https://github.com/vitejs/vite/blob/91a18c2f7da796ff8217417a4bf189ddda719895/packages/vite/src/node/ssr/ssrExternal.ts#L87\n    const CJS_CONTENT_REGEX =\n      /\\bmodule\\.exports\\b|\\bexports[.[]|\\brequire\\s*\\(|\\bObject\\.(?:defineProperty|defineProperties|assign)\\s*\\(\\s*exports\\b/;\n    const strippedContent = stripCommentsAndStrings(mainJsContent);\n    if (CJS_CONTENT_REGEX.test(strippedContent)) {\n      deprecate(deprecationMessage);\n    }\n  }\n\n  const resolvedRenderer = renderer && resolveAddonName(options.configDir, renderer, options);\n\n  const channel = getServerChannel(server, {\n    token: getWsToken(),\n    host: options.host,\n    allowedHosts,\n    skipValidation: isWebContainer(),\n    localAddress,\n    networkAddress,\n  });\n\n  // Load second pass: all presets are applied in order\n  presets = await loadAllPresets({\n    corePresets: [\n      join(resolvePackageDir('storybook'), 'dist/core-server/presets/common-preset.js'),\n      ...(managerBuilder.corePresets || []),\n      ...(previewBuilder.corePresets || []),\n      ...(resolvedRenderer ? [resolvedRenderer] : []),\n      ...corePresets,\n    ],\n    overridePresets: [\n      ...(previewBuilder.overridePresets || []),\n      import.meta.resolve('storybook/internal/core-server/presets/common-override-preset'),\n    ],\n    ...options,\n    channel,\n  });\n\n  const features = await presets.apply('features');\n  global.FEATURES = features;\n  await presets.apply('experimental_serverChannel', channel);\n\n  const fullOptions: Options = {\n    ...options,\n    presets,\n    features,\n    channel,\n  };\n\n  const { managerResult, previewResult } = await buildOrThrow(async () =>\n    storybookDevServer(fullOptions, server)\n  );\n\n  const previewTotalTime = previewResult?.totalTime;\n  const managerTotalTime = managerResult?.totalTime;\n  const previewStats = previewResult?.stats;\n  const managerStats = managerResult?.stats;\n\n  const statsOption = options.webpackStatsJson || options.statsJson;\n  if (statsOption) {\n    const target = statsOption === true ? options.outputDir : statsOption;\n\n    await outputStats(target, previewStats);\n  }\n\n  if (options.smokeTest) {\n    const warnings: Error[] = [];\n    warnings.push(...(managerStats?.toJson()?.warnings || []));\n    try {\n      warnings.push(...(previewStats?.toJson()?.warnings || []));\n    } catch (err) {\n      if (err instanceof NoStatsForViteDevError) {\n        // pass, the Vite builder has no warnings in the stats object anyway,\n        // but no stats at all in dev mode\n      } else {\n        throw err;\n      }\n    }\n\n    const problems = warnings\n      .filter((warning) => !warning.message.includes(`export 'useInsertionEffect'`))\n      .filter((warning) => !warning.message.includes(`compilation but it's unused`))\n      .filter(\n        (warning) => !warning.message.includes(`Conflicting values for 'process.env.NODE_ENV'`)\n      );\n\n    if (problems.length > 0) {\n      logger.error('Smoke tests failed.');\n      logger.log(problems.map((p) => p.stack).join('\\n'));\n    } else {\n      logger.step(CLI_COLORS.success('Smoke tests passed, exiting.'));\n    }\n    logger.outro('');\n    process.exit(problems.length > 0 ? 1 : 0);\n  } else {\n    const name =\n      frameworkName.split('@storybook/').length > 1\n        ? frameworkName.split('@storybook/')[1]\n        : frameworkName;\n\n    if (!options.quiet) {\n      outputStartupInformation({\n        updateInfo: versionCheck,\n        version: storybookVersion,\n        name,\n        address: localAddress,\n        networkAddress,\n        allowedHosts,\n        managerTotalTime,\n        previewTotalTime,\n      });\n    }\n  }\n  return { port, address: localAddress, networkAddress };\n}\n"
  },
  {
    "path": "code/core/src/core-server/build-index.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { buildIndex } from './build-index.ts';\n\ndescribe('buildIndex', () => {\n  it.skip('should build index', async () => {\n    const index = await buildIndex({\n      configDir: `${__dirname}/utils/__mockdata__`,\n    });\n    expect(index).toMatchInlineSnapshot(`\n      {\n        \"entries\": {\n          \"my-component-a--story-one\": {\n            \"componentPath\": undefined,\n            \"id\": \"my-component-a--story-one\",\n            \"importPath\": \"./core/src/core-server/utils/__mockdata__/docs-id-generation/A.stories.jsx\",\n            \"name\": \"Story One\",\n            \"subtype\": \"story\",\n            \"tags\": [\n              \"dev\",\n              \"test\",\n              \"autodocs\",\n            ],\n            \"title\": \"A\",\n            \"type\": \"story\",\n          },\n          \"my-component-b--docs\": {\n            \"id\": \"my-component-b--docs\",\n            \"importPath\": \"./core/src/core-server/utils/__mockdata__/docs-id-generation/B.docs.mdx\",\n            \"name\": \"Docs\",\n            \"storiesImports\": [\n              \"./core/src/core-server/utils/__mockdata__/docs-id-generation/B.stories.jsx\",\n            ],\n            \"tags\": [\n              \"dev\",\n              \"test\",\n              \"attached-mdx\",\n            ],\n            \"title\": \"B\",\n            \"type\": \"docs\",\n          },\n          \"my-component-b--story-one\": {\n            \"componentPath\": undefined,\n            \"id\": \"my-component-b--story-one\",\n            \"importPath\": \"./core/src/core-server/utils/__mockdata__/docs-id-generation/B.stories.jsx\",\n            \"name\": \"Story One\",\n            \"subtype\": \"story\",\n            \"tags\": [\n              \"dev\",\n              \"test\",\n            ],\n            \"title\": \"B\",\n            \"type\": \"story\",\n          },\n        },\n        \"v\": 5,\n      }\n    `);\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/build-index.ts",
    "content": "import { writeFile } from 'node:fs/promises';\n\nimport { normalizeStories } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\nimport type { BuilderOptions, CLIOptions, LoadOptions } from 'storybook/internal/types';\n\nimport { loadStorybook } from './load.ts';\nimport { StoryIndexGenerator } from './utils/StoryIndexGenerator.ts';\n\nexport type BuildIndexOptions = CLIOptions & LoadOptions & BuilderOptions;\n\nexport const buildIndex = async (options: BuildIndexOptions) => {\n  const { presets } = await loadStorybook(options);\n  const [indexers, stories, docsOptions] = await Promise.all([\n    presets.apply('experimental_indexers', []),\n    presets.apply('stories', []),\n    presets.apply('docs'),\n  ]);\n\n  const { configDir } = options;\n  const workingDir = process.cwd();\n  const directories = {\n    configDir,\n    workingDir,\n  };\n  const normalizedStories = normalizeStories(stories, directories);\n\n  const generator = new StoryIndexGenerator(normalizedStories, {\n    ...directories,\n    indexers,\n    docs: docsOptions,\n    build: {},\n  });\n\n  await generator.initialize();\n  return generator.getIndex();\n};\n\nexport const buildIndexStandalone = async (options: BuildIndexOptions & { outputFile: string }) => {\n  const index = await buildIndex(options);\n  logger.info(`Writing index to ${options.outputFile}`);\n  await writeFile(options.outputFile, JSON.stringify(index));\n};\n"
  },
  {
    "path": "code/core/src/core-server/build-static.ts",
    "content": "import { cp, mkdir } from 'node:fs/promises';\nimport { rm } from 'node:fs/promises';\n\nimport { Channel } from 'storybook/internal/channels';\nimport {\n  loadAllPresets,\n  loadMainConfig,\n  logConfig,\n  resolveAddonName,\n} from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\nimport { getPrecedingUpgrade, telemetry } from 'storybook/internal/telemetry';\nimport type { BuilderOptions, CLIOptions, LoadOptions, Options } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { join, relative, resolve } from 'pathe';\nimport picocolors from 'picocolors';\n\nimport { resolvePackageDir } from '../shared/utils/module.ts';\nimport type { StoryIndexGenerator } from './utils/StoryIndexGenerator.ts';\nimport { buildOrThrow } from './utils/build-or-throw.ts';\nimport { copyAllStaticFilesRelativeToMain } from './utils/copy-all-static-files.ts';\nimport { getBuilders } from './utils/get-builders.ts';\nimport { writeIndexJson } from './utils/index-json.ts';\nimport { writeManifests } from './utils/manifests/manifests.ts';\nimport { extractStorybookMetadata } from './utils/metadata.ts';\nimport { outputStats } from './utils/output-stats.ts';\nimport { summarizeIndex } from './utils/summarizeIndex.ts';\n\nexport type BuildStaticStandaloneOptions = CLIOptions &\n  LoadOptions &\n  BuilderOptions & { outputDir: string };\n\nexport async function buildStaticStandalone(options: BuildStaticStandaloneOptions) {\n  options.configType = 'PRODUCTION';\n\n  if (options.outputDir === '') {\n    throw new Error(\"Won't remove current directory. Check your outputDir!\");\n  }\n\n  options.outputDir = resolve(options.outputDir);\n  options.configDir = resolve(options.configDir);\n\n  logger.step(`Cleaning outputDir: ${picocolors.cyan(relative(process.cwd(), options.outputDir))}`);\n  if (options.outputDir === '/') {\n    throw new Error(\"Won't remove directory '/'. Check your outputDir!\");\n  }\n  await rm(options.outputDir, { recursive: true, force: true }).catch(() => {});\n  await mkdir(options.outputDir, { recursive: true });\n\n  const config = await loadMainConfig(options);\n  const { framework } = config;\n  const corePresets = [];\n\n  const frameworkName = typeof framework === 'string' ? framework : framework?.name;\n  if (frameworkName) {\n    corePresets.push(join(frameworkName, 'preset'));\n  } else if (!options.ignorePreview) {\n    logger.warn(`you have not specified a framework in your ${options.configDir}/main.js`);\n  }\n\n  const commonPreset = join(\n    resolvePackageDir('storybook'),\n    'dist/core-server/presets/common-preset.js'\n  );\n  const commonOverridePreset = import.meta\n    .resolve('storybook/internal/core-server/presets/common-override-preset');\n\n  logger.step('Loading presets');\n\n  // no-op channel, as it's only relevant in dev mode\n  const channel = new Channel({});\n  let presets = await loadAllPresets({\n    corePresets: [commonPreset, ...corePresets],\n    overridePresets: [commonOverridePreset],\n    isCritical: true,\n    channel,\n    ...options,\n  });\n\n  const { renderer } = await presets.apply('core', {});\n  const build = await presets.apply('build', {});\n  const [previewBuilder, managerBuilder] = await getBuilders({\n    ...options,\n    presets,\n    build,\n    channel,\n  });\n\n  const resolvedRenderer = renderer\n    ? resolveAddonName(options.configDir, renderer, options)\n    : undefined;\n  presets = await loadAllPresets({\n    corePresets: [\n      commonPreset,\n      ...(managerBuilder.corePresets || []),\n      ...(previewBuilder.corePresets || []),\n      ...(resolvedRenderer ? [resolvedRenderer] : []),\n      ...corePresets,\n    ],\n    overridePresets: [...(previewBuilder.overridePresets || []), commonOverridePreset],\n    build,\n    channel,\n    ...options,\n  });\n\n  const [features, core, staticDirs] = await Promise.all([\n    presets.apply('features'),\n    presets.apply('core'),\n    presets.apply('staticDirs'),\n  ]);\n\n  const invokedBy = process.env.STORYBOOK_INVOKED_BY;\n  if (!core?.disableTelemetry && invokedBy) {\n    // NOTE: we don't await this event to avoid slowing things down.\n    // This could result in telemetry events being lost.\n    telemetry('test-run', { runner: invokedBy, watch: false }, { configDir: options.configDir });\n  }\n\n  const fullOptions: Options = {\n    ...options,\n    channel,\n    presets,\n    features,\n    build,\n  };\n\n  const effects: Promise<void>[] = [];\n\n  global.FEATURES = features;\n\n  if (!options.previewOnly) {\n    await buildOrThrow(async () =>\n      managerBuilder.build({ startTime: process.hrtime(), options: fullOptions })\n    );\n  }\n\n  if (staticDirs) {\n    effects.push(\n      copyAllStaticFilesRelativeToMain(staticDirs, options.outputDir, options.configDir)\n    );\n  }\n\n  const coreServerPublicDir = join(resolvePackageDir('storybook'), 'assets/browser');\n  effects.push(cp(coreServerPublicDir, options.outputDir, { recursive: true }));\n\n  let storyIndexGeneratorPromise: Promise<StoryIndexGenerator | undefined> =\n    Promise.resolve(undefined);\n  if (!options.ignorePreview) {\n    storyIndexGeneratorPromise = presets.apply<StoryIndexGenerator>('storyIndexGenerator');\n\n    effects.push(\n      writeIndexJson(\n        join(options.outputDir, 'index.json'),\n        storyIndexGeneratorPromise as Promise<StoryIndexGenerator>\n      )\n    );\n\n    if (features?.componentsManifest) {\n      effects.push(writeManifests(options.outputDir, presets));\n    }\n  }\n\n  if (!core?.disableProjectJson) {\n    effects.push(\n      extractStorybookMetadata(join(options.outputDir, 'project.json'), options.configDir)\n    );\n  }\n\n  if (options.debugWebpack) {\n    logConfig('Preview webpack config', await previewBuilder.getConfig(fullOptions));\n  }\n\n  if (options.ignorePreview) {\n    logger.info(`Not building preview`);\n  } else {\n    logger.info('Building preview..');\n  }\n\n  const startTime = process.hrtime();\n  await Promise.all([\n    ...(options.ignorePreview\n      ? []\n      : [\n          previewBuilder\n            .build({\n              startTime,\n              options: fullOptions,\n            })\n            .then(async (previewStats) => {\n              logger.trace({ message: 'Preview built', time: process.hrtime(startTime) });\n\n              const statsOption = options.webpackStatsJson || options.statsJson;\n              if (statsOption) {\n                const target = statsOption === true ? options.outputDir : statsOption;\n                await outputStats(target, previewStats);\n              }\n            })\n            .catch((error) => {\n              logger.error('Failed to build the preview');\n              process.exitCode = 1;\n              throw error;\n            }),\n        ]),\n    ...effects,\n  ]);\n\n  // Now the code has successfully built, we can count this as a 'build' event.\n  // NOTE: we don't send the 'build' event for test runs as we want to be as fast as possible.\n  if (!core?.disableTelemetry && !options.test) {\n    try {\n      const generator = await storyIndexGeneratorPromise;\n      const storyIndex = await generator?.getIndex();\n      const payload: any = {\n        precedingUpgrade: await getPrecedingUpgrade(),\n      };\n      if (storyIndex) {\n        Object.assign(payload, {\n          storyIndex: summarizeIndex(storyIndex),\n        });\n      }\n\n      await telemetry('build', payload, { configDir: options.configDir });\n    } catch (e) {\n      // Telemetry failures should not fail the build process\n      logger.debug?.(`Build telemetry failed: ${e instanceof Error ? e.message : String(e)}`);\n    }\n  }\n\n  logger.step(`Output directory: ${options.outputDir}`);\n}\n"
  },
  {
    "path": "code/core/src/core-server/change-detection/ChangeDetectionService.test.ts",
    "content": "import { join } from 'node:path';\n\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { logger } from 'storybook/internal/node-logger';\nimport type {\n  Builder,\n  ModuleGraph,\n  ModuleGraphChangeEvent,\n  ModuleNode,\n  StoryIndex,\n} from 'storybook/internal/types';\nimport { CHANGE_DETECTION_STATUS_TYPE_ID } from 'storybook/internal/types';\n\nimport {\n  createStatusStore,\n  UNIVERSAL_STATUS_STORE_OPTIONS,\n} from '../../shared/status-store/index.ts';\nimport { MockUniversalStore } from '../../shared/universal-store/mock.ts';\nimport { getChangeDetectionReadiness, internal_resetChangeDetectionReadiness } from './index.ts';\nimport { ChangeDetectionFailureError, ChangeDetectionUnavailableError } from './errors.ts';\nimport { ChangeDetectionService } from './ChangeDetectionService.ts';\n\nvi.mock('storybook/internal/node-logger', { spy: true });\n\nfunction createDeferred<T>() {\n  let resolve!: (value: T) => void;\n\n  return {\n    promise: new Promise<T>((fulfill) => {\n      resolve = fulfill;\n    }),\n    resolve,\n  };\n}\n\nfunction createModuleNode(file: string): ModuleNode {\n  return {\n    file,\n    type: 'js',\n    importers: new Set(),\n    importedModules: new Set(),\n  };\n}\n\nfunction createStoryIndex(\n  entries: Array<{ storyId: string; importPath: string; title?: string; name?: string }>\n): StoryIndex {\n  return {\n    v: 5,\n    entries: Object.fromEntries(\n      entries.map(({ storyId, importPath, title = 'Story', name = 'Default' }) => [\n        storyId,\n        {\n          id: storyId,\n          type: 'story',\n          subtype: 'story',\n          title,\n          name,\n          importPath,\n        },\n      ])\n    ),\n  };\n}\n\nfunction createBuilder() {\n  let onModuleGraphChange: ((event: ModuleGraphChangeEvent) => void) | undefined;\n\n  const builder = {\n    onModuleGraphChange: vi.fn((callback: (event: ModuleGraphChangeEvent) => void) => {\n      onModuleGraphChange = callback;\n      return vi.fn(() => {\n        onModuleGraphChange = undefined;\n      });\n    }),\n  } as unknown as Builder<unknown>;\n\n  return {\n    builder,\n    emit(moduleGraph: ModuleGraph) {\n      onModuleGraphChange?.({ type: 'moduleGraph', moduleGraph });\n    },\n    emitUnavailable(reason: string, error?: Error) {\n      onModuleGraphChange?.({ type: 'unavailable', reason, error });\n    },\n    emitError(error: Error) {\n      onModuleGraphChange?.({ type: 'error', error });\n    },\n  };\n}\n\ndescribe('ChangeDetectionService', () => {\n  const workingDir = '/repo';\n\n  beforeEach(() => {\n    vi.useFakeTimers();\n    internal_resetChangeDetectionReadiness();\n    vi.mocked(logger.info).mockImplementation(() => undefined);\n    vi.mocked(logger.warn).mockImplementation(() => undefined);\n    vi.mocked(logger.error).mockImplementation(() => undefined);\n  });\n\n  afterEach(() => {\n    vi.useRealTimers();\n    vi.clearAllMocks();\n    internal_resetChangeDetectionReadiness();\n  });\n\n  it('marks only the nearest stories as modified', async () => {\n    const buttonCss = createModuleNode('/repo/src/Button.module.css');\n    const buttonComponent = createModuleNode('/repo/src/Button.tsx');\n    const buttonStory = createModuleNode('/repo/src/Button.stories.tsx');\n    const headerComponent = createModuleNode('/repo/src/Header.tsx');\n    const headerStory = createModuleNode('/repo/src/Header.stories.tsx');\n\n    buttonCss.importers.add(buttonComponent);\n    buttonComponent.importers.add(buttonStory);\n    buttonComponent.importers.add(headerComponent);\n    headerComponent.importers.add(headerStory);\n\n    const moduleGraph: ModuleGraph = new Map([\n      ['/repo/src/Button.module.css', new Set([buttonCss])],\n      ['/repo/src/Button.tsx', new Set([buttonComponent])],\n      ['/repo/src/Button.stories.tsx', new Set([buttonStory])],\n      ['/repo/src/Header.tsx', new Set([headerComponent])],\n      ['/repo/src/Header.stories.tsx', new Set([headerStory])],\n    ]);\n    const storyIndex = createStoryIndex([\n      { storyId: 'button--primary', importPath: './src/Button.stories.tsx', title: 'Button' },\n      { storyId: 'header--default', importPath: './src/Header.stories.tsx', title: 'Header' },\n    ]);\n    const { getStatusStoreByTypeId } = createStatusStore({\n      universalStatusStore: new MockUniversalStore(UNIVERSAL_STATUS_STORE_OPTIONS),\n      environment: 'server',\n    });\n    const gitDiffProvider = {\n      getChangedFiles: vi.fn().mockResolvedValue({\n        changed: new Set(['src/Button.module.css']),\n        new: new Set(),\n      }),\n      getRepoRoot: vi.fn().mockResolvedValue(workingDir),\n    };\n    const { builder, emit } = createBuilder();\n    const service = new ChangeDetectionService({\n      storyIndexGeneratorPromise: Promise.resolve({\n        getIndex: vi.fn().mockResolvedValue(storyIndex),\n      } as never),\n      statusStore: getStatusStoreByTypeId(CHANGE_DETECTION_STATUS_TYPE_ID),\n      gitDiffProvider,\n      workingDir,\n    });\n\n    service.start(builder.onModuleGraphChange, true);\n    emit(moduleGraph);\n    await vi.runAllTimersAsync();\n\n    expect(getStatusStoreByTypeId(CHANGE_DETECTION_STATUS_TYPE_ID).getAll()).toEqual({\n      'button--primary': {\n        [CHANGE_DETECTION_STATUS_TYPE_ID]: {\n          storyId: 'button--primary',\n          typeId: CHANGE_DETECTION_STATUS_TYPE_ID,\n          value: 'status-value:modified',\n          title: '',\n          description: '',\n          data: {\n            changedFiles: ['src/Button.module.css'],\n          },\n          sidebarContextMenu: false,\n        },\n      },\n      'header--default': {\n        [CHANGE_DETECTION_STATUS_TYPE_ID]: {\n          storyId: 'header--default',\n          typeId: CHANGE_DETECTION_STATUS_TYPE_ID,\n          value: 'status-value:affected',\n          title: '',\n          description: '',\n          data: {\n            changedFiles: ['src/Button.module.css'],\n          },\n          sidebarContextMenu: false,\n        },\n      },\n    });\n    expect(await getChangeDetectionReadiness()).toEqual({ status: 'ready' });\n    await service.dispose();\n  });\n\n  it('marks new story files from the git new set and unsets them after they are reverted', async () => {\n    const storyIndex = createStoryIndex([\n      {\n        storyId: 'new-button--primary',\n        importPath: './src/NewButton.stories.tsx',\n        title: 'NewButton',\n      },\n    ]);\n    const { getStatusStoreByTypeId } = createStatusStore({\n      universalStatusStore: new MockUniversalStore(UNIVERSAL_STATUS_STORE_OPTIONS),\n      environment: 'server',\n    });\n    const gitDiffProvider = {\n      getChangedFiles: vi\n        .fn()\n        .mockResolvedValueOnce({\n          changed: new Set(),\n          new: new Set(['src/NewButton.stories.tsx']),\n        })\n        .mockResolvedValueOnce({\n          changed: new Set(),\n          new: new Set(),\n        }),\n      getRepoRoot: vi.fn().mockResolvedValue(workingDir),\n    };\n    const { builder, emit } = createBuilder();\n    const service = new ChangeDetectionService({\n      storyIndexGeneratorPromise: Promise.resolve({\n        getIndex: vi.fn().mockResolvedValue(storyIndex),\n      } as never),\n      statusStore: getStatusStoreByTypeId(CHANGE_DETECTION_STATUS_TYPE_ID),\n      gitDiffProvider,\n      workingDir,\n      debounceMs: 10,\n    });\n\n    service.start(builder.onModuleGraphChange, true);\n    emit(new Map());\n    await vi.runAllTimersAsync();\n\n    expect(getStatusStoreByTypeId(CHANGE_DETECTION_STATUS_TYPE_ID).getAll()).toEqual({\n      'new-button--primary': {\n        [CHANGE_DETECTION_STATUS_TYPE_ID]: {\n          storyId: 'new-button--primary',\n          typeId: CHANGE_DETECTION_STATUS_TYPE_ID,\n          value: 'status-value:new',\n          title: '',\n          description: '',\n          data: {\n            changedFiles: ['src/NewButton.stories.tsx'],\n          },\n          sidebarContextMenu: false,\n        },\n      },\n    });\n\n    emit(new Map());\n    await vi.runAllTimersAsync();\n\n    expect(getStatusStoreByTypeId(CHANGE_DETECTION_STATUS_TYPE_ID).getAll()).toEqual({\n      'new-button--primary': {},\n    });\n    await service.dispose();\n  });\n\n  it('logs unavailability when the builder does not expose module graph changes', async () => {\n    const { getStatusStoreByTypeId } = createStatusStore({\n      universalStatusStore: new MockUniversalStore(UNIVERSAL_STATUS_STORE_OPTIONS),\n      environment: 'server',\n    });\n    const service = new ChangeDetectionService({\n      storyIndexGeneratorPromise: Promise.resolve({\n        getIndex: vi.fn(),\n      } as never),\n      statusStore: getStatusStoreByTypeId(CHANGE_DETECTION_STATUS_TYPE_ID),\n      gitDiffProvider: {\n        getChangedFiles: vi.fn(),\n        getRepoRoot: vi.fn(),\n      },\n      workingDir,\n    });\n\n    service.start(undefined, true);\n\n    expect(logger.warn).toHaveBeenCalledWith(\n      'Change detection unavailable: Not supported by builder'\n    );\n    expect(await getChangeDetectionReadiness()).toEqual({\n      status: 'unavailable',\n      reason: 'builder does not support module graph',\n    });\n    await service.dispose();\n  });\n\n  it('resolves readiness when the builder reports change detection startup failure', async () => {\n    const { getStatusStoreByTypeId } = createStatusStore({\n      universalStatusStore: new MockUniversalStore(UNIVERSAL_STATUS_STORE_OPTIONS),\n      environment: 'server',\n    });\n    const gitDiffProvider = {\n      getChangedFiles: vi.fn(),\n      getRepoRoot: vi.fn(),\n    };\n    const { builder, emitError } = createBuilder();\n    const service = new ChangeDetectionService({\n      storyIndexGeneratorPromise: Promise.resolve({\n        getIndex: vi.fn(),\n      } as never),\n      statusStore: getStatusStoreByTypeId(CHANGE_DETECTION_STATUS_TYPE_ID),\n      gitDiffProvider,\n      workingDir,\n    });\n\n    service.start(builder.onModuleGraphChange, true);\n    emitError(new Error('module graph warmup failed'));\n    await Promise.resolve();\n\n    expect(logger.error).toHaveBeenCalledWith(\n      'Change detection failed: module graph warmup failed'\n    );\n    expect(await getChangeDetectionReadiness()).toEqual({\n      status: 'error',\n      error: expect.objectContaining({ message: 'module graph warmup failed' }),\n    });\n    expect(gitDiffProvider.getChangedFiles).not.toHaveBeenCalled();\n    await service.dispose();\n  });\n\n  it('keeps the previous statuses when a live rescan fails', async () => {\n    const storyIndex = createStoryIndex([\n      { storyId: 'button--primary', importPath: './src/Button.stories.tsx', title: 'Button' },\n    ]);\n    const { getStatusStoreByTypeId } = createStatusStore({\n      universalStatusStore: new MockUniversalStore(UNIVERSAL_STATUS_STORE_OPTIONS),\n      environment: 'server',\n    });\n    const gitDiffProvider = {\n      getChangedFiles: vi\n        .fn()\n        .mockResolvedValueOnce({\n          changed: new Set(['src/Button.stories.tsx']),\n          new: new Set(),\n        })\n        .mockRejectedValueOnce(new ChangeDetectionFailureError('scan blew up')),\n      getRepoRoot: vi.fn().mockResolvedValue(workingDir),\n    };\n    const { builder, emit } = createBuilder();\n    const service = new ChangeDetectionService({\n      storyIndexGeneratorPromise: Promise.resolve({\n        getIndex: vi.fn().mockResolvedValue(storyIndex),\n      } as never),\n      statusStore: getStatusStoreByTypeId(CHANGE_DETECTION_STATUS_TYPE_ID),\n      gitDiffProvider,\n      workingDir,\n      debounceMs: 10,\n    });\n\n    service.start(builder.onModuleGraphChange, true);\n    emit(new Map());\n    await vi.runAllTimersAsync();\n    emit(new Map());\n    await vi.runAllTimersAsync();\n\n    expect(getStatusStoreByTypeId(CHANGE_DETECTION_STATUS_TYPE_ID).getAll()).toEqual({\n      'button--primary': {\n        [CHANGE_DETECTION_STATUS_TYPE_ID]: {\n          storyId: 'button--primary',\n          typeId: CHANGE_DETECTION_STATUS_TYPE_ID,\n          value: 'status-value:modified',\n          title: '',\n          description: '',\n          data: {\n            changedFiles: ['src/Button.stories.tsx'],\n          },\n          sidebarContextMenu: false,\n        },\n      },\n    });\n    expect(logger.error).toHaveBeenCalledWith('Change detection failed: scan blew up');\n    await service.dispose();\n  });\n\n  it('does not apply scan results or rerun after disposal', async () => {\n    const storyIndex = createStoryIndex([\n      { storyId: 'button--primary', importPath: './src/Button.stories.tsx', title: 'Button' },\n    ]);\n    const buttonStory = createModuleNode('/repo/src/Button.stories.tsx');\n    const moduleGraph: ModuleGraph = new Map([\n      ['/repo/src/Button.stories.tsx', new Set([buttonStory])],\n    ]);\n    const { getStatusStoreByTypeId } = createStatusStore({\n      universalStatusStore: new MockUniversalStore(UNIVERSAL_STATUS_STORE_OPTIONS),\n      environment: 'server',\n    });\n    const changedFilesDeferred = createDeferred<{\n      changed: Set<string>;\n      new: Set<string>;\n    }>();\n    const gitDiffProvider = {\n      getChangedFiles: vi.fn().mockImplementation(() => changedFilesDeferred.promise),\n      getRepoRoot: vi.fn().mockResolvedValue(workingDir),\n    };\n    const { builder, emit } = createBuilder();\n    const service = new ChangeDetectionService({\n      storyIndexGeneratorPromise: Promise.resolve({\n        getIndex: vi.fn().mockResolvedValue(storyIndex),\n      } as never),\n      statusStore: getStatusStoreByTypeId(CHANGE_DETECTION_STATUS_TYPE_ID),\n      gitDiffProvider,\n      workingDir,\n      debounceMs: 0,\n    });\n\n    service.start(builder.onModuleGraphChange, true);\n    emit(moduleGraph);\n    await vi.advanceTimersByTimeAsync(0);\n    emit(moduleGraph);\n    await vi.advanceTimersByTimeAsync(0);\n    await service.dispose();\n\n    changedFilesDeferred.resolve({\n      changed: new Set(['src/Button.stories.tsx']),\n      new: new Set(),\n    });\n    await Promise.resolve();\n    await Promise.resolve();\n\n    expect(gitDiffProvider.getChangedFiles).toHaveBeenCalledTimes(1);\n    expect(getStatusStoreByTypeId(CHANGE_DETECTION_STATUS_TYPE_ID).getAll()).toEqual({});\n    await expect(\n      Promise.race([\n        getChangeDetectionReadiness().then(() => 'resolved'),\n        Promise.resolve('pending'),\n      ])\n    ).resolves.toBe('pending');\n  });\n\n  it('tears down after a permanently unavailable scan result', async () => {\n    const { getStatusStoreByTypeId } = createStatusStore({\n      universalStatusStore: new MockUniversalStore(UNIVERSAL_STATUS_STORE_OPTIONS),\n      environment: 'server',\n    });\n    const gitDiffProvider = {\n      getChangedFiles: vi\n        .fn()\n        .mockRejectedValue(new ChangeDetectionUnavailableError('not a git repository')),\n      getRepoRoot: vi.fn(),\n    };\n    const { builder, emit } = createBuilder();\n    const service = new ChangeDetectionService({\n      storyIndexGeneratorPromise: Promise.resolve({\n        getIndex: vi.fn(),\n      } as never),\n      statusStore: getStatusStoreByTypeId(CHANGE_DETECTION_STATUS_TYPE_ID),\n      gitDiffProvider,\n      workingDir,\n      debounceMs: 0,\n    });\n\n    service.start(builder.onModuleGraphChange, true);\n    emit(new Map());\n    await vi.advanceTimersByTimeAsync(0);\n    emit(new Map());\n    await vi.advanceTimersByTimeAsync(0);\n\n    expect(gitDiffProvider.getChangedFiles).toHaveBeenCalledTimes(1);\n    expect(logger.warn).toHaveBeenCalledWith('Change detection unavailable: not a git repository');\n    expect(await getChangeDetectionReadiness()).toEqual({\n      status: 'unavailable',\n      reason: 'not a git repository',\n      error: expect.any(ChangeDetectionUnavailableError),\n    });\n    await service.dispose();\n  });\n\n  it('prefers modified over affected when the same story is reached by multiple changed files', async () => {\n    const shared = createModuleNode('/repo/src/shared.ts');\n    const closeComponent = createModuleNode('/repo/src/Close.tsx');\n    const farComponent = createModuleNode('/repo/src/Far.tsx');\n    const story = createModuleNode('/repo/src/Button.stories.tsx');\n\n    shared.importers.add(closeComponent);\n    shared.importers.add(farComponent);\n    closeComponent.importers.add(story);\n    farComponent.importers.add(closeComponent);\n\n    const directChange = createModuleNode('/repo/src/direct.ts');\n    const indirectChange = createModuleNode('/repo/src/indirect.ts');\n    directChange.importers.add(closeComponent);\n    indirectChange.importers.add(farComponent);\n\n    const moduleGraph: ModuleGraph = new Map([\n      ['/repo/src/shared.ts', new Set([shared])],\n      ['/repo/src/Close.tsx', new Set([closeComponent])],\n      ['/repo/src/Far.tsx', new Set([farComponent])],\n      ['/repo/src/Button.stories.tsx', new Set([story])],\n      ['/repo/src/direct.ts', new Set([directChange])],\n      ['/repo/src/indirect.ts', new Set([indirectChange])],\n    ]);\n    const storyIndex = createStoryIndex([\n      { storyId: 'button--primary', importPath: './src/Button.stories.tsx', title: 'Button' },\n    ]);\n    const { getStatusStoreByTypeId } = createStatusStore({\n      universalStatusStore: new MockUniversalStore(UNIVERSAL_STATUS_STORE_OPTIONS),\n      environment: 'server',\n    });\n    const gitDiffProvider = {\n      getChangedFiles: vi.fn().mockResolvedValue({\n        changed: new Set(['src/direct.ts', 'src/indirect.ts']),\n        new: new Set(),\n      }),\n      getRepoRoot: vi.fn().mockResolvedValue(workingDir),\n    };\n    const { builder, emit } = createBuilder();\n    const service = new ChangeDetectionService({\n      storyIndexGeneratorPromise: Promise.resolve({\n        getIndex: vi.fn().mockResolvedValue(storyIndex),\n      } as never),\n      statusStore: getStatusStoreByTypeId(CHANGE_DETECTION_STATUS_TYPE_ID),\n      gitDiffProvider,\n      workingDir,\n    });\n\n    service.start(builder.onModuleGraphChange, true);\n    emit(moduleGraph);\n    await vi.runAllTimersAsync();\n\n    expect(getStatusStoreByTypeId(CHANGE_DETECTION_STATUS_TYPE_ID).getAll()).toEqual({\n      'button--primary': {\n        [CHANGE_DETECTION_STATUS_TYPE_ID]: {\n          storyId: 'button--primary',\n          typeId: CHANGE_DETECTION_STATUS_TYPE_ID,\n          value: 'status-value:modified',\n          title: '',\n          description: '',\n          data: {\n            changedFiles: ['src/direct.ts', 'src/indirect.ts'],\n          },\n          sidebarContextMenu: false,\n        },\n      },\n    });\n    await service.dispose();\n  });\n\n  it('stores changed files as normalized repo-relative paths', async () => {\n    const buttonCss = createModuleNode(join(workingDir, 'src', 'Button.module.css'));\n    const buttonComponent = createModuleNode(join(workingDir, 'src', 'Button.tsx'));\n    const buttonStory = createModuleNode(join(workingDir, 'src', 'Button.stories.tsx'));\n\n    buttonCss.importers.add(buttonComponent);\n    buttonComponent.importers.add(buttonStory);\n\n    const moduleGraph: ModuleGraph = new Map([\n      [join(workingDir, 'src', 'Button.module.css'), new Set([buttonCss])],\n      [join(workingDir, 'src', 'Button.tsx'), new Set([buttonComponent])],\n      [join(workingDir, 'src', 'Button.stories.tsx'), new Set([buttonStory])],\n    ]);\n    const storyIndex = createStoryIndex([\n      { storyId: 'button--primary', importPath: './src/Button.stories.tsx', title: 'Button' },\n    ]);\n    const { getStatusStoreByTypeId } = createStatusStore({\n      universalStatusStore: new MockUniversalStore(UNIVERSAL_STATUS_STORE_OPTIONS),\n      environment: 'server',\n    });\n    const gitDiffProvider = {\n      getChangedFiles: vi.fn().mockResolvedValue({\n        changed: new Set(['src/Button.module.css']),\n        new: new Set(),\n      }),\n      getRepoRoot: vi.fn().mockResolvedValue(workingDir),\n    };\n    const { builder, emit } = createBuilder();\n    const service = new ChangeDetectionService({\n      storyIndexGeneratorPromise: Promise.resolve({\n        getIndex: vi.fn().mockResolvedValue(storyIndex),\n      } as never),\n      statusStore: getStatusStoreByTypeId(CHANGE_DETECTION_STATUS_TYPE_ID),\n      gitDiffProvider,\n      workingDir,\n    });\n\n    service.start(builder.onModuleGraphChange, true);\n    emit(moduleGraph);\n    await vi.runAllTimersAsync();\n\n    expect(getStatusStoreByTypeId(CHANGE_DETECTION_STATUS_TYPE_ID).getAll()).toEqual({\n      'button--primary': {\n        [CHANGE_DETECTION_STATUS_TYPE_ID]: {\n          storyId: 'button--primary',\n          typeId: CHANGE_DETECTION_STATUS_TYPE_ID,\n          value: 'status-value:modified',\n          title: '',\n          description: '',\n          data: {\n            changedFiles: ['src/Button.module.css'],\n          },\n          sidebarContextMenu: false,\n        },\n      },\n    });\n    await service.dispose();\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/change-detection/ChangeDetectionService.ts",
    "content": "import { relative, resolve } from 'node:path';\n\nimport { logger } from 'storybook/internal/node-logger';\nimport type {\n  Builder,\n  ModuleGraph,\n  ModuleGraphChangeEvent,\n  Status,\n  StatusStoreByTypeId,\n} from 'storybook/internal/types';\nimport { CHANGE_DETECTION_STATUS_TYPE_ID } from 'storybook/internal/types';\n\nimport type { StoryIndexGenerator } from '../utils/StoryIndexGenerator.ts';\nimport { ChangeDetectionFailureError, ChangeDetectionUnavailableError } from './errors.ts';\nimport { GitDiffProvider } from './GitDiffProvider.ts';\nimport { resetChangeDetectionReadiness, setChangeDetectionReadiness } from './readiness.ts';\nimport { findAffectedStoryFiles } from './trace-changed.ts';\n\nconst CHANGE_DETECTION_DEBOUNCE_MS = 200;\n\nfunction isSameStatus(a: Status | undefined, b: Status): boolean {\n  if (!a) {\n    return false;\n  }\n\n  return (\n    a.storyId === b.storyId &&\n    a.typeId === b.typeId &&\n    a.value === b.value &&\n    a.title === b.title &&\n    a.description === b.description &&\n    a.sidebarContextMenu === b.sidebarContextMenu &&\n    JSON.stringify(a.data) === JSON.stringify(b.data)\n  );\n}\n\nfunction getStoryIdsByAbsolutePath(\n  storyIndex: Awaited<ReturnType<StoryIndexGenerator['getIndex']>>,\n  workingDir: string\n): Map<string, Set<string>> {\n  const storyIdsByFile = new Map<string, Set<string>>();\n\n  Object.values(storyIndex.entries).forEach((entry) => {\n    if (entry.type !== 'story' || entry.importPath.startsWith('virtual:')) {\n      return;\n    }\n\n    const absolutePath = resolve(workingDir, entry.importPath);\n    // logger.info(`Story ${entry.id} absolute path: ${absolutePath}`);\n    const storyIds = storyIdsByFile.get(absolutePath) ?? new Set<string>();\n    storyIds.add(entry.id);\n    storyIdsByFile.set(absolutePath, storyIds);\n  });\n\n  return storyIdsByFile;\n}\n\nfunction mergeStatusValues(\n  previousValue: Status['value'] | undefined,\n  nextValue: Status['value']\n): Status['value'] {\n  if (previousValue === 'status-value:new' || nextValue === 'status-value:new') {\n    return 'status-value:new';\n  }\n\n  if (previousValue === 'status-value:modified' || nextValue === 'status-value:modified') {\n    return 'status-value:modified';\n  }\n\n  if (previousValue === 'status-value:affected' || nextValue === 'status-value:affected') {\n    return 'status-value:affected';\n  }\n\n  return nextValue;\n}\n\nfunction toRepoRelativePath(repoRoot: string, filePath: string): string {\n  const relativePath = relative(repoRoot, filePath);\n  return relativePath.startsWith('\\\\\\\\?\\\\') ? relativePath : relativePath.replace(/\\\\/g, '/');\n}\n\n/**\n * Coordinates change detection by listening to builder module-graph updates, resolving changed\n * files from git, mapping those changes to affected stories, and publishing the resulting story\n * statuses to the status store.\n */\nexport class ChangeDetectionService {\n  private disposed = false;\n  private unsubscribe: (() => void) | undefined;\n  private debounceTimer: ReturnType<typeof setTimeout> | undefined;\n  private latestModuleGraph: ModuleGraph | undefined;\n  private hasReceivedModuleGraph = false;\n  private scanInFlight = false;\n  private rerunAfterCurrentScan = false;\n  private readinessResolved = false;\n  private previousStatuses = new Map<string, Status>();\n  private readonly gitDiffProvider: Pick<GitDiffProvider, 'getChangedFiles' | 'getRepoRoot'>;\n  private readonly workingDir: string;\n  private readonly debounceMs: number;\n\n  constructor(\n    private readonly options: {\n      storyIndexGeneratorPromise: Promise<StoryIndexGenerator>;\n      statusStore: StatusStoreByTypeId;\n      gitDiffProvider?: Pick<GitDiffProvider, 'getChangedFiles' | 'getRepoRoot'>;\n      workingDir?: string;\n      debounceMs?: number;\n    }\n  ) {\n    this.gitDiffProvider = options.gitDiffProvider ?? new GitDiffProvider(options.workingDir);\n    this.workingDir = options.workingDir ?? process.cwd();\n    this.debounceMs = options.debounceMs ?? CHANGE_DETECTION_DEBOUNCE_MS;\n    resetChangeDetectionReadiness();\n  }\n\n  start(\n    onModuleGraphChange: Builder<unknown>['onModuleGraphChange'],\n    enabled: boolean | undefined\n  ): void {\n    if (enabled === false) {\n      logger.debug('Change detection disabled.');\n      this.resolveReadiness({\n        status: 'unavailable',\n        reason: 'disabled',\n      });\n      return;\n    }\n\n    if (!onModuleGraphChange) {\n      logger.warn('Change detection unavailable: Not supported by builder');\n      this.resolveReadiness({\n        status: 'unavailable',\n        reason: 'builder does not support module graph',\n      });\n      return;\n    }\n\n    logger.debug('Change detection enabled.');\n    this.unsubscribe = onModuleGraphChange((event) => {\n      if (this.disposed) {\n        return;\n      }\n\n      if (event.type === 'moduleGraph') {\n        this.latestModuleGraph = event.moduleGraph;\n        this.scheduleScan(this.hasReceivedModuleGraph ? this.debounceMs : 0);\n        this.hasReceivedModuleGraph = true;\n        return;\n      }\n\n      this.handleBuilderStartupEvent(event);\n    });\n  }\n\n  async dispose(): Promise<void> {\n    this.disposed = true;\n    this.rerunAfterCurrentScan = false;\n\n    if (this.debounceTimer) {\n      clearTimeout(this.debounceTimer);\n      this.debounceTimer = undefined;\n    }\n\n    this.unsubscribe?.();\n    this.unsubscribe = undefined;\n  }\n\n  private scheduleScan(delayMs: number): void {\n    if (this.debounceTimer) {\n      clearTimeout(this.debounceTimer);\n    }\n\n    this.debounceTimer = setTimeout(() => {\n      this.debounceTimer = undefined;\n      void this.scan();\n    }, delayMs);\n  }\n\n  private async scan(): Promise<void> {\n    if (this.disposed || !this.latestModuleGraph) {\n      return;\n    }\n\n    if (this.scanInFlight) {\n      this.rerunAfterCurrentScan = true;\n      return;\n    }\n\n    this.scanInFlight = true;\n\n    try {\n      const nextStatuses = await this.buildStatuses(this.latestModuleGraph);\n      if (this.disposed) {\n        return;\n      }\n\n      this.applyStatusStorePatch(nextStatuses);\n      this.resolveReadiness({ status: 'ready' });\n    } catch (error) {\n      if (this.disposed) {\n        return;\n      }\n\n      if (error instanceof ChangeDetectionUnavailableError) {\n        logger.warn(`Change detection unavailable: ${error.message}`);\n        this.resolveReadiness({\n          status: 'unavailable',\n          reason: error.message,\n          error,\n        });\n        await this.dispose();\n      } else if (error instanceof ChangeDetectionFailureError) {\n        logger.error(`Change detection failed: ${error.message}`);\n        this.resolveReadiness({\n          status: 'error',\n          error,\n        });\n      } else {\n        const failure = new ChangeDetectionFailureError(\n          error instanceof Error ? error.message : String(error),\n          { cause: error instanceof Error ? error : undefined }\n        );\n        logger.error(`Change detection failed: ${failure.message}`);\n        this.resolveReadiness({\n          status: 'error',\n          error: failure,\n        });\n      }\n    } finally {\n      this.scanInFlight = false;\n\n      if (!this.disposed && this.rerunAfterCurrentScan) {\n        this.rerunAfterCurrentScan = false;\n        void this.scan();\n      }\n    }\n  }\n\n  private async buildStatuses(moduleGraph: ModuleGraph): Promise<Map<string, Status>> {\n    const [changes, repoRoot, storyIndexGenerator] = await Promise.all([\n      this.gitDiffProvider.getChangedFiles(),\n      this.gitDiffProvider.getRepoRoot(),\n      this.options.storyIndexGeneratorPromise,\n    ]);\n\n    const changedFiles = new Set(\n      Array.from(changes.changed).map((filePath) => resolve(repoRoot, filePath))\n    );\n    const newFiles = new Set(\n      Array.from(changes.new).map((filePath) => resolve(repoRoot, filePath))\n    );\n    const scannedFiles = new Set([...changedFiles, ...newFiles]);\n\n    const storyIndex = await storyIndexGenerator.getIndex();\n    const storyIdsByFile = getStoryIdsByAbsolutePath(storyIndex, this.workingDir);\n    const statuses = new Map<string, Status>();\n\n    for (const changedFile of scannedFiles) {\n      const affectedStoryFiles = findAffectedStoryFiles(changedFile, moduleGraph, storyIdsByFile);\n      const lowestDistance = Math.min(\n        ...Array.from(affectedStoryFiles.values(), ({ distance }) => distance)\n      );\n\n      for (const [storyFile, { distance }] of affectedStoryFiles.entries()) {\n        const storyIds = storyIdsByFile.get(storyFile);\n        if (!storyIds) {\n          continue;\n        }\n\n        const value: Status['value'] = newFiles.has(storyFile)\n          ? 'status-value:new'\n          : distance === lowestDistance\n            ? 'status-value:modified'\n            : 'status-value:affected';\n\n        storyIds.forEach((storyId) => {\n          const existingStatus = statuses.get(storyId);\n          const changedStoryFiles = new Set<string>(existingStatus?.data?.changedFiles ?? []);\n          changedStoryFiles.add(toRepoRelativePath(repoRoot, changedFile));\n\n          statuses.set(storyId, {\n            storyId,\n            typeId: CHANGE_DETECTION_STATUS_TYPE_ID,\n            value: mergeStatusValues(existingStatus?.value, value),\n            title: '',\n            description: '',\n            data: {\n              changedFiles: Array.from(changedStoryFiles).sort(),\n            },\n            sidebarContextMenu: false,\n          });\n        });\n      }\n    }\n\n    return statuses;\n  }\n\n  private applyStatusStorePatch(nextStatuses: Map<string, Status>): void {\n    const removedStoryIds = Array.from(this.previousStatuses.keys()).filter(\n      (storyId) => !nextStatuses.has(storyId)\n    );\n    const changedStatuses = Array.from(nextStatuses.values()).filter(\n      (status) => !isSameStatus(this.previousStatuses.get(status.storyId), status)\n    );\n\n    if (removedStoryIds.length > 0) {\n      this.options.statusStore.unset(removedStoryIds);\n    }\n\n    if (changedStatuses.length > 0) {\n      this.options.statusStore.set(changedStatuses);\n    }\n\n    this.previousStatuses = nextStatuses;\n  }\n\n  private resolveReadiness(\n    readiness:\n      | { status: 'ready' }\n      | { status: 'unavailable'; reason: string; error?: Error }\n      | { status: 'error'; error: Error }\n  ): void {\n    if (this.readinessResolved) {\n      return;\n    }\n\n    this.readinessResolved = true;\n    setChangeDetectionReadiness(readiness);\n  }\n\n  private handleBuilderStartupEvent(\n    event: Exclude<ModuleGraphChangeEvent, { type: 'moduleGraph' }>\n  ): void {\n    if (event.type === 'unavailable') {\n      logger.warn(`Change detection unavailable: ${event.reason}`);\n      this.resolveReadiness({\n        status: 'unavailable',\n        reason: event.reason,\n        error: event.error,\n      });\n    } else {\n      logger.error(`Change detection failed: ${event.error.message}`);\n      this.resolveReadiness({\n        status: 'error',\n        error: event.error,\n      });\n    }\n\n    void this.dispose();\n  }\n}\n"
  },
  {
    "path": "code/core/src/core-server/change-detection/GitDiffProvider.test.ts",
    "content": "import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport { execa } from 'execa';\n\nimport { ChangeDetectionFailureError, ChangeDetectionUnavailableError } from './errors.ts';\nimport { GitDiffProvider } from './GitDiffProvider.ts';\n\nvi.mock('execa', { spy: true });\n\ntype ExecaMockResult = { stdout: string } | { error: Error };\n\nfunction resolved(stdout: string): ExecaMockResult {\n  return { stdout };\n}\n\nfunction rejected(error: Error): ExecaMockResult {\n  return { error };\n}\n\ndescribe('GitDiffProvider', () => {\n  let repoRootResult: ExecaMockResult;\n  let stagedResult: ExecaMockResult;\n  let unstagedResult: ExecaMockResult;\n  let untrackedResult: ExecaMockResult;\n  let stagedAddedResult: ExecaMockResult;\n\n  beforeEach(() => {\n    vi.clearAllMocks();\n    repoRootResult = resolved('/repo');\n    stagedResult = resolved('src/Button.tsx\\nsrc/NewButton.stories.tsx\\n');\n    unstagedResult = resolved('src/Button.tsx\\n');\n    untrackedResult = resolved('src/Button.css\\n');\n    stagedAddedResult = resolved('src/NewButton.stories.tsx\\n');\n\n    vi.mocked(execa).mockImplementation(((_command: string | URL, ...rest: unknown[]) => {\n      const args = Array.isArray(rest[0]) ? rest[0] : [];\n      const gitArgs = args.join(' ');\n      const result =\n        gitArgs === 'rev-parse --show-toplevel'\n          ? repoRootResult\n          : gitArgs === 'diff --name-only --diff-filter=d --cached'\n            ? stagedResult\n            : gitArgs === 'diff --name-only --diff-filter=d'\n              ? unstagedResult\n              : gitArgs === 'ls-files --others --exclude-standard'\n                ? untrackedResult\n                : gitArgs === 'diff --name-only --diff-filter=A --cached'\n                  ? stagedAddedResult\n                  : undefined;\n\n      if (!result) {\n        throw new Error(`Unexpected git args: ${gitArgs}`);\n      }\n\n      if ('error' in result) {\n        throw result.error;\n      }\n\n      return Promise.resolve(result) as ReturnType<typeof execa>;\n    }) as unknown as typeof execa);\n  });\n\n  afterEach(() => {\n    vi.clearAllMocks();\n  });\n\n  it('returns the union of staged, unstaged, and untracked files', async () => {\n    const provider = new GitDiffProvider('/repo');\n\n    await expect(provider.getChangedFiles()).resolves.toEqual({\n      changed: new Set(['src/Button.tsx', 'src/NewButton.stories.tsx']),\n      new: new Set(['src/Button.css', 'src/NewButton.stories.tsx']),\n    });\n  });\n\n  it('throws a typed unavailable error when git cannot find a repository', async () => {\n    repoRootResult = rejected(new Error('fatal: not a git repository'));\n\n    const provider = new GitDiffProvider('/repo');\n\n    await expect(provider.getChangedFiles()).rejects.toBeInstanceOf(\n      ChangeDetectionUnavailableError\n    );\n  });\n\n  it('attributes staged diff failures to the specific git command', async () => {\n    stagedResult = rejected(new Error('index is locked'));\n\n    const provider = new GitDiffProvider('/repo');\n\n    await expect(provider.getChangedFiles()).rejects.toEqual(\n      expect.objectContaining({\n        name: 'ChangeDetectionFailureError',\n        message: expect.stringContaining('git diff --name-only --diff-filter=d --cached failed'),\n      })\n    );\n    await expect(provider.getChangedFiles()).rejects.toBeInstanceOf(ChangeDetectionFailureError);\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/change-detection/GitDiffProvider.ts",
    "content": "// eslint-disable-next-line depend/ban-dependencies\nimport { execa, type ExecaError } from 'execa';\n\nimport { ChangeDetectionFailureError, ChangeDetectionUnavailableError } from './errors.ts';\n\nexport interface GitDiffResult {\n  changed: Set<string>;\n  new: Set<string>;\n}\n\nfunction parseChangedFiles(stdout: string): Set<string> {\n  return new Set(\n    stdout\n      .split('\\n')\n      .map((line) => line.trim())\n      .filter(Boolean)\n  );\n}\n\nexport class GitDiffProvider {\n  private repoRoot: string | undefined;\n\n  constructor(private readonly cwd = process.cwd()) {}\n\n  async getRepoRoot(): Promise<string> {\n    if (this.repoRoot) {\n      return this.repoRoot;\n    }\n\n    try {\n      const { stdout } = await execa('git', ['rev-parse', '--show-toplevel'], {\n        cwd: this.cwd,\n        stdio: 'pipe',\n      });\n\n      this.repoRoot = stdout.trim();\n      return this.repoRoot;\n    } catch (error) {\n      throw this.toGitError(error, 'git rev-parse --show-toplevel');\n    }\n  }\n\n  async getChangedFiles(): Promise<GitDiffResult> {\n    const repoRoot = await this.getRepoRoot();\n    const runGitCommand = async (args: string[]) => {\n      try {\n        return await execa('git', args, { cwd: repoRoot, stdio: 'pipe' });\n      } catch (error) {\n        throw this.toGitError(error, `git ${args.join(' ')}`);\n      }\n    };\n\n    const [staged, unstaged, untracked, stagedAdded] = await Promise.all([\n      runGitCommand(['diff', '--name-only', '--diff-filter=d', '--cached']),\n      runGitCommand(['diff', '--name-only', '--diff-filter=d']),\n      runGitCommand(['ls-files', '--others', '--exclude-standard']),\n      runGitCommand(['diff', '--name-only', '--diff-filter=A', '--cached']),\n    ]);\n\n    return {\n      changed: new Set([\n        ...parseChangedFiles(staged.stdout),\n        ...parseChangedFiles(unstaged.stdout),\n      ]),\n      new: new Set([\n        ...parseChangedFiles(untracked.stdout),\n        ...parseChangedFiles(stagedAdded.stdout),\n      ]),\n    };\n  }\n\n  private toGitError(error: unknown, command: string): Error {\n    const execaError = error as Partial<ExecaError>;\n    const stderr = [execaError.stderr, execaError.shortMessage, execaError.message]\n      .filter(Boolean)\n      .join('\\n');\n\n    if (execaError.code === 'ENOENT') {\n      return new ChangeDetectionUnavailableError('git is not available', { cause: error as Error });\n    }\n\n    if (stderr.includes('not a git repository')) {\n      return new ChangeDetectionUnavailableError('not a git repository', {\n        cause: error as Error,\n      });\n    }\n\n    return new ChangeDetectionFailureError(`${command} failed${stderr ? `: ${stderr}` : ''}`, {\n      cause: error as Error,\n    });\n  }\n}\n"
  },
  {
    "path": "code/core/src/core-server/change-detection/errors.ts",
    "content": "export class ChangeDetectionUnavailableError extends Error {\n  constructor(message: string, options?: ErrorOptions) {\n    super(message, options);\n    this.name = 'ChangeDetectionUnavailableError';\n  }\n}\n\nexport class ChangeDetectionFailureError extends Error {\n  constructor(message: string, options?: ErrorOptions) {\n    super(message, options);\n    this.name = 'ChangeDetectionFailureError';\n  }\n}\n"
  },
  {
    "path": "code/core/src/core-server/change-detection/index.ts",
    "content": "export { ChangeDetectionFailureError, ChangeDetectionUnavailableError } from './errors.ts';\nexport { GitDiffProvider } from './GitDiffProvider.ts';\nexport {\n  getChangeDetectionReadiness,\n  resetChangeDetectionReadiness as internal_resetChangeDetectionReadiness,\n  type ChangeDetectionReadiness,\n} from './readiness.ts';\nexport { ChangeDetectionService } from './ChangeDetectionService.ts';\n"
  },
  {
    "path": "code/core/src/core-server/change-detection/readiness.ts",
    "content": "export type ChangeDetectionReadiness =\n  | { status: 'ready' }\n  | { status: 'unavailable'; reason: string; error?: Error }\n  | { status: 'error'; error: Error };\n\ntype Deferred<T> = {\n  promise: Promise<T>;\n  resolve: (value: T) => void;\n};\n\nfunction createDeferred<T>(): Deferred<T> {\n  let resolve!: (value: T) => void;\n\n  return {\n    promise: new Promise<T>((fulfill) => {\n      resolve = fulfill;\n    }),\n    resolve,\n  };\n}\n\nlet readinessDeferred = createDeferred<ChangeDetectionReadiness>();\nlet readinessState: ChangeDetectionReadiness | undefined;\n\nexport function getChangeDetectionReadiness(): Promise<ChangeDetectionReadiness> {\n  return readinessState ? Promise.resolve(readinessState) : readinessDeferred.promise;\n}\n\nexport function setChangeDetectionReadiness(readiness: ChangeDetectionReadiness): void {\n  if (readinessState) {\n    return;\n  }\n\n  readinessState = readiness;\n  readinessDeferred.resolve(readiness);\n}\n\nexport function resetChangeDetectionReadiness(): void {\n  readinessDeferred = createDeferred<ChangeDetectionReadiness>();\n  readinessState = undefined;\n}\n"
  },
  {
    "path": "code/core/src/core-server/change-detection/trace-changed.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport type { ModuleGraph, ModuleNode } from 'storybook/internal/types';\n\nimport { findAffectedStoryFiles } from './trace-changed.ts';\n\nfunction createModuleNode(file: string): ModuleNode {\n  return {\n    file,\n    type: 'js',\n    importers: new Set(),\n    importedModules: new Set(),\n  };\n}\n\nfunction createStoryIdsByFile(...files: string[]): Map<string, Set<string>> {\n  return new Map(files.map((file) => [file, new Set([file])]));\n}\n\ndescribe('findAffectedStoryFiles', () => {\n  it('returns every reachable story file with its shortest distance', () => {\n    const buttonCss = createModuleNode('/repo/src/Button.module.css');\n    const button = createModuleNode('/repo/src/Button.tsx');\n    const header = createModuleNode('/repo/src/Header.tsx');\n    const buttonStory = createModuleNode('/repo/src/Button.stories.tsx');\n    const headerStory = createModuleNode('/repo/src/Header.stories.tsx');\n    const page = createModuleNode('/repo/src/Page.tsx');\n    const pageStory = createModuleNode('/repo/src/Page.stories.tsx');\n\n    buttonCss.importers.add(button);\n    button.importers.add(buttonStory);\n    button.importers.add(header);\n    header.importers.add(headerStory);\n    header.importers.add(page);\n    page.importers.add(pageStory);\n\n    const moduleGraph: ModuleGraph = new Map([\n      ['/repo/src/Button.module.css', new Set([buttonCss])],\n      ['/repo/src/Button.tsx', new Set([button])],\n      ['/repo/src/Header.tsx', new Set([header])],\n      ['/repo/src/Button.stories.tsx', new Set([buttonStory])],\n      ['/repo/src/Header.stories.tsx', new Set([headerStory])],\n      ['/repo/src/Page.tsx', new Set([page])],\n      ['/repo/src/Page.stories.tsx', new Set([pageStory])],\n    ]);\n\n    expect(\n      findAffectedStoryFiles(\n        '/repo/src/Button.module.css',\n        moduleGraph,\n        createStoryIdsByFile(\n          '/repo/src/Button.stories.tsx',\n          '/repo/src/Header.stories.tsx',\n          '/repo/src/Page.stories.tsx'\n        )\n      )\n    ).toEqual(\n      new Map([\n        ['/repo/src/Button.stories.tsx', { distance: 2 }],\n        ['/repo/src/Header.stories.tsx', { distance: 3 }],\n        ['/repo/src/Page.stories.tsx', { distance: 4 }],\n      ])\n    );\n  });\n\n  it('keeps the shortest distance when the same story file is reachable multiple ways', () => {\n    const shared = createModuleNode('/repo/src/shared.ts');\n    const a = createModuleNode('/repo/src/A.tsx');\n    const b = createModuleNode('/repo/src/B.tsx');\n    const storyViaA = createModuleNode('/repo/src/Shared.stories.tsx');\n    const storyViaB = createModuleNode('/repo/src/Shared.stories.tsx');\n\n    shared.importers.add(a);\n    shared.importers.add(b);\n    a.importers.add(storyViaA);\n    b.importers.add(a);\n    b.importers.add(storyViaB);\n\n    const moduleGraph: ModuleGraph = new Map([\n      ['/repo/src/shared.ts', new Set([shared])],\n      ['/repo/src/A.tsx', new Set([a])],\n      ['/repo/src/B.tsx', new Set([b])],\n      ['/repo/src/Shared.stories.tsx', new Set([storyViaA, storyViaB])],\n    ]);\n\n    expect(\n      findAffectedStoryFiles(\n        '/repo/src/shared.ts',\n        moduleGraph,\n        createStoryIdsByFile('/repo/src/Shared.stories.tsx')\n      )\n    ).toEqual(new Map([['/repo/src/Shared.stories.tsx', { distance: 2 }]]));\n  });\n\n  it('handles cycles without looping forever', () => {\n    const changed = createModuleNode('/repo/src/changed.ts');\n    const a = createModuleNode('/repo/src/A.ts');\n    const b = createModuleNode('/repo/src/B.ts');\n    const story = createModuleNode('/repo/src/Cycle.stories.tsx');\n\n    changed.importers.add(a);\n    a.importers.add(b);\n    b.importers.add(a);\n    b.importers.add(story);\n\n    const moduleGraph: ModuleGraph = new Map([\n      ['/repo/src/changed.ts', new Set([changed])],\n      ['/repo/src/A.ts', new Set([a])],\n      ['/repo/src/B.ts', new Set([b])],\n      ['/repo/src/Cycle.stories.tsx', new Set([story])],\n    ]);\n\n    expect(\n      findAffectedStoryFiles(\n        '/repo/src/changed.ts',\n        moduleGraph,\n        createStoryIdsByFile('/repo/src/Cycle.stories.tsx')\n      )\n    ).toEqual(new Map([['/repo/src/Cycle.stories.tsx', { distance: 3 }]]));\n  });\n\n  it('returns the changed story file with distance zero', () => {\n    expect(\n      findAffectedStoryFiles(\n        '/repo/src/Button.stories.tsx',\n        new Map(),\n        createStoryIdsByFile('/repo/src/Button.stories.tsx')\n      )\n    ).toEqual(new Map([['/repo/src/Button.stories.tsx', { distance: 0 }]]));\n  });\n\n  it('returns an empty map when no story files are reachable', () => {\n    const changed = createModuleNode('/repo/src/changed.ts');\n    const component = createModuleNode('/repo/src/Component.tsx');\n\n    changed.importers.add(component);\n\n    const moduleGraph: ModuleGraph = new Map([\n      ['/repo/src/changed.ts', new Set([changed])],\n      ['/repo/src/Component.tsx', new Set([component])],\n    ]);\n\n    expect(\n      findAffectedStoryFiles(\n        '/repo/src/changed.ts',\n        moduleGraph,\n        createStoryIdsByFile('/repo/src/Button.stories.tsx')\n      )\n    ).toEqual(new Map());\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/change-detection/trace-changed.ts",
    "content": "import type { ModuleGraph, ModuleNode } from 'storybook/internal/types';\n\nexport function findAffectedStoryFiles(\n  changedFile: string,\n  moduleGraph: ModuleGraph,\n  storyIdsByFile: Map<string, Set<string>>\n): Map<string, { distance: number }> {\n  const affectedStoryFiles = new Map<string, { distance: number }>();\n\n  if (storyIdsByFile.has(changedFile)) {\n    affectedStoryFiles.set(changedFile, { distance: 0 });\n  }\n\n  const startingNodes = moduleGraph.get(changedFile);\n  if (!startingNodes?.size) {\n    return affectedStoryFiles;\n  }\n\n  const visited = new Map<ModuleNode, number>();\n  const queue = Array.from(startingNodes, (node) => ({ node, distance: 0 }));\n  let queueIndex = 0;\n\n  startingNodes.forEach((node) => {\n    visited.set(node, 0);\n  });\n\n  while (queueIndex < queue.length) {\n    const current = queue[queueIndex++];\n    current.node.importers.forEach((importer) => {\n      const distance = current.distance + 1;\n      const previousDistance = visited.get(importer);\n\n      if (previousDistance !== undefined && previousDistance <= distance) {\n        return;\n      }\n\n      visited.set(importer, distance);\n      if (storyIdsByFile.has(importer.file)) {\n        const previousStoryDistance = affectedStoryFiles.get(importer.file)?.distance;\n\n        if (previousStoryDistance === undefined || distance < previousStoryDistance) {\n          affectedStoryFiles.set(importer.file, { distance });\n        }\n      }\n\n      queue.push({ node: importer, distance });\n    });\n  }\n\n  return affectedStoryFiles;\n}\n"
  },
  {
    "path": "code/core/src/core-server/dev-server.ts",
    "content": "import { logConfig, normalizeStories } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\nimport { MissingBuilderError } from 'storybook/internal/server-errors';\nimport { CHANGE_DETECTION_STATUS_TYPE_ID } from 'storybook/internal/types';\nimport type { Options } from 'storybook/internal/types';\n\nimport compression from '@polka/compression';\nimport polka from 'polka';\n\nimport { telemetry } from '../telemetry/index.ts';\nimport { ChangeDetectionService } from './change-detection/index.ts';\nimport { getStatusStoreByTypeId } from './stores/status.ts';\nimport type { StoryIndexGenerator } from './utils/StoryIndexGenerator.ts';\nimport { doTelemetry } from './utils/doTelemetry.ts';\nimport { getManagerBuilder, getPreviewBuilder } from './utils/get-builders.ts';\nimport { getCachingMiddleware } from './utils/get-caching-middleware.ts';\nimport { getAccessControlMiddleware } from './utils/getAccessControlMiddleware.ts';\nimport { getHostValidationMiddleware } from './utils/getHostValidationMiddleware.ts';\nimport { registerIndexJsonRoute } from './utils/index-json.ts';\nimport { registerManifests } from './utils/manifests/manifests.ts';\nimport { useStorybookMetadata } from './utils/metadata.ts';\nimport { getMiddleware } from './utils/middleware.ts';\nimport { openInBrowser } from './utils/open-browser/open-in-browser.ts';\nimport type { getServer } from './utils/server-init.ts';\nimport { useStatics } from './utils/server-statics.ts';\nimport { summarizeIndex } from './utils/summarizeIndex.ts';\n\nexport async function storybookDevServer(\n  options: Options,\n  server: Awaited<ReturnType<typeof getServer>>\n) {\n  const core = await options.presets.apply('core');\n\n  const app = polka({ server });\n\n  const workingDir = process.cwd();\n  const configDir = options.configDir;\n  const features = await options.presets.apply('features');\n  const stories = await options.presets.apply('stories');\n  // StoryIndexGenerator depends on these normalized stories to be referentially equal\n  // So it's important that we only normalize them once here and pass the same reference around\n  const normalizedStories = normalizeStories(stories, {\n    configDir,\n    workingDir,\n  });\n\n  const storyIndexGeneratorPromise =\n    options.presets.apply<StoryIndexGenerator>('storyIndexGenerator');\n\n  app.use(compression({ level: 1 }));\n\n  if (typeof options.extendServer === 'function') {\n    options.extendServer(server);\n  }\n\n  app.use(\n    getHostValidationMiddleware({\n      host: options.host,\n      allowedHosts: core?.allowedHosts,\n      localAddress: options.localAddress,\n      networkAddress: options.networkAddress,\n    })\n  );\n  app.use(getAccessControlMiddleware(core?.crossOriginIsolated ?? false));\n  app.use(getCachingMiddleware());\n\n  registerIndexJsonRoute({\n    app,\n    storyIndexGeneratorPromise,\n    normalizedStories,\n    channel: options.channel,\n    workingDir,\n    configDir,\n  });\n\n  (await getMiddleware(options.configDir))(app);\n\n  // Apply experimental_devServer preset to allow addons/frameworks to extend the dev server with middlewares, etc.\n  await options.presets.apply('experimental_devServer', app);\n\n  if (!core?.builder) {\n    throw new MissingBuilderError();\n  }\n\n  const resolvedPreviewBuilder =\n    typeof core?.builder === 'string' ? core.builder : core?.builder?.name;\n\n  const [previewBuilder, managerBuilder] = await Promise.all([\n    getPreviewBuilder(resolvedPreviewBuilder),\n    getManagerBuilder(),\n    useStatics(app, options),\n  ]);\n\n  if (options.debugWebpack) {\n    logConfig('Preview webpack config', await previewBuilder.getConfig(options));\n  }\n\n  // Boot up the `/project.json` route handler early to avoid Vite Dev Server\n  // serving a NX monorepo `project.json` file instead.\n  if (!core?.disableProjectJson) {\n    useStorybookMetadata(app, options.configDir);\n  }\n\n  const managerResult = options.previewOnly\n    ? undefined\n    : await managerBuilder.start({\n        startTime: process.hrtime(),\n        options,\n        router: app,\n        server,\n        channel: options.channel,\n      });\n\n  let previewResult: Awaited<ReturnType<(typeof previewBuilder)['start']>> =\n    await Promise.resolve();\n\n  if (!options.ignorePreview) {\n    const changeDetectionService = new ChangeDetectionService({\n      storyIndexGeneratorPromise,\n      statusStore: getStatusStoreByTypeId(CHANGE_DETECTION_STATUS_TYPE_ID),\n      workingDir,\n    });\n    changeDetectionService.start(previewBuilder.onModuleGraphChange, features?.changeDetection);\n\n    logger.debug('Starting preview..');\n    previewResult = await previewBuilder\n      .start({\n        startTime: process.hrtime(),\n        options,\n        router: app,\n        server,\n        channel: options.channel,\n      })\n      .catch(async (e: unknown) => {\n        logger.error('Failed to build the preview');\n        process.exitCode = 1;\n\n        await changeDetectionService.dispose().catch(() => undefined);\n        await managerBuilder?.bail().catch(() => undefined);\n        // For some reason, even when Webpack fails e.g. wrong main.js config,\n        // the preview may continue to print to stdout, which can affect output\n        // when we catch this error and process those errors (e.g. telemetry)\n        // gets overwritten by preview progress output. Therefore, we should bail the preview too.\n        await previewBuilder?.bail().catch(() => undefined);\n\n        // re-throw the error\n        throw e;\n      });\n  }\n\n  const listening = new Promise<void>((resolve, reject) => {\n    server.once('error', reject);\n    app.listen({ port: options.port, host: options.host }, resolve);\n  });\n\n  try {\n    const [indexGenerator] = await Promise.all([storyIndexGeneratorPromise, listening]);\n\n    if (indexGenerator && !options.ci && !options.smokeTest && options.open) {\n      const url = options.host ? options.networkAddress : options.localAddress;\n      openInBrowser(options.previewOnly ? `${url}iframe.html?navigator=true` : url!).catch(() => {\n        // the browser window could not be opened, this is non-critical, we just ignore the error\n      });\n    }\n  } catch (e) {\n    await managerBuilder?.bail().catch(() => undefined);\n    await previewBuilder?.bail().catch(() => undefined);\n    throw e;\n  }\n\n  if (features?.componentsManifest) {\n    registerManifests({ app, presets: options.presets });\n  }\n  // Now the preview has successfully started, we can count this as a 'dev' event.\n  doTelemetry(app, core, storyIndexGeneratorPromise, options);\n\n  async function cancelTelemetry() {\n    const payload = { eventType: 'dev' };\n    try {\n      const generator = await storyIndexGeneratorPromise;\n      const indexAndStats = await generator?.getIndexAndStats();\n      // compute stats so we can get more accurate story counts\n      if (indexAndStats) {\n        Object.assign(payload, {\n          storyIndex: summarizeIndex(indexAndStats.storyIndex),\n          storyStats: indexAndStats.stats,\n        });\n      }\n    } catch {}\n    await telemetry('canceled', payload, { immediate: true });\n    process.exit(0);\n  }\n\n  if (!core?.disableTelemetry) {\n    process.on('SIGINT', cancelTelemetry);\n    process.on('SIGTERM', cancelTelemetry);\n  }\n\n  return { previewResult, managerResult };\n}\n"
  },
  {
    "path": "code/core/src/core-server/index.ts",
    "content": "/// <reference path=\"./typings.d.ts\" />\n\nexport { getPreviewHeadTemplate, getPreviewBodyTemplate } from 'storybook/internal/common';\n\nexport * from './build-static.ts';\nexport * from './build-dev.ts';\nexport * from './build-index.ts';\nexport * from './withTelemetry.ts';\nexport { default as build } from './standalone.ts';\nexport { mapStaticDir } from './utils/server-statics.ts';\nexport { StoryIndexGenerator } from './utils/StoryIndexGenerator.ts';\nexport { generateStoryFile } from './utils/generate-story.ts';\nexport type { GenerateStoryResult, GenerateStoryOptions } from './utils/generate-story.ts';\nexport type { ComponentArgTypesData } from './utils/get-dummy-args-from-argtypes.ts';\n\nexport { loadStorybook as experimental_loadStorybook } from './load.ts';\n\nexport { Tag } from '../shared/constants/tags.ts';\nexport { analyze as analyzeMdx } from '@storybook/docs-mdx';\n\nexport { UniversalStore as experimental_UniversalStore } from '../shared/universal-store/index.ts';\nexport { MockUniversalStore as experimental_MockUniversalStore } from '../shared/universal-store/mock.ts';\nexport {\n  getStatusStoreByTypeId as experimental_getStatusStore,\n  fullStatusStore as internal_fullStatusStore,\n  universalStatusStore as internal_universalStatusStore,\n} from './stores/status.ts';\nexport {\n  getChangeDetectionReadiness as experimental_getChangeDetectionReadiness,\n  type ChangeDetectionReadiness as Experimental_ChangeDetectionReadiness,\n} from './change-detection/index.ts';\nexport { ChangeDetectionService } from './change-detection/ChangeDetectionService.ts';\nexport {\n  getTestProviderStoreById as experimental_getTestProviderStore,\n  fullTestProviderStore as internal_fullTestProviderStore,\n  universalTestProviderStore as internal_universalTestProviderStore,\n} from './stores/test-provider.ts';\n\nexport { getServerPort } from './utils/server-address.ts';\n"
  },
  {
    "path": "code/core/src/core-server/load.ts",
    "content": "import { Channel } from 'storybook/internal/channels';\nimport {\n  getProjectRoot,\n  loadAllPresets,\n  loadMainConfig,\n  resolveAddonName,\n  validateFrameworkName,\n} from 'storybook/internal/common';\nimport { oneWayHash } from 'storybook/internal/telemetry';\nimport type { BuilderOptions, CLIOptions, LoadOptions, Options } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { dirname, isAbsolute, join, relative, resolve } from 'pathe';\n\nimport { resolvePackageDir } from '../shared/utils/module.ts';\n\nexport async function loadStorybook(\n  options: CLIOptions &\n    LoadOptions &\n    BuilderOptions & {\n      storybookVersion?: string;\n      previewConfigPath?: string;\n    }\n): Promise<Options> {\n  const configDir = resolve(options.configDir);\n\n  const cacheKey = oneWayHash(relative(getProjectRoot(), configDir));\n\n  options.configType = 'DEVELOPMENT';\n  options.configDir = configDir;\n  options.cacheKey = cacheKey;\n\n  const config = await loadMainConfig(options);\n  const { framework } = config;\n  const corePresets = [];\n\n  let frameworkName = typeof framework === 'string' ? framework : framework?.name;\n  if (!options.ignorePreview) {\n    validateFrameworkName(frameworkName);\n  }\n  if (frameworkName) {\n    corePresets.push(join(frameworkName, 'preset'));\n  }\n\n  frameworkName = frameworkName || 'custom';\n\n  // Load first pass: We need to determine the builder\n  // We need to do this because builders might introduce 'overridePresets' which we need to take into account\n  // We hope to remove this in SB8\n\n  // no-op channel, as it's only relevant in dev mode\n  const channel = new Channel({});\n\n  let presets = await loadAllPresets({\n    corePresets,\n    overridePresets: [\n      import.meta.resolve('storybook/internal/core-server/presets/common-override-preset'),\n    ],\n    ...options,\n    isCritical: true,\n    channel,\n  });\n\n  const { renderer, builder } = await presets.apply('core', {});\n  const resolvedRenderer = renderer && resolveAddonName(options.configDir, renderer, options);\n\n  const builderName = typeof builder === 'string' ? builder : builder?.name;\n\n  if (builderName) {\n    /* builderName can be a bare package name (e.g. '@storybook/builder-vite') or an already-resolved\n       file URL / absolute path (e.g. 'file:///.../.../dist/index.js'). For bare package names, we\n       need to resolve the package directory first; for already-resolved paths, dirname works directly.\n    */\n    const isResolved = builderName.startsWith('file:') || isAbsolute(builderName);\n    const builderPresetDir = isResolved ? dirname(builderName) : resolvePackageDir(builderName);\n    corePresets.push(join(builderPresetDir, 'preset.js'));\n  }\n\n  // Load second pass: all presets are applied in order\n\n  presets = await loadAllPresets({\n    corePresets: [\n      join(resolvePackageDir('storybook'), 'dist/core-server/presets/common-preset.js'),\n      ...(resolvedRenderer ? [resolvedRenderer] : []),\n      ...corePresets,\n    ],\n    overridePresets: [\n      import.meta.resolve('storybook/internal/core-server/presets/common-override-preset'),\n    ],\n    channel,\n    ...options,\n  });\n\n  const features = await presets.apply('features');\n  global.FEATURES = features;\n\n  return {\n    ...options,\n    presets,\n    features,\n  } as Options;\n}\n"
  },
  {
    "path": "code/core/src/core-server/presets/common-manager.ts",
    "content": "/* these imports are in the exact order in which the panels need to be registered */\n\n// THE ORDER OF THESE IMPORTS MATTERS! IT DEFINES THE ORDER OF PANELS AND TOOLS!\nimport controlsManager from '../../controls/manager.tsx';\nimport actionsManager from '../../actions/manager.tsx';\nimport componentTestingManager from '../../component-testing/manager.tsx';\nimport backgroundsManager from '../../backgrounds/manager.tsx';\nimport measureManager from '../../measure/manager.tsx';\nimport outlineManager from '../../outline/manager.tsx';\nimport viewportManager from '../../viewport/manager.tsx';\n\nexport default [\n  measureManager,\n  actionsManager,\n  backgroundsManager,\n  componentTestingManager,\n  controlsManager,\n  viewportManager,\n  outlineManager,\n];\n"
  },
  {
    "path": "code/core/src/core-server/presets/common-override-preset.ts",
    "content": "import type { PresetProperty, TestBuildFlags } from 'storybook/internal/types';\n\nimport { removeMDXEntries } from '../utils/remove-mdx-entries.ts';\n\nexport const framework: PresetProperty<'framework'> = async (config) => {\n  // This will get called with the values from the user's main config, but before\n  // framework preset from framework packages e.g. react-webpack5 gets called.\n  // This means we can add default values to the framework config, before it's requested by other packages.\n  const name = typeof config === 'string' ? config : config?.name;\n  const options = typeof config === 'string' ? {} : config?.options || {};\n\n  return {\n    name,\n    options,\n  };\n};\n\nexport const stories: PresetProperty<'stories'> = async (entries, options) => {\n  if (options?.build?.test?.disableMDXEntries) {\n    return removeMDXEntries(entries, options);\n  }\n  return entries;\n};\n\nexport const typescript: PresetProperty<'typescript'> = async (input, options) => {\n  if (options?.build?.test?.disableDocgen) {\n    return { ...(input ?? {}), reactDocgen: false, check: false };\n  }\n  return input;\n};\n\nconst createTestBuildFeatures = (value: boolean): Required<TestBuildFlags> => ({\n  disableBlocks: value,\n  disabledAddons: value\n    ? ['@storybook/addon-docs', '@storybook/addon-essentials/docs', '@storybook/addon-coverage']\n    : [],\n  disableMDXEntries: value,\n  disableAutoDocs: value,\n  disableDocgen: value,\n  disableSourcemaps: value,\n  disableTreeShaking: value,\n  esbuildMinify: value,\n});\n\nexport const build: PresetProperty<'build'> = async (value, options) => {\n  return {\n    ...value,\n    test: options.test\n      ? {\n          ...createTestBuildFeatures(!!options.test),\n          ...value?.test,\n        }\n      : createTestBuildFeatures(false),\n  };\n};\n"
  },
  {
    "path": "code/core/src/core-server/presets/common-preset.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\n\nimport type { Channel } from 'storybook/internal/channels';\nimport { normalizeStories, optionalEnvToBoolean } from 'storybook/internal/common';\nimport {\n  JsPackageManagerFactory,\n  type RemoveAddonOptions,\n  getDirectoryFromWorkingDir,\n  getPreviewBodyTemplate,\n  getPreviewHeadTemplate,\n  loadEnvs,\n  removeAddon as removeAddonBase,\n} from 'storybook/internal/common';\nimport { StoryIndexGenerator } from 'storybook/internal/core-server';\nimport { loadCsf } from 'storybook/internal/csf-tools';\nimport { logger } from 'storybook/internal/node-logger';\nimport { telemetry } from 'storybook/internal/telemetry';\nimport type {\n  CoreConfig,\n  Indexer,\n  Options,\n  PresetProperty,\n  PresetPropertyFn,\n  StorybookConfigRaw,\n} from 'storybook/internal/types';\n\nimport { isAbsolute, join } from 'pathe';\nimport * as pathe from 'pathe';\nimport { dedent } from 'ts-dedent';\n\nimport { resolvePackageDir } from '../../shared/utils/module.ts';\nimport { initCreateNewStoryChannel } from '../server-channel/create-new-story-channel.ts';\nimport { initFileSearchChannel } from '../server-channel/file-search-channel.ts';\nimport { initGhostStoriesChannel } from '../server-channel/ghost-stories-channel.ts';\nimport { initOpenInEditorChannel } from '../server-channel/open-in-editor-channel.ts';\nimport { initTelemetryChannel } from '../server-channel/telemetry-channel.ts';\nimport { initializeChecklist } from '../utils/checklist.ts';\nimport { defaultFavicon, defaultStaticDirs } from '../utils/constants.ts';\nimport { initializeSaveStory } from '../utils/save-story/save-story.ts';\nimport { parseStaticDir } from '../utils/server-statics.ts';\nimport { type OptionsWithRequiredCache, initializeWhatsNew } from '../utils/whats-new.ts';\nimport { getWsToken } from './wsToken.ts';\n\nconst interpolate = (string: string, data: Record<string, string> = {}) =>\n  Object.entries(data).reduce((acc, [k, v]) => acc.replace(new RegExp(`%${k}%`, 'g'), v), string);\n\nexport const staticDirs: PresetPropertyFn<'staticDirs'> = async (values = []) => [\n  ...defaultStaticDirs,\n  ...values,\n];\n\nexport const favicon = async (\n  value: string | undefined,\n  options: Pick<Options, 'presets' | 'configDir'>\n) => {\n  if (value) {\n    return value;\n  }\n\n  const staticDirsValue = await options.presets.apply('staticDirs');\n\n  const statics = staticDirsValue\n    ? staticDirsValue.map((dir) => (typeof dir === 'string' ? dir : `${dir.from}:${dir.to}`))\n    : [];\n\n  const faviconPaths = statics\n    .map((dir) => {\n      const results = [];\n      const normalizedDir =\n        staticDirsValue && !isAbsolute(dir)\n          ? getDirectoryFromWorkingDir({\n              configDir: options.configDir,\n              workingDir: process.cwd(),\n              directory: dir,\n            })\n          : dir;\n\n      const { staticPath, targetEndpoint } = parseStaticDir(normalizedDir);\n\n      // Direct favicon references (e.g. `staticDirs: ['favicon.svg']`)\n      if (['/favicon.svg', '/favicon.ico'].includes(targetEndpoint)) {\n        results.push(staticPath);\n      }\n      // Favicon files in a static directory (e.g. `staticDirs: ['static']`)\n      if (targetEndpoint === '/') {\n        results.push(join(staticPath, 'favicon.svg'));\n        results.push(join(staticPath, 'favicon.ico'));\n      }\n\n      return results.filter((path) => existsSync(path));\n    })\n    .reduce((l1, l2) => l1.concat(l2), []);\n\n  if (faviconPaths.length > 1) {\n    logger.debug(dedent`\n      Looks like multiple favicons were detected. Using the first one.\n\n      ${faviconPaths.join(', ')}\n    `);\n  }\n\n  return faviconPaths[0] || defaultFavicon;\n};\n\nexport const babel = async (_: unknown, options: Options) => {\n  const { presets } = options;\n  const babelDefault = ((await presets.apply('babelDefault', {}, options)) ?? {}) as Record<\n    string,\n    any\n  >;\n  return {\n    ...babelDefault,\n    // This override makes sure that we will never transpile babel further down then the browsers that storybook supports.\n    // This is needed to support the mount property of the context described here:\n    // https://storybook.js.org/docs/writing-tests/interaction-testing#run-code-before-each-story-in-a-file\n    overrides: [\n      ...(babelDefault?.overrides ?? []),\n      {\n        include: /\\.(story|stories)\\.[cm]?[jt]sx?$/,\n        presets: [\n          [\n            '@babel/preset-env',\n            {\n              bugfixes: true,\n              targets: {\n                // This is the same browser supports that we use to bundle our manager and preview code.\n                chrome: 100,\n                safari: 15,\n                firefox: 91,\n              },\n            },\n          ],\n        ],\n      },\n    ],\n  };\n};\n\nexport const title = (previous: string, options: Options) =>\n  previous || options.packageJson?.name || false;\n\nexport const logLevel = (previous: any, options: Options) => previous || options.loglevel || 'info';\n\nexport const previewHead = async (base: any, { configDir, presets }: Options) => {\n  const interpolations = await presets.apply<Record<string, string>>('env');\n  return getPreviewHeadTemplate(configDir, interpolations);\n};\n\nexport const env = async () => {\n  const { raw } = await loadEnvs({ production: true });\n  return raw;\n};\n\nexport const previewBody = async (base: any, { configDir, presets }: Options) => {\n  const interpolations = await presets.apply<Record<string, string>>('env');\n  return getPreviewBodyTemplate(configDir, interpolations);\n};\n\nexport const typescript = () => ({\n  check: false,\n  // 'react-docgen' faster than `react-docgen-typescript` but produces lower quality results\n  reactDocgen: 'react-docgen',\n  reactDocgenTypescriptOptions: {\n    shouldExtractLiteralValuesFromEnum: true,\n    shouldRemoveUndefinedFromOptional: true,\n    propFilter: (prop: any) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),\n    // NOTE: this default cannot be changed\n    savePropValueAsString: true,\n  },\n});\n\n/** This API is used by third-parties to access certain APIs in a Node environment */\nexport const experimental_serverAPI = (extension: Record<string, Function>, options: Options) => {\n  let removeAddon = removeAddonBase;\n  const packageManager = JsPackageManagerFactory.getPackageManager({\n    configDir: options.configDir,\n  });\n  if (!options.disableTelemetry) {\n    removeAddon = async (id: string, opts: RemoveAddonOptions) => {\n      await telemetry('remove', { addon: id, source: 'api' });\n      return removeAddonBase(id, { ...opts, packageManager });\n    };\n  }\n  return { ...extension, removeAddon };\n};\n\n/**\n * If for some reason this config is not applied, the reason is that likely there is an addon that\n * does `export core = () => ({ someConfig })`, instead of `export core = (existing) => ({\n * ...existing, someConfig })`, just overwriting everything and not merging with the existing\n * values.\n */\nexport const core = async (existing: CoreConfig, options: Options): Promise<CoreConfig> => ({\n  ...existing,\n  channelOptions: {\n    ...(existing?.channelOptions ?? {}),\n    ...(options.configType === 'DEVELOPMENT' ? { wsToken: getWsToken() } : {}),\n  },\n  disableTelemetry: options.disableTelemetry === true,\n  enableCrashReports:\n    options.enableCrashReports || optionalEnvToBoolean(process.env.STORYBOOK_ENABLE_CRASH_REPORTS),\n});\n\nexport const features: PresetProperty<'features'> = async (existing) => ({\n  ...existing,\n  actions: true,\n  argTypeTargetsV7: true,\n  backgrounds: true,\n  changeDetection: false,\n  componentsManifest: true,\n  controls: true,\n  disallowImplicitActionsInRenderV8: true,\n  highlight: true,\n  interactions: true,\n  legacyDecoratorFileOrder: false,\n  measure: true,\n  outline: true,\n  sidebarOnboardingChecklist: true,\n  viewport: true,\n});\n\nexport const csfIndexer: Indexer = {\n  test: /(stories|story)\\.(m?js|ts)x?$/,\n  createIndex: async (fileName, options) => {\n    const code = (await readFile(fileName, 'utf-8')).toString();\n    if (code.trim().length === 0) {\n      logger.debug(`The file ${fileName} is empty. Skipping indexing.`);\n      return [];\n    }\n    return loadCsf(code, { ...options, fileName }).parse().indexInputs;\n  },\n};\n\nexport const experimental_indexers: PresetProperty<'experimental_indexers'> = (existingIndexers) =>\n  [csfIndexer].concat(existingIndexers || []);\n\nexport const frameworkOptions = async (\n  _: never,\n  options: Options\n): Promise<Record<string, any> | null> => {\n  const config = await options.presets.apply('framework');\n\n  if (typeof config === 'string') {\n    return {};\n  }\n\n  if (typeof config === 'undefined') {\n    return null;\n  }\n\n  return config.options;\n};\n\nexport const managerHead = async (_: any, options: Options) => {\n  const location = join(options.configDir, 'manager-head.html');\n  if (existsSync(location)) {\n    const contents = readFile(location, { encoding: 'utf8' });\n    const interpolations = options.presets.apply<Record<string, string>>('env');\n\n    return interpolate(await contents, await interpolations);\n  }\n\n  return '';\n};\n\nexport const channelToken = async (value: string | undefined) => {\n  return value;\n};\n\nexport const experimental_serverChannel = async (\n  channel: Channel,\n  options: OptionsWithRequiredCache\n) => {\n  const coreOptions = await options.presets.apply('core');\n\n  initializeChecklist();\n  initializeWhatsNew(channel, options, coreOptions);\n  initializeSaveStory(channel, options, coreOptions);\n\n  initFileSearchChannel(channel, options, coreOptions);\n  initCreateNewStoryChannel(channel, options, coreOptions);\n  initGhostStoriesChannel(channel, options, coreOptions);\n  initOpenInEditorChannel(channel, options, coreOptions);\n  initTelemetryChannel(channel, options);\n\n  return channel;\n};\n\n/**\n * Try to resolve react and react-dom from the root node_modules of the project addon-docs uses this\n * to alias react and react-dom to the project's version when possible If the user doesn't have an\n * explicit dependency on react this will return the existing values Which will be the versions\n * shipped with addon-docs\n */\nexport const resolvedReact = async (existing: any) => {\n  try {\n    return {\n      ...existing,\n      react: resolvePackageDir('react'),\n      reactDom: resolvePackageDir('react-dom'),\n    };\n  } catch (e) {\n    return existing;\n  }\n};\n\nexport const managerEntries = async (existing: any) => {\n  return [\n    pathe.join(resolvePackageDir('storybook'), 'dist/core-server/presets/common-manager.js'),\n    ...(existing || []),\n  ];\n};\n\n// Store the promise (not the result) to prevent race conditions.\n// The promise is assigned synchronously, so concurrent calls will share the same initialization.\n// This is essentially an async singleton pattern.\nlet storyIndexGeneratorPromise: Promise<StoryIndexGenerator> | undefined;\nexport const storyIndexGenerator: PresetPropertyFn<\n  'storyIndexGenerator',\n  StorybookConfigRaw\n> = async (_, options) => {\n  if (storyIndexGeneratorPromise) {\n    return storyIndexGeneratorPromise;\n  }\n\n  storyIndexGeneratorPromise = (async () => {\n    const workingDir = process.cwd();\n    const configDir = options.configDir;\n    const stories = await options.presets.apply('stories');\n    const normalizedStories = normalizeStories(stories, {\n      configDir,\n      workingDir,\n    });\n\n    const [indexers, docs] = await Promise.all([\n      options.presets.apply('experimental_indexers', []),\n      options.presets.apply('docs'),\n    ]);\n\n    const generator = new StoryIndexGenerator(normalizedStories, {\n      workingDir,\n      configDir,\n      indexers,\n      docs,\n    });\n    await generator.initialize();\n    return generator;\n  })();\n\n  return storyIndexGeneratorPromise;\n};\n"
  },
  {
    "path": "code/core/src/core-server/presets/favicon.test.ts",
    "content": "import * as fs from 'node:fs';\n\nimport { expect, it, vi } from 'vitest';\n\nimport { logger } from 'storybook/internal/node-logger';\nimport { type Presets } from 'storybook/internal/types';\n\nimport { dirname, join, normalize } from 'pathe';\n\nimport * as m from './common-preset.ts';\n\n// mock src/core-server/utils/constants.ts:8:27\nvi.mock('../utils/constants', () => {\n  return {\n    defaultStaticDirs: [{ from: './from', to: './to' }],\n    defaultFavicon: join(\n      dirname(require.resolve('storybook/package.json')),\n      '/assets/browser/favicon.svg'\n    ),\n  };\n});\n\nvi.mock('../../shared/utils/module', () => ({\n  resolvePackageDir: vi.fn().mockReturnValue('mocked-path'),\n}));\n\nconst defaultFavicon = join(\n  dirname(require.resolve('storybook/package.json')),\n  '/assets/browser/favicon.svg'\n);\n\nconst createPath = (...p: string[]) => join(process.cwd(), ...p);\nconst createOptions = (locations: string[]): Parameters<typeof m.favicon>[1] => ({\n  configDir: '',\n  presets: {\n    apply: async (extension: string, config: any) => {\n      switch (extension) {\n        case 'staticDirs': {\n          return locations.map((location) => ({ from: location, to: '/' }));\n        }\n        default: {\n          return config as any;\n        }\n      }\n    },\n  } as Presets,\n});\n\nvi.mock('storybook/internal/node-logger', () => {\n  return {\n    logger: {\n      debug: vi.fn(() => {}),\n    },\n  };\n});\n\nvi.mock('node:fs', async (importOriginal) => ({\n  ...(await importOriginal<typeof import('node:fs')>()),\n  existsSync: vi.fn((p: string) => {\n    return false;\n  }),\n  statSync: vi.fn((p: string) => {\n    return {\n      isFile: () => false,\n    };\n  }),\n}));\nconst existsSyncMock = vi.mocked(fs.existsSync);\nconst statSyncMock = vi.mocked(fs.statSync);\n\nit('with no staticDirs favicon should return default', async () => {\n  const options = createOptions([]);\n\n  expect(await m.favicon(undefined, options)).toBe(defaultFavicon);\n});\n\nit('with staticDirs referencing a favicon.ico directly should return the found favicon', async () => {\n  const location = 'favicon.ico';\n  existsSyncMock.mockImplementation((p) => {\n    return normalize(String(p)) === normalize(createPath(location));\n  });\n  statSyncMock.mockImplementation((p) => {\n    return {\n      isFile: () => normalize(String(p)) === normalize(createPath('favicon.ico')),\n    } as any;\n  });\n  const options = createOptions([location]);\n\n  expect(normalize(await m.favicon(undefined, options))).toBe(normalize(createPath('favicon.ico')));\n});\n\nit('with staticDirs containing a single favicon.ico should return the found favicon', async () => {\n  const location = 'static';\n  existsSyncMock.mockImplementation((p) => {\n    if (normalize(String(p)) === normalize(createPath(location))) {\n      return true;\n    }\n    if (normalize(String(p)) === normalize(createPath(location, 'favicon.ico'))) {\n      return true;\n    }\n    return false;\n  });\n  const options = createOptions([location]);\n\n  expect(normalize(await m.favicon(undefined, options))).toBe(\n    normalize(createPath(location, 'favicon.ico'))\n  );\n});\n\nit('with staticDirs containing a single favicon.svg should return the found favicon', async () => {\n  const location = 'static';\n  existsSyncMock.mockImplementation((p) => {\n    if (normalize(String(p)) === normalize(createPath(location))) {\n      return true;\n    }\n    if (normalize(String(p)) === normalize(createPath(location, 'favicon.svg'))) {\n      return true;\n    }\n    return false;\n  });\n  const options = createOptions([location]);\n\n  expect(normalize(await m.favicon(undefined, options))).toBe(\n    normalize(createPath(location, 'favicon.svg'))\n  );\n});\n\nit('with staticDirs containing a multiple favicons should return the first favicon and show a debug message', async () => {\n  const location = 'static';\n  existsSyncMock.mockImplementation((p) => {\n    if (normalize(String(p)) === normalize(createPath(location))) {\n      return true;\n    }\n    if (normalize(String(p)) === normalize(createPath(location, 'favicon.ico'))) {\n      return true;\n    }\n    if (normalize(String(p)) === normalize(createPath(location, 'favicon.svg'))) {\n      return true;\n    }\n    return false;\n  });\n  const options = createOptions([location]);\n\n  expect(normalize(await m.favicon(undefined, options))).toBe(\n    normalize(createPath(location, 'favicon.svg'))\n  );\n\n  expect(logger.debug).toHaveBeenCalledWith(expect.stringContaining('multiple favicons'));\n});\n\nit('with multiple staticDirs containing a multiple favicons should return the first favicon and show a debug message', async () => {\n  const locationA = 'static-a';\n  const locationB = 'static-b';\n  existsSyncMock.mockImplementation((p) => {\n    if (normalize(String(p)) === normalize(createPath(locationA))) {\n      return true;\n    }\n    if (normalize(String(p)) === normalize(createPath(locationB))) {\n      return true;\n    }\n    if (normalize(String(p)) === normalize(createPath(locationA, 'favicon.ico'))) {\n      return true;\n    }\n    if (normalize(String(p)) === normalize(createPath(locationB, 'favicon.svg'))) {\n      return true;\n    }\n    return false;\n  });\n  const options = createOptions([locationA, locationB]);\n\n  expect(normalize(await m.favicon(undefined, options))).toBe(\n    normalize(createPath(locationA, 'favicon.ico'))\n  );\n\n  expect(logger.debug).toHaveBeenCalledWith(expect.stringContaining('multiple favicons'));\n});\n"
  },
  {
    "path": "code/core/src/core-server/presets/wsToken.ts",
    "content": "import { randomUUID } from 'crypto';\n\n/**\n * This function generates a WebSocket token and stores it in the global scope, ensuring it is a\n * singleton.\n *\n * This is because otherwise there is a cyclical dependency between the server channel and the\n * presets:\n *\n * 1. Token is needed to create the server channel\n * 2. Initial loading of all presets needs the server channel\n * 3. Core preset needs to have the token in its channel options\n *\n * By making the token a shared singleton, we can ensure that both the server channel and the\n * presets have access to the same token without creating this circular dependency.\n */\nexport const getWsToken = () => {\n  if (!globalThis.STORYBOOK_WEBSOCKET_TOKEN) {\n    globalThis.STORYBOOK_WEBSOCKET_TOKEN = randomUUID();\n  }\n  return globalThis.STORYBOOK_WEBSOCKET_TOKEN;\n};\n"
  },
  {
    "path": "code/core/src/core-server/server-channel/create-new-story-channel.test.ts",
    "content": "import { join } from 'node:path';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { ChannelTransport } from 'storybook/internal/channels';\nimport { Channel } from 'storybook/internal/channels';\nimport type { CreateNewStoryRequestPayload, RequestData } from 'storybook/internal/core-events';\nimport {\n  CREATE_NEW_STORYFILE_REQUEST,\n  CREATE_NEW_STORYFILE_RESPONSE,\n} from 'storybook/internal/core-events';\n\nimport { initCreateNewStoryChannel } from './create-new-story-channel.ts';\n\nvi.mock('storybook/internal/common', async (importOriginal) => {\n  const actual = await importOriginal<typeof import('storybook/internal/common')>();\n  return {\n    ...actual,\n    getProjectRoot: () => process.cwd(),\n    extractFrameworkPackageName: (name: string) => name?.replace('@storybook/', '') || '',\n    normalizeStories: actual.normalizeStories || ((stories) => stories),\n    getStoryId: async () => ({\n      storyId: 'components-page--default',\n      kind: 'components-page',\n    }),\n  };\n});\n\nconst mockFs = vi.hoisted(() => {\n  return {\n    writeFile: vi.fn(),\n  };\n});\n\nvi.mock('node:fs/promises', async (importOriginal) => {\n  const actual = await importOriginal<typeof import('node:fs/promises')>();\n  return {\n    ...actual,\n    writeFile: mockFs.writeFile,\n  };\n});\n\ndescribe('createNewStoryChannel', () => {\n  const transport = { setHandler: vi.fn(), send: vi.fn() } satisfies ChannelTransport;\n  const mockChannel = new Channel({ transport });\n  const createNewStoryFileEventListener = vi.fn();\n\n  beforeEach(() => {\n    transport.setHandler.mockClear();\n    transport.send.mockClear();\n    createNewStoryFileEventListener.mockClear();\n  });\n\n  describe('initCreateNewStoryChannel', { retry: 3 }, () => {\n    it('should emit an event with a story id', async () => {\n      mockChannel.addListener(CREATE_NEW_STORYFILE_RESPONSE, createNewStoryFileEventListener);\n      const cwd = process.cwd();\n\n      initCreateNewStoryChannel(\n        mockChannel,\n        {\n          configDir: join(cwd, '.storybook'),\n          presets: {\n            apply: (val: string) => {\n              if (val === 'framework') {\n                return Promise.resolve('@storybook/nextjs');\n              }\n              if (val === 'stories') {\n                return Promise.resolve(['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)']);\n              }\n            },\n          },\n        } as any,\n        { disableTelemetry: true }\n      );\n\n      mockChannel.emit(CREATE_NEW_STORYFILE_REQUEST, {\n        id: 'components-page--default',\n        payload: {\n          componentFilePath: 'src/components/Page.jsx',\n          componentExportName: 'Page',\n          componentIsDefaultExport: true,\n        },\n      });\n\n      await vi.waitFor(() => {\n        expect(createNewStoryFileEventListener).toHaveBeenCalled();\n      });\n\n      expect(createNewStoryFileEventListener).toHaveBeenCalledWith({\n        error: null,\n        id: 'components-page--default',\n        payload: {\n          storyId: 'components-page--default',\n          storyFilePath: join('src', 'components', 'Page.stories.jsx'),\n          exportedStoryName: 'Default',\n        },\n        success: true,\n      });\n    });\n\n    it('should emit an error event if an error occurs', async () => {\n      mockChannel.addListener(CREATE_NEW_STORYFILE_RESPONSE, createNewStoryFileEventListener);\n      const cwd = process.cwd();\n\n      mockFs.writeFile.mockImplementation(() => {\n        throw new Error('Failed to write file');\n      });\n\n      initCreateNewStoryChannel(\n        mockChannel,\n        {\n          configDir: join(cwd, '.storybook'),\n          presets: {\n            apply: (val: string) => {\n              if (val === 'framework') {\n                return Promise.resolve('@storybook/nextjs');\n              }\n              if (val === 'stories') {\n                return Promise.resolve(['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)']);\n              }\n            },\n          },\n        } as any,\n        { disableTelemetry: true }\n      );\n\n      mockChannel.emit(CREATE_NEW_STORYFILE_REQUEST, {\n        id: 'components-page--default',\n        payload: {\n          componentFilePath: 'src/components/Page.jsx',\n          componentExportName: 'Page',\n          componentIsDefaultExport: true,\n          componentExportCount: 1,\n        },\n      } satisfies RequestData<CreateNewStoryRequestPayload>);\n\n      await vi.waitFor(() => {\n        expect(createNewStoryFileEventListener).toHaveBeenCalled();\n      });\n\n      expect(createNewStoryFileEventListener).toHaveBeenCalledWith({\n        error: 'Failed to write file',\n        id: 'components-page--default',\n        success: false,\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/server-channel/create-new-story-channel.ts",
    "content": "import type { Channel } from 'storybook/internal/channels';\nimport type {\n  CreateNewStoryErrorPayload,\n  CreateNewStoryRequestPayload,\n  CreateNewStoryResponsePayload,\n  RequestData,\n  ResponseData,\n} from 'storybook/internal/core-events';\nimport {\n  CREATE_NEW_STORYFILE_REQUEST,\n  CREATE_NEW_STORYFILE_RESPONSE,\n} from 'storybook/internal/core-events';\nimport { telemetry } from 'storybook/internal/telemetry';\nimport type { CoreConfig, Options } from 'storybook/internal/types';\n\nimport { generateStoryFile } from '../utils/generate-story.ts';\n\nexport function initCreateNewStoryChannel(\n  channel: Channel,\n  options: Options,\n  coreOptions: CoreConfig\n) {\n  /** Listens for events to create a new storyfile */\n  channel.on(\n    CREATE_NEW_STORYFILE_REQUEST,\n    async (data: RequestData<CreateNewStoryRequestPayload>) => {\n      const result = await generateStoryFile(data.payload, options);\n\n      if (result.success) {\n        channel.emit(CREATE_NEW_STORYFILE_RESPONSE, {\n          success: true,\n          id: data.id,\n          payload: {\n            storyId: result.storyId!,\n            storyFilePath: result.storyFilePath!,\n            exportedStoryName: result.exportedStoryName!,\n          },\n          error: null,\n        } satisfies ResponseData<CreateNewStoryResponsePayload>);\n\n        if (!coreOptions.disableTelemetry) {\n          telemetry('create-new-story-file', {\n            success: true,\n          });\n        }\n      } else {\n        channel.emit(CREATE_NEW_STORYFILE_RESPONSE, {\n          success: false,\n          id: data.id,\n          payload:\n            result.errorType === 'STORY_FILE_EXISTS'\n              ? {\n                  type: 'STORY_FILE_EXISTS',\n                  kind: result.kind!,\n                }\n              : undefined,\n          error: result.error || 'Unknown error occurred',\n        } satisfies ResponseData<CreateNewStoryResponsePayload, CreateNewStoryErrorPayload>);\n\n        if (!coreOptions.disableTelemetry) {\n          await telemetry('create-new-story-file', {\n            success: false,\n            error: result.errorType || result.error,\n          });\n        }\n      }\n    }\n  );\n\n  return channel;\n}\n"
  },
  {
    "path": "code/core/src/core-server/server-channel/file-search-channel.test.ts",
    "content": "// @vitest-environment happy-dom\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { Channel } from 'storybook/internal/channels';\nimport type { ChannelTransport } from 'storybook/internal/channels';\nimport * as common from 'storybook/internal/common';\nimport type {\n  FileComponentSearchRequestPayload,\n  RequestData,\n} from 'storybook/internal/core-events';\nimport {\n  FILE_COMPONENT_SEARCH_REQUEST,\n  FILE_COMPONENT_SEARCH_RESPONSE,\n} from 'storybook/internal/core-events';\n\nimport { SupportedRenderer } from '../../types/index.ts';\nimport { searchFiles } from '../utils/search-files.ts';\nimport { initFileSearchChannel } from './file-search-channel.ts';\n\nvi.mock(import('../utils/search-files.ts'), async (importOriginal) => ({\n  searchFiles: vi.fn((await importOriginal()).searchFiles),\n}));\n\nvi.mock('storybook/internal/common');\n\nbeforeEach(() => {\n  vi.restoreAllMocks();\n  vi.mocked(common.getFrameworkName).mockResolvedValue('@storybook/react');\n  vi.mocked(common.extractRenderer).mockResolvedValue(SupportedRenderer.REACT);\n  vi.spyOn(common, 'getProjectRoot').mockReturnValue(\n    require('path').join(__dirname, '..', 'utils', '__search-files-tests__')\n  );\n});\n\ndescribe('file-search-channel', () => {\n  const transport = { setHandler: vi.fn(), send: vi.fn() } satisfies ChannelTransport;\n  const mockChannel = new Channel({ transport });\n  const searchResultChannelListener = vi.fn();\n\n  describe('initFileSearchChannel', async () => {\n    it('should emit search result event with the search result', { timeout: 10000 }, async () => {\n      const mockOptions = {};\n      const data = { searchQuery: 'es-module' };\n\n      await initFileSearchChannel(mockChannel, mockOptions as any, { disableTelemetry: true });\n\n      mockChannel.addListener(FILE_COMPONENT_SEARCH_RESPONSE, searchResultChannelListener);\n      mockChannel.emit(FILE_COMPONENT_SEARCH_REQUEST, {\n        id: data.searchQuery,\n        payload: {},\n      } satisfies RequestData<FileComponentSearchRequestPayload>);\n\n      await vi.waitFor(() => expect(searchResultChannelListener).toHaveBeenCalled(), {\n        timeout: 8000,\n      });\n\n      expect(searchResultChannelListener).toHaveBeenCalledWith({\n        id: data.searchQuery,\n        error: null,\n        payload: {\n          files: [\n            {\n              exportedComponents: [\n                {\n                  default: false,\n                  name: 'p',\n                },\n                {\n                  default: false,\n                  name: 'q',\n                },\n                {\n                  default: false,\n                  name: 'C',\n                },\n                {\n                  default: false,\n                  name: 'externalName',\n                },\n                {\n                  default: false,\n                  name: 'ns',\n                },\n                {\n                  default: true,\n                  name: 'default',\n                },\n              ],\n              filepath: 'src/es-module.js',\n              storyFileExists: true,\n            },\n          ],\n        },\n        success: true,\n      });\n    });\n\n    it(\n      'should emit search result event with an empty search result',\n      { timeout: 10000 },\n      async () => {\n        const mockOptions = {};\n        const data = { searchQuery: 'no-file-for-search-query' };\n\n        await initFileSearchChannel(mockChannel, mockOptions as any, { disableTelemetry: true });\n\n        mockChannel.addListener(FILE_COMPONENT_SEARCH_RESPONSE, searchResultChannelListener);\n        mockChannel.emit(FILE_COMPONENT_SEARCH_REQUEST, {\n          id: data.searchQuery,\n          payload: {},\n        } satisfies RequestData<FileComponentSearchRequestPayload>);\n\n        await vi.waitFor(\n          () => {\n            expect(searchResultChannelListener).toHaveBeenCalled();\n          },\n          {\n            timeout: 8000,\n          }\n        );\n\n        expect(searchResultChannelListener).toHaveBeenCalledWith({\n          id: data.searchQuery,\n          error: null,\n          payload: {\n            files: [],\n          },\n          success: true,\n        });\n      }\n    );\n\n    it('should emit an error message if an error occurs while searching for components in the project', async () => {\n      const mockOptions = {} as any;\n      const data = { searchQuery: 'commonjs' };\n      await initFileSearchChannel(mockChannel, mockOptions, { disableTelemetry: true });\n\n      mockChannel.addListener(FILE_COMPONENT_SEARCH_RESPONSE, searchResultChannelListener);\n\n      mockChannel.emit(FILE_COMPONENT_SEARCH_REQUEST, {\n        id: data.searchQuery,\n        payload: {},\n      });\n\n      vi.mocked(searchFiles).mockRejectedValue(new Error('ENOENT: no such file or directory'));\n\n      await vi.waitFor(() => expect(searchResultChannelListener).toHaveBeenCalled());\n\n      expect(searchResultChannelListener).toHaveBeenCalledWith({\n        id: data.searchQuery,\n        error:\n          'An error occurred while searching for components in the project.\\nENOENT: no such file or directory',\n        success: false,\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/server-channel/file-search-channel.ts",
    "content": "import { readFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\n\nimport type { Channel } from 'storybook/internal/channels';\nimport { extractRenderer, getFrameworkName, getProjectRoot } from 'storybook/internal/common';\nimport type {\n  FileComponentSearchRequestPayload,\n  FileComponentSearchResponsePayload,\n  RequestData,\n  ResponseData,\n} from 'storybook/internal/core-events';\nimport {\n  FILE_COMPONENT_SEARCH_REQUEST,\n  FILE_COMPONENT_SEARCH_RESPONSE,\n} from 'storybook/internal/core-events';\nimport { telemetry } from 'storybook/internal/telemetry';\nimport type { CoreConfig, Options, SupportedRenderer } from 'storybook/internal/types';\n\nimport { doesStoryFileExist, getStoryMetadata } from '../utils/get-new-story-file.ts';\nimport { getParser } from '../utils/parser/index.ts';\nimport { searchFiles } from '../utils/search-files.ts';\n\nexport async function initFileSearchChannel(\n  channel: Channel,\n  options: Options,\n  coreOptions: CoreConfig\n) {\n  /** Listens for a search query event and searches for files in the project */\n  channel.on(\n    FILE_COMPONENT_SEARCH_REQUEST,\n    async (data: RequestData<FileComponentSearchRequestPayload>) => {\n      const searchQuery = data.id;\n      try {\n        if (!searchQuery) {\n          return;\n        }\n\n        const frameworkName = await getFrameworkName(options);\n\n        const rendererName = (await extractRenderer(frameworkName)) as SupportedRenderer;\n\n        const files = await searchFiles({\n          searchQuery,\n          cwd: getProjectRoot(),\n        });\n\n        const entries = files.map(async (file) => {\n          const parser = getParser(rendererName);\n\n          try {\n            const content = await readFile(join(getProjectRoot(), file), 'utf-8');\n            const { storyFileName } = getStoryMetadata(join(getProjectRoot(), file));\n            const dir = dirname(file);\n\n            const storyFileExists = doesStoryFileExist(join(getProjectRoot(), dir), storyFileName);\n\n            const info = await parser.parse(content);\n\n            return {\n              filepath: file,\n              exportedComponents: info.exports,\n              storyFileExists,\n            };\n          } catch (e) {\n            if (!coreOptions.disableTelemetry) {\n              telemetry('create-new-story-file-search', {\n                success: false,\n                error: `Could not parse file: ${e}`,\n              });\n            }\n\n            return {\n              filepath: file,\n              storyFileExists: false,\n              exportedComponents: null,\n            };\n          }\n        });\n\n        if (!coreOptions.disableTelemetry) {\n          telemetry('create-new-story-file-search', {\n            success: true,\n            payload: {\n              fileCount: entries.length,\n            },\n          });\n        }\n\n        channel.emit(FILE_COMPONENT_SEARCH_RESPONSE, {\n          success: true,\n          id: searchQuery,\n          payload: {\n            files: await Promise.all(entries),\n          },\n          error: null,\n        } satisfies ResponseData<FileComponentSearchResponsePayload>);\n      } catch (e: any) {\n        /** Emits the search result event with an error message */\n        channel.emit(FILE_COMPONENT_SEARCH_RESPONSE, {\n          success: false,\n          id: searchQuery ?? '',\n          error: `An error occurred while searching for components in the project.\\n${e?.message}`,\n        } satisfies ResponseData<FileComponentSearchResponsePayload>);\n\n        if (!coreOptions.disableTelemetry) {\n          telemetry('create-new-story-file-search', {\n            success: false,\n            error: `An error occurred while searching for components: ${e}`,\n          });\n        }\n      }\n    }\n  );\n\n  return channel;\n}\n"
  },
  {
    "path": "code/core/src/core-server/server-channel/ghost-stories-channel.test.ts",
    "content": "import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { ChannelTransport } from 'storybook/internal/channels';\nimport { Channel } from 'storybook/internal/channels';\nimport { GHOST_STORIES_REQUEST, GHOST_STORIES_RESPONSE } from 'storybook/internal/core-events';\nimport type { Options } from 'storybook/internal/types';\n\nimport { initGhostStoriesChannel } from './ghost-stories-channel.ts';\n\nvi.mock('storybook/internal/common', async (importOriginal) => {\n  const actual = await importOriginal<typeof import('storybook/internal/common')>();\n  return {\n    ...actual,\n    cache: {\n      get: vi.fn(),\n      set: vi.fn(),\n    },\n    executeCommand: vi.fn(),\n    resolvePathInStorybookCache: vi.fn(),\n  };\n});\n\nvi.mock('storybook/internal/telemetry', async (importOriginal) => {\n  const actual = await importOriginal<typeof import('storybook/internal/telemetry')>();\n  return {\n    ...actual,\n    getLastEvents: vi.fn(),\n    getSessionId: vi.fn(),\n    getStorybookMetadata: vi.fn(),\n    telemetry: vi.fn(),\n  };\n});\n\nvi.mock('../utils/ghost-stories/get-candidates', async (importOriginal) => {\n  const actual = await importOriginal<typeof import('../utils/ghost-stories/get-candidates')>();\n  return {\n    ...actual,\n    getComponentCandidates: vi.fn(),\n  };\n});\n\nconst mockFs = vi.hoisted(() => {\n  return {\n    existsSync: vi.fn(),\n    mkdir: vi.fn(),\n    readFile: vi.fn(),\n  };\n});\n\nvi.mock('node:fs', async (importOriginal) => {\n  const actual = await importOriginal<typeof import('node:fs')>();\n  return {\n    ...actual,\n    existsSync: mockFs.existsSync,\n  };\n});\n\nvi.mock('node:fs/promises', async (importOriginal) => {\n  const actual = await importOriginal<typeof import('node:fs/promises')>();\n  return {\n    ...actual,\n    mkdir: mockFs.mkdir,\n    readFile: mockFs.readFile,\n  };\n});\n\nconst mockCommon = await import('storybook/internal/common');\nconst mockTelemetry = await import('storybook/internal/telemetry');\nconst mockStoryGeneration = await import('../utils/ghost-stories/get-candidates.ts');\n\ndescribe('ghostStoriesChannel', () => {\n  const transport = { setHandler: vi.fn(), send: vi.fn() } satisfies ChannelTransport;\n  const mockChannel = new Channel({ transport });\n  const ghostStoriesEventListener = vi.fn();\n  // to avoid noise in the test output\n  const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});\n  const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});\n\n  beforeEach(() => {\n    transport.setHandler.mockClear();\n    transport.send.mockClear();\n    ghostStoriesEventListener.mockClear();\n    consoleErrorSpy.mockClear();\n    consoleLogSpy.mockClear();\n\n    // Reset channel listeners\n    mockChannel.removeAllListeners();\n\n    // Reset all mocks\n    vi.mocked(mockCommon.cache.get).mockReset();\n    vi.mocked(mockCommon.cache.set).mockReset();\n    vi.mocked(mockCommon.executeCommand).mockReset();\n    vi.mocked(mockCommon.resolvePathInStorybookCache).mockReset();\n    vi.mocked(mockTelemetry.getLastEvents).mockReset();\n    vi.mocked(mockTelemetry.getSessionId).mockReset();\n    vi.mocked(mockTelemetry.getStorybookMetadata).mockReset();\n    vi.mocked(mockTelemetry.telemetry).mockReset();\n    vi.mocked(mockStoryGeneration.getComponentCandidates).mockReset();\n    mockFs.existsSync.mockReset();\n    mockFs.mkdir.mockReset();\n    mockFs.readFile.mockReset();\n  });\n\n  afterAll(() => {\n    consoleErrorSpy.mockRestore();\n    consoleLogSpy.mockRestore();\n  });\n\n  describe('initGhostStoriesChannel', { retry: 3 }, () => {\n    it('should execute successful discovery run', async () => {\n      mockChannel.addListener(GHOST_STORIES_RESPONSE, ghostStoriesEventListener);\n      // Has not run yet (no ghost stories event and session matches)\n      vi.mocked(mockTelemetry.getLastEvents).mockResolvedValue({\n        init: { body: { sessionId: 'test-session' } },\n      } as any);\n      vi.mocked(mockTelemetry.getSessionId).mockResolvedValue('test-session');\n\n      // Has React + Vitest\n      vi.mocked(mockTelemetry.getStorybookMetadata).mockResolvedValue({\n        renderer: '@storybook/react',\n        addons: { '@storybook/addon-vitest': {} },\n      } as any);\n\n      // Has valid candidates for story files\n      vi.mocked(mockStoryGeneration.getComponentCandidates).mockResolvedValue({\n        candidates: ['component1.tsx', 'component2.tsx'],\n        globMatchCount: 10,\n        analyzedCount: 5,\n        avgComplexity: 2.5,\n      });\n\n      // Has ran tests successfully and written reports to JSON file in cache directory\n      vi.mocked(mockCommon.resolvePathInStorybookCache).mockReturnValue(\n        '/cache/ghost-stories-tests'\n      );\n      vi.mocked(mockCommon.executeCommand).mockResolvedValue({} as any);\n      mockFs.existsSync.mockReturnValue(true);\n      mockFs.readFile.mockResolvedValue(\n        JSON.stringify({\n          numTotalTests: 2,\n          numPassedTests: 2,\n          numFailedTests: 0,\n          testResults: [\n            {\n              assertionResults: [\n                {\n                  meta: { storyId: 'component1--default' },\n                  status: 'passed',\n                },\n                {\n                  meta: { storyId: 'component2--default' },\n                  status: 'passed',\n                },\n              ],\n            },\n          ],\n        })\n      );\n\n      initGhostStoriesChannel(mockChannel, {} as Options, { disableTelemetry: false });\n\n      mockChannel.emit(GHOST_STORIES_REQUEST);\n\n      await vi.waitFor(() => {\n        expect(ghostStoriesEventListener).toHaveBeenCalled();\n      });\n\n      // Vitest command is executed with the correct arguments\n      expect(mockCommon.executeCommand).toHaveBeenCalledWith({\n        command: 'npx',\n        args: [\n          'vitest',\n          'run',\n          '--reporter=json',\n          '--testTimeout=1000',\n          expect.stringContaining('--outputFile=/cache/ghost-stories-tests/test-results-'),\n          'component1.tsx',\n          'component2.tsx',\n        ],\n        stdio: 'pipe',\n        env: {\n          STORYBOOK_COMPONENT_PATHS: 'component1.tsx;component2.tsx',\n        },\n      } as any);\n\n      // Telemetry is called with the correct data\n      expect(mockTelemetry.telemetry).toHaveBeenCalledWith('ghost-stories', {\n        stats: {\n          globMatchCount: 10,\n          candidateAnalysisDuration: expect.any(Number),\n          totalRunDuration: expect.any(Number),\n          analyzedCount: 5,\n          avgComplexity: 2.5,\n          candidateCount: 2,\n          testRunDuration: expect.any(Number),\n        },\n        results: {\n          total: 2,\n          passed: 2,\n          successRate: 1,\n          successRateWithoutEmptyRender: 1,\n          categorizedErrors: expect.any(Object),\n          uniqueErrorCount: 0,\n          passedButEmptyRender: 0,\n        },\n      });\n    });\n\n    it('should execute successful discovery run with test failure', async () => {\n      mockChannel.addListener(GHOST_STORIES_RESPONSE, ghostStoriesEventListener);\n      // Has not run yet (no ghost stories event and session matches)\n      vi.mocked(mockTelemetry.getLastEvents).mockResolvedValue({\n        init: { body: { sessionId: 'test-session' } },\n      } as any);\n      vi.mocked(mockTelemetry.getSessionId).mockResolvedValue('test-session');\n\n      // Has React + Vitest\n      vi.mocked(mockTelemetry.getStorybookMetadata).mockResolvedValue({\n        renderer: '@storybook/react',\n        addons: { '@storybook/addon-vitest': {} },\n      } as any);\n\n      // Has valid candidates for story files\n      vi.mocked(mockStoryGeneration.getComponentCandidates).mockResolvedValue({\n        candidates: ['component1.tsx', 'component2.tsx'],\n        globMatchCount: 10,\n      });\n\n      // Has ran tests but with failures, reports written to JSON file in cache directory\n      vi.mocked(mockCommon.resolvePathInStorybookCache).mockReturnValue(\n        '/cache/ghost-stories-tests'\n      );\n      vi.mocked(mockCommon.executeCommand).mockResolvedValue({} as any);\n      mockFs.existsSync.mockReturnValue(true);\n      mockFs.readFile.mockResolvedValue(\n        JSON.stringify({\n          numTotalTests: 2,\n          numPassedTests: 0,\n          numFailedTests: 2,\n          testResults: [\n            {\n              assertionResults: [\n                {\n                  meta: { storyId: 'component1--default' },\n                  status: 'failed',\n                  failureMessages: ['Error: Expected button to be disabled'],\n                },\n                {\n                  meta: { storyId: 'component2--default' },\n                  status: 'failed',\n                  failureMessages: ['TypeError: Cannot read properties of undefined'],\n                },\n              ],\n            },\n          ],\n        })\n      );\n\n      initGhostStoriesChannel(mockChannel, {} as Options, { disableTelemetry: false });\n\n      mockChannel.emit(GHOST_STORIES_REQUEST);\n\n      await vi.waitFor(() => {\n        expect(ghostStoriesEventListener).toHaveBeenCalled();\n      });\n\n      // Vitest command is executed with the correct arguments\n      expect(mockCommon.executeCommand).toHaveBeenCalledWith({\n        command: 'npx',\n        args: [\n          'vitest',\n          'run',\n          '--reporter=json',\n          '--testTimeout=1000',\n          expect.stringContaining('--outputFile=/cache/ghost-stories-tests/test-results-'),\n          'component1.tsx',\n          'component2.tsx',\n        ],\n        stdio: 'pipe',\n        env: {\n          STORYBOOK_COMPONENT_PATHS: 'component1.tsx;component2.tsx',\n        },\n      } as any);\n\n      // Telemetry is called with the correct data\n      expect(mockTelemetry.telemetry).toHaveBeenCalledWith(\n        'ghost-stories',\n        expect.objectContaining({\n          stats: {\n            globMatchCount: 10,\n            candidateAnalysisDuration: expect.any(Number),\n            totalRunDuration: expect.any(Number),\n            analyzedCount: expect.any(Number),\n            avgComplexity: expect.any(Number),\n            candidateCount: 2,\n            testRunDuration: expect.any(Number),\n          },\n          results: expect.objectContaining({\n            total: 2,\n            passed: 0,\n            successRate: 0,\n            // categorizedErrors is now an object with categories as keys\n            categorizedErrors: expect.any(Object),\n            uniqueErrorCount: expect.any(Number),\n            passedButEmptyRender: 0,\n          }),\n        })\n      );\n    });\n\n    describe('no-op conditions', () => {\n      it('should skip discovery run when telemetry is disabled', async () => {\n        mockChannel.addListener(GHOST_STORIES_RESPONSE, ghostStoriesEventListener);\n\n        initGhostStoriesChannel(mockChannel, {} as Options, { disableTelemetry: true });\n\n        mockChannel.emit(GHOST_STORIES_REQUEST);\n\n        // When telemetry is disabled, no listener is set up, so wait a bit and check nothing happened\n        await new Promise((resolve) => setTimeout(resolve, 10));\n\n        expect(ghostStoriesEventListener).not.toHaveBeenCalled();\n        expect(mockCommon.cache.get).not.toHaveBeenCalled();\n        expect(mockTelemetry.getStorybookMetadata).not.toHaveBeenCalled();\n        expect(mockStoryGeneration.getComponentCandidates).not.toHaveBeenCalled();\n      });\n\n      it('should skip discovery run when already ran', async () => {\n        mockChannel.addListener(GHOST_STORIES_RESPONSE, ghostStoriesEventListener);\n        // Has already run (ghost stories event exists)\n        vi.mocked(mockTelemetry.getLastEvents).mockResolvedValue({\n          'ghost-stories': { timestamp: Date.now(), body: {} },\n          init: { body: { sessionId: 'test-session' } },\n        } as any);\n        vi.mocked(mockTelemetry.getSessionId).mockResolvedValue('test-session');\n\n        initGhostStoriesChannel(mockChannel, {} as Options, { disableTelemetry: false });\n\n        mockChannel.emit(GHOST_STORIES_REQUEST);\n\n        await vi.waitFor(() => {\n          expect(ghostStoriesEventListener).toHaveBeenCalled();\n        });\n\n        expect(mockTelemetry.getLastEvents).toHaveBeenCalled();\n        expect(mockTelemetry.getSessionId).toHaveBeenCalled();\n        expect(mockTelemetry.getStorybookMetadata).not.toHaveBeenCalled();\n        expect(mockStoryGeneration.getComponentCandidates).not.toHaveBeenCalled();\n      });\n\n      it('should skip discovery run when not in a React + Vitest project', async () => {\n        mockChannel.addListener(GHOST_STORIES_RESPONSE, ghostStoriesEventListener);\n        // Has not run yet (no ghost stories event and session matches)\n        vi.mocked(mockTelemetry.getLastEvents).mockResolvedValue({\n          init: { body: { sessionId: 'test-session' } },\n        } as any);\n        vi.mocked(mockTelemetry.getSessionId).mockResolvedValue('test-session');\n        vi.mocked(mockTelemetry.getStorybookMetadata).mockResolvedValue({\n          renderer: '@storybook/vue',\n          addons: { '@storybook/addon-vitest': {} },\n        } as any);\n\n        initGhostStoriesChannel(mockChannel, {} as Options, { disableTelemetry: false });\n\n        mockChannel.emit(GHOST_STORIES_REQUEST);\n\n        await vi.waitFor(() => {\n          expect(ghostStoriesEventListener).toHaveBeenCalled();\n        });\n\n        expect(mockTelemetry.getLastEvents).toHaveBeenCalled();\n        expect(mockTelemetry.getSessionId).toHaveBeenCalled();\n        expect(mockTelemetry.getStorybookMetadata).toHaveBeenCalled();\n        expect(mockStoryGeneration.getComponentCandidates).not.toHaveBeenCalled();\n      });\n\n      it('should skip discovery run when vitest addon not present', async () => {\n        mockChannel.addListener(GHOST_STORIES_RESPONSE, ghostStoriesEventListener);\n        // Has not run yet (no ghost stories event and session matches)\n        vi.mocked(mockTelemetry.getLastEvents).mockResolvedValue({\n          init: { body: { sessionId: 'test-session' } },\n        } as any);\n        vi.mocked(mockTelemetry.getSessionId).mockResolvedValue('test-session');\n        vi.mocked(mockTelemetry.getStorybookMetadata).mockResolvedValue({\n          renderer: '@storybook/react',\n          addons: {},\n        } as any);\n\n        initGhostStoriesChannel(mockChannel, {} as Options, { disableTelemetry: false });\n\n        mockChannel.emit(GHOST_STORIES_REQUEST);\n\n        await vi.waitFor(() => {\n          expect(ghostStoriesEventListener).toHaveBeenCalled();\n        });\n\n        expect(mockTelemetry.getLastEvents).toHaveBeenCalled();\n        expect(mockTelemetry.getSessionId).toHaveBeenCalled();\n        expect(mockTelemetry.getStorybookMetadata).toHaveBeenCalled();\n        expect(mockStoryGeneration.getComponentCandidates).not.toHaveBeenCalled();\n      });\n    });\n\n    describe('error conditions', () => {\n      it('should handle error in getComponentCandidates', async () => {\n        mockChannel.addListener(GHOST_STORIES_RESPONSE, ghostStoriesEventListener);\n        // Has not run yet (no ghost stories event and session matches)\n        vi.mocked(mockTelemetry.getLastEvents).mockResolvedValue({\n          init: { body: { sessionId: 'test-session' } },\n        } as any);\n        vi.mocked(mockTelemetry.getSessionId).mockResolvedValue('test-session');\n        vi.mocked(mockTelemetry.getStorybookMetadata).mockResolvedValue({\n          renderer: '@storybook/react',\n          addons: { '@storybook/addon-vitest': {} },\n        } as any);\n        vi.mocked(mockStoryGeneration.getComponentCandidates).mockResolvedValue({\n          candidates: [],\n          error: 'Failed to analyze components',\n          globMatchCount: 0,\n        });\n\n        initGhostStoriesChannel(mockChannel, {} as Options, { disableTelemetry: false });\n\n        mockChannel.emit(GHOST_STORIES_REQUEST);\n\n        await vi.waitFor(() => {\n          expect(ghostStoriesEventListener).toHaveBeenCalled();\n        });\n\n        expect(mockStoryGeneration.getComponentCandidates).toHaveBeenCalled();\n        expect(mockTelemetry.telemetry).toHaveBeenCalledWith('ghost-stories', {\n          runError: 'Failed to analyze components',\n          stats: {\n            globMatchCount: 0,\n            candidateAnalysisDuration: expect.any(Number),\n            totalRunDuration: expect.any(Number),\n            analyzedCount: 0,\n            avgComplexity: 0,\n            candidateCount: 0,\n          },\n        });\n      });\n\n      it('should handle no candidates found', async () => {\n        mockChannel.addListener(GHOST_STORIES_RESPONSE, ghostStoriesEventListener);\n        // Has not run yet (no ghost stories event and session matches)\n        vi.mocked(mockTelemetry.getLastEvents).mockResolvedValue({\n          init: { body: { sessionId: 'test-session' } },\n        } as any);\n        vi.mocked(mockTelemetry.getSessionId).mockResolvedValue('test-session');\n        vi.mocked(mockTelemetry.getStorybookMetadata).mockResolvedValue({\n          renderer: '@storybook/react',\n          addons: { '@storybook/addon-vitest': {} },\n        } as any);\n        vi.mocked(mockStoryGeneration.getComponentCandidates).mockResolvedValue({\n          candidates: [],\n          globMatchCount: 5,\n          analyzedCount: 3,\n          avgComplexity: 1.5,\n        });\n\n        initGhostStoriesChannel(mockChannel, {} as Options, { disableTelemetry: false });\n\n        mockChannel.emit(GHOST_STORIES_REQUEST);\n\n        await vi.waitFor(() => {\n          expect(ghostStoriesEventListener).toHaveBeenCalled();\n        });\n\n        expect(mockStoryGeneration.getComponentCandidates).toHaveBeenCalled();\n        expect(mockTelemetry.telemetry).toHaveBeenCalledWith('ghost-stories', {\n          runError: 'No candidates found',\n          stats: {\n            globMatchCount: 5,\n            candidateAnalysisDuration: expect.any(Number),\n            totalRunDuration: expect.any(Number),\n            analyzedCount: 3,\n            avgComplexity: 1.5,\n            candidateCount: 0,\n          },\n        });\n      });\n\n      it('should handle JSON report not found', async () => {\n        mockChannel.addListener(GHOST_STORIES_RESPONSE, ghostStoriesEventListener);\n        // Has not run yet (no ghost stories event and session matches)\n        vi.mocked(mockTelemetry.getLastEvents).mockResolvedValue({\n          init: { body: { sessionId: 'test-session' } },\n        } as any);\n        vi.mocked(mockTelemetry.getSessionId).mockResolvedValue('test-session');\n        vi.mocked(mockTelemetry.getStorybookMetadata).mockResolvedValue({\n          renderer: '@storybook/react',\n          addons: { '@storybook/addon-vitest': {} },\n        } as any);\n        vi.mocked(mockStoryGeneration.getComponentCandidates).mockResolvedValue({\n          candidates: ['component1.tsx'],\n          globMatchCount: 5,\n          analyzedCount: 2,\n          avgComplexity: 1.0,\n        });\n        vi.mocked(mockCommon.resolvePathInStorybookCache).mockReturnValue(\n          '/cache/ghost-stories-tests'\n        );\n        vi.mocked(mockCommon.executeCommand).mockRejectedValue(new Error('Test execution failed'));\n        mockFs.existsSync.mockReturnValue(false);\n\n        initGhostStoriesChannel(mockChannel, {} as Options, { disableTelemetry: false });\n\n        mockChannel.emit(GHOST_STORIES_REQUEST);\n\n        await vi.waitFor(() => {\n          expect(ghostStoriesEventListener).toHaveBeenCalled();\n        });\n\n        expect(mockTelemetry.telemetry).toHaveBeenCalledWith('ghost-stories', {\n          runError: 'JSON report not found',\n          stats: {\n            globMatchCount: 5,\n            candidateAnalysisDuration: expect.any(Number),\n            totalRunDuration: expect.any(Number),\n            analyzedCount: 2,\n            avgComplexity: 1.0,\n            candidateCount: 1,\n            testRunDuration: expect.any(Number),\n          },\n        });\n      });\n\n      it('should handle test startup error', async () => {\n        mockChannel.addListener(GHOST_STORIES_RESPONSE, ghostStoriesEventListener);\n        // Has not run yet (no ghost stories event and session matches)\n        vi.mocked(mockTelemetry.getLastEvents).mockResolvedValue({\n          init: { body: { sessionId: 'test-session' } },\n        } as any);\n        vi.mocked(mockTelemetry.getSessionId).mockResolvedValue('test-session');\n        vi.mocked(mockTelemetry.getStorybookMetadata).mockResolvedValue({\n          renderer: '@storybook/react',\n          addons: { '@storybook/addon-vitest': {} },\n        } as any);\n        vi.mocked(mockStoryGeneration.getComponentCandidates).mockResolvedValue({\n          candidates: ['component1.tsx'],\n          globMatchCount: 5,\n          analyzedCount: 2,\n          avgComplexity: 1.0,\n        });\n        vi.mocked(mockCommon.resolvePathInStorybookCache).mockReturnValue(\n          '/cache/ghost-stories-tests'\n        );\n        vi.mocked(mockCommon.executeCommand).mockRejectedValue(new Error('Startup Error'));\n        mockFs.existsSync.mockReturnValue(true);\n        mockFs.readFile.mockResolvedValue(\n          JSON.stringify({\n            numTotalTests: 2,\n            numPassedTests: 0,\n            numFailedTests: 2,\n            testResults: [],\n          })\n        );\n\n        initGhostStoriesChannel(mockChannel, {} as Options, { disableTelemetry: false });\n\n        mockChannel.emit(GHOST_STORIES_REQUEST);\n\n        await vi.waitFor(() => {\n          expect(ghostStoriesEventListener).toHaveBeenCalled();\n        });\n\n        expect(mockTelemetry.telemetry).toHaveBeenCalledWith('ghost-stories', {\n          runError: 'Startup Error',\n          stats: {\n            globMatchCount: 5,\n            candidateAnalysisDuration: expect.any(Number),\n            totalRunDuration: expect.any(Number),\n            analyzedCount: 2,\n            avgComplexity: 1.0,\n            candidateCount: 1,\n            testRunDuration: expect.any(Number),\n          },\n        });\n      });\n\n      it('should handle general error during execution', async () => {\n        mockChannel.addListener(GHOST_STORIES_RESPONSE, ghostStoriesEventListener);\n        vi.mocked(mockTelemetry.getLastEvents).mockRejectedValue(new Error('Cache error') as any);\n\n        initGhostStoriesChannel(mockChannel, {} as Options, { disableTelemetry: false });\n\n        mockChannel.emit(GHOST_STORIES_REQUEST);\n\n        await vi.waitFor(() => {\n          expect(ghostStoriesEventListener).toHaveBeenCalled();\n        });\n\n        expect(mockTelemetry.telemetry).toHaveBeenCalledWith('ghost-stories', {\n          runError: 'Unknown error during ghost run',\n          stats: {},\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/server-channel/ghost-stories-channel.ts",
    "content": "import type { Channel } from 'storybook/internal/channels';\nimport { GHOST_STORIES_REQUEST, GHOST_STORIES_RESPONSE } from 'storybook/internal/core-events';\nimport {\n  getLastEvents,\n  getSessionId,\n  getStorybookMetadata,\n  telemetry,\n} from 'storybook/internal/telemetry';\nimport type { CoreConfig, Options } from 'storybook/internal/types';\n\nimport { getComponentCandidates } from '../utils/ghost-stories/get-candidates.ts';\nimport { runStoryTests } from '../utils/ghost-stories/run-story-tests.ts';\n\nexport function initGhostStoriesChannel(\n  channel: Channel,\n  options: Options,\n  coreOptions: CoreConfig\n) {\n  if (coreOptions.disableTelemetry) {\n    return channel;\n  }\n\n  /** Listens for events to discover and test stories */\n  channel.on(GHOST_STORIES_REQUEST, async () => {\n    const stats: {\n      globMatchCount?: number;\n      candidateAnalysisDuration?: number;\n      totalRunDuration?: number;\n      analyzedCount?: number;\n      avgComplexity?: number;\n      candidateCount?: number;\n      testRunDuration?: number;\n    } = {};\n\n    try {\n      const ghostRunStart = Date.now();\n      const lastEvents = await getLastEvents();\n      const lastInit = lastEvents?.init;\n      if (!lastEvents || !lastInit) {\n        return;\n      }\n\n      const sessionId = await getSessionId();\n      const lastGhostStoriesRun = lastEvents['ghost-stories'];\n      if (\n        lastGhostStoriesRun ||\n        (lastInit.body?.sessionId && lastInit.body.sessionId !== sessionId)\n      ) {\n        return;\n      }\n\n      const metadata = await getStorybookMetadata(options.configDir);\n      const isReactStorybook = metadata?.renderer?.includes('@storybook/react');\n      const hasVitestAddon =\n        !!metadata?.addons &&\n        Object.keys(metadata.addons).some((addonKey) =>\n          addonKey.includes('@storybook/addon-vitest')\n        );\n\n      // For now this is gated by React + Vitest\n      if (!isReactStorybook || !hasVitestAddon) {\n        return;\n      }\n\n      // Phase 1: find candidates from components\n      const candidateAnalysisStart = Date.now();\n      const candidatesResult = await getComponentCandidates();\n      stats.candidateAnalysisDuration = Date.now() - candidateAnalysisStart;\n      stats.globMatchCount = candidatesResult.globMatchCount;\n      stats.analyzedCount = candidatesResult.analyzedCount ?? 0;\n      stats.avgComplexity = candidatesResult.avgComplexity ?? 0;\n      stats.candidateCount = candidatesResult.candidates.length;\n\n      if (candidatesResult.error) {\n        stats.totalRunDuration = Date.now() - ghostRunStart;\n        telemetry('ghost-stories', {\n          stats,\n          runError: candidatesResult.error,\n        });\n        return;\n      }\n\n      if (candidatesResult.candidates.length === 0) {\n        stats.totalRunDuration = Date.now() - ghostRunStart;\n        telemetry('ghost-stories', {\n          stats,\n          runError: 'No candidates found',\n        });\n        return;\n      }\n\n      // Phase 2: Run tests on those candidates Vitest. The components will be transformed directly to tests\n      // If they pass, it means that creating a story file for them would succeed.\n      const testRunResult = await runStoryTests(candidatesResult.candidates);\n      stats.totalRunDuration = Date.now() - ghostRunStart;\n      stats.testRunDuration = testRunResult.duration;\n      if (testRunResult.runError) {\n        telemetry('ghost-stories', {\n          stats,\n          runError: testRunResult.runError,\n        });\n        return;\n      }\n\n      telemetry('ghost-stories', {\n        stats,\n        results: testRunResult.summary,\n      });\n    } catch {\n      telemetry('ghost-stories', {\n        stats,\n        runError: 'Unknown error during ghost run',\n      });\n    } finally {\n      // we don't currently do anything with this, but will be useful in the future\n      channel.emit(GHOST_STORIES_RESPONSE);\n    }\n  });\n\n  return channel;\n}\n"
  },
  {
    "path": "code/core/src/core-server/server-channel/open-in-editor-channel.ts",
    "content": "import type { Channel } from 'storybook/internal/channels';\nimport type {\n  OpenInEditorRequestPayload,\n  OpenInEditorResponsePayload,\n} from 'storybook/internal/core-events';\nimport { OPEN_IN_EDITOR_REQUEST, OPEN_IN_EDITOR_RESPONSE } from 'storybook/internal/core-events';\nimport { telemetry } from 'storybook/internal/telemetry';\nimport type { CoreConfig, Options, StoryIndex } from 'storybook/internal/types';\n\nimport launch from 'launch-editor';\n\nexport async function initOpenInEditorChannel(\n  channel: Channel,\n  _options: Options,\n  coreOptions: CoreConfig\n) {\n  channel.on(OPEN_IN_EDITOR_REQUEST, async (payload: OpenInEditorRequestPayload) => {\n    const sendTelemetry = (data: { success: boolean; error?: string }) => {\n      if (!coreOptions.disableTelemetry) {\n        telemetry('open-in-editor', data);\n      }\n    };\n    try {\n      const { file: targetFile, line, column } = payload;\n\n      if (!targetFile) {\n        throw new Error('No file was provided to open');\n      }\n\n      const location =\n        typeof line === 'number'\n          ? `${targetFile}:${line}${typeof column === 'number' ? `:${column}` : ''}`\n          : targetFile;\n\n      await new Promise<void>((resolve, reject) => {\n        launch(location, undefined, (_fileName: string, errorMessage: string | null) => {\n          if (errorMessage) {\n            reject(new Error(errorMessage));\n          } else {\n            resolve();\n          }\n        });\n      });\n\n      channel.emit(OPEN_IN_EDITOR_RESPONSE, {\n        file: targetFile!,\n        line,\n        column,\n        error: null,\n      } satisfies OpenInEditorResponsePayload);\n\n      sendTelemetry({ success: true });\n    } catch (e: any) {\n      const error = e?.message || 'Failed to open in editor';\n      channel.emit(OPEN_IN_EDITOR_RESPONSE, {\n        error,\n        ...payload,\n      } satisfies OpenInEditorResponsePayload);\n\n      sendTelemetry({ success: false, error });\n    }\n  });\n\n  return channel;\n}\n"
  },
  {
    "path": "code/core/src/core-server/server-channel/telemetry-channel.test.ts",
    "content": "import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { makePayload } from './telemetry-channel.ts';\n\ndescribe('makePayload', () => {\n  beforeEach(() => {\n    vi.useFakeTimers();\n    vi.setSystemTime(new Date('2024-01-01T00:00:00Z'));\n  });\n  afterEach(() => {\n    vi.useRealTimers();\n  });\n\n  it('new user init session', () => {\n    const userAgent = 'Mozilla/5.0';\n    const sessionId = 'session-123';\n    const lastInit = {\n      timestamp: Date.now() - 3000,\n      body: {\n        sessionId,\n        payload: { newUser: true },\n      },\n    };\n\n    expect(makePayload(userAgent, lastInit as any, sessionId)).toMatchInlineSnapshot(`\n      {\n        \"isNewUser\": true,\n        \"timeSinceInit\": 3000,\n        \"userAgent\": \"Mozilla/5.0\",\n      }\n    `);\n  });\n\n  it('existing user init session', () => {\n    const userAgent = 'Mozilla/5.0';\n    const sessionId = 'session-123';\n    const lastInit = {\n      timestamp: Date.now() - 3000,\n      body: {\n        sessionId,\n        payload: {},\n      },\n    };\n\n    expect(makePayload(userAgent, lastInit as any, sessionId)).toMatchInlineSnapshot(`\n      {\n        \"isNewUser\": false,\n        \"timeSinceInit\": 3000,\n        \"userAgent\": \"Mozilla/5.0\",\n      }\n    `);\n  });\n\n  it('no init session', () => {\n    const userAgent = 'Mozilla/5.0';\n    const sessionId = 'session-123';\n    const lastInit = undefined;\n\n    expect(makePayload(userAgent, lastInit, sessionId)).toMatchInlineSnapshot(`\n      {\n        \"isNewUser\": false,\n        \"timeSinceInit\": undefined,\n        \"userAgent\": \"Mozilla/5.0\",\n      }\n    `);\n  });\n\n  it('init session with different sessionId', () => {\n    const userAgent = 'Mozilla/5.0';\n    const sessionId = 'session-123';\n    const lastInit = {\n      timestamp: Date.now() - 3000,\n      body: {\n        sessionId: 'session-456',\n      },\n    };\n\n    expect(makePayload(userAgent, lastInit as any, sessionId)).toMatchInlineSnapshot(`\n      {\n        \"isNewUser\": false,\n        \"timeSinceInit\": undefined,\n        \"userAgent\": \"Mozilla/5.0\",\n      }\n    `);\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/server-channel/telemetry-channel.ts",
    "content": "import type { Channel } from 'storybook/internal/channels';\nimport {\n  PREVIEW_INITIALIZED,\n  SHARE_ISOLATE_MODE,\n  SHARE_POPOVER_OPENED,\n  SHARE_STORY_LINK,\n} from 'storybook/internal/core-events';\nimport { type InitPayload, telemetry } from 'storybook/internal/telemetry';\nimport { type CacheEntry, getLastEvents } from 'storybook/internal/telemetry';\nimport { getSessionId } from 'storybook/internal/telemetry';\nimport type { Options } from 'storybook/internal/types';\n\nexport const makePayload = (\n  userAgent: string,\n  lastInit: CacheEntry | undefined,\n  sessionId: string\n) => {\n  let timeSinceInit: number | undefined;\n  const payload = {\n    userAgent,\n    isNewUser: false,\n    timeSinceInit,\n  };\n\n  if (sessionId && lastInit?.body?.sessionId === sessionId) {\n    payload.timeSinceInit = Date.now() - lastInit.timestamp;\n    payload.isNewUser = !!(lastInit.body.payload as InitPayload).newUser;\n  }\n  return payload;\n};\n\nexport function initTelemetryChannel(channel: Channel, options: Options) {\n  if (!options.disableTelemetry) {\n    channel.on(PREVIEW_INITIALIZED, async ({ userAgent }) => {\n      try {\n        const sessionId = await getSessionId();\n        const lastEvents = await getLastEvents();\n        const lastInit = lastEvents.init;\n        const lastPreviewFirstLoad = lastEvents['preview-first-load'];\n        if (!lastPreviewFirstLoad) {\n          const payload = makePayload(userAgent, lastInit, sessionId);\n          telemetry('preview-first-load', payload);\n        }\n      } catch {}\n    });\n    channel.on(SHARE_POPOVER_OPENED, async () => {\n      telemetry('share', { action: 'popover-opened' });\n    });\n    channel.on(SHARE_STORY_LINK, async () => {\n      telemetry('share', { action: 'story-link-copied' });\n    });\n    channel.on(SHARE_ISOLATE_MODE, async () => {\n      telemetry('share', { action: 'isolate-mode-opened' });\n    });\n  }\n}\n"
  },
  {
    "path": "code/core/src/core-server/standalone.ts",
    "content": "import { buildDevStandalone } from './build-dev.ts';\nimport { buildIndexStandalone } from './build-index.ts';\nimport { buildStaticStandalone } from './build-static.ts';\n\nasync function build(options: any = {}, frameworkOptions: any = {}) {\n  const { mode = 'dev' } = options;\n\n  const { default: packageJson } = await import('storybook/package.json', {\n    with: { type: 'json' },\n  });\n\n  const commonOptions = {\n    ...options,\n    ...frameworkOptions,\n    frameworkPresets: [\n      ...(options.frameworkPresets || []),\n      ...(frameworkOptions.frameworkPresets || []),\n    ],\n    packageJson,\n  };\n\n  if (mode === 'dev') {\n    return buildDevStandalone(commonOptions);\n  }\n\n  if (mode === 'static') {\n    return buildStaticStandalone(commonOptions);\n  }\n\n  if (mode === 'index') {\n    return buildIndexStandalone(commonOptions);\n  }\n\n  throw new Error(`'mode' parameter should be either 'dev', 'static', or 'index'`);\n}\n\nexport default build;\n"
  },
  {
    "path": "code/core/src/core-server/stores/status.ts",
    "content": "import { optionalEnvToBoolean } from '../../common/utils/envs.ts';\nimport { createStatusStore } from '../../shared/status-store/index.ts';\nimport { UNIVERSAL_STATUS_STORE_OPTIONS } from '../../shared/status-store/index.ts';\nimport { UniversalStore } from '../../shared/universal-store/index.ts';\n\nconst statusStore = createStatusStore({\n  universalStatusStore: UniversalStore.create({\n    ...UNIVERSAL_STATUS_STORE_OPTIONS,\n    /*\n      This is a temporary workaround, to ensure that the store is not created in the\n      vitest sub-process in addon-vitest, even though it imports from core-server\n      If it was created in the sub-process, it would try to connect to the leader in the dev server\n      before it was ready.\n      This will be fixed when we do the planned UniversalStore v0.2.\n    */\n    leader: !optionalEnvToBoolean(process.env.VITEST_CHILD_PROCESS),\n  }),\n  environment: 'server',\n});\n\nexport const { fullStatusStore, getStatusStoreByTypeId, universalStatusStore } = statusStore;\n"
  },
  {
    "path": "code/core/src/core-server/stores/test-provider.ts",
    "content": "import { optionalEnvToBoolean } from '../../common/utils/envs.ts';\nimport { createTestProviderStore } from '../../shared/test-provider-store/index.ts';\nimport { UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS } from '../../shared/test-provider-store/index.ts';\nimport { UniversalStore } from '../../shared/universal-store/index.ts';\n\nconst testProviderStore = createTestProviderStore({\n  universalTestProviderStore: UniversalStore.create({\n    ...UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS,\n    /*\n            This is a temporary workaround, to ensure that the store is not created in the\n            vitest sub-process in addon-vitest, even though it imports from core-server\n            If it was created in the sub-process, it would try to connect to the leader in the dev server\n            before it was ready.\n            This will be fixed when we do the planned UniversalStore v0.2.\n          */\n    leader: !optionalEnvToBoolean(process.env.VITEST_CHILD_PROCESS),\n  }),\n});\n\nexport const { fullTestProviderStore, getTestProviderStoreById, universalTestProviderStore } =\n  testProviderStore;\n"
  },
  {
    "path": "code/core/src/core-server/typings.d.ts",
    "content": "declare module 'lazy-universal-dotenv';\n// TODO: Remove in SB11\ndeclare module 'pnp-webpack-plugin';\ndeclare module '@aw-web-design/x-default-browser';\ndeclare module '@discoveryjs/json-ext';\ndeclare module 'watchpack';\n\ndeclare var FEATURES: import('storybook/internal/types').StorybookConfigRaw['features'];\ndeclare var TAGS_OPTIONS: import('storybook/internal/types').TagsOptions;\n"
  },
  {
    "path": "code/core/src/core-server/utils/IndexingError.ts",
    "content": "// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\n\nexport class IndexingError extends Error {\n  importPaths: string[];\n\n  constructor(message: string, importPaths: string[], stack?: string) {\n    super();\n    this.message = message;\n    this.importPaths = importPaths;\n    if (stack) {\n      this.stack = stack;\n    }\n  }\n\n  pathsString() {\n    if (this.importPaths.length === 1) {\n      return `${slash(this.importPaths[0])}`;\n    }\n\n    return `${this.importPaths.map(slash).join(',')}`;\n  }\n\n  toString() {\n    return `${this.pathsString()}: ${this.message}`;\n  }\n}\n\nexport class MultipleIndexingError extends Error {\n  constructor(public indexingErrors: IndexingError[]) {\n    super();\n\n    if (this.indexingErrors.length === 0) {\n      throw new Error('Unexpected empty error list');\n    }\n\n    if (this.indexingErrors.length === 1) {\n      const [err] = this.indexingErrors;\n      this.message = `Unable to index ${err.pathsString()}`;\n    } else {\n      this.message = `Unable to index files:\\n${this.indexingErrors\n        .map((err) => `- ${err}`)\n        .join('\\n')}`;\n    }\n  }\n\n  toString() {\n    if (this.indexingErrors.length === 1) {\n      return `${this.message}:\\n  ${this.indexingErrors[0].stack}`;\n    }\n\n    return this.message;\n  }\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/StoryIndexGenerator.test.ts",
    "content": "import { join } from 'node:path';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { normalizeStoriesEntry } from 'storybook/internal/common';\nimport { toId } from 'storybook/internal/csf';\nimport { getStorySortParameter, loadCsf } from 'storybook/internal/csf-tools';\nimport { logger, once } from 'storybook/internal/node-logger';\nimport type { NormalizedStoriesSpecifier, StoryIndexEntry } from 'storybook/internal/types';\n\nimport { Tag } from '../../shared/constants/tags.ts';\nimport { csfIndexer } from '../presets/common-preset.ts';\nimport type { StoryIndexGeneratorOptions } from './StoryIndexGenerator.ts';\nimport { StoryIndexGenerator } from './StoryIndexGenerator.ts';\n\nvi.mock('../utils/constants', () => {\n  return {\n    defaultStaticDirs: [{ from: './from', to: './to' }],\n    defaultFavicon: './favicon.svg',\n  };\n});\n\nvi.mock('storybook/internal/csf', async (importOriginal) => {\n  const csf = await importOriginal<typeof import('storybook/internal/csf')>();\n  return {\n    ...csf,\n    toId: vi.fn(csf.toId),\n  };\n});\n\nvi.mock('storybook/internal/node-logger');\n\nvi.mock('storybook/internal/csf-tools', async (importOriginal) => {\n  const csfTools = await importOriginal<typeof import('storybook/internal/csf-tools')>();\n  return {\n    ...csfTools,\n    loadCsf: vi.fn(csfTools.loadCsf),\n    getStorySortParameter: vi.fn(csfTools.getStorySortParameter),\n  };\n});\n\nconst toIdMock = vi.mocked(toId);\nconst loadCsfMock = vi.mocked(loadCsf);\nconst getStorySortParameterMock = vi.mocked(getStorySortParameter);\n\nconst options: StoryIndexGeneratorOptions = {\n  configDir: join(__dirname, '__mockdata__'),\n  workingDir: join(__dirname, '__mockdata__'),\n  indexers: [csfIndexer],\n  docs: { defaultName: 'docs' },\n};\n\ndescribe('StoryIndexGenerator', () => {\n  beforeEach(() => {\n    vi.mocked(logger.warn).mockClear();\n    vi.mocked(once.warn).mockClear();\n    toIdMock.mockClear();\n    loadCsfMock.mockClear();\n    getStorySortParameterMock.mockClear();\n    StoryIndexGenerator.clearFindMatchingFilesCache();\n  });\n  describe('extraction', () => {\n    const storiesSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n      './src/A.stories.(ts|js|mjs|jsx)',\n      options\n    );\n    const docsSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n      './src/docs2/*.mdx',\n      options\n    );\n\n    describe('single file specifier', () => {\n      it('extracts stories from the right files', async () => {\n        const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/A.stories.js',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([specifier], options);\n        await generator.initialize();\n\n        const { storyIndex, stats } = await generator.getIndexAndStats();\n        expect(storyIndex).toMatchInlineSnapshot(`\n          {\n            \"entries\": {\n              \"a--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"a--story-one\",\n                \"importPath\": \"./src/A.stories.js\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"component-tag\",\n                  \"story-tag\",\n                ],\n                \"title\": \"A\",\n                \"type\": \"story\",\n              },\n            },\n            \"v\": 5,\n          }\n        `);\n\n        expect(stats).toMatchInlineSnapshot(`\n          {\n            \"beforeEach\": 0,\n            \"factory\": 0,\n            \"globals\": 0,\n            \"loaders\": 0,\n            \"moduleMock\": 0,\n            \"mount\": 0,\n            \"play\": 0,\n            \"render\": 0,\n            \"storyFn\": 0,\n            \"tags\": 1,\n          }\n        `);\n      });\n    });\n    describe('single file .story specifier', () => {\n      it('extracts stories from the right files', async () => {\n        const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/F.story.ts',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([specifier], options);\n        await generator.initialize();\n\n        const { storyIndex } = await generator.getIndexAndStats();\n        expect(storyIndex).toMatchInlineSnapshot(`\n          {\n            \"entries\": {\n              \"f--docs\": {\n                \"id\": \"f--docs\",\n                \"importPath\": \"./src/F.story.ts\",\n                \"name\": \"docs\",\n                \"storiesImports\": [],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"F\",\n                \"type\": \"docs\",\n              },\n              \"f--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"f--story-one\",\n                \"importPath\": \"./src/F.story.ts\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"F\",\n                \"type\": \"story\",\n              },\n            },\n            \"v\": 5,\n          }\n        `);\n      });\n    });\n    describe('no prefix stories specifier', () => {\n      it('extracts stories from the right files', async () => {\n        const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/stories.ts',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([specifier], options);\n        await generator.initialize();\n\n        const { storyIndex } = await generator.getIndexAndStats();\n        expect(storyIndex).toMatchInlineSnapshot(`\n          {\n            \"entries\": {\n              \"stories--docs\": {\n                \"id\": \"stories--docs\",\n                \"importPath\": \"./src/stories.ts\",\n                \"name\": \"docs\",\n                \"storiesImports\": [],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"stories\",\n                \"type\": \"docs\",\n              },\n              \"stories--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"stories--story-one\",\n                \"importPath\": \"./src/stories.ts\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"stories\",\n                \"type\": \"story\",\n              },\n            },\n            \"v\": 5,\n          }\n        `);\n      });\n    });\n    describe('empty or whitespace-only files', () => {\n      it('ignores story files that only contain whitespace (e.g. just a newline)', async () => {\n        const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/Empty.stories.ts',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([specifier], options);\n        await generator.initialize();\n\n        const { storyIndex } = await generator.getIndexAndStats();\n        expect(storyIndex).toMatchInlineSnapshot(`\n          {\n            \"entries\": {},\n            \"v\": 5,\n          }\n        `);\n      });\n    });\n    describe('non-recursive specifier', () => {\n      it('extracts stories from the right files', async () => {\n        const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/*/*.stories.(ts|js|mjs|jsx)',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([specifier], options);\n        await generator.initialize();\n\n        const { storyIndex } = await generator.getIndexAndStats();\n        expect(storyIndex).toMatchInlineSnapshot(`\n          {\n            \"entries\": {\n              \"componentpath-extension--story-one\": {\n                \"componentPath\": \"./src/componentPath/component.js\",\n                \"exportName\": \"StoryOne\",\n                \"id\": \"componentpath-extension--story-one\",\n                \"importPath\": \"./src/componentPath/extension.stories.js\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"componentPath/extension\",\n                \"type\": \"story\",\n              },\n              \"componentpath-noextension--story-one\": {\n                \"componentPath\": \"./src/componentPath/component.js\",\n                \"exportName\": \"StoryOne\",\n                \"id\": \"componentpath-noextension--story-one\",\n                \"importPath\": \"./src/componentPath/noExtension.stories.js\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"componentPath/noExtension\",\n                \"type\": \"story\",\n              },\n              \"componentpath-package--story-one\": {\n                \"componentPath\": \"component-package\",\n                \"exportName\": \"StoryOne\",\n                \"id\": \"componentpath-package--story-one\",\n                \"importPath\": \"./src/componentPath/package.stories.js\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"componentPath/package\",\n                \"type\": \"story\",\n              },\n              \"nested-button--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"nested-button--story-one\",\n                \"importPath\": \"./src/nested/Button.stories.ts\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"component-tag\",\n                ],\n                \"title\": \"nested/Button\",\n                \"type\": \"story\",\n              },\n              \"second-nested-g--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"second-nested-g--story-one\",\n                \"importPath\": \"./src/second-nested/G.stories.ts\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"second-nested/G\",\n                \"type\": \"story\",\n              },\n            },\n            \"v\": 5,\n          }\n        `);\n      });\n    });\n    describe('recursive specifier', () => {\n      it('extracts stories from the right files', async () => {\n        const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/**/*.stories.(ts|js|mjs|jsx)',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([specifier], options);\n        await generator.initialize();\n\n        const { storyIndex, stats } = await generator.getIndexAndStats();\n        expect(storyIndex).toMatchInlineSnapshot(`\n          {\n            \"entries\": {\n              \"a--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"a--story-one\",\n                \"importPath\": \"./src/A.stories.js\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"component-tag\",\n                  \"story-tag\",\n                ],\n                \"title\": \"A\",\n                \"type\": \"story\",\n              },\n              \"b--docs\": {\n                \"id\": \"b--docs\",\n                \"importPath\": \"./src/B.stories.ts\",\n                \"name\": \"docs\",\n                \"storiesImports\": [],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"B\",\n                \"type\": \"docs\",\n              },\n              \"b--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"b--story-one\",\n                \"importPath\": \"./src/B.stories.ts\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"B\",\n                \"type\": \"story\",\n              },\n              \"componentpath-extension--story-one\": {\n                \"componentPath\": \"./src/componentPath/component.js\",\n                \"exportName\": \"StoryOne\",\n                \"id\": \"componentpath-extension--story-one\",\n                \"importPath\": \"./src/componentPath/extension.stories.js\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"componentPath/extension\",\n                \"type\": \"story\",\n              },\n              \"componentpath-noextension--story-one\": {\n                \"componentPath\": \"./src/componentPath/component.js\",\n                \"exportName\": \"StoryOne\",\n                \"id\": \"componentpath-noextension--story-one\",\n                \"importPath\": \"./src/componentPath/noExtension.stories.js\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"componentPath/noExtension\",\n                \"type\": \"story\",\n              },\n              \"componentpath-package--story-one\": {\n                \"componentPath\": \"component-package\",\n                \"exportName\": \"StoryOne\",\n                \"id\": \"componentpath-package--story-one\",\n                \"importPath\": \"./src/componentPath/package.stories.js\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"componentPath/package\",\n                \"type\": \"story\",\n              },\n              \"d--docs\": {\n                \"id\": \"d--docs\",\n                \"importPath\": \"./src/D.stories.jsx\",\n                \"name\": \"docs\",\n                \"storiesImports\": [],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"D\",\n                \"type\": \"docs\",\n              },\n              \"d--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"d--story-one\",\n                \"importPath\": \"./src/D.stories.jsx\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"D\",\n                \"type\": \"story\",\n              },\n              \"example-button--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"example-button--story-one\",\n                \"importPath\": \"./src/Button.stories.ts\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"foobar\",\n                ],\n                \"title\": \"Example/Button\",\n                \"type\": \"story\",\n              },\n              \"first-nested-deeply-f--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"first-nested-deeply-f--story-one\",\n                \"importPath\": \"./src/first-nested/deeply/F.stories.js\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"first-nested/deeply/F\",\n                \"type\": \"story\",\n              },\n              \"first-nested-deeply-features--with-csf-1\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"WithCSF1\",\n                \"id\": \"first-nested-deeply-features--with-csf-1\",\n                \"importPath\": \"./src/first-nested/deeply/Features.stories.jsx\",\n                \"name\": \"With CSF 1\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"first-nested/deeply/Features\",\n                \"type\": \"story\",\n              },\n              \"first-nested-deeply-features--with-play\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"WithPlay\",\n                \"id\": \"first-nested-deeply-features--with-play\",\n                \"importPath\": \"./src/first-nested/deeply/Features.stories.jsx\",\n                \"name\": \"With Play\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"play-fn\",\n                ],\n                \"title\": \"first-nested/deeply/Features\",\n                \"type\": \"story\",\n              },\n              \"first-nested-deeply-features--with-render\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"WithRender\",\n                \"id\": \"first-nested-deeply-features--with-render\",\n                \"importPath\": \"./src/first-nested/deeply/Features.stories.jsx\",\n                \"name\": \"With Render\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"first-nested/deeply/Features\",\n                \"type\": \"story\",\n              },\n              \"first-nested-deeply-features--with-story-fn\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"WithStoryFn\",\n                \"id\": \"first-nested-deeply-features--with-story-fn\",\n                \"importPath\": \"./src/first-nested/deeply/Features.stories.jsx\",\n                \"name\": \"With Story Fn\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"first-nested/deeply/Features\",\n                \"type\": \"story\",\n              },\n              \"first-nested-deeply-features--with-test\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"WithTest\",\n                \"id\": \"first-nested-deeply-features--with-test\",\n                \"importPath\": \"./src/first-nested/deeply/Features.stories.jsx\",\n                \"name\": \"With Test\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"play-fn\",\n                ],\n                \"title\": \"first-nested/deeply/Features\",\n                \"type\": \"story\",\n              },\n              \"h--docs\": {\n                \"id\": \"h--docs\",\n                \"importPath\": \"./src/H.stories.mjs\",\n                \"name\": \"docs\",\n                \"storiesImports\": [],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"H\",\n                \"type\": \"docs\",\n              },\n              \"h--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"h--story-one\",\n                \"importPath\": \"./src/H.stories.mjs\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"H\",\n                \"type\": \"story\",\n              },\n              \"nested-button--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"nested-button--story-one\",\n                \"importPath\": \"./src/nested/Button.stories.ts\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"component-tag\",\n                ],\n                \"title\": \"nested/Button\",\n                \"type\": \"story\",\n              },\n              \"second-nested-g--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"second-nested-g--story-one\",\n                \"importPath\": \"./src/second-nested/G.stories.ts\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"second-nested/G\",\n                \"type\": \"story\",\n              },\n            },\n            \"v\": 5,\n          }\n        `);\n\n        expect(stats).toMatchInlineSnapshot(`\n          {\n            \"beforeEach\": 1,\n            \"factory\": 0,\n            \"globals\": 0,\n            \"loaders\": 1,\n            \"moduleMock\": 0,\n            \"mount\": 1,\n            \"play\": 2,\n            \"render\": 1,\n            \"storyFn\": 1,\n            \"tags\": 5,\n          }\n        `);\n      });\n    });\n\n    describe('autodocs', () => {\n      const autodocsOptions = {\n        ...options,\n        docs: { ...options.docs, autodocs: 'tag' as const },\n      };\n      it('generates an entry per CSF file with the autodocs tag', async () => {\n        const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/**/*.stories.(ts|js|mjs|jsx)',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([specifier], autodocsOptions);\n        await generator.initialize();\n\n        const { storyIndex, stats } = await generator.getIndexAndStats();\n        expect(storyIndex).toMatchInlineSnapshot(`\n          {\n            \"entries\": {\n              \"a--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"a--story-one\",\n                \"importPath\": \"./src/A.stories.js\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"component-tag\",\n                  \"story-tag\",\n                ],\n                \"title\": \"A\",\n                \"type\": \"story\",\n              },\n              \"b--docs\": {\n                \"id\": \"b--docs\",\n                \"importPath\": \"./src/B.stories.ts\",\n                \"name\": \"docs\",\n                \"storiesImports\": [],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"B\",\n                \"type\": \"docs\",\n              },\n              \"b--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"b--story-one\",\n                \"importPath\": \"./src/B.stories.ts\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"B\",\n                \"type\": \"story\",\n              },\n              \"componentpath-extension--story-one\": {\n                \"componentPath\": \"./src/componentPath/component.js\",\n                \"exportName\": \"StoryOne\",\n                \"id\": \"componentpath-extension--story-one\",\n                \"importPath\": \"./src/componentPath/extension.stories.js\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"componentPath/extension\",\n                \"type\": \"story\",\n              },\n              \"componentpath-noextension--story-one\": {\n                \"componentPath\": \"./src/componentPath/component.js\",\n                \"exportName\": \"StoryOne\",\n                \"id\": \"componentpath-noextension--story-one\",\n                \"importPath\": \"./src/componentPath/noExtension.stories.js\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"componentPath/noExtension\",\n                \"type\": \"story\",\n              },\n              \"componentpath-package--story-one\": {\n                \"componentPath\": \"component-package\",\n                \"exportName\": \"StoryOne\",\n                \"id\": \"componentpath-package--story-one\",\n                \"importPath\": \"./src/componentPath/package.stories.js\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"componentPath/package\",\n                \"type\": \"story\",\n              },\n              \"d--docs\": {\n                \"id\": \"d--docs\",\n                \"importPath\": \"./src/D.stories.jsx\",\n                \"name\": \"docs\",\n                \"storiesImports\": [],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"D\",\n                \"type\": \"docs\",\n              },\n              \"d--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"d--story-one\",\n                \"importPath\": \"./src/D.stories.jsx\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"D\",\n                \"type\": \"story\",\n              },\n              \"example-button--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"example-button--story-one\",\n                \"importPath\": \"./src/Button.stories.ts\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"foobar\",\n                ],\n                \"title\": \"Example/Button\",\n                \"type\": \"story\",\n              },\n              \"first-nested-deeply-f--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"first-nested-deeply-f--story-one\",\n                \"importPath\": \"./src/first-nested/deeply/F.stories.js\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"first-nested/deeply/F\",\n                \"type\": \"story\",\n              },\n              \"first-nested-deeply-features--with-csf-1\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"WithCSF1\",\n                \"id\": \"first-nested-deeply-features--with-csf-1\",\n                \"importPath\": \"./src/first-nested/deeply/Features.stories.jsx\",\n                \"name\": \"With CSF 1\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"first-nested/deeply/Features\",\n                \"type\": \"story\",\n              },\n              \"first-nested-deeply-features--with-play\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"WithPlay\",\n                \"id\": \"first-nested-deeply-features--with-play\",\n                \"importPath\": \"./src/first-nested/deeply/Features.stories.jsx\",\n                \"name\": \"With Play\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"play-fn\",\n                ],\n                \"title\": \"first-nested/deeply/Features\",\n                \"type\": \"story\",\n              },\n              \"first-nested-deeply-features--with-render\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"WithRender\",\n                \"id\": \"first-nested-deeply-features--with-render\",\n                \"importPath\": \"./src/first-nested/deeply/Features.stories.jsx\",\n                \"name\": \"With Render\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"first-nested/deeply/Features\",\n                \"type\": \"story\",\n              },\n              \"first-nested-deeply-features--with-story-fn\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"WithStoryFn\",\n                \"id\": \"first-nested-deeply-features--with-story-fn\",\n                \"importPath\": \"./src/first-nested/deeply/Features.stories.jsx\",\n                \"name\": \"With Story Fn\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"first-nested/deeply/Features\",\n                \"type\": \"story\",\n              },\n              \"first-nested-deeply-features--with-test\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"WithTest\",\n                \"id\": \"first-nested-deeply-features--with-test\",\n                \"importPath\": \"./src/first-nested/deeply/Features.stories.jsx\",\n                \"name\": \"With Test\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"play-fn\",\n                ],\n                \"title\": \"first-nested/deeply/Features\",\n                \"type\": \"story\",\n              },\n              \"h--docs\": {\n                \"id\": \"h--docs\",\n                \"importPath\": \"./src/H.stories.mjs\",\n                \"name\": \"docs\",\n                \"storiesImports\": [],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"H\",\n                \"type\": \"docs\",\n              },\n              \"h--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"h--story-one\",\n                \"importPath\": \"./src/H.stories.mjs\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"H\",\n                \"type\": \"story\",\n              },\n              \"nested-button--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"nested-button--story-one\",\n                \"importPath\": \"./src/nested/Button.stories.ts\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"component-tag\",\n                ],\n                \"title\": \"nested/Button\",\n                \"type\": \"story\",\n              },\n              \"second-nested-g--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"second-nested-g--story-one\",\n                \"importPath\": \"./src/second-nested/G.stories.ts\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"second-nested/G\",\n                \"type\": \"story\",\n              },\n            },\n            \"v\": 5,\n          }\n        `);\n\n        expect(stats).toMatchInlineSnapshot(`\n          {\n            \"beforeEach\": 1,\n            \"factory\": 0,\n            \"globals\": 0,\n            \"loaders\": 1,\n            \"moduleMock\": 0,\n            \"mount\": 1,\n            \"play\": 2,\n            \"render\": 1,\n            \"storyFn\": 1,\n            \"tags\": 5,\n          }\n        `);\n      });\n\n      const autodocsTrueOptions = {\n        ...autodocsOptions,\n        docs: {\n          ...autodocsOptions.docs,\n          autodocs: true,\n        },\n      };\n      it('generates an entry for every CSF file when docsOptions.autodocs = true', async () => {\n        const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/**/*.stories.(ts|js|mjs|jsx)',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([specifier], autodocsTrueOptions);\n        await generator.initialize();\n\n        expect(Object.keys((await generator.getIndex()).entries)).toMatchInlineSnapshot(`\n  [\n    \"a--story-one\",\n    \"b--docs\",\n    \"b--story-one\",\n    \"example-button--story-one\",\n    \"d--docs\",\n    \"d--story-one\",\n    \"h--docs\",\n    \"h--story-one\",\n    \"componentpath-extension--story-one\",\n    \"componentpath-noextension--story-one\",\n    \"componentpath-package--story-one\",\n    \"first-nested-deeply-f--story-one\",\n    \"first-nested-deeply-features--with-play\",\n    \"first-nested-deeply-features--with-story-fn\",\n    \"first-nested-deeply-features--with-render\",\n    \"first-nested-deeply-features--with-test\",\n    \"first-nested-deeply-features--with-csf-1\",\n    \"nested-button--story-one\",\n    \"second-nested-g--story-one\",\n  ]\n`);\n      });\n\n      it('generates an entry for every CSF file when projectTags contains autodocs', async () => {\n        const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/**/*.stories.(ts|js|mjs|jsx)',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([specifier], autodocsOptions);\n        generator.getProjectTags = () => [Tag.DEV, Tag.TEST, Tag.AUTODOCS];\n        await generator.initialize();\n\n        expect(Object.keys((await generator.getIndex()).entries)).toMatchInlineSnapshot(`\n          [\n            \"a--docs\",\n            \"a--story-one\",\n            \"b--docs\",\n            \"b--story-one\",\n            \"example-button--docs\",\n            \"example-button--story-one\",\n            \"d--docs\",\n            \"d--story-one\",\n            \"h--docs\",\n            \"h--story-one\",\n            \"componentpath-extension--docs\",\n            \"componentpath-extension--story-one\",\n            \"componentpath-noextension--docs\",\n            \"componentpath-noextension--story-one\",\n            \"componentpath-package--docs\",\n            \"componentpath-package--story-one\",\n            \"first-nested-deeply-f--docs\",\n            \"first-nested-deeply-f--story-one\",\n            \"first-nested-deeply-features--docs\",\n            \"first-nested-deeply-features--with-play\",\n            \"first-nested-deeply-features--with-story-fn\",\n            \"first-nested-deeply-features--with-render\",\n            \"first-nested-deeply-features--with-test\",\n            \"first-nested-deeply-features--with-csf-1\",\n            \"nested-button--docs\",\n            \"nested-button--story-one\",\n            \"second-nested-g--docs\",\n            \"second-nested-g--story-one\",\n          ]\n        `);\n      });\n\n      it('adds the autodocs tag to the autogenerated docs entries when projectTags contains autodocs', async () => {\n        const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/**/*.stories.(ts|js|mjs|jsx)',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([specifier], autodocsOptions);\n        generator.getProjectTags = () => [Tag.DEV, Tag.TEST, Tag.AUTODOCS];\n        await generator.initialize();\n\n        const index = await generator.getIndex();\n        expect(index.entries['first-nested-deeply-f--docs'].tags).toEqual(\n          expect.arrayContaining([Tag.AUTODOCS])\n        );\n      });\n\n      it('throws an error if you attach a named MetaOf entry which clashes with a tagged autodocs entry', async () => {\n        const csfSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/B.stories.ts',\n          options\n        );\n\n        const docsSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './errors/MetaOfClashingDefaultName.mdx',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([csfSpecifier, docsSpecifier], autodocsOptions);\n        await generator.initialize();\n\n        await expect(generator.getIndex()).rejects.toThrowErrorMatchingInlineSnapshot(\n          `[Error: Unable to index ./errors/MetaOfClashingDefaultName.mdx,./src/B.stories.ts]`\n        );\n      });\n\n      it('throws an error if you attach a unnamed MetaOf entry with the same name as the CSF file that clashes with a tagged autodocs entry', async () => {\n        const csfSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/B.stories.ts',\n          options\n        );\n\n        const docsSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './errors/B.mdx',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([csfSpecifier, docsSpecifier], autodocsOptions);\n        await generator.initialize();\n\n        await expect(generator.getIndex()).rejects.toThrowErrorMatchingInlineSnapshot(\n          `[Error: Unable to index ./errors/B.mdx,./src/B.stories.ts]`\n        );\n      });\n\n      it('allows you to create a second unnamed MetaOf entry that does not clash with autodocs', async () => {\n        const csfSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/B.stories.ts',\n          options\n        );\n\n        const docsSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './errors/MetaOfNoName.mdx',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([csfSpecifier, docsSpecifier], autodocsOptions);\n        await generator.initialize();\n\n        const { storyIndex } = await generator.getIndexAndStats();\n        expect(storyIndex).toMatchInlineSnapshot(`\n          {\n            \"entries\": {\n              \"b--docs\": {\n                \"id\": \"b--docs\",\n                \"importPath\": \"./src/B.stories.ts\",\n                \"name\": \"docs\",\n                \"storiesImports\": [],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"B\",\n                \"type\": \"docs\",\n              },\n              \"b--metaofnoname\": {\n                \"id\": \"b--metaofnoname\",\n                \"importPath\": \"./errors/MetaOfNoName.mdx\",\n                \"name\": \"MetaOfNoName\",\n                \"storiesImports\": [\n                  \"./src/B.stories.ts\",\n                ],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                  \"attached-mdx\",\n                ],\n                \"title\": \"B\",\n                \"type\": \"docs\",\n              },\n              \"b--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"b--story-one\",\n                \"importPath\": \"./src/B.stories.ts\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"B\",\n                \"type\": \"story\",\n              },\n            },\n            \"v\": 5,\n          }\n        `);\n      });\n      it('allows you to create a second MetaOf entry with a different name to autodocs', async () => {\n        const csfSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/B.stories.ts',\n          options\n        );\n\n        const docsSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './errors/MetaOfName.mdx',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([csfSpecifier, docsSpecifier], autodocsOptions);\n        await generator.initialize();\n\n        const { storyIndex } = await generator.getIndexAndStats();\n        expect(storyIndex).toMatchInlineSnapshot(`\n          {\n            \"entries\": {\n              \"b--docs\": {\n                \"id\": \"b--docs\",\n                \"importPath\": \"./src/B.stories.ts\",\n                \"name\": \"docs\",\n                \"storiesImports\": [],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"B\",\n                \"type\": \"docs\",\n              },\n              \"b--name\": {\n                \"id\": \"b--name\",\n                \"importPath\": \"./errors/MetaOfName.mdx\",\n                \"name\": \"name\",\n                \"storiesImports\": [\n                  \"./src/B.stories.ts\",\n                ],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                  \"attached-mdx\",\n                ],\n                \"title\": \"B\",\n                \"type\": \"docs\",\n              },\n              \"b--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"b--story-one\",\n                \"importPath\": \"./src/B.stories.ts\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"B\",\n                \"type\": \"story\",\n              },\n            },\n            \"v\": 5,\n          }\n        `);\n      });\n\n      it('allows you to override autodocs with MetaOf when docsOptions.autodocs = true', async () => {\n        const csfSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/A.stories.js',\n          options\n        );\n\n        const docsSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './errors/A.mdx',\n          options\n        );\n\n        const generator = new StoryIndexGenerator(\n          [csfSpecifier, docsSpecifier],\n          autodocsTrueOptions\n        );\n        await generator.initialize();\n\n        const { storyIndex } = await generator.getIndexAndStats();\n        expect(storyIndex).toMatchInlineSnapshot(`\n          {\n            \"entries\": {\n              \"a--docs\": {\n                \"id\": \"a--docs\",\n                \"importPath\": \"./errors/A.mdx\",\n                \"name\": \"docs\",\n                \"storiesImports\": [\n                  \"./src/A.stories.js\",\n                ],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"component-tag\",\n                  \"story-tag\",\n                  \"attached-mdx\",\n                ],\n                \"title\": \"A\",\n                \"type\": \"docs\",\n              },\n              \"a--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"a--story-one\",\n                \"importPath\": \"./src/A.stories.js\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"component-tag\",\n                  \"story-tag\",\n                ],\n                \"title\": \"A\",\n                \"type\": \"story\",\n              },\n            },\n            \"v\": 5,\n          }\n        `);\n      });\n\n      it('allows you to override autodocs with MetaOf when projectTags contains autodocs', async () => {\n        const csfSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/A.stories.js',\n          options\n        );\n\n        const docsSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './errors/A.mdx',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([csfSpecifier, docsSpecifier], autodocsOptions);\n        generator.getProjectTags = () => [Tag.DEV, Tag.TEST, Tag.AUTODOCS];\n        await generator.initialize();\n\n        const { storyIndex } = await generator.getIndexAndStats();\n        expect(storyIndex).toMatchInlineSnapshot(`\n          {\n            \"entries\": {\n              \"a--docs\": {\n                \"id\": \"a--docs\",\n                \"importPath\": \"./errors/A.mdx\",\n                \"name\": \"docs\",\n                \"storiesImports\": [\n                  \"./src/A.stories.js\",\n                ],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"autodocs\",\n                  \"component-tag\",\n                  \"story-tag\",\n                  \"attached-mdx\",\n                ],\n                \"title\": \"A\",\n                \"type\": \"docs\",\n              },\n              \"a--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"a--story-one\",\n                \"importPath\": \"./src/A.stories.js\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"autodocs\",\n                  \"component-tag\",\n                  \"story-tag\",\n                ],\n                \"title\": \"A\",\n                \"type\": \"story\",\n              },\n            },\n            \"v\": 5,\n          }\n        `);\n      });\n\n      it('generates a combined entry if there are two stories files for the same title', async () => {\n        const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './duplicate/*.stories.(ts|js|mjs|jsx)',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([specifier], autodocsOptions);\n        await generator.initialize();\n\n        const { storyIndex } = await generator.getIndexAndStats();\n        expect(storyIndex).toMatchInlineSnapshot(`\n          {\n            \"entries\": {\n              \"duplicate-a--docs\": {\n                \"id\": \"duplicate-a--docs\",\n                \"importPath\": \"./duplicate/A.stories.js\",\n                \"name\": \"docs\",\n                \"storiesImports\": [\n                  \"./duplicate/SecondA.stories.js\",\n                ],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"duplicate/A\",\n                \"type\": \"docs\",\n              },\n              \"duplicate-a--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"duplicate-a--story-one\",\n                \"importPath\": \"./duplicate/A.stories.js\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"duplicate/A\",\n                \"type\": \"story\",\n              },\n              \"duplicate-a--story-two\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryTwo\",\n                \"id\": \"duplicate-a--story-two\",\n                \"importPath\": \"./duplicate/SecondA.stories.js\",\n                \"name\": \"Story Two\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"duplicate/A\",\n                \"type\": \"story\",\n              },\n            },\n            \"v\": 5,\n          }\n        `);\n      });\n\n      // https://github.com/storybookjs/storybook/issues/19142\n      it('does not generate a docs page entry if there are no stories in the CSF file', async () => {\n        const csfSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './errors/NoStories.stories.ts',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([csfSpecifier], autodocsOptions);\n        await generator.initialize();\n\n        const { storyIndex } = await generator.getIndexAndStats();\n        expect(storyIndex).toMatchInlineSnapshot(`\n          {\n            \"entries\": {},\n            \"v\": 5,\n          }\n        `);\n      });\n\n      it('prioritizes using the component id over meta.title for generating its id, if provided. (autodocs)', async () => {\n        const csfSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './docs-id-generation/A.stories.jsx',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([csfSpecifier], autodocsOptions);\n        await generator.initialize();\n\n        const { storyIndex } = await generator.getIndexAndStats();\n        expect(storyIndex).toMatchInlineSnapshot(`\n          {\n            \"entries\": {\n              \"my-component-a--docs\": {\n                \"id\": \"my-component-a--docs\",\n                \"importPath\": \"./docs-id-generation/A.stories.jsx\",\n                \"name\": \"docs\",\n                \"storiesImports\": [],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"A\",\n                \"type\": \"docs\",\n              },\n              \"my-component-a--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"my-component-a--story-one\",\n                \"importPath\": \"./docs-id-generation/A.stories.jsx\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"A\",\n                \"type\": \"story\",\n              },\n            },\n            \"v\": 5,\n          }\n        `);\n      });\n    });\n\n    describe('docs specifier', () => {\n      it('creates correct docs entries', async () => {\n        const generator = new StoryIndexGenerator([storiesSpecifier, docsSpecifier], options);\n        await generator.initialize();\n\n        const { storyIndex } = await generator.getIndexAndStats();\n        expect(storyIndex).toMatchInlineSnapshot(`\n          {\n            \"entries\": {\n              \"a--metaof\": {\n                \"id\": \"a--metaof\",\n                \"importPath\": \"./src/docs2/MetaOf.mdx\",\n                \"name\": \"MetaOf\",\n                \"storiesImports\": [\n                  \"./src/A.stories.js\",\n                ],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"component-tag\",\n                  \"story-tag\",\n                  \"attached-mdx\",\n                ],\n                \"title\": \"A\",\n                \"type\": \"docs\",\n              },\n              \"a--second-docs\": {\n                \"id\": \"a--second-docs\",\n                \"importPath\": \"./src/docs2/SecondMetaOf.mdx\",\n                \"name\": \"Second Docs\",\n                \"storiesImports\": [\n                  \"./src/A.stories.js\",\n                ],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"component-tag\",\n                  \"story-tag\",\n                  \"attached-mdx\",\n                ],\n                \"title\": \"A\",\n                \"type\": \"docs\",\n              },\n              \"a--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"a--story-one\",\n                \"importPath\": \"./src/A.stories.js\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"component-tag\",\n                  \"story-tag\",\n                ],\n                \"title\": \"A\",\n                \"type\": \"story\",\n              },\n              \"componentreference--docs\": {\n                \"id\": \"componentreference--docs\",\n                \"importPath\": \"./src/docs2/ComponentReference.mdx\",\n                \"name\": \"docs\",\n                \"storiesImports\": [],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"unattached-mdx\",\n                ],\n                \"title\": \"ComponentReference\",\n                \"type\": \"docs\",\n              },\n              \"docs2-yabbadabbadooo--docs\": {\n                \"id\": \"docs2-yabbadabbadooo--docs\",\n                \"importPath\": \"./src/docs2/Title.mdx\",\n                \"name\": \"docs\",\n                \"storiesImports\": [],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"unattached-mdx\",\n                ],\n                \"title\": \"docs2/Yabbadabbadooo\",\n                \"type\": \"docs\",\n              },\n              \"notitle--docs\": {\n                \"id\": \"notitle--docs\",\n                \"importPath\": \"./src/docs2/NoTitle.mdx\",\n                \"name\": \"docs\",\n                \"storiesImports\": [],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"unattached-mdx\",\n                ],\n                \"title\": \"NoTitle\",\n                \"type\": \"docs\",\n              },\n              \"tags--docs\": {\n                \"id\": \"tags--docs\",\n                \"importPath\": \"./src/docs2/Tags.mdx\",\n                \"name\": \"docs\",\n                \"storiesImports\": [],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"foo\",\n                  \"bar\",\n                  \"unattached-mdx\",\n                ],\n                \"title\": \"Tags\",\n                \"type\": \"docs\",\n              },\n            },\n            \"v\": 5,\n          }\n        `);\n      });\n\n      it('does not append title prefix if meta references a CSF file', async () => {\n        const generator = new StoryIndexGenerator(\n          [\n            storiesSpecifier,\n            normalizeStoriesEntry(\n              { directory: './src/docs2', files: '**/*.mdx', titlePrefix: 'titlePrefix' },\n              options\n            ),\n          ],\n          options\n        );\n        await generator.initialize();\n\n        // NOTE: `toMatchInlineSnapshot` on objects sorts the keys, but in actuality, they are\n        // not sorted by default.\n        expect(Object.values((await generator.getIndex()).entries).map((e) => e.title))\n          .toMatchInlineSnapshot(`\n            [\n              \"A\",\n              \"titlePrefix/ComponentReference\",\n              \"A\",\n              \"titlePrefix/NoTitle\",\n              \"A\",\n              \"titlePrefix/Tags\",\n              \"titlePrefix/docs2/Yabbadabbadooo\",\n            ]\n          `);\n      });\n\n      it('Allows you to override default name for docs files', async () => {\n        const generator = new StoryIndexGenerator([storiesSpecifier, docsSpecifier], {\n          ...options,\n          docs: {\n            ...options.docs,\n            defaultName: 'Info',\n          },\n        });\n        await generator.initialize();\n\n        const { storyIndex } = await generator.getIndexAndStats();\n        expect(storyIndex).toMatchInlineSnapshot(`\n          {\n            \"entries\": {\n              \"a--metaof\": {\n                \"id\": \"a--metaof\",\n                \"importPath\": \"./src/docs2/MetaOf.mdx\",\n                \"name\": \"MetaOf\",\n                \"storiesImports\": [\n                  \"./src/A.stories.js\",\n                ],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"component-tag\",\n                  \"story-tag\",\n                  \"attached-mdx\",\n                ],\n                \"title\": \"A\",\n                \"type\": \"docs\",\n              },\n              \"a--second-docs\": {\n                \"id\": \"a--second-docs\",\n                \"importPath\": \"./src/docs2/SecondMetaOf.mdx\",\n                \"name\": \"Second Docs\",\n                \"storiesImports\": [\n                  \"./src/A.stories.js\",\n                ],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"component-tag\",\n                  \"story-tag\",\n                  \"attached-mdx\",\n                ],\n                \"title\": \"A\",\n                \"type\": \"docs\",\n              },\n              \"a--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"a--story-one\",\n                \"importPath\": \"./src/A.stories.js\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"component-tag\",\n                  \"story-tag\",\n                ],\n                \"title\": \"A\",\n                \"type\": \"story\",\n              },\n              \"componentreference--info\": {\n                \"id\": \"componentreference--info\",\n                \"importPath\": \"./src/docs2/ComponentReference.mdx\",\n                \"name\": \"Info\",\n                \"storiesImports\": [],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"unattached-mdx\",\n                ],\n                \"title\": \"ComponentReference\",\n                \"type\": \"docs\",\n              },\n              \"docs2-yabbadabbadooo--info\": {\n                \"id\": \"docs2-yabbadabbadooo--info\",\n                \"importPath\": \"./src/docs2/Title.mdx\",\n                \"name\": \"Info\",\n                \"storiesImports\": [],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"unattached-mdx\",\n                ],\n                \"title\": \"docs2/Yabbadabbadooo\",\n                \"type\": \"docs\",\n              },\n              \"notitle--info\": {\n                \"id\": \"notitle--info\",\n                \"importPath\": \"./src/docs2/NoTitle.mdx\",\n                \"name\": \"Info\",\n                \"storiesImports\": [],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"unattached-mdx\",\n                ],\n                \"title\": \"NoTitle\",\n                \"type\": \"docs\",\n              },\n              \"tags--info\": {\n                \"id\": \"tags--info\",\n                \"importPath\": \"./src/docs2/Tags.mdx\",\n                \"name\": \"Info\",\n                \"storiesImports\": [],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"foo\",\n                  \"bar\",\n                  \"unattached-mdx\",\n                ],\n                \"title\": \"Tags\",\n                \"type\": \"docs\",\n              },\n            },\n            \"v\": 5,\n          }\n        `);\n      });\n\n      it('pulls the attached story file to the front of the list', async () => {\n        const generator = new StoryIndexGenerator(\n          [\n            normalizeStoriesEntry('./src/A.stories.js', options),\n            normalizeStoriesEntry('./src/B.stories.ts', options),\n            normalizeStoriesEntry('./complex/TwoStoryReferences.mdx', options),\n          ],\n          options\n        );\n        await generator.initialize();\n        const { storyIndex } = await generator.getIndexAndStats();\n        expect(storyIndex).toMatchInlineSnapshot(`\n          {\n            \"entries\": {\n              \"a--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"a--story-one\",\n                \"importPath\": \"./src/A.stories.js\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"component-tag\",\n                  \"story-tag\",\n                ],\n                \"title\": \"A\",\n                \"type\": \"story\",\n              },\n              \"b--docs\": {\n                \"id\": \"b--docs\",\n                \"importPath\": \"./src/B.stories.ts\",\n                \"name\": \"docs\",\n                \"storiesImports\": [],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"B\",\n                \"type\": \"docs\",\n              },\n              \"b--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"b--story-one\",\n                \"importPath\": \"./src/B.stories.ts\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                ],\n                \"title\": \"B\",\n                \"type\": \"story\",\n              },\n              \"b--twostoryreferences\": {\n                \"id\": \"b--twostoryreferences\",\n                \"importPath\": \"./complex/TwoStoryReferences.mdx\",\n                \"name\": \"TwoStoryReferences\",\n                \"storiesImports\": [\n                  \"./src/B.stories.ts\",\n                  \"./src/A.stories.js\",\n                ],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"autodocs\",\n                  \"attached-mdx\",\n                ],\n                \"title\": \"B\",\n                \"type\": \"docs\",\n              },\n            },\n            \"v\": 5,\n          }\n        `);\n      });\n\n      it('prioritizes using the component id over meta.title for generating its id, if provided. (mdx docs)', async () => {\n        const csfSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './docs-id-generation/B.stories.jsx',\n          options\n        );\n\n        const docsSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './docs-id-generation/B.docs.mdx',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([csfSpecifier, docsSpecifier], options);\n        await generator.initialize();\n\n        const { storyIndex } = await generator.getIndexAndStats();\n        expect(storyIndex).toMatchInlineSnapshot(`\n          {\n            \"entries\": {\n              \"my-component-b--docs\": {\n                \"id\": \"my-component-b--docs\",\n                \"importPath\": \"./docs-id-generation/B.docs.mdx\",\n                \"name\": \"docs\",\n                \"storiesImports\": [\n                  \"./docs-id-generation/B.stories.jsx\",\n                ],\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                  \"attached-mdx\",\n                ],\n                \"title\": \"B\",\n                \"type\": \"docs\",\n              },\n              \"my-component-b--story-one\": {\n                \"componentPath\": undefined,\n                \"exportName\": \"StoryOne\",\n                \"id\": \"my-component-b--story-one\",\n                \"importPath\": \"./docs-id-generation/B.stories.jsx\",\n                \"name\": \"Story One\",\n                \"subtype\": \"story\",\n                \"tags\": [\n                  \"dev\",\n                  \"test\",\n                  \"manifest\",\n                ],\n                \"title\": \"B\",\n                \"type\": \"story\",\n              },\n            },\n            \"v\": 5,\n          }\n        `);\n      });\n\n      it('puts the Meta of stories file first in storiesImports even when it is not the last import', async () => {\n        const csfSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/*.stories.(js|ts)',\n          options\n        );\n\n        const docsSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './complex/MetaOfImportOrder.mdx',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([csfSpecifier, docsSpecifier], options);\n        await generator.initialize();\n\n        const { storyIndex } = await generator.getIndexAndStats();\n        const docsEntry = storyIndex.entries['a--metaofimportorder'];\n\n        expect(docsEntry).toMatchObject({\n          type: 'docs',\n          title: 'A',\n          importPath: './complex/MetaOfImportOrder.mdx',\n          storiesImports: ['./src/A.stories.js', './src/B.stories.ts'],\n        });\n      });\n    });\n\n    describe('errors', () => {\n      it('when docs dependencies are missing', async () => {\n        const generator = new StoryIndexGenerator(\n          [normalizeStoriesEntry('./src/docs2/MetaOf.mdx', options)],\n          options\n        );\n        await generator.initialize();\n        await expect(() => generator.getIndex()).rejects.toThrowErrorMatchingInlineSnapshot(\n          `[Error: Unable to index ./src/docs2/MetaOf.mdx]`\n        );\n      });\n    });\n\n    describe('warnings', () => {\n      it('when entries do not match any files', async () => {\n        const generator = new StoryIndexGenerator(\n          [normalizeStoriesEntry('./src/docs2/wrong.js', options)],\n          options\n        );\n        await generator.initialize();\n        await generator.getIndex();\n\n        expect(once.warn).toHaveBeenCalledTimes(1);\n        const logMessage = vi.mocked(once.warn).mock.calls[0][0];\n        expect(logMessage).toContain(`No story files found for the specified pattern`);\n      });\n    });\n\n    describe('duplicates', () => {\n      it('errors when two MDX entries reference the same CSF file without a name', async () => {\n        const docsErrorSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './errors/**/A.mdx',\n          options\n        );\n\n        const generator = new StoryIndexGenerator(\n          [storiesSpecifier, docsSpecifier, docsErrorSpecifier],\n          options\n        );\n        await generator.initialize();\n\n        await expect(generator.getIndex()).rejects.toThrowErrorMatchingInlineSnapshot(\n          `[Error: Unable to index ./errors/A.mdx,./errors/duplicate/A.mdx]`\n        );\n      });\n\n      it('errors when a MDX entry has the same name as a story', async () => {\n        const docsErrorSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './errors/MetaOfClashingName.mdx',\n          options\n        );\n\n        const generator = new StoryIndexGenerator(\n          [storiesSpecifier, docsSpecifier, docsErrorSpecifier],\n          options\n        );\n        await generator.initialize();\n\n        await expect(generator.getIndex()).rejects.toThrowErrorMatchingInlineSnapshot(\n          `[Error: Unable to index ./src/A.stories.js,./errors/MetaOfClashingName.mdx]`\n        );\n      });\n\n      it('errors when a story has the default docs name', async () => {\n        const docsErrorSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './errors/A.mdx',\n          options\n        );\n\n        const generator = new StoryIndexGenerator(\n          [storiesSpecifier, docsSpecifier, docsErrorSpecifier],\n          {\n            ...options,\n            docs: { ...options.docs, defaultName: 'Story One' },\n          }\n        );\n        await generator.initialize();\n\n        await expect(generator.getIndex()).rejects.toThrowErrorMatchingInlineSnapshot(\n          `[Error: Unable to index ./src/A.stories.js,./errors/A.mdx]`\n        );\n      });\n      it('errors when two duplicate stories exists, with duplicated entries details', async () => {\n        const generator = new StoryIndexGenerator([storiesSpecifier, docsSpecifier], {\n          ...options,\n        });\n        await generator.initialize();\n        const mockEntry: StoryIndexEntry = {\n          id: 'StoryId',\n          name: 'StoryName',\n          title: 'ComponentTitle',\n          importPath: 'Path',\n          type: 'story',\n          subtype: 'story',\n        };\n        expect(() => {\n          generator.chooseDuplicate(mockEntry, { ...mockEntry, importPath: 'DifferentPath' }, []);\n        }).toThrowErrorMatchingInlineSnapshot(`[Error: Duplicate stories with id: StoryId]`);\n      });\n\n      it('DOES NOT error when the same MDX file matches two specifiers', async () => {\n        const generator = new StoryIndexGenerator(\n          [storiesSpecifier, docsSpecifier, docsSpecifier],\n          options\n        );\n        await generator.initialize();\n\n        expect(Object.keys((await generator.getIndex()).entries)).toMatchInlineSnapshot(`\n          [\n            \"a--story-one\",\n            \"componentreference--docs\",\n            \"a--metaof\",\n            \"notitle--docs\",\n            \"a--second-docs\",\n            \"tags--docs\",\n            \"docs2-yabbadabbadooo--docs\",\n          ]\n        `);\n\n        expect(logger.warn).not.toHaveBeenCalled();\n      });\n\n      it('DOES NOT throw when the same CSF file matches two specifiers', async () => {\n        const generator = new StoryIndexGenerator([storiesSpecifier, storiesSpecifier], {\n          ...options,\n        });\n        await generator.initialize();\n        expect(Object.keys((await generator.getIndex()).entries)).toMatchInlineSnapshot(`\n          [\n            \"a--story-one\",\n          ]\n        `);\n\n        expect(logger.warn).not.toHaveBeenCalled();\n      });\n    });\n  });\n\n  describe('sorting', () => {\n    it('runs a user-defined sort function', async () => {\n      const storiesSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n        './src/**/*.stories.(ts|js|mjs|jsx)',\n        options\n      );\n      const docsSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n        './src/docs2/*.mdx',\n        options\n      );\n\n      const generator = new StoryIndexGenerator([docsSpecifier, storiesSpecifier], options);\n      await generator.initialize();\n\n      getStorySortParameterMock.mockReturnValueOnce({\n        order: ['docs2', 'D', 'B', 'nested', 'A', 'second-nested', 'first-nested/deeply'],\n      });\n\n      expect(Object.keys((await generator.getIndex()).entries)).toMatchInlineSnapshot(`\n        [\n          \"docs2-yabbadabbadooo--docs\",\n          \"d--docs\",\n          \"d--story-one\",\n          \"b--docs\",\n          \"b--story-one\",\n          \"nested-button--story-one\",\n          \"a--metaof\",\n          \"a--second-docs\",\n          \"a--story-one\",\n          \"second-nested-g--story-one\",\n          \"componentreference--docs\",\n          \"notitle--docs\",\n          \"tags--docs\",\n          \"example-button--story-one\",\n          \"h--docs\",\n          \"h--story-one\",\n          \"componentpath-extension--story-one\",\n          \"componentpath-noextension--story-one\",\n          \"componentpath-package--story-one\",\n          \"first-nested-deeply-f--story-one\",\n          \"first-nested-deeply-features--with-play\",\n          \"first-nested-deeply-features--with-story-fn\",\n          \"first-nested-deeply-features--with-render\",\n          \"first-nested-deeply-features--with-test\",\n          \"first-nested-deeply-features--with-csf-1\",\n        ]\n      `);\n    });\n  });\n\n  describe('caching', () => {\n    describe('no invalidation', () => {\n      it('does not extract csf files a second time', async () => {\n        const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/**/*.stories.(ts|js|mjs|jsx)',\n          options\n        );\n\n        loadCsfMock.mockClear();\n        expect(loadCsfMock).toHaveBeenCalledTimes(0);\n        const generator = new StoryIndexGenerator([specifier], options);\n        await generator.initialize();\n        await generator.getIndex();\n        expect(loadCsfMock).toHaveBeenCalledTimes(12);\n\n        loadCsfMock.mockClear();\n        await generator.getIndex();\n        expect(loadCsfMock).not.toHaveBeenCalled();\n      });\n\n      it('does not extract docs files a second time', async () => {\n        const storiesSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/A.stories.(ts|js|mjs|jsx)',\n          options\n        );\n        const docsSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/docs2/*.mdx',\n          options\n        );\n        loadCsfMock.mockClear();\n        expect(loadCsfMock).toHaveBeenCalledTimes(0);\n        const generator = new StoryIndexGenerator([storiesSpecifier, docsSpecifier], options);\n        await generator.initialize();\n        await generator.getIndex();\n        expect(toId).toHaveBeenCalledTimes(7);\n\n        toIdMock.mockClear();\n        await generator.getIndex();\n        expect(toId).not.toHaveBeenCalled();\n      });\n\n      it('does not call the sort function a second time', async () => {\n        const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/**/*.stories.(ts|js|mjs|jsx)',\n          options\n        );\n\n        const sortFn = vi.fn();\n        getStorySortParameterMock.mockReturnValue(sortFn);\n        const generator = new StoryIndexGenerator([specifier], options);\n        await generator.initialize();\n        await generator.getIndex();\n        expect(sortFn).toHaveBeenCalled();\n\n        sortFn.mockClear();\n        await generator.getIndex();\n        expect(sortFn).not.toHaveBeenCalled();\n      });\n    });\n\n    describe('file changed', () => {\n      it('calls extract csf file for just the one file', async () => {\n        const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/**/*.stories.(ts|js|mjs|jsx)',\n          options\n        );\n\n        loadCsfMock.mockClear();\n        const generator = new StoryIndexGenerator([specifier], options);\n        await generator.initialize();\n        await generator.getIndex();\n        expect(loadCsfMock).toHaveBeenCalledTimes(12);\n\n        generator.invalidate('./src/B.stories.ts', false);\n\n        loadCsfMock.mockClear();\n        await generator.getIndex();\n        expect(loadCsfMock).toHaveBeenCalledTimes(1);\n      });\n\n      it('calls extract docs file for just the one file', async () => {\n        const storiesSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/A.stories.(ts|js|mjs|jsx)',\n          options\n        );\n        const docsSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/docs2/*.mdx',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([storiesSpecifier, docsSpecifier], options);\n        await generator.initialize();\n        await generator.getIndex();\n        expect(toId).toHaveBeenCalledTimes(7);\n\n        generator.invalidate('./src/docs2/Title.mdx', false);\n\n        toIdMock.mockClear();\n        await generator.getIndex();\n        expect(toId).toHaveBeenCalledTimes(1);\n      });\n\n      it('calls extract for a csf file and any of its docs dependents', async () => {\n        const storiesSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/A.stories.(ts|js|mjs|jsx)',\n          options\n        );\n        const docsSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/docs2/*.mdx',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([storiesSpecifier, docsSpecifier], options);\n        await generator.initialize();\n        await generator.getIndex();\n        expect(toId).toHaveBeenCalledTimes(7);\n\n        generator.invalidate('./src/A.stories.js', false);\n\n        toIdMock.mockClear();\n        await generator.getIndex();\n        expect(toId).toHaveBeenCalledTimes(3);\n      });\n\n      it('does call the sort function a second time', async () => {\n        const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/**/*.stories.(ts|js|mjs|jsx)',\n          options\n        );\n\n        const sortFn = vi.fn();\n        getStorySortParameterMock.mockReturnValue(sortFn);\n        const generator = new StoryIndexGenerator([specifier], options);\n        await generator.initialize();\n        await generator.getIndex();\n        expect(sortFn).toHaveBeenCalled();\n\n        generator.invalidate('./src/B.stories.ts', false);\n\n        sortFn.mockClear();\n        await generator.getIndex();\n        expect(sortFn).toHaveBeenCalled();\n      });\n    });\n\n    describe('file removed', () => {\n      it('does not extract csf files a second time', async () => {\n        const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/**/*.stories.(ts|js|mjs|jsx)',\n          options\n        );\n\n        loadCsfMock.mockClear();\n        const generator = new StoryIndexGenerator([specifier], options);\n        await generator.initialize();\n        await generator.getIndex();\n        expect(loadCsfMock).toHaveBeenCalledTimes(12);\n\n        generator.invalidate('./src/B.stories.ts', true);\n\n        loadCsfMock.mockClear();\n        await generator.getIndex();\n        expect(loadCsfMock).not.toHaveBeenCalled();\n      });\n\n      it('does call the sort function a second time', async () => {\n        const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/**/*.stories.(ts|js|mjs|jsx)',\n          options\n        );\n\n        const sortFn = vi.fn();\n        getStorySortParameterMock.mockReturnValue(sortFn);\n        const generator = new StoryIndexGenerator([specifier], options);\n        await generator.initialize();\n        await generator.getIndex();\n        expect(sortFn).toHaveBeenCalled();\n\n        generator.invalidate('./src/B.stories.ts', true);\n\n        sortFn.mockClear();\n        await generator.getIndex();\n        expect(sortFn).toHaveBeenCalled();\n      });\n\n      it('does not include the deleted stories in results', async () => {\n        const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/**/*.stories.(ts|js|mjs|jsx)',\n          options\n        );\n\n        loadCsfMock.mockClear();\n        const generator = new StoryIndexGenerator([specifier], options);\n        await generator.initialize();\n        await generator.getIndex();\n        expect(loadCsfMock).toHaveBeenCalledTimes(12);\n\n        generator.invalidate('./src/B.stories.ts', true);\n\n        expect(Object.keys((await generator.getIndex()).entries)).not.toContain('b--story-one');\n      });\n\n      it('does not include the deleted docs in results', async () => {\n        const storiesSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/A.stories.(ts|js|mjs|jsx)',\n          options\n        );\n        const docsSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/docs2/*.mdx',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([docsSpecifier, storiesSpecifier], options);\n        await generator.initialize();\n        await generator.getIndex();\n        expect(toId).toHaveBeenCalledTimes(7);\n\n        expect(Object.keys((await generator.getIndex()).entries)).toContain('notitle--docs');\n\n        generator.invalidate('./src/docs2/NoTitle.mdx', true);\n\n        expect(Object.keys((await generator.getIndex()).entries)).not.toContain('notitle--docs');\n      });\n\n      it('cleans up properly on dependent docs deletion', async () => {\n        const storiesSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/A.stories.(ts|js|mjs|jsx)',\n          options\n        );\n        const docsSpecifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(\n          './src/docs2/*.mdx',\n          options\n        );\n\n        const generator = new StoryIndexGenerator([docsSpecifier, storiesSpecifier], options);\n        await generator.initialize();\n        await generator.getIndex();\n        expect(toId).toHaveBeenCalledTimes(7);\n\n        expect(Object.keys((await generator.getIndex()).entries)).toContain('a--metaof');\n\n        generator.invalidate('./src/docs2/MetaOf.mdx', true);\n\n        expect(Object.keys((await generator.getIndex()).entries)).not.toContain('a--metaof');\n\n        // this will throw if MetaOf is not removed from A's dependents\n        generator.invalidate('./src/A.stories.js', false);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/StoryIndexGenerator.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { dirname, extname, join, normalize, relative, resolve, sep } from 'node:path';\n\nimport { commonGlobOptions, getProjectRoot, normalizeStoryPath } from 'storybook/internal/common';\nimport { combineTags, storyNameFromExport, toId } from 'storybook/internal/csf';\nimport { getStorySortParameter, loadConfig } from 'storybook/internal/csf-tools';\nimport { logger, once } from 'storybook/internal/node-logger';\nimport { isExampleStoryId } from 'storybook/internal/telemetry';\nimport type {\n  DocsIndexEntry,\n  DocsOptions,\n  IndexEntry,\n  IndexInputStats,\n  Indexer,\n  NormalizedStoriesSpecifier,\n  Path,\n  StoryIndex,\n  StoryIndexEntry,\n  StoryIndexInput,\n  StorybookConfigRaw,\n} from 'storybook/internal/types';\n\nimport { analyze } from '@storybook/docs-mdx';\n\nimport * as find from 'empathic/find';\nimport picocolors from 'picocolors';\n// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\nimport invariant from 'tiny-invariant';\nimport { dedent } from 'ts-dedent';\nimport * as TsconfigPaths from 'tsconfig-paths';\n\nimport { resolveImport, supportedExtensions } from '../../common/index.ts';\nimport { userOrAutoTitleFromSpecifier } from '../../preview-api/modules/store/autoTitle.ts';\nimport { sortStoriesV7 } from '../../preview-api/modules/store/sortStories.ts';\nimport { Tag } from '../../shared/constants/tags.ts';\nimport { IndexingError, MultipleIndexingError } from './IndexingError.ts';\nimport { autoName } from './autoName.ts';\nimport { type IndexStatsSummary, addStats } from './summarizeStats.ts';\n\n// Extended type to keep track of the csf meta id so we know the component id when referencing docs in `extractDocs`\ntype StoryIndexEntryWithExtra = StoryIndexEntry & {\n  extra: { metaId?: string; stats: IndexInputStats };\n};\n/** A .mdx file will produce a docs entry */\ntype DocsCacheEntry = DocsIndexEntry;\n/** A `_.stories._` file will produce a list of stories and possibly a docs entry */\ntype StoriesCacheEntry = {\n  entries: (StoryIndexEntryWithExtra | DocsIndexEntry)[];\n  dependents: Path[];\n  type: 'stories';\n};\ntype ErrorEntry = {\n  type: 'error';\n  err: IndexingError;\n};\ntype CacheEntry = false | StoriesCacheEntry | DocsCacheEntry | ErrorEntry;\ntype SpecifierStoriesCache = Record<Path, CacheEntry>;\n\nexport type StoryIndexGeneratorOptions = {\n  workingDir: Path;\n  configDir: Path;\n  indexers: Indexer[];\n  docs: DocsOptions;\n  build?: StorybookConfigRaw['build'];\n};\n\n/** Was this docs entry generated by a .mdx file? (see discussion below) */\nexport function isMdxEntry({ tags }: DocsIndexEntry) {\n  return tags?.includes(Tag.UNATTACHED_MDX) || tags?.includes(Tag.ATTACHED_MDX);\n}\n\nconst makeAbsolute = (otherImport: Path, normalizedPath: Path, workingDir: Path) =>\n  otherImport.startsWith('.')\n    ? slash(resolve(workingDir, normalizeStoryPath(join(dirname(normalizedPath), otherImport))))\n    : otherImport;\n\n/**\n * The StoryIndexGenerator extracts stories and docs entries for each file matching (one or more)\n * stories \"specifiers\", as defined in main.js.\n *\n * The output is a set of entries (see above for the types).\n *\n * Each file is treated as a stories or a (modern) docs file.\n *\n * A stories file is indexed by an indexer (passed in), which produces a list of stories.\n *\n * - If the stories have the `parameters.docsOnly` setting, they are disregarded.\n * - If the stories have `autodocs` enabled, a docs entry is added pointing to the story file.\n *\n * A (modern) docs (.mdx) file is indexed, a docs entry is added.\n *\n * In the preview, a docs entry with the `autodocs` tag will be rendered as a CSF file that exports\n * an MDX template on the `docs.page` parameter, whereas other docs entries are rendered as MDX\n * files directly.\n *\n * The entries are \"uniq\"-ed and sorted. Stories entries are preferred to docs entries and MDX docs\n * entries are preferred to CSF templates (with warnings).\n */\nexport class StoryIndexGenerator {\n  // An internal cache mapping specifiers to a set of path=><set of stories>\n  // Later, we'll combine each of these subsets together to form the full index\n  private specifierToCache: Map<NormalizedStoriesSpecifier, SpecifierStoriesCache>;\n\n  /** Cache for findMatchingFiles results */\n  private static findMatchingFilesCache = new Map<string, SpecifierStoriesCache>();\n\n  // Cache the last value of `getStoryIndex`. We invalidate (by unsetting) when:\n  //  - any file changes, including deletions\n  //  - the preview changes [not yet implemented]\n  private lastIndex?: StoryIndex | null;\n\n  // Cache the last value stats calculation, mirroring lastIndex\n  private lastStats?: IndexStatsSummary;\n\n  // Same as the above but for the error case\n  private lastError?: Error | null;\n\n  private invalidationListeners: Set<() => void> = new Set();\n\n  constructor(\n    public readonly specifiers: NormalizedStoriesSpecifier[],\n    public readonly options: StoryIndexGeneratorOptions\n  ) {\n    this.specifierToCache = new Map();\n  }\n\n  /** Generate a cache key for findMatchingFiles */\n  private static getFindMatchingFilesCacheKey(\n    specifier: NormalizedStoriesSpecifier,\n    workingDir: Path,\n    ignoreWarnings: boolean\n  ): string {\n    return JSON.stringify({\n      directory: specifier.directory,\n      files: specifier.files,\n      workingDir,\n      ignoreWarnings,\n    });\n  }\n\n  /** Clear the findMatchingFiles cache */\n  public static clearFindMatchingFilesCache(): void {\n    this.findMatchingFilesCache.clear();\n  }\n\n  static async findMatchingFiles(\n    specifier: NormalizedStoriesSpecifier,\n    workingDir: Path,\n    ignoreWarnings = false\n  ): Promise<SpecifierStoriesCache> {\n    // Check cache first\n    const cacheKey = this.getFindMatchingFilesCacheKey(specifier, workingDir, ignoreWarnings);\n    const cached = this.findMatchingFilesCache.get(cacheKey);\n    if (cached) {\n      return cached;\n    }\n\n    const pathToSubIndex = {} as SpecifierStoriesCache;\n\n    // Calculate a new CWD for each glob to handle paths that go above the workingDir.\n    const globCwd = slash(resolve(workingDir, specifier.directory));\n    // Prepend ./ to patterns starting with ! to ensure they are treated as extglobs\n    const globPattern = specifier.files.startsWith('!') ? `./${specifier.files}` : specifier.files;\n\n    // Dynamically import globby because it is a pure ESM module\n    // eslint-disable-next-line depend/ban-dependencies\n    const { globby } = await import('globby');\n\n    // Execute globby within the new CWD to ensure `ignore` patterns work correctly.\n    const files = await globby(globPattern, {\n      absolute: true,\n      cwd: globCwd,\n      ...commonGlobOptions(globPattern),\n    });\n\n    if (files.length === 0 && !ignoreWarnings) {\n      once.warn(\n        `No story files found for the specified pattern: ${picocolors.blue(\n          join(specifier.directory, specifier.files)\n        )}`\n      );\n    }\n\n    files.sort().forEach((absolutePath: Path) => {\n      const ext = extname(absolutePath);\n      if (ext === '.storyshot') {\n        const relativePath = relative(workingDir, absolutePath);\n        logger.info(`Skipping ${ext} file ${relativePath}`);\n        return;\n      }\n\n      pathToSubIndex[absolutePath] = false;\n    });\n\n    // Store in cache before returning\n    this.findMatchingFilesCache.set(cacheKey, pathToSubIndex);\n    return pathToSubIndex;\n  }\n\n  static async findMatchingFilesForSpecifiers(\n    specifiers: NormalizedStoriesSpecifier[],\n    workingDir: Path,\n    ignoreWarnings = false\n  ): Promise<Array<readonly [NormalizedStoriesSpecifier, SpecifierStoriesCache]>> {\n    return Promise.all(\n      specifiers.map(async (specifier) => {\n        const pathToSubIndex = await StoryIndexGenerator.findMatchingFiles(\n          specifier,\n          workingDir,\n          ignoreWarnings\n        );\n        return [specifier, pathToSubIndex] as const;\n      })\n    );\n  }\n\n  async initialize() {\n    // Find all matching paths for each specifier\n    const specifiersAndCaches = await StoryIndexGenerator.findMatchingFilesForSpecifiers(\n      this.specifiers,\n      this.options.workingDir\n    );\n\n    // We do this in a second step to avoid timing issues with the Promise.all above -- to ensure\n    // the keys in the `specifierToCache` object are consistent with the order of specifiers.\n    specifiersAndCaches.forEach(([specifier, cache]) =>\n      this.specifierToCache.set(specifier, cache)\n    );\n\n    const previewCode = await this.getPreviewCode();\n    const projectTags = this.getProjectTags(previewCode);\n\n    // Extract stories for each file\n    await this.ensureExtracted({ projectTags });\n  }\n\n  /** Run the updater function over all the empty cache entries */\n  async updateExtracted(\n    updater: (\n      specifier: NormalizedStoriesSpecifier,\n      absolutePath: Path,\n      existingEntry: CacheEntry\n    ) => Promise<CacheEntry>,\n    overwrite = false\n  ) {\n    await Promise.all(\n      this.specifiers.map(async (specifier) => {\n        const entry = this.specifierToCache.get(specifier);\n        invariant(\n          entry,\n          `specifier does not have a matching cache entry in specifierToCache: ${JSON.stringify(\n            specifier\n          )}`\n        );\n        return Promise.all(\n          Object.keys(entry).map(async (absolutePath) => {\n            if (entry[absolutePath] && !overwrite) {\n              return;\n            }\n\n            try {\n              entry[absolutePath] = await updater(specifier, absolutePath, entry[absolutePath]);\n            } catch (err) {\n              const relativePath = `.${sep}${relative(this.options.workingDir, absolutePath)}`;\n\n              entry[absolutePath] = {\n                type: 'error',\n                err: new IndexingError(\n                  err instanceof Error ? err.message : String(err),\n                  [relativePath],\n                  err instanceof Error ? err.stack : undefined\n                ),\n              };\n            }\n          })\n        );\n      })\n    );\n  }\n\n  isDocsMdx(absolutePath: Path) {\n    return /(?<!\\.stories)\\.mdx$/i.test(absolutePath);\n  }\n\n  async ensureExtracted({\n    projectTags,\n  }: {\n    projectTags?: Tag[];\n  }): Promise<{ entries: (IndexEntry | ErrorEntry)[]; stats: IndexStatsSummary }> {\n    // First process all the story files. Then, in a second pass,\n    // process the docs files. The reason for this is that the docs\n    // files may use the `<Meta of={XStories} />` syntax, which requires\n    // that the story file that contains the meta be processed first.\n    await this.updateExtracted(async (specifier, absolutePath) =>\n      this.isDocsMdx(absolutePath)\n        ? false\n        : this.extractStories(specifier, absolutePath, projectTags)\n    );\n\n    await this.updateExtracted(async (specifier, absolutePath) =>\n      this.extractDocs(specifier, absolutePath, projectTags)\n    );\n\n    const statsSummary = {} as IndexStatsSummary;\n    const entries = this.specifiers.flatMap((specifier) => {\n      const cache = this.specifierToCache.get(specifier);\n      invariant(\n        cache,\n        `specifier does not have a matching cache entry in specifierToCache: ${JSON.stringify(\n          specifier\n        )}`\n      );\n      return Object.values(cache).flatMap((entry): (IndexEntry | ErrorEntry)[] => {\n        if (!entry) {\n          return [];\n        }\n\n        if (entry.type === 'docs') {\n          return [entry];\n        }\n\n        if (entry.type === 'error') {\n          return [entry];\n        }\n\n        return entry.entries.map((item) => {\n          if (item.type === 'docs') {\n            return item;\n          }\n\n          // don't count example stories towards feature usage stats\n          if (!isExampleStoryId(item.id)) {\n            addStats(item.extra.stats, statsSummary);\n          }\n\n          // Drop extra data used for internal bookkeeping\n          const { extra, ...existing } = item;\n          return existing;\n        });\n      });\n    });\n\n    return { entries, stats: statsSummary };\n  }\n\n  findDependencies(absoluteImports: Path[]) {\n    return [...this.specifierToCache.values()].flatMap((cache: SpecifierStoriesCache) =>\n      Object.entries(cache)\n        .filter(([fileName, cacheEntry]) => {\n          /**\n           * We are only interested in stories cache entries (and assume they've been processed\n           * already) If we found a match in the cache that's still null or not a stories file, it\n           * is a docs file and it isn't a dependency / storiesImport.\n           *\n           * @see\n           * https://github.com/storybookjs/storybook/issues/20958\n           */\n          if (!cacheEntry || cacheEntry.type !== 'stories') {\n            return false;\n          }\n\n          return !!absoluteImports.find((storyImport) =>\n            fileName.match(\n              new RegExp(`^${storyImport.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}(\\\\.[^.]+)?$`)\n            )\n          );\n        })\n        .map(([_, cacheEntry]) => cacheEntry as StoriesCacheEntry)\n    );\n  }\n\n  /**\n   * Try to find the component path from a raw import string and return it in the same format as\n   * `importPath`. Respect tsconfig paths if available.\n   *\n   * If no such file exists, assume that the import is from a package and return the raw\n   */\n  resolveComponentPath(\n    rawComponentPath: Path,\n    absolutePath: Path,\n    matchPath: TsconfigPaths.MatchPath | undefined\n  ) {\n    const matchedPath =\n      matchPath?.(rawComponentPath, undefined, undefined, supportedExtensions) ?? rawComponentPath;\n    let resolved;\n    try {\n      resolved = resolveImport(matchedPath, { basedir: dirname(absolutePath) });\n    } catch (_) {\n      return matchedPath;\n    }\n    const relativePath = relative(this.options.workingDir, resolved);\n    return slash(normalizeStoryPath(relativePath));\n  }\n\n  async extractStories(\n    specifier: NormalizedStoriesSpecifier,\n    absolutePath: Path,\n    projectTags: Tag[] = []\n  ): Promise<StoriesCacheEntry | DocsCacheEntry> {\n    const relativePath = relative(this.options.workingDir, absolutePath);\n    const importPath = slash(normalizeStoryPath(relativePath));\n    const defaultMakeTitle = (userTitle?: string) => {\n      const title = userOrAutoTitleFromSpecifier(importPath, specifier, userTitle);\n      invariant(\n        title,\n        \"makeTitle created an undefined title. This happens when the fileName doesn't match any specifier from main.js\"\n      );\n      return title;\n    };\n\n    const indexer = this.options.indexers.find((ind) => ind.test.exec(absolutePath));\n\n    invariant(indexer, `No matching indexer found for ${absolutePath}`);\n\n    const indexInputs = (await indexer.createIndex(absolutePath, {\n      makeTitle: defaultMakeTitle,\n    })) as StoryIndexInput[]; // we don't actually support DocsIndexInputs at runtime, although types say we do\n    const tsconfigPath = find.up('tsconfig.json', {\n      cwd: this.options.workingDir,\n      last: getProjectRoot(),\n    });\n    const tsconfig = TsconfigPaths.loadConfig(tsconfigPath);\n    let matchPath: TsconfigPaths.MatchPath | undefined;\n    if (tsconfig.resultType === 'success') {\n      matchPath = TsconfigPaths.createMatchPath(tsconfig.absoluteBaseUrl, tsconfig.paths, [\n        'browser',\n        'module',\n        'main',\n      ]);\n    }\n\n    const toImportPath = (path: string | undefined) => {\n      if (!path) {\n        return importPath;\n      }\n      if (path.startsWith('virtual:')) {\n        return path;\n      }\n      return slash(normalizeStoryPath(relative(this.options.workingDir, path)));\n    };\n\n    const storyEntries: ((StoryIndexEntryWithExtra | DocsCacheEntry) & { tags: Tag[] })[] =\n      indexInputs.map((input) => {\n        const name = input.name ?? storyNameFromExport(input.exportName);\n        const componentPath =\n          input.rawComponentPath &&\n          this.resolveComponentPath(input.rawComponentPath, absolutePath, matchPath);\n        const title = input.title ?? defaultMakeTitle();\n\n        const id = input.__id ?? toId(input.metaId ?? title, storyNameFromExport(input.exportName));\n        const tags = combineTags(...projectTags, ...(input.tags ?? []));\n        const subtype = input.subtype ?? 'story';\n\n        const entry: StoryIndexEntryWithExtra & { tags: Tag[] } = {\n          type: 'story',\n          subtype,\n          id,\n          extra: {\n            metaId: input.metaId,\n            stats: input.__stats ?? {},\n          },\n          name,\n          title,\n          importPath: toImportPath(input.importPath),\n          componentPath,\n          tags,\n        };\n\n        if (subtype === 'test') {\n          entry.parent = input.parent;\n          entry.parentName = input.parentName;\n        }\n        if (input.exportName) {\n          entry.exportName = input.exportName;\n        }\n\n        return entry;\n      });\n\n    // We need a docs entry attached to the CSF file if either:\n    //  a) autodocs is globally enabled\n    //  b) we have autodocs enabled for this file\n    const hasAutodocsTag = storyEntries.some((entry) => entry.tags.includes(Tag.AUTODOCS));\n    const createDocEntry = hasAutodocsTag && !!this.options.docs;\n\n    if (createDocEntry && this.options.build?.test?.disableAutoDocs !== true) {\n      const docsName = this.options.docs?.defaultName ?? 'Docs';\n      const name = docsName;\n      const { metaId } = indexInputs[0];\n      const entry = storyEntries[0];\n      const id = toId(metaId ?? entry.title, name);\n      const tags = combineTags(...projectTags, ...(indexInputs[0].tags ?? []));\n\n      const docsEntry: DocsCacheEntry & { tags: Tag[] } = {\n        id,\n        title: entry.title,\n        name,\n        importPath: entry.importPath,\n        type: 'docs',\n        tags,\n        storiesImports: [],\n      };\n\n      return {\n        entries: [docsEntry, ...storyEntries],\n        dependents: [],\n        type: 'stories',\n      };\n    }\n\n    return {\n      entries: storyEntries,\n      dependents: [],\n      type: 'stories',\n    };\n  }\n\n  async extractDocs(\n    specifier: NormalizedStoriesSpecifier,\n    absolutePath: Path,\n    projectTags: Tag[] = []\n  ) {\n    const relativePath = relative(this.options.workingDir, absolutePath);\n    try {\n      const normalizedPath = normalizeStoryPath(relativePath);\n      const importPath = slash(normalizedPath);\n\n      const content = await readFile(absolutePath, { encoding: 'utf8' });\n      const result = await analyze(content);\n\n      // Templates are not indexed\n      if (result.isTemplate) {\n        return false;\n      }\n\n      const absoluteImports = (result.imports as string[]).map((p) =>\n        makeAbsolute(p, normalizedPath, this.options.workingDir)\n      );\n\n      // Go through the cache and collect all of the cache entries that this docs file depends on.\n      // We'll use this to make sure this docs cache entry is invalidated when any of its dependents\n      // are invalidated.f\n      const dependencies = this.findDependencies(absoluteImports);\n\n      // To ensure the `<Meta of={}/>` import is always first in the list, we'll bring the dependency\n      // that contains it to the front of the list.\n      let sortedDependencies = dependencies;\n\n      // Also, if `result.of` is set, it means that we're using the `<Meta of={XStories} />` syntax,\n      // so find the `title` defined the file that `meta` points to.\n      let csfEntry: StoryIndexEntryWithExtra | undefined;\n      if (result.of) {\n        const absoluteOf = makeAbsolute(result.of, normalizedPath, this.options.workingDir);\n        let metaDependency: StoriesCacheEntry | undefined;\n\n        dependencies.forEach((dep) => {\n          if (dep.entries.length > 0) {\n            const first = dep.entries.find((e) => e.type !== 'docs') as StoryIndexEntryWithExtra;\n\n            if (\n              normalize(resolve(this.options.workingDir, first.importPath)).startsWith(\n                normalize(absoluteOf)\n              )\n            ) {\n              csfEntry = first;\n              metaDependency = dep;\n            }\n          }\n        });\n\n        if (metaDependency) {\n          sortedDependencies = [\n            metaDependency,\n            ...dependencies.filter((d) => d !== metaDependency),\n          ];\n        }\n\n        invariant(\n          csfEntry,\n          dedent`\n            Could not find or load CSF file at path \"${result.of}\" referenced by \\`of={}\\` in docs file \"${relativePath}\".\n\n            - Does that file exist?\n            - If so, is it a CSF file (\\`.stories.*\\`)?\n            - If so, is it matched by the \\`stories\\` glob in \\`main.js\\`?\n            - If so, has the file successfully loaded in Storybook and are its stories visible?\n          `\n        );\n      }\n\n      // Track that we depend on this for easy invalidation later.\n      dependencies.forEach((dep) => {\n        dep.dependents.push(absolutePath);\n      });\n\n      const title =\n        csfEntry?.title || userOrAutoTitleFromSpecifier(importPath, specifier, result.title);\n      invariant(\n        title,\n        \"makeTitle created an undefined title. This happens when a specifier's doesn't have any matches in its fileName\"\n      );\n      const defaultName = this.options.docs?.defaultName ?? 'Docs';\n\n      const name =\n        result.name ||\n        (csfEntry ? autoName(importPath, csfEntry.importPath, defaultName) : defaultName);\n\n      const id = toId(csfEntry?.extra.metaId || title, name);\n\n      const tags = combineTags(\n        ...projectTags,\n        ...(csfEntry?.tags ?? []),\n        ...(result.metaTags ?? []),\n        csfEntry ? Tag.ATTACHED_MDX : Tag.UNATTACHED_MDX\n      );\n\n      const docsEntry: DocsCacheEntry = {\n        id,\n        title,\n        name,\n        importPath,\n        storiesImports: sortedDependencies.map((dep) => dep.entries[0].importPath),\n        type: 'docs',\n        tags,\n      };\n      return docsEntry;\n    } catch (err) {\n      if (err && (err as { source: any }).source?.match(/mdast-util-mdx-jsx/g)) {\n        logger.warn(\n          `💡 This seems to be an MDX2 syntax error. Please refer to the MDX section in the following resource for assistance on how to fix this: ${picocolors.yellow(\n            'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#mdx2-upgrade'\n          )}`\n        );\n      }\n      throw err;\n    }\n  }\n\n  chooseDuplicate(firstEntry: IndexEntry, secondEntry: IndexEntry, projectTags: Tag[]): IndexEntry {\n    // NOTE: it is possible for the same entry to show up twice (if it matches >1 glob). That's OK.\n    if (firstEntry.importPath === secondEntry.importPath) {\n      return firstEntry;\n    }\n\n    let firstIsBetter = true;\n    if (secondEntry.type === 'story') {\n      firstIsBetter = false;\n    } else if (isMdxEntry(secondEntry) && firstEntry.type === 'docs' && !isMdxEntry(firstEntry)) {\n      firstIsBetter = false;\n    }\n    const betterEntry = firstIsBetter ? firstEntry : secondEntry;\n    const worseEntry = firstIsBetter ? secondEntry : firstEntry;\n\n    const changeDocsName = 'Use `<Meta of={} name=\"Other Name\">` to distinguish them.';\n\n    // This shouldn't be possible, but double check and use for typing\n    if (worseEntry.type === 'story') {\n      throw new IndexingError(`Duplicate stories with id: ${firstEntry.id}`, [\n        firstEntry.importPath,\n        secondEntry.importPath,\n      ]);\n    }\n\n    if (betterEntry.type === 'story') {\n      const worseDescriptor = isMdxEntry(worseEntry)\n        ? `component docs page`\n        : `automatically generated docs page`;\n      const docsName = this.options.docs?.defaultName ?? 'Docs';\n      if (betterEntry.name === docsName) {\n        throw new IndexingError(\n          `You have a story for ${betterEntry.title} with the same name as your default docs entry name (${betterEntry.name}), so the docs page is being dropped. Consider changing the story name.`,\n          [firstEntry.importPath, secondEntry.importPath]\n        );\n      } else {\n        throw new IndexingError(\n          `You have a story for ${betterEntry.title} with the same name as your ${worseDescriptor} (${worseEntry.name}), so the docs page is being dropped. ${changeDocsName}`,\n          [firstEntry.importPath, secondEntry.importPath]\n        );\n      }\n    } else if (isMdxEntry(betterEntry)) {\n      // Both entries are MDX but pointing at the same place\n      if (isMdxEntry(worseEntry)) {\n        throw new IndexingError(\n          `You have two component docs pages with the same name ${betterEntry.title}:${betterEntry.name}. ${changeDocsName}`,\n          [firstEntry.importPath, secondEntry.importPath]\n        );\n      }\n\n      // If you link a file to a tagged CSF file, you have probably made a mistake\n      if (worseEntry.tags?.includes(Tag.AUTODOCS) && !projectTags?.includes(Tag.AUTODOCS)) {\n        throw new IndexingError(\n          `You created a component docs page for '${worseEntry.title}', but also tagged the CSF file with '${Tag.AUTODOCS}'. This is probably a mistake.`,\n          [betterEntry.importPath, worseEntry.importPath]\n        );\n      }\n\n      // Otherwise the existing entry is created by project-level autodocs which is allowed to be overridden.\n    } else {\n      // If both entries are templates (e.g. you have two CSF files with the same title), then\n      //   we need to merge the entries. We'll use the first one's name and importPath,\n      //   but ensure we include both as storiesImports so they are both loaded before rendering\n      //   the story (for the <Stories> block & friends)\n      return {\n        ...betterEntry,\n        storiesImports: [\n          ...betterEntry.storiesImports,\n          worseEntry.importPath,\n          ...worseEntry.storiesImports,\n        ],\n      };\n    }\n\n    return betterEntry;\n  }\n\n  async sortStories(entries: StoryIndex['entries'], storySortParameter: any) {\n    const sortableStories = Object.values(entries);\n    const fileNameOrder = StoryIndexGenerator.storyFileNames(this.specifierToCache);\n    sortStoriesV7(sortableStories, storySortParameter, fileNameOrder);\n\n    return sortableStories.reduce(\n      (acc, item) => {\n        acc[item.id] = item;\n        return acc;\n      },\n      {} as StoryIndex['entries']\n    );\n  }\n\n  async getIndex() {\n    return (await this.getIndexAndStats()).storyIndex;\n  }\n\n  async getIndexAndStats(): Promise<{ storyIndex: StoryIndex; stats: IndexStatsSummary }> {\n    if (this.lastIndex && this.lastStats) {\n      return { storyIndex: this.lastIndex, stats: this.lastStats };\n    }\n\n    if (this.lastError) {\n      throw this.lastError;\n    }\n\n    const previewCode = await this.getPreviewCode();\n    const projectTags = this.getProjectTags(previewCode);\n\n    // Extract any entries that are currently missing\n    // Pull out each file's stories into a list of stories, to be composed and sorted\n    const { entries: storiesList, stats } = await this.ensureExtracted({ projectTags });\n\n    try {\n      const errorEntries = storiesList.filter((entry) => entry.type === 'error');\n\n      if (errorEntries.length) {\n        throw new MultipleIndexingError(errorEntries.map((entry) => (entry as ErrorEntry).err));\n      }\n\n      const duplicateErrors: IndexingError[] = [];\n      const indexEntries: StoryIndex['entries'] = {};\n      (storiesList as IndexEntry[]).forEach((entry) => {\n        try {\n          const existing = indexEntries[entry.id];\n          if (existing) {\n            indexEntries[entry.id] = this.chooseDuplicate(existing, entry, projectTags);\n          } else {\n            indexEntries[entry.id] = entry;\n          }\n        } catch (err) {\n          if (err instanceof IndexingError) {\n            duplicateErrors.push(err);\n          }\n        }\n      });\n\n      if (duplicateErrors.length) {\n        throw new MultipleIndexingError(duplicateErrors);\n      }\n\n      const sorted = await this.sortStories(\n        indexEntries,\n        previewCode && getStorySortParameter(previewCode)\n      );\n\n      this.lastStats = stats;\n      this.lastIndex = {\n        v: 5,\n        entries: sorted,\n      };\n\n      return { storyIndex: this.lastIndex, stats: this.lastStats };\n    } catch (err) {\n      this.lastError = err == null || err instanceof Error ? err : undefined;\n      invariant(this.lastError);\n      logger.warn(`🚨 ${this.lastError.toString()}`);\n      throw this.lastError;\n    }\n  }\n\n  invalidateAll() {\n    this.specifierToCache.forEach((cache) => {\n      Object.keys(cache).forEach((key) => {\n        cache[key] = false;\n      });\n    });\n    this.lastIndex = null;\n    this.lastError = null;\n    this.invalidationListeners.forEach((listener) => listener());\n  }\n\n  invalidate(importPath: Path, removed: boolean) {\n    const absolutePath = slash(resolve(this.options.workingDir, importPath));\n    const specifier = Array.from(this.specifierToCache.keys()).find((ns) =>\n      ns.importPathMatcher.exec(importPath)\n    );\n    if (!specifier) {\n      // not a story file\n      return;\n    }\n    const cache = this.specifierToCache.get(specifier);\n    invariant(\n      cache,\n      `specifier does not have a matching cache entry in specifierToCache: ${JSON.stringify(\n        specifier\n      )}`\n    );\n    const cacheEntry = cache[absolutePath];\n    if (cacheEntry && cacheEntry.type === 'stories') {\n      const { dependents } = cacheEntry;\n\n      const invalidated = new Set();\n      // the dependent can be in ANY cache, so we loop over all of them\n      this.specifierToCache.forEach((otherCache) => {\n        dependents.forEach((dep) => {\n          if (otherCache[dep]) {\n            invalidated.add(dep);\n\n            otherCache[dep] = false;\n          }\n        });\n      });\n    }\n\n    if (removed) {\n      if (cacheEntry && cacheEntry.type === 'docs') {\n        const absoluteImports = cacheEntry.storiesImports.map((p) =>\n          resolve(this.options.workingDir, p)\n        );\n        const dependencies = this.findDependencies(absoluteImports);\n        dependencies.forEach((dep) =>\n          dep.dependents.splice(dep.dependents.indexOf(absolutePath), 1)\n        );\n      }\n      delete cache[absolutePath];\n    } else {\n      cache[absolutePath] = false;\n    }\n    this.lastIndex = null;\n    this.lastError = null;\n    this.invalidationListeners.forEach((listener) => listener());\n  }\n\n  onInvalidated(listener: () => void) {\n    this.invalidationListeners.add(listener);\n    return () => {\n      this.invalidationListeners.delete(listener);\n    };\n  }\n\n  async getPreviewCode() {\n    const previewFile = ['js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs', 'mts']\n      .map((ext) => join(this.options.configDir, `preview.${ext}`))\n      .find((fname) => existsSync(fname));\n\n    return previewFile && (await readFile(previewFile, { encoding: 'utf8' })).toString();\n  }\n\n  getProjectTags(previewCode?: string) {\n    let projectTags = [] as Tag[];\n    const defaultTags = [Tag.DEV, Tag.TEST, Tag.MANIFEST];\n    if (previewCode) {\n      try {\n        const projectAnnotations = loadConfig(previewCode).parse();\n        projectTags = projectAnnotations.getFieldValue(['tags']) ?? [];\n      } catch (err) {\n        once.warn(dedent`\n          Unable to parse tags from project configuration. If defined, tags should be specified inline, e.g.\n\n          export default {\n            tags: ['foo'],\n          }\n\n          ---\n\n          Received:\n\n          ${previewCode}\n        `);\n      }\n    }\n    return [...defaultTags, ...projectTags];\n  }\n\n  // Get the story file names in \"imported order\"\n  static storyFileNames(specifierToCache: Map<NormalizedStoriesSpecifier, SpecifierStoriesCache>) {\n    return Array.from(specifierToCache.values()).flatMap((r) => Object.keys(r));\n  }\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/E.stories.ts",
    "content": "const component = {};\nexport default {\n  component,\n};\n\nexport const StoryOne = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/complex/MetaOfImportOrder.mdx",
    "content": "{/* References BStories first, but is attached to A */}\nimport * as BStories from '../src/B.stories';\nimport * as AStories from '../src/A.stories';\n\n<Meta of={AStories}/>\n\n# This file references two story files\n\nIt is important that A.stories is the first listed in `storiesImports` even when it is not the first import."
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/complex/TwoStoryReferences.mdx",
    "content": "{/* References AStories first, but is attached to B */}\nimport * as AStories from '../src/A.stories';\nimport * as BStories from '../src/B.stories';\n\n<Meta of={BStories}/>\n\n# This file references two story files\n\nIt is important that B.stories is the first listed in `storiesImports` (so we can tell what it is attached to)\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/deeply/nested/single/File.stories.ts",
    "content": "export default {\n  component: {},\n};\n\nexport const StoryOne = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/docs-id-generation/A.stories.jsx",
    "content": "// Stories for a component with meta.id\nconst component = {};\nexport default {\n  id: 'my-component-A',\n  component,\n  tags: ['autodocs'],\n};\n\nexport const StoryOne = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/docs-id-generation/B.docs.mdx",
    "content": "import * as Stories from './B.stories';\n\n<Meta of={Stories} />\n\n# Docs with of\n\nhello docs\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/docs-id-generation/B.stories.jsx",
    "content": "// Stories for a component with meta.id\nconst component = {};\nexport default {\n  id: 'my-component-B',\n  component,\n};\n\nexport const StoryOne = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/duplicate/A.stories.js",
    "content": "const component = {};\nexport default {\n  component,\n  title: 'duplicate/A',\n  tags: ['autodocs'],\n};\n\nexport const StoryOne = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/duplicate/SecondA.stories.js",
    "content": "const component = {};\nexport default {\n  component,\n  title: 'duplicate/A',\n  tags: ['autodocs'],\n};\n\nexport const StoryTwo = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/errors/A.mdx",
    "content": "import * as AStories from '../src/A.stories';\n\n<Meta of={AStories} />\n\n# Docs with of\n\nhello docs\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/errors/B.mdx",
    "content": "import * as BStories from '../src/B.stories';\n\n<Meta of={BStories} />\n\n# Docs with of\n\nhello docs\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/errors/MetaOfClashingDefaultName.mdx",
    "content": "import * as BStories from '../src/B.stories';\n\n{/* This is the same name as the default name (i.e. autodocs entry) */}\n\n<Meta of={BStories} name=\"Docs\" />\n\n# Docs with of\n\nhello docs\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/errors/MetaOfClashingName.mdx",
    "content": "import * as AStories from '../src/A.stories';\n\n{/* This is the same name as a story */}\n\n<Meta of={AStories} name=\"Story One\" />\n\n# Docs with of\n\nhello docs\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/errors/MetaOfName.mdx",
    "content": "import * as BStories from '../src/B.stories';\n\n<Meta of={BStories} name=\"name\" />\n\n# Docs with of\n\nhello docs\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/errors/MetaOfNoName.mdx",
    "content": "import * as BStories from '../src/B.stories';\n\n<Meta of={BStories} />\n\n# Docs with of\n\nhello docs\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/errors/NoMeta.stories.ts",
    "content": "/* eslint-disable storybook/default-exports */\n// no default export\n// e.g. https://github.com/storybookjs/storybook/issues/16421\nexport const StoryOne = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/errors/NoStories.stories.ts",
    "content": "/* eslint-disable storybook/story-exports */\nconst component = {};\nexport default {\n  component,\n};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/errors/duplicate/A.mdx",
    "content": "import * as AStories from '../../src/A.stories';\n\n<Meta of={AStories} />\n\n# Docs with of\n\nhello docs\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/main.js",
    "content": "export default {\n  stories: ['docs-id-generation/*.(stories|docs).*'],\n  framework: '@storybook/react-vite',\n};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/preview.js",
    "content": "export const parameters = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/A.js",
    "content": "// This could be the component for `A.stories.js`\nexport const A = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/A.stories.js",
    "content": "const component = {};\nexport default {\n  component,\n  tags: ['component-tag'],\n};\n\nexport const StoryOne = { tags: ['story-tag'] };\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/B.stories.ts",
    "content": "const component = {};\nexport default {\n  component,\n  tags: ['autodocs'],\n};\n\nexport const StoryOne = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/Button.stories.ts",
    "content": "const component = {};\nexport default {\n  title: 'Example/Button',\n  component,\n  tags: ['foobar'],\n};\n\nexport const StoryOne = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/C.js",
    "content": "export const C = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/D.stories.jsx",
    "content": "const component = {};\nexport default {\n  component,\n  tags: ['autodocs'],\n};\n\nexport const StoryOne = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/Empty.stories.ts",
    "content": ""
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/F.story.ts",
    "content": "const component = {};\nexport default {\n  component,\n  tags: ['autodocs'],\n};\n\nexport const StoryOne = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/H.stories.mjs",
    "content": "const component = {};\n\nexport default {\n  component,\n  tags: ['autodocs'],\n};\n\nexport const StoryOne = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/componentPath/component.js",
    "content": "export default {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/componentPath/extension.stories.js",
    "content": "import component from './component.js';\n\nexport default {\n  component,\n};\n\nexport const StoryOne = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/componentPath/noExtension.stories.js",
    "content": "import component from './component';\n\nexport default {\n  component,\n};\n\nexport const StoryOne = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/componentPath/package.stories.js",
    "content": "import component from 'component-package';\n\nexport default {\n  component,\n};\n\nexport const StoryOne = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/docs2/ComponentReference.js",
    "content": "// This a component that happens to have the same name as an MDX file referencing it\nexport const ComponentReference = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/docs2/ComponentReference.mdx",
    "content": "{/* This will overlap with ComponentReference.mdx (this file). There's not much we can do about this */} \nimport ComponentReference from './ComponentReference';\n\n{/* This prefixes A.stories.ts, we need to make sure we don't get confused. */} \nimport { A } from '../A';"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/docs2/MetaOf.mdx",
    "content": "import * as AStories from '../A.stories';\n\n<Meta of={AStories} />\n\n# Docs with of\n\nhello docs\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/docs2/NoTitle.mdx",
    "content": "# Docs with no title\n\nhello docs\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/docs2/SecondMetaOf.mdx",
    "content": "import * as AStories from '../A.stories';\n\n<Meta of={AStories} name=\"Second Docs\" />\n\n# Second Docs\n\nhello docs\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/docs2/Tags.mdx",
    "content": "import { Meta } from '@storybook/addon-docs';\n\n<Meta tags={['foo', 'bar']} />\n\n# Docs with tags\n\nhello docs"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/docs2/Template.mdx",
    "content": "import { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta isTemplate />\n\n# Docs with title\n\nhello docs\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/docs2/Title.mdx",
    "content": "import { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"docs2/Yabbadabbadooo\" />\n\n# Docs with title\n\nhello docs\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/first-nested/deeply/F.stories.js",
    "content": "const component = {};\nexport default {\n  component,\n};\n\nexport const StoryOne = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/first-nested/deeply/Features.stories.jsx",
    "content": "const component = {};\nexport default {\n  component,\n};\n\nexport const WithPlay = {\n  play: async () => {},\n};\n\nexport const WithStoryFn = () => {};\n\nexport const WithRender = {\n  render: () => {},\n};\n\nexport const WithTest = {\n  beforeEach: async () => {},\n  play: async ({ mount }) => {\n    await mount();\n  },\n};\n\nexport const WithCSF1 = {\n  parameters: {},\n  decorators: [],\n  loaders: [],\n};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/nested/Button.stories.ts",
    "content": "const component = {};\nexport default {\n  component,\n  tags: ['component-tag'],\n};\n\nexport const StoryOne = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/nested/Button.ts",
    "content": "export const Button = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/second-nested/G.stories.ts",
    "content": "const component = {};\nexport default {\n  component,\n};\n\nexport const StoryOne = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__mockdata__/src/stories.ts",
    "content": "const component = {};\nexport default {\n  component,\n  tags: ['autodocs'],\n};\n\nexport const StoryOne = {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__search-files-tests__/.gitignore",
    "content": "src/ignored.js\n!src/node_modules"
  },
  {
    "path": "code/core/src/core-server/utils/__search-files-tests__/README.md",
    "content": "The parent directory \"\\_\\_tests\\_\\_ was created to unit test the search-file functionality\n"
  },
  {
    "path": "code/core/src/core-server/utils/__search-files-tests__/src/assets/asset.css",
    "content": ""
  },
  {
    "path": "code/core/src/core-server/utils/__search-files-tests__/src/assets/asset.json",
    "content": ""
  },
  {
    "path": "code/core/src/core-server/utils/__search-files-tests__/src/commonjs-module-default.js",
    "content": "module.exports = require('./commonjs');\n"
  },
  {
    "path": "code/core/src/core-server/utils/__search-files-tests__/src/commonjs-module.js",
    "content": "// named exports detection\nmodule.exports.a = 'a';\n\n(function () {\n  exports.b = 'b';\n})();\n\nObject.defineProperty(exports, 'c', { value: 'c' });\n/* exports.d = 'not detected'; */\n\n// reexports detection\n\n/* exports.d = 'not detected'; */\n\n// reexports detection\nif (maybe) {\n  module.exports = require('./dep1.js');\n}\n\nif (another) {\n  module.exports = require('./dep2.js');\n}\n\n// literal exports assignments\n\n// literal exports assignments\nmodule.exports = { a, b: c, d, e: f };\n\n// __esModule detection\nObject.defineProperty(module.exports, '__esModule', { value: true });\n"
  },
  {
    "path": "code/core/src/core-server/utils/__search-files-tests__/src/es-module.js",
    "content": "import * as ns from 'external2';\n\nexport var p = 5;\n\nexport function q() {}\n\nexport class C {}\n\nexport { x as externalName } from 'external';\n\nexport { ns };\n\nexport default function () {\n  return 'default';\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/__search-files-tests__/src/es-module.stories.js",
    "content": "export default {};\n"
  },
  {
    "path": "code/core/src/core-server/utils/__search-files-tests__/src/file-extensions/extension.cjs",
    "content": "export default function () {\n  return 'default';\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/__search-files-tests__/src/file-extensions/extension.cts",
    "content": "export default function () {\n  return 'default';\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/__search-files-tests__/src/file-extensions/extension.js",
    "content": "export default function () {\n  return 'default';\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/__search-files-tests__/src/file-extensions/extension.jsx",
    "content": "export default function () {\n  return 'default';\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/__search-files-tests__/src/file-extensions/extension.mjs",
    "content": "export default function () {\n  return 'default';\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/__search-files-tests__/src/file-extensions/extension.mts",
    "content": "export default function () {\n  return 'default';\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/__search-files-tests__/src/file-extensions/extension.ts",
    "content": "export default function () {\n  return 'default';\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/__search-files-tests__/src/file-extensions/extension.tsx",
    "content": "export default function () {\n  return 'default';\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/__search-files-tests__/src/no-export.js",
    "content": ""
  },
  {
    "path": "code/core/src/core-server/utils/__search-files-tests__/src/tests/some.spec.ts",
    "content": ""
  },
  {
    "path": "code/core/src/core-server/utils/__search-files-tests__/src/tests/some.test.ts",
    "content": ""
  },
  {
    "path": "code/core/src/core-server/utils/__tests__/IndexingError.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { IndexingError, MultipleIndexingError } from '../IndexingError.ts';\n\nit('formats single file errors', () => {\n  const error = new IndexingError('parse error', ['./stories/File.stories.ts']);\n\n  expect(error.toString()).toMatchInlineSnapshot(`\"./stories/File.stories.ts: parse error\"`);\n});\n\nit('formats multi file errors', () => {\n  const error = new IndexingError('Duplicate stories', [\n    './stories/File.stories.ts',\n    '/path/to/other/File.stories.ts',\n  ]);\n\n  expect(error.toString()).toMatchInlineSnapshot(\n    `\"./stories/File.stories.ts,/path/to/other/File.stories.ts: Duplicate stories\"`\n  );\n});\n\ndescribe('formatIndexingErrors', () => {\n  it('formats one error with trace', () => {\n    const stack = `Error: parse error\n          at Object.<anonymous> (/user/storybookjs/storybook/code/lib/core-server/src/utils/__tests__/IndexingError.test.ts:26:25)\n          at Promise.then.completed (/user/storybookjs/storybook/code/node_modules/jest-circus/build/utils.js:293:28)\n          at new Promise (<anonymous>)`;\n    const error = new IndexingError('parse error', ['./stories/File.stories.ts'], stack);\n    const multiError = new MultipleIndexingError([error]);\n\n    expect(multiError.toString()).toMatchInlineSnapshot(`\n      \"Unable to index ./stories/File.stories.ts:\n        Error: parse error\n                at Object.<anonymous> (/user/storybookjs/storybook/code/lib/core-server/src/utils/__tests__/IndexingError.test.ts:26:25)\n                at Promise.then.completed (/user/storybookjs/storybook/code/node_modules/jest-circus/build/utils.js:293:28)\n                at new Promise (<anonymous>)\"\n    `);\n  });\n\n  it('formats multiple errors without trace', () => {\n    const errors = [0, 1, 2].map((index) => {\n      return new IndexingError('parse error', [`./stories/File-${index}.stories.ts`]);\n    });\n    const multiError = new MultipleIndexingError(errors);\n\n    expect(multiError.toString()).toMatchInlineSnapshot(`\n      \"Unable to index files:\n      - ./stories/File-0.stories.ts: parse error\n      - ./stories/File-1.stories.ts: parse error\n      - ./stories/File-2.stories.ts: parse error\"\n    `);\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/__tests__/autoName.test.ts",
    "content": "import { expect, it } from 'vitest';\n\nimport { autoName } from '../autoName.ts';\n\nit('pulls name from named MDX files', () => {\n  expect(autoName('Conventions.mdx', 'Button.mdx', 'Docs')).toEqual('Conventions');\n});\n\nit('falls back for default named MDX files', () => {\n  expect(autoName('Button.mdx', 'Button.stories.jsx', 'Docs')).toEqual('Docs');\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/__tests__/getHostValidationMiddleware.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { getHostValidationMiddleware, isValidHost } from '../getHostValidationMiddleware.ts';\n\nfunction createMockRequest(headers: Record<string, string>) {\n  return { headers } as any;\n}\n\nfunction createMockResponse() {\n  const res: any = {\n    writeHead: vi.fn(),\n    end: vi.fn(),\n  };\n  return res;\n}\n\ndescribe('getHostValidationMiddleware', () => {\n  it('calls next() when allowedHosts is true (allow all)', () => {\n    const middleware = getHostValidationMiddleware({\n      host: 'localhost',\n      allowedHosts: true,\n    });\n    const req = createMockRequest({ host: 'malicious-site.com:6006' });\n    const res = createMockResponse();\n    const next = vi.fn();\n\n    middleware(req, res, next);\n\n    expect(next).toHaveBeenCalledTimes(1);\n    expect(res.writeHead).not.toHaveBeenCalled();\n  });\n\n  it('returns 403 when Host is invalid (strict allowedHosts)', () => {\n    const middleware = getHostValidationMiddleware({\n      host: 'localhost',\n      allowedHosts: [],\n      localAddress: 'http://localhost:6006',\n      networkAddress: 'http://192.168.1.100:6006',\n    });\n    const req = createMockRequest({ host: 'evil.com:6006' });\n    const res = createMockResponse();\n    const next = vi.fn();\n\n    middleware(req, res, next);\n\n    expect(res.writeHead).toHaveBeenCalledWith(403, { 'Content-Type': 'text/plain' });\n    expect(res.end).toHaveBeenCalledWith('Invalid host');\n    expect(next).not.toHaveBeenCalled();\n  });\n\n  it('calls next() when Host is valid (matches localAddress)', () => {\n    const middleware = getHostValidationMiddleware({\n      host: 'localhost',\n      allowedHosts: [],\n      localAddress: 'http://localhost:6006',\n      networkAddress: 'http://192.168.1.100:6006',\n    });\n    const req = createMockRequest({ host: 'localhost:6006' });\n    const res = createMockResponse();\n    const next = vi.fn();\n\n    middleware(req, res, next);\n\n    expect(next).toHaveBeenCalledTimes(1);\n    expect(res.writeHead).not.toHaveBeenCalled();\n  });\n\n  it('calls next() when Host matches networkAddress', () => {\n    const middleware = getHostValidationMiddleware({\n      host: '0.0.0.0',\n      allowedHosts: [],\n      localAddress: 'http://localhost:6006',\n      networkAddress: 'http://192.168.1.100:6006',\n    });\n    const req = createMockRequest({ host: '192.168.1.100:6006' });\n    const res = createMockResponse();\n    const next = vi.fn();\n\n    middleware(req, res, next);\n\n    expect(next).toHaveBeenCalledTimes(1);\n    expect(res.writeHead).not.toHaveBeenCalled();\n  });\n\n  it('calls next() when allowedHosts is empty but Host matches localAddress', () => {\n    const middleware = getHostValidationMiddleware({\n      host: 'localhost',\n      allowedHosts: [],\n      localAddress: 'http://localhost:6006',\n      networkAddress: 'http://192.168.1.100:6006',\n    });\n    const req = createMockRequest({ host: 'localhost:6006' });\n    const res = createMockResponse();\n    const next = vi.fn();\n\n    middleware(req, res, next);\n\n    expect(next).toHaveBeenCalledTimes(1);\n    expect(res.writeHead).not.toHaveBeenCalled();\n  });\n\n  it('returns 403 when Host header is absent (allowedHosts not true)', () => {\n    const middleware = getHostValidationMiddleware({\n      host: 'localhost',\n      allowedHosts: [],\n      localAddress: 'http://localhost:6006',\n    });\n    const req = createMockRequest({});\n    const res = createMockResponse();\n    const next = vi.fn();\n\n    middleware(req, res, next);\n\n    expect(res.writeHead).toHaveBeenCalledWith(403, { 'Content-Type': 'text/plain' });\n    expect(next).not.toHaveBeenCalled();\n  });\n\n  it('calls next() when Host matches allowedHosts hostname (custom domain)', () => {\n    const middleware = getHostValidationMiddleware({\n      allowedHosts: ['my-app.example.com'],\n    });\n    const req = createMockRequest({ host: 'my-app.example.com:6006' });\n    const res = createMockResponse();\n    const next = vi.fn();\n\n    middleware(req, res, next);\n\n    expect(next).toHaveBeenCalledTimes(1);\n    expect(res.writeHead).not.toHaveBeenCalled();\n  });\n});\n\ndescribe('isValidHost', () => {\n  const options = {\n    localAddress: 'http://localhost:6006',\n    networkAddress: 'http://192.168.1.100:6006',\n  } as any;\n\n  /** When allowedHosts is set to [], only local/network hosts are allowed (no default allow-all). */\n  const strictOptions = { ...options, allowedHosts: [] } as any;\n\n  it('returns true for exact local address match', () => {\n    expect(isValidHost('localhost:6006', options)).toBe(true);\n  });\n\n  it('returns true for network address match', () => {\n    expect(isValidHost('192.168.1.100:6006', options)).toBe(true);\n  });\n\n  it('returns true for localhost host', () => {\n    expect(isValidHost('localhost:6006', options)).toBe(true);\n  });\n\n  it('returns true for 127.0.0.1 host', () => {\n    expect(isValidHost('127.0.0.1:6006', options)).toBe(true);\n  });\n\n  it('when allowedHosts is undefined (default []), rejects foreign hosts', () => {\n    expect(isValidHost('malicious-site.com', options)).toBe(false);\n    expect(isValidHost('any-origin.example.com', options)).toBe(false);\n  });\n\n  it('when allowedHosts is true, allows any host', () => {\n    const allowAllOptions = { ...options, allowedHosts: true } as any;\n    expect(isValidHost('malicious-site.com', allowAllOptions)).toBe(true);\n    expect(isValidHost('any-origin.example.com', allowAllOptions)).toBe(true);\n  });\n\n  it('returns false for different host when allowedHosts is empty', () => {\n    expect(isValidHost('malicious-site.com', strictOptions)).toBe(false);\n  });\n\n  it('returns true for localhost with different port (host-validation-middleware allows localhost)', () => {\n    expect(isValidHost('localhost:8080', strictOptions)).toBe(true);\n  });\n\n  it('returns true for localhost with same host (host-validation-middleware allows localhost)', () => {\n    expect(isValidHost('localhost:6006', strictOptions)).toBe(true);\n  });\n\n  it('returns false for undefined host when not allow-all', () => {\n    expect(isValidHost(undefined, strictOptions)).toBe(false);\n  });\n\n  it('returns false for null host when not allow-all', () => {\n    expect(isValidHost(null as any, strictOptions)).toBe(false);\n  });\n\n  it('returns true when localAddress is missing but hostname is localhost (host-validation-middleware allows localhost)', () => {\n    const optionsWithoutLocal = {\n      networkAddress: 'http://192.168.1.100:6006',\n      allowedHosts: [],\n    } as any;\n    expect(isValidHost('localhost:6006', optionsWithoutLocal)).toBe(true);\n  });\n\n  it('handles https local/network addresses correctly', () => {\n    const httpsOptions = {\n      localAddress: 'https://localhost:6006',\n      networkAddress: 'https://192.168.1.100:6006',\n    } as any;\n    expect(isValidHost('localhost:6006', httpsOptions)).toBe(true);\n    expect(isValidHost('192.168.1.100:6006', httpsOptions)).toBe(true);\n    const strictHttpsOptions = { ...httpsOptions, allowedHosts: [] } as any;\n    expect(isValidHost('localhost:6006', strictHttpsOptions)).toBe(true);\n  });\n\n  it('handles network address without port', () => {\n    const optionsWithoutNetwork = {\n      localAddress: 'http://localhost:6006',\n    } as any;\n    expect(isValidHost('localhost:6006', optionsWithoutNetwork)).toBe(true);\n    const strictNoNetwork = { ...optionsWithoutNetwork, allowedHosts: [] } as any;\n    expect(isValidHost('192.168.1.100:6006', strictNoNetwork)).toBe(true);\n  });\n\n  it('returns true for different network IP (host-validation-middleware allows any IPv4)', () => {\n    expect(isValidHost('10.0.0.1:6006', strictOptions)).toBe(true);\n  });\n\n  it('returns true when request host is in allowedHosts', () => {\n    const optionsWithAllowed = {\n      ...options,\n      allowedHosts: ['my-app.example.com', 'other.example.com'],\n    } as any;\n    expect(isValidHost('my-app.example.com', optionsWithAllowed)).toBe(true);\n    expect(isValidHost('other.example.com', optionsWithAllowed)).toBe(true);\n  });\n\n  it('returns false when request host is not in allowedHosts and not local/network', () => {\n    const optionsWithAllowed = {\n      localAddress: 'http://localhost:6006',\n      networkAddress: 'http://192.168.1.100:6006',\n      allowedHosts: ['my-app.example.com'],\n    } as any;\n    expect(isValidHost('other-site.com', optionsWithAllowed)).toBe(false);\n  });\n\n  it('allowedHosts does not override default local/network checks', () => {\n    const optionsWithAllowed = {\n      ...options,\n      allowedHosts: ['my-app.example.com'],\n    } as any;\n    expect(isValidHost('localhost:6006', optionsWithAllowed)).toBe(true);\n    expect(isValidHost('192.168.1.100:6006', optionsWithAllowed)).toBe(true);\n  });\n\n  it('empty allowedHosts does not allow arbitrary hosts', () => {\n    const optionsWithEmptyAllowed = {\n      localAddress: 'http://localhost:6006',\n      allowedHosts: [],\n    } as any;\n    expect(isValidHost('localhost:6006', optionsWithEmptyAllowed)).toBe(true);\n    expect(isValidHost('arbitrary.com', optionsWithEmptyAllowed)).toBe(false);\n  });\n\n  it('when host is 0.0.0.0 and allowedHosts is empty, permits all hosts', () => {\n    const optionsZeroHost = {\n      host: '0.0.0.0',\n      allowedHosts: [],\n    } as any;\n    expect(isValidHost('malicious-site.com', optionsZeroHost)).toBe(true);\n    expect(isValidHost('any-origin.example.com', optionsZeroHost)).toBe(true);\n  });\n\n  it('when host is 0.0.0.0 but allowedHosts is not empty, does not permit arbitrary hosts', () => {\n    const optionsZeroHostWithAllowed = {\n      host: '0.0.0.0',\n      localAddress: 'http://localhost:6006',\n      allowedHosts: ['my-app.example.com'],\n    } as any;\n    expect(isValidHost('malicious-site.com', optionsZeroHostWithAllowed)).toBe(false);\n    expect(isValidHost('my-app.example.com', optionsZeroHostWithAllowed)).toBe(true);\n  });\n\n  it('when allowedHosts has hostnames, matches by hostname (host-validation-middleware ignores port in allowedHosts)', () => {\n    const optionsWithAllowed = {\n      localAddress: 'http://localhost:6006',\n      allowedHosts: ['my-app.example.com', 'other.example.com'],\n    } as any;\n    expect(isValidHost('my-app.example.com:8443', optionsWithAllowed)).toBe(true);\n    expect(isValidHost('other.example.com:8080', optionsWithAllowed)).toBe(true);\n    expect(isValidHost('other-site.com:8080', optionsWithAllowed)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/__tests__/index-extraction.test.ts",
    "content": "import { join } from 'node:path';\n\nimport { describe, expect, it, vi } from 'vitest';\n\nimport { normalizeStoriesEntry } from 'storybook/internal/common';\nimport type { NormalizedStoriesSpecifier } from 'storybook/internal/types';\n\nimport { Tag } from '../../../shared/constants/tags.ts';\nimport type { StoryIndexGeneratorOptions } from '../StoryIndexGenerator.ts';\nimport { StoryIndexGenerator } from '../StoryIndexGenerator.ts';\n\nvi.mock('storybook/internal/node-logger');\n\nconst options: StoryIndexGeneratorOptions = {\n  configDir: join(__dirname, '..', '__mockdata__'),\n  workingDir: join(__dirname, '..', '__mockdata__'),\n  indexers: [],\n  docs: { defaultName: 'docs' },\n};\n\ndescribe('story extraction', () => {\n  it('extracts stories from full indexer inputs', async () => {\n    const relativePath = './src/A.stories.js';\n    const absolutePath = join(options.workingDir, relativePath);\n    const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(relativePath, options);\n\n    const generator = new StoryIndexGenerator([specifier], {\n      ...options,\n      indexers: [\n        {\n          test: /\\.stories\\.(m?js|ts)x?$/,\n          createIndex: async (fileName) => [\n            // properties identical to the auto-generated ones, eg. 'StoryOne' -> 'Story One'\n            {\n              type: 'story',\n              subtype: 'story',\n              importPath: fileName,\n              exportName: 'StoryOne',\n              name: 'Story One',\n              title: 'A',\n              metaId: 'a',\n              tags: ['story-tag-from-indexer'],\n              __id: 'a--story-one',\n            },\n            // properties different from the auto-generated ones, eg. 'StoryOne' -> 'Another Story Name'\n            {\n              type: 'story',\n              subtype: 'story',\n              importPath: fileName,\n              exportName: 'StoryOne',\n              name: 'Another Story Name',\n              title: 'Custom Title',\n              metaId: 'custom-id',\n              tags: ['story-tag-from-indexer'],\n              __id: 'some-fully-custom-id',\n            },\n          ],\n        },\n      ],\n    });\n    const result = await generator.extractStories(specifier, absolutePath);\n\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"dependents\": [],\n        \"entries\": [\n          {\n            \"componentPath\": undefined,\n            \"exportName\": \"StoryOne\",\n            \"extra\": {\n              \"metaId\": \"a\",\n              \"stats\": {},\n            },\n            \"id\": \"a--story-one\",\n            \"importPath\": \"./src/A.stories.js\",\n            \"name\": \"Story One\",\n            \"subtype\": \"story\",\n            \"tags\": [\n              \"story-tag-from-indexer\",\n            ],\n            \"title\": \"A\",\n            \"type\": \"story\",\n          },\n          {\n            \"componentPath\": undefined,\n            \"exportName\": \"StoryOne\",\n            \"extra\": {\n              \"metaId\": \"custom-id\",\n              \"stats\": {},\n            },\n            \"id\": \"some-fully-custom-id\",\n            \"importPath\": \"./src/A.stories.js\",\n            \"name\": \"Another Story Name\",\n            \"subtype\": \"story\",\n            \"tags\": [\n              \"story-tag-from-indexer\",\n            ],\n            \"title\": \"Custom Title\",\n            \"type\": \"story\",\n          },\n        ],\n        \"type\": \"stories\",\n      }\n    `);\n  });\n\n  it('extracts stories from minimal indexer inputs', async () => {\n    const relativePath = './src/first-nested/deeply/F.stories.js';\n    const absolutePath = join(options.workingDir, relativePath);\n    const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(relativePath, options);\n\n    const generator = new StoryIndexGenerator([specifier], {\n      ...options,\n      indexers: [\n        {\n          test: /\\.stories\\.(m?js|ts)x?$/,\n          createIndex: async (fileName) => [\n            {\n              exportName: 'StoryOne',\n              importPath: fileName,\n              type: 'story',\n              subtype: 'story',\n            },\n          ],\n        },\n      ],\n    });\n    const result = await generator.extractStories(specifier, absolutePath);\n\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"dependents\": [],\n        \"entries\": [\n          {\n            \"componentPath\": undefined,\n            \"exportName\": \"StoryOne\",\n            \"extra\": {\n              \"metaId\": undefined,\n              \"stats\": {},\n            },\n            \"id\": \"f--story-one\",\n            \"importPath\": \"./src/first-nested/deeply/F.stories.js\",\n            \"name\": \"Story One\",\n            \"subtype\": \"story\",\n            \"tags\": [],\n            \"title\": \"F\",\n            \"type\": \"story\",\n          },\n        ],\n        \"type\": \"stories\",\n      }\n    `);\n  });\n\n  it('auto-generates title from indexer inputs without title', async () => {\n    const relativePath = './src/first-nested/deeply/F.stories.js';\n    const absolutePath = join(options.workingDir, relativePath);\n    const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(relativePath, options);\n\n    const generator = new StoryIndexGenerator([specifier], {\n      ...options,\n      indexers: [\n        {\n          test: /\\.stories\\.(m?js|ts)x?$/,\n          createIndex: async (fileName) => [\n            {\n              exportName: 'StoryOne',\n              __id: 'a--story-one',\n              name: 'Story One',\n              metaId: 'a',\n              tags: ['story-tag-from-indexer'],\n              importPath: fileName,\n              type: 'story',\n              subtype: 'story',\n            },\n          ],\n        },\n      ],\n    });\n    const result = await generator.extractStories(specifier, absolutePath);\n\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"dependents\": [],\n        \"entries\": [\n          {\n            \"componentPath\": undefined,\n            \"exportName\": \"StoryOne\",\n            \"extra\": {\n              \"metaId\": \"a\",\n              \"stats\": {},\n            },\n            \"id\": \"a--story-one\",\n            \"importPath\": \"./src/first-nested/deeply/F.stories.js\",\n            \"name\": \"Story One\",\n            \"subtype\": \"story\",\n            \"tags\": [\n              \"story-tag-from-indexer\",\n            ],\n            \"title\": \"F\",\n            \"type\": \"story\",\n          },\n        ],\n        \"type\": \"stories\",\n      }\n    `);\n  });\n\n  it('auto-generates name from indexer inputs without name', async () => {\n    const relativePath = './src/A.stories.js';\n    const absolutePath = join(options.workingDir, relativePath);\n    const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(relativePath, options);\n\n    const generator = new StoryIndexGenerator([specifier], {\n      ...options,\n      indexers: [\n        {\n          test: /\\.stories\\.(m?js|ts)x?$/,\n          createIndex: async (fileName) => [\n            {\n              exportName: 'StoryOne',\n              __id: 'a--story-one',\n              title: 'A',\n              metaId: 'a',\n              tags: ['story-tag-from-indexer'],\n              importPath: fileName,\n              type: 'story',\n              subtype: 'story',\n            },\n          ],\n        },\n      ],\n    });\n    const result = await generator.extractStories(specifier, absolutePath);\n\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"dependents\": [],\n        \"entries\": [\n          {\n            \"componentPath\": undefined,\n            \"exportName\": \"StoryOne\",\n            \"extra\": {\n              \"metaId\": \"a\",\n              \"stats\": {},\n            },\n            \"id\": \"a--story-one\",\n            \"importPath\": \"./src/A.stories.js\",\n            \"name\": \"Story One\",\n            \"subtype\": \"story\",\n            \"tags\": [\n              \"story-tag-from-indexer\",\n            ],\n            \"title\": \"A\",\n            \"type\": \"story\",\n          },\n        ],\n        \"type\": \"stories\",\n      }\n    `);\n  });\n\n  it('auto-generates id', async () => {\n    const relativePath = './src/A.stories.js';\n    const absolutePath = join(options.workingDir, relativePath);\n    const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(relativePath, options);\n\n    const generator = new StoryIndexGenerator([specifier], {\n      ...options,\n      indexers: [\n        {\n          test: /\\.stories\\.(m?js|ts)x?$/,\n          createIndex: async (fileName) => [\n            // exportName + title -> id\n            {\n              exportName: 'StoryOne',\n              name: 'Story One',\n              title: 'A',\n              tags: ['story-tag-from-indexer'],\n              importPath: fileName,\n              type: 'story',\n              subtype: 'story',\n            },\n            // exportName + custom title (ignoring custom name) -> id\n            {\n              exportName: 'StoryTwo',\n              name: 'Custom Name For Second Story',\n              title: 'Custom Title',\n              tags: ['story-tag-from-indexer'],\n              importPath: fileName,\n              type: 'story',\n              subtype: 'story',\n            },\n            // exportName + custom metaId (ignoring custom title and name) -> id\n            {\n              exportName: 'StoryThree',\n              metaId: 'custom-meta-id',\n              title: 'Custom Title',\n              tags: ['story-tag-from-indexer'],\n              importPath: fileName,\n              type: 'story',\n              subtype: 'story',\n            },\n          ],\n        },\n      ],\n    });\n    const result = await generator.extractStories(specifier, absolutePath);\n\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"dependents\": [],\n        \"entries\": [\n          {\n            \"componentPath\": undefined,\n            \"exportName\": \"StoryOne\",\n            \"extra\": {\n              \"metaId\": undefined,\n              \"stats\": {},\n            },\n            \"id\": \"a--story-one\",\n            \"importPath\": \"./src/A.stories.js\",\n            \"name\": \"Story One\",\n            \"subtype\": \"story\",\n            \"tags\": [\n              \"story-tag-from-indexer\",\n            ],\n            \"title\": \"A\",\n            \"type\": \"story\",\n          },\n          {\n            \"componentPath\": undefined,\n            \"exportName\": \"StoryTwo\",\n            \"extra\": {\n              \"metaId\": undefined,\n              \"stats\": {},\n            },\n            \"id\": \"custom-title--story-two\",\n            \"importPath\": \"./src/A.stories.js\",\n            \"name\": \"Custom Name For Second Story\",\n            \"subtype\": \"story\",\n            \"tags\": [\n              \"story-tag-from-indexer\",\n            ],\n            \"title\": \"Custom Title\",\n            \"type\": \"story\",\n          },\n          {\n            \"componentPath\": undefined,\n            \"exportName\": \"StoryThree\",\n            \"extra\": {\n              \"metaId\": \"custom-meta-id\",\n              \"stats\": {},\n            },\n            \"id\": \"custom-meta-id--story-three\",\n            \"importPath\": \"./src/A.stories.js\",\n            \"name\": \"Story Three\",\n            \"subtype\": \"story\",\n            \"tags\": [\n              \"story-tag-from-indexer\",\n            ],\n            \"title\": \"Custom Title\",\n            \"type\": \"story\",\n          },\n        ],\n        \"type\": \"stories\",\n      }\n    `);\n  });\n\n  it('auto-generates id, title and name from exportName input', async () => {\n    const relativePath = './src/A.stories.js';\n    const absolutePath = join(options.workingDir, relativePath);\n    const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(relativePath, options);\n\n    const generator = new StoryIndexGenerator([specifier], {\n      ...options,\n      indexers: [\n        {\n          test: /\\.stories\\.(m?js|ts)x?$/,\n          createIndex: async (fileName) => [\n            {\n              exportName: 'StoryOne',\n              tags: ['story-tag-from-indexer'],\n              importPath: fileName,\n              type: 'story',\n              subtype: 'story',\n            },\n          ],\n        },\n      ],\n    });\n    const result = await generator.extractStories(specifier, absolutePath);\n\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"dependents\": [],\n        \"entries\": [\n          {\n            \"componentPath\": undefined,\n            \"exportName\": \"StoryOne\",\n            \"extra\": {\n              \"metaId\": undefined,\n              \"stats\": {},\n            },\n            \"id\": \"a--story-one\",\n            \"importPath\": \"./src/A.stories.js\",\n            \"name\": \"Story One\",\n            \"subtype\": \"story\",\n            \"tags\": [\n              \"story-tag-from-indexer\",\n            ],\n            \"title\": \"A\",\n            \"type\": \"story\",\n          },\n        ],\n        \"type\": \"stories\",\n      }\n    `);\n  });\n});\ndescribe('docs entries from story extraction', () => {\n  it(`adds docs entry when autodocs is \"tag\" and an entry has the \"${Tag.AUTODOCS}\" tag`, async () => {\n    const relativePath = './src/A.stories.js';\n    const absolutePath = join(options.workingDir, relativePath);\n    const specifier: NormalizedStoriesSpecifier = normalizeStoriesEntry(relativePath, options);\n\n    const generator = new StoryIndexGenerator([specifier], {\n      ...options,\n      docs: { defaultName: 'docs' },\n      indexers: [\n        {\n          test: /\\.stories\\.(m?js|ts)x?$/,\n          createIndex: async (fileName) => [\n            {\n              exportName: 'StoryOne',\n              __id: 'a--story-one',\n              name: 'Story One',\n              title: 'A',\n              tags: [Tag.AUTODOCS, 'story-tag-from-indexer'],\n              importPath: fileName,\n              type: 'story',\n              subtype: 'story',\n            },\n          ],\n        },\n      ],\n    });\n    const result = await generator.extractStories(specifier, absolutePath);\n\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"dependents\": [],\n        \"entries\": [\n          {\n            \"id\": \"a--docs\",\n            \"importPath\": \"./src/A.stories.js\",\n            \"name\": \"docs\",\n            \"storiesImports\": [],\n            \"tags\": [\n              \"autodocs\",\n              \"story-tag-from-indexer\",\n            ],\n            \"title\": \"A\",\n            \"type\": \"docs\",\n          },\n          {\n            \"componentPath\": undefined,\n            \"exportName\": \"StoryOne\",\n            \"extra\": {\n              \"metaId\": undefined,\n              \"stats\": {},\n            },\n            \"id\": \"a--story-one\",\n            \"importPath\": \"./src/A.stories.js\",\n            \"name\": \"Story One\",\n            \"subtype\": \"story\",\n            \"tags\": [\n              \"autodocs\",\n              \"story-tag-from-indexer\",\n            ],\n            \"title\": \"A\",\n            \"type\": \"story\",\n          },\n        ],\n        \"type\": \"stories\",\n      }\n    `);\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/__tests__/remove-mdx-stories.test.ts",
    "content": "import { join } from 'node:path';\n\nimport { describe, expect, it, vi } from 'vitest';\n\nimport { normalizeStoriesEntry } from 'storybook/internal/common';\nimport { type StoriesEntry } from 'storybook/internal/types';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport { glob as globOriginal } from 'glob';\n// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\n\nimport { removeMDXEntries } from '../remove-mdx-entries.ts';\n\nconst configDir = '/configDir/';\nconst workingDir = '/';\n\nvi.mock('glob', () => ({ glob: vi.fn() }));\nconst glob = vi.mocked(globOriginal);\n\nconst createList = (list: { entry: StoriesEntry; result: string[] }[]) => {\n  return list.reduce<Record<string, { result: string[]; entry: StoriesEntry }>>(\n    (acc, { entry, result }) => {\n      const { directory, files } = normalizeStoriesEntry(entry, {\n        configDir,\n        workingDir,\n      });\n      acc[slash(join('/', directory, files))] = { result, entry };\n      return acc;\n    },\n    {}\n  );\n};\n\nconst createGlobMock = (input: ReturnType<typeof createList>) => {\n  return async (k: string | string[]) => {\n    if (Array.isArray(k)) {\n      throw new Error('do not pass an array to glob during tests');\n    }\n    if (input[slash(k)]) {\n      return input[slash(k)]?.result;\n    }\n\n    throw new Error('can not find key in input');\n  };\n};\n\ndescribe('remove-mdx-stories', () => {\n  it('empty', async () => {\n    const list = createList([]);\n    glob.mockImplementation(createGlobMock(list));\n\n    await expect(() => removeMDXEntries(Object.keys(list), { configDir })).rejects\n      .toThrowErrorMatchingInlineSnapshot(`\n    [SB_CORE-COMMON_0004 (InvalidStoriesEntryError): Storybook could not index your stories.\nYour main configuration does not contain a 'stories' field, or it resolved to an empty array.\n\nPlease check your main configuration file and make sure it exports a 'stories' field that is not an empty array.\n\nMore info: https://storybook.js.org/docs/faq?ref=error#can-i-have-a-storybook-with-no-local-stories\n]\n`);\n  });\n\n  it('minimal', async () => {\n    const list = createList([{ entry: '*.js', result: [] }]);\n    glob.mockImplementation(createGlobMock(list));\n\n    const result = await removeMDXEntries(\n      Object.values(list).map((e) => e.entry),\n      { configDir }\n    );\n\n    expect(result).toMatchInlineSnapshot(`\n    [\n      {\n        \"directory\": \".\",\n        \"files\": \"*.js\",\n        \"titlePrefix\": \"\",\n      },\n    ]\n  `);\n  });\n\n  it('multiple', async () => {\n    const list = createList([\n      { entry: '*.ts', result: [] },\n      { entry: '*.js', result: [] },\n    ]);\n    glob.mockImplementation(createGlobMock(list));\n\n    const result = await removeMDXEntries(\n      Object.values(list).map((e) => e.entry),\n      { configDir }\n    );\n\n    expect(result).toMatchInlineSnapshot(`\n    [\n      {\n        \"directory\": \".\",\n        \"files\": \"*.ts\",\n        \"titlePrefix\": \"\",\n      },\n      {\n        \"directory\": \".\",\n        \"files\": \"*.js\",\n        \"titlePrefix\": \"\",\n      },\n    ]\n  `);\n  });\n\n  it('mdx but not matching any files', async () => {\n    const list = createList([\n      { entry: '*.mdx', result: [] },\n      { entry: '*.js', result: [] },\n    ]);\n    glob.mockImplementation(createGlobMock(list));\n\n    const result = await removeMDXEntries(\n      Object.values(list).map((e) => e.entry),\n      { configDir }\n    );\n\n    expect(result).toMatchInlineSnapshot(`\n    [\n      {\n        \"directory\": \".\",\n        \"files\": \"*.mdx\",\n        \"titlePrefix\": \"\",\n      },\n      {\n        \"directory\": \".\",\n        \"files\": \"*.js\",\n        \"titlePrefix\": \"\",\n      },\n    ]\n  `);\n  });\n\n  it('removes entries that only yield mdx files', async () => {\n    const list = createList([\n      { entry: '*.mdx', result: ['/configDir/my-file.mdx'] },\n      { entry: '*.js', result: [] },\n    ]);\n    glob.mockImplementation(createGlobMock(list));\n\n    const result = await removeMDXEntries(\n      Object.values(list).map((e) => e.entry),\n      { configDir }\n    );\n\n    expect(result).toMatchInlineSnapshot(`\n    [\n      {\n        \"directory\": \".\",\n        \"files\": \"*.js\",\n        \"titlePrefix\": \"\",\n      },\n    ]\n  `);\n  });\n\n  it('expands entries that only yield mixed files', async () => {\n    const list = createList([\n      { entry: '*.@(mdx|ts)', result: ['/configDir/my-file.mdx', '/configDir/my-file.ts'] },\n      { entry: '*.js', result: [] },\n    ]);\n    glob.mockImplementation(createGlobMock(list));\n\n    const result = await removeMDXEntries(\n      Object.values(list).map((e) => e.entry),\n      { configDir }\n    );\n\n    expect(result).toMatchInlineSnapshot(`\n    [\n      {\n        \"directory\": \".\",\n        \"files\": \"**/my-file.ts\",\n        \"titlePrefix\": \"\",\n      },\n      {\n        \"directory\": \".\",\n        \"files\": \"*.js\",\n        \"titlePrefix\": \"\",\n      },\n    ]\n  `);\n  });\n\n  it('passes titlePrefix', async () => {\n    const list = createList([\n      {\n        entry: { files: '*.@(mdx|ts)', directory: '.', titlePrefix: 'foo' },\n        result: ['/configDir/my-file.mdx', '/configDir/my-file.ts'],\n      },\n    ]);\n    glob.mockImplementation(createGlobMock(list));\n\n    const result = await removeMDXEntries(\n      Object.values(list).map((e) => e.entry),\n      { configDir }\n    );\n\n    expect(result).toMatchInlineSnapshot(`\n    [\n      {\n        \"directory\": \".\",\n        \"files\": \"**/my-file.ts\",\n        \"titlePrefix\": \"foo\",\n      },\n    ]\n  `);\n  });\n\n  it('expands to multiple entries', async () => {\n    const list = createList([\n      {\n        entry: { files: '*.@(mdx|ts)', directory: '.', titlePrefix: 'foo' },\n        result: [\n          '/configDir/my-file.mdx',\n          '/configDir/my-file1.ts',\n          '/configDir/my-file2.ts',\n          '/configDir/my-file3.ts',\n        ],\n      },\n    ]);\n    glob.mockImplementation(createGlobMock(list));\n\n    const result = await removeMDXEntries(\n      Object.values(list).map((e) => e.entry),\n      { configDir }\n    );\n\n    expect(result).toMatchInlineSnapshot(`\n    [\n      {\n        \"directory\": \".\",\n        \"files\": \"**/my-file1.ts\",\n        \"titlePrefix\": \"foo\",\n      },\n      {\n        \"directory\": \".\",\n        \"files\": \"**/my-file2.ts\",\n        \"titlePrefix\": \"foo\",\n      },\n      {\n        \"directory\": \".\",\n        \"files\": \"**/my-file3.ts\",\n        \"titlePrefix\": \"foo\",\n      },\n    ]\n  `);\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/__tests__/server-address.test.ts",
    "content": "import os, { type NetworkInterfaceInfoIPv4 } from 'node:os';\n\nimport { describe, expect, it, vi } from 'vitest';\n\nimport { getServerAddresses } from '../server-address.ts';\n\nconst mockedNetworkAddress: NetworkInterfaceInfoIPv4 = {\n  address: '192.168.0.5',\n  netmask: '255.255.255.0',\n  family: 'IPv4',\n  mac: '01:02:03:0a:0b:0c',\n  internal: false,\n  cidr: '192.168.0.5/24',\n};\n\nvi.mock(\n  'node:os',\n  async (importOriginal): Promise<typeof os & { default: typeof os }> => ({\n    ...(await importOriginal()),\n    // We have to mock both the default export and named exports here for whatever reason\n    ['default' as never]: {\n      networkInterfaces: vi.fn(() => ({\n        eth0: [mockedNetworkAddress],\n      })),\n      release: vi.fn(() => '10.0.26100'),\n    },\n    networkInterfaces: vi.fn(() => ({\n      eth0: [mockedNetworkAddress],\n    })),\n    release: vi.fn(() => '10.0.26100'),\n  })\n);\nconst mockedOs = vi.mocked(os);\n\ndescribe('getServerAddresses', () => {\n  it('builds addresses with a specified host', () => {\n    const { address, networkAddress } = getServerAddresses(9009, '192.168.89.89', 'http');\n    expect(address).toEqual('http://localhost:9009/');\n    expect(networkAddress).toEqual('http://192.168.89.89:9009/');\n  });\n\n  it('builds addresses with local IP when host is not specified', () => {\n    const { address, networkAddress } = getServerAddresses(9009, '', 'http');\n    expect(address).toEqual('http://localhost:9009/');\n    expect(networkAddress).toEqual(`http://${mockedNetworkAddress.address}:9009/`);\n  });\n\n  it('builds addresses with default address when host is not specified and external IPv4 is not found', () => {\n    mockedOs.networkInterfaces.mockReturnValueOnce({\n      eth0: [{ ...mockedNetworkAddress, internal: true }],\n    });\n    const { address, networkAddress } = getServerAddresses(9009, '', 'http');\n    expect(address).toEqual('http://localhost:9009/');\n    expect(networkAddress).toEqual('http://0.0.0.0:9009/');\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/__tests__/server-channel.test.ts",
    "content": "import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { Channel } from 'storybook/internal/channels';\n\nimport { EventEmitter } from 'events';\nimport type { Server } from 'http';\nimport { stringify } from 'telejson';\n\nimport { ServerChannelTransport, getServerChannel } from '../get-server-channel.ts';\n\nconst mockToken = 'test-token-123';\n\nconst options = {\n  localAddress: 'http://localhost:6006',\n  networkAddress: 'http://192.168.1.100:6006',\n  token: mockToken,\n} as any;\n\nconst webContainerOptions = {\n  ...options,\n  skipValidation: true,\n} as any;\n\ndescribe('getServerChannel', () => {\n  it('should return a channel', () => {\n    const server = { on: vi.fn() } as any as Server;\n    const result = getServerChannel(server, options);\n    expect(result).toBeInstanceOf(Channel);\n  });\n\n  it('should attach to the http server', () => {\n    const server = { on: vi.fn() } as any as Server;\n    getServerChannel(server, options);\n    expect(server.on).toHaveBeenCalledWith('upgrade', expect.any(Function));\n  });\n});\n\ndescribe('ServerChannelTransport', () => {\n  beforeEach(() => {\n    vi.spyOn(console, 'warn').mockImplementation(() => {});\n  });\n\n  afterEach(() => {\n    vi.restoreAllMocks();\n  });\n\n  it('parses simple JSON', () => {\n    const server = new EventEmitter() as any as Server;\n    const socket = new EventEmitter();\n    const transport = new ServerChannelTransport(server, options);\n    const handler = vi.fn();\n    transport.setHandler(handler);\n\n    // @ts-expect-error (an internal API)\n    transport.socket.emit('connection', socket);\n    socket.emit('message', '\"hello\"');\n\n    expect(handler).toHaveBeenCalledWith('hello');\n  });\n\n  it('parses object JSON', () => {\n    const server = new EventEmitter() as any as Server;\n    const socket = new EventEmitter();\n    const transport = new ServerChannelTransport(server, options);\n    const handler = vi.fn();\n    transport.setHandler(handler);\n\n    // @ts-expect-error (an internal API)\n    transport.socket.emit('connection', socket);\n    socket.emit('message', JSON.stringify({ type: 'hello' }));\n\n    expect(handler).toHaveBeenCalledWith({ type: 'hello' });\n  });\n\n  it('supports telejson cyclical data', () => {\n    const server = new EventEmitter() as any as Server;\n    const socket = new EventEmitter();\n    const transport = new ServerChannelTransport(server, options);\n    const handler = vi.fn();\n    transport.setHandler(handler);\n\n    // @ts-expect-error (an internal API)\n    transport.socket.emit('connection', socket);\n\n    const input: any = { a: 1 };\n    input.b = input;\n    socket.emit('message', stringify(input));\n\n    expect(handler.mock.calls[0][0]).toMatchInlineSnapshot(`\n      {\n        \"a\": 1,\n        \"b\": [Circular],\n      }\n    `);\n  });\n\n  it('rejects connections without token', () => {\n    const server = new EventEmitter() as any as Server;\n    const socket = new EventEmitter() as any;\n    socket.write = vi.fn();\n    socket.destroy = vi.fn();\n    const destroySpy = vi.spyOn(socket, 'destroy');\n    const transport = new ServerChannelTransport(server, options);\n\n    // Simulate upgrade request without token\n    const request = {\n      url: '/storybook-server-channel',\n      headers: {\n        origin: 'http://localhost:6006',\n      },\n    } as any;\n    const head = Buffer.from('');\n\n    server.listeners('upgrade')[0](request, socket, head);\n\n    expect(socket.write).toHaveBeenCalledWith(\n      'HTTP/1.1 403 Forbidden\\r\\nConnection: close\\r\\n\\r\\n'\n    );\n    expect(destroySpy).toHaveBeenCalled();\n  });\n\n  it('rejects connections with invalid token', () => {\n    const server = new EventEmitter() as any as Server;\n    const socket = new EventEmitter() as any;\n    socket.write = vi.fn();\n    socket.destroy = vi.fn();\n    const destroySpy = vi.spyOn(socket, 'destroy');\n    new ServerChannelTransport(server, options);\n\n    // Simulate upgrade request with wrong token\n    const request = {\n      url: '/storybook-server-channel?token=wrong-token',\n      headers: {\n        origin: 'http://localhost:6006',\n      },\n    } as any;\n    const head = Buffer.from('');\n\n    server.listeners('upgrade')[0](request, socket, head);\n\n    expect(socket.write).toHaveBeenCalledWith(\n      'HTTP/1.1 403 Forbidden\\r\\nConnection: close\\r\\n\\r\\n'\n    );\n    expect(destroySpy).toHaveBeenCalled();\n  });\n\n  it('accepts connections with valid token', () => {\n    const server = new EventEmitter() as any as Server;\n    const socket = new EventEmitter() as any;\n    socket.write = vi.fn();\n    socket.destroy = vi.fn();\n    const destroySpy = vi.spyOn(socket, 'destroy');\n    const handleUpgradeSpy = vi.fn();\n    const transport = new ServerChannelTransport(server, options);\n\n    // Mock handleUpgrade to track if it's called\n    // @ts-expect-error (accessing private property)\n    transport.socket.handleUpgrade = handleUpgradeSpy;\n\n    // Simulate upgrade request with correct token and valid origin\n    const request = {\n      url: `/storybook-server-channel?token=${mockToken}`,\n      headers: {\n        origin: 'http://localhost:6006',\n      },\n    } as any;\n    const head = Buffer.from('');\n\n    server.listeners('upgrade')[0](request, socket, head);\n\n    expect(socket.write).not.toHaveBeenCalled();\n    expect(destroySpy).not.toHaveBeenCalled();\n    expect(handleUpgradeSpy).toHaveBeenCalled();\n  });\n\n  it('rejects connections with invalid origin', () => {\n    const server = new EventEmitter() as any as Server;\n    const socket = new EventEmitter() as any;\n    socket.write = vi.fn();\n    socket.destroy = vi.fn();\n    const destroySpy = vi.spyOn(socket, 'destroy');\n    const transport = new ServerChannelTransport(server, options);\n\n    // Simulate upgrade request with invalid origin\n    const request = {\n      url: `/storybook-server-channel?token=${mockToken}`,\n      headers: {\n        origin: 'http://malicious-site.com',\n      },\n    } as any;\n    const head = Buffer.from('');\n\n    server.listeners('upgrade')[0](request, socket, head);\n\n    expect(socket.write).toHaveBeenCalledWith(\n      'HTTP/1.1 403 Forbidden\\r\\nConnection: close\\r\\n\\r\\n'\n    );\n    expect(destroySpy).toHaveBeenCalled();\n  });\n\n  it('rejects connections without origin header', () => {\n    const server = new EventEmitter() as any as Server;\n    const socket = new EventEmitter() as any;\n    socket.write = vi.fn();\n    socket.destroy = vi.fn();\n    const destroySpy = vi.spyOn(socket, 'destroy');\n    const transport = new ServerChannelTransport(server, options);\n\n    // Simulate upgrade request without origin header\n    const request = {\n      url: `/storybook-server-channel?token=${mockToken}`,\n      headers: {},\n    } as any;\n    const head = Buffer.from('');\n\n    server.listeners('upgrade')[0](request, socket, head);\n\n    expect(socket.write).toHaveBeenCalledWith(\n      'HTTP/1.1 403 Forbidden\\r\\nConnection: close\\r\\n\\r\\n'\n    );\n    expect(destroySpy).toHaveBeenCalled();\n  });\n\n  it('accepts connections with network address origin', () => {\n    const server = new EventEmitter() as any as Server;\n    const socket = new EventEmitter() as any;\n    socket.write = vi.fn();\n    socket.destroy = vi.fn();\n    const destroySpy = vi.spyOn(socket, 'destroy');\n    const handleUpgradeSpy = vi.fn();\n    const transport = new ServerChannelTransport(server, options);\n\n    // Mock handleUpgrade to track if it's called\n    // @ts-expect-error (accessing private property)\n    transport.socket.handleUpgrade = handleUpgradeSpy;\n\n    // Simulate upgrade request with network address origin\n    const request = {\n      url: `/storybook-server-channel?token=${mockToken}`,\n      headers: {\n        origin: 'http://192.168.1.100:6006',\n      },\n    } as any;\n    const head = Buffer.from('');\n\n    server.listeners('upgrade')[0](request, socket, head);\n\n    expect(socket.write).not.toHaveBeenCalled();\n    expect(destroySpy).not.toHaveBeenCalled();\n    expect(handleUpgradeSpy).toHaveBeenCalled();\n  });\n\n  it('accepts connections with 127.0.0.1 origin', () => {\n    const server = new EventEmitter() as any as Server;\n    const socket = new EventEmitter() as any;\n    socket.write = vi.fn();\n    socket.destroy = vi.fn();\n    const destroySpy = vi.spyOn(socket, 'destroy');\n    const handleUpgradeSpy = vi.fn();\n    const transport = new ServerChannelTransport(server, options);\n\n    // Mock handleUpgrade to track if it's called\n    // @ts-expect-error (accessing private property)\n    transport.socket.handleUpgrade = handleUpgradeSpy;\n\n    // Simulate upgrade request with 127.0.0.1 origin\n    const request = {\n      url: `/storybook-server-channel?token=${mockToken}`,\n      headers: {\n        origin: 'http://127.0.0.1:6006',\n      },\n    } as any;\n    const head = Buffer.from('');\n\n    server.listeners('upgrade')[0](request, socket, head);\n\n    expect(socket.write).not.toHaveBeenCalled();\n    expect(destroySpy).not.toHaveBeenCalled();\n    expect(handleUpgradeSpy).toHaveBeenCalled();\n  });\n\n  it('rejects connections to wrong path', () => {\n    const server = new EventEmitter() as any as Server;\n    const socket = new EventEmitter() as any;\n    socket.write = vi.fn();\n    socket.destroy = vi.fn();\n    const destroySpy = vi.spyOn(socket, 'destroy');\n    const handleUpgradeSpy = vi.fn();\n    const transport = new ServerChannelTransport(server, options);\n\n    // Mock handleUpgrade to track if it's called\n    // @ts-expect-error (accessing private property)\n    transport.socket.handleUpgrade = handleUpgradeSpy;\n\n    // Simulate upgrade request to wrong path\n    const request = {\n      url: `/wrong-path?token=${mockToken}`,\n      headers: {\n        origin: 'http://localhost:6006',\n      },\n    } as any;\n    const head = Buffer.from('');\n\n    server.listeners('upgrade')[0](request, socket, head);\n\n    // Should not call handleUpgrade for wrong path\n    expect(handleUpgradeSpy).not.toHaveBeenCalled();\n    // Socket should not be destroyed for wrong path (just ignored)\n    expect(destroySpy).not.toHaveBeenCalled();\n  });\n\n  it('accepts connections without token when validation is disabled', () => {\n    const server = new EventEmitter() as any as Server;\n    const socket = new EventEmitter() as any;\n    socket.write = vi.fn();\n    socket.destroy = vi.fn();\n    const destroySpy = vi.spyOn(socket, 'destroy');\n    const handleUpgradeSpy = vi.fn();\n    const transport = new ServerChannelTransport(server, webContainerOptions);\n\n    // Mock handleUpgrade to track if it's called\n    // @ts-expect-error (accessing private property)\n    transport.socket.handleUpgrade = handleUpgradeSpy;\n\n    const request = {\n      url: '/storybook-server-channel',\n      headers: {\n        origin: 'http://localhost:6006',\n      },\n    } as any;\n    const head = Buffer.from('');\n\n    server.listeners('upgrade')[0](request, socket, head);\n\n    expect(socket.write).not.toHaveBeenCalled();\n    expect(destroySpy).not.toHaveBeenCalled();\n    expect(handleUpgradeSpy).toHaveBeenCalled();\n  });\n\n  it('accepts connections with invalid origin when validation is disabled', () => {\n    const server = new EventEmitter() as any as Server;\n    const socket = new EventEmitter() as any;\n    socket.write = vi.fn();\n    socket.destroy = vi.fn();\n    const destroySpy = vi.spyOn(socket, 'destroy');\n    const handleUpgradeSpy = vi.fn();\n    const transport = new ServerChannelTransport(server, webContainerOptions);\n\n    // Mock handleUpgrade to track if it's called\n    // @ts-expect-error (accessing private property)\n    transport.socket.handleUpgrade = handleUpgradeSpy;\n\n    const request = {\n      url: '/storybook-server-channel?token=wrong-token',\n      headers: {\n        origin: 'http://malicious-site.com',\n      },\n    } as any;\n    const head = Buffer.from('');\n\n    server.listeners('upgrade')[0](request, socket, head);\n\n    expect(socket.write).not.toHaveBeenCalled();\n    expect(destroySpy).not.toHaveBeenCalled();\n    expect(handleUpgradeSpy).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/__tests__/server-statics.test.ts",
    "content": "import fs from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { onlyWindows, skipWindows } from '../../../../../vitest.helpers.ts';\nimport { parseStaticDir, prepareNestedSvg } from '../server-statics.ts';\n\nvi.mock('node:fs');\nconst existsSyncMock = vi.mocked(fs.existsSync);\nconst statSyncMock = vi.mocked(fs.statSync);\n\ndescribe('prepareNestedSvg', () => {\n  it('should remove xml declaration and add preserveAspectRatio', () => {\n    const fixedSvg = prepareNestedSvg(`\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<svg><g /></svg>\n    `);\n    expect(fixedSvg).toMatchInlineSnapshot(\n      `\"<svg preserveAspectRatio=\"xMidYMid meet\"><g /></svg>\"`\n    );\n  });\n\n  it('should update width and height', () => {\n    const fixedSvg = prepareNestedSvg(`\n<svg width=\"64px\" height=\"64px\" viewBox=\"0 0 64 64\" fill=\"none\"><g /></svg>\n    `);\n    expect(fixedSvg).toMatchInlineSnapshot(\n      `\"<svg width=\"32px\" height=\"32px\" viewBox=\"0 0 64 64\" fill=\"none\" preserveAspectRatio=\"xMidYMid meet\"><g /></svg>\"`\n    );\n  });\n\n  it('should add viewBox if none is present', () => {\n    const fixedSvg = prepareNestedSvg(`\n<svg width=\"64px\" height=\"64px\" fill=\"none\"><g /></svg>\n    `);\n    expect(fixedSvg).toMatchInlineSnapshot(\n      `\"<svg width=\"32px\" height=\"32px\" fill=\"none\" viewBox=\"0 0 64 64\" preserveAspectRatio=\"xMidYMid meet\"><g /></svg>\"`\n    );\n  });\n\n  it('handles a full svg', () => {\n    const fixedSvg = prepareNestedSvg(`\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"64\" height=\"64\" fill=\"none\">\n  <circle cx=\"23\" cy=\"35\" r=\"8\" fill=\"#fff\" />\n  <circle cx=\"41\" cy=\"35\" r=\"8\" fill=\"#fff\" />\n  <path fill=\"#9FA628\"\n    d=\"M62.6 5.8c-2.8 0-4.4-1.6-4.4-4.4 0-.8-.6-1.4-1.4-1.4-.8 0-1.4.6-1.4 1.4 0 1.6.4 3 1 4.2l-3.8 4C49.6 7.2 45.8 6 40.8 6H23.4c-5 0-8.8 1.2-11.8 3.6L7.8 5.8c.8-1.2 1-2.6 1-4.2C8.8.6 8 0 7.2 0S5.8.6 5.8 1.4c0 2.8-1.6 4.4-4.4 4.4-.8 0-1.4.6-1.4 1.4 0 .8.6 1.4 1.4 1.4 1.6 0 3-.4 4.2-1l4 3.8C7.2 14.4 6 18.2 6 23.2V48c0 5.6 4.4 10 10 10h32c5.6 0 10-4.4 10-10V23.2c0-5-1.2-8.8-3.6-11.8l3.8-3.8c1.2.8 2.6 1 4.2 1 .8 0 1.4-.6 1.4-1.4 0-.8-.4-1.4-1.2-1.4zM23 42c-3.8 0-7-3.2-7-7s3.2-7 7-7 7 3.2 7 7-3.2 7-7 7zm18 0c-3.8 0-7-3.2-7-7s3.2-7 7-7 7 3.2 7 7-3.2 7-7 7z\" />\n  <circle cx=\"23\" cy=\"35\" r=\"4\" fill=\"#BF6C35\" />\n  <circle cx=\"41\" cy=\"35\" r=\"4\" fill=\"#BF6C35\" />\n</svg>\n    `);\n    expect(fixedSvg).toMatchInlineSnapshot(`\n      \"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32px\" height=\"32px\" fill=\"none\" viewBox=\"0 0 64 64\" preserveAspectRatio=\"xMidYMid meet\">\n        <circle cx=\"23\" cy=\"35\" r=\"8\" fill=\"#fff\" />\n        <circle cx=\"41\" cy=\"35\" r=\"8\" fill=\"#fff\" />\n        <path fill=\"#9FA628\"\n          d=\"M62.6 5.8c-2.8 0-4.4-1.6-4.4-4.4 0-.8-.6-1.4-1.4-1.4-.8 0-1.4.6-1.4 1.4 0 1.6.4 3 1 4.2l-3.8 4C49.6 7.2 45.8 6 40.8 6H23.4c-5 0-8.8 1.2-11.8 3.6L7.8 5.8c.8-1.2 1-2.6 1-4.2C8.8.6 8 0 7.2 0S5.8.6 5.8 1.4c0 2.8-1.6 4.4-4.4 4.4-.8 0-1.4.6-1.4 1.4 0 .8.6 1.4 1.4 1.4 1.6 0 3-.4 4.2-1l4 3.8C7.2 14.4 6 18.2 6 23.2V48c0 5.6 4.4 10 10 10h32c5.6 0 10-4.4 10-10V23.2c0-5-1.2-8.8-3.6-11.8l3.8-3.8c1.2.8 2.6 1 4.2 1 .8 0 1.4-.6 1.4-1.4 0-.8-.4-1.4-1.2-1.4zM23 42c-3.8 0-7-3.2-7-7s3.2-7 7-7 7 3.2 7 7-3.2 7-7 7zm18 0c-3.8 0-7-3.2-7-7s3.2-7 7-7 7 3.2 7 7-3.2 7-7 7z\" />\n        <circle cx=\"23\" cy=\"35\" r=\"4\" fill=\"#BF6C35\" />\n        <circle cx=\"41\" cy=\"35\" r=\"4\" fill=\"#BF6C35\" />\n      </svg>\"\n    `);\n  });\n});\n\ndescribe('parseStaticDir', () => {\n  beforeEach(() => {\n    existsSyncMock.mockReturnValue(true);\n    statSyncMock.mockReturnValue({ isFile: () => false } as fs.Stats);\n  });\n\n  it('returns the static dir/path and default target', async () => {\n    expect(parseStaticDir('public')).toEqual({\n      staticDir: './public',\n      staticPath: resolve('public'),\n      targetDir: './',\n      targetEndpoint: '/',\n    });\n\n    expect(parseStaticDir('foo/bar')).toEqual({\n      staticDir: './foo/bar',\n      staticPath: resolve('foo/bar'),\n      targetDir: './',\n      targetEndpoint: '/',\n    });\n  });\n\n  it('returns the static dir/path and custom target', async () => {\n    expect(parseStaticDir('public:/custom-endpoint')).toEqual({\n      staticDir: './public',\n      staticPath: resolve('public'),\n      targetDir: './custom-endpoint',\n      targetEndpoint: '/custom-endpoint',\n    });\n\n    expect(parseStaticDir('foo/bar:/custom-endpoint')).toEqual({\n      staticDir: './foo/bar',\n      staticPath: resolve('foo/bar'),\n      targetDir: './custom-endpoint',\n      targetEndpoint: '/custom-endpoint',\n    });\n  });\n\n  it('pins relative endpoint at root', async () => {\n    const normal = parseStaticDir('public:relative-endpoint');\n    expect(normal.targetEndpoint).toBe('/relative-endpoint');\n\n    const windows = parseStaticDir('C:\\\\public:relative-endpoint');\n    expect(windows.targetEndpoint).toBe('/relative-endpoint');\n  });\n\n  it('checks that the path exists', async () => {\n    existsSyncMock.mockReturnValueOnce(false);\n    expect(() => parseStaticDir('nonexistent')).toThrow(resolve('nonexistent'));\n  });\n\n  skipWindows(() => {\n    it('supports absolute file paths - posix', async () => {\n      expect(parseStaticDir('/foo/bar')).toEqual({\n        staticDir: '/foo/bar',\n        staticPath: '/foo/bar',\n        targetDir: './',\n        targetEndpoint: '/',\n      });\n    });\n\n    it('supports absolute file paths with custom endpoint - posix', async () => {\n      expect(parseStaticDir('/foo/bar:/custom-endpoint')).toEqual({\n        staticDir: '/foo/bar',\n        staticPath: '/foo/bar',\n        targetDir: './custom-endpoint',\n        targetEndpoint: '/custom-endpoint',\n      });\n    });\n  });\n\n  onlyWindows(() => {\n    it('supports absolute file paths - windows', async () => {\n      expect(parseStaticDir('C:\\\\foo\\\\bar')).toEqual({\n        staticDir: resolve('C:\\\\foo\\\\bar'),\n        staticPath: resolve('C:\\\\foo\\\\bar'),\n        targetDir: './',\n        targetEndpoint: '/',\n      });\n    });\n\n    it('supports absolute file paths with custom endpoint - windows', async () => {\n      expect(parseStaticDir('C:\\\\foo\\\\bar:/custom-endpoint')).toEqual({\n        staticDir: expect.any(String), // can't test this properly on unix\n        staticPath: resolve('C:\\\\foo\\\\bar'),\n        targetDir: './custom-endpoint',\n        targetEndpoint: '/custom-endpoint',\n      });\n\n      expect(parseStaticDir('C:\\\\foo\\\\bar:\\\\custom-endpoint')).toEqual({\n        staticDir: expect.any(String), // can't test this properly on unix\n        staticPath: resolve('C:\\\\foo\\\\bar'),\n        targetDir: './custom-endpoint',\n        targetEndpoint: '/custom-endpoint',\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/__tests__/validate-token.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { isValidToken } from '../validate-token.ts';\n\ndescribe('isValidToken', () => {\n  const validToken = 'test-token-123';\n\n  it('returns true for matching tokens', () => {\n    expect(isValidToken(validToken, validToken)).toBe(true);\n  });\n\n  it('returns false for non-matching tokens', () => {\n    expect(isValidToken('wrong-token', validToken)).toBe(false);\n  });\n\n  it('returns false for null token', () => {\n    expect(isValidToken(null, validToken)).toBe(false);\n  });\n\n  it('returns false for undefined token', () => {\n    expect(isValidToken(undefined as any, validToken)).toBe(false);\n  });\n\n  it('returns false for empty token', () => {\n    expect(isValidToken('', validToken)).toBe(false);\n  });\n\n  it('returns false when expected token is null', () => {\n    expect(isValidToken(validToken, null as any)).toBe(false);\n  });\n\n  it('returns false when expected token is undefined', () => {\n    expect(isValidToken(validToken, undefined as any)).toBe(false);\n  });\n\n  it('returns false for empty expected token', () => {\n    expect(isValidToken(validToken, '')).toBe(false);\n  });\n\n  it('returns false for tokens with different lengths', () => {\n    expect(isValidToken('short', 'much-longer-token')).toBe(false);\n  });\n\n  it('handles special characters in tokens', () => {\n    const specialToken = 'token-with-special-chars-!@#$%^&*()';\n    expect(isValidToken(specialToken, specialToken)).toBe(true);\n    expect(isValidToken(specialToken, 'different-token')).toBe(false);\n  });\n\n  it('handles unicode characters in tokens', () => {\n    const unicodeToken = 'token-with-unicode-🚀-测试';\n    expect(isValidToken(unicodeToken, unicodeToken)).toBe(true);\n    expect(isValidToken(unicodeToken, 'different-token')).toBe(false);\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/autoName.ts",
    "content": "import { basename } from 'node:path';\n\nimport type { Path } from 'storybook/internal/types';\n\n/**\n * Calculate a name to use for a docs entry if not specified. The rule is:\n *\n * 1. If the name of the MDX file is the \"same\" as the CSF file (e.g. Button.mdx, Button.stories.jsx)\n *    use the default name.\n * 2. Else use the (ext-less) name of the MDX file\n *\n * @param mdxImportPath ImportPath of the MDX file with of={}\n * @param csfImportPath ImportPath of the of CSF file\n */\nexport function autoName(mdxImportPath: Path, csfImportPath: Path, defaultName: string) {\n  const mdxBasename = basename(mdxImportPath);\n  const csfBasename = basename(csfImportPath);\n\n  const [mdxFilename] = mdxBasename.split('.');\n  const [csfFilename] = csfBasename.split('.');\n\n  if (mdxFilename === csfFilename) {\n    return defaultName;\n  }\n\n  return mdxFilename;\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/build-or-throw.ts",
    "content": "import { NoMatchingExportError } from 'storybook/internal/server-errors';\n\nexport async function buildOrThrow<T>(callback: () => Promise<T>): Promise<T> {\n  try {\n    return await callback();\n  } catch (err: any) {\n    const builderErrors = err.errors as { text: string }[];\n    if (builderErrors) {\n      const inconsistentVersionsError = builderErrors.find((er) =>\n        er.text?.includes('No matching export')\n      );\n\n      if (inconsistentVersionsError) {\n        throw new NoMatchingExportError(err);\n      }\n    }\n\n    throw err;\n  }\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/checklist.ts",
    "content": "import { createFileSystemCache, resolvePathInStorybookCache } from 'storybook/internal/common';\nimport { experimental_UniversalStore } from 'storybook/internal/core-server';\nimport { logger } from 'storybook/internal/node-logger';\nimport { telemetry } from 'storybook/internal/telemetry';\n\nimport { throttle } from 'es-toolkit/function';\nimport { toMerged } from 'es-toolkit/object';\n\nimport { globalSettings } from '../../cli/index.ts';\nimport {\n  type ChecklistState,\n  type StoreEvent,\n  type StoreState,\n  UNIVERSAL_CHECKLIST_STORE_OPTIONS,\n} from '../../shared/checklist-store/index.ts';\n\nexport async function initializeChecklist() {\n  try {\n    const store = experimental_UniversalStore.create<StoreState, StoreEvent>({\n      ...UNIVERSAL_CHECKLIST_STORE_OPTIONS,\n      leader: true,\n    });\n\n    const cache = createFileSystemCache({\n      basePath: resolvePathInStorybookCache('checklist'),\n      ns: 'storybook',\n    });\n\n    const [[userState, saveUserState], [projectState, saveProjectState]] = await Promise.all([\n      globalSettings().then((settings) => {\n        const save = throttle(() => settings.save(), 1000);\n        const state = {\n          items: settings.value.checklist?.items ?? {},\n          widget: settings.value.checklist?.widget ?? {},\n        };\n        const setState = ({\n          items = state.items,\n          widget = state.widget,\n        }: {\n          items?: typeof state.items;\n          widget?: typeof state.widget;\n        }) => {\n          settings.value.checklist = { items, widget };\n          save();\n        };\n        return [state, setState] as const;\n      }),\n\n      cache.get<Pick<ChecklistState, 'items'>>('state').then((cachedState) => {\n        const state = { items: cachedState?.items ?? {} };\n        const setState = ({ items }: Pick<ChecklistState, 'items'>) =>\n          cache.set('state', { items });\n        return [state, setState] as const;\n      }),\n    ]);\n\n    store.setState(\n      (value) =>\n        ({\n          ...toMerged(value, toMerged(userState, projectState)),\n          loaded: true,\n        }) satisfies StoreState\n    );\n\n    store.onStateChange((state: StoreState, previousState: StoreState) => {\n      const entries = Object.entries(state.items);\n\n      // Split values into project-local (done) and user-local (accepted, skipped) persistence\n      const projectValues: Partial<StoreState['items']> = {};\n      const userValues: Partial<StoreState['items']> = {};\n      entries.forEach(([id, { status, mutedAt }]) => {\n        if (status === 'done') {\n          projectValues[id as keyof StoreState['items']] = { status };\n        } else if (status === 'accepted' || status === 'skipped') {\n          userValues[id as keyof StoreState['items']] = { status };\n        }\n        if (mutedAt) {\n          userValues[id as keyof StoreState['items']] = {\n            ...userValues[id as keyof StoreState['items']],\n            mutedAt,\n          };\n        }\n      });\n      saveProjectState({ items: projectValues as StoreState['items'] });\n      saveUserState({ items: userValues, widget: state.widget });\n\n      // Skip telemetry when loading from persistence (first transition to loaded: true)\n      if (!previousState.loaded) {\n        return;\n      }\n\n      // Gather items that have changed state\n      const { mutedItems, statusItems } = entries.reduce(\n        (acc, [item, { mutedAt, status }]) => {\n          const prev = previousState.items[item as keyof typeof state.items];\n          if (mutedAt !== prev?.mutedAt) {\n            acc.mutedItems.push(item);\n          }\n          if (status !== prev?.status) {\n            acc.statusItems.push(item);\n          }\n          return acc;\n        },\n        { mutedItems: [] as string[], statusItems: [] as string[] }\n      );\n      if (mutedItems.length > 0) {\n        telemetry('onboarding-checklist-muted', {\n          items: mutedItems,\n          completedItems: entries.reduce<string[]>((acc, [id, { status }]) => {\n            return status === 'done' || status === 'accepted' ? acc.concat([id]) : acc;\n          }, []),\n          skippedItems: entries.reduce<string[]>((acc, [id, { status }]) => {\n            return status === 'skipped' ? acc.concat([id]) : acc;\n          }, []),\n        });\n      }\n      statusItems.forEach((item) => {\n        const { status } = state.items[item as keyof typeof state.items];\n        telemetry('onboarding-checklist-status', { item, status });\n      });\n    });\n  } catch (err) {\n    logger.error('Failed to initialize checklist');\n    logger.error(err);\n  }\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/constants.ts",
    "content": "import { join } from 'pathe';\n\nimport { resolvePackageDir } from '../../shared/utils/module.ts';\n\nexport const DEBOUNCE = 100;\n\nexport const defaultStaticDirs = [\n  {\n    from: join(resolvePackageDir('storybook'), 'assets/browser'),\n    to: '/sb-common-assets',\n  },\n];\n\nexport const defaultFavicon = join(resolvePackageDir('storybook'), 'assets/browser/favicon.svg');\n"
  },
  {
    "path": "code/core/src/core-server/utils/copy-all-static-files.ts",
    "content": "import { cp } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\n\nimport { getDirectoryFromWorkingDir } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport picocolors from 'picocolors';\n\nimport { parseStaticDir } from './server-statics.ts';\n\nexport async function copyAllStaticFiles(staticDirs: any[] | undefined, outputDir: string) {\n  if (staticDirs && staticDirs.length > 0) {\n    await Promise.all(\n      staticDirs.map(async (dir) => {\n        try {\n          const { staticDir, staticPath, targetDir } = parseStaticDir(dir);\n          const targetPath = join(outputDir, targetDir);\n\n          // we copy prebuild static files from node_modules/storybook/internal/manager & preview\n          if (!staticDir.includes('node_modules')) {\n            const from = picocolors.cyan(print(staticDir));\n            const to = picocolors.cyan(print(targetDir));\n            logger.info(`Copying static files: ${from} => ${to}`);\n          }\n\n          // Storybook's own files should not be overwritten, so we skip such files if we find them\n          const skipPaths = ['index.html', 'iframe.html'].map((f) => join(outputDir, f));\n          await cp(staticPath, targetPath, {\n            dereference: true,\n            preserveTimestamps: true,\n            filter: (_, dest) => !skipPaths.includes(dest),\n            recursive: true,\n          });\n        } catch (e) {\n          if (e instanceof Error) {\n            logger.error(e.message);\n          }\n          process.exit(-1);\n        }\n      })\n    );\n  }\n}\n\nexport async function copyAllStaticFilesRelativeToMain(\n  staticDirs: any[] | undefined,\n  outputDir: string,\n  configDir: string\n) {\n  const workingDir = process.cwd();\n\n  return staticDirs?.reduce(async (acc, dir) => {\n    await acc;\n\n    const staticDirAndTarget = typeof dir === 'string' ? dir : `${dir.from}:${dir.to}`;\n    const { staticPath: from, targetEndpoint: to } = parseStaticDir(\n      getDirectoryFromWorkingDir({\n        configDir,\n        workingDir,\n        directory: staticDirAndTarget,\n      })\n    );\n\n    const targetPath = join(outputDir, to);\n    const skipPaths = ['index.html', 'iframe.html'].map((f) => join(outputDir, f));\n    if (!from.includes('node_modules')) {\n      logger.info(\n        `Copying static files: ${picocolors.cyan(print(from))} at ${picocolors.cyan(print(targetPath))}`\n      );\n    }\n    await cp(from, targetPath, {\n      dereference: true,\n      preserveTimestamps: true,\n      filter: (_, dest) => !skipPaths.includes(dest),\n      recursive: true,\n    });\n  }, Promise.resolve());\n}\nfunction print(p: string): string {\n  return relative(process.cwd(), p);\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/doTelemetry.ts",
    "content": "import { getPrecedingUpgrade, telemetry } from 'storybook/internal/telemetry';\nimport type { CoreConfig, Options } from 'storybook/internal/types';\n\nimport type { Polka } from 'polka';\nimport invariant from 'tiny-invariant';\n\nimport { sendTelemetryError } from '../withTelemetry.ts';\nimport type { StoryIndexGenerator } from './StoryIndexGenerator.ts';\nimport { summarizeIndex } from './summarizeIndex.ts';\nimport { versionStatus } from './versionStatus.ts';\n\nexport async function doTelemetry(\n  app: Polka,\n  core: CoreConfig,\n  storyIndexGeneratorPromise: Promise<StoryIndexGenerator>,\n  options: Options\n) {\n  if (!core?.disableTelemetry) {\n    const generator = await storyIndexGeneratorPromise;\n    let indexAndStats;\n    try {\n      indexAndStats = await generator?.getIndexAndStats();\n    } catch (err) {\n      // If we fail to get the index, treat it as a recoverable error, but send it up to telemetry\n      // as if we crashed. In the future we will revisit this to send a distinct error\n      if (!(err instanceof Error)) {\n        throw new Error('encountered a non-recoverable error');\n      }\n      sendTelemetryError(err, 'dev', {\n        cliOptions: options,\n        presetOptions: {\n          ...options,\n          corePresets: [],\n          overridePresets: [],\n        },\n      });\n      return;\n    }\n    const { versionCheck, versionUpdates } = options;\n    invariant(\n      !versionUpdates || (versionUpdates && versionCheck),\n      'versionCheck should be defined when versionUpdates is true'\n    );\n    const payload = {\n      precedingUpgrade: await getPrecedingUpgrade(),\n    };\n    if (indexAndStats) {\n      Object.assign(payload, {\n        versionStatus: versionUpdates && versionCheck ? versionStatus(versionCheck) : 'disabled',\n        storyIndex: summarizeIndex(indexAndStats.storyIndex),\n        storyStats: indexAndStats.stats,\n      });\n    }\n    telemetry('dev', payload, { configDir: options.configDir });\n  }\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/generate-story.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { writeFile } from 'node:fs/promises';\nimport { relative } from 'node:path';\n\nimport { getProjectRoot, getStoryId } from 'storybook/internal/common';\nimport type { CreateNewStoryRequestPayload } from 'storybook/internal/core-events';\nimport type { Options } from 'storybook/internal/types';\n\nimport { getNewStoryFile } from './get-new-story-file.ts';\n\nexport interface GenerateStoryResult {\n  success: boolean;\n  storyId?: string;\n  kind?: string;\n  storyFilePath?: string;\n  exportedStoryName?: string;\n  error?: string;\n  errorType?: 'STORY_FILE_EXISTS' | 'UNKNOWN';\n}\n\nexport interface GenerateStoryOptions {\n  /**\n   * If true, checks if the file exists and returns an error without writing. If false, writes the\n   * file even if it exists (overwrites).\n   *\n   * @default true\n   */\n  checkFileExists?: boolean;\n}\n\n/**\n * Generates and writes a new story file for a component.\n *\n * This function orchestrates the entire story file creation process:\n *\n * 1. Generates the story file path and content based on the component\n * 2. Optionally checks if the file already exists\n * 3. Writes the story file to disk\n * 4. Returns metadata about the created story\n *\n * @example\n *\n * ```ts\n * const result = await generateStoryFile(\n *   {\n *     componentFilePath: 'src/components/Button.tsx',\n *     componentExportName: 'Button',\n *     componentIsDefaultExport: true,\n *     componentExportCount: 1,\n *   },\n *   options\n * );\n *\n * if (result.success) {\n *   console.log(`Story created at ${result.storyFilePath}`);\n * }\n * ```\n *\n * @param payload - The component information for which to create a story\n * @param options - Storybook options for configuration\n * @param generateOptions - Additional options for story generation behavior\n * @returns A promise that resolves to the result of the story generation\n */\nexport async function generateStoryFile(\n  payload: CreateNewStoryRequestPayload,\n  options: Options,\n  generateOptions: GenerateStoryOptions = {}\n): Promise<GenerateStoryResult> {\n  const { checkFileExists = true } = generateOptions;\n\n  try {\n    const { storyFilePath, exportedStoryName, storyFileContent } = await getNewStoryFile(\n      payload,\n      options\n    );\n\n    const relativeStoryFilePath = relative(getProjectRoot(), storyFilePath);\n\n    const { storyId, kind } = await getStoryId({ storyFilePath, exportedStoryName }, options);\n\n    if (checkFileExists && existsSync(storyFilePath)) {\n      return {\n        success: false,\n        kind,\n        storyFilePath: relativeStoryFilePath,\n        error: `A story file already exists at ${relativeStoryFilePath}`,\n        errorType: 'STORY_FILE_EXISTS',\n      };\n    }\n\n    await writeFile(storyFilePath, storyFileContent, 'utf-8');\n\n    return {\n      success: true,\n      storyId,\n      kind,\n      storyFilePath: relativeStoryFilePath,\n      exportedStoryName,\n    };\n  } catch (e: any) {\n    return {\n      success: false,\n      error: e?.message || 'Unknown error occurred',\n      errorType: 'UNKNOWN',\n    };\n  }\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/get-builders.ts",
    "content": "import { MissingBuilderError } from 'storybook/internal/server-errors';\nimport type { Builder, Options } from 'storybook/internal/types';\n\nimport { importModule } from '../../shared/utils/module.ts';\n\nexport async function getManagerBuilder(): Promise<Builder<unknown>> {\n  return await import('../../builder-manager/index.ts');\n}\n\nexport async function getPreviewBuilder(resolvedPreviewBuilder: string): Promise<Builder<unknown>> {\n  return await importModule(resolvedPreviewBuilder);\n}\n\nexport async function getBuilders({ presets }: Options): Promise<Builder<unknown>[]> {\n  const { builder } = await presets.apply('core', {});\n  if (!builder) {\n    throw new MissingBuilderError();\n  }\n\n  const resolvedPreviewBuilder = typeof builder === 'string' ? builder : builder.name;\n\n  return Promise.all([getPreviewBuilder(resolvedPreviewBuilder), getManagerBuilder()]);\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/get-caching-middleware.ts",
    "content": "import type { Middleware } from '../../types/index.ts';\n\nexport function getCachingMiddleware(): Middleware {\n  return (req, res, next) => {\n    res.setHeader('Cache-Control', 'no-store');\n    next();\n  };\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/get-component-variable-name.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { getComponentVariableName } from './get-component-variable-name.ts';\n\ndescribe('get-variable-name', () => {\n  it('should return a valid variable name for a given string', async () => {\n    await expect(getComponentVariableName('foo-bar')).resolves.toBe('FooBar');\n    await expect(getComponentVariableName('foo bar')).resolves.toBe('FooBar');\n    await expect(getComponentVariableName('0-foo-bar')).resolves.toBe('FooBar');\n    await expect(getComponentVariableName('*Foo-bar-$')).resolves.toBe('FooBar$');\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/get-component-variable-name.ts",
    "content": "/**\n * Get a valid variable name for a component.\n *\n * @param name The name of the component.\n * @returns A valid variable name.\n */\nexport const getComponentVariableName = async (name: string) => {\n  const camelCase = await import('camelcase');\n\n  const camelCased = camelCase.default(name.replace(/^[^a-zA-Z_$]*/, ''), { pascalCase: true });\n  const sanitized = camelCased.replace(/[^a-zA-Z_$]+/, '');\n  return sanitized;\n};\n"
  },
  {
    "path": "code/core/src/core-server/utils/get-dummy-args-from-argtypes.test.ts",
    "content": "import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { SBType } from '../../types/index.ts';\nimport {\n  generateDummyArgsFromArgTypes,\n  generateDummyValueFromSBType,\n} from './get-dummy-args-from-argtypes.ts';\n\ndescribe('new-story-docgen', () => {\n  const MOCK_DATE = new Date('2025-01-01T00:00:00.000Z');\n  beforeEach(() => {\n    vi.setSystemTime(MOCK_DATE);\n  });\n\n  afterEach(() => {\n    vi.useRealTimers();\n  });\n\n  describe('generateDummyValueFromSBType', () => {\n    it('generates primitives', () => {\n      expect(generateDummyValueFromSBType({ name: 'boolean' })).toBe(true);\n      expect(generateDummyValueFromSBType({ name: 'number' })).toBe(0);\n      expect(generateDummyValueFromSBType({ name: 'other', value: 'void' })).toBeUndefined();\n      expect(generateDummyValueFromSBType({ name: 'other', value: 'null' })).toBeNull();\n      expect(generateDummyValueFromSBType({ name: 'other', value: 'any' })).toBeNull();\n      expect(generateDummyValueFromSBType({ name: 'other', value: 'unknown' })).toBeNull();\n    });\n\n    it('generates date', () => {\n      expect(generateDummyValueFromSBType({ name: 'date' })).toEqual(MOCK_DATE);\n    });\n\n    it('generates string values using token heuristics', () => {\n      expect(generateDummyValueFromSBType({ name: 'string' }, 'backgroundColor')).toBe('#ff4785');\n      expect(generateDummyValueFromSBType({ name: 'string' }, 'createdAt')).toBe(\n        MOCK_DATE.toLocaleDateString()\n      );\n      expect(generateDummyValueFromSBType({ name: 'string' }, 'imageUrl')).toBe(\n        'https://placehold.co/600x400?text=Storybook'\n      );\n      expect(generateDummyValueFromSBType({ name: 'string' }, 'websiteUrl')).toBe(\n        'https://example.com'\n      );\n      expect(generateDummyValueFromSBType({ name: 'string' }, 'email')).toBe(\n        'storybook@example.com'\n      );\n      expect(generateDummyValueFromSBType({ name: 'string' }, 'phoneNumber')).toBe('1234567890');\n    });\n\n    it('avoids image URL for image metadata props', () => {\n      // image + width is penalized, so we fall back to the name.\n      expect(generateDummyValueFromSBType({ name: 'string' }, 'imageWidth')).toBe('imageWidth');\n    });\n\n    it('generates node values using prop name', () => {\n      expect(generateDummyValueFromSBType({ name: 'node', renderer: 'react' }, 'children')).toBe(\n        'children'\n      );\n      expect(generateDummyValueFromSBType({ name: 'node', renderer: 'react' })).toBe('Hello world');\n    });\n\n    it('generates functions as placeholders', () => {\n      expect(generateDummyValueFromSBType({ name: 'function' })).toBe(\n        '[[STORYBOOK_FN_PLACEHOLDER]]'\n      );\n    });\n\n    it('generates object values recursively', () => {\n      const type = {\n        name: 'object' as const,\n        value: {\n          count: { name: 'number' as const },\n          onClick: { name: 'function' as const },\n        },\n      };\n\n      expect(generateDummyValueFromSBType(type)).toEqual({\n        count: 0,\n        onClick: '[[STORYBOOK_FN_PLACEHOLDER]]',\n      });\n    });\n\n    it('generates union values, preferring literals', () => {\n      expect(\n        generateDummyValueFromSBType({\n          name: 'union',\n          value: [{ name: 'literal', value: \"'foo'\" }, { name: 'string' }],\n        })\n      ).toBe('foo');\n\n      expect(\n        generateDummyValueFromSBType({\n          name: 'union',\n          value: [{ name: 'literal', value: '\"bar\"' }, { name: 'string' }],\n        })\n      ).toBe('bar');\n\n      expect(generateDummyValueFromSBType({ name: 'union', value: [] })).toBe('');\n    });\n\n    it('generates array values', () => {\n      expect(\n        generateDummyValueFromSBType({\n          name: 'array',\n          value: [{ name: 'other', value: 'X' }] as unknown as SBType,\n        })\n      ).toEqual([]);\n      expect(\n        generateDummyValueFromSBType({\n          name: 'array',\n          value: [{ name: 'number' }] as unknown as SBType,\n        })\n      ).toEqual([0]);\n    });\n\n    it('generates tuple values', () => {\n      expect(\n        generateDummyValueFromSBType({\n          name: 'tuple',\n          value: [{ name: 'string' }, { name: 'number' }],\n        })\n      ).toEqual(['', 0]);\n    });\n\n    it('generates other values conservatively', () => {\n      expect(generateDummyValueFromSBType({ name: 'other', value: 'ReactMouseEvent' })).toBe(\n        '[[STORYBOOK_FN_PLACEHOLDER]]'\n      );\n      expect(generateDummyValueFromSBType({ name: 'other', value: 'Foo' })).toBeNull();\n      expect(generateDummyValueFromSBType({ name: 'other', value: 'null' })).toBeNull();\n    });\n  });\n\n  describe('generateDummyArgsFromArgTypes', () => {\n    it('skips URL generation when skipUrlGeneration option is true', () => {\n      const argTypes = {\n        imageUrl: {\n          type: { name: 'string' },\n        },\n        websiteUrl: {\n          type: { name: 'string' },\n        },\n      } as any;\n\n      // With skipUrlGeneration: false (default behavior)\n      const resultWithUrls = generateDummyArgsFromArgTypes(argTypes, { skipUrlGeneration: false });\n      expect(resultWithUrls.optional.imageUrl).toBe('https://placehold.co/600x400?text=Storybook');\n      expect(resultWithUrls.optional.websiteUrl).toBe('https://example.com');\n\n      // With skipUrlGeneration: true\n      const resultWithoutUrls = generateDummyArgsFromArgTypes(argTypes, {\n        skipUrlGeneration: true,\n      });\n      expect(resultWithoutUrls.optional.imageUrl).toBe('imageUrl');\n      expect(resultWithoutUrls.optional.websiteUrl).toBe('websiteUrl');\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/get-dummy-args-from-argtypes.ts",
    "content": "import type { ArgTypes, SBType } from 'storybook/internal/csf';\n\nexport type ComponentArgTypesInfo = {\n  required: boolean;\n  type: SBType;\n};\n\nexport type ComponentArgTypesData = {\n  props?: Record<string, ComponentArgTypesInfo>;\n};\n\nexport type Options = {\n  skipUrlGeneration?: boolean;\n};\n\nexport const STORYBOOK_FN_PLACEHOLDER = '[[STORYBOOK_FN_PLACEHOLDER]]';\n\n/**\n * Generate dummy props using ArgTypes instead of ComponentArgTypesData This provides more accurate\n * dummy generation by leveraging ArgTypes structure\n */\nexport function generateDummyArgsFromArgTypes(argTypes: ArgTypes, options: Options = {}) {\n  const required: Record<string, unknown> = {};\n  const optional: Record<string, unknown> = {};\n\n  for (const [propName, argType] of Object.entries(argTypes)) {\n    // Determine if prop is required\n    const isRequired = argType.type && typeof argType.type === 'object' && argType.type.required;\n\n    // Generate dummy value directly from SBType\n    let dummyValue: unknown;\n    if (typeof argType.type === 'string') {\n      // Handle scalar type strings - convert to SBType\n      const sbType: SBType = { name: argType.type };\n      dummyValue = generateDummyValueFromSBType(sbType, propName, options);\n    } else if (argType.type && typeof argType.type === 'object') {\n      // Handle SBType objects directly\n      dummyValue = generateDummyValueFromSBType(argType.type, propName, options);\n    } else {\n      // Fallback as we don't know what the type is\n      dummyValue = undefined;\n    }\n\n    if (isRequired) {\n      required[propName] = dummyValue;\n    } else {\n      optional[propName] = dummyValue;\n    }\n  }\n\n  return { required, optional };\n}\n\n// Tokenize prop names so we can use them to determine the most likely type of the prop e.g. image, url, etc.\nfunction tokenize(name: string): string[] {\n  if (!name) {\n    return [];\n  }\n\n  return name\n    .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n    .replace(/[_\\-]+/g, ' ')\n    .split(' ')\n    .map((t) => t.toLowerCase())\n    .filter(Boolean);\n}\n\nfunction hasAny(tokens: string[], set: Set<string>): boolean {\n  return tokens.some((t) => set.has(t));\n}\n\nconst URL_TOKENS = new Set(['url', 'href', 'link']);\nconst IMAGE_TOKENS = new Set(['image', 'img', 'photo', 'avatar', 'logo']);\nconst EMAIL_TOKENS = new Set(['email', 'e-mail', 'mail']);\nconst PHONE_TOKENS = new Set(['phone', 'tel', 'telephone', 'mobile', 'cell']);\n\nconst COLOR_TOKENS = new Set(['color', 'background', 'bg']);\nconst DATE_TOKENS = new Set(['date', 'at', 'time', 'timestamp']);\n\nconst NEGATIVE_IMAGE_TOKENS = new Set([\n  'size',\n  'width',\n  'height',\n  'ratio',\n  'count',\n  'status',\n  'loading',\n  'config',\n  'options',\n  'variant',\n]);\n\ntype MostLikelyType = 'image' | 'url' | 'email' | 'phone';\n\nfunction getMostLikelyTypeFromTokens(tokens: string[]): MostLikelyType | null {\n  const score: Partial<Record<MostLikelyType, number>> = {};\n\n  for (const token of tokens) {\n    if (IMAGE_TOKENS.has(token)) {\n      score.image = (score.image ?? 0) + 3;\n    }\n    if (URL_TOKENS.has(token)) {\n      score.url = (score.url ?? 0) + 2;\n    }\n    if (EMAIL_TOKENS.has(token)) {\n      score.email = (score.email ?? 0) + 3;\n    }\n    if (PHONE_TOKENS.has(token)) {\n      score.phone = (score.phone ?? 0) + 3;\n    }\n  }\n\n  // Penalize image metadata so we don't end up adding an image URL to a prop like imageWidth\n  if (hasAny(tokens, NEGATIVE_IMAGE_TOKENS)) {\n    score.image = (score.image ?? 0) - 4;\n  }\n\n  let best: MostLikelyType | null = null;\n  let bestScore = 0;\n\n  for (const [kind, value] of Object.entries(score) as [MostLikelyType, number][]) {\n    if (value > bestScore) {\n      bestScore = value;\n      best = kind;\n    }\n  }\n\n  return best;\n}\n\nfunction normalizeStringLiteral(value: unknown) {\n  if (typeof value !== 'string') {\n    return value;\n  }\n\n  if (\n    (value.startsWith('\"') && value.endsWith('\"')) ||\n    (value.startsWith(\"'\") && value.endsWith(\"'\"))\n  ) {\n    return value.slice(1, -1);\n  }\n\n  return value;\n}\n\nexport function generateDummyValueFromSBType(\n  sbType: SBType,\n  propName?: string,\n  options?: Options\n): unknown {\n  switch (sbType.name) {\n    case 'boolean':\n      return true;\n\n    case 'number':\n      return 0;\n\n    case 'string': {\n      const name = propName ?? '';\n      const tokens = tokenize(name);\n      if (hasAny(tokens, COLOR_TOKENS)) {\n        return '#ff4785';\n      }\n\n      if (hasAny(tokens, DATE_TOKENS)) {\n        return new Date().toLocaleDateString();\n      }\n\n      const mostLikelyType = getMostLikelyTypeFromTokens(tokens);\n\n      if (options?.skipUrlGeneration && (mostLikelyType === 'image' || mostLikelyType === 'url')) {\n        return name;\n      }\n\n      switch (mostLikelyType) {\n        case 'image':\n          return 'https://placehold.co/600x400?text=Storybook';\n\n        case 'url':\n          return 'https://example.com';\n\n        case 'email':\n          return 'storybook@example.com';\n\n        case 'phone':\n          return '1234567890';\n\n        default:\n          return name ?? 'Hello world';\n      }\n    }\n\n    case 'date':\n      return new Date();\n\n    case 'node':\n      return propName ?? 'Hello world';\n\n    case 'function':\n      return STORYBOOK_FN_PLACEHOLDER;\n\n    case 'literal':\n      return normalizeStringLiteral(sbType.value);\n\n    case 'object': {\n      const result: Record<string, unknown> = {};\n\n      for (const [key, valueType] of Object.entries(sbType.value)) {\n        result[key] = generateDummyValueFromSBType(valueType, key, options);\n      }\n\n      return result;\n    }\n\n    case 'union': {\n      if (!sbType.value?.length) {\n        return '';\n      }\n\n      // Look for literal types in the union\n      const literalType = sbType.value.find((t) => t.name === 'literal');\n      if (literalType?.name === 'literal') {\n        return normalizeStringLiteral(literalType.value);\n      }\n\n      return generateDummyValueFromSBType(sbType.value[0], propName, options);\n    }\n\n    case 'array': {\n      const v = sbType.value as unknown as SBType[];\n\n      // If we don't know what the element is, be conservative and return empty.\n      if (v?.length < 1 || v[0]?.name === 'other') {\n        return [];\n      }\n      return [generateDummyValueFromSBType(v[0], propName, options)];\n    }\n\n    case 'tuple':\n      return sbType.value.map((el) => generateDummyValueFromSBType(el, undefined, options));\n\n    case 'enum':\n      return sbType.value[0] ?? propName;\n\n    case 'intersection': {\n      // For intersections, combine all object types\n      const objectTypes = sbType.value.filter((t) => t.name === 'object');\n      if (objectTypes.length > 0) {\n        const result: Record<string, unknown> = {};\n        objectTypes.forEach((objType) => {\n          if (objType.name === 'object') {\n            Object.entries(objType.value).forEach(([key, type]) => {\n              result[key] = generateDummyValueFromSBType(type, key, options);\n            });\n          }\n        });\n        return result;\n      }\n      return {};\n    }\n\n    case 'other': {\n      const value = sbType.value;\n      if (value?.startsWith('React') || value?.includes('Event') || value?.includes('Element')) {\n        return STORYBOOK_FN_PLACEHOLDER;\n      }\n\n      if (value === 'null') {\n        return null;\n      }\n\n      if (value === 'void' || value === 'undefined') {\n        return undefined;\n      }\n\n      return null;\n    }\n  }\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/get-new-story-file.test.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { findConfigFile, getProjectRoot } from 'storybook/internal/common';\nimport { isCsfFactoryPreview } from 'storybook/internal/csf-tools';\nimport type { Options } from 'storybook/internal/types';\n\nimport * as walk from 'empathic/walk';\n\nimport { STORYBOOK_FN_PLACEHOLDER } from './get-dummy-args-from-argtypes.ts';\nimport { getNewStoryFile } from './get-new-story-file.ts';\n\nvi.mock('storybook/internal/common', { spy: true });\nvi.mock('storybook/internal/csf-tools', { spy: true });\nvi.mock('node:fs', { spy: true });\nvi.mock('node:fs/promises', { spy: true });\nvi.mock('empathic/walk', { spy: true });\n\ndescribe('get-new-story-file', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n    vi.mocked(getProjectRoot).mockReturnValue(join(__dirname));\n    vi.mocked(findConfigFile).mockReturnValue(\n      undefined as unknown as ReturnType<typeof findConfigFile>\n    );\n    vi.mocked(existsSync).mockReturnValue(false);\n  });\n\n  it('should create a new story file (TypeScript)', async () => {\n    const { exportedStoryName, storyFileContent, storyFilePath } = await getNewStoryFile(\n      {\n        componentFilePath: 'src/components/Page.tsx',\n        componentExportName: 'Page',\n        componentIsDefaultExport: false,\n        componentExportCount: 1,\n      },\n      {\n        presets: {\n          apply: (val: string) => {\n            if (val === 'framework') {\n              return Promise.resolve('@storybook/nextjs');\n            }\n          },\n        },\n      } as unknown as Options\n    );\n\n    expect(exportedStoryName).toBe('Default');\n    expect(storyFileContent).toMatchInlineSnapshot(`\n      \"import type { Meta, StoryObj } from \"@storybook/nextjs\";\n\n      import { Page } from \"./Page\";\n\n      const meta = {\n        component: Page,\n      } satisfies Meta<typeof Page>;\n\n      export default meta;\n\n      type Story = StoryObj<typeof meta>;\n\n      export const Default: Story = {};\n      \"\n    `);\n    expect(storyFilePath).toBe(join(__dirname, 'src', 'components', 'Page.stories.tsx'));\n  });\n\n  it('should create a new story file (TypeScript) with a framework package using the pnp workaround', async () => {\n    const { exportedStoryName, storyFileContent, storyFilePath } = await getNewStoryFile(\n      {\n        componentFilePath: 'src/components/Page.tsx',\n        componentExportName: 'Page',\n        componentIsDefaultExport: false,\n        componentExportCount: 1,\n      },\n      {\n        presets: {\n          apply: (val: string) => {\n            if (val === 'framework') {\n              return Promise.resolve('path/to/@storybook/react-vite');\n            }\n          },\n        },\n      } as unknown as Options\n    );\n\n    expect(exportedStoryName).toBe('Default');\n    expect(storyFileContent).toMatchInlineSnapshot(`\n      \"import type { Meta, StoryObj } from \"@storybook/react-vite\";\n\n      import { Page } from \"./Page\";\n\n      const meta = {\n        component: Page,\n      } satisfies Meta<typeof Page>;\n\n      export default meta;\n\n      type Story = StoryObj<typeof meta>;\n\n      export const Default: Story = {};\n      \"\n    `);\n    expect(storyFilePath).toBe(join(__dirname, 'src', 'components', 'Page.stories.tsx'));\n  });\n\n  it('should create a new story file (JavaScript)', async () => {\n    const { exportedStoryName, storyFileContent, storyFilePath } = await getNewStoryFile(\n      {\n        componentFilePath: 'src/components/Page.jsx',\n        componentExportName: 'Page',\n        componentIsDefaultExport: true,\n        componentExportCount: 1,\n      },\n      {\n        presets: {\n          apply: (val: string) => {\n            if (val === 'framework') {\n              return Promise.resolve('@storybook/nextjs');\n            }\n          },\n        },\n      } as unknown as Options\n    );\n\n    expect(exportedStoryName).toBe('Default');\n    expect(storyFileContent).toMatchInlineSnapshot(`\n      \"import Page from \"./Page\";\n\n      const meta = {\n        component: Page,\n      };\n\n      export default meta;\n\n      export const Default = {};\n      \"\n    `);\n    expect(storyFilePath).toBe(join(__dirname, 'src', 'components', 'Page.stories.jsx'));\n  });\n\n  it('replaces function placeholder via AST and adds fn import', async () => {\n    const { storyFileContent } = await getNewStoryFile(\n      {\n        componentFilePath: 'src/components/Page.tsx',\n        componentExportName: 'Page',\n        componentIsDefaultExport: false,\n        componentExportCount: 1,\n      },\n      {\n        presets: {\n          apply: (val: string) => {\n            if (val === 'framework') {\n              return Promise.resolve('@storybook/nextjs');\n            }\n            if (val === 'internal_getArgTypesData') {\n              return Promise.resolve({\n                onClick: { name: 'onClick', type: { name: 'function', required: true } },\n              });\n            }\n          },\n        },\n      } as unknown as Options\n    );\n\n    expect(storyFileContent).toContain('import { fn } from \"storybook/test\";');\n    expect(storyFileContent).toContain('fn()');\n    expect(storyFileContent).not.toContain(STORYBOOK_FN_PLACEHOLDER);\n  });\n\n  it('should prevent XSS by escaping special characters in the component file name', async () => {\n    const { storyFileContent } = await getNewStoryFile(\n      {\n        componentFilePath: \"src/stories/Button';alert(document.domain);var a='.tsx\",\n        componentExportName: 'Button',\n        componentIsDefaultExport: true,\n        componentExportCount: 1,\n      },\n      {\n        presets: {\n          apply: (val: string) => {\n            if (val === 'framework') {\n              return Promise.resolve('@storybook/nextjs');\n            }\n          },\n        },\n      } as unknown as Options\n    );\n\n    expect(storyFileContent).toMatchInlineSnapshot(`\n  \"import type { Meta, StoryObj } from '@storybook/nextjs';\n\n  import Buttonalert(documentDomain);varA=\\\\' from './Button\\\\';alert(document.domain);var a=\\\\'';\n\n  const meta = {\n    component: Buttonalert(documentDomain);varA=\\\\',\n  } satisfies Meta<typeof Buttonalert(documentDomain);varA=\\\\'>;\n\n  export default meta;\n\n  type Story = StoryObj<typeof meta>;\n\n  export const Default: Story = {};\"\n`);\n  });\n\n  it('should create a new story file (CSF factory)', async () => {\n    const configDir = join(__dirname, '.storybook');\n    const previewConfigPath = join(configDir, 'preview.ts');\n\n    vi.mocked(findConfigFile).mockReturnValue(\n      previewConfigPath as unknown as ReturnType<typeof findConfigFile>\n    );\n    vi.mocked(isCsfFactoryPreview).mockReturnValue(true);\n\n    // Make checkForImportsMap return true so we keep the default '#.storybook/preview' import.\n    vi.mocked(walk.up).mockReturnValue([configDir] as unknown as ReturnType<typeof walk.up>);\n    vi.mocked(existsSync).mockImplementation((path) => path.toString().endsWith('package.json'));\n    vi.mocked(readFile).mockImplementation(async (path) => {\n      const p = path.toString();\n      if (p === previewConfigPath) {\n        return 'export default {};';\n      }\n      if (p.endsWith('package.json')) {\n        return JSON.stringify({ imports: {} });\n      }\n      return '';\n    });\n\n    const { exportedStoryName, storyFileContent, storyFilePath } = await getNewStoryFile(\n      {\n        componentFilePath: 'src/components/Page.tsx',\n        componentExportName: 'Page',\n        componentIsDefaultExport: false,\n        componentExportCount: 1,\n      },\n      {\n        configDir,\n        presets: {\n          apply: (val: string) => {\n            if (val === 'framework') {\n              return Promise.resolve('@storybook/nextjs');\n            }\n            if (val === 'internal_getArgTypesData') {\n              return Promise.resolve({\n                label: { name: 'label', type: { name: 'string', required: true } },\n                answer: { name: 'answer', type: { name: 'number', required: true } },\n                onClick: { name: 'onClick', type: { name: 'function', required: true } },\n              });\n            }\n          },\n        },\n      } as unknown as Options\n    );\n\n    expect(exportedStoryName).toBe('Default');\n    expect(storyFileContent).toMatchInlineSnapshot(`\n      \"import { fn } from \"storybook/test\";\n      import preview from \"#.storybook/preview\";\n\n      import { Page } from \"./Page\";\n\n      const meta = preview.meta({\n        component: Page,\n      });\n\n      export const Default = meta.story({\n        args: {\n          label: \"label\",\n          answer: 0,\n          onClick: fn(),\n        },\n      });\n      \"\n    `);\n    expect(storyFilePath).toBe(join(__dirname, 'src', 'components', 'Page.stories.tsx'));\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/get-new-story-file.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { basename, dirname, extname, join, relative } from 'node:path';\n\nimport { types as t, traverse } from 'storybook/internal/babel';\nimport {\n  extractFrameworkPackageName,\n  findConfigFile,\n  formatFileContent,\n  getFrameworkName,\n  getProjectRoot,\n} from 'storybook/internal/common';\nimport type { CreateNewStoryRequestPayload } from 'storybook/internal/core-events';\nimport { isCsfFactoryPreview } from 'storybook/internal/csf-tools';\nimport { logger } from 'storybook/internal/node-logger';\nimport type { Options } from 'storybook/internal/types';\n\nimport * as walk from 'empathic/walk';\n\nimport type { ArgTypes } from '../../csf/index.ts';\nimport { loadConfig, printConfig } from '../../csf-tools/index.ts';\nimport {\n  STORYBOOK_FN_PLACEHOLDER,\n  generateDummyArgsFromArgTypes,\n} from './get-dummy-args-from-argtypes.ts';\nimport { getCsfFactoryTemplateForNewStoryFile } from './new-story-templates/csf-factory-template.ts';\nimport { getJavaScriptTemplateForNewStoryFile } from './new-story-templates/javascript.ts';\nimport { getTypeScriptTemplateForNewStoryFile } from './new-story-templates/typescript.ts';\nimport { escapeForTemplate } from './safeString.ts';\n\nexport async function getNewStoryFile(\n  {\n    componentFilePath,\n    componentExportName,\n    componentIsDefaultExport,\n    componentExportCount,\n  }: CreateNewStoryRequestPayload,\n  options: Options\n) {\n  const frameworkPackageName = await getFrameworkName(options);\n  const sanitizedFrameworkPackageName = extractFrameworkPackageName(frameworkPackageName);\n\n  const base = basename(componentFilePath);\n  const extension = extname(componentFilePath);\n  const basenameWithoutExtension = escapeForTemplate(base.replace(extension, ''));\n  const dir = dirname(componentFilePath);\n\n  const { storyFileName, isTypescript, storyFileExtension } = getStoryMetadata(componentFilePath);\n  const storyFileNameWithExtension = `${storyFileName}.${storyFileExtension}`;\n  const alternativeStoryFileNameWithExtension = `${basenameWithoutExtension}.${componentExportName}.stories.${storyFileExtension}`;\n\n  const exportedStoryName = 'Default';\n\n  let useCsfFactory = false;\n  let previewConfigPath: string | undefined;\n  try {\n    const previewConfig = findConfigFile('preview', options.configDir);\n    if (previewConfig) {\n      const previewContent = await readFile(previewConfig, 'utf-8');\n      useCsfFactory = isCsfFactoryPreview(loadConfig(previewContent));\n      previewConfigPath = previewConfig;\n    }\n  } catch {\n    // TODO: improve this later on, for now while CSF factories are experimental, just fallback to CSF3\n  }\n\n  let args: Record<string, unknown> | undefined = undefined;\n\n  try {\n    const argTypes = (await options.presets.apply('internal_getArgTypesData', null, {\n      ...options,\n      componentFilePath,\n      componentExportName,\n    })) as ArgTypes | null;\n    logger.debug(`Extracted argTypes for ${componentExportName}: ${JSON.stringify(argTypes)}`);\n\n    if (argTypes) {\n      const { required } = generateDummyArgsFromArgTypes(argTypes);\n      if (Object.keys(required).length > 0) {\n        args = required;\n        logger.debug(\n          `Generated dummy data using ArgTypes for ${componentExportName}: ${JSON.stringify(args)}`\n        );\n      }\n    }\n  } catch (error) {\n    // If anything fails with the dummy data generation, just proceed without args\n    logger.debug(`Could not generate dummy data for ${componentExportName}: ${error}`);\n  }\n\n  let storyFileContent = '';\n  if (useCsfFactory) {\n    // Calculate relative path from story file to preview config if needed\n    // Only use relative path if package.json doesn't have an imports map\n    let previewImportPath: string | undefined;\n    if (previewConfigPath) {\n      const hasImportsMap = await checkForImportsMap(options.configDir);\n      if (!hasImportsMap) {\n        const storyFilePath = join(getProjectRoot(), dir);\n        const relPath = relative(storyFilePath, previewConfigPath);\n        const pathWithoutExt = relPath.replace(/\\.(ts|js|mts|cts|tsx|jsx)$/, '');\n        previewImportPath = escapeForTemplate(\n          pathWithoutExt.startsWith('.') ? pathWithoutExt : `./${pathWithoutExt}`\n        );\n      }\n    }\n\n    storyFileContent = await getCsfFactoryTemplateForNewStoryFile({\n      basenameWithoutExtension,\n      componentExportName,\n      componentIsDefaultExport,\n      exportedStoryName,\n      previewImportPath,\n      args,\n    });\n  } else {\n    storyFileContent =\n      isTypescript && frameworkPackageName\n        ? await getTypeScriptTemplateForNewStoryFile({\n            basenameWithoutExtension,\n            componentExportName,\n            componentIsDefaultExport,\n            frameworkPackage: sanitizedFrameworkPackageName,\n            exportedStoryName,\n            args,\n          })\n        : await getJavaScriptTemplateForNewStoryFile({\n            basenameWithoutExtension,\n            componentExportName,\n            componentIsDefaultExport,\n            exportedStoryName,\n            args,\n          });\n  }\n\n  storyFileContent = replaceArgsPlaceholders(storyFileContent);\n\n  const storyFilePath =\n    doesStoryFileExist(join(getProjectRoot(), dir), storyFileName) && componentExportCount > 1\n      ? join(getProjectRoot(), dir, alternativeStoryFileNameWithExtension)\n      : join(getProjectRoot(), dir, storyFileNameWithExtension);\n\n  const formattedStoryFileContent = await formatFileContent(storyFilePath, storyFileContent);\n\n  return {\n    storyFilePath,\n    exportedStoryName,\n    storyFileContent: formattedStoryFileContent,\n    dirname: dir,\n  };\n}\n\nexport const getStoryMetadata = (componentFilePath: string) => {\n  const isTypescript = /\\.(ts|tsx|mts|cts)$/.test(componentFilePath);\n  const base = basename(componentFilePath);\n  const extension = extname(componentFilePath);\n  const basenameWithoutExtension = base.replace(extension, '');\n  const storyFileExtension = isTypescript ? 'tsx' : 'jsx';\n  return {\n    storyFileName: `${basenameWithoutExtension}.stories`,\n    storyFileExtension,\n    isTypescript,\n  };\n};\n\nexport const doesStoryFileExist = (parentFolder: string, storyFileName: string) => {\n  return (\n    existsSync(join(parentFolder, `${storyFileName}.ts`)) ||\n    existsSync(join(parentFolder, `${storyFileName}.tsx`)) ||\n    existsSync(join(parentFolder, `${storyFileName}.js`)) ||\n    existsSync(join(parentFolder, `${storyFileName}.jsx`))\n  );\n};\n\nasync function checkForImportsMap(configDir: string): Promise<boolean> {\n  try {\n    // Walk up from configDir to project root, checking each directory for package.json with imports\n    for (const directory of walk.up(configDir, { last: getProjectRoot() })) {\n      const packageJsonPath = join(directory, 'package.json');\n      if (existsSync(packageJsonPath)) {\n        const packageJsonContent = await readFile(packageJsonPath, 'utf-8');\n        const packageJson = JSON.parse(packageJsonContent);\n        if (packageJson.imports) {\n          return true;\n        }\n      }\n    }\n    return false;\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Replaces non-primitive args placeholders like `[[STORYBOOK_FN_PLACEHOLDER]]` where it needs more\n * involved changes like adding imports, etc.\n */\nfunction replaceArgsPlaceholders(storyFileContent: string) {\n  // Avoid parsing unless we actually have placeholders to replace.\n  if (!storyFileContent.includes(STORYBOOK_FN_PLACEHOLDER)) {\n    return storyFileContent;\n  }\n\n  const storyFile = loadConfig(storyFileContent).parse();\n\n  let needsFnImport = false;\n\n  traverse(storyFile._ast, {\n    StringLiteral(path) {\n      if (path.node.value === STORYBOOK_FN_PLACEHOLDER) {\n        needsFnImport = true;\n        path.replaceWith(t.callExpression(t.identifier('fn'), []));\n      }\n    },\n  });\n\n  if (needsFnImport) {\n    storyFile.setImport(['fn'], 'storybook/test');\n  }\n\n  return printConfig(storyFile).code;\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/get-server-channel.ts",
    "content": "import type { IncomingMessage } from 'node:http';\n\nimport type { ChannelHandler } from 'storybook/internal/channels';\nimport { Channel, HEARTBEAT_INTERVAL } from 'storybook/internal/channels';\n\nimport { isJSON, parse, stringify } from 'telejson';\nimport WebSocket, { WebSocketServer } from 'ws';\n\nimport { logger } from '../../node-logger/index.ts';\nimport { UniversalStore } from '../../shared/universal-store/index.ts';\nimport { type HostValidationOptions, isValidHost } from './getHostValidationMiddleware.ts';\nimport { isValidToken } from './validate-token.ts';\n\ntype Server = NonNullable<NonNullable<ConstructorParameters<typeof WebSocketServer>[0]>['server']>;\n\ntype ServerChannelTransportOptions = HostValidationOptions & {\n  skipValidation?: boolean;\n  token: string;\n};\n\n/**\n * This class represents a channel transport that allows for a one-to-many relationship between the\n * server and clients. Unlike other channels such as the postmessage and websocket channel\n * implementations, this channel will receive from many clients and any events emitted will be sent\n * out to all connected clients.\n */\nexport class ServerChannelTransport {\n  private socket: WebSocketServer;\n\n  private handler?: ChannelHandler;\n\n  constructor(server: Server, options: ServerChannelTransportOptions) {\n    this.socket = new WebSocketServer({ noServer: true });\n\n    server.on('upgrade', (request: IncomingMessage, socket, head) => {\n      try {\n        const url = request.url && new URL(request.url, options.localAddress);\n        if (!url || url.pathname !== '/storybook-server-channel') {\n          return;\n        }\n\n        if (!options.skipValidation) {\n          const originHost = request.headers.origin && new URL(request.headers.origin).host;\n          if (!isValidHost(originHost, options)) {\n            throw new Error('Invalid websocket origin');\n          }\n\n          const requestToken = url.searchParams.get('token');\n          if (!isValidToken(requestToken, options.token)) {\n            throw new Error('Invalid websocket token');\n          }\n        }\n\n        this.socket.handleUpgrade(request, socket, head, (ws) => {\n          this.socket.emit('connection', ws, request);\n        });\n      } catch (error) {\n        logger.warn(`Rejecting WebSocket connection: ${error}`);\n        socket.write('HTTP/1.1 403 Forbidden\\r\\nConnection: close\\r\\n\\r\\n');\n        socket.destroy();\n      }\n    });\n\n    this.socket.on('connection', (wss) => {\n      wss.on('message', (raw) => {\n        const data = raw.toString();\n        const event = typeof data === 'string' && isJSON(data) ? parse(data, {}) : data;\n        this.handler?.(event);\n      });\n    });\n\n    const interval = setInterval(() => {\n      this.send({ type: 'ping' });\n    }, HEARTBEAT_INTERVAL);\n\n    this.socket.on('close', function close() {\n      clearInterval(interval);\n    });\n\n    process.on('SIGTERM', () => {\n      this.socket.clients.forEach((client) => {\n        if (client.readyState === WebSocket.OPEN) {\n          client.close(1001, 'Server is shutting down');\n        }\n      });\n      this.socket.close(() => process.exit(0));\n    });\n  }\n\n  setHandler(handler: ChannelHandler) {\n    this.handler = handler;\n  }\n\n  send(event: any) {\n    const data = stringify(event, { maxDepth: 15 });\n\n    Array.from(this.socket.clients)\n      .filter((c) => c.readyState === WebSocket.OPEN)\n      .forEach((client) => client.send(data));\n  }\n}\n\nexport function getServerChannel(server: Server, options: ServerChannelTransportOptions) {\n  const transports = [new ServerChannelTransport(server, options)];\n\n  const channel = new Channel({ transports, async: true });\n\n  UniversalStore.__prepare(channel, UniversalStore.Environment.SERVER);\n\n  return channel;\n}\n\n// for backwards compatibility\nexport type ServerChannel = ReturnType<typeof getServerChannel>;\n"
  },
  {
    "path": "code/core/src/core-server/utils/getAccessControlMiddleware.ts",
    "content": "import type { Middleware } from '../../types/index.ts';\n\nexport function getAccessControlMiddleware(crossOriginIsolated: boolean): Middleware {\n  return (req, res, next) => {\n    // These headers are required to enable SharedArrayBuffer\n    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer\n    if (crossOriginIsolated) {\n      res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');\n      res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');\n    }\n    next();\n  };\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/getHostValidationMiddleware.ts",
    "content": "import type { IncomingMessage } from 'node:http';\n\nimport { isHostAllowed } from 'host-validation-middleware';\n\nimport type { Middleware } from '../../types/index.ts';\n\nexport const DEFAULT_ALLOWED_HOSTS: string[] | true = [];\n\nexport type HostValidationOptions = {\n  host?: string;\n  allowedHosts?: string[] | true;\n  localAddress?: string;\n  networkAddress?: string;\n};\n\n/**\n * Validates a host (Host header–shaped string, e.g. \"localhost:6006\") against known local/network\n * addresses and allowed hosts. Callers must pass host-shaped input; normalize from an origin URL\n * (e.g. new URL(origin).host) before invoking if needed.\n *\n * @param host - The host to validate (hostname or \"hostname:port\").\n * @param options - The builder options.\n * @returns `true` if the host is valid, `false` otherwise.\n */\nexport const isValidHost = (host: string | undefined, options: HostValidationOptions): boolean => {\n  const allowedHosts = options.allowedHosts ?? DEFAULT_ALLOWED_HOSTS;\n  if (allowedHosts === true) {\n    return true;\n  }\n  if (!host) {\n    return false;\n  }\n\n  try {\n    // Setting host to 0.0.0.0 binds to all hosts, which implies allowing all hosts.\n    // This is common in containerized environments like Docker.\n    if (options.host === '0.0.0.0' && allowedHosts.length === 0) {\n      return true;\n    }\n    return isHostAllowed(host, [\n      ...allowedHosts,\n      ...(options.localAddress ? [new URL(options.localAddress).host] : []),\n      ...(options.networkAddress ? [new URL(options.networkAddress).host] : []),\n    ]);\n  } catch {\n    return false;\n  }\n};\n\n/**\n * Validates the Host header against known local/network addresses and allowed hosts. Requests with\n * no Host header (e.g. same-origin navigation, GET from address bar) are not allowed.\n */\nexport function getHostValidationMiddleware(\n  options: HostValidationOptions\n): Middleware<IncomingMessage> {\n  return (req, res, next) => {\n    const host = req.headers.host;\n    const allowedHosts = options.allowedHosts ?? DEFAULT_ALLOWED_HOSTS;\n    if (allowedHosts !== true && !isValidHost(host, options)) {\n      res.writeHead(403, { 'Content-Type': 'text/plain' });\n      res.end('Invalid host');\n      return;\n    }\n    next();\n  };\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/ghost-stories/component-analyzer.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { getComponentComplexity } from './component-analyzer.ts';\n\ndescribe('getComponentComplexity', () => {\n  it('returns score between 0 and 1', () => {\n    const source = 'const x = 1;';\n    const score = getComponentComplexity(source);\n    expect(score).toBeGreaterThanOrEqual(0);\n    expect(score).toBeLessThanOrEqual(1);\n  });\n\n  it('calculates complexity based on runtime lines and imports', () => {\n    const superSimpleComponent = `\n      import React from 'react';\n      export const Button = () => <button>Click</button>;\n    `;\n\n    const simpleComponent = `\n      import React from 'react';\n      import { foo } from './foo';\n      export const Button = () => {\n        return <>\n          <foo>\n            <bar>\n              <baz>\n                <qux>\n              </baz>\n            </bar>\n          </foo>\n        </>;\n      };\n    `;\n\n    const complexComponent = `\n      import React, { useState, useEffect } from 'react';\n      import { api } from './api';\n      import { utils } from './utils';\n      import { types } from './types';\n\n      interface Props {\n        id: string;\n        onClick: () => void;\n      }\n\n      type State = {\n        loading: boolean;\n        data: any[];\n      };\n\n      export const ComplexComponent: React.FC<Props> = ({ id, onClick }) => {\n        const [state, setState] = useState<State>({ loading: true, data: [] });\n        const [count, setCount] = useState(0);\n\n        useEffect(() => {\n          api.fetchData(id).then(data => {\n            setState({ loading: false, data });\n          });\n        }, [id]);\n\n        useEffect(() => {\n          setCount(c => c + 1);\n        }, [state.data]);\n\n        const handleClick = () => {\n          setCount(0);\n          onClick();\n        };\n\n        if (state.loading) {\n          return <div>Loading...</div>;\n        }\n\n        return (\n          <div>\n            <h1>Data Count: {state.data.length}</h1>\n            <button onClick={handleClick}>\n              Clicked {count} times\n            </button>\n            {state.data.map(item => (\n              <div key={item.id}>{item.name}</div>\n            ))}\n          </div>\n        );\n      };\n    `;\n\n    const superSimpleScore = getComponentComplexity(superSimpleComponent);\n    const simpleScore = getComponentComplexity(simpleComponent);\n    const complexScore = getComponentComplexity(complexComponent);\n\n    expect(superSimpleScore).toMatchInlineSnapshot(`0.0234375`);\n    expect(simpleScore).toMatchInlineSnapshot(`0.13125`);\n    expect(complexScore).toMatchInlineSnapshot(`0.4125`);\n\n    expect(complexScore).toBeGreaterThan(simpleScore);\n  });\n\n  it('handles empty source', () => {\n    expect(getComponentComplexity('')).toBe(0);\n  });\n\n  it('converges to 1 as complexity increases', () => {\n    const lowComplexity = 'const x = 1;';\n    const highComplexity = 'const x = 1;\\n'.repeat(1000) + 'import a from \"b\";\\n'.repeat(100);\n\n    const lowScore = getComponentComplexity(lowComplexity);\n    const highScore = getComponentComplexity(highComplexity);\n\n    expect(highScore).toBeGreaterThan(lowScore);\n    expect(highScore).toBeCloseTo(1, 1); // Should be very close to 1\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/ghost-stories/component-analyzer.ts",
    "content": "const COMPLEXITY_CONFIG = {\n  /** Weight applied to non-empty lines */\n  locWeight: 1,\n  /** Imports can be cheap, so they get a lower weight */\n  importWeight: 0.5,\n  /**\n   * Defines what raw complexity value should map to the upper bound of a \"simple\" file For instance\n   * 30 LOC + 4 imports = 32. This would result in a score of 0.3\n   */\n  simpleBaseline: 32,\n  simpleScore: 0.3,\n};\n\n/**\n * Simple analyzer which gives a score to a component based on its complexity. In the future, it\n * will be replaced with a thorough check that analyzes many complexity factors like auth usage,\n * theming usage, context usage, imports breakdown, etc. but for now this will do.\n */\nexport const getComponentComplexity = (fileContent: string): number => {\n  const lines = fileContent.split('\\n');\n\n  const nonEmptyLines = lines.filter((line) => line.trim() !== '').length;\n\n  const importCount = lines.filter((line) => line.trim().startsWith('import')).length;\n\n  const rawComplexity =\n    nonEmptyLines * COMPLEXITY_CONFIG.locWeight + importCount * COMPLEXITY_CONFIG.importWeight;\n\n  /** Normalize against the \"simple\" baseline and what score is considered to be simple. */\n  const normalizedScore =\n    rawComplexity / (COMPLEXITY_CONFIG.simpleBaseline / COMPLEXITY_CONFIG.simpleScore);\n\n  return Math.min(normalizedScore, 1);\n};\n"
  },
  {
    "path": "code/core/src/core-server/utils/ghost-stories/get-candidates.test.ts",
    "content": "import { readFile } from 'node:fs/promises';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { getComponentComplexity } from './component-analyzer.ts';\nimport { getCandidatesForStorybook } from './get-candidates.ts';\n\nvi.mock('node:fs/promises');\nvi.mock('glob');\nvi.mock('storybook/internal/node-logger');\nvi.mock('./component-analyzer');\n\ndescribe('getCandidatesForStorybook', () => {\n  beforeEach(() => {\n    vi.resetAllMocks();\n  });\n\n  it('returns simple candidates when enough are found', async () => {\n    const files = ['/path/to/SimpleComponent.tsx', '/path/to/ComplexComponent.tsx'];\n    const sampleCount = 1;\n\n    // Mock readFile for both files\n    vi.mocked(readFile).mockResolvedValueOnce(`\n        export const SimpleComponent = () => <div>Simple</div>;\n      `).mockResolvedValueOnce(`\n        export const ComplexComponent = () => <div>Complex</div>;\n      `);\n\n    // Mock getComponentComplexity\n    vi.mocked(getComponentComplexity)\n      .mockReturnValueOnce(0.1) // Simple component (below 0.2)\n      .mockReturnValueOnce(0.8); // Complex component (above 0.2)\n\n    const result = await getCandidatesForStorybook(files, sampleCount);\n\n    expect(result).toEqual({\n      candidates: ['/path/to/SimpleComponent.tsx'],\n      analyzedCount: 1,\n      avgComplexity: 0.1,\n    });\n    // Should only read the first file since it found a simple candidate and sampleCount=1\n    expect(readFile).toHaveBeenCalledTimes(1);\n    expect(readFile).toHaveBeenCalledWith('/path/to/SimpleComponent.tsx', 'utf-8');\n    expect(getComponentComplexity).toHaveBeenCalledTimes(1);\n  });\n\n  it('returns analyzed candidates when not enough simple ones found', async () => {\n    const files = ['/path/to/ComplexComponent1.tsx', '/path/to/ComplexComponent2.tsx'];\n    const sampleCount = 2;\n\n    // Mock readFile for both files\n    vi.mocked(readFile).mockResolvedValueOnce(`\n        export const ComplexComponent = () => <div>Complex</div>;\n      `).mockResolvedValueOnce(`\n        const ComplexComponent = () => <div>Complex</div>;\n        export default ComplexComponent;\n      `);\n\n    // Assuming both components are complex\n    vi.mocked(getComponentComplexity).mockReturnValueOnce(0.5).mockReturnValueOnce(0.6);\n\n    const result = await getCandidatesForStorybook(files, sampleCount);\n\n    expect(result).toEqual({\n      candidates: ['/path/to/ComplexComponent1.tsx', '/path/to/ComplexComponent2.tsx'],\n      analyzedCount: 2,\n      avgComplexity: 0.55,\n    });\n    expect(readFile).toHaveBeenCalledTimes(2);\n    expect(getComponentComplexity).toHaveBeenCalledTimes(2);\n  });\n\n  it('filters out invalid candidates', async () => {\n    const files = ['/path/to/ValidComponent.tsx', '/path/to/InvalidComponent.js'];\n    const sampleCount = 2;\n\n    // Mock readFile\n    vi.mocked(readFile).mockResolvedValueOnce(`\n        export const ValidComponent = () => <div>Valid</div>;\n      `).mockResolvedValueOnce(`\n        console.log('invalid as there is no export nor JSX');\n      `);\n\n    vi.mocked(getComponentComplexity).mockReturnValue(0.1);\n\n    const result = await getCandidatesForStorybook(files, sampleCount);\n\n    // Even though the sample count is 2, only one is returned as the invalid component is filtered out\n    expect(result).toEqual({\n      candidates: ['/path/to/ValidComponent.tsx'],\n      analyzedCount: 1,\n      avgComplexity: 0.1,\n    });\n    expect(readFile).toHaveBeenCalledTimes(2);\n    expect(getComponentComplexity).toHaveBeenCalledTimes(1);\n  });\n\n  it('handles readFile errors gracefully', async () => {\n    const files = ['/path/to/ValidComponent.tsx', '/path/to/ErrorComponent.tsx'];\n    const sampleCount = 2;\n\n    // Suppose one of the files fails for whatever reason\n    vi.mocked(readFile)\n      .mockResolvedValueOnce(\n        `\n        export const ValidComponent = () => <div>Valid</div>;\n      `\n      )\n      .mockRejectedValueOnce(new Error('File not found'));\n\n    vi.mocked(getComponentComplexity).mockReturnValue(0.1);\n\n    const result = await getCandidatesForStorybook(files, sampleCount);\n\n    // Should attempt to read both files and still proceed correctly with the valid ones\n    expect(result).toEqual({\n      candidates: ['/path/to/ValidComponent.tsx'],\n      analyzedCount: 1,\n      avgComplexity: 0.1,\n    });\n    expect(readFile).toHaveBeenCalledTimes(2);\n    expect(getComponentComplexity).toHaveBeenCalledTimes(1);\n  });\n\n  it('stops reading as soon as enough simple candidates are found', async () => {\n    const files = ['/path/to/Complex1.tsx', '/path/to/Simple.tsx'];\n    const sampleCount = 1;\n\n    vi.mocked(readFile).mockResolvedValueOnce(`\n        export const ComplexComponent = () => <div>Complex</div>;\n      `).mockResolvedValueOnce(`\n        export const SimpleComponent = () => <div>Simple</div>;\n      `).mockResolvedValueOnce(`\n        export const SimpleComponent = () => <div>Simple</div>;\n      `);\n\n    vi.mocked(getComponentComplexity)\n      .mockReturnValueOnce(0.5) // Complex\n      .mockReturnValueOnce(0.1); // Simple - should stop after processing this\n\n    const result = await getCandidatesForStorybook(files, sampleCount);\n\n    expect(result).toEqual({\n      candidates: ['/path/to/Simple.tsx'],\n      analyzedCount: 2,\n      avgComplexity: 0.1,\n    });\n    // Should stop after the second file as the sample count was already fulfilled\n    expect(readFile).toHaveBeenCalledTimes(2);\n    expect(getComponentComplexity).toHaveBeenCalledTimes(2);\n  });\n\n  it('returns all analyzed candidates when sampleCount exceeds amount of detected simple candidates', async () => {\n    const files = ['/path/to/Component1.tsx', '/path/to/Component2.tsx'];\n    const sampleCount = 3; // More than available\n\n    vi.mocked(readFile).mockResolvedValueOnce(`\n      export const SimpleComponent = () => <div>Simple</div>;\n      `).mockResolvedValueOnce(`\n        export const ComplexComponent = () => <div>Complex</div>;\n        `).mockResolvedValueOnce(`\n        export const ComplexComponent = () => <div>Complex</div>;\n        `);\n\n    vi.mocked(getComponentComplexity)\n      .mockReturnValueOnce(0.2) // Simple\n      .mockReturnValueOnce(0.3) // Not simple\n      .mockReturnValueOnce(0.4); // Not simple\n\n    const result = await getCandidatesForStorybook(files, sampleCount);\n\n    expect(result).toEqual({\n      candidates: ['/path/to/Component1.tsx', '/path/to/Component2.tsx'],\n      analyzedCount: 2,\n      avgComplexity: 0.25,\n    });\n    expect(readFile).toHaveBeenCalledTimes(2);\n    expect(getComponentComplexity).toHaveBeenCalledTimes(2);\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/ghost-stories/get-candidates.ts",
    "content": "import { readFile } from 'node:fs/promises';\n\nimport { babelParse, traverse } from 'storybook/internal/babel';\nimport { logger } from 'storybook/internal/node-logger';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport { glob } from 'glob';\n\nimport { getComponentComplexity } from './component-analyzer.ts';\n\n// A valid candidate includes React code and at least one export\nfunction isValidCandidate(source: string): boolean {\n  const ast = babelParse(source);\n\n  let hasJSX = false;\n  let hasExport = false;\n\n  traverse(ast, {\n    JSXElement(path) {\n      hasJSX = true;\n\n      if (hasExport) {\n        path.stop();\n      }\n    },\n    JSXFragment(path) {\n      hasJSX = true;\n\n      if (hasExport) {\n        path.stop();\n      }\n    },\n    ExportNamedDeclaration(path) {\n      hasExport = true;\n\n      if (hasJSX) {\n        path.stop();\n      }\n    },\n    ExportDefaultDeclaration(path) {\n      hasExport = true;\n\n      if (hasJSX) {\n        path.stop();\n      }\n    },\n    ExportAllDeclaration(path) {\n      hasExport = true;\n\n      if (hasJSX) {\n        path.stop();\n      }\n    },\n  });\n\n  return hasJSX && hasExport;\n}\n\n/**\n * Based on a list of files, analyze them to find potential candidates to generate story files for.\n * this is based on whether the file has JSX and exports and how many runtime LOC and imports it\n * has.\n */\nexport async function getCandidatesForStorybook(\n  files: string[],\n  sampleCount: number\n): Promise<{\n  candidates: string[];\n  analyzedCount: number;\n  avgComplexity: number;\n}> {\n  const simpleCandidates: { file: string; complexity: number }[] = [];\n  const analyzedCandidates: { file: string; complexity: number }[] = [];\n\n  for (const file of files) {\n    let source: string;\n    try {\n      source = await readFile(file, 'utf-8');\n      // filter out non-React code or files without exports\n      if (!isValidCandidate(source)) {\n        continue;\n      }\n    } catch {\n      continue;\n    }\n\n    const complexity = getComponentComplexity(source);\n    analyzedCandidates.push({ file, complexity });\n\n    if (complexity < 0.3) {\n      simpleCandidates.push({ file, complexity });\n      if (simpleCandidates.length >= sampleCount) {\n        break;\n      }\n    }\n  }\n\n  let selectedCandidates: { file: string; complexity: number }[] = [];\n\n  // If we have enough simple candidates, use those\n  if (simpleCandidates.length >= sampleCount) {\n    selectedCandidates = simpleCandidates\n      .sort((a, b) => a.complexity - b.complexity)\n      .slice(0, sampleCount);\n  } else {\n    selectedCandidates = analyzedCandidates\n      .sort((a, b) => a.complexity - b.complexity)\n      .slice(0, sampleCount);\n  }\n\n  const avgComplexity =\n    selectedCandidates.length > 0\n      ? Number(\n          (\n            selectedCandidates.reduce((acc, curr) => acc + curr.complexity, 0) /\n            selectedCandidates.length\n          ).toFixed(2)\n        )\n      : 0;\n\n  return {\n    candidates: selectedCandidates.map(({ file }) => file),\n    analyzedCount: analyzedCandidates.length,\n    avgComplexity,\n  };\n}\n\nexport async function getComponentCandidates({\n  sampleSize = 20,\n  globPattern = '**/*.{tsx,jsx}',\n}: {\n  sampleSize?: number;\n  globPattern?: string;\n} = {}): Promise<{\n  candidates: string[];\n  error?: string;\n  globMatchCount: number;\n  analyzedCount?: number;\n  avgComplexity?: number;\n}> {\n  let globMatchCount = 0;\n\n  try {\n    let files: string[] = [];\n\n    // Find files matching the glob pattern\n    files = await glob(globPattern, {\n      cwd: process.cwd(),\n      absolute: true,\n      ignore: [\n        '**/node_modules/**',\n        '**/.git/**',\n        '**/dist/**',\n        '**/__mocks__/**',\n        '**/build/**',\n        '**/storybook-static/**',\n        '**/*.test.*',\n        '**/*.d.*',\n        '**/*.config.*',\n        '**/*.spec.*',\n        '**/*.stories.*',\n        // skip example story files that come from the CLI\n        '**/stories/{Button,Header,Page}.*',\n        '**/stories/{button,header,page}.*',\n      ],\n    });\n\n    globMatchCount = files.length;\n\n    if (globMatchCount === 0) {\n      return {\n        candidates: [],\n        globMatchCount,\n      };\n    }\n\n    const { analyzedCount, avgComplexity, candidates } = await getCandidatesForStorybook(\n      files,\n      sampleSize\n    );\n\n    return {\n      analyzedCount,\n      avgComplexity,\n      candidates,\n      globMatchCount,\n    };\n  } catch {\n    return {\n      candidates: [],\n      error: 'Failed to find candidates',\n      globMatchCount,\n    };\n  }\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/ghost-stories/parse-vitest-report.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { parseVitestResults } from './parse-vitest-report.ts';\n\nvi.mock('../../../shared/utils/categorize-render-errors', { spy: true });\n\ndescribe('parse-vitest-report', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n  });\n\n  describe('parseVitestResults', () => {\n    it('should parse basic vitest results with all passing tests', () => {\n      const mockVitestResults = {\n        success: true,\n        numTotalTests: 3,\n        numPassedTests: 3,\n        numFailedTests: 0,\n        testResults: [\n          {\n            assertionResults: [\n              {\n                fullName: 'Story1',\n                status: 'passed',\n                failureMessages: [],\n              },\n              {\n                fullName: 'Story2',\n                status: 'passed',\n                failureMessages: [],\n              },\n              {\n                fullName: 'Story3',\n                status: 'passed',\n                failureMessages: [],\n              },\n            ],\n          },\n        ],\n      };\n\n      const result = parseVitestResults(mockVitestResults);\n\n      expect(result.summary).toEqual({\n        total: 3,\n        passed: 3,\n        passedButEmptyRender: 0,\n        successRate: 1.0,\n        successRateWithoutEmptyRender: 1.0,\n        uniqueErrorCount: 0,\n        categorizedErrors: {},\n      });\n    });\n\n    it('should parse vitest results with failed tests and extract error messages', () => {\n      const mockVitestResults = {\n        success: false,\n        numTotalTests: 3,\n        numPassedTests: 1,\n        numFailedTests: 2,\n        testResults: [\n          {\n            assertionResults: [\n              {\n                fullName: 'Story1',\n                status: 'passed',\n                failureMessages: [],\n              },\n              {\n                fullName: 'Story2',\n                status: 'failed',\n                failureMessages: [\n                  'Error: Cannot read property \"x\" of undefined\\n  at Component.render',\n                ],\n              },\n              {\n                fullName: 'Story3',\n                status: 'failed',\n                failureMessages: ['Error: Module not found: react-router\\n  at import statement'],\n              },\n            ],\n          },\n        ],\n      };\n\n      const result = parseVitestResults(mockVitestResults);\n\n      expect(result.summary?.total).toBe(3);\n      expect(result.summary?.passed).toBe(1);\n      expect(result.summary?.successRate).toBe(0.33);\n      expect(result.summary?.uniqueErrorCount).toBe(2);\n    });\n\n    it('should categorize errors and include them in the summary', () => {\n      const mockVitestResults = {\n        success: false,\n        numTotalTests: 4,\n        numPassedTests: 1,\n        numFailedTests: 3,\n        testResults: [\n          {\n            assertionResults: [\n              {\n                fullName: 'Story1',\n                status: 'passed',\n                failureMessages: [],\n              },\n              {\n                fullName: 'Story2',\n                status: 'failed',\n                failureMessages: [\n                  'Error: Cannot read property \"x\" of undefined\\n  at /deps/styled-components.js:1168:14',\n                ],\n              },\n              {\n                fullName: 'Story3',\n                status: 'failed',\n                failureMessages: [\n                  'Error: Cannot read property \"x\" of undefined\\n  at /deps/styled-components.js:1168:14',\n                ],\n              },\n              {\n                fullName: 'Story4',\n                status: 'failed',\n                failureMessages: ['Error: Module not found: react-router\\n  at import statement'],\n              },\n              {\n                fullName: 'Story5',\n                status: 'failed',\n                failureMessages: ['Error: Invalid hook call\\n  at useEffect'],\n              },\n            ],\n          },\n        ],\n      };\n\n      const result = parseVitestResults(mockVitestResults);\n\n      expect(result.summary?.total).toBe(4);\n      expect(result.summary?.passed).toBe(1);\n      expect(result.summary?.uniqueErrorCount).toBe(3);\n      expect(result.summary?.categorizedErrors).toEqual({\n        HOOK_USAGE_ERROR: {\n          uniqueCount: 1,\n          count: 1,\n          matchedDependencies: [],\n        },\n        MISSING_THEME_PROVIDER: {\n          uniqueCount: 1,\n          count: 2,\n          matchedDependencies: ['styled-components'],\n        },\n        MODULE_IMPORT_ERROR: {\n          uniqueCount: 1,\n          count: 1,\n          matchedDependencies: [],\n        },\n      });\n    });\n\n    it('should detect empty render reports', () => {\n      const mockVitestResults = {\n        success: true,\n        numTotalTests: 3,\n        numPassedTests: 3,\n        numFailedTests: 0,\n        testResults: [\n          {\n            assertionResults: [\n              {\n                fullName: 'Story1',\n                status: 'passed',\n                meta: {\n                  reports: [{ type: 'render-analysis', result: { emptyRender: false } }],\n                },\n                failureMessages: [],\n              },\n              {\n                fullName: 'Story2',\n                status: 'passed',\n                meta: {\n                  reports: [{ type: 'render-analysis', result: { emptyRender: true } }],\n                },\n                failureMessages: [],\n              },\n              {\n                fullName: 'Story3',\n                status: 'passed',\n                meta: {\n                  reports: [{ type: 'render-analysis', result: { emptyRender: true } }],\n                },\n                failureMessages: [],\n              },\n            ],\n          },\n        ],\n      };\n\n      const result = parseVitestResults(mockVitestResults);\n\n      expect(result.summary?.passedButEmptyRender).toBe(2);\n      expect(result.summary?.successRate).toBe(1.0);\n      expect(result.summary?.successRateWithoutEmptyRender).toBe(0.33);\n    });\n\n    it('should handle multiple test suites', () => {\n      const mockVitestResults = {\n        success: true,\n        numTotalTests: 4,\n        numPassedTests: 3,\n        numFailedTests: 1,\n        testResults: [\n          {\n            assertionResults: [\n              {\n                fullName: 'Suite1-Story1',\n                status: 'passed',\n                failureMessages: [],\n              },\n              {\n                fullName: 'Suite1-Story2',\n                status: 'failed',\n                failureMessages: ['Error: Test failed'],\n              },\n            ],\n          },\n          {\n            assertionResults: [\n              {\n                fullName: 'Suite2-Story1',\n                status: 'passed',\n                failureMessages: [],\n              },\n              {\n                fullName: 'Suite2-Story2',\n                status: 'passed',\n                failureMessages: [],\n              },\n            ],\n          },\n        ],\n      };\n\n      const result = parseVitestResults(mockVitestResults);\n\n      expect(result.summary?.total).toBe(4);\n      expect(result.summary?.passed).toBe(3);\n    });\n\n    it('should handle zero total tests', () => {\n      const mockVitestResults = {\n        success: true,\n        numTotalTests: 0,\n        numPassedTests: 0,\n        numFailedTests: 0,\n        testResults: [],\n      };\n\n      const result = parseVitestResults(mockVitestResults);\n\n      expect(result.summary?.total).toBe(0);\n      expect(result.summary?.successRate).toBe(0);\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/ghost-stories/parse-vitest-report.ts",
    "content": "import type { ErrorCategory } from '../../../shared/utils/categorize-render-errors.ts';\nimport { categorizeError } from '../../../shared/utils/categorize-render-errors.ts';\nimport {\n  type ErrorCategorizationResult,\n  type StoryTestResult,\n  type TestRunSummary,\n} from './types.ts';\n\n/**\n * For a given list of test results:\n *\n * - Go through failures\n * - Categorize errors into categories\n * - Return structured data about the run, with categorized errors instead of the actual error\n *   messages\n */\nfunction extractCategorizedErrors(testResults: StoryTestResult[]): ErrorCategorizationResult {\n  const failed = testResults.filter((r) => r.status === 'FAIL' && r.error);\n\n  // Map: category -> { count, uniqueErrors: Set<string>, matchedDependencies }\n  const map = new Map<\n    ErrorCategory,\n    { count: number; uniqueErrors: Set<string>; matchedDependencies: Set<string> }\n  >();\n\n  // To count unique error messages (by their message, not by category)\n  const uniqueErrorMessages = new Set<string>();\n\n  for (const r of failed) {\n    const { category, matchedDependencies } = categorizeError(r.error!, r.stack);\n\n    if (!map.has(category)) {\n      map.set(category, { count: 0, uniqueErrors: new Set(), matchedDependencies: new Set() });\n    }\n\n    const data = map.get(category)!;\n    data.count++;\n    matchedDependencies.forEach((dep) => data.matchedDependencies.add(dep));\n\n    // Use the full error message for unique error message counting\n    uniqueErrorMessages.add(r.error!);\n    data.uniqueErrors.add(r.error!);\n  }\n\n  const categorizedErrors = Array.from(map.entries()).reduce<Record<string, any>>(\n    (acc, [category, data]) => {\n      acc[category] = {\n        uniqueCount: data.uniqueErrors.size,\n        count: data.count,\n        matchedDependencies: Array.from(data.matchedDependencies).sort(),\n      };\n      return acc;\n    },\n    {}\n  );\n\n  return {\n    totalErrors: failed.length,\n    uniqueErrorCount: uniqueErrorMessages.size,\n    categorizedErrors,\n  };\n}\n\n/** Transform the Vitest test results to our expected format and return a TestRunSummary */\nexport function parseVitestResults(report: any): TestRunSummary {\n  // Transform the Vitest test results to our expected format\n  const storyTestResults: StoryTestResult[] = [];\n  let passedButEmptyRender = 0;\n\n  for (const testSuite of report.testResults) {\n    for (const assertion of testSuite.assertionResults) {\n      const storyId = assertion.meta?.storyId || assertion.fullName;\n\n      const status =\n        assertion.status === 'passed' ? 'PASS' : assertion.status === 'failed' ? 'FAIL' : 'PENDING';\n\n      // Check for empty render in reports\n      const hasEmptyRender = assertion.meta?.reports?.some(\n        (report: { type: string; result?: { emptyRender?: boolean } }) =>\n          report.type === 'render-analysis' && report.result?.emptyRender === true\n      );\n\n      if (status === 'PASS' && hasEmptyRender) {\n        passedButEmptyRender++;\n      }\n\n      // Extract error message (first line of failureMessages)\n      let error: string | undefined;\n      let stack: string | undefined;\n      if (assertion.failureMessages && assertion.failureMessages.length > 0) {\n        stack = assertion.failureMessages[0];\n        error = stack?.split('\\n')[0]; // Take only the first line\n      }\n\n      storyTestResults.push({\n        storyId,\n        status,\n        error,\n        stack,\n      });\n    }\n  }\n\n  const total = report.numTotalTests;\n  const passed = report.numPassedTests;\n  const successRate = total > 0 ? parseFloat((passed / total).toFixed(2)) : 0;\n  const successRateWithoutEmptyRender =\n    total > 0 ? parseFloat(((passed - passedButEmptyRender) / total).toFixed(2)) : 0;\n\n  // Extract and categorize unique errors\n  const errorClassification = extractCategorizedErrors(storyTestResults);\n  const categorizedErrors = errorClassification.categorizedErrors;\n\n  return {\n    summary: {\n      total,\n      passed,\n      passedButEmptyRender,\n      successRate,\n      successRateWithoutEmptyRender,\n      uniqueErrorCount: errorClassification.uniqueErrorCount,\n      categorizedErrors,\n    },\n  };\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/ghost-stories/run-story-tests.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { mkdir, readFile } from 'node:fs/promises';\n\nimport { executeCommand, resolvePathInStorybookCache } from 'storybook/internal/common';\n\nimport { join } from 'pathe';\n\nimport { parseVitestResults } from './parse-vitest-report.ts';\nimport type { TestRunSummary } from './types.ts';\n\nexport async function runStoryTests(componentFilePaths: string[]): Promise<TestRunSummary> {\n  try {\n    // Create the cache directory for story discovery tests\n    const cacheDir = resolvePathInStorybookCache('ghost-stories-tests');\n    await mkdir(cacheDir, { recursive: true });\n\n    // Create timestamped output file\n    const timestamp = Date.now();\n    const outputFile = join(cacheDir, `test-results-${timestamp}.json`);\n\n    // Start timing the command execution\n    const startTime = Date.now();\n    let testFailureMessage;\n\n    try {\n      // Execute the test runner command with specific story files\n      const testProcess = executeCommand({\n        command: 'npx',\n        args: [\n          'vitest',\n          'run',\n          '--reporter=json',\n          '--testTimeout=1000',\n          `--outputFile=${outputFile}`,\n          ...componentFilePaths,\n        ],\n        stdio: 'pipe',\n        env: {\n          STORYBOOK_COMPONENT_PATHS: componentFilePaths.join(';'),\n        },\n      });\n\n      await testProcess;\n    } catch (error) {\n      const execaError = error as { stdout?: string; stderr?: string };\n      const errorMessage = (execaError.stderr || String(error) || '').toLowerCase();\n      if (errorMessage.includes('browsertype.launch')) {\n        testFailureMessage = 'Playwright is not installed';\n      } else if (errorMessage.includes('startup error')) {\n        testFailureMessage = 'Startup Error';\n      } else if (errorMessage.includes('no tests found')) {\n        testFailureMessage = 'No tests found';\n      } else if (errorMessage.includes('test timeout')) {\n        testFailureMessage = 'Test timeout';\n      } else if (errorMessage.includes('react-native-web')) {\n        testFailureMessage = 'React Native Web error';\n      } else if (errorMessage.includes('unhandled rejection')) {\n        testFailureMessage = 'Unhandled Rejection';\n      }\n    }\n\n    // Calculate duration of the command execution\n    const duration = Date.now() - startTime;\n\n    if (testFailureMessage) {\n      return {\n        duration,\n        runError: testFailureMessage,\n      };\n    }\n\n    if (!existsSync(outputFile)) {\n      return {\n        duration,\n        runError: 'JSON report not found',\n      };\n    }\n\n    // Type is the return Vitest JSON report structure\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    let vitestReport: any;\n    try {\n      const resultsJson = await readFile(outputFile, 'utf8');\n      vitestReport = JSON.parse(resultsJson);\n    } catch {\n      return {\n        duration,\n        runError: 'Failed to read or parse JSON report',\n      };\n    }\n\n    if (!vitestReport.testResults || vitestReport.testResults.length === 0) {\n      return {\n        duration,\n        runError: 'No tests found',\n      };\n    }\n\n    return { ...parseVitestResults(vitestReport), duration };\n  } catch {\n    return {\n      runError: 'Uncaught error running story tests',\n      duration: 0,\n    };\n  }\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/ghost-stories/test-annotations.ts",
    "content": "import type { AfterEach } from 'storybook/internal/csf';\nimport { definePreviewAddon } from 'storybook/internal/csf';\n\nconst isEmptyRender = (element: Element) => {\n  const style = getComputedStyle(element);\n  const rect = element.getBoundingClientRect();\n\n  const rendersContent =\n    rect.width > 0 &&\n    rect.height > 0 &&\n    style.visibility !== 'hidden' &&\n    Number(style.opacity) > 0 &&\n    style.display !== 'none';\n\n  return !rendersContent;\n};\n\nconst afterEach: AfterEach = async ({ reporting, canvasElement, globals }) => {\n  try {\n    // We only run this through ghost stories runs\n    if (!globals.ghostStories) {\n      return;\n    }\n\n    const emptyRender = isEmptyRender(canvasElement.firstElementChild ?? canvasElement);\n\n    if (emptyRender) {\n      reporting.addReport({\n        type: 'render-analysis',\n        version: 1,\n        result: {\n          emptyRender,\n        },\n        status: 'warning',\n      });\n    }\n  } catch {}\n};\n\nexport default () => definePreviewAddon({ afterEach });\n"
  },
  {
    "path": "code/core/src/core-server/utils/ghost-stories/types.ts",
    "content": "export interface StoryTestResult {\n  storyId: string;\n  status: 'PASS' | 'FAIL' | 'PENDING';\n  error?: string;\n  stack?: string;\n}\n\nexport interface CategorizedError {\n  category: string;\n  count: number;\n  uniqueCount: number;\n  matchedDependencies: string[];\n}\n\nexport interface ErrorCategorizationResult {\n  totalErrors: number;\n  categorizedErrors: Record<string, CategorizedError>;\n  uniqueErrorCount: number;\n}\n\nexport interface TestRunSummary {\n  duration?: number;\n  summary?: {\n    total: number;\n    passed: number;\n    passedButEmptyRender: number;\n    successRate: number;\n    successRateWithoutEmptyRender: number;\n    uniqueErrorCount: number;\n    categorizedErrors: Record<string, CategorizedError>;\n  };\n  // Error message if the operation failed\n  runError?: string;\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/index-json.test.ts",
    "content": "import { join } from 'node:path';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { normalizeStoriesEntry } from 'storybook/internal/common';\nimport { STORY_INDEX_INVALIDATED } from 'storybook/internal/core-events';\n\nimport { debounce } from 'es-toolkit/function';\nimport type { Polka, Request, Response } from 'polka';\nimport Watchpack from 'watchpack';\n\nimport { csfIndexer } from '../presets/common-preset.ts';\nimport type { StoryIndexGeneratorOptions } from './StoryIndexGenerator.ts';\nimport { StoryIndexGenerator } from './StoryIndexGenerator.ts';\nimport type { ServerChannel } from './get-server-channel.ts';\nimport { DEBOUNCE, registerIndexJsonRoute } from './index-json.ts';\n\nvi.mock('watchpack');\nvi.mock('es-toolkit/function', { spy: true });\nvi.mock('storybook/internal/node-logger');\n\nvi.mock('../utils/constants', () => {\n  return {\n    defaultStaticDirs: [{ from: './from', to: './to' }],\n    defaultFavicon: './favicon.svg',\n  };\n});\n\nconst workingDir = join(__dirname, '__mockdata__');\nconst normalizedStories = [\n  normalizeStoriesEntry(\n    {\n      titlePrefix: '',\n      directory: './src',\n      files: '**/*.stories.@(ts|js|mjs|jsx)',\n    },\n    { workingDir, configDir: workingDir }\n  ),\n  normalizeStoriesEntry(\n    {\n      titlePrefix: '',\n      directory: './src',\n      files: '**/*.mdx',\n    },\n    { workingDir, configDir: workingDir }\n  ),\n];\n\nconst getStoryIndexGeneratorPromise = async (\n  overrides: any = {},\n  inputNormalizedStories = normalizedStories\n) => {\n  const options: StoryIndexGeneratorOptions = {\n    indexers: [csfIndexer],\n    configDir: workingDir,\n    workingDir,\n    docs: { defaultName: 'docs' },\n    ...overrides,\n  };\n  const generator = new StoryIndexGenerator(inputNormalizedStories, options);\n  await generator.initialize();\n  return generator;\n};\n\ndescribe('registerIndexJsonRoute', () => {\n  const use = vi.fn();\n  const app: Polka = { use } as any;\n  const end = vi.fn();\n  const write = vi.fn();\n  const response: Response = {\n    header: vi.fn(),\n    send: vi.fn(),\n    status: vi.fn(),\n    setHeader: vi.fn(),\n    flushHeaders: vi.fn(),\n    write,\n    flush: vi.fn(),\n    end,\n    on: vi.fn(),\n  } as any;\n\n  beforeEach(async () => {\n    use.mockClear();\n    end.mockClear();\n    write.mockClear();\n    vi.mocked(debounce).mockImplementation((cb) => cb as any);\n    Watchpack.mockClear();\n  });\n\n  const request: Request = {\n    headers: { accept: 'application/json' },\n  } as any;\n\n  describe('JSON endpoint', () => {\n    it('scans and extracts index', async () => {\n      const mockServerChannel = { emit: vi.fn() } as any as ServerChannel;\n      registerIndexJsonRoute({\n        app,\n        channel: mockServerChannel,\n        workingDir,\n        normalizedStories,\n        storyIndexGeneratorPromise: getStoryIndexGeneratorPromise(),\n      });\n\n      expect(use).toHaveBeenCalledTimes(1);\n      const route = use.mock.calls[0][1];\n\n      console.time('route');\n      await route(request, response);\n      console.timeEnd('route');\n\n      expect(end).toHaveBeenCalledTimes(1);\n      expect(JSON.parse(end.mock.calls[0][0])).toMatchInlineSnapshot(`\n        {\n          \"entries\": {\n            \"a--metaof\": {\n              \"id\": \"a--metaof\",\n              \"importPath\": \"./src/docs2/MetaOf.mdx\",\n              \"name\": \"MetaOf\",\n              \"storiesImports\": [\n                \"./src/A.stories.js\",\n              ],\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n                \"component-tag\",\n                \"story-tag\",\n                \"attached-mdx\",\n              ],\n              \"title\": \"A\",\n              \"type\": \"docs\",\n            },\n            \"a--second-docs\": {\n              \"id\": \"a--second-docs\",\n              \"importPath\": \"./src/docs2/SecondMetaOf.mdx\",\n              \"name\": \"Second Docs\",\n              \"storiesImports\": [\n                \"./src/A.stories.js\",\n              ],\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n                \"component-tag\",\n                \"story-tag\",\n                \"attached-mdx\",\n              ],\n              \"title\": \"A\",\n              \"type\": \"docs\",\n            },\n            \"a--story-one\": {\n              \"exportName\": \"StoryOne\",\n              \"id\": \"a--story-one\",\n              \"importPath\": \"./src/A.stories.js\",\n              \"name\": \"Story One\",\n              \"subtype\": \"story\",\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n                \"component-tag\",\n                \"story-tag\",\n              ],\n              \"title\": \"A\",\n              \"type\": \"story\",\n            },\n            \"b--docs\": {\n              \"id\": \"b--docs\",\n              \"importPath\": \"./src/B.stories.ts\",\n              \"name\": \"docs\",\n              \"storiesImports\": [],\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n                \"autodocs\",\n              ],\n              \"title\": \"B\",\n              \"type\": \"docs\",\n            },\n            \"b--story-one\": {\n              \"exportName\": \"StoryOne\",\n              \"id\": \"b--story-one\",\n              \"importPath\": \"./src/B.stories.ts\",\n              \"name\": \"Story One\",\n              \"subtype\": \"story\",\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n                \"autodocs\",\n              ],\n              \"title\": \"B\",\n              \"type\": \"story\",\n            },\n            \"componentpath-extension--story-one\": {\n              \"componentPath\": \"./src/componentPath/component.js\",\n              \"exportName\": \"StoryOne\",\n              \"id\": \"componentpath-extension--story-one\",\n              \"importPath\": \"./src/componentPath/extension.stories.js\",\n              \"name\": \"Story One\",\n              \"subtype\": \"story\",\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n              ],\n              \"title\": \"componentPath/extension\",\n              \"type\": \"story\",\n            },\n            \"componentpath-noextension--story-one\": {\n              \"componentPath\": \"./src/componentPath/component.js\",\n              \"exportName\": \"StoryOne\",\n              \"id\": \"componentpath-noextension--story-one\",\n              \"importPath\": \"./src/componentPath/noExtension.stories.js\",\n              \"name\": \"Story One\",\n              \"subtype\": \"story\",\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n              ],\n              \"title\": \"componentPath/noExtension\",\n              \"type\": \"story\",\n            },\n            \"componentpath-package--story-one\": {\n              \"componentPath\": \"component-package\",\n              \"exportName\": \"StoryOne\",\n              \"id\": \"componentpath-package--story-one\",\n              \"importPath\": \"./src/componentPath/package.stories.js\",\n              \"name\": \"Story One\",\n              \"subtype\": \"story\",\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n              ],\n              \"title\": \"componentPath/package\",\n              \"type\": \"story\",\n            },\n            \"d--docs\": {\n              \"id\": \"d--docs\",\n              \"importPath\": \"./src/D.stories.jsx\",\n              \"name\": \"docs\",\n              \"storiesImports\": [],\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n                \"autodocs\",\n              ],\n              \"title\": \"D\",\n              \"type\": \"docs\",\n            },\n            \"d--story-one\": {\n              \"exportName\": \"StoryOne\",\n              \"id\": \"d--story-one\",\n              \"importPath\": \"./src/D.stories.jsx\",\n              \"name\": \"Story One\",\n              \"subtype\": \"story\",\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n                \"autodocs\",\n              ],\n              \"title\": \"D\",\n              \"type\": \"story\",\n            },\n            \"docs2-componentreference--docs\": {\n              \"id\": \"docs2-componentreference--docs\",\n              \"importPath\": \"./src/docs2/ComponentReference.mdx\",\n              \"name\": \"docs\",\n              \"storiesImports\": [],\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n                \"unattached-mdx\",\n              ],\n              \"title\": \"docs2/ComponentReference\",\n              \"type\": \"docs\",\n            },\n            \"docs2-notitle--docs\": {\n              \"id\": \"docs2-notitle--docs\",\n              \"importPath\": \"./src/docs2/NoTitle.mdx\",\n              \"name\": \"docs\",\n              \"storiesImports\": [],\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n                \"unattached-mdx\",\n              ],\n              \"title\": \"docs2/NoTitle\",\n              \"type\": \"docs\",\n            },\n            \"docs2-tags--docs\": {\n              \"id\": \"docs2-tags--docs\",\n              \"importPath\": \"./src/docs2/Tags.mdx\",\n              \"name\": \"docs\",\n              \"storiesImports\": [],\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n                \"foo\",\n                \"bar\",\n                \"unattached-mdx\",\n              ],\n              \"title\": \"docs2/Tags\",\n              \"type\": \"docs\",\n            },\n            \"docs2-yabbadabbadooo--docs\": {\n              \"id\": \"docs2-yabbadabbadooo--docs\",\n              \"importPath\": \"./src/docs2/Title.mdx\",\n              \"name\": \"docs\",\n              \"storiesImports\": [],\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n                \"unattached-mdx\",\n              ],\n              \"title\": \"docs2/Yabbadabbadooo\",\n              \"type\": \"docs\",\n            },\n            \"example-button--story-one\": {\n              \"exportName\": \"StoryOne\",\n              \"id\": \"example-button--story-one\",\n              \"importPath\": \"./src/Button.stories.ts\",\n              \"name\": \"Story One\",\n              \"subtype\": \"story\",\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n                \"foobar\",\n              ],\n              \"title\": \"Example/Button\",\n              \"type\": \"story\",\n            },\n            \"first-nested-deeply-f--story-one\": {\n              \"exportName\": \"StoryOne\",\n              \"id\": \"first-nested-deeply-f--story-one\",\n              \"importPath\": \"./src/first-nested/deeply/F.stories.js\",\n              \"name\": \"Story One\",\n              \"subtype\": \"story\",\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n              ],\n              \"title\": \"first-nested/deeply/F\",\n              \"type\": \"story\",\n            },\n            \"first-nested-deeply-features--with-csf-1\": {\n              \"exportName\": \"WithCSF1\",\n              \"id\": \"first-nested-deeply-features--with-csf-1\",\n              \"importPath\": \"./src/first-nested/deeply/Features.stories.jsx\",\n              \"name\": \"With CSF 1\",\n              \"subtype\": \"story\",\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n              ],\n              \"title\": \"first-nested/deeply/Features\",\n              \"type\": \"story\",\n            },\n            \"first-nested-deeply-features--with-play\": {\n              \"exportName\": \"WithPlay\",\n              \"id\": \"first-nested-deeply-features--with-play\",\n              \"importPath\": \"./src/first-nested/deeply/Features.stories.jsx\",\n              \"name\": \"With Play\",\n              \"subtype\": \"story\",\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n                \"play-fn\",\n              ],\n              \"title\": \"first-nested/deeply/Features\",\n              \"type\": \"story\",\n            },\n            \"first-nested-deeply-features--with-render\": {\n              \"exportName\": \"WithRender\",\n              \"id\": \"first-nested-deeply-features--with-render\",\n              \"importPath\": \"./src/first-nested/deeply/Features.stories.jsx\",\n              \"name\": \"With Render\",\n              \"subtype\": \"story\",\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n              ],\n              \"title\": \"first-nested/deeply/Features\",\n              \"type\": \"story\",\n            },\n            \"first-nested-deeply-features--with-story-fn\": {\n              \"exportName\": \"WithStoryFn\",\n              \"id\": \"first-nested-deeply-features--with-story-fn\",\n              \"importPath\": \"./src/first-nested/deeply/Features.stories.jsx\",\n              \"name\": \"With Story Fn\",\n              \"subtype\": \"story\",\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n              ],\n              \"title\": \"first-nested/deeply/Features\",\n              \"type\": \"story\",\n            },\n            \"first-nested-deeply-features--with-test\": {\n              \"exportName\": \"WithTest\",\n              \"id\": \"first-nested-deeply-features--with-test\",\n              \"importPath\": \"./src/first-nested/deeply/Features.stories.jsx\",\n              \"name\": \"With Test\",\n              \"subtype\": \"story\",\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n                \"play-fn\",\n              ],\n              \"title\": \"first-nested/deeply/Features\",\n              \"type\": \"story\",\n            },\n            \"h--docs\": {\n              \"id\": \"h--docs\",\n              \"importPath\": \"./src/H.stories.mjs\",\n              \"name\": \"docs\",\n              \"storiesImports\": [],\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n                \"autodocs\",\n              ],\n              \"title\": \"H\",\n              \"type\": \"docs\",\n            },\n            \"h--story-one\": {\n              \"exportName\": \"StoryOne\",\n              \"id\": \"h--story-one\",\n              \"importPath\": \"./src/H.stories.mjs\",\n              \"name\": \"Story One\",\n              \"subtype\": \"story\",\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n                \"autodocs\",\n              ],\n              \"title\": \"H\",\n              \"type\": \"story\",\n            },\n            \"nested-button--story-one\": {\n              \"exportName\": \"StoryOne\",\n              \"id\": \"nested-button--story-one\",\n              \"importPath\": \"./src/nested/Button.stories.ts\",\n              \"name\": \"Story One\",\n              \"subtype\": \"story\",\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n                \"component-tag\",\n              ],\n              \"title\": \"nested/Button\",\n              \"type\": \"story\",\n            },\n            \"second-nested-g--story-one\": {\n              \"exportName\": \"StoryOne\",\n              \"id\": \"second-nested-g--story-one\",\n              \"importPath\": \"./src/second-nested/G.stories.ts\",\n              \"name\": \"Story One\",\n              \"subtype\": \"story\",\n              \"tags\": [\n                \"dev\",\n                \"test\",\n                \"manifest\",\n              ],\n              \"title\": \"second-nested/G\",\n              \"type\": \"story\",\n            },\n          },\n          \"v\": 5,\n        }\n      `);\n    }, 20_000);\n\n    it('can handle simultaneous access', async () => {\n      const mockServerChannel = { emit: vi.fn() } as any as ServerChannel;\n\n      registerIndexJsonRoute({\n        app,\n        channel: mockServerChannel,\n        workingDir,\n        normalizedStories,\n        storyIndexGeneratorPromise: getStoryIndexGeneratorPromise(),\n      });\n\n      expect(use).toHaveBeenCalledTimes(1);\n      const route = use.mock.calls[0][1];\n\n      const firstPromise = route(request, response);\n      const secondResponse = { ...response, end: vi.fn(), status: vi.fn() };\n      const secondPromise = route(request, secondResponse);\n\n      await Promise.all([firstPromise, secondPromise]);\n      expect(end).toHaveBeenCalledTimes(1);\n      expect(response.statusCode).not.toEqual(500);\n      expect(secondResponse.end).toHaveBeenCalledTimes(1);\n      expect(secondResponse.status).not.toEqual(500);\n    });\n  });\n\n  describe('SSE endpoint', () => {\n    beforeEach(() => {\n      use.mockClear();\n      end.mockClear();\n    });\n\n    it('sends invalidate events', async () => {\n      const mockServerChannel = { emit: vi.fn() } as any as ServerChannel;\n      registerIndexJsonRoute({\n        app,\n        channel: mockServerChannel,\n        workingDir,\n        normalizedStories,\n        storyIndexGeneratorPromise: getStoryIndexGeneratorPromise(),\n      });\n\n      expect(use).toHaveBeenCalledTimes(1);\n      const route = use.mock.calls[0][1];\n\n      await route(request, response);\n\n      expect(write).not.toHaveBeenCalled();\n\n      expect(Watchpack).toHaveBeenCalledTimes(1);\n      const watcher = Watchpack.mock.instances[0];\n      expect(watcher.watch).toHaveBeenCalledWith(\n        expect.objectContaining({\n          directories: expect.any(Array),\n          files: expect.any(Array),\n        })\n      );\n\n      expect(watcher.on).toHaveBeenCalledTimes(2);\n      const onChange = watcher.on.mock.calls[0][1];\n\n      onChange(`${workingDir}/src/nested/Button.stories.ts`);\n      // Wait for the batched events to be processed\n      await vi.waitFor(() => {\n        expect(mockServerChannel.emit).toHaveBeenCalledTimes(1);\n      });\n      expect(mockServerChannel.emit).toHaveBeenCalledWith(STORY_INDEX_INVALIDATED);\n    });\n\n    it('only sends one invalidation when multiple event listeners are listening', async () => {\n      const mockServerChannel = { emit: vi.fn() } as any as ServerChannel;\n      registerIndexJsonRoute({\n        app,\n        channel: mockServerChannel,\n        workingDir,\n        normalizedStories,\n        storyIndexGeneratorPromise: getStoryIndexGeneratorPromise(),\n      });\n\n      expect(use).toHaveBeenCalledTimes(1);\n      const route = use.mock.calls[0][1];\n\n      // Don't wait for the first request here before starting the second\n      await Promise.all([\n        route(request, response),\n        route(request, { ...response, write: vi.fn() }),\n      ]);\n\n      expect(write).not.toHaveBeenCalled();\n\n      expect(Watchpack).toHaveBeenCalledTimes(1);\n      const watcher = Watchpack.mock.instances[0];\n      expect(watcher.watch).toHaveBeenCalledWith(\n        expect.objectContaining({\n          directories: expect.any(Array),\n          files: expect.any(Array),\n        })\n      );\n\n      expect(watcher.on).toHaveBeenCalledTimes(2);\n      const onChange = watcher.on.mock.calls[0][1];\n\n      onChange(`${workingDir}/src/nested/Button.stories.ts`);\n      // Wait for the batched events to be processed\n      await vi.waitFor(() => {\n        expect(mockServerChannel.emit).toHaveBeenCalledTimes(1);\n      });\n      expect(mockServerChannel.emit).toHaveBeenCalledWith(STORY_INDEX_INVALIDATED);\n    });\n\n    it('debounces invalidation events', async () => {\n      vi.mocked(debounce).mockImplementation(\n        (await vi.importActual<typeof import('es-toolkit/function')>('es-toolkit/function'))\n          .debounce\n      );\n\n      const mockServerChannel = { emit: vi.fn() } as any as ServerChannel;\n      registerIndexJsonRoute({\n        app,\n        channel: mockServerChannel,\n        workingDir,\n        normalizedStories,\n        storyIndexGeneratorPromise: getStoryIndexGeneratorPromise(),\n      });\n\n      expect(use).toHaveBeenCalledTimes(1);\n      const route = use.mock.calls[0][1];\n\n      await route(request, response);\n\n      expect(write).not.toHaveBeenCalled();\n\n      expect(Watchpack).toHaveBeenCalledTimes(1);\n      const watcher = Watchpack.mock.instances[0];\n      expect(watcher.watch).toHaveBeenCalledWith(\n        expect.objectContaining({\n          directories: expect.any(Array),\n          files: expect.any(Array),\n        })\n      );\n\n      expect(watcher.on).toHaveBeenCalledTimes(2);\n      const onChange = watcher.on.mock.calls[0][1];\n\n      // Fire multiple change events in rapid succession\n      // These get batched by watchStorySpecifiers (100ms batching window)\n      // and then debounced by maybeInvalidate (100ms debounce)\n      onChange(`${workingDir}/src/nested/Button.stories.ts`);\n      onChange(`${workingDir}/src/nested/Button.stories.ts`);\n      onChange(`${workingDir}/src/nested/Button.stories.ts`);\n      onChange(`${workingDir}/src/nested/Button.stories.ts`);\n      onChange(`${workingDir}/src/nested/Button.stories.ts`);\n\n      // Wait for first batch to be processed and emit (leading edge)\n      await vi.waitFor(() => {\n        expect(mockServerChannel.emit).toHaveBeenCalledTimes(1);\n      });\n      expect(mockServerChannel.emit).toHaveBeenCalledWith(STORY_INDEX_INVALIDATED);\n\n      // Fire another change event after the first batch is processed\n      // This will trigger the trailing edge of the debounce\n      onChange(`${workingDir}/src/nested/Button.stories.ts`);\n\n      // Wait for trailing debounce to trigger second emit\n      await vi.waitFor(() => {\n        expect(mockServerChannel.emit).toHaveBeenCalledTimes(2);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/index-json.ts",
    "content": "import { writeFile } from 'node:fs/promises';\nimport { basename } from 'node:path';\n\nimport type { ChannelLike } from 'storybook/internal/channels';\nimport { STORY_INDEX_INVALIDATED } from 'storybook/internal/core-events';\nimport type { NormalizedStoriesSpecifier } from 'storybook/internal/types';\n\nimport { debounce } from 'es-toolkit/function';\nimport type { Polka } from 'polka';\n\nimport type { StoryIndexGenerator } from './StoryIndexGenerator.ts';\nimport { watchStorySpecifiers } from './watch-story-specifiers.ts';\nimport { watchConfig } from './watchConfig.ts';\n\nexport const DEBOUNCE = 100;\n\nexport async function writeIndexJson(\n  outputFile: string,\n  initializedStoryIndexGenerator: Promise<StoryIndexGenerator>\n) {\n  const generator = await initializedStoryIndexGenerator;\n  const storyIndex = await generator.getIndex();\n  await writeFile(outputFile, JSON.stringify(storyIndex));\n}\n\nexport function registerIndexJsonRoute({\n  app,\n  storyIndexGeneratorPromise,\n  workingDir = process.cwd(),\n  configDir,\n  channel,\n  normalizedStories,\n}: {\n  app: Polka;\n  storyIndexGeneratorPromise: Promise<StoryIndexGenerator>;\n  channel: ChannelLike;\n  workingDir?: string;\n  configDir?: string;\n  normalizedStories: NormalizedStoriesSpecifier[];\n}) {\n  const maybeInvalidate = debounce(() => channel.emit(STORY_INDEX_INVALIDATED), DEBOUNCE, {\n    edges: ['leading', 'trailing'],\n  });\n  watchStorySpecifiers(normalizedStories, { workingDir }, async (path, removed) => {\n    (await storyIndexGeneratorPromise).invalidate(path, removed);\n    maybeInvalidate();\n  });\n  if (configDir) {\n    watchConfig(configDir, async (filePath) => {\n      if (basename(filePath).startsWith('preview')) {\n        (await storyIndexGeneratorPromise).invalidateAll();\n        maybeInvalidate();\n      }\n    });\n  }\n\n  app.use('/index.json', async (req, res) => {\n    try {\n      const index = await (await storyIndexGeneratorPromise).getIndex();\n      res.setHeader('Content-Type', 'application/json');\n      res.setHeader('Access-Control-Allow-Origin', '*');\n      res.setHeader(\n        'Access-Control-Allow-Headers',\n        'Origin, X-Requested-With, Content-Type, Accept'\n      );\n      res.end(JSON.stringify(index));\n    } catch (err) {\n      res.statusCode = 500;\n      res.end(err instanceof Error ? err.toString() : String(err));\n    }\n  });\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/manifests/manifests.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { logger } from 'storybook/internal/node-logger';\nimport type { ComponentsManifest, Manifests, Presets, StoryIndex } from 'storybook/internal/types';\n\nimport { vol } from 'memfs';\nimport type { Polka } from 'polka';\n\nimport { Tag } from '../../../shared/constants/tags.ts';\nimport { registerManifests, writeManifests } from './manifests.ts';\n\n// Mock dependencies\nvi.mock('node:fs/promises', async () => {\n  const fs = (await import('memfs')).fs.promises;\n  return { default: fs, ...fs };\n});\nvi.mock('storybook/internal/node-logger');\n\ndescribe('manifests', () => {\n  let mockGenerator: { getIndex: ReturnType<typeof vi.fn> };\n  let mockManifests: Manifests | null;\n\n  type RouteHandler = (req: { params?: { name?: string } }, res: MockResponse) => Promise<void>;\n  type MockResponse = {\n    setHeader: ReturnType<typeof vi.fn>;\n    end: ReturnType<typeof vi.fn>;\n    statusCode?: number | undefined;\n  };\n\n  const createResponse = (): MockResponse => ({\n    setHeader: vi.fn(),\n    end: vi.fn(),\n    statusCode: undefined,\n  });\n\n  const setupMockPresets = () => {\n    mockGenerator = {\n      getIndex: vi.fn().mockResolvedValue({\n        entries: {},\n      } as StoryIndex),\n    };\n    mockManifests = {};\n\n    return {\n      apply: vi.fn().mockImplementation((key: string) => {\n        switch (key) {\n          case 'storyIndexGenerator':\n            return Promise.resolve(mockGenerator);\n          case 'experimental_manifests':\n            return Promise.resolve(mockManifests ?? undefined);\n          default:\n            return Promise.resolve(undefined);\n        }\n      }),\n    } satisfies Presets;\n  };\n\n  beforeEach(() => {\n    vol.reset();\n    vi.clearAllMocks();\n  });\n\n  describe('writeManifests', () => {\n    let mockPresets: Presets;\n\n    beforeEach(() => {\n      mockPresets = setupMockPresets();\n    });\n\n    it('should do nothing when manifests are empty', async () => {\n      mockManifests = {};\n\n      await writeManifests('/output', mockPresets);\n\n      expect(vol.toJSON()).toEqual({});\n    });\n\n    it('should create manifests directory and write JSON files', async () => {\n      mockManifests = {\n        custom: { data: 'value' },\n        another: { items: [1, 2, 3] },\n      };\n\n      await writeManifests('/output', mockPresets);\n\n      const files = vol.toJSON();\n      expect(files['/output/manifests/custom.json']).toBe(JSON.stringify({ data: 'value' }));\n      expect(files['/output/manifests/another.json']).toBe(JSON.stringify({ items: [1, 2, 3] }));\n    });\n\n    it('should write HTML file when components manifest exists', async () => {\n      const componentsManifest: ComponentsManifest = {\n        v: 0,\n        components: {\n          Button: {\n            id: 'button',\n            name: 'Button',\n            path: './Button.tsx',\n            stories: [],\n            jsDocTags: {},\n          },\n        },\n      };\n      mockManifests = {\n        components: componentsManifest,\n      };\n\n      await writeManifests('/output', mockPresets);\n\n      const files = vol.toJSON();\n      expect(files['/output/manifests/components.html']).toBeDefined();\n      expect(files['/output/manifests/components.html']).toContain('<!doctype html>');\n    });\n\n    it('should write HTML file when docs manifest exists', async () => {\n      mockManifests = {\n        docs: {\n          v: 0,\n          docs: {\n            'intro--docs': {\n              id: 'intro--docs',\n              name: 'docs',\n              path: './Intro.mdx',\n              title: 'Intro',\n              content: '# Introduction',\n            },\n          },\n        },\n      };\n\n      await writeManifests('/output', mockPresets);\n\n      const files = vol.toJSON();\n      expect(files['/output/manifests/components.html']).toBeDefined();\n      expect(files['/output/manifests/components.html']).toContain('<!doctype html>');\n      expect(files['/output/manifests/components.html']).toContain('Unattached Docs');\n    });\n\n    it('should handle errors when presets.apply fails', async () => {\n      const error = new Error('Preset application failed');\n      vi.mocked(mockPresets.apply).mockRejectedValue(error);\n\n      await writeManifests('/output', mockPresets);\n\n      expect(vi.mocked(logger).error).toHaveBeenCalledWith('Failed to generate manifests');\n      expect(vi.mocked(logger).error).toHaveBeenCalledWith(error);\n      expect(vol.toJSON()).toEqual({});\n    });\n\n    it('should handle non-Error objects in catch block', async () => {\n      const errorString = 'Something went wrong';\n      vi.mocked(mockPresets.apply).mockRejectedValue(errorString);\n\n      await writeManifests('/output', mockPresets);\n\n      expect(vi.mocked(logger).error).toHaveBeenCalledWith('Failed to generate manifests');\n      expect(vi.mocked(logger).error).toHaveBeenCalledWith(errorString);\n    });\n\n    it('should filter entries by manifest tag and pass manifestEntries to preset', async () => {\n      mockGenerator.getIndex.mockResolvedValue({\n        v: 5,\n        entries: {\n          'story-with-manifest': {\n            type: 'story',\n            subtype: 'story',\n            id: 'story-with-manifest',\n            name: 'Story',\n            title: 'Example',\n            importPath: './Example.stories.tsx',\n            tags: [Tag.MANIFEST, 'other'],\n          },\n          'story-without-manifest': {\n            type: 'story',\n            subtype: 'story',\n            id: 'story-without-manifest',\n            name: 'Other',\n            title: 'Other',\n            importPath: './Other.stories.tsx',\n            tags: ['other'],\n          },\n          'docs-entry': {\n            type: 'docs',\n            id: 'docs',\n            name: 'Docs',\n            title: 'Docs',\n            importPath: './Docs.mdx',\n            tags: [Tag.MANIFEST],\n            storiesImports: [],\n          },\n        },\n      } as StoryIndex);\n\n      mockManifests = { custom: { data: 'value' } };\n\n      await writeManifests('/output', mockPresets);\n\n      expect(mockPresets.apply).toHaveBeenCalledWith(\n        'experimental_manifests',\n        undefined,\n        expect.objectContaining({\n          manifestEntries: expect.arrayContaining([\n            expect.objectContaining({ id: 'story-with-manifest' }),\n          ]),\n        })\n      );\n\n      // Get the specific apply call to the experimental_manifests preset\n      const manifestsPresetCall = vi\n        .mocked(mockPresets.apply)\n        .mock.calls.find((call) => call[0] === 'experimental_manifests');\n\n      expect(manifestsPresetCall).toBeDefined();\n      const manifestEntriesArg =\n        (manifestsPresetCall?.[2] as { manifestEntries?: Array<{ id: string }> })\n          ?.manifestEntries ?? [];\n\n      // Should include both story and docs entries with manifest tag\n      expect(manifestEntriesArg).toHaveLength(2);\n      const entryIds = manifestEntriesArg.map((entry) => entry.id);\n      expect(entryIds).toContain('story-with-manifest');\n      expect(entryIds).toContain('docs');\n      // Should NOT include story without manifest tag\n      expect(entryIds).not.toContain('story-without-manifest');\n    });\n  });\n\n  describe('registerManifests', () => {\n    let mockApp: Polka;\n    let mockGet: ReturnType<typeof vi.fn>;\n    let mockPresets: Presets;\n\n    beforeEach(() => {\n      mockGet = vi.fn();\n      mockApp = { get: mockGet } as unknown as Polka;\n      mockPresets = setupMockPresets();\n    });\n\n    describe('route registration', () => {\n      it('should register two routes', () => {\n        registerManifests({ app: mockApp, presets: mockPresets });\n\n        expect(mockGet).toHaveBeenCalledTimes(2);\n        expect(mockGet).toHaveBeenCalledWith('/manifests/:name.json', expect.any(Function));\n        expect(mockGet).toHaveBeenCalledWith('/manifests/components.html', expect.any(Function));\n      });\n    });\n\n    describe('/manifests/:name.json route', () => {\n      it('should return manifest as JSON when it exists', async () => {\n        mockManifests = {\n          custom: { data: 'value' },\n        };\n\n        registerManifests({ app: mockApp, presets: mockPresets });\n\n        const handler = mockGet.mock.calls[0][1] as RouteHandler;\n        const req = { params: { name: 'custom' } };\n        const res = createResponse();\n\n        await handler(req, res);\n\n        expect(res.setHeader).toHaveBeenCalledWith('Content-Type', 'application/json');\n        expect(res.end).toHaveBeenCalledWith(JSON.stringify({ data: 'value' }));\n        expect(res.statusCode).toBeUndefined();\n      });\n\n      it('should return 404 when manifest does not exist', async () => {\n        mockManifests = {\n          existing: { data: 'value' },\n        };\n\n        registerManifests({ app: mockApp, presets: mockPresets });\n\n        const handler = mockGet.mock.calls[0][1] as RouteHandler;\n        const req = { params: { name: 'nonexistent' } };\n        const res = createResponse();\n\n        await handler(req, res);\n\n        expect(res.statusCode).toBe(404);\n        expect(res.end).toHaveBeenCalledWith('Manifest \"nonexistent\" not found');\n      });\n\n      it('should return 404 when manifests object is empty', async () => {\n        mockManifests = {};\n\n        registerManifests({ app: mockApp, presets: mockPresets });\n\n        const handler = mockGet.mock.calls[0][1] as RouteHandler;\n        const req = { params: { name: 'any' } };\n        const res = createResponse();\n\n        await handler(req, res);\n\n        expect(res.statusCode).toBe(404);\n        expect(res.end).toHaveBeenCalledWith('Manifest \"any\" not found');\n      });\n\n      it('should handle errors with 500 status and log the error', async () => {\n        const error = new Error('Preset failed');\n        vi.mocked(mockPresets.apply).mockRejectedValue(error);\n\n        registerManifests({ app: mockApp, presets: mockPresets });\n\n        const handler = mockGet.mock.calls[0][1] as RouteHandler;\n        const req = { params: { name: 'custom' } };\n        const res = createResponse();\n\n        await handler(req, res);\n\n        expect(vi.mocked(logger).error).toHaveBeenCalledWith(error);\n        expect(res.statusCode).toBe(500);\n        expect(res.end).toHaveBeenCalledWith(error.toString());\n      });\n\n      it('should handle non-Error objects in error handler', async () => {\n        const errorString = 'Something went wrong';\n        vi.mocked(mockPresets.apply).mockRejectedValue(errorString);\n\n        registerManifests({ app: mockApp, presets: mockPresets });\n\n        const handler = mockGet.mock.calls[0][1] as RouteHandler;\n        const req = { params: { name: 'custom' } };\n        const res = createResponse();\n\n        await handler(req, res);\n\n        expect(vi.mocked(logger).error).toHaveBeenCalledWith(errorString);\n        expect(res.statusCode).toBe(500);\n        expect(res.end).toHaveBeenCalledWith(errorString);\n      });\n\n      it('should handle when presets.apply returns null/undefined', async () => {\n        mockManifests = null;\n\n        registerManifests({ app: mockApp, presets: mockPresets });\n\n        const handler = mockGet.mock.calls[0][1] as RouteHandler;\n        const req = { params: { name: 'custom' } };\n        const res = createResponse();\n\n        await handler(req, res);\n\n        expect(res.statusCode).toBe(404);\n        expect(res.end).toHaveBeenCalledWith('Manifest \"custom\" not found');\n      });\n    });\n\n    describe('/manifests/components.html route', () => {\n      it('should return rendered HTML when components manifest exists', async () => {\n        const componentsManifest: ComponentsManifest = {\n          v: 0,\n          components: {\n            Button: {\n              id: 'button',\n              name: 'Button',\n              path: './Button.tsx',\n              stories: [],\n              jsDocTags: {},\n            },\n          },\n        };\n        mockManifests = {\n          components: componentsManifest,\n        };\n\n        registerManifests({ app: mockApp, presets: mockPresets });\n\n        const handler = mockGet.mock.calls[1][1] as RouteHandler;\n        const req = {};\n        const res = createResponse();\n\n        await handler(req, res);\n\n        expect(res.setHeader).toHaveBeenCalledWith('Content-Type', 'text/html; charset=utf-8');\n        expect(res.end).toHaveBeenCalled();\n        const html = res.end.mock.calls[0]?.[0];\n        expect(html).toContain('<!doctype html>');\n        expect(html).toContain('Manifest Debugger');\n        expect(res.statusCode).toBeUndefined();\n      });\n\n      it('should return 404 message when no components or docs manifest exist', async () => {\n        mockManifests = {\n          other: { data: 'value' },\n        };\n\n        registerManifests({ app: mockApp, presets: mockPresets });\n\n        const handler = mockGet.mock.calls[1][1] as RouteHandler;\n        const req = {};\n        const res = createResponse();\n\n        await handler(req, res);\n\n        expect(res.statusCode).toBe(404);\n        expect(res.setHeader).toHaveBeenCalledWith('Content-Type', 'text/html; charset=utf-8');\n        expect(res.end).toHaveBeenCalledWith(\n          '<pre>No components or docs manifest configured.</pre>'\n        );\n      });\n\n      it('should return 404 when manifests is empty', async () => {\n        mockManifests = {};\n\n        registerManifests({ app: mockApp, presets: mockPresets });\n\n        const handler = mockGet.mock.calls[1][1] as RouteHandler;\n        const req = {};\n        const res = createResponse();\n\n        await handler(req, res);\n\n        expect(res.statusCode).toBe(404);\n        expect(res.end).toHaveBeenCalledWith(\n          '<pre>No components or docs manifest configured.</pre>'\n        );\n      });\n\n      it('should handle errors with 500 status and return error HTML', async () => {\n        const error = new Error('Rendering failed');\n        error.stack = 'Error: Rendering failed\\n  at test.ts:123';\n        vi.mocked(mockPresets.apply).mockRejectedValue(error);\n\n        registerManifests({ app: mockApp, presets: mockPresets });\n\n        const handler = mockGet.mock.calls[1][1] as RouteHandler;\n        const req = {};\n        const res = createResponse();\n\n        await handler(req, res);\n\n        expect(res.statusCode).toBe(500);\n        expect(res.setHeader).toHaveBeenCalledWith('Content-Type', 'text/html; charset=utf-8');\n        expect(res.end).toHaveBeenCalledWith(\n          '<pre>Error: Rendering failed\\n  at test.ts:123</pre>'\n        );\n      });\n\n      it('should handle non-Error objects in error handler', async () => {\n        const errorString = 'Something went wrong';\n        vi.mocked(mockPresets.apply).mockRejectedValue(errorString);\n\n        registerManifests({ app: mockApp, presets: mockPresets });\n\n        const handler = mockGet.mock.calls[1][1] as RouteHandler;\n        const req = {};\n        const res = createResponse();\n\n        await handler(req, res);\n\n        expect(res.statusCode).toBe(500);\n        expect(res.setHeader).toHaveBeenCalledWith('Content-Type', 'text/html; charset=utf-8');\n        expect(res.end).toHaveBeenCalledWith(`<pre>${errorString}</pre>`);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/manifests/manifests.ts",
    "content": "import { mkdir, writeFile } from 'node:fs/promises';\n\nimport { logger } from 'storybook/internal/node-logger';\nimport type { Manifests, Presets } from 'storybook/internal/types';\n\nimport { join } from 'pathe';\nimport type { Polka } from 'polka';\nimport invariant from 'tiny-invariant';\n\nimport { Tag } from '../../../shared/constants/tags.ts';\nimport { type DocsManifest, renderComponentsManifest } from './render-components-manifest.ts';\n\nfunction isDocsManifest(manifest: unknown): manifest is DocsManifest {\n  return typeof manifest === 'object' && manifest !== null && 'docs' in manifest;\n}\n\nasync function getManifests(presets: Presets, { watch }: { watch?: boolean } = {}) {\n  const generator = await presets.apply('storyIndexGenerator');\n  invariant(generator, 'storyIndexGenerator must be configured');\n  const index = await generator.getIndex();\n  const manifestEntries = Object.values(index.entries).filter(\n    (entry) => entry.tags?.includes(Tag.MANIFEST) ?? false\n  );\n\n  return (\n    (await presets.apply<Manifests>('experimental_manifests', undefined, {\n      manifestEntries,\n      watch,\n    })) ?? {}\n  );\n}\n\nexport async function writeManifests(outputDir: string, presets: Presets) {\n  try {\n    const manifests = await getManifests(presets);\n    const docsManifest = isDocsManifest(manifests.docs) ? manifests.docs : undefined;\n\n    if (Object.keys(manifests).length === 0) {\n      return;\n    }\n    await mkdir(join(outputDir, 'manifests'), { recursive: true });\n    await Promise.all(\n      Object.entries(manifests).map(([name, content]) =>\n        writeFile(join(outputDir, 'manifests', `${name}.json`), JSON.stringify(content))\n      )\n    );\n    if ('components' in manifests || 'docs' in manifests) {\n      await writeFile(\n        join(outputDir, 'manifests', 'components.html'),\n        renderComponentsManifest(manifests.components, docsManifest)\n      );\n    }\n  } catch (e) {\n    logger.error('Failed to generate manifests');\n    logger.error(e instanceof Error ? e : String(e));\n  }\n}\n\nexport function registerManifests({ app, presets }: { app: Polka; presets: Presets }) {\n  app.get('/manifests/:name.json', async (req, res) => {\n    try {\n      const manifests = await getManifests(presets, { watch: true });\n      const manifest = manifests[req.params.name];\n\n      if (manifest) {\n        res.setHeader('Content-Type', 'application/json');\n        res.end(JSON.stringify(manifest));\n      } else {\n        res.statusCode = 404;\n        res.end(`Manifest \"${req.params.name}\" not found`);\n      }\n    } catch (e) {\n      logger.error(e instanceof Error ? e : String(e));\n      res.statusCode = 500;\n      res.end(e instanceof Error ? e.toString() : String(e));\n    }\n  });\n\n  app.get('/manifests/components.html', async (req, res) => {\n    try {\n      const manifests = await getManifests(presets, { watch: true });\n      const componentsManifest = manifests.components;\n      const docsManifest = isDocsManifest(manifests.docs) ? manifests.docs : undefined;\n\n      if (!componentsManifest && !docsManifest) {\n        res.statusCode = 404;\n        res.setHeader('Content-Type', 'text/html; charset=utf-8');\n        res.end(`<pre>No components or docs manifest configured.</pre>`);\n        return;\n      }\n\n      res.setHeader('Content-Type', 'text/html; charset=utf-8');\n      res.end(renderComponentsManifest(componentsManifest, docsManifest));\n    } catch (e) {\n      res.statusCode = 500;\n      res.setHeader('Content-Type', 'text/html; charset=utf-8');\n      res.end(`<pre>${e instanceof Error ? e.stack : String(e)}</pre>`);\n    }\n  });\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/manifests/render-components-manifest.ts",
    "content": "import path from 'node:path';\n\nimport { groupBy } from 'storybook/internal/common';\n\nimport type { ComponentDoc, PropItem } from 'react-docgen-typescript';\n\n// Type-only import to reuse the source-of-truth react-component-meta manifest shape\n// without creating a runtime dependency from core to the React renderer package.\nimport type { ComponentDoc as ReactComponentMetaDoc } from '../../../../../renderers/react/src/componentManifest/componentMeta/componentMetaExtractor.ts';\nimport type { ComponentManifest, ComponentsManifest } from '../../../types/index.ts';\n\n/** Minimal docs entry type for rendering in the manifest debugger */\ninterface DocsManifestEntry {\n  id: string;\n  name: string;\n  path: string;\n  title: string;\n  content?: string;\n  summary?: string;\n  error?: { name: string; message: string };\n}\n\n/** Minimal docs manifest type for rendering in the manifest debugger */\nexport interface DocsManifest {\n  v: number;\n  docs: Record<string, DocsManifestEntry>;\n}\n\n/** Extended component manifest that may include docs from the docs addon */\ninterface ComponentManifestWithDocs extends ComponentManifest {\n  docs?: Record<string, DocsManifestEntry>;\n  reactDocgen?: DocgenDoc;\n  reactDocgenTypescript?: RdtComponentDoc;\n  reactComponentMeta?: ReactComponentMetaDoc;\n}\n\n// AI generated manifests/components.html page\n// Only HTML/CSS no JS\nexport function renderComponentsManifest(\n  manifest: ComponentsManifest | undefined,\n  docsManifest?: DocsManifest\n) {\n  const entries = Object.entries(manifest?.components ?? {}).sort((a, b) =>\n    (a[1].name || a[0]).localeCompare(b[1].name || b[0])\n  );\n\n  // Get unattached docs entries\n  const docsEntries = Object.entries(docsManifest?.docs ?? {}).sort((a, b) =>\n    (a[1].name || a[0]).localeCompare(b[1].name || b[0])\n  );\n\n  const analyses = entries.map(([, c]) => analyzeComponent(c));\n  const docsAnalyses = docsEntries.map(([, d]) => analyzeDoc(d));\n  const attachedDocs = analyses.reduce((sum, a) => sum + a.totalDocs, 0);\n  const attachedDocsWithError = analyses.reduce((sum, a) => sum + a.docsErrors, 0);\n  const unattachedDocsWithError = docsAnalyses.filter((a) => a.hasError).length;\n  const totals = {\n    components: entries.length,\n    componentsWithPropTypeError: analyses.filter((a) => a.hasPropTypeError).length,\n    infos: analyses.filter((a) => a.hasWarns).length,\n    stories: analyses.reduce((sum, a) => sum + a.totalStories, 0),\n    storyErrors: analyses.reduce((sum, a) => sum + a.storyErrors, 0),\n    docs: docsEntries.length + attachedDocs,\n    docsWithError: unattachedDocsWithError + attachedDocsWithError,\n  };\n\n  const activeEngine = manifest?.meta?.docgen ?? 'react-docgen';\n  const durationMs = manifest?.meta?.durationMs ?? 0;\n\n  // Top filters (clickable), no <b> tags; 1px active ring lives in CSS via :target\n  const allPill = `<a class=\"filter-pill all\" data-k=\"all\" href=\"#filter-all\">All</a>`;\n  const compErrorsPill =\n    totals.componentsWithPropTypeError > 0\n      ? `<a class=\"filter-pill err\" data-k=\"errors\" href=\"#filter-errors\">${totals.componentsWithPropTypeError}/${totals.components} prop type ${plural(totals.componentsWithPropTypeError, 'error')}</a>`\n      : totals.components > 0\n        ? `<span class=\"filter-pill ok\" aria-disabled=\"true\">${totals.components} components ok</span>`\n        : '';\n  const compInfosPill =\n    totals.infos > 0\n      ? `<a class=\"filter-pill info\" data-k=\"infos\" href=\"#filter-infos\">${totals.infos}/${totals.components} ${plural(totals.infos, 'info', 'infos')}</a>`\n      : '';\n  const storiesPill =\n    totals.storyErrors > 0\n      ? `<a class=\"filter-pill err\" data-k=\"story-errors\" href=\"#filter-story-errors\">${totals.storyErrors}/${totals.stories} story errors</a>`\n      : totals.stories > 0\n        ? `<span class=\"filter-pill ok\" aria-disabled=\"true\">${totals.stories} ${plural(totals.stories, 'story', 'stories')} ok</span>`\n        : '';\n  const docsPill =\n    totals.docs > 0\n      ? totals.docsWithError > 0\n        ? `<a class=\"filter-pill info\" data-k=\"docs\" href=\"#filter-docs\">${totals.docsWithError}/${totals.docs} doc ${plural(totals.docsWithError, 'error')}</a>`\n        : `<a class=\"filter-pill ok\" data-k=\"docs\" href=\"#filter-docs\">${totals.docs} ${plural(totals.docs, 'doc')} ok</a>`\n      : '';\n\n  const grid = entries.map(([key, c], idx) => renderComponentCard(key, c, `${idx}`)).join('');\n  const docsGrid = docsEntries.map(([key, d], idx) => renderDocCard(key, d, `doc-${idx}`)).join('');\n\n  const errorGroups = Object.entries(\n    groupBy(\n      entries.map(([, it]) => it).filter((it) => it.error),\n      (manifest) => manifest.error?.name ?? 'Error'\n    )\n  ).sort(([, a], [, b]) => b.length - a.length);\n\n  const errorGroupsHTML = errorGroups\n    .map(([error, grouped]) => {\n      const id = error.toLowerCase().replace(/[^a-z0-9]+/g, '-');\n      const headerText = `${esc(error)}`;\n      const cards = grouped\n        .map((manifest, id) => renderComponentCard(manifest.id, manifest, `error-${id}`))\n        .join('');\n      return `\n        <section class=\"group\">\n          <input id=\"${id}-toggle\" class=\"group-tg\" type=\"checkbox\" hidden />\n          <label for=\"${id}-toggle\" class=\"group-header\">\n            <span class=\"caret\">▸</span>\n            <span class=\"group-title\">${headerText}</span>\n            <span class=\"group-count\">${grouped.length}</span>\n          </label>\n          <div class=\"group-cards\">${cards}</div>\n        </section>\n      `;\n    })\n    .join('');\n\n  return `<!doctype html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\" />\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <title>Components Manifest</title>\n  <style>\n      :root {\n          --bg: #0b0c10;\n          --panel: #121318;\n          --muted: #9aa0a6;\n          --fg: #e8eaed;\n          --ok: #22c55e;\n          --info: #1e88e5;\n          --err: #c62828;\n          --ok-bg: #0c1a13;\n          --info-bg: #0c1624;\n          --err-bg: #1a0e0e;\n          --chip: #1f2330;\n          --border: #2b2f3a;\n          --link: #8ab4f8;\n          --active-ring: 1px; /* 1px active ring for pills and toggles */\n      }\n\n      * {\n          box-sizing: border-box;\n      }\n\n      html,\n      body {\n          margin: 0;\n          background: var(--bg);\n          color: var(--fg);\n          font: 14px/1.5 system-ui,\n          -apple-system,\n          Segoe UI,\n          Roboto,\n          Ubuntu,\n          Cantarell,\n          'Helvetica Neue',\n          Arial,\n          'Noto Sans';\n      }\n\n      .wrap {\n          max-width: 1100px;\n          margin: 0 auto;\n          padding: 16px 20px;\n      }\n\n      header {\n          position: sticky;\n          top: 0;\n          backdrop-filter: blur(6px);\n          background: color-mix(in srgb, var(--bg) 84%, transparent);\n          border-bottom: 1px solid var(--border);\n          z-index: 10;\n      }\n\n      h1 {\n          font-size: 20px;\n          margin: 0 0 6px;\n      }\n\n      .summary {\n          display: flex;\n          gap: 12px;\n          flex-wrap: wrap;\n          align-items: center;\n      }\n\n      /* Top filter pills */\n      .filter-pill {\n          display: inline-flex;\n          align-items: center;\n          gap: 6px;\n          padding: 6px 12px;\n          border: 1px solid var(--border);\n          border-radius: 999px;\n          background: var(--panel);\n          text-decoration: none;\n          cursor: pointer;\n          user-select: none;\n          color: var(--fg);\n      }\n\n      .filter-pill.ok {\n          color: #b9f6ca;\n          border-color: color-mix(in srgb, var(--ok) 55%, var(--border));\n          background: color-mix(in srgb, var(--ok) 18%, #000);\n      }\n\n      .filter-pill.info {\n          color: #b3d9ff;\n          border-color: color-mix(in srgb, var(--info) 55%, var(--border));\n          background: var(--info-bg);\n      }\n\n      .filter-pill.err {\n          color: #ff9aa0;\n          border-color: color-mix(in srgb, var(--err) 55%, var(--border));\n          background: var(--err-bg);\n      }\n\n      .filter-pill.all {\n          color: #d7dbe0;\n          border-color: var(--border);\n          background: var(--panel);\n      }\n\n      .filter-pill[aria-disabled='true'] {\n          cursor: default;\n          text-decoration: none;\n      }\n\n      .filter-pill:focus,\n      .filter-pill:active {\n          outline: none;\n          box-shadow: none;\n      }\n\n      /* Selected top pill ring via :target */\n      #filter-all:target ~ header .filter-pill[data-k='all'],\n      #filter-errors:target ~ header .filter-pill[data-k='errors'],\n      #filter-infos:target ~ header .filter-pill[data-k='infos'],\n      #filter-story-errors:target ~ header .filter-pill[data-k='story-errors'],\n      #filter-doc-errors:target ~ header .filter-pill[data-k='docs'],\n      #filter-docs:target ~ header .filter-pill[data-k='docs'] {\n          box-shadow: 0 0 0 var(--active-ring) currentColor;\n          border-color: currentColor;\n      }\n\n      /* Hidden targets for filtering */\n      #filter-all,\n      #filter-errors,\n      #filter-infos,\n      #filter-story-errors,\n      #filter-doc-errors,\n      #filter-docs {\n          display: none;\n      }\n\n      main {\n          padding: 36px 0 40px;\n      }\n\n      .grid {\n          display: grid;\n          grid-template-columns: 1fr;\n          gap: 18px;\n      }\n\n      /* one card per row */\n\n      .card {\n          border: 1px solid var(--border);\n          background: var(--panel);\n          border-radius: 14px;\n          padding: 14px;\n          display: flex;\n          flex-direction: column;\n          gap: 10px;\n      }\n\n      .head {\n          display: flex;\n          flex-direction: column;\n          gap: 8px;\n      }\n\n      .title {\n          display: flex;\n          align-items: center;\n          justify-content: space-between;\n          gap: 10px;\n      }\n\n      .title h2 {\n          font-size: 16px;\n          margin: 0;\n          overflow: hidden;\n          text-overflow: ellipsis;\n          white-space: nowrap;\n      }\n\n      .meta {\n          font-size: 12px;\n          color: var(--muted);\n          overflow: hidden;\n          text-overflow: ellipsis;\n          white-space: nowrap;\n      }\n\n      .kv {\n          display: flex;\n          flex-wrap: wrap;\n          gap: 6px;\n      }\n\n      .chip {\n          font-size: 12px;\n          padding: 4px 8px;\n          border-radius: 999px;\n          background: var(--chip);\n          border: 1px solid var(--border);\n      }\n\n      .hint {\n          color: var(--muted);\n          font-size: 12px;\n      }\n\n      .badges {\n          display: flex;\n          gap: 8px;\n          flex-wrap: wrap;\n      }\n\n      /* Per-card badges: labels become toggles when clickable */\n      .badge {\n          font-size: 12px;\n          padding: 3px 8px;\n          border-radius: 999px;\n          border: 1px solid var(--border);\n          background: var(--chip);\n          color: #d7dbe0;\n      }\n\n      .badge.ok {\n          color: #b9f6ca;\n          border-color: color-mix(in srgb, var(--ok) 55%, var(--border));\n      }\n\n      .badge.info {\n          color: #b3d9ff;\n          border-color: color-mix(in srgb, var(--info) 55%, var(--border));\n      }\n\n      .badge.err {\n          color: #ff9aa0;\n          border-color: color-mix(in srgb, var(--err) 55%, var(--border));\n      }\n\n      .as-toggle {\n          cursor: pointer;\n      }\n\n      /* 1px ring on active toggle */\n      .tg-err:checked + label.as-toggle,\n      .tg-info:checked + label.as-toggle,\n      .tg-stories:checked + label.as-toggle,\n      .tg-docs:checked + label.as-toggle,\n      .tg-content:checked + label.as-toggle,\n      .tg-props:checked + label.as-toggle {\n          box-shadow: 0 0 0 var(--active-ring) currentColor;\n          border-color: currentColor;\n      }\n\n      /* Panels: hidden by default, shown when respective toggle checked */\n      .panels {\n          display: grid;\n          gap: 10px;\n      }\n\n      .panel {\n          display: none;\n      }\n\n      .tg-err:checked ~ .panels .panel-err {\n          display: grid;\n      }\n\n      .tg-info:checked ~ .panels .panel-info {\n          display: grid;\n          gap: 8px;\n      }\n\n      .tg-stories:checked ~ .panels .panel-stories {\n          display: grid;\n          gap: 8px;\n      }\n\n      .tg-docs:checked ~ .panels .panel-docs {\n          display: grid;\n          gap: 8px;\n      }\n\n      .tg-content:checked ~ .panels .panel-content {\n          display: grid;\n          gap: 8px;\n      }\n\n      .tg-props:checked ~ .panels .panel-props {\n          display: grid;\n      }\n\n      /* Colored notes for prop type error + info */\n      .note {\n          padding: 12px;\n          border: 1px solid var(--border);\n          border-radius: 10px;\n      }\n\n      .note.err {\n          border-color: color-mix(in srgb, var(--err) 55%, var(--border));\n          background: var(--err-bg);\n          color: #ffd1d4;\n      }\n\n      .note.info {\n          border-color: color-mix(in srgb, var(--info) 55%, var(--border));\n          background: var(--info-bg);\n          color: #d6e8ff;\n      }\n\n      .note.ok {\n          border-color: color-mix(in srgb, var(--ok) 55%, var(--border));\n          background: var(--ok-bg);\n          color: var(--fg);\n      }\n\n      .note-title {\n          font-weight: 600;\n          margin-bottom: 6px;\n      }\n\n      .note-body {\n          white-space: normal;\n      }\n\n      /* Story error cards */\n      .ex {\n          padding: 10px;\n          border: 1px solid var(--border);\n          border-radius: 10px;\n          background: #0f131b;\n      }\n\n      .ex.err {\n          border-color: color-mix(in srgb, var(--err) 55%, var(--border));\n      }\n\n      .row {\n          display: flex;\n          align-items: center;\n          gap: 8px;\n          flex-wrap: wrap;\n      }\n\n      .status-dot {\n          width: 8px;\n          height: 8px;\n          border-radius: 50%;\n          display: inline-block;\n      }\n\n      .dot-ok {\n          background: var(--ok);\n      }\n\n      .dot-err {\n          background: var(--err);\n      }\n\n      .ex-name {\n          font-weight: 600;\n      }\n\n      /* Error groups (visible in errors filter) */\n      .error-groups {\n          display: none;\n          margin-bottom: 16px;\n      }\n\n      .group {\n          border: 1px solid var(--border);\n          background: var(--panel);\n          border-radius: 14px;\n          overflow: hidden;\n      }\n\n      .group + .group {\n          margin-top: 12px;\n      }\n\n      .group-header {\n          display: flex;\n          align-items: center;\n          gap: 10px;\n          padding: 12px 14px;\n          cursor: pointer;\n          border-bottom: 1px solid var(--border);\n      }\n\n      .group-header:hover {\n          background: #141722;\n      }\n\n      .group-title {\n          font-weight: 600;\n          flex: 1;\n      }\n\n      .group-count {\n          font-size: 12px;\n          color: var(--muted);\n      }\n\n      .group-cards {\n          display: none;\n          padding: 12px;\n      }\n\n      .group .card {\n          margin: 12px 0;\n      }\n\n      .group .card:first-child {\n          margin-top: 0;\n      }\n\n      .group .card:last-child {\n          margin-bottom: 0;\n      }\n\n      /* caret rotation */\n      .group-tg:checked + label .caret {\n          transform: rotate(90deg);\n      }\n\n      .caret {\n          transition: transform 0.15s ease;\n      }\n\n      /* toggle body */\n      .group-tg:checked ~ .group-cards {\n          display: block;\n      }\n\n      /* CSS-only filtering of cards via top pills */\n      #filter-errors:target ~ main .card:not(.has-error):not(.has-story-error) {\n          display: none;\n      }\n\n      #filter-infos:target ~ main .card:not(.has-info) {\n          display: none;\n      }\n\n      #filter-story-errors:target ~ main .card:not(.has-story-error) {\n          display: none;\n      }\n\n      #filter-doc-errors:target ~ main .card:not(.has-doc-error) {\n          display: none;\n      }\n\n      #filter-docs:target ~ main .card:has(> .tg-docs),\n      #filter-docs:target ~ main .card.is-doc {\n          display: block;\n      }\n\n      #filter-docs:target ~ main .card:not(:has(> .tg-docs)):not(.is-doc) {\n          display: none;\n      }\n\n      #filter-all:target ~ main .card {\n          display: block;\n      }\n\n      /* In errors view, hide standalone component-error cards in the regular grid (they will appear in groups) */\n      #filter-errors:target ~ main .grid .card.has-error {\n          display: none;\n      }\n\n      /* Show grouped section only in errors view */\n      #filter-errors:target ~ main .error-groups {\n          display: block;\n      }\n\n      /* Section titles */\n      .section-title {\n          font-size: 16px;\n          font-weight: 600;\n          color: var(--muted);\n          margin: 24px 0 12px;\n          padding-bottom: 8px;\n          border-bottom: 1px solid var(--border);\n      }\n      .section-title:first-child {\n          margin-top: 0;\n      }\n\n      /* When a toggle is checked, show the corresponding panel */\n      .card > .tg-err:checked ~ .panels .panel-err {\n          display: grid;\n      }\n      \n      .card > .tg-info:checked ~ .panels .panel-info {\n          display: grid;\n      }\n      \n      .card > .tg-stories:checked ~ .panels .panel-stories {\n          display: grid;\n      }\n\n      .card > .tg-docs:checked ~ .panels .panel-docs {\n          display: grid;\n      }\n\n      .card > .tg-content:checked ~ .panels .panel-content {\n          display: grid;\n      }\n\n      /* Add vertical spacing around panels only when any panel is visible */\n      .card > .tg-err:checked ~ .panels,\n      .card > .tg-info:checked ~ .panels,\n      .card > .tg-stories:checked ~ .panels,\n      .card > .tg-docs:checked ~ .panels,\n      .card > .tg-content:checked ~ .panels,\n      .card > .tg-props:checked ~ .panels {\n          margin: 10px 0;\n      }\n\n      /* Optional: a subtle 1px ring on the active badge, using :has() if available */\n      @supports selector(.card:has(.tg-err:checked)) {\n          .card:has(.tg-err:checked) label[for$='-err'],\n          .card:has(.tg-info:checked) label[for$='-info'],\n          .card:has(.tg-stories:checked) label[for$='-stories'],\n          .card:has(.tg-docs:checked) label[for$='-docs'],\n          .card:has(.tg-content:checked) label[for$='-content'],\n          .card:has(.tg-props:checked) label[for$='-props'] {\n              box-shadow: 0 0 0 1px currentColor;\n              border-color: currentColor;\n          }\n      }\n\n      /* Wrap long lines in code blocks at ~120 characters */\n      pre, code {\n          font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n      }\n      pre {\n          white-space: pre-wrap;\n          overflow-wrap: anywhere;\n          word-break: break-word;\n          overflow-x: auto; /* fallback for extremely long tokens */\n          margin: 8px 0 0;\n      }\n      pre > code {\n          display: block;\n          white-space: inherit;\n          overflow-wrap: inherit;\n          word-break: inherit;\n          inline-size: min(100%, 120ch);\n      }\n\n      /* MDX content container for docs */\n      .mdx-content {\n          background: #0f131b;\n          border: 1px solid var(--border);\n          border-radius: 10px;\n          padding: 12px;\n          max-height: 400px;\n          overflow-y: auto;\n          margin-top: 8px;\n      }\n  </style>\n</head>\n<body>\n<!-- Hidden targets for the top-level filters -->\n<span id=\"filter-all\"></span>\n<span id=\"filter-errors\"></span>\n<span id=\"filter-infos\"></span>\n<span id=\"filter-story-errors\"></span>\n<span id=\"filter-doc-errors\"></span>\n<span id=\"filter-docs\"></span>\n<header>\n  <div class=\"wrap\">\n    <h1>Manifest Debugger</h1>\n    <div class=\"summary\">${allPill}${compErrorsPill}${compInfosPill}${storiesPill}${docsPill}</div>\n  </div>\n</header>\n<main>\n  <div class=\"wrap\">\n    ${\n      activeEngine === 'react-docgen'\n        ? `<div class=\"note info\" style=\"margin-bottom: 16px;\">\n            <strong>Tip:</strong> You are using <code>react-docgen</code> (the default). Generation took <strong>${(durationMs / 1000).toFixed(1)}s</strong>. For higher quality prop types, consider switching to <code>react-docgen-typescript</code> in your <code>main.ts</code>:\n            <pre><code>typescript: {\n  reactDocgen: 'react-docgen-typescript',\n}</code></pre>\n            Note: <code>react-docgen-typescript</code> can be slower. If performance is acceptable for your project, it generally produces better results.\n            <a href=\"https://storybook.js.org/docs/api/main-config/main-config-typescript#reactdocgen\" target=\"_blank\">Learn more</a>\n          </div>`\n        : activeEngine === 'react-docgen-typescript' && durationMs > 7500\n          ? `<div class=\"note err\" style=\"margin-bottom: 16px;\">\n              <strong>Performance warning:</strong> <code>react-docgen-typescript</code> took <strong>${(durationMs / 1000).toFixed(1)}s</strong> to generate the manifest. This delay applies every time the manifest is used by an agent. Consider switching to the faster <code>react-docgen</code> in your <code>main.ts</code>:\n              <pre><code>typescript: {\n  reactDocgen: 'react-docgen',\n}</code></pre>\n              <a href=\"https://storybook.js.org/docs/api/main-config/main-config-typescript#reactdocgen\" target=\"_blank\">Learn more</a>\n            </div>`\n          : `<div class=\"note ok\" style=\"margin-bottom: 16px;\">\n              Using <code>${activeEngine}</code>. Generation took <strong>${(durationMs / 1000).toFixed(1)}s</strong>.\n            </div>`\n    }\n    ${\n      grid\n        ? `<h2 class=\"section-title\">Components</h2>\n    <div class=\"grid\" role=\"list\">\n      ${grid}\n    </div>`\n        : ''\n    }\n    ${\n      errorGroups.length\n        ? `<div class=\"error-groups\" role=\"region\" aria-label=\"Prop type error groups\">${errorGroupsHTML}</div>`\n        : ''\n    }\n    ${\n      docsGrid\n        ? `<h2 class=\"section-title\">Unattached Docs</h2>\n    <div class=\"grid\" role=\"list\">\n      ${docsGrid}\n    </div>`\n        : ''\n    }\n    ${\n      !grid && !docsGrid\n        ? `<div class=\"card\"><div class=\"head\"><div class=\"hint\">No components or docs.</div></div></div>`\n        : ''\n    }\n  </div>\n</main>\n</body>\n</html>  `;\n}\n\nconst esc = (s: unknown) =>\n  String(s ?? '').replace(/[&<>\"']/g, (c) => {\n    return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' }[c] ?? c;\n  });\nconst plural = (n: number, one: string, many = `${one}s`) => (n === 1 ? one : many);\n\nfunction analyzeComponent(c: ComponentManifestWithDocs) {\n  const hasPropTypeError = !!c.error;\n  const warns: string[] = [];\n\n  if (!c.description?.trim()) {\n    warns.push('No description found. Write a jsdoc comment such as /** Component description */.');\n  }\n\n  if (!c.import?.trim()) {\n    warns.push(\n      `Specify an @import jsdoc tag on your component or your stories meta such as @import import { ${c.name} } from 'my-design-system';`\n    );\n  }\n\n  const totalStories = c.stories?.length ?? 0;\n  const storyErrors = (c.stories ?? []).filter((e) => !!e?.error).length;\n  const storyOk = totalStories - storyErrors;\n\n  // Analyze attached docs\n  const docsEntries = c.docs ? Object.values(c.docs) : [];\n  const totalDocs = docsEntries.length;\n  const docsErrors = docsEntries.filter((d) => !!d?.error).length;\n  const docsOk = totalDocs - docsErrors;\n\n  const hasAnyError = hasPropTypeError || storyErrors > 0 || docsErrors > 0; // for status dot (red if any errors)\n\n  return {\n    hasPropTypeError,\n    hasAnyError,\n    hasWarns: warns.length > 0,\n    warns,\n    totalStories,\n    storyErrors,\n    storyOk,\n    totalDocs,\n    docsErrors,\n    docsOk,\n  };\n}\n\nfunction analyzeDoc(d: DocsManifestEntry) {\n  return {\n    hasError: !!d.error,\n  };\n}\n\nfunction note(title: string, bodyHTML: string, kind: 'info' | 'err') {\n  return `\n    <div class=\"note ${kind}\">\n      <div class=\"note-title\">${esc(title)}</div>\n      <div class=\"note-body\">${bodyHTML}</div>\n    </div>`;\n}\n\nfunction renderDocCard(key: string, d: DocsManifestEntry, id: string) {\n  const a = analyzeDoc(d);\n  const statusDot = a.hasError ? 'dot-err' : 'dot-ok';\n\n  const slug = `${id}-${(d.id || key)\n    .toLowerCase()\n    .replace(/[^a-z0-9]+/g, '-')\n    .replace(/^-+|-+$/g, '')}`;\n\n  const errorBadge = a.hasError\n    ? `<label for=\"${slug}-err\" class=\"badge err as-toggle\">error</label>`\n    : '';\n\n  const contentBadge = d.content\n    ? `<label for=\"${slug}-content\" class=\"badge ok as-toggle\">view content</label>`\n    : '';\n\n  return `\n<article\n  class=\"card is-doc ${a.hasError ? 'has-doc-error' : 'no-doc-error'}\"\n  role=\"listitem\"\n  aria-label=\"${esc(d.name || key)}\">\n  <div class=\"head\">\n    <div class=\"title\">\n      <h2><span class=\"status-dot ${statusDot}\"></span> ${esc(d.title || d.name || key)}</h2>\n      <div class=\"badges\">\n        ${errorBadge}\n        ${contentBadge}\n      </div>\n    </div>\n    <div class=\"meta\" title=\"${esc(d.path)}\">${esc(d.id)} · ${esc(d.path)}</div>\n    ${d.summary ? `<div>${esc(d.summary)}</div>` : ''}\n  </div>\n\n  <!-- Hidden toggles must be siblings BEFORE .panels -->\n  ${a.hasError ? `<input id=\"${slug}-err\" class=\"tg tg-err\" type=\"checkbox\" hidden />` : ''}\n  ${d.content ? `<input id=\"${slug}-content\" class=\"tg tg-content\" type=\"checkbox\" hidden />` : ''}\n\n  <div class=\"panels\">\n    ${\n      a.hasError\n        ? `\n        <div class=\"panel panel-err\">\n          <div class=\"note err\">\n            <div class=\"note-title\">${esc(d.error?.name || 'Error')}</div>\n            <div class=\"note-body\"><pre><code>${esc(d.error?.message || 'Unknown error')}</code></pre></div>\n          </div>\n        </div>`\n        : ''\n    }\n    ${\n      d.content\n        ? `\n        <div class=\"panel panel-content\">\n          <div class=\"mdx-content\">\n            <pre><code>${esc(d.content)}</code></pre>\n          </div>\n        </div>`\n        : ''\n    }\n  </div>\n</article>`;\n}\n\nfunction renderComponentCard(key: string, c: ComponentManifestWithDocs, id: string) {\n  const a = analyzeComponent(c);\n  const statusDot = a.hasAnyError ? 'dot-err' : 'dot-ok';\n  const allStories = c.stories ?? [];\n  const errorStories = allStories.filter((ex) => !!ex?.error);\n  const okStories = allStories.filter((ex) => !ex?.error);\n\n  // Get attached docs entries\n  const allDocs = c.docs ? Object.values(c.docs) : [];\n  const errorDocs = allDocs.filter((d) => !!d?.error);\n  const okDocs = allDocs.filter((d) => !d?.error);\n\n  const slug = `c-${id}-${(c.id || key)\n    .toLowerCase()\n    .replace(/[^a-z0-9]+/g, '-')\n    .replace(/^-+|-+$/g, '')}`;\n\n  const componentErrorBadge = a.hasPropTypeError\n    ? `<label for=\"${slug}-err\" class=\"badge err as-toggle\">prop type error</label>`\n    : '';\n\n  const infosBadge = a.hasWarns\n    ? `<label for=\"${slug}-info\" class=\"badge info as-toggle\">${a.warns.length} ${plural(a.warns.length, 'info', 'infos')}</label>`\n    : '';\n\n  const storiesBadge =\n    a.totalStories > 0\n      ? `<label for=\"${slug}-stories\" class=\"badge ${a.storyErrors > 0 ? 'err' : 'ok'} as-toggle\">${a.storyErrors > 0 ? `${a.storyErrors}/${a.totalStories} story errors` : `${a.totalStories} ${plural(a.totalStories, 'story', 'stories')}`}</label>`\n      : '';\n\n  const docsBadge =\n    a.totalDocs > 0\n      ? `<label for=\"${slug}-docs\" class=\"badge ${a.docsErrors > 0 ? 'err' : 'ok'} as-toggle\">${a.docsErrors > 0 ? `${a.docsErrors}/${a.totalDocs} doc errors` : `${a.totalDocs} ${plural(a.totalDocs, 'doc')}`}</label>`\n      : '';\n\n  const {\n    parsed: activeParsed,\n    engine: cardEngine,\n    filePath,\n    exportName,\n  } = getDocgenRenderData(c, a.hasPropTypeError);\n  const propEntries = activeParsed ? Object.entries(activeParsed.props ?? {}) : [];\n  const propTypesBadge =\n    !a.hasPropTypeError && propEntries.length > 0\n      ? `<label for=\"${slug}-props\" class=\"badge ok as-toggle\">${propEntries.length} ${plural(propEntries.length, 'prop type')}</label>`\n      : '';\n\n  const primaryBadge = componentErrorBadge || propTypesBadge;\n\n  const propsCode =\n    propEntries.length > 0\n      ? propEntries\n          .sort(([aName], [bName]) => aName.localeCompare(bName))\n          .map(([propName, info]) => {\n            const description = (info?.description ?? '').trim();\n            const t = (info?.type ?? 'any').trim();\n            const optional = info?.required ? '' : '?';\n            const defaultVal = (info?.defaultValue ?? '').trim();\n            const def = defaultVal ? ` = ${defaultVal}` : '';\n            const doc =\n              ['/**', ...description.split('\\n').map((line) => ` * ${line}`), ' */'].join('\\n') +\n              '\\n';\n            return `${description ? doc : ''}${propName}${optional}: ${t}${def}`;\n          })\n          .join('\\n\\n')\n      : '';\n\n  const tags =\n    c.jsDocTags && typeof c.jsDocTags === 'object'\n      ? Object.entries(c.jsDocTags)\n          .flatMap(([k, v]) =>\n            (Array.isArray(v) ? v : [v]).map(\n              (val) => `<span class=\"chip\">${esc(k)}: ${esc(val)}</span>`\n            )\n          )\n          .join('')\n      : '';\n\n  return `\n<article\n  class=\"card \n  ${a.hasPropTypeError ? 'has-error' : 'no-error'} \n  ${a.hasWarns ? 'has-info' : 'no-info'} \n  ${a.storyErrors ? 'has-story-error' : 'no-story-error'}\n  ${a.docsErrors ? 'has-doc-error' : 'no-doc-error'}\"\n  role=\"listitem\"\n  aria-label=\"${esc(c.name || key)}\">\n  <div class=\"head\">\n    <div class=\"title\">\n      <h2><span class=\"status-dot ${statusDot}\"></span> ${esc(c.name || key)}</h2>\n      <div class=\"badges\">\n        ${primaryBadge}\n        ${infosBadge}\n        ${storiesBadge}\n        ${docsBadge}\n      </div>\n    </div>\n    <div class=\"meta\" title=\"${esc(c.path)}\">${esc(c.id)} · ${esc(c.path)}</div>\n    ${c.summary ? `<div>${esc(c.summary)}</div>` : ''}\n    ${c.description ? `<div class=\"hint\">${esc(c.description)}</div>` : ''}\n    ${tags ? `<div class=\"kv\">${tags}</div>` : ''}\n  </div>\n\n  <!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->\n  ${a.hasPropTypeError ? `<input id=\"${slug}-err\" class=\"tg tg-err\" type=\"checkbox\" hidden />` : ''}\n  ${a.hasWarns ? `<input id=\"${slug}-info\" class=\"tg tg-info\" type=\"checkbox\" hidden />` : ''}\n  ${a.totalStories > 0 ? `<input id=\"${slug}-stories\" class=\"tg tg-stories\" type=\"checkbox\" hidden />` : ''}\n  ${a.totalDocs > 0 ? `<input id=\"${slug}-docs\" class=\"tg tg-docs\" type=\"checkbox\" hidden />` : ''}\n  ${!a.hasPropTypeError && propEntries.length > 0 ? `<input id=\"${slug}-props\" class=\"tg tg-props\" type=\"checkbox\" hidden />` : ''}\n\n  <div class=\"panels\">\n    ${\n      a.hasPropTypeError\n        ? `\n        <div class=\"panel panel-err\">\n          ${note('Prop type error', `<pre><code>${esc(c.error?.message || 'Unknown error')}</code></pre>`, 'err')}\n        </div>`\n        : ''\n    }\n    ${\n      a.hasWarns\n        ? `\n        <div class=\"panel panel-info\">\n          ${a.warns.map((w) => note('Info', esc(w), 'info')).join('')}\n        </div>`\n        : ''\n    }\n    ${\n      !a.hasPropTypeError && propEntries.length > 0\n        ? `\n        <div class=\"panel panel-props\">\n          <div class=\"note ok\">\n            <div class=\"row\">\n              <span class=\"ex-name\">Prop types <small>(${cardEngine})</small></span>\n              <span class=\"badge ok\">${propEntries.length} ${plural(propEntries.length, 'prop type')}</span>\n            </div>\n            <pre><code>Component: ${filePath ? esc(path.relative(process.cwd(), filePath)) : ''}${exportName ? '::' + esc(exportName) : ''}</code></pre>\n            <pre><code>Props:</code></pre>\n            <pre><code>${esc(propsCode)}</code></pre>\n          </div>\n        </div>`\n        : ''\n    }\n    ${\n      a.totalStories > 0\n        ? `\n        <div class=\"panel panel-stories\">\n          ${errorStories\n            .map(\n              (ex) => `\n            <div class=\"note err\">\n              <div class=\"row\">\n                <span class=\"ex-name\">${esc(ex.name)}</span>\n                <span class=\"badge err\">story error</span>\n              </div>\n              ${ex?.summary ? `<div class=\\\"hint\\\">Summary: ${esc(ex.summary)}</div>` : ''}\n              ${ex?.description ? `<div class=\\\"hint\\\">${esc(ex.description)}</div>` : ''}\n              ${ex?.snippet ? `<pre><code>${esc(ex.snippet)}</code></pre>` : ''}\n              ${ex?.error?.message ? `<pre><code>${esc(ex.error.message)}</code></pre>` : ''}\n            </div>`\n            )\n            .join('')}\n          \n          \n          ${\n            c.import\n              ? `<div class=\"note ok\">\n                <div class=\"row\">\n                  <span class=\"ex-name\">Imports</span>\n                </div>\n                <pre><code>${c.import}</code></pre>\n              </div>`\n              : ''\n          }\n          \n          ${okStories\n            .map(\n              (ex) => `\n            <div class=\"note ok\">\n              <div class=\"row\">\n                <span class=\"ex-name\">${esc(ex.name)}</span>\n                <span class=\"badge ok\">story ok</span>\n              </div>\n              ${ex?.summary ? `<div>${esc(ex.summary)}</div>` : ''}\n              ${ex?.description ? `<div class=\\\"hint\\\">${esc(ex.description)}</div>` : ''}\n              ${ex?.snippet ? `<pre><code>${esc(ex.snippet)}</code></pre>` : ''}\n            </div>`\n            )\n            .join('')}\n        </div>`\n        : ''\n    }\n    ${\n      a.totalDocs > 0\n        ? `\n        <div class=\"panel panel-docs\">\n          ${errorDocs\n            .map(\n              (doc) => `\n            <div class=\"note err\">\n              <div class=\"row\">\n                <span class=\"ex-name\">${esc(doc.name)}</span>\n                <span class=\"badge err\">doc error</span>\n              </div>\n              <div class=\"hint\">${esc(doc.path)}</div>\n              ${doc?.summary ? `<div>${esc(doc.summary)}</div>` : ''}\n              ${doc?.error?.message ? `<pre><code>${esc(doc.error.message)}</code></pre>` : ''}\n            </div>`\n            )\n            .join('')}\n          ${okDocs\n            .map(\n              (doc) => `\n            <div class=\"note ok\">\n              <div class=\"row\">\n                <span class=\"ex-name\">${esc(doc.name)}</span>\n                <span class=\"badge ok\">doc ok</span>\n              </div>\n              <div class=\"hint\">${esc(doc.path)}</div>\n              ${doc?.summary ? `<div>${esc(doc.summary)}</div>` : ''}\n              ${doc?.content ? `<div class=\"mdx-content\"><pre><code>${esc(doc.content)}</code></pre></div>` : ''}\n            </div>`\n            )\n            .join('')}\n        </div>`\n        : ''\n    }\n  </div>\n</article>`;\n}\n\ntype ParsedProp = {\n  description?: string;\n  type?: string;\n  defaultValue?: string;\n  required?: boolean;\n};\n\ntype ParsedDocgen = {\n  props: Record<string, ParsedProp>;\n};\n\ntype RdtComponentDoc = ComponentDoc & { exportName?: string };\ntype DocgenRenderData = {\n  parsed?: ParsedDocgen;\n  engine?: 'react-docgen' | 'react-docgen-typescript' | 'react-component-meta';\n  filePath?: string;\n  exportName?: string;\n};\n\nconst getDocgenRenderData = (\n  component: ComponentManifestWithDocs,\n  hasPropTypeError: boolean\n): DocgenRenderData => {\n  if (hasPropTypeError) {\n    return {};\n  }\n\n  if (component.reactDocgen) {\n    return {\n      parsed: parseReactDocgen(component.reactDocgen),\n      engine: 'react-docgen',\n      filePath: component.reactDocgen.definedInFile,\n      exportName: component.reactDocgen.exportName,\n    };\n  }\n\n  if (component.reactDocgenTypescript) {\n    return {\n      parsed: parseReactDocgenTypescript(component.reactDocgenTypescript),\n      engine: 'react-docgen-typescript',\n      filePath: component.reactDocgenTypescript.filePath,\n      exportName: component.reactDocgenTypescript.exportName,\n    };\n  }\n\n  if (component.reactComponentMeta) {\n    return {\n      parsed: parseReactComponentMeta(component.reactComponentMeta),\n      engine: 'react-component-meta',\n      filePath: component.reactComponentMeta.filePath,\n      exportName: component.reactComponentMeta.exportName,\n    };\n  }\n\n  return {};\n};\n\nconst parseReactDocgenTypescript = (reactDocgenTypescript: RdtComponentDoc): ParsedDocgen => {\n  const props: Record<string, PropItem> = reactDocgenTypescript.props ?? {};\n  return {\n    props: Object.fromEntries(\n      Object.entries(props).map(([propName, prop]) => [\n        propName,\n        {\n          description: prop.description,\n          // RDT uses prop.type.name as a flat string (e.g. \"() => void\", \"{ id: string }\")\n          // For enums, prefer prop.type.raw which has the full union\n          type: prop.type?.raw ?? prop.type?.name,\n          defaultValue: prop.defaultValue?.value,\n          required: prop.required,\n        },\n      ])\n    ),\n  };\n};\n\nconst parseReactComponentMeta = (reactComponentMeta: ReactComponentMetaDoc): ParsedDocgen => {\n  const props = reactComponentMeta.props ?? {};\n  return {\n    props: Object.fromEntries(\n      Object.entries(props).map(([propName, prop]) => [\n        propName,\n        {\n          description: prop.description,\n          type: prop.type?.raw ?? prop.type?.name,\n          defaultValue: prop.defaultValue?.value,\n          required: prop.required,\n        },\n      ])\n    ),\n  };\n};\n\n/** Shape of a react-docgen tsType node (recursive) */\ninterface DocgenTsType {\n  name?: string;\n  raw?: string;\n  value?: string;\n  elements?: DocgenTsType[];\n  type?: string;\n  signature?: {\n    arguments?: { name: string; type?: DocgenTsType }[];\n    return?: DocgenTsType;\n    properties?: { key: string; value?: DocgenTsType & { required?: boolean } }[];\n  };\n}\n\n/** Shape of a single prop from react-docgen's Documentation.props */\ninterface DocgenPropItem {\n  description?: string;\n  tsType?: DocgenTsType;\n  type?: DocgenTsType;\n  defaultValue?: { value?: string } | null;\n  required?: boolean;\n}\n\n/** Shape of react-docgen's Documentation (only fields we read) */\ninterface DocgenDoc {\n  props?: Record<string, DocgenPropItem>;\n  definedInFile?: string;\n  exportName?: string;\n}\n\nconst parseReactDocgen = (reactDocgen: DocgenDoc): ParsedDocgen => {\n  const props = reactDocgen.props ?? {};\n  return {\n    props: Object.fromEntries(\n      Object.entries(props).map(([propName, prop]) => [\n        propName,\n        {\n          description: prop.description,\n          type: serializeTsType(prop.tsType ?? prop.type),\n          defaultValue: prop.defaultValue?.value,\n          required: prop.required,\n        },\n      ])\n    ),\n  };\n};\n\n// Serialize a react-docgen tsType into a TypeScript-like string when raw is not available\nfunction serializeTsType(tsType: DocgenTsType | undefined): string | undefined {\n  if (!tsType) {\n    return undefined;\n  }\n  // Prefer raw if provided\n  if (tsType.raw && tsType.raw.trim().length > 0) {\n    return tsType.raw;\n  }\n\n  if (!tsType.name) {\n    return undefined;\n  }\n\n  if (tsType.elements) {\n    if (tsType.name === 'union') {\n      const parts = tsType.elements.map((el) => serializeTsType(el) ?? 'unknown');\n      return parts.join(' | ');\n    }\n    if (tsType.name === 'intersection') {\n      const parts = tsType.elements.map((el) => serializeTsType(el) ?? 'unknown');\n      return parts.join(' & ');\n    }\n    if (tsType.name === 'Array') {\n      // Prefer raw earlier; here build fallback\n      const el = tsType.elements[0];\n      const inner = serializeTsType(el) ?? 'unknown';\n      return `${inner}[]`;\n    }\n    if (tsType.name === 'tuple') {\n      const parts = tsType.elements.map((el) => serializeTsType(el) ?? 'unknown');\n      return `[${parts.join(', ')}]`;\n    }\n  }\n  if (tsType.value && tsType.name === 'literal') {\n    return tsType.value;\n  }\n  if (tsType.signature && tsType.name === 'signature') {\n    if (tsType.type === 'function') {\n      const args = (tsType.signature.arguments ?? []).map((a) => {\n        const argType = serializeTsType(a.type) ?? 'any';\n        return `${a.name}: ${argType}`;\n      });\n      const ret = serializeTsType(tsType.signature.return) ?? 'void';\n      return `(${args.join(', ')}) => ${ret}`;\n    }\n    if (tsType.type === 'object') {\n      const props = (tsType.signature.properties ?? []).map((p) => {\n        const req: boolean = Boolean(p.value?.required);\n        const propType = serializeTsType(p.value) ?? 'any';\n        return `${p.key}${req ? '' : '?'}: ${propType}`;\n      });\n      return `{ ${props.join('; ')} }`;\n    }\n    return 'unknown';\n  }\n  // Default case (Generic like Item<TMeta>)\n  if (tsType.elements) {\n    const inner = tsType.elements.map((el) => serializeTsType(el) ?? 'unknown');\n\n    if (inner.length > 0) {\n      return `${tsType.name}<${inner.join(', ')}>`;\n    }\n  }\n\n  return tsType.name;\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/metadata.ts",
    "content": "import { writeFile } from 'node:fs/promises';\n\nimport { getStorybookMetadata } from 'storybook/internal/telemetry';\n\nimport type { Polka } from 'polka';\n\nexport async function extractStorybookMetadata(outputFile: string, configDir: string) {\n  const storybookMetadata = await getStorybookMetadata(configDir);\n\n  await writeFile(outputFile, JSON.stringify(storybookMetadata));\n}\n\nexport function useStorybookMetadata(app: Polka, configDir?: string) {\n  app.use('/project.json', async (req, res) => {\n    const storybookMetadata = await getStorybookMetadata(configDir);\n    res.setHeader('Content-Type', 'application/json');\n    res.write(JSON.stringify(storybookMetadata));\n    res.end();\n  });\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/middleware.ts",
    "content": "import { existsSync } from 'node:fs';\n\nimport { resolve } from 'pathe';\n\nconst fileExists = (basename: string) =>\n  ['.js', '.mjs', '.cjs'].reduce((found: string, ext: string) => {\n    const filename = `${basename}${ext}`;\n    return !found && existsSync(filename) ? filename : found;\n  }, '');\n\nexport async function getMiddleware(configDir: string) {\n  const middlewarePath = fileExists(resolve(configDir, 'middleware'));\n  if (middlewarePath) {\n    const middlewareModule = await import('file://' + middlewarePath);\n    return middlewareModule.default ?? middlewareModule;\n  }\n  return () => {};\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/new-story-templates/csf-factory-template.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { getCsfFactoryTemplateForNewStoryFile } from './csf-factory-template.ts';\n\ndescribe('csf-factories', () => {\n  it('should return a CSF factories template with a default import', async () => {\n    const result = await getCsfFactoryTemplateForNewStoryFile({\n      basenameWithoutExtension: 'foo',\n      componentExportName: 'default',\n      componentIsDefaultExport: true,\n      exportedStoryName: 'Default',\n    });\n\n    expect(result).toMatchInlineSnapshot(`\n      \"import preview from '#.storybook/preview';\n\n      import Foo from './foo';\n\n      const meta = preview.meta({\n        component: Foo,\n      });\n\n      export const Default = meta.story({});\"\n    `);\n  });\n\n  it('should return a CSF factories template with a named import', async () => {\n    const result = await getCsfFactoryTemplateForNewStoryFile({\n      basenameWithoutExtension: 'foo',\n      componentExportName: 'FooComponent',\n      componentIsDefaultExport: false,\n      exportedStoryName: 'Default',\n    });\n\n    expect(result).toMatchInlineSnapshot(`\n      \"import preview from '#.storybook/preview';\n\n      import { FooComponent } from './foo';\n\n      const meta = preview.meta({\n        component: FooComponent,\n      });\n\n      export const Default = meta.story({});\"\n    `);\n  });\n\n  it('should return a CSF factories template with a custom preview import path', async () => {\n    const result = await getCsfFactoryTemplateForNewStoryFile({\n      basenameWithoutExtension: 'foo',\n      componentExportName: 'default',\n      componentIsDefaultExport: true,\n      exportedStoryName: 'Default',\n      previewImportPath: '../../.storybook/preview',\n    });\n\n    expect(result).toMatchInlineSnapshot(`\n      \"import preview from '../../.storybook/preview';\n\n      import Foo from './foo';\n\n      const meta = preview.meta({\n        component: Foo,\n      });\n\n      export const Default = meta.story({});\"\n    `);\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/new-story-templates/csf-factory-template.ts",
    "content": "import { dedent } from 'ts-dedent';\n\nimport { getComponentVariableName } from '../get-component-variable-name.ts';\n\ninterface CsfFactoryTemplateData {\n  /** The components file name without the extension */\n  basenameWithoutExtension: string;\n  componentExportName: string;\n  componentIsDefaultExport: boolean;\n  /** The exported name of the default story */\n  exportedStoryName: string;\n  /** The import path for the preview config (if not provided, uses '#.storybook/preview') */\n  previewImportPath?: string;\n  /** The args to include in the story */\n  args?: Record<string, any>;\n}\n\nexport async function getCsfFactoryTemplateForNewStoryFile(data: CsfFactoryTemplateData) {\n  const importName = data.componentIsDefaultExport\n    ? await getComponentVariableName(data.basenameWithoutExtension)\n    : data.componentExportName;\n  const importStatement = data.componentIsDefaultExport\n    ? `import ${importName} from './${data.basenameWithoutExtension}';`\n    : `import { ${importName} } from './${data.basenameWithoutExtension}';`;\n  const previewImport = data.previewImportPath\n    ? `import preview from '${data.previewImportPath}';`\n    : `import preview from '#.storybook/preview';`;\n\n  const argsString =\n    data.args && Object.keys(data.args).length > 0\n      ? `{ args: ${JSON.stringify(data.args, null, 2)} }`\n      : '{}';\n\n  return dedent`\n  ${previewImport}\n\n  ${importStatement}\n\n  const meta = preview.meta({\n    component: ${importName},\n  });\n\n  export const ${data.exportedStoryName} = meta.story(${argsString});\n  `;\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/new-story-templates/javascript.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { getJavaScriptTemplateForNewStoryFile } from './javascript.ts';\n\ndescribe('javascript', () => {\n  it('should return a TypeScript template with a default import', async () => {\n    const result = await getJavaScriptTemplateForNewStoryFile({\n      basenameWithoutExtension: 'foo',\n      componentExportName: 'default',\n      componentIsDefaultExport: true,\n      exportedStoryName: 'Default',\n    });\n\n    expect(result).toMatchInlineSnapshot(`\n      \"import Foo from './foo';\n\n      const meta = {\n        component: Foo,\n      };\n      \n      export default meta;\n      \n      export const Default = {};\"\n    `);\n  });\n\n  it('should return a TypeScript template with a named import', async () => {\n    const result = await getJavaScriptTemplateForNewStoryFile({\n      basenameWithoutExtension: 'foo',\n      componentExportName: 'Example',\n      componentIsDefaultExport: false,\n      exportedStoryName: 'Default',\n    });\n\n    expect(result).toMatchInlineSnapshot(`\n      \"import { Example } from './foo';\n\n      const meta = {\n        component: Example,\n      };\n\n      export default meta;\n\n      export const Default = {};\"\n    `);\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/new-story-templates/javascript.ts",
    "content": "import { dedent } from 'ts-dedent';\n\nimport { getComponentVariableName } from '../get-component-variable-name.ts';\n\ninterface JavaScriptTemplateData {\n  /** The components file name without the extension */\n  basenameWithoutExtension: string;\n  componentExportName: string;\n  componentIsDefaultExport: boolean;\n  /** The exported name of the default story */\n  exportedStoryName: string;\n  /** The args to include in the story */\n  args?: Record<string, any>;\n}\n\nexport async function getJavaScriptTemplateForNewStoryFile(data: JavaScriptTemplateData) {\n  const importName = data.componentIsDefaultExport\n    ? await getComponentVariableName(data.basenameWithoutExtension)\n    : data.componentExportName;\n  const importStatement = data.componentIsDefaultExport\n    ? `import ${importName} from './${data.basenameWithoutExtension}';`\n    : `import { ${importName} } from './${data.basenameWithoutExtension}';`;\n\n  const hasArgs = Boolean(data.args && Object.keys(data.args).length > 0);\n  const argsString = hasArgs ? `args: ${JSON.stringify(data.args, null, 2)},` : '';\n  const storyExport = hasArgs\n    ? dedent`\n      export const ${data.exportedStoryName} = {\n        ${argsString}\n      };\n      `\n    : `export const ${data.exportedStoryName} = {};`;\n\n  return dedent`\n  ${importStatement}\n\n  const meta = {\n    component: ${importName},\n  };\n\n  export default meta;\n\n  ${storyExport}\n  `;\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/new-story-templates/typescript.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { getTypeScriptTemplateForNewStoryFile } from './typescript.ts';\n\ndescribe('typescript', () => {\n  it('should return a TypeScript template with a default import', async () => {\n    const result = await getTypeScriptTemplateForNewStoryFile({\n      basenameWithoutExtension: 'foo',\n      componentExportName: 'default',\n      componentIsDefaultExport: true,\n      frameworkPackage: '@storybook/react-vite',\n      exportedStoryName: 'Default',\n    });\n\n    expect(result).toMatchInlineSnapshot(`\n      \"import type { Meta, StoryObj } from '@storybook/react-vite';\n\n      import Foo from './foo';\n\n      const meta = {\n        component: Foo,\n      } satisfies Meta<typeof Foo>;\n\n      export default meta;\n\n      type Story = StoryObj<typeof meta>;\n\n      export const Default: Story = {};\"\n    `);\n  });\n\n  it('should return a TypeScript template with a named import', async () => {\n    const result = await getTypeScriptTemplateForNewStoryFile({\n      basenameWithoutExtension: 'foo',\n      componentExportName: 'Example',\n      componentIsDefaultExport: false,\n      frameworkPackage: '@storybook/react-vite',\n      exportedStoryName: 'Default',\n    });\n\n    expect(result).toMatchInlineSnapshot(`\n      \"import type { Meta, StoryObj } from '@storybook/react-vite';\n\n      import { Example } from './foo';\n\n      const meta = {\n        component: Example,\n      } satisfies Meta<typeof Example>;\n\n      export default meta;\n\n      type Story = StoryObj<typeof meta>;\n\n      export const Default: Story = {};\"\n    `);\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/new-story-templates/typescript.ts",
    "content": "import { dedent } from 'ts-dedent';\n\nimport { getComponentVariableName } from '../get-component-variable-name.ts';\n\ninterface TypeScriptTemplateData {\n  /** The components file name without the extension */\n  basenameWithoutExtension: string;\n  componentExportName: string;\n  componentIsDefaultExport: boolean;\n  /** The framework package name, e.g. @storybook/nextjs */\n  frameworkPackage: string;\n  /** The exported name of the default story */\n  exportedStoryName: string;\n  /** The args to include in the story */\n  args?: Record<string, any>;\n}\n\nexport async function getTypeScriptTemplateForNewStoryFile(data: TypeScriptTemplateData) {\n  const importName = data.componentIsDefaultExport\n    ? await getComponentVariableName(data.basenameWithoutExtension)\n    : data.componentExportName;\n  const importStatement = data.componentIsDefaultExport\n    ? `import ${importName} from './${data.basenameWithoutExtension}'`\n    : `import { ${importName} } from './${data.basenameWithoutExtension}'`;\n\n  const hasArgs = Boolean(data.args && Object.keys(data.args).length > 0);\n  const argsString = hasArgs ? `args: ${JSON.stringify(data.args, null, 2)},` : '';\n  const storyExport = hasArgs\n    ? dedent`\n      export const ${data.exportedStoryName}: Story = {\n        ${argsString}\n      };\n      `\n    : `export const ${data.exportedStoryName}: Story = {};`;\n\n  return dedent`\n  import type { Meta, StoryObj } from '${data.frameworkPackage}';\n\n  ${importStatement};\n\n  const meta = {\n    component: ${importName},\n  } satisfies Meta<typeof ${importName}>;\n\n  export default meta;\n\n  type Story = StoryObj<typeof meta>;\n\n  ${storyExport}\n  `;\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/open-browser/open-in-browser.ts",
    "content": "import { logger } from 'storybook/internal/node-logger';\n\nimport open from 'open';\nimport { dedent } from 'ts-dedent';\n\nimport { openBrowser } from './opener.ts';\n\nexport async function openInBrowser(address: string) {\n  let errorOccurred = false;\n  let openBrowserResult: boolean | undefined;\n\n  try {\n    openBrowserResult = await openBrowser(address);\n  } catch (error) {\n    errorOccurred = true;\n  }\n\n  // If openBrowser returned false, it means BROWSER=none was set intentionally\n  // In this case, don't try to open a browser at all (fixes #24191)\n  if (openBrowserResult === false) {\n    return;\n  }\n\n  try {\n    if (errorOccurred) {\n      await open(address);\n      errorOccurred = false;\n    }\n  } catch (error) {\n    errorOccurred = true;\n  }\n\n  if (errorOccurred) {\n    const browserEnv = process.env.BROWSER;\n    const browserHint = browserEnv\n      ? `\\n\\nNote: BROWSER environment variable is set to \"${browserEnv}\". ` +\n        `To disable browser opening, use BROWSER=none or the --ci flag.`\n      : '';\n\n    logger.error(dedent`\n        Could not open ${address} inside a browser. If you're running this command inside a\n        docker container or on a CI, you need to pass the '--ci' flag to prevent opening a\n        browser by default.${browserHint}\n      `);\n  }\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/open-browser/opener.test.ts",
    "content": "import type { ChildProcess } from 'node:child_process';\n\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport spawn from 'cross-spawn';\nimport open from 'open';\n\nimport { BrowserEnvError, openBrowser } from './opener.ts';\n\nvi.mock('open', { spy: true });\nvi.mock('cross-spawn', { spy: true });\n\ndescribe('openBrowser BROWSER script handling', () => {\n  const originalEnv = { ...process.env };\n  const originalArgv = [...process.argv];\n  let platformSpy: ReturnType<typeof vi.spyOn>;\n\n  beforeEach(() => {\n    vi.resetAllMocks();\n    platformSpy = vi.spyOn(process, 'platform', 'get').mockReturnValue('linux');\n    process.env = { ...originalEnv };\n    process.argv = ['node', 'test'];\n\n    vi.mocked(open).mockImplementation(() => {\n      return Promise.resolve({} as unknown as Awaited<ReturnType<typeof open>>);\n    });\n    const child = { on: vi.fn() } as unknown as ChildProcess;\n    vi.mocked(spawn).mockImplementation(() => child);\n  });\n\n  afterEach(() => {\n    vi.restoreAllMocks();\n    process.env = originalEnv;\n    process.argv = originalArgv;\n  });\n\n  it('executes a node script when BROWSER points to a JS file', () => {\n    process.env.BROWSER = '/tmp/browser.js';\n\n    openBrowser('http://localhost:6006/');\n\n    expect(vi.mocked(spawn)).toHaveBeenCalledWith(\n      process.execPath,\n      ['/tmp/browser.js', 'http://localhost:6006/'],\n      { stdio: 'inherit' }\n    );\n    expect(vi.mocked(open)).not.toHaveBeenCalled();\n  });\n\n  it('executes a node script when BROWSER points to a MJS file', () => {\n    process.env.BROWSER = '/tmp/browser.mjs';\n\n    openBrowser('http://localhost:6006/');\n\n    expect(vi.mocked(spawn)).toHaveBeenCalledWith(\n      process.execPath,\n      ['/tmp/browser.mjs', 'http://localhost:6006/'],\n      { stdio: 'inherit' }\n    );\n    expect(vi.mocked(open)).not.toHaveBeenCalled();\n  });\n\n  it('executes a node script when BROWSER points to a CJS file', () => {\n    process.env.BROWSER = '/tmp/browser.cjs';\n\n    openBrowser('http://localhost:6006/');\n\n    expect(vi.mocked(spawn)).toHaveBeenCalledWith(\n      process.execPath,\n      ['/tmp/browser.cjs', 'http://localhost:6006/'],\n      { stdio: 'inherit' }\n    );\n    expect(vi.mocked(open)).not.toHaveBeenCalled();\n  });\n\n  it('falls back to opening the browser when BROWSER points to a shell script on Windows', () => {\n    process.env.BROWSER = '/tmp/customBrowser.sh';\n    platformSpy.mockReturnValue('win32');\n\n    expect(() => openBrowser('http://localhost:6006/')).toThrow(BrowserEnvError);\n  });\n\n  it('executes a shell script on Linux when BROWSER is a shell script', () => {\n    process.env.BROWSER = '/tmp/findAHandler.sh';\n    platformSpy.mockReturnValue('linux');\n\n    openBrowser('http://localhost:6006/');\n\n    expect(vi.mocked(spawn)).toHaveBeenCalledWith(\n      'sh',\n      ['/tmp/findAHandler.sh', 'http://localhost:6006/'],\n      { stdio: 'inherit' }\n    );\n    expect(vi.mocked(open)).not.toHaveBeenCalled();\n  });\n\n  it('starts browser process on Linux when BROWSER is not a shell script', () => {\n    process.env.BROWSER = 'google chrome';\n    platformSpy.mockReturnValue('linux');\n\n    openBrowser('http://localhost:6006/');\n\n    expect(vi.mocked(spawn)).not.toHaveBeenCalled();\n    expect(vi.mocked(open)).toHaveBeenCalledWith('http://localhost:6006/', {\n      app: 'google chrome',\n      wait: false,\n      url: true,\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/open-browser/opener.ts",
    "content": "/**\n * Copyright (c) 2015-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the LICENSE file in the root\n * directory of this source tree.\n */\nimport { execSync } from 'node:child_process';\nimport { join } from 'node:path';\n\nimport { logger } from 'storybook/internal/node-logger';\n\nimport spawn from 'cross-spawn';\nimport open, { type App } from 'open';\nimport picocolors from 'picocolors';\n\nimport { resolvePackageDir } from '../../../common/index.ts';\nimport { StorybookError } from '../../../storybook-error.ts';\n\n// https://github.com/sindresorhus/open#app\nconst OSX_CHROME = 'google chrome';\n\nenum Actions {\n  NONE = 0,\n  BROWSER = 1,\n  SCRIPT = 2,\n  SHELL_SCRIPT = 3,\n}\n\nfunction getBrowserEnv():\n  | {\n      action: Actions.SCRIPT | Actions.SHELL_SCRIPT;\n      value: string;\n      args: string[];\n    }\n  | {\n      action: Actions.BROWSER;\n      value?: string;\n      args: string[];\n    }\n  | {\n      action: Actions.NONE;\n      value?: undefined;\n      args?: undefined;\n    } {\n  // Attempt to honor this environment variable.\n  // It is specific to the operating system.\n  // See https://github.com/sindresorhus/open#app for documentation.\n  const value = process.env.BROWSER;\n  const args = process.env.BROWSER_ARGS ? process.env.BROWSER_ARGS.split(' ') : [];\n\n  // Default.\n  if (!value) {\n    return { action: Actions.BROWSER, args };\n  }\n\n  if (value.toLowerCase() === 'none') {\n    return { action: Actions.NONE };\n  }\n\n  if (\n    value.toLowerCase().endsWith('.js') ||\n    value.toLowerCase().endsWith('.mjs') ||\n    value.toLowerCase().endsWith('.cjs') ||\n    value.toLowerCase().endsWith('.ts')\n  ) {\n    return { action: Actions.SCRIPT, value, args };\n  }\n\n  if (value.toLowerCase().endsWith('.sh')) {\n    return { action: Actions.SHELL_SCRIPT, value, args };\n  }\n\n  return { action: Actions.BROWSER, value, args };\n}\n\nexport class BrowserEnvError extends StorybookError {\n  constructor(message: string) {\n    super({\n      category: 'CORE_SERVER',\n      code: 1,\n      message,\n      name: 'BrowserEnvError',\n    });\n  }\n}\n\nfunction attachEventHandlers(child: ReturnType<typeof spawn>, scriptPath: string) {\n  child.on('error', (error) => {\n    logger.error(\n      `Failed to run script specified in BROWSER.\\n${picocolors.cyan(scriptPath)}: ${error.message}`\n    );\n  });\n\n  child.on('close', (code) => {\n    if (code !== 0) {\n      logger.error(\n        `The script specified as BROWSER environment variable failed.\\n${picocolors.cyan(scriptPath)} exited with code ${code}.`\n      );\n      return;\n    }\n  });\n}\n\nfunction executeNodeScript(scriptPath: string, url: string) {\n  const extraArgs = process.argv.slice(2);\n  const child = spawn(process.execPath, [scriptPath, ...extraArgs, url], {\n    stdio: 'inherit',\n  });\n  attachEventHandlers(child, scriptPath);\n  return true;\n}\n\nfunction executeShellScript(scriptPath: string, url: string) {\n  const extraArgs = process.argv.slice(2);\n  const child = spawn('sh', [scriptPath, ...extraArgs, url], {\n    stdio: 'inherit',\n  });\n  attachEventHandlers(child, scriptPath);\n  return true;\n}\n\nfunction startBrowserProcess(\n  browser: App | readonly App[] | undefined,\n  url: string,\n  args: string[]\n) {\n  // If we're on OS X, the user hasn't specifically\n  // requested a different browser, we can try opening\n  // Chrome with AppleScript. This lets us reuse an\n  // existing tab when possible instead of creating a new one.\n  const shouldTryOpenChromiumWithAppleScript =\n    process.platform === 'darwin' && (typeof browser !== 'string' || browser === OSX_CHROME);\n\n  if (shouldTryOpenChromiumWithAppleScript) {\n    // Will use the first open browser found from list\n    const supportedChromiumBrowsers = [\n      'Google Chrome Canary',\n      'Google Chrome Dev',\n      'Google Chrome Beta',\n      'Google Chrome',\n      'Microsoft Edge',\n      'Brave Browser',\n      'Vivaldi',\n      'Chromium',\n    ];\n\n    for (const chromiumBrowser of supportedChromiumBrowsers) {\n      try {\n        // Try our best to reuse existing tab\n        // on OSX Chromium-based browser with AppleScript\n        execSync(`ps cax | grep \"${chromiumBrowser}\"`);\n        const pathToApplescript = join(\n          resolvePackageDir('storybook'),\n          'assets',\n          'server',\n          'openBrowser.applescript'\n        );\n\n        const command = `osascript \"${pathToApplescript}\" \\\"`\n          .concat(encodeURI(url), '\" \"')\n          .concat(\n            process.env.OPEN_MATCH_HOST_ONLY === 'true'\n              ? encodeURI(new URL(url).origin)\n              : encodeURI(url),\n            '\" \"'\n          )\n          .concat(chromiumBrowser, '\"');\n\n        execSync(command, {\n          cwd: __dirname,\n        });\n\n        return true;\n      } catch {\n        // Ignore errors.\n      }\n    }\n  }\n\n  // Another special case: on OS X, check if BROWSER has been set to \"open\".\n  // In this case, instead of passing `open` to `opn` (which won't work),\n  // just ignore it (thus ensuring the intended behavior, i.e. opening the system browser):\n  // https://github.com/facebook/create-react-app/pull/1690#issuecomment-283518768\n  // @ts-expect-error - browser is a string\n  if (process.platform === 'darwin' && browser === 'open') {\n    browser = undefined;\n  }\n\n  // If there are arguments, they must be passed as array with the browser\n  if (typeof browser === 'string' && args.length > 0) {\n    // @ts-expect-error - browser is a string\n    browser = [browser].concat(args);\n  }\n\n  // Fallback to open\n  // (It will always open new tab)\n  try {\n    const options = { app: browser, wait: false, url: true };\n    open(url, options).catch(() => {}); // Prevent `unhandledRejection` error.\n    return true;\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Reads the BROWSER environment variable and decides what to do with it. Returns true if it opened\n * a browser or ran a node.js script, otherwise false.\n */\nexport function openBrowser(url: string) {\n  const { action, value, args } = getBrowserEnv();\n  // Returns win32 on PowerShell and Linux on WSL. Matches conditions when `sh` can be invoked.\n  const canRunShell = process.platform !== 'win32';\n  const browserTarget = value as unknown as App | readonly App[] | undefined;\n\n  switch (action) {\n    case Actions.NONE: {\n      // Special case: BROWSER=\"none\" will prevent opening completely.\n      return false;\n    }\n    case Actions.SCRIPT: {\n      return executeNodeScript(value, url);\n    }\n    case Actions.SHELL_SCRIPT: {\n      if (canRunShell) {\n        return executeShellScript(value, url);\n      }\n      throw new BrowserEnvError(\n        'Shell scripts are not supported on Windows PowerShell. Use WSL instead.'\n      );\n    }\n    case Actions.BROWSER: {\n      return startBrowserProcess(browserTarget, url, args);\n    }\n    default: {\n      throw new BrowserEnvError('Not implemented.');\n    }\n  }\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/output-startup-information.ts",
    "content": "import { CLI_COLORS, logger } from 'storybook/internal/node-logger';\nimport type { VersionCheck } from 'storybook/internal/types';\n\nimport picocolors from 'picocolors';\nimport prettyTime from 'pretty-hrtime';\nimport { dedent } from 'ts-dedent';\n\nimport { createUpdateMessage } from './update-check.ts';\n\nexport function outputStartupInformation(options: {\n  updateInfo: VersionCheck;\n  version: string;\n  name: string;\n  address: string;\n  networkAddress: string;\n  allowedHosts?: string[] | true;\n  managerTotalTime?: [number, number];\n  previewTotalTime?: [number, number];\n}) {\n  const {\n    updateInfo,\n    version,\n    name,\n    address,\n    networkAddress,\n    allowedHosts,\n    managerTotalTime,\n    previewTotalTime,\n  } = options;\n\n  const otherAllowedHosts =\n    allowedHosts === true\n      ? 'all (insecure)'\n      : allowedHosts?.length\n        ? allowedHosts.join(', ')\n        : undefined;\n  const updateMessage = createUpdateMessage(updateInfo, version);\n\n  const serverMessages = [\n    `- Local:                ${address}`,\n    `- On your network:      ${networkAddress}`,\n    otherAllowedHosts && `- Other allowed hosts:  ${otherAllowedHosts}`,\n  ];\n\n  logger.logBox(\n    dedent`\n      Storybook ready!\n\n      ${serverMessages.join('\\n')}${updateMessage ? `\\n\\n${updateMessage}` : ''}\n    `,\n    {\n      formatBorder: CLI_COLORS.storybook,\n      contentPadding: 3,\n      rounded: true,\n    }\n  );\n\n  const timeStatement = [\n    managerTotalTime && `${picocolors.underline(prettyTime(managerTotalTime))} for manager`,\n    previewTotalTime && `${picocolors.underline(prettyTime(previewTotalTime))} for preview`,\n  ]\n    .filter(Boolean)\n    .join(' and ');\n\n  logger.info(timeStatement);\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/output-stats.ts",
    "content": "import { createWriteStream } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { logger } from 'storybook/internal/node-logger';\nimport type { Stats } from 'storybook/internal/types';\n\nimport { stringifyStream } from '@discoveryjs/json-ext';\nimport picocolors from 'picocolors';\n\nexport async function outputStats(directory: string, previewStats?: any, managerStats?: any) {\n  if (previewStats) {\n    const filePath = await writeStats(directory, 'preview', previewStats as Stats);\n    logger.info(`Preview stats written to ${picocolors.cyan(filePath)}`);\n  }\n  if (managerStats) {\n    const filePath = await writeStats(directory, 'manager', managerStats as Stats);\n    logger.info(`Manager stats written to ${picocolors.cyan(filePath)}`);\n  }\n}\n\nexport const writeStats = async (directory: string, name: string, stats: Stats) => {\n  const filePath = join(directory, `${name}-stats.json`);\n  const { chunks, ...data } = stats.toJson(); // omit chunks, which is about half of the total data\n  await new Promise((resolve, reject) => {\n    stringifyStream(data, null, 2)\n      .on('error', reject)\n      .pipe(createWriteStream(filePath))\n      .on('error', reject)\n      .on('finish', resolve as any);\n  });\n  return filePath;\n};\n"
  },
  {
    "path": "code/core/src/core-server/utils/parser/generic-parser.test.ts",
    "content": "import { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { describe, expect, it } from 'vitest';\n\nimport { GenericParser } from './generic-parser.ts';\n\nconst genericParser = new GenericParser();\n\nconst TEST_DIR = join(__dirname, '..', '__search-files-tests__');\n\ndescribe('generic-parser', () => {\n  it('should correctly return exports from ES modules', async () => {\n    const content = readFileSync(join(TEST_DIR, 'src', 'es-module.js'), 'utf-8');\n    const { exports } = await genericParser.parse(content);\n\n    expect(exports).toEqual([\n      {\n        default: false,\n        name: 'p',\n      },\n      {\n        default: false,\n        name: 'q',\n      },\n      {\n        default: false,\n        name: 'C',\n      },\n      {\n        default: false,\n        name: 'externalName',\n      },\n      {\n        default: false,\n        name: 'ns',\n      },\n      {\n        default: true,\n        name: 'default',\n      },\n    ]);\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/parser/generic-parser.ts",
    "content": "import { parser, types as t } from 'storybook/internal/babel';\n\nimport type { Parser, ParserResult } from './types.ts';\n\n/** A generic parser that can parse both ES and CJS modules. */\nexport class GenericParser implements Parser {\n  /**\n   * Parse the content of a file and return the exports\n   *\n   * @param content The content of the file\n   * @returns The exports of the file\n   */\n  async parse(content: string): Promise<ParserResult> {\n    const ast = parser.parse(content, {\n      allowImportExportEverywhere: true,\n      allowAwaitOutsideFunction: true,\n      allowNewTargetOutsideFunction: true,\n      allowReturnOutsideFunction: true,\n      allowUndeclaredExports: true,\n      plugins: [\n        // Language features\n        'typescript',\n        'jsx',\n        // Latest ECMAScript features\n        'asyncGenerators',\n        'bigInt',\n        'classProperties',\n        'classPrivateProperties',\n        'classPrivateMethods',\n        'classStaticBlock',\n        'dynamicImport',\n        'exportNamespaceFrom',\n        'logicalAssignment',\n        'moduleStringNames',\n        'nullishCoalescingOperator',\n        'numericSeparator',\n        'objectRestSpread',\n        'optionalCatchBinding',\n        'optionalChaining',\n        'privateIn',\n        'regexpUnicodeSets',\n        'topLevelAwait',\n        // ECMAScript proposals\n        'asyncDoExpressions',\n        'decimal',\n        'decorators',\n        'decoratorAutoAccessors',\n        'deferredImportEvaluation',\n        'destructuringPrivate',\n        'doExpressions',\n        'explicitResourceManagement',\n        'exportDefaultFrom',\n        'functionBind',\n        'functionSent',\n        'importAttributes',\n        'importReflection',\n        'moduleBlocks',\n        'partialApplication',\n        'recordAndTuple',\n        'sourcePhaseImports',\n        'throwExpressions',\n      ],\n    });\n\n    const exports: ParserResult['exports'] = [];\n\n    ast.program.body.forEach(function traverse(node) {\n      if (t.isExportNamedDeclaration(node)) {\n        // Handles function declarations: `export function a() {}`\n        if (t.isFunctionDeclaration(node.declaration) && t.isIdentifier(node.declaration.id)) {\n          exports.push({\n            name: node.declaration.id.name,\n            default: false,\n          });\n        }\n        // Handles class declarations: `export class A {}`\n        if (t.isClassDeclaration(node.declaration) && t.isIdentifier(node.declaration.id)) {\n          exports.push({\n            name: node.declaration.id.name,\n            default: false,\n          });\n        }\n        // Handles export specifiers: `export { a }`\n        if (node.declaration === null && node.specifiers.length > 0) {\n          node.specifiers.forEach((specifier) => {\n            if (t.isExportSpecifier(specifier) && t.isIdentifier(specifier.exported)) {\n              exports.push({\n                name: specifier.exported.name,\n                default: false,\n              });\n            }\n          });\n        }\n        if (t.isVariableDeclaration(node.declaration)) {\n          node.declaration.declarations.forEach((declaration) => {\n            // Handle variable declarators: `export const a = 1;`\n            if (t.isVariableDeclarator(declaration) && t.isIdentifier(declaration.id)) {\n              exports.push({\n                name: declaration.id.name,\n                default: false,\n              });\n            }\n          });\n        }\n      } else if (t.isExportDefaultDeclaration(node)) {\n        exports.push({\n          name: 'default',\n          default: true,\n        });\n      }\n    });\n\n    return { exports };\n  }\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/parser/index.ts",
    "content": "import type { SupportedRenderer } from 'storybook/internal/types';\n\nimport { GenericParser } from './generic-parser.ts';\nimport type { Parser } from './types.ts';\n\n/**\n * Get the parser for a given renderer\n *\n * @param renderer The renderer to get the parser for\n * @returns The parser for the renderer\n */\nexport function getParser(renderer: SupportedRenderer | null): Parser {\n  switch (renderer) {\n    default:\n      return new GenericParser();\n  }\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/parser/types.ts",
    "content": "export type ParserResult = {\n  exports: Array<{\n    name: string;\n    default: boolean;\n  }>;\n};\n\n/** A parser that can parse the exports of a file */\nexport interface Parser {\n  /**\n   * Parse the content of a file and return the exports\n   *\n   * @param content The content of the file\n   * @returns The result of the parsing. Contains the exports of the file\n   */\n  parse: (content: string) => Promise<ParserResult>;\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/remove-mdx-entries.ts",
    "content": "import { isAbsolute, join, relative } from 'node:path';\n\nimport { commonGlobOptions, normalizeStories } from 'storybook/internal/common';\nimport type { Options, StoriesEntry } from 'storybook/internal/types';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport { glob } from 'glob';\n// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\n\nexport async function removeMDXEntries(\n  entries: StoriesEntry[],\n  options: Pick<Options, 'configDir'>\n): Promise<StoriesEntry[]> {\n  const list = normalizeStories(entries, {\n    configDir: options.configDir,\n    workingDir: options.configDir,\n    defaultFilesPattern: '**/*.@(stories.@(js|jsx|mjs|ts|tsx))',\n  });\n  const result = (\n    await Promise.all(\n      list.map(async ({ directory, files, titlePrefix }) => {\n        const pattern = join(directory, files);\n        const absolutePattern = isAbsolute(pattern) ? pattern : join(options.configDir, pattern);\n        const absoluteDirectory = isAbsolute(directory)\n          ? directory\n          : join(options.configDir, directory);\n\n        return {\n          files: (\n            await glob(slash(absolutePattern), {\n              ...commonGlobOptions(absolutePattern),\n              follow: true,\n            })\n          ).map((f) => relative(absoluteDirectory, f)),\n          directory,\n          titlePrefix,\n        };\n      })\n    )\n  ).flatMap<StoriesEntry>(({ directory, files, titlePrefix }, i) => {\n    const filteredEntries = files.filter((s) => !s.endsWith('.mdx'));\n    // only return the filtered entries when there is something to filter\n    // as webpack is faster with unexpanded globs\n    let items = [];\n    if (filteredEntries.length < files.length) {\n      items = filteredEntries.map((k) => ({\n        directory,\n        titlePrefix,\n        files: `**/${k}`,\n      }));\n    } else {\n      items = [\n        { directory: list[i].directory, titlePrefix: list[i].titlePrefix, files: list[i].files },\n      ];\n    }\n\n    return items;\n  });\n  return result;\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/safeString.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { escapeForTemplate } from './safeString.ts';\n\ndescribe('safeString', () => {\n  describe('escapeForTemplate', () => {\n    it('should escape backticks in template strings', () => {\n      expect(escapeForTemplate('button`s.tsx')).toMatchInlineSnapshot('\"button\\\\`s.tsx\"');\n    });\n\n    it('should escape dollar signs for template expressions', () => {\n      expect(escapeForTemplate('button$file.tsx')).toMatchInlineSnapshot('\"button\\\\$file.tsx\"');\n    });\n\n    it('should escape backslashes', () => {\n      expect(escapeForTemplate('button\\\\file.tsx')).toMatchInlineSnapshot('\"button\\\\\\\\file.tsx\"');\n    });\n\n    it('should escape quotes', () => {\n      expect(escapeForTemplate(\"button's.tsx\")).toMatchInlineSnapshot(`\"button\\\\'s.tsx\"`);\n      expect(escapeForTemplate('button\"s.tsx')).toMatchInlineSnapshot(`\"button\\\\\"s.tsx\"`);\n    });\n\n    it('should handle multiple special characters', () => {\n      expect(escapeForTemplate('button`${file}\\\\path.tsx')).toMatchInlineSnapshot(\n        `\"button\\\\\\`\\\\\\${file}\\\\\\\\path.tsx\"`\n      );\n    });\n\n    it('should preserve normal file paths', () => {\n      expect(escapeForTemplate('./src/components/Button.tsx')).toMatchInlineSnapshot(\n        '\"./src/components/Button.tsx\"'\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/safeString.ts",
    "content": "/**\n * Escape special characters in a string for safe use within template literals in generated code.\n * This escapes backticks and template expression delimiters.\n *\n * @example\n *\n * ```ts\n * const fileName = \"button's.tsx\";\n * const template = `import Button from './${escapeForTemplate(fileName)}'`;\n * // Results in: import Button from './button\\\\'s.tsx'\n * ```\n */\nexport function escapeForTemplate(str: string): string {\n  return str\n    .replace(/\\\\/g, '\\\\\\\\') // Escape backslashes first\n    .replace(/(['\"$`])/g, '\\\\$&') // Then escape quotes, dollar signs, and backticks\n    .replace(/[\\n\\r]/g, '\\\\$&'); // Then newlines\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/save-story/duplicate-story-with-new-name.test.ts",
    "content": "import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { describe, expect, test } from 'vitest';\n\nimport { printCsf, readCsf } from 'storybook/internal/csf-tools';\n\nimport { format } from 'prettier';\n\nimport { duplicateStoryWithNewName } from './duplicate-story-with-new-name.ts';\nimport { getDiff } from './getDiff.ts';\n\nconst makeTitle = (userTitle: string) => userTitle;\n\nconst FILES = {\n  csfVariances: join(__dirname, 'mocks/csf-variances.stories.tsx'),\n  csf4Variances: join(__dirname, 'mocks/csf4-variances.stories.tsx'),\n  unsupportedCsfVariances: join(__dirname, 'mocks/unsupported-csf-variances.stories.tsx'),\n  typescriptConstructs: join(__dirname, 'mocks/typescript-constructs.stories.tsx'),\n};\n\ndescribe('success', () => {\n  test('CSF Variances', async () => {\n    const before = await format(await readFile(FILES.csfVariances, 'utf-8'), {\n      parser: 'typescript',\n    });\n    const CSF = await readCsf(FILES.csfVariances, { makeTitle });\n\n    const parsed = CSF.parse();\n    const names = Object.keys(parsed._stories);\n\n    names.forEach((name) => {\n      duplicateStoryWithNewName(parsed, name, name + 'Duplicated');\n    });\n\n    const after = await format(printCsf(parsed).code, {\n      parser: 'typescript',\n    });\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n            canvasElement.style.backgroundColor = \"red\";\n          },\n        } satisfies Story;\n        \n      + export const EmptyDuplicated = {} satisfies Story;\n      + export const EmptyWithCommentDuplicated = {} satisfies Story;\n      + export const OnlyArgsDuplicated = {} satisfies Story;\n      + \n      + export const RenderNoArgsDuplicated = {\n      +   render: (args) => <MyComponent {...args} />,\n      + } satisfies Story;\n      + \n      + export const RenderArgsDuplicated = {\n      +   render: (args) => <MyComponent {...args} />,\n      + } satisfies Story;\n      + \n      + export const RenderExistingArgsDuplicated = {\n      +   render: (args) => <MyComponent {...args} />,\n      + } satisfies Story;\n      + \n      + export const OrderedArgsDuplicated = {\n      +   render: (args) => <MyComponent {...args} />,\n      + } satisfies Story;\n      + \n      + export const HasPlayFunctionDuplicated = {\n      +   play: async ({ canvasElement }) => {\n      +     console.log(\"play\");\n      + \n      +     canvasElement.style.backgroundColor = \"red\";\n      +   },\n      + } satisfies Story;\n      + \"\n    `);\n  });\n  test('CSF4 Variances', async () => {\n    const before = await format(await readFile(FILES.csf4Variances, 'utf-8'), {\n      parser: 'typescript',\n    });\n    const CSF = await readCsf(FILES.csf4Variances, { makeTitle });\n\n    const parsed = CSF.parse();\n    const names = Object.keys(parsed._stories);\n\n    names.forEach((name) => {\n      duplicateStoryWithNewName(parsed, name, name + 'Duplicated');\n    });\n\n    const after = await format(printCsf(parsed).code, {\n      parser: 'typescript',\n    });\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n            foo: \"bar\",\n          },\n        });\n        \n      + export const EmptyDuplicated = meta.story({});\n      + export const WithArgsDuplicated = meta.story({});\n      + \"\n    `);\n  });\n  test('Unsupported CSF Variances', async () => {\n    const CSF = await readCsf(FILES.unsupportedCsfVariances, { makeTitle });\n\n    const parsed = CSF.parse();\n    const names = Object.keys(parsed._stories);\n\n    for (const name of names) {\n      await expect(() => duplicateStoryWithNewName(parsed, name, name + 'Duplicated')).toThrow();\n    }\n  });\n  test('Typescript Constructs', async () => {\n    const before = await format(await readFile(FILES.typescriptConstructs, 'utf-8'), {\n      parser: 'typescript',\n    });\n    const CSF = await readCsf(FILES.typescriptConstructs, { makeTitle });\n\n    const parsed = CSF.parse();\n    const names = Object.keys(parsed._stories);\n\n    names.forEach((name) => {\n      duplicateStoryWithNewName(parsed, name, name + 'Duplicated');\n    });\n\n    const after = await format(printCsf(parsed).code, {\n      parser: 'typescript',\n    });\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n            initial: \"bar\",\n          },\n        };\n        \n      + export const CastDuplicated: Story = {};\n      + export const AsDuplicated = {} as Story;\n      + export const SatisfiesDuplicated = {} satisfies Story;\n      + export const NoneDuplicated = {};\n      + \"\n    `);\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/save-story/duplicate-story-with-new-name.ts",
    "content": "import { types as t, traverse } from 'storybook/internal/babel';\nimport type { CsfFile } from 'storybook/internal/csf-tools';\n\nimport { SaveStoryError } from './utils.ts';\n\ntype In = ReturnType<CsfFile['parse']>;\n\nexport const duplicateStoryWithNewName = (csfFile: In, storyName: string, newStoryName: string) => {\n  const node = csfFile._storyExports[storyName];\n  const cloned = t.cloneNode(node) as t.VariableDeclarator;\n\n  if (!cloned) {\n    throw new SaveStoryError(`cannot clone Node`);\n  }\n\n  let found = false;\n  traverse(cloned, {\n    Identifier(path) {\n      if (found) {\n        return;\n      }\n\n      if (path.node.name === storyName) {\n        found = true;\n        path.node.name = newStoryName;\n      }\n    },\n    ObjectProperty(path) {\n      const key = path.get('key');\n      if (key.isIdentifier() && key.node.name === 'args') {\n        path.remove();\n      }\n    },\n\n    noScope: true,\n  });\n\n  const isCsf4Story =\n    t.isCallExpression(cloned.init) &&\n    t.isMemberExpression(cloned.init.callee) &&\n    t.isIdentifier(cloned.init.callee.property) &&\n    cloned.init.callee.property.name === 'story';\n\n  // detect CSF2 and throw\n  if (\n    !isCsf4Story &&\n    (t.isArrowFunctionExpression(cloned.init) || t.isCallExpression(cloned.init))\n  ) {\n    throw new SaveStoryError(`Creating a new story based on a CSF2 story is not supported`);\n  }\n\n  traverse(csfFile._ast, {\n    Program(path) {\n      path.pushContainer(\n        'body',\n        t.exportNamedDeclaration(t.variableDeclaration('const', [cloned]))\n      );\n    },\n  });\n\n  return cloned;\n};\n"
  },
  {
    "path": "code/core/src/core-server/utils/save-story/getDiff.ts",
    "content": "import { diffLines } from 'diff';\n\n/**\n * Get a diff between two strings\n *\n * @example\n *\n * ```ts\n * const before = 'foo\\nbar\\nbaz';\n * const after = 'foo\\nbaz';\n * const diff = getDiff(before, after);\n * console.log(diff);\n * //   foo\n * // - bar\n * //   baz\n * ```\n *\n * @param before The original string\n * @param after The new string\n * @returns The diff as a string\n */\nexport function getDiff(before: string, after: string): string {\n  const context = 4;\n  return diffLines(before, after, {})\n    .map((r, index, l) => {\n      const lines = r.value.split('\\n');\n\n      if (r.removed) {\n        return r.value\n          .split('\\n')\n          .map((v) => `- ${v}`)\n          .join('\\n');\n      }\n      if (r.added) {\n        return r.value\n          .split('\\n')\n          .map((v) => `+ ${v}`)\n          .join('\\n');\n      }\n\n      if (index === 0) {\n        const sliced = lines.slice(0 - context);\n\n        if (sliced.length !== lines.length) {\n          sliced.unshift('...');\n        }\n        return sliced.map((v) => `  ${v}`).join('\\n');\n      }\n\n      if (index === l.length - 1) {\n        const sliced = lines.slice(0, context);\n\n        if (sliced.length !== lines.length) {\n          sliced.push('...');\n        }\n        return sliced.map((v) => `  ${v}`).join('\\n');\n      }\n\n      if (lines.length <= context * 2 + 1) {\n        return lines.map((v) => `  ${v}`).join('\\n');\n      }\n      return [\n        //\n        ...lines.slice(0, context).map((v) => `  ${v}`),\n        '...',\n        ...lines.slice(0 - context).map((v) => `  ${v}`),\n      ].join('\\n');\n    })\n    .join('\\n');\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/save-story/mocks/csf-variances.stories.tsx",
    "content": "import React from 'react';\nimport type { FC } from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nexport default {\n  title: 'MyComponent',\n  args: {\n    initial: 'foo',\n  },\n} satisfies Meta<typeof MyComponent>;\n\ntype Story = StoryObj<typeof MyComponent>;\n\n// dummy component\nconst MyComponent: FC<{ absolute: boolean; bordered: boolean; initial: string }> = (props) => (\n  <pre>{JSON.stringify(props)}</pre>\n);\n\nexport const Empty = {} satisfies Story;\n\nexport const EmptyWithComment = {\n  // this is a useless comment, to test that it is preserved\n} satisfies Story;\n\nexport const OnlyArgs = {\n  args: {\n    absolute: true,\n  },\n} satisfies Story;\n\nexport const RenderNoArgs = {\n  render: (args) => <MyComponent {...args} />,\n} satisfies Story;\n\nexport const RenderArgs = {\n  args: {\n    absolute: true,\n  },\n  render: (args) => <MyComponent {...args} />,\n} satisfies Story;\n\nexport const RenderExistingArgs = {\n  args: {\n    absolute: true,\n    bordered: true,\n    initial: 'test2',\n  },\n  render: (args) => <MyComponent {...args} />,\n} satisfies Story;\n\n// The order of both the properties of the story and the order of args should be preserved\nexport const OrderedArgs = {\n  args: {\n    bordered: true,\n    initial: 'test2',\n    absolute: true,\n  },\n  render: (args) => <MyComponent {...args} />,\n} satisfies Story;\n\n// The order of both the properties of the story and the order of args should be preserved\nexport const HasPlayFunction = {\n  args: {\n    bordered: true,\n    initial: 'test2',\n    absolute: true,\n  },\n  play: async ({ canvasElement }) => {\n    console.log('play');\n\n    canvasElement.style.backgroundColor = 'red';\n  },\n} satisfies Story;\n"
  },
  {
    "path": "code/core/src/core-server/utils/save-story/mocks/csf4-variances.stories.tsx",
    "content": "// @ts-expect-error this is just a mock file\nimport preview from '#.storybook/preview';\n\nconst meta = preview.meta({\n  title: 'MyComponent',\n  args: {\n    initial: 'foo',\n  },\n});\nexport const Empty = meta.story({});\nexport const WithArgs = meta.story({\n  args: {\n    foo: 'bar',\n  },\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/save-story/mocks/data-variances.stories.tsx",
    "content": "import React from 'react';\nimport type { FC } from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nexport default {\n  title: 'MyComponent',\n  args: {\n    myString: 'foo',\n  },\n} satisfies Meta<typeof MyComponent>;\n\ntype Story = StoryObj<typeof MyComponent>;\n\n// dummy component\nconst MyComponent: FC<{\n  myUndefined: undefined;\n  myNull: null;\n  myBoolean: boolean;\n  myString: string;\n  myNumber: number;\n  myArray: string[];\n  myArrayDeep: string[][];\n  myObject: object;\n  myFunction: () => void;\n}> = (props) => <pre>{JSON.stringify(props)}</pre>;\n\nexport const All = {\n  args: {\n    myArray: ['foo', 'bar'],\n    myArrayDeep: [['foo'], ['bar']],\n    myBoolean: true,\n    myFunction: () => {},\n    myNull: null,\n    myNumber: 42,\n    myObject: {\n      foo: 'bar',\n    },\n    myString: 'foo',\n    myUndefined: undefined,\n  },\n} satisfies Story;\n\nexport const None = {\n  args: {},\n} satisfies Story;\n"
  },
  {
    "path": "code/core/src/core-server/utils/save-story/mocks/export-variances.stories.tsx",
    "content": "import React from 'react';\nimport type { FC } from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nexport default {\n  title: 'MyComponent',\n  args: {\n    initial: 'foo',\n  },\n} satisfies Meta<typeof MyComponent>;\n\ntype Story = StoryObj<typeof MyComponent>;\n\n// dummy component\nconst MyComponent: FC<{ absolute: boolean; bordered: boolean; initial: string }> = (props) => (\n  <pre>{JSON.stringify(props)}</pre>\n);\n\nexport const DirectExport: Story = {\n  args: {\n    initial: 'bar',\n  },\n};\n\nconst BlockExport: Story = {\n  args: {\n    initial: 'bar',\n  },\n};\n\nconst NotYetRenamedExport: Story = {\n  args: {\n    initial: 'bar',\n  },\n};\n\nexport { BlockExport, NotYetRenamedExport as RenamedExport };\n"
  },
  {
    "path": "code/core/src/core-server/utils/save-story/mocks/typescript-constructs.stories.tsx",
    "content": "import React from 'react';\nimport type { FC } from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nexport default {\n  title: 'MyComponent',\n  args: {\n    initial: 'foo',\n  },\n} satisfies Meta<typeof MyComponent>;\n\ntype Story = StoryObj<typeof MyComponent>;\n\n// dummy component\nconst MyComponent: FC<{ absolute: boolean; bordered: boolean; initial: string }> = (props) => (\n  <pre>{JSON.stringify(props)}</pre>\n);\n\nexport const Cast: Story = {\n  args: {\n    initial: 'bar',\n  },\n};\n\nexport const As = {\n  args: {\n    initial: 'bar',\n  },\n} as Story;\n\nexport const Satisfies = {\n  args: {\n    initial: 'bar',\n  },\n} satisfies Story;\n\nexport const None = {\n  args: {\n    initial: 'bar',\n  },\n};\n"
  },
  {
    "path": "code/core/src/core-server/utils/save-story/mocks/unsupported-csf-variances.stories.tsx",
    "content": "import React from 'react';\nimport type { FC } from 'react';\n\nimport type { Meta } from '@storybook/react-vite';\n\nexport default {\n  title: 'MyComponent',\n  args: {\n    initial: 'foo',\n  },\n} satisfies Meta<typeof MyComponent>;\n\n// dummy component\nconst MyComponent: FC<{ absolute: boolean; bordered: boolean; initial: string }> = (props) => (\n  <pre>{JSON.stringify(props)}</pre>\n);\n\nexport const CSF2 = () => <MyComponent absolute bordered initial=\"test2\" />;\n\nexport const CSF2b = CSF2.bind({});\n"
  },
  {
    "path": "code/core/src/core-server/utils/save-story/save-story.ts",
    "content": "import { writeFile } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\n\nimport type { Channel } from 'storybook/internal/channels';\nimport { formatFileContent } from 'storybook/internal/common';\nimport type {\n  RequestData,\n  ResponseData,\n  SaveStoryRequestPayload,\n  SaveStoryResponsePayload,\n} from 'storybook/internal/core-events';\nimport {\n  SAVE_STORY_REQUEST,\n  SAVE_STORY_RESPONSE,\n  STORY_RENDERED,\n} from 'storybook/internal/core-events';\nimport { storyNameFromExport, toId } from 'storybook/internal/csf';\nimport { printCsf, readCsf } from 'storybook/internal/csf-tools';\nimport { logger } from 'storybook/internal/node-logger';\nimport { isExampleStoryId, telemetry } from 'storybook/internal/telemetry';\nimport type { CoreConfig, Options } from 'storybook/internal/types';\n\nimport { duplicateStoryWithNewName } from './duplicate-story-with-new-name.ts';\nimport { updateArgsInCsfFile } from './update-args-in-csf-file.ts';\nimport { SaveStoryError } from './utils.ts';\n\nconst parseArgs = (args: string): Record<string, any> =>\n  JSON.parse(args, (_, value) => {\n    if (value === '__sb_empty_function_arg__') {\n      return () => {};\n    }\n    return value;\n  });\n\n// Removes extra newlines between story properties. See https://github.com/benjamn/recast/issues/242\n// Only updates the part of the code for the story with the given name.\nconst removeExtraNewlines = (code: string, name: string) => {\n  const anything = '([\\\\s\\\\S])'; // Multiline match for any character.\n  const newline = '(\\\\r\\\\n|\\\\r|\\\\n)'; // Either newlines or carriage returns may be used in the file.\n  const closing = newline + '};' + newline; // Marks the end of the story definition.\n  const regex = new RegExp(\n    // Looks for an export by the given name, considers the first closing brace on its own line\n    // to be the end of the story definition.\n    `^(?<before>${anything}*)(?<story>export const ${name} =${anything}+?${closing})(?<after>${anything}*)$`\n  );\n  const { before, story, after } = code.match(regex)?.groups || {};\n  return story\n    ? before + story.replaceAll(/(\\r\\n|\\r|\\n)(\\r\\n|\\r|\\n)([ \\t]*[a-z0-9_]+): /gi, '$2$3:') + after\n    : code;\n};\n\nexport function initializeSaveStory(channel: Channel, options: Options, coreConfig: CoreConfig) {\n  channel.on(SAVE_STORY_REQUEST, async ({ id, payload }: RequestData<SaveStoryRequestPayload>) => {\n    const { csfId, importPath, args, name } = payload;\n\n    let newStoryId: string | undefined;\n    let newStoryName: string | undefined;\n    let sourceFileName: string | undefined;\n    let sourceFilePath: string | undefined;\n    let sourceStoryName: string | undefined;\n\n    try {\n      sourceFileName = basename(importPath);\n      sourceFilePath = join(process.cwd(), importPath);\n\n      const csf = await readCsf(sourceFilePath, {\n        makeTitle: (userTitle: string) => userTitle || 'myTitle',\n      });\n\n      const parsed = csf.parse();\n      const stories = Object.entries(parsed._stories);\n\n      const [componentId, storyId] = csfId.split('--');\n      newStoryName = name && storyNameFromExport(name);\n      newStoryId = newStoryName && toId(componentId, newStoryName);\n\n      const [storyName] = stories.find(([key, value]) => value.id.endsWith(`--${storyId}`)) || [];\n      if (!storyName) {\n        throw new SaveStoryError(`Source story not found.`);\n      }\n      if (name && csf.getStoryExport(name)) {\n        throw new SaveStoryError(`Story already exists.`);\n      }\n\n      sourceStoryName = storyNameFromExport(storyName);\n\n      await updateArgsInCsfFile(\n        name ? duplicateStoryWithNewName(parsed, storyName, name) : csf.getStoryExport(storyName),\n        args ? parseArgs(args) : {}\n      );\n\n      const code = await formatFileContent(\n        sourceFilePath,\n        removeExtraNewlines(printCsf(csf).code, name || storyName)\n      );\n\n      // Writing the CSF file should trigger HMR, which causes the story to rerender. Delay the\n      // response until that happens, but don't wait too long.\n      await Promise.all([\n        new Promise<void>((resolve) => {\n          channel.on(STORY_RENDERED, resolve);\n          setTimeout(() => resolve(channel.off(STORY_RENDERED, resolve)), 3000);\n        }),\n        writeFile(sourceFilePath, code),\n      ]);\n\n      channel.emit(SAVE_STORY_RESPONSE, {\n        id,\n        success: true,\n        payload: {\n          csfId,\n          newStoryId,\n          newStoryName,\n          newStoryExportName: name,\n          sourceFileContent: code,\n          sourceFileName,\n          sourceStoryName,\n          sourceStoryExportName: storyName,\n        },\n        error: null,\n      } satisfies ResponseData<SaveStoryResponsePayload>);\n\n      // don't take credit for save-from-controls actions against CLI example stories\n      const isCLIExample = isExampleStoryId(newStoryId ?? csfId);\n      if (!coreConfig.disableTelemetry && !isCLIExample) {\n        await telemetry('save-story', {\n          action: name ? 'createStory' : 'updateStory',\n          success: true,\n        });\n      }\n    } catch (error: any) {\n      channel.emit(SAVE_STORY_RESPONSE, {\n        id,\n        success: false,\n        error: error instanceof SaveStoryError ? error.message : 'Unknown error',\n      } satisfies ResponseData<SaveStoryResponsePayload>);\n\n      logger.error(\n        `Error writing to ${sourceFilePath}:\\n${error.stack || error.message || error.toString()}`\n      );\n\n      if (!coreConfig.disableTelemetry && !(error instanceof SaveStoryError)) {\n        await telemetry('save-story', {\n          action: name ? 'createStory' : 'updateStory',\n          success: false,\n          error,\n        });\n      }\n    }\n  });\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/save-story/update-args-in-csf-file.test.ts",
    "content": "import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { describe, expect, test } from 'vitest';\n\nimport { printCsf, readCsf } from 'storybook/internal/csf-tools';\n\nimport { format } from 'prettier';\n\nimport { getDiff } from './getDiff.ts';\nimport { updateArgsInCsfFile } from './update-args-in-csf-file.ts';\n\nconst makeTitle = (userTitle: string) => userTitle;\n\nconst FILES = {\n  typescriptConstructs: join(__dirname, 'mocks/typescript-constructs.stories.tsx'),\n  csfVariances: join(__dirname, 'mocks/csf-variances.stories.tsx'),\n  csf4Variances: join(__dirname, 'mocks/csf4-variances.stories.tsx'),\n  unsupportedCsfVariances: join(__dirname, 'mocks/unsupported-csf-variances.stories.tsx'),\n  exportVariances: join(__dirname, 'mocks/export-variances.stories.tsx'),\n  dataVariances: join(__dirname, 'mocks/data-variances.stories.tsx'),\n};\n\ndescribe('success', () => {\n  test('Typescript Constructs', async () => {\n    const newArgs = { bordered: true, initial: 'test1' };\n\n    const before = await format(await readFile(FILES.typescriptConstructs, 'utf-8'), {\n      parser: 'typescript',\n    });\n    const CSF = await readCsf(FILES.typescriptConstructs, { makeTitle });\n\n    const parsed = CSF.parse();\n    const names = Object.keys(parsed._stories);\n    const nodes = names.map((name) => CSF.getStoryExport(name));\n\n    nodes.forEach((node) => {\n      updateArgsInCsfFile(node, newArgs);\n    });\n\n    const after = await format(printCsf(parsed).code, {\n      parser: 'typescript',\n    });\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        \n        export const Cast: Story = {\n          args: {\n        \n      -     initial: \"bar\",\n      - \n      +     initial: \"test1\",\n      +     bordered: true,\n      + \n          },\n        };\n        \n        export const As = {\n          args: {\n        \n      -     initial: \"bar\",\n      - \n      +     initial: \"test1\",\n      +     bordered: true,\n      + \n          },\n        } as Story;\n        \n        export const Satisfies = {\n          args: {\n        \n      -     initial: \"bar\",\n      - \n      +     initial: \"test1\",\n      +     bordered: true,\n      + \n          },\n        } satisfies Story;\n        \n        export const None = {\n          args: {\n        \n      -     initial: \"bar\",\n      - \n      +     initial: \"test1\",\n      +     bordered: true,\n      + \n          },\n        };\n        \"\n    `);\n  });\n  test('Unsupported CSF Variances', async () => {\n    const newArgs = { bordered: true, initial: 'test1' };\n\n    const CSF = await readCsf(FILES.unsupportedCsfVariances, { makeTitle });\n    const parsed = CSF.parse();\n    const names = Object.keys(parsed._stories);\n    const nodes = names.map((name) => CSF.getStoryExport(name));\n\n    for (const node of nodes) {\n      await expect(() => updateArgsInCsfFile(node, newArgs)).rejects.toThrowError();\n    }\n  });\n  test('CSF Variances', async () => {\n    const newArgs = { bordered: true, initial: 'test1' };\n\n    const before = await format(await readFile(FILES.csfVariances, 'utf-8'), {\n      parser: 'typescript',\n    });\n    const CSF = await readCsf(FILES.csfVariances, { makeTitle });\n\n    const parsed = CSF.parse();\n    const names = Object.keys(parsed._stories);\n    const nodes = names.map((name) => CSF.getStoryExport(name));\n\n    nodes.forEach((node) => {\n      updateArgsInCsfFile(node, newArgs);\n    });\n\n    const after = await format(printCsf(parsed).code, {\n      parser: 'typescript',\n    });\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    // TODO, the comment is not preserved!!!\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n          initial: string;\n        }> = (props) => <pre>{JSON.stringify(props)}</pre>;\n        \n        \n      - export const Empty = {} satisfies Story;\n      - \n      + export const Empty = {\n      +   args: {\n      +     bordered: true,\n      +     initial: \"test1\",\n      +   },\n      + } satisfies Story;\n      + \n        \n        export const EmptyWithComment = {\n        \n      -   // this is a useless comment, to test that it is preserved\n      - \n      +   args: {\n      +     bordered: true,\n      +     initial: \"test1\",\n      +   },\n      + \n        } satisfies Story;\n        \n        export const OnlyArgs = {\n          args: {\n            absolute: true,\n        \n      +     bordered: true,\n      +     initial: \"test1\",\n      + \n          },\n        } satisfies Story;\n        \n        export const RenderNoArgs = {\n        \n      +   args: {\n      +     bordered: true,\n      +     initial: \"test1\",\n      +   },\n      + \n      + \n          render: (args) => <MyComponent {...args} />,\n        } satisfies Story;\n        \n        export const RenderArgs = {\n          args: {\n            absolute: true,\n        \n      +     bordered: true,\n      +     initial: \"test1\",\n      + \n          },\n          render: (args) => <MyComponent {...args} />,\n        } satisfies Story;\n        \n        export const RenderExistingArgs = {\n          args: {\n            absolute: true,\n            bordered: true,\n        \n      -     initial: \"test2\",\n      - \n      +     initial: \"test1\",\n      + \n          },\n          render: (args) => <MyComponent {...args} />,\n        } satisfies Story;\n        \n        // The order of both the properties of the story and the order of args should be preserved\n        export const OrderedArgs = {\n          args: {\n            bordered: true,\n        \n      -     initial: \"test2\",\n      - \n      +     initial: \"test1\",\n      + \n            absolute: true,\n          },\n          render: (args) => <MyComponent {...args} />,\n        } satisfies Story;\n      ...\n        export const HasPlayFunction = {\n          args: {\n            bordered: true,\n        \n      -     initial: \"test2\",\n      - \n      +     initial: \"test1\",\n      + \n            absolute: true,\n          },\n          play: async ({ canvasElement }) => {\n            console.log(\"play\");\n        ...\"\n    `);\n  });\n  test('CSF4 Variances', async () => {\n    const newArgs = { bordered: true, initial: 'test1' };\n\n    const before = await format(await readFile(FILES.csf4Variances, 'utf-8'), {\n      parser: 'typescript',\n    });\n    const CSF = await readCsf(FILES.csf4Variances, { makeTitle });\n\n    const parsed = CSF.parse();\n    const names = Object.keys(parsed._stories);\n    const nodes = names.map((name) => CSF.getStoryExport(name));\n\n    nodes.forEach((node) => {\n      updateArgsInCsfFile(node, newArgs);\n    });\n\n    const after = await format(printCsf(parsed).code, {\n      parser: 'typescript',\n    });\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    // TODO, the comment is not preserved!!!\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n            initial: \"foo\",\n          },\n        });\n        \n      - export const Empty = meta.story({});\n      - \n      + export const Empty = meta.story({\n      +   args: {\n      +     bordered: true,\n      +     initial: \"test1\",\n      +   },\n      + });\n      + \n        export const WithArgs = meta.story({\n          args: {\n            foo: \"bar\",\n        \n      +     bordered: true,\n      +     initial: \"test1\",\n      + \n          },\n        });\n        \"\n    `);\n  });\n  test('Export Variances', async () => {\n    const newArgs = { bordered: true, initial: 'test1' };\n\n    const before = await format(await readFile(FILES.exportVariances, 'utf-8'), {\n      parser: 'typescript',\n    });\n    const CSF = await readCsf(FILES.exportVariances, { makeTitle });\n\n    const parsed = CSF.parse();\n    const names = Object.keys(parsed._stories);\n    const nodes = names.map((name) => CSF.getStoryExport(name));\n\n    nodes.forEach((node) => {\n      if (node === undefined) {\n        return;\n      }\n      updateArgsInCsfFile(node, newArgs);\n    });\n\n    const after = await format(printCsf(parsed).code, {\n      parser: 'typescript',\n    });\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    // TODO this is incomplete due to no support for export variances in csf-tools\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        \n        export const DirectExport: Story = {\n          args: {\n        \n      -     initial: \"bar\",\n      - \n      +     initial: \"test1\",\n      +     bordered: true,\n      + \n          },\n        };\n        \n        const BlockExport: Story = {\n        ...\"\n    `);\n  });\n  test('Data Variances', async () => {\n    const newArgs = {\n      myArray: ['FOO', 'BAR'],\n      myArrayDeep: [['FOO'], ['BAR']],\n      myBoolean: true,\n      myFunction: () => {},\n      myNull: null,\n      myNumber: 41,\n      myObject: {\n        FOO: 'BAR',\n      },\n      myString: 'FOO',\n      myUndefined: undefined,\n    };\n\n    const before = await format(await readFile(FILES.dataVariances, 'utf-8'), {\n      parser: 'typescript',\n    });\n    const CSF = await readCsf(FILES.dataVariances, { makeTitle });\n\n    const parsed = CSF.parse();\n    const names = Object.keys(parsed._stories);\n    const nodes = names.map((name) => CSF.getStoryExport(name));\n\n    nodes.forEach((node) => {\n      if (node === undefined) {\n        return;\n      }\n      updateArgsInCsfFile(node, newArgs);\n    });\n\n    const after = await format(printCsf(parsed).code, {\n      parser: 'typescript',\n    });\n\n    // check if the code was updated at all\n    expect(after).not.toBe(before);\n\n    // check if the code was updated correctly\n    expect(getDiff(before, after)).toMatchInlineSnapshot(`\n      \"  ...\n        \n        export const All = {\n          args: {\n        \n      -     myArray: [\"foo\", \"bar\"],\n      -     myArrayDeep: [[\"foo\"], [\"bar\"]],\n      - \n      +     myArray: [\"FOO\", \"BAR\"],\n      +     myArrayDeep: [[\"FOO\"], [\"BAR\"]],\n      + \n            myBoolean: true,\n            myFunction: () => {},\n            myNull: null,\n        \n      -     myNumber: 42,\n      - \n      +     myNumber: 41,\n      + \n            myObject: {\n        \n      -       foo: \"bar\",\n      - \n      +       FOO: \"BAR\",\n      + \n            },\n        \n      -     myString: \"foo\",\n      - \n      +     myString: \"FOO\",\n      + \n            myUndefined: undefined,\n          },\n        } satisfies Story;\n        \n        export const None = {\n        \n      -   args: {},\n      - \n      +   args: {\n      +     myArray: [\"FOO\", \"BAR\"],\n      +     myArrayDeep: [[\"FOO\"], [\"BAR\"]],\n      +     myBoolean: true,\n      +     myFunction: () => {},\n      +     myNull: null,\n      +     myNumber: 41,\n      + \n      +     myObject: {\n      +       FOO: \"BAR\",\n      +     },\n      + \n      +     myString: \"FOO\",\n      +     myUndefined: undefined,\n      +   },\n      + \n        } satisfies Story;\n        \"\n    `);\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/save-story/update-args-in-csf-file.ts",
    "content": "import { types as t, traverse } from 'storybook/internal/babel';\n\nimport { SaveStoryError } from './utils.ts';\nimport { valueToAST } from './valueToAST.ts';\n\nexport const updateArgsInCsfFile = async (node: t.Node, input: Record<string, any>) => {\n  let found = false;\n  const args = Object.fromEntries(\n    Object.entries(input).map(([k, v]) => {\n      return [k, valueToAST(v)];\n    })\n  );\n\n  const isCsf4Story =\n    t.isCallExpression(node) &&\n    t.isMemberExpression(node.callee) &&\n    t.isIdentifier(node.callee.property) &&\n    node.callee.property.name === 'story';\n\n  // detect CSF2 and throw\n  if (!isCsf4Story && (t.isArrowFunctionExpression(node) || t.isCallExpression(node))) {\n    throw new SaveStoryError(`Updating a CSF2 story is not supported`);\n  }\n\n  if (t.isObjectExpression(node)) {\n    const properties = node.properties;\n    const argsProperty = properties.find((property) => {\n      if (t.isObjectProperty(property)) {\n        const key = property.key;\n        return t.isIdentifier(key) && key.name === 'args';\n      }\n      return false;\n    });\n\n    if (argsProperty) {\n      if (t.isObjectProperty(argsProperty)) {\n        const a = argsProperty.value;\n        if (t.isObjectExpression(a)) {\n          a.properties.forEach((p) => {\n            if (t.isObjectProperty(p)) {\n              const key = p.key;\n              if (t.isIdentifier(key) && key.name in args) {\n                p.value = args[key.name];\n                delete args[key.name];\n              }\n            }\n          });\n\n          const remainder = Object.entries(args);\n          if (Object.keys(args).length) {\n            remainder.forEach(([key, value]) => {\n              a.properties.push(t.objectProperty(t.identifier(key), value));\n            });\n          }\n        }\n      }\n    } else {\n      properties.unshift(\n        t.objectProperty(\n          t.identifier('args'),\n          t.objectExpression(\n            Object.entries(args).map(([key, value]) => t.objectProperty(t.identifier(key), value))\n          )\n        )\n      );\n    }\n    return;\n  }\n\n  traverse(node, {\n    ObjectExpression(path) {\n      if (found) {\n        return;\n      }\n\n      found = true;\n      const properties = path.get('properties');\n      const argsProperty = properties.find((property) => {\n        if (property.isObjectProperty()) {\n          const key = property.get('key');\n          return key.isIdentifier() && key.node.name === 'args';\n        }\n        return false;\n      });\n\n      if (argsProperty) {\n        if (argsProperty.isObjectProperty()) {\n          const a = argsProperty.get('value');\n          if (a.isObjectExpression()) {\n            a.traverse({\n              ObjectProperty(p) {\n                const key = p.get('key');\n                if (key.isIdentifier() && key.node.name in args) {\n                  p.get('value').replaceWith(args[key.node.name]);\n                  delete args[key.node.name];\n                }\n              },\n              noScope: true,\n            });\n\n            const remainder = Object.entries(args);\n            if (Object.keys(args).length) {\n              remainder.forEach(([key, value]) => {\n                a.pushContainer('properties', t.objectProperty(t.identifier(key), value));\n              });\n            }\n          }\n        }\n      } else {\n        path.unshiftContainer(\n          'properties',\n          t.objectProperty(\n            t.identifier('args'),\n            t.objectExpression(\n              Object.entries(args).map(([key, value]) => t.objectProperty(t.identifier(key), value))\n            )\n          )\n        );\n      }\n    },\n\n    noScope: true,\n  });\n};\n"
  },
  {
    "path": "code/core/src/core-server/utils/save-story/utils.ts",
    "content": "export class SaveStoryError extends Error {}\n"
  },
  {
    "path": "code/core/src/core-server/utils/save-story/valueToAST.ts",
    "content": "import { parser, types as t } from 'storybook/internal/babel';\n\nexport function valueToAST<T>(literal: T): any {\n  if (literal === null) {\n    return t.nullLiteral();\n  }\n  switch (typeof literal) {\n    case 'function':\n      const ast = parser.parse(literal.toString(), {\n        allowReturnOutsideFunction: true,\n        allowSuperOutsideMethod: true,\n      });\n\n      // @ts-expect-error (it's the contents of the function, it's an expression, trust me)\n      return ast.program.body[0]?.expression;\n\n    case 'number':\n      return t.numericLiteral(literal);\n    case 'string':\n      return t.stringLiteral(literal);\n    case 'boolean':\n      return t.booleanLiteral(literal);\n    case 'undefined':\n      return t.identifier('undefined');\n    default:\n      if (Array.isArray(literal)) {\n        return t.arrayExpression(literal.map(valueToAST));\n      }\n      return t.objectExpression(\n        Object.keys(literal)\n          .filter((k) => {\n            // @ts-expect-error (it's a completely unknown object)\n            const value = literal[k];\n            return typeof value !== 'undefined';\n          })\n          .map((k) => {\n            // @ts-expect-error (it's a completely unknown object)\n            const value = literal[k];\n            return t.objectProperty(t.stringLiteral(k), valueToAST(value));\n          })\n      );\n  }\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/search-files.test.ts",
    "content": "import { join } from 'node:path';\n\nimport { describe, expect, it } from 'vitest';\n\nimport { searchFiles } from './search-files.ts';\n\ndescribe('search-files', () => {\n  it('should automatically convert static search to a dynamic glob search', async (t) => {\n    const files = await searchFiles({\n      searchQuery: 'ommonjs',\n      cwd: join(__dirname, '__search-files-tests__'),\n    });\n\n    expect(files).toEqual(['src/commonjs-module-default.js', 'src/commonjs-module.js']);\n  });\n\n  it('should automatically convert static search to a dynamic glob search (with file extension)', async (t) => {\n    const files = await searchFiles({\n      searchQuery: 'module.js',\n      cwd: join(__dirname, '__search-files-tests__'),\n    });\n\n    expect(files).toEqual(['src/commonjs-module.js', 'src/es-module.js']);\n  });\n\n  it('should return all files if the search query matches the parent folder', async (t) => {\n    const files = await searchFiles({\n      searchQuery: 'file-extensions',\n      cwd: join(__dirname, '__search-files-tests__'),\n    });\n\n    expect(files).toEqual([\n      'src/file-extensions/extension.cjs',\n      'src/file-extensions/extension.cts',\n      'src/file-extensions/extension.js',\n      'src/file-extensions/extension.jsx',\n      'src/file-extensions/extension.mjs',\n      'src/file-extensions/extension.mts',\n      'src/file-extensions/extension.ts',\n      'src/file-extensions/extension.tsx',\n    ]);\n  });\n\n  it('should ignore files that do not have the allowed extensions', async (t) => {\n    const files = await searchFiles({\n      searchQuery: 'asset',\n      cwd: join(__dirname, '__search-files-tests__'),\n    });\n\n    expect(files).toEqual([]);\n  });\n\n  it('should ignore test files (*.spec.*, *.test.*)', async (t) => {\n    const files = await searchFiles({\n      searchQuery: 'tests',\n      cwd: join(__dirname, '__search-files-tests__'),\n    });\n\n    expect(files).toEqual([]);\n  });\n\n  it('should work with glob search patterns', async (t) => {\n    const files = await searchFiles({\n      searchQuery: '**/commonjs-module.js',\n      cwd: join(__dirname, '__search-files-tests__'),\n    });\n\n    expect(files).toEqual(['src/commonjs-module.js']);\n  });\n\n  it('should respect glob but also the allowed file extensions', async (t) => {\n    const files = await searchFiles({\n      searchQuery: '**/*',\n      cwd: join(__dirname, '__search-files-tests__'),\n    });\n\n    expect(files).toEqual([\n      'src/commonjs-module-default.js',\n      'src/commonjs-module.js',\n      'src/es-module.js',\n      'src/no-export.js',\n      'src/file-extensions/extension.cjs',\n      'src/file-extensions/extension.cts',\n      'src/file-extensions/extension.js',\n      'src/file-extensions/extension.jsx',\n      'src/file-extensions/extension.mjs',\n      'src/file-extensions/extension.mts',\n      'src/file-extensions/extension.ts',\n      'src/file-extensions/extension.tsx',\n    ]);\n  });\n\n  it('should ignore node_modules', async (t) => {\n    const files = await searchFiles({\n      searchQuery: 'file-in-common.js',\n      cwd: join(__dirname, '__search-files-tests__'),\n    });\n\n    expect(files).toEqual([]);\n  });\n\n  it('should ignore story files', async (t) => {\n    const files = await searchFiles({\n      searchQuery: 'es-module.stories.js',\n      cwd: join(__dirname, '__search-files-tests__'),\n    });\n\n    expect(files).toEqual([]);\n  });\n\n  it('should not return files outside of project root', async (t) => {\n    await expect(() =>\n      searchFiles({\n        searchQuery: '../**/*',\n        cwd: join(__dirname, '__search-files-tests__'),\n      })\n    ).rejects.toThrowError();\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/search-files.ts",
    "content": "export type SearchResult = Array<string>;\n\n/** File extensions that should be searched for */\nconst FILE_EXTENSIONS = ['js', 'mjs', 'cjs', 'jsx', 'mts', 'ts', 'tsx', 'cts'];\n\nconst IGNORED_FILES = [\n  '**/node_modules/**',\n  '**/*.spec.*',\n  '**/*.test.*',\n  '**/*.stories.*',\n  '**/storybook-static/**',\n];\n\n/**\n * Search for files in a directory that match the search query\n *\n * @param searchQuery The search query. This can be a glob pattern\n * @param cwd The directory to search in\n * @param renderer The renderer to use for parsing the files\n * @returns A list of files that match the search query\n */\nexport async function searchFiles({\n  searchQuery,\n  cwd,\n  ignoredFiles = IGNORED_FILES,\n  fileExtensions = FILE_EXTENSIONS,\n}: {\n  searchQuery: string;\n  cwd: string;\n  ignoredFiles?: string[];\n  fileExtensions?: string[];\n}): Promise<SearchResult> {\n  // Dynamically import globby because it is a pure ESM module\n  // eslint-disable-next-line depend/ban-dependencies\n  const { globby, isDynamicPattern } = await import('globby');\n\n  const hasSearchSpecialGlobChars = isDynamicPattern(searchQuery, { cwd });\n\n  const hasFileExtensionRegex = /(\\.[a-z]+)$/i;\n  const searchQueryHasExtension = hasFileExtensionRegex.test(searchQuery);\n  const fileExtensionsPattern = `{${fileExtensions.join(',')}}`;\n\n  const globbedSearchQuery = hasSearchSpecialGlobChars\n    ? searchQuery\n    : searchQueryHasExtension\n      ? [`**/*${searchQuery}*`, `**/*${searchQuery}*/**`]\n      : [\n          `**/*${searchQuery}*.${fileExtensionsPattern}`,\n          `**/*${searchQuery}*/**/*.${fileExtensionsPattern}`,\n        ];\n\n  const entries = await globby(globbedSearchQuery, {\n    ignore: ignoredFiles,\n    gitignore: true,\n    caseSensitiveMatch: false,\n    cwd,\n    objectMode: true,\n  });\n\n  return entries\n    .map((entry) => entry.path)\n    .filter((entry) => fileExtensions.some((ext) => entry.endsWith(`.${ext}`)));\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/server-address.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport detectPort from 'detect-port';\n\nimport { getServerAddresses, getServerChannelUrl, getServerPort } from './server-address.ts';\n\nvi.mock('node:os', () => ({\n  default: { release: () => '' },\n  platform: 'darwin',\n  constants: {\n    signals: {},\n  },\n}));\nvi.mock('detect-port');\nvi.mock('storybook/internal/node-logger');\n\ndescribe('getServerAddresses', () => {\n  const port = 3000;\n  const host = 'localhost';\n  const proto = 'http';\n\n  it('should return server addresses without initial path by default', () => {\n    const expectedAddress = `${proto}://localhost:${port}/`;\n    const expectedNetworkAddress = `${proto}://${host}:${port}/`;\n\n    const result = getServerAddresses(port, host, proto);\n\n    expect(result.address).toBe(expectedAddress);\n    expect(result.networkAddress).toBe(expectedNetworkAddress);\n  });\n\n  it('should return server addresses with initial path', () => {\n    const initialPath = '/foo/bar';\n\n    const expectedAddress = `${proto}://localhost:${port}/?path=/foo/bar`;\n    const expectedNetworkAddress = `${proto}://${host}:${port}/?path=/foo/bar`;\n\n    const result = getServerAddresses(port, host, proto, initialPath);\n\n    expect(result.address).toBe(expectedAddress);\n    expect(result.networkAddress).toBe(expectedNetworkAddress);\n  });\n\n  it('should return server addresses with initial path and add slash if missing', () => {\n    const initialPath = 'foo/bar';\n\n    const expectedAddress = `${proto}://localhost:${port}/?path=/foo/bar`;\n    const expectedNetworkAddress = `${proto}://${host}:${port}/?path=/foo/bar`;\n\n    const result = getServerAddresses(port, host, proto, initialPath);\n\n    expect(result.address).toBe(expectedAddress);\n    expect(result.networkAddress).toBe(expectedNetworkAddress);\n  });\n});\n\ndescribe('getServerPort', () => {\n  const port = 3000;\n\n  it('should resolve with a free port', async () => {\n    const expectedFreePort = 4000;\n\n    vi.mocked(detectPort).mockResolvedValue(expectedFreePort);\n\n    const result = await getServerPort(port);\n\n    expect(result).toBe(expectedFreePort);\n  });\n});\n\ndescribe('getServerChannelUrl', () => {\n  const port = 3000;\n  it('should return WebSocket URL with HTTP', () => {\n    const options = { https: false };\n    const expectedUrl = `ws://localhost:${port}/storybook-server-channel`;\n\n    const result = getServerChannelUrl(port, options);\n\n    expect(result).toBe(expectedUrl);\n  });\n\n  it('should return WebSocket URL with HTTPS', () => {\n    const options = { https: true };\n    const expectedUrl = `wss://localhost:${port}/storybook-server-channel`;\n\n    const result = getServerChannelUrl(port, options);\n\n    expect(result).toBe(expectedUrl);\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/server-address.ts",
    "content": "import os from 'node:os';\n\nimport { logger } from 'storybook/internal/node-logger';\n\nimport detectFreePort from 'detect-port';\n\nexport function getServerAddresses(\n  port: number,\n  host: string | undefined,\n  proto: string,\n  initialPath?: string\n) {\n  const address = new URL(`${proto}://localhost:${port}/`);\n  const networkAddress = new URL(`${proto}://${host || getLocalIp()}:${port}/`);\n\n  if (initialPath) {\n    const searchParams = `?path=${decodeURIComponent(\n      initialPath.startsWith('/') ? initialPath : `/${initialPath}`\n    )}`;\n    address.search = searchParams;\n    networkAddress.search = searchParams;\n  }\n\n  return {\n    address: address.href,\n    networkAddress: networkAddress.href,\n  };\n}\n\ninterface PortOptions {\n  exactPort?: boolean;\n}\n\nexport const getServerPort = (port?: number, { exactPort }: PortOptions = {}) =>\n  detectFreePort(port)\n    .then((freePort) => {\n      if (freePort !== port && exactPort) {\n        process.exit(-1);\n      }\n      return freePort;\n    })\n    .catch((error) => {\n      logger.error(error);\n      process.exit(-1);\n    });\n\nexport const getServerChannelUrl = (port: number, { https }: { https?: boolean }) => {\n  return `${https ? 'wss' : 'ws'}://localhost:${port}/storybook-server-channel`;\n};\n\nconst getLocalIp = () => {\n  const allIps = Object.values(os.networkInterfaces()).flat();\n  const allFilteredIps = allIps.filter((ip) => ip && ip.family === 'IPv4' && !ip.internal);\n\n  return allFilteredIps.length ? allFilteredIps[0]?.address : '0.0.0.0';\n};\n"
  },
  {
    "path": "code/core/src/core-server/utils/server-init.ts",
    "content": "import { readFile } from 'node:fs/promises';\n\nimport { logger } from 'storybook/internal/node-logger';\n\nimport http from 'http';\nimport https from 'https';\n\nexport async function getServer(options: {\n  https?: boolean;\n  sslCert?: string;\n  sslKey?: string;\n  sslCa?: string[];\n}): Promise<http.Server | https.Server> {\n  if (!options.https) {\n    return http.createServer();\n  }\n\n  if (!options.sslCert) {\n    logger.error('Error: --ssl-cert is required with --https');\n    process.exit(-1);\n  }\n\n  if (!options.sslKey) {\n    logger.error('Error: --ssl-key is required with --https');\n    process.exit(-1);\n  }\n\n  const sslOptions = {\n    ca: await Promise.all((options.sslCa || []).map((ca) => readFile(ca, { encoding: 'utf8' }))),\n    cert: await readFile(options.sslCert, { encoding: 'utf8' }),\n    key: await readFile(options.sslKey, { encoding: 'utf8' }),\n  };\n\n  return https.createServer(sslOptions);\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/server-statics.ts",
    "content": "import { existsSync, statSync } from 'node:fs';\nimport { readFile, stat } from 'node:fs/promises';\nimport { basename, dirname, isAbsolute, join, posix, resolve, sep, win32 } from 'node:path';\n\nimport {\n  getDirectoryFromWorkingDir,\n  getProjectRoot,\n  resolvePathInStorybookCache,\n} from 'storybook/internal/common';\nimport { CLI_COLORS, logger, once } from 'storybook/internal/node-logger';\nimport type { Options, StorybookConfigRaw } from 'storybook/internal/types';\n\nimport { relative } from 'pathe';\nimport picocolors from 'picocolors';\nimport type { Polka } from 'polka';\nimport sirv from 'sirv';\nimport { dedent } from 'ts-dedent';\n\nimport { resolvePackageDir } from '../../shared/utils/module.ts';\n\nconst cacheDir = resolvePathInStorybookCache('', 'ignored-sub').split('ignored-sub')[0];\n\nconst files = new Map<string, { data: string; mtime: number }>();\nconst readFileOnce = async (path: string) => {\n  if (files.has(path)) {\n    return files.get(path)!;\n  } else {\n    const [data, stats] = await Promise.all([readFile(path, 'utf-8'), stat(path)]);\n    const result = { data, mtime: stats.mtimeMs };\n    files.set(path, result);\n    return result;\n  }\n};\n\nconst faviconWrapperPath = join(\n  resolvePackageDir('storybook'),\n  '/assets/browser/favicon-wrapper.svg'\n);\n\nexport const prepareNestedSvg = (svg: string) => {\n  const [, openingTag, contents, closingTag] = svg?.match(/(<svg[^>]*>)(.*?)(<\\/svg>)/s) ?? [];\n  if (!openingTag || !contents || !closingTag) {\n    return svg;\n  }\n\n  // Extract and set width/height in the opening tag\n  let width: number | undefined;\n  let height: number | undefined;\n  let modifiedTag = openingTag\n    .replace(/width=[\"']([^\"']*)[\"']/g, (_, value) => {\n      width = parseFloat(value);\n      return 'width=\"32px\"';\n    })\n    .replace(/height=[\"']([^\"']*)[\"']/g, (_, value) => {\n      height = parseFloat(value);\n      return 'height=\"32px\"';\n    });\n\n  // Set a viewBox to the original dimensions\n  const hasViewBox = /viewBox=[\"'][^\"']*[\"']/.test(modifiedTag);\n  if (!hasViewBox && width && height) {\n    modifiedTag = modifiedTag.replace(/>$/, ` viewBox=\"0 0 ${width} ${height}\">`);\n  }\n\n  // Add or replace preserveAspectRatio to center and contain the nested SVG\n  modifiedTag = modifiedTag\n    .replace(/preserveAspectRatio=[\"'][^\"']*[\"']/g, '')\n    .replace(/>$/, ' preserveAspectRatio=\"xMidYMid meet\">');\n\n  // Replace the original opening tag with our modified one\n  return modifiedTag + contents + closingTag;\n};\n\nexport async function useStatics(app: Polka, options: Options): Promise<void> {\n  const staticDirs = (await options.presets.apply('staticDirs')) ?? [];\n  const faviconPath = await options.presets.apply<string>('favicon');\n\n  // Fix for serving favicon in dev mode - use the directory containing the favicon\n  // rather than trying to serve the file directly\n  const faviconDir = resolve(faviconPath, '..');\n  const faviconFile = basename(faviconPath);\n  app.use(`/${faviconFile}`, async (req, res, next) => {\n    const status = req.query.status;\n    if (\n      status &&\n      faviconFile.endsWith('.svg') &&\n      ['active', 'critical', 'negative', 'positive', 'warning'].includes(status)\n    ) {\n      const [faviconInfo, faviconWrapperInfo] = await Promise.all([\n        readFileOnce(join(faviconDir, faviconFile)),\n        readFileOnce(faviconWrapperPath),\n      ]).catch((e) => {\n        if (e instanceof Error) {\n          once.warn(`Failed to read favicon: ${e.message}`);\n        }\n        return [null, null];\n      });\n\n      if (faviconInfo && faviconWrapperInfo) {\n        const svg = faviconWrapperInfo.data\n          .replace('<g id=\"mask\"', `<g mask=\"url(#${status}-mask)\"`)\n          .replace('<use id=\"status\"', `<use href=\"#${status}\"`)\n          .replace('<use id=\"icon\" />', prepareNestedSvg(faviconInfo.data));\n        res.setHeader('Content-Type', 'image/svg+xml');\n        res.setHeader('ETag', `\"${faviconWrapperInfo.mtime}-${faviconInfo.mtime}\"`);\n        res.end(svg);\n        return;\n      }\n    }\n\n    req.url = `/${faviconFile}`;\n    return sirvWorkaround(faviconDir)(req, res, next);\n  });\n\n  staticDirs.map((dir) => {\n    try {\n      const { staticDir, staticPath, targetEndpoint } = mapStaticDir(dir, options.configDir);\n\n      // Don't log for internal static dirs\n      if (!targetEndpoint.startsWith('/sb-') && !staticDir.startsWith(cacheDir)) {\n        const relativeStaticDir = relative(getProjectRoot(), staticDir);\n        logger.debug(\n          `Serving static files from ${CLI_COLORS.info(relativeStaticDir)} at ${CLI_COLORS.info(targetEndpoint)}`\n        );\n      }\n\n      if (existsSync(staticPath) && statSync(staticPath).isFile()) {\n        // sirv doesn't support serving single files, so we need to pass the file's directory to sirv instead\n        const staticPathDir = resolve(staticPath, '..');\n        const staticPathFile = basename(staticPath);\n        app.use(targetEndpoint, (req, res, next) => {\n          // Rewrite the URL to match the file's name, ensuring that we only ever serve the file\n          // even when sirv is passed the full directory\n          req.url = `/${staticPathFile}`;\n          sirvWorkaround(staticPathDir)(req, res, next);\n        });\n      } else {\n        app.use(targetEndpoint, sirvWorkaround(staticPath));\n      }\n    } catch (e) {\n      if (e instanceof Error) {\n        logger.warn(e.message);\n      }\n    }\n  });\n}\n\n/**\n * This is a workaround for sirv breaking when serving multiple directories on the same endpoint.\n *\n * @see https://github.com/lukeed/polka/issues/218\n */\nconst sirvWorkaround: typeof sirv =\n  (dir, opts = {}) =>\n  (req, res, next) => {\n    // polka+sirv will modify the request URL, so we need to restore it after sirv is done\n    // req._parsedUrl is an internal construct used by both polka and sirv\n    const originalParsedUrl = (req as any)._parsedUrl;\n\n    const maybeNext = next\n      ? () => {\n          (req as any)._parsedUrl = originalParsedUrl;\n          next();\n        }\n      : undefined;\n\n    sirv(dir, { dev: true, etag: true, extensions: [], ...opts })(req, res, maybeNext);\n  };\n\nexport const parseStaticDir = (arg: string) => {\n  // Split on last index of ':', for Windows compatibility (e.g. 'C:\\some\\dir:\\foo')\n  const lastColonIndex = arg.lastIndexOf(':');\n  const isWindowsAbsolute = win32.isAbsolute(arg);\n  const isWindowsRawDirOnly = isWindowsAbsolute && lastColonIndex === 1; // e.g. 'C:\\some\\dir'\n  const splitIndex = lastColonIndex !== -1 && !isWindowsRawDirOnly ? lastColonIndex : arg.length;\n  const [from, to] = [arg.slice(0, splitIndex), arg.slice(splitIndex + 1)];\n\n  const staticDir = isAbsolute(from) ? from : `./${from}`;\n  const staticPath = resolve(staticDir);\n\n  if (!existsSync(staticPath)) {\n    throw new Error(\n      dedent`\n        Failed to load static files, no such directory: ${picocolors.cyan(staticPath)}\n        Make sure this directory exists.\n      `\n    );\n  }\n\n  const targetRaw = to || (statSync(staticPath).isFile() ? basename(staticPath) : '/');\n  const target = targetRaw.split(sep).join(posix.sep); // Ensure target has forward-slash path\n  const targetDir = target.replace(/^\\/?/, './');\n  const targetEndpoint = targetDir.substring(1);\n\n  return { staticDir, staticPath, targetDir, targetEndpoint };\n};\n\nexport const mapStaticDir = (\n  staticDir: NonNullable<StorybookConfigRaw['staticDirs']>[number],\n  configDir: string\n) => {\n  const specifier = typeof staticDir === 'string' ? staticDir : `${staticDir.from}:${staticDir.to}`;\n  const normalizedDir = isAbsolute(specifier)\n    ? specifier\n    : getDirectoryFromWorkingDir({ configDir, workingDir: process.cwd(), directory: specifier });\n\n  return parseStaticDir(normalizedDir);\n};\n"
  },
  {
    "path": "code/core/src/core-server/utils/strip-comments-and-strings.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { stripCommentsAndStrings } from './strip-comments-and-strings.ts';\n\ndescribe('stripCommentsAndStrings', () => {\n  it('should remove single-quoted strings', () => {\n    expect(stripCommentsAndStrings(\"import x from './drei-exports.ts'\")).toBe('import x from \"\"');\n  });\n\n  it('should remove double-quoted strings', () => {\n    expect(stripCommentsAndStrings('const file = \"exports.ts\"')).toBe('const file = \"\"');\n  });\n\n  it('should remove template strings', () => {\n    expect(stripCommentsAndStrings('const path = `${dir}/exports.ts`')).toBe('const path = \"\"');\n  });\n\n  it('should remove line comments', () => {\n    expect(stripCommentsAndStrings('const x = 1 // exports.foo')).toBe('const x = 1 ');\n  });\n\n  it('should remove block comments', () => {\n    expect(stripCommentsAndStrings('/* exports.foo = 1 */ const x = 1')).toBe(' const x = 1');\n  });\n\n  it('should preserve code outside strings and comments', () => {\n    expect(stripCommentsAndStrings('module.exports = {}')).toBe('module.exports = {}');\n    expect(stripCommentsAndStrings('exports.foo = bar')).toBe('exports.foo = bar');\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/strip-comments-and-strings.ts",
    "content": "export function stripCommentsAndStrings(code: string): string {\n  let result = code.replace(/(['\"`])(?:\\\\.|(?!\\1)[\\s\\S])*?\\1/g, '\"\"');\n  result = result.replace(/\\/\\*[\\s\\S]*?\\*\\//g, '');\n  result = result\n    .split('\\n')\n    .map((line) => line.split('//')[0])\n    .join('\\n');\n  return result;\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/summarizeIndex.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { Tag } from '../../shared/constants/tags.ts';\nimport { isPageStory, summarizeIndex } from './summarizeIndex.ts';\n\ndescribe('isPageStory', () => {\n  describe('true positives', () => {\n    it.each(['pages/login', 'screens/login', 'components/LoginPage', 'components/LoginScreen'])(\n      '%s',\n      (title) => {\n        expect(isPageStory(title)).toBe(true);\n      }\n    );\n  });\n\n  describe('false positives', () => {\n    it.each([\n      'components/PagerStatus',\n      'components/DefectScreener',\n      'addons/docs/docspage/autoplay',\n    ])('%s', (title) => {\n      expect(isPageStory(title)).toBe(true);\n    });\n  });\n\n  describe('true negatives', () => {\n    it.each(['atoms/Button', 'components/Slider'])('%s', (title) => {\n      expect(isPageStory(title)).toBe(false);\n    });\n  });\n\n  describe('false negatives', () => {\n    it.each(['flows/login', 'login-flow/forgot password'])('%s', (title) => {\n      expect(isPageStory(title)).toBe(false);\n    });\n  });\n});\n\ndescribe('summarizeIndex', () => {\n  it('example stories', () => {\n    expect(\n      summarizeIndex({\n        v: 5,\n        entries: {\n          'example-introduction--docs': {\n            id: 'example-introduction--docs',\n            title: 'Example/Introduction',\n            name: 'Docs',\n            importPath: './src/stories/Introduction.mdx',\n            storiesImports: [],\n            type: 'docs',\n            tags: ['docs'],\n          },\n          'example-button--docs': {\n            id: 'example-button--docs',\n            title: 'Example/Button',\n            name: 'Docs',\n            importPath: './src/stories/Button.stories.ts',\n            type: 'docs',\n            tags: [Tag.AUTODOCS, 'docs'],\n            storiesImports: [],\n          },\n          'example-button--primary': {\n            id: 'example-button--primary',\n            title: 'Example/Button',\n            name: 'Primary',\n            importPath: './src/stories/Button.stories.ts',\n            tags: [Tag.AUTODOCS, 'story'],\n            type: 'story',\n            subtype: 'story',\n          },\n          'example-button--secondary': {\n            id: 'example-button--secondary',\n            title: 'Example/Button',\n            name: 'Secondary',\n            importPath: './src/stories/Button.stories.ts',\n            tags: [Tag.AUTODOCS, 'story'],\n            type: 'story',\n            subtype: 'story',\n          },\n          'example-button--large': {\n            id: 'example-button--large',\n            title: 'Example/Button',\n            name: 'Large',\n            importPath: './src/stories/Button.stories.ts',\n            tags: [Tag.AUTODOCS, 'story'],\n            type: 'story',\n            subtype: 'story',\n          },\n          'example-button--small': {\n            id: 'example-button--small',\n            title: 'Example/Button',\n            name: 'Small',\n            importPath: './src/stories/Button.stories.ts',\n            tags: [Tag.AUTODOCS, 'story'],\n            type: 'story',\n            subtype: 'story',\n          },\n          'example-header--docs': {\n            id: 'example-header--docs',\n            title: 'Example/Header',\n            name: 'Docs',\n            importPath: './src/stories/Header.stories.ts',\n            type: 'docs',\n            tags: [Tag.AUTODOCS, 'docs'],\n            storiesImports: [],\n          },\n          'example-header--logged-in': {\n            id: 'example-header--logged-in',\n            title: 'Example/Header',\n            name: 'Logged In',\n            importPath: './src/stories/Header.stories.ts',\n            tags: [Tag.AUTODOCS, 'story'],\n            type: 'story',\n            subtype: 'story',\n          },\n          'example-header--logged-out': {\n            id: 'example-header--logged-out',\n            title: 'Example/Header',\n            name: 'Logged Out',\n            importPath: './src/stories/Header.stories.ts',\n            tags: [Tag.AUTODOCS, 'story'],\n            type: 'story',\n            subtype: 'story',\n          },\n          'example-page--logged-out': {\n            id: 'example-page--logged-out',\n            title: 'Example/Page',\n            name: 'Logged Out',\n            importPath: './src/stories/Page.stories.ts',\n            tags: ['story'],\n            type: 'story',\n            subtype: 'story',\n          },\n          'example-page--logged-in': {\n            id: 'example-page--logged-in',\n            title: 'Example/Page',\n            name: 'Logged In',\n            importPath: './src/stories/Page.stories.ts',\n            tags: [Tag.PLAY_FN, 'story'],\n            type: 'story',\n            subtype: 'story',\n          },\n        },\n      })\n    ).toMatchInlineSnapshot(`\n      {\n        \"autodocsCount\": 0,\n        \"componentCount\": 0,\n        \"exampleDocsCount\": 3,\n        \"exampleStoryCount\": 8,\n        \"maxTestsPerStory\": 0,\n        \"mdxCount\": 0,\n        \"onboardingDocsCount\": 0,\n        \"onboardingStoryCount\": 0,\n        \"pageStoryCount\": 0,\n        \"playStoryCount\": 0,\n        \"singleTestStoryCount\": 0,\n        \"storyCount\": 0,\n        \"svelteCsfV4Count\": 0,\n        \"svelteCsfV5Count\": 0,\n        \"testStoryCount\": 0,\n        \"version\": 5,\n      }\n    `);\n  });\n  it('onboarding stories', () => {\n    expect(\n      summarizeIndex({\n        v: 5,\n        entries: {\n          'example-introduction--docs': {\n            id: 'example-introduction--docs',\n            title: 'Example/Introduction',\n            name: 'Docs',\n            importPath: './src/stories/Introduction.mdx',\n            storiesImports: [],\n            type: 'docs',\n            tags: ['docs'],\n          },\n          'example-button--docs': {\n            id: 'example-button--docs',\n            title: 'Example/Button',\n            name: 'Docs',\n            importPath: './src/stories/Button.stories.ts',\n            type: 'docs',\n            tags: [Tag.AUTODOCS, 'docs'],\n            storiesImports: [],\n          },\n          'example-button--primary': {\n            id: 'example-button--primary',\n            title: 'Example/Button',\n            name: 'Primary',\n            importPath: './src/stories/Button.stories.ts',\n            tags: [Tag.AUTODOCS, 'story'],\n            type: 'story',\n            subtype: 'story',\n          },\n          'example-button--warning': {\n            id: 'example-button--warning',\n            title: 'Example/Button',\n            name: 'Warning',\n            importPath: './src/stories/Button.stories.ts',\n            tags: [Tag.AUTODOCS, 'story', 'svelte-csf-v4'],\n            type: 'story',\n            subtype: 'story',\n          },\n        },\n      })\n    ).toMatchInlineSnapshot(`\n      {\n        \"autodocsCount\": 0,\n        \"componentCount\": 0,\n        \"exampleDocsCount\": 2,\n        \"exampleStoryCount\": 1,\n        \"maxTestsPerStory\": 0,\n        \"mdxCount\": 0,\n        \"onboardingDocsCount\": 0,\n        \"onboardingStoryCount\": 1,\n        \"pageStoryCount\": 0,\n        \"playStoryCount\": 0,\n        \"singleTestStoryCount\": 0,\n        \"storyCount\": 0,\n        \"svelteCsfV4Count\": 0,\n        \"svelteCsfV5Count\": 0,\n        \"testStoryCount\": 0,\n        \"version\": 5,\n      }\n    `);\n  });\n  it('user stories', () => {\n    expect(\n      summarizeIndex({\n        v: 5,\n        entries: {\n          'stories-renderers-react-errors--story-contains-unrenderable': {\n            id: 'stories-renderers-react-errors--story-contains-unrenderable',\n            title: 'stories/renderers/react/errors',\n            name: 'Story Contains Unrenderable',\n            importPath: './src/stories/renderers/react/errors.stories.tsx',\n            tags: ['story'],\n            type: 'story',\n            subtype: 'story',\n          },\n          'stories-renderers-react-hooks--basic': {\n            id: 'stories-renderers-react-hooks--basic',\n            title: 'stories/renderers/react/hooks',\n            name: 'Basic',\n            importPath: './src/stories/renderers/react/hooks.stories.tsx',\n            tags: ['story'],\n            type: 'story',\n            subtype: 'story',\n          },\n          'stories-renderers-react-js-argtypes--js-class-component': {\n            id: 'stories-renderers-react-js-argtypes--js-class-component',\n            title: 'stories/renderers/react/js-argtypes',\n            name: 'Js Class Component',\n            importPath: './src/stories/renderers/react/js-argtypes.stories.jsx',\n            tags: ['story', 'svelte-csf-v5'],\n            type: 'story',\n            subtype: 'story',\n          },\n          'stories-renderers-react-js-argtypes--js-function-component': {\n            id: 'stories-renderers-react-js-argtypes--js-function-component',\n            title: 'stories/renderers/react/js-argtypes',\n            name: 'Js Function Component',\n            importPath: './src/stories/renderers/react/js-argtypes.stories.jsx',\n            tags: ['story', 'svelte-csf-v4'],\n            type: 'story',\n            subtype: 'story',\n          },\n        },\n      })\n    ).toMatchInlineSnapshot(`\n      {\n        \"autodocsCount\": 0,\n        \"componentCount\": 3,\n        \"exampleDocsCount\": 0,\n        \"exampleStoryCount\": 0,\n        \"maxTestsPerStory\": 0,\n        \"mdxCount\": 0,\n        \"onboardingDocsCount\": 0,\n        \"onboardingStoryCount\": 0,\n        \"pageStoryCount\": 0,\n        \"playStoryCount\": 0,\n        \"singleTestStoryCount\": 0,\n        \"storyCount\": 4,\n        \"svelteCsfV4Count\": 1,\n        \"svelteCsfV5Count\": 1,\n        \"testStoryCount\": 0,\n        \"version\": 5,\n      }\n    `);\n  });\n  it('test function', () => {\n    expect(\n      summarizeIndex({\n        v: 5,\n        entries: {\n          'component-testing-test-fn--default': {\n            type: 'story',\n            subtype: 'story',\n            id: 'component-testing-test-fn--default',\n            name: 'Default',\n            title: 'component-testing/test-fn',\n            importPath: './core/src/component-testing/components/test-fn.stories.tsx',\n            tags: [Tag.DEV, Tag.TEST, 'vitest', 'some-tag'],\n          },\n          'component-testing-test-fn--default:simple': {\n            type: 'story',\n            subtype: 'story',\n            id: 'component-testing-test-fn--default:simple',\n            name: 'simple',\n            title: 'component-testing/test-fn',\n            importPath: './core/src/component-testing/components/test-fn.stories.tsx',\n            tags: [Tag.DEV, Tag.TEST, 'vitest', 'some-tag', Tag.TEST_FN],\n            parent: 'component-testing-test-fn--default',\n          },\n          'component-testing-test-fn--default:referring-to-function-in-file': {\n            type: 'story',\n            subtype: 'story',\n            id: 'component-testing-test-fn--default:referring-to-function-in-file',\n            name: 'referring to function in file',\n            title: 'component-testing/test-fn',\n            importPath: './core/src/component-testing/components/test-fn.stories.tsx',\n            tags: [Tag.DEV, Tag.TEST, 'vitest', 'some-tag', Tag.TEST_FN],\n            parent: 'component-testing-test-fn--default',\n          },\n          'component-testing-test-fn--default:with-overrides': {\n            type: 'story',\n            subtype: 'story',\n            id: 'component-testing-test-fn--default:with-overrides',\n            name: 'with overrides',\n            title: 'component-testing/test-fn',\n            importPath: './core/src/component-testing/components/test-fn.stories.tsx',\n            tags: [Tag.DEV, Tag.TEST, 'vitest', 'some-tag', Tag.TEST_FN],\n            parent: 'component-testing-test-fn--default',\n          },\n          'component-testing-test-fn--default:with-play-function': {\n            type: 'story',\n            subtype: 'story',\n            id: 'component-testing-test-fn--default:with-play-function',\n            name: 'with play function',\n            title: 'component-testing/test-fn',\n            importPath: './core/src/component-testing/components/test-fn.stories.tsx',\n            tags: [Tag.DEV, Tag.TEST, 'vitest', 'some-tag', Tag.TEST_FN],\n            parent: 'component-testing-test-fn--default',\n          },\n          'component-testing-test-fn--default-extended': {\n            type: 'story',\n            subtype: 'story',\n            id: 'component-testing-test-fn--default-extended',\n            name: 'Default Extended',\n            title: 'component-testing/test-fn',\n            importPath: './core/src/component-testing/components/test-fn.stories.tsx',\n            tags: [Tag.DEV, Tag.TEST, 'vitest', 'some-tag'],\n          },\n          'component-testing-test-fn--default-extended:should-have-extended-args': {\n            type: 'story',\n            subtype: 'story',\n            id: 'component-testing-test-fn--default-extended:should-have-extended-args',\n            name: 'should have extended args',\n            title: 'component-testing/test-fn',\n            importPath: './core/src/component-testing/components/test-fn.stories.tsx',\n            tags: [Tag.DEV, Tag.TEST, 'vitest', 'some-tag', Tag.TEST_FN],\n            parent: 'component-testing-test-fn--default-extended',\n          },\n        },\n      })\n    ).toMatchInlineSnapshot(`\n      {\n        \"autodocsCount\": 0,\n        \"componentCount\": 1,\n        \"exampleDocsCount\": 0,\n        \"exampleStoryCount\": 0,\n        \"maxTestsPerStory\": 4,\n        \"mdxCount\": 0,\n        \"onboardingDocsCount\": 0,\n        \"onboardingStoryCount\": 0,\n        \"pageStoryCount\": 0,\n        \"playStoryCount\": 0,\n        \"singleTestStoryCount\": 1,\n        \"storyCount\": 7,\n        \"svelteCsfV4Count\": 0,\n        \"svelteCsfV5Count\": 0,\n        \"testStoryCount\": 5,\n        \"version\": 5,\n      }\n    `);\n  });\n  it('pages', () => {\n    expect(\n      summarizeIndex({\n        v: 5,\n        entries: {\n          'example-page--logged-out': {\n            id: 'example-page--logged-out',\n            title: 'Example/Page',\n            name: 'Logged Out',\n            importPath: './src/stories/Page.stories.ts',\n            tags: ['story'],\n            type: 'story',\n            subtype: 'story',\n          },\n          'example-page--logged-in': {\n            id: 'example-page--logged-in',\n            title: 'Example/Page',\n            name: 'Logged In',\n            importPath: './src/stories/Page.stories.ts',\n            tags: [Tag.PLAY_FN, 'story'],\n            type: 'story',\n            subtype: 'story',\n          },\n          'addons-docs-docspage-autoplay--docs': {\n            id: 'addons-docs-docspage-autoplay--docs',\n            title: 'addons/docs/docspage/autoplay',\n            name: 'Docs',\n            importPath: './template-stories/addons/docs/docspage/autoplay.stories.ts',\n            type: 'docs',\n            tags: [Tag.AUTODOCS, 'docs'],\n            storiesImports: [],\n          },\n          'addons-docs-docspage-autoplay--no-autoplay': {\n            id: 'addons-docs-docspage-autoplay--no-autoplay',\n            title: 'addons/docs/docspage/autoplay',\n            name: 'No Autoplay',\n            importPath: './template-stories/addons/docs/docspage/autoplay.stories.ts',\n            tags: [Tag.PLAY_FN, 'story'],\n            type: 'story',\n            subtype: 'story',\n          },\n        },\n      })\n    ).toMatchInlineSnapshot(`\n      {\n        \"autodocsCount\": 1,\n        \"componentCount\": 1,\n        \"exampleDocsCount\": 0,\n        \"exampleStoryCount\": 2,\n        \"maxTestsPerStory\": 0,\n        \"mdxCount\": 0,\n        \"onboardingDocsCount\": 0,\n        \"onboardingStoryCount\": 0,\n        \"pageStoryCount\": 1,\n        \"playStoryCount\": 1,\n        \"singleTestStoryCount\": 0,\n        \"storyCount\": 1,\n        \"svelteCsfV4Count\": 0,\n        \"svelteCsfV5Count\": 0,\n        \"testStoryCount\": 0,\n        \"version\": 5,\n      }\n    `);\n  });\n  it('autodocs', () => {\n    expect(\n      summarizeIndex({\n        v: 5,\n        entries: {\n          'example-button--docs': {\n            id: 'example-button--docs',\n            title: 'Example/Button',\n            name: 'Docs',\n            importPath: './src/stories/Button.stories.ts',\n            type: 'docs',\n            tags: [Tag.AUTODOCS, 'docs'],\n            storiesImports: [],\n          },\n          'example-button--large': {\n            id: 'example-button--large',\n            title: 'Example/Button',\n            name: 'Large',\n            importPath: './src/stories/Button.stories.ts',\n            tags: [Tag.AUTODOCS, 'story'],\n            type: 'story',\n            subtype: 'story',\n          },\n          'example-button--small': {\n            id: 'example-button--small',\n            title: 'Example/Button',\n            name: 'Small',\n            importPath: './src/stories/Button.stories.ts',\n            tags: [Tag.AUTODOCS, 'story'],\n            type: 'story',\n            subtype: 'story',\n          },\n          'lib-preview-api-shortcuts--docs': {\n            id: 'lib-preview-api-shortcuts--docs',\n            title: 'lib/preview-api/shortcuts',\n            name: 'Docs',\n            importPath: './template-stories/lib/preview-api/shortcuts.stories.ts',\n            type: 'docs',\n            tags: [Tag.AUTODOCS, 'docs'],\n            storiesImports: [],\n          },\n        },\n      })\n    ).toMatchInlineSnapshot(`\n      {\n        \"autodocsCount\": 1,\n        \"componentCount\": 0,\n        \"exampleDocsCount\": 1,\n        \"exampleStoryCount\": 2,\n        \"maxTestsPerStory\": 0,\n        \"mdxCount\": 0,\n        \"onboardingDocsCount\": 0,\n        \"onboardingStoryCount\": 0,\n        \"pageStoryCount\": 0,\n        \"playStoryCount\": 0,\n        \"singleTestStoryCount\": 0,\n        \"storyCount\": 0,\n        \"svelteCsfV4Count\": 0,\n        \"svelteCsfV5Count\": 0,\n        \"testStoryCount\": 0,\n        \"version\": 5,\n      }\n    `);\n  });\n  it('mdx', () => {\n    expect(\n      summarizeIndex({\n        v: 5,\n        entries: {\n          'example-introduction--docs': {\n            id: 'example-introduction--docs',\n            title: 'Example/Introduction',\n            name: 'Docs',\n            importPath: './src/stories/Introduction.mdx',\n            storiesImports: [],\n            type: 'docs',\n            tags: ['docs'],\n          },\n          'addons-docs-docs2-notitle--docs': {\n            id: 'addons-docs-docs2-notitle--docs',\n            title: 'addons/docs/docs2/NoTitle',\n            name: 'Docs',\n            importPath: './template-stories/addons/docs/docs2/NoTitle.mdx',\n            storiesImports: [],\n            type: 'docs',\n            tags: ['docs', Tag.ATTACHED_MDX],\n          },\n          'addons-docs-yabbadabbadooo--docs': {\n            id: 'addons-docs-yabbadabbadooo--docs',\n            title: 'addons/docs/Yabbadabbadooo',\n            name: 'Docs',\n            importPath: './template-stories/addons/docs/docs2/Title.mdx',\n            storiesImports: [],\n            type: 'docs',\n            tags: ['docs', Tag.ATTACHED_MDX],\n          },\n        },\n      })\n    ).toMatchInlineSnapshot(`\n      {\n        \"autodocsCount\": 0,\n        \"componentCount\": 0,\n        \"exampleDocsCount\": 1,\n        \"exampleStoryCount\": 0,\n        \"maxTestsPerStory\": 0,\n        \"mdxCount\": 2,\n        \"onboardingDocsCount\": 0,\n        \"onboardingStoryCount\": 0,\n        \"pageStoryCount\": 0,\n        \"playStoryCount\": 0,\n        \"singleTestStoryCount\": 0,\n        \"storyCount\": 0,\n        \"svelteCsfV4Count\": 0,\n        \"svelteCsfV5Count\": 0,\n        \"testStoryCount\": 0,\n        \"version\": 5,\n      }\n    `);\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/summarizeIndex.ts",
    "content": "import { isExampleStoryId } from 'storybook/internal/telemetry';\nimport type { IndexEntry, StoryIndex } from 'storybook/internal/types';\n\nimport { Tag } from '../../shared/constants/tags.ts';\nimport { isMdxEntry } from './StoryIndexGenerator.ts';\n\nconst PAGE_REGEX = /(page|screen)/i;\n\nexport const isPageStory = (storyId: string) => PAGE_REGEX.test(storyId);\n\n/** Is this story generated by the CLI */\nconst isCLIExampleEntry = (entry: IndexEntry) =>\n  [\n    'example-introduction--docs',\n    'configure-your-project--docs',\n    'example-button--docs',\n    'example-button--primary',\n    'example-button--secondary',\n    'example-button--large',\n    'example-button--small',\n    'example-header--docs',\n    'example-header--logged-in',\n    'example-header--logged-out',\n    'example-page--logged-in',\n    'example-page--logged-out',\n  ].includes(entry.id);\n\nexport function summarizeIndex(storyIndex: StoryIndex) {\n  let storyCount = 0;\n  const componentTitles = new Set<string>();\n  let exampleStoryCount = 0;\n  let onboardingStoryCount = 0;\n  let onboardingDocsCount = 0;\n  let exampleDocsCount = 0;\n  let pageStoryCount = 0;\n  let playStoryCount = 0;\n  let testStoryCount = 0;\n  let autodocsCount = 0;\n  let mdxCount = 0;\n  let svelteCsfV4Count = 0;\n  let svelteCsfV5Count = 0;\n  const testsPerParentStory = new Map<string, number>();\n  Object.values(storyIndex.entries).forEach((entry) => {\n    if (isCLIExampleEntry(entry)) {\n      if (entry.type === 'story') {\n        exampleStoryCount += 1;\n      }\n\n      if (entry.type === 'docs') {\n        exampleDocsCount += 1;\n      }\n    } else if (isExampleStoryId(entry.id)) {\n      if (entry.type === 'story') {\n        onboardingStoryCount += 1;\n      }\n\n      if (entry.type === 'docs') {\n        onboardingDocsCount += 1;\n      }\n    } else if (entry.type === 'story') {\n      storyCount += 1;\n      componentTitles.add(entry.title);\n      if (isPageStory(entry.title)) {\n        pageStoryCount += 1;\n      }\n      if (entry.tags?.includes(Tag.PLAY_FN)) {\n        playStoryCount += 1;\n      }\n      if (entry.tags?.includes(Tag.TEST_FN) && entry.parent) {\n        testStoryCount += 1;\n        testsPerParentStory.set(entry.parent, (testsPerParentStory.get(entry.parent) ?? 0) + 1);\n      }\n      if (entry.tags?.includes('svelte-csf-v4')) {\n        svelteCsfV4Count += 1;\n      } else if (entry.tags?.includes('svelte-csf-v5')) {\n        svelteCsfV5Count += 1;\n      }\n    } else if (entry.type === 'docs') {\n      if (isMdxEntry(entry)) {\n        mdxCount += 1;\n      } else if (entry.tags?.includes(Tag.AUTODOCS)) {\n        autodocsCount += 1;\n      }\n    }\n  });\n  const componentCount = componentTitles.size;\n  let maxTestsPerStory = 0;\n  let singleTestStoryCount = 0;\n  testsPerParentStory.forEach((count) => {\n    if (count > maxTestsPerStory) {\n      maxTestsPerStory = count;\n    }\n    if (count === 1) {\n      singleTestStoryCount += 1;\n    }\n  });\n\n  return {\n    storyCount,\n    componentCount,\n    pageStoryCount,\n    playStoryCount,\n    testStoryCount,\n    maxTestsPerStory,\n    singleTestStoryCount,\n    autodocsCount,\n    mdxCount,\n    exampleStoryCount,\n    exampleDocsCount,\n    onboardingStoryCount,\n    onboardingDocsCount,\n    svelteCsfV4Count,\n    svelteCsfV5Count,\n    version: storyIndex.v,\n  };\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/summarizeStats.test.ts",
    "content": "import { expect, it } from 'vitest';\n\nimport { summarizeStats } from './summarizeStats.ts';\n\nit('should summarize stats', () => {\n  const stats = [\n    { play: true, render: true, storyFn: false },\n    { play: true, render: false, storyFn: false },\n    { play: false, render: false, storyFn: false },\n  ];\n  const result = summarizeStats(stats);\n  expect(result).toMatchInlineSnapshot(`\n    {\n      \"play\": 2,\n      \"render\": 1,\n      \"storyFn\": 0,\n    }\n  `);\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/summarizeStats.ts",
    "content": "import type { IndexInputStats } from 'storybook/internal/types';\n\nexport type IndexStatsSummary = Record<keyof IndexInputStats, number>;\n\nexport const addStats = (stat: IndexInputStats, acc: IndexStatsSummary) => {\n  Object.entries(stat).forEach(([key, value]) => {\n    const statsKey = key as keyof IndexInputStats;\n\n    if (!acc[statsKey]) {\n      acc[statsKey] = 0;\n    }\n    acc[statsKey] += value ? 1 : 0;\n  });\n};\n\nexport const summarizeStats = (stats: IndexInputStats[]): IndexStatsSummary => {\n  return stats.reduce((acc, stat) => {\n    addStats(stat, acc);\n    return acc;\n  }, {} as IndexStatsSummary);\n};\n"
  },
  {
    "path": "code/core/src/core-server/utils/update-check.ts",
    "content": "import { cache } from 'storybook/internal/common';\nimport { colors } from 'storybook/internal/node-logger';\nimport type { VersionCheck } from 'storybook/internal/types';\n\nimport picocolors from 'picocolors';\nimport semver from 'semver';\nimport { dedent } from 'ts-dedent';\n\nconst { STORYBOOK_VERSION_BASE = 'https://storybook.js.org', CI } = process.env;\n\nexport const updateCheck = async (version: string): Promise<VersionCheck> => {\n  let result;\n  const time = Date.now();\n  try {\n    const fromCache = await cache.get('lastUpdateCheck', { success: false, time: 0 });\n\n    // if last check was more then 24h ago\n    if (time - 86400000 > fromCache.time && !CI) {\n      const fromFetch: any = await Promise.race([\n        fetch(`${STORYBOOK_VERSION_BASE}/versions.json?current=${version}`),\n        // if fetch is too slow, we won't wait for it\n        new Promise((res, rej) => global.setTimeout(rej, 1500)),\n      ]);\n      const data = await fromFetch.json();\n      result = { success: true, cached: false, data, time };\n      await cache.set('lastUpdateCheck', result);\n    } else {\n      result = { ...fromCache, cached: true };\n    }\n  } catch (error) {\n    result = { success: false, cached: false, error, time };\n  }\n  return result;\n};\n\nexport function createUpdateMessage(updateInfo: VersionCheck, version: string): string {\n  let updateMessage;\n\n  try {\n    const isPrerelease = semver.prerelease(updateInfo.data.latest.version);\n    const upgradeCommand = `npx storybook@${isPrerelease ? 'next' : 'latest'} upgrade`;\n    updateMessage =\n      updateInfo.success && semver.lt(version, updateInfo.data.latest.version)\n        ? dedent`\n          ${colors.orange(\n            `A new version (${picocolors.bold(updateInfo.data.latest.version)}) is available!`\n          )}\n\n          ${picocolors.gray('Upgrade now:')} ${colors.green(upgradeCommand)}\n\n          ${picocolors.gray('Read full changelog:')} ${picocolors.gray(\n            picocolors.underline('https://github.com/storybookjs/storybook/blob/main/CHANGELOG.md')\n          )}\n        `\n        : '';\n  } catch (e) {\n    updateMessage = '';\n  }\n  return updateMessage;\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/validate-token.ts",
    "content": "import { timingSafeEqual } from 'node:crypto';\n\n/**\n * Validates a secret token using constant-time comparison to prevent timing attacks.\n *\n * @returns `true` if tokens match, `false` otherwise\n */\nexport function isValidToken(requestToken: string | null, expectedToken: string): boolean {\n  if (!requestToken || !expectedToken) {\n    return false;\n  }\n\n  const a = new Uint8Array(Buffer.from(requestToken, 'utf8'));\n  const b = new Uint8Array(Buffer.from(expectedToken, 'utf8'));\n  try {\n    return a.length === b.length && timingSafeEqual(a, b);\n  } catch {\n    return false;\n  }\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/versionStatus.ts",
    "content": "import type { VersionCheck } from 'storybook/internal/types';\n\nexport const versionStatus = (versionCheck: VersionCheck) => {\n  if (versionCheck.error) {\n    return 'error';\n  }\n\n  if (versionCheck.cached) {\n    return 'cached';\n  }\n  return 'success';\n};\n"
  },
  {
    "path": "code/core/src/core-server/utils/warnOnIncompatibleAddons.ts",
    "content": "import type { JsPackageManager } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport {\n  getIncompatiblePackagesSummary,\n  getIncompatibleStorybookPackages,\n} from '../../../../lib/cli-storybook/src/doctor/getIncompatibleStorybookPackages.ts';\n\nexport const warnOnIncompatibleAddons = async (\n  currentStorybookVersion: string,\n  packageManager: JsPackageManager\n) => {\n  const incompatiblePackagesList = await getIncompatibleStorybookPackages({\n    skipUpgradeCheck: true,\n    skipErrors: true,\n    currentStorybookVersion,\n    packageManager,\n  });\n\n  const incompatiblePackagesMessage = getIncompatiblePackagesSummary(\n    incompatiblePackagesList,\n    currentStorybookVersion\n  );\n\n  if (incompatiblePackagesMessage) {\n    logger.warn(incompatiblePackagesMessage);\n  }\n};\n"
  },
  {
    "path": "code/core/src/core-server/utils/warnWhenUsingArgTypesRegex.ts",
    "content": "import { readFile } from 'node:fs/promises';\n\nimport { type BabelFile, core } from 'storybook/internal/babel';\nimport { babelParse } from 'storybook/internal/csf-tools';\nimport type { StorybookConfig } from 'storybook/internal/types';\n\nimport picocolors from 'picocolors';\nimport { dedent } from 'ts-dedent';\n\nexport async function warnWhenUsingArgTypesRegex(\n  previewConfigPath: string | undefined,\n  config: StorybookConfig\n) {\n  const previewContent = previewConfigPath\n    ? await readFile(previewConfigPath, { encoding: 'utf8' })\n    : '';\n\n  const hasVisualTestAddon =\n    config?.addons?.some((it) =>\n      typeof it === 'string'\n        ? it === '@chromatic-com/storybook'\n        : it.name === '@chromatic-com/storybook'\n    ) ?? false;\n\n  if (hasVisualTestAddon && previewConfigPath && previewContent.includes('argTypesRegex')) {\n    // @ts-expect-error File is not yet exposed, see https://github.com/babel/babel/issues/11350#issuecomment-644118606\n    const file: BabelFile = new core.File(\n      { filename: previewConfigPath },\n      { code: previewContent, ast: babelParse(previewContent) }\n    );\n\n    file.path.traverse({\n      Identifier: (path) => {\n        if (path.node.name === 'argTypesRegex') {\n          const message = dedent`\n            ${picocolors.bold('Attention')}: We've detected that you're using ${picocolors.cyan(\n              'actions.argTypesRegex'\n            )} together with the visual test addon:\n            \n            ${path.buildCodeFrameError(previewConfigPath).message}\n            \n            We recommend removing the ${picocolors.cyan(\n              'argTypesRegex'\n            )} and assigning explicit action with the ${picocolors.cyan(\n              'fn'\n            )} function from ${picocolors.cyan('storybook/test')} instead:\n            https://storybook.js.org/docs/essentials/actions#via-storybooktest-fn-spies\n            \n            The build used by the addon for snapshot testing doesn't take the regex into account, which can cause hard to debug problems when a snapshot depends on the presence of action props.\n          `;\n          console.warn(message);\n        }\n      },\n    });\n  }\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/watch-story-specifiers.test.ts",
    "content": "import { join } from 'node:path';\n\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { normalizeStoriesEntry } from 'storybook/internal/common';\n\nimport Watchpack from 'watchpack';\n\nimport { watchStorySpecifiers } from './watch-story-specifiers.ts';\n\nvi.mock('watchpack');\n\ndescribe('watchStorySpecifiers', () => {\n  const workingDir = join(__dirname, '__mockdata__');\n  const options = {\n    configDir: join(workingDir, '.storybook'),\n    workingDir,\n  };\n  const abspath = (filename: string) => join(workingDir, filename);\n\n  let close: () => void;\n\n  beforeEach(() => {\n    vi.useFakeTimers();\n  });\n\n  afterEach(() => {\n    close?.();\n    vi.useRealTimers();\n  });\n\n  // Helper to flush the batched events queue\n  const flushEvents = async () => {\n    await vi.runAllTimersAsync();\n  };\n\n  it('watches basic globs', async () => {\n    const specifier = normalizeStoriesEntry('../src/**/*.stories.@(ts|js)', options);\n\n    const onInvalidate = vi.fn();\n    close = watchStorySpecifiers([specifier], { workingDir }, onInvalidate);\n\n    expect(Watchpack).toHaveBeenCalledTimes(1);\n    const watcher = Watchpack.mock.instances[0];\n\n    expect(watcher.on).toHaveBeenCalledTimes(2);\n    const baseOnChange = watcher.on.mock.calls[0][1];\n    const baseOnRemove = watcher.on.mock.calls[1][1];\n    const onChange = (filename: string, ...args: any[]) => baseOnChange(abspath(filename), ...args);\n    const onRemove = (filename: string, ...args: any[]) => baseOnRemove(abspath(filename), ...args);\n\n    // File changed, matching\n    onInvalidate.mockClear();\n    onChange('src/nested/Button.stories.ts', 1234);\n    await flushEvents();\n    expect(onInvalidate).toHaveBeenCalledWith(`./src/nested/Button.stories.ts`, false);\n\n    // File changed, NOT matching\n    onInvalidate.mockClear();\n    onChange('src/nested/Button.ts', 1234);\n    await flushEvents();\n    expect(onInvalidate).not.toHaveBeenCalled();\n\n    // File removed, matching\n    onInvalidate.mockClear();\n    onRemove('src/nested/Button.stories.ts');\n    await flushEvents();\n    expect(onInvalidate).toHaveBeenCalledWith(`./src/nested/Button.stories.ts`, true);\n\n    // File removed, NOT matching\n    onInvalidate.mockClear();\n    onRemove('src/nested/Button.ts');\n    await flushEvents();\n    expect(onInvalidate).not.toHaveBeenCalled();\n\n    // File moved out, matching\n    onInvalidate.mockClear();\n    onChange('src/nested/Button.stories.ts', null);\n    await flushEvents();\n    expect(onInvalidate).toHaveBeenCalledWith(`./src/nested/Button.stories.ts`, true);\n\n    // File renamed, matching\n    onInvalidate.mockClear();\n    onChange('src/nested/Button.stories.ts', null);\n    onChange('src/nested/Button-2.stories.ts', 1234);\n    await flushEvents();\n    expect(onInvalidate).toHaveBeenCalledWith(`./src/nested/Button.stories.ts`, true);\n    expect(onInvalidate).toHaveBeenCalledWith(`./src/nested/Button-2.stories.ts`, false);\n  });\n\n  it('scans directories when they are added', async () => {\n    // This test uses real timers because globby performs actual filesystem I/O\n    // that doesn't work well with fake timers\n    vi.useRealTimers();\n\n    const specifier = normalizeStoriesEntry('../src/**/*.stories.@(ts|js)', options);\n\n    const onInvalidate = vi.fn();\n    close = watchStorySpecifiers([specifier], { workingDir }, onInvalidate);\n\n    expect(Watchpack).toHaveBeenCalledTimes(1);\n    const watcher = Watchpack.mock.instances[0];\n\n    expect(watcher.on).toHaveBeenCalledTimes(2);\n    const baseOnChange = watcher.on.mock.calls[0][1];\n    const onChange = (filename: string, ...args: any[]) => baseOnChange(abspath(filename), ...args);\n\n    onInvalidate.mockClear();\n    onChange('src/nested', 1234);\n    // Wait for the batching timeout and globby to complete\n    await vi.waitFor(() => {\n      expect(onInvalidate).toHaveBeenCalledWith(`./src/nested/Button.stories.ts`, false);\n    });\n  });\n\n  it('watches single file globs', async () => {\n    const specifier = normalizeStoriesEntry('../src/nested/Button.mdx', options);\n\n    const onInvalidate = vi.fn();\n    close = watchStorySpecifiers([specifier], { workingDir }, onInvalidate);\n\n    expect(Watchpack).toHaveBeenCalledTimes(1);\n    const watcher = Watchpack.mock.instances[0];\n\n    expect(watcher.on).toHaveBeenCalledTimes(2);\n    const baseOnChange = watcher.on.mock.calls[0][1];\n    const baseOnRemove = watcher.on.mock.calls[1][1];\n    const onChange = (filename: string, ...args: any[]) => baseOnChange(abspath(filename), ...args);\n    const onRemove = (filename: string, ...args: any[]) => baseOnRemove(abspath(filename), ...args);\n\n    // File changed, matching\n    onInvalidate.mockClear();\n    onChange('src/nested/Button.mdx', 1234);\n    await flushEvents();\n    expect(onInvalidate).toHaveBeenCalledWith(`./src/nested/Button.mdx`, false);\n\n    // File changed, NOT matching\n    onInvalidate.mockClear();\n    onChange('src/nested/Button.tsx', 1234);\n    await flushEvents();\n    expect(onInvalidate).not.toHaveBeenCalled();\n\n    // File removed, matching\n    onInvalidate.mockClear();\n    onRemove('src/nested/Button.mdx');\n    await flushEvents();\n    expect(onInvalidate).toHaveBeenCalledWith(`./src/nested/Button.mdx`, true);\n\n    // File removed, NOT matching\n    onInvalidate.mockClear();\n    onRemove('src/nested/Button.tsx');\n    await flushEvents();\n    expect(onInvalidate).not.toHaveBeenCalled();\n\n    // File moved out, matching\n    onInvalidate.mockClear();\n    onChange('src/nested/Button.mdx', null);\n    await flushEvents();\n    expect(onInvalidate).toHaveBeenCalledWith(`./src/nested/Button.mdx`, true);\n  });\n\n  it('multiplexes between two specifiers on the same directory', async () => {\n    const globSpecifier = normalizeStoriesEntry('../src/**/*.stories.@(ts|js)', options);\n    const fileSpecifier = normalizeStoriesEntry('../src/nested/Button.mdx', options);\n\n    const onInvalidate = vi.fn();\n    close = watchStorySpecifiers([globSpecifier, fileSpecifier], { workingDir }, onInvalidate);\n\n    expect(Watchpack).toHaveBeenCalledTimes(1);\n    const watcher = Watchpack.mock.instances[0];\n\n    expect(watcher.on).toHaveBeenCalledTimes(2);\n    const baseOnChange = watcher.on.mock.calls[0][1];\n    const onChange = (filename: string, ...args: any[]) => baseOnChange(abspath(filename), ...args);\n\n    onInvalidate.mockClear();\n    onChange('src/nested/Button.stories.ts', 1234);\n    await flushEvents();\n    expect(onInvalidate).toHaveBeenCalledWith(`./src/nested/Button.stories.ts`, false);\n\n    onInvalidate.mockClear();\n    onChange('src/nested/Button.mdx', 1234);\n    await flushEvents();\n    expect(onInvalidate).toHaveBeenCalledWith(`./src/nested/Button.mdx`, false);\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/utils/watch-story-specifiers.ts",
    "content": "import { type Dirent, lstatSync, readdirSync } from 'node:fs';\nimport { basename, join, relative, resolve } from 'node:path';\n\nimport { commonGlobOptions } from 'storybook/internal/common';\nimport type { NormalizedStoriesSpecifier, Path } from 'storybook/internal/types';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\nimport Watchpack from 'watchpack';\n\nconst isDirectory = (directory: Path) => {\n  try {\n    return lstatSync(directory).isDirectory();\n  } catch (err) {\n    return false;\n  }\n};\n\n// Takes an array of absolute paths to directories and synchronously returns\n// absolute paths to all existing files and directories nested within those\n// directories (including the passed parent directories).\nfunction getNestedFilesAndDirectories(directories: Path[]) {\n  const traversedDirectories = new Set<Path>();\n  const files = new Set<Path>();\n  const traverse = (directory: Path) => {\n    if (traversedDirectories.has(directory)) {\n      return;\n    }\n    readdirSync(directory, { withFileTypes: true }).forEach((ent: Dirent) => {\n      if (ent.isDirectory()) {\n        traverse(join(directory, ent.name));\n      } else if (ent.isFile()) {\n        files.add(join(directory, ent.name));\n      }\n    });\n    traversedDirectories.add(directory);\n  };\n  directories.filter(isDirectory).forEach(traverse);\n  return { files: Array.from(files), directories: Array.from(traversedDirectories) };\n}\n\nexport function watchStorySpecifiers(\n  specifiers: NormalizedStoriesSpecifier[],\n  options: { workingDir: Path },\n  onInvalidate: (path: Path, removed: boolean) => void\n) {\n  // Watch all nested files and directories up front to avoid this issue:\n  // https://github.com/webpack/watchpack/issues/222\n  const { files, directories } = getNestedFilesAndDirectories(\n    specifiers.map((ns) => resolve(options.workingDir, ns.directory))\n  );\n\n  // See https://www.npmjs.com/package/watchpack for full options.\n  // If you want less traffic, consider using aggregation with some interval\n  const wp = new Watchpack({\n    // poll: true, // Slow!!! Enable only in special cases\n    followSymlinks: false,\n    ignored: ['**/.git', '**/node_modules'],\n  });\n  wp.watch({ files, directories });\n\n  const toImportPath = (absolutePath: Path) => {\n    const relativePath = relative(options.workingDir, absolutePath);\n    return slash(relativePath.startsWith('.') ? relativePath : `./${relativePath}`);\n  };\n\n  async function onChangeOrRemove(absolutePath: Path, removed: boolean) {\n    // Watchpack should return absolute paths, given we passed in absolute paths\n    // to watch. Convert to an import path so we can run against the specifiers.\n    const importPath = toImportPath(absolutePath);\n\n    const matchingSpecifier = specifiers.find((ns) => ns.importPathMatcher.exec(importPath));\n    if (matchingSpecifier) {\n      onInvalidate(importPath, removed);\n      return;\n    }\n\n    // When a directory is removed, watchpack will fire a removed event for each file also\n    // (so we don't need to do anything special).\n    // However, when a directory is added, it does not fire events for any files *within* the directory,\n    // so we need to scan within that directory for new files. It is tricky to use a glob for this,\n    // so we'll do something a bit more \"dumb\" for now\n    if (!removed && isDirectory(absolutePath)) {\n      await Promise.all(\n        specifiers\n          // We only receive events for files (incl. directories) that are *within* a specifier,\n          // so will match one (or more) specifiers with this simple `startsWith`\n          .filter((specifier) => importPath.startsWith(specifier.directory))\n          .map(async (specifier) => {\n            // If `./path/to/dir` was added, check all files matching `./path/to/dir/**/*.stories.*`\n            // (where the last bit depends on `files`).\n            const dirGlob = join(\n              absolutePath,\n              '**',\n              // files can be e.g. '**/foo/*/*.js' so we just want the last bit,\n              // because the directory could already be within the files part (e.g. './x/foo/bar')\n              basename(specifier.files)\n            );\n\n            // Dynamically import globby because it is a pure ESM module\n            // eslint-disable-next-line depend/ban-dependencies\n            const { globby } = await import('globby');\n\n            // glob only supports forward slashes\n            const addedFiles = await globby(slash(dirGlob), commonGlobOptions(dirGlob));\n\n            addedFiles.forEach((filePath: Path) => {\n              const fileImportPath = toImportPath(filePath);\n\n              if (specifier.importPathMatcher.exec(fileImportPath)) {\n                onInvalidate(fileImportPath, removed);\n              }\n            });\n          })\n      );\n    }\n  }\n\n  // Batch rapid file events to avoid redundant processing.\n  // Watchpack fires multiple events for the same file in rapid succession.\n  // We collect events for 100ms, then process unique paths only.\n  const pendingEvents = new Map<Path, { removed: boolean }>();\n  let batchTimeout: ReturnType<typeof setTimeout> | undefined;\n\n  function queueEvent(absolutePath: Path, removed: boolean) {\n    // Store/overwrite the event for this path (last event type wins)\n    pendingEvents.set(absolutePath, { removed });\n\n    // Reset the timer on each new event to batch them together\n    if (batchTimeout) {\n      clearTimeout(batchTimeout);\n    }\n    batchTimeout = setTimeout(async () => {\n      batchTimeout = undefined;\n      const events = new Map(pendingEvents);\n      pendingEvents.clear();\n\n      await Promise.all(\n        Array.from(events.entries()).map(([path, { removed }]) => onChangeOrRemove(path, removed))\n      );\n    }, 100);\n  }\n\n  wp.on('change', (filePath: Path, mtime: Date, explanation: string) => {\n    // When a file is renamed (including being moved out of the watched dir)\n    // we see first an event with explanation=rename and no mtime for the old name.\n    // then an event with explanation=rename with an mtime for the new name.\n    // In theory we could try and track both events together and move the exports\n    // but that seems dangerous (what if the contents changed?) and frankly not worth it\n    // (at this stage at least)\n    const removed = !mtime;\n    queueEvent(filePath, removed);\n  });\n  wp.on('remove', (filePath: Path) => {\n    queueEvent(filePath, true);\n  });\n\n  return () => wp.close();\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/watchConfig.ts",
    "content": "import type { Path } from 'storybook/internal/types';\n\nimport Watchpack from 'watchpack';\n\n// copied from './watch-story-specifiers.ts'\n/** Watch the `.storybook` dir for changes */\nexport function watchConfig(\n  configDir: Path,\n  onInvalidate: (path: Path, removed: boolean) => Promise<void>\n) {\n  const wp = new Watchpack({\n    followSymlinks: false,\n    ignored: ['**/.git', '**/node_modules'],\n  });\n\n  wp.watch({\n    directories: [configDir],\n  });\n  wp.on('change', async (filePath: Path, mtime: Date, explanation: string) => {\n    const removed = !mtime;\n    await onInvalidate(filePath, removed);\n  });\n  wp.on('remove', async (filePath: Path, explanation: string) => {\n    await onInvalidate(filePath, true);\n  });\n\n  return () => wp.close();\n}\n"
  },
  {
    "path": "code/core/src/core-server/utils/whats-new.ts",
    "content": "import { writeFile } from 'node:fs/promises';\n\nimport type { Channel } from 'storybook/internal/channels';\nimport { findConfigFile, loadMainConfig } from 'storybook/internal/common';\nimport type { WhatsNewCache, WhatsNewData } from 'storybook/internal/core-events';\nimport {\n  REQUEST_WHATS_NEW_DATA,\n  RESULT_WHATS_NEW_DATA,\n  SET_WHATS_NEW_CACHE,\n  TELEMETRY_ERROR,\n  TOGGLE_WHATS_NEW_NOTIFICATIONS,\n} from 'storybook/internal/core-events';\nimport { printConfig, readConfig } from 'storybook/internal/csf-tools';\nimport { logger } from 'storybook/internal/node-logger';\nimport { telemetry } from 'storybook/internal/telemetry';\nimport type { CoreConfig, Options } from 'storybook/internal/types';\n\nimport invariant from 'tiny-invariant';\n\nimport { sendTelemetryError } from '../withTelemetry.ts';\n\nexport type OptionsWithRequiredCache = Exclude<Options, 'cache'> & Required<Pick<Options, 'cache'>>;\n\n// Grabbed from the implementation: https://github.com/storybookjs/dx-functions/blob/main/netlify/functions/whats-new.ts\nexport type WhatsNewResponse = {\n  title: string;\n  url: string;\n  blogUrl?: string;\n  publishedAt: string;\n  excerpt: string;\n};\n\nconst WHATS_NEW_CACHE = 'whats-new-cache';\nconst WHATS_NEW_URL = 'https://storybook.js.org/whats-new/v1';\n\nexport function initializeWhatsNew(\n  channel: Channel,\n  options: OptionsWithRequiredCache,\n  coreOptions: CoreConfig\n) {\n  channel.on(SET_WHATS_NEW_CACHE, async (data: WhatsNewCache) => {\n    const cache: WhatsNewCache = await options.cache.get(WHATS_NEW_CACHE).catch((e) => {\n      logger.verbose(e);\n      return {};\n    });\n    await options.cache.set(WHATS_NEW_CACHE, { ...cache, ...data });\n  });\n\n  channel.on(REQUEST_WHATS_NEW_DATA, async () => {\n    try {\n      const post = (await fetch(WHATS_NEW_URL).then(async (response) => {\n        if (response.ok) {\n          return response.json();\n        }\n\n        throw response;\n      })) as WhatsNewResponse;\n\n      const main = await loadMainConfig({ configDir: options.configDir });\n      const disableWhatsNewNotifications =\n        (main.core as CoreConfig)?.disableWhatsNewNotifications === true;\n\n      const cache: WhatsNewCache = (await options.cache.get(WHATS_NEW_CACHE)) ?? {};\n      const data = {\n        ...post,\n        status: 'SUCCESS',\n        postIsRead: post.url === cache.lastReadPost,\n        showNotification: post.url !== cache.lastDismissedPost && post.url !== cache.lastReadPost,\n        disableWhatsNewNotifications,\n      } satisfies WhatsNewData;\n      channel.emit(RESULT_WHATS_NEW_DATA, { data });\n    } catch (e) {\n      logger.verbose(e instanceof Error ? e.message : String(e));\n      channel.emit(RESULT_WHATS_NEW_DATA, {\n        data: { status: 'ERROR' } satisfies WhatsNewData,\n      });\n    }\n  });\n\n  channel.on(\n    TOGGLE_WHATS_NEW_NOTIFICATIONS,\n    async ({ disableWhatsNewNotifications }: { disableWhatsNewNotifications: boolean }) => {\n      const isTelemetryEnabled = coreOptions.disableTelemetry !== true;\n      try {\n        const mainPath = findConfigFile('main', options.configDir);\n        invariant(mainPath, `unable to find Storybook main file in ${options.configDir}`);\n        const main = await readConfig(mainPath);\n        if (!main._exportsObject) {\n          // eslint-disable-next-line local-rules/no-uncategorized-errors\n          throw new Error(\n            `Unable to parse Storybook main file while trying to read 'core' property`\n          );\n        }\n        main.setFieldValue(['core', 'disableWhatsNewNotifications'], disableWhatsNewNotifications);\n        await writeFile(mainPath, printConfig(main).code);\n        if (isTelemetryEnabled) {\n          await telemetry('core-config', { disableWhatsNewNotifications });\n        }\n      } catch (error) {\n        invariant(error instanceof Error);\n        if (isTelemetryEnabled) {\n          await sendTelemetryError(error, 'core-config', {\n            cliOptions: options,\n            presetOptions: {\n              ...options,\n              corePresets: [],\n              overridePresets: [],\n            },\n            skipPrompt: true,\n          });\n        }\n      }\n    }\n  );\n\n  channel.on(TELEMETRY_ERROR, async (error) => {\n    const isTelemetryEnabled = coreOptions.disableTelemetry !== true;\n\n    if (isTelemetryEnabled) {\n      await sendTelemetryError(error, 'browser', {\n        cliOptions: options,\n        presetOptions: {\n          ...options,\n          corePresets: [],\n          overridePresets: [],\n        },\n        skipPrompt: true,\n      });\n    }\n  });\n}\n"
  },
  {
    "path": "code/core/src/core-server/withTelemetry.test.ts",
    "content": "import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { cache, isCI, loadAllPresets } from 'storybook/internal/common';\nimport { prompt } from 'storybook/internal/node-logger';\nimport { ErrorCollector, oneWayHash, telemetry } from 'storybook/internal/telemetry';\n\nimport { getErrorLevel, sendTelemetryError, withTelemetry } from './withTelemetry.ts';\n\nvi.mock('storybook/internal/common', { spy: true });\nvi.mock('storybook/internal/telemetry', { spy: true });\nvi.mock('storybook/internal/node-logger', { spy: true });\n\nconst cliOptions = {};\nconst originalStdoutIsTTY = process.stdout.isTTY;\n\nconst setStdoutIsTTY = (value: boolean | undefined) => {\n  Object.defineProperty(process.stdout, 'isTTY', {\n    value,\n    configurable: true,\n  });\n};\n\nafterEach(() => {\n  setStdoutIsTTY(originalStdoutIsTTY);\n});\n\ndescribe('withTelemetry', () => {\n  beforeEach(() => {\n    vi.resetAllMocks();\n    vi.mocked(ErrorCollector.getErrors).mockReturnValue([]);\n    vi.mocked(telemetry).mockResolvedValue(undefined);\n  });\n  it('works in happy path', async () => {\n    const run = vi.fn();\n\n    await withTelemetry('dev', { cliOptions }, run);\n\n    expect(telemetry).toHaveBeenCalledTimes(1);\n    expect(telemetry).toHaveBeenCalledWith('boot', { eventType: 'dev' }, { stripMetadata: true });\n  });\n\n  it('does not send boot when cli option is passed', async () => {\n    const run = vi.fn();\n\n    await withTelemetry('dev', { cliOptions: { disableTelemetry: true } }, run);\n\n    expect(telemetry).toHaveBeenCalledTimes(0);\n  });\n\n  describe('when command fails', () => {\n    const error = new Error('An Error!');\n    const run = vi.fn(async () => {\n      throw error;\n    });\n\n    it('sends boot message', async () => {\n      await expect(async () =>\n        withTelemetry('dev', { cliOptions, printError: vi.fn() }, run)\n      ).rejects.toThrow(error);\n\n      expect(telemetry).toHaveBeenCalledWith('boot', { eventType: 'dev' }, { stripMetadata: true });\n    });\n\n    it('does not send boot when cli option is passed', async () => {\n      await expect(async () =>\n        withTelemetry('dev', { cliOptions: { disableTelemetry: true }, printError: vi.fn() }, run)\n      ).rejects.toThrow(error);\n\n      expect(telemetry).toHaveBeenCalledTimes(0);\n    });\n\n    it('sends error message when no options are passed', async () => {\n      await expect(async () =>\n        withTelemetry('dev', { cliOptions, printError: vi.fn() }, run)\n      ).rejects.toThrow(error);\n\n      expect(telemetry).toHaveBeenCalledTimes(2);\n      expect(telemetry).toHaveBeenCalledWith(\n        'error',\n        expect.objectContaining({\n          eventType: 'dev',\n          error: undefined, // error is only included when errorLevel === 'full'\n          isErrorInstance: true,\n        }),\n        expect.objectContaining({})\n      );\n    });\n\n    it('prompts for crash reports when init fails without preset options', async () => {\n      vi.mocked(isCI).mockReturnValue(false);\n      vi.mocked(cache.get).mockResolvedValueOnce(undefined);\n      vi.mocked(prompt.confirm).mockResolvedValueOnce(true);\n      setStdoutIsTTY(true);\n\n      await expect(async () =>\n        withTelemetry('init', { cliOptions, printError: vi.fn() }, run)\n      ).rejects.toThrow(error);\n\n      expect(prompt.confirm).toHaveBeenCalledTimes(1);\n      expect(cache.set).toHaveBeenCalledWith('enableCrashReports', true);\n      expect(telemetry).toHaveBeenCalledWith(\n        'error',\n        expect.objectContaining({\n          eventType: 'init',\n          error: expect.objectContaining({ message: 'An Error!', name: 'Error' }),\n          isErrorInstance: true,\n        }),\n        expect.objectContaining({ enableCrashReports: true })\n      );\n    });\n\n    it('does not send full error details when init prompt is rejected', async () => {\n      vi.mocked(isCI).mockReturnValue(false);\n      vi.mocked(cache.get).mockResolvedValueOnce(undefined);\n      vi.mocked(prompt.confirm).mockResolvedValueOnce(false);\n      setStdoutIsTTY(true);\n\n      await expect(async () =>\n        withTelemetry('init', { cliOptions, printError: vi.fn() }, run)\n      ).rejects.toThrow(error);\n\n      expect(prompt.confirm).toHaveBeenCalledTimes(1);\n      expect(cache.set).toHaveBeenCalledWith('enableCrashReports', false);\n      expect(telemetry).toHaveBeenCalledWith(\n        'error',\n        expect.objectContaining({\n          eventType: 'init',\n          error: undefined,\n          isErrorInstance: true,\n        }),\n        expect.objectContaining({ enableCrashReports: false })\n      );\n    });\n\n    it('does not send error message when cli opt out is passed', async () => {\n      await expect(async () =>\n        withTelemetry('dev', { cliOptions: { disableTelemetry: true }, printError: vi.fn() }, run)\n      ).rejects.toThrow(error);\n\n      expect(telemetry).toHaveBeenCalledTimes(0);\n      expect(telemetry).not.toHaveBeenCalledWith(\n        'error',\n        expect.objectContaining({}),\n        expect.objectContaining({})\n      );\n    });\n\n    it('does not send full error message when crash reports are disabled', async () => {\n      vi.mocked(loadAllPresets).mockResolvedValueOnce({\n        apply: async () => ({ enableCrashReports: false }) as any,\n      });\n      await expect(async () =>\n        withTelemetry(\n          'dev',\n          { cliOptions: {} as any, presetOptions: {} as any, printError: vi.fn() },\n          run\n        )\n      ).rejects.toThrow(error);\n\n      expect(telemetry).toHaveBeenCalledTimes(2);\n      expect(telemetry).toHaveBeenCalledWith(\n        'error',\n        expect.objectContaining({ eventType: 'dev' }),\n        expect.objectContaining({})\n      );\n    });\n\n    it('does send error message when crash reports are enabled', async () => {\n      vi.mocked(loadAllPresets).mockResolvedValueOnce({\n        apply: async () => ({ enableCrashReports: true }) as any,\n      });\n\n      await expect(async () =>\n        withTelemetry(\n          'dev',\n          { cliOptions: {} as any, presetOptions: {} as any, printError: vi.fn() },\n          run\n        )\n      ).rejects.toThrow(error);\n\n      expect(telemetry).toHaveBeenCalledTimes(2);\n      expect(telemetry).toHaveBeenCalledWith(\n        'error',\n        expect.objectContaining({\n          eventType: 'dev',\n          error: expect.objectContaining({ message: 'An Error!', name: 'Error' }),\n          isErrorInstance: true,\n        }),\n        expect.objectContaining({ enableCrashReports: true })\n      );\n    });\n\n    it('does not send any error message when telemetry is disabled', async () => {\n      vi.mocked(loadAllPresets).mockResolvedValueOnce({\n        apply: async () => ({ disableTelemetry: true }) as any,\n      });\n\n      await expect(async () =>\n        withTelemetry(\n          'dev',\n          { cliOptions: {} as any, presetOptions: {} as any, printError: vi.fn() },\n          run\n        )\n      ).rejects.toThrow(error);\n\n      expect(telemetry).toHaveBeenCalledTimes(1);\n      expect(telemetry).not.toHaveBeenCalledWith(\n        'error',\n        expect.objectContaining({}),\n        expect.objectContaining({})\n      );\n    });\n\n    it('does send error messages when telemetry is disabled, but crash reports are enabled', async () => {\n      vi.mocked(loadAllPresets).mockResolvedValueOnce({\n        apply: async () => ({ disableTelemetry: true, enableCrashReports: true }) as any,\n      });\n\n      await expect(async () =>\n        withTelemetry(\n          'dev',\n          { cliOptions: {} as any, presetOptions: {} as any, printError: vi.fn() },\n          run\n        )\n      ).rejects.toThrow(error);\n\n      expect(telemetry).toHaveBeenCalledTimes(2);\n      expect(telemetry).toHaveBeenCalledWith(\n        'error',\n        expect.objectContaining({\n          eventType: 'dev',\n          error: expect.objectContaining({ message: 'An Error!', name: 'Error' }),\n          isErrorInstance: true,\n        }),\n        expect.objectContaining({ enableCrashReports: true })\n      );\n    });\n\n    it('does not send  full  error messages when disabled crash reports are cached', async () => {\n      vi.mocked(loadAllPresets).mockResolvedValueOnce({\n        apply: async () => ({}) as any,\n      });\n      vi.mocked(cache.get).mockResolvedValueOnce(false);\n\n      await expect(async () =>\n        withTelemetry(\n          'dev',\n          { cliOptions: {} as any, presetOptions: {} as any, printError: vi.fn() },\n          run\n        )\n      ).rejects.toThrow(error);\n\n      expect(telemetry).toHaveBeenCalledTimes(2);\n      expect(telemetry).toHaveBeenCalledWith(\n        'error',\n        expect.objectContaining({ eventType: 'dev' }),\n        expect.objectContaining({})\n      );\n    });\n\n    it('does send error messages when enabled crash reports are cached', async () => {\n      vi.mocked(loadAllPresets).mockResolvedValueOnce({\n        apply: async () => ({}) as any,\n      });\n      vi.mocked(cache.get).mockResolvedValueOnce(true);\n\n      await expect(async () =>\n        withTelemetry(\n          'dev',\n          { cliOptions: {} as any, presetOptions: {} as any, printError: vi.fn() },\n          run\n        )\n      ).rejects.toThrow(error);\n\n      expect(telemetry).toHaveBeenCalledTimes(2);\n      expect(telemetry).toHaveBeenCalledWith(\n        'error',\n        expect.objectContaining({\n          eventType: 'dev',\n          error: expect.objectContaining({ message: 'An Error!', name: 'Error' }),\n          isErrorInstance: true,\n        }),\n        expect.objectContaining({ enableCrashReports: true })\n      );\n    });\n\n    it('does not send full error messages when disabled crash reports are prompted', async () => {\n      vi.mocked(loadAllPresets).mockResolvedValueOnce({\n        apply: async () => ({}) as any,\n      });\n      vi.mocked(cache.get).mockResolvedValueOnce(undefined);\n      vi.mocked(prompt.confirm).mockResolvedValueOnce(false);\n\n      await expect(async () =>\n        withTelemetry(\n          'dev',\n          { cliOptions: {} as any, presetOptions: {} as any, printError: vi.fn() },\n          run\n        )\n      ).rejects.toThrow(error);\n\n      expect(telemetry).toHaveBeenCalledTimes(2);\n      expect(telemetry).toHaveBeenCalledWith(\n        'error',\n        expect.objectContaining({ eventType: 'dev' }),\n        expect.objectContaining({})\n      );\n    });\n\n    it('does send error messages when enabled crash reports are prompted', async () => {\n      vi.mocked(loadAllPresets).mockResolvedValueOnce({\n        apply: async () => ({}) as any,\n      });\n      vi.mocked(cache.get).mockResolvedValueOnce(undefined);\n      vi.mocked(prompt.confirm).mockResolvedValueOnce(true);\n\n      await expect(async () =>\n        withTelemetry(\n          'dev',\n          { cliOptions: {} as any, presetOptions: {} as any, printError: vi.fn() },\n          run\n        )\n      ).rejects.toThrow(error);\n\n      expect(telemetry).toHaveBeenCalledTimes(2);\n      expect(telemetry).toHaveBeenCalledWith(\n        'error',\n        expect.objectContaining({\n          eventType: 'dev',\n          error: expect.objectContaining({ message: 'An Error!', name: 'Error' }),\n          isErrorInstance: true,\n        }),\n        expect.objectContaining({ enableCrashReports: true })\n      );\n    });\n\n    // if main.js has errors, we have no way to tell if they've disabled error reporting,\n    // so we assume they have.\n    it('does not send full error messages when presets fail to evaluate', async () => {\n      vi.mocked(loadAllPresets).mockRejectedValueOnce(error);\n\n      await expect(async () =>\n        withTelemetry(\n          'dev',\n          { cliOptions: {} as any, presetOptions: {} as any, printError: vi.fn() },\n          run\n        )\n      ).rejects.toThrow(error);\n\n      expect(telemetry).toHaveBeenCalledTimes(2);\n      expect(telemetry).toHaveBeenCalledWith(\n        'error',\n        expect.objectContaining({ eventType: 'dev' }),\n        expect.objectContaining({})\n      );\n    });\n  });\n});\n\ndescribe('sendTelemetryError', () => {\n  beforeEach(() => {\n    vi.resetAllMocks();\n    vi.mocked(ErrorCollector.getErrors).mockReturnValue([]);\n  });\n\n  it('handles error instances and sends telemetry', async () => {\n    const options: any = {\n      cliOptions: {},\n      skipPrompt: false,\n    };\n    const mockError = new Error('Test error');\n    const eventType: any = 'testEventType';\n\n    vi.mocked(oneWayHash).mockReturnValueOnce('some-hash');\n\n    await sendTelemetryError(mockError, eventType, options);\n\n    expect(telemetry).toHaveBeenCalledWith(\n      'error',\n      expect.objectContaining({\n        error: undefined, // error is only included when errorLevel === 'full'\n        eventType,\n        isErrorInstance: true,\n        errorHash: 'some-hash',\n        name: 'Error',\n      }),\n      expect.objectContaining({\n        enableCrashReports: false,\n        immediate: true,\n      })\n    );\n  });\n\n  it('handles non-error instances and sends telemetry with no-message hash', async () => {\n    const options: any = {\n      cliOptions: {},\n      skipPrompt: false,\n    };\n    const mockError = { error: new Error('Test error') };\n    const eventType: any = 'testEventType';\n\n    await sendTelemetryError(mockError, eventType, options);\n\n    expect(telemetry).toHaveBeenCalledWith(\n      'error',\n      expect.objectContaining({\n        error: undefined, // error is only included when errorLevel === 'full'\n        eventType,\n        isErrorInstance: false,\n        errorHash: 'NO_MESSAGE',\n      }),\n      expect.objectContaining({\n        enableCrashReports: false,\n        immediate: true,\n      })\n    );\n  });\n\n  it('handles error with empty message and sends telemetry with empty-message hash', async () => {\n    const options: any = {\n      cliOptions: {},\n      skipPrompt: false,\n    };\n    const mockError = new Error();\n    const eventType: any = 'testEventType';\n\n    await sendTelemetryError(mockError, eventType, options);\n\n    expect(telemetry).toHaveBeenCalledWith(\n      'error',\n      expect.objectContaining({\n        error: undefined, // error is only included when errorLevel === 'full'\n        eventType,\n        isErrorInstance: true,\n        errorHash: 'EMPTY_MESSAGE',\n        name: 'Error',\n      }),\n      expect.objectContaining({\n        enableCrashReports: false,\n        immediate: true,\n      })\n    );\n  });\n\n  it('does not prompt for non-blocking init errors without cached consent', async () => {\n    const options: any = {\n      cliOptions: {},\n      skipPrompt: false,\n    };\n    const mockError = new Error('Init non-blocking error');\n\n    vi.mocked(isCI).mockReturnValue(false);\n    vi.mocked(cache.get).mockResolvedValueOnce(undefined);\n    vi.mocked(prompt.confirm).mockResolvedValueOnce(true);\n    setStdoutIsTTY(true);\n\n    await sendTelemetryError(mockError, 'init', options, false);\n\n    expect(prompt.confirm).not.toHaveBeenCalled();\n    expect(vi.mocked(cache.set).mock.calls).not.toContainEqual([\n      'enableCrashReports',\n      expect.anything(),\n    ]);\n    expect(telemetry).toHaveBeenCalledWith(\n      'error',\n      expect.objectContaining({\n        eventType: 'init',\n        blocking: false,\n        error: undefined,\n        isErrorInstance: true,\n      }),\n      expect.objectContaining({\n        enableCrashReports: false,\n        immediate: true,\n      })\n    );\n  });\n\n  it('uses cached crash report consent for non-blocking init errors', async () => {\n    const options: any = {\n      cliOptions: {},\n      skipPrompt: false,\n    };\n    const mockError = new Error('Init non-blocking error');\n\n    vi.mocked(cache.get).mockResolvedValueOnce(true);\n\n    await sendTelemetryError(mockError, 'init', options, false);\n\n    expect(prompt.confirm).not.toHaveBeenCalled();\n    expect(telemetry).toHaveBeenCalledWith(\n      'error',\n      expect.objectContaining({\n        eventType: 'init',\n        blocking: false,\n        error: expect.objectContaining({ message: 'Init non-blocking error', name: 'Error' }),\n        isErrorInstance: true,\n      }),\n      expect.objectContaining({\n        enableCrashReports: true,\n        immediate: true,\n      })\n    );\n  });\n});\n\ndescribe('getErrorLevel', () => {\n  beforeEach(() => {\n    vi.resetAllMocks();\n    vi.mocked(ErrorCollector.getErrors).mockReturnValue([]);\n  });\n\n  it('returns \"none\" when cliOptions.disableTelemetry is true', async () => {\n    const options: any = {\n      cliOptions: {\n        disableTelemetry: true,\n      },\n      presetOptions: undefined,\n      skipPrompt: false,\n    };\n\n    const errorLevel = await getErrorLevel(options);\n\n    expect(errorLevel).toBe('none');\n  });\n\n  it('returns \"error\" when presetOptions is not provided', async () => {\n    const options: any = {\n      cliOptions: {\n        disableTelemetry: false,\n      },\n      presetOptions: undefined,\n      skipPrompt: false,\n      eventType: 'dev',\n    };\n\n    const errorLevel = await getErrorLevel(options);\n\n    expect(errorLevel).toBe('error');\n  });\n\n  it('returns \"full\" for init when presetOptions are not provided and prompt is accepted', async () => {\n    const options: any = {\n      cliOptions: {\n        disableTelemetry: false,\n      },\n      presetOptions: undefined,\n      skipPrompt: false,\n      eventType: 'init',\n    };\n\n    vi.mocked(isCI).mockReturnValue(false);\n    vi.mocked(cache.get).mockResolvedValueOnce(undefined);\n    vi.mocked(prompt.confirm).mockResolvedValueOnce(true);\n    setStdoutIsTTY(true);\n\n    const errorLevel = await getErrorLevel(options);\n\n    expect(errorLevel).toBe('full');\n    expect(loadAllPresets).not.toHaveBeenCalled();\n    expect(prompt.confirm).toHaveBeenCalledTimes(1);\n    expect(cache.set).toHaveBeenCalledWith('enableCrashReports', true);\n  });\n\n  it('returns \"error\" for init when presetOptions are not provided and prompt is rejected', async () => {\n    const options: any = {\n      cliOptions: {\n        disableTelemetry: false,\n      },\n      presetOptions: undefined,\n      skipPrompt: false,\n      eventType: 'init',\n    };\n\n    vi.mocked(isCI).mockReturnValue(false);\n    vi.mocked(cache.get).mockResolvedValueOnce(undefined);\n    vi.mocked(prompt.confirm).mockResolvedValueOnce(false);\n    setStdoutIsTTY(true);\n\n    const errorLevel = await getErrorLevel(options);\n\n    expect(errorLevel).toBe('error');\n    expect(loadAllPresets).not.toHaveBeenCalled();\n    expect(prompt.confirm).toHaveBeenCalledTimes(1);\n    expect(cache.set).toHaveBeenCalledWith('enableCrashReports', false);\n  });\n\n  it('returns \"full\" when core.enableCrashReports is true', async () => {\n    const options: any = {\n      cliOptions: {\n        disableTelemetry: false,\n      },\n      presetOptions: {},\n      skipPrompt: false,\n    };\n\n    vi.mocked(loadAllPresets).mockResolvedValueOnce({\n      apply: async () => ({ enableCrashReports: true }) as any,\n    });\n    vi.mocked(cache.get).mockResolvedValueOnce(false);\n\n    const errorLevel = await getErrorLevel(options);\n\n    expect(errorLevel).toBe('full');\n  });\n\n  it('returns \"error\" when core.enableCrashReports is false', async () => {\n    const options: any = {\n      cliOptions: {\n        disableTelemetry: false,\n      },\n      presetOptions: {},\n      skipPrompt: false,\n    };\n\n    vi.mocked(loadAllPresets).mockResolvedValueOnce({\n      apply: async () => ({ enableCrashReports: false }) as any,\n    });\n    vi.mocked(cache.get).mockResolvedValueOnce(false);\n\n    const errorLevel = await getErrorLevel(options);\n\n    expect(errorLevel).toBe('error');\n  });\n\n  it('returns \"none\" when core.disableTelemetry is true', async () => {\n    const options: any = {\n      cliOptions: {\n        disableTelemetry: false,\n      },\n      presetOptions: {},\n      skipPrompt: false,\n    };\n\n    vi.mocked(loadAllPresets).mockResolvedValueOnce({\n      apply: async () => ({ disableTelemetry: true }) as any,\n    });\n    vi.mocked(cache.get).mockResolvedValueOnce(false);\n\n    const errorLevel = await getErrorLevel(options);\n\n    expect(errorLevel).toBe('none');\n  });\n\n  it('returns \"full\" if cache contains crashReports true', async () => {\n    const options: any = {\n      cliOptions: {\n        disableTelemetry: false,\n      },\n      presetOptions: {},\n      skipPrompt: false,\n    };\n\n    vi.mocked(cache.get).mockResolvedValueOnce(true);\n    vi.mocked(loadAllPresets).mockResolvedValueOnce({\n      apply: async () => ({}) as any,\n    });\n\n    const errorLevel = await getErrorLevel(options);\n\n    expect(errorLevel).toBe('full');\n  });\n\n  it('returns \"error\" when skipPrompt is true', async () => {\n    const options: any = {\n      cliOptions: {\n        disableTelemetry: false,\n      },\n      presetOptions: {},\n      skipPrompt: true,\n    };\n\n    vi.mocked(loadAllPresets).mockResolvedValueOnce({\n      apply: async () => ({}) as any,\n    });\n    vi.mocked(cache.get).mockResolvedValueOnce(undefined);\n\n    const errorLevel = await getErrorLevel(options);\n\n    expect(errorLevel).toBe('error');\n  });\n});\n"
  },
  {
    "path": "code/core/src/core-server/withTelemetry.ts",
    "content": "import { HandledError, cache, isCI, loadAllPresets } from 'storybook/internal/common';\nimport { logger, prompt } from 'storybook/internal/node-logger';\nimport {\n  ErrorCollector,\n  getPrecedingUpgrade,\n  oneWayHash,\n  telemetry,\n} from 'storybook/internal/telemetry';\nimport type { EventType } from 'storybook/internal/telemetry';\nimport type { CLIOptions } from 'storybook/internal/types';\n\nimport { StorybookError } from '../storybook-error.ts';\n\ntype TelemetryOptions = {\n  cliOptions: CLIOptions;\n  presetOptions?: Parameters<typeof loadAllPresets>[0];\n  printError?: (err: any) => void;\n  skipPrompt?: boolean;\n  eventType?: EventType;\n};\n\nconst promptCrashReports = async () => {\n  if (isCI() || !process.stdout.isTTY) {\n    return undefined;\n  }\n\n  const enableCrashReports = await prompt.confirm({\n    message:\n      'Would you like to send anonymous crash reports to improve Storybook and fix bugs faster?',\n    initialValue: true,\n  });\n\n  await cache.set('enableCrashReports', enableCrashReports);\n\n  return enableCrashReports;\n};\n\ntype ErrorLevel = 'none' | 'error' | 'full';\n\nexport async function getErrorLevel({\n  cliOptions,\n  presetOptions,\n  skipPrompt,\n  eventType,\n}: TelemetryOptions): Promise<ErrorLevel> {\n  if (cliOptions.disableTelemetry) {\n    return 'none';\n  }\n\n  if (!presetOptions && eventType !== 'init') {\n    return 'error';\n  }\n\n  if (presetOptions) {\n    const presets = await loadAllPresets(presetOptions);\n\n    // If the user has chosen to enable/disable crash reports in main.js\n    // or disabled telemetry, we can return that\n    const core = await presets.apply('core');\n\n    if (core?.enableCrashReports !== undefined) {\n      return core.enableCrashReports ? 'full' : 'error';\n    }\n\n    if (core?.disableTelemetry) {\n      return 'none';\n    }\n  }\n\n  // Deal with typo, remove in future version (7.1?)\n  const valueFromCache =\n    (await cache.get('enableCrashReports')) ?? (await cache.get('enableCrashreports'));\n\n  if (valueFromCache !== undefined) {\n    return valueFromCache ? 'full' : 'error';\n  }\n\n  if (skipPrompt) {\n    return 'error';\n  }\n\n  const valueFromPrompt = await promptCrashReports();\n\n  if (valueFromPrompt !== undefined) {\n    return valueFromPrompt ? 'full' : 'error';\n  }\n\n  return 'full';\n}\n\nexport async function sendTelemetryError(\n  _error: unknown,\n  eventType: EventType,\n  options: TelemetryOptions,\n  blocking = true,\n  parent?: StorybookError\n) {\n  try {\n    let errorLevel = 'error';\n    try {\n      errorLevel = await getErrorLevel({\n        ...options,\n        eventType,\n        skipPrompt: options.skipPrompt || (eventType === 'init' && !blocking),\n      });\n    } catch (err) {\n      // If this throws, eg. due to main.js breaking, we fall back to 'error'\n    }\n    if (errorLevel !== 'none') {\n      const precedingUpgrade = await getPrecedingUpgrade();\n\n      const error = _error as Error & Record<string, any>;\n\n      let errorHash;\n      if ('message' in error) {\n        errorHash = error.message ? oneWayHash(error.message) : 'EMPTY_MESSAGE';\n      } else {\n        errorHash = 'NO_MESSAGE';\n      }\n\n      const { code, name, category } = error;\n      await telemetry(\n        'error',\n        {\n          code,\n          name,\n          category,\n          eventType,\n          blocking,\n          precedingUpgrade,\n          error: errorLevel === 'full' ? error : undefined,\n          errorHash,\n          // if we ever end up sending a non-error instance, we'd like to know\n          isErrorInstance: error instanceof Error,\n          // Include parent error information if this is a sub-error\n          ...(parent ? { parent: parent.fullErrorCode } : {}),\n        },\n        {\n          immediate: true,\n          configDir: options.cliOptions.configDir || options.presetOptions?.configDir,\n          enableCrashReports: errorLevel === 'full',\n        }\n      );\n\n      // If this is a StorybookError with sub-errors, send telemetry for each sub-error separately\n      if (error && 'subErrors' in error && error.subErrors.length > 0) {\n        for (const subError of error.subErrors) {\n          await sendTelemetryError(subError, eventType, options, blocking, error as StorybookError);\n        }\n      }\n    }\n  } catch (err) {\n    // if this throws an error, we just move on\n  }\n}\n\nexport function isTelemetryEnabled(options: TelemetryOptions) {\n  return !(options.cliOptions.disableTelemetry || options.cliOptions.test === true);\n}\n\nexport async function withTelemetry<T>(\n  eventType: EventType,\n  options: TelemetryOptions,\n  run: () => Promise<T>\n): Promise<T | undefined> {\n  const enableTelemetry = isTelemetryEnabled(options);\n\n  let canceled = false;\n\n  async function cancelTelemetry() {\n    canceled = true;\n    if (enableTelemetry) {\n      await telemetry('canceled', { eventType }, { stripMetadata: true, immediate: true });\n    }\n\n    process.exit(0);\n  }\n\n  if (eventType === 'init') {\n    // We catch Ctrl+C user interactions to be able to detect a cancel event\n    process.on('SIGINT', cancelTelemetry);\n  }\n\n  if (enableTelemetry) {\n    telemetry('boot', { eventType }, { stripMetadata: true });\n  }\n\n  try {\n    return await run();\n  } catch (error: any) {\n    if (canceled) {\n      return undefined;\n    }\n\n    const isHandledError =\n      error instanceof HandledError || (error instanceof StorybookError && error.isHandledError);\n\n    if (!isHandledError) {\n      const { printError = logger.error } = options;\n      printError(error);\n    }\n\n    if (enableTelemetry) {\n      await sendTelemetryError(error, eventType, options);\n    }\n\n    throw error;\n  } finally {\n    if (enableTelemetry) {\n      const errors = ErrorCollector.getErrors();\n      for (const error of errors) {\n        await sendTelemetryError(error, eventType, options, false);\n      }\n      process.off('SIGINT', cancelTelemetry);\n    }\n  }\n}\n"
  },
  {
    "path": "code/core/src/csf/SBType.ts",
    "content": "interface SBBaseType {\n  required?: boolean;\n  raw?: string;\n}\n\nexport type SBScalarType = SBBaseType & {\n  name: 'boolean' | 'string' | 'number' | 'function' | 'symbol' | 'date';\n};\n\nexport type SBArrayType = SBBaseType & {\n  name: 'array';\n  value: SBType;\n};\nexport type SBNodeType = SBBaseType & {\n  // Framework-specific “renderable node” (e.g. ReactNode, Vue VNode).\n  name: 'node';\n  renderer: string;\n};\nexport type SBObjectType = SBBaseType & {\n  name: 'object';\n  value: Record<string, SBType>;\n};\nexport type SBEnumType = SBBaseType & {\n  name: 'enum';\n  value: (string | number)[];\n};\nexport type SBIntersectionType = SBBaseType & {\n  name: 'intersection';\n  value: SBType[];\n};\nexport type SBUnionType = SBBaseType & {\n  name: 'union';\n  value: SBType[];\n};\nexport type SBLiteralType = SBBaseType & {\n  name: 'literal';\n  value: unknown;\n};\nexport type SBTupleType = SBBaseType & {\n  name: 'tuple';\n  value: SBType[];\n};\nexport type SBOtherType = SBBaseType & {\n  name: 'other';\n  value: string;\n};\n\nexport type SBType =\n  | SBScalarType\n  | SBEnumType\n  | SBArrayType\n  | SBNodeType\n  | SBObjectType\n  | SBIntersectionType\n  | SBUnionType\n  | SBLiteralType\n  | SBTupleType\n  | SBOtherType;\n"
  },
  {
    "path": "code/core/src/csf/core-annotations.ts",
    "content": "import type { StorybookTypes } from 'storybook/internal/types';\n\nimport actionAnnotations, { type ActionsTypes } from '../actions/preview.ts';\nimport backgroundsAnnotations, { type BackgroundTypes } from '../backgrounds/preview.ts';\nimport componentTestingAnnotations from '../component-testing/preview.ts';\nimport { type ControlsTypes } from '../controls/preview.ts';\nimport ghostStoriesAnnotations from '../core-server/utils/ghost-stories/test-annotations.ts';\nimport highlightAnnotations, { type HighlightTypes } from '../highlight/preview.ts';\nimport measureAnnotations, { type MeasureTypes } from '../measure/preview.ts';\nimport outlineAnnotations, { type OutlineTypes } from '../outline/preview.ts';\nimport testAnnotations, { type TestTypes } from '../test/preview.ts';\nimport viewportAnnotations, { type ViewportTypes } from '../viewport/preview.ts';\n\nexport type { ActionsTypes } from '../actions/preview.ts';\nexport type { BackgroundsGlobals, BackgroundTypes } from '../backgrounds/preview.ts';\nexport type { ControlsTypes } from '../controls/preview.ts';\nexport type { HighlightTypes } from '../highlight/preview.ts';\nexport type { MeasureTypes } from '../measure/preview.ts';\nexport type { OutlineTypes } from '../outline/preview.ts';\nexport type { TestTypes } from '../test/preview.ts';\nexport type { ViewportGlobals, ViewportTypes } from '../viewport/preview.ts';\n\nexport type CoreTypes = StorybookTypes &\n  ActionsTypes &\n  BackgroundTypes &\n  ControlsTypes &\n  HighlightTypes &\n  MeasureTypes &\n  OutlineTypes &\n  TestTypes &\n  ViewportTypes;\n\nexport function getCoreAnnotations() {\n  return [\n    // @ts-expect-error CJS fallback\n    (measureAnnotations.default ?? measureAnnotations)(),\n    // @ts-expect-error CJS fallback\n    (backgroundsAnnotations.default ?? backgroundsAnnotations)(),\n    // @ts-expect-error CJS fallback\n    (highlightAnnotations.default ?? highlightAnnotations)(),\n    // @ts-expect-error CJS fallback\n    (outlineAnnotations.default ?? outlineAnnotations)(),\n    // @ts-expect-error CJS fallback\n    (viewportAnnotations.default ?? viewportAnnotations)(),\n    // @ts-expect-error CJS fallback\n    (actionAnnotations.default ?? actionAnnotations)(),\n    // @ts-expect-error CJS fallback\n    (componentTestingAnnotations.default ?? componentTestingAnnotations)(),\n    // @ts-expect-error CJS fallback\n    (testAnnotations.default ?? testAnnotations)(),\n    // @ts-expect-error CJS fallback\n    (ghostStoriesAnnotations.default ?? ghostStoriesAnnotations)(),\n  ];\n}\n"
  },
  {
    "path": "code/core/src/csf/csf-factories.test.ts",
    "content": "//* @vitest-environment happy-dom */\nimport { describe, expect, test, vi } from 'vitest';\n\nimport { definePreview, definePreviewAddon, getStoryChildren } from './csf-factories.ts';\n\ninterface Addon1Types {\n  parameters: { foo?: { value: string } };\n}\n\nconst addon = definePreviewAddon<Addon1Types>({});\n\ninterface Addon2Types {\n  parameters: { bar?: { value: string } };\n}\n\nconst addon2 = definePreviewAddon<Addon2Types>({});\n\nconst preview = definePreview({ addons: [addon, addon2], renderToCanvas: () => {} });\n\nconst meta = preview.type<{ args: { label: string } }>().meta({\n  args: { label: 'foo' },\n  render: ({ label }) => 'hello' + label,\n});\n\ntest('addon parameters are inferred', () => {\n  const MyStory = meta.story({\n    parameters: {\n      foo: {\n        value: '1',\n      },\n      bar: {\n        value: '1',\n      },\n    },\n  });\n  const MyStory2 = meta.story({\n    // @ts-expect-error can not assign numbers to strings\n    parameters: {\n      foo: {\n        value: 1,\n      },\n      bar: {\n        value: 1,\n      },\n    },\n  });\n});\n\ndescribe('test function', () => {\n  test('without overrides', async () => {\n    const MyStory = meta.story({ args: { label: 'foo' } });\n    const testFn = vi.fn(() => console.log('testFn'));\n    const testName = 'should run test';\n\n    // register test\n    MyStory.test(testName, testFn);\n    const test = getStoryChildren(MyStory).find(({ input }) => input.name === testName)!;\n    expect(test.input.args).toEqual({ label: 'foo' });\n\n    // execute test\n    await test.run(undefined, testName);\n    expect(testFn).toHaveBeenCalled();\n  });\n  test('with overrides', async () => {\n    const MyStory = meta.story({ args: { label: 'foo' } });\n    const testFn = vi.fn();\n    const testName = 'should run test';\n\n    // register test\n    MyStory.test(testName, { args: { label: 'bar' } }, testFn);\n    const test = getStoryChildren(MyStory).find(({ input }) => input.name === testName)!;\n    expect(test.input.args).toEqual({ label: 'bar' });\n\n    // execute test\n    await test.run();\n    expect(testFn).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "code/core/src/csf/csf-factories.ts",
    "content": "import type { AddonTypes, StoryContext } from 'storybook/internal/csf';\nimport { combineTags } from 'storybook/internal/csf';\nimport type {\n  ComponentAnnotations,\n  ComposedStoryFn,\n  NormalizedProjectAnnotations,\n  ProjectAnnotations,\n  Renderer,\n  StoryAnnotations,\n  TestFunction,\n} from 'storybook/internal/types';\n\nimport type { SetOptional } from 'type-fest';\n\nimport {\n  combineParameters,\n  composeConfigs,\n  composeStory,\n  normalizeArrays,\n  normalizeProjectAnnotations,\n} from '../preview-api/index.ts';\nimport { mountDestructured } from '../preview-api/modules/preview-web/render/mount-utils.ts';\nimport { Tag } from '../shared/constants/tags.ts';\nimport { getCoreAnnotations } from './core-annotations.ts';\n\nexport interface Preview<TRenderer extends Renderer = Renderer> {\n  readonly _tag: 'Preview';\n  input: ProjectAnnotations<TRenderer> & { addons?: PreviewAddon<never>[] };\n  composed: NormalizedProjectAnnotations<TRenderer>;\n\n  meta<\n    TArgs,\n    TInput extends ComponentAnnotations<TRenderer & { args: TArgs }, TArgs & TRenderer['args']>,\n  >(\n    input: TInput\n  ): Meta<TRenderer & { args: TArgs }, TInput>;\n\n  type<T>(): Preview<TRenderer & T>;\n}\n\nexport type InferTypes<T extends PreviewAddon<never>[]> = T extends PreviewAddon<infer C>[]\n  ? C & { csf4: true }\n  : never;\n\nexport function definePreview<TRenderer extends Renderer, Addons extends PreviewAddon<never>[]>(\n  input: ProjectAnnotations<TRenderer> & { addons?: Addons }\n): Preview<TRenderer & InferTypes<Addons>> {\n  let composed: NormalizedProjectAnnotations<TRenderer & InferTypes<Addons>>;\n  const preview = {\n    _tag: 'Preview',\n    input: input,\n    get composed() {\n      if (composed) {\n        return composed;\n      }\n      const { addons, ...rest } = input;\n      composed = normalizeProjectAnnotations<TRenderer & InferTypes<Addons>>(\n        composeConfigs([...getCoreAnnotations(), ...(addons ?? []), rest])\n      );\n      return composed;\n    },\n    type() {\n      return this;\n    },\n    meta(meta) {\n      // @ts-expect-error hard\n      return defineMeta(meta, this);\n    },\n  } as Preview<TRenderer & InferTypes<Addons>>;\n  globalThis.globalProjectAnnotations = preview.composed;\n  return preview;\n}\n\nexport interface PreviewAddon<\n  in TExtraContext extends AddonTypes = AddonTypes,\n> extends ProjectAnnotations<Renderer> {}\n\nexport function definePreviewAddon<TExtraContext extends AddonTypes = AddonTypes>(\n  preview: ProjectAnnotations<Renderer>\n): PreviewAddon<TExtraContext> {\n  return preview;\n}\n\nexport function isPreview(input: unknown): input is Preview<Renderer> {\n  return input != null && typeof input === 'object' && '_tag' in input && input?._tag === 'Preview';\n}\n\nexport interface Meta<\n  TRenderer extends Renderer,\n  TMetaInput extends ComponentAnnotations<TRenderer, TRenderer['args']> = ComponentAnnotations<\n    TRenderer,\n    TRenderer['args']\n  >,\n> {\n  readonly _tag: 'Meta';\n  input: TMetaInput;\n  // composed: NormalizedComponentAnnotations<TRenderer>;\n  preview: Preview<TRenderer>;\n\n  story(\n    input?: () => TRenderer['storyResult']\n  ): Story<TRenderer, { render: () => TRenderer['storyResult'] }>;\n\n  story<\n    TInput extends StoryAnnotations<\n      TRenderer,\n      TRenderer['args'],\n      SetOptional<TRenderer['args'], keyof TRenderer['args'] & keyof TMetaInput['args']>\n    >,\n  >(\n    input?: TInput\n  ): Story<TRenderer, TInput>;\n}\n\nexport function isMeta(input: unknown): input is Meta<Renderer> {\n  return input != null && typeof input === 'object' && '_tag' in input && input?._tag === 'Meta';\n}\n\nfunction defineMeta<\n  TRenderer extends Renderer,\n  TInput extends ComponentAnnotations<TRenderer, TRenderer['args']> = ComponentAnnotations<\n    TRenderer,\n    TRenderer['args']\n  >,\n>(input: TInput, preview: Preview<TRenderer>): Meta<TRenderer, TInput> {\n  return {\n    _tag: 'Meta',\n    input: { ...input, parameters: { ...input.parameters, csfFactory: true } },\n    preview,\n    // @ts-expect-error hard\n    story(\n      story: StoryAnnotations<TRenderer, TRenderer['args']> | (() => TRenderer['storyResult']) = {}\n    ) {\n      return defineStory(typeof story === 'function' ? { render: story } : story, this);\n    },\n  };\n}\n\nexport interface Story<\n  TRenderer extends Renderer,\n  TInput extends StoryAnnotations<TRenderer, TRenderer['args']> = StoryAnnotations<\n    TRenderer,\n    TRenderer['args']\n  >,\n> {\n  readonly _tag: 'Story';\n  input: TInput;\n  composed: Pick<\n    ComposedStoryFn<TRenderer>,\n    'argTypes' | 'parameters' | 'id' | 'tags' | 'globals'\n  > & {\n    args: TRenderer['args'];\n    name: string;\n  };\n  meta: Meta<TRenderer>;\n  play: TInput['play'];\n  run: (\n    context?: Partial<StoryContext<TRenderer, Partial<TRenderer['args']>>>,\n    testName?: string\n  ) => Promise<void>;\n\n  extend<TInput extends StoryAnnotations<TRenderer, TRenderer['args']>>(\n    input: TInput\n  ): Story<TRenderer, TInput>;\n  test(name: string, fn: TestFunction<TRenderer>): void;\n  test(\n    name: string,\n    annotations: StoryAnnotations<TRenderer, TRenderer['args']>,\n    fn: TestFunction<TRenderer>\n  ): void;\n}\n\nexport function isStory<TRenderer extends Renderer>(input: unknown): input is Story<TRenderer> {\n  return input != null && typeof input === 'object' && '_tag' in input && input?._tag === 'Story';\n}\n\nfunction defineStory<\n  TRenderer extends Renderer,\n  TInput extends StoryAnnotations<TRenderer, TRenderer['args']>,\n>(input: TInput, meta: Meta<TRenderer>): Story<TRenderer, TInput> {\n  let composed: ComposedStoryFn<TRenderer>;\n  const compose = () => {\n    if (!composed) {\n      composed = composeStory(\n        input as StoryAnnotations<TRenderer>,\n        meta.input as ComponentAnnotations<TRenderer>,\n        undefined,\n        meta.preview.composed\n      );\n    }\n    return composed;\n  };\n\n  const __children: Story<TRenderer>[] = [];\n\n  return {\n    _tag: 'Story',\n    input,\n    meta,\n    // @ts-expect-error this is a private property used only once in renderers/react/src/preview\n    __compose: compose,\n    __children,\n    get composed() {\n      const composed = compose();\n      const { args, argTypes, parameters, id, tags, globals, storyName: name } = composed;\n      return { args, argTypes, parameters, id, tags, name, globals };\n    },\n    get play() {\n      return input.play ?? meta.input?.play ?? (async () => {});\n    },\n    async run(context) {\n      await compose().run(context);\n    },\n    test(\n      name: string,\n      overridesOrTestFn: StoryAnnotations<TRenderer, TRenderer['args']> | TestFunction<TRenderer>,\n      testFn?: TestFunction<TRenderer, TRenderer['args']>\n    ): void {\n      const annotations = typeof overridesOrTestFn !== 'function' ? overridesOrTestFn : {};\n      const testFunction = typeof overridesOrTestFn !== 'function' ? testFn! : overridesOrTestFn;\n\n      const play =\n        mountDestructured(this.play) || mountDestructured(testFunction)\n          ? // mount needs to be explicitly destructured\n            // eslint-disable-next-line @typescript-eslint/no-unused-vars\n            async ({ mount, context }: StoryContext<TRenderer>) => {\n              await this.play?.(context);\n              await testFunction(context);\n            }\n          : async (context: StoryContext<TRenderer>) => {\n              await this.play?.(context);\n              await testFunction(context);\n            };\n\n      const test = this.extend({\n        ...annotations,\n        name,\n        tags: [Tag.TEST_FN, `!${Tag.AUTODOCS}`, ...(annotations.tags ?? [])],\n        play,\n      });\n      __children.push(test);\n\n      return test as unknown as void;\n    },\n    extend<TInput extends StoryAnnotations<TRenderer, TRenderer['args']>>(input: TInput) {\n      return defineStory(\n        {\n          ...this.input,\n          ...input,\n          args: { ...(this.input.args || {}), ...input.args },\n          argTypes: combineParameters(this.input.argTypes, input.argTypes),\n          afterEach: [\n            ...normalizeArrays(this.input?.afterEach ?? []),\n            ...normalizeArrays(input.afterEach ?? []),\n          ],\n          beforeEach: [\n            ...normalizeArrays(this.input?.beforeEach ?? []),\n            ...normalizeArrays(input.beforeEach ?? []),\n          ],\n          decorators: [\n            ...normalizeArrays(this.input?.decorators ?? []),\n            ...normalizeArrays(input.decorators ?? []),\n          ],\n          globals: { ...this.input.globals, ...input.globals },\n          loaders: [\n            ...normalizeArrays(this.input?.loaders ?? []),\n            ...normalizeArrays(input.loaders ?? []),\n          ],\n          parameters: combineParameters(this.input.parameters, input.parameters),\n          tags: combineTags(...(this.input.tags ?? []), ...(input.tags ?? [])),\n        },\n        this.meta\n      );\n    },\n  };\n}\n\nexport function getStoryChildren<TRenderer extends Renderer>(\n  story: Story<TRenderer>\n): Story<TRenderer>[] {\n  if ('__children' in story) {\n    return story.__children as Story<TRenderer>[];\n  }\n  return [];\n}\n"
  },
  {
    "path": "code/core/src/csf/includeConditionalArg.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { includeConditionalArg, testValue } from './includeConditionalArg.ts';\nimport type { Conditional } from './story.ts';\n\ndescribe('testValue', () => {\n  describe('truthy', () => {\n    it.each([\n      ['implicit true', {}, true, true],\n      ['implicit truthy', {}, 1, true],\n      ['implicit falsey', {}, 0, false],\n      ['truthy true', { truthy: true }, true, true],\n      ['truthy truthy', { truthy: true }, 1, true],\n      ['truthy falsey', { truthy: true }, 0, false],\n      ['falsey true', { truthy: false }, true, false],\n      ['falsey truthy', { truthy: false }, 1, false],\n      ['falsey falsey', { truthy: false }, 0, true],\n    ])('%s', (_name, cond, value, expected) => {\n      expect(testValue(cond, value)).toBe(expected);\n    });\n  });\n\n  describe('exists', () => {\n    it.each([\n      ['exist', { exists: true }, 1, true],\n      ['exist false', { exists: true }, undefined, false],\n      ['nexist', { exists: false }, undefined, true],\n      ['nexist false', { exists: false }, 1, false],\n    ])('%s', (_name, cond, value, expected) => {\n      expect(testValue(cond, value)).toBe(expected);\n    });\n  });\n  describe('eq', () => {\n    it.each([\n      ['true', { eq: 1 }, 1, true],\n      ['false', { eq: 1 }, 2, false],\n      ['undefined', { eq: undefined }, undefined, false],\n      ['undefined false', { eq: 1 }, undefined, false],\n      ['object true', { eq: { x: 1 } }, { x: 1 }, true],\n      ['object false', { eq: { x: 1 } }, { x: 2 }, false],\n    ])('%s', (_name, cond, value, expected) => {\n      expect(testValue(cond, value)).toBe(expected);\n    });\n  });\n  describe('neq', () => {\n    it.each([\n      ['true', { neq: 1 }, 2, true],\n      ['false', { neq: 1 }, 1, false],\n      ['undefined true', { neq: 1 }, undefined, true],\n      ['undefined false', { neq: undefined }, undefined, false],\n      ['object true', { neq: { x: 1 } }, { x: 2 }, true],\n      ['object false', { neq: { x: 1 } }, { x: 1 }, false],\n    ])('%s', (_name, cond, value, expected) => {\n      expect(testValue(cond, value)).toBe(expected);\n    });\n  });\n});\n\ndescribe('includeConditionalArg', () => {\n  describe('errors', () => {\n    it('should throw if neither arg nor global is specified', () => {\n      expect(() =>\n        includeConditionalArg({ if: {} as Conditional }, {}, {})\n      ).toThrowErrorMatchingInlineSnapshot(`[Error: Invalid conditional value {}]`);\n    });\n    it('should throw if arg and global are both specified', () => {\n      expect(() =>\n        includeConditionalArg({ if: { arg: 'a', global: 'b' } }, {}, {})\n      ).toThrowErrorMatchingInlineSnapshot(\n        `[Error: Invalid conditional value {\"arg\":\"a\",\"global\":\"b\"}]`\n      );\n    });\n    it('should throw if multiple exists / eq / neq are specified', () => {\n      expect(() =>\n        includeConditionalArg({ if: { arg: 'a', exists: true, eq: 1 } }, {}, {})\n      ).toThrowErrorMatchingInlineSnapshot(\n        `[Error: Invalid conditional test {\"exists\":true,\"eq\":1}]`\n      );\n\n      expect(() =>\n        includeConditionalArg({ if: { arg: 'a', exists: false, neq: 0 } }, {}, {})\n      ).toThrowErrorMatchingInlineSnapshot(\n        `[Error: Invalid conditional test {\"exists\":false,\"neq\":0}]`\n      );\n\n      expect(() =>\n        includeConditionalArg({ if: { arg: 'a', eq: 1, neq: 0 } }, {}, {})\n      ).toThrowErrorMatchingInlineSnapshot(`[Error: Invalid conditional test {\"eq\":1,\"neq\":0}]`);\n    });\n  });\n\n  describe('args', () => {\n    describe('implicit', () => {\n      it.each([\n        ['implicit true', { if: { arg: 'a' } }, { a: 1 }, {}, true],\n        ['truthy true', { if: { arg: 'a', truthy: true } }, { a: 0 }, {}, false],\n        ['truthy false', { if: { arg: 'a', truthy: false } }, {}, {}, true],\n      ])('%s', (_name, argType, args, globals, expected) => {\n        expect(includeConditionalArg(argType, args, globals)).toBe(expected);\n      });\n    });\n    describe('exists', () => {\n      it.each([\n        ['exist', { if: { arg: 'a', exists: true } }, { a: 1 }, {}, true],\n        ['exist false', { if: { arg: 'a', exists: true } }, {}, {}, false],\n      ])('%s', (_name, argType, args, globals, expected) => {\n        expect(includeConditionalArg(argType, args, globals)).toBe(expected);\n      });\n    });\n    describe('eq', () => {\n      it.each([\n        ['scalar true', { if: { arg: 'a', eq: 1 } }, { a: 1 }, {}, true],\n        ['scalar false', { if: { arg: 'a', eq: 1 } }, { a: 2 }, { a: 1 }, false],\n      ])('%s', (_name, argType, args, globals, expected) => {\n        expect(includeConditionalArg(argType, args, globals)).toBe(expected);\n      });\n    });\n    describe('neq', () => {\n      it.each([\n        ['scalar true', { if: { arg: 'a', neq: 1 } }, { a: 2 }, {}, true],\n        ['scalar false', { if: { arg: 'a', neq: 1 } }, { a: 1 }, { a: 2 }, false],\n      ])('%s', (_name, argType, args, globals, expected) => {\n        expect(includeConditionalArg(argType, args, globals)).toBe(expected);\n      });\n    });\n  });\n  describe('globals', () => {\n    describe('truthy', () => {\n      it.each([\n        ['implicit true', { if: { global: 'a' } }, {}, { a: 1 }, true],\n        ['implicit undefined', { if: { global: 'a' } }, {}, {}, false],\n        ['truthy true', { if: { global: 'a', truthy: true } }, {}, { a: 0 }, false],\n        ['truthy false', { if: { global: 'a', truthy: false } }, {}, { a: 0 }, true],\n      ])('%s', (_name, argType, args, globals, expected) => {\n        expect(includeConditionalArg(argType, args, globals)).toBe(expected);\n      });\n    });\n    describe('exists', () => {\n      it.each([\n        ['implicit exist true', { if: { global: 'a', exists: true } }, {}, { a: 1 }, true],\n        ['implicit exist false', { if: { global: 'a', exists: true } }, { a: 1 }, {}, false],\n      ])('%s', (_name, argType, args, globals, expected) => {\n        expect(includeConditionalArg(argType, args, globals)).toBe(expected);\n      });\n    });\n    describe('eq', () => {\n      it.each([\n        ['scalar true', { if: { global: 'a', eq: 1 } }, {}, { a: 1 }, true],\n        ['scalar false', { if: { global: 'a', eq: 1 } }, { a: 2 }, { a: 2 }, false],\n      ])('%s', (_name, argType, args, globals, expected) => {\n        expect(includeConditionalArg(argType, args, globals)).toBe(expected);\n      });\n    });\n    describe('neq', () => {\n      it.each([\n        ['scalar true', { if: { global: 'a', neq: 1 } }, {}, { a: 2 }, true],\n        ['scalar false', { if: { global: 'a', neq: 1 } }, { a: 2 }, { a: 1 }, false],\n      ])('%s', (_name, argType, args, globals, expected) => {\n        expect(includeConditionalArg(argType, args, globals)).toBe(expected);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/csf/includeConditionalArg.ts",
    "content": "/* @ts-expect-error (has no typings) */\nimport { isEqual } from '@ngard/tiny-isequal';\n\nimport type { Args, Conditional, Globals, InputType } from './story.ts';\n\nconst count = (vals: any[]) => vals.map((v) => typeof v !== 'undefined').filter(Boolean).length;\n\nexport const testValue = (cond: Omit<Conditional, 'arg' | 'global'>, value: any) => {\n  const { exists, eq, neq, truthy } = cond as any;\n  if (count([exists, eq, neq, truthy]) > 1) {\n    throw new Error(`Invalid conditional test ${JSON.stringify({ exists, eq, neq })}`);\n  }\n  if (typeof eq !== 'undefined') {\n    return isEqual(value, eq);\n  }\n  if (typeof neq !== 'undefined') {\n    return !isEqual(value, neq);\n  }\n  if (typeof exists !== 'undefined') {\n    const valueExists = typeof value !== 'undefined';\n    return exists ? valueExists : !valueExists;\n  }\n  const shouldBeTruthy = typeof truthy === 'undefined' ? true : truthy;\n  return shouldBeTruthy ? !!value : !value;\n};\n\n/**\n * Helper function to include/exclude an arg based on the value of other other args aka \"conditional\n * args\"\n */\nexport const includeConditionalArg = (argType: InputType, args: Args, globals: Globals) => {\n  if (!argType.if) {\n    return true;\n  }\n\n  const { arg, global } = argType.if as any;\n  if (count([arg, global]) !== 1) {\n    throw new Error(`Invalid conditional value ${JSON.stringify({ arg, global })}`);\n  }\n\n  const value = arg ? args[arg] : globals[global];\n\n  return testValue(argType.if!, value);\n};\n"
  },
  {
    "path": "code/core/src/csf/index.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { combineTags, isExportStory, storyNameFromExport, toId } from './index.ts';\n\ndescribe('toId', () => {\n  const testCases: [string, string, string | undefined, string][] = [\n    // name, kind, story, output\n    ['handles simple cases', 'kind', 'story', 'kind--story'],\n    ['handles kind without story', 'kind', undefined, 'kind'],\n    ['handles basic substitution', 'a b$c?d😀e', '1-2:3', 'a-b-c-d😀e--1-2-3'],\n    ['handles runs of non-url chars', 'a?&*b', 'story', 'a-b--story'],\n    ['removes non-url chars from start and end', '?ab-', 'story', 'ab--story'],\n    ['downcases', 'KIND', 'STORY', 'kind--story'],\n    ['non-latin', 'Кнопки', 'нормальный', 'кнопки--нормальный'],\n    ['korean', 'kind', '바보 (babo)', 'kind--바보-babo'],\n    ['all punctuation', 'kind', 'unicorns,’–—―′¿`\"<>()!.!!!{}[]%^&$*#&', 'kind--unicorns'],\n  ];\n\n  testCases.forEach(([name, kind, story, output]) => {\n    it(name, () => {\n      expect(toId(kind, story)).toBe(output);\n    });\n  });\n\n  it('does not allow kind with *no* url chars', () => {\n    expect(() => toId('?', 'asdf')).toThrow(\n      `Invalid kind '?', must include alphanumeric characters`\n    );\n  });\n\n  it('does not allow empty kind', () => {\n    expect(() => toId('', 'asdf')).toThrow(`Invalid kind '', must include alphanumeric characters`);\n  });\n\n  it('does not allow story with *no* url chars', () => {\n    expect(() => toId('kind', '?')).toThrow(\n      `Invalid name '?', must include alphanumeric characters`\n    );\n  });\n\n  it('allows empty story', () => {\n    expect(() => toId('kind', '')).not.toThrow();\n  });\n});\n\ndescribe('storyNameFromExport', () => {\n  it('should format CSF exports with sensible defaults', () => {\n    const testCases = {\n      name: 'Name',\n      someName: 'Some Name',\n      someNAME: 'Some NAME',\n      some_custom_NAME: 'Some Custom NAME',\n      someName1234: 'Some Name 1234',\n      someName1_2_3_4: 'Some Name 1 2 3 4',\n    };\n    Object.entries(testCases).forEach(([key, val]) => expect(storyNameFromExport(key)).toBe(val));\n  });\n});\n\ndescribe('isExportStory', () => {\n  it('should exclude __esModule', () => {\n    expect(isExportStory('__esModule', {})).toBeFalsy();\n  });\n\n  it('should include all stories when there are no filters', () => {\n    expect(isExportStory('a', {})).toBeTruthy();\n  });\n\n  it('should filter stories by arrays', () => {\n    expect(isExportStory('a', { includeStories: ['a'] })).toBeTruthy();\n    expect(isExportStory('a', { includeStories: [] })).toBeFalsy();\n    expect(isExportStory('a', { includeStories: ['b'] })).toBeFalsy();\n\n    expect(isExportStory('a', { excludeStories: ['a'] })).toBeFalsy();\n    expect(isExportStory('a', { excludeStories: [] })).toBeTruthy();\n    expect(isExportStory('a', { excludeStories: ['b'] })).toBeTruthy();\n\n    expect(isExportStory('a', { includeStories: ['a'], excludeStories: ['a'] })).toBeFalsy();\n    expect(isExportStory('a', { includeStories: [], excludeStories: [] })).toBeFalsy();\n    expect(isExportStory('a', { includeStories: ['a'], excludeStories: ['b'] })).toBeTruthy();\n  });\n\n  it('should filter stories by regex', () => {\n    expect(isExportStory('a', { includeStories: /a/ })).toBeTruthy();\n    expect(isExportStory('a', { includeStories: /.*/ })).toBeTruthy();\n    expect(isExportStory('a', { includeStories: /b/ })).toBeFalsy();\n\n    expect(isExportStory('a', { excludeStories: /a/ })).toBeFalsy();\n    expect(isExportStory('a', { excludeStories: /.*/ })).toBeFalsy();\n    expect(isExportStory('a', { excludeStories: /b/ })).toBeTruthy();\n\n    expect(isExportStory('a', { includeStories: /a/, excludeStories: ['a'] })).toBeFalsy();\n    expect(isExportStory('a', { includeStories: /.*/, excludeStories: /.*/ })).toBeFalsy();\n    expect(isExportStory('a', { includeStories: /a/, excludeStories: /b/ })).toBeTruthy();\n  });\n});\n\ndescribe('combineTags', () => {\n  it.each([\n    [[], []],\n    [\n      ['a', 'b'],\n      ['a', 'b'],\n    ],\n    [\n      ['a', 'b', 'b'],\n      ['a', 'b'],\n    ],\n    [['a', 'b', '!b'], ['a']],\n    [['b', '!b', 'b'], ['b']],\n  ])('combineTags(%o) -> %o', (tags, expected) => {\n    expect(combineTags(...tags)).toEqual(expected);\n  });\n});\n"
  },
  {
    "path": "code/core/src/csf/index.ts",
    "content": "import { toStartCaseStr } from './toStartCaseStr.ts';\n\n/**\n * Remove punctuation and illegal characters from a story ID.\n *\n * See https://gist.github.com/davidjrice/9d2af51100e41c6c4b4a\n */\nexport const sanitize = (string: string) => {\n  return string\n    .toLowerCase()\n\n    .replace(/[ ’–—―′¿'`~!@#$%^&*()_|+\\-=?;:'\",.<>\\{\\}\\[\\]\\\\\\/]/gi, '-')\n    .replace(/-+/g, '-')\n    .replace(/^-+/, '')\n    .replace(/-+$/, '');\n};\n\nconst sanitizeSafe = (string: string, part: string) => {\n  const sanitized = sanitize(string);\n  if (sanitized === '') {\n    throw new Error(`Invalid ${part} '${string}', must include alphanumeric characters`);\n  }\n  return sanitized;\n};\n\n/** Generate a storybook ID from a component/kind and story name. */\nexport const toId = (kind: string, name?: string) =>\n  `${sanitizeSafe(kind, 'kind')}${name ? `--${sanitizeSafe(name, 'name')}` : ''}`;\n\n/** Generate a storybook test ID from a story ID and test name. */\nexport const toTestId = (parentId: string, testName: string) =>\n  `${parentId}:${sanitizeSafe(testName, 'test')}`;\n\n/** Transform a CSF named export into a readable story name */\nexport const storyNameFromExport = (key: string) => toStartCaseStr(key);\n\ntype StoryDescriptor = string[] | RegExp;\nexport interface IncludeExcludeOptions {\n  includeStories?: StoryDescriptor;\n  excludeStories?: StoryDescriptor;\n}\n\nfunction matches(storyKey: string, arrayOrRegex: StoryDescriptor) {\n  if (Array.isArray(arrayOrRegex)) {\n    return arrayOrRegex.includes(storyKey);\n  }\n  return storyKey.match(arrayOrRegex);\n}\n\n/** Does a named export match CSF inclusion/exclusion options? */\nexport function isExportStory(\n  key: string,\n  { includeStories, excludeStories }: IncludeExcludeOptions\n) {\n  return (\n    // https://babeljs.io/docs/en/babel-plugin-transform-modules-commonjs\n    key !== '__esModule' &&\n    (!includeStories || matches(key, includeStories)) &&\n    (!excludeStories || !matches(key, excludeStories))\n  );\n}\n\nexport interface SeparatorOptions {\n  rootSeparator: string | RegExp;\n  groupSeparator: string | RegExp;\n}\n\n/** Parse out the component/kind name from a path, using the given separator config. */\nexport const parseKind = (kind: string, { rootSeparator, groupSeparator }: SeparatorOptions) => {\n  const [root, remainder] = kind.split(rootSeparator, 2);\n  const groups = (remainder || kind).split(groupSeparator).filter((i) => !!i);\n\n  // when there's no remainder, it means the root wasn't found/split\n  return {\n    root: remainder ? root : null,\n    groups,\n  };\n};\n\n/** Combine a set of project / meta / story tags, removing duplicates and handling negations. */\nexport const combineTags = (...tags: string[]): string[] => {\n  const result = tags.reduce((acc, tag) => {\n    if (tag.startsWith('!')) {\n      acc.delete(tag.slice(1));\n    } else {\n      acc.add(tag);\n    }\n    return acc;\n  }, new Set<string>());\n  return Array.from(result);\n};\n\nexport { includeConditionalArg } from './includeConditionalArg.ts';\nexport * from './story.ts';\nexport * from './csf-factories.ts';\nexport * from './core-annotations.ts';\n"
  },
  {
    "path": "code/core/src/csf/story.test.ts",
    "content": "/* global HTMLElement */\nimport { test } from 'vitest';\n\nimport { expectTypeOf } from 'expect-type';\n\nimport type {\n  Args,\n  ArgsFromMeta,\n  ArgsStoryFn,\n  ComponentAnnotations,\n  DecoratorFunction,\n  LoaderFunction,\n  ProjectAnnotations,\n  Renderer,\n  StoryAnnotationsOrFn,\n  StrictArgs,\n} from './story.ts';\n\n// NOTE Example of internal type definition for @storybook/<X> (where X is a renderer)\ninterface XRenderer extends Renderer {\n  component: (args: this['T']) => string;\n  storyResult: string;\n  canvasElement: HTMLElement;\n}\n\ntype XMeta<TArgs = Args> = ComponentAnnotations<XRenderer, TArgs>;\ntype XStory<TArgs = Args> = StoryAnnotationsOrFn<XRenderer, TArgs>;\n\n// NOTE Examples of using types from @storybook/<X> in real project\n\ntype ButtonArgs = {\n  x: string;\n  y: string;\n};\n\nconst Button = (props: ButtonArgs) => 'Button';\n\nconst ButtonIcon = ({ icon }: { icon: string }) => `ButtonIcon ${icon}`;\n\nlet a = 1;\nasync function doSomething() {\n  a = 2;\n}\n\nasync function validateSomething() {}\n\nasync function cleanup() {\n  a = 1;\n}\n\n// NOTE Various kind usages\nconst simple: XMeta = {\n  title: 'simple',\n  component: Button,\n  tags: ['foo', 'bar'],\n  decorators: [(storyFn, context) => `withDecorator(${storyFn(context)})`],\n  parameters: { a: () => null, b: NaN, c: Symbol('symbol') },\n  loaders: [() => Promise.resolve({ d: '3' })],\n  async beforeEach() {\n    await doSomething();\n    return cleanup;\n  },\n  async afterEach() {\n    await validateSomething();\n  },\n  args: { x: '1' },\n  argTypes: { x: { type: { name: 'string' } } },\n};\n\nconst strict: XMeta<ButtonArgs> = {\n  title: 'simple',\n  component: Button,\n  tags: ['foo', 'bar'],\n  decorators: [(storyFn, context) => `withDecorator(${storyFn(context)})`],\n  parameters: { a: () => null, b: NaN, c: Symbol('symbol') },\n  loaders: [() => Promise.resolve({ d: '3' })],\n  args: { x: '1' },\n  async beforeEach() {\n    await doSomething();\n    return cleanup;\n  },\n  async afterEach() {\n    await validateSomething();\n  },\n  argTypes: { x: { type: { name: 'string' } } },\n};\n\nconst options = ['foo', 'bar'] as const;\nconst simpleWithReadonlyOptions: XMeta<ButtonArgs> = {\n  title: 'simple',\n  component: Button,\n  tags: ['foo', 'bar'],\n  decorators: [(storyFn, context) => `withDecorator(${storyFn(context)})`],\n  parameters: { a: () => null, b: NaN, c: Symbol('symbol') },\n  loaders: [() => Promise.resolve({ d: '3' })],\n  args: { x: '1' },\n  argTypes: {\n    x: {\n      control: {\n        type: 'select',\n      },\n      options,\n    },\n  },\n};\n\n// NOTE Various story usages\nconst Simple: XStory = () => 'Simple';\n\nconst CSF1Story: XStory = () => 'Named Story';\nCSF1Story.story = {\n  name: 'Another name for story',\n  tags: ['foo', 'bar'],\n  decorators: [(storyFn) => `Wrapped(${storyFn()}`],\n  parameters: { a: [1, '2', {}], b: undefined, c: Button },\n  loaders: [() => Promise.resolve({ d: '3' })],\n  async beforeEach() {\n    await doSomething();\n    return cleanup;\n  },\n  args: { a: 1 },\n};\n\nconst simpleWithSubComponents: XMeta = {\n  title: 'simple',\n  component: Button,\n  tags: ['foo', 'bar'],\n  decorators: [(storyFn, context) => `withDecorator(${storyFn(context)})`],\n  parameters: { a: () => null, b: NaN, c: Symbol('symbol') },\n  loaders: [() => Promise.resolve({ d: '3' })],\n  async beforeEach() {\n    await doSomething();\n    return cleanup;\n  },\n  args: { x: '1' },\n  argTypes: { x: { type: { name: 'string' } } },\n  subcomponents: { ButtonIcon }, // the fact that this line does not cause a Typescript compilation error itself means that the type is correct\n};\n\nconst CSF2Story: XStory = () => 'Named Story';\nCSF2Story.storyName = 'Another name for story';\nCSF2Story.tags = ['foo', 'bar'];\nCSF2Story.decorators = [(storyFn) => `Wrapped(${storyFn()}`];\nCSF2Story.parameters = { a: [1, '2', {}], b: undefined, c: Button };\nCSF2Story.loaders = [() => Promise.resolve({ d: '3' })];\nCSF2Story.args = { a: 1 };\n\nconst CSF3Story: XStory = {\n  render: (args) => 'Named Story',\n  name: 'Another name for story',\n  tags: ['foo', 'bar'],\n  decorators: [(storyFn) => `Wrapped(${storyFn()}`],\n  parameters: { a: [1, '2', {}], b: undefined, c: Button },\n  loaders: [() => Promise.resolve({ d: '3' })],\n  args: { a: 1 },\n};\n\nconst CSF3StoryStrict: XStory<ButtonArgs> = {\n  render: (args) => 'Named Story',\n  name: 'Another name for story',\n  tags: ['foo', 'bar'],\n  decorators: [(storyFn) => `Wrapped(${storyFn()}`],\n  parameters: { a: [1, '2', {}], b: undefined, c: Button },\n  loaders: [() => Promise.resolve({ d: '3' })],\n  args: { x: '1' },\n  play: async ({ step, canvasElement }) => {\n    await step('a step', async ({ step: substep }) => {\n      await substep('a substep', () => {});\n    });\n  },\n};\n\nconst project: ProjectAnnotations<XRenderer> = {\n  async runStep(label, play, context) {\n    return play(context);\n  },\n};\n\ntest('ArgsFromMeta will infer correct args from render/loader/decorators', () => {\n  const decorator1: DecoratorFunction<XRenderer, { decoratorArg: string }> = (Story, { args }) =>\n    `${args.decoratorArg}`;\n\n  const decorator2: DecoratorFunction<XRenderer, { decoratorArg2: string }> = (Story, { args }) =>\n    `${args.decoratorArg2}`;\n\n  const decorator3: DecoratorFunction<XRenderer, Args> = (Story, { args }) => ``;\n\n  const decorator4: DecoratorFunction<XRenderer, StrictArgs> = (Story, { args }) => ``;\n\n  const loader: LoaderFunction<XRenderer, { loaderArg: number }> = async ({ args }) => ({\n    loader: `${args.loaderArg}`,\n  });\n\n  const loader2: LoaderFunction<XRenderer, { loaderArg2: number }> = async ({ args }) => ({\n    loader2: `${args.loaderArg2}`,\n  });\n\n  const renderer: ArgsStoryFn<XRenderer, { theme: string }> = (args) => `${args.theme}`;\n\n  const meta = {\n    component: Button,\n    args: { disabled: false },\n    render: renderer,\n    decorators: [decorator1, decorator2, decorator3, decorator4],\n    loaders: [loader, loader2],\n  };\n  expectTypeOf<ArgsFromMeta<XRenderer, typeof meta>>().toEqualTypeOf<{\n    theme: string;\n    decoratorArg: string;\n    decoratorArg2: string;\n    loaderArg: number;\n    loaderArg2: number;\n  }>();\n});\n\ntest('You can assign a component to Meta, even when you pass a top type', () => {\n  expectTypeOf({ component: Button }).toMatchTypeOf<XMeta>();\n  expectTypeOf({ component: Button }).toMatchTypeOf<XMeta<Record<string, any>>>();\n  expectTypeOf({ component: Button }).toMatchTypeOf<XMeta<Record<string, unknown>>>();\n  expectTypeOf({ component: Button }).toMatchTypeOf<XMeta<unknown>>();\n  expectTypeOf({ component: Button }).toMatchTypeOf<XMeta<any>>();\n  expectTypeOf({ component: Button }).not.toMatchTypeOf<XMeta<{ a?: number }>>();\n  expectTypeOf({ component: Button }).not.toMatchTypeOf<XMeta<{ a: number }>>();\n});\n"
  },
  {
    "path": "code/core/src/csf/story.ts",
    "content": "import type { RemoveIndexSignature, Simplify, UnionToIntersection } from 'type-fest';\n\nimport type { ToolbarArgType } from '../toolbar/index.ts';\nimport type { SBScalarType, SBType } from './SBType.ts';\nimport type { CoreTypes } from './core-annotations.ts';\n\nexport * from './SBType.ts';\nexport type StoryId = string;\nexport type ComponentId = string;\nexport type ComponentTitle = string;\nexport type StoryName = string;\n\n/** @deprecated */\nexport type StoryKind = ComponentTitle;\n\nexport type Tag = string;\n\nexport interface StoryIdentifier {\n  componentId: ComponentId;\n  title: ComponentTitle;\n  /** @deprecated */\n  kind: ComponentTitle;\n\n  id: StoryId;\n  name: StoryName;\n  /** @deprecated */\n  story: StoryName;\n\n  tags: Tag[];\n}\n\nexport interface Parameters {\n  [name: string]: any;\n}\n\nexport interface StrictParameters {\n  [name: string]: unknown;\n}\n\ntype ControlType =\n  | 'object'\n  | 'boolean'\n  | 'check'\n  | 'inline-check'\n  | 'radio'\n  | 'inline-radio'\n  | 'select'\n  | 'multi-select'\n  | 'number'\n  | 'range'\n  | 'file'\n  | 'color'\n  | 'date'\n  | 'text';\n\ntype ConditionalTest = { truthy?: boolean } | { exists: boolean } | { eq: any } | { neq: any };\ntype ConditionalValue = { arg: string } | { global: string };\nexport type Conditional = ConditionalValue & ConditionalTest;\n\ninterface ControlBase {\n  [key: string]: any;\n  /** @see https://storybook.js.org/docs/api/arg-types#controltype */\n  type?: ControlType;\n  disable?: boolean;\n}\n\ninterface Report {\n  type: string;\n  version?: number;\n  result: unknown;\n  status: 'failed' | 'passed' | 'warning';\n}\n\ninterface ReportingAPI {\n  reports: Report[];\n  addReport: (report: Report) => void;\n}\n\ntype Control =\n  | ControlType\n  | false\n  | (ControlBase &\n      (\n        | ControlBase\n        | {\n            type: 'color';\n            /** @see https://storybook.js.org/docs/api/arg-types#controlpresetcolors */\n            presetColors?: string[];\n          }\n        | {\n            type: 'file';\n            /** @see https://storybook.js.org/docs/api/arg-types#controlaccept */\n            accept?: string;\n          }\n        | {\n            type: 'inline-check' | 'radio' | 'inline-radio' | 'select' | 'multi-select';\n            /** @see https://storybook.js.org/docs/api/arg-types#controllabels */\n            labels?: { [options: string]: string };\n          }\n        | {\n            type: 'number' | 'range';\n            /** @see https://storybook.js.org/docs/api/arg-types#controlmax */\n            max?: number;\n            /** @see https://storybook.js.org/docs/api/arg-types#controlmin */\n            min?: number;\n            /** @see https://storybook.js.org/docs/api/arg-types#controlstep */\n            step?: number;\n          }\n      ));\n\nexport interface InputType {\n  /** @see https://storybook.js.org/docs/api/arg-types#control */\n  control?: Control;\n  /** @see https://storybook.js.org/docs/api/arg-types#description */\n  description?: string;\n  /** @see https://storybook.js.org/docs/api/arg-types#if */\n  if?: Conditional;\n  /** @see https://storybook.js.org/docs/api/arg-types#mapping */\n  mapping?: { [key: string]: any };\n  /** @see https://storybook.js.org/docs/api/arg-types#name */\n  name?: string;\n  /** @see https://storybook.js.org/docs/api/arg-types#options */\n  options?: readonly any[];\n  /** @see https://storybook.js.org/docs/api/arg-types#table */\n  table?: {\n    [key: string]: unknown;\n    /** @see https://storybook.js.org/docs/api/arg-types#tablecategory */\n    category?: string;\n    /** @see https://storybook.js.org/docs/api/arg-types#tabledefaultvalue */\n    defaultValue?: { summary?: string | undefined; detail?: string | undefined };\n    /** @see https://storybook.js.org/docs/api/arg-types#tabledisable */\n    disable?: boolean;\n    /** @see https://storybook.js.org/docs/api/arg-types#tablesubcategory */\n    subcategory?: string;\n    /** @see https://storybook.js.org/docs/api/arg-types#tabletype */\n    type?: { summary?: string | undefined; detail?: string | undefined };\n  };\n  /** @see https://storybook.js.org/docs/api/arg-types#type */\n  type?: SBType | SBScalarType['name'];\n  /**\n   * @deprecated Use `table.defaultValue.summary` instead.\n   * @see https://storybook.js.org/docs/api/arg-types#defaultvalue\n   */\n  defaultValue?: any;\n  [key: string]: any;\n}\n\nexport interface StrictInputType extends InputType {\n  name: string;\n  type?: SBType;\n}\n\nexport interface Args {\n  [name: string]: any;\n}\n\nexport interface StrictArgs {\n  [name: string]: unknown;\n}\n\n/** @see https://storybook.js.org/docs/api/arg-types#argtypes */\nexport type ArgTypes<TArgs = Args> = { [name in keyof TArgs]: InputType };\nexport type StrictArgTypes<TArgs = Args> = { [name in keyof TArgs]: StrictInputType };\n\nexport interface Globals {\n  [name: string]: any;\n}\nexport interface GlobalTypes {\n  [name: string]: ToolbarArgType;\n}\n\n/**\n * AddonTypes allows addons to extend the type system with additional args, parameters, and globals.\n *\n * Addons can use `definePreviewAddon<AddonTypes>()` to declare additional types that will be merged\n * into the story context. For example, an addon that provides a `theme` arg could declare:\n *\n * ```ts\n * const themeAddon = definePreviewAddon<{ args: { theme: 'light' | 'dark' } }>({\n *   decorators: [(Story, { args }) => <ThemeProvider theme={args.theme}><Story /></ThemeProvider>]\n * });\n * ```\n *\n * When users include this addon in their preview config, the `theme` arg becomes available and\n * type-checked across all stories.\n */\nexport interface AddonTypes {\n  args?: unknown;\n  parameters?: Record<string, any>;\n  globals?: Record<string, any>;\n}\n\nexport interface Renderer extends AddonTypes {\n  /** What is the type of the `component` annotation in this renderer? */\n  component: any;\n\n  /** What does the story function return in this renderer? */\n  storyResult: any;\n\n  /** What type of element does this renderer render to? */\n  canvasElement: any;\n\n  mount(): Promise<Canvas>;\n\n  // A generic type T that can be used in the definition of the component like this:\n  // component: (args: this['T']) => string;\n  // This generic type will eventually be filled in with TArgs\n  // Credits to Michael Arnaldi.\n  T?: unknown;\n\n  args: unknown;\n\n  csf4: boolean;\n}\n\n/** @deprecated - Use `Renderer` */\nexport type AnyFramework = Renderer;\n\nexport interface StoryContextForEnhancers<\n  TRenderer extends Renderer = Renderer,\n  TArgs = Args,\n> extends StoryIdentifier {\n  component?: (TRenderer & { T: any })['component'];\n  subcomponents?: Record<string, (TRenderer & { T: any })['component']>;\n  parameters: Parameters;\n  initialArgs: TArgs;\n  argTypes: StrictArgTypes<TArgs>;\n}\n\nexport type ArgsEnhancer<TRenderer extends Renderer = Renderer, TArgs = Args> = (\n  context: StoryContextForEnhancers<TRenderer, TArgs>\n) => TArgs;\nexport type ArgTypesEnhancer<TRenderer extends Renderer = Renderer, TArgs = Args> = ((\n  context: StoryContextForEnhancers<TRenderer, TArgs>\n) => StrictArgTypes<TArgs>) & {\n  secondPass?: boolean;\n};\n\nexport interface StoryContextUpdate<TArgs = Args> {\n  args?: TArgs;\n  globals?: Globals;\n  // NOTE: it is currently possibly to add *any* key you like to the context\n  // (although you cannot override the basic keys). This will likely be removed in future.\n  [key: string]: any;\n}\n\nexport type ViewMode = 'story' | 'docs';\n\nexport type LoaderFunction<TRenderer extends Renderer = Renderer, TArgs = Args> = (\n  context: StoryContextForLoaders<TRenderer, TArgs>\n) => Promise<Record<string, any> | void> | Record<string, any> | void;\n\ntype Awaitable<T> = T | PromiseLike<T>;\nexport type CleanupCallback = () => Awaitable<unknown>;\n\nexport type BeforeAll = () => Awaitable<CleanupCallback | void>;\n\nexport type BeforeEach<TRenderer extends Renderer = Renderer, TArgs = Args> = (\n  context: StoryContext<TRenderer, TArgs>\n) => Awaitable<CleanupCallback | void>;\n\nexport type AfterEach<TRenderer extends Renderer = Renderer, TArgs = Args> = (\n  context: StoryContext<TRenderer, TArgs>\n) => Awaitable<void>;\n\nexport interface Canvas {}\n\nexport interface StoryContext<TRenderer extends Renderer = Renderer, TArgs = Args>\n  extends StoryContextForEnhancers<TRenderer, TArgs>, Required<StoryContextUpdate<TArgs>> {\n  loaded: Record<string, any>;\n  abortSignal: AbortSignal;\n  canvasElement: TRenderer['canvasElement'];\n  hooks: unknown;\n  originalStoryFn: ArgsStoryFn<TRenderer>;\n  viewMode: ViewMode;\n  step: StepFunction<TRenderer, TArgs>;\n  context: this;\n  canvas: Canvas;\n  mount: TRenderer['mount'];\n  reporting: ReportingAPI;\n}\n\n/** @deprecated Use {@link StoryContext} instead. */\nexport interface StoryContextForLoaders<\n  TRenderer extends Renderer = Renderer,\n  TArgs = Args,\n> extends StoryContext<TRenderer, TArgs> {}\n\n/** @deprecated Use {@link StoryContext} instead. */\nexport interface PlayFunctionContext<\n  TRenderer extends Renderer = Renderer,\n  TArgs = Args,\n> extends StoryContext<TRenderer, TArgs> {}\n\nexport type StepLabel = string;\n\nexport type StepFunction<TRenderer extends Renderer = Renderer, TArgs = Args> = (\n  label: StepLabel,\n  play: PlayFunction<TRenderer, TArgs>\n) => Promise<void> | void;\n\nexport type PlayFunction<TRenderer extends Renderer = Renderer, TArgs = Args> = (\n  context: PlayFunctionContext<TRenderer, TArgs>\n) => Promise<void> | void;\n\nexport type TestFunction<TRenderer extends Renderer = Renderer, TArgs = TRenderer['args']> = (\n  context: StoryContext<TRenderer, TArgs>\n) => Promise<void> | void;\n\n// This is the type of story function passed to a decorator -- does not rely on being passed any context\nexport type PartialStoryFn<TRenderer extends Renderer = Renderer, TArgs = Args> = (\n  update?: StoryContextUpdate<Partial<TArgs>>\n) => TRenderer['storyResult'];\n\n// This is a passArgsFirst: false user story function\nexport type LegacyStoryFn<TRenderer extends Renderer = Renderer, TArgs = Args> = (\n  context: StoryContext<TRenderer, TArgs>\n) => TRenderer['storyResult'];\n\n// This is a passArgsFirst: true user story function\nexport type ArgsStoryFn<TRenderer extends Renderer = Renderer, TArgs = Args> = (\n  args: TArgs,\n  context: StoryContext<TRenderer, TArgs>\n) => (TRenderer & { T: TArgs })['storyResult'];\n\n// This is either type of user story function\nexport type StoryFn<TRenderer extends Renderer = Renderer, TArgs = Args> =\n  | LegacyStoryFn<TRenderer, TArgs>\n  | ArgsStoryFn<TRenderer, TArgs>;\n\nexport type DecoratorFunction<TRenderer extends Renderer = Renderer, TArgs = Args> = (\n  fn: PartialStoryFn<TRenderer, TArgs>,\n  c: StoryContext<TRenderer, TArgs>\n) => TRenderer['storyResult'];\n\nexport type DecoratorApplicator<TRenderer extends Renderer = Renderer, TArgs = Args> = (\n  storyFn: LegacyStoryFn<TRenderer, TArgs>,\n  decorators: DecoratorFunction<TRenderer, TArgs>[]\n) => LegacyStoryFn<TRenderer, TArgs>;\n\nexport type StepRunner<TRenderer extends Renderer = Renderer, TArgs = Args> = (\n  label: StepLabel,\n  play: PlayFunction<TRenderer, TArgs>,\n  context: StoryContext<TRenderer, TArgs>\n) => Promise<void>;\n\nexport interface BaseAnnotations<TRenderer extends Renderer = Renderer, TArgs = Args> {\n  /**\n   * Wrapper components or Storybook decorators that wrap a story.\n   *\n   * Decorators defined in Meta will be applied to every story variation.\n   *\n   * @see [Decorators](https://storybook.js.org/docs/writing-stories/decorators)\n   */\n  decorators?:\n    | DecoratorFunction<TRenderer, Simplify<TArgs>>[]\n    | DecoratorFunction<TRenderer, Simplify<TArgs>>;\n\n  /**\n   * Custom metadata for a story.\n   *\n   * @see [Parameters](https://storybook.js.org/docs/writing-stories/parameters)\n   */\n  parameters?: Parameters &\n    (TRenderer['csf4'] extends true ? CoreTypes['parameters'] & TRenderer['parameters'] : unknown);\n\n  /**\n   * Dynamic data that are provided (and possibly updated by) Storybook and its addons.\n   *\n   * @see [Args](https://storybook.js.org/docs/writing-stories/args)\n   */\n  args?: Partial<TArgs>;\n\n  /**\n   * ArgTypes encode basic metadata for args, such as `name`, `description`, `defaultValue` for an\n   * arg. These get automatically filled in by Storybook Docs.\n   *\n   * @see [ArgTypes](https://storybook.js.org/docs/api/arg-types)\n   */\n  argTypes?: Partial<ArgTypes<TArgs>>;\n\n  /**\n   * Asynchronous functions which provide data for a story.\n   *\n   * @see [Loaders](https://storybook.js.org/docs/writing-stories/loaders)\n   */\n  loaders?: LoaderFunction<TRenderer, TArgs>[] | LoaderFunction<TRenderer, TArgs>;\n\n  /**\n   * Function to be called before each story. When the function is async, it will be awaited.\n   *\n   * `beforeEach` can be added to preview, the default export and to a specific story. They are run\n   * (and awaited) in the order: preview, default export, story\n   *\n   * A cleanup function can be returned.\n   */\n  beforeEach?: BeforeEach<TRenderer, TArgs>[] | BeforeEach<TRenderer, TArgs>;\n\n  /**\n   * Function to be called after each play function for post-test assertions. Don't use this\n   * function for cleaning up state. You can use the return callback of `beforeEach` for that, which\n   * is run when switching stories. When the function is async, it will be awaited.\n   *\n   * `afterEach` can be added to preview, the default export and to a specific story. They are run\n   * (and awaited) reverse order: preview, default export, story\n   */\n  afterEach?: AfterEach<TRenderer, TArgs>[] | AfterEach<TRenderer, TArgs>;\n\n  /**\n   * Define a custom render function for the story(ies). If not passed, a default render function by\n   * the renderer will be used.\n   */\n  render?: ArgsStoryFn<TRenderer, TArgs>;\n\n  /** Named tags for a story, used to filter stories in different contexts. */\n  tags?: Tag[];\n\n  mount?: (context: StoryContext<TRenderer, TArgs>) => TRenderer['mount'];\n}\n\nexport interface ProjectAnnotations<\n  TRenderer extends Renderer = Renderer,\n  TArgs = Args,\n> extends BaseAnnotations<TRenderer, TArgs> {\n  argsEnhancers?: ArgsEnhancer<TRenderer, Args>[];\n  argTypesEnhancers?: ArgTypesEnhancer<TRenderer, Args>[];\n\n  /**\n   * Lifecycle hook which runs once, before any loaders, decorators or stories, and may rerun when\n   * configuration changes or when reinitializing (e.g. between test runs). The function may be\n   * synchronous or asynchronous, and may return a cleanup function which may also be synchronous or\n   * asynchronous. The cleanup function is not guaranteed to run (e.g. when the browser closes), but\n   * runs when configuration changes or when reinitializing. This hook may only be defined globally\n   * (i.e. not on component or story level). When multiple hooks are specified, they are to be\n   * executed sequentially (and awaited) in the following order:\n   *\n   * - Addon hooks (in order of addons array in e.g. .storybook/main.js)\n   * - Annotation hooks (in order of previewAnnotations array in e.g. .storybook/main.js)\n   * - Preview hook (via e.g. .storybook/preview.js) Cleanup functions are executed sequentially in\n   *   reverse order of initialization.\n   */\n  beforeAll?: BeforeAll;\n\n  initialGlobals?: Globals &\n    (TRenderer['csf4'] extends true ? CoreTypes['globals'] & TRenderer['globals'] : unknown);\n  globalTypes?: GlobalTypes;\n  applyDecorators?: DecoratorApplicator<TRenderer, Args>;\n  runStep?: StepRunner<TRenderer, TArgs>;\n}\n\ntype StoryDescriptor = string[] | RegExp;\nexport interface ComponentAnnotations<\n  TRenderer extends Renderer = Renderer,\n  TArgs = Args,\n> extends BaseAnnotations<TRenderer, TArgs> {\n  /**\n   * Title of the component which will be presented in the navigation. **Should be unique.**\n   *\n   * Components can be organized in a nested structure using \"/\" as a separator.\n   *\n   * Since CSF 3.0 this property is optional -- it can be inferred from the filesystem path\n   *\n   * @example Export default { ... title: 'Design System/Atoms/Button' }\n   *\n   * @see [Story Hierarchy](https://storybook.js.org/docs/writing-stories/naming-components-and-hierarchy#structure-and-hierarchy)\n   */\n  title?: ComponentTitle;\n\n  /**\n   * Id of the component (prefix of the story id) which is used for URLs.\n   *\n   * By default is inferred from sanitizing the title\n   *\n   * @see [Permalink to stories](https://storybook.js.org/docs/configure/sidebar-and-urls#permalink-to-stories)\n   */\n  id?: ComponentId;\n\n  /**\n   * Used to only include certain named exports as stories. Useful when you want to have non-story\n   * exports such as mock data or ignore a few stories.\n   *\n   * @example IncludeStories: ['SimpleStory', 'ComplexStory'] includeStories: /.*Story$/\n   *\n   * @see [Non-story exports](https://storybook.js.org/docs/api/csf#non-story-exports)\n   */\n  includeStories?: StoryDescriptor;\n\n  /**\n   * Used to exclude certain named exports. Useful when you want to have non-story exports such as\n   * mock data or ignore a few stories.\n   *\n   * @example ExcludeStories: ['simpleData', 'complexData'] excludeStories: /.*Data$/\n   *\n   * @see [Non-story exports](https://storybook.js.org/docs/api/csf#non-story-exports)\n   */\n  excludeStories?: StoryDescriptor;\n\n  /**\n   * The primary component for your story.\n   *\n   * Used by addons for automatic prop table generation and display of other component metadata.\n   */\n  component?: (TRenderer & {\n    // We fall back to `any` when TArgs is missing (and so TArgs will be Args).\n    // We also fallback to `any` for any other \"top\" type (Record<string, any>, Record<string, unknown>, any, unknown).\n    // This is because you can not assign Component with more specific props, to a Component that accepts anything\n\n    // For example this won't compile\n    // const Button: FC<Args> = (props: {prop: number} ) => {}\n    //\n    // Note that the subtyping relationship is inversed for T and (t: T) => any. As this is fine:\n    // const args: Args = { prop: 1 };\n    // The correct way would probably to fall back to `never`, being the inverse of unknown. Or maybe `Record<string, never>`\n    //\n    // Any is really weird as it pretends to be never and unknown at the same time (so being the absolute bottom and top type at the same time)\n    // However, I don't have the guts to fallback to Record<string, never>, forgive me.\n    //\n    // If this all doesn't make sense, you may want to look at the test: You can assign a component to Meta, even when you pass a top type.\n    T: Record<string, unknown> extends Required<TArgs> ? any : TArgs;\n  })['component'];\n\n  /**\n   * Auxiliary subcomponents that are part of the stories.\n   *\n   * Used by addons for automatic prop table generation and display of other component metadata.\n   *\n   * @example Import { Button, ButtonGroup } from './components';\n   *\n   * Export default { ... subcomponents: { Button, ButtonGroup } }\n   *\n   * By defining them each component will have its tab in the args table.\n   */\n  subcomponents?: Record<string, (TRenderer & { T: any })['component']>;\n\n  /** Function that is executed after the story is rendered. */\n  play?: PlayFunction<TRenderer, TArgs>;\n\n  /** Override the globals values for all stories in this component */\n  globals?: Globals &\n    (TRenderer['csf4'] extends true ? CoreTypes['globals'] & TRenderer['globals'] : unknown);\n}\n\nexport type StoryAnnotations<\n  TRenderer extends Renderer = Renderer,\n  TArgs = Args,\n  TRequiredArgs = Partial<TArgs>,\n> = BaseAnnotations<TRenderer, TArgs> & {\n  /** Override the display name in the UI (CSF v3) */\n  name?: StoryName;\n\n  /** Override the display name in the UI (CSF v2) */\n  storyName?: StoryName;\n\n  /** Function that is executed after the story is rendered. */\n  play?: PlayFunction<TRenderer, TArgs>;\n\n  /** Override the globals values for this story */\n  globals?: Globals &\n    (TRenderer['csf4'] extends true ? CoreTypes['globals'] & TRenderer['globals'] : unknown);\n\n  /** @deprecated */\n  story?: Omit<StoryAnnotations<TRenderer, TArgs>, 'story'>;\n} & ({} extends TRequiredArgs ? { args?: TRequiredArgs } : { args: TRequiredArgs });\n\nexport type LegacyAnnotatedStoryFn<TRenderer extends Renderer = Renderer, TArgs = Args> = StoryFn<\n  TRenderer,\n  TArgs\n> &\n  StoryAnnotations<TRenderer, TArgs>;\n\nexport type LegacyStoryAnnotationsOrFn<TRenderer extends Renderer = Renderer, TArgs = Args> =\n  | LegacyAnnotatedStoryFn<TRenderer, TArgs>\n  | StoryAnnotations<TRenderer, TArgs>;\n\nexport type AnnotatedStoryFn<TRenderer extends Renderer = Renderer, TArgs = Args> = ArgsStoryFn<\n  TRenderer,\n  TArgs\n> &\n  StoryAnnotations<TRenderer, TArgs>;\n\nexport type StoryAnnotationsOrFn<TRenderer extends Renderer = Renderer, TArgs = Args> =\n  | AnnotatedStoryFn<TRenderer, TArgs>\n  | StoryAnnotations<TRenderer, TArgs>;\n\nexport type ArgsFromMeta<TRenderer extends Renderer, Meta> = Meta extends {\n  render?: ArgsStoryFn<TRenderer, infer RArgs>;\n  loaders?: (infer Loaders)[] | (infer Loaders);\n  decorators?: (infer Decorators)[] | (infer Decorators);\n}\n  ? Simplify<\n      RemoveIndexSignature<\n        RArgs & DecoratorsArgs<TRenderer, Decorators> & LoaderArgs<TRenderer, Loaders>\n      >\n    >\n  : unknown;\n\ntype DecoratorsArgs<TRenderer extends Renderer, Decorators> = UnionToIntersection<\n  Decorators extends DecoratorFunction<TRenderer, infer TArgs> ? TArgs : unknown\n>;\n\ntype LoaderArgs<TRenderer extends Renderer, Loaders> = UnionToIntersection<\n  Loaders extends LoaderFunction<TRenderer, infer TArgs> ? TArgs : unknown\n>;\n"
  },
  {
    "path": "code/core/src/csf/toStartCaseStr.test.ts",
    "content": "import { expect, test } from 'vitest';\n\nimport { toStartCaseStr } from './toStartCaseStr.ts';\n\ntest.each([\n  ['snake_case', 'Snake Case'],\n  ['AAAaaaAAAaaa', 'AA Aaaa AA Aaaa'],\n  ['kebab-case', 'Kebab Case'],\n  ['camelCase', 'Camel Case'],\n  ['camelCase1', 'Camel Case 1'],\n  ['camelCase1a', 'Camel Case 1 A'],\n  ['camelCase1A', 'Camel Case 1 A'],\n  ['camelCase1A2', 'Camel Case 1 A 2'],\n  ['camelCase1A2b', 'Camel Case 1 A 2 B'],\n  ['camelCase1A2B', 'Camel Case 1 A 2 B'],\n  ['camelCase1A2B3', 'Camel Case 1 A 2 B 3'],\n  ['__FOOBAR__', 'FOOBAR'],\n  ['__FOO_BAR__', 'FOO BAR'],\n  ['__FOO__BAR__', 'FOO BAR'],\n  [' FOO BAR', 'FOO BAR'],\n  ['1. Fooo', '1 Fooo'],\n  ['ZIndex', 'Z Index'],\n])('%s', (str, expected) => {\n  const outcome = toStartCaseStr(str);\n  expect(outcome).toEqual(expected);\n});\n"
  },
  {
    "path": "code/core/src/csf/toStartCaseStr.ts",
    "content": "export function toStartCaseStr(str: string) {\n  return str\n    .replace(/_/g, ' ')\n    .replace(/-/g, ' ')\n    .replace(/\\./g, ' ')\n    .replace(/([^\\n])([A-Z])([a-z])/g, (str2, $1, $2, $3) => `${$1} ${$2}${$3}`)\n    .replace(/([a-z])([A-Z])/g, (str2, $1, $2) => `${$1} ${$2}`)\n    .replace(/([a-z])([0-9])/gi, (str2, $1, $2) => `${$1} ${$2}`)\n    .replace(/([0-9])([a-z])/gi, (str2, $1, $2) => `${$1} ${$2}`)\n    .replace(/(\\s|^)(\\w)/g, (str2, $1, $2) => `${$1}${$2.toUpperCase()}`)\n    .replace(/ +/g, ' ')\n    .trim();\n}\n"
  },
  {
    "path": "code/core/src/csf-tools/ConfigFile.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { babelPrint } from 'storybook/internal/babel';\n\nimport { dedent } from 'ts-dedent';\n\nimport { loadConfig, printConfig } from './ConfigFile.ts';\n\nexpect.addSnapshotSerializer({\n  serialize: (val: any) => (typeof val === 'string' ? val : val.toString()),\n  test: (val) => true,\n});\n\nconst getField = (path: string[], source: string) => {\n  const config = loadConfig(source).parse();\n  return config.getFieldValue(path);\n};\n\nconst setField = (path: string[], value: any, source: string) => {\n  const config = loadConfig(source).parse();\n  config.setFieldValue(path, value);\n  return printConfig(config).code;\n};\n\nconst appendToArray = (path: string[], value: any, source: string) => {\n  const config = loadConfig(source).parse();\n  config.appendValueToArray(path, value);\n  return printConfig(config).code;\n};\n\nconst removeField = (path: string[], source: string) => {\n  const config = loadConfig(source).parse();\n  config.removeField(path);\n  return printConfig(config).code;\n};\n\ndescribe('ConfigFile', () => {\n  describe('getField', () => {\n    describe('named exports', () => {\n      it('missing export', () => {\n        expect(\n          getField(\n            ['core', 'builder'],\n            dedent`\n            export const foo = { builder: 'webpack5' }\n            `\n          )\n        ).toBeUndefined();\n      });\n      it('missing field', () => {\n        expect(\n          getField(\n            ['core', 'builder'],\n            dedent`\n            export const core = { foo: 'webpack5' }\n            `\n          )\n        ).toBeUndefined();\n      });\n      it('found scalar', () => {\n        expect(\n          getField(\n            ['core', 'builder'],\n            dedent`\n            export const core = { builder: 'webpack5' }\n            `\n          )\n        ).toEqual('webpack5');\n      });\n      it('found object', () => {\n        expect(\n          getField(\n            ['core', 'builder'],\n            dedent`\n            export const core = { builder: { name: 'webpack5' } }\n            `\n          )\n        ).toEqual({ name: 'webpack5' });\n      });\n      it('variable ref export', () => {\n        expect(\n          getField(\n            ['core', 'builder'],\n            dedent`\n            const coreVar = { builder: 'webpack5' };\n            export const core = coreVar;\n            `\n          )\n        ).toEqual('webpack5');\n      });\n      it('variable export', () => {\n        expect(\n          getField(\n            ['core', 'builder'],\n            dedent`\n            const coreVar = { builder: 'webpack5' };\n            export const core = coreVar;\n            `\n          )\n        ).toEqual('webpack5');\n      });\n      it('resolves values through various TS satisfies/as syntaxes', () => {\n        const syntaxes = [\n          'const coreVar = { builder: \"webpack5\" } as const; export const core = coreVar satisfies any;',\n          'const coreVar = { builder: \"webpack5\" } as const; export const core = coreVar as any;',\n          'const coreVar = { builder: \"webpack5\" } as const satisfies Record<string, unknown>; export { coreVar as core };',\n        ];\n\n        for (const source of syntaxes) {\n          expect(getField(['core', 'builder'], source)).toEqual('webpack5');\n        }\n      });\n    });\n\n    describe('module exports', () => {\n      it('missing export', () => {\n        expect(\n          getField(\n            ['core', 'builder'],\n            dedent`\n            module.exports = { foo: { builder: 'webpack5' } }\n            `\n          )\n        ).toBeUndefined();\n      });\n      it('found scalar', () => {\n        expect(\n          getField(\n            ['core', 'builder'],\n            dedent`\n            module.exports = { core: { builder: 'webpack5' } }\n            `\n          )\n        ).toEqual('webpack5');\n      });\n      it('variable ref export', () => {\n        expect(\n          getField(\n            ['core', 'builder'],\n            dedent`\n            const core = { builder: 'webpack5' };\n            module.exports = { core };\n            `\n          )\n        ).toEqual('webpack5');\n      });\n      it('variable rename', () => {\n        expect(\n          getField(\n            ['core', 'builder'],\n            dedent`\n            const coreVar = { builder: 'webpack5' };\n            module.exports = { core: coreVar };\n            `\n          )\n        ).toEqual('webpack5');\n      });\n      it('variable exports', () => {\n        expect(\n          getField(\n            ['stories'],\n            dedent`\n              import type { StorybookConfig } from '@storybook/react-webpack5';\n\n              const config: StorybookConfig = {\n                stories: [{ directory: '../src', titlePrefix: 'Demo' }],\n              }\n              module.exports = config;\n            `\n          )\n        ).toEqual([{ directory: '../src', titlePrefix: 'Demo' }]);\n      });\n    });\n\n    describe('default export', () => {\n      it('missing export', () => {\n        expect(\n          getField(\n            ['core', 'builder'],\n            dedent`\n            export default { foo: { builder: 'webpack5' } }\n            `\n          )\n        ).toBeUndefined();\n      });\n      it('found scalar', () => {\n        expect(\n          getField(\n            ['core', 'builder'],\n            dedent`\n            export default { core: { builder: 'webpack5' } }\n            `\n          )\n        ).toEqual('webpack5');\n      });\n      it('variable ref export', () => {\n        expect(\n          getField(\n            ['core', 'builder'],\n            dedent`\n            const core = { builder: 'webpack5' };\n            export default { core };\n            `\n          )\n        ).toEqual('webpack5');\n      });\n      it('variable rename', () => {\n        expect(\n          getField(\n            ['core', 'builder'],\n            dedent`\n            const coreVar = { builder: 'webpack5' };\n            export default { core: coreVar };\n            `\n          )\n        ).toEqual('webpack5');\n      });\n      it('variable exports', () => {\n        expect(\n          getField(\n            ['stories'],\n            dedent`\n              import type { StorybookConfig } from '@storybook/react-webpack5';\n\n              const config: StorybookConfig = {\n                stories: [{ directory: '../src', titlePrefix: 'Demo' }],\n              }\n              export default config;\n            `\n          )\n        ).toEqual([{ directory: '../src', titlePrefix: 'Demo' }]);\n      });\n      it('export specifier', () => {\n        expect(\n          getField(\n            ['foo'],\n            dedent`\n              const foo = 'bar';\n              export { foo };\n            `\n          )\n        ).toEqual('bar');\n      });\n      it('export aliased specifier', () => {\n        expect(\n          getField(\n            ['fooAlias'],\n            dedent`\n              const foo = 'bar';\n              export { foo as fooAlias };\n            `\n          )\n        ).toEqual('bar');\n      });\n    });\n\n    describe('factory config', () => {\n      it('parses correctly', () => {\n        const source = dedent`\n          import { definePreview } from '@storybook/react-vite';\n\n          const config = definePreview({\n            framework: 'foo',\n          });\n          export default config;\n        `;\n        const config = loadConfig(source).parse();\n        expect(config.getNameFromPath(['framework'])).toEqual('foo');\n      });\n      it('found scalar', () => {\n        expect(\n          getField(\n            ['core', 'builder'],\n            dedent`\n            import { definePreview } from '@storybook/react-vite';\n            export const foo = definePreview({ core: { builder: 'webpack5' } });\n            `\n          )\n        ).toEqual('webpack5');\n      });\n      it('tags', () => {\n        expect(\n          getField(\n            ['tags'],\n            dedent`\n              import { definePreview } from '@storybook/react-vite';\n              const parameters = {};\n              export const config = definePreview({\n                parameters,\n                tags: ['test', 'vitest', '!a11ytest'],\n              });\n            `\n          )\n        ).toEqual(['test', 'vitest', '!a11ytest']);\n      });\n      it('parses correctly with .type<T>() chaining on export default', () => {\n        const source = dedent`\n          import { definePreview } from '@storybook/react-vite';\n\n          export default definePreview({\n            parameters: {\n              foo: 'bar',\n            },\n          }).type<{\n            parameters: {\n              customParam?: string;\n            };\n          }>();\n        `;\n        const config = loadConfig(source).parse();\n        expect(config.getFieldValue(['parameters', 'foo'])).toEqual('bar');\n      });\n    });\n  });\n\n  describe('setField', () => {\n    describe('named exports', () => {\n      it('missing export', () => {\n        expect(\n          setField(\n            ['core', 'builder'],\n            'webpack5',\n            dedent`\n              export const addons = [];\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          export const addons = [];\n\n          export const core = {\n            builder: \"webpack5\"\n          };\n        `);\n      });\n      it('missing field', () => {\n        expect(\n          setField(\n            ['core', 'builder'],\n            'webpack5',\n            dedent`\n              export const core = { foo: 'bar' };\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          export const core = {\n            foo: 'bar',\n            builder: 'webpack5'\n          };\n        `);\n      });\n      it('found scalar', () => {\n        expect(\n          setField(\n            ['core', 'builder'],\n            'webpack5',\n            dedent`\n              export const core = { builder: 'webpack4' };\n            `\n          )\n        ).toMatchInlineSnapshot(`export const core = { builder: 'webpack5' };`);\n      });\n      it('found top-level scalar', () => {\n        expect(\n          setField(\n            ['foo'],\n            'baz',\n            dedent`\n              export const foo = 'bar';\n            `\n          )\n        ).toMatchInlineSnapshot(`export const foo = 'baz';`);\n      });\n      it('found object', () => {\n        expect(\n          setField(\n            ['core', 'builder'],\n            { name: 'webpack5' },\n            dedent`\n              export const core = { builder: { name: 'webpack4' } };\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          export const core = { builder: {\n            name: 'webpack5'\n          } };\n        `);\n      });\n      it('variable export', () => {\n        expect(\n          setField(\n            ['core', 'builder'],\n            'webpack5',\n            dedent`\n            const coreVar = { builder: 'webpack4' };\n            export const core = coreVar;\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          const coreVar = { builder: 'webpack5' };\n          export const core = coreVar;\n        `);\n      });\n    });\n\n    describe('module exports', () => {\n      it('missing export', () => {\n        expect(\n          setField(\n            ['core', 'builder'],\n            'webpack5',\n            dedent`\n              module.exports = { addons: [] };\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          module.exports = {\n            addons: [],\n\n            core: {\n              builder: \"webpack5\"\n            }\n          };\n        `);\n      });\n      it('missing field', () => {\n        expect(\n          setField(\n            ['core', 'builder'],\n            'webpack5',\n            dedent`\n              module.exports = { core: { foo: 'bar' }};\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          module.exports = { core: {\n            foo: 'bar',\n            builder: 'webpack5'\n          }};\n        `);\n      });\n      it('found scalar', () => {\n        expect(\n          setField(\n            ['core', 'builder'],\n            'webpack5',\n            dedent`\n              module.exports = { core: { builder: 'webpack4' } };\n            `\n          )\n        ).toMatchInlineSnapshot(`module.exports = { core: { builder: 'webpack5' } };`);\n      });\n    });\n\n    describe('default export', () => {\n      it('missing export', () => {\n        expect(\n          setField(\n            ['core', 'builder'],\n            'webpack5',\n            dedent`\n              export default { addons: [] };\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          export default {\n            addons: [],\n\n            core: {\n              builder: \"webpack5\"\n            }\n          };\n        `);\n      });\n      it('missing field', () => {\n        expect(\n          setField(\n            ['core', 'builder'],\n            'webpack5',\n            dedent`\n              export default { core: { foo: 'bar' }};\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          export default { core: {\n            foo: 'bar',\n            builder: 'webpack5'\n          }};\n        `);\n      });\n      it('found scalar', () => {\n        expect(\n          setField(\n            ['core', 'builder'],\n            'webpack5',\n            dedent`\n              export default { core: { builder: 'webpack4' } };\n            `\n          )\n        ).toMatchInlineSnapshot(`export default { core: { builder: 'webpack5' } };`);\n      });\n    });\n\n    describe('quotes', () => {\n      it('no quotes', () => {\n        expect(setField(['foo', 'bar'], 'baz', '')).toMatchInlineSnapshot(`\n          export const foo = {\n            bar: \"baz\"\n          };\n        `);\n      });\n      it('more single quotes', () => {\n        expect(setField(['foo', 'bar'], 'baz', `export const stories = ['a', 'b', \"c\"]`))\n          .toMatchInlineSnapshot(`\n          export const stories = ['a', 'b', \"c\"]\n\n          export const foo = {\n            bar: 'baz'\n          };\n        `);\n      });\n      it('more double quotes', () => {\n        expect(setField(['foo', 'bar'], 'baz', `export const stories = ['a', \"b\", \"c\"]`))\n          .toMatchInlineSnapshot(`\n          export const stories = ['a', \"b\", \"c\"]\n\n          export const foo = {\n            bar: \"baz\"\n          };\n        `);\n      });\n    });\n\n    describe('export specifiers', () => {\n      it('found object', () => {\n        expect(\n          setField(\n            ['core', 'builder'],\n            'webpack5',\n            dedent`\n              const core = { builder: 'webpack4' };\n              export { core };\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          const core = { builder: 'webpack5' };\n          export { core };\n        `);\n      });\n\n      it('sets nested field in parameters variable', () => {\n        expect(\n          setField(\n            ['parameters', 'a11y'],\n            'todo',\n            dedent`\n              const parameters = { foo: 'bar' };\n              const preview = {\n                parameters,\n              }\n              export default preview;\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          const parameters = {\n            foo: 'bar',\n            a11y: 'todo'\n          };\n          const preview = {\n            parameters,\n          }\n          export default preview;\n        `);\n      });\n\n      it('sets nested field when parameters exists as both variable and direct object', () => {\n        expect(\n          setField(\n            ['parameters', 'a11y'],\n            'todo',\n            dedent`\n              const parameters = { foo: 'bar' };\n              const preview = {\n                parameters: {},\n              }\n              export default preview;\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          const parameters = { foo: 'bar' };\n          const preview = {\n            parameters: {\n              a11y: 'todo'\n            },\n          }\n          export default preview;\n        `);\n      });\n    });\n\n    describe('factory config', () => {\n      it('missing export', () => {\n        expect(\n          setField(\n            ['core', 'builder'],\n            'webpack5',\n            dedent`\n              import { definePreview } from '@storybook/react-vite';\n              export const foo = definePreview({\n                addons: [],\n              });\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          import { definePreview } from '@storybook/react-vite';\n          export const foo = definePreview({\n            addons: [],\n\n            core: {\n              builder: 'webpack5'\n            }\n          });\n        `);\n      });\n      it('missing field', () => {\n        expect(\n          setField(\n            ['core', 'builder'],\n            'webpack5',\n            dedent`\n              import { definePreview } from '@storybook/react-vite';\n              export const foo = definePreview({\n                core: { foo: 'bar' },\n              });\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          import { definePreview } from '@storybook/react-vite';\n          export const foo = definePreview({\n            core: {\n              foo: 'bar',\n              builder: 'webpack5'\n            },\n          });\n        `);\n      });\n      it('found scalar', () => {\n        expect(\n          setField(\n            ['core', 'builder'],\n            'webpack5',\n            dedent`\n              import { definePreview } from '@storybook/react-vite';\n              export const foo = definePreview({\n                core: { builder: 'webpack4' },\n              });\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          import { definePreview } from '@storybook/react-vite';\n          export const foo = definePreview({\n            core: { builder: 'webpack5' },\n          });\n        `);\n      });\n    });\n  });\n\n  describe('appendToArray', () => {\n    it('missing export', () => {\n      expect(\n        appendToArray(\n          ['addons'],\n          'docs',\n          dedent`\n              export default { core: { builder: 'webpack5' } };\n            `\n        )\n      ).toMatchInlineSnapshot(`\n        export default {\n          core: { builder: 'webpack5' },\n          addons: ['docs']\n        };\n      `);\n    });\n    it('found scalar', () => {\n      expect(() =>\n        appendToArray(\n          ['addons'],\n          'docs',\n          dedent`\n              export default { addons: 5 };\n            `\n        )\n      ).toThrowErrorMatchingInlineSnapshot(\n        `Error: Expected array at 'addons', got 'NumericLiteral'`\n      );\n    });\n    it('array of simple values', () => {\n      expect(\n        appendToArray(\n          ['addons'],\n          'docs',\n          dedent`\n              export default { addons: ['a11y', 'viewport'] };\n            `\n        )\n      ).toMatchInlineSnapshot(`export default { addons: ['a11y', 'viewport', 'docs'] };`);\n    });\n\n    it('array of complex values', () => {\n      expect(\n        appendToArray(\n          ['addons'],\n          'docs',\n          dedent`\n              export default { addons: [require.resolve('a11y'), someVariable] };\n            `\n        )\n      ).toMatchInlineSnapshot(\n        `export default { addons: [require.resolve('a11y'), someVariable, 'docs'] };`\n      );\n    });\n  });\n\n  describe('removeField', () => {\n    describe('named exports', () => {\n      it('missing export', () => {\n        expect(\n          removeField(\n            ['core', 'builder'],\n            dedent`\n              export const addons = [];\n            `\n          )\n        ).toMatchInlineSnapshot(`export const addons = [];`);\n      });\n      it('missing field', () => {\n        expect(\n          removeField(\n            ['core', 'builder'],\n            dedent`\n              export const core = { foo: 'bar' };\n            `\n          )\n        ).toMatchInlineSnapshot(`export const core = { foo: 'bar' };`);\n      });\n      it('found scalar', () => {\n        expect(\n          removeField(\n            ['core', 'builder'],\n            dedent`\n              export const core = { builder: 'webpack4' };\n            `\n          )\n        ).toMatchInlineSnapshot(`export const core = {};`);\n      });\n      it('found object', () => {\n        expect(\n          removeField(\n            ['core', 'builder'],\n            dedent`\n              export const core = { builder: { name: 'webpack4' } };\n            `\n          )\n        ).toMatchInlineSnapshot(`export const core = {};`);\n      });\n      it('nested object', () => {\n        expect(\n          removeField(\n            ['core', 'builder', 'name'],\n            dedent`\n              export const core = { builder: { name: 'webpack4' } };\n            `\n          )\n        ).toMatchInlineSnapshot(`export const core = { builder: {} };`);\n      });\n      it('string literal key', () => {\n        expect(\n          removeField(\n            ['core', 'builder'],\n            dedent`\n              export const core = { 'builder': 'webpack4' };\n            `\n          )\n        ).toMatchInlineSnapshot(`export const core = {};`);\n      });\n      it('variable export', () => {\n        expect(\n          removeField(\n            ['core', 'builder'],\n            dedent`\n            const coreVar = { builder: 'webpack4' };\n            export const core = coreVar;\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          const coreVar = {};\n          export const core = coreVar;\n        `);\n      });\n      it('root export variable', () => {\n        expect(\n          removeField(\n            ['core'],\n            dedent`\n              export const core = { builder: { name: 'webpack4' } };\n\n              export const addons = [];\n            `\n          )\n        ).toMatchInlineSnapshot(`export const addons = [];`);\n      });\n    });\n\n    describe('module exports', () => {\n      it('missing export', () => {\n        expect(\n          removeField(\n            ['core', 'builder'],\n            dedent`\n              module.exports = { addons: [] };\n            `\n          )\n        ).toMatchInlineSnapshot(`module.exports = { addons: [] };`);\n      });\n      it('missing field', () => {\n        expect(\n          removeField(\n            ['core', 'builder'],\n            dedent`\n              module.exports = { core: { foo: 'bar' }};\n            `\n          )\n        ).toMatchInlineSnapshot(`module.exports = { core: { foo: 'bar' }};`);\n      });\n      it('found scalar', () => {\n        expect(\n          removeField(\n            ['core', 'builder'],\n            dedent`\n              module.exports = { core: { builder: 'webpack4' } };\n            `\n          )\n        ).toMatchInlineSnapshot(`module.exports = { core: {} };`);\n      });\n      it('nested scalar', () => {\n        expect(\n          removeField(\n            ['core', 'builder', 'name'],\n            dedent`\n              module.exports = { core: { builder: { name: 'webpack4' } } };\n            `\n          )\n        ).toMatchInlineSnapshot(`module.exports = { core: { builder: {} } };`);\n      });\n      it('string literal key', () => {\n        expect(\n          removeField(\n            ['core', 'builder'],\n            dedent`\n              module.exports = { 'core': { 'builder': 'webpack4' } };\n            `\n          )\n        ).toMatchInlineSnapshot(`module.exports = { 'core': {} };`);\n      });\n      it('root property', () => {\n        expect(\n          removeField(\n            ['core'],\n            dedent`\n              module.exports = { core: { builder: { name: 'webpack4' } }, addons: [] };\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          module.exports = {\n            addons: []\n          };\n        `);\n      });\n    });\n\n    describe('default export', () => {\n      it('missing export', () => {\n        expect(\n          removeField(\n            ['core', 'builder'],\n            dedent`\n              export default { addons: [] };\n            `\n          )\n        ).toMatchInlineSnapshot(`export default { addons: [] };`);\n      });\n      it('missing field', () => {\n        expect(\n          removeField(\n            ['core', 'builder'],\n            dedent`\n              export default { core: { foo: 'bar' }};\n            `\n          )\n        ).toMatchInlineSnapshot(`export default { core: { foo: 'bar' }};`);\n      });\n      it('found scalar', () => {\n        expect(\n          removeField(\n            ['core', 'builder'],\n            dedent`\n              export default { core: { builder: 'webpack4' } };\n            `\n          )\n        ).toMatchInlineSnapshot(`export default { core: {} };`);\n      });\n      it('nested scalar', () => {\n        expect(\n          removeField(\n            ['core', 'builder', 'name'],\n            dedent`\n              export default { core: { builder: { name: 'webpack4' } } };\n            `\n          )\n        ).toMatchInlineSnapshot(`export default { core: { builder: {} } };`);\n      });\n      it('string literal key', () => {\n        expect(\n          removeField(\n            ['core', 'builder'],\n            dedent`\n              export default { 'core': { 'builder': 'webpack4' } };\n            `\n          )\n        ).toMatchInlineSnapshot(`export default { 'core': {} };`);\n      });\n      it('root property', () => {\n        expect(\n          removeField(\n            ['core'],\n            dedent`\n              export default { core: { builder: { name: 'webpack4' } }, addons: [] };\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          export default {\n            addons: []\n          };\n        `);\n      });\n      it('root globals as variable', () => {\n        expect(\n          removeField(\n            ['globals'],\n            dedent`\n              const preview = { globals: { a: 1 }, bar: { a: 1 } };\n              export default preview;\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          const preview = {\n            bar: { a: 1 }\n          };\n          export default preview;\n        `);\n      });\n\n      it('root globals satsifies as variable', () => {\n        expect(\n          removeField(\n            ['globals'],\n            dedent`\n              const preview = {\n                globals: { a: 1 },\n                bar: { a: 1 }\n              } satisfies Foo;\n              export default preview;\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          const preview = {\n            bar: { a: 1 }\n          } satisfies Foo;\n          export default preview;\n        `);\n      });\n\n      it('root globals as const satisfies as variable', () => {\n        expect(\n          removeField(\n            ['globals'],\n            dedent`\n              const preview = {\n                globals: { a: 1 },\n                bar: { a: 1 }\n              } as const satisfies Foo;\n              export default preview;\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          const preview = {\n            bar: { a: 1 }\n          } as const satisfies Foo;\n          export default preview;\n        `);\n      });\n    });\n\n    describe('quotes', () => {\n      it('no quotes', () => {\n        expect(setField(['foo', 'bar'], 'baz', '')).toMatchInlineSnapshot(`\n          export const foo = {\n            bar: \"baz\"\n          };\n        `);\n      });\n      it('more single quotes', () => {\n        expect(setField(['foo', 'bar'], 'baz', `export const stories = ['a', 'b', \"c\"]`))\n          .toMatchInlineSnapshot(`\n          export const stories = ['a', 'b', \"c\"]\n\n          export const foo = {\n            bar: 'baz'\n          };\n        `);\n      });\n      it('more double quotes', () => {\n        expect(setField(['foo', 'bar'], 'baz', `export const stories = ['a', \"b\", \"c\"]`))\n          .toMatchInlineSnapshot(`\n          export const stories = ['a', \"b\", \"c\"]\n\n          export const foo = {\n            bar: \"baz\"\n          };\n        `);\n      });\n    });\n  });\n\n  describe('config helpers', () => {\n    describe('getNameFromPath', () => {\n      it(`supports string literal node`, () => {\n        const source = dedent`\n          import type { StorybookConfig } from '@storybook/react-webpack5';\n\n          const config: StorybookConfig = {\n            framework: 'foo',\n          }\n          export default config;\n        `;\n        const config = loadConfig(source).parse();\n        expect(config.getNameFromPath(['framework'])).toEqual('foo');\n      });\n\n      describe('satisfies', () => {\n        it(`supports string literal node`, () => {\n          const source = dedent`\n            import type { StorybookConfig } from '@storybook/react-webpack5';\n  \n            const config = {\n              framework: 'foo',\n            } satisfies StorybookConfig\n            export default config;\n          `;\n          const config = loadConfig(source).parse();\n          expect(config.getNameFromPath(['framework'])).toEqual('foo');\n        });\n\n        it(`supports string literal node without variables`, () => {\n          const source = dedent`\n            import type { StorybookConfig } from '@storybook/react-webpack5';\n  \n            export default {\n              framework: 'foo',\n            } satisfies StorybookConfig;\n          `;\n          const config = loadConfig(source).parse();\n          expect(config.getNameFromPath(['framework'])).toEqual('foo');\n        });\n\n        it(`supports object expression node with name property`, () => {\n          const source = dedent`\n            import type { StorybookConfig } from '@storybook/react-webpack5';\n  \n            const config = {\n              framework: { name: 'foo', options: { bar: require('baz') } },\n              \"otherField\": { \"name\": 'foo', options: { bar: require('baz') } },\n            } satisfies StorybookConfig\n            export default config;\n          `;\n          const config = loadConfig(source).parse();\n          expect(config.getNameFromPath(['framework'])).toEqual('foo');\n          expect(config.getNameFromPath(['otherField'])).toEqual('foo');\n        });\n      });\n\n      it(`supports object expression node with name property`, () => {\n        const source = dedent`\n          import type { StorybookConfig } from '@storybook/react-webpack5';\n\n          const config: StorybookConfig = {\n            framework: { name: 'foo', options: { bar: require('baz') } },\n            \"otherField\": { \"name\": 'foo', options: { bar: require('baz') } },\n          }\n          export default config;\n        `;\n        const config = loadConfig(source).parse();\n        expect(config.getNameFromPath(['framework'])).toEqual('foo');\n        expect(config.getNameFromPath(['otherField'])).toEqual('foo');\n      });\n\n      it(`supports pnp wrapped names`, () => {\n        const source = dedent`\n          import type { StorybookConfig } from '@storybook/react-webpack5';\n\n          const config: StorybookConfig = {\n            framework: getAbsolutePath('foo'),\n          }\n          export default config;\n        `;\n        const config = loadConfig(source).parse();\n        expect(config.getNameFromPath(['framework'])).toEqual('foo');\n      });\n\n      it(`returns undefined when accessing a field that does not exist`, () => {\n        const source = dedent`\n          import type { StorybookConfig } from '@storybook/react-webpack5';\n\n          const config: StorybookConfig = { }\n          export default config;\n        `;\n        const config = loadConfig(source).parse();\n        expect(config.getNameFromPath(['framework'])).toBeUndefined();\n      });\n\n      it(`throws an error when node is of unexpected type`, () => {\n        const source = dedent`\n          import type { StorybookConfig } from '@storybook/react-webpack5';\n\n          const config: StorybookConfig = {\n            framework: makesNoSense(),\n          }\n          export default config;\n        `;\n        const config = loadConfig(source).parse();\n        expect(() => config.getNameFromPath(['framework'])).toThrowError(\n          `The given node must be a string literal or an object expression with a \"name\" property that is a string literal.`\n        );\n      });\n    });\n\n    describe('getNamesFromPath', () => {\n      it(`supports an array with string literal and object expression with name property`, () => {\n        const source = dedent`\n          import type { StorybookConfig } from '@storybook/react-webpack5';\n\n          const config: StorybookConfig = {\n            addons: [\n              'foo',\n              { name: 'bar', options: {} },\n            ],\n            \"otherField\": [\n              \"foo\",\n              { \"name\": 'bar', options: {} },\n            ],\n          }\n          export default config;\n        `;\n        const config = loadConfig(source).parse();\n        expect(config.getNamesFromPath(['addons'])).toEqual(['foo', 'bar']);\n        expect(config.getNamesFromPath(['otherField'])).toEqual(['foo', 'bar']);\n      });\n\n      describe('satisfies', () => {\n        describe('default export', () => {\n          it(`supports an array with string literal and object expression with name property`, () => {\n            const source = dedent`\n              import type { StorybookConfig } from '@storybook/react-webpack5';\n    \n              const config = {\n                addons: [\n                  'foo',\n                  { name: 'bar', options: {} },\n                ],\n                \"otherField\": [\n                  \"foo\",\n                  { \"name\": 'bar', options: {} },\n                ],\n              } satisfies StorybookConfig\n              export default config;\n            `;\n            const config = loadConfig(source).parse();\n            expect(config.getNamesFromPath(['addons'])).toEqual(['foo', 'bar']);\n            expect(config.getNamesFromPath(['otherField'])).toEqual(['foo', 'bar']);\n          });\n\n          it(`supports an array with string literal and object expression with name property without variable`, () => {\n            const source = dedent`\n              import type { StorybookConfig } from '@storybook/react-webpack5';\n    \n              export default {\n                addons: [\n                  'foo',\n                  { name: 'bar', options: {} },\n                ],\n                \"otherField\": [\n                  \"foo\",\n                  { \"name\": 'bar', options: {} },\n                ],\n              } satisfies StorybookConfig;\n            `;\n            const config = loadConfig(source).parse();\n            expect(config.getNamesFromPath(['addons'])).toEqual(['foo', 'bar']);\n            expect(config.getNamesFromPath(['otherField'])).toEqual(['foo', 'bar']);\n          });\n        });\n\n        describe('module exports', () => {\n          it(`supports an array with string literal and object expression with name property`, () => {\n            const source = dedent`\n              import type { StorybookConfig } from '@storybook/react-webpack5';\n    \n              const config = {\n                addons: [\n                  'foo',\n                  { name: 'bar', options: {} },\n                ],\n                \"otherField\": [\n                  \"foo\",\n                  { \"name\": 'bar', options: {} },\n                ],\n              } satisfies StorybookConfig\n              module.exports = config;\n            `;\n            const config = loadConfig(source).parse();\n            expect(config.getNamesFromPath(['addons'])).toEqual(['foo', 'bar']);\n            expect(config.getNamesFromPath(['otherField'])).toEqual(['foo', 'bar']);\n          });\n\n          it(`supports an array with string literal and object expression with name property without variable`, () => {\n            const source = dedent`\n              import type { StorybookConfig } from '@storybook/react-webpack5';\n    \n              module.exports = {\n                addons: [\n                  'foo',\n                  { name: 'bar', options: {} },\n                ],\n                \"otherField\": [\n                  \"foo\",\n                  { \"name\": 'bar', options: {} },\n                ],\n              } satisfies StorybookConfig;\n            `;\n            const config = loadConfig(source).parse();\n            expect(config.getNamesFromPath(['addons'])).toEqual(['foo', 'bar']);\n            expect(config.getNamesFromPath(['otherField'])).toEqual(['foo', 'bar']);\n          });\n        });\n      });\n    });\n\n    it(`returns undefined when accessing a field that does not exist`, () => {\n      const source = dedent`\n        import type { StorybookConfig } from '@storybook/react-webpack5';\n\n        const config: StorybookConfig = { }\n        export default config;\n      `;\n      const config = loadConfig(source).parse();\n      expect(config.getNamesFromPath(['addons'])).toBeUndefined();\n    });\n  });\n\n  describe('setImport', () => {\n    it(`supports setting a default import for a field that does not exist`, () => {\n      const source = dedent`\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.setImport('path', 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        import path from 'path';\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n\n    it(`uses the existing node import when using node:xyz paths but the package xyz is already imported`, () => {\n      const source = dedent`\n        import { join } from 'path';\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.setImport(['dirname'], 'node:path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        import { join, dirname } from 'path';\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n\n    it(`supports setting a default import for a field that does exist`, () => {\n      const source = dedent`\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.setImport('path', 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        import path from 'path';\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n\n    it(`supports setting a named import for a field that does not exist`, () => {\n      const source = dedent`\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.setImport(['dirname'], 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        import { dirname } from 'path';\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n\n    it(`supports setting a named import for a field where the source already exists`, () => {\n      const source = dedent`\n        import { dirname } from 'path';\n\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.setImport(['dirname'], 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        import { dirname } from 'path';\n\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n\n    it(`supports setting a namespaced import`, () => {\n      const config = loadConfig('').parse();\n      config.setImport({ namespace: 'path' }, 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`import * as path from 'path';`);\n    });\n\n    it(`supports setting import without specifier`, () => {\n      const config = loadConfig('').parse();\n      config.setImport(null, 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`import 'path';`);\n    });\n  });\n\n  describe('setRequireImport', () => {\n    it(`supports setting a default import for a field that does not exist`, () => {\n      const source = dedent`\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.setRequireImport('path', 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        const path = require('path');\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n\n    it(`supports setting a default import for a field that does exist`, () => {\n      const source = dedent`\n        const path = require('path');\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.setRequireImport('path', 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        const path = require('path');\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n\n    it(`supports setting a named import for a field that does not exist`, () => {\n      const source = dedent`\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.setRequireImport(['dirname'], 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        const {\n          dirname,\n        } = require('path');\n\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n\n    it(`supports setting a named import for a field where the source already exists`, () => {\n      const source = dedent`\n        const { dirname } = require('path');\n\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.setRequireImport(['dirname', 'basename'], 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        const {\n          dirname,\n          basename,\n        } = require('path');\n\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n\n    it(`supports setting a named import for a field where the source already exists without \"node:\" prefix`, () => {\n      const source = dedent`\n        const { dirname } = require('path');\n\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.setRequireImport(['dirname', 'basename'], 'node:path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        const {\n          dirname,\n          basename,\n        } = require('path');\n\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n  });\n\n  describe('removeImport', () => {\n    it(`removes a default require import`, () => {\n      const source = dedent`\n        const path = require('path');\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.removeImport('path', 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n\n    it(`removes a default ES6 import`, () => {\n      const source = dedent`\n        import path from 'path';\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.removeImport('path', 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n\n    it(`removes a named require import`, () => {\n      const source = dedent`\n        const { dirname, basename } = require('path');\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.removeImport(['dirname'], 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        const {\n          basename,\n        } = require('path');\n        const config: StorybookConfig = { };\n        export default config;\n        `);\n    });\n\n    it(`removes a named ES6 import`, () => {\n      const source = dedent`\n        import { dirname, basename } from 'path';\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.removeImport(['dirname'], 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        import { basename } from 'path';\n        const config: StorybookConfig = { };\n        export default config;\n        `);\n    });\n\n    it(`removes multiple named require imports`, () => {\n      const source = dedent`\n        const { dirname, basename, join } = require('path');\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.removeImport(['dirname', 'basename'], 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        const {\n          join,\n        } = require('path');\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n\n    it(`removes multiple named ES6 imports`, () => {\n      const source = dedent`\n        import { dirname, basename, join } from 'path';\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.removeImport(['dirname', 'basename'], 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        import { join } from 'path';\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n\n    it(`removes a namespace ES6 import`, () => {\n      const source = dedent`\n        import * as path from 'path';\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n      const config = loadConfig(source).parse();\n      config.removeImport({ namespace: 'path' }, 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n\n    it(`preserves default import when removing a namespace ES6 import`, () => {\n      const source = dedent`\n        import path, * as alsoPath from 'path';\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n      const config = loadConfig(source).parse();\n      config.removeImport({ namespace: 'alsoPath' }, 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        import path from 'path';\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n\n    it(`removes entire require declaration when all named imports are removed`, () => {\n      const source = dedent`\n        const { dirname, basename } = require('path');\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.removeImport(['dirname', 'basename'], 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n\n    it(`removes entire ES6 declaration when all named imports are removed`, () => {\n      const source = dedent`\n        import { dirname, basename } from 'path';\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.removeImport(['dirname', 'basename'], 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n\n    it(`handles node: prefix in require imports`, () => {\n      const source = dedent`\n        const { dirname } = require('path');\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.removeImport(['dirname'], 'node:path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n\n    it(`handles node: prefix in ES6 imports`, () => {\n      const source = dedent`\n        import { dirname } from 'path';\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.removeImport(['dirname'], 'node:path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n\n    it(`does nothing when require import does not exist`, () => {\n      const source = dedent`\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.removeImport('path', 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(source);\n    });\n\n    it(`does nothing when trying to remove non-existent named require import`, () => {\n      const source = dedent`\n        const { dirname } = require('path');\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.removeImport(['nonexistent'], 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(source);\n    });\n\n    it(`does nothing when trying to remove non-existent named ES6 import`, () => {\n      const source = dedent`\n        import { dirname } from 'path';\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.removeImport(['nonexistent'], 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(source);\n    });\n\n    it(`removes ES6 import while preserving require import`, () => {\n      const source = dedent`\n        import { readFile } from 'fs';\n        const { dirname } = require('path');\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.removeImport(['readFile'], 'fs');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        const { dirname } = require('path');\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n\n    it(`removes require import while preserving ES6 import`, () => {\n      const source = dedent`\n        import { readFile } from 'fs';\n        const { dirname } = require('path');\n        const config: StorybookConfig = { };\n        export default config;\n      `;\n\n      const config = loadConfig(source).parse();\n      config.removeImport(['dirname'], 'path');\n\n      const parsed = babelPrint(config._ast);\n\n      expect(parsed).toMatchInlineSnapshot(`\n        import { readFile } from 'fs';\n        const config: StorybookConfig = { };\n        export default config;\n      `);\n    });\n  });\n\n  describe('removeEntryFromArray', () => {\n    it('removes a string literal entry', () => {\n      const source = dedent`\n        export default {\n          addons: ['a', 'b', 'c'],\n        }\n      `;\n      const config = loadConfig(source).parse();\n      config.removeEntryFromArray(['addons'], 'b');\n      expect(config.getFieldValue(['addons'])).toMatchInlineSnapshot(`a,c`);\n    });\n\n    it('removes a preset-style object entry', () => {\n      const source = dedent`\n        export default {\n          addons: ['a', { name: 'b', options: {} }, 'c'],\n        }\n      `;\n      const config = loadConfig(source).parse();\n      config.removeEntryFromArray(['addons'], 'b');\n      expect(config.getFieldValue(['addons'])).toMatchInlineSnapshot(`a,c`);\n    });\n\n    it('removes a pnp-wrapped string entry', () => {\n      const source = dedent`\n        export default {\n          addons: ['a', getAbsolutePath('b'), 'c'],\n        }\n      `;\n      const config = loadConfig(source).parse();\n      config.removeEntryFromArray(['addons'], 'b');\n      expect(config.getFieldValue(['addons'])).toMatchInlineSnapshot(`a,c`);\n    });\n\n    it('removes a pnp-wrapped object entry', () => {\n      const source = dedent`\n        export default {\n          addons: ['a',  { name: getAbsolutePath('b'), options: {} }, 'c'],\n        }\n      `;\n      const config = loadConfig(source).parse();\n      config.removeEntryFromArray(['addons'], 'b');\n      expect(config.getFieldValue(['addons'])).toMatchInlineSnapshot(`a,c`);\n    });\n\n    it('throws when entry is missing', () => {\n      const source = dedent`\n        export default {\n          addons: ['a', { name: 'b', options: {} }, 'c'],\n        }\n      `;\n      const config = loadConfig(source).parse();\n      expect(() => config.removeEntryFromArray(['addons'], 'x')).toThrowErrorMatchingInlineSnapshot(\n        `Error: Could not find 'x' in array at 'addons'`\n      );\n    });\n\n    it('throws when target array is not an arral', () => {\n      const source = dedent`\n        export default {\n          addons: {},\n        }\n      `;\n      const config = loadConfig(source).parse();\n      expect(() => config.removeEntryFromArray(['addons'], 'x')).toThrowErrorMatchingInlineSnapshot(\n        `Error: Expected array at 'addons', got 'ObjectExpression'`\n      );\n    });\n  });\n\n  describe('parse', () => {\n    it(\"export { X } with X is import { X } from 'another-file'\", () => {\n      const source = dedent`\n          import type { StorybookConfig } from '@storybook/react-webpack5';\n          import { path } from 'path';\n\n          export { path };\n\n          const config: StorybookConfig = {\n            addons: [\n              'foo',\n              { name: 'bar', options: {} },\n            ],\n            \"otherField\": [\n              \"foo\",\n              { \"name\": 'bar', options: {} },\n            ],\n          }\n          export default config;\n        `;\n      const config = loadConfig(source).parse();\n\n      expect(config._exportDecls['path']).toBe(undefined);\n      expect(config._exports['path']).toBe(undefined);\n    });\n\n    it('detects const and function export declarations', () => {\n      const source = dedent`\n        export function normalFunction() { };\n        export const value = ['@storybook/addon-essentials'];\n        export async function asyncFunction() { };\n        `;\n      const config = loadConfig(source).parse();\n\n      expect(Object.keys(config._exportDecls)).toHaveLength(3);\n    });\n\n    it('detects exports object on various TS satisfies/as export syntaxes', () => {\n      const syntaxes = [\n        'const config = { framework: \"foo\" }; export default config;',\n        'const config = { framework: \"foo\" }; export default config satisfies StorybookConfig;',\n        'const config = { framework: \"foo\" }; export default config as StorybookConfig;',\n        'const config = { framework: \"foo\" }; export default config as unknown as StorybookConfig;',\n        'export default { framework: \"foo\" };',\n        'export default { framework: \"foo\" } satisfies StorybookConfig;',\n        'export default { framework: \"foo\" } as StorybookConfig;',\n        'export default { framework: \"foo\" } as unknown as StorybookConfig;',\n      ];\n      for (const source of syntaxes) {\n        const config = loadConfig(source).parse();\n        expect(config._exportsObject?.type).toBe('ObjectExpression');\n        expect(config._exportsObject?.properties).toHaveLength(1);\n      }\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/csf-tools/ConfigFile.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\n\nimport {\n  type RecastOptions,\n  babelParse,\n  generate,\n  recast,\n  types as t,\n  traverse,\n} from 'storybook/internal/babel';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { dedent } from 'ts-dedent';\n\nimport type { PrintResultType } from './PrintResultType.ts';\n\nconst getCsfParsingErrorMessage = ({\n  expectedType,\n  foundType,\n  node,\n}: {\n  expectedType: string;\n  foundType: string | undefined;\n  node: any | undefined;\n}) => {\n  return dedent`\n      CSF Parsing error: Expected '${expectedType}' but found '${foundType}' instead in '${node?.type}'.\n    `;\n};\n\nconst propKey = (p: t.ObjectProperty) => {\n  if (t.isIdentifier(p.key)) {\n    return p.key.name;\n  }\n\n  if (t.isStringLiteral(p.key)) {\n    return p.key.value;\n  }\n  return null;\n};\n\nconst _getPath = (path: string[], node: t.Node): t.Node | undefined => {\n  if (path.length === 0) {\n    return node;\n  }\n  if (t.isObjectExpression(node)) {\n    const [first, ...rest] = path;\n    const field = (node.properties as t.ObjectProperty[]).find((p) => propKey(p) === first);\n    if (field) {\n      return _getPath(rest, (field as t.ObjectProperty).value);\n    }\n  }\n  return undefined;\n};\n\nconst _getPathProperties = (path: string[], node: t.Node): t.ObjectProperty[] | undefined => {\n  if (path.length === 0) {\n    if (t.isObjectExpression(node)) {\n      return node.properties as t.ObjectProperty[];\n    }\n    throw new Error('Expected object expression');\n  }\n  if (t.isObjectExpression(node)) {\n    const [first, ...rest] = path;\n    const field = (node.properties as t.ObjectProperty[]).find((p) => propKey(p) === first);\n    if (field) {\n      // FXIME handle spread etc.\n      if (rest.length === 0) {\n        return node.properties as t.ObjectProperty[];\n      }\n\n      return _getPathProperties(rest, (field as t.ObjectProperty).value);\n    }\n  }\n  return undefined;\n};\n\nconst _findVarDeclarator = (\n  identifier: string,\n  program: t.Program\n): t.VariableDeclarator | null | undefined => {\n  let declarator: t.VariableDeclarator | null | undefined = null;\n  let declarations: t.VariableDeclarator[] | null = null;\n\n  program.body.find((node: t.Node) => {\n    if (t.isVariableDeclaration(node)) {\n      declarations = node.declarations;\n    } else if (t.isExportNamedDeclaration(node) && t.isVariableDeclaration(node.declaration)) {\n      declarations = node.declaration.declarations;\n    }\n\n    return (\n      declarations &&\n      declarations.find((decl: t.VariableDeclarator) => {\n        if (\n          t.isVariableDeclarator(decl) &&\n          t.isIdentifier(decl.id) &&\n          decl.id.name === identifier\n        ) {\n          declarator = decl;\n          return true; // stop looking\n        }\n        return false;\n      })\n    );\n  });\n  return declarator;\n};\n\nconst _findVarInitialization = (identifier: string, program: t.Program) => {\n  const declarator = _findVarDeclarator(identifier, program);\n  return declarator?.init;\n};\n\nconst _makeObjectExpression = (path: string[], value: t.Expression): t.Expression => {\n  if (path.length === 0) {\n    return value;\n  }\n  const [first, ...rest] = path;\n  const innerExpression = _makeObjectExpression(rest, value);\n  return t.objectExpression([t.objectProperty(t.identifier(first), innerExpression)]);\n};\n\nconst _updateExportNode = (path: string[], expr: t.Expression, existing: t.ObjectExpression) => {\n  const [first, ...rest] = path;\n  const existingField = (existing.properties as t.ObjectProperty[]).find(\n    (p) => propKey(p) === first\n  ) as t.ObjectProperty;\n  if (!existingField) {\n    existing.properties.push(\n      t.objectProperty(t.identifier(first), _makeObjectExpression(rest, expr))\n    );\n  } else if (t.isObjectExpression(existingField.value) && rest.length > 0) {\n    _updateExportNode(rest, expr, existingField.value);\n  } else {\n    existingField.value = _makeObjectExpression(rest, expr);\n  }\n};\n\nexport class ConfigFile {\n  _ast: t.File;\n\n  _code: string;\n\n  _exports: Record<string, t.Expression> = {};\n\n  // FIXME: this is a hack. this is only used in the case where the user is\n  // modifying a named export that's a scalar. The _exports map is not suitable\n  // for that. But rather than refactor the whole thing, we just use this as a stopgap.\n  _exportDecls: Record<string, t.VariableDeclarator | t.FunctionDeclaration> = {};\n\n  _exportsObject: t.ObjectExpression | undefined;\n\n  _quotes: 'single' | 'double' | undefined;\n\n  fileName?: string;\n\n  hasDefaultExport = false;\n\n  constructor(ast: t.File, code: string, fileName?: string) {\n    this._ast = ast;\n    this._code = code;\n    this.fileName = fileName;\n  }\n\n  _parseExportsObject(exportsObject: t.ObjectExpression) {\n    this._exportsObject = exportsObject;\n    (exportsObject.properties as t.ObjectProperty[]).forEach((p) => {\n      const exportName = propKey(p);\n      if (exportName) {\n        const exportVal = this._resolveDeclaration(p.value as t.Node);\n        this._exports[exportName] = exportVal as t.Expression;\n      }\n    });\n  }\n\n  /** Unwraps TS assertions/satisfies from a node, to get the underlying node. */\n  _unwrap = (node: t.Node | undefined | null): any => {\n    if (t.isTSAsExpression(node) || t.isTSSatisfiesExpression(node)) {\n      return this._unwrap(node.expression);\n    }\n    return node;\n  };\n\n  /**\n   * Resolve a declaration node by unwrapping TS assertions/satisfies and following identifiers to\n   * resolve the correct node in case it's an identifier.\n   */\n  _resolveDeclaration = (node: t.Node, parent: t.Node = this._ast.program) => {\n    const decl = this._unwrap(node);\n    if (t.isIdentifier(decl) && t.isProgram(parent)) {\n      const initialization = _findVarInitialization(decl.name, parent);\n      return initialization ? this._unwrap(initialization) : decl;\n    }\n    return decl;\n  };\n\n  parse() {\n    // eslint-disable-next-line @typescript-eslint/no-this-alias\n    const self = this;\n    traverse(this._ast, {\n      ExportDefaultDeclaration: {\n        enter({ node, parent }) {\n          self.hasDefaultExport = true;\n          let decl = self._resolveDeclaration(node.declaration as t.Node, parent);\n\n          // csf factory - unwrap call expressions like definePreview({...}) or definePreview({...}).type<T>()\n          while (t.isCallExpression(decl)) {\n            if (t.isObjectExpression(decl.arguments[0])) {\n              decl = decl.arguments[0];\n              break;\n            } else if (\n              t.isMemberExpression(decl.callee) &&\n              t.isCallExpression(decl.callee.object)\n            ) {\n              decl = decl.callee.object;\n            } else {\n              break;\n            }\n          }\n\n          if (t.isObjectExpression(decl)) {\n            self._parseExportsObject(decl);\n          } else {\n            logger.warn(\n              getCsfParsingErrorMessage({\n                expectedType: 'ObjectExpression',\n                foundType: decl?.type,\n                node: decl || node.declaration,\n              })\n            );\n          }\n        },\n      },\n      ExportNamedDeclaration: {\n        enter({ node, parent }) {\n          if (t.isVariableDeclaration(node.declaration)) {\n            // export const X = ...;\n            node.declaration.declarations.forEach((decl) => {\n              if (t.isVariableDeclarator(decl) && t.isIdentifier(decl.id)) {\n                const { name: exportName } = decl.id;\n                const exportVal = self._resolveDeclaration(decl.init as t.Node, parent);\n                self._exports[exportName] = exportVal;\n                self._exportDecls[exportName] = decl;\n              }\n            });\n          } else if (t.isFunctionDeclaration(node.declaration)) {\n            // export function X() {...};\n            const decl = node.declaration;\n            if (t.isIdentifier(decl.id)) {\n              const { name: exportName } = decl.id;\n              self._exportDecls[exportName] = decl;\n            }\n          } else if (node.specifiers) {\n            // export { X };\n            node.specifiers.forEach((spec) => {\n              if (\n                t.isExportSpecifier(spec) &&\n                t.isIdentifier(spec.local) &&\n                t.isIdentifier(spec.exported)\n              ) {\n                const { name: localName } = spec.local;\n                const { name: exportName } = spec.exported;\n\n                const decl = _findVarDeclarator(localName, parent as t.Program) as any;\n                // decl can be empty in case X from `import { X } from ....` because it is not handled in _findVarDeclarator\n                if (decl) {\n                  self._exports[exportName] = self._resolveDeclaration(decl.init, parent);\n                  self._exportDecls[exportName] = decl;\n                }\n              }\n            });\n          } else {\n            logger.warn(\n              getCsfParsingErrorMessage({\n                expectedType: 'VariableDeclaration',\n                foundType: node.declaration?.type,\n                node: node.declaration,\n              })\n            );\n          }\n        },\n      },\n      ExpressionStatement: {\n        enter({ node, parent }) {\n          if (t.isAssignmentExpression(node.expression) && node.expression.operator === '=') {\n            const { left, right } = node.expression;\n            if (\n              t.isMemberExpression(left) &&\n              t.isIdentifier(left.object) &&\n              left.object.name === 'module' &&\n              t.isIdentifier(left.property) &&\n              left.property.name === 'exports'\n            ) {\n              let exportObject = right;\n              exportObject = self._resolveDeclaration(exportObject as t.Node, parent);\n\n              if (t.isObjectExpression(exportObject)) {\n                self._exportsObject = exportObject;\n                (exportObject.properties as t.ObjectProperty[]).forEach((p) => {\n                  const exportName = propKey(p);\n                  if (exportName) {\n                    const exportVal = self._resolveDeclaration(p.value as t.Node, parent);\n                    self._exports[exportName] = exportVal as t.Expression;\n                  }\n                });\n              } else {\n                logger.warn(\n                  getCsfParsingErrorMessage({\n                    expectedType: 'ObjectExpression',\n                    foundType: exportObject?.type,\n                    node: exportObject,\n                  })\n                );\n              }\n            }\n          }\n        },\n      },\n      CallExpression: {\n        enter: ({ node }) => {\n          if (\n            t.isIdentifier(node.callee) &&\n            node.callee.name === 'definePreview' &&\n            node.arguments.length === 1 &&\n            t.isObjectExpression(node.arguments[0])\n          ) {\n            self._parseExportsObject(node.arguments[0]);\n          }\n        },\n      },\n    });\n    return self;\n  }\n\n  getFieldNode(path: string[]) {\n    const [root, ...rest] = path;\n    const exported = this._exports[root];\n\n    if (!exported) {\n      return undefined;\n    }\n    return _getPath(rest, exported);\n  }\n\n  getFieldProperties(path: string[]): ReturnType<typeof _getPathProperties> {\n    const [root, ...rest] = path;\n    const exported = this._exports[root];\n\n    if (!exported) {\n      return undefined;\n    }\n    return _getPathProperties(rest, exported);\n  }\n\n  getFieldValue<T = any>(path: string[]): T | undefined {\n    const node = this.getFieldNode(path);\n    if (node) {\n      const { code } = generate(node, {});\n\n      const value = (0, eval)(`(() => (${code}))()`);\n      return value;\n    }\n    return undefined;\n  }\n\n  getSafeFieldValue(path: string[]) {\n    try {\n      return this.getFieldValue(path);\n    } catch (e) {\n      //\n    }\n    return undefined;\n  }\n\n  setFieldNode(path: string[], expr: t.Expression) {\n    const [first, ...rest] = path;\n    const exportNode = this._exports[first];\n\n    // First check if we have a direct path in the exports\n    if (this._exportsObject) {\n      const properties = this._exportsObject.properties as t.ObjectProperty[];\n      const existingProp = properties.find((p) => propKey(p) === first);\n\n      // If the property exists and is an identifier, follow the reference\n      if (existingProp && t.isIdentifier(existingProp.value)) {\n        const varDecl = _findVarDeclarator(existingProp.value.name, this._ast.program);\n        if (varDecl && t.isObjectExpression(varDecl.init)) {\n          _updateExportNode(rest, expr, varDecl.init);\n          return;\n        }\n      }\n\n      // Otherwise update the export object directly\n      _updateExportNode(path, expr, this._exportsObject);\n      this._exports[path[0]] = expr;\n      return;\n    }\n\n    if (exportNode && t.isObjectExpression(exportNode) && rest.length > 0) {\n      _updateExportNode(rest, expr, exportNode);\n      return;\n    }\n\n    // If no direct path found, try variable declarations\n    const varDecl = _findVarDeclarator(first, this._ast.program);\n    if (varDecl && t.isObjectExpression(varDecl.init)) {\n      _updateExportNode(rest, expr, varDecl.init);\n      return;\n    }\n\n    if (exportNode && rest.length === 0 && this._exportDecls[path[0]]) {\n      const decl = this._exportDecls[path[0]];\n      if (t.isVariableDeclarator(decl)) {\n        decl.init = _makeObjectExpression([], expr);\n      }\n    } else if (this.hasDefaultExport) {\n      // This means the main.js of the user has a default export that is not an object expression, therefore we can't change the AST.\n      throw new Error(\n        `Could not set the \"${path.join(\n          '.'\n        )}\" field as the default export is not an object in this file.`\n      );\n    } else {\n      // create a new named export and add it to the top level\n      const exportObj = _makeObjectExpression(rest, expr);\n      const newExport = t.exportNamedDeclaration(\n        t.variableDeclaration('const', [t.variableDeclarator(t.identifier(first), exportObj)])\n      );\n      this._exports[first] = exportObj;\n      this._ast.program.body.push(newExport);\n    }\n  }\n\n  /**\n   * @example\n   *\n   * ```ts\n   * // 1. { framework: 'framework-name' }\n   * // 2. { framework: { name: 'framework-name', options: {} }\n   * getNameFromPath(['framework']); // => 'framework-name'\n   * ```\n   *\n   * @returns The name of a node in a given path, supporting the following formats:\n   */\n\n  getNameFromPath(path: string[]): string | undefined {\n    const node = this.getFieldNode(path);\n    if (!node) {\n      return undefined;\n    }\n\n    return this._getPresetValue(node, 'name');\n  }\n\n  /**\n   * Returns an array of names of a node in a given path, supporting the following formats:\n   *\n   * @example\n   *\n   * ```ts\n   * const config = {\n   *   addons: ['first-addon', { name: 'second-addon', options: {} }],\n   * };\n   * // => ['first-addon', 'second-addon']\n   * getNamesFromPath(['addons']);\n   * ```\n   */\n  getNamesFromPath(path: string[]): string[] | undefined {\n    const node = this.getFieldNode(path);\n    if (!node) {\n      return undefined;\n    }\n\n    const pathNames: string[] = [];\n    if (t.isArrayExpression(node)) {\n      (node.elements as t.Expression[]).forEach((element) => {\n        pathNames.push(this._getPresetValue(element, 'name'));\n      });\n    }\n\n    return pathNames;\n  }\n\n  _getPnpWrappedValue(node: t.Node) {\n    if (t.isCallExpression(node)) {\n      const arg = node.arguments[0];\n      if (t.isStringLiteral(arg)) {\n        return arg.value;\n      }\n    }\n    return undefined;\n  }\n\n  /**\n   * Given a node and a fallback property, returns a **non-evaluated** string value of the node.\n   *\n   * 1. `{ node: 'value' }`\n   * 2. `{ node: { fallbackProperty: 'value' } }`\n   */\n  _getPresetValue(node: t.Node, fallbackProperty: string) {\n    let value;\n    if (t.isStringLiteral(node)) {\n      value = node.value;\n    } else if (t.isObjectExpression(node)) {\n      node.properties.forEach((prop) => {\n        // { framework: { name: 'value' } }\n        if (\n          t.isObjectProperty(prop) &&\n          t.isIdentifier(prop.key) &&\n          prop.key.name === fallbackProperty\n        ) {\n          if (t.isStringLiteral(prop.value)) {\n            value = prop.value.value;\n          } else {\n            value = this._getPnpWrappedValue(prop.value);\n          }\n        }\n\n        // { \"framework\": { \"name\": \"value\" } }\n        if (\n          t.isObjectProperty(prop) &&\n          t.isStringLiteral(prop.key) &&\n          prop.key.value === 'name' &&\n          t.isStringLiteral(prop.value)\n        ) {\n          value = prop.value.value;\n        }\n      });\n    } else if (t.isCallExpression(node)) {\n      value = this._getPnpWrappedValue(node);\n    }\n\n    if (!value) {\n      throw new Error(\n        `The given node must be a string literal or an object expression with a \"${fallbackProperty}\" property that is a string literal.`\n      );\n    }\n\n    return value;\n  }\n\n  removeField(path: string[]) {\n    const removeProperty = (properties: t.ObjectProperty[], prop: string) => {\n      const index = properties.findIndex(\n        (p) =>\n          (t.isIdentifier(p.key) && p.key.name === prop) ||\n          (t.isStringLiteral(p.key) && p.key.value === prop)\n      );\n      if (index >= 0) {\n        properties.splice(index, 1);\n      }\n    };\n    // the structure of this._exports doesn't work for this use case\n    // so we have to manually bypass it here\n    if (path.length === 1) {\n      let removedRootProperty = false;\n      // removing the root export\n      this._ast.program.body.forEach((node) => {\n        // named export\n        if (t.isExportNamedDeclaration(node) && t.isVariableDeclaration(node.declaration)) {\n          const decl = node.declaration.declarations[0];\n          if (t.isIdentifier(decl.id) && decl.id.name === path[0]) {\n            this._ast.program.body.splice(this._ast.program.body.indexOf(node), 1);\n            removedRootProperty = true;\n          }\n        }\n        // default export\n        if (t.isExportDefaultDeclaration(node)) {\n          const resolved = this._resolveDeclaration(node.declaration as t.Node);\n          if (t.isObjectExpression(resolved)) {\n            const properties = resolved.properties as t.ObjectProperty[];\n            removeProperty(properties, path[0]);\n            removedRootProperty = true;\n          }\n        }\n        // module.exports\n        if (\n          t.isExpressionStatement(node) &&\n          t.isAssignmentExpression(node.expression) &&\n          t.isMemberExpression(node.expression.left) &&\n          t.isIdentifier(node.expression.left.object) &&\n          node.expression.left.object.name === 'module' &&\n          t.isIdentifier(node.expression.left.property) &&\n          node.expression.left.property.name === 'exports' &&\n          t.isObjectExpression(node.expression.right)\n        ) {\n          const properties = node.expression.right.properties as t.ObjectProperty[];\n          removeProperty(properties, path[0]);\n          removedRootProperty = true;\n        }\n      });\n\n      if (removedRootProperty) {\n        return;\n      }\n    }\n\n    const properties = this.getFieldProperties(path) as t.ObjectProperty[];\n    if (properties) {\n      const lastPath = path.at(-1) as string;\n      removeProperty(properties, lastPath);\n    }\n  }\n\n  appendValueToArray(path: string[], value: any) {\n    const node = this.valueToNode(value);\n\n    if (node) {\n      this.appendNodeToArray(path, node);\n    }\n  }\n\n  appendNodeToArray(path: string[], node: t.Expression) {\n    const current = this.getFieldNode(path);\n    if (!current) {\n      this.setFieldNode(path, t.arrayExpression([node]));\n    } else if (t.isArrayExpression(current)) {\n      current.elements.push(node);\n    } else {\n      throw new Error(`Expected array at '${path.join('.')}', got '${current.type}'`);\n    }\n  }\n\n  /**\n   * Specialized helper to remove addons or other array entries that can either be strings or\n   * objects with a name property.\n   */\n  removeEntryFromArray(path: string[], value: string) {\n    const current = this.getFieldNode(path);\n\n    if (!current) {\n      return;\n    }\n    if (t.isArrayExpression(current)) {\n      const index = current.elements.findIndex((element) => {\n        if (t.isStringLiteral(element)) {\n          return element.value === value;\n        }\n        if (t.isObjectExpression(element)) {\n          const name = this._getPresetValue(element, 'name');\n          return name === value;\n        }\n        return this._getPnpWrappedValue(element as t.Node) === value;\n      });\n      if (index >= 0) {\n        current.elements.splice(index, 1);\n      } else {\n        throw new Error(`Could not find '${value}' in array at '${path.join('.')}'`);\n      }\n    } else {\n      throw new Error(`Expected array at '${path.join('.')}', got '${current.type}'`);\n    }\n  }\n\n  _inferQuotes() {\n    if (!this._quotes) {\n      // first 500 tokens for efficiency\n      const occurrences = (this._ast.tokens || []).slice(0, 500).reduce(\n        (acc, token) => {\n          if (token.type.label === 'string') {\n            acc[this._code[token.start]] += 1;\n          }\n          return acc;\n        },\n        { \"'\": 0, '\"': 0 }\n      );\n      this._quotes = occurrences[\"'\"] > occurrences['\"'] ? 'single' : 'double';\n    }\n    return this._quotes;\n  }\n\n  valueToNode(value: any): t.Expression | undefined {\n    const quotes = this._inferQuotes();\n    let valueNode;\n    // we do this rather than types.valueToNode because apparently\n    // babel only preserves quotes if they are parsed from the original code.\n    if (quotes === 'single') {\n      const { code } = generate(t.valueToNode(value), { jsescOption: { quotes } });\n      const program = babelParse(`const __x = ${code}`);\n      traverse(program, {\n        VariableDeclaration: {\n          enter({ node }) {\n            if (\n              node.declarations.length === 1 &&\n              t.isVariableDeclarator(node.declarations[0]) &&\n              t.isIdentifier(node.declarations[0].id) &&\n              node.declarations[0].id.name === '__x'\n            ) {\n              valueNode = node.declarations[0].init;\n            }\n          },\n        },\n      });\n    } else {\n      // double quotes is the default so we can skip all that\n      valueNode = t.valueToNode(value);\n    }\n    return valueNode;\n  }\n\n  setFieldValue(path: string[], value: any) {\n    const valueNode = this.valueToNode(value);\n    if (!valueNode) {\n      throw new Error(`Unexpected value ${JSON.stringify(value)}`);\n    }\n    this.setFieldNode(path, valueNode);\n  }\n\n  getBodyDeclarations(): t.Statement[] {\n    return this._ast.program.body;\n  }\n\n  setBodyDeclaration(declaration: t.Declaration) {\n    this._ast.program.body.push(declaration);\n  }\n\n  /**\n   * Import specifiers for a specific require import\n   *\n   * @example\n   *\n   * ```ts\n   * // const { foo } = require('bar');\n   * setRequireImport(['foo'], 'bar');\n   *\n   * // const foo = require('bar');\n   * setRequireImport('foo', 'bar');\n   * ```\n   *\n   * @param importSpecifiers - The import specifiers to set. If a string is passed in, a default\n   *   import will be set. Otherwise, an array of named imports will be set\n   * @param fromImport - The module to import from\n   */\n  setRequireImport(importSpecifier: string[] | string, fromImport: string) {\n    const requireDeclaration = this._ast.program.body.find((node) => {\n      const hasDeclaration =\n        t.isVariableDeclaration(node) &&\n        node.declarations.length === 1 &&\n        t.isVariableDeclarator(node.declarations[0]) &&\n        t.isCallExpression(node.declarations[0].init) &&\n        t.isIdentifier(node.declarations[0].init.callee) &&\n        node.declarations[0].init.callee.name === 'require' &&\n        t.isStringLiteral(node.declarations[0].init.arguments[0]) &&\n        (node.declarations[0].init.arguments[0].value === fromImport ||\n          node.declarations[0].init.arguments[0].value === fromImport.split('node:')[1]);\n      if (hasDeclaration) {\n        // @ts-expect-error the node declaration was found above already\n        fromImport = node.declarations[0].init.arguments[0].value;\n      }\n\n      return hasDeclaration;\n    }) as t.VariableDeclaration | undefined;\n\n    /**\n     * Returns true, when the given import declaration has the given import specifier\n     *\n     * @example\n     *\n     * ```ts\n     * // const { foo } = require('bar');\n     * hasImportSpecifier(declaration, 'foo');\n     * ```\n     */\n    const hasRequireSpecifier = (name: string) =>\n      t.isObjectPattern(requireDeclaration?.declarations[0].id) &&\n      requireDeclaration?.declarations[0].id.properties.find(\n        (specifier) =>\n          t.isObjectProperty(specifier) &&\n          t.isIdentifier(specifier.key) &&\n          specifier.key.name === name\n      );\n\n    /**\n     * Returns true, when the given import declaration has the given default import specifier\n     *\n     * @example\n     *\n     * ```ts\n     * // import foo from 'bar';\n     * hasImportSpecifier(declaration, 'foo');\n     * ```\n     */\n    const hasDefaultRequireSpecifier = (declaration: t.VariableDeclaration, name: string) =>\n      declaration.declarations.length === 1 &&\n      t.isVariableDeclarator(declaration.declarations[0]) &&\n      t.isIdentifier(declaration.declarations[0].id) &&\n      declaration.declarations[0].id.name === name;\n\n    // if the import specifier is a string, we're dealing with default imports\n    if (typeof importSpecifier === 'string') {\n      // If the import declaration with the given source exists\n      const addDefaultRequireSpecifier = () => {\n        this._ast.program.body.unshift(\n          t.variableDeclaration('const', [\n            t.variableDeclarator(\n              t.identifier(importSpecifier),\n              t.callExpression(t.identifier('require'), [t.stringLiteral(fromImport)])\n            ),\n          ])\n        );\n      };\n\n      if (requireDeclaration) {\n        if (!hasDefaultRequireSpecifier(requireDeclaration, importSpecifier)) {\n          // If the import declaration hasn't the specified default identifier, we add a new variable declaration\n          addDefaultRequireSpecifier();\n        }\n        // If the import declaration with the given source doesn't exist\n      } else {\n        // Add the import declaration to the top of the file\n        addDefaultRequireSpecifier();\n      }\n      // if the import specifier is an array, we're dealing with named imports\n    } else if (requireDeclaration) {\n      importSpecifier.forEach((specifier) => {\n        if (!hasRequireSpecifier(specifier)) {\n          (requireDeclaration.declarations[0].id as t.ObjectPattern).properties.push(\n            t.objectProperty(t.identifier(specifier), t.identifier(specifier), undefined, true)\n          );\n        }\n      });\n    } else {\n      this._ast.program.body.unshift(\n        t.variableDeclaration('const', [\n          t.variableDeclarator(\n            t.objectPattern(\n              importSpecifier.map((specifier) =>\n                t.objectProperty(t.identifier(specifier), t.identifier(specifier), undefined, true)\n              )\n            ),\n            t.callExpression(t.identifier('require'), [t.stringLiteral(fromImport)])\n          ),\n        ])\n      );\n    }\n  }\n\n  /**\n   * Set import specifiers for a given import statement.\n   *\n   * Does not support setting type imports (yet)\n   *\n   * @example\n   *\n   * ```ts\n   * // import { foo } from 'bar';\n   * setImport(['foo'], 'bar');\n   *\n   * // import foo from 'bar';\n   * setImport('foo', 'bar');\n   *\n   * // import * as foo from 'bar';\n   * setImport({ namespace: 'foo' }, 'bar');\n   *\n   * // import 'bar';\n   * setImport(null, 'bar');\n   * ```\n   *\n   * @param importSpecifiers - The import specifiers to set. If a string is passed in, a default\n   *   import will be set. Otherwise, an array of named imports will be set\n   * @param fromImport - The module to import from\n   */\n  setImport(importSpecifier: string[] | string | { namespace: string } | null, fromImport: string) {\n    const importDeclaration = this._ast.program.body.find((node) => {\n      const hasDeclaration =\n        t.isImportDeclaration(node) &&\n        (node.source.value === fromImport || node.source.value === fromImport.split('node:')[1]);\n\n      if (hasDeclaration) {\n        fromImport = node.source.value;\n      }\n\n      return hasDeclaration;\n    }) as t.ImportDeclaration | undefined;\n\n    const getNewImportSpecifier = (specifier: string) =>\n      t.importSpecifier(t.identifier(specifier), t.identifier(specifier));\n    /**\n     * Returns true, when the given import declaration has the given import specifier\n     *\n     * @example\n     *\n     * ```ts\n     * // import { foo } from 'bar';\n     * hasImportSpecifier(declaration, 'foo');\n     * ```\n     */\n    const hasImportSpecifier = (declaration: t.ImportDeclaration, name: string) =>\n      declaration.specifiers.find(\n        (specifier) =>\n          t.isImportSpecifier(specifier) &&\n          t.isIdentifier(specifier.imported) &&\n          specifier.imported.name === name\n      );\n\n    /**\n     * Returns true, when the given import declaration has the given default import specifier\n     *\n     * @example\n     *\n     * ```ts\n     * // import foo from 'bar';\n     * hasNamespaceImportSpecifier(declaration, 'foo');\n     * ```\n     */\n    const hasNamespaceImportSpecifier = (declaration: t.ImportDeclaration, name: string) =>\n      declaration.specifiers.find(\n        (specifier) =>\n          t.isImportNamespaceSpecifier(specifier) &&\n          t.isIdentifier(specifier.local) &&\n          specifier.local.name === name\n      );\n\n    /** Returns true when the given import declaration has a default import specifier */\n    const hasDefaultImportSpecifier = (declaration: t.ImportDeclaration, name: string) =>\n      declaration.specifiers.find(\n        (specifier) =>\n          t.isImportDefaultSpecifier(specifier) &&\n          t.isIdentifier(specifier.local) &&\n          specifier.local.name === name\n      );\n\n    // Handle side-effect imports (e.g., import 'foo')\n    if (importSpecifier === null) {\n      if (!importDeclaration) {\n        this._ast.program.body.unshift(t.importDeclaration([], t.stringLiteral(fromImport)));\n      }\n      // Handle default imports e.g. import foo from 'bar'\n    } else if (typeof importSpecifier === 'string') {\n      if (importDeclaration) {\n        if (!hasDefaultImportSpecifier(importDeclaration, importSpecifier)) {\n          importDeclaration.specifiers.push(\n            t.importDefaultSpecifier(t.identifier(importSpecifier))\n          );\n        }\n      } else {\n        this._ast.program.body.unshift(\n          t.importDeclaration(\n            [t.importDefaultSpecifier(t.identifier(importSpecifier))],\n            t.stringLiteral(fromImport)\n          )\n        );\n      }\n      // Handle named imports e.g. import { foo } from 'bar'\n    } else if (Array.isArray(importSpecifier)) {\n      if (importDeclaration) {\n        importSpecifier.forEach((specifier) => {\n          if (!hasImportSpecifier(importDeclaration, specifier)) {\n            importDeclaration.specifiers.push(getNewImportSpecifier(specifier));\n          }\n        });\n      } else {\n        this._ast.program.body.unshift(\n          t.importDeclaration(\n            importSpecifier.map(getNewImportSpecifier),\n            t.stringLiteral(fromImport)\n          )\n        );\n      }\n      // Handle namespace imports e.g. import * as foo from 'bar'\n    } else if (importSpecifier.namespace) {\n      if (importDeclaration) {\n        if (!hasNamespaceImportSpecifier(importDeclaration, importSpecifier.namespace)) {\n          importDeclaration.specifiers.push(\n            t.importNamespaceSpecifier(t.identifier(importSpecifier.namespace))\n          );\n        }\n      } else {\n        this._ast.program.body.unshift(\n          t.importDeclaration(\n            [t.importNamespaceSpecifier(t.identifier(importSpecifier.namespace))],\n            t.stringLiteral(fromImport)\n          )\n        );\n      }\n    }\n  }\n\n  _removeRequireImport(\n    importSpecifier: string[] | string | { namespace: string } | null,\n    fromImport: string\n  ) {\n    // Find require declaration first.\n    const requireDeclarationIndex = this._ast.program.body.findIndex((node) => {\n      const hasDeclaration =\n        t.isVariableDeclaration(node) &&\n        node.declarations.length === 1 &&\n        t.isVariableDeclarator(node.declarations[0]) &&\n        t.isCallExpression(node.declarations[0].init) &&\n        t.isIdentifier(node.declarations[0].init.callee) &&\n        node.declarations[0].init.callee.name === 'require' &&\n        t.isStringLiteral(node.declarations[0].init.arguments[0]) &&\n        (node.declarations[0].init.arguments[0].value === fromImport ||\n          node.declarations[0].init.arguments[0].value === fromImport.split('node:')[1]);\n\n      return hasDeclaration;\n    });\n\n    if (requireDeclarationIndex === -1) {\n      return;\n    }\n\n    const requireDeclaration = this._ast.program.body[\n      requireDeclarationIndex\n    ] as t.VariableDeclaration;\n    const declarator = requireDeclaration.declarations[0];\n\n    // Handle side-effect requires - require() statements don't have side-effect only versions like imports\n    // so we skip this case for require statements\n    if (importSpecifier === null) {\n      return;\n    }\n\n    // Handle default requires e.g. const foo = require('bar')\n    if (typeof importSpecifier === 'string') {\n      // For default requires, if the identifier matches, remove the entire declaration\n      if (t.isIdentifier(declarator.id) && declarator.id.name === importSpecifier) {\n        this._ast.program.body.splice(requireDeclarationIndex, 1);\n      }\n      return;\n    }\n\n    // require() doesn't have namespace imports so we skip this.\n    // We only allow it in our param type to keep things consistent for removeImport.\n    if (typeof importSpecifier === 'object' && 'namespace' in importSpecifier) {\n      return;\n    }\n\n    // Handle named requires e.g. const { foo, bar } = require('baz')\n    if (Array.isArray(importSpecifier) && t.isObjectPattern(declarator.id)) {\n      const objectPattern = declarator.id as t.ObjectPattern;\n      importSpecifier.forEach((specifier) => {\n        const index = objectPattern.properties.findIndex(\n          (prop) =>\n            t.isObjectProperty(prop) && t.isIdentifier(prop.key) && prop.key.name === specifier\n        );\n\n        if (index !== -1) {\n          objectPattern.properties.splice(index, 1);\n        }\n      });\n\n      // If no properties left in the destructuring, remove the entire declaration\n      if (objectPattern.properties.length === 0) {\n        this._ast.program.body.splice(requireDeclarationIndex, 1);\n      }\n    }\n  }\n\n  _removeImport(\n    importSpecifier: string[] | string | { namespace: string } | null,\n    fromImport: string\n  ) {\n    // Find import declaration first.\n    const importDeclarationIndex = this._ast.program.body.findIndex(\n      (node) =>\n        t.isImportDeclaration(node) &&\n        (node.source.value === fromImport || node.source.value === fromImport.split('node:')[1])\n    );\n    if (importDeclarationIndex === -1) {\n      return;\n    }\n    const importDeclaration = this._ast.program.body[importDeclarationIndex] as t.ImportDeclaration;\n\n    // Remove side-effect imports (e.g., import 'foo') if exact match, else do nothing.\n    if (importSpecifier === null) {\n      if (importDeclaration.specifiers.length === 0) {\n        this._ast.program.body.splice(importDeclarationIndex, 1);\n      }\n\n      return;\n    }\n\n    // From now on, remove requested specifiers from the import declaration.\n    // Handle namespace imports e.g. import * as foo from 'bar'\n    if (typeof importSpecifier === 'object' && 'namespace' in importSpecifier) {\n      const index = importDeclaration.specifiers.findIndex(\n        (specifier) =>\n          t.isImportNamespaceSpecifier(specifier) &&\n          t.isIdentifier(specifier.local) &&\n          specifier.local.name === importSpecifier.namespace\n      );\n\n      if (index !== -1) {\n        importDeclaration.specifiers.splice(index, 1);\n      }\n    }\n\n    // Handle default imports e.g. import foo from 'bar'\n    if (typeof importSpecifier === 'string') {\n      const index = importDeclaration.specifiers.findIndex(\n        (specifier) =>\n          t.isImportDefaultSpecifier(specifier) &&\n          t.isIdentifier(specifier.local) &&\n          specifier.local.name === importSpecifier\n      );\n\n      if (index !== -1) {\n        importDeclaration.specifiers.splice(index, 1);\n      }\n    }\n\n    // Handle named imports e.g. import { foo } from 'bar'\n    if (Array.isArray(importSpecifier)) {\n      importSpecifier.forEach((specifier) => {\n        const index = importDeclaration.specifiers.findIndex(\n          (current) =>\n            t.isImportSpecifier(current) &&\n            t.isIdentifier(current.imported) &&\n            current.imported.name === specifier\n        );\n\n        if (index !== -1) {\n          importDeclaration.specifiers.splice(index, 1);\n        }\n      });\n    }\n\n    // If the import declaration has no specifiers left, remove it.\n    if (importDeclaration.specifiers.length === 0) {\n      this._ast.program.body.splice(importDeclarationIndex, 1);\n    }\n  }\n\n  /**\n   * Remove import specifiers for a given import statement.\n   *\n   * Does not support removing type imports (yet)\n   *\n   * @example\n   *\n   * ```ts\n   * // import { foo } from 'bar';\n   * setImport(['foo'], 'bar');\n   *\n   * // import foo from 'bar';\n   * setImport('foo', 'bar');\n   *\n   * // import * as foo from 'bar';\n   * setImport({ namespace: 'foo' }, 'bar');\n   *\n   * // import 'bar';\n   * setImport(null, 'bar');\n   * ```\n   *\n   * @param importSpecifiers - The import specifiers to remove. If a string is passed in, will only\n   *   remove the default import. Otherwise, named imports matching the array will be removed.\n   * @param fromImport - The module to import from\n   */\n  removeImport(\n    importSpecifier: string[] | string | { namespace: string } | null,\n    fromImport: string\n  ) {\n    this._removeRequireImport(importSpecifier, fromImport);\n    this._removeImport(importSpecifier, fromImport);\n  }\n}\n\nexport const loadConfig = (code: string, fileName?: string) => {\n  const ast = babelParse(code);\n  return new ConfigFile(ast, code, fileName);\n};\n\nexport const formatConfig = (config: ConfigFile): string => {\n  return printConfig(config).code;\n};\n\nexport const printConfig = (config: ConfigFile, options: RecastOptions = {}): PrintResultType => {\n  return recast.print(config._ast, options);\n};\n\nexport const readConfig = async (fileName: string) => {\n  const code = (await readFile(fileName, 'utf-8')).toString();\n  return loadConfig(code, fileName).parse();\n};\n\nexport const writeConfig = async (config: ConfigFile, fileName?: string) => {\n  const fname = fileName || config.fileName;\n\n  if (!fname) {\n    throw new Error('Please specify a fileName for writeConfig');\n  }\n  await writeFile(fname, formatConfig(config));\n};\n\nexport const isCsfFactoryPreview = (previewConfig: ConfigFile) => {\n  const program = previewConfig._ast.program;\n  return !!program.body.find((node) => {\n    return (\n      t.isImportDeclaration(node) &&\n      node.source.value.includes('storybook') &&\n      node.specifiers.some((specifier) => {\n        return (\n          t.isImportSpecifier(specifier) &&\n          t.isIdentifier(specifier.imported) &&\n          specifier.imported.name === 'definePreview'\n        );\n      })\n    );\n  });\n};\n"
  },
  {
    "path": "code/core/src/csf-tools/CsfFile.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { logger } from 'storybook/internal/node-logger';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport yaml from 'js-yaml';\nimport { dedent } from 'ts-dedent';\n\nimport {\n  type CsfOptions,\n  formatCsf,\n  isModuleMock,\n  isValidPreviewPath,\n  loadCsf,\n} from './CsfFile.ts';\n\nexpect.addSnapshotSerializer({\n  print: (val: any) => yaml.dump(val).trimEnd(),\n  test: (val) => typeof val !== 'string' && !(val instanceof Error),\n});\n\nconst makeTitle = (userTitle?: string) => {\n  return userTitle || 'Default Title';\n};\n\nconst parse = (code: string, includeParameters?: boolean) => {\n  const { stories, meta } = loadCsf(code, { makeTitle }).parse();\n  const filtered = includeParameters ? stories : stories.map(({ parameters, ...rest }) => rest);\n  return { meta, stories: filtered };\n};\n\nconst transform = (code: string, options: Partial<CsfOptions> = { makeTitle }) => {\n  const parsed = loadCsf(code, { ...options, makeTitle }).parse();\n  return formatCsf(parsed);\n};\n\ndescribe('CsfFile', () => {\n  describe('basic', () => {\n    it('filters out non-story exports', () => {\n      const code = `\n        export default { title: 'foo/bar', excludeStories: ['invalidStory'] };\n        export const invalidStory = {};\n        export const validStory = {};\n      `;\n      const parsed = loadCsf(code, { makeTitle }).parse();\n      expect(Object.keys(parsed._stories)).toEqual(['validStory']);\n    });\n\n    it('filters out non-story exports', () => {\n      const code = `\n        export default { title: 'foo/bar', excludeStories: ['invalidStory'] };\n        export const invalidStory = {};\n        export const A = {}\n        const B = {};\n        export { B };\n      `;\n      const parsed = loadCsf(code, { makeTitle }).parse();\n      expect(Object.keys(parsed._stories)).toEqual(['A', 'B']);\n    });\n\n    it('transforms inline default exports to constant declarations', () => {\n      expect(\n        transform(\n          dedent`\n            export default { title: 'foo/bar' };\n          `,\n          { transformInlineMeta: true }\n        )\n      ).toMatchInlineSnapshot(`\n        \"const _meta = {\n          title: 'foo/bar'\n        };\n        export default _meta;\"\n      `);\n    });\n\n    it('exported const stories', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar' };\n          const A = () => {};\n          const B = (args) => {};\n          export { A, B };\n        `,\n          true\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: A\n            localName: A\n            parameters:\n              __id: foo-bar--a\n            __stats:\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n          - id: foo-bar--b\n            name: B\n            localName: B\n            parameters:\n              __id: foo-bar--b\n            __stats:\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('underscores', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar' };\n          export const __Basic__ = () => {};\n        `,\n          true\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--basic\n            name: Basic\n            parameters:\n              __isArgsStory: false\n              __id: foo-bar--basic\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('exclude stories', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar', excludeStories: ['B', 'C'] };\n          export const A = () => {};\n          export const B = (args) => {};\n          export const C = () => {};\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n          excludeStories:\n            - B\n            - C\n        stories:\n          - id: foo-bar--a\n            name: A\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('include stories', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar', includeStories: ['IncludeA'] };\n          export const SomeHelper = () => {};\n          export const IncludeA = () => {};\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n          includeStories:\n            - IncludeA\n        stories:\n          - id: foo-bar--include-a\n            name: Include A\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('storyName annotation', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar' };\n          export const A = () => {};\n          A.storyName = 'Some story';\n      `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: Some story\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('no title', () => {\n      expect(\n        parse(\n          dedent`\n          export default { component: 'foo' }\n          export const A = () => {};\n          export const B = () => {};\n      `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          component: '''foo'''\n          title: Default Title\n        stories:\n          - id: default-title--a\n            name: A\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n          - id: default-title--b\n            name: B\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('custom component id', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar', id: 'custom-id' };\n          export const A = () => {};\n          export const B = () => {};\n      `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n          id: custom-id\n        stories:\n          - id: custom-id--a\n            name: A\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n          - id: custom-id--b\n            name: B\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('custom parameters.__id', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar', id: 'custom-meta-id' };\n          export const JustCustomMetaId = {};\n          export const CustomParemetersId = { parameters: { __id: 'custom-id' } };\n      `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n          id: custom-meta-id\n        stories:\n          - id: custom-meta-id--just-custom-meta-id\n            name: Just Custom Meta Id\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n          - id: custom-id\n            name: Custom Paremeters Id\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('typescript', () => {\n      expect(\n        parse(\n          dedent`\n          import type { Meta, StoryFn } from '@storybook/react';\n          type PropTypes = {};\n          export default { title: 'foo/bar/baz' } as Meta<PropTypes>;\n          export const A: StoryFn<PropTypes> = () => <>A</>;\n          export const B: StoryFn<PropTypes> = () => <>B</>;\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar/baz\n        stories:\n          - id: foo-bar-baz--a\n            name: A\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n          - id: foo-bar-baz--b\n            name: B\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('typescript satisfies', () => {\n      expect(\n        parse(\n          dedent`\n          import type { Meta, StoryFn, StoryObj } from '@storybook/react';\n          type PropTypes = {};\n          export default { title: 'foo/bar' } satisfies Meta<PropTypes>;\n          export const A = { name: 'AA' } satisfies StoryObj<PropTypes>;\n          export const B = ((args) => {}) satisfies StoryFn<PropTypes>;\n        `,\n          true\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: AA\n            parameters:\n              __isArgsStory: true\n              __id: foo-bar--a\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n          - id: foo-bar--b\n            name: B\n            parameters:\n              __isArgsStory: true\n              __id: foo-bar--b\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('typescript as', () => {\n      expect(\n        parse(\n          dedent`\n          import type { Meta, StoryFn, StoryObj } from '@storybook/react';\n          type PropTypes = {};\n          export default { title: 'foo/bar' } as Meta<PropTypes>;\n          export const A = { name: 'AA' } as StoryObj<PropTypes>;\n          export const B = ((args) => {}) as StoryFn<PropTypes>;\n        `,\n          true\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: AA\n            parameters:\n              __isArgsStory: true\n              __id: foo-bar--a\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n          - id: foo-bar--b\n            name: B\n            parameters:\n              __isArgsStory: true\n              __id: foo-bar--b\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('typescript satisfies as', () => {\n      expect(\n        parse(\n          dedent`\n          import type { Meta, StoryFn, StoryObj } from '@storybook/react';\n          type PropTypes = {};\n          export default { title: 'foo/bar' } satisfies Meta<PropTypes> as Meta<PropTypes>;\n          export const A = { name: 'AA' } satisfies StoryObj<PropTypes>;\n          export const B = ((args) => {}) satisfies StoryFn<PropTypes>;\n        `,\n          true\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: AA\n            parameters:\n              __isArgsStory: true\n              __id: foo-bar--a\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n          - id: foo-bar--b\n            name: B\n            parameters:\n              __isArgsStory: true\n              __id: foo-bar--b\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('typescript meta var', () => {\n      expect(\n        parse(\n          dedent`\n          import type { Meta, StoryFn } from '@storybook/react';\n          type PropTypes = {};\n          const meta = { title: 'foo/bar/baz' } as Meta<PropTypes>;\n          export default meta;\n          export const A: StoryFn<PropTypes> = () => <>A</>;\n          export const B: StoryFn<PropTypes> = () => <>B</>;\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar/baz\n        stories:\n          - id: foo-bar-baz--a\n            name: A\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n          - id: foo-bar-baz--b\n            name: B\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('typescript satisfies meta var', () => {\n      expect(\n        parse(\n          dedent`\n          import type { Meta, StoryFn } from '@storybook/react';\n          type PropTypes = {};\n          const meta = { title: 'foo/bar/baz' } satisfies Meta<PropTypes>;\n          export default meta;\n          export const A: StoryFn<PropTypes> = () => <>A</>;\n          export const B: StoryFn<PropTypes> = () => <>B</>;\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar/baz\n        stories:\n          - id: foo-bar-baz--a\n            name: A\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n          - id: foo-bar-baz--b\n            name: B\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('typescript satisfies as meta', () => {\n      expect(\n        parse(\n          dedent`\n          import type { Meta, StoryFn } from '@storybook/react';\n          type PropTypes = {};\n          const meta = { title: 'foo/bar/baz' } satisfies Meta<PropTypes> as Meta<PropTypes>;\n          export default meta;\n          export const A: StoryFn<PropTypes> = () => <>A</>;\n          export const B: StoryFn<PropTypes> = () => <>B</>;\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar/baz\n        stories:\n          - id: foo-bar-baz--a\n            name: A\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n          - id: foo-bar-baz--b\n            name: B\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('typescript satisfies as stories', () => {\n      expect(\n        parse(\n          dedent`\n          import type { Meta, StoryFn, StoryObj } from '@storybook/react';\n          type PropTypes = {};\n          export default { title: 'foo/bar' } as Meta<PropTypes>;\n          export const A = { name: 'AA' } satisfies StoryObj<PropTypes> as StoryObj<PropTypes>;\n          export const B = ((args) => {}) satisfies StoryFn<PropTypes> as StoryFn<PropTypes>;\n        `,\n          true\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: AA\n            parameters:\n              __isArgsStory: true\n              __id: foo-bar--a\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n          - id: foo-bar--b\n            name: B\n            parameters:\n              __isArgsStory: true\n              __id: foo-bar--b\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('typescript satisfies as export specifier', () => {\n      expect(\n        parse(\n          dedent`\n          import type { Meta, StoryFn } from '@storybook/react';\n          type PropTypes = {};\n          const meta = { title: 'foo/bar/baz' } satisfies Meta<PropTypes> as Meta<PropTypes>;\n          const story = { name: 'Story A' };\n          export { meta as default, story as A };\n        `,\n          true\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar/baz\n        stories:\n          - id: foo-bar-baz--a\n            name: A\n            localName: story\n            parameters:\n              __id: foo-bar-baz--a\n            __stats:\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('component object', () => {\n      expect(\n        parse(\n          dedent`\n          export default { component: {} }\n          export const A = () => {};\n          export const B = () => {};\n      `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          component: '{}'\n          title: Default Title\n        stories:\n          - id: default-title--a\n            name: A\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n          - id: default-title--b\n            name: B\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('template bind', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar' };\n          const Template = (args) => { };\n          export const A = Template.bind({});\n          A.args = { x: 1 };\n        `,\n          true\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: A\n            parameters:\n              __isArgsStory: true\n              __id: foo-bar--a\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('meta variable', () => {\n      expect(\n        parse(\n          dedent`\n          const meta = { title: 'foo/bar' };\n          export default meta;\n          export const A = () => {}\n        `,\n          true\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: A\n            parameters:\n              __isArgsStory: false\n              __id: foo-bar--a\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('docs-only story', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar' };\n          export const __page = () => {};\n          __page.parameters = { docsOnly: true };\n        `,\n          true\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--page\n            name: Page\n            parameters:\n              __isArgsStory: false\n              __id: foo-bar--page\n              docsOnly: true\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('docs-only story with local vars', () => {\n      expect(\n        parse(\n          dedent`\n            export const TestControl = () => _jsx(\"p\", {\n              children: \"Hello\"\n            });\n            export default { title: 'foo/bar', includeStories: [\"__page\"] };\n            export const __page = () => {};\n            __page.parameters = { docsOnly: true };\n          `,\n          true\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n          includeStories:\n            - __page\n        stories:\n          - id: foo-bar--page\n            name: Page\n            parameters:\n              __isArgsStory: false\n              __id: foo-bar--page\n              docsOnly: true\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('title variable', () => {\n      expect(\n        parse(\n          dedent`\n            const title = 'foo/bar';\n            export default { title };\n            export const A = () => {};\n            export const B = (args) => {};\n        `,\n          true\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: A\n            parameters:\n              __isArgsStory: false\n              __id: foo-bar--a\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n          - id: foo-bar--b\n            name: B\n            parameters:\n              __isArgsStory: true\n              __id: foo-bar--b\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('re-exported stories', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar' };\n          export { default as A } from './A';\n          export { B } from './B';\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: A\n            localName: default\n            __stats:\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n          - id: foo-bar--b\n            name: B\n            localName: B\n            __stats:\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('named exports order', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar' };\n          export const A = () => {};\n          export const B = (args) => {};\n          export const __namedExportsOrder = ['B', 'A'];\n        `,\n          true\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--b\n            name: B\n            parameters:\n              __isArgsStory: true\n              __id: foo-bar--b\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n          - id: foo-bar--a\n            name: A\n            parameters:\n              __isArgsStory: false\n              __id: foo-bar--a\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('as default export', () => {\n      expect(\n        parse(\n          dedent`\n          const meta = { title: 'foo/bar' };\n          export const A = () => {};\n          export {\n            meta as default,\n            A\n          };\n        `,\n          true\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: A\n            localName: A\n            parameters:\n              __id: foo-bar--a\n            __stats:\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('support for parameter decorators', () => {\n      expect(\n        parse(dedent`\n        import { Component, Input, Output, EventEmitter, Inject, HostBinding } from '@angular/core';\n        import { CHIP_COLOR } from './chip-color.token';\n\n        @Component({\n          selector: 'storybook-chip',\n        })\n        export class ChipComponent {\n          // The error occurs on the Inject decorator used on a parameter\n          constructor(@Inject(CHIP_COLOR) chipColor: string) {\n            this.backgroundColor = chipColor;\n          }\n        }\n\n        export default {\n          title: 'Chip',\n        }\n      `)\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: Chip\n        stories: []\n      `);\n    });\n  });\n\n  describe('error handling', () => {\n    it('no meta', () => {\n      expect(() =>\n        parse(\n          dedent`\n          export const A = () => {};\n          export const B = () => {};\n      `\n        )\n      ).toThrow('CSF: missing default export');\n    });\n\n    it('bad meta', () => {\n      expect(() =>\n        parse(\n          dedent`\n          const foo = bar();\n          export default foo;\n          export const A = () => {};\n          export const B = () => {};\n      `\n        )\n      ).toThrow('CSF: default export must be an object');\n    });\n\n    it('no metadata', () => {\n      expect(\n        parse(\n          dedent`\n          export default { foo: '5' };\n          export const A = () => {};\n          export const B = () => {};\n      `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: Default Title\n        stories:\n          - id: default-title--a\n            name: A\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n          - id: default-title--b\n            name: B\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('dynamic titles', () => {\n      expect(() =>\n        parse(\n          dedent`\n            export default { title: 'foo' + 'bar' };\n            export const A = () => {};\n        `,\n          true\n        )\n      ).toThrow('CSF: unexpected dynamic title');\n    });\n\n    it('storiesOf calls', () => {\n      expect(() =>\n        parse(\n          dedent`\n            import { storiesOf } from '@storybook/react';\n            export default { title: 'foo/bar' };\n            export const A = () => {};\n            storiesOf('foo').add('bar', () => <baz />);\n        `,\n          true\n        )\n      ).toThrow('Unexpected `storiesOf` usage:');\n    });\n\n    it('function exports', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar' };\n          export function A() {}\n          export function B() {}\n      `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: A\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n          - id: foo-bar--b\n            name: B\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: true\n              mount: false\n              moduleMock: false\n      `);\n    });\n  });\n\n  // NOTE: this does not have a public API, but we can still test it\n  describe('indexed annotations', () => {\n    it('meta annotations', () => {\n      const input = dedent`\n        export default { title: 'foo/bar', x: 1, y: 2 };\n      `;\n      const csf = loadCsf(input, { makeTitle }).parse();\n      expect(Object.keys(csf._metaAnnotations)).toEqual(['title', 'x', 'y']);\n    });\n\n    it('story annotations', () => {\n      const input = dedent`\n        export default { title: 'foo/bar' };\n        export const A = () => {};\n        A.x = 1;\n        A.y = 2;\n        export const B = () => {};\n        B.z = 3;\n    `;\n      const csf = loadCsf(input, { makeTitle }).parse();\n      expect(Object.keys(csf._storyAnnotations.A)).toEqual(['x', 'y']);\n      expect(Object.keys(csf._storyAnnotations.B)).toEqual(['z']);\n    });\n\n    it('v1-style story annotations', () => {\n      const input = dedent`\n        export default { title: 'foo/bar' };\n        export const A = () => {};\n        A.story = {\n          x: 1,\n          y: 2,\n        }\n        export const B = () => {};\n        B.story = {\n          z: 3,\n        }\n    `;\n      const csf = loadCsf(input, { makeTitle }).parse();\n      expect(Object.keys(csf._storyAnnotations.A)).toEqual(['x', 'y']);\n      expect(Object.keys(csf._storyAnnotations.B)).toEqual(['z']);\n    });\n  });\n\n  describe('CSF3', () => {\n    it('Object export with no-args render', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar' };\n          export const A = {\n            render: () => {}\n          }\n        `,\n          true\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: A\n            parameters:\n              __isArgsStory: false\n              __id: foo-bar--a\n            __stats:\n              factory: false\n              play: false\n              render: true\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('Object export with args render', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar' };\n          export const A = {\n            render: (args) => {}\n          }\n        `,\n          true\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: A\n            parameters:\n              __isArgsStory: true\n              __id: foo-bar--a\n            __stats:\n              factory: false\n              play: false\n              render: true\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('Object export with args render method', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar' };\n          export const A = {\n            render(args) {}\n          }\n        `,\n          true\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: A\n            parameters:\n              __isArgsStory: true\n              __id: foo-bar--a\n            __stats:\n              factory: false\n              play: false\n              render: true\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('Object export with default render', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar' };\n          export const A = {}\n        `,\n          true\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: A\n            parameters:\n              __isArgsStory: true\n              __id: foo-bar--a\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('Object export with name', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar' };\n          export const A = {\n            name: 'Apple'\n          }\n        `,\n          true\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: Apple\n            parameters:\n              __isArgsStory: true\n              __id: foo-bar--a\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('Object export with storyName', () => {\n      const consoleWarnMock = vi.spyOn(logger, 'warn').mockImplementation(() => {});\n\n      parse(\n        dedent`\n        export default { title: 'foo/bar' };\n        export const A = {\n          storyName: 'Apple'\n        }\n      `,\n        true\n      );\n\n      expect(consoleWarnMock).toHaveBeenCalledWith(\n        'Unexpected usage of \"storyName\" in \"A\". Please use \"name\" instead.'\n      );\n      consoleWarnMock.mockRestore();\n    });\n  });\n\n  describe('import handling', () => {\n    it('imports', () => {\n      const input = dedent`\n        import Button from './Button';\n        import { Check } from './Check';\n        export default { title: 'foo/bar', x: 1, y: 2 };\n      `;\n      const csf = loadCsf(input, { makeTitle }).parse();\n      expect(csf.imports).toMatchInlineSnapshot(`\n        - ./Button\n        - ./Check\n      `);\n    });\n    it.skip('dynamic imports', () => {\n      const input = dedent`\n        const Button = await import('./Button');\n        export default { title: 'foo/bar', x: 1, y: 2 };\n      `;\n      const csf = loadCsf(input, { makeTitle }).parse();\n      expect(csf.imports).toMatchInlineSnapshot();\n    });\n    it.skip('requires', () => {\n      const input = dedent`\n        const Button = require('./Button');\n        export default { title: 'foo/bar', x: 1, y: 2 };\n      `;\n      const csf = loadCsf(input, { makeTitle }).parse();\n      expect(csf.imports).toMatchInlineSnapshot();\n    });\n  });\n\n  describe('tags', () => {\n    it('csf2', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar', tags: ['X'] };\n          export const A = () => {};\n          A.tags = ['Y'];\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n          tags:\n            - X\n        stories:\n          - id: foo-bar--a\n            name: A\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: true\n              storyFn: true\n              mount: false\n              moduleMock: false\n            tags:\n              - 'Y'\n      `);\n    });\n\n    it('csf3', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar', tags: ['X'] };\n          export const A = {\n            render: () => {},\n            tags: ['Y'],\n          };\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n          tags:\n            - X\n        stories:\n          - id: foo-bar--a\n            name: A\n            __stats:\n              factory: false\n              play: false\n              render: true\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: true\n              storyFn: false\n              mount: false\n              moduleMock: false\n            tags:\n              - 'Y'\n      `);\n    });\n\n    it('csf3 as renamed export', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar', tags: ['X'] };\n\n          const localName = {\n            render: () => {},\n            tags: ['Y']\n          };\n          export {\n            localName as exportedName,\n          };\n        `,\n          true\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n          tags:\n            - X\n        stories:\n          - id: foo-bar--exported-name\n            name: exportedName\n            localName: localName\n            parameters:\n              __id: foo-bar--exported-name\n            __stats:\n              play: false\n              render: true\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: true\n              storyFn: false\n              mount: false\n              moduleMock: false\n            tags:\n              - 'Y'\n      `);\n    });\n\n    it('variables', () => {\n      expect(\n        parse(\n          dedent`\n          const x = ['X'];\n          const y = ['Y'];\n          export default { title: 'foo/bar', tags: x };\n          export const A = {\n            render: () => {},\n            tags: y,\n          };\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n          tags:\n            - X\n        stories:\n          - id: foo-bar--a\n            name: A\n            __stats:\n              factory: false\n              play: false\n              render: true\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: true\n              storyFn: false\n              mount: false\n              moduleMock: false\n            tags:\n              - 'Y'\n      `);\n    });\n\n    it('array error', () => {\n      expect(() =>\n        parse(\n          dedent`\n            export default { title: 'foo/bar', tags: 'X' };\n            export const A = {\n              render: () => {},\n            };\n          `\n        )\n      ).toThrow('CSF: Expected tags array');\n    });\n\n    it('array element handling', () => {\n      expect(() =>\n        parse(\n          dedent`\n            export default { title: 'foo/bar', tags: [10] };\n            export const A = {\n              render: () => {},\n            };\n          `\n        )\n      ).toThrow('CSF: Expected tag to be string literal');\n    });\n  });\n\n  describe('play functions', () => {\n    it('story csf2', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar', tags: ['X'] };\n          export const A = () => {};\n          A.play = () => {};\n          A.tags = ['Y'];\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n          tags:\n            - X\n        stories:\n          - id: foo-bar--a\n            name: A\n            __stats:\n              factory: false\n              play: true\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: true\n              storyFn: true\n              mount: false\n              moduleMock: false\n            tags:\n              - 'Y'\n              - play-fn\n      `);\n    });\n\n    it('story csf3', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar', tags: ['X'] };\n          export const A = {\n            render: () => {},\n            play: () => {},\n            tags: ['Y'],\n          };\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n          tags:\n            - X\n        stories:\n          - id: foo-bar--a\n            name: A\n            __stats:\n              factory: false\n              play: true\n              render: true\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: true\n              storyFn: false\n              mount: false\n              moduleMock: false\n            tags:\n              - 'Y'\n              - play-fn\n      `);\n    });\n\n    it('play method', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar' };\n          export const A = {\n            play({ context }) {},\n          };\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: A\n            __stats:\n              factory: false\n              play: true\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n            tags:\n              - play-fn\n      `);\n    });\n\n    it('meta play method', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar', play({ context }) {} };\n          export const A = {};`\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n          tags:\n            - play-fn\n        stories:\n          - id: foo-bar--a\n            name: A\n            __stats:\n              factory: false\n              play: true\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n      `);\n    });\n\n    it('mount', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar' };\n          export const A = {\n            play: ({ mount }) => {},\n          };\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: A\n            __stats:\n              factory: false\n              play: true\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: true\n              moduleMock: false\n            tags:\n              - play-fn\n      `);\n    });\n\n    it('mount renamed', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar' };\n          export const A = {\n            play: ({ mount: mountRenamed, context }) => {},\n          };\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: A\n            __stats:\n              factory: false\n              play: true\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: true\n              moduleMock: false\n            tags:\n              - play-fn\n      `);\n    });\n\n    it('mount in method', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar' };\n          export const A = {\n            play({ mount, context }) {},\n          };\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: A\n            __stats:\n              factory: false\n              play: true\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: true\n              moduleMock: false\n            tags:\n              - play-fn\n      `);\n    });\n\n    it('mount meta', () => {\n      expect(\n        parse(\n          dedent`\n          export default {\n            title: 'foo/bar',\n            play: ({ context, mount: mountRenamed }) => {},\n          };\n          export const A = {};\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n          tags:\n            - play-fn\n        stories:\n          - id: foo-bar--a\n            name: A\n            __stats:\n              factory: false\n              play: true\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: true\n              moduleMock: false\n      `);\n    });\n\n    it('meta csf2', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar', play: () => {}, tags: ['X'] };\n          export const A = {\n            render: () => {},\n            loaders: [],\n            tags: ['Y'],\n          };\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n          tags:\n            - X\n            - play-fn\n        stories:\n          - id: foo-bar--a\n            name: A\n            __stats:\n              factory: false\n              play: true\n              render: true\n              loaders: true\n              beforeEach: false\n              globals: false\n              tags: true\n              storyFn: false\n              mount: false\n              moduleMock: false\n            tags:\n              - 'Y'\n      `);\n    });\n\n    it('meta csf3', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar', play: () => {}, tags: ['X'] };\n          export const A = () => {};\n          A.tags = ['Y'];\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n          tags:\n            - X\n            - play-fn\n        stories:\n          - id: foo-bar--a\n            name: A\n            __stats:\n              factory: false\n              play: true\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: true\n              storyFn: true\n              mount: false\n              moduleMock: false\n            tags:\n              - 'Y'\n      `);\n    });\n  });\n\n  describe('index inputs', () => {\n    it('generates index inputs', () => {\n      const { indexInputs } = loadCsf(\n        dedent`\n      export default {\n        id: 'component-id',\n        title: 'custom foo title',\n        tags: ['component-tag']\n      };\n\n      export const A = {\n        play: () => {},\n        tags: ['story-tag'],\n      };\n\n      export const B = {\n        play: () => {},\n        tags: ['story-tag'],\n      };\n    `,\n        { makeTitle, fileName: 'foo/bar.stories.js' }\n      ).parse();\n\n      expect(indexInputs).toMatchInlineSnapshot(`\n        - exportName: A\n          title: custom foo title\n          metaId: component-id\n          tags:\n            - component-tag\n            - story-tag\n            - play-fn\n          __id: component-id--a\n          __stats:\n            factory: false\n            play: true\n            render: false\n            loaders: false\n            beforeEach: false\n            globals: false\n            tags: true\n            storyFn: false\n            mount: false\n            moduleMock: false\n          type: story\n          subtype: story\n          name: A\n        - exportName: B\n          title: custom foo title\n          metaId: component-id\n          tags:\n            - component-tag\n            - story-tag\n            - play-fn\n          __id: component-id--b\n          __stats:\n            factory: false\n            play: true\n            render: false\n            loaders: false\n            beforeEach: false\n            globals: false\n            tags: true\n            storyFn: false\n            mount: false\n            moduleMock: false\n          type: story\n          subtype: story\n          name: B\n      `);\n    });\n\n    it('supports custom parameters.__id', () => {\n      const { indexInputs } = loadCsf(\n        dedent`\n      export default {\n        id: 'component-id',\n        title: 'custom foo title',\n        tags: ['component-tag']\n      };\n\n      export const A = {\n        parameters: { __id: 'custom-story-id' }\n      };\n    `,\n        { makeTitle, fileName: 'foo/bar.stories.js' }\n      ).parse();\n\n      expect(indexInputs).toMatchInlineSnapshot(`\n        - exportName: A\n          title: custom foo title\n          metaId: component-id\n          tags:\n            - component-tag\n          __id: custom-story-id\n          __stats:\n            factory: false\n            play: false\n            render: false\n            loaders: false\n            beforeEach: false\n            globals: false\n            tags: true\n            storyFn: false\n            mount: false\n            moduleMock: false\n          type: story\n          subtype: story\n          name: A\n      `);\n    });\n\n    it('removes duplicate tags', () => {\n      const { indexInputs } = loadCsf(\n        dedent`\n      export default {\n        title: 'custom foo title',\n        tags: ['component-tag', 'component-tag-dup', 'component-tag-dup', 'inherit-tag-dup']\n      };\n\n      export const A = {\n        tags: ['story-tag', 'story-tag-dup', 'story-tag-dup', 'inherit-tag-dup']\n      };\n    `,\n        { makeTitle, fileName: 'foo/bar.stories.js' }\n      ).parse();\n\n      expect(indexInputs).toMatchInlineSnapshot(`\n        - exportName: A\n          title: custom foo title\n          tags:\n            - component-tag\n            - component-tag-dup\n            - component-tag-dup\n            - inherit-tag-dup\n            - story-tag\n            - story-tag-dup\n            - story-tag-dup\n            - inherit-tag-dup\n          __id: custom-foo-title--a\n          __stats:\n            factory: false\n            play: false\n            render: false\n            loaders: false\n            beforeEach: false\n            globals: false\n            tags: true\n            storyFn: false\n            mount: false\n            moduleMock: false\n          type: story\n          subtype: story\n          name: A\n      `);\n    });\n\n    it('throws if getting indexInputs without filename option', () => {\n      const csf = loadCsf(\n        dedent`\n      export default {\n        title: 'custom foo title',\n        tags: ['component-tag', 'component-tag-dup', 'component-tag-dup', 'inherit-tag-dup']\n      };\n\n      export const A = {\n        tags: ['story-tag', 'story-tag-dup', 'story-tag-dup', 'inherit-tag-dup']\n      };\n    `,\n        { makeTitle }\n      ).parse();\n\n      expect(() => csf.indexInputs).toThrowErrorMatchingInlineSnapshot(`\n        [Error: Cannot automatically create index inputs with CsfFile.indexInputs because the CsfFile instance was created without a the fileName option.\n        Either add the fileName option when creating the CsfFile instance, or create the index inputs manually.]\n      `);\n    });\n  });\n\n  describe('component paths', () => {\n    it('no component', () => {\n      const { indexInputs } = loadCsf(\n        dedent`\n          import { Component } from '../src/Component.js';\n          export default {\n            title: 'custom foo title',\n          };\n\n          export const A = {\n            render: () => {},\n          };\n        `,\n        { makeTitle, fileName: 'foo/bar.stories.js' }\n      ).parse();\n\n      expect(indexInputs).toMatchInlineSnapshot(`\n        - exportName: A\n          title: custom foo title\n          tags: []\n          __id: custom-foo-title--a\n          __stats:\n            factory: false\n            play: false\n            render: true\n            loaders: false\n            beforeEach: false\n            globals: false\n            tags: false\n            storyFn: false\n            mount: false\n            moduleMock: false\n          type: story\n          subtype: story\n          name: A\n      `);\n    });\n\n    it('local component', () => {\n      const { indexInputs } = loadCsf(\n        dedent`\n          const Component = (props) => <div>hello</div>;\n\n          export default {\n            title: 'custom foo title',\n            component: Component,\n          };\n\n          export const A = {\n            render: () => {},\n          };\n        `,\n        { makeTitle, fileName: 'foo/bar.stories.js' }\n      ).parse();\n\n      expect(indexInputs).toMatchInlineSnapshot(`\n        - exportName: A\n          title: custom foo title\n          tags: []\n          __id: custom-foo-title--a\n          __stats:\n            factory: false\n            play: false\n            render: true\n            loaders: false\n            beforeEach: false\n            globals: false\n            tags: false\n            storyFn: false\n            mount: false\n            moduleMock: false\n          type: story\n          subtype: story\n          name: A\n      `);\n    });\n\n    it('imported component from file', () => {\n      const { indexInputs } = loadCsf(\n        dedent`\n          import { Component } from '../src/Component.js';\n          export default {\n            title: 'custom foo title',\n            component: Component,\n          };\n\n          export const A = {\n            render: () => {},\n          };\n        `,\n        { makeTitle, fileName: 'foo/bar.stories.js' }\n      ).parse();\n\n      expect(indexInputs).toMatchInlineSnapshot(`\n        - rawComponentPath: ../src/Component.js\n          exportName: A\n          title: custom foo title\n          tags: []\n          __id: custom-foo-title--a\n          __stats:\n            factory: false\n            play: false\n            render: true\n            loaders: false\n            beforeEach: false\n            globals: false\n            tags: false\n            storyFn: false\n            mount: false\n            moduleMock: false\n          type: story\n          subtype: story\n          name: A\n      `);\n    });\n\n    it('imported component from library', () => {\n      const { indexInputs } = loadCsf(\n        dedent`\n          import { Component } from 'some-library';\n          export default {\n            title: 'custom foo title',\n            component: Component,\n          };\n\n          export const A = {\n            render: () => {},\n          };\n        `,\n        { makeTitle, fileName: 'foo/bar.stories.js' }\n      ).parse();\n\n      expect(indexInputs).toMatchInlineSnapshot(`\n        - rawComponentPath: some-library\n          exportName: A\n          title: custom foo title\n          tags: []\n          __id: custom-foo-title--a\n          __stats:\n            factory: false\n            play: false\n            render: true\n            loaders: false\n            beforeEach: false\n            globals: false\n            tags: false\n            storyFn: false\n            mount: false\n            moduleMock: false\n          type: story\n          subtype: story\n          name: A\n      `);\n    });\n  });\n\n  describe('beforeEach', () => {\n    it('basic', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar' };\n          export const A = {\n            beforeEach: async () => {},\n          };\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: A\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: true\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n      `);\n    });\n  });\n\n  describe('globals', () => {\n    it('basic', () => {\n      expect(\n        parse(\n          dedent`\n          export default { title: 'foo/bar' };\n          export const A = {\n            globals: { foo: 'bar' }\n          };\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: A\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: true\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: false\n      `);\n    });\n  });\n\n  describe('module mocks', () => {\n    it('alias', () => {\n      expect(\n        parse(\n          dedent`\n          import foo from '#bar.mock';\n          export default { title: 'foo/bar' };\n          export const A = {};\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: A\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: true\n      `);\n    });\n    it('relative', () => {\n      expect(\n        parse(\n          dedent`\n          import foo from './bar.mock';\n          export default { title: 'foo/bar' };\n          export const A = {};\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        meta:\n          title: foo/bar\n        stories:\n          - id: foo-bar--a\n            name: A\n            __stats:\n              factory: false\n              play: false\n              render: false\n              loaders: false\n              beforeEach: false\n              globals: false\n              tags: false\n              storyFn: false\n              mount: false\n              moduleMock: true\n      `);\n    });\n  });\n\n  describe('csf factories', () => {\n    describe('normal', () => {\n      it('meta variable', () => {\n        expect(\n          parse(\n            dedent`\n              import { config } from '#.storybook/preview'\n              const meta = config.meta({ component: 'foo' });\n              export const A = meta.story({})\n              export const B = meta.story({})\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          meta:\n            component: '''foo'''\n            title: Default Title\n          stories:\n            - id: default-title--a\n              name: A\n              __stats:\n                factory: true\n                play: false\n                render: false\n                loaders: false\n                beforeEach: false\n                globals: false\n                tags: false\n                storyFn: false\n                mount: false\n                moduleMock: false\n            - id: default-title--b\n              name: B\n              __stats:\n                factory: true\n                play: false\n                render: false\n                loaders: false\n                beforeEach: false\n                globals: false\n                tags: false\n                storyFn: false\n                mount: false\n                moduleMock: false\n        `);\n      });\n\n      it('meta variable with renamed factory', () => {\n        expect(\n          parse(\n            dedent`\n              import { boo as moo } from '#.storybook/preview'\n              const meta = moo.meta({ component: 'foo' });\n              export const A = meta.story({})\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          meta:\n            component: '''foo'''\n            title: Default Title\n          stories:\n            - id: default-title--a\n              name: A\n              __stats:\n                factory: true\n                play: false\n                render: false\n                loaders: false\n                beforeEach: false\n                globals: false\n                tags: false\n                storyFn: false\n                mount: false\n                moduleMock: false\n        `);\n      });\n\n      it('meta default export', () => {\n        expect(\n          parse(\n            dedent`\n              import { config } from '#.storybook/preview'\n              const meta = config.meta({ component: 'foo' });\n              export default meta;\n              export const A = meta.story({})\n              export const B = meta.story({})\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          meta:\n            component: '''foo'''\n            title: Default Title\n          stories:\n            - id: default-title--a\n              name: A\n              __stats:\n                factory: true\n                play: false\n                render: false\n                loaders: false\n                beforeEach: false\n                globals: false\n                tags: false\n                storyFn: false\n                mount: false\n                moduleMock: false\n            - id: default-title--b\n              name: B\n              __stats:\n                factory: true\n                play: false\n                render: false\n                loaders: false\n                beforeEach: false\n                globals: false\n                tags: false\n                storyFn: false\n                mount: false\n                moduleMock: false\n        `);\n      });\n\n      it('extend story', () => {\n        expect(\n          parse(\n            dedent`\n              import { config } from '#.storybook/preview'\n              const meta = config.meta({ component: 'foo' });\n              export default meta;\n              export const A = meta.story({})\n              export const B = A.extend({})\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          meta:\n            component: '''foo'''\n            title: Default Title\n          stories:\n            - id: default-title--a\n              name: A\n              __stats:\n                factory: true\n                play: false\n                render: false\n                loaders: false\n                beforeEach: false\n                globals: false\n                tags: false\n                storyFn: false\n                mount: false\n                moduleMock: false\n            - id: default-title--b\n              name: B\n              __stats:\n                factory: true\n                play: false\n                render: false\n                loaders: false\n                beforeEach: false\n                globals: false\n                tags: false\n                storyFn: false\n                mount: false\n                moduleMock: false\n        `);\n      });\n\n      it('story test - index snapshot', () => {\n        expect(\n          parse(\n            dedent`\n              import { config } from '#.storybook/preview'\n              const meta = config.meta({ component: 'foo' });\n              export default meta;\n              export const A = meta.story({ args: { label: 'foo' } })\n              A.test('simple test', async () => {})\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          meta:\n            component: '''foo'''\n            title: Default Title\n          stories:\n            - id: default-title--a\n              name: A\n              __stats:\n                factory: true\n                tests: true\n                play: false\n                render: false\n                loaders: false\n                beforeEach: false\n                globals: false\n                tags: false\n                storyFn: false\n                mount: false\n                moduleMock: false\n        `);\n      });\n\n      it('story test - parsing', () => {\n        const data = loadCsf(\n          dedent`\n            import { config } from '#.storybook/preview'\n            const meta = config.meta({ component: 'foo' });\n            export default meta;\n            export const A = meta.story({ args: { label: 'foo' } })\n            A.test('simple test', async () => {})\n            A.test('with overrides', { args: { label: 'bar' } }, async () => {})\n            const runTest = () => {}\n            A.test('with function reference', runTest)\n            A.test('with function call', runTest())\n          `,\n          { makeTitle }\n        ).parse();\n        const story = data._stories['A'];\n        expect(story.__stats.tests).toBe(true);\n\n        const storyTests = data.getStoryTests('A');\n        expect(storyTests).toHaveLength(4);\n        expect(storyTests[0].name).toBe('simple test');\n        expect(storyTests[1].name).toBe('with overrides');\n        expect(storyTests[2].name).toBe('with function reference');\n        expect(storyTests[3].name).toBe('with function call');\n        expect(storyTests[0].function).toBeDefined();\n        expect(storyTests[1].function).toBeDefined();\n        expect(storyTests[2].function).toBeDefined();\n        expect(storyTests[3].function).toBeDefined();\n      });\n\n      it('story name', () => {\n        expect(\n          parse(\n            dedent`\n              import { config } from '#.storybook/preview'\n              const meta = config.meta({ component: 'foo' });\n              export const A = meta.story({ name: 'bar'})\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          meta:\n            component: '''foo'''\n            title: Default Title\n          stories:\n            - id: default-title--a\n              name: bar\n              __stats:\n                factory: true\n                play: false\n                render: false\n                loaders: false\n                beforeEach: false\n                globals: false\n                tags: false\n                storyFn: false\n                mount: false\n                moduleMock: false\n        `);\n      });\n\n      it('Object export with no-args render', () => {\n        expect(\n          parse(\n            dedent`\n              import { config } from '#.storybook/preview'\n              const meta = config.meta({ title: 'foo/bar' });\n              export const A = meta.story({\n                render: () => {}\n              })\n            `,\n            true\n          )\n        ).toMatchInlineSnapshot(`\n          meta:\n            title: foo/bar\n          stories:\n            - id: foo-bar--a\n              name: A\n              parameters:\n                __isArgsStory: false\n                __id: foo-bar--a\n              __stats:\n                factory: true\n                play: false\n                render: true\n                loaders: false\n                beforeEach: false\n                globals: false\n                tags: false\n                storyFn: false\n                mount: false\n                moduleMock: false\n        `);\n      });\n\n      it('Object export with args render', () => {\n        expect(\n          parse(\n            dedent`\n            import { config } from '#.storybook/preview'\n            const meta = config.meta({ title: 'foo/bar' });\n            export const A = meta.story({\n              render: (args) => {}\n            });\n          `,\n            true\n          )\n        ).toMatchInlineSnapshot(`\n          meta:\n            title: foo/bar\n          stories:\n            - id: foo-bar--a\n              name: A\n              parameters:\n                __isArgsStory: true\n                __id: foo-bar--a\n              __stats:\n                factory: true\n                play: false\n                render: true\n                loaders: false\n                beforeEach: false\n                globals: false\n                tags: false\n                storyFn: false\n                mount: false\n                moduleMock: false\n        `);\n      });\n\n      it('meta variable with .type() chaining', () => {\n        expect(\n          parse(\n            dedent`\n              import { config } from '#.storybook/preview'\n              const meta = config.type<{ args: { label: string } }>().meta({ component: 'foo' });\n              export const A = meta.story({})\n              export const B = meta.story({})\n            `\n          )\n        ).toMatchInlineSnapshot(`\n          meta:\n            component: '''foo'''\n            title: Default Title\n          stories:\n            - id: default-title--a\n              name: A\n              __stats:\n                factory: true\n                play: false\n                render: false\n                loaders: false\n                beforeEach: false\n                globals: false\n                tags: false\n                storyFn: false\n                mount: false\n                moduleMock: false\n            - id: default-title--b\n              name: B\n              __stats:\n                factory: true\n                play: false\n                render: false\n                loaders: false\n                beforeEach: false\n                globals: false\n                tags: false\n                storyFn: false\n                mount: false\n                moduleMock: false\n        `);\n      });\n    });\n    describe('errors', () => {\n      it('multiple meta variables', () => {\n        expect(() =>\n          parse(\n            dedent`\n            import { config } from '#.storybook/preview'\n            const foo = config.meta({ component: 'foo' });\n            export const A = foo.story({})\n            const bar = config.meta({ component: 'bar' });\n            export const B = bar.story({})\n        `\n          )\n        ).toThrowErrorMatchingInlineSnapshot(`\n          [MultipleMetaError: CSF: multiple meta objects (line 4, col 24)\n\n          More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export]\n        `);\n      });\n\n      it('default export and meta', () => {\n        expect(() =>\n          parse(\n            dedent`\n            import { config } from '#.storybook/preview'\n            export default { title: 'atoms/foo' };\n            const meta = config.meta({ component: 'foo' });\n            export const A = meta.story({})\n            export const B = meta.story({})\n        `\n          )\n        ).toThrowErrorMatchingInlineSnapshot(`\n          [MultipleMetaError: CSF: multiple meta objects (line 3, col 25)\n\n          More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export]\n        `);\n      });\n\n      it('meta and default export', () => {\n        expect(() =>\n          parse(\n            dedent`\n            import { config } from '#.storybook/preview'\n            const meta = config.meta({ component: 'foo' });\n            export default { title: 'atoms/foo' };\n            export const A = meta.story({})\n            export const B = meta.story({})\n        `\n          )\n        ).toThrowErrorMatchingInlineSnapshot(`\n          [MultipleMetaError: CSF: multiple meta objects \n\n          More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export]\n        `);\n      });\n\n      it('bad preview import', () => {\n        // Only throws when the variable is named \"preview\" to avoid false positives\n        // from libraries like Zod that have their own .meta() methods\n        expect(() =>\n          parse(\n            dedent`\n            import { preview } from '#.storybook/bad-preview'\n            const meta = preview.meta({ component: 'foo' });\n            export const A = meta.story({})\n        `\n          )\n        ).toThrowErrorMatchingInlineSnapshot(`\n          [BadMetaError: CSF: meta() factory must be imported from .storybook/preview configuration (line 1, col 0)\n\n          More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export]\n        `);\n      });\n\n      it('local defineConfig', () => {\n        expect(() =>\n          parse(\n            dedent`\n            import { defineConfig } from '@storybook/react/preview';\n            const config = defineConfig({ });\n            const meta = config.meta({ component: 'foo' });\n            export const A = meta.story({})\n        `\n          )\n        ).toThrowErrorMatchingInlineSnapshot(`\n          [BadMetaError: CSF: meta() factory must be imported from .storybook/preview configuration (line 4, col 28)\n\n          More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export]\n        `);\n      });\n\n      it('skips non-factory exports in factory files', () => {\n        const parsed = loadCsf(\n          dedent`\n            import { config } from '#.storybook/preview'\n            const meta = config.meta({ component: 'foo' });\n            export const A = meta.story({})\n            export const B = {}\n            export const someHelper = () => {}\n          `,\n          { makeTitle }\n        ).parse();\n        // Only factory stories are indexed, non-factory exports are skipped\n        expect(Object.keys(parsed._stories)).toEqual(['A']);\n      });\n\n      it('excludeStories still works with factories', () => {\n        const parsed = loadCsf(\n          dedent`\n            import { config } from '#.storybook/preview'\n            const meta = config.meta({ component: 'foo', excludeStories: ['B'] });\n            export const A = meta.story({})\n            export const B = meta.story({})\n          `,\n          { makeTitle }\n        ).parse();\n        // B is excluded via excludeStories\n        expect(Object.keys(parsed._stories)).toEqual(['A']);\n      });\n\n      it('factory stories in non-factory file', () => {\n        expect(() =>\n          parse(\n            dedent`\n              import { meta } from 'somewhere';\n              export default { title: 'atoms/foo' };\n              export const A = {}\n              export const B = meta.story({})\n            `\n          )\n        ).toThrowErrorMatchingInlineSnapshot(`\n          [MixedFactoryError: CSF: expected non-factory story (line 4, col 28)\n\n          More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export]\n        `);\n      });\n\n      it('ignores unrelated .meta() calls on imported variables (e.g., Zod v4)', () => {\n        // This should NOT throw - mySchema.meta() is not a CSF Factory call\n        // See: https://github.com/storybookjs/storybook/issues/33654\n        const parsed = loadCsf(\n          dedent`\n            import { mySchema } from './schemas';\n\n            const validatedSchema = mySchema.meta({ description: 'Value' });\n\n            export default {\n              title: 'Example',\n              component: () => null,\n            };\n\n            export const Default = {};\n          `,\n          { makeTitle }\n        ).parse();\n\n        expect(parsed._meta).toMatchInlineSnapshot(`\n          title: Example\n          component: () => null\n        `);\n        expect(Object.keys(parsed._stories)).toEqual(['Default']);\n      });\n\n      it('ignores chained .meta() calls from libraries like Zod', () => {\n        // More complex Zod-like patterns should also work\n        const parsed = loadCsf(\n          dedent`\n            import { z } from 'zod';\n            import { mySchema } from './schemas';\n\n            const workingSchema = z.object({\n              name: z.string().meta({ description: 'Name' }),\n            });\n\n            const failingSchema = z.object({\n              value: mySchema.meta({ description: 'Value' }),\n            });\n\n            export default {\n              title: 'Example',\n              component: () => null,\n            };\n\n            export const Default = {};\n          `,\n          { makeTitle }\n        ).parse();\n\n        expect(parsed._meta?.title).toBe('Example');\n        expect(Object.keys(parsed._stories)).toEqual(['Default']);\n      });\n    });\n  });\n});\n\ndescribe('isModuleMock', () => {\n  it('prefix', () => {\n    expect(isModuleMock('#foo.mock')).toBe(true);\n    expect(isModuleMock('./foo.mock')).toBe(true);\n    expect(isModuleMock('../foo.mock')).toBe(true);\n    expect(isModuleMock('/foo.mock')).toBe(true);\n\n    expect(isModuleMock('foo.mock')).toBe(false);\n    expect(isModuleMock('@/foo.mock')).toBe(false);\n  });\n  it('sufixes', () => {\n    expect(isModuleMock('#foo.mock.js')).toBe(true);\n    expect(isModuleMock('#foo.mock.mjs')).toBe(true);\n    expect(isModuleMock('#foo.mock.vue')).toBe(true);\n\n    expect(isModuleMock('#foo.mocktail')).toBe(false);\n    expect(isModuleMock('#foo.mock.test.ts')).toBe(false);\n  });\n});\n\ndescribe('isValidPreviewPath', () => {\n  it.each([\n    ['#.storybook/preview', true],\n    ['../../.storybook/preview', true],\n    ['/path/to/.storybook/preview', true],\n    ['./preview', true],\n    ['./preview.ts', true],\n    ['./preview.tsx', true],\n    ['./preview.js', true],\n    ['./preview.jsx', true],\n    ['./preview.mjs', true],\n    ['foo', false],\n    ['#.storybook/bad-preview', false],\n    ['preview', false],\n  ])('isValidPreviewPath(\"%s\") === %s', (path, expected) => {\n    expect(isValidPreviewPath(path)).toBe(expected);\n  });\n});\n"
  },
  {
    "path": "code/core/src/csf-tools/CsfFile.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\n\nimport {\n  BabelFileClass,\n  type GeneratorOptions,\n  type NodePath,\n  type RecastOptions,\n  babelParse,\n  generate,\n  recast,\n  types as t,\n  traverse,\n} from 'storybook/internal/babel';\nimport { isExportStory, storyNameFromExport, toId, toTestId } from 'storybook/internal/csf';\nimport { logger } from 'storybook/internal/node-logger';\nimport type {\n  ComponentAnnotations,\n  IndexInput,\n  IndexInputStats,\n  IndexedCSFFile,\n  StoryAnnotations,\n} from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\n\nimport { Tag } from '../shared/constants/tags.ts';\nimport type { PrintResultType } from './PrintResultType.ts';\nimport { findVarInitialization } from './findVarInitialization.ts';\n\n// We add this BabelFile as a temporary workaround to deal with a BabelFileClass \"ImportEquals should have a literal source\" issue in no link mode with tsup\ninterface BabelFile {\n  ast: t.File;\n  opts: any;\n  hub: any;\n  metadata: object;\n  path: NodePath<t.Program>;\n  scope: any;\n  inputMap: object | null;\n  code: string;\n}\n\nconst PREVIEW_FILE_REGEX = /\\/preview(.(js|jsx|mjs|ts|tsx))?$/;\nexport const isValidPreviewPath = (filepath: string) => PREVIEW_FILE_REGEX.test(filepath);\n\nfunction parseIncludeExclude(prop: t.Node) {\n  if (t.isArrayExpression(prop)) {\n    return prop.elements.map((e) => {\n      if (t.isStringLiteral(e)) {\n        return e.value;\n      }\n      throw new Error(`Expected string literal: ${e}`);\n    });\n  }\n\n  if (t.isStringLiteral(prop)) {\n    return new RegExp(prop.value);\n  }\n\n  if (t.isRegExpLiteral(prop)) {\n    return new RegExp(prop.pattern, prop.flags);\n  }\n\n  throw new Error(`Unknown include/exclude: ${prop}`);\n}\n\nfunction parseTags(prop: t.Node) {\n  if (!t.isArrayExpression(prop)) {\n    throw new Error('CSF: Expected tags array');\n  }\n\n  return prop.elements.map((e) => {\n    if (t.isStringLiteral(e)) {\n      return e.value;\n    }\n    throw new Error(`CSF: Expected tag to be string literal`);\n  }) as Tag[];\n}\n\nfunction parseTestTags(optionsNode: t.Node | null | undefined, program: t.Program) {\n  if (!optionsNode) {\n    return [] as string[];\n  }\n\n  let node: t.Node = optionsNode;\n  if (t.isIdentifier(node)) {\n    node = findVarInitialization(node.name, program);\n  }\n\n  if (t.isObjectExpression(node)) {\n    const tagsProp = node.properties.find(\n      (property) =>\n        t.isObjectProperty(property) && t.isIdentifier(property.key) && property.key.name === 'tags'\n    ) as t.ObjectProperty | undefined;\n\n    if (tagsProp) {\n      let tagsNode: t.Node = tagsProp.value as t.Node;\n      if (t.isIdentifier(tagsNode)) {\n        tagsNode = findVarInitialization(tagsNode.name, program);\n      }\n      return parseTags(tagsNode);\n    }\n  }\n\n  return [] as string[];\n}\n\nconst formatLocation = (node: t.Node, fileName?: string) => {\n  let loc = '';\n  if (node.loc) {\n    const { line, column } = node.loc?.start || {};\n    loc = `(line ${line}, col ${column})`;\n  }\n  return `${fileName || ''} ${loc}`.trim();\n};\n\nexport const isModuleMock = (importPath: string) => MODULE_MOCK_REGEX.test(importPath);\n\nconst isArgsStory = (init: t.Node, parent: t.Node, csf: CsfFile) => {\n  let storyFn: t.Node = init;\n  // export const Foo = Bar.bind({})\n  if (t.isCallExpression(init)) {\n    const { callee, arguments: bindArguments } = init;\n    if (\n      t.isProgram(parent) &&\n      t.isMemberExpression(callee) &&\n      t.isIdentifier(callee.object) &&\n      t.isIdentifier(callee.property) &&\n      callee.property.name === 'bind' &&\n      (bindArguments.length === 0 ||\n        (bindArguments.length === 1 &&\n          t.isObjectExpression(bindArguments[0]) &&\n          bindArguments[0].properties.length === 0))\n    ) {\n      const boundIdentifier = callee.object.name;\n      const template = findVarInitialization(boundIdentifier, parent);\n      if (template) {\n        csf._templates[boundIdentifier] = template;\n        storyFn = template;\n      }\n    }\n  }\n  if (t.isArrowFunctionExpression(storyFn)) {\n    return storyFn.params.length > 0;\n  }\n  if (t.isFunctionDeclaration(storyFn)) {\n    return storyFn.params.length > 0;\n  }\n  return false;\n};\n\nconst parseExportsOrder = (init: t.Expression) => {\n  if (t.isArrayExpression(init)) {\n    return (init.elements as t.Expression[]).map((item) => {\n      if (t.isStringLiteral(item)) {\n        return item.value;\n      }\n      throw new Error(`Expected string literal named export: ${item}`);\n    });\n  }\n  throw new Error(`Expected array of string literals: ${init}`);\n};\n\nconst sortExports = (exportByName: Record<string, any>, order: string[]) => {\n  return order.reduce(\n    (acc, name) => {\n      const namedExport = exportByName[name];\n\n      if (namedExport) {\n        acc[name] = namedExport;\n      }\n      return acc;\n    },\n    {} as Record<string, any>\n  );\n};\n\nconst hasMount = (play: t.Node | undefined) => {\n  if (\n    t.isArrowFunctionExpression(play) ||\n    t.isFunctionDeclaration(play) ||\n    t.isObjectMethod(play)\n  ) {\n    const params = play.params;\n    if (params.length >= 1) {\n      const [arg] = params;\n      if (t.isObjectPattern(arg)) {\n        return !!arg.properties.find((prop) => {\n          if (t.isObjectProperty(prop) && t.isIdentifier(prop.key)) {\n            return prop.key.name === 'mount';\n          }\n        });\n      }\n    }\n  }\n  return false;\n};\n\nconst MODULE_MOCK_REGEX = /^[.\\/#].*\\.mock($|\\.[^.]*$)/i;\n\nexport interface CsfOptions {\n  fileName?: string;\n  makeTitle: (userTitle: string) => string;\n  /**\n   * If an inline meta is detected e.g. `export default { title: 'foo' }` it will be transformed\n   * into a constant format e.g. `export const _meta = { title: 'foo' }; export default _meta;`\n   */\n  transformInlineMeta?: boolean;\n}\n\nexport class NoMetaError extends Error {\n  constructor(message: string, ast: t.Node, fileName?: string) {\n    const msg = message.trim();\n    super(dedent`\n      CSF: ${msg} ${formatLocation(ast, fileName)}\n      \n      More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export\n    `);\n    this.name = this.constructor.name;\n  }\n}\n\nexport class MultipleMetaError extends Error {\n  constructor(message: string, ast: t.Node, fileName?: string) {\n    const msg = `${message} ${formatLocation(ast, fileName)}`.trim();\n    super(dedent`\n      CSF: ${message} ${formatLocation(ast, fileName)}\n      \n      More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export\n    `);\n    this.name = this.constructor.name;\n  }\n}\n\nexport class MixedFactoryError extends Error {\n  constructor(message: string, ast: t.Node, fileName?: string) {\n    const msg = `${message} ${formatLocation(ast, fileName)}`.trim();\n    super(dedent`\n      CSF: ${message} ${formatLocation(ast, fileName)}\n      \n      More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export\n    `);\n    this.name = this.constructor.name;\n  }\n}\n\nexport class BadMetaError extends Error {\n  constructor(message: string, ast: t.Node, fileName?: string) {\n    const msg = ``.trim();\n    super(dedent`\n      CSF: ${message} ${formatLocation(ast, fileName)}\n      \n      More info: https://storybook.js.org/docs/writing-stories?ref=error#default-export\n    `);\n    this.name = this.constructor.name;\n  }\n}\n\nexport interface StaticMeta extends Pick<\n  ComponentAnnotations,\n  'id' | 'title' | 'includeStories' | 'excludeStories' | 'tags'\n> {\n  component?: string;\n}\n\nexport interface StaticStory extends Pick<StoryAnnotations, 'name' | 'parameters' | 'tags'> {\n  id: string;\n  localName?: string;\n  __stats: IndexInputStats;\n}\n\nexport interface StoryTest {\n  node: t.Node;\n  function: t.Node;\n  name: string;\n  id: string;\n  tags: string[];\n  parent: { node: t.Node };\n}\n\nexport class CsfFile {\n  _ast: t.File;\n\n  _file: BabelFile;\n\n  _options: CsfOptions;\n\n  _rawComponentPath?: string;\n\n  _componentImportSpecifier?: t.ImportSpecifier | t.ImportDefaultSpecifier;\n\n  _meta?: StaticMeta;\n\n  _stories: Record<string, StaticStory> = {};\n\n  _metaAnnotations: Record<string, t.Node> = {};\n\n  _storyExports: Record<string, t.VariableDeclarator | t.FunctionDeclaration> = {};\n\n  _storyDeclarationPath: Record<string, NodePath<t.VariableDeclarator | t.FunctionDeclaration>> =\n    {};\n\n  _storyPaths: Record<string, NodePath<t.ExportNamedDeclaration>> = {};\n\n  _metaStatement: t.Statement | undefined;\n\n  _metaStatementPath: NodePath<t.Statement> | undefined;\n\n  _metaNode: t.ObjectExpression | undefined;\n\n  _metaPath: NodePath<t.ExportDefaultDeclaration> | undefined;\n\n  _metaVariableName: string | undefined;\n\n  _metaIsFactory: boolean | undefined;\n\n  _storyStatements: Record<string, t.ExportNamedDeclaration | t.Expression> = {};\n\n  _storyAnnotations: Record<string, Record<string, t.Node>> = {};\n\n  _templates: Record<string, t.Expression> = {};\n\n  _namedExportsOrder?: string[];\n\n  imports: string[];\n\n  _tests: StoryTest[] = [];\n\n  constructor(ast: t.File, options: CsfOptions, file: BabelFile) {\n    this._ast = ast;\n    this._file = file;\n    this._options = options;\n    this.imports = [];\n  }\n\n  _parseTitle(value: t.Node) {\n    const node = t.isIdentifier(value)\n      ? findVarInitialization(value.name, this._ast.program)\n      : value;\n    if (t.isStringLiteral(node)) {\n      return node.value;\n    }\n    if (t.isTSSatisfiesExpression(node) && t.isStringLiteral(node.expression)) {\n      return node.expression.value;\n    }\n\n    throw new Error(dedent`\n      CSF: unexpected dynamic title ${formatLocation(node, this._options.fileName)}\n\n      More info: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#string-literal-titles\n    `);\n  }\n\n  _parseMeta(declaration: t.ObjectExpression, program: t.Program) {\n    if (this._metaNode) {\n      throw new MultipleMetaError('multiple meta objects', declaration, this._options.fileName);\n    }\n    this._metaNode = declaration;\n    const meta: StaticMeta = {};\n    (declaration.properties as t.ObjectProperty[]).forEach((p) => {\n      if (t.isIdentifier(p.key)) {\n        const value = t.isObjectMethod(p) ? p : p.value;\n        this._metaAnnotations[p.key.name] = value;\n\n        if (p.key.name === 'title') {\n          meta.title = this._parseTitle(p.value);\n        } else if (['includeStories', 'excludeStories'].includes(p.key.name)) {\n          (meta as any)[p.key.name] = parseIncludeExclude(p.value);\n        } else if (p.key.name === 'component') {\n          const n = p.value;\n          if (t.isIdentifier(n)) {\n            const id = n.name;\n            const importStmt = program.body.find(\n              (stmt) =>\n                t.isImportDeclaration(stmt) &&\n                stmt.specifiers.find((spec) => spec.local.name === id)\n            ) as t.ImportDeclaration;\n            if (importStmt) {\n              // Example: `import { ComponentImport } from './path-to-component'`\n              // const meta = { component: ComponentImport };\n              // Sets:\n              // - _rawComponentPath = './path-to-component'\n              // - _componentImportSpecifier = ComponentImport\n              const { source } = importStmt;\n              const specifier = importStmt.specifiers.find((spec) => spec.local.name === id);\n              if (t.isStringLiteral(source) && specifier) {\n                this._rawComponentPath = source.value;\n                if (t.isImportSpecifier(specifier) || t.isImportDefaultSpecifier(specifier)) {\n                  this._componentImportSpecifier = specifier;\n                }\n              }\n            }\n          }\n          const { code } = recast.print(p.value, {});\n          meta.component = code;\n        } else if (p.key.name === 'tags') {\n          let node = p.value;\n          if (t.isIdentifier(node)) {\n            node = findVarInitialization(node.name, this._ast.program);\n          }\n          meta.tags = parseTags(node);\n        } else if (p.key.name === 'id') {\n          if (t.isStringLiteral(p.value)) {\n            meta.id = p.value.value;\n          } else {\n            throw new Error(`Unexpected component id: ${p.value}`);\n          }\n        }\n      }\n    });\n    this._meta = meta;\n  }\n\n  getStoryExport(key: string) {\n    let node = this._storyExports[key] as t.Node;\n    node = t.isVariableDeclarator(node) ? (node.init as t.Node) : node;\n    if (t.isCallExpression(node)) {\n      const { callee, arguments: bindArguments } = node;\n      if (\n        t.isMemberExpression(callee) &&\n        t.isIdentifier(callee.object) &&\n        t.isIdentifier(callee.property) &&\n        callee.property.name === 'bind' &&\n        (bindArguments.length === 0 ||\n          (bindArguments.length === 1 &&\n            t.isObjectExpression(bindArguments[0]) &&\n            bindArguments[0].properties.length === 0))\n      ) {\n        const { name } = callee.object;\n        node = this._templates[name];\n      }\n    }\n    return node;\n  }\n\n  parse() {\n    // eslint-disable-next-line @typescript-eslint/no-this-alias\n    const self = this;\n    traverse(this._ast, {\n      ExportDefaultDeclaration: {\n        enter(path) {\n          const { node, parent } = path;\n          const isVariableReference = t.isIdentifier(node.declaration) && t.isProgram(parent);\n\n          /**\n           * Transform inline default exports into a constant declaration as it is needed for the\n           * Vitest plugin to compose stories using CSF1 through CSF3 should not be needed at all\n           * once we move to CSF4 entirely\n           *\n           * `export default {};`\n           *\n           * Becomes\n           *\n           * `const _meta = {}; export default _meta;`\n           */\n          if (\n            self._options.transformInlineMeta &&\n            !isVariableReference &&\n            t.isExpression(node.declaration)\n          ) {\n            const metaId = path.scope.generateUidIdentifier('meta');\n            self._metaVariableName = metaId.name;\n            const nodes = [\n              t.variableDeclaration('const', [t.variableDeclarator(metaId, node.declaration)]),\n              t.exportDefaultDeclaration(metaId),\n            ];\n\n            // Preserve sourcemaps location\n            nodes.forEach((_node: t.Node) => (_node.loc = path.node.loc));\n            path.replaceWithMultiple(nodes);\n\n            // This is a bit brittle because it assumes that we will hit the inserted default export\n            // as the traversal continues.\n            return;\n          }\n\n          let metaNode: t.ObjectExpression | undefined;\n          let decl;\n          if (isVariableReference) {\n            // const meta = { ... };\n            // export default meta;\n            const variableName = (node.declaration as t.Identifier).name;\n            self._metaVariableName = variableName;\n            const isMetaVariable = (declaration: t.VariableDeclarator) =>\n              t.isIdentifier(declaration.id) && declaration.id.name === variableName;\n\n            self._metaStatementPath = self._file.path\n              .get('body')\n              .find(\n                (path) =>\n                  path.isVariableDeclaration() && path.node.declarations.some(isMetaVariable)\n              );\n\n            self._metaStatement = self._metaStatementPath?.node;\n\n            decl = ((self?._metaStatement as t.VariableDeclaration)?.declarations || []).find(\n              isMetaVariable\n            )?.init;\n          } else {\n            self._metaStatement = node;\n            self._metaStatementPath = path;\n            decl = node.declaration;\n          }\n\n          if (t.isObjectExpression(decl)) {\n            // export default { ... };\n            metaNode = decl;\n          } else if (\n            // export default { ... } as Meta<...>\n            // export default { ... } satisfies Meta<...>\n            (t.isTSAsExpression(decl) || t.isTSSatisfiesExpression(decl)) &&\n            t.isObjectExpression(decl.expression)\n          ) {\n            metaNode = decl.expression;\n          } else if (\n            // export default { ... } satisfies Meta as Meta<...>\n            t.isTSAsExpression(decl) &&\n            t.isTSSatisfiesExpression(decl.expression) &&\n            t.isObjectExpression(decl.expression.expression)\n          ) {\n            metaNode = decl.expression.expression;\n          }\n\n          if (metaNode && t.isProgram(parent)) {\n            self._parseMeta(metaNode, parent);\n          }\n\n          if (self._metaStatement && !self._metaNode) {\n            throw new NoMetaError(\n              'default export must be an object',\n              self._metaStatement,\n              self._options.fileName\n            );\n          }\n\n          self._metaPath = path;\n        },\n      },\n      ExportNamedDeclaration: {\n        enter(path) {\n          const { node, parent } = path;\n          const declaration = path.get('declaration');\n          let declarations;\n          if (declaration.isVariableDeclaration()) {\n            declarations = declaration.get('declarations').filter((d) => d.isVariableDeclarator());\n          } else if (declaration.isFunctionDeclaration()) {\n            declarations = [declaration];\n          }\n          if (declarations) {\n            // export const X = ...;\n            declarations.forEach((declPath) => {\n              const decl = declPath.node;\n              const id = declPath.node.id;\n\n              if (t.isIdentifier(id)) {\n                const { name: exportName } = id;\n                if (exportName === '__namedExportsOrder' && declPath.isVariableDeclarator()) {\n                  self._namedExportsOrder = parseExportsOrder(declPath.node.init as t.Expression);\n                  return;\n                }\n\n                // Determine the story node, unwrapping TS expressions\n                let storyNode;\n                if (t.isVariableDeclarator(decl)) {\n                  if (\n                    t.isTSAsExpression(decl.init) &&\n                    t.isTSSatisfiesExpression(decl.init.expression)\n                  ) {\n                    // { ... } satisfies Meta<...> as Meta<...>\n                    storyNode = decl.init.expression.expression;\n                  } else if (\n                    t.isTSAsExpression(decl.init) ||\n                    t.isTSSatisfiesExpression(decl.init)\n                  ) {\n                    // { ... } as Meta<...>\n                    // { ... } satisfies Meta<...>\n                    storyNode = decl.init.expression;\n                  } else {\n                    storyNode = decl.init;\n                  }\n                } else {\n                  storyNode = decl;\n                }\n\n                // Check if this is a factory story (meta.story() or meta.extend())\n                let storyIsFactory = false;\n                if (\n                  t.isCallExpression(storyNode) &&\n                  t.isMemberExpression(storyNode.callee) &&\n                  t.isIdentifier(storyNode.callee.property) &&\n                  (storyNode.callee.property.name === 'story' ||\n                    storyNode.callee.property.name === 'extend')\n                ) {\n                  storyIsFactory = true;\n                  storyNode = storyNode.arguments[0];\n                }\n\n                // Skip non-factory exports in factory files\n                if (self._metaIsFactory && !storyIsFactory) {\n                  return;\n                }\n\n                if (!self._metaIsFactory && storyIsFactory) {\n                  if (self._metaNode) {\n                    throw new MixedFactoryError(\n                      'expected non-factory story',\n                      storyNode as t.Node,\n                      self._options.fileName\n                    );\n                  } else {\n                    throw new BadMetaError(\n                      'meta() factory must be imported from .storybook/preview configuration',\n                      storyNode as t.Node,\n                      self._options.fileName\n                    );\n                  }\n                }\n\n                // Now we know this is a valid story, register it\n                self._storyExports[exportName] = decl;\n                self._storyDeclarationPath[exportName] = declPath;\n                self._storyPaths[exportName] = path;\n                self._storyStatements[exportName] = node;\n                let name = storyNameFromExport(exportName);\n                if (self._storyAnnotations[exportName]) {\n                  logger.warn(\n                    `Unexpected annotations for \"${exportName}\" before story declaration`\n                  );\n                } else {\n                  self._storyAnnotations[exportName] = {};\n                }\n\n                const parameters: { [key: string]: any } = {};\n                if (t.isObjectExpression(storyNode)) {\n                  parameters.__isArgsStory = true; // assume default render is an args story\n                  // CSF3 object export\n                  (storyNode.properties as t.ObjectProperty[]).forEach((p) => {\n                    if (t.isIdentifier(p.key)) {\n                      const key = p.key.name;\n                      if (t.isObjectMethod(p)) {\n                        self._storyAnnotations[exportName][key] = p;\n                      } else {\n                        if (p.key.name === 'render') {\n                          parameters.__isArgsStory = isArgsStory(\n                            p.value as t.Expression,\n                            parent,\n                            self\n                          );\n                        } else if (p.key.name === 'name' && t.isStringLiteral(p.value)) {\n                          name = p.value.value;\n                        } else if (p.key.name === 'storyName' && t.isStringLiteral(p.value)) {\n                          logger.warn(\n                            `Unexpected usage of \"storyName\" in \"${exportName}\". Please use \"name\" instead.`\n                          );\n                        } else if (p.key.name === 'parameters' && t.isObjectExpression(p.value)) {\n                          const idProperty = p.value.properties.find(\n                            (property) =>\n                              t.isObjectProperty(property) &&\n                              t.isIdentifier(property.key) &&\n                              property.key.name === '__id'\n                          ) as t.ObjectProperty | undefined;\n                          if (idProperty) {\n                            parameters.__id = (idProperty.value as t.StringLiteral).value;\n                          }\n                        }\n                        self._storyAnnotations[exportName][p.key.name] = p.value;\n                      }\n                    }\n                  });\n                } else {\n                  parameters.__isArgsStory = isArgsStory(storyNode as t.Node, parent, self);\n                }\n                self._stories[exportName] = {\n                  id: 'FIXME',\n                  name,\n                  parameters,\n                  __stats: {\n                    factory: storyIsFactory,\n                  },\n                };\n              }\n            });\n          } else if (node.specifiers.length > 0) {\n            // export { X as Y }\n            node.specifiers.forEach((specifier) => {\n              if (t.isExportSpecifier(specifier) && t.isIdentifier(specifier.exported)) {\n                const { name: exportName } = specifier.exported;\n                const { name: localName } = specifier.local;\n                const decl = t.isProgram(parent)\n                  ? findVarInitialization(localName, parent)\n                  : specifier.local;\n\n                if (exportName === 'default') {\n                  let metaNode: t.ObjectExpression | undefined;\n\n                  if (t.isObjectExpression(decl)) {\n                    // export default { ... };\n                    metaNode = decl;\n                  } else if (\n                    // export default { ... } as Meta<...>\n                    // export default { ... } satisfies Meta<...>\n                    (t.isTSAsExpression(decl) || t.isTSSatisfiesExpression(decl)) &&\n                    t.isObjectExpression(decl.expression)\n                  ) {\n                    metaNode = decl.expression;\n                  } else if (\n                    // export default { ... } satisfies Meta as Meta<...>\n                    t.isTSAsExpression(decl) &&\n                    t.isTSSatisfiesExpression(decl.expression) &&\n                    t.isObjectExpression(decl.expression.expression)\n                  ) {\n                    metaNode = decl.expression.expression;\n                  }\n\n                  if (metaNode && t.isProgram(parent)) {\n                    self._parseMeta(metaNode, parent);\n                  }\n                } else {\n                  const annotations = {} as Record<string, t.Node>;\n                  const storyNode = decl;\n                  if (t.isObjectExpression(storyNode)) {\n                    (storyNode.properties as t.ObjectProperty[]).forEach((p) => {\n                      if (t.isIdentifier(p.key)) {\n                        annotations[p.key.name] = p.value;\n                      }\n                    });\n                  }\n                  self._storyAnnotations[exportName] = annotations;\n                  self._storyStatements[exportName] = decl;\n                  self._storyPaths[exportName] = path;\n                  self._stories[exportName] = {\n                    id: 'FIXME',\n                    name: exportName,\n                    localName,\n                    parameters: {},\n                    __stats: {},\n                  };\n                }\n              }\n            });\n          }\n        },\n      },\n      ExpressionStatement: {\n        enter({ node, parent }) {\n          const { expression } = node;\n          // B.storyName = 'some string';\n          if (\n            t.isProgram(parent) &&\n            t.isAssignmentExpression(expression) &&\n            t.isMemberExpression(expression.left) &&\n            t.isIdentifier(expression.left.object) &&\n            t.isIdentifier(expression.left.property)\n          ) {\n            const exportName = expression.left.object.name;\n            const annotationKey = expression.left.property.name;\n            const annotationValue = expression.right;\n\n            // v1-style annotation\n            // A.story = { parameters: ..., decorators: ... }\n\n            if (self._storyAnnotations[exportName]) {\n              if (annotationKey === 'story' && t.isObjectExpression(annotationValue)) {\n                (annotationValue.properties as t.ObjectProperty[]).forEach((prop) => {\n                  if (t.isIdentifier(prop.key)) {\n                    self._storyAnnotations[exportName][prop.key.name] = prop.value;\n                  }\n                });\n              } else {\n                self._storyAnnotations[exportName][annotationKey] = annotationValue;\n              }\n            }\n\n            if (annotationKey === 'storyName' && t.isStringLiteral(annotationValue)) {\n              const storyName = annotationValue.value;\n              const story = self._stories[exportName];\n\n              if (!story) {\n                return;\n              }\n              story.name = storyName;\n            }\n          }\n          // B.test('foo', () => {})\n          // B.test('foo', context, () => {})\n          if (\n            t.isCallExpression(expression) &&\n            t.isMemberExpression(expression.callee) &&\n            t.isIdentifier(expression.callee.object) &&\n            t.isIdentifier(expression.callee.property) &&\n            expression.callee.property.name === 'test' &&\n            expression.arguments.length >= 2 &&\n            t.isStringLiteral(expression.arguments[0])\n          ) {\n            const exportName = expression.callee.object.name;\n            const testName = expression.arguments[0].value;\n            const testFunction =\n              expression.arguments.length === 2 ? expression.arguments[1] : expression.arguments[2];\n            const testArguments =\n              expression.arguments.length === 2 ? null : expression.arguments[1];\n            const tags = parseTestTags(testArguments as t.Node | null, self._ast.program);\n\n            self._tests.push({\n              function: testFunction,\n              name: testName,\n              node: expression,\n              // can't set id because meta title isn't available yet\n              // so it's set later on\n              id: 'FIXME',\n              tags,\n              parent: { node: self._storyStatements[exportName] },\n            });\n\n            // TODO: fix this when stories fail\n            self._stories[exportName].__stats.tests = true;\n          }\n        },\n      },\n      CallExpression: {\n        enter(path) {\n          const { node } = path;\n          const { callee } = node;\n          if (t.isIdentifier(callee) && callee.name === 'storiesOf') {\n            throw new Error(dedent`\n              Unexpected \\`storiesOf\\` usage: ${formatLocation(node, self._options.fileName)}.\n\n              SB8 does not support \\`storiesOf\\`.\n            `);\n          }\n          if (\n            t.isMemberExpression(callee) &&\n            t.isIdentifier(callee.property) &&\n            callee.property.name === 'meta' &&\n            node.arguments.length > 0\n          ) {\n            // Find the root object for factory pattern:\n            // - preview.meta() => preview\n            // - preview.type().meta() => preview\n            let rootObject = callee.object;\n            if (t.isCallExpression(rootObject) && t.isMemberExpression(rootObject.callee)) {\n              rootObject = rootObject.callee.object;\n            }\n\n            if (t.isIdentifier(rootObject)) {\n              const configCandidate = path.scope.getBinding(rootObject.name);\n              const configParent = configCandidate?.path?.parentPath?.node;\n              if (t.isImportDeclaration(configParent)) {\n                if (isValidPreviewPath(configParent.source.value)) {\n                  self._metaIsFactory = true;\n                  const metaDeclarator = path.findParent((p) =>\n                    p.isVariableDeclarator()\n                  ) as NodePath<t.VariableDeclarator>;\n\n                  // find the name of the meta variable declaration\n                  // e.g. const foo = preview.meta({ ... });\n                  // otherwise fallback to meta\n                  self._metaVariableName = t.isIdentifier(metaDeclarator.node.id)\n                    ? metaDeclarator.node.id.name\n                    : callee.property.name;\n                  const metaNode = node.arguments[0] as t.ObjectExpression;\n                  self._parseMeta(metaNode, self._ast.program);\n                } else if (rootObject.name === 'preview') {\n                  // Only throw if the variable is named \"preview\" - this indicates\n                  // the user is trying to use CSF Factories but with a wrong import path.\n                  // Other .meta() calls (e.g., Zod v4's .meta()) are silently ignored.\n                  throw new BadMetaError(\n                    'meta() factory must be imported from .storybook/preview configuration',\n                    configParent,\n                    self._options.fileName\n                  );\n                }\n              }\n            }\n          }\n        },\n      },\n      ImportDeclaration: {\n        enter({ node }) {\n          const { source } = node;\n          if (t.isStringLiteral(source)) {\n            self.imports.push(source.value);\n          } else {\n            throw new Error('CSF: unexpected import source');\n          }\n        },\n      },\n    });\n\n    if (!self._meta) {\n      throw new NoMetaError('missing default export', self._ast, self._options.fileName);\n    }\n\n    // default export can come at any point in the file, so we do this post processing last\n    const entries = Object.entries(self._stories);\n    self._meta.title = this._options.makeTitle(self._meta?.title as string);\n    if (self._metaAnnotations.play) {\n      self._meta.tags = [...(self._meta.tags || []), Tag.PLAY_FN];\n    }\n    self._stories = entries.reduce(\n      (acc, [key, story]) => {\n        if (!isExportStory(key, self._meta as StaticMeta)) {\n          return acc;\n        }\n        const id =\n          story.parameters?.__id ??\n          toId((self._meta?.id || self._meta?.title) as string, storyNameFromExport(key));\n        const parameters: Record<string, any> = { ...story.parameters, __id: id };\n\n        const { includeStories } = self._meta || {};\n        if (\n          key === '__page' &&\n          (entries.length === 1 || (Array.isArray(includeStories) && includeStories.length === 1))\n        ) {\n          parameters.docsOnly = true;\n        }\n        acc[key] = { ...story, id, parameters };\n        const storyAnnotations = self._storyAnnotations[key];\n        const { tags, play } = storyAnnotations;\n        if (tags) {\n          const node = t.isIdentifier(tags)\n            ? findVarInitialization(tags.name, this._ast.program)\n            : tags;\n          acc[key].tags = parseTags(node);\n        }\n        if (play) {\n          acc[key].tags = [...(acc[key].tags || []), Tag.PLAY_FN];\n        }\n        const stats = acc[key].__stats;\n        ['play', 'render', 'loaders', 'beforeEach', 'globals', 'tags'].forEach((annotation) => {\n          stats[annotation as keyof IndexInputStats] =\n            !!storyAnnotations[annotation] || !!self._metaAnnotations[annotation];\n        });\n        const storyExport = self.getStoryExport(key);\n        stats.storyFn = !!(\n          t.isArrowFunctionExpression(storyExport) || t.isFunctionDeclaration(storyExport)\n        );\n        stats.mount = hasMount(storyAnnotations.play ?? self._metaAnnotations.play);\n        stats.moduleMock = !!self.imports.find((fname) => isModuleMock(fname));\n\n        const storyNode = self._storyStatements[key];\n        const storyTests = self._tests.filter((t) => t.parent.node === storyNode);\n        if (storyTests.length > 0) {\n          // TODO: [test-syntax] if we want to add a tag for the story that contains tests, this is the place for it\n          // acc[key].tags = [...(acc[key].tags || []), 'story-with-tests'];\n\n          stats.tests = true;\n          storyTests.forEach((test) => {\n            test.id = toTestId(id, test.name);\n          });\n        }\n\n        return acc;\n      },\n      {} as Record<string, StaticStory>\n    );\n\n    Object.keys(self._storyExports).forEach((key) => {\n      if (!isExportStory(key, self._meta as StaticMeta)) {\n        delete self._storyExports[key];\n        delete self._storyAnnotations[key];\n        delete self._storyStatements[key];\n      }\n    });\n\n    if (self._namedExportsOrder) {\n      const unsortedExports = Object.keys(self._storyExports);\n      self._storyExports = sortExports(self._storyExports, self._namedExportsOrder);\n      self._stories = sortExports(self._stories, self._namedExportsOrder);\n\n      const sortedExports = Object.keys(self._storyExports);\n      if (unsortedExports.length !== sortedExports.length) {\n        throw new Error(\n          `Missing exports after sort: ${unsortedExports.filter(\n            (key) => !sortedExports.includes(key)\n          )}`\n        );\n      }\n    }\n\n    return self as CsfFile & IndexedCSFFile;\n  }\n\n  public get meta() {\n    return this._meta;\n  }\n\n  public get stories() {\n    return Object.values(this._stories);\n  }\n\n  public getStoryTests(story: string | t.Node) {\n    const storyNode = typeof story === 'string' ? this._storyStatements[story] : story;\n    if (!storyNode) {\n      return [];\n    }\n    return this._tests.filter((t) => t.parent.node === storyNode);\n  }\n\n  public get indexInputs(): IndexInput[] {\n    const { fileName } = this._options;\n    if (!fileName) {\n      throw new Error(\n        dedent`Cannot automatically create index inputs with CsfFile.indexInputs because the CsfFile instance was created without a the fileName option.\n        Either add the fileName option when creating the CsfFile instance, or create the index inputs manually.`\n      );\n    }\n\n    const index: IndexInput[] = [];\n\n    Object.entries(this._stories).map(([exportName, story]) => {\n      // don't remove any duplicates or negations -- tags will be combined in the index\n      const tags = [...(this._meta?.tags ?? []), ...(story.tags ?? [])];\n      const storyInput = {\n        rawComponentPath: this._rawComponentPath,\n        exportName,\n        title: this.meta?.title,\n        metaId: this.meta?.id,\n        tags,\n        __id: story.id,\n        __stats: story.__stats,\n      };\n\n      const tests = this.getStoryTests(exportName);\n      const hasTests = tests.length > 0;\n\n      index.push({\n        ...storyInput,\n        type: 'story',\n        subtype: 'story',\n        name: story.name,\n      });\n\n      if (hasTests) {\n        tests.forEach((test) => {\n          index.push({\n            ...storyInput,\n            // TODO implementent proper title => path behavior in `transformStoryIndexToStoriesHash`\n            // title: `${storyInput.title}/${story.name}`,\n            type: 'story',\n            subtype: 'test',\n            name: test.name,\n            parent: story.id,\n            parentName: story.name,\n            tags: [\n              ...storyInput.tags,\n              // this tag comes before test tags so users can invert if they like\n              `!${Tag.AUTODOCS}`,\n              ...test.tags,\n              // this tag comes after test tags so users can't change it\n              Tag.TEST_FN,\n            ],\n            __id: test.id,\n          });\n        });\n      }\n    });\n\n    return index;\n  }\n}\n\n/** Using new babel.File is more powerful and give access to API such as buildCodeFrameError */\nexport const babelParseFile = ({\n  code,\n  filename = '',\n  ast,\n}: {\n  code: string;\n  filename?: string;\n  ast?: t.File;\n}): BabelFile => {\n  return new BabelFileClass(\n    { filename, highlightCode: false },\n    { code, ast: ast ?? babelParse(code) }\n  );\n};\n\nexport const loadCsf = (code: string, options: CsfOptions) => {\n  const ast = babelParse(code);\n  const file = babelParseFile({ code, filename: options.fileName, ast });\n  return new CsfFile(ast, options, file);\n};\n\nexport const formatCsf = (\n  csf: CsfFile,\n  options: GeneratorOptions & { inputSourceMap?: any } = { sourceMaps: false },\n  code?: string\n): ReturnType<typeof generate> | string => {\n  const result = generate(csf._ast, options, code);\n  if (options.sourceMaps) {\n    return result;\n  }\n  return result.code;\n};\n\n/** Use this function, if you want to preserve styles. Uses recast under the hood. */\nexport const printCsf = (csf: CsfFile, options: RecastOptions = {}): PrintResultType => {\n  return recast.print(csf._ast, options);\n};\n\nexport const readCsf = async (fileName: string, options: CsfOptions) => {\n  const code = (await readFile(fileName, 'utf-8')).toString();\n  return loadCsf(code, { ...options, fileName });\n};\n\nexport const writeCsf = async (csf: CsfFile, fileName?: string) => {\n  const fname = fileName || csf._options.fileName;\n\n  if (!fname) {\n    throw new Error('Please specify a fileName for writeCsf');\n  }\n  await writeFile(fileName as string, printCsf(csf).code);\n};\n"
  },
  {
    "path": "code/core/src/csf-tools/PrintResultType.ts",
    "content": "export interface PrintResultType {\n  code: string;\n  map?: any;\n  toString(): string;\n}\n"
  },
  {
    "path": "code/core/src/csf-tools/README.md",
    "content": "# Storybook CSF Tools\n\nAn experimental library to read, analyze, transform, and write CSF programmatically.\n\n- Read - Parse a CSF file with Babel\n- Analyze - Extract its metadata & stories based on the Babel AST\n- Write - Write the AST back to a file\n\nIt can can parse MDX into CSF.\n\nComing soon:\n\n- Transform - Update the AST to add/remove/modify stories & metadata (TODO)\n"
  },
  {
    "path": "code/core/src/csf-tools/enrichCsf.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { dedent } from 'ts-dedent';\n\nimport { formatCsf, loadCsf } from './CsfFile.ts';\nimport type { EnrichCsfOptions } from './enrichCsf.ts';\nimport { enrichCsf, extractSource } from './enrichCsf.ts';\n\nexpect.addSnapshotSerializer({\n  print: (val: any) => val.replace(/\\\\r\\\\n/gm, '\\\\n'),\n  test: () => true,\n});\n\nconst enrich = async (code: string, originalCode: string, options?: EnrichCsfOptions) => {\n  // we don't actually care about the title\n\n  const csf = loadCsf(code, { makeTitle: (userTitle) => userTitle ?? 'Unknown' }).parse();\n  const csfSource = loadCsf(originalCode, {\n    makeTitle: (userTitle) => userTitle ?? 'Unknown',\n  }).parse();\n  await enrichCsf(csf, csfSource, options);\n  return formatCsf(csf);\n};\n\ndescribe('enrichCsf', () => {\n  describe('source', () => {\n    it('csf1', async () => {\n      expect(\n        await enrich(\n          dedent`\n          // compiled code\n          export default {\n           title: 'Button',\n          }\n          export const Basic = () => React.createElement(Button)\n        `,\n          dedent`\n        // original code\n        export default {\n         title: 'Button',\n        }\n        export const Basic = () => <Button />\n      `\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        export default {\n          title: 'Button'\n        };\n        export const Basic = () => React.createElement(Button);\n        Basic.parameters = {\n          ...Basic.parameters,\n          docs: {\n            ...Basic.parameters?.docs,\n            source: {\n              originalSource: \"() => <Button />\",\n              ...Basic.parameters?.docs?.source\n            }\n          }\n        };\n      `);\n    });\n    it('csf2', async () => {\n      expect(\n        await enrich(\n          dedent`\n        // compiled code\n        export default {\n          title: 'Button',\n        }\n        const Template = (args) => React.createElement(Button, args);\n        export const Basic = Template.bind({});\n        Basic.parameters = { foo: 'bar' }\n      `,\n          dedent`\n          // original code\n          export default {\n            title: 'Button',\n          }\n          const Template = (args) => <Button {...args} />\n          export const Basic = Template.bind({});\n          Basic.parameters = { foo: 'bar' }\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        export default {\n          title: 'Button'\n        };\n        const Template = args => React.createElement(Button, args);\n        export const Basic = Template.bind({});\n        Basic.parameters = {\n          foo: 'bar'\n        };\n        Basic.parameters = {\n          ...Basic.parameters,\n          docs: {\n            ...Basic.parameters?.docs,\n            source: {\n              originalSource: \"args => <Button {...args} />\",\n              ...Basic.parameters?.docs?.source\n            }\n          }\n        };\n      `);\n    });\n    it('csf3', async () => {\n      expect(\n        await enrich(\n          dedent`\n        // compiled code\n        export default {\n          title: 'Button',\n        }\n        export const Basic = { parameters: { foo: 'bar' } }\n      `,\n          dedent`\n          // original code\n          export default {\n            title: 'Button',\n          }\n          export const Basic = {\n            parameters: { foo: 'bar' }\n          }\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        export default {\n          title: 'Button'\n        };\n        export const Basic = {\n          parameters: {\n            foo: 'bar'\n          }\n        };\n        Basic.parameters = {\n          ...Basic.parameters,\n          docs: {\n            ...Basic.parameters?.docs,\n            source: {\n              originalSource: \"{\\\\n  parameters: {\\\\n    foo: 'bar'\\\\n  }\\\\n}\",\n              ...Basic.parameters?.docs?.source\n            }\n          }\n        };\n      `);\n    });\n    it('csf factories', async () => {\n      expect(\n        await enrich(\n          dedent`\n          // compiled code\n          import {config} from \"/.storybook/preview.ts\";\n          const meta = config.meta({\n              args: {\n                label: \"Hello world!\"\n              }\n          });\n          export const Story = meta.story({});\n        `,\n          dedent`\n          // original code\n          import {config} from \"#.storybook/preview.ts\";\n          const meta = config.meta({\n              args: {\n                label: \"Hello world!\"\n              }\n          });\n          export const Story = meta.story({});\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        import { config } from \"/.storybook/preview.ts\";\n        const meta = config.meta({\n          args: {\n            label: \"Hello world!\"\n          }\n        });\n        export const Story = meta.story({});\n        Story.input.parameters = {\n          ...Story.input.parameters,\n          docs: {\n            ...Story.input.parameters?.docs,\n            source: {\n              originalSource: \"meta.story({})\",\n              ...Story.input.parameters?.docs?.source\n            }\n          }\n        };\n      `);\n    });\n    it('multiple stories', async () => {\n      expect(\n        await enrich(\n          dedent`\n        // compiled code\n        export default {\n          title: 'Button',\n        }\n        export const A = {}\n        export const B = {}\n      `,\n          dedent`\n          // original code\n          export default {\n            title: 'Button',\n          }\n          export const A = {}\n          export const B = {}\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        export default {\n          title: 'Button'\n        };\n        export const A = {};\n        export const B = {};\n        A.parameters = {\n          ...A.parameters,\n          docs: {\n            ...A.parameters?.docs,\n            source: {\n              originalSource: \"{}\",\n              ...A.parameters?.docs?.source\n            }\n          }\n        };\n        B.parameters = {\n          ...B.parameters,\n          docs: {\n            ...B.parameters?.docs,\n            source: {\n              originalSource: \"{}\",\n              ...B.parameters?.docs?.source\n            }\n          }\n        };\n      `);\n    });\n  });\n\n  describe('story descriptions', () => {\n    it('skips inline comments', async () => {\n      expect(\n        await enrich(\n          dedent`\n        // compiled code\n        export default {\n         title: 'Button',\n        }\n        // The most basic button\n        export const Basic = () => React.createElement(Button);\n      `,\n          dedent`\n          // original code\n          export default {\n           title: 'Button',\n          }\n          // The most basic button\n          export const Basic = () => <Button />\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        export default {\n          title: 'Button'\n        };\n        // The most basic button\n        export const Basic = () => React.createElement(Button);\n        Basic.parameters = {\n          ...Basic.parameters,\n          docs: {\n            ...Basic.parameters?.docs,\n            source: {\n              originalSource: \"() => <Button />\",\n              ...Basic.parameters?.docs?.source\n            }\n          }\n        };\n      `);\n    });\n\n    it('skips blocks without jsdoc', async () => {\n      expect(\n        await enrich(\n          dedent`\n          // compiled code\n          export default {\n           title: 'Button',\n          }\n          export const Basic = () => React.createElement(Button)\n        `,\n          dedent`\n          // original code\n          export default {\n           title: 'Button',\n          }\n          /* The most basic button */\n          export const Basic = () => <Button />\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        export default {\n          title: 'Button'\n        };\n        export const Basic = () => React.createElement(Button);\n        Basic.parameters = {\n          ...Basic.parameters,\n          docs: {\n            ...Basic.parameters?.docs,\n            source: {\n              originalSource: \"() => <Button />\",\n              ...Basic.parameters?.docs?.source\n            }\n          }\n        };\n      `);\n    });\n\n    it('JSDoc single-line', async () => {\n      expect(\n        await enrich(\n          dedent`\n          // compiled code\n          export default {\n           title: 'Button',\n          }\n          export const Basic = () => React.createElement(Button);\n        `,\n          dedent`\n          // original code\n          export default {\n           title: 'Button',\n          }\n          /** The most basic button */\n          export const Basic = () => <Button />\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        export default {\n          title: 'Button'\n        };\n        export const Basic = () => React.createElement(Button);\n        Basic.parameters = {\n          ...Basic.parameters,\n          docs: {\n            ...Basic.parameters?.docs,\n            source: {\n              originalSource: \"() => <Button />\",\n              ...Basic.parameters?.docs?.source\n            },\n            description: {\n              story: \"The most basic button\",\n              ...Basic.parameters?.docs?.description\n            }\n          }\n        };\n      `);\n    });\n\n    it('JSDoc multi-line', async () => {\n      expect(\n        await enrich(\n          dedent`\n        // compiled code\n        export default {\n         title: 'Button',\n        }\n        export const Basic = () => React.createElement(Button);\n      `,\n          dedent`\n          // original code\n          export default {\n           title: 'Button',\n          }\n          /**\n           * The most basic button\n           * \n           * In a block!\n           */\n          export const Basic = () => <Button />\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        export default {\n          title: 'Button'\n        };\n        export const Basic = () => React.createElement(Button);\n        Basic.parameters = {\n          ...Basic.parameters,\n          docs: {\n            ...Basic.parameters?.docs,\n            source: {\n              originalSource: \"() => <Button />\",\n              ...Basic.parameters?.docs?.source\n            },\n            description: {\n              story: \"The most basic button\\\\n\\\\nIn a block!\",\n              ...Basic.parameters?.docs?.description\n            }\n          }\n        };\n      `);\n    });\n\n    it('preserves indentation', async () => {\n      expect(\n        await enrich(\n          dedent`\n          // compiled code\n          export default {\n           title: 'Button',\n          }\n          export const Basic = () => React.createElement(Button);\n        `,\n          dedent`\n        // original code\n        export default {\n         title: 'Button',\n        }\n        /**\n         * - A bullet list\n         *   - A sub-bullet\n         * - A second bullet\n         */\n        export const Basic = () => <Button />\n      `\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        export default {\n          title: 'Button'\n        };\n        export const Basic = () => React.createElement(Button);\n        Basic.parameters = {\n          ...Basic.parameters,\n          docs: {\n            ...Basic.parameters?.docs,\n            source: {\n              originalSource: \"() => <Button />\",\n              ...Basic.parameters?.docs?.source\n            },\n            description: {\n              story: \"- A bullet list\\\\n  - A sub-bullet\\\\n- A second bullet\",\n              ...Basic.parameters?.docs?.description\n            }\n          }\n        };\n      `);\n    });\n  });\n\n  describe('meta descriptions', () => {\n    it('skips inline comments', async () => {\n      expect(\n        await enrich(\n          dedent`\n        // compiled code\n        export default {\n          title: 'Button',\n        }\n        export const Basic = () => React.createElement(Button);\n        `,\n          dedent`\n        // original code\n        // The most basic button\n        export default {\n          title: 'Button',\n        }\n        export const Basic = () => <Button />\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        export default {\n          title: 'Button'\n        };\n        export const Basic = () => React.createElement(Button);\n        Basic.parameters = {\n          ...Basic.parameters,\n          docs: {\n            ...Basic.parameters?.docs,\n            source: {\n              originalSource: \"() => <Button />\",\n              ...Basic.parameters?.docs?.source\n            }\n          }\n        };\n      `);\n    });\n\n    it('skips blocks without jsdoc', async () => {\n      expect(\n        await enrich(\n          dedent`\n        // compiled code\n        export default {\n         title: 'Button',\n        }\n        export const Basic = () => React.createElement();\n      `,\n          dedent`\n          // original code\n          /* The most basic button */\n          export default {\n           title: 'Button',\n          }\n          export const Basic = () => <Button />\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        export default {\n          title: 'Button'\n        };\n        export const Basic = () => React.createElement();\n        Basic.parameters = {\n          ...Basic.parameters,\n          docs: {\n            ...Basic.parameters?.docs,\n            source: {\n              originalSource: \"() => <Button />\",\n              ...Basic.parameters?.docs?.source\n            }\n          }\n        };\n      `);\n    });\n\n    it('JSDoc single-line', async () => {\n      expect(\n        await enrich(\n          dedent`\n          // compiled code\n          export default {\n           title: 'Button'\n          }\n          export const Basic = () => React.createElement(Button)\n        `,\n          dedent`\n          // original code\n          /** The most basic button */\n          export default {\n           title: 'Button'\n          }\n          export const Basic = () => <Button />\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        export default {\n          title: 'Button',\n          parameters: {\n            docs: {\n              description: {\n                component: \"The most basic button\"\n              }\n            }\n          }\n        };\n        export const Basic = () => React.createElement(Button);\n        Basic.parameters = {\n          ...Basic.parameters,\n          docs: {\n            ...Basic.parameters?.docs,\n            source: {\n              originalSource: \"() => <Button />\",\n              ...Basic.parameters?.docs?.source\n            }\n          }\n        };\n      `);\n    });\n\n    it('JSDoc multi-line', async () => {\n      expect(\n        await enrich(\n          dedent`\n        // compiled code\n        export default {\n         title: 'Button',\n        }\n        export const Basic = () => React.createElement();\n      `,\n          dedent`\n          // original code\n          /**\n           * The most basic button\n           * \n           * In a block!\n           */\n          export default {\n           title: 'Button',\n          }\n          export const Basic = () => <Button />\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        export default {\n          title: 'Button',\n          parameters: {\n            docs: {\n              description: {\n                component: \"The most basic button\\\\n\\\\nIn a block!\"\n              }\n            }\n          }\n        };\n        export const Basic = () => React.createElement();\n        Basic.parameters = {\n          ...Basic.parameters,\n          docs: {\n            ...Basic.parameters?.docs,\n            source: {\n              originalSource: \"() => <Button />\",\n              ...Basic.parameters?.docs?.source\n            }\n          }\n        };\n      `);\n    });\n\n    it('preserves indentation', async () => {\n      expect(\n        await enrich(\n          dedent`\n        // compiled code\n        export default {\n         title: 'Button',\n        }\n        export const Basic = () => React.createElement(Button);\n      `,\n          dedent`\n          // original code\n          /**\n           * - A bullet list\n           *   - A sub-bullet\n           * - A second bullet\n           */\n          export default {\n           title: 'Button',\n          }\n          export const Basic = () => <Button />\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        export default {\n          title: 'Button',\n          parameters: {\n            docs: {\n              description: {\n                component: \"- A bullet list\\\\n  - A sub-bullet\\\\n- A second bullet\"\n              }\n            }\n          }\n        };\n        export const Basic = () => React.createElement(Button);\n        Basic.parameters = {\n          ...Basic.parameters,\n          docs: {\n            ...Basic.parameters?.docs,\n            source: {\n              originalSource: \"() => <Button />\",\n              ...Basic.parameters?.docs?.source\n            }\n          }\n        };\n      `);\n    });\n\n    it('correctly interleaves parameters', async () => {\n      expect(\n        await enrich(\n          dedent`\n        // compiled code\n        export default {\n          title: 'Button',\n          parameters: {\n            foo: 'bar',\n            docs: { story: { inline: true } }\n          }\n        }\n        export const Basic = () => React.createElement(Button);\n      `,\n          dedent`\n          /** The most basic button */\n          export default {\n            title: 'Button',\n            parameters: {\n              foo: 'bar',\n              docs: { story: { inline: true } }\n            }\n          }\n          export const Basic = () => <Button />\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        export default {\n          title: 'Button',\n          parameters: {\n            foo: 'bar',\n            docs: {\n              story: {\n                inline: true\n              },\n              description: {\n                component: \"The most basic button\"\n              }\n            }\n          }\n        };\n        export const Basic = () => React.createElement(Button);\n        Basic.parameters = {\n          ...Basic.parameters,\n          docs: {\n            ...Basic.parameters?.docs,\n            source: {\n              originalSource: \"() => <Button />\",\n              ...Basic.parameters?.docs?.source\n            }\n          }\n        };\n      `);\n    });\n\n    it('respects user component description', async () => {\n      expect(\n        await enrich(\n          dedent`\n        // compiled code\n        export default {\n          title: 'Button',\n          parameters: {\n            docs: {\n              description: {\n                component: 'hahaha'\n              }\n            }\n          }\n        }\n        export const Basic = () => React.createElement(Button);\n      `,\n          dedent`\n          // original code\n          /** The most basic button */\n          export default {\n            title: 'Button',\n            parameters: {\n              docs: {\n                description: {\n                  component: 'hahaha'\n                }\n              }\n            }\n          }\n          export const Basic = () => <Button />\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        export default {\n          title: 'Button',\n          parameters: {\n            docs: {\n              description: {\n                component: 'hahaha'\n              }\n            }\n          }\n        };\n        export const Basic = () => React.createElement(Button);\n        Basic.parameters = {\n          ...Basic.parameters,\n          docs: {\n            ...Basic.parameters?.docs,\n            source: {\n              originalSource: \"() => <Button />\",\n              ...Basic.parameters?.docs?.source\n            }\n          }\n        };\n      `);\n    });\n\n    it('respects meta variables', async () => {\n      expect(\n        await enrich(\n          dedent`\n        // compiled code\n        const meta = {\n          title: 'Button'\n        }\n        export default meta;\n        export const Basic = () => React.createElement(Button);\n        `,\n          dedent`\n        // original code\n        /** The most basic button */\n        const meta = {\n          title: 'Button'\n        }\n        /** This should be ignored */\n        export default meta;\n        export const Basic = () => <Button />\n        `\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        const meta = {\n          title: 'Button',\n          parameters: {\n            docs: {\n              description: {\n                component: \"The most basic button\"\n              }\n            }\n          }\n        };\n        export default meta;\n        export const Basic = () => React.createElement(Button);\n        Basic.parameters = {\n          ...Basic.parameters,\n          docs: {\n            ...Basic.parameters?.docs,\n            source: {\n              originalSource: \"() => <Button />\",\n              ...Basic.parameters?.docs?.source\n            }\n          }\n        };\n      `);\n    });\n  });\n\n  describe('options', () => {\n    it('disableSource', async () => {\n      expect(\n        await enrich(\n          dedent`\n          // compiled code\n          export default {\n           title: 'Button',\n          }\n          export const Basic = () => React.createElement(Button);\n        `,\n          dedent`\n          // original code\n          export default {\n           title: 'Button',\n          }\n          /** The most basic button */\n          export const Basic = () => <Button />\n        `,\n          { disableSource: true }\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        export default {\n          title: 'Button'\n        };\n        export const Basic = () => React.createElement(Button);\n        Basic.parameters = {\n          ...Basic.parameters,\n          docs: {\n            ...Basic.parameters?.docs,\n            description: {\n              story: \"The most basic button\",\n              ...Basic.parameters?.docs?.description\n            }\n          }\n        };\n      `);\n    });\n\n    it('disableDescription', async () => {\n      expect(\n        await enrich(\n          dedent`\n          // compiled code\n          export default {\n           title: 'Button',\n          }\n          export const Basic = () => React.createElement(Button);\n        `,\n          dedent`\n          // original code\n          export default {\n           title: 'Button',\n          }\n          /** The most basic button */\n          export const Basic = () => <Button />\n        `,\n          { disableDescription: true }\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        export default {\n          title: 'Button'\n        };\n        export const Basic = () => React.createElement(Button);\n        Basic.parameters = {\n          ...Basic.parameters,\n          docs: {\n            ...Basic.parameters?.docs,\n            source: {\n              originalSource: \"() => <Button />\",\n              ...Basic.parameters?.docs?.source\n            }\n          }\n        };\n      `);\n    });\n\n    it('disable all', async () => {\n      expect(\n        await enrich(\n          dedent`\n          // compiled code\n          export default {\n           title: 'Button',\n          }\n          export const Basic = () => React.createElement(Button);\n        `,\n          dedent`\n          // original code\n          export default {\n           title: 'Button',\n          }\n          /** The most basic button */\n          export const Basic = () => <Button />\n        `,\n          { disableSource: true, disableDescription: true }\n        )\n      ).toMatchInlineSnapshot(`\n        // compiled code\n        export default {\n          title: 'Button'\n        };\n        export const Basic = () => React.createElement(Button);\n      `);\n    });\n  });\n});\n\nconst source = (csfExport: string) => {\n  const code = dedent`\n    export default { title: 'Button' }\n    ${csfExport}\n  `;\n  const csf = loadCsf(code, { makeTitle: (userTitle) => userTitle }).parse();\n  const exportNode = Object.values(csf._storyExports)[0];\n  return extractSource(exportNode);\n};\n\ndescribe('extractSource', () => {\n  it('csf1', () => {\n    expect(\n      source(dedent`\n        export const Basic = () => <Button />\n      `)\n    ).toMatchInlineSnapshot(`() => <Button />`);\n  });\n  it('csf2', () => {\n    expect(\n      source(dedent`\n        export const Basic =  (args) => <Button {...args} />;\n      `)\n    ).toMatchInlineSnapshot(`args => <Button {...args} />`);\n  });\n  it('csf3', () => {\n    expect(\n      source(dedent`\n        export const Basic = {\n          parameters: { foo: 'bar' }\n        }\n      `)\n    ).toMatchInlineSnapshot(`\n      {\n        parameters: {\n          foo: 'bar'\n        }\n      }\n    `);\n  });\n});\n"
  },
  {
    "path": "code/core/src/csf-tools/enrichCsf.ts",
    "content": "import { generate, types as t } from 'storybook/internal/babel';\nimport { type CsfEnricher } from 'storybook/internal/types';\n\nimport type { CsfFile } from './CsfFile.ts';\n\nexport interface EnrichCsfOptions {\n  disableSource?: boolean;\n  disableDescription?: boolean;\n  enrichCsf?: CsfEnricher;\n}\n\nexport const enrichCsfStory = (\n  csf: CsfFile,\n  csfSource: CsfFile,\n  key: string,\n  options?: EnrichCsfOptions\n) => {\n  const storyExport = csfSource.getStoryExport(key);\n  const isCsfFactory =\n    t.isCallExpression(storyExport) &&\n    t.isMemberExpression(storyExport.callee) &&\n    t.isIdentifier(storyExport.callee.object) &&\n    storyExport.callee.object.name === 'meta';\n  const source = !options?.disableSource && extractSource(storyExport);\n  const description =\n    !options?.disableDescription && extractDescription(csfSource._storyStatements[key]);\n  const parameters = [];\n  // in csf 1/2/3 use Story.parameters; CSF factories use Story.input.parameters\n  const baseStoryObject = isCsfFactory\n    ? t.memberExpression(t.identifier(key), t.identifier('input'))\n    : t.identifier(key);\n  const originalParameters = t.memberExpression(baseStoryObject, t.identifier('parameters'));\n  parameters.push(t.spreadElement(originalParameters));\n  const optionalDocs = t.optionalMemberExpression(\n    originalParameters,\n    t.identifier('docs'),\n    false,\n    true\n  );\n  const extraDocsParameters = [];\n\n  // docs: { source: { originalSource: %%source%% } },\n  if (source) {\n    const optionalSource = t.optionalMemberExpression(\n      optionalDocs,\n      t.identifier('source'),\n      false,\n      true\n    );\n\n    extraDocsParameters.push(\n      t.objectProperty(\n        t.identifier('source'),\n        t.objectExpression([\n          t.objectProperty(t.identifier('originalSource'), t.stringLiteral(source)),\n          t.spreadElement(optionalSource),\n        ])\n      )\n    );\n  }\n\n  // docs: { description: { story: %%description%% } },\n  if (description) {\n    const optionalDescription = t.optionalMemberExpression(\n      optionalDocs,\n      t.identifier('description'),\n      false,\n      true\n    );\n    extraDocsParameters.push(\n      t.objectProperty(\n        t.identifier('description'),\n        t.objectExpression([\n          t.objectProperty(t.identifier('story'), t.stringLiteral(description)),\n          t.spreadElement(optionalDescription),\n        ])\n      )\n    );\n  }\n\n  if (extraDocsParameters.length > 0) {\n    parameters.push(\n      t.objectProperty(\n        t.identifier('docs'),\n        t.objectExpression([t.spreadElement(optionalDocs), ...extraDocsParameters])\n      )\n    );\n    const addParameter = t.expressionStatement(\n      t.assignmentExpression('=', originalParameters, t.objectExpression(parameters))\n    );\n    csf._ast.program.body.push(addParameter);\n  }\n};\n\nconst addComponentDescription = (\n  node: t.ObjectExpression,\n  path: string[],\n  value: t.ObjectProperty\n) => {\n  if (!path.length) {\n    const hasExistingComponent = node.properties.find(\n      (p) => t.isObjectProperty(p) && t.isIdentifier(p.key) && p.key.name === 'component'\n    );\n    if (!hasExistingComponent) {\n      // make this the lowest-priority so that if the user is object-spreading on top of it,\n      // the users' code will \"win\"\n      node.properties.unshift(value);\n    }\n    return;\n  }\n  const [first, ...rest] = path;\n  const existing = node.properties.find(\n    (p) =>\n      t.isObjectProperty(p) &&\n      t.isIdentifier(p.key) &&\n      p.key.name === first &&\n      t.isObjectExpression(p.value)\n  );\n  let subNode: t.ObjectExpression;\n  if (existing) {\n    subNode = (existing as t.ObjectProperty).value as t.ObjectExpression;\n  } else {\n    subNode = t.objectExpression([]);\n    node.properties.push(t.objectProperty(t.identifier(first), subNode));\n  }\n  addComponentDescription(subNode, rest, value);\n};\n\nexport const enrichCsfMeta = (csf: CsfFile, csfSource: CsfFile, options?: EnrichCsfOptions) => {\n  const description = !options?.disableDescription && extractDescription(csfSource._metaStatement);\n  // docs: { description: { component: %%description%% } },\n  if (description) {\n    const metaNode = csf._metaNode;\n    if (metaNode && t.isObjectExpression(metaNode)) {\n      addComponentDescription(\n        metaNode,\n        ['parameters', 'docs', 'description'],\n        t.objectProperty(t.identifier('component'), t.stringLiteral(description))\n      );\n    }\n  }\n};\n\nexport const enrichCsf = async (csf: CsfFile, csfSource: CsfFile, options?: EnrichCsfOptions) => {\n  enrichCsfMeta(csf, csfSource, options);\n  await options?.enrichCsf?.(csf, csfSource);\n  Object.keys(csf._storyExports).forEach((key) => {\n    enrichCsfStory(csf, csfSource, key, options);\n  });\n};\n\nexport const extractSource = (node: t.Node) => {\n  const src = t.isVariableDeclarator(node) ? node.init : node;\n  const { code } = generate(src as t.Node, {});\n  return code;\n};\n\nexport const extractDescription = (node?: t.Node) => {\n  if (!node?.leadingComments) {\n    return '';\n  }\n  const comments = node.leadingComments\n    .map((comment) => {\n      if (comment.type === 'CommentLine' || !comment.value.startsWith('*')) {\n        return null;\n      }\n      return (\n        comment.value\n          .split('\\n')\n          // remove leading *'s and spaces from the beginning of each line\n          .map((line) => line.replace(/^(\\s+)?(\\*+)?(\\s)?/, ''))\n          .join('\\n')\n          .trim()\n      );\n    })\n    .filter(Boolean);\n  return comments.join('\\n');\n};\n"
  },
  {
    "path": "code/core/src/csf-tools/findVarInitialization.ts",
    "content": "import { types as t } from 'storybook/internal/babel';\n\nexport const findVarInitialization = (identifier: string, program: t.Program): t.Expression => {\n  let init: t.Expression = null as any;\n  let declarations: t.VariableDeclarator[] = null as any;\n  program.body.find((node: t.Node) => {\n    if (t.isVariableDeclaration(node)) {\n      declarations = node.declarations;\n    } else if (t.isExportNamedDeclaration(node) && t.isVariableDeclaration(node.declaration)) {\n      declarations = node.declaration.declarations;\n    }\n\n    return (\n      declarations &&\n      declarations.find((decl: t.Node) => {\n        if (\n          t.isVariableDeclarator(decl) &&\n          t.isIdentifier(decl.id) &&\n          decl.id.name === identifier\n        ) {\n          init = decl.init as t.Expression;\n          return true; // stop looking\n        }\n        return false;\n      })\n    );\n  });\n  return init;\n};\n"
  },
  {
    "path": "code/core/src/csf-tools/getStorySortParameter.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { dedent } from 'ts-dedent';\n\nimport { getStorySortParameter } from './getStorySortParameter.ts';\n\ndescribe('getStorySortParameter', () => {\n  describe('named exports', () => {\n    describe('supported', () => {\n      it('no parameters', () => {\n        expect(\n          getStorySortParameter(dedent`\n          export const decorators = [];\n        `)\n        ).toBeUndefined();\n      });\n\n      it('no storySort parameter', () => {\n        expect(\n          getStorySortParameter(dedent`\n          export const parameters = {\n            layout: 'fullscreen',\n          };\n        `)\n        ).toBeUndefined();\n      });\n\n      it('with wildcards', () => {\n        expect(\n          getStorySortParameter(dedent`\n          export const parameters = {\n            options: {\n              storySort: [\n                \"Intro\",\n                \"Pages\",\n                [\"Home\", \"Login\", \"Admin\"],\n                \"Components\",\n                \"*\",\n                \"WIP\",    \n              ]\n            }\n          };\n        `)\n        ).toMatchInlineSnapshot(`\n          [\n            \"Intro\",\n            \"Pages\",\n            [\n              \"Home\",\n              \"Login\",\n              \"Admin\",\n            ],\n            \"Components\",\n            \"*\",\n            \"WIP\",\n          ]\n        `);\n      });\n\n      it('arrow function', () => {\n        expect(\n          getStorySortParameter(dedent`\n          export const parameters = {\n            options: {\n              storySort: (a, b) =>\n                a[1].kind === b[1].kind\n                  ? 0\n                  : a[1].id.localeCompare(b[1].id, undefined, { numeric: true }),\n            },\n          };\n        `)\n        ).toMatchInlineSnapshot(`[Function]`);\n      });\n\n      it('function', () => {\n        expect(\n          getStorySortParameter(dedent`\n          export const parameters = {\n            options: {\n              storySort: function sortStories(a, b) {\n                return a[1].kind === b[1].kind\n                  ? 0\n                  : a[1].id.localeCompare(b[1].id, undefined, { numeric: true });\n              },\n            },\n          };\n        `)\n        ).toMatchInlineSnapshot(`[Function]`);\n      });\n\n      it('empty sort', () => {\n        expect(\n          getStorySortParameter(dedent`\n          export const parameters = {\n            options: {\n              storySort: {\n                method: \"\",\n                order: [],\n                locales: \"\",\n              },\n            },\n          };\n        `)\n        ).toMatchInlineSnapshot(`\n          {\n            \"locales\": \"\",\n            \"method\": \"\",\n            \"order\": [],\n          }\n        `);\n      });\n\n      it('parameters typescript', () => {\n        expect(\n          getStorySortParameter(dedent`\n          export const parameters = {\n            options: {\n              storySort: {\n                method: \"\",\n                order: [],\n                locales: \"\",\n              },\n            },\n          } as Parameters;\n        `)\n        ).toMatchInlineSnapshot(`\n          {\n            \"locales\": \"\",\n            \"method\": \"\",\n            \"order\": [],\n          }\n        `);\n      });\n\n      it('parameters typescript satisfies', () => {\n        expect(\n          getStorySortParameter(dedent`\n          export const parameters = {\n            options: {\n              storySort: {\n                method: \"\",\n                order: [],\n                locales: \"\",\n              },\n            },\n          } satisfies Parameters;\n        `)\n        ).toMatchInlineSnapshot(`\n          {\n            \"locales\": \"\",\n            \"method\": \"\",\n            \"order\": [],\n          }\n        `);\n      });\n    });\n\n    describe('unsupported', () => {\n      it('invalid parameters', () => {\n        expect(\n          getStorySortParameter(dedent`\n          export const parameters = [];\n        `)\n        ).toBeUndefined();\n      });\n\n      it('parameters var', () => {\n        expect(\n          getStorySortParameter(dedent`\n          const parameters = {\n            options: {\n              storySort: {\n                method: \"\",\n                order: [],\n                locales: \"\",\n              },\n            },\n          };\n          export { parameters };\n      `)\n        ).toBeUndefined();\n      });\n\n      it('options var', () => {\n        expect(() =>\n          getStorySortParameter(dedent`\n          const options = {\n            storySort: {\n              method: \"\",\n              order: [],\n              locales: \"\",\n            },\n          };\n          export const parameters = {\n            options,\n          };\n      `)\n        ).toThrowErrorMatchingInlineSnapshot(`\n          [Error: Unexpected 'options'. Parameter 'options.storySort' should be defined inline e.g.:\n\nexport default {\n  parameters: {\n    options: {\n      storySort: <array | object | function>\n    },\n  },\n};]\n`);\n      });\n\n      it('storySort var', () => {\n        expect(() =>\n          getStorySortParameter(dedent`\n          const storySort = {\n            method: \"\",\n            order: [],\n            locales: \"\",\n          };\n          export const parameters = {\n            options: {\n              storySort,\n            },\n          };\n      `)\n        ).toThrowErrorMatchingInlineSnapshot(`\n          [Error: Unexpected 'storySort'. Parameter 'options.storySort' should be defined inline e.g.:\n\nexport default {\n  parameters: {\n    options: {\n      storySort: <array | object | function>\n    },\n  },\n};]\n        `);\n      });\n\n      it('order var', () => {\n        expect(() =>\n          getStorySortParameter(dedent`\n          const order = [];\n          export const parameters = {\n            options: {\n              storySort: {\n                method: \"\",\n                order,\n                locales: \"\",\n              }\n            },\n          };\n      `)\n        ).toThrowErrorMatchingInlineSnapshot(`\n          [Error: Unexpected 'order'. Parameter 'options.storySort' should be defined inline e.g.:\n\nexport default {\n  parameters: {\n    options: {\n      storySort: <array | object | function>\n    },\n  },\n};]\n`);\n      });\n    });\n  });\n\n  describe('default export', () => {\n    describe('supported', () => {\n      it('inline', () => {\n        expect(\n          getStorySortParameter(dedent`\n          export default {\n            parameters: {\n              options: {\n                storySort: [\n                  \"Intro\",\n                  \"*\",\n                  \"WIP\",    \n                ]\n              }\n            }\n          };\n        `)\n        ).toMatchInlineSnapshot(`\n          [\n            \"Intro\",\n            \"*\",\n            \"WIP\",\n          ]\n        `);\n      });\n\n      it('no storysort', () => {\n        expect(\n          getStorySortParameter(dedent`\n          const config = {\n            controls: {\n              matchers: {\n                color: /(background|color)$/i,\n                date: /Date$/,\n              },\n            },\n          }\n          \n          export default config\n        `)\n        ).toBeUndefined();\n      });\n\n      it('variable parameters without storysort', () => {\n        expect(\n          getStorySortParameter(dedent`\n          const parameters = {\n            controls: {\n              matchers: {\n                color: /(background|color)$/i,\n                date: /Date$/,\n              },\n            },\n          };\n\n          const preview = {\n            parameters,\n          };\n          export default preview;\n        `)\n        ).toBeUndefined();\n      });\n\n      it('variable parameters with storysort', () => {\n        expect(\n          getStorySortParameter(dedent`\n          const parameters = {\n            options: {\n              storySort: [\n                \"Intro\",\n                \"*\",\n                \"WIP\",    \n              ]\n            }\n          };\n\n          const preview = {\n            parameters,\n          };\n          export default preview;\n        `)\n        ).toMatchInlineSnapshot(`\n          [\n            \"Intro\",\n            \"*\",\n            \"WIP\",\n          ]\n        `);\n      });\n\n      it('inline typescript', () => {\n        expect(\n          getStorySortParameter(dedent`\n          export default {\n            parameters: {\n              options: {\n                storySort: [\n                  \"Intro\",\n                  \"*\",\n                  \"WIP\",    \n                ]\n              }\n            }\n          } satisfies Preview;\n        `)\n        ).toMatchInlineSnapshot(`\n          [\n            \"Intro\",\n            \"*\",\n            \"WIP\",\n          ]\n        `);\n      });\n\n      it('variable', () => {\n        expect(\n          getStorySortParameter(dedent`\n          const preview = {\n            parameters: {\n              options: {\n                storySort: [\n                  \"Intro\",\n                  \"*\",\n                  \"WIP\",    \n                ]\n              }\n            }\n          };\n          export default preview;\n        `)\n        ).toMatchInlineSnapshot(`\n          [\n            \"Intro\",\n            \"*\",\n            \"WIP\",\n          ]\n        `);\n      });\n\n      it('typescript var', () => {\n        expect(\n          getStorySortParameter(dedent`\n          const preview: Preview = {\n            parameters: {\n              options: {\n                storySort: [\n                  \"Intro\",\n                  \"*\",\n                  \"WIP\",    \n                ]\n              }\n            }\n          };\n          export default preview;\n        `)\n        ).toMatchInlineSnapshot(`\n          [\n            \"Intro\",\n            \"*\",\n            \"WIP\",\n          ]\n        `);\n      });\n\n      it('typescript satisfies var', () => {\n        expect(\n          getStorySortParameter(dedent`\n          const preview = {\n            parameters: {\n              options: {\n                storySort: [\n                  \"Intro\",\n                  \"*\",\n                  \"WIP\",    \n                ]\n              }\n            }\n          } satisfies Preview;\n          export default preview;\n        `)\n        ).toMatchInlineSnapshot(`\n          [\n            \"Intro\",\n            \"*\",\n            \"WIP\",\n          ]\n        `);\n      });\n\n      it('storysort satisfies inline', () => {\n        expect(\n          getStorySortParameter(dedent`\n          enum ComponentGroups {\n            General = 'General'\n          }\n          export default {\n            parameters: {\n              options: {\n                storySort: {\n                  order: ['General'] satisfies ComponentGroups[]\n                }\n              }\n            }\n          };\n        `)\n        ).toMatchInlineSnapshot(`\n          {\n            \"order\": [\n              \"General\",\n            ],\n          }\n        `);\n      });\n      describe('csf factories', () => {\n        it('inline storysort in default export', () => {\n          expect(\n            getStorySortParameter(dedent`\n              export default definePreview({\n                parameters: {\n                  options: {\n                    storySort: {\n                      order: ['General']\n                    }\n                  },\n                },\n              });\n          `)\n          ).toMatchInlineSnapshot(`\n            {\n              \"order\": [\n                \"General\",\n              ],\n            }\n          `);\n        });\n        it('variable reference in default export', () => {\n          expect(\n            getStorySortParameter(dedent`\n              const parameters = {\n                options: {\n                  storySort: {\n                    order: ['General']\n                  }\n                },\n              };\n              export default definePreview({\n                parameters,\n              });\n          `)\n          ).toMatchInlineSnapshot(`\n            {\n              \"order\": [\n                \"General\",\n              ],\n            }\n          `);\n        });\n      });\n    });\n    describe('unsupported', () => {\n      it('bad default export', () => {\n        expect(\n          getStorySortParameter(dedent`\n          export default 'foo';\n        `)\n        ).toBeUndefined();\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/csf-tools/getStorySortParameter.ts",
    "content": "import { babelParse, generate, types as t, traverse } from 'storybook/internal/babel';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { dedent } from 'ts-dedent';\n\nimport { findVarInitialization } from './findVarInitialization.ts';\n\nconst getValue = (obj: t.ObjectExpression, key: string) => {\n  let value: t.Expression | undefined;\n  (obj.properties as t.ObjectProperty[]).forEach((p) => {\n    if (t.isIdentifier(p.key) && p.key.name === key) {\n      value = p.value as t.Expression;\n    }\n  });\n  return value;\n};\n\nconst parseValue = (value: t.Expression): any => {\n  const expr = stripTSModifiers(value);\n\n  if (t.isArrayExpression(expr)) {\n    return (expr.elements as t.Expression[]).map((o) => {\n      return parseValue(o);\n    });\n  }\n  if (t.isObjectExpression(expr)) {\n    return (expr.properties as t.ObjectProperty[]).reduce((acc, p) => {\n      if (t.isIdentifier(p.key)) {\n        acc[p.key.name] = parseValue(p.value as t.Expression);\n      }\n      return acc;\n    }, {} as any);\n  }\n  if (t.isLiteral(expr)) {\n    // @ts-expect-error (Converted from ts-ignore)\n    return expr.value;\n  }\n  if (t.isIdentifier(expr)) {\n    return unsupported(expr.name, true);\n  }\n  throw new Error(`Unknown node type ${expr.type}`);\n};\n\nconst unsupported = (unexpectedVar: string, isError: boolean) => {\n  const message = dedent`\n    Unexpected '${unexpectedVar}'. Parameter 'options.storySort' should be defined inline e.g.:\n\n    export default {\n      parameters: {\n        options: {\n          storySort: <array | object | function>\n        },\n      },\n    };\n  `;\n  if (isError) {\n    throw new Error(message);\n  } else {\n    logger.log(message);\n  }\n};\n\nconst stripTSModifiers = (expr: t.Expression): t.Expression =>\n  t.isTSAsExpression(expr) || t.isTSSatisfiesExpression(expr) ? expr.expression : expr;\n\nconst parseParameters = (params: t.Expression): t.Expression | undefined => {\n  const paramsObject = stripTSModifiers(params);\n  if (t.isObjectExpression(paramsObject)) {\n    const options = getValue(paramsObject, 'options');\n    if (options) {\n      if (t.isObjectExpression(options)) {\n        return getValue(options, 'storySort');\n      }\n      unsupported('options', true);\n    }\n  }\n  return undefined;\n};\n\nconst parseDefault = (defaultExpr: t.Expression, program: t.Program): t.Expression | undefined => {\n  const defaultObj = stripTSModifiers(defaultExpr);\n  if (t.isObjectExpression(defaultObj)) {\n    let params = getValue(defaultObj, 'parameters');\n    if (t.isIdentifier(params)) {\n      params = findVarInitialization(params.name, program);\n    }\n    if (params) {\n      return parseParameters(params);\n    }\n  } else {\n    unsupported('default', true);\n  }\n  return undefined;\n};\n\nexport const getStorySortParameter = (previewCode: string) => {\n  // don't even try to process the file\n  if (!previewCode.includes('storySort')) {\n    return undefined;\n  }\n\n  let storySort: t.Expression | undefined;\n  const ast = babelParse(previewCode);\n  traverse(ast, {\n    ExportNamedDeclaration: {\n      enter({ node }) {\n        if (t.isVariableDeclaration(node.declaration)) {\n          node.declaration.declarations.forEach((decl) => {\n            if (t.isVariableDeclarator(decl) && t.isIdentifier(decl.id)) {\n              const { name: exportName } = decl.id;\n              if (exportName === 'parameters' && decl.init) {\n                const paramsObject = stripTSModifiers(decl.init);\n                storySort = parseParameters(paramsObject);\n              }\n            }\n          });\n        } else {\n          node.specifiers.forEach((spec) => {\n            if (t.isIdentifier(spec.exported) && spec.exported.name === 'parameters') {\n              unsupported('parameters', false);\n            }\n          });\n        }\n      },\n    },\n    ExportDefaultDeclaration: {\n      enter({ node }) {\n        let defaultObj = node.declaration as t.Expression;\n        if (t.isIdentifier(defaultObj)) {\n          defaultObj = findVarInitialization(defaultObj.name, ast.program);\n        }\n        defaultObj = stripTSModifiers(defaultObj);\n        // parse the call arg when using definePreview({ ... })\n        if (t.isCallExpression(defaultObj) && t.isObjectExpression(defaultObj.arguments?.[0])) {\n          storySort = parseDefault(defaultObj.arguments[0], ast.program);\n        } else if (t.isObjectExpression(defaultObj)) {\n          storySort = parseDefault(defaultObj, ast.program);\n        } else {\n          unsupported('default', false);\n        }\n      },\n    },\n  });\n\n  if (!storySort) {\n    return undefined;\n  }\n\n  if (t.isArrowFunctionExpression(storySort)) {\n    const { code: sortCode } = generate(storySort, {});\n\n    return (0, eval)(sortCode);\n  }\n\n  if (t.isFunctionExpression(storySort)) {\n    const { code: sortCode } = generate(storySort, {});\n    const functionName = storySort.id?.name;\n    // Wrap the function within an arrow function, call it, and return\n    const wrapper = `(a, b) => {\n      ${sortCode};\n      return ${functionName}(a, b)\n    }`;\n\n    return (0, eval)(wrapper);\n  }\n\n  if (t.isLiteral(storySort) || t.isArrayExpression(storySort) || t.isObjectExpression(storySort)) {\n    return parseValue(storySort);\n  }\n\n  return unsupported('storySort', true);\n};\n"
  },
  {
    "path": "code/core/src/csf-tools/index.ts",
    "content": "export * from './CsfFile.ts';\nexport * from './ConfigFile.ts';\nexport * from './getStorySortParameter.ts';\nexport * from './enrichCsf.ts';\nexport { babelParse } from 'storybook/internal/babel';\nexport { vitestTransform } from './vitest-plugin/transformer.ts';\nexport { componentTransform } from './vitest-plugin/component-transformer.ts';\n"
  },
  {
    "path": "code/core/src/csf-tools/storyIndexer.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { loadCsf } from './CsfFile.ts';\n\nconst getIndex = (code: string) => {\n  const inputs = loadCsf(code, { makeTitle: () => 'title', fileName: 'a.stories.ts' }).parse()\n    .indexInputs;\n\n  return {\n    raw: inputs,\n    entries: inputs.map((i) => i.name),\n  };\n};\n\ndescribe('test fn', () => {\n  it('indexes CSF v1 to v3 stories', () => {\n    const { entries } = getIndex(\n      `\n          export default { component: 'foo' };\n          export const CSF1 = () => 'foo';\n          export const CSF2 = (args) => 'foo';\n          export const CSF3 = {};\n          export const CustomName = {\n            name: 'Custom name',\n          };\n        `\n    );\n    expect(entries).toMatchInlineSnapshot(`\n      [\n        \"CSF 1\",\n        \"CSF 2\",\n        \"CSF 3\",\n        \"Custom name\",\n      ]\n    `);\n  });\n\n  it('indexes test functions', () => {\n    const { entries } = getIndex(\n      `\n          import { config } from '#.storybook/preview'\n          const meta = config.meta({ component: 'foo' });\n          export const A = meta.story({})\n          A.test('async test function', async () => {})\n          A.test('sync test function', () => {})\n          A.test('with overrides', { args: { label: 'bar' } }, () => {})\n          const reference = () => {}\n          A.test('with function reference', reference)\n        `\n    );\n    expect(entries).toMatchInlineSnapshot(`\n      [\n        \"A\",\n        \"async test function\",\n        \"sync test function\",\n        \"with overrides\",\n        \"with function reference\",\n      ]\n    `);\n  });\n});\n"
  },
  {
    "path": "code/core/src/csf-tools/vitest-plugin/component-transformer.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { componentTransform } from './component-transformer.ts';\n\nconst transform = async ({\n  code,\n  fileName = 'src/components/Badge.tsx',\n}: {\n  code: string;\n  fileName?: string;\n}) => {\n  return componentTransform({ code, fileName });\n};\n\ndescribe('component transformer', () => {\n  it('adds a vitest test for a named component export', async () => {\n    const code = `\n      import { Body } from '../typography';\n\n      export const Badge = ({ text }: { text: string }) => (\n        <div>\n          <Body>{text}</Body>\n        </div>\n      );\n    `;\n\n    const result = await transform({ code });\n\n    expect(result.code).toContain('import { test as _test, expect as _expect } from \"vitest\";');\n    expect(result.code).toContain('import { testStory as _testStory, convertToFilePath }');\n    expect(result.code).toContain('meta: {');\n    expect(result.code).toContain('component: Badge');\n    expect(result.code).toContain('_test(\"Badge\", _testStory({');\n\n    expect(result.code).toMatchInlineSnapshot(`\n      \"import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n      import { test as _test, expect as _expect } from \"vitest\";\n      import { Body } from '../typography';\n      export const Badge = ({\n        text\n      }: {\n        text: string;\n      }) => <div>\n                <Body>{text}</Body>\n              </div>;\n      const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n      if (_isRunningFromThisFile) {\n        _test(\"Badge\", _testStory({\n          exportName: \"Badge\",\n          story: {\n            args: {}\n          },\n          meta: {\n            title: \"generated/tests/Badge\",\n            component: Badge\n          },\n          skipTags: [],\n          storyId: \"generated-Badge\",\n          componentPath: \"src/components/Badge.tsx\",\n          componentName: \"Badge\"\n        }));\n      }\"\n    `);\n  });\n\n  it('wraps a default inline component export by hoisting it to a const first', async () => {\n    const code = `\n      export default () => <div />;\n    `;\n\n    const result = await transform({ code, fileName: 'src/components/Spinner.tsx' });\n\n    expect(result.code).toContain('const _Spinner = () => <div />;');\n    expect(result.code).toContain('export default _Spinner;');\n    expect(result.code).toContain('_test(\"Spinner\", _testStory({');\n\n    expect(result.code).toMatchInlineSnapshot(`\n      \"import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n      import { test as _test, expect as _expect } from \"vitest\";\n      const _Spinner = () => <div />;\n      export default _Spinner;\n      const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n      if (_isRunningFromThisFile) {\n        _test(\"Spinner\", _testStory({\n          exportName: \"Spinner\",\n          story: {\n            args: {}\n          },\n          meta: {\n            title: \"generated/tests/Spinner\",\n            component: _Spinner\n          },\n          skipTags: [],\n          storyId: \"generated-Spinner\",\n          componentPath: \"src/components/Spinner.tsx\",\n          componentName: \"_Spinner\"\n        }));\n      }\"\n    `);\n  });\n\n  it('generates tests for wrapped exports', async () => {\n    const code = `\n      import { someWrapper } from '../lib/util';\n      function Component() {}\n\n      export default someWrapper(Component);\n\n      export function withErrorBoundary<P extends object, R>(\n        Component: ComponentType<P>,\n      ) {\n        return forwardRef<R, P>(function WithErrorBoundary(props, ref) {\n          return (\n            <ErrorBoundary>\n              <Component {...props} ref={ref} />\n            </ErrorBoundary>\n          )\n        })\n      }\n      \n      export const FancyButton = React.forwardRef((props, ref) => (\n        <button ref={ref}>\n          {props.children}\n        </button>\n      ));\n\n      export const Label = memo(() => <div />);\n      \n      export {\n        Label,\n      };\n    `;\n\n    const result = await transform({ code, fileName: 'src/components/Spinner.tsx' });\n\n    expect(result.code).toContain('const _Spinner = someWrapper(Component);');\n    expect(result.code).toContain('export default _Spinner;');\n    expect(result.code).toContain('_test(\"Spinner\", _testStory({');\n\n    expect(result.code).toMatchInlineSnapshot(`\n      \"import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n      import { test as _test, expect as _expect } from \"vitest\";\n      import { someWrapper } from '../lib/util';\n      function Component() {}\n      const _Spinner = someWrapper(Component);\n      export default _Spinner;\n      export function withErrorBoundary<P extends object, R>(Component: ComponentType<P>) {\n        return forwardRef<R, P>(function WithErrorBoundary(props, ref) {\n          return <ErrorBoundary>\n                    <Component {...props} ref={ref} />\n                  </ErrorBoundary>;\n        });\n      }\n      export const FancyButton = React.forwardRef((props, ref) => <button ref={ref}>\n                {props.children}\n              </button>);\n      export const Label = memo(() => <div />);\n      export { Label };\n      const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n      if (_isRunningFromThisFile) {\n        _test(\"Spinner\", _testStory({\n          exportName: \"Spinner\",\n          story: {\n            args: {}\n          },\n          meta: {\n            title: \"generated/tests/Spinner\",\n            component: _Spinner\n          },\n          skipTags: [],\n          storyId: \"generated-Spinner\",\n          componentPath: \"src/components/Spinner.tsx\",\n          componentName: \"_Spinner\"\n        }));\n        _test(\"withErrorBoundary\", _testStory({\n          exportName: \"withErrorBoundary\",\n          story: {\n            args: {}\n          },\n          meta: {\n            title: \"generated/tests/withErrorBoundary\",\n            component: withErrorBoundary\n          },\n          skipTags: [],\n          storyId: \"generated-withErrorBoundary\",\n          componentPath: \"src/components/Spinner.tsx\",\n          componentName: \"withErrorBoundary\"\n        }));\n        _test(\"FancyButton\", _testStory({\n          exportName: \"FancyButton\",\n          story: {\n            args: {}\n          },\n          meta: {\n            title: \"generated/tests/FancyButton\",\n            component: FancyButton\n          },\n          skipTags: [],\n          storyId: \"generated-FancyButton\",\n          componentPath: \"src/components/Spinner.tsx\",\n          componentName: \"FancyButton\"\n        }));\n        _test(\"Label\", _testStory({\n          exportName: \"Label\",\n          story: {\n            args: {}\n          },\n          meta: {\n            title: \"generated/tests/Label\",\n            component: Label\n          },\n          skipTags: [],\n          storyId: \"generated-Label\",\n          componentPath: \"src/components/Spinner.tsx\",\n          componentName: \"Label\"\n        }));\n        _test(\"Label\", _testStory({\n          exportName: \"Label\",\n          story: {\n            args: {}\n          },\n          meta: {\n            title: \"generated/tests/Label\",\n            component: Label\n          },\n          skipTags: [],\n          storyId: \"generated-Label\",\n          componentPath: \"src/components/Spinner.tsx\",\n          componentName: \"Label\"\n        }));\n      }\"\n    `);\n  });\n\n  it('generates tests for every exported component', async () => {\n    const code = `\n      export const Label = () => <div />;\n      export const Tag = () => <span />;\n      export default () => <div />;\n\n      const Input = () => <input />;\n      const Checkbox = () => <input type=\"checkbox\" />;\n      export {\n        Input,\n        Checkbox as CheckboxInput\n      };\n    `;\n\n    const result = await transform({ code, fileName: 'src/components/Badge.tsx' });\n\n    expect(result.code).toContain('_test(\"Badge\", _testStory({');\n    expect(result.code).toContain('_test(\"Tag\", _testStory({');\n    expect(result.code).toMatchInlineSnapshot(`\n      \"import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n      import { test as _test, expect as _expect } from \"vitest\";\n      export const Label = () => <div />;\n      export const Tag = () => <span />;\n      const _Badge = () => <div />;\n      export default _Badge;\n      const Input = () => <input />;\n      const Checkbox = () => <input type=\"checkbox\" />;\n      export { Input, Checkbox as CheckboxInput };\n      const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n      if (_isRunningFromThisFile) {\n        _test(\"Label\", _testStory({\n          exportName: \"Label\",\n          story: {\n            args: {}\n          },\n          meta: {\n            title: \"generated/tests/Label\",\n            component: Label\n          },\n          skipTags: [],\n          storyId: \"generated-Label\",\n          componentPath: \"src/components/Badge.tsx\",\n          componentName: \"Label\"\n        }));\n        _test(\"Tag\", _testStory({\n          exportName: \"Tag\",\n          story: {\n            args: {}\n          },\n          meta: {\n            title: \"generated/tests/Tag\",\n            component: Tag\n          },\n          skipTags: [],\n          storyId: \"generated-Tag\",\n          componentPath: \"src/components/Badge.tsx\",\n          componentName: \"Tag\"\n        }));\n        _test(\"Badge\", _testStory({\n          exportName: \"Badge\",\n          story: {\n            args: {}\n          },\n          meta: {\n            title: \"generated/tests/Badge\",\n            component: _Badge\n          },\n          skipTags: [],\n          storyId: \"generated-Badge\",\n          componentPath: \"src/components/Badge.tsx\",\n          componentName: \"_Badge\"\n        }));\n        _test(\"Input\", _testStory({\n          exportName: \"Input\",\n          story: {\n            args: {}\n          },\n          meta: {\n            title: \"generated/tests/Input\",\n            component: Input\n          },\n          skipTags: [],\n          storyId: \"generated-Input\",\n          componentPath: \"src/components/Badge.tsx\",\n          componentName: \"Input\"\n        }));\n        _test(\"CheckboxInput\", _testStory({\n          exportName: \"CheckboxInput\",\n          story: {\n            args: {}\n          },\n          meta: {\n            title: \"generated/tests/CheckboxInput\",\n            component: Checkbox\n          },\n          skipTags: [],\n          storyId: \"generated-CheckboxInput\",\n          componentPath: \"src/components/Badge.tsx\",\n          componentName: \"Checkbox\"\n        }));\n      }\"\n    `);\n  });\n\n  it('leaves non-component exports untouched', async () => {\n    const code = `\n      export const VALUES = [1, 2, 3];\n    `;\n\n    const result = await transform({ code, fileName: 'src/constants.ts' });\n\n    expect(result.code).toBe(code);\n  });\n\n  it('does not add fn import when no function placeholders exist', async () => {\n    const code = `\n      import { Body } from '../typography';\n\n      export const Badge = ({ text }: { text: string }) => (\n        <div>\n          <Body>{text}</Body>\n        </div>\n      );\n    `;\n\n    const mockGetComponentArgTypes = vi.fn().mockResolvedValue({\n      rating: { name: 'rating', type: { name: 'number' } },\n      photoUrl: { name: 'photoUrl', type: { name: 'string', required: true } },\n    });\n\n    const result = await componentTransform({\n      code,\n      fileName: 'src/components/Badge.tsx',\n      getComponentArgTypes: mockGetComponentArgTypes,\n    });\n\n    expect(result.code).not.toContain('import { fn as _fn } from \"storybook/test\"');\n  });\n\n  it('generates test with args from getComponentArgTypes', async () => {\n    const code = `\n      import { Body } from '../typography';\n\n      export const Badge = ({ text }: { text: string }) => (\n        <div>\n          <Body>{text}</Body>\n        </div>\n      );\n    `;\n\n    const mockGetComponentArgTypes = vi.fn().mockResolvedValue({\n      rating: { name: 'rating', type: { name: 'number' } },\n      photoUrl: { name: 'photoUrl', type: { name: 'string', required: true } },\n      onClick: { name: 'onClick', type: { name: 'function', required: true } },\n      someObject: {\n        name: 'someObject',\n        type: {\n          name: 'object',\n          value: {\n            category: { name: 'string' },\n            onClick: { name: 'function' },\n          },\n          required: true,\n        },\n      },\n    });\n\n    const result = await componentTransform({\n      code,\n      fileName: 'src/components/Badge.tsx',\n      getComponentArgTypes: mockGetComponentArgTypes,\n    });\n\n    expect(result.code).toContain('import { fn as _fn } from \"storybook/test\"');\n    expect(result.code).toMatchInlineSnapshot(`\n      \"import { fn as _fn } from \"storybook/test\";\n      import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n      import { test as _test, expect as _expect } from \"vitest\";\n      import { Body } from '../typography';\n      export const Badge = ({\n        text\n      }: {\n        text: string;\n      }) => <div>\n                <Body>{text}</Body>\n              </div>;\n      const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n      if (_isRunningFromThisFile) {\n        _test(\"Badge\", _testStory({\n          exportName: \"Badge\",\n          story: {\n            args: {\n              photoUrl: \"photoUrl\",\n              onClick: _fn(),\n              someObject: {\n                category: \"category\",\n                onClick: _fn()\n              }\n            }\n          },\n          meta: {\n            title: \"generated/tests/Badge\",\n            component: Badge\n          },\n          skipTags: [],\n          storyId: \"generated-Badge\",\n          componentPath: \"src/components/Badge.tsx\",\n          componentName: \"Badge\"\n        }));\n      }\"\n    `);\n  });\n\n  it('uses string literals for non-identifier object property keys', async () => {\n    const code = `\n      export const Badge = () => <div />;\n    `;\n\n    const mockGetComponentArgTypes = vi.fn().mockImplementation(({ componentName }) => {\n      if (componentName === 'Badge') {\n        return Promise.resolve({\n          'data-testid': { name: 'data-testid', type: { name: 'string', required: true } },\n          'aria-label': { name: 'aria-label', type: { name: 'string', required: true } },\n          '2invalid': { name: '2invalid', type: { name: 'string', required: true } },\n          validKey: { name: 'validKey', type: { name: 'string', required: true } },\n        });\n      }\n      return Promise.resolve({});\n    });\n\n    const result = await componentTransform({\n      code,\n      fileName: 'src/components/Badge.tsx',\n      getComponentArgTypes: mockGetComponentArgTypes,\n    });\n\n    // Check that the mock was called with the correct component name\n    expect(mockGetComponentArgTypes).toHaveBeenCalledWith({\n      componentName: 'Badge',\n      fileName: 'src/components/Badge.tsx',\n    });\n\n    // Check that non-identifier keys use string literals\n    expect(result.code).toContain('\"data-testid\": \"data-testid\"');\n    expect(result.code).toContain('\"aria-label\": \"aria-label\"');\n    expect(result.code).toContain('\"2invalid\": \"2invalid\"');\n    // Check that valid identifiers still use identifier syntax\n    expect(result.code).toContain('validKey: \"validKey\"');\n    expect(result.code).toMatchInlineSnapshot(`\n      \"import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n      import { test as _test, expect as _expect } from \"vitest\";\n      export const Badge = () => <div />;\n      const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n      if (_isRunningFromThisFile) {\n        _test(\"Badge\", _testStory({\n          exportName: \"Badge\",\n          story: {\n            args: {\n              \"data-testid\": \"data-testid\",\n              \"aria-label\": \"aria-label\",\n              \"2invalid\": \"2invalid\",\n              validKey: \"validKey\"\n            }\n          },\n          meta: {\n            title: \"generated/tests/Badge\",\n            component: Badge\n          },\n          skipTags: [],\n          storyId: \"generated-Badge\",\n          componentPath: \"src/components/Badge.tsx\",\n          componentName: \"Badge\"\n        }));\n      }\"\n    `);\n  });\n\n  it('correctly handles aliased function and class exports', async () => {\n    const code = `\n      function MyComponent() {\n        return <div />;\n      }\n\n      class MyClassComponent {\n        render() {\n          return <div />;\n        }\n      }\n\n      export { MyComponent as RenamedComponent, MyClassComponent as RenamedClass };\n    `;\n\n    const result = await transform({ code, fileName: 'src/components/Test.tsx' });\n\n    // Should use the exported names, not the original names\n    expect(result.code).toContain('_test(\"RenamedComponent\", _testStory({');\n    expect(result.code).toContain('exportName: \"RenamedComponent\"');\n    expect(result.code).toContain('_test(\"RenamedClass\", _testStory({');\n    expect(result.code).toContain('exportName: \"RenamedClass\"');\n  });\n});\n"
  },
  {
    "path": "code/core/src/csf-tools/vitest-plugin/component-transformer.ts",
    "content": "import path from 'node:path';\n\nimport {\n  BabelFileClass,\n  type NodePath,\n  babelParse,\n  generate,\n  types as t,\n  traverse,\n} from 'storybook/internal/babel';\nimport type { ArgTypes } from 'storybook/internal/csf';\n\nimport {\n  STORYBOOK_FN_PLACEHOLDER,\n  generateDummyArgsFromArgTypes,\n} from '../../core-server/utils/get-dummy-args-from-argtypes.ts';\nimport { createTestGuardDeclaration } from './transformer.ts';\n\nconst VITEST_IMPORT_SOURCE = 'vitest';\nconst TEST_UTILS_IMPORT_SOURCE = '@storybook/addon-vitest/internal/test-utils';\nconst STORYBOOK_TEST_IMPORT_SOURCE = 'storybook/test';\n\ntype ComponentExport = {\n  exportedName: string;\n  localIdentifier: t.Identifier;\n};\n\nconst sanitizeIdentifier = (value: string) => {\n  const sanitized = value.replace(/[^a-zA-Z0-9_$]+/g, '');\n  return sanitized || 'Component';\n};\n\nconst createComponentNameFromFileName = (fileName: string) => {\n  if (!fileName) {\n    return 'Component';\n  }\n\n  const basename = path.basename(fileName, path.extname(fileName));\n  return sanitizeIdentifier(basename);\n};\n\nconst containsJsxNode = (valuePath: NodePath<t.Node | null | undefined> | null) => {\n  if (!valuePath?.node) {\n    return false;\n  }\n\n  let found = false;\n  valuePath.traverse({\n    JSXElement(path) {\n      found = true;\n      path.stop();\n    },\n    JSXFragment(path) {\n      found = true;\n      path.stop();\n    },\n  });\n  return found;\n};\n\nconst unwrapExpression = (node: t.Node | null): t.Node | null => {\n  if (!node) {\n    return null;\n  }\n\n  if (t.isTSAsExpression(node) || t.isTSSatisfiesExpression(node)) {\n    return unwrapExpression(node.expression);\n  }\n\n  return node;\n};\n\nconst dedupeImports = (program: t.Program, source: string, specifiers: t.ImportSpecifier[]) => {\n  const existing = program.body.find(\n    (node) => t.isImportDeclaration(node) && node.source.value === source\n  ) as t.ImportDeclaration | undefined;\n\n  if (existing) {\n    specifiers.forEach((specifier) => {\n      if (\n        existing.specifiers.every(\n          (existingSpecifier) =>\n            !t.isImportSpecifier(existingSpecifier) ||\n            existingSpecifier.local.name !== specifier.local.name\n        )\n      ) {\n        existing.specifiers.push(specifier);\n      }\n    });\n    return;\n  }\n\n  program.body.unshift(t.importDeclaration(specifiers, t.stringLiteral(source)));\n};\n\n// Traverses the AST to find all exported components that contain JSX. Handles named exports,\n// default exports, and various declaration types.\nconst collectComponentExports = (program: t.Program, fileName: string) => {\n  const components: ComponentExport[] = [];\n\n  // Helper to add a component to the collection if it contains JSX\n  const addComponent = (\n    exportedName: string,\n    localIdentifier: t.Identifier,\n    valuePath: NodePath<t.Node | null | undefined> | null\n  ) => {\n    if (!valuePath || !valuePath.node) {\n      return;\n    }\n\n    const target = unwrapExpression(valuePath.node);\n    if (!target) {\n      return;\n    }\n\n    if (!containsJsxNode(valuePath)) {\n      return;\n    }\n\n    components.push({ exportedName, localIdentifier });\n  };\n\n  traverse(program, {\n    ExportNamedDeclaration(path) {\n      const { node } = path;\n      if (node.source) {\n        return;\n      }\n\n      const declarationPath = path.get('declaration');\n\n      if (declarationPath.isVariableDeclaration()) {\n        declarationPath.get('declarations').forEach((declPath) => {\n          if (!declPath.isVariableDeclarator()) {\n            return;\n          }\n          const id = declPath.node.id;\n          if (!t.isIdentifier(id)) {\n            return;\n          }\n          const initPath = declPath.get('init');\n          addComponent(id.name, id, initPath);\n        });\n      } else if (declarationPath.isFunctionDeclaration() && declarationPath.node.id) {\n        const declarationId = declarationPath.node.id;\n        if (t.isIdentifier(declarationId)) {\n          addComponent(declarationId.name, declarationId, declarationPath);\n        }\n      } else if (declarationPath.isClassDeclaration() && declarationPath.node.id) {\n        const declarationId = declarationPath.node.id;\n        if (t.isIdentifier(declarationId)) {\n          addComponent(declarationId.name, declarationId, declarationPath);\n        }\n      }\n\n      path.get('specifiers').forEach((specifierPath) => {\n        if (!specifierPath.isExportSpecifier()) {\n          return;\n        }\n        const { local, exported } = specifierPath.node;\n        if (!t.isIdentifier(local) || !t.isIdentifier(exported)) {\n          return;\n        }\n        const binding = specifierPath.scope.getBinding(local.name);\n        if (!binding) {\n          return;\n        }\n\n        const bindingPath = binding.path;\n        const localIdentifier = binding.identifier;\n        if (!t.isIdentifier(localIdentifier)) {\n          return;\n        }\n        if (bindingPath.isVariableDeclarator()) {\n          addComponent(exported.name, localIdentifier, bindingPath.get('init'));\n        } else if (bindingPath.isFunctionDeclaration() || bindingPath.isClassDeclaration()) {\n          const bindingNodeId = bindingPath.node.id;\n          if (t.isIdentifier(bindingNodeId)) {\n            addComponent(exported.name, localIdentifier, bindingPath);\n          }\n        }\n      });\n    },\n    ExportDefaultDeclaration(path) {\n      const { node } = path;\n      const declaration = node.declaration;\n\n      if (\n        t.isFunctionExpression(declaration) ||\n        t.isArrowFunctionExpression(declaration) ||\n        t.isClassExpression(declaration)\n      ) {\n        const identifierName = createComponentNameFromFileName(fileName);\n        const identifier = path.scope.generateUidIdentifier(identifierName);\n        const variableDeclaration = t.variableDeclaration('const', [\n          t.variableDeclarator(identifier, declaration),\n        ]);\n        variableDeclaration.loc = node.loc;\n        path.insertBefore(variableDeclaration);\n        node.declaration = identifier;\n\n        const insertedVarPath = path.getPrevSibling();\n        let initPath: NodePath<t.Node | null | undefined> | null = null;\n        if (insertedVarPath?.isVariableDeclaration()) {\n          const declarationPath = insertedVarPath.get('declarations')[0];\n          if (declarationPath?.isVariableDeclarator()) {\n            initPath = declarationPath.get('init');\n          }\n        }\n\n        addComponent(identifierName, identifier, initPath);\n        return;\n      }\n\n      if (t.isCallExpression(declaration)) {\n        // Handle wrapped component exports e.g.\n        // export default someWrapper(Component)\n        const identifierName = createComponentNameFromFileName(fileName);\n        const identifier = path.scope.generateUidIdentifier(identifierName);\n        const variableDeclaration = t.variableDeclaration('const', [\n          t.variableDeclarator(identifier, declaration),\n        ]);\n        variableDeclaration.loc = node.loc;\n        path.insertBefore(variableDeclaration);\n        node.declaration = identifier;\n\n        // Assume wrapped exports are components without detecting JSX to filter out. We can do that if needed in the future based on feedback.\n        components.push({ exportedName: identifierName, localIdentifier: identifier });\n        return;\n      }\n\n      if (t.isIdentifier(declaration)) {\n        const binding = path.scope.getBinding(declaration.name);\n        if (!binding) {\n          return;\n        }\n\n        const bindingIdentifier = binding.identifier;\n        if (!t.isIdentifier(bindingIdentifier)) {\n          return;\n        }\n\n        if (binding.path.isVariableDeclarator()) {\n          addComponent(\n            createComponentNameFromFileName(fileName),\n            bindingIdentifier,\n            binding.path.get('init')\n          );\n        } else if (binding.path.isFunctionDeclaration() || binding.path.isClassDeclaration()) {\n          const bindingNodeId = binding.path.node.id;\n          if (t.isIdentifier(bindingNodeId)) {\n            addComponent(bindingNodeId.name, bindingIdentifier, binding.path);\n          }\n        }\n        return;\n      }\n\n      if (t.isFunctionDeclaration(declaration) && declaration.id) {\n        addComponent(\n          declaration.id.name,\n          declaration.id,\n          path.get('declaration') as NodePath<t.FunctionDeclaration>\n        );\n        return;\n      }\n\n      if (t.isClassDeclaration(declaration) && declaration.id) {\n        addComponent(\n          declaration.id.name,\n          declaration.id,\n          path.get('declaration') as NodePath<t.ClassDeclaration>\n        );\n      }\n    },\n  });\n\n  return components;\n};\n\n/**\n * Transforms a component file directly into a Vitest test file. Uses a getComponentArgTypes\n * function to retrieve component argTypes for required prop generation. Uses portable stories to\n * construct a test based on the default state of a component (basic render + required args)\n */\nexport const componentTransform = async ({\n  code,\n  fileName,\n  getComponentArgTypes,\n}: {\n  code: string;\n  fileName: string;\n  getComponentArgTypes?: (options: {\n    componentName: string;\n    fileName: string;\n  }) => Promise<ArgTypes | null | undefined>;\n}): Promise<ReturnType<typeof generate> | { code: string; map: null }> => {\n  const ast = babelParse(code);\n  const file = new BabelFileClass({ filename: fileName, highlightCode: false }, { code, ast });\n\n  const components = collectComponentExports(ast.program, fileName);\n  if (!components.length) {\n    return { code, map: null };\n  }\n\n  const vitestTestId = file.path.scope.generateUidIdentifier('test');\n  const vitestExpectId = file.path.scope.generateUidIdentifier('expect');\n  const testStoryId = file.path.scope.generateUidIdentifier('testStory');\n  const convertToFilePathId = t.identifier('convertToFilePath');\n  const fnId = file.path.scope.generateUidIdentifier('fn');\n\n  dedupeImports(ast.program, VITEST_IMPORT_SOURCE, [\n    t.importSpecifier(vitestTestId, t.identifier('test')),\n    t.importSpecifier(vitestExpectId, t.identifier('expect')),\n  ]);\n  dedupeImports(ast.program, TEST_UTILS_IMPORT_SOURCE, [\n    t.importSpecifier(testStoryId, t.identifier('testStory')),\n    t.importSpecifier(convertToFilePathId, t.identifier('convertToFilePath')),\n  ]);\n\n  const testStatements: t.ExpressionStatement[] = [];\n\n  // Detect whether argTypes contains fn placeholders that need replacing with an actual function expression. Done ahead of time for performance reasons.\n  const hasFunctionPlaceholder = (value: unknown): boolean => {\n    return JSON.stringify(value).includes(STORYBOOK_FN_PLACEHOLDER);\n  };\n\n  /**\n   * When argTypes relate to handlers like onClick, they will have a string value like\n   * [[STORYBOOK_FN_PLACEHOLDER]] In those cases we need to replace them with an actual fn() call\n   * from storybook/test\n   */\n  const valueToNodeRecursive = (value: unknown, replaceFnCalls: boolean): t.Expression => {\n    // When there are no function placeholders, no need to recurse - just use valueToNode\n    if (!replaceFnCalls) {\n      return t.valueToNode(value) as t.Expression;\n    }\n\n    if (value === STORYBOOK_FN_PLACEHOLDER) {\n      return t.callExpression(fnId, []);\n    }\n\n    if (typeof value === 'object' && value !== null) {\n      if (Array.isArray(value)) {\n        return t.arrayExpression(value.map((val) => valueToNodeRecursive(val, replaceFnCalls)));\n      }\n\n      // For objects, create a new object with recursively processed values\n      const properties = Object.entries(value).map(([key, val]) => {\n        const keyNode = t.isValidIdentifier(key) ? t.identifier(key) : t.stringLiteral(key);\n        return t.objectProperty(keyNode, valueToNodeRecursive(val, replaceFnCalls));\n      });\n      return t.objectExpression(properties);\n    }\n\n    return t.valueToNode(value) as t.Expression;\n  };\n\n  // Helper to convert a props object to an AST object expression\n  const buildArgsExpression = (args?: Record<string, unknown>, useFnImport = false) => {\n    if (!args || Object.keys(args).length === 0) {\n      return t.objectExpression([]);\n    }\n\n    const properties = Object.entries(args).map(([key, value]) => {\n      const keyNode = t.isValidIdentifier(key) ? t.identifier(key) : t.stringLiteral(key);\n      return t.objectProperty(keyNode, valueToNodeRecursive(value, useFnImport));\n    });\n    return t.objectExpression(properties);\n  };\n\n  // Check if any component has function placeholders and add import if needed\n  let hasAnyFunctionPlaceholders = false;\n\n  // Each collected component becomes a test case\n  for (const component of components) {\n    const argTypes = getComponentArgTypes\n      ? await getComponentArgTypes({ componentName: component.exportedName, fileName })\n      : undefined;\n    const generatedArgs = argTypes\n      ? generateDummyArgsFromArgTypes(argTypes, { skipUrlGeneration: true }).required\n      : undefined;\n\n    if (!hasAnyFunctionPlaceholders && generatedArgs && hasFunctionPlaceholder(generatedArgs)) {\n      hasAnyFunctionPlaceholders = true;\n    }\n\n    // Each component export is passed as component in an inline meta\n    // this allows for multiple component metas in a single test file\n    const meta = t.objectExpression([\n      t.objectProperty(\n        t.identifier('title'),\n        t.stringLiteral(`generated/tests/${component.exportedName}`)\n      ),\n      t.objectProperty(t.identifier('component'), component.localIdentifier),\n    ]);\n\n    // The actual testStory function\n    const testStoryArgs = t.objectExpression([\n      t.objectProperty(t.identifier('exportName'), t.stringLiteral(component.exportedName)),\n      // This is where the story annotation for a particular component is defined, inline\n      t.objectProperty(\n        t.identifier('story'),\n        t.objectExpression([\n          t.objectProperty(\n            t.identifier('args'),\n            buildArgsExpression(generatedArgs, hasAnyFunctionPlaceholders)\n          ),\n        ])\n      ),\n      t.objectProperty(t.identifier('meta'), meta),\n      t.objectProperty(t.identifier('skipTags'), t.arrayExpression([])),\n      t.objectProperty(\n        t.identifier('storyId'),\n        t.stringLiteral(`generated-${component.exportedName}`)\n      ),\n      t.objectProperty(t.identifier('componentPath'), t.stringLiteral(fileName)),\n      t.objectProperty(\n        t.identifier('componentName'),\n        t.stringLiteral(component.localIdentifier.name)\n      ),\n    ]);\n\n    const testCall = t.expressionStatement(\n      t.callExpression(vitestTestId, [\n        t.stringLiteral(component.exportedName),\n        t.callExpression(testStoryId, [testStoryArgs]),\n      ])\n    );\n\n    testStatements.push(testCall);\n  }\n\n  if (hasAnyFunctionPlaceholders) {\n    dedupeImports(ast.program, STORYBOOK_TEST_IMPORT_SOURCE, [\n      t.importSpecifier(fnId, t.identifier('fn')),\n    ]);\n  }\n\n  // Wrap the code in a guard to avoid side effects when running tests\n  const { declaration: guardDeclaration, identifier: guardIdentifier } = createTestGuardDeclaration(\n    file.path.scope,\n    vitestExpectId,\n    convertToFilePathId\n  );\n\n  ast.program.body.push(guardDeclaration);\n  ast.program.body.push(t.ifStatement(guardIdentifier, t.blockStatement(testStatements)));\n\n  return generate(ast, { sourceMaps: true, sourceFileName: fileName }, code);\n};\n"
  },
  {
    "path": "code/core/src/csf-tools/vitest-plugin/transformer.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { getStoryTitle } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { type RawSourceMap, SourceMapConsumer } from 'source-map';\n\nimport { Tag } from '../../shared/constants/tags.ts';\nimport { vitestTransform as originalTransform } from './transformer.ts';\n\nvi.mock('storybook/internal/common', async (importOriginal) => {\n  const actual = await importOriginal<typeof import('storybook/internal/common')>();\n  return {\n    ...actual,\n    getStoryTitle: vi.fn(() => 'automatic/calculated/title'),\n  };\n});\n\nexpect.addSnapshotSerializer({\n  serialize: (val: any) => (typeof val === 'string' ? val : val.toString()),\n  test: (val) => true,\n});\n\nconst transform = async ({\n  code = '',\n  fileName = 'src/components/Button.stories.js',\n  tagsFilter = {\n    include: [Tag.TEST] as string[],\n    exclude: [] as string[],\n    skip: [] as string[],\n  },\n  configDir = '.storybook',\n  stories = [],\n  previewLevelTags = [],\n}) => {\n  const transformed = await originalTransform({\n    code,\n    fileName,\n    configDir,\n    stories,\n    tagsFilter,\n    previewLevelTags,\n  });\n  if (typeof transformed === 'string') {\n    return { code: transformed, map: null };\n  }\n\n  return transformed;\n};\n\ndescribe('transformer', () => {\n  describe('CSF v1/v2/v3', () => {\n    describe('default exports (meta)', () => {\n      it('should add title to inline default export if not present', async () => {\n        const code = `\n          export default {\n            component: Button,\n          };\n          export const Story = {};\n        `;\n\n        const result = await transform({ code });\n\n        expect(getStoryTitle).toHaveBeenCalled();\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          const _meta = {\n            component: Button,\n            title: \"automatic/calculated/title\"\n          };\n          export default _meta;\n          export const Story = {};\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"Story\", _testStory({\n              exportName: \"Story\",\n              story: Story,\n              meta: _meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--story\"\n            }));\n          }\n        `);\n      });\n\n      it('should overwrite title to inline default export if already present', async () => {\n        const code = `\n          export default {\n            title: 'Button',\n            component: Button,\n          };\n          export const Story = {};\n        `;\n\n        const result = await transform({ code });\n\n        expect(getStoryTitle).toHaveBeenCalled();\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          const _meta = {\n            title: \"automatic/calculated/title\",\n            component: Button\n          };\n          export default _meta;\n          export const Story = {};\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"Story\", _testStory({\n              exportName: \"Story\",\n              story: Story,\n              meta: _meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--story\"\n            }));\n          }\n        `);\n      });\n\n      it('should add title to const declared default export if not present', async () => {\n        const code = `\n          const meta = {\n            component: Button,\n          };\n          export default meta;\n\n          export const Story = {};\n        `;\n\n        const result = await transform({ code });\n\n        expect(getStoryTitle).toHaveBeenCalled();\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          const meta = {\n            component: Button,\n            title: \"automatic/calculated/title\"\n          };\n          export default meta;\n          export const Story = {};\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"Story\", _testStory({\n              exportName: \"Story\",\n              story: Story,\n              meta: meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--story\"\n            }));\n          }\n        `);\n      });\n\n      it('should overwrite title to const declared default export if already present', async () => {\n        const code = `\n          const meta = {\n            title: 'Button',\n            component: Button,\n          };\n          export default meta;\n\n          export const Story = {};\n        `;\n\n        const result = await transform({ code });\n\n        expect(getStoryTitle).toHaveBeenCalled();\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          const meta = {\n            title: \"automatic/calculated/title\",\n            component: Button\n          };\n          export default meta;\n          export const Story = {};\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"Story\", _testStory({\n              exportName: \"Story\",\n              story: Story,\n              meta: meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--story\"\n            }));\n          }\n        `);\n      });\n    });\n\n    describe('named exports (stories)', () => {\n      it('should add test statement to inline exported stories', async () => {\n        const code = `\n          export default {\n            component: Button,\n          }\n          export const Primary = {\n            args: {\n              label: 'Primary Button',\n            },\n          };\n        `;\n\n        const result = await transform({ code });\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          const _meta = {\n            component: Button,\n            title: \"automatic/calculated/title\"\n          };\n          export default _meta;\n          export const Primary = {\n            args: {\n              label: 'Primary Button'\n            }\n          };\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"Primary\", _testStory({\n              exportName: \"Primary\",\n              story: Primary,\n              meta: _meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--primary\"\n            }));\n          }\n        `);\n      });\n\n      describe(\"use the story's name as test title\", () => {\n        it('should support CSF v3 via name property', async () => {\n          const code = `\n          export default { component: Button }\n          export const Primary = { name: \"custom name\" };`;\n          const result = await transform({ code });\n\n          expect(result.code).toMatchInlineSnapshot(`\n            import { test as _test, expect as _expect } from \"vitest\";\n            import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n            const _meta = {\n              component: Button,\n              title: \"automatic/calculated/title\"\n            };\n            export default _meta;\n            export const Primary = {\n              name: \"custom name\"\n            };\n            const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n            if (_isRunningFromThisFile) {\n              _test(\"custom name\", _testStory({\n                exportName: \"Primary\",\n                story: Primary,\n                meta: _meta,\n                skipTags: [],\n                storyId: \"automatic-calculated-title--primary\"\n              }));\n            }\n          `);\n        });\n\n        it('should support CSF v1/v2 via storyName property', async () => {\n          const code = `\n          export default { component: Button }\n          export const Story = () => {}\n          Story.storyName = 'custom name';`;\n          const result = await transform({ code: code });\n          expect(result.code).toMatchInlineSnapshot(`\n            import { test as _test, expect as _expect } from \"vitest\";\n            import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n            const _meta = {\n              component: Button,\n              title: \"automatic/calculated/title\"\n            };\n            export default _meta;\n            export const Story = () => {};\n            Story.storyName = 'custom name';\n            const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n            if (_isRunningFromThisFile) {\n              _test(\"custom name\", _testStory({\n                exportName: \"Story\",\n                story: Story,\n                meta: _meta,\n                skipTags: [],\n                storyId: \"automatic-calculated-title--story\"\n              }));\n            }\n          `);\n        });\n      });\n\n      it('should add test statement to const declared exported stories', async () => {\n        const code = `\n          export default {};\n          const Primary = {\n            args: {\n              label: 'Primary Button',\n            },\n          };\n\n          export { Primary };\n        `;\n\n        const result = await transform({ code });\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          const _meta = {\n            title: \"automatic/calculated/title\"\n          };\n          export default _meta;\n          const Primary = {\n            args: {\n              label: 'Primary Button'\n            }\n          };\n          export { Primary };\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"Primary\", _testStory({\n              exportName: \"Primary\",\n              story: Primary,\n              meta: _meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--primary\"\n            }));\n          }\n        `);\n      });\n\n      it('should add test statement to const declared renamed exported stories', async () => {\n        const code = `\n          export default {};\n          const Primary = {\n            args: {\n              label: 'Primary Button',\n            },\n          };\n\n          export { Primary as PrimaryStory };\n        `;\n\n        const result = await transform({ code });\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          const _meta = {\n            title: \"automatic/calculated/title\"\n          };\n          export default _meta;\n          const Primary = {\n            args: {\n              label: 'Primary Button'\n            }\n          };\n          export { Primary as PrimaryStory };\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"PrimaryStory\", _testStory({\n              exportName: \"PrimaryStory\",\n              story: Primary,\n              meta: _meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--primary-story\"\n            }));\n          }\n        `);\n      });\n\n      it('should add tests for multiple stories', async () => {\n        const code = `\n          export default {};\n          const Primary = {\n            args: {\n              label: 'Primary Button',\n            },\n          };\n\n          export const Secondary = {}\n\n          export { Primary };\n        `;\n\n        const result = await transform({ code });\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          const _meta = {\n            title: \"automatic/calculated/title\"\n          };\n          export default _meta;\n          const Primary = {\n            args: {\n              label: 'Primary Button'\n            }\n          };\n          export const Secondary = {};\n          export { Primary };\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"Secondary\", _testStory({\n              exportName: \"Secondary\",\n              story: Secondary,\n              meta: _meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--secondary\"\n            }));\n            _test(\"Primary\", _testStory({\n              exportName: \"Primary\",\n              story: Primary,\n              meta: _meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--primary\"\n            }));\n          }\n        `);\n      });\n\n      it('should exclude exports via excludeStories', async () => {\n        const code = `\n          export default {\n            title: 'Button',\n            component: Button,\n            excludeStories: ['nonStory'],\n          }\n          export const Story = {};\n          export const nonStory = 123\n        `;\n\n        const result = await transform({ code });\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          const _meta = {\n            title: \"automatic/calculated/title\",\n            component: Button,\n            excludeStories: ['nonStory']\n          };\n          export default _meta;\n          export const Story = {};\n          export const nonStory = 123;\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"Story\", _testStory({\n              exportName: \"Story\",\n              story: Story,\n              meta: _meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--story\"\n            }));\n          }\n        `);\n      });\n\n      it('should return a describe with skip if there are no valid stories', async () => {\n        const code = `\n          export default {\n            title: 'Button',\n            component: Button,\n            tags: ['!test']\n          }\n          export const Story = {}\n        `;\n        const result = await transform({ code });\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, describe as _describe } from \"vitest\";\n          const _meta = {\n            title: \"automatic/calculated/title\",\n            component: Button,\n            tags: ['!test']\n          };\n          export default _meta;\n          export const Story = {};\n          _describe.skip(\"No valid tests found\");\n        `);\n      });\n    });\n\n    describe('tags filtering mechanism', () => {\n      it('should only include stories from tags.include', async () => {\n        const code = `\n          export default {};\n          export const Included = { tags: ['include-me'] };\n\n          export const NotIncluded = {}\n        `;\n\n        const result = await transform({\n          code,\n          tagsFilter: { include: ['include-me'], exclude: [], skip: [] },\n        });\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          const _meta = {\n            title: \"automatic/calculated/title\"\n          };\n          export default _meta;\n          export const Included = {\n            tags: ['include-me']\n          };\n          export const NotIncluded = {};\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"Included\", _testStory({\n              exportName: \"Included\",\n              story: Included,\n              meta: _meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--included\"\n            }));\n          }\n        `);\n      });\n\n      it('should exclude stories from tags.exclude', async () => {\n        const code = `\n          export default {};\n          export const Included = {};\n\n          export const NotIncluded = { tags: ['exclude-me'] }\n        `;\n\n        const result = await transform({\n          code,\n          tagsFilter: { include: [Tag.TEST], exclude: ['exclude-me'], skip: [] },\n        });\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          const _meta = {\n            title: \"automatic/calculated/title\"\n          };\n          export default _meta;\n          export const Included = {};\n          export const NotIncluded = {\n            tags: ['exclude-me']\n          };\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"Included\", _testStory({\n              exportName: \"Included\",\n              story: Included,\n              meta: _meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--included\"\n            }));\n          }\n        `);\n      });\n\n      it('should pass skip tags to testStory call using tags.skip', async () => {\n        const code = `\n          export default {};\n          export const Skipped = { tags: ['skip-me'] };\n        `;\n\n        const result = await transform({\n          code,\n          tagsFilter: { include: [Tag.TEST], exclude: [], skip: ['skip-me'] },\n        });\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          const _meta = {\n            title: \"automatic/calculated/title\"\n          };\n          export default _meta;\n          export const Skipped = {\n            tags: ['skip-me']\n          };\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"Skipped\", _testStory({\n              exportName: \"Skipped\",\n              story: Skipped,\n              meta: _meta,\n              skipTags: [\"skip-me\"],\n              storyId: \"automatic-calculated-title--skipped\"\n            }));\n          }\n        `);\n      });\n    });\n\n    describe('component info extraction', () => {\n      it('should extract component name from named import specifier', async () => {\n        const code = `\n        import { Button } from './Button';\n        export default {\n          component: Button,\n        }\n        export const Primary = {};\n      `;\n\n        const result = await transform({\n          code,\n        });\n\n        expect(result.code).toContain('componentPath: \"./Button\"');\n        expect(result.code).toContain('componentName: \"Button\"');\n      });\n      it('should extract component name from default import specifier', async () => {\n        const code = `\n        import Button from './Button';\n        export default {\n          component: Button,\n        }\n        export const Primary = {};\n      `;\n\n        const result = await transform({\n          code,\n        });\n\n        expect(result.code).toContain('componentPath: \"./Button\"');\n        expect(result.code).toContain('componentName: \"Button\"');\n      });\n\n      it('should extract component name from aliased import specifier', async () => {\n        const code = `\n        import { Component as Button } from './Button';\n        export default {\n          component: Button,\n        }\n        export const Primary = {};\n      `;\n\n        const result = await transform({\n          code,\n        });\n\n        expect(result.code).toContain('componentPath: \"./Button\"');\n        expect(result.code).toContain('componentName: \"Button\"');\n      });\n    });\n\n    describe('source map calculation', () => {\n      it('should remap the location of an inline named export to its relative testStory function', async () => {\n        const originalCode = `\n          const meta = {\n            title: 'Button',\n            component: Button,\n          }\n          export default meta;\n          export const Primary = {};\n        `;\n\n        const { code: transformedCode, map } = await transform({\n          code: originalCode,\n        });\n\n        expect(transformedCode).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          const meta = {\n            title: \"automatic/calculated/title\",\n            component: Button\n          };\n          export default meta;\n          export const Primary = {};\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"Primary\", _testStory({\n              exportName: \"Primary\",\n              story: Primary,\n              meta: meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--primary\"\n            }));\n          }\n        `);\n\n        const consumer = await new SourceMapConsumer(map as unknown as RawSourceMap);\n\n        // Locate `__test(\"Primary\"...` in the transformed code\n        const testPrimaryLine =\n          transformedCode.split('\\n').findIndex((line) => line.includes('_test(\"Primary\"')) + 1;\n        const testPrimaryColumn = transformedCode\n          .split('\\n')\n          [testPrimaryLine - 1].indexOf('_test(\"Primary\"');\n\n        // Get the original position from the source map for `__test(\"Primary\"...`\n        const originalPosition = consumer.originalPositionFor({\n          line: testPrimaryLine,\n          column: testPrimaryColumn,\n        });\n\n        // Locate `export const Primary` in the original code\n        const originalPrimaryLine =\n          originalCode.split('\\n').findIndex((line) => line.includes('export const Primary')) + 1;\n        const originalPrimaryColumn = originalCode\n          .split('\\n')\n          [originalPrimaryLine - 1].indexOf('export const Primary');\n\n        // The original locations of the transformed code should match with the ones of the original code\n        expect(originalPosition.line, 'original line location').toBe(originalPrimaryLine);\n        expect(originalPosition.column, 'original column location').toBe(originalPrimaryColumn);\n      });\n    });\n  });\n\n  describe('CSF Factories', () => {\n    describe('default exports (meta)', () => {\n      it('should add title to inline default export if not present', async () => {\n        const code = `\n        import { config } from '#.storybook/preview';\n        const meta = config.meta({ component: Button });\n        export const Story = meta.story({});\n      `;\n\n        const result = await transform({ code });\n\n        expect(getStoryTitle).toHaveBeenCalled();\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          import { config } from '#.storybook/preview';\n          const meta = config.meta({\n            component: Button,\n            title: \"automatic/calculated/title\"\n          });\n          export const Story = meta.story({});\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"Story\", _testStory({\n              exportName: \"Story\",\n              story: Story,\n              meta: meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--story\"\n            }));\n          }\n        `);\n      });\n    });\n\n    describe('named exports (stories)', () => {\n      it(\"should use the story's name as test title\", async () => {\n        const code = `\n        import { config } from '#.storybook/preview';\n        const meta = config.meta({ component: Button });\n        export const Primary = meta.story({ name: \"custom name\" });`;\n        const result = await transform({ code });\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          import { config } from '#.storybook/preview';\n          const meta = config.meta({\n            component: Button,\n            title: \"automatic/calculated/title\"\n          });\n          export const Primary = meta.story({\n            name: \"custom name\"\n          });\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"custom name\", _testStory({\n              exportName: \"Primary\",\n              story: Primary,\n              meta: meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--primary\"\n            }));\n          }\n        `);\n      });\n\n      it('should add test statement to const declared exported stories', async () => {\n        const code = `\n        import { config } from '#.storybook/preview';\n        const meta = config.meta({ component: Button });\n        const Primary = meta.story({\n          args: {\n            label: 'Primary Button',\n          }\n        });\n\n        export { Primary };\n      `;\n\n        const result = await transform({ code });\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          import { config } from '#.storybook/preview';\n          const meta = config.meta({\n            component: Button,\n            title: \"automatic/calculated/title\"\n          });\n          const Primary = meta.story({\n            args: {\n              label: 'Primary Button'\n            }\n          });\n          export { Primary };\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"Primary\", _testStory({\n              exportName: \"Primary\",\n              story: Primary,\n              meta: meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--primary\"\n            }));\n          }\n        `);\n      });\n\n      it('should add test statement to const declared renamed exported stories', async () => {\n        const code = `\n        import { config } from '#.storybook/preview';\n        const meta = config.meta({ component: Button });\n        const Primary = meta.story({\n          args: {\n            label: 'Primary Button',\n          }\n        });\n\n        export { Primary as PrimaryStory };\n      `;\n\n        const result = await transform({ code });\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          import { config } from '#.storybook/preview';\n          const meta = config.meta({\n            component: Button,\n            title: \"automatic/calculated/title\"\n          });\n          const Primary = meta.story({\n            args: {\n              label: 'Primary Button'\n            }\n          });\n          export { Primary as PrimaryStory };\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"PrimaryStory\", _testStory({\n              exportName: \"PrimaryStory\",\n              story: Primary,\n              meta: meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--primary-story\"\n            }));\n          }\n        `);\n      });\n\n      it('should add tests for multiple stories', async () => {\n        const code = `\n        export default {};\n        const Primary = {\n          args: {\n            label: 'Primary Button',\n          },\n        };\n\n        export const Secondary = {}\n\n        export { Primary };\n      `;\n\n        const result = await transform({ code });\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          const _meta = {\n            title: \"automatic/calculated/title\"\n          };\n          export default _meta;\n          const Primary = {\n            args: {\n              label: 'Primary Button'\n            }\n          };\n          export const Secondary = {};\n          export { Primary };\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"Secondary\", _testStory({\n              exportName: \"Secondary\",\n              story: Secondary,\n              meta: _meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--secondary\"\n            }));\n            _test(\"Primary\", _testStory({\n              exportName: \"Primary\",\n              story: Primary,\n              meta: _meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--primary\"\n            }));\n          }\n        `);\n      });\n\n      it('should exclude exports via excludeStories', async () => {\n        const code = `\n        export default {\n          title: 'Button',\n          component: Button,\n          excludeStories: ['nonStory'],\n        }\n        export const Story = {};\n        export const nonStory = 123\n      `;\n\n        const result = await transform({ code });\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          const _meta = {\n            title: \"automatic/calculated/title\",\n            component: Button,\n            excludeStories: ['nonStory']\n          };\n          export default _meta;\n          export const Story = {};\n          export const nonStory = 123;\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"Story\", _testStory({\n              exportName: \"Story\",\n              story: Story,\n              meta: _meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--story\"\n            }));\n          }\n        `);\n      });\n\n      it('should return a describe with skip if there are no valid stories', async () => {\n        const code = `\n        export default {\n          title: 'Button',\n          component: Button,\n          tags: ['!test']\n        }\n        export const Story = {}\n      `;\n        const result = await transform({ code });\n\n        expect(result.code).toMatchInlineSnapshot(`\n        import { test as _test, describe as _describe } from \"vitest\";\n        const _meta = {\n          title: \"automatic/calculated/title\",\n          component: Button,\n          tags: ['!test']\n        };\n        export default _meta;\n        export const Story = {};\n        _describe.skip(\"No valid tests found\");\n      `);\n      });\n      it('should support test annotation', async () => {\n        const code = `\n        import { config } from '#.storybook/preview';\n        const meta = config.meta({ component: Button });\n        export const A = meta.story({});\n        A.test(\"foo\", { args: { primary: true }}, () => {});\n        A.test(\"bar\", () => {});\n      `;\n\n        const result = await transform({ code });\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect, describe as _describe } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          import { config } from '#.storybook/preview';\n          const meta = config.meta({\n            component: Button,\n            title: \"automatic/calculated/title\"\n          });\n          export const A = meta.story({});\n          A.test(\"foo\", {\n            args: {\n              primary: true\n            }\n          }, () => {});\n          A.test(\"bar\", () => {});\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _describe(\"A  \", () => {\n              _test(\"base story\", _testStory({\n                exportName: \"A\",\n                story: A,\n                meta: meta,\n                skipTags: [],\n                storyId: \"automatic-calculated-title--a\"\n              }));\n              _test(\"foo\", _testStory({\n                exportName: \"A\",\n                story: A,\n                meta: meta,\n                skipTags: [],\n                storyId: \"automatic-calculated-title--a:foo\",\n                testName: \"foo\"\n              }));\n              _test(\"bar\", _testStory({\n                exportName: \"A\",\n                story: A,\n                meta: meta,\n                skipTags: [],\n                storyId: \"automatic-calculated-title--a:bar\",\n                testName: \"bar\"\n              }));\n            });\n          }\n        `);\n      });\n    });\n\n    describe('test syntax', () => {\n      it('should add test statement to story tests', async () => {\n        const code = `\n          import { config } from '#.storybook/preview';\n          const meta = config.meta({});\n          export const Primary = meta.story({});\n          Primary.test(\"foo\", () => {});\n        `;\n        const result = await transform({ code });\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect, describe as _describe } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          import { config } from '#.storybook/preview';\n          const meta = config.meta({\n            title: \"automatic/calculated/title\"\n          });\n          export const Primary = meta.story({});\n          Primary.test(\"foo\", () => {});\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _describe(\"Primary  \", () => {\n              _test(\"base story\", _testStory({\n                exportName: \"Primary\",\n                story: Primary,\n                meta: meta,\n                skipTags: [],\n                storyId: \"automatic-calculated-title--primary\"\n              }));\n              _test(\"foo\", _testStory({\n                exportName: \"Primary\",\n                story: Primary,\n                meta: meta,\n                skipTags: [],\n                storyId: \"automatic-calculated-title--primary:foo\",\n                testName: \"foo\"\n              }));\n            });\n          }\n        `);\n      });\n    });\n\n    describe('tags filtering mechanism', () => {\n      it('should only include stories from tags.include', async () => {\n        const code = `\n        import { config } from '#.storybook/preview';\n        const meta = config.meta({});\n        export const Included = meta.story({ tags: ['include-me'] });\n\n        export const NotIncluded = meta.story({});\n      `;\n\n        const result = await transform({\n          code,\n          tagsFilter: { include: ['include-me'], exclude: [], skip: [] },\n        });\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          import { config } from '#.storybook/preview';\n          const meta = config.meta({\n            title: \"automatic/calculated/title\"\n          });\n          export const Included = meta.story({\n            tags: ['include-me']\n          });\n          export const NotIncluded = meta.story({});\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"Included\", _testStory({\n              exportName: \"Included\",\n              story: Included,\n              meta: meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--included\"\n            }));\n          }\n        `);\n      });\n\n      it('should exclude stories from tags.exclude', async () => {\n        const code = `\n          import { config } from '#.storybook/preview';\n          const meta = config.meta({});\n          export const Included = meta.story({});\n\n          export const NotIncluded = meta.story({ tags: ['exclude-me'] });\n        `;\n\n        const result = await transform({\n          code,\n          tagsFilter: { include: [Tag.TEST], exclude: ['exclude-me'], skip: [] },\n        });\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          import { config } from '#.storybook/preview';\n          const meta = config.meta({\n            title: \"automatic/calculated/title\"\n          });\n          export const Included = meta.story({});\n          export const NotIncluded = meta.story({\n            tags: ['exclude-me']\n          });\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"Included\", _testStory({\n              exportName: \"Included\",\n              story: Included,\n              meta: meta,\n              skipTags: [],\n              storyId: \"automatic-calculated-title--included\"\n            }));\n          }\n        `);\n      });\n\n      it('should pass skip tags to testStory call using tags.skip', async () => {\n        const code = `\n        import { config } from '#.storybook/preview';\n        const meta = config.meta({});\n        export const Skipped = meta.story({ tags: ['skip-me'] });\n      `;\n\n        const result = await transform({\n          code,\n          tagsFilter: { include: [Tag.TEST], exclude: [], skip: ['skip-me'] },\n        });\n\n        expect(result.code).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          import { config } from '#.storybook/preview';\n          const meta = config.meta({\n            title: \"automatic/calculated/title\"\n          });\n          export const Skipped = meta.story({\n            tags: ['skip-me']\n          });\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _test(\"Skipped\", _testStory({\n              exportName: \"Skipped\",\n              story: Skipped,\n              meta: meta,\n              skipTags: [\"skip-me\"],\n              storyId: \"automatic-calculated-title--skipped\"\n            }));\n          }\n        `);\n      });\n    });\n\n    describe('source map calculation', () => {\n      it('should remap the location of an inline named export to its relative testStory function', async () => {\n        const originalCode = `\n        import { config } from '#.storybook/preview';\n        const meta = config.meta({});\n        export const Primary = meta.story({});\n        Primary.test(\"foo\", () => {});\n      `;\n\n        const { code: transformedCode, map } = await transform({\n          code: originalCode,\n        });\n\n        expect(transformedCode).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect, describe as _describe } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          import { config } from '#.storybook/preview';\n          const meta = config.meta({\n            title: \"automatic/calculated/title\"\n          });\n          export const Primary = meta.story({});\n          Primary.test(\"foo\", () => {});\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _describe(\"Primary  \", () => {\n              _test(\"base story\", _testStory({\n                exportName: \"Primary\",\n                story: Primary,\n                meta: meta,\n                skipTags: [],\n                storyId: \"automatic-calculated-title--primary\"\n              }));\n              _test(\"foo\", _testStory({\n                exportName: \"Primary\",\n                story: Primary,\n                meta: meta,\n                skipTags: [],\n                storyId: \"automatic-calculated-title--primary:foo\",\n                testName: \"foo\"\n              }));\n            });\n          }\n        `);\n\n        const consumer = await new SourceMapConsumer(map as unknown as RawSourceMap);\n\n        // Locate `_test(\"base story\"...` in the transformed code\n        const testPrimaryLine =\n          transformedCode.split('\\n').findIndex((line) => line.includes('_test(\"base story\"')) + 1;\n        const testPrimaryColumn = transformedCode\n          .split('\\n')\n          [testPrimaryLine - 1].indexOf('_test(\"base story\"');\n\n        // Get the original position from the source map for `_test(\"base story\"...`\n        const originalPosition = consumer.originalPositionFor({\n          line: testPrimaryLine,\n          column: testPrimaryColumn,\n        });\n\n        // Locate `export const Primary` in the original code\n        const originalPrimaryLine =\n          originalCode.split('\\n').findIndex((line) => line.includes('export const Primary')) + 1;\n        const originalPrimaryColumn = originalCode\n          .split('\\n')\n          [originalPrimaryLine - 1].indexOf('export const Primary');\n\n        // The original locations of the transformed code should match with the ones of the original code\n        expect(originalPosition.line, 'original line location').toBe(originalPrimaryLine);\n        expect(originalPosition.column, 'original column location').toBe(originalPrimaryColumn);\n      });\n\n      it.skip('should remap the location of story tests', async () => {\n        const originalCode = `\n        import { config } from '#.storybook/preview';\n        const meta = config.meta({});\n        export const Primary = meta.story({});\n        Primary.test(\"foo\", () => {});\n      `;\n\n        const { code: transformedCode, map } = await transform({\n          code: originalCode,\n        });\n\n        expect(transformedCode).toMatchInlineSnapshot(`\n          import { test as _test, expect as _expect, describe as _describe } from \"vitest\";\n          import { testStory as _testStory, convertToFilePath } from \"@storybook/addon-vitest/internal/test-utils\";\n          import { config } from '#.storybook/preview';\n          const meta = config.meta({\n            title: \"automatic/calculated/title\"\n          });\n          export const Primary = meta.story({});\n          Primary.test(\"foo\", () => {});\n          const _isRunningFromThisFile = convertToFilePath(import.meta.url).includes(globalThis.__vitest_worker__.filepath ?? _expect.getState().testPath);\n          if (_isRunningFromThisFile) {\n            _describe(\"Primary\", () => {\n              _test(\"base story\", _testStory(\"Primary\", Primary, meta, []));\n              _test(\"foo\", _testStory(\"Primary\", Primary, meta, [], \"foo\"));\n            });\n          }\n        `);\n\n        const consumer = await new SourceMapConsumer(map as unknown as RawSourceMap);\n\n        // Locate `_test(\"render test\"...` in the transformed code\n        const testPrimaryLine =\n          transformedCode.split('\\n').findIndex((line) => line.includes('_test(\"render test\"')) + 1;\n        const testPrimaryColumn = transformedCode\n          .split('\\n')\n          [testPrimaryLine - 1].indexOf('_test(\"render test\"');\n\n        // Get the original position from the source map for `_test(\"render test\"...`\n        const originalPosition = consumer.originalPositionFor({\n          line: testPrimaryLine,\n          column: testPrimaryColumn,\n        });\n\n        // Locate `export const Primary` in the original code\n        const originalPrimaryLine =\n          originalCode.split('\\n').findIndex((line) => line.includes('export const Primary')) + 1;\n        const originalPrimaryColumn = originalCode\n          .split('\\n')\n          [originalPrimaryLine - 1].indexOf('export const Primary');\n\n        // The original locations of the transformed code should match with the ones of the original code\n        expect(originalPosition.line, 'original line location').toBe(originalPrimaryLine);\n        expect(originalPosition.column, 'original column location').toBe(originalPrimaryColumn);\n\n        // Locate `_test(\"foo\"...` in the transformed code\n        const storyTestLine =\n          transformedCode.split('\\n').findIndex((line) => line.includes('_test(\"foo\"')) + 1;\n        const storyTestColumn = transformedCode\n          .split('\\n')\n          [storyTestLine - 1].indexOf('_test(\"foo\"');\n\n        // Get the original position from the source map for `_test(\"foo\"...`\n        const originalTestPosition = consumer.originalPositionFor({\n          line: storyTestLine,\n          column: storyTestColumn,\n        });\n\n        // Locate `Primary.test(\"foo\"'` in the original code\n        const originalStoryTestLine =\n          originalCode.split('\\n').findIndex((line) => line.includes('Primary.test(\"foo\"')) + 1;\n        const originalStoryTestColumn = originalCode\n          .split('\\n')\n          [originalStoryTestLine - 1].indexOf('Primary.test(\"foo\"');\n\n        // The original locations of the transformed code should match with the ones of the original code\n        expect(originalTestPosition.line, 'original line location').toBe(originalStoryTestLine);\n        expect(originalTestPosition.column, 'original column location').toBe(\n          originalStoryTestColumn\n        );\n      });\n    });\n  });\n\n  describe('error handling', () => {\n    const warnSpy = vi.spyOn(logger, 'warn');\n    beforeEach(() => {\n      vi.mocked(getStoryTitle).mockRestore();\n      warnSpy.mockReset();\n    });\n\n    it('should warn when autotitle is not successful', async () => {\n      const code = `\n        export default {}\n        export const Primary = {};\n      `;\n\n      vi.mocked(getStoryTitle).mockImplementation(() => undefined);\n\n      warnSpy.mockImplementation(() => {});\n\n      await transform({ code });\n      expect(warnSpy.mock.calls[0]).toMatchInlineSnapshot(`\n        [Storybook]: Could not calculate story title for \"src/components/Button.stories.js\".\n        Please make sure that this file matches the globs included in the \"stories\" field in your Storybook configuration at \".storybook\".\n      `);\n    });\n\n    it('should warn when on unsupported story formats', async () => {\n      const code = `\n        export default {}\n        export { Primary } from './Button.stories';\n      `;\n\n      warnSpy.mockImplementation(() => {});\n\n      await transform({ code });\n      expect(warnSpy.mock.calls[0]).toMatchInlineSnapshot(`\n        [Storybook]: Could not transform \"Primary\" story into test at \"src/components/Button.stories.js\".\n        Please make sure to define stories in the same file and not re-export stories coming from other files\".\n      `);\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/csf-tools/vitest-plugin/transformer.ts",
    "content": "/* eslint-disable local-rules/no-uncategorized-errors */\nimport { types as t } from 'storybook/internal/babel';\nimport { getStoryTitle } from 'storybook/internal/common';\nimport { combineTags } from 'storybook/internal/csf';\nimport { logger } from 'storybook/internal/node-logger';\nimport type { StoriesEntry, Tag } from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\n\nimport { type StoryTest, formatCsf, loadCsf } from '../CsfFile.ts';\n\ntype TagsFilter = {\n  include: string[];\n  exclude: string[];\n  skip: string[];\n};\n\nconst isValidTest = (storyTags: string[], tagsFilter: TagsFilter) => {\n  if (tagsFilter.include.length && !tagsFilter.include.some((tag) => storyTags?.includes(tag))) {\n    return false;\n  }\n  if (tagsFilter.exclude.some((tag) => storyTags?.includes(tag))) {\n    return false;\n  }\n  // Skipped tests are intentionally included here\n  return true;\n};\n/**\n * TODO: the functionality in this file can be moved back to the vitest plugin itself It can use\n * `storybook/internal/babel` for all it's babel needs, without duplicating babel embedding in our\n * bundles.\n */\n\n/**\n * We add double space characters so that it's possible to do a regex for all test run use cases.\n * Otherwise, if there were two unrelated stories like \"Primary Button\" and \"Primary Button Mobile\",\n * once you run tests for \"Primary Button\" and its children it would also match \"Primary Button\n * Mobile\". As it turns out, this limitation is also present in the Vitest VSCode extension and the\n * issue would occur with normal vitest tests as well, but because we use double spaces, we\n * circumvent the issue.\n */\nconst DOUBLE_SPACES = '  ';\nconst getLiteralWithZeroWidthSpace = (testTitle: string) =>\n  t.stringLiteral(`${testTitle}${DOUBLE_SPACES}`);\n\n/**\n * In Storybook users might be importing stories from other story files. As a side effect, tests can\n * get re-triggered. To avoid this, we add a guard to only run tests if the current file is the one\n * running the test.\n *\n * Const isRunningFromThisFile = import.meta.url.includes(expect.getState().testPath ??\n * globalThis.**vitest_worker**.filepath) if(isRunningFromThisFile) { ... }\n */\nexport function createTestGuardDeclaration(\n  scope: { generateUidIdentifier: (name: string) => t.Identifier },\n  expectId: t.Identifier,\n  convertToFilePathId: t.Identifier\n): { declaration: t.VariableDeclaration; identifier: t.Identifier } {\n  const isRunningFromThisFileId = scope.generateUidIdentifier('isRunningFromThisFile');\n\n  // expect.getState().testPath\n  const testPathProperty = t.memberExpression(\n    t.callExpression(t.memberExpression(expectId, t.identifier('getState')), []),\n    t.identifier('testPath')\n  );\n\n  // There is a bug in Vitest where expect.getState().testPath is undefined when called outside of a test function so we add this fallback in the meantime\n  // https://github.com/vitest-dev/vitest/issues/6367\n  // globalThis.__vitest_worker__.filepath\n  const filePathProperty = t.memberExpression(\n    t.memberExpression(t.identifier('globalThis'), t.identifier('__vitest_worker__')),\n    t.identifier('filepath')\n  );\n\n  // Combine testPath and filepath using the ?? operator\n  const nullishCoalescingExpression = t.logicalExpression(\n    '??',\n    // TODO: switch order of testPathProperty and filePathProperty when the bug is fixed\n    // https://github.com/vitest-dev/vitest/issues/6367 (or probably just use testPathProperty)\n    filePathProperty,\n    testPathProperty\n  );\n\n  // Create the final expression: import.meta.url.includes(...)\n  const includesCall = t.callExpression(\n    t.memberExpression(\n      t.callExpression(convertToFilePathId, [\n        t.memberExpression(\n          t.memberExpression(t.identifier('import'), t.identifier('meta')),\n          t.identifier('url')\n        ),\n      ]),\n      t.identifier('includes')\n    ),\n    [nullishCoalescingExpression]\n  );\n\n  const isRunningFromThisFileDeclaration = t.variableDeclaration('const', [\n    t.variableDeclarator(isRunningFromThisFileId, includesCall),\n  ]);\n\n  return {\n    declaration: isRunningFromThisFileDeclaration,\n    identifier: isRunningFromThisFileId,\n  };\n}\n\nexport async function vitestTransform({\n  code,\n  fileName,\n  configDir,\n  stories,\n  tagsFilter,\n  previewLevelTags = [],\n}: {\n  code: string;\n  fileName: string;\n  configDir: string;\n  tagsFilter: TagsFilter;\n  stories: StoriesEntry[];\n  previewLevelTags: Tag[];\n}): Promise<ReturnType<typeof formatCsf>> {\n  const parsed = loadCsf(code, {\n    fileName,\n    transformInlineMeta: true,\n    makeTitle: (title) => {\n      const result =\n        getStoryTitle({\n          storyFilePath: fileName,\n          configDir,\n          stories,\n          userTitle: title,\n        }) || 'unknown';\n\n      if (result === 'unknown') {\n        logger.warn(\n          dedent`\n            [Storybook]: Could not calculate story title for \"${fileName}\".\n            Please make sure that this file matches the globs included in the \"stories\" field in your Storybook configuration at \"${configDir}\".\n          `\n        );\n      }\n      return result;\n    },\n  }).parse();\n\n  const ast = parsed._ast;\n\n  const metaExportName = parsed._metaVariableName!;\n\n  const metaNode = parsed._metaNode as t.ObjectExpression;\n\n  const metaTitleProperty = metaNode.properties.find(\n    (prop) => t.isObjectProperty(prop) && t.isIdentifier(prop.key) && prop.key.name === 'title'\n  );\n\n  const metaTitle = t.stringLiteral(parsed._meta?.title || 'unknown');\n  if (!metaTitleProperty) {\n    metaNode.properties.push(t.objectProperty(t.identifier('title'), metaTitle));\n  } else if (t.isObjectProperty(metaTitleProperty)) {\n    // If the title is present in meta, overwrite it because autotitle can still affect existing titles\n    metaTitleProperty.value = metaTitle;\n  }\n\n  if (!metaNode || !parsed._meta) {\n    throw new Error(\n      'The Storybook vitest plugin could not detect the meta (default export) object in the story file. \\n\\nPlease make sure you have a default export with the meta object. If you are using a different export format that is not supported, please file an issue with details about your use case.'\n    );\n  }\n\n  // Filter out stories based on the passed tags filter\n  const validStories: (typeof parsed)['_storyStatements'] = {};\n  Object.keys(parsed._stories).forEach((key) => {\n    const finalTags = combineTags(\n      'test',\n      'dev',\n      ...previewLevelTags,\n      ...(parsed.meta?.tags || []),\n      ...(parsed._stories[key].tags || [])\n    );\n\n    if (isValidTest(finalTags, tagsFilter)) {\n      validStories[key] = parsed._storyStatements[key];\n    }\n  });\n\n  const vitestTestId = parsed._file.path.scope.generateUidIdentifier('test');\n  const vitestDescribeId = parsed._file.path.scope.generateUidIdentifier('describe');\n\n  // if no valid stories are found, we just add describe.skip() to the file to avoid empty test files\n  if (Object.keys(validStories).length === 0) {\n    const describeSkipBlock = t.expressionStatement(\n      t.callExpression(t.memberExpression(vitestDescribeId, t.identifier('skip')), [\n        t.stringLiteral('No valid tests found'),\n      ])\n    );\n\n    ast.program.body.push(describeSkipBlock);\n    const imports = [\n      t.importDeclaration(\n        [\n          t.importSpecifier(vitestTestId, t.identifier('test')),\n          t.importSpecifier(vitestDescribeId, t.identifier('describe')),\n        ],\n        t.stringLiteral('vitest')\n      ),\n    ];\n\n    ast.program.body.unshift(...imports);\n\n    return formatCsf(parsed, { sourceMaps: true, sourceFileName: fileName }, code);\n  }\n\n  const vitestExpectId = parsed._file.path.scope.generateUidIdentifier('expect');\n  const testStoryId = parsed._file.path.scope.generateUidIdentifier('testStory');\n  const skipTagsId = t.identifier(JSON.stringify(tagsFilter.skip));\n  const componentPathLiteral = parsed._rawComponentPath\n    ? t.stringLiteral(parsed._rawComponentPath)\n    : null;\n\n  let componentNameLiteral = null;\n  if (\n    parsed._componentImportSpecifier &&\n    (t.isImportSpecifier(parsed._componentImportSpecifier) ||\n      t.isImportDefaultSpecifier(parsed._componentImportSpecifier))\n  ) {\n    componentNameLiteral = t.stringLiteral(parsed._componentImportSpecifier.local.name);\n  }\n\n  const { declaration: isRunningFromThisFileDeclaration, identifier: isRunningFromThisFileId } =\n    createTestGuardDeclaration(\n      parsed._file.path.scope,\n      vitestExpectId,\n      t.identifier('convertToFilePath')\n    );\n\n  ast.program.body.push(isRunningFromThisFileDeclaration);\n\n  const getTestStatementForStory = ({\n    localName,\n    exportName,\n    testTitle,\n    node,\n    overrideSourcemap = true,\n    storyId,\n  }: {\n    localName: string;\n    exportName: string;\n    testTitle: string;\n    node: t.Node;\n    overrideSourcemap?: boolean;\n    storyId: string;\n  }): t.ExpressionStatement => {\n    const objectProperties: t.ObjectProperty[] = [\n      t.objectProperty(t.identifier('exportName'), t.stringLiteral(exportName)),\n      t.objectProperty(t.identifier('story'), t.identifier(localName)),\n      t.objectProperty(t.identifier('meta'), t.identifier(metaExportName)),\n      t.objectProperty(t.identifier('skipTags'), skipTagsId),\n      t.objectProperty(t.identifier('storyId'), t.stringLiteral(storyId)),\n    ];\n\n    if (componentPathLiteral) {\n      objectProperties.push(t.objectProperty(t.identifier('componentPath'), componentPathLiteral));\n    }\n\n    if (componentNameLiteral) {\n      objectProperties.push(t.objectProperty(t.identifier('componentName'), componentNameLiteral));\n    }\n\n    // Create the _test expression directly using the exportName identifier\n    const testStoryCall = t.expressionStatement(\n      t.callExpression(vitestTestId, [\n        t.stringLiteral(testTitle),\n        t.callExpression(testStoryId, [t.objectExpression(objectProperties)]),\n      ])\n    );\n\n    if (overrideSourcemap) {\n      // Preserve sourcemaps location\n      testStoryCall.loc = node.loc;\n    }\n\n    // Return just the testStoryCall as composeStoryCall is not needed\n    return testStoryCall;\n  };\n\n  const getDescribeStatementForStory = (options: {\n    localName: string;\n    describeTitle: string;\n    exportName: string;\n    tests: StoryTest[];\n    node: t.Node;\n    parentStoryId: string;\n  }): t.ExpressionStatement => {\n    const { localName, describeTitle, exportName, tests, node, parentStoryId } = options;\n    const describeBlock = t.callExpression(vitestDescribeId, [\n      getLiteralWithZeroWidthSpace(describeTitle),\n      t.arrowFunctionExpression(\n        [],\n        t.blockStatement([\n          getTestStatementForStory({\n            ...options,\n            testTitle: 'base story',\n            overrideSourcemap: false,\n            storyId: parentStoryId,\n          }),\n          ...tests.map(({ name: testName, node: testNode, id: storyId }) => {\n            const objectProperties: t.ObjectProperty[] = [\n              t.objectProperty(t.identifier('exportName'), t.stringLiteral(exportName)),\n              t.objectProperty(t.identifier('story'), t.identifier(localName)),\n              t.objectProperty(t.identifier('meta'), t.identifier(metaExportName)),\n              t.objectProperty(t.identifier('skipTags'), t.arrayExpression([])),\n              t.objectProperty(t.identifier('storyId'), t.stringLiteral(storyId)),\n            ];\n\n            if (componentPathLiteral) {\n              objectProperties.push(\n                t.objectProperty(t.identifier('componentPath'), componentPathLiteral)\n              );\n            }\n\n            if (componentNameLiteral) {\n              objectProperties.push(\n                t.objectProperty(t.identifier('componentName'), componentNameLiteral)\n              );\n            }\n\n            if (testName) {\n              objectProperties.push(\n                t.objectProperty(t.identifier('testName'), t.stringLiteral(testName))\n              );\n            }\n\n            const testStatement = t.expressionStatement(\n              t.callExpression(vitestTestId, [\n                t.stringLiteral(testName),\n                t.callExpression(testStoryId, [t.objectExpression(objectProperties)]),\n              ])\n            );\n            testStatement.loc = testNode.loc;\n            return testStatement;\n          }),\n        ])\n      ),\n    ]);\n\n    describeBlock.loc = node.loc;\n    return t.expressionStatement(describeBlock);\n  };\n\n  const storyTestStatements = Object.entries(validStories)\n    .map(([exportName, node]) => {\n      if (node === null) {\n        logger.warn(\n          dedent`\n            [Storybook]: Could not transform \"${exportName}\" story into test at \"${fileName}\".\n            Please make sure to define stories in the same file and not re-export stories coming from other files\".\n          `\n        );\n        return;\n      }\n\n      const localName = parsed._stories[exportName].localName ?? exportName;\n      // use the story's name as the test title for vitest, and fallback to exportName\n      const testTitle = parsed._stories[exportName].name ?? exportName;\n      const storyId = parsed._stories[exportName].id;\n      const tests = parsed.getStoryTests(exportName);\n\n      if (tests?.length > 0) {\n        return getDescribeStatementForStory({\n          localName,\n          describeTitle: testTitle,\n          exportName,\n          tests,\n          node,\n          parentStoryId: storyId,\n        });\n      }\n\n      return getTestStatementForStory({\n        testTitle,\n        localName,\n        exportName,\n        node,\n        storyId,\n      });\n    })\n    .filter((st) => !!st) as t.ExpressionStatement[];\n\n  const testBlock = t.ifStatement(isRunningFromThisFileId, t.blockStatement(storyTestStatements));\n\n  ast.program.body.push(testBlock);\n\n  const hasTests = Object.keys(validStories).some(\n    (exportName) => parsed.getStoryTests(exportName).length > 0\n  );\n\n  const imports = [\n    t.importDeclaration(\n      [\n        t.importSpecifier(vitestTestId, t.identifier('test')),\n        t.importSpecifier(vitestExpectId, t.identifier('expect')),\n        ...(hasTests ? [t.importSpecifier(vitestDescribeId, t.identifier('describe'))] : []),\n      ],\n      t.stringLiteral('vitest')\n    ),\n    t.importDeclaration(\n      [\n        t.importSpecifier(testStoryId, t.identifier('testStory')),\n        t.importSpecifier(t.identifier('convertToFilePath'), t.identifier('convertToFilePath')),\n      ],\n      t.stringLiteral('@storybook/addon-vitest/internal/test-utils')\n    ),\n  ];\n\n  ast.program.body.unshift(...imports);\n\n  return formatCsf(parsed, { sourceMaps: true, sourceFileName: fileName }, code);\n}\n"
  },
  {
    "path": "code/core/src/docs-tools/README.md",
    "content": "# Storybook Docs Utils\n\nShared utility functions for frameworks to implement docs:\n\n- ArgType extraction\n- Dynamic snippet generation\n- Is the user using docs or controls?\n\nThis library is used by most framework packages so it and its dependencies should be minimized\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/__testfixtures__/proptypes/arrays.js",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nexport const Component = (props) => <>JSON.stringify(props)</>;\nComponent.propTypes = {\n  optionalArray: PropTypes.array,\n  arrayOfStrings: PropTypes.arrayOf(PropTypes.string),\n  arrayOfShape: PropTypes.arrayOf(\n    PropTypes.shape({\n      active: PropTypes.bool,\n    })\n  ),\n};\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/__testfixtures__/proptypes/enums.js",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nexport const Component = (props) => <>JSON.stringify(props)</>;\nComponent.propTypes = {\n  oneOfNumber: PropTypes.oneOf([1, 2, 3]),\n  oneOfMiscellaneous: PropTypes.oneOf([false, true, undefined]),\n  oneOfStringNumber: PropTypes.oneOf(['1', '2', '3']),\n  oneOfString: PropTypes.oneOf(['static', 'timed']),\n};\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/__testfixtures__/proptypes/misc.js",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nexport const Component = (props) => <>JSON.stringify(props)</>;\nComponent.propTypes = {\n  // An object that could be one of many types\n  optionalUnion: PropTypes.oneOfType([\n    PropTypes.string,\n    PropTypes.number,\n    PropTypes.instanceOf(Object),\n  ]),\n  optionalMessage: PropTypes.instanceOf(Object),\n  // A value of any data type\n  requiredAny: PropTypes.any.isRequired,\n};\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/__testfixtures__/proptypes/objects.js",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nexport const Component = (props) => <>JSON.stringify(props)</>;\nComponent.propTypes = {\n  optionalObject: PropTypes.object,\n  optionalObjectOf: PropTypes.objectOf(PropTypes.number),\n  optionalObjectWithShape: PropTypes.shape({\n    color: PropTypes.string,\n    fontSize: PropTypes.number,\n  }),\n  optionalObjectWithStrictShape: PropTypes.exact({\n    name: PropTypes.string,\n    quantity: PropTypes.number,\n  }),\n};\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/__testfixtures__/proptypes/react.js",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nexport const Component = (props) => <>JSON.stringify(props)</>;\nComponent.propTypes = {\n  // Anything that can be rendered: numbers, strings, elements or an array\n  // (or fragment) containing these types.\n  optionalNode: PropTypes.node,\n  // A React element.\n  optionalElement: PropTypes.element,\n  // A React element type (ie. MyComponent).\n  optionalElementType: PropTypes.elementType,\n};\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/__testfixtures__/proptypes/scalars.js",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nexport const Component = (props) => <>JSON.stringify(props)</>;\nComponent.propTypes = {\n  optionalBool: PropTypes.bool,\n  optionalFunc: PropTypes.func,\n  optionalNumber: PropTypes.number,\n  optionalString: PropTypes.string,\n  optionalSymbol: PropTypes.symbol,\n};\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/__testfixtures__/typescript/aliases.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\ntype StringAlias = string;\ntype NumberAlias = number;\ntype AliasesIntersection = StringAlias & NumberAlias;\ntype AliasesUnion = StringAlias | NumberAlias;\ninterface GenericAlias<T> {\n  value: T;\n}\ninterface Props {\n  typeAlias: StringAlias;\n  aliasesIntersection: AliasesIntersection;\n  aliasesUnion: AliasesUnion;\n  genericAlias: GenericAlias<string>;\n}\nexport const Component: FC<Props> = (props: Props) => <>JSON.stringify(props)</>;\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/__testfixtures__/typescript/arrays.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\ninterface ItemInterface {\n  text: string;\n  value: string;\n}\ninterface Point {\n  x: number;\n  y: number;\n}\ninterface Props {\n  arrayOfPoints: Point[];\n  arrayOfInlineObjects: { w: number; h: number }[];\n  arrayOfPrimitive: string[];\n  arrayOfComplexObject: ItemInterface[];\n}\nexport const Component: FC<Props> = (props: Props) => <>JSON.stringify(props)</>;\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/__testfixtures__/typescript/enums.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nenum DefaultEnum {\n  TopLeft,\n  TopRight,\n  TopCenter,\n}\nenum NumericEnum {\n  TopLeft = 0,\n  TopRight,\n  TopCenter,\n}\nenum StringEnum {\n  TopLeft = 'top-left',\n  TopRight = 'top-right',\n  TopCenter = 'top-center',\n}\ninterface Props {\n  defaultEnum: DefaultEnum;\n  numericEnum: NumericEnum;\n  stringEnum: StringEnum;\n}\nexport const Component: FC<Props> = (props: Props) => <>JSON.stringify(props)</>;\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/__testfixtures__/typescript/functions.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\ninterface ItemInterface {\n  text: string;\n  value: string;\n}\ninterface Props {\n  onClick?: () => void;\n  voidFunc: () => void;\n  funcWithArgsAndReturns: (a: string, b: string) => string;\n  funcWithUnionArg: (a: string | number) => string;\n  funcWithMultipleUnionReturns: () => string | ItemInterface;\n}\nexport const Component: FC<Props> = (props: Props) => <>JSON.stringify(props)</>;\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/__testfixtures__/typescript/interfaces.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\ninterface ItemInterface {\n  text: string;\n  value: string;\n}\ninterface GenericInterface<T> {\n  value: T;\n}\ninterface Props {\n  interface: ItemInterface;\n  genericInterface: GenericInterface<string>;\n}\nexport const Component: FC<Props> = (props: Props) => <>JSON.stringify(props)</>;\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/__testfixtures__/typescript/intersections.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\ninterface ItemInterface {\n  text: string;\n  value: string;\n}\ninterface PersonInterface {\n  name: string;\n}\ntype InterfaceIntersection = ItemInterface & PersonInterface;\ninterface Props {\n  intersectionType: InterfaceIntersection;\n  intersectionWithInlineType: ItemInterface & { inlineValue: string };\n}\nexport const Component: FC<Props> = (props: Props) => <>JSON.stringify(props)</>;\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/__testfixtures__/typescript/optionals.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\ninterface Props {\n  any?: any;\n  string?: string;\n  bool?: boolean;\n  number?: number;\n  symbol?: symbol;\n  readonly readonlyPrimitive?: string;\n}\nexport const Component: FC<Props> = ({\n  any = 'foo',\n  string = 'bar',\n  bool = true,\n  number = 4,\n  ...rest\n}: Props) => {\n  const props = { any, string, bool, number, ...rest };\n  return <>{JSON.stringify(props)}</>;\n};\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/__testfixtures__/typescript/records.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\ninterface ItemInterface {\n  text: string;\n  value: string;\n}\ninterface Props {\n  recordOfPrimitive: Record<string, number>;\n  recordOfComplexObject: Record<string, ItemInterface>;\n}\nexport const Component: FC<Props> = (props: Props) => <>JSON.stringify(props)</>;\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/__testfixtures__/typescript/scalars.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\ninterface Props {\n  any: any;\n  string: string;\n  bool: boolean;\n  number: number;\n  symbol: symbol;\n  readonly readonlyPrimitive: string;\n}\nexport const Component: FC<Props> = (props: Props) => <>JSON.stringify(props)</>;\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/__testfixtures__/typescript/tuples.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\ninterface ItemInterface {\n  text: string;\n  value: string;\n}\ninterface Props {\n  tupleOfPrimitive: [string, number];\n  tupleWithComplexType: [string, ItemInterface];\n}\nexport const Component: FC<Props> = (props: Props) => <>JSON.stringify(props)</>;\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/__testfixtures__/typescript/unions.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\ntype Kind = 'default' | 'action';\nenum DefaultEnum {\n  TopLeft,\n  TopRight,\n  TopCenter,\n}\nenum NumericEnum {\n  TopLeft = 0,\n  TopRight,\n  TopCenter,\n}\ntype EnumUnion = DefaultEnum | NumericEnum;\ninterface Props {\n  kind?: Kind;\n  inlinedNumericLiteralUnion: 0 | 1;\n  enumUnion: EnumUnion;\n}\nexport const Component: FC<Props> = (props: Props) => <>JSON.stringify(props)</>;\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/convert.test.ts",
    "content": "import { readFileSync } from 'node:fs';\n\nimport { describe, expect, it } from 'vitest';\n\nimport { transformSync } from 'storybook/internal/babel';\n\nimport { mapValues } from 'es-toolkit/object';\nimport requireFromString from 'require-from-string';\n\nimport { normalizeNewlines } from '../utils.ts';\nimport { convert } from './index.ts';\n\nexpect.addSnapshotSerializer({\n  print: (val: any) => JSON.stringify(val, null, 2),\n  test: (val) => typeof val !== 'string',\n});\n\ndescribe('storybook type system', () => {\n  describe('TypeScript', () => {\n    it('scalars', () => {\n      const input = readFixture('typescript/functions.tsx');\n      expect(input).toMatchInlineSnapshot(`\n        \"import type { FC } from 'react';\n        import React from 'react';\n\n        interface ItemInterface {\n          text: string;\n          value: string;\n        }\n        interface Props {\n          onClick?: () => void;\n          voidFunc: () => void;\n          funcWithArgsAndReturns: (a: string, b: string) => string;\n          funcWithUnionArg: (a: string | number) => string;\n          funcWithMultipleUnionReturns: () => string | ItemInterface;\n        }\n        export const Component: FC<Props> = (props: Props) => <>JSON.stringify(props)</>;\n        \"\n      `);\n      expect(convertTs(input)).toMatchInlineSnapshot(`\n        {\n          \"onClick\": {\n            \"raw\": \"() => void\",\n            \"name\": \"function\"\n          },\n          \"voidFunc\": {\n            \"raw\": \"() => void\",\n            \"name\": \"function\"\n          },\n          \"funcWithArgsAndReturns\": {\n            \"raw\": \"(a: string, b: string) => string\",\n            \"name\": \"function\"\n          },\n          \"funcWithUnionArg\": {\n            \"raw\": \"(a: string | number) => string\",\n            \"name\": \"function\"\n          },\n          \"funcWithMultipleUnionReturns\": {\n            \"raw\": \"() => string | ItemInterface\",\n            \"name\": \"function\"\n          }\n        }\n      `);\n    });\n    it('functions', () => {\n      const input = readFixture('typescript/functions.tsx');\n      expect(input).toMatchInlineSnapshot(`\n        \"import type { FC } from 'react';\n        import React from 'react';\n\n        interface ItemInterface {\n          text: string;\n          value: string;\n        }\n        interface Props {\n          onClick?: () => void;\n          voidFunc: () => void;\n          funcWithArgsAndReturns: (a: string, b: string) => string;\n          funcWithUnionArg: (a: string | number) => string;\n          funcWithMultipleUnionReturns: () => string | ItemInterface;\n        }\n        export const Component: FC<Props> = (props: Props) => <>JSON.stringify(props)</>;\n        \"\n      `);\n      expect(convertTs(input)).toMatchInlineSnapshot(`\n        {\n          \"onClick\": {\n            \"raw\": \"() => void\",\n            \"name\": \"function\"\n          },\n          \"voidFunc\": {\n            \"raw\": \"() => void\",\n            \"name\": \"function\"\n          },\n          \"funcWithArgsAndReturns\": {\n            \"raw\": \"(a: string, b: string) => string\",\n            \"name\": \"function\"\n          },\n          \"funcWithUnionArg\": {\n            \"raw\": \"(a: string | number) => string\",\n            \"name\": \"function\"\n          },\n          \"funcWithMultipleUnionReturns\": {\n            \"raw\": \"() => string | ItemInterface\",\n            \"name\": \"function\"\n          }\n        }\n      `);\n    });\n    it('enums', () => {\n      const input = readFixture('typescript/enums.tsx');\n      expect(input).toMatchInlineSnapshot(`\n        \"import type { FC } from 'react';\n        import React from 'react';\n\n        enum DefaultEnum {\n          TopLeft,\n          TopRight,\n          TopCenter,\n        }\n        enum NumericEnum {\n          TopLeft = 0,\n          TopRight,\n          TopCenter,\n        }\n        enum StringEnum {\n          TopLeft = 'top-left',\n          TopRight = 'top-right',\n          TopCenter = 'top-center',\n        }\n        interface Props {\n          defaultEnum: DefaultEnum;\n          numericEnum: NumericEnum;\n          stringEnum: StringEnum;\n        }\n        export const Component: FC<Props> = (props: Props) => <>JSON.stringify(props)</>;\n        \"\n      `);\n      expect(convertTs(input)).toMatchInlineSnapshot(`\n        {\n          \"defaultEnum\": {\n            \"name\": \"other\",\n            \"value\": \"DefaultEnum\"\n          },\n          \"numericEnum\": {\n            \"name\": \"other\",\n            \"value\": \"NumericEnum\"\n          },\n          \"stringEnum\": {\n            \"name\": \"other\",\n            \"value\": \"StringEnum\"\n          }\n        }\n      `);\n    });\n    it('unions', () => {\n      const input = readFixture('typescript/unions.tsx');\n      expect(input).toMatchInlineSnapshot(`\n        \"import type { FC } from 'react';\n        import React from 'react';\n\n        type Kind = 'default' | 'action';\n        enum DefaultEnum {\n          TopLeft,\n          TopRight,\n          TopCenter,\n        }\n        enum NumericEnum {\n          TopLeft = 0,\n          TopRight,\n          TopCenter,\n        }\n        type EnumUnion = DefaultEnum | NumericEnum;\n        interface Props {\n          kind?: Kind;\n          inlinedNumericLiteralUnion: 0 | 1;\n          enumUnion: EnumUnion;\n        }\n        export const Component: FC<Props> = (props: Props) => <>JSON.stringify(props)</>;\n        \"\n      `);\n      expect(convertTs(input)).toMatchInlineSnapshot(`\n        {\n          \"kind\": {\n            \"raw\": \"'default' | 'action'\",\n            \"name\": \"enum\",\n            \"value\": [\n              \"default\",\n              \"action\"\n            ]\n          },\n          \"inlinedNumericLiteralUnion\": {\n            \"raw\": \"0 | 1\",\n            \"name\": \"enum\",\n            \"value\": [\n              0,\n              1\n            ]\n          },\n          \"enumUnion\": {\n            \"raw\": \"DefaultEnum | NumericEnum\",\n            \"name\": \"union\",\n            \"value\": [\n              {\n                \"name\": \"other\",\n                \"value\": \"DefaultEnum\"\n              },\n              {\n                \"name\": \"other\",\n                \"value\": \"NumericEnum\"\n              }\n            ]\n          }\n        }\n      `);\n    });\n    it('intersections', () => {\n      const input = readFixture('typescript/intersections.tsx');\n      expect(input).toMatchInlineSnapshot(`\n        \"import type { FC } from 'react';\n        import React from 'react';\n\n        interface ItemInterface {\n          text: string;\n          value: string;\n        }\n        interface PersonInterface {\n          name: string;\n        }\n        type InterfaceIntersection = ItemInterface & PersonInterface;\n        interface Props {\n          intersectionType: InterfaceIntersection;\n          intersectionWithInlineType: ItemInterface & { inlineValue: string };\n        }\n        export const Component: FC<Props> = (props: Props) => <>JSON.stringify(props)</>;\n        \"\n      `);\n      expect(convertTs(input)).toMatchInlineSnapshot(`\n        {\n          \"intersectionType\": {\n            \"raw\": \"ItemInterface & PersonInterface\",\n            \"name\": \"intersection\",\n            \"value\": [\n              {\n                \"name\": \"other\",\n                \"value\": \"ItemInterface\"\n              },\n              {\n                \"name\": \"other\",\n                \"value\": \"PersonInterface\"\n              }\n            ]\n          },\n          \"intersectionWithInlineType\": {\n            \"raw\": \"ItemInterface & { inlineValue: string }\",\n            \"name\": \"intersection\",\n            \"value\": [\n              {\n                \"name\": \"other\",\n                \"value\": \"ItemInterface\"\n              },\n              {\n                \"raw\": \"{ inlineValue: string }\",\n                \"name\": \"object\",\n                \"value\": {\n                  \"inlineValue\": {\n                    \"name\": \"string\"\n                  }\n                }\n              }\n            ]\n          }\n        }\n      `);\n    });\n    it('arrays', () => {\n      const input = readFixture('typescript/arrays.tsx');\n      expect(input).toMatchInlineSnapshot(`\n        \"import type { FC } from 'react';\n        import React from 'react';\n\n        interface ItemInterface {\n          text: string;\n          value: string;\n        }\n        interface Point {\n          x: number;\n          y: number;\n        }\n        interface Props {\n          arrayOfPoints: Point[];\n          arrayOfInlineObjects: { w: number; h: number }[];\n          arrayOfPrimitive: string[];\n          arrayOfComplexObject: ItemInterface[];\n        }\n        export const Component: FC<Props> = (props: Props) => <>JSON.stringify(props)</>;\n        \"\n      `);\n      expect(convertTs(input)).toMatchInlineSnapshot(`\n        {\n          \"arrayOfPoints\": {\n            \"raw\": \"Point[]\",\n            \"name\": \"array\",\n            \"value\": [\n              {\n                \"name\": \"other\",\n                \"value\": \"Point\"\n              }\n            ]\n          },\n          \"arrayOfInlineObjects\": {\n            \"raw\": \"{ w: number; h: number }[]\",\n            \"name\": \"array\",\n            \"value\": [\n              {\n                \"raw\": \"{ w: number; h: number }\",\n                \"name\": \"object\",\n                \"value\": {\n                  \"w\": {\n                    \"name\": \"number\"\n                  },\n                  \"h\": {\n                    \"name\": \"number\"\n                  }\n                }\n              }\n            ]\n          },\n          \"arrayOfPrimitive\": {\n            \"raw\": \"string[]\",\n            \"name\": \"array\",\n            \"value\": [\n              {\n                \"name\": \"string\"\n              }\n            ]\n          },\n          \"arrayOfComplexObject\": {\n            \"raw\": \"ItemInterface[]\",\n            \"name\": \"array\",\n            \"value\": [\n              {\n                \"name\": \"other\",\n                \"value\": \"ItemInterface\"\n              }\n            ]\n          }\n        }\n      `);\n    });\n    it('interfaces', () => {\n      const input = readFixture('typescript/interfaces.tsx');\n      expect(input).toMatchInlineSnapshot(`\n        \"import type { FC } from 'react';\n        import React from 'react';\n\n        interface ItemInterface {\n          text: string;\n          value: string;\n        }\n        interface GenericInterface<T> {\n          value: T;\n        }\n        interface Props {\n          interface: ItemInterface;\n          genericInterface: GenericInterface<string>;\n        }\n        export const Component: FC<Props> = (props: Props) => <>JSON.stringify(props)</>;\n        \"\n      `);\n      expect(convertTs(input)).toMatchInlineSnapshot(`\n        {\n          \"interface\": {\n            \"name\": \"other\",\n            \"value\": \"ItemInterface\"\n          },\n          \"genericInterface\": {\n            \"raw\": \"GenericInterface<string>\",\n            \"name\": \"other\",\n            \"value\": \"GenericInterface\"\n          }\n        }\n      `);\n    });\n    it('records', () => {\n      const input = readFixture('typescript/records.tsx');\n      expect(input).toMatchInlineSnapshot(`\n        \"import type { FC } from 'react';\n        import React from 'react';\n\n        interface ItemInterface {\n          text: string;\n          value: string;\n        }\n        interface Props {\n          recordOfPrimitive: Record<string, number>;\n          recordOfComplexObject: Record<string, ItemInterface>;\n        }\n        export const Component: FC<Props> = (props: Props) => <>JSON.stringify(props)</>;\n        \"\n      `);\n      expect(convertTs(input)).toMatchInlineSnapshot(`\n        {\n          \"recordOfPrimitive\": {\n            \"raw\": \"Record<string, number>\",\n            \"name\": \"other\",\n            \"value\": \"Record\"\n          },\n          \"recordOfComplexObject\": {\n            \"raw\": \"Record<string, ItemInterface>\",\n            \"name\": \"other\",\n            \"value\": \"Record\"\n          }\n        }\n      `);\n    });\n    it('aliases', () => {\n      const input = readFixture('typescript/aliases.tsx');\n      expect(input).toMatchInlineSnapshot(`\n        \"import type { FC } from 'react';\n        import React from 'react';\n\n        type StringAlias = string;\n        type NumberAlias = number;\n        type AliasesIntersection = StringAlias & NumberAlias;\n        type AliasesUnion = StringAlias | NumberAlias;\n        interface GenericAlias<T> {\n          value: T;\n        }\n        interface Props {\n          typeAlias: StringAlias;\n          aliasesIntersection: AliasesIntersection;\n          aliasesUnion: AliasesUnion;\n          genericAlias: GenericAlias<string>;\n        }\n        export const Component: FC<Props> = (props: Props) => <>JSON.stringify(props)</>;\n        \"\n      `);\n      expect(convertTs(input)).toMatchInlineSnapshot(`\n        {\n          \"typeAlias\": {\n            \"name\": \"string\"\n          },\n          \"aliasesIntersection\": {\n            \"raw\": \"StringAlias & NumberAlias\",\n            \"name\": \"intersection\",\n            \"value\": [\n              {\n                \"name\": \"string\"\n              },\n              {\n                \"name\": \"number\"\n              }\n            ]\n          },\n          \"aliasesUnion\": {\n            \"raw\": \"StringAlias | NumberAlias\",\n            \"name\": \"union\",\n            \"value\": [\n              {\n                \"name\": \"string\"\n              },\n              {\n                \"name\": \"number\"\n              }\n            ]\n          },\n          \"genericAlias\": {\n            \"raw\": \"GenericAlias<string>\",\n            \"name\": \"other\",\n            \"value\": \"GenericAlias\"\n          }\n        }\n      `);\n    });\n    it('tuples', () => {\n      const input = readFixture('typescript/tuples.tsx');\n      expect(input).toMatchInlineSnapshot(`\n        \"import type { FC } from 'react';\n        import React from 'react';\n\n        interface ItemInterface {\n          text: string;\n          value: string;\n        }\n        interface Props {\n          tupleOfPrimitive: [string, number];\n          tupleWithComplexType: [string, ItemInterface];\n        }\n        export const Component: FC<Props> = (props: Props) => <>JSON.stringify(props)</>;\n        \"\n      `);\n      expect(convertTs(input)).toMatchInlineSnapshot(`\n        {\n          \"tupleOfPrimitive\": {\n            \"raw\": \"[string, number]\",\n            \"name\": \"other\",\n            \"value\": \"tuple\"\n          },\n          \"tupleWithComplexType\": {\n            \"raw\": \"[string, ItemInterface]\",\n            \"name\": \"other\",\n            \"value\": \"tuple\"\n          }\n        }\n      `);\n    });\n  });\n  describe('PropTypes', () => {\n    it('scalars', () => {\n      const input = readFixture('proptypes/scalars.js');\n      expect(input).toMatchInlineSnapshot(`\n        \"import React from 'react';\n\n        import PropTypes from 'prop-types';\n\n        export const Component = (props) => <>JSON.stringify(props)</>;\n        Component.propTypes = {\n          optionalBool: PropTypes.bool,\n          optionalFunc: PropTypes.func,\n          optionalNumber: PropTypes.number,\n          optionalString: PropTypes.string,\n          optionalSymbol: PropTypes.symbol,\n        };\n        \"\n      `);\n      expect(convertJs(input)).toMatchInlineSnapshot(`\n        {\n          \"optionalBool\": {\n            \"name\": \"boolean\"\n          },\n          \"optionalFunc\": {\n            \"name\": \"function\"\n          },\n          \"optionalNumber\": {\n            \"name\": \"number\"\n          },\n          \"optionalString\": {\n            \"name\": \"string\"\n          },\n          \"optionalSymbol\": {\n            \"name\": \"symbol\"\n          }\n        }\n      `);\n    });\n    it('arrays', () => {\n      const input = readFixture('proptypes/arrays.js');\n      expect(input).toMatchInlineSnapshot(`\n        \"import React from 'react';\n\n        import PropTypes from 'prop-types';\n\n        export const Component = (props) => <>JSON.stringify(props)</>;\n        Component.propTypes = {\n          optionalArray: PropTypes.array,\n          arrayOfStrings: PropTypes.arrayOf(PropTypes.string),\n          arrayOfShape: PropTypes.arrayOf(\n            PropTypes.shape({\n              active: PropTypes.bool,\n            })\n          ),\n        };\n        \"\n      `);\n      expect(convertJs(input)).toMatchInlineSnapshot(`\n        {\n          \"optionalArray\": {\n            \"name\": \"array\"\n          },\n          \"arrayOfStrings\": {\n            \"name\": \"array\",\n            \"value\": {\n              \"name\": \"string\"\n            }\n          },\n          \"arrayOfShape\": {\n            \"name\": \"array\",\n            \"value\": {\n              \"name\": \"object\",\n              \"value\": {\n                \"active\": {\n                  \"name\": \"boolean\"\n                }\n              }\n            }\n          }\n        }\n      `);\n    });\n    it('enums', () => {\n      const input = readFixture('proptypes/enums.js');\n      expect(input).toMatchInlineSnapshot(`\n        \"import React from 'react';\n\n        import PropTypes from 'prop-types';\n\n        export const Component = (props) => <>JSON.stringify(props)</>;\n        Component.propTypes = {\n          oneOfNumber: PropTypes.oneOf([1, 2, 3]),\n          oneOfMiscellaneous: PropTypes.oneOf([false, true, undefined]),\n          oneOfStringNumber: PropTypes.oneOf(['1', '2', '3']),\n          oneOfString: PropTypes.oneOf(['static', 'timed']),\n        };\n        \"\n      `);\n      expect(convertJs(input)).toMatchInlineSnapshot(`\n        {\n          \"oneOfNumber\": {\n            \"name\": \"enum\",\n            \"value\": [\n              1,\n              2,\n              3\n            ]\n          },\n          \"oneOfMiscellaneous\": {\n            \"name\": \"enum\",\n            \"value\": [\n              \"false\",\n              \"true\",\n              \"undefined\"\n            ]\n          },\n          \"oneOfStringNumber\": {\n            \"name\": \"enum\",\n            \"value\": [\n              \"1\",\n              \"2\",\n              \"3\"\n            ]\n          },\n          \"oneOfString\": {\n            \"name\": \"enum\",\n            \"value\": [\n              \"static\",\n              \"timed\"\n            ]\n          }\n        }\n      `);\n    });\n    it('misc', () => {\n      const input = readFixture('proptypes/misc.js');\n      expect(input).toMatchInlineSnapshot(`\n        \"import React from 'react';\n\n        import PropTypes from 'prop-types';\n\n        export const Component = (props) => <>JSON.stringify(props)</>;\n        Component.propTypes = {\n          // An object that could be one of many types\n          optionalUnion: PropTypes.oneOfType([\n            PropTypes.string,\n            PropTypes.number,\n            PropTypes.instanceOf(Object),\n          ]),\n          optionalMessage: PropTypes.instanceOf(Object),\n          // A value of any data type\n          requiredAny: PropTypes.any.isRequired,\n        };\n        \"\n      `);\n      expect(convertJs(input)).toMatchInlineSnapshot(`\n        {\n          \"optionalUnion\": {\n            \"name\": \"union\",\n            \"value\": [\n              {\n                \"name\": \"string\"\n              },\n              {\n                \"name\": \"number\"\n              },\n              {\n                \"name\": \"other\",\n                \"value\": \"instanceOf(Object)\"\n              }\n            ]\n          },\n          \"optionalMessage\": {\n            \"name\": \"other\",\n            \"value\": \"instanceOf(Object)\"\n          },\n          \"requiredAny\": {\n            \"name\": \"other\",\n            \"value\": \"any\"\n          }\n        }\n      `);\n    });\n    it('objects', () => {\n      const input = readFixture('proptypes/objects.js');\n      expect(input).toMatchInlineSnapshot(`\n        \"import React from 'react';\n\n        import PropTypes from 'prop-types';\n\n        export const Component = (props) => <>JSON.stringify(props)</>;\n        Component.propTypes = {\n          optionalObject: PropTypes.object,\n          optionalObjectOf: PropTypes.objectOf(PropTypes.number),\n          optionalObjectWithShape: PropTypes.shape({\n            color: PropTypes.string,\n            fontSize: PropTypes.number,\n          }),\n          optionalObjectWithStrictShape: PropTypes.exact({\n            name: PropTypes.string,\n            quantity: PropTypes.number,\n          }),\n        };\n        \"\n      `);\n      expect(convertJs(input)).toMatchInlineSnapshot(`\n        {\n          \"optionalObject\": {\n            \"name\": \"object\"\n          },\n          \"optionalObjectOf\": {\n            \"name\": \"objectOf\",\n            \"value\": {\n              \"name\": \"number\"\n            }\n          },\n          \"optionalObjectWithShape\": {\n            \"name\": \"object\",\n            \"value\": {\n              \"color\": {\n                \"name\": \"string\"\n              },\n              \"fontSize\": {\n                \"name\": \"number\"\n              }\n            }\n          },\n          \"optionalObjectWithStrictShape\": {\n            \"name\": \"object\",\n            \"value\": {\n              \"name\": {\n                \"name\": \"string\"\n              },\n              \"quantity\": {\n                \"name\": \"number\"\n              }\n            }\n          }\n        }\n      `);\n    });\n    it('react', () => {\n      const input = readFixture('proptypes/react.js');\n      expect(input).toMatchInlineSnapshot(`\n        \"import React from 'react';\n\n        import PropTypes from 'prop-types';\n\n        export const Component = (props) => <>JSON.stringify(props)</>;\n        Component.propTypes = {\n          // Anything that can be rendered: numbers, strings, elements or an array\n          // (or fragment) containing these types.\n          optionalNode: PropTypes.node,\n          // A React element.\n          optionalElement: PropTypes.element,\n          // A React element type (ie. MyComponent).\n          optionalElementType: PropTypes.elementType,\n        };\n        \"\n      `);\n      expect(convertJs(input)).toMatchInlineSnapshot(`\n        {\n          \"optionalNode\": {\n            \"name\": \"other\",\n            \"value\": \"node\"\n          },\n          \"optionalElement\": {\n            \"name\": \"other\",\n            \"value\": \"element\"\n          },\n          \"optionalElementType\": {\n            \"name\": \"other\",\n            \"value\": \"elementType\"\n          }\n        }\n      `);\n    });\n  });\n});\n\nconst readFixture = (fixture: string) =>\n  readFileSync(`${__dirname}/__testfixtures__/${fixture}`).toString();\n\nconst transformToModule = (inputCode: string) => {\n  const options = {\n    presets: [\n      [\n        '@babel/preset-env',\n        {\n          targets: {\n            esmodules: true,\n          },\n        },\n      ],\n    ],\n  };\n  const codeTransform = transformSync(inputCode, options);\n  return codeTransform && normalizeNewlines(codeTransform.code ?? '');\n};\n\nconst annotateWithDocgen = (inputCode: string, filename: string) => {\n  const options = {\n    presets: ['@babel/typescript', '@babel/react'],\n    plugins: ['babel-plugin-react-docgen', '@babel/plugin-transform-class-properties'],\n    babelrc: false,\n    filename,\n  };\n  const codeTransform = transformSync(inputCode, options);\n  return codeTransform && normalizeNewlines(codeTransform.code ?? '');\n};\n\nconst convertCommon = (code: string, fileExt: string) => {\n  const docgenPretty = annotateWithDocgen(code, `temp.${fileExt}`);\n  const { Component } = requireFromString(transformToModule(docgenPretty ?? ''));\n  const { props = {} } = Component.__docgenInfo || {};\n  const types = mapValues(props, (prop) => convert(prop));\n  return types;\n};\n\nconst convertTs = (code: string) => convertCommon(code, 'tsx');\n\nconst convertJs = (code: string) => convertCommon(code, 'js');\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/flow/convert.ts",
    "content": "import { UnknownArgTypesError } from 'storybook/internal/preview-errors';\nimport type { SBType } from 'storybook/internal/types';\n\nimport type { FlowLiteralType, FlowSigType, FlowType } from './types.ts';\n\nconst isLiteral = (type: FlowType): type is FlowLiteralType => type.name === 'literal';\nconst toEnumOption = (element: FlowLiteralType) => element.value.replace(/['|\"]/g, '');\n\nconst convertSig = (type: FlowSigType) => {\n  switch (type.type) {\n    case 'function':\n      return { name: 'function' };\n    case 'object':\n      const values: any = {};\n      type.signature.properties.forEach((prop) => {\n        values[prop.key] = convert(prop.value);\n      });\n      return {\n        name: 'object',\n        value: values,\n      };\n    default:\n      throw new UnknownArgTypesError({ type: type, language: 'Flow' });\n  }\n};\n\nexport const convert = (type: FlowType): SBType | void => {\n  const { name, raw } = type;\n  const base: any = {};\n\n  if (typeof raw !== 'undefined') {\n    base.raw = raw;\n  }\n  switch (type.name) {\n    case 'literal':\n      return { ...base, name: 'other', value: type.value };\n    case 'string':\n    case 'number':\n    case 'symbol':\n    case 'boolean': {\n      return { ...base, name };\n    }\n    case 'Array': {\n      return { ...base, name: 'array', value: type.elements.map(convert) };\n    }\n    case 'signature':\n      return { ...base, ...convertSig(type) };\n    case 'union':\n      if (type.elements?.every(isLiteral)) {\n        return { ...base, name: 'enum', value: type.elements?.map(toEnumOption) };\n      }\n      return { ...base, name, value: type.elements?.map(convert) };\n\n    case 'intersection':\n      return { ...base, name, value: type.elements?.map(convert) };\n    default:\n      return { ...base, name: 'other', value: name };\n  }\n};\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/flow/index.ts",
    "content": "export * from './convert.ts';\nexport * from './types.ts';\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/flow/types.ts",
    "content": "interface FlowBaseType {\n  name: string;\n  type?: string;\n  raw?: string;\n  required?: boolean;\n}\n\ntype FlowArgType = FlowType;\n\ntype FlowCombinationType = FlowBaseType & {\n  name: 'union' | 'intersection';\n  elements: FlowType[];\n};\n\ntype FlowFuncSigType = FlowBaseType & {\n  name: 'signature';\n  type: 'function';\n  signature: {\n    arguments: FlowArgType[];\n    return: FlowType;\n  };\n};\n\ntype FlowObjectSigType = FlowBaseType & {\n  name: 'signature';\n  type: 'object';\n  signature: {\n    properties: {\n      key: string;\n      value: FlowType;\n    }[];\n  };\n};\n\ntype FlowScalarType = FlowBaseType & {\n  name: 'any' | 'boolean' | 'number' | 'void' | 'string' | 'symbol';\n};\n\nexport type FlowLiteralType = FlowBaseType & {\n  name: 'literal';\n  value: string;\n};\n\ntype FlowArrayType = FlowBaseType & {\n  name: 'Array';\n  elements: FlowType[];\n};\n\nexport type FlowSigType = FlowObjectSigType | FlowFuncSigType;\n\nexport type FlowType =\n  | FlowScalarType\n  | FlowLiteralType\n  | FlowCombinationType\n  | FlowSigType\n  | FlowArrayType;\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/index.ts",
    "content": "import type { DocgenInfo } from '../docgen/types.ts';\nimport type { FlowType } from './flow/index.ts';\nimport { convert as flowConvert } from './flow/index.ts';\nimport { convert as propTypesConvert } from './proptypes/index.ts';\nimport type { TSType } from './typescript/index.ts';\nimport { convert as tsConvert } from './typescript/index.ts';\n\nexport const convert = (docgenInfo: DocgenInfo) => {\n  const { type, tsType, flowType } = docgenInfo;\n  try {\n    if (type != null) {\n      return propTypesConvert(type);\n    }\n\n    if (tsType != null) {\n      return tsConvert(tsType as TSType);\n    }\n\n    if (flowType != null) {\n      return flowConvert(flowType as FlowType);\n    }\n  } catch (err) {\n    // if we can't convert the type, we'll just return null to fallback to a simple summary, and provide the error to the user\n    console.error(err);\n  }\n\n  return null;\n};\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/proptypes/convert.ts",
    "content": "import type { SBType } from 'storybook/internal/types';\n\nimport { mapValues } from 'es-toolkit/object';\n\nimport { parseLiteral } from '../utils.ts';\nimport type { PTType } from './types.ts';\n\nconst SIGNATURE_REGEXP = /^\\(.*\\) => /;\n\nexport const convert = (type: PTType): SBType | any => {\n  const { name, raw, computed, value } = type;\n  const base: any = {};\n\n  if (typeof raw !== 'undefined') {\n    base.raw = raw;\n  }\n\n  switch (name) {\n    case 'enum': {\n      const values = computed ? value : value.map((v: PTType) => parseLiteral(v.value));\n      return { ...base, name, value: values };\n    }\n    case 'string':\n    case 'number':\n    case 'symbol':\n      return { ...base, name };\n    case 'func':\n      return { ...base, name: 'function' };\n    case 'bool':\n    case 'boolean':\n      return { ...base, name: 'boolean' };\n    case 'arrayOf':\n    case 'array':\n      return { ...base, name: 'array', value: value && convert(value as PTType) };\n    case 'object':\n      return { ...base, name };\n    case 'objectOf':\n      return { ...base, name, value: convert(value as PTType) };\n    case 'shape':\n    case 'exact':\n      const values = mapValues(value, (field) => convert(field));\n      return { ...base, name: 'object', value: values };\n    case 'union':\n      return { ...base, name: 'union', value: value.map((v: PTType) => convert(v)) };\n    case 'instanceOf':\n    case 'element':\n    case 'elementType':\n    default: {\n      if (name?.indexOf('|') > 0) {\n        // react-docgen-typescript-plugin doesn't always produce enum-like unions\n        // (like if a user has turned off shouldExtractValuesFromUnion) so here we\n        // try to recover and construct one.\n        try {\n          const literalValues = name.split('|').map((v: string) => JSON.parse(v));\n          return { ...base, name: 'enum', value: literalValues };\n        } catch (err) {\n          // fall through\n        }\n      }\n      const otherVal = value ? `${name}(${value})` : name;\n      const otherName = SIGNATURE_REGEXP.test(name) ? 'function' : 'other';\n\n      return { ...base, name: otherName, value: otherVal };\n    }\n  }\n};\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/proptypes/index.ts",
    "content": "export * from './convert.ts';\nexport * from './types.ts';\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/proptypes/types.ts",
    "content": "interface PTBaseType {\n  name: string;\n  description?: string;\n  required?: boolean;\n}\n\nexport type PTType = PTBaseType & {\n  value?: any;\n  raw?: string;\n  computed?: boolean;\n};\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/typescript/convert.ts",
    "content": "import { UnknownArgTypesError } from 'storybook/internal/preview-errors';\nimport type { SBType } from 'storybook/internal/types';\n\nimport { parseLiteral } from '../utils.ts';\nimport type { TSSigType, TSType } from './types.ts';\n\n// Type guards for narrowing TSType discriminant unions\ntype TSLiteralType = Extract<TSType, { name: 'literal' }>;\ntype TSUndefinedType = Extract<TSType, { name: 'undefined' }>;\n\nconst isLiteral = (type: TSType): type is TSLiteralType => type.name === 'literal';\nconst isUndefined = (type: TSType): type is TSUndefinedType => type.name === 'undefined';\n\nconst convertSig = (type: TSSigType) => {\n  switch (type.type) {\n    case 'function':\n      return { name: 'function' };\n    case 'object':\n      const values: any = {};\n      type.signature.properties.forEach((prop) => {\n        values[prop.key] = convert(prop.value);\n      });\n      return {\n        name: 'object',\n        value: values,\n      };\n    default:\n      throw new UnknownArgTypesError({ type, language: 'Typescript' });\n  }\n};\n\nexport const convert = (type: TSType): SBType | void => {\n  const { name, raw } = type;\n  const base: any = {};\n\n  if (typeof raw !== 'undefined') {\n    base.raw = raw;\n  }\n  switch (type.name) {\n    case 'string':\n    case 'number':\n    case 'symbol':\n    case 'boolean': {\n      return { ...base, name };\n    }\n    case 'Array': {\n      return { ...base, name: 'array', value: type.elements.map(convert) };\n    }\n    case 'signature':\n      return { ...base, ...convertSig(type) };\n    case 'union': {\n      const nonUndefinedElements = type.elements.filter((element) => !isUndefined(element));\n      const allLiterals = nonUndefinedElements.length > 0 && nonUndefinedElements.every(isLiteral);\n\n      if (allLiterals) {\n        // TypeScript can't infer from .every(), so we filter again with the type guard\n        const literalElements = nonUndefinedElements.filter(isLiteral);\n        return {\n          ...base,\n          name: 'enum',\n          value: literalElements.map((element) => parseLiteral(element.value)),\n        };\n      }\n      return { ...base, name, value: type.elements.map(convert) };\n    }\n    case 'intersection':\n      return { ...base, name, value: type.elements.map(convert) };\n    default:\n      return { ...base, name: 'other', value: name };\n  }\n};\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/typescript/index.ts",
    "content": "export * from './convert.ts';\nexport * from './types.ts';\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/typescript/types.ts",
    "content": "interface TSBaseType {\n  name: string;\n  type?: string;\n  raw?: string;\n  required?: boolean;\n}\n\ntype TSArgType = TSType;\n\ntype TSCombinationType = TSBaseType & {\n  name: 'union' | 'intersection';\n  elements: TSType[];\n};\n\ntype TSFuncSigType = TSBaseType & {\n  name: 'signature';\n  type: 'function';\n  signature: {\n    arguments: TSArgType[];\n    return: TSType;\n  };\n};\n\ntype TSObjectSigType = TSBaseType & {\n  name: 'signature';\n  type: 'object';\n  signature: {\n    properties: {\n      key: string;\n      value: TSType;\n    }[];\n  };\n};\n\ntype TSScalarType = TSBaseType & {\n  name: 'any' | 'boolean' | 'number' | 'void' | 'string' | 'symbol' | 'undefined';\n};\n\ntype TSLiteralType = TSBaseType & {\n  name: 'literal';\n  value: string;\n};\n\ntype TSArrayType = TSBaseType & {\n  name: 'Array';\n  elements: TSType[];\n};\n\nexport type TSSigType = TSObjectSigType | TSFuncSigType;\n\nexport type TSType = TSScalarType | TSLiteralType | TSCombinationType | TSSigType | TSArrayType;\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/convert/utils.ts",
    "content": "const QUOTE_REGEX = /^['\"]|['\"]$/g;\nexport const trimQuotes = (str: string) => str.replace(QUOTE_REGEX, '');\nexport const includesQuotes = (str: string) => QUOTE_REGEX.test(str);\nexport const parseLiteral = (str: string) => {\n  const trimmedValue = trimQuotes(str);\n\n  return includesQuotes(str) || Number.isNaN(Number(trimmedValue))\n    ? trimmedValue\n    : Number(trimmedValue);\n};\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/docgen/PropDef.ts",
    "content": "// FIXME: this is legacy code that needs to be updated & simplified with ArgType refactor\n\nexport interface JsDocParam {\n  name: string | undefined | null;\n  description?: string | null;\n}\n\nexport interface JsDocReturns {\n  description?: string | null;\n}\n\nexport interface JsDocTags {\n  params?: JsDocParam[] | null;\n  returns?: JsDocReturns | null;\n}\n\nexport interface PropSummaryValue {\n  summary?: string | undefined;\n  detail?: string | undefined;\n}\n\nexport type PropType = PropSummaryValue;\nexport type PropDefaultValue = PropSummaryValue;\n\nexport interface PropDef {\n  name: string;\n  type: PropType | null;\n  sbType?: any;\n  required: boolean;\n  description?: string;\n  defaultValue?: PropDefaultValue | null;\n  jsDocTags?: JsDocTags;\n}\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/docgen/createPropDef.ts",
    "content": "import { convert } from '../convert/index.ts';\nimport type { JsDocParsingResult } from '../jsdocParser.ts';\nimport { createSummaryValue } from '../utils.ts';\nimport type { JsDocParam, PropDefaultValue } from './PropDef.ts';\nimport { createFlowPropDef } from './flow/createPropDef.ts';\nimport { createTsPropDef } from './typeScript/createPropDef.ts';\nimport type { DocgenInfo, DocgenPropDefaultValue, DocgenType, PropDef } from './types.ts';\nimport { TypeSystem } from './types.ts';\nimport { isDefaultValueBlacklisted } from './utils/defaultValue.ts';\n\nexport type PropDefFactory = (\n  propName: string,\n  docgenInfo: DocgenInfo,\n  jsDocParsingResult?: JsDocParsingResult\n) => PropDef;\n\nfunction createType(type: DocgenType) {\n  // A type could be null if a defaultProp has been provided without a type definition.\n  return type != null ? createSummaryValue(type.name) : null;\n}\n\n// A heuristic to tell if a defaultValue comes from RDT\nfunction isReactDocgenTypescript(defaultValue: DocgenPropDefaultValue) {\n  const { computed, func } = defaultValue;\n  return typeof computed === 'undefined' && typeof func === 'undefined';\n}\n\nfunction isStringValued(type?: DocgenType) {\n  if (!type) {\n    return false;\n  }\n\n  if (type.name === 'string') {\n    return true;\n  }\n\n  if (type.name === 'enum') {\n    return (\n      Array.isArray(type.value) &&\n      type.value.every(\n        ({ value: tv }) => typeof tv === 'string' && tv[0] === '\"' && tv[tv.length - 1] === '\"'\n      )\n    );\n  }\n  return false;\n}\n\nfunction createDefaultValue(\n  defaultValue: DocgenPropDefaultValue,\n  type: DocgenType\n): PropDefaultValue | null {\n  if (defaultValue != null) {\n    const { value } = defaultValue;\n\n    if (!isDefaultValueBlacklisted(value)) {\n      // Work around a bug in `react-docgen-typescript-loader`, which returns 'string' for a string\n      // default, instead of \"'string'\" -- which is incorrect\n      if (isReactDocgenTypescript(defaultValue) && isStringValued(type)) {\n        return createSummaryValue(JSON.stringify(value));\n      }\n\n      return createSummaryValue(value);\n    }\n  }\n\n  return null;\n}\n\nfunction createBasicPropDef(name: string, type: DocgenType, docgenInfo: DocgenInfo): PropDef {\n  const { description, required, defaultValue } = docgenInfo;\n\n  return {\n    name,\n    type: createType(type),\n    required,\n    description,\n    defaultValue: createDefaultValue(defaultValue, type),\n  };\n}\n\nfunction applyJsDocResult(propDef: PropDef, jsDocParsingResult?: JsDocParsingResult): PropDef {\n  if (jsDocParsingResult?.includesJsDoc) {\n    const { description, extractedTags } = jsDocParsingResult;\n\n    if (description != null) {\n      propDef.description = jsDocParsingResult.description;\n    }\n\n    const value = {\n      ...extractedTags,\n      params: extractedTags?.params?.map(\n        (x): JsDocParam => ({\n          name: x.getPrettyName(),\n          description: x.description,\n        })\n      ),\n    };\n\n    if (Object.values(value).filter(Boolean).length > 0) {\n      propDef.jsDocTags = value;\n    }\n  }\n\n  return propDef;\n}\n\nexport const javaScriptFactory: PropDefFactory = (propName, docgenInfo, jsDocParsingResult) => {\n  const propDef = createBasicPropDef(propName, docgenInfo.type, docgenInfo);\n  propDef.sbType = convert(docgenInfo);\n\n  return applyJsDocResult(propDef, jsDocParsingResult);\n};\n\nexport const tsFactory: PropDefFactory = (propName, docgenInfo, jsDocParsingResult) => {\n  const propDef = createTsPropDef(propName, docgenInfo);\n  propDef.sbType = convert(docgenInfo);\n\n  return applyJsDocResult(propDef, jsDocParsingResult);\n};\n\nexport const flowFactory: PropDefFactory = (propName, docgenInfo, jsDocParsingResult) => {\n  const propDef = createFlowPropDef(propName, docgenInfo);\n  propDef.sbType = convert(docgenInfo);\n\n  return applyJsDocResult(propDef, jsDocParsingResult);\n};\n\nexport const unknownFactory: PropDefFactory = (propName, docgenInfo, jsDocParsingResult) => {\n  const propDef = createBasicPropDef(propName, { name: 'unknown' }, docgenInfo);\n\n  return applyJsDocResult(propDef, jsDocParsingResult);\n};\n\nexport const getPropDefFactory = (typeSystem: TypeSystem): PropDefFactory => {\n  switch (typeSystem) {\n    case TypeSystem.JAVASCRIPT:\n      return javaScriptFactory;\n    case TypeSystem.TYPESCRIPT:\n      return tsFactory;\n    case TypeSystem.FLOW:\n      return flowFactory;\n    default:\n      return unknownFactory;\n  }\n};\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/docgen/extractDocgenProps.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport type { Component } from '../types.ts';\nimport { extractComponentProps } from './extractDocgenProps.ts';\n\nconst DOCGEN_SECTION = 'props';\nconst PROP_NAME = 'propName';\n\ninterface TypeSystemDef {\n  name: string;\n  typeProperty: string;\n}\n\nconst TypeSystems: TypeSystemDef[] = [\n  { name: 'javascript', typeProperty: 'type' },\n  { name: 'typescript', typeProperty: 'tsType' },\n  { name: 'flow', typeProperty: 'flowType' },\n];\n\nfunction createType(typeName: string, others: Record<string, any> = {}): Record<string, string> {\n  return {\n    name: typeName,\n    ...others,\n  };\n}\n\nfunction createStringType(typeSystemDef: TypeSystemDef, others: Record<string, any> = {}): any {\n  return {\n    [typeSystemDef.typeProperty]: createType('string', others),\n  };\n}\n\nfunction createFuncType(typeSystemDef: TypeSystemDef, others: Record<string, any> = {}): any {\n  const typeName = typeSystemDef.name === 'javascript' ? 'func' : '() => {}';\n\n  return {\n    [typeSystemDef.typeProperty]: createType(typeName, others),\n  };\n}\n\nfunction createComponent(docgenInfo: Record<string, any>): Component {\n  const component = () => {};\n  component.__docgenInfo = {\n    [DOCGEN_SECTION]: {\n      [PROP_NAME]: {\n        required: false,\n        ...docgenInfo,\n      },\n    },\n  };\n\n  return component;\n}\n\nTypeSystems.forEach((x) => {\n  describe(`${x.name}`, () => {\n    it('should map defaults docgen info properly', () => {\n      const component = createComponent({\n        ...createStringType(x),\n        description: 'Hey! Hey!',\n        defaultValue: {\n          value: \"'Default'\",\n          computed: false,\n        },\n      });\n\n      const { propDef } = extractComponentProps(component, DOCGEN_SECTION)[0];\n\n      expect(propDef.name).toBe(PROP_NAME);\n      expect(propDef.type?.summary).toBe('string');\n      expect(propDef.description).toBe('Hey! Hey!');\n      expect(propDef.required).toBe(false);\n      expect(propDef.defaultValue?.summary).toBe(\"'Default'\");\n    });\n\n    if (x === TypeSystems[0]) {\n      // NOTE: `react-docgen-typescript currently doesn't serialize string as expected\n      it('should map defaults docgen info properly, RDT broken strings', () => {\n        const component = createComponent({\n          ...createStringType(x),\n          description: 'Hey! Hey!',\n          defaultValue: {\n            value: 'Default',\n          },\n        });\n\n        const { propDef } = extractComponentProps(component, DOCGEN_SECTION)[0];\n\n        expect(propDef.name).toBe(PROP_NAME);\n        expect(propDef.type?.summary).toBe('string');\n        expect(propDef.description).toBe('Hey! Hey!');\n        expect(propDef.required).toBe(false);\n        expect(propDef.defaultValue?.summary).toBe('\"Default\"');\n      });\n\n      it('should map defaults docgen info properly, RDT broken enums', () => {\n        const component = createComponent({\n          [x.typeProperty]: createType('enum', {\n            value: [{ value: '\"Default\"' }, { value: '\"Other\"' }],\n          }),\n          description: 'Hey! Hey!',\n          defaultValue: {\n            value: 'Default',\n          },\n        });\n\n        const { propDef } = extractComponentProps(component, DOCGEN_SECTION)[0];\n\n        expect(propDef.name).toBe(PROP_NAME);\n        expect(propDef.type?.summary).toBe('enum');\n        expect(propDef.description).toBe('Hey! Hey!');\n        expect(propDef.required).toBe(false);\n        expect(propDef.defaultValue?.summary).toBe('\"Default\"');\n      });\n\n      it('should map defaults docgen info properly, vue', () => {\n        const component = createComponent({\n          ...createStringType(x),\n          description: 'Hey! Hey!',\n          defaultValue: {\n            value: \"'Default'\",\n            func: false,\n          },\n        });\n\n        const { propDef } = extractComponentProps(component, DOCGEN_SECTION)[0];\n\n        expect(propDef.name).toBe(PROP_NAME);\n        expect(propDef.type?.summary).toBe('string');\n        expect(propDef.description).toBe('Hey! Hey!');\n        expect(propDef.required).toBe(false);\n        expect(propDef.defaultValue?.summary).toBe(\"'Default'\");\n      });\n    }\n\n    it('should remove JSDoc tags from the description', () => {\n      const component = createComponent({\n        ...createStringType(x),\n        description: 'Hey!\\n@param event\\nreturns {string}',\n      });\n\n      const { propDef } = extractComponentProps(component, DOCGEN_SECTION)[0];\n\n      expect(propDef.description).toBe('Hey!');\n    });\n\n    it('should not remove newline characters of multilines description without JSDoc tags', () => {\n      const component = createComponent({\n        ...createStringType(x),\n        description: 'onClick description\\nis a\\nmulti-lines\\ndescription',\n      });\n\n      const { propDef } = extractComponentProps(component, DOCGEN_SECTION)[0];\n\n      expect(propDef.description).toBe('onClick description\\nis a\\nmulti-lines\\ndescription');\n    });\n\n    it('should not remove newline characters of multilines description with JSDoc tags', () => {\n      const component = createComponent({\n        ...createFuncType(x),\n        description: 'onClick description\\nis a\\nmulti-lines\\ndescription\\n@param event',\n      });\n\n      const { propDef } = extractComponentProps(component, DOCGEN_SECTION)[0];\n\n      expect(propDef.description).toBe('onClick description\\nis a\\nmulti-lines\\ndescription');\n    });\n\n    it('should not remove markdown from description without JSDoc tags', () => {\n      const component = createComponent({\n        ...createStringType(x),\n        description: 'onClick *emphasis*, **strong**, `formatted` description.',\n      });\n\n      const { propDef } = extractComponentProps(component, DOCGEN_SECTION)[0];\n\n      expect(propDef.description).toBe('onClick *emphasis*, **strong**, `formatted` description.');\n    });\n\n    it('should not remove markdown from description with JSDoc tags', () => {\n      const component = createComponent({\n        ...createFuncType(x),\n        description: 'onClick *emphasis*, **strong**, `formatted` description.\\n@param event',\n      });\n\n      const { propDef } = extractComponentProps(component, DOCGEN_SECTION)[0];\n\n      expect(propDef.description).toBe('onClick *emphasis*, **strong**, `formatted` description.');\n    });\n\n    it('should return null when the property is marked with @ignore', () => {\n      const component = createComponent({\n        ...createStringType(x),\n        description: 'onClick description\\n@ignore',\n      });\n\n      expect(extractComponentProps(component, DOCGEN_SECTION).length).toBe(0);\n    });\n\n    it('should provide raw @param tags', () => {\n      const component = createComponent({\n        ...createFuncType(x),\n        description:\n          'onClick description\\n@param {SyntheticEvent} event - Original event.\\n@param {string} value',\n      });\n\n      const { propDef } = extractComponentProps(component, DOCGEN_SECTION)[0];\n\n      expect(propDef.description).toBe('onClick description');\n      expect(propDef.jsDocTags).toBeDefined();\n      expect(propDef.jsDocTags?.params).toBeDefined();\n      expect(propDef.jsDocTags?.params?.[0].name).toBe('event');\n      expect(propDef.jsDocTags?.params?.[0].description).toBe('Original event.');\n      expect(propDef.jsDocTags?.params?.[1].name).toBe('value');\n      expect(propDef.jsDocTags?.params?.[1].description).toBeNull();\n    });\n\n    it(\"should not return 'null' default value\", () => {\n      const component = createComponent({\n        ...createStringType(x),\n        defaultValue: { value: 'null' },\n      });\n\n      const { propDef } = extractComponentProps(component, DOCGEN_SECTION)[0];\n\n      expect(propDef.defaultValue).toBeNull();\n    });\n\n    it(\"should not return 'undefined' default value\", () => {\n      const component = createComponent({\n        ...createStringType(x),\n        defaultValue: { value: 'undefined' },\n      });\n\n      const { propDef } = extractComponentProps(component, DOCGEN_SECTION)[0];\n\n      expect(propDef.defaultValue).toBeNull();\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/docgen/extractDocgenProps.ts",
    "content": "import type { ExtractedJsDoc } from '../jsdocParser.ts';\nimport { parseJsDoc } from '../jsdocParser.ts';\nimport type { Component } from '../types.ts';\nimport type { PropDefFactory } from './createPropDef.ts';\nimport { getPropDefFactory } from './createPropDef.ts';\nimport type { DocgenInfo, PropDef } from './types.ts';\nimport { TypeSystem } from './types.ts';\nimport { getDocgenDescription, getDocgenSection, isValidDocgenSection } from './utils/index.ts';\n\nexport interface ExtractedProp {\n  propDef: PropDef;\n  docgenInfo: DocgenInfo;\n  jsDocTags?: ExtractedJsDoc;\n  typeSystem: TypeSystem;\n}\n\nexport type ExtractProps = (component: Component, section: string) => ExtractedProp[];\n\nconst getTypeSystem = (docgenInfo: DocgenInfo): TypeSystem => {\n  if (docgenInfo.type != null) {\n    return TypeSystem.JAVASCRIPT;\n  }\n\n  if (docgenInfo.flowType != null) {\n    return TypeSystem.FLOW;\n  }\n\n  if (docgenInfo.tsType != null) {\n    return TypeSystem.TYPESCRIPT;\n  }\n\n  return TypeSystem.UNKNOWN;\n};\n\nexport const extractComponentSectionArray = (docgenSection: any) => {\n  const typeSystem = getTypeSystem(docgenSection[0]);\n  const createPropDef = getPropDefFactory(typeSystem);\n\n  return docgenSection.map((item: any) => {\n    let sanitizedItem = item;\n    if (item.type?.elements) {\n      sanitizedItem = {\n        ...item,\n        type: {\n          ...item.type,\n          value: item.type.elements,\n        },\n      };\n    }\n    return extractProp(sanitizedItem.name, sanitizedItem, typeSystem, createPropDef);\n  });\n};\n\nexport const extractComponentSectionObject = (docgenSection: any) => {\n  const docgenPropsKeys = Object.keys(docgenSection);\n  const typeSystem = getTypeSystem(docgenSection[docgenPropsKeys[0]]);\n  const createPropDef = getPropDefFactory(typeSystem);\n\n  return docgenPropsKeys\n    .map((propName) => {\n      const docgenInfo = docgenSection[propName];\n\n      return docgenInfo != null\n        ? extractProp(propName, docgenInfo, typeSystem, createPropDef)\n        : null;\n    })\n    .filter(Boolean);\n};\n\nexport const extractComponentProps: ExtractProps = (component, section) => {\n  const docgenSection = getDocgenSection(component, section);\n\n  if (!isValidDocgenSection(docgenSection)) {\n    return [];\n  }\n\n  // vue-docgen-api has diverged from react-docgen and returns an array\n  return Array.isArray(docgenSection)\n    ? extractComponentSectionArray(docgenSection)\n    : extractComponentSectionObject(docgenSection);\n};\n\nfunction extractProp(\n  propName: string,\n  docgenInfo: DocgenInfo,\n  typeSystem: TypeSystem,\n  createPropDef: PropDefFactory\n): ExtractedProp | null {\n  const jsDocParsingResult = parseJsDoc(docgenInfo.description);\n  const isIgnored = jsDocParsingResult.includesJsDoc && jsDocParsingResult.ignore;\n\n  if (!isIgnored) {\n    const propDef = createPropDef(propName, docgenInfo, jsDocParsingResult);\n\n    return {\n      propDef,\n      jsDocTags: jsDocParsingResult.extractedTags,\n      docgenInfo,\n      typeSystem,\n    };\n  }\n\n  return null;\n}\n\nexport function extractComponentDescription(component?: Component): string {\n  return component != null ? getDocgenDescription(component) : '';\n}\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/docgen/flow/createDefaultValue.ts",
    "content": "import { createSummaryValue, isTooLongForDefaultValueSummary } from '../../utils.ts';\nimport type { PropDefaultValue } from '../PropDef.ts';\nimport type { DocgenPropDefaultValue, DocgenPropType } from '../types.ts';\nimport { isDefaultValueBlacklisted } from '../utils/defaultValue.ts';\n\nexport function createDefaultValue(\n  defaultValue: DocgenPropDefaultValue | null,\n  type: DocgenPropType | null\n): PropDefaultValue | null {\n  if (defaultValue != null) {\n    const { value } = defaultValue;\n\n    if (!isDefaultValueBlacklisted(value)) {\n      return !isTooLongForDefaultValueSummary(value)\n        ? createSummaryValue(value)\n        : createSummaryValue(type?.name, value);\n    }\n  }\n\n  return null;\n}\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/docgen/flow/createPropDef.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport type { DocgenInfo } from '../types.ts';\nimport { createFlowPropDef } from './createPropDef.ts';\n\nconst PROP_NAME = 'propName';\n\nfunction createDocgenInfo({ flowType, ...others }: Partial<DocgenInfo>): DocgenInfo {\n  return {\n    flowType,\n    required: false,\n    ...others,\n  } as DocgenInfo;\n}\n\ndescribe('type', () => {\n  ['string', 'number', 'boolean', 'any', 'void', 'Object', 'String', 'MyClass', 'literal'].forEach(\n    (x) => {\n      it(`should support ${x}`, () => {\n        const docgenInfo = createDocgenInfo({\n          flowType: { name: x },\n        });\n\n        const { type } = createFlowPropDef(PROP_NAME, docgenInfo);\n\n        expect(type?.summary).toBe(x);\n        expect(type?.detail).toBeUndefined();\n      });\n    }\n  );\n\n  ['Array', 'Class', 'MyClass'].forEach((x) => {\n    it(`should support untyped ${x}`, () => {\n      const docgenInfo = createDocgenInfo({\n        flowType: { name: x },\n      });\n\n      const { type } = createFlowPropDef(PROP_NAME, docgenInfo);\n\n      expect(type?.summary).toBe(x);\n      expect(type?.detail).toBeUndefined();\n    });\n\n    it(`should support typed ${x}`, () => {\n      const docgenInfo = createDocgenInfo({\n        flowType: {\n          name: x,\n          elements: [\n            {\n              name: 'any',\n            },\n          ],\n          raw: `${x}<any>`,\n        },\n      });\n\n      const { type } = createFlowPropDef(PROP_NAME, docgenInfo);\n\n      expect(type?.summary).toBe(`${x}<any>`);\n      expect(type?.detail).toBeUndefined();\n    });\n  });\n\n  it('should support short object signature', () => {\n    const docgenInfo = createDocgenInfo({\n      flowType: {\n        name: 'signature',\n        type: 'object',\n        raw: '{ foo: string, bar?: mixed }',\n        signature: {\n          properties: [\n            {\n              key: 'foo',\n              value: {\n                name: 'string',\n                required: true,\n              },\n            },\n            {\n              key: 'bar',\n              value: {\n                name: 'mixed',\n                required: false,\n              },\n            },\n          ],\n        },\n      },\n    });\n\n    const { type } = createFlowPropDef(PROP_NAME, docgenInfo);\n\n    expect(type?.summary).toBe('{ foo: string, bar?: mixed }');\n    expect(type?.detail).toBeUndefined();\n  });\n\n  it('should support long object signature', () => {\n    const docgenInfo = createDocgenInfo({\n      flowType: {\n        name: 'signature',\n        type: 'object',\n        raw: '{ (x: string): void, prop1: string, prop2: string, prop3: string, prop4: string, prop5: string, prop6: string, prop7: string, prop8: string }',\n        signature: {\n          properties: [\n            {\n              key: 'prop1',\n              value: {\n                name: 'string',\n                required: true,\n              },\n            },\n            {\n              key: 'prop2',\n              value: {\n                name: 'string',\n                required: true,\n              },\n            },\n            {\n              key: 'prop3',\n              value: {\n                name: 'string',\n                required: true,\n              },\n            },\n            {\n              key: 'prop4',\n              value: {\n                name: 'string',\n                required: true,\n              },\n            },\n            {\n              key: 'prop5',\n              value: {\n                name: 'string',\n                required: true,\n              },\n            },\n            {\n              key: 'prop5',\n              value: {\n                name: 'string',\n                required: true,\n              },\n            },\n            {\n              key: 'prop6',\n              value: {\n                name: 'string',\n                required: true,\n              },\n            },\n            {\n              key: 'prop7',\n              value: {\n                name: 'string',\n                required: true,\n              },\n            },\n            {\n              key: 'prop8',\n              value: {\n                name: 'string',\n                required: true,\n              },\n            },\n          ],\n          constructor: {\n            name: 'signature',\n            type: 'function',\n            raw: '(x: string): void',\n            signature: {\n              arguments: [\n                {\n                  name: 'x',\n                  type: {\n                    name: 'string',\n                  },\n                },\n              ],\n              return: {\n                name: 'void',\n              },\n            },\n          },\n        },\n      },\n    });\n\n    const { type } = createFlowPropDef(PROP_NAME, docgenInfo);\n\n    expect(type?.summary).toBe('object');\n    expect(type?.detail).toBe(\n      '{ (x: string): void, prop1: string, prop2: string, prop3: string, prop4: string, prop5: string, prop6: string, prop7: string, prop8: string }'\n    );\n  });\n\n  it('should support func signature', () => {\n    const docgenInfo = createDocgenInfo({\n      flowType: {\n        name: 'signature',\n        type: 'function',\n        raw: '(x: string) => void',\n        signature: {\n          arguments: [\n            {\n              name: 'x',\n              type: {\n                name: 'string',\n              },\n            },\n          ],\n          return: {\n            name: 'void',\n          },\n        },\n      },\n    });\n\n    const { type } = createFlowPropDef(PROP_NAME, docgenInfo);\n\n    expect(type?.summary).toBe('(x: string) => void');\n    expect(type?.detail).toBeUndefined();\n  });\n\n  it('should support tuple', () => {\n    const docgenInfo = createDocgenInfo({\n      flowType: {\n        name: 'tuple',\n        raw: '[foo, \"value\", number]',\n        elements: [\n          {\n            name: 'foo',\n          },\n          {\n            name: 'literal',\n            value: '\"value\"',\n          },\n          {\n            name: 'number',\n          },\n        ],\n      },\n    });\n\n    const { type } = createFlowPropDef(PROP_NAME, docgenInfo);\n\n    expect(type?.summary).toBe('[foo, \"value\", number]');\n  });\n\n  it('should support union', () => {\n    const docgenInfo = createDocgenInfo({\n      flowType: {\n        name: 'union',\n        raw: 'number | string',\n        elements: [\n          {\n            name: 'number',\n          },\n          {\n            name: 'string',\n          },\n        ],\n      },\n    });\n\n    const { type } = createFlowPropDef(PROP_NAME, docgenInfo);\n\n    expect(type?.summary).toBe('number | string');\n  });\n\n  it('should support nested union elements', () => {\n    const docgenInfo = createDocgenInfo({\n      flowType: {\n        name: 'union',\n        raw: '\"minimum\" | \"maximum\" | UserSize',\n        elements: [\n          {\n            name: 'literal',\n            value: '\"minimum\"',\n          },\n          {\n            name: 'literal',\n            value: '\"maximum\"',\n          },\n          {\n            name: 'union',\n            raw: 'string | number',\n            elements: [\n              {\n                name: 'number',\n              },\n              {\n                name: 'string',\n              },\n            ],\n          },\n        ],\n      },\n    });\n\n    const { type } = createFlowPropDef(PROP_NAME, docgenInfo);\n\n    expect(type?.summary).toBe('\"minimum\" | \"maximum\" | number | string');\n  });\n\n  it('uses raw union value if elements are missing', () => {\n    const docgenInfo = createDocgenInfo({\n      flowType: {\n        name: 'union',\n        raw: '\"minimum\" | \"maximum\" | UserSize',\n      },\n    });\n\n    const { type } = createFlowPropDef(PROP_NAME, docgenInfo);\n\n    expect(type?.summary).toBe('\"minimum\" | \"maximum\" | UserSize');\n  });\n\n  it('removes a leading | if raw union value is used', () => {\n    const docgenInfo = createDocgenInfo({\n      flowType: {\n        name: 'union',\n        raw: '| \"minimum\" | \"maximum\" | UserSize',\n      },\n    });\n\n    const { type } = createFlowPropDef(PROP_NAME, docgenInfo);\n\n    expect(type?.summary).toBe('\"minimum\" | \"maximum\" | UserSize');\n  });\n\n  it('even removes extra spaces after a leading | if raw union value is used', () => {\n    const docgenInfo = createDocgenInfo({\n      flowType: {\n        name: 'union',\n        raw: '|     \"minimum\" | \"maximum\" | UserSize',\n      },\n    });\n\n    const { type } = createFlowPropDef(PROP_NAME, docgenInfo);\n\n    expect(type?.summary).toBe('\"minimum\" | \"maximum\" | UserSize');\n  });\n\n  it('should support intersection', () => {\n    const docgenInfo = createDocgenInfo({\n      flowType: {\n        name: 'intersection',\n        raw: 'number & string',\n        elements: [\n          {\n            name: 'number',\n          },\n          {\n            name: 'string',\n          },\n        ],\n      },\n    });\n\n    const { type } = createFlowPropDef(PROP_NAME, docgenInfo);\n\n    expect(type?.summary).toBe('number & string');\n  });\n});\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/docgen/flow/createPropDef.ts",
    "content": "import type { PropDefFactory } from '../createPropDef.ts';\nimport { createDefaultValue } from './createDefaultValue.ts';\nimport { createType } from './createType.ts';\n\nexport const createFlowPropDef: PropDefFactory = (propName, docgenInfo) => {\n  const { flowType, description, required, defaultValue } = docgenInfo;\n\n  return {\n    name: propName,\n    type: createType(flowType),\n    required,\n    description,\n    defaultValue: createDefaultValue(defaultValue ?? null, flowType ?? null),\n  };\n};\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/docgen/flow/createType.ts",
    "content": "import { createSummaryValue, isTooLongForTypeSummary } from '../../utils.ts';\nimport type { PropType } from '../PropDef.ts';\nimport type { DocgenFlowType } from '../types.ts';\n\nenum FlowTypesType {\n  UNION = 'union',\n  SIGNATURE = 'signature',\n}\n\ninterface DocgenFlowUnionElement {\n  name: string;\n  value?: string;\n  elements?: DocgenFlowUnionElement[];\n  raw?: string;\n}\n\ninterface DocgenFlowUnionType extends DocgenFlowType {\n  elements: DocgenFlowUnionElement[];\n}\n\nfunction generateUnionElement({ name, value, elements, raw }: DocgenFlowUnionElement): string {\n  if (value != null) {\n    return value;\n  }\n\n  if (elements != null) {\n    return elements.map(generateUnionElement).join(' | ');\n  }\n\n  if (raw != null) {\n    return raw;\n  }\n\n  return name;\n}\n\nfunction generateUnion({ name, raw, elements }: DocgenFlowUnionType): PropType {\n  if (elements != null) {\n    return createSummaryValue(elements.map(generateUnionElement).join(' | '));\n  }\n\n  if (raw != null) {\n    // Flow Unions can be defined with or without a leading `|` character, so try to remove it.\n    return createSummaryValue(raw.replace(/^\\|\\s*/, ''));\n  }\n\n  return createSummaryValue(name);\n}\n\nfunction generateFuncSignature({ type, raw }: DocgenFlowType): PropType {\n  if (raw != null) {\n    return createSummaryValue(raw);\n  }\n\n  return createSummaryValue(type);\n}\n\nfunction generateObjectSignature({ type, raw }: DocgenFlowType): PropType {\n  if (raw != null) {\n    return !isTooLongForTypeSummary(raw) ? createSummaryValue(raw) : createSummaryValue(type, raw);\n  }\n\n  return createSummaryValue(type);\n}\n\nfunction generateSignature(flowType: DocgenFlowType): PropType {\n  const { type } = flowType;\n\n  return type === 'object' ? generateObjectSignature(flowType) : generateFuncSignature(flowType);\n}\n\nfunction generateDefault({ name, raw }: DocgenFlowType): PropType {\n  if (raw != null) {\n    return !isTooLongForTypeSummary(raw) ? createSummaryValue(raw) : createSummaryValue(name, raw);\n  }\n\n  return createSummaryValue(name);\n}\n\nexport function createType(type?: DocgenFlowType): PropType | null {\n  // A type could be null if a defaultProp has been provided without a type definition.\n  if (type == null) {\n    return null;\n  }\n\n  switch (type.name) {\n    case FlowTypesType.UNION:\n      return generateUnion(type as DocgenFlowUnionType);\n    case FlowTypesType.SIGNATURE:\n      return generateSignature(type);\n    default:\n      return generateDefault(type);\n  }\n}\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/docgen/index.ts",
    "content": "export * from './types.ts';\nexport * from './utils/index.ts';\n\nexport * from './extractDocgenProps.ts';\n\nexport * from './PropDef.ts';\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/docgen/typeScript/createDefaultValue.ts",
    "content": "import { createSummaryValue } from '../../utils.ts';\nimport type { PropDefaultValue } from '../PropDef.ts';\nimport type { DocgenInfo } from '../types.ts';\nimport { isDefaultValueBlacklisted } from '../utils/defaultValue.ts';\n\nexport function createDefaultValue({ defaultValue }: DocgenInfo): PropDefaultValue | null {\n  if (defaultValue != null) {\n    const { value } = defaultValue;\n\n    if (!isDefaultValueBlacklisted(value)) {\n      return createSummaryValue(value);\n    }\n  }\n\n  return null;\n}\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/docgen/typeScript/createPropDef.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport type { DocgenInfo } from '../types.ts';\nimport { createTsPropDef } from './createPropDef.ts';\n\nconst PROP_NAME = 'propName';\n\nfunction createDocgenInfo({ tsType, ...others }: Partial<DocgenInfo>): DocgenInfo {\n  return {\n    tsType,\n    required: true,\n    ...others,\n  } as DocgenInfo;\n}\n\ndescribe('type', () => {\n  it(\"should remove ' | undefined' from optional props type\", () => {\n    const docgenInfo = createDocgenInfo({\n      tsType: { name: 'string | undefined' },\n      required: false,\n    });\n\n    const { type } = createTsPropDef(PROP_NAME, docgenInfo);\n\n    expect(type?.summary).toBe('string');\n    expect(type?.detail).toBeUndefined();\n  });\n});\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/docgen/typeScript/createPropDef.ts",
    "content": "import type { PropDefFactory } from '../createPropDef.ts';\nimport { createDefaultValue } from './createDefaultValue.ts';\nimport { createType } from './createType.ts';\n\nexport const createTsPropDef: PropDefFactory = (propName, docgenInfo) => {\n  const { description, required } = docgenInfo;\n\n  return {\n    name: propName,\n    type: createType(docgenInfo),\n    required,\n    description,\n    defaultValue: createDefaultValue(docgenInfo),\n  };\n};\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/docgen/typeScript/createType.ts",
    "content": "import { createSummaryValue } from '../../utils.ts';\nimport type { PropType } from '../PropDef.ts';\nimport type { DocgenInfo } from '../types.ts';\n\nexport function createType({ tsType, required }: DocgenInfo): PropType | null {\n  // A type could be null if a defaultProp has been provided without a type definition.\n  if (tsType == null) {\n    return null;\n  }\n\n  let typeName = tsType.name;\n  if (!required) {\n    typeName = typeName.replace(' | undefined', '');\n  }\n\n  return createSummaryValue(\n    ['Array', 'Record', 'signature'].includes(tsType.name) ? tsType.raw : typeName\n  );\n}\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/docgen/types.ts",
    "content": "import type { StrictArgTypes } from 'storybook/internal/types';\n\nimport type { Component } from '../types.ts';\nimport type { PropDef } from './PropDef.ts';\n\nexport type PropsExtractor = (component: Component) => { rows?: PropDef[] } | null;\n\nexport type ArgTypesExtractor = (component: Component) => StrictArgTypes | null;\n\nexport interface DocgenType {\n  name: string;\n  description?: string;\n  required?: boolean;\n  value?: any; // Seems like this can be many things\n}\n\nexport interface DocgenPropType extends DocgenType {\n  value?: any;\n  raw?: string;\n  computed?: boolean;\n}\n\nexport interface DocgenFlowType extends DocgenType {\n  type?: string;\n  raw?: string;\n  signature?: any;\n  elements?: any[];\n}\n\nexport interface DocgenTypeScriptType extends DocgenType {\n  raw?: string;\n}\n\n// export type DocgenType = DocgenPropType | DocgenFlowType | DocgenTypeScriptType;\n\nexport interface DocgenPropDefaultValue {\n  value: string;\n  computed?: boolean;\n  func?: boolean;\n}\n\nexport interface DocgenInfo {\n  type: DocgenPropType;\n  flowType?: DocgenFlowType;\n  tsType?: DocgenTypeScriptType;\n  required: boolean;\n  description: string;\n  defaultValue: DocgenPropDefaultValue;\n}\n\nexport enum TypeSystem {\n  JAVASCRIPT = 'JavaScript',\n  FLOW = 'Flow',\n  TYPESCRIPT = 'TypeScript',\n  UNKNOWN = 'Unknown',\n}\n\nexport type { PropDef };\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/docgen/utils/defaultValue.ts",
    "content": "const BLACKLIST = ['null', 'undefined'];\n\nexport function isDefaultValueBlacklisted(value: string): boolean {\n  return BLACKLIST.some((x) => x === value);\n}\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/docgen/utils/docgenInfo.ts",
    "content": "import type { Component } from '../../types.ts';\nimport { str } from './string.ts';\n\nexport function hasDocgen<T = any>(\n  component: Component\n): component is object & { __docgenInfo: T } {\n  return !!component.__docgenInfo;\n}\n\nexport function isValidDocgenSection(docgenSection: any) {\n  return docgenSection != null && Object.keys(docgenSection).length > 0;\n}\n\nexport function getDocgenSection(component: Component, section: string): any {\n  return hasDocgen(component) ? component.__docgenInfo[section] : null;\n}\n\nexport function getDocgenDescription(component: Component): string {\n  return hasDocgen(component) ? str(component.__docgenInfo.description) : '';\n}\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/docgen/utils/index.ts",
    "content": "export * from './defaultValue.ts';\nexport * from './string.ts';\nexport * from './docgenInfo.ts';\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/docgen/utils/string.ts",
    "content": "export const str = (obj: any) => {\n  if (!obj) {\n    return '';\n  }\n  if (typeof obj === 'string') {\n    return obj as string;\n  }\n  throw new Error(`Description: expected string, got: ${JSON.stringify(obj)}`);\n};\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/enhanceArgTypes.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport type { ArgTypes, StrictInputType } from 'storybook/internal/types';\n\nimport { enhanceArgTypes } from './enhanceArgTypes.ts';\n\nexpect.addSnapshotSerializer({\n  print: (val: any) => JSON.stringify(val, null, 2),\n  test: (val) => typeof val !== 'string',\n});\n\nconst enhance = ({\n  argType,\n  arg,\n  extractedArgTypes,\n  isArgsStory = true,\n}: {\n  argType?: StrictInputType;\n  arg?: any;\n  extractedArgTypes?: ArgTypes;\n  isArgsStory?: boolean;\n}) => {\n  const context = {\n    componentId: 'foo',\n    title: 'foo',\n    kind: 'foo',\n    id: 'foo--bar',\n    name: 'bar',\n    story: 'bar',\n    component: 'dummy',\n    parameters: {\n      __isArgsStory: isArgsStory,\n      docs: {\n        extractArgTypes: extractedArgTypes && (() => extractedArgTypes),\n      },\n    },\n    argTypes: argType && { input: argType },\n    initialArgs: { input: arg },\n    args: { input: arg },\n    globals: {},\n  };\n  // @ts-expect-error (not strict)\n  return enhanceArgTypes(context);\n};\n\ndescribe('enhanceArgTypes', () => {\n  describe('no-args story function', () => {\n    it('should no-op', () => {\n      expect(\n        enhance({\n          argType: { name: 'input', foo: 'unmodified', type: { name: 'number' } },\n          isArgsStory: false,\n        }).input\n      ).toMatchInlineSnapshot(`\n        {\n          \"name\": \"input\",\n          \"foo\": \"unmodified\",\n          \"type\": {\n            \"name\": \"number\"\n          }\n        }\n      `);\n    });\n  });\n  describe('args story function', () => {\n    describe('single-source input', () => {\n      describe('argTypes input', () => {\n        it('number', () => {\n          expect(\n            enhance({\n              argType: { name: 'input', type: { name: 'number' } },\n            }).input\n          ).toMatchInlineSnapshot(`\n            {\n              \"name\": \"input\",\n              \"type\": {\n                \"name\": \"number\"\n              }\n            }\n          `);\n        });\n      });\n\n      describe('extraction from component', () => {\n        it('number', () => {\n          expect(\n            enhance({ extractedArgTypes: { input: { name: 'input', type: { name: 'number' } } } })\n              .input\n          ).toMatchInlineSnapshot(`\n            {\n              \"name\": \"input\",\n              \"type\": {\n                \"name\": \"number\"\n              }\n            }\n          `);\n        });\n      });\n\n      describe('controls input', () => {\n        it('range', () => {\n          expect(\n            enhance({\n              argType: { name: 'input', control: { type: 'range', min: 0, max: 100 } },\n            }).input\n          ).toMatchInlineSnapshot(`\n            {\n              \"name\": \"input\",\n              \"control\": {\n                \"type\": \"range\",\n                \"min\": 0,\n                \"max\": 100\n              }\n            }\n          `);\n        });\n        it('options', () => {\n          expect(\n            enhance({\n              argType: { name: 'input', control: { type: 'radio', options: [1, 2] } },\n            }).input\n          ).toMatchInlineSnapshot(`\n            {\n              \"name\": \"input\",\n              \"control\": {\n                \"type\": \"radio\",\n                \"options\": [\n                  1,\n                  2\n                ]\n              }\n            }\n          `);\n        });\n      });\n    });\n\n    describe('mixed-source input', () => {\n      it('user-specified argTypes take precedence over extracted argTypes', () => {\n        expect(\n          enhance({\n            argType: { name: 'input', type: { name: 'number' } },\n            extractedArgTypes: { input: { type: { name: 'string' } } },\n          }).input\n        ).toMatchInlineSnapshot(`\n          {\n            \"type\": {\n              \"name\": \"number\"\n            },\n            \"name\": \"input\"\n          }\n        `);\n      });\n\n      it('user-specified argTypes take precedence over inferred argTypes', () => {\n        expect(\n          enhance({\n            argType: { name: 'input', type: { name: 'number' } },\n            arg: 'hello',\n          }).input\n        ).toMatchInlineSnapshot(`\n          {\n            \"name\": \"input\",\n            \"type\": {\n              \"name\": \"number\"\n            }\n          }\n        `);\n      });\n\n      it('extracted argTypes take precedence over inferred argTypes', () => {\n        expect(\n          enhance({\n            extractedArgTypes: { input: { type: { name: 'string' } } },\n            arg: 6,\n          }).input\n        ).toMatchInlineSnapshot(`\n          {\n            \"type\": {\n              \"name\": \"string\"\n            }\n          }\n        `);\n      });\n\n      it('user-specified controls take precedence over inferred controls', () => {\n        expect(\n          enhance({\n            argType: { name: 'input', defaultValue: 5, control: { type: 'range', step: 50 } },\n            arg: 3,\n            extractedArgTypes: { input: { name: 'input' } },\n          }).input\n        ).toMatchInlineSnapshot(`\n          {\n            \"name\": \"input\",\n            \"defaultValue\": 5,\n            \"control\": {\n              \"type\": \"range\",\n              \"step\": 50\n            }\n          }\n        `);\n      });\n\n      it('includes extracted argTypes when there are no user-specified argTypes', () => {\n        expect(\n          enhance({\n            arg: 3,\n            extractedArgTypes: { input: { name: 'input' }, foo: { type: { name: 'number' } } },\n          })\n        ).toMatchInlineSnapshot(`\n          {\n            \"input\": {\n              \"name\": \"input\"\n            },\n            \"foo\": {\n              \"type\": {\n                \"name\": \"number\"\n              }\n            }\n          }\n        `);\n      });\n\n      it('includes extracted argTypes when user-specified argTypes match', () => {\n        expect(\n          enhance({\n            argType: { name: 'input', type: { name: 'number' } },\n            extractedArgTypes: { input: { name: 'input' }, foo: { type: { name: 'number' } } },\n          })\n        ).toMatchInlineSnapshot(`\n          {\n            \"input\": {\n              \"name\": \"input\",\n              \"type\": {\n                \"name\": \"number\"\n              }\n            },\n            \"foo\": {\n              \"type\": {\n                \"name\": \"number\"\n              }\n            }\n          }\n        `);\n      });\n\n      it('excludes extracted argTypes when user-specified argTypes do not match', () => {\n        expect(\n          enhance({\n            argType: { name: 'input', type: { name: 'number' } },\n            extractedArgTypes: { foo: { type: { name: 'number' } } },\n          })\n        ).toMatchInlineSnapshot(`\n          {\n            \"foo\": {\n              \"type\": {\n                \"name\": \"number\"\n              }\n            },\n            \"input\": {\n              \"name\": \"input\",\n              \"type\": {\n                \"name\": \"number\"\n              }\n            }\n          }\n        `);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/enhanceArgTypes.ts",
    "content": "import type { Renderer, StoryContextForEnhancers } from 'storybook/internal/types';\n\nimport { combineParameters } from '../../preview-api/modules/store/parameters.ts';\n\nexport const enhanceArgTypes = <TRenderer extends Renderer>(\n  context: StoryContextForEnhancers<TRenderer>\n) => {\n  const {\n    component,\n    argTypes: userArgTypes,\n    parameters: { docs = {} },\n  } = context;\n  const { extractArgTypes } = docs;\n\n  if (!extractArgTypes || !component) {\n    return userArgTypes;\n  }\n\n  const extractedArgTypes = extractArgTypes(component);\n  return extractedArgTypes ? combineParameters(extractedArgTypes, userArgTypes) : userArgTypes;\n};\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/index.ts",
    "content": "export * from './convert/index.ts';\nexport * from './docgen/index.ts';\n\nexport * from './jsdocParser.ts';\nexport * from './types.ts';\nexport * from './utils.ts';\n\nexport * from './enhanceArgTypes.ts';\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/jsdocParser.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { parseJsDoc } from './jsdocParser.ts';\n\ndescribe('parseJsDoc', () => {\n  it('should set includesJsDoc to false when the value is null', () => {\n    const { includesJsDoc, description, extractedTags } = parseJsDoc(null, {});\n\n    expect(includesJsDoc).toBeFalsy();\n    expect(description).toBeUndefined();\n    expect(extractedTags).toBeUndefined();\n  });\n\n  it('should set includesJsDoc to false when the value dont contains JSDoc', () => {\n    const { includesJsDoc, description, extractedTags } = parseJsDoc('Hey!');\n\n    expect(includesJsDoc).toBeFalsy();\n    expect(description).toBeUndefined();\n    expect(extractedTags).toBeUndefined();\n  });\n\n  it('should set includesJsDoc to true when the value contains JSDoc', () => {\n    const { includesJsDoc } = parseJsDoc('Hey!\\n@version 1.2');\n\n    expect(includesJsDoc).toBeTruthy();\n  });\n\n  it('should remove all JSDoc tags from the description', () => {\n    const { description } = parseJsDoc('Hey!\\n@version 1.2\\n@deprecated');\n\n    expect(description).toBe('Hey!');\n  });\n\n  describe('@ignore', () => {\n    it('should set ignore to true when @ignore is present', () => {\n      const { ignore, description, extractedTags } = parseJsDoc('Hey!\\n@ignore');\n\n      expect(ignore).toBeTruthy();\n      expect(description).toBeUndefined();\n      expect(extractedTags).toBeUndefined();\n    });\n\n    it('should set ignore to false when @ignore is not present', () => {\n      const { ignore } = parseJsDoc('Hey!\\n@version 1.2');\n\n      expect(ignore).toBeFalsy();\n    });\n  });\n\n  describe('@param', () => {\n    it('should ignore invalid @param tags', () => {\n      const { extractedTags } = parseJsDoc('@param');\n\n      expect(extractedTags?.params).toBeNull();\n    });\n\n    it('should return a @param with a name', () => {\n      const { extractedTags } = parseJsDoc('@param event');\n\n      expect(extractedTags?.params).not.toBeNull();\n      expect(extractedTags?.params?.[0].name).toBe('event');\n      expect(extractedTags?.params?.[0].type).toBeNull();\n      expect(extractedTags?.params?.[0].description).toBeNull();\n    });\n\n    it('should return a @param with a name and a type', () => {\n      const { extractedTags } = parseJsDoc('@param {SyntheticEvent} event');\n\n      expect(extractedTags?.params).not.toBeNull();\n      expect(extractedTags?.params?.[0].name).toBe('event');\n      expect(extractedTags?.params?.[0].type).not.toBeNull();\n      expect(extractedTags?.params?.[0].type.value).toBe('SyntheticEvent');\n      expect(extractedTags?.params?.[0].description).toBeNull();\n    });\n\n    it('should return a @param with a name, a type and a description', () => {\n      const { extractedTags } = parseJsDoc('@param {SyntheticEvent} event - React event');\n\n      expect(extractedTags?.params).not.toBeNull();\n      expect(extractedTags?.params?.[0].name).toBe('event');\n      expect(extractedTags?.params?.[0].type).not.toBeNull();\n      expect(extractedTags?.params?.[0].type.value).toBe('SyntheticEvent');\n      expect(extractedTags?.params?.[0].description).toBe('React event');\n    });\n\n    it('should support multiple @param tags', () => {\n      const { extractedTags } = parseJsDoc(\n        '@param {SyntheticEvent} event1 - React event\\n@param {SyntheticEvent} event2 - React event\\n@param {SyntheticEvent} event3 - React event'\n      );\n\n      ['event1', 'event2', 'event3'].forEach((x, i) => {\n        expect(extractedTags?.params?.[i].name).toBe(x);\n        expect(extractedTags?.params?.[i].type).not.toBeNull();\n        expect(extractedTags?.params?.[i].type.value).toBe('SyntheticEvent');\n        expect(extractedTags?.params?.[i].description).toBe('React event');\n      });\n    });\n\n    it('should not return extra @param', () => {\n      const { extractedTags } = parseJsDoc('@param event');\n\n      expect(Object.keys(extractedTags?.params ?? []).length).toBe(1);\n    });\n\n    it('should support multiline description when there is a @param', () => {\n      const { description, extractedTags } = parseJsDoc(\n        'This is a\\nmultiline description\\n@param event'\n      );\n\n      expect(description).toBe('This is a\\nmultiline description');\n      expect(extractedTags?.params).not.toBeNull();\n      expect(extractedTags?.params?.[0].name).toBe('event');\n    });\n\n    it('should support multiline @param description', () => {\n      const { extractedTags } = parseJsDoc(\n        '@param event - This is a\\nmultiline description\\n@param anotherEvent'\n      );\n\n      expect(extractedTags?.params).not.toBeNull();\n      expect(extractedTags?.params?.[0].name).toBe('event');\n      expect(extractedTags?.params?.[0].description).toBe('This is a\\nmultiline description');\n      expect(extractedTags?.params?.[1].name).toBe('anotherEvent');\n    });\n\n    ['@arg', '@argument'].forEach((x) => {\n      it(`should support ${x} alias`, () => {\n        const { extractedTags } = parseJsDoc(`${x} {SyntheticEvent} event - React event`);\n\n        expect(extractedTags?.params).not.toBeNull();\n        expect(extractedTags?.params?.[0].name).toBe('event');\n        expect(extractedTags?.params?.[0].type).not.toBeNull();\n        expect(extractedTags?.params?.[0].type.value).toBe('SyntheticEvent');\n        expect(extractedTags?.params?.[0].description).toBe('React event');\n      });\n    });\n\n    describe('getTypeName', () => {\n      it('should support record type with a single field', () => {\n        const { extractedTags } = parseJsDoc('@param {{a: number}} event');\n\n        expect(extractedTags?.params?.[0].getTypeName()).toBe('({a: number})');\n      });\n\n      it('should support record type with multiple fields', () => {\n        const { extractedTags } = parseJsDoc('@param {{a: number, b: string}} event');\n\n        expect(extractedTags?.params?.[0].getTypeName()).toBe('({a: number, b: string})');\n      });\n\n      it('should support record type with a field having only a name', () => {\n        const { extractedTags } = parseJsDoc('@param {{a}} event');\n\n        expect(extractedTags?.params?.[0].getTypeName()).toBe('({a})');\n      });\n\n      it('should support union type', () => {\n        const { extractedTags } = parseJsDoc('@param {(number|boolean)} event');\n\n        expect(extractedTags?.params?.[0].getTypeName()).toBe('(number|boolean)');\n      });\n\n      it('should support array type', () => {\n        const { extractedTags } = parseJsDoc('@param {number[]} event');\n\n        expect(extractedTags?.params?.[0].getTypeName()).toBe('number[]');\n      });\n\n      it('should support untyped array type', () => {\n        const { extractedTags } = parseJsDoc('@param {[]} event');\n\n        expect(extractedTags?.params?.[0].getTypeName()).toBe('[]');\n      });\n\n      it('should support nullable type', () => {\n        const { extractedTags } = parseJsDoc('@param {?number} event');\n\n        expect(extractedTags?.params?.[0].getTypeName()).toBe('number');\n      });\n\n      it('should support non nullable type', () => {\n        const { extractedTags } = parseJsDoc('@param {!number} event');\n\n        expect(extractedTags?.params?.[0].getTypeName()).toBe('number');\n      });\n\n      it('should support optional param with []', () => {\n        const { extractedTags } = parseJsDoc('@param {number} [event]');\n\n        expect(extractedTags?.params?.[0].getTypeName()).toBe('number');\n      });\n\n      it('should support optional param with =', () => {\n        const { extractedTags } = parseJsDoc('@param {number=} event');\n\n        expect(extractedTags?.params?.[0].getTypeName()).toBe('number');\n      });\n\n      it('should support any type', () => {\n        const { extractedTags } = parseJsDoc('@param {*} event');\n\n        expect(extractedTags?.params?.[0].getTypeName()).toBe('any');\n      });\n    });\n\n    describe('getPrettyName', () => {\n      it('should return @param name', () => {\n        const { extractedTags } = parseJsDoc('@param {SyntheticEvent} event - React event');\n\n        expect(extractedTags?.params?.[0].getPrettyName()).toBe('event');\n      });\n\n      it('should fix missing space between the @param name and the description separator', () => {\n        const { extractedTags } = parseJsDoc('@param {SyntheticEvent} event- React event');\n\n        expect(extractedTags?.params?.[0].getPrettyName()).toBe('event');\n      });\n\n      it('should fix @param name ending with . followed by a @returns tag', () => {\n        const { extractedTags } = parseJsDoc('@param {SyntheticEvent} event.\\n');\n\n        expect(extractedTags?.params?.[0].getPrettyName()).toBe('event');\n      });\n    });\n  });\n\n  describe('@deprecated', () => {\n    it('should ignore invalid @deprecated', () => {\n      const { extractedTags } = parseJsDoc('@deprecated');\n\n      expect(extractedTags?.returns).toBeNull();\n    });\n\n    it('should return a @deprecated with a name', () => {\n      const { extractedTags } = parseJsDoc('@deprecated string');\n\n      expect(extractedTags?.deprecated).not.toBeNull();\n      expect(extractedTags?.deprecated).not.toBeNull();\n      expect(extractedTags?.deprecated).toBe('string');\n    });\n  });\n\n  describe('@returns', () => {\n    it('should ignore invalid @returns', () => {\n      const { extractedTags } = parseJsDoc('@returns');\n\n      expect(extractedTags?.returns).toBeNull();\n    });\n\n    it('should return a @returns with a type', () => {\n      const { extractedTags } = parseJsDoc('@returns {string}');\n\n      expect(extractedTags?.returns).not.toBeNull();\n      expect(extractedTags?.returns?.type).not.toBeNull();\n      expect(extractedTags?.returns?.type.value).toBe('string');\n    });\n\n    it('should return a @returns with a type and a description', () => {\n      const { extractedTags } = parseJsDoc('@returns {string} - A bar description');\n\n      expect(extractedTags?.returns).not.toBeNull();\n      expect(extractedTags?.returns?.type).not.toBeNull();\n      expect(extractedTags?.returns?.type.value).toBe('string');\n      expect(extractedTags?.returns?.description).toBe('A bar description');\n    });\n\n    it('should support multiline @returns description', () => {\n      const { extractedTags } = parseJsDoc(\n        '@returns {string} - This is\\na multiline\\ndescription\\n'\n      );\n\n      expect(extractedTags?.returns).not.toBeNull();\n      expect(extractedTags?.returns?.type).not.toBeNull();\n      expect(extractedTags?.returns?.type.value).toBe('string');\n      expect(extractedTags?.returns?.description).toBe('This is\\na multiline\\ndescription');\n    });\n\n    it('should only consider the last @returns tag when there is multiple', () => {\n      const { extractedTags } = parseJsDoc('@returns {string}\\n@returns {number}');\n\n      expect(extractedTags?.returns).not.toBeNull();\n      expect(extractedTags?.returns?.type).not.toBeNull();\n      expect(extractedTags?.returns?.type.value).toBe('number');\n    });\n\n    describe('getTypeName', () => {\n      it('should support named type', () => {\n        const { extractedTags } = parseJsDoc('@returns {string}');\n\n        expect(extractedTags?.returns?.getTypeName()).toBe('string');\n      });\n\n      it('should support record type with a single field', () => {\n        const { extractedTags } = parseJsDoc('@returns {{a: number}}');\n\n        expect(extractedTags?.returns?.getTypeName()).toBe('({a: number})');\n      });\n\n      it('should support record type with multiple fields', () => {\n        const { extractedTags } = parseJsDoc('@returns {{a: number, b: string}}');\n\n        expect(extractedTags?.returns?.getTypeName()).toBe('({a: number, b: string})');\n      });\n\n      it('should support record type with a field having only a name', () => {\n        const { extractedTags } = parseJsDoc('@returns {{a}}');\n\n        expect(extractedTags?.returns?.getTypeName()).toBe('({a})');\n      });\n\n      it('should support array type', () => {\n        const { extractedTags } = parseJsDoc('@returns {integer[]}');\n\n        expect(extractedTags?.returns?.getTypeName()).toBe('integer[]');\n      });\n\n      it('should support untyped array type', () => {\n        const { extractedTags } = parseJsDoc('@returns {[]}');\n\n        expect(extractedTags?.returns?.getTypeName()).toBe('[]');\n      });\n\n      it('should support union type', () => {\n        const { extractedTags } = parseJsDoc('@returns {(number|boolean)}');\n\n        expect(extractedTags?.returns?.getTypeName()).toBe('(number|boolean)');\n      });\n\n      it('should support any type', () => {\n        const { extractedTags } = parseJsDoc('@returns {*}');\n\n        expect(extractedTags?.returns?.getTypeName()).toBe('any');\n      });\n\n      it('should support void', () => {\n        const { extractedTags } = parseJsDoc('@returns {void}');\n\n        expect(extractedTags?.returns?.getTypeName()).toBe('void');\n      });\n    });\n  });\n\n  it('should ignore unsupported JSDoc tags', () => {\n    const { extractedTags } = parseJsDoc('Hey!\\n@param event', { tags: [] });\n\n    expect(extractedTags?.params).toBeNull();\n  });\n\n  it('should remove extra newline characters between tags', () => {\n    const { extractedTags } = parseJsDoc(\n      'Hey!\\n@param {SyntheticEvent} event - Original event.\\n     \\n     \\n     \\n@returns {string}'\n    );\n\n    expect(extractedTags?.params).not.toBeNull();\n    expect(Object.keys(extractedTags?.params ?? []).length).toBe(1);\n    expect(extractedTags?.params?.[0].name).toBe('event');\n    expect(extractedTags?.params?.[0].type.value).toBe('SyntheticEvent');\n    expect(extractedTags?.params?.[0].description).toBe('Original event.');\n    expect(extractedTags?.returns).not.toBeNull();\n    expect(extractedTags?.returns?.type.value).toBe('string');\n  });\n});\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/jsdocParser.ts",
    "content": "import type { Block, Spec } from 'comment-parser';\nimport { parse as parseJSDoc } from 'comment-parser';\nimport type { RootResult as JSDocType } from 'jsdoc-type-pratt-parser';\nimport {\n  parse as parseJSDocType,\n  stringifyRules,\n  transform as transformJSDocType,\n} from 'jsdoc-type-pratt-parser';\n\nimport type { JsDocParam, JsDocReturns } from './docgen/index.ts';\n\nexport interface ExtractedJsDocParam extends JsDocParam {\n  type?: any;\n  getPrettyName: () => string | undefined;\n  getTypeName: () => string | null;\n}\n\nexport interface ExtractedJsDocReturns extends JsDocReturns {\n  type?: any;\n  getTypeName: () => string | null;\n}\n\nexport interface ExtractedJsDoc {\n  params?: ExtractedJsDocParam[] | null;\n  deprecated?: string | null;\n  returns?: ExtractedJsDocReturns | null;\n  ignore: boolean;\n}\n\nexport interface JsDocParsingOptions {\n  tags?: string[];\n}\n\nexport interface JsDocParsingResult {\n  includesJsDoc: boolean;\n  ignore: boolean;\n  description?: string;\n  extractedTags?: ExtractedJsDoc;\n}\n\nexport type ParseJsDoc = (\n  value: string | null,\n  options?: JsDocParsingOptions\n) => JsDocParsingResult;\n\nfunction containsJsDoc(value?: string | null): boolean {\n  return value != null && value.includes('@');\n}\n\nfunction parse(content: string | null): Block {\n  const contentString = content ?? '';\n  const mappedLines = contentString\n    .split('\\n')\n    .map((line) => ` * ${line}`)\n    .join('\\n');\n  const normalisedContent = '/**\\n' + mappedLines + '\\n*/';\n\n  const ast = parseJSDoc(normalisedContent, {\n    spacing: 'preserve',\n  });\n\n  if (!ast || ast.length === 0) {\n    throw new Error('Cannot parse JSDoc tags.');\n  }\n\n  // Return the first block, since we shouldn't ever really encounter\n  // multiple blocks of JSDoc\n  return ast[0];\n}\n\nconst DEFAULT_OPTIONS = {\n  tags: ['param', 'arg', 'argument', 'returns', 'ignore', 'deprecated'],\n};\n\nexport const parseJsDoc: ParseJsDoc = (value, options = DEFAULT_OPTIONS) => {\n  if (!containsJsDoc(value)) {\n    return {\n      includesJsDoc: false,\n      ignore: false,\n    };\n  }\n\n  const jsDocAst = parse(value);\n\n  const extractedTags = extractJsDocTags(jsDocAst, options.tags);\n\n  if (extractedTags.ignore) {\n    // There is no point in doing other stuff since this prop will not be rendered.\n    return {\n      includesJsDoc: true,\n      ignore: true,\n    };\n  }\n\n  return {\n    includesJsDoc: true,\n    ignore: false,\n    // Always use the parsed description to ensure JSDoc is removed from the description.\n    description: jsDocAst.description.trim(),\n    extractedTags,\n  };\n};\n\nfunction extractJsDocTags(ast: Block, tags?: string[]): ExtractedJsDoc {\n  const extractedTags: ExtractedJsDoc = {\n    params: null,\n    deprecated: null,\n    returns: null,\n    ignore: false,\n  };\n\n  for (const tagSpec of ast.tags) {\n    // Skip any tags we don't care about\n    if (tags !== undefined && !tags.includes(tagSpec.tag)) {\n      continue;\n    }\n\n    if (tagSpec.tag === 'ignore') {\n      extractedTags.ignore = true;\n      // Once we reach an @ignore tag, there is no point in parsing the other tags since we will not render the prop.\n      break;\n    } else {\n      switch (tagSpec.tag) {\n        // arg & argument are aliases for param.\n        case 'param':\n        case 'arg':\n        case 'argument': {\n          const paramTag = extractParam(tagSpec);\n          if (paramTag != null) {\n            if (extractedTags.params == null) {\n              extractedTags.params = [];\n            }\n            extractedTags.params.push(paramTag);\n          }\n          break;\n        }\n        case 'deprecated': {\n          const deprecatedTag = extractDeprecated(tagSpec);\n          if (deprecatedTag != null) {\n            extractedTags.deprecated = deprecatedTag;\n          }\n          break;\n        }\n        case 'returns': {\n          const returnsTag = extractReturns(tagSpec);\n          if (returnsTag != null) {\n            extractedTags.returns = returnsTag;\n          }\n          break;\n        }\n        default:\n          break;\n      }\n    }\n  }\n\n  return extractedTags;\n}\n\nfunction normaliseParamName(name: string): string {\n  return name.replace(/[\\.-]$/, '');\n}\n\nfunction extractParam(tag: Spec): ExtractedJsDocParam | null {\n  // Ignore tags with empty names or `-`.\n  // We ignore `-` since it means a comment was likely missing a name but\n  // using separators. For example: `@param {foo} - description`\n  if (!tag.name || tag.name === '-') {\n    return null;\n  }\n\n  const type = extractType(tag.type);\n\n  return {\n    name: tag.name,\n    type: type,\n    description: normaliseDescription(tag.description),\n    getPrettyName: () => {\n      return normaliseParamName(tag.name);\n    },\n    getTypeName: () => {\n      return type ? extractTypeName(type) : null;\n    },\n  };\n}\n\nfunction extractDeprecated(tag: Spec): string | null {\n  if (tag.name) {\n    return joinNameAndDescription(tag.name, tag.description);\n  }\n\n  return null;\n}\n\nfunction joinNameAndDescription(name: string, desc: string): string | null {\n  const joined = name === '' ? desc : `${name} ${desc}`;\n  return normaliseDescription(joined);\n}\n\nfunction normaliseDescription(text: string): string | null {\n  const normalised = text.replace(/^- /g, '').trim();\n\n  return normalised === '' ? null : normalised;\n}\n\nfunction extractReturns(tag: Spec): ExtractedJsDocReturns | null {\n  const type = extractType(tag.type);\n\n  if (type) {\n    return {\n      type: type,\n      description: joinNameAndDescription(tag.name, tag.description),\n      getTypeName: () => {\n        return extractTypeName(type);\n      },\n    };\n  }\n\n  return null;\n}\n\nconst jsdocStringifyRules = stringifyRules();\nconst originalJsdocStringifyObject = jsdocStringifyRules.JsdocTypeObject;\njsdocStringifyRules.JsdocTypeAny = () => 'any';\njsdocStringifyRules.JsdocTypeObject = (result, transform) =>\n  `(${originalJsdocStringifyObject(result, transform)})`;\njsdocStringifyRules.JsdocTypeOptional = (result, transform) => transform(result.element);\njsdocStringifyRules.JsdocTypeNullable = (result, transform) => transform(result.element);\njsdocStringifyRules.JsdocTypeNotNullable = (result, transform) => transform(result.element);\njsdocStringifyRules.JsdocTypeUnion = (result, transform) =>\n  result.elements.map(transform).join('|');\n\nfunction extractType(typeString: string): JSDocType | null {\n  try {\n    return parseJSDocType(typeString, 'typescript');\n  } catch (_err) {\n    return null;\n  }\n}\n\nfunction extractTypeName(type: JSDocType): string {\n  return transformJSDocType(jsdocStringifyRules, type);\n}\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/types.ts",
    "content": "export type Component = any;\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/typings.d.ts",
    "content": "declare module 'require-from-string';\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/utils.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { createSummaryValue } from './utils.ts';\n\ndescribe('createSummaryValue', () => {\n  it('creates an object with just summary if detail is not passed', () => {\n    const summary = 'boolean';\n    expect(createSummaryValue(summary)).toEqual({ summary });\n  });\n\n  it('creates an object with summary & detail if passed', () => {\n    const summary = 'MyType';\n    const detail = 'boolean | string';\n    expect(createSummaryValue(summary, detail)).toEqual({ summary, detail });\n  });\n\n  it('creates an object with just summary if details are equal', () => {\n    const summary = 'boolean';\n    const detail = 'boolean';\n    expect(createSummaryValue(summary, detail)).toEqual({ summary });\n  });\n});\n"
  },
  {
    "path": "code/core/src/docs-tools/argTypes/utils.ts",
    "content": "import type { PropSummaryValue } from './docgen/index.ts';\n\nexport const MAX_TYPE_SUMMARY_LENGTH = 90;\nexport const MAX_DEFAULT_VALUE_SUMMARY_LENGTH = 50;\n\nexport function isTooLongForTypeSummary(value: string): boolean {\n  return value.length > MAX_TYPE_SUMMARY_LENGTH;\n}\n\nexport function isTooLongForDefaultValueSummary(value: string): boolean {\n  return value.length > MAX_DEFAULT_VALUE_SUMMARY_LENGTH;\n}\n\nexport function createSummaryValue(summary?: string, detail?: string): PropSummaryValue {\n  if (summary === detail) {\n    return { summary };\n  }\n  return { summary, detail };\n}\n\nexport const normalizeNewlines = (string: string) => string.replace(/\\\\r\\\\n/g, '\\\\n');\n"
  },
  {
    "path": "code/core/src/docs-tools/index.ts",
    "content": "export * from './argTypes/index.ts';\nexport * from './shared.ts';\n"
  },
  {
    "path": "code/core/src/docs-tools/shared.ts",
    "content": "export const ADDON_ID = 'storybook/docs';\nexport const PANEL_ID = `${ADDON_ID}/panel`;\nexport const PARAM_KEY = `docs`;\n\nexport const SNIPPET_RENDERED = `${ADDON_ID}/snippet-rendered`;\n\nexport enum SourceType {\n  /**\n   * AUTO is the default\n   *\n   * Use the CODE logic if:\n   *\n   * - The user has set a custom source snippet in `docs.source.code` story parameter\n   * - The story is not an args-based story\n   *\n   * Use the DYNAMIC rendered snippet if the story is an args story\n   */\n  AUTO = 'auto',\n\n  /** Render the code extracted by csf-plugin */\n  CODE = 'code',\n\n  /** Render dynamically-rendered source snippet from the story's virtual DOM (currently React only) */\n  DYNAMIC = 'dynamic',\n}\n"
  },
  {
    "path": "code/core/src/highlight/StoryContent.tsx",
    "content": "import React from 'react';\n\nexport const StoryContent = ({\n  dynamic,\n  withPopover,\n}: {\n  dynamic: boolean;\n  withPopover: boolean;\n}) => {\n  const [extra, setExtra] = React.useState(false);\n  React.useEffect(() => {\n    if (!dynamic) {\n      return;\n    }\n    const interval = setInterval(() => setExtra((v) => !v), 1200);\n    return () => clearInterval(interval);\n  }, [dynamic]);\n\n  return (\n    <main style={{ minHeight: 1200, minWidth: 1200 }}>\n      {withPopover && (\n        <>\n          {/* @ts-expect-error popover is not yet supported by React */}\n          <button popovertarget=\"my-popover\">Open Popover 1</button>\n          {/* @ts-expect-error popover is not yet supported by React */}\n          <div popover=\"manual\" id=\"my-popover\" style={{ padding: 20 }}>\n            Greetings, one and all!\n          </div>\n        </>\n      )}\n      <input\n        aria-label=\"Sample input\"\n        id=\"input\"\n        type=\"text\"\n        style={{ margin: 20 }}\n        defaultValue=\"input\"\n      />\n      <div id=\"zeroheight\" />\n      <div id=\"zerowidth\" style={{ width: 0, margin: 20 }} />\n      <div\n        id=\"sticky\"\n        style={{\n          position: 'sticky',\n          marginTop: 150,\n          top: 0,\n          left: 0,\n          width: '100%',\n          height: 50,\n          border: '1px solid black',\n          borderRadius: 10,\n        }}\n      />\n      <div\n        id=\"fixed\"\n        style={{\n          position: 'fixed',\n          top: 300,\n          left: 50,\n          right: 50,\n          height: 150,\n          border: '1px solid black',\n          borderRadius: 10,\n        }}\n      />\n      <div\n        id=\"moving\"\n        style={{\n          position: 'absolute',\n          top: 100,\n          left: 150,\n          width: 150,\n          height: 150,\n          border: '1px solid black',\n          borderRadius: 10,\n        }}\n      />\n      <div\n        id=\"scaling\"\n        style={{\n          position: 'absolute',\n          top: 50,\n          left: '50%',\n          width: 200,\n          height: 150,\n          border: '1px solid black',\n          borderRadius: 10,\n        }}\n      >\n        <div\n          id=\"inner\"\n          style={{\n            position: 'absolute',\n            top: '25%',\n            left: '-1px',\n            width: 120,\n            height: '50%',\n            border: '1px solid black',\n            borderRadius: 10,\n          }}\n        />\n      </div>\n      <div\n        id=\"overflow\"\n        style={{\n          position: 'absolute',\n          top: 100,\n          left: 350,\n          width: 200,\n          height: 150,\n          border: '1px solid black',\n          overflow: 'auto',\n        }}\n      >\n        <div\n          id=\"child\"\n          style={{\n            margin: 30,\n            width: 120,\n            height: 200,\n            backgroundColor: 'yellow',\n          }}\n        />\n      </div>\n      {extra && (\n        <div\n          id=\"extra\"\n          style={{\n            position: 'absolute',\n            top: 325,\n            left: 75,\n            width: 300,\n            height: 100,\n            border: '1px solid black',\n            borderRadius: 10,\n          }}\n        />\n      )}\n      <div\n        id=\"footer\"\n        style={{\n          position: 'absolute',\n          top: 1000,\n          left: 10,\n          right: 10,\n          height: 190,\n          border: '1px solid black',\n          borderRadius: 10,\n        }}\n      />\n    </main>\n  );\n};\n"
  },
  {
    "path": "code/core/src/highlight/constants.ts",
    "content": "export const ADDON_ID = 'storybook/highlight';\n\nexport const HIGHLIGHT = `${ADDON_ID}/add`;\nexport const REMOVE_HIGHLIGHT = `${ADDON_ID}/remove`;\nexport const RESET_HIGHLIGHT = `${ADDON_ID}/reset`;\nexport const SCROLL_INTO_VIEW = `${ADDON_ID}/scroll-into-view`;\n\nexport const MAX_Z_INDEX = 2147483647;\nexport const MIN_TOUCH_AREA_SIZE = 28;\n"
  },
  {
    "path": "code/core/src/highlight/icons.ts",
    "content": "export const iconPaths = {\n  chevronLeft: [\n    'M9.10355 10.1464C9.29882 10.3417 9.29882 10.6583 9.10355 10.8536C8.90829 11.0488 8.59171 11.0488 8.39645 10.8536L4.89645 7.35355C4.70118 7.15829 4.70118 6.84171 4.89645 6.64645L8.39645 3.14645C8.59171 2.95118 8.90829 2.95118 9.10355 3.14645C9.29882 3.34171 9.29882 3.65829 9.10355 3.85355L5.95711 7L9.10355 10.1464Z',\n  ],\n  chevronRight: [\n    'M4.89645 10.1464C4.70118 10.3417 4.70118 10.6583 4.89645 10.8536C5.09171 11.0488 5.40829 11.0488 5.60355 10.8536L9.10355 7.35355C9.29882 7.15829 9.29882 6.84171 9.10355 6.64645L5.60355 3.14645C5.40829 2.95118 5.09171 2.95118 4.89645 3.14645C4.70118 3.34171 4.70118 3.65829 4.89645 3.85355L8.04289 7L4.89645 10.1464Z',\n  ],\n  info: [\n    'M7 5.5a.5.5 0 01.5.5v4a.5.5 0 01-1 0V6a.5.5 0 01.5-.5zM7 4.5A.75.75 0 107 3a.75.75 0 000 1.5z',\n    'M7 14A7 7 0 107 0a7 7 0 000 14zm0-1A6 6 0 107 1a6 6 0 000 12z',\n  ],\n  shareAlt: [\n    'M2 1.004a1 1 0 00-1 1v10a1 1 0 001 1h10a1 1 0 001-1v-4.5a.5.5 0 00-1 0v4.5H2v-10h4.5a.5.5 0 000-1H2z',\n    'M7.354 7.357L12 2.711v1.793a.5.5 0 001 0v-3a.5.5 0 00-.5-.5h-3a.5.5 0 100 1h1.793L6.646 6.65a.5.5 0 10.708.707z',\n  ],\n};\n\nexport type IconName = keyof typeof iconPaths;\n"
  },
  {
    "path": "code/core/src/highlight/index.ts",
    "content": "export { HIGHLIGHT, REMOVE_HIGHLIGHT, RESET_HIGHLIGHT, SCROLL_INTO_VIEW } from './constants.ts';\nexport type { ClickEventDetails, HighlightMenuItem, HighlightOptions } from './types.ts';\n"
  },
  {
    "path": "code/core/src/highlight/preview.ts",
    "content": "/* eslint-env browser */\nimport { definePreviewAddon } from 'storybook/internal/csf';\n\nimport { addons } from 'storybook/preview-api';\n\nimport type { HighlightTypes } from './types.ts';\nimport { useHighlights } from './useHighlights.ts';\n\nif (globalThis?.FEATURES?.highlight && addons?.ready) {\n  addons.ready().then(useHighlights);\n}\n\nexport type { HighlightTypes };\n\nexport default () => definePreviewAddon<HighlightTypes>({});\n"
  },
  {
    "path": "code/core/src/highlight/types.ts",
    "content": "import type { IconName } from './icons.ts';\n\nexport interface HighlightTypes {\n  parameters: HighlightParameters;\n}\n\nexport interface HighlightParameters {\n  /**\n   * Highlight configuration\n   *\n   * @see https://storybook.js.org/docs/essentials/highlight#parameters\n   */\n  highlight?: {\n    /**\n     * Removes the tool and disables the feature's behavior. If you wish to turn off this feature\n     * for the entire Storybook, you can set the option in your `main.js|ts` configuration file.\n     *\n     * @see https://storybook.js.org/docs/essentials/highlight#disable\n     */\n    disable?: boolean;\n  };\n}\n\nexport interface HighlightMenuItem {\n  /** Unique identifier for the menu item */\n  id: string;\n  /** Title of the menu item */\n  title: string;\n  /** Description of the menu item */\n  description?: string;\n  /** Icon for the menu item, left side */\n  iconLeft?: IconName;\n  /** Icon for the menu item, right side */\n  iconRight?: IconName;\n  /** Name for a channel event to trigger when the menu item is clicked */\n  clickEvent?: string;\n  /** HTML selectors for which this menu item should show (subset of `selectors`) */\n  selectors?: HighlightOptions['selectors'];\n}\n\nexport interface HighlightOptions {\n  /** Unique identifier for the highlight, required if you want to remove the highlight later */\n  id?: string;\n  /** HTML selectors of the elements */\n  selectors: string[];\n  /** Priority of the highlight, higher takes precedence, defaults to 0 */\n  priority?: number;\n  /** CSS styles to apply to the highlight */\n  styles?: Record<string, string>;\n  /** CSS styles to apply to the highlight when it is hovered */\n  hoverStyles?: Record<string, string>;\n  /** CSS styles to apply to the highlight when it is focused or selected */\n  focusStyles?: Record<string, string>;\n  /** Keyframes required for animations */\n  keyframes?: string;\n  /** Groups of menu items to show when the highlight is selected */\n  menu?: HighlightMenuItem[][];\n}\n\nexport interface ClickEventDetails {\n  top: number;\n  left: number;\n  width: number;\n  height: number;\n  selectors: string[];\n  element: {\n    attributes: Record<string, string>;\n    localName: string;\n    tagName: string;\n    outerHTML: string;\n  };\n}\n\n// Legacy format\nexport interface LegacyHighlightOptions {\n  /** @deprecated Use selectors instead */\n  elements: string[];\n  /** @deprecated Use styles instead */\n  color: string;\n  /** @deprecated Use styles instead */\n  style: 'dotted' | 'dashed' | 'solid' | 'double';\n}\n\nexport type RawHighlightOptions = HighlightOptions | LegacyHighlightOptions;\n\nexport type Highlight = {\n  id?: string;\n  priority: number;\n  selectors: string[];\n  styles: Record<string, string>;\n  hoverStyles?: Record<string, string>;\n  focusStyles?: Record<string, string>;\n  menu?: HighlightMenuItem[][];\n};\n\nexport type Box = {\n  element: HTMLElement;\n  selectors: Highlight['selectors'];\n  styles: Highlight['styles'];\n  hoverStyles?: Highlight['hoverStyles'];\n  focusStyles?: Highlight['focusStyles'];\n  menu?: Highlight['menu'];\n  top: number;\n  left: number;\n  width: number;\n  height: number;\n};\n"
  },
  {
    "path": "code/core/src/highlight/typings.d.ts",
    "content": "declare var __STORYBOOK_HIGHLIGHT_INITIALIZED: boolean;\n"
  },
  {
    "path": "code/core/src/highlight/useHighlights.stories.tsx",
    "content": "import React from 'react';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { fn, userEvent, within } from 'storybook/test';\n\nimport preview from '../../../.storybook/preview.tsx';\nimport { StoryContent } from './StoryContent.tsx';\nimport { HIGHLIGHT, REMOVE_HIGHLIGHT, SCROLL_INTO_VIEW } from './constants.ts';\n\nconst highlight = (\n  selectors: string[],\n  options?: {\n    styles?: Record<string, string>;\n    hoverStyles?: Record<string, string>;\n    focusStyles?: Record<string, string>;\n    keyframes?: string;\n    menu?: {\n      id: string;\n      title: string;\n      description?: string;\n      right?: string;\n      href?: string;\n      clickEvent?: string;\n    }[];\n  }\n) => {\n  const emit = useChannel({ 'my-click-event': fn().mockName('my-click-event') });\n  const id = Math.random().toString(36).substring(2, 15);\n  React.useEffect(() => {\n    emit(HIGHLIGHT, {\n      id,\n      selectors,\n      styles: {\n        backgroundColor: `color-mix(in srgb, teal, transparent 80%)`,\n        outline: `1px solid color-mix(in srgb, teal, transparent 30%)`,\n      },\n      hoverStyles: options?.menu ? { outlineWidth: '2px' } : {},\n      focusStyles: {\n        backgroundColor: 'transparent',\n      },\n      ...options,\n    });\n    return () => emit(REMOVE_HIGHLIGHT, id);\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [emit]);\n};\n\nconst meta = preview.meta({\n  title: 'Highlight',\n  decorators: [\n    (storyFn, { parameters }) => {\n      // @ts-expect-error Parameters are not inferred\n      parameters.highlights.forEach(({ selectors, options }) => highlight(selectors, options));\n      return storyFn();\n    },\n  ],\n  render: (args, { parameters }) => {\n    return <StoryContent dynamic={parameters.dynamic} withPopover={parameters.withPopover} />;\n  },\n  parameters: {\n    layout: 'fullscreen',\n    highlights: [],\n  },\n});\n\nexport const Default = meta.story({\n  parameters: {\n    highlights: [{ selectors: ['div', 'input'] }],\n  },\n});\n\nexport const Multiple = meta.story({\n  parameters: {\n    highlights: [\n      { selectors: ['main > div', 'input'] },\n      { selectors: ['div > div'], options: { styles: { border: '3px solid hotpink' } } },\n    ],\n  },\n});\n\nexport const Dynamic = meta.story({\n  parameters: {\n    dynamic: true,\n    highlights: [{ selectors: ['div', 'input'] }],\n  },\n  play: async ({ canvasElement }) => {\n    const scaling = canvasElement.querySelector('#scaling') as HTMLElement;\n    const moving = canvasElement.querySelector('#moving') as HTMLElement;\n\n    const interval = setInterval(() => {\n      scaling.style.height = `${parseInt(scaling.style.height) + 5}px`;\n      moving.style.left = `${parseInt(moving.style.left) + 5}px`;\n    }, 1000);\n    setTimeout(() => clearInterval(interval), 60000);\n  },\n});\n\nexport const Styles = meta.story({\n  parameters: {\n    highlights: [\n      {\n        selectors: ['div', 'input'],\n        options: {\n          styles: {\n            backgroundColor: `color-mix(in srgb, hotpink, transparent 90%)`,\n            outline: '3px solid hotpink',\n            animation: 'highlight-pulse 3s linear infinite',\n            transition: 'outline-offset 0.2s ease-in-out',\n          },\n          hoverStyles: {\n            outlineOffset: '3px',\n          },\n          focusStyles: {\n            backgroundColor: 'transparent',\n          },\n          keyframes: `@keyframes highlight-pulse {\n            0% { outline-color: rgba(255, 105, 180, 1); }\n            50% { outline-color: rgba(255, 105, 180, 0.2); }\n            100% { outline-color: rgba(255, 105, 180, 1); }\n          }`,\n        },\n      },\n    ],\n  },\n});\n\nexport const ScrollIntoView = meta.story({\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      React.useEffect(() => emit(SCROLL_INTO_VIEW, '#footer'), [emit]);\n      return storyFn();\n    },\n  ],\n});\n\nexport const Selectable = meta.story({\n  parameters: {\n    highlights: [{ selectors: ['div', 'input'], options: { menu: [] } }],\n  },\n  play: async () => {\n    await new Promise((resolve) => setTimeout(resolve, 200));\n    await userEvent.pointer({\n      coords: { pageX: 470, pageY: 240 },\n      keys: '[MouseLeft]',\n    });\n  },\n});\n\nexport const Menu = meta.story({\n  parameters: {\n    highlights: [\n      {\n        selectors: ['div', 'input'],\n        options: {\n          menu: [\n            [\n              {\n                id: 'color-contrast',\n                title: 'Insufficient color contrast',\n                description: 'Elements must meet minimum color contrast ratio thresholds.',\n                clickEvent: 'my-click-event',\n              },\n            ],\n            [\n              {\n                id: 'links-need-discernible-text',\n                title: 'Links need discernible text',\n                description: 'This is where a summary of the violation goes.',\n              },\n              {\n                id: 'links-need-discernible-text-details',\n                title: 'Important stuff',\n                description: 'Click here to view more details.',\n                iconLeft: 'info',\n                iconRight: 'shareAlt',\n                clickEvent: 'my-click-event',\n              },\n            ],\n          ],\n        },\n      },\n    ],\n  },\n  play: async () => {\n    await new Promise((resolve) => setTimeout(resolve, 200));\n    await userEvent.pointer({\n      coords: { pageX: 470, pageY: 240 },\n      keys: '[MouseLeft]',\n    });\n\n    await new Promise((resolve) => setTimeout(resolve, 200));\n    const elementItem = document.querySelector('#storybook-highlights-menu .element-list button')!;\n    await userEvent.pointer({\n      target: elementItem,\n      coords: { pageX: 470, pageY: 260 },\n      keys: '[MouseLeft]',\n    });\n\n    await new Promise((resolve) => setTimeout(resolve, 200));\n    const menuItem = document.querySelector('#storybook-highlights-menu .menu-list button')!;\n    await userEvent.pointer({\n      target: menuItem,\n      coords: { pageX: 470, pageY: 310 },\n      keys: '[MouseLeft]',\n    });\n  },\n});\n\nexport const OnPopover = meta.story({\n  parameters: {\n    highlights: [{ selectors: ['[popover]'], options: { menu: [] } }],\n    withPopover: true,\n  },\n  play: async ({ canvasElement }) => {\n    const button = within(canvasElement).getByText('Open Popover 1');\n    await userEvent.click(button);\n\n    await new Promise((resolve) => setTimeout(resolve, 200));\n    await userEvent.pointer({\n      coords: { pageX: window.innerWidth / 2, pageY: window.innerHeight / 2 },\n      keys: '[MouseLeft]',\n    });\n  },\n});\n\nexport const LayoutCentered = meta.story({\n  parameters: {\n    highlights: [{ selectors: ['div'] }],\n    layout: 'centered',\n  },\n  render: () => <div style={{ padding: 10 }}>Content</div>,\n});\n"
  },
  {
    "path": "code/core/src/highlight/useHighlights.ts",
    "content": "/// <reference path=\"./typings.d.ts\" />\n/* eslint-env browser */\nimport type { Channel } from 'storybook/internal/channels';\nimport { STORY_RENDER_PHASE_CHANGED } from 'storybook/internal/core-events';\n\nimport {\n  HIGHLIGHT,\n  MAX_Z_INDEX,\n  MIN_TOUCH_AREA_SIZE,\n  REMOVE_HIGHLIGHT,\n  RESET_HIGHLIGHT,\n  SCROLL_INTO_VIEW,\n} from './constants.ts';\nimport type { Box, Highlight, HighlightOptions, RawHighlightOptions } from './types.ts';\nimport {\n  createElement,\n  createIcon,\n  getEventDetails,\n  hidePopover,\n  isOverMenu,\n  isTargeted,\n  keepInViewport,\n  mapBoxes,\n  mapElements,\n  normalizeOptions,\n  showPopover,\n  useStore,\n} from './utils.ts';\n\nconst menuId = 'storybook-highlights-menu';\nconst rootId = 'storybook-highlights-root';\nconst storybookRootId = 'storybook-root';\n\nexport const useHighlights = (channel: Channel) => {\n  if (globalThis.__STORYBOOK_HIGHLIGHT_INITIALIZED) {\n    return;\n  }\n\n  globalThis.__STORYBOOK_HIGHLIGHT_INITIALIZED = true;\n\n  const { document } = globalThis;\n\n  const highlights = useStore<HighlightOptions[]>([]);\n  const elements = useStore<Map<HTMLElement, Highlight>>(new Map());\n  const boxes = useStore<Box[]>([]);\n\n  const clickCoords = useStore<{ x: number; y: number } | undefined>();\n  const hoverCoords = useStore<{ x: number; y: number } | undefined>();\n  const targets = useStore<Box[]>([]);\n  const hovered = useStore<Box[]>([]);\n  const focused = useStore<Box | undefined>();\n  const selected = useStore<Box | undefined>();\n\n  let root = document.getElementById(rootId);\n\n  // Only create the root element when first highlights are added\n  highlights.subscribe(() => {\n    if (!root) {\n      root = createElement('div', { id: rootId }) as HTMLElement;\n      document.body.appendChild(root);\n    }\n  });\n\n  // Update tracked elements when highlights change or the DOM tree changes\n  highlights.subscribe((value) => {\n    const storybookRoot = document.getElementById(storybookRootId)!;\n    if (!storybookRoot) {\n      return;\n    }\n\n    elements.set(mapElements(value));\n\n    const observer = new MutationObserver(() => elements.set(mapElements(value)));\n    observer.observe(storybookRoot, { subtree: true, childList: true });\n\n    return () => {\n      observer.disconnect();\n    };\n  });\n\n  // Update highlight boxes when elements are resized or scrollable elements are scrolled\n  elements.subscribe((value) => {\n    const updateBoxes = () => requestAnimationFrame(() => boxes.set(mapBoxes(value)));\n    const observer = new ResizeObserver(updateBoxes);\n    observer.observe(document.body);\n    Array.from(value.keys()).forEach((element) => observer.observe(element));\n\n    const scrollers = Array.from(document.body.querySelectorAll('*')).filter((el) => {\n      const { overflow, overflowX, overflowY } = window.getComputedStyle(el);\n      return ['auto', 'scroll'].some((o) => [overflow, overflowX, overflowY].includes(o));\n    });\n    scrollers.forEach((element) => element.addEventListener('scroll', updateBoxes));\n\n    return () => {\n      observer.disconnect();\n      scrollers.forEach((element) => element.removeEventListener('scroll', updateBoxes));\n    };\n  });\n\n  // Update highlight boxes for sticky elements when scrolling the window\n  elements.subscribe((value) => {\n    const sticky = Array.from(value.keys()).filter(({ style }) => style.position === 'sticky');\n    const updateBoxes = () =>\n      requestAnimationFrame(() => {\n        boxes.set((current) =>\n          current.map((box) => {\n            if (sticky.includes(box.element)) {\n              const { top, left } = box.element.getBoundingClientRect();\n              return { ...box, top: top + window.scrollY, left: left + window.scrollX };\n            }\n            return box;\n          })\n        );\n      });\n\n    document.addEventListener('scroll', updateBoxes);\n    return () => document.removeEventListener('scroll', updateBoxes);\n  });\n\n  // Remove stale click targets (boxes) when elements are removed\n  elements.subscribe((value) => {\n    targets.set((t) => t.filter(({ element }) => value.has(element)));\n  });\n\n  // Update selected and focused elements when clickable targets change\n  targets.subscribe((value) => {\n    if (value.length) {\n      selected.set((s) => (value.some((t) => t.element === s?.element) ? s : undefined));\n      focused.set((s) => (value.some((t) => t.element === s?.element) ? s : undefined));\n    } else {\n      selected.set(undefined);\n      focused.set(undefined);\n      clickCoords.set(undefined);\n    }\n  });\n\n  //\n  // Rendering\n  //\n\n  const styleElementByHighlight = new Map<string, HTMLStyleElement>(new Map());\n\n  // Update highlight keyframes when highlights change\n  highlights.subscribe((value) => {\n    value.forEach(({ keyframes }) => {\n      if (keyframes) {\n        let style = styleElementByHighlight.get(keyframes);\n        if (!style) {\n          style = document.createElement('style');\n          style.setAttribute('data-highlight', 'keyframes');\n          styleElementByHighlight.set(keyframes, style);\n          document.head.appendChild(style);\n        }\n        style.innerHTML = keyframes;\n      }\n    });\n\n    // Clean up stale keyframes\n    styleElementByHighlight.forEach((style, keyframes) => {\n      if (!value.some((v) => v.keyframes === keyframes)) {\n        style.remove();\n        styleElementByHighlight.delete(keyframes);\n      }\n    });\n  });\n\n  const boxElementByTargetElement = new Map<HTMLElement, HTMLDivElement>(new Map());\n\n  // Create an element for every highlight box\n  boxes.subscribe((value) => {\n    value.forEach((box) => {\n      let boxElement = boxElementByTargetElement.get(box.element);\n      if (root && !boxElement) {\n        const props = {\n          popover: 'manual',\n          'data-highlight-dimensions': `w${box.width.toFixed(0)}h${box.height.toFixed(0)}`,\n          'data-highlight-coordinates': `x${box.left.toFixed(0)}y${box.top.toFixed(0)}`,\n        };\n        boxElement = root.appendChild(\n          createElement('div', props, [createElement('div')]) as HTMLDivElement\n        );\n        boxElementByTargetElement.set(box.element, boxElement);\n      }\n    });\n\n    // Clean up stale highlight boxes\n    boxElementByTargetElement.forEach((box, element) => {\n      if (!value.some(({ element: e }) => e === element)) {\n        box.remove();\n        boxElementByTargetElement.delete(element);\n      }\n    });\n  });\n\n  // Handle click events on highlight boxes\n  boxes.subscribe((value) => {\n    const targetable = value.filter((box) => box.menu);\n    if (!targetable.length) {\n      return;\n    }\n\n    const onClick = (event: MouseEvent) => {\n      // The menu may get repositioned, so we wait for the next frame before checking its position\n      requestAnimationFrame(() => {\n        const menu = document.getElementById(menuId);\n        const coords = { x: event.pageX, y: event.pageY };\n\n        // Don't do anything if the click is within the menu\n        if (menu && !isOverMenu(menu, coords)) {\n          // Update menu coordinates and clicked target boxes based on the click position\n          const results = targetable.filter((box) => {\n            const boxElement = boxElementByTargetElement.get(box.element)!;\n            return isTargeted(box, boxElement, coords);\n          });\n          clickCoords.set(results.length ? coords : undefined);\n          targets.set(results);\n        }\n      });\n    };\n\n    document.addEventListener('click', onClick);\n    return () => document.removeEventListener('click', onClick);\n  });\n\n  const updateHovered = () => {\n    const menu = document.getElementById(menuId);\n    const coords = hoverCoords.get();\n    if (!coords || (menu && isOverMenu(menu, coords))) {\n      return;\n    }\n\n    hovered.set((current) => {\n      const update = boxes.get().filter((box) => {\n        const boxElement = boxElementByTargetElement.get(box.element)!;\n        return isTargeted(box, boxElement, coords);\n      });\n      const existing = current.filter((box) => update.includes(box));\n      const additions = update.filter((box) => !current.includes(box));\n      const hasRemovals = current.length - existing.length;\n      // Only set a new value if there are additions or removals\n      return additions.length || hasRemovals ? [...existing, ...additions] : current;\n    });\n  };\n  hoverCoords.subscribe(updateHovered);\n  boxes.subscribe(updateHovered);\n\n  const updateBoxStyles = () => {\n    const selectedElement = selected.get();\n    const targetElements = selectedElement ? [selectedElement] : targets.get();\n    const focusedElement = targetElements.length === 1 ? targetElements[0] : focused.get();\n    const isMenuOpen = clickCoords.get() !== undefined;\n\n    boxes.get().forEach((box) => {\n      const boxElement = boxElementByTargetElement.get(box.element);\n      if (boxElement) {\n        const isFocused = focusedElement === box;\n        const isHovered = isMenuOpen\n          ? focusedElement\n            ? isFocused\n            : targetElements.includes(box)\n          : hovered.get()?.includes(box);\n\n        Object.assign(boxElement.style, {\n          animation: 'none',\n          background: 'transparent',\n          border: 'none',\n          boxSizing: 'border-box',\n          outline: 'none',\n          outlineOffset: '0px',\n          ...box.styles,\n          ...(isHovered ? box.hoverStyles : {}),\n          ...(isFocused ? box.focusStyles : {}),\n          position: getComputedStyle(box.element).position === 'fixed' ? 'fixed' : 'absolute',\n          zIndex: MAX_Z_INDEX - 10,\n          top: `${box.top}px`,\n          left: `${box.left}px`,\n          width: `${box.width}px`,\n          height: `${box.height}px`,\n          margin: 0,\n          padding: 0,\n          cursor: box.menu && isHovered ? 'pointer' : 'default',\n          pointerEvents: box.menu ? 'auto' : 'none',\n          display: 'flex',\n          alignItems: 'center',\n          justifyContent: 'center',\n          overflow: 'visible',\n        });\n        Object.assign((boxElement.children[0] as HTMLDivElement).style, {\n          width: '100%',\n          height: '100%',\n          minHeight: `${MIN_TOUCH_AREA_SIZE}px`,\n          minWidth: `${MIN_TOUCH_AREA_SIZE}px`,\n          boxSizing: 'content-box',\n          padding: boxElement.style.outlineWidth || '0px',\n        });\n\n        showPopover(boxElement);\n      }\n    });\n  };\n  boxes.subscribe(updateBoxStyles);\n  targets.subscribe(updateBoxStyles);\n  hovered.subscribe(updateBoxStyles);\n  focused.subscribe(updateBoxStyles);\n  selected.subscribe(updateBoxStyles);\n\n  const renderMenu = () => {\n    if (!root) {\n      return;\n    }\n\n    let menu = document.getElementById(menuId);\n    if (menu) {\n      menu.innerHTML = '';\n    } else {\n      const props = { id: menuId, popover: 'manual' };\n      menu = root.appendChild(createElement('div', props) as HTMLElement);\n      root.appendChild(\n        createElement('style', {}, [\n          `\n            #${menuId} {\n              position: absolute;\n              z-index: ${MAX_Z_INDEX};\n              width: 300px;\n              padding: 0px;\n              margin: 15px 0 0 0;\n              transform: translateX(-50%);\n              font-family: \"Nunito Sans\", -apple-system, \".SFNSText-Regular\", \"San Francisco\", BlinkMacSystemFont, \"Segoe UI\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n              font-size: 12px;\n              background: white;\n              border: none;\n              border-radius: 6px;\n              box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.05), 0 5px 15px 0 rgba(0, 0, 0, 0.1);\n              color: #2E3438;\n            }\n            #${menuId} ul {\n              list-style: none;\n              margin: 0;\n              padding: 0;\n            }\n            #${menuId} > ul {\n              max-height: 300px;\n              overflow-y: auto;\n              padding: 4px 0;\n            }\n            #${menuId} li {\n              padding: 0 4px;\n              margin: 0;\n            }\n            #${menuId} li > :not(ul) {\n              display: flex;\n              padding: 8px;\n              margin: 0;\n              align-items: center;\n              gap: 8px;\n              border-radius: 4px;\n            }\n            #${menuId} button {\n              width: 100%;\n              border: 0;\n              background: transparent;\n              color: inherit;\n              text-align: left;\n              font-family: inherit;\n              font-size: inherit;\n            }\n            #${menuId} button:focus-visible {\n              outline-color: #029CFD;\n            }\n            #${menuId} button:hover {\n              background: rgba(2, 156, 253, 0.07);\n              color: #029CFD;\n              cursor: pointer;\n            }\n            #${menuId} li code {\n              white-space: nowrap;\n              overflow: hidden;\n              text-overflow: ellipsis;\n              line-height: 16px;\n              font-size: 11px;\n            }\n            #${menuId} li svg {\n              flex-shrink: 0;\n              margin: 1px;\n              color: #73828C;\n            }\n            #${menuId} li > button:hover svg, #${menuId} li > button:focus-visible svg {\n              color: #029CFD;\n            }\n            #${menuId} .element-list li svg {\n              display: none;\n            }\n            #${menuId} li.selectable svg, #${menuId} li.selected svg {\n              display: block;\n            }\n            #${menuId} .menu-list {\n              border-top: 1px solid rgba(38, 85, 115, 0.15);\n            }\n            #${menuId} .menu-list > li:not(:last-child) {\n              padding-bottom: 4px;\n              margin-bottom: 4px;\n              border-bottom: 1px solid rgba(38, 85, 115, 0.15);\n            }\n            #${menuId} .menu-items, #${menuId} .menu-items li {\n              padding: 0;\n            }\n            #${menuId} .menu-item {\n              display: flex;\n            }\n            #${menuId} .menu-item-content {\n              display: flex;\n              flex-direction: column;\n              flex-grow: 1;\n            }\n          `,\n        ])\n      );\n    }\n\n    const selectedElement = selected.get();\n    const elementList = selectedElement ? [selectedElement] : targets.get();\n\n    if (elementList.length) {\n      menu.style.position =\n        getComputedStyle(elementList[0].element).position === 'fixed' ? 'fixed' : 'absolute';\n\n      menu.appendChild(\n        createElement(\n          'ul',\n          { class: 'element-list' },\n          elementList.map((target) => {\n            const selectable =\n              elementList.length > 1 &&\n              !!target.menu?.some((group) =>\n                group.some(\n                  (item) =>\n                    !item.selectors || item.selectors.some((s) => target.selectors.includes(s))\n                )\n              );\n            const props = selectable\n              ? {\n                  class: 'selectable',\n                  onClick: () => selected.set(target),\n                  onMouseEnter: () => focused.set(target),\n                  onMouseLeave: () => focused.set(undefined),\n                }\n              : selectedElement\n                ? { class: 'selected', onClick: () => selected.set(undefined) }\n                : {};\n            const asButton = selectable || selectedElement;\n            return createElement('li', props, [\n              createElement(asButton ? 'button' : 'div', asButton ? { type: 'button' } : {}, [\n                selectedElement ? createIcon('chevronLeft') : null,\n                createElement('code', {}, [target.element.outerHTML]),\n                selectable ? createIcon('chevronRight') : null,\n              ]),\n            ]);\n          })\n        )\n      );\n    }\n\n    if (selected.get() || targets.get().length === 1) {\n      const target = selected.get() || targets.get()[0];\n      const menuGroups = target.menu?.filter((group) =>\n        group.some(\n          (item) => !item.selectors || item.selectors.some((s) => target.selectors.includes(s))\n        )\n      );\n      if (menuGroups?.length) {\n        menu.appendChild(\n          createElement(\n            'ul',\n            { class: 'menu-list' },\n            menuGroups.map((menuItems) =>\n              createElement('li', {}, [\n                createElement(\n                  'ul',\n                  { class: 'menu-items' },\n                  menuItems.map(\n                    ({ id, title, description, iconLeft, iconRight, clickEvent: event }) => {\n                      const onClick =\n                        event && (() => channel.emit(event, id, getEventDetails(target)));\n                      return createElement('li', {}, [\n                        createElement(\n                          onClick ? 'button' : 'div',\n                          onClick\n                            ? { class: 'menu-item', type: 'button', onClick }\n                            : { class: 'menu-item' },\n                          [\n                            iconLeft ? createIcon(iconLeft) : null,\n                            createElement('div', { class: 'menu-item-content' }, [\n                              createElement(description ? 'strong' : 'span', {}, [title]),\n                              description && createElement('span', {}, [description]),\n                            ]),\n                            iconRight ? createIcon(iconRight) : null,\n                          ]\n                        ),\n                      ]);\n                    }\n                  )\n                ),\n              ])\n            )\n          )\n        );\n      }\n    }\n\n    const coords = clickCoords.get();\n    if (coords) {\n      Object.assign(menu.style, {\n        display: 'block',\n        left: `${menu.style.position === 'fixed' ? coords.x - window.scrollX : coords.x}px`,\n        top: `${menu.style.position === 'fixed' ? coords.y - window.scrollY : coords.y}px`,\n      });\n\n      // Put the menu in #top-layer, above any other popovers and z-indexes\n      showPopover(menu);\n\n      // Reposition the menu on after it renders, to avoid rendering outside the viewport\n      requestAnimationFrame(() => keepInViewport(menu, coords, { topOffset: 15, centered: true }));\n    } else {\n      hidePopover(menu);\n      Object.assign(menu.style, { display: 'none' });\n    }\n  };\n  targets.subscribe(renderMenu);\n  selected.subscribe(renderMenu);\n\n  //\n  // Channel event handlers\n  //\n\n  const addHighlight = (highlight: RawHighlightOptions) => {\n    const info = normalizeOptions(highlight);\n    highlights.set((value) => {\n      const others = info.id ? value.filter((h) => h.id !== info.id) : value;\n      return info.selectors?.length ? [...others, info] : others;\n    });\n  };\n\n  const removeHighlight = (id: string) => {\n    if (id) {\n      highlights.set((value) => value.filter((h) => h.id !== id));\n    }\n  };\n\n  const resetState = () => {\n    highlights.set([]);\n    elements.set(new Map());\n    boxes.set([]);\n    clickCoords.set(undefined);\n    hoverCoords.set(undefined);\n    targets.set([]);\n    hovered.set([]);\n    focused.set(undefined);\n    selected.set(undefined);\n  };\n\n  let removeTimeout: NodeJS.Timeout;\n  const scrollIntoView = (target: string, options?: ScrollIntoViewOptions) => {\n    const id = 'scrollIntoView-highlight';\n    clearTimeout(removeTimeout);\n    removeHighlight(id);\n\n    const element = document.querySelector(target);\n    if (!element) {\n      console.warn(`Cannot scroll into view: ${target} not found`);\n      return;\n    }\n\n    element.scrollIntoView({ behavior: 'smooth', block: 'center', ...options });\n    const keyframeName = `kf-${Math.random().toString(36).substring(2, 15)}`;\n    highlights.set((value) => [\n      ...value,\n      {\n        id,\n        priority: 1000,\n        selectors: [target],\n        styles: {\n          outline: '2px solid #1EA7FD',\n          outlineOffset: '-1px',\n          animation: `${keyframeName} 3s linear forwards`,\n        },\n        keyframes: `@keyframes ${keyframeName} {\n          0% { outline: 2px solid #1EA7FD; }\n          20% { outline: 2px solid #1EA7FD00; }\n          40% { outline: 2px solid #1EA7FD; }\n          60% { outline: 2px solid #1EA7FD00; }\n          80% { outline: 2px solid #1EA7FD; }\n          100% { outline: 2px solid #1EA7FD00; }\n        }`,\n      },\n    ]);\n    removeTimeout = setTimeout(() => removeHighlight(id), 3500);\n  };\n\n  const onMouseMove = (event: MouseEvent): void => {\n    requestAnimationFrame(() => hoverCoords.set({ x: event.pageX, y: event.pageY }));\n  };\n\n  document.body.addEventListener('mousemove', onMouseMove);\n\n  channel.on(HIGHLIGHT, addHighlight);\n  channel.on(REMOVE_HIGHLIGHT, removeHighlight);\n  channel.on(RESET_HIGHLIGHT, resetState);\n  channel.on(SCROLL_INTO_VIEW, scrollIntoView);\n  channel.on(STORY_RENDER_PHASE_CHANGED, ({ newPhase }: { newPhase: string }) => {\n    if (newPhase === 'loading') {\n      resetState();\n    }\n  });\n};\n"
  },
  {
    "path": "code/core/src/highlight/utils.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { useStore } from './utils.ts';\n\ndescribe('useStore', () => {\n  it('should return the initial value', () => {\n    const { get } = useStore(1);\n    expect(get()).toBe(1);\n  });\n\n  it('should update the value', () => {\n    const { get, set } = useStore(1);\n    set(2);\n    expect(get()).toBe(2);\n  });\n\n  it('should update the value using a function', () => {\n    const { get, set } = useStore(1);\n    set((value) => value + 1);\n    expect(get()).toBe(2);\n  });\n\n  it('should subscribe and unsubscribe from the store', () => {\n    const { set, subscribe } = useStore(1);\n    const callback = vi.fn();\n\n    const unsubscribe = subscribe(callback);\n    set(2);\n    expect(callback).toHaveBeenCalledWith(2);\n\n    unsubscribe();\n    set(3);\n    expect(callback).toHaveBeenCalledTimes(1);\n  });\n\n  it('should invoke listener teardowns', () => {\n    const { set, subscribe } = useStore();\n    const callback = vi.fn();\n    subscribe(() => callback);\n    set(1);\n    expect(callback).toHaveBeenCalledTimes(0);\n    set(2);\n    expect(callback).toHaveBeenCalledTimes(1);\n  });\n\n  it('should teardown the store', () => {\n    const { get, teardown } = useStore(1);\n    teardown();\n    expect(get()).toBeUndefined();\n  });\n});\n"
  },
  {
    "path": "code/core/src/highlight/utils.ts",
    "content": "/* eslint-env browser */\nimport { MIN_TOUCH_AREA_SIZE } from './constants.ts';\nimport { type IconName, iconPaths } from './icons.ts';\nimport type {\n  Box,\n  ClickEventDetails,\n  Highlight,\n  HighlightOptions,\n  RawHighlightOptions,\n} from './types.ts';\n\nconst svgElements = 'svg,path,rect,circle,line,polyline,polygon,ellipse,text'.split(',');\n\nexport const createElement = (type: string, props: Record<string, any> = {}, children?: any[]) => {\n  const element = svgElements.includes(type)\n    ? document.createElementNS('http://www.w3.org/2000/svg', type)\n    : document.createElement(type);\n\n  Object.entries(props).forEach(([key, val]) => {\n    if (/[A-Z]/.test(key)) {\n      if (key === 'onClick') {\n        element.addEventListener('click', val);\n        (element as HTMLButtonElement).addEventListener('keydown', (e) => {\n          if (e.key === 'Enter' || e.key === ' ') {\n            e.preventDefault();\n            val();\n          }\n        });\n      }\n      if (key === 'onMouseEnter') {\n        element.addEventListener('mouseenter', val);\n      }\n      if (key === 'onMouseLeave') {\n        element.addEventListener('mouseleave', val);\n      }\n    } else {\n      element.setAttribute(key, val);\n    }\n  });\n\n  children?.forEach((child) => {\n    if (child === null || child === undefined || child === false) {\n      return;\n    }\n    try {\n      element.appendChild(child as Node);\n    } catch (e) {\n      element.appendChild(document.createTextNode(String(child)));\n    }\n  });\n\n  return element;\n};\n\nexport const createIcon = (name: IconName) =>\n  iconPaths[name] &&\n  createElement(\n    'svg',\n    { width: '14', height: '14', viewBox: '0 0 14 14', xmlns: 'http://www.w3.org/2000/svg' },\n    iconPaths[name].map((d) =>\n      createElement('path', {\n        fill: 'currentColor',\n        'fill-rule': 'evenodd',\n        'clip-rule': 'evenodd',\n        d,\n      })\n    )\n  );\n\nexport const normalizeOptions = (options: RawHighlightOptions): Highlight => {\n  if ('elements' in options) {\n    // Legacy format\n    const { elements, color, style } = options;\n    return {\n      id: undefined,\n      priority: 0,\n      selectors: elements,\n      styles: {\n        outline: `2px ${style} ${color}`,\n        outlineOffset: '2px',\n        boxShadow: '0 0 0 6px rgba(255,255,255,0.6)',\n      },\n      menu: undefined,\n    };\n  }\n\n  const { menu, ...rest } = options;\n  return {\n    id: undefined,\n    priority: 0,\n    styles: {\n      outline: '2px dashed #029cfd',\n    },\n    ...rest,\n    menu: Array.isArray(menu) ? (menu.every(Array.isArray) ? menu : [menu]) : undefined,\n  };\n};\n\nexport const isFunction = (obj: unknown): obj is (...args: any[]) => any => obj instanceof Function;\n\ntype Listener<T> = (value: T) => void | (() => void);\n\nconst state = new Map<symbol, any>();\nconst listeners = new Map<symbol, Listener<any>[]>();\nconst teardowns = new Map<Listener<any>, ReturnType<Listener<any>>>();\n\nexport const useStore = <T>(initialValue?: T) => {\n  const key = Symbol();\n  listeners.set(key, []);\n  state.set(key, initialValue);\n\n  const get = () => state.get(key) as T;\n  const set = (update: T | ((state: T) => T)) => {\n    const current = state.get(key) as T;\n    const next = isFunction(update) ? update(current) : update;\n    if (next !== current) {\n      state.set(key, next);\n      listeners.get(key)?.forEach((listener) => {\n        teardowns.get(listener)?.();\n        teardowns.set(listener, listener(next));\n      });\n    }\n  };\n  const subscribe = (listener: Listener<T>) => {\n    listeners.get(key)?.push(listener);\n    return () => {\n      const list = listeners.get(key);\n      if (list) {\n        listeners.set(\n          key,\n          list.filter((l) => l !== listener)\n        );\n      }\n    };\n  };\n  const teardown = () => {\n    listeners.get(key)?.forEach((listener) => {\n      teardowns.get(listener)?.();\n      teardowns.delete(listener);\n    });\n    listeners.delete(key);\n    state.delete(key);\n  };\n\n  return { get, set, subscribe, teardown } as const;\n};\n\nexport const mapElements = (highlights: HighlightOptions[]): Map<HTMLElement, Highlight> => {\n  const root = document.getElementById('storybook-root');\n  const map = new Map();\n  for (const highlight of highlights) {\n    const { priority = 0 } = highlight;\n    for (const selector of highlight.selectors) {\n      const elements = [\n        ...document.querySelectorAll(\n          // Elements matching the selector, excluding storybook elements and their descendants.\n          // Necessary to find portaled elements (e.g. children of `body`).\n          `:is(${selector}):not([id^=\"storybook-\"], [id^=\"storybook-\"] *, [class^=\"sb-\"], [class^=\"sb-\"] *)`\n        ),\n        // Elements matching the selector inside the storybook root, as these were excluded above.\n        ...(root?.querySelectorAll(selector) || []),\n      ];\n      for (const element of elements) {\n        const existing = map.get(element);\n        if (!existing || existing.priority <= priority) {\n          map.set(element, {\n            ...highlight,\n            priority,\n            selectors: Array.from(new Set((existing?.selectors || []).concat(selector))),\n          });\n        }\n      }\n    }\n  }\n  return map;\n};\n\nexport const mapBoxes = (elements: Map<HTMLElement, Highlight>): Box[] =>\n  Array.from(elements.entries())\n    .map<Box>(([element, { selectors, styles, hoverStyles, focusStyles, menu }]) => {\n      const { top, left, width, height } = element.getBoundingClientRect();\n      const { position } = getComputedStyle(element);\n      return {\n        element,\n        selectors,\n        styles,\n        hoverStyles,\n        focusStyles,\n        menu,\n        top: position === 'fixed' ? top : top + window.scrollY,\n        left: position === 'fixed' ? left : left + window.scrollX,\n        width,\n        height,\n      };\n    })\n    .sort((a, b) => b.width * b.height - a.width * a.height);\n\nexport const isOverMenu = (menuElement: HTMLElement, coordinates: { x: number; y: number }) => {\n  const menu = menuElement.getBoundingClientRect();\n  const { x, y } = coordinates;\n  return (\n    menu?.top &&\n    menu?.left &&\n    x >= menu.left &&\n    x <= menu.left + menu.width &&\n    y >= menu.top &&\n    y <= menu.top + menu.height\n  );\n};\n\nexport const isTargeted = (\n  box: Box,\n  boxElement: HTMLElement,\n  coordinates: { x: number; y: number }\n) => {\n  if (!boxElement || !coordinates) {\n    return false;\n  }\n  let { left, top, width, height } = box;\n  if (height < MIN_TOUCH_AREA_SIZE) {\n    top = top - Math.round((MIN_TOUCH_AREA_SIZE - height) / 2);\n    height = MIN_TOUCH_AREA_SIZE;\n  }\n  if (width < MIN_TOUCH_AREA_SIZE) {\n    left = left - Math.round((MIN_TOUCH_AREA_SIZE - width) / 2);\n    width = MIN_TOUCH_AREA_SIZE;\n  }\n  if (boxElement.style.position === 'fixed') {\n    left += window.scrollX;\n    top += window.scrollY;\n  }\n  const { x, y } = coordinates;\n  return x >= left && x <= left + width && y >= top && y <= top + height;\n};\n\nexport const keepInViewport = (\n  element: HTMLElement,\n  targetCoordinates: { x: number; y: number },\n  options: { margin?: number; topOffset?: number; centered?: boolean } = {}\n) => {\n  const { x, y } = targetCoordinates;\n  const { margin = 5, topOffset = 0, centered = false } = options;\n  const { scrollX, scrollY, innerHeight: windowHeight, innerWidth: windowWidth } = window;\n\n  const top = Math.min(\n    element.style.position === 'fixed' ? y - scrollY : y,\n    windowHeight - element.clientHeight - margin - topOffset + scrollY\n  );\n\n  const leftOffset = centered ? element.clientWidth / 2 : 0;\n  const left =\n    element.style.position === 'fixed'\n      ? Math.max(Math.min(x - scrollX, windowWidth - leftOffset - margin), leftOffset + margin)\n      : Math.max(\n          Math.min(x, windowWidth - leftOffset - margin + scrollX),\n          leftOffset + margin + scrollX\n        );\n\n  Object.assign(element.style, {\n    ...(left !== x && { left: `${left}px` }),\n    ...(top !== y && { top: `${top}px` }),\n  });\n};\n\nexport const showPopover = (element: HTMLElement) => {\n  if (window.HTMLElement.prototype.hasOwnProperty('showPopover')) {\n    element.showPopover();\n  }\n};\n\nexport const hidePopover = (element: HTMLElement) => {\n  if (window.HTMLElement.prototype.hasOwnProperty('showPopover')) {\n    element.hidePopover();\n  }\n};\n\nexport const getEventDetails = (target: Box): ClickEventDetails => ({\n  top: target.top,\n  left: target.left,\n  width: target.width,\n  height: target.height,\n  selectors: target.selectors,\n  element: {\n    attributes: Object.fromEntries(\n      Array.from(target.element.attributes).map((attr) => [attr.name, attr.value])\n    ),\n    localName: target.element.localName,\n    tagName: target.element.tagName,\n    outerHTML: target.element.outerHTML,\n  },\n});\n"
  },
  {
    "path": "code/core/src/instrumenter/EVENTS.ts",
    "content": "export const EVENTS = {\n  CALL: 'storybook/instrumenter/call',\n  SYNC: 'storybook/instrumenter/sync',\n  START: 'storybook/instrumenter/start',\n  BACK: 'storybook/instrumenter/back',\n  GOTO: 'storybook/instrumenter/goto',\n  NEXT: 'storybook/instrumenter/next',\n  END: 'storybook/instrumenter/end',\n};\n"
  },
  {
    "path": "code/core/src/instrumenter/README.md",
    "content": "# Storybook Instrumenter\n\nThe Storybook Instrumenter is used to patch a (3rd party) module to track and intercept function invocations for step-through debugging using the Interactions addon. In essence, the Instrumenter traverses a given object, recursively monkey-patching any functions to make them \"tracked\".\n\nDuring normal operation, tracked functions simply call through to their original function, forwarding the return value. As a side-effect, they also emit a `call` event whenever they are invoked.\n\nThrough `options`, functions can be marked \"interceptable\", which give them another mode of operation. In this \"intercept\" mode, the original function is _not_ invoked, instead the interceptable function returns a `Promise` which only resolves when receiving an event to do so. This enables step-through debugging, directly in the browser. A consequence of this design is that all interceptable functions must be `await`-ed, even if their original function is not asynchronous (i.e. it normally does not return a Promise).\n\n## API\n\nThe primary way to use the Storybook Instrumenter is through the `instrument` function:\n\n```ts\ninstrument<TObj extends Record<string, any>>(obj: TObj, options: Options): TObj\n```\n\n`instrument` takes a plain JS object or imported ES module, and optionally an `options` object. It traverses the input object, recursively iterating over object properties and arrays. Any values with typeof `function` are tracked (through monkey-patching). Finally, a shallow copy of the original object is returned (with functions replaced). If the `mutate: true` option is set, the original object is mutated instead of returning a shallow copy.\n\n### Options\n\n- [`intercept`](#intercept) Control which instrumented functions are interceptable.\n- [`mutate`](#mutate) Mutate and return the input object rather than returning a shallow copy.\n- [`path`](#path) Virtual object path to prepend to the actual input object function paths.\n- [`retain`](#retain) Retain calls across renders and when switching stories.\n\n#### `intercept`\n\n> `boolean | ((method: string, path: Array<string | CallRef>) => boolean)`\n\nDepending on the library and functions to be instrumented, you may want to configure some or all functions to be interceptable. Interceptable calls are _debuggable_, meaning they can be paused on. When paused, an interceptable function will not invoke it's original function, but rather return a pending Promise. This promise is only resolved when stepping over the call in the debugger. Only interceptable calls will appear as rows in the Interactions addon panel. Non-interceptable calls may appear as inline arguments to an interceptable function.\n\n`intercept` can take either a boolean (default `false`) or a function which returns a boolean. This enables you to only make specific library functions interceptable. This function receives a `method` and `path`, referring to the name of the function and the path to that function in the object tree. Some functions may return an object which is then instrumented as well, in which case the `path` will contain a \"call ref\", which is a plain object containing a `__callId__` property referencing the originating call.\n\nHere's an example `intercept` function (from `storybook/test`):\n\n```js\n(method, path) => path[0] === 'fireEvent' || method.startsWith('findBy') || method.startsWith('waitFor'),\n```\n\nThis means all methods under `fireEvent` (an object) are instrumentable, as well as any methods which name starts with `findBy` or `waitFor`.\n\n#### `mutate`\n\n> `boolean`\n\nBy default, `instrument` creates a shallow clone of the input object, replacing functions with their tracked counterparts without affecting the original input object. This is usually the safest and most predictable behavior, but in some situations you may have to rely on mutation. By setting `mutate: true` you can enable this behavior. Be careful though: mutating a Node module can lead to hard-to-debug issues.\n\n#### `path`\n\n> `Array<string | CallRef>`\n\nStorybook Interactions will automatically generate a pseudo-code representation of tracked function calls based on their metadata. For example, this call:\n\n```js\n{ path: ['userEvent'], method: 'keyboard', args: ['hello'], ... }\n```\n\nWill print as `userEvent.keyboard(\"hello\")`.\n\nBy default, the call `path` is determined by the hierarchy of the input object. To get the above result, your input object would have to look something like this:\n\n```js\n{ userEvent: { keyboard: function(text) { ... } } }\n```\n\nThe `path` config option allows you to prepend elements to the normal path. So if your input object does not have a `userEvent` property, but directly contains `keyboard`, then you can set `path: ['userEvent']` to correct for this.\n\n#### `retain`\n\n> `boolean`\n\nOn rare occasions, you may have an instrumented function that's invoked outside the context of a story render or play function. One example can be found in `argsEnhancers` which run when Storybook is initialized, but aren't rerun when you switch or rerun stories. Normally, the Storybook Instrumenter clears its internal record of calls when switching between stories, losing track of those function calls which happened on initialization. Set `retain: true` to keep these calls on record while switching or rerunning stories.\n\n> Note that retained functions should not be interceptable.\n\n## Events\n\nThe Storybook Instrumenter uses the [Storybook Channel API](../channels/README.md) to send and receive events.\n\n### Emitted tracking events\n\nThe instrumenter emits two types of events for tracking function invocations (\"calls\"):\n\n- [`storybook/instrumenter/call`](#storybook-instrumenter-call) Provides call metadata whenever a tracked function is invoked.\n- [`storybook/instrumenter/sync`](#storybook-instrumenter-sync) Provides a call log after one or more tracked functions are invoked.\n\n#### `storybook/instrumenter/call`\n\nThis event is emitted whenever a tracked function is invoked (a \"call\").\n\nThe event payload consists of all metadata about the function invocation, including a unique `id`, any arguments, the method name and object path. However, the order of events is not guaranteed and you may receive the same call multiple times while debugging. Moreover, this event is emitted for _all_ tracked calls, not just interceptable ones.\n\n#### `storybook/instrumenter/sync`\n\nThis event is emitted whenever a tracked function is invoked, but the event is debounced until the next \"tick\", so multiple consecutive synchronous calls will trigger a single `sync` event.\n\nThe event payload object contains an array of `logItems` and a `controlStates` object. The `logItems` array represent a \"normalized\" log of _interceptable_ calls. The order of calls in this log is guaranteed and step-through debugging will not append to the log but rather update it to set the proper `status` for each call. The log does not contain full call metadata but only a `callId` property, so this must be mapped onto received `storybook/instrumenter/call` events. For the value of `controlStates`, see [Control states](#control-states).\n\nAn example `sync` payload may look like this:\n\n```js\n{\n  controlStates: {\n    start: false,\n    back: false,\n    goto: true,\n    next: true,\n    end: true,\n  },\n  logItems: [\n    { callId: 'tooltip--hovered [0] hover', status: 'waiting' }\n  ]\n}\n```\n\n### Received control events\n\nThe instrumenter listens for these control events:\n\n- `storybook/instrumenter/start` - Remount the story and start the debugger at the first interceptable call\n- `storybook/instrumenter/back` - Remount the story and start the debugger at the previous interceptable call\n- `storybook/instrumenter/goto` - Fast-forwards to - or remounts and starts debugging at - the given interceptable call\n- `storybook/instrumenter/next` - Resolves the Promise for the currently intercepted call, letting execution continue to the next call\n- `storybook/instrumenter/end` - Resolves all Promises for intercepted calls, letting execution continue to the end\n\nRemounting is achieved through emitting Storybook's `forceRemount` event. In some situations, this will trigger a full page refresh (of the preview) in order to flush pending promises (e.g. long-running interactions).\n\n## Control states\n\nBesides patching functions, the instrumenter keeps track of \"control states\". These indicate whether the debugger is available, and which control events are available for use:\n\n- `start: boolean` - Whether emitting `storybook/instrumenter/start` would work\n- `back: boolean` - Whether emitting `storybook/instrumenter/back` would work\n- `goto: boolean` - Whether emitting `storybook/instrumenter/goto` would work\n- `next: boolean` - Whether emitting `storybook/instrumenter/next` would work\n- `end: boolean` - Whether emitting `storybook/instrumenter/end` would work\n\nThese values are provided in the `controlStates` object on the `storybook/instrumenter/sync` event payload.\n"
  },
  {
    "path": "code/core/src/instrumenter/index.ts",
    "content": "export { instrument } from './instrumenter.ts';\n\nexport { EVENTS } from './EVENTS.ts';\nexport * from './types.ts';\n"
  },
  {
    "path": "code/core/src/instrumenter/instrumenter.test.ts",
    "content": "// @vitest-environment happy-dom\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { SET_CURRENT_STORY, STORY_RENDER_PHASE_CHANGED } from 'storybook/internal/core-events';\n\nimport { global } from '@storybook/global';\n\nimport { EVENTS } from './EVENTS.ts';\nimport { Instrumenter, isClass } from './instrumenter.ts';\nimport { addons } from './preview-api.ts';\nimport type { Options } from './types.ts';\n\nconst mocks = await vi.hoisted(async () => {\n  const { Channel } = await import('storybook/internal/channels');\n  const { EVENTS: INSTRUMENTER_EVENTS } = await import('./EVENTS.ts');\n  const { FORCE_REMOUNT } = await import('storybook/internal/core-events');\n\n  const transport = {\n    setHandler: () => {},\n    send: () => {},\n  };\n\n  const channel = new Channel({ transport });\n\n  const callSpy = vi.fn();\n  const syncSpy = vi.fn();\n  const forceRemountSpy = vi.fn();\n\n  channel.on(INSTRUMENTER_EVENTS.CALL, callSpy);\n  channel.on(INSTRUMENTER_EVENTS.SYNC, syncSpy);\n  channel.on(FORCE_REMOUNT, forceRemountSpy);\n\n  return {\n    callSpy,\n    syncSpy,\n    forceRemountSpy,\n    ready: vi.fn().mockResolvedValue(Promise.resolve(true)),\n    channel,\n  };\n});\n\nvi.mock('storybook/internal/client-logger');\nvi.mock('./preview-api', () => {\n  return {\n    addons: {\n      ready: mocks.ready,\n      getChannel: vi.fn().mockImplementation(() => {\n        return mocks.channel;\n      }),\n    },\n  };\n});\n\nclass HTMLElement {\n  constructor(props: any) {\n    Object.assign(this, props);\n  }\n}\n\n// @ts-expect-error (global scope type conflicts)\ndelete global.location;\n// @ts-expect-error (global scope type conflicts)\nglobal.location = { reload: vi.fn() };\n// @ts-expect-error (global scope type conflicts)\nglobal.HTMLElement = HTMLElement;\n\nconst storyId = 'kind--story';\nglobal.window.__STORYBOOK_PREVIEW__ = {\n  selectionStore: { selection: { storyId, viewMode: 'story' } },\n} as any;\n\nconst setRenderPhase = (newPhase: string) =>\n  addons.getChannel().emit(STORY_RENDER_PHASE_CHANGED, { newPhase, storyId });\n\nlet instrumenter: Instrumenter;\nconst instrument = <TObj extends Record<string, any>>(obj: TObj, options: Options = {}) =>\n  instrumenter.instrument(obj, options);\n\nconst tick = () => new Promise((resolve) => setTimeout(resolve, 0));\n\nbeforeEach(async () => {\n  vi.useRealTimers();\n  global.window.parent.__STORYBOOK_ADDON_INTERACTIONS_INSTRUMENTER_STATE__ = {};\n  mocks.callSpy.mockClear();\n  mocks.syncSpy.mockClear();\n  mocks.forceRemountSpy.mockClear();\n  mocks.ready.mockClear();\n  instrumenter = new Instrumenter();\n  await tick();\n  setRenderPhase('loading');\n});\n\nafterEach(() => {\n  addons.getChannel().emit(SET_CURRENT_STORY); // trigger a cleanup\n});\n\ndescribe('Instrumenter', () => {\n  it('patches object methods', () => {\n    const fn = () => {};\n    const result = instrument({ fn });\n    expect(result).toStrictEqual({ fn: expect.any(Function) });\n    expect(result.fn.name).toBe('fn');\n    expect(result.fn.__originalFn__).toBe(fn);\n  });\n\n  it('patches nested methods', () => {\n    const fn1: any = () => {};\n    const fn2: any = () => {};\n    const result = instrument({ foo: { fn1, bar: { fn2 } } });\n    expect(result).toStrictEqual({\n      foo: {\n        fn1: expect.any(Function),\n        bar: { fn2: expect.any(Function) },\n      },\n    });\n    expect(result.foo.fn1.__originalFn__).toBe(fn1);\n    expect(result.foo.bar.fn2.__originalFn__).toBe(fn2);\n  });\n\n  it('does not patch already patched functions', () => {\n    const fn: any = () => {};\n    const result = instrument(instrument({ fn }));\n    expect(result.fn.__originalFn__).toBe(fn);\n    expect(result.fn.__originalFn__.__originalFn__).not.toBeDefined();\n  });\n\n  it('does not traverse into arrays', () => {\n    const fn1: any = () => {};\n    const fn2: any = () => {};\n    const result = instrument({ arr: [fn1, { fn2 }] });\n    expect(result).toStrictEqual({ arr: [fn1, { fn2 }] });\n    expect(result.arr[0].__originalFn__).not.toBeDefined();\n    expect(result.arr[1].fn2.__originalFn__).not.toBeDefined();\n  });\n\n  it('patches function properties on functions', () => {\n    const fn1: any = () => {};\n    fn1.fn2 = () => {};\n    const result = instrument({ fn1 });\n    expect(result.fn1).toEqual(expect.any(Function));\n    expect(result.fn1.fn2).toEqual(expect.any(Function));\n    expect(result.fn1.__originalFn__).toBe(fn1);\n    expect(result.fn1.fn2.__originalFn__).toBe(fn1.fn2);\n  });\n\n  it('patches functions correctly that reference this', () => {\n    const object = {\n      name: 'name',\n      method() {\n        return this.name;\n      },\n    };\n\n    const instrumented = instrument(object);\n    expect(object.method()).toEqual(instrumented.method());\n\n    expect(instrumented.method).toEqual(expect.any(Function));\n    expect(instrumented.method.__originalFn__).toBe(object.method);\n  });\n\n  it('patches functions correctly that use proxies', () => {\n    const object = new Proxy(\n      {\n        name: 'name',\n        method() {\n          return this.name;\n        },\n      },\n      {\n        get(target, prop, receiver) {\n          if (prop === 'name') {\n            return `${target[prop]}!`;\n          }\n          return Reflect.get(target, prop, receiver);\n        },\n      }\n    );\n\n    const instrumented = instrument(object);\n    expect(object.method()).toEqual(instrumented.method());\n\n    expect(instrumented.method).toEqual(expect.any(Function));\n    expect(instrumented.method.__originalFn__).toBe(object.method);\n  });\n\n  it('patched functions call the original function when invoked', () => {\n    const { fn } = instrument({ fn: vi.fn() });\n    const obj = {};\n    fn('foo', obj);\n    expect(fn.__originalFn__).toHaveBeenCalledWith('foo', obj);\n  });\n\n  it('emits a \"call\" event every time a patched function is invoked', async () => {\n    const { fn } = instrument({ fn: (...args: any) => {} });\n\n    fn('foo', 'bar');\n    fn('baz');\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({\n        id: 'kind--story [0] fn',\n        args: ['foo', 'bar'],\n      })\n    );\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({\n        id: 'kind--story [1] fn',\n        args: ['baz'],\n      })\n    );\n  });\n\n  it('handles circular references', () => {\n    const { fn } = instrument({ fn: (...args: any) => {} });\n    const obj = { key: 'value', obj: {}, array: [] as any[] };\n    obj.obj = obj;\n    obj.array = [obj];\n\n    expect(() => fn(obj)).not.toThrow();\n\n    expect(mocks.callSpy.mock.calls[0][0].args).toMatchInlineSnapshot(`\n      [\n        {\n          \"array\": [\n            \"[Circular]\",\n          ],\n          \"key\": \"value\",\n          \"obj\": \"[Circular]\",\n        },\n      ]\n    `);\n  });\n\n  it('provides metadata about the call in the event', () => {\n    const { obj } = instrument({ obj: { fn: () => {} } });\n    obj.fn();\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({\n        path: ['obj'],\n        method: 'fn',\n        interceptable: false,\n        status: 'done',\n        ancestors: [],\n      })\n    );\n  });\n\n  it('maps event args which originate from an earlier call to a call ref', () => {\n    const { fn1, fn2 } = instrument({\n      fn1: (arg: any) => arg,\n      fn2: (arg: any) => {},\n    });\n    fn2(fn1({}));\n    expect(mocks.callSpy).toHaveBeenLastCalledWith(\n      expect.objectContaining({\n        method: 'fn2',\n        args: [{ __callId__: mocks.callSpy.mock.calls[0][0].id, retain: false }],\n      })\n    );\n  });\n\n  it('does not map primitive event args which originate from an earlier call', () => {\n    const { fn1, fn2 } = instrument({\n      fn1: (...args: any) => args[0],\n      fn2: (...args: any) => {},\n    });\n    fn2(\n      fn1(undefined),\n      fn1(null),\n      fn1(true),\n      fn1('foo'),\n      fn1(1),\n      fn1(BigInt(1)),\n      fn1({}),\n      fn1([]),\n      fn1(() => {}),\n      fn1(Symbol('hi')),\n      fn1(new Error('Oops'))\n    );\n    expect(mocks.callSpy).toHaveBeenLastCalledWith(\n      expect.objectContaining({\n        method: 'fn2',\n        args: [\n          /* call 0 */ undefined,\n          /* call 1 */ null,\n          /* call 2 */ true,\n          /* call 3 */ 'foo',\n          /* call 4 */ 1,\n          /* call 5 */ BigInt(1),\n          { __callId__: mocks.callSpy.mock.calls[6][0].id, retain: false },\n          { __callId__: mocks.callSpy.mock.calls[7][0].id, retain: false },\n          { __callId__: mocks.callSpy.mock.calls[8][0].id, retain: false },\n          { __callId__: mocks.callSpy.mock.calls[9][0].id, retain: false },\n          { __callId__: mocks.callSpy.mock.calls[10][0].id, retain: false },\n        ],\n      })\n    );\n  });\n\n  it('maps HTML Elements in event args to an element ref', () => {\n    const { fn } = instrument({ fn: (...args: any) => {} });\n    fn(new HTMLElement({ prefix: '', localName: 'div', id: 'root', classList: [] }));\n    expect(mocks.callSpy).toHaveBeenLastCalledWith(\n      expect.objectContaining({\n        args: [{ __element__: { prefix: '', localName: 'div', id: 'root', classNames: [] } }],\n      })\n    );\n  });\n\n  it('tracks the parent call id for calls inside callbacks', () => {\n    const fn = (callback?: Function) => callback && callback();\n    const { fn1, fn2, fn3, fn4, fn5 } = instrument({ fn1: fn, fn2: fn, fn3: fn, fn4: fn, fn5: fn });\n    fn1(() => {\n      fn2(() => fn3());\n      fn4();\n    });\n    fn5();\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({ id: 'kind--story [0] fn1', ancestors: [] })\n    );\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({\n        id: 'kind--story [0] fn1 [0] fn2',\n        ancestors: ['kind--story [0] fn1'],\n      })\n    );\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({\n        id: 'kind--story [0] fn1 [0] fn2 [0] fn3',\n        ancestors: ['kind--story [0] fn1', 'kind--story [0] fn1 [0] fn2'],\n      })\n    );\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({\n        id: 'kind--story [0] fn1 [1] fn4',\n        ancestors: ['kind--story [0] fn1'],\n      })\n    );\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({ id: 'kind--story [1] fn5', ancestors: [] })\n    );\n  });\n\n  it('handles exceptions when making calls inside callbacks', () => {\n    const fn = (callback?: Function) => callback && callback();\n    const { fn1, fn2, fn3 } = instrument({\n      fn1: fn,\n      fn2: fn,\n      fn3: fn,\n    });\n    const error = new Error('foo');\n    let thrownError;\n    fn1(() => {\n      try {\n        fn2(() => {\n          throw error;\n        });\n      } catch (err) {\n        thrownError = err;\n      }\n      fn3();\n    });\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({ id: 'kind--story [0] fn1', ancestors: [] })\n    );\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({\n        id: 'kind--story [0] fn1 [0] fn2',\n        ancestors: ['kind--story [0] fn1'],\n      })\n    );\n    expect(thrownError).toBe(error);\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({\n        id: 'kind--story [0] fn1 [1] fn3',\n        ancestors: ['kind--story [0] fn1'],\n      })\n    );\n  });\n\n  it('tracks the parent call id for async callbacks', async () => {\n    const fn = (callback?: Function) => Promise.resolve(callback && callback());\n    const { fn1, fn2, fn3 } = instrument({ fn1: fn, fn2: fn, fn3: fn });\n    await fn1(() => fn2());\n    await fn3();\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({ id: 'kind--story [0] fn1', ancestors: [] })\n    );\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({\n        id: 'kind--story [0] fn1 [0] fn2',\n        ancestors: ['kind--story [0] fn1'],\n      })\n    );\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({ id: 'kind--story [1] fn3', ancestors: [] })\n    );\n  });\n\n  it('does not nest calls after an interceptable step into that step', async () => {\n    // Simulate the step function (intercept: true, async, takes a callback)\n    const { step } = instrument(\n      {\n        step: async (label: string, play: Function) => play(),\n      },\n      { intercept: true }\n    );\n\n    // Simulate waitFor (intercept: true, takes a callback, calls it synchronously)\n    const { waitFor } = instrument(\n      {\n        waitFor: (callback: Function) => callback(),\n      },\n      { intercept: true }\n    );\n\n    // Simulate an inner instrumented function (like expect().toHaveBeenCalledWith())\n    const { fn1, fn2 } = instrument({ fn1: () => {}, fn2: () => {} });\n\n    setRenderPhase('playing');\n\n    // step(\"label\", async () => { fn1() })\n    await step('label', async () => {\n      fn1();\n    });\n\n    // waitFor(() => { fn2() }) — should NOT be nested inside step\n    waitFor(() => {\n      fn2();\n    });\n\n    // step itself should have ancestors: []\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({ method: 'step', ancestors: [] })\n    );\n    // fn1 inside step callback should have ancestors: [step_id]\n    const stepCall = mocks.callSpy.mock.calls.find((c: any) => c[0].method === 'step');\n    const stepCallId = stepCall![0].id;\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({ method: 'fn1', ancestors: [stepCallId] })\n    );\n    // waitFor should have ancestors: [] (NOT nested inside step)\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({ method: 'waitFor', ancestors: [] })\n    );\n    // fn2 inside waitFor callback should have ancestors: [waitFor_id] only\n    const waitForCall = mocks.callSpy.mock.calls.find((c: any) => c[0].method === 'waitFor');\n    const waitForCallId = waitForCall![0].id;\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({ method: 'fn2', ancestors: [waitForCallId] })\n    );\n  });\n\n  it('instruments the call result to support chaining', () => {\n    const { fn1 } = instrument({\n      fn1: () => ({\n        fn2: () => {},\n      }),\n    });\n    fn1().fn2();\n    expect(mocks.callSpy).toHaveBeenLastCalledWith(\n      expect.objectContaining({\n        method: 'fn2',\n        path: [{ __callId__: mocks.callSpy.mock.calls[0][0].id }],\n      })\n    );\n  });\n\n  it('handles exceptions when making calls inside async callbacks', async () => {\n    const fn = (callback?: Function) => Promise.resolve(callback && callback());\n    const { fn1, fn2, fn3 } = instrument({\n      fn1: fn,\n      fn2: fn,\n      fn3: fn,\n    });\n    const error = new Error('foo');\n    let thrownError;\n    await fn1(async () => {\n      try {\n        await fn2(async () => {\n          throw error;\n        });\n      } catch (err) {\n        thrownError = err;\n      }\n      await fn3();\n    });\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({ id: 'kind--story [0] fn1', ancestors: [] })\n    );\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({\n        id: 'kind--story [0] fn1 [0] fn2',\n        ancestors: ['kind--story [0] fn1'],\n      })\n    );\n    expect(thrownError).toBe(error);\n    expect(mocks.callSpy).toHaveBeenCalledWith(\n      expect.objectContaining({\n        id: 'kind--story [0] fn1 [1] fn3',\n        ancestors: ['kind--story [0] fn1'],\n      })\n    );\n  });\n\n  it('emits a \"sync\" event with debounce after a patched function is invoked', () => {\n    const { fn } = instrument({ fn: (...args: any) => {} }, { intercept: true });\n    vi.useFakeTimers();\n    mocks.syncSpy.mockClear();\n    fn('foo');\n    fn('bar');\n    vi.runAllTimers();\n    expect(mocks.syncSpy).toHaveBeenCalledTimes(1);\n  });\n\n  it('sends a folded log with the \"sync\" event', () => {\n    const { fn } = instrument({ fn: (...args: any) => ({ fn2: () => {} }) }, { intercept: true });\n    vi.useFakeTimers();\n    mocks.syncSpy.mockClear();\n    fn('foo', fn('bar')).fn2();\n    fn('baz');\n    vi.runAllTimers();\n    expect(mocks.syncSpy).toHaveBeenCalledWith(\n      expect.objectContaining({\n        logItems: [\n          { callId: 'kind--story [2] fn2', status: 'done', ancestors: [] },\n          { callId: 'kind--story [3] fn', status: 'done', ancestors: [] },\n        ],\n      })\n    );\n  });\n\n  it('sends control states with the \"sync\" event', () => {\n    const { fn } = instrument({ fn: (...args: any) => {} }, { intercept: true });\n    vi.useFakeTimers();\n    mocks.syncSpy.mockClear();\n    fn('foo');\n    vi.runAllTimers();\n    expect(mocks.syncSpy).toHaveBeenCalledWith(\n      expect.objectContaining({\n        controlStates: {\n          detached: false,\n          start: true,\n          back: true,\n          goto: true,\n          next: false,\n          end: false,\n        },\n      })\n    );\n  });\n\n  it('rethrows errors', () => {\n    const { fn } = instrument({\n      fn: () => {\n        throw new Error('Boom!');\n      },\n    });\n    expect(fn).toThrow('Boom!');\n  });\n\n  it('catches nested exceptions and rethrows', () => {\n    const { fn1, fn2 } = instrument({\n      fn1: (_: any) => {},\n      fn2: () => {\n        throw new Error('Boom!');\n      },\n    });\n    expect(() => fn1(fn2())).toThrow('Boom!');\n  });\n\n  it('bubbles child exceptions up to parent (in callback)', () => {\n    const instrumented = instrument({\n      fn1: vi.fn((callback: Function) => callback()),\n      fn2: () => {\n        throw new Error('Boom!');\n      },\n    });\n\n    vi.spyOn(instrumented, 'fn1');\n\n    const { fn1, fn2 } = instrumented;\n    let error;\n    try {\n      fn1(() => {\n        fn2();\n      });\n    } catch (e) {\n      error = e;\n    }\n\n    expect(fn1).toHaveBeenCalled();\n    expect(error).toEqual(new Error('Boom!'));\n    // @ts-expect-error callId is what is tested\n    expect(error.callId).toBe('kind--story [0] fn1 [0] fn2');\n  });\n\n  it(\"re-throws anything that isn't an error\", () => {\n    const { fn } = instrument({\n      fn: () => {\n        throw 'Boom!';\n      },\n    });\n    expect(fn).toThrow('Boom!');\n    expect(mocks.callSpy).not.toHaveBeenCalled();\n  });\n\n  it('does not affect intercepted methods', () => {\n    const { fn } = instrument({ fn: vi.fn() }, { intercept: true });\n    fn('foo');\n    expect(fn.__originalFn__).toHaveBeenCalledWith('foo');\n  });\n\n  it('clears state when switching stories', () => {\n    addons.getChannel().emit(SET_CURRENT_STORY); // initialization\n    instrumenter.state = {\n      'kind--story': {\n        isDebugging: false,\n        cursor: 123,\n        calls: [{ id: 'kind--story [0] fn' }],\n        shadowCalls: [{ id: 'kind--story [0] fn' }, { id: 'kind--story [1] fn' }],\n        callRefsByResult: new Map([[{}, 'ref']]),\n        chainedCallIds: new Set(['kind--story [0] fn']),\n        parentCall: { id: 'kind--story [0] fn' },\n        playUntil: 'kind--story [1] fn',\n        resolvers: { ref: () => {} },\n        syncTimeout: 123,\n        forwardedException: new Error('Oops'),\n      },\n    } as any;\n    addons.getChannel().emit(SET_CURRENT_STORY);\n    expect(instrumenter.state).toStrictEqual({});\n  });\n\n  describe('with intercept: true', () => {\n    const options = { intercept: true };\n\n    it('only includes intercepted calls in the log', async () => {\n      const fn = (callback?: Function) => callback && callback();\n      const { fn1, fn2 } = instrument({ fn1: fn, fn2: fn }, options);\n      const { fn3 } = instrument({ fn3: fn }, { intercept: false });\n      fn1();\n      fn2();\n      fn3();\n      await tick();\n      expect(mocks.syncSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          logItems: [\n            { callId: 'kind--story [0] fn1', status: 'done', ancestors: [] },\n            { callId: 'kind--story [1] fn2', status: 'done', ancestors: [] },\n          ],\n        })\n      );\n    });\n\n    it('also includes child calls in the log', async () => {\n      const fn = (callback?: Function) => callback && callback();\n      const { fn1, fn2 } = instrument({ fn1: fn, fn2: fn }, options);\n      fn1(() => {\n        fn2();\n      });\n      await tick();\n      expect(mocks.syncSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          logItems: [\n            { callId: 'kind--story [0] fn1', status: 'done', ancestors: [] },\n            {\n              callId: 'kind--story [0] fn1 [0] fn2',\n              status: 'done',\n              ancestors: ['kind--story [0] fn1'],\n            },\n          ],\n        })\n      );\n    });\n\n    it('emits a call event with error data when the function throws', () => {\n      const { fn } = instrument(\n        {\n          fn: () => {\n            throw new Error('Boom!');\n          },\n        },\n        options\n      );\n      expect(fn).toThrow();\n      expect(mocks.callSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          id: 'kind--story [0] fn',\n          exception: expect.objectContaining({\n            name: 'Error',\n            message: 'Boom!',\n            stack: expect.stringContaining('Error: Boom!'),\n            callId: 'kind--story [0] fn',\n          }),\n        })\n      );\n    });\n  });\n\n  describe('while debugging', () => {\n    afterEach(() => {\n      addons.getChannel().emit(EVENTS.END, { storyId });\n    });\n\n    it('remounts on the \"start\" event', async () => {\n      addons.getChannel().emit(EVENTS.START, { storyId });\n      expect(mocks.forceRemountSpy).toHaveBeenCalled();\n    });\n\n    it('defers calls to intercepted functions', () => {\n      const { fn } = instrument({ fn: vi.fn() }, { intercept: true });\n      addons.getChannel().emit(EVENTS.START, { storyId });\n      expect(fn()).toEqual(expect.any(Promise));\n      expect(fn.__originalFn__).not.toHaveBeenCalled();\n    });\n\n    it('does not defer calls to non-intercepted functions', () => {\n      const { fn } = instrument({ fn: vi.fn(() => 'ok') });\n      addons.getChannel().emit(EVENTS.START, { storyId });\n      expect(fn()).toBe('ok');\n      expect(fn.__originalFn__).toHaveBeenCalled();\n    });\n\n    it('does not defer calls to intercepted functions that are chained upon', () => {\n      const { fn1 } = instrument(\n        { fn1: vi.fn(() => ({ fn2: vi.fn() as any })) },\n        { intercept: true }\n      );\n      fn1().fn2();\n      addons.getChannel().emit(EVENTS.START, { storyId });\n      const res1 = fn1();\n      expect(res1.fn2()).toEqual(expect.any(Promise));\n      expect(fn1.__originalFn__).toHaveBeenCalledTimes(2);\n      expect(res1.fn2.__originalFn__).not.toHaveBeenCalled();\n    });\n\n    it.skip('starts debugging at the first non-nested interceptable call', () => {\n      const fn = (...args: any[]) => args;\n      const { fn1, fn2, fn3 } = instrument({ fn1: fn, fn2: fn, fn3: fn }, { intercept: true });\n      fn3(fn1(), fn2()); // setup the dependencies\n      addons.getChannel().emit(EVENTS.START, { storyId });\n      const a = fn1('a');\n      const b = fn2('b');\n      const c = fn3(a, b);\n      expect(a).toEqual(['a']);\n      expect(b).toEqual(['b']);\n      expect(c).toEqual(expect.any(Promise));\n    });\n\n    it('steps through each interceptable function on \"next\"', async () => {\n      const fn = vi.fn(async () => {});\n      const { fn: instrumentedFn } = instrument(\n        {\n          fn: async () => fn(),\n        },\n        { intercept: true }\n      );\n\n      const mockedInstrumentedFn = vi.fn(instrumentedFn);\n      const play = async () => {\n        await mockedInstrumentedFn();\n        await mockedInstrumentedFn();\n        await mockedInstrumentedFn();\n      };\n\n      await play();\n      fn.mockClear();\n      mockedInstrumentedFn.mockClear();\n\n      addons.getChannel().emit(EVENTS.START, { storyId });\n\n      const p = play();\n      expect(mockedInstrumentedFn).toHaveBeenCalledTimes(1);\n      expect(fn).toHaveBeenCalledTimes(0);\n\n      addons.getChannel().emit(EVENTS.NEXT, { storyId });\n      await tick();\n\n      expect(mockedInstrumentedFn).toHaveBeenCalledTimes(2);\n      expect(fn).toHaveBeenCalledTimes(1);\n\n      addons.getChannel().emit(EVENTS.END, { storyId });\n      await tick();\n\n      expect(mockedInstrumentedFn).toHaveBeenCalledTimes(3);\n      expect(fn).toHaveBeenCalledTimes(3);\n\n      await p;\n    });\n  });\n\n  describe('while detached from parent window', () => {\n    beforeEach(() => {\n      global.window.parent = {\n        ...global.window.parent,\n        get __STORYBOOK_ADDON_INTERACTIONS_INSTRUMENTER_STATE__() {\n          throw new Error('Blocked');\n        },\n        set __STORYBOOK_ADDON_INTERACTIONS_INSTRUMENTER_STATE__(_: unknown) {},\n      };\n      instrumenter = new Instrumenter();\n    });\n\n    it('disables control states', async () => {\n      const { fn } = instrument({ fn: (...args: any) => {} }, { intercept: true });\n      vi.useFakeTimers();\n      mocks.syncSpy.mockClear();\n      fn('foo');\n      vi.runAllTimers();\n\n      expect(mocks.syncSpy).toHaveBeenLastCalledWith(\n        expect.objectContaining({\n          controlStates: {\n            detached: true,\n            start: false,\n            back: false,\n            goto: false,\n            next: false,\n            end: false,\n          },\n        })\n      );\n    });\n  });\n\n  describe('isClass', () => {\n    it('returns true for class declarations', () => {\n      class TestClass {}\n      expect(isClass(TestClass)).toBe(true);\n    });\n\n    it('returns true for class expressions', () => {\n      const TestClass = class {};\n      expect(isClass(TestClass)).toBe(true);\n    });\n\n    it('returns false for regular functions', () => {\n      function testFunction() {}\n      expect(isClass(testFunction)).toBe(false);\n    });\n\n    it('returns false for arrow functions', () => {\n      const arrowFunction = () => {};\n      expect(isClass(arrowFunction)).toBe(false);\n    });\n\n    it('returns false for function expressions', () => {\n      const functionExpression = function () {};\n      expect(isClass(functionExpression)).toBe(false);\n    });\n\n    it('returns false for functions without prototype', () => {\n      expect(isClass(Promise.resolve)).toBe(false);\n    });\n\n    it('returns false for method shorthand', () => {\n      expect(isClass({ method() {} })).toBe(false);\n    });\n\n    it('returns false for non-function values', () => {\n      expect(isClass(null)).toBe(false);\n      expect(isClass(undefined)).toBe(false);\n      expect(isClass(123)).toBe(false);\n      expect(isClass('string')).toBe(false);\n      expect(isClass({})).toBe(false);\n      expect(isClass([])).toBe(false);\n      expect(isClass(true)).toBe(false);\n      expect(isClass(Symbol('test'))).toBe(false);\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/instrumenter/instrumenter.ts",
    "content": "import type { Channel } from 'storybook/internal/channels';\nimport { once } from 'storybook/internal/client-logger';\nimport {\n  FORCE_REMOUNT,\n  SET_CURRENT_STORY,\n  STORY_RENDER_PHASE_CHANGED,\n} from 'storybook/internal/core-events';\nimport type { StoryId } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { processError } from '@vitest/utils/error';\n\nimport { EVENTS } from './EVENTS.ts';\nimport { addons } from './preview-api.ts';\nimport type {\n  Call,\n  CallRef,\n  ControlStates,\n  LogItem,\n  Options,\n  RenderPhase,\n  State,\n  SyncPayload,\n} from './types.ts';\nimport { CallStates } from './types.ts';\nimport './typings.d.ts';\n\ntype PatchedObj<TObj extends Record<string, unknown>> = {\n  [Property in keyof TObj]: TObj[Property] & { __originalFn__: TObj[Property] };\n};\n\nconst alreadyCompletedException = new Error(\n  `This function ran after the play function completed. Did you forget to \\`await\\` it?`\n);\n\nconst isObject = (o: unknown): o is object =>\n  Object.prototype.toString.call(o) === '[object Object]';\nconst isModule = (o: unknown): o is NodeModule =>\n  Object.prototype.toString.call(o) === '[object Module]';\nconst isInstrumentable = (o: unknown) => {\n  if (!isObject(o) && !isModule(o)) {\n    return false;\n  }\n\n  if (o.constructor === undefined) {\n    return true;\n  }\n  const proto = o.constructor.prototype;\n\n  if (!isObject(proto)) {\n    return false;\n  }\n  return true;\n};\n\nconst construct = (obj: any) => {\n  try {\n    return new obj.constructor();\n  } catch {\n    return {};\n  }\n};\n\nconst getInitialState = (): State => ({\n  renderPhase: 'preparing',\n  isDebugging: false,\n  isPlaying: false,\n  isLocked: false,\n  cursor: 0,\n  calls: [],\n  shadowCalls: [],\n  callRefsByResult: new Map(),\n  chainedCallIds: new Set<Call['id']>(),\n  ancestors: [],\n  playUntil: undefined,\n  resolvers: {},\n  syncTimeout: undefined,\n});\n\nconst getRetainedState = (state: State, isDebugging = false) => {\n  const calls = (isDebugging ? state.shadowCalls : state.calls).filter((call) => call.retain);\n\n  if (!calls.length) {\n    return undefined;\n  }\n  const callRefsByResult = new Map(\n    Array.from(state.callRefsByResult.entries()).filter(([, ref]) => ref.retain)\n  );\n  return { cursor: calls.length, calls, callRefsByResult };\n};\n\n/** This class is not supposed to be used directly. Use the `instrument` function below instead. */\nexport class Instrumenter {\n  channel: Channel | undefined;\n\n  detached = false;\n  initialized = false;\n\n  // State is tracked per story to deal with multiple stories on the same canvas (i.e. docs mode)\n  state: Record<StoryId, State> = {};\n\n  constructor() {\n    // Restore state from the parent window in case the iframe was reloaded.\n    this.loadParentWindowState();\n\n    // When called from `start`, isDebugging will be true.\n    const resetState = ({\n      storyId,\n      renderPhase,\n      isPlaying = true,\n      isDebugging = false,\n    }: {\n      storyId: StoryId;\n      renderPhase?: RenderPhase;\n      isPlaying?: boolean;\n      isDebugging?: boolean;\n    }) => {\n      const state = this.getState(storyId);\n      this.setState(storyId, {\n        ...getInitialState(),\n        ...getRetainedState(state, isDebugging),\n        renderPhase: renderPhase || state.renderPhase,\n        shadowCalls: isDebugging ? state.shadowCalls : [],\n        chainedCallIds: isDebugging ? state.chainedCallIds : new Set<Call['id']>(),\n        playUntil: isDebugging ? state.playUntil : undefined,\n        isPlaying,\n        isDebugging,\n      });\n      this.sync(storyId);\n    };\n\n    const start =\n      (channel: Channel) =>\n      ({ storyId, playUntil }: { storyId: string; playUntil?: Call['id'] }) => {\n        if (!this.getState(storyId).isDebugging) {\n          // Move everything into shadowCalls (a \"carbon copy\") and mark them as \"waiting\", so we keep\n          // a record of the original calls which haven't yet been executed while stepping through.\n          this.setState(storyId, ({ calls }) => ({\n            calls: [],\n            shadowCalls: calls.map((call) => ({ ...call, status: CallStates.WAITING })),\n            isDebugging: true,\n          }));\n        }\n\n        const log = this.getLog(storyId);\n        this.setState(storyId, ({ shadowCalls }) => {\n          if (playUntil || !log.length) {\n            return { playUntil };\n          }\n          const firstRowIndex = shadowCalls.findIndex((call) => call.id === log[0].callId);\n          return {\n            playUntil: shadowCalls\n              .slice(0, firstRowIndex)\n              .filter((call) => call.interceptable && !call.ancestors?.length)\n              .slice(-1)[0]?.id,\n          };\n        });\n\n        // Force remount may trigger a page reload if the play function can't be aborted.\n        channel.emit(FORCE_REMOUNT, { storyId, isDebugging: true });\n      };\n\n    const back =\n      (channel: Channel) =>\n      ({ storyId }: { storyId: string }) => {\n        const log = this.getLog(storyId).filter((call) => !call.ancestors?.length);\n        const last = log.reduceRight((res, item, index) => {\n          if (res >= 0 || item.status === CallStates.WAITING) {\n            return res;\n          }\n          return index;\n        }, -1);\n        start(channel)({ storyId, playUntil: log[last - 1]?.callId });\n      };\n\n    const goto =\n      (channel: Channel) =>\n      ({ storyId, callId }: { storyId: string; callId: Call['id'] }) => {\n        const { calls, shadowCalls, resolvers } = this.getState(storyId);\n        const call = calls.find(({ id }) => id === callId);\n        const shadowCall = shadowCalls.find(({ id }) => id === callId);\n        if (!call && shadowCall && Object.values(resolvers).length > 0) {\n          const nextId = this.getLog(storyId).find((c) => c.status === CallStates.WAITING)?.callId;\n\n          if (shadowCall.id !== nextId) {\n            this.setState(storyId, { playUntil: shadowCall.id });\n          }\n          Object.values(resolvers).forEach((resolve) => resolve());\n        } else {\n          start(channel)({ storyId, playUntil: callId });\n        }\n      };\n\n    const next =\n      (channel: Channel) =>\n      ({ storyId }: { storyId: string }) => {\n        const { resolvers } = this.getState(storyId);\n        if (Object.values(resolvers).length > 0) {\n          Object.values(resolvers).forEach((resolve) => resolve());\n        } else {\n          const nextId = this.getLog(storyId).find((c) => c.status === CallStates.WAITING)?.callId;\n\n          if (nextId) {\n            start(channel)({ storyId, playUntil: nextId });\n          } else {\n            end({ storyId });\n          }\n        }\n      };\n\n    const end = ({ storyId }: { storyId: string }) => {\n      this.setState(storyId, { playUntil: undefined, isDebugging: false });\n      Object.values(this.getState(storyId).resolvers).forEach((resolve) => resolve());\n    };\n\n    const renderPhaseChanged = ({\n      storyId,\n      newPhase,\n    }: {\n      storyId: string;\n      newPhase: RenderPhase;\n    }) => {\n      const { isDebugging } = this.getState(storyId);\n      if (newPhase === 'preparing' && isDebugging) {\n        return resetState({ storyId, renderPhase: newPhase, isDebugging });\n      } else if (newPhase === 'playing') {\n        return resetState({ storyId, renderPhase: newPhase, isDebugging });\n      }\n\n      if (newPhase === 'played') {\n        this.setState(storyId, {\n          renderPhase: newPhase,\n          isLocked: false,\n          isPlaying: false,\n          isDebugging: false,\n        });\n      } else if (newPhase === 'errored') {\n        this.setState(storyId, {\n          renderPhase: newPhase,\n          isLocked: false,\n          isPlaying: false,\n        });\n      } else if (newPhase === 'aborted') {\n        this.setState(storyId, {\n          renderPhase: newPhase,\n          isLocked: true,\n          isPlaying: false,\n        });\n      } else {\n        this.setState(storyId, {\n          renderPhase: newPhase,\n        });\n      }\n\n      this.sync(storyId);\n    };\n\n    // Support portable stories where addons are not available\n    if (addons) {\n      addons.ready().then(() => {\n        this.channel = addons.getChannel();\n\n        // A forceRemount might be triggered for debugging (on `start`), or elsewhere in Storybook.\n        this.channel.on(FORCE_REMOUNT, resetState);\n\n        // Start with a clean slate before playing after a remount, and stop debugging when done.\n        this.channel.on(STORY_RENDER_PHASE_CHANGED, renderPhaseChanged);\n\n        // Trash non-retained state and clear the log when switching stories, but not on initial boot.\n        this.channel.on(SET_CURRENT_STORY, () => {\n          if (this.initialized) {\n            this.cleanup();\n          } else {\n            this.initialized = true;\n          }\n        });\n\n        this.channel.on(EVENTS.START, start(this.channel));\n        this.channel.on(EVENTS.BACK, back(this.channel));\n        this.channel.on(EVENTS.GOTO, goto(this.channel));\n        this.channel.on(EVENTS.NEXT, next(this.channel));\n        this.channel.on(EVENTS.END, end);\n      });\n    }\n  }\n\n  loadParentWindowState = () => {\n    try {\n      this.state = global.window?.parent?.__STORYBOOK_ADDON_INTERACTIONS_INSTRUMENTER_STATE__ || {};\n    } catch {\n      // This happens when window.parent is not on the same origin (e.g. for a composed storybook)\n      this.detached = true;\n    }\n  };\n\n  updateParentWindowState = () => {\n    try {\n      global.window.parent.__STORYBOOK_ADDON_INTERACTIONS_INSTRUMENTER_STATE__ = this.state;\n    } catch {\n      // This happens when window.parent is not on the same origin (e.g. for a composed storybook)\n      this.detached = true;\n    }\n  };\n\n  getState(storyId: StoryId) {\n    return this.state[storyId] || getInitialState();\n  }\n\n  setState(storyId: StoryId, update: Partial<State> | ((state: State) => Partial<State>)) {\n    if (storyId) {\n      const state = this.getState(storyId);\n      const patch = typeof update === 'function' ? update(state) : update;\n      this.state = { ...this.state, [storyId]: { ...state, ...patch } };\n      // Track state on the parent window so we can reload the iframe without losing state.\n      this.updateParentWindowState();\n    }\n  }\n\n  cleanup() {\n    // Reset stories with retained state to their initial state, and drop the rest.\n    this.state = Object.entries(this.state).reduce(\n      (acc, [storyId, state]) => {\n        const retainedState = getRetainedState(state);\n\n        if (!retainedState) {\n          return acc;\n        }\n        acc[storyId] = Object.assign(getInitialState(), retainedState);\n        return acc;\n      },\n      {} as Record<StoryId, State>\n    );\n    const controlStates: ControlStates = {\n      detached: this.detached,\n      start: false,\n      back: false,\n      goto: false,\n      next: false,\n      end: false,\n    };\n    const payload: SyncPayload = { controlStates, logItems: [] };\n    this.channel?.emit(EVENTS.SYNC, payload);\n    this.updateParentWindowState();\n  }\n\n  getLog(storyId: string): LogItem[] {\n    const { calls, shadowCalls } = this.getState(storyId);\n    const merged = [...shadowCalls];\n    calls.forEach((call, index) => {\n      merged[index] = call;\n    });\n\n    const seen = new Set();\n    return merged.reduceRight<LogItem[]>((acc, call) => {\n      call.args.forEach((arg) => {\n        if (arg?.__callId__) {\n          seen.add(arg.__callId__);\n        }\n      });\n      call.path.forEach((node) => {\n        if ((node as CallRef).__callId__) {\n          seen.add((node as CallRef).__callId__);\n        }\n      });\n      if ((call.interceptable || call.exception) && !seen.has(call.id)) {\n        acc.unshift({ callId: call.id, status: call.status, ancestors: call.ancestors });\n        seen.add(call.id);\n      }\n      return acc;\n    }, []);\n  }\n\n  // Traverses the object structure to recursively patch all function properties.\n  // Returns the original object, or a new object with the same constructor,\n  // depending on whether it should mutate.\n  instrument<TObj extends Record<string, unknown>>(\n    obj: TObj,\n    options: Options,\n    depth = 0\n  ): PatchedObj<TObj> {\n    if (!isInstrumentable(obj)) {\n      return obj as PatchedObj<TObj>;\n    }\n\n    const { mutate = false, path = [] } = options;\n\n    const keys = options.getKeys ? options.getKeys(obj, depth) : Object.keys(obj);\n    depth += 1;\n    return keys.reduce(\n      (acc, key) => {\n        const descriptor = getPropertyDescriptor(obj, key);\n        if (typeof descriptor?.get === 'function') {\n          if (descriptor.configurable) {\n            const getter = () => descriptor?.get?.bind(obj)?.();\n            Object.defineProperty(acc, key, {\n              get: () => {\n                return this.instrument(getter(), { ...options, path: path.concat(key) }, depth);\n              },\n            });\n          }\n          return acc;\n        }\n\n        const value = (obj as Record<string, any>)[key];\n\n        // Nothing to patch, but might be instrumentable, so we recurse\n        if (typeof value !== 'function') {\n          acc[key] = this.instrument(value, { ...options, path: path.concat(key) }, depth);\n          return acc;\n        }\n\n        // Already patched, so we pass through unchanged\n        if ('__originalFn__' in value && typeof value.__originalFn__ === 'function') {\n          acc[key] = value;\n          return acc;\n        }\n\n        // Patch the function and mark it \"patched\" by adding a reference to the original function\n        acc[key] = (...args: any[]) => this.track(key, value, obj, args, options);\n        acc[key].__originalFn__ = value;\n\n        // Reuse the original name as the patched function's name\n        Object.defineProperty(acc[key], 'name', { value: key, writable: false });\n\n        // Deal with functions that also act like an object\n        if (Object.keys(value).length > 0) {\n          Object.assign(\n            acc[key],\n            this.instrument({ ...value }, { ...options, path: path.concat(key) }, depth)\n          );\n        }\n\n        return acc;\n      },\n      mutate ? obj : construct(obj)\n    );\n  }\n\n  // Monkey patch an object method to record calls.\n  // Returns a function that invokes the original function, records the invocation (\"call\") and\n  // returns the original result.\n  track(\n    method: string,\n    fn: Function,\n    object: Record<string, unknown>,\n    args: any[],\n    options: Options\n  ) {\n    const storyId: StoryId =\n      args?.[0]?.__storyId__ || global.__STORYBOOK_PREVIEW__?.selectionStore?.selection?.storyId;\n    const { cursor, ancestors } = this.getState(storyId);\n    this.setState(storyId, { cursor: cursor + 1 });\n    const id = `${ancestors.slice(-1)[0] || storyId} [${cursor}] ${method}`;\n    const { path = [], intercept = false, retain = false } = options;\n    const interceptable = typeof intercept === 'function' ? intercept(method, path) : intercept;\n    const call = { id, cursor, storyId, ancestors, path, method, args, interceptable, retain };\n    const interceptOrInvoke = interceptable && !ancestors.length ? this.intercept : this.invoke;\n    const result = interceptOrInvoke.call(this, fn, object, call, options);\n    return this.instrument(result, { ...options, mutate: true, path: [{ __callId__: call.id }] });\n  }\n\n  intercept(fn: Function, object: Record<string, unknown>, call: Call, options: Options) {\n    const { chainedCallIds, isDebugging, playUntil } = this.getState(call.storyId);\n\n    // For a \"jump to step\" action, continue playing until we hit a call by that ID.\n    // For chained calls, we can only return a Promise for the last call in the chain.\n    const isChainedUpon = chainedCallIds.has(call.id);\n    if (!isDebugging || isChainedUpon || playUntil) {\n      if (playUntil === call.id) {\n        this.setState(call.storyId, { playUntil: undefined });\n      }\n      return this.invoke(fn, object, call, options);\n    }\n\n    // Instead of invoking the function, defer the function call until we continue playing.\n    return new Promise((resolve) => {\n      this.setState(call.storyId, ({ resolvers }) => ({\n        isLocked: false,\n        resolvers: { ...resolvers, [call.id]: resolve },\n      }));\n    }).then(() => {\n      this.setState(call.storyId, (state) => {\n        const { [call.id]: _, ...resolvers } = state.resolvers;\n        return { isLocked: true, resolvers };\n      });\n      return this.invoke(fn, object, call, options);\n    });\n  }\n\n  invoke(fn: Function, object: Record<string, unknown>, call: Call, options: Options) {\n    const { callRefsByResult, renderPhase } = this.getState(call.storyId);\n\n    // TODO This function should not needed anymore, as the channel already serializes values with telejson\n    // Possibly we need to add HTMLElement support to telejson though\n    // Keeping this function here, as removing it means we need to refactor the deserializing that happens in core interactions\n    const maximumDepth = 25; // mimicks the max depth of telejson\n    const serializeValues = (value: any, depth: number, seen: unknown[]): any => {\n      if (seen.includes(value)) {\n        return '[Circular]';\n      }\n      seen = [...seen, value];\n\n      if (depth > maximumDepth) {\n        return '...';\n      }\n\n      if (callRefsByResult.has(value)) {\n        return callRefsByResult.get(value);\n      }\n      if (value instanceof Array) {\n        return value.map((it) => serializeValues(it, ++depth, seen));\n      }\n      if (value instanceof Date) {\n        return { __date__: { value: value.toISOString() } };\n      }\n      if (value instanceof Error) {\n        const { name, message, stack } = value;\n        return { __error__: { name, message, stack } };\n      }\n      if (value instanceof RegExp) {\n        const { flags, source } = value;\n        return { __regexp__: { flags, source } };\n      }\n      if (value instanceof global.window?.HTMLElement) {\n        const { prefix, localName, id, classList, innerText } = value;\n        const classNames = Array.from(classList);\n        return { __element__: { prefix, localName, id, classNames, innerText } };\n      }\n      if (typeof value === 'function') {\n        return {\n          __function__: { name: 'getMockName' in value ? value.getMockName() : value.name },\n        };\n      }\n      if (typeof value === 'symbol') {\n        return { __symbol__: { description: value.description } };\n      }\n      if (\n        typeof value === 'object' &&\n        value?.constructor?.name &&\n        value?.constructor?.name !== 'Object'\n      ) {\n        return { __class__: { name: value.constructor.name } };\n      }\n      if (Object.prototype.toString.call(value) === '[object Object]') {\n        return Object.fromEntries(\n          Object.entries(value).map(([key, val]) => [key, serializeValues(val, ++depth, seen)])\n        );\n      }\n      return value;\n    };\n\n    const info: Call = {\n      ...call,\n      args: call.args.map((arg) => serializeValues(arg, 0, [])),\n    };\n\n    // Mark any ancestor calls as \"chained upon\" so we won't attempt to defer it later.\n    call.path.forEach((ref: any) => {\n      if (ref?.__callId__) {\n        this.setState(call.storyId, ({ chainedCallIds }) => ({\n          chainedCallIds: new Set(Array.from(chainedCallIds).concat(ref.__callId__)),\n        }));\n      }\n    });\n\n    const handleException = (e: any) => {\n      if (e instanceof Error) {\n        const { name, message, stack, callId = call.id } = e as Error & { callId: Call['id'] };\n\n        // This will calculate the diff for chai errors\n        const {\n          showDiff = undefined,\n          diff = undefined,\n          actual = undefined,\n          expected = undefined,\n        } = e.name === 'AssertionError' ? processError(e) : e;\n\n        const exception = { name, message, stack, callId, showDiff, diff, actual, expected };\n        this.update({ ...info, status: CallStates.ERROR, exception });\n\n        // Always track errors to their originating call.\n        this.setState(call.storyId, (state) => ({\n          callRefsByResult: new Map([\n            ...Array.from(state.callRefsByResult.entries()),\n            [e, { __callId__: call.id, retain: call.retain }],\n          ]),\n        }));\n\n        // Exceptions inside callbacks should bubble up to the parent call.\n        if (call.ancestors?.length) {\n          if (!Object.prototype.hasOwnProperty.call(e, 'callId')) {\n            Object.defineProperty(e, 'callId', { value: call.id });\n          }\n          throw e;\n        }\n      }\n      throw e;\n    };\n\n    try {\n      if (renderPhase === 'played' && !call.retain) {\n        throw alreadyCompletedException;\n      }\n\n      // Some libraries override function args through the `getArgs` option.\n      const actualArgs = options.getArgs\n        ? options.getArgs(call, this.getState(call.storyId))\n        : call.args;\n\n      // Wrap any callback functions to provide a way to access their \"parent\" call.\n      // This is picked up in the `track` function and used for call metadata.\n      const finalArgs = actualArgs.map((arg: any) => {\n        // We only want to wrap plain functions, not objects.\n\n        // We only want to wrap plain functions, not objects or classes.\n        if (typeof arg !== 'function' || isClass(arg) || Object.keys(arg).length) {\n          return arg;\n        }\n\n        return (...args: any) => {\n          // Set the cursor and ancestors for calls that happen inside the callback.\n          const { cursor, ancestors } = this.getState(call.storyId);\n          this.setState(call.storyId, { cursor: 0, ancestors: [...ancestors, call.id] });\n          const restore = () => this.setState(call.storyId, { cursor, ancestors });\n\n          // Invoke the actual callback function, taking care to reset the cursor and ancestors\n          // to their original values before we entered the callback, once the callback completes.\n          let willRestore = false;\n          try {\n            const res = arg(...args);\n            if (res instanceof Promise) {\n              willRestore = true; // We need to wait for the promise to finish before restoring\n              return res.finally(restore);\n            }\n            return res;\n          } finally {\n            if (!willRestore) {\n              restore();\n            }\n          }\n        };\n      });\n\n      const result = fn.apply(object, finalArgs);\n\n      // Track the result so we can trace later uses of it back to the originating call.\n      // Primitive results (undefined, null, boolean, string, number, BigInt) are ignored.\n      if (result && ['object', 'function', 'symbol'].includes(typeof result)) {\n        this.setState(call.storyId, (state) => ({\n          callRefsByResult: new Map([\n            ...Array.from(state.callRefsByResult.entries()),\n            [result, { __callId__: call.id, retain: call.retain }],\n          ]),\n        }));\n      }\n\n      this.update({\n        ...info,\n        status: result instanceof Promise ? CallStates.ACTIVE : CallStates.DONE,\n      });\n\n      if (result instanceof Promise) {\n        return result.then((value) => {\n          this.update({ ...info, status: CallStates.DONE });\n          return value;\n        }, handleException);\n      }\n\n      return result;\n    } catch (e) {\n      return handleException(e);\n    }\n  }\n\n  // Sends the call info to the manager and synchronizes the log.\n  update(call: Call) {\n    this.channel?.emit(EVENTS.CALL, call);\n    this.setState(call.storyId, ({ calls }) => {\n      // Omit earlier calls for the same ID, which may have been superseded by a later invocation.\n      // This typically happens when calls are part of a callback which runs multiple times.\n      const callsById = calls\n        .concat(call)\n        .reduce<Record<Call['id'], Call>>((a, c) => Object.assign(a, { [c.id]: c }), {});\n      return {\n        // Calls are sorted to ensure parent calls always come before calls in their callback.\n        calls: Object.values(callsById).sort((a, b) =>\n          a.id.localeCompare(b.id, undefined, { numeric: true })\n        ),\n      };\n    });\n    this.sync(call.storyId);\n  }\n\n  // Builds a log of interceptable calls and control states and sends it to the manager.\n  // Uses a 0ms debounce because this might get called many times in one tick.\n  sync(storyId: string) {\n    const synchronize = () => {\n      const { isLocked, isPlaying } = this.getState(storyId);\n      const logItems: LogItem[] = this.getLog(storyId);\n      const pausedAt = logItems\n        .filter(({ ancestors }) => !ancestors.length)\n        .find((item) => item.status === CallStates.WAITING)?.callId;\n\n      const hasActive = logItems.some((item) => item.status === CallStates.ACTIVE);\n      if (this.detached || isLocked || hasActive || logItems.length === 0) {\n        const controlStates: ControlStates = {\n          detached: this.detached,\n          start: false,\n          back: false,\n          goto: false,\n          next: false,\n          end: false,\n        };\n        const payload: SyncPayload = { controlStates, logItems };\n        this.channel?.emit(EVENTS.SYNC, payload);\n        return;\n      }\n\n      const hasPrevious = logItems.some(\n        (item) => item.status === CallStates.DONE || item.status === CallStates.ERROR\n      );\n      const controlStates: ControlStates = {\n        detached: this.detached,\n        start: hasPrevious,\n        back: hasPrevious,\n        goto: true,\n        next: isPlaying,\n        end: isPlaying,\n      };\n\n      const payload: SyncPayload = { controlStates, logItems, pausedAt };\n      this.channel?.emit(EVENTS.SYNC, payload);\n    };\n\n    this.setState(storyId, ({ syncTimeout }) => {\n      clearTimeout(syncTimeout);\n      return { syncTimeout: setTimeout(synchronize, 0) };\n    });\n  }\n}\n\n/**\n * Instruments an object or module by traversing its properties, patching any functions (methods) to\n * enable debugging. Patched functions will emit a `call` event when invoked. When intercept = true,\n * patched functions will return a Promise when the debugger stops before this function. As such,\n * \"interceptable\" functions will have to be `await`-ed.\n */\nexport function instrument<TObj extends Record<string, any>>(\n  obj: TObj,\n  options: Options = {}\n): TObj {\n  try {\n    let forceInstrument = false;\n    let skipInstrument = false;\n\n    if (global.window?.location?.search?.includes('instrument=true')) {\n      forceInstrument = true;\n    } else if (global.window?.location?.search?.includes('instrument=false')) {\n      skipInstrument = true;\n    }\n\n    // Don't do any instrumentation if not loaded in an iframe unless it's forced - instrumentation can also be skipped.\n    if ((global.window?.parent === global.window && !forceInstrument) || skipInstrument) {\n      return obj;\n    }\n\n    // Only create an instance if we don't have one (singleton) yet.\n    if (global.window && !global.window.__STORYBOOK_ADDON_INTERACTIONS_INSTRUMENTER__) {\n      global.window.__STORYBOOK_ADDON_INTERACTIONS_INSTRUMENTER__ = new Instrumenter();\n    }\n\n    const instrumenter: Instrumenter = global.window?.__STORYBOOK_ADDON_INTERACTIONS_INSTRUMENTER__;\n    return instrumenter.instrument(obj, options);\n  } catch (e) {\n    // Access to the parent window might fail due to CORS restrictions.\n    once.warn(e);\n    return obj;\n  }\n}\n\nfunction getPropertyDescriptor<T>(obj: T, propName: keyof T) {\n  let target = obj;\n  while (target != null) {\n    const descriptor = Object.getOwnPropertyDescriptor(target, propName);\n    if (descriptor) {\n      return descriptor;\n    }\n    target = Object.getPrototypeOf(target);\n  }\n  return undefined;\n}\n\nexport function isClass(obj: unknown) {\n  // if not a function, return false.\n\n  // if not a function, return false.\n  if (typeof obj !== 'function') {\n    return false;\n  }\n\n  // ⭐ is a function, has a prototype, and can't be deleted!\n\n  // ⭐ although a function's prototype is writable (can be reassigned),\n  //   it's not configurable (can't update property flags), so it\n  //   will remain writable.\n  //\n  // ⭐ a class's prototype is non-writable.\n  //\n  // Table: property flags of function/class prototype\n  // ---------------------------------\n  //   prototype  write  enum  config\n  // ---------------------------------\n  //   function     v      .      .\n  //   class        .      .      .\n  // ---------------------------------\n\n  // ⭐ is a function, has a prototype, and can't be deleted!\n\n  // ⭐ although a function's prototype is writable (can be reassigned),\n  //   it's not configurable (can't update property flags), so it\n  //   will remain writable.\n  //\n  // ⭐ a class's prototype is non-writable.\n  //\n  // Table: property flags of function/class prototype\n  // ---------------------------------\n  //   prototype  write  enum  config\n  // ---------------------------------\n  //   function     v      .      .\n  //   class        .      .      .\n  // ---------------------------------\n  const descriptor = Object.getOwnPropertyDescriptor(obj, 'prototype');\n\n  // every method shorthand version has no prototype\n  if (!descriptor) {\n    return false;\n  }\n\n  return !descriptor.writable;\n}\n"
  },
  {
    "path": "code/core/src/instrumenter/preview-api.ts",
    "content": "import type { AddonStore } from '../preview-api/modules/addons/main.ts';\n\n/**\n * We do this for mocking purposes, it's a lot easier to mock the a module than the addons channel\n * than it is to mock a globalThis property.\n */\n\nexport const addons: AddonStore = globalThis.__STORYBOOK_ADDONS_PREVIEW;\n"
  },
  {
    "path": "code/core/src/instrumenter/types.ts",
    "content": "import type { StoryId } from 'storybook/internal/types';\n\nimport type { RenderPhase } from '../preview-api/modules/preview-web/render/StoryRender.ts';\n\nexport type { RenderPhase };\n\nexport interface Call {\n  id: string;\n  cursor: number;\n  storyId: StoryId;\n  ancestors: Call['id'][];\n  path: Array<string | CallRef>;\n  method: string;\n  args: any[];\n  interceptable: boolean;\n  retain: boolean;\n  status?: CallStates.DONE | CallStates.ERROR | CallStates.ACTIVE | CallStates.WAITING;\n  exception?: {\n    name: Error['name'];\n    message: Error['message'];\n    stack: Error['stack'];\n    callId: Call['id'];\n    showDiff?: boolean;\n    diff?: string;\n    actual?: unknown;\n    expected?: unknown;\n  };\n}\n\nexport enum CallStates {\n  DONE = 'done',\n  ERROR = 'error',\n  ACTIVE = 'active',\n  WAITING = 'waiting',\n}\n\nexport interface CallRef {\n  __callId__: Call['id'];\n}\n\nexport interface ElementRef {\n  __element__: {\n    prefix?: string;\n    localName: string;\n    id?: string;\n    classNames?: string[];\n    innerText?: string;\n  };\n}\n\nexport interface ControlStates {\n  detached: boolean;\n  start: boolean;\n  back: boolean;\n  goto: boolean;\n  next: boolean;\n  end: boolean;\n}\n\nexport interface LogItem {\n  callId: Call['id'];\n  status: Call['status'];\n  ancestors: Call['id'][];\n}\n\nexport interface SyncPayload {\n  controlStates: ControlStates;\n  logItems: LogItem[];\n  pausedAt?: Call['id'];\n}\n\nexport interface State {\n  renderPhase: RenderPhase;\n  isDebugging: boolean;\n  isPlaying: boolean;\n  isLocked: boolean;\n  cursor: number;\n  calls: Call[];\n  shadowCalls: Call[];\n  callRefsByResult: Map<any, CallRef & { retain: boolean }>;\n  chainedCallIds: Set<Call['id']>;\n  ancestors: Call['id'][];\n  playUntil?: Call['id'];\n  resolvers: Record<Call['id'], Function>;\n  syncTimeout?: ReturnType<typeof setTimeout>;\n  forwardedException?: Error;\n}\n\nexport interface Options {\n  intercept?: boolean | ((method: string, path: Array<string | CallRef>) => boolean);\n  retain?: boolean;\n  mutate?: boolean;\n  path?: Array<string | CallRef>;\n  getArgs?: (call: Call, state: State) => Call['args'];\n  getKeys?: (originalObject: Record<string, unknown>, depth: number) => string[];\n}\n"
  },
  {
    "path": "code/core/src/instrumenter/typings.d.ts",
    "content": "declare interface Window {\n  __STORYBOOK_PREVIEW__: any;\n  __STORYBOOK_ADDON_INTERACTIONS_INSTRUMENTER__: any;\n  __STORYBOOK_ADDON_INTERACTIONS_INSTRUMENTER_STATE__: any;\n\n  FEATURES: import('storybook/internal/types').StorybookConfigRaw['features'];\n  LOGLEVEL: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent' | undefined;\n}\n"
  },
  {
    "path": "code/core/src/manager/App.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React, { useEffect } from 'react';\n\nimport Events from 'storybook/internal/core-events';\nimport type { Addon_PageType } from 'storybook/internal/types';\n\nimport { addons } from 'storybook/manager-api';\nimport { Global, createGlobal } from 'storybook/theming';\n\nimport { ManagerErrorBoundary } from './components/error-boundary/ManagerErrorBoundary.tsx';\nimport { Layout } from './components/layout/Layout.tsx';\nimport { useLayout } from './components/layout/LayoutProvider.tsx';\nimport Panel from './container/Panel.tsx';\nimport Preview from './container/Preview.tsx';\nimport Sidebar from './container/Sidebar.tsx';\n\ntype Props = {\n  managerLayoutState: ComponentProps<typeof Layout>['managerLayoutState'];\n  setManagerLayoutState: ComponentProps<typeof Layout>['setManagerLayoutState'];\n  pages: Addon_PageType[];\n  hasTab: boolean;\n};\n\nexport const App = ({ managerLayoutState, setManagerLayoutState, pages, hasTab }: Props) => {\n  const { setMobileAboutOpen } = useLayout();\n\n  /**\n   * Lets us tell the UI whether or not keyboard shortcuts are enabled, in places where it's not\n   * convenient to load the addons singleton to figure it out.\n   */\n  const { enableShortcuts = true } = addons.getConfig();\n  useEffect(() => {\n    document.body.setAttribute('data-shortcuts-enabled', enableShortcuts ? 'true' : 'false');\n  }, [enableShortcuts]);\n\n  /**\n   * Detects when our component library has enabled a focus trap. By convention, react-aria sets the\n   * document root to `inert` when a focus trap is enabled. We observe that attribute and inform the\n   * preview iframe when to respect the focus trap, via a channel event. This is necessary because\n   * inert is no longer propagated into iframes as per https://github.com/whatwg/html/issues/7605,\n   * and the replacement permission policy is not yet widely available\n   * (https://github.com/w3c/webappsec-permissions-policy/issues/273).\n   */\n  useEffect(() => {\n    const rootElement = document.getElementById('root');\n    if (!rootElement) {\n      return;\n    }\n\n    const observer = new MutationObserver(() => {\n      const hasInert = rootElement.hasAttribute('inert');\n      addons.getChannel().emit(Events.MANAGER_INERT_ATTRIBUTE_CHANGED, hasInert);\n    });\n\n    observer.observe(rootElement, {\n      attributes: true,\n      attributeFilter: ['inert'],\n    });\n\n    return () => observer.disconnect();\n  }, []);\n\n  return (\n    <>\n      <Global styles={createGlobal} />\n      <ManagerErrorBoundary>\n        <Layout\n          hasTab={hasTab}\n          managerLayoutState={managerLayoutState}\n          setManagerLayoutState={setManagerLayoutState}\n          slotMain={<Preview id=\"main\" withLoader />}\n          slotSidebar={<Sidebar onMenuClick={() => setMobileAboutOpen((state) => !state)} />}\n          slotPanel={<Panel />}\n          slotPages={pages.map(({ id, render: Content }) => (\n            <Content key={id} />\n          ))}\n        />\n      </ManagerErrorBoundary>\n    </>\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/README.md",
    "content": "<h1>Storybook manager's UI</h1>\n\nStorybook manager is the core UI of [Storybook](https://storybook.js.org).\nIt's a React based UI which you can initialize with a function.\nYou can configure it by providing a provider API.\n\n## Table of Contents\n\n- [Table of Contents](#table-of-contents)\n- [Usage](#usage)\n- [API](#api)\n  - [.setOptions()](#setoptions)\n- [.setStories()](#setstories)\n- [.onStory()](#onstory)\n- [Hacking Guide](#hacking-guide)\n  - [The App](#the-app)\n  - [Changing UI](#changing-ui)\n  - [Mounting](#mounting)\n  - [App Context](#app-context)\n  - [Actions](#actions)\n  - [Core API](#core-api)\n  - [Keyboard Shortcuts](#keyboard-shortcuts)\n  - [URL Changes](#url-changes)\n  - [Story Order](#story-order)\n\n## Usage\n\nFirst you need to install `@storybook/manager` into your app.\n\n```sh\nyarn add @storybook/manager --dev\n```\n\nThen you need to create a Provider class like this:\n\n```js\nimport React from 'react';\nimport { Provider } from '@storybook/manager';\n\nexport default class MyProvider extends Provider {\n  getElements(type) {\n    return {};\n  }\n\n  renderPreview() {\n    return <p>This is the Preview</p>;\n  }\n\n  handleAPI(api) {\n    // no need to do anything for now.\n  }\n}\n```\n\nThen you need to initialize the UI like this:\n\n```js\nimport { renderStorybookUI } from '@storybook/manager';\nimport global from 'global';\nimport Provider from './provider';\n\nconst { document } = global;\n\nconst roolEl = document.getElementById('root');\nrenderStorybookUI(roolEl, new Provider());\n```\n\n## API\n\n### .setOptions()\n\n```js\nimport { Provider } from '@storybook/manager';\n\nclass ReactProvider extends Provider {\n  handleAPI(api) {\n    api.setOptions({\n      // see available options in\n      // https://storybook.js.org/docs/react/configure/features-and-behavior\n    });\n  }\n}\n```\n\n## .setStories()\n\nThis API is used to pass the`kind` and `stories` list to storybook-ui.\n\n```js\nimport { Provider } from '@storybook/manager';\n\nclass ReactProvider extends Provider {\n  handleAPI(api) {\n    api.setStories([\n      {\n        kind: 'Component 1',\n        stories: ['State 1', 'State 2'],\n      },\n\n      {\n        kind: 'Component 2',\n        stories: ['State a', 'State b'],\n      },\n    ]);\n  }\n}\n```\n\n## .onStory()\n\nYou can use to listen to the story change and update the preview.\n\n```js\nimport { Provider } from '@storybook/manager';\n\nclass ReactProvider extends Provider {\n  handleAPI(api) {\n    api.onStory((kind, story) => {\n      this.globalState.emit('change', kind, story);\n    });\n  }\n}\n```\n\n## Hacking Guide\n\nIf you like to add features to the Storybook UI or fix bugs, this is the guide you need to follow.\n\nFirst of all, familiarize yourself with code used. Check the [source](./src/) folder for the source code.\n\n### The App\n\nThis is a Redux app written based on the [Mantra architecture](https://github.com/kadirahq/mantra/).\nIt's a set of modules. You can see those modules at `src/modules` directory.\n\n### Changing UI\n\nIf you like to change the appearance of the UI, you need to look at the `ui` module. Change components at the `components` directory for UI tweaks.\n\nYou can also change containers(which are written with [react-komposer](https://github.com/kadirahq/react-komposer/)) to add more data from the redux state.\n\n### Mounting\n\nThe UI is mounted in the `src/modules/ui/routes.js`. Inside that, we have injected dependencies as well. Refer [mantra-core](https://github.com/mantrajs/mantra-core) for that.\n\nWe've injected the context and actions.\n\n### App Context\n\nApp context is the app which application context you initialize when creating the UI. It is initialized in the `src/index.js` file. It's a non serializable state. You can access the app context from containers and basically most of the place in the app.\n\nSo, that's the place to put app wide configurations and objects which won't changed after initialized. Our redux store is also stayed inside the app context.\n\n### Actions\n\nActions are the place we implement app logic in a Mantra app. Each module has a set of actions and they are globally accessible. These actions are located at `<module>/actions` directory.\n\nThey got injected into the app(when mounting) and you can access them via containers. If you are familiar with redux, this is exactly action creators. But they are not only limited to do redux stuff. Actions has the access to the app context, so literally it can do anything.\n\n### Core API\n\nCore API (which is passed to the Provider with `handleAPI` method) is implemented in the `api` module. We put the provider passed by the user in the app context. Then api module access it and use it as needed.\n\n### Keyboard Shortcuts\n\nKeyboard shortcuts are implemented in a bit different way. The final state of keyboard shortcuts is managed by the `shortcuts` module. But they are implemented in the `ui` module with `src/modules/ui/configs/handle_routing.js`\n\nThese shortcuts also can be called from main API using the `handleShortcut` method. Check the example app for the usage. That's implemented as an action in the `shortcuts` module.\n\nThe above action(or the `handleShortcut` method) accepts events as a constant defined by this module. They are defined in the `src/libs/key_events.js`. This is basically to serialize these events.\n\n> In react-storybook we need to pass these events from the preview iframe to the main app. That's the core reason for this.\n\n### URL Changes\n\nTODO: state we use reach/router customized to query params\n\n### Story Order\n\nStories are sorted in the order in which they were imported. This can be overridden by adding storySort to the Parameters for the stories in `.storybook/preview.js`:\n\n```js\naddParameters({\n  options: {\n    storySort: (a, b) => a[1].id.localeCompare(b[1].id),\n  },\n});\n```\n"
  },
  {
    "path": "code/core/src/manager/__tests__/index.test.ts",
    "content": "// @vitest-environment happy-dom\nimport { describe, expect, it } from 'vitest';\n\nimport { renderStorybookUI } from '../index.tsx';\n\ndescribe('Main API', () => {\n  it('should fail if provider is not extended from the base Provider', () => {\n    const run = () => {\n      const fakeProvider = {};\n      // @ts-expect-error (Converted from ts-ignore)\n      renderStorybookUI(null, fakeProvider);\n    };\n\n    expect(run).toThrow(/base Provider/);\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager/components/Focus/Focus.tsx",
    "content": "import React, { useEffect, useRef, useState } from 'react';\n\nimport { styled } from 'storybook/theming';\n\nimport { useLocationHash } from '../../hooks/useLocation.ts';\n\nconst FocusOutline = styled.div<{ active?: boolean; outlineOffset?: number }>(\n  ({ theme, active = false, outlineOffset = 0 }) => ({\n    width: '100%',\n    borderRadius: 'inherit',\n    transition: 'outline-color var(--transition-duration, 0.2s)',\n    outline: `2px solid ${active ? theme.color.secondary : 'transparent'}`,\n    outlineOffset,\n  })\n);\n\nconst FocusProxy = styled(FocusOutline)<{ targetId: string }>(({ theme, targetId }) => ({\n  [`&:has([data-target-id=\"${targetId}\"]:focus-visible)`]: {\n    outlineColor: theme.color.secondary,\n  },\n}));\n\nconst FocusRing = ({\n  active = false,\n  highlightDuration,\n  nodeRef,\n  ...props\n}: React.ComponentProps<typeof FocusOutline> & {\n  highlightDuration?: number;\n  nodeRef?: React.RefObject<HTMLDivElement>;\n}) => {\n  const [visible, setVisible] = useState(active);\n\n  useEffect(() => {\n    if (highlightDuration) {\n      setVisible(active);\n      const timeout = setTimeout(setVisible, highlightDuration, false);\n      return () => clearTimeout(timeout);\n    }\n  }, [active, highlightDuration]);\n\n  return <FocusOutline {...props} active={highlightDuration ? visible : active} ref={nodeRef} />;\n};\n\nconst FocusTarget = ({\n  targetHash,\n  highlightDuration,\n  ...props\n}: Omit<React.ComponentProps<typeof FocusRing>, 'active'> & {\n  targetHash: string;\n}) => {\n  const nodeRef = useRef<HTMLDivElement>(null);\n  const locationHash = useLocationHash();\n  const [active, setActive] = useState(locationHash === targetHash);\n\n  useEffect(() => {\n    const timeouts: ReturnType<typeof setTimeout>[] = [];\n\n    setActive(false);\n    if (locationHash === targetHash) {\n      timeouts.push(\n        setTimeout(() => {\n          setActive(true);\n          nodeRef.current?.focus({ preventScroll: true });\n          nodeRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n        }, 0)\n      );\n      if (highlightDuration) {\n        timeouts.push(setTimeout(setActive, highlightDuration, false));\n      }\n    }\n\n    return () => timeouts.forEach(clearTimeout);\n  }, [locationHash, targetHash, highlightDuration]);\n\n  return <FocusRing {...props} active={active} nodeRef={nodeRef} tabIndex={-1} />;\n};\n\nexport const Focus = {\n  Outline: FocusOutline,\n  Proxy: FocusProxy,\n  Ring: FocusRing,\n  Target: FocusTarget,\n};\n"
  },
  {
    "path": "code/core/src/manager/components/Optional/Optional.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { keyframes, styled } from 'storybook/theming';\n\nimport { Optional } from './Optional.tsx';\n\nconst resize = keyframes`\n  to {\n    width: 150px;\n  }\n`;\n\nconst Resizing = styled.div({\n  display: 'inline-flex',\n  justifyContent: 'space-between',\n  width: '250px',\n  animation: `${resize} 3s ease-in-out infinite alternate`,\n  border: '1px solid silver',\n});\n\nconst meta: Meta<typeof Optional> = {\n  title: 'Optional',\n  component: Optional,\n  decorators: [\n    (Story) => (\n      <Resizing>\n        <Story />\n        <div style={{ display: 'inline-block', whiteSpace: 'nowrap' }}>Other stuff</div>\n      </Resizing>\n    ),\n  ],\n};\n\nexport default meta;\n\nexport const Default: StoryObj<typeof Optional> = {\n  args: {\n    content: (\n      <div style={{ display: 'inline-block', whiteSpace: 'nowrap', background: 'papayawhip' }}>\n        Optional content\n      </div>\n    ),\n  },\n};\n\nexport const Fallback: StoryObj<typeof Optional> = {\n  args: {\n    content: (\n      <div style={{ display: 'inline-block', whiteSpace: 'nowrap', background: 'papayawhip' }}>\n        Optional content\n      </div>\n    ),\n    fallback: (\n      <div style={{ display: 'inline-block', whiteSpace: 'nowrap', background: 'palevioletred' }}>\n        Fallback\n      </div>\n    ),\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/components/Optional/Optional.tsx",
    "content": "import type { ReactElement } from 'react';\nimport React, { useEffect, useRef, useState } from 'react';\n\nimport { styled } from 'storybook/theming';\n\nconst Wrapper = styled.div({\n  display: 'inline-grid',\n  gridTemplateColumns: 'max-content',\n  overflow: 'hidden',\n});\n\nconst Content = styled.div<{ isHidden: boolean | null }>(({ isHidden }) => ({\n  display: 'inline-block',\n  gridArea: '1/1',\n  opacity: isHidden === null ? 0 : 1,\n  visibility: isHidden ? 'hidden' : 'visible',\n}));\n\nexport const Optional = ({\n  content,\n  fallback,\n}: {\n  content: ReactElement;\n  fallback?: ReactElement;\n}) => {\n  const contentRef = useRef<HTMLDivElement>(null);\n  const wrapperRef = useRef<HTMLDivElement>(null);\n  const [hidden, setHidden] = useState<boolean | null>(null);\n\n  const contentWidth = useRef(contentRef.current?.offsetWidth ?? 0);\n  const wrapperWidth = useRef(wrapperRef.current?.offsetWidth ?? 0);\n\n  useEffect(() => {\n    if (contentRef.current && wrapperRef.current) {\n      const resizeObserver = new ResizeObserver(() => {\n        wrapperWidth.current = wrapperRef.current?.offsetWidth || wrapperWidth.current;\n        contentWidth.current = contentRef.current?.offsetWidth || contentWidth.current;\n        setHidden(contentWidth.current > wrapperWidth.current);\n      });\n      resizeObserver.observe(wrapperRef.current);\n      return () => resizeObserver.disconnect();\n    }\n  }, []);\n\n  return (\n    <Wrapper ref={wrapperRef}>\n      <Content isHidden={hidden} ref={contentRef}>\n        {content}\n      </Content>\n\n      {fallback && <Content isHidden={!hidden}>{fallback}</Content>}\n    </Wrapper>\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/components/Particles/Particles.stories.tsx",
    "content": "import preview from '../../../../../.storybook/preview.tsx';\nimport { Particles } from './Particles.tsx';\n\nconst SomeComponent = (props: React.ComponentProps<'div'>) => {\n  return <div {...props}>Cool</div>;\n};\n\nconst meta = preview.meta({\n  component: Particles,\n  parameters: {\n    layout: 'centered',\n    chromatic: {\n      disableSnapshot: true,\n    },\n  },\n  args: {\n    anchor: SomeComponent,\n  },\n});\n\nexport const Default = meta.story({});\n"
  },
  {
    "path": "code/core/src/manager/components/Particles/Particles.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React, { memo, useLayoutEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { keyframes, styled } from 'storybook/theming';\n\nconst Shape = styled.svg(({ color }) => ({\n  fill: color,\n  position: 'absolute',\n  inset: '0',\n  margin: 'auto',\n  width: '12px',\n  height: '12px',\n  pointerEvents: 'none',\n}));\n\nconst Donut = (props: ComponentProps<typeof Shape>) => (\n  <Shape viewBox=\"0 0 90 90\" xmlns=\"http://www.w3.org/2000/svg\" color=\"red\" {...props}>\n    <path d=\"M45 0c24.853 0 45 20.147 45 45S69.853 90 45 90 0 69.853 0 45 20.147 0 45 0zm.5 27C35.283 27 27 35.283 27 45.5S35.283 64 45.5 64 64 55.717 64 45.5 55.717 27 45.5 27z\" />\n  </Shape>\n);\n\nconst L = (props: ComponentProps<typeof Shape>) => (\n  <Shape viewBox=\"0 0 55 89\" xmlns=\"http://www.w3.org/2000/svg\" color=\"#66BF3C\" {...props}>\n    <path d=\"M55 3v83a3 3 0 01-3 3H3a3 3 0 01-3-3V64a3 3 0 013-3h21a3 3 0 003-3V3a3 3 0 013-3h22a3 3 0 013 3z\" />\n  </Shape>\n);\n\nconst Slice = (props: ComponentProps<typeof Shape>) => (\n  <Shape viewBox=\"0 0 92 92\" xmlns=\"http://www.w3.org/2000/svg\" color=\"#FF4785\" {...props}>\n    <path d=\"M92 89V3c0-3-2.056-3-3-3C39.294 0 0 39.294 0 89c0 0 0 3 3 3h86a3 3 0 003-3z\" />\n  </Shape>\n);\n\nconst Square = ({ style, ...props }: ComponentProps<typeof Shape>) => (\n  <Shape\n    viewBox=\"0 0 90 90\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    color=\"#1EA7FD\"\n    {...props}\n    style={{ borderRadius: 5, ...style }}\n  >\n    <path d=\"M0 0h90v90H0z\" />\n  </Shape>\n);\n\nconst Triangle = (props: ComponentProps<typeof Shape>) => (\n  <Shape viewBox=\"0 0 96 88\" xmlns=\"http://www.w3.org/2000/svg\" color=\"#FFAE00\" {...props}>\n    <path d=\"M50.63 1.785l44.928 81.77A3 3 0 0192.928 88H3.072a3 3 0 01-2.629-4.445l44.929-81.77a3 3 0 015.258 0z\" />\n  </Shape>\n);\n\nconst T = (props: ComponentProps<typeof Shape>) => (\n  <Shape viewBox=\"0 0 92 62\" xmlns=\"http://www.w3.org/2000/svg\" color=\"#FC521F\" {...props}>\n    <path d=\"M63 3v25a3 3 0 003 3h23a3 3 0 013 3v25a3 3 0 01-3 3H3a3 3 0 01-3-3V34a3 3 0 013-3h24a3 3 0 003-3V3a3 3 0 013-3h27a3 3 0 013 3z\" />\n  </Shape>\n);\n\nconst Z = (props: ComponentProps<typeof Shape>) => (\n  <Shape viewBox=\"0 0 56 90\" xmlns=\"http://www.w3.org/2000/svg\" color=\"#6F2CAC\" {...props}>\n    <path d=\"M28 3v25a3 3 0 003 3h22a3 3 0 013 3v53a3 3 0 01-3 3H31a3 3 0 01-3-3V62a3 3 0 00-3-3H3a3 3 0 01-3-3V3a3 3 0 013-3h22a3 3 0 013 3z\" />\n  </Shape>\n);\n\nconst fadeToTransparent = keyframes`\n  to {\n    opacity: 0;\n  }\n`;\n\nconst disperse = keyframes`\n  to {\n    transform: translate(\n      calc(cos(var(--angle)) * var(--distance)),\n      calc(sin(var(--angle)) * var(--distance))\n    ) rotate(var(--rotation));\n  }\n`;\n\nconst slideDown = keyframes`\n  to {\n    transform: translateY(50px);\n  }\n`;\n\nconst Container = styled.div({\n  position: 'absolute',\n  display: 'flex',\n  flexDirection: 'row',\n  flexWrap: 'wrap',\n  gap: 10,\n  '--particle-curve': 'cubic-bezier(0.2, 0.56, 0, 1)',\n  animation: `${slideDown} 1000ms forwards cubic-bezier(0.587, -0.381, 0.583, 0.599)`,\n  animationDelay: '150ms',\n  zIndex: 999,\n\n  svg: {\n    width: 15,\n    height: 15,\n    animation: `${fadeToTransparent} var(--fade-duration) forwards, ${disperse} 1000ms forwards var(--particle-curve)`,\n  },\n});\n\nconst FADE_DURATION = 1200;\nconst NUM_OF_PARTICLES = 8;\n// `JITTER` is the amount of variance allowed for each angle.\n// Tweak this value to control how orderly/chaotic the animation appears.\nconst JITTER = 15;\n\nconst random = (min: number, max: number) => Math.random() * (max - min) + min;\nconst sortRandomly = (array: any[]) => array.sort(() => Math.random() - 0.5);\n\nexport const Particles = memo(function Particles({\n  anchor: Anchor,\n}: {\n  anchor: React.ElementType;\n}) {\n  const anchorRef = useRef<HTMLDivElement>(null);\n  const [left, setLeft] = useState(0);\n  const [top, setTop] = useState(0);\n\n  const shapes = sortRandomly([Donut, L, Slice, Square, Triangle, T, Z]);\n  const colors = sortRandomly([\n    '#FF0000',\n    '#FF4787',\n    '#66BF3C',\n    '#1EA7FD',\n    '#FC521F',\n    '#6F2CAC',\n    '#FFAE00',\n  ]);\n\n  useLayoutEffect(() => {\n    const rect = anchorRef.current?.getBoundingClientRect();\n    if (rect) {\n      setLeft(rect.left + rect.width / 2);\n      setTop(rect.top + rect.height / 2);\n    }\n  }, []);\n\n  return (\n    <div ref={anchorRef}>\n      <Anchor />\n      {createPortal(\n        <Container style={{ top: top + 'px', left: left + 'px' }}>\n          {shapes.map((Particle, index) => {\n            const angle = (360 / NUM_OF_PARTICLES) * index + random(-JITTER, JITTER);\n            const distance = random(50, 80);\n            const rotation = random(-360, 360);\n\n            const style = {\n              '--angle': angle + 'deg',\n              '--distance': distance + 'px',\n              '--rotation': rotation + 'deg',\n              '--fade-duration': FADE_DURATION + 'ms',\n            } as React.CSSProperties;\n\n            return <Particle key={Particle.name} style={style} color={colors[index]} />;\n          })}\n        </Container>,\n        document.getElementById('root') ?? document.body\n      )}\n    </div>\n  );\n});\n"
  },
  {
    "path": "code/core/src/manager/components/Shortcut.tsx",
    "content": "import React from 'react';\n\nimport { shortcutToHumanString } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nconst Wrapper = styled.span(({ theme }) => ({\n  display: 'inline-flex',\n  alignItems: 'center',\n  justifyContent: 'center',\n  height: 16,\n  fontSize: '11px',\n  fontWeight: theme.typography.weight.regular,\n  background: theme.base === 'light' ? 'rgba(0,0,0,0.05)' : 'rgba(255,255,255,0.05)',\n  color: theme.base === 'light' ? theme.color.dark : theme.textMutedColor,\n  borderRadius: 2,\n  userSelect: 'none',\n  pointerEvents: 'none',\n  padding: '0 4px',\n}));\n\nconst Key = styled.kbd(({ theme }) => ({\n  padding: 0,\n  fontFamily: theme.typography.fonts.base,\n  verticalAlign: 'middle',\n  '& + &': {\n    marginLeft: 6,\n  },\n}));\n\nexport const Shortcut = ({ keys }: { keys: string[] }) => (\n  <Wrapper>\n    {keys.map((key) => (\n      <Key key={key}>{shortcutToHumanString([key])}</Key>\n    ))}\n  </Wrapper>\n);\n"
  },
  {
    "path": "code/core/src/manager/components/TextFlip.stories.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport { useState } from 'react';\n\nimport preview from '../../../../.storybook/preview.tsx';\nimport { Button } from '../../components/index.ts';\nimport { TextFlip } from './TextFlip.tsx';\n\nconst Counter = ({\n  text,\n  reverse = false,\n  ...props\n}: { text: string; reverse?: boolean } & ComponentProps<typeof TextFlip>) => {\n  const [value, setValue] = useState(Number(text));\n  return (\n    <Button onClick={() => setValue(reverse ? value - 1 : value + 1)}>\n      <TextFlip text={String(value)} {...props} />\n    </Button>\n  );\n};\n\nconst meta = preview.meta({\n  component: TextFlip,\n  args: {\n    text: 'Use controls to change this',\n    placeholder: 'This is some long placeholder text',\n  },\n  render: (args) => (\n    <Button>\n      <TextFlip {...args} />\n    </Button>\n  ),\n});\n\nexport const Default = meta.story({});\n\nexport const Increasing = meta.story(() => <Counter placeholder=\"00\" text=\"-1\" />);\n\nexport const Decreasing = meta.story(() => <Counter placeholder=\"00\" text=\"99\" reverse />);\n"
  },
  {
    "path": "code/core/src/manager/components/TextFlip.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React, { useRef, useState } from 'react';\n\nimport { keyframes, styled } from 'storybook/theming';\n\nconst slideIn = keyframes({\n  from: {\n    transform: 'translateY(var(--slide-in-from))',\n    opacity: 0,\n  },\n});\n\nconst slideOut = keyframes({\n  to: {\n    transform: 'translateY(var(--slide-out-to))',\n    opacity: 0,\n  },\n});\n\nconst Container = styled.div({\n  display: 'inline-grid',\n  gridTemplateColumns: '1fr',\n  justifyContent: 'center',\n  alignItems: 'center',\n});\n\nconst Placeholder = styled.div({\n  gridArea: '1 / 1',\n  userSelect: 'none',\n  visibility: 'hidden',\n});\n\nconst Text = styled.span<{\n  duration: number;\n  isExiting?: boolean;\n  isEntering?: boolean;\n  reverse?: boolean;\n}>(({ duration, isExiting, isEntering, reverse }) => {\n  let animation: string | undefined;\n\n  if (isExiting) {\n    animation = `${slideOut} ${duration}ms forwards`;\n  } else if (isEntering) {\n    animation = `${slideIn} ${duration}ms forwards`;\n  }\n\n  return {\n    gridArea: '1 / 1',\n    animation,\n    pointerEvents: isExiting ? 'none' : 'auto',\n    userSelect: isExiting ? 'none' : 'text',\n    '--slide-in-from': reverse ? '-100%' : '100%',\n    '--slide-out-to': reverse ? '100%' : '-100%',\n\n    '@media (prefers-reduced-motion: reduce)': {\n      animation: 'none',\n      opacity: isExiting ? 0 : 1,\n      transform: 'translateY(0)',\n    },\n  };\n});\n\nexport const TextFlip = ({\n  text,\n  duration = 250,\n  placeholder,\n  ...props\n}: {\n  text: string;\n  duration?: number;\n  placeholder?: string;\n} & ComponentProps<typeof Container>) => {\n  const textRef = useRef(text);\n  const [staleValue, setStaleValue] = useState(text);\n\n  const isAnimating = text !== staleValue;\n  const reverse = isAnimating && numericCompare(staleValue, text);\n\n  textRef.current = text;\n\n  return (\n    <Container {...props}>\n      {isAnimating && (\n        <Text\n          aria-hidden\n          duration={duration}\n          reverse={reverse}\n          isExiting\n          onAnimationEnd={() => setStaleValue(textRef.current)}\n        >\n          {staleValue}\n        </Text>\n      )}\n      <Text duration={duration} reverse={reverse} isEntering={isAnimating}>\n        {text}\n      </Text>\n      {placeholder && <Placeholder aria-hidden>{placeholder}</Placeholder>}\n    </Container>\n  );\n};\n\nfunction numericCompare(a: string, b: string): boolean {\n  const na = Number(a);\n  const nb = Number(b);\n  return Number.isNaN(na) || Number.isNaN(nb)\n    ? a.localeCompare(b, undefined, { numeric: true }) > 0\n    : na > nb;\n}\n"
  },
  {
    "path": "code/core/src/manager/components/TourGuide/HighlightElement.stories.tsx",
    "content": "import { Button } from 'storybook/internal/components';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { HighlightElement } from './HighlightElement.tsx';\n\nconst meta = preview.meta({\n  component: HighlightElement,\n  parameters: {\n    layout: 'centered',\n  },\n});\n\nexport const Default = meta.story({\n  args: {\n    targetSelector: '#highlighted',\n  },\n  render: (args: { targetSelector: string; pulsating?: boolean }) => (\n    <div style={{ overflow: 'hidden' }}>\n      <Button variant=\"ghost\" id=\"highlighted\">\n        I'm highlighted\n      </Button>\n      <HighlightElement {...args} />\n    </div>\n  ),\n});\n\nexport const Pulsating = meta.story({\n  args: {\n    targetSelector: '#highlighted',\n    pulsating: true,\n  },\n  render: (args: { targetSelector: string; pulsating?: boolean }) => (\n    <>\n      <Button variant=\"ghost\" id=\"highlighted\">\n        I'm pulsating\n      </Button>\n      <HighlightElement {...args} />\n    </>\n  ),\n});\n\nexport const PulsatingOverflow = meta.story({\n  args: {\n    targetSelector: '#highlighted',\n    pulsating: true,\n  },\n  render: (args: { targetSelector: string; pulsating?: boolean }) => (\n    <div style={{ overflow: 'hidden' }}>\n      <Button variant=\"ghost\" id=\"highlighted\">\n        I'm pulsating despite being contained by overflow:hidden\n      </Button>\n      <HighlightElement {...args} />\n    </div>\n  ),\n});\n\nexport const WithScrollableContainer = meta.story({\n  args: {\n    targetSelector: '#highlighted-in-scroll',\n    pulsating: true,\n  },\n  render: (args: { targetSelector: string; pulsating?: boolean }) => (\n    <div\n      style={{\n        width: '290px',\n        height: '360px',\n        overflow: 'scroll',\n        border: '1px solid #ccc',\n        padding: '15px',\n      }}\n    >\n      <div style={{ height: 300 }}></div>\n      <Button variant=\"ghost\" id=\"highlighted-in-scroll\">\n        Scroll down to see the highlight follow me\n      </Button>\n      <div style={{ height: 300 }}></div>\n      <HighlightElement {...args} />\n    </div>\n  ),\n});\n"
  },
  {
    "path": "code/core/src/manager/components/TourGuide/HighlightElement.tsx",
    "content": "import { useEffect } from 'react';\n\nconst HIGHLIGHT_KEYFRAMES_ID = 'storybook-highlight-element-keyframes';\n\nconst keyframes = `\n  @keyframes sb-highlight-pulsate {\n    0% {\n      box-shadow: rgba(2,156,253,1) 0 0 2px 1px, 0 0 0 0 rgba(2, 156, 253, 0.7), 0 0 0 0 rgba(2, 156, 253, 0.4);\n    }\n    50% {\n      box-shadow: rgba(2,156,253,1) 0 0 2px 1px, 0 0 0 20px rgba(2, 156, 253, 0), 0 0 0 40px rgba(2, 156, 253, 0);\n    }\n    100% {\n      box-shadow: rgba(2,156,253,1) 0 0 2px 1px, 0 0 0 0 rgba(2, 156, 253, 0), 0 0 0 0 rgba(2, 156, 253, 0);\n    }\n  }\n`;\n\nconst createOverlay = (element: HTMLElement) => {\n  const overlay = document.createElement('div');\n  overlay.id = 'storybook-highlight-element';\n  overlay.style.position = 'fixed';\n  overlay.style.pointerEvents = 'none';\n  overlay.style.zIndex = '2147483647';\n  overlay.style.transition = 'opacity 0.2s ease-in-out';\n\n  requestAnimationFrame(() => {\n    updateOverlayStyles(element, overlay);\n    element.scrollIntoView({ behavior: 'smooth', block: 'center' });\n  });\n\n  return overlay;\n};\n\nconst updateOverlayStyles = (element: HTMLElement, overlay: HTMLDivElement) => {\n  const rect = element.getBoundingClientRect();\n  const computedStyle = window.getComputedStyle(element);\n\n  overlay.style.top = `${rect.top}px`;\n  overlay.style.left = `${rect.left}px`;\n  overlay.style.width = `${rect.width}px`;\n  overlay.style.height = `${rect.height}px`;\n  overlay.style.borderRadius = computedStyle.borderRadius;\n};\n\nconst findScrollableAncestors = (element: HTMLElement) => {\n  const scrollableAncestors: Array<HTMLElement | Window> = [window];\n  let parent = element.parentElement;\n\n  while (parent) {\n    const style = window.getComputedStyle(parent);\n    const isScrollable =\n      style.overflow === 'auto' ||\n      style.overflow === 'scroll' ||\n      style.overflowX === 'auto' ||\n      style.overflowX === 'scroll' ||\n      style.overflowY === 'auto' ||\n      style.overflowY === 'scroll';\n\n    if (isScrollable) {\n      scrollableAncestors.push(parent);\n    }\n\n    parent = parent.parentElement;\n  }\n  return scrollableAncestors;\n};\n\n/**\n * Highlights a DOM element on the page by creating a visual overlay. The overlay automatically\n * updates its position when the element moves or scrolls, and can optionally display a pulsating\n * animation effect.\n *\n * @param props - Component props\n * @param props.targetSelector - CSS selector string to identify the element to highlight\n * @param props.pulsating - Optional flag to enable a pulsating animation effect\n * @returns Returns null (it doesn't render in place, it appends to the body)\n * @todo Use createPortal to render the overlay in the body and avoid manually setting styles\n */\nexport function HighlightElement({\n  targetSelector,\n  pulsating = false,\n}: {\n  targetSelector: string;\n  pulsating?: boolean;\n}) {\n  useEffect(() => {\n    const element = document.querySelector<HTMLElement>(targetSelector);\n    if (!element || !element.parentElement) {\n      return;\n    }\n\n    const overlay = document.body.appendChild(createOverlay(element));\n\n    if (pulsating) {\n      if (!document.getElementById(HIGHLIGHT_KEYFRAMES_ID)) {\n        const style = document.createElement('style');\n        style.id = HIGHLIGHT_KEYFRAMES_ID;\n        style.innerHTML = keyframes;\n        document.head.appendChild(style);\n      }\n\n      overlay.style.animation = 'sb-highlight-pulsate 3s infinite';\n      overlay.style.transformOrigin = 'center';\n      overlay.style.animationTimingFunction = 'ease-in-out';\n    } else {\n      overlay.style.boxShadow = 'rgba(2,156,253,1) 0 0 2px 1px';\n    }\n\n    let scrollTimeout: number | null = null;\n    const handleScroll = () => {\n      if (overlay.parentElement) {\n        overlay.remove();\n      }\n\n      if (scrollTimeout !== null) {\n        clearTimeout(scrollTimeout);\n      }\n\n      scrollTimeout = window.setTimeout(() => {\n        if (!element) {\n          return;\n        }\n\n        updateOverlayStyles(element, overlay);\n        overlay.style.opacity = '0';\n        document.body.appendChild(overlay);\n        requestAnimationFrame(() => (overlay.style.opacity = '1'));\n      }, 150);\n    };\n\n    const resizeObserver = new ResizeObserver(\n      () => overlay.parentElement && updateOverlayStyles(element, overlay)\n    );\n    resizeObserver.observe(window.document.body);\n    resizeObserver.observe(element);\n\n    const scrollContainers = findScrollableAncestors(element);\n    scrollContainers.forEach((el) =>\n      el.addEventListener('scroll', handleScroll, { passive: true })\n    );\n    scrollContainers\n      .filter((el): el is HTMLElement => el !== window)\n      .forEach((el) => resizeObserver.observe(el));\n\n    return () => {\n      if (scrollTimeout !== null) {\n        clearTimeout(scrollTimeout);\n      }\n\n      if (overlay.parentElement) {\n        overlay.remove();\n      }\n\n      scrollContainers.forEach((el) => el.removeEventListener('scroll', handleScroll));\n      resizeObserver.disconnect();\n    };\n  }, [targetSelector, pulsating]);\n\n  return null;\n}\n"
  },
  {
    "path": "code/core/src/manager/components/TourGuide/TourGuide.stories.tsx",
    "content": "import { useState } from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { fn } from 'storybook/test';\n\nimport { TourGuide } from './TourGuide.tsx';\n\nconst meta = {\n  component: TourGuide,\n  args: {\n    onComplete: fn(),\n    onDismiss: fn(),\n  },\n} satisfies Meta<typeof TourGuide>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {\n  args: {\n    steps: [\n      {\n        title: 'One',\n        content: 'Welcome to the guided tour!',\n        target: '#storybook-root',\n      },\n      {\n        title: 'Two',\n        content: 'More stuff',\n        target: '#storybook-root',\n      },\n      {\n        title: 'Three',\n        content: 'Some more stuff',\n        target: '#storybook-root',\n      },\n      {\n        title: 'Four',\n        content: 'All done',\n        target: '#storybook-root',\n      },\n    ],\n  },\n};\n\nexport const Controlled: Story = {\n  render: (args) => {\n    const [step, setStep] = useState<string>('one');\n    return (\n      <TourGuide\n        {...args}\n        step={step}\n        onNext={() => setStep((v) => (v === 'one' ? 'two' : 'one'))}\n      />\n    );\n  },\n  args: {\n    steps: [\n      {\n        key: 'one',\n        title: 'One',\n        content: 'Hello!',\n        target: '#storybook-root',\n      },\n      {\n        key: 'two',\n        title: 'Two',\n        content: 'I go back and forth!',\n        target: '#storybook-root',\n      },\n      {\n        key: 'three',\n        title: 'Three',\n        content: \"Can't touch this\",\n        target: '#storybook-root',\n      },\n    ],\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/components/TourGuide/TourGuide.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport { darken } from 'polished';\nimport type { CallBackProps } from 'react-joyride';\nimport Joyride, { ACTIONS, type Step } from 'react-joyride';\nimport { useTheme } from 'storybook/theming';\nimport { ThemeProvider, convert, themes } from 'storybook/theming';\n\nimport { HighlightElement } from './HighlightElement.tsx';\nimport { TourTooltip } from './TourTooltip.tsx';\n\ntype StepDefinition = {\n  key?: string;\n  highlight?: string;\n  hideNextButton?: boolean;\n  onNext?: ({ next }: { next: () => void }) => void;\n} & Partial<\n  Pick<\n    // Unfortunately we can't use ts-expect-error here for some reason\n    // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n    // @ts-ignore Ignore circular reference\n    Step,\n    | 'content'\n    | 'disableBeacon'\n    | 'disableOverlay'\n    | 'floaterProps'\n    | 'offset'\n    | 'placement'\n    | 'spotlightClicks'\n    | 'styles'\n    | 'target'\n    | 'title'\n  >\n>;\n\nexport const TourGuide = ({\n  step,\n  steps,\n  onNext,\n  onComplete,\n  onDismiss,\n}: {\n  step?: string;\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore Circular reference in Step type\n  steps: StepDefinition[];\n  onNext?: ({ next }: { next: () => void }) => void;\n  onComplete?: () => void;\n  onDismiss?: () => void;\n}) => {\n  const [stepIndex, setStepIndex] = useState<number | null>(step ? null : 0);\n  const theme = useTheme();\n\n  const timeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n  const updateStepIndex = useCallback((index: number) => {\n    clearTimeout(timeoutRef.current);\n    setStepIndex((current) => {\n      if (index === -1) {\n        return null;\n      }\n      if (current === null || current === index) {\n        return index;\n      }\n      // Briefly hide the tour tooltip while switching steps\n      timeoutRef.current = setTimeout(setStepIndex, 300, index);\n      return null;\n    });\n  }, []);\n\n  useEffect(\n    () => (step ? updateStepIndex(steps.findIndex(({ key }) => key === step)) : undefined),\n    [step, steps, updateStepIndex]\n  );\n\n  const mappedSteps = useMemo(() => {\n    return steps.map((step, index) => {\n      const next = () => updateStepIndex(index + 1);\n      return {\n        disableBeacon: true,\n        disableOverlay: true,\n        spotlightClicks: true,\n        offset: 0,\n        ...step,\n        content: (\n          <>\n            {step.content}\n            {step.highlight && <HighlightElement targetSelector={step.highlight} pulsating />}\n          </>\n        ),\n        onNext: step.onNext ? () => step.onNext?.({ next }) : onNext && (() => onNext?.({ next })),\n      };\n    });\n  }, [steps, onNext, updateStepIndex]);\n\n  const callback = useCallback(\n    (data: CallBackProps) => {\n      if (data.action === ACTIONS.NEXT && data.lifecycle === 'complete') {\n        if (data.index === data.size - 1) {\n          onComplete?.();\n        } else if (data.step?.onNext) {\n          data.step.onNext();\n        } else {\n          updateStepIndex(data.index + 1);\n        }\n      }\n      if (data.action === ACTIONS.CLOSE) {\n        onDismiss?.();\n      }\n    },\n    [onComplete, onDismiss, updateStepIndex]\n  );\n\n  if (stepIndex === null) {\n    return null;\n  }\n\n  return (\n    <Joyride\n      continuous\n      steps={mappedSteps}\n      stepIndex={stepIndex}\n      spotlightPadding={0}\n      disableCloseOnEsc\n      disableOverlayClose\n      disableScrolling\n      callback={callback}\n      tooltipComponent={TourTooltip}\n      floaterProps={{\n        disableAnimation: true,\n        styles: {\n          arrow: {\n            length: 20,\n            spread: 2,\n          },\n          floater: {\n            filter:\n              theme.base === 'light'\n                ? 'drop-shadow(0px 5px 5px rgba(0,0,0,0.05)) drop-shadow(0 1px 3px rgba(0,0,0,0.1))'\n                : 'drop-shadow(#fff5 0px 0px 0.5px) drop-shadow(#fff5 0px 0px 0.5px)',\n          },\n        },\n      }}\n      styles={{\n        overlay: {\n          mixBlendMode: 'unset',\n          backgroundColor: steps[stepIndex]?.target === 'body' ? 'rgba(27, 28, 29, 0.2)' : 'none',\n        },\n        spotlight: {\n          backgroundColor: 'none',\n          border: `solid 2px ${theme.base === 'light' ? theme.color.secondary : darken(0.18, theme.color.secondary)}`,\n          boxShadow: '0px 0px 0px 9999px rgba(27, 28, 29, 0.2)',\n        },\n        tooltip: {\n          width: 280,\n          color: theme.color.lightest,\n          background:\n            theme.base === 'light' ? theme.color.secondary : darken(0.18, theme.color.secondary),\n        },\n        options: {\n          zIndex: 9998,\n          primaryColor:\n            theme.base === 'light' ? theme.color.secondary : darken(0.18, theme.color.secondary),\n          arrowColor:\n            theme.base === 'light' ? theme.color.secondary : darken(0.18, theme.color.secondary),\n        },\n      }}\n    />\n  );\n};\n\nlet root: ReturnType<typeof createRoot> | null = null;\n\nTourGuide.render = (props: ComponentProps<typeof TourGuide> | null) => {\n  let container = document.getElementById('storybook-tour');\n  if (!container) {\n    container = document.createElement('div');\n    container.id = 'storybook-tour';\n    document.body.appendChild(container);\n  }\n  root = root ?? createRoot(container);\n  root.render(\n    props ? (\n      <ThemeProvider theme={convert(themes.light)}>\n        <TourGuide\n          {...props}\n          onComplete={() => {\n            props.onComplete?.();\n            root?.render(null);\n            root = null;\n          }}\n          onDismiss={() => {\n            props.onDismiss?.();\n            root?.render(null);\n            root = null;\n          }}\n        />\n      </ThemeProvider>\n    ) : null\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/components/TourGuide/TourTooltip.tsx",
    "content": "import type { FC } from 'react';\nimport React, { useEffect } from 'react';\n\nimport { Button } from 'storybook/internal/components';\n\nimport { CloseAltIcon } from '@storybook/icons';\n\nimport { darken, lighten, transparentize } from 'polished';\nimport type { Step, TooltipRenderProps } from 'react-joyride';\nimport { color, styled } from 'storybook/theming';\n\nconst ONBOARDING_ARROW_STYLE_ID = 'storybook-onboarding-arrow-style';\n\nconst TooltipBody = styled.div`\n  padding: 15px;\n  border-radius: 5px;\n`;\n\nconst Wrapper = styled.div`\n  display: flex;\n  flex-direction: column;\n  align-items: flex-start;\n`;\n\nconst TooltipHeader = styled.div`\n  display: flex;\n  align-items: center;\n  align-self: stretch;\n  justify-content: space-between;\n  margin: -5px -5px 5px 0;\n`;\n\nconst TooltipTitle = styled.div`\n  line-height: 18px;\n  font-weight: 700;\n  font-size: 14px;\n  margin: 5px 5px 5px 0;\n`;\n\nconst TooltipContent = styled.p`\n  font-size: 14px;\n  line-height: 18px;\n  text-align: start;\n  text-wrap: balance;\n  margin: 0;\n  margin-top: 5px;\n`;\n\nconst TooltipFooter = styled.div`\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  margin-top: 15px;\n`;\n\nconst Count = styled.span`\n  font-size: 13px;\n`;\n\nconst NextButton = styled(Button)(({ theme }) => ({\n  background: theme.color.lightest,\n  border: 'none',\n  boxShadow: 'none',\n  color: theme.base === 'light' ? theme.color.secondary : darken(0.18, theme.color.secondary),\n\n  '&:hover, &:focus': {\n    background: transparentize(0.1, theme.color.lightest),\n    color:\n      theme.base === 'light'\n        ? lighten(0.1, theme.color.secondary)\n        : darken(0.3, theme.color.secondary),\n  },\n}));\n\ntype TooltipProps = {\n  index: number;\n  size: number;\n  step: Partial<\n    Pick<\n      // this only seems to happen during the check task, nos in vsCode..\n      // this seems to be 'any' in vsCode because of it?\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore (hide property 'input' circularly references itself in mapped type)\n      Step,\n      | 'title'\n      | 'content'\n      | 'target'\n      | 'offset'\n      | 'placement'\n      | 'disableOverlay'\n      | 'disableBeacon'\n      | 'floaterProps'\n      | 'spotlightClicks'\n      | 'styles'\n    > & {\n      hideNextButton: boolean;\n    }\n  >;\n  closeProps: TooltipRenderProps['closeProps'];\n  primaryProps: TooltipRenderProps['primaryProps'];\n  tooltipProps: TooltipRenderProps['tooltipProps'];\n};\n\nexport const TourTooltip: FC<TooltipProps> = ({\n  index,\n  size,\n  step,\n  closeProps,\n  primaryProps,\n  tooltipProps,\n}) => {\n  useEffect(() => {\n    const style = document.createElement('style');\n    style.id = ONBOARDING_ARROW_STYLE_ID;\n    style.innerHTML = `\n      .__floater__arrow { container-type: size; }\n      .__floater__arrow span { background: ${color.secondary}; }\n      .__floater__arrow span::before, .__floater__arrow span::after {\n        content: '';\n        display: block;\n        width: 2px;\n        height: 2px;\n        background: ${color.secondary};\n        box-shadow: 0 0 0 2px ${color.secondary};\n        border-radius: 3px;\n        flex: 0 0 2px;\n      }\n      @container (min-height: 1px) {\n        .__floater__arrow span { flex-direction: column; }\n      }\n    `;\n    document.head.appendChild(style);\n    return () => document.getElementById(ONBOARDING_ARROW_STYLE_ID)?.remove();\n  }, []);\n\n  return (\n    <TooltipBody {...tooltipProps} style={step.styles?.tooltip}>\n      <Wrapper>\n        <TooltipHeader>\n          {step.title && <TooltipTitle>{step.title}</TooltipTitle>}\n          <Button\n            {...closeProps}\n            onClick={closeProps.onClick as any}\n            variant=\"solid\"\n            padding=\"small\"\n            ariaLabel=\"Close\"\n          >\n            <CloseAltIcon />\n          </Button>\n        </TooltipHeader>\n        <TooltipContent>{step.content}</TooltipContent>\n      </Wrapper>\n      <TooltipFooter id=\"buttonNext\">\n        <Count>\n          {index + 1} of {size}\n        </Count>\n        {!step.hideNextButton && (\n          <NextButton {...primaryProps}>{index + 1 === size ? 'Done' : 'Next'}</NextButton>\n        )}\n      </TooltipFooter>\n    </TooltipBody>\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/components/error-boundary/ManagerErrorBoundary.stories.tsx",
    "content": "import React, { useEffect, useState } from 'react';\n\nimport { expect, fn, spyOn } from 'storybook/test';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { ManagerErrorBoundary } from './ManagerErrorBoundary.tsx';\n\n// Mocks for play assertions: set by decorator, asserted in play functions\nlet consoleErrorSpy: ReturnType<typeof spyOn>;\nconst sendTelemetryErrorMock = fn();\n\n// Stable wrapper: only cleanup in useEffect so teardown runs correctly with React Strict Mode.\n// Setup must run synchronously in the decorator so the spy is in place before Story renders.\nconst RestoreGlobals = ({\n  children,\n  originalSendTelemetryError,\n}: {\n  children: React.ReactNode;\n  originalSendTelemetryError: typeof globalThis.sendTelemetryError;\n}) => {\n  useEffect(\n    () => () => {\n      consoleErrorSpy.mockRestore();\n      globalThis.sendTelemetryError = originalSendTelemetryError;\n    },\n    [originalSendTelemetryError]\n  );\n  return <>{children}</>;\n};\n\n// Component that throws an error immediately when rendered\nconst ThrowingComponent = ({ shouldThrow = true }: { shouldThrow?: boolean }) => {\n  if (shouldThrow) {\n    throw new Error('This is a test error thrown by ThrowingComponent');\n  }\n  return <div>This component rendered successfully!</div>;\n};\n\n// Component that throws an error on interaction\nconst InteractiveThrowingComponent = () => {\n  const [shouldThrow, setShouldThrow] = useState(false);\n\n  if (shouldThrow) {\n    throw new Error('Error triggered by user interaction');\n  }\n\n  return <button onClick={() => setShouldThrow(true)}>Click to trigger error</button>;\n};\n\n// Component that throws an error with a long stack trace\nconst DeepErrorComponent = () => {\n  const throwDeepError = () => {\n    const level1 = () => {\n      const level2 = () => {\n        const level3 = () => {\n          throw new Error('A deeply nested error with a long stack trace for testing purposes');\n        };\n        level3();\n      };\n      level2();\n    };\n    level1();\n  };\n\n  throwDeepError();\n  return null;\n};\n\nconst meta = preview.meta({\n  title: 'ManagerErrorBoundary',\n  component: ManagerErrorBoundary,\n  parameters: {\n    layout: 'fullscreen',\n    test: {\n      // Ignore unhandled errors in tests since we're testing error boundaries\n      dangerouslyIgnoreUnhandledErrors: true,\n    },\n    chromatic: {\n      // Pause at the error state for visual testing\n      pauseAnimationAtEnd: true,\n    },\n  },\n  decorators: [\n    (Story) => {\n      consoleErrorSpy = spyOn(console, 'error').mockImplementation(() => {});\n      sendTelemetryErrorMock.mockClear();\n      const originalSendTelemetryError = globalThis.sendTelemetryError;\n      globalThis.sendTelemetryError = sendTelemetryErrorMock;\n      return (\n        <RestoreGlobals originalSendTelemetryError={originalSendTelemetryError}>\n          <Story />\n        </RestoreGlobals>\n      );\n    },\n  ],\n});\n\nexport default meta;\n\nexport const WithError = meta.story({\n  render: () => (\n    <ManagerErrorBoundary>\n      <ThrowingComponent />\n    </ManagerErrorBoundary>\n  ),\n  play: async ({ canvas }) => {\n    await expect(canvas.getByTestId('manager-error-boundary')).toBeInTheDocument();\n    await expect(canvas.getByText('Something went wrong')).toBeInTheDocument();\n    await expect(\n      canvas.getByText('This is a test error thrown by ThrowingComponent')\n    ).toBeInTheDocument();\n\n    await expect(consoleErrorSpy).toHaveBeenCalledWith(\n      'Storybook Manager UI Error:',\n      expect.any(Error)\n    );\n    await expect(consoleErrorSpy).toHaveBeenCalledWith('Component Stack:', expect.any(String));\n\n    await expect(sendTelemetryErrorMock).toHaveBeenCalledTimes(1);\n    await expect(sendTelemetryErrorMock).toHaveBeenCalledWith(\n      expect.objectContaining({\n        message: 'This is a test error thrown by ThrowingComponent',\n      })\n    );\n  },\n});\n\nexport const WithDeepStackTrace = meta.story({\n  render: () => (\n    <ManagerErrorBoundary>\n      <DeepErrorComponent />\n    </ManagerErrorBoundary>\n  ),\n});\n\nexport const WithoutError = meta.story({\n  render: () => (\n    <ManagerErrorBoundary>\n      <div style={{ padding: 40 }}>\n        <h1>Everything is fine!</h1>\n        <p>This content should render normally when there is no error.</p>\n      </div>\n    </ManagerErrorBoundary>\n  ),\n  play: async ({ canvas }) => {\n    await expect(canvas.getByText('Everything is fine!')).toBeInTheDocument();\n    await expect(\n      canvas.getByText('This content should render normally when there is no error.')\n    ).toBeInTheDocument();\n    await expect(canvas.queryByTestId('manager-error-boundary')).not.toBeInTheDocument();\n  },\n});\n\nexport const InteractiveError = meta.story({\n  render: () => (\n    <ManagerErrorBoundary>\n      <div style={{ padding: 40, textAlign: 'center' }}>\n        <h2>Interactive Error Test</h2>\n        <p>Click the button below to trigger an error and see the error boundary in action.</p>\n        <InteractiveThrowingComponent />\n      </div>\n    </ManagerErrorBoundary>\n  ),\n});\n\nexport const CustomErrorMessage = meta.story({\n  render: () => {\n    const CustomError = () => {\n      throw new Error(\n        'Custom error: Unable to load addons configuration. Please check your manager.ts file.'\n      );\n    };\n\n    return (\n      <ManagerErrorBoundary>\n        <CustomError />\n      </ManagerErrorBoundary>\n    );\n  },\n  play: async ({ canvas }) => {\n    await expect(canvas.getByTestId('manager-error-boundary')).toBeInTheDocument();\n    await expect(\n      canvas.getByText(\n        'Custom error: Unable to load addons configuration. Please check your manager.ts file.'\n      )\n    ).toBeInTheDocument();\n\n    await expect(sendTelemetryErrorMock).toHaveBeenCalledWith(\n      expect.objectContaining({\n        message:\n          'Custom error: Unable to load addons configuration. Please check your manager.ts file.',\n      })\n    );\n  },\n});\n"
  },
  {
    "path": "code/core/src/manager/components/error-boundary/ManagerErrorBoundary.tsx",
    "content": "import type { ReactNode } from 'react';\nimport React, { Component } from 'react';\n\nimport { Badge, Button, Collapsible } from 'storybook/internal/components';\n\nimport { SyncIcon, UnfoldIcon } from '@storybook/icons';\n\nimport { transparentize } from 'polished';\nimport { styled } from 'storybook/theming';\n\nconst Container = styled.div(({ theme }) => ({\n  display: 'flex',\n  justifyContent: 'center',\n  alignItems: 'center',\n  width: '100vw',\n  height: '100vh',\n  backgroundColor: theme.background.app,\n  color: theme.color.defaultText,\n  fontFamily: theme.typography.fonts.base,\n}));\n\nconst Content = styled.div(({ theme }) => ({\n  display: 'flex',\n  flexDirection: 'column',\n  justifyContent: 'space-between',\n  width: '80%',\n  height: '80%',\n  padding: 20,\n  gap: 20,\n  backgroundColor: theme.background.content,\n  borderRadius: theme.appBorderRadius,\n  border: `1px solid ${theme.color.negative}`,\n  boxShadow: '0 0 64px rgba(0, 0, 0, 0.1)',\n  overflow: 'auto',\n}));\n\nconst Info = styled.div(({ theme }) => ({\n  display: 'flex',\n  flexDirection: 'column',\n  alignItems: 'start',\n  gap: 15,\n}));\n\nconst Heading = styled.h1(({ theme }) => ({\n  display: 'flex',\n  alignItems: 'center',\n  margin: 0,\n  gap: 10,\n  fontSize: theme.typography.size.s2,\n  fontWeight: theme.typography.weight.bold,\n  color: theme.color.defaultText,\n}));\n\nconst SubHeading = styled.p(({ theme }) => ({\n  fontSize: theme.typography.size.s2,\n  color: theme.textMutedColor,\n  margin: 0,\n  lineHeight: 1.4,\n  textWrap: 'balance',\n}));\n\nconst ErrorWrapper = styled.div(({ theme }) => ({\n  display: 'flex',\n  flexDirection: 'column-reverse',\n  width: '100%',\n  flex: '0 0 auto',\n  border: `1px solid ${theme.appBorderColor}`,\n  borderRadius: theme.appBorderRadius,\n  pre: {\n    borderRadius: 0,\n  },\n}));\n\nconst CollapseToggle = styled.div(({ theme }) => ({\n  flex: '0 0 auto',\n  display: 'flex',\n  alignItems: 'center',\n  gap: 10,\n  height: 40,\n  width: '100%',\n  padding: '0 10px',\n  cursor: 'pointer',\n  fontSize: theme.typography.size.s2,\n  fontWeight: theme.typography.weight.bold,\n  color: theme.color.defaultText,\n  userSelect: 'none',\n  '&:hover': {\n    backgroundColor: theme.base === 'light' ? 'rgba(0, 0, 0, 0.02)' : 'rgba(255, 255, 255, 0.03)',\n  },\n  svg: {\n    color: theme.textMutedColor,\n  },\n}));\n\nconst ErrorMessage = styled.pre(({ theme }) => ({\n  order: 1,\n  padding: '11px 15px',\n  margin: 0,\n  fontSize: theme.typography.size.s1,\n  color: theme.color.negativeText,\n  backgroundColor: transparentize(theme.base === 'light' ? 0.95 : 0.9, theme.color.negative),\n  borderBottom: `1px solid ${theme.appBorderColor}`,\n  whiteSpace: 'pre-wrap',\n  wordBreak: 'break-word',\n  fontFamily: theme.typography.fonts.mono,\n  lineHeight: '18px',\n}));\n\nconst ErrorStack = styled.pre(({ theme }) => ({\n  padding: 15,\n  margin: 0,\n  fontSize: theme.typography.size.s1,\n  color: theme.textMutedColor,\n  borderBottom: `1px solid ${theme.appBorderColor}`,\n  borderRadius: 0,\n  whiteSpace: 'pre-wrap',\n  wordBreak: 'break-word',\n  fontFamily: theme.typography.fonts.mono,\n}));\n\ninterface ErrorFallbackProps {\n  error: Error;\n  errorInfo: React.ErrorInfo | null;\n}\n\nconst ErrorFallback = ({ error, errorInfo }: ErrorFallbackProps) => {\n  return (\n    <Container data-testid=\"manager-error-boundary\">\n      <Content>\n        <Info>\n          <Heading>\n            <Badge status=\"negative\">Error</Badge>\n            <span>Something went wrong</span>\n          </Heading>\n          <SubHeading>\n            The Storybook Manager UI encountered an error. This is usually caused by custom addon\n            code or configuration. Please check your browser console for more details. Try clearing\n            browser storage if the issue persists.\n          </SubHeading>\n          <Button asChild size=\"medium\">\n            <a href={window.location.origin + window.location.pathname.replace('iframe.html', '')}>\n              <SyncIcon size={14} />\n              Reload Storybook\n            </a>\n          </Button>\n        </Info>\n        <ErrorWrapper>\n          <ErrorMessage>{error.message || 'Unknown error'}</ErrorMessage>\n          <Collapsible\n            collapsed={true}\n            summary={({ isCollapsed, toggleCollapsed }) => (\n              <CollapseToggle onClick={toggleCollapsed}>\n                <UnfoldIcon />\n                {isCollapsed ? 'Expand error' : 'Collapse error'}\n              </CollapseToggle>\n            )}\n          >\n            {(error.stack || errorInfo?.componentStack) && (\n              <ErrorStack>\n                {error.stack}\n                {errorInfo?.componentStack && `\\n\\nComponent Stack:${errorInfo.componentStack}`}\n              </ErrorStack>\n            )}\n          </Collapsible>\n        </ErrorWrapper>\n      </Content>\n    </Container>\n  );\n};\n\ninterface ManagerErrorBoundaryProps {\n  children: ReactNode;\n}\n\ninterface ManagerErrorBoundaryState {\n  hasError: boolean;\n  error: Error | null;\n  errorInfo: React.ErrorInfo | null;\n}\n\nexport class ManagerErrorBoundary extends Component<\n  ManagerErrorBoundaryProps,\n  ManagerErrorBoundaryState\n> {\n  constructor(props: ManagerErrorBoundaryProps) {\n    super(props);\n    this.state = { hasError: false, error: null, errorInfo: null };\n  }\n\n  static getDerivedStateFromError(error: Error): Partial<ManagerErrorBoundaryState> {\n    return { hasError: true, error };\n  }\n\n  componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n    // Log error to console for debugging\n    console.error('Storybook Manager UI Error:', error);\n    console.error('Component Stack:', errorInfo.componentStack);\n    this.setState({ errorInfo });\n\n    if (typeof globalThis.sendTelemetryError === 'function') {\n      globalThis.sendTelemetryError(error);\n    }\n  }\n\n  render() {\n    const { hasError, error, errorInfo } = this.state;\n    const { children } = this.props;\n\n    if (hasError && error) {\n      return <ErrorFallback error={error} errorInfo={errorInfo} />;\n    }\n\n    return children;\n  }\n}\n"
  },
  {
    "path": "code/core/src/manager/components/error-boundary/index.ts",
    "content": "export { ManagerErrorBoundary } from './ManagerErrorBoundary.tsx';\n"
  },
  {
    "path": "code/core/src/manager/components/layout/Drag.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { expect, userEvent, within } from 'storybook/test';\n\nimport { Drag } from './Drag.tsx';\n\n/**\n * Presentational drag-handle component used for the sidebar and addon-panel resizers.\n *\n * Covers positioning, tooltips and hover/focus states, and ARIA attribute markup. The actual\n * keyboard-resize logic lives in `useDragging` and can be tested in Layout stories.\n */\nconst meta = {\n  title: 'Layout/Drag',\n  component: Drag,\n  parameters: {\n    layout: 'centered',\n  },\n  decorators: [\n    (storyFn) => (\n      // Drag uses `position: absolute` so it needs a positioned parent.\n      <div\n        style={{\n          position: 'relative',\n          width: 200,\n          height: 200,\n          border: '2px dashed #aaa',\n          background: 'thistle',\n        }}\n      >\n        {storyFn()}\n      </div>\n    ),\n  ],\n} satisfies Meta<typeof Drag>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const PositionLeft: Story = {\n  name: 'Position: left (sidebar)',\n  args: {\n    position: 'left',\n    'aria-label': 'Sidebar resize handle',\n    'aria-valuenow': 200,\n    'aria-valuemax': 500,\n  },\n  play: async ({ canvas, step }) => {\n    const handle = canvas.getByRole('separator');\n\n    await step('Has aria-orientation=\"vertical\" for left position', async () => {\n      expect(handle).toHaveAttribute('aria-orientation', 'vertical');\n    });\n\n    await step('Shows on the right of the parent element', async () => {\n      handle.focus();\n      const parentRect = handle.parentElement?.getBoundingClientRect();\n      const handleRect = handle.getBoundingClientRect();\n      expect(handleRect.left).toBeGreaterThan(parentRect?.left ?? 0);\n    });\n  },\n};\n\nexport const PositionRight: Story = {\n  name: 'Position: right (addon panel)',\n  args: {\n    position: 'right',\n    'aria-label': 'Addon panel resize handle',\n    'aria-valuenow': 300,\n    'aria-valuemax': 600,\n  },\n  play: async ({ canvas, step }) => {\n    const handle = canvas.getByRole('separator');\n\n    await step('Has aria-orientation=\"vertical\" for right position', async () => {\n      expect(handle).toHaveAttribute('aria-orientation', 'vertical');\n    });\n\n    await step('Shows on the left of the parent element', async () => {\n      handle.focus();\n      const parentRect = handle.parentElement?.getBoundingClientRect();\n      const handleRect = handle.getBoundingClientRect();\n      expect(handleRect.left).toBeLessThan(parentRect?.left ?? 0);\n    });\n  },\n};\n\nexport const PositionBottom: Story = {\n  name: 'Position: bottom (bottom panel)',\n  args: {\n    position: 'bottom',\n    'aria-label': 'Addon panel resize handle',\n    'aria-valuenow': 150,\n    'aria-valuemax': 400,\n  },\n  play: async ({ canvas, step }) => {\n    const handle = canvas.getByRole('separator');\n\n    await step('Has aria-orientation=\"horizontal\" for bottom position', async () => {\n      expect(handle).toHaveAttribute('aria-orientation', 'horizontal');\n    });\n\n    await step('Shows on the top of the parent element', async () => {\n      handle.focus();\n      const parentRect = handle.parentElement?.getBoundingClientRect();\n      const handleRect = handle.getBoundingClientRect();\n      expect(handleRect.top).toBeLessThan(parentRect?.top ?? 0);\n    });\n  },\n};\n\nexport const PositionTop: Story = {\n  name: 'Position: top',\n  args: {\n    position: 'top',\n    'aria-label': 'Top panel resize handle',\n    'aria-valuenow': 150,\n    'aria-valuemax': 400,\n  },\n  play: async ({ canvas, step }) => {\n    const handle = canvas.getByRole('separator');\n\n    await step('Has aria-orientation=\"horizontal\" for top position', async () => {\n      expect(handle).toHaveAttribute('aria-orientation', 'horizontal');\n    });\n\n    await step('Shows on the bottom of the parent element', async () => {\n      handle.focus();\n      const parentRect = handle.parentElement?.getBoundingClientRect();\n      const handleRect = handle.getBoundingClientRect();\n      expect(handleRect.top).toBeGreaterThan(parentRect?.top ?? 0);\n    });\n  },\n};\n\nexport const AriaRole: Story = {\n  name: 'ARIA: role separator',\n  args: {\n    position: 'left',\n    'aria-label': 'Sidebar resize handle',\n    'aria-valuenow': 240,\n    'aria-valuemax': 480,\n  },\n  play: async ({ canvas, step }) => {\n    await step('Has role=\"separator\"', async () => {\n      const handle = canvas.getByRole('separator');\n      expect(handle).toBeInTheDocument();\n    });\n  },\n};\n\nexport const AriaOrientationVertical: Story = {\n  name: 'ARIA: orientation vertical',\n  args: {\n    position: 'left',\n    'aria-label': 'Sidebar resize handle',\n    'aria-valuenow': 240,\n    'aria-valuemax': 480,\n  },\n  play: async ({ canvas, step }) => {\n    await step('Has aria-orientation=\"vertical\" for left position', async () => {\n      const handle = canvas.getByRole('separator');\n      expect(handle).toHaveAttribute('aria-orientation', 'vertical');\n    });\n  },\n};\n\nexport const AriaOrientationHorizontal: Story = {\n  name: 'ARIA: orientation horizontal',\n  args: {\n    position: 'bottom',\n    'aria-label': 'Bottom panel resize handle',\n    'aria-valuenow': 150,\n    'aria-valuemax': 400,\n  },\n  play: async ({ canvas, step }) => {\n    await step('Has aria-orientation=\"horizontal\" for bottom position', async () => {\n      const handle = canvas.getByRole('separator');\n      expect(handle).toHaveAttribute('aria-orientation', 'horizontal');\n    });\n  },\n};\n\nexport const AriaLabel: Story = {\n  name: 'ARIA: aria-label',\n  args: {\n    position: 'bottom',\n    'aria-label': 'Specific resize handle label',\n    'aria-valuenow': 150,\n    'aria-valuemax': 400,\n  },\n  play: async ({ canvas, step }) => {\n    await step('Has correct aria-label', async () => {\n      const handle = canvas.getByRole('separator');\n      expect(handle).toHaveAttribute('aria-label', 'Specific resize handle label');\n    });\n  },\n};\n\nexport const AriaValue: Story = {\n  name: 'ARIA: aria-value* attributes',\n  args: {\n    position: 'bottom',\n    'aria-label': 'Specific resize handle label',\n    'aria-valuenow': 150,\n    'aria-valuemax': 400,\n  },\n  play: async ({ canvas, step }) => {\n    await step('Has correct aria-value* attributes', async () => {\n      const handle = canvas.getByRole('separator');\n      expect(handle).toHaveAttribute('aria-valuemin', '0');\n      expect(handle).toHaveAttribute('aria-valuenow', '150');\n      expect(handle).toHaveAttribute('aria-valuemax', '400');\n    });\n  },\n};\n\nexport const FocusTooltipVertical: Story = {\n  name: 'Keyboard: vertical focus tooltip',\n  args: {\n    position: 'left',\n    'aria-label': 'Sidebar resize handle',\n    'aria-valuenow': 200,\n    'aria-valuemax': 500,\n  },\n  play: async ({ canvas, step }) => {\n    const handle = canvas.getByRole('separator');\n\n    await step('Tab onto the handle', async () => {\n      await userEvent.tab();\n      expect(handle).toHaveFocus();\n    });\n\n    await step('Tooltip with ← → hint is visible', async () => {\n      // The tooltip is rendered in a portal outside canvas.\n      const tooltip = await within(document.body).findByText('← → to resize');\n      expect(tooltip).toBeInTheDocument();\n    });\n\n    await step('Tooltip disappears on blur', async () => {\n      handle.blur();\n      // Give the tooltip time to un-mount / fade out.\n      await new Promise((r) => setTimeout(r, 250));\n      const tooltip = within(document.body).queryByText('← → to resize');\n      expect(tooltip).not.toBeInTheDocument();\n    });\n  },\n};\n\nexport const FocusTooltipHorizontal: Story = {\n  name: 'Keyboard: horizontal focus tooltip',\n  args: {\n    position: 'bottom',\n    'aria-label': 'Bottom panel resize handle',\n    'aria-valuenow': 150,\n    'aria-valuemax': 400,\n  },\n  play: async ({ canvas, step }) => {\n    const handle = canvas.getByRole('separator');\n\n    await step('Tab onto the handle', async () => {\n      await userEvent.tab();\n      expect(handle).toHaveFocus();\n    });\n\n    await step('Tooltip with ↑ ↓ hint is visible', async () => {\n      const tooltip = await within(document.body).findByText('↑ ↓ to resize');\n      expect(tooltip).toBeInTheDocument();\n    });\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/components/layout/Drag.tsx",
    "content": "import React, { forwardRef } from 'react';\n\nimport { styled } from 'storybook/theming';\n\nimport type { PopperPlacement } from '../../../components/index.ts';\nimport { TooltipNote } from '../../../components/components/tooltip/TooltipNote.tsx';\nimport { TooltipProvider } from '../../../components/components/tooltip/TooltipProvider.tsx';\n\ninterface DragProps {\n  /** Which side the drag handle sits on, relative to the content it resizes. Determines orientation. */\n  position: 'left' | 'right' | 'top' | 'bottom';\n\n  /** Whether the drag handle overlaps the adjacent content area. */\n  overlapping?: boolean;\n\n  /** Accessible label describing what this separator resizes. */\n  'aria-label': string;\n\n  /** Current size (in pixels) of the region controlled by this separator. */\n  'aria-valuenow': number;\n\n  /** Maximum size (in pixels) for the region controlled by this separator. */\n  'aria-valuemax'?: number;\n}\n\nconst oppositePosition: Record<string, PopperPlacement> = {\n  left: 'right',\n  right: 'left',\n  top: 'bottom',\n  bottom: 'top',\n};\n\n/**\n * Drag handle for the sidebar and panel resizers. Can be horizontal (bottom panel) or vertical\n * (sidebar or right panel). Implements the WAI-ARIA separator role with keyboard resize support.\n *\n * The component automatically sets `role=\"separator\"`, `tabIndex={0}`, and `aria-valuemin={0}`. A\n * tooltip is shown on focus advertising the arrow keys available for keyboard resizing.\n */\nexport const Drag = forwardRef<HTMLDivElement, DragProps>(function Drag(props, ref) {\n  const {\n    overlapping,\n    position,\n    'aria-label': ariaLabel,\n    'aria-valuenow': ariaValueNow,\n    'aria-valuemax': ariaValueMax,\n    ...rest\n  } = props;\n\n  const orientation = position === 'left' || position === 'right' ? 'vertical' : 'horizontal';\n  const tooltipNote = orientation === 'vertical' ? '← → to resize' : '↑ ↓ to resize';\n\n  return (\n    <TooltipProvider\n      triggerOnFocusOnly\n      placement={oppositePosition[position]}\n      tooltip={<TooltipNote note={tooltipNote} />}\n    >\n      <DragHandle\n        ref={ref}\n        $orientation={orientation}\n        $overlapping={overlapping}\n        $position={position}\n        role=\"separator\"\n        tabIndex={0}\n        aria-orientation={orientation}\n        aria-label={ariaLabel}\n        aria-valuenow={ariaValueNow}\n        aria-valuemin={0}\n        aria-valuemax={ariaValueMax}\n        {...rest}\n      />\n    </TooltipProvider>\n  );\n});\n\nconst DragHandle = styled.div<{\n  $orientation?: 'horizontal' | 'vertical';\n  $overlapping?: boolean;\n  $position: 'left' | 'right' | 'top' | 'bottom';\n}>(\n  ({ theme }) => ({\n    position: 'absolute',\n    opacity: 0,\n    transition: 'opacity 0.2s ease-in-out',\n    zIndex: 100,\n\n    '&:after': {\n      content: '\"\"',\n      display: 'block',\n      backgroundColor: theme.color.secondary,\n    },\n\n    '&:hover': {\n      opacity: 1,\n    },\n  }),\n  ({ theme, $orientation = 'vertical' }) => ({\n    '&:focus-visible': {\n      opacity: 1,\n      outline: '2px solid transparent',\n      ...($orientation === 'horizontal' ? { height: 7 } : { width: 7 }),\n      boxShadow: `inset 0 0 0 4px ${theme.color.secondary}`,\n\n      '@media (forced-colors: active)': {\n        outline: '2px solid Highlight',\n      },\n    },\n  }),\n  ({ $orientation = 'vertical', $overlapping = true, $position = 'left' }) =>\n    $orientation === 'vertical'\n      ? {\n          // This is an old code smell, where 10px matches the sidebar and 13px matches the addon panel.\n          // It should be tidied up at some point.\n          width: $overlapping ? ($position === 'left' ? 10 : 13) : 7,\n          height: '100%',\n          top: 0,\n          right: $position === 'left' ? -7 : undefined,\n          left: $position === 'right' ? -7 : undefined,\n\n          '&:after': {\n            width: 1,\n            height: '100%',\n            marginLeft: $position === 'left' ? 3 : 6,\n          },\n\n          '&:hover': {\n            cursor: 'col-resize',\n          },\n        }\n      : {\n          width: '100%',\n          height: $overlapping ? 13 : 7,\n          top: $position === 'bottom' ? -7 : undefined,\n          bottom: $position === 'top' ? -7 : undefined,\n          left: 0,\n\n          '&:after': {\n            width: '100%',\n            height: 1,\n            marginTop: 6,\n          },\n\n          '&:hover': {\n            cursor: 'row-resize',\n          },\n        }\n);\n"
  },
  {
    "path": "code/core/src/manager/components/layout/Layout.stories.tsx",
    "content": "import type { FC, PropsWithChildren } from 'react';\nimport React, { useState } from 'react';\n\nimport { LocationProvider } from 'storybook/internal/router';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { startCase } from 'es-toolkit/string';\nimport { action } from 'storybook/actions';\nimport { ManagerContext } from 'storybook/manager-api';\nimport { expect, fn, userEvent, waitFor, within } from 'storybook/test';\nimport { styled } from 'storybook/theming';\n\nimport { isChromatic } from '../../../../../.storybook/isChromatic.ts';\nimport {\n  MINIMUM_HORIZONTAL_PANEL_HEIGHT_PX,\n  MINIMUM_RIGHT_PANEL_WIDTH_PX,\n  MINIMUM_SIDEBAR_WIDTH_PX,\n} from '../../constants.ts';\nimport { Layout } from './Layout.tsx';\nimport { LayoutProvider } from './LayoutProvider.tsx';\n\nconst PlaceholderBlock = styled.div({\n  width: '100%',\n  height: '100%',\n  display: 'flex',\n  justifyContent: 'center',\n  alignItems: 'center',\n  overflow: 'hidden',\n});\n\nconst PlaceholderClock: FC<{ id: string } & PropsWithChildren> = ({ children, id }) => {\n  const [count, setCount] = React.useState(0);\n  React.useEffect(() => {\n    if (isChromatic()) {\n      return;\n    }\n    const interval = setInterval(() => {\n      setCount(count + 1);\n    }, 1000);\n    return () => clearInterval(interval);\n  }, [count]);\n  return (\n    <PlaceholderBlock>\n      <h2 data-chromatic=\"ignore\">{count}</h2>\n      <button data-testid={id} className=\"sb-sr-only\">\n        Focusable\n      </button>\n      {children}\n    </PlaceholderBlock>\n  );\n};\n\nconst MockSidebar: FC<any> = () => <PlaceholderClock id=\"sidebar\" />;\n\nconst MockPreview: FC<any> = () => <PlaceholderClock id=\"preview\" />;\n\nconst MockPanel: FC<any> = () => <PlaceholderClock id=\"panel\" />;\n\nconst MockPage: FC<any> = () => <PlaceholderClock id=\"page\" />;\n\nconst defaultState = {\n  navSize: 150,\n  bottomPanelHeight: 150,\n  rightPanelWidth: 150,\n  panelPosition: 'bottom',\n  viewMode: 'story',\n} as const;\n\nconst renderLabel = ({ name }: { name: string }) => startCase(name);\n\nconst mockManagerStore: any = {\n  state: {\n    index: {\n      someRootId: {\n        type: 'root',\n        id: 'someRootId',\n        name: 'root',\n        renderLabel,\n      },\n      someComponentId: {\n        type: 'component',\n        id: 'someComponentId',\n        name: 'component',\n        parent: 'someRootId',\n        renderLabel,\n      },\n      someStoryId: {\n        type: 'story',\n        subtype: 'story',\n        id: 'someStoryId',\n        name: 'story',\n        parent: 'someComponentId',\n        renderLabel,\n      },\n    },\n  },\n  api: {\n    getCurrentStoryData: fn(() => {\n      return mockManagerStore.state.index.someStoryId;\n    }),\n  },\n};\n\nconst meta = {\n  title: 'Layout',\n  component: Layout,\n  args: {\n    managerLayoutState: defaultState,\n    slotMain: <MockPreview />,\n    slotSidebar: <MockSidebar />,\n    slotPanel: <MockPanel />,\n    slotPages: <MockPage />,\n    setManagerLayoutState: fn(),\n    hasTab: false,\n  },\n  globals: { sb_theme: 'light' },\n  parameters: { layout: 'fullscreen' },\n  decorators: [\n    (storyFn) => (\n      <ManagerContext.Provider value={mockManagerStore}>\n        <LocationProvider>\n          <LayoutProvider>{storyFn()}</LayoutProvider>\n        </LocationProvider>\n      </ManagerContext.Provider>\n    ),\n  ],\n  render: (args) => {\n    const [managerLayoutState, setManagerLayoutState] = useState(args.managerLayoutState);\n\n    return (\n      <Layout\n        {...args}\n        managerLayoutState={managerLayoutState}\n        setManagerLayoutState={(nextPartialState) => {\n          setManagerLayoutState({ ...managerLayoutState, ...nextPartialState });\n          action('setManagerStoreState')(nextPartialState);\n        }}\n      />\n    );\n  },\n} satisfies Meta<typeof Layout>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Desktop: Story = {};\nexport const Dark: Story = {\n  globals: { sb_theme: 'dark' },\n};\nexport const DesktopHorizontal: Story = {\n  args: {\n    managerLayoutState: { ...defaultState, panelPosition: 'right' },\n  },\n  play: async ({ canvas, step }) => {\n    await step('Verify preview can be focused', async () => {\n      const preview = canvas.getByTestId('preview');\n      preview.focus();\n      expect(preview).toHaveFocus();\n    });\n    await step('Verify panel can be focused', async () => {\n      const panel = canvas.getByTestId('panel');\n      panel.focus();\n      expect(panel).toHaveFocus();\n    });\n  },\n};\n\nexport const DesktopCollapsedPanel: Story = {\n  args: {\n    managerLayoutState: { ...defaultState, bottomPanelHeight: 0 },\n  },\n  play: async ({ canvas, step }) => {\n    await step('Verify panel is aria-hidden and not interactive', async () => {\n      const panel = canvas.queryByTestId('panel');\n\n      const ariaHiddenNode = panel?.closest('[aria-hidden=\"true\"]');\n      expect(ariaHiddenNode).toBeInTheDocument();\n      expect(ariaHiddenNode).toHaveAttribute('aria-hidden', 'true');\n\n      panel?.focus();\n      expect(panel).not.toHaveFocus();\n    });\n  },\n};\n\nexport const DesktopDocs: Story = {\n  args: {\n    managerLayoutState: { ...defaultState, viewMode: 'docs' },\n  },\n  play: async ({ canvas, step }) => {\n    await step('Verify pages main landmark is not rendered', async () => {\n      const pagesMain = canvas.queryByRole('main', { name: 'Main content' });\n      expect(pagesMain).not.toBeInTheDocument();\n    });\n    await step('Verify preview area is rendered', async () => {\n      const preview = canvas.getByTestId('preview');\n      expect(preview).toBeInTheDocument();\n    });\n  },\n};\n\nexport const DesktopPages: Story = {\n  args: {\n    managerLayoutState: { ...defaultState, viewMode: 'settings' },\n  },\n  play: async ({ canvas, step }) => {\n    await step('Verify pages main landmark is rendered', async () => {\n      const pagesMain = canvas.queryByRole('main', { name: 'Main content' });\n      expect(pagesMain).toBeInTheDocument();\n      const page = canvas.getByTestId('page');\n      page.focus();\n      expect(page).toHaveFocus();\n    });\n    await step('Verify preview area is not rendered', async () => {\n      const preview = canvas.queryByTestId('preview');\n      expect(preview).not.toBeInTheDocument();\n    });\n  },\n};\n\nexport const KeyboardSidebarResize: Story = {\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const handle = canvas.getByRole('separator', { name: 'Sidebar resize handle' });\n\n    await step('Focus the sidebar handle', async () => {\n      handle.focus();\n      expect(handle).toHaveFocus();\n    });\n\n    await step('ArrowRight widens the sidebar', async () => {\n      const before = Number(handle.getAttribute('aria-valuenow'));\n      await userEvent.keyboard('{ArrowRight}');\n      await waitFor(() =>\n        expect(Number(handle.getAttribute('aria-valuenow'))).toBeGreaterThan(before)\n      );\n    });\n\n    await step('Shift+ArrowRight widens by a larger step', async () => {\n      const before = Number(handle.getAttribute('aria-valuenow'));\n      await userEvent.keyboard('{Shift>}{ArrowRight}{/Shift}');\n      await waitFor(() =>\n        expect(Number(handle.getAttribute('aria-valuenow')) - before).toBeGreaterThanOrEqual(50)\n      );\n    });\n\n    await step('ArrowLeft narrows the sidebar', async () => {\n      const before = Number(handle.getAttribute('aria-valuenow'));\n      await userEvent.keyboard('{ArrowLeft}');\n      await waitFor(() =>\n        expect(Number(handle.getAttribute('aria-valuenow'))).toBeLessThan(before)\n      );\n    });\n\n    await step('Home collapses the sidebar to 0', async () => {\n      await userEvent.keyboard('{Home}');\n      await waitFor(() => expect(handle).toHaveAttribute('aria-valuenow', '0'));\n    });\n\n    await step('End expands the sidebar to its maximum', async () => {\n      await userEvent.keyboard('{End}');\n      await waitFor(() => {\n        const valuenow = Number(handle.getAttribute('aria-valuenow'));\n        const valuemax = Number(handle.getAttribute('aria-valuemax'));\n        expect(valuenow).toBe(valuemax);\n      });\n    });\n\n    await step('ArrowLeft narrows the sidebar again', async () => {\n      const before = Number(handle.getAttribute('aria-valuenow'));\n      await userEvent.keyboard('{ArrowLeft}');\n      await waitFor(() =>\n        expect(Number(handle.getAttribute('aria-valuenow'))).toBeLessThan(before)\n      );\n    });\n  },\n};\n\nexport const KeyboardSidebarMinSize: Story = {\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const handle = canvas.getByRole('separator', { name: 'Sidebar resize handle' });\n\n    await step('Focus the sidebar handle', async () => {\n      handle.focus();\n      expect(handle).toHaveFocus();\n    });\n\n    await step('Home collapses the sidebar to 0', async () => {\n      await userEvent.keyboard('{Home}');\n      await waitFor(() => expect(handle).toHaveAttribute('aria-valuenow', '0'));\n    });\n\n    await step('ArrowRight brings the sidebar to its min size', async () => {\n      await userEvent.keyboard('{ArrowRight}');\n      await waitFor(() =>\n        expect(handle).toHaveAttribute('aria-valuenow', `${MINIMUM_SIDEBAR_WIDTH_PX}`)\n      );\n    });\n\n    await step('ArrowLeft collapses it again', async () => {\n      await userEvent.keyboard('{ArrowLeft}');\n      await waitFor(() => expect(handle).toHaveAttribute('aria-valuenow', '0'));\n    });\n  },\n};\n\nexport const KeyboardBottomPanelResize: Story = {\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const handle = canvas.getByRole('separator', { name: 'Addon panel resize handle' });\n\n    await step('Focus the panel handle', async () => {\n      handle.focus();\n      expect(handle).toHaveFocus();\n    });\n\n    await step('ArrowUp increases the panel height', async () => {\n      const before = Number(handle.getAttribute('aria-valuenow'));\n      await userEvent.keyboard('{ArrowUp}');\n      await waitFor(() =>\n        expect(Number(handle.getAttribute('aria-valuenow'))).toBeGreaterThan(before)\n      );\n    });\n\n    await step('Shift+ArrowUp increases by a larger step', async () => {\n      const before = Number(handle.getAttribute('aria-valuenow'));\n      await userEvent.keyboard('{Shift>}{ArrowUp}{/Shift}');\n      await waitFor(() =>\n        expect(Number(handle.getAttribute('aria-valuenow')) - before).toBeGreaterThanOrEqual(50)\n      );\n    });\n\n    await step('ArrowDown decreases the panel height', async () => {\n      const before = Number(handle.getAttribute('aria-valuenow'));\n      await userEvent.keyboard('{ArrowDown}');\n      await waitFor(() =>\n        expect(Number(handle.getAttribute('aria-valuenow'))).toBeLessThan(before)\n      );\n    });\n\n    await step('Home collapses the panel to 0', async () => {\n      await userEvent.keyboard('{Home}');\n      await waitFor(() => expect(handle).toHaveAttribute('aria-valuenow', '0'));\n    });\n\n    await step('End expands the panel to its maximum', async () => {\n      await userEvent.keyboard('{End}');\n      await waitFor(() => {\n        const valuenow = Number(handle.getAttribute('aria-valuenow'));\n        const valuemax = Number(handle.getAttribute('aria-valuemax'));\n        expect(valuenow).toBe(valuemax);\n      });\n    });\n\n    await step('ArrowDown decreases the panel height again', async () => {\n      const before = Number(handle.getAttribute('aria-valuenow'));\n      await userEvent.keyboard('{ArrowDown}');\n      await waitFor(() =>\n        expect(Number(handle.getAttribute('aria-valuenow'))).toBeLessThan(before)\n      );\n    });\n  },\n};\n\nexport const KeyboardBottomPanelMinSize: Story = {\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const handle = canvas.getByRole('separator', { name: 'Addon panel resize handle' });\n\n    await step('Focus the addon panel handle', async () => {\n      handle.focus();\n      expect(handle).toHaveFocus();\n    });\n\n    await step('Home collapses the addon panel to 0', async () => {\n      await userEvent.keyboard('{Home}');\n      await waitFor(() => expect(handle).toHaveAttribute('aria-valuenow', '0'));\n    });\n\n    await step('ArrowUp brings the addon panel to its min size', async () => {\n      await userEvent.keyboard('{ArrowUp}');\n      await waitFor(() =>\n        expect(handle).toHaveAttribute('aria-valuenow', `${MINIMUM_HORIZONTAL_PANEL_HEIGHT_PX}`)\n      );\n    });\n\n    await step('ArrowDown collapses it again', async () => {\n      await userEvent.keyboard('{ArrowDown}');\n      await waitFor(() => expect(handle).toHaveAttribute('aria-valuenow', '0'));\n    });\n  },\n};\n\nexport const KeyboardRightPanelResize: Story = {\n  args: {\n    managerLayoutState: { ...defaultState, panelPosition: 'right' },\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const handle = canvas.getByRole('separator', { name: 'Addon panel resize handle' });\n\n    await step('Focus the panel handle', async () => {\n      handle.focus();\n      expect(handle).toHaveFocus();\n    });\n\n    await step('ArrowLeft widens the right panel', async () => {\n      const before = Number(handle.getAttribute('aria-valuenow'));\n      await userEvent.keyboard('{ArrowLeft}');\n      await waitFor(() =>\n        expect(Number(handle.getAttribute('aria-valuenow'))).toBeGreaterThan(before)\n      );\n    });\n\n    await step('Shift+ArrowLeft widens by a larger step', async () => {\n      const before = Number(handle.getAttribute('aria-valuenow'));\n      await userEvent.keyboard('{Shift>}{ArrowLeft}{/Shift}');\n      await waitFor(() =>\n        expect(Number(handle.getAttribute('aria-valuenow')) - before).toBeGreaterThanOrEqual(50)\n      );\n    });\n\n    await step('ArrowRight narrows the right panel', async () => {\n      const before = Number(handle.getAttribute('aria-valuenow'));\n      await userEvent.keyboard('{ArrowRight}');\n      await waitFor(() =>\n        expect(Number(handle.getAttribute('aria-valuenow'))).toBeLessThan(before)\n      );\n    });\n\n    await step('Home collapses the right panel to 0', async () => {\n      await userEvent.keyboard('{Home}');\n      await waitFor(() => expect(handle).toHaveAttribute('aria-valuenow', '0'));\n    });\n\n    await step('End expands the right panel to its maximum', async () => {});\n\n    await step('End expands the right panel to its maximum', async () => {\n      await userEvent.keyboard('{End}');\n      await waitFor(() => {\n        const valuenow = Number(handle.getAttribute('aria-valuenow'));\n        const valuemax = Number(handle.getAttribute('aria-valuemax'));\n        expect(valuenow).toBe(valuemax);\n      });\n    });\n\n    await step('ArrowRight narrows the right panel again', async () => {\n      const before = Number(handle.getAttribute('aria-valuenow'));\n      await userEvent.keyboard('{ArrowRight}');\n      await waitFor(() =>\n        expect(Number(handle.getAttribute('aria-valuenow'))).toBeLessThan(before)\n      );\n    });\n  },\n};\n\nexport const KeyboardRightPanelMinSize: Story = {\n  args: {\n    managerLayoutState: { ...defaultState, panelPosition: 'right' },\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const handle = canvas.getByRole('separator', { name: 'Addon panel resize handle' });\n\n    await step('Focus the addon panel handle', async () => {\n      handle.focus();\n      expect(handle).toHaveFocus();\n    });\n\n    await step('Home collapses the addon panel to 0', async () => {\n      await userEvent.keyboard('{Home}');\n      await waitFor(() => expect(handle).toHaveAttribute('aria-valuenow', '0'));\n    });\n\n    await step('ArrowLeft brings the addon panel to its min size', async () => {\n      await userEvent.keyboard('{ArrowLeft}');\n      await waitFor(() =>\n        expect(handle).toHaveAttribute('aria-valuenow', `${MINIMUM_RIGHT_PANEL_WIDTH_PX}`)\n      );\n    });\n\n    await step('ArrowRight collapses it again', async () => {\n      await userEvent.keyboard('{ArrowRight}');\n      await waitFor(() => expect(handle).toHaveAttribute('aria-valuenow', '0'));\n    });\n  },\n};\n\nexport const Mobile = {\n  parameters: {\n    viewport: {\n      defaultViewport: 'mobile1',\n    },\n    chromatic: { viewports: [320] },\n  },\n};\nexport const MobileDark = {\n  ...Mobile,\n  globals: { sb_theme: 'dark' },\n};\n\nexport const MobileDocs = {\n  ...Mobile,\n  args: {\n    managerLayoutState: { ...defaultState, viewMode: 'docs' },\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/components/layout/Layout.tsx",
    "content": "import type { CSSProperties } from 'react';\nimport React, { useEffect, useLayoutEffect, useState } from 'react';\n\nimport type { API_Layout, API_ViewMode } from 'storybook/internal/types';\n\nimport { type API, useStorybookApi } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport { MEDIA_DESKTOP_BREAKPOINT, MINIMUM_CONTENT_WIDTH_PX } from '../../constants.ts';\nimport { Notifications } from '../../container/Notifications.tsx';\nimport { MobileNavigation } from '../mobile/navigation/MobileNavigation.tsx';\nimport { useLayout } from './LayoutProvider.tsx';\nimport { MainAreaContainer } from './MainAreaContainer.tsx';\nimport { PanelContainer } from './PanelContainer.tsx';\nimport { SidebarContainer } from './SidebarContainer.tsx';\nimport { useDragging } from './useDragging.ts';\nimport { useLandmarkIndicator } from './useLandmarkIndicator.ts';\n\ninterface InternalLayoutState {\n  isDragging: boolean;\n}\n\ninterface ManagerLayoutState extends Pick<\n  API_Layout,\n  'navSize' | 'bottomPanelHeight' | 'rightPanelWidth' | 'panelPosition'\n> {\n  viewMode: API_ViewMode;\n}\n\nexport type LayoutState = InternalLayoutState & ManagerLayoutState;\n\ninterface Props {\n  managerLayoutState: ManagerLayoutState;\n  setManagerLayoutState: (state: Partial<Omit<ManagerLayoutState, 'viewMode'>>) => void;\n  slotMain?: React.ReactNode;\n  slotSidebar?: React.ReactNode;\n  slotPanel?: React.ReactNode;\n  slotPages?: React.ReactNode;\n  hasTab: boolean;\n}\n\nconst layoutStateIsEqual = (state: ManagerLayoutState, other: ManagerLayoutState) =>\n  state.navSize === other.navSize &&\n  state.bottomPanelHeight === other.bottomPanelHeight &&\n  state.rightPanelWidth === other.rightPanelWidth &&\n  state.panelPosition === other.panelPosition;\n\n/**\n * Manages the internal state of panels while dragging, and syncs it with the layout state in the\n * global manager store when the user is done dragging. Also syncs the layout state from the global\n * manager store to the internal state here when necessary\n */\nconst useLayoutSyncingState = ({\n  api,\n  managerLayoutState,\n  setManagerLayoutState,\n  isDesktop,\n  hasTab,\n}: {\n  api: API;\n  managerLayoutState: Props['managerLayoutState'];\n  setManagerLayoutState: Props['setManagerLayoutState'];\n  isDesktop: boolean;\n  hasTab: boolean;\n}) => {\n  // ref to keep track of previous managerLayoutState, to check if the props change\n  const prevManagerLayoutStateRef = React.useRef<ManagerLayoutState>(managerLayoutState);\n\n  const [internalDraggingSizeState, setInternalDraggingSizeState] = useState<LayoutState>({\n    ...managerLayoutState,\n    isDragging: false,\n  });\n\n  /** Sync FROM managerLayoutState to internalDraggingState if user is not dragging */\n  useEffect(() => {\n    if (\n      internalDraggingSizeState.isDragging || // don't interrupt user's drag\n      layoutStateIsEqual(managerLayoutState, prevManagerLayoutStateRef.current) // don't set any state if managerLayoutState hasn't changed\n    ) {\n      return;\n    }\n    prevManagerLayoutStateRef.current = managerLayoutState;\n    setInternalDraggingSizeState((state) => ({ ...state, ...managerLayoutState }));\n  }, [internalDraggingSizeState.isDragging, managerLayoutState, setInternalDraggingSizeState]);\n\n  /** Sync size changes TO managerLayoutState when drag is done */\n  useLayoutEffect(() => {\n    if (\n      internalDraggingSizeState.isDragging || // wait with syncing managerLayoutState until user is done dragging\n      layoutStateIsEqual(managerLayoutState, internalDraggingSizeState) // don't sync managerLayoutState if it doesn't differ from internalDraggingSizeStatee)\n    ) {\n      return;\n    }\n    const nextState = {\n      navSize: internalDraggingSizeState.navSize,\n      bottomPanelHeight: internalDraggingSizeState.bottomPanelHeight,\n      rightPanelWidth: internalDraggingSizeState.rightPanelWidth,\n    };\n    prevManagerLayoutStateRef.current = {\n      ...prevManagerLayoutStateRef.current,\n      ...nextState,\n    };\n    setManagerLayoutState(nextState);\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [internalDraggingSizeState, setManagerLayoutState]);\n\n  const isPagesShown =\n    managerLayoutState.viewMode !== undefined &&\n    managerLayoutState.viewMode !== 'story' &&\n    managerLayoutState.viewMode !== 'docs';\n  const isPanelShown = managerLayoutState.viewMode === 'story' && !hasTab;\n\n  const { navSize, rightPanelWidth, bottomPanelHeight } = internalDraggingSizeState.isDragging\n    ? internalDraggingSizeState\n    : managerLayoutState;\n\n  const customisedNavSize = api.getNavSizeWithCustomisations?.(navSize) ?? navSize;\n  const customisedShowPanel = api.getShowPanelWithCustomisations?.(isPanelShown) ?? isPanelShown;\n\n  const { panelResizerRef, sidebarResizerRef, sidebarMaxWidth, panelMaxSize } = useDragging({\n    setState: setInternalDraggingSizeState,\n    isDesktop,\n    navSize: customisedNavSize,\n    showPanel: customisedShowPanel,\n    rightPanelWidth,\n    panelPosition: managerLayoutState.panelPosition,\n  });\n\n  return {\n    navSize: customisedNavSize,\n    rightPanelWidth,\n    bottomPanelHeight,\n    panelPosition: managerLayoutState.panelPosition,\n    panelResizerRef,\n    sidebarResizerRef,\n    sidebarMaxWidth,\n    panelMaxSize,\n    showPages: isPagesShown,\n    showPanel: customisedShowPanel,\n    isDragging: internalDraggingSizeState.isDragging,\n  };\n};\n\nconst OrderedMobileNavigation = styled(MobileNavigation)({\n  order: 1,\n});\n\nexport const Layout = ({ managerLayoutState, setManagerLayoutState, hasTab, ...slots }: Props) => {\n  const { isDesktop, isMobile } = useLayout();\n  const api = useStorybookApi();\n\n  const {\n    navSize,\n    rightPanelWidth,\n    bottomPanelHeight,\n    panelPosition,\n    panelResizerRef,\n    sidebarResizerRef,\n    sidebarMaxWidth,\n    panelMaxSize,\n    showPages,\n    showPanel,\n  } = useLayoutSyncingState({ api, managerLayoutState, setManagerLayoutState, isDesktop, hasTab });\n\n  // Install landmark navigation listener in parent container of all landmarks.\n  useLandmarkIndicator();\n\n  return (\n    <LayoutContainer\n      panelPosition={managerLayoutState.panelPosition}\n      showPanel={showPanel}\n      style={\n        {\n          '--nav-width': `${navSize}px`,\n          '--right-panel-width': `${rightPanelWidth}px`,\n          '--bottom-panel-height': `${bottomPanelHeight}px`,\n        } as CSSProperties\n      }\n    >\n      <>\n        {isDesktop && (\n          <SidebarContainer\n            navSize={navSize}\n            sidebarMaxWidth={sidebarMaxWidth}\n            sidebarResizerRef={sidebarResizerRef}\n          >\n            {slots.slotSidebar}\n          </SidebarContainer>\n        )}\n        {isMobile && (\n          <OrderedMobileNavigation\n            menu={slots.slotSidebar}\n            panel={slots.slotPanel}\n            showPanel={showPanel}\n          />\n        )}\n\n        <MainAreaContainer\n          showPages={showPages}\n          slotMain={slots.slotMain}\n          slotPages={slots.slotPages}\n        />\n\n        {isDesktop && showPanel && (\n          <PanelContainer\n            bottomPanelHeight={bottomPanelHeight}\n            rightPanelWidth={rightPanelWidth}\n            panelMaxSize={panelMaxSize}\n            panelResizerRef={panelResizerRef}\n            position={panelPosition}\n          >\n            {slots.slotPanel}\n          </PanelContainer>\n        )}\n        {isMobile && <Notifications />}\n      </>\n    </LayoutContainer>\n  );\n};\n\nconst LayoutContainer = styled.div<{\n  panelPosition: LayoutState['panelPosition'];\n  showPanel: boolean;\n}>(({ panelPosition, showPanel }) => ({\n  width: '100%',\n  height: ['100vh', '100dvh'],\n  overflow: 'hidden',\n  display: 'flex',\n  flexDirection: 'column',\n  colorScheme: 'light dark',\n\n  [MEDIA_DESKTOP_BREAKPOINT]: {\n    display: 'grid',\n    gap: 0,\n    // This uses CSS variables to prevent Emotion from generating a new CSS className for every possible value\n    gridTemplateColumns: `minmax(0, var(--nav-width)) minmax(${MINIMUM_CONTENT_WIDTH_PX}px, 1fr) minmax(0, var(--right-panel-width))`,\n    gridTemplateRows: `1fr minmax(0, var(--bottom-panel-height))`,\n    gridTemplateAreas: (() => {\n      if (!showPanel) {\n        // showPanel is false by default when viewMode is not 'story', but can be overridden by the user\n        return `\"sidebar content content\"\n                  \"sidebar content content\"`;\n      }\n      if (panelPosition === 'right') {\n        return `\"sidebar content panel\"\n                  \"sidebar content panel\"`;\n      }\n      return `\"sidebar content content\"\n                \"sidebar panel   panel\"`;\n    })(),\n  },\n}));\n"
  },
  {
    "path": "code/core/src/manager/components/layout/LayoutProvider.tsx",
    "content": "import type { FC, PropsWithChildren } from 'react';\nimport React, { createContext, useContext, useMemo, useState } from 'react';\n\nimport { BREAKPOINT } from '../../constants.ts';\nimport { useMediaQuery } from '../../hooks/useMedia.tsx';\n\ntype LayoutContextType = {\n  isMobileMenuOpen: boolean;\n  setMobileMenuOpen: React.Dispatch<React.SetStateAction<boolean>>;\n  isMobileAboutOpen: boolean;\n  setMobileAboutOpen: React.Dispatch<React.SetStateAction<boolean>>;\n  isMobilePanelOpen: boolean;\n  setMobilePanelOpen: React.Dispatch<React.SetStateAction<boolean>>;\n  isDesktop: boolean;\n  isMobile: boolean;\n};\n\nconst LayoutContext = createContext<LayoutContextType>({\n  isMobileMenuOpen: false,\n  setMobileMenuOpen: () => {},\n  isMobileAboutOpen: false,\n  setMobileAboutOpen: () => {},\n  isMobilePanelOpen: false,\n  setMobilePanelOpen: () => {},\n  isDesktop: false,\n  isMobile: false,\n});\n\nexport const LayoutProvider: FC<\n  PropsWithChildren & {\n    forceDesktop?: boolean;\n  }\n> = ({ children, forceDesktop }) => {\n  const [isMobileMenuOpen, setMobileMenuOpen] = useState(false);\n  const [isMobileAboutOpen, setMobileAboutOpen] = useState(false);\n  const [isMobilePanelOpen, setMobilePanelOpen] = useState(false);\n  const isDesktop = forceDesktop ?? useMediaQuery(`(min-width: ${BREAKPOINT}px)`);\n  const isMobile = !isDesktop;\n\n  const contextValue = useMemo(\n    () => ({\n      isMobileMenuOpen,\n      setMobileMenuOpen,\n      isMobileAboutOpen,\n      setMobileAboutOpen,\n      isMobilePanelOpen,\n      setMobilePanelOpen,\n      isDesktop,\n      isMobile,\n    }),\n    [\n      isMobileMenuOpen,\n      setMobileMenuOpen,\n      isMobileAboutOpen,\n      setMobileAboutOpen,\n      isMobilePanelOpen,\n      setMobilePanelOpen,\n      isDesktop,\n      isMobile,\n    ]\n  );\n  return <LayoutContext.Provider value={contextValue}>{children}</LayoutContext.Provider>;\n};\n\nexport const useLayout = () => useContext(LayoutContext);\n"
  },
  {
    "path": "code/core/src/manager/components/layout/MainAreaContainer.tsx",
    "content": "import React, { useRef } from 'react';\n\nimport { Match } from 'storybook/internal/router';\n\nimport { styled } from 'storybook/theming';\n\nimport { MEDIA_DESKTOP_BREAKPOINT } from '../../constants.ts';\nimport { useLandmark } from '../../hooks/useLandmark.ts';\n\ninterface PagesContainerProps {\n  children: React.ReactNode;\n}\n\nconst PagesInnerContainer = styled.main(({ theme }) => ({\n  display: 'flex',\n  flexDirection: 'column',\n  gridRowStart: 'sidebar-start',\n  gridRowEnd: '-1',\n  gridColumnStart: 'sidebar-end',\n  gridColumnEnd: '-1',\n  backgroundColor: theme.appContentBg,\n  zIndex: 1,\n}));\n\n/**\n * Shows Router-controlled pages (e.g. settings/about), inside a landmark for navigability. Assumes\n * that the main preview area is not concurrently reachable by assistive technologies, since these\n * components both define a `main` role.\n */\nconst PagesContainer = React.memo<PagesContainerProps>(function PagesContainer(props) {\n  const { children } = props;\n\n  const mainRef = useRef<HTMLElement>(null);\n  const { landmarkProps } = useLandmark(\n    { 'aria-labelledby': 'main-content-heading', role: 'main' },\n    mainRef\n  );\n\n  return (\n    <PagesInnerContainer id=\"main-content-wrapper\" ref={mainRef} {...landmarkProps}>\n      <h2 id=\"main-content-heading\" className=\"sb-sr-only\">\n        Main content\n      </h2>\n      {children}\n    </PagesInnerContainer>\n  );\n});\n\nconst MainInnerContainer = styled.div<{ shown: boolean }>(({ theme, shown }) => ({\n  flex: 1,\n  position: 'relative',\n  backgroundColor: theme.appContentBg,\n  display: shown ? 'grid' : 'none', // This is needed to make the content container fill the available space\n  overflow: 'auto',\n\n  [MEDIA_DESKTOP_BREAKPOINT]: {\n    flex: 'auto',\n    gridArea: 'content',\n  },\n}));\n\ninterface MainAreaContainerProps {\n  showPages: boolean;\n  slotMain: React.ReactNode;\n  slotPages: React.ReactNode;\n}\n\n/**\n * Shows Router-controlled pages (e.g. settings/about), inside a landmark for navigability, OR shows\n * the preview area. Ensures a single `main` landmark exists at a time.\n */\nconst MainAreaContainer = React.memo<MainAreaContainerProps>(function MainAreaContainer({\n  showPages,\n  slotMain,\n  slotPages,\n}) {\n  return (\n    <>\n      {showPages ? (\n        <PagesContainer>{slotPages}</PagesContainer>\n      ) : (\n        <Match path={/(^\\/story|docs|onboarding\\/|^\\/$)/} startsWith={false}>\n          {({ match }) => <MainInnerContainer shown={!!match}>{slotMain}</MainInnerContainer>}\n        </Match>\n      )}\n    </>\n  );\n});\n\nexport { MainAreaContainer };\n"
  },
  {
    "path": "code/core/src/manager/components/layout/PanelContainer.tsx",
    "content": "import React from 'react';\n\nimport { styled } from 'storybook/theming';\n\nimport type { API_Layout } from '../../../types/index.ts';\nimport { Drag } from './Drag.tsx';\n\ninterface PanelContainerProps {\n  children: React.ReactNode;\n  bottomPanelHeight: number;\n  rightPanelWidth: number;\n  panelMaxSize: number | undefined;\n  panelResizerRef: React.Ref<HTMLDivElement>;\n  position: API_Layout['panelPosition'];\n}\n\nconst Container = styled.div<{ position: API_Layout['panelPosition'] }>(({ theme, position }) => ({\n  gridArea: 'panel',\n  position: 'relative',\n  backgroundColor: theme.appContentBg,\n  borderTop: position === 'bottom' ? `1px solid ${theme.appBorderColor}` : undefined,\n  borderLeft: position === 'right' ? `1px solid ${theme.appBorderColor}` : undefined,\n}));\n\nconst PanelSlot = styled.div({\n  height: '100%',\n});\n\n/**\n * Shows the addon panel and its resize drag handle. The drag handle is always rendered so users can\n * reopen the panel. The panel is always rendered (to preserve internal state), but it's excluded\n * from the Accessibility Object Model when effectively collapsed.\n */\nconst PanelContainer = React.memo<PanelContainerProps>(function PanelContainer(props) {\n  const { children, bottomPanelHeight, rightPanelWidth, panelMaxSize, panelResizerRef, position } =\n    props;\n\n  const shouldHidePanelContent =\n    position === 'bottom' ? bottomPanelHeight === 0 : rightPanelWidth === 0;\n\n  return (\n    <Container position={position}>\n      <Drag\n        ref={panelResizerRef}\n        position={position}\n        overlapping={position === 'bottom' ? !!bottomPanelHeight : !!rightPanelWidth}\n        aria-label=\"Addon panel resize handle\"\n        aria-valuenow={position === 'bottom' ? bottomPanelHeight : rightPanelWidth}\n        aria-valuemax={panelMaxSize}\n      />\n      <PanelSlot\n        // This ensures that the panel content is not reachable by keyboard or assistive\n        // tech when actually collapsed.\n        hidden={shouldHidePanelContent ? true : undefined}\n        aria-hidden={shouldHidePanelContent ? true : undefined}\n      >\n        {children}\n      </PanelSlot>\n    </Container>\n  );\n});\n\nexport { PanelContainer };\n"
  },
  {
    "path": "code/core/src/manager/components/layout/SidebarContainer.tsx",
    "content": "import React from 'react';\n\nimport { styled } from 'storybook/theming';\n\nimport { Drag } from './Drag.tsx';\n\ninterface SidebarContainerProps {\n  children: React.ReactNode;\n  navSize: number;\n  sidebarMaxWidth: number | undefined;\n  sidebarResizerRef: React.Ref<HTMLDivElement>;\n}\n\nconst Container = styled.div(({ theme }) => ({\n  backgroundColor: theme.appBg,\n  gridArea: 'sidebar',\n  position: 'relative',\n  borderRight: `1px solid ${theme.appBorderColor}`,\n}));\n\nconst SidebarSlot = styled.div({\n  height: '100%',\n});\n\n/**\n * Shows the sidebar and its resize drag handle. The drag handle is always rendered so users can\n * reopen the sidebar. The sidebar is always rendered (to preserve internal state), but it's\n * excluded from the Accessibility Object Model when effectively collapsed.\n */\nconst SidebarContainer = React.memo<SidebarContainerProps>(function SidebarContainer(props) {\n  const { children, navSize, sidebarMaxWidth, sidebarResizerRef } = props;\n\n  const shouldHideSidebarContent = navSize === 0;\n\n  return (\n    <Container>\n      <SidebarSlot\n        // This ensures that the sidebar content is not reachable by keyboard or assistive\n        // tech when actually collapsed.\n        hidden={shouldHideSidebarContent ? true : undefined}\n        aria-hidden={shouldHideSidebarContent ? true : undefined}\n      >\n        {children}\n      </SidebarSlot>\n      <Drag\n        ref={sidebarResizerRef}\n        position=\"left\"\n        aria-label=\"Sidebar resize handle\"\n        aria-valuenow={navSize}\n        aria-valuemax={sidebarMaxWidth}\n      />\n    </Container>\n  );\n});\n\nexport { SidebarContainer };\n"
  },
  {
    "path": "code/core/src/manager/components/layout/useDragging.ts",
    "content": "import type { Dispatch, SetStateAction } from 'react';\nimport { useEffect, useRef } from 'react';\n\nimport type { API_Layout } from 'storybook/internal/types';\n\nimport {\n  MINIMUM_CONTENT_WIDTH_PX,\n  MINIMUM_HORIZONTAL_PANEL_HEIGHT_PX,\n  MINIMUM_HORIZONTAL_PANEL_WIDTH_PX,\n  MINIMUM_RIGHT_PANEL_WIDTH_PX,\n  MINIMUM_SIDEBAR_WIDTH_PX,\n  TOOLBAR_HEIGHT_PX,\n} from '../../constants.ts';\nimport type { LayoutState } from './Layout.tsx';\n\n// the distance from the edge of the screen at which the panel/sidebar will snap to the edge\nconst SNAP_THRESHOLD_PX = 30;\nconst STIFFNESS = 0.9;\nconst KEYBOARD_STEP_PX = 10;\nconst KEYBOARD_SHIFT_MULTIPLIER = 5;\nconst RESIZE_KEYS = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End'];\n\n/** Clamps a value between min and max. */\nfunction clamp(value: number, min: number, max: number): number {\n  return Math.min(Math.max(value, min), max);\n}\n\n/** Interpolates a value between min and max based on the relativeValue. */\nfunction interpolate(relativeValue: number, min: number, max: number): number {\n  return min + (max - min) * relativeValue;\n}\n\n/**\n * Computes the maximum width for the sidebar, accounting for the content minimum and the panel's\n * estimated horizontal footprint. When the panel is at the bottom its minimum enforced width is\n * reserved so the browser never squashes it below `MINIMUM_HORIZONTAL_PANEL_WIDTH_PX`.\n */\nfunction computeSidebarMaxWidth(\n  panelPosition: API_Layout['panelPosition'],\n  rightPanelWidth: number,\n  showPanel: boolean\n): number {\n  if (typeof window === 'undefined') {\n    return 0;\n  }\n\n  const panelWidth = !showPanel\n    ? 0\n    : panelPosition === 'right'\n      ? rightPanelWidth\n      : MINIMUM_HORIZONTAL_PANEL_WIDTH_PX;\n  return Math.max(window.innerWidth - MINIMUM_CONTENT_WIDTH_PX - panelWidth, 0);\n}\n\n/**\n * Computes the maximum size for the panel:\n *\n * - Bottom panel: `innerHeight` minus the toolbar so it cannot push the toolbar off-screen.\n * - Right panel: `innerWidth` minus the content minimum and the sidebar.\n */\nfunction computePanelMaxSize(panelPosition: API_Layout['panelPosition'], navSize: number): number {\n  if (typeof window === 'undefined') {\n    return 0;\n  }\n\n  if (panelPosition === 'bottom') {\n    return Math.max(window.innerHeight - TOOLBAR_HEIGHT_PX, 0);\n  }\n  return Math.max(window.innerWidth - MINIMUM_CONTENT_WIDTH_PX - navSize, 0);\n}\n\n/**\n * Given the current layout state, a size key, a max size, and the key pressed, returns the next\n * layout state with the resized panel/sidebar. All sidebar/panel-specific logic lives in the\n * callers; this function is fully parameterised.\n *\n * @param sizeKey - The layout state key to resize.\n * @param maxSize - The effective maximum size for the region.\n * @param increaseKey - The key that grows the region.\n * @param decreaseKey - The key that shrinks the region.\n */\nfunction applyResizeKeyboard(\n  state: LayoutState,\n  sizeKey: 'navSize' | 'bottomPanelHeight' | 'rightPanelWidth',\n  key: string,\n  step: number,\n  minSize: number,\n  maxSize: number,\n  increaseKey: string,\n  decreaseKey: string\n): LayoutState {\n  const currentSize = state[sizeKey];\n\n  switch (key) {\n    case increaseKey:\n      return { ...state, [sizeKey]: clamp(currentSize + step, minSize, maxSize) };\n    case decreaseKey:\n      const effectivelyComputed = clamp(currentSize - step, 0, maxSize);\n      return { ...state, [sizeKey]: effectivelyComputed < minSize ? 0 : effectivelyComputed };\n    case 'Home':\n      return { ...state, [sizeKey]: 0 };\n    case 'End':\n      return { ...state, [sizeKey]: maxSize };\n    default:\n      return state;\n  }\n}\n\nexport function useDragging({\n  setState,\n  showPanel,\n  isDesktop,\n  navSize,\n  rightPanelWidth,\n  panelPosition,\n}: {\n  setState: Dispatch<SetStateAction<LayoutState>>;\n  showPanel: boolean;\n  isDesktop: boolean;\n  navSize: number;\n  rightPanelWidth: number;\n  panelPosition: API_Layout['panelPosition'];\n}) {\n  const panelResizerRef = useRef<HTMLDivElement>(null);\n  const sidebarResizerRef = useRef<HTMLDivElement>(null);\n\n  // Compute current max sizes so callers can use them for aria attributes without duplicating logic.\n  // Evaluated at render time (from the same values the containers receive), so they stay in sync.\n  const sidebarMaxWidth = computeSidebarMaxWidth(panelPosition, rightPanelWidth, showPanel);\n  const panelMaxSize = computePanelMaxSize(panelPosition, navSize);\n\n  useEffect(() => {\n    const panelResizer = panelResizerRef.current;\n    const sidebarResizer = sidebarResizerRef.current;\n    const previewIframe = document.querySelector('#storybook-preview-iframe') as HTMLIFrameElement;\n    let draggedElement: typeof panelResizer | typeof sidebarResizer | null = null;\n\n    const onDragStart = (e: MouseEvent) => {\n      e.preventDefault();\n\n      setState((state) => ({\n        ...state,\n        isDragging: true,\n      }));\n\n      if (e.currentTarget === panelResizer) {\n        draggedElement = panelResizer;\n      } else if (e.currentTarget === sidebarResizer) {\n        draggedElement = sidebarResizer;\n      }\n      window.addEventListener('mousemove', onDrag);\n      window.addEventListener('mouseup', onDragEnd);\n\n      if (previewIframe) {\n        // prevent iframe from capturing mouse events\n        previewIframe.style.pointerEvents = 'none';\n      }\n    };\n\n    const onDragEnd = () => {\n      setState((state) => {\n        if (draggedElement === sidebarResizer) {\n          if (state.navSize < MINIMUM_SIDEBAR_WIDTH_PX && state.navSize > 0) {\n            // snap the sidebar back to its minimum width if it's smaller than the threshold\n            return {\n              ...state,\n              isDragging: false,\n              navSize: MINIMUM_SIDEBAR_WIDTH_PX,\n            };\n          }\n        }\n        if (draggedElement === panelResizer) {\n          if (\n            state.panelPosition === 'right' &&\n            state.rightPanelWidth < MINIMUM_RIGHT_PANEL_WIDTH_PX &&\n            state.rightPanelWidth > 0\n          ) {\n            // snap the right panel back to its minimum width if it's smaller than the threshold\n            return {\n              ...state,\n              isDragging: false,\n              rightPanelWidth: MINIMUM_RIGHT_PANEL_WIDTH_PX,\n            };\n          } else if (\n            state.panelPosition === 'bottom' &&\n            state.bottomPanelHeight < MINIMUM_HORIZONTAL_PANEL_HEIGHT_PX &&\n            state.bottomPanelHeight > 0\n          ) {\n            // snap the bottom panel back to its minimum height if it's smaller than the threshold\n            return {\n              ...state,\n              isDragging: false,\n              bottomPanelHeight: MINIMUM_HORIZONTAL_PANEL_HEIGHT_PX,\n            };\n          }\n        }\n        return {\n          ...state,\n          isDragging: false,\n        };\n      });\n      window.removeEventListener('mousemove', onDrag);\n      window.removeEventListener('mouseup', onDragEnd);\n      // make iframe capture pointer events again\n      previewIframe?.removeAttribute('style');\n      draggedElement = null;\n    };\n\n    const onDrag = (e: MouseEvent) => {\n      if (e.buttons === 0) {\n        onDragEnd();\n        return;\n      }\n\n      setState((state) => {\n        if (draggedElement === sidebarResizer) {\n          const sidebarDragX = e.clientX;\n\n          if (sidebarDragX === state.navSize) {\n            return state;\n          }\n          if (sidebarDragX <= SNAP_THRESHOLD_PX) {\n            return {\n              ...state,\n              navSize: 0,\n            };\n          }\n          if (sidebarDragX <= MINIMUM_SIDEBAR_WIDTH_PX) {\n            // set sidebar width to a value in between the actual drag position and the min width, determined by the stiffness\n            return {\n              ...state,\n              navSize: interpolate(STIFFNESS, sidebarDragX, MINIMUM_SIDEBAR_WIDTH_PX),\n            };\n          }\n          return {\n            ...state,\n            navSize: clamp(\n              sidebarDragX,\n              0,\n              computeSidebarMaxWidth(state.panelPosition, state.rightPanelWidth, showPanel)\n            ),\n          };\n        }\n        if (draggedElement === panelResizer) {\n          const sizeAxisState =\n            state.panelPosition === 'bottom' ? 'bottomPanelHeight' : 'rightPanelWidth';\n          const panelDragSize =\n            state.panelPosition === 'bottom'\n              ? // @ts-expect-error (non strict)\n                e.view.innerHeight - e.clientY\n              : // @ts-expect-error (non strict)\n                e.view.innerWidth - e.clientX;\n          const minimumSize =\n            state.panelPosition === 'bottom'\n              ? MINIMUM_HORIZONTAL_PANEL_HEIGHT_PX\n              : MINIMUM_RIGHT_PANEL_WIDTH_PX;\n\n          if (panelDragSize === state[sizeAxisState]) {\n            return state;\n          }\n          if (panelDragSize <= SNAP_THRESHOLD_PX) {\n            return {\n              ...state,\n              [sizeAxisState]: 0,\n            };\n          }\n          // set panel width/height to a value in between the actual drag position and the min size, determined by the stiffness\n          if (panelDragSize <= minimumSize) {\n            return {\n              ...state,\n              [sizeAxisState]: interpolate(STIFFNESS, panelDragSize, minimumSize),\n            };\n          }\n\n          return {\n            ...state,\n            [sizeAxisState]: clamp(\n              panelDragSize,\n              0,\n              computePanelMaxSize(state.panelPosition, state.navSize)\n            ),\n          };\n        }\n        return state;\n      });\n    };\n\n    const onSidebarKeyDown = (e: KeyboardEvent) => {\n      if (!RESIZE_KEYS.includes(e.key)) {\n        return;\n      }\n      e.preventDefault();\n      const step = e.shiftKey ? KEYBOARD_STEP_PX * KEYBOARD_SHIFT_MULTIPLIER : KEYBOARD_STEP_PX;\n      setState((state) =>\n        applyResizeKeyboard(\n          state,\n          'navSize',\n          e.key,\n          step,\n          MINIMUM_SIDEBAR_WIDTH_PX,\n          computeSidebarMaxWidth(state.panelPosition, state.rightPanelWidth, showPanel),\n          'ArrowRight',\n          'ArrowLeft'\n        )\n      );\n    };\n\n    const onPanelKeyDown = (e: KeyboardEvent) => {\n      if (!RESIZE_KEYS.includes(e.key)) {\n        return;\n      }\n      e.preventDefault();\n      const step = e.shiftKey ? KEYBOARD_STEP_PX * KEYBOARD_SHIFT_MULTIPLIER : KEYBOARD_STEP_PX;\n      setState((state) =>\n        applyResizeKeyboard(\n          state,\n          state.panelPosition === 'bottom' ? 'bottomPanelHeight' : 'rightPanelWidth',\n          e.key,\n          step,\n          state.panelPosition === 'bottom'\n            ? MINIMUM_HORIZONTAL_PANEL_HEIGHT_PX\n            : MINIMUM_RIGHT_PANEL_WIDTH_PX,\n          computePanelMaxSize(state.panelPosition, state.navSize),\n          state.panelPosition === 'bottom' ? 'ArrowUp' : 'ArrowLeft',\n          state.panelPosition === 'bottom' ? 'ArrowDown' : 'ArrowRight'\n        )\n      );\n    };\n\n    panelResizer?.addEventListener('mousedown', onDragStart);\n    sidebarResizer?.addEventListener('mousedown', onDragStart);\n    panelResizer?.addEventListener('keydown', onPanelKeyDown);\n    sidebarResizer?.addEventListener('keydown', onSidebarKeyDown);\n\n    return () => {\n      panelResizer?.removeEventListener('mousedown', onDragStart);\n      sidebarResizer?.removeEventListener('mousedown', onDragStart);\n      panelResizer?.removeEventListener('keydown', onPanelKeyDown);\n      sidebarResizer?.removeEventListener('keydown', onSidebarKeyDown);\n      // make iframe capture pointer events again\n      previewIframe?.removeAttribute('style');\n    };\n  }, [\n    // we need to rerun this effect when the panel is shown/hidden or when changing between mobile/desktop to re-attach the event listeners\n    showPanel,\n    isDesktop,\n    setState,\n  ]);\n\n  return { panelResizerRef, sidebarResizerRef, sidebarMaxWidth, panelMaxSize };\n}\n"
  },
  {
    "path": "code/core/src/manager/components/layout/useLandmarkIndicator.ts",
    "content": "import { useEffect, useRef } from 'react';\n\nimport { useTheme } from 'storybook/theming';\n\nimport { useMediaQuery } from '../../hooks/useMedia.tsx';\n\nfunction findActiveLandmarkElement() {\n  let currentElement: Element | null = document.activeElement;\n  let landmarkElement: HTMLElement | null = null;\n\n  while (currentElement) {\n    if (currentElement instanceof HTMLElement && currentElement.hasAttribute('data-sb-landmark')) {\n      landmarkElement = currentElement;\n      break;\n    }\n    currentElement = currentElement.parentElement;\n  }\n\n  return landmarkElement;\n}\n\nexport function useRegionFocusAnimation() {\n  const theme = useTheme();\n  const reducedMotion = useMediaQuery('(prefers-reduced-motion: reduce)');\n  const currentAnimationRef = useRef<Animation | null>(null);\n\n  const animateLandmark = (elementToAnimate: HTMLElement | null) => {\n    if (!elementToAnimate) {\n      return;\n    }\n\n    // Cancel previous landmark animation if user switches fast.\n    if (currentAnimationRef.current) {\n      currentAnimationRef.current.cancel();\n      currentAnimationRef.current = null;\n    }\n\n    if (!reducedMotion) {\n      const animation = elementToAnimate.animate(\n        [{ border: `2px solid ${theme.color.primary}` }, { border: `2px solid transparent` }],\n        {\n          duration: 1500,\n          pseudoElement: '::after',\n        }\n      );\n      currentAnimationRef.current = animation;\n\n      animation.onfinish = () => {\n        currentAnimationRef.current = null;\n      };\n    }\n  };\n\n  return animateLandmark;\n}\n\n// Global keyboard handler for F6/Shift+F6 landmark navigation that\n// highlights the landmark containing the current element. This helps\n// users who navigate through landmark shortcuts more quickly visualise\n// which region of the UI they landed into.\n// Call this once at the app root.\nexport function useLandmarkIndicator() {\n  const animateLandmark = useRegionFocusAnimation();\n\n  useEffect(() => {\n    const handleKeyDown = (e: KeyboardEvent) => {\n      if (e.key !== 'F6') {\n        return;\n      }\n\n      const landmarkElement = findActiveLandmarkElement();\n      if (!landmarkElement) {\n        return;\n      }\n\n      animateLandmark(landmarkElement);\n    };\n\n    document.addEventListener('keydown', handleKeyDown, { capture: true });\n    return () => {\n      document.removeEventListener('keydown', handleKeyDown, { capture: true });\n    };\n  }, [animateLandmark]);\n}\n"
  },
  {
    "path": "code/core/src/manager/components/mobile/about/MobileAbout.stories.tsx",
    "content": "import React, { useEffect } from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { ManagerContext } from 'storybook/manager-api';\nimport { within } from 'storybook/test';\n\nimport { LayoutProvider, useLayout } from '../../layout/LayoutProvider.tsx';\nimport { MobileAbout } from './MobileAbout.tsx';\n\n/** A helper component to open the about page via the MobileLayoutContext */\nconst OpenAboutHelper = ({ children }: { children: any }) => {\n  const { setMobileAboutOpen } = useLayout();\n  useEffect(() => {\n    setMobileAboutOpen(true);\n  }, [setMobileAboutOpen]);\n  return children;\n};\n\nconst meta = {\n  component: MobileAbout,\n  title: 'Mobile/About',\n  globals: { sb_theme: 'light' },\n  parameters: {\n    layout: 'fullscreen',\n    viewport: {\n      defaultViewport: 'mobile1',\n    },\n    chromatic: { viewports: [320] },\n  },\n  decorators: [\n    (storyFn) => {\n      return (\n        <ManagerContext.Provider\n          value={\n            {\n              api: {\n                getCurrentVersion: () => ({\n                  version: '7.2.0',\n                }),\n              },\n            } as any\n          }\n        >\n          <LayoutProvider>\n            <OpenAboutHelper>{storyFn()}</OpenAboutHelper>\n          </LayoutProvider>\n        </ManagerContext.Provider>\n      );\n    },\n  ],\n} satisfies Meta<typeof MobileAbout>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {};\nexport const Dark: Story = {\n  globals: { sb_theme: 'dark' },\n};\n\nexport const Closed: Story = {\n  play: async ({ canvasElement }) => {\n    await new Promise((resolve) => setTimeout(resolve, 1000));\n    const closeButton = within(canvasElement).getByText('Back');\n    closeButton.click();\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/components/mobile/about/MobileAbout.tsx",
    "content": "import type { FC } from 'react';\nimport React, { useEffect, useRef } from 'react';\n\nimport { Button, Link, ScrollArea } from 'storybook/internal/components';\n\nimport { ArrowLeftIcon, GithubIcon, ShareAltIcon, StorybookIcon } from '@storybook/icons';\n\nimport { useTransitionState } from 'react-transition-state';\nimport { keyframes, styled } from 'storybook/theming';\n\nimport { MOBILE_TRANSITION_DURATION } from '../../../constants.ts';\nimport { useLayout } from '../../layout/LayoutProvider.tsx';\nimport { UpgradeBlock } from '../../upgrade/UpgradeBlock.tsx';\n\nexport const MobileAbout: FC = () => {\n  const { isMobileAboutOpen, setMobileAboutOpen } = useLayout();\n  const aboutRef = useRef(null);\n\n  const [state, toggle] = useTransitionState({\n    timeout: MOBILE_TRANSITION_DURATION,\n    mountOnEnter: true,\n    unmountOnExit: true,\n  });\n\n  // Update transition state when isMobileAboutOpen changes\n  useEffect(() => {\n    toggle(isMobileAboutOpen);\n  }, [isMobileAboutOpen, toggle]);\n\n  if (!state.isMounted) {\n    return null;\n  }\n\n  return (\n    <Container\n      ref={aboutRef}\n      $status={state.status}\n      $transitionDuration={MOBILE_TRANSITION_DURATION}\n    >\n      <ScrollArea vertical offset={3} scrollbarSize={6}>\n        <InnerArea>\n          <CloseButton\n            onClick={() => setMobileAboutOpen(false)}\n            ariaLabel=\"Close about section\"\n            tooltip=\"Close about section\"\n            variant=\"ghost\"\n          >\n            <ArrowLeftIcon />\n            Back\n          </CloseButton>\n          <LinkContainer>\n            <LinkLine\n              href=\"https://github.com/storybookjs/storybook\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n            >\n              <LinkLeft>\n                <GithubIcon />\n                <span>Github</span>\n              </LinkLeft>\n              <ShareAltIcon width={12} />\n            </LinkLine>\n            <LinkLine\n              href=\"https://storybook.js.org/docs/get-started/install?ref=ui\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n            >\n              <LinkLeft>\n                <StorybookIcon />\n                <span>Documentation</span>\n              </LinkLeft>\n              <ShareAltIcon width={12} />\n            </LinkLine>\n          </LinkContainer>\n          <UpgradeBlock />\n          <BottomText>\n            Open source software maintained by{' '}\n            <Link href=\"https://chromatic.com\" target=\"_blank\" rel=\"noopener noreferrer\">\n              Chromatic\n            </Link>{' '}\n            and the{' '}\n            <Link\n              href=\"https://github.com/storybookjs/storybook/graphs/contributors\"\n              rel=\"noopener noreferrer\"\n            >\n              Storybook Community\n            </Link>\n          </BottomText>\n        </InnerArea>\n      </ScrollArea>\n    </Container>\n  );\n};\n\nconst slideFromRight = keyframes({\n  from: {\n    opacity: 0,\n    transform: 'translate(20px, 0)',\n  },\n  to: {\n    opacity: 1,\n    transform: 'translate(0, 0)',\n  },\n});\n\nconst slideToRight = keyframes({\n  from: {\n    opacity: 1,\n    transform: 'translate(0, 0)',\n  },\n  to: {\n    opacity: 0,\n    transform: 'translate(20px, 0)',\n  },\n});\n\nconst Container = styled.div<{ $status: string; $transitionDuration: number }>(\n  ({ theme, $status, $transitionDuration }) => ({\n    position: 'absolute',\n    width: '100%',\n    height: '100%',\n    borderRadius: '10px 10px 0 0',\n    top: 0,\n    left: 0,\n    zIndex: 11,\n    overflow: 'auto',\n    color: theme.color.defaultText,\n    background: theme.background.content,\n    animation:\n      $status === 'exiting'\n        ? `${slideToRight} ${$transitionDuration}ms`\n        : `${slideFromRight} ${$transitionDuration}ms`,\n  })\n);\n\nconst InnerArea = styled.div({\n  display: 'flex',\n  flexDirection: 'column',\n  gap: 20,\n  padding: '25px 12px 20px',\n});\n\nconst LinkContainer = styled.div({});\n\nconst LinkLine = styled.a(({ theme }) => ({\n  all: 'unset',\n  display: 'flex',\n  alignItems: 'center',\n  justifyContent: 'space-between',\n  fontSize: theme.typography.size.s2 - 1,\n  borderBottom: `1px solid ${theme.appBorderColor}`,\n  cursor: 'pointer',\n  padding: '0 10px',\n\n  '&:last-child': {\n    borderBottom: 'none',\n  },\n}));\n\nconst LinkLeft = styled.div(({ theme }) => ({\n  display: 'flex',\n  alignItems: 'center',\n  fontSize: theme.typography.size.s2 - 1,\n  height: 40,\n  gap: 5,\n}));\n\nconst BottomText = styled.div(({ theme }) => ({\n  fontSize: theme.typography.size.s2 - 1,\n  marginTop: 30,\n}));\n\nconst CloseButton = styled(Button)({\n  alignSelf: 'start',\n});\n"
  },
  {
    "path": "code/core/src/manager/components/mobile/navigation/MobileAddonsDrawer.tsx",
    "content": "import type { FC, ReactNode } from 'react';\nimport React from 'react';\n\nimport { Modal } from 'storybook/internal/components';\n\nimport { MOBILE_TRANSITION_DURATION } from '../../../constants.ts';\n\ninterface MobileAddonsDrawerProps {\n  children: ReactNode;\n  id?: string;\n  isOpen: boolean;\n  onOpenChange: (isOpen: boolean) => void;\n}\n\nexport const MobileAddonsDrawer: FC<MobileAddonsDrawerProps> = ({\n  children,\n  id,\n  isOpen,\n  onOpenChange,\n}) => {\n  return (\n    <Modal\n      ariaLabel=\"Addon panel\"\n      transitionDuration={MOBILE_TRANSITION_DURATION}\n      variant=\"bottom-drawer\"\n      height=\"42vh\"\n      id={id}\n      open={isOpen}\n      onOpenChange={onOpenChange}\n    >\n      {children}\n    </Modal>\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/components/mobile/navigation/MobileMenuDrawer.tsx",
    "content": "import type { FC, ReactNode } from 'react';\nimport React from 'react';\n\nimport { Modal } from 'storybook/internal/components';\n\nimport { MOBILE_TRANSITION_DURATION } from '../../../constants.ts';\nimport { MobileAbout } from '../about/MobileAbout.tsx';\n\ninterface MobileMenuDrawerProps {\n  children: ReactNode;\n  id?: string;\n  isOpen: boolean;\n  onOpenChange: (isOpen: boolean) => void;\n}\n\nexport const MobileMenuDrawer: FC<MobileMenuDrawerProps> = ({\n  children,\n  id,\n  isOpen,\n  onOpenChange,\n}) => {\n  return (\n    <Modal\n      ariaLabel=\"Menu\"\n      transitionDuration={MOBILE_TRANSITION_DURATION}\n      variant=\"bottom-drawer\"\n      height=\"80vh\"\n      id={id}\n      open={isOpen}\n      onOpenChange={onOpenChange}\n    >\n      {children}\n      <MobileAbout />\n    </Modal>\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/components/mobile/navigation/MobileNavigation.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { startCase } from 'es-toolkit/string';\nimport { ManagerContext } from 'storybook/manager-api';\nimport { fn, screen, userEvent } from 'storybook/test';\n\nimport { LayoutProvider, useLayout } from '../../layout/LayoutProvider.tsx';\nimport { MobileNavigation } from './MobileNavigation.tsx';\n\nconst MockMenu = () => {\n  const { setMobileMenuOpen } = useLayout();\n  return (\n    <div>\n      menu\n      <button\n        type=\"button\"\n        aria-label=\"Close navigation menu\"\n        onClick={() => setMobileMenuOpen(false)}\n      >\n        close\n      </button>\n    </div>\n  );\n};\n\nconst MockPanel = () => {\n  const { setMobilePanelOpen } = useLayout();\n  return (\n    <div>\n      panel\n      <button\n        type=\"button\"\n        aria-label=\"Close addon panel\"\n        onClick={() => setMobilePanelOpen(false)}\n      >\n        close\n      </button>\n    </div>\n  );\n};\n\nconst renderLabel = ({ name }: { name: string }) => startCase(name);\n\nconst mockManagerStore: any = {\n  state: {\n    index: {\n      someRootId: {\n        type: 'root',\n        id: 'someRootId',\n        name: 'root',\n        renderLabel,\n      },\n      someComponentId: {\n        type: 'component',\n        id: 'someComponentId',\n        name: 'component',\n        parent: 'someRootId',\n        renderLabel,\n      },\n      someStoryId: {\n        type: 'story',\n        subtype: 'story',\n        id: 'someStoryId',\n        name: 'story',\n        parent: 'someComponentId',\n        renderLabel,\n      },\n    },\n  },\n  api: {\n    getCurrentStoryData: fn(() => {\n      return mockManagerStore.state.index.someStoryId;\n    }),\n  },\n};\n\nconst meta = {\n  component: MobileNavigation,\n  title: 'Mobile/Navigation',\n  decorators: [\n    (storyFn) => (\n      <ManagerContext.Provider value={mockManagerStore}>\n        <LayoutProvider>\n          <div style={{ display: 'flex', flexDirection: 'column', height: '100svh' }}>\n            <div style={{ flex: 1 }} />\n            {storyFn()}\n          </div>\n        </LayoutProvider>\n      </ManagerContext.Provider>\n    ),\n  ],\n  parameters: {\n    layout: 'fullscreen',\n    viewport: {\n      defaultViewport: 'mobile1',\n    },\n    chromatic: { viewports: [320] },\n  },\n  args: {\n    menu: <MockMenu />,\n    panel: <MockPanel />,\n    showPanel: true,\n  },\n} satisfies Meta<typeof MobileNavigation>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {\n  globals: { sb_theme: 'light' },\n};\nexport const Dark: Story = {\n  globals: { sb_theme: 'dark' },\n  parameters: { chromatic: { disableSnapshot: true } },\n};\n\nexport const LongStoryName: Story = {\n  decorators: [\n    (storyFn) => {\n      const mockManagerStoreWithLongNames: any = {\n        state: {\n          index: {\n            someRootId: {\n              type: 'root',\n              id: 'someRootId',\n              name: 'someLongRootName',\n              renderLabel,\n            },\n            someComponentId: {\n              type: 'component',\n              id: 'someComponentId',\n              name: 'someComponentName',\n              parent: 'someRootId',\n              renderLabel,\n            },\n            someStoryId: {\n              type: 'story',\n              subtype: 'story',\n              id: 'someStoryId',\n              name: 'someLongStoryName',\n              parent: 'someComponentId',\n              renderLabel,\n            },\n          },\n        },\n        api: {\n          getCurrentStoryData() {\n            return mockManagerStoreWithLongNames.state.index.someStoryId;\n          },\n        },\n      };\n      return (\n        <ManagerContext.Provider value={mockManagerStoreWithLongNames}>\n          {storyFn()}\n        </ManagerContext.Provider>\n      );\n    },\n  ],\n};\n\nexport const MenuOpen: Story = {\n  play: async ({ canvas }) => {\n    const menuOpen = await canvas.findByLabelText('Open navigation menu', {}, { timeout: 3000 });\n    await userEvent.click(menuOpen);\n  },\n};\n\nexport const MenuClosed: Story = {\n  play: async (context) => {\n    // @ts-expect-error (non strict)\n    await MenuOpen.play(context);\n    await new Promise((resolve) => setTimeout(resolve, 500));\n    const overlay = await screen.findByLabelText('Close navigation menu');\n    await userEvent.click(overlay);\n  },\n};\n\nexport const PanelOpen: Story = {\n  play: async ({ canvas }) => {\n    const panelButton = await canvas.findByLabelText('Open addon panel', {}, { timeout: 3000 });\n    await userEvent.click(panelButton);\n  },\n};\n\nexport const PanelClosed: Story = {\n  play: async (context) => {\n    // @ts-expect-error (non strict)\n    await PanelOpen.play(context);\n    await new Promise((resolve) => setTimeout(resolve, 500));\n    const closeButton = await screen.findByLabelText('Close addon panel');\n    await userEvent.click(closeButton);\n  },\n};\n\nexport const PanelDisabled: Story = {\n  args: {\n    showPanel: false,\n  },\n};\n\nexport const ReactNodeRenderLabel: Story = {\n  decorators: [\n    (storyFn) => {\n      const renderReactNodeLabel = ({ name }: { name: string }) => <em>{startCase(name)}</em>;\n\n      const mockManagerStoreWithReactNodeLabels: any = {\n        state: {\n          index: {\n            someRootId: {\n              type: 'root',\n              id: 'someRootId',\n              name: 'root',\n              renderLabel: renderReactNodeLabel,\n            },\n            someComponentId: {\n              type: 'component',\n              id: 'someComponentId',\n              name: 'component',\n              parent: 'someRootId',\n              renderLabel: renderReactNodeLabel,\n            },\n            someStoryId: {\n              type: 'story',\n              subtype: 'story',\n              id: 'someStoryId',\n              name: 'story',\n              parent: 'someComponentId',\n              renderLabel: renderReactNodeLabel,\n            },\n          },\n        },\n        api: {\n          getCurrentStoryData() {\n            return mockManagerStoreWithReactNodeLabels.state.index.someStoryId;\n          },\n        },\n      };\n      return (\n        <ManagerContext.Provider value={mockManagerStoreWithReactNodeLabels}>\n          {storyFn()}\n        </ManagerContext.Provider>\n      );\n    },\n  ],\n};\n"
  },
  {
    "path": "code/core/src/manager/components/mobile/navigation/MobileNavigation.tsx",
    "content": "import React, { useRef } from 'react';\nimport type { ComponentProps, FC } from 'react';\n\nimport { Button } from 'storybook/internal/components';\nimport type { API_IndexHash, API_Refs } from 'storybook/internal/types';\n\nimport { BottomBarToggleIcon, MenuIcon } from '@storybook/icons';\n\nimport { useId } from '@react-aria/utils';\nimport { useStorybookApi, useStorybookState } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport { useLandmark } from '../../../hooks/useLandmark.ts';\nimport { useLayout } from '../../layout/LayoutProvider.tsx';\nimport { MobileAddonsDrawer } from './MobileAddonsDrawer.tsx';\nimport { MobileMenuDrawer } from './MobileMenuDrawer.tsx';\n\ninterface MobileNavigationProps {\n  menu?: React.ReactNode;\n  panel?: React.ReactNode;\n  showPanel: boolean;\n}\n\n// Function to combine all indexes\nfunction combineIndexes(rootIndex: API_IndexHash | undefined, refs: API_Refs) {\n  // Create a copy of the root index to avoid mutation\n  const combinedIndex = { ...(rootIndex || {}) }; // Use an empty object as fallback\n\n  // Traverse refs and merge each nested index with the root index\n  Object.values(refs).forEach((ref) => {\n    if (ref.index) {\n      Object.assign(combinedIndex, ref.index);\n    }\n  });\n\n  return combinedIndex;\n}\n\n/**\n * Walks the tree from the current story to combine story+component+folder names into a single\n * string\n */\nconst useFullStoryName = () => {\n  const { index, refs } = useStorybookState();\n  const api = useStorybookApi();\n  const currentStory = api.getCurrentStoryData();\n\n  if (!currentStory) {\n    return '';\n  }\n  const combinedIndex = combineIndexes(index, refs || {});\n  const storyLabel = currentStory.renderLabel?.(currentStory, api);\n  let fullStoryName = typeof storyLabel === 'string' ? storyLabel : currentStory.name;\n\n  let node = combinedIndex[currentStory.id];\n\n  while (\n    node &&\n    'parent' in node &&\n    node.parent &&\n    combinedIndex[node.parent] &&\n    fullStoryName.length < 24\n  ) {\n    node = combinedIndex[node.parent];\n    const parentLabel = node.renderLabel?.(node, api);\n    const parentName = typeof parentLabel === 'string' ? parentLabel : node.name;\n    fullStoryName = `${parentName}/${fullStoryName}`;\n  }\n  return fullStoryName;\n};\n\nexport const MobileNavigation: FC<MobileNavigationProps & ComponentProps<typeof Container>> = ({\n  menu,\n  panel,\n  showPanel,\n  ...props\n}) => {\n  const { isMobileMenuOpen, isMobilePanelOpen, setMobileMenuOpen, setMobilePanelOpen } =\n    useLayout();\n  const fullStoryName = useFullStoryName();\n  const headingId = useId();\n\n  const sectionRef = useRef<HTMLElement>(null);\n  const { landmarkProps } = useLandmark(\n    { 'aria-labelledby': headingId, role: 'banner' },\n    sectionRef\n  );\n\n  return (\n    <Container {...props}>\n      <MobileMenuDrawer\n        id=\"storybook-mobile-menu\"\n        isOpen={isMobileMenuOpen}\n        onOpenChange={setMobileMenuOpen}\n      >\n        {menu}\n      </MobileMenuDrawer>\n\n      <MobileAddonsDrawer\n        id=\"storybook-mobile-addon-panel\"\n        isOpen={isMobilePanelOpen}\n        onOpenChange={setMobilePanelOpen}\n      >\n        {panel}\n      </MobileAddonsDrawer>\n\n      {!isMobilePanelOpen && (\n        <MobileBottomBar className=\"sb-bar\" {...landmarkProps} ref={sectionRef}>\n          <h2 id={headingId} className=\"sb-sr-only\">\n            Navigation controls\n          </h2>\n          <BottomBarButton\n            padding=\"small\"\n            variant=\"ghost\"\n            onClick={() => setMobileMenuOpen(!isMobileMenuOpen)}\n            ariaLabel=\"Open navigation menu\"\n            aria-expanded={isMobileMenuOpen}\n            aria-controls=\"storybook-mobile-menu\"\n          >\n            <MenuIcon />\n            <Text>{fullStoryName}</Text>\n          </BottomBarButton>\n          <span className=\"sb-sr-only\" aria-current=\"page\">\n            {fullStoryName}\n          </span>\n          {showPanel && (\n            <BottomBarButton\n              padding=\"small\"\n              variant=\"ghost\"\n              onClick={() => setMobilePanelOpen(true)}\n              ariaLabel=\"Open addon panel\"\n              aria-expanded={isMobilePanelOpen}\n              aria-controls=\"storybook-mobile-addon-panel\"\n            >\n              <BottomBarToggleIcon />\n            </BottomBarButton>\n          )}\n        </MobileBottomBar>\n      )}\n    </Container>\n  );\n};\n\nconst Container = styled.section(({ theme }) => ({\n  bottom: 0,\n  left: 0,\n  width: '100%',\n  zIndex: 10,\n  background: theme.barBg,\n  borderTop: `1px solid ${theme.appBorderColor}`,\n}));\n\nconst MobileBottomBar = styled.header({\n  display: 'flex',\n  alignItems: 'center',\n  justifyContent: 'space-between',\n  width: '100%',\n  height: 40,\n  padding: '0 6px',\n\n  /* Because Popper.js's tooltip is creating extra div layers, we have to\n   * punch through them to configure the button to ellipsize. */\n  '& > *:first-child': {\n    /* 6px padding * 2 + 28px for the orientation button */\n    maxWidth: 'calc(100% - 40px)',\n    '& > button': {\n      maxWidth: '100%',\n    },\n    '& > button p': {\n      textOverflow: 'ellipsis',\n    },\n  },\n});\n\nconst BottomBarButton = styled(Button)({\n  WebkitLineClamp: 1,\n  flexShrink: 1,\n  p: {\n    textOverflow: 'ellipsis',\n  },\n});\n\nconst Text = styled.p({\n  display: '-webkit-box',\n  WebkitLineClamp: 1,\n  WebkitBoxOrient: 'vertical',\n  overflow: 'hidden',\n});\n"
  },
  {
    "path": "code/core/src/manager/components/notifications/NotificationItem.stories.tsx",
    "content": "import React from 'react';\n\nimport { LocationProvider } from 'storybook/internal/router';\n\nimport {\n  AccessibilityIcon as AccessibilityIconIcon,\n  BookIcon as BookIconIcon,\n  FaceHappyIcon,\n} from '@storybook/icons';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { action } from 'storybook/actions';\nimport { expect, fn, userEvent, waitFor, within } from 'storybook/test';\n\nimport NotificationItem from './NotificationItem.tsx';\n\nconst meta = {\n  component: NotificationItem,\n  title: 'Notifications/NotificationItem',\n  decorators: [\n    (Story) => (\n      <LocationProvider>\n        <Story />\n      </LocationProvider>\n    ),\n    (Story) => (\n      <div style={{ width: '240px' }}>\n        <Story />\n      </div>\n    ),\n  ],\n  excludeStories: /.*Data$/,\n  args: {\n    onDismissNotification: () => {},\n  },\n} satisfies Meta<typeof NotificationItem>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nconst onClear = fn(action('onClear'));\nconst onClick = fn(action('onClick'));\n\nexport const Simple: Story = {\n  args: {\n    notification: {\n      id: '1',\n      onClear,\n      content: {\n        headline: 'Storybook cool!',\n      },\n    },\n  },\n};\n\nexport const Timeout: Story = {\n  args: {\n    notification: {\n      id: 'Timeout',\n      onClear,\n      onClick,\n      content: {\n        headline: 'Storybook cool!',\n      },\n      duration: 3000,\n    },\n  },\n  play: async ({ args }) => {\n    await waitFor(\n      () => {\n        expect(args.notification.onClear).toHaveBeenCalledWith({ dismissed: false, timeout: true });\n      },\n      {\n        timeout: 4000,\n      }\n    );\n  },\n};\n\nexport const LongHeadline: Story = {\n  args: {\n    notification: {\n      id: '2',\n      onClear,\n      content: {\n        headline: 'This is a long message that extends over two lines!',\n      },\n      link: undefined,\n    },\n  },\n};\n\nexport const Clickable: Story = {\n  args: {\n    notification: {\n      id: 'Clickable',\n      onClear,\n      onClick,\n      content: {\n        headline: 'Storybook cool!',\n      },\n    },\n  },\n  play: async ({ args, canvasElement }) => {\n    const canvas = within(canvasElement);\n    const notification = await canvas.findByText('Storybook cool!');\n    await userEvent.click(notification);\n    await expect(args.notification.onClick).toHaveBeenCalledWith({ onDismiss: expect.anything() });\n  },\n};\n\nexport const Link: Story = {\n  args: {\n    notification: {\n      id: '3',\n      onClear,\n      content: {\n        headline: 'Storybook X.X is available! Download now »',\n      },\n      link: '/some/path',\n    },\n  },\n};\n\nexport const LinkIconWithColor: Story = {\n  args: {\n    notification: {\n      id: '4',\n      onClear,\n      content: {\n        headline: 'Storybook with a smile!',\n      },\n      icon: <FaceHappyIcon color=\"hotpink\" />,\n      link: '/some/path',\n    },\n  },\n};\n\nexport const LinkIconWithColorSubHeadline: Story = {\n  args: {\n    notification: {\n      id: '5',\n      onClear,\n      content: {\n        headline: 'Storybook X.X is available with a smile! Download now »',\n        subHeadline: 'This link also has a sub headline',\n      },\n      icon: <FaceHappyIcon color=\"tomato\" />,\n      link: '/some/path',\n    },\n  },\n};\n\nexport const BookIcon: Story = {\n  args: {\n    notification: {\n      id: '6',\n      onClear,\n      content: {\n        headline: 'Storybook has a book icon!',\n      },\n      icon: <BookIconIcon />,\n      link: undefined,\n    },\n  },\n};\n\nexport const StrongSubHeadline: Story = {\n  args: {\n    notification: {\n      id: '7',\n      onClear,\n      content: {\n        headline: 'Storybook has a book icon!',\n        subHeadline: <strong>Strong subHeadline</strong>,\n      },\n      icon: <BookIconIcon />,\n      link: undefined,\n    },\n  },\n};\n\nexport const StrongEmphasizedSubHeadline: Story = {\n  args: {\n    notification: {\n      id: '8',\n      onClear,\n      content: {\n        headline: 'Storybook cool!',\n        subHeadline: (\n          <span>\n            <em>Emphasized</em> normal <strong>strong Storybook!</strong>\n          </span>\n        ),\n      },\n      icon: <BookIconIcon />,\n      link: undefined,\n    },\n  },\n};\n\nexport const BookIconSubHeadline: Story = {\n  args: {\n    notification: {\n      id: '9',\n      onClear,\n      content: {\n        headline: 'Storybook has a book icon!',\n        subHeadline: 'Find out more!',\n      },\n      icon: <BookIconIcon />,\n      link: undefined,\n    },\n  },\n};\n\nexport const BookIconLongSubHeadline: Story = {\n  args: {\n    notification: {\n      id: '10',\n      onClear,\n      content: {\n        headline: 'Storybook has a book icon!',\n        subHeadline:\n          'Find out more! by clicking on buttons and downloading some applications. Find out more! by clicking on buttons and downloading some applications',\n      },\n      icon: <BookIconIcon />,\n      link: undefined,\n    },\n  },\n};\n\nexport const AccessibilityIcon: Story = {\n  args: {\n    notification: {\n      id: '11',\n      onClear,\n      content: {\n        headline: 'Storybook has a accessibility icon!',\n        subHeadline: 'It is here!',\n      },\n      icon: <AccessibilityIconIcon />,\n      link: undefined,\n    },\n  },\n};\n\nexport const AccessibilityGoldIcon: Story = {\n  args: {\n    notification: {\n      id: '12',\n      onClear,\n      content: {\n        headline: 'Accessibility icon!',\n        subHeadline: 'It is gold!',\n      },\n      icon: <AccessibilityIconIcon color=\"gold\" />,\n      link: undefined,\n    },\n  },\n};\n\nexport const AccessibilityGoldIconLongHeadLineNoSubHeadline: Story = {\n  args: {\n    notification: {\n      id: '13',\n      onClear,\n      content: {\n        headline: 'Storybook notifications has a accessibility icon it can be any color!',\n      },\n      icon: <AccessibilityIconIcon color=\"gold\" />,\n      link: undefined,\n    },\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/components/notifications/NotificationItem.tsx",
    "content": "import type { FC, SyntheticEvent } from 'react';\nimport React, { useCallback, useEffect, useRef } from 'react';\n\nimport { Button } from 'storybook/internal/components';\nimport { Link } from 'storybook/internal/router';\n\nimport { CloseAltIcon } from '@storybook/icons';\n\nimport { transparentize } from 'polished';\nimport { type State } from 'storybook/manager-api';\nimport { keyframes, styled } from 'storybook/theming';\n\nimport { MEDIA_DESKTOP_BREAKPOINT } from '../../constants.ts';\n\nconst slideIn = keyframes({\n  '0%': {\n    opacity: 0,\n    transform: 'translateY(30px)',\n  },\n  '100%': {\n    opacity: 1,\n    transform: 'translateY(0)',\n  },\n});\n\nconst grow = keyframes({\n  '0%': {\n    width: '0%',\n  },\n  '100%': {\n    width: '100%',\n  },\n});\n\nconst Notification = styled.div<{ duration?: number }>(\n  ({ theme }) => ({\n    position: 'relative',\n    display: 'flex',\n    border: `1px solid ${theme.appBorderColor}`,\n    padding: '12px 6px 12px 12px',\n    borderRadius: theme.appBorderRadius + 1,\n    alignItems: 'center',\n\n    animation: `${slideIn} 500ms`,\n    background: theme.base === 'light' ? 'hsla(203, 50%, 20%, .97)' : 'hsla(203, 30%, 95%, .97)',\n    boxShadow: `0 2px 5px 0 rgba(0, 0, 0, 0.05), 0 5px 15px 0 rgba(0, 0, 0, 0.1)`,\n    color: theme.color.inverseText,\n    textDecoration: 'none',\n    overflow: 'hidden',\n\n    [MEDIA_DESKTOP_BREAKPOINT]: {\n      boxShadow: `0 1px 2px 0 rgba(0, 0, 0, 0.05), 0px -5px 20px 10px ${theme.background.app}`,\n    },\n  }),\n  ({ duration, theme }) =>\n    duration && {\n      '&::after': {\n        content: '\"\"',\n        display: 'block',\n        position: 'absolute',\n        bottom: 0,\n        left: 0,\n        height: 3,\n        background: theme.color.secondary,\n        animation: `${grow} ${duration}ms linear forwards reverse`,\n      },\n    }\n);\n\nconst NotificationWithInteractiveStates = styled(Notification)({\n  cursor: 'pointer',\n  border: 'none',\n  outline: 'none',\n  textAlign: 'left',\n  transition: 'all 150ms ease-out',\n  transform: 'translate3d(0, 0, 0)',\n  '&:hover': {\n    transform: 'translate3d(0, -3px, 0)',\n    boxShadow:\n      '0 1px 3px 0 rgba(30,167,253,0.5), 0 2px 5px 0 rgba(0,0,0,0.05), 0 5px 15px 0 rgba(0,0,0,0.1)',\n  },\n  '&:active': {\n    transform: 'translate3d(0, 0, 0)',\n    boxShadow:\n      '0 1px 3px 0 rgba(30,167,253,0.5), 0 2px 5px 0 rgba(0,0,0,0.05), 0 5px 15px 0 rgba(0,0,0,0.1)',\n  },\n  '&:focus': {\n    boxShadow:\n      'rgba(2,156,253,1) 0 0 0 1px inset, 0 1px 3px 0 rgba(30,167,253,0.5), 0 2px 5px 0 rgba(0,0,0,0.05), 0 5px 15px 0 rgba(0,0,0,0.1)',\n  },\n});\nconst NotificationButton = NotificationWithInteractiveStates.withComponent('div');\nconst NotificationLink = NotificationWithInteractiveStates.withComponent(Link);\n\nconst NotificationIconWrapper = styled.div({\n  display: 'flex',\n  marginRight: 10,\n  alignItems: 'center',\n\n  svg: {\n    width: 16,\n    height: 16,\n  },\n});\n\nconst NotificationTextWrapper = styled.div(({ theme }) => ({\n  width: '100%',\n  display: 'flex',\n  flexDirection: 'column',\n  color: theme.color.inverseText,\n}));\n\nconst Headline = styled.div(({ theme }) => ({\n  height: '100%',\n  alignItems: 'center',\n  whiteSpace: 'balance',\n  overflow: 'hidden',\n  textOverflow: 'ellipsis',\n  fontSize: theme.typography.size.s1,\n  lineHeight: '16px',\n  fontWeight: theme.typography.weight.bold,\n}));\n\nconst SubHeadline = styled.div(({ theme }) => ({\n  color: transparentize(0.25, theme.color.inverseText),\n  fontSize: theme.typography.size.s1 - 1,\n  lineHeight: '14px',\n  marginTop: 2,\n  whiteSpace: 'balance',\n}));\n\nconst ItemContent: FC<Pick<State['notifications'][0], 'icon' | 'content'>> = ({\n  icon,\n  content: { headline, subHeadline },\n}) => (\n  <>\n    {!icon || <NotificationIconWrapper>{icon}</NotificationIconWrapper>}\n    <NotificationTextWrapper>\n      <Headline title={headline}>{headline}</Headline>\n      {subHeadline && <SubHeadline>{subHeadline}</SubHeadline>}\n    </NotificationTextWrapper>\n  </>\n);\n\nconst DismissButtonWrapper = styled(Button)(({ theme }) => ({\n  width: 28,\n  alignSelf: 'center',\n  marginTop: 0,\n  color: theme.base === 'light' ? 'rgba(255,255,255,0.7)' : ' #999999',\n}));\n\nconst DismissNotificationItem: FC<{\n  onDismiss: () => void;\n}> = ({ onDismiss }) => (\n  <DismissButtonWrapper\n    padding=\"small\"\n    variant=\"ghost\"\n    ariaLabel=\"Dismiss notification\"\n    onClick={(e: SyntheticEvent) => {\n      e.preventDefault();\n      e.stopPropagation();\n      onDismiss();\n    }}\n  >\n    <CloseAltIcon size={12} />\n  </DismissButtonWrapper>\n);\n\nexport const NotificationItemSpacer = styled.div({\n  height: 48,\n});\n\nconst NotificationItem: FC<{\n  notification: State['notifications'][0];\n  onDismissNotification: (id: string) => void;\n  zIndex?: number;\n}> = ({\n  notification: { content, duration, link, onClear, onClick, id, icon },\n  onDismissNotification,\n  zIndex,\n}) => {\n  const onTimeout = useCallback(() => {\n    onDismissNotification(id);\n\n    if (onClear) {\n      onClear({ dismissed: false, timeout: true });\n    }\n  }, [id, onDismissNotification, onClear]);\n\n  const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n  useEffect(() => {\n    if (!duration) {\n      return;\n    }\n    timer.current = setTimeout(onTimeout, duration);\n    // @ts-expect-error (non strict)\n    return () => clearTimeout(timer.current);\n  }, [duration, onTimeout]);\n\n  const onDismiss = useCallback(() => {\n    // @ts-expect-error (non strict)\n    clearTimeout(timer.current);\n    onDismissNotification(id);\n\n    if (onClear) {\n      onClear({ dismissed: true, timeout: false });\n    }\n  }, [id, onDismissNotification, onClear]);\n\n  if (link) {\n    return (\n      <NotificationLink to={link} duration={duration} style={{ zIndex }}>\n        <ItemContent icon={icon} content={content} />\n        <DismissNotificationItem onDismiss={onDismiss} />\n      </NotificationLink>\n    );\n  }\n\n  if (onClick) {\n    return (\n      <NotificationButton\n        duration={duration}\n        onClick={() => onClick({ onDismiss })}\n        style={{ zIndex }}\n      >\n        <ItemContent icon={icon} content={content} />\n        <DismissNotificationItem onDismiss={onDismiss} />\n      </NotificationButton>\n    );\n  }\n\n  return (\n    <Notification duration={duration} style={{ zIndex }}>\n      <ItemContent icon={icon} content={content} />\n      <DismissNotificationItem onDismiss={onDismiss} />\n    </Notification>\n  );\n};\n\nexport default NotificationItem;\n"
  },
  {
    "path": "code/core/src/manager/components/notifications/NotificationList.stories.tsx",
    "content": "import React from 'react';\n\nimport { LocationProvider } from 'storybook/internal/router';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport * as itemStories from './NotificationItem.stories.tsx';\nimport { NotificationList } from './NotificationList.tsx';\n\nconst meta = {\n  component: NotificationList,\n  title: 'Notifications/NotificationList',\n  decorators: [\n    (StoryFn) => (\n      <LocationProvider>\n        <StoryFn />\n      </LocationProvider>\n    ),\n\n    (storyFn) => (\n      <div style={{ width: '240px', margin: '1rem', position: 'relative', height: '100%' }}>\n        {storyFn()}\n      </div>\n    ),\n  ],\n  excludeStories: /.*Data$/,\n} satisfies Meta<typeof NotificationList>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\ntype ItemStories = typeof itemStories & { [key: string]: any };\n\nconst items = Array.from(Object.keys(itemStories as ItemStories))\n  .filter((key) => !['default', '__namedExportsOrder'].includes(key))\n  .map((key) => (itemStories as ItemStories)[key].args.notification);\n\nexport const Single: Story = {\n  args: {\n    notifications: [items[0]],\n    clearNotification: () => {},\n  },\n};\n\nexport const Multiple: Story = {\n  args: {\n    notifications: items.slice(0, 3),\n    clearNotification: () => {},\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/components/notifications/NotificationList.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport type { State } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport { useLayout } from '../layout/LayoutProvider.tsx';\nimport NotificationItem from './NotificationItem.tsx';\n\ninterface NotificationListProps {\n  notifications: State['notifications'];\n  clearNotification: (id: string) => void;\n}\n\nexport const NotificationList: FC<NotificationListProps> = ({\n  notifications,\n  clearNotification,\n}) => {\n  const { isMobile } = useLayout();\n  return (\n    <List isMobile={isMobile}>\n      {notifications &&\n        notifications.map((notification, index) => (\n          <NotificationItem\n            key={notification.id}\n            onDismissNotification={(id: string) => clearNotification(id)}\n            notification={notification}\n            zIndex={notifications.length - index}\n          />\n        ))}\n    </List>\n  );\n};\n\nconst List = styled.div<{ isMobile?: boolean }>(\n  {\n    zIndex: 200,\n    '> * + *': {\n      marginTop: 12,\n    },\n    '&:empty': {\n      display: 'none',\n    },\n  },\n  ({ isMobile }) =>\n    isMobile && {\n      position: 'fixed',\n      bottom: 40,\n      margin: 20,\n    }\n);\n"
  },
  {
    "path": "code/core/src/manager/components/panel/Panel.stories.tsx",
    "content": "import type { EventHandler, FocusEvent, MouseEvent } from 'react';\nimport React, { useCallback, useRef, useState } from 'react';\n\nimport { Badge, Spaced } from 'storybook/internal/components';\nimport type { Addon_BaseType, Addon_Collection } from 'storybook/internal/types';\nimport { Addon_TypesEnum } from 'storybook/internal/types';\n\nimport { BellIcon } from '@storybook/icons';\n\nimport { action } from 'storybook/actions';\n\nimport { defaultShortcuts } from '../../settings/defaultShortcuts.tsx';\nimport { AddonPanel } from './Panel.tsx';\n\nconst onSelect = action('onSelect');\nconst toggleVisibility = action('toggleVisibility');\nconst togglePosition = action('togglePosition');\n\nconst panels: Addon_Collection<Addon_BaseType> = {\n  test1: {\n    title: 'Test 1',\n    type: Addon_TypesEnum.PANEL,\n    render: ({ active }) => (active ? <div id=\"test1\">TEST 1</div> : null),\n  },\n  test2: {\n    title: 'Test 2',\n    type: Addon_TypesEnum.PANEL,\n    render: ({ active }) => (active ? <div id=\"test2\">TEST 2</div> : null),\n  },\n};\n\nexport default {\n  title: 'Panel',\n  component: AddonPanel,\n};\n\nexport const Default = () => {\n  const [selectedPanel, setSelectedPanel] = useState('test2');\n  return (\n    <AddonPanel\n      absolute={false}\n      panels={panels}\n      actions={{ onSelect: setSelectedPanel, toggleVisibility, togglePosition }}\n      selectedPanel={selectedPanel}\n      shortcuts={defaultShortcuts}\n    />\n  );\n};\n\nexport const JSXTitles = () => {\n  const [selectedPanel, setSelectedPanel] = useState('function-string');\n  return (\n    <AddonPanel\n      absolute={false}\n      panels={{\n        'function-string': {\n          type: Addon_TypesEnum.PANEL,\n          title: () => 'Test 1',\n          render: ({ active }) => (active ? <div id=\"test1\">TEST as string</div> : null),\n        },\n        'function-jsx': {\n          type: Addon_TypesEnum.PANEL,\n          title: () => (\n            <div>\n              <Spaced col={1}>\n                <div style={{ display: 'inline-block', verticalAlign: 'middle' }}>Test 1</div>\n                <Badge status=\"critical\">4</Badge>\n              </Spaced>\n            </div>\n          ),\n          render: ({ active }) => (active ? <div id=\"test1\">TEST with label</div> : null),\n        },\n        'function-jsx-icon': {\n          type: Addon_TypesEnum.PANEL,\n          title: () => (\n            <div>\n              <Spaced col={1}>\n                <div style={{ display: 'inline-block', verticalAlign: 'middle' }}>Alert!</div>\n                <BellIcon />\n              </Spaced>\n            </div>\n          ),\n          render: ({ active }) => (active ? <div id=\"test1\">TEST with label</div> : null),\n        },\n        'function-jsx-state': {\n          type: Addon_TypesEnum.PANEL,\n          title: () => {\n            const MAX = 10;\n            const [count, setCount] = useState(0);\n            const timer = useRef(null);\n\n            const startTimer = useCallback<EventHandler<MouseEvent<any>>>((event) => {\n              event.stopPropagation();\n              if (timer.current) {\n                return;\n              }\n              // @ts-expect-error (non strict)\n              timer.current = setInterval(() => {\n                setCount((c) => {\n                  if (c === MAX) {\n                    // @ts-expect-error (non strict)\n                    clearInterval(timer.current);\n                    timer.current = null;\n                    return c;\n                  }\n                  return c + 1;\n                });\n              }, 1000);\n            }, []);\n            const stopTimer = useCallback<EventHandler<MouseEvent<any> | FocusEvent<any>>>(\n              (event) => {\n                event.stopPropagation();\n                if (timer.current) {\n                  clearInterval(timer.current);\n                  timer.current = null;\n                }\n              },\n              []\n            );\n\n            return (\n              <div\n                onMouseEnter={startTimer}\n                onMouseLeave={stopTimer}\n                onBlur={stopTimer}\n                tabIndex={-1}\n              >\n                <Spaced col={1}>\n                  <div style={{ display: 'inline-block' }}>Hover over me!</div>\n                  {count ? (\n                    <Badge status={count > 8 ? 'critical' : 'warning'}>{count}</Badge>\n                  ) : null}\n                </Spaced>\n              </div>\n            );\n          },\n          render: ({ active }) => {\n            return active ? <div id=\"test1\">TEST with timer</div> : null;\n          },\n        },\n      }}\n      actions={{ onSelect: setSelectedPanel, toggleVisibility, togglePosition }}\n      selectedPanel={selectedPanel}\n      shortcuts={defaultShortcuts}\n    />\n  );\n};\n\nexport const NoPanels = () => (\n  <AddonPanel\n    panels={{}}\n    actions={{ onSelect, toggleVisibility, togglePosition }}\n    shortcuts={defaultShortcuts}\n  />\n);\n"
  },
  {
    "path": "code/core/src/manager/components/panel/Panel.tsx",
    "content": "import type { ReactNode } from 'react';\nimport React, { Component, useMemo, useRef } from 'react';\n\nimport {\n  Button,\n  EmptyTabContent,\n  Link,\n  StatelessTab,\n  StatelessTabList,\n  StatelessTabPanel,\n  StatelessTabsView,\n} from 'storybook/internal/components';\nimport type { Addon_BaseType } from 'storybook/internal/types';\n\nimport { BottomBarIcon, CloseIcon, DocumentIcon, SidebarAltIcon } from '@storybook/icons';\n\nimport type { State } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport { focusableUIElements } from '../../../manager-api/modules/layout.ts';\nimport { useLandmark } from '../../hooks/useLandmark.ts';\nimport { useLayout } from '../layout/LayoutProvider.tsx';\n\nexport interface SafeTabProps {\n  title: Addon_BaseType['title'];\n  id: string;\n  children: Addon_BaseType['render'];\n}\n\ninterface ErrorBoundaryProps {\n  children: ReactNode;\n}\n\nclass TabErrorBoundary extends Component<ErrorBoundaryProps, { hasError: boolean }> {\n  constructor(props: ErrorBoundaryProps) {\n    super(props);\n    this.state = { hasError: false };\n  }\n\n  static getDerivedStateFromError() {\n    return { hasError: true };\n  }\n\n  componentDidCatch(error: Error, info: React.ErrorInfo) {\n    console.error('Error rendering addon panel');\n    console.error(error);\n    console.error(info.componentStack);\n  }\n\n  render() {\n    const { hasError } = this.state;\n    if (hasError) {\n      return (\n        <EmptyTabContent\n          title=\"This addon has errors\"\n          description=\"Check your browser logs and addon code to pinpoint what went wrong. This issue was not caused by Storybook.\"\n        />\n      );\n    }\n\n    const { children } = this.props;\n    return children;\n  }\n}\n\nconst Aside = styled.aside({\n  height: '100%',\n  display: 'flex',\n  flexDirection: 'column',\n});\n\n// Ensures we don't cause difficult-to-debug hooks violations\n// whether addon authors pass a React component ctor or anonymous function.\nfunction renderChild(RenderProp: Addon_BaseType['render']) {\n  return <RenderProp active={true} />;\n}\n\n// Avoids crashes due to rules of hooks.\nconst PreRenderAddons = ({ panels }: { panels: Record<string, Addon_BaseType> }) => {\n  return Object.entries(panels).map(([k, v]) => (\n    <StatelessTabPanel key={k} name={k} hasScrollbar={false}>\n      <TabErrorBoundary key={k}>{renderChild(v.render)}</TabErrorBoundary>\n    </StatelessTabPanel>\n  ));\n};\n\nexport const AddonPanel = React.memo<{\n  selectedPanel?: string;\n  actions: { onSelect: (id: string) => void } & Record<string, any>;\n  panels: Record<string, Addon_BaseType>;\n  shortcuts: State['shortcuts'];\n  panelPosition?: 'bottom' | 'right';\n  absolute?: boolean;\n}>(({ panels, shortcuts, actions, selectedPanel = null, panelPosition = 'right' }) => {\n  const { isDesktop, setMobilePanelOpen } = useLayout();\n\n  const emptyState = (\n    <EmptyTabContent\n      title=\"Storybook add-ons\"\n      description={\n        <>Integrate your tools with Storybook to connect workflows and unlock advanced features.</>\n      }\n      footer={\n        <Link href={'https://storybook.js.org/addons?ref=ui'} target=\"_blank\" withArrow>\n          <DocumentIcon /> Explore integrations catalog\n        </Link>\n      }\n    />\n  );\n\n  const tools = useMemo(\n    () => (\n      <ActionsWrapper>\n        {isDesktop ? (\n          <>\n            <Button\n              key=\"position\"\n              padding=\"small\"\n              variant=\"ghost\"\n              onClick={actions.togglePosition}\n              ariaLabel={\n                panelPosition === 'bottom'\n                  ? 'Move addon panel to right'\n                  : 'Move addon panel to bottom'\n              }\n              ariaDescription=\"Changes the location of the addon panel to the bottom or right of the screen, but does not have any effect on its content.\"\n              shortcut={shortcuts.panelPosition}\n            >\n              {panelPosition === 'bottom' ? <SidebarAltIcon /> : <BottomBarIcon />}\n            </Button>\n            <Button\n              key=\"visibility\"\n              padding=\"small\"\n              variant=\"ghost\"\n              onClick={actions.toggleVisibility}\n              ariaLabel=\"Hide addon panel\"\n              shortcut={shortcuts.togglePanel}\n            >\n              <CloseIcon />\n            </Button>\n          </>\n        ) : (\n          <Button\n            padding=\"small\"\n            variant=\"ghost\"\n            onClick={() => setMobilePanelOpen(false)}\n            ariaLabel=\"Close addon panel\"\n          >\n            <CloseIcon />\n          </Button>\n        )}\n      </ActionsWrapper>\n    ),\n    [actions, isDesktop, panelPosition, setMobilePanelOpen, shortcuts]\n  );\n\n  const asideRef = useRef<HTMLElement>(null);\n  const { landmarkProps } = useLandmark(\n    { 'aria-labelledby': 'storybook-panel-heading', role: 'region' },\n    asideRef\n  );\n\n  return (\n    <Aside ref={asideRef} id={focusableUIElements.addonPanel} {...landmarkProps}>\n      <h2 id=\"storybook-panel-heading\" className=\"sb-sr-only\">\n        Addon panel\n      </h2>\n      <StatelessTabsView\n        id={focusableUIElements.storyPanelRoot}\n        showToolsWhenEmpty\n        emptyState={emptyState}\n        selected={selectedPanel ?? undefined}\n        onSelectionChange={(id) => actions.onSelect(id)}\n        tools={tools}\n      >\n        <StatelessTabList aria-label=\"Available addons\">\n          {Object.entries(panels).map(([k, v]) => (\n            <StatelessTab key={k} name={k}>\n              {typeof v.title === 'function' ? <v.title /> : v.title}\n            </StatelessTab>\n          ))}\n        </StatelessTabList>\n        {Object.keys(panels).length ? <PreRenderAddons panels={panels} /> : null}\n      </StatelessTabsView>\n    </Aside>\n  );\n});\n\nAddonPanel.displayName = 'AddonPanel';\n\nconst ActionsWrapper = styled.div({\n  display: 'flex',\n  alignItems: 'center',\n  gap: 6,\n});\n"
  },
  {
    "path": "code/core/src/manager/components/preview/FramesRenderer.tsx",
    "content": "import type { FC } from 'react';\nimport React, { Fragment, useRef } from 'react';\n\nimport { Button } from 'storybook/internal/components';\n\nimport type { Combo } from 'storybook/manager-api';\nimport { Consumer } from 'storybook/manager-api';\nimport { Global, styled } from 'storybook/theming';\nimport type { CSSObject } from 'storybook/theming';\n\nimport { Viewport } from './Viewport.tsx';\nimport type { FramesRendererProps } from './utils/types.tsx';\n\nconst getActive = (refId: FramesRendererProps['refId'], refs: FramesRendererProps['refs']) => {\n  if (refId && refs[refId]) {\n    return `storybook-ref-${refId}`;\n  }\n\n  return 'storybook-preview-iframe';\n};\n\nconst SkipToSidebarLink = styled(Button)(({ theme }) => ({\n  display: 'none',\n  '@media (min-width: 600px)': {\n    position: 'absolute',\n    display: 'block',\n    top: 10,\n    right: 15,\n    padding: '10px 15px',\n    fontSize: theme.typography.size.s1,\n    transform: 'translateY(-100px)',\n    '&:focus': {\n      transform: 'translateY(0)',\n      zIndex: 1,\n    },\n  },\n}));\n\nconst whenSidebarIsVisible = ({ api, state }: Combo) => ({\n  isFullscreen: api.getIsFullscreen(),\n  isNavShown: api.getIsNavShown(),\n  selectedStoryId: state.storyId,\n});\n\nconst styles: CSSObject = {\n  '#root [data-is-storybook=\"false\"]': {\n    display: 'none',\n  },\n  '#root [data-is-storybook=\"true\"]': {\n    display: 'block',\n  },\n};\n\nexport const FramesRenderer: FC<FramesRendererProps> = ({\n  api,\n  refs,\n  scale,\n  viewMode = 'story',\n  refId,\n  queryParams = {},\n  storyId = '*',\n}) => {\n  const version = refs[refId]?.version;\n  const active = getActive(refId, refs);\n  const { current: frames } = useRef<Record<string, string>>({});\n\n  const refsToLoad = Object.values(refs).filter((ref) => {\n    return ref.type === 'auto-inject' || ref.id === refId;\n  }, {});\n\n  if (!frames['storybook-preview-iframe']) {\n    frames['storybook-preview-iframe'] = api.getStoryHrefs(storyId, {\n      queryParams: { ...queryParams, ...(version && { version }) },\n      refId,\n      viewMode,\n    }).previewHref;\n  }\n\n  refsToLoad.forEach((ref) => {\n    const id = `storybook-ref-${ref.id}`;\n    if (!frames[id]?.startsWith(`${ref.url.replace(/\\/?$/, '/')}iframe.html`)) {\n      frames[id] = api.getStoryHrefs(storyId, {\n        queryParams: { ...queryParams, ...(version && { version }) },\n        refId: ref.id,\n        viewMode,\n      }).previewHref;\n    }\n  });\n\n  return (\n    <Fragment>\n      <Global styles={styles} />\n      <Consumer filter={whenSidebarIsVisible}>\n        {({ isFullscreen, isNavShown, selectedStoryId }) => {\n          if (isFullscreen || !isNavShown || !selectedStoryId) {\n            return null;\n          }\n          return (\n            <SkipToSidebarLink ariaLabel={false} asChild>\n              <a href={`#${selectedStoryId}`} tabIndex={0}>\n                Skip to sidebar\n              </a>\n            </SkipToSidebarLink>\n          );\n        }}\n      </Consumer>\n      {Object.entries(frames).map(([id, src]) => (\n        <Viewport key={id} id={id} src={src} active={id === active} scale={scale} />\n      ))}\n    </Fragment>\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/components/preview/Iframe.stories.tsx",
    "content": "import type { CSSProperties } from 'react';\nimport React from 'react';\n\nimport { IFrame } from './Iframe.tsx';\n\nexport default {\n  component: IFrame,\n  title: 'Iframe',\n  parameters: {\n    layout: 'fullscreen',\n    viewport: {\n      defaultViewport: 'sized',\n      viewports: {\n        sized: {\n          name: 'Sized',\n          styles: {\n            width: '700px',\n            height: '700px',\n          },\n        },\n      },\n    },\n    chromatic: { viewports: [700] },\n  },\n  globals: { sb_theme: 'light' },\n};\n\nconst style: CSSProperties = {\n  maxWidth: '700px',\n  height: '700px',\n};\n\nexport const WorkingStory = {\n  render: () => (\n    <IFrame\n      active\n      id=\"iframe\"\n      title=\"Missing\"\n      src=\"/iframe.html?id=components-loader--infinite-state\"\n      allowFullScreen\n      style={style}\n      scale={1.0}\n    />\n  ),\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const WorkingDocs = {\n  render: () => (\n    <IFrame\n      active\n      id=\"iframe\"\n      title=\"Missing\"\n      src=\"/iframe.html?id=brand-colorpalette--docs\"\n      allowFullScreen\n      style={style}\n      scale={1.0}\n    />\n  ),\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const MissingStory = {\n  render: () => (\n    <IFrame\n      active\n      id=\"iframe\"\n      title=\"Missing\"\n      src=\"/iframe.html?id=missing\"\n      allowFullScreen\n      style={style}\n      scale={1.0}\n    />\n  ),\n  parameters: {\n    // Raise the threshold to ignore monospace font inconsistencies\n    chromatic: { diffThreshold: 0.65 },\n  },\n};\n\nexport const PreparingStory = {\n  render: () => (\n    <IFrame\n      active\n      id=\"iframe\"\n      title=\"Preparing Story\"\n      src=\"/iframe.html?__SPECIAL_TEST_PARAMETER__=preparing-story\"\n      allowFullScreen\n      style={style}\n      scale={1.0}\n    />\n  ),\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const PreparingDocs = {\n  render: () => (\n    <IFrame\n      active\n      id=\"iframe\"\n      title=\"Preparing Docs\"\n      src=\"/iframe.html?__SPECIAL_TEST_PARAMETER__=preparing-docs\"\n      allowFullScreen\n      style={style}\n      scale={1.0}\n    />\n  ),\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/components/preview/Iframe.tsx",
    "content": "import type { IframeHTMLAttributes } from 'react';\nimport React from 'react';\n\nimport { Zoom } from 'storybook/internal/components';\n\nimport { styled } from 'storybook/theming';\n\nconst StyledIframe = styled.iframe(({ theme }) => ({\n  backgroundColor: theme.background.preview,\n  display: 'block',\n  boxSizing: 'content-box',\n  height: '100%',\n  width: '100%',\n  border: 'none',\n  transition: 'background-position 0s, visibility 0s',\n  backgroundPosition: '-1px -1px, -1px -1px, -1px -1px, -1px -1px',\n  margin: `auto`,\n}));\n\nexport interface IFrameProps {\n  id: string;\n  title: string;\n  src: string;\n  allowFullScreen: boolean;\n  scale: number;\n  active: boolean;\n}\n\nexport function IFrame(props: IFrameProps & IframeHTMLAttributes<HTMLIFrameElement>) {\n  const { active, id, title, src, allowFullScreen, scale, ...rest } = props;\n  const iFrameRef = React.useRef<HTMLIFrameElement>(null);\n  return (\n    <Zoom.IFrame scale={scale} active={active} iFrameRef={iFrameRef}>\n      <StyledIframe\n        data-is-storybook={active ? 'true' : 'false'}\n        onLoad={(e) => e.currentTarget.setAttribute('data-is-loaded', 'true')}\n        id={id}\n        title={title}\n        src={src}\n        allow=\"clipboard-write;\"\n        allowFullScreen={allowFullScreen}\n        ref={iFrameRef}\n        {...rest}\n      />\n    </Zoom.IFrame>\n  );\n}\n"
  },
  {
    "path": "code/core/src/manager/components/preview/NumericInput.stories.tsx",
    "content": "import { useState } from 'react';\n\nimport { expect, fireEvent, fn, mocked } from 'storybook/test';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { NumericInput } from './NumericInput.tsx';\n\nconst meta = preview.meta({\n  component: NumericInput,\n  tags: ['autodocs'],\n  args: {\n    setValue: fn(),\n  },\n  render: (args) => {\n    const [value, setValue] = useState(args.value);\n    args.value = value;\n    args.setValue = mocked(args.setValue).mockImplementation(setValue);\n    return <NumericInput {...args} />;\n  },\n});\n\nexport default meta;\n\nexport const Default = meta.story({\n  args: {\n    value: '10',\n  },\n  play: async ({ args, canvas }) => {\n    const input = await canvas.findByRole('textbox');\n    fireEvent.keyDown(input, { key: 'ArrowUp' });\n    fireEvent.keyDown(input, { key: 'ArrowUp' });\n    fireEvent.keyDown(input, { key: 'ArrowDown' });\n    expect(input).toHaveValue('11');\n    expect(args.setValue).toHaveBeenNthCalledWith(1, '11');\n    expect(args.setValue).toHaveBeenNthCalledWith(2, '12');\n    expect(args.setValue).toHaveBeenNthCalledWith(3, '11');\n  },\n});\n\nexport const WithParsedUnit = meta.story({\n  args: {\n    value: '10em',\n  },\n  play: async ({ args, canvas }) => {\n    const input = await canvas.findByRole('textbox');\n    fireEvent.keyDown(input, { key: 'ArrowUp' });\n    fireEvent.keyDown(input, { key: 'ArrowUp' });\n    fireEvent.keyDown(input, { key: 'ArrowDown' });\n    expect(input).toHaveValue('11em');\n    expect(args.setValue).toHaveBeenNthCalledWith(1, '11em');\n    expect(args.setValue).toHaveBeenNthCalledWith(2, '12em');\n    expect(args.setValue).toHaveBeenNthCalledWith(3, '11em');\n  },\n});\n\nexport const WithExplicitUnit = meta.story({\n  args: {\n    value: '10',\n    unit: 'vw',\n  },\n  play: async ({ args, canvas }) => {\n    const input = await canvas.findByRole('textbox');\n    fireEvent.keyDown(input, { key: 'ArrowUp' });\n    fireEvent.keyDown(input, { key: 'ArrowUp' });\n    fireEvent.keyDown(input, { key: 'ArrowDown' });\n    expect(input).toHaveValue('11');\n    expect(args.setValue).toHaveBeenNthCalledWith(1, '11vw');\n    expect(args.setValue).toHaveBeenNthCalledWith(2, '12vw');\n    expect(args.setValue).toHaveBeenNthCalledWith(3, '11vw');\n  },\n});\n\nexport const WithBaseUnit = meta.story({\n  args: {\n    value: '10em',\n    baseUnit: 'em',\n  },\n  play: async ({ args, canvas }) => {\n    const input = await canvas.findByRole('textbox');\n    fireEvent.keyDown(input, { key: 'ArrowUp' });\n    fireEvent.keyDown(input, { key: 'ArrowUp' });\n    fireEvent.keyDown(input, { key: 'ArrowDown' });\n    expect(input).toHaveValue('11');\n    expect(args.setValue).toHaveBeenNthCalledWith(1, '11em');\n    expect(args.setValue).toHaveBeenNthCalledWith(2, '12em');\n    expect(args.setValue).toHaveBeenNthCalledWith(3, '11em');\n  },\n});\n\nexport const WithMinAndMax = meta.story({\n  args: {\n    value: '10em',\n    minValue: 9,\n    maxValue: 11,\n  },\n  play: async ({ args, canvas }) => {\n    const input = await canvas.findByRole('textbox');\n    fireEvent.keyDown(input, { key: 'ArrowUp' });\n    fireEvent.keyDown(input, { key: 'ArrowUp' });\n    fireEvent.keyDown(input, { key: 'ArrowUp' });\n    expect(input).toHaveValue('11em');\n    fireEvent.keyDown(input, { key: 'ArrowDown' });\n    fireEvent.keyDown(input, { key: 'ArrowDown' });\n    fireEvent.keyDown(input, { key: 'ArrowDown' });\n    expect(input).toHaveValue('9em');\n    expect(args.setValue).toHaveBeenNthCalledWith(1, '11em');\n    expect(args.setValue).toHaveBeenNthCalledWith(2, '11em');\n    expect(args.setValue).toHaveBeenNthCalledWith(3, '11em');\n    expect(args.setValue).toHaveBeenNthCalledWith(4, '10em');\n    expect(args.setValue).toHaveBeenNthCalledWith(5, '9em');\n    expect(args.setValue).toHaveBeenNthCalledWith(6, '9em');\n  },\n});\n"
  },
  {
    "path": "code/core/src/manager/components/preview/NumericInput.tsx",
    "content": "import type { ChangeEvent, ComponentProps, ReactNode } from 'react';\nimport React, {\n  forwardRef,\n  useCallback,\n  useEffect,\n  useImperativeHandle,\n  useMemo,\n  useRef,\n  useState,\n} from 'react';\n\nimport { Form } from 'storybook/internal/components';\n\nimport { useId } from '@react-aria/utils';\nimport { styled } from 'storybook/theming';\n\nconst Wrapper = styled.div<{ after?: ReactNode; before?: ReactNode }>(\n  ({ after, before, theme }) => ({\n    position: 'relative',\n    display: 'flex',\n    alignItems: 'center',\n    width: '100%',\n    height: 32,\n    paddingInline: 9,\n    fontSize: theme.typography.size.s1,\n    color: theme.textMutedColor,\n    background: theme.input.background,\n    boxShadow: `${theme.input.border} 0 0 0 1px inset`,\n    borderRadius: theme.input.borderRadius,\n    svg: {\n      display: 'block',\n    },\n    input: {\n      width: '100%',\n      height: '100%',\n      minHeight: '100%',\n      flex: '1 1 auto',\n      paddingInline: 0,\n      fontSize: 'inherit',\n      background: 'transparent',\n      border: 'none',\n      boxShadow: 'none',\n      color: theme.input.color,\n      '&:focus, &:focus-visible': {\n        boxShadow: 'none',\n        outline: 'none',\n      },\n    },\n    'input:disabled': {\n      background: 'transparent',\n    },\n    'input + div': {\n      paddingInline: 0,\n      fontSize: 'inherit',\n    },\n    '&:has(input:focus-visible)': {\n      outline: `2px solid ${theme.color.secondary}`,\n      outlineOffset: -2,\n    },\n    '&:has(input:disabled)': {\n      background: theme.base === 'light' ? theme.color.lighter : theme.input.background,\n      cursor: 'not-allowed',\n    },\n    ...(after && { paddingRight: 2 }),\n    ...(before && { paddingLeft: 2 }),\n  })\n);\n\ninterface NumericInputProps extends Omit<ComponentProps<typeof Form.Input>, 'value'> {\n  label?: string;\n  before?: ReactNode;\n  after?: ReactNode;\n  value: string;\n  setValue: (value: string) => void;\n  minValue?: number;\n  maxValue?: number;\n  step?: number;\n  unit?: string;\n  baseUnit?: string;\n}\n\nexport const NumericInput = forwardRef<HTMLInputElement, NumericInputProps>(function NumericInput(\n  {\n    label,\n    before,\n    after,\n    value,\n    setValue,\n    minValue = -Infinity,\n    maxValue = Infinity,\n    step = 1,\n    unit: fixedUnit,\n    baseUnit = fixedUnit,\n    className,\n    style,\n    ...props\n  },\n  forwardedRef\n) {\n  const baseUnitRegex = useMemo(() => baseUnit && new RegExp(`${baseUnit}$`), [baseUnit]);\n  const inputId = useId();\n  const inputRef = useRef<HTMLInputElement>(null);\n  const [inputValue, setInputValue] = useState(\n    baseUnitRegex ? value.replace(baseUnitRegex, '') : value\n  );\n  const id = props.id || inputId;\n\n  useImperativeHandle(forwardedRef, () => inputRef.current!);\n\n  const parseValue = useCallback(\n    (value: string) => {\n      const [, inputValue, unit = fixedUnit || baseUnit || ''] =\n        value.match(/(-?\\d+(?:\\.\\d+)?)(\\%|[a-z]{1,4})?$/) || [];\n      const number = Math.max(minValue, Math.min(parseFloat(inputValue), maxValue));\n      return { number, unit };\n    },\n    [minValue, maxValue, fixedUnit, baseUnit]\n  );\n\n  const updateValue = useCallback(\n    (value: string) => {\n      const { number, unit } = parseValue(value);\n      if (Number.isNaN(number)) {\n        setInputValue(value);\n      } else {\n        setInputValue(`${number}${unit === baseUnit ? '' : unit}`);\n        setValue(`${number}${unit}`);\n      }\n    },\n    [parseValue, setValue, baseUnit]\n  );\n\n  const onChange = useCallback(\n    (e: ChangeEvent<HTMLInputElement>) => updateValue(e.target.value),\n    [updateValue]\n  );\n\n  const setInputSelection = useCallback(() => {\n    requestAnimationFrame(() => {\n      const input = inputRef.current;\n      const index = input?.value.search(/[^-\\d.]/) ?? -1;\n      if (input && index >= 0) {\n        input.setSelectionRange(index, index);\n      }\n    });\n  }, []);\n\n  const updateInputValue = useCallback(\n    () => setInputValue(baseUnitRegex ? value.replace(baseUnitRegex, '') : value),\n    [value, baseUnitRegex]\n  );\n\n  useEffect(() => {\n    if (inputRef.current !== document.activeElement) {\n      updateInputValue();\n    }\n  }, [updateInputValue]);\n\n  useEffect(() => {\n    const handleKeyDown = (e: KeyboardEvent) => {\n      if (e.key !== 'ArrowUp' && e.key !== 'ArrowDown') {\n        return;\n      }\n      e.preventDefault();\n\n      const { number, unit } = parseValue(inputValue);\n      if (!Number.isNaN(number)) {\n        const delta = e.shiftKey ? step * 10 : step;\n        updateValue(`${e.key === 'ArrowUp' ? number + delta : number - delta}${unit}`);\n        setInputSelection();\n      }\n    };\n\n    const input = inputRef.current;\n    if (input) {\n      input.addEventListener('keydown', handleKeyDown);\n      return () => input.removeEventListener('keydown', handleKeyDown);\n    }\n  }, [inputValue, parseValue, setInputSelection, step, updateValue]);\n\n  return (\n    <Wrapper after={after} before={before} className={className} style={style}>\n      {before && <div>{before}</div>}\n      {label && (\n        <label htmlFor={id} className=\"sb-sr-only\">\n          {label}\n        </label>\n      )}\n      <Form.Input\n        {...props}\n        id={id}\n        ref={inputRef}\n        value={inputValue}\n        suffix={fixedUnit ? fixedUnit : inputValue && baseUnit}\n        onChange={onChange}\n        onFocus={setInputSelection}\n        onBlur={updateInputValue}\n      />\n      {after && <div>{after}</div>}\n    </Wrapper>\n  );\n});\n"
  },
  {
    "path": "code/core/src/manager/components/preview/Preview.tsx",
    "content": "import type { FC } from 'react';\nimport React, { Fragment, useEffect, useRef, useState } from 'react';\n\nimport { deprecate } from 'storybook/internal/client-logger';\nimport { Loader, useTabsState } from 'storybook/internal/components';\nimport { PREVIEW_BUILDER_PROGRESS, SET_CURRENT_STORY } from 'storybook/internal/core-events';\nimport type { Addon_BaseType, Addon_WrapperType } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport type { TabListState } from '@react-stately/tabs';\nimport { Helmet } from 'react-helmet-async';\nimport { type Combo, Consumer, addons, merge, types } from 'storybook/manager-api';\n\nimport { useLandmark } from '../../hooks/useLandmark.ts';\nimport { FramesRenderer } from './FramesRenderer.tsx';\nimport { ToolbarComp } from './Toolbar.tsx';\nimport { ApplyWrappers } from './Wrappers.tsx';\nimport { ZoomConsumer, ZoomProvider } from './tools/zoom.tsx';\nimport * as S from './utils/components.ts';\nimport type { PreviewProps } from './utils/types.tsx';\n\nconst canvasMapper = ({ state, api }: Combo) => ({\n  api,\n  storyId: state.storyId,\n  refId: state.refId,\n  viewMode: state.viewMode,\n  customCanvas: api.renderPreview,\n  queryParams: state.customQueryParams,\n  getElements: api.getElements,\n  entry: api.getData(state.storyId, state.refId),\n  previewInitialized: state.previewInitialized,\n  refs: state.refs,\n});\n\nexport const createCanvasTab = (): Addon_BaseType => ({\n  id: 'canvas',\n  type: types.TAB,\n  title: 'Canvas',\n  route: ({ storyId, refId }) => (refId ? `/story/${refId}_${storyId}` : `/story/${storyId}`),\n  match: ({ viewMode }) => !!(viewMode && viewMode.match(/^(story|docs)$/)),\n  render: () => null,\n});\n\nconst Preview = React.memo<PreviewProps>(function Preview(props) {\n  const {\n    api,\n    id: previewId,\n    options,\n    viewMode,\n    storyId,\n    entry = undefined,\n    description,\n    baseUrl,\n    withLoader = true,\n    tools,\n    toolsExtra,\n    tabs,\n    wrappers,\n    tabId,\n  } = props;\n\n  // SB11: remove code\n  // NOTE: we interface with the old API without rewriting the UI because we know\n  // that addon tabs are pretty rare and we want to deprecate them. To make this UI\n  // accessible, we'd need to pass tabContent/CanvasWrap to the tabs consumed by\n  // the TabPanel. It's doable, but not worth the effort considering the feature's\n  // remaining lifespan.\n  const tabState = useTabsState({\n    selected: tabId ?? 'canvas',\n    onSelectionChange: (key) => {\n      api.applyQueryParams({ tab: key === 'canvas' ? undefined : key });\n    },\n    tabs: tabs.map((tab, index) => ({\n      id: tab.id ?? `tab-${index}`,\n      title: tab.title,\n      isDisabled: !!tab.disabled,\n      children: () => tab.render({ active: true }),\n    })),\n  });\n\n  if (tabs.length > 1) {\n    deprecate('Addon tabs are deprecated and will be removed in Storybook 11.');\n  }\n  // SB11: end remove code\n\n  const tabContent = tabs.find((tab) => tab.id === tabId)?.render;\n\n  const shouldScale = viewMode === 'story';\n  const { showToolbar } = options;\n  const customisedShowToolbar = api.getShowToolbarWithCustomisations(showToolbar);\n\n  const previousStoryId = useRef(storyId);\n\n  useEffect(() => {\n    if (entry && viewMode) {\n      // Don't emit the event on first (\"real\") render, only when entry changes\n      if (storyId === previousStoryId.current) {\n        return;\n      }\n\n      previousStoryId.current = storyId;\n\n      if (viewMode.match(/docs|story/)) {\n        const { refId, id } = entry;\n        api.emit(SET_CURRENT_STORY, {\n          storyId: id,\n          viewMode,\n          options: { target: refId },\n        });\n      }\n    }\n  }, [entry, viewMode, storyId, api]);\n\n  const mainRef = useRef<HTMLElement>(null);\n  const { landmarkProps } = useLandmark(\n    { 'aria-labelledby': 'main-preview-heading', role: 'main' },\n    mainRef\n  );\n\n  return (\n    <Fragment>\n      {previewId === 'main' && (\n        <Helmet key=\"description\">\n          <title>{description}</title>\n        </Helmet>\n      )}\n      <ZoomProvider shouldScale={shouldScale}>\n        <S.PreviewContainer>\n          <ToolbarComp\n            key=\"tools\"\n            isShown={customisedShowToolbar}\n            tabs={tabs}\n            tabState={tabState as TabListState<object>}\n            tools={tools}\n            toolsExtra={toolsExtra}\n          />\n          <S.FrameWrap ref={mainRef} {...landmarkProps}>\n            <h2 id=\"main-preview-heading\" className=\"sb-sr-only\">\n              Main preview area\n            </h2>\n            {tabContent && <S.IframeWrapper>{tabContent({ active: true })}</S.IframeWrapper>}\n            <S.CanvasWrap show={!tabId || tabId === 'canvas'}>\n              <Canvas {...{ withLoader, baseUrl }} wrappers={wrappers} />\n            </S.CanvasWrap>\n          </S.FrameWrap>\n        </S.PreviewContainer>\n      </ZoomProvider>\n    </Fragment>\n  );\n});\n\nexport { Preview };\n\nconst Canvas: FC<{\n  withLoader: boolean;\n  baseUrl: string;\n  children?: never;\n  wrappers: Addon_WrapperType[];\n}> = ({ baseUrl, withLoader, wrappers }) => {\n  return (\n    <Consumer filter={canvasMapper}>\n      {({\n        api,\n        entry,\n        refs,\n        customCanvas,\n        storyId,\n        refId,\n        viewMode,\n        queryParams,\n        previewInitialized,\n      }) => {\n        const id = 'canvas';\n\n        const [progress, setProgress] = useState(undefined);\n        useEffect(() => {\n          if (global.CONFIG_TYPE === 'DEVELOPMENT') {\n            try {\n              const channel = addons.getChannel();\n\n              channel.on(PREVIEW_BUILDER_PROGRESS, (options) => {\n                setProgress(options);\n              });\n            } catch {\n              //\n            }\n          }\n        }, []);\n        // A ref simply depends on its readiness\n        // @ts-expect-error (non strict)\n        const refLoading = !!refs[refId] && !refs[refId].previewInitialized;\n        // The root also might need to wait on webpack\n        // @ts-expect-error (non strict)\n        const isBuilding = !(progress?.value === 1 || progress === undefined);\n        const rootLoading = !refId && (!previewInitialized || isBuilding);\n        const isLoading = entry ? refLoading || rootLoading : rootLoading;\n\n        return (\n          <ZoomConsumer>\n            {({ value: scale }) => {\n              return (\n                <>\n                  {withLoader && isLoading && (\n                    <S.LoaderWrapper>\n                      <Loader id=\"preview-loader\" role=\"progressbar\" progress={progress} />\n                    </S.LoaderWrapper>\n                  )}\n                  <ApplyWrappers id={id} storyId={storyId} viewMode={viewMode} wrappers={wrappers}>\n                    {customCanvas ? (\n                      customCanvas(storyId, viewMode, id, baseUrl, scale, queryParams)\n                    ) : (\n                      <FramesRenderer\n                        api={api}\n                        refs={refs}\n                        scale={scale}\n                        entry={entry}\n                        viewMode={viewMode}\n                        // @ts-expect-error (non strict)\n                        refId={refId}\n                        queryParams={queryParams}\n                        storyId={storyId}\n                      />\n                    )}\n                  </ApplyWrappers>\n                </>\n              );\n            }}\n          </ZoomConsumer>\n        );\n      }}\n    </Consumer>\n  );\n};\n\nexport function filterTabs(panels: Addon_BaseType[], parameters?: Record<string, any> | undefined) {\n  const { previewTabs } = addons.getConfig();\n  const parametersTabs = parameters ? parameters.previewTabs : undefined;\n\n  if (previewTabs || parametersTabs) {\n    // deep merge global and local settings\n    const tabs = merge(previewTabs || {}, parametersTabs || {});\n    const arrTabs = Object.keys(tabs).map((key, index) => ({\n      index,\n      ...(typeof tabs[key] === 'string' ? { title: tabs[key] } : tabs[key]),\n      id: key,\n    }));\n    return panels\n      .filter((panel) => {\n        const t = arrTabs.find((tab) => tab.id === panel.id);\n        return t === undefined || t.id === 'canvas' || !t.hidden;\n      })\n      .map((panel, index) => ({ ...panel, index }) as Addon_BaseType)\n      .sort((p1, p2) => {\n        const tab_1 = arrTabs.find((tab) => tab.id === p1.id);\n        // @ts-expect-error (Converted from ts-ignore)\n        const index_1 = tab_1 ? tab_1.index : arrTabs.length + p1.index;\n        const tab_2 = arrTabs.find((tab) => tab.id === p2.id);\n        // @ts-expect-error (Converted from ts-ignore)\n        const index_2 = tab_2 ? tab_2.index : arrTabs.length + p2.index;\n        return index_1 - index_2;\n      })\n      .map((panel) => {\n        const t = arrTabs.find((tab) => tab.id === panel.id);\n        if (t) {\n          return {\n            ...panel,\n            title: t.title || panel.title,\n            disabled: t.disabled,\n            hidden: t.hidden,\n          } as Addon_BaseType;\n        }\n        return panel;\n      });\n  }\n  return panels;\n}\n"
  },
  {
    "path": "code/core/src/manager/components/preview/SizeInput.tsx",
    "content": "import type { ChangeEvent, ComponentProps } from 'react';\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { Form } from 'storybook/internal/components';\n\nimport { useId } from '@react-aria/utils';\nimport { styled } from 'storybook/theming';\n\nconst Wrapper = styled.span<{ prefix?: string }>(({ theme, prefix }) => ({\n  position: 'relative',\n  fontSize: theme.typography.size.s1,\n  input: {\n    width: 70,\n    height: 28,\n    minHeight: 28,\n    paddingLeft: 25,\n    paddingRight: 0,\n    fontSize: 'inherit',\n    '&:focus': {\n      boxShadow: 'none',\n      outline: `2px solid ${theme.color.secondary}`,\n      outlineOffset: -2,\n    },\n  },\n  ...(prefix && {\n    '&::before': {\n      display: 'flex',\n      alignItems: 'center',\n      justifyContent: 'center',\n      content: `\"${prefix}\"`,\n      position: 'absolute',\n      left: 5,\n      top: 0,\n      bottom: 0,\n      width: 20,\n      zIndex: 1,\n      color: theme.textMutedColor,\n    },\n  }),\n}));\n\nexport const SizeInput = ({\n  label,\n  prefix,\n  value,\n  setValue,\n  ...props\n}: {\n  label?: string;\n  prefix?: string;\n  value: string;\n  setValue: (value: string) => void;\n} & Omit<ComponentProps<typeof Form.Input>, 'value'>) => {\n  const inputId = useId();\n  const inputRef = useRef<HTMLInputElement>(null);\n  const [inputValue, setInputValue] = useState(value.replace(/px$/, ''));\n  const id = props.id || inputId;\n\n  useEffect(() => setInputValue(value.replace(/px$/, '')), [value]);\n\n  const onChange = useCallback(\n    (e: ChangeEvent<HTMLInputElement>) => {\n      setInputValue(e.target.value);\n      setValue(Number.isNaN(Number(e.target.value)) ? e.target.value : `${e.target.value}px`);\n    },\n    [setValue]\n  );\n\n  useEffect(() => {\n    const handleKeyDown = (e: KeyboardEvent) => {\n      if (e.key !== 'ArrowUp' && e.key !== 'ArrowDown') {\n        return;\n      }\n      e.preventDefault();\n      const num = parseInt(inputValue, 10);\n      const update = e.key === 'ArrowUp' ? num + 1 : num - 1;\n      if (!Number.isNaN(num) && update >= 0) {\n        const unit = inputValue.match(/[0-9]{1,4}(%|[a-z]{0,4})?$/)?.[1] || 'px';\n        setInputValue(`${update}${unit === 'px' ? '' : unit}`);\n        setValue(`${update}${unit}`);\n      }\n    };\n\n    const input = inputRef.current;\n    if (input) {\n      input.addEventListener('keydown', handleKeyDown);\n      return () => input.removeEventListener('keydown', handleKeyDown);\n    }\n  }, [inputValue, setValue]);\n\n  return (\n    <Wrapper prefix={prefix}>\n      {label && (\n        <label htmlFor={id} className=\"sb-sr-only\">\n          {label}\n        </label>\n      )}\n      <Form.Input {...props} id={id} ref={inputRef} value={inputValue} onChange={onChange} />\n    </Wrapper>\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/components/preview/Toolbar.tsx",
    "content": "import React, { useRef } from 'react';\n\nimport { AbstractToolbar, Button, Separator, TabList } from 'storybook/internal/components';\nimport { type Addon_BaseType, Addon_TypesEnum } from 'storybook/internal/types';\n\nimport { CloseIcon, ExpandIcon } from '@storybook/icons';\n\nimport type { TabListState } from '@react-stately/tabs';\nimport {\n  type API,\n  type Combo,\n  Consumer,\n  type LeafEntry,\n  type State,\n  addons,\n  merge,\n  types,\n} from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport { useLandmark } from '../../hooks/useLandmark.ts';\nimport { useLayout } from '../layout/LayoutProvider.tsx';\nimport type { PreviewProps } from './utils/types.tsx';\n\nexport const getTools = (getFn: API['getElements']) => Object.values(getFn(types.TOOL));\nexport const getToolsExtra = (getFn: API['getElements']) => Object.values(getFn(types.TOOLEXTRA));\n\nconst fullScreenMapper = ({ api, state }: Combo) => {\n  return {\n    toggle: api.toggleFullscreen,\n    isFullscreen: api.getIsFullscreen(),\n    shortcut: api.getShortcutKeys().fullScreen,\n    hasPanel: Object.keys(api.getElements(Addon_TypesEnum.PANEL)).length > 0,\n    singleStory: state.singleStory,\n  };\n};\n\nexport const fullScreenTool: Addon_BaseType = {\n  title: 'fullscreen',\n  id: 'fullscreen',\n  type: types.TOOL,\n  // @ts-expect-error (non strict)\n  match: (p) => ['story', 'docs'].includes(p.viewMode),\n  render: () => {\n    const { isMobile } = useLayout();\n\n    if (isMobile) {\n      return null;\n    }\n\n    return (\n      <Consumer filter={fullScreenMapper}>\n        {({ toggle, isFullscreen, shortcut, hasPanel, singleStory }) =>\n          (!singleStory || (singleStory && hasPanel)) && (\n            <Button\n              key=\"full\"\n              padding=\"small\"\n              variant=\"ghost\"\n              onClick={() => toggle()}\n              ariaLabel={isFullscreen ? 'Exit full screen' : 'Enter full screen'}\n              shortcut={shortcut}\n            >\n              {isFullscreen ? <CloseIcon /> : <ExpandIcon />}\n            </Button>\n          )\n        }\n      </Consumer>\n    );\n  },\n};\n\nexport interface ToolData {\n  isShown: boolean;\n  tabs: Addon_BaseType[];\n  tabState: TabListState<object>;\n  tools: Addon_BaseType[];\n  toolsExtra: Addon_BaseType[];\n}\n\nexport const ToolbarComp = React.memo<ToolData>(function ToolbarComp({\n  isShown,\n  tools,\n  toolsExtra,\n  tabs,\n  tabState,\n}) {\n  const sectionRef = useRef<HTMLElement>(null);\n  const { landmarkProps } = useLandmark(\n    { 'aria-labelledby': 'sb-preview-toolbar-title', role: 'region' },\n    sectionRef\n  );\n\n  return isShown && (tabs || tools || toolsExtra) ? (\n    <StyledSection\n      className=\"sb-bar\"\n      key=\"toolbar\"\n      data-testid=\"sb-preview-toolbar\"\n      ref={sectionRef}\n      {...landmarkProps}\n    >\n      <h2 id=\"sb-preview-toolbar-title\" className=\"sb-sr-only\">\n        Toolbar\n      </h2>\n      {tabs.length > 1 ? (\n        <>\n          <TabList state={tabState} />\n          <Separator />\n        </>\n      ) : null}\n      <StyledToolbar>\n        <Tools key=\"left\" list={tools} />\n        <Tools key=\"right\" list={toolsExtra} />\n      </StyledToolbar>\n    </StyledSection>\n  ) : null;\n});\n\nexport const Tools = React.memo<{ list: Addon_BaseType[] }>(function Tools({ list }) {\n  return (\n    <ToolGroup>\n      {list.filter(Boolean).map(({ render: Render, id, ...t }, index) => (\n        // @ts-expect-error (Converted from ts-ignore)\n        <Render key={id || t.key || `f-${index}`} />\n      ))}\n    </ToolGroup>\n  );\n});\n\nfunction toolbarItemHasBeenExcluded(item: Partial<Addon_BaseType>, entry: LeafEntry | undefined) {\n  const parameters = entry?.type === 'story' && entry?.prepared ? entry?.parameters : {};\n  // @ts-expect-error (non strict)\n  const toolbarItemsFromStoryParameters = 'toolbar' in parameters ? parameters.toolbar : undefined;\n  const { toolbar: toolbarItemsFromAddonsConfig } = addons.getConfig();\n\n  const toolbarItems = merge(\n    toolbarItemsFromAddonsConfig || {},\n    toolbarItemsFromStoryParameters || {}\n  );\n\n  // @ts-expect-error (non strict)\n  return toolbarItems ? !!toolbarItems[item?.id]?.hidden : false;\n}\n\nexport function filterToolsSide(\n  tools: Addon_BaseType[],\n  entry: PreviewProps['entry'],\n  viewMode: State['viewMode'],\n  location: State['location'],\n  path: State['path'],\n  tabId: string\n) {\n  const filter = (item: Partial<Addon_BaseType>) =>\n    item &&\n    (!item.match ||\n      item.match({\n        storyId: entry?.id,\n        refId: entry?.refId,\n        viewMode,\n        location,\n        path,\n        tabId,\n      })) &&\n    !toolbarItemHasBeenExcluded(item, entry);\n\n  return tools.filter(filter);\n}\n\nconst StyledSection = styled.section(({ theme }) => ({\n  position: 'relative',\n  display: 'flex',\n  alignItems: 'center',\n  color: theme.barTextColor,\n  width: '100%',\n  flexShrink: 0,\n  overflowX: 'auto',\n  overflowY: 'hidden',\n  boxShadow: `${theme.appBorderColor}  0 -1px 0 0 inset`,\n  background: theme.barBg,\n  scrollbarColor: `${theme.barTextColor} ${theme.barBg}`,\n  scrollbarWidth: 'thin',\n  zIndex: 4,\n}));\n\nconst StyledToolbar = styled(AbstractToolbar)({\n  flex: 1,\n  display: 'flex',\n  justifyContent: 'space-between',\n  flexWrap: 'nowrap',\n  flexShrink: 0,\n  height: 40,\n  marginInline: 10,\n  gap: 30,\n});\n\nconst ToolGroup = styled.div({\n  display: 'flex',\n  whiteSpace: 'nowrap',\n  flexBasis: 'auto',\n  gap: 6,\n  alignItems: 'center',\n});\n"
  },
  {
    "path": "code/core/src/manager/components/preview/Viewport.stories.tsx",
    "content": "import { ManagerContext } from 'storybook/manager-api';\nimport { fn } from 'storybook/test';\nimport type { ViewportMap } from 'storybook/viewport';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { Viewport } from './Viewport.tsx';\n\nconst managerContext: any = {\n  state: {},\n  api: {\n    getCurrentParameter: fn(),\n    getGlobals: fn(() => ({})),\n    getStoryGlobals: fn(() => ({})),\n    getUserGlobals: fn(() => ({})),\n    getUrlState: fn(() => ({ viewMode: 'story' })),\n    updateGlobals: fn(),\n    setAddonShortcut: fn(),\n    on: fn(),\n    off: fn(),\n    emit: fn(),\n  },\n};\n\nconst customViewports = {\n  narrow: {\n    name: 'Narrow',\n    styles: {\n      height: '100%',\n      width: '400px',\n    },\n    type: 'other',\n  },\n  short: {\n    name: 'Short',\n    styles: {\n      height: '400px',\n      width: '100%',\n    },\n    type: 'other',\n  },\n  calc: {\n    name: 'Calculated',\n    styles: {\n      height: 'calc(100% - 50px)',\n      width: 'calc(100% - 50px)',\n    },\n    type: 'other',\n  },\n} as ViewportMap;\n\nconst meta = preview.meta({\n  component: Viewport,\n  args: {\n    active: true,\n    id: 'storybook-preview-iframe',\n    src: '/iframe.html?id=manager-settings-checklist--default',\n    scale: 1,\n  },\n  decorators: [\n    (Story) => (\n      <ManagerContext.Provider value={managerContext}>\n        <Story />\n      </ManagerContext.Provider>\n    ),\n  ],\n  globals: {\n    viewport: { value: undefined },\n  },\n  parameters: {\n    layout: 'centered',\n  },\n  beforeEach: () => {\n    managerContext.api.getCurrentParameter.mockReset();\n    managerContext.api.getGlobals.mockReset();\n    managerContext.api.getStoryGlobals.mockReset();\n    managerContext.api.getUserGlobals.mockReset();\n  },\n});\n\nexport const Default = meta.story({\n  parameters: {\n    layout: 'fullscreen',\n  },\n});\n\nexport const Mobile = meta.story({\n  beforeEach() {\n    managerContext.api.getGlobals.mockReturnValue({ viewport: { value: 'mobile1' } });\n  },\n});\n\nexport const Locked = meta.story({\n  beforeEach() {\n    managerContext.api.getGlobals.mockReturnValue({\n      viewport: { value: 'mobile1' },\n    });\n    managerContext.api.getStoryGlobals.mockReturnValue({\n      viewport: { value: 'mobile1' },\n    });\n  },\n});\n\nexport const Rotated = meta.story({\n  beforeEach() {\n    managerContext.api.getGlobals.mockReturnValue({\n      viewport: { value: 'mobile1', isRotated: true },\n    });\n  },\n});\n\nexport const Short = meta.story({\n  globals: {\n    viewport: { value: 'short' },\n  },\n  parameters: {\n    viewport: { options: customViewports },\n    chromatic: { disableSnapshot: true },\n  },\n  render: () => <></>,\n});\n\nexport const Narrow = meta.story({\n  globals: {\n    viewport: { value: 'narrow' },\n  },\n  parameters: {\n    viewport: { options: customViewports },\n    chromatic: { disableSnapshot: true },\n  },\n  render: () => <></>,\n});\n\nexport const Calculated = meta.story({\n  globals: {\n    viewport: { value: 'calc' },\n  },\n  parameters: {\n    viewport: { options: customViewports },\n    chromatic: { disableSnapshot: true },\n  },\n  render: () => <></>,\n  tags: ['!test', '!vitest'], // Vitest browser does not support calculated viewports\n});\n"
  },
  {
    "path": "code/core/src/manager/components/preview/Viewport.tsx",
    "content": "import React, { useEffect, useMemo, useRef, useState } from 'react';\n\nimport { ActionList } from 'storybook/internal/components';\n\nimport { TransferIcon, UndoIcon } from '@storybook/icons';\n\nimport { styled } from 'storybook/theming';\n\nimport {\n  VIEWPORT_MIN_HEIGHT,\n  VIEWPORT_MIN_WIDTH,\n  useViewport,\n} from '../../../viewport/useViewport.ts';\nimport { IFrame } from './Iframe.tsx';\nimport { NumericInput } from './NumericInput.tsx';\n\ntype DragSide = 'none' | 'both' | 'bottom' | 'right';\n\nconst ViewportWrapper = styled.div<{\n  active: boolean;\n  isDefault: boolean;\n}>(({ active, isDefault, theme }) => ({\n  gridArea: '1 / 1',\n  alignSelf: 'start',\n  justifySelf: 'start',\n  display: active ? 'inline-flex' : 'none',\n  flexDirection: 'column',\n  gap: 6,\n  width: '100%',\n  height: '100%',\n  paddingTop: isDefault ? 0 : 6,\n  paddingBottom: isDefault ? 0 : 40,\n  paddingInline: isDefault ? 0 : 40,\n\n  '&:has([data-size-input=\"width\"]:focus-visible)': {\n    '[data-dragging]': {\n      borderRightColor: theme.color.secondary,\n      boxShadow: `4px 0 5px -2px ${theme.background.hoverable}`,\n    },\n  },\n  '&:has([data-size-input=\"height\"]:focus-visible)': {\n    '[data-dragging]': {\n      borderBottomColor: theme.color.secondary,\n      boxShadow: `0 4px 5px -2px ${theme.background.hoverable}`,\n    },\n  },\n}));\n\nconst ViewportControls = styled.div({\n  display: 'flex',\n  gap: 6,\n});\n\nconst ViewportDimensions = styled.div({\n  display: 'flex',\n  gap: 2,\n});\n\nconst FrameWrapper = styled.div<{\n  isDefault: boolean;\n  'data-dragging': DragSide;\n}>(({ isDefault, 'data-dragging': dragging, theme }) => ({\n  position: 'relative',\n  minWidth: VIEWPORT_MIN_WIDTH,\n  minHeight: VIEWPORT_MIN_HEIGHT,\n  boxSizing: 'content-box', // we're sizing the contents, not the box itself\n  border: `1px solid ${theme.button.border}`,\n  borderWidth: isDefault ? 0 : 1,\n  borderRadius: isDefault ? 0 : 4,\n  transition: 'border-color 0.2s, box-shadow 0.2s',\n  '&:has([data-side=\"right\"]:hover), &[data-dragging=\"right\"]': {\n    borderRightColor: theme.color.secondary,\n    boxShadow: `4px 0 5px -2px ${theme.background.hoverable}`,\n    '[data-side=\"right\"]::after': {\n      opacity: 1,\n    },\n  },\n  '&:has([data-side=\"bottom\"]:hover), &[data-dragging=\"bottom\"]': {\n    borderBottomColor: theme.color.secondary,\n    boxShadow: `0 4px 5px -2px ${theme.background.hoverable}`,\n    '[data-side=\"bottom\"]::after': {\n      opacity: 1,\n    },\n  },\n  '&:has([data-side=\"both\"]:hover), &[data-dragging=\"both\"]': {\n    boxShadow: `3px 3px 5px -2px ${theme.background.hoverable}`,\n    '&::after, [data-side]::after': {\n      opacity: 1,\n    },\n  },\n  '&::after': {\n    content: '\"\"',\n    display: 'block',\n    position: 'absolute',\n    pointerEvents: 'none',\n    bottom: 1,\n    right: 1,\n    width: 12,\n    height: 12,\n    opacity: 0,\n    transition: 'opacity 0.2s',\n    background: `linear-gradient(to top left,\n      rgba(0,0,0,0) 0%,\n      rgba(0,0,0,0) calc(25% - 1px),\n      ${theme.color.secondary} 25%,\n      rgba(0,0,0,0) calc(25% + 1px),\n      rgba(0,0,0,0) calc(45% - 1px),\n      ${theme.color.secondary} 45%,\n      rgba(0,0,0,0) calc(45% + 1px),\n      rgba(0,0,0,0) 100%)`,\n  },\n  iframe: {\n    pointerEvents: dragging === 'none' ? 'auto' : 'none',\n  },\n}));\n\nconst DragHandle = styled.div<{\n  isDefault: boolean;\n  'data-side': DragSide;\n}>(\n  { display: 'none' },\n  ({ theme, isDefault }) =>\n    !isDefault && {\n      display: 'block',\n      position: 'absolute',\n      fontSize: 10,\n      '&[data-side=\"both\"]': {\n        right: -12,\n        bottom: -12,\n        width: 25,\n        height: 25,\n        cursor: 'nwse-resize',\n      },\n      '&[data-side=\"bottom\"]': {\n        left: 0,\n        right: 13,\n        bottom: -12,\n        height: 20,\n        cursor: 'row-resize',\n        '&::after': {\n          content: 'attr(data-value)',\n          position: 'absolute',\n          top: '50%',\n          left: '50%',\n          transform: 'translate(-50%, -50%)',\n          borderRadius: 4,\n          backgroundColor: theme.background.hoverable,\n          padding: '2px 4px',\n          opacity: 0,\n          transition: 'opacity 0.2s',\n        },\n      },\n      '&[data-side=\"right\"]': {\n        top: 0,\n        right: -12,\n        bottom: 13,\n        width: 20,\n        cursor: 'col-resize',\n        '&::after': {\n          content: 'attr(data-value)',\n          position: 'absolute',\n          top: '50%',\n          left: '50%',\n          transform: 'translate(-50%, -50%)',\n          borderRadius: 4,\n          backgroundColor: theme.background.hoverable,\n          padding: '2px 4px',\n          opacity: 0,\n          transition: 'opacity 0.2s',\n        },\n      },\n    }\n);\n\nconst ScrollEdge = styled.div<{ 'data-edge': DragSide }>({\n  position: 'absolute',\n  pointerEvents: 'none',\n  width: 0,\n  height: 0,\n  '&[data-edge=\"right\"]': {\n    right: -40,\n    height: '100%',\n  },\n  '&[data-edge=\"bottom\"]': {\n    bottom: -40,\n    width: '100%',\n  },\n  '&[data-edge=\"both\"]': {\n    right: -40,\n    bottom: -40,\n  },\n});\n\nconst SizeInput = styled(NumericInput)({\n  width: 85,\n  height: 28,\n  minHeight: 28,\n});\n\nexport const Viewport = ({\n  active,\n  id,\n  src,\n  scale,\n}: {\n  active: boolean;\n  id: string;\n  src: string;\n  scale: number;\n}) => {\n  const { width, height, isCustom, isDefault, lastSelectedOption, resize, rotate, select } =\n    useViewport();\n\n  const [dragging, setDragging] = useState<DragSide>('none');\n  const targetRef = useRef<HTMLDivElement>(null);\n  const dragRefX = useRef<HTMLDivElement>(null);\n  const dragRefY = useRef<HTMLDivElement>(null);\n  const dragRefXY = useRef<HTMLDivElement>(null);\n  const dragSide = useRef<DragSide>('none');\n  const dragStart = useRef<[number, number] | undefined>();\n  const dragScrollTarget = useRef<Element | null | undefined>(null);\n\n  useEffect(() => {\n    const onDrag = (e: MouseEvent) => {\n      if (!targetRef.current || !dragStart.current) {\n        return;\n      }\n      if (dragRefX.current && (dragSide.current === 'both' || dragSide.current === 'right')) {\n        const newWidth = Math.max(VIEWPORT_MIN_WIDTH, dragStart.current[0] + e.clientX);\n        targetRef.current.style.width = `${newWidth}px`;\n        dragRefX.current.dataset.value = `${Math.round(newWidth / scale)}`;\n      }\n      if (dragRefY.current && (dragSide.current === 'both' || dragSide.current === 'bottom')) {\n        const newHeight = Math.max(VIEWPORT_MIN_HEIGHT, dragStart.current[1] + e.clientY);\n        targetRef.current.style.height = `${newHeight}px`;\n        dragRefY.current.dataset.value = `${Math.round(newHeight / scale)}`;\n      }\n      if (dragScrollTarget.current) {\n        dragScrollTarget.current.scrollIntoView({ block: 'center', inline: 'center' });\n      }\n    };\n\n    const onEnd = () => {\n      window.removeEventListener('mouseup', onEnd);\n      window.removeEventListener('mousemove', onDrag);\n      setDragging('none');\n      dragStart.current = undefined;\n      if (targetRef.current) {\n        const { clientWidth, clientHeight, dataset } = targetRef.current;\n        const scale = Number(dataset.scale) || 1;\n        resize(`${Math.round(clientWidth / scale)}px`, `${Math.round(clientHeight / scale)}px`);\n      }\n    };\n\n    const onStart = (e: MouseEvent) => {\n      e.preventDefault();\n      window.addEventListener('mouseup', onEnd);\n      window.addEventListener('mousemove', onDrag);\n      dragSide.current = (e.currentTarget as HTMLElement).dataset.side as DragSide;\n      dragStart.current = [\n        (targetRef.current?.clientWidth ?? 0) - e.clientX,\n        (targetRef.current?.clientHeight ?? 0) - e.clientY,\n      ];\n      dragScrollTarget.current = targetRef.current?.querySelector(\n        `[data-edge=\"${dragSide.current}\"]`\n      );\n      setDragging(dragSide.current);\n    };\n\n    const handles = [dragRefX.current, dragRefY.current, dragRefXY.current];\n    handles.forEach((el) => el?.addEventListener('mousedown', onStart));\n    return () => handles.forEach((el) => el?.removeEventListener('mousedown', onStart));\n  }, [resize, scale]);\n\n  const dimensions = useMemo(() => {\n    const [, nx = '', ux = 'px'] = width.match(/^(\\d+(?:\\.\\d+)?)(\\%|[a-z]{1,4})?$/) || [];\n    const [, ny = '', uy = 'px'] = height.match(/^(\\d+(?:\\.\\d+)?)(\\%|[a-z]{1,4})?$/) || [];\n    return {\n      frame: {\n        width: `calc(${width} * ${scale})`,\n        height: `calc(${height} * ${scale})`,\n      },\n      display: {\n        width: `${nx || width}${ux === 'px' ? '' : ux}`,\n        height: `${ny || height}${uy === 'px' ? '' : uy}`,\n      },\n      locked: {\n        width: !nx || !ny,\n        height: !nx || !ny,\n      },\n    };\n  }, [width, height, scale]);\n\n  return (\n    <ViewportWrapper key={id} active={active} isDefault={isDefault}>\n      {!isDefault && (\n        <ViewportControls>\n          <ViewportDimensions>\n            <SizeInput\n              aria-label=\"Viewport width\"\n              data-size-input=\"width\"\n              label=\"Viewport width\"\n              before={\n                <ActionList.Action size=\"small\" readOnly aria-hidden>\n                  W\n                </ActionList.Action>\n              }\n              value={width}\n              minValue={0}\n              setValue={(value) => resize(value, height)}\n              disabled={dimensions.locked.width}\n            />\n            <ActionList.Button\n              key=\"viewport-rotate\"\n              size=\"small\"\n              padding=\"small\"\n              ariaLabel=\"Rotate viewport\"\n              onClick={rotate}\n            >\n              <TransferIcon />\n            </ActionList.Button>\n            <SizeInput\n              aria-label=\"Viewport height\"\n              data-size-input=\"height\"\n              label=\"Viewport height\"\n              before={\n                <ActionList.Action size=\"small\" readOnly aria-hidden>\n                  H\n                </ActionList.Action>\n              }\n              value={height}\n              minValue={0}\n              setValue={(value) => resize(width, value)}\n              disabled={dimensions.locked.height}\n            />\n            {isCustom && lastSelectedOption && (\n              <ActionList.Button\n                key=\"viewport-restore\"\n                size=\"small\"\n                padding=\"small\"\n                ariaLabel=\"Restore viewport\"\n                onClick={() => select(lastSelectedOption)}\n              >\n                <UndoIcon />\n              </ActionList.Button>\n            )}\n          </ViewportDimensions>\n        </ViewportControls>\n      )}\n      <FrameWrapper\n        isDefault={isDefault}\n        data-dragging={dragging}\n        data-scale={scale}\n        style={isDefault ? { height: '100%', width: '100%' } : dimensions.frame}\n        ref={targetRef}\n      >\n        <div\n          style={{\n            height: `${(1 / scale) * 100}%`,\n            width: `${(1 / scale) * 100}%`,\n            transform: scale !== 1 ? `scale(${scale})` : 'none',\n            transformOrigin: 'top left',\n          }}\n        >\n          <IFrame allowFullScreen active={active} key={id} id={id} title={id} src={src} scale={1} />\n          {!isDefault && (\n            <>\n              <ScrollEdge data-edge=\"right\" />\n              <ScrollEdge data-edge=\"bottom\" />\n              <ScrollEdge data-edge=\"both\" />\n            </>\n          )}\n        </div>\n        {!dimensions.locked.width && (\n          <DragHandle\n            ref={dragRefX}\n            isDefault={isDefault}\n            data-side=\"right\"\n            data-value={dimensions.display.width}\n          />\n        )}\n        {!dimensions.locked.height && (\n          <DragHandle\n            ref={dragRefY}\n            isDefault={isDefault}\n            data-side=\"bottom\"\n            data-value={dimensions.display.height}\n          />\n        )}\n        {!dimensions.locked.width && !dimensions.locked.height && (\n          <DragHandle ref={dragRefXY} isDefault={isDefault} data-side=\"both\" />\n        )}\n      </FrameWrapper>\n    </ViewportWrapper>\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/components/preview/Wrappers.tsx",
    "content": "import type { FC, PropsWithChildren } from 'react';\nimport React, { Fragment } from 'react';\n\nimport { Addon_TypesEnum } from 'storybook/internal/types';\nimport type { Addon_WrapperType } from 'storybook/internal/types';\n\nimport { IframeWrapper } from './utils/components.ts';\nimport type { ApplyWrappersProps } from './utils/types.tsx';\n\nexport const ApplyWrappers: FC<PropsWithChildren<ApplyWrappersProps>> = ({\n  wrappers,\n  id,\n  storyId,\n  children,\n}) => {\n  return (\n    <Fragment>\n      {wrappers.reduceRight(\n        (acc, wrapper, index) => (\n          <wrapper.render {...{ index, children: acc, id, storyId }} />\n        ),\n        children\n      )}\n    </Fragment>\n  );\n};\n\nexport const defaultWrappers: Addon_WrapperType[] = [\n  {\n    id: 'iframe-wrapper',\n    type: Addon_TypesEnum.PREVIEW,\n    render: (p) => <IframeWrapper id=\"storybook-preview-wrapper\">{p.children}</IframeWrapper>,\n  },\n];\n"
  },
  {
    "path": "code/core/src/manager/components/preview/tools/addons.tsx",
    "content": "import React from 'react';\n\nimport { Button } from 'storybook/internal/components';\nimport type { Addon_BaseType } from 'storybook/internal/types';\n\nimport { BottomBarIcon, SidebarAltIcon } from '@storybook/icons';\n\nimport { Consumer, types } from 'storybook/manager-api';\nimport type { Combo } from 'storybook/manager-api';\n\nimport { focusableUIElements } from '../../../../manager-api/modules/layout.ts';\n\nconst SHOW_ADDON_PANEL_BUTTON_ID = 'storybook-show-addon-panel';\n\nconst menuMapper = ({ api, state }: Combo) => ({\n  isVisible: api.getIsPanelShown(),\n  singleStory: state.singleStory,\n  panelPosition: state.layout.panelPosition,\n  showPanel: async (forceFocus: boolean) => {\n    api.togglePanel(true);\n    api.focusOnUIElement(focusableUIElements.addonPanel, {\n      forceFocus,\n      poll: true,\n    });\n  },\n});\n\nexport const addonsTool: Addon_BaseType = {\n  title: 'addons',\n  id: 'addons',\n  type: types.TOOL,\n  match: ({ viewMode, tabId }) => viewMode === 'story' && !tabId,\n  render: () => {\n    return (\n      <Consumer filter={menuMapper}>\n        {({ isVisible, showPanel, singleStory, panelPosition }) =>\n          !singleStory &&\n          !isVisible && (\n            <>\n              <Button\n                padding=\"small\"\n                variant=\"ghost\"\n                ariaLabel=\"Show addon panel\"\n                id={SHOW_ADDON_PANEL_BUTTON_ID}\n                key=\"addons\"\n                onClick={() => showPanel(false)}\n                onKeyDown={(e) => {\n                  if (e.key === 'Enter' || e.key === ' ') {\n                    e.preventDefault();\n                    showPanel(true);\n                  }\n                }}\n              >\n                {panelPosition === 'bottom' ? <BottomBarIcon /> : <SidebarAltIcon />}\n              </Button>\n            </>\n          )\n        }\n      </Consumer>\n    );\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/components/preview/tools/menu.tsx",
    "content": "import React from 'react';\n\nimport { Button, Separator } from 'storybook/internal/components';\nimport type { Addon_BaseType } from 'storybook/internal/types';\n\nimport { MenuIcon } from '@storybook/icons';\n\nimport { Consumer, types } from 'storybook/manager-api';\nimport type { Combo } from 'storybook/manager-api';\n\nimport { focusableUIElements } from '../../../../manager-api/modules/layout.ts';\n\nconst menuMapper = ({ api, state }: Combo) => ({\n  isVisible: api.getIsNavShown(),\n  singleStory: state.singleStory,\n  viewMode: state.viewMode,\n  showSidebar: async (forceFocus: boolean) => {\n    api.toggleNav(true);\n    api.focusOnUIElement(focusableUIElements.sidebarRegion, {\n      forceFocus,\n      poll: true,\n    });\n  },\n});\n\nexport const menuTool: Addon_BaseType = {\n  title: 'menu',\n  id: 'menu',\n  type: types.TOOL,\n  // @ts-expect-error (non strict)\n  match: ({ viewMode }) => ['story', 'docs'].includes(viewMode),\n  render: () => {\n    return (\n      <Consumer filter={menuMapper}>\n        {({ isVisible, showSidebar, singleStory }) =>\n          !singleStory &&\n          !isVisible && (\n            <>\n              <Button\n                padding=\"small\"\n                variant=\"ghost\"\n                ariaLabel=\"Show sidebar\"\n                id={focusableUIElements.showSidebar}\n                key=\"menu\"\n                onClick={() => showSidebar(false)}\n                onKeyDown={(e) => {\n                  if (e.key === 'Enter' || e.key === ' ') {\n                    e.preventDefault();\n                    showSidebar(true);\n                  }\n                }}\n              >\n                <MenuIcon />\n              </Button>\n              <Separator />\n            </>\n          )\n        }\n      </Consumer>\n    );\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/components/preview/tools/open-in-editor.tsx",
    "content": "import React from 'react';\n\nimport { Button } from 'storybook/internal/components';\nimport type { Addon_BaseType } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\nimport { EditorIcon } from '@storybook/icons';\n\nimport { Consumer, types, useStorybookApi } from 'storybook/manager-api';\nimport type { Combo } from 'storybook/manager-api';\n\nconst mapper = ({ state, api }: Combo) => {\n  const { storyId, refId } = state;\n  const entry = api.getData(storyId, refId);\n\n  const isCompositionStory = !!refId; // Only allow opening local stories in editor\n\n  return {\n    storyId,\n    isCompositionStory,\n    importPath: entry?.importPath as string | undefined,\n  };\n};\n\nexport const openInEditorTool: Addon_BaseType = {\n  title: 'open-in-editor',\n  id: 'open-in-editor',\n  type: types.TOOL,\n  match: ({ viewMode, tabId }) =>\n    global.CONFIG_TYPE === 'DEVELOPMENT' && (viewMode === 'story' || viewMode === 'docs') && !tabId,\n  render: () => (\n    <Consumer filter={mapper}>\n      {({ importPath, isCompositionStory }) => {\n        const api = useStorybookApi();\n        if (isCompositionStory || !importPath) {\n          return null;\n        }\n        return (\n          <Button\n            key=\"open-in-editor\"\n            onClick={() =>\n              api.openInEditor({\n                file: importPath,\n              })\n            }\n            ariaLabel=\"Open in editor\"\n            padding=\"small\"\n            variant=\"ghost\"\n          >\n            <EditorIcon />\n          </Button>\n        );\n      }}\n    </Consumer>\n  ),\n};\n"
  },
  {
    "path": "code/core/src/manager/components/preview/tools/remount.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React, { useEffect, useState } from 'react';\n\nimport { Button } from 'storybook/internal/components';\nimport { FORCE_REMOUNT } from 'storybook/internal/core-events';\nimport type { Addon_BaseType } from 'storybook/internal/types';\n\nimport { SyncIcon } from '@storybook/icons';\n\nimport { Consumer, types } from 'storybook/manager-api';\nimport type { Combo } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\ninterface AnimatedButtonProps {\n  animating?: boolean;\n}\n\nconst StyledAnimatedButton = styled(Button)<\n  AnimatedButtonProps & Pick<ComponentProps<typeof Button>, 'disabled'>\n>(({ theme, animating, disabled }) => ({\n  opacity: disabled ? 0.5 : 1,\n  svg: {\n    animation: animating ? `${theme.animation.rotate360} 1000ms ease-out` : undefined,\n  },\n}));\n\nconst menuMapper = ({ api, state }: Combo) => {\n  const { storyId } = state;\n  return {\n    storyId,\n    remount: () => api.emit(FORCE_REMOUNT, { storyId: state.storyId }),\n    api,\n  };\n};\n\nexport const remountTool: Addon_BaseType = {\n  title: 'remount',\n  id: 'remount',\n  type: types.TOOL,\n  match: ({ viewMode, tabId }) => viewMode === 'story' && !tabId,\n  render: () => (\n    <Consumer filter={menuMapper}>\n      {({ remount, storyId, api }) => {\n        const [isAnimating, setIsAnimating] = useState(false);\n        const remountComponent = () => {\n          if (!storyId) {\n            return;\n          }\n          remount();\n        };\n\n        useEffect(() => {\n          const handler = () => setIsAnimating(true);\n          api.on(FORCE_REMOUNT, handler);\n          return () => api.off?.(FORCE_REMOUNT, handler);\n        }, [api]);\n\n        return (\n          <StyledAnimatedButton\n            key=\"remount\"\n            padding=\"small\"\n            variant=\"ghost\"\n            ariaLabel=\"Reload story\"\n            onClick={remountComponent}\n            onAnimationEnd={() => setIsAnimating(false)}\n            animating={isAnimating}\n            disabled={!storyId}\n          >\n            <SyncIcon />\n          </StyledAnimatedButton>\n        );\n      }}\n    </Consumer>\n  ),\n};\n"
  },
  {
    "path": "code/core/src/manager/components/preview/tools/share.stories.tsx",
    "content": "import React from 'react';\n\nimport { global } from '@storybook/global';\n\nimport type { StoryObj } from '@storybook/react-vite';\n\nimport { ManagerContext } from 'storybook/manager-api';\nimport { expect, fn, screen, waitFor } from 'storybook/test';\n\nimport { shareTool } from './share.tsx';\n\nconst managerContext = {\n  state: {\n    storyId: 'manager-preview-tools-share--default',\n    refId: undefined,\n  },\n  api: {\n    emit: fn().mockName('api::emit'),\n    getShortcutKeys: () => ({\n      copyStoryLink: ['alt', 'shift', 'l'],\n      openInIsolation: ['alt', 'shift', 'i'],\n    }),\n    getStoryHrefs: () => ({\n      managerHref: '/?path=/story/manager-preview-tools-share--default',\n      previewHref: '/iframe.html?id=manager-preview-tools-share--default&viewMode=story',\n    }),\n  },\n} as any;\n\nconst ManagerDecorator = (Story: any) => (\n  <ManagerContext.Provider value={managerContext}>\n    <div style={{ padding: 24 }}>{Story()}</div>\n  </ManagerContext.Provider>\n);\n\nconst meta = {\n  title: 'Manager/Preview/Tools/Share',\n  render: shareTool.render,\n  decorators: [ManagerDecorator],\n  parameters: { layout: 'centered' },\n  tags: ['!vitest'],\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {\n  beforeEach: () => {\n    const originalConfigType = global.CONFIG_TYPE;\n    global.STORYBOOK_NETWORK_ADDRESS = 'http://127.0.0.1:6006';\n    global.CONFIG_TYPE = 'DEVELOPMENT';\n\n    return () => {\n      global.CONFIG_TYPE = originalConfigType;\n    };\n  },\n  play: async ({ userEvent, canvas }) => {\n    await waitFor(async () => {\n      await userEvent.click(canvas.getByRole('button'));\n      await expect(await screen.findByText('Scan to open')).toBeVisible();\n    });\n  },\n};\n\nexport const Production: Story = {\n  ...Default,\n  beforeEach: () => {\n    const originalConfigType = global.CONFIG_TYPE;\n    global.STORYBOOK_NETWORK_ADDRESS = 'http://127.0.0.1:6006';\n    global.CONFIG_TYPE = 'PRODUCTION';\n\n    return () => {\n      global.CONFIG_TYPE = originalConfigType;\n    };\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/components/preview/tools/share.tsx",
    "content": "import React, { useEffect, useMemo, useState } from 'react';\n\nimport { Button, PopoverProvider, TooltipLinkList } from 'storybook/internal/components';\nimport {\n  SHARE_ISOLATE_MODE,\n  SHARE_POPOVER_OPENED,\n  SHARE_STORY_LINK,\n} from 'storybook/internal/core-events';\nimport type { Addon_BaseType } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\nimport { LinkIcon, ShareAltIcon, ShareIcon } from '@storybook/icons';\n\nimport copy from 'copy-to-clipboard';\nimport { QRCodeSVG as QRCode } from 'qrcode.react';\nimport { Consumer, types } from 'storybook/manager-api';\nimport type { API, Combo } from 'storybook/manager-api';\nimport { styled, useTheme } from 'storybook/theming';\n\nimport { Shortcut } from '../../Shortcut.tsx';\n\nconst mapper = ({ api, state }: Combo) => {\n  const { storyId, refId } = state;\n  return { api, refId, storyId };\n};\n\nconst QRContainer = styled.div(() => ({\n  display: 'flex',\n  alignItems: 'center',\n  padding: 8,\n  maxWidth: 200,\n}));\n\nconst QRImageContainer = styled.div(() => ({\n  width: 64,\n  height: 64,\n  marginRight: 12,\n  backgroundColor: 'white',\n  padding: 2,\n}));\n\nconst QRImage = ({ value }: { value: string }) => {\n  const theme = useTheme();\n  return (\n    <QRImageContainer>\n      <QRCode value={value} marginSize={0} size={60} fgColor={theme.color.darkest} />\n    </QRImageContainer>\n  );\n};\n\nconst QRContent = styled.div(() => ({}));\n\nconst QRTitle = styled.div(({ theme }) => ({\n  fontWeight: theme.typography.weight.bold,\n  fontSize: theme.typography.size.s1,\n  marginBottom: 4,\n}));\n\nconst QRDescription = styled.div(({ theme }) => ({\n  fontSize: theme.typography.size.s1,\n  color: theme.textMutedColor,\n}));\n\nconst ShareMenu = React.memo(function ShareMenu({\n  api,\n  storyId,\n  refId,\n}: {\n  api: API;\n  storyId: string;\n  refId: string | undefined;\n}) {\n  const shortcutKeys = api.getShortcutKeys();\n  const enableShortcuts = !!shortcutKeys;\n  const [copied, setCopied] = useState(false);\n  const copyStoryLink = shortcutKeys?.copyStoryLink;\n  const openInIsolation = shortcutKeys?.openInIsolation;\n\n  useEffect(() => {\n    api.emit(SHARE_POPOVER_OPENED);\n  }, [api]);\n\n  const links = useMemo(() => {\n    const copyTitle = copied ? 'Copied!' : 'Copy story link';\n    const originHrefs = api.getStoryHrefs(storyId, { base: 'origin', refId });\n    const networkHrefs = api.getStoryHrefs(storyId, { base: 'network', refId });\n\n    return [\n      [\n        {\n          id: 'copy-link',\n          title: copyTitle,\n          icon: <LinkIcon />,\n          right: enableShortcuts ? <Shortcut keys={copyStoryLink} /> : null,\n          onClick: () => {\n            api.emit(SHARE_STORY_LINK, originHrefs.managerHref);\n            copy(originHrefs.managerHref);\n            setCopied(true);\n            setTimeout(() => setCopied(false), 2000);\n          },\n        },\n        {\n          id: 'open-new-tab',\n          title: 'Open in isolation mode',\n          icon: <ShareAltIcon />,\n          right: enableShortcuts ? <Shortcut keys={openInIsolation} /> : null,\n          onClick: () => {\n            api.emit(SHARE_ISOLATE_MODE, originHrefs.previewHref);\n          },\n          href: originHrefs.previewHref,\n          target: '_blank',\n          rel: 'noopener noreferrer',\n        },\n      ],\n      [\n        {\n          id: 'qr-section',\n          content: (\n            <QRContainer>\n              <QRImage value={networkHrefs.managerHref} />\n              <QRContent>\n                <QRTitle>Scan to open</QRTitle>\n                <QRDescription>\n                  {global.CONFIG_TYPE === 'DEVELOPMENT'\n                    ? 'Device must be on the same network.'\n                    : 'View story on another device.'}\n                </QRDescription>\n              </QRContent>\n            </QRContainer>\n          ),\n        },\n      ],\n    ];\n  }, [api, storyId, refId, copied, enableShortcuts, copyStoryLink, openInIsolation]);\n\n  return <TooltipLinkList links={links} style={{ width: 240 }} />;\n});\n\nexport const shareTool: Addon_BaseType = {\n  title: 'share',\n  id: 'share',\n  type: types.TOOL,\n  match: ({ viewMode, tabId }) => viewMode === 'story' && !tabId,\n  render: () => (\n    <Consumer filter={mapper}>\n      {({ api, storyId, refId }) =>\n        storyId ? (\n          <PopoverProvider\n            ariaLabel=\"Share this story\"\n            hasChrome\n            placement=\"bottom\"\n            padding={0}\n            popover={<ShareMenu {...{ api, storyId, refId }} />}\n          >\n            <Button padding=\"small\" variant=\"ghost\" ariaLabel=\"Share\" tooltip=\"Share...\">\n              <ShareIcon />\n            </Button>\n          </PopoverProvider>\n        ) : null\n      }\n    </Consumer>\n  ),\n};\n"
  },
  {
    "path": "code/core/src/manager/components/preview/tools/zoom.stories.tsx",
    "content": "import { useState } from 'react';\n\nimport type { StoryContext } from '@storybook/react-vite';\n\nimport { expect, fireEvent, fn, screen, waitFor, within } from 'storybook/test';\n\nimport preview from '../../../../../../.storybook/preview.tsx';\nimport { Zoom } from './zoom.tsx';\n\nconst openDialog = async (context: StoryContext<typeof Zoom>) => {\n  const zoom = await context.canvas.findByRole('switch', { name: 'Change zoom level' });\n  await context.userEvent.click(zoom);\n  return screen.findByRole('dialog');\n};\n\nconst meta = preview.meta({\n  component: Zoom,\n  args: {\n    value: 1,\n    zoomIn: fn(),\n    zoomOut: fn(),\n    zoomTo: fn(),\n    zoomBy: fn(),\n  },\n  render: (args: Parameters<typeof Zoom>[0]) => {\n    const [value, setValue] = useState(args.value);\n    return (\n      <Zoom\n        {...{\n          value,\n          zoomIn: () => setValue(value + 0.5),\n          zoomOut: () => setValue(value - 0.5),\n          zoomTo: setValue,\n          zoomBy: (delta: number) => setValue(Math.max(0.01, value + delta)),\n        }}\n      />\n    );\n  },\n  play: async (context) => {\n    await openDialog(context as any);\n  },\n});\n\nexport default meta;\n\nexport const Default = meta.story({});\n\nexport const ZoomIn = meta.story({\n  play: async (context) => {\n    const dialog = await openDialog(context as any);\n    const zoomIn = await within(dialog).findByRole('button', { name: 'Zoom in' });\n    await context.userEvent.click(zoomIn);\n  },\n});\n\nexport const ZoomOut = meta.story({\n  play: async (context) => {\n    const dialog = await openDialog(context as any);\n    const zoomOut = await within(dialog).findByRole('button', { name: 'Zoom out' });\n    await context.userEvent.click(zoomOut);\n  },\n});\n\nexport const Undo = meta.story({\n  play: async (context) => {\n    const dialog = await openDialog(context as any);\n    const zoomIn = await within(dialog).findByRole('button', { name: 'Zoom in' });\n    await context.userEvent.click(zoomIn);\n    const undo = await within(dialog).findByRole('button', { name: 'Reset zoom' });\n    await context.userEvent.click(undo);\n  },\n});\n\nexport const MaxZoom = meta.story({\n  args: {\n    value: 8,\n  },\n});\n\nexport const MinZoom = meta.story({\n  args: {\n    value: 0.25,\n  },\n});\n\nexport const ArrowUpKey = meta.story({\n  args: {},\n  play: async ({ canvas, userEvent }) => {\n    const zoom = await canvas.findByRole('switch', { name: 'Change zoom level' });\n    zoom.focus();\n    await userEvent.keyboard('[ArrowUp]');\n    expect(zoom).toHaveTextContent('101%');\n  },\n});\n\nexport const ArrowDownKey = meta.story({\n  args: {},\n  play: async ({ canvas, userEvent }) => {\n    const zoom = await canvas.findByRole('switch', { name: 'Change zoom level' });\n    await zoom.focus();\n    await userEvent.keyboard('[ArrowDown]');\n    expect(zoom).toHaveTextContent('99%');\n  },\n});\n\nexport const PageUpKey = meta.story({\n  args: {},\n  play: async ({ canvas, userEvent }) => {\n    const zoom = await canvas.findByRole('switch', { name: 'Change zoom level' });\n    zoom.focus();\n    await userEvent.keyboard('[PageUp]');\n    expect(zoom).toHaveTextContent('150%');\n  },\n});\n\nexport const PageDownKey = meta.story({\n  args: {},\n  play: async ({ canvas, userEvent }) => {\n    const zoom = await canvas.findByRole('switch', { name: 'Change zoom level' });\n    zoom.focus();\n    await userEvent.keyboard('[PageDown]');\n    expect(zoom).toHaveTextContent('50%');\n  },\n});\n\nexport const HomeKey = meta.story({\n  args: {},\n  play: async ({ canvas, userEvent }) => {\n    const zoom = await canvas.findByRole('switch', { name: 'Change zoom level' });\n    zoom.focus();\n    await userEvent.keyboard('[Home]');\n    expect(zoom).toHaveTextContent('800%');\n  },\n});\n\nexport const EndKey = meta.story({\n  args: {},\n  play: async ({ canvas, userEvent }) => {\n    const zoom = await canvas.findByRole('switch', { name: 'Change zoom level' });\n    zoom.focus();\n    await userEvent.keyboard('[End]');\n    expect(zoom).toHaveTextContent('25%');\n  },\n});\n\nexport const WheelUp = meta.story({\n  args: {},\n  play: async ({ canvas }) => {\n    const zoom = await canvas.findByRole('switch', { name: 'Change zoom level' });\n    await fireEvent.wheel(zoom, { deltaY: -100 });\n    await waitFor(() => expect(zoom).toHaveTextContent('150%'));\n  },\n});\n\nexport const WheelDown = meta.story({\n  args: {},\n  play: async ({ canvas }) => {\n    const zoom = await canvas.findByRole('switch', { name: 'Change zoom level' });\n    await fireEvent.wheel(zoom, { deltaY: 100 });\n    await waitFor(() => expect(zoom).toHaveTextContent('50%'));\n  },\n});\n"
  },
  {
    "path": "code/core/src/manager/components/preview/tools/zoom.tsx",
    "content": "import type { PropsWithChildren } from 'react';\nimport React, { Component, createContext, memo, useCallback, useEffect, useRef } from 'react';\n\nimport { ActionList, PopoverProvider, ToggleButton } from 'storybook/internal/components';\nimport type { Addon_BaseType } from 'storybook/internal/types';\n\nimport { UndoIcon, ZoomIcon } from '@storybook/icons';\n\nimport { types, useStorybookApi } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport { Shortcut } from '../../Shortcut.tsx';\nimport { NumericInput } from '../NumericInput.tsx';\n\nconst ZOOM_LEVELS = [0.25, 0.5, 0.75, 0.9, 1, 1.1, 1.25, 1.5, 2, 3, 4, 8] as const;\nconst INITIAL_ZOOM_LEVEL = 1;\n\nconst ZoomButton = styled(ToggleButton)({\n  minWidth: 48,\n});\n\nconst ZoomResetButton = styled(ActionList.Button)<{ $isInitialValue: boolean }>(\n  ({ $isInitialValue }) => ({\n    visibility: $isInitialValue ? 'hidden' : undefined,\n  })\n);\n\nconst Context = createContext({ value: INITIAL_ZOOM_LEVEL, set: (v: number) => {} });\n\nconst ZoomInput = styled(NumericInput)({\n  input: {\n    width: 100,\n  },\n});\n\nexport const ZoomConsumer = Context.Consumer;\n\nexport class ZoomProvider extends Component<\n  PropsWithChildren<{ shouldScale: boolean }>,\n  { value: number }\n> {\n  state = {\n    value: INITIAL_ZOOM_LEVEL,\n  };\n\n  set = (value: number) => this.setState({ value });\n\n  render() {\n    const { children, shouldScale } = this.props;\n    const { set } = this;\n    const { value } = this.state;\n    return (\n      <Context.Provider value={{ value: shouldScale ? value : INITIAL_ZOOM_LEVEL, set }}>\n        {children}\n      </Context.Provider>\n    );\n  }\n}\n\nexport const Zoom = memo<{\n  value: number;\n  zoomIn: () => void;\n  zoomOut: () => void;\n  zoomTo: (value: number) => void;\n  zoomBy: (delta: number) => void;\n}>(function Zoom({ value, zoomIn, zoomOut, zoomTo, zoomBy }) {\n  const inputRef = useRef<HTMLInputElement>(null);\n\n  return (\n    <PopoverProvider\n      padding=\"none\"\n      onVisibleChange={(isVisible) => {\n        if (isVisible) {\n          requestAnimationFrame(() => inputRef.current?.select());\n        }\n      }}\n      popover={\n        <>\n          <ActionList>\n            <ActionList.Item>\n              <ZoomInput\n                aria-label=\"Zoom percentage\"\n                ref={inputRef}\n                unit=\"%\"\n                before={\n                  <ActionList.Button size=\"small\" padding=\"small\" readOnly aria-hidden>\n                    <ZoomIcon />\n                  </ActionList.Button>\n                }\n                after={\n                  <ZoomResetButton\n                    size=\"small\"\n                    padding=\"small\"\n                    $isInitialValue={value === INITIAL_ZOOM_LEVEL}\n                    onClick={() => zoomTo(INITIAL_ZOOM_LEVEL)}\n                    ariaLabel=\"Reset zoom\"\n                    aria-hidden={value === INITIAL_ZOOM_LEVEL}\n                  >\n                    <UndoIcon />\n                  </ZoomResetButton>\n                }\n                value={`${Math.round(value * 100)}%`}\n                minValue={1}\n                maxValue={800}\n                setValue={(value: string) => {\n                  const zoomLevel = parseInt(value, 10) / 100;\n                  if (!Number.isNaN(zoomLevel)) {\n                    zoomTo(zoomLevel);\n                  }\n                }}\n              />\n            </ActionList.Item>\n          </ActionList>\n          <ActionList>\n            <ActionList.Item>\n              <ActionList.Action\n                onClick={zoomIn}\n                ariaLabel=\"Zoom in\"\n                disabled={value >= ZOOM_LEVELS.at(-1)!}\n              >\n                <ActionList.Text>Zoom in</ActionList.Text>\n                <Shortcut keys={['alt', '+']} />\n              </ActionList.Action>\n            </ActionList.Item>\n            <ActionList.Item>\n              <ActionList.Action\n                onClick={zoomOut}\n                ariaLabel=\"Zoom out\"\n                disabled={value <= ZOOM_LEVELS.at(0)!}\n              >\n                <ActionList.Text>Zoom out</ActionList.Text>\n                <Shortcut keys={['alt', '-']} />\n              </ActionList.Action>\n            </ActionList.Item>\n            <ActionList.Item active={value === 0.5}>\n              <ActionList.Action onClick={() => zoomTo(0.5)} ariaLabel=\"Zoom to 50%\">\n                <ActionList.Text>50%</ActionList.Text>\n              </ActionList.Action>\n            </ActionList.Item>\n            <ActionList.Item active={value === 1}>\n              <ActionList.Action onClick={() => zoomTo(1)} ariaLabel=\"Zoom to 100%\">\n                <ActionList.Text>100%</ActionList.Text>\n                <Shortcut keys={['alt', '0']} />\n              </ActionList.Action>\n            </ActionList.Item>\n            <ActionList.Item active={value === 2}>\n              <ActionList.Action onClick={() => zoomTo(2)} ariaLabel=\"Zoom to 200%\">\n                200%\n              </ActionList.Action>\n            </ActionList.Item>\n          </ActionList>\n        </>\n      }\n    >\n      <ZoomButton\n        padding=\"small\"\n        variant=\"ghost\"\n        ariaLabel=\"Change zoom level\"\n        pressed={value !== INITIAL_ZOOM_LEVEL}\n        onKeyDown={(e) => {\n          if (e.key === 'ArrowDown') {\n            zoomBy(e.getModifierState('Shift') ? -0.1 : -0.01);\n            e.preventDefault();\n          } else if (e.key === 'ArrowUp') {\n            zoomBy(e.getModifierState('Shift') ? 0.1 : 0.01);\n            e.preventDefault();\n          } else if (e.key === 'PageDown') {\n            zoomOut();\n            e.preventDefault();\n          } else if (e.key === 'PageUp') {\n            zoomIn();\n            e.preventDefault();\n          } else if (e.key === 'Home') {\n            zoomTo(ZOOM_LEVELS[ZOOM_LEVELS.length - 1]);\n            e.preventDefault();\n          } else if (e.key === 'End') {\n            zoomTo(ZOOM_LEVELS[0]);\n            e.preventDefault();\n          }\n        }}\n        onWheel={(e) => {\n          if (e.deltaY < 0) {\n            zoomIn();\n          } else if (e.deltaY > 0) {\n            zoomOut();\n          }\n          e.preventDefault();\n        }}\n      >\n        {Math.round(value * 100)}%\n      </ZoomButton>\n    </PopoverProvider>\n  );\n});\n\nconst ZoomWrapper = memo<{\n  set: (zoomLevel: number) => void;\n  value: number;\n}>(function ZoomWrapper({ set, value }) {\n  const api = useStorybookApi();\n\n  const zoomIn = useCallback(() => {\n    const higherZoomLevel = ZOOM_LEVELS.find((level) => level > value);\n    if (higherZoomLevel) {\n      set(higherZoomLevel);\n    }\n  }, [set, value]);\n\n  const zoomOut = useCallback(() => {\n    const lowerZoomLevel = ZOOM_LEVELS.findLast((level) => level < value);\n    if (lowerZoomLevel) {\n      set(lowerZoomLevel);\n    }\n  }, [set, value]);\n\n  const zoomBy = useCallback(\n    (delta: number) => {\n      const min = ZOOM_LEVELS[0];\n      const max = ZOOM_LEVELS[ZOOM_LEVELS.length - 1];\n      set(Math.max(min, Math.min(max, value + delta)));\n    },\n    [set, value]\n  );\n\n  const zoomTo = useCallback(\n    (value: number) => {\n      set(value);\n    },\n    [set]\n  );\n\n  useEffect(() => {\n    api.setAddonShortcut('zoom', {\n      label: 'Zoom to 100%',\n      defaultShortcut: ['alt', '0'],\n      actionName: 'zoomReset',\n      action: () => zoomTo(1),\n    });\n    api.setAddonShortcut('zoom', {\n      label: 'Zoom in',\n      defaultShortcut: ['alt', '='],\n      actionName: 'zoomIn',\n      action: zoomIn,\n    });\n    api.setAddonShortcut('zoom', {\n      label: 'Zoom in',\n      defaultShortcut: ['alt', '+'],\n      actionName: 'zoomPlus',\n      action: zoomIn,\n    });\n    api.setAddonShortcut('zoom', {\n      label: 'Zoom out',\n      defaultShortcut: ['alt', '-'],\n      actionName: 'zoomOut',\n      action: zoomOut,\n    });\n  }, [api, zoomIn, zoomOut, zoomTo]);\n\n  return <Zoom key=\"zoom\" {...{ value, zoomIn, zoomOut, zoomTo, zoomBy }} />;\n});\n\nexport const zoomTool: Addon_BaseType = {\n  title: 'zoom',\n  id: 'zoom',\n  type: types.TOOL,\n  match: ({ viewMode, tabId }) => viewMode === 'story' && !tabId,\n  render: () => <ZoomConsumer>{(zoomContext) => <ZoomWrapper {...zoomContext} />}</ZoomConsumer>,\n};\n"
  },
  {
    "path": "code/core/src/manager/components/preview/utils/components.ts",
    "content": "import { Link } from 'storybook/internal/router';\n\nimport { styled } from 'storybook/theming';\n\nexport const PreviewContainer = styled.div({\n  display: 'flex',\n  flexDirection: 'column',\n  width: '100%',\n  height: '100%',\n  overflow: 'hidden',\n});\n\nexport const FrameWrap = styled.main({\n  overflow: 'auto',\n  width: '100%',\n  zIndex: 3,\n  background: 'transparent',\n  flex: 1,\n});\nexport const CanvasWrap = styled.div<{ show: boolean }>(\n  {\n    alignContent: 'center',\n    alignItems: 'center',\n    justifyContent: 'center',\n    justifyItems: 'center',\n    overflow: 'auto',\n    gridTemplateColumns: '100%',\n    gridTemplateRows: '100%',\n    position: 'relative',\n    minWidth: '100%',\n    minHeight: '100%',\n  },\n  ({ show }) => ({ display: show ? 'grid' : 'none' })\n);\n\nexport const UnstyledLink = styled(Link)({\n  color: 'inherit',\n  textDecoration: 'inherit',\n  display: 'inline-block',\n});\n\nexport const DesktopOnly = styled.span({\n  // Hides full screen icon at mobile breakpoint defined in app.js\n  '@media (max-width: 599px)': {\n    display: 'none',\n  },\n});\n\nexport const IframeWrapper = styled.div(({ theme }) => ({\n  alignContent: 'center',\n  alignItems: 'center',\n  justifyContent: 'center',\n  justifyItems: 'center',\n  overflow: 'auto',\n\n  display: 'grid',\n  gridTemplateColumns: '100%',\n  gridTemplateRows: '100%',\n\n  position: 'relative',\n  width: '100%',\n  height: '100%',\n}));\n\nexport const LoaderWrapper = styled.div(({ theme }) => ({\n  position: 'absolute',\n  top: 0,\n  left: 0,\n  bottom: 0,\n  right: 0,\n  background: theme.background.preview,\n  zIndex: 1,\n}));\n"
  },
  {
    "path": "code/core/src/manager/components/preview/utils/types.tsx",
    "content": "import type { ReactElement } from 'react';\n\nimport type {\n  API_ViewMode,\n  Addon_BaseType,\n  Addon_WrapperType,\n  StoryId,\n} from 'storybook/internal/types';\n\nimport type { API, LeafEntry, State } from 'storybook/manager-api';\n\nexport interface PreviewProps {\n  api: API;\n  viewMode: API_ViewMode;\n  refs: State['refs'];\n  storyId: StoryId;\n  entry: LeafEntry;\n  options: {\n    showTabs: boolean;\n    showToolbar: boolean;\n  };\n  id?: string;\n  queryParams: State['customQueryParams'];\n  customCanvas?: CustomCanvasRenderer;\n  description: string;\n  baseUrl: string;\n  withLoader: boolean;\n  tabs: Addon_BaseType[];\n  tools: Addon_BaseType[];\n  toolsExtra: Addon_BaseType[];\n  tabId: string | undefined;\n  wrappers: Addon_WrapperType[];\n}\n\nexport interface ApplyWrappersProps {\n  wrappers: Addon_WrapperType[];\n  viewMode: State['viewMode'];\n  id: string;\n  storyId: StoryId;\n}\n\nexport type CustomCanvasRenderer = (\n  storyId: string,\n  viewMode: State['viewMode'],\n  id: string,\n  baseUrl: string,\n  scale: number,\n  queryParams: Record<string, any>\n) => ReactElement<any, any> | null;\n\nexport interface FramesRendererProps {\n  api: API;\n  entry: LeafEntry;\n  storyId: StoryId;\n  refId: string;\n  baseUrl: string;\n  scale: number;\n  viewMode: API_ViewMode;\n  queryParams: State['customQueryParams'];\n  refs: State['refs'];\n}\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/Brand.tsx",
    "content": "import React from 'react';\n\nimport { StorybookLogo } from 'storybook/internal/components';\n\nimport { styled, withTheme } from 'storybook/theming';\n\nexport const StorybookLogoStyled = styled(StorybookLogo)(({ theme }) => ({\n  width: 'auto',\n  height: '22px !important',\n  display: 'block',\n  color: theme.base === 'light' ? theme.color.defaultText : theme.color.lightest,\n}));\n\nexport const Img = styled.img({\n  display: 'block',\n  maxWidth: '150px !important',\n  maxHeight: '100px',\n});\n\nexport const LogoLink = styled.a(({ theme }) => ({\n  display: 'inline-flex',\n  alignItems: 'center',\n  height: '100%',\n  margin: '-3px -4px',\n  padding: '2px 3px',\n  border: '1px solid transparent',\n  borderRadius: 3,\n  color: 'inherit',\n  textDecoration: 'none',\n  '&:focus-visible': {\n    outline: `2px solid ${theme.color.secondary}`,\n    outlineOffset: 2,\n  },\n}));\n\n// @ts-expect-error (TODO)\nexport const Brand = withTheme(({ theme }) => {\n  const { title = 'Storybook', url = './', image, target } = theme.brand;\n  const targetValue = target || (url === './' ? '' : '_blank');\n\n  // When image is explicitly set to null, enable custom HTML support\n  if (image === null) {\n    if (title === null) {\n      return null;\n    }\n\n    if (!url) {\n      return <div dangerouslySetInnerHTML={{ __html: title }} />;\n    }\n    return <LogoLink href={url} target={targetValue} dangerouslySetInnerHTML={{ __html: title }} />;\n  }\n\n  const logo = image ? <Img src={image} alt={title} /> : <StorybookLogoStyled alt={title} />;\n\n  if (url) {\n    return (\n      <LogoLink title={title} href={url} target={targetValue}>\n        {logo}\n      </LogoLink>\n    );\n  }\n\n  // The wrapper div serves to prevent image misalignment\n  return <div>{logo}</div>;\n});\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/ChecklistWidget.stories.tsx",
    "content": "import type { PlayFunction } from 'storybook/internal/csf';\n\nimport { ManagerContext } from 'storybook/manager-api';\nimport { fn } from 'storybook/test';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { initialState } from '../../../shared/checklist-store/checklistData.state.ts';\nimport { internal_universalChecklistStore as mockStore } from '../../manager-stores.mock.ts';\nimport { ChecklistWidget } from './ChecklistWidget.tsx';\n\nconst managerContext: any = {\n  state: {},\n  api: {\n    getIsNavShown: () => true,\n    getData: fn().mockName('api::getData'),\n    getIndex: fn().mockName('api::getIndex'),\n    getUrlState: fn().mockName('api::getUrlState'),\n    navigate: fn().mockName('api::navigate'),\n    on: fn().mockName('api::on'),\n    off: fn().mockName('api::off'),\n    once: fn().mockName('api::once'),\n  },\n};\n\nconst meta = preview.meta({\n  component: ChecklistWidget,\n  decorators: [\n    (Story) => (\n      <ManagerContext.Provider value={managerContext}>\n        <div style={{ width: 300, height: 250 }}>{Story()}</div>\n      </ManagerContext.Provider>\n    ),\n  ],\n  beforeEach: async () => {\n    mockStore.setState({\n      loaded: true,\n      widget: {},\n      items: {\n        ...initialState.items,\n        controls: { status: 'accepted' },\n        renderComponent: { status: 'done' },\n        installVitest: { status: 'done' },\n        moreComponents: { status: 'skipped' },\n        moreStories: { status: 'skipped' },\n      },\n    });\n  },\n});\n\nconst wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst play: PlayFunction = async ({ step }) => {\n  await wait(3000);\n  await step('Complete viewports task', () => {\n    mockStore.setState({\n      loaded: true,\n      widget: {},\n      items: {\n        ...initialState.items,\n        controls: { status: 'accepted' },\n        renderComponent: { status: 'done' },\n        installVitest: { status: 'done' },\n        viewports: { status: 'done' },\n        moreComponents: { status: 'skipped' },\n        moreStories: { status: 'skipped' },\n      },\n    });\n  });\n\n  await wait(1000);\n  await step('Skip installVitest task', () => {\n    mockStore.setState({\n      loaded: true,\n      widget: {},\n      items: {\n        ...initialState.items,\n        controls: { status: 'accepted' },\n        renderComponent: { status: 'done' },\n        installVitest: { status: 'done' },\n        viewports: { status: 'done' },\n        moreComponents: { status: 'skipped' },\n        moreStories: { status: 'skipped' },\n        writeInteractions: { status: 'skipped' },\n      },\n    });\n  });\n};\n\nexport const Default = meta.story({\n  play,\n});\n\nexport const Narrow = meta.story({\n  decorators: [(Story) => <div style={{ width: 200, height: 250 }}>{Story()}</div>],\n  play,\n});\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/ChecklistWidget.tsx",
    "content": "import React, { useEffect, useRef, useState } from 'react';\n\nimport {\n  ActionList,\n  Card,\n  Collapsible,\n  PopoverProvider,\n  ProgressSpinner,\n} from 'storybook/internal/components';\n\nimport {\n  ChevronSmallUpIcon,\n  EyeCloseIcon,\n  ListUnorderedIcon,\n  StatusFailIcon,\n  StatusPassIcon,\n} from '@storybook/icons';\n\nimport { type TransitionMapOptions, useTransitionMap } from 'react-transition-state';\nimport { useStorybookApi } from 'storybook/manager-api';\nimport { keyframes, styled } from 'storybook/theming';\n\nimport { Optional } from '../Optional/Optional.tsx';\nimport { Particles } from '../Particles/Particles.tsx';\nimport { TextFlip } from '../TextFlip.tsx';\nimport type { ChecklistItem } from './useChecklist.ts';\nimport { useChecklist } from './useChecklist.ts';\n\nconst fadeScaleIn = keyframes`\n  from {\n    opacity: 0;\n    transform: scale(0.7);\n  }\n  to {\n    opacity: 1;\n    transform: scale(1);\n  }\n`;\n\nconst expand = keyframes`\n  from {\n    transform: scaleX(0);\n  }\n  to {\n    transform: scaleX(1);\n  }\n`;\n\nconst useTransitionArray = <K, V>(\n  array: V[],\n  subset: V[],\n  options: { keyFn: (item: V) => K } & TransitionMapOptions<K>\n) => {\n  const keyFnRef = useRef(options.keyFn);\n  const { setItem, toggle, stateMap } = useTransitionMap<K>({\n    allowMultiple: true,\n    mountOnEnter: true,\n    unmountOnExit: true,\n    preEnter: true,\n    ...options,\n  });\n\n  useEffect(() => {\n    const keyFn = keyFnRef.current;\n    array.forEach((task) => setItem(keyFn(task)));\n  }, [array, setItem]);\n\n  useEffect(() => {\n    const keyFn = keyFnRef.current;\n    array.forEach((task) => toggle(keyFn(task), subset.map(keyFn).includes(keyFn(task))));\n  }, [array, subset, toggle]);\n\n  return Array.from(stateMap).map(\n    ([key, value]) => [array.find((item) => keyFnRef.current(item) === key)!, value] as const\n  );\n};\n\nconst CollapsibleWithMargin = styled(Collapsible)(({ collapsed }) => ({\n  marginTop: collapsed ? 0 : 16,\n}));\n\nconst HoverCard = styled(Card)({\n  '&:hover #checklist-module-collapse-toggle': {\n    opacity: 1,\n  },\n});\n\nconst CollapseToggle = styled(ActionList.Button)({\n  opacity: 0,\n  transition: 'opacity var(--transition-duration, 0.2s)',\n  '&:focus, &:hover': {\n    opacity: 1,\n  },\n});\n\nconst ProgressCircle = styled(ProgressSpinner)(({ theme }) => ({\n  color: theme.color.secondary,\n}));\n\nconst Checked = styled(StatusPassIcon)(({ theme }) => ({\n  padding: 1,\n  borderRadius: '50%',\n  background: theme.color.positive,\n  color: theme.background.content,\n  animation: `${fadeScaleIn} 500ms forwards`,\n}));\n\nconst ItemLabel = styled.span<{ isCompleted: boolean; isSkipped: boolean }>(\n  ({ theme, isCompleted, isSkipped }) => ({\n    position: 'relative',\n    margin: '0 -2px',\n    padding: '0 2px',\n    color: isSkipped\n      ? theme.color.mediumdark\n      : isCompleted\n        ? theme.base === 'dark'\n          ? theme.color.positive\n          : theme.color.positiveText\n        : theme.color.defaultText,\n    transition: 'color 500ms',\n  }),\n  ({ theme, isSkipped }) =>\n    isSkipped && {\n      alignSelf: 'flex-start',\n      '&:after': {\n        content: '\"\"',\n        position: 'absolute',\n        top: '50%',\n        left: 0,\n        width: '100%',\n        height: 1,\n        background: theme.color.mediumdark,\n        animation: `${expand} 500ms forwards`,\n        transformOrigin: 'left',\n      },\n    }\n);\n\nconst title = (progress: number) => {\n  switch (true) {\n    case progress < 50:\n      return 'Get started';\n    case progress < 75:\n      return 'Level up';\n    default:\n      return 'Become an expert';\n  }\n};\n\nconst OpenGuideButton = ({\n  children,\n  afterClick,\n}: {\n  children?: React.ReactNode;\n  afterClick?: () => void;\n}) => {\n  const api = useStorybookApi();\n  return (\n    <ActionList.Action\n      ariaLabel=\"Open onboarding guide\"\n      onClick={(e) => {\n        e.stopPropagation();\n        api.navigate('/settings/guide');\n        afterClick?.();\n      }}\n    >\n      <ActionList.Icon>\n        <ListUnorderedIcon />\n      </ActionList.Icon>\n      {children}\n    </ActionList.Action>\n  );\n};\n\nexport const ChecklistWidget = () => {\n  const api = useStorybookApi();\n  const { loaded, ready, allItems, nextItems, progress, accept, mute, items } = useChecklist();\n  const [renderItems, setRenderItems] = useState<ChecklistItem[]>(nextItems);\n  const [animated, setAnimated] = useState(false);\n\n  useEffect(() => {\n    if (ready) {\n      // Don't animate anything until the checklist items have settled down.\n      const timeout = setTimeout(setAnimated, 1000, true);\n      return () => clearTimeout(timeout);\n    }\n  }, [ready]);\n\n  useEffect(() => {\n    if (!animated) {\n      setRenderItems(nextItems);\n      return;\n    }\n\n    // Render outgoing items with updated state for 2 seconds before\n    // rendering new items, in order to allow exit transition.\n    setRenderItems((current) => {\n      let animateOut = false;\n      const prevItems = current.map((item) => {\n        const { status } = items[item.id];\n        const isAccepted = status === 'accepted';\n        const isDone = status === 'done';\n        const isSkipped = status === 'skipped';\n        animateOut = animateOut || isAccepted || isDone || isSkipped;\n        return { ...item, isCompleted: isAccepted || isDone, isAccepted, isDone, isSkipped };\n      });\n      return animateOut ? prevItems : nextItems;\n    });\n\n    const timeout = setTimeout(setRenderItems, 2000, nextItems);\n    return () => clearTimeout(timeout);\n  }, [animated, nextItems, items]);\n\n  const hasItems = renderItems.length > 0;\n  const transitionItems = useTransitionArray(allItems, renderItems, {\n    keyFn: (item) => item.id,\n    timeout: animated ? 300 : 0,\n  });\n\n  if (!api.getIsNavShown()) {\n    return null;\n  }\n\n  return (\n    <CollapsibleWithMargin collapsed={!hasItems || !loaded}>\n      <HoverCard id=\"storybook-checklist-widget\" outlineAnimation=\"rainbow\">\n        <Collapsible\n          storageKey=\"checklist-widget\"\n          initialCollapsed={!hasItems}\n          disabled={!hasItems}\n          summary={({ isCollapsed, toggleCollapsed, toggleProps }) => (\n            <ActionList as=\"div\" onClick={toggleCollapsed}>\n              <ActionList.Item as=\"div\">\n                <ActionList.Item as=\"div\" style={{ flexShrink: 1 }}>\n                  {loaded && (\n                    <Optional\n                      content={\n                        <OpenGuideButton>\n                          <strong>{title(progress)}</strong>\n                        </OpenGuideButton>\n                      }\n                      fallback={<OpenGuideButton />}\n                    />\n                  )}\n                </ActionList.Item>\n                <ActionList.Item as=\"div\">\n                  <CollapseToggle\n                    {...toggleProps}\n                    id=\"checklist-module-collapse-toggle\"\n                    ariaLabel={`${isCollapsed ? 'Expand' : 'Collapse'} onboarding guide`}\n                  >\n                    <ChevronSmallUpIcon\n                      style={{\n                        transform: isCollapsed ? 'rotate(180deg)' : 'none',\n                        transition: 'transform 250ms',\n                        willChange: 'auto',\n                      }}\n                    />\n                  </CollapseToggle>\n                  {loaded && (\n                    <PopoverProvider\n                      ariaLabel=\"Onboarding guide menu\"\n                      padding={0}\n                      popover={({ onHide }) => (\n                        <ActionList>\n                          <ActionList.Item>\n                            <OpenGuideButton afterClick={onHide}>\n                              <ActionList.Text>Open full guide</ActionList.Text>\n                            </OpenGuideButton>\n                          </ActionList.Item>\n                          <ActionList.Item>\n                            <ActionList.Action\n                              ariaLabel={false}\n                              onClick={(e) => {\n                                e.stopPropagation();\n                                mute(allItems.map(({ id }) => id));\n                                onHide();\n                              }}\n                            >\n                              <ActionList.Icon>\n                                <EyeCloseIcon />\n                              </ActionList.Icon>\n                              <ActionList.Text>Remove from sidebar</ActionList.Text>\n                            </ActionList.Action>\n                          </ActionList.Item>\n                        </ActionList>\n                      )}\n                    >\n                      <ActionList.Button\n                        ariaLabel={`${progress}% completed`}\n                        onClick={(e) => e.stopPropagation()}\n                      >\n                        <ProgressCircle\n                          percentage={progress}\n                          running={false}\n                          size={16}\n                          width={1.5}\n                        />\n                        <TextFlip text={`${progress}%`} placeholder=\"00%\" />\n                      </ActionList.Button>\n                    </PopoverProvider>\n                  )}\n                </ActionList.Item>\n              </ActionList.Item>\n            </ActionList>\n          )}\n        >\n          <ActionList>\n            {transitionItems.map(\n              ([item, { status, isMounted }]) =>\n                isMounted && (\n                  <ActionList.HoverItem key={item.id} targetId={item.id} transitionStatus={status}>\n                    <ActionList.Action\n                      ariaLabel={`Open onboarding guide for ${item.label}`}\n                      onClick={() => api.navigate(`/settings/guide#${item.id}`)}\n                    >\n                      <ActionList.Icon>\n                        {item.isCompleted && animated ? (\n                          <Particles anchor={Checked} key={item.id} />\n                        ) : (\n                          <StatusFailIcon />\n                        )}\n                      </ActionList.Icon>\n                      <ActionList.Text>\n                        <ItemLabel isCompleted={item.isCompleted} isSkipped={item.isSkipped}>\n                          {item.label}\n                        </ItemLabel>\n                      </ActionList.Text>\n                    </ActionList.Action>\n                    {item.action && (\n                      <ActionList.Button\n                        data-target-id={item.id}\n                        ariaLabel={false}\n                        onClick={(e) => {\n                          e.stopPropagation();\n                          item.action?.onClick({\n                            api,\n                            accept: () => accept(item.id),\n                          });\n                        }}\n                      >\n                        {item.action.label}\n                      </ActionList.Button>\n                    )}\n                  </ActionList.HoverItem>\n                )\n            )}\n          </ActionList>\n        </Collapsible>\n      </HoverCard>\n    </CollapsibleWithMargin>\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/ContextMenu.tsx",
    "content": "import type { ComponentProps, FC, SyntheticEvent } from 'react';\nimport React, { useContext, useMemo, useState } from 'react';\n\nimport { PopoverProvider, TooltipLinkList } from 'storybook/internal/components';\nimport {\n  type API_HashEntry,\n  type Addon_Collection,\n  type Addon_TestProviderType,\n  Addon_TypesEnum,\n  type StatusValue,\n} from 'storybook/internal/types';\n\nimport { CopyIcon, EditorIcon, EllipsisIcon } from '@storybook/icons';\n\nimport copy from 'copy-to-clipboard';\nimport { useStorybookApi } from 'storybook/manager-api';\nimport type { API } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport type { Link } from '../../../components/components/tooltip/TooltipLinkList.tsx';\nimport { getMostCriticalStatusValue } from '../../utils/status.tsx';\nimport { Shortcut } from '../Shortcut.tsx';\nimport { UseSymbol } from './IconSymbols.tsx';\nimport { StatusButton } from './StatusButton.tsx';\nimport { StatusContext } from './StatusContext.tsx';\nimport type { ExcludesNull } from './Tree.tsx';\n\nconst empty = {\n  onMouseEnter: () => {},\n  node: null,\n};\n\nconst FloatingStatusButton = styled(StatusButton)({\n  background: 'var(--tree-node-background-hover)',\n  boxShadow: '0 0 5px 5px var(--tree-node-background-hover)',\n  position: 'absolute',\n  right: 0,\n  zIndex: 1,\n  '&:focus-visible': {\n    outlineOffset: -2,\n  },\n});\n\nexport const useContextMenu = (context: API_HashEntry, links: Link[], api: API) => {\n  const [hoverCount, setHoverCount] = useState(0);\n  const [isOpen, setIsOpen] = useState(false);\n  const [copyText, setCopyText] = React.useState('Copy story name');\n  const { allStatuses, groupStatus } = useContext(StatusContext);\n\n  const shortcutKeys = api.getShortcutKeys();\n  const enableShortcuts = !!shortcutKeys;\n\n  const topLinks = useMemo<Link[]>(() => {\n    const defaultLinks = [];\n\n    if (context && 'importPath' in context && context.importPath) {\n      defaultLinks.push({\n        id: 'open-in-editor',\n        title: 'Open in editor',\n        icon: <EditorIcon />,\n        right: enableShortcuts ? <Shortcut keys={shortcutKeys.openInEditor} /> : null,\n        onClick: (e: SyntheticEvent) => {\n          if (context.importPath) {\n            e.preventDefault();\n            api.openInEditor({ file: context.importPath });\n          }\n        },\n      });\n    }\n\n    if (context.type === 'story') {\n      defaultLinks.push({\n        id: 'copy-story-name',\n        title: copyText,\n        icon: <CopyIcon />,\n        // TODO: bring this back once we want to add shortcuts for this\n        // right:\n        //   enableShortcuts && shortcutKeys.copyStoryName ? (\n        //     <Shortcut keys={shortcutKeys.copyStoryName} />\n        //   ) : null,\n        onClick: (e: SyntheticEvent) => {\n          e.preventDefault();\n          copy(context.exportName);\n          setCopyText('Copied!');\n          setTimeout(() => {\n            setCopyText('Copy story name');\n          }, 2000);\n        },\n      });\n    }\n\n    return defaultLinks;\n  }, [api, context, copyText, enableShortcuts, shortcutKeys]);\n\n  const handlers = useMemo(() => {\n    return {\n      onMouseEnter: () => {\n        setHoverCount((c) => c + 1);\n      },\n      onOpen: (event: SyntheticEvent) => {\n        event.stopPropagation();\n        setIsOpen(true);\n      },\n      onClose: () => {\n        setIsOpen(false);\n      },\n    };\n  }, []);\n  /**\n   * Calculate the providerLinks whenever the user mouses over the container. We use an incrementor,\n   * instead of a simple boolean to ensure that the links are recalculated\n   */\n  const providerLinks = useMemo(() => {\n    const registeredTestProviders = api.getElements(Addon_TypesEnum.experimental_TEST_PROVIDER);\n\n    if (hoverCount) {\n      return generateTestProviderLinks(registeredTestProviders, context);\n    }\n    return [];\n  }, [api, context, hoverCount]);\n\n  // We just don't want to render the context menu for composed storybook stories\n  const shouldRender =\n    !context.refId && (providerLinks.length > 0 || links.length > 0 || topLinks.length > 0);\n\n  const isLeafNode = context.type === 'story' || context.type === 'docs';\n\n  const itemStatus = useMemo<StatusValue>(() => {\n    let status: StatusValue = 'status-value:unknown';\n    if (!context) {\n      return status;\n    }\n\n    if (isLeafNode) {\n      const values = Object.values(allStatuses?.[context.id] || {}).map((s) => s.value);\n      status = getMostCriticalStatusValue(values);\n    }\n\n    if (!isLeafNode) {\n      // On component/groups we only show non-ellipsis on hover on non-success status colors\n      const groupValue = groupStatus && groupStatus[context.id];\n      status =\n        groupValue === 'status-value:success' || groupValue === undefined\n          ? 'status-value:unknown'\n          : groupValue;\n    }\n\n    return status;\n  }, [allStatuses, groupStatus, context, isLeafNode]);\n\n  const MenuIcon = useMemo(() => {\n    // On component/groups we only show non-ellipsis on hover on non-success statuses\n    if (context.type !== 'story' && context.type !== 'docs') {\n      if (itemStatus !== 'status-value:success' && itemStatus !== 'status-value:unknown') {\n        return (\n          <svg key=\"icon\" viewBox=\"0 0 6 6\" width=\"6\" height=\"6\">\n            <UseSymbol type=\"dot\" />\n          </svg>\n        );\n      }\n\n      return <EllipsisIcon />;\n    }\n\n    if (itemStatus === 'status-value:error') {\n      return (\n        <svg key=\"icon\" viewBox=\"0 0 14 14\" width=\"14\" height=\"14\">\n          <UseSymbol type=\"error\" />\n        </svg>\n      );\n    }\n    if (itemStatus === 'status-value:warning') {\n      return (\n        <svg key=\"icon\" viewBox=\"0 0 14 14\" width=\"14\" height=\"14\">\n          <UseSymbol type=\"warning\" />\n        </svg>\n      );\n    }\n    if (itemStatus === 'status-value:success') {\n      return (\n        <svg key=\"icon\" viewBox=\"0 0 14 14\" width=\"14\" height=\"14\">\n          <UseSymbol type=\"success\" />\n        </svg>\n      );\n    }\n    return <EllipsisIcon />;\n  }, [itemStatus, context.type]);\n\n  return useMemo(() => {\n    // Never show the SidebarContextMenu in production\n    if (globalThis.CONFIG_TYPE !== 'DEVELOPMENT') {\n      return empty;\n    }\n\n    return {\n      onMouseEnter: handlers.onMouseEnter,\n      node: shouldRender ? (\n        <PopoverProvider\n          ariaLabel=\"Context menu\"\n          placement=\"bottom-end\"\n          defaultVisible={false}\n          visible={isOpen}\n          onVisibleChange={setIsOpen}\n          popover={<LiveContextMenu context={context} links={[...topLinks, ...links]} />}\n          hasChrome={true}\n          padding={0}\n        >\n          <FloatingStatusButton\n            data-displayed={isOpen ? 'on' : 'off'}\n            data-testid=\"context-menu\"\n            ariaLabel=\"Open context menu\"\n            type=\"button\"\n            status={itemStatus}\n            onClick={handlers.onOpen}\n          >\n            {MenuIcon}\n          </FloatingStatusButton>\n        </PopoverProvider>\n      ) : null,\n    };\n  }, [context, handlers, isOpen, shouldRender, links, topLinks, itemStatus, MenuIcon]);\n};\n\n/**\n * This component re-subscribes to storybook's core state, hence the Live prefix. It is used to\n * render the context menu for the sidebar. it self is a tooltip link list that renders the links\n * provided to it. In addition to the links, it also renders the test providers.\n */\nconst LiveContextMenu: FC<{ context: API_HashEntry } & ComponentProps<typeof TooltipLinkList>> = ({\n  context,\n  links,\n  ...rest\n}) => {\n  const registeredTestProviders = useStorybookApi().getElements(\n    Addon_TypesEnum.experimental_TEST_PROVIDER\n  );\n  const providerLinks: Link[] = generateTestProviderLinks(registeredTestProviders, context);\n\n  /**\n   * The context menu can take a list of lists of links, so that the links are grouped and separated\n   * by a line separator, so we need to make sure that links are contained within arrays (but not\n   * more than one level deep)\n   */\n  const groups: Link[][] =\n    Array.isArray(links[0]) || links.length === 0 ? (links as Link[][]) : [links as Link[]];\n\n  const all = groups.concat([providerLinks]);\n\n  return <TooltipLinkList {...rest} links={all} />;\n};\n\nexport function generateTestProviderLinks(\n  registeredTestProviders: Addon_Collection<Addon_TestProviderType>,\n  context: API_HashEntry\n): Link[] {\n  return Object.entries(registeredTestProviders)\n    .map(([testProviderId, state]) => {\n      if (!state) {\n        return null;\n      }\n      const content = state.sidebarContextMenu?.({ context });\n\n      if (!content) {\n        return null;\n      }\n\n      return {\n        id: testProviderId,\n        content,\n      };\n    })\n    .filter(Boolean as unknown as ExcludesNull);\n}\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/CreateNewStoryFileModal.tsx",
    "content": "import React, { useCallback, useDeferredValue, useEffect, useRef, useState } from 'react';\n\nimport {\n  CREATE_NEW_STORYFILE_REQUEST,\n  CREATE_NEW_STORYFILE_RESPONSE,\n  FILE_COMPONENT_SEARCH_REQUEST,\n  FILE_COMPONENT_SEARCH_RESPONSE,\n  GHOST_STORIES_REQUEST,\n} from 'storybook/internal/core-events';\nimport type {\n  CreateNewStoryErrorPayload,\n  CreateNewStoryRequestPayload,\n  CreateNewStoryResponsePayload,\n  FileComponentSearchRequestPayload,\n  FileComponentSearchResponsePayload,\n  RequestData,\n  ResponseData,\n} from 'storybook/internal/core-events';\n\nimport { global } from '@storybook/global';\nimport { CheckIcon } from '@storybook/icons';\n\nimport type { RequestResponseError } from 'storybook/manager-api';\nimport { addons, experimental_requestResponse, useStorybookApi } from 'storybook/manager-api';\n\nimport { useDebounce } from '../../hooks/useDebounce.ts';\nimport type { NewStoryPayload, SearchResult } from './FileSearchList.tsx';\nimport { FileSearchModal } from './FileSearchModal.tsx';\nimport { trySelectNewStory } from './FileSearchModal.utils.tsx';\n\ninterface CreateNewStoryFileModalProps {\n  open: boolean;\n  onOpenChange: (open: boolean) => void;\n}\n\nconst isRendererReact = global.STORYBOOK_RENDERER === 'react';\n\nexport const CreateNewStoryFileModal = ({ open, onOpenChange }: CreateNewStoryFileModalProps) => {\n  const [isLoading, setLoading] = useState(false);\n  const [fileSearchQuery, setFileSearchQuery] = useState('');\n  const fileSearchQueryDebounced = useDebounce(fileSearchQuery, 600);\n  const fileSearchQueryDeferred = useDeferredValue(fileSearchQueryDebounced);\n  const emittedValue = useRef<string | null>(null);\n  const [error, setError] = useState<{ selectedItemId?: number | string; error: string } | null>(\n    null\n  );\n  const api = useStorybookApi();\n\n  const hasRunGhostStoriesFlow = useRef(false);\n\n  const [searchResults, setSearchResults] = useState<SearchResult[] | null>(null);\n\n  const handleSuccessfullyCreatedStory = useCallback(\n    (componentExportName: string) => {\n      api.addNotification({\n        id: 'create-new-story-file-success',\n        content: {\n          headline: 'Story file created',\n          subHeadline: `${componentExportName} was created`,\n        },\n        duration: 8_000,\n        icon: <CheckIcon />,\n      });\n\n      onOpenChange(false);\n    },\n    [api, onOpenChange]\n  );\n\n  const handleStoryAlreadyExists = useCallback(() => {\n    api.addNotification({\n      id: 'create-new-story-file-error',\n      content: {\n        headline: 'Story already exists',\n        subHeadline: `Successfully navigated to existing story`,\n      },\n      duration: 8_000,\n      icon: <CheckIcon />,\n    });\n\n    onOpenChange(false);\n  }, [api, onOpenChange]);\n\n  const handleFileSearch = useCallback(() => {\n    setLoading(true);\n    const channel = addons.getChannel();\n\n    const set = (data: ResponseData<FileComponentSearchResponsePayload>) => {\n      const isLatestRequest = data.id === fileSearchQueryDeferred;\n\n      if (isLatestRequest) {\n        if (data.success) {\n          setSearchResults(data.payload.files);\n        } else {\n          setError({ error: data.error });\n        }\n\n        channel.off(FILE_COMPONENT_SEARCH_RESPONSE, set);\n        setLoading(false);\n        emittedValue.current = null;\n      }\n    };\n\n    channel.on(FILE_COMPONENT_SEARCH_RESPONSE, set);\n\n    if (fileSearchQueryDeferred !== '' && emittedValue.current !== fileSearchQueryDeferred) {\n      emittedValue.current = fileSearchQueryDeferred;\n      channel.emit(FILE_COMPONENT_SEARCH_REQUEST, {\n        id: fileSearchQueryDeferred,\n        payload: {},\n      } satisfies RequestData<FileComponentSearchRequestPayload>);\n    } else {\n      setSearchResults(null);\n      setLoading(false);\n    }\n\n    return () => {\n      channel.off(FILE_COMPONENT_SEARCH_RESPONSE, set);\n    };\n  }, [fileSearchQueryDeferred]);\n\n  const handleCreateNewStory = useCallback(\n    async ({\n      componentExportName,\n      componentFilePath,\n      componentIsDefaultExport,\n      componentExportCount,\n      selectedItemId,\n    }: NewStoryPayload) => {\n      try {\n        const channel = addons.getChannel();\n\n        const createNewStoryResult = await experimental_requestResponse<\n          CreateNewStoryRequestPayload,\n          CreateNewStoryResponsePayload,\n          CreateNewStoryErrorPayload\n        >(channel, CREATE_NEW_STORYFILE_REQUEST, CREATE_NEW_STORYFILE_RESPONSE, {\n          componentExportName,\n          componentFilePath,\n          componentIsDefaultExport,\n          componentExportCount,\n        });\n\n        setError(null);\n\n        const storyId = createNewStoryResult.storyId;\n\n        await trySelectNewStory(api.selectStory, storyId);\n\n        handleSuccessfullyCreatedStory(componentExportName);\n        handleFileSearch();\n      } catch (e: any) {\n        switch (e?.payload?.type as CreateNewStoryErrorPayload['type']) {\n          case 'STORY_FILE_EXISTS':\n            const err = e as RequestResponseError<CreateNewStoryErrorPayload>;\n            // @ts-expect-error (non strict)\n            await trySelectNewStory(api.selectStory, err.payload.kind);\n            handleStoryAlreadyExists();\n            break;\n          default:\n            setError({ selectedItemId: selectedItemId, error: (e as any)?.message });\n            break;\n        }\n      }\n    },\n    [api?.selectStory, handleSuccessfullyCreatedStory, handleFileSearch, handleStoryAlreadyExists]\n  );\n\n  useEffect(() => {\n    setError(null);\n  }, [fileSearchQueryDeferred]);\n\n  useEffect(() => {\n    return handleFileSearch();\n  }, [handleFileSearch]);\n\n  const executeGhostStoriesFlow = useCallback(async () => {\n    const channel = addons.getChannel();\n    channel.emit(GHOST_STORIES_REQUEST);\n  }, []);\n\n  // Trigger the one-time flow when modal opens\n  useEffect(() => {\n    if (open && isRendererReact && !hasRunGhostStoriesFlow.current) {\n      hasRunGhostStoriesFlow.current = true;\n      executeGhostStoriesFlow();\n    }\n  }, [open, executeGhostStoriesFlow]);\n\n  return (\n    <FileSearchModal\n      error={error}\n      fileSearchQuery={fileSearchQuery}\n      fileSearchQueryDeferred={fileSearchQueryDeferred}\n      onCreateNewStory={handleCreateNewStory}\n      isLoading={isLoading}\n      onOpenChange={onOpenChange}\n      open={open}\n      searchResults={searchResults}\n      setError={setError}\n      setFileSearchQuery={setFileSearchQuery}\n    />\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/Explorer.stories.tsx",
    "content": "import React from 'react';\n\nimport { Explorer } from './Explorer.tsx';\nimport { IconSymbols } from './IconSymbols.tsx';\nimport * as RefStories from './Refs.stories.tsx';\nimport { mockDataset } from './mockdata.ts';\nimport type { RefType } from './types.ts';\n\nexport default {\n  component: Explorer,\n  title: 'Sidebar/Explorer',\n  globals: { sb_theme: 'side-by-side' },\n  parameters: { layout: 'fullscreen' },\n  decorators: [\n    RefStories.default.decorators[0],\n    (storyFn: any) => (\n      <div style={{ padding: '0 20px', maxWidth: '230px' }}>\n        <IconSymbols />\n        {storyFn()}\n      </div>\n    ),\n  ],\n};\n\nconst simple: Record<string, RefType> = {\n  storybook_internal: {\n    title: undefined,\n    id: 'storybook_internal',\n    url: 'iframe.html',\n    previewInitialized: true,\n    // @ts-expect-error (invalid input)\n    filteredIndex: mockDataset.withRoot,\n  },\n};\n\nconst withRefs: Record<string, RefType> = {\n  ...simple,\n  basic: {\n    id: 'basic',\n    title: 'Basic ref',\n    url: 'https://example.com',\n    previewInitialized: true,\n    type: 'auto-inject',\n    // @ts-expect-error (invalid input)\n    filteredIndex: mockDataset.noRoot,\n  },\n  injected: {\n    id: 'injected',\n    title: 'Not ready',\n    url: 'https://example.com',\n    previewInitialized: false,\n    type: 'auto-inject',\n    // @ts-expect-error (invalid input)\n    filteredIndex: mockDataset.noRoot,\n  },\n  unknown: {\n    id: 'unknown',\n    title: 'Unknown ref',\n    url: 'https://example.com',\n    previewInitialized: true,\n    type: 'unknown',\n    // @ts-expect-error (invalid input)\n    filteredIndex: mockDataset.noRoot,\n  },\n  lazy: {\n    id: 'lazy',\n    title: 'Lazy loaded ref',\n    url: 'https://example.com',\n    previewInitialized: false,\n    type: 'lazy',\n    // @ts-expect-error (invalid input)\n    filteredIndex: mockDataset.withRoot,\n  },\n};\n\nexport const Simple = () => (\n  <Explorer\n    dataset={{ hash: simple, entries: Object.entries(simple) }}\n    selected={{\n      refId: 'storybook_internal',\n      storyId: 'root-1-child-a2--grandchild-a1-1:test1',\n    }}\n    isLoading={false}\n    isBrowsing\n    hasEntries={true}\n    isHidden={false}\n  />\n);\n\nexport const WithRefs = () => (\n  <Explorer\n    dataset={{ hash: withRefs, entries: Object.entries(withRefs) }}\n    selected={{\n      refId: 'storybook_internal',\n      storyId: 'root-1-child-a2--grandchild-a1-1',\n    }}\n    isLoading={false}\n    isBrowsing\n    hasEntries={true}\n    isHidden={false}\n  />\n);\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/Explorer.tsx",
    "content": "import type { FC } from 'react';\nimport React, { useRef } from 'react';\n\nimport { useLandmark } from '../../hooks/useLandmark.ts';\nimport { HighlightStyles } from './HighlightStyles.tsx';\nimport { Ref } from './Refs.tsx';\nimport type { CombinedDataset, Selection } from './types.ts';\nimport { useHighlighted } from './useHighlighted.ts';\n\nexport interface ExplorerProps {\n  className?: string;\n  isLoading: boolean;\n  isBrowsing: boolean;\n  isHidden: boolean;\n  hasEntries: boolean;\n  dataset: CombinedDataset;\n  selected: Selection;\n}\n\nexport const Explorer: FC<ExplorerProps> = React.memo(function Explorer({\n  hasEntries,\n  isLoading,\n  isBrowsing,\n  isHidden,\n  dataset,\n  selected,\n  ...restProps\n}) {\n  const containerRef = useRef<HTMLElement>(null);\n\n  // Track highlighted nodes, keep it in sync with props and enable keyboard navigation\n  const [highlighted, setHighlighted, highlightedRef] = useHighlighted({\n    containerRef,\n    isLoading,\n    isBrowsing,\n    selected,\n  });\n\n  const { landmarkProps } = useLandmark(\n    { 'aria-labelledby': 'storybook-explorer-tree-heading', role: 'navigation' },\n    containerRef\n  );\n\n  return (\n    <nav\n      hidden={isHidden || undefined}\n      aria-hidden={isHidden || undefined}\n      className={isBrowsing ? undefined : 'sb-sr-only'}\n      ref={containerRef}\n      id=\"storybook-explorer-tree\"\n      data-highlighted-ref-id={highlighted?.refId}\n      data-highlighted-item-id={highlighted?.itemId}\n      {...landmarkProps}\n      {...restProps}\n    >\n      <h2 id=\"storybook-explorer-tree-heading\" className=\"sb-sr-only\">\n        Stories\n      </h2>\n      {highlighted && <HighlightStyles {...highlighted} />}\n      {dataset.entries.map(([refId, ref]) => (\n        <Ref\n          {...ref}\n          key={refId}\n          isLoading={isLoading}\n          isBrowsing={isBrowsing}\n          hasEntries={hasEntries}\n          selectedStoryId={selected?.refId === ref.id ? selected.storyId : null}\n          highlightedRef={highlightedRef}\n          setHighlighted={setHighlighted}\n        />\n      ))}\n    </nav>\n  );\n});\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/FIleSearchList.utils.tsx",
    "content": "import { useEffect } from 'react';\nimport { flushSync } from 'react-dom';\n\nimport type { Virtualizer } from '@tanstack/react-virtual';\n\ninterface UseArrowKeyNavigationProps {\n  rowVirtualizer: Virtualizer<HTMLDivElement, Element>;\n  parentRef: React.MutableRefObject<HTMLDivElement>;\n  selectedItem: number | null;\n}\n\n/** Hook to navigate through the list of items and subitems using the arrow keys */\nexport const useArrowKeyNavigation = ({\n  parentRef,\n  rowVirtualizer,\n  selectedItem,\n}: UseArrowKeyNavigationProps) => {\n  useEffect(() => {\n    const handleArrowKeys = (event: KeyboardEvent) => {\n      if (!parentRef.current) {\n        return;\n      }\n\n      const maxIndex = rowVirtualizer.options.count;\n      const activeElement = document.activeElement;\n      // @ts-expect-error (non strict)\n      const rowIndex = parseInt(activeElement.getAttribute('data-index') || '-1', 10);\n      // @ts-expect-error (non strict)\n      const isActiveElementInput = activeElement.tagName === 'INPUT';\n\n      const getFirstElement = () =>\n        document.querySelector('[data-index=\"0\"]') as HTMLElement | null;\n      const getLastElement = () =>\n        document.querySelector(`[data-index=\"${maxIndex - 1}\"]`) as HTMLElement | null;\n\n      if (event.code === 'ArrowDown' && activeElement) {\n        event.stopPropagation();\n\n        // If the search input is focused, focus the first element\n        if (isActiveElementInput) {\n          getFirstElement()?.focus();\n          return;\n        }\n\n        // if the last element is focused, focus the first element\n        if (rowIndex === maxIndex - 1) {\n          flushSync(() => {\n            rowVirtualizer.scrollToIndex(0, { align: 'start' });\n          });\n          setTimeout(() => {\n            getFirstElement()?.focus();\n          }, 100);\n          return;\n        }\n\n        // if the focus is on an selected element, focus the first element in the sublist\n        if (selectedItem === rowIndex) {\n          const firstSubListItem = document.querySelector(\n            `[data-index-position=\"${selectedItem}_first\"]`\n          ) as HTMLElement;\n          firstSubListItem?.focus();\n          return;\n        }\n\n        // if the focus is on the last element on a sublist, focus the next parent list element\n        if (selectedItem !== null) {\n          const isLastElementSelected = activeElement\n            .getAttribute('data-index-position')\n            ?.includes('last');\n          if (isLastElementSelected) {\n            const nextElement = document.querySelector(\n              `[data-index=\"${selectedItem + 1}\"]`\n            ) as HTMLElement;\n            nextElement?.focus();\n            return;\n          }\n        }\n\n        const nextElement = activeElement.nextElementSibling as HTMLElement;\n        nextElement?.focus();\n      }\n\n      if (event.code === 'ArrowUp' && activeElement) {\n        if (isActiveElementInput) {\n          flushSync(() => {\n            rowVirtualizer.scrollToIndex(maxIndex - 1, { align: 'start' });\n          });\n          setTimeout(() => {\n            getLastElement()?.focus();\n          }, 100);\n          return;\n        }\n\n        // if the focus is on the first element on a sublist, focus the previous parent list element\n        if (selectedItem !== null) {\n          const isLastElementSelected = activeElement\n            .getAttribute('data-index-position')\n            ?.includes('first');\n          if (isLastElementSelected) {\n            const prevElement = document.querySelector(\n              `[data-index=\"${selectedItem}\"]`\n            ) as HTMLElement;\n            prevElement?.focus();\n            return;\n          }\n        }\n\n        const previousElement = activeElement.previousElementSibling as HTMLElement;\n        previousElement?.focus();\n      }\n    };\n    // listener for arrow keys to select the next/previous element by using the current active element as base\n    document.addEventListener('keydown', handleArrowKeys, { capture: true });\n\n    return () => {\n      document.removeEventListener('keydown', handleArrowKeys, { capture: true });\n    };\n  }, [rowVirtualizer, selectedItem, parentRef]);\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/FileList.tsx",
    "content": "import { rgba } from 'polished';\nimport { styled } from 'storybook/theming';\n\nexport const FileListWrapper = styled('div')(({ theme }) => ({\n  marginTop: '-16px',\n  // after element which fades out the list\n  '&::after': {\n    content: '\"\"',\n    position: 'fixed',\n    pointerEvents: 'none',\n    bottom: 0,\n    left: 0,\n    right: 0,\n    height: '80px',\n    background: `linear-gradient(${rgba(theme.barBg, 0)} 10%, ${theme.barBg} 80%)`,\n  },\n}));\n\nexport const FileList = styled('div')({\n  height: '280px',\n  overflow: 'auto',\n  msOverflowStyle: 'none',\n  scrollbarWidth: 'none',\n  position: 'relative',\n  '::-webkit-scrollbar': {\n    display: 'none',\n  },\n});\n\nexport const FileListLi = styled('li')(({ theme }) => ({\n  ':focus-visible': {\n    outline: 'none',\n\n    '.file-list-item': {\n      borderRadius: '4px',\n      background: theme.base === 'dark' ? 'rgba(255,255,255,.1)' : theme.color.mediumlight,\n\n      '> svg': {\n        display: 'flex',\n      },\n    },\n  },\n}));\n\nexport const FileListItem = styled('div')({\n  display: 'flex',\n  flexDirection: 'column',\n  position: 'relative',\n});\n\nexport const FileListItemContentWrapper = styled.div<{\n  selected: boolean;\n  disabled: boolean;\n  error: boolean;\n}>(({ theme, selected, disabled, error }) => ({\n  display: 'flex',\n  alignItems: 'flex-start',\n  gap: '8px',\n  alignSelf: 'stretch',\n  padding: '8px 16px',\n  cursor: 'pointer',\n  borderRadius: '4px',\n\n  ...(selected && {\n    borderRadius: '4px',\n    background: theme.base === 'dark' ? 'rgba(255,255,255,.1)' : theme.color.mediumlight,\n\n    '> svg': {\n      display: 'flex',\n    },\n  }),\n\n  ...(disabled && {\n    cursor: 'not-allowed',\n\n    div: {\n      color: `${theme.textMutedColor} !important`,\n    },\n  }),\n\n  ...(error && {\n    background: theme.base === 'light' ? '#00000011' : '#00000033',\n  }),\n\n  '&:hover': {\n    background: error\n      ? '#00000022'\n      : theme.base === 'dark'\n        ? 'rgba(255,255,255,.1)'\n        : theme.color.mediumlight,\n\n    '> svg': {\n      display: 'flex',\n    },\n  },\n}));\n\nexport const FileListUl = styled('ul')({\n  margin: 0,\n  padding: '0 0 0 0',\n  width: '100%',\n  position: 'relative',\n});\n\nexport const FileListItemContent = styled('div')({\n  display: 'flex',\n  flexDirection: 'column',\n  alignItems: 'flex-start',\n  width: 'calc(100% - 50px)',\n});\n\nexport const FileListIconWrapper = styled('div')<{ error: boolean }>(({ theme, error }) => ({\n  color: error ? theme.color.negativeText : theme.color.secondary,\n}));\n\nexport const FileListItemLabel = styled('div')<{ error: boolean }>(({ theme, error }) => ({\n  color: error\n    ? theme.color.negativeText\n    : theme.base === 'dark'\n      ? theme.color.lighter\n      : theme.color.darkest,\n  fontSize: '14px',\n  whiteSpace: 'nowrap',\n  textOverflow: 'ellipsis',\n  overflow: 'hidden',\n  maxWidth: '100%',\n}));\n\nexport const FileListItemPath = styled('div')(({ theme }) => ({\n  color: theme.textMutedColor,\n  fontSize: '14px',\n  whiteSpace: 'nowrap',\n  textOverflow: 'ellipsis',\n  overflow: 'hidden',\n  maxWidth: '100%',\n}));\n\nexport const FileListExport = styled('ul')({\n  margin: 0,\n  padding: 0,\n});\n\nexport const FileListItemExport = styled('li')<{ error: boolean }>(({ theme, error }) => ({\n  padding: '8px 16px 8px 58px',\n  display: 'flex',\n  gap: '8px',\n  alignItems: 'center',\n  justifyContent: 'space-between',\n  fontSize: '14px',\n  cursor: 'pointer',\n  borderRadius: '4px',\n\n  ':focus-visible': {\n    outline: 'none',\n  },\n\n  ...(error && {\n    background: '#F9ECEC',\n    color: theme.color.negativeText,\n  }),\n\n  '&:hover,:focus-visible': {\n    background: error\n      ? '#F9ECEC'\n      : theme.base === 'dark'\n        ? 'rgba(255, 255, 255, 0.1)'\n        : theme.color.mediumlight,\n\n    '> svg': {\n      display: 'flex',\n    },\n  },\n\n  '> div > svg': {\n    color: error ? theme.color.negativeText : theme.color.secondary,\n  },\n}));\n\nexport const FileListItemExportName = styled('div')({\n  display: 'flex',\n  alignItems: 'center',\n  gap: '8px',\n  width: 'calc(100% - 20px)',\n});\n\nexport const FileListItemExportNameContent = styled('span')(({ theme }) => ({\n  whiteSpace: 'nowrap',\n  textOverflow: 'ellipsis',\n  overflow: 'hidden',\n  display: 'inline-block',\n  color: theme.base === 'dark' ? theme.color.lightest : theme.color.darkest,\n}));\n\nexport const FileListItemExportNameContentWithExport = styled(FileListItemExportNameContent)({\n  maxWidth: 'calc(100% - 120px)',\n});\n\nexport const DefaultExport = styled('span')(({ theme }) => ({\n  display: 'inline-block',\n  padding: `1px ${theme.appBorderRadius}px`,\n  borderRadius: '2px',\n  fontSize: '10px',\n  color: theme.color.defaultText,\n  backgroundColor: theme.base === 'dark' ? 'rgba(255, 255, 255, 0.1)' : '#F2F4F5',\n}));\n\nexport const NoResults = styled('div')(({ theme }) => ({\n  textAlign: 'center',\n  maxWidth: '334px',\n  margin: '16px auto 50px auto',\n  fontSize: '14px',\n  color: theme.base === 'dark' ? theme.color.lightest : '#000',\n}));\n\nexport const NoResultsDescription = styled('p')(({ theme }) => ({\n  margin: 0,\n  color: theme.textMutedColor,\n}));\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/FileSearchList.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { expect, fireEvent, fn, within } from 'storybook/test';\n\nimport { FileSearchList } from './FileSearchList.tsx';\n\nconst meta = {\n  component: FileSearchList,\n  title: 'Sidebar/FileSearchList',\n  args: {\n    onNewStory: fn(),\n  },\n  parameters: {\n    layout: 'fullscreen',\n  },\n} satisfies Meta<typeof FileSearchList>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {\n  args: {\n    isLoading: true,\n    searchResults: null,\n    // @ts-expect-error (non strict)\n    errorItemId: null,\n  },\n};\n\nexport const Empty: Story = {\n  args: {\n    isLoading: false,\n    searchResults: [],\n    // @ts-expect-error (non strict)\n    errorItemId: null,\n  },\n};\n\nexport const WithResults: Story = {\n  play: async ({ canvasElement, args }) => {\n    const canvas = within(canvasElement);\n    const firstItem = await canvas.findByText('module-multiple-exports.js', {}, { timeout: 3000 });\n    fireEvent.click(firstItem);\n\n    const exportedElement1 = await canvas.findByText('module-multiple-exports');\n    fireEvent.click(exportedElement1);\n\n    expect(args.onNewStory).toHaveBeenCalledWith(\n      expect.objectContaining({\n        selectedItemId: 'src/module-multiple-exports.js_0',\n        componentExportName: 'default',\n        componentFilePath: 'src/module-multiple-exports.js',\n        componentIsDefaultExport: true,\n      })\n    );\n\n    const exportedElement2 = await canvas.findByText('namedExport');\n    fireEvent.click(exportedElement2);\n\n    expect(args.onNewStory).toHaveBeenCalledWith(\n      expect.objectContaining({\n        selectedItemId: 'src/module-multiple-exports.js_1',\n        componentExportName: 'namedExport',\n        componentFilePath: 'src/module-multiple-exports.js',\n        componentIsDefaultExport: false,\n      })\n    );\n\n    const singleExport = await canvas.findByText('module-single-export.js');\n    fireEvent.click(singleExport);\n\n    expect(args.onNewStory).toHaveBeenCalledWith(\n      expect.objectContaining({\n        selectedItemId: 'src/module-single-export.js',\n        componentExportName: 'default',\n        componentFilePath: 'src/module-single-export.js',\n        componentIsDefaultExport: true,\n      })\n    );\n\n    expect(args.onNewStory).toHaveBeenCalledTimes(3);\n\n    const noExportsModule1 = await canvas.findByText('no-exports-module.js');\n    fireEvent.click(noExportsModule1);\n\n    expect(args.onNewStory).toHaveBeenCalledTimes(3);\n\n    const noExportsModule2 = await canvas.findByText('no-exports-module-1.js');\n    fireEvent.click(noExportsModule2);\n\n    expect(args.onNewStory).toHaveBeenCalledTimes(3);\n  },\n  args: {\n    isLoading: false,\n    // @ts-expect-error (non strict)\n    errorItemId: null,\n    searchResults: [\n      {\n        exportedComponents: [],\n        storyFileExists: false,\n        filepath: 'src/no-exports-module.js',\n      },\n      {\n        storyFileExists: false,\n        exportedComponents: [\n          {\n            default: true,\n            name: 'default',\n          },\n          {\n            default: false,\n            name: 'namedExport',\n          },\n        ],\n        filepath: 'src/module-multiple-exports.js',\n      },\n      {\n        storyFileExists: false,\n        exportedComponents: null,\n        filepath: 'src/no-exports-module-1.js',\n      },\n      {\n        storyFileExists: false,\n        exportedComponents: [\n          {\n            default: true,\n            name: 'default',\n          },\n        ],\n        filepath: 'src/module-single-export.js',\n      },\n      {\n        storyFileExists: true,\n        exportedComponents: [\n          {\n            default: true,\n            name: 'default',\n          },\n          {\n            default: false,\n            name: 'namedExportWithStory',\n          },\n        ],\n        filepath: 'src/has-story-file-with-multiple-exports.js',\n      },\n      {\n        storyFileExists: true,\n        exportedComponents: [\n          {\n            default: true,\n            name: 'default',\n          },\n        ],\n        filepath: 'src/has-story-file.js',\n      },\n    ],\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/FileSearchList.tsx",
    "content": "import React, { memo, useCallback, useMemo, useState } from 'react';\n\nimport { TooltipNote, TooltipProvider } from 'storybook/internal/components';\nimport type {\n  CreateNewStoryRequestPayload,\n  FileComponentSearchResponsePayload,\n} from 'storybook/internal/core-events';\n\nimport {\n  BookmarkHollowIcon,\n  ChevronSmallDownIcon,\n  ChevronSmallRightIcon,\n  ComponentIcon,\n} from '@storybook/icons';\n\nimport type { VirtualItem } from '@tanstack/react-virtual';\nimport { useVirtualizer } from '@tanstack/react-virtual';\nimport { styled } from 'storybook/theming';\n\nimport { useArrowKeyNavigation } from './FIleSearchList.utils.tsx';\nimport {\n  DefaultExport,\n  FileList,\n  FileListExport,\n  FileListIconWrapper,\n  FileListItem,\n  FileListItemContent,\n  FileListItemContentWrapper,\n  FileListItemExport,\n  FileListItemExportName,\n  FileListItemExportNameContent,\n  FileListItemExportNameContentWithExport,\n  FileListItemLabel,\n  FileListItemPath,\n  FileListLi,\n  FileListUl,\n  FileListWrapper,\n  NoResults,\n  NoResultsDescription,\n} from './FileList.tsx';\nimport { FileSearchListLoadingSkeleton } from './FileSearchListSkeleton.tsx';\n\nexport type SearchResult = NonNullable<FileComponentSearchResponsePayload['files']>[0];\n\nexport interface NewStoryPayload extends CreateNewStoryRequestPayload {\n  selectedItemId: string | number;\n}\n\nconst TreeExpandIconStyled = styled(ChevronSmallRightIcon)(({ theme }) => ({\n  color: theme.textMutedColor,\n  marginTop: 2,\n}));\n\nconst TreeCollapseIconStyled = styled(ChevronSmallDownIcon)(({ theme }) => ({\n  color: theme.textMutedColor,\n  marginTop: 2,\n}));\n\ninterface FileSearchListProps {\n  isLoading: boolean;\n  searchResults: Array<SearchResult> | null;\n  onNewStory: (props: NewStoryPayload) => void;\n  errorItemId?: number | string;\n}\n\ninterface FileItemContentProps {\n  virtualItem: VirtualItem;\n  selected: number | null;\n  searchResult: SearchResult;\n}\n\ninterface FileItemSelectionPayload {\n  virtualItem: VirtualItem;\n  searchResult: SearchResult;\n  itemId: string;\n}\n\ninterface FileItemComponentSelectionPayload {\n  searchResult: SearchResult;\n  component: NonNullable<SearchResult['exportedComponents']>[0];\n  id: string;\n}\n\nexport const FileSearchList = memo(function FileSearchList({\n  isLoading,\n  searchResults,\n  onNewStory,\n  errorItemId,\n}: FileSearchListProps) {\n  const [selectedItem, setSelectedItem] = useState<number | null>(null);\n  const parentRef = React.useRef<HTMLDivElement>();\n\n  const sortedSearchResults = useMemo(() => {\n    // search results with no exports should be at the end of the list\n    return [...(searchResults ?? [])]?.sort((a, b) => {\n      const isALowPriority = a.exportedComponents === null || a.exportedComponents?.length === 0;\n      const hasAStory = a.storyFileExists;\n\n      const isBLowPriority = b.exportedComponents === null || b.exportedComponents?.length === 0;\n      const hasBStory = b.storyFileExists;\n\n      if (hasAStory && !hasBStory) {\n        return -1;\n      }\n\n      if (hasBStory && !hasAStory) {\n        return 1;\n      }\n\n      if (isALowPriority && !isBLowPriority) {\n        return 1;\n      }\n\n      if (!isALowPriority && isBLowPriority) {\n        return -1;\n      }\n\n      return 0;\n    });\n  }, [searchResults]);\n\n  const count = searchResults?.length || 0;\n\n  const rowVirtualizer = useVirtualizer({\n    count,\n    // @ts-expect-error (non strict)\n\n    getScrollElement: () => parentRef.current,\n    paddingStart: 16,\n    paddingEnd: 40,\n    estimateSize: () => 54,\n    overscan: 2,\n  });\n\n  // @ts-expect-error (non strict)\n  useArrowKeyNavigation({ rowVirtualizer, parentRef, selectedItem });\n\n  const handleFileItemSelection = useCallback(\n    ({ virtualItem, searchResult, itemId }: FileItemSelectionPayload) => {\n      // @ts-expect-error (non strict)\n      if (searchResult?.exportedComponents?.length > 1) {\n        setSelectedItem((sItem) => {\n          if (sItem === virtualItem.index) {\n            return null;\n          }\n\n          return virtualItem.index;\n        });\n      } else if (searchResult?.exportedComponents?.length === 1) {\n        onNewStory({\n          componentExportName: searchResult.exportedComponents[0].name,\n          componentFilePath: searchResult.filepath,\n          componentIsDefaultExport: searchResult.exportedComponents[0].default,\n          selectedItemId: itemId,\n          componentExportCount: 1,\n        });\n      }\n    },\n    [onNewStory]\n  );\n\n  const handleFileItemComponentSelection = useCallback(\n    ({ searchResult, component, id }: FileItemComponentSelectionPayload) => {\n      onNewStory({\n        componentExportName: component.name,\n        componentFilePath: searchResult.filepath,\n        componentIsDefaultExport: component.default,\n        selectedItemId: id,\n        // @ts-expect-error (non strict)\n        componentExportCount: searchResult.exportedComponents.length,\n      });\n    },\n    [onNewStory]\n  );\n\n  const ListItem = useCallback(\n    ({\n      virtualItem,\n      selected,\n      searchResult,\n      noExports,\n    }: FileItemContentProps & { noExports: boolean }) => {\n      const itemError = errorItemId === searchResult.filepath;\n      const itemSelected = selected === virtualItem.index;\n      const tooltip = noExports\n        ? \"We can't evaluate exports for this file. Automatic story creation is disabled.\"\n        : undefined;\n\n      return (\n        <FileListItem\n          aria-expanded={itemSelected}\n          aria-controls={`file-list-export-${virtualItem.index}`}\n          id={`file-list-item-wrapper-${virtualItem.index}`}\n        >\n          <TooltipProvider\n            tooltip={tooltip ? <TooltipNote note={tooltip} /> : undefined}\n            placement=\"top-start\"\n            delayHide={100}\n            delayShow={200}\n          >\n            <FileListItemContentWrapper\n              className=\"file-list-item\"\n              selected={itemSelected}\n              error={itemError}\n              disabled={noExports}\n            >\n              {itemSelected ? (\n                <TreeCollapseIconStyled size={14} />\n              ) : (\n                <TreeExpandIconStyled size={14} />\n              )}\n              <FileListIconWrapper error={itemError}>\n                <ComponentIcon />\n              </FileListIconWrapper>\n              <FileListItemContent>\n                <FileListItemLabel error={itemError}>\n                  {searchResult.filepath.split('/').at(-1)}\n                </FileListItemLabel>\n                <FileListItemPath>{searchResult.filepath}</FileListItemPath>\n              </FileListItemContent>\n            </FileListItemContentWrapper>\n          </TooltipProvider>\n          {/* @ts-expect-error (non strict) */}\n          {searchResult?.exportedComponents?.length > 1 && itemSelected && (\n            <FileListExport\n              role=\"region\"\n              id={`file-list-export-${virtualItem.index}`}\n              aria-labelledby={`file-list-item-wrapper-${virtualItem.index}`}\n              onClick={(e) => {\n                e.stopPropagation();\n              }}\n              onKeyUp={(e) => {\n                if (e.key === 'Enter') {\n                  e.stopPropagation();\n                }\n              }}\n            >\n              {searchResult.exportedComponents?.map((component, itemExportId) => {\n                const itemExportError = errorItemId === `${searchResult.filepath}_${itemExportId}`;\n                const position =\n                  itemExportId === 0\n                    ? 'first'\n                    : // @ts-expect-error (non strict)\n                      itemExportId === searchResult.exportedComponents.length - 1\n                      ? 'last'\n                      : 'middle';\n\n                return (\n                  <FileListItemExport\n                    tabIndex={0}\n                    data-index-position={`${virtualItem.index}_${position}`}\n                    key={component.name}\n                    error={itemExportError}\n                    onClick={() => {\n                      handleFileItemComponentSelection({\n                        searchResult,\n                        component,\n                        id: `${searchResult.filepath}_${itemExportId}`,\n                      });\n                    }}\n                    onKeyUp={(event) => {\n                      if (event.key === 'Enter') {\n                        handleFileItemComponentSelection({\n                          searchResult,\n                          component,\n                          id: `${searchResult.filepath}_${itemExportId}`,\n                        });\n                      }\n                    }}\n                  >\n                    <FileListItemExportName>\n                      <BookmarkHollowIcon />\n                      {component.default ? (\n                        <>\n                          <FileListItemExportNameContentWithExport>\n                            {searchResult.filepath.split('/').at(-1)?.split('.')?.at(0)}\n                          </FileListItemExportNameContentWithExport>\n                          <DefaultExport>Default export</DefaultExport>\n                        </>\n                      ) : (\n                        <FileListItemExportNameContent>\n                          {component.name}\n                        </FileListItemExportNameContent>\n                      )}\n                    </FileListItemExportName>\n                  </FileListItemExport>\n                );\n              })}\n            </FileListExport>\n          )}\n        </FileListItem>\n      );\n    },\n    [handleFileItemComponentSelection, errorItemId]\n  );\n\n  if (isLoading && (searchResults === null || searchResults?.length === 0)) {\n    return <FileSearchListLoadingSkeleton />;\n  }\n\n  if (searchResults?.length === 0) {\n    return (\n      <NoResults>\n        <p>We could not find any file with that name</p>\n        <NoResultsDescription>\n          You may want to try using different keywords, check for typos, and adjust your filters\n        </NoResultsDescription>\n      </NoResults>\n    );\n  }\n\n  if (sortedSearchResults?.length > 0) {\n    return (\n      <FileListWrapper>\n        {/* @ts-expect-error (non strict) */}\n        <FileList ref={parentRef}>\n          <FileListUl\n            style={{\n              height: `${rowVirtualizer.getTotalSize()}px`,\n            }}\n          >\n            {rowVirtualizer.getVirtualItems().map((virtualItem) => {\n              const searchResult = sortedSearchResults[virtualItem.index];\n              const noExports =\n                searchResult.exportedComponents === null ||\n                searchResult.exportedComponents?.length === 0;\n\n              const itemProps = {};\n\n              return (\n                <FileListLi\n                  key={virtualItem.key}\n                  data-index={virtualItem.index}\n                  ref={rowVirtualizer.measureElement}\n                  onClick={() => {\n                    handleFileItemSelection({\n                      virtualItem,\n                      itemId: searchResult.filepath,\n                      searchResult,\n                    });\n                  }}\n                  onKeyUp={(event) => {\n                    if (event.key === 'Enter') {\n                      handleFileItemSelection({\n                        virtualItem,\n                        itemId: searchResult.filepath,\n                        searchResult,\n                      });\n                    }\n                  }}\n                  style={{\n                    position: 'absolute',\n                    top: 0,\n                    left: 0,\n                    width: '100%',\n                    transform: `translateY(${virtualItem.start}px)`,\n                  }}\n                  tabIndex={0}\n                >\n                  <ListItem\n                    {...itemProps}\n                    key={virtualItem.index}\n                    searchResult={searchResult}\n                    selected={selectedItem}\n                    virtualItem={virtualItem}\n                    noExports={noExports}\n                  />\n                </FileListLi>\n              );\n            })}\n          </FileListUl>\n        </FileList>\n      </FileListWrapper>\n    );\n  }\n\n  return null;\n});\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/FileSearchListSkeleton.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { FileSearchListLoadingSkeleton } from './FileSearchListSkeleton.tsx';\n\nconst meta = {\n  component: FileSearchListLoadingSkeleton,\n  title: 'Sidebar/FileSearchListLoadingSkeleton',\n} satisfies Meta<typeof FileSearchListLoadingSkeleton>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {\n  args: {},\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/FileSearchListSkeleton.tsx",
    "content": "import React from 'react';\n\nimport { styled } from 'storybook/theming';\n\nimport { FileList, FileListItem } from './FileList.tsx';\n\nconst FileListItemContentWrapperSkeleton = styled('div')(({ theme }) => ({\n  display: 'flex',\n  alignItems: 'flex-start',\n  gap: '8px',\n  alignSelf: 'stretch',\n  padding: '8px 16px',\n}));\n\nconst FileListItemContentSkeleton = styled('div')({\n  display: 'flex',\n  flexDirection: 'column',\n  alignItems: 'flex-start',\n  width: '100%',\n  borderRadius: '3px',\n});\n\nconst FileListIconWrapperSkeleton = styled.div(({ theme }) => ({\n  width: '14px',\n  height: '14px',\n  borderRadius: '3px',\n  marginTop: '1px',\n  background: theme.base === 'dark' ? 'rgba(255,255,255,.1)' : 'rgba(0,0,0,.1)',\n  animation: `${theme.animation.glow} 1.5s ease-in-out infinite`,\n}));\n\nconst FileListItemSkeleton = styled.div(({ theme }) => ({\n  height: '16px',\n  borderRadius: '3px',\n  background: theme.base === 'dark' ? 'rgba(255,255,255,.1)' : 'rgba(0,0,0,.1)',\n  animation: `${theme.animation.glow} 1.5s ease-in-out infinite`,\n  width: '100%',\n  maxWidth: '100%',\n\n  '+ div': {\n    marginTop: '6px',\n  },\n}));\n\nexport const FileSearchListLoadingSkeleton = () => {\n  return (\n    <FileList>\n      {[1, 2, 3].map((result) => (\n        <FileListItem key={result}>\n          <FileListItemContentWrapperSkeleton>\n            <FileListIconWrapperSkeleton />\n            <FileListItemContentSkeleton>\n              <FileListItemSkeleton style={{ width: '90px' }} />\n              <FileListItemSkeleton style={{ width: '300px' }} />\n            </FileListItemContentSkeleton>\n          </FileListItemContentWrapperSkeleton>\n        </FileListItem>\n      ))}\n    </FileList>\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/FileSearchModal.stories.tsx",
    "content": "import React from 'react';\n\nimport { ModalDecorator } from 'storybook/internal/components';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { expect, fireEvent, fn, within } from 'storybook/test';\n\nimport { WithResults } from './FileSearchList.stories.tsx';\nimport { FileSearchModal } from './FileSearchModal.tsx';\n\nconst meta = {\n  component: FileSearchModal,\n  title: 'Sidebar/FileSearchModal',\n  args: {\n    open: true,\n    setError: fn(),\n    onCreateNewStory: fn(),\n    onOpenChange: fn(),\n    setFileSearchQuery: fn(),\n  },\n  parameters: {\n    layout: 'fullscreen',\n  },\n  decorators: [ModalDecorator],\n  globals: {\n    sb_theme: 'dark',\n  },\n} satisfies Meta<typeof FileSearchModal>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const InitialState: Story = {\n  args: {\n    fileSearchQuery: '',\n    fileSearchQueryDeferred: '',\n    isLoading: false,\n    error: null,\n    searchResults: null,\n  },\n};\nexport const InitialStateLight = Object.assign({}, InitialState, {\n  globals: { sb_theme: 'light' },\n});\n\nexport const Loading: Story = {\n  args: {\n    fileSearchQuery: 'src',\n    fileSearchQueryDeferred: 'src',\n    isLoading: true,\n    error: null,\n    searchResults: null,\n  },\n};\nexport const LoadingLight = Object.assign({}, Loading, { globals: { sb_theme: 'light' } });\n\nexport const LoadingWithPreviousResults: Story = {\n  args: {\n    fileSearchQuery: 'src',\n    fileSearchQueryDeferred: 'src',\n    isLoading: true,\n    error: null,\n    searchResults: WithResults.args.searchResults,\n  },\n};\nexport const LoadingWithPreviousResultsLight = Object.assign({}, LoadingWithPreviousResults, {\n  globals: { sb_theme: 'light' },\n});\n\nexport const Empty: Story = {\n  args: {\n    fileSearchQuery: 'src',\n    fileSearchQueryDeferred: 'src',\n    isLoading: false,\n    error: null,\n    searchResults: [],\n  },\n};\nexport const EmptyLight = Object.assign({}, Empty, { globals: { sb_theme: 'light' } });\n\nexport const WithSearchResults: Story = {\n  args: {\n    fileSearchQuery: 'src',\n    fileSearchQueryDeferred: 'src',\n    isLoading: false,\n    error: null,\n    searchResults: WithResults.args.searchResults,\n  },\n  play: async ({ canvasElement, args }) => {\n    const parent = within(canvasElement.parentNode as HTMLElement);\n\n    const moduleSingleExport = await parent.findByText(\n      'module-single-export.js',\n      {},\n      { timeout: 3000 }\n    );\n    await fireEvent.click(moduleSingleExport);\n\n    await expect(args.onCreateNewStory).toHaveBeenCalledWith({\n      componentExportCount: 1,\n      componentExportName: 'default',\n      componentFilePath: 'src/module-single-export.js',\n      componentIsDefaultExport: true,\n      selectedItemId: 'src/module-single-export.js',\n    });\n  },\n};\nexport const WithSearchResultsLight = Object.assign({}, WithSearchResults, {\n  globals: { sb_theme: 'light' },\n});\n\nexport const WithSearchResultsAndError: Story = {\n  args: {\n    fileSearchQuery: 'src',\n    fileSearchQueryDeferred: 'src',\n    isLoading: false,\n    error: { error: 'Some error occurred', selectedItemId: 'src/module-multiple-exports.js' },\n    searchResults: WithResults.args.searchResults,\n  },\n};\nexport const WithSearchResultsAndErrorLight = Object.assign({}, WithSearchResultsAndError, {\n  globals: { sb_theme: 'light' },\n});\n\nexport const WithSearchResultsAndMultiLineError: Story = {\n  args: {\n    fileSearchQuery: 'src',\n    fileSearchQueryDeferred: 'src',\n    isLoading: false,\n    error: {\n      error: 'A very long error occurred. A very long error occurred. A very long error occurred.',\n      selectedItemId: 'src/module-multiple-exports.js',\n    },\n    searchResults: WithResults.args.searchResults,\n  },\n};\nexport const WithSearchResultsAndMultiLineErrorLight = Object.assign(\n  {},\n  WithSearchResultsAndMultiLineError,\n  { globals: { sb_theme: 'light' } }\n);\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/FileSearchModal.tsx",
    "content": "import React, { useEffect, useState, useTransition } from 'react';\n\nimport { Form, Modal } from 'storybook/internal/components';\n\nimport { CloseAltIcon, SearchIcon, SyncIcon } from '@storybook/icons';\n\nimport { styled } from 'storybook/theming';\n\nimport { useMeasure } from '../../hooks/useMeasure.tsx';\nimport type { NewStoryPayload, SearchResult } from './FileSearchList.tsx';\nimport { FileSearchList } from './FileSearchList.tsx';\n\nconst MODAL_HEIGHT = 418;\n\nconst ModalStyled = styled(Modal)(() => ({\n  boxShadow: 'none',\n  background: 'transparent',\n  overflow: 'visible',\n}));\n\nconst ModalChild = styled.div<{ height?: number }>(({ theme, height }) => ({\n  backgroundColor: theme.background.bar,\n  borderRadius: 6,\n  boxShadow: `rgba(255, 255, 255, 0.05) 0 0 0 1px inset, rgba(14, 18, 22, 0.35) 0px 10px 18px -10px`,\n  padding: '16px',\n  transition: 'height 0.3s',\n  height: height ? `${height + 32}px` : 'auto',\n  overflow: 'hidden',\n}));\n\nconst ModalContent = styled(Modal.Content)(({ theme }) => ({\n  margin: 0,\n  color: theme.color.defaultText,\n}));\n\nconst ModalInput = styled(Form.Input)(({ theme }) => ({\n  paddingLeft: 40,\n  paddingRight: 28,\n  fontSize: 14,\n  height: 40,\n\n  ...(theme.base === 'light' && {\n    color: theme.color.darkest,\n  }),\n\n  '::placeholder': {\n    color: theme.color.mediumdark,\n  },\n  '&:invalid:not(:placeholder-shown)': {\n    boxShadow: `${theme.color.negative} 0 0 0 1px inset`,\n  },\n  '&::-webkit-search-decoration, &::-webkit-search-cancel-button, &::-webkit-search-results-button, &::-webkit-search-results-decoration':\n    {\n      display: 'none',\n    },\n}));\n\nconst SearchField = styled.div({\n  display: 'flex',\n  flexDirection: 'column',\n  flexGrow: 1,\n  position: 'relative',\n});\n\nconst SearchIconWrapper = styled.div(({ theme }) => ({\n  position: 'absolute',\n  top: 0,\n  left: 16,\n  zIndex: 1,\n  pointerEvents: 'none',\n  color: theme.darkest,\n  display: 'flex',\n  alignItems: 'center',\n  height: '100%',\n}));\n\nconst LoadingIcon = styled.div(({ theme }) => ({\n  position: 'absolute',\n  top: 0,\n  right: 16,\n  zIndex: 1,\n  color: theme.darkest,\n  display: 'flex',\n  alignItems: 'center',\n  height: '100%',\n  '@keyframes spin': {\n    from: { transform: 'rotate(0deg)' },\n    to: { transform: 'rotate(360deg)' },\n  },\n  animation: 'spin 1s linear infinite',\n}));\n\nconst ModalError = styled(Modal.Error)({\n  position: 'absolute',\n  padding: '8px 40px 8px 16px',\n  bottom: 0,\n  maxHeight: 'initial',\n  width: '100%',\n\n  div: {\n    wordBreak: 'break-word',\n  },\n\n  '> div': {\n    padding: 0,\n  },\n});\n\nconst ModalErrorCloseIcon = styled(CloseAltIcon)({\n  position: 'absolute',\n  top: 4,\n  right: -24,\n  cursor: 'pointer',\n});\n\ntype Error = { selectedItemId?: number | string; error: string } | null;\n\ninterface FileSearchModalProps {\n  open: boolean;\n  onOpenChange: (open: boolean) => void;\n  fileSearchQuery: string;\n  fileSearchQueryDeferred: string;\n  setFileSearchQuery: (query: string) => void;\n  isLoading: boolean;\n  error: Error;\n  searchResults: SearchResult[] | null;\n  onCreateNewStory: (payload: NewStoryPayload) => void;\n  setError: (error: Error) => void;\n}\n\nexport const FileSearchModal = ({\n  open,\n  onOpenChange,\n  fileSearchQuery,\n  setFileSearchQuery,\n  isLoading,\n  error,\n  searchResults,\n  onCreateNewStory,\n  setError,\n}: FileSearchModalProps) => {\n  const [modalContentRef, modalContentDimensions] = useMeasure<HTMLDivElement>();\n  // @ts-expect-error (non strict)\n  const [modalMaxHeight, setModalMaxHeight] = useState<number>(modalContentDimensions.height);\n  const [, startTransition] = useTransition();\n  // This internal state is used to maintain cursor position when the user types in the search input\n  // See: https://github.com/facebook/react/issues/5386#issuecomment-334001976\n  const [searchInputValue, setSearchInputValue] = useState<string>(fileSearchQuery);\n\n  useEffect(() => {\n    // @ts-expect-error (non strict)\n    if (modalMaxHeight < modalContentDimensions.height) {\n      // @ts-expect-error (non strict)\n      setModalMaxHeight(modalContentDimensions.height);\n    }\n  }, [modalContentDimensions.height, modalMaxHeight]);\n\n  return (\n    <ModalStyled\n      ariaLabel=\"Add a new story\"\n      height={MODAL_HEIGHT}\n      width={440}\n      open={open}\n      onOpenChange={onOpenChange}\n    >\n      {/* @ts-expect-error (non strict) */}\n      <ModalChild height={fileSearchQuery === '' ? modalContentDimensions.height : modalMaxHeight}>\n        <ModalContent ref={modalContentRef}>\n          <Modal.Header>\n            <Modal.Title>Add a new story</Modal.Title>\n            <Modal.Description>We will create a new story for your component</Modal.Description>\n          </Modal.Header>\n          <SearchField>\n            <SearchIconWrapper>\n              <SearchIcon />\n            </SearchIconWrapper>\n            <ModalInput\n              placeholder=\"./components/**/*.tsx\"\n              type=\"search\"\n              required\n              autoFocus\n              value={searchInputValue}\n              onChange={(e) => {\n                const newValue = (e.target as HTMLInputElement).value;\n                setSearchInputValue(newValue);\n                startTransition(() => {\n                  setFileSearchQuery(newValue);\n                });\n              }}\n            />\n            {isLoading && (\n              <LoadingIcon>\n                <SyncIcon />\n              </LoadingIcon>\n            )}\n          </SearchField>\n          {\n            <FileSearchList\n              errorItemId={error?.selectedItemId}\n              isLoading={isLoading}\n              searchResults={searchResults}\n              onNewStory={onCreateNewStory}\n            />\n          }\n        </ModalContent>\n      </ModalChild>\n      {error && fileSearchQuery !== '' && (\n        <ModalError>\n          <div>{error.error}</div>\n          <ModalErrorCloseIcon\n            onClick={() => {\n              setError(null);\n            }}\n          />\n        </ModalError>\n      )}\n    </ModalStyled>\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/FileSearchModal.utils.test.tsx",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport type { ArgTypes } from 'storybook/internal/csf';\n\nimport { extractSeededRequiredArgs } from './FileSearchModal.utils.tsx';\n\ndescribe('FileSearchModal.utils', () => {\n  describe('extractSeededRequiredArgs', () => {\n    it('should extract seeded required args', () => {\n      const argTypes = {\n        string: {\n          type: { name: 'string', required: true },\n        },\n        stringOptional: {\n          type: { name: 'string', required: false },\n        },\n        number: {\n          type: { name: 'number', required: true },\n        },\n        boolean: {\n          type: { name: 'boolean', required: true },\n        },\n        function: {\n          type: { name: 'function', required: true },\n        },\n        object: {\n          type: {\n            name: 'object',\n            required: true,\n            value: {\n              a: { name: 'string', required: true },\n              b: { name: 'number' },\n            },\n          },\n        },\n        union: {\n          type: {\n            name: 'union',\n            required: true,\n            value: [{ name: 'string', required: true }, { name: 'number' }],\n          },\n        },\n        enum: {\n          type: {\n            name: 'enum',\n            required: true,\n            value: ['a', 'b', 'c'],\n          },\n          options: ['a', 'b', 'c'],\n        },\n        otherObject: {\n          type: { name: 'other', required: true, value: '' },\n          control: { type: 'object' },\n        },\n        otherInlineRadio: {\n          type: { name: 'other', required: true, value: '' },\n          control: { type: 'inline-radio', options: ['a', 'b', 'c'] },\n        },\n        otherRadio: {\n          type: { name: 'other', required: true, value: '' },\n          control: { type: 'radio', options: ['d', 'e', 'f'] },\n        },\n        otherInlineCheck: {\n          type: { name: 'other', required: true, value: '' },\n          control: { type: 'inline-check', options: ['g', 'h', 'i'] },\n        },\n        otherCheck: {\n          type: { name: 'other', required: true, value: '' },\n          control: { type: 'check', options: ['j', 'k', 'l'] },\n        },\n        otherSelect: {\n          type: { name: 'other', required: true, value: '' },\n          control: { type: 'select', options: ['m', 'n', 'o'] },\n        },\n        otherMultiSelect: {\n          type: { name: 'other', required: true, value: '' },\n          control: { type: 'multi-select', options: ['p', 'q', 'r'] },\n        },\n        otherColor: {\n          type: { name: 'other', required: true, value: '' },\n          control: { type: 'color' },\n        },\n        intersection: {\n          type: {\n            name: 'intersection',\n            required: true,\n            value: [\n              {\n                name: 'object',\n                value: {\n                  a: { name: 'string', required: true },\n                  b: { name: 'number' },\n                },\n              },\n            ],\n          },\n        },\n        tuple: {\n          type: {\n            name: 'other',\n            required: true,\n            value: 'tuple',\n          },\n        },\n      } as ArgTypes;\n\n      expect(extractSeededRequiredArgs(argTypes)).toEqual({\n        boolean: true,\n        function: expect.any(Function),\n        number: 0,\n        enum: 'a',\n        otherCheck: 'j',\n        otherColor: '#000000',\n        otherInlineCheck: 'g',\n        otherInlineRadio: 'a',\n        otherMultiSelect: 'p',\n        otherObject: {},\n        otherRadio: 'd',\n        otherSelect: 'm',\n        string: 'string',\n        object: { a: 'a' },\n        union: 'union',\n        intersection: { a: 'a' },\n        tuple: [],\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/FileSearchModal.utils.tsx",
    "content": "import type { ArgTypes, SBType } from 'storybook/internal/csf';\n\nexport { trySelectStory as trySelectNewStory } from '../../utils/trySelectStory.ts';\n\nexport function extractSeededRequiredArgs(argTypes: ArgTypes) {\n  const extractedArgTypes = Object.keys(argTypes).reduce(\n    (acc, key: keyof typeof argTypes) => {\n      const argType = argTypes[key];\n\n      if (typeof argType.control === 'object' && 'type' in argType.control) {\n        switch (argType.control.type) {\n          case 'object':\n            acc[key] = {};\n            break;\n          case 'inline-radio':\n          case 'radio':\n          case 'inline-check':\n          case 'check':\n          case 'select':\n          case 'multi-select':\n            acc[key] = argType.control.options?.[0];\n            break;\n          case 'color':\n            acc[key] = '#000000';\n            break;\n          default:\n            break;\n        }\n      }\n\n      // @ts-expect-error (non strict)\n      setArgType(argType.type, acc, key);\n      return acc;\n    },\n    {} as Record<string, any>\n  );\n  return extractedArgTypes;\n}\n\nfunction setArgType(\n  type: 'string' | 'number' | 'boolean' | 'symbol' | 'function' | SBType,\n  obj: Record<string, any>,\n  objKey: string | number\n) {\n  if (typeof type === 'string' || !type.required) {\n    return;\n  }\n\n  switch (type.name) {\n    case 'boolean':\n      obj[objKey] = true;\n      break;\n    case 'number':\n      obj[objKey] = 0;\n      break;\n    case 'string':\n      obj[objKey] = objKey;\n      break;\n    case 'array':\n      obj[objKey] = [];\n      break;\n    case 'object':\n      obj[objKey] = {};\n      Object.entries(type.value ?? {}).forEach(([typeKey, typeVal]) => {\n        setArgType(typeVal, obj[objKey], typeKey);\n      });\n      break;\n    case 'function':\n      obj[objKey] = () => {};\n      break;\n    case 'intersection':\n      if (type.value?.every((v) => v.name === 'object')) {\n        obj[objKey] = {};\n        type.value?.forEach((typeVal) => {\n          if (typeVal.name === 'object') {\n            Object.entries(typeVal.value ?? {}).forEach(([typeValKey, typeValVal]) => {\n              setArgType(typeValVal, obj[objKey], typeValKey);\n            });\n          }\n        });\n      }\n      break;\n    case 'union':\n      if (type.value?.[0] !== undefined) {\n        setArgType(type.value[0], obj, objKey);\n      }\n      break;\n\n    case 'enum':\n      if (type.value?.[0] !== undefined) {\n        obj[objKey] = type.value?.[0];\n      }\n      break;\n\n    case 'other':\n      if (typeof type.value === 'string' && type.value === 'tuple') {\n        obj[objKey] = [];\n      }\n      break;\n    default:\n      break;\n  }\n}\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/Filter.stories.tsx",
    "content": "import React, { useMemo, useState } from 'react';\n\nimport type { DocsIndexEntry, StoryIndex, StoryIndexEntry } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { ManagerContext } from 'storybook/manager-api';\nimport { expect, screen, waitFor } from 'storybook/test';\n\nimport { internal_fullStatusStore } from '../../manager-stores.mock.ts';\n\nimport { Filter } from './Filter.tsx';\n\nconst getDefaultTagFilters = () => {\n  const tagOptions = global.TAGS_OPTIONS ?? {};\n\n  return Object.entries(tagOptions).reduce(\n    (acc, [tag, option]) => {\n      if (option.defaultFilterSelection === 'include') {\n        acc.included.push(tag);\n      }\n      if (option.defaultFilterSelection === 'exclude') {\n        acc.excluded.push(tag);\n      }\n      return acc;\n    },\n    { included: [] as string[], excluded: [] as string[] }\n  );\n};\n\nconst createInitialState = (initialStoryState: Record<string, unknown> = {}) => {\n  const defaults = getDefaultTagFilters();\n\n  const defaultIncludedTagFilters =\n    (initialStoryState.defaultIncludedTagFilters as string[] | undefined) ?? defaults.included;\n  const defaultExcludedTagFilters =\n    (initialStoryState.defaultExcludedTagFilters as string[] | undefined) ?? defaults.excluded;\n\n  return {\n    ...initialStoryState,\n    defaultIncludedTagFilters,\n    defaultExcludedTagFilters,\n    includedTagFilters:\n      (initialStoryState.includedTagFilters as string[] | undefined) ?? defaultIncludedTagFilters,\n    excludedTagFilters:\n      (initialStoryState.excludedTagFilters as string[] | undefined) ?? defaultExcludedTagFilters,\n  };\n};\n\nconst meta = {\n  component: Filter,\n  title: 'Sidebar/Filter',\n  tags: ['haha', 'this-is-a-very-long-tag-that-will-be-truncated-after-a-while'],\n  decorators: [\n    (Story, { args, parameters }) => {\n      const [state, setState] = useState(() =>\n        createInitialState(parameters?.initialStoryState as Record<string, unknown> | undefined)\n      );\n\n      const api = useMemo(\n        () => ({\n          addTagFilters: (tags: string[], excluded: boolean) => {\n            setState((current: any) => {\n              const includedTagFilters = new Set(current.includedTagFilters ?? []);\n              const excludedTagFilters = new Set(current.excludedTagFilters ?? []);\n\n              tags.forEach((tag) => {\n                if (excluded) {\n                  includedTagFilters.delete(tag);\n                  excludedTagFilters.add(tag);\n                } else {\n                  includedTagFilters.add(tag);\n                  excludedTagFilters.delete(tag);\n                }\n              });\n\n              return {\n                ...current,\n                includedTagFilters: Array.from(includedTagFilters),\n                excludedTagFilters: Array.from(excludedTagFilters),\n              };\n            });\n          },\n          removeTagFilters: (tags: string[]) => {\n            setState((current: any) => ({\n              ...current,\n              includedTagFilters: (current.includedTagFilters ?? []).filter(\n                (tag: string) => !tags.includes(tag)\n              ),\n              excludedTagFilters: (current.excludedTagFilters ?? []).filter(\n                (tag: string) => !tags.includes(tag)\n              ),\n            }));\n          },\n          resetTagFilters: () => {\n            setState((current: any) => ({\n              ...current,\n              includedTagFilters: current.defaultIncludedTagFilters ?? [],\n              excludedTagFilters: current.defaultExcludedTagFilters ?? [],\n            }));\n          },\n          setAllTagFilters: (included: string[], excluded: string[]) => {\n            setState((current: any) => ({\n              ...current,\n              includedTagFilters: included,\n              excludedTagFilters: excluded,\n            }));\n          },\n          addStatusFilters: (statuses: string[], excluded: boolean) => {\n            setState((current: any) => {\n              const includedStatusFilters = new Set(current.includedStatusFilters ?? []);\n              const excludedStatusFilters = new Set(current.excludedStatusFilters ?? []);\n\n              statuses.forEach((status) => {\n                if (excluded) {\n                  includedStatusFilters.delete(status);\n                  excludedStatusFilters.add(status);\n                } else {\n                  includedStatusFilters.add(status);\n                  excludedStatusFilters.delete(status);\n                }\n              });\n\n              return {\n                ...current,\n                includedStatusFilters: Array.from(includedStatusFilters),\n                excludedStatusFilters: Array.from(excludedStatusFilters),\n              };\n            });\n          },\n          removeStatusFilters: (statuses: string[]) => {\n            setState((current: any) => ({\n              ...current,\n              includedStatusFilters: (current.includedStatusFilters ?? []).filter(\n                (s: string) => !statuses.includes(s)\n              ),\n              excludedStatusFilters: (current.excludedStatusFilters ?? []).filter(\n                (s: string) => !statuses.includes(s)\n              ),\n            }));\n          },\n          resetStatusFilters: () => {\n            setState((current: any) => ({\n              ...current,\n              includedStatusFilters: [],\n              excludedStatusFilters: [],\n            }));\n          },\n          getDocsUrl: ({ subpath }: { subpath: string }) =>\n            `https://storybook.js.org/docs/${subpath}`,\n        }),\n        []\n      );\n\n      return (\n        <ManagerContext.Provider value={{ api, state } as any}>\n          <Story args={{ ...args, api }} />\n        </ManagerContext.Provider>\n      );\n    },\n  ],\n} satisfies Meta<typeof Filter>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Closed: Story = {\n  parameters: {\n    initialStoryState: {\n      internal_index: {\n        v: 6,\n        entries: {\n          'c1-s1': { tags: ['A', 'B', 'C', 'dev', 'play-fn'], type: 'story' } as StoryIndexEntry,\n          'c1-test': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n          'c1-doc': { tags: [], type: 'docs' } as unknown as DocsIndexEntry,\n        },\n      } as StoryIndex,\n    },\n  },\n};\n\nexport const ClosedWithDefaultTags: Story = {\n  ...Closed,\n  beforeEach: () => {\n    const originalTagsOptions = global.TAGS_OPTIONS;\n    global.TAGS_OPTIONS = {\n      A: { defaultFilterSelection: 'include' },\n      B: { defaultFilterSelection: 'include' },\n    };\n\n    return () => {\n      global.TAGS_OPTIONS = originalTagsOptions;\n    };\n  },\n};\n\nexport const ClosedWithSelection: Story = {\n  parameters: {\n    initialStoryState: {\n      internal_index: {\n        v: 6,\n        entries: {\n          'c1-s1': { tags: ['A', 'B', 'C', 'dev', 'play-fn'], type: 'story' } as StoryIndexEntry,\n          'c1-test': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n          'c1-doc': { tags: [], type: 'docs' } as unknown as DocsIndexEntry,\n        },\n      } as StoryIndex,\n      includedTagFilters: ['A', 'B'],\n    },\n  },\n};\n\nexport const Clear = {\n  ...ClosedWithSelection,\n  beforeEach: () => {\n    internal_fullStatusStore.set([\n      {\n        storyId: 'c1-s1',\n        typeId: 'change-detection',\n        value: 'status-value:new',\n        title: 'New',\n        description: '',\n      },\n      {\n        storyId: 'c1-test',\n        typeId: 'change-detection',\n        value: 'status-value:modified',\n        title: 'Modified',\n        description: '',\n      },\n      {\n        storyId: 'c1-doc',\n        typeId: 'change-detection',\n        value: 'status-value:affected',\n        title: 'Affected',\n        description: '',\n      },\n    ]);\n    return () => internal_fullStatusStore.unset();\n  },\n  play: async ({ canvas }) => {\n    const button = await canvas.findByRole('button', {}, { timeout: 3000 });\n    button.click();\n\n    const clearButton = await screen.findByRole('button', { name: 'Clear filters' });\n\n    expect(clearButton).toBeInTheDocument();\n    clearButton.click();\n    await waitFor(() => expect(clearButton).not.toBeInTheDocument());\n  },\n} satisfies Story;\n\nexport const ResetToDefaults: Story = {\n  ...ClosedWithDefaultTags,\n  parameters: {\n    initialStoryState: {\n      internal_index: {\n        v: 6,\n        entries: {\n          'c1-s1': { tags: ['A', 'B', 'C', 'dev', 'play-fn'], type: 'story' } as StoryIndexEntry,\n          'c1-test': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n          'c1-doc': { tags: [], type: 'docs' } as unknown as DocsIndexEntry,\n        },\n      } as StoryIndex,\n      excludedTagFilters: ['A', 'B', 'C'],\n    },\n  },\n  play: async ({ canvas }) => {\n    const button = await canvas.findByRole('button', {}, { timeout: 3000 });\n    button.click();\n\n    const resetButton = await screen.findByRole('button', { name: 'Reset filters' });\n\n    expect(resetButton).toBeInTheDocument();\n    expect(resetButton).not.toHaveAttribute('aria-disabled', 'true');\n    resetButton.click();\n    await waitFor(() => expect(resetButton).toHaveAttribute('aria-disabled', 'true'));\n  },\n} satisfies Story;\n\nexport const NoUserTags = {\n  parameters: {\n    initialStoryState: {\n      internal_index: {\n        v: 6,\n        entries: {\n          'c1-s1': { tags: ['dev', 'play-fn'], type: 'story' } as StoryIndexEntry,\n          'c1-test': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n          'c1-doc': { tags: [], type: 'docs' } as unknown as DocsIndexEntry,\n        },\n      } as StoryIndex,\n    },\n  },\n  beforeEach: () => {\n    internal_fullStatusStore.set([\n      {\n        storyId: 'c1-s1',\n        typeId: 'change-detection',\n        value: 'status-value:new',\n        title: 'New',\n        description: '',\n      },\n      {\n        storyId: 'c1-test',\n        typeId: 'change-detection',\n        value: 'status-value:modified',\n        title: 'Modified',\n        description: '',\n      },\n      {\n        storyId: 'c1-doc',\n        typeId: 'change-detection',\n        value: 'status-value:affected',\n        title: 'Affected',\n        description: '',\n      },\n    ]);\n    return () => internal_fullStatusStore.unset();\n  },\n  play: async ({ canvas }) => {\n    const button = await canvas.findByRole('button', {}, { timeout: 3000 });\n    button.click();\n\n    const learnLink = await screen.findByRole('link', { name: 'Learn how to add tags' });\n\n    expect(learnLink).toBeInTheDocument();\n  },\n} satisfies Story;\n\nexport const WithSelection = {\n  ...ClosedWithSelection,\n  play: async ({ canvas }) => {\n    const button = await canvas.findByRole('button', {}, { timeout: 3000 });\n    button.click();\n  },\n} satisfies Story;\n\nexport const WithSelectionInverted = {\n  ...Clear,\n  parameters: {\n    initialStoryState: {\n      internal_index: {\n        v: 6,\n        entries: {\n          'c1-s1': { tags: ['A', 'B', 'C', 'dev', 'play-fn'], type: 'story' } as StoryIndexEntry,\n          'c1-test': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n          'c1-doc': { tags: [], type: 'docs' } as unknown as DocsIndexEntry,\n        },\n      } as StoryIndex,\n      excludedTagFilters: ['A', 'B'],\n    },\n  },\n  play: async ({ canvas }) => {\n    const button = await canvas.findByRole('button', {}, { timeout: 3000 });\n    button.click();\n  },\n} satisfies Story;\n\nexport const WithSelectionMixed = {\n  parameters: {\n    initialStoryState: {\n      internal_index: {\n        v: 6,\n        entries: {\n          'c1-s1': { tags: ['A', 'B', 'C', 'dev', 'play-fn'], type: 'story' } as StoryIndexEntry,\n          'c1-test': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n          'c1-doc': { tags: [], type: 'docs' } as unknown as DocsIndexEntry,\n        },\n      } as StoryIndex,\n      includedTagFilters: ['A'],\n      excludedTagFilters: ['B'],\n    },\n  },\n  play: async ({ canvas }) => {\n    const button = await canvas.findByRole('button', {}, { timeout: 3000 });\n    button.click();\n  },\n} satisfies Story;\n\nexport const Empty: Story = {\n  parameters: {\n    initialStoryState: {\n      internal_index: {\n        v: 6,\n        entries: {},\n      } as StoryIndex,\n    },\n  },\n  play: async ({ canvas }) => {\n    const button = await canvas.findByRole('button', {}, { timeout: 3000 });\n    button.click();\n\n    const learnButton = await screen.findByText('Learn how to add tags');\n    expect(learnButton).toBeInTheDocument();\n  },\n};\n\n/** Production is equal to development now */\nexport const EmptyProduction: Story = {\n  parameters: {\n    initialStoryState: {\n      internal_index: {\n        v: 6,\n        entries: {},\n      } as StoryIndex,\n    },\n  },\n  play: Empty.play,\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/Filter.story-helpers.tsx",
    "content": "import React from 'react';\n\nimport { Channel } from 'storybook/internal/channels';\nimport type { API_Provider, DecoratorFunction } from 'storybook/internal/types';\n\nimport { deepMerge } from '@vitest/utils';\nimport type { API, State } from 'storybook/manager-api';\nimport { fn } from 'storybook/test';\n\nimport { IconSymbols } from './IconSymbols.tsx';\n\nimport type { ModuleArgs, ModuleFn } from '../../../manager-api/lib/types.tsx';\nimport { init as initStories } from '../../../manager-api/modules/stories.ts';\nimport { createTestingStore } from '../../../manager-api/test-utils/store.ts';\n\n/** Mock API wrapper that forces component updates when store state changes. */\nexport class MockAPIWrapper<SubAPI, SubState> extends React.Component<{\n  children: React.ReactNode;\n  args: Record<string, unknown>;\n  initFn: ModuleFn<SubAPI, SubState>;\n  initOptions?: Partial<ModuleArgs>;\n  initialStoryState?: Partial<State>;\n}> {\n  api: ReturnType<typeof initStories>['api'];\n  store: ReturnType<typeof createTestingStore>;\n  channel: Channel;\n  mounted: boolean;\n\n  constructor(props: {\n    children: React.ReactNode;\n    args: Record<string, unknown>;\n    initFn: ModuleFn<SubAPI, SubState>;\n    initOptions?: Partial<ModuleArgs>;\n    initialStoryState?: Partial<State>;\n  }) {\n    super(props);\n\n    // Set up store.\n    this.mounted = false;\n    this.store = createTestingStore({} as State, (newState) => {\n      if (this.mounted) {\n        this.setState(newState);\n      }\n    });\n\n    // Mock channel and provider.\n    this.channel = new Channel({});\n    const provider: API_Provider<API> = {\n      getConfig: () => ({}),\n      handleAPI: () => {},\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore - TSC in CI fails to recognise this is the right Channel type.\n      channel: this.channel,\n    };\n\n    // Mock other submodules we depend on.\n    const fullAPI = {\n      experimental_setFilter: fn().mockName('API::experimental_setFilter'),\n      getRefs: fn().mockName('API::getRefs').mockReturnValue({}),\n      setRef: fn().mockName('API::setRef'),\n      updateRef: fn().mockName('API::updateRef'),\n      setOptions: fn().mockName('API::setOptions'),\n    } as unknown as API;\n\n    const { api, init, state } = props.initFn({\n      fullAPI,\n      store: this.store,\n      provider,\n      location: { search: '' },\n      navigate: () => {},\n      path: '',\n      docsOptions: {},\n      state: {} as State,\n      ...(props.initOptions ?? {}),\n    });\n\n    // Apply module and initial story states.\n    if (props.initialStoryState) {\n      this.store.setState(deepMerge<State>(state as State, props.initialStoryState));\n    } else {\n      this.store.setState(state as State);\n    }\n\n    // Call module's post init function if it exists.\n    if (init && typeof init === 'function') {\n      init();\n    }\n\n    this.api = api as API;\n  }\n\n  componentDidMount() {\n    this.mounted = true;\n  }\n\n  componentWillUnmount() {\n    this.mounted = false;\n  }\n\n  render() {\n    const { children, args } = this.props;\n    return (\n      <>\n        {React.cloneElement(children as React.ReactElement, {\n          args: {\n            ...args,\n            api: {\n              ...this.api,\n              getDocsUrl: () => 'https://storybook.js.org/docs/',\n              getUrlState: () => ({\n                queryParams: {},\n                path: '',\n                viewMode: 'story',\n                url: 'http://localhost:6006/',\n              }),\n              applyQueryParams: fn().mockName('api::applyQueryParams'),\n            },\n          },\n        })}\n      </>\n    );\n  }\n}\n\nexport const IconSymbolsDecorator: DecoratorFunction = (Story) => (\n  <>\n    <IconSymbols />\n    <Story />\n  </>\n);\n\nexport const MockAPIDecorator: DecoratorFunction = (Story, { args, parameters }) => (\n  <MockAPIWrapper\n    args={args}\n    initFn={initStories}\n    initialStoryState={parameters?.initialStoryState}\n    initOptions={{ singleStory: false }}\n  >\n    <Story />\n  </MockAPIWrapper>\n);\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/Filter.tsx",
    "content": "import React, { useCallback, useState } from 'react';\n\nimport { Badge, Button, PopoverProvider } from 'storybook/internal/components';\nimport type { StatusesByStoryIdAndTypeId, StoryIndex } from 'storybook/internal/types';\nimport type { StatusValue } from 'storybook/internal/types';\n\nimport { FilterIcon } from '@storybook/icons';\n\nimport { type API, type Combo, Consumer, experimental_useStatusStore } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport { FilterPanel } from './FilterPanel.tsx';\n\nconst StyledButton = styled(Button)<{ $isHighlighted: boolean }>(({ $isHighlighted, theme }) => ({\n  '&:focus-visible': {\n    outlineOffset: 4,\n  },\n  ...($isHighlighted && {\n    background: theme.background.hoverable,\n    color: theme.color.secondary,\n  }),\n}));\n\nconst TagSelected = styled(Badge)(({ theme }) => ({\n  position: 'absolute',\n  top: 7,\n  right: 7,\n  transform: 'translate(50%, -50%)',\n  display: 'flex',\n  alignItems: 'center',\n  justifyContent: 'center',\n  padding: 3,\n  height: 6,\n  minWidth: 6,\n  lineHeight: 'px',\n  boxShadow: `${theme.barSelectedColor} 0 0 0 1px inset`,\n  fontSize: theme.typography.size.s1 - 1,\n  background: theme.barSelectedColor,\n  color: theme.color.inverseText,\n}));\n\nconst filterMapper = ({ api, state }: Combo) => ({\n  api,\n  indexJson: state.internal_index as StoryIndex | undefined,\n  activeFilterCount:\n    (state.includedTagFilters?.length ?? 0) +\n    (state.excludedTagFilters?.length ?? 0) +\n    (state.includedStatusFilters?.length ?? 0) +\n    (state.excludedStatusFilters?.length ?? 0),\n  defaultIncludedFilters: state.defaultIncludedTagFilters,\n  defaultExcludedFilters: state.defaultExcludedTagFilters,\n  includedFilters: state.includedTagFilters,\n  excludedFilters: state.excludedTagFilters,\n  includedStatusFilters: (state.includedStatusFilters ?? []) as StatusValue[],\n  excludedStatusFilters: (state.excludedStatusFilters ?? []) as StatusValue[],\n});\n\ninterface FilterInnerProps {\n  api: API;\n  indexJson: StoryIndex;\n  activeFilterCount: number;\n  defaultIncludedFilters: string[];\n  defaultExcludedFilters: string[];\n  includedFilters: string[];\n  excludedFilters: string[];\n  includedStatusFilters: StatusValue[];\n  excludedStatusFilters: StatusValue[];\n}\n\nconst FilterInner = ({\n  api,\n  indexJson,\n  activeFilterCount,\n  defaultIncludedFilters,\n  defaultExcludedFilters,\n  includedFilters,\n  excludedFilters,\n  includedStatusFilters,\n  excludedStatusFilters,\n}: FilterInnerProps) => {\n  const [expanded, setExpanded] = useState(false);\n  const allStatuses = experimental_useStatusStore() as StatusesByStoryIdAndTypeId;\n\n  const handleToggleExpand = useCallback(\n    (event: React.SyntheticEvent<Element, Event>): void => {\n      event.preventDefault();\n      setExpanded(!expanded);\n    },\n    [expanded]\n  );\n\n  return (\n    <PopoverProvider\n      ariaLabel=\"Tag filters\"\n      placement=\"bottom\"\n      onVisibleChange={setExpanded}\n      offset={8}\n      padding={0}\n      popover={() => (\n        <FilterPanel\n          api={api}\n          indexJson={indexJson}\n          defaultIncludedFilters={defaultIncludedFilters}\n          defaultExcludedFilters={defaultExcludedFilters}\n          includedFilters={includedFilters}\n          excludedFilters={excludedFilters}\n          allStatuses={allStatuses}\n          includedStatusFilters={includedStatusFilters}\n          excludedStatusFilters={excludedStatusFilters}\n        />\n      )}\n    >\n      <StyledButton\n        key=\"tags\"\n        ariaLabel={\n          activeFilterCount\n            ? `${activeFilterCount} active tag ${activeFilterCount !== 1 ? 'filters' : 'filter'}`\n            : 'Tag filters'\n        }\n        ariaDescription=\"Filter the items shown in a sidebar based on the tags applied to them.\"\n        variant=\"ghost\"\n        padding=\"small\"\n        $isHighlighted={activeFilterCount > 0}\n        onClick={handleToggleExpand}\n      >\n        <FilterIcon />\n        {activeFilterCount > 0 && <TagSelected />}\n      </StyledButton>\n    </PopoverProvider>\n  );\n};\n\nexport const Filter = () => (\n  <Consumer filter={filterMapper}>\n    {({\n      api,\n      indexJson,\n      activeFilterCount,\n      defaultIncludedFilters,\n      defaultExcludedFilters,\n      includedFilters,\n      excludedFilters,\n      includedStatusFilters,\n      excludedStatusFilters,\n    }) =>\n      indexJson ? (\n        <FilterInner\n          api={api}\n          indexJson={indexJson}\n          activeFilterCount={activeFilterCount}\n          defaultIncludedFilters={defaultIncludedFilters}\n          defaultExcludedFilters={defaultExcludedFilters}\n          includedFilters={includedFilters}\n          excludedFilters={excludedFilters}\n          includedStatusFilters={includedStatusFilters}\n          excludedStatusFilters={excludedStatusFilters}\n        />\n      ) : null\n    }\n  </Consumer>\n);\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/FilterPanel.stories.tsx",
    "content": "import type {\n  DocsIndexEntry,\n  StoryIndex,\n  StoryIndexEntry,\n  StatusesByStoryIdAndTypeId,\n  StatusValue,\n} from 'storybook/internal/types';\nimport type { Meta, StoryObj } from '@storybook/react-vite';\nimport type { API } from '../../../manager-api/index.ts';\n\nimport { IconSymbolsDecorator, MockAPIDecorator } from './Filter.story-helpers.tsx';\nimport { FilterPanel } from './FilterPanel.tsx';\n\nconst getEntries = (includeUserTags: boolean) => {\n  const entries = {\n    'c1-autodocs': { tags: ['tag1', 'autodocs'], type: 'docs' } as DocsIndexEntry,\n    'c1-story1': { tags: ['tag1', 'dev'], type: 'story' } as StoryIndexEntry,\n    'c1-story2': { tags: ['tag1'], type: 'story' } as StoryIndexEntry,\n    'c2-autodocs': { tags: ['tag1', 'autodocs'], type: 'docs' } as DocsIndexEntry,\n    'c2-story1': { tags: ['tag1', 'play-fn'], type: 'story' } as StoryIndexEntry,\n    'c2-story2': { tags: ['tag1'], type: 'story' } as StoryIndexEntry,\n    'c2-story3': { tags: ['tag1'], type: 'story' } as StoryIndexEntry,\n    'c3-autodocs': { tags: ['tag1', 'autodocs'], type: 'docs' } as DocsIndexEntry,\n    'c3-story1': { tags: ['tag1', 'play-fn'], type: 'story' } as StoryIndexEntry,\n    'c3-story2': { tags: ['tag1', 'play-fn'], type: 'story' } as StoryIndexEntry,\n    'c3-story3': { tags: ['tag1', 'play-fn'], type: 'story' } as StoryIndexEntry,\n    'c4-autodocs': { tags: ['tag1', 'autodocs'], type: 'docs' } as DocsIndexEntry,\n    'c4-story1': { tags: ['tag1'], type: 'story' } as StoryIndexEntry,\n    'c4-story2': { tags: ['tag1'], type: 'story' } as StoryIndexEntry,\n    'c5-autodocs': { tags: ['tag2', 'autodocs'], type: 'docs' } as DocsIndexEntry,\n    'c5-story1': { tags: ['tag2', 'play-fn'], type: 'story' } as StoryIndexEntry,\n    'c5-story2': { tags: ['tag2', 'play-fn'], type: 'story' } as StoryIndexEntry,\n    'c5-story3': { tags: ['tag2', 'play-fn'], type: 'story' } as StoryIndexEntry,\n    'c6-autodocs': { tags: ['tag2', 'autodocs'], type: 'docs' } as DocsIndexEntry,\n    'c6-story1': { tags: ['tag2'], type: 'story' } as StoryIndexEntry,\n    'c6-story2': { tags: ['tag2'], type: 'story' } as StoryIndexEntry,\n    'c6-story3': { tags: ['tag2'], type: 'story' } as StoryIndexEntry,\n    'c7-autodocs': { tags: ['tag2', 'autodocs'], type: 'docs' } as DocsIndexEntry,\n    'c7-story1': { tags: ['tag2'], type: 'story' } as StoryIndexEntry,\n    'c7-story2': { tags: ['tag2'], type: 'story' } as StoryIndexEntry,\n    'c7-story3': { tags: ['tag2'], type: 'story' } as StoryIndexEntry,\n    'c8-autodocs': { tags: ['tag2', 'autodocs'], type: 'docs' } as DocsIndexEntry,\n    'c8-story1': { tags: ['tag2', 'play-fn'], type: 'story' } as StoryIndexEntry,\n    'c8-story2': { tags: ['tag2', 'play-fn'], type: 'story' } as StoryIndexEntry,\n    'c8-story3': { tags: ['tag2'], type: 'story' } as StoryIndexEntry,\n    'c9-autodocs': { tags: ['tag2', 'autodocs'], type: 'docs' } as DocsIndexEntry,\n    'c9-story1': { tags: ['tag2'], type: 'story' } as StoryIndexEntry,\n    'c9-story2': { tags: ['tag2', 'play-fn'], type: 'story' } as StoryIndexEntry,\n    'c9-story3': { tags: ['tag2', 'play-fn'], type: 'story' } as StoryIndexEntry,\n    'c10-autodocs': { tags: ['tag2', 'autodocs'], type: 'docs' } as DocsIndexEntry,\n    'c10-story1': { tags: ['tag2', 'play-fn'], type: 'story' } as StoryIndexEntry,\n    'c10-story2': { tags: ['tag2', 'play-fn'], type: 'story' } as StoryIndexEntry,\n    'c10-story3': { tags: ['tag2', 'play-fn'], type: 'story' } as StoryIndexEntry,\n    'c11-story1': {\n      tags: ['tag3-which-is-very-long-and-will-be-truncated-after-a-while'],\n      type: 'story',\n    } as StoryIndexEntry,\n    'c11-story2': {\n      tags: ['tag3-which-is-very-long-and-will-be-truncated-after-a-while'],\n      type: 'story',\n    } as StoryIndexEntry,\n    'c12-s1-test1': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n    'c12-s1-test2': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n    'c12-s1-test3': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n    'c12-s1-test4': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n    'c12-s1-test5': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n    'c12-s1-test6': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n    'c12-s1-test7': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n    'c12-s1-test8': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n    'c12-s3-test1': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n    'c12-s3-test2': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n    'c12-s3-test3': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n    'c12-s3-test4': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n    'c12-s3-test5': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n    'c12-s3-test6': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n    'c12-s3-test7': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n    'c12-s3-test8': { tags: ['test-fn'], type: 'story', subtype: 'test' } as StoryIndexEntry,\n  };\n\n  if (!includeUserTags) {\n    Object.values(entries).forEach((entry) => {\n      entry.tags = entry.tags?.filter((tag) =>\n        ['autodocs', 'dev', 'play-fn', 'test-fn'].includes(tag)\n      );\n    });\n  }\n\n  return entries;\n};\n\n// Helper to build an allStatuses map with one entry per status value\nconst makeStatuses = (\n  ...values: Array<{ storyId: string; typeId: string; statusValue: StatusValue; title: string }>\n): StatusesByStoryIdAndTypeId =>\n  values.reduce<StatusesByStoryIdAndTypeId>((acc, { storyId, typeId, statusValue, title }) => {\n    acc[storyId] ??= {};\n    acc[storyId][typeId] = {\n      value: statusValue,\n      typeId,\n      storyId,\n      title,\n      description: '',\n    };\n    return acc;\n  }, {});\n\nconst meta = {\n  component: FilterPanel,\n  title: 'Sidebar/FilterPanel',\n  // Will provide api mock\n  decorators: [MockAPIDecorator, IconSymbolsDecorator],\n  tags: ['hoho'],\n  args: {\n    api: {} as API,\n    indexJson: {\n      v: 6,\n      entries: getEntries(true),\n    } as StoryIndex,\n    defaultExcludedFilters: [],\n    defaultIncludedFilters: [],\n    includedFilters: [],\n    excludedFilters: [],\n    allStatuses: {},\n    includedStatusFilters: [],\n    excludedStatusFilters: [],\n  },\n} satisfies Meta<typeof FilterPanel>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {};\n\nexport const BuiltInOnly: Story = {\n  args: {\n    indexJson: {\n      v: 6,\n      entries: getEntries(false),\n    } as StoryIndex,\n    allStatuses: makeStatuses(\n      {\n        storyId: 'c1-story1',\n        typeId: 'change-detection',\n        statusValue: 'status-value:new',\n        title: 'New',\n      },\n      {\n        storyId: 'c1-story2',\n        typeId: 'change-detection',\n        statusValue: 'status-value:modified',\n        title: 'Modified',\n      },\n      {\n        storyId: 'c2-story1',\n        typeId: 'change-detection',\n        statusValue: 'status-value:affected',\n        title: 'Affected',\n      }\n    ),\n  },\n};\n\n/**\n * Production is equal to development now. We want to avoid a completely empty FilterPanel and\n * we can't easily detect if there'll be items matching the built-in filters. Plus, onboarding users\n * on custom tags is still useful in production.\n */\nexport const BuiltInOnlyProduction: Story = {\n  args: {\n    ...BuiltInOnly.args,\n  },\n};\n\nexport const Included: Story = {\n  args: {\n    indexJson: {\n      v: 6,\n      entries: getEntries(true),\n    } as StoryIndex,\n    includedFilters: ['tag1'],\n  },\n};\n\nexport const Excluded: Story = {\n  args: {\n    indexJson: {\n      v: 6,\n      entries: getEntries(true),\n    } as StoryIndex,\n    excludedFilters: ['tag1'],\n  },\n};\n\nexport const Mixed: Story = {\n  args: {\n    indexJson: {\n      v: 6,\n      entries: getEntries(true),\n    } as StoryIndex,\n    includedFilters: ['tag1'],\n    excludedFilters: ['tag2'],\n  },\n};\n\nexport const DefaultSelection: Story = {\n  args: {\n    indexJson: {\n      v: 6,\n      entries: getEntries(true),\n    } as StoryIndex,\n    includedFilters: ['tag1'],\n    excludedFilters: ['tag2'],\n    defaultIncludedFilters: ['tag1'],\n    defaultExcludedFilters: ['tag2'],\n  },\n};\n\nexport const DefaultSelectionModified: Story = {\n  args: {\n    indexJson: {\n      v: 6,\n      entries: getEntries(true),\n    } as StoryIndex,\n    includedFilters: ['tag1', 'tag2'],\n    defaultIncludedFilters: ['tag1'],\n    defaultExcludedFilters: ['tag2'],\n  },\n};\n\nexport const WithStatuses: Story = {\n  args: {\n    allStatuses: makeStatuses(\n      {\n        storyId: 'c1-story1',\n        typeId: 'change-detection',\n        statusValue: 'status-value:new',\n        title: 'New',\n      },\n      {\n        storyId: 'c1-story2',\n        typeId: 'change-detection',\n        statusValue: 'status-value:modified',\n        title: 'Modified',\n      },\n      {\n        storyId: 'c2-story1',\n        typeId: 'change-detection',\n        statusValue: 'status-value:affected',\n        title: 'Affected',\n      }\n    ),\n  },\n};\n\nexport const WithStatusesIncluded: Story = {\n  args: {\n    ...WithStatuses.args,\n    includedStatusFilters: ['status-value:new', 'status-value:modified'],\n  },\n};\n\nexport const WithStatusesExcluded: Story = {\n  args: {\n    ...WithStatuses.args,\n    excludedStatusFilters: ['status-value:affected'],\n  },\n};\n\nexport const OnlyNewStatus: Story = {\n  args: {\n    allStatuses: makeStatuses({\n      storyId: 'c1-story1',\n      typeId: 'change-detection',\n      statusValue: 'status-value:new',\n      title: 'New',\n    }),\n  },\n};\n\nexport const OnlyModifiedStatus: Story = {\n  args: {\n    allStatuses: makeStatuses({\n      storyId: 'c1-story2',\n      typeId: 'change-detection',\n      statusValue: 'status-value:modified',\n      title: 'Modified',\n    }),\n  },\n};\n\nexport const OnlyAffectedStatus: Story = {\n  args: {\n    allStatuses: makeStatuses({\n      storyId: 'c2-story1',\n      typeId: 'change-detection',\n      statusValue: 'status-value:affected',\n      title: 'Affected',\n    }),\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/FilterPanel.tsx",
    "content": "import React, { Fragment, useCallback, useMemo } from 'react';\n\nimport { ActionList } from 'storybook/internal/components';\nimport type { StatusValue, StatusesByStoryIdAndTypeId, StoryIndex } from 'storybook/internal/types';\n\nimport { BatchAcceptIcon, DocumentIcon, ShareAltIcon, SweepIcon, UndoIcon } from '@storybook/icons';\n\nimport type { API } from 'storybook/manager-api';\nimport { styled, useTheme } from 'storybook/theming';\n\nimport { getStatus } from '../../utils/status.tsx';\nimport { createFilterLink, StatusIcon } from './FilterPanelLink.tsx';\nimport { type FilterItem, areFiltersEqual } from './FilterPanel.utils.ts';\nimport {\n  type StatusFilterEntry,\n  type TagFilterEntry,\n  useStatusFilterEntries,\n  useTagFilterEntries,\n} from './useFilterData.tsx';\n\nconst Wrapper = styled.div({\n  minWidth: 240,\n  maxWidth: 300,\n  maxHeight: 15.5 * 32 + 8, // 15.5 items at 32px each + 8px padding\n  overflow: 'hidden',\n  overflowY: 'auto',\n  scrollbarWidth: 'thin',\n});\n\nexport interface FilterPanelProps {\n  api: API;\n  indexJson: StoryIndex;\n  defaultIncludedFilters: string[];\n  defaultExcludedFilters: string[];\n  includedFilters: string[];\n  excludedFilters: string[];\n  allStatuses: StatusesByStoryIdAndTypeId;\n  includedStatusFilters: StatusValue[];\n  excludedStatusFilters: StatusValue[];\n}\n\nexport const FilterPanel = ({\n  api,\n  indexJson,\n  defaultIncludedFilters,\n  defaultExcludedFilters,\n  includedFilters,\n  excludedFilters,\n  allStatuses,\n  includedStatusFilters,\n  excludedStatusFilters,\n}: FilterPanelProps) => {\n  const theme = useTheme();\n\n  const { builtInEntries, tagEntries } = useTagFilterEntries(indexJson);\n  const statusEntries = useStatusFilterEntries(allStatuses);\n\n  const toTagFilterItem = useCallback(\n    (entry: TagFilterEntry): FilterItem | null => {\n      if (entry.count === 0 && entry.type === 'built-in') return null;\n      const isIncluded = includedFilters.includes(entry.id);\n      const isExcluded = excludedFilters.includes(entry.id);\n      const isChecked = isIncluded || isExcluded;\n      return {\n        id: entry.id,\n        type: entry.type,\n        title: entry.title,\n        count: entry.count,\n        icon: entry.icon,\n        isIncluded,\n        isExcluded,\n        onCheckboxChange: () => {\n          if (isChecked) {\n            api.removeTagFilters([entry.id]);\n          } else {\n            api.addTagFilters([entry.id], false);\n          }\n        },\n        onInvert: () => api.addTagFilters([entry.id], !isExcluded),\n      };\n    },\n    [api, includedFilters, excludedFilters]\n  );\n\n  const toStatusFilterItem = useCallback(\n    (entry: StatusFilterEntry): FilterItem => {\n      const isIncluded = includedStatusFilters.includes(entry.statusValue);\n      const isExcluded = excludedStatusFilters.includes(entry.statusValue);\n      const isChecked = isIncluded || isExcluded;\n      const { icon: statusIconEl, iconColor } = getStatus(theme, entry.statusValue);\n      return {\n        id: entry.shortName,\n        type: 'status',\n        title: entry.shortName.charAt(0).toUpperCase() + entry.shortName.slice(1),\n        count: entry.count,\n        icon: statusIconEl ? <StatusIcon $iconColor={iconColor}>{statusIconEl}</StatusIcon> : null,\n        isIncluded,\n        isExcluded,\n        onCheckboxChange: () => {\n          if (isChecked) {\n            api.removeStatusFilters([entry.statusValue]);\n          } else {\n            api.addStatusFilters([entry.statusValue], false);\n          }\n        },\n        onInvert: () => api.addStatusFilters([entry.statusValue], !isExcluded),\n      };\n    },\n    [api, includedStatusFilters, excludedStatusFilters, theme]\n  );\n\n  const builtInItems = useMemo(\n    () =>\n      builtInEntries\n        .sort((a, b) => a.id.localeCompare(b.id))\n        .map(toTagFilterItem)\n        .filter((f): f is FilterItem => f !== null),\n    [builtInEntries, toTagFilterItem]\n  );\n\n  const tagItems = useMemo(\n    () =>\n      tagEntries\n        .sort((a, b) => a.id.localeCompare(b.id))\n        .map(toTagFilterItem)\n        .filter((f): f is FilterItem => f !== null),\n    [tagEntries, toTagFilterItem]\n  );\n\n  const statusItems = useMemo(\n    () => statusEntries.map(toStatusFilterItem),\n    [statusEntries, toStatusFilterItem]\n  );\n\n  const filterIds = useMemo(\n    () => [...builtInEntries.map((e) => e.id), ...tagEntries.map((e) => e.id)],\n    [builtInEntries, tagEntries]\n  );\n\n  const setAllFilters = useCallback(\n    (selected: boolean) => {\n      api.setAllTagFilters(selected ? filterIds : [], []);\n    },\n    [api, filterIds]\n  );\n\n  const isDefaultSelection =\n    areFiltersEqual(includedFilters, defaultIncludedFilters) &&\n    areFiltersEqual(excludedFilters, defaultExcludedFilters);\n\n  const hasDefaultSelection =\n    defaultIncludedFilters.length > 0 || defaultExcludedFilters.length > 0;\n\n  const isNothingSelectedYet =\n    includedFilters.length === 0 &&\n    excludedFilters.length === 0 &&\n    includedStatusFilters.length === 0 &&\n    excludedStatusFilters.length === 0;\n\n  const hasItems = builtInItems.length > 0 || tagItems.length > 0;\n\n  return (\n    <Wrapper>\n      {hasItems && (\n        <ActionList as=\"div\">\n          <ActionList.Item as=\"div\">\n            {isNothingSelectedYet ? (\n              <ActionList.Button\n                ariaLabel={false}\n                id=\"select-all\"\n                key=\"select-all\"\n                onClick={() => setAllFilters(true)}\n              >\n                <BatchAcceptIcon />\n                <ActionList.Text>Select all</ActionList.Text>\n              </ActionList.Button>\n            ) : (\n              <ActionList.Button\n                ariaLabel={false}\n                id=\"deselect-all\"\n                key=\"deselect-all\"\n                onClick={() => {\n                  setAllFilters(false);\n                  api.resetStatusFilters();\n                }}\n              >\n                <SweepIcon />\n                <ActionList.Text>Clear filters</ActionList.Text>\n              </ActionList.Button>\n            )}\n            {hasDefaultSelection && (\n              <ActionList.Button\n                id=\"reset-filters\"\n                key=\"reset-filters\"\n                onClick={() => api.resetTagFilters()}\n                ariaLabel=\"Reset filters\"\n                tooltip=\"Reset to default selection\"\n                disabled={isDefaultSelection}\n              >\n                <UndoIcon />\n              </ActionList.Button>\n            )}\n          </ActionList.Item>\n        </ActionList>\n      )}\n      {builtInItems.length > 0 && (\n        <ActionList>\n          {builtInItems.map((item) => {\n            const link = createFilterLink(item);\n            return <Fragment key={link.id}>{link.content}</Fragment>;\n          })}\n        </ActionList>\n      )}\n      {statusItems.length > 0 && (\n        <ActionList>\n          {statusItems.map((item) => {\n            const link = createFilterLink(item);\n            return <Fragment key={link.id}>{link.content}</Fragment>;\n          })}\n        </ActionList>\n      )}\n      {tagItems.length > 0 && (\n        <ActionList>\n          {tagItems.map((item) => {\n            const link = createFilterLink(item);\n            return <Fragment key={link.id}>{link.content}</Fragment>;\n          })}\n        </ActionList>\n      )}\n      {tagItems.length === 0 && (\n        <ActionList as=\"div\">\n          <ActionList.Item as=\"div\">\n            <ActionList.Link\n              ariaLabel={false}\n              href={api.getDocsUrl({ subpath: 'writing-stories/tags#custom-tags' })}\n              target=\"_blank\"\n            >\n              <ActionList.Icon>\n                <DocumentIcon />\n              </ActionList.Icon>\n              <ActionList.Text>\n                <span>Learn how to add tags</span>\n              </ActionList.Text>\n              <ActionList.Icon>\n                <ShareAltIcon />\n              </ActionList.Icon>\n            </ActionList.Link>\n          </ActionList.Item>\n        </ActionList>\n      )}\n    </Wrapper>\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/FilterPanel.utils.ts",
    "content": "import type { ReactElement } from 'react';\n\nimport type { FilterFunction, StatusValue, Tag } from 'storybook/internal/types';\n\nimport { BUILT_IN_FILTERS, USER_TAG_FILTER } from '../../../shared/constants/tags.ts';\n\nexport { statusValueShortName, toStatusValue } from '../../../shared/status-store/index.ts';\n\nexport type FilterItem = {\n  id: string;\n  type: string;\n  title: string;\n  count: number;\n  icon: ReactElement | null;\n  isIncluded: boolean;\n  isExcluded: boolean;\n  onCheckboxChange: () => void;\n  onInvert: () => void;\n};\n\n/** Tags that are hidden in the filter UI. There's a more general built-in list defined in `shared/constants/tags`. */\nexport const BUILT_IN_TAGS = new Set([\n  'dev',\n  'test',\n  'autodocs',\n  'attached-mdx',\n  'unattached-mdx',\n  'play-fn',\n  'test-fn',\n  'manifest',\n]);\n\n/** Only change-detection statuses are shown in the sidebar filter panel. */\nexport const STATUS_DISPLAY_ORDER: StatusValue[] = [\n  'status-value:new',\n  'status-value:modified',\n  'status-value:affected',\n];\n\n/**\n * Equality check for filter arrays. Works on the basis that there are no duplicates.\n * We use arrays because we need arrays for data persistence in the layout module.\n */\nexport const areFiltersEqual = (left: string[], right: string[]) =>\n  left.length === right.length && new Set([...left, ...right]).size === left.length;\n\nexport const getFilterFunction = (tag: Tag): FilterFunction | null => {\n  if (Object.hasOwn(BUILT_IN_FILTERS, tag)) {\n    return BUILT_IN_FILTERS[tag as keyof typeof BUILT_IN_FILTERS];\n  } else {\n    return USER_TAG_FILTER(tag);\n  }\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/FilterPanelLink.tsx",
    "content": "import React from 'react';\n\nimport { ActionList, Form } from 'storybook/internal/components';\n\nimport { DeleteIcon } from '@storybook/icons';\n\nimport { styled } from 'storybook/theming';\n\nimport type { Link } from '../../../components/components/tooltip/TooltipLinkList.tsx';\nimport type { FilterItem } from './FilterPanel.utils.ts';\n\nconst MutedText = styled.span(({ theme }) => ({\n  color: theme.textMutedColor,\n}));\n\nexport const StatusIcon = styled.span<{ $iconColor?: string | null }>(({ $iconColor }) => ({\n  display: 'contents',\n  color: $iconColor ?? undefined,\n  '> svg': {\n    transform: 'scale(1.3)',\n  },\n}));\n\nexport const createFilterLink = ({\n  id,\n  type,\n  title,\n  count,\n  icon,\n  isIncluded,\n  isExcluded,\n  onCheckboxChange,\n  onInvert,\n}: FilterItem): Link => {\n  const isChecked = isIncluded || isExcluded;\n  const toggleLabel = `${type} filter: ${isExcluded ? `exclude ${title}` : title}`;\n  const toggleTooltip = `${isChecked ? 'Remove' : 'Add'} ${type} filter: ${title}`;\n  const invertButtonLabel = `${isExcluded ? 'Include' : 'Exclude'} ${type}: ${title}`;\n\n  return {\n    id: `filter-${type}-${id}`,\n    content: (\n      <ActionList.HoverItem targetId={`filter-${type}-${id}`}>\n        <ActionList.Action as=\"label\" ariaLabel={false} tabIndex={-1} tooltip={toggleTooltip}>\n          <ActionList.Icon>\n            {isExcluded ? <DeleteIcon /> : isIncluded ? null : icon}\n            <Form.Checkbox\n              checked={isChecked}\n              onChange={onCheckboxChange}\n              data-tag={title}\n              aria-label={toggleLabel}\n            />\n          </ActionList.Icon>\n          <ActionList.Text>\n            <span>\n              {title}\n              {isExcluded && <MutedText> (excluded)</MutedText>}\n            </span>\n          </ActionList.Text>\n          {isExcluded ? <s>{count}</s> : <span>{count}</span>}\n        </ActionList.Action>\n        <ActionList.Button\n          data-target-id={`filter-${type}-${id}`}\n          ariaLabel={invertButtonLabel}\n          onClick={onInvert}\n        >\n          <span style={{ minWidth: 45 }}>{isExcluded ? 'Include' : 'Exclude'}</span>\n        </ActionList.Button>\n      </ActionList.HoverItem>\n    ),\n  };\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/Heading.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryFn, StoryObj } from '@storybook/react-vite';\n\nimport { action } from 'storybook/actions';\nimport { screen } from 'storybook/test';\nimport { ThemeProvider, useTheme } from 'storybook/theming';\nimport type { Theme } from 'storybook/theming';\n\nimport { Heading } from './Heading.tsx';\n\ntype Story = StoryFn<typeof Heading>;\n\nexport default {\n  component: Heading,\n  title: 'Sidebar/Heading',\n  excludeStories: /.*Data$/,\n  parameters: { layout: 'fullscreen' },\n  globals: { sb_theme: 'side-by-side' },\n  decorators: [\n    (storyFn) => <div style={{ padding: '0 20px', maxWidth: '230px' }}>{storyFn()}</div>,\n  ],\n} as Meta<typeof Heading>;\n\nconst menuItems = [\n  [\n    { title: 'Menu Item 1', onClick: action('onActivateMenuItem'), id: '1' },\n    { title: 'Menu Item 2', onClick: action('onActivateMenuItem'), id: '2' },\n    { title: 'Menu Item 3', onClick: action('onActivateMenuItem'), id: '3' },\n  ],\n];\n\nexport const MenuHighlighted: Story = () => (\n  <Heading menuHighlighted menu={menuItems} isLoading={false} />\n);\n\nexport const standardData = { menu: menuItems };\n\nexport const Standard: Story = () => {\n  const theme = useTheme() as Theme;\n  return (\n    <ThemeProvider\n      theme={{\n        ...theme,\n        brand: {\n          title: undefined,\n          url: undefined,\n          image: undefined,\n          target: undefined,\n        },\n      }}\n    >\n      <Heading menu={menuItems} isLoading={false} />\n    </ThemeProvider>\n  );\n};\n\nexport const StandardNoLink: Story = () => {\n  const theme = useTheme() as Theme;\n  return (\n    <ThemeProvider\n      theme={{\n        ...theme,\n        brand: {\n          title: undefined,\n          url: null,\n          image: undefined,\n          target: undefined,\n        },\n      }}\n    >\n      <Heading menu={menuItems} isLoading={false} />\n    </ThemeProvider>\n  );\n};\n\nexport const LinkAndText: Story = () => {\n  const theme = useTheme() as Theme;\n  return (\n    <ThemeProvider\n      theme={{\n        ...theme,\n        brand: {\n          title: 'My title',\n          url: 'https://example.com',\n          image: null,\n          target: undefined,\n        },\n      }}\n    >\n      <Heading menu={menuItems} isLoading={false} />\n    </ThemeProvider>\n  );\n};\n\nexport const OnlyText: Story = () => {\n  const theme = useTheme() as Theme;\n  return (\n    <ThemeProvider\n      theme={{\n        ...theme,\n        brand: {\n          title: 'My title',\n          url: null,\n          image: null,\n          target: undefined,\n        },\n      }}\n    >\n      <Heading menu={menuItems} isLoading={false} />\n    </ThemeProvider>\n  );\n};\n\nexport const LongText: Story = () => {\n  const theme = useTheme() as Theme;\n  return (\n    <ThemeProvider\n      theme={{\n        ...theme,\n        brand: {\n          title: 'My title is way to long to actually fit',\n          url: null,\n          image: null,\n          target: undefined,\n        },\n      }}\n    >\n      <Heading menu={menuItems} isLoading={false} />\n    </ThemeProvider>\n  );\n};\n\nexport const CustomTitle: Story = () => {\n  const theme = useTheme() as Theme;\n  return (\n    <ThemeProvider\n      theme={{\n        ...theme,\n        brand: {\n          title: '<span style=\"color:red\">My custom title</span>',\n          url: null,\n          image: null,\n          target: undefined,\n        },\n      }}\n    >\n      <Heading menu={menuItems} isLoading={false} />\n    </ThemeProvider>\n  );\n};\n\nexport const CustomBrandImage: Story = () => {\n  const theme = useTheme() as Theme;\n  return (\n    <ThemeProvider\n      theme={{\n        ...theme,\n        brand: {\n          title: 'My Title',\n          url: 'https://example.com',\n          image: 'https://storybook.js.org/images/placeholders/150x22.png',\n          target: undefined,\n        },\n      }}\n    >\n      <Heading menu={menuItems} isLoading={false} />\n    </ThemeProvider>\n  );\n};\n\nexport const CustomBrandImageTall: Story = () => {\n  const theme = useTheme() as Theme;\n  return (\n    <ThemeProvider\n      theme={{\n        ...theme,\n        brand: {\n          title: 'My Title',\n          url: 'https://example.com',\n          image: 'https://storybook.js.org/images/placeholders/100x150.png',\n          target: undefined,\n        },\n      }}\n    >\n      <Heading menu={menuItems} isLoading={false} />\n    </ThemeProvider>\n  );\n};\n\nexport const CustomBrandImageUnsizedSVG: Story = () => {\n  const theme = useTheme() as Theme;\n  return (\n    <ThemeProvider\n      theme={{\n        ...theme,\n        brand: {\n          title: 'My Title',\n          url: 'https://example.com',\n          image: 'https://s.cdpn.io/91525/potofgold.svg',\n          target: undefined,\n        },\n      }}\n    >\n      <Heading menu={menuItems} isLoading={false} />\n    </ThemeProvider>\n  );\n};\n\nexport const NoBrand: Story = () => {\n  const theme = useTheme() as Theme;\n  return (\n    <ThemeProvider\n      theme={{\n        ...theme,\n        brand: {\n          title: undefined,\n          url: null,\n          image: null,\n          target: undefined,\n        },\n      }}\n    >\n      <Heading menu={menuItems} isLoading={false} />\n    </ThemeProvider>\n  );\n};\n\nexport const SkipToCanvasLinkFocused: StoryObj<typeof Heading> = {\n  args: {\n    menu: menuItems,\n    skipLinkHref: '#storybook-preview-wrapper',\n    isLoading: false,\n  },\n  globals: { sb_theme: 'light' },\n  parameters: { layout: 'padded', chromatic: { delay: 300 } },\n  play: () => {\n    // focus each instance for chromatic/storybook's stacked theme\n    screen.getAllByText('Skip to content').forEach((x) => x.focus());\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/Heading.tsx",
    "content": "import type { ComponentProps, FC } from 'react';\nimport React from 'react';\n\nimport { Button } from 'storybook/internal/components';\n\nimport { styled } from 'storybook/theming';\n\nimport { Brand } from './Brand.tsx';\nimport type { MenuList, SidebarMenuProps } from './Menu.tsx';\nimport { SidebarMenu } from './Menu.tsx';\n\nexport interface HeadingProps {\n  menuHighlighted?: boolean;\n  menu: MenuList;\n  skipLinkHref?: string;\n  isLoading: boolean;\n  onMenuClick?: SidebarMenuProps['onClick'];\n}\n\nconst BrandArea = styled.div(({ theme }) => ({\n  fontSize: theme.typography.size.s2,\n  fontWeight: theme.typography.weight.bold,\n  color: theme.color.defaultText,\n  marginRight: 20,\n  display: 'flex',\n  width: '100%',\n  alignItems: 'center',\n  minHeight: 22,\n\n  '& > * > *': {\n    maxWidth: '100%',\n  },\n  '& > *': {\n    maxWidth: '100%',\n    height: 'auto',\n    display: 'block',\n    flex: '1 1 auto',\n  },\n}));\n\nconst HeadingWrapper = styled.div({\n  display: 'flex',\n  alignItems: 'center',\n  justifyContent: 'space-between',\n  position: 'relative',\n  minHeight: 42,\n  paddingLeft: 8,\n});\n\nconst SkipToCanvasLink = styled(Button)(({ theme }) => ({\n  display: 'none',\n  '@media (min-width: 600px)': {\n    display: 'block',\n    position: 'absolute',\n    fontSize: theme.typography.size.s1,\n    border: 0,\n    width: 1,\n    height: 1,\n    padding: 0,\n    margin: -1,\n    overflow: 'hidden',\n    clip: 'rect(0, 0, 0, 0)',\n    whiteSpace: 'nowrap',\n    wordWrap: 'normal',\n    opacity: 0,\n    transition: 'opacity 150ms ease-out',\n    '&:focus': {\n      width: '100%',\n      height: 'inherit',\n      padding: '10px 15px',\n      margin: 0,\n      clip: 'unset',\n      overflow: 'unset',\n      opacity: 1,\n      zIndex: 3,\n    },\n  },\n}));\n\nexport const Heading: FC<HeadingProps & ComponentProps<typeof HeadingWrapper>> = ({\n  menuHighlighted = false,\n  menu,\n  skipLinkHref,\n  isLoading,\n  onMenuClick,\n  ...props\n}) => {\n  return (\n    <HeadingWrapper {...props}>\n      {skipLinkHref && (\n        <SkipToCanvasLink ariaLabel={false} asChild>\n          <a href={skipLinkHref} tabIndex={0}>\n            Skip to content\n          </a>\n        </SkipToCanvasLink>\n      )}\n\n      <BrandArea>\n        <Brand />\n      </BrandArea>\n\n      <SidebarMenu menu={menu} isHighlighted={menuHighlighted} onClick={onMenuClick} />\n    </HeadingWrapper>\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/HighlightStyles.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { transparentize } from 'polished';\nimport { Global } from 'storybook/theming';\n\nimport type { Highlight } from './types.ts';\n\n// @ts-expect-error (non strict)\nexport const HighlightStyles: FC<Highlight> = ({ refId, itemId }) => (\n  <Global\n    styles={({ color }) => {\n      const background = transparentize(0.85, color.secondary);\n      return {\n        [`[data-ref-id=\"${refId}\"][data-item-id=\"${itemId}\"]:not([data-selected=\"true\"])`]: {\n          [`&[data-nodetype=\"component\"], &[data-nodetype=\"group\"]`]: {\n            background,\n            '&:hover, &:focus': { background },\n          },\n          [`&[data-nodetype=\"story\"], &[data-nodetype=\"document\"], &[data-nodetype=\"test\"]`]: {\n            color: color.defaultText,\n            background,\n            '&:hover, &:focus': { background },\n          },\n        },\n      };\n    }}\n  />\n);\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/IconSymbols.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { IconSymbols } from './IconSymbols.tsx';\n\nconst meta = {\n  component: IconSymbols,\n  title: 'Sidebar/IconSymbols',\n} satisfies Meta<typeof IconSymbols>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/IconSymbols.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { styled } from 'storybook/theming';\n\nconst Svg = styled.svg`\n  position: absolute;\n  width: 0;\n  height: 0;\n  display: inline-block;\n  shape-rendering: inherit;\n  vertical-align: middle;\n`;\n\n// We are importing the icons from @storybook/icons as we need to add symbols inside of them.\n// This will allow to set icons once and use them everywhere.\n\nconst GROUP_ID = 'icon--group';\nconst COMPONENT_ID = 'icon--component';\nconst DOCUMENT_ID = 'icon--document';\nconst STORY_ID = 'icon--story';\nconst TEST_ID = 'icon--test';\nconst SUCCESS_ID = 'icon--success';\nconst ERROR_ID = 'icon--error';\nconst WARNING_ID = 'icon--warning';\nconst DOT_ID = 'icon--dot';\nconst NEW_ID = 'icon--new';\nconst MODIFIED_ID = 'icon--modified';\nconst AFFECTED_ID = 'icon--affected';\n\nexport const IconSymbols: FC = () => {\n  return (\n    <Svg data-chromatic=\"ignore\">\n      <symbol id={GROUP_ID}>\n        {/* https://github.com/storybookjs/icons/blob/main/src/icons/FolderIcon.tsx */}\n        <path\n          fillRule=\"evenodd\"\n          clipRule=\"evenodd\"\n          d=\"M6.586 3.504l-1.5-1.5H1v9h12v-7.5H6.586zm.414-1L5.793 1.297a1 1 0 00-.707-.293H.5a.5.5 0 00-.5.5v10a.5.5 0 00.5.5h13a.5.5 0 00.5-.5v-8.5a.5.5 0 00-.5-.5H7z\"\n          fill=\"currentColor\"\n        />\n      </symbol>\n      <symbol id={COMPONENT_ID}>\n        {/* https://github.com/storybookjs/icons/blob/main/src/icons/ComponentIcon.tsx */}\n        <path\n          fillRule=\"evenodd\"\n          clipRule=\"evenodd\"\n          d=\"M3.5 1.004a2.5 2.5 0 00-2.5 2.5v7a2.5 2.5 0 002.5 2.5h7a2.5 2.5 0 002.5-2.5v-7a2.5 2.5 0 00-2.5-2.5h-7zm8.5 5.5H7.5v-4.5h3a1.5 1.5 0 011.5 1.5v3zm0 1v3a1.5 1.5 0 01-1.5 1.5h-3v-4.5H12zm-5.5 4.5v-4.5H2v3a1.5 1.5 0 001.5 1.5h3zM2 6.504h4.5v-4.5h-3a1.5 1.5 0 00-1.5 1.5v3z\"\n          fill=\"currentColor\"\n        />\n      </symbol>\n      <symbol id={DOCUMENT_ID}>\n        {/* https://github.com/storybookjs/icons/blob/main/src/icons/DocumentIcon.tsx */}\n        <path\n          d=\"M4 5.5a.5.5 0 01.5-.5h5a.5.5 0 010 1h-5a.5.5 0 01-.5-.5zM4.5 7.5a.5.5 0 000 1h5a.5.5 0 000-1h-5zM4 10.5a.5.5 0 01.5-.5h5a.5.5 0 010 1h-5a.5.5 0 01-.5-.5z\"\n          fill=\"currentColor\"\n        />\n        <path\n          fillRule=\"evenodd\"\n          clipRule=\"evenodd\"\n          d=\"M1.5 0a.5.5 0 00-.5.5v13a.5.5 0 00.5.5h11a.5.5 0 00.5-.5V3.207a.5.5 0 00-.146-.353L10.146.146A.5.5 0 009.793 0H1.5zM2 1h7.5v2a.5.5 0 00.5.5h2V13H2V1z\"\n          fill=\"currentColor\"\n        />\n      </symbol>\n      <symbol id={STORY_ID}>\n        {/* https://github.com/storybookjs/icons/blob/main/src/icons/BookmarkHollowIcon.tsx */}\n        <path\n          fillRule=\"evenodd\"\n          clipRule=\"evenodd\"\n          d=\"M3.5 0h7a.5.5 0 01.5.5v13a.5.5 0 01-.454.498.462.462 0 01-.371-.118L7 11.159l-3.175 2.72a.46.46 0 01-.379.118A.5.5 0 013 13.5V.5a.5.5 0 01.5-.5zM4 12.413l2.664-2.284a.454.454 0 01.377-.128.498.498 0 01.284.12L10 12.412V1H4v11.413z\"\n          fill=\"currentColor\"\n        />\n      </symbol>\n      <symbol id={TEST_ID}>\n        {/* https://github.com/storybookjs/icons/blob/main/src/icons/BeakerIcon.tsx */}\n        <path\n          fillRule=\"evenodd\"\n          clipRule=\"evenodd\"\n          d=\"M4.5 2h.75v3.866l-3.034 5.26A1.25 1.25 0 003.299 13H10.7a1.25 1.25 0 001.083-1.875L8.75 5.866V2h.75a.5.5 0 100-1h-5a.5.5 0 000 1zm1.75 4V2h1.5v4.134l.067.116L8.827 8H5.173l1.01-1.75.067-.116V6zM4.597 9l-1.515 2.625A.25.25 0 003.3 12H10.7a.25.25 0 00.217-.375L9.404 9H4.597z\"\n          fill=\"currentColor\"\n        />\n      </symbol>\n      <symbol id={SUCCESS_ID}>\n        <path\n          fillRule=\"evenodd\"\n          clipRule=\"evenodd\"\n          d=\"M10.854 4.146a.5.5 0 010 .708l-5 5a.5.5 0 01-.708 0l-2-2a.5.5 0 11.708-.708L5.5 8.793l4.646-4.647a.5.5 0 01.708 0z\"\n          fill=\"currentColor\"\n        />\n      </symbol>\n      <symbol id={ERROR_ID}>\n        <path\n          fillRule=\"evenodd\"\n          clipRule=\"evenodd\"\n          d=\"M7 4a3 3 0 100 6 3 3 0 000-6zM3 7a4 4 0 118 0 4 4 0 01-8 0z\"\n          fill=\"currentColor\"\n        />\n      </symbol>\n      <symbol id={WARNING_ID}>\n        <path\n          fillRule=\"evenodd\"\n          clipRule=\"evenodd\"\n          d=\"M7.206 3.044a.498.498 0 01.23.212l3.492 5.985a.494.494 0 01.006.507.497.497 0 01-.443.252H3.51a.499.499 0 01-.437-.76l3.492-5.984a.497.497 0 01.642-.212zM7 4.492L4.37 9h5.26L7 4.492z\"\n          fill=\"currentColor\"\n        />\n      </symbol>\n      <symbol id={DOT_ID}>\n        <circle cx=\"3\" cy=\"3\" r=\"3\" fill=\"currentColor\" />\n      </symbol>\n      <symbol id={NEW_ID}>\n        <path\n          d=\"M7 3.5L6.96971 3.68173C6.68873 5.36762 5.36762 6.68873 3.68173 6.96971L3.5 7\"\n          stroke=\"currentColor\"\n          strokeLinecap=\"round\"\n          fill=\"none\"\n        />\n        <path\n          d=\"M7 3.5L7.03029 3.68173C7.31127 5.36762 8.63238 6.68873 10.3183 6.96971L10.5 7\"\n          stroke=\"currentColor\"\n          strokeLinecap=\"round\"\n          fill=\"none\"\n        />\n        <path\n          d=\"M7 10.5L6.96971 10.3183C6.68873 8.63238 5.36762 7.31127 3.68173 7.03029L3.5 7\"\n          stroke=\"currentColor\"\n          strokeLinecap=\"round\"\n          fill=\"none\"\n        />\n        <path\n          d=\"M7 10.5L7.03029 10.3183C7.31127 8.63238 8.63238 7.31127 10.3183 7.03029L10.5 7\"\n          stroke=\"currentColor\"\n          strokeLinecap=\"round\"\n          fill=\"none\"\n        />\n        <path d=\"M7 4.5L4.5 7L7 9.5L9.5 7L7 4.5Z\" fill=\"currentColor\" />\n      </symbol>\n      <symbol id={MODIFIED_ID}>\n        <circle cx=\"7\" cy=\"7\" r=\"3\" fill=\"currentColor\" />\n      </symbol>\n      <symbol id={AFFECTED_ID}>\n        <circle cx=\"7\" cy=\"7\" r=\"2\" fill=\"currentColor\" />\n        <path\n          d=\"M7 3.5A3.5 3.5 0 0 0 7 10.5\"\n          stroke=\"currentColor\"\n          strokeWidth=\"1\"\n          strokeLinecap=\"round\"\n          fill=\"none\"\n        />\n        <path\n          d=\"M7 3.5A3.5 3.5 0 0 1 7 10.5\"\n          stroke=\"currentColor\"\n          strokeWidth=\"1\"\n          strokeLinecap=\"round\"\n          fill=\"none\"\n        />\n      </symbol>\n    </Svg>\n  );\n};\n\nexport const UseSymbol: FC<{\n  type:\n    | 'group'\n    | 'component'\n    | 'document'\n    | 'story'\n    | 'test'\n    | 'success'\n    | 'error'\n    | 'warning'\n    | 'dot'\n    | 'new'\n    | 'modified'\n    | 'affected';\n}> = ({ type }) => {\n  if (type === 'group') {\n    return <use xlinkHref={`#${GROUP_ID}`} />;\n  }\n\n  if (type === 'component') {\n    return <use xlinkHref={`#${COMPONENT_ID}`} />;\n  }\n\n  if (type === 'document') {\n    return <use xlinkHref={`#${DOCUMENT_ID}`} />;\n  }\n\n  if (type === 'story') {\n    return <use xlinkHref={`#${STORY_ID}`} />;\n  }\n\n  if (type === 'test') {\n    return <use xlinkHref={`#${TEST_ID}`} />;\n  }\n\n  if (type === 'success') {\n    return <use xlinkHref={`#${SUCCESS_ID}`} />;\n  }\n\n  if (type === 'error') {\n    return <use xlinkHref={`#${ERROR_ID}`} />;\n  }\n\n  if (type === 'warning') {\n    return <use xlinkHref={`#${WARNING_ID}`} />;\n  }\n\n  if (type === 'dot') {\n    return <use xlinkHref={`#${DOT_ID}`} />;\n  }\n\n  if (type === 'new') {\n    return <use xlinkHref={`#${NEW_ID}`} />;\n  }\n\n  if (type === 'modified') {\n    return <use xlinkHref={`#${MODIFIED_ID}`} />;\n  }\n\n  if (type === 'affected') {\n    return <use xlinkHref={`#${AFFECTED_ID}`} />;\n  }\n\n  return null;\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/Loader.tsx",
    "content": "import type { FC } from 'react';\nimport React, { Fragment } from 'react';\n\nimport { styled } from 'storybook/theming';\n\nconst LOADER_SEQUENCE = [0, 0, 1, 1, 2, 3, 3, 3, 1, 1, 1, 2, 2, 2, 3];\n\nconst Loadingitem = styled.div<{\n  depth?: number;\n}>(\n  {\n    cursor: 'progress',\n    fontSize: 13,\n    height: '16px',\n    marginTop: 4,\n    marginBottom: 4,\n    alignItems: 'center',\n    overflow: 'hidden',\n  },\n  ({ depth = 0 }) => ({\n    marginLeft: depth * 15,\n    maxWidth: 85 - depth * 5,\n  }),\n  ({ theme }) => theme.animation.inlineGlow,\n  ({ theme }) => ({\n    background: theme.appBorderColor,\n  })\n);\n\nexport const Contained = styled.div({\n  display: 'flex',\n  flexDirection: 'column',\n  paddingLeft: 20,\n  paddingRight: 20,\n});\n\ninterface LoaderProps {\n  /**\n   * The number of lines to display in the loader. These are indented according to a pre-defined\n   * sequence of depths.\n   */\n  size: number;\n}\n\nexport const Loader: FC<LoaderProps> = ({ size }) => {\n  const repeats = Math.ceil(size / LOADER_SEQUENCE.length);\n  // Creates an array that repeats LOADER_SEQUENCE depths in order, until the size is reached.\n  const sequence = Array.from(Array(repeats)).fill(LOADER_SEQUENCE).flat().slice(0, size);\n  return (\n    <Fragment>\n      {sequence.map((depth, index) => (\n        <Loadingitem depth={depth} key={index} />\n      ))}\n    </Fragment>\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/Menu.stories.tsx",
    "content": "import React from 'react';\n\nimport { TooltipLinkList } from 'storybook/internal/components';\n\nimport { LinkIcon } from '@storybook/icons';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { ManagerContext } from 'storybook/manager-api';\nimport { expect, fn, screen, userEvent, waitFor, within } from 'storybook/test';\nimport { styled } from 'storybook/theming';\n\nimport { initialState } from '../../../shared/checklist-store/checklistData.state.ts';\nimport { useMenu } from '../../container/Menu.tsx';\nimport { internal_universalChecklistStore as mockStore } from '../../manager-stores.mock.ts';\nimport { LayoutProvider } from '../layout/LayoutProvider.tsx';\nimport { type MenuList, SidebarMenu } from './Menu.tsx';\n\nconst getAPIMocks = () => ({\n  getShortcutKeys: fn()\n    .mockName('api::getShortcutKeys')\n    .mockImplementation(() => ({})),\n  getAddonsShortcuts: fn()\n    .mockName('api::getAddonsShortcuts')\n    .mockImplementation(() => ({})),\n  versionUpdateAvailable: fn()\n    .mockName('api::versionUpdateAvailable')\n    .mockImplementation(() => false),\n  isWhatsNewUnread: fn()\n    .mockName('api::isWhatsNewUnread')\n    .mockImplementation(() => false),\n  getDocsUrl: fn()\n    .mockName('api::getDocsUrl')\n    .mockImplementation(() => 'https://storybook.js.org/docs/'),\n  toggleNav: fn().mockName('api::toggleNav'),\n  toggleToolbar: fn().mockName('api::toggleToolbar'),\n  togglePanel: fn().mockName('api::togglePanel'),\n  jumpToComponent: fn().mockName('api::jumpToComponent'),\n  jumpToStory: fn().mockName('api::jumpToStory'),\n  emit: fn().mockName('api::emit'),\n});\n\nconst fakemenu: MenuList = [\n  [\n    { title: 'has icon', icon: <LinkIcon />, id: 'icon' },\n    { title: 'has no icon', id: 'non' },\n  ],\n];\n\nconst managerContext: any = {\n  state: {},\n  api: {\n    getData: fn().mockName('api::getData'),\n    getIndex: fn().mockName('api::getIndex'),\n    getUrlState: fn().mockName('api::getUrlState'),\n    navigate: fn().mockName('api::navigate'),\n    on: fn().mockName('api::on'),\n    off: fn().mockName('api::off'),\n    once: fn().mockName('api::once'),\n  },\n};\n\nconst meta = {\n  component: SidebarMenu,\n  title: 'Sidebar/Menu',\n  args: {\n    menu: fakemenu,\n  },\n  globals: { sb_theme: 'side-by-side' },\n  decorators: [\n    (storyFn) => (\n      <ManagerContext.Provider value={managerContext}>\n        <LayoutProvider>{storyFn()}</LayoutProvider>\n      </ManagerContext.Provider>\n    ),\n  ],\n  beforeEach: async () => {\n    mockStore.setState({\n      loaded: true,\n      widget: {},\n      items: {\n        ...initialState.items,\n        controls: { status: 'accepted' },\n        renderComponent: { status: 'done' },\n        viewports: { status: 'skipped' },\n      },\n    });\n  },\n} satisfies Meta<typeof SidebarMenu>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Items: Story = {\n  render: () => <TooltipLinkList links={fakemenu} />,\n};\n\nexport const Real: Story = {\n  args: {\n    isHighlighted: true,\n  },\n  // @ts-expect-error (non strict)\n  render: (args) => <SidebarMenu menu={fakemenu} {...args} />,\n};\n\nconst DoubleThemeRenderingHack = styled.div({\n  '#storybook-root > [data-side=\"left\"] > &': {\n    textAlign: 'right',\n  },\n});\n\nexport const Expanded: Story = {\n  globals: { sb_theme: 'light', viewport: 'desktop' },\n  render: () => {\n    const menu = useMenu({\n      api: {\n        ...getAPIMocks(),\n        // @ts-expect-error (Converted from ts-ignore)\n        getShortcutKeys: () => ({}),\n        getAddonsShortcuts: () => ({}),\n        versionUpdateAvailable: () => false,\n        isWhatsNewUnread: () => false,\n        getDocsUrl: () => 'https://storybook.js.org/docs/',\n      },\n      showToolbar: false,\n      isPanelShown: false,\n      isNavShown: false,\n      enableShortcuts: false,\n    });\n    return (\n      <DoubleThemeRenderingHack>\n        <SidebarMenu menu={menu} />\n      </DoubleThemeRenderingHack>\n    );\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    await step('Wait 3 seconds for story to load', async () => {\n      await new Promise((res) => {\n        setTimeout(res, 3000);\n      });\n    });\n\n    await step('Expand menu', async () => {\n      const menuButton = await canvas.findByRole('switch');\n      await userEvent.click(menuButton);\n    });\n\n    await step('Check menu is open', async () => {\n      const aboutStorybookBtn = await screen.findByText(/About your Storybook/);\n      await expect(aboutStorybookBtn).toBeInTheDocument();\n    });\n  },\n  decorators: [\n    (StoryFn) => (\n      <div style={{ height: 800 }}>\n        <StoryFn />\n      </div>\n    ),\n  ],\n};\n\nexport const ExpandedWithShortcuts: Story = {\n  ...Expanded,\n  render: () => {\n    const menu = useMenu({\n      api: {\n        ...getAPIMocks(),\n        // @ts-expect-error (invalid)\n        getShortcutKeys: () => ({\n          shortcutsPage: ['⌘', '⇧​', ','],\n          toggleNav: ['⌥', 'S'],\n          togglePanel: ['⌥', 'A'],\n          toolbar: ['⌥', 'T'],\n          panelPosition: ['⌥', 'D'],\n          fullScreen: ['⌥', 'F'],\n          search: ['⌥', 'K'],\n          prevComponent: ['⌥', '↑'],\n          nextComponent: ['⌥', '↓'],\n          prevStory: ['⌥', '←'],\n          nextStory: ['⌥', '→'],\n          collapseAll: ['⌥', '⇧', '↑'],\n        }),\n        getAddonsShortcuts: () => ({}),\n        versionUpdateAvailable: () => false,\n        isWhatsNewUnread: () => false,\n        getDocsUrl: () => 'https://storybook.js.org/docs/',\n      },\n      showToolbar: false,\n      isPanelShown: false,\n      isNavShown: false,\n      enableShortcuts: true,\n    });\n\n    return (\n      <DoubleThemeRenderingHack>\n        <SidebarMenu menu={menu} />\n      </DoubleThemeRenderingHack>\n    );\n  },\n  play: async (context) => {\n    const canvas = within(context.canvasElement);\n    // This story can have significant loading time.\n    await new Promise((res) => {\n      setTimeout(res, 2000);\n    });\n    const menuButton = await waitFor(() => canvas.findByRole('switch'));\n    await userEvent.click(menuButton);\n    const aboutStorybookBtn = await screen.findByText(/About your Storybook/);\n    await expect(aboutStorybookBtn).toBeInTheDocument();\n    const releaseNotes = canvas.queryByText(/What's new/);\n    await expect(releaseNotes).not.toBeInTheDocument();\n  },\n};\n\nexport const ExpandedWithWhatsNew: Story = {\n  ...Expanded,\n  render: () => {\n    const menu = useMenu({\n      api: {\n        ...getAPIMocks(),\n        // @ts-expect-error (invalid)\n        getShortcutKeys: () => ({}),\n        getAddonsShortcuts: () => ({}),\n        versionUpdateAvailable: () => false,\n        isWhatsNewUnread: () => true,\n        getDocsUrl: () => 'https://storybook.js.org/docs/',\n      },\n      showToolbar: false,\n      isPanelShown: false,\n      isNavShown: false,\n      enableShortcuts: false,\n    });\n\n    return (\n      <DoubleThemeRenderingHack>\n        <SidebarMenu menu={menu} isHighlighted />\n      </DoubleThemeRenderingHack>\n    );\n  },\n  play: async (context) => {\n    const canvas = within(context.canvasElement);\n    await new Promise((res) => {\n      setTimeout(res, 500);\n    });\n    // @ts-expect-error (non strict)\n    await Expanded.play(context);\n    const releaseNotes = await canvas.queryByText(/What's new/);\n    await expect(releaseNotes).not.toBeInTheDocument();\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/Menu.tsx",
    "content": "import type { ComponentProps, FC } from 'react';\nimport React, { useState } from 'react';\n\nimport { ActionList, Button, PopoverProvider, ToggleButton } from 'storybook/internal/components';\n\nimport { CloseIcon, CogIcon } from '@storybook/icons';\n\nimport { transparentize } from 'polished';\nimport { type Theme, css, styled } from 'storybook/theming';\n\nimport type { useMenu } from '../../container/Menu.tsx';\nimport { useLayout } from '../layout/LayoutProvider.tsx';\n\nexport type MenuList = ReturnType<typeof useMenu>;\n\nconst buttonStyleAdditions = ({\n  highlighted,\n  isMobile,\n  theme,\n}: {\n  highlighted: boolean;\n  isMobile: boolean;\n  theme: Theme;\n}) => css`\n  position: relative;\n  overflow: visible;\n  margin-top: 0;\n  z-index: 1;\n  ${isMobile &&\n  `\n    width: 36px;\n    height: 36px;\n  `}\n  ${highlighted &&\n  `\n    &:before,\n    &:after {\n      content: '';\n      position: absolute;\n      top: 6px;\n      right: 6px;\n      width: 5px;\n      height: 5px;\n      z-index: 2;\n      border-radius: 50%;\n      background: ${theme.background.app};\n      border: 1px solid ${theme.background.app};\n      box-shadow: 0 0 0 2px ${theme.background.app};\n    }\n    &:after {\n      background: ${theme.color.positive};\n      border: 1px solid rgba(0, 0, 0, 0.1);\n      box-shadow: 0 0 0 2px ${theme.background.app};\n    }\n    &:hover:after,\n    &:focus-visible:after {\n      box-shadow: 0 0 0 2px ${transparentize(0.88, theme.color.secondary)};\n    }\n  `}\n`;\n\nconst Container = styled.div({\n  minWidth: 250,\n});\n\nexport const SidebarButton = styled(Button)<\n  ComponentProps<typeof Button> & {\n    highlighted: boolean;\n    isMobile: boolean;\n  }\n>(buttonStyleAdditions);\n\nexport const SidebarToggleButton = styled(ToggleButton)<\n  ComponentProps<typeof ToggleButton> & {\n    highlighted: boolean;\n    isMobile: boolean;\n  }\n>(buttonStyleAdditions);\n\nconst MenuButtonGroup = styled.div({\n  display: 'flex',\n  gap: 6,\n});\n\nconst SidebarMenuList: FC<{\n  menu: MenuList;\n  onHide: () => void;\n}> = ({ menu, onHide }) => (\n  <Container>\n    {menu\n      .filter((links) => links.length)\n      .flatMap((links) => (\n        <ActionList key={links.map((link) => link.id).join('_')}>\n          {links.map((link) => {\n            const linkContent = (\n              <>\n                {(link.icon || link.input) && (\n                  <ActionList.Icon>{link.icon || link.input}</ActionList.Icon>\n                )}\n                {(link.title || link.center) && (\n                  <ActionList.Text>{link.title || link.center}</ActionList.Text>\n                )}\n                {link.right}\n              </>\n            );\n\n            return (\n              <ActionList.Item key={link.id} active={link.active}>\n                <ActionList.Action\n                  asChild={!!link.href}\n                  ariaLabel={false}\n                  id={`list-item-${link.id}`}\n                  disabled={link.disabled}\n                  onClick={(e) => {\n                    // Prevent interaction with disabled links\n                    if (link.disabled) {\n                      e.preventDefault();\n                      return;\n                    }\n                    // Prevent browser navigation for internal links, where we'll use our\n                    // router API instead, but want to show an `href` for UX/SEO purposes.\n                    if (link.href && link.internal) {\n                      e.preventDefault();\n                    }\n                    link.onClick?.(e, {\n                      id: link.id,\n                      active: link.active,\n                      disabled: link.disabled,\n                      title: link.title,\n                      href: link.href,\n                    });\n                    if (link.closeOnClick) {\n                      onHide();\n                    }\n                  }}\n                >\n                  {link.href ? (\n                    <a\n                      href={link.href}\n                      target={link.internal ? undefined : '_blank'}\n                      rel={link.internal ? 'canonical' : 'noreferrer'}\n                    >\n                      {linkContent}\n                    </a>\n                  ) : (\n                    linkContent\n                  )}\n                </ActionList.Action>\n              </ActionList.Item>\n            );\n          })}\n        </ActionList>\n      ))}\n  </Container>\n);\n\nexport interface SidebarMenuProps {\n  menu: MenuList;\n  isHighlighted?: boolean;\n  onClick?: React.MouseEventHandler<HTMLButtonElement>;\n}\n\nexport const SidebarMenu: FC<SidebarMenuProps> = ({ menu, isHighlighted, onClick }) => {\n  const [isTooltipVisible, setIsTooltipVisible] = useState(false);\n  const { isMobile, setMobileMenuOpen } = useLayout();\n\n  if (isMobile) {\n    return (\n      <MenuButtonGroup>\n        <SidebarButton\n          padding=\"small\"\n          variant=\"ghost\"\n          ariaLabel=\"About Storybook\"\n          highlighted={!!isHighlighted}\n          onClick={(e) => {\n            onClick?.(e);\n            e.preventDefault();\n          }}\n          isMobile={true}\n          asChild\n        >\n          <a href=\"./?path=/settings/about\" rel=\"canonical\">\n            <CogIcon />\n          </a>\n        </SidebarButton>\n        <SidebarButton\n          padding=\"small\"\n          variant=\"ghost\"\n          ariaLabel=\"Close menu\"\n          highlighted={false}\n          onClick={() => setMobileMenuOpen(false)}\n          isMobile={true}\n        >\n          <CloseIcon />\n        </SidebarButton>\n      </MenuButtonGroup>\n    );\n  }\n\n  return (\n    <PopoverProvider\n      ariaLabel=\"Storybook menu\"\n      placement={'bottom-start'}\n      padding={0}\n      popover={({ onHide }) => <SidebarMenuList onHide={onHide} menu={menu} />}\n      onVisibleChange={setIsTooltipVisible}\n    >\n      <SidebarToggleButton\n        ariaLabel=\"Settings\"\n        pressed={isTooltipVisible}\n        highlighted={!!isHighlighted}\n        padding=\"small\"\n        variant=\"ghost\"\n        size=\"medium\"\n        isMobile={false}\n      >\n        <CogIcon />\n      </SidebarToggleButton>\n    </PopoverProvider>\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/NoResults.tsx",
    "content": "import { styled } from 'storybook/theming';\n\nexport const NoResults = styled.div(({ theme }) => ({\n  display: 'flex',\n  flexDirection: 'column',\n  textAlign: 'center',\n  textWrap: 'balance',\n  gap: 4,\n  padding: '20px 0',\n  lineHeight: `18px`,\n  fontSize: `${theme.typography.size.s2}px`,\n  color: theme.color.defaultText,\n  small: {\n    color: theme.textMutedColor,\n    fontSize: `${theme.typography.size.s1}px`,\n  },\n}));\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/RefBlocks.tsx",
    "content": "import type { FC } from 'react';\nimport React, { Fragment, useCallback, useState } from 'react';\n\nimport { logger } from 'storybook/internal/client-logger';\nimport {\n  Button,\n  ErrorFormatter,\n  Link,\n  PopoverProvider,\n  Spaced,\n} from 'storybook/internal/components';\n\nimport { global } from '@storybook/global';\nimport { ChevronDownIcon, LockIcon, SyncIcon } from '@storybook/icons';\n\nimport { styled } from 'storybook/theming';\n\nimport { useLayout } from '../layout/LayoutProvider.tsx';\nimport { Contained, Loader } from './Loader.tsx';\nimport { NoResults } from './NoResults.tsx';\n\nconst { window: globalWindow } = global;\n\nconst TextStyle = styled.div(({ theme }) => ({\n  fontSize: theme.typography.size.s2,\n  lineHeight: '20px',\n  margin: 0,\n}));\nconst Text = styled.div(({ theme }) => ({\n  fontSize: theme.typography.size.s2,\n  lineHeight: '20px',\n  margin: 0,\n\n  code: {\n    fontSize: theme.typography.size.s1,\n  },\n\n  ul: {\n    paddingLeft: 20,\n    marginTop: 8,\n    marginBottom: 8,\n  },\n}));\n\nconst ErrorDisplay = styled.pre<{ isMobile: boolean }>(\n  {\n    boxSizing: 'border-box',\n    borderRadius: 8,\n    overflow: 'auto',\n    whiteSpace: 'pre',\n  },\n  ({ isMobile }) =>\n    isMobile\n      ? {\n          maxWidth: 'calc(100vw - 40px)',\n        }\n      : {\n          minWidth: 420,\n          maxWidth: 640,\n        },\n  ({ theme }) => ({\n    color: theme.color.dark,\n  })\n);\n\nexport const AuthBlock: FC<{ loginUrl: string; id: string }> = ({ loginUrl, id }) => {\n  const [isAuthAttempted, setAuthAttempted] = useState(false);\n\n  const refresh = useCallback(() => {\n    globalWindow.document.location.reload();\n  }, []);\n\n  const open = useCallback<React.MouseEventHandler>((e) => {\n    e.preventDefault();\n    const childWindow = globalWindow.open(loginUrl, `storybook_auth_${id}`, 'resizable,scrollbars');\n\n    // poll for window to close\n    const timer = setInterval(() => {\n      if (!childWindow) {\n        logger.error('unable to access loginUrl window');\n        clearInterval(timer);\n      } else if (childWindow.closed) {\n        clearInterval(timer);\n        setAuthAttempted(true);\n      }\n    }, 1000);\n  }, []);\n\n  return (\n    <Contained>\n      <Spaced>\n        {isAuthAttempted ? (\n          <Fragment>\n            <Text>\n              Authentication on <strong>{loginUrl}</strong> concluded. Refresh the page to fetch\n              this Storybook.\n            </Text>\n            <div>\n              <Button ariaLabel={false} size=\"small\" variant=\"outline\" onClick={refresh}>\n                <SyncIcon />\n                Refresh now\n              </Button>\n            </div>\n          </Fragment>\n        ) : (\n          <Fragment>\n            <Text>Sign in to browse this Storybook.</Text>\n            <div>\n              <Button size=\"small\" variant=\"outline\" onClick={open}>\n                <LockIcon />\n                Sign in\n              </Button>\n            </div>\n          </Fragment>\n        )}\n      </Spaced>\n    </Contained>\n  );\n};\n\nexport const ErrorBlock: FC<{ error: Error }> = ({ error }) => {\n  const { isMobile } = useLayout();\n  return (\n    <Contained>\n      <Spaced>\n        <TextStyle>\n          Oh no! Something went wrong loading this Storybook.\n          <br />\n          <PopoverProvider\n            ariaLabel=\"Error details\"\n            hasCloseButton\n            offset={isMobile ? 0 : 8}\n            placement={isMobile ? 'bottom-end' : 'bottom-start'}\n            popover={\n              <ErrorDisplay isMobile={isMobile}>\n                <ErrorFormatter error={error} />\n              </ErrorDisplay>\n            }\n          >\n            <Link>\n              View error <ChevronDownIcon />\n            </Link>\n          </PopoverProvider>{' '}\n          <Link href=\"https://storybook.js.org/docs?ref=ui\" cancel={false} target=\"_blank\">\n            View docs\n          </Link>\n        </TextStyle>\n      </Spaced>\n    </Contained>\n  );\n};\n\nconst FlexSpaced = styled(Spaced)({\n  display: 'flex',\n});\nconst WideSpaced = styled(Spaced)({\n  flex: 1,\n});\n\nexport const EmptyBlock = ({ isMain, hasEntries }: { isMain: boolean; hasEntries: boolean }) => (\n  <Contained>\n    <FlexSpaced col={1}>\n      <WideSpaced>\n        {hasEntries ? (\n          <NoResults>\n            <strong>No stories found</strong>\n            <small>Your selected filters did not match any stories.</small>\n          </NoResults>\n        ) : isMain ? (\n          <Text>\n            Oh no! Your Storybook is empty. This can happen when:\n            <ul>\n              <li>\n                Your{' '}\n                <Link\n                  href=\"https://storybook.js.org/docs/api/main-config/main-config-stories?ref=ui\"\n                  cancel={false}\n                  target=\"_blank\"\n                >\n                  stories glob configuration\n                </Link>{' '}\n                does not match any files.{' '}\n              </li>\n              <li>\n                You have{' '}\n                <Link\n                  href=\"https://storybook.js.org/docs/writing-stories?ref=ui\"\n                  cancel={false}\n                  target=\"_blank\"\n                >\n                  no stories defined\n                </Link>{' '}\n                in your story files.{' '}\n              </li>\n            </ul>\n          </Text>\n        ) : (\n          <Text>\n            This composed Storybook is empty. Perhaps no stories match your selected filters.\n          </Text>\n        )}\n      </WideSpaced>\n    </FlexSpaced>\n  </Contained>\n);\n\nexport const LoaderBlock: FC<{ isMain: boolean }> = ({ isMain }) => (\n  <Contained>\n    <Loader size={isMain ? 17 : 5} />\n  </Contained>\n);\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/RefIndicator.tsx",
    "content": "import type { FC, MouseEventHandler, ReactNode } from 'react';\nimport React, { forwardRef, useCallback, useMemo } from 'react';\n\nimport { Button, PopoverProvider, Select, Spaced } from 'storybook/internal/components';\n\nimport { global } from '@storybook/global';\nimport {\n  AlertIcon,\n  DocumentIcon,\n  GlobeIcon,\n  LightningIcon,\n  LockIcon,\n  MarkupIcon,\n  TimeIcon,\n} from '@storybook/icons';\n\nimport { useStorybookApi } from 'storybook/manager-api';\nimport { styled, useTheme } from 'storybook/theming';\n\nimport type { NormalLink } from '../../../components/components/tooltip/TooltipLinkList.tsx';\nimport type { getStateType } from '../../utils/tree.ts';\nimport { useLayout } from '../layout/LayoutProvider.tsx';\nimport type { RefType } from './types.ts';\n\nconst { document, window: globalWindow } = global;\n\nexport type ClickHandler = NormalLink['onClick'];\nexport interface IndicatorIconProps {\n  type: ReturnType<typeof getStateType>;\n}\nexport interface CurrentVersionProps {\n  url: string;\n  versions: RefType['versions'];\n}\n\nconst IndicatorPlacement = styled.div(({ theme }) => ({\n  height: 16,\n\n  display: 'flex',\n  alignItems: 'center',\n\n  '& > * + *': {\n    marginLeft: theme.layoutMargin,\n  },\n}));\n\nconst IndicatorClickTarget = styled(Button)(({ theme }) => ({\n  color: theme.textMutedColor,\n  svg: {\n    height: 14,\n    width: 14,\n    padding: 2,\n    transition: 'all 150ms ease-out',\n    color: 'inherit',\n  },\n}));\n\nconst MessageTitle = styled.span(({ theme }) => ({\n  fontWeight: theme.typography.weight.bold,\n}));\n\nconst StyledMessage = styled.a(({ theme }) => ({\n  textDecoration: 'none',\n  lineHeight: '16px',\n  padding: 15,\n  display: 'flex',\n  flexDirection: 'row',\n  alignItems: 'flex-start',\n  color: theme.color.defaultText,\n\n  '&:not(:last-child)': {\n    borderBottom: `1px solid ${theme.appBorderColor}`,\n  },\n  '&:hover': {\n    background: theme.background.hoverable,\n    color: theme.color.defaultText,\n  },\n  '&:link, &:active, &:focus': {\n    color: theme.color.defaultText,\n  },\n  '&:focus-visible': {\n    background: theme.background.hoverable,\n    borderRadius: 8,\n    boxShadow: `inset 0 0 0 2px ${theme.color.secondary}`,\n    outline: 'none',\n  },\n  '& > *': {\n    flex: 1,\n  },\n  '& > svg': {\n    marginTop: 3,\n    width: 16,\n    height: 16,\n    marginRight: 10,\n    flex: 'unset',\n  },\n}));\n\nconst Message: FC<{\n  blank?: boolean;\n  children: ReactNode;\n  href?: string;\n  onClick?: MouseEventHandler;\n}> = ({ href, blank = true, children, onClick }) => {\n  return (\n    <StyledMessage href={href} target={blank ? '_blank' : undefined} onClick={onClick}>\n      {children}\n    </StyledMessage>\n  );\n};\n\nexport const MessageWrapper = styled.div<{\n  isMobile: boolean;\n}>(\n  ({ isMobile }) => ({\n    width: isMobile ? 'calc(100vw - 20px)' : 280,\n    boxSizing: 'border-box',\n    borderRadius: 8,\n    overflow: 'hidden',\n  }),\n  ({ theme }) => ({\n    color: theme.color.dark,\n  })\n);\n\nconst SubtleSelect = styled(Select)(({ theme }) => ({\n  background: 'transparent',\n  color: theme.color.defaultText,\n  fontSize: theme.typography.size.s1,\n  fontWeight: theme.typography.weight.regular,\n}));\n\nexport const RefIndicator = React.memo(\n  forwardRef<HTMLDivElement, RefType & { state: ReturnType<typeof getStateType> }>(\n    ({ state, ...ref }, forwardedRef) => {\n      const api = useStorybookApi();\n      const { isMobile } = useLayout();\n      const list = useMemo(() => Object.values(ref.index || {}), [ref.index]);\n      const componentCount = useMemo(\n        () => list.filter((v) => v.type === 'component').length,\n        [list]\n      );\n      const leafCount = useMemo(\n        () => list.filter((v) => v.type === 'docs' || v.type === 'story').length,\n        [list]\n      );\n\n      const currentVersion = useMemo(() => {\n        if (ref.versions) {\n          return Object.entries(ref.versions).find(([, v]) => v === ref.url)?.[0];\n        }\n        return undefined;\n      }, [ref.versions, ref.url]);\n\n      return (\n        <IndicatorPlacement ref={forwardedRef}>\n          <PopoverProvider\n            ariaLabel=\"Composed Storybook status\"\n            placement={isMobile ? 'bottom' : 'bottom-start'}\n            padding={0}\n            popover={() => (\n              <MessageWrapper isMobile={isMobile}>\n                <Spaced row={0}>\n                  {state === 'loading' && <LoadingMessage url={ref.url} />}\n                  {(state === 'error' || state === 'empty') && (\n                    <ErrorOccurredMessage url={ref.url} />\n                  )}\n                  {state === 'ready' && (\n                    <>\n                      <ReadyMessage {...{ url: ref.url, componentCount, leafCount }} />\n                      {ref.sourceUrl && <SourceCodeMessage url={ref.sourceUrl} />}\n                    </>\n                  )}\n                  {state === 'auth' && <LoginRequiredMessage {...ref} />}\n                  {ref.type === 'auto-inject' && state !== 'error' && (\n                    <PerformanceDegradedMessage />\n                  )}\n                  {state !== 'loading' && <ReadDocsMessage />}\n                </Spaced>\n              </MessageWrapper>\n            )}\n          >\n            <IndicatorClickTarget\n              variant=\"ghost\"\n              padding=\"small\"\n              size=\"small\"\n              data-action=\"toggle-indicator\"\n              ariaLabel=\"Extra actions\"\n            >\n              <GlobeIcon />\n            </IndicatorClickTarget>\n          </PopoverProvider>\n\n          {ref.versions && Object.keys(ref.versions).length ? (\n            <>\n              <SubtleSelect\n                padding=\"small\"\n                size=\"small\"\n                ariaLabel=\"Version\"\n                tooltip=\"Choose version\"\n                defaultOptions={currentVersion}\n                onSelect={(item) => {\n                  // We only pass strings as version ids, so item is always a string\n                  const href = ref.versions?.[item as string];\n                  if (href) {\n                    api.changeRefVersion(ref.id, href);\n                  }\n                }}\n                options={Object.entries(ref.versions).map(([id, href]) => ({\n                  value: id,\n                  title: id,\n                  href,\n                }))}\n              >\n                version\n              </SubtleSelect>\n            </>\n          ) : null}\n        </IndicatorPlacement>\n      );\n    }\n  )\n);\n\nconst ReadyMessage: FC<{\n  url: string;\n  componentCount: number;\n  leafCount: number;\n}> = ({ url, componentCount, leafCount }) => {\n  const theme = useTheme();\n\n  return (\n    <Message href={url.replace(/\\/?$/, '/index.html')}>\n      <GlobeIcon color={theme.color.secondary} />\n      <div>\n        <MessageTitle>View external Storybook</MessageTitle>\n        <div>\n          Explore {componentCount} components and {leafCount} stories in a new browser tab.\n        </div>\n      </div>\n    </Message>\n  );\n};\n\nconst SourceCodeMessage: FC<{\n  url?: string;\n}> = ({ url }) => {\n  const theme = useTheme();\n\n  return (\n    <Message href={url}>\n      <MarkupIcon color={theme.color.secondary} />\n      <div>\n        <MessageTitle>View source code</MessageTitle>\n      </div>\n    </Message>\n  );\n};\n\nconst LoginRequiredMessage: FC<RefType> = ({ loginUrl, id }) => {\n  const theme = useTheme();\n  const open = useCallback<MouseEventHandler>(\n    (e) => {\n      e.preventDefault();\n      const childWindow = globalWindow.open(\n        loginUrl,\n        `storybook_auth_${id}`,\n        'resizable,scrollbars'\n      );\n\n      // poll for window to close\n      const timer = setInterval(() => {\n        if (!childWindow) {\n          clearInterval(timer);\n        } else if (childWindow.closed) {\n          clearInterval(timer);\n          document.location.reload();\n        }\n      }, 1000);\n    },\n    [id, loginUrl]\n  );\n\n  return (\n    <Message onClick={open} blank={false}>\n      <LockIcon color={theme.color.gold} />\n      <div>\n        <MessageTitle>Log in required</MessageTitle>\n        <div>You need to authenticate to view this Storybook's components.</div>\n      </div>\n    </Message>\n  );\n};\n\nconst ReadDocsMessage: FC = () => {\n  const theme = useTheme();\n\n  return (\n    <Message href=\"https://storybook.js.org/docs/sharing/storybook-composition?ref=ui\">\n      <DocumentIcon color={theme.color.green} />\n      <div>\n        <MessageTitle>Read Composition docs</MessageTitle>\n        <div>Learn how to combine multiple Storybooks into one.</div>\n      </div>\n    </Message>\n  );\n};\n\nconst ErrorOccurredMessage: FC<{ url: string }> = ({ url }) => {\n  const theme = useTheme();\n\n  return (\n    <Message href={url.replace(/\\/?$/, '/index.html')}>\n      <AlertIcon color={theme.color.negative} />\n      <div>\n        <MessageTitle>Something went wrong</MessageTitle>\n        <div>This external Storybook didn't load. Debug it in a new tab now.</div>\n      </div>\n    </Message>\n  );\n};\n\nconst LoadingMessage: FC<{ url: string }> = ({ url }) => {\n  const theme = useTheme();\n\n  return (\n    <Message href={url.replace(/\\/?$/, '/index.html')}>\n      <TimeIcon color={theme.color.secondary} />\n      <div>\n        <MessageTitle>Please wait</MessageTitle>\n        <div>This Storybook is loading.</div>\n      </div>\n    </Message>\n  );\n};\n\n// TODO: This is a temporary fix as the documentation link is not available with the 8.0 release, since the features it referenced were removed. See https://storybook.js.org/docs/7/sharing/storybook-composition#improve-your-storybook-composition for context.\nconst PerformanceDegradedMessage: FC = () => {\n  const theme = useTheme();\n\n  return (\n    <Message href=\"https://storybook.js.org/docs/sharing/storybook-composition?ref=ui\">\n      <LightningIcon color={theme.color.gold} />\n      <div>\n        <MessageTitle>Reduce lag</MessageTitle>\n        <div>Learn how to speed up Composition performance.</div>\n      </div>\n    </Message>\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/Refs.stories.tsx",
    "content": "/* eslint-disable local-rules/no-uncategorized-errors */\nimport React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { ManagerContext } from 'storybook/manager-api';\nimport { fn, userEvent, within } from 'storybook/test';\nimport { dedent } from 'ts-dedent';\n\nimport { standardData as standardHeaderData } from './Heading.stories.tsx';\nimport { IconSymbols } from './IconSymbols.tsx';\nimport { Ref } from './Refs.tsx';\nimport { mockDataset } from './mockdata.ts';\nimport type { RefType } from './types.ts';\n\nconst managerContext = {\n  state: { docsOptions: {} },\n  api: {\n    on: fn().mockName('api::on'),\n    off: fn().mockName('api::off'),\n    once: fn().mockName('api::once'),\n    emit: fn().mockName('api::emit'),\n    getElements: fn(() => ({})).mockName('api::getElements'),\n    getShortcutKeys: fn(() => ({})).mockName('api::getShortcutKeys'),\n  },\n} as any;\n\nconst meta = {\n  component: Ref,\n  title: 'Sidebar/Refs',\n  excludeStories: /.*Data$/,\n  parameters: {\n    layout: 'fullscreen',\n    chromatic: { ignoreSelectors: ['[role=\"dialog\"] pre'] },\n  },\n  globals: { sb_theme: 'side-by-side' },\n  decorators: [\n    (storyFn) => (\n      <ManagerContext.Provider value={managerContext}>\n        <IconSymbols />\n        {storyFn()}\n      </ManagerContext.Provider>\n    ),\n    (storyFn) => <div style={{ padding: '0 20px', maxWidth: '230px' }}>{storyFn()}</div>,\n  ],\n} satisfies Meta<typeof Ref>;\n\nexport default meta;\n\nconst { menu } = standardHeaderData;\nconst filteredIndex = mockDataset.withRoot;\nconst storyId = '1-12-121';\n\nexport const simpleData = { menu, filteredIndex, storyId };\nexport const loadingData = { menu, filteredIndex: {} };\n\n// @ts-expect-error (non strict)\nconst indexError: Error = (() => {\n  try {\n    const err = new Error('There was a severe problem');\n    err.stack = dedent`\n      at errorStory (/sb-preview/file.js:000:0001)\n      at hookified (/sb-preview/file.js:000:0001)\n      at defaultDecorateStory (/sb-preview/file.js:000:0001)\n      at jsxDecorator (/assets/file.js:000:0001)\n      at hookified (/sb-preview/file.js:000:0001)\n      at decorateStory (/sb-preview/file.js:000:0001)\n    `;\n    throw err;\n  } catch (e) {\n    return e;\n  }\n})();\n\nconst refs: Record<string, RefType> = {\n  optimized: {\n    id: 'optimized',\n    title: 'It is optimized',\n    url: 'https://example.com',\n    previewInitialized: false,\n    type: 'lazy',\n    // @ts-expect-error (invalid input)\n    filteredIndex,\n    allStatuses: {},\n  },\n  empty: {\n    id: 'empty',\n    title: 'It is empty because no stories were loaded',\n    url: 'https://example.com',\n    type: 'lazy',\n    filteredIndex: {},\n    previewInitialized: false,\n    allStatuses: {},\n  },\n  startInjected_unknown: {\n    id: 'startInjected_unknown',\n    title: 'It started injected and is unknown',\n    url: 'https://example.com',\n    type: 'unknown',\n    previewInitialized: false,\n    // @ts-expect-error (invalid input)\n    filteredIndex,\n    allStatuses: {},\n  },\n  startInjected_loading: {\n    id: 'startInjected_loading',\n    title: 'It started injected and is loading',\n    url: 'https://example.com',\n    type: 'auto-inject',\n    previewInitialized: false,\n    // @ts-expect-error (invalid input)\n    filteredIndex,\n    allStatuses: {},\n  },\n  startInjected_ready: {\n    id: 'startInjected_ready',\n    title: 'It started injected and is ready',\n    url: 'https://example.com',\n    type: 'auto-inject',\n    previewInitialized: true,\n    // @ts-expect-error (invalid input)\n    filteredIndex,\n    allStatuses: {},\n  },\n  versions: {\n    id: 'versions',\n    title: 'It has versions',\n    url: 'https://example.com',\n    type: 'lazy',\n    // @ts-expect-error (invalid input)\n    filteredIndex,\n    versions: { '1.0.0': 'https://example.com/v1', '2.0.0': 'https://example.com' },\n    previewInitialized: true,\n    allStatuses: {},\n  },\n  versionsMissingCurrent: {\n    id: 'versions_missing_current',\n    title: 'It has versions',\n    url: 'https://example.com',\n    type: 'lazy',\n    // @ts-expect-error (invalid input)\n    filteredIndex,\n    versions: { '1.0.0': 'https://example.com/v1', '2.0.0': 'https://example.com/v2' },\n    previewInitialized: true,\n    allStatuses: {},\n  },\n  error: {\n    id: 'error',\n    title: 'This has problems',\n    url: 'https://example.com',\n    type: 'lazy',\n    indexError,\n    previewInitialized: true,\n    allStatuses: {},\n  },\n  auth: {\n    id: 'Authentication',\n    title: 'This requires a login',\n    url: 'https://example.com',\n    type: 'lazy',\n    loginUrl: 'https://example.com',\n    previewInitialized: true,\n    allStatuses: {},\n  },\n  long: {\n    id: 'long',\n    title: 'This storybook has a very very long name for some reason',\n    url: 'https://example.com',\n    // @ts-expect-error (invalid input)\n    filteredIndex,\n    type: 'lazy',\n    versions: {\n      '111.111.888-new': 'https://example.com/new',\n      '111.111.888': 'https://example.com',\n    },\n    previewInitialized: true,\n  },\n  withSourceCode: {\n    id: 'sourceCode',\n    title: 'This has source code',\n    url: 'https://example.com',\n    sourceUrl: 'https://github.com/storybookjs/storybook',\n    previewInitialized: false,\n    type: 'lazy',\n    // @ts-expect-error (invalid input)\n    filteredIndex,\n    allStatuses: {},\n  },\n};\n\nexport const Optimized = () => (\n  <Ref\n    {...refs.optimized}\n    hasEntries={true}\n    isLoading={false}\n    isBrowsing\n    selectedStoryId=\"\"\n    highlightedRef={{ current: null }}\n    setHighlighted={() => {}}\n  />\n);\nexport const NoEntries = () => (\n  <Ref\n    {...refs.empty}\n    hasEntries={false}\n    isLoading={false}\n    isBrowsing\n    selectedStoryId=\"\"\n    highlightedRef={{ current: null }}\n    setHighlighted={() => {}}\n  />\n);\nexport const IsEmpty = () => (\n  <Ref\n    {...refs.empty}\n    hasEntries={true}\n    isLoading={false}\n    isBrowsing\n    selectedStoryId=\"\"\n    highlightedRef={{ current: null }}\n    setHighlighted={() => {}}\n  />\n);\nexport const StartInjectedUnknown = () => (\n  <Ref\n    {...refs.startInjected_unknown}\n    hasEntries={true}\n    isLoading={false}\n    isBrowsing\n    selectedStoryId=\"\"\n    highlightedRef={{ current: null }}\n    setHighlighted={() => {}}\n  />\n);\nexport const StartInjectedLoading = () => (\n  <Ref\n    {...refs.startInjected_loading}\n    hasEntries={true}\n    isLoading={false}\n    isBrowsing\n    selectedStoryId=\"\"\n    highlightedRef={{ current: null }}\n    setHighlighted={() => {}}\n  />\n);\nexport const StartInjectedReady = () => (\n  <Ref\n    {...refs.startInjected_ready}\n    hasEntries={true}\n    isLoading={false}\n    isBrowsing\n    selectedStoryId=\"\"\n    highlightedRef={{ current: null }}\n    setHighlighted={() => {}}\n  />\n);\nexport const Versions = () => (\n  <Ref\n    {...refs.versions}\n    hasEntries={true}\n    isLoading={false}\n    isBrowsing\n    selectedStoryId=\"\"\n    highlightedRef={{ current: null }}\n    setHighlighted={() => {}}\n  />\n);\nexport const VersionsMissingCurrent = () => (\n  <Ref\n    {...refs.versionsMissingCurrent}\n    hasEntries={true}\n    isLoading={false}\n    isBrowsing\n    selectedStoryId=\"\"\n    highlightedRef={{ current: null }}\n    setHighlighted={() => {}}\n  />\n);\nexport const Errored = () => (\n  <Ref\n    {...refs.error}\n    hasEntries={true}\n    isLoading={false}\n    isBrowsing\n    selectedStoryId=\"\"\n    highlightedRef={{ current: null }}\n    setHighlighted={() => {}}\n  />\n);\nexport const ErroredMobile = () => (\n  <Ref\n    {...refs.error}\n    hasEntries={true}\n    isLoading={false}\n    isBrowsing\n    selectedStoryId=\"\"\n    highlightedRef={{ current: null }}\n    setHighlighted={() => {}}\n  />\n);\nErroredMobile.globals = { sb_theme: 'stacked', viewport: { value: 'mobile1' } };\nexport const ErroredWithErrorOpen: StoryObj = {\n  render: () => Errored(),\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const button = await canvas.findByText('View error');\n    await userEvent.click(button);\n  },\n};\nexport const ErroredMobileWithErrorOpen: StoryObj = {\n  render: () => ErroredMobile(),\n  globals: { sb_theme: 'stacked', viewport: { value: 'mobile1' } },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const button = await canvas.findByText('View error');\n    await userEvent.click(button);\n  },\n};\nexport const ErroredWithIndicatorOpen: StoryObj = {\n  render: () => Errored(),\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const button = await canvas.findByRole('button', { name: 'Extra actions' });\n    await userEvent.click(button);\n  },\n};\nexport const ErroredMobileWithIndicatorOpen: StoryObj = {\n  render: () => ErroredMobile(),\n  globals: { sb_theme: 'stacked', viewport: { value: 'mobile1' } },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const button = await canvas.findByRole('button', { name: 'Extra actions' });\n    await userEvent.click(button);\n  },\n};\nexport const Auth = () => (\n  <Ref\n    {...refs.auth}\n    hasEntries={true}\n    isLoading={false}\n    isBrowsing\n    selectedStoryId=\"\"\n    highlightedRef={{ current: null }}\n    setHighlighted={() => {}}\n  />\n);\nexport const Long = () => (\n  <Ref\n    {...refs.long}\n    hasEntries={true}\n    isLoading={false}\n    isBrowsing\n    selectedStoryId=\"\"\n    highlightedRef={{ current: null }}\n    setHighlighted={() => {}}\n  />\n);\n\nexport const WithSourceCode = () => (\n  <Ref\n    {...refs.withSourceCode}\n    hasEntries={true}\n    isLoading={false}\n    isBrowsing\n    selectedStoryId=\"\"\n    highlightedRef={{ current: null }}\n    setHighlighted={() => {}}\n  />\n);\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/Refs.tsx",
    "content": "import type { FC, MutableRefObject } from 'react';\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { useStorybookApi, useStorybookState } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport { getStateType } from '../../utils/tree.ts';\nimport { AuthBlock, EmptyBlock, ErrorBlock, LoaderBlock } from './RefBlocks.tsx';\nimport { RefIndicator } from './RefIndicator.tsx';\nimport { DEFAULT_REF_ID } from './Sidebar.tsx';\nimport { Tree } from './Tree.tsx';\nimport { CollapseIcon } from './components/CollapseIcon.tsx';\nimport type { Highlight, RefType } from './types.ts';\n\nexport interface RefProps {\n  isLoading: boolean;\n  isBrowsing: boolean;\n  hasEntries: boolean;\n  selectedStoryId: string | null;\n  highlightedRef: MutableRefObject<Highlight>;\n  setHighlighted: (highlight: Highlight) => void;\n}\n\nconst Wrapper = styled.div<{ isMain: boolean }>(({ isMain }) => ({\n  position: 'relative',\n  marginTop: isMain ? undefined : 0,\n}));\n\nconst RefHead = styled.div(({ theme }) => ({\n  fontWeight: theme.typography.weight.bold,\n  fontSize: theme.typography.size.s2,\n\n  // Similar to ListItem.tsx\n  textDecoration: 'none',\n  lineHeight: '16px',\n  display: 'flex',\n  alignItems: 'center',\n  justifyContent: 'space-between',\n  background: 'transparent',\n\n  width: '100%',\n  marginTop: 20,\n  paddingTop: 16,\n  paddingBottom: 12,\n  borderTop: `1px solid ${theme.appBorderColor}`,\n\n  color: theme.color.defaultText,\n}));\n\nconst RefTitle = styled.div({\n  textOverflow: 'ellipsis',\n  whiteSpace: 'nowrap',\n  flex: 1,\n  overflow: 'hidden',\n  marginLeft: 2,\n});\n\nconst CollapseButton = styled.button(({ theme }) => ({\n  all: 'unset',\n  display: 'flex',\n  padding: '0px 8px',\n  gap: 6,\n  alignItems: 'center',\n  cursor: 'pointer',\n  overflow: 'hidden',\n\n  '&:focus': {\n    borderColor: theme.color.secondary,\n    'span:first-of-type': {\n      borderLeftColor: theme.color.secondary,\n    },\n  },\n}));\n\nexport const Ref: FC<RefType & RefProps> = React.memo(function Ref(props) {\n  const { docsOptions } = useStorybookState();\n  const api = useStorybookApi();\n  const {\n    filteredIndex: index,\n    id: refId,\n    title = refId,\n    isLoading: isLoadingMain,\n    isBrowsing,\n    hasEntries,\n    selectedStoryId,\n    highlightedRef,\n    setHighlighted,\n    loginUrl,\n    type,\n    expanded = true,\n    indexError,\n    previewInitialized,\n    allStatuses,\n  } = props;\n\n  const length = useMemo(() => (index ? Object.keys(index).length : 0), [index]);\n  const indicatorRef = useRef(null);\n\n  const isMain = refId === DEFAULT_REF_ID;\n  const isLoadingInjected =\n    (type === 'auto-inject' && !previewInitialized) || type === 'server-checked';\n  const isLoading = isLoadingMain || isLoadingInjected || type === 'unknown';\n  const isError = !!indexError;\n  const isEmpty = !isLoading && length === 0;\n  const isAuthRequired = !!loginUrl && length === 0;\n\n  const state = getStateType(isLoading, isAuthRequired, isError, isEmpty);\n  const [isExpanded, setExpanded] = useState<boolean>(expanded);\n\n  useEffect(() => {\n    if (index && selectedStoryId && index[selectedStoryId]) {\n      setExpanded(true);\n    }\n  }, [setExpanded, index, selectedStoryId]);\n\n  const handleClick = useCallback(() => setExpanded((value) => !value), [setExpanded]);\n\n  const setHighlightedItemId = useCallback(\n    (itemId: string) => setHighlighted({ itemId, refId }),\n    [setHighlighted, refId]\n  );\n\n  const onSelectStoryId = useCallback(\n    (storyId: string) => api?.selectStory(storyId, undefined, { ref: isMain ? undefined : refId }),\n    [api, isMain, refId]\n  );\n\n  return (\n    <>\n      {isMain || (\n        <RefHead\n          aria-label={`${isExpanded ? 'Hide' : 'Show'} ${title} stories`}\n          aria-expanded={isExpanded}\n        >\n          <CollapseButton data-action=\"collapse-ref\" onClick={handleClick}>\n            <CollapseIcon isExpanded={isExpanded} />\n            <RefTitle title={title}>{title}</RefTitle>\n          </CollapseButton>\n          <RefIndicator {...props} state={state} ref={indicatorRef} />\n        </RefHead>\n      )}\n      {isExpanded && (\n        <Wrapper data-title={title} isMain={isMain}>\n          {/* @ts-expect-error (non strict) */}\n          {state === 'auth' && <AuthBlock id={refId} loginUrl={loginUrl} />}\n          {/* @ts-expect-error (non strict) */}\n          {state === 'error' && <ErrorBlock error={indexError} />}\n          {state === 'loading' && <LoaderBlock isMain={isMain} />}\n          {state === 'empty' && <EmptyBlock isMain={isMain} hasEntries={hasEntries} />}\n          {state === 'ready' && (\n            <Tree\n              allStatuses={allStatuses}\n              isBrowsing={isBrowsing}\n              isMain={isMain}\n              refId={refId}\n              // @ts-expect-error (non strict)\n              data={index}\n              // @ts-expect-error (non strict)\n              docsMode={docsOptions.docsMode}\n              selectedStoryId={selectedStoryId}\n              onSelectStoryId={onSelectStoryId}\n              highlightedRef={highlightedRef}\n              setHighlightedItemId={setHighlightedItemId}\n            />\n          )}\n        </Wrapper>\n      )}\n    </>\n  );\n});\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/Search.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryFn } from '@storybook/react-vite';\n\nimport { action } from 'storybook/actions';\nimport type { API } from 'storybook/manager-api';\nimport { ManagerContext } from 'storybook/manager-api';\n\nimport { IconSymbols } from './IconSymbols.tsx';\nimport { Search } from './Search.tsx';\nimport type { SearchProps } from './Search.tsx';\nimport { SearchResults } from './SearchResults.tsx';\nimport { noResults } from './SearchResults.stories.tsx';\nimport { DEFAULT_REF_ID } from './Sidebar.tsx';\nimport { index } from './mockdata.large.ts';\nimport type { Selection } from './types.ts';\n\nconst refId = DEFAULT_REF_ID;\nconst data = { [refId]: { id: refId, url: '/', index, previewInitialized: true, allStatuses: {} } };\nconst dataset = { hash: data, entries: Object.entries(data) };\nconst getLastViewed = () =>\n  Object.values(index)\n    .filter((item, i) => item.type === 'component' && item.parent && i % 20 === 0)\n    .map((component) => ({ storyId: component.id, refId }));\n\nconst meta = {\n  component: Search,\n  title: 'Sidebar/Search',\n  parameters: { layout: 'fullscreen' },\n  globals: { sb_theme: 'side-by-side' },\n  decorators: [\n    (storyFn: any) => (\n      <div\n        style={{\n          display: 'flex',\n          flexDirection: 'column',\n          gap: 16,\n          padding: 20,\n          maxWidth: '230px',\n        }}\n      >\n        <IconSymbols />\n        {storyFn()}\n      </div>\n    ),\n  ],\n} satisfies Meta<typeof Search>;\nexport default meta;\n\nconst baseProps: Omit<SearchProps, 'children'> = {\n  dataset,\n  getLastViewed: () => [] as Selection[],\n};\n\nexport const Simple: StoryFn = () => <Search {...baseProps}>{() => null}</Search>;\n\nexport const SimpleWithCreateButton: StoryFn = () => <Search {...baseProps}>{() => null}</Search>;\n\nexport const FilledIn: StoryFn = () => (\n  <Search {...baseProps} initialQuery=\"Foo bar\">\n    {() => <SearchResults {...noResults} />}\n  </Search>\n);\n\nexport const LastViewed: StoryFn = () => (\n  <Search {...baseProps} getLastViewed={getLastViewed}>\n    {({ query, results, closeMenu, getMenuProps, getItemProps, highlightedIndex }) => (\n      <SearchResults\n        query={query}\n        results={results}\n        closeMenu={closeMenu}\n        getMenuProps={getMenuProps}\n        getItemProps={getItemProps}\n        highlightedIndex={highlightedIndex}\n      />\n    )}\n  </Search>\n);\n\nexport const ShortcutsDisabled: StoryFn = () => (\n  <Search {...baseProps} enableShortcuts={false}>\n    {() => null}\n  </Search>\n);\n\nexport const CustomShortcuts: StoryFn = () => <Search {...baseProps}>{() => null}</Search>;\n\nCustomShortcuts.decorators = [\n  (storyFn) => (\n    <ManagerContext.Provider\n      value={\n        {\n          api: {\n            getShortcutKeys: () => ({ search: ['control', 'shift', 's'] }),\n          } as API,\n        } as any\n      }\n    >\n      {storyFn()}\n    </ManagerContext.Provider>\n  ),\n];\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/Search.tsx",
    "content": "import React, { type ReactNode, useCallback, useRef, useState } from 'react';\n\nimport { Button } from 'storybook/internal/components';\n\nimport { global } from '@storybook/global';\nimport { CloseIcon, SearchIcon } from '@storybook/icons';\n\nimport type { DownshiftState, StateChangeOptions } from 'downshift';\nimport Downshift from 'downshift';\nimport type { FuseOptions } from 'fuse.js';\nimport Fuse from 'fuse.js';\nimport { shortcutToHumanString, useStorybookApi } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport { useLandmark } from '../../hooks/useLandmark.ts';\nimport { getGroupStatus, getMostCriticalStatusValue } from '../../utils/status.tsx';\nimport { scrollIntoView, searchItem } from '../../utils/tree.ts';\nimport { useLayout } from '../layout/LayoutProvider.tsx';\nimport { DEFAULT_REF_ID } from './Sidebar.tsx';\nimport type {\n  CombinedDataset,\n  DownshiftItem,\n  SearchChildrenFn,\n  SearchItem,\n  SearchResult,\n  Selection,\n} from './types.ts';\nimport { isExpandType, isSearchResult } from './types.ts';\n\nconst { document } = global;\n\nconst DEFAULT_MAX_SEARCH_RESULTS = 50;\n\nconst options = {\n  shouldSort: true,\n  tokenize: true,\n  findAllMatches: true,\n  includeScore: true,\n  includeMatches: true,\n  threshold: 0.2,\n  location: 0,\n  distance: 100,\n  maxPatternLength: 32,\n  minMatchCharLength: 1,\n  keys: [\n    { name: 'name', weight: 0.7 },\n    { name: 'path', weight: 0.3 },\n  ],\n} as FuseOptions<SearchItem>;\n\nconst SearchBar = styled.div({\n  display: 'flex',\n  flexDirection: 'row',\n  columnGap: 6,\n});\n\nconst ScreenReaderLabel = styled.label({\n  position: 'absolute',\n  left: -10000,\n  top: 'auto',\n  width: 1,\n  height: 1,\n  overflow: 'hidden',\n});\n\nconst SearchField = styled.div<{ isMobile: boolean }>(({ theme, isMobile }) => ({\n  display: 'flex',\n  flexDirection: 'row',\n  alignItems: 'center',\n  padding: isMobile ? 4 : 2,\n  flexGrow: 1,\n  height: isMobile ? 36 : 32,\n  width: '100%',\n  boxShadow: `${theme.button.border} 0 0 0 1px inset`,\n  borderRadius: theme.appBorderRadius + 2,\n\n  '&:has(input:focus), &:has(input:active)': {\n    background: theme.background.app,\n    outline: `2px solid ${theme.color.secondary}`,\n    outlineOffset: 2,\n  },\n}));\n\nconst IconWrapper = styled.div(({ theme, onClick }) => ({\n  cursor: onClick ? 'pointer' : 'default',\n  flex: '0 0 28px',\n  height: '100%',\n  pointerEvents: onClick ? 'auto' : 'none',\n  color: theme.textMutedColor,\n  display: 'flex',\n  alignItems: 'center',\n  justifyContent: 'center',\n}));\n\nconst Input = styled.input<{ isMobile: boolean }>(({ theme, isMobile }) => ({\n  appearance: 'none',\n  height: 28,\n  width: '100%',\n  padding: 0,\n  border: 0,\n  background: 'transparent',\n  fontSize: isMobile ? '16px' : `${theme.typography.size.s1 + 1}px`,\n  fontFamily: 'inherit',\n  transition: 'all 150ms',\n  color: theme.color.defaultText,\n  outline: 0,\n\n  '&::placeholder': {\n    color: theme.textMutedColor,\n    opacity: 1,\n  },\n  '&:valid ~ code, &:focus ~ code': {\n    display: 'none',\n  },\n  '&:invalid ~ svg': {\n    display: 'none',\n  },\n  '&:valid ~ svg': {\n    display: 'block',\n  },\n  '&::-ms-clear': {\n    display: 'none',\n  },\n  '&::-webkit-search-decoration, &::-webkit-search-cancel-button, &::-webkit-search-results-button, &::-webkit-search-results-decoration':\n    {\n      display: 'none',\n    },\n}));\n\nconst FocusKey = styled.code(({ theme }) => ({\n  margin: 5,\n  marginTop: 6,\n  height: 16,\n  fontFamily: theme.typography.fonts.base,\n  lineHeight: '16px',\n  textAlign: 'center',\n  fontSize: '11px',\n  color: theme.base === 'light' ? theme.color.dark : theme.textMutedColor,\n  userSelect: 'none',\n  pointerEvents: 'none',\n  display: 'flex',\n  alignItems: 'center',\n  gap: 4,\n  flexShrink: 0,\n}));\n\nconst FocusKeyCmd = styled.span({\n  fontSize: '14px',\n});\n\nconst Actions = styled.div({\n  display: 'flex',\n  alignItems: 'center',\n  gap: 2,\n});\n\nconst FocusContainer = styled.div({ outline: 0 });\n\nexport type SearchProps = {\n  children: SearchChildrenFn;\n  dataset: CombinedDataset;\n  enableShortcuts?: boolean;\n  getLastViewed: () => Selection[];\n  initialQuery?: string;\n  searchBarContent?: ReactNode;\n  searchFieldContent?: ReactNode;\n};\n\nexport const Search = React.memo<SearchProps>(function Search({\n  children,\n  dataset,\n  enableShortcuts = true,\n  getLastViewed,\n  initialQuery = '',\n  searchBarContent,\n  searchFieldContent,\n}) {\n  const api = useStorybookApi();\n  const inputRef = useRef<HTMLInputElement>(null);\n  const [inputPlaceholder, setPlaceholder] = useState('Find components');\n  const [allComponents, showAllComponents] = useState(false);\n  const searchShortcut = api ? shortcutToHumanString(api.getShortcutKeys().search) : '/';\n\n  const makeFuse = useCallback(() => {\n    const list = dataset.entries.reduce<SearchItem[]>((acc, [refId, { index, allStatuses }]) => {\n      const groupStatus = getGroupStatus(index || {}, allStatuses ?? {});\n\n      if (index) {\n        acc.push(\n          ...Object.values(index).map((item) => {\n            const storyStatuses = allStatuses?.[item.id];\n            const mostCriticalStatusValue = storyStatuses\n              ? getMostCriticalStatusValue(Object.values(storyStatuses).map((s) => s.value))\n              : null;\n            return {\n              ...searchItem(item, dataset.hash[refId]),\n              status: mostCriticalStatusValue ?? groupStatus[item.id] ?? null,\n            };\n          })\n        );\n      }\n      return acc;\n    }, []);\n    return new Fuse(list, options);\n  }, [dataset]);\n\n  const getResults = useCallback(\n    (input: string) => {\n      const fuse = makeFuse();\n\n      if (!input) {\n        return [];\n      }\n\n      let results: DownshiftItem[] = [];\n      const resultIds: Set<string> = new Set();\n      const distinctResults = (fuse.search(input) as SearchResult[]).filter(({ item }) => {\n        if (\n          !(item.type === 'component' || item.type === 'docs' || item.type === 'story') ||\n          // @ts-expect-error (non strict)\n          resultIds.has(item.parent)\n        ) {\n          return false;\n        }\n        resultIds.add(item.id);\n        return true;\n      });\n\n      if (distinctResults.length) {\n        results = distinctResults.slice(0, allComponents ? 1000 : DEFAULT_MAX_SEARCH_RESULTS);\n        if (distinctResults.length > DEFAULT_MAX_SEARCH_RESULTS && !allComponents) {\n          results.push({\n            showAll: () => showAllComponents(true),\n            totalCount: distinctResults.length,\n            moreCount: distinctResults.length - DEFAULT_MAX_SEARCH_RESULTS,\n          });\n        }\n      }\n\n      return results;\n    },\n    [allComponents, makeFuse]\n  );\n\n  const onSelect = useCallback(\n    (selectedItem: DownshiftItem) => {\n      if (isSearchResult(selectedItem)) {\n        const { id, refId } = selectedItem.item;\n        // @ts-expect-error (non strict)\n        api?.selectStory(id, undefined, { ref: refId !== DEFAULT_REF_ID && refId });\n        // @ts-expect-error (non strict)\n        inputRef.current.blur();\n        showAllComponents(false);\n        return;\n      }\n      if (isExpandType(selectedItem)) {\n        selectedItem.showAll();\n      }\n    },\n    [api]\n  );\n\n  const onInputValueChange = useCallback((inputValue: string, stateAndHelpers: any) => {\n    showAllComponents(false);\n  }, []);\n\n  const stateReducer = useCallback(\n    (state: DownshiftState<DownshiftItem>, changes: StateChangeOptions<DownshiftItem>) => {\n      switch (changes.type) {\n        case Downshift.stateChangeTypes.blurInput: {\n          return {\n            ...changes,\n            // Prevent clearing the input on blur\n            inputValue: state.inputValue,\n            // Return to the tree view after selecting an item\n            isOpen: state.inputValue && !state.selectedItem,\n          };\n        }\n\n        case Downshift.stateChangeTypes.mouseUp: {\n          // Prevent clearing the input on refocus\n          return state;\n        }\n\n        case Downshift.stateChangeTypes.keyDownEscape: {\n          if (state.inputValue) {\n            // Clear the inputValue, but don't return to the tree view\n            return { ...changes, inputValue: '', isOpen: true, selectedItem: null };\n          }\n          // When pressing escape a second time return to the tree view\n          // The onKeyDown handler will also blur the input in this case\n          return { ...changes, isOpen: false, selectedItem: null };\n        }\n\n        case Downshift.stateChangeTypes.clickItem:\n        case Downshift.stateChangeTypes.keyDownEnter: {\n          if (isSearchResult(changes.selectedItem)) {\n            // Return to the tree view, but keep the input value\n            return { ...changes, inputValue: state.inputValue };\n          }\n          if (isExpandType(changes.selectedItem)) {\n            // Downshift should completely ignore this\n            return state;\n          }\n          return changes;\n        }\n\n        default:\n          return changes;\n      }\n    },\n    []\n  );\n  const { isMobile } = useLayout();\n\n  const searchLandmarkRef = useRef<HTMLDivElement>(null);\n  const { landmarkProps } = useLandmark({ role: 'search' }, searchLandmarkRef);\n\n  return (\n    // @ts-expect-error (non strict)\n    <Downshift<DownshiftItem>\n      initialInputValue={initialQuery}\n      stateReducer={stateReducer}\n      // @ts-expect-error (Converted from ts-ignore)\n      itemToString={(result) => result?.item?.name || ''}\n      scrollIntoView={(e) => scrollIntoView(e)}\n      onSelect={onSelect}\n      onInputValueChange={onInputValueChange}\n    >\n      {({\n        isOpen,\n        openMenu,\n        closeMenu,\n        inputValue,\n        getInputProps,\n        getItemProps,\n        getLabelProps,\n        getMenuProps,\n        getRootProps,\n        highlightedIndex,\n        reset,\n      }) => {\n        const input = inputValue ? inputValue.trim() : '';\n        let results: DownshiftItem[] = input ? getResults(input) : [];\n\n        const lastViewed = !input && getLastViewed();\n        if (lastViewed && lastViewed.length) {\n          // @ts-expect-error (non strict)\n          results = lastViewed.reduce((acc, { storyId, refId }) => {\n            const data = dataset.hash[refId];\n            if (data && data.index && data.index[storyId]) {\n              const story = data.index[storyId];\n              const item = story.type === 'story' ? data.index[story.parent] : story;\n              // prevent duplicates\n              // @ts-expect-error (non strict)\n              if (!acc.some((res) => res.item.refId === refId && res.item.id === item.id)) {\n                // @ts-expect-error (non strict)\n                acc.push({ item: searchItem(item, dataset.hash[refId]), matches: [], score: 0 });\n              }\n            }\n            return acc;\n          }, []);\n        }\n\n        const inputId = 'storybook-explorer-searchfield';\n        const inputProps = getInputProps({\n          id: inputId,\n          ref: inputRef,\n          required: true,\n          type: 'search',\n          placeholder: inputPlaceholder,\n          onFocus: () => {\n            openMenu();\n            setPlaceholder('Type to find...');\n          },\n          onBlur: () => setPlaceholder('Find components'),\n          onKeyDown: (e) => {\n            // @ts-expect-error (non strict)\n            if (e.key === 'Escape' && inputValue.length === 0) {\n              // When pressing escape while the input is empty, blur the input\n              // The stateReducer will handle returning to the tree view\n              // @ts-expect-error (non strict)\n              inputRef.current.blur();\n            }\n          },\n        });\n\n        const labelProps = getLabelProps({\n          htmlFor: inputId,\n        });\n\n        return (\n          <>\n            <ScreenReaderLabel {...labelProps}>Search for components</ScreenReaderLabel>\n            <SearchBar ref={searchLandmarkRef} {...landmarkProps}>\n              <SearchField\n                {...getRootProps({ refKey: '' }, { suppressRefError: true })}\n                isMobile={isMobile}\n                className=\"search-field\"\n              >\n                <IconWrapper>\n                  <SearchIcon />\n                </IconWrapper>\n                <Input {...inputProps} isMobile={isMobile} />\n                {!isMobile && enableShortcuts && !isOpen && (\n                  <FocusKey>\n                    {searchShortcut === '⌘ K' ? (\n                      <>\n                        <FocusKeyCmd>⌘</FocusKeyCmd>K\n                      </>\n                    ) : (\n                      searchShortcut\n                    )}\n                  </FocusKey>\n                )}\n                <Actions>\n                  {input && (\n                    <Button\n                      padding=\"small\"\n                      variant=\"ghost\"\n                      ariaLabel=\"Clear search\"\n                      onClick={() => {\n                        reset({ inputValue: '' });\n                        closeMenu();\n                        inputRef.current?.focus();\n                      }}\n                    >\n                      <CloseIcon />\n                    </Button>\n                  )}\n                  {searchFieldContent}\n                </Actions>\n              </SearchField>\n              {searchBarContent}\n            </SearchBar>\n            <FocusContainer tabIndex={0} id=\"storybook-explorer-menu\">\n              {children({\n                query: input,\n                results,\n                isNavVisible: !isOpen && document.activeElement !== inputRef.current,\n                isNavReachable: !isOpen || input.length === 0,\n                isSearchResultRendered: isOpen,\n                closeMenu,\n                getMenuProps,\n                getItemProps,\n                highlightedIndex,\n              })}\n            </FocusContainer>\n          </>\n        );\n      }}\n    </Downshift>\n  );\n});\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/SearchResults.stories.tsx",
    "content": "import React from 'react';\n\nimport type { StoriesHash } from 'storybook/manager-api';\n\nimport { searchItem } from '../../utils/tree.ts';\nimport { IconSymbols } from './IconSymbols.tsx';\nimport { SearchResults } from './SearchResults.tsx';\nimport { mockDataset } from './mockdata.ts';\nimport type { CombinedDataset, Refs, SearchItem } from './types.ts';\n\nexport default {\n  component: SearchResults,\n  title: 'Sidebar/SearchResults',\n  includeStories: /^[A-Z]/,\n  parameters: { layout: 'fullscreen' },\n  globals: { sb_theme: 'side-by-side' },\n  decorators: [\n    (storyFn: any) => (\n      <div style={{ padding: '0 20px', maxWidth: '230px' }}>\n        <IconSymbols />\n        {storyFn()}\n      </div>\n    ),\n  ],\n};\n\nconst combinedDataset = (refs: Record<string, StoriesHash>): CombinedDataset => {\n  const hash = Object.entries(refs).reduce(\n    (acc, [refId, index]) =>\n      Object.assign(acc, {\n        [refId]: {\n          index,\n          title: null,\n          id: refId,\n          url: 'iframe.html',\n          ready: true,\n          error: false,\n          allStatuses: {},\n        },\n      }),\n    {}\n  );\n  return { hash, entries: Object.entries(hash) };\n};\n\n// @ts-expect-error (invalid input)\nconst dataset = combinedDataset({ internal: mockDataset.withRoot, composed: mockDataset.noRoot });\n\n// @ts-expect-error (non strict)\nconst internal = Object.values(dataset.hash.internal.index).map((item) =>\n  searchItem(item, dataset.hash.internal)\n);\n// @ts-expect-error (non strict)\nconst composed = Object.values(dataset.hash.composed.index).map((item) =>\n  searchItem(item, dataset.hash.composed)\n);\nconst stories: SearchItem[] = internal.concat(composed);\n\nconst results = stories\n  .filter(({ name }) => name.includes('A2'))\n  .map((item) => {\n    const i = item.name.indexOf('A2');\n    return { item, matches: [{ value: item.name, indices: [[i, i + 1]] }], score: 0 };\n  });\n\nconst recents = stories\n  .filter((item) => item.type === 'component') // even though we track stories, we display them grouped by component\n  .map((story) => ({ item: story, matches: [], score: 0 }));\n\n// We need this to prevent react key warnings\nconst passKey: any = (props = { key: '' }) => ({ key: props.key });\n\nexport const searching = {\n  query: 'query',\n  results,\n  closeMenu: () => {},\n  getMenuProps: passKey,\n  getItemProps: passKey,\n  highlightedIndex: 0,\n};\nexport const noResults = {\n  ...searching,\n  results: [] as any,\n};\nexport const lastViewed = {\n  query: '',\n  results: recents,\n  closeMenu: () => {},\n  getMenuProps: passKey,\n  getItemProps: passKey,\n  highlightedIndex: 0,\n};\n\nexport const Searching = () => <SearchResults {...searching} />;\n\nexport const NoResults = () => <SearchResults {...noResults} />;\n\nexport const LastViewed = () => <SearchResults {...lastViewed} />;\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/SearchResults.tsx",
    "content": "import type { FC, MouseEventHandler, PropsWithChildren, ReactNode } from 'react';\nimport React, { useCallback, useEffect } from 'react';\n\nimport { Button } from 'storybook/internal/components';\nimport { PRELOAD_ENTRIES } from 'storybook/internal/core-events';\n\nimport { global } from '@storybook/global';\nimport { TrashIcon } from '@storybook/icons';\n\nimport type { ControllerStateAndHelpers } from 'downshift';\nimport { transparentize } from 'polished';\nimport { useStorybookApi } from 'storybook/manager-api';\nimport { styled, useTheme } from 'storybook/theming';\n\nimport { matchesKeyCode, matchesModifiers } from '../../keybinding.ts';\nimport { getStatus } from '../../utils/status.tsx';\nimport { UseSymbol } from './IconSymbols.tsx';\nimport { NoResults } from './NoResults.tsx';\nimport { StatusLabel } from './StatusButton.tsx';\nimport { TypeIcon } from './TreeNode.tsx';\nimport type { DownshiftItem, Match, SearchResult } from './types.ts';\nimport { isExpandType } from './types.ts';\n\nconst { document } = global;\n\nconst ResultsList = styled.ol({\n  listStyle: 'none',\n  margin: 0,\n  padding: 0,\n});\n\nconst ResultRow = styled.li<{ isHighlighted: boolean }>(({ theme, isHighlighted }) => ({\n  width: '100%',\n  border: 'none',\n  cursor: 'pointer',\n  display: 'flex',\n  alignItems: 'start',\n  justifyContent: 'space-between',\n  textAlign: 'left',\n  color: 'inherit',\n  fontSize: `${theme.typography.size.s2}px`,\n  background: isHighlighted ? theme.background.hoverable : 'transparent',\n  minHeight: 28,\n  borderRadius: 4,\n  gap: 6,\n  paddingTop: 7,\n  paddingBottom: 7,\n  paddingLeft: 8,\n  paddingRight: 8,\n\n  '&:hover, &:focus': {\n    background: transparentize(0.93, theme.color.secondary),\n    outline: 'none',\n  },\n}));\n\nconst IconWrapper = styled.div({\n  marginTop: 2,\n});\n\nconst ResultRowContent = styled.div({\n  flex: 1,\n  display: 'flex',\n  flexDirection: 'column',\n});\n\nconst Mark = styled.mark(({ theme }) => ({\n  background: 'transparent',\n  color: theme.color.secondary,\n  '@media (forced-colors: active)': {\n    color: 'HighlightText',\n    background: 'Highlight',\n  },\n}));\n\nconst MoreWrapper = styled.div({\n  marginTop: 8,\n});\n\nconst RecentlyOpenedTitle = styled.div(({ theme }) => ({\n  display: 'flex',\n  justifyContent: 'space-between',\n  fontSize: `${theme.typography.size.s1 - 1}px`,\n  fontWeight: theme.typography.weight.bold,\n  minHeight: 28,\n  letterSpacing: '0.16em',\n  textTransform: 'uppercase',\n  color: theme.textMutedColor,\n  marginBottom: 4,\n  alignItems: 'center',\n\n  '.search-result-recentlyOpened-clear': {\n    visibility: 'hidden',\n  },\n\n  '&:hover': {\n    '.search-result-recentlyOpened-clear': {\n      visibility: 'visible',\n    },\n  },\n}));\n\nconst Highlight: FC<PropsWithChildren<{ match?: Match }>> = React.memo(function Highlight({\n  children,\n  match,\n}) {\n  if (!match) {\n    return children;\n  }\n  const { value, indices } = match;\n  const { nodes: result } = indices.reduce<{ cursor: number; nodes: ReactNode[] }>(\n    ({ cursor, nodes }, [start, end], index, { length }) => {\n      nodes.push(<span key={`${index}-1`}>{value.slice(cursor, start)}</span>);\n      nodes.push(<Mark key={`${index}-2`}>{value.slice(start, end + 1)}</Mark>);\n      if (index === length - 1) {\n        nodes.push(<span key={`${index}-3`}>{value.slice(end + 1)}</span>);\n      }\n      return { cursor: end + 1, nodes };\n    },\n    { cursor: 0, nodes: [] }\n  );\n  return <span>{result}</span>;\n});\n\nconst Title = styled.div({\n  display: 'grid',\n  justifyContent: 'start',\n  gridAutoColumns: 'auto',\n  gridAutoFlow: 'column',\n\n  '& > span': {\n    display: 'block',\n    whiteSpace: 'nowrap',\n    overflow: 'hidden',\n    textOverflow: 'ellipsis',\n  },\n});\n\nconst Path = styled.div(({ theme }) => ({\n  display: 'grid',\n  justifyContent: 'start',\n  gridAutoColumns: 'auto',\n  gridAutoFlow: 'column',\n  fontSize: `${theme.typography.size.s1 - 1}px`,\n\n  '& > span': {\n    display: 'block',\n    whiteSpace: 'nowrap',\n    overflow: 'hidden',\n    textOverflow: 'ellipsis',\n  },\n\n  '& > span + span': {\n    '&:before': {\n      content: \"' / '\",\n    },\n  },\n}));\n\nconst Result: FC<\n  SearchResult & {\n    isHighlighted: boolean;\n  } & React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>\n> = React.memo(function Result({ item, matches, onClick, ...props }) {\n  const theme = useTheme();\n  const click: MouseEventHandler<HTMLLIElement> = useCallback(\n    (event) => {\n      event.preventDefault();\n      onClick?.(event);\n    },\n    [onClick]\n  );\n\n  const api = useStorybookApi();\n  useEffect(() => {\n    if (api && props.isHighlighted && item.type === 'component') {\n      api.emit(PRELOAD_ENTRIES, { ids: [item.children[0]] }, { options: { target: item.refId } });\n    }\n  }, [api, props.isHighlighted, item]);\n\n  const nameMatch = matches.find((match: Match) => match.key === 'name');\n  const pathMatches = matches.filter((match: Match) => match.key === 'path');\n\n  const icon = item.status ? getStatus(theme, item.status).icon : null;\n\n  return (\n    <ResultRow {...props} onClick={click}>\n      <IconWrapper>\n        {item.type === 'component' && (\n          <TypeIcon viewBox=\"0 0 14 14\" width=\"14\" height=\"14\" type=\"component\">\n            <UseSymbol type=\"component\" />\n          </TypeIcon>\n        )}\n        {item.type === 'story' && (\n          <TypeIcon viewBox=\"0 0 14 14\" width=\"14\" height=\"14\" type={item.subtype}>\n            <UseSymbol type={item.subtype} />\n          </TypeIcon>\n        )}\n        {!(item.type === 'component' || item.type === 'story') && (\n          <TypeIcon viewBox=\"0 0 14 14\" width=\"14\" height=\"14\" type=\"document\">\n            <UseSymbol type=\"document\" />\n          </TypeIcon>\n        )}\n      </IconWrapper>\n      <ResultRowContent className=\"search-result-item--label\">\n        <Title>\n          <Highlight match={nameMatch}>{item.name}</Highlight>\n        </Title>\n        <Path>\n          {item.path.map((group, index) => (\n            <span key={index}>\n              <Highlight match={pathMatches.find((match: Match) => match.arrayIndex === index)}>\n                {group}\n              </Highlight>\n            </span>\n          ))}\n        </Path>\n      </ResultRowContent>\n      {item.status ? <StatusLabel status={item.status}>{icon}</StatusLabel> : null}\n    </ResultRow>\n  );\n});\n\nexport const SearchResults: FC<{\n  query: string;\n  results: DownshiftItem[];\n  closeMenu: (cb?: () => void) => void;\n  getMenuProps: ControllerStateAndHelpers<DownshiftItem>['getMenuProps'];\n  getItemProps: ControllerStateAndHelpers<DownshiftItem>['getItemProps'];\n  highlightedIndex: number | null;\n  isLoading?: boolean;\n  enableShortcuts?: boolean;\n  clearLastViewed?: () => void;\n}> = React.memo(function SearchResults({\n  query,\n  results,\n  closeMenu,\n  getMenuProps,\n  getItemProps,\n  highlightedIndex,\n  isLoading = false,\n  enableShortcuts = true,\n  clearLastViewed,\n}) {\n  const api = useStorybookApi();\n  useEffect(() => {\n    const handleEscape = (event: KeyboardEvent) => {\n      if (!enableShortcuts || isLoading || event.repeat) {\n        return;\n      }\n      if (matchesModifiers(false, event) && matchesKeyCode('Escape', event)) {\n        const target = event.target as Element;\n\n        if (target?.id === 'storybook-explorer-searchfield') {\n          return; // handled by downshift\n        }\n        event.preventDefault();\n        closeMenu();\n      }\n    };\n\n    document.addEventListener('keydown', handleEscape);\n    return () => document.removeEventListener('keydown', handleEscape);\n  }, [closeMenu, enableShortcuts, isLoading]);\n\n  const mouseOverHandler: MouseEventHandler = useCallback((event) => {\n    if (!api) {\n      return;\n    }\n    const currentTarget = event.currentTarget as HTMLElement;\n    const storyId = currentTarget.getAttribute('data-id');\n    const refId = currentTarget.getAttribute('data-refid');\n    // @ts-expect-error (non strict)\n    const item = api.resolveStory(storyId, refId === 'storybook_internal' ? undefined : refId);\n\n    if (item?.type === 'component') {\n      api.emit(PRELOAD_ENTRIES, {\n        // @ts-expect-error (TODO)\n        ids: [item.isLeaf ? item.id : item.children[0]],\n        options: { target: refId },\n      });\n    }\n  }, []);\n\n  const handleClearLastViewed = () => {\n    // @ts-expect-error (non strict)\n    clearLastViewed();\n    closeMenu();\n  };\n\n  return (\n    <ResultsList {...getMenuProps()} key=\"results-list\">\n      {results.length > 0 && !query && (\n        <RecentlyOpenedTitle className=\"search-result-recentlyOpened\">\n          Recently opened\n          <Button\n            padding=\"small\"\n            variant=\"ghost\"\n            className=\"search-result-recentlyOpened-clear\"\n            onClick={handleClearLastViewed}\n            ariaLabel=\"Clear recently opened items\"\n          >\n            <TrashIcon />\n          </Button>\n        </RecentlyOpenedTitle>\n      )}\n      {results.length === 0 && query && (\n        <li>\n          <NoResults>\n            <strong>No components found</strong>\n            <small>Find components by name or path.</small>\n          </NoResults>\n        </li>\n      )}\n      {results.map((result: DownshiftItem, index) => {\n        if (isExpandType(result)) {\n          const props = { ...results, ...getItemProps({ key: index, index, item: result }) };\n          const { key, ...rest } = props;\n          return (\n            <MoreWrapper key=\"search-result-expand\">\n              <Button key={key} {...rest} size=\"small\">\n                Show {result.moreCount} more results\n              </Button>\n            </MoreWrapper>\n          );\n        }\n\n        const { item } = result;\n        const key = `${item.refId}::${item.id}`;\n        return (\n          <Result\n            {...result}\n            {...getItemProps({ key, index, item: result })}\n            isHighlighted={highlightedIndex === index}\n            key={key}\n            data-id={result.item.id}\n            data-refid={result.item.refId}\n            onMouseOver={mouseOverHandler}\n            className=\"search-result-item\"\n          />\n        );\n      })}\n    </ResultsList>\n  );\n});\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/Sidebar.stories.tsx",
    "content": "import React from 'react';\n\nimport type {\n  DecoratorFunction,\n  StatusValue,\n  StatusesByStoryIdAndTypeId,\n} from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport type { IndexHash } from 'storybook/manager-api';\nimport { ManagerContext } from 'storybook/manager-api';\nimport { expect, fn, userEvent, waitFor, within } from 'storybook/test';\n\nimport { initialState } from '../../../shared/checklist-store/checklistData.state.ts';\nimport {\n  internal_fullStatusStore,\n  internal_universalChecklistStore,\n} from '../../manager-stores.mock.ts';\nimport { LayoutProvider } from '../layout/LayoutProvider.tsx';\nimport { standardData as standardHeaderData } from './Heading.stories.tsx';\nimport { DEFAULT_REF_ID, Sidebar } from './Sidebar.tsx';\nimport { mockDataset } from './mockdata.ts';\nimport type { RefType } from './types.ts';\n\nconst wait = (ms: number) =>\n  new Promise<void>((resolve) => {\n    setTimeout(resolve, ms);\n  });\n\nconst { menu } = standardHeaderData;\nconst index = mockDataset.withRoot as IndexHash;\nconst storyId = 'root-1-child-a2--grandchild-a1-1';\n\nexport const simpleData = { menu, index, storyId };\nexport const loadingData = { menu };\n\nconst managerContext: any = (args: Meta<typeof Sidebar>['args']) => ({\n  state: {\n    docsOptions: {\n      defaultName: 'Docs',\n      autodocs: 'tag',\n      docsMode: false,\n    },\n    internal_index: args?.indexJson,\n  },\n  api: {\n    emit: fn().mockName('api::emit'),\n    on: fn().mockName('api::on'),\n    off: fn().mockName('api::off'),\n    once: fn().mockName('api::once'),\n    getData: fn().mockName('api::getData'),\n    getIndex: fn().mockName('api::getIndex'),\n    getShortcutKeys: fn(() => ({ search: ['control', 'shift', 's'] })).mockName(\n      'api::getShortcutKeys'\n    ),\n    getChannel: fn().mockName('api::getChannel'),\n    getElements: fn(() => ({})),\n    navigate: fn().mockName('api::navigate'),\n    selectStory: fn().mockName('api::selectStory'),\n    experimental_setFilter: fn().mockName('api::experimental_setFilter'),\n    getDocsUrl: () => 'https://storybook.js.org/docs/',\n    getIsNavShown: () => true,\n    getUrlState: () => ({\n      queryParams: {},\n      path: '',\n      viewMode: 'story',\n      url: 'http://localhost:6006/',\n    }),\n    applyQueryParams: fn().mockName('api::applyQueryParams'),\n  },\n});\n\nconst meta = {\n  component: Sidebar,\n  title: 'Sidebar/Sidebar',\n  excludeStories: /.*Data$/,\n  parameters: { layout: 'fullscreen' },\n  args: {\n    previewInitialized: true,\n    menu,\n    index: index,\n    indexJson: {\n      entries: {\n        // force the tags filter menu to show in production\n        ['dummy--dummyId']: {\n          id: 'dummy--dummyId',\n          name: 'Dummy story',\n          title: 'dummy',\n          importPath: './dummy.stories.js',\n          type: 'story',\n          subtype: 'story',\n          tags: ['A', 'B', 'C', 'dev'],\n        },\n      },\n      v: 6,\n    },\n    storyId,\n    refId: DEFAULT_REF_ID,\n    refs: {},\n    allStatuses: {},\n    showCreateStoryButton: true,\n    isDevelopment: true,\n  },\n  decorators: [\n    (storyFn, { args, globals, title }) => (\n      <ManagerContext.Provider value={managerContext(args)}>\n        <LayoutProvider\n          forceDesktop={\n            globals.viewport?.value === 'desktop' ||\n            globals.viewport?.value === undefined ||\n            title.endsWith('scrolled')\n          }\n        >\n          {storyFn()}\n        </LayoutProvider>\n      </ManagerContext.Provider>\n    ),\n  ],\n  globals: { sb_theme: 'side-by-side' },\n  beforeEach: () => {\n    internal_fullStatusStore.unset();\n    internal_universalChecklistStore.setState({\n      loaded: true,\n      widget: {},\n      items: {\n        ...initialState.items,\n        controls: { status: 'accepted' },\n        renderComponent: { status: 'done' },\n        viewports: { status: 'skipped' },\n      },\n    });\n  },\n} satisfies Meta<typeof Sidebar>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nconst mobileLayoutDecorator: DecoratorFunction = (storyFn, { args, globals, title }) => (\n  <ManagerContext.Provider value={managerContext(args)}>\n    <LayoutProvider\n      forceDesktop={\n        globals.viewport?.value === 'desktop' ||\n        globals.viewport?.value === undefined ||\n        title.endsWith('scrolled')\n      }\n    >\n      {storyFn()}\n    </LayoutProvider>\n  </ManagerContext.Provider>\n);\n\nconst refs: Record<string, RefType> = {\n  optimized: {\n    id: 'optimized',\n    title: 'This is a ref',\n    url: 'https://example.com',\n    type: 'lazy',\n    filteredIndex: index,\n    previewInitialized: true,\n    allStatuses: {},\n  },\n};\n\n// eslint-disable-next-line local-rules/no-uncategorized-errors\nconst indexError = new Error('Failed to load index');\n\nconst refsError = {\n  optimized: {\n    ...refs.optimized,\n    // @ts-expect-error (non strict)\n    filteredIndex: undefined as IndexHash,\n    indexError,\n  },\n};\n\nconst refsEmpty = {\n  optimized: {\n    ...refs.optimized,\n    // type: 'auto-inject',\n    filteredIndex: {} as IndexHash,\n  },\n};\n\nconst waitForChecklistWidget = async () => {\n  await waitFor(\n    () =>\n      expect(document.getElementById('storybook-checklist-widget')?.checkVisibility()).toBe(true),\n    { timeout: 5000 }\n  );\n  await wait(300); // wait for expand animation\n};\n\nexport const Simple: Story = {\n  play: waitForChecklistWidget,\n};\n\nexport const SimpleInProduction: Story = {\n  args: {\n    showCreateStoryButton: false,\n  },\n  beforeEach: () => {\n    const configType = global.CONFIG_TYPE;\n    global.CONFIG_TYPE = 'PRODUCTION';\n    return () => {\n      global.CONFIG_TYPE = configType;\n    };\n  },\n};\n\nexport const SimpleNoChecklist: Story = {\n  args: {\n    showCreateStoryButton: false,\n  },\n  beforeEach: () => {\n    const features = global.FEATURES;\n    global.FEATURES = { ...features, sidebarOnboardingChecklist: false };\n    return () => {\n      global.FEATURES = features;\n    };\n  },\n};\n\nexport const Mobile: Story = {\n  decorators: [mobileLayoutDecorator],\n  globals: { sb_theme: 'light', viewport: { value: 'mobile1' } },\n  play: waitForChecklistWidget,\n};\n\nexport const Loading: Story = {\n  args: {\n    previewInitialized: false,\n    index: undefined,\n  },\n};\n\nexport const LoadingMobile: Story = {\n  args: Loading.args,\n  decorators: [mobileLayoutDecorator],\n  globals: { sb_theme: 'light', viewport: { value: 'mobile1' } },\n};\n\nexport const Empty: Story = {\n  args: {\n    index: {},\n  },\n  play: waitForChecklistWidget,\n};\n\nexport const EmptyMobile: Story = {\n  args: Empty.args,\n  decorators: [mobileLayoutDecorator],\n  globals: { sb_theme: 'light', viewport: { value: 'mobile1' } },\n  play: waitForChecklistWidget,\n};\n\nexport const EmptyIndex: Story = {\n  args: {\n    index: {},\n    indexJson: {\n      entries: {},\n      v: 6,\n    },\n  },\n  play: waitForChecklistWidget,\n};\n\nexport const IndexError: Story = {\n  args: {\n    indexError,\n  },\n  play: waitForChecklistWidget,\n};\n\nexport const WithRefs: Story = {\n  args: {\n    refs,\n  },\n  play: waitForChecklistWidget,\n};\n\nexport const WithRefsNarrow: Story = {\n  args: {\n    refs: {\n      wide: {\n        ...refs.optimized,\n        title: 'This is a ref with a very long title',\n      },\n    },\n  },\n  parameters: {\n    viewport: {\n      options: {\n        narrow: {\n          name: 'narrow',\n          styles: {\n            width: '230px',\n            height: '800px',\n          },\n        },\n      },\n    },\n    chromatic: {\n      modes: {\n        narrow: {\n          viewport: 230,\n        },\n      },\n    },\n  },\n  globals: {\n    viewport: {\n      value: 'narrow',\n    },\n  },\n  play: waitForChecklistWidget,\n};\n\nexport const WithRefsMobile: Story = {\n  args: WithRefs.args,\n  decorators: [mobileLayoutDecorator],\n  globals: { sb_theme: 'light', viewport: { value: 'mobile1' } },\n  play: waitForChecklistWidget,\n};\n\nexport const LoadingWithRefs: Story = {\n  args: {\n    ...Loading.args,\n    refs,\n  },\n};\n\nexport const LoadingWithRefError: Story = {\n  args: {\n    ...Loading.args,\n    refs: refsError,\n  },\n};\n\nexport const LoadingWithRefErrorMobile: Story = {\n  args: LoadingWithRefError.args,\n  decorators: [mobileLayoutDecorator],\n  globals: { sb_theme: 'light', viewport: { value: 'mobile1' } },\n};\n\nexport const WithRefEmpty: Story = {\n  args: {\n    ...Empty.args,\n    refs: refsEmpty,\n  },\n  play: waitForChecklistWidget,\n};\n\nexport const StatusesCollapsed: Story = {\n  args: {\n    allStatuses: Object.entries(index).reduce((acc, [id, item]) => {\n      if (item.type !== 'story') {\n        return acc;\n      }\n\n      if (item.name.includes('B')) {\n        return {\n          ...acc,\n          [id]: {\n            addonA: {\n              typeId: 'addonA',\n              storyId: id,\n              value: 'status-value:warning',\n              title: 'Addon A',\n              description: 'We just wanted you to know',\n            },\n            addonB: {\n              typeId: 'addonB',\n              storyId: id,\n              value: 'status-value:error',\n              title: 'Addon B',\n              description: 'This is a big deal!',\n            },\n          },\n        } satisfies StatusesByStoryIdAndTypeId;\n      }\n      return acc;\n    }, {} as StatusesByStoryIdAndTypeId),\n  },\n  play: waitForChecklistWidget,\n};\n\nexport const StatusesOpen: Story = {\n  ...StatusesCollapsed,\n  args: {\n    allStatuses: Object.entries(index).reduce((acc, [id, item]) => {\n      if (item.type !== 'story') {\n        return acc;\n      }\n\n      return {\n        ...acc,\n        [id]: {\n          addonA: {\n            typeId: 'addonA',\n            storyId: id,\n            value: 'status-value:warning',\n            title: 'Addon A',\n            description: 'We just wanted you to know',\n          },\n          addonB: {\n            typeId: 'addonB',\n            storyId: id,\n            value: 'status-value:error',\n            title: 'Addon B',\n            description: 'This is a big deal!',\n          },\n        },\n      } satisfies StatusesByStoryIdAndTypeId;\n    }, {} as StatusesByStoryIdAndTypeId),\n  },\n  play: waitForChecklistWidget,\n};\n\nexport const Searching: Story = {\n  ...StatusesOpen,\n  parameters: { chromatic: { delay: 2200 } },\n  globals: { sb_theme: 'light' },\n  decorators: [\n    (StoryFn) => (\n      <div style={{ width: '100vw', height: '100vh', position: 'relative' }}>\n        <StoryFn />\n      </div>\n    ),\n  ],\n  play: async ({ canvasElement, step }) => {\n    await waitForChecklistWidget();\n    const canvas = await within(canvasElement);\n    const search = await canvas.findByPlaceholderText('Find components');\n    userEvent.clear(search);\n    userEvent.type(search, 'B2');\n  },\n};\n\nexport const Bottom: Story = {\n  beforeEach: () => {\n    internal_fullStatusStore.set([\n      {\n        storyId,\n        typeId: 'vitest',\n        value: 'status-value:warning',\n        title: 'Vitest',\n        description: 'Vitest',\n      },\n      {\n        storyId,\n        typeId: 'vta',\n        value: 'status-value:error',\n        title: 'VTA',\n        description: 'VTA',\n      },\n      {\n        storyId: 'root-1-child-a2--grandchild-a1-2',\n        typeId: 'vitest',\n        value: 'status-value:warning',\n        title: 'Vitest',\n        description: 'Vitest',\n      },\n    ]);\n  },\n};\n\n/**\n * Given the following sequence of events:\n *\n * 1. Story is selected at the top of the sidebar\n * 2. The sidebar is scrolled to the bottom\n * 3. Some re-rendering happens because of a changed state/prop The sidebar should remain scrolled to\n *    the bottom\n */\nexport const Scrolled: Story = {\n  parameters: {\n    // we need a very short viewport\n    viewport: {\n      defaultViewport: 'mobile1',\n      defaultOrientation: 'landscape',\n    },\n  },\n  args: {\n    storyId: 'group-1--child-b1',\n  },\n  globals: { sb_theme: 'light' },\n  decorators: [\n    (StoryFn) => (\n      <div style={{ width: '100vw', height: '100vh', position: 'relative' }}>\n        <StoryFn />\n      </div>\n    ),\n  ],\n\n  render: (args) => {\n    const [, setState] = React.useState(0);\n    return (\n      <>\n        <button\n          style={{ position: 'absolute', zIndex: 10, bottom: 0, right: 0 }}\n          onClick={() => setState(() => Math.random())}\n        >\n          Change state\n        </button>\n        <Sidebar {...args} />\n      </>\n    );\n  },\n  play: async ({ canvasElement, step }) => {\n    await waitForChecklistWidget();\n    const canvas = await within(canvasElement);\n    const scrollable = await canvasElement.querySelector('[data-radix-scroll-area-viewport]');\n    await step('expand component', async () => {\n      const componentNode = await canvas.queryAllByText('Child A2')[1];\n      await userEvent.click(componentNode);\n    });\n    await wait(100);\n    await step('scroll to bottom', async () => {\n      // @ts-expect-error (non strict)\n      scrollable.scrollTo(0, scrollable.scrollHeight);\n    });\n    await step('toggle parent state', async () => {\n      const button = await canvas.findByRole('button', { name: 'Change state' });\n      await userEvent.click(button);\n    });\n    await wait(100);\n\n    // expect the scrollable to be scrolled to the bottom\n    // @ts-expect-error (non strict)\n    await expect(scrollable.scrollTop).toBe(scrollable.scrollHeight - scrollable.clientHeight);\n  },\n};\n\nexport const StatusesNew: Story = {\n  args: {\n    allStatuses: Object.entries(index).reduce((acc, [id, item]) => {\n      if (item.type !== 'story') return acc;\n      return {\n        ...acc,\n        [id]: {\n          addonA: {\n            typeId: 'addonA',\n            storyId: id,\n            value: 'status-value:new' as StatusValue,\n            title: 'Change Detection',\n            description: 'This story is new',\n          },\n        },\n      } satisfies StatusesByStoryIdAndTypeId;\n    }, {} as StatusesByStoryIdAndTypeId),\n  },\n  play: waitForChecklistWidget,\n};\n\nexport const StatusesModified: Story = {\n  args: {\n    allStatuses: Object.entries(index).reduce((acc, [id, item]) => {\n      if (item.type !== 'story') return acc;\n      return {\n        ...acc,\n        [id]: {\n          addonA: {\n            typeId: 'addonA',\n            storyId: id,\n            value: 'status-value:modified' as StatusValue,\n            title: 'Change Detection',\n            description: 'This story was modified',\n          },\n        },\n      } satisfies StatusesByStoryIdAndTypeId;\n    }, {} as StatusesByStoryIdAndTypeId),\n  },\n  play: waitForChecklistWidget,\n};\n\nexport const StatusesAffected: Story = {\n  args: {\n    allStatuses: Object.entries(index).reduce((acc, [id, item]) => {\n      if (item.type !== 'story') return acc;\n      return {\n        ...acc,\n        [id]: {\n          addonA: {\n            typeId: 'addonA',\n            storyId: id,\n            value: 'status-value:affected' as StatusValue,\n            title: 'Change Detection',\n            description: 'This story is affected by a change',\n          },\n        },\n      } satisfies StatusesByStoryIdAndTypeId;\n    }, {} as StatusesByStoryIdAndTypeId),\n  },\n  play: waitForChecklistWidget,\n};\n\nexport const StatusesMixed: Story = {\n  args: {\n    allStatuses: Object.entries(index).reduce((acc, [id, item]) => {\n      if (item.type !== 'story') return acc;\n      const values: StatusValue[] = [\n        'status-value:new',\n        'status-value:modified',\n        'status-value:affected',\n        'status-value:success',\n        'status-value:warning',\n      ];\n      const value = values[Object.keys(acc).length % values.length];\n      return {\n        ...acc,\n        [id]: {\n          addonA: {\n            typeId: 'addonA',\n            storyId: id,\n            value,\n            title: 'Change Detection',\n            description: '',\n          },\n        },\n      } satisfies StatusesByStoryIdAndTypeId;\n    }, {} as StatusesByStoryIdAndTypeId),\n  },\n  play: waitForChecklistWidget,\n};\n\nexport const StatusesChangeDetectionPriority: Story = {\n  args: {\n    allStatuses: Object.entries(index).reduce((acc, [id, item]) => {\n      if (item.type !== 'story') return acc;\n      // Cycles through all change-detection variants + warning/error to verify\n      // priority ordering (most critical wins): error > warning > affected > modified > new\n      const priorityValues: StatusValue[] = [\n        'status-value:new',\n        'status-value:modified',\n        'status-value:affected',\n        'status-value:warning',\n        'status-value:error',\n      ];\n      const value = priorityValues[Object.keys(acc).length % priorityValues.length];\n      return {\n        ...acc,\n        [id]: {\n          addonA: {\n            typeId: 'addonA',\n            storyId: id,\n            value,\n            title: 'Change Detection',\n            description: `Priority test: ${value}`,\n          },\n        },\n      } satisfies StatusesByStoryIdAndTypeId;\n    }, {} as StatusesByStoryIdAndTypeId),\n  },\n  play: waitForChecklistWidget,\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/Sidebar.tsx",
    "content": "import React, { useMemo, useRef, useState } from 'react';\n\nimport { Button, ScrollArea } from 'storybook/internal/components';\nimport type { API_LoadedRefData, StoryIndex } from 'storybook/internal/types';\nimport type { StatusesByStoryIdAndTypeId } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\nimport { PlusIcon } from '@storybook/icons';\n\nimport { type State, useStorybookApi } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport { focusableUIElements } from '../../../manager-api/modules/layout.ts';\nimport { MEDIA_DESKTOP_BREAKPOINT } from '../../constants.ts';\nimport { useLandmark } from '../../hooks/useLandmark.ts';\nimport { useLayout } from '../layout/LayoutProvider.tsx';\nimport { ChecklistWidget } from './ChecklistWidget.tsx';\nimport { CreateNewStoryFileModal } from './CreateNewStoryFileModal.tsx';\nimport { Explorer } from './Explorer.tsx';\nimport type { HeadingProps } from './Heading.tsx';\nimport { Heading } from './Heading.tsx';\nimport { IconSymbols } from './IconSymbols.tsx';\nimport { Search } from './Search.tsx';\nimport { SearchResults } from './SearchResults.tsx';\nimport { SidebarBottom } from './SidebarBottom.tsx';\nimport { Filter } from './Filter.tsx';\nimport type { CombinedDataset, Selection } from './types.ts';\nimport { useLastViewed } from './useLastViewed.ts';\n\nexport const DEFAULT_REF_ID = 'storybook_internal';\n\nconst Container = styled.header(({ theme }) => ({\n  position: 'absolute',\n  zIndex: 1,\n  left: 0,\n  top: 0,\n  bottom: 0,\n  right: 0,\n  width: '100%',\n  height: '100%',\n  display: 'flex',\n  flexDirection: 'column',\n  background: theme.background.content,\n\n  [MEDIA_DESKTOP_BREAKPOINT]: {\n    background: theme.background.app,\n  },\n}));\n\nconst Stack = styled.div({\n  display: 'flex',\n  flexDirection: 'column',\n  gap: 16,\n  padding: '16px 12px 20px 12px',\n});\n\nconst CreateNewStoryButton = styled(Button)<{ isMobile: boolean }>(({ theme, isMobile }) => ({\n  color: theme.textMutedColor,\n  width: isMobile ? 36 : 32,\n  height: isMobile ? 36 : 32,\n  borderRadius: theme.appBorderRadius + 2,\n}));\n\nconst useCombination = (\n  index: SidebarProps['index'],\n  indexError: SidebarProps['indexError'],\n  previewInitialized: SidebarProps['previewInitialized'],\n  allStatuses: StatusesByStoryIdAndTypeId,\n  refs: SidebarProps['refs']\n): CombinedDataset => {\n  const hash = useMemo(\n    () => ({\n      [DEFAULT_REF_ID]: {\n        index,\n        filteredIndex: index,\n        indexError,\n        previewInitialized,\n        allStatuses,\n        title: null,\n        id: DEFAULT_REF_ID,\n        url: 'iframe.html',\n      },\n      ...refs,\n    }),\n    [refs, index, indexError, previewInitialized, allStatuses]\n  );\n  // @ts-expect-error (non strict)\n  return useMemo(() => ({ hash, entries: Object.entries(hash) }), [hash]);\n};\n\nconst isRendererReact = global.STORYBOOK_RENDERER === 'react';\n\nexport interface SidebarProps extends API_LoadedRefData {\n  refs: State['refs'];\n  allStatuses: StatusesByStoryIdAndTypeId;\n  menu: any[];\n  storyId?: string;\n  refId?: string;\n  menuHighlighted?: boolean;\n  enableShortcuts?: boolean;\n  onMenuClick?: HeadingProps['onMenuClick'];\n  showCreateStoryButton?: boolean;\n  indexJson?: StoryIndex;\n  isDevelopment?: boolean;\n}\nexport const Sidebar = React.memo(function Sidebar({\n  // @ts-expect-error (non strict)\n  storyId = null,\n  refId = DEFAULT_REF_ID,\n  index,\n  indexJson,\n  indexError,\n  allStatuses,\n  previewInitialized,\n  menu,\n  menuHighlighted = false,\n  enableShortcuts = true,\n  isDevelopment = global.CONFIG_TYPE === 'DEVELOPMENT',\n  refs = {},\n  onMenuClick,\n  showCreateStoryButton = isDevelopment && isRendererReact,\n}: SidebarProps) {\n  const [isFileSearchModalOpen, setIsFileSearchModalOpen] = useState(false);\n  // @ts-expect-error (non strict)\n  const selected: Selection = useMemo(() => storyId && { storyId, refId }, [storyId, refId]);\n  const dataset = useCombination(index, indexError, previewInitialized, allStatuses, refs);\n  const isLoading = !index && !indexError;\n  const hasEntries = Object.keys(indexJson?.entries ?? {}).length > 0;\n  const lastViewedProps = useLastViewed(selected);\n  const { isMobile } = useLayout();\n  const api = useStorybookApi();\n  const { viewMode } = api.getUrlState();\n\n  const headerRef = useRef<HTMLElement>(null);\n  const { landmarkProps } = useLandmark(\n    { 'aria-labelledby': 'global-site-h1', role: 'banner' },\n    headerRef\n  );\n\n  const isPagesShown = viewMode !== undefined && viewMode !== 'story' && viewMode !== 'docs';\n  const skipLinkHref = isPagesShown ? '#main-content-wrapper' : '#storybook-preview-wrapper';\n\n  return (\n    <Container\n      className=\"container sidebar-container\"\n      id={focusableUIElements.sidebarRegion}\n      ref={headerRef}\n      {...landmarkProps}\n    >\n      <h1 id=\"global-site-h1\" className=\"sb-sr-only\">\n        Storybook\n      </h1>\n      <IconSymbols />\n      <ScrollArea vertical offset={3} scrollbarSize={6} scrollPadding=\"4rem\">\n        <Stack>\n          <div>\n            <Heading\n              className=\"sidebar-header\"\n              menuHighlighted={menuHighlighted}\n              menu={menu}\n              skipLinkHref={skipLinkHref}\n              isLoading={isLoading}\n              onMenuClick={onMenuClick}\n            />\n            {!isLoading &&\n              global.CONFIG_TYPE === 'DEVELOPMENT' &&\n              global.FEATURES?.sidebarOnboardingChecklist !== false && <ChecklistWidget />}\n          </div>\n          <Search\n            dataset={dataset}\n            enableShortcuts={enableShortcuts}\n            searchBarContent={\n              showCreateStoryButton && (\n                <>\n                  <CreateNewStoryButton\n                    isMobile={isMobile}\n                    onClick={() => {\n                      setIsFileSearchModalOpen(true);\n                    }}\n                    ariaLabel=\"Create a new story\"\n                    variant=\"outline\"\n                    padding=\"small\"\n                  >\n                    <PlusIcon />\n                  </CreateNewStoryButton>\n                  <CreateNewStoryFileModal\n                    open={isFileSearchModalOpen}\n                    onOpenChange={setIsFileSearchModalOpen}\n                  />\n                </>\n              )\n            }\n            searchFieldContent={<Filter />}\n            {...lastViewedProps}\n          >\n            {({\n              query,\n              results,\n              isNavVisible,\n              isNavReachable,\n              isSearchResultRendered,\n              closeMenu,\n              getMenuProps,\n              getItemProps,\n              highlightedIndex,\n            }) => (\n              <>\n                {\n                  <Explorer\n                    dataset={dataset}\n                    selected={selected}\n                    isLoading={isLoading}\n                    isBrowsing={isNavVisible}\n                    isHidden={!isNavReachable}\n                    hasEntries={hasEntries}\n                  />\n                }\n                {isSearchResultRendered && (\n                  <SearchResults\n                    query={query}\n                    results={results}\n                    closeMenu={closeMenu}\n                    getMenuProps={getMenuProps}\n                    getItemProps={getItemProps}\n                    highlightedIndex={highlightedIndex}\n                    enableShortcuts={enableShortcuts}\n                    isLoading={isLoading}\n                    clearLastViewed={lastViewedProps.clearLastViewed}\n                  />\n                )}\n              </>\n            )}\n          </Search>\n        </Stack>\n        {isMobile || isLoading ? null : <SidebarBottom isDevelopment={isDevelopment} />}\n      </ScrollArea>\n    </Container>\n  );\n});\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/SidebarBottom.stories.tsx",
    "content": "import React, { type FC, useEffect, useState } from 'react';\n\nimport {\n  type Addon_Collection,\n  type Addon_TestProviderType,\n  Addon_TypesEnum,\n} from 'storybook/internal/types';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { type API, ManagerContext } from 'storybook/manager-api';\nimport { expect, fireEvent, fn, waitFor, within } from 'storybook/test';\n\nimport type { TestProviderStateByProviderId } from '../../../shared/test-provider-store/index.ts';\nimport { SidebarBottomBase } from './SidebarBottom.tsx';\n\nconst DynamicHeightDemo: FC = () => {\n  const [height, setHeight] = useState(100);\n\n  useEffect(() => {\n    const interval = setInterval(() => {\n      setHeight((h) => (h === 100 ? 200 : 100));\n    }, 2000);\n    return () => clearInterval(interval);\n  }, []);\n\n  return (\n    <div\n      style={{\n        height,\n        transition: '1s height',\n        display: 'flex',\n        alignItems: 'center',\n        justifyContent: 'center',\n        backgroundColor: 'hotpink',\n      }}\n    >\n      CUSTOM CONTENT WITH DYNAMIC HEIGHT\n    </div>\n  );\n};\n\nconst managerContext: any = {\n  state: {\n    docsOptions: {\n      defaultName: 'Docs',\n      autodocs: 'tag',\n      docsMode: false,\n    },\n  },\n  api: {\n    on: fn().mockName('api::on'),\n    off: fn().mockName('api::off'),\n    once: fn().mockName('api::once'),\n    updateTestProviderState: fn(),\n  },\n};\n\nconst registeredTestProviders: Addon_Collection<Addon_TestProviderType> = {\n  'component-tests': {\n    type: Addon_TypesEnum.experimental_TEST_PROVIDER,\n    id: 'component-tests',\n    render: () => <div>Component tests</div>,\n  },\n  'visual-tests': {\n    type: Addon_TypesEnum.experimental_TEST_PROVIDER,\n    id: 'visual-tests',\n    render: () => <div>Visual tests</div>,\n  },\n};\nconst testProviderStates: TestProviderStateByProviderId = {\n  'component-tests': 'test-provider-state:succeeded',\n  'visual-tests': 'test-provider-state:pending',\n};\nconst meta = {\n  component: SidebarBottomBase,\n  title: 'Sidebar/SidebarBottom',\n  args: {\n    isDevelopment: true,\n    warningCount: 0,\n    errorCount: 0,\n    successCount: 0,\n    hasStatuses: false,\n    notifications: [],\n    api: {\n      on: fn(),\n      off: fn(),\n      once: fn(),\n      clearNotification: fn(),\n      updateTestProviderState: fn(),\n      emit: fn(),\n      experimental_setFilter: fn(),\n      getChannel: fn(),\n      getElements: fn(() => ({})),\n    } as any as API,\n    onRunAll: fn(),\n    registeredTestProviders,\n    testProviderStates,\n  },\n  parameters: {\n    layout: 'fullscreen',\n  },\n  decorators: [\n    (storyFn) => (\n      <ManagerContext.Provider value={managerContext}>{storyFn()}</ManagerContext.Provider>\n    ),\n  ],\n} satisfies Meta<typeof SidebarBottomBase>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Errors: Story = {\n  args: {\n    errorCount: 2,\n    hasStatuses: true,\n  },\n};\n\nexport const Warnings: Story = {\n  args: {\n    warningCount: 2,\n    hasStatuses: true,\n  },\n};\n\nexport const Both: Story = {\n  args: {\n    errorCount: 2,\n    warningCount: 2,\n    hasStatuses: true,\n  },\n};\n\nexport const DynamicHeight: Story = {\n  // do not test in chromatic\n  parameters: {\n    chromatic: {\n      disableSnapshot: true,\n    },\n  },\n  args: {\n    registeredTestProviders: {\n      'dynamic-height': {\n        type: Addon_TypesEnum.experimental_TEST_PROVIDER,\n        id: 'dynamic-height',\n        render: () => <DynamicHeightDemo />,\n      },\n    },\n  },\n  play: async ({ canvasElement }) => {\n    const screen = within(canvasElement);\n\n    const toggleButton = await screen.findByLabelText(/Expand/, {}, { timeout: 3000 });\n    await fireEvent.click(toggleButton);\n\n    const content = await screen.findByText('CUSTOM CONTENT WITH DYNAMIC HEIGHT');\n    const collapse = screen.getByTestId('collapse');\n\n    await expect(content).toBeVisible();\n\n    await fireEvent.click(toggleButton);\n\n    await waitFor(() => expect(collapse.getBoundingClientRect()).toHaveProperty('height', 0));\n\n    await fireEvent.click(toggleButton);\n\n    await waitFor(() => expect(collapse.getBoundingClientRect()).not.toHaveProperty('height', 0));\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/SidebarBottom.tsx",
    "content": "import React, { Fragment, useEffect, useRef, useState } from 'react';\n\nimport {\n  type API_FilterFunction,\n  type Addon_Collection,\n  type Addon_TestProviderType,\n  Addon_TypesEnum,\n} from 'storybook/internal/types';\n\nimport {\n  experimental_useStatusStore,\n  experimental_useTestProviderStore,\n  internal_fullStatusStore,\n  internal_fullTestProviderStore,\n} from '#manager-stores';\nimport { type API, type State, useStorybookApi, useStorybookState } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport type { TestProviderStateByProviderId } from '../../../shared/test-provider-store/index.ts';\nimport { NotificationList } from '../notifications/NotificationList.tsx';\nimport { TestingWidget } from './TestingWidget.tsx';\n\n// This ID is used dynamically add/remove space at the bottom to prevent overlapping the main sidebar content.\nconst SIDEBAR_BOTTOM_SPACER_ID = 'sidebar-bottom-spacer';\n// This ID is used by some integrators to target the (fixed position) sidebar bottom element so it should remain stable.\nconst SIDEBAR_BOTTOM_WRAPPER_ID = 'sidebar-bottom-wrapper';\n\nconst filterNone: API_FilterFunction = () => true;\nconst filterWarn: API_FilterFunction = ({ statuses = {} }) =>\n  Object.values(statuses).some(({ value }) => value === 'status-value:warning');\nconst filterError: API_FilterFunction = ({ statuses = {} }) =>\n  Object.values(statuses).some(({ value }) => value === 'status-value:error');\nconst filterBoth: API_FilterFunction = ({ statuses = {} }) =>\n  Object.values(statuses).some(({ value }) =>\n    ['status-value:warning', 'status-value:error'].includes(value as any)\n  );\n\nconst getFilter = (warningsActive = false, errorsActive = false) => {\n  if (warningsActive && errorsActive) {\n    return filterBoth;\n  }\n\n  if (warningsActive) {\n    return filterWarn;\n  }\n\n  if (errorsActive) {\n    return filterError;\n  }\n  return filterNone;\n};\n\nconst Spacer = styled.div({\n  pointerEvents: 'none',\n});\n\nconst Content = styled.div(({ theme }) => ({\n  position: 'absolute',\n  zIndex: 1,\n  bottom: 0,\n  left: 0,\n  right: 0,\n  padding: 12,\n  display: 'flex',\n  flexDirection: 'column',\n  gap: 12,\n  color: theme.color.defaultText,\n  fontSize: theme.typography.size.s1,\n\n  '&:empty': {\n    display: 'none',\n  },\n\n  '--card-box-shadow': `0 1px 2px 0 rgba(0, 0, 0, 0.05), 0px -5px 20px 10px ${theme.background.app}`,\n\n  // Integrators can use these to style their custom additions\n  '--sb-sidebar-bottom-card-background': theme.background.content,\n  '--sb-sidebar-bottom-card-border': `1px solid ${theme.appBorderColor}`,\n  '--sb-sidebar-bottom-card-border-radius': `${theme.appBorderRadius + 1}px`,\n  '--sb-sidebar-bottom-card-box-shadow': `0 1px 2px 0 rgba(0, 0, 0, 0.05), 0px -5px 20px 10px ${theme.background.app}`,\n}));\n\ninterface SidebarBottomProps {\n  api: API;\n  notifications: State['notifications'];\n  errorCount: number;\n  warningCount: number;\n  successCount: number;\n  hasStatuses: boolean;\n  isDevelopment?: boolean;\n  testProviderStates: TestProviderStateByProviderId;\n  registeredTestProviders: Addon_Collection<Addon_TestProviderType>;\n  onRunAll: () => void;\n}\n\nexport const SidebarBottomBase = ({\n  api,\n  notifications = [],\n  errorCount,\n  warningCount,\n  successCount,\n  hasStatuses,\n  isDevelopment,\n  testProviderStates,\n  registeredTestProviders,\n  onRunAll,\n}: SidebarBottomProps) => {\n  const spacerRef = useRef<HTMLDivElement | null>(null);\n  const wrapperRef = useRef<HTMLDivElement | null>(null);\n  const [warningsActive, setWarningsActive] = useState(false);\n  const [errorsActive, setErrorsActive] = useState(false);\n\n  useEffect(() => {\n    if (spacerRef.current && wrapperRef.current) {\n      const resizeObserver = new ResizeObserver(() => {\n        if (spacerRef.current && wrapperRef.current) {\n          spacerRef.current.style.height = `${wrapperRef.current.scrollHeight}px`;\n        }\n      });\n      resizeObserver.observe(wrapperRef.current);\n      return () => resizeObserver.disconnect();\n    }\n  }, []);\n\n  useEffect(() => {\n    const filter = getFilter(warningCount > 0 && warningsActive, errorCount > 0 && errorsActive);\n    api.experimental_setFilter('sidebar-bottom-filter', filter);\n  }, [api, warningCount, errorCount, warningsActive, errorsActive]);\n\n  if (\n    !warningCount &&\n    !errorCount &&\n    Object.values(registeredTestProviders).length === 0 &&\n    notifications.length === 0\n  ) {\n    return null;\n  }\n\n  return (\n    <Fragment>\n      <Spacer id={SIDEBAR_BOTTOM_SPACER_ID} ref={spacerRef}></Spacer>\n      <Content id={SIDEBAR_BOTTOM_WRAPPER_ID} ref={wrapperRef}>\n        <NotificationList notifications={notifications} clearNotification={api.clearNotification} />\n        {isDevelopment && (\n          <TestingWidget\n            {...{\n              registeredTestProviders,\n              testProviderStates,\n              onRunAll: () => {\n                onRunAll();\n                setErrorsActive(false);\n                setWarningsActive(false);\n              },\n              hasStatuses,\n              clearStatuses: () => {\n                internal_fullStatusStore.unset();\n                internal_fullTestProviderStore.clearAll();\n                setErrorsActive(false);\n                setWarningsActive(false);\n              },\n              errorCount,\n              errorsActive,\n              setErrorsActive,\n              warningCount,\n              warningsActive,\n              setWarningsActive,\n              successCount,\n            }}\n          />\n        )}\n      </Content>\n    </Fragment>\n  );\n};\n\nexport const SidebarBottom = ({ isDevelopment }: { isDevelopment?: boolean }) => {\n  const api = useStorybookApi();\n  const registeredTestProviders = api.getElements(Addon_TypesEnum.experimental_TEST_PROVIDER);\n  const { notifications } = useStorybookState();\n  const { hasStatuses, errorCount, warningCount, successCount } = experimental_useStatusStore(\n    (statuses) => {\n      return Object.values(statuses).reduce(\n        (result, storyStatuses) => {\n          Object.values(storyStatuses).forEach((status) => {\n            result.hasStatuses = true;\n            if (status.value === 'status-value:error') {\n              result.errorCount += 1;\n            }\n            if (status.value === 'status-value:warning') {\n              result.warningCount += 1;\n            }\n            if (status.value === 'status-value:success') {\n              result.successCount += 1;\n            }\n          });\n          return result;\n        },\n        { errorCount: 0, warningCount: 0, successCount: 0, hasStatuses: false }\n      );\n    }\n  );\n\n  const testProviderStates = experimental_useTestProviderStore();\n\n  return (\n    <SidebarBottomBase\n      api={api}\n      notifications={notifications}\n      hasStatuses={hasStatuses}\n      errorCount={errorCount}\n      warningCount={warningCount}\n      successCount={successCount}\n      isDevelopment={isDevelopment}\n      testProviderStates={testProviderStates}\n      registeredTestProviders={registeredTestProviders}\n      onRunAll={internal_fullTestProviderStore.runAll}\n    />\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/StatusButton.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React, { forwardRef } from 'react';\n\nimport { Button } from 'storybook/internal/components';\nimport type { StatusValue } from 'storybook/internal/types';\n\nimport type { Theme } from '@emotion/react';\nimport { darken, lighten } from 'polished';\nimport { styled } from 'storybook/theming';\n\nimport { getStatus } from '../../utils/status.tsx';\n\nconst withStatusColor = ({ theme, status }: { theme: Theme; status: StatusValue }) => ({\n  color: getStatus(theme, status).iconColor ?? undefined,\n});\n\nexport const StatusLabel = styled.div<{ status: StatusValue }>(withStatusColor, {\n  margin: 3,\n});\n\nexport type StatusButtonProps = ComponentProps<typeof StyledButton>;\n\nconst StyledButton = styled(Button)<{\n  height?: number;\n  width?: number;\n  status: StatusValue;\n  selectedItem?: boolean;\n}>(\n  withStatusColor,\n  ({ theme, height, width }) => ({\n    transition: 'none',\n    display: 'inline-flex',\n    alignItems: 'center',\n    justifyContent: 'center',\n    width: width || 28,\n    height: height || 28,\n\n    '&:hover': {\n      color: theme.color.secondary,\n      background:\n        theme.base === 'dark'\n          ? darken(0.3, theme.color.secondary)\n          : lighten(0.4, theme.color.secondary),\n    },\n\n    '[data-selected=\"true\"] &': {\n      background:\n        theme.base === 'dark' ? darken(0.18, theme.color.secondary) : theme.color.secondary,\n      boxShadow: `0 0 5px 5px ${theme.base === 'dark' ? darken(0.18, theme.color.secondary) : theme.color.secondary}`,\n\n      '&:hover': {\n        background:\n          theme.base === 'dark' ? darken(0.1, theme.color.secondary) : theme.color.secondary,\n      },\n    },\n\n    '&:focus': {\n      color: theme.color.secondary,\n      borderColor: theme.color.secondary,\n      outlineOffset: -2,\n\n      '&:not(:focus-visible)': {\n        borderColor: 'transparent',\n      },\n    },\n  }),\n  ({ theme, selectedItem }) =>\n    selectedItem && {\n      '&:hover': {\n        boxShadow: `inset 0 0 0 2px ${theme.color.secondary}`,\n        background: 'rgba(255, 255, 255, 0.2)',\n      },\n    }\n);\n\nexport const StatusButton = forwardRef<HTMLButtonElement, StatusButtonProps>((props, ref) => {\n  return <StyledButton variant=\"ghost\" padding=\"small\" {...props} ref={ref} />;\n});\nStatusButton.displayName = 'StatusButton';\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/StatusContext.tsx",
    "content": "import { createContext, useContext } from 'react';\n\nimport type {\n  Status,\n  StatusValue,\n  StatusesByStoryIdAndTypeId,\n  StoryId,\n} from 'storybook/internal/types';\n\nimport type { StoriesHash } from 'storybook/manager-api';\n\nimport type { Item } from '../../container/Sidebar.tsx';\nimport { getDescendantIds } from '../../utils/tree.ts';\n\nexport const StatusContext = createContext<{\n  data?: StoriesHash;\n  allStatuses?: StatusesByStoryIdAndTypeId;\n  groupStatus?: Record<StoryId, StatusValue>;\n}>({});\n\nexport const useStatusSummary = (item: Item) => {\n  const { data, allStatuses, groupStatus } = useContext(StatusContext);\n  const summary: {\n    counts: Record<StatusValue, number>;\n    statusesByValue: Record<StatusValue, Record<StoryId, Status[]>>;\n  } = {\n    counts: {\n      'status-value:pending': 0,\n      'status-value:success': 0,\n      'status-value:new': 0,\n      'status-value:modified': 0,\n      'status-value:affected': 0,\n      'status-value:error': 0,\n      'status-value:warning': 0,\n      'status-value:unknown': 0,\n    },\n    statusesByValue: {\n      'status-value:pending': {},\n      'status-value:success': {},\n      'status-value:new': {},\n      'status-value:modified': {},\n      'status-value:affected': {},\n      'status-value:error': {},\n      'status-value:warning': {},\n      'status-value:unknown': {},\n    },\n  };\n\n  if (\n    data &&\n    allStatuses &&\n    groupStatus &&\n    [\n      'status-value:pending',\n      'status-value:new',\n      'status-value:modified',\n      'status-value:affected',\n      'status-value:warning',\n      'status-value:error',\n    ].includes(groupStatus[item.id])\n  ) {\n    for (const storyId of getDescendantIds(data, item.id, false)) {\n      for (const status of Object.values(allStatuses[storyId] ?? {})) {\n        summary.counts[status.value]++;\n        summary.statusesByValue[status.value][storyId] ??= [];\n        summary.statusesByValue[status.value][storyId].push(status);\n      }\n    }\n  }\n\n  return summary;\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/TestingWidget.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Listener } from 'storybook/internal/channels';\nimport type { TestProviderStateByProviderId } from 'storybook/internal/types';\nimport {\n  type Addon_Collection,\n  type Addon_TestProviderType,\n  Addon_TypesEnum,\n} from 'storybook/internal/types';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { ManagerContext, mockChannel } from 'storybook/manager-api';\nimport { expect, fireEvent, fn, waitFor } from 'storybook/test';\nimport { styled } from 'storybook/theming';\n\nimport { internal_fullTestProviderStore } from '../../manager-stores.mock.ts';\nimport { TestingWidget } from './TestingWidget.tsx';\n\nconst Wrapper = styled.div(({ theme }) => ({\n  maxWidth: 250,\n  '--card-box-shadow': `0 1px 2px 0 rgba(0, 0, 0, 0.05), 0px -5px 20px 10px ${theme.background.app}`,\n}));\n\nconst TestProvider = styled.div({\n  padding: 8,\n  fontSize: 12,\n});\n\nconst registeredTestProviders: Addon_Collection<Addon_TestProviderType> = {\n  'component-tests': {\n    type: Addon_TypesEnum.experimental_TEST_PROVIDER,\n    id: 'component-tests',\n    render: () => <TestProvider>Component tests</TestProvider>,\n  },\n  'visual-tests': {\n    type: Addon_TypesEnum.experimental_TEST_PROVIDER,\n    id: 'visual-tests',\n    render: () => <TestProvider>Visual tests</TestProvider>,\n  },\n  linting: {\n    type: Addon_TypesEnum.experimental_TEST_PROVIDER,\n    id: 'linting',\n    render: () => <TestProvider>Linting</TestProvider>,\n  },\n};\n\nconst testProviderStates: TestProviderStateByProviderId = {\n  'component-tests': 'test-provider-state:pending',\n  'visual-tests': 'test-provider-state:pending',\n  linting: 'test-provider-state:pending',\n};\n\nconst channel = mockChannel();\nconst managerContext: any = {\n  api: {\n    on: (eventName: string, listener: Listener) => {\n      return channel.on(eventName, listener);\n    },\n    off: (eventName: string, listener: Listener) => channel.off(eventName, listener),\n    runTestProvider: fn().mockName('api::runTestProvider'),\n    cancelTestProvider: fn().mockName('api::cancelTestProvider'),\n    updateTestProviderState: fn().mockName('api::updateTestProviderState'),\n  },\n};\n\nconst meta = {\n  component: TestingWidget,\n  title: 'Sidebar/TestingWidget',\n  args: {\n    registeredTestProviders,\n    testProviderStates,\n    hasStatuses: false,\n    clearStatuses: fn(),\n    onRunAll: fn(),\n    errorCount: 0,\n    errorsActive: false,\n    setErrorsActive: fn(),\n    warningCount: 0,\n    warningsActive: false,\n    setWarningsActive: fn(),\n    successCount: 0,\n  },\n  decorators: [\n    (StoryFn) => (\n      <ManagerContext.Provider value={managerContext}>\n        <Wrapper>\n          <StoryFn />\n        </Wrapper>\n      </ManagerContext.Provider>\n    ),\n  ],\n} satisfies Meta<typeof TestingWidget>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {};\n\nexport const Expanded: Story = {\n  play: async ({ canvas }) => {\n    const button = await canvas.findByRole('button', { name: /Expand/ });\n    await fireEvent.click(button);\n    await new Promise((resolve) => setTimeout(resolve, 500));\n  },\n};\n\nexport const Statuses: Story = {\n  args: {\n    hasStatuses: true,\n    errorCount: 14,\n    warningCount: 42,\n  },\n  play: Expanded.play,\n};\n\nexport const PassingStatuses: Story = {\n  args: {\n    hasStatuses: true,\n  },\n  play: Expanded.play,\n};\n\nexport const ErrorsActive: Story = {\n  args: {\n    ...Statuses.args,\n    errorsActive: true,\n  },\n  play: Expanded.play,\n};\n\nexport const WarningsActive: Story = {\n  args: {\n    ...Statuses.args,\n    warningsActive: true,\n  },\n  play: Expanded.play,\n};\n\nexport const BothActive: Story = {\n  args: {\n    ...Statuses.args,\n    errorsActive: true,\n    warningsActive: true,\n  },\n  play: Expanded.play,\n};\n\nexport const CollapsedStatuses: Story = {\n  args: Statuses.args,\n};\n\nexport const Running: Story = {\n  args: {\n    testProviderStates: {\n      ...testProviderStates,\n      'component-tests': 'test-provider-state:running',\n    },\n  },\n  play: Expanded.play,\n};\n\nexport const RunningWithErrors: Story = {\n  args: {\n    ...Statuses.args,\n    ...Running.args,\n  },\n  play: Expanded.play,\n};\n\nexport const CollapsedRunning: Story = {\n  args: Running.args,\n};\n\nexport const CollapsedRunningWithErrors: Story = {\n  args: {\n    ...RunningWithErrors.args,\n  },\n};\n\nexport const Crashed: Story = {\n  args: {\n    testProviderStates: {\n      ...testProviderStates,\n      'component-tests': 'test-provider-state:crashed',\n    },\n  },\n};\n\nexport const SettingsUpdated: Story = {\n  play: async (playContext) => {\n    await Expanded.play!(playContext);\n    const testingModule = document.getElementById('storybook-testing-module');\n    await waitFor(() => expect(testingModule!.dataset.updated).toBe('false'));\n    internal_fullTestProviderStore.settingsChanged();\n    await waitFor(() => expect(testingModule!.dataset.updated).toBe('true'));\n    await waitFor(() => expect(testingModule!.dataset.updated).toBe('false'));\n  },\n};\n\nexport const NoTestProvider: Story = {\n  args: {\n    registeredTestProviders: {},\n  },\n};\n\nexport const NoTestProviderWithStatuses: Story = {\n  args: {\n    ...Statuses.args,\n    registeredTestProviders: {},\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/TestingWidget.tsx",
    "content": "import React, {\n  type ComponentProps,\n  type ReactNode,\n  type SyntheticEvent,\n  useCallback,\n  useEffect,\n  useRef,\n  useState,\n} from 'react';\n\nimport { once } from 'storybook/internal/client-logger';\nimport { ActionList, Card } from 'storybook/internal/components';\nimport type {\n  Addon_Collection,\n  Addon_TestProviderType,\n  TestProviderStateByProviderId,\n} from 'storybook/internal/types';\n\nimport { ChevronSmallUpIcon, PlayAllHollowIcon, SweepIcon } from '@storybook/icons';\n\nimport { internal_fullTestProviderStore } from '#manager-stores';\nimport { styled } from 'storybook/theming';\n\nimport { useLandmark } from '../../hooks/useLandmark.ts';\nimport { Optional } from '../Optional/Optional.tsx';\nimport { useDynamicFavicon } from './useDynamicFavicon.ts';\n\nconst DEFAULT_HEIGHT = 500;\n\nconst HoverCard = styled(Card)({\n  display: 'flex',\n  flexDirection: 'column-reverse',\n\n  '&:hover #testing-module-collapse-toggle': {\n    opacity: 1,\n  },\n});\n\nconst Collapsible = styled.div(({ theme }) => ({\n  overflow: 'hidden',\n  boxShadow: `inset 0 -1px 0 ${theme.appBorderColor}`,\n}));\n\nconst Content = styled.div({\n  display: 'flex',\n  flexDirection: 'column',\n});\n\nconst Bar = styled.div<{ onClick?: (e: SyntheticEvent) => void }>(({ onClick }) => ({\n  display: 'flex',\n  width: '100%',\n  cursor: onClick ? 'pointer' : 'default',\n  userSelect: 'none',\n  alignItems: 'center',\n  justifyContent: 'space-between',\n  overflow: 'hidden',\n  padding: 4,\n  gap: 4,\n}));\n\nconst Action = styled.div({\n  display: 'flex',\n  flexBasis: '100%',\n  containerType: 'inline-size',\n});\n\nconst Filters = styled.div({\n  display: 'flex',\n  justifyContent: 'flex-end',\n  gap: 4,\n});\n\nconst CollapseToggle = styled(ActionList.Button)({\n  opacity: 0,\n  transition: 'opacity 250ms',\n  '&:focus, &:hover': {\n    opacity: 1,\n  },\n});\n\nconst RunButton = ({\n  children,\n  isRunning,\n  onRunAll,\n  ...props\n}: { children?: ReactNode; isRunning: boolean; onRunAll: () => void } & ComponentProps<\n  typeof ActionList.Button\n>) => (\n  <ActionList.Button\n    ariaLabel={isRunning ? 'Running...' : 'Run tests'}\n    tooltip={isRunning ? 'Running tests...' : 'Start all tests'}\n    disabled={isRunning}\n    onClick={(e: SyntheticEvent) => {\n      e.stopPropagation();\n      onRunAll();\n    }}\n    {...props}\n  >\n    <ActionList.Icon>\n      <PlayAllHollowIcon />\n    </ActionList.Icon>\n    {children}\n  </ActionList.Button>\n);\n\nconst StatusButton = styled(ActionList.Toggle)<{\n  pressed: boolean;\n  status: 'negative' | 'warning';\n}>(\n  { minWidth: 28, outlineOffset: -2 },\n  ({ pressed, status, theme }) =>\n    !pressed &&\n    (theme.base === 'light'\n      ? {\n          background: {\n            negative: theme.background.negative,\n            warning: theme.background.warning,\n          }[status],\n          color: {\n            negative: theme.color.negativeText,\n            warning: theme.color.warningText,\n          }[status],\n        }\n      : {\n          background: {\n            negative: `${theme.color.negative}22`,\n            warning: `${theme.color.warning}22`,\n          }[status],\n          color: {\n            negative: theme.color.negative,\n            warning: theme.color.warning,\n          }[status],\n        })\n);\n\nconst TestProvider = styled.div(({ theme }) => ({\n  padding: 4,\n\n  '&:not(:last-child)': {\n    boxShadow: `inset 0 -1px 0 ${theme.appBorderColor}`,\n  },\n}));\n\ninterface TestingModuleProps {\n  registeredTestProviders: Addon_Collection<Addon_TestProviderType>;\n  testProviderStates: TestProviderStateByProviderId;\n  hasStatuses: boolean;\n  clearStatuses: () => void;\n  onRunAll: () => void;\n  errorCount: number;\n  errorsActive: boolean;\n  setErrorsActive: (active: boolean) => void;\n  warningCount: number;\n  warningsActive: boolean;\n  setWarningsActive: (active: boolean) => void;\n  successCount: number;\n}\n\nexport const TestingWidget = ({\n  registeredTestProviders,\n  testProviderStates,\n  hasStatuses,\n  clearStatuses,\n  onRunAll,\n  errorCount,\n  errorsActive,\n  setErrorsActive,\n  warningCount,\n  warningsActive,\n  setWarningsActive,\n  successCount,\n}: TestingModuleProps) => {\n  const timeoutRef = useRef<null | ReturnType<typeof setTimeout>>(null);\n  const contentRef = useRef<HTMLDivElement>(null);\n  const [maxHeight, setMaxHeight] = useState(DEFAULT_HEIGHT);\n  const [isCollapsed, setCollapsed] = useState(true);\n  const [isChangingCollapse, setChangingCollapse] = useState(false);\n  const [isUpdated, setIsUpdated] = useState(false);\n  const settingsUpdatedTimeoutRef = useRef<ReturnType<typeof setTimeout>>();\n\n  useEffect(() => {\n    const unsubscribe = internal_fullTestProviderStore.onSettingsChanged(() => {\n      setIsUpdated(true);\n      clearTimeout(settingsUpdatedTimeoutRef.current);\n      settingsUpdatedTimeoutRef.current = setTimeout(() => {\n        setIsUpdated(false);\n      }, 1000);\n    });\n    return () => {\n      unsubscribe();\n      clearTimeout(settingsUpdatedTimeoutRef.current);\n    };\n  }, []);\n\n  useEffect(() => {\n    if (contentRef.current) {\n      setMaxHeight(contentRef.current?.getBoundingClientRect().height || DEFAULT_HEIGHT);\n\n      const resizeObserver = new ResizeObserver(() => {\n        requestAnimationFrame(() => {\n          if (contentRef.current && !isCollapsed) {\n            const height = contentRef.current?.getBoundingClientRect().height || DEFAULT_HEIGHT;\n\n            setMaxHeight(height);\n          }\n        });\n      });\n      resizeObserver.observe(contentRef.current);\n      return () => resizeObserver.disconnect();\n    }\n  }, [isCollapsed]);\n\n  const toggleCollapsed = useCallback((event?: SyntheticEvent, value?: boolean) => {\n    event?.stopPropagation();\n    setChangingCollapse(true);\n    setCollapsed((s) => value ?? !s);\n    if (timeoutRef.current) {\n      clearTimeout(timeoutRef.current);\n    }\n    timeoutRef.current = setTimeout(() => {\n      setChangingCollapse(false);\n    }, 250);\n  }, []);\n\n  const isRunning = Object.values(testProviderStates).some(\n    (testProviderState) => testProviderState === 'test-provider-state:running'\n  );\n  const isCrashed = Object.values(testProviderStates).some(\n    (testProviderState) => testProviderState === 'test-provider-state:crashed'\n  );\n  const hasTestProviders = Object.values(registeredTestProviders).length > 0;\n\n  useEffect(() => {\n    if (isCrashed && isCollapsed) {\n      toggleCollapsed(undefined, false);\n    }\n  }, [isCrashed, isCollapsed, toggleCollapsed]);\n\n  useDynamicFavicon(\n    isCrashed\n      ? 'critical'\n      : errorCount > 0\n        ? 'negative'\n        : warningCount > 0\n          ? 'warning'\n          : isRunning\n            ? 'active'\n            : successCount > 0\n              ? 'positive'\n              : undefined\n  );\n\n  const cardRef = useRef<HTMLDivElement>(null);\n  const { landmarkProps } = useLandmark(\n    { 'aria-labelledby': 'storybook-testing-widget-heading', role: 'region' },\n    cardRef\n  );\n\n  if (!hasTestProviders && !errorCount && !warningCount) {\n    return null;\n  }\n\n  return (\n    <HoverCard\n      id=\"storybook-testing-module\"\n      data-updated={isUpdated}\n      outlineAnimation={isRunning ? 'spin' : 'none'}\n      outlineColor={\n        isCrashed || (isRunning && errorCount > 0) ? 'negative' : isUpdated ? 'positive' : undefined\n      }\n      ref={cardRef}\n      outlineAttrs={landmarkProps}\n    >\n      <h2 id=\"storybook-testing-widget-heading\" className=\"sb-sr-only\">\n        Component tests\n      </h2>\n      <Bar {...(hasTestProviders ? { onClick: (e) => toggleCollapsed(e) } : {})}>\n        <Action>\n          {hasTestProviders && (\n            <Optional\n              content={\n                <RunButton isRunning={isRunning} onRunAll={onRunAll}>\n                  {isRunning ? 'Running...' : 'Run tests'}\n                </RunButton>\n              }\n              fallback={<RunButton isRunning={isRunning} onRunAll={onRunAll} />}\n            />\n          )}\n        </Action>\n        <Filters>\n          {hasTestProviders && (\n            <CollapseToggle\n              onClick={(e) => toggleCollapsed(e)}\n              id=\"testing-module-collapse-toggle\"\n              ariaLabel={isCollapsed ? 'Expand testing module' : 'Collapse testing module'}\n            >\n              <ChevronSmallUpIcon\n                style={{\n                  transform: isCollapsed ? 'none' : 'rotate(180deg)',\n                  transition: 'transform 250ms',\n                }}\n              />\n            </CollapseToggle>\n          )}\n\n          {errorCount > 0 && (\n            <StatusButton\n              id=\"errors-found-filter\"\n              size=\"medium\"\n              variant=\"ghost\"\n              padding={errorCount < 10 ? 'medium' : 'small'}\n              status=\"negative\"\n              pressed={errorsActive}\n              onClick={(e: SyntheticEvent) => {\n                e.stopPropagation();\n                setErrorsActive(!errorsActive);\n              }}\n              ariaLabel={`Filter main navigation to show ${errorCount} tests with errors`}\n              tooltip={\n                errorsActive\n                  ? 'Clear test error filter'\n                  : `Filter sidebar to show ${errorCount} tests with errors`\n              }\n            >\n              {errorCount < 1000 ? errorCount : '999+'}\n            </StatusButton>\n          )}\n          {warningCount > 0 && (\n            <StatusButton\n              id=\"warnings-found-filter\"\n              size=\"medium\"\n              variant=\"ghost\"\n              padding={warningCount < 10 ? 'medium' : 'small'}\n              status=\"warning\"\n              pressed={warningsActive}\n              onClick={(e: SyntheticEvent) => {\n                e.stopPropagation();\n                setWarningsActive(!warningsActive);\n              }}\n              ariaLabel={`Filter main navigation to show ${warningCount} tests with warnings`}\n              tooltip={\n                warningsActive\n                  ? 'Clear test warning filter'\n                  : `Filter sidebar to show ${warningCount} tests with warnings`\n              }\n            >\n              {warningCount < 1000 ? warningCount : '999+'}\n            </StatusButton>\n          )}\n          {hasStatuses && (\n            <ActionList.Button\n              id=\"clear-statuses\"\n              onClick={(e: SyntheticEvent) => {\n                e.stopPropagation();\n                clearStatuses();\n              }}\n              disabled={isRunning}\n              ariaLabel={\n                isRunning ? \"Can't clear statuses while tests are running\" : 'Clear all statuses'\n              }\n            >\n              <SweepIcon />\n            </ActionList.Button>\n          )}\n        </Filters>\n      </Bar>\n\n      {hasTestProviders && (\n        <Collapsible\n          data-testid=\"collapse\"\n          {...(isCollapsed && { inert: '' })}\n          style={{\n            transition: isChangingCollapse ? 'max-height 250ms' : 'max-height 0ms',\n            display: hasTestProviders ? 'block' : 'none',\n            maxHeight: isCollapsed ? 0 : maxHeight,\n          }}\n        >\n          <Content ref={contentRef}>\n            {Object.values(registeredTestProviders).map((registeredTestProvider) => {\n              const { render: Render, id } = registeredTestProvider;\n              if (!Render) {\n                once.warn(\n                  `No render function found for test provider with id '${id}', skipping...`\n                );\n                return null;\n              }\n              return (\n                <TestProvider key={id} data-module-id={id}>\n                  <Render />\n                </TestProvider>\n              );\n            })}\n          </Content>\n        </Collapsible>\n      )}\n    </HoverCard>\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/Tree.stories.tsx",
    "content": "import React, { useState } from 'react';\n\nimport {\n  type Addon_Collection,\n  type Addon_TestProviderType,\n  Addon_TypesEnum,\n} from 'storybook/internal/types';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { action } from 'storybook/actions';\nimport { type ComponentEntry, type IndexHash, ManagerContext } from 'storybook/manager-api';\nimport { expect, fn, screen, userEvent, within } from 'storybook/test';\n\nimport { IconSymbols } from './IconSymbols.tsx';\nimport { DEFAULT_REF_ID } from './Sidebar.tsx';\nimport { Tree } from './Tree.tsx';\nimport { index } from './mockdata.large.ts';\n\nconst managerContext: any = {\n  state: {\n    docsOptions: {\n      defaultName: 'Docs',\n      autodocs: 'tag',\n      docsMode: false,\n    },\n  },\n  api: {\n    on: fn().mockName('api::on'),\n    off: fn().mockName('api::off'),\n    once: fn().mockName('api::once'),\n    emit: fn().mockName('api::emit'),\n    getShortcutKeys: fn().mockName('api::getShortcutKeys'),\n    getCurrentStoryData: fn().mockName('api::getCurrentStoryData'),\n    getElements: fn(\n      () =>\n        ({\n          'component-tests': {\n            type: Addon_TypesEnum.experimental_TEST_PROVIDER,\n            id: 'component-tests',\n            render: () => 'Component tests',\n            sidebarContextMenu: () => <div>TEST_PROVIDER_CONTEXT_CONTENT</div>,\n          },\n          'visual-tests': {\n            type: Addon_TypesEnum.experimental_TEST_PROVIDER,\n            id: 'visual-tests',\n            render: () => 'Visual tests',\n            sidebarContextMenu: () => null,\n          },\n        }) satisfies Addon_Collection<Addon_TestProviderType>\n    ),\n    getData: fn().mockName('api::getData'),\n  },\n};\n\nconst meta = {\n  component: Tree,\n  title: 'Sidebar/Tree',\n  excludeStories: /.*Data$/,\n  globals: {\n    sb_theme: 'light',\n    viewport: { value: 'sized' },\n  },\n  parameters: {\n    layout: 'fullscreen',\n    viewport: {\n      options: {\n        sized: {\n          name: 'Sized',\n          styles: {\n            width: '380px',\n            height: '90%',\n          },\n        },\n      },\n    },\n    chromatic: { viewports: [380] },\n  },\n  decorators: [\n    (storyFn) => (\n      <ManagerContext.Provider value={managerContext}>\n        <IconSymbols />\n        {storyFn()}\n      </ManagerContext.Provider>\n    ),\n  ],\n} as Meta<typeof Tree>;\n\nexport default meta;\n\n// @ts-expect-error (non strict)\nconst storyId = Object.values(index).find((story) => story.type === 'story').id;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Full: Story = {\n  args: {\n    docsMode: false,\n    isBrowsing: true,\n    isMain: true,\n    refId: DEFAULT_REF_ID,\n    setHighlightedItemId: action('setHighlightedItemId'),\n  },\n  render: (args) => {\n    const [selectedId, setSelectedId] = useState(storyId);\n    return (\n      <Tree\n        {...args}\n        data={index}\n        selectedStoryId={selectedId}\n        onSelectStoryId={setSelectedId}\n        highlightedRef={{ current: { itemId: selectedId, refId: DEFAULT_REF_ID } }}\n      />\n    );\n  },\n};\nexport const Dark: Story = {\n  ...Full,\n  globals: { sb_theme: 'dark' },\n};\n\nexport const SingleStoryComponents: Story = {\n  args: {\n    docsMode: false,\n    isBrowsing: true,\n    isMain: true,\n    refId: DEFAULT_REF_ID,\n    setHighlightedItemId: action('setHighlightedItemId'),\n  },\n  render: (args) => {\n    const [selectedId, setSelectedId] = useState('tooltip-tooltipbuildlist--default');\n    return (\n      <Tree\n        {...args}\n        // @ts-expect-error (non strict)\n        data={{\n          ...{\n            single: {\n              type: 'component',\n              name: 'Single',\n              id: 'single',\n              parent: null,\n              depth: 0,\n              children: ['single--single'],\n              renderLabel: () => <span>🔥 Single</span>,\n            },\n            'single--single': {\n              type: 'story',\n              subtype: 'story',\n              id: 'single--single',\n              title: 'Single',\n              name: 'Single',\n              tags: [],\n              prepared: true,\n              args: {},\n              argTypes: {},\n              initialArgs: {},\n              depth: 1,\n              parent: 'single',\n              renderLabel: () => <span>🔥 Single</span>,\n              importPath: './single.stories.js',\n            },\n          },\n          ...Object.keys(index).reduce((acc, key) => {\n            if (key === 'tooltip-tooltipselect--default') {\n              acc['tooltip-tooltipselect--tooltipselect'] = {\n                ...index[key],\n                id: 'tooltip-tooltipselect--tooltipselect',\n                name: 'TooltipSelect',\n              };\n              return acc;\n            }\n            if (key === 'tooltip-tooltipselect') {\n              acc[key] = {\n                ...(index[key] as ComponentEntry),\n                children: ['tooltip-tooltipselect--tooltipselect'],\n              };\n              return acc;\n            }\n            if (key.startsWith('tooltip')) {\n              acc[key] = index[key];\n            }\n            return acc;\n          }, {} as IndexHash),\n        }}\n        highlightedRef={{ current: { itemId: selectedId, refId: DEFAULT_REF_ID } }}\n        selectedStoryId={selectedId}\n        onSelectStoryId={setSelectedId}\n      />\n    );\n  },\n};\n\nexport const DocsOnlySingleStoryComponents = {\n  render: () => {\n    const [selectedId, setSelectedId] = useState('tooltip-tooltipbuildlist--default');\n    return (\n      <Tree\n        docsMode={false}\n        isBrowsing\n        isMain\n        refId={DEFAULT_REF_ID}\n        // @ts-expect-error (non strict)\n        data={{\n          ...{\n            single: {\n              type: 'component',\n              name: 'Single',\n              id: 'single',\n              parent: null,\n              depth: 0,\n              children: ['single--docs'],\n            },\n            'single--docs': {\n              type: 'docs',\n              id: 'single--docs',\n              title: 'Single',\n              name: 'Single',\n              tags: [],\n              prepared: true,\n              depth: 1,\n              parent: 'single',\n              importPath: './single.stories.js',\n            },\n          },\n          ...Object.keys(index).reduce((acc, key) => {\n            if (key === 'tooltip-tooltipselect--default') {\n              acc['tooltip-tooltipselect--tooltipselect'] = {\n                ...index[key],\n                id: 'tooltip-tooltipselect--tooltipselect',\n                name: 'TooltipSelect',\n              };\n              return acc;\n            }\n            if (key === 'tooltip-tooltipselect') {\n              acc[key] = {\n                ...(index[key] as ComponentEntry),\n                children: ['tooltip-tooltipselect--tooltipselect'],\n              };\n              return acc;\n            }\n            if (key.startsWith('tooltip')) {\n              acc[key] = index[key];\n            }\n            return acc;\n          }, {} as IndexHash),\n        }}\n        highlightedRef={{ current: { itemId: selectedId, refId: DEFAULT_REF_ID } }}\n        setHighlightedItemId={action('setHighlightedItemId')}\n        selectedStoryId={selectedId}\n        onSelectStoryId={setSelectedId}\n      />\n    );\n  },\n};\n\n// SkipToCanvas Link only shows on desktop widths\nexport const SkipToCanvasLinkFocused: Story = {\n  ...DocsOnlySingleStoryComponents,\n  parameters: {\n    chromatic: { viewports: [1280] },\n    viewport: {\n      options: {\n        desktop: {\n          name: 'Desktop',\n          styles: {\n            width: '100%',\n            height: '100%',\n          },\n        },\n      },\n    },\n  },\n  globals: {\n    viewport: { value: 'desktop' },\n  },\n  play: async ({ canvasElement }) => {\n    const screen = await within(canvasElement);\n    const link = await screen.findByText('Skip to content');\n\n    await link.focus();\n\n    await expect(link).toBeVisible();\n  },\n};\n\n// SkipToCanvas Link only shows on desktop widths\nexport const WithContextContent: Story = {\n  ...DocsOnlySingleStoryComponents,\n  parameters: {\n    chromatic: { viewports: [1280] },\n    viewport: {\n      options: {\n        desktop: {\n          name: 'Desktop',\n          styles: {\n            width: '100%',\n            height: '100%',\n          },\n        },\n      },\n    },\n  },\n  globals: {\n    viewport: { value: 'desktop' },\n  },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n\n    const link = await canvas.findByText('TooltipBuildList');\n    await userEvent.hover(link);\n\n    const contextButton = await canvas.findAllByTestId('context-menu');\n    await userEvent.click(contextButton[0]);\n\n    const popover = screen.getByRole('dialog');\n    await expect(popover).toBeVisible();\n    expect(popover).toHaveTextContent('TEST_PROVIDER_CONTEXT_CONTENT');\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/Tree.tsx",
    "content": "import type { ComponentProps, FC, MutableRefObject } from 'react';\nimport React, { useCallback, useMemo, useRef } from 'react';\n\nimport { Button, ListItem } from 'storybook/internal/components';\nimport { PRELOAD_ENTRIES } from 'storybook/internal/core-events';\nimport type { StatusValue } from 'storybook/internal/types';\nimport {\n  type API_HashEntry,\n  type StatusByTypeId,\n  type StatusesByStoryIdAndTypeId,\n  type StoryId,\n} from 'storybook/internal/types';\n\nimport {\n  CollapseIcon as CollapseIconSvg,\n  ExpandAltIcon,\n  StatusFailIcon,\n  StatusPassIcon,\n  StatusWarnIcon,\n  SyncIcon,\n} from '@storybook/icons';\n\nimport { internal_fullStatusStore as fullStatusStore } from '#manager-stores';\nimport { darken } from 'polished';\nimport { useStorybookApi } from 'storybook/manager-api';\nimport type {\n  API,\n  ComponentEntry,\n  GroupEntry,\n  StoriesHash,\n  StoryEntry,\n} from 'storybook/manager-api';\nimport { styled, useTheme } from 'storybook/theming';\n\nimport type { Link } from '../../../components/components/tooltip/TooltipLinkList.tsx';\nimport { MEDIA_DESKTOP_BREAKPOINT } from '../../constants.ts';\nimport { getGroupStatus, getMostCriticalStatusValue, getStatus } from '../../utils/status.tsx';\nimport {\n  createId,\n  getAncestorIds,\n  getDescendantIds,\n  getLink,\n  isStoryHoistable,\n} from '../../utils/tree.ts';\nimport { useLayout } from '../layout/LayoutProvider.tsx';\nimport { useContextMenu } from './ContextMenu.tsx';\nimport { UseSymbol } from './IconSymbols.tsx';\nimport { StatusButton } from './StatusButton.tsx';\nimport { StatusContext } from './StatusContext.tsx';\nimport {\n  ComponentNode,\n  DocumentNode,\n  GroupNode,\n  RootNode,\n  StoryBranchNode,\n  StoryLeafNode,\n  TestNode,\n} from './TreeNode.tsx';\nimport { CollapseIcon } from './components/CollapseIcon.tsx';\nimport type { Highlight, Item } from './types.ts';\nimport type { ExpandAction, ExpandedState } from './useExpanded.ts';\nimport { useExpanded } from './useExpanded.ts';\n\nexport type ExcludesNull = <T>(x: T | null) => x is T;\n\nconst CollapseButton = styled(Button)(({ theme }) => ({\n  fontSize: `${theme.typography.size.s1 - 1}px`,\n  fontWeight: theme.typography.weight.bold,\n  letterSpacing: '0.16em',\n  textTransform: 'uppercase',\n  color: theme.textMutedColor,\n  padding: '0 8px',\n}));\n\nexport const LeafNodeStyleWrapper = styled.div(({ theme }) => ({\n  position: 'relative',\n  display: 'flex',\n  justifyContent: 'space-between',\n  alignItems: 'flex-start',\n  color: theme.color.defaultText,\n  background: 'transparent',\n  minHeight: 28,\n  borderRadius: 4,\n  overflow: 'hidden',\n  '--tree-node-background-hover': theme.background.content,\n\n  [MEDIA_DESKTOP_BREAKPOINT]: {\n    '--tree-node-background-hover': theme.background.app,\n  },\n\n  '&:hover, &:focus': {\n    '--tree-node-background-hover': theme.background.hoverable,\n    background: 'var(--tree-node-background-hover)',\n    outline: 'none',\n  },\n\n  '& [data-displayed=\"off\"]': {\n    visibility: 'hidden',\n  },\n\n  '&:hover [data-displayed=\"off\"]': {\n    visibility: 'visible',\n  },\n\n  '& [data-displayed=\"on\"] + *': {\n    visibility: 'hidden',\n  },\n\n  '&:hover [data-displayed=\"off\"] + *': {\n    visibility: 'hidden',\n  },\n\n  '&[data-selected=\"true\"]': {\n    color: theme.color.lightest,\n    background: theme.base === 'dark' ? darken(0.18, theme.color.secondary) : theme.color.secondary,\n    fontWeight: theme.typography.weight.bold,\n\n    '&&:hover, &&:focus': {\n      background:\n        theme.base === 'dark' ? darken(0.18, theme.color.secondary) : theme.color.secondary,\n    },\n    svg: { color: theme.color.lightest },\n  },\n\n  a: { color: 'currentColor' },\n}));\n\nconst SkipToContentLink = styled(Button)(({ theme }) => ({\n  display: 'none',\n  '@media (min-width: 600px)': {\n    display: 'block',\n    fontSize: '10px',\n    overflow: 'hidden',\n    width: 1,\n    height: '20px',\n    boxSizing: 'border-box',\n    opacity: 0,\n    padding: 0,\n\n    '&:focus': {\n      opacity: 1,\n      padding: '5px 10px',\n      background: 'white',\n      color: theme.color.secondary,\n      width: 'auto',\n    },\n  },\n}));\n\ninterface NodeProps {\n  item: Item;\n  refId: string;\n  docsMode: boolean;\n  isOrphan: boolean;\n  isDisplayed: boolean;\n  isSelected: boolean;\n  isFullyExpanded?: boolean;\n  isExpanded: boolean;\n  setExpanded: (action: ExpandAction) => void;\n  setFullyExpanded?: () => void;\n  onSelectStoryId: (itemId: string) => void;\n  statuses: StatusByTypeId;\n  groupStatus: Record<StoryId, StatusValue>;\n  api: API;\n  collapsedData: Record<string, API_HashEntry>;\n}\n\nconst SuccessStatusIcon: FC<ComponentProps<typeof StatusPassIcon>> = (props) => {\n  const theme = useTheme();\n  return <StatusPassIcon {...props} color={theme.color.positive} />;\n};\n\nconst ErrorStatusIcon: FC<ComponentProps<typeof StatusFailIcon>> = (props) => {\n  const theme = useTheme();\n  return <StatusFailIcon {...props} color={theme.color.negative} />;\n};\n\nconst WarnStatusIcon: FC<ComponentProps<typeof StatusWarnIcon>> = (props) => {\n  const theme = useTheme();\n  return <StatusWarnIcon {...props} color={theme.color.warning} />;\n};\n\nconst PendingStatusIcon: FC<ComponentProps<typeof SyncIcon>> = (props) => {\n  const theme = useTheme();\n  return <SyncIcon {...props} size={12} color={theme.color.defaultText} />;\n};\n\nconst StatusIconMap: Record<StatusValue, React.ReactNode | null> = {\n  'status-value:success': <SuccessStatusIcon />,\n  'status-value:error': <ErrorStatusIcon />,\n  'status-value:warning': <WarnStatusIcon />,\n  'status-value:pending': <PendingStatusIcon />,\n  'status-value:new': null,\n  'status-value:modified': null,\n  'status-value:affected': null,\n  'status-value:unknown': null,\n};\n\nexport const ContextMenu = {\n  ListItem,\n};\n\nconst statusOrder: StatusValue[] = [\n  'status-value:success',\n  'status-value:error',\n  'status-value:warning',\n  'status-value:pending',\n  'status-value:unknown',\n];\n\nconst Node = React.memo<NodeProps>(function Node(props) {\n  const {\n    item,\n    statuses,\n    groupStatus,\n    refId,\n    docsMode,\n    isOrphan,\n    isDisplayed,\n    isSelected,\n    isFullyExpanded,\n    setFullyExpanded,\n    isExpanded,\n    setExpanded,\n    onSelectStoryId,\n    api,\n  } = props;\n  const theme = useTheme();\n  const { isDesktop, isMobile, setMobileMenuOpen } = useLayout();\n\n  if (!isDisplayed) {\n    return null;\n  }\n\n  const statusLinks = useMemo<Link[]>(() => {\n    if (item.type === 'story' || item.type === 'docs') {\n      return Object.entries(statuses)\n        .filter(([, status]) => status.sidebarContextMenu !== false)\n        .sort((a, b) => statusOrder.indexOf(a[1].value) - statusOrder.indexOf(b[1].value))\n        .map(([typeId, status]) => ({\n          id: typeId,\n          title: status.title,\n          description: status.description,\n          'aria-label': `Test status for ${status.title}: ${status.value}`,\n          icon: StatusIconMap[status.value],\n          onClick: () => {\n            onSelectStoryId(item.id);\n            fullStatusStore.selectStatuses([status]);\n          },\n        }));\n    }\n\n    return [];\n  }, [item.id, item.type, onSelectStoryId, statuses]);\n\n  const id = createId(item.id, refId);\n  const contextMenu =\n    refId === 'storybook_internal'\n      ? useContextMenu(item, statusLinks, api)\n      : { node: null, onMouseEnter: () => {} };\n\n  if (\n    (item.type === 'story' &&\n      !('children' in item && item.children) &&\n      (!('subtype' in item) || item.subtype !== 'test')) ||\n    item.type === 'docs'\n  ) {\n    const LeafNode = item.type === 'docs' ? DocumentNode : StoryLeafNode;\n\n    const statusValue = getMostCriticalStatusValue(\n      Object.values(statuses || {}).map((s) => s.value)\n    );\n    const { icon, textColor } = getStatus(theme, statusValue);\n\n    return (\n      <LeafNodeStyleWrapper\n        key={id}\n        className=\"sidebar-item\"\n        data-selected={isSelected}\n        data-ref-id={refId}\n        data-item-id={item.id}\n        data-parent-id={item.parent}\n        data-nodetype={item.type === 'docs' ? 'document' : 'story'}\n        data-highlightable={isDisplayed}\n        onMouseEnter={contextMenu.onMouseEnter}\n      >\n        <LeafNode\n          // @ts-expect-error (non strict)\n          style={isSelected ? {} : { color: textColor }}\n          href={getLink(item, refId)}\n          id={id}\n          depth={isOrphan ? item.depth : item.depth - 1}\n          onClick={(event) => {\n            event.preventDefault();\n            onSelectStoryId(item.id);\n\n            if (isMobile) {\n              setMobileMenuOpen(false);\n            }\n          }}\n          {...(item.type === 'docs' && { docsMode })}\n        >\n          {(item.renderLabel as (i: typeof item, api: API) => React.ReactNode)?.(item, api) ||\n            item.name}\n        </LeafNode>\n        {isSelected && (\n          <SkipToContentLink asChild ariaLabel={false}>\n            <a href=\"#storybook-preview-wrapper\">Skip to content</a>\n          </SkipToContentLink>\n        )}\n        {contextMenu.node}\n        {icon ? (\n          <StatusButton\n            ariaLabel={`Status: ${statusValue.replace('status-value:', '')}`}\n            data-testid=\"tree-status-button\"\n            type=\"button\"\n            status={statusValue}\n            selectedItem={isSelected}\n          >\n            {icon}\n          </StatusButton>\n        ) : null}\n      </LeafNodeStyleWrapper>\n    );\n  }\n\n  if (item.type === 'root') {\n    return (\n      <RootNode\n        key={id}\n        id={id}\n        className=\"sidebar-subheading\"\n        data-ref-id={refId}\n        data-item-id={item.id}\n        data-nodetype=\"root\"\n      >\n        <CollapseButton\n          variant=\"ghost\"\n          ariaLabel={isExpanded ? 'Collapse' : 'Expand'}\n          data-action=\"collapse-root\"\n          onClick={(event) => {\n            event.preventDefault();\n            setExpanded({ ids: [item.id], value: !isExpanded });\n          }}\n          aria-expanded={isExpanded}\n        >\n          <CollapseIcon isExpanded={isExpanded} />\n          {item.renderLabel?.(item, api) || item.name}\n        </CollapseButton>\n        {isExpanded && (\n          <Button\n            padding=\"small\"\n            variant=\"ghost\"\n            className=\"sidebar-subheading-action\"\n            ariaLabel={isFullyExpanded ? 'Collapse all' : 'Expand all'}\n            data-action=\"expand-all\"\n            data-expanded={isFullyExpanded}\n            onClick={(event) => {\n              event.preventDefault();\n              // @ts-expect-error (non strict)\n              setFullyExpanded();\n            }}\n          >\n            {isFullyExpanded ? <CollapseIconSvg /> : <ExpandAltIcon />}\n          </Button>\n        )}\n      </RootNode>\n    );\n  }\n\n  const itemStatus = getMostCriticalStatusValue(Object.values(statuses || {}).map((s) => s.value));\n  const { icon: itemIcon, textColor: itemColor } = getStatus(theme, itemStatus);\n  const itemStatusButton = itemIcon ? (\n    <StatusButton\n      ariaLabel={`Status: ${itemStatus.replace('status-value:', '')}`}\n      data-testid=\"tree-status-button\"\n      role=\"status\"\n      type=\"button\"\n      status={itemStatus}\n      selectedItem={isSelected}\n    >\n      {itemIcon}\n    </StatusButton>\n  ) : null;\n\n  if (\n    item.type === 'component' ||\n    item.type === 'group' ||\n    (item.type === 'story' && 'children' in item && item.children)\n  ) {\n    const { children = [] } = item;\n    const BranchNode = { component: ComponentNode, group: GroupNode, story: StoryBranchNode }[\n      item.type\n    ];\n    const status = getMostCriticalStatusValue([itemStatus, groupStatus?.[item.id]]);\n    const color = status ? getStatus(theme, status).textColor : null;\n    const showBranchStatus = (\n      [\n        'status-value:modified',\n        'status-value:affected',\n        'status-value:new',\n        'status-value:warning',\n        'status-value:error',\n      ] as StatusValue[]\n    ).includes(status);\n\n    return (\n      <LeafNodeStyleWrapper\n        key={id}\n        className=\"sidebar-item\"\n        data-selected={isSelected}\n        data-ref-id={refId}\n        data-item-id={item.id}\n        data-parent-id={item.parent}\n        data-nodetype={item.type}\n        data-highlightable={isDisplayed}\n        onMouseEnter={contextMenu.onMouseEnter}\n      >\n        <BranchNode\n          id={id}\n          style={color && !isSelected ? { color } : {}}\n          aria-controls={children.join(' ')}\n          aria-expanded={isExpanded}\n          depth={isOrphan ? item.depth : item.depth - 1}\n          isExpandable={children.length > 0}\n          isExpanded={isExpanded}\n          onClick={(event) => {\n            event.preventDefault();\n            if (item.type === 'story') {\n              onSelectStoryId(item.id);\n              if (!isExpanded || isSelected) {\n                setExpanded({ ids: [item.id], value: !isExpanded });\n              }\n            } else if (item.type === 'component') {\n              if (!isExpanded && isDesktop) {\n                onSelectStoryId(item.id);\n              }\n              setExpanded({ ids: [item.id], value: !isExpanded });\n            } else {\n              setExpanded({ ids: [item.id], value: !isExpanded });\n            }\n          }}\n          onMouseEnter={() => {\n            if (item.type === 'component' || item.type === 'story') {\n              api.emit(PRELOAD_ENTRIES, {\n                ids: [children[0]],\n                options: { target: refId },\n              });\n            }\n          }}\n        >\n          {(item.renderLabel as (i: typeof item, api: API) => React.ReactNode)?.(item, api) ||\n            item.name}\n        </BranchNode>\n        {isSelected && (\n          <SkipToContentLink asChild ariaLabel={false}>\n            <a href=\"#storybook-preview-wrapper\">Skip to content</a>\n          </SkipToContentLink>\n        )}\n        {contextMenu.node}\n        {showBranchStatus ? (\n          <StatusButton\n            ariaLabel={`Status: ${status.replace('status-value:', '')}`}\n            data-testid=\"tree-status-button\"\n            type=\"button\"\n            status={status}\n            selectedItem={isSelected}\n          >\n            {status === 'status-value:error' || status === 'status-value:warning' ? (\n              <svg key=\"icon\" viewBox=\"0 0 6 6\" width=\"6\" height=\"6\" type=\"dot\">\n                <UseSymbol type=\"dot\" />\n              </svg>\n            ) : (\n              getStatus(theme, status).icon\n            )}\n          </StatusButton>\n        ) : (\n          itemStatusButton\n        )}\n      </LeafNodeStyleWrapper>\n    );\n  }\n\n  const isTest = item.type === 'story' && item.subtype === 'test';\n  const LeafNode = isTest ? TestNode : { docs: DocumentNode, story: StoryLeafNode }[item.type];\n  const nodeType = isTest ? 'test' : { docs: 'document', story: 'story' }[item.type];\n\n  return (\n    <LeafNodeStyleWrapper\n      key={id}\n      className=\"sidebar-item\"\n      data-selected={isSelected}\n      data-ref-id={refId}\n      data-item-id={item.id}\n      data-parent-id={item.parent}\n      data-nodetype={nodeType}\n      data-highlightable={isDisplayed}\n      onMouseEnter={contextMenu.onMouseEnter}\n    >\n      <LeafNode\n        style={itemColor && !isSelected ? { color: itemColor } : {}}\n        href={getLink(item, refId)}\n        id={id}\n        depth={isOrphan ? item.depth : item.depth - 1}\n        onClick={(event) => {\n          event.preventDefault();\n          onSelectStoryId(item.id);\n\n          if (isMobile) {\n            setMobileMenuOpen(false);\n          }\n        }}\n      >\n        {(item.renderLabel as (i: typeof item, api: API) => React.ReactNode)?.(item, api) ||\n          item.name}\n      </LeafNode>\n      {isSelected && (\n        <SkipToContentLink ariaLabel={false} asChild>\n          <a href=\"#storybook-preview-wrapper\">Skip to content</a>\n        </SkipToContentLink>\n      )}\n      {contextMenu.node}\n      {itemStatusButton}\n    </LeafNodeStyleWrapper>\n  );\n});\n\nconst Root = React.memo<NodeProps & { expandableDescendants: string[] }>(function Root({\n  setExpanded,\n  isFullyExpanded,\n  expandableDescendants,\n  ...props\n}) {\n  const setFullyExpanded = useCallback(\n    () => setExpanded({ ids: expandableDescendants, value: !isFullyExpanded }),\n    [setExpanded, isFullyExpanded, expandableDescendants]\n  );\n  return (\n    <Node\n      {...props}\n      setExpanded={setExpanded}\n      isFullyExpanded={isFullyExpanded}\n      setFullyExpanded={setFullyExpanded}\n    />\n  );\n});\n\nexport const Tree = React.memo<{\n  isBrowsing: boolean;\n  isMain: boolean;\n  allStatuses?: StatusesByStoryIdAndTypeId;\n  refId: string;\n  data: StoriesHash;\n  docsMode: boolean;\n  highlightedRef: MutableRefObject<Highlight>;\n  setHighlightedItemId: (itemId: string) => void;\n  selectedStoryId: string | null;\n  onSelectStoryId: (storyId: string) => void;\n}>(function Tree({\n  isBrowsing,\n  refId,\n  data,\n  allStatuses,\n  docsMode,\n  highlightedRef,\n  setHighlightedItemId,\n  selectedStoryId,\n  onSelectStoryId,\n}) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const api = useStorybookApi();\n\n  // Find top-level nodes and group them so we can hoist any orphans and expand any roots.\n  const [rootIds, orphanIds, initialExpanded] = useMemo(\n    () =>\n      Object.keys(data).reduce<[string[], string[], ExpandedState]>(\n        (acc, id) => {\n          const item = data[id];\n\n          if (item.type === 'root') {\n            acc[0].push(id);\n          } else if (!item.parent) {\n            acc[1].push(id);\n          }\n\n          if (item.type === 'root' && item.startCollapsed) {\n            acc[2][id] = false;\n          }\n          return acc;\n        },\n        [[], [], {}]\n      ),\n    [data]\n  );\n\n  // Create a map of expandable descendants for each root/orphan item, which is needed later.\n  // Doing that here is a performance enhancement, as it avoids traversing the tree again later.\n  const { expandableDescendants } = useMemo(() => {\n    return [...orphanIds, ...rootIds].reduce(\n      (acc, nodeId) => {\n        acc.expandableDescendants[nodeId] = getDescendantIds(data, nodeId, false).filter(\n          (d) => !['story', 'docs'].includes(data[d].type)\n        );\n        return acc;\n      },\n      { orphansFirst: [] as string[], expandableDescendants: {} as Record<string, string[]> }\n    );\n  }, [data, rootIds, orphanIds]);\n\n  // Create a list of component IDs which should be collapsed into their (only) child.\n  // That is:\n  //  - components with a single story child with the same name\n  //  - components with only a single docs child\n  const singleStoryComponentIds = useMemo(() => {\n    return Object.keys(data).filter((id) => {\n      const entry = data[id];\n\n      if (entry.type !== 'component') {\n        return false;\n      }\n\n      const { children = [], name } = entry;\n\n      if (children.length !== 1) {\n        return false;\n      }\n\n      const onlyChild = data[children[0]];\n\n      if (onlyChild.type === 'docs') {\n        return true;\n      }\n\n      if (onlyChild.type === 'story' && onlyChild.subtype === 'story') {\n        return isStoryHoistable(onlyChild.name, name);\n      }\n      return false;\n    });\n  }, [data]);\n\n  // Omit single-story components from the list of nodes.\n  const collapsedItems = useMemo(\n    () => Object.keys(data).filter((id) => !singleStoryComponentIds.includes(id)),\n    [data, singleStoryComponentIds]\n  );\n\n  // Rewrite the dataset to place the single child story in place of the component.\n  // TODO: Move this to the `transformStoryIndexToStoriesHash` util.\n  const collapsedData = useMemo(() => {\n    return singleStoryComponentIds.reduce(\n      (acc, id) => {\n        const { children, parent, name } = data[id] as ComponentEntry;\n        const [childId] = children;\n        if (parent) {\n          const siblings = [...(data[parent] as GroupEntry).children];\n          siblings[siblings.indexOf(id)] = childId;\n          acc[parent] = { ...data[parent], children: siblings } as GroupEntry;\n        }\n        acc[childId] = {\n          ...data[childId],\n          name,\n          parent,\n          depth: data[childId].depth - 1,\n        } as StoryEntry;\n        return acc;\n      },\n      { ...data }\n    );\n  }, [data, singleStoryComponentIds]);\n\n  const ancestry = useMemo(() => {\n    return collapsedItems.reduce(\n      (acc, id) => Object.assign(acc, { [id]: getAncestorIds(collapsedData, id) }),\n      {} as { [key: string]: string[] }\n    );\n  }, [collapsedItems, collapsedData]);\n\n  // Track expanded nodes, keep it in sync with props and enable keyboard shortcuts.\n  const [expanded, setExpanded] = useExpanded({\n    // @ts-expect-error (non strict)\n    containerRef,\n    isBrowsing,\n    refId,\n    data: collapsedData,\n    initialExpanded,\n    rootIds,\n    highlightedRef,\n    setHighlightedItemId,\n    selectedStoryId,\n    onSelectStoryId,\n  });\n\n  const groupStatus = useMemo(\n    () => getGroupStatus(collapsedData, allStatuses ?? {}),\n    [collapsedData, allStatuses]\n  );\n\n  const treeItems = useMemo(() => {\n    return collapsedItems.map((itemId) => {\n      const item = collapsedData[itemId];\n      const id = createId(itemId, refId);\n\n      if (item.type === 'root') {\n        const descendants = expandableDescendants[item.id];\n        const isFullyExpanded = descendants.every((d: string) => expanded[d]);\n        return (\n          // @ts-expect-error (TODO)\n          <Root\n            api={api}\n            key={id}\n            item={item}\n            refId={refId}\n            collapsedData={collapsedData}\n            isOrphan={false}\n            isDisplayed\n            isSelected={selectedStoryId === itemId}\n            isExpanded={!!expanded[itemId]}\n            setExpanded={setExpanded}\n            isFullyExpanded={isFullyExpanded}\n            expandableDescendants={descendants}\n            onSelectStoryId={onSelectStoryId}\n          />\n        );\n      }\n\n      const isDisplayed = !item.parent || ancestry[itemId].every((a: string) => expanded[a]);\n\n      if (isDisplayed === false) {\n        return null;\n      }\n\n      return (\n        <Node\n          api={api}\n          collapsedData={collapsedData}\n          key={id}\n          item={item}\n          statuses={allStatuses?.[itemId] ?? {}}\n          groupStatus={groupStatus}\n          refId={refId}\n          docsMode={docsMode}\n          isOrphan={orphanIds.some((oid) => itemId === oid || itemId.startsWith(`${oid}-`))}\n          isDisplayed={isDisplayed}\n          isSelected={selectedStoryId === itemId}\n          isExpanded={!!expanded[itemId]}\n          setExpanded={setExpanded}\n          onSelectStoryId={onSelectStoryId}\n        />\n      );\n    });\n  }, [\n    ancestry,\n    api,\n    collapsedData,\n    collapsedItems,\n    docsMode,\n    expandableDescendants,\n    expanded,\n    groupStatus,\n    onSelectStoryId,\n    orphanIds,\n    refId,\n    selectedStoryId,\n    setExpanded,\n    allStatuses,\n  ]);\n  return (\n    <StatusContext.Provider value={{ data, allStatuses, groupStatus }}>\n      <div ref={containerRef}>{treeItems}</div>\n    </StatusContext.Provider>\n  );\n});\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/TreeNode.stories.tsx",
    "content": "import React from 'react';\n\nimport { HighlightStyles } from './HighlightStyles.tsx';\nimport { IconSymbols } from './IconSymbols.tsx';\nimport { LeafNodeStyleWrapper } from './Tree.tsx';\nimport {\n  ComponentNode,\n  DocumentNode,\n  GroupNode,\n  StoryBranchNode,\n  StoryLeafNode,\n  TestNode,\n} from './TreeNode.tsx';\n\nexport default {\n  title: 'Sidebar/TreeNode',\n  parameters: { layout: 'padded' },\n  globals: { sb_theme: 'side-by-side' },\n  component: StoryLeafNode,\n  decorators: [\n    (StoryFn: any) => (\n      <>\n        <IconSymbols />\n        <StoryFn />\n      </>\n    ),\n  ],\n};\n\nexport const Types = () => (\n  <>\n    <ComponentNode>Component</ComponentNode>\n    <GroupNode>Group</GroupNode>\n    <StoryBranchNode>Story (with tests)</StoryBranchNode>\n    <StoryLeafNode>Story (leaf node)</StoryLeafNode>\n    <TestNode>Test</TestNode>\n    <DocumentNode docsMode={false}>Document</DocumentNode>\n  </>\n);\n\nexport const Expandable = () => (\n  <>\n    <ComponentNode isExpandable>Collapsed component</ComponentNode>\n    <ComponentNode isExpandable isExpanded>\n      Expanded component\n    </ComponentNode>\n    <GroupNode isExpandable>Collapsed group</GroupNode>\n    <GroupNode isExpandable isExpanded>\n      Expanded group\n    </GroupNode>\n  </>\n);\n\nexport const ExpandableLongName = () => (\n  <>\n    <ComponentNode isExpandable>\n      Collapsed component with a very very very very very very very very very very very very very\n      very very very very very very veryvery very very very very very very very very veryvery very\n      very very very very very very very veryvery very very very very very very very very veryvery\n      very very very very very very very very veryvery very very very very very very very very\n      veryvery very very very very very very very very veryvery very very very very very very very\n      very very long name\n    </ComponentNode>\n    <ComponentNode isExpandable isExpanded>\n      Expanded component with a very very very very very very very very very very very very very\n      very very very very very very veryvery very very very very very very very very veryvery very\n      very very very very very very very veryvery very very very very very very very very veryvery\n      very very very very very very very very veryvery very very very very very very very very\n      veryvery very very very very very very very very veryvery very very very very very very very\n      very very long name\n    </ComponentNode>\n    <GroupNode isExpandable>\n      Collapsed group with a very very very very very very very very very very very very very very\n      very very very very very veryvery very very very very very very very very veryvery very very\n      very very very very very very veryvery very very very very very very very very veryvery very\n      very very very very very very very veryvery very very very very very very very very veryvery\n      very very very very very very very very veryvery very very very very very very very very very\n      long name\n    </GroupNode>\n    <GroupNode isExpandable isExpanded>\n      Expanded group with a very very very very very very very very very very very very very very\n      very very very very very veryvery very very very very very very very very veryvery very very\n      very very very very very very veryvery very very very very very very very very veryvery very\n      very very very very very very very veryvery very very very very very very very very veryvery\n      very very very very very very very very veryvery very very very very very very very very very\n      long name\n    </GroupNode>\n  </>\n);\n\nexport const Nested = () => (\n  <>\n    <DocumentNode docsMode={false} depth={0}>\n      Zero\n    </DocumentNode>\n    <GroupNode isExpandable isExpanded depth={0}>\n      Zero\n    </GroupNode>\n    <GroupNode isExpandable isExpanded depth={1}>\n      One\n    </GroupNode>\n    <StoryBranchNode depth={2}>Two</StoryBranchNode>\n    <TestNode depth={3}>Three</TestNode>\n    <ComponentNode isExpandable isExpanded depth={2}>\n      Two\n    </ComponentNode>\n    <StoryBranchNode depth={3}>Three</StoryBranchNode>\n    <TestNode depth={4}>Four</TestNode>\n  </>\n);\n\nexport const NestedLongName = () => (\n  <>\n    <DocumentNode docsMode={false} depth={0}>\n      A very very very very very very very very very very very very very very very very very very\n      very veryvery very very very very very very very very veryvery very very very very very very\n      very very veryvery very very very very very very very very veryvery very very very very very\n      very very very veryvery very very very very very very very very veryvery very very very very\n      very very very very veryvery very very very very very very very very very long name\n    </DocumentNode>\n    <GroupNode isExpandable isExpanded depth={0}>\n      A very very very very very very very very very very very very very very very very very very\n      very veryvery very very very very very very very very veryvery very very very very very very\n      very very veryvery very very very very very very very very veryvery very very very very very\n      very very very veryvery very very very very very very very very veryvery very very very very\n      very very very very veryvery very very very very very very very very very long name\n    </GroupNode>\n    <GroupNode isExpandable isExpanded depth={1}>\n      A very very very very very very very very very very very very very very very very very very\n      very veryvery very very very very very very very very veryvery very very very very very very\n      very very veryvery very very very very very very very very veryvery very very very very very\n      very very very veryvery very very very very very very very very veryvery very very very very\n      very very very very veryvery very very very very very very very very very long name\n    </GroupNode>\n    <StoryBranchNode depth={2}>\n      A very very very very very very very very very very very very very very very very very very\n      very veryvery very very very very very very very very veryvery very very very very very very\n      very very veryvery very very very very very very very very veryvery very very very very very\n      very very very veryvery very very very very very very very very veryvery very very very very\n      very very very very veryvery very very very very very very very very very long name\n    </StoryBranchNode>\n    <TestNode depth={3}>\n      A very very very very very very very very very very very very very very very very very very\n      very veryvery very very very very very very very very veryvery very very very very very very\n      very very veryvery very very very very very very very very veryvery very very very very very\n      very very very veryvery very very very very very very very very veryvery very very very very\n      very very very very veryvery very very very very very very very very very long name\n    </TestNode>\n    <ComponentNode isExpandable isExpanded depth={2}>\n      A very very very very very very very very very very very very very very very very very very\n      very veryvery very very very very very very very very veryvery very very very very very very\n      very very veryvery very very very very very very very very veryvery very very very very very\n      very very very veryvery very very very very very very very very veryvery very very very very\n      very very very very veryvery very very very very very very very very very long name\n    </ComponentNode>\n    <StoryBranchNode depth={3}>\n      A very very very very very very very very very very very very very very very very very very\n      very veryvery very very very very very very very very veryvery very very very very very very\n      very very veryvery very very very very very very very very veryvery very very very very very\n      very very very veryvery very very very very very very very very veryvery very very very very\n      very very very very veryvery very very very very very very very very very long name\n    </StoryBranchNode>\n    <TestNode depth={4}>\n      A very very very very very very very very very very very very very very very very very very\n      very veryvery very very very very very very very very veryvery very very very very very very\n      very very veryvery very very very very very very very very veryvery very very very very very\n      very very very veryvery very very very very very very very very veryvery very very very very\n      very very very very veryvery very very very very very very very very very long name\n    </TestNode>\n  </>\n);\n\nexport const Selection = () => (\n  <>\n    <HighlightStyles refId=\"foo\" itemId=\"bar\" />\n    <LeafNodeStyleWrapper\n      data-ref-id=\"baz\"\n      data-item-id=\"bar\"\n      data-nodetype=\"story\"\n      data-selected=\"false\"\n      className=\"sidebar-item\"\n    >\n      <StoryLeafNode>Default story</StoryLeafNode>\n    </LeafNodeStyleWrapper>\n    <LeafNodeStyleWrapper\n      data-ref-id=\"baz\"\n      data-item-id=\"bar\"\n      data-nodetype=\"story\"\n      data-selected=\"true\"\n      className=\"sidebar-item\"\n    >\n      <StoryLeafNode>Selected story</StoryLeafNode>\n    </LeafNodeStyleWrapper>\n    <LeafNodeStyleWrapper\n      data-ref-id=\"foo\"\n      data-item-id=\"bar\"\n      data-nodetype=\"story\"\n      data-selected=\"false\"\n      className=\"sidebar-item\"\n    >\n      <StoryLeafNode>Highlighted story</StoryLeafNode>\n    </LeafNodeStyleWrapper>\n    <LeafNodeStyleWrapper\n      data-ref-id=\"foo\"\n      data-item-id=\"bar\"\n      data-nodetype=\"story\"\n      data-selected=\"true\"\n      className=\"sidebar-item\"\n    >\n      <StoryLeafNode>Highlighted + Selected story</StoryLeafNode>\n    </LeafNodeStyleWrapper>\n    <LeafNodeStyleWrapper\n      data-ref-id=\"baz\"\n      data-item-id=\"bar\"\n      data-nodetype=\"test\"\n      data-selected=\"false\"\n      className=\"sidebar-item\"\n    >\n      <TestNode>Default test</TestNode>\n    </LeafNodeStyleWrapper>\n    <LeafNodeStyleWrapper\n      data-ref-id=\"baz\"\n      data-item-id=\"bar\"\n      data-nodetype=\"test\"\n      data-selected=\"true\"\n      className=\"sidebar-item\"\n    >\n      <TestNode>Selected test</TestNode>\n    </LeafNodeStyleWrapper>\n    <LeafNodeStyleWrapper\n      data-ref-id=\"foo\"\n      data-item-id=\"baz\"\n      data-nodetype=\"group\"\n      data-selected=\"false\"\n      className=\"sidebar-item\"\n    >\n      <GroupNode>Default group</GroupNode>\n    </LeafNodeStyleWrapper>\n    <LeafNodeStyleWrapper\n      data-ref-id=\"foo\"\n      data-item-id=\"bar\"\n      data-nodetype=\"group\"\n      data-selected=\"false\"\n      className=\"sidebar-item\"\n    >\n      <GroupNode>Highlighted group</GroupNode>\n    </LeafNodeStyleWrapper>\n  </>\n);\n\nexport const SelectionWithLongName = () => (\n  <>\n    <HighlightStyles refId=\"foo\" itemId=\"bar\" />\n    <LeafNodeStyleWrapper\n      data-ref-id=\"baz\"\n      data-item-id=\"bar\"\n      data-nodetype=\"story\"\n      data-selected=\"false\"\n      className=\"sidebar-item\"\n    >\n      <StoryLeafNode>\n        Default story with a very very very very very very very very very very very very very very\n        very very very very very veryvery very very very very very very very very veryvery very very\n        very very very very very very veryvery very very very very very very very very veryvery very\n        very very very very very very very veryvery very very very very very very very very veryvery\n        very very very very very very very very veryvery very very very very very very very very\n        very long name\n      </StoryLeafNode>\n    </LeafNodeStyleWrapper>\n    <LeafNodeStyleWrapper\n      data-ref-id=\"baz\"\n      data-item-id=\"bar\"\n      data-nodetype=\"story\"\n      data-selected=\"true\"\n      className=\"sidebar-item\"\n    >\n      <StoryLeafNode>\n        Selected story with a very very very very very very very very very very very very very very\n        very very very very very veryvery very very very very very very very very veryvery very very\n        very very very very very very veryvery very very very very very very very very veryvery very\n        very very very very very very very veryvery very very very very very very very very veryvery\n        very very very very very very very very veryvery very very very very very very very very\n        very long name\n      </StoryLeafNode>\n    </LeafNodeStyleWrapper>\n    <LeafNodeStyleWrapper\n      data-ref-id=\"foo\"\n      data-item-id=\"bar\"\n      data-nodetype=\"story\"\n      data-selected=\"false\"\n      className=\"sidebar-item\"\n    >\n      <StoryLeafNode>\n        Highlighted story with a very very very very very very very very very very very very very\n        very very very very very very veryvery very very very very very very very very veryvery very\n        very very very very very very very veryvery very very very very very very very very veryvery\n        very very very very very very very very veryvery very very very very very very very very\n        veryvery very very very very very very very very veryvery very very very very very very very\n        very very long name\n      </StoryLeafNode>\n    </LeafNodeStyleWrapper>\n    <LeafNodeStyleWrapper\n      data-ref-id=\"foo\"\n      data-item-id=\"bar\"\n      data-nodetype=\"story\"\n      data-selected=\"true\"\n      className=\"sidebar-item\"\n    >\n      <StoryLeafNode>\n        Highlighted + Selected story with a very very very very very very very very very very very\n        very very very very very very very very veryvery very very very very very very very very\n        veryvery very very very very very very very very veryvery very very very very very very very\n        very veryvery very very very very very very very very veryvery very very very very very very\n        very very veryvery very very very very very very very very veryvery very very very very very\n        very very very very long name\n      </StoryLeafNode>\n    </LeafNodeStyleWrapper>\n    <LeafNodeStyleWrapper\n      data-ref-id=\"foo\"\n      data-item-id=\"baz\"\n      data-nodetype=\"group\"\n      data-selected=\"false\"\n      className=\"sidebar-item\"\n    >\n      <GroupNode>\n        Default group with a very very very very very very very very very very very very very very\n        very very very very very veryvery very very very very very very very very veryvery very very\n        very very very very very very veryvery very very very very very very very very veryvery very\n        very very very very very very very veryvery very very very very very very very very veryvery\n        very very very very very very very very veryvery very very very very very very very very\n        very long name\n      </GroupNode>\n    </LeafNodeStyleWrapper>\n    <LeafNodeStyleWrapper\n      data-ref-id=\"foo\"\n      data-item-id=\"bar\"\n      data-nodetype=\"group\"\n      data-selected=\"false\"\n      className=\"sidebar-item\"\n    >\n      <GroupNode>\n        Highlighted group with a very very very very very very very very very very very very very\n        very very very very very very veryvery very very very very very very very very veryvery very\n        very very very very very very very veryvery very very very very very very very very veryvery\n        very very very very very very very very veryvery very very very very very very very very\n        veryvery very very very very very very very very veryvery very very very very very very very\n        very very long name\n      </GroupNode>\n    </LeafNodeStyleWrapper>\n  </>\n);\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/TreeNode.tsx",
    "content": "import type { ComponentProps, FC } from 'react';\nimport React from 'react';\n\nimport { type FunctionInterpolation, styled } from 'storybook/theming';\n\nimport { UseSymbol } from './IconSymbols.tsx';\nimport { CollapseIcon } from './components/CollapseIcon.tsx';\n\nexport const TypeIcon = styled.svg<{ type: 'component' | 'story' | 'test' | 'group' | 'document' }>(\n  ({ theme, type }) => ({\n    width: 14,\n    height: 14,\n    flex: '0 0 auto',\n    color: (() => {\n      if (type === 'group') {\n        return theme.base === 'dark' ? theme.color.primary : theme.color.ultraviolet;\n      }\n\n      if (type === 'component') {\n        return theme.color.secondary;\n      }\n\n      if (type === 'document') {\n        return theme.base === 'dark' ? theme.color.gold : '#ff8300';\n      }\n\n      if (type === 'story') {\n        return theme.color.seafoam;\n      }\n\n      if (type === 'test') {\n        return theme.color.green;\n      }\n\n      return 'currentColor';\n    })(),\n  })\n);\n\nconst commonNodeStyles: FunctionInterpolation<{ depth?: number; isExpandable?: boolean }> = ({\n  theme,\n  depth = 0,\n  isExpandable = false,\n}) => ({\n  flex: 1,\n  width: '100%',\n  cursor: 'pointer',\n  display: 'flex',\n  alignItems: 'start',\n  textAlign: 'left',\n  textDecoration: 'none',\n  border: 'none',\n  color: 'inherit',\n  fontSize: `${theme.typography.size.s2}px`,\n  fontWeight: 'inherit',\n  background: 'transparent',\n  minHeight: 28,\n  borderRadius: 4,\n  gap: 6,\n  paddingLeft: `${(isExpandable ? 8 : 22) + depth * 18}px`,\n  paddingTop: 5,\n  paddingBottom: 4,\n  paddingRight: 6,\n  overflowWrap: 'break-word',\n  wordWrap: 'break-word',\n  wordBreak: 'break-word',\n});\n\nconst BranchNode = styled.button<{\n  depth?: number;\n  isExpandable?: boolean;\n  isExpanded?: boolean;\n  isSelected?: boolean;\n}>(commonNodeStyles);\n\nconst LeafNode = styled.a<{ depth?: number }>(commonNodeStyles);\n\nexport const RootNode = styled.div({\n  display: 'flex',\n  alignItems: 'center',\n  justifyContent: 'space-between',\n  marginTop: 16,\n  marginBottom: 4,\n\n  '&:first-of-type': {\n    marginTop: 0,\n  },\n});\n\nconst Wrapper = styled.div({\n  display: 'flex',\n  alignItems: 'center',\n  gap: 6,\n  marginTop: 2,\n});\n\nexport const GroupNode: FC<\n  ComponentProps<typeof BranchNode> & { isExpanded?: boolean; isExpandable?: boolean }\n> = React.memo(function GroupNode({\n  children,\n  isExpanded = false,\n  isExpandable = false,\n  ...props\n}) {\n  return (\n    <BranchNode isExpandable={isExpandable} tabIndex={-1} {...props}>\n      <Wrapper>\n        {isExpandable && <CollapseIcon isExpanded={isExpanded} />}\n        <TypeIcon viewBox=\"0 0 14 14\" width=\"14\" height=\"14\" type=\"group\">\n          <UseSymbol type=\"group\" />\n        </TypeIcon>\n      </Wrapper>\n      {children}\n    </BranchNode>\n  );\n});\n\nexport const ComponentNode: FC<ComponentProps<typeof BranchNode>> = React.memo(\n  function ComponentNode({\n    theme,\n    children,\n    isExpanded = false,\n    isExpandable = false,\n    isSelected,\n    ...props\n  }) {\n    return (\n      <BranchNode isExpandable={isExpandable} tabIndex={-1} {...props}>\n        <Wrapper>\n          {isExpandable && <CollapseIcon isExpanded={isExpanded} />}\n          <TypeIcon viewBox=\"0 0 14 14\" width=\"12\" height=\"12\" type=\"component\">\n            <UseSymbol type=\"component\" />\n          </TypeIcon>\n        </Wrapper>\n        {children}\n      </BranchNode>\n    );\n  }\n);\n\nexport const DocumentNode: FC<ComponentProps<typeof LeafNode> & { docsMode?: boolean }> =\n  React.memo(function DocumentNode({ theme, children, docsMode, ...props }) {\n    return (\n      <LeafNode tabIndex={-1} rel=\"canonical\" {...props}>\n        <Wrapper>\n          <TypeIcon viewBox=\"0 0 14 14\" width=\"12\" height=\"12\" type=\"document\">\n            <UseSymbol type=\"document\" />\n          </TypeIcon>\n        </Wrapper>\n        {children}\n      </LeafNode>\n    );\n  });\n\nexport const StoryBranchNode: FC<ComponentProps<typeof BranchNode>> = React.memo(\n  function StoryNode({\n    theme,\n    children,\n    isExpandable = false,\n    isExpanded = false,\n    isSelected,\n    ...props\n  }) {\n    return (\n      <BranchNode isExpandable={isExpandable} tabIndex={-1} {...props}>\n        <Wrapper>\n          {isExpandable && <CollapseIcon isExpanded={isExpanded} />}\n          <TypeIcon viewBox=\"0 0 14 14\" width=\"12\" height=\"12\" type=\"story\">\n            <UseSymbol type=\"story\" />\n          </TypeIcon>\n        </Wrapper>\n        {children}\n      </BranchNode>\n    );\n  }\n);\n\nexport const StoryLeafNode: FC<ComponentProps<typeof LeafNode>> = React.memo(function StoryNode({\n  theme,\n  children,\n  ...props\n}) {\n  return (\n    <LeafNode tabIndex={-1} rel=\"canonical\" {...props}>\n      <Wrapper>\n        <TypeIcon viewBox=\"0 0 14 14\" width=\"12\" height=\"12\" type=\"story\">\n          <UseSymbol type=\"story\" />\n        </TypeIcon>\n      </Wrapper>\n      {children}\n    </LeafNode>\n  );\n});\n\nexport const TestNode: FC<ComponentProps<typeof LeafNode>> = React.memo(function TestNode({\n  theme,\n  children,\n  ...props\n}) {\n  return (\n    <LeafNode tabIndex={-1} rel=\"canonical\" {...props}>\n      <Wrapper>\n        <TypeIcon viewBox=\"0 0 14 14\" width=\"12\" height=\"12\" type=\"test\">\n          <UseSymbol type=\"test\" />\n        </TypeIcon>\n      </Wrapper>\n      {children}\n    </LeafNode>\n  );\n});\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/__tests__/Sidebar.test.tsx",
    "content": "// @vitest-environment happy-dom\nimport { cleanup, fireEvent, render, screen } from '@testing-library/react';\nimport type { RenderResult } from '@testing-library/react';\nimport { afterEach, describe, expect, test } from 'vitest';\n\nimport React from 'react';\n\nimport type { API_IndexHash } from 'storybook/internal/types';\n\nimport type { HashEntry, Refs } from 'storybook/manager-api';\nimport type { Theme } from 'storybook/theming';\nimport { ThemeProvider, ensure, themes } from 'storybook/theming';\n\nimport { Sidebar } from '../Sidebar.tsx';\nimport type { SidebarProps } from '../Sidebar.tsx';\n\nconst DOCS_NAME = 'Docs';\n\nconst factory = (props: Partial<SidebarProps>): RenderResult => {\n  const theme: Theme = ensure(themes.light);\n\n  return render(\n    <ThemeProvider theme={theme}>\n      <Sidebar menu={[]} index={{}} previewInitialized refs={{}} allStatuses={{}} {...props} />\n    </ThemeProvider>\n  );\n};\n\nconst generateStories = ({ title, refId }: { title: string; refId?: string }): API_IndexHash => {\n  const [root, componentName]: [string, string] = title.split('/') as any;\n  const rootId: string = root.toLowerCase().replace(/\\s+/g, '-');\n  const hypenatedComponentName: string = componentName.toLowerCase().replace(/\\s+/g, '-');\n  const componentId = `${rootId}-${hypenatedComponentName}`;\n  const docsId = `${rootId}-${hypenatedComponentName}--docs`;\n\n  const storyBase: HashEntry[] = [\n    {\n      type: 'root',\n      id: rootId,\n      depth: 0,\n      refId,\n      name: root,\n      children: [componentId],\n      startCollapsed: false,\n      tags: [],\n    },\n    {\n      type: 'component',\n      id: componentId,\n      depth: 1,\n      refId,\n      name: componentName,\n      children: [docsId],\n      parent: rootId,\n      tags: [],\n    },\n    // @ts-expect-error the missing fields are deprecated and replaced by the type prop\n    {\n      type: 'docs',\n      id: docsId,\n      depth: 2,\n      refId,\n      name: DOCS_NAME,\n      title,\n      parent: componentId,\n      importPath: './docs.js',\n    },\n  ];\n\n  return storyBase.reduce((accumulator: API_IndexHash, current: HashEntry): API_IndexHash => {\n    accumulator[current.id] = current;\n    return accumulator;\n  }, {});\n};\n\ndescribe('Sidebar', () => {\n  afterEach(() => {\n    cleanup();\n  });\n\n  // TODO: Bring this test back whenever possible.\n  // Seems to be failing because of two reasons:\n  // - There is a warning \"ReactDOM.render is no longer supported in React 18. Use createRoot instead.\"\n  // - There is a TypeError: Cannot read properties of undefined (reading 'size') - coming from ThemeProvider\n  test.skip(\"should not render an extra nested 'Page'\", async () => {\n    const refId = 'next';\n    const title = 'Getting Started/Install';\n    const refIndex: API_IndexHash = generateStories({ refId, title });\n    const internalIndex: API_IndexHash = generateStories({ title: 'Welcome/Example' });\n\n    const refs: Refs = {\n      [refId]: {\n        index: refIndex,\n        id: refId,\n        previewInitialized: true,\n        title: refId,\n        url: 'https://ref.url',\n      },\n    };\n\n    factory({\n      refs,\n      refId,\n      index: internalIndex,\n    });\n\n    fireEvent.click(screen.getByText('Install'));\n    fireEvent.click(screen.getByText('Example'));\n\n    const pageItems: HTMLElement[] = await screen.queryAllByText('Page');\n\n    expect(pageItems).toHaveLength(0);\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/components/CollapseIcon.tsx",
    "content": "import type { ComponentProps, FC } from 'react';\nimport React from 'react';\n\nimport { styled } from 'storybook/theming';\n\nexport const CollapseIconWrapper = styled.div<{ isExpanded: boolean }>(({ theme, isExpanded }) => ({\n  width: 8,\n  height: 8,\n  display: 'flex',\n  justifyContent: 'center',\n  alignItems: 'center',\n  transform: isExpanded ? 'rotateZ(90deg)' : 'none',\n  transition: 'transform .1s ease-out',\n  color: theme.textMutedColor,\n}));\n\nexport const CollapseIcon: FC<ComponentProps<typeof CollapseIconWrapper>> = (props) => (\n  <CollapseIconWrapper {...props}>\n    <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"8\" height=\"8\" fill=\"none\">\n      <path\n        fill=\"currentColor\"\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n        d=\"M1.896 7.146a.5.5 0 1 0 .708.708l3.5-3.5a.5.5 0 0 0 0-.708l-3.5-3.5a.5.5 0 1 0-.708.708L5.043 4 1.896 7.146Z\"\n      />\n    </svg>\n  </CollapseIconWrapper>\n);\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/mockdata.large.ts",
    "content": "/**\n * This data originates from the storiesHash state in Storybook. Grab it from the Manager node using\n * React DevTools by assigning it to a global variable, then use the following script to remove the\n * parameters, otherwise you'll end up with a huge file:\n *\n * JSON.stringify( Object.values($reactTemp1) .reduce((acc, {parameters, ...node}) => { acc[node.id]\n * = node; return acc; }, {}), null, 2)\n */\nimport type { Dataset } from './types.ts';\n\n// @ts-expect-error (TODO)\nexport const index = {\n  images: {\n    name: 'Images',\n    id: 'images',\n    depth: 0,\n    children: [\n      'images--marketing-hero',\n      'images--brand',\n      'images--colored-icons',\n      'images--logos',\n      'images--shapes',\n      'images--thumbnails',\n      'images--payment',\n    ],\n    type: 'component',\n  },\n  'images--marketing-hero': {\n    id: 'images--marketing-hero',\n    title: 'Images',\n    name: 'marketing hero',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 1,\n    parent: 'images',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'images--brand': {\n    id: 'images--brand',\n    title: 'Images',\n    name: 'brand',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 1,\n    parent: 'images',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'images--colored-icons': {\n    id: 'images--colored-icons',\n    title: 'Images',\n    name: 'colored icons',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 1,\n    parent: 'images',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'images--logos': {\n    id: 'images--logos',\n    title: 'Images',\n    name: 'logos',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 1,\n    parent: 'images',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'images--shapes': {\n    id: 'images--shapes',\n    title: 'Images',\n    name: 'shapes',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 1,\n    parent: 'images',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'images--thumbnails': {\n    id: 'images--thumbnails',\n    title: 'Images',\n    name: 'thumbnails',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 1,\n    parent: 'images',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'images--payment': {\n    id: 'images--payment',\n    title: 'Images',\n    name: 'payment',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 1,\n    parent: 'images',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  emails: {\n    name: 'Emails',\n    id: 'emails',\n    depth: 0,\n    children: [\n      'emails-introduction',\n      'emails-buildnotification',\n      'emails-commentnotification',\n      'emails-paymentnotification',\n      'emails-reviewnotification',\n      'emails-snapshotnotification',\n    ],\n    type: 'root',\n  },\n  'emails-introduction': {\n    id: 'emails-introduction',\n    title: 'Emails',\n    name: 'Introduction',\n    importPath: './path.js',\n    parent: 'emails',\n    depth: 1,\n    type: 'docs',\n  },\n  'emails-buildnotification': {\n    name: 'BuildNotification',\n    id: 'emails-buildnotification',\n    parent: 'emails',\n    depth: 1,\n    children: [\n      'emails-buildnotification--with-changes',\n      'emails-buildnotification--without-email',\n      'emails-buildnotification--with-error',\n    ],\n    type: 'component',\n  },\n  'emails-buildnotification--with-changes': {\n    id: 'emails-buildnotification--with-changes',\n    title: 'Emails/BuildNotification',\n    name: 'with changes',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-buildnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-buildnotification--without-email': {\n    id: 'emails-buildnotification--without-email',\n    title: 'Emails/BuildNotification',\n    name: 'without email',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-buildnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-buildnotification--with-error': {\n    id: 'emails-buildnotification--with-error',\n    title: 'Emails/BuildNotification',\n    name: 'with error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-buildnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-commentnotification': {\n    name: 'CommentNotification',\n    id: 'emails-commentnotification',\n    parent: 'emails',\n    depth: 1,\n    children: [\n      'emails-commentnotification--new-discussion',\n      'emails-commentnotification--new-discussion-no-diff',\n      'emails-commentnotification--new-discussion-no-snapshot',\n      'emails-commentnotification--new-discussion-no-pr',\n      'emails-commentnotification--new-reply',\n      'emails-commentnotification--resolution',\n    ],\n    type: 'component',\n  },\n  'emails-commentnotification--new-discussion': {\n    id: 'emails-commentnotification--new-discussion',\n    title: 'Emails/CommentNotification',\n    name: 'new discussion',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-commentnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-commentnotification--new-discussion-no-diff': {\n    id: 'emails-commentnotification--new-discussion-no-diff',\n    title: 'Emails/CommentNotification',\n    name: 'new discussion, no diff',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-commentnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-commentnotification--new-discussion-no-snapshot': {\n    id: 'emails-commentnotification--new-discussion-no-snapshot',\n    title: 'Emails/CommentNotification',\n    name: 'new discussion, no snapshot',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-commentnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-commentnotification--new-discussion-no-pr': {\n    id: 'emails-commentnotification--new-discussion-no-pr',\n    title: 'Emails/CommentNotification',\n    name: 'new discussion, no PR',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-commentnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-commentnotification--new-reply': {\n    id: 'emails-commentnotification--new-reply',\n    title: 'Emails/CommentNotification',\n    name: 'new reply',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-commentnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-commentnotification--resolution': {\n    id: 'emails-commentnotification--resolution',\n    title: 'Emails/CommentNotification',\n    name: 'resolution',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-commentnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-paymentnotification': {\n    name: 'PaymentNotification',\n    id: 'emails-paymentnotification',\n    parent: 'emails',\n    depth: 1,\n    children: [\n      'emails-paymentnotification--trial-ending',\n      'emails-paymentnotification--trial-ended',\n      'emails-paymentnotification--payment-failed',\n      'emails-paymentnotification--payment-due',\n    ],\n    type: 'component',\n  },\n  'emails-paymentnotification--trial-ending': {\n    id: 'emails-paymentnotification--trial-ending',\n    title: 'Emails/PaymentNotification',\n    name: 'trial ending',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-paymentnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-paymentnotification--trial-ended': {\n    id: 'emails-paymentnotification--trial-ended',\n    title: 'Emails/PaymentNotification',\n    name: 'trial ended',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-paymentnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-paymentnotification--payment-failed': {\n    id: 'emails-paymentnotification--payment-failed',\n    title: 'Emails/PaymentNotification',\n    name: 'payment failed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-paymentnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-paymentnotification--payment-due': {\n    id: 'emails-paymentnotification--payment-due',\n    title: 'Emails/PaymentNotification',\n    name: 'payment due',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-paymentnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-reviewnotification': {\n    name: 'ReviewNotification',\n    id: 'emails-reviewnotification',\n    parent: 'emails',\n    depth: 1,\n    children: [\n      'emails-reviewnotification--approval',\n      'emails-reviewnotification--approval-with-pending-reviews',\n      'emails-reviewnotification--approval-with-pending-review',\n      'emails-reviewnotification--approval-git-lab',\n      'emails-reviewnotification--requesting-review',\n      'emails-reviewnotification--requesting-review-small-diff-count',\n      'emails-reviewnotification--requesting-review-with-errors',\n      'emails-reviewnotification--requesting-review-only-errors',\n    ],\n    type: 'component',\n  },\n  'emails-reviewnotification--approval': {\n    id: 'emails-reviewnotification--approval',\n    title: 'Emails/ReviewNotification',\n    name: 'Approval',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-reviewnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-reviewnotification--approval-with-pending-reviews': {\n    id: 'emails-reviewnotification--approval-with-pending-reviews',\n    title: 'Emails/ReviewNotification',\n    name: 'Approval, With Pending Reviews',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-reviewnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-reviewnotification--approval-with-pending-review': {\n    id: 'emails-reviewnotification--approval-with-pending-review',\n    title: 'Emails/ReviewNotification',\n    name: 'Approval, With Single Pending Review',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-reviewnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-reviewnotification--approval-git-lab': {\n    id: 'emails-reviewnotification--approval-git-lab',\n    title: 'Emails/ReviewNotification',\n    name: 'Approval, GitLab',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-reviewnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-reviewnotification--requesting-review': {\n    id: 'emails-reviewnotification--requesting-review',\n    title: 'Emails/ReviewNotification',\n    name: 'Requesting Review',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-reviewnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-reviewnotification--requesting-review-small-diff-count': {\n    id: 'emails-reviewnotification--requesting-review-small-diff-count',\n    title: 'Emails/ReviewNotification',\n    name: 'Requesting Review, Small Diff Count',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-reviewnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-reviewnotification--requesting-review-with-errors': {\n    id: 'emails-reviewnotification--requesting-review-with-errors',\n    title: 'Emails/ReviewNotification',\n    name: 'Requesting Review, With Errored Diffs',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-reviewnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-reviewnotification--requesting-review-only-errors': {\n    id: 'emails-reviewnotification--requesting-review-only-errors',\n    title: 'Emails/ReviewNotification',\n    name: 'Requesting Review, Only Errored Diffs',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-reviewnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-snapshotnotification': {\n    name: 'SnapshotNotification',\n    id: 'emails-snapshotnotification',\n    parent: 'emails',\n    depth: 1,\n    children: [\n      'emails-snapshotnotification--ninety-percent',\n      'emails-snapshotnotification--limit-reached',\n    ],\n    type: 'component',\n  },\n  'emails-snapshotnotification--ninety-percent': {\n    id: 'emails-snapshotnotification--ninety-percent',\n    title: 'Emails/SnapshotNotification',\n    name: 'Ninety Percent',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-snapshotnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'emails-snapshotnotification--limit-reached': {\n    id: 'emails-snapshotnotification--limit-reached',\n    title: 'Emails/SnapshotNotification',\n    name: 'Limit Reached',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'emails-snapshotnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  tooltip: {\n    name: 'tooltip',\n    id: 'tooltip',\n    depth: 0,\n    children: ['tooltip-tooltipbuildlist', 'tooltip-tooltipselect'],\n    type: 'root',\n  },\n  'tooltip-tooltipbuildlist': {\n    name: 'TooltipBuildList',\n    id: 'tooltip-tooltipbuildlist',\n    parent: 'tooltip',\n    depth: 1,\n    children: ['tooltip-tooltipbuildlist--default', 'tooltip-tooltipbuildlist--no-commit'],\n    type: 'component',\n  },\n  'tooltip-tooltipbuildlist--default': {\n    id: 'tooltip-tooltipbuildlist--default',\n    title: 'tooltip/TooltipBuildList',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'tooltip-tooltipbuildlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'tooltip-tooltipbuildlist--no-commit': {\n    id: 'tooltip-tooltipbuildlist--no-commit',\n    title: 'tooltip/TooltipBuildList',\n    name: 'no commit',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'tooltip-tooltipbuildlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'tooltip-tooltipselect': {\n    name: 'TooltipSelect',\n    id: 'tooltip-tooltipselect',\n    parent: 'tooltip',\n    depth: 1,\n    children: ['tooltip-tooltipselect--default'],\n    type: 'component',\n  },\n  'tooltip-tooltipselect--default': {\n    id: 'tooltip-tooltipselect--default',\n    title: 'tooltip/TooltipSelect',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'tooltip-tooltipselect',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components': {\n    name: 'Webapp components',\n    id: 'webapp-components',\n    depth: 0,\n    children: [\n      'webapp-components-accountmenu',\n      'webapp-components-activityitem',\n      'webapp-components-activitylist',\n      'webapp-components-appowneritem',\n      'webapp-components-appownerlist',\n      'webapp-components-aspectratiopreserver',\n      'webapp-components-asynctextaction',\n      'webapp-components-badgecount',\n      'webapp-components-banner',\n      'webapp-components-baselinehistory',\n      'webapp-components-billingplans',\n      'webapp-components-branchpicker',\n      'webapp-components-breadcrumb',\n      'webapp-components-buildcomponentlist',\n      'webapp-components-builditem',\n      'webapp-components-buildlist',\n      'webapp-components-buildstatuslight',\n      'webapp-components-button',\n      'webapp-components-buttonmulti',\n      'webapp-components-buttontoggle',\n      'webapp-components-canvas',\n      'webapp-components-cardinal',\n      'webapp-components-checkbox',\n      'webapp-components-cieyebrow',\n      'webapp-components-clipboard',\n      'webapp-components-clipboardcode',\n      'webapp-components-clipboardicon',\n      'webapp-components-clipboardinput',\n      'webapp-components-comment',\n      'webapp-components-componentbranchlist',\n      'webapp-components-componentbuildlist',\n      'webapp-components-componentbuildspicker',\n      'webapp-components-componentitem',\n      'webapp-components-componentlist',\n      'webapp-components-componentrepresentationimage',\n      'webapp-components-creditcardform',\n      'webapp-components-dateformatter',\n      'webapp-components-diffimage',\n      'webapp-components-difftoggles',\n      'webapp-components-emptymessage',\n      'webapp-components-eyebrow',\n      'webapp-components-eyebrowonboarding',\n      'webapp-components-flexcenter',\n      'webapp-components-form',\n      'webapp-components-header',\n      'webapp-components-heading',\n      'webapp-components-ignoredregions',\n      'webapp-components-imagetile',\n      'webapp-components-interstitial',\n      'webapp-components-inviteeyebrow',\n      'webapp-components-isactiveelement',\n      'webapp-components-isolatorframe',\n      'webapp-components-linklist',\n      'webapp-components-linktabs',\n      'webapp-components-listheading',\n      'webapp-components-liveview',\n      'webapp-components-mailinglistsubscribeform',\n      'webapp-components-newappform',\n      'webapp-components-notifications',\n      'webapp-components-pageheader',\n      'webapp-components-pagetitlebar',\n      'webapp-components-pagination',\n      'webapp-components-paymentcollectcta',\n      'webapp-components-paymentcollectmodal',\n      'webapp-components-paymenteyebrow',\n      'webapp-components-progressbar',\n      'webapp-components-projectitem',\n      'webapp-components-projectlist',\n      'webapp-components-pullrequestitem',\n      'webapp-components-pullrequestlist',\n      'webapp-components-pullrequeststatuslight',\n      'webapp-components-questiontooltip',\n      'webapp-components-radar',\n      'webapp-components-radio',\n      'webapp-components-rawspeclist',\n      'webapp-components-repositoryitem',\n      'webapp-components-repositorylist',\n      'webapp-components-repositoryowneritem',\n      'webapp-components-repositoryownerlist',\n      'webapp-components-repositorypicker',\n      'webapp-components-scrollintoview',\n      'webapp-components-section',\n      'webapp-components-sharetooltipmessage',\n      'webapp-components-sidebarnav',\n      'webapp-components-snapshoterror',\n      'webapp-components-snapshoterrormessage',\n      'webapp-components-snapshotsizechanged',\n      'webapp-components-specitem',\n      'webapp-components-speclist',\n      'webapp-components-specname',\n      'webapp-components-startchat',\n      'webapp-components-statuslight',\n      'webapp-components-statustooltip',\n      'webapp-components-subheader',\n      'webapp-components-table',\n      'webapp-components-tabledrawer',\n      'webapp-components-tooltipignore',\n      'webapp-components-useritem',\n      'webapp-components-userlist',\n      'webapp-components-video',\n      'webapp-components-warning',\n      'webapp-components-wobbler',\n    ],\n    type: 'root',\n  },\n  'webapp-components-accountmenu': {\n    name: 'AccountMenu',\n    id: 'webapp-components-accountmenu',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-accountmenu--default',\n      'webapp-components-accountmenu--saml-user',\n    ],\n    type: 'component',\n  },\n  'webapp-components-accountmenu--default': {\n    id: 'webapp-components-accountmenu--default',\n    title: 'Webapp components/AccountMenu',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-accountmenu',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-accountmenu--saml-user': {\n    id: 'webapp-components-accountmenu--saml-user',\n    title: 'Webapp components/AccountMenu',\n    name: 'saml user',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-accountmenu',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-activityitem': {\n    name: 'ActivityItem',\n    id: 'webapp-components-activityitem',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-activityitem--all-activity-item',\n      'webapp-components-activityitem--loading',\n      'webapp-components-activityitem--passed',\n      'webapp-components-activityitem--failed',\n      'webapp-components-activityitem--unreviewed',\n      'webapp-components-activityitem--in-progress',\n      'webapp-components-activityitem--from-agent-passed',\n      'webapp-components-activityitem--timed-out',\n      'webapp-components-activityitem--errored',\n      'webapp-components-activityitem--no-account-name',\n      'webapp-components-activityitem--long-account-name',\n    ],\n    type: 'component',\n  },\n  'webapp-components-activityitem--all-activity-item': {\n    id: 'webapp-components-activityitem--all-activity-item',\n    title: 'Webapp components/ActivityItem',\n    name: 'All ActivityItem',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-activityitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-activityitem--loading': {\n    id: 'webapp-components-activityitem--loading',\n    title: 'Webapp components/ActivityItem',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-activityitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-activityitem--passed': {\n    id: 'webapp-components-activityitem--passed',\n    title: 'Webapp components/ActivityItem',\n    name: 'Passed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-activityitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-activityitem--failed': {\n    id: 'webapp-components-activityitem--failed',\n    title: 'Webapp components/ActivityItem',\n    name: 'Failed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-activityitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-activityitem--unreviewed': {\n    id: 'webapp-components-activityitem--unreviewed',\n    title: 'Webapp components/ActivityItem',\n    name: 'Unreviewed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-activityitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-activityitem--in-progress': {\n    id: 'webapp-components-activityitem--in-progress',\n    title: 'Webapp components/ActivityItem',\n    name: 'In progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-activityitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-activityitem--from-agent-passed': {\n    id: 'webapp-components-activityitem--from-agent-passed',\n    title: 'Webapp components/ActivityItem',\n    name: 'From agent, passed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-activityitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-activityitem--timed-out': {\n    id: 'webapp-components-activityitem--timed-out',\n    title: 'Webapp components/ActivityItem',\n    name: 'Timed out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-activityitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-activityitem--errored': {\n    id: 'webapp-components-activityitem--errored',\n    title: 'Webapp components/ActivityItem',\n    name: 'Errored',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-activityitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-activityitem--no-account-name': {\n    id: 'webapp-components-activityitem--no-account-name',\n    title: 'Webapp components/ActivityItem',\n    name: 'no account name',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-activityitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-activityitem--long-account-name': {\n    id: 'webapp-components-activityitem--long-account-name',\n    title: 'Webapp components/ActivityItem',\n    name: 'long account name',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-activityitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-activitylist': {\n    name: 'ActivityList',\n    id: 'webapp-components-activitylist',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-activitylist--loading',\n      'webapp-components-activitylist--full',\n      'webapp-components-activitylist--full-no-account-name',\n      'webapp-components-activitylist--empty',\n    ],\n    type: 'component',\n  },\n  'webapp-components-activitylist--loading': {\n    id: 'webapp-components-activitylist--loading',\n    title: 'Webapp components/ActivityList',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-activitylist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-activitylist--full': {\n    id: 'webapp-components-activitylist--full',\n    title: 'Webapp components/ActivityList',\n    name: 'full',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-activitylist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-activitylist--full-no-account-name': {\n    id: 'webapp-components-activitylist--full-no-account-name',\n    title: 'Webapp components/ActivityList',\n    name: 'full, no account name',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-activitylist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-activitylist--empty': {\n    id: 'webapp-components-activitylist--empty',\n    title: 'Webapp components/ActivityList',\n    name: 'empty',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-activitylist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-appowneritem': {\n    name: 'AppOwnerItem',\n    id: 'webapp-components-appowneritem',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-appowneritem--user',\n      'webapp-components-appowneritem--user-active',\n      'webapp-components-appowneritem--org',\n      'webapp-components-appowneritem--org-active',\n      'webapp-components-appowneritem--org-no-avatar',\n      'webapp-components-appowneritem--org-no-avatar-active',\n      'webapp-components-appowneritem--shared-with-you',\n      'webapp-components-appowneritem--shared-with-you-active',\n    ],\n    type: 'component',\n  },\n  'webapp-components-appowneritem--user': {\n    id: 'webapp-components-appowneritem--user',\n    title: 'Webapp components/AppOwnerItem',\n    name: 'user',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-appowneritem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-appowneritem--user-active': {\n    id: 'webapp-components-appowneritem--user-active',\n    title: 'Webapp components/AppOwnerItem',\n    name: 'user, active',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-appowneritem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-appowneritem--org': {\n    id: 'webapp-components-appowneritem--org',\n    title: 'Webapp components/AppOwnerItem',\n    name: 'org',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-appowneritem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-appowneritem--org-active': {\n    id: 'webapp-components-appowneritem--org-active',\n    title: 'Webapp components/AppOwnerItem',\n    name: 'org, active',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-appowneritem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-appowneritem--org-no-avatar': {\n    id: 'webapp-components-appowneritem--org-no-avatar',\n    title: 'Webapp components/AppOwnerItem',\n    name: 'org no avatar, ',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-appowneritem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-appowneritem--org-no-avatar-active': {\n    id: 'webapp-components-appowneritem--org-no-avatar-active',\n    title: 'Webapp components/AppOwnerItem',\n    name: 'org no avatar, active',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-appowneritem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-appowneritem--shared-with-you': {\n    id: 'webapp-components-appowneritem--shared-with-you',\n    title: 'Webapp components/AppOwnerItem',\n    name: 'shared with you',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-appowneritem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-appowneritem--shared-with-you-active': {\n    id: 'webapp-components-appowneritem--shared-with-you-active',\n    title: 'Webapp components/AppOwnerItem',\n    name: 'shared with you, active',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-appowneritem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-appownerlist': {\n    name: 'AppOwnerList',\n    id: 'webapp-components-appownerlist',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-appownerlist--user-selected',\n      'webapp-components-appownerlist--shared-with-you-selected',\n      'webapp-components-appownerlist--org-selected',\n      'webapp-components-appownerlist--org-selected-saml',\n      'webapp-components-appownerlist--org-selected-adding-pure',\n      'webapp-components-appownerlist--org-selected-adding-pure-no-accounts',\n      'webapp-components-appownerlist--org-selected-adding-pure-refreshing',\n      'webapp-components-appownerlist--org-selected-adding-pure-bitbucket',\n    ],\n    type: 'component',\n  },\n  'webapp-components-appownerlist--user-selected': {\n    id: 'webapp-components-appownerlist--user-selected',\n    title: 'Webapp components/AppOwnerList',\n    name: 'user selected',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-appownerlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-appownerlist--shared-with-you-selected': {\n    id: 'webapp-components-appownerlist--shared-with-you-selected',\n    title: 'Webapp components/AppOwnerList',\n    name: 'sharedWithYou selected',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-appownerlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-appownerlist--org-selected': {\n    id: 'webapp-components-appownerlist--org-selected',\n    title: 'Webapp components/AppOwnerList',\n    name: 'org selected',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-appownerlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-appownerlist--org-selected-saml': {\n    id: 'webapp-components-appownerlist--org-selected-saml',\n    title: 'Webapp components/AppOwnerList',\n    name: 'org selected, saml',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-appownerlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-appownerlist--org-selected-adding-pure': {\n    id: 'webapp-components-appownerlist--org-selected-adding-pure',\n    title: 'Webapp components/AppOwnerList',\n    name: 'org selected, adding (pure)',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-appownerlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-appownerlist--org-selected-adding-pure-no-accounts': {\n    id: 'webapp-components-appownerlist--org-selected-adding-pure-no-accounts',\n    title: 'Webapp components/AppOwnerList',\n    name: 'org selected, adding (pure) no accounts',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-appownerlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-appownerlist--org-selected-adding-pure-refreshing': {\n    id: 'webapp-components-appownerlist--org-selected-adding-pure-refreshing',\n    title: 'Webapp components/AppOwnerList',\n    name: 'org selected, adding (pure), refreshing',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-appownerlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-appownerlist--org-selected-adding-pure-bitbucket': {\n    id: 'webapp-components-appownerlist--org-selected-adding-pure-bitbucket',\n    title: 'Webapp components/AppOwnerList',\n    name: 'org selected, adding (pure), bitbucket',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-appownerlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-aspectratiopreserver': {\n    name: 'AspectRatioPreserver',\n    id: 'webapp-components-aspectratiopreserver',\n    parent: 'webapp-components',\n    depth: 1,\n    children: ['webapp-components-aspectratiopreserver--default'],\n    type: 'component',\n  },\n  'webapp-components-aspectratiopreserver--default': {\n    id: 'webapp-components-aspectratiopreserver--default',\n    title: 'Webapp components/AspectRatioPreserver',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-aspectratiopreserver',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-asynctextaction': {\n    name: 'AsyncTextAction',\n    id: 'webapp-components-asynctextaction',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-asynctextaction--base',\n      'webapp-components-asynctextaction--loading',\n      'webapp-components-asynctextaction--loading-with-loading-message',\n      'webapp-components-asynctextaction--loading-left-placement',\n    ],\n    type: 'component',\n  },\n  'webapp-components-asynctextaction--base': {\n    id: 'webapp-components-asynctextaction--base',\n    title: 'Webapp components/AsyncTextAction',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-asynctextaction',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-asynctextaction--loading': {\n    id: 'webapp-components-asynctextaction--loading',\n    title: 'Webapp components/AsyncTextAction',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-asynctextaction',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-asynctextaction--loading-with-loading-message': {\n    id: 'webapp-components-asynctextaction--loading-with-loading-message',\n    title: 'Webapp components/AsyncTextAction',\n    name: 'Loading, With Loading Message',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-asynctextaction',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-asynctextaction--loading-left-placement': {\n    id: 'webapp-components-asynctextaction--loading-left-placement',\n    title: 'Webapp components/AsyncTextAction',\n    name: 'Loading, Left Placement',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-asynctextaction',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-badgecount': {\n    name: 'BadgeCount',\n    id: 'webapp-components-badgecount',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-badgecount--all-badge-counts',\n      'webapp-components-badgecount--positive',\n      'webapp-components-badgecount--negative',\n      'webapp-components-badgecount--warning',\n    ],\n    type: 'component',\n  },\n  'webapp-components-badgecount--all-badge-counts': {\n    id: 'webapp-components-badgecount--all-badge-counts',\n    title: 'Webapp components/BadgeCount',\n    name: 'all badgeCounts',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-badgecount',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-badgecount--positive': {\n    id: 'webapp-components-badgecount--positive',\n    title: 'Webapp components/BadgeCount',\n    name: 'positive',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-badgecount',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-badgecount--negative': {\n    id: 'webapp-components-badgecount--negative',\n    title: 'Webapp components/BadgeCount',\n    name: 'negative',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-badgecount',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-badgecount--warning': {\n    id: 'webapp-components-badgecount--warning',\n    title: 'Webapp components/BadgeCount',\n    name: 'warning',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-badgecount',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-banner': {\n    name: 'Banner',\n    id: 'webapp-components-banner',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-banner--base',\n      'webapp-components-banner--positive',\n      'webapp-components-banner--negative',\n    ],\n    type: 'component',\n  },\n  'webapp-components-banner--base': {\n    id: 'webapp-components-banner--base',\n    title: 'Webapp components/Banner',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-banner',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-banner--positive': {\n    id: 'webapp-components-banner--positive',\n    title: 'Webapp components/Banner',\n    name: 'Positive',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-banner',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-banner--negative': {\n    id: 'webapp-components-banner--negative',\n    title: 'Webapp components/Banner',\n    name: 'Negative',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-banner',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-baselinehistory': {\n    name: 'BaselineHistory',\n    id: 'webapp-components-baselinehistory',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-baselinehistory--loading',\n      'webapp-components-baselinehistory--new-story',\n      'webapp-components-baselinehistory--typical',\n      'webapp-components-baselinehistory--baseline-was-accepted',\n      'webapp-components-baselinehistory--second-build',\n      'webapp-components-baselinehistory--third-build',\n      'webapp-components-baselinehistory--most-recent-ancestor',\n      'webapp-components-baselinehistory--in-tooltip-smaller',\n    ],\n    type: 'component',\n  },\n  'webapp-components-baselinehistory--loading': {\n    id: 'webapp-components-baselinehistory--loading',\n    title: 'Webapp components/BaselineHistory',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-baselinehistory',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-baselinehistory--new-story': {\n    id: 'webapp-components-baselinehistory--new-story',\n    title: 'Webapp components/BaselineHistory',\n    name: 'new story',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-baselinehistory',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-baselinehistory--typical': {\n    id: 'webapp-components-baselinehistory--typical',\n    title: 'Webapp components/BaselineHistory',\n    name: 'typical',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-baselinehistory',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-baselinehistory--baseline-was-accepted': {\n    id: 'webapp-components-baselinehistory--baseline-was-accepted',\n    title: 'Webapp components/BaselineHistory',\n    name: 'baseline was accepted',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-baselinehistory',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-baselinehistory--second-build': {\n    id: 'webapp-components-baselinehistory--second-build',\n    title: 'Webapp components/BaselineHistory',\n    name: 'second build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-baselinehistory',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-baselinehistory--third-build': {\n    id: 'webapp-components-baselinehistory--third-build',\n    title: 'Webapp components/BaselineHistory',\n    name: 'third build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-baselinehistory',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-baselinehistory--most-recent-ancestor': {\n    id: 'webapp-components-baselinehistory--most-recent-ancestor',\n    title: 'Webapp components/BaselineHistory',\n    name: 'most recent ancestor',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-baselinehistory',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-baselinehistory--in-tooltip-smaller': {\n    id: 'webapp-components-baselinehistory--in-tooltip-smaller',\n    title: 'Webapp components/BaselineHistory',\n    name: 'inTooltip (smaller)',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-baselinehistory',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-billingplans': {\n    name: 'BillingPlans',\n    id: 'webapp-components-billingplans',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-billingplans--is-subscribed',\n      'webapp-components-billingplans--is-subscribed-changing-plan',\n      'webapp-components-billingplans--free',\n      'webapp-components-billingplans--trial',\n      'webapp-components-billingplans--in-trial-plan-chosen',\n      'webapp-components-billingplans--open-source-paying-for-plan',\n      'webapp-components-billingplans--open-source-paying-for-plan-changing-plan',\n      'webapp-components-billingplans--open-source-free-account',\n      'webapp-components-billingplans--open-source-plan-chosen',\n    ],\n    type: 'component',\n  },\n  'webapp-components-billingplans--is-subscribed': {\n    id: 'webapp-components-billingplans--is-subscribed',\n    title: 'Webapp components/BillingPlans',\n    name: 'is subscribed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-billingplans',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-billingplans--is-subscribed-changing-plan': {\n    id: 'webapp-components-billingplans--is-subscribed-changing-plan',\n    title: 'Webapp components/BillingPlans',\n    name: 'is subscribed, changing plan',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-billingplans',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-billingplans--free': {\n    id: 'webapp-components-billingplans--free',\n    title: 'Webapp components/BillingPlans',\n    name: 'Free',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-billingplans',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-billingplans--trial': {\n    id: 'webapp-components-billingplans--trial',\n    title: 'Webapp components/BillingPlans',\n    name: 'trial',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-billingplans',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-billingplans--in-trial-plan-chosen': {\n    id: 'webapp-components-billingplans--in-trial-plan-chosen',\n    title: 'Webapp components/BillingPlans',\n    name: 'inTrial, plan chosen',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-billingplans',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-billingplans--open-source-paying-for-plan': {\n    id: 'webapp-components-billingplans--open-source-paying-for-plan',\n    title: 'Webapp components/BillingPlans',\n    name: 'openSource, paying for plan',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-billingplans',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-billingplans--open-source-paying-for-plan-changing-plan': {\n    id: 'webapp-components-billingplans--open-source-paying-for-plan-changing-plan',\n    title: 'Webapp components/BillingPlans',\n    name: 'openSource, paying for plan, changing plan',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-billingplans',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-billingplans--open-source-free-account': {\n    id: 'webapp-components-billingplans--open-source-free-account',\n    title: 'Webapp components/BillingPlans',\n    name: 'openSource, free account',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-billingplans',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-billingplans--open-source-plan-chosen': {\n    id: 'webapp-components-billingplans--open-source-plan-chosen',\n    title: 'Webapp components/BillingPlans',\n    name: 'openSource, plan chosen',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-billingplans',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-branchpicker': {\n    name: 'BranchPicker',\n    id: 'webapp-components-branchpicker',\n    parent: 'webapp-components',\n    depth: 1,\n    children: ['webapp-components-branchpicker--default'],\n    type: 'component',\n  },\n  'webapp-components-branchpicker--default': {\n    id: 'webapp-components-branchpicker--default',\n    title: 'Webapp components/BranchPicker',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-branchpicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-breadcrumb': {\n    name: 'Breadcrumb',\n    id: 'webapp-components-breadcrumb',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-breadcrumb--loading',\n      'webapp-components-breadcrumb--root',\n      'webapp-components-breadcrumb--many-breadcrumbs',\n    ],\n    type: 'component',\n  },\n  'webapp-components-breadcrumb--loading': {\n    id: 'webapp-components-breadcrumb--loading',\n    title: 'Webapp components/Breadcrumb',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-breadcrumb',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-breadcrumb--root': {\n    id: 'webapp-components-breadcrumb--root',\n    title: 'Webapp components/Breadcrumb',\n    name: 'root',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-breadcrumb',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-breadcrumb--many-breadcrumbs': {\n    id: 'webapp-components-breadcrumb--many-breadcrumbs',\n    title: 'Webapp components/Breadcrumb',\n    name: 'many breadcrumbs',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-breadcrumb',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist': {\n    name: 'BuildComponentList',\n    id: 'webapp-components-buildcomponentlist',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-buildcomponentlist-buildcomponentlist',\n      'webapp-components-buildcomponentlist-buildcomponentlistheader',\n      'webapp-components-buildcomponentlist-groupitem',\n      'webapp-components-buildcomponentlist-polymorphiclist',\n      'webapp-components-buildcomponentlist-rootitem',\n    ],\n    type: 'group',\n  },\n  'webapp-components-buildcomponentlist-buildcomponentlist': {\n    name: 'BuildComponentList',\n    id: 'webapp-components-buildcomponentlist-buildcomponentlist',\n    parent: 'webapp-components-buildcomponentlist',\n    depth: 2,\n    children: [\n      'webapp-components-buildcomponentlist-buildcomponentlist--loading',\n      'webapp-components-buildcomponentlist-buildcomponentlist--full',\n      'webapp-components-buildcomponentlist-buildcomponentlist--full-prefixed',\n      'webapp-components-buildcomponentlist-buildcomponentlist--empty',\n      'webapp-components-buildcomponentlist-buildcomponentlist--filtering-results',\n      'webapp-components-buildcomponentlist-buildcomponentlist--filtering-no-results',\n    ],\n    type: 'component',\n  },\n  'webapp-components-buildcomponentlist-buildcomponentlist--loading': {\n    id: 'webapp-components-buildcomponentlist-buildcomponentlist--loading',\n    title: 'Webapp components/BuildComponentList/BuildComponentList',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-buildcomponentlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-buildcomponentlist--full': {\n    id: 'webapp-components-buildcomponentlist-buildcomponentlist--full',\n    title: 'Webapp components/BuildComponentList/BuildComponentList',\n    name: 'full',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-buildcomponentlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-buildcomponentlist--full-prefixed': {\n    id: 'webapp-components-buildcomponentlist-buildcomponentlist--full-prefixed',\n    title: 'Webapp components/BuildComponentList/BuildComponentList',\n    name: 'full, prefixed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-buildcomponentlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-buildcomponentlist--empty': {\n    id: 'webapp-components-buildcomponentlist-buildcomponentlist--empty',\n    title: 'Webapp components/BuildComponentList/BuildComponentList',\n    name: 'empty',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-buildcomponentlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-buildcomponentlist--filtering-results': {\n    id: 'webapp-components-buildcomponentlist-buildcomponentlist--filtering-results',\n    title: 'Webapp components/BuildComponentList/BuildComponentList',\n    name: 'filtering, results',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-buildcomponentlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-buildcomponentlist--filtering-no-results': {\n    id: 'webapp-components-buildcomponentlist-buildcomponentlist--filtering-no-results',\n    title: 'Webapp components/BuildComponentList/BuildComponentList',\n    name: 'filtering, no results',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-buildcomponentlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-buildcomponentlistheader': {\n    name: 'BuildComponentListHeader',\n    id: 'webapp-components-buildcomponentlist-buildcomponentlistheader',\n    parent: 'webapp-components-buildcomponentlist',\n    depth: 2,\n    children: [\n      'webapp-components-buildcomponentlist-buildcomponentlistheader--loading',\n      'webapp-components-buildcomponentlist-buildcomponentlistheader--default',\n      'webapp-components-buildcomponentlist-buildcomponentlistheader--with-actions',\n      'webapp-components-buildcomponentlist-buildcomponentlistheader--is-searching',\n      'webapp-components-buildcomponentlist-buildcomponentlistheader--is-searching-no-results',\n      'webapp-components-buildcomponentlist-buildcomponentlistheader--navigating-with-breadcrumb',\n    ],\n    type: 'component',\n  },\n  'webapp-components-buildcomponentlist-buildcomponentlistheader--loading': {\n    id: 'webapp-components-buildcomponentlist-buildcomponentlistheader--loading',\n    title: 'Webapp components/BuildComponentList/BuildComponentListHeader',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-buildcomponentlistheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-buildcomponentlistheader--default': {\n    id: 'webapp-components-buildcomponentlist-buildcomponentlistheader--default',\n    title: 'Webapp components/BuildComponentList/BuildComponentListHeader',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-buildcomponentlistheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-buildcomponentlistheader--with-actions': {\n    id: 'webapp-components-buildcomponentlist-buildcomponentlistheader--with-actions',\n    title: 'Webapp components/BuildComponentList/BuildComponentListHeader',\n    name: 'with actions',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-buildcomponentlistheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-buildcomponentlistheader--is-searching': {\n    id: 'webapp-components-buildcomponentlist-buildcomponentlistheader--is-searching',\n    title: 'Webapp components/BuildComponentList/BuildComponentListHeader',\n    name: 'isSearching',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-buildcomponentlistheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-buildcomponentlistheader--is-searching-no-results': {\n    id: 'webapp-components-buildcomponentlist-buildcomponentlistheader--is-searching-no-results',\n    title: 'Webapp components/BuildComponentList/BuildComponentListHeader',\n    name: 'isSearching no results',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-buildcomponentlistheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-buildcomponentlistheader--navigating-with-breadcrumb': {\n    id: 'webapp-components-buildcomponentlist-buildcomponentlistheader--navigating-with-breadcrumb',\n    title: 'Webapp components/BuildComponentList/BuildComponentListHeader',\n    name: 'navigating with breadcrumb',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-buildcomponentlistheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-groupitem': {\n    name: 'GroupItem',\n    id: 'webapp-components-buildcomponentlist-groupitem',\n    parent: 'webapp-components-buildcomponentlist',\n    depth: 2,\n    children: [\n      'webapp-components-buildcomponentlist-groupitem--all',\n      'webapp-components-buildcomponentlist-groupitem--loading',\n      'webapp-components-buildcomponentlist-groupitem--empty',\n      'webapp-components-buildcomponentlist-groupitem--single',\n      'webapp-components-buildcomponentlist-groupitem--fewer',\n      'webapp-components-buildcomponentlist-groupitem--full',\n      'webapp-components-buildcomponentlist-groupitem--full-snapshotting',\n      'webapp-components-buildcomponentlist-groupitem--full-errored',\n      'webapp-components-buildcomponentlist-groupitem--complex',\n    ],\n    type: 'component',\n  },\n  'webapp-components-buildcomponentlist-groupitem--all': {\n    id: 'webapp-components-buildcomponentlist-groupitem--all',\n    title: 'Webapp components/BuildComponentList/GroupItem',\n    name: 'all',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-groupitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-groupitem--loading': {\n    id: 'webapp-components-buildcomponentlist-groupitem--loading',\n    title: 'Webapp components/BuildComponentList/GroupItem',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-groupitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-groupitem--empty': {\n    id: 'webapp-components-buildcomponentlist-groupitem--empty',\n    title: 'Webapp components/BuildComponentList/GroupItem',\n    name: 'empty',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-groupitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-groupitem--single': {\n    id: 'webapp-components-buildcomponentlist-groupitem--single',\n    title: 'Webapp components/BuildComponentList/GroupItem',\n    name: 'single',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-groupitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-groupitem--fewer': {\n    id: 'webapp-components-buildcomponentlist-groupitem--fewer',\n    title: 'Webapp components/BuildComponentList/GroupItem',\n    name: 'fewer',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-groupitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-groupitem--full': {\n    id: 'webapp-components-buildcomponentlist-groupitem--full',\n    title: 'Webapp components/BuildComponentList/GroupItem',\n    name: 'full',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-groupitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-groupitem--full-snapshotting': {\n    id: 'webapp-components-buildcomponentlist-groupitem--full-snapshotting',\n    title: 'Webapp components/BuildComponentList/GroupItem',\n    name: 'full snapshotting',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-groupitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-groupitem--full-errored': {\n    id: 'webapp-components-buildcomponentlist-groupitem--full-errored',\n    title: 'Webapp components/BuildComponentList/GroupItem',\n    name: 'full errored',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-groupitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-groupitem--complex': {\n    id: 'webapp-components-buildcomponentlist-groupitem--complex',\n    title: 'Webapp components/BuildComponentList/GroupItem',\n    name: 'complex',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-groupitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-polymorphiclist': {\n    name: 'PolymorphicList',\n    id: 'webapp-components-buildcomponentlist-polymorphiclist',\n    parent: 'webapp-components-buildcomponentlist',\n    depth: 2,\n    children: [\n      'webapp-components-buildcomponentlist-polymorphiclist--default',\n      'webapp-components-buildcomponentlist-polymorphiclist--complex',\n      'webapp-components-buildcomponentlist-polymorphiclist--loading',\n    ],\n    type: 'component',\n  },\n  'webapp-components-buildcomponentlist-polymorphiclist--default': {\n    id: 'webapp-components-buildcomponentlist-polymorphiclist--default',\n    title: 'Webapp components/BuildComponentList/PolymorphicList',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-polymorphiclist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-polymorphiclist--complex': {\n    id: 'webapp-components-buildcomponentlist-polymorphiclist--complex',\n    title: 'Webapp components/BuildComponentList/PolymorphicList',\n    name: 'complex',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-polymorphiclist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-polymorphiclist--loading': {\n    id: 'webapp-components-buildcomponentlist-polymorphiclist--loading',\n    title: 'Webapp components/BuildComponentList/PolymorphicList',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-polymorphiclist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-rootitem': {\n    name: 'RootItem',\n    id: 'webapp-components-buildcomponentlist-rootitem',\n    parent: 'webapp-components-buildcomponentlist',\n    depth: 2,\n    children: [\n      'webapp-components-buildcomponentlist-rootitem--default',\n      'webapp-components-buildcomponentlist-rootitem--complex',\n    ],\n    type: 'component',\n  },\n  'webapp-components-buildcomponentlist-rootitem--default': {\n    id: 'webapp-components-buildcomponentlist-rootitem--default',\n    title: 'Webapp components/BuildComponentList/RootItem',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-rootitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildcomponentlist-rootitem--complex': {\n    id: 'webapp-components-buildcomponentlist-rootitem--complex',\n    title: 'Webapp components/BuildComponentList/RootItem',\n    name: 'complex',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-buildcomponentlist-rootitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-builditem': {\n    name: 'BuildItem',\n    id: 'webapp-components-builditem',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-builditem--all-build-item',\n      'webapp-components-builditem--loading',\n      'webapp-components-builditem--passed',\n      'webapp-components-builditem--failed',\n      'webapp-components-builditem--unreviewed',\n      'webapp-components-builditem--in-progress',\n      'webapp-components-builditem--from-agent-passed',\n      'webapp-components-builditem--timed-out',\n      'webapp-components-builditem--errored',\n      'webapp-components-builditem--publish-only',\n      'webapp-components-builditem--upgrade',\n    ],\n    type: 'component',\n  },\n  'webapp-components-builditem--all-build-item': {\n    id: 'webapp-components-builditem--all-build-item',\n    title: 'Webapp components/BuildItem',\n    name: 'All BuildItem',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-builditem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-builditem--loading': {\n    id: 'webapp-components-builditem--loading',\n    title: 'Webapp components/BuildItem',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-builditem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-builditem--passed': {\n    id: 'webapp-components-builditem--passed',\n    title: 'Webapp components/BuildItem',\n    name: 'Passed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-builditem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-builditem--failed': {\n    id: 'webapp-components-builditem--failed',\n    title: 'Webapp components/BuildItem',\n    name: 'Failed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-builditem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-builditem--unreviewed': {\n    id: 'webapp-components-builditem--unreviewed',\n    title: 'Webapp components/BuildItem',\n    name: 'Unreviewed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-builditem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-builditem--in-progress': {\n    id: 'webapp-components-builditem--in-progress',\n    title: 'Webapp components/BuildItem',\n    name: 'In progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-builditem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-builditem--from-agent-passed': {\n    id: 'webapp-components-builditem--from-agent-passed',\n    title: 'Webapp components/BuildItem',\n    name: 'From agent, passed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-builditem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-builditem--timed-out': {\n    id: 'webapp-components-builditem--timed-out',\n    title: 'Webapp components/BuildItem',\n    name: 'Timed out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-builditem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-builditem--errored': {\n    id: 'webapp-components-builditem--errored',\n    title: 'Webapp components/BuildItem',\n    name: 'Errored',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-builditem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-builditem--publish-only': {\n    id: 'webapp-components-builditem--publish-only',\n    title: 'Webapp components/BuildItem',\n    name: 'Publish Only',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-builditem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-builditem--upgrade': {\n    id: 'webapp-components-builditem--upgrade',\n    title: 'Webapp components/BuildItem',\n    name: 'Upgrade',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-builditem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildlist': {\n    name: 'BuildList',\n    id: 'webapp-components-buildlist',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-buildlist--loading',\n      'webapp-components-buildlist--full',\n      'webapp-components-buildlist--has-next-page',\n      'webapp-components-buildlist--empty',\n      'webapp-components-buildlist--error',\n    ],\n    type: 'component',\n  },\n  'webapp-components-buildlist--loading': {\n    id: 'webapp-components-buildlist--loading',\n    title: 'Webapp components/BuildList',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buildlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildlist--full': {\n    id: 'webapp-components-buildlist--full',\n    title: 'Webapp components/BuildList',\n    name: 'full',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buildlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildlist--has-next-page': {\n    id: 'webapp-components-buildlist--has-next-page',\n    title: 'Webapp components/BuildList',\n    name: 'has next page',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buildlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildlist--empty': {\n    id: 'webapp-components-buildlist--empty',\n    title: 'Webapp components/BuildList',\n    name: 'empty',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buildlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildlist--error': {\n    id: 'webapp-components-buildlist--error',\n    title: 'Webapp components/BuildList',\n    name: 'error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buildlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildstatuslight': {\n    name: 'BuildStatusLight',\n    id: 'webapp-components-buildstatuslight',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-buildstatuslight--loading',\n      'webapp-components-buildstatuslight--in-progress',\n      'webapp-components-buildstatuslight--in-progress-rep-only',\n      'webapp-components-buildstatuslight--in-progress-rep-only-limited',\n      'webapp-components-buildstatuslight--pending',\n      'webapp-components-buildstatuslight--passed-limited',\n      'webapp-components-buildstatuslight--passed',\n      'webapp-components-buildstatuslight--denied',\n      'webapp-components-buildstatuslight--accepted',\n      'webapp-components-buildstatuslight--timed-out',\n      'webapp-components-buildstatuslight--timed-out-rep-only',\n      'webapp-components-buildstatuslight--timed-out-rep-only-limited',\n      'webapp-components-buildstatuslight--build-error',\n      'webapp-components-buildstatuslight--build-error-rep-only',\n      'webapp-components-buildstatuslight--build-error-rep-only-limited',\n    ],\n    type: 'component',\n  },\n  'webapp-components-buildstatuslight--loading': {\n    id: 'webapp-components-buildstatuslight--loading',\n    title: 'Webapp components/BuildStatusLight',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buildstatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildstatuslight--in-progress': {\n    id: 'webapp-components-buildstatuslight--in-progress',\n    title: 'Webapp components/BuildStatusLight',\n    name: 'In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buildstatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildstatuslight--in-progress-rep-only': {\n    id: 'webapp-components-buildstatuslight--in-progress-rep-only',\n    title: 'Webapp components/BuildStatusLight',\n    name: 'In Progress, Representative Only',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buildstatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildstatuslight--in-progress-rep-only-limited': {\n    id: 'webapp-components-buildstatuslight--in-progress-rep-only-limited',\n    title: 'Webapp components/BuildStatusLight',\n    name: 'In Progress, Representative Only, Limited',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buildstatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildstatuslight--pending': {\n    id: 'webapp-components-buildstatuslight--pending',\n    title: 'Webapp components/BuildStatusLight',\n    name: 'Pending',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buildstatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildstatuslight--passed-limited': {\n    id: 'webapp-components-buildstatuslight--passed-limited',\n    title: 'Webapp components/BuildStatusLight',\n    name: 'Passed, Limited',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buildstatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildstatuslight--passed': {\n    id: 'webapp-components-buildstatuslight--passed',\n    title: 'Webapp components/BuildStatusLight',\n    name: 'Passed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buildstatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildstatuslight--denied': {\n    id: 'webapp-components-buildstatuslight--denied',\n    title: 'Webapp components/BuildStatusLight',\n    name: 'Denied',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buildstatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildstatuslight--accepted': {\n    id: 'webapp-components-buildstatuslight--accepted',\n    title: 'Webapp components/BuildStatusLight',\n    name: 'Accepted',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buildstatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildstatuslight--timed-out': {\n    id: 'webapp-components-buildstatuslight--timed-out',\n    title: 'Webapp components/BuildStatusLight',\n    name: 'Timed Out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buildstatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildstatuslight--timed-out-rep-only': {\n    id: 'webapp-components-buildstatuslight--timed-out-rep-only',\n    title: 'Webapp components/BuildStatusLight',\n    name: 'Timed Out, Representative Only',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buildstatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildstatuslight--timed-out-rep-only-limited': {\n    id: 'webapp-components-buildstatuslight--timed-out-rep-only-limited',\n    title: 'Webapp components/BuildStatusLight',\n    name: 'Timed Out, Representative Only, Limited',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buildstatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildstatuslight--build-error': {\n    id: 'webapp-components-buildstatuslight--build-error',\n    title: 'Webapp components/BuildStatusLight',\n    name: 'Build Error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buildstatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildstatuslight--build-error-rep-only': {\n    id: 'webapp-components-buildstatuslight--build-error-rep-only',\n    title: 'Webapp components/BuildStatusLight',\n    name: 'Build Error, Representative Only',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buildstatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buildstatuslight--build-error-rep-only-limited': {\n    id: 'webapp-components-buildstatuslight--build-error-rep-only-limited',\n    title: 'Webapp components/BuildStatusLight',\n    name: 'Build Error, Representative Only, Limited',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buildstatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-button': {\n    name: 'Button',\n    id: 'webapp-components-button',\n    parent: 'webapp-components',\n    depth: 1,\n    children: ['webapp-components-button--positive'],\n    type: 'component',\n  },\n  'webapp-components-button--positive': {\n    id: 'webapp-components-button--positive',\n    title: 'Webapp components/Button',\n    name: 'positive',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-button',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buttonmulti': {\n    name: 'ButtonMulti',\n    id: 'webapp-components-buttonmulti',\n    parent: 'webapp-components',\n    depth: 1,\n    children: ['webapp-components-buttonmulti--default'],\n    type: 'component',\n  },\n  'webapp-components-buttonmulti--default': {\n    id: 'webapp-components-buttonmulti--default',\n    title: 'Webapp components/ButtonMulti',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buttonmulti',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buttontoggle': {\n    name: 'ButtonToggle',\n    id: 'webapp-components-buttontoggle',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-buttontoggle--outline-buttons-small',\n      'webapp-components-buttontoggle--outline-three-buttons-small',\n      'webapp-components-buttontoggle--pill-w-text',\n      'webapp-components-buttontoggle--pill-w-image',\n      'webapp-components-buttontoggle--tab',\n    ],\n    type: 'component',\n  },\n  'webapp-components-buttontoggle--outline-buttons-small': {\n    id: 'webapp-components-buttontoggle--outline-buttons-small',\n    title: 'Webapp components/ButtonToggle',\n    name: 'outline buttons small',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buttontoggle',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buttontoggle--outline-three-buttons-small': {\n    id: 'webapp-components-buttontoggle--outline-three-buttons-small',\n    title: 'Webapp components/ButtonToggle',\n    name: 'outline three buttons small',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buttontoggle',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buttontoggle--pill-w-text': {\n    id: 'webapp-components-buttontoggle--pill-w-text',\n    title: 'Webapp components/ButtonToggle',\n    name: 'pill w/text',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buttontoggle',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buttontoggle--pill-w-image': {\n    id: 'webapp-components-buttontoggle--pill-w-image',\n    title: 'Webapp components/ButtonToggle',\n    name: 'pill w/image',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buttontoggle',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-buttontoggle--tab': {\n    id: 'webapp-components-buttontoggle--tab',\n    title: 'Webapp components/ButtonToggle',\n    name: 'tab',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-buttontoggle',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas': {\n    name: 'Canvas',\n    id: 'webapp-components-canvas',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-canvas--default',\n      'webapp-components-canvas--default-w-label-link',\n      'webapp-components-canvas--pure-w-label-link-at-top',\n      'webapp-components-canvas--pure-w-label-link-not-at-top',\n      'webapp-components-canvas--default-w-label-link-baseline-tooltip',\n      'webapp-components-canvas--default-w-figure-link',\n      'webapp-components-canvas--default-w-diff-figure',\n      'webapp-components-canvas--default-w-diff-figure-horizontally-larger',\n      'webapp-components-canvas--default-w-diff-figure-vertically-larger',\n      'webapp-components-canvas--default-w-diff-figure-larger-both-ways',\n      'webapp-components-canvas--loading',\n      'webapp-components-canvas--in-progress',\n      'webapp-components-canvas--snapshot-error',\n      'webapp-components-canvas--ignored-regions-hidden',\n      'webapp-components-canvas--ignored-regions-shown',\n      'webapp-components-canvas--ignored-regions-shown-w-diff-figure',\n      'webapp-components-canvas--interactive-url-w-interactive-mode',\n      'webapp-components-canvas--interactive-url-w-interactive-mode-bad-url',\n      'webapp-components-canvas--interactive-url-w-interactive-mode-bad-spec',\n      'webapp-components-canvas--interactive-url-wo-interactive-mode',\n      'webapp-components-canvas--pure-interactive-url-connection-problem',\n      'webapp-components-canvas--tall-thin-image',\n      'webapp-components-canvas--tall-thin-image-w-ignored-regions',\n      'webapp-components-canvas--wide-short-image',\n    ],\n    type: 'component',\n  },\n  'webapp-components-canvas--default': {\n    id: 'webapp-components-canvas--default',\n    title: 'Webapp components/Canvas',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--default-w-label-link': {\n    id: 'webapp-components-canvas--default-w-label-link',\n    title: 'Webapp components/Canvas',\n    name: 'default w/label link',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--pure-w-label-link-at-top': {\n    id: 'webapp-components-canvas--pure-w-label-link-at-top',\n    title: 'Webapp components/Canvas',\n    name: 'pure, w/label link, at top',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--pure-w-label-link-not-at-top': {\n    id: 'webapp-components-canvas--pure-w-label-link-not-at-top',\n    title: 'Webapp components/Canvas',\n    name: 'pure, w/label link, not at top',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--default-w-label-link-baseline-tooltip': {\n    id: 'webapp-components-canvas--default-w-label-link-baseline-tooltip',\n    title: 'Webapp components/Canvas',\n    name: 'default w/label link + baseline tooltip',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--default-w-figure-link': {\n    id: 'webapp-components-canvas--default-w-figure-link',\n    title: 'Webapp components/Canvas',\n    name: 'default w/figureLink',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--default-w-diff-figure': {\n    id: 'webapp-components-canvas--default-w-diff-figure',\n    title: 'Webapp components/Canvas',\n    name: 'default w/diffFigure',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--default-w-diff-figure-horizontally-larger': {\n    id: 'webapp-components-canvas--default-w-diff-figure-horizontally-larger',\n    title: 'Webapp components/Canvas',\n    name: 'default w/diffFigure, horizontally larger',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--default-w-diff-figure-vertically-larger': {\n    id: 'webapp-components-canvas--default-w-diff-figure-vertically-larger',\n    title: 'Webapp components/Canvas',\n    name: 'default w/diffFigure, vertically larger',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--default-w-diff-figure-larger-both-ways': {\n    id: 'webapp-components-canvas--default-w-diff-figure-larger-both-ways',\n    title: 'Webapp components/Canvas',\n    name: 'default w/diffFigure, larger both ways',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--loading': {\n    id: 'webapp-components-canvas--loading',\n    title: 'Webapp components/Canvas',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--in-progress': {\n    id: 'webapp-components-canvas--in-progress',\n    title: 'Webapp components/Canvas',\n    name: 'in progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--snapshot-error': {\n    id: 'webapp-components-canvas--snapshot-error',\n    title: 'Webapp components/Canvas',\n    name: 'snapshotError',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--ignored-regions-hidden': {\n    id: 'webapp-components-canvas--ignored-regions-hidden',\n    title: 'Webapp components/Canvas',\n    name: 'ignored regions hidden',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--ignored-regions-shown': {\n    id: 'webapp-components-canvas--ignored-regions-shown',\n    title: 'Webapp components/Canvas',\n    name: 'ignored regions shown',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--ignored-regions-shown-w-diff-figure': {\n    id: 'webapp-components-canvas--ignored-regions-shown-w-diff-figure',\n    title: 'Webapp components/Canvas',\n    name: 'ignored regions shown w/diffFigure',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--interactive-url-w-interactive-mode': {\n    id: 'webapp-components-canvas--interactive-url-w-interactive-mode',\n    title: 'Webapp components/Canvas',\n    name: 'interactiveUrl w/ interactiveMode',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--interactive-url-w-interactive-mode-bad-url': {\n    id: 'webapp-components-canvas--interactive-url-w-interactive-mode-bad-url',\n    title: 'Webapp components/Canvas',\n    name: 'interactiveUrl w/ interactiveMode, bad URL',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--interactive-url-w-interactive-mode-bad-spec': {\n    id: 'webapp-components-canvas--interactive-url-w-interactive-mode-bad-spec',\n    title: 'Webapp components/Canvas',\n    name: 'interactiveUrl w/ interactiveMode, bad spec',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--interactive-url-wo-interactive-mode': {\n    id: 'webapp-components-canvas--interactive-url-wo-interactive-mode',\n    title: 'Webapp components/Canvas',\n    name: 'interactiveUrl w/o interactiveMode',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--pure-interactive-url-connection-problem': {\n    id: 'webapp-components-canvas--pure-interactive-url-connection-problem',\n    title: 'Webapp components/Canvas',\n    name: 'pure, interactiveUrl connection problem',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--tall-thin-image': {\n    id: 'webapp-components-canvas--tall-thin-image',\n    title: 'Webapp components/Canvas',\n    name: 'tall thin image',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--tall-thin-image-w-ignored-regions': {\n    id: 'webapp-components-canvas--tall-thin-image-w-ignored-regions',\n    title: 'Webapp components/Canvas',\n    name: 'tall thin image w/ ignored regions',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-canvas--wide-short-image': {\n    id: 'webapp-components-canvas--wide-short-image',\n    title: 'Webapp components/Canvas',\n    name: 'wide short image',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-canvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-cardinal': {\n    name: 'Cardinal',\n    id: 'webapp-components-cardinal',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-cardinal--all-cardinals',\n      'webapp-components-cardinal--small-loading',\n      'webapp-components-cardinal--small-default',\n      'webapp-components-cardinal--small-positive',\n      'webapp-components-cardinal--small-negative',\n      'webapp-components-cardinal--small-warning',\n      'webapp-components-cardinal--small-neutral',\n      'webapp-components-cardinal--small-selectable',\n      'webapp-components-cardinal--large-loading',\n      'webapp-components-cardinal--large-default',\n      'webapp-components-cardinal--large-link',\n      'webapp-components-cardinal--large-singular',\n      'webapp-components-cardinal--large-plural',\n    ],\n    type: 'component',\n  },\n  'webapp-components-cardinal--all-cardinals': {\n    id: 'webapp-components-cardinal--all-cardinals',\n    title: 'Webapp components/Cardinal',\n    name: 'all cardinals',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-cardinal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-cardinal--small-loading': {\n    id: 'webapp-components-cardinal--small-loading',\n    title: 'Webapp components/Cardinal',\n    name: 'small loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-cardinal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-cardinal--small-default': {\n    id: 'webapp-components-cardinal--small-default',\n    title: 'Webapp components/Cardinal',\n    name: 'small default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-cardinal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-cardinal--small-positive': {\n    id: 'webapp-components-cardinal--small-positive',\n    title: 'Webapp components/Cardinal',\n    name: 'small positive',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-cardinal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-cardinal--small-negative': {\n    id: 'webapp-components-cardinal--small-negative',\n    title: 'Webapp components/Cardinal',\n    name: 'small negative',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-cardinal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-cardinal--small-warning': {\n    id: 'webapp-components-cardinal--small-warning',\n    title: 'Webapp components/Cardinal',\n    name: 'small warning',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-cardinal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-cardinal--small-neutral': {\n    id: 'webapp-components-cardinal--small-neutral',\n    title: 'Webapp components/Cardinal',\n    name: 'small neutral',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-cardinal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-cardinal--small-selectable': {\n    id: 'webapp-components-cardinal--small-selectable',\n    title: 'Webapp components/Cardinal',\n    name: 'small selectable',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-cardinal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-cardinal--large-loading': {\n    id: 'webapp-components-cardinal--large-loading',\n    title: 'Webapp components/Cardinal',\n    name: 'large loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-cardinal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-cardinal--large-default': {\n    id: 'webapp-components-cardinal--large-default',\n    title: 'Webapp components/Cardinal',\n    name: 'large default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-cardinal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-cardinal--large-link': {\n    id: 'webapp-components-cardinal--large-link',\n    title: 'Webapp components/Cardinal',\n    name: 'large link',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-cardinal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-cardinal--large-singular': {\n    id: 'webapp-components-cardinal--large-singular',\n    title: 'Webapp components/Cardinal',\n    name: 'large singular',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-cardinal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-cardinal--large-plural': {\n    id: 'webapp-components-cardinal--large-plural',\n    title: 'Webapp components/Cardinal',\n    name: 'large plural',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-cardinal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-checkbox': {\n    name: 'Checkbox',\n    id: 'webapp-components-checkbox',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-checkbox--all-checkboxes',\n      'webapp-components-checkbox--unchecked',\n      'webapp-components-checkbox--checked',\n      'webapp-components-checkbox--primary',\n    ],\n    type: 'component',\n  },\n  'webapp-components-checkbox--all-checkboxes': {\n    id: 'webapp-components-checkbox--all-checkboxes',\n    title: 'Webapp components/Checkbox',\n    name: 'all checkboxes',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-checkbox',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-checkbox--unchecked': {\n    id: 'webapp-components-checkbox--unchecked',\n    title: 'Webapp components/Checkbox',\n    name: 'unchecked',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-checkbox',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-checkbox--checked': {\n    id: 'webapp-components-checkbox--checked',\n    title: 'Webapp components/Checkbox',\n    name: 'checked',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-checkbox',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-checkbox--primary': {\n    id: 'webapp-components-checkbox--primary',\n    title: 'Webapp components/Checkbox',\n    name: 'primary',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-checkbox',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-cieyebrow': {\n    name: 'CIEyebrow',\n    id: 'webapp-components-cieyebrow',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-cieyebrow--unlinked',\n      'webapp-components-cieyebrow--github',\n      'webapp-components-cieyebrow--bitbucket',\n      'webapp-components-cieyebrow--gitlab',\n      'webapp-components-cieyebrow--dismissed',\n    ],\n    type: 'component',\n  },\n  'webapp-components-cieyebrow--unlinked': {\n    id: 'webapp-components-cieyebrow--unlinked',\n    title: 'Webapp components/CIEyebrow',\n    name: 'Unlinked',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-cieyebrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-cieyebrow--github': {\n    id: 'webapp-components-cieyebrow--github',\n    title: 'Webapp components/CIEyebrow',\n    name: 'Github',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-cieyebrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-cieyebrow--bitbucket': {\n    id: 'webapp-components-cieyebrow--bitbucket',\n    title: 'Webapp components/CIEyebrow',\n    name: 'Bitbucket',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-cieyebrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-cieyebrow--gitlab': {\n    id: 'webapp-components-cieyebrow--gitlab',\n    title: 'Webapp components/CIEyebrow',\n    name: 'Gitlab',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-cieyebrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-cieyebrow--dismissed': {\n    id: 'webapp-components-cieyebrow--dismissed',\n    title: 'Webapp components/CIEyebrow',\n    name: 'Dismissed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-cieyebrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-clipboard': {\n    name: 'Clipboard',\n    id: 'webapp-components-clipboard',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-clipboard--default',\n      'webapp-components-clipboard--with-feedback',\n    ],\n    type: 'component',\n  },\n  'webapp-components-clipboard--default': {\n    id: 'webapp-components-clipboard--default',\n    title: 'Webapp components/Clipboard',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-clipboard',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-clipboard--with-feedback': {\n    id: 'webapp-components-clipboard--with-feedback',\n    title: 'Webapp components/Clipboard',\n    name: 'With Feedback',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-clipboard',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-clipboardcode': {\n    name: 'ClipboardCode',\n    id: 'webapp-components-clipboardcode',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-clipboardcode--default',\n      'webapp-components-clipboardcode--wrapped',\n    ],\n    type: 'component',\n  },\n  'webapp-components-clipboardcode--default': {\n    id: 'webapp-components-clipboardcode--default',\n    title: 'Webapp components/ClipboardCode',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-clipboardcode',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-clipboardcode--wrapped': {\n    id: 'webapp-components-clipboardcode--wrapped',\n    title: 'Webapp components/ClipboardCode',\n    name: 'Wrapped',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-clipboardcode',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-clipboardicon': {\n    name: 'ClipboardIcon',\n    id: 'webapp-components-clipboardicon',\n    parent: 'webapp-components',\n    depth: 1,\n    children: ['webapp-components-clipboardicon--default'],\n    type: 'component',\n  },\n  'webapp-components-clipboardicon--default': {\n    id: 'webapp-components-clipboardicon--default',\n    title: 'Webapp components/ClipboardIcon',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-clipboardicon',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-clipboardinput': {\n    name: 'ClipboardInput',\n    id: 'webapp-components-clipboardinput',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-clipboardinput--default',\n      'webapp-components-clipboardinput--clipped',\n    ],\n    type: 'component',\n  },\n  'webapp-components-clipboardinput--default': {\n    id: 'webapp-components-clipboardinput--default',\n    title: 'Webapp components/ClipboardInput',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-clipboardinput',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-clipboardinput--clipped': {\n    id: 'webapp-components-clipboardinput--clipped',\n    title: 'Webapp components/ClipboardInput',\n    name: 'Clipped',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-clipboardinput',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment': {\n    name: 'Comment',\n    id: 'webapp-components-comment',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-comment-addcomment',\n      'webapp-components-comment-comment',\n      'webapp-components-comment-commentdate',\n      'webapp-components-comment-commentformmanager',\n      'webapp-components-comment-commentheading',\n      'webapp-components-comment-commentlist',\n      'webapp-components-comment-commenttextarea',\n      'webapp-components-comment-commentthread',\n      'webapp-components-comment-deletecomment',\n      'webapp-components-comment-inlinecommentthread',\n      'webapp-components-comment-replytocomment',\n      'webapp-components-comment-resolvecommentthreadbutton',\n      'webapp-components-comment-undoresolvecommentthreadbutton',\n    ],\n    type: 'group',\n  },\n  'webapp-components-comment-addcomment': {\n    name: 'AddComment',\n    id: 'webapp-components-comment-addcomment',\n    parent: 'webapp-components-comment',\n    depth: 2,\n    children: [\n      'webapp-components-comment-addcomment--base',\n      'webapp-components-comment-addcomment--initial-value',\n      'webapp-components-comment-addcomment--with-form-open',\n      'webapp-components-comment-addcomment--with-form-open-loading',\n      'webapp-components-comment-addcomment--form-pure-with-value',\n      'webapp-components-comment-addcomment--form-pure-with-value-loading',\n      'webapp-components-comment-addcomment--form-pure-with-error',\n    ],\n    type: 'component',\n  },\n  'webapp-components-comment-addcomment--base': {\n    id: 'webapp-components-comment-addcomment--base',\n    title: 'Webapp components/Comment/AddComment',\n    name: 'base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-addcomment',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-addcomment--initial-value': {\n    id: 'webapp-components-comment-addcomment--initial-value',\n    title: 'Webapp components/Comment/AddComment',\n    name: 'Initial Value',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-addcomment',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-addcomment--with-form-open': {\n    id: 'webapp-components-comment-addcomment--with-form-open',\n    title: 'Webapp components/Comment/AddComment',\n    name: 'with form open',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-addcomment',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-addcomment--with-form-open-loading': {\n    id: 'webapp-components-comment-addcomment--with-form-open-loading',\n    title: 'Webapp components/Comment/AddComment',\n    name: 'with form open, loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-addcomment',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-addcomment--form-pure-with-value': {\n    id: 'webapp-components-comment-addcomment--form-pure-with-value',\n    title: 'Webapp components/Comment/AddComment',\n    name: 'form, pure, with value',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-addcomment',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-addcomment--form-pure-with-value-loading': {\n    id: 'webapp-components-comment-addcomment--form-pure-with-value-loading',\n    title: 'Webapp components/Comment/AddComment',\n    name: 'form, pure, with value, loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-addcomment',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-addcomment--form-pure-with-error': {\n    id: 'webapp-components-comment-addcomment--form-pure-with-error',\n    title: 'Webapp components/Comment/AddComment',\n    name: 'form, pure, with error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-addcomment',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-comment': {\n    name: 'Comment',\n    id: 'webapp-components-comment-comment',\n    parent: 'webapp-components-comment',\n    depth: 2,\n    children: [\n      'webapp-components-comment-comment--base',\n      'webapp-components-comment-comment--with-link',\n      'webapp-components-comment-comment--collapsed',\n      'webapp-components-comment-comment--collapsed-truncated',\n    ],\n    type: 'component',\n  },\n  'webapp-components-comment-comment--base': {\n    id: 'webapp-components-comment-comment--base',\n    title: 'Webapp components/Comment/Comment',\n    name: 'base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-comment',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-comment--with-link': {\n    id: 'webapp-components-comment-comment--with-link',\n    title: 'Webapp components/Comment/Comment',\n    name: 'with link',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-comment',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-comment--collapsed': {\n    id: 'webapp-components-comment-comment--collapsed',\n    title: 'Webapp components/Comment/Comment',\n    name: 'collapsed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-comment',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-comment--collapsed-truncated': {\n    id: 'webapp-components-comment-comment--collapsed-truncated',\n    title: 'Webapp components/Comment/Comment',\n    name: 'collapsed, truncated',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-comment',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-commentdate': {\n    name: 'CommentDate',\n    id: 'webapp-components-comment-commentdate',\n    parent: 'webapp-components-comment',\n    depth: 2,\n    children: [\n      'webapp-components-comment-commentdate--base',\n      'webapp-components-comment-commentdate--with-build',\n    ],\n    type: 'component',\n  },\n  'webapp-components-comment-commentdate--base': {\n    id: 'webapp-components-comment-commentdate--base',\n    title: 'Webapp components/Comment/CommentDate',\n    name: 'base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-commentdate',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-commentdate--with-build': {\n    id: 'webapp-components-comment-commentdate--with-build',\n    title: 'Webapp components/Comment/CommentDate',\n    name: 'with build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-commentdate',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-commentformmanager': {\n    name: 'CommentFormManager',\n    id: 'webapp-components-comment-commentformmanager',\n    parent: 'webapp-components-comment',\n    depth: 2,\n    children: [\n      'webapp-components-comment-commentformmanager--base',\n      'webapp-components-comment-commentformmanager--pure-form-visible',\n      'webapp-components-comment-commentformmanager--pure-form-not-visible',\n    ],\n    type: 'component',\n  },\n  'webapp-components-comment-commentformmanager--base': {\n    id: 'webapp-components-comment-commentformmanager--base',\n    title: 'Webapp components/Comment/CommentFormManager',\n    name: 'base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-commentformmanager',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-commentformmanager--pure-form-visible': {\n    id: 'webapp-components-comment-commentformmanager--pure-form-visible',\n    title: 'Webapp components/Comment/CommentFormManager',\n    name: 'pure, form visible',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-commentformmanager',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-commentformmanager--pure-form-not-visible': {\n    id: 'webapp-components-comment-commentformmanager--pure-form-not-visible',\n    title: 'Webapp components/Comment/CommentFormManager',\n    name: 'pure, form not visible',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-commentformmanager',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-commentheading': {\n    name: 'CommentHeading',\n    id: 'webapp-components-comment-commentheading',\n    parent: 'webapp-components-comment',\n    depth: 2,\n    children: ['webapp-components-comment-commentheading--base'],\n    type: 'component',\n  },\n  'webapp-components-comment-commentheading--base': {\n    id: 'webapp-components-comment-commentheading--base',\n    title: 'Webapp components/Comment/CommentHeading',\n    name: 'base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-commentheading',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-commentlist': {\n    name: 'CommentList',\n    id: 'webapp-components-comment-commentlist',\n    parent: 'webapp-components-comment',\n    depth: 2,\n    children: [\n      'webapp-components-comment-commentlist--can-comment',\n      'webapp-components-comment-commentlist--cannot-comment',\n    ],\n    type: 'component',\n  },\n  'webapp-components-comment-commentlist--can-comment': {\n    id: 'webapp-components-comment-commentlist--can-comment',\n    title: 'Webapp components/Comment/CommentList',\n    name: 'can comment',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-commentlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-commentlist--cannot-comment': {\n    id: 'webapp-components-comment-commentlist--cannot-comment',\n    title: 'Webapp components/Comment/CommentList',\n    name: 'cannot comment',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-commentlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-commenttextarea': {\n    name: 'CommentTextarea',\n    id: 'webapp-components-comment-commenttextarea',\n    parent: 'webapp-components-comment',\n    depth: 2,\n    children: [\n      'webapp-components-comment-commenttextarea--base',\n      'webapp-components-comment-commenttextarea--with-value',\n    ],\n    type: 'component',\n  },\n  'webapp-components-comment-commenttextarea--base': {\n    id: 'webapp-components-comment-commenttextarea--base',\n    title: 'Webapp components/Comment/CommentTextarea',\n    name: 'base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-commenttextarea',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-commenttextarea--with-value': {\n    id: 'webapp-components-comment-commenttextarea--with-value',\n    title: 'Webapp components/Comment/CommentTextarea',\n    name: 'with value',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-commenttextarea',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-commentthread': {\n    name: 'CommentThread',\n    id: 'webapp-components-comment-commentthread',\n    parent: 'webapp-components-comment',\n    depth: 2,\n    children: [\n      'webapp-components-comment-commentthread--pure-collapsed',\n      'webapp-components-comment-commentthread--pure-expanded',\n      'webapp-components-comment-commentthread--pure-expanded-w-list',\n    ],\n    type: 'component',\n  },\n  'webapp-components-comment-commentthread--pure-collapsed': {\n    id: 'webapp-components-comment-commentthread--pure-collapsed',\n    title: 'Webapp components/Comment/CommentThread',\n    name: 'pure, collapsed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-commentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-commentthread--pure-expanded': {\n    id: 'webapp-components-comment-commentthread--pure-expanded',\n    title: 'Webapp components/Comment/CommentThread',\n    name: 'pure, expanded',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-commentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-commentthread--pure-expanded-w-list': {\n    id: 'webapp-components-comment-commentthread--pure-expanded-w-list',\n    title: 'Webapp components/Comment/CommentThread',\n    name: 'pure, expanded, w/ list',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-commentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-deletecomment': {\n    name: 'DeleteComment',\n    id: 'webapp-components-comment-deletecomment',\n    parent: 'webapp-components-comment',\n    depth: 2,\n    children: [\n      'webapp-components-comment-deletecomment--can-delete',\n      'webapp-components-comment-deletecomment--can-delete-with-children',\n      'webapp-components-comment-deletecomment--cannot-delete',\n    ],\n    type: 'component',\n  },\n  'webapp-components-comment-deletecomment--can-delete': {\n    id: 'webapp-components-comment-deletecomment--can-delete',\n    title: 'Webapp components/Comment/DeleteComment',\n    name: 'can delete',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-deletecomment',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-deletecomment--can-delete-with-children': {\n    id: 'webapp-components-comment-deletecomment--can-delete-with-children',\n    title: 'Webapp components/Comment/DeleteComment',\n    name: 'can delete, with children',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-deletecomment',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-deletecomment--cannot-delete': {\n    id: 'webapp-components-comment-deletecomment--cannot-delete',\n    title: 'Webapp components/Comment/DeleteComment',\n    name: 'cannot delete',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-deletecomment',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-inlinecommentthread': {\n    name: 'InlineCommentThread',\n    id: 'webapp-components-comment-inlinecommentthread',\n    parent: 'webapp-components-comment',\n    depth: 2,\n    children: [\n      'webapp-components-comment-inlinecommentthread--active-logged-out',\n      'webapp-components-comment-inlinecommentthread--active',\n      'webapp-components-comment-inlinecommentthread--active-non-owner',\n      'webapp-components-comment-inlinecommentthread--resolved-logged-out',\n      'webapp-components-comment-inlinecommentthread--resolved',\n      'webapp-components-comment-inlinecommentthread--header-not-commentable',\n      'webapp-components-comment-inlinecommentthread--header-resolved-owner',\n      'webapp-components-comment-inlinecommentthread--header-resolved-non-owner',\n      'webapp-components-comment-inlinecommentthread--header-resolved-logged-out',\n      'webapp-components-comment-inlinecommentthread--header-active-owner',\n      'webapp-components-comment-inlinecommentthread--header-active-non-owner',\n      'webapp-components-comment-inlinecommentthread--collapsed',\n      'webapp-components-comment-inlinecommentthread--collapsed-mutating',\n      'webapp-components-comment-inlinecommentthread--collapsed-mutating-logged-out',\n    ],\n    type: 'component',\n  },\n  'webapp-components-comment-inlinecommentthread--active-logged-out': {\n    id: 'webapp-components-comment-inlinecommentthread--active-logged-out',\n    title: 'Webapp components/Comment/InlineCommentThread',\n    name: 'active, logged out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-inlinecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-inlinecommentthread--active': {\n    id: 'webapp-components-comment-inlinecommentthread--active',\n    title: 'Webapp components/Comment/InlineCommentThread',\n    name: 'active',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-inlinecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-inlinecommentthread--active-non-owner': {\n    id: 'webapp-components-comment-inlinecommentthread--active-non-owner',\n    title: 'Webapp components/Comment/InlineCommentThread',\n    name: 'active, non-owner',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-inlinecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-inlinecommentthread--resolved-logged-out': {\n    id: 'webapp-components-comment-inlinecommentthread--resolved-logged-out',\n    title: 'Webapp components/Comment/InlineCommentThread',\n    name: 'resolved, logged out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-inlinecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-inlinecommentthread--resolved': {\n    id: 'webapp-components-comment-inlinecommentthread--resolved',\n    title: 'Webapp components/Comment/InlineCommentThread',\n    name: 'resolved',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-inlinecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-inlinecommentthread--header-not-commentable': {\n    id: 'webapp-components-comment-inlinecommentthread--header-not-commentable',\n    title: 'Webapp components/Comment/InlineCommentThread',\n    name: 'header, not-commentable',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-inlinecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-inlinecommentthread--header-resolved-owner': {\n    id: 'webapp-components-comment-inlinecommentthread--header-resolved-owner',\n    title: 'Webapp components/Comment/InlineCommentThread',\n    name: 'header, resolved, owner',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-inlinecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-inlinecommentthread--header-resolved-non-owner': {\n    id: 'webapp-components-comment-inlinecommentthread--header-resolved-non-owner',\n    title: 'Webapp components/Comment/InlineCommentThread',\n    name: 'header, resolved, non-owner',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-inlinecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-inlinecommentthread--header-resolved-logged-out': {\n    id: 'webapp-components-comment-inlinecommentthread--header-resolved-logged-out',\n    title: 'Webapp components/Comment/InlineCommentThread',\n    name: 'header, resolved, logged out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-inlinecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-inlinecommentthread--header-active-owner': {\n    id: 'webapp-components-comment-inlinecommentthread--header-active-owner',\n    title: 'Webapp components/Comment/InlineCommentThread',\n    name: 'header, active, owner',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-inlinecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-inlinecommentthread--header-active-non-owner': {\n    id: 'webapp-components-comment-inlinecommentthread--header-active-non-owner',\n    title: 'Webapp components/Comment/InlineCommentThread',\n    name: 'header, active, non-owner',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-inlinecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-inlinecommentthread--collapsed': {\n    id: 'webapp-components-comment-inlinecommentthread--collapsed',\n    title: 'Webapp components/Comment/InlineCommentThread',\n    name: 'collapsed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-inlinecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-inlinecommentthread--collapsed-mutating': {\n    id: 'webapp-components-comment-inlinecommentthread--collapsed-mutating',\n    title: 'Webapp components/Comment/InlineCommentThread',\n    name: 'collapsed, mutating',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-inlinecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-inlinecommentthread--collapsed-mutating-logged-out': {\n    id: 'webapp-components-comment-inlinecommentthread--collapsed-mutating-logged-out',\n    title: 'Webapp components/Comment/InlineCommentThread',\n    name: 'collapsed, mutating, logged out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-inlinecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-replytocomment': {\n    name: 'ReplyToComment',\n    id: 'webapp-components-comment-replytocomment',\n    parent: 'webapp-components-comment',\n    depth: 2,\n    children: [\n      'webapp-components-comment-replytocomment--base',\n      'webapp-components-comment-replytocomment--initial-value',\n      'webapp-components-comment-replytocomment--base-with-form-open',\n      'webapp-components-comment-replytocomment--form-pure-with-value',\n      'webapp-components-comment-replytocomment--form-pure-with-error',\n    ],\n    type: 'component',\n  },\n  'webapp-components-comment-replytocomment--base': {\n    id: 'webapp-components-comment-replytocomment--base',\n    title: 'Webapp components/Comment/ReplyToComment',\n    name: 'base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-replytocomment',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-replytocomment--initial-value': {\n    id: 'webapp-components-comment-replytocomment--initial-value',\n    title: 'Webapp components/Comment/ReplyToComment',\n    name: 'Initial Value',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-replytocomment',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-replytocomment--base-with-form-open': {\n    id: 'webapp-components-comment-replytocomment--base-with-form-open',\n    title: 'Webapp components/Comment/ReplyToComment',\n    name: 'base, with form open',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-replytocomment',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-replytocomment--form-pure-with-value': {\n    id: 'webapp-components-comment-replytocomment--form-pure-with-value',\n    title: 'Webapp components/Comment/ReplyToComment',\n    name: 'form, pure, with value',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-replytocomment',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-replytocomment--form-pure-with-error': {\n    id: 'webapp-components-comment-replytocomment--form-pure-with-error',\n    title: 'Webapp components/Comment/ReplyToComment',\n    name: 'form, pure, with error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-replytocomment',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-resolvecommentthreadbutton': {\n    name: 'ResolveCommentThreadButton',\n    id: 'webapp-components-comment-resolvecommentthreadbutton',\n    parent: 'webapp-components-comment',\n    depth: 2,\n    children: [\n      'webapp-components-comment-resolvecommentthreadbutton--base',\n      'webapp-components-comment-resolvecommentthreadbutton--with-text',\n    ],\n    type: 'component',\n  },\n  'webapp-components-comment-resolvecommentthreadbutton--base': {\n    id: 'webapp-components-comment-resolvecommentthreadbutton--base',\n    title: 'Webapp components/Comment/ResolveCommentThreadButton',\n    name: 'base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-resolvecommentthreadbutton',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-resolvecommentthreadbutton--with-text': {\n    id: 'webapp-components-comment-resolvecommentthreadbutton--with-text',\n    title: 'Webapp components/Comment/ResolveCommentThreadButton',\n    name: 'with text',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-resolvecommentthreadbutton',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-undoresolvecommentthreadbutton': {\n    name: 'UndoResolveCommentThreadButton',\n    id: 'webapp-components-comment-undoresolvecommentthreadbutton',\n    parent: 'webapp-components-comment',\n    depth: 2,\n    children: [\n      'webapp-components-comment-undoresolvecommentthreadbutton--can-undo-large',\n      'webapp-components-comment-undoresolvecommentthreadbutton--can-undo-loading-large',\n      'webapp-components-comment-undoresolvecommentthreadbutton--cannot-undo-large',\n      'webapp-components-comment-undoresolvecommentthreadbutton--can-undo-small',\n      'webapp-components-comment-undoresolvecommentthreadbutton--cannot-undo-small',\n    ],\n    type: 'component',\n  },\n  'webapp-components-comment-undoresolvecommentthreadbutton--can-undo-large': {\n    id: 'webapp-components-comment-undoresolvecommentthreadbutton--can-undo-large',\n    title: 'Webapp components/Comment/UndoResolveCommentThreadButton',\n    name: 'can undo, large',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-undoresolvecommentthreadbutton',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-undoresolvecommentthreadbutton--can-undo-loading-large': {\n    id: 'webapp-components-comment-undoresolvecommentthreadbutton--can-undo-loading-large',\n    title: 'Webapp components/Comment/UndoResolveCommentThreadButton',\n    name: 'can undo, loading, large',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-undoresolvecommentthreadbutton',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-undoresolvecommentthreadbutton--cannot-undo-large': {\n    id: 'webapp-components-comment-undoresolvecommentthreadbutton--cannot-undo-large',\n    title: 'Webapp components/Comment/UndoResolveCommentThreadButton',\n    name: 'cannot undo, large',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-undoresolvecommentthreadbutton',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-undoresolvecommentthreadbutton--can-undo-small': {\n    id: 'webapp-components-comment-undoresolvecommentthreadbutton--can-undo-small',\n    title: 'Webapp components/Comment/UndoResolveCommentThreadButton',\n    name: 'can undo, small',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-undoresolvecommentthreadbutton',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-comment-undoresolvecommentthreadbutton--cannot-undo-small': {\n    id: 'webapp-components-comment-undoresolvecommentthreadbutton--cannot-undo-small',\n    title: 'Webapp components/Comment/UndoResolveCommentThreadButton',\n    name: 'cannot undo, small',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-comment-undoresolvecommentthreadbutton',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentbranchlist': {\n    name: 'ComponentBranchList',\n    id: 'webapp-components-componentbranchlist',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-componentbranchlist--master',\n      'webapp-components-componentbranchlist--feature',\n    ],\n    type: 'component',\n  },\n  'webapp-components-componentbranchlist--master': {\n    id: 'webapp-components-componentbranchlist--master',\n    title: 'Webapp components/ComponentBranchList',\n    name: 'master',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentbranchlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentbranchlist--feature': {\n    id: 'webapp-components-componentbranchlist--feature',\n    title: 'Webapp components/ComponentBranchList',\n    name: 'feature',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentbranchlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentbuildlist': {\n    name: 'ComponentBuildList',\n    id: 'webapp-components-componentbuildlist',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-componentbuildlist--latest',\n      'webapp-components-componentbuildlist--historical',\n    ],\n    type: 'component',\n  },\n  'webapp-components-componentbuildlist--latest': {\n    id: 'webapp-components-componentbuildlist--latest',\n    title: 'Webapp components/ComponentBuildList',\n    name: 'latest',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentbuildlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentbuildlist--historical': {\n    id: 'webapp-components-componentbuildlist--historical',\n    title: 'Webapp components/ComponentBuildList',\n    name: 'historical',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentbuildlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentbuildspicker': {\n    name: 'ComponentBuildsPicker',\n    id: 'webapp-components-componentbuildspicker',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-componentbuildspicker--loading',\n      'webapp-components-componentbuildspicker--interactive',\n      'webapp-components-componentbuildspicker--feature-selected',\n      'webapp-components-componentbuildspicker--hide-branches',\n    ],\n    type: 'component',\n  },\n  'webapp-components-componentbuildspicker--loading': {\n    id: 'webapp-components-componentbuildspicker--loading',\n    title: 'Webapp components/ComponentBuildsPicker',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentbuildspicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentbuildspicker--interactive': {\n    id: 'webapp-components-componentbuildspicker--interactive',\n    title: 'Webapp components/ComponentBuildsPicker',\n    name: 'interactive',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentbuildspicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentbuildspicker--feature-selected': {\n    id: 'webapp-components-componentbuildspicker--feature-selected',\n    title: 'Webapp components/ComponentBuildsPicker',\n    name: 'feature selected',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentbuildspicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentbuildspicker--hide-branches': {\n    id: 'webapp-components-componentbuildspicker--hide-branches',\n    title: 'Webapp components/ComponentBuildsPicker',\n    name: 'hide branches',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentbuildspicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentitem': {\n    name: 'ComponentItem',\n    id: 'webapp-components-componentitem',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-componentitem--all',\n      'webapp-components-componentitem--various-image-sizes',\n      'webapp-components-componentitem--loading',\n      'webapp-components-componentitem--in-progress',\n      'webapp-components-componentitem--errored',\n      'webapp-components-componentitem--no-capture',\n      'webapp-components-componentitem--first-run-using-baseline-images',\n      'webapp-components-componentitem--unchanged-using-baseline-images',\n      'webapp-components-componentitem--unchanged-not-using-baseline-images',\n    ],\n    type: 'component',\n  },\n  'webapp-components-componentitem--all': {\n    id: 'webapp-components-componentitem--all',\n    title: 'Webapp components/ComponentItem',\n    name: 'All',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentitem--various-image-sizes': {\n    id: 'webapp-components-componentitem--various-image-sizes',\n    title: 'Webapp components/ComponentItem',\n    name: 'Various Image Sizes',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentitem--loading': {\n    id: 'webapp-components-componentitem--loading',\n    title: 'Webapp components/ComponentItem',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentitem--in-progress': {\n    id: 'webapp-components-componentitem--in-progress',\n    title: 'Webapp components/ComponentItem',\n    name: 'In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentitem--errored': {\n    id: 'webapp-components-componentitem--errored',\n    title: 'Webapp components/ComponentItem',\n    name: 'Errored',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentitem--no-capture': {\n    id: 'webapp-components-componentitem--no-capture',\n    title: 'Webapp components/ComponentItem',\n    name: 'No Capture',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentitem--first-run-using-baseline-images': {\n    id: 'webapp-components-componentitem--first-run-using-baseline-images',\n    title: 'Webapp components/ComponentItem',\n    name: 'First Run Using Baseline Images',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentitem--unchanged-using-baseline-images': {\n    id: 'webapp-components-componentitem--unchanged-using-baseline-images',\n    title: 'Webapp components/ComponentItem',\n    name: 'Unchanged Using Baseline Images',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentitem--unchanged-not-using-baseline-images': {\n    id: 'webapp-components-componentitem--unchanged-not-using-baseline-images',\n    title: 'Webapp components/ComponentItem',\n    name: 'Unchanged Not Using Baseline Images',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentlist': {\n    name: 'ComponentList',\n    id: 'webapp-components-componentlist',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-componentlist--loading',\n      'webapp-components-componentlist--full',\n      'webapp-components-componentlist--empty',\n    ],\n    type: 'component',\n  },\n  'webapp-components-componentlist--loading': {\n    id: 'webapp-components-componentlist--loading',\n    title: 'Webapp components/ComponentList',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentlist--full': {\n    id: 'webapp-components-componentlist--full',\n    title: 'Webapp components/ComponentList',\n    name: 'full',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentlist--empty': {\n    id: 'webapp-components-componentlist--empty',\n    title: 'Webapp components/ComponentList',\n    name: 'empty',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentrepresentationimage': {\n    name: 'ComponentRepresentationImage',\n    id: 'webapp-components-componentrepresentationimage',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-componentrepresentationimage--all',\n      'webapp-components-componentrepresentationimage--various-image-sizes',\n      'webapp-components-componentrepresentationimage--in-progress',\n      'webapp-components-componentrepresentationimage--with-error',\n      'webapp-components-componentrepresentationimage--first-run-using-baseline-images',\n      'webapp-components-componentrepresentationimage--unchanged-using-baseline-images',\n      'webapp-components-componentrepresentationimage--unchanged-not-using-baseline-images',\n      'webapp-components-componentrepresentationimage--no-capture',\n      'webapp-components-componentrepresentationimage--image',\n      'webapp-components-componentrepresentationimage--long-name',\n    ],\n    type: 'component',\n  },\n  'webapp-components-componentrepresentationimage--all': {\n    id: 'webapp-components-componentrepresentationimage--all',\n    title: 'Webapp components/ComponentRepresentationImage',\n    name: 'all',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentrepresentationimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentrepresentationimage--various-image-sizes': {\n    id: 'webapp-components-componentrepresentationimage--various-image-sizes',\n    title: 'Webapp components/ComponentRepresentationImage',\n    name: 'various image sizes',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentrepresentationimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentrepresentationimage--in-progress': {\n    id: 'webapp-components-componentrepresentationimage--in-progress',\n    title: 'Webapp components/ComponentRepresentationImage',\n    name: 'in progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentrepresentationimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentrepresentationimage--with-error': {\n    id: 'webapp-components-componentrepresentationimage--with-error',\n    title: 'Webapp components/ComponentRepresentationImage',\n    name: 'with error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentrepresentationimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentrepresentationimage--first-run-using-baseline-images': {\n    id: 'webapp-components-componentrepresentationimage--first-run-using-baseline-images',\n    title: 'Webapp components/ComponentRepresentationImage',\n    name: 'first run, using baseline images',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentrepresentationimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentrepresentationimage--unchanged-using-baseline-images': {\n    id: 'webapp-components-componentrepresentationimage--unchanged-using-baseline-images',\n    title: 'Webapp components/ComponentRepresentationImage',\n    name: 'unchanged, using baseline images',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentrepresentationimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentrepresentationimage--unchanged-not-using-baseline-images': {\n    id: 'webapp-components-componentrepresentationimage--unchanged-not-using-baseline-images',\n    title: 'Webapp components/ComponentRepresentationImage',\n    name: 'unchanged, not using baseline images',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentrepresentationimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentrepresentationimage--no-capture': {\n    id: 'webapp-components-componentrepresentationimage--no-capture',\n    title: 'Webapp components/ComponentRepresentationImage',\n    name: 'no capture',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentrepresentationimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentrepresentationimage--image': {\n    id: 'webapp-components-componentrepresentationimage--image',\n    title: 'Webapp components/ComponentRepresentationImage',\n    name: 'image',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentrepresentationimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-componentrepresentationimage--long-name': {\n    id: 'webapp-components-componentrepresentationimage--long-name',\n    title: 'Webapp components/ComponentRepresentationImage',\n    name: 'long name',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-componentrepresentationimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-creditcardform': {\n    name: 'CreditCardForm',\n    id: 'webapp-components-creditcardform',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-creditcardform--default',\n      'webapp-components-creditcardform--default-billing-fails',\n      'webapp-components-creditcardform--pure-submitting',\n      'webapp-components-creditcardform--pure-errored',\n      'webapp-components-creditcardform--with-billing-email',\n      'webapp-components-creditcardform--custom-label-and-cta',\n    ],\n    type: 'component',\n  },\n  'webapp-components-creditcardform--default': {\n    id: 'webapp-components-creditcardform--default',\n    title: 'Webapp components/CreditCardForm',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-creditcardform',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-creditcardform--default-billing-fails': {\n    id: 'webapp-components-creditcardform--default-billing-fails',\n    title: 'Webapp components/CreditCardForm',\n    name: 'default, billing fails',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-creditcardform',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-creditcardform--pure-submitting': {\n    id: 'webapp-components-creditcardform--pure-submitting',\n    title: 'Webapp components/CreditCardForm',\n    name: 'pure, submitting',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-creditcardform',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-creditcardform--pure-errored': {\n    id: 'webapp-components-creditcardform--pure-errored',\n    title: 'Webapp components/CreditCardForm',\n    name: 'pure, errored',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-creditcardform',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-creditcardform--with-billing-email': {\n    id: 'webapp-components-creditcardform--with-billing-email',\n    title: 'Webapp components/CreditCardForm',\n    name: 'with billing email',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-creditcardform',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-creditcardform--custom-label-and-cta': {\n    id: 'webapp-components-creditcardform--custom-label-and-cta',\n    title: 'Webapp components/CreditCardForm',\n    name: 'custom label and cta',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-creditcardform',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-dateformatter': {\n    name: 'DateFormatter',\n    id: 'webapp-components-dateformatter',\n    parent: 'webapp-components',\n    depth: 1,\n    children: ['webapp-components-dateformatter--all-dates'],\n    type: 'component',\n  },\n  'webapp-components-dateformatter--all-dates': {\n    id: 'webapp-components-dateformatter--all-dates',\n    title: 'Webapp components/DateFormatter',\n    name: 'all dates',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-dateformatter',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-diffimage': {\n    name: 'DiffImage',\n    id: 'webapp-components-diffimage',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-diffimage--default',\n      'webapp-components-diffimage--loading',\n      'webapp-components-diffimage--with-diff',\n      'webapp-components-diffimage--with-strobe-diff',\n      'webapp-components-diffimage--with-focus-diff',\n      'webapp-components-diffimage--with-focus-strobe-diff',\n      'webapp-components-diffimage--with-bigger-diff',\n      'webapp-components-diffimage--with-horizontally-bigger-diff',\n      'webapp-components-diffimage--with-vertically-bigger-diff',\n      'webapp-components-diffimage--responsive',\n      'webapp-components-diffimage--responsive-centered',\n      'webapp-components-diffimage--with-scaled-diff',\n      'webapp-components-diffimage--with-scaled-overflow-diff',\n      'webapp-components-diffimage--with-link',\n      'webapp-components-diffimage--with-link-wrapper',\n    ],\n    type: 'component',\n  },\n  'webapp-components-diffimage--default': {\n    id: 'webapp-components-diffimage--default',\n    title: 'Webapp components/DiffImage',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-diffimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-diffimage--loading': {\n    id: 'webapp-components-diffimage--loading',\n    title: 'Webapp components/DiffImage',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-diffimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-diffimage--with-diff': {\n    id: 'webapp-components-diffimage--with-diff',\n    title: 'Webapp components/DiffImage',\n    name: 'with diff',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-diffimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-diffimage--with-strobe-diff': {\n    id: 'webapp-components-diffimage--with-strobe-diff',\n    title: 'Webapp components/DiffImage',\n    name: 'with strobe diff',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-diffimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-diffimage--with-focus-diff': {\n    id: 'webapp-components-diffimage--with-focus-diff',\n    title: 'Webapp components/DiffImage',\n    name: 'with focus diff',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-diffimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-diffimage--with-focus-strobe-diff': {\n    id: 'webapp-components-diffimage--with-focus-strobe-diff',\n    title: 'Webapp components/DiffImage',\n    name: 'with focus+strobe diff',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-diffimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-diffimage--with-bigger-diff': {\n    id: 'webapp-components-diffimage--with-bigger-diff',\n    title: 'Webapp components/DiffImage',\n    name: 'with bigger diff',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-diffimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-diffimage--with-horizontally-bigger-diff': {\n    id: 'webapp-components-diffimage--with-horizontally-bigger-diff',\n    title: 'Webapp components/DiffImage',\n    name: 'with horizontally bigger diff',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-diffimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-diffimage--with-vertically-bigger-diff': {\n    id: 'webapp-components-diffimage--with-vertically-bigger-diff',\n    title: 'Webapp components/DiffImage',\n    name: 'with vertically bigger diff',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-diffimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-diffimage--responsive': {\n    id: 'webapp-components-diffimage--responsive',\n    title: 'Webapp components/DiffImage',\n    name: 'responsive',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-diffimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-diffimage--responsive-centered': {\n    id: 'webapp-components-diffimage--responsive-centered',\n    title: 'Webapp components/DiffImage',\n    name: 'responsive, centered',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-diffimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-diffimage--with-scaled-diff': {\n    id: 'webapp-components-diffimage--with-scaled-diff',\n    title: 'Webapp components/DiffImage',\n    name: 'with scaled diff',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-diffimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-diffimage--with-scaled-overflow-diff': {\n    id: 'webapp-components-diffimage--with-scaled-overflow-diff',\n    title: 'Webapp components/DiffImage',\n    name: 'with scaled overflow diff',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-diffimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-diffimage--with-link': {\n    id: 'webapp-components-diffimage--with-link',\n    title: 'Webapp components/DiffImage',\n    name: 'with link',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-diffimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-diffimage--with-link-wrapper': {\n    id: 'webapp-components-diffimage--with-link-wrapper',\n    title: 'Webapp components/DiffImage',\n    name: 'with link wrapper',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-diffimage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-difftoggles': {\n    name: 'DiffToggles',\n    id: 'webapp-components-difftoggles',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-difftoggles--no-diff',\n      'webapp-components-difftoggles--diff',\n      'webapp-components-difftoggles--diff-strobe',\n      'webapp-components-difftoggles--diff-focus',\n      'webapp-components-difftoggles--diff-focus-strobe',\n    ],\n    type: 'component',\n  },\n  'webapp-components-difftoggles--no-diff': {\n    id: 'webapp-components-difftoggles--no-diff',\n    title: 'Webapp components/DiffToggles',\n    name: 'no diff',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-difftoggles',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-difftoggles--diff': {\n    id: 'webapp-components-difftoggles--diff',\n    title: 'Webapp components/DiffToggles',\n    name: 'diff',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-difftoggles',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-difftoggles--diff-strobe': {\n    id: 'webapp-components-difftoggles--diff-strobe',\n    title: 'Webapp components/DiffToggles',\n    name: 'diff strobe',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-difftoggles',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-difftoggles--diff-focus': {\n    id: 'webapp-components-difftoggles--diff-focus',\n    title: 'Webapp components/DiffToggles',\n    name: 'diff focus',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-difftoggles',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-difftoggles--diff-focus-strobe': {\n    id: 'webapp-components-difftoggles--diff-focus-strobe',\n    title: 'Webapp components/DiffToggles',\n    name: 'diff focus+strobe',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-difftoggles',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-emptymessage': {\n    name: 'EmptyMessage',\n    id: 'webapp-components-emptymessage',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-emptymessage--all-messages',\n      'webapp-components-emptymessage--default',\n      'webapp-components-emptymessage--custom',\n      'webapp-components-emptymessage--custom-noun',\n    ],\n    type: 'component',\n  },\n  'webapp-components-emptymessage--all-messages': {\n    id: 'webapp-components-emptymessage--all-messages',\n    title: 'Webapp components/EmptyMessage',\n    name: 'all messages',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-emptymessage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-emptymessage--default': {\n    id: 'webapp-components-emptymessage--default',\n    title: 'Webapp components/EmptyMessage',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-emptymessage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-emptymessage--custom': {\n    id: 'webapp-components-emptymessage--custom',\n    title: 'Webapp components/EmptyMessage',\n    name: 'custom',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-emptymessage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-emptymessage--custom-noun': {\n    id: 'webapp-components-emptymessage--custom-noun',\n    title: 'Webapp components/EmptyMessage',\n    name: 'custom noun',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-emptymessage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-eyebrow': {\n    name: 'Eyebrow',\n    id: 'webapp-components-eyebrow',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-eyebrow--default',\n      'webapp-components-eyebrow--positive',\n      'webapp-components-eyebrow--warning',\n      'webapp-components-eyebrow--negative',\n    ],\n    type: 'component',\n  },\n  'webapp-components-eyebrow--default': {\n    id: 'webapp-components-eyebrow--default',\n    title: 'Webapp components/Eyebrow',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-eyebrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-eyebrow--positive': {\n    id: 'webapp-components-eyebrow--positive',\n    title: 'Webapp components/Eyebrow',\n    name: 'Positive',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-eyebrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-eyebrow--warning': {\n    id: 'webapp-components-eyebrow--warning',\n    title: 'Webapp components/Eyebrow',\n    name: 'Warning',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-eyebrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-eyebrow--negative': {\n    id: 'webapp-components-eyebrow--negative',\n    title: 'Webapp components/Eyebrow',\n    name: 'Negative',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-eyebrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-eyebrowonboarding': {\n    name: 'EyebrowOnboarding',\n    id: 'webapp-components-eyebrowonboarding',\n    parent: 'webapp-components',\n    depth: 1,\n    children: ['webapp-components-eyebrowonboarding--default'],\n    type: 'component',\n  },\n  'webapp-components-eyebrowonboarding--default': {\n    id: 'webapp-components-eyebrowonboarding--default',\n    title: 'Webapp components/EyebrowOnboarding',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-eyebrowonboarding',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-flexcenter': {\n    name: 'FlexCenter',\n    id: 'webapp-components-flexcenter',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-flexcenter--21',\n      'webapp-components-flexcenter--22',\n      'webapp-components-flexcenter--23',\n    ],\n    type: 'component',\n  },\n  'webapp-components-flexcenter--21': {\n    id: 'webapp-components-flexcenter--21',\n    title: 'Webapp components/FlexCenter',\n    name: '2:1',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-flexcenter',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-flexcenter--22': {\n    id: 'webapp-components-flexcenter--22',\n    title: 'Webapp components/FlexCenter',\n    name: '2:2',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-flexcenter',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-flexcenter--23': {\n    id: 'webapp-components-flexcenter--23',\n    title: 'Webapp components/FlexCenter',\n    name: '2:3',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-flexcenter',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-form': {\n    name: 'Form',\n    id: 'webapp-components-form',\n    parent: 'webapp-components',\n    depth: 1,\n    children: ['webapp-components-form--all-inputs'],\n    type: 'component',\n  },\n  'webapp-components-form--all-inputs': {\n    id: 'webapp-components-form--all-inputs',\n    title: 'Webapp components/Form',\n    name: 'all inputs',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-form',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-header': {\n    name: 'Header',\n    id: 'webapp-components-header',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-header--loading',\n      'webapp-components-header--logged-in-app',\n      'webapp-components-header--logged-in-app-saml-user',\n      'webapp-components-header--logged-in-app-shared-with-you',\n      'webapp-components-header--logged-in-app-shared-with-admin',\n      'webapp-components-header--logged-in-app-shared-with-you-open-source',\n      'webapp-components-header--logged-in-linked-account',\n      'webapp-components-header--logged-in-personal-account',\n      'webapp-components-header--logged-in-shared-with-you-app-owner',\n      'webapp-components-header--logged-in-no-app-owner-or-app',\n      'webapp-components-header--logged-in-no-app-owner-onboarding',\n      'webapp-components-header--not-logged-in-can-login',\n      'webapp-components-header--not-logged-in-can-not-login',\n      'webapp-components-header--long-name',\n    ],\n    type: 'component',\n  },\n  'webapp-components-header--loading': {\n    id: 'webapp-components-header--loading',\n    title: 'Webapp components/Header',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-header',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-header--logged-in-app': {\n    id: 'webapp-components-header--logged-in-app',\n    title: 'Webapp components/Header',\n    name: 'Logged in, app',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-header',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-header--logged-in-app-saml-user': {\n    id: 'webapp-components-header--logged-in-app-saml-user',\n    title: 'Webapp components/Header',\n    name: 'Logged in, app, saml user',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-header',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-header--logged-in-app-shared-with-you': {\n    id: 'webapp-components-header--logged-in-app-shared-with-you',\n    title: 'Webapp components/Header',\n    name: 'Logged in, app, shared with you',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-header',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-header--logged-in-app-shared-with-admin': {\n    id: 'webapp-components-header--logged-in-app-shared-with-admin',\n    title: 'Webapp components/Header',\n    name: 'Logged in, app, shared with admin',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-header',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-header--logged-in-app-shared-with-you-open-source': {\n    id: 'webapp-components-header--logged-in-app-shared-with-you-open-source',\n    title: 'Webapp components/Header',\n    name: 'Logged in, app, shared with you, open source',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-header',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-header--logged-in-linked-account': {\n    id: 'webapp-components-header--logged-in-linked-account',\n    title: 'Webapp components/Header',\n    name: 'Logged in, linked account',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-header',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-header--logged-in-personal-account': {\n    id: 'webapp-components-header--logged-in-personal-account',\n    title: 'Webapp components/Header',\n    name: 'Logged in, personal account',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-header',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-header--logged-in-shared-with-you-app-owner': {\n    id: 'webapp-components-header--logged-in-shared-with-you-app-owner',\n    title: 'Webapp components/Header',\n    name: 'Logged in, shared with you appOwner',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-header',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-header--logged-in-no-app-owner-or-app': {\n    id: 'webapp-components-header--logged-in-no-app-owner-or-app',\n    title: 'Webapp components/Header',\n    name: 'Logged in no appOwner or app',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-header',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-header--logged-in-no-app-owner-onboarding': {\n    id: 'webapp-components-header--logged-in-no-app-owner-onboarding',\n    title: 'Webapp components/Header',\n    name: 'Logged in no appOwner (onboarding)',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-header',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-header--not-logged-in-can-login': {\n    id: 'webapp-components-header--not-logged-in-can-login',\n    title: 'Webapp components/Header',\n    name: 'Not logged in, can login',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-header',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-header--not-logged-in-can-not-login': {\n    id: 'webapp-components-header--not-logged-in-can-not-login',\n    title: 'Webapp components/Header',\n    name: 'Not logged in, can not login',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-header',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-header--long-name': {\n    id: 'webapp-components-header--long-name',\n    title: 'Webapp components/Header',\n    name: 'Long name',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-header',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-heading': {\n    name: 'Heading',\n    id: 'webapp-components-heading',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-heading--loading',\n      'webapp-components-heading--default',\n      'webapp-components-heading--no-subtitle',\n    ],\n    type: 'component',\n  },\n  'webapp-components-heading--loading': {\n    id: 'webapp-components-heading--loading',\n    title: 'Webapp components/Heading',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-heading',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-heading--default': {\n    id: 'webapp-components-heading--default',\n    title: 'Webapp components/Heading',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-heading',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-heading--no-subtitle': {\n    id: 'webapp-components-heading--no-subtitle',\n    title: 'Webapp components/Heading',\n    name: 'no subtitle',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-heading',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-ignoredregions': {\n    name: 'IgnoredRegions',\n    id: 'webapp-components-ignoredregions',\n    parent: 'webapp-components',\n    depth: 1,\n    children: ['webapp-components-ignoredregions--basic'],\n    type: 'component',\n  },\n  'webapp-components-ignoredregions--basic': {\n    id: 'webapp-components-ignoredregions--basic',\n    title: 'Webapp components/IgnoredRegions',\n    name: 'basic',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-ignoredregions',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-imagetile': {\n    name: 'ImageTile',\n    id: 'webapp-components-imagetile',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-imagetile--loading',\n      'webapp-components-imagetile--default',\n      'webapp-components-imagetile--long-text',\n      'webapp-components-imagetile--no-label',\n      'webapp-components-imagetile--no-description',\n      'webapp-components-imagetile--as-link',\n      'webapp-components-imagetile--as-button',\n      'webapp-components-imagetile--with-image',\n      'webapp-components-imagetile--with-background',\n      'webapp-components-imagetile--with-border',\n    ],\n    type: 'component',\n  },\n  'webapp-components-imagetile--loading': {\n    id: 'webapp-components-imagetile--loading',\n    title: 'Webapp components/ImageTile',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-imagetile',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-imagetile--default': {\n    id: 'webapp-components-imagetile--default',\n    title: 'Webapp components/ImageTile',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-imagetile',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-imagetile--long-text': {\n    id: 'webapp-components-imagetile--long-text',\n    title: 'Webapp components/ImageTile',\n    name: 'Long Text',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-imagetile',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-imagetile--no-label': {\n    id: 'webapp-components-imagetile--no-label',\n    title: 'Webapp components/ImageTile',\n    name: 'No Label',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-imagetile',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-imagetile--no-description': {\n    id: 'webapp-components-imagetile--no-description',\n    title: 'Webapp components/ImageTile',\n    name: 'No Description',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-imagetile',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-imagetile--as-link': {\n    id: 'webapp-components-imagetile--as-link',\n    title: 'Webapp components/ImageTile',\n    name: 'As Link',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-imagetile',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-imagetile--as-button': {\n    id: 'webapp-components-imagetile--as-button',\n    title: 'Webapp components/ImageTile',\n    name: 'As Button',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-imagetile',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-imagetile--with-image': {\n    id: 'webapp-components-imagetile--with-image',\n    title: 'Webapp components/ImageTile',\n    name: 'With Image',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-imagetile',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-imagetile--with-background': {\n    id: 'webapp-components-imagetile--with-background',\n    title: 'Webapp components/ImageTile',\n    name: 'With Background',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-imagetile',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-imagetile--with-border': {\n    id: 'webapp-components-imagetile--with-border',\n    title: 'Webapp components/ImageTile',\n    name: 'With Border',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-imagetile',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-interstitial': {\n    name: 'Interstitial',\n    id: 'webapp-components-interstitial',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-interstitial--dots',\n      'webapp-components-interstitial--bar',\n      'webapp-components-interstitial--ring',\n      'webapp-components-interstitial--icon',\n    ],\n    type: 'component',\n  },\n  'webapp-components-interstitial--dots': {\n    id: 'webapp-components-interstitial--dots',\n    title: 'Webapp components/Interstitial',\n    name: 'Dots',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-interstitial',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-interstitial--bar': {\n    id: 'webapp-components-interstitial--bar',\n    title: 'Webapp components/Interstitial',\n    name: 'Bar',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-interstitial',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-interstitial--ring': {\n    id: 'webapp-components-interstitial--ring',\n    title: 'Webapp components/Interstitial',\n    name: 'Ring',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-interstitial',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-interstitial--icon': {\n    id: 'webapp-components-interstitial--icon',\n    title: 'Webapp components/Interstitial',\n    name: 'Icon',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-interstitial',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-inviteeyebrow': {\n    name: 'InviteEyebrow',\n    id: 'webapp-components-inviteeyebrow',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-inviteeyebrow--unlinked',\n      'webapp-components-inviteeyebrow--linked',\n    ],\n    type: 'component',\n  },\n  'webapp-components-inviteeyebrow--unlinked': {\n    id: 'webapp-components-inviteeyebrow--unlinked',\n    title: 'Webapp components/InviteEyebrow',\n    name: 'Unlinked',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-inviteeyebrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-inviteeyebrow--linked': {\n    id: 'webapp-components-inviteeyebrow--linked',\n    title: 'Webapp components/InviteEyebrow',\n    name: 'Linked',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-inviteeyebrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-isactiveelement': {\n    name: 'IsActiveElement',\n    id: 'webapp-components-isactiveelement',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-isactiveelement--active',\n      'webapp-components-isactiveelement--not-active',\n    ],\n    type: 'component',\n  },\n  'webapp-components-isactiveelement--active': {\n    id: 'webapp-components-isactiveelement--active',\n    title: 'Webapp components/IsActiveElement',\n    name: 'active',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-isactiveelement',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-isactiveelement--not-active': {\n    id: 'webapp-components-isactiveelement--not-active',\n    title: 'Webapp components/IsActiveElement',\n    name: 'not active',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-isactiveelement',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-isolatorframe': {\n    name: 'IsolatorFrame',\n    id: 'webapp-components-isolatorframe',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-isolatorframe--fail-to-connect',\n      'webapp-components-isolatorframe--hidden',\n      'webapp-components-isolatorframe--storybook-34',\n      'webapp-components-isolatorframe--storybook-40',\n      'webapp-components-isolatorframe--storybook-5',\n      'webapp-components-isolatorframe--storybook-5-legacy-package',\n      'webapp-components-isolatorframe--storybook-5-error',\n      'webapp-components-isolatorframe--storybook-6',\n      'webapp-components-isolatorframe--invalid-spec',\n    ],\n    type: 'component',\n  },\n  'webapp-components-isolatorframe--fail-to-connect': {\n    id: 'webapp-components-isolatorframe--fail-to-connect',\n    title: 'Webapp components/IsolatorFrame',\n    name: 'fail to connect',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-isolatorframe',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-isolatorframe--hidden': {\n    id: 'webapp-components-isolatorframe--hidden',\n    title: 'Webapp components/IsolatorFrame',\n    name: 'hidden',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-isolatorframe',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-isolatorframe--storybook-34': {\n    id: 'webapp-components-isolatorframe--storybook-34',\n    title: 'Webapp components/IsolatorFrame',\n    name: 'Storybook 3.4',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-isolatorframe',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-isolatorframe--storybook-40': {\n    id: 'webapp-components-isolatorframe--storybook-40',\n    title: 'Webapp components/IsolatorFrame',\n    name: 'Storybook 4.0',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-isolatorframe',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-isolatorframe--storybook-5': {\n    id: 'webapp-components-isolatorframe--storybook-5',\n    title: 'Webapp components/IsolatorFrame',\n    name: 'Storybook 5',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-isolatorframe',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-isolatorframe--storybook-5-legacy-package': {\n    id: 'webapp-components-isolatorframe--storybook-5-legacy-package',\n    title: 'Webapp components/IsolatorFrame',\n    name: 'Storybook 5, legacy package',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-isolatorframe',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-isolatorframe--storybook-5-error': {\n    id: 'webapp-components-isolatorframe--storybook-5-error',\n    title: 'Webapp components/IsolatorFrame',\n    name: 'Storybook 5, error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-isolatorframe',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-isolatorframe--storybook-6': {\n    id: 'webapp-components-isolatorframe--storybook-6',\n    title: 'Webapp components/IsolatorFrame',\n    name: 'Storybook 6',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-isolatorframe',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-isolatorframe--invalid-spec': {\n    id: 'webapp-components-isolatorframe--invalid-spec',\n    title: 'Webapp components/IsolatorFrame',\n    name: 'invalid spec',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-isolatorframe',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-linklist': {\n    name: 'LinkList',\n    id: 'webapp-components-linklist',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-linklist--all-link-lists',\n      'webapp-components-linklist--loading',\n      'webapp-components-linklist--full',\n      'webapp-components-linklist--paginated',\n      'webapp-components-linklist--empty-w-custom-noun',\n      'webapp-components-linklist--empty',\n    ],\n    type: 'component',\n  },\n  'webapp-components-linklist--all-link-lists': {\n    id: 'webapp-components-linklist--all-link-lists',\n    title: 'Webapp components/LinkList',\n    name: 'All LinkLists',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-linklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-linklist--loading': {\n    id: 'webapp-components-linklist--loading',\n    title: 'Webapp components/LinkList',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-linklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-linklist--full': {\n    id: 'webapp-components-linklist--full',\n    title: 'Webapp components/LinkList',\n    name: 'full',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-linklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-linklist--paginated': {\n    id: 'webapp-components-linklist--paginated',\n    title: 'Webapp components/LinkList',\n    name: 'paginated',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-linklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-linklist--empty-w-custom-noun': {\n    id: 'webapp-components-linklist--empty-w-custom-noun',\n    title: 'Webapp components/LinkList',\n    name: 'empty w/custom noun',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-linklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-linklist--empty': {\n    id: 'webapp-components-linklist--empty',\n    title: 'Webapp components/LinkList',\n    name: 'empty',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-linklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-linktabs': {\n    name: 'LinkTabs',\n    id: 'webapp-components-linktabs',\n    parent: 'webapp-components',\n    depth: 1,\n    children: ['webapp-components-linktabs--default'],\n    type: 'component',\n  },\n  'webapp-components-linktabs--default': {\n    id: 'webapp-components-linktabs--default',\n    title: 'Webapp components/LinkTabs',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-linktabs',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-listheading': {\n    name: 'ListHeading',\n    id: 'webapp-components-listheading',\n    parent: 'webapp-components',\n    depth: 1,\n    children: ['webapp-components-listheading--all'],\n    type: 'component',\n  },\n  'webapp-components-listheading--all': {\n    id: 'webapp-components-listheading--all',\n    title: 'Webapp components/ListHeading',\n    name: 'all',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-listheading',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-liveview': {\n    name: 'LiveView',\n    id: 'webapp-components-liveview',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-liveview--storybook-5-preloading',\n      'webapp-components-liveview--storybook-34-preloading',\n      'webapp-components-liveview--storybook-40-preloading',\n      'webapp-components-liveview--storybook-5-visible',\n      'webapp-components-liveview--storybook-5-error-visible',\n      'webapp-components-liveview--storybook-34-visible',\n      'webapp-components-liveview--storybook-40-visible',\n      'webapp-components-liveview--pure-downloading',\n      'webapp-components-liveview--pure-connecting',\n      'webapp-components-liveview--pure-connected',\n      'webapp-components-liveview--staging',\n      'webapp-components-liveview--production',\n    ],\n    type: 'component',\n  },\n  'webapp-components-liveview--storybook-5-preloading': {\n    id: 'webapp-components-liveview--storybook-5-preloading',\n    title: 'Webapp components/LiveView',\n    name: 'Storybook 5, preloading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-liveview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-liveview--storybook-34-preloading': {\n    id: 'webapp-components-liveview--storybook-34-preloading',\n    title: 'Webapp components/LiveView',\n    name: 'Storybook 3.4, preloading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-liveview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-liveview--storybook-40-preloading': {\n    id: 'webapp-components-liveview--storybook-40-preloading',\n    title: 'Webapp components/LiveView',\n    name: 'Storybook 4.0, preloading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-liveview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-liveview--storybook-5-visible': {\n    id: 'webapp-components-liveview--storybook-5-visible',\n    title: 'Webapp components/LiveView',\n    name: 'Storybook 5, visible',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-liveview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-liveview--storybook-5-error-visible': {\n    id: 'webapp-components-liveview--storybook-5-error-visible',\n    title: 'Webapp components/LiveView',\n    name: 'Storybook 5, error, visible',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-liveview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-liveview--storybook-34-visible': {\n    id: 'webapp-components-liveview--storybook-34-visible',\n    title: 'Webapp components/LiveView',\n    name: 'Storybook 3.4, visible',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-liveview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-liveview--storybook-40-visible': {\n    id: 'webapp-components-liveview--storybook-40-visible',\n    title: 'Webapp components/LiveView',\n    name: 'Storybook 4.0, visible',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-liveview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-liveview--pure-downloading': {\n    id: 'webapp-components-liveview--pure-downloading',\n    title: 'Webapp components/LiveView',\n    name: 'pure, downloading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-liveview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-liveview--pure-connecting': {\n    id: 'webapp-components-liveview--pure-connecting',\n    title: 'Webapp components/LiveView',\n    name: 'pure, connecting',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-liveview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-liveview--pure-connected': {\n    id: 'webapp-components-liveview--pure-connected',\n    title: 'Webapp components/LiveView',\n    name: 'pure, connected',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-liveview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-liveview--staging': {\n    id: 'webapp-components-liveview--staging',\n    title: 'Webapp components/LiveView',\n    name: 'Staging',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-liveview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-liveview--production': {\n    id: 'webapp-components-liveview--production',\n    title: 'Webapp components/LiveView',\n    name: 'Production',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-liveview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-mailinglistsubscribeform': {\n    name: 'MailingListSubscribeForm',\n    id: 'webapp-components-mailinglistsubscribeform',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-mailinglistsubscribeform--basic',\n      'webapp-components-mailinglistsubscribeform--opt-in',\n    ],\n    type: 'component',\n  },\n  'webapp-components-mailinglistsubscribeform--basic': {\n    id: 'webapp-components-mailinglistsubscribeform--basic',\n    title: 'Webapp components/MailingListSubscribeForm',\n    name: 'basic',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-mailinglistsubscribeform',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-mailinglistsubscribeform--opt-in': {\n    id: 'webapp-components-mailinglistsubscribeform--opt-in',\n    title: 'Webapp components/MailingListSubscribeForm',\n    name: 'opt-in',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-mailinglistsubscribeform',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-newappform': {\n    name: 'NewAppForm',\n    id: 'webapp-components-newappform',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-newappform--default-personal',\n      'webapp-components-newappform--default-personal-creating',\n      'webapp-components-newappform--default-personal-unlinked',\n      'webapp-components-newappform--default-organization',\n      'webapp-components-newappform--default-github-failure',\n      'webapp-components-newappform--compact-personal-unlinked',\n    ],\n    type: 'component',\n  },\n  'webapp-components-newappform--default-personal': {\n    id: 'webapp-components-newappform--default-personal',\n    title: 'Webapp components/NewAppForm',\n    name: 'default, personal',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-newappform',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-newappform--default-personal-creating': {\n    id: 'webapp-components-newappform--default-personal-creating',\n    title: 'Webapp components/NewAppForm',\n    name: 'default, personal, creating',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-newappform',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-newappform--default-personal-unlinked': {\n    id: 'webapp-components-newappform--default-personal-unlinked',\n    title: 'Webapp components/NewAppForm',\n    name: 'default, personal, unlinked',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-newappform',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-newappform--default-organization': {\n    id: 'webapp-components-newappform--default-organization',\n    title: 'Webapp components/NewAppForm',\n    name: 'default, organization',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-newappform',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-newappform--default-github-failure': {\n    id: 'webapp-components-newappform--default-github-failure',\n    title: 'Webapp components/NewAppForm',\n    name: 'default, github, failure',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-newappform',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-newappform--compact-personal-unlinked': {\n    id: 'webapp-components-newappform--compact-personal-unlinked',\n    title: 'Webapp components/NewAppForm',\n    name: 'compact, personal, unlinked',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-newappform',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-notifications': {\n    name: 'Notifications',\n    id: 'webapp-components-notifications',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-notifications-notification',\n      'webapp-components-notifications-notifications',\n      'webapp-components-notifications-reviewsyncfailednotification',\n      'webapp-components-notifications-syncingnotification',\n    ],\n    type: 'group',\n  },\n  'webapp-components-notifications-notification': {\n    name: 'Notification',\n    id: 'webapp-components-notifications-notification',\n    parent: 'webapp-components-notifications',\n    depth: 2,\n    children: ['webapp-components-notifications-notification--notification'],\n    type: 'component',\n  },\n  'webapp-components-notifications-notification--notification': {\n    id: 'webapp-components-notifications-notification--notification',\n    title: 'Webapp components/Notifications/Notification',\n    name: 'notification',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-notifications-notification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-notifications-notifications': {\n    name: 'Notifications',\n    id: 'webapp-components-notifications-notifications',\n    parent: 'webapp-components-notifications',\n    depth: 2,\n    children: ['webapp-components-notifications-notifications--with-initial-notifications'],\n    type: 'component',\n  },\n  'webapp-components-notifications-notifications--with-initial-notifications': {\n    id: 'webapp-components-notifications-notifications--with-initial-notifications',\n    title: 'Webapp components/Notifications/Notifications',\n    name: 'with initial notifications',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-notifications-notifications',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-notifications-reviewsyncfailednotification': {\n    name: 'ReviewSyncFailedNotification',\n    id: 'webapp-components-notifications-reviewsyncfailednotification',\n    parent: 'webapp-components-notifications',\n    depth: 2,\n    children: ['webapp-components-notifications-reviewsyncfailednotification--notification'],\n    type: 'component',\n  },\n  'webapp-components-notifications-reviewsyncfailednotification--notification': {\n    id: 'webapp-components-notifications-reviewsyncfailednotification--notification',\n    title: 'Webapp components/Notifications/ReviewSyncFailedNotification',\n    name: 'notification',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-notifications-reviewsyncfailednotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-notifications-syncingnotification': {\n    name: 'SyncingNotification',\n    id: 'webapp-components-notifications-syncingnotification',\n    parent: 'webapp-components-notifications',\n    depth: 2,\n    children: ['webapp-components-notifications-syncingnotification--notification'],\n    type: 'component',\n  },\n  'webapp-components-notifications-syncingnotification--notification': {\n    id: 'webapp-components-notifications-syncingnotification--notification',\n    title: 'Webapp components/Notifications/SyncingNotification',\n    name: 'notification',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-components-notifications-syncingnotification',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pageheader': {\n    name: 'PageHeader',\n    id: 'webapp-components-pageheader',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-pageheader--default',\n      'webapp-components-pageheader--loading',\n      'webapp-components-pageheader--long',\n    ],\n    type: 'component',\n  },\n  'webapp-components-pageheader--default': {\n    id: 'webapp-components-pageheader--default',\n    title: 'Webapp components/PageHeader',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pageheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pageheader--loading': {\n    id: 'webapp-components-pageheader--loading',\n    title: 'Webapp components/PageHeader',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pageheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pageheader--long': {\n    id: 'webapp-components-pageheader--long',\n    title: 'Webapp components/PageHeader',\n    name: 'Long',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pageheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pagetitlebar': {\n    name: 'PageTitleBar',\n    id: 'webapp-components-pagetitlebar',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-pagetitlebar--loading',\n      'webapp-components-pagetitlebar--with-actions',\n      'webapp-components-pagetitlebar--with-children-and-actions',\n    ],\n    type: 'component',\n  },\n  'webapp-components-pagetitlebar--loading': {\n    id: 'webapp-components-pagetitlebar--loading',\n    title: 'Webapp components/PageTitleBar',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pagetitlebar',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pagetitlebar--with-actions': {\n    id: 'webapp-components-pagetitlebar--with-actions',\n    title: 'Webapp components/PageTitleBar',\n    name: 'with actions',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pagetitlebar',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pagetitlebar--with-children-and-actions': {\n    id: 'webapp-components-pagetitlebar--with-children-and-actions',\n    title: 'Webapp components/PageTitleBar',\n    name: 'with children and actions',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pagetitlebar',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pagination': {\n    name: 'Pagination',\n    id: 'webapp-components-pagination',\n    parent: 'webapp-components',\n    depth: 1,\n    children: ['webapp-components-pagination--back', 'webapp-components-pagination--next'],\n    type: 'component',\n  },\n  'webapp-components-pagination--back': {\n    id: 'webapp-components-pagination--back',\n    title: 'Webapp components/Pagination',\n    name: 'back',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pagination',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pagination--next': {\n    id: 'webapp-components-pagination--next',\n    title: 'Webapp components/Pagination',\n    name: 'next',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pagination',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-paymentcollectcta': {\n    name: 'PaymentCollectCTA',\n    id: 'webapp-components-paymentcollectcta',\n    parent: 'webapp-components',\n    depth: 1,\n    children: ['webapp-components-paymentcollectcta--account-upgrading'],\n    type: 'component',\n  },\n  'webapp-components-paymentcollectcta--account-upgrading': {\n    id: 'webapp-components-paymentcollectcta--account-upgrading',\n    title: 'Webapp components/PaymentCollectCTA',\n    name: 'account upgrading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-paymentcollectcta',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-paymentcollectmodal': {\n    name: 'PaymentCollectModal',\n    id: 'webapp-components-paymentcollectmodal',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-paymentcollectmodal--account-upgrading',\n      'webapp-components-paymentcollectmodal--pre-subscribed',\n      'webapp-components-paymentcollectmodal--exceeded-threshold',\n      'webapp-components-paymentcollectmodal--free',\n      'webapp-components-paymentcollectmodal--in-trial',\n      'webapp-components-paymentcollectmodal--trial-ending',\n      'webapp-components-paymentcollectmodal--payment-failed',\n      'webapp-components-paymentcollectmodal--payment-required',\n    ],\n    type: 'component',\n  },\n  'webapp-components-paymentcollectmodal--account-upgrading': {\n    id: 'webapp-components-paymentcollectmodal--account-upgrading',\n    title: 'Webapp components/PaymentCollectModal',\n    name: 'account upgrading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-paymentcollectmodal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-paymentcollectmodal--pre-subscribed': {\n    id: 'webapp-components-paymentcollectmodal--pre-subscribed',\n    title: 'Webapp components/PaymentCollectModal',\n    name: 'Pre Subscribed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-paymentcollectmodal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-paymentcollectmodal--exceeded-threshold': {\n    id: 'webapp-components-paymentcollectmodal--exceeded-threshold',\n    title: 'Webapp components/PaymentCollectModal',\n    name: 'Exceeded Threshold',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-paymentcollectmodal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-paymentcollectmodal--free': {\n    id: 'webapp-components-paymentcollectmodal--free',\n    title: 'Webapp components/PaymentCollectModal',\n    name: 'Free',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-paymentcollectmodal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-paymentcollectmodal--in-trial': {\n    id: 'webapp-components-paymentcollectmodal--in-trial',\n    title: 'Webapp components/PaymentCollectModal',\n    name: 'in trial',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-paymentcollectmodal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-paymentcollectmodal--trial-ending': {\n    id: 'webapp-components-paymentcollectmodal--trial-ending',\n    title: 'Webapp components/PaymentCollectModal',\n    name: 'trial ending',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-paymentcollectmodal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-paymentcollectmodal--payment-failed': {\n    id: 'webapp-components-paymentcollectmodal--payment-failed',\n    title: 'Webapp components/PaymentCollectModal',\n    name: 'payment failed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-paymentcollectmodal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-paymentcollectmodal--payment-required': {\n    id: 'webapp-components-paymentcollectmodal--payment-required',\n    title: 'Webapp components/PaymentCollectModal',\n    name: 'payment required',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-paymentcollectmodal',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-paymenteyebrow': {\n    name: 'PaymentEyebrow',\n    id: 'webapp-components-paymenteyebrow',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-paymenteyebrow--trial-ending',\n      'webapp-components-paymenteyebrow--payment-failed',\n      'webapp-components-paymenteyebrow--payment-required',\n      'webapp-components-paymenteyebrow--exceeded-threshold',\n    ],\n    type: 'component',\n  },\n  'webapp-components-paymenteyebrow--trial-ending': {\n    id: 'webapp-components-paymenteyebrow--trial-ending',\n    title: 'Webapp components/PaymentEyebrow',\n    name: 'trial ending',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-paymenteyebrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-paymenteyebrow--payment-failed': {\n    id: 'webapp-components-paymenteyebrow--payment-failed',\n    title: 'Webapp components/PaymentEyebrow',\n    name: 'payment failed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-paymenteyebrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-paymenteyebrow--payment-required': {\n    id: 'webapp-components-paymenteyebrow--payment-required',\n    title: 'Webapp components/PaymentEyebrow',\n    name: 'payment required',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-paymenteyebrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-paymenteyebrow--exceeded-threshold': {\n    id: 'webapp-components-paymenteyebrow--exceeded-threshold',\n    title: 'Webapp components/PaymentEyebrow',\n    name: 'exceeded threshold',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-paymenteyebrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-progressbar': {\n    name: 'ProgressBar',\n    id: 'webapp-components-progressbar',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-progressbar--loading',\n      'webapp-components-progressbar--short',\n      'webapp-components-progressbar--inprogress-25',\n      'webapp-components-progressbar--inprogress-50',\n      'webapp-components-progressbar--inprogress-tooltip',\n      'webapp-components-progressbar--reviewing-partial',\n      'webapp-components-progressbar--reviewing-complete',\n    ],\n    type: 'component',\n  },\n  'webapp-components-progressbar--loading': {\n    id: 'webapp-components-progressbar--loading',\n    title: 'Webapp components/ProgressBar',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-progressbar',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-progressbar--short': {\n    id: 'webapp-components-progressbar--short',\n    title: 'Webapp components/ProgressBar',\n    name: 'short',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-progressbar',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-progressbar--inprogress-25': {\n    id: 'webapp-components-progressbar--inprogress-25',\n    title: 'Webapp components/ProgressBar',\n    name: 'inprogress 25',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-progressbar',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-progressbar--inprogress-50': {\n    id: 'webapp-components-progressbar--inprogress-50',\n    title: 'Webapp components/ProgressBar',\n    name: 'inprogress 50',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-progressbar',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-progressbar--inprogress-tooltip': {\n    id: 'webapp-components-progressbar--inprogress-tooltip',\n    title: 'Webapp components/ProgressBar',\n    name: 'inprogress, tooltip',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-progressbar',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-progressbar--reviewing-partial': {\n    id: 'webapp-components-progressbar--reviewing-partial',\n    title: 'Webapp components/ProgressBar',\n    name: 'reviewing partial',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-progressbar',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-progressbar--reviewing-complete': {\n    id: 'webapp-components-progressbar--reviewing-complete',\n    title: 'Webapp components/ProgressBar',\n    name: 'reviewing complete',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-progressbar',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-projectitem': {\n    name: 'ProjectItem',\n    id: 'webapp-components-projectitem',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-projectitem--all-project-item',\n      'webapp-components-projectitem--loading',\n      'webapp-components-projectitem--app-screen-loading-see-1196',\n      'webapp-components-projectitem--default',\n      'webapp-components-projectitem--default-no-account-name',\n      'webapp-components-projectitem--default-few-users',\n      'webapp-components-projectitem--in-setup',\n    ],\n    type: 'component',\n  },\n  'webapp-components-projectitem--all-project-item': {\n    id: 'webapp-components-projectitem--all-project-item',\n    title: 'Webapp components/ProjectItem',\n    name: 'All ProjectItem',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-projectitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-projectitem--loading': {\n    id: 'webapp-components-projectitem--loading',\n    title: 'Webapp components/ProjectItem',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-projectitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-projectitem--app-screen-loading-see-1196': {\n    id: 'webapp-components-projectitem--app-screen-loading-see-1196',\n    title: 'Webapp components/ProjectItem',\n    name: 'app screen loading (see #1196)',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-projectitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-projectitem--default': {\n    id: 'webapp-components-projectitem--default',\n    title: 'Webapp components/ProjectItem',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-projectitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-projectitem--default-no-account-name': {\n    id: 'webapp-components-projectitem--default-no-account-name',\n    title: 'Webapp components/ProjectItem',\n    name: 'default, noAccountName',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-projectitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-projectitem--default-few-users': {\n    id: 'webapp-components-projectitem--default-few-users',\n    title: 'Webapp components/ProjectItem',\n    name: 'default few users',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-projectitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-projectitem--in-setup': {\n    id: 'webapp-components-projectitem--in-setup',\n    title: 'Webapp components/ProjectItem',\n    name: 'in setup',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-projectitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-projectlist': {\n    name: 'ProjectList',\n    id: 'webapp-components-projectlist',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-projectlist--loading',\n      'webapp-components-projectlist--full',\n      'webapp-components-projectlist--full-no-account-name',\n    ],\n    type: 'component',\n  },\n  'webapp-components-projectlist--loading': {\n    id: 'webapp-components-projectlist--loading',\n    title: 'Webapp components/ProjectList',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-projectlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-projectlist--full': {\n    id: 'webapp-components-projectlist--full',\n    title: 'Webapp components/ProjectList',\n    name: 'full',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-projectlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-projectlist--full-no-account-name': {\n    id: 'webapp-components-projectlist--full-no-account-name',\n    title: 'Webapp components/ProjectList',\n    name: 'full, no account name',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-projectlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequestitem': {\n    name: 'PullRequestItem',\n    id: 'webapp-components-pullrequestitem',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-pullrequestitem--all-pull-request-item',\n      'webapp-components-pullrequestitem--loading',\n      'webapp-components-pullrequestitem--unbuilt',\n      'webapp-components-pullrequestitem--building',\n      'webapp-components-pullrequestitem--passed',\n      'webapp-components-pullrequestitem--pending',\n      'webapp-components-pullrequestitem--errored-diffs',\n      'webapp-components-pullrequestitem--errored-build-closed',\n    ],\n    type: 'component',\n  },\n  'webapp-components-pullrequestitem--all-pull-request-item': {\n    id: 'webapp-components-pullrequestitem--all-pull-request-item',\n    title: 'Webapp components/PullRequestItem',\n    name: 'All PullRequestItem',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequestitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequestitem--loading': {\n    id: 'webapp-components-pullrequestitem--loading',\n    title: 'Webapp components/PullRequestItem',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequestitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequestitem--unbuilt': {\n    id: 'webapp-components-pullrequestitem--unbuilt',\n    title: 'Webapp components/PullRequestItem',\n    name: 'Unbuilt',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequestitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequestitem--building': {\n    id: 'webapp-components-pullrequestitem--building',\n    title: 'Webapp components/PullRequestItem',\n    name: 'Building',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequestitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequestitem--passed': {\n    id: 'webapp-components-pullrequestitem--passed',\n    title: 'Webapp components/PullRequestItem',\n    name: 'Passed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequestitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequestitem--pending': {\n    id: 'webapp-components-pullrequestitem--pending',\n    title: 'Webapp components/PullRequestItem',\n    name: 'Pending',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequestitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequestitem--errored-diffs': {\n    id: 'webapp-components-pullrequestitem--errored-diffs',\n    title: 'Webapp components/PullRequestItem',\n    name: 'Errored Diffs',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequestitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequestitem--errored-build-closed': {\n    id: 'webapp-components-pullrequestitem--errored-build-closed',\n    title: 'Webapp components/PullRequestItem',\n    name: 'Errored build, closed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequestitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequestlist': {\n    name: 'PullRequestList',\n    id: 'webapp-components-pullrequestlist',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-pullrequestlist--loading',\n      'webapp-components-pullrequestlist--full',\n      'webapp-components-pullrequestlist--full-ui-review-disabled',\n      'webapp-components-pullrequestlist--empty',\n      'webapp-components-pullrequestlist--empty-branch',\n      'webapp-components-pullrequestlist--error',\n    ],\n    type: 'component',\n  },\n  'webapp-components-pullrequestlist--loading': {\n    id: 'webapp-components-pullrequestlist--loading',\n    title: 'Webapp components/PullRequestList',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequestlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequestlist--full': {\n    id: 'webapp-components-pullrequestlist--full',\n    title: 'Webapp components/PullRequestList',\n    name: 'full',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequestlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequestlist--full-ui-review-disabled': {\n    id: 'webapp-components-pullrequestlist--full-ui-review-disabled',\n    title: 'Webapp components/PullRequestList',\n    name: 'full, UI review disabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequestlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequestlist--empty': {\n    id: 'webapp-components-pullrequestlist--empty',\n    title: 'Webapp components/PullRequestList',\n    name: 'empty',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequestlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequestlist--empty-branch': {\n    id: 'webapp-components-pullrequestlist--empty-branch',\n    title: 'Webapp components/PullRequestList',\n    name: 'empty branch',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequestlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequestlist--error': {\n    id: 'webapp-components-pullrequestlist--error',\n    title: 'Webapp components/PullRequestList',\n    name: 'error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequestlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight': {\n    name: 'PullRequestStatusLight',\n    id: 'webapp-components-pullrequeststatuslight',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-pullrequeststatuslight--loading',\n      'webapp-components-pullrequeststatuslight--passed',\n      'webapp-components-pullrequeststatuslight--no-builds',\n      'webapp-components-pullrequeststatuslight--checklist',\n      'webapp-components-pullrequeststatuslight--errored-diffs',\n      'webapp-components-pullrequeststatuslight--errored-diffs-and-checklist',\n      'webapp-components-pullrequeststatuslight--build-in-progress',\n      'webapp-components-pullrequeststatuslight--comparison-in-progress',\n      'webapp-components-pullrequeststatuslight--build-error',\n      'webapp-components-pullrequeststatuslight--comparison-error',\n      'webapp-components-pullrequeststatuslight--paused',\n      'webapp-components-pullrequeststatuslight--payment-required',\n      'webapp-components-pullrequeststatuslight--publish-only',\n      'webapp-components-pullrequeststatuslight--publish-only-build-in-progress',\n      'webapp-components-pullrequeststatuslight--publish-only-build-error',\n      'webapp-components-pullrequeststatuslight--ui-review-disabled',\n      'webapp-components-pullrequeststatuslight--ui-review-disabled-build-in-progress',\n      'webapp-components-pullrequeststatuslight--ui-review-disabled-build-error',\n      'webapp-components-pullrequeststatuslight--ui-review-disabled-publish-only',\n      'webapp-components-pullrequeststatuslight--ui-review-disabled-paused',\n      'webapp-components-pullrequeststatuslight--tiny',\n    ],\n    type: 'component',\n  },\n  'webapp-components-pullrequeststatuslight--loading': {\n    id: 'webapp-components-pullrequeststatuslight--loading',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight--passed': {\n    id: 'webapp-components-pullrequeststatuslight--passed',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'Passed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight--no-builds': {\n    id: 'webapp-components-pullrequeststatuslight--no-builds',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'No Builds',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight--checklist': {\n    id: 'webapp-components-pullrequeststatuslight--checklist',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'Checklist',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight--errored-diffs': {\n    id: 'webapp-components-pullrequeststatuslight--errored-diffs',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'Errored Diffs',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight--errored-diffs-and-checklist': {\n    id: 'webapp-components-pullrequeststatuslight--errored-diffs-and-checklist',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'Errored Diffs And Checklist',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight--build-in-progress': {\n    id: 'webapp-components-pullrequeststatuslight--build-in-progress',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'Build In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight--comparison-in-progress': {\n    id: 'webapp-components-pullrequeststatuslight--comparison-in-progress',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'Comparison In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight--build-error': {\n    id: 'webapp-components-pullrequeststatuslight--build-error',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'Build Error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight--comparison-error': {\n    id: 'webapp-components-pullrequeststatuslight--comparison-error',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'Comparison Error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight--paused': {\n    id: 'webapp-components-pullrequeststatuslight--paused',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'Paused',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight--payment-required': {\n    id: 'webapp-components-pullrequeststatuslight--payment-required',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'Payment Required',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight--publish-only': {\n    id: 'webapp-components-pullrequeststatuslight--publish-only',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'Publish Only',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight--publish-only-build-in-progress': {\n    id: 'webapp-components-pullrequeststatuslight--publish-only-build-in-progress',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'Publish Only, Build In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight--publish-only-build-error': {\n    id: 'webapp-components-pullrequeststatuslight--publish-only-build-error',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'Publish Only, Build Error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight--ui-review-disabled': {\n    id: 'webapp-components-pullrequeststatuslight--ui-review-disabled',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'UI Review Disabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight--ui-review-disabled-build-in-progress': {\n    id: 'webapp-components-pullrequeststatuslight--ui-review-disabled-build-in-progress',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'UI Review Disabled, Build In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight--ui-review-disabled-build-error': {\n    id: 'webapp-components-pullrequeststatuslight--ui-review-disabled-build-error',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'UI Review Disabled, Build Error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight--ui-review-disabled-publish-only': {\n    id: 'webapp-components-pullrequeststatuslight--ui-review-disabled-publish-only',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'UI Review Disabled, Publish Only',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight--ui-review-disabled-paused': {\n    id: 'webapp-components-pullrequeststatuslight--ui-review-disabled-paused',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'UI Review Disabled, Paused',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-pullrequeststatuslight--tiny': {\n    id: 'webapp-components-pullrequeststatuslight--tiny',\n    title: 'Webapp components/PullRequestStatusLight',\n    name: 'Tiny',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-pullrequeststatuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-questiontooltip': {\n    name: 'QuestionTooltip',\n    id: 'webapp-components-questiontooltip',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-questiontooltip--default',\n      'webapp-components-questiontooltip--start-open',\n    ],\n    type: 'component',\n  },\n  'webapp-components-questiontooltip--default': {\n    id: 'webapp-components-questiontooltip--default',\n    title: 'Webapp components/QuestionTooltip',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-questiontooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-questiontooltip--start-open': {\n    id: 'webapp-components-questiontooltip--start-open',\n    title: 'Webapp components/QuestionTooltip',\n    name: 'start open',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-questiontooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-radar': {\n    name: 'Radar',\n    id: 'webapp-components-radar',\n    parent: 'webapp-components',\n    depth: 1,\n    children: ['webapp-components-radar--radar'],\n    type: 'component',\n  },\n  'webapp-components-radar--radar': {\n    id: 'webapp-components-radar--radar',\n    title: 'Webapp components/Radar',\n    name: 'Radar',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-radar',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-radio': {\n    name: 'Radio',\n    id: 'webapp-components-radio',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-radio--all-radios',\n      'webapp-components-radio--unchecked',\n      'webapp-components-radio--checked',\n      'webapp-components-radio--primary',\n    ],\n    type: 'component',\n  },\n  'webapp-components-radio--all-radios': {\n    id: 'webapp-components-radio--all-radios',\n    title: 'Webapp components/Radio',\n    name: 'all radios',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-radio',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-radio--unchecked': {\n    id: 'webapp-components-radio--unchecked',\n    title: 'Webapp components/Radio',\n    name: 'unchecked',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-radio',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-radio--checked': {\n    id: 'webapp-components-radio--checked',\n    title: 'Webapp components/Radio',\n    name: 'checked',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-radio',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-radio--primary': {\n    id: 'webapp-components-radio--primary',\n    title: 'Webapp components/Radio',\n    name: 'primary',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-radio',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-rawspeclist': {\n    name: 'RawSpecList',\n    id: 'webapp-components-rawspeclist',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-rawspeclist--loading',\n      'webapp-components-rawspeclist--default',\n      'webapp-components-rawspeclist--empty',\n    ],\n    type: 'component',\n  },\n  'webapp-components-rawspeclist--loading': {\n    id: 'webapp-components-rawspeclist--loading',\n    title: 'Webapp components/RawSpecList',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-rawspeclist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-rawspeclist--default': {\n    id: 'webapp-components-rawspeclist--default',\n    title: 'Webapp components/RawSpecList',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-rawspeclist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-rawspeclist--empty': {\n    id: 'webapp-components-rawspeclist--empty',\n    title: 'Webapp components/RawSpecList',\n    name: 'empty',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-rawspeclist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-repositoryitem': {\n    name: 'RepositoryItem',\n    id: 'webapp-components-repositoryitem',\n    parent: 'webapp-components',\n    depth: 1,\n    children: ['webapp-components-repositoryitem--default'],\n    type: 'component',\n  },\n  'webapp-components-repositoryitem--default': {\n    id: 'webapp-components-repositoryitem--default',\n    title: 'Webapp components/RepositoryItem',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-repositoryitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-repositorylist': {\n    name: 'RepositoryList',\n    id: 'webapp-components-repositorylist',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-repositorylist--personal',\n      'webapp-components-repositorylist--personal-bitbucket',\n      'webapp-components-repositorylist--empty',\n      'webapp-components-repositorylist--empty-bitbucket',\n    ],\n    type: 'component',\n  },\n  'webapp-components-repositorylist--personal': {\n    id: 'webapp-components-repositorylist--personal',\n    title: 'Webapp components/RepositoryList',\n    name: 'personal',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-repositorylist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-repositorylist--personal-bitbucket': {\n    id: 'webapp-components-repositorylist--personal-bitbucket',\n    title: 'Webapp components/RepositoryList',\n    name: 'personal, bitbucket',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-repositorylist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-repositorylist--empty': {\n    id: 'webapp-components-repositorylist--empty',\n    title: 'Webapp components/RepositoryList',\n    name: 'empty',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-repositorylist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-repositorylist--empty-bitbucket': {\n    id: 'webapp-components-repositorylist--empty-bitbucket',\n    title: 'Webapp components/RepositoryList',\n    name: 'empty, bitbucket',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-repositorylist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-repositoryowneritem': {\n    name: 'RepositoryOwnerItem',\n    id: 'webapp-components-repositoryowneritem',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-repositoryowneritem--user',\n      'webapp-components-repositoryowneritem--org',\n    ],\n    type: 'component',\n  },\n  'webapp-components-repositoryowneritem--user': {\n    id: 'webapp-components-repositoryowneritem--user',\n    title: 'Webapp components/RepositoryOwnerItem',\n    name: 'user',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-repositoryowneritem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-repositoryowneritem--org': {\n    id: 'webapp-components-repositoryowneritem--org',\n    title: 'Webapp components/RepositoryOwnerItem',\n    name: 'org',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-repositoryowneritem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-repositoryownerlist': {\n    name: 'RepositoryOwnerList',\n    id: 'webapp-components-repositoryownerlist',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-repositoryownerlist--user-selected',\n      'webapp-components-repositoryownerlist--org-selected',\n    ],\n    type: 'component',\n  },\n  'webapp-components-repositoryownerlist--user-selected': {\n    id: 'webapp-components-repositoryownerlist--user-selected',\n    title: 'Webapp components/RepositoryOwnerList',\n    name: 'user selected',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-repositoryownerlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-repositoryownerlist--org-selected': {\n    id: 'webapp-components-repositoryownerlist--org-selected',\n    title: 'Webapp components/RepositoryOwnerList',\n    name: 'org selected',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-repositoryownerlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-repositorypicker': {\n    name: 'RepositoryPicker',\n    id: 'webapp-components-repositorypicker',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-repositorypicker--loading',\n      'webapp-components-repositorypicker--personal',\n      'webapp-components-repositorypicker--personal-w-no-apps',\n      'webapp-components-repositorypicker--organization',\n      'webapp-components-repositorypicker--organization-w-no-apps',\n    ],\n    type: 'component',\n  },\n  'webapp-components-repositorypicker--loading': {\n    id: 'webapp-components-repositorypicker--loading',\n    title: 'Webapp components/RepositoryPicker',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-repositorypicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-repositorypicker--personal': {\n    id: 'webapp-components-repositorypicker--personal',\n    title: 'Webapp components/RepositoryPicker',\n    name: 'personal',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-repositorypicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-repositorypicker--personal-w-no-apps': {\n    id: 'webapp-components-repositorypicker--personal-w-no-apps',\n    title: 'Webapp components/RepositoryPicker',\n    name: 'personal w/ no apps',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-repositorypicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-repositorypicker--organization': {\n    id: 'webapp-components-repositorypicker--organization',\n    title: 'Webapp components/RepositoryPicker',\n    name: 'organization',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-repositorypicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-repositorypicker--organization-w-no-apps': {\n    id: 'webapp-components-repositorypicker--organization-w-no-apps',\n    title: 'Webapp components/RepositoryPicker',\n    name: 'organization w/ no apps',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-repositorypicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-scrollintoview': {\n    name: 'ScrollIntoView',\n    id: 'webapp-components-scrollintoview',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-scrollintoview--w-scroll-into-view',\n      'webapp-components-scrollintoview--w-out-scroll-into-view',\n    ],\n    type: 'component',\n  },\n  'webapp-components-scrollintoview--w-scroll-into-view': {\n    id: 'webapp-components-scrollintoview--w-scroll-into-view',\n    title: 'Webapp components/ScrollIntoView',\n    name: 'w/ scroll into view',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-scrollintoview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-scrollintoview--w-out-scroll-into-view': {\n    id: 'webapp-components-scrollintoview--w-out-scroll-into-view',\n    title: 'Webapp components/ScrollIntoView',\n    name: 'w/out scroll into view',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-scrollintoview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-section': {\n    name: 'Section',\n    id: 'webapp-components-section',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-section--full',\n      'webapp-components-section--with-children',\n      'webapp-components-section--with-callout',\n      'webapp-components-section--multiple-sections-nochrome',\n      'webapp-components-section--blank',\n      'webapp-components-section--loading',\n    ],\n    type: 'component',\n  },\n  'webapp-components-section--full': {\n    id: 'webapp-components-section--full',\n    title: 'Webapp components/Section',\n    name: 'full',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-section',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-section--with-children': {\n    id: 'webapp-components-section--with-children',\n    title: 'Webapp components/Section',\n    name: 'with children',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-section',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-section--with-callout': {\n    id: 'webapp-components-section--with-callout',\n    title: 'Webapp components/Section',\n    name: 'with callout',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-section',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-section--multiple-sections-nochrome': {\n    id: 'webapp-components-section--multiple-sections-nochrome',\n    title: 'Webapp components/Section',\n    name: 'multiple sections nochrome',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-section',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-section--blank': {\n    id: 'webapp-components-section--blank',\n    title: 'Webapp components/Section',\n    name: 'blank',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-section',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-section--loading': {\n    id: 'webapp-components-section--loading',\n    title: 'Webapp components/Section',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-section',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-sharetooltipmessage': {\n    name: 'ShareTooltipMessage',\n    id: 'webapp-components-sharetooltipmessage',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-sharetooltipmessage--unlinked',\n      'webapp-components-sharetooltipmessage--linked',\n    ],\n    type: 'component',\n  },\n  'webapp-components-sharetooltipmessage--unlinked': {\n    id: 'webapp-components-sharetooltipmessage--unlinked',\n    title: 'Webapp components/ShareTooltipMessage',\n    name: 'Unlinked',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-sharetooltipmessage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-sharetooltipmessage--linked': {\n    id: 'webapp-components-sharetooltipmessage--linked',\n    title: 'Webapp components/ShareTooltipMessage',\n    name: 'Linked',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-sharetooltipmessage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-sidebarnav': {\n    name: 'SidebarNav',\n    id: 'webapp-components-sidebarnav',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-sidebarnav--loading',\n      'webapp-components-sidebarnav--account',\n      'webapp-components-sidebarnav--project',\n      'webapp-components-sidebarnav--project-setup',\n    ],\n    type: 'component',\n  },\n  'webapp-components-sidebarnav--loading': {\n    id: 'webapp-components-sidebarnav--loading',\n    title: 'Webapp components/SidebarNav',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-sidebarnav',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-sidebarnav--account': {\n    id: 'webapp-components-sidebarnav--account',\n    title: 'Webapp components/SidebarNav',\n    name: 'account',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-sidebarnav',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-sidebarnav--project': {\n    id: 'webapp-components-sidebarnav--project',\n    title: 'Webapp components/SidebarNav',\n    name: 'project',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-sidebarnav',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-sidebarnav--project-setup': {\n    id: 'webapp-components-sidebarnav--project-setup',\n    title: 'Webapp components/SidebarNav',\n    name: 'project setup',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-sidebarnav',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-snapshoterror': {\n    name: 'SnapshotError',\n    id: 'webapp-components-snapshoterror',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-snapshoterror--default',\n      'webapp-components-snapshoterror--with-metadata',\n    ],\n    type: 'component',\n  },\n  'webapp-components-snapshoterror--default': {\n    id: 'webapp-components-snapshoterror--default',\n    title: 'Webapp components/SnapshotError',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-snapshoterror',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-snapshoterror--with-metadata': {\n    id: 'webapp-components-snapshoterror--with-metadata',\n    title: 'Webapp components/SnapshotError',\n    name: 'With Metadata',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-snapshoterror',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-snapshoterrormessage': {\n    name: 'SnapshotErrorMessage',\n    id: 'webapp-components-snapshoterrormessage',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-snapshoterrormessage--image-too-large',\n      'webapp-components-snapshoterrormessage--navigation-timeout',\n      'webapp-components-snapshoterrormessage--no-js',\n      'webapp-components-snapshoterrormessage--failed-js',\n      'webapp-components-snapshoterrormessage--story-missing',\n    ],\n    type: 'component',\n  },\n  'webapp-components-snapshoterrormessage--image-too-large': {\n    id: 'webapp-components-snapshoterrormessage--image-too-large',\n    title: 'Webapp components/SnapshotErrorMessage',\n    name: 'Image Too Large',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-snapshoterrormessage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-snapshoterrormessage--navigation-timeout': {\n    id: 'webapp-components-snapshoterrormessage--navigation-timeout',\n    title: 'Webapp components/SnapshotErrorMessage',\n    name: 'Navigation Timeout',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-snapshoterrormessage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-snapshoterrormessage--no-js': {\n    id: 'webapp-components-snapshoterrormessage--no-js',\n    title: 'Webapp components/SnapshotErrorMessage',\n    name: 'No JS',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-snapshoterrormessage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-snapshoterrormessage--failed-js': {\n    id: 'webapp-components-snapshoterrormessage--failed-js',\n    title: 'Webapp components/SnapshotErrorMessage',\n    name: 'Failed JS',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-snapshoterrormessage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-snapshoterrormessage--story-missing': {\n    id: 'webapp-components-snapshoterrormessage--story-missing',\n    title: 'Webapp components/SnapshotErrorMessage',\n    name: 'Story Missing',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-snapshoterrormessage',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-snapshotsizechanged': {\n    name: 'SnapshotSizeChanged',\n    id: 'webapp-components-snapshotsizechanged',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-snapshotsizechanged--width-increased',\n      'webapp-components-snapshotsizechanged--width-decreased',\n      'webapp-components-snapshotsizechanged--height-increased',\n      'webapp-components-snapshotsizechanged--height-decreased',\n    ],\n    type: 'component',\n  },\n  'webapp-components-snapshotsizechanged--width-increased': {\n    id: 'webapp-components-snapshotsizechanged--width-increased',\n    title: 'Webapp components/SnapshotSizeChanged',\n    name: 'width increased',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-snapshotsizechanged',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-snapshotsizechanged--width-decreased': {\n    id: 'webapp-components-snapshotsizechanged--width-decreased',\n    title: 'Webapp components/SnapshotSizeChanged',\n    name: 'width decreased',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-snapshotsizechanged',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-snapshotsizechanged--height-increased': {\n    id: 'webapp-components-snapshotsizechanged--height-increased',\n    title: 'Webapp components/SnapshotSizeChanged',\n    name: 'height increased',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-snapshotsizechanged',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-snapshotsizechanged--height-decreased': {\n    id: 'webapp-components-snapshotsizechanged--height-decreased',\n    title: 'Webapp components/SnapshotSizeChanged',\n    name: 'height decreased',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-snapshotsizechanged',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-specitem': {\n    name: 'SpecItem',\n    id: 'webapp-components-specitem',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-specitem--all',\n      'webapp-components-specitem--loading',\n      'webapp-components-specitem--needs-review',\n      'webapp-components-specitem--default',\n      'webapp-components-specitem--long-name',\n      'webapp-components-specitem--selected',\n      'webapp-components-specitem--w-ignored-selectors',\n    ],\n    type: 'component',\n  },\n  'webapp-components-specitem--all': {\n    id: 'webapp-components-specitem--all',\n    title: 'Webapp components/SpecItem',\n    name: 'All',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-specitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-specitem--loading': {\n    id: 'webapp-components-specitem--loading',\n    title: 'Webapp components/SpecItem',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-specitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-specitem--needs-review': {\n    id: 'webapp-components-specitem--needs-review',\n    title: 'Webapp components/SpecItem',\n    name: 'needs review',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-specitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-specitem--default': {\n    id: 'webapp-components-specitem--default',\n    title: 'Webapp components/SpecItem',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-specitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-specitem--long-name': {\n    id: 'webapp-components-specitem--long-name',\n    title: 'Webapp components/SpecItem',\n    name: 'long name',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-specitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-specitem--selected': {\n    id: 'webapp-components-specitem--selected',\n    title: 'Webapp components/SpecItem',\n    name: 'selected',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-specitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-specitem--w-ignored-selectors': {\n    id: 'webapp-components-specitem--w-ignored-selectors',\n    title: 'Webapp components/SpecItem',\n    name: 'w/ignored selectors',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-specitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-speclist': {\n    name: 'SpecList',\n    id: 'webapp-components-speclist',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-speclist--loading',\n      'webapp-components-speclist--full',\n      'webapp-components-speclist--empty',\n    ],\n    type: 'component',\n  },\n  'webapp-components-speclist--loading': {\n    id: 'webapp-components-speclist--loading',\n    title: 'Webapp components/SpecList',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-speclist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-speclist--full': {\n    id: 'webapp-components-speclist--full',\n    title: 'Webapp components/SpecList',\n    name: 'full',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-speclist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-speclist--empty': {\n    id: 'webapp-components-speclist--empty',\n    title: 'Webapp components/SpecList',\n    name: 'empty',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-speclist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-specname': {\n    name: 'SpecName',\n    id: 'webapp-components-specname',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-specname--basic',\n      'webapp-components-specname--basic-is-link',\n      'webapp-components-specname--unnamed',\n      'webapp-components-specname--with-build-number',\n    ],\n    type: 'component',\n  },\n  'webapp-components-specname--basic': {\n    id: 'webapp-components-specname--basic',\n    title: 'Webapp components/SpecName',\n    name: 'basic',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-specname',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-specname--basic-is-link': {\n    id: 'webapp-components-specname--basic-is-link',\n    title: 'Webapp components/SpecName',\n    name: 'basic isLink',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-specname',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-specname--unnamed': {\n    id: 'webapp-components-specname--unnamed',\n    title: 'Webapp components/SpecName',\n    name: 'unnamed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-specname',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-specname--with-build-number': {\n    id: 'webapp-components-specname--with-build-number',\n    title: 'Webapp components/SpecName',\n    name: 'with build number',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-specname',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-startchat': {\n    name: 'StartChat',\n    id: 'webapp-components-startchat',\n    parent: 'webapp-components',\n    depth: 1,\n    children: ['webapp-components-startchat--base', 'webapp-components-startchat--custom'],\n    type: 'component',\n  },\n  'webapp-components-startchat--base': {\n    id: 'webapp-components-startchat--base',\n    title: 'Webapp components/StartChat',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-startchat',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-startchat--custom': {\n    id: 'webapp-components-startchat--custom',\n    title: 'Webapp components/StartChat',\n    name: 'Custom',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-startchat',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-statuslight': {\n    name: 'StatusLight',\n    id: 'webapp-components-statuslight',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-statuslight--all-statuslights',\n      'webapp-components-statuslight--positive',\n      'webapp-components-statuslight--negative',\n      'webapp-components-statuslight--warning',\n      'webapp-components-statuslight--loading',\n      'webapp-components-statuslight--disabled',\n      'webapp-components-statuslight--progress',\n      'webapp-components-statuslight--error',\n      'webapp-components-statuslight--tiny',\n      'webapp-components-statuslight--small',\n      'webapp-components-statuslight--medium',\n      'webapp-components-statuslight--large',\n    ],\n    type: 'component',\n  },\n  'webapp-components-statuslight--all-statuslights': {\n    id: 'webapp-components-statuslight--all-statuslights',\n    title: 'Webapp components/StatusLight',\n    name: 'all statuslights',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-statuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-statuslight--positive': {\n    id: 'webapp-components-statuslight--positive',\n    title: 'Webapp components/StatusLight',\n    name: 'positive',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-statuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-statuslight--negative': {\n    id: 'webapp-components-statuslight--negative',\n    title: 'Webapp components/StatusLight',\n    name: 'negative',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-statuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-statuslight--warning': {\n    id: 'webapp-components-statuslight--warning',\n    title: 'Webapp components/StatusLight',\n    name: 'warning',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-statuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-statuslight--loading': {\n    id: 'webapp-components-statuslight--loading',\n    title: 'Webapp components/StatusLight',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-statuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-statuslight--disabled': {\n    id: 'webapp-components-statuslight--disabled',\n    title: 'Webapp components/StatusLight',\n    name: 'disabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-statuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-statuslight--progress': {\n    id: 'webapp-components-statuslight--progress',\n    title: 'Webapp components/StatusLight',\n    name: 'progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-statuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-statuslight--error': {\n    id: 'webapp-components-statuslight--error',\n    title: 'Webapp components/StatusLight',\n    name: 'error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-statuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-statuslight--tiny': {\n    id: 'webapp-components-statuslight--tiny',\n    title: 'Webapp components/StatusLight',\n    name: 'tiny',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-statuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-statuslight--small': {\n    id: 'webapp-components-statuslight--small',\n    title: 'Webapp components/StatusLight',\n    name: 'small',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-statuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-statuslight--medium': {\n    id: 'webapp-components-statuslight--medium',\n    title: 'Webapp components/StatusLight',\n    name: 'medium',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-statuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-statuslight--large': {\n    id: 'webapp-components-statuslight--large',\n    title: 'Webapp components/StatusLight',\n    name: 'large',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-statuslight',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-statustooltip': {\n    name: 'StatusTooltip',\n    id: 'webapp-components-statustooltip',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-statustooltip--base',\n      'webapp-components-statustooltip--with-message',\n      'webapp-components-statustooltip--single-link',\n      'webapp-components-statustooltip--multiple-links',\n    ],\n    type: 'component',\n  },\n  'webapp-components-statustooltip--base': {\n    id: 'webapp-components-statustooltip--base',\n    title: 'Webapp components/StatusTooltip',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-statustooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-statustooltip--with-message': {\n    id: 'webapp-components-statustooltip--with-message',\n    title: 'Webapp components/StatusTooltip',\n    name: 'With Message',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-statustooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-statustooltip--single-link': {\n    id: 'webapp-components-statustooltip--single-link',\n    title: 'Webapp components/StatusTooltip',\n    name: 'Single Link',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-statustooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-statustooltip--multiple-links': {\n    id: 'webapp-components-statustooltip--multiple-links',\n    title: 'Webapp components/StatusTooltip',\n    name: 'Multiple Links',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-statustooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-subheader': {\n    name: 'Subheader',\n    id: 'webapp-components-subheader',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-subheader--all',\n      'webapp-components-subheader--loading',\n      'webapp-components-subheader--full',\n      'webapp-components-subheader--left',\n    ],\n    type: 'component',\n  },\n  'webapp-components-subheader--all': {\n    id: 'webapp-components-subheader--all',\n    title: 'Webapp components/Subheader',\n    name: 'all',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-subheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-subheader--loading': {\n    id: 'webapp-components-subheader--loading',\n    title: 'Webapp components/Subheader',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-subheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-subheader--full': {\n    id: 'webapp-components-subheader--full',\n    title: 'Webapp components/Subheader',\n    name: 'full',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-subheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-subheader--left': {\n    id: 'webapp-components-subheader--left',\n    title: 'Webapp components/Subheader',\n    name: 'left',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-subheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-table': {\n    name: 'Table',\n    id: 'webapp-components-table',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-table--all-tables',\n      'webapp-components-table--loading',\n      'webapp-components-table--empty',\n      'webapp-components-table--full',\n      'webapp-components-table--with-drawers',\n      'webapp-components-table--without-headings',\n    ],\n    type: 'component',\n  },\n  'webapp-components-table--all-tables': {\n    id: 'webapp-components-table--all-tables',\n    title: 'Webapp components/Table',\n    name: 'All tables',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-table',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-table--loading': {\n    id: 'webapp-components-table--loading',\n    title: 'Webapp components/Table',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-table',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-table--empty': {\n    id: 'webapp-components-table--empty',\n    title: 'Webapp components/Table',\n    name: 'Empty',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-table',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-table--full': {\n    id: 'webapp-components-table--full',\n    title: 'Webapp components/Table',\n    name: 'Full',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-table',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-table--with-drawers': {\n    id: 'webapp-components-table--with-drawers',\n    title: 'Webapp components/Table',\n    name: 'With drawers',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-table',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-table--without-headings': {\n    id: 'webapp-components-table--without-headings',\n    title: 'Webapp components/Table',\n    name: 'Without headings',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-table',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-tabledrawer': {\n    name: 'TableDrawer',\n    id: 'webapp-components-tabledrawer',\n    parent: 'webapp-components',\n    depth: 1,\n    children: ['webapp-components-tabledrawer--open'],\n    type: 'component',\n  },\n  'webapp-components-tabledrawer--open': {\n    id: 'webapp-components-tabledrawer--open',\n    title: 'Webapp components/TableDrawer',\n    name: 'open',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-tabledrawer',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-tooltipignore': {\n    name: 'TooltipIgnore',\n    id: 'webapp-components-tooltipignore',\n    parent: 'webapp-components',\n    depth: 1,\n    children: ['webapp-components-tooltipignore--default'],\n    type: 'component',\n  },\n  'webapp-components-tooltipignore--default': {\n    id: 'webapp-components-tooltipignore--default',\n    title: 'Webapp components/TooltipIgnore',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-tooltipignore',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-useritem': {\n    name: 'UserItem',\n    id: 'webapp-components-useritem',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-useritem--all-user-items',\n      'webapp-components-useritem--loading',\n      'webapp-components-useritem--no-link',\n      'webapp-components-useritem--link',\n    ],\n    type: 'component',\n  },\n  'webapp-components-useritem--all-user-items': {\n    id: 'webapp-components-useritem--all-user-items',\n    title: 'Webapp components/UserItem',\n    name: 'All UserItems',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-useritem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-useritem--loading': {\n    id: 'webapp-components-useritem--loading',\n    title: 'Webapp components/UserItem',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-useritem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-useritem--no-link': {\n    id: 'webapp-components-useritem--no-link',\n    title: 'Webapp components/UserItem',\n    name: 'No link',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-useritem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-useritem--link': {\n    id: 'webapp-components-useritem--link',\n    title: 'Webapp components/UserItem',\n    name: 'Link',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-useritem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-userlist': {\n    name: 'UserList',\n    id: 'webapp-components-userlist',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-userlist--all-user-lists',\n      'webapp-components-userlist--loading',\n      'webapp-components-userlist--full-w-links',\n      'webapp-components-userlist--full-no-links',\n      'webapp-components-userlist--paginated-no-links',\n      'webapp-components-userlist--empty',\n    ],\n    type: 'component',\n  },\n  'webapp-components-userlist--all-user-lists': {\n    id: 'webapp-components-userlist--all-user-lists',\n    title: 'Webapp components/UserList',\n    name: 'All UserLists',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-userlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-userlist--loading': {\n    id: 'webapp-components-userlist--loading',\n    title: 'Webapp components/UserList',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-userlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-userlist--full-w-links': {\n    id: 'webapp-components-userlist--full-w-links',\n    title: 'Webapp components/UserList',\n    name: 'full w/links',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-userlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-userlist--full-no-links': {\n    id: 'webapp-components-userlist--full-no-links',\n    title: 'Webapp components/UserList',\n    name: 'full no links',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-userlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-userlist--paginated-no-links': {\n    id: 'webapp-components-userlist--paginated-no-links',\n    title: 'Webapp components/UserList',\n    name: 'paginated no links',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-userlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-userlist--empty': {\n    id: 'webapp-components-userlist--empty',\n    title: 'Webapp components/UserList',\n    name: 'empty',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-userlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-video': {\n    name: 'Video',\n    id: 'webapp-components-video',\n    parent: 'webapp-components',\n    depth: 1,\n    children: ['webapp-components-video--default'],\n    type: 'component',\n  },\n  'webapp-components-video--default': {\n    id: 'webapp-components-video--default',\n    title: 'Webapp components/Video',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-video',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-warning': {\n    name: 'Warning',\n    id: 'webapp-components-warning',\n    parent: 'webapp-components',\n    depth: 1,\n    children: [\n      'webapp-components-warning--base',\n      'webapp-components-warning--with-icon',\n      'webapp-components-warning--with-action',\n      'webapp-components-warning--with-icon-action',\n      'webapp-components-warning--stacked-multiple-items',\n      'webapp-components-warning--stacked-single-item',\n    ],\n    type: 'component',\n  },\n  'webapp-components-warning--base': {\n    id: 'webapp-components-warning--base',\n    title: 'Webapp components/Warning',\n    name: 'base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-warning',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-warning--with-icon': {\n    id: 'webapp-components-warning--with-icon',\n    title: 'Webapp components/Warning',\n    name: 'with icon',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-warning',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-warning--with-action': {\n    id: 'webapp-components-warning--with-action',\n    title: 'Webapp components/Warning',\n    name: 'with action',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-warning',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-warning--with-icon-action': {\n    id: 'webapp-components-warning--with-icon-action',\n    title: 'Webapp components/Warning',\n    name: 'with icon, action',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-warning',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-warning--stacked-multiple-items': {\n    id: 'webapp-components-warning--stacked-multiple-items',\n    title: 'Webapp components/Warning',\n    name: 'stacked, multiple items',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-warning',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-warning--stacked-single-item': {\n    id: 'webapp-components-warning--stacked-single-item',\n    title: 'Webapp components/Warning',\n    name: 'stacked, single item',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-warning',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-components-wobbler': {\n    name: 'Wobbler',\n    id: 'webapp-components-wobbler',\n    parent: 'webapp-components',\n    depth: 1,\n    children: ['webapp-components-wobbler--simple'],\n    type: 'component',\n  },\n  'webapp-components-wobbler--simple': {\n    id: 'webapp-components-wobbler--simple',\n    title: 'Webapp components/Wobbler',\n    name: 'simple',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-components-wobbler',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-containers': {\n    name: 'Webapp containers',\n    id: 'webapp-containers',\n    depth: 0,\n    children: ['webapp-containers-appbuildspaginated', 'webapp-containers-componentbuildspicker'],\n    type: 'root',\n  },\n  'webapp-containers-appbuildspaginated': {\n    name: 'AppBuildsPaginated',\n    id: 'webapp-containers-appbuildspaginated',\n    parent: 'webapp-containers',\n    depth: 1,\n    children: [\n      'webapp-containers-appbuildspaginated--loading',\n      'webapp-containers-appbuildspaginated--has-next-page',\n      'webapp-containers-appbuildspaginated--error',\n    ],\n    type: 'component',\n  },\n  'webapp-containers-appbuildspaginated--loading': {\n    id: 'webapp-containers-appbuildspaginated--loading',\n    title: 'Webapp containers/AppBuildsPaginated',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-containers-appbuildspaginated',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-containers-appbuildspaginated--has-next-page': {\n    id: 'webapp-containers-appbuildspaginated--has-next-page',\n    title: 'Webapp containers/AppBuildsPaginated',\n    name: 'has next page',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-containers-appbuildspaginated',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-containers-appbuildspaginated--error': {\n    id: 'webapp-containers-appbuildspaginated--error',\n    title: 'Webapp containers/AppBuildsPaginated',\n    name: 'error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-containers-appbuildspaginated',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-containers-componentbuildspicker': {\n    name: 'ComponentBuildsPicker',\n    id: 'webapp-containers-componentbuildspicker',\n    parent: 'webapp-containers',\n    depth: 1,\n    children: [\n      'webapp-containers-componentbuildspicker--loading',\n      'webapp-containers-componentbuildspicker--app',\n      'webapp-containers-componentbuildspicker--component',\n    ],\n    type: 'component',\n  },\n  'webapp-containers-componentbuildspicker--loading': {\n    id: 'webapp-containers-componentbuildspicker--loading',\n    title: 'Webapp containers/ComponentBuildsPicker',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-containers-componentbuildspicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-containers-componentbuildspicker--app': {\n    id: 'webapp-containers-componentbuildspicker--app',\n    title: 'Webapp containers/ComponentBuildsPicker',\n    name: 'app',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-containers-componentbuildspicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-containers-componentbuildspicker--component': {\n    id: 'webapp-containers-componentbuildspicker--component',\n    title: 'Webapp containers/ComponentBuildsPicker',\n    name: 'component',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-containers-componentbuildspicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts': {\n    name: 'Webapp layouts',\n    id: 'webapp-layouts',\n    depth: 0,\n    children: [\n      'webapp-layouts-account',\n      'webapp-layouts-app',\n      'webapp-layouts-interstitial',\n      'webapp-layouts-marketing',\n      'webapp-layouts-onboarding',\n      'webapp-layouts-page',\n      'webapp-layouts-setup',\n    ],\n    type: 'root',\n  },\n  'webapp-layouts-account': {\n    name: 'Account',\n    id: 'webapp-layouts-account',\n    parent: 'webapp-layouts',\n    depth: 1,\n    children: [\n      'webapp-layouts-account--loading',\n      'webapp-layouts-account--projects',\n      'webapp-layouts-account--projects-personal-account',\n      'webapp-layouts-account--projects-personal-account-saml',\n      'webapp-layouts-account--projects-shared-with-you',\n      'webapp-layouts-account--projects-saml-account-owner',\n      'webapp-layouts-account--projects-saml-account-not-owner',\n      'webapp-layouts-account--billing',\n    ],\n    type: 'component',\n  },\n  'webapp-layouts-account--loading': {\n    id: 'webapp-layouts-account--loading',\n    title: 'Webapp layouts/Account',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-account',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-account--projects': {\n    id: 'webapp-layouts-account--projects',\n    title: 'Webapp layouts/Account',\n    name: 'projects',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-account',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-account--projects-personal-account': {\n    id: 'webapp-layouts-account--projects-personal-account',\n    title: 'Webapp layouts/Account',\n    name: 'projects, personal account',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-account',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-account--projects-personal-account-saml': {\n    id: 'webapp-layouts-account--projects-personal-account-saml',\n    title: 'Webapp layouts/Account',\n    name: 'projects, personal account, saml',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-account',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-account--projects-shared-with-you': {\n    id: 'webapp-layouts-account--projects-shared-with-you',\n    title: 'Webapp layouts/Account',\n    name: 'projects, shared with you',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-account',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-account--projects-saml-account-owner': {\n    id: 'webapp-layouts-account--projects-saml-account-owner',\n    title: 'Webapp layouts/Account',\n    name: 'projects, saml account, owner',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-account',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-account--projects-saml-account-not-owner': {\n    id: 'webapp-layouts-account--projects-saml-account-not-owner',\n    title: 'Webapp layouts/Account',\n    name: 'projects, saml account, not owner',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-account',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-account--billing': {\n    id: 'webapp-layouts-account--billing',\n    title: 'Webapp layouts/Account',\n    name: 'billing',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-account',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-app': {\n    name: 'App',\n    id: 'webapp-layouts-app',\n    parent: 'webapp-layouts',\n    depth: 1,\n    children: [\n      'webapp-layouts-app--loading',\n      'webapp-layouts-app--builds',\n      'webapp-layouts-app--builds-shared-with-you',\n      'webapp-layouts-app--setup',\n      'webapp-layouts-app--builds-with-branch',\n      'webapp-layouts-app--components',\n      'webapp-layouts-app--no-ci',\n      'webapp-layouts-app--no-ci-100-builds',\n      'webapp-layouts-app--not-logged-in',\n      'webapp-layouts-app--admin',\n      'webapp-layouts-app--gerrit',\n    ],\n    type: 'component',\n  },\n  'webapp-layouts-app--loading': {\n    id: 'webapp-layouts-app--loading',\n    title: 'Webapp layouts/App',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-app',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-app--builds': {\n    id: 'webapp-layouts-app--builds',\n    title: 'Webapp layouts/App',\n    name: 'builds',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-app',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-app--builds-shared-with-you': {\n    id: 'webapp-layouts-app--builds-shared-with-you',\n    title: 'Webapp layouts/App',\n    name: 'builds, sharedWithYou',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-app',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-app--setup': {\n    id: 'webapp-layouts-app--setup',\n    title: 'Webapp layouts/App',\n    name: 'setup',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-app',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-app--builds-with-branch': {\n    id: 'webapp-layouts-app--builds-with-branch',\n    title: 'Webapp layouts/App',\n    name: 'builds with branch',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-app',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-app--components': {\n    id: 'webapp-layouts-app--components',\n    title: 'Webapp layouts/App',\n    name: 'components',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-app',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-app--no-ci': {\n    id: 'webapp-layouts-app--no-ci',\n    title: 'Webapp layouts/App',\n    name: 'no CI',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-app',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-app--no-ci-100-builds': {\n    id: 'webapp-layouts-app--no-ci-100-builds',\n    title: 'Webapp layouts/App',\n    name: 'no CI, 100 builds',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-app',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-app--not-logged-in': {\n    id: 'webapp-layouts-app--not-logged-in',\n    title: 'Webapp layouts/App',\n    name: 'not logged in',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-app',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-app--admin': {\n    id: 'webapp-layouts-app--admin',\n    title: 'Webapp layouts/App',\n    name: 'admin',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-app',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-app--gerrit': {\n    id: 'webapp-layouts-app--gerrit',\n    title: 'Webapp layouts/App',\n    name: 'Gerrit',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-app',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-interstitial': {\n    name: 'Interstitial',\n    id: 'webapp-layouts-interstitial',\n    parent: 'webapp-layouts',\n    depth: 1,\n    children: ['webapp-layouts-interstitial--default'],\n    type: 'component',\n  },\n  'webapp-layouts-interstitial--default': {\n    id: 'webapp-layouts-interstitial--default',\n    title: 'Webapp layouts/Interstitial',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-interstitial',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-marketing': {\n    name: 'Marketing',\n    id: 'webapp-layouts-marketing',\n    parent: 'webapp-layouts',\n    depth: 1,\n    children: [\n      'webapp-layouts-marketing--not-logged-in',\n      'webapp-layouts-marketing--logged-in',\n      'webapp-layouts-marketing--maintenance-mode',\n      'webapp-layouts-marketing--dark-hero',\n    ],\n    type: 'component',\n  },\n  'webapp-layouts-marketing--not-logged-in': {\n    id: 'webapp-layouts-marketing--not-logged-in',\n    title: 'Webapp layouts/Marketing',\n    name: 'not logged in',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-marketing',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-marketing--logged-in': {\n    id: 'webapp-layouts-marketing--logged-in',\n    title: 'Webapp layouts/Marketing',\n    name: 'logged in',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-marketing',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-marketing--maintenance-mode': {\n    id: 'webapp-layouts-marketing--maintenance-mode',\n    title: 'Webapp layouts/Marketing',\n    name: 'maintenanceMode',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-marketing',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-marketing--dark-hero': {\n    id: 'webapp-layouts-marketing--dark-hero',\n    title: 'Webapp layouts/Marketing',\n    name: 'darkHero',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-marketing',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-onboarding': {\n    name: 'Onboarding',\n    id: 'webapp-layouts-onboarding',\n    parent: 'webapp-layouts',\n    depth: 1,\n    children: [\n      'webapp-layouts-onboarding--loading',\n      'webapp-layouts-onboarding--logged-out',\n      'webapp-layouts-onboarding--logged-in',\n      'webapp-layouts-onboarding--logged-in-with-app',\n    ],\n    type: 'component',\n  },\n  'webapp-layouts-onboarding--loading': {\n    id: 'webapp-layouts-onboarding--loading',\n    title: 'Webapp layouts/Onboarding',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-onboarding',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-onboarding--logged-out': {\n    id: 'webapp-layouts-onboarding--logged-out',\n    title: 'Webapp layouts/Onboarding',\n    name: 'loggedOut',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-onboarding',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-onboarding--logged-in': {\n    id: 'webapp-layouts-onboarding--logged-in',\n    title: 'Webapp layouts/Onboarding',\n    name: 'loggedIn',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-onboarding',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-onboarding--logged-in-with-app': {\n    id: 'webapp-layouts-onboarding--logged-in-with-app',\n    title: 'Webapp layouts/Onboarding',\n    name: 'loggedIn with app',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-onboarding',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-page': {\n    name: 'Page',\n    id: 'webapp-layouts-page',\n    parent: 'webapp-layouts',\n    depth: 1,\n    children: [\n      'webapp-layouts-page--loading',\n      'webapp-layouts-page--logged-in-has-app-owner',\n      'webapp-layouts-page--logged-in-has-app-owner-personal',\n      'webapp-layouts-page--logged-in-has-exceeded-threshold',\n      'webapp-layouts-page--logged-in-has-app',\n      'webapp-layouts-page--logged-in-has-app-shared-with-you',\n      'webapp-layouts-page--not-logged-in',\n      'webapp-layouts-page--with-eyebrow',\n      'webapp-layouts-page--tall-eyebrow',\n    ],\n    type: 'component',\n  },\n  'webapp-layouts-page--loading': {\n    id: 'webapp-layouts-page--loading',\n    title: 'Webapp layouts/Page',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-page',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-page--logged-in-has-app-owner': {\n    id: 'webapp-layouts-page--logged-in-has-app-owner',\n    title: 'Webapp layouts/Page',\n    name: 'loggedIn has appOwner',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-page',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-page--logged-in-has-app-owner-personal': {\n    id: 'webapp-layouts-page--logged-in-has-app-owner-personal',\n    title: 'Webapp layouts/Page',\n    name: 'loggedIn has appOwner, personal',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-page',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-page--logged-in-has-exceeded-threshold': {\n    id: 'webapp-layouts-page--logged-in-has-exceeded-threshold',\n    title: 'Webapp layouts/Page',\n    name: 'loggedIn, exceeded threshold',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-page',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-page--logged-in-has-app': {\n    id: 'webapp-layouts-page--logged-in-has-app',\n    title: 'Webapp layouts/Page',\n    name: 'loggedIn has app',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-page',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-page--logged-in-has-app-shared-with-you': {\n    id: 'webapp-layouts-page--logged-in-has-app-shared-with-you',\n    title: 'Webapp layouts/Page',\n    name: 'loggedIn has app, shared with you',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-page',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-page--not-logged-in': {\n    id: 'webapp-layouts-page--not-logged-in',\n    title: 'Webapp layouts/Page',\n    name: 'not logged in',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-page',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-page--with-eyebrow': {\n    id: 'webapp-layouts-page--with-eyebrow',\n    title: 'Webapp layouts/Page',\n    name: 'eyebrow',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-page',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-page--tall-eyebrow': {\n    id: 'webapp-layouts-page--tall-eyebrow',\n    title: 'Webapp layouts/Page',\n    name: 'tall eyebrow',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-page',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-setup': {\n    name: 'Setup',\n    id: 'webapp-layouts-setup',\n    parent: 'webapp-layouts',\n    depth: 1,\n    children: [\n      'webapp-layouts-setup--loading',\n      'webapp-layouts-setup--loading-onboarding',\n      'webapp-layouts-setup--basic',\n      'webapp-layouts-setup--basic-onboarding',\n      'webapp-layouts-setup--basic-read-only',\n      'webapp-layouts-setup--basic-admin',\n    ],\n    type: 'component',\n  },\n  'webapp-layouts-setup--loading': {\n    id: 'webapp-layouts-setup--loading',\n    title: 'Webapp layouts/Setup',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-setup',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-setup--loading-onboarding': {\n    id: 'webapp-layouts-setup--loading-onboarding',\n    title: 'Webapp layouts/Setup',\n    name: 'Loading Onboarding',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-setup',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-setup--basic': {\n    id: 'webapp-layouts-setup--basic',\n    title: 'Webapp layouts/Setup',\n    name: 'Basic',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-setup',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-setup--basic-onboarding': {\n    id: 'webapp-layouts-setup--basic-onboarding',\n    title: 'Webapp layouts/Setup',\n    name: 'Basic Onboarding',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-setup',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-setup--basic-read-only': {\n    id: 'webapp-layouts-setup--basic-read-only',\n    title: 'Webapp layouts/Setup',\n    name: 'Basic Read Only',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-setup',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-layouts-setup--basic-admin': {\n    id: 'webapp-layouts-setup--basic-admin',\n    title: 'Webapp layouts/Setup',\n    name: 'Basic Admin',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-layouts-setup',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens': {\n    name: 'Webapp screens',\n    id: 'webapp-screens',\n    depth: 0,\n    children: [\n      'webapp-screens-appsscreen',\n      'webapp-screens-billingscreen',\n      'webapp-screens-build',\n      'webapp-screens-buildsscreen',\n      'webapp-screens-component',\n      'webapp-screens-componentsscreen',\n      'webapp-screens-error',\n      'webapp-screens-installgithubappsuccessscreen',\n      'webapp-screens-installwebhookscreen',\n      'webapp-screens-joinbetascreen',\n      'webapp-screens-loadingscreen',\n      'webapp-screens-loginscreen',\n      'webapp-screens-managescreen',\n      'webapp-screens-marketing',\n      'webapp-screens-notificationsscreen',\n      'webapp-screens-onboarding',\n      'webapp-screens-preferencesupdatedscreen',\n      'webapp-screens-pullrequest',\n      'webapp-screens-pullrequestsscreen',\n      'webapp-screens-settingsscreen',\n      'webapp-screens-setup',\n      'webapp-screens-snapshot',\n    ],\n    type: 'root',\n  },\n  'webapp-screens-appsscreen': {\n    name: 'AppsScreen',\n    id: 'webapp-screens-appsscreen',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: [\n      'webapp-screens-appsscreen--loading',\n      'webapp-screens-appsscreen--personal',\n      'webapp-screens-appsscreen--personal-modal-open',\n      'webapp-screens-appsscreen--personal-saml-user',\n      'webapp-screens-appsscreen--personal-saml-user-modal-open',\n      'webapp-screens-appsscreen--organization',\n      'webapp-screens-appsscreen--organization-modal-open',\n      'webapp-screens-appsscreen--saml-account',\n      'webapp-screens-appsscreen--saml-account-modal-open',\n      'webapp-screens-appsscreen--shared-with-you',\n      'webapp-screens-appsscreen--no-projects-personal-account',\n      'webapp-screens-appsscreen--personal-account-creating-first-app',\n      'webapp-screens-appsscreen--no-projects-shared-with-you-app-owner',\n      'webapp-screens-appsscreen--no-projects-linked-account',\n      'webapp-screens-appsscreen--no-projects-saml-account',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-appsscreen--loading': {\n    id: 'webapp-screens-appsscreen--loading',\n    title: 'Webapp screens/AppsScreen',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-appsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-appsscreen--personal': {\n    id: 'webapp-screens-appsscreen--personal',\n    title: 'Webapp screens/AppsScreen',\n    name: 'personal',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-appsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-appsscreen--personal-modal-open': {\n    id: 'webapp-screens-appsscreen--personal-modal-open',\n    title: 'Webapp screens/AppsScreen',\n    name: 'personal, modal open',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-appsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-appsscreen--personal-saml-user': {\n    id: 'webapp-screens-appsscreen--personal-saml-user',\n    title: 'Webapp screens/AppsScreen',\n    name: 'personal, samlUser',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-appsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-appsscreen--personal-saml-user-modal-open': {\n    id: 'webapp-screens-appsscreen--personal-saml-user-modal-open',\n    title: 'Webapp screens/AppsScreen',\n    name: 'personal, samlUser, modal open',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-appsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-appsscreen--organization': {\n    id: 'webapp-screens-appsscreen--organization',\n    title: 'Webapp screens/AppsScreen',\n    name: 'organization',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-appsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-appsscreen--organization-modal-open': {\n    id: 'webapp-screens-appsscreen--organization-modal-open',\n    title: 'Webapp screens/AppsScreen',\n    name: 'organization, modal open',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-appsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-appsscreen--saml-account': {\n    id: 'webapp-screens-appsscreen--saml-account',\n    title: 'Webapp screens/AppsScreen',\n    name: 'saml account',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-appsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-appsscreen--saml-account-modal-open': {\n    id: 'webapp-screens-appsscreen--saml-account-modal-open',\n    title: 'Webapp screens/AppsScreen',\n    name: 'saml account, modal open',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-appsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-appsscreen--shared-with-you': {\n    id: 'webapp-screens-appsscreen--shared-with-you',\n    title: 'Webapp screens/AppsScreen',\n    name: 'sharedWithYou',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-appsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-appsscreen--no-projects-personal-account': {\n    id: 'webapp-screens-appsscreen--no-projects-personal-account',\n    title: 'Webapp screens/AppsScreen',\n    name: 'no projects, personal account',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-appsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-appsscreen--personal-account-creating-first-app': {\n    id: 'webapp-screens-appsscreen--personal-account-creating-first-app',\n    title: 'Webapp screens/AppsScreen',\n    name: 'personal account, creatingFirstApp',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-appsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-appsscreen--no-projects-shared-with-you-app-owner': {\n    id: 'webapp-screens-appsscreen--no-projects-shared-with-you-app-owner',\n    title: 'Webapp screens/AppsScreen',\n    name: 'no projects, sharedWithYou app owner',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-appsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-appsscreen--no-projects-linked-account': {\n    id: 'webapp-screens-appsscreen--no-projects-linked-account',\n    title: 'Webapp screens/AppsScreen',\n    name: 'no projects, linked account',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-appsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-appsscreen--no-projects-saml-account': {\n    id: 'webapp-screens-appsscreen--no-projects-saml-account',\n    title: 'Webapp screens/AppsScreen',\n    name: 'no projects, saml account',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-appsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen': {\n    name: 'BillingScreen',\n    id: 'webapp-screens-billingscreen',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: [\n      'webapp-screens-billingscreen--loading',\n      'webapp-screens-billingscreen--pre-subscribed',\n      'webapp-screens-billingscreen--free',\n      'webapp-screens-billingscreen--free-with-bonus',\n      'webapp-screens-billingscreen--free-with-bonus-in-past',\n      'webapp-screens-billingscreen--free-over-limit',\n      'webapp-screens-billingscreen--paid-plan-over-limit',\n      'webapp-screens-billingscreen--trial',\n      'webapp-screens-billingscreen--trial-ending',\n      'webapp-screens-billingscreen--subscribed',\n      'webapp-screens-billingscreen--subscribed-still-in-trial',\n      'webapp-screens-billingscreen--subscribed-still-in-trial-over-limit',\n      'webapp-screens-billingscreen--subscribed-custom-plan',\n      'webapp-screens-billingscreen--subscribed-custom-plan-usage-limits',\n      'webapp-screens-billingscreen--subscribed-custom-plan-usage-limits-exceeded-threshold',\n      'webapp-screens-billingscreen--subscribed-open-source-plan-free',\n      'webapp-screens-billingscreen--subscribed-open-source-plan-free-exceeded-threshold',\n      'webapp-screens-billingscreen--subscribed-open-source-plan-paid',\n      'webapp-screens-billingscreen--subscribed-invoice-failed',\n      'webapp-screens-billingscreen--subscribed-payment-required',\n      'webapp-screens-billingscreen--subscribed-slow-builds-no-parallelization-saving',\n      'webapp-screens-billingscreen--pure-subscribed-change-plan-drawer-open',\n      'webapp-screens-billingscreen--pure-subscribed-email-drawer-open',\n      'webapp-screens-billingscreen-billingemailform',\n      'webapp-screens-billingscreen-invoicelist',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-billingscreen--loading': {\n    id: 'webapp-screens-billingscreen--loading',\n    title: 'Webapp screens/BillingScreen',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--pre-subscribed': {\n    id: 'webapp-screens-billingscreen--pre-subscribed',\n    title: 'Webapp screens/BillingScreen',\n    name: 'pre subscribed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--free': {\n    id: 'webapp-screens-billingscreen--free',\n    title: 'Webapp screens/BillingScreen',\n    name: 'Free',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--free-with-bonus': {\n    id: 'webapp-screens-billingscreen--free-with-bonus',\n    title: 'Webapp screens/BillingScreen',\n    name: 'Free With Bonus',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--free-with-bonus-in-past': {\n    id: 'webapp-screens-billingscreen--free-with-bonus-in-past',\n    title: 'Webapp screens/BillingScreen',\n    name: 'Free With Bonus In Past',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--free-over-limit': {\n    id: 'webapp-screens-billingscreen--free-over-limit',\n    title: 'Webapp screens/BillingScreen',\n    name: 'Free Over Limit',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--paid-plan-over-limit': {\n    id: 'webapp-screens-billingscreen--paid-plan-over-limit',\n    title: 'Webapp screens/BillingScreen',\n    name: 'Paid Plan Over Limit',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--trial': {\n    id: 'webapp-screens-billingscreen--trial',\n    title: 'Webapp screens/BillingScreen',\n    name: 'trial',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--trial-ending': {\n    id: 'webapp-screens-billingscreen--trial-ending',\n    title: 'Webapp screens/BillingScreen',\n    name: 'trial ending',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--subscribed': {\n    id: 'webapp-screens-billingscreen--subscribed',\n    title: 'Webapp screens/BillingScreen',\n    name: 'subscribed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--subscribed-still-in-trial': {\n    id: 'webapp-screens-billingscreen--subscribed-still-in-trial',\n    title: 'Webapp screens/BillingScreen',\n    name: 'subscribed, still in trial',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--subscribed-still-in-trial-over-limit': {\n    id: 'webapp-screens-billingscreen--subscribed-still-in-trial-over-limit',\n    title: 'Webapp screens/BillingScreen',\n    name: 'subscribed, still in trial, over limit',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--subscribed-custom-plan': {\n    id: 'webapp-screens-billingscreen--subscribed-custom-plan',\n    title: 'Webapp screens/BillingScreen',\n    name: 'subscribed, custom plan',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--subscribed-custom-plan-usage-limits': {\n    id: 'webapp-screens-billingscreen--subscribed-custom-plan-usage-limits',\n    title: 'Webapp screens/BillingScreen',\n    name: 'subscribed, custom plan, usage limits',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--subscribed-custom-plan-usage-limits-exceeded-threshold': {\n    id: 'webapp-screens-billingscreen--subscribed-custom-plan-usage-limits-exceeded-threshold',\n    title: 'Webapp screens/BillingScreen',\n    name: 'subscribed, custom plan, usage limits, exceeded threshold',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--subscribed-open-source-plan-free': {\n    id: 'webapp-screens-billingscreen--subscribed-open-source-plan-free',\n    title: 'Webapp screens/BillingScreen',\n    name: 'subscribed, open source plan, free',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--subscribed-open-source-plan-free-exceeded-threshold': {\n    id: 'webapp-screens-billingscreen--subscribed-open-source-plan-free-exceeded-threshold',\n    title: 'Webapp screens/BillingScreen',\n    name: 'subscribed, open source plan, free, exceeded threshold',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--subscribed-open-source-plan-paid': {\n    id: 'webapp-screens-billingscreen--subscribed-open-source-plan-paid',\n    title: 'Webapp screens/BillingScreen',\n    name: 'subscribed, open source plan, paid',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--subscribed-invoice-failed': {\n    id: 'webapp-screens-billingscreen--subscribed-invoice-failed',\n    title: 'Webapp screens/BillingScreen',\n    name: 'subscribed, invoice failed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--subscribed-payment-required': {\n    id: 'webapp-screens-billingscreen--subscribed-payment-required',\n    title: 'Webapp screens/BillingScreen',\n    name: 'subscribed, payment required',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--subscribed-slow-builds-no-parallelization-saving': {\n    id: 'webapp-screens-billingscreen--subscribed-slow-builds-no-parallelization-saving',\n    title: 'Webapp screens/BillingScreen',\n    name: 'subscribed, slow builds (no parallelization saving)',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--pure-subscribed-change-plan-drawer-open': {\n    id: 'webapp-screens-billingscreen--pure-subscribed-change-plan-drawer-open',\n    title: 'Webapp screens/BillingScreen',\n    name: 'pure, subscribed, change plan drawer open',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen--pure-subscribed-email-drawer-open': {\n    id: 'webapp-screens-billingscreen--pure-subscribed-email-drawer-open',\n    title: 'Webapp screens/BillingScreen',\n    name: 'pure, subscribed, email drawer open',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-billingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen-billingemailform': {\n    name: 'BillingEmailForm',\n    id: 'webapp-screens-billingscreen-billingemailform',\n    parent: 'webapp-screens-billingscreen',\n    depth: 2,\n    children: [\n      'webapp-screens-billingscreen-billingemailform--default',\n      'webapp-screens-billingscreen-billingemailform--pure-default',\n      'webapp-screens-billingscreen-billingemailform--submitting',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-billingscreen-billingemailform--default': {\n    id: 'webapp-screens-billingscreen-billingemailform--default',\n    title: 'Webapp screens/BillingScreen/BillingEmailForm',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-billingscreen-billingemailform',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen-billingemailform--pure-default': {\n    id: 'webapp-screens-billingscreen-billingemailform--pure-default',\n    title: 'Webapp screens/BillingScreen/BillingEmailForm',\n    name: 'pure default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-billingscreen-billingemailform',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen-billingemailform--submitting': {\n    id: 'webapp-screens-billingscreen-billingemailform--submitting',\n    title: 'Webapp screens/BillingScreen/BillingEmailForm',\n    name: 'submitting',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-billingscreen-billingemailform',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen-invoicelist': {\n    name: 'InvoiceList',\n    id: 'webapp-screens-billingscreen-invoicelist',\n    parent: 'webapp-screens-billingscreen',\n    depth: 2,\n    children: [\n      'webapp-screens-billingscreen-invoicelist--full',\n      'webapp-screens-billingscreen-invoicelist--full-first-invoice-not-finalized',\n      'webapp-screens-billingscreen-invoicelist--full-payment-failed',\n      'webapp-screens-billingscreen-invoicelist--trial',\n      'webapp-screens-billingscreen-invoicelist--free',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-billingscreen-invoicelist--full': {\n    id: 'webapp-screens-billingscreen-invoicelist--full',\n    title: 'Webapp screens/BillingScreen/InvoiceList',\n    name: 'full',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-billingscreen-invoicelist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen-invoicelist--full-first-invoice-not-finalized': {\n    id: 'webapp-screens-billingscreen-invoicelist--full-first-invoice-not-finalized',\n    title: 'Webapp screens/BillingScreen/InvoiceList',\n    name: 'full, first invoice not finalized',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-billingscreen-invoicelist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen-invoicelist--full-payment-failed': {\n    id: 'webapp-screens-billingscreen-invoicelist--full-payment-failed',\n    title: 'Webapp screens/BillingScreen/InvoiceList',\n    name: 'full, payment failed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-billingscreen-invoicelist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen-invoicelist--trial': {\n    id: 'webapp-screens-billingscreen-invoicelist--trial',\n    title: 'Webapp screens/BillingScreen/InvoiceList',\n    name: 'trial',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-billingscreen-invoicelist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-billingscreen-invoicelist--free': {\n    id: 'webapp-screens-billingscreen-invoicelist--free',\n    title: 'Webapp screens/BillingScreen/InvoiceList',\n    name: 'Free',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-billingscreen-invoicelist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build': {\n    name: 'Build',\n    id: 'webapp-screens-build',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: [\n      'webapp-screens-build-buildcomponents',\n      'webapp-screens-build-buildheader',\n      'webapp-screens-build-buildscreen',\n      'webapp-screens-build-buildsummary',\n      'webapp-screens-build-componentrow',\n      'webapp-screens-build-rowexpander',\n      'webapp-screens-build-snapshotrow',\n      'webapp-screens-build-snapshotstable',\n      'webapp-screens-build-specrow',\n      'webapp-screens-build-testsummary',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-build-buildcomponents': {\n    name: 'BuildComponents',\n    id: 'webapp-screens-build-buildcomponents',\n    parent: 'webapp-screens-build',\n    depth: 2,\n    children: [\n      'webapp-screens-build-buildcomponents--loading',\n      'webapp-screens-build-buildcomponents--simple',\n      'webapp-screens-build-buildcomponents--passed',\n      'webapp-screens-build-buildcomponents--failed',\n      'webapp-screens-build-buildcomponents--in-progress',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-build-buildcomponents--loading': {\n    id: 'webapp-screens-build-buildcomponents--loading',\n    title: 'Webapp screens/Build/BuildComponents',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildcomponents',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildcomponents--simple': {\n    id: 'webapp-screens-build-buildcomponents--simple',\n    title: 'Webapp screens/Build/BuildComponents',\n    name: 'simple',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildcomponents',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildcomponents--passed': {\n    id: 'webapp-screens-build-buildcomponents--passed',\n    title: 'Webapp screens/Build/BuildComponents',\n    name: 'passed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildcomponents',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildcomponents--failed': {\n    id: 'webapp-screens-build-buildcomponents--failed',\n    title: 'Webapp screens/Build/BuildComponents',\n    name: 'failed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildcomponents',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildcomponents--in-progress': {\n    id: 'webapp-screens-build-buildcomponents--in-progress',\n    title: 'Webapp screens/Build/BuildComponents',\n    name: 'in progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildcomponents',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildheader': {\n    name: 'BuildHeader',\n    id: 'webapp-screens-build-buildheader',\n    parent: 'webapp-screens-build',\n    depth: 2,\n    children: [\n      'webapp-screens-build-buildheader--loading',\n      'webapp-screens-build-buildheader--automatic',\n      'webapp-screens-build-buildheader--passed',\n      'webapp-screens-build-buildheader--denied',\n      'webapp-screens-build-buildheader--failed',\n      'webapp-screens-build-buildheader--errored',\n      'webapp-screens-build-buildheader--timed-out',\n      'webapp-screens-build-buildheader--in-progress',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-build-buildheader--loading': {\n    id: 'webapp-screens-build-buildheader--loading',\n    title: 'Webapp screens/Build/BuildHeader',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildheader--automatic': {\n    id: 'webapp-screens-build-buildheader--automatic',\n    title: 'Webapp screens/Build/BuildHeader',\n    name: 'Automatic',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildheader--passed': {\n    id: 'webapp-screens-build-buildheader--passed',\n    title: 'Webapp screens/Build/BuildHeader',\n    name: 'Passed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildheader--denied': {\n    id: 'webapp-screens-build-buildheader--denied',\n    title: 'Webapp screens/Build/BuildHeader',\n    name: 'Denied',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildheader--failed': {\n    id: 'webapp-screens-build-buildheader--failed',\n    title: 'Webapp screens/Build/BuildHeader',\n    name: 'Failed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildheader--errored': {\n    id: 'webapp-screens-build-buildheader--errored',\n    title: 'Webapp screens/Build/BuildHeader',\n    name: 'Errored',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildheader--timed-out': {\n    id: 'webapp-screens-build-buildheader--timed-out',\n    title: 'Webapp screens/Build/BuildHeader',\n    name: 'Timed Out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildheader--in-progress': {\n    id: 'webapp-screens-build-buildheader--in-progress',\n    title: 'Webapp screens/Build/BuildHeader',\n    name: 'In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildscreen': {\n    name: 'BuildScreen',\n    id: 'webapp-screens-build-buildscreen',\n    parent: 'webapp-screens-build',\n    depth: 2,\n    children: [\n      'webapp-screens-build-buildscreen--loading',\n      'webapp-screens-build-buildscreen--unreviewed',\n      'webapp-screens-build-buildscreen--passed',\n      'webapp-screens-build-buildscreen--paused',\n      'webapp-screens-build-buildscreen--disabled',\n      'webapp-screens-build-buildscreen--denied',\n      'webapp-screens-build-buildscreen--component-errors',\n      'webapp-screens-build-buildscreen--build-error',\n      'webapp-screens-build-buildscreen--build-timeout',\n      'webapp-screens-build-buildscreen--build-in-progress',\n      'webapp-screens-build-buildscreen--tunnelled-build',\n      'webapp-screens-build-buildscreen--newer-build',\n      'webapp-screens-build-buildscreen--upgrade-build-with-newer-build',\n      'webapp-screens-build-buildscreen--upgrade-build-no-newer-build',\n      'webapp-screens-build-buildscreen--no-ancestor',\n      'webapp-screens-build-buildscreen--no-ancestor-newer-build',\n      'webapp-screens-build-buildscreen--multiple-ancestors',\n      'webapp-screens-build-buildscreen--onboarding',\n      'webapp-screens-build-buildscreen--onboarding-no-tests',\n      'webapp-screens-build-buildscreen--no-snapshots-remaining',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-build-buildscreen--loading': {\n    id: 'webapp-screens-build-buildscreen--loading',\n    title: 'Webapp screens/Build/BuildScreen',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildscreen--unreviewed': {\n    id: 'webapp-screens-build-buildscreen--unreviewed',\n    title: 'Webapp screens/Build/BuildScreen',\n    name: 'Unreviewed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildscreen--passed': {\n    id: 'webapp-screens-build-buildscreen--passed',\n    title: 'Webapp screens/Build/BuildScreen',\n    name: 'Passed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildscreen--paused': {\n    id: 'webapp-screens-build-buildscreen--paused',\n    title: 'Webapp screens/Build/BuildScreen',\n    name: 'Paused',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildscreen--disabled': {\n    id: 'webapp-screens-build-buildscreen--disabled',\n    title: 'Webapp screens/Build/BuildScreen',\n    name: 'Disabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildscreen--denied': {\n    id: 'webapp-screens-build-buildscreen--denied',\n    title: 'Webapp screens/Build/BuildScreen',\n    name: 'Denied',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildscreen--component-errors': {\n    id: 'webapp-screens-build-buildscreen--component-errors',\n    title: 'Webapp screens/Build/BuildScreen',\n    name: 'Component Errors',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildscreen--build-error': {\n    id: 'webapp-screens-build-buildscreen--build-error',\n    title: 'Webapp screens/Build/BuildScreen',\n    name: 'Build Error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildscreen--build-timeout': {\n    id: 'webapp-screens-build-buildscreen--build-timeout',\n    title: 'Webapp screens/Build/BuildScreen',\n    name: 'Build Timeout',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildscreen--build-in-progress': {\n    id: 'webapp-screens-build-buildscreen--build-in-progress',\n    title: 'Webapp screens/Build/BuildScreen',\n    name: 'Build In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildscreen--tunnelled-build': {\n    id: 'webapp-screens-build-buildscreen--tunnelled-build',\n    title: 'Webapp screens/Build/BuildScreen',\n    name: 'Tunnelled Build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildscreen--newer-build': {\n    id: 'webapp-screens-build-buildscreen--newer-build',\n    title: 'Webapp screens/Build/BuildScreen',\n    name: 'Newer Build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildscreen--upgrade-build-with-newer-build': {\n    id: 'webapp-screens-build-buildscreen--upgrade-build-with-newer-build',\n    title: 'Webapp screens/Build/BuildScreen',\n    name: 'Upgrade Build With Newer Build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildscreen--upgrade-build-no-newer-build': {\n    id: 'webapp-screens-build-buildscreen--upgrade-build-no-newer-build',\n    title: 'Webapp screens/Build/BuildScreen',\n    name: 'Upgrade Build No Newer Build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildscreen--no-ancestor': {\n    id: 'webapp-screens-build-buildscreen--no-ancestor',\n    title: 'Webapp screens/Build/BuildScreen',\n    name: 'No Ancestor',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildscreen--no-ancestor-newer-build': {\n    id: 'webapp-screens-build-buildscreen--no-ancestor-newer-build',\n    title: 'Webapp screens/Build/BuildScreen',\n    name: 'No Ancestor Newer Build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildscreen--multiple-ancestors': {\n    id: 'webapp-screens-build-buildscreen--multiple-ancestors',\n    title: 'Webapp screens/Build/BuildScreen',\n    name: 'Multiple Ancestors',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildscreen--onboarding': {\n    id: 'webapp-screens-build-buildscreen--onboarding',\n    title: 'Webapp screens/Build/BuildScreen',\n    name: 'Onboarding',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildscreen--onboarding-no-tests': {\n    id: 'webapp-screens-build-buildscreen--onboarding-no-tests',\n    title: 'Webapp screens/Build/BuildScreen',\n    name: 'Onboarding No Tests',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildscreen--no-snapshots-remaining': {\n    id: 'webapp-screens-build-buildscreen--no-snapshots-remaining',\n    title: 'Webapp screens/Build/BuildScreen',\n    name: 'No Snapshots Remaining',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary': {\n    name: 'BuildSummary',\n    id: 'webapp-screens-build-buildsummary',\n    parent: 'webapp-screens-build',\n    depth: 2,\n    children: [\n      'webapp-screens-build-buildsummary--loading',\n      'webapp-screens-build-buildsummary--default',\n      'webapp-screens-build-buildsummary--tests-paused',\n      'webapp-screens-build-buildsummary--tests-disabled',\n      'webapp-screens-build-buildsummary--single-pull-request',\n      'webapp-screens-build-buildsummary--multiple-pull-requests',\n      'webapp-screens-build-buildsummary--build-error',\n      'webapp-screens-build-buildsummary--build-timeout',\n      'webapp-screens-build-buildsummary-ancestors',\n      'webapp-screens-build-buildsummary-commit',\n      'webapp-screens-build-buildsummary-pullrequests',\n      'webapp-screens-build-buildsummary-tests',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-build-buildsummary--loading': {\n    id: 'webapp-screens-build-buildsummary--loading',\n    title: 'Webapp screens/Build/BuildSummary',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary--default': {\n    id: 'webapp-screens-build-buildsummary--default',\n    title: 'Webapp screens/Build/BuildSummary',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary--tests-paused': {\n    id: 'webapp-screens-build-buildsummary--tests-paused',\n    title: 'Webapp screens/Build/BuildSummary',\n    name: 'Tests Paused',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary--tests-disabled': {\n    id: 'webapp-screens-build-buildsummary--tests-disabled',\n    title: 'Webapp screens/Build/BuildSummary',\n    name: 'Tests Disabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary--single-pull-request': {\n    id: 'webapp-screens-build-buildsummary--single-pull-request',\n    title: 'Webapp screens/Build/BuildSummary',\n    name: 'Single Pull Request',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary--multiple-pull-requests': {\n    id: 'webapp-screens-build-buildsummary--multiple-pull-requests',\n    title: 'Webapp screens/Build/BuildSummary',\n    name: 'Multiple Pull Requests',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary--build-error': {\n    id: 'webapp-screens-build-buildsummary--build-error',\n    title: 'Webapp screens/Build/BuildSummary',\n    name: 'Build Error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary--build-timeout': {\n    id: 'webapp-screens-build-buildsummary--build-timeout',\n    title: 'Webapp screens/Build/BuildSummary',\n    name: 'Build Timeout',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-buildsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-ancestors': {\n    name: 'Ancestors',\n    id: 'webapp-screens-build-buildsummary-ancestors',\n    parent: 'webapp-screens-build-buildsummary',\n    depth: 3,\n    children: [\n      'webapp-screens-build-buildsummary-ancestors--loading',\n      'webapp-screens-build-buildsummary-ancestors--none',\n      'webapp-screens-build-buildsummary-ancestors--one',\n      'webapp-screens-build-buildsummary-ancestors--multiple',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-build-buildsummary-ancestors--loading': {\n    id: 'webapp-screens-build-buildsummary-ancestors--loading',\n    title: 'Webapp screens/Build/BuildSummary/Ancestors',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-ancestors',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-ancestors--none': {\n    id: 'webapp-screens-build-buildsummary-ancestors--none',\n    title: 'Webapp screens/Build/BuildSummary/Ancestors',\n    name: 'None',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-ancestors',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-ancestors--one': {\n    id: 'webapp-screens-build-buildsummary-ancestors--one',\n    title: 'Webapp screens/Build/BuildSummary/Ancestors',\n    name: 'One',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-ancestors',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-ancestors--multiple': {\n    id: 'webapp-screens-build-buildsummary-ancestors--multiple',\n    title: 'Webapp screens/Build/BuildSummary/Ancestors',\n    name: 'Multiple',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-ancestors',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-commit': {\n    name: 'Commit',\n    id: 'webapp-screens-build-buildsummary-commit',\n    parent: 'webapp-screens-build-buildsummary',\n    depth: 3,\n    children: [\n      'webapp-screens-build-buildsummary-commit--loading',\n      'webapp-screens-build-buildsummary-commit--default',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-build-buildsummary-commit--loading': {\n    id: 'webapp-screens-build-buildsummary-commit--loading',\n    title: 'Webapp screens/Build/BuildSummary/Commit',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-commit',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-commit--default': {\n    id: 'webapp-screens-build-buildsummary-commit--default',\n    title: 'Webapp screens/Build/BuildSummary/Commit',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-commit',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-pullrequests': {\n    name: 'PullRequests',\n    id: 'webapp-screens-build-buildsummary-pullrequests',\n    parent: 'webapp-screens-build-buildsummary',\n    depth: 3,\n    children: [\n      'webapp-screens-build-buildsummary-pullrequests--loading',\n      'webapp-screens-build-buildsummary-pullrequests--none',\n      'webapp-screens-build-buildsummary-pullrequests--one',\n      'webapp-screens-build-buildsummary-pullrequests--multiple',\n      'webapp-screens-build-buildsummary-pullrequests--gitlab',\n      'webapp-screens-build-buildsummary-pullrequests--missing-app-installation',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-build-buildsummary-pullrequests--loading': {\n    id: 'webapp-screens-build-buildsummary-pullrequests--loading',\n    title: 'Webapp screens/Build/BuildSummary/PullRequests',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-pullrequests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-pullrequests--none': {\n    id: 'webapp-screens-build-buildsummary-pullrequests--none',\n    title: 'Webapp screens/Build/BuildSummary/PullRequests',\n    name: 'None',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-pullrequests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-pullrequests--one': {\n    id: 'webapp-screens-build-buildsummary-pullrequests--one',\n    title: 'Webapp screens/Build/BuildSummary/PullRequests',\n    name: 'One',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-pullrequests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-pullrequests--multiple': {\n    id: 'webapp-screens-build-buildsummary-pullrequests--multiple',\n    title: 'Webapp screens/Build/BuildSummary/PullRequests',\n    name: 'Multiple',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-pullrequests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-pullrequests--gitlab': {\n    id: 'webapp-screens-build-buildsummary-pullrequests--gitlab',\n    title: 'Webapp screens/Build/BuildSummary/PullRequests',\n    name: 'Gitlab',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-pullrequests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-pullrequests--missing-app-installation': {\n    id: 'webapp-screens-build-buildsummary-pullrequests--missing-app-installation',\n    title: 'Webapp screens/Build/BuildSummary/PullRequests',\n    name: 'Missing App Installation',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-pullrequests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-tests': {\n    name: 'Tests',\n    id: 'webapp-screens-build-buildsummary-tests',\n    parent: 'webapp-screens-build-buildsummary',\n    depth: 3,\n    children: [\n      'webapp-screens-build-buildsummary-tests--loading',\n      'webapp-screens-build-buildsummary-tests--default',\n      'webapp-screens-build-buildsummary-tests--currently-paused',\n      'webapp-screens-build-buildsummary-tests--currently-paused-payment-required',\n      'webapp-screens-build-buildsummary-tests--currently-paused-no-subscription',\n      'webapp-screens-build-buildsummary-tests--currently-paused-org',\n      'webapp-screens-build-buildsummary-tests--paused-in-the-past',\n      'webapp-screens-build-buildsummary-tests--currently-disabled',\n      'webapp-screens-build-buildsummary-tests--currently-disabled-no-savings',\n      'webapp-screens-build-buildsummary-tests--currently-disabled-read-only',\n      'webapp-screens-build-buildsummary-tests--disabled-in-the-past',\n      'webapp-screens-build-buildsummary-tests--one-browser',\n      'webapp-screens-build-buildsummary-tests--two-browsers',\n      'webapp-screens-build-buildsummary-tests--all-browsers',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-build-buildsummary-tests--loading': {\n    id: 'webapp-screens-build-buildsummary-tests--loading',\n    title: 'Webapp screens/Build/BuildSummary/Tests',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-tests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-tests--default': {\n    id: 'webapp-screens-build-buildsummary-tests--default',\n    title: 'Webapp screens/Build/BuildSummary/Tests',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-tests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-tests--currently-paused': {\n    id: 'webapp-screens-build-buildsummary-tests--currently-paused',\n    title: 'Webapp screens/Build/BuildSummary/Tests',\n    name: 'Currently Paused',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-tests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-tests--currently-paused-payment-required': {\n    id: 'webapp-screens-build-buildsummary-tests--currently-paused-payment-required',\n    title: 'Webapp screens/Build/BuildSummary/Tests',\n    name: 'Currently Paused, Payment Required',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-tests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-tests--currently-paused-no-subscription': {\n    id: 'webapp-screens-build-buildsummary-tests--currently-paused-no-subscription',\n    title: 'Webapp screens/Build/BuildSummary/Tests',\n    name: 'Currently Paused, No Subscription',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-tests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-tests--currently-paused-org': {\n    id: 'webapp-screens-build-buildsummary-tests--currently-paused-org',\n    title: 'Webapp screens/Build/BuildSummary/Tests',\n    name: 'Currently Paused, Org',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-tests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-tests--paused-in-the-past': {\n    id: 'webapp-screens-build-buildsummary-tests--paused-in-the-past',\n    title: 'Webapp screens/Build/BuildSummary/Tests',\n    name: 'Paused In The Past',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-tests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-tests--currently-disabled': {\n    id: 'webapp-screens-build-buildsummary-tests--currently-disabled',\n    title: 'Webapp screens/Build/BuildSummary/Tests',\n    name: 'Currently Disabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-tests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-tests--currently-disabled-no-savings': {\n    id: 'webapp-screens-build-buildsummary-tests--currently-disabled-no-savings',\n    title: 'Webapp screens/Build/BuildSummary/Tests',\n    name: 'Currently Disabled, No Savings',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-tests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-tests--currently-disabled-read-only': {\n    id: 'webapp-screens-build-buildsummary-tests--currently-disabled-read-only',\n    title: 'Webapp screens/Build/BuildSummary/Tests',\n    name: 'Currently Disabled, Read Only',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-tests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-tests--disabled-in-the-past': {\n    id: 'webapp-screens-build-buildsummary-tests--disabled-in-the-past',\n    title: 'Webapp screens/Build/BuildSummary/Tests',\n    name: 'Disabled In The Past',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-tests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-tests--one-browser': {\n    id: 'webapp-screens-build-buildsummary-tests--one-browser',\n    title: 'Webapp screens/Build/BuildSummary/Tests',\n    name: 'One Browser',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-tests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-tests--two-browsers': {\n    id: 'webapp-screens-build-buildsummary-tests--two-browsers',\n    title: 'Webapp screens/Build/BuildSummary/Tests',\n    name: 'Two Browsers',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-tests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-buildsummary-tests--all-browsers': {\n    id: 'webapp-screens-build-buildsummary-tests--all-browsers',\n    title: 'Webapp screens/Build/BuildSummary/Tests',\n    name: 'All Browsers',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-build-buildsummary-tests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-componentrow': {\n    name: 'ComponentRow',\n    id: 'webapp-screens-build-componentrow',\n    parent: 'webapp-screens-build',\n    depth: 2,\n    children: [\n      'webapp-screens-build-componentrow--pending',\n      'webapp-screens-build-componentrow--pending-single-spec',\n      'webapp-screens-build-componentrow--pending-multiple-stories-per-spec',\n      'webapp-screens-build-componentrow--pending-mixed',\n      'webapp-screens-build-componentrow--pending-unreviewable',\n      'webapp-screens-build-componentrow--pending-reviewing-build',\n      'webapp-screens-build-componentrow--pending-reviewing-component',\n      'webapp-screens-build-componentrow--pending-reviewing-spec',\n      'webapp-screens-build-componentrow--pending-reviewing-snapshot',\n      'webapp-screens-build-componentrow--pure-pending-expanded',\n      'webapp-screens-build-componentrow--pure-pending-unexpanded',\n      'webapp-screens-build-componentrow--accepted',\n      'webapp-screens-build-componentrow--denied',\n      'webapp-screens-build-componentrow--reviewed-many-reviewers',\n      'webapp-screens-build-componentrow--pure-unexpanded-reviewed-many-reviewers',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-build-componentrow--pending': {\n    id: 'webapp-screens-build-componentrow--pending',\n    title: 'Webapp screens/Build/ComponentRow',\n    name: 'pending',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-componentrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-componentrow--pending-single-spec': {\n    id: 'webapp-screens-build-componentrow--pending-single-spec',\n    title: 'Webapp screens/Build/ComponentRow',\n    name: 'pending, single spec',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-componentrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-componentrow--pending-multiple-stories-per-spec': {\n    id: 'webapp-screens-build-componentrow--pending-multiple-stories-per-spec',\n    title: 'Webapp screens/Build/ComponentRow',\n    name: 'pending, multiple stories per spec',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-componentrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-componentrow--pending-mixed': {\n    id: 'webapp-screens-build-componentrow--pending-mixed',\n    title: 'Webapp screens/Build/ComponentRow',\n    name: 'pending, mixed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-componentrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-componentrow--pending-unreviewable': {\n    id: 'webapp-screens-build-componentrow--pending-unreviewable',\n    title: 'Webapp screens/Build/ComponentRow',\n    name: 'pending, unreviewable',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-componentrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-componentrow--pending-reviewing-build': {\n    id: 'webapp-screens-build-componentrow--pending-reviewing-build',\n    title: 'Webapp screens/Build/ComponentRow',\n    name: 'pending, reviewing build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-componentrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-componentrow--pending-reviewing-component': {\n    id: 'webapp-screens-build-componentrow--pending-reviewing-component',\n    title: 'Webapp screens/Build/ComponentRow',\n    name: 'pending, reviewing component',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-componentrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-componentrow--pending-reviewing-spec': {\n    id: 'webapp-screens-build-componentrow--pending-reviewing-spec',\n    title: 'Webapp screens/Build/ComponentRow',\n    name: 'pending, reviewing spec',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-componentrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-componentrow--pending-reviewing-snapshot': {\n    id: 'webapp-screens-build-componentrow--pending-reviewing-snapshot',\n    title: 'Webapp screens/Build/ComponentRow',\n    name: 'pending, reviewing snapshot',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-componentrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-componentrow--pure-pending-expanded': {\n    id: 'webapp-screens-build-componentrow--pure-pending-expanded',\n    title: 'Webapp screens/Build/ComponentRow',\n    name: 'pure, pending, expanded',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-componentrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-componentrow--pure-pending-unexpanded': {\n    id: 'webapp-screens-build-componentrow--pure-pending-unexpanded',\n    title: 'Webapp screens/Build/ComponentRow',\n    name: 'pure, pending, unexpanded',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-componentrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-componentrow--accepted': {\n    id: 'webapp-screens-build-componentrow--accepted',\n    title: 'Webapp screens/Build/ComponentRow',\n    name: 'accepted',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-componentrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-componentrow--denied': {\n    id: 'webapp-screens-build-componentrow--denied',\n    title: 'Webapp screens/Build/ComponentRow',\n    name: 'denied',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-componentrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-componentrow--reviewed-many-reviewers': {\n    id: 'webapp-screens-build-componentrow--reviewed-many-reviewers',\n    title: 'Webapp screens/Build/ComponentRow',\n    name: 'reviewed, many reviewers',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-componentrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-componentrow--pure-unexpanded-reviewed-many-reviewers': {\n    id: 'webapp-screens-build-componentrow--pure-unexpanded-reviewed-many-reviewers',\n    title: 'Webapp screens/Build/ComponentRow',\n    name: 'pure, unexpanded, reviewed, many reviewers',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-componentrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-rowexpander': {\n    name: 'RowExpander',\n    id: 'webapp-screens-build-rowexpander',\n    parent: 'webapp-screens-build',\n    depth: 2,\n    children: [\n      'webapp-screens-build-rowexpander--expanded',\n      'webapp-screens-build-rowexpander--collapsed',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-build-rowexpander--expanded': {\n    id: 'webapp-screens-build-rowexpander--expanded',\n    title: 'Webapp screens/Build/RowExpander',\n    name: 'expanded',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-rowexpander',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-rowexpander--collapsed': {\n    id: 'webapp-screens-build-rowexpander--collapsed',\n    title: 'Webapp screens/Build/RowExpander',\n    name: 'collapsed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-rowexpander',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotrow': {\n    name: 'SnapshotRow',\n    id: 'webapp-screens-build-snapshotrow',\n    parent: 'webapp-screens-build',\n    depth: 2,\n    children: [\n      'webapp-screens-build-snapshotrow--pending',\n      'webapp-screens-build-snapshotrow--pending-unreviewable',\n      'webapp-screens-build-snapshotrow--pending-accepting',\n      'webapp-screens-build-snapshotrow--pending-denying',\n      'webapp-screens-build-snapshotrow--pending-spec-reviewing',\n      'webapp-screens-build-snapshotrow--accepted',\n      'webapp-screens-build-snapshotrow--accepted-undoing',\n      'webapp-screens-build-snapshotrow--denied',\n      'webapp-screens-build-snapshotrow--denied-undoing',\n      'webapp-screens-build-snapshotrow--new',\n      'webapp-screens-build-snapshotrow--failed',\n      'webapp-screens-build-snapshotrow--in-progress',\n      'webapp-screens-build-snapshotrow--pending-indented-1',\n      'webapp-screens-build-snapshotrow--pending-indented-1-for-snapshot',\n      'webapp-screens-build-snapshotrow--pending-indented-2',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-build-snapshotrow--pending': {\n    id: 'webapp-screens-build-snapshotrow--pending',\n    title: 'Webapp screens/Build/SnapshotRow',\n    name: 'pending',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotrow--pending-unreviewable': {\n    id: 'webapp-screens-build-snapshotrow--pending-unreviewable',\n    title: 'Webapp screens/Build/SnapshotRow',\n    name: 'pending, unreviewable',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotrow--pending-accepting': {\n    id: 'webapp-screens-build-snapshotrow--pending-accepting',\n    title: 'Webapp screens/Build/SnapshotRow',\n    name: 'pending, accepting',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotrow--pending-denying': {\n    id: 'webapp-screens-build-snapshotrow--pending-denying',\n    title: 'Webapp screens/Build/SnapshotRow',\n    name: 'pending, denying',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotrow--pending-spec-reviewing': {\n    id: 'webapp-screens-build-snapshotrow--pending-spec-reviewing',\n    title: 'Webapp screens/Build/SnapshotRow',\n    name: 'pending, spec reviewing',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotrow--accepted': {\n    id: 'webapp-screens-build-snapshotrow--accepted',\n    title: 'Webapp screens/Build/SnapshotRow',\n    name: 'accepted',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotrow--accepted-undoing': {\n    id: 'webapp-screens-build-snapshotrow--accepted-undoing',\n    title: 'Webapp screens/Build/SnapshotRow',\n    name: 'accepted, undoing',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotrow--denied': {\n    id: 'webapp-screens-build-snapshotrow--denied',\n    title: 'Webapp screens/Build/SnapshotRow',\n    name: 'denied',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotrow--denied-undoing': {\n    id: 'webapp-screens-build-snapshotrow--denied-undoing',\n    title: 'Webapp screens/Build/SnapshotRow',\n    name: 'denied, undoing',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotrow--new': {\n    id: 'webapp-screens-build-snapshotrow--new',\n    title: 'Webapp screens/Build/SnapshotRow',\n    name: 'new',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotrow--failed': {\n    id: 'webapp-screens-build-snapshotrow--failed',\n    title: 'Webapp screens/Build/SnapshotRow',\n    name: 'failed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotrow--in-progress': {\n    id: 'webapp-screens-build-snapshotrow--in-progress',\n    title: 'Webapp screens/Build/SnapshotRow',\n    name: 'in progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotrow--pending-indented-1': {\n    id: 'webapp-screens-build-snapshotrow--pending-indented-1',\n    title: 'Webapp screens/Build/SnapshotRow',\n    name: 'pending, indented 1',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotrow--pending-indented-1-for-snapshot': {\n    id: 'webapp-screens-build-snapshotrow--pending-indented-1-for-snapshot',\n    title: 'Webapp screens/Build/SnapshotRow',\n    name: 'pending, indented 1, for snapshot',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotrow--pending-indented-2': {\n    id: 'webapp-screens-build-snapshotrow--pending-indented-2',\n    title: 'Webapp screens/Build/SnapshotRow',\n    name: 'pending, indented 2',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotstable': {\n    name: 'SnapshotsTable',\n    id: 'webapp-screens-build-snapshotstable',\n    parent: 'webapp-screens-build',\n    depth: 2,\n    children: [\n      'webapp-screens-build-snapshotstable--changes',\n      'webapp-screens-build-snapshotstable--changes-single-snaphot-only',\n      'webapp-screens-build-snapshotstable--changes-multiple-components',\n      'webapp-screens-build-snapshotstable--changes-multiple-snapshots-per-spec',\n      'webapp-screens-build-snapshotstable--changes-mixed',\n      'webapp-screens-build-snapshotstable--changes-unreviewable',\n      'webapp-screens-build-snapshotstable--changes-review-failed',\n      'webapp-screens-build-snapshotstable--changes-review-passed',\n      'webapp-screens-build-snapshotstable--new-stories',\n      'webapp-screens-build-snapshotstable--new-stories-in-progress',\n      'webapp-screens-build-snapshotstable--errors',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-build-snapshotstable--changes': {\n    id: 'webapp-screens-build-snapshotstable--changes',\n    title: 'Webapp screens/Build/SnapshotsTable',\n    name: 'changes',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotstable',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotstable--changes-single-snaphot-only': {\n    id: 'webapp-screens-build-snapshotstable--changes-single-snaphot-only',\n    title: 'Webapp screens/Build/SnapshotsTable',\n    name: 'changes, single snaphot only',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotstable',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotstable--changes-multiple-components': {\n    id: 'webapp-screens-build-snapshotstable--changes-multiple-components',\n    title: 'Webapp screens/Build/SnapshotsTable',\n    name: 'changes, multiple components',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotstable',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotstable--changes-multiple-snapshots-per-spec': {\n    id: 'webapp-screens-build-snapshotstable--changes-multiple-snapshots-per-spec',\n    title: 'Webapp screens/Build/SnapshotsTable',\n    name: 'changes, multiple snapshots per spec',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotstable',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotstable--changes-mixed': {\n    id: 'webapp-screens-build-snapshotstable--changes-mixed',\n    title: 'Webapp screens/Build/SnapshotsTable',\n    name: 'changes, mixed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotstable',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotstable--changes-unreviewable': {\n    id: 'webapp-screens-build-snapshotstable--changes-unreviewable',\n    title: 'Webapp screens/Build/SnapshotsTable',\n    name: 'changes, unreviewable',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotstable',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotstable--changes-review-failed': {\n    id: 'webapp-screens-build-snapshotstable--changes-review-failed',\n    title: 'Webapp screens/Build/SnapshotsTable',\n    name: 'changes, review failed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotstable',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotstable--changes-review-passed': {\n    id: 'webapp-screens-build-snapshotstable--changes-review-passed',\n    title: 'Webapp screens/Build/SnapshotsTable',\n    name: 'changes, review passed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotstable',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotstable--new-stories': {\n    id: 'webapp-screens-build-snapshotstable--new-stories',\n    title: 'Webapp screens/Build/SnapshotsTable',\n    name: 'new stories',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotstable',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotstable--new-stories-in-progress': {\n    id: 'webapp-screens-build-snapshotstable--new-stories-in-progress',\n    title: 'Webapp screens/Build/SnapshotsTable',\n    name: 'new stories, in progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotstable',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-snapshotstable--errors': {\n    id: 'webapp-screens-build-snapshotstable--errors',\n    title: 'Webapp screens/Build/SnapshotsTable',\n    name: 'errors',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-snapshotstable',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-specrow': {\n    name: 'SpecRow',\n    id: 'webapp-screens-build-specrow',\n    parent: 'webapp-screens-build',\n    depth: 2,\n    children: [\n      'webapp-screens-build-specrow--pending',\n      'webapp-screens-build-specrow--pending-reviewing-component',\n      'webapp-screens-build-specrow--pending-reviewing-spec',\n      'webapp-screens-build-specrow--pending-reviewing-snapshot',\n      'webapp-screens-build-specrow--pending-single-snapshot',\n      'webapp-screens-build-specrow--pending-unreviewable',\n      'webapp-screens-build-specrow--pure-pending-expanded',\n      'webapp-screens-build-specrow--pure-pending-unexpanded',\n      'webapp-screens-build-specrow--accepted',\n      'webapp-screens-build-specrow--denied',\n      'webapp-screens-build-specrow--reviewed-many-reviewers',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-build-specrow--pending': {\n    id: 'webapp-screens-build-specrow--pending',\n    title: 'Webapp screens/Build/SpecRow',\n    name: 'pending',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-specrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-specrow--pending-reviewing-component': {\n    id: 'webapp-screens-build-specrow--pending-reviewing-component',\n    title: 'Webapp screens/Build/SpecRow',\n    name: 'pending, reviewing component',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-specrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-specrow--pending-reviewing-spec': {\n    id: 'webapp-screens-build-specrow--pending-reviewing-spec',\n    title: 'Webapp screens/Build/SpecRow',\n    name: 'pending, reviewing spec',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-specrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-specrow--pending-reviewing-snapshot': {\n    id: 'webapp-screens-build-specrow--pending-reviewing-snapshot',\n    title: 'Webapp screens/Build/SpecRow',\n    name: 'pending, reviewing snapshot',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-specrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-specrow--pending-single-snapshot': {\n    id: 'webapp-screens-build-specrow--pending-single-snapshot',\n    title: 'Webapp screens/Build/SpecRow',\n    name: 'pending, single snapshot',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-specrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-specrow--pending-unreviewable': {\n    id: 'webapp-screens-build-specrow--pending-unreviewable',\n    title: 'Webapp screens/Build/SpecRow',\n    name: 'pending, unreviewable',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-specrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-specrow--pure-pending-expanded': {\n    id: 'webapp-screens-build-specrow--pure-pending-expanded',\n    title: 'Webapp screens/Build/SpecRow',\n    name: 'pure, pending, expanded',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-specrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-specrow--pure-pending-unexpanded': {\n    id: 'webapp-screens-build-specrow--pure-pending-unexpanded',\n    title: 'Webapp screens/Build/SpecRow',\n    name: 'pure, pending, unexpanded',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-specrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-specrow--accepted': {\n    id: 'webapp-screens-build-specrow--accepted',\n    title: 'Webapp screens/Build/SpecRow',\n    name: 'accepted',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-specrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-specrow--denied': {\n    id: 'webapp-screens-build-specrow--denied',\n    title: 'Webapp screens/Build/SpecRow',\n    name: 'denied',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-specrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-specrow--reviewed-many-reviewers': {\n    id: 'webapp-screens-build-specrow--reviewed-many-reviewers',\n    title: 'Webapp screens/Build/SpecRow',\n    name: 'reviewed, many reviewers',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-specrow',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary': {\n    name: 'TestSummary',\n    id: 'webapp-screens-build-testsummary',\n    parent: 'webapp-screens-build',\n    depth: 2,\n    children: [\n      'webapp-screens-build-testsummary--loading',\n      'webapp-screens-build-testsummary--no-changes',\n      'webapp-screens-build-testsummary--all-accepted',\n      'webapp-screens-build-testsummary--some-denied',\n      'webapp-screens-build-testsummary--reviewing',\n      'webapp-screens-build-testsummary--reviewing-multiple-baselines',\n      'webapp-screens-build-testsummary--reviewing-paginated',\n      'webapp-screens-build-testsummary--reviewing-new-stories',\n      'webapp-screens-build-testsummary--reviewing-readonly',\n      'webapp-screens-build-testsummary--not-reviewable',\n      'webapp-screens-build-testsummary--first-build',\n      'webapp-screens-build-testsummary--first-cross-browser-build',\n      'webapp-screens-build-testsummary--upgrade-build',\n      'webapp-screens-build-testsummary--upgraded-build',\n      'webapp-screens-build-testsummary--single-component-error',\n      'webapp-screens-build-testsummary--multiple-component-errors',\n      'webapp-screens-build-testsummary--only-component-errors',\n      'webapp-screens-build-testsummary--build-in-progress',\n      'webapp-screens-build-testsummary--build-timeout',\n      'webapp-screens-build-testsummary--build-error',\n      'webapp-screens-build-testsummary--pure-reviewing-build',\n      'webapp-screens-build-testsummary--pure-reviewing-component',\n      'webapp-screens-build-testsummary--pure-paginating',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-build-testsummary--loading': {\n    id: 'webapp-screens-build-testsummary--loading',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--no-changes': {\n    id: 'webapp-screens-build-testsummary--no-changes',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'No Changes',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--all-accepted': {\n    id: 'webapp-screens-build-testsummary--all-accepted',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'All Accepted',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--some-denied': {\n    id: 'webapp-screens-build-testsummary--some-denied',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'Some Denied',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--reviewing': {\n    id: 'webapp-screens-build-testsummary--reviewing',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'Reviewing',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--reviewing-multiple-baselines': {\n    id: 'webapp-screens-build-testsummary--reviewing-multiple-baselines',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'Reviewing Multiple Baselines',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--reviewing-paginated': {\n    id: 'webapp-screens-build-testsummary--reviewing-paginated',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'Reviewing Paginated',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--reviewing-new-stories': {\n    id: 'webapp-screens-build-testsummary--reviewing-new-stories',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'Reviewing New Stories',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--reviewing-readonly': {\n    id: 'webapp-screens-build-testsummary--reviewing-readonly',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'Reviewing Readonly',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--not-reviewable': {\n    id: 'webapp-screens-build-testsummary--not-reviewable',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'Not Reviewable',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--first-build': {\n    id: 'webapp-screens-build-testsummary--first-build',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'First Build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--first-cross-browser-build': {\n    id: 'webapp-screens-build-testsummary--first-cross-browser-build',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'First Cross Browser Build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--upgrade-build': {\n    id: 'webapp-screens-build-testsummary--upgrade-build',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'Upgrade Build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--upgraded-build': {\n    id: 'webapp-screens-build-testsummary--upgraded-build',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'Upgraded Build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--single-component-error': {\n    id: 'webapp-screens-build-testsummary--single-component-error',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'Single Component Error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--multiple-component-errors': {\n    id: 'webapp-screens-build-testsummary--multiple-component-errors',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'Multiple Component Errors',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--only-component-errors': {\n    id: 'webapp-screens-build-testsummary--only-component-errors',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'Only Component Errors',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--build-in-progress': {\n    id: 'webapp-screens-build-testsummary--build-in-progress',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'Build In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--build-timeout': {\n    id: 'webapp-screens-build-testsummary--build-timeout',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'Build Timeout',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--build-error': {\n    id: 'webapp-screens-build-testsummary--build-error',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'Build Error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--pure-reviewing-build': {\n    id: 'webapp-screens-build-testsummary--pure-reviewing-build',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'Pure Reviewing Build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--pure-reviewing-component': {\n    id: 'webapp-screens-build-testsummary--pure-reviewing-component',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'Pure Reviewing Component',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-build-testsummary--pure-paginating': {\n    id: 'webapp-screens-build-testsummary--pure-paginating',\n    title: 'Webapp screens/Build/TestSummary',\n    name: 'Pure Paginating',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-build-testsummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-buildsscreen': {\n    name: 'BuildsScreen',\n    id: 'webapp-screens-buildsscreen',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: [\n      'webapp-screens-buildsscreen--loading',\n      'webapp-screens-buildsscreen--simple',\n      'webapp-screens-buildsscreen--simple-shared-with-you',\n      'webapp-screens-buildsscreen--simple-ci-explainer',\n      'webapp-screens-buildsscreen--simple-branch-selected',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-buildsscreen--loading': {\n    id: 'webapp-screens-buildsscreen--loading',\n    title: 'Webapp screens/BuildsScreen',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-buildsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-buildsscreen--simple': {\n    id: 'webapp-screens-buildsscreen--simple',\n    title: 'Webapp screens/BuildsScreen',\n    name: 'simple',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-buildsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-buildsscreen--simple-shared-with-you': {\n    id: 'webapp-screens-buildsscreen--simple-shared-with-you',\n    title: 'Webapp screens/BuildsScreen',\n    name: 'simple, shared with you',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-buildsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-buildsscreen--simple-ci-explainer': {\n    id: 'webapp-screens-buildsscreen--simple-ci-explainer',\n    title: 'Webapp screens/BuildsScreen',\n    name: 'simple, ci explainer',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-buildsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-buildsscreen--simple-branch-selected': {\n    id: 'webapp-screens-buildsscreen--simple-branch-selected',\n    title: 'Webapp screens/BuildsScreen',\n    name: 'simple, branch selected',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-buildsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component': {\n    name: 'Component',\n    id: 'webapp-screens-component',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: [\n      'webapp-screens-component-componentcanvas',\n      'webapp-screens-component-componentcomments',\n      'webapp-screens-component-componentcommentthread',\n      'webapp-screens-component-componentheader',\n      'webapp-screens-component-componentscreen',\n      'webapp-screens-component-componentsidebar',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-component-componentcanvas': {\n    name: 'ComponentCanvas',\n    id: 'webapp-screens-component-componentcanvas',\n    parent: 'webapp-screens-component',\n    depth: 2,\n    children: [\n      'webapp-screens-component-componentcanvas--loading',\n      'webapp-screens-component-componentcanvas--empty',\n      'webapp-screens-component-componentcanvas--in-progress',\n      'webapp-screens-component-componentcanvas--in-progress-interactive',\n      'webapp-screens-component-componentcanvas--snapshot-error',\n      'webapp-screens-component-componentcanvas--snapshot-error-interactive',\n      'webapp-screens-component-componentcanvas--snapshot-failed',\n      'webapp-screens-component-componentcanvas--snapshot-did-not-capture',\n      'webapp-screens-component-componentcanvas--pending-non-interactive',\n      'webapp-screens-component-componentcanvas--pending-non-interactive-ignored-regions',\n      'webapp-screens-component-componentcanvas--pending-interactive',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-component-componentcanvas--loading': {\n    id: 'webapp-screens-component-componentcanvas--loading',\n    title: 'Webapp screens/Component/ComponentCanvas',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcanvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcanvas--empty': {\n    id: 'webapp-screens-component-componentcanvas--empty',\n    title: 'Webapp screens/Component/ComponentCanvas',\n    name: 'empty',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcanvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcanvas--in-progress': {\n    id: 'webapp-screens-component-componentcanvas--in-progress',\n    title: 'Webapp screens/Component/ComponentCanvas',\n    name: 'in progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcanvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcanvas--in-progress-interactive': {\n    id: 'webapp-screens-component-componentcanvas--in-progress-interactive',\n    title: 'Webapp screens/Component/ComponentCanvas',\n    name: 'in progress, interactive',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcanvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcanvas--snapshot-error': {\n    id: 'webapp-screens-component-componentcanvas--snapshot-error',\n    title: 'Webapp screens/Component/ComponentCanvas',\n    name: 'snapshot error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcanvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcanvas--snapshot-error-interactive': {\n    id: 'webapp-screens-component-componentcanvas--snapshot-error-interactive',\n    title: 'Webapp screens/Component/ComponentCanvas',\n    name: 'snapshot error, interactive',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcanvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcanvas--snapshot-failed': {\n    id: 'webapp-screens-component-componentcanvas--snapshot-failed',\n    title: 'Webapp screens/Component/ComponentCanvas',\n    name: 'snapshot failed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcanvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcanvas--snapshot-did-not-capture': {\n    id: 'webapp-screens-component-componentcanvas--snapshot-did-not-capture',\n    title: 'Webapp screens/Component/ComponentCanvas',\n    name: 'snapshot did not capture',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcanvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcanvas--pending-non-interactive': {\n    id: 'webapp-screens-component-componentcanvas--pending-non-interactive',\n    title: 'Webapp screens/Component/ComponentCanvas',\n    name: 'pending, non-interactive',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcanvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcanvas--pending-non-interactive-ignored-regions': {\n    id: 'webapp-screens-component-componentcanvas--pending-non-interactive-ignored-regions',\n    title: 'Webapp screens/Component/ComponentCanvas',\n    name: 'pending, non-interactive, ignored regions',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcanvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcanvas--pending-interactive': {\n    id: 'webapp-screens-component-componentcanvas--pending-interactive',\n    title: 'Webapp screens/Component/ComponentCanvas',\n    name: 'pending, interactive',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcanvas',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcomments': {\n    name: 'ComponentComments',\n    id: 'webapp-screens-component-componentcomments',\n    parent: 'webapp-screens-component',\n    depth: 2,\n    children: [\n      'webapp-screens-component-componentcomments--without-comments',\n      'webapp-screens-component-componentcomments--without-comments-comments-disabled',\n      'webapp-screens-component-componentcomments--without-comments-logged-out',\n      'webapp-screens-component-componentcomments--with-comments-resolved',\n      'webapp-screens-component-componentcomments--with-comments-resolved-logged-out',\n      'webapp-screens-component-componentcomments--with-comments-active',\n      'webapp-screens-component-componentcomments--with-comments-active-non-owner',\n      'webapp-screens-component-componentcomments--with-comments-active-logged-out',\n      'webapp-screens-component-componentcomments--with-comments-combined',\n      'webapp-screens-component-componentcomments--with-comments-combined-comments-disabled',\n      'webapp-screens-component-componentcomments--with-comments-combined-logged-out',\n      'webapp-screens-component-componentcomments--with-comments-comments-disabled',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-component-componentcomments--without-comments': {\n    id: 'webapp-screens-component-componentcomments--without-comments',\n    title: 'Webapp screens/Component/ComponentComments',\n    name: 'without comments',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcomments',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcomments--without-comments-comments-disabled': {\n    id: 'webapp-screens-component-componentcomments--without-comments-comments-disabled',\n    title: 'Webapp screens/Component/ComponentComments',\n    name: 'without comments, comments disabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcomments',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcomments--without-comments-logged-out': {\n    id: 'webapp-screens-component-componentcomments--without-comments-logged-out',\n    title: 'Webapp screens/Component/ComponentComments',\n    name: 'without comments, logged out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcomments',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcomments--with-comments-resolved': {\n    id: 'webapp-screens-component-componentcomments--with-comments-resolved',\n    title: 'Webapp screens/Component/ComponentComments',\n    name: 'with comments, resolved',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcomments',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcomments--with-comments-resolved-logged-out': {\n    id: 'webapp-screens-component-componentcomments--with-comments-resolved-logged-out',\n    title: 'Webapp screens/Component/ComponentComments',\n    name: 'with comments, resolved, logged out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcomments',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcomments--with-comments-active': {\n    id: 'webapp-screens-component-componentcomments--with-comments-active',\n    title: 'Webapp screens/Component/ComponentComments',\n    name: 'with comments, active',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcomments',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcomments--with-comments-active-non-owner': {\n    id: 'webapp-screens-component-componentcomments--with-comments-active-non-owner',\n    title: 'Webapp screens/Component/ComponentComments',\n    name: 'with comments, active, non-owner',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcomments',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcomments--with-comments-active-logged-out': {\n    id: 'webapp-screens-component-componentcomments--with-comments-active-logged-out',\n    title: 'Webapp screens/Component/ComponentComments',\n    name: 'with comments, active, logged out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcomments',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcomments--with-comments-combined': {\n    id: 'webapp-screens-component-componentcomments--with-comments-combined',\n    title: 'Webapp screens/Component/ComponentComments',\n    name: 'with comments, combined',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcomments',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcomments--with-comments-combined-comments-disabled': {\n    id: 'webapp-screens-component-componentcomments--with-comments-combined-comments-disabled',\n    title: 'Webapp screens/Component/ComponentComments',\n    name: 'with comments, combined, comments disabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcomments',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcomments--with-comments-combined-logged-out': {\n    id: 'webapp-screens-component-componentcomments--with-comments-combined-logged-out',\n    title: 'Webapp screens/Component/ComponentComments',\n    name: 'with comments, combined, logged out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcomments',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcomments--with-comments-comments-disabled': {\n    id: 'webapp-screens-component-componentcomments--with-comments-comments-disabled',\n    title: 'Webapp screens/Component/ComponentComments',\n    name: 'with comments, comments disabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcomments',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcommentthread': {\n    name: 'ComponentCommentThread',\n    id: 'webapp-screens-component-componentcommentthread',\n    parent: 'webapp-screens-component',\n    depth: 2,\n    children: [\n      'webapp-screens-component-componentcommentthread--active',\n      'webapp-screens-component-componentcommentthread--active-unreviewable',\n      'webapp-screens-component-componentcommentthread--active-logged-out',\n      'webapp-screens-component-componentcommentthread--resolved',\n      'webapp-screens-component-componentcommentthread--resolved-expanded',\n      'webapp-screens-component-componentcommentthread--resolved-expanded-non-owner',\n      'webapp-screens-component-componentcommentthread--resolved-unreviewable',\n      'webapp-screens-component-componentcommentthread--resolved-unreviewable-expanded',\n      'webapp-screens-component-componentcommentthread--resolved-logged-out',\n      'webapp-screens-component-componentcommentthread--resolved-logged-out-expanded',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-component-componentcommentthread--active': {\n    id: 'webapp-screens-component-componentcommentthread--active',\n    title: 'Webapp screens/Component/ComponentCommentThread',\n    name: 'active',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcommentthread--active-unreviewable': {\n    id: 'webapp-screens-component-componentcommentthread--active-unreviewable',\n    title: 'Webapp screens/Component/ComponentCommentThread',\n    name: 'active, unreviewable',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcommentthread--active-logged-out': {\n    id: 'webapp-screens-component-componentcommentthread--active-logged-out',\n    title: 'Webapp screens/Component/ComponentCommentThread',\n    name: 'active, logged out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcommentthread--resolved': {\n    id: 'webapp-screens-component-componentcommentthread--resolved',\n    title: 'Webapp screens/Component/ComponentCommentThread',\n    name: 'resolved',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcommentthread--resolved-expanded': {\n    id: 'webapp-screens-component-componentcommentthread--resolved-expanded',\n    title: 'Webapp screens/Component/ComponentCommentThread',\n    name: 'resolved, expanded',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcommentthread--resolved-expanded-non-owner': {\n    id: 'webapp-screens-component-componentcommentthread--resolved-expanded-non-owner',\n    title: 'Webapp screens/Component/ComponentCommentThread',\n    name: 'resolved, expanded, non-owner',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcommentthread--resolved-unreviewable': {\n    id: 'webapp-screens-component-componentcommentthread--resolved-unreviewable',\n    title: 'Webapp screens/Component/ComponentCommentThread',\n    name: 'resolved, unreviewable',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcommentthread--resolved-unreviewable-expanded': {\n    id: 'webapp-screens-component-componentcommentthread--resolved-unreviewable-expanded',\n    title: 'Webapp screens/Component/ComponentCommentThread',\n    name: 'resolved, unreviewable, expanded',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcommentthread--resolved-logged-out': {\n    id: 'webapp-screens-component-componentcommentthread--resolved-logged-out',\n    title: 'Webapp screens/Component/ComponentCommentThread',\n    name: 'resolved, logged out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentcommentthread--resolved-logged-out-expanded': {\n    id: 'webapp-screens-component-componentcommentthread--resolved-logged-out-expanded',\n    title: 'Webapp screens/Component/ComponentCommentThread',\n    name: 'resolved, logged out, expanded',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentcommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentheader': {\n    name: 'ComponentHeader',\n    id: 'webapp-screens-component-componentheader',\n    parent: 'webapp-screens-component',\n    depth: 2,\n    children: [\n      'webapp-screens-component-componentheader--loading',\n      'webapp-screens-component-componentheader--default',\n      'webapp-screens-component-componentheader--long-name',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-component-componentheader--loading': {\n    id: 'webapp-screens-component-componentheader--loading',\n    title: 'Webapp screens/Component/ComponentHeader',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentheader--default': {\n    id: 'webapp-screens-component-componentheader--default',\n    title: 'Webapp screens/Component/ComponentHeader',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentheader--long-name': {\n    id: 'webapp-screens-component-componentheader--long-name',\n    title: 'Webapp screens/Component/ComponentHeader',\n    name: 'long name',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen': {\n    name: 'ComponentScreen',\n    id: 'webapp-screens-component-componentscreen',\n    parent: 'webapp-screens-component',\n    depth: 2,\n    children: [\n      'webapp-screens-component-componentscreen--loading',\n      'webapp-screens-component-componentscreen--in-progress',\n      'webapp-screens-component-componentscreen--in-progress-canvas',\n      'webapp-screens-component-componentscreen--default-not-logged-in',\n      'webapp-screens-component-componentscreen--default-not-all-snapshots-not-logged-in',\n      'webapp-screens-component-componentscreen--default',\n      'webapp-screens-component-componentscreen--comments',\n      'webapp-screens-component-componentscreen--default-canvas',\n      'webapp-screens-component-componentscreen--default-not-all-snapshots',\n      'webapp-screens-component-componentscreen--default-docs',\n      'webapp-screens-component-componentscreen--default-no-docs',\n      'webapp-screens-component-componentscreen--default-explainer-eyebrow',\n      'webapp-screens-component-componentscreen--cross-browser-no-browser-selected',\n      'webapp-screens-component-componentscreen--cross-browser-browser-selected',\n      'webapp-screens-component-componentscreen--default-one-viewport-from-default',\n      'webapp-screens-component-componentscreen--default-from-snapshot',\n      'webapp-screens-component-componentscreen--default-from-build',\n      'webapp-screens-component-componentscreen--default-from-library',\n      'webapp-screens-component-componentscreen--story-selected',\n      'webapp-screens-component-componentscreen--story-and-viewport-selected',\n      'webapp-screens-component-componentscreen--story-selected-with-ignored-regions',\n      'webapp-screens-component-componentscreen--errored-story-snapshot',\n      'webapp-screens-component-componentscreen--errored-story-canvas',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-component-componentscreen--loading': {\n    id: 'webapp-screens-component-componentscreen--loading',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--in-progress': {\n    id: 'webapp-screens-component-componentscreen--in-progress',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'in progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--in-progress-canvas': {\n    id: 'webapp-screens-component-componentscreen--in-progress-canvas',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'in progress, canvas',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--default-not-logged-in': {\n    id: 'webapp-screens-component-componentscreen--default-not-logged-in',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'default, not logged in',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--default-not-all-snapshots-not-logged-in': {\n    id: 'webapp-screens-component-componentscreen--default-not-all-snapshots-not-logged-in',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'Default Not All Snapshots Not Logged In',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--default': {\n    id: 'webapp-screens-component-componentscreen--default',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--comments': {\n    id: 'webapp-screens-component-componentscreen--comments',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'comments',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--default-canvas': {\n    id: 'webapp-screens-component-componentscreen--default-canvas',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'default, canvas',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--default-not-all-snapshots': {\n    id: 'webapp-screens-component-componentscreen--default-not-all-snapshots',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'Default Not All Snapshots',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--default-docs': {\n    id: 'webapp-screens-component-componentscreen--default-docs',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'default, docs',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--default-no-docs': {\n    id: 'webapp-screens-component-componentscreen--default-no-docs',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'default, no docs',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--default-explainer-eyebrow': {\n    id: 'webapp-screens-component-componentscreen--default-explainer-eyebrow',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'default explainer eyebrow ',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--cross-browser-no-browser-selected': {\n    id: 'webapp-screens-component-componentscreen--cross-browser-no-browser-selected',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'cross browser, no browser selected',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--cross-browser-browser-selected': {\n    id: 'webapp-screens-component-componentscreen--cross-browser-browser-selected',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'cross browser, browser selected',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--default-one-viewport-from-default': {\n    id: 'webapp-screens-component-componentscreen--default-one-viewport-from-default',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'default, one viewport from default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--default-from-snapshot': {\n    id: 'webapp-screens-component-componentscreen--default-from-snapshot',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'default, from snapshot',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--default-from-build': {\n    id: 'webapp-screens-component-componentscreen--default-from-build',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'default, from build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--default-from-library': {\n    id: 'webapp-screens-component-componentscreen--default-from-library',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'default, from library',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--story-selected': {\n    id: 'webapp-screens-component-componentscreen--story-selected',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'story selected',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--story-and-viewport-selected': {\n    id: 'webapp-screens-component-componentscreen--story-and-viewport-selected',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'story and viewport selected',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--story-selected-with-ignored-regions': {\n    id: 'webapp-screens-component-componentscreen--story-selected-with-ignored-regions',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'story selected with ignored regions',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--errored-story-snapshot': {\n    id: 'webapp-screens-component-componentscreen--errored-story-snapshot',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'errored story, snapshot',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentscreen--errored-story-canvas': {\n    id: 'webapp-screens-component-componentscreen--errored-story-canvas',\n    title: 'Webapp screens/Component/ComponentScreen',\n    name: 'errored story, canvas',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentsidebar': {\n    name: 'ComponentSidebar',\n    id: 'webapp-screens-component-componentsidebar',\n    parent: 'webapp-screens-component',\n    depth: 2,\n    children: [\n      'webapp-screens-component-componentsidebar--loading',\n      'webapp-screens-component-componentsidebar--default',\n      'webapp-screens-component-componentsidebar--not-logged-in',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-component-componentsidebar--loading': {\n    id: 'webapp-screens-component-componentsidebar--loading',\n    title: 'Webapp screens/Component/ComponentSidebar',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentsidebar',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentsidebar--default': {\n    id: 'webapp-screens-component-componentsidebar--default',\n    title: 'Webapp screens/Component/ComponentSidebar',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentsidebar',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-component-componentsidebar--not-logged-in': {\n    id: 'webapp-screens-component-componentsidebar--not-logged-in',\n    title: 'Webapp screens/Component/ComponentSidebar',\n    name: 'not logged in',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-component-componentsidebar',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-componentsscreen': {\n    name: 'ComponentsScreen',\n    id: 'webapp-screens-componentsscreen',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: ['webapp-screens-componentsscreen-componentsscreen'],\n    type: 'group',\n  },\n  'webapp-screens-componentsscreen-componentsscreen': {\n    name: 'ComponentsScreen',\n    id: 'webapp-screens-componentsscreen-componentsscreen',\n    parent: 'webapp-screens-componentsscreen',\n    depth: 2,\n    children: [\n      'webapp-screens-componentsscreen-componentsscreen--loading',\n      'webapp-screens-componentsscreen-componentsscreen--default-unlinked-click-share-dropdown',\n      'webapp-screens-componentsscreen-componentsscreen--default-linked-click-share-dropdown',\n      'webapp-screens-componentsscreen-componentsscreen--default-explainer-eyebrow',\n      'webapp-screens-componentsscreen-componentsscreen--in-group',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-componentsscreen-componentsscreen--loading': {\n    id: 'webapp-screens-componentsscreen-componentsscreen--loading',\n    title: 'Webapp screens/ComponentsScreen/ComponentsScreen',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-componentsscreen-componentsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-componentsscreen-componentsscreen--default-unlinked-click-share-dropdown': {\n    id: 'webapp-screens-componentsscreen-componentsscreen--default-unlinked-click-share-dropdown',\n    title: 'Webapp screens/ComponentsScreen/ComponentsScreen',\n    name: 'default unlinked (click share dropdown)',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-componentsscreen-componentsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-componentsscreen-componentsscreen--default-linked-click-share-dropdown': {\n    id: 'webapp-screens-componentsscreen-componentsscreen--default-linked-click-share-dropdown',\n    title: 'Webapp screens/ComponentsScreen/ComponentsScreen',\n    name: 'default linked (click share dropdown)',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-componentsscreen-componentsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-componentsscreen-componentsscreen--default-explainer-eyebrow': {\n    id: 'webapp-screens-componentsscreen-componentsscreen--default-explainer-eyebrow',\n    title: 'Webapp screens/ComponentsScreen/ComponentsScreen',\n    name: 'default explainer eyebrow',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-componentsscreen-componentsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-componentsscreen-componentsscreen--in-group': {\n    id: 'webapp-screens-componentsscreen-componentsscreen--in-group',\n    title: 'Webapp screens/ComponentsScreen/ComponentsScreen',\n    name: 'in group',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-componentsscreen-componentsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-error': {\n    name: 'Error',\n    id: 'webapp-screens-error',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: [\n      'webapp-screens-error-errorscreen',\n      'webapp-screens-error-noaccessscreen',\n      'webapp-screens-error-notfoundscreen',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-error-errorscreen': {\n    name: 'ErrorScreen',\n    id: 'webapp-screens-error-errorscreen',\n    parent: 'webapp-screens-error',\n    depth: 2,\n    children: [\n      'webapp-screens-error-errorscreen--status-code',\n      'webapp-screens-error-errorscreen--status-code-logged-out',\n      'webapp-screens-error-errorscreen--not-found',\n      'webapp-screens-error-errorscreen--no-access',\n      'webapp-screens-error-errorscreen--no-access-logged-out',\n      'webapp-screens-error-errorscreen--error',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-error-errorscreen--status-code': {\n    id: 'webapp-screens-error-errorscreen--status-code',\n    title: 'Webapp screens/Error/ErrorScreen',\n    name: 'statusCode',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-error-errorscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-error-errorscreen--status-code-logged-out': {\n    id: 'webapp-screens-error-errorscreen--status-code-logged-out',\n    title: 'Webapp screens/Error/ErrorScreen',\n    name: 'statusCode logged out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-error-errorscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-error-errorscreen--not-found': {\n    id: 'webapp-screens-error-errorscreen--not-found',\n    title: 'Webapp screens/Error/ErrorScreen',\n    name: 'not found',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-error-errorscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-error-errorscreen--no-access': {\n    id: 'webapp-screens-error-errorscreen--no-access',\n    title: 'Webapp screens/Error/ErrorScreen',\n    name: 'no access',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-error-errorscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-error-errorscreen--no-access-logged-out': {\n    id: 'webapp-screens-error-errorscreen--no-access-logged-out',\n    title: 'Webapp screens/Error/ErrorScreen',\n    name: 'no access, logged out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-error-errorscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-error-errorscreen--error': {\n    id: 'webapp-screens-error-errorscreen--error',\n    title: 'Webapp screens/Error/ErrorScreen',\n    name: 'error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-error-errorscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-error-noaccessscreen': {\n    name: 'NoAccessScreen',\n    id: 'webapp-screens-error-noaccessscreen',\n    parent: 'webapp-screens-error',\n    depth: 2,\n    children: ['webapp-screens-error-noaccessscreen--default'],\n    type: 'component',\n  },\n  'webapp-screens-error-noaccessscreen--default': {\n    id: 'webapp-screens-error-noaccessscreen--default',\n    title: 'Webapp screens/Error/NoAccessScreen',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-error-noaccessscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-error-notfoundscreen': {\n    name: 'NotFoundScreen',\n    id: 'webapp-screens-error-notfoundscreen',\n    parent: 'webapp-screens-error',\n    depth: 2,\n    children: ['webapp-screens-error-notfoundscreen--default'],\n    type: 'component',\n  },\n  'webapp-screens-error-notfoundscreen--default': {\n    id: 'webapp-screens-error-notfoundscreen--default',\n    title: 'Webapp screens/Error/NotFoundScreen',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-error-notfoundscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-installgithubappsuccessscreen': {\n    name: 'InstallGitHubAppSuccessScreen',\n    id: 'webapp-screens-installgithubappsuccessscreen',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: ['webapp-screens-installgithubappsuccessscreen--default'],\n    type: 'component',\n  },\n  'webapp-screens-installgithubappsuccessscreen--default': {\n    id: 'webapp-screens-installgithubappsuccessscreen--default',\n    title: 'Webapp screens/InstallGitHubAppSuccessScreen',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-installgithubappsuccessscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-installwebhookscreen': {\n    name: 'InstallWebhookScreen',\n    id: 'webapp-screens-installwebhookscreen',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: [\n      'webapp-screens-installwebhookscreen--github',\n      'webapp-screens-installwebhookscreen--bitbucket',\n      'webapp-screens-installwebhookscreen--gitlab',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-installwebhookscreen--github': {\n    id: 'webapp-screens-installwebhookscreen--github',\n    title: 'Webapp screens/InstallWebhookScreen',\n    name: 'Github',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-installwebhookscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-installwebhookscreen--bitbucket': {\n    id: 'webapp-screens-installwebhookscreen--bitbucket',\n    title: 'Webapp screens/InstallWebhookScreen',\n    name: 'Bitbucket',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-installwebhookscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-installwebhookscreen--gitlab': {\n    id: 'webapp-screens-installwebhookscreen--gitlab',\n    title: 'Webapp screens/InstallWebhookScreen',\n    name: 'Gitlab',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-installwebhookscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-joinbetascreen': {\n    name: 'JoinBetaScreen',\n    id: 'webapp-screens-joinbetascreen',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: ['webapp-screens-joinbetascreen--default'],\n    type: 'component',\n  },\n  'webapp-screens-joinbetascreen--default': {\n    id: 'webapp-screens-joinbetascreen--default',\n    title: 'Webapp screens/JoinBetaScreen',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-joinbetascreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-loadingscreen': {\n    name: 'LoadingScreen',\n    id: 'webapp-screens-loadingscreen',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: ['webapp-screens-loadingscreen--default'],\n    type: 'component',\n  },\n  'webapp-screens-loadingscreen--default': {\n    id: 'webapp-screens-loadingscreen--default',\n    title: 'Webapp screens/LoadingScreen',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-loadingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-loginscreen': {\n    name: 'LoginScreen',\n    id: 'webapp-screens-loginscreen',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: [\n      'webapp-screens-loginscreen--loading',\n      'webapp-screens-loginscreen--default',\n      'webapp-screens-loginscreen--default-logged-in',\n      'webapp-screens-loginscreen--subdomain',\n      'webapp-screens-loginscreen-loginbuttons',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-loginscreen--loading': {\n    id: 'webapp-screens-loginscreen--loading',\n    title: 'Webapp screens/LoginScreen',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-loginscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-loginscreen--default': {\n    id: 'webapp-screens-loginscreen--default',\n    title: 'Webapp screens/LoginScreen',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-loginscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-loginscreen--default-logged-in': {\n    id: 'webapp-screens-loginscreen--default-logged-in',\n    title: 'Webapp screens/LoginScreen',\n    name: 'Default Logged In',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-loginscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-loginscreen--subdomain': {\n    id: 'webapp-screens-loginscreen--subdomain',\n    title: 'Webapp screens/LoginScreen',\n    name: 'Subdomain',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-loginscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-loginscreen-loginbuttons': {\n    name: 'LoginButtons',\n    id: 'webapp-screens-loginscreen-loginbuttons',\n    parent: 'webapp-screens-loginscreen',\n    depth: 2,\n    children: [\n      'webapp-screens-loginscreen-loginbuttons--default',\n      'webapp-screens-loginscreen-loginbuttons--is-loading',\n      'webapp-screens-loginscreen-loginbuttons--saml',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-loginscreen-loginbuttons--default': {\n    id: 'webapp-screens-loginscreen-loginbuttons--default',\n    title: 'Webapp screens/LoginScreen/LoginButtons',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-loginscreen-loginbuttons',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-loginscreen-loginbuttons--is-loading': {\n    id: 'webapp-screens-loginscreen-loginbuttons--is-loading',\n    title: 'Webapp screens/LoginScreen/LoginButtons',\n    name: 'isLoading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-loginscreen-loginbuttons',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-loginscreen-loginbuttons--saml': {\n    id: 'webapp-screens-loginscreen-loginbuttons--saml',\n    title: 'Webapp screens/LoginScreen/LoginButtons',\n    name: 'saml',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-loginscreen-loginbuttons',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen': {\n    name: 'ManageScreen',\n    id: 'webapp-screens-managescreen',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: [\n      'webapp-screens-managescreen-browserpicker',\n      'webapp-screens-managescreen-integrations',\n      'webapp-screens-managescreen-managescreen',\n      'webapp-screens-managescreen-uireview',\n      'webapp-screens-managescreen-visualtests',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-managescreen-browserpicker': {\n    name: 'BrowserPicker',\n    id: 'webapp-screens-managescreen-browserpicker',\n    parent: 'webapp-screens-managescreen',\n    depth: 2,\n    children: [\n      'webapp-screens-managescreen-browserpicker--interactive',\n      'webapp-screens-managescreen-browserpicker--browser-upgrade',\n      'webapp-screens-managescreen-browserpicker--adding',\n      'webapp-screens-managescreen-browserpicker--added',\n      'webapp-screens-managescreen-browserpicker--removing',\n      'webapp-screens-managescreen-browserpicker--removed',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-managescreen-browserpicker--interactive': {\n    id: 'webapp-screens-managescreen-browserpicker--interactive',\n    title: 'Webapp screens/ManageScreen/BrowserPicker',\n    name: 'interactive',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-browserpicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-browserpicker--browser-upgrade': {\n    id: 'webapp-screens-managescreen-browserpicker--browser-upgrade',\n    title: 'Webapp screens/ManageScreen/BrowserPicker',\n    name: 'browser upgrade',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-browserpicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-browserpicker--adding': {\n    id: 'webapp-screens-managescreen-browserpicker--adding',\n    title: 'Webapp screens/ManageScreen/BrowserPicker',\n    name: 'adding',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-browserpicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-browserpicker--added': {\n    id: 'webapp-screens-managescreen-browserpicker--added',\n    title: 'Webapp screens/ManageScreen/BrowserPicker',\n    name: 'added',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-browserpicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-browserpicker--removing': {\n    id: 'webapp-screens-managescreen-browserpicker--removing',\n    title: 'Webapp screens/ManageScreen/BrowserPicker',\n    name: 'removing',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-browserpicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-browserpicker--removed': {\n    id: 'webapp-screens-managescreen-browserpicker--removed',\n    title: 'Webapp screens/ManageScreen/BrowserPicker',\n    name: 'removed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-browserpicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-integrations': {\n    name: 'Integrations',\n    id: 'webapp-screens-managescreen-integrations',\n    parent: 'webapp-screens-managescreen',\n    depth: 2,\n    children: [\n      'webapp-screens-managescreen-integrations--loading',\n      'webapp-screens-managescreen-integrations--interactive',\n      'webapp-screens-managescreen-integrations--unset',\n      'webapp-screens-managescreen-integrations--expanded',\n      'webapp-screens-managescreen-integrations--filled',\n      'webapp-screens-managescreen-integrations--filled-overflow',\n      'webapp-screens-managescreen-integrations--saving',\n      'webapp-screens-managescreen-integrations--set',\n      'webapp-screens-managescreen-integrations--set-overflow',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-managescreen-integrations--loading': {\n    id: 'webapp-screens-managescreen-integrations--loading',\n    title: 'Webapp screens/ManageScreen/Integrations',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {\n      app: {\n        id: ':appId',\n        slackWebhookUrl: 'https://slack-webhook-url.slack.com',\n        customWebhookUrl: 'https://custom-webhook-url.example.com',\n      },\n      isLoading: true,\n    },\n    argTypes: {\n      app: {\n        control: {\n          type: 'object',\n        },\n        name: 'app',\n        type: {\n          name: 'object',\n          value: {\n            id: {\n              name: 'string',\n            },\n            slackWebhookUrl: {\n              name: 'string',\n            },\n            customWebhookUrl: {\n              name: 'string',\n            },\n          },\n        },\n      },\n      onUpdateApp: {\n        name: 'onUpdateApp',\n        type: {\n          name: 'function',\n        },\n      },\n      isLoading: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isLoading',\n        type: {\n          name: 'boolean',\n        },\n      },\n    },\n    initialArgs: {\n      app: {\n        id: ':appId',\n        slackWebhookUrl: 'https://slack-webhook-url.slack.com',\n        customWebhookUrl: 'https://custom-webhook-url.example.com',\n      },\n      isLoading: true,\n    },\n    depth: 3,\n    parent: 'webapp-screens-managescreen-integrations',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-integrations--interactive': {\n    id: 'webapp-screens-managescreen-integrations--interactive',\n    title: 'Webapp screens/ManageScreen/Integrations',\n    name: 'Interactive',\n    importPath: './path.js',\n    args: {\n      app: {\n        id: ':appId',\n        slackWebhookUrl: 'https://slack-webhook-url.slack.com',\n        customWebhookUrl: 'https://custom-webhook-url.example.com',\n      },\n    },\n    argTypes: {\n      app: {\n        control: {\n          type: 'object',\n        },\n        name: 'app',\n        type: {\n          name: 'object',\n          value: {\n            id: {\n              name: 'string',\n            },\n            slackWebhookUrl: {\n              name: 'string',\n            },\n            customWebhookUrl: {\n              name: 'string',\n            },\n          },\n        },\n      },\n      onUpdateApp: {\n        name: 'onUpdateApp',\n        type: {\n          name: 'function',\n        },\n      },\n    },\n    initialArgs: {\n      app: {\n        id: ':appId',\n        slackWebhookUrl: 'https://slack-webhook-url.slack.com',\n        customWebhookUrl: 'https://custom-webhook-url.example.com',\n      },\n    },\n    depth: 3,\n    parent: 'webapp-screens-managescreen-integrations',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-integrations--unset': {\n    id: 'webapp-screens-managescreen-integrations--unset',\n    title: 'Webapp screens/ManageScreen/Integrations',\n    name: 'Unset',\n    importPath: './path.js',\n    args: {\n      app: {\n        id: ':appId',\n        slackWebhookUrl: '',\n        customWebhookUrl: '',\n      },\n      slackWebhookUrl: '',\n      customWebhookUrl: '',\n      isSlackSaving: false,\n      isCustomSaving: false,\n      isSlackDrawerOpen: false,\n      isCustomDrawerOpen: false,\n    },\n    argTypes: {\n      app: {\n        control: {\n          type: 'object',\n        },\n        name: 'app',\n        type: {\n          name: 'object',\n          value: {\n            id: {\n              name: 'string',\n            },\n            slackWebhookUrl: {\n              name: 'string',\n            },\n            customWebhookUrl: {\n              name: 'string',\n            },\n          },\n        },\n      },\n      onUpdateApp: {\n        name: 'onUpdateApp',\n        type: {\n          name: 'function',\n        },\n      },\n      slackWebhookUrl: {\n        control: {\n          type: 'text',\n        },\n        name: 'slackWebhookUrl',\n        type: {\n          name: 'string',\n        },\n      },\n      customWebhookUrl: {\n        control: {\n          type: 'text',\n        },\n        name: 'customWebhookUrl',\n        type: {\n          name: 'string',\n        },\n      },\n      isSlackSaving: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isSlackSaving',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isCustomSaving: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isCustomSaving',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isSlackDrawerOpen: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isSlackDrawerOpen',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isCustomDrawerOpen: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isCustomDrawerOpen',\n        type: {\n          name: 'boolean',\n        },\n      },\n      toggleDrawer: {\n        name: 'toggleDrawer',\n        type: {\n          name: 'function',\n        },\n      },\n      setCustomWebhookUrl: {\n        name: 'setCustomWebhookUrl',\n        type: {\n          name: 'function',\n        },\n      },\n      setSlackWebhookUrl: {\n        name: 'setSlackWebhookUrl',\n        type: {\n          name: 'function',\n        },\n      },\n    },\n    initialArgs: {\n      app: {\n        id: ':appId',\n        slackWebhookUrl: '',\n        customWebhookUrl: '',\n      },\n      slackWebhookUrl: '',\n      customWebhookUrl: '',\n      isSlackSaving: false,\n      isCustomSaving: false,\n      isSlackDrawerOpen: false,\n      isCustomDrawerOpen: false,\n    },\n    depth: 3,\n    parent: 'webapp-screens-managescreen-integrations',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-integrations--expanded': {\n    id: 'webapp-screens-managescreen-integrations--expanded',\n    title: 'Webapp screens/ManageScreen/Integrations',\n    name: 'Expanded',\n    importPath: './path.js',\n    args: {\n      app: {\n        id: ':appId',\n        slackWebhookUrl: '',\n        customWebhookUrl: '',\n      },\n      slackWebhookUrl: '',\n      customWebhookUrl: '',\n      isSlackSaving: false,\n      isCustomSaving: false,\n      isSlackDrawerOpen: true,\n      isCustomDrawerOpen: true,\n    },\n    argTypes: {\n      app: {\n        control: {\n          type: 'object',\n        },\n        name: 'app',\n        type: {\n          name: 'object',\n          value: {\n            id: {\n              name: 'string',\n            },\n            slackWebhookUrl: {\n              name: 'string',\n            },\n            customWebhookUrl: {\n              name: 'string',\n            },\n          },\n        },\n      },\n      onUpdateApp: {\n        name: 'onUpdateApp',\n        type: {\n          name: 'function',\n        },\n      },\n      slackWebhookUrl: {\n        control: {\n          type: 'text',\n        },\n        name: 'slackWebhookUrl',\n        type: {\n          name: 'string',\n        },\n      },\n      customWebhookUrl: {\n        control: {\n          type: 'text',\n        },\n        name: 'customWebhookUrl',\n        type: {\n          name: 'string',\n        },\n      },\n      isSlackSaving: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isSlackSaving',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isCustomSaving: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isCustomSaving',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isSlackDrawerOpen: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isSlackDrawerOpen',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isCustomDrawerOpen: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isCustomDrawerOpen',\n        type: {\n          name: 'boolean',\n        },\n      },\n      toggleDrawer: {\n        name: 'toggleDrawer',\n        type: {\n          name: 'function',\n        },\n      },\n      setCustomWebhookUrl: {\n        name: 'setCustomWebhookUrl',\n        type: {\n          name: 'function',\n        },\n      },\n      setSlackWebhookUrl: {\n        name: 'setSlackWebhookUrl',\n        type: {\n          name: 'function',\n        },\n      },\n    },\n    initialArgs: {\n      app: {\n        id: ':appId',\n        slackWebhookUrl: '',\n        customWebhookUrl: '',\n      },\n      slackWebhookUrl: '',\n      customWebhookUrl: '',\n      isSlackSaving: false,\n      isCustomSaving: false,\n      isSlackDrawerOpen: true,\n      isCustomDrawerOpen: true,\n    },\n    depth: 3,\n    parent: 'webapp-screens-managescreen-integrations',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-integrations--filled': {\n    id: 'webapp-screens-managescreen-integrations--filled',\n    title: 'Webapp screens/ManageScreen/Integrations',\n    name: 'Filled',\n    importPath: './path.js',\n    args: {\n      app: {\n        id: ':appId',\n        slackWebhookUrl: '',\n        customWebhookUrl: '',\n      },\n      slackWebhookUrl: 'https://slack-webhook-url.slack.com',\n      customWebhookUrl: 'https://custom-webhook-url.example.com',\n      isSlackSaving: false,\n      isCustomSaving: false,\n      isSlackDrawerOpen: true,\n      isCustomDrawerOpen: true,\n    },\n    argTypes: {\n      app: {\n        control: {\n          type: 'object',\n        },\n        name: 'app',\n        type: {\n          name: 'object',\n          value: {\n            id: {\n              name: 'string',\n            },\n            slackWebhookUrl: {\n              name: 'string',\n            },\n            customWebhookUrl: {\n              name: 'string',\n            },\n          },\n        },\n      },\n      onUpdateApp: {\n        name: 'onUpdateApp',\n        type: {\n          name: 'function',\n        },\n      },\n      slackWebhookUrl: {\n        control: {\n          type: 'text',\n        },\n        name: 'slackWebhookUrl',\n        type: {\n          name: 'string',\n        },\n      },\n      customWebhookUrl: {\n        control: {\n          type: 'text',\n        },\n        name: 'customWebhookUrl',\n        type: {\n          name: 'string',\n        },\n      },\n      isSlackSaving: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isSlackSaving',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isCustomSaving: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isCustomSaving',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isSlackDrawerOpen: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isSlackDrawerOpen',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isCustomDrawerOpen: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isCustomDrawerOpen',\n        type: {\n          name: 'boolean',\n        },\n      },\n      toggleDrawer: {\n        name: 'toggleDrawer',\n        type: {\n          name: 'function',\n        },\n      },\n      setCustomWebhookUrl: {\n        name: 'setCustomWebhookUrl',\n        type: {\n          name: 'function',\n        },\n      },\n      setSlackWebhookUrl: {\n        name: 'setSlackWebhookUrl',\n        type: {\n          name: 'function',\n        },\n      },\n    },\n    initialArgs: {\n      app: {\n        id: ':appId',\n        slackWebhookUrl: '',\n        customWebhookUrl: '',\n      },\n      slackWebhookUrl: 'https://slack-webhook-url.slack.com',\n      customWebhookUrl: 'https://custom-webhook-url.example.com',\n      isSlackSaving: false,\n      isCustomSaving: false,\n      isSlackDrawerOpen: true,\n      isCustomDrawerOpen: true,\n    },\n    depth: 3,\n    parent: 'webapp-screens-managescreen-integrations',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-integrations--filled-overflow': {\n    id: 'webapp-screens-managescreen-integrations--filled-overflow',\n    title: 'Webapp screens/ManageScreen/Integrations',\n    name: 'Filled Overflow',\n    importPath: './path.js',\n    args: {\n      app: {\n        id: ':appId',\n        slackWebhookUrl: '',\n        customWebhookUrl: '',\n      },\n      slackWebhookUrl:\n        'https://slack-webhook-url.slack.com?some-really-long-query-string-to-make-the-url-overflow-by-a-lot',\n      customWebhookUrl:\n        'https://custom-webhook-url.example.com?some-really-long-query-string-to-make-the-url-overflow-by-a-lot',\n      isSlackSaving: false,\n      isCustomSaving: false,\n      isSlackDrawerOpen: true,\n      isCustomDrawerOpen: true,\n    },\n    argTypes: {\n      app: {\n        control: {\n          type: 'object',\n        },\n        name: 'app',\n        type: {\n          name: 'object',\n          value: {\n            id: {\n              name: 'string',\n            },\n            slackWebhookUrl: {\n              name: 'string',\n            },\n            customWebhookUrl: {\n              name: 'string',\n            },\n          },\n        },\n      },\n      onUpdateApp: {\n        name: 'onUpdateApp',\n        type: {\n          name: 'function',\n        },\n      },\n      slackWebhookUrl: {\n        control: {\n          type: 'text',\n        },\n        name: 'slackWebhookUrl',\n        type: {\n          name: 'string',\n        },\n      },\n      customWebhookUrl: {\n        control: {\n          type: 'text',\n        },\n        name: 'customWebhookUrl',\n        type: {\n          name: 'string',\n        },\n      },\n      isSlackSaving: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isSlackSaving',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isCustomSaving: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isCustomSaving',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isSlackDrawerOpen: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isSlackDrawerOpen',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isCustomDrawerOpen: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isCustomDrawerOpen',\n        type: {\n          name: 'boolean',\n        },\n      },\n      toggleDrawer: {\n        name: 'toggleDrawer',\n        type: {\n          name: 'function',\n        },\n      },\n      setCustomWebhookUrl: {\n        name: 'setCustomWebhookUrl',\n        type: {\n          name: 'function',\n        },\n      },\n      setSlackWebhookUrl: {\n        name: 'setSlackWebhookUrl',\n        type: {\n          name: 'function',\n        },\n      },\n    },\n    initialArgs: {\n      app: {\n        id: ':appId',\n        slackWebhookUrl: '',\n        customWebhookUrl: '',\n      },\n      slackWebhookUrl:\n        'https://slack-webhook-url.slack.com?some-really-long-query-string-to-make-the-url-overflow-by-a-lot',\n      customWebhookUrl:\n        'https://custom-webhook-url.example.com?some-really-long-query-string-to-make-the-url-overflow-by-a-lot',\n      isSlackSaving: false,\n      isCustomSaving: false,\n      isSlackDrawerOpen: true,\n      isCustomDrawerOpen: true,\n    },\n    depth: 3,\n    parent: 'webapp-screens-managescreen-integrations',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-integrations--saving': {\n    id: 'webapp-screens-managescreen-integrations--saving',\n    title: 'Webapp screens/ManageScreen/Integrations',\n    name: 'Saving',\n    importPath: './path.js',\n    args: {\n      app: {\n        id: ':appId',\n        slackWebhookUrl: '',\n        customWebhookUrl: '',\n      },\n      slackWebhookUrl: 'https://slack-webhook-url.slack.com',\n      customWebhookUrl: 'https://custom-webhook-url.example.com',\n      isSlackSaving: true,\n      isCustomSaving: true,\n      isSlackDrawerOpen: true,\n      isCustomDrawerOpen: true,\n    },\n    argTypes: {\n      app: {\n        control: {\n          type: 'object',\n        },\n        name: 'app',\n        type: {\n          name: 'object',\n          value: {\n            id: {\n              name: 'string',\n            },\n            slackWebhookUrl: {\n              name: 'string',\n            },\n            customWebhookUrl: {\n              name: 'string',\n            },\n          },\n        },\n      },\n      onUpdateApp: {\n        name: 'onUpdateApp',\n        type: {\n          name: 'function',\n        },\n      },\n      slackWebhookUrl: {\n        control: {\n          type: 'text',\n        },\n        name: 'slackWebhookUrl',\n        type: {\n          name: 'string',\n        },\n      },\n      customWebhookUrl: {\n        control: {\n          type: 'text',\n        },\n        name: 'customWebhookUrl',\n        type: {\n          name: 'string',\n        },\n      },\n      isSlackSaving: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isSlackSaving',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isCustomSaving: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isCustomSaving',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isSlackDrawerOpen: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isSlackDrawerOpen',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isCustomDrawerOpen: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isCustomDrawerOpen',\n        type: {\n          name: 'boolean',\n        },\n      },\n      toggleDrawer: {\n        name: 'toggleDrawer',\n        type: {\n          name: 'function',\n        },\n      },\n      setCustomWebhookUrl: {\n        name: 'setCustomWebhookUrl',\n        type: {\n          name: 'function',\n        },\n      },\n      setSlackWebhookUrl: {\n        name: 'setSlackWebhookUrl',\n        type: {\n          name: 'function',\n        },\n      },\n    },\n    initialArgs: {\n      app: {\n        id: ':appId',\n        slackWebhookUrl: '',\n        customWebhookUrl: '',\n      },\n      slackWebhookUrl: 'https://slack-webhook-url.slack.com',\n      customWebhookUrl: 'https://custom-webhook-url.example.com',\n      isSlackSaving: true,\n      isCustomSaving: true,\n      isSlackDrawerOpen: true,\n      isCustomDrawerOpen: true,\n    },\n    depth: 3,\n    parent: 'webapp-screens-managescreen-integrations',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-integrations--set': {\n    id: 'webapp-screens-managescreen-integrations--set',\n    title: 'Webapp screens/ManageScreen/Integrations',\n    name: 'Set',\n    importPath: './path.js',\n    args: {\n      app: {\n        id: ':appId',\n        slackWebhookUrl: 'https://slack-webhook-url.slack.com',\n        customWebhookUrl: 'https://custom-webhook-url.example.com',\n      },\n      slackWebhookUrl: '',\n      customWebhookUrl: '',\n      isSlackSaving: false,\n      isCustomSaving: false,\n      isSlackDrawerOpen: false,\n      isCustomDrawerOpen: false,\n    },\n    argTypes: {\n      app: {\n        control: {\n          type: 'object',\n        },\n        name: 'app',\n        type: {\n          name: 'object',\n          value: {\n            id: {\n              name: 'string',\n            },\n            slackWebhookUrl: {\n              name: 'string',\n            },\n            customWebhookUrl: {\n              name: 'string',\n            },\n          },\n        },\n      },\n      onUpdateApp: {\n        name: 'onUpdateApp',\n        type: {\n          name: 'function',\n        },\n      },\n      slackWebhookUrl: {\n        control: {\n          type: 'text',\n        },\n        name: 'slackWebhookUrl',\n        type: {\n          name: 'string',\n        },\n      },\n      customWebhookUrl: {\n        control: {\n          type: 'text',\n        },\n        name: 'customWebhookUrl',\n        type: {\n          name: 'string',\n        },\n      },\n      isSlackSaving: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isSlackSaving',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isCustomSaving: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isCustomSaving',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isSlackDrawerOpen: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isSlackDrawerOpen',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isCustomDrawerOpen: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isCustomDrawerOpen',\n        type: {\n          name: 'boolean',\n        },\n      },\n      toggleDrawer: {\n        name: 'toggleDrawer',\n        type: {\n          name: 'function',\n        },\n      },\n      setCustomWebhookUrl: {\n        name: 'setCustomWebhookUrl',\n        type: {\n          name: 'function',\n        },\n      },\n      setSlackWebhookUrl: {\n        name: 'setSlackWebhookUrl',\n        type: {\n          name: 'function',\n        },\n      },\n    },\n    initialArgs: {\n      app: {\n        id: ':appId',\n        slackWebhookUrl: 'https://slack-webhook-url.slack.com',\n        customWebhookUrl: 'https://custom-webhook-url.example.com',\n      },\n      slackWebhookUrl: '',\n      customWebhookUrl: '',\n      isSlackSaving: false,\n      isCustomSaving: false,\n      isSlackDrawerOpen: false,\n      isCustomDrawerOpen: false,\n    },\n    depth: 3,\n    parent: 'webapp-screens-managescreen-integrations',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-integrations--set-overflow': {\n    id: 'webapp-screens-managescreen-integrations--set-overflow',\n    title: 'Webapp screens/ManageScreen/Integrations',\n    name: 'Set Overflow',\n    importPath: './path.js',\n    args: {\n      app: {\n        id: ':appId',\n        slackWebhookUrl:\n          'https://slack-webhook-url.slack.com?some-really-long-query-string-to-make-the-url-overflow-by-a-lot',\n        customWebhookUrl:\n          'https://custom-webhook-url.example.com?some-really-long-query-string-to-make-the-url-overflow-by-a-lot',\n      },\n      slackWebhookUrl: '',\n      customWebhookUrl: '',\n      isSlackSaving: false,\n      isCustomSaving: false,\n      isSlackDrawerOpen: false,\n      isCustomDrawerOpen: false,\n    },\n    argTypes: {\n      app: {\n        control: {\n          type: 'object',\n        },\n        name: 'app',\n        type: {\n          name: 'object',\n          value: {\n            id: {\n              name: 'string',\n            },\n            slackWebhookUrl: {\n              name: 'string',\n            },\n            customWebhookUrl: {\n              name: 'string',\n            },\n          },\n        },\n      },\n      onUpdateApp: {\n        name: 'onUpdateApp',\n        type: {\n          name: 'function',\n        },\n      },\n      slackWebhookUrl: {\n        control: {\n          type: 'text',\n        },\n        name: 'slackWebhookUrl',\n        type: {\n          name: 'string',\n        },\n      },\n      customWebhookUrl: {\n        control: {\n          type: 'text',\n        },\n        name: 'customWebhookUrl',\n        type: {\n          name: 'string',\n        },\n      },\n      isSlackSaving: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isSlackSaving',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isCustomSaving: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isCustomSaving',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isSlackDrawerOpen: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isSlackDrawerOpen',\n        type: {\n          name: 'boolean',\n        },\n      },\n      isCustomDrawerOpen: {\n        control: {\n          type: 'boolean',\n        },\n        name: 'isCustomDrawerOpen',\n        type: {\n          name: 'boolean',\n        },\n      },\n      toggleDrawer: {\n        name: 'toggleDrawer',\n        type: {\n          name: 'function',\n        },\n      },\n      setCustomWebhookUrl: {\n        name: 'setCustomWebhookUrl',\n        type: {\n          name: 'function',\n        },\n      },\n      setSlackWebhookUrl: {\n        name: 'setSlackWebhookUrl',\n        type: {\n          name: 'function',\n        },\n      },\n    },\n    initialArgs: {\n      app: {\n        id: ':appId',\n        slackWebhookUrl:\n          'https://slack-webhook-url.slack.com?some-really-long-query-string-to-make-the-url-overflow-by-a-lot',\n        customWebhookUrl:\n          'https://custom-webhook-url.example.com?some-really-long-query-string-to-make-the-url-overflow-by-a-lot',\n      },\n      slackWebhookUrl: '',\n      customWebhookUrl: '',\n      isSlackSaving: false,\n      isCustomSaving: false,\n      isSlackDrawerOpen: false,\n      isCustomDrawerOpen: false,\n    },\n    depth: 3,\n    parent: 'webapp-screens-managescreen-integrations',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-managescreen': {\n    name: 'ManageScreen',\n    id: 'webapp-screens-managescreen-managescreen',\n    parent: 'webapp-screens-managescreen',\n    depth: 2,\n    children: [\n      'webapp-screens-managescreen-managescreen--loading',\n      'webapp-screens-managescreen-managescreen--unlinked-one-user',\n      'webapp-screens-managescreen-managescreen--unlinked-one-user-no-invite-url',\n      'webapp-screens-managescreen-managescreen--unlinked-one-user-no-invite-url-saml',\n      'webapp-screens-managescreen-managescreen--unlinked-multiple-users',\n      'webapp-screens-managescreen-managescreen--unlinked-cross-browser',\n      'webapp-screens-managescreen-managescreen--linked',\n      'webapp-screens-managescreen-managescreen--linked-refreshing',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-managescreen-managescreen--loading': {\n    id: 'webapp-screens-managescreen-managescreen--loading',\n    title: 'Webapp screens/ManageScreen/ManageScreen',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-managescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-managescreen--unlinked-one-user': {\n    id: 'webapp-screens-managescreen-managescreen--unlinked-one-user',\n    title: 'Webapp screens/ManageScreen/ManageScreen',\n    name: 'unlinked one user',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-managescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-managescreen--unlinked-one-user-no-invite-url': {\n    id: 'webapp-screens-managescreen-managescreen--unlinked-one-user-no-invite-url',\n    title: 'Webapp screens/ManageScreen/ManageScreen',\n    name: 'unlinked one user, no invite url',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-managescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-managescreen--unlinked-one-user-no-invite-url-saml': {\n    id: 'webapp-screens-managescreen-managescreen--unlinked-one-user-no-invite-url-saml',\n    title: 'Webapp screens/ManageScreen/ManageScreen',\n    name: 'unlinked one user, no invite url, saml',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-managescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-managescreen--unlinked-multiple-users': {\n    id: 'webapp-screens-managescreen-managescreen--unlinked-multiple-users',\n    title: 'Webapp screens/ManageScreen/ManageScreen',\n    name: 'unlinked multiple users',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-managescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-managescreen--unlinked-cross-browser': {\n    id: 'webapp-screens-managescreen-managescreen--unlinked-cross-browser',\n    title: 'Webapp screens/ManageScreen/ManageScreen',\n    name: 'unlinked, cross browser',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-managescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-managescreen--linked': {\n    id: 'webapp-screens-managescreen-managescreen--linked',\n    title: 'Webapp screens/ManageScreen/ManageScreen',\n    name: 'linked',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-managescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-managescreen--linked-refreshing': {\n    id: 'webapp-screens-managescreen-managescreen--linked-refreshing',\n    title: 'Webapp screens/ManageScreen/ManageScreen',\n    name: 'linked, refreshing',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-managescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-uireview': {\n    name: 'UIReview',\n    id: 'webapp-screens-managescreen-uireview',\n    parent: 'webapp-screens-managescreen',\n    depth: 2,\n    children: [\n      'webapp-screens-managescreen-uireview--loading',\n      'webapp-screens-managescreen-uireview--enabled',\n      'webapp-screens-managescreen-uireview--enabled-updating',\n      'webapp-screens-managescreen-uireview--just-enabled',\n      'webapp-screens-managescreen-uireview--enabled-exceeded-threshold',\n      'webapp-screens-managescreen-uireview--enabled-payment-required',\n      'webapp-screens-managescreen-uireview--disabled',\n      'webapp-screens-managescreen-uireview--disabled-updating',\n      'webapp-screens-managescreen-uireview--just-disabled',\n      'webapp-screens-managescreen-uireview--just-disabled-paused',\n      'webapp-screens-managescreen-uireview--disabled-exceeded-threshold',\n      'webapp-screens-managescreen-uireview--disabled-exceeded-threshold-org',\n      'webapp-screens-managescreen-uireview--disabled-payment-required',\n      'webapp-screens-managescreen-uireview--unlinked',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-managescreen-uireview--loading': {\n    id: 'webapp-screens-managescreen-uireview--loading',\n    title: 'Webapp screens/ManageScreen/UIReview',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-uireview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-uireview--enabled': {\n    id: 'webapp-screens-managescreen-uireview--enabled',\n    title: 'Webapp screens/ManageScreen/UIReview',\n    name: 'Enabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-uireview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-uireview--enabled-updating': {\n    id: 'webapp-screens-managescreen-uireview--enabled-updating',\n    title: 'Webapp screens/ManageScreen/UIReview',\n    name: 'Enabled, Updating',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-uireview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-uireview--just-enabled': {\n    id: 'webapp-screens-managescreen-uireview--just-enabled',\n    title: 'Webapp screens/ManageScreen/UIReview',\n    name: 'Just Enabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-uireview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-uireview--enabled-exceeded-threshold': {\n    id: 'webapp-screens-managescreen-uireview--enabled-exceeded-threshold',\n    title: 'Webapp screens/ManageScreen/UIReview',\n    name: 'Enabled, Exceeded Threshold',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-uireview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-uireview--enabled-payment-required': {\n    id: 'webapp-screens-managescreen-uireview--enabled-payment-required',\n    title: 'Webapp screens/ManageScreen/UIReview',\n    name: 'Enabled, Payment Required',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-uireview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-uireview--disabled': {\n    id: 'webapp-screens-managescreen-uireview--disabled',\n    title: 'Webapp screens/ManageScreen/UIReview',\n    name: 'Disabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-uireview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-uireview--disabled-updating': {\n    id: 'webapp-screens-managescreen-uireview--disabled-updating',\n    title: 'Webapp screens/ManageScreen/UIReview',\n    name: 'Disabled, Updating',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-uireview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-uireview--just-disabled': {\n    id: 'webapp-screens-managescreen-uireview--just-disabled',\n    title: 'Webapp screens/ManageScreen/UIReview',\n    name: 'Just Disabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-uireview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-uireview--just-disabled-paused': {\n    id: 'webapp-screens-managescreen-uireview--just-disabled-paused',\n    title: 'Webapp screens/ManageScreen/UIReview',\n    name: 'Just Disabled Paused',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-uireview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-uireview--disabled-exceeded-threshold': {\n    id: 'webapp-screens-managescreen-uireview--disabled-exceeded-threshold',\n    title: 'Webapp screens/ManageScreen/UIReview',\n    name: 'Disabled, Exceeded Threshold',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-uireview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-uireview--disabled-exceeded-threshold-org': {\n    id: 'webapp-screens-managescreen-uireview--disabled-exceeded-threshold-org',\n    title: 'Webapp screens/ManageScreen/UIReview',\n    name: 'Disabled, Exceeded Threshold, Org',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-uireview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-uireview--disabled-payment-required': {\n    id: 'webapp-screens-managescreen-uireview--disabled-payment-required',\n    title: 'Webapp screens/ManageScreen/UIReview',\n    name: 'Disabled, Payment Required',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-uireview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-uireview--unlinked': {\n    id: 'webapp-screens-managescreen-uireview--unlinked',\n    title: 'Webapp screens/ManageScreen/UIReview',\n    name: 'Unlinked',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-uireview',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-visualtests': {\n    name: 'VisualTests',\n    id: 'webapp-screens-managescreen-visualtests',\n    parent: 'webapp-screens-managescreen',\n    depth: 2,\n    children: [\n      'webapp-screens-managescreen-visualtests--loading',\n      'webapp-screens-managescreen-visualtests--enabled',\n      'webapp-screens-managescreen-visualtests--enabled-updating',\n      'webapp-screens-managescreen-visualtests--just-enabled',\n      'webapp-screens-managescreen-visualtests--just-enabled-two-browsers',\n      'webapp-screens-managescreen-visualtests--just-enabled-three-browsers',\n      'webapp-screens-managescreen-visualtests--enabled-no-snapshots',\n      'webapp-screens-managescreen-visualtests--enabled-payment-required',\n      'webapp-screens-managescreen-visualtests--disabled-has-snapshots',\n      'webapp-screens-managescreen-visualtests--disabled-updating',\n      'webapp-screens-managescreen-visualtests--disabled-no-snapshots',\n      'webapp-screens-managescreen-visualtests--disabled-no-snapshots-org',\n      'webapp-screens-managescreen-visualtests--disabled-payment-required',\n      'webapp-screens-managescreen-visualtests--capture-stack-upgrade-available',\n      'webapp-screens-managescreen-visualtests--capture-stack-upgrading',\n      'webapp-screens-managescreen-visualtests--capture-stack-just-upgraded',\n      'webapp-screens-managescreen-visualtests--capture-stack-downgrade-available',\n      'webapp-screens-managescreen-visualtests--capture-stack-downgrading',\n      'webapp-screens-managescreen-visualtests--capture-stack-just-downgraded',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-managescreen-visualtests--loading': {\n    id: 'webapp-screens-managescreen-visualtests--loading',\n    title: 'Webapp screens/ManageScreen/VisualTests',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-visualtests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-visualtests--enabled': {\n    id: 'webapp-screens-managescreen-visualtests--enabled',\n    title: 'Webapp screens/ManageScreen/VisualTests',\n    name: 'Enabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-visualtests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-visualtests--enabled-updating': {\n    id: 'webapp-screens-managescreen-visualtests--enabled-updating',\n    title: 'Webapp screens/ManageScreen/VisualTests',\n    name: 'Enabled, Updating',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-visualtests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-visualtests--just-enabled': {\n    id: 'webapp-screens-managescreen-visualtests--just-enabled',\n    title: 'Webapp screens/ManageScreen/VisualTests',\n    name: 'Just Enabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-visualtests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-visualtests--just-enabled-two-browsers': {\n    id: 'webapp-screens-managescreen-visualtests--just-enabled-two-browsers',\n    title: 'Webapp screens/ManageScreen/VisualTests',\n    name: 'Just Enabled Two Browsers',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-visualtests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-visualtests--just-enabled-three-browsers': {\n    id: 'webapp-screens-managescreen-visualtests--just-enabled-three-browsers',\n    title: 'Webapp screens/ManageScreen/VisualTests',\n    name: 'Just Enabled Three Browsers',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-visualtests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-visualtests--enabled-no-snapshots': {\n    id: 'webapp-screens-managescreen-visualtests--enabled-no-snapshots',\n    title: 'Webapp screens/ManageScreen/VisualTests',\n    name: 'Enabled, No Snapshots',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-visualtests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-visualtests--enabled-payment-required': {\n    id: 'webapp-screens-managescreen-visualtests--enabled-payment-required',\n    title: 'Webapp screens/ManageScreen/VisualTests',\n    name: 'Enabled, Payment Required',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-visualtests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-visualtests--disabled-has-snapshots': {\n    id: 'webapp-screens-managescreen-visualtests--disabled-has-snapshots',\n    title: 'Webapp screens/ManageScreen/VisualTests',\n    name: 'Disabled, Has Snapshots',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-visualtests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-visualtests--disabled-updating': {\n    id: 'webapp-screens-managescreen-visualtests--disabled-updating',\n    title: 'Webapp screens/ManageScreen/VisualTests',\n    name: 'Disabled, Updating',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-visualtests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-visualtests--disabled-no-snapshots': {\n    id: 'webapp-screens-managescreen-visualtests--disabled-no-snapshots',\n    title: 'Webapp screens/ManageScreen/VisualTests',\n    name: 'Disabled, No Snapshots',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-visualtests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-visualtests--disabled-no-snapshots-org': {\n    id: 'webapp-screens-managescreen-visualtests--disabled-no-snapshots-org',\n    title: 'Webapp screens/ManageScreen/VisualTests',\n    name: 'Disabled, No Snapshots, Org',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-visualtests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-visualtests--disabled-payment-required': {\n    id: 'webapp-screens-managescreen-visualtests--disabled-payment-required',\n    title: 'Webapp screens/ManageScreen/VisualTests',\n    name: 'Disabled, Payment Required',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-visualtests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-visualtests--capture-stack-upgrade-available': {\n    id: 'webapp-screens-managescreen-visualtests--capture-stack-upgrade-available',\n    title: 'Webapp screens/ManageScreen/VisualTests',\n    name: 'Capture Stack Upgrade Available',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-visualtests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-visualtests--capture-stack-upgrading': {\n    id: 'webapp-screens-managescreen-visualtests--capture-stack-upgrading',\n    title: 'Webapp screens/ManageScreen/VisualTests',\n    name: 'Capture Stack Upgrading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-visualtests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-visualtests--capture-stack-just-upgraded': {\n    id: 'webapp-screens-managescreen-visualtests--capture-stack-just-upgraded',\n    title: 'Webapp screens/ManageScreen/VisualTests',\n    name: 'Capture Stack Just Upgraded',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-visualtests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-visualtests--capture-stack-downgrade-available': {\n    id: 'webapp-screens-managescreen-visualtests--capture-stack-downgrade-available',\n    title: 'Webapp screens/ManageScreen/VisualTests',\n    name: 'Capture Stack Downgrade Available',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-visualtests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-visualtests--capture-stack-downgrading': {\n    id: 'webapp-screens-managescreen-visualtests--capture-stack-downgrading',\n    title: 'Webapp screens/ManageScreen/VisualTests',\n    name: 'Capture Stack Downgrading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-visualtests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-managescreen-visualtests--capture-stack-just-downgraded': {\n    id: 'webapp-screens-managescreen-visualtests--capture-stack-just-downgraded',\n    title: 'Webapp screens/ManageScreen/VisualTests',\n    name: 'Capture Stack Just Downgraded',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-managescreen-visualtests',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing': {\n    name: 'Marketing',\n    id: 'webapp-screens-marketing',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: [\n      'webapp-screens-marketing-articles',\n      'webapp-screens-marketing-companyscreen',\n      'webapp-screens-marketing-comparescreen',\n      'webapp-screens-marketing-cta',\n      'webapp-screens-marketing-faq',\n      'webapp-screens-marketing-feature',\n      'webapp-screens-marketing-featurecallout',\n      'webapp-screens-marketing-featuresscreens',\n      'webapp-screens-marketing-hero',\n      'webapp-screens-marketing-integrations',\n      'webapp-screens-marketing-landingscreen',\n      'webapp-screens-marketing-marketingfooter',\n      'webapp-screens-marketing-marketingheader',\n      'webapp-screens-marketing-marketingpagetitle',\n      'webapp-screens-marketing-personascreens',\n      'webapp-screens-marketing-pricingscreen',\n      'webapp-screens-marketing-socialproof',\n      'webapp-screens-marketing-testimonial',\n      'webapp-screens-marketing-testimonials',\n      'webapp-screens-marketing-valueprop',\n      'webapp-screens-marketing-workflows',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-marketing-articles': {\n    name: 'Articles',\n    id: 'webapp-screens-marketing-articles',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: ['webapp-screens-marketing-articles--default'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-articles--default': {\n    id: 'webapp-screens-marketing-articles--default',\n    title: 'Webapp screens/Marketing/Articles',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-articles',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-companyscreen': {\n    name: 'CompanyScreen',\n    id: 'webapp-screens-marketing-companyscreen',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: [\n      'webapp-screens-marketing-companyscreen-aboutscreen',\n      'webapp-screens-marketing-companyscreen-jobsscreen',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-marketing-companyscreen-aboutscreen': {\n    name: 'AboutScreen',\n    id: 'webapp-screens-marketing-companyscreen-aboutscreen',\n    parent: 'webapp-screens-marketing-companyscreen',\n    depth: 3,\n    children: ['webapp-screens-marketing-companyscreen-aboutscreen--base'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-companyscreen-aboutscreen--base': {\n    id: 'webapp-screens-marketing-companyscreen-aboutscreen--base',\n    title: 'Webapp screens/Marketing/CompanyScreen/AboutScreen',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-companyscreen-aboutscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-companyscreen-jobsscreen': {\n    name: 'JobsScreen',\n    id: 'webapp-screens-marketing-companyscreen-jobsscreen',\n    parent: 'webapp-screens-marketing-companyscreen',\n    depth: 3,\n    children: ['webapp-screens-marketing-companyscreen-jobsscreen--base'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-companyscreen-jobsscreen--base': {\n    id: 'webapp-screens-marketing-companyscreen-jobsscreen--base',\n    title: 'Webapp screens/Marketing/CompanyScreen/JobsScreen',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-companyscreen-jobsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-comparescreen': {\n    name: 'CompareScreen',\n    id: 'webapp-screens-marketing-comparescreen',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: [\n      'webapp-screens-marketing-comparescreen-comparelayout',\n      'webapp-screens-marketing-comparescreen-comparescreen',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-marketing-comparescreen-comparelayout': {\n    name: 'CompareLayout',\n    id: 'webapp-screens-marketing-comparescreen-comparelayout',\n    parent: 'webapp-screens-marketing-comparescreen',\n    depth: 3,\n    children: [\n      'webapp-screens-marketing-comparescreen-comparelayout--default',\n      'webapp-screens-marketing-comparescreen-comparelayout--arc',\n      'webapp-screens-marketing-comparescreen-comparelayout--rect',\n      'webapp-screens-marketing-comparescreen-comparelayout--tetrisl',\n      'webapp-screens-marketing-comparescreen-comparelayout--tetriss',\n      'webapp-screens-marketing-comparescreen-comparelayout--tetrist',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-marketing-comparescreen-comparelayout--default': {\n    id: 'webapp-screens-marketing-comparescreen-comparelayout--default',\n    title: 'Webapp screens/Marketing/CompareScreen/CompareLayout',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-comparescreen-comparelayout',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-comparescreen-comparelayout--arc': {\n    id: 'webapp-screens-marketing-comparescreen-comparelayout--arc',\n    title: 'Webapp screens/Marketing/CompareScreen/CompareLayout',\n    name: 'arc',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-comparescreen-comparelayout',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-comparescreen-comparelayout--rect': {\n    id: 'webapp-screens-marketing-comparescreen-comparelayout--rect',\n    title: 'Webapp screens/Marketing/CompareScreen/CompareLayout',\n    name: 'rect',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-comparescreen-comparelayout',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-comparescreen-comparelayout--tetrisl': {\n    id: 'webapp-screens-marketing-comparescreen-comparelayout--tetrisl',\n    title: 'Webapp screens/Marketing/CompareScreen/CompareLayout',\n    name: 'tetrisl',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-comparescreen-comparelayout',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-comparescreen-comparelayout--tetriss': {\n    id: 'webapp-screens-marketing-comparescreen-comparelayout--tetriss',\n    title: 'Webapp screens/Marketing/CompareScreen/CompareLayout',\n    name: 'tetriss',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-comparescreen-comparelayout',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-comparescreen-comparelayout--tetrist': {\n    id: 'webapp-screens-marketing-comparescreen-comparelayout--tetrist',\n    title: 'Webapp screens/Marketing/CompareScreen/CompareLayout',\n    name: 'tetrist',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-comparescreen-comparelayout',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-comparescreen-comparescreen': {\n    name: 'CompareScreen',\n    id: 'webapp-screens-marketing-comparescreen-comparescreen',\n    parent: 'webapp-screens-marketing-comparescreen',\n    depth: 3,\n    children: [\n      'webapp-screens-marketing-comparescreen-comparescreen--chromatic',\n      'webapp-screens-marketing-comparescreen-comparescreen--jest-image-snapshot',\n      'webapp-screens-marketing-comparescreen-comparescreen--backstop-js',\n      'webapp-screens-marketing-comparescreen-comparescreen--percy',\n      'webapp-screens-marketing-comparescreen-comparescreen--screener',\n      'webapp-screens-marketing-comparescreen-comparescreen--applitools',\n      'webapp-screens-marketing-comparescreen-comparescreen--visual-testing',\n      'webapp-screens-marketing-comparescreen-comparescreen--deploy-storybook',\n      'webapp-screens-marketing-comparescreen-comparescreen--netlify',\n      'webapp-screens-marketing-comparescreen-comparescreen--vercel',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-marketing-comparescreen-comparescreen--chromatic': {\n    id: 'webapp-screens-marketing-comparescreen-comparescreen--chromatic',\n    title: 'Webapp screens/Marketing/CompareScreen/CompareScreen',\n    name: 'Chromatic',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-comparescreen-comparescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-comparescreen-comparescreen--jest-image-snapshot': {\n    id: 'webapp-screens-marketing-comparescreen-comparescreen--jest-image-snapshot',\n    title: 'Webapp screens/Marketing/CompareScreen/CompareScreen',\n    name: 'Jest image snapshot',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-comparescreen-comparescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-comparescreen-comparescreen--backstop-js': {\n    id: 'webapp-screens-marketing-comparescreen-comparescreen--backstop-js',\n    title: 'Webapp screens/Marketing/CompareScreen/CompareScreen',\n    name: 'BackstopJS',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-comparescreen-comparescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-comparescreen-comparescreen--percy': {\n    id: 'webapp-screens-marketing-comparescreen-comparescreen--percy',\n    title: 'Webapp screens/Marketing/CompareScreen/CompareScreen',\n    name: 'Percy',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-comparescreen-comparescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-comparescreen-comparescreen--screener': {\n    id: 'webapp-screens-marketing-comparescreen-comparescreen--screener',\n    title: 'Webapp screens/Marketing/CompareScreen/CompareScreen',\n    name: 'Screener',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-comparescreen-comparescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-comparescreen-comparescreen--applitools': {\n    id: 'webapp-screens-marketing-comparescreen-comparescreen--applitools',\n    title: 'Webapp screens/Marketing/CompareScreen/CompareScreen',\n    name: 'Applitools',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-comparescreen-comparescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-comparescreen-comparescreen--visual-testing': {\n    id: 'webapp-screens-marketing-comparescreen-comparescreen--visual-testing',\n    title: 'Webapp screens/Marketing/CompareScreen/CompareScreen',\n    name: 'Visual testing overview',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-comparescreen-comparescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-comparescreen-comparescreen--deploy-storybook': {\n    id: 'webapp-screens-marketing-comparescreen-comparescreen--deploy-storybook',\n    title: 'Webapp screens/Marketing/CompareScreen/CompareScreen',\n    name: 'Deploy Storybook overview',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-comparescreen-comparescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-comparescreen-comparescreen--netlify': {\n    id: 'webapp-screens-marketing-comparescreen-comparescreen--netlify',\n    title: 'Webapp screens/Marketing/CompareScreen/CompareScreen',\n    name: 'Netlify',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-comparescreen-comparescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-comparescreen-comparescreen--vercel': {\n    id: 'webapp-screens-marketing-comparescreen-comparescreen--vercel',\n    title: 'Webapp screens/Marketing/CompareScreen/CompareScreen',\n    name: 'Vercel',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-comparescreen-comparescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-cta': {\n    name: 'CTA',\n    id: 'webapp-screens-marketing-cta',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: ['webapp-screens-marketing-cta--default'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-cta--default': {\n    id: 'webapp-screens-marketing-cta--default',\n    title: 'Webapp screens/Marketing/CTA',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-cta',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-faq': {\n    name: 'FAQ',\n    id: 'webapp-screens-marketing-faq',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: ['webapp-screens-marketing-faq--default'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-faq--default': {\n    id: 'webapp-screens-marketing-faq--default',\n    title: 'Webapp screens/Marketing/FAQ',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-faq',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-feature': {\n    name: 'Feature',\n    id: 'webapp-screens-marketing-feature',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: [\n      'webapp-screens-marketing-feature--default',\n      'webapp-screens-marketing-feature--w-children',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-marketing-feature--default': {\n    id: 'webapp-screens-marketing-feature--default',\n    title: 'Webapp screens/Marketing/Feature',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-feature',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-feature--w-children': {\n    id: 'webapp-screens-marketing-feature--w-children',\n    title: 'Webapp screens/Marketing/Feature',\n    name: 'w/children',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-feature',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featurecallout': {\n    name: 'FeatureCallout',\n    id: 'webapp-screens-marketing-featurecallout',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: ['webapp-screens-marketing-featurecallout--default'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-featurecallout--default': {\n    id: 'webapp-screens-marketing-featurecallout--default',\n    title: 'Webapp screens/Marketing/FeatureCallout',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-featurecallout',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens': {\n    name: 'FeaturesScreens',\n    id: 'webapp-screens-marketing-featuresscreens',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: [\n      'webapp-screens-marketing-featuresscreens-documentscreen',\n      'webapp-screens-marketing-featuresscreens-featuresscreenshero',\n      'webapp-screens-marketing-featuresscreens-publishscreen',\n      'webapp-screens-marketing-featuresscreens-testscreen',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-marketing-featuresscreens-documentscreen': {\n    name: 'DocumentScreen',\n    id: 'webapp-screens-marketing-featuresscreens-documentscreen',\n    parent: 'webapp-screens-marketing-featuresscreens',\n    depth: 3,\n    children: [\n      'webapp-screens-marketing-featuresscreens-documentscreen--base',\n      'webapp-screens-marketing-featuresscreens-documentscreen-componentexample',\n      'webapp-screens-marketing-featuresscreens-documentscreen-documentanimation',\n      'webapp-screens-marketing-featuresscreens-documentscreen-documentscreenhero',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-marketing-featuresscreens-documentscreen--base': {\n    id: 'webapp-screens-marketing-featuresscreens-documentscreen--base',\n    title: 'Webapp screens/Marketing/FeaturesScreens/DocumentScreen',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-featuresscreens-documentscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-documentscreen-componentexample': {\n    name: 'ComponentExample',\n    id: 'webapp-screens-marketing-featuresscreens-documentscreen-componentexample',\n    parent: 'webapp-screens-marketing-featuresscreens-documentscreen',\n    depth: 4,\n    children: [\n      'webapp-screens-marketing-featuresscreens-documentscreen-componentexample--base',\n      'webapp-screens-marketing-featuresscreens-documentscreen-componentexample--did-activate-docs',\n      'webapp-screens-marketing-featuresscreens-documentscreen-componentexample--pure-snapshot',\n      'webapp-screens-marketing-featuresscreens-documentscreen-componentexample--pure-snapshot-ff',\n      'webapp-screens-marketing-featuresscreens-documentscreen-componentexample--pure-docs',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-marketing-featuresscreens-documentscreen-componentexample--base': {\n    id: 'webapp-screens-marketing-featuresscreens-documentscreen-componentexample--base',\n    title: 'Webapp screens/Marketing/FeaturesScreens/DocumentScreen/ComponentExample',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-documentscreen-componentexample',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-documentscreen-componentexample--did-activate-docs': {\n    id: 'webapp-screens-marketing-featuresscreens-documentscreen-componentexample--did-activate-docs',\n    title: 'Webapp screens/Marketing/FeaturesScreens/DocumentScreen/ComponentExample',\n    name: 'Did Activate Docs',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-documentscreen-componentexample',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-documentscreen-componentexample--pure-snapshot': {\n    id: 'webapp-screens-marketing-featuresscreens-documentscreen-componentexample--pure-snapshot',\n    title: 'Webapp screens/Marketing/FeaturesScreens/DocumentScreen/ComponentExample',\n    name: 'Pure, Snapshot View',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-documentscreen-componentexample',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-documentscreen-componentexample--pure-snapshot-ff': {\n    id: 'webapp-screens-marketing-featuresscreens-documentscreen-componentexample--pure-snapshot-ff',\n    title: 'Webapp screens/Marketing/FeaturesScreens/DocumentScreen/ComponentExample',\n    name: 'Pure, Snapshot View, Firefox',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-documentscreen-componentexample',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-documentscreen-componentexample--pure-docs': {\n    id: 'webapp-screens-marketing-featuresscreens-documentscreen-componentexample--pure-docs',\n    title: 'Webapp screens/Marketing/FeaturesScreens/DocumentScreen/ComponentExample',\n    name: 'Pure, Docs View',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-documentscreen-componentexample',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-documentscreen-documentanimation': {\n    name: 'DocumentAnimation',\n    id: 'webapp-screens-marketing-featuresscreens-documentscreen-documentanimation',\n    parent: 'webapp-screens-marketing-featuresscreens-documentscreen',\n    depth: 4,\n    children: [\n      'webapp-screens-marketing-featuresscreens-documentscreen-documentanimation--base',\n      'webapp-screens-marketing-featuresscreens-documentscreen-documentanimation--cutoff',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-marketing-featuresscreens-documentscreen-documentanimation--base': {\n    id: 'webapp-screens-marketing-featuresscreens-documentscreen-documentanimation--base',\n    title: 'Webapp screens/Marketing/FeaturesScreens/DocumentScreen/DocumentAnimation',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-documentscreen-documentanimation',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-documentscreen-documentanimation--cutoff': {\n    id: 'webapp-screens-marketing-featuresscreens-documentscreen-documentanimation--cutoff',\n    title: 'Webapp screens/Marketing/FeaturesScreens/DocumentScreen/DocumentAnimation',\n    name: 'Cutoff',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-documentscreen-documentanimation',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-documentscreen-documentscreenhero': {\n    name: 'DocumentScreenHero',\n    id: 'webapp-screens-marketing-featuresscreens-documentscreen-documentscreenhero',\n    parent: 'webapp-screens-marketing-featuresscreens-documentscreen',\n    depth: 4,\n    children: [\n      'webapp-screens-marketing-featuresscreens-documentscreen-documentscreenhero--base',\n      'webapp-screens-marketing-featuresscreens-documentscreen-documentscreenhero--maintenance-mode',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-marketing-featuresscreens-documentscreen-documentscreenhero--base': {\n    id: 'webapp-screens-marketing-featuresscreens-documentscreen-documentscreenhero--base',\n    title: 'Webapp screens/Marketing/FeaturesScreens/DocumentScreen/DocumentScreenHero',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-documentscreen-documentscreenhero',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-documentscreen-documentscreenhero--maintenance-mode': {\n    id: 'webapp-screens-marketing-featuresscreens-documentscreen-documentscreenhero--maintenance-mode',\n    title: 'Webapp screens/Marketing/FeaturesScreens/DocumentScreen/DocumentScreenHero',\n    name: 'Maintenance Mode',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-documentscreen-documentscreenhero',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-featuresscreenshero': {\n    name: 'FeaturesScreensHero',\n    id: 'webapp-screens-marketing-featuresscreens-featuresscreenshero',\n    parent: 'webapp-screens-marketing-featuresscreens',\n    depth: 3,\n    children: ['webapp-screens-marketing-featuresscreens-featuresscreenshero--base'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-featuresscreens-featuresscreenshero--base': {\n    id: 'webapp-screens-marketing-featuresscreens-featuresscreenshero--base',\n    title: 'Webapp screens/Marketing/FeaturesScreens/FeaturesScreensHero',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-featuresscreens-featuresscreenshero',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-publishscreen': {\n    name: 'PublishScreen',\n    id: 'webapp-screens-marketing-featuresscreens-publishscreen',\n    parent: 'webapp-screens-marketing-featuresscreens',\n    depth: 3,\n    children: [\n      'webapp-screens-marketing-featuresscreens-publishscreen--base',\n      'webapp-screens-marketing-featuresscreens-publishscreen-feedbackanimation',\n      'webapp-screens-marketing-featuresscreens-publishscreen-publishscreenhero',\n      'webapp-screens-marketing-featuresscreens-publishscreen-review',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-marketing-featuresscreens-publishscreen--base': {\n    id: 'webapp-screens-marketing-featuresscreens-publishscreen--base',\n    title: 'Webapp screens/Marketing/FeaturesScreens/PublishScreen',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-featuresscreens-publishscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-publishscreen-feedbackanimation': {\n    name: 'FeedbackAnimation',\n    id: 'webapp-screens-marketing-featuresscreens-publishscreen-feedbackanimation',\n    parent: 'webapp-screens-marketing-featuresscreens-publishscreen',\n    depth: 4,\n    children: [\n      'webapp-screens-marketing-featuresscreens-publishscreen-feedbackanimation--base',\n      'webapp-screens-marketing-featuresscreens-publishscreen-feedbackanimation--no-animation',\n      'webapp-screens-marketing-featuresscreens-publishscreen-feedbackanimation--cutoff',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-marketing-featuresscreens-publishscreen-feedbackanimation--base': {\n    id: 'webapp-screens-marketing-featuresscreens-publishscreen-feedbackanimation--base',\n    title: 'Webapp screens/Marketing/FeaturesScreens/PublishScreen/FeedbackAnimation',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-publishscreen-feedbackanimation',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-publishscreen-feedbackanimation--no-animation': {\n    id: 'webapp-screens-marketing-featuresscreens-publishscreen-feedbackanimation--no-animation',\n    title: 'Webapp screens/Marketing/FeaturesScreens/PublishScreen/FeedbackAnimation',\n    name: 'No Animation',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-publishscreen-feedbackanimation',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-publishscreen-feedbackanimation--cutoff': {\n    id: 'webapp-screens-marketing-featuresscreens-publishscreen-feedbackanimation--cutoff',\n    title: 'Webapp screens/Marketing/FeaturesScreens/PublishScreen/FeedbackAnimation',\n    name: 'Cutoff',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-publishscreen-feedbackanimation',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-publishscreen-publishscreenhero': {\n    name: 'PublishScreenHero',\n    id: 'webapp-screens-marketing-featuresscreens-publishscreen-publishscreenhero',\n    parent: 'webapp-screens-marketing-featuresscreens-publishscreen',\n    depth: 4,\n    children: [\n      'webapp-screens-marketing-featuresscreens-publishscreen-publishscreenhero--base',\n      'webapp-screens-marketing-featuresscreens-publishscreen-publishscreenhero--maintenance-mode',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-marketing-featuresscreens-publishscreen-publishscreenhero--base': {\n    id: 'webapp-screens-marketing-featuresscreens-publishscreen-publishscreenhero--base',\n    title: 'Webapp screens/Marketing/FeaturesScreens/PublishScreen/PublishScreenHero',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-publishscreen-publishscreenhero',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-publishscreen-publishscreenhero--maintenance-mode': {\n    id: 'webapp-screens-marketing-featuresscreens-publishscreen-publishscreenhero--maintenance-mode',\n    title: 'Webapp screens/Marketing/FeaturesScreens/PublishScreen/PublishScreenHero',\n    name: 'Maintenance Mode',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-publishscreen-publishscreenhero',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-publishscreen-review': {\n    name: 'Review',\n    id: 'webapp-screens-marketing-featuresscreens-publishscreen-review',\n    parent: 'webapp-screens-marketing-featuresscreens-publishscreen',\n    depth: 4,\n    children: ['webapp-screens-marketing-featuresscreens-publishscreen-review--base'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-featuresscreens-publishscreen-review--base': {\n    id: 'webapp-screens-marketing-featuresscreens-publishscreen-review--base',\n    title: 'Webapp screens/Marketing/FeaturesScreens/PublishScreen/Review',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-publishscreen-review',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-testscreen': {\n    name: 'TestScreen',\n    id: 'webapp-screens-marketing-featuresscreens-testscreen',\n    parent: 'webapp-screens-marketing-featuresscreens',\n    depth: 3,\n    children: [\n      'webapp-screens-marketing-featuresscreens-testscreen--base',\n      'webapp-screens-marketing-featuresscreens-testscreen-pinpointbugsanimation',\n      'webapp-screens-marketing-featuresscreens-testscreen-snapshotexample',\n      'webapp-screens-marketing-featuresscreens-testscreen-testscreenhero',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-marketing-featuresscreens-testscreen--base': {\n    id: 'webapp-screens-marketing-featuresscreens-testscreen--base',\n    title: 'Webapp screens/Marketing/FeaturesScreens/TestScreen',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-featuresscreens-testscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-testscreen-pinpointbugsanimation': {\n    name: 'PinpointBugsAnimation',\n    id: 'webapp-screens-marketing-featuresscreens-testscreen-pinpointbugsanimation',\n    parent: 'webapp-screens-marketing-featuresscreens-testscreen',\n    depth: 4,\n    children: [\n      'webapp-screens-marketing-featuresscreens-testscreen-pinpointbugsanimation--base',\n      'webapp-screens-marketing-featuresscreens-testscreen-pinpointbugsanimation--paused',\n      'webapp-screens-marketing-featuresscreens-testscreen-pinpointbugsanimation--cutoff',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-marketing-featuresscreens-testscreen-pinpointbugsanimation--base': {\n    id: 'webapp-screens-marketing-featuresscreens-testscreen-pinpointbugsanimation--base',\n    title: 'Webapp screens/Marketing/FeaturesScreens/TestScreen/PinpointBugsAnimation',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-testscreen-pinpointbugsanimation',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-testscreen-pinpointbugsanimation--paused': {\n    id: 'webapp-screens-marketing-featuresscreens-testscreen-pinpointbugsanimation--paused',\n    title: 'Webapp screens/Marketing/FeaturesScreens/TestScreen/PinpointBugsAnimation',\n    name: 'Paused',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-testscreen-pinpointbugsanimation',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-testscreen-pinpointbugsanimation--cutoff': {\n    id: 'webapp-screens-marketing-featuresscreens-testscreen-pinpointbugsanimation--cutoff',\n    title: 'Webapp screens/Marketing/FeaturesScreens/TestScreen/PinpointBugsAnimation',\n    name: 'Cutoff',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-testscreen-pinpointbugsanimation',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-testscreen-snapshotexample': {\n    name: 'SnapshotExample',\n    id: 'webapp-screens-marketing-featuresscreens-testscreen-snapshotexample',\n    parent: 'webapp-screens-marketing-featuresscreens-testscreen',\n    depth: 4,\n    children: ['webapp-screens-marketing-featuresscreens-testscreen-snapshotexample--default'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-featuresscreens-testscreen-snapshotexample--default': {\n    id: 'webapp-screens-marketing-featuresscreens-testscreen-snapshotexample--default',\n    title: 'Webapp screens/Marketing/FeaturesScreens/TestScreen/SnapshotExample',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-testscreen-snapshotexample',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-testscreen-testscreenhero': {\n    name: 'TestScreenHero',\n    id: 'webapp-screens-marketing-featuresscreens-testscreen-testscreenhero',\n    parent: 'webapp-screens-marketing-featuresscreens-testscreen',\n    depth: 4,\n    children: [\n      'webapp-screens-marketing-featuresscreens-testscreen-testscreenhero--base',\n      'webapp-screens-marketing-featuresscreens-testscreen-testscreenhero--maintenance-mode',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-marketing-featuresscreens-testscreen-testscreenhero--base': {\n    id: 'webapp-screens-marketing-featuresscreens-testscreen-testscreenhero--base',\n    title: 'Webapp screens/Marketing/FeaturesScreens/TestScreen/TestScreenHero',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-testscreen-testscreenhero',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-featuresscreens-testscreen-testscreenhero--maintenance-mode': {\n    id: 'webapp-screens-marketing-featuresscreens-testscreen-testscreenhero--maintenance-mode',\n    title: 'Webapp screens/Marketing/FeaturesScreens/TestScreen/TestScreenHero',\n    name: 'Maintenance Mode',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 5,\n    parent: 'webapp-screens-marketing-featuresscreens-testscreen-testscreenhero',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-hero': {\n    name: 'Hero',\n    id: 'webapp-screens-marketing-hero',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: [\n      'webapp-screens-marketing-hero--base',\n      'webapp-screens-marketing-hero--bottom-animation',\n      'webapp-screens-marketing-hero--bottom-animation-inverted',\n      'webapp-screens-marketing-hero--maintenance-mode',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-marketing-hero--base': {\n    id: 'webapp-screens-marketing-hero--base',\n    title: 'Webapp screens/Marketing/Hero',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-hero',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-hero--bottom-animation': {\n    id: 'webapp-screens-marketing-hero--bottom-animation',\n    title: 'Webapp screens/Marketing/Hero',\n    name: 'Bottom Animation',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-hero',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-hero--bottom-animation-inverted': {\n    id: 'webapp-screens-marketing-hero--bottom-animation-inverted',\n    title: 'Webapp screens/Marketing/Hero',\n    name: 'Bottom Animation Inverted',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-hero',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-hero--maintenance-mode': {\n    id: 'webapp-screens-marketing-hero--maintenance-mode',\n    title: 'Webapp screens/Marketing/Hero',\n    name: 'Maintenance Mode',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-hero',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-integrations': {\n    name: 'Integrations',\n    id: 'webapp-screens-marketing-integrations',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: ['webapp-screens-marketing-integrations--default'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-integrations--default': {\n    id: 'webapp-screens-marketing-integrations--default',\n    title: 'Webapp screens/Marketing/Integrations',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-integrations',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-landingscreen': {\n    name: 'LandingScreen',\n    id: 'webapp-screens-marketing-landingscreen',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: [\n      'webapp-screens-marketing-landingscreen-automatedworkflows',\n      'webapp-screens-marketing-landingscreen-landingscreen',\n      'webapp-screens-marketing-landingscreen-landingscreenhero',\n      'webapp-screens-marketing-landingscreen-notables',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-marketing-landingscreen-automatedworkflows': {\n    name: 'AutomatedWorkflows',\n    id: 'webapp-screens-marketing-landingscreen-automatedworkflows',\n    parent: 'webapp-screens-marketing-landingscreen',\n    depth: 3,\n    children: [\n      'webapp-screens-marketing-landingscreen-automatedworkflows--base',\n      'webapp-screens-marketing-landingscreen-automatedworkflows--paused',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-marketing-landingscreen-automatedworkflows--base': {\n    id: 'webapp-screens-marketing-landingscreen-automatedworkflows--base',\n    title: 'Webapp screens/Marketing/LandingScreen/AutomatedWorkflows',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-landingscreen-automatedworkflows',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-landingscreen-automatedworkflows--paused': {\n    id: 'webapp-screens-marketing-landingscreen-automatedworkflows--paused',\n    title: 'Webapp screens/Marketing/LandingScreen/AutomatedWorkflows',\n    name: 'Paused',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-landingscreen-automatedworkflows',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-landingscreen-landingscreen': {\n    name: 'LandingScreen',\n    id: 'webapp-screens-marketing-landingscreen-landingscreen',\n    parent: 'webapp-screens-marketing-landingscreen',\n    depth: 3,\n    children: [\n      'webapp-screens-marketing-landingscreen-landingscreen--not-logged-in',\n      'webapp-screens-marketing-landingscreen-landingscreen--not-logged-in-maintenance-mode',\n      'webapp-screens-marketing-landingscreen-landingscreen--logged-in',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-marketing-landingscreen-landingscreen--not-logged-in': {\n    id: 'webapp-screens-marketing-landingscreen-landingscreen--not-logged-in',\n    title: 'Webapp screens/Marketing/LandingScreen/LandingScreen',\n    name: 'not logged in',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-landingscreen-landingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-landingscreen-landingscreen--not-logged-in-maintenance-mode': {\n    id: 'webapp-screens-marketing-landingscreen-landingscreen--not-logged-in-maintenance-mode',\n    title: 'Webapp screens/Marketing/LandingScreen/LandingScreen',\n    name: 'not logged in, maintenance mode',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-landingscreen-landingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-landingscreen-landingscreen--logged-in': {\n    id: 'webapp-screens-marketing-landingscreen-landingscreen--logged-in',\n    title: 'Webapp screens/Marketing/LandingScreen/LandingScreen',\n    name: 'logged in',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-landingscreen-landingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-landingscreen-landingscreenhero': {\n    name: 'LandingScreenHero',\n    id: 'webapp-screens-marketing-landingscreen-landingscreenhero',\n    parent: 'webapp-screens-marketing-landingscreen',\n    depth: 3,\n    children: [\n      'webapp-screens-marketing-landingscreen-landingscreenhero--base',\n      'webapp-screens-marketing-landingscreen-landingscreenhero--maintenance-mode',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-marketing-landingscreen-landingscreenhero--base': {\n    id: 'webapp-screens-marketing-landingscreen-landingscreenhero--base',\n    title: 'Webapp screens/Marketing/LandingScreen/LandingScreenHero',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-landingscreen-landingscreenhero',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-landingscreen-landingscreenhero--maintenance-mode': {\n    id: 'webapp-screens-marketing-landingscreen-landingscreenhero--maintenance-mode',\n    title: 'Webapp screens/Marketing/LandingScreen/LandingScreenHero',\n    name: 'Maintenance Mode',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-landingscreen-landingscreenhero',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-landingscreen-notables': {\n    name: 'Notables',\n    id: 'webapp-screens-marketing-landingscreen-notables',\n    parent: 'webapp-screens-marketing-landingscreen',\n    depth: 3,\n    children: ['webapp-screens-marketing-landingscreen-notables--default'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-landingscreen-notables--default': {\n    id: 'webapp-screens-marketing-landingscreen-notables--default',\n    title: 'Webapp screens/Marketing/LandingScreen/Notables',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-landingscreen-notables',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-marketingfooter': {\n    name: 'MarketingFooter',\n    id: 'webapp-screens-marketing-marketingfooter',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: ['webapp-screens-marketing-marketingfooter--default'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-marketingfooter--default': {\n    id: 'webapp-screens-marketing-marketingfooter--default',\n    title: 'Webapp screens/Marketing/MarketingFooter',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-marketingfooter',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-marketingheader': {\n    name: 'MarketingHeader',\n    id: 'webapp-screens-marketing-marketingheader',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: [\n      'webapp-screens-marketing-marketingheader--not-logged-in',\n      'webapp-screens-marketing-marketingheader--logged-in',\n      'webapp-screens-marketing-marketingheader--not-logged-in-maintenance-mode',\n      'webapp-screens-marketing-marketingheader--logged-in-maintenance-mode',\n      'webapp-screens-marketing-marketingheader--inverse-logged-in',\n      'webapp-screens-marketing-marketingheader--inverse-not-logged-in',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-marketing-marketingheader--not-logged-in': {\n    id: 'webapp-screens-marketing-marketingheader--not-logged-in',\n    title: 'Webapp screens/Marketing/MarketingHeader',\n    name: 'not logged in',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-marketingheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-marketingheader--logged-in': {\n    id: 'webapp-screens-marketing-marketingheader--logged-in',\n    title: 'Webapp screens/Marketing/MarketingHeader',\n    name: 'logged in',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-marketingheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-marketingheader--not-logged-in-maintenance-mode': {\n    id: 'webapp-screens-marketing-marketingheader--not-logged-in-maintenance-mode',\n    title: 'Webapp screens/Marketing/MarketingHeader',\n    name: 'not logged in, maintenanceMode',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-marketingheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-marketingheader--logged-in-maintenance-mode': {\n    id: 'webapp-screens-marketing-marketingheader--logged-in-maintenance-mode',\n    title: 'Webapp screens/Marketing/MarketingHeader',\n    name: 'logged in, maintenanceMode',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-marketingheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-marketingheader--inverse-logged-in': {\n    id: 'webapp-screens-marketing-marketingheader--inverse-logged-in',\n    title: 'Webapp screens/Marketing/MarketingHeader',\n    name: 'logged in, inverse',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-marketingheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-marketingheader--inverse-not-logged-in': {\n    id: 'webapp-screens-marketing-marketingheader--inverse-not-logged-in',\n    title: 'Webapp screens/Marketing/MarketingHeader',\n    name: 'not logged in, inverse',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-marketingheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-marketingpagetitle': {\n    name: 'MarketingPageTitle',\n    id: 'webapp-screens-marketing-marketingpagetitle',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: ['webapp-screens-marketing-marketingpagetitle--default'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-marketingpagetitle--default': {\n    id: 'webapp-screens-marketing-marketingpagetitle--default',\n    title: 'Webapp screens/Marketing/MarketingPageTitle',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-marketingpagetitle',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-personascreens': {\n    name: 'PersonaScreens',\n    id: 'webapp-screens-marketing-personascreens',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: [\n      'webapp-screens-marketing-personascreens-designsystemsscreen',\n      'webapp-screens-marketing-personascreens-digitalagenciesscreen',\n      'webapp-screens-marketing-personascreens-frontendteamsscreen',\n      'webapp-screens-marketing-personascreens-personaheader',\n      'webapp-screens-marketing-personascreens-storybookusersscreen',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-marketing-personascreens-designsystemsscreen': {\n    name: 'DesignSystemsScreen',\n    id: 'webapp-screens-marketing-personascreens-designsystemsscreen',\n    parent: 'webapp-screens-marketing-personascreens',\n    depth: 3,\n    children: ['webapp-screens-marketing-personascreens-designsystemsscreen--default'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-personascreens-designsystemsscreen--default': {\n    id: 'webapp-screens-marketing-personascreens-designsystemsscreen--default',\n    title: 'Webapp screens/Marketing/PersonaScreens/DesignSystemsScreen',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-personascreens-designsystemsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-personascreens-digitalagenciesscreen': {\n    name: 'DigitalAgenciesScreen',\n    id: 'webapp-screens-marketing-personascreens-digitalagenciesscreen',\n    parent: 'webapp-screens-marketing-personascreens',\n    depth: 3,\n    children: ['webapp-screens-marketing-personascreens-digitalagenciesscreen--default'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-personascreens-digitalagenciesscreen--default': {\n    id: 'webapp-screens-marketing-personascreens-digitalagenciesscreen--default',\n    title: 'Webapp screens/Marketing/PersonaScreens/DigitalAgenciesScreen',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-personascreens-digitalagenciesscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-personascreens-frontendteamsscreen': {\n    name: 'FrontendTeamsScreen',\n    id: 'webapp-screens-marketing-personascreens-frontendteamsscreen',\n    parent: 'webapp-screens-marketing-personascreens',\n    depth: 3,\n    children: ['webapp-screens-marketing-personascreens-frontendteamsscreen--default'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-personascreens-frontendteamsscreen--default': {\n    id: 'webapp-screens-marketing-personascreens-frontendteamsscreen--default',\n    title: 'Webapp screens/Marketing/PersonaScreens/FrontendTeamsScreen',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-personascreens-frontendteamsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-personascreens-personaheader': {\n    name: 'PersonaHeader',\n    id: 'webapp-screens-marketing-personascreens-personaheader',\n    parent: 'webapp-screens-marketing-personascreens',\n    depth: 3,\n    children: ['webapp-screens-marketing-personascreens-personaheader--default'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-personascreens-personaheader--default': {\n    id: 'webapp-screens-marketing-personascreens-personaheader--default',\n    title: 'Webapp screens/Marketing/PersonaScreens/PersonaHeader',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-personascreens-personaheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-personascreens-storybookusersscreen': {\n    name: 'StorybookUsersScreen',\n    id: 'webapp-screens-marketing-personascreens-storybookusersscreen',\n    parent: 'webapp-screens-marketing-personascreens',\n    depth: 3,\n    children: ['webapp-screens-marketing-personascreens-storybookusersscreen--default'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-personascreens-storybookusersscreen--default': {\n    id: 'webapp-screens-marketing-personascreens-storybookusersscreen--default',\n    title: 'Webapp screens/Marketing/PersonaScreens/StorybookUsersScreen',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-personascreens-storybookusersscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-pricingscreen': {\n    name: 'PricingScreen',\n    id: 'webapp-screens-marketing-pricingscreen',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: [\n      'webapp-screens-marketing-pricingscreen-faqpricing',\n      'webapp-screens-marketing-pricingscreen-prices',\n      'webapp-screens-marketing-pricingscreen-pricingfeatures',\n      'webapp-screens-marketing-pricingscreen-pricingscreen',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-marketing-pricingscreen-faqpricing': {\n    name: 'FAQPricing',\n    id: 'webapp-screens-marketing-pricingscreen-faqpricing',\n    parent: 'webapp-screens-marketing-pricingscreen',\n    depth: 3,\n    children: ['webapp-screens-marketing-pricingscreen-faqpricing--default'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-pricingscreen-faqpricing--default': {\n    id: 'webapp-screens-marketing-pricingscreen-faqpricing--default',\n    title: 'Webapp screens/Marketing/PricingScreen/FAQPricing',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-pricingscreen-faqpricing',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-pricingscreen-prices': {\n    name: 'Prices',\n    id: 'webapp-screens-marketing-pricingscreen-prices',\n    parent: 'webapp-screens-marketing-pricingscreen',\n    depth: 3,\n    children: [\n      'webapp-screens-marketing-pricingscreen-prices--logged-in',\n      'webapp-screens-marketing-pricingscreen-prices--not-logged-in',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-marketing-pricingscreen-prices--logged-in': {\n    id: 'webapp-screens-marketing-pricingscreen-prices--logged-in',\n    title: 'Webapp screens/Marketing/PricingScreen/Prices',\n    name: 'Logged In',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-pricingscreen-prices',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-pricingscreen-prices--not-logged-in': {\n    id: 'webapp-screens-marketing-pricingscreen-prices--not-logged-in',\n    title: 'Webapp screens/Marketing/PricingScreen/Prices',\n    name: 'Not Logged In',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-pricingscreen-prices',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-pricingscreen-pricingfeatures': {\n    name: 'PricingFeatures',\n    id: 'webapp-screens-marketing-pricingscreen-pricingfeatures',\n    parent: 'webapp-screens-marketing-pricingscreen',\n    depth: 3,\n    children: ['webapp-screens-marketing-pricingscreen-pricingfeatures--default'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-pricingscreen-pricingfeatures--default': {\n    id: 'webapp-screens-marketing-pricingscreen-pricingfeatures--default',\n    title: 'Webapp screens/Marketing/PricingScreen/PricingFeatures',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-pricingscreen-pricingfeatures',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-pricingscreen-pricingscreen': {\n    name: 'PricingScreen',\n    id: 'webapp-screens-marketing-pricingscreen-pricingscreen',\n    parent: 'webapp-screens-marketing-pricingscreen',\n    depth: 3,\n    children: [\n      'webapp-screens-marketing-pricingscreen-pricingscreen--logged-in',\n      'webapp-screens-marketing-pricingscreen-pricingscreen--not-logged-in',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-marketing-pricingscreen-pricingscreen--logged-in': {\n    id: 'webapp-screens-marketing-pricingscreen-pricingscreen--logged-in',\n    title: 'Webapp screens/Marketing/PricingScreen/PricingScreen',\n    name: 'Logged In',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-pricingscreen-pricingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-pricingscreen-pricingscreen--not-logged-in': {\n    id: 'webapp-screens-marketing-pricingscreen-pricingscreen--not-logged-in',\n    title: 'Webapp screens/Marketing/PricingScreen/PricingScreen',\n    name: 'Not Logged In',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-marketing-pricingscreen-pricingscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-socialproof': {\n    name: 'SocialProof',\n    id: 'webapp-screens-marketing-socialproof',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: ['webapp-screens-marketing-socialproof--default'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-socialproof--default': {\n    id: 'webapp-screens-marketing-socialproof--default',\n    title: 'Webapp screens/Marketing/SocialProof',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-socialproof',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-testimonial': {\n    name: 'Testimonial',\n    id: 'webapp-screens-marketing-testimonial',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: [\n      'webapp-screens-marketing-testimonial--default',\n      'webapp-screens-marketing-testimonial--compact',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-marketing-testimonial--default': {\n    id: 'webapp-screens-marketing-testimonial--default',\n    title: 'Webapp screens/Marketing/Testimonial',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-testimonial',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-testimonial--compact': {\n    id: 'webapp-screens-marketing-testimonial--compact',\n    title: 'Webapp screens/Marketing/Testimonial',\n    name: 'compact',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-testimonial',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-testimonials': {\n    name: 'Testimonials',\n    id: 'webapp-screens-marketing-testimonials',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: ['webapp-screens-marketing-testimonials--default'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-testimonials--default': {\n    id: 'webapp-screens-marketing-testimonials--default',\n    title: 'Webapp screens/Marketing/Testimonials',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-testimonials',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-valueprop': {\n    name: 'ValueProp',\n    id: 'webapp-screens-marketing-valueprop',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: ['webapp-screens-marketing-valueprop--default'],\n    type: 'component',\n  },\n  'webapp-screens-marketing-valueprop--default': {\n    id: 'webapp-screens-marketing-valueprop--default',\n    title: 'Webapp screens/Marketing/ValueProp',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-valueprop',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-workflows': {\n    name: 'Workflows',\n    id: 'webapp-screens-marketing-workflows',\n    parent: 'webapp-screens-marketing',\n    depth: 2,\n    children: [\n      'webapp-screens-marketing-workflows--publish',\n      'webapp-screens-marketing-workflows--test',\n      'webapp-screens-marketing-workflows--document',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-marketing-workflows--publish': {\n    id: 'webapp-screens-marketing-workflows--publish',\n    title: 'Webapp screens/Marketing/Workflows',\n    name: 'Publish',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-workflows',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-workflows--test': {\n    id: 'webapp-screens-marketing-workflows--test',\n    title: 'Webapp screens/Marketing/Workflows',\n    name: 'Test',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-workflows',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-marketing-workflows--document': {\n    id: 'webapp-screens-marketing-workflows--document',\n    title: 'Webapp screens/Marketing/Workflows',\n    name: 'Document',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-marketing-workflows',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-notificationsscreen': {\n    name: 'NotificationsScreen',\n    id: 'webapp-screens-notificationsscreen',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: [\n      'webapp-screens-notificationsscreen--loading',\n      'webapp-screens-notificationsscreen--default',\n      'webapp-screens-notificationsscreen--empty',\n      'webapp-screens-notificationsscreen--without-an-email-link',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-notificationsscreen--loading': {\n    id: 'webapp-screens-notificationsscreen--loading',\n    title: 'Webapp screens/NotificationsScreen',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-notificationsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-notificationsscreen--default': {\n    id: 'webapp-screens-notificationsscreen--default',\n    title: 'Webapp screens/NotificationsScreen',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-notificationsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-notificationsscreen--empty': {\n    id: 'webapp-screens-notificationsscreen--empty',\n    title: 'Webapp screens/NotificationsScreen',\n    name: 'empty',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-notificationsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-notificationsscreen--without-an-email-link': {\n    id: 'webapp-screens-notificationsscreen--without-an-email-link',\n    title: 'Webapp screens/NotificationsScreen',\n    name: 'without an email link',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-notificationsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-onboarding': {\n    name: 'Onboarding',\n    id: 'webapp-screens-onboarding',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: [\n      'webapp-screens-onboarding-chooserepository',\n      'webapp-screens-onboarding-createproject',\n      'webapp-screens-onboarding-onboardingscreen-clickable',\n      'webapp-screens-onboarding-projecttypepicker',\n      'webapp-screens-onboarding-setupprojectflow-clickable',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-onboarding-chooserepository': {\n    name: 'ChooseRepository',\n    id: 'webapp-screens-onboarding-chooserepository',\n    parent: 'webapp-screens-onboarding',\n    depth: 2,\n    children: [\n      'webapp-screens-onboarding-chooserepository--loading',\n      'webapp-screens-onboarding-chooserepository--default',\n      'webapp-screens-onboarding-chooserepository--default-refreshing',\n      'webapp-screens-onboarding-chooserepository--default-bitbucket',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-onboarding-chooserepository--loading': {\n    id: 'webapp-screens-onboarding-chooserepository--loading',\n    title: 'Webapp screens/Onboarding/ChooseRepository',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-onboarding-chooserepository',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-onboarding-chooserepository--default': {\n    id: 'webapp-screens-onboarding-chooserepository--default',\n    title: 'Webapp screens/Onboarding/ChooseRepository',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-onboarding-chooserepository',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-onboarding-chooserepository--default-refreshing': {\n    id: 'webapp-screens-onboarding-chooserepository--default-refreshing',\n    title: 'Webapp screens/Onboarding/ChooseRepository',\n    name: 'default, refreshing',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-onboarding-chooserepository',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-onboarding-chooserepository--default-bitbucket': {\n    id: 'webapp-screens-onboarding-chooserepository--default-bitbucket',\n    title: 'Webapp screens/Onboarding/ChooseRepository',\n    name: 'default, bitbucket',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-onboarding-chooserepository',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-onboarding-createproject': {\n    name: 'CreateProject',\n    id: 'webapp-screens-onboarding-createproject',\n    parent: 'webapp-screens-onboarding',\n    depth: 2,\n    children: ['webapp-screens-onboarding-createproject--default'],\n    type: 'component',\n  },\n  'webapp-screens-onboarding-createproject--default': {\n    id: 'webapp-screens-onboarding-createproject--default',\n    title: 'Webapp screens/Onboarding/CreateProject',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-onboarding-createproject',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-onboarding-onboardingscreen-clickable': {\n    name: 'OnboardingScreen (clickable)',\n    id: 'webapp-screens-onboarding-onboardingscreen-clickable',\n    parent: 'webapp-screens-onboarding',\n    depth: 2,\n    children: [\n      'webapp-screens-onboarding-onboardingscreen-clickable--loading',\n      'webapp-screens-onboarding-onboardingscreen-clickable--default',\n      'webapp-screens-onboarding-onboardingscreen-clickable--saml',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-onboarding-onboardingscreen-clickable--loading': {\n    id: 'webapp-screens-onboarding-onboardingscreen-clickable--loading',\n    title: 'Webapp screens/Onboarding/OnboardingScreen (clickable)',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-onboarding-onboardingscreen-clickable',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-onboarding-onboardingscreen-clickable--default': {\n    id: 'webapp-screens-onboarding-onboardingscreen-clickable--default',\n    title: 'Webapp screens/Onboarding/OnboardingScreen (clickable)',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-onboarding-onboardingscreen-clickable',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-onboarding-onboardingscreen-clickable--saml': {\n    id: 'webapp-screens-onboarding-onboardingscreen-clickable--saml',\n    title: 'Webapp screens/Onboarding/OnboardingScreen (clickable)',\n    name: 'saml',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-onboarding-onboardingscreen-clickable',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-onboarding-projecttypepicker': {\n    name: 'ProjectTypePicker',\n    id: 'webapp-screens-onboarding-projecttypepicker',\n    parent: 'webapp-screens-onboarding',\n    depth: 2,\n    children: [\n      'webapp-screens-onboarding-projecttypepicker--github',\n      'webapp-screens-onboarding-projecttypepicker--bitbucket',\n      'webapp-screens-onboarding-projecttypepicker--gitlab',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-onboarding-projecttypepicker--github': {\n    id: 'webapp-screens-onboarding-projecttypepicker--github',\n    title: 'Webapp screens/Onboarding/ProjectTypePicker',\n    name: 'Github',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-onboarding-projecttypepicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-onboarding-projecttypepicker--bitbucket': {\n    id: 'webapp-screens-onboarding-projecttypepicker--bitbucket',\n    title: 'Webapp screens/Onboarding/ProjectTypePicker',\n    name: 'Bitbucket',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-onboarding-projecttypepicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-onboarding-projecttypepicker--gitlab': {\n    id: 'webapp-screens-onboarding-projecttypepicker--gitlab',\n    title: 'Webapp screens/Onboarding/ProjectTypePicker',\n    name: 'Gitlab',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-onboarding-projecttypepicker',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-onboarding-setupprojectflow-clickable': {\n    name: 'SetupProjectFlow (clickable)',\n    id: 'webapp-screens-onboarding-setupprojectflow-clickable',\n    parent: 'webapp-screens-onboarding',\n    depth: 2,\n    children: [\n      'webapp-screens-onboarding-setupprojectflow-clickable--loading',\n      'webapp-screens-onboarding-setupprojectflow-clickable--onboarding',\n      'webapp-screens-onboarding-setupprojectflow-clickable--onboarding-saml-user',\n      'webapp-screens-onboarding-setupprojectflow-clickable--add-project',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-onboarding-setupprojectflow-clickable--loading': {\n    id: 'webapp-screens-onboarding-setupprojectflow-clickable--loading',\n    title: 'Webapp screens/Onboarding/SetupProjectFlow (clickable)',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-onboarding-setupprojectflow-clickable',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-onboarding-setupprojectflow-clickable--onboarding': {\n    id: 'webapp-screens-onboarding-setupprojectflow-clickable--onboarding',\n    title: 'Webapp screens/Onboarding/SetupProjectFlow (clickable)',\n    name: 'onboarding',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-onboarding-setupprojectflow-clickable',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-onboarding-setupprojectflow-clickable--onboarding-saml-user': {\n    id: 'webapp-screens-onboarding-setupprojectflow-clickable--onboarding-saml-user',\n    title: 'Webapp screens/Onboarding/SetupProjectFlow (clickable)',\n    name: 'onboarding, saml user',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-onboarding-setupprojectflow-clickable',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-onboarding-setupprojectflow-clickable--add-project': {\n    id: 'webapp-screens-onboarding-setupprojectflow-clickable--add-project',\n    title: 'Webapp screens/Onboarding/SetupProjectFlow (clickable)',\n    name: 'add project',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-onboarding-setupprojectflow-clickable',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-preferencesupdatedscreen': {\n    name: 'PreferencesUpdatedScreen',\n    id: 'webapp-screens-preferencesupdatedscreen',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: ['webapp-screens-preferencesupdatedscreen--default'],\n    type: 'component',\n  },\n  'webapp-screens-preferencesupdatedscreen--default': {\n    id: 'webapp-screens-preferencesupdatedscreen--default',\n    title: 'Webapp screens/PreferencesUpdatedScreen',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-preferencesupdatedscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest': {\n    name: 'PullRequest',\n    id: 'webapp-screens-pullrequest',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: [\n      'webapp-screens-pullrequest-activity',\n      'webapp-screens-pullrequest-buildstatustooltip',\n      'webapp-screens-pullrequest-checklist',\n      'webapp-screens-pullrequest-features',\n      'webapp-screens-pullrequest-nocomparison',\n      'webapp-screens-pullrequest-pullrequestchangecomments',\n      'webapp-screens-pullrequest-pullrequestchangecommentthread',\n      'webapp-screens-pullrequest-pullrequestchangeitem',\n      'webapp-screens-pullrequest-pullrequestchanges',\n      'webapp-screens-pullrequest-pullrequestchecktooltip',\n      'webapp-screens-pullrequest-pullrequestcomponents',\n      'webapp-screens-pullrequest-pullrequestexplainer',\n      'webapp-screens-pullrequest-pullrequestheader',\n      'webapp-screens-pullrequest-pullrequestparticipants',\n      'webapp-screens-pullrequest-pullrequestreviewers',\n      'webapp-screens-pullrequest-pullrequestscreen',\n      'webapp-screens-pullrequest-reviewbutton',\n      'webapp-screens-pullrequest-selectreviewers',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-pullrequest-activity': {\n    name: 'Activity',\n    id: 'webapp-screens-pullrequest-activity',\n    parent: 'webapp-screens-pullrequest',\n    depth: 2,\n    children: [\n      'webapp-screens-pullrequest-activity-activity',\n      'webapp-screens-pullrequest-activity-activityitem',\n      'webapp-screens-pullrequest-activity-buildactivity',\n      'webapp-screens-pullrequest-activity-commentthreadactivity',\n      'webapp-screens-pullrequest-activity-reviewactivity',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-pullrequest-activity-activity': {\n    name: 'Activity',\n    id: 'webapp-screens-pullrequest-activity-activity',\n    parent: 'webapp-screens-pullrequest-activity',\n    depth: 3,\n    children: [\n      'webapp-screens-pullrequest-activity-activity--loading',\n      'webapp-screens-pullrequest-activity-activity--no-builds',\n      'webapp-screens-pullrequest-activity-activity--simple',\n      'webapp-screens-pullrequest-activity-activity--ui-review-disabled',\n      'webapp-screens-pullrequest-activity-activity--ui-review-disabled-no-reviewers',\n      'webapp-screens-pullrequest-activity-activity--reviews',\n      'webapp-screens-pullrequest-activity-activity--in-progress-build',\n      'webapp-screens-pullrequest-activity-activity--comments',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-activity-activity--loading': {\n    id: 'webapp-screens-pullrequest-activity-activity--loading',\n    title: 'Webapp screens/PullRequest/Activity/Activity',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-activity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-activity--no-builds': {\n    id: 'webapp-screens-pullrequest-activity-activity--no-builds',\n    title: 'Webapp screens/PullRequest/Activity/Activity',\n    name: 'No Builds',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-activity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-activity--simple': {\n    id: 'webapp-screens-pullrequest-activity-activity--simple',\n    title: 'Webapp screens/PullRequest/Activity/Activity',\n    name: 'Simple',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-activity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-activity--ui-review-disabled': {\n    id: 'webapp-screens-pullrequest-activity-activity--ui-review-disabled',\n    title: 'Webapp screens/PullRequest/Activity/Activity',\n    name: 'UI Review Disabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-activity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-activity--ui-review-disabled-no-reviewers': {\n    id: 'webapp-screens-pullrequest-activity-activity--ui-review-disabled-no-reviewers',\n    title: 'Webapp screens/PullRequest/Activity/Activity',\n    name: 'UI Review Disabled No Reviewers',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-activity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-activity--reviews': {\n    id: 'webapp-screens-pullrequest-activity-activity--reviews',\n    title: 'Webapp screens/PullRequest/Activity/Activity',\n    name: 'Reviews',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-activity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-activity--in-progress-build': {\n    id: 'webapp-screens-pullrequest-activity-activity--in-progress-build',\n    title: 'Webapp screens/PullRequest/Activity/Activity',\n    name: 'In Progress Build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-activity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-activity--comments': {\n    id: 'webapp-screens-pullrequest-activity-activity--comments',\n    title: 'Webapp screens/PullRequest/Activity/Activity',\n    name: 'Comments',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-activity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-activityitem': {\n    name: 'ActivityItem',\n    id: 'webapp-screens-pullrequest-activity-activityitem',\n    parent: 'webapp-screens-pullrequest-activity',\n    depth: 3,\n    children: [\n      'webapp-screens-pullrequest-activity-activityitem--default',\n      'webapp-screens-pullrequest-activity-activityitem--loading',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-activity-activityitem--default': {\n    id: 'webapp-screens-pullrequest-activity-activityitem--default',\n    title: 'Webapp screens/PullRequest/Activity/ActivityItem',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-activityitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-activityitem--loading': {\n    id: 'webapp-screens-pullrequest-activity-activityitem--loading',\n    title: 'Webapp screens/PullRequest/Activity/ActivityItem',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-activityitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-buildactivity': {\n    name: 'BuildActivity',\n    id: 'webapp-screens-pullrequest-activity-buildactivity',\n    parent: 'webapp-screens-pullrequest-activity',\n    depth: 3,\n    children: [\n      'webapp-screens-pullrequest-activity-buildactivity--loading',\n      'webapp-screens-pullrequest-activity-buildactivity--no-capture',\n      'webapp-screens-pullrequest-activity-buildactivity--in-progress',\n      'webapp-screens-pullrequest-activity-buildactivity--timed-out',\n      'webapp-screens-pullrequest-activity-buildactivity--error',\n      'webapp-screens-pullrequest-activity-buildactivity--failed',\n      'webapp-screens-pullrequest-activity-buildactivity--passed',\n      'webapp-screens-pullrequest-activity-buildactivity--pending',\n      'webapp-screens-pullrequest-activity-buildactivity--accepted',\n      'webapp-screens-pullrequest-activity-buildactivity--denied',\n      'webapp-screens-pullrequest-activity-buildactivity--limited',\n      'webapp-screens-pullrequest-activity-buildactivity--publish-only',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-activity-buildactivity--loading': {\n    id: 'webapp-screens-pullrequest-activity-buildactivity--loading',\n    title: 'Webapp screens/PullRequest/Activity/BuildActivity',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-buildactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-buildactivity--no-capture': {\n    id: 'webapp-screens-pullrequest-activity-buildactivity--no-capture',\n    title: 'Webapp screens/PullRequest/Activity/BuildActivity',\n    name: 'No Capture',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-buildactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-buildactivity--in-progress': {\n    id: 'webapp-screens-pullrequest-activity-buildactivity--in-progress',\n    title: 'Webapp screens/PullRequest/Activity/BuildActivity',\n    name: 'In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-buildactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-buildactivity--timed-out': {\n    id: 'webapp-screens-pullrequest-activity-buildactivity--timed-out',\n    title: 'Webapp screens/PullRequest/Activity/BuildActivity',\n    name: 'Timed Out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-buildactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-buildactivity--error': {\n    id: 'webapp-screens-pullrequest-activity-buildactivity--error',\n    title: 'Webapp screens/PullRequest/Activity/BuildActivity',\n    name: 'Error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-buildactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-buildactivity--failed': {\n    id: 'webapp-screens-pullrequest-activity-buildactivity--failed',\n    title: 'Webapp screens/PullRequest/Activity/BuildActivity',\n    name: 'Failed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-buildactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-buildactivity--passed': {\n    id: 'webapp-screens-pullrequest-activity-buildactivity--passed',\n    title: 'Webapp screens/PullRequest/Activity/BuildActivity',\n    name: 'Passed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-buildactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-buildactivity--pending': {\n    id: 'webapp-screens-pullrequest-activity-buildactivity--pending',\n    title: 'Webapp screens/PullRequest/Activity/BuildActivity',\n    name: 'Pending',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-buildactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-buildactivity--accepted': {\n    id: 'webapp-screens-pullrequest-activity-buildactivity--accepted',\n    title: 'Webapp screens/PullRequest/Activity/BuildActivity',\n    name: 'Accepted',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-buildactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-buildactivity--denied': {\n    id: 'webapp-screens-pullrequest-activity-buildactivity--denied',\n    title: 'Webapp screens/PullRequest/Activity/BuildActivity',\n    name: 'Denied',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-buildactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-buildactivity--limited': {\n    id: 'webapp-screens-pullrequest-activity-buildactivity--limited',\n    title: 'Webapp screens/PullRequest/Activity/BuildActivity',\n    name: 'Limited',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-buildactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-buildactivity--publish-only': {\n    id: 'webapp-screens-pullrequest-activity-buildactivity--publish-only',\n    title: 'Webapp screens/PullRequest/Activity/BuildActivity',\n    name: 'Publish Only',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-buildactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-commentthreadactivity': {\n    name: 'CommentThreadActivity',\n    id: 'webapp-screens-pullrequest-activity-commentthreadactivity',\n    parent: 'webapp-screens-pullrequest-activity',\n    depth: 3,\n    children: [\n      'webapp-screens-pullrequest-activity-commentthreadactivity--active',\n      'webapp-screens-pullrequest-activity-commentthreadactivity--active-truncated-text',\n      'webapp-screens-pullrequest-activity-commentthreadactivity--active-diff-thread',\n      'webapp-screens-pullrequest-activity-commentthreadactivity--active-short-height',\n      'webapp-screens-pullrequest-activity-commentthreadactivity--active-non-owner',\n      'webapp-screens-pullrequest-activity-commentthreadactivity--active-logged-out',\n      'webapp-screens-pullrequest-activity-commentthreadactivity--resolved',\n      'webapp-screens-pullrequest-activity-commentthreadactivity--resolved-diff-thread',\n      'webapp-screens-pullrequest-activity-commentthreadactivity--resolved-mutating',\n      'webapp-screens-pullrequest-activity-commentthreadactivity--resolved-expanded',\n      'webapp-screens-pullrequest-activity-commentthreadactivity--resolved-expanded-mutating',\n      'webapp-screens-pullrequest-activity-commentthreadactivity--resolved-logged-out',\n      'webapp-screens-pullrequest-activity-commentthreadactivity--resolved-logged-out-expanded',\n      'webapp-screens-pullrequest-activity-commentthreadactivity--outdated',\n      'webapp-screens-pullrequest-activity-commentthreadactivity--outdated-non-owner',\n      'webapp-screens-pullrequest-activity-commentthreadactivity--outdated-logged-out',\n      'webapp-screens-pullrequest-activity-commentthreadactivity--outdated-collapsed',\n      'webapp-screens-pullrequest-activity-commentthreadactivity--outdated-tooltip',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-activity-commentthreadactivity--active': {\n    id: 'webapp-screens-pullrequest-activity-commentthreadactivity--active',\n    title: 'Webapp screens/PullRequest/Activity/CommentThreadActivity',\n    name: 'Active',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-commentthreadactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-commentthreadactivity--active-truncated-text': {\n    id: 'webapp-screens-pullrequest-activity-commentthreadactivity--active-truncated-text',\n    title: 'Webapp screens/PullRequest/Activity/CommentThreadActivity',\n    name: 'Active Truncated Text',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-commentthreadactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-commentthreadactivity--active-diff-thread': {\n    id: 'webapp-screens-pullrequest-activity-commentthreadactivity--active-diff-thread',\n    title: 'Webapp screens/PullRequest/Activity/CommentThreadActivity',\n    name: 'Active Diff Thread',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-commentthreadactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-commentthreadactivity--active-short-height': {\n    id: 'webapp-screens-pullrequest-activity-commentthreadactivity--active-short-height',\n    title: 'Webapp screens/PullRequest/Activity/CommentThreadActivity',\n    name: 'Active Short Height',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-commentthreadactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-commentthreadactivity--active-non-owner': {\n    id: 'webapp-screens-pullrequest-activity-commentthreadactivity--active-non-owner',\n    title: 'Webapp screens/PullRequest/Activity/CommentThreadActivity',\n    name: 'Active Non Owner',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-commentthreadactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-commentthreadactivity--active-logged-out': {\n    id: 'webapp-screens-pullrequest-activity-commentthreadactivity--active-logged-out',\n    title: 'Webapp screens/PullRequest/Activity/CommentThreadActivity',\n    name: 'Active Logged Out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-commentthreadactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-commentthreadactivity--resolved': {\n    id: 'webapp-screens-pullrequest-activity-commentthreadactivity--resolved',\n    title: 'Webapp screens/PullRequest/Activity/CommentThreadActivity',\n    name: 'Resolved',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-commentthreadactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-commentthreadactivity--resolved-diff-thread': {\n    id: 'webapp-screens-pullrequest-activity-commentthreadactivity--resolved-diff-thread',\n    title: 'Webapp screens/PullRequest/Activity/CommentThreadActivity',\n    name: 'Resolved Diff Thread',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-commentthreadactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-commentthreadactivity--resolved-mutating': {\n    id: 'webapp-screens-pullrequest-activity-commentthreadactivity--resolved-mutating',\n    title: 'Webapp screens/PullRequest/Activity/CommentThreadActivity',\n    name: 'Resolved Mutating',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-commentthreadactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-commentthreadactivity--resolved-expanded': {\n    id: 'webapp-screens-pullrequest-activity-commentthreadactivity--resolved-expanded',\n    title: 'Webapp screens/PullRequest/Activity/CommentThreadActivity',\n    name: 'Resolved Expanded',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-commentthreadactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-commentthreadactivity--resolved-expanded-mutating': {\n    id: 'webapp-screens-pullrequest-activity-commentthreadactivity--resolved-expanded-mutating',\n    title: 'Webapp screens/PullRequest/Activity/CommentThreadActivity',\n    name: 'Resolved Expanded Mutating',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-commentthreadactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-commentthreadactivity--resolved-logged-out': {\n    id: 'webapp-screens-pullrequest-activity-commentthreadactivity--resolved-logged-out',\n    title: 'Webapp screens/PullRequest/Activity/CommentThreadActivity',\n    name: 'Resolved Logged Out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-commentthreadactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-commentthreadactivity--resolved-logged-out-expanded': {\n    id: 'webapp-screens-pullrequest-activity-commentthreadactivity--resolved-logged-out-expanded',\n    title: 'Webapp screens/PullRequest/Activity/CommentThreadActivity',\n    name: 'Resolved Logged Out Expanded',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-commentthreadactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-commentthreadactivity--outdated': {\n    id: 'webapp-screens-pullrequest-activity-commentthreadactivity--outdated',\n    title: 'Webapp screens/PullRequest/Activity/CommentThreadActivity',\n    name: 'Outdated',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-commentthreadactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-commentthreadactivity--outdated-non-owner': {\n    id: 'webapp-screens-pullrequest-activity-commentthreadactivity--outdated-non-owner',\n    title: 'Webapp screens/PullRequest/Activity/CommentThreadActivity',\n    name: 'Outdated Non Owner',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-commentthreadactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-commentthreadactivity--outdated-logged-out': {\n    id: 'webapp-screens-pullrequest-activity-commentthreadactivity--outdated-logged-out',\n    title: 'Webapp screens/PullRequest/Activity/CommentThreadActivity',\n    name: 'Outdated Logged Out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-commentthreadactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-commentthreadactivity--outdated-collapsed': {\n    id: 'webapp-screens-pullrequest-activity-commentthreadactivity--outdated-collapsed',\n    title: 'Webapp screens/PullRequest/Activity/CommentThreadActivity',\n    name: 'Outdated Collapsed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-commentthreadactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-commentthreadactivity--outdated-tooltip': {\n    id: 'webapp-screens-pullrequest-activity-commentthreadactivity--outdated-tooltip',\n    title: 'Webapp screens/PullRequest/Activity/CommentThreadActivity',\n    name: 'Outdated Tooltip',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-commentthreadactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-reviewactivity': {\n    name: 'ReviewActivity',\n    id: 'webapp-screens-pullrequest-activity-reviewactivity',\n    parent: 'webapp-screens-pullrequest-activity',\n    depth: 3,\n    children: [\n      'webapp-screens-pullrequest-activity-reviewactivity--assigned-self',\n      'webapp-screens-pullrequest-activity-reviewactivity--assigned-other',\n      'webapp-screens-pullrequest-activity-reviewactivity--approved',\n      'webapp-screens-pullrequest-activity-reviewactivity--unapproved',\n      'webapp-screens-pullrequest-activity-reviewactivity--unassigned-self',\n      'webapp-screens-pullrequest-activity-reviewactivity--unassigned-other',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-activity-reviewactivity--assigned-self': {\n    id: 'webapp-screens-pullrequest-activity-reviewactivity--assigned-self',\n    title: 'Webapp screens/PullRequest/Activity/ReviewActivity',\n    name: 'Assigned Self',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-reviewactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-reviewactivity--assigned-other': {\n    id: 'webapp-screens-pullrequest-activity-reviewactivity--assigned-other',\n    title: 'Webapp screens/PullRequest/Activity/ReviewActivity',\n    name: 'Assigned Other',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-reviewactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-reviewactivity--approved': {\n    id: 'webapp-screens-pullrequest-activity-reviewactivity--approved',\n    title: 'Webapp screens/PullRequest/Activity/ReviewActivity',\n    name: 'Approved',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-reviewactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-reviewactivity--unapproved': {\n    id: 'webapp-screens-pullrequest-activity-reviewactivity--unapproved',\n    title: 'Webapp screens/PullRequest/Activity/ReviewActivity',\n    name: 'Unapproved',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-reviewactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-reviewactivity--unassigned-self': {\n    id: 'webapp-screens-pullrequest-activity-reviewactivity--unassigned-self',\n    title: 'Webapp screens/PullRequest/Activity/ReviewActivity',\n    name: 'Unassigned Self',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-reviewactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-activity-reviewactivity--unassigned-other': {\n    id: 'webapp-screens-pullrequest-activity-reviewactivity--unassigned-other',\n    title: 'Webapp screens/PullRequest/Activity/ReviewActivity',\n    name: 'Unassigned Other',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-activity-reviewactivity',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-buildstatustooltip': {\n    name: 'BuildStatusTooltip',\n    id: 'webapp-screens-pullrequest-buildstatustooltip',\n    parent: 'webapp-screens-pullrequest',\n    depth: 2,\n    children: [\n      'webapp-screens-pullrequest-buildstatustooltip--passing',\n      'webapp-screens-pullrequest-buildstatustooltip--build-in-progress',\n      'webapp-screens-pullrequest-buildstatustooltip--build-in-progress-tests-disabled',\n      'webapp-screens-pullrequest-buildstatustooltip--paused',\n      'webapp-screens-pullrequest-buildstatustooltip--errored-build',\n      'webapp-screens-pullrequest-buildstatustooltip--errored-snapshots',\n      'webapp-screens-pullrequest-buildstatustooltip--denied-snapshots',\n      'webapp-screens-pullrequest-buildstatustooltip--pending-snapshots',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-buildstatustooltip--passing': {\n    id: 'webapp-screens-pullrequest-buildstatustooltip--passing',\n    title: 'Webapp screens/PullRequest/BuildStatusTooltip',\n    name: 'Passing',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-buildstatustooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-buildstatustooltip--build-in-progress': {\n    id: 'webapp-screens-pullrequest-buildstatustooltip--build-in-progress',\n    title: 'Webapp screens/PullRequest/BuildStatusTooltip',\n    name: 'Build In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-buildstatustooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-buildstatustooltip--build-in-progress-tests-disabled': {\n    id: 'webapp-screens-pullrequest-buildstatustooltip--build-in-progress-tests-disabled',\n    title: 'Webapp screens/PullRequest/BuildStatusTooltip',\n    name: 'Build In Progress Tests Disabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-buildstatustooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-buildstatustooltip--paused': {\n    id: 'webapp-screens-pullrequest-buildstatustooltip--paused',\n    title: 'Webapp screens/PullRequest/BuildStatusTooltip',\n    name: 'Paused',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-buildstatustooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-buildstatustooltip--errored-build': {\n    id: 'webapp-screens-pullrequest-buildstatustooltip--errored-build',\n    title: 'Webapp screens/PullRequest/BuildStatusTooltip',\n    name: 'Errored Build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-buildstatustooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-buildstatustooltip--errored-snapshots': {\n    id: 'webapp-screens-pullrequest-buildstatustooltip--errored-snapshots',\n    title: 'Webapp screens/PullRequest/BuildStatusTooltip',\n    name: 'Errored Snapshots',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-buildstatustooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-buildstatustooltip--denied-snapshots': {\n    id: 'webapp-screens-pullrequest-buildstatustooltip--denied-snapshots',\n    title: 'Webapp screens/PullRequest/BuildStatusTooltip',\n    name: 'Denied Snapshots',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-buildstatustooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-buildstatustooltip--pending-snapshots': {\n    id: 'webapp-screens-pullrequest-buildstatustooltip--pending-snapshots',\n    title: 'Webapp screens/PullRequest/BuildStatusTooltip',\n    name: 'Pending Snapshots',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-buildstatustooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist': {\n    name: 'Checklist',\n    id: 'webapp-screens-pullrequest-checklist',\n    parent: 'webapp-screens-pullrequest',\n    depth: 2,\n    children: [\n      'webapp-screens-pullrequest-checklist-checklist',\n      'webapp-screens-pullrequest-checklist-checklistactivecommentthread',\n      'webapp-screens-pullrequest-checklist-checklistactivecommentthreads',\n      'webapp-screens-pullrequest-checklist-checklistbuilderrors',\n      'webapp-screens-pullrequest-checklist-checklisterroreddiffs',\n      'webapp-screens-pullrequest-checklist-checklistheader',\n      'webapp-screens-pullrequest-checklist-checklistitemheader',\n      'webapp-screens-pullrequest-checklist-checklistpendingreviews',\n      'webapp-screens-pullrequest-checklist-checklistspeccolumn',\n      'webapp-screens-pullrequest-checklist-checklistvisualchanges',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-pullrequest-checklist-checklist': {\n    name: 'Checklist',\n    id: 'webapp-screens-pullrequest-checklist-checklist',\n    parent: 'webapp-screens-pullrequest-checklist',\n    depth: 3,\n    children: [\n      'webapp-screens-pullrequest-checklist-checklist--empty',\n      'webapp-screens-pullrequest-checklist-checklist--no-checks',\n      'webapp-screens-pullrequest-checklist-checklist--all-passing',\n      'webapp-screens-pullrequest-checklist-checklist--pending-reviews',\n      'webapp-screens-pullrequest-checklist-checklist--active-comment-threads',\n      'webapp-screens-pullrequest-checklist-checklist--visual-changes',\n      'webapp-screens-pullrequest-checklist-checklist--build-error',\n      'webapp-screens-pullrequest-checklist-checklist--build-in-progress',\n      'webapp-screens-pullrequest-checklist-checklist--comparison-in-progress',\n      'webapp-screens-pullrequest-checklist-checklist--no-comparison',\n      'webapp-screens-pullrequest-checklist-checklist--diff-errors',\n      'webapp-screens-pullrequest-checklist-checklist--paused-exceeded-threshold',\n      'webapp-screens-pullrequest-checklist-checklist--paused-exceeded-threshold-org',\n      'webapp-screens-pullrequest-checklist-checklist--paused-exceeded-threshold-no-plan-access',\n      'webapp-screens-pullrequest-checklist-checklist--paused-exceeded-threshold-in-progress-build',\n      'webapp-screens-pullrequest-checklist-checklist--paused-exceeded-threshold-error-build',\n      'webapp-screens-pullrequest-checklist-checklist--paused-payment-required',\n      'webapp-screens-pullrequest-checklist-checklist--was-paused-now-resumed',\n      'webapp-screens-pullrequest-checklist-checklist--all-tests',\n      'webapp-screens-pullrequest-checklist-checklist--all-tests-exceeded-threshold',\n      'webapp-screens-pullrequest-checklist-checklist--all-tests-was-paused-now-resumed',\n      'webapp-screens-pullrequest-checklist-checklist--all-tests-ui-review-disabled',\n      'webapp-screens-pullrequest-checklist-checklist--all-tests-ui-review-disabled-publish-only',\n      'webapp-screens-pullrequest-checklist-checklist--all-tests-build-error',\n      'webapp-screens-pullrequest-checklist-checklist--all-tests-build-in-progress',\n      'webapp-screens-pullrequest-checklist-checklist--all-tests-comparison-in-progress',\n      'webapp-screens-pullrequest-checklist-checklist--all-tests-no-reviewers',\n      'webapp-screens-pullrequest-checklist-checklist--logged-out',\n      'webapp-screens-pullrequest-checklist-checklist--logged-out-no-reviewers',\n      'webapp-screens-pullrequest-checklist-checklist--pure-selecting-reviewers',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-checklist-checklist--empty': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--empty',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'Empty',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--no-checks': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--no-checks',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'No Checks',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--all-passing': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--all-passing',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'All Passing',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--pending-reviews': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--pending-reviews',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'Pending Reviews',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--active-comment-threads': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--active-comment-threads',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'Active Comment Threads',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--visual-changes': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--visual-changes',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'Visual Changes',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--build-error': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--build-error',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'Build Error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--build-in-progress': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--build-in-progress',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'Build In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--comparison-in-progress': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--comparison-in-progress',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'Comparison In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--no-comparison': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--no-comparison',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'No Comparison',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--diff-errors': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--diff-errors',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'Diff Errors',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--paused-exceeded-threshold': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--paused-exceeded-threshold',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'Paused, Exceeded Threshold',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--paused-exceeded-threshold-org': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--paused-exceeded-threshold-org',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'Paused, Exceeded Threshold, Org',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--paused-exceeded-threshold-no-plan-access': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--paused-exceeded-threshold-no-plan-access',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'Paused, Exceeded Threshold, No Access To Update Plans',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--paused-exceeded-threshold-in-progress-build': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--paused-exceeded-threshold-in-progress-build',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'Paused, Exceeded Threshold, In Progress Build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--paused-exceeded-threshold-error-build': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--paused-exceeded-threshold-error-build',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'Paused, Exceeded Threshold, Error Build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--paused-payment-required': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--paused-payment-required',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'Paused, Payment Required',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--was-paused-now-resumed': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--was-paused-now-resumed',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'Was Paused, Now Resumed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--all-tests': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--all-tests',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'All Tests',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--all-tests-exceeded-threshold': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--all-tests-exceeded-threshold',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'All Tests Exceeded Threshold',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--all-tests-was-paused-now-resumed': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--all-tests-was-paused-now-resumed',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'All Tests, Was Paused, Now Resumed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--all-tests-ui-review-disabled': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--all-tests-ui-review-disabled',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'All Tests UI Review Disabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--all-tests-ui-review-disabled-publish-only': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--all-tests-ui-review-disabled-publish-only',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'All Tests UI Review Disabled Publish Only',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--all-tests-build-error': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--all-tests-build-error',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'All Tests, Build Error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--all-tests-build-in-progress': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--all-tests-build-in-progress',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'All Tests, Build In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--all-tests-comparison-in-progress': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--all-tests-comparison-in-progress',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'All Tests, Comparison In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--all-tests-no-reviewers': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--all-tests-no-reviewers',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'All Tests, No Reviewers',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--logged-out': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--logged-out',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'Logged Out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--logged-out-no-reviewers': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--logged-out-no-reviewers',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'Logged Out, No Reviewers',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklist--pure-selecting-reviewers': {\n    id: 'webapp-screens-pullrequest-checklist-checklist--pure-selecting-reviewers',\n    title: 'Webapp screens/PullRequest/Checklist/Checklist',\n    name: 'Pure, Selecting Reviewers',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistactivecommentthread': {\n    name: 'ChecklistActiveCommentThread',\n    id: 'webapp-screens-pullrequest-checklist-checklistactivecommentthread',\n    parent: 'webapp-screens-pullrequest-checklist',\n    depth: 3,\n    children: [\n      'webapp-screens-pullrequest-checklist-checklistactivecommentthread--base',\n      'webapp-screens-pullrequest-checklist-checklistactivecommentthread--logged-out',\n      'webapp-screens-pullrequest-checklist-checklistactivecommentthread--pure-resolving',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-checklist-checklistactivecommentthread--base': {\n    id: 'webapp-screens-pullrequest-checklist-checklistactivecommentthread--base',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistActiveCommentThread',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistactivecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistactivecommentthread--logged-out': {\n    id: 'webapp-screens-pullrequest-checklist-checklistactivecommentthread--logged-out',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistActiveCommentThread',\n    name: 'Logged Out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistactivecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistactivecommentthread--pure-resolving': {\n    id: 'webapp-screens-pullrequest-checklist-checklistactivecommentthread--pure-resolving',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistActiveCommentThread',\n    name: 'Pure, Resolving',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistactivecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistactivecommentthreads': {\n    name: 'ChecklistActiveCommentThreads',\n    id: 'webapp-screens-pullrequest-checklist-checklistactivecommentthreads',\n    parent: 'webapp-screens-pullrequest-checklist',\n    depth: 3,\n    children: [\n      'webapp-screens-pullrequest-checklist-checklistactivecommentthreads--single',\n      'webapp-screens-pullrequest-checklist-checklistactivecommentthreads--multiple-constrained',\n      'webapp-screens-pullrequest-checklist-checklistactivecommentthreads--multiple',\n      'webapp-screens-pullrequest-checklist-checklistactivecommentthreads--multiple-logged-out',\n      'webapp-screens-pullrequest-checklist-checklistactivecommentthreads--multiple-git-lab',\n      'webapp-screens-pullrequest-checklist-checklistactivecommentthreads--pure-resolving-all',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-checklist-checklistactivecommentthreads--single': {\n    id: 'webapp-screens-pullrequest-checklist-checklistactivecommentthreads--single',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistActiveCommentThreads',\n    name: 'Single',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistactivecommentthreads',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistactivecommentthreads--multiple-constrained': {\n    id: 'webapp-screens-pullrequest-checklist-checklistactivecommentthreads--multiple-constrained',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistActiveCommentThreads',\n    name: 'Multiple, Constrained',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistactivecommentthreads',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistactivecommentthreads--multiple': {\n    id: 'webapp-screens-pullrequest-checklist-checklistactivecommentthreads--multiple',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistActiveCommentThreads',\n    name: 'Multiple',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistactivecommentthreads',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistactivecommentthreads--multiple-logged-out': {\n    id: 'webapp-screens-pullrequest-checklist-checklistactivecommentthreads--multiple-logged-out',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistActiveCommentThreads',\n    name: 'Multiple, Logged Out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistactivecommentthreads',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistactivecommentthreads--multiple-git-lab': {\n    id: 'webapp-screens-pullrequest-checklist-checklistactivecommentthreads--multiple-git-lab',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistActiveCommentThreads',\n    name: 'Multiple, GitLab',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistactivecommentthreads',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistactivecommentthreads--pure-resolving-all': {\n    id: 'webapp-screens-pullrequest-checklist-checklistactivecommentthreads--pure-resolving-all',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistActiveCommentThreads',\n    name: 'Pure, Resolving All',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistactivecommentthreads',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistbuilderrors': {\n    name: 'ChecklistBuildErrors',\n    id: 'webapp-screens-pullrequest-checklist-checklistbuilderrors',\n    parent: 'webapp-screens-pullrequest-checklist',\n    depth: 3,\n    children: ['webapp-screens-pullrequest-checklist-checklistbuilderrors--base'],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-checklist-checklistbuilderrors--base': {\n    id: 'webapp-screens-pullrequest-checklist-checklistbuilderrors--base',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistBuildErrors',\n    name: 'Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistbuilderrors',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklisterroreddiffs': {\n    name: 'ChecklistErroredDiffs',\n    id: 'webapp-screens-pullrequest-checklist-checklisterroreddiffs',\n    parent: 'webapp-screens-pullrequest-checklist',\n    depth: 3,\n    children: [\n      'webapp-screens-pullrequest-checklist-checklisterroreddiffs--single',\n      'webapp-screens-pullrequest-checklist-checklisterroreddiffs--multiple',\n      'webapp-screens-pullrequest-checklist-checklisterroreddiffs--multiple-git-lab',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-checklist-checklisterroreddiffs--single': {\n    id: 'webapp-screens-pullrequest-checklist-checklisterroreddiffs--single',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistErroredDiffs',\n    name: 'Single',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklisterroreddiffs',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklisterroreddiffs--multiple': {\n    id: 'webapp-screens-pullrequest-checklist-checklisterroreddiffs--multiple',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistErroredDiffs',\n    name: 'Multiple',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklisterroreddiffs',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklisterroreddiffs--multiple-git-lab': {\n    id: 'webapp-screens-pullrequest-checklist-checklisterroreddiffs--multiple-git-lab',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistErroredDiffs',\n    name: 'Multiple, GitLab',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklisterroreddiffs',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistheader': {\n    name: 'ChecklistHeader',\n    id: 'webapp-screens-pullrequest-checklist-checklistheader',\n    parent: 'webapp-screens-pullrequest-checklist',\n    depth: 3,\n    children: [\n      'webapp-screens-pullrequest-checklist-checklistheader--no-checks',\n      'webapp-screens-pullrequest-checklist-checklistheader--all-passing',\n      'webapp-screens-pullrequest-checklist-checklistheader--publish-only',\n      'webapp-screens-pullrequest-checklist-checklistheader--with-warnings',\n      'webapp-screens-pullrequest-checklist-checklistheader--with-warnings-git-lab',\n      'webapp-screens-pullrequest-checklist-checklistheader--with-errors',\n      'webapp-screens-pullrequest-checklist-checklistheader--with-build-errors',\n      'webapp-screens-pullrequest-checklist-checklistheader--build-in-progress',\n      'webapp-screens-pullrequest-checklist-checklistheader--comparison-in-progress',\n      'webapp-screens-pullrequest-checklist-checklistheader--ui-review-disabled',\n      'webapp-screens-pullrequest-checklist-checklistheader--with-build-errors-ui-review-disabled',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-checklist-checklistheader--no-checks': {\n    id: 'webapp-screens-pullrequest-checklist-checklistheader--no-checks',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistHeader',\n    name: 'No Checks',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistheader--all-passing': {\n    id: 'webapp-screens-pullrequest-checklist-checklistheader--all-passing',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistHeader',\n    name: 'All Passing',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistheader--publish-only': {\n    id: 'webapp-screens-pullrequest-checklist-checklistheader--publish-only',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistHeader',\n    name: 'Publish Only',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistheader--with-warnings': {\n    id: 'webapp-screens-pullrequest-checklist-checklistheader--with-warnings',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistHeader',\n    name: 'With Warnings',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistheader--with-warnings-git-lab': {\n    id: 'webapp-screens-pullrequest-checklist-checklistheader--with-warnings-git-lab',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistHeader',\n    name: 'With Warnings, GitLab',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistheader--with-errors': {\n    id: 'webapp-screens-pullrequest-checklist-checklistheader--with-errors',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistHeader',\n    name: 'With Errors',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistheader--with-build-errors': {\n    id: 'webapp-screens-pullrequest-checklist-checklistheader--with-build-errors',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistHeader',\n    name: 'With Build Errors',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistheader--build-in-progress': {\n    id: 'webapp-screens-pullrequest-checklist-checklistheader--build-in-progress',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistHeader',\n    name: 'Build In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistheader--comparison-in-progress': {\n    id: 'webapp-screens-pullrequest-checklist-checklistheader--comparison-in-progress',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistHeader',\n    name: 'Comparison In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistheader--ui-review-disabled': {\n    id: 'webapp-screens-pullrequest-checklist-checklistheader--ui-review-disabled',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistHeader',\n    name: 'UI Review Disabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistheader--with-build-errors-ui-review-disabled': {\n    id: 'webapp-screens-pullrequest-checklist-checklistheader--with-build-errors-ui-review-disabled',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistHeader',\n    name: 'With Build Errors, UI Review Disabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistitemheader': {\n    name: 'ChecklistItemHeader',\n    id: 'webapp-screens-pullrequest-checklist-checklistitemheader',\n    parent: 'webapp-screens-pullrequest-checklist',\n    depth: 3,\n    children: [\n      'webapp-screens-pullrequest-checklist-checklistitemheader--warning',\n      'webapp-screens-pullrequest-checklist-checklistitemheader--with-action',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-checklist-checklistitemheader--warning': {\n    id: 'webapp-screens-pullrequest-checklist-checklistitemheader--warning',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistItemHeader',\n    name: 'Warning',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistitemheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistitemheader--with-action': {\n    id: 'webapp-screens-pullrequest-checklist-checklistitemheader--with-action',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistItemHeader',\n    name: 'With Action',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistitemheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistpendingreviews': {\n    name: 'ChecklistPendingReviews',\n    id: 'webapp-screens-pullrequest-checklist-checklistpendingreviews',\n    parent: 'webapp-screens-pullrequest-checklist',\n    depth: 3,\n    children: [\n      'webapp-screens-pullrequest-checklist-checklistpendingreviews--single',\n      'webapp-screens-pullrequest-checklist-checklistpendingreviews--multiple',\n      'webapp-screens-pullrequest-checklist-checklistpendingreviews--multiple-approving',\n      'webapp-screens-pullrequest-checklist-checklistpendingreviews--multiple-unassigning',\n      'webapp-screens-pullrequest-checklist-checklistpendingreviews--multiple-logged-out',\n      'webapp-screens-pullrequest-checklist-checklistpendingreviews--multiple-git-lab',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-checklist-checklistpendingreviews--single': {\n    id: 'webapp-screens-pullrequest-checklist-checklistpendingreviews--single',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistPendingReviews',\n    name: 'Single',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistpendingreviews',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistpendingreviews--multiple': {\n    id: 'webapp-screens-pullrequest-checklist-checklistpendingreviews--multiple',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistPendingReviews',\n    name: 'Multiple',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistpendingreviews',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistpendingreviews--multiple-approving': {\n    id: 'webapp-screens-pullrequest-checklist-checklistpendingreviews--multiple-approving',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistPendingReviews',\n    name: 'Multiple, Approving',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistpendingreviews',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistpendingreviews--multiple-unassigning': {\n    id: 'webapp-screens-pullrequest-checklist-checklistpendingreviews--multiple-unassigning',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistPendingReviews',\n    name: 'Multiple, Unassigning',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistpendingreviews',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistpendingreviews--multiple-logged-out': {\n    id: 'webapp-screens-pullrequest-checklist-checklistpendingreviews--multiple-logged-out',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistPendingReviews',\n    name: 'Multiple, Logged Out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistpendingreviews',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistpendingreviews--multiple-git-lab': {\n    id: 'webapp-screens-pullrequest-checklist-checklistpendingreviews--multiple-git-lab',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistPendingReviews',\n    name: 'Multiple, GitLab',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistpendingreviews',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistspeccolumn': {\n    name: 'ChecklistSpecColumn',\n    id: 'webapp-screens-pullrequest-checklist-checklistspeccolumn',\n    parent: 'webapp-screens-pullrequest-checklist',\n    depth: 3,\n    children: [\n      'webapp-screens-pullrequest-checklist-checklistspeccolumn--loading-spec',\n      'webapp-screens-pullrequest-checklist-checklistspeccolumn--default-spec',\n      'webapp-screens-pullrequest-checklist-checklistspeccolumn--low-data-spec',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-checklist-checklistspeccolumn--loading-spec': {\n    id: 'webapp-screens-pullrequest-checklist-checklistspeccolumn--loading-spec',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistSpecColumn',\n    name: 'Loading Spec',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistspeccolumn',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistspeccolumn--default-spec': {\n    id: 'webapp-screens-pullrequest-checklist-checklistspeccolumn--default-spec',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistSpecColumn',\n    name: 'Default Spec',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistspeccolumn',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistspeccolumn--low-data-spec': {\n    id: 'webapp-screens-pullrequest-checklist-checklistspeccolumn--low-data-spec',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistSpecColumn',\n    name: 'Low Data Spec',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistspeccolumn',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistvisualchanges': {\n    name: 'ChecklistVisualChanges',\n    id: 'webapp-screens-pullrequest-checklist-checklistvisualchanges',\n    parent: 'webapp-screens-pullrequest-checklist',\n    depth: 3,\n    children: [\n      'webapp-screens-pullrequest-checklist-checklistvisualchanges--single',\n      'webapp-screens-pullrequest-checklist-checklistvisualchanges--single-tall-image',\n      'webapp-screens-pullrequest-checklist-checklistvisualchanges--multiple',\n      'webapp-screens-pullrequest-checklist-checklistvisualchanges--approving',\n      'webapp-screens-pullrequest-checklist-checklistvisualchanges--logged-out',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-checklist-checklistvisualchanges--single': {\n    id: 'webapp-screens-pullrequest-checklist-checklistvisualchanges--single',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistVisualChanges',\n    name: 'Single',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistvisualchanges',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistvisualchanges--single-tall-image': {\n    id: 'webapp-screens-pullrequest-checklist-checklistvisualchanges--single-tall-image',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistVisualChanges',\n    name: 'Single, Tall Image',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistvisualchanges',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistvisualchanges--multiple': {\n    id: 'webapp-screens-pullrequest-checklist-checklistvisualchanges--multiple',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistVisualChanges',\n    name: 'Multiple',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistvisualchanges',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistvisualchanges--approving': {\n    id: 'webapp-screens-pullrequest-checklist-checklistvisualchanges--approving',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistVisualChanges',\n    name: 'Approving',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistvisualchanges',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-checklist-checklistvisualchanges--logged-out': {\n    id: 'webapp-screens-pullrequest-checklist-checklistvisualchanges--logged-out',\n    title: 'Webapp screens/PullRequest/Checklist/ChecklistVisualChanges',\n    name: 'Logged Out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-checklist-checklistvisualchanges',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-features': {\n    name: 'Features',\n    id: 'webapp-screens-pullrequest-features',\n    parent: 'webapp-screens-pullrequest',\n    depth: 2,\n    children: [\n      'webapp-screens-pullrequest-features-uireviewfeature',\n      'webapp-screens-pullrequest-features-uitestsfeature',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-pullrequest-features-uireviewfeature': {\n    name: 'UIReviewFeature',\n    id: 'webapp-screens-pullrequest-features-uireviewfeature',\n    parent: 'webapp-screens-pullrequest-features',\n    depth: 3,\n    children: [\n      'webapp-screens-pullrequest-features-uireviewfeature--logged-in',\n      'webapp-screens-pullrequest-features-uireviewfeature--logged-out',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-features-uireviewfeature--logged-in': {\n    id: 'webapp-screens-pullrequest-features-uireviewfeature--logged-in',\n    title: 'Webapp screens/PullRequest/Features/UIReviewFeature',\n    name: 'Logged In',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-features-uireviewfeature',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-features-uireviewfeature--logged-out': {\n    id: 'webapp-screens-pullrequest-features-uireviewfeature--logged-out',\n    title: 'Webapp screens/PullRequest/Features/UIReviewFeature',\n    name: 'Logged Out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-features-uireviewfeature',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-features-uitestsfeature': {\n    name: 'UITestsFeature',\n    id: 'webapp-screens-pullrequest-features-uitestsfeature',\n    parent: 'webapp-screens-pullrequest-features',\n    depth: 3,\n    children: [\n      'webapp-screens-pullrequest-features-uitestsfeature--passed',\n      'webapp-screens-pullrequest-features-uitestsfeature--in-progress',\n      'webapp-screens-pullrequest-features-uitestsfeature--accepted',\n      'webapp-screens-pullrequest-features-uitestsfeature--pending',\n      'webapp-screens-pullrequest-features-uitestsfeature--denied',\n      'webapp-screens-pullrequest-features-uitestsfeature--failed',\n      'webapp-screens-pullrequest-features-uitestsfeature--errored',\n      'webapp-screens-pullrequest-features-uitestsfeature--timed-out',\n      'webapp-screens-pullrequest-features-uitestsfeature--paused',\n      'webapp-screens-pullrequest-features-uitestsfeature--paused-payment-required',\n      'webapp-screens-pullrequest-features-uitestsfeature--paused-organization',\n      'webapp-screens-pullrequest-features-uitestsfeature--paused-organization-no-plan',\n      'webapp-screens-pullrequest-features-uitestsfeature--ui-tests-disabled-for-build-enabled-on-app',\n      'webapp-screens-pullrequest-features-uitestsfeature--ui-tests-paused-for-build-enabled-on-app',\n      'webapp-screens-pullrequest-features-uitestsfeature--disabled',\n      'webapp-screens-pullrequest-features-uitestsfeature--disabled-read-only',\n      'webapp-screens-pullrequest-features-uitestsfeature--disabled-low-spec-count',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-features-uitestsfeature--passed': {\n    id: 'webapp-screens-pullrequest-features-uitestsfeature--passed',\n    title: 'Webapp screens/PullRequest/Features/UITestsFeature',\n    name: 'Passed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-features-uitestsfeature',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-features-uitestsfeature--in-progress': {\n    id: 'webapp-screens-pullrequest-features-uitestsfeature--in-progress',\n    title: 'Webapp screens/PullRequest/Features/UITestsFeature',\n    name: 'In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-features-uitestsfeature',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-features-uitestsfeature--accepted': {\n    id: 'webapp-screens-pullrequest-features-uitestsfeature--accepted',\n    title: 'Webapp screens/PullRequest/Features/UITestsFeature',\n    name: 'Accepted',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-features-uitestsfeature',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-features-uitestsfeature--pending': {\n    id: 'webapp-screens-pullrequest-features-uitestsfeature--pending',\n    title: 'Webapp screens/PullRequest/Features/UITestsFeature',\n    name: 'Pending',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-features-uitestsfeature',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-features-uitestsfeature--denied': {\n    id: 'webapp-screens-pullrequest-features-uitestsfeature--denied',\n    title: 'Webapp screens/PullRequest/Features/UITestsFeature',\n    name: 'Denied',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-features-uitestsfeature',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-features-uitestsfeature--failed': {\n    id: 'webapp-screens-pullrequest-features-uitestsfeature--failed',\n    title: 'Webapp screens/PullRequest/Features/UITestsFeature',\n    name: 'Failed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-features-uitestsfeature',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-features-uitestsfeature--errored': {\n    id: 'webapp-screens-pullrequest-features-uitestsfeature--errored',\n    title: 'Webapp screens/PullRequest/Features/UITestsFeature',\n    name: 'Errored',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-features-uitestsfeature',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-features-uitestsfeature--timed-out': {\n    id: 'webapp-screens-pullrequest-features-uitestsfeature--timed-out',\n    title: 'Webapp screens/PullRequest/Features/UITestsFeature',\n    name: 'Timed Out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-features-uitestsfeature',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-features-uitestsfeature--paused': {\n    id: 'webapp-screens-pullrequest-features-uitestsfeature--paused',\n    title: 'Webapp screens/PullRequest/Features/UITestsFeature',\n    name: 'Paused',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-features-uitestsfeature',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-features-uitestsfeature--paused-payment-required': {\n    id: 'webapp-screens-pullrequest-features-uitestsfeature--paused-payment-required',\n    title: 'Webapp screens/PullRequest/Features/UITestsFeature',\n    name: 'Paused, Payment Required',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-features-uitestsfeature',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-features-uitestsfeature--paused-organization': {\n    id: 'webapp-screens-pullrequest-features-uitestsfeature--paused-organization',\n    title: 'Webapp screens/PullRequest/Features/UITestsFeature',\n    name: 'Paused, Organization',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-features-uitestsfeature',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-features-uitestsfeature--paused-organization-no-plan': {\n    id: 'webapp-screens-pullrequest-features-uitestsfeature--paused-organization-no-plan',\n    title: 'Webapp screens/PullRequest/Features/UITestsFeature',\n    name: 'Paused, Organization, No Plan',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-features-uitestsfeature',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-features-uitestsfeature--ui-tests-disabled-for-build-enabled-on-app':\n    {\n      id: 'webapp-screens-pullrequest-features-uitestsfeature--ui-tests-disabled-for-build-enabled-on-app',\n      title: 'Webapp screens/PullRequest/Features/UITestsFeature',\n      name: 'UI Tests Disabled For Build, Enabled On App',\n      importPath: './path.js',\n      args: {},\n      argTypes: {},\n      initialArgs: {},\n      depth: 4,\n      parent: 'webapp-screens-pullrequest-features-uitestsfeature',\n      type: 'story',\n      subtype: 'story',\n      prepared: true,\n    },\n  'webapp-screens-pullrequest-features-uitestsfeature--ui-tests-paused-for-build-enabled-on-app': {\n    id: 'webapp-screens-pullrequest-features-uitestsfeature--ui-tests-paused-for-build-enabled-on-app',\n    title: 'Webapp screens/PullRequest/Features/UITestsFeature',\n    name: 'UI Tests Paused For Build, Enabled On App',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-features-uitestsfeature',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-features-uitestsfeature--disabled': {\n    id: 'webapp-screens-pullrequest-features-uitestsfeature--disabled',\n    title: 'Webapp screens/PullRequest/Features/UITestsFeature',\n    name: 'Disabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-features-uitestsfeature',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-features-uitestsfeature--disabled-read-only': {\n    id: 'webapp-screens-pullrequest-features-uitestsfeature--disabled-read-only',\n    title: 'Webapp screens/PullRequest/Features/UITestsFeature',\n    name: 'Disabled, Read Only',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-features-uitestsfeature',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-features-uitestsfeature--disabled-low-spec-count': {\n    id: 'webapp-screens-pullrequest-features-uitestsfeature--disabled-low-spec-count',\n    title: 'Webapp screens/PullRequest/Features/UITestsFeature',\n    name: 'Disabled, Low Spec Count',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-pullrequest-features-uitestsfeature',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-nocomparison': {\n    name: 'NoComparison',\n    id: 'webapp-screens-pullrequest-nocomparison',\n    parent: 'webapp-screens-pullrequest',\n    depth: 2,\n    children: [\n      'webapp-screens-pullrequest-nocomparison--no-head-build',\n      'webapp-screens-pullrequest-nocomparison--no-merge-base-build',\n      'webapp-screens-pullrequest-nocomparison--head-build-in-progress',\n      'webapp-screens-pullrequest-nocomparison--patch-build-in-progress',\n      'webapp-screens-pullrequest-nocomparison--publish-only-head-build',\n      'webapp-screens-pullrequest-nocomparison--publish-only-merge-base',\n      'webapp-screens-pullrequest-nocomparison--head-build-errored',\n      'webapp-screens-pullrequest-nocomparison--patch-build-errored',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-nocomparison--no-head-build': {\n    id: 'webapp-screens-pullrequest-nocomparison--no-head-build',\n    title: 'Webapp screens/PullRequest/NoComparison',\n    name: 'No Head Build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-nocomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-nocomparison--no-merge-base-build': {\n    id: 'webapp-screens-pullrequest-nocomparison--no-merge-base-build',\n    title: 'Webapp screens/PullRequest/NoComparison',\n    name: 'No Merge Base Build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-nocomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-nocomparison--head-build-in-progress': {\n    id: 'webapp-screens-pullrequest-nocomparison--head-build-in-progress',\n    title: 'Webapp screens/PullRequest/NoComparison',\n    name: 'Head Build In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-nocomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-nocomparison--patch-build-in-progress': {\n    id: 'webapp-screens-pullrequest-nocomparison--patch-build-in-progress',\n    title: 'Webapp screens/PullRequest/NoComparison',\n    name: 'Patch Build In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-nocomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-nocomparison--publish-only-head-build': {\n    id: 'webapp-screens-pullrequest-nocomparison--publish-only-head-build',\n    title: 'Webapp screens/PullRequest/NoComparison',\n    name: 'Publish Only Head Build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-nocomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-nocomparison--publish-only-merge-base': {\n    id: 'webapp-screens-pullrequest-nocomparison--publish-only-merge-base',\n    title: 'Webapp screens/PullRequest/NoComparison',\n    name: 'Publish Only Merge Base',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-nocomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-nocomparison--head-build-errored': {\n    id: 'webapp-screens-pullrequest-nocomparison--head-build-errored',\n    title: 'Webapp screens/PullRequest/NoComparison',\n    name: 'Head Build Errored',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-nocomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-nocomparison--patch-build-errored': {\n    id: 'webapp-screens-pullrequest-nocomparison--patch-build-errored',\n    title: 'Webapp screens/PullRequest/NoComparison',\n    name: 'Patch Build Errored',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-nocomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangecomments': {\n    name: 'PullRequestChangeComments',\n    id: 'webapp-screens-pullrequest-pullrequestchangecomments',\n    parent: 'webapp-screens-pullrequest',\n    depth: 2,\n    children: [\n      'webapp-screens-pullrequest-pullrequestchangecomments--no-thread',\n      'webapp-screens-pullrequest-pullrequestchangecomments--no-thread-new-story',\n      'webapp-screens-pullrequest-pullrequestchangecomments--no-thread-removed-story',\n      'webapp-screens-pullrequest-pullrequestchangecomments--active-thread',\n      'webapp-screens-pullrequest-pullrequestchangecomments--resolved-thread',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-pullrequestchangecomments--no-thread': {\n    id: 'webapp-screens-pullrequest-pullrequestchangecomments--no-thread',\n    title: 'Webapp screens/PullRequest/PullRequestChangeComments',\n    name: 'no thread',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangecomments',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangecomments--no-thread-new-story': {\n    id: 'webapp-screens-pullrequest-pullrequestchangecomments--no-thread-new-story',\n    title: 'Webapp screens/PullRequest/PullRequestChangeComments',\n    name: 'no thread, new story',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangecomments',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangecomments--no-thread-removed-story': {\n    id: 'webapp-screens-pullrequest-pullrequestchangecomments--no-thread-removed-story',\n    title: 'Webapp screens/PullRequest/PullRequestChangeComments',\n    name: 'no thread, removed story',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangecomments',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangecomments--active-thread': {\n    id: 'webapp-screens-pullrequest-pullrequestchangecomments--active-thread',\n    title: 'Webapp screens/PullRequest/PullRequestChangeComments',\n    name: 'active thread',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangecomments',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangecomments--resolved-thread': {\n    id: 'webapp-screens-pullrequest-pullrequestchangecomments--resolved-thread',\n    title: 'Webapp screens/PullRequest/PullRequestChangeComments',\n    name: 'resolved thread',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangecomments',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangecommentthread': {\n    name: 'PullRequestChangeCommentThread',\n    id: 'webapp-screens-pullrequest-pullrequestchangecommentthread',\n    parent: 'webapp-screens-pullrequest',\n    depth: 2,\n    children: [\n      'webapp-screens-pullrequest-pullrequestchangecommentthread--no-user',\n      'webapp-screens-pullrequest-pullrequestchangecommentthread--w-user',\n      'webapp-screens-pullrequest-pullrequestchangecommentthread--pure-w-user',\n      'webapp-screens-pullrequest-pullrequestchangecommentthread--pure-w-user-collapsed',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-pullrequestchangecommentthread--no-user': {\n    id: 'webapp-screens-pullrequest-pullrequestchangecommentthread--no-user',\n    title: 'Webapp screens/PullRequest/PullRequestChangeCommentThread',\n    name: 'no user',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangecommentthread--w-user': {\n    id: 'webapp-screens-pullrequest-pullrequestchangecommentthread--w-user',\n    title: 'Webapp screens/PullRequest/PullRequestChangeCommentThread',\n    name: 'w/ user',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangecommentthread--pure-w-user': {\n    id: 'webapp-screens-pullrequest-pullrequestchangecommentthread--pure-w-user',\n    title: 'Webapp screens/PullRequest/PullRequestChangeCommentThread',\n    name: 'pure, w/ user',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangecommentthread--pure-w-user-collapsed': {\n    id: 'webapp-screens-pullrequest-pullrequestchangecommentthread--pure-w-user-collapsed',\n    title: 'Webapp screens/PullRequest/PullRequestChangeCommentThread',\n    name: 'pure, w/ user, collapsed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangecommentthread',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangeitem': {\n    name: 'PullRequestChangeItem',\n    id: 'webapp-screens-pullrequest-pullrequestchangeitem',\n    parent: 'webapp-screens-pullrequest',\n    depth: 2,\n    children: [\n      'webapp-screens-pullrequest-pullrequestchangeitem--loading',\n      'webapp-screens-pullrequest-pullrequestchangeitem--added',\n      'webapp-screens-pullrequest-pullrequestchangeitem--added-logged-out',\n      'webapp-screens-pullrequest-pullrequestchangeitem--added-w-active-comment-thread',\n      'webapp-screens-pullrequest-pullrequestchangeitem--removed',\n      'webapp-screens-pullrequest-pullrequestchangeitem--visually-different',\n      'webapp-screens-pullrequest-pullrequestchangeitem--visually-different-after-upgrade',\n      'webapp-screens-pullrequest-pullrequestchangeitem--scaled',\n      'webapp-screens-pullrequest-pullrequestchangeitem--size-changed',\n      'webapp-screens-pullrequest-pullrequestchangeitem--errored',\n      'webapp-screens-pullrequest-pullrequestchangeitem--fixed',\n      'webapp-screens-pullrequest-pullrequestchangeitem--no-diff',\n      'webapp-screens-pullrequest-pullrequestchangeitem--diff',\n      'webapp-screens-pullrequest-pullrequestchangeitem--diff-strobe',\n      'webapp-screens-pullrequest-pullrequestchangeitem--diff-focus',\n      'webapp-screens-pullrequest-pullrequestchangeitem--diff-focus-strobe',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-pullrequestchangeitem--loading': {\n    id: 'webapp-screens-pullrequest-pullrequestchangeitem--loading',\n    title: 'Webapp screens/PullRequest/PullRequestChangeItem',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangeitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangeitem--added': {\n    id: 'webapp-screens-pullrequest-pullrequestchangeitem--added',\n    title: 'Webapp screens/PullRequest/PullRequestChangeItem',\n    name: 'added',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangeitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangeitem--added-logged-out': {\n    id: 'webapp-screens-pullrequest-pullrequestchangeitem--added-logged-out',\n    title: 'Webapp screens/PullRequest/PullRequestChangeItem',\n    name: 'added, logged out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangeitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangeitem--added-w-active-comment-thread': {\n    id: 'webapp-screens-pullrequest-pullrequestchangeitem--added-w-active-comment-thread',\n    title: 'Webapp screens/PullRequest/PullRequestChangeItem',\n    name: 'added, w/ active comment thread',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangeitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangeitem--removed': {\n    id: 'webapp-screens-pullrequest-pullrequestchangeitem--removed',\n    title: 'Webapp screens/PullRequest/PullRequestChangeItem',\n    name: 'removed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangeitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangeitem--visually-different': {\n    id: 'webapp-screens-pullrequest-pullrequestchangeitem--visually-different',\n    title: 'Webapp screens/PullRequest/PullRequestChangeItem',\n    name: 'visually different',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangeitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangeitem--visually-different-after-upgrade': {\n    id: 'webapp-screens-pullrequest-pullrequestchangeitem--visually-different-after-upgrade',\n    title: 'Webapp screens/PullRequest/PullRequestChangeItem',\n    name: 'visually different after upgrade',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangeitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangeitem--scaled': {\n    id: 'webapp-screens-pullrequest-pullrequestchangeitem--scaled',\n    title: 'Webapp screens/PullRequest/PullRequestChangeItem',\n    name: 'scaled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangeitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangeitem--size-changed': {\n    id: 'webapp-screens-pullrequest-pullrequestchangeitem--size-changed',\n    title: 'Webapp screens/PullRequest/PullRequestChangeItem',\n    name: 'size changed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangeitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangeitem--errored': {\n    id: 'webapp-screens-pullrequest-pullrequestchangeitem--errored',\n    title: 'Webapp screens/PullRequest/PullRequestChangeItem',\n    name: 'errored',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangeitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangeitem--fixed': {\n    id: 'webapp-screens-pullrequest-pullrequestchangeitem--fixed',\n    title: 'Webapp screens/PullRequest/PullRequestChangeItem',\n    name: 'fixed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangeitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangeitem--no-diff': {\n    id: 'webapp-screens-pullrequest-pullrequestchangeitem--no-diff',\n    title: 'Webapp screens/PullRequest/PullRequestChangeItem',\n    name: 'no diff',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangeitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangeitem--diff': {\n    id: 'webapp-screens-pullrequest-pullrequestchangeitem--diff',\n    title: 'Webapp screens/PullRequest/PullRequestChangeItem',\n    name: 'diff',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangeitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangeitem--diff-strobe': {\n    id: 'webapp-screens-pullrequest-pullrequestchangeitem--diff-strobe',\n    title: 'Webapp screens/PullRequest/PullRequestChangeItem',\n    name: 'diff strobe',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangeitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangeitem--diff-focus': {\n    id: 'webapp-screens-pullrequest-pullrequestchangeitem--diff-focus',\n    title: 'Webapp screens/PullRequest/PullRequestChangeItem',\n    name: 'diff focus',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangeitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchangeitem--diff-focus-strobe': {\n    id: 'webapp-screens-pullrequest-pullrequestchangeitem--diff-focus-strobe',\n    title: 'Webapp screens/PullRequest/PullRequestChangeItem',\n    name: 'diff focus+strobe',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchangeitem',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchanges': {\n    name: 'PullRequestChanges',\n    id: 'webapp-screens-pullrequest-pullrequestchanges',\n    parent: 'webapp-screens-pullrequest',\n    depth: 2,\n    children: [\n      'webapp-screens-pullrequest-pullrequestchanges--default',\n      'webapp-screens-pullrequest-pullrequestchanges--ui-review-disabled',\n      'webapp-screens-pullrequest-pullrequestchanges--ui-review-disabled-logged-out',\n      'webapp-screens-pullrequest-pullrequestchanges--ui-review-paused',\n      'webapp-screens-pullrequest-pullrequestchanges--ui-review-paused-logged-out',\n      'webapp-screens-pullrequest-pullrequestchanges--ui-review-blocked',\n      'webapp-screens-pullrequest-pullrequestchanges--ui-review-blocked-logged-out',\n      'webapp-screens-pullrequest-pullrequestchanges--loading',\n      'webapp-screens-pullrequest-pullrequestchanges--build-in-progress-80-complete',\n      'webapp-screens-pullrequest-pullrequestchanges--comparison-in-progress-20-complete',\n      'webapp-screens-pullrequest-pullrequestchanges--empty',\n      'webapp-screens-pullrequest-pullrequestchanges--unsupported',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-pullrequestchanges--default': {\n    id: 'webapp-screens-pullrequest-pullrequestchanges--default',\n    title: 'Webapp screens/PullRequest/PullRequestChanges',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchanges',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchanges--ui-review-disabled': {\n    id: 'webapp-screens-pullrequest-pullrequestchanges--ui-review-disabled',\n    title: 'Webapp screens/PullRequest/PullRequestChanges',\n    name: 'UI Review Disabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchanges',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchanges--ui-review-disabled-logged-out': {\n    id: 'webapp-screens-pullrequest-pullrequestchanges--ui-review-disabled-logged-out',\n    title: 'Webapp screens/PullRequest/PullRequestChanges',\n    name: 'UI Review Disabled Logged Out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchanges',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchanges--ui-review-paused': {\n    id: 'webapp-screens-pullrequest-pullrequestchanges--ui-review-paused',\n    title: 'Webapp screens/PullRequest/PullRequestChanges',\n    name: 'UI Review Paused',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchanges',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchanges--ui-review-paused-logged-out': {\n    id: 'webapp-screens-pullrequest-pullrequestchanges--ui-review-paused-logged-out',\n    title: 'Webapp screens/PullRequest/PullRequestChanges',\n    name: 'UI Review Paused Logged Out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchanges',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchanges--ui-review-blocked': {\n    id: 'webapp-screens-pullrequest-pullrequestchanges--ui-review-blocked',\n    title: 'Webapp screens/PullRequest/PullRequestChanges',\n    name: 'UI Review Blocked',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchanges',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchanges--ui-review-blocked-logged-out': {\n    id: 'webapp-screens-pullrequest-pullrequestchanges--ui-review-blocked-logged-out',\n    title: 'Webapp screens/PullRequest/PullRequestChanges',\n    name: 'UI Review Blocked Logged Out',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchanges',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchanges--loading': {\n    id: 'webapp-screens-pullrequest-pullrequestchanges--loading',\n    title: 'Webapp screens/PullRequest/PullRequestChanges',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchanges',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchanges--build-in-progress-80-complete': {\n    id: 'webapp-screens-pullrequest-pullrequestchanges--build-in-progress-80-complete',\n    title: 'Webapp screens/PullRequest/PullRequestChanges',\n    name: 'Build In Progress (80% complete)',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchanges',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchanges--comparison-in-progress-20-complete': {\n    id: 'webapp-screens-pullrequest-pullrequestchanges--comparison-in-progress-20-complete',\n    title: 'Webapp screens/PullRequest/PullRequestChanges',\n    name: 'Comparison In Progress (20% complete)',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchanges',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchanges--empty': {\n    id: 'webapp-screens-pullrequest-pullrequestchanges--empty',\n    title: 'Webapp screens/PullRequest/PullRequestChanges',\n    name: 'Empty',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchanges',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchanges--unsupported': {\n    id: 'webapp-screens-pullrequest-pullrequestchanges--unsupported',\n    title: 'Webapp screens/PullRequest/PullRequestChanges',\n    name: 'Unsupported',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchanges',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchecktooltip': {\n    name: 'PullRequestCheckTooltip',\n    id: 'webapp-screens-pullrequest-pullrequestchecktooltip',\n    parent: 'webapp-screens-pullrequest',\n    depth: 2,\n    children: [\n      'webapp-screens-pullrequest-pullrequestchecktooltip--passing',\n      'webapp-screens-pullrequest-pullrequestchecktooltip--passing-ui-review-disabled',\n      'webapp-screens-pullrequest-pullrequestchecktooltip--passing-no-changes',\n      'webapp-screens-pullrequest-pullrequestchecktooltip--passing-no-changes-in-progress',\n      'webapp-screens-pullrequest-pullrequestchecktooltip--representative-only-build',\n      'webapp-screens-pullrequest-pullrequestchecktooltip--representative-only-build-resumed',\n      'webapp-screens-pullrequest-pullrequestchecktooltip--representative-only-build-in-progress',\n      'webapp-screens-pullrequest-pullrequestchecktooltip--representative-only-build-error',\n      'webapp-screens-pullrequest-pullrequestchecktooltip--pending-incomplete-setup',\n      'webapp-screens-pullrequest-pullrequestchecktooltip--awaiting-activity',\n      'webapp-screens-pullrequest-pullrequestchecktooltip--pending-visual-changes',\n      'webapp-screens-pullrequest-pullrequestchecktooltip--pending-reviews',\n      'webapp-screens-pullrequest-pullrequestchecktooltip--active-comment-threads',\n      'webapp-screens-pullrequest-pullrequestchecktooltip--errored-diffs',\n      'webapp-screens-pullrequest-pullrequestchecktooltip--all-tests',\n      'webapp-screens-pullrequest-pullrequestchecktooltip--build-error',\n      'webapp-screens-pullrequest-pullrequestchecktooltip--git-lab',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-pullrequestchecktooltip--passing': {\n    id: 'webapp-screens-pullrequest-pullrequestchecktooltip--passing',\n    title: 'Webapp screens/PullRequest/PullRequestCheckTooltip',\n    name: 'Passing',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchecktooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchecktooltip--passing-ui-review-disabled': {\n    id: 'webapp-screens-pullrequest-pullrequestchecktooltip--passing-ui-review-disabled',\n    title: 'Webapp screens/PullRequest/PullRequestCheckTooltip',\n    name: 'Passing, UI Review Disabled',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchecktooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchecktooltip--passing-no-changes': {\n    id: 'webapp-screens-pullrequest-pullrequestchecktooltip--passing-no-changes',\n    title: 'Webapp screens/PullRequest/PullRequestCheckTooltip',\n    name: 'Passing, No Changes',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchecktooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchecktooltip--passing-no-changes-in-progress': {\n    id: 'webapp-screens-pullrequest-pullrequestchecktooltip--passing-no-changes-in-progress',\n    title: 'Webapp screens/PullRequest/PullRequestCheckTooltip',\n    name: 'Passing, No Changes, In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchecktooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchecktooltip--representative-only-build': {\n    id: 'webapp-screens-pullrequest-pullrequestchecktooltip--representative-only-build',\n    title: 'Webapp screens/PullRequest/PullRequestCheckTooltip',\n    name: 'Representative Only Build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchecktooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchecktooltip--representative-only-build-resumed': {\n    id: 'webapp-screens-pullrequest-pullrequestchecktooltip--representative-only-build-resumed',\n    title: 'Webapp screens/PullRequest/PullRequestCheckTooltip',\n    name: 'Representative Only Build, Resumed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchecktooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchecktooltip--representative-only-build-in-progress': {\n    id: 'webapp-screens-pullrequest-pullrequestchecktooltip--representative-only-build-in-progress',\n    title: 'Webapp screens/PullRequest/PullRequestCheckTooltip',\n    name: 'Representative Only Build In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchecktooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchecktooltip--representative-only-build-error': {\n    id: 'webapp-screens-pullrequest-pullrequestchecktooltip--representative-only-build-error',\n    title: 'Webapp screens/PullRequest/PullRequestCheckTooltip',\n    name: 'Representative Only Build w/ Error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchecktooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchecktooltip--pending-incomplete-setup': {\n    id: 'webapp-screens-pullrequest-pullrequestchecktooltip--pending-incomplete-setup',\n    title: 'Webapp screens/PullRequest/PullRequestCheckTooltip',\n    name: 'Pending, Incomplete Setup',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchecktooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchecktooltip--awaiting-activity': {\n    id: 'webapp-screens-pullrequest-pullrequestchecktooltip--awaiting-activity',\n    title: 'Webapp screens/PullRequest/PullRequestCheckTooltip',\n    name: 'Awaiting activity',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchecktooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchecktooltip--pending-visual-changes': {\n    id: 'webapp-screens-pullrequest-pullrequestchecktooltip--pending-visual-changes',\n    title: 'Webapp screens/PullRequest/PullRequestCheckTooltip',\n    name: 'Pending, Visual Changes',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchecktooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchecktooltip--pending-reviews': {\n    id: 'webapp-screens-pullrequest-pullrequestchecktooltip--pending-reviews',\n    title: 'Webapp screens/PullRequest/PullRequestCheckTooltip',\n    name: 'Pending Reviews',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchecktooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchecktooltip--active-comment-threads': {\n    id: 'webapp-screens-pullrequest-pullrequestchecktooltip--active-comment-threads',\n    title: 'Webapp screens/PullRequest/PullRequestCheckTooltip',\n    name: 'Active Comment Threads',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchecktooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchecktooltip--errored-diffs': {\n    id: 'webapp-screens-pullrequest-pullrequestchecktooltip--errored-diffs',\n    title: 'Webapp screens/PullRequest/PullRequestCheckTooltip',\n    name: 'Errored Diffs',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchecktooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchecktooltip--all-tests': {\n    id: 'webapp-screens-pullrequest-pullrequestchecktooltip--all-tests',\n    title: 'Webapp screens/PullRequest/PullRequestCheckTooltip',\n    name: 'All Tests',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchecktooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchecktooltip--build-error': {\n    id: 'webapp-screens-pullrequest-pullrequestchecktooltip--build-error',\n    title: 'Webapp screens/PullRequest/PullRequestCheckTooltip',\n    name: 'Build Error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchecktooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestchecktooltip--git-lab': {\n    id: 'webapp-screens-pullrequest-pullrequestchecktooltip--git-lab',\n    title: 'Webapp screens/PullRequest/PullRequestCheckTooltip',\n    name: 'Git Lab',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestchecktooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestcomponents': {\n    name: 'PullRequestComponents',\n    id: 'webapp-screens-pullrequest-pullrequestcomponents',\n    parent: 'webapp-screens-pullrequest',\n    depth: 2,\n    children: [\n      'webapp-screens-pullrequest-pullrequestcomponents--loading',\n      'webapp-screens-pullrequest-pullrequestcomponents--simple',\n      'webapp-screens-pullrequest-pullrequestcomponents--passed',\n      'webapp-screens-pullrequest-pullrequestcomponents--failed',\n      'webapp-screens-pullrequest-pullrequestcomponents--in-progress',\n      'webapp-screens-pullrequest-pullrequestcomponents--empty',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-pullrequestcomponents--loading': {\n    id: 'webapp-screens-pullrequest-pullrequestcomponents--loading',\n    title: 'Webapp screens/PullRequest/PullRequestComponents',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestcomponents',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestcomponents--simple': {\n    id: 'webapp-screens-pullrequest-pullrequestcomponents--simple',\n    title: 'Webapp screens/PullRequest/PullRequestComponents',\n    name: 'simple',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestcomponents',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestcomponents--passed': {\n    id: 'webapp-screens-pullrequest-pullrequestcomponents--passed',\n    title: 'Webapp screens/PullRequest/PullRequestComponents',\n    name: 'passed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestcomponents',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestcomponents--failed': {\n    id: 'webapp-screens-pullrequest-pullrequestcomponents--failed',\n    title: 'Webapp screens/PullRequest/PullRequestComponents',\n    name: 'failed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestcomponents',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestcomponents--in-progress': {\n    id: 'webapp-screens-pullrequest-pullrequestcomponents--in-progress',\n    title: 'Webapp screens/PullRequest/PullRequestComponents',\n    name: 'in progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestcomponents',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestcomponents--empty': {\n    id: 'webapp-screens-pullrequest-pullrequestcomponents--empty',\n    title: 'Webapp screens/PullRequest/PullRequestComponents',\n    name: 'empty',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestcomponents',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestexplainer': {\n    name: 'PullRequestExplainer',\n    id: 'webapp-screens-pullrequest-pullrequestexplainer',\n    parent: 'webapp-screens-pullrequest',\n    depth: 2,\n    children: ['webapp-screens-pullrequest-pullrequestexplainer--default'],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-pullrequestexplainer--default': {\n    id: 'webapp-screens-pullrequest-pullrequestexplainer--default',\n    title: 'Webapp screens/PullRequest/PullRequestExplainer',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestexplainer',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestheader': {\n    name: 'PullRequestHeader',\n    id: 'webapp-screens-pullrequest-pullrequestheader',\n    parent: 'webapp-screens-pullrequest',\n    depth: 2,\n    children: [\n      'webapp-screens-pullrequest-pullrequestheader--loading',\n      'webapp-screens-pullrequest-pullrequestheader--open-unbuilt',\n      'webapp-screens-pullrequest-pullrequestheader--open-building',\n      'webapp-screens-pullrequest-pullrequestheader--merged-passed',\n      'webapp-screens-pullrequest-pullrequestheader--open-pending',\n      'webapp-screens-pullrequest-pullrequestheader--errored-closed',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-pullrequestheader--loading': {\n    id: 'webapp-screens-pullrequest-pullrequestheader--loading',\n    title: 'Webapp screens/PullRequest/PullRequestHeader',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestheader--open-unbuilt': {\n    id: 'webapp-screens-pullrequest-pullrequestheader--open-unbuilt',\n    title: 'Webapp screens/PullRequest/PullRequestHeader',\n    name: 'Open, unbuilt',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestheader--open-building': {\n    id: 'webapp-screens-pullrequest-pullrequestheader--open-building',\n    title: 'Webapp screens/PullRequest/PullRequestHeader',\n    name: 'Open, building',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestheader--merged-passed': {\n    id: 'webapp-screens-pullrequest-pullrequestheader--merged-passed',\n    title: 'Webapp screens/PullRequest/PullRequestHeader',\n    name: 'Merged, passed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestheader--open-pending': {\n    id: 'webapp-screens-pullrequest-pullrequestheader--open-pending',\n    title: 'Webapp screens/PullRequest/PullRequestHeader',\n    name: 'Open, pending',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestheader--errored-closed': {\n    id: 'webapp-screens-pullrequest-pullrequestheader--errored-closed',\n    title: 'Webapp screens/PullRequest/PullRequestHeader',\n    name: 'Errored, closed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestparticipants': {\n    name: 'PullRequestParticipants',\n    id: 'webapp-screens-pullrequest-pullrequestparticipants',\n    parent: 'webapp-screens-pullrequest',\n    depth: 2,\n    children: [\n      'webapp-screens-pullrequest-pullrequestparticipants--loading',\n      'webapp-screens-pullrequest-pullrequestparticipants--default',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-pullrequestparticipants--loading': {\n    id: 'webapp-screens-pullrequest-pullrequestparticipants--loading',\n    title: 'Webapp screens/PullRequest/PullRequestParticipants',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestparticipants',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestparticipants--default': {\n    id: 'webapp-screens-pullrequest-pullrequestparticipants--default',\n    title: 'Webapp screens/PullRequest/PullRequestParticipants',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestparticipants',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestreviewers': {\n    name: 'PullRequestReviewers',\n    id: 'webapp-screens-pullrequest-pullrequestreviewers',\n    parent: 'webapp-screens-pullrequest',\n    depth: 2,\n    children: [\n      'webapp-screens-pullrequest-pullrequestreviewers--loading',\n      'webapp-screens-pullrequest-pullrequestreviewers--stateful',\n      'webapp-screens-pullrequest-pullrequestreviewers--unreviewed',\n      'webapp-screens-pullrequest-pullrequestreviewers--unreviewed-limited',\n      'webapp-screens-pullrequest-pullrequestreviewers--assigning',\n      'webapp-screens-pullrequest-pullrequestreviewers--assigned-tooltip',\n      'webapp-screens-pullrequest-pullrequestreviewers--assigned',\n      'webapp-screens-pullrequest-pullrequestreviewers--ui-review-disabled-assigned',\n      'webapp-screens-pullrequest-pullrequestreviewers--paused',\n      'webapp-screens-pullrequest-pullrequestreviewers--approved',\n      'webapp-screens-pullrequest-pullrequestreviewers--ui-review-disabled-approved',\n      'webapp-screens-pullrequest-pullrequestreviewers--unreviewed-anonymous',\n      'webapp-screens-pullrequest-pullrequestreviewers--ui-review-disabled-unreviewed-anonymous',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-pullrequestreviewers--loading': {\n    id: 'webapp-screens-pullrequest-pullrequestreviewers--loading',\n    title: 'Webapp screens/PullRequest/PullRequestReviewers',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestreviewers',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestreviewers--stateful': {\n    id: 'webapp-screens-pullrequest-pullrequestreviewers--stateful',\n    title: 'Webapp screens/PullRequest/PullRequestReviewers',\n    name: 'Stateful',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestreviewers',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestreviewers--unreviewed': {\n    id: 'webapp-screens-pullrequest-pullrequestreviewers--unreviewed',\n    title: 'Webapp screens/PullRequest/PullRequestReviewers',\n    name: 'Unreviewed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestreviewers',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestreviewers--unreviewed-limited': {\n    id: 'webapp-screens-pullrequest-pullrequestreviewers--unreviewed-limited',\n    title: 'Webapp screens/PullRequest/PullRequestReviewers',\n    name: 'Unreviewed Limited',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestreviewers',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestreviewers--assigning': {\n    id: 'webapp-screens-pullrequest-pullrequestreviewers--assigning',\n    title: 'Webapp screens/PullRequest/PullRequestReviewers',\n    name: 'Assigning',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestreviewers',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestreviewers--assigned-tooltip': {\n    id: 'webapp-screens-pullrequest-pullrequestreviewers--assigned-tooltip',\n    title: 'Webapp screens/PullRequest/PullRequestReviewers',\n    name: 'Assigned PR, open tooltip, selecting reviewers',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestreviewers',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestreviewers--assigned': {\n    id: 'webapp-screens-pullrequest-pullrequestreviewers--assigned',\n    title: 'Webapp screens/PullRequest/PullRequestReviewers',\n    name: 'Assigned',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestreviewers',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestreviewers--ui-review-disabled-assigned': {\n    id: 'webapp-screens-pullrequest-pullrequestreviewers--ui-review-disabled-assigned',\n    title: 'Webapp screens/PullRequest/PullRequestReviewers',\n    name: 'UI Review Disabled, Assigned',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestreviewers',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestreviewers--paused': {\n    id: 'webapp-screens-pullrequest-pullrequestreviewers--paused',\n    title: 'Webapp screens/PullRequest/PullRequestReviewers',\n    name: 'Paused',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestreviewers',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestreviewers--approved': {\n    id: 'webapp-screens-pullrequest-pullrequestreviewers--approved',\n    title: 'Webapp screens/PullRequest/PullRequestReviewers',\n    name: 'Approved',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestreviewers',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestreviewers--ui-review-disabled-approved': {\n    id: 'webapp-screens-pullrequest-pullrequestreviewers--ui-review-disabled-approved',\n    title: 'Webapp screens/PullRequest/PullRequestReviewers',\n    name: 'UI Review Disabled, Approved',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestreviewers',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestreviewers--unreviewed-anonymous': {\n    id: 'webapp-screens-pullrequest-pullrequestreviewers--unreviewed-anonymous',\n    title: 'Webapp screens/PullRequest/PullRequestReviewers',\n    name: 'Unreviewed, anonymous',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestreviewers',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestreviewers--ui-review-disabled-unreviewed-anonymous': {\n    id: 'webapp-screens-pullrequest-pullrequestreviewers--ui-review-disabled-unreviewed-anonymous',\n    title: 'Webapp screens/PullRequest/PullRequestReviewers',\n    name: 'UI Review Disabled, Unreviewed, anonymous',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestreviewers',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestscreen': {\n    name: 'PullRequestScreen',\n    id: 'webapp-screens-pullrequest-pullrequestscreen',\n    parent: 'webapp-screens-pullrequest',\n    depth: 2,\n    children: [\n      'webapp-screens-pullrequest-pullrequestscreen--loading',\n      'webapp-screens-pullrequest-pullrequestscreen--no-builds',\n      'webapp-screens-pullrequest-pullrequestscreen--activity',\n      'webapp-screens-pullrequest-pullrequestscreen--activity-no-merge-base-build',\n      'webapp-screens-pullrequest-pullrequestscreen--loading-reviews-approving',\n      'webapp-screens-pullrequest-pullrequestscreen--loading-reviews-unapproving',\n      'webapp-screens-pullrequest-pullrequestscreen--explainer',\n      'webapp-screens-pullrequest-pullrequestscreen--comments',\n      'webapp-screens-pullrequest-pullrequestscreen--components',\n      'webapp-screens-pullrequest-pullrequestscreen--ui-changes',\n      'webapp-screens-pullrequest-pullrequestscreen--ui-changes-loading-diffs',\n      'webapp-screens-pullrequest-pullrequestscreen--ui-changes-build-in-progress',\n      'webapp-screens-pullrequest-pullrequestscreen--ui-changes-comparison-in-progress',\n      'webapp-screens-pullrequest-pullrequestscreen--ui-changes-no-changes',\n      'webapp-screens-pullrequest-pullrequestscreen--ui-changes-with-errors',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-pullrequestscreen--loading': {\n    id: 'webapp-screens-pullrequest-pullrequestscreen--loading',\n    title: 'Webapp screens/PullRequest/PullRequestScreen',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestscreen--no-builds': {\n    id: 'webapp-screens-pullrequest-pullrequestscreen--no-builds',\n    title: 'Webapp screens/PullRequest/PullRequestScreen',\n    name: 'No Builds',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestscreen--activity': {\n    id: 'webapp-screens-pullrequest-pullrequestscreen--activity',\n    title: 'Webapp screens/PullRequest/PullRequestScreen',\n    name: 'Activity',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestscreen--activity-no-merge-base-build': {\n    id: 'webapp-screens-pullrequest-pullrequestscreen--activity-no-merge-base-build',\n    title: 'Webapp screens/PullRequest/PullRequestScreen',\n    name: 'Activity No Merge Base Build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestscreen--loading-reviews-approving': {\n    id: 'webapp-screens-pullrequest-pullrequestscreen--loading-reviews-approving',\n    title: 'Webapp screens/PullRequest/PullRequestScreen',\n    name: 'Loading Reviews Approving',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestscreen--loading-reviews-unapproving': {\n    id: 'webapp-screens-pullrequest-pullrequestscreen--loading-reviews-unapproving',\n    title: 'Webapp screens/PullRequest/PullRequestScreen',\n    name: 'Loading Reviews Unapproving',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestscreen--explainer': {\n    id: 'webapp-screens-pullrequest-pullrequestscreen--explainer',\n    title: 'Webapp screens/PullRequest/PullRequestScreen',\n    name: 'Explainer',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestscreen--comments': {\n    id: 'webapp-screens-pullrequest-pullrequestscreen--comments',\n    title: 'Webapp screens/PullRequest/PullRequestScreen',\n    name: 'Comments',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestscreen--components': {\n    id: 'webapp-screens-pullrequest-pullrequestscreen--components',\n    title: 'Webapp screens/PullRequest/PullRequestScreen',\n    name: 'Components',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestscreen--ui-changes': {\n    id: 'webapp-screens-pullrequest-pullrequestscreen--ui-changes',\n    title: 'Webapp screens/PullRequest/PullRequestScreen',\n    name: 'UI Changes',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestscreen--ui-changes-loading-diffs': {\n    id: 'webapp-screens-pullrequest-pullrequestscreen--ui-changes-loading-diffs',\n    title: 'Webapp screens/PullRequest/PullRequestScreen',\n    name: 'UI Changes Loading Diffs',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestscreen--ui-changes-build-in-progress': {\n    id: 'webapp-screens-pullrequest-pullrequestscreen--ui-changes-build-in-progress',\n    title: 'Webapp screens/PullRequest/PullRequestScreen',\n    name: 'UI Changes Build In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestscreen--ui-changes-comparison-in-progress': {\n    id: 'webapp-screens-pullrequest-pullrequestscreen--ui-changes-comparison-in-progress',\n    title: 'Webapp screens/PullRequest/PullRequestScreen',\n    name: 'UI Changes Comparison In Progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestscreen--ui-changes-no-changes': {\n    id: 'webapp-screens-pullrequest-pullrequestscreen--ui-changes-no-changes',\n    title: 'Webapp screens/PullRequest/PullRequestScreen',\n    name: 'UI Changes No Changes',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-pullrequestscreen--ui-changes-with-errors': {\n    id: 'webapp-screens-pullrequest-pullrequestscreen--ui-changes-with-errors',\n    title: 'Webapp screens/PullRequest/PullRequestScreen',\n    name: 'UI Changes With Errors',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-pullrequestscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-reviewbutton': {\n    name: 'ReviewButton',\n    id: 'webapp-screens-pullrequest-reviewbutton',\n    parent: 'webapp-screens-pullrequest',\n    depth: 2,\n    children: [\n      'webapp-screens-pullrequest-reviewbutton--unreviewed',\n      'webapp-screens-pullrequest-reviewbutton--assigned',\n      'webapp-screens-pullrequest-reviewbutton--approving',\n      'webapp-screens-pullrequest-reviewbutton--approved',\n      'webapp-screens-pullrequest-reviewbutton--retracting',\n      'webapp-screens-pullrequest-reviewbutton--actions-story',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-reviewbutton--unreviewed': {\n    id: 'webapp-screens-pullrequest-reviewbutton--unreviewed',\n    title: 'Webapp screens/PullRequest/ReviewButton',\n    name: 'Unreviewed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-reviewbutton',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-reviewbutton--assigned': {\n    id: 'webapp-screens-pullrequest-reviewbutton--assigned',\n    title: 'Webapp screens/PullRequest/ReviewButton',\n    name: 'Assigned',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-reviewbutton',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-reviewbutton--approving': {\n    id: 'webapp-screens-pullrequest-reviewbutton--approving',\n    title: 'Webapp screens/PullRequest/ReviewButton',\n    name: 'Approving',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-reviewbutton',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-reviewbutton--approved': {\n    id: 'webapp-screens-pullrequest-reviewbutton--approved',\n    title: 'Webapp screens/PullRequest/ReviewButton',\n    name: 'Approved',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-reviewbutton',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-reviewbutton--retracting': {\n    id: 'webapp-screens-pullrequest-reviewbutton--retracting',\n    title: 'Webapp screens/PullRequest/ReviewButton',\n    name: 'Retracting',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-reviewbutton',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-reviewbutton--actions-story': {\n    id: 'webapp-screens-pullrequest-reviewbutton--actions-story',\n    title: 'Webapp screens/PullRequest/ReviewButton',\n    name: 'Actions',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-reviewbutton',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-selectreviewers': {\n    name: 'SelectReviewers',\n    id: 'webapp-screens-pullrequest-selectreviewers',\n    parent: 'webapp-screens-pullrequest',\n    depth: 2,\n    children: [\n      'webapp-screens-pullrequest-selectreviewers--select-reviewers',\n      'webapp-screens-pullrequest-selectreviewers--changing-reviewers',\n      'webapp-screens-pullrequest-selectreviewers--many-collaborators-long-name',\n      'webapp-screens-pullrequest-selectreviewers--no-collaborators-found',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequest-selectreviewers--select-reviewers': {\n    id: 'webapp-screens-pullrequest-selectreviewers--select-reviewers',\n    title: 'Webapp screens/PullRequest/SelectReviewers',\n    name: 'Select reviewers',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-selectreviewers',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-selectreviewers--changing-reviewers': {\n    id: 'webapp-screens-pullrequest-selectreviewers--changing-reviewers',\n    title: 'Webapp screens/PullRequest/SelectReviewers',\n    name: 'Changing reviewers',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-selectreviewers',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-selectreviewers--many-collaborators-long-name': {\n    id: 'webapp-screens-pullrequest-selectreviewers--many-collaborators-long-name',\n    title: 'Webapp screens/PullRequest/SelectReviewers',\n    name: 'Many collaborators, long name',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-selectreviewers',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequest-selectreviewers--no-collaborators-found': {\n    id: 'webapp-screens-pullrequest-selectreviewers--no-collaborators-found',\n    title: 'Webapp screens/PullRequest/SelectReviewers',\n    name: 'No collaborators found',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-pullrequest-selectreviewers',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequestsscreen': {\n    name: 'PullRequestsScreen',\n    id: 'webapp-screens-pullrequestsscreen',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: [\n      'webapp-screens-pullrequestsscreen--loading',\n      'webapp-screens-pullrequestsscreen--git-hub-p-rs',\n      'webapp-screens-pullrequestsscreen--git-lab-m-rs',\n      'webapp-screens-pullrequestsscreen--explainer',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-pullrequestsscreen--loading': {\n    id: 'webapp-screens-pullrequestsscreen--loading',\n    title: 'Webapp screens/PullRequestsScreen',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-pullrequestsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequestsscreen--git-hub-p-rs': {\n    id: 'webapp-screens-pullrequestsscreen--git-hub-p-rs',\n    title: 'Webapp screens/PullRequestsScreen',\n    name: 'GitHub PRs',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-pullrequestsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequestsscreen--git-lab-m-rs': {\n    id: 'webapp-screens-pullrequestsscreen--git-lab-m-rs',\n    title: 'Webapp screens/PullRequestsScreen',\n    name: 'GitLab MRs',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-pullrequestsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-pullrequestsscreen--explainer': {\n    id: 'webapp-screens-pullrequestsscreen--explainer',\n    title: 'Webapp screens/PullRequestsScreen',\n    name: 'Explainer',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-pullrequestsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-settingsscreen': {\n    name: 'SettingsScreen',\n    id: 'webapp-screens-settingsscreen',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: [\n      'webapp-screens-settingsscreen--loading',\n      'webapp-screens-settingsscreen--default',\n      'webapp-screens-settingsscreen--default-refreshing-membership',\n      'webapp-screens-settingsscreen--unlinked',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-settingsscreen--loading': {\n    id: 'webapp-screens-settingsscreen--loading',\n    title: 'Webapp screens/SettingsScreen',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-settingsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-settingsscreen--default': {\n    id: 'webapp-screens-settingsscreen--default',\n    title: 'Webapp screens/SettingsScreen',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-settingsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-settingsscreen--default-refreshing-membership': {\n    id: 'webapp-screens-settingsscreen--default-refreshing-membership',\n    title: 'Webapp screens/SettingsScreen',\n    name: 'default, refreshing membership',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-settingsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-settingsscreen--unlinked': {\n    id: 'webapp-screens-settingsscreen--unlinked',\n    title: 'Webapp screens/SettingsScreen',\n    name: 'unlinked',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 2,\n    parent: 'webapp-screens-settingsscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup': {\n    name: 'Setup',\n    id: 'webapp-screens-setup',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: [\n      'webapp-screens-setup-catchchanges',\n      'webapp-screens-setup-publishstorybook',\n      'webapp-screens-setup-verifychanges',\n      'webapp-screens-setup-wrapup',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-setup-catchchanges': {\n    name: 'CatchChanges',\n    id: 'webapp-screens-setup-catchchanges',\n    parent: 'webapp-screens-setup',\n    depth: 2,\n    children: [\n      'webapp-screens-setup-catchchanges-catchchangesscreen',\n      'webapp-screens-setup-catchchanges-changesspottedscreen',\n      'webapp-screens-setup-catchchanges-changessummary',\n      'webapp-screens-setup-catchchanges-instructions',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-setup-catchchanges-catchchangesscreen': {\n    name: 'CatchChangesScreen',\n    id: 'webapp-screens-setup-catchchanges-catchchangesscreen',\n    parent: 'webapp-screens-setup-catchchanges',\n    depth: 3,\n    children: [\n      'webapp-screens-setup-catchchanges-catchchangesscreen--loading',\n      'webapp-screens-setup-catchchanges-catchchangesscreen--default',\n      'webapp-screens-setup-catchchanges-catchchangesscreen--default-onboarding',\n      'webapp-screens-setup-catchchanges-catchchangesscreen--no-changes-warning',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-setup-catchchanges-catchchangesscreen--loading': {\n    id: 'webapp-screens-setup-catchchanges-catchchangesscreen--loading',\n    title: 'Webapp screens/Setup/CatchChanges/CatchChangesScreen',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-catchchanges-catchchangesscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-catchchanges-catchchangesscreen--default': {\n    id: 'webapp-screens-setup-catchchanges-catchchangesscreen--default',\n    title: 'Webapp screens/Setup/CatchChanges/CatchChangesScreen',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-catchchanges-catchchangesscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-catchchanges-catchchangesscreen--default-onboarding': {\n    id: 'webapp-screens-setup-catchchanges-catchchangesscreen--default-onboarding',\n    title: 'Webapp screens/Setup/CatchChanges/CatchChangesScreen',\n    name: 'Default Onboarding',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-catchchanges-catchchangesscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-catchchanges-catchchangesscreen--no-changes-warning': {\n    id: 'webapp-screens-setup-catchchanges-catchchangesscreen--no-changes-warning',\n    title: 'Webapp screens/Setup/CatchChanges/CatchChangesScreen',\n    name: 'No Changes Warning',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-catchchanges-catchchangesscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-catchchanges-changesspottedscreen': {\n    name: 'ChangesSpottedScreen',\n    id: 'webapp-screens-setup-catchchanges-changesspottedscreen',\n    parent: 'webapp-screens-setup-catchchanges',\n    depth: 3,\n    children: [\n      'webapp-screens-setup-catchchanges-changesspottedscreen--loading',\n      'webapp-screens-setup-catchchanges-changesspottedscreen--default',\n      'webapp-screens-setup-catchchanges-changesspottedscreen--default-onboarding',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-setup-catchchanges-changesspottedscreen--loading': {\n    id: 'webapp-screens-setup-catchchanges-changesspottedscreen--loading',\n    title: 'Webapp screens/Setup/CatchChanges/ChangesSpottedScreen',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-catchchanges-changesspottedscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-catchchanges-changesspottedscreen--default': {\n    id: 'webapp-screens-setup-catchchanges-changesspottedscreen--default',\n    title: 'Webapp screens/Setup/CatchChanges/ChangesSpottedScreen',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-catchchanges-changesspottedscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-catchchanges-changesspottedscreen--default-onboarding': {\n    id: 'webapp-screens-setup-catchchanges-changesspottedscreen--default-onboarding',\n    title: 'Webapp screens/Setup/CatchChanges/ChangesSpottedScreen',\n    name: 'Default Onboarding',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-catchchanges-changesspottedscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-catchchanges-changessummary': {\n    name: 'ChangesSummary',\n    id: 'webapp-screens-setup-catchchanges-changessummary',\n    parent: 'webapp-screens-setup-catchchanges',\n    depth: 3,\n    children: [\n      'webapp-screens-setup-catchchanges-changessummary--loading',\n      'webapp-screens-setup-catchchanges-changessummary--default',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-setup-catchchanges-changessummary--loading': {\n    id: 'webapp-screens-setup-catchchanges-changessummary--loading',\n    title: 'Webapp screens/Setup/CatchChanges/ChangesSummary',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-catchchanges-changessummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-catchchanges-changessummary--default': {\n    id: 'webapp-screens-setup-catchchanges-changessummary--default',\n    title: 'Webapp screens/Setup/CatchChanges/ChangesSummary',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-catchchanges-changessummary',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-catchchanges-instructions': {\n    name: 'Instructions',\n    id: 'webapp-screens-setup-catchchanges-instructions',\n    parent: 'webapp-screens-setup-catchchanges',\n    depth: 3,\n    children: [\n      'webapp-screens-setup-catchchanges-instructions--loading',\n      'webapp-screens-setup-catchchanges-instructions--default',\n      'webapp-screens-setup-catchchanges-instructions--no-changes-warning',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-setup-catchchanges-instructions--loading': {\n    id: 'webapp-screens-setup-catchchanges-instructions--loading',\n    title: 'Webapp screens/Setup/CatchChanges/Instructions',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-catchchanges-instructions',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-catchchanges-instructions--default': {\n    id: 'webapp-screens-setup-catchchanges-instructions--default',\n    title: 'Webapp screens/Setup/CatchChanges/Instructions',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-catchchanges-instructions',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-catchchanges-instructions--no-changes-warning': {\n    id: 'webapp-screens-setup-catchchanges-instructions--no-changes-warning',\n    title: 'Webapp screens/Setup/CatchChanges/Instructions',\n    name: 'No Changes Warning',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-catchchanges-instructions',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-publishstorybook': {\n    name: 'PublishStorybook',\n    id: 'webapp-screens-setup-publishstorybook',\n    parent: 'webapp-screens-setup',\n    depth: 2,\n    children: [\n      'webapp-screens-setup-publishstorybook-builderrorlist',\n      'webapp-screens-setup-publishstorybook-confirmationsuccess',\n      'webapp-screens-setup-publishstorybook-instructions',\n      'webapp-screens-setup-publishstorybook-publishfailedscreen',\n      'webapp-screens-setup-publishstorybook-publishstorybookscreen',\n      'webapp-screens-setup-publishstorybook-publishsuccessscreen',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-setup-publishstorybook-builderrorlist': {\n    name: 'BuildErrorList',\n    id: 'webapp-screens-setup-publishstorybook-builderrorlist',\n    parent: 'webapp-screens-setup-publishstorybook',\n    depth: 3,\n    children: [\n      'webapp-screens-setup-publishstorybook-builderrorlist--loading',\n      'webapp-screens-setup-publishstorybook-builderrorlist--default',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-setup-publishstorybook-builderrorlist--loading': {\n    id: 'webapp-screens-setup-publishstorybook-builderrorlist--loading',\n    title: 'Webapp screens/Setup/PublishStorybook/BuildErrorList',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-publishstorybook-builderrorlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-publishstorybook-builderrorlist--default': {\n    id: 'webapp-screens-setup-publishstorybook-builderrorlist--default',\n    title: 'Webapp screens/Setup/PublishStorybook/BuildErrorList',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-publishstorybook-builderrorlist',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-publishstorybook-confirmationsuccess': {\n    name: 'ConfirmationSuccess',\n    id: 'webapp-screens-setup-publishstorybook-confirmationsuccess',\n    parent: 'webapp-screens-setup-publishstorybook',\n    depth: 3,\n    children: [\n      'webapp-screens-setup-publishstorybook-confirmationsuccess--loading',\n      'webapp-screens-setup-publishstorybook-confirmationsuccess--default',\n      'webapp-screens-setup-publishstorybook-confirmationsuccess--scroll',\n      'webapp-screens-setup-publishstorybook-confirmationsuccess--small',\n      'webapp-screens-setup-publishstorybook-confirmationsuccess--small-scroll',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-setup-publishstorybook-confirmationsuccess--loading': {\n    id: 'webapp-screens-setup-publishstorybook-confirmationsuccess--loading',\n    title: 'Webapp screens/Setup/PublishStorybook/ConfirmationSuccess',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-publishstorybook-confirmationsuccess',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-publishstorybook-confirmationsuccess--default': {\n    id: 'webapp-screens-setup-publishstorybook-confirmationsuccess--default',\n    title: 'Webapp screens/Setup/PublishStorybook/ConfirmationSuccess',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-publishstorybook-confirmationsuccess',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-publishstorybook-confirmationsuccess--scroll': {\n    id: 'webapp-screens-setup-publishstorybook-confirmationsuccess--scroll',\n    title: 'Webapp screens/Setup/PublishStorybook/ConfirmationSuccess',\n    name: 'Scroll',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-publishstorybook-confirmationsuccess',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-publishstorybook-confirmationsuccess--small': {\n    id: 'webapp-screens-setup-publishstorybook-confirmationsuccess--small',\n    title: 'Webapp screens/Setup/PublishStorybook/ConfirmationSuccess',\n    name: 'Small',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-publishstorybook-confirmationsuccess',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-publishstorybook-confirmationsuccess--small-scroll': {\n    id: 'webapp-screens-setup-publishstorybook-confirmationsuccess--small-scroll',\n    title: 'Webapp screens/Setup/PublishStorybook/ConfirmationSuccess',\n    name: 'Small Scroll',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-publishstorybook-confirmationsuccess',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-publishstorybook-instructions': {\n    name: 'Instructions',\n    id: 'webapp-screens-setup-publishstorybook-instructions',\n    parent: 'webapp-screens-setup-publishstorybook',\n    depth: 3,\n    children: [\n      'webapp-screens-setup-publishstorybook-instructions--loading',\n      'webapp-screens-setup-publishstorybook-instructions--default',\n      'webapp-screens-setup-publishstorybook-instructions--retry',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-setup-publishstorybook-instructions--loading': {\n    id: 'webapp-screens-setup-publishstorybook-instructions--loading',\n    title: 'Webapp screens/Setup/PublishStorybook/Instructions',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-publishstorybook-instructions',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-publishstorybook-instructions--default': {\n    id: 'webapp-screens-setup-publishstorybook-instructions--default',\n    title: 'Webapp screens/Setup/PublishStorybook/Instructions',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-publishstorybook-instructions',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-publishstorybook-instructions--retry': {\n    id: 'webapp-screens-setup-publishstorybook-instructions--retry',\n    title: 'Webapp screens/Setup/PublishStorybook/Instructions',\n    name: 'Retry',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-publishstorybook-instructions',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-publishstorybook-publishfailedscreen': {\n    name: 'PublishFailedScreen',\n    id: 'webapp-screens-setup-publishstorybook-publishfailedscreen',\n    parent: 'webapp-screens-setup-publishstorybook',\n    depth: 3,\n    children: [\n      'webapp-screens-setup-publishstorybook-publishfailedscreen--loading',\n      'webapp-screens-setup-publishstorybook-publishfailedscreen--default',\n      'webapp-screens-setup-publishstorybook-publishfailedscreen--default-onboarding',\n      'webapp-screens-setup-publishstorybook-publishfailedscreen--infrastructure-error',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-setup-publishstorybook-publishfailedscreen--loading': {\n    id: 'webapp-screens-setup-publishstorybook-publishfailedscreen--loading',\n    title: 'Webapp screens/Setup/PublishStorybook/PublishFailedScreen',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-publishstorybook-publishfailedscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-publishstorybook-publishfailedscreen--default': {\n    id: 'webapp-screens-setup-publishstorybook-publishfailedscreen--default',\n    title: 'Webapp screens/Setup/PublishStorybook/PublishFailedScreen',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-publishstorybook-publishfailedscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-publishstorybook-publishfailedscreen--default-onboarding': {\n    id: 'webapp-screens-setup-publishstorybook-publishfailedscreen--default-onboarding',\n    title: 'Webapp screens/Setup/PublishStorybook/PublishFailedScreen',\n    name: 'Default Onboarding',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-publishstorybook-publishfailedscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-publishstorybook-publishfailedscreen--infrastructure-error': {\n    id: 'webapp-screens-setup-publishstorybook-publishfailedscreen--infrastructure-error',\n    title: 'Webapp screens/Setup/PublishStorybook/PublishFailedScreen',\n    name: 'Infrastructure Error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-publishstorybook-publishfailedscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-publishstorybook-publishstorybookscreen': {\n    name: 'PublishStorybookScreen',\n    id: 'webapp-screens-setup-publishstorybook-publishstorybookscreen',\n    parent: 'webapp-screens-setup-publishstorybook',\n    depth: 3,\n    children: [\n      'webapp-screens-setup-publishstorybook-publishstorybookscreen--loading',\n      'webapp-screens-setup-publishstorybook-publishstorybookscreen--default',\n      'webapp-screens-setup-publishstorybook-publishstorybookscreen--default-onboarding',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-setup-publishstorybook-publishstorybookscreen--loading': {\n    id: 'webapp-screens-setup-publishstorybook-publishstorybookscreen--loading',\n    title: 'Webapp screens/Setup/PublishStorybook/PublishStorybookScreen',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-publishstorybook-publishstorybookscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-publishstorybook-publishstorybookscreen--default': {\n    id: 'webapp-screens-setup-publishstorybook-publishstorybookscreen--default',\n    title: 'Webapp screens/Setup/PublishStorybook/PublishStorybookScreen',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-publishstorybook-publishstorybookscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-publishstorybook-publishstorybookscreen--default-onboarding': {\n    id: 'webapp-screens-setup-publishstorybook-publishstorybookscreen--default-onboarding',\n    title: 'Webapp screens/Setup/PublishStorybook/PublishStorybookScreen',\n    name: 'Default Onboarding',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-publishstorybook-publishstorybookscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-publishstorybook-publishsuccessscreen': {\n    name: 'PublishSuccessScreen',\n    id: 'webapp-screens-setup-publishstorybook-publishsuccessscreen',\n    parent: 'webapp-screens-setup-publishstorybook',\n    depth: 3,\n    children: [\n      'webapp-screens-setup-publishstorybook-publishsuccessscreen--loading',\n      'webapp-screens-setup-publishstorybook-publishsuccessscreen--default',\n      'webapp-screens-setup-publishstorybook-publishsuccessscreen--default-onboarding',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-setup-publishstorybook-publishsuccessscreen--loading': {\n    id: 'webapp-screens-setup-publishstorybook-publishsuccessscreen--loading',\n    title: 'Webapp screens/Setup/PublishStorybook/PublishSuccessScreen',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-publishstorybook-publishsuccessscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-publishstorybook-publishsuccessscreen--default': {\n    id: 'webapp-screens-setup-publishstorybook-publishsuccessscreen--default',\n    title: 'Webapp screens/Setup/PublishStorybook/PublishSuccessScreen',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-publishstorybook-publishsuccessscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-publishstorybook-publishsuccessscreen--default-onboarding': {\n    id: 'webapp-screens-setup-publishstorybook-publishsuccessscreen--default-onboarding',\n    title: 'Webapp screens/Setup/PublishStorybook/PublishSuccessScreen',\n    name: 'Default Onboarding',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-publishstorybook-publishsuccessscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-verifychanges': {\n    name: 'VerifyChanges',\n    id: 'webapp-screens-setup-verifychanges',\n    parent: 'webapp-screens-setup',\n    depth: 2,\n    children: [\n      'webapp-screens-setup-verifychanges-comparison',\n      'webapp-screens-setup-verifychanges-comparisoncomments',\n      'webapp-screens-setup-verifychanges-feedbackscreen',\n      'webapp-screens-setup-verifychanges-verifychangesscreen',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-setup-verifychanges-comparison': {\n    name: 'Comparison',\n    id: 'webapp-screens-setup-verifychanges-comparison',\n    parent: 'webapp-screens-setup-verifychanges',\n    depth: 3,\n    children: [\n      'webapp-screens-setup-verifychanges-comparison--loading',\n      'webapp-screens-setup-verifychanges-comparison--default',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-setup-verifychanges-comparison--loading': {\n    id: 'webapp-screens-setup-verifychanges-comparison--loading',\n    title: 'Webapp screens/Setup/VerifyChanges/Comparison',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-verifychanges-comparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-verifychanges-comparison--default': {\n    id: 'webapp-screens-setup-verifychanges-comparison--default',\n    title: 'Webapp screens/Setup/VerifyChanges/Comparison',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-verifychanges-comparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-verifychanges-comparisoncomments': {\n    name: 'ComparisonComments',\n    id: 'webapp-screens-setup-verifychanges-comparisoncomments',\n    parent: 'webapp-screens-setup-verifychanges',\n    depth: 3,\n    children: [\n      'webapp-screens-setup-verifychanges-comparisoncomments--loading',\n      'webapp-screens-setup-verifychanges-comparisoncomments--default',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-setup-verifychanges-comparisoncomments--loading': {\n    id: 'webapp-screens-setup-verifychanges-comparisoncomments--loading',\n    title: 'Webapp screens/Setup/VerifyChanges/ComparisonComments',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-verifychanges-comparisoncomments',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-verifychanges-comparisoncomments--default': {\n    id: 'webapp-screens-setup-verifychanges-comparisoncomments--default',\n    title: 'Webapp screens/Setup/VerifyChanges/ComparisonComments',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-verifychanges-comparisoncomments',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-verifychanges-feedbackscreen': {\n    name: 'FeedbackScreen',\n    id: 'webapp-screens-setup-verifychanges-feedbackscreen',\n    parent: 'webapp-screens-setup-verifychanges',\n    depth: 3,\n    children: [\n      'webapp-screens-setup-verifychanges-feedbackscreen--loading',\n      'webapp-screens-setup-verifychanges-feedbackscreen--default',\n      'webapp-screens-setup-verifychanges-feedbackscreen--default-onboarding',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-setup-verifychanges-feedbackscreen--loading': {\n    id: 'webapp-screens-setup-verifychanges-feedbackscreen--loading',\n    title: 'Webapp screens/Setup/VerifyChanges/FeedbackScreen',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-verifychanges-feedbackscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-verifychanges-feedbackscreen--default': {\n    id: 'webapp-screens-setup-verifychanges-feedbackscreen--default',\n    title: 'Webapp screens/Setup/VerifyChanges/FeedbackScreen',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-verifychanges-feedbackscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-verifychanges-feedbackscreen--default-onboarding': {\n    id: 'webapp-screens-setup-verifychanges-feedbackscreen--default-onboarding',\n    title: 'Webapp screens/Setup/VerifyChanges/FeedbackScreen',\n    name: 'Default Onboarding',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-verifychanges-feedbackscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-verifychanges-verifychangesscreen': {\n    name: 'VerifyChangesScreen',\n    id: 'webapp-screens-setup-verifychanges-verifychangesscreen',\n    parent: 'webapp-screens-setup-verifychanges',\n    depth: 3,\n    children: [\n      'webapp-screens-setup-verifychanges-verifychangesscreen--loading',\n      'webapp-screens-setup-verifychanges-verifychangesscreen--default',\n      'webapp-screens-setup-verifychanges-verifychangesscreen--default-onboarding',\n      'webapp-screens-setup-verifychanges-verifychangesscreen--mutating',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-setup-verifychanges-verifychangesscreen--loading': {\n    id: 'webapp-screens-setup-verifychanges-verifychangesscreen--loading',\n    title: 'Webapp screens/Setup/VerifyChanges/VerifyChangesScreen',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-verifychanges-verifychangesscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-verifychanges-verifychangesscreen--default': {\n    id: 'webapp-screens-setup-verifychanges-verifychangesscreen--default',\n    title: 'Webapp screens/Setup/VerifyChanges/VerifyChangesScreen',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-verifychanges-verifychangesscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-verifychanges-verifychangesscreen--default-onboarding': {\n    id: 'webapp-screens-setup-verifychanges-verifychangesscreen--default-onboarding',\n    title: 'Webapp screens/Setup/VerifyChanges/VerifyChangesScreen',\n    name: 'Default Onboarding',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-verifychanges-verifychangesscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-verifychanges-verifychangesscreen--mutating': {\n    id: 'webapp-screens-setup-verifychanges-verifychangesscreen--mutating',\n    title: 'Webapp screens/Setup/VerifyChanges/VerifyChangesScreen',\n    name: 'Mutating',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-verifychanges-verifychangesscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-wrapup': {\n    name: 'WrapUp',\n    id: 'webapp-screens-setup-wrapup',\n    parent: 'webapp-screens-setup',\n    depth: 2,\n    children: [\n      'webapp-screens-setup-wrapup-mergechecksscreen',\n      'webapp-screens-setup-wrapup-setupcompletescreen',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-setup-wrapup-mergechecksscreen': {\n    name: 'MergeChecksScreen',\n    id: 'webapp-screens-setup-wrapup-mergechecksscreen',\n    parent: 'webapp-screens-setup-wrapup',\n    depth: 3,\n    children: [\n      'webapp-screens-setup-wrapup-mergechecksscreen--loading',\n      'webapp-screens-setup-wrapup-mergechecksscreen--default',\n      'webapp-screens-setup-wrapup-mergechecksscreen--default-onboarding',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-setup-wrapup-mergechecksscreen--loading': {\n    id: 'webapp-screens-setup-wrapup-mergechecksscreen--loading',\n    title: 'Webapp screens/Setup/WrapUp/MergeChecksScreen',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-wrapup-mergechecksscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-wrapup-mergechecksscreen--default': {\n    id: 'webapp-screens-setup-wrapup-mergechecksscreen--default',\n    title: 'Webapp screens/Setup/WrapUp/MergeChecksScreen',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-wrapup-mergechecksscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-wrapup-mergechecksscreen--default-onboarding': {\n    id: 'webapp-screens-setup-wrapup-mergechecksscreen--default-onboarding',\n    title: 'Webapp screens/Setup/WrapUp/MergeChecksScreen',\n    name: 'Default Onboarding',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-wrapup-mergechecksscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-wrapup-setupcompletescreen': {\n    name: 'SetupCompleteScreen',\n    id: 'webapp-screens-setup-wrapup-setupcompletescreen',\n    parent: 'webapp-screens-setup-wrapup',\n    depth: 3,\n    children: [\n      'webapp-screens-setup-wrapup-setupcompletescreen--loading',\n      'webapp-screens-setup-wrapup-setupcompletescreen--default',\n      'webapp-screens-setup-wrapup-setupcompletescreen--default-onboarding',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-setup-wrapup-setupcompletescreen--loading': {\n    id: 'webapp-screens-setup-wrapup-setupcompletescreen--loading',\n    title: 'Webapp screens/Setup/WrapUp/SetupCompleteScreen',\n    name: 'Loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-wrapup-setupcompletescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-wrapup-setupcompletescreen--default': {\n    id: 'webapp-screens-setup-wrapup-setupcompletescreen--default',\n    title: 'Webapp screens/Setup/WrapUp/SetupCompleteScreen',\n    name: 'Default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-wrapup-setupcompletescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-setup-wrapup-setupcompletescreen--default-onboarding': {\n    id: 'webapp-screens-setup-wrapup-setupcompletescreen--default-onboarding',\n    title: 'Webapp screens/Setup/WrapUp/SetupCompleteScreen',\n    name: 'Default Onboarding',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 4,\n    parent: 'webapp-screens-setup-wrapup-setupcompletescreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot': {\n    name: 'Snapshot',\n    id: 'webapp-screens-snapshot',\n    parent: 'webapp-screens',\n    depth: 1,\n    children: [\n      'webapp-screens-snapshot-capturewarningtooltip',\n      'webapp-screens-snapshot-reviewbuttons',\n      'webapp-screens-snapshot-snapshotcomparison',\n      'webapp-screens-snapshot-snapshotheader',\n      'webapp-screens-snapshot-snapshothtmldiff',\n      'webapp-screens-snapshot-snapshotscreen',\n    ],\n    type: 'group',\n  },\n  'webapp-screens-snapshot-capturewarningtooltip': {\n    name: 'CaptureWarningTooltip',\n    id: 'webapp-screens-snapshot-capturewarningtooltip',\n    parent: 'webapp-screens-snapshot',\n    depth: 2,\n    children: ['webapp-screens-snapshot-capturewarningtooltip--default-story'],\n    type: 'component',\n  },\n  'webapp-screens-snapshot-capturewarningtooltip--default-story': {\n    id: 'webapp-screens-snapshot-capturewarningtooltip--default-story',\n    title: 'Webapp screens/Snapshot/CaptureWarningTooltip',\n    name: 'open',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-capturewarningtooltip',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-reviewbuttons': {\n    name: 'ReviewButtons',\n    id: 'webapp-screens-snapshot-reviewbuttons',\n    parent: 'webapp-screens-snapshot',\n    depth: 2,\n    children: [\n      'webapp-screens-snapshot-reviewbuttons--in-progress',\n      'webapp-screens-snapshot-reviewbuttons--failed',\n      'webapp-screens-snapshot-reviewbuttons--unreviewed',\n      'webapp-screens-snapshot-reviewbuttons--unreviewed-accepting',\n      'webapp-screens-snapshot-reviewbuttons--unreviewed-denying',\n      'webapp-screens-snapshot-reviewbuttons--accepted',\n      'webapp-screens-snapshot-reviewbuttons--accepted-undoing',\n      'webapp-screens-snapshot-reviewbuttons--auto-accepted-first-build',\n      'webapp-screens-snapshot-reviewbuttons--denied',\n      'webapp-screens-snapshot-reviewbuttons--denied-undoing',\n      'webapp-screens-snapshot-reviewbuttons--unreviewable-no-descendant',\n      'webapp-screens-snapshot-reviewbuttons--unreviewable-with-descendant',\n      'webapp-screens-snapshot-reviewbuttons--read-only-logged-in',\n      'webapp-screens-snapshot-reviewbuttons--read-only-not-logged-in',\n      'webapp-screens-snapshot-reviewbuttons--error',\n      'webapp-screens-snapshot-reviewbuttons--error-last',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-snapshot-reviewbuttons--in-progress': {\n    id: 'webapp-screens-snapshot-reviewbuttons--in-progress',\n    title: 'Webapp screens/Snapshot/ReviewButtons',\n    name: 'in progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-reviewbuttons',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-reviewbuttons--failed': {\n    id: 'webapp-screens-snapshot-reviewbuttons--failed',\n    title: 'Webapp screens/Snapshot/ReviewButtons',\n    name: 'failed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-reviewbuttons',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-reviewbuttons--unreviewed': {\n    id: 'webapp-screens-snapshot-reviewbuttons--unreviewed',\n    title: 'Webapp screens/Snapshot/ReviewButtons',\n    name: 'unreviewed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-reviewbuttons',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-reviewbuttons--unreviewed-accepting': {\n    id: 'webapp-screens-snapshot-reviewbuttons--unreviewed-accepting',\n    title: 'Webapp screens/Snapshot/ReviewButtons',\n    name: 'unreviewed, accepting',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-reviewbuttons',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-reviewbuttons--unreviewed-denying': {\n    id: 'webapp-screens-snapshot-reviewbuttons--unreviewed-denying',\n    title: 'Webapp screens/Snapshot/ReviewButtons',\n    name: 'unreviewed, denying',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-reviewbuttons',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-reviewbuttons--accepted': {\n    id: 'webapp-screens-snapshot-reviewbuttons--accepted',\n    title: 'Webapp screens/Snapshot/ReviewButtons',\n    name: 'accepted',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-reviewbuttons',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-reviewbuttons--accepted-undoing': {\n    id: 'webapp-screens-snapshot-reviewbuttons--accepted-undoing',\n    title: 'Webapp screens/Snapshot/ReviewButtons',\n    name: 'accepted, undoing',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-reviewbuttons',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-reviewbuttons--auto-accepted-first-build': {\n    id: 'webapp-screens-snapshot-reviewbuttons--auto-accepted-first-build',\n    title: 'Webapp screens/Snapshot/ReviewButtons',\n    name: 'auto-accepted, first build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-reviewbuttons',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-reviewbuttons--denied': {\n    id: 'webapp-screens-snapshot-reviewbuttons--denied',\n    title: 'Webapp screens/Snapshot/ReviewButtons',\n    name: 'denied',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-reviewbuttons',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-reviewbuttons--denied-undoing': {\n    id: 'webapp-screens-snapshot-reviewbuttons--denied-undoing',\n    title: 'Webapp screens/Snapshot/ReviewButtons',\n    name: 'denied, undoing',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-reviewbuttons',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-reviewbuttons--unreviewable-no-descendant': {\n    id: 'webapp-screens-snapshot-reviewbuttons--unreviewable-no-descendant',\n    title: 'Webapp screens/Snapshot/ReviewButtons',\n    name: 'unreviewable, no descendant',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-reviewbuttons',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-reviewbuttons--unreviewable-with-descendant': {\n    id: 'webapp-screens-snapshot-reviewbuttons--unreviewable-with-descendant',\n    title: 'Webapp screens/Snapshot/ReviewButtons',\n    name: 'unreviewable, with descendant',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-reviewbuttons',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-reviewbuttons--read-only-logged-in': {\n    id: 'webapp-screens-snapshot-reviewbuttons--read-only-logged-in',\n    title: 'Webapp screens/Snapshot/ReviewButtons',\n    name: 'read only, logged in',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-reviewbuttons',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-reviewbuttons--read-only-not-logged-in': {\n    id: 'webapp-screens-snapshot-reviewbuttons--read-only-not-logged-in',\n    title: 'Webapp screens/Snapshot/ReviewButtons',\n    name: 'read only, not logged in',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-reviewbuttons',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-reviewbuttons--error': {\n    id: 'webapp-screens-snapshot-reviewbuttons--error',\n    title: 'Webapp screens/Snapshot/ReviewButtons',\n    name: 'error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-reviewbuttons',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-reviewbuttons--error-last': {\n    id: 'webapp-screens-snapshot-reviewbuttons--error-last',\n    title: 'Webapp screens/Snapshot/ReviewButtons',\n    name: 'error, last',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-reviewbuttons',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison': {\n    name: 'SnapshotComparison',\n    id: 'webapp-screens-snapshot-snapshotcomparison',\n    parent: 'webapp-screens-snapshot',\n    depth: 2,\n    children: [\n      'webapp-screens-snapshot-snapshotcomparison--loading',\n      'webapp-screens-snapshot-snapshotcomparison--2-up',\n      'webapp-screens-snapshot-snapshotcomparison--2-up-pure-diff-visible',\n      'webapp-screens-snapshot-snapshotcomparison--2-up-pure-diff-visible-diff-strobe',\n      'webapp-screens-snapshot-snapshotcomparison--2-up-pure-diff-visible-diff-focus',\n      'webapp-screens-snapshot-snapshotcomparison--2-up-pure-diff-visible-diff-focus-and-strobe',\n      'webapp-screens-snapshot-snapshotcomparison--2-up-pure-diff-invisible',\n      'webapp-screens-snapshot-snapshotcomparison--2-up-pure-diff-invisible-diff-focus-diff-strobe',\n      'webapp-screens-snapshot-snapshotcomparison--2-up-diff-version-1',\n      'webapp-screens-snapshot-snapshotcomparison--2-up-ignoring',\n      'webapp-screens-snapshot-snapshotcomparison--2-up-diff-bigger',\n      'webapp-screens-snapshot-snapshotcomparison--1-up',\n      'webapp-screens-snapshot-snapshotcomparison--1-up-header-offset',\n      'webapp-screens-snapshot-snapshotcomparison--1-up-pure-diff-visible',\n      'webapp-screens-snapshot-snapshotcomparison--1-up-pure-diff-visible-diff-strobe',\n      'webapp-screens-snapshot-snapshotcomparison--1-up-pure-diff-visible-diff-focus',\n      'webapp-screens-snapshot-snapshotcomparison--1-up-pure-diff-visible-diff-focus-and-strobe',\n      'webapp-screens-snapshot-snapshotcomparison--1-up-pure-diff-invisible',\n      'webapp-screens-snapshot-snapshotcomparison--1-up-pure-switching-diff-visible',\n      'webapp-screens-snapshot-snapshotcomparison--1-up-pure-switching-diff-visible-diff-strobe',\n      'webapp-screens-snapshot-snapshotcomparison--1-up-pure-switching-diff-visible-diff-focus',\n      'webapp-screens-snapshot-snapshotcomparison--1-up-pure-switching-diff-visible-diff-focus-and-strobe',\n      'webapp-screens-snapshot-snapshotcomparison--1-up-pure-switching-diff-invisible',\n      'webapp-screens-snapshot-snapshotcomparison--1-up-diff-version-1',\n      'webapp-screens-snapshot-snapshotcomparison--1-up-diff-bigger',\n      'webapp-screens-snapshot-snapshotcomparison--1-up-ignoring',\n      'webapp-screens-snapshot-snapshotcomparison--no-baseline',\n      'webapp-screens-snapshot-snapshotcomparison--no-baseline-in-progress',\n      'webapp-screens-snapshot-snapshotcomparison--no-baseline-ignoring',\n      'webapp-screens-snapshot-snapshotcomparison--failed',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-snapshot-snapshotcomparison--loading': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--loading',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--2-up': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--2-up',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '2 up',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--2-up-pure-diff-visible': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--2-up-pure-diff-visible',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '2 up, pure, diff visible',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--2-up-pure-diff-visible-diff-strobe': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--2-up-pure-diff-visible-diff-strobe',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '2 up, pure, diff visible, diff strobe',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--2-up-pure-diff-visible-diff-focus': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--2-up-pure-diff-visible-diff-focus',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '2 up, pure, diff visible, diff focus',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--2-up-pure-diff-visible-diff-focus-and-strobe': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--2-up-pure-diff-visible-diff-focus-and-strobe',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '2 up, pure, diff visible, diff focus and strobe',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--2-up-pure-diff-invisible': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--2-up-pure-diff-invisible',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '2 up, pure, diff invisible',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--2-up-pure-diff-invisible-diff-focus-diff-strobe': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--2-up-pure-diff-invisible-diff-focus-diff-strobe',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '2 up, pure, diff invisible, diffFocus + diffStrobe',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--2-up-diff-version-1': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--2-up-diff-version-1',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '2 up, diff version 1',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--2-up-ignoring': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--2-up-ignoring',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '2 up ignoring',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--2-up-diff-bigger': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--2-up-diff-bigger',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '2 up, diff bigger',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--1-up': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--1-up',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '1 up',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--1-up-header-offset': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--1-up-header-offset',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '1 up, header offset',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--1-up-pure-diff-visible': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--1-up-pure-diff-visible',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '1 up, pure, diff visible',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--1-up-pure-diff-visible-diff-strobe': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--1-up-pure-diff-visible-diff-strobe',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '1 up, pure, diff visible, diff strobe',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--1-up-pure-diff-visible-diff-focus': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--1-up-pure-diff-visible-diff-focus',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '1 up, pure, diff visible, diff focus',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--1-up-pure-diff-visible-diff-focus-and-strobe': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--1-up-pure-diff-visible-diff-focus-and-strobe',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '1 up, pure, diff visible, diff focus and strobe',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--1-up-pure-diff-invisible': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--1-up-pure-diff-invisible',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '1 up, pure, diff invisible',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--1-up-pure-switching-diff-visible': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--1-up-pure-switching-diff-visible',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '1 up, pure, switching, diff visible',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--1-up-pure-switching-diff-visible-diff-strobe': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--1-up-pure-switching-diff-visible-diff-strobe',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '1 up, pure, switching, diff visible, diff strobe',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--1-up-pure-switching-diff-visible-diff-focus': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--1-up-pure-switching-diff-visible-diff-focus',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '1 up, pure, switching, diff visible, diff focus',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--1-up-pure-switching-diff-visible-diff-focus-and-strobe':\n    {\n      id: 'webapp-screens-snapshot-snapshotcomparison--1-up-pure-switching-diff-visible-diff-focus-and-strobe',\n      title: 'Webapp screens/Snapshot/SnapshotComparison',\n      name: '1 up, pure, switching, diff visible, diff focus and strobe',\n      importPath: './path.js',\n      args: {},\n      argTypes: {},\n      initialArgs: {},\n      depth: 3,\n      parent: 'webapp-screens-snapshot-snapshotcomparison',\n      type: 'story',\n      subtype: 'story',\n      prepared: true,\n    },\n  'webapp-screens-snapshot-snapshotcomparison--1-up-pure-switching-diff-invisible': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--1-up-pure-switching-diff-invisible',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '1 up, pure, switching, diff invisible',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--1-up-diff-version-1': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--1-up-diff-version-1',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '1 up, diff version 1',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--1-up-diff-bigger': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--1-up-diff-bigger',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '1 up, diff bigger',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--1-up-ignoring': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--1-up-ignoring',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: '1 up ignoring',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--no-baseline': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--no-baseline',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: 'no baseline',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--no-baseline-in-progress': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--no-baseline-in-progress',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: 'no baseline in progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--no-baseline-ignoring': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--no-baseline-ignoring',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: 'no baseline ignoring',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotcomparison--failed': {\n    id: 'webapp-screens-snapshot-snapshotcomparison--failed',\n    title: 'Webapp screens/Snapshot/SnapshotComparison',\n    name: 'failed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotcomparison',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotheader': {\n    name: 'SnapshotHeader',\n    id: 'webapp-screens-snapshot-snapshotheader',\n    parent: 'webapp-screens-snapshot',\n    depth: 2,\n    children: [\n      'webapp-screens-snapshot-snapshotheader--loading',\n      'webapp-screens-snapshot-snapshotheader--pending',\n      'webapp-screens-snapshot-snapshotheader--pending-viewport-default',\n      'webapp-screens-snapshot-snapshotheader--pending-first',\n      'webapp-screens-snapshot-snapshotheader--pending-last',\n      'webapp-screens-snapshot-snapshotheader--pending-no-baseline',\n      'webapp-screens-snapshot-snapshotheader--pending-has-ignored-selectors',\n      'webapp-screens-snapshot-snapshotheader--pending-has-ignored-selectors-showing',\n      'webapp-screens-snapshot-snapshotheader--accepted',\n      'webapp-screens-snapshot-snapshotheader--auto-accepted-first-build',\n      'webapp-screens-snapshot-snapshotheader--denied',\n      'webapp-screens-snapshot-snapshotheader--unreviewable-with-descendant',\n      'webapp-screens-snapshot-snapshotheader--read-only-logged-in',\n      'webapp-screens-snapshot-snapshotheader--read-only-not-logged-in',\n      'webapp-screens-snapshot-snapshotheader--in-progress',\n      'webapp-screens-snapshot-snapshotheader--failed',\n      'webapp-screens-snapshot-snapshotheader--error',\n      'webapp-screens-snapshot-snapshotheader--error-last',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-snapshot-snapshotheader--loading': {\n    id: 'webapp-screens-snapshot-snapshotheader--loading',\n    title: 'Webapp screens/Snapshot/SnapshotHeader',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotheader--pending': {\n    id: 'webapp-screens-snapshot-snapshotheader--pending',\n    title: 'Webapp screens/Snapshot/SnapshotHeader',\n    name: 'pending',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotheader--pending-viewport-default': {\n    id: 'webapp-screens-snapshot-snapshotheader--pending-viewport-default',\n    title: 'Webapp screens/Snapshot/SnapshotHeader',\n    name: 'pending, viewport default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotheader--pending-first': {\n    id: 'webapp-screens-snapshot-snapshotheader--pending-first',\n    title: 'Webapp screens/Snapshot/SnapshotHeader',\n    name: 'pending, first',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotheader--pending-last': {\n    id: 'webapp-screens-snapshot-snapshotheader--pending-last',\n    title: 'Webapp screens/Snapshot/SnapshotHeader',\n    name: 'pending, last',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotheader--pending-no-baseline': {\n    id: 'webapp-screens-snapshot-snapshotheader--pending-no-baseline',\n    title: 'Webapp screens/Snapshot/SnapshotHeader',\n    name: 'pending, no baseline',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotheader--pending-has-ignored-selectors': {\n    id: 'webapp-screens-snapshot-snapshotheader--pending-has-ignored-selectors',\n    title: 'Webapp screens/Snapshot/SnapshotHeader',\n    name: 'pending, has ignored selectors',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotheader--pending-has-ignored-selectors-showing': {\n    id: 'webapp-screens-snapshot-snapshotheader--pending-has-ignored-selectors-showing',\n    title: 'Webapp screens/Snapshot/SnapshotHeader',\n    name: 'pending, has ignored selectors, showing',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotheader--accepted': {\n    id: 'webapp-screens-snapshot-snapshotheader--accepted',\n    title: 'Webapp screens/Snapshot/SnapshotHeader',\n    name: 'accepted',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotheader--auto-accepted-first-build': {\n    id: 'webapp-screens-snapshot-snapshotheader--auto-accepted-first-build',\n    title: 'Webapp screens/Snapshot/SnapshotHeader',\n    name: 'auto-accepted, first build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotheader--denied': {\n    id: 'webapp-screens-snapshot-snapshotheader--denied',\n    title: 'Webapp screens/Snapshot/SnapshotHeader',\n    name: 'denied',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotheader--unreviewable-with-descendant': {\n    id: 'webapp-screens-snapshot-snapshotheader--unreviewable-with-descendant',\n    title: 'Webapp screens/Snapshot/SnapshotHeader',\n    name: 'unreviewable, with descendant',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotheader--read-only-logged-in': {\n    id: 'webapp-screens-snapshot-snapshotheader--read-only-logged-in',\n    title: 'Webapp screens/Snapshot/SnapshotHeader',\n    name: 'read only, logged in',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotheader--read-only-not-logged-in': {\n    id: 'webapp-screens-snapshot-snapshotheader--read-only-not-logged-in',\n    title: 'Webapp screens/Snapshot/SnapshotHeader',\n    name: 'read only, not logged in',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotheader--in-progress': {\n    id: 'webapp-screens-snapshot-snapshotheader--in-progress',\n    title: 'Webapp screens/Snapshot/SnapshotHeader',\n    name: 'in progress',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotheader--failed': {\n    id: 'webapp-screens-snapshot-snapshotheader--failed',\n    title: 'Webapp screens/Snapshot/SnapshotHeader',\n    name: 'failed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotheader--error': {\n    id: 'webapp-screens-snapshot-snapshotheader--error',\n    title: 'Webapp screens/Snapshot/SnapshotHeader',\n    name: 'error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotheader--error-last': {\n    id: 'webapp-screens-snapshot-snapshotheader--error-last',\n    title: 'Webapp screens/Snapshot/SnapshotHeader',\n    name: 'error, last',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotheader',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshothtmldiff': {\n    name: 'SnapshotHtmlDiff',\n    id: 'webapp-screens-snapshot-snapshothtmldiff',\n    parent: 'webapp-screens-snapshot',\n    depth: 2,\n    children: [\n      'webapp-screens-snapshot-snapshothtmldiff--loading',\n      'webapp-screens-snapshot-snapshothtmldiff--loading-baseline',\n      'webapp-screens-snapshot-snapshothtmldiff--default',\n      'webapp-screens-snapshot-snapshothtmldiff--long-lines',\n      'webapp-screens-snapshot-snapshothtmldiff--too-large-issue-1885',\n      'webapp-screens-snapshot-snapshothtmldiff--large-after-pretty-print-issue-1885-b',\n      'webapp-screens-snapshot-snapshothtmldiff--too-large-html',\n      'webapp-screens-snapshot-snapshothtmldiff--too-large-diff',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-snapshot-snapshothtmldiff--loading': {\n    id: 'webapp-screens-snapshot-snapshothtmldiff--loading',\n    title: 'Webapp screens/Snapshot/SnapshotHtmlDiff',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshothtmldiff',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshothtmldiff--loading-baseline': {\n    id: 'webapp-screens-snapshot-snapshothtmldiff--loading-baseline',\n    title: 'Webapp screens/Snapshot/SnapshotHtmlDiff',\n    name: 'loading-baseline',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshothtmldiff',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshothtmldiff--default': {\n    id: 'webapp-screens-snapshot-snapshothtmldiff--default',\n    title: 'Webapp screens/Snapshot/SnapshotHtmlDiff',\n    name: 'default',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshothtmldiff',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshothtmldiff--long-lines': {\n    id: 'webapp-screens-snapshot-snapshothtmldiff--long-lines',\n    title: 'Webapp screens/Snapshot/SnapshotHtmlDiff',\n    name: 'long lines',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshothtmldiff',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshothtmldiff--too-large-issue-1885': {\n    id: 'webapp-screens-snapshot-snapshothtmldiff--too-large-issue-1885',\n    title: 'Webapp screens/Snapshot/SnapshotHtmlDiff',\n    name: 'too large (issue #1885)',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshothtmldiff',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshothtmldiff--large-after-pretty-print-issue-1885-b': {\n    id: 'webapp-screens-snapshot-snapshothtmldiff--large-after-pretty-print-issue-1885-b',\n    title: 'Webapp screens/Snapshot/SnapshotHtmlDiff',\n    name: 'large after pretty print (issue #1885b)',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshothtmldiff',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshothtmldiff--too-large-html': {\n    id: 'webapp-screens-snapshot-snapshothtmldiff--too-large-html',\n    title: 'Webapp screens/Snapshot/SnapshotHtmlDiff',\n    name: 'too large (HTML)',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshothtmldiff',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshothtmldiff--too-large-diff': {\n    id: 'webapp-screens-snapshot-snapshothtmldiff--too-large-diff',\n    title: 'Webapp screens/Snapshot/SnapshotHtmlDiff',\n    name: 'too large (DIFF)',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshothtmldiff',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen': {\n    name: 'SnapshotScreen',\n    id: 'webapp-screens-snapshot-snapshotscreen',\n    parent: 'webapp-screens-snapshot',\n    depth: 2,\n    children: [\n      'webapp-screens-snapshot-snapshotscreen--loading',\n      'webapp-screens-snapshot-snapshotscreen--pending-metadata-loading',\n      'webapp-screens-snapshot-snapshotscreen--pending',\n      'webapp-screens-snapshot-snapshotscreen--pending-multi-browser',\n      'webapp-screens-snapshot-snapshotscreen--pending-multi-browser-one-unchanged',\n      'webapp-screens-snapshot-snapshotscreen--pending-new-browser',\n      'webapp-screens-snapshot-snapshotscreen--baseline-upgraded',\n      'webapp-screens-snapshot-snapshotscreen--pending-tall',\n      'webapp-screens-snapshot-snapshotscreen--pending-has-ignored',\n      'webapp-screens-snapshot-snapshotscreen--pending-no-baseline-new-specs',\n      'webapp-screens-snapshot-snapshotscreen--in-progress-no-baseline',\n      'webapp-screens-snapshot-snapshotscreen--in-progress-no-baseline-one-complete',\n      'webapp-screens-snapshot-snapshotscreen--disabled-because-of-newer-build',\n      'webapp-screens-snapshot-snapshotscreen--read-only-logged-in',\n      'webapp-screens-snapshot-snapshotscreen--read-only-not-logged-in',\n      'webapp-screens-snapshot-snapshotscreen--failed',\n      'webapp-screens-snapshot-snapshotscreen--failed-cross-browser-one-complete',\n      'webapp-screens-snapshot-snapshotscreen--error',\n      'webapp-screens-snapshot-snapshotscreen--error-cross-browser-same',\n      'webapp-screens-snapshot-snapshotscreen--error-cross-browser-different',\n      'webapp-screens-snapshot-snapshotscreen--error-image-too-large',\n      'webapp-screens-snapshot-snapshotscreen--error-navigation-timeout',\n      'webapp-screens-snapshot-snapshotscreen--error-navigation-timeout-cross-browser',\n      'webapp-screens-snapshot-snapshotscreen--error-no-js',\n      'webapp-screens-snapshot-snapshotscreen--error-failed-js',\n      'webapp-screens-snapshot-snapshotscreen--error-story-missing',\n      'webapp-screens-snapshot-snapshotscreen--error-metadata-loading',\n      'webapp-screens-snapshot-snapshotscreen--timeout-warning',\n      'webapp-screens-snapshot-snapshotscreen--certificate-warning',\n    ],\n    type: 'component',\n  },\n  'webapp-screens-snapshot-snapshotscreen--loading': {\n    id: 'webapp-screens-snapshot-snapshotscreen--loading',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--pending-metadata-loading': {\n    id: 'webapp-screens-snapshot-snapshotscreen--pending-metadata-loading',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'pending, metadata loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--pending': {\n    id: 'webapp-screens-snapshot-snapshotscreen--pending',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'pending',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--pending-multi-browser': {\n    id: 'webapp-screens-snapshot-snapshotscreen--pending-multi-browser',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'pending, multi-browser',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--pending-multi-browser-one-unchanged': {\n    id: 'webapp-screens-snapshot-snapshotscreen--pending-multi-browser-one-unchanged',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'pending, multi-browser, one unchanged',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--pending-new-browser': {\n    id: 'webapp-screens-snapshot-snapshotscreen--pending-new-browser',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'pending, new browser',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--baseline-upgraded': {\n    id: 'webapp-screens-snapshot-snapshotscreen--baseline-upgraded',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'pending, baseline upgraded',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--pending-tall': {\n    id: 'webapp-screens-snapshot-snapshotscreen--pending-tall',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'pending, tall',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--pending-has-ignored': {\n    id: 'webapp-screens-snapshot-snapshotscreen--pending-has-ignored',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'pending, has ignored',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--pending-no-baseline-new-specs': {\n    id: 'webapp-screens-snapshot-snapshotscreen--pending-no-baseline-new-specs',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'pending, no baseline (new specs)',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--in-progress-no-baseline': {\n    id: 'webapp-screens-snapshot-snapshotscreen--in-progress-no-baseline',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'in progress, no baseline',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--in-progress-no-baseline-one-complete': {\n    id: 'webapp-screens-snapshot-snapshotscreen--in-progress-no-baseline-one-complete',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'in progress, no baseline, one complete',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--disabled-because-of-newer-build': {\n    id: 'webapp-screens-snapshot-snapshotscreen--disabled-because-of-newer-build',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'disabled because of newer build',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--read-only-logged-in': {\n    id: 'webapp-screens-snapshot-snapshotscreen--read-only-logged-in',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'read only logged in',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--read-only-not-logged-in': {\n    id: 'webapp-screens-snapshot-snapshotscreen--read-only-not-logged-in',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'read only not logged in',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--failed': {\n    id: 'webapp-screens-snapshot-snapshotscreen--failed',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'failed',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--failed-cross-browser-one-complete': {\n    id: 'webapp-screens-snapshot-snapshotscreen--failed-cross-browser-one-complete',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'failed, cross browser, one complete',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--error': {\n    id: 'webapp-screens-snapshot-snapshotscreen--error',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'error',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--error-cross-browser-same': {\n    id: 'webapp-screens-snapshot-snapshotscreen--error-cross-browser-same',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'error, cross-browser, same',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--error-cross-browser-different': {\n    id: 'webapp-screens-snapshot-snapshotscreen--error-cross-browser-different',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'error, cross-browser, different',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--error-image-too-large': {\n    id: 'webapp-screens-snapshot-snapshotscreen--error-image-too-large',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'error, image too large',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--error-navigation-timeout': {\n    id: 'webapp-screens-snapshot-snapshotscreen--error-navigation-timeout',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'error, navigation timeout',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--error-navigation-timeout-cross-browser': {\n    id: 'webapp-screens-snapshot-snapshotscreen--error-navigation-timeout-cross-browser',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'error, navigation timeout, cross browser',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--error-no-js': {\n    id: 'webapp-screens-snapshot-snapshotscreen--error-no-js',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'Error No JS',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--error-failed-js': {\n    id: 'webapp-screens-snapshot-snapshotscreen--error-failed-js',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'Error Failed JS',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--error-story-missing': {\n    id: 'webapp-screens-snapshot-snapshotscreen--error-story-missing',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'error, story missing',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--error-metadata-loading': {\n    id: 'webapp-screens-snapshot-snapshotscreen--error-metadata-loading',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'error, metadata loading',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--timeout-warning': {\n    id: 'webapp-screens-snapshot-snapshotscreen--timeout-warning',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'timeoutWarning',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n  'webapp-screens-snapshot-snapshotscreen--certificate-warning': {\n    id: 'webapp-screens-snapshot-snapshotscreen--certificate-warning',\n    title: 'Webapp screens/Snapshot/SnapshotScreen',\n    name: 'Certificate Warning',\n    importPath: './path.js',\n    args: {},\n    argTypes: {},\n    initialArgs: {},\n    depth: 3,\n    parent: 'webapp-screens-snapshot-snapshotscreen',\n    type: 'story',\n    subtype: 'story',\n    prepared: true,\n  },\n} as Dataset;\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/mockdata.ts",
    "content": "import type { API_HashEntry } from 'storybook/internal/types';\n\nexport type MockDataSet = Record<string, Record<string, Partial<API_HashEntry>>>;\n\nexport const mockDataset: MockDataSet = {\n  withRoot: {\n    'group-1': {\n      type: 'group',\n      children: ['group-1--child-b1', 'group-1--child-b2'],\n      depth: 0,\n      id: 'group-1',\n      name: 'Group 1',\n    },\n    'group-1--child-b1': {\n      type: 'story',\n      subtype: 'story',\n      prepared: true,\n      id: 'group-1--child-b1',\n      depth: 1,\n      name: 'Child B1',\n      parent: 'group-1',\n      title: '',\n      args: {},\n      initialArgs: {},\n      importPath: './importPath.js',\n    },\n    'group-1--child-b2': {\n      type: 'story',\n      subtype: 'story',\n      prepared: true,\n      id: 'group-1--child-b2',\n      depth: 1,\n      name: 'Child B2',\n      parent: 'group-1',\n      title: '',\n      args: {},\n      initialArgs: {},\n      importPath: './importPath.js',\n    },\n    'root-1': {\n      type: 'root',\n      children: ['root-1-child-a1', 'root-1-child-a2'],\n      depth: 0,\n      id: 'root-1',\n      name: 'Root 1',\n    },\n    'root-1-child-a1': {\n      type: 'component',\n      id: 'root-1-child-a1',\n      parent: 'root-1',\n      depth: 1,\n      name: 'Child A1',\n      children: [],\n    },\n    'root-1-child-a2': {\n      type: 'component',\n      id: 'root-1-child-a2',\n      parent: 'root-1',\n      name: 'Child A2',\n      depth: 1,\n      children: ['root-1-child-a2--grandchild-a1-1', 'root-1-child-a2--grandchild-a1-2'],\n    },\n    'root-1-child-a2--grandchild-a1-1': {\n      type: 'story',\n      subtype: 'story',\n      prepared: true,\n      id: 'root-1-child-a2--grandchild-a1-1',\n      parent: 'root-1-child-a2',\n      depth: 2,\n      name: 'GrandChild A1.1',\n      title: '',\n      args: {},\n      initialArgs: {},\n      importPath: './importPath.js',\n      children: ['root-1-child-a2--grandchild-a1-1:test1'],\n    },\n    'root-1-child-a2--grandchild-a1-1:test1': {\n      type: 'story',\n      subtype: 'test',\n      prepared: true,\n      id: 'root-1-child-a2--grandchild-a1-1:test1',\n      parent: 'root-1-child-a2--grandchild-a1-1',\n      depth: 3,\n      name: 'Test 1',\n      title: '',\n      args: {},\n      initialArgs: {},\n      importPath: './importPath.js',\n    },\n    'root-1-child-a2--grandchild-a1-2': {\n      type: 'story',\n      subtype: 'story',\n      prepared: true,\n      id: 'root-1-child-a2--grandchild-a1-2',\n      parent: 'root-1-child-a2',\n      depth: 2,\n      name: 'GrandChild A1.2',\n      title: '',\n      args: {},\n      initialArgs: {},\n      importPath: './importPath.js',\n    },\n    'root-3': {\n      type: 'root',\n      children: ['root-3--child-a1', 'root-3-child-a2'],\n      depth: 0,\n      id: 'root-3',\n      name: 'Root 3',\n    },\n    'root-3--child-a1': {\n      type: 'story',\n      subtype: 'story',\n      prepared: true,\n      id: 'root-3--child-a1',\n      depth: 1,\n      name: 'Child A1',\n      parent: 'root-3',\n      title: '',\n      args: {},\n      initialArgs: {},\n      importPath: './importPath.js',\n    },\n    'root-3-child-a2': {\n      type: 'component',\n      id: 'root-3-child-a2',\n      name: 'Child A2',\n      depth: 1,\n      children: ['root-3-child-a2--grandchild-a1-1', 'root-3-child-a2--grandchild-a1-2'],\n      parent: 'root-3',\n    },\n    'root-3-child-a2--grandchild-a1-1': {\n      type: 'story',\n      subtype: 'story',\n      prepared: true,\n      id: 'root-3-child-a2--grandchild-a1-1',\n      depth: 2,\n      name: 'GrandChild A1.1',\n      parent: 'root-3-child-a2',\n      title: '',\n      args: {},\n      initialArgs: {},\n      importPath: './importPath.js',\n    },\n    'root-3-child-a2--grandchild-a1-2': {\n      type: 'story',\n      subtype: 'story',\n      prepared: true,\n      id: 'root-3-child-a2--grandchild-a1-2',\n      depth: 2,\n      name: 'GrandChild A1.2',\n      parent: 'root-3-child-a2',\n      title: '',\n      args: {},\n      initialArgs: {},\n      importPath: './importPath.js',\n    },\n  },\n  noRoot: {\n    'root-1': {\n      children: ['root-1-child-a1', 'root-1-child-a2'],\n      type: 'group',\n      depth: 0,\n      id: 'root-1',\n      name: 'Parent A',\n    },\n    'group-1': {\n      children: ['group-1--child-b1', 'group-1--child-b2'],\n      type: 'component',\n      depth: 0,\n      id: 'group-1',\n      name: 'Parent B',\n    },\n    'root-1-child-a1': {\n      id: 'root-1-child-a1',\n      depth: 1,\n      name: 'Child A1',\n      type: 'story',\n      subtype: 'story',\n      prepared: true,\n      parent: 'root-1',\n      title: '',\n      args: {},\n      initialArgs: {},\n      importPath: './importPath.js',\n    },\n    'root-1-child-a2--grandchild-a1-1': {\n      id: 'root-1-child-a2--grandchild-a1-1',\n      depth: 2,\n      name: 'GrandChild A1.1',\n      type: 'story',\n      subtype: 'story',\n      prepared: true,\n      parent: 'root-1-child-a2',\n      title: '',\n      args: {},\n      initialArgs: {},\n      importPath: './importPath.js',\n    },\n    'root-1-child-a2--grandchild-a1-2': {\n      id: 'root-1-child-a2--grandchild-a1-2',\n      depth: 2,\n      name: 'GrandChild A1.2',\n      type: 'story',\n      subtype: 'story',\n      prepared: true,\n      parent: 'root-1-child-a2',\n      title: '',\n      args: {},\n      initialArgs: {},\n      importPath: './importPath.js',\n    },\n    'root-1-child-a2': {\n      id: 'root-1-child-a2',\n      name: 'Child A2',\n      depth: 1,\n      children: ['root-1-child-a2--grandchild-a1-1', 'root-1-child-a2--grandchild-a1-2'],\n      type: 'component',\n      parent: 'root-1',\n    },\n    'group-1--child-b1': {\n      id: 'group-1--child-b1',\n      depth: 1,\n      name: 'Child B1',\n      type: 'story',\n      subtype: 'story',\n      prepared: true,\n      parent: 'group-1',\n      title: '',\n      args: {},\n      initialArgs: {},\n      importPath: './importPath.js',\n    },\n    'group-1--child-b2': {\n      id: 'group-1--child-b2',\n      depth: 1,\n      name: 'Child B2',\n      type: 'story',\n      subtype: 'story',\n      prepared: true,\n      parent: 'group-1',\n      title: '',\n      args: {},\n      initialArgs: {},\n      importPath: './importPath.js',\n    },\n  },\n};\n\nexport const mockSelected = {\n  withRoot: {\n    'root-1': false,\n    'group-1': false,\n    'root-1-child-a1': false,\n    'root-1-child-a2--grandchild-a1-1': false,\n    'root-1-child-a2--grandchild-a1-2': false,\n    'root-1-child-a2': false,\n    'group-1--child-b1': false,\n    'group-1--child-b2': false,\n    'root-3': false,\n    'root-3--child-a1': false,\n    'root-3-child-a2': false,\n    'root-3-child-a2--grandchild-a1-1': false,\n    'root-3-child-a2--grandchild-a1-2': false,\n  },\n  noRoot: {\n    'root-1': false,\n    'group-1': false,\n    'root-1-child-a1': false,\n    'root-1-child-a2--grandchild-a1-1': false,\n    'root-1-child-a2--grandchild-a1-2': false,\n    'root-1-child-a2': false,\n    'group-1--child-b1': false,\n    'group-1--child-b2': false,\n  },\n};\n\nexport const mockExpanded = {\n  withRoot: {\n    'root-1': true,\n    'group-1': false,\n    'root-1-child-a1': true,\n    'root-1-child-a2--grandchild-a1-1': false,\n    'root-1-child-a2--grandchild-a1-2': false,\n    'root-1-child-a2': false,\n    'group-1--child-b1': false,\n    'group-1--child-b2': false,\n    'root-3': false,\n    'root-3--child-a1': false,\n    'root-3-child-a2': false,\n    'root-3-child-a2--grandchild-a1-1': false,\n    'root-3-child-a2--grandchild-a1-2': false,\n  },\n  noRoot: {\n    'root-1': true,\n    'group-1': false,\n    'root-1-child-a1': true,\n    'root-1-child-a2--grandchild-a1-1': false,\n    'root-1-child-a2--grandchild-a1-2': false,\n    'root-1-child-a2': false,\n    'group-1--child-b1': false,\n    'group-1--child-b2': false,\n  },\n  noRootSecond: {\n    'root-1': true,\n    'group-1': false,\n    'root-1-child-a1': true,\n    'root-1-child-a2--grandchild-a1-1': true,\n    'root-1-child-a2--grandchild-a1-2': true,\n    'root-1-child-a2': true,\n    'group-1--child-b1': false,\n    'group-1--child-b2': false,\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/types.ts",
    "content": "import type { StatusValue, StatusesByStoryIdAndTypeId } from 'storybook/internal/types';\n\nimport type { ControllerStateAndHelpers } from 'downshift';\nimport type { State, StoriesHash } from 'storybook/manager-api';\n\nexport type Refs = State['refs'];\nexport type RefType = Refs[keyof Refs] & { allStatuses?: StatusesByStoryIdAndTypeId };\nexport type Item = StoriesHash[keyof StoriesHash];\nexport type Dataset = Record<string, Item>;\n\nexport interface CombinedDataset {\n  hash: Refs;\n  entries: [string, RefType][];\n}\n\nexport interface ItemRef {\n  itemId: string;\n  refId: string;\n}\nexport interface StoryRef {\n  storyId: string;\n  refId: string;\n}\n\nexport type Highlight = ItemRef | null;\nexport type Selection = StoryRef | null;\n\nexport interface Match {\n  value: string;\n  indices: [number, number][];\n  key: 'name' | 'path';\n  arrayIndex: number;\n}\n\nexport function isExpandType(x: any): x is ExpandType {\n  return !!(x && x.showAll);\n}\nexport function isSearchResult(x: any): x is SearchResult {\n  return !!(x && x.item);\n}\nexport interface ExpandType {\n  showAll: () => void;\n  totalCount: number;\n  moreCount: number;\n}\n\nexport type SearchItem = Item & { refId: string; path: string[]; status?: StatusValue };\n\nexport type SearchResult = Fuse.FuseResultWithMatches<SearchItem> &\n  Fuse.FuseResultWithScore<SearchItem>;\n\nexport type DownshiftItem = SearchResult | ExpandType;\n\nexport type SearchChildrenFn = (args: {\n  query: string;\n  results: DownshiftItem[];\n  // Whether the nav explorer should be visible in the UI. When the search input is\n  // focused, it gets replaced with a list of recently viewed stories. When there\n  // is a search query, it gets replaced by the search results.\n  isNavVisible: boolean;\n  // Whether the nav explorer should be reachable in the document. When the search\n  // input is focused, we keep the nav rendered in the document and reachable by\n  // keyboard, so keyboard shortcuts to navigate to it still work.\n  isNavReachable: boolean;\n  // Whether the UI with search results or recently viewed pages is visible.\n  isSearchResultRendered: boolean;\n  closeMenu: (cb?: () => void) => void;\n  getMenuProps: ControllerStateAndHelpers<DownshiftItem>['getMenuProps'];\n  getItemProps: ControllerStateAndHelpers<DownshiftItem>['getItemProps'];\n  highlightedIndex: number | null;\n}) => React.ReactNode;\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/useChecklist.ts",
    "content": "import { useEffect, useMemo, useState } from 'react';\n\nimport { PREVIEW_INITIALIZED } from 'storybook/internal/core-events';\nimport { type API_IndexHash } from 'storybook/internal/types';\n\nimport {\n  internal_checklistStore as checklistStore,\n  internal_universalChecklistStore as universalChecklistStore,\n} from '#manager-stores';\nimport { debounce, throttle } from 'es-toolkit/function';\nimport {\n  type API,\n  experimental_UniversalStore,\n  experimental_useUniversalStore,\n  useStorybookApi,\n  useStorybookState,\n} from 'storybook/manager-api';\n\nimport type { ItemState } from '../../../shared/checklist-store/index.ts';\nimport type { ChecklistData } from '../../../shared/checklist-store/checklistData.tsx';\nimport { checklistData } from '../../../shared/checklist-store/checklistData.tsx';\n\ntype RawItemWithSection = ChecklistData['sections'][number]['items'][number] & {\n  itemIndex: number;\n  sectionId: string;\n  sectionIndex: number;\n  sectionTitle: string;\n};\n\nexport type ChecklistItem = RawItemWithSection & {\n  isAvailable: boolean;\n  isOpen: boolean;\n  isLockedBy: string | undefined;\n  isImmutable: boolean;\n  isReady: boolean;\n  isCompleted: boolean;\n  isAccepted: boolean;\n  isDone: boolean;\n  isSkipped: boolean;\n  isMuted: boolean;\n};\n\nconst subscriptions = new Map<string, void | (() => void)>();\n\nconst useStoryIndex = () => {\n  const state = useStorybookState();\n  const [index, setIndex] = useState<API_IndexHash | undefined>(() => state.index);\n  const updateIndex = useMemo(() => throttle(setIndex, 500), []);\n\n  useEffect(() => updateIndex(state.index), [state.index, updateIndex]);\n  useEffect(() => () => updateIndex.cancel?.(), [updateIndex]);\n\n  return index;\n};\n\nconst checkAvailable = (\n  item: RawItemWithSection,\n  itemsById: Record<RawItemWithSection['id'], RawItemWithSection>,\n  context: { api: API; index: API_IndexHash | undefined; item: RawItemWithSection }\n) => {\n  if (item.available && !item.available(context)) {\n    return false;\n  }\n  for (const afterId of item.after ?? []) {\n    if (itemsById[afterId] && !checkAvailable(itemsById[afterId], itemsById, context)) {\n      return false;\n    }\n  }\n  return true;\n};\n\nconst checkSkipped = (\n  item: RawItemWithSection,\n  itemsById: Record<RawItemWithSection['id'], RawItemWithSection>,\n  state: Record<string, ItemState>\n) => {\n  const itemValue = state[item.id];\n  if (itemValue.status === 'skipped') {\n    return true;\n  }\n  for (const afterId of item.after ?? []) {\n    if (itemsById[afterId] && checkSkipped(itemsById[afterId], itemsById, state)) {\n      return true;\n    }\n  }\n  return false;\n};\n\nconst getAncestorIds = (\n  item: RawItemWithSection,\n  itemsById: Record<RawItemWithSection['id'], RawItemWithSection>\n): string[] => {\n  if (!item.after || item.after.length === 0) {\n    return [];\n  }\n  return item.after.flatMap((afterId) => {\n    const afterItem = itemsById[afterId];\n    return afterItem ? [...getAncestorIds(afterItem, itemsById), afterId] : [];\n  });\n};\n\nconst checkLockedBy = (\n  item: RawItemWithSection,\n  itemsById: Record<RawItemWithSection['id'], RawItemWithSection>,\n  state: Record<string, ItemState>\n): string | undefined =>\n  getAncestorIds(item, itemsById).find(\n    (id) => state[id].status !== 'accepted' && state[id].status !== 'done'\n  );\n\nexport const useChecklist = () => {\n  const api = useStorybookApi();\n  const index = useStoryIndex();\n  const [checklistState] = experimental_useUniversalStore(universalChecklistStore);\n  const { loaded, items, widget } = checklistState;\n  const { status } = universalChecklistStore;\n\n  const [initialized, setInitialized] = useState(false);\n  const [ready, setReady] = useState(false);\n\n  const debounceReady = useMemo(() => debounce(() => setReady(true), 500), []);\n\n  const itemsById = useMemo<Record<string, RawItemWithSection>>(() => {\n    return Object.fromEntries(\n      checklistData.sections.flatMap(\n        ({ items, id: sectionId, title: sectionTitle }, sectionIndex) =>\n          items.map(({ id, ...item }, itemIndex) => {\n            return [id, { id, itemIndex, sectionId, sectionIndex, sectionTitle, ...item }];\n          })\n      )\n    );\n  }, []);\n\n  const allItems = useMemo(() => {\n    return Object.values(itemsById).map<ChecklistItem>((item) => {\n      const { status, mutedAt } = items[item.id];\n      const isOpen = status === 'open';\n      const isAccepted = status === 'accepted';\n      const isDone = status === 'done';\n      const isCompleted = isAccepted || isDone;\n      const isSkipped = !isCompleted && checkSkipped(item, itemsById, items);\n      const isMuted = !!mutedAt || !!widget.disable;\n\n      const isAvailable = isCompleted\n        ? item.afterCompletion !== 'unavailable'\n        : checkAvailable(item, itemsById, { api, index, item });\n      const isLockedBy = checkLockedBy(item, itemsById, items);\n      const isImmutable = isCompleted && item.afterCompletion === 'immutable';\n      const isReady = isOpen && isAvailable && !isMuted && !isLockedBy;\n\n      return {\n        ...item,\n        isAvailable,\n        isOpen,\n        isLockedBy,\n        isImmutable,\n        isReady,\n        isCompleted,\n        isAccepted,\n        isDone,\n        isSkipped,\n        isMuted,\n      };\n    });\n  }, [itemsById, items, widget, api, index]);\n\n  const itemCollections = useMemo(() => {\n    const availableItems = allItems.filter((item) => item.isAvailable);\n    const openItems = availableItems.filter((item) => item.isOpen);\n    const readyItems = openItems.filter((item) => item.isReady);\n\n    // Collect a list of the next 3 tasks that are ready.\n    // Tasks are pulled from each section in a round-robin fashion,\n    // so that users can choose their own adventure.\n    const nextItems = Object.values(\n      readyItems.reduce<Record<string, ChecklistItem[]>>((acc, item) => {\n        // Reset itemIndex to only include ready items.\n        acc[item.sectionId] ??= [];\n        acc[item.sectionId].push({ ...item, itemIndex: acc[item.sectionId].length });\n        return acc;\n      }, {})\n    )\n      .flat()\n      .sort((a, b) => a.itemIndex - b.itemIndex)\n      .slice(0, 3)\n      .sort((a, b) => a.sectionIndex - b.sectionIndex);\n\n    const progress = availableItems.length\n      ? Math.round(((availableItems.length - openItems.length) / availableItems.length) * 100)\n      : 100;\n\n    return { availableItems, openItems, readyItems, nextItems, progress };\n  }, [allItems]);\n\n  useEffect(() => {\n    if (!loaded || status !== experimental_UniversalStore.Status.READY) {\n      return;\n    }\n\n    for (const item of allItems) {\n      if (!item.subscribe) {\n        continue;\n      }\n\n      const subscribed = subscriptions.has(item.id);\n      if (item.isOpen && item.isAvailable && !subscribed) {\n        subscriptions.set(\n          item.id,\n          item.subscribe({\n            api,\n            item,\n            accept: () => checklistStore.accept(item.id),\n            done: () => checklistStore.done(item.id),\n            skip: () => checklistStore.skip(item.id),\n          })\n        );\n      } else if (subscribed && !(item.isOpen && item.isAvailable)) {\n        const unsubscribe = subscriptions.get(item.id);\n        subscriptions.delete(item.id);\n        if (typeof unsubscribe === 'function') {\n          unsubscribe();\n        }\n      }\n    }\n  }, [api, loaded, status, allItems]);\n\n  useEffect(() => {\n    const initialize = () => setInitialized(true);\n    const timeout = setTimeout(initialize, 1000);\n    api.once(PREVIEW_INITIALIZED, initialize);\n    return () => {\n      clearTimeout(timeout);\n      api.off(PREVIEW_INITIALIZED, initialize);\n    };\n  }, [api]);\n\n  useEffect(() => {\n    if (initialized && items && status === experimental_UniversalStore.Status.READY) {\n      debounceReady();\n    }\n  }, [initialized, items, status, debounceReady]);\n\n  return {\n    ready,\n    allItems,\n    ...itemCollections,\n    ...checklistStore,\n    ...checklistState,\n  };\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/useDynamicFavicon.stories.tsx",
    "content": "import React, { useEffect, useState } from 'react';\n\nimport { getFaviconUrl } from './useDynamicFavicon.ts';\n\nexport default {\n  title: 'Dynamic Favicon',\n  args: {\n    size: 16,\n  },\n  argTypes: {\n    size: {\n      control: 'select',\n      options: [16, 32, 64, 128, 256],\n    },\n    status: {\n      control: 'select',\n      options: ['active', 'positive', 'warning', 'negative', 'critical'],\n    },\n  },\n  render: ({ status, size }: { status?: Parameters<typeof getFaviconUrl>[1]; size?: number }) => {\n    const [favicon, setFavicon] = useState<string | null>(null);\n\n    useEffect(() => {\n      getFaviconUrl(undefined, status).then(({ href }) => setFavicon(href));\n    }, [status]);\n\n    return favicon ? <img width={size} height={size} src={favicon} /> : <></>;\n  },\n};\n\nexport const Statuses = {\n  argTypes: {\n    status: {\n      table: {\n        disable: true,\n      },\n    },\n  },\n  parameters: {\n    chromatic: {\n      // Dynamic favicon status doesn't work in static builds\n      disableSnapshot: true,\n    },\n  },\n  render: ({ size }: { size: number }) => (\n    <div style={{ display: 'flex', gap: size / 2 }}>\n      <img role=\"presentation\" width={size} height={size} src={'./favicon.svg'} />\n      <img role=\"presentation\" width={size} height={size} src={'./favicon.svg?status=active'} />\n      <img role=\"presentation\" width={size} height={size} src={'./favicon.svg?status=positive'} />\n      <img role=\"presentation\" width={size} height={size} src={'./favicon.svg?status=warning'} />\n      <img role=\"presentation\" width={size} height={size} src={'./favicon.svg?status=negative'} />\n      <img role=\"presentation\" width={size} height={size} src={'./favicon.svg?status=critical'} />\n    </div>\n  ),\n};\n\nexport const Sizes = {\n  argTypes: {\n    size: {\n      table: {\n        disable: true,\n      },\n    },\n  },\n  render: ({ status }: { status?: Parameters<typeof getFaviconUrl>[1] }) => (\n    <div style={{ display: 'flex', gap: 10 }}>\n      <img role=\"presentation\" width={16} height={16} src={`./favicon.svg?status=${status}`} />\n      <img role=\"presentation\" width={32} height={32} src={`./favicon.svg?status=${status}`} />\n      <img role=\"presentation\" width={64} height={64} src={`./favicon.svg?status=${status}`} />\n      <img role=\"presentation\" width={128} height={128} src={`./favicon.svg?status=${status}`} />\n      <img role=\"presentation\" width={256} height={256} src={`./favicon.svg?status=${status}`} />\n    </div>\n  ),\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/useDynamicFavicon.ts",
    "content": "/* eslint-env browser */\nimport { useEffect, useRef } from 'react';\n\nconst STATUSES = ['active', 'critical', 'negative', 'positive', 'warning'] as const;\n\nlet initialIcon: string | undefined;\n\nexport const getFaviconUrl = (\n  initialHref: string = './favicon.svg',\n  status?: (typeof STATUSES)[number]\n) => {\n  initialIcon ??= initialHref;\n  const href = initialIcon + (status && STATUSES.includes(status) ? `?status=${status}` : '');\n\n  return new Promise<{ href: string; status?: (typeof STATUSES)[number] }>((resolve) => {\n    const img = new Image();\n    img.onload = () => resolve({ href, status });\n    img.onerror = () => resolve({ href: initialIcon!, status });\n    img.src = href;\n  });\n};\n\nexport const useDynamicFavicon = (status?: (typeof STATUSES)[number]) => {\n  const links = useRef(document.head.querySelectorAll<HTMLLinkElement>(\"link[rel*='icon']\"));\n  useEffect(() => {\n    let isMounted = true;\n    const [element, ...others] = links.current;\n    // Custom filenames are not supported, so if there's other icon links, we don't do anything\n    if (element && !others.length) {\n      getFaviconUrl(element.href, status).then(\n        (result) => {\n          if (isMounted && result.status === status && element.dataset.status !== status) {\n            element.href = result.href;\n            if (result.status) {\n              element.dataset.status = result.status;\n            } else {\n              delete element.dataset.status;\n            }\n          }\n        },\n        () => {\n          if (isMounted) {\n            element.href = initialIcon!;\n          }\n        }\n      );\n      return () => {\n        isMounted = false;\n        element.href = initialIcon!;\n      };\n    }\n  }, [status]);\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/useExpanded.ts",
    "content": "import type { Dispatch, MutableRefObject, Reducer } from 'react';\nimport { useCallback, useEffect, useReducer } from 'react';\n\nimport { STORIES_COLLAPSE_ALL, STORIES_EXPAND_ALL } from 'storybook/internal/core-events';\n\nimport { global } from '@storybook/global';\n\nimport { throttle } from 'es-toolkit/function';\nimport type { StoriesHash } from 'storybook/manager-api';\nimport { useStorybookApi } from 'storybook/manager-api';\n\nimport { matchesKeyCode, matchesModifiers } from '../../keybinding.ts';\nimport { getAncestorIds, getDescendantIds, isAncestor, scrollIntoView } from '../../utils/tree.ts';\nimport type { Highlight } from './types.ts';\n\nconst { document } = global;\n\nexport type ExpandedState = Record<string, boolean>;\n\nexport interface ExpandAction {\n  ids: string[];\n  value: boolean;\n}\n\nexport interface ExpandedProps {\n  containerRef: MutableRefObject<HTMLElement>;\n  isBrowsing: boolean;\n  refId: string;\n  data: StoriesHash;\n  initialExpanded?: ExpandedState;\n  rootIds: string[];\n  highlightedRef: MutableRefObject<Highlight>;\n  setHighlightedItemId: (storyId: string) => void;\n  selectedStoryId: string | null;\n  onSelectStoryId: (storyId: string) => void;\n}\n\nconst initializeExpanded = ({\n  refId,\n  data,\n  initialExpanded,\n  highlightedRef,\n  rootIds,\n  selectedStoryId,\n}: {\n  refId: string;\n  data: StoriesHash;\n  initialExpanded?: ExpandedState;\n  highlightedRef: MutableRefObject<Highlight>;\n  rootIds: string[];\n  selectedStoryId: string | null;\n}) => {\n  const selectedStory = selectedStoryId && data[selectedStoryId];\n  const candidates = [...rootIds];\n  if (highlightedRef.current?.refId === refId) {\n    candidates.push(...getAncestorIds(data, highlightedRef.current?.itemId));\n  }\n  if (selectedStory && 'children' in selectedStory && selectedStory.children?.length) {\n    candidates.push(selectedStoryId);\n  }\n  return candidates.reduce<ExpandedState>(\n    // @ts-expect-error (non strict)\n    (acc, id) => Object.assign(acc, { [id]: id in initialExpanded ? initialExpanded[id] : true }),\n    {}\n  );\n};\n\nconst noop = () => {};\n\nexport const useExpanded = ({\n  containerRef,\n  isBrowsing,\n  refId,\n  data,\n  initialExpanded,\n  rootIds,\n  highlightedRef,\n  setHighlightedItemId,\n  selectedStoryId,\n  onSelectStoryId,\n}: ExpandedProps): [ExpandedState, Dispatch<ExpandAction>] => {\n  const api = useStorybookApi();\n\n  // Track the set of currently expanded nodes within this tree.\n  // Root nodes are expanded by default.\n  const [expanded, setExpanded] = useReducer<\n    Reducer<ExpandedState, ExpandAction>,\n    {\n      refId: string;\n      data: StoriesHash;\n      highlightedRef: MutableRefObject<Highlight>;\n      rootIds: string[];\n      initialExpanded: ExpandedState;\n    }\n  >(\n    (state, { ids, value }) =>\n      ids.reduce((acc, id) => Object.assign(acc, { [id]: value }), { ...state }),\n    // @ts-expect-error (non strict)\n    { refId, data, highlightedRef, rootIds, initialExpanded, selectedStoryId },\n    initializeExpanded\n  );\n\n  const getElementByDataItemId = useCallback(\n    (id: string) => containerRef.current?.querySelector(`[data-item-id=\"${id}\"]`),\n    [containerRef]\n  );\n\n  const highlightElement = useCallback(\n    (element: Element) => {\n      // @ts-expect-error (non strict)\n      setHighlightedItemId(element.getAttribute('data-item-id'));\n      scrollIntoView(element);\n    },\n    [setHighlightedItemId]\n  );\n\n  const updateExpanded = useCallback(\n    ({ ids, value }: ExpandAction) => {\n      // @ts-expect-error (non strict)\n      setExpanded({ ids, value });\n      if (ids.length === 1) {\n        const element = containerRef.current?.querySelector(\n          `[data-item-id=\"${ids[0]}\"][data-ref-id=\"${refId}\"]`\n        );\n\n        if (element) {\n          highlightElement(element);\n        }\n      }\n    },\n    [containerRef, highlightElement, refId]\n  );\n\n  // Expand the whole ancestry of the currently selected story whenever it changes.\n  useEffect(() => {\n    // @ts-expect-error (non strict)\n    setExpanded({ ids: getAncestorIds(data, selectedStoryId), value: true });\n  }, [data, selectedStoryId]);\n\n  const collapseAll = useCallback(() => {\n    const ids = Object.keys(data).filter((id) => !rootIds.includes(id));\n    // @ts-expect-error (non strict)\n    setExpanded({ ids, value: false });\n  }, [data, rootIds]);\n\n  const expandAll = useCallback(() => {\n    // @ts-expect-error (non strict)\n    setExpanded({ ids: Object.keys(data), value: true });\n  }, [data]);\n\n  useEffect(() => {\n    if (!api) {\n      return noop;\n    }\n\n    api.on(STORIES_COLLAPSE_ALL, collapseAll);\n    api.on(STORIES_EXPAND_ALL, expandAll);\n\n    return () => {\n      api.off(STORIES_COLLAPSE_ALL, collapseAll);\n      api.off(STORIES_EXPAND_ALL, expandAll);\n    };\n  }, [api, collapseAll, expandAll]);\n\n  // Expand, collapse or select nodes in the tree using keyboard shortcuts.\n  useEffect(() => {\n    const menuElement = document.getElementById('storybook-explorer-menu');\n\n    // Even though we ignore repeated events, use throttle because IE doesn't support event.repeat.\n    const navigateTree = throttle((event: KeyboardEvent) => {\n      const highlightedItemId =\n        highlightedRef.current?.refId === refId && highlightedRef.current?.itemId;\n\n      if (!isBrowsing || !containerRef.current || !highlightedItemId || event.repeat) {\n        return;\n      }\n\n      if (!matchesModifiers(false, event)) {\n        return;\n      }\n\n      const isEnter = matchesKeyCode('Enter', event);\n      const isSpace = matchesKeyCode('Space', event);\n      const isArrowLeft = matchesKeyCode('ArrowLeft', event);\n      const isArrowRight = matchesKeyCode('ArrowRight', event);\n\n      if (!(isEnter || isSpace || isArrowLeft || isArrowRight)) {\n        return;\n      }\n\n      const highlightedElement = getElementByDataItemId(highlightedItemId);\n\n      if (!highlightedElement || highlightedElement.getAttribute('data-ref-id') !== refId) {\n        return;\n      }\n\n      const target = event.target as Element;\n\n      // @ts-expect-error (non strict)\n      if (!isAncestor(menuElement, target) && !isAncestor(target, menuElement)) {\n        return;\n      }\n      if (target.hasAttribute('data-action')) {\n        if (isEnter || isSpace) {\n          return;\n        }\n        (target as HTMLButtonElement).blur();\n      }\n\n      const type = highlightedElement.getAttribute('data-nodetype');\n      if (\n        type &&\n        (isEnter || isSpace) &&\n        ['component', 'story', 'document', 'test'].includes(type)\n      ) {\n        onSelectStoryId(highlightedItemId);\n      }\n\n      const isExpanded = highlightedElement.getAttribute('aria-expanded');\n\n      if (isArrowLeft) {\n        if (isExpanded === 'true') {\n          // The highlighted node is expanded, so we collapse it.\n          // @ts-expect-error (non strict)\n          setExpanded({ ids: [highlightedItemId], value: false });\n          return;\n        }\n\n        const parentId = highlightedElement.getAttribute('data-parent-id');\n        const parentElement = parentId && getElementByDataItemId(parentId);\n        if (parentElement && parentElement.getAttribute('data-highlightable') === 'true') {\n          // The highlighted node isn't expanded, so we move the highlight to its parent instead.\n          highlightElement(parentElement);\n          return;\n        }\n\n        // The parent can't be highlighted, which means it must be a root.\n        // The highlighted node is already collapsed, so we collapse its descendants.\n        // @ts-expect-error (non strict)\n        setExpanded({ ids: getDescendantIds(data, highlightedItemId, true), value: false });\n        return;\n      }\n\n      if (isArrowRight) {\n        if (isExpanded === 'false') {\n          updateExpanded({ ids: [highlightedItemId], value: true });\n        } else if (isExpanded === 'true') {\n          updateExpanded({ ids: getDescendantIds(data, highlightedItemId, true), value: true });\n        }\n      }\n    }, 60);\n\n    document.addEventListener('keydown', navigateTree);\n    return () => document.removeEventListener('keydown', navigateTree);\n  }, [\n    containerRef,\n    isBrowsing,\n    refId,\n    data,\n    highlightedRef,\n    setHighlightedItemId,\n    onSelectStoryId,\n  ]);\n\n  return [expanded, updateExpanded];\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/useFilterData.tsx",
    "content": "import React, { useMemo } from 'react';\n\nimport type {\n  FilterFunction,\n  StatusValue,\n  StatusesByStoryIdAndTypeId,\n  StoryIndex,\n  Tag,\n} from 'storybook/internal/types';\n\nimport { BeakerIcon, DocumentIcon, PlayHollowIcon } from '@storybook/icons';\n\nimport { color } from 'storybook/theming';\n\nimport {\n  BUILT_IN_TAGS,\n  STATUS_DISPLAY_ORDER,\n  getFilterFunction,\n  statusValueShortName,\n} from './FilterPanel.utils.ts';\n\nexport interface TagFilterEntry {\n  id: string;\n  type: 'built-in' | 'tag';\n  title: string;\n  count: number;\n  icon: React.ReactElement | null;\n}\n\nexport interface StatusFilterEntry {\n  statusValue: StatusValue;\n  shortName: string;\n  count: number;\n}\n\nconst BUILT_IN_FILTER_DEFS: Array<{\n  id: string;\n  title: string;\n  icon: React.ReactElement;\n  tag: string;\n}> = [\n  { id: '_docs', title: 'Documentation', icon: <DocumentIcon color={color.gold} />, tag: '_docs' },\n  { id: '_play', title: 'Play', icon: <PlayHollowIcon color={color.seafoam} />, tag: '_play' },\n  { id: '_test', title: 'Testing', icon: <BeakerIcon color={color.green} />, tag: '_test' },\n];\n\nexport function useTagFilterEntries(indexJson: StoryIndex) {\n  return useMemo(() => {\n    const entries = Object.values(indexJson.entries);\n\n    const userTagsCounts = entries.reduce<Record<Tag, number>>((acc, entry) => {\n      entry.tags?.forEach((tag: Tag) => {\n        if (!BUILT_IN_TAGS.has(tag)) {\n          acc[tag] = (acc[tag] || 0) + 1;\n        }\n      });\n      return acc;\n    }, {});\n\n    const tagEntries: TagFilterEntry[] = Object.entries(userTagsCounts).map(([tag, count]) => ({\n      id: tag,\n      type: 'tag',\n      title: tag,\n      count,\n      icon: null,\n    }));\n\n    const getBuiltInCount = (filterFn: FilterFunction | null) =>\n      entries.filter((entry) => filterFn?.(entry)).length;\n\n    const builtInEntries: TagFilterEntry[] = BUILT_IN_FILTER_DEFS.map((def) => ({\n      id: def.id,\n      type: 'built-in',\n      title: def.title,\n      icon: def.icon,\n      count: getBuiltInCount(getFilterFunction(def.tag)),\n    }));\n\n    return { builtInEntries, tagEntries };\n  }, [indexJson.entries]);\n}\n\nexport function useStatusFilterEntries(allStatuses: StatusesByStoryIdAndTypeId) {\n  return useMemo(() => {\n    const counts = {} as Record<StatusValue, number>;\n    Object.values(allStatuses).forEach((statusByTypeId) => {\n      Object.values(statusByTypeId).forEach((status) => {\n        counts[status.value] = (counts[status.value] ?? 0) + 1;\n      });\n    });\n\n    return STATUS_DISPLAY_ORDER.filter((statusValue) => (counts[statusValue] ?? 0) > 0).map(\n      (statusValue) => ({\n        statusValue,\n        shortName: statusValueShortName(statusValue),\n        count: counts[statusValue],\n      })\n    );\n  }, [allStatuses]);\n}\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/useHighlighted.ts",
    "content": "import type { Dispatch, MutableRefObject, RefObject, SetStateAction } from 'react';\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { PRELOAD_ENTRIES } from 'storybook/internal/core-events';\n\nimport { global } from '@storybook/global';\n\nimport { useStorybookApi } from 'storybook/manager-api';\n\nimport { matchesKeyCode, matchesModifiers } from '../../keybinding.ts';\nimport { cycle, isAncestor, scrollIntoView } from '../../utils/tree.ts';\nimport type { Highlight, Selection } from './types.ts';\n\nconst { document, window: globalWindow } = global;\n\nexport interface HighlightedProps {\n  containerRef: RefObject<HTMLElement | null>;\n  isLoading: boolean;\n  isBrowsing: boolean;\n  selected: Selection;\n}\n\nconst fromSelection = (selection: Selection): Highlight =>\n  selection ? { itemId: selection.storyId, refId: selection.refId } : null;\n\nconst scrollToSelector = (\n  selector: string,\n  options: {\n    containerRef?: RefObject<Element | null>;\n    center?: boolean;\n    attempts?: number;\n    delay?: number;\n  } = {},\n  _attempt = 1\n) => {\n  const { containerRef, center = false, attempts = 3, delay = 500 } = options;\n  const element = (containerRef ? containerRef.current : document)?.querySelector(selector);\n  if (element) {\n    scrollIntoView(element, center);\n  } else if (_attempt <= attempts) {\n    setTimeout(scrollToSelector, delay, selector, options, _attempt + 1);\n  }\n};\n\nexport const useHighlighted = ({\n  containerRef,\n  isLoading,\n  isBrowsing,\n  selected,\n}: HighlightedProps): [\n  Highlight,\n  Dispatch<SetStateAction<Highlight>>,\n  MutableRefObject<Highlight>,\n] => {\n  const initialHighlight = fromSelection(selected);\n  const highlightedRef = useRef<Highlight>(initialHighlight);\n  const [highlighted, setHighlighted] = useState<Highlight>(initialHighlight);\n  const api = useStorybookApi();\n\n  const updateHighlighted = useCallback(\n    (highlight: Highlight) => {\n      highlightedRef.current = highlight;\n      setHighlighted(highlight);\n    },\n    [highlightedRef]\n  );\n\n  // Sets the highlighted node and scrolls it into view, using DOM elements as reference\n  const highlightElement = useCallback(\n    (element: Element, center = false) => {\n      const itemId = element.getAttribute('data-item-id');\n      const refId = element.getAttribute('data-ref-id');\n\n      if (!itemId || !refId) {\n        return;\n      }\n      updateHighlighted({ itemId, refId });\n      scrollIntoView(element, center);\n    },\n    [updateHighlighted]\n  );\n\n  // Highlight and scroll to the selected story whenever the selection or dataset changes\n  useEffect(() => {\n    const highlight = fromSelection(selected);\n    updateHighlighted(highlight);\n    if (highlight) {\n      scrollToSelector(`[data-item-id=\"${highlight.itemId}\"][data-ref-id=\"${highlight.refId}\"]`, {\n        containerRef,\n        center: true,\n      });\n    }\n  }, [containerRef, selected, updateHighlighted]);\n\n  // Highlight nodes up/down the tree using arrow keys\n  useEffect(() => {\n    const menuElement = document.getElementById('storybook-explorer-menu');\n\n    let lastRequestId: number;\n    const navigateTree = (event: KeyboardEvent) => {\n      if (isLoading || !isBrowsing || !containerRef.current) {\n        return; // allow event.repeat\n      }\n\n      if (!matchesModifiers(false, event)) {\n        return;\n      }\n\n      const isArrowUp = matchesKeyCode('ArrowUp', event);\n      const isArrowDown = matchesKeyCode('ArrowDown', event);\n\n      if (!(isArrowUp || isArrowDown)) {\n        return;\n      }\n\n      const requestId = globalWindow.requestAnimationFrame(() => {\n        globalWindow.cancelAnimationFrame(lastRequestId);\n        lastRequestId = requestId;\n\n        const target = event.target as Element;\n\n        // @ts-expect-error (non strict)\n        if (!isAncestor(menuElement, target) && !isAncestor(target, menuElement)) {\n          return;\n        }\n\n        if (target.hasAttribute('data-action')) {\n          (target as HTMLButtonElement).blur();\n        }\n\n        const highlightable = Array.from(\n          containerRef.current?.querySelectorAll('[data-highlightable=true]') || []\n        );\n        const currentIndex = highlightable.findIndex(\n          (el) =>\n            el.getAttribute('data-item-id') === highlightedRef.current?.itemId &&\n            el.getAttribute('data-ref-id') === highlightedRef.current?.refId\n        );\n        const nextIndex = cycle(highlightable, currentIndex, isArrowUp ? -1 : 1);\n        const didRunAround = isArrowUp ? nextIndex === highlightable.length - 1 : nextIndex === 0;\n        highlightElement(highlightable[nextIndex], didRunAround);\n\n        if (highlightable[nextIndex].getAttribute('data-nodetype') === 'component') {\n          // @ts-expect-error (non strict)\n          const { itemId, refId } = highlightedRef.current;\n          const item = api.resolveStory(itemId, refId === 'storybook_internal' ? undefined : refId);\n          if (item?.type === 'component') {\n            api.emit(PRELOAD_ENTRIES, {\n              ids: [item.children[0]],\n              options: { target: refId },\n            });\n          }\n        }\n      });\n    };\n\n    document.addEventListener('keydown', navigateTree);\n    return () => document.removeEventListener('keydown', navigateTree);\n  }, [api, containerRef, isLoading, isBrowsing, highlightedRef, highlightElement]);\n\n  // @ts-expect-error (non strict)\n  return [highlighted, updateHighlighted, highlightedRef];\n};\n"
  },
  {
    "path": "code/core/src/manager/components/sidebar/useLastViewed.ts",
    "content": "import { useCallback, useEffect, useMemo, useRef } from 'react';\n\nimport { debounce } from 'es-toolkit/function';\nimport store from 'store2';\n\nimport type { Selection, StoryRef } from './types.ts';\n\nconst save = debounce((value) => store.set('lastViewedStoryIds', value), 1000);\n\nexport const useLastViewed = (selection: Selection) => {\n  const initialLastViewedStoryIds = useMemo((): StoryRef[] => {\n    const items = store.get('lastViewedStoryIds');\n\n    if (!items || !Array.isArray(items)) {\n      return [];\n    }\n\n    if (!items.some((item) => typeof item === 'object' && item.storyId && item.refId)) {\n      return [];\n    }\n    return items;\n  }, [store]);\n\n  const lastViewedRef = useRef(initialLastViewedStoryIds);\n\n  const updateLastViewed = useCallback(\n    (story: StoryRef) => {\n      const items = lastViewedRef.current;\n      const index = items.findIndex(\n        ({ storyId, refId }) => storyId === story.storyId && refId === story.refId\n      );\n\n      if (index === 0) {\n        return;\n      }\n      if (index === -1) {\n        lastViewedRef.current = [story, ...items];\n      } else {\n        lastViewedRef.current = [story, ...items.slice(0, index), ...items.slice(index + 1)];\n      }\n      save(lastViewedRef.current);\n    },\n    [lastViewedRef]\n  );\n\n  useEffect(() => {\n    if (selection) {\n      updateLastViewed(selection);\n    }\n  }, [selection]);\n\n  return {\n    getLastViewed: useCallback(() => lastViewedRef.current, [lastViewedRef]),\n    clearLastViewed: useCallback(() => {\n      lastViewedRef.current = lastViewedRef.current.slice(0, 1);\n      save(lastViewedRef.current);\n    }, [lastViewedRef]),\n  };\n};\n"
  },
  {
    "path": "code/core/src/manager/components/upgrade/UpgradeBlock.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { ManagerContext } from 'storybook/manager-api';\nimport { fn } from 'storybook/test';\n\nimport { UpgradeBlock } from './UpgradeBlock.tsx';\n\nconst meta = {\n  component: UpgradeBlock,\n  title: 'UpgradeBlock',\n  decorators: [\n    (storyFn) => (\n      <ManagerContext.Provider\n        value={\n          {\n            api: {\n              getCurrentVersion: () => ({\n                version: '7.2.2-alpha.0',\n              }),\n            },\n          } as any\n        }\n      >\n        {storyFn()}\n      </ManagerContext.Provider>\n    ),\n  ],\n  args: { onNavigateToWhatsNew: fn() },\n} satisfies Meta<typeof UpgradeBlock>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {\n  args: {},\n};\n"
  },
  {
    "path": "code/core/src/manager/components/upgrade/UpgradeBlock.tsx",
    "content": "import type { FC } from 'react';\nimport React, { useState } from 'react';\n\nimport { Link } from 'storybook/internal/components';\n\nimport { useStorybookApi } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport { MEDIA_DESKTOP_BREAKPOINT } from '../../constants.ts';\n\ninterface UpgradeBlockProps {\n  onNavigateToWhatsNew?: () => void;\n}\n\nexport const UpgradeBlock: FC<UpgradeBlockProps> = ({ onNavigateToWhatsNew }) => {\n  const api = useStorybookApi();\n  const [activeTab, setActiveTab] = useState<'npm' | 'yarn' | 'pnpm'>('npm');\n\n  return (\n    <Container>\n      <strong>You are on Storybook {api.getCurrentVersion().version}</strong>\n      <p>Run the following script to check for updates and upgrade to the latest version.</p>\n      <Tabs>\n        <ButtonTab active={activeTab === 'npm'} onClick={() => setActiveTab('npm')}>\n          npm\n        </ButtonTab>\n        <ButtonTab active={activeTab === 'yarn'} onClick={() => setActiveTab('yarn')}>\n          yarn\n        </ButtonTab>\n        <ButtonTab active={activeTab === 'pnpm'} onClick={() => setActiveTab('pnpm')}>\n          pnpm\n        </ButtonTab>\n      </Tabs>\n      <Code>\n        {activeTab === 'npm'\n          ? 'npx storybook@latest upgrade'\n          : `${activeTab} dlx storybook@latest upgrade`}\n      </Code>\n      {onNavigateToWhatsNew && (\n        <Link onClick={onNavigateToWhatsNew}>See what's new in Storybook</Link>\n      )}\n    </Container>\n  );\n};\n\nconst Container = styled.div(({ theme }) => ({\n  border: '1px solid',\n  borderRadius: 5,\n  padding: 20,\n  marginTop: 0,\n  borderColor: theme.appBorderColor,\n  fontSize: theme.typography.size.s2,\n  width: '100%',\n\n  [MEDIA_DESKTOP_BREAKPOINT]: {\n    maxWidth: 400,\n  },\n}));\n\nconst Tabs = styled.div({\n  display: 'flex',\n  gap: 2,\n});\n\nconst Code = styled.pre(({ theme }) => ({\n  background: theme.base === 'light' ? 'rgba(0, 0, 0, 0.05)' : theme.appBorderColor,\n  fontSize: theme.typography.size.s2 - 1,\n  margin: '4px 0 16px',\n}));\n\nconst ButtonTab = styled.button<{ active: boolean }>(({ theme, active }) => ({\n  all: 'unset',\n  alignItems: 'center',\n  gap: 10,\n  color: theme.color.defaultText,\n  fontSize: theme.typography.size.s2 - 1,\n  borderBottom: '2px solid transparent',\n  borderBottomColor: active ? theme.color.secondary : 'none',\n  padding: '0 10px 5px',\n  marginBottom: '5px',\n  cursor: 'pointer',\n}));\n"
  },
  {
    "path": "code/core/src/manager/constants.ts",
    "content": "export const BREAKPOINT = 600;\nexport const MEDIA_DESKTOP_BREAKPOINT = `@media (min-width: ${BREAKPOINT}px)`;\nexport const MOBILE_TRANSITION_DURATION = 300;\n\n/** Minimum width in pixels for the main content area in the layout grid. */\nexport const MINIMUM_CONTENT_WIDTH_PX = 100;\n\n/**\n * Upper bound on the minimum width that browsers will enforce for the addon panel in its horizontal\n * layout. Use it to compute the max width of other items (e.g. sidebar).\n */\nexport const MINIMUM_HORIZONTAL_PANEL_WIDTH_PX = 360;\n\n/** Minimum height in pixels for the addon panel in the bottom position, beyond which it collapses. */\nexport const MINIMUM_HORIZONTAL_PANEL_HEIGHT_PX = 40;\n\n/** Minimum width in pixels for the sidebar, beyond which it collapses entirely. */\nexport const MINIMUM_SIDEBAR_WIDTH_PX = 240;\n\n/** Minimum width in pixels for the addon panel in the right position, beyond which it collapses. */\nexport const MINIMUM_RIGHT_PANEL_WIDTH_PX = 270;\n\n/**\n * Height in pixels of the toolbar in the main content area. Used to compute the maximum height of\n * the bottom panel so it does not push the toolbar out of view.\n */\nexport const TOOLBAR_HEIGHT_PX = 40;\n"
  },
  {
    "path": "code/core/src/manager/container/Menu.stories.tsx",
    "content": "import React from 'react';\n\nimport { Button, PopoverProvider, TooltipLinkList } from 'storybook/internal/components';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { action } from 'storybook/actions';\n\nimport { initialState } from '../../shared/checklist-store/checklistData.state.ts';\nimport { Shortcut } from '../components/Shortcut.tsx';\nimport { internal_universalChecklistStore as mockStore } from '../manager-stores.mock.ts';\n\nconst onLinkClick = action('onLinkClick');\n\nexport default {\n  component: TooltipLinkList,\n  decorators: [\n    (storyFn) => (\n      <div\n        style={{\n          height: '300px',\n        }}\n      >\n        <PopoverProvider\n          ariaLabel=\"Menu\"\n          placement=\"top\"\n          defaultVisible\n          padding={0}\n          popover={storyFn()}\n        >\n          <Button ariaLabel={false}>Click me</Button>\n        </PopoverProvider>\n      </div>\n    ),\n  ],\n  beforeEach: async () => {\n    mockStore.setState({\n      loaded: true,\n      widget: {},\n      items: {\n        ...initialState.items,\n        controls: { status: 'accepted' },\n        renderComponent: { status: 'done' },\n        viewports: { status: 'skipped' },\n      },\n    });\n  },\n  excludeStories: ['links'],\n} satisfies Meta<typeof TooltipLinkList>;\n\ntype Story = StoryObj<typeof TooltipLinkList>;\n\nexport const WithShortcuts = {\n  args: {\n    links: [\n      {\n        id: '1',\n        title: 'Link 1',\n        center: 'This is an addition description',\n        right: <Shortcut keys={['⌘']} />,\n        href: 'http://google.com',\n        onClick: onLinkClick,\n      },\n      {\n        id: '2',\n        title: 'Link 2',\n        center: 'This is an addition description',\n        right: <Shortcut keys={['⌘', 'K']} />,\n        href: 'http://google.com',\n        onClick: onLinkClick,\n      },\n    ],\n  },\n} satisfies Story;\n\nexport const WithShortcutsActive = {\n  args: {\n    links: [\n      {\n        id: '1',\n        title: 'Link 1',\n        center: 'This is an addition description',\n        active: true,\n        right: <Shortcut keys={['⌘']} />,\n        href: 'http://google.com',\n        onClick: onLinkClick,\n      },\n      {\n        id: '2',\n        title: 'Link 2',\n        center: 'This is an addition description',\n        right: <Shortcut keys={['⌘', 'K']} />,\n        href: 'http://google.com',\n        onClick: onLinkClick,\n      },\n    ],\n  },\n} satisfies Story;\n"
  },
  {
    "path": "code/core/src/manager/container/Menu.tsx",
    "content": "import React, { useCallback, useMemo } from 'react';\n\nimport { ActionList, ProgressSpinner } from 'storybook/internal/components';\nimport { STORIES_COLLAPSE_ALL } from 'storybook/internal/core-events';\n\nimport { global } from '@storybook/global';\nimport {\n  CheckIcon,\n  CommandIcon,\n  DocumentIcon,\n  InfoIcon,\n  ListUnorderedIcon,\n  ShareAltIcon,\n} from '@storybook/icons';\n\nimport type { API } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport type { NormalLink } from '../../components/components/tooltip/TooltipLinkList.tsx';\nimport { Shortcut } from '../components/Shortcut.tsx';\nimport { useChecklist } from '../components/sidebar/useChecklist.ts';\n\nexport type MenuItem = NormalLink & {\n  closeOnClick?: boolean;\n  internal?: boolean;\n};\n\nconst ProgressCircle = styled(ProgressSpinner)(({ theme }) => ({\n  color: theme.color.secondary,\n}));\n\nexport const useMenu = ({\n  api,\n  showToolbar,\n  isPanelShown,\n  isNavShown,\n  enableShortcuts,\n}: {\n  api: API;\n  showToolbar: boolean;\n  isPanelShown: boolean;\n  isNavShown: boolean;\n  enableShortcuts: boolean;\n}): MenuItem[][] => {\n  const shortcutKeys = api.getShortcutKeys();\n  const { progress } = useChecklist();\n\n  const about = useMemo(\n    () => ({\n      id: 'about',\n      title: 'About your Storybook',\n      onClick: () => api.changeSettingsTab('about'),\n      href: './?path=/settings/about',\n      internal: true,\n      closeOnClick: true,\n      icon: <InfoIcon />,\n    }),\n    [api]\n  );\n\n  const guide = useMemo(\n    () => ({\n      id: 'guide',\n      title: 'Onboarding guide',\n      onClick: () => api.changeSettingsTab('guide'),\n      href: './?path=/settings/guide',\n      internal: true,\n      closeOnClick: true,\n      icon: <ListUnorderedIcon />,\n      right: progress < 100 && (\n        <ActionList.Button as=\"div\" readOnly padding=\"none\" ariaLabel={`${progress}% completed`}>\n          <ProgressCircle percentage={progress} running={false} size={16} width={1.5} />\n          {progress}%\n        </ActionList.Button>\n      ),\n    }),\n    [api, progress]\n  );\n\n  const shortcuts = useMemo(\n    () => ({\n      id: 'shortcuts',\n      title: 'Keyboard shortcuts',\n      onClick: () => api.changeSettingsTab('shortcuts'),\n      href: './?path=/settings/shortcuts',\n      internal: true,\n      closeOnClick: true,\n      right: enableShortcuts ? <Shortcut keys={shortcutKeys.shortcutsPage} /> : null,\n      icon: <CommandIcon />,\n    }),\n    [api, enableShortcuts, shortcutKeys.shortcutsPage]\n  );\n\n  const sidebarToggle = useMemo(\n    () => ({\n      id: 'S',\n      title: 'Show sidebar',\n      onClick: () => api.toggleNav(),\n      closeOnClick: true,\n      active: isNavShown,\n      right: enableShortcuts ? <Shortcut keys={shortcutKeys.toggleNav} /> : null,\n      icon: isNavShown ? <CheckIcon /> : <></>,\n    }),\n    [api, enableShortcuts, shortcutKeys, isNavShown]\n  );\n\n  const toolbarToogle = useMemo(\n    () => ({\n      id: 'T',\n      title: 'Show toolbar',\n      onClick: () => api.toggleToolbar(),\n      active: showToolbar,\n      right: enableShortcuts ? <Shortcut keys={shortcutKeys.toolbar} /> : null,\n      icon: showToolbar ? <CheckIcon /> : <></>,\n    }),\n    [api, enableShortcuts, shortcutKeys, showToolbar]\n  );\n\n  const addonsToggle = useMemo(\n    () => ({\n      id: 'A',\n      title: 'Show addons panel',\n      onClick: () => api.togglePanel(),\n      active: isPanelShown,\n      right: enableShortcuts ? <Shortcut keys={shortcutKeys.togglePanel} /> : null,\n      icon: isPanelShown ? <CheckIcon /> : <></>,\n    }),\n    [api, enableShortcuts, shortcutKeys, isPanelShown]\n  );\n\n  const up = useMemo(\n    () => ({\n      id: 'up',\n      title: 'Previous component',\n      onClick: () => api.jumpToComponent(-1),\n      right: enableShortcuts ? <Shortcut keys={shortcutKeys.prevComponent} /> : null,\n      icon: <></>,\n    }),\n    [api, enableShortcuts, shortcutKeys]\n  );\n\n  const down = useMemo(\n    () => ({\n      id: 'down',\n      title: 'Next component',\n      onClick: () => api.jumpToComponent(1),\n      right: enableShortcuts ? <Shortcut keys={shortcutKeys.nextComponent} /> : null,\n      icon: <></>,\n    }),\n    [api, enableShortcuts, shortcutKeys]\n  );\n\n  const prev = useMemo(\n    () => ({\n      id: 'prev',\n      title: 'Previous story',\n      onClick: () => api.jumpToStory(-1),\n      right: enableShortcuts ? <Shortcut keys={shortcutKeys.prevStory} /> : null,\n      icon: <></>,\n    }),\n    [api, enableShortcuts, shortcutKeys]\n  );\n\n  const next = useMemo(\n    () => ({\n      id: 'next',\n      title: 'Next story',\n      onClick: () => api.jumpToStory(1),\n      right: enableShortcuts ? <Shortcut keys={shortcutKeys.nextStory} /> : null,\n      icon: <></>,\n    }),\n    [api, enableShortcuts, shortcutKeys]\n  );\n\n  const collapse = useMemo(\n    () => ({\n      id: 'collapse',\n      title: 'Collapse all',\n      onClick: () => api.emit(STORIES_COLLAPSE_ALL),\n      right: enableShortcuts ? <Shortcut keys={shortcutKeys.collapseAll} /> : null,\n      icon: <></>,\n    }),\n    [api, enableShortcuts, shortcutKeys]\n  );\n\n  const documentation = useMemo(() => {\n    const docsUrl = api.getDocsUrl({ versioned: true, renderer: true });\n\n    return {\n      id: 'documentation',\n      title: 'Documentation',\n      closeOnClick: true,\n      href: docsUrl,\n      right: (\n        <ActionList.Icon>\n          <ShareAltIcon />\n        </ActionList.Icon>\n      ),\n      icon: <DocumentIcon />,\n    };\n  }, [api]);\n\n  const getAddonsShortcuts = useCallback(() => {\n    const addonsShortcuts = api.getAddonsShortcuts();\n    const keys = shortcutKeys as any;\n    return Object.entries(addonsShortcuts)\n      .filter(([_, { showInMenu }]) => showInMenu)\n      .map(([actionName, { label, action }]) => ({\n        id: actionName,\n        title: label,\n        onClick: () => action(),\n        right: enableShortcuts ? <Shortcut keys={keys[actionName]} /> : null,\n      }));\n  }, [api, enableShortcuts, shortcutKeys]);\n\n  return useMemo(\n    () =>\n      [\n        [\n          about,\n          ...(global.CONFIG_TYPE === 'DEVELOPMENT' ? [guide] : []),\n          ...(enableShortcuts ? [shortcuts] : []),\n        ],\n        [sidebarToggle, toolbarToogle, addonsToggle, up, down, prev, next, collapse],\n        getAddonsShortcuts(),\n        [documentation],\n      ] satisfies NormalLink[][],\n    [\n      about,\n      guide,\n      documentation,\n      shortcuts,\n      sidebarToggle,\n      toolbarToogle,\n      addonsToggle,\n      up,\n      down,\n      prev,\n      next,\n      collapse,\n      getAddonsShortcuts,\n      enableShortcuts,\n    ]\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/container/Notifications.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport type { Combo } from 'storybook/manager-api';\nimport { Consumer } from 'storybook/manager-api';\n\nimport { NotificationList } from '../components/notifications/NotificationList.tsx';\n\nconst mapper = ({ state, api }: Combo) => {\n  return {\n    notifications: state.notifications,\n    clearNotification: api.clearNotification,\n  };\n};\n\nexport const Notifications: FC = (props) => (\n  <Consumer filter={mapper}>\n    {(fromState) => <NotificationList {...props} {...fromState} />}\n  </Consumer>\n);\n"
  },
  {
    "path": "code/core/src/manager/container/Panel.stories.tsx",
    "content": "import React from 'react';\n\nexport default {\n  title: 'Addon Panel',\n};\n\nexport const AllAddons = () => <div>By default all addon panels are rendered</div>;\n\n/*\nTODO: this story currently breaks the whole Storybook UI (including the manager).\nCurrent findings:\n- Only happens when actions below are disabled, not when a11y is.\n- Is related to panels and addon tabs.\n- Commenting out code/ui/components/src/tabs/tabs.tsx#L186 fixes the issue.\n- ... this line: {list.map(({ id, active, render }) => render({ key: id, active }))}\n- The error is most likely the shenanigans we do at code/ui/components/src/tabs/tabs.tsx#childrenToList\n\nexport const FilteredAddons = () => <div>By default all addon panels are rendered</div>;\nFilteredAddons.parameters = {\n  a11y: { disable: true },\n  actions: { disable: true },\n};\n*/\n"
  },
  {
    "path": "code/core/src/manager/container/Panel.tsx",
    "content": "import type { FC } from 'react';\nimport React, { useMemo, useState } from 'react';\n\nimport { Addon_TypesEnum } from 'storybook/internal/types';\n\nimport { useChannel, useStorybookApi, useStorybookState } from 'storybook/manager-api';\n\nimport { STORY_PREPARED } from '../../core-events/index.ts';\nimport { focusableUIElements } from '../../manager-api/modules/layout.ts';\nimport { AddonPanel } from '../components/panel/Panel.tsx';\n\nconst Panel: FC<any> = (props) => {\n  const api = useStorybookApi();\n  const state = useStorybookState();\n  const [story, setStory] = useState(api.getCurrentStoryData());\n\n  useChannel(\n    {\n      [STORY_PREPARED]: () => {\n        setStory(api.getCurrentStoryData());\n      },\n    },\n    []\n  );\n\n  const { parameters, type } = story ?? {};\n\n  const panelActions = useMemo(\n    () => ({\n      onSelect: (panel: string) => api.setSelectedPanel(panel),\n      toggleVisibility: async () => {\n        const wasPanelShown = api.getIsPanelShown();\n        api.togglePanel();\n        if (wasPanelShown) {\n          const success = await api.focusOnUIElement(focusableUIElements.showAddonPanel);\n          // Fallback to body for predictable behavior.\n          if (success === false) {\n            document.body.focus();\n          }\n        }\n      },\n      togglePosition: () => api.togglePanelPosition(),\n    }),\n    [api]\n  );\n\n  const panels = useMemo(() => {\n    const allPanels = api.getElements(Addon_TypesEnum.PANEL);\n\n    if (!allPanels || type !== 'story') {\n      return allPanels;\n    }\n\n    const filteredPanels: typeof allPanels = {};\n    Object.entries(allPanels).forEach(([id, p]) => {\n      const { paramKey }: any = p;\n      if (paramKey && parameters && parameters[paramKey] && parameters[paramKey].disable) {\n        return;\n      }\n      if (p.disabled === true || (typeof p.disabled === 'function' && p.disabled(parameters))) {\n        return;\n      }\n      filteredPanels[id] = p;\n    });\n\n    return filteredPanels;\n  }, [api, type, parameters]);\n\n  return (\n    <AddonPanel\n      panels={panels}\n      selectedPanel={api.getSelectedPanel()}\n      panelPosition={state.layout.panelPosition}\n      actions={panelActions}\n      shortcuts={api.getShortcutKeys()}\n      {...props}\n    />\n  );\n};\n\nexport default Panel;\n"
  },
  {
    "path": "code/core/src/manager/container/Preview.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React from 'react';\n\nimport type { Addon_BaseType, Addon_Collection, Addon_WrapperType } from 'storybook/internal/types';\nimport { Addon_TypesEnum } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport memoizerific from 'memoizerific';\nimport type { State, StoriesHash } from 'storybook/manager-api';\nimport { Consumer } from 'storybook/manager-api';\n\nimport { Preview, createCanvasTab, filterTabs } from '../components/preview/Preview.tsx';\nimport { filterToolsSide, fullScreenTool } from '../components/preview/Toolbar.tsx';\nimport { defaultWrappers } from '../components/preview/Wrappers.tsx';\nimport { addonsTool } from '../components/preview/tools/addons.tsx';\nimport { menuTool } from '../components/preview/tools/menu.tsx';\nimport { openInEditorTool } from '../components/preview/tools/open-in-editor.tsx';\nimport { remountTool } from '../components/preview/tools/remount.tsx';\nimport { shareTool } from '../components/preview/tools/share.tsx';\nimport { zoomTool } from '../components/preview/tools/zoom.tsx';\nimport type { PreviewProps } from '../components/preview/utils/types.tsx';\n\nconst defaultTabs = [createCanvasTab()];\nconst defaultTools = [menuTool, remountTool];\nconst defaultToolsExtra = [zoomTool, addonsTool, fullScreenTool, shareTool, openInEditorTool];\n\nconst emptyTabsList: Addon_BaseType[] = [];\n\ntype FilterProps = [\n  entry: PreviewProps['entry'],\n  viewMode: State['viewMode'],\n  location: State['location'],\n  path: State['path'],\n  tabId: string,\n];\n\n// memoization to return the same array every time, unless something relevant changes\nconst memoizedTabs = memoizerific(1)(\n  (\n    _,\n    tabElements: Addon_Collection<Addon_BaseType>,\n    parameters: Record<string, any> | undefined,\n    showTabs: boolean\n  ) =>\n    showTabs\n      ? filterTabs([...defaultTabs, ...Object.values(tabElements)], parameters)\n      : emptyTabsList\n);\nconst memoizedTools = memoizerific(1)(\n  (_, toolElements: Addon_Collection<Addon_BaseType>, filterProps: FilterProps) =>\n    filterToolsSide([...defaultTools, ...Object.values(toolElements)], ...filterProps)\n);\nconst memoizedExtra = memoizerific(1)(\n  (_, extraElements: Addon_Collection<Addon_BaseType>, filterProps: FilterProps) =>\n    filterToolsSide([...defaultToolsExtra, ...Object.values(extraElements)], ...filterProps)\n);\n\nconst memoizedWrapper = memoizerific(1)((_, previewElements: Addon_Collection) => [\n  ...defaultWrappers,\n  ...Object.values(previewElements),\n]);\n\nconst { PREVIEW_URL } = global;\n\nexport type Item = StoriesHash[keyof StoriesHash];\n\nconst splitTitleAddExtraSpace = (input: string) =>\n  input.split('/').join(' / ').replace(/\\s\\s/, ' ');\n\nconst getDescription = (item: Item) => {\n  if (item?.type === 'story' || item?.type === 'docs') {\n    const { title, name } = item;\n    return title && name ? splitTitleAddExtraSpace(`${title} - ${name} ⋅ Storybook`) : 'Storybook';\n  }\n\n  return item?.name ? `${item.name} ⋅ Storybook` : 'Storybook';\n};\n\nconst mapper = ({\n  api,\n  state,\n  // @ts-expect-error (non strict)\n}: Parameters<ComponentProps<typeof Consumer>['filter']>[0]): Omit<\n  ComponentProps<typeof Preview>,\n  'withLoader' | 'id'\n> => {\n  const { layout, location, customQueryParams, storyId, refs, viewMode, path, refId } = state;\n  const entry = api.getData(storyId, refId);\n\n  const tabsList = Object.values(api.getElements(Addon_TypesEnum.TAB));\n  const wrapperList = Object.values(api.getElements(Addon_TypesEnum.PREVIEW));\n  const toolsList = Object.values(api.getElements(Addon_TypesEnum.TOOL));\n  const toolsExtraList = Object.values(api.getElements(Addon_TypesEnum.TOOLEXTRA));\n\n  const tabId = api.getQueryParam('tab');\n\n  const tools = memoizedTools(toolsList.length, api.getElements(Addon_TypesEnum.TOOL), [\n    entry,\n    viewMode,\n    location,\n    path,\n    // @ts-expect-error (non strict)\n    tabId,\n  ]) as Addon_BaseType[];\n  const toolsExtra = memoizedExtra(\n    toolsExtraList.length,\n    api.getElements(Addon_TypesEnum.TOOLEXTRA),\n    // @ts-expect-error (non strict)\n    [entry, viewMode, location, path, tabId]\n  ) as Addon_BaseType[];\n\n  return {\n    api,\n    entry,\n    options: layout,\n    description: getDescription(entry),\n    viewMode,\n    refs,\n    storyId,\n    baseUrl: PREVIEW_URL || 'iframe.html',\n    queryParams: customQueryParams,\n    tools: tools,\n    toolsExtra: toolsExtra,\n    tabs: memoizedTabs(\n      tabsList.length,\n      api.getElements(Addon_TypesEnum.TAB),\n      entry ? entry.parameters : undefined,\n      layout.showTabs\n    ) as Addon_BaseType[],\n    wrappers: memoizedWrapper(\n      wrapperList.length,\n      api.getElements(Addon_TypesEnum.PREVIEW)\n    ) as Addon_WrapperType[],\n    tabId: tabId,\n  };\n};\n\nconst PreviewConnected = React.memo(function PreviewConnected(props: {\n  id: string;\n  withLoader: boolean;\n}) {\n  return (\n    <Consumer filter={mapper}>{(fromState) => <Preview {...props} {...fromState} />}</Consumer>\n  );\n});\n\nexport default PreviewConnected;\n"
  },
  {
    "path": "code/core/src/manager/container/Sidebar.tsx",
    "content": "import React from 'react';\n\nimport type { Combo, StoriesHash } from 'storybook/manager-api';\nimport { Consumer, experimental_useStatusStore } from 'storybook/manager-api';\n\nimport type { SidebarProps as SidebarComponentProps } from '../components/sidebar/Sidebar.tsx';\nimport { Sidebar as SidebarComponent } from '../components/sidebar/Sidebar.tsx';\nimport { useMenu } from './Menu.tsx';\n\nexport type Item = StoriesHash[keyof StoriesHash];\n\ninterface SidebarProps {\n  onMenuClick?: SidebarComponentProps['onMenuClick'];\n}\n\nconst Sidebar = React.memo(function Sideber({ onMenuClick }: SidebarProps) {\n  const mapper = ({ state, api }: Combo) => {\n    const {\n      ui: { name, url, enableShortcuts },\n      viewMode,\n      storyId,\n      refId,\n      layout: { showToolbar },\n      // FIXME: This is the actual `index.json` index where the `index` below\n      // is actually the stories hash. We should fix this up and make it consistent.\n      internal_index,\n      filteredIndex: index,\n      indexError,\n      previewInitialized,\n      refs,\n    } = state;\n\n    const whatsNewNotificationsEnabled =\n      state.whatsNewData?.status === 'SUCCESS' && !state.disableWhatsNewNotifications;\n\n    return {\n      api,\n      title: name,\n      url,\n      indexJson: internal_index,\n      index,\n      indexError,\n      previewInitialized,\n      refs,\n      storyId,\n      refId,\n      viewMode,\n      showToolbar,\n      isPanelShown: api.getIsPanelShown(),\n      isNavShown: api.getIsNavShown(),\n      menuHighlighted: whatsNewNotificationsEnabled && api.isWhatsNewUnread(),\n      enableShortcuts,\n    };\n  };\n\n  return (\n    <Consumer filter={mapper}>\n      {({ api, showToolbar, isPanelShown, isNavShown, enableShortcuts, ...state }) => {\n        const menu = useMenu({ api, showToolbar, isPanelShown, isNavShown, enableShortcuts });\n        const allStatuses = experimental_useStatusStore();\n\n        return (\n          <SidebarComponent\n            {...state}\n            menu={menu}\n            onMenuClick={onMenuClick}\n            allStatuses={allStatuses}\n            enableShortcuts={enableShortcuts}\n          />\n        );\n      }}\n    </Consumer>\n  );\n});\n\nexport default Sidebar;\n"
  },
  {
    "path": "code/core/src/manager/globals/exports.ts",
    "content": "// this file is generated by sourcefiles.ts\n// this is done to prevent runtime dependencies from making it's way into the build/start script of the manager\n// the manager builder needs to know which dependencies are 'globalized' in the ui\n\nexport default {\n  react: [\n    'Children',\n    'Component',\n    'Fragment',\n    'Profiler',\n    'PureComponent',\n    'StrictMode',\n    'Suspense',\n    '__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED',\n    'act',\n    'cloneElement',\n    'createContext',\n    'createElement',\n    'createFactory',\n    'createRef',\n    'forwardRef',\n    'isValidElement',\n    'lazy',\n    'memo',\n    'startTransition',\n    'unstable_act',\n    'useCallback',\n    'useContext',\n    'useDebugValue',\n    'useDeferredValue',\n    'useEffect',\n    'useId',\n    'useImperativeHandle',\n    'useInsertionEffect',\n    'useLayoutEffect',\n    'useMemo',\n    'useReducer',\n    'useRef',\n    'useState',\n    'useSyncExternalStore',\n    'useTransition',\n    'version',\n  ],\n  'react-dom': [\n    '__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED',\n    'createPortal',\n    'createRoot',\n    'findDOMNode',\n    'flushSync',\n    'hydrate',\n    'hydrateRoot',\n    'render',\n    'unmountComponentAtNode',\n    'unstable_batchedUpdates',\n    'unstable_renderSubtreeIntoContainer',\n    'version',\n  ],\n  'react-dom/client': ['createRoot', 'hydrateRoot'],\n  '@storybook/icons': [\n    'AccessibilityAltIcon',\n    'AccessibilityIcon',\n    'AccessibilityIgnoredIcon',\n    'AddIcon',\n    'AdminIcon',\n    'AlertAltIcon',\n    'AlertIcon',\n    'AlignLeftIcon',\n    'AlignRightIcon',\n    'AppleIcon',\n    'ArrowBottomLeftIcon',\n    'ArrowBottomRightIcon',\n    'ArrowDownIcon',\n    'ArrowLeftIcon',\n    'ArrowRightIcon',\n    'ArrowSolidDownIcon',\n    'ArrowSolidLeftIcon',\n    'ArrowSolidRightIcon',\n    'ArrowSolidUpIcon',\n    'ArrowTopLeftIcon',\n    'ArrowTopRightIcon',\n    'ArrowUpIcon',\n    'AzureDevOpsIcon',\n    'BackIcon',\n    'BasketIcon',\n    'BatchAcceptIcon',\n    'BatchDenyIcon',\n    'BeakerIcon',\n    'BellIcon',\n    'BitbucketIcon',\n    'BoldIcon',\n    'BookIcon',\n    'BookmarkHollowIcon',\n    'BookmarkIcon',\n    'BottomBarIcon',\n    'BottomBarToggleIcon',\n    'BoxIcon',\n    'BranchIcon',\n    'BrowserIcon',\n    'BugIcon',\n    'ButtonIcon',\n    'CPUIcon',\n    'CalendarIcon',\n    'CameraIcon',\n    'CameraStabilizeIcon',\n    'CategoryIcon',\n    'CertificateIcon',\n    'ChangedIcon',\n    'ChatIcon',\n    'CheckIcon',\n    'ChevronDownIcon',\n    'ChevronLeftIcon',\n    'ChevronRightIcon',\n    'ChevronSmallDownIcon',\n    'ChevronSmallLeftIcon',\n    'ChevronSmallRightIcon',\n    'ChevronSmallUpIcon',\n    'ChevronUpIcon',\n    'ChromaticIcon',\n    'ChromeIcon',\n    'CircleHollowIcon',\n    'CircleIcon',\n    'ClearIcon',\n    'CloseAltIcon',\n    'CloseIcon',\n    'CloudHollowIcon',\n    'CloudIcon',\n    'CogIcon',\n    'CollapseIcon',\n    'CommandIcon',\n    'CommentAddIcon',\n    'CommentIcon',\n    'CommentsIcon',\n    'CommitIcon',\n    'CompassIcon',\n    'ComponentDrivenIcon',\n    'ComponentIcon',\n    'ContrastIcon',\n    'ContrastIgnoredIcon',\n    'ControlsIcon',\n    'CopyIcon',\n    'CreditIcon',\n    'CrossIcon',\n    'DashboardIcon',\n    'DatabaseIcon',\n    'DeleteIcon',\n    'DiamondIcon',\n    'DirectionIcon',\n    'DiscordIcon',\n    'DocChartIcon',\n    'DocListIcon',\n    'DocumentIcon',\n    'DownloadIcon',\n    'DragIcon',\n    'EditIcon',\n    'EditorIcon',\n    'EllipsisIcon',\n    'EmailIcon',\n    'ExpandAltIcon',\n    'ExpandIcon',\n    'EyeCloseIcon',\n    'EyeIcon',\n    'FaceHappyIcon',\n    'FaceNeutralIcon',\n    'FaceSadIcon',\n    'FacebookIcon',\n    'FailedIcon',\n    'FastForwardIcon',\n    'FigmaIcon',\n    'FilterIcon',\n    'FlagIcon',\n    'FolderIcon',\n    'FormIcon',\n    'GDriveIcon',\n    'GiftIcon',\n    'GithubIcon',\n    'GitlabIcon',\n    'GlobeIcon',\n    'GoogleIcon',\n    'GraphBarIcon',\n    'GraphLineIcon',\n    'GraphqlIcon',\n    'GridAltIcon',\n    'GridIcon',\n    'GrowIcon',\n    'HeartHollowIcon',\n    'HeartIcon',\n    'HomeIcon',\n    'HourglassIcon',\n    'InfoIcon',\n    'ItalicIcon',\n    'JumpToIcon',\n    'KeyIcon',\n    'LightningIcon',\n    'LightningOffIcon',\n    'LinkBrokenIcon',\n    'LinkIcon',\n    'LinkedinIcon',\n    'LinuxIcon',\n    'ListOrderedIcon',\n    'ListUnorderedIcon',\n    'LocationIcon',\n    'LockIcon',\n    'MarkdownIcon',\n    'MarkupIcon',\n    'MediumIcon',\n    'MemoryIcon',\n    'MenuIcon',\n    'MergeIcon',\n    'MirrorIcon',\n    'MobileIcon',\n    'MoonIcon',\n    'NutIcon',\n    'OutboxIcon',\n    'OutlineIcon',\n    'PaintBrushAltIcon',\n    'PaintBrushIcon',\n    'PaperClipIcon',\n    'ParagraphIcon',\n    'PassedIcon',\n    'PhoneIcon',\n    'PhotoDragIcon',\n    'PhotoIcon',\n    'PhotoStabilizeIcon',\n    'PinAltIcon',\n    'PinIcon',\n    'PlayAllHollowIcon',\n    'PlayBackIcon',\n    'PlayHollowIcon',\n    'PlayIcon',\n    'PlayNextIcon',\n    'PlusIcon',\n    'PointerDefaultIcon',\n    'PointerHandIcon',\n    'PowerIcon',\n    'PrintIcon',\n    'ProceedIcon',\n    'ProfileIcon',\n    'PullRequestIcon',\n    'QuestionIcon',\n    'RSSIcon',\n    'RedirectIcon',\n    'ReduxIcon',\n    'RefreshIcon',\n    'ReplyIcon',\n    'RepoIcon',\n    'RequestChangeIcon',\n    'RewindIcon',\n    'RulerIcon',\n    'SaveIcon',\n    'SearchIcon',\n    'ShareAltIcon',\n    'ShareIcon',\n    'ShieldIcon',\n    'SideBySideIcon',\n    'SidebarAltIcon',\n    'SidebarAltToggleIcon',\n    'SidebarIcon',\n    'SidebarToggleIcon',\n    'SortDownIcon',\n    'SortUpIcon',\n    'SpeakerIcon',\n    'StackedIcon',\n    'StarHollowIcon',\n    'StarIcon',\n    'StatusFailIcon',\n    'StatusIcon',\n    'StatusPassIcon',\n    'StatusWarnIcon',\n    'StickerIcon',\n    'StopAltHollowIcon',\n    'StopAltIcon',\n    'StopIcon',\n    'StorybookIcon',\n    'StructureIcon',\n    'SubtractIcon',\n    'SunIcon',\n    'SupportIcon',\n    'SweepIcon',\n    'SwitchAltIcon',\n    'SyncIcon',\n    'TabletIcon',\n    'ThumbsUpIcon',\n    'TimeIcon',\n    'TimerIcon',\n    'TransferIcon',\n    'TrashIcon',\n    'TwitterIcon',\n    'TypeIcon',\n    'UbuntuIcon',\n    'UndoIcon',\n    'UnfoldIcon',\n    'UnlockIcon',\n    'UnpinIcon',\n    'UploadIcon',\n    'UserAddIcon',\n    'UserAltIcon',\n    'UserIcon',\n    'UsersIcon',\n    'VSCodeIcon',\n    'VerifiedIcon',\n    'VideoIcon',\n    'WandIcon',\n    'WatchIcon',\n    'WindowsIcon',\n    'WrenchIcon',\n    'XIcon',\n    'YoutubeIcon',\n    'ZoomIcon',\n    'ZoomOutIcon',\n    'ZoomResetIcon',\n    'iconList',\n  ],\n  'storybook/manager-api': [\n    'ActiveTabs',\n    'Consumer',\n    'ManagerContext',\n    'Provider',\n    'RequestResponseError',\n    'Tag',\n    'addons',\n    'combineParameters',\n    'controlOrMetaKey',\n    'controlOrMetaSymbol',\n    'eventMatchesShortcut',\n    'eventToShortcut',\n    'experimental_MockUniversalStore',\n    'experimental_UniversalStore',\n    'experimental_getStatusStore',\n    'experimental_getTestProviderStore',\n    'experimental_requestResponse',\n    'experimental_useStatusStore',\n    'experimental_useTestProviderStore',\n    'experimental_useUniversalStore',\n    'internal_checklistStore',\n    'internal_fullStatusStore',\n    'internal_fullTestProviderStore',\n    'internal_universalChecklistStore',\n    'internal_universalStatusStore',\n    'internal_universalTestProviderStore',\n    'isMacLike',\n    'isShortcutTaken',\n    'keyToSymbol',\n    'merge',\n    'mockChannel',\n    'optionOrAltSymbol',\n    'shortcutMatchesShortcut',\n    'shortcutToAriaKeyshortcuts',\n    'shortcutToHumanString',\n    'types',\n    'useAddonState',\n    'useArgTypes',\n    'useArgs',\n    'useChannel',\n    'useGlobalTypes',\n    'useGlobals',\n    'useParameter',\n    'useSharedState',\n    'useStoryPrepared',\n    'useStorybookApi',\n    'useStorybookState',\n  ],\n  'storybook/theming': [\n    'CacheProvider',\n    'ClassNames',\n    'Global',\n    'ThemeProvider',\n    'background',\n    'color',\n    'convert',\n    'create',\n    'createCache',\n    'createGlobal',\n    'createReset',\n    'css',\n    'darken',\n    'ensure',\n    'getPreferredColorScheme',\n    'ignoreSsrWarning',\n    'isPropValid',\n    'jsx',\n    'keyframes',\n    'lighten',\n    'srOnlyStyles',\n    'styled',\n    'themes',\n    'tokens',\n    'typography',\n    'useTheme',\n    'withTheme',\n  ],\n  'storybook/theming/create': ['create', 'themes'],\n  'storybook/test': [\n    'buildQueries',\n    'clearAllMocks',\n    'configure',\n    'createEvent',\n    'expect',\n    'findAllByAltText',\n    'findAllByDisplayValue',\n    'findAllByLabelText',\n    'findAllByPlaceholderText',\n    'findAllByRole',\n    'findAllByTestId',\n    'findAllByText',\n    'findAllByTitle',\n    'findByAltText',\n    'findByDisplayValue',\n    'findByLabelText',\n    'findByPlaceholderText',\n    'findByRole',\n    'findByTestId',\n    'findByText',\n    'findByTitle',\n    'fireEvent',\n    'fn',\n    'getAllByAltText',\n    'getAllByDisplayValue',\n    'getAllByLabelText',\n    'getAllByPlaceholderText',\n    'getAllByRole',\n    'getAllByTestId',\n    'getAllByText',\n    'getAllByTitle',\n    'getByAltText',\n    'getByDisplayValue',\n    'getByLabelText',\n    'getByPlaceholderText',\n    'getByRole',\n    'getByTestId',\n    'getByText',\n    'getByTitle',\n    'getConfig',\n    'getDefaultNormalizer',\n    'getElementError',\n    'getNodeText',\n    'getQueriesForElement',\n    'getRoles',\n    'getSuggestedQuery',\n    'isInaccessible',\n    'isMockFunction',\n    'logDOM',\n    'logRoles',\n    'mocked',\n    'mocks',\n    'onMockCall',\n    'prettyDOM',\n    'prettyFormat',\n    'queries',\n    'queryAllByAltText',\n    'queryAllByAttribute',\n    'queryAllByDisplayValue',\n    'queryAllByLabelText',\n    'queryAllByPlaceholderText',\n    'queryAllByRole',\n    'queryAllByTestId',\n    'queryAllByText',\n    'queryAllByTitle',\n    'queryByAltText',\n    'queryByAttribute',\n    'queryByDisplayValue',\n    'queryByLabelText',\n    'queryByPlaceholderText',\n    'queryByRole',\n    'queryByTestId',\n    'queryByText',\n    'queryByTitle',\n    'queryHelpers',\n    'resetAllMocks',\n    'restoreAllMocks',\n    'sb',\n    'screen',\n    'spyOn',\n    'uninstrumentedUserEvent',\n    'userEvent',\n    'waitFor',\n    'waitForElementToBeRemoved',\n    'within',\n  ],\n  'storybook/internal/channels': [\n    'Channel',\n    'HEARTBEAT_INTERVAL',\n    'HEARTBEAT_MAX_LATENCY',\n    'PostMessageTransport',\n    'WebsocketTransport',\n    'createBrowserChannel',\n  ],\n  'storybook/internal/client-logger': ['deprecate', 'logger', 'once', 'pretty'],\n  'storybook/internal/components': [\n    'A',\n    'AbstractToolbar',\n    'ActionBar',\n    'ActionList',\n    'AddonPanel',\n    'Badge',\n    'Bar',\n    'Blockquote',\n    'Button',\n    'Card',\n    'ClipboardCode',\n    'Code',\n    'Collapsible',\n    'DL',\n    'Div',\n    'DocumentWrapper',\n    'EmptyTabContent',\n    'ErrorFormatter',\n    'FlexBar',\n    'Form',\n    'H1',\n    'H2',\n    'H3',\n    'H4',\n    'H5',\n    'H6',\n    'HR',\n    'IconButton',\n    'Img',\n    'LI',\n    'Link',\n    'ListItem',\n    'Loader',\n    'Modal',\n    'ModalDecorator',\n    'OL',\n    'P',\n    'Placeholder',\n    'Popover',\n    'PopoverProvider',\n    'Pre',\n    'ProgressSpinner',\n    'ResetWrapper',\n    'ScrollArea',\n    'Select',\n    'Separator',\n    'Spaced',\n    'Span',\n    'StatelessTab',\n    'StatelessTabList',\n    'StatelessTabPanel',\n    'StatelessTabsView',\n    'StorybookIcon',\n    'StorybookLogo',\n    'SyntaxHighlighter',\n    'TT',\n    'TabBar',\n    'TabButton',\n    'TabList',\n    'TabPanel',\n    'TabWrapper',\n    'Table',\n    'Tabs',\n    'TabsState',\n    'TabsView',\n    'ToggleButton',\n    'Toolbar',\n    'Tooltip',\n    'TooltipLinkList',\n    'TooltipMessage',\n    'TooltipNote',\n    'TooltipProvider',\n    'UL',\n    'WithTooltip',\n    'WithTooltipPure',\n    'Zoom',\n    'codeCommon',\n    'components',\n    'convertToReactAriaPlacement',\n    'createCopyToClipboardFunction',\n    'getStoryHref',\n    'interleaveSeparators',\n    'nameSpaceClassNames',\n    'resetComponents',\n    'useTabsState',\n    'withReset',\n  ],\n  'storybook/internal/core-events': [\n    'ARGTYPES_INFO_REQUEST',\n    'ARGTYPES_INFO_RESPONSE',\n    'CHANNEL_CREATED',\n    'CHANNEL_WS_DISCONNECT',\n    'CONFIG_ERROR',\n    'CREATE_NEW_STORYFILE_REQUEST',\n    'CREATE_NEW_STORYFILE_RESPONSE',\n    'CURRENT_STORY_WAS_SET',\n    'DOCS_PREPARED',\n    'DOCS_RENDERED',\n    'FILE_COMPONENT_SEARCH_REQUEST',\n    'FILE_COMPONENT_SEARCH_RESPONSE',\n    'FORCE_REMOUNT',\n    'FORCE_RE_RENDER',\n    'GHOST_STORIES_REQUEST',\n    'GHOST_STORIES_RESPONSE',\n    'GLOBALS_UPDATED',\n    'MANAGER_INERT_ATTRIBUTE_CHANGED',\n    'NAVIGATE_URL',\n    'OPEN_IN_EDITOR_REQUEST',\n    'OPEN_IN_EDITOR_RESPONSE',\n    'PLAY_FUNCTION_THREW_EXCEPTION',\n    'PRELOAD_ENTRIES',\n    'PREVIEW_BUILDER_PROGRESS',\n    'PREVIEW_INITIALIZED',\n    'PREVIEW_KEYDOWN',\n    'REGISTER_SUBSCRIPTION',\n    'REQUEST_WHATS_NEW_DATA',\n    'RESET_STORY_ARGS',\n    'RESULT_WHATS_NEW_DATA',\n    'SAVE_STORY_REQUEST',\n    'SAVE_STORY_RESPONSE',\n    'SELECT_STORY',\n    'SET_CONFIG',\n    'SET_CURRENT_STORY',\n    'SET_FILTER',\n    'SET_GLOBALS',\n    'SET_INDEX',\n    'SET_STORIES',\n    'SET_WHATS_NEW_CACHE',\n    'SHARED_STATE_CHANGED',\n    'SHARED_STATE_SET',\n    'SHARE_ISOLATE_MODE',\n    'SHARE_POPOVER_OPENED',\n    'SHARE_STORY_LINK',\n    'STORIES_COLLAPSE_ALL',\n    'STORIES_EXPAND_ALL',\n    'STORY_ARGS_UPDATED',\n    'STORY_CHANGED',\n    'STORY_ERRORED',\n    'STORY_FINISHED',\n    'STORY_HOT_UPDATED',\n    'STORY_INDEX_INVALIDATED',\n    'STORY_MISSING',\n    'STORY_PREPARED',\n    'STORY_RENDERED',\n    'STORY_RENDER_PHASE_CHANGED',\n    'STORY_SPECIFIED',\n    'STORY_THREW_EXCEPTION',\n    'STORY_UNCHANGED',\n    'TELEMETRY_ERROR',\n    'TOGGLE_WHATS_NEW_NOTIFICATIONS',\n    'UNHANDLED_ERRORS_WHILE_PLAYING',\n    'UPDATE_GLOBALS',\n    'UPDATE_QUERY_PARAMS',\n    'UPDATE_STORY_ARGS',\n  ],\n  'storybook/internal/manager-errors': [\n    'Category',\n    'ProviderDoesNotExtendBaseProviderError',\n    'StatusTypeIdMismatchError',\n    'UncaughtManagerError',\n  ],\n  'storybook/internal/router': [\n    'BaseLocationProvider',\n    'DEEPLY_EQUAL',\n    'Link',\n    'Location',\n    'LocationProvider',\n    'Match',\n    'MemoryRouter',\n    'Route',\n    'buildArgsParam',\n    'deepDiff',\n    'getMatch',\n    'parsePath',\n    'queryFromLocation',\n    'stringifyQuery',\n    'useNavigate',\n  ],\n  'storybook/internal/types': [\n    'Addon_TypesEnum',\n    'CHANGE_DETECTION_STATUS_TYPE_ID',\n    'CoreWebpackCompiler',\n    'Feature',\n    'SupportedBuilder',\n    'SupportedFramework',\n    'SupportedLanguage',\n    'SupportedRenderer',\n  ],\n} as const;\n"
  },
  {
    "path": "code/core/src/manager/globals/globals-module-info.ts",
    "content": "import type { ModuleInfo } from '@fal-works/esbuild-plugin-global-externals';\n\nimport Exports from './exports.ts';\nimport { globalPackages, globalsNameReferenceMap } from './globals.ts';\n\n/*\n * We create a map of a module's name to a ModuleInfo.\n * Which is a config object for a esbuild-plugin, to swap a import of a module to a reference of a global variable.\n * To get this plugin to do the best job it can, it needs to know all the exports in the ModuleInfo config object.\n * We generate this information via a script into `exports.ts`.\n *\n * It's really important that there are no actual to the runtime of the modules, hence the cumbersome generation.\n * But we also want to ensure we don't miss any exports, or globals.\n *\n * So in order to add additional modules to be swapped for globals, you need to add them to:\n * - `Keys` in `types.ts`\n * - `values` in `runtime.ts`.\n *\n * If you forget to do either, TypeScript will complain.\n *\n * This `globals-module-info.ts` file is consumed by the `builder-manager` package,\n * The `runtime.ts` file is used inside the manager's browser code runtime.\n */\n\nconst duplicatedKeys = [\n  'storybook/theming',\n  'storybook/theming/create',\n  'storybook/manager-api',\n  'storybook/test',\n  'storybook/actions',\n  'storybook/highlight',\n  'storybook/viewport',\n];\n\nexport const globalsModuleInfoMap = globalPackages.reduce(\n  (acc, key) => {\n    acc[key] = {\n      type: 'esm',\n      varName: globalsNameReferenceMap[key],\n      namedExports: Exports[key],\n      defaultExport: true,\n    };\n\n    if (duplicatedKeys.includes(key)) {\n      acc[key.replace('storybook', 'storybook/internal') as typeof key] = {\n        type: 'esm',\n        varName: globalsNameReferenceMap[key],\n        namedExports: Exports[key],\n        defaultExport: true,\n      };\n    }\n    return acc;\n  },\n  {} as Required<Record<keyof typeof globalsNameReferenceMap, Required<ModuleInfo>>>\n);\n"
  },
  {
    "path": "code/core/src/manager/globals/globals.ts",
    "content": "// Here we map the name of a module to their REFERENCE in the global scope.\nexport const globalsNameReferenceMap = {\n  react: '__REACT__',\n  'react-dom': '__REACT_DOM__',\n  'react-dom/client': '__REACT_DOM_CLIENT__',\n  '@storybook/icons': '__STORYBOOK_ICONS__',\n\n  'storybook/manager-api': '__STORYBOOK_API__',\n\n  'storybook/test': '__STORYBOOK_TEST__',\n\n  'storybook/theming': '__STORYBOOK_THEMING__',\n  'storybook/theming/create': '__STORYBOOK_THEMING_CREATE__',\n\n  'storybook/internal/channels': '__STORYBOOK_CHANNELS__',\n  'storybook/internal/client-logger': '__STORYBOOK_CLIENT_LOGGER__',\n  'storybook/internal/components': '__STORYBOOK_COMPONENTS__',\n  'storybook/internal/core-events': '__STORYBOOK_CORE_EVENTS__',\n  'storybook/internal/manager-errors': '__STORYBOOK_CORE_EVENTS_MANAGER_ERRORS__',\n  'storybook/internal/router': '__STORYBOOK_ROUTER__',\n  'storybook/internal/types': '__STORYBOOK_TYPES__',\n} as const;\n\nexport const globalPackages = Object.keys(globalsNameReferenceMap) as Array<\n  keyof typeof globalsNameReferenceMap\n>;\n"
  },
  {
    "path": "code/core/src/manager/globals/runtime.ts",
    "content": "import * as REACT from 'react';\nimport * as REACT_DOM from 'react-dom';\nimport * as REACT_DOM_CLIENT from 'react-dom/client';\n\nimport * as CHANNELS from 'storybook/internal/channels';\nimport * as CLIENT_LOGGER from 'storybook/internal/client-logger';\nimport * as COMPONENTS from 'storybook/internal/components';\nimport * as EVENTS from 'storybook/internal/core-events';\nimport * as EVENTS_MANAGER_ERRORS from 'storybook/internal/manager-errors';\nimport * as ROUTER from 'storybook/internal/router';\nimport * as TYPES from 'storybook/internal/types';\n\nimport * as ICONS from '@storybook/icons';\n\nimport * as MANAGER_API from 'storybook/manager-api';\nimport * as TEST from 'storybook/test';\nimport * as THEMING from 'storybook/theming';\nimport * as THEMINGCREATE from 'storybook/theming/create';\n\nimport type { globalsNameReferenceMap } from './globals.ts';\n\n// Here we map the name of a module to their VALUE in the global scope.\nexport const globalsNameValueMap: Required<Record<keyof typeof globalsNameReferenceMap, any>> = {\n  react: REACT,\n  'react-dom': REACT_DOM,\n  'react-dom/client': REACT_DOM_CLIENT,\n  '@storybook/icons': ICONS,\n\n  'storybook/manager-api': MANAGER_API,\n\n  'storybook/theming': THEMING,\n  'storybook/theming/create': THEMINGCREATE,\n\n  'storybook/test': TEST,\n\n  'storybook/internal/channels': CHANNELS,\n  'storybook/internal/client-logger': CLIENT_LOGGER,\n  'storybook/internal/components': COMPONENTS,\n  'storybook/internal/core-events': EVENTS,\n  'storybook/internal/manager-errors': EVENTS_MANAGER_ERRORS,\n  'storybook/internal/router': ROUTER,\n  'storybook/internal/types': TYPES,\n};\n"
  },
  {
    "path": "code/core/src/manager/globals-runtime.ts",
    "content": "/// <reference path=\"./typings.d.ts\" />\nimport { TELEMETRY_ERROR } from 'storybook/internal/core-events';\n\nimport { globalPackages, globalsNameReferenceMap } from './globals/globals.ts';\nimport { globalsNameValueMap } from './globals/runtime.ts';\nimport { prepareForTelemetry, shouldSkipError } from './utils/prepareForTelemetry.ts';\n\n// Apply all the globals\nglobalPackages.forEach((key) => {\n  globalThis[globalsNameReferenceMap[key]] = globalsNameValueMap[key];\n});\n\nconst queuedErrors: Error[] = [];\n\nglobalThis.sendTelemetryError = (error) => {\n  if (shouldSkipError(error)) {\n    return;\n  }\n\n  const channel = globalThis.__STORYBOOK_ADDONS_CHANNEL__;\n  const preparedError = prepareForTelemetry(error);\n\n  if (!channel) {\n    queuedErrors.push(preparedError);\n    return;\n  }\n\n  // Flush any queued errors first\n  while (queuedErrors.length > 0) {\n    const queuedError = queuedErrors.shift();\n    channel.emit(TELEMETRY_ERROR, queuedError);\n  }\n\n  channel.emit(TELEMETRY_ERROR, preparedError);\n};\n\n// handle all uncaught errors at the root of the application and log to telemetry\nglobalThis.addEventListener('error', (args) => {\n  const error = args.error || args;\n  globalThis.sendTelemetryError(error);\n});\n\nglobalThis.addEventListener('unhandledrejection', ({ reason }) => {\n  globalThis.sendTelemetryError(reason);\n});\n"
  },
  {
    "path": "code/core/src/manager/globals.ts",
    "content": "export * from './globals/globals.ts';\n"
  },
  {
    "path": "code/core/src/manager/hooks/useDebounce.ts",
    "content": "import { useEffect, useState } from 'react';\n\nexport function useDebounce<T>(value: T, delay: number): T {\n  const [debouncedValue, setDebouncedValue] = useState(value);\n\n  useEffect(() => {\n    const handler = setTimeout(() => {\n      setDebouncedValue(value);\n    }, delay);\n\n    return () => {\n      clearTimeout(handler);\n    };\n  }, [value, delay]);\n\n  return debouncedValue;\n}\n"
  },
  {
    "path": "code/core/src/manager/hooks/useLandmark.ts",
    "content": "import { type RefObject } from 'react';\n\nimport {\n  type AriaLandmarkProps,\n  type LandmarkAria,\n  useLandmark as useUpstream,\n} from '@react-aria/landmark';\nimport type { FocusableElement } from '@react-types/shared';\n\nexport function useLandmark(\n  props: AriaLandmarkProps,\n  ref: RefObject<FocusableElement | null>\n): LandmarkAria & { landmarkProps: { 'data-sb-landmark': true } } {\n  const { landmarkProps } = useUpstream(props, ref);\n\n  return {\n    landmarkProps: {\n      ...landmarkProps,\n      'data-sb-landmark': true,\n    },\n  };\n}\n"
  },
  {
    "path": "code/core/src/manager/hooks/useLocation.ts",
    "content": "import { useEffect, useState } from 'react';\n\nexport const LocationMonitor = {\n  _currentHref: globalThis.window?.location.href ?? '',\n  _intervalId: null as ReturnType<typeof setInterval> | null,\n  _listeners: new Set<(location: Location) => void>(),\n\n  start() {\n    if (this._intervalId === null) {\n      this._intervalId = setInterval(() => {\n        const newLocation = globalThis.window.location;\n        if (newLocation.href !== this._currentHref) {\n          this._currentHref = newLocation.href;\n          this._listeners.forEach((listener) => listener(newLocation));\n        }\n      }, 100);\n    }\n  },\n\n  stop() {\n    if (this._intervalId !== null) {\n      clearInterval(this._intervalId);\n      this._intervalId = null;\n    }\n  },\n\n  subscribe(...listeners: Array<(location: Location) => void>) {\n    listeners.forEach((listener) => this._listeners.add(listener));\n    this.start();\n    return () => {\n      listeners.forEach((listener) => this._listeners.delete(listener));\n      if (this._listeners.size === 0) {\n        this.stop();\n      }\n    };\n  },\n};\n\nexport const useLocationHash = () => {\n  const [hash, setHash] = useState(globalThis.window?.location.hash ?? '');\n  useEffect(() => LocationMonitor.subscribe((location) => setHash(location.hash)), []);\n  return hash.slice(1);\n};\n"
  },
  {
    "path": "code/core/src/manager/hooks/useMeasure.tsx",
    "content": "import React from 'react';\n\n// Copied and modified from https://usehooks.com/usemeasure\nexport function useMeasure<T extends Element>() {\n  const [dimensions, setDimensions] = React.useState({\n    width: null,\n    height: null,\n  });\n\n  const prevObserver = React.useRef(null);\n\n  const customRef = React.useCallback((node: T) => {\n    if (prevObserver.current) {\n      // @ts-expect-error (non strict)\n      prevObserver.current.disconnect();\n      prevObserver.current = null;\n    }\n\n    if (node?.nodeType === Node.ELEMENT_NODE) {\n      const observer = new ResizeObserver(([entry]) => {\n        if (entry && entry.borderBoxSize) {\n          const { inlineSize: width, blockSize: height } = entry.borderBoxSize[0];\n\n          // @ts-expect-error (non strict)\n          setDimensions({ width, height });\n        }\n      });\n\n      observer.observe(node);\n      // @ts-expect-error (non strict)\n      prevObserver.current = observer;\n    }\n  }, []);\n\n  return [customRef, dimensions] as const;\n}\n"
  },
  {
    "path": "code/core/src/manager/hooks/useMedia.tsx",
    "content": "import { useEffect, useState } from 'react';\n\n// The hook is taken from this library:\n// https://usehooks-ts.com/react-hook/use-media-query\n// The good thing about it is that is uses window.matchMedia\n\nexport function useMediaQuery(query: string): boolean {\n  const getMatches = (queryMatch: string): boolean => {\n    // Prevents SSR issues\n    if (typeof window !== 'undefined') {\n      return window.matchMedia(queryMatch).matches;\n    }\n    return false;\n  };\n\n  const [matches, setMatches] = useState<boolean>(getMatches(query));\n\n  function handleChange() {\n    setMatches(getMatches(query));\n  }\n\n  useEffect(() => {\n    const matchMedia = window.matchMedia(query);\n\n    // Triggered at the first client-side load and if query changes\n    handleChange();\n\n    // Listen matchMedia\n    matchMedia.addEventListener('change', handleChange);\n\n    return () => {\n      matchMedia.removeEventListener('change', handleChange);\n    };\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [query]);\n\n  return matches;\n}\n"
  },
  {
    "path": "code/core/src/manager/index.stories.tsx",
    "content": "import type { Channel } from 'storybook/internal/channels';\nimport { CHANNEL_CREATED, CHANNEL_WS_DISCONNECT } from 'storybook/internal/core-events';\nimport { MemoryRouter } from 'storybook/internal/router';\nimport type { Addon_Config, Addon_Types } from 'storybook/internal/types';\nimport type { API_PreparedStoryIndex } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\nimport { FailedIcon } from '@storybook/icons';\n\nimport { HelmetProvider } from 'react-helmet-async';\nimport type { API, AddonStore } from 'storybook/manager-api';\nimport { addons, mockChannel } from 'storybook/manager-api';\nimport { screen, within } from 'storybook/test';\nimport { color } from 'storybook/theming';\n\nimport preview from '../../../.storybook/preview.tsx';\nimport { Main } from './index.tsx';\nimport Provider from './provider.ts';\n\nconst WS_DISCONNECTED_NOTIFICATION_ID = 'CORE/WS_DISCONNECTED';\n\nconst channel = mockChannel() as unknown as Channel;\n\nconst originalGetItem = Storage.prototype.getItem;\nconst originalSetItem = Storage.prototype.setItem;\nconst originalClear = Storage.prototype.clear;\n\nconst mockStoryIndex: API_PreparedStoryIndex = {\n  v: 5,\n  entries: {\n    'example-button--primary': {\n      type: 'story',\n      subtype: 'story',\n      id: 'example-button--primary',\n      title: 'Example/Button',\n      name: 'Primary',\n      importPath: './example-button.stories.tsx',\n      parameters: {},\n    },\n  },\n};\n\nclass ReactProvider extends Provider {\n  addons: AddonStore;\n\n  channel: Channel;\n\n  wsDisconnected = false;\n\n  constructor() {\n    super();\n\n    addons.setChannel(channel);\n    channel.emit(CHANNEL_CREATED);\n\n    this.addons = addons;\n    this.channel = channel;\n    global.__STORYBOOK_ADDONS_CHANNEL__ = channel;\n  }\n\n  getElements(type: Addon_Types) {\n    return this.addons.getElements(type);\n  }\n\n  getConfig(): Addon_Config {\n    return this.addons.getConfig();\n  }\n\n  handleAPI(api: API) {\n    this.addons.loadAddons(api);\n\n    // Initialize story index with mock data\n    api.setIndex(mockStoryIndex).then(() => {\n      // Mark preview as initialized so the iframe doesn't show a spinner\n      api.setPreviewInitialized();\n\n      // Set the current story to example-button--primary after the index is initialized\n      // This navigates to the story URL, which will cause the iframe to load the correct story\n      api.selectStory('example-button--primary', undefined, { viewMode: 'story' });\n    });\n\n    this.channel.on(CHANNEL_WS_DISCONNECT, (ev) => {\n      const TIMEOUT_CODE = 3008;\n      this.wsDisconnected = true;\n\n      api.addNotification({\n        id: WS_DISCONNECTED_NOTIFICATION_ID,\n        content: {\n          headline: ev.code === TIMEOUT_CODE ? 'Server timed out' : 'Connection lost',\n          subHeadline: 'Please restart your Storybook server and reload the page',\n        },\n        icon: <FailedIcon color={color.negative} />,\n        link: undefined,\n      });\n    });\n  }\n}\n\nconst meta = preview.meta({\n  title: 'Main',\n  component: Main,\n  args: {\n    provider: new ReactProvider(),\n  },\n  parameters: {\n    layout: 'fullscreen',\n    chromatic: {\n      disableSnapshot: true,\n    },\n  },\n  beforeEach: () => {\n    global.PREVIEW_URL = 'about:blank';\n\n    Storage.prototype.getItem = () => null;\n    Storage.prototype.setItem = () => {};\n    Storage.prototype.clear = () => {};\n  },\n  afterEach: () => {\n    Storage.prototype.getItem = originalGetItem;\n    Storage.prototype.setItem = originalSetItem;\n    Storage.prototype.clear = originalClear;\n  },\n  decorators: [\n    (Story) => (\n      <HelmetProvider key=\"helmet.Provider\">\n        <MemoryRouter key=\"location.provider\">\n          <Story />\n        </MemoryRouter>\n      </HelmetProvider>\n    ),\n  ],\n});\n\nexport default meta;\n\nexport const Default = meta.story({});\n\nexport const ToggleSidebar = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(await canvas.findByLabelText('Settings'));\n    await userEvent.click(await screen.findByRole('button', { name: /Show sidebar/i }));\n  },\n});\n\nexport const ToggleToolbar = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(await canvas.findByLabelText('Settings'));\n    await userEvent.click(await screen.findByRole('button', { name: /Show toolbar/i }));\n  },\n});\n\nexport const TogglePanel = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(await canvas.findByLabelText('Settings'));\n    await userEvent.click(await screen.findByRole('button', { name: /Show addons panel/i }));\n  },\n});\n\nexport const RightPanel = meta.story({\n  play: async ({ canvasElement, userEvent }) => {\n    const panel = within(canvasElement.querySelector('#storybook-panel-root') as HTMLElement);\n    await userEvent.click(await panel.findByLabelText('Move addon panel to right'));\n  },\n});\n\nexport const FullScreen = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(await canvas.findByRole('button', { name: /Enter full screen/i }));\n  },\n});\n\nexport const ShareMenu = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(await canvas.findByRole('button', { name: /Share/i }));\n  },\n});\n\nexport const ConnectionLost = meta.story({\n  play: async () => {\n    channel.emit(CHANNEL_WS_DISCONNECT, { code: 3007 });\n  },\n});\n\nexport const ServerTimedOut = meta.story({\n  play: async () => {\n    channel.emit(CHANNEL_WS_DISCONNECT, { code: 3008 });\n  },\n});\n\nexport const AboutPage = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(await canvas.findByLabelText('Settings'));\n    await userEvent.click(await screen.findByRole('link', { name: /About your Storybook/i }));\n  },\n});\n\nexport const GuidePage = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(await canvas.findByLabelText('Settings'));\n    await userEvent.click(await screen.findByRole('link', { name: /Onboarding guide/i }));\n  },\n});\n\nexport const ShortcutsPage = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(await canvas.findByLabelText('Settings'));\n    await userEvent.click(await screen.findByRole('link', { name: /Keyboard shortcuts/i }));\n  },\n});\n"
  },
  {
    "path": "code/core/src/manager/index.tsx",
    "content": "import type { ComponentProps, FC } from 'react';\nimport React, { useCallback, useMemo } from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport { ProviderDoesNotExtendBaseProviderError } from 'storybook/internal/manager-errors';\nimport { Location, LocationProvider, useNavigate } from 'storybook/internal/router';\nimport type { Addon_PageType } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { HelmetProvider } from 'react-helmet-async';\nimport { Provider as ManagerProvider, types } from 'storybook/manager-api';\nimport type { Combo } from 'storybook/manager-api';\nimport { ThemeProvider, ensure as ensureTheme } from 'storybook/theming';\n\nimport { App } from './App.tsx';\nimport type { Layout } from './components/layout/Layout.tsx';\nimport { LayoutProvider } from './components/layout/LayoutProvider.tsx';\nimport Provider from './provider.ts';\nimport { settingsPageAddon } from './settings/index.tsx';\n\n// @ts-expect-error (Converted from ts-ignore)\nThemeProvider.displayName = 'ThemeProvider';\n// @ts-expect-error (Converted from ts-ignore)\nHelmetProvider.displayName = 'HelmetProvider';\n\nexport interface RootProps {\n  provider: Provider;\n  history?: History;\n}\n\nexport const Root: FC<RootProps> = ({ provider }) => (\n  <HelmetProvider key=\"helmet.Provider\">\n    <LocationProvider key=\"location.provider\">\n      <Main provider={provider} />\n    </LocationProvider>\n  </HelmetProvider>\n);\n\nexport const Main: FC<{ provider: Provider }> = ({ provider }) => {\n  const navigate = useNavigate();\n\n  return (\n    <Location key=\"location.consumer\">\n      {(locationData) => (\n        <ManagerProvider\n          key=\"manager\"\n          provider={provider}\n          {...locationData}\n          navigate={navigate}\n          docsOptions={global?.DOCS_OPTIONS || {}}\n        >\n          {(combo: Combo) => {\n            const { state, api } = combo;\n            const setManagerLayoutState = useCallback<\n              ComponentProps<typeof Layout>['setManagerLayoutState']\n            >(\n              (sizes) => {\n                api.setSizes(sizes);\n              },\n              [api]\n            );\n\n            const pages: Addon_PageType[] = useMemo(\n              () => [settingsPageAddon, ...Object.values(api.getElements(types.experimental_PAGE))],\n              [Object.keys(api.getElements(types.experimental_PAGE)).join()]\n            );\n\n            return (\n              <ThemeProvider key=\"theme.provider\" theme={ensureTheme(state.theme)}>\n                <LayoutProvider>\n                  <App\n                    key=\"app\"\n                    pages={pages}\n                    managerLayoutState={{\n                      ...state.layout,\n                      viewMode: state.viewMode,\n                    }}\n                    hasTab={!!api.getQueryParam('tab')}\n                    setManagerLayoutState={setManagerLayoutState}\n                  />\n                </LayoutProvider>\n              </ThemeProvider>\n            );\n          }}\n        </ManagerProvider>\n      )}\n    </Location>\n  );\n};\n\nexport function renderStorybookUI(domNode: HTMLElement, provider: Provider) {\n  if (!(provider instanceof Provider)) {\n    throw new ProviderDoesNotExtendBaseProviderError();\n  }\n\n  const root = createRoot(domNode);\n  root.render(<Root key=\"root\" provider={provider} />);\n}\n\nexport { Provider };\n"
  },
  {
    "path": "code/core/src/manager/keybinding.ts",
    "content": "const codeToKeyMap = {\n  // event.code => event.key\n  Space: ' ',\n  Slash: '/',\n  ArrowLeft: 'ArrowLeft',\n  ArrowUp: 'ArrowUp',\n  ArrowRight: 'ArrowRight',\n  ArrowDown: 'ArrowDown',\n  Escape: 'Escape',\n  Enter: 'Enter',\n};\n\ninterface Modifiers {\n  alt?: boolean;\n  ctrl?: boolean;\n  meta?: boolean;\n  shift?: boolean;\n}\n\nconst allFalse = { alt: false, ctrl: false, meta: false, shift: false };\n\nexport const matchesModifiers = (modifiers: Modifiers | false, event: KeyboardEvent) => {\n  const { alt, ctrl, meta, shift } = modifiers === false ? allFalse : modifiers;\n\n  if (typeof alt === 'boolean' && alt !== event.altKey) {\n    return false;\n  }\n\n  if (typeof ctrl === 'boolean' && ctrl !== event.ctrlKey) {\n    return false;\n  }\n\n  if (typeof meta === 'boolean' && meta !== event.metaKey) {\n    return false;\n  }\n\n  if (typeof shift === 'boolean' && shift !== event.shiftKey) {\n    return false;\n  }\n  return true;\n};\n\nexport const matchesKeyCode = (code: keyof typeof codeToKeyMap, event: KeyboardEvent) => {\n  // event.code is preferable but not supported in IE\n  return event.code ? event.code === code : event.key === codeToKeyMap[code];\n};\n"
  },
  {
    "path": "code/core/src/manager/manager-stores.mock.ts",
    "content": "import {\n  experimental_MockUniversalStore,\n  experimental_useUniversalStore,\n} from 'storybook/manager-api';\nimport * as testUtils from 'storybook/test';\n\nimport {\n  type StoreEvent,\n  type StoreState,\n  UNIVERSAL_CHECKLIST_STORE_OPTIONS,\n  createChecklistStore,\n} from '../shared/checklist-store/index.ts';\nimport {\n  type StatusStoreEvent,\n  type StatusesByStoryIdAndTypeId,\n  createStatusStore,\n} from '../shared/status-store/index.ts';\nimport { UNIVERSAL_STATUS_STORE_OPTIONS } from '../shared/status-store/index.ts';\nimport type {\n  TestProviderStateByProviderId,\n  TestProviderStoreEvent,\n} from '../shared/test-provider-store/index.ts';\nimport { UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS } from '../shared/test-provider-store/index.ts';\nimport { createTestProviderStore } from '../shared/test-provider-store/index.ts';\nimport type { UniversalStore } from '../shared/universal-store/index.ts';\n\nexport const {\n  fullStatusStore: internal_fullStatusStore,\n  getStatusStoreByTypeId: experimental_getStatusStore,\n  useStatusStore: experimental_useStatusStore,\n} = createStatusStore({\n  universalStatusStore: new experimental_MockUniversalStore(\n    UNIVERSAL_STATUS_STORE_OPTIONS,\n    testUtils\n  ) as unknown as UniversalStore<StatusesByStoryIdAndTypeId, StatusStoreEvent>,\n  useUniversalStore: experimental_useUniversalStore,\n  environment: 'manager',\n});\n\nexport const {\n  fullTestProviderStore: internal_fullTestProviderStore,\n  getTestProviderStoreById: experimental_getTestProviderStore,\n  useTestProviderStore: experimental_useTestProviderStore,\n} = createTestProviderStore({\n  universalTestProviderStore: new experimental_MockUniversalStore(\n    UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS,\n    testUtils\n  ) as unknown as UniversalStore<TestProviderStateByProviderId, TestProviderStoreEvent>,\n  useUniversalStore: experimental_useUniversalStore,\n});\n\nexport const internal_universalChecklistStore = new experimental_MockUniversalStore<\n  StoreState,\n  StoreEvent\n>(\n  {\n    ...UNIVERSAL_CHECKLIST_STORE_OPTIONS,\n    leader: globalThis.CONFIG_TYPE === 'PRODUCTION',\n  },\n  testUtils\n) as unknown as UniversalStore<StoreState, StoreEvent>;\n\nexport const internal_checklistStore = createChecklistStore(internal_universalChecklistStore);\n"
  },
  {
    "path": "code/core/src/manager/manager-stores.ts",
    "content": "export {\n  internal_fullStatusStore,\n  experimental_getStatusStore,\n  experimental_useStatusStore,\n  internal_fullTestProviderStore,\n  experimental_getTestProviderStore,\n  experimental_useTestProviderStore,\n  internal_checklistStore,\n  internal_universalChecklistStore,\n} from 'storybook/manager-api';\n"
  },
  {
    "path": "code/core/src/manager/provider.ts",
    "content": "import type { Addon_Types } from 'storybook/internal/types';\n\nexport default class Provider {\n  getElements(_type: Addon_Types) {\n    throw new Error('Provider.getElements() is not implemented!');\n  }\n\n  handleAPI(_api: unknown) {\n    throw new Error('Provider.handleAPI() is not implemented!');\n  }\n\n  getConfig() {\n    console.error('Provider.getConfig() is not implemented!');\n\n    return {};\n  }\n}\n"
  },
  {
    "path": "code/core/src/manager/runtime.tsx",
    "content": "import React from 'react';\n\nimport type { Channel } from 'storybook/internal/channels';\nimport { createBrowserChannel } from 'storybook/internal/channels';\nimport { CHANNEL_CREATED, CHANNEL_WS_DISCONNECT } from 'storybook/internal/core-events';\nimport type { Addon_Config, Addon_Types } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\nimport { FailedIcon } from '@storybook/icons';\n\nimport type { API, AddonStore } from 'storybook/manager-api';\nimport { addons, types } from 'storybook/manager-api';\nimport { color } from 'storybook/theming';\n\nimport { ToolbarManager } from '../toolbar/components/ToolbarManager.tsx';\nimport { TOOLBAR_ID } from '../toolbar/constants.ts';\nimport { renderStorybookUI } from './index.tsx';\nimport Provider from './provider.ts';\n\nconst WS_DISCONNECTED_NOTIFICATION_ID = 'CORE/WS_DISCONNECTED';\n\n// Register the toolbar in the manager\naddons.register(TOOLBAR_ID, () =>\n  addons.add(TOOLBAR_ID, {\n    title: TOOLBAR_ID,\n    type: types.TOOL,\n    match: ({ tabId }) => !tabId,\n    render: () => <ToolbarManager />,\n  })\n);\n\nclass ReactProvider extends Provider {\n  addons: AddonStore;\n\n  channel: Channel;\n\n  wsDisconnected = false;\n\n  constructor() {\n    super();\n\n    const channel = createBrowserChannel({ page: 'manager' });\n\n    addons.setChannel(channel);\n\n    channel.emit(CHANNEL_CREATED);\n\n    this.addons = addons;\n    this.channel = channel;\n    global.__STORYBOOK_ADDONS_CHANNEL__ = channel;\n  }\n\n  getElements(type: Addon_Types) {\n    return this.addons.getElements(type);\n  }\n\n  getConfig(): Addon_Config {\n    return this.addons.getConfig();\n  }\n\n  handleAPI(api: API) {\n    this.addons.loadAddons(api);\n\n    this.channel.on(CHANNEL_WS_DISCONNECT, (ev) => {\n      const TIMEOUT_CODE = 3008;\n      this.wsDisconnected = true;\n\n      api.addNotification({\n        id: WS_DISCONNECTED_NOTIFICATION_ID,\n        content: {\n          headline: ev.code === TIMEOUT_CODE ? 'Server timed out' : 'Connection lost',\n          subHeadline: 'Please restart your Storybook server and reload the page',\n        },\n        icon: <FailedIcon color={color.negative} />,\n        link: undefined,\n      });\n    });\n  }\n}\n\nconst { document } = global;\nconst rootEl = document.getElementById('root');\n\n// We need to wait for the script tag containing the global objects\n// to be run by Webkit before rendering the UI. This is fine in most browsers.\nsetTimeout(() => {\n  // @ts-expect-error (non strict)\n  renderStorybookUI(rootEl, new ReactProvider());\n}, 0);\n"
  },
  {
    "path": "code/core/src/manager/settings/About.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { Button, Link, StorybookLogo } from 'storybook/internal/components';\n\nimport { DocumentIcon, GithubIcon } from '@storybook/icons';\n\nimport { styled } from 'storybook/theming';\n\nimport { UpgradeBlock } from '../components/upgrade/UpgradeBlock.tsx';\n\nconst Container = styled.div({\n  display: 'flex',\n  alignItems: 'center',\n  flexDirection: 'column',\n  marginTop: 40,\n});\n\nconst Header = styled.header({\n  marginBottom: 32,\n  alignItems: 'center',\n  display: 'flex',\n\n  '> svg': {\n    height: 48,\n    width: 'auto',\n    marginRight: 8,\n  },\n});\n\nconst Footer = styled.div(({ theme }) => ({\n  marginBottom: 24,\n  display: 'flex',\n  flexDirection: 'column',\n  alignItems: 'center',\n  color: theme.base === 'light' ? theme.color.dark : theme.color.lightest,\n  fontWeight: theme.typography.weight.regular,\n  fontSize: theme.typography.size.s2,\n}));\n\nconst Actions = styled.div({\n  display: 'flex',\n  flexDirection: 'row',\n  alignItems: 'center',\n  marginBottom: 24,\n  marginTop: 24,\n  gap: 16,\n});\n\nconst StyledLink = styled(Link as any)(({ theme }) => ({\n  '&&': {\n    fontWeight: theme.typography.weight.bold,\n    color: theme.base === 'light' ? theme.color.dark : theme.color.light,\n  },\n  '&:hover': {\n    color: theme.base === 'light' ? theme.color.darkest : theme.color.lightest,\n  },\n}));\n\nconst AboutScreen: FC<{ onNavigateToWhatsNew?: () => void }> = ({ onNavigateToWhatsNew }) => {\n  return (\n    <Container>\n      <Header>\n        <StorybookLogo alt=\"Storybook\" />\n      </Header>\n      <UpgradeBlock onNavigateToWhatsNew={onNavigateToWhatsNew} />\n      <Footer>\n        <Actions>\n          <Button ariaLabel={false} asChild>\n            <a href=\"https://github.com/storybookjs/storybook\">\n              <GithubIcon />\n              GitHub\n            </a>\n          </Button>\n          <Button ariaLabel={false} asChild>\n            <a href=\"https://storybook.js.org/docs?ref=ui\">\n              <DocumentIcon style={{ display: 'inline', marginRight: 5 }} />\n              Documentation\n            </a>\n          </Button>\n        </Actions>\n        <div>\n          Open source software maintained by{' '}\n          <StyledLink href=\"https://www.chromatic.com/\">Chromatic</StyledLink> and the{' '}\n          <StyledLink href=\"https://github.com/storybookjs/storybook/graphs/contributors\">\n            Storybook Community\n          </StyledLink>\n        </div>\n      </Footer>\n    </Container>\n  );\n};\n\nexport { AboutScreen };\n"
  },
  {
    "path": "code/core/src/manager/settings/AboutPage.tsx",
    "content": "import type { FC, PropsWithChildren } from 'react';\nimport React, { Component, useCallback } from 'react';\n\nimport { type API, useStorybookApi, useStorybookState } from 'storybook/manager-api';\n\nimport { AboutScreen } from './About.tsx';\n\n// Clear a notification on mount. This could be exported by core/notifications.js perhaps?\nclass NotificationClearer extends Component<\n  PropsWithChildren<{ api: API; notificationId: string }>\n> {\n  componentDidMount() {\n    const { api, notificationId } = this.props;\n    api.clearNotification(notificationId);\n  }\n\n  render() {\n    const { children } = this.props;\n    return children;\n  }\n}\n\nexport const AboutPage: FC = () => {\n  const api = useStorybookApi();\n  const state = useStorybookState();\n\n  const onNavigateToWhatsNew = useCallback(() => {\n    api.changeSettingsTab('whats-new');\n  }, [api]);\n  return (\n    <NotificationClearer api={api} notificationId=\"update\">\n      <AboutScreen\n        onNavigateToWhatsNew={\n          state.whatsNewData?.status === 'SUCCESS' ? onNavigateToWhatsNew : undefined\n        }\n      />\n    </NotificationClearer>\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/settings/Checklist/Checklist.stories.tsx",
    "content": "import React from 'react';\n\nimport { internal_checklistStore as checklistStore } from '#manager-stores';\nimport { ManagerContext } from 'storybook/manager-api';\nimport { fn } from 'storybook/test';\nimport { styled } from 'storybook/theming';\n\nimport preview from '../../../../../.storybook/preview.tsx';\nimport { checklistData } from '../../../shared/checklist-store/checklistData.tsx';\nimport type { ChecklistItem } from '../../components/sidebar/useChecklist.ts';\nimport { Checklist } from './Checklist.tsx';\n\nconst values: Record<string, 'accepted' | 'done' | 'skipped'> = {\n  controls: 'accepted',\n  renderComponent: 'done',\n  whatsNewStorybook10: 'done',\n  viewports: 'skipped',\n};\n\nconst availableItems = checklistData.sections.flatMap(\n  ({ id: sectionId, title: sectionTitle, items }, sectionIndex) =>\n    items.map<ChecklistItem>((item, itemIndex) => {\n      const itemValue = values[item.id];\n      const isAccepted = itemValue === 'accepted';\n      const isDone = itemValue === 'done';\n      const isSkipped = itemValue === 'skipped';\n      const isOpen = !isAccepted && !isDone && !isSkipped;\n      return {\n        ...item,\n        itemIndex,\n        sectionId,\n        sectionIndex,\n        sectionTitle,\n        isAvailable: true,\n        isLockedBy: undefined,\n        isImmutable: false,\n        isCompleted: isAccepted || isDone,\n        isReady: true,\n        isOpen,\n        isAccepted,\n        isDone,\n        isSkipped,\n        isMuted: false,\n      };\n    })\n);\n\nconst Container = styled.div(({ theme }) => ({\n  fontSize: theme.typography.size.s2,\n}));\n\nconst managerContext: any = {\n  state: {},\n  api: {\n    getDocsUrl: fn(\n      ({ asset, subpath }) =>\n        // TODO: Remove hard-coded version. Should be `major.minor` of latest release.\n        `https://storybook.js.org/${asset ? 'docs-assets/10.0' : 'docs'}/${subpath}`\n    ).mockName('api::getDocsUrl'),\n    getData: fn().mockName('api::getData'),\n    getIndex: fn().mockName('api::getIndex'),\n    getUrlState: fn().mockName('api::getUrlState'),\n    navigate: fn().mockName('api::navigate'),\n    on: fn().mockName('api::on'),\n    off: fn().mockName('api::off'),\n    once: fn().mockName('api::once'),\n  },\n};\n\nconst meta = preview.meta({\n  component: Checklist,\n  decorators: [\n    (Story) => (\n      <ManagerContext.Provider value={managerContext}>\n        <Container>\n          <Story />\n        </Container>\n      </ManagerContext.Provider>\n    ),\n  ],\n});\n\nexport const Default = meta.story({\n  args: { availableItems, ...checklistStore },\n});\n"
  },
  {
    "path": "code/core/src/manager/settings/Checklist/Checklist.tsx",
    "content": "import React, { useMemo } from 'react';\n\nimport { ActionList, Button, Collapsible } from 'storybook/internal/components';\n\nimport {\n  CheckIcon,\n  ChevronSmallDownIcon,\n  LockIcon,\n  StatusPassIcon,\n  UndoIcon,\n} from '@storybook/icons';\n\nimport { useStorybookApi } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport { Focus } from '../../components/Focus/Focus.tsx';\nimport type { ChecklistItem, useChecklist } from '../../components/sidebar/useChecklist.ts';\nimport { useLocationHash } from '../../hooks/useLocation.ts';\n\ntype ChecklistSection = {\n  id: string;\n  title: string;\n  itemIds: string[];\n  progress: number;\n};\n\nconst Sections = styled.ol(({ theme }) => ({\n  listStyle: 'none',\n  display: 'flex',\n  flexDirection: 'column',\n  gap: 20,\n  margin: 0,\n  padding: 0,\n\n  '& > li': {\n    background: theme.background.content,\n    border: `1px solid ${theme.base === 'dark' ? theme.color.darker : theme.color.border}`,\n    borderRadius: 8,\n  },\n}));\n\nconst Items = styled.ol(({ theme }) => ({\n  listStyle: 'none',\n  display: 'flex',\n  flexDirection: 'column',\n  margin: 0,\n  padding: 0,\n\n  '& > li:not(:last-child)': {\n    boxShadow: `inset 0 -1px 0 ${theme.base === 'dark' ? theme.color.darker : theme.color.border}`,\n  },\n\n  '& > li:last-child': {\n    borderBottomLeftRadius: 7,\n    borderBottomRightRadius: 7,\n  },\n}));\n\nconst SectionSummary = styled.div<{ progress: number; isCollapsed: boolean }>(\n  ({ theme, progress, isCollapsed, onClick }) => ({\n    position: 'relative',\n    fontWeight: 'bold',\n    display: 'flex',\n    alignItems: 'center',\n    gap: 10,\n    padding: '10px 10px 10px 15px',\n    borderBottom: `5px solid ${theme.base === 'dark' ? theme.color.darker : theme.color.light}`,\n    borderBottomLeftRadius: isCollapsed ? 7 : 0,\n    borderBottomRightRadius: isCollapsed ? 7 : 0,\n    transition: 'border-radius var(--transition-duration, 0.2s)',\n    cursor: onClick ? 'pointer' : 'default',\n    '--toggle-button-rotate': isCollapsed ? '0deg' : '180deg',\n    '--toggle-button-opacity': 0,\n\n    '&:hover, &:focus-visible': {\n      outline: 'none',\n      '--toggle-button-opacity': 1,\n    },\n\n    '&::after': {\n      pointerEvents: 'none',\n      position: 'absolute',\n      top: 0,\n      bottom: -5,\n      left: 0,\n      right: 0,\n      content: '\"\"',\n      display: 'block',\n      width: `${progress}%`,\n      borderBottom: `5px solid ${theme.color.positive}`,\n      borderBottomLeftRadius: 'inherit',\n      borderBottomRightRadius: progress === 100 ? 'inherit' : 0,\n      transition: 'width var(--transition-duration, 0.2s)',\n    },\n  })\n);\n\nconst SectionHeading = styled.h2(({ theme }) => ({\n  flex: 1,\n  margin: 0,\n  fontSize: theme.typography.size.s3,\n  fontWeight: theme.typography.weight.bold,\n}));\n\nconst ItemSummary = styled.div<{ isCollapsed: boolean; onClick?: () => void }>(\n  ({ theme, isCollapsed, onClick }) => ({\n    fontWeight: theme.typography.weight.regular,\n    fontSize: theme.typography.size.s2,\n    display: 'flex',\n    alignItems: 'center',\n    minHeight: 40,\n    gap: 10,\n    padding: isCollapsed ? '6px 10px 6px 15px' : '10px 10px 10px 15px',\n    transition: 'padding var(--transition-duration, 0.2s)',\n    cursor: onClick ? 'pointer' : 'default',\n    '--toggle-button-rotate': isCollapsed ? '0deg' : '180deg',\n\n    '&:focus-visible': {\n      outline: 'none',\n    },\n  })\n);\n\nconst ItemHeading = styled.h3<{ skipped: boolean }>(({ theme, skipped }) => ({\n  flex: 1,\n  margin: 0,\n  color: skipped ? theme.textMutedColor : theme.color.defaultText,\n  overflow: 'hidden',\n  textOverflow: 'ellipsis',\n  whiteSpace: 'nowrap',\n  fontSize: theme.typography.size.s2,\n  fontWeight: theme.typography.weight.bold,\n}));\n\nconst ItemContent = styled.div(({ theme }) => ({\n  display: 'flex',\n  flexDirection: 'column',\n  alignItems: 'flex-start',\n  gap: 8,\n  padding: '0 15px 15px 41px',\n  fontSize: theme.typography.size.s2,\n\n  code: {\n    fontSize: '0.9em',\n    backgroundColor: theme.background.app,\n    borderRadius: theme.appBorderRadius,\n    padding: '1px 3px',\n  },\n  img: {\n    maxWidth: '100%',\n    margin: '15px auto',\n  },\n  p: {\n    margin: 0,\n    lineHeight: 1.4,\n  },\n  'ol, ul': {\n    paddingLeft: 25,\n    listStyleType: 'disc',\n\n    'li::marker': {\n      color: theme.color.mediumdark,\n    },\n  },\n}));\n\nconst StatusIcon = styled.div(({ theme }) => ({\n  position: 'relative',\n  flex: '0 0 auto',\n  minHeight: 16,\n  minWidth: 16,\n  margin: 0,\n  background: theme.base === 'dark' ? theme.color.darkest : theme.background.app,\n  borderRadius: 9,\n  outline: `1px solid ${theme.base === 'dark' ? theme.color.darker : theme.color.border}`,\n  outlineOffset: -1,\n}));\nconst Checked = styled(StatusPassIcon)<{ 'data-visible'?: boolean }>(\n  ({ theme, 'data-visible': visible }) => ({\n    position: 'absolute',\n    width: 'inherit',\n    height: 'inherit',\n    top: 0,\n    left: 0,\n    bottom: 0,\n    right: 0,\n    padding: 1,\n    borderRadius: '50%',\n    background: theme.color.positive,\n    color: theme.background.content,\n    opacity: visible ? 1 : 0,\n    transform: visible ? 'scale(1)' : 'scale(0.7)',\n    transition: 'all var(--transition-duration, 0.2s)',\n  })\n);\nconst Skipped = styled.span<{ visible?: boolean }>(({ theme, visible }) => ({\n  display: 'flex',\n  alignItems: 'center',\n  color: theme.textMutedColor,\n  fontSize: '12px',\n  fontWeight: 'bold',\n  overflow: 'hidden',\n  padding: visible ? '0 10px' : 0,\n  opacity: visible ? 1 : 0,\n  width: visible ? 'auto' : 0,\n  height: visible ? 18 : 16,\n  transition: 'all var(--transition-duration, 0.2s)',\n}));\n\nconst Actions = styled.div({\n  alignSelf: 'flex-end',\n  flexDirection: 'row-reverse',\n  display: 'flex',\n  gap: 4,\n});\n\nconst ToggleButton = styled(Button)({\n  opacity: 'var(--toggle-button-opacity)',\n  transition: 'opacity var(--transition-duration, 0.2s)',\n\n  '&:hover, &:focus': {\n    opacity: 1,\n  },\n\n  svg: {\n    transform: 'rotate(var(--toggle-button-rotate))',\n    transition: 'transform var(--transition-duration, 0.2s)',\n  },\n});\n\nexport const Checklist = ({\n  availableItems,\n  accept,\n  skip,\n  reset,\n}: Pick<ReturnType<typeof useChecklist>, 'availableItems' | 'accept' | 'skip' | 'reset'>) => {\n  const api = useStorybookApi();\n  const locationHash = useLocationHash();\n\n  const { itemsById, sectionsById } = useMemo(\n    () =>\n      availableItems.reduce<{\n        itemsById: Record<string, ChecklistItem>;\n        sectionsById: Record<string, ChecklistSection>;\n      }>(\n        (acc, item) => {\n          acc.itemsById[item.id] = item;\n          const { sectionId: id, sectionTitle: title } = item;\n          acc.sectionsById[id] = acc.sectionsById[id] ?? { id, title, itemIds: [] };\n          acc.sectionsById[id].itemIds.push(item.id);\n          return acc;\n        },\n        { itemsById: {}, sectionsById: {} }\n      ),\n    [availableItems]\n  );\n\n  const sections = useMemo(\n    () =>\n      Object.values(sectionsById).map(({ id, title, itemIds }) => {\n        const items = itemIds.map<ChecklistItem>((id) => itemsById[id]);\n        const progress =\n          (items.reduce((acc, item) => (item.isOpen ? acc : acc + 1), 0) / items.length) * 100;\n        return { id, title, items, progress };\n      }),\n    [itemsById, sectionsById]\n  );\n\n  return (\n    <Sections>\n      {sections.map(({ id, title, items, progress }) => {\n        const collapsed = progress === 100 && items.every((item) => item.id !== locationHash);\n\n        return (\n          <li key={id}>\n            <Focus.Proxy targetId={`toggle-${id}`}>\n              <Collapsible\n                collapsed={collapsed}\n                summary={({ isCollapsed, toggleCollapsed, toggleProps }) => (\n                  <SectionSummary\n                    progress={progress}\n                    isCollapsed={isCollapsed}\n                    onClick={toggleCollapsed}\n                  >\n                    <StatusIcon>\n                      <Checked data-visible={progress === 100} />\n                    </StatusIcon>\n                    <SectionHeading>{title}</SectionHeading>\n                    <Actions>\n                      <ToggleButton\n                        {...toggleProps}\n                        data-target-id={`toggle-${id}`}\n                        variant=\"ghost\"\n                        padding=\"small\"\n                        aria-label={title}\n                      >\n                        <ChevronSmallDownIcon />\n                      </ToggleButton>\n                    </Actions>\n                  </SectionSummary>\n                )}\n              >\n                <Items>\n                  {items.map(\n                    ({\n                      content,\n                      isOpen,\n                      isAccepted,\n                      isDone,\n                      isLockedBy,\n                      isImmutable,\n                      isSkipped,\n                      ...item\n                    }) => {\n                      const isChecked = isAccepted || isDone;\n                      const isCollapsed = item.id !== locationHash;\n                      const isLocked = !!isLockedBy;\n                      const itemContent = content?.({ api });\n\n                      return (\n                        <ActionList.Item key={item.id}>\n                          <Focus.Target\n                            targetHash={item.id}\n                            highlightDuration={2000}\n                            outlineOffset={-2}\n                          >\n                            <Focus.Proxy targetId={`toggle-${item.id}`} outlineOffset={-2}>\n                              <Collapsible\n                                collapsed={isCollapsed}\n                                summary={({ isCollapsed, toggleCollapsed, toggleProps }) => (\n                                  <ItemSummary\n                                    isCollapsed={isCollapsed || !itemContent}\n                                    onClick={itemContent ? toggleCollapsed : undefined}\n                                  >\n                                    <StatusIcon>\n                                      <Checked data-visible={isChecked} />\n                                      <Skipped visible={isSkipped}>Skipped</Skipped>\n                                    </StatusIcon>\n                                    <ItemHeading skipped={isSkipped}>{item.label}</ItemHeading>\n                                    <Actions>\n                                      {itemContent && (\n                                        <ToggleButton\n                                          {...toggleProps}\n                                          data-target-id={`toggle-${item.id}`}\n                                          variant=\"ghost\"\n                                          padding=\"small\"\n                                          ariaLabel={`${isCollapsed ? 'Expand' : 'Collapse'} ${item.label}`}\n                                        >\n                                          <ChevronSmallDownIcon />\n                                        </ToggleButton>\n                                      )}\n                                      {isLocked && (\n                                        <Button\n                                          variant=\"ghost\"\n                                          padding=\"small\"\n                                          ariaLabel=\"Locked\"\n                                          tooltip={`Complete “${itemsById[isLockedBy].label}” first`}\n                                          disabled\n                                          readOnly\n                                        >\n                                          <LockIcon />\n                                        </Button>\n                                      )}\n                                      {isOpen && !isLocked && item.action && (\n                                        <Button\n                                          ariaLabel={false}\n                                          variant=\"solid\"\n                                          size=\"small\"\n                                          onClick={(e) => {\n                                            e.stopPropagation();\n                                            item.action?.onClick({\n                                              api,\n                                              accept: () => accept(item.id),\n                                            });\n                                          }}\n                                        >\n                                          {item.action.label}\n                                        </Button>\n                                      )}\n                                      {isOpen && !isLocked && !item.action && !item.subscribe && (\n                                        <Button\n                                          ariaLabel={false}\n                                          variant=\"outline\"\n                                          size=\"small\"\n                                          onClick={(e) => {\n                                            e.stopPropagation();\n                                            accept(item.id);\n                                          }}\n                                        >\n                                          <CheckIcon />\n                                          Mark as complete\n                                        </Button>\n                                      )}\n                                      {isOpen && !isLocked && (\n                                        <Button\n                                          ariaLabel={false}\n                                          variant=\"ghost\"\n                                          size=\"small\"\n                                          onClick={(e) => {\n                                            e.stopPropagation();\n                                            skip(item.id);\n                                          }}\n                                        >\n                                          Skip\n                                        </Button>\n                                      )}\n                                      {((isAccepted && !isImmutable) || isSkipped) && !isLocked && (\n                                        <Button\n                                          ariaLabel=\"Undo\"\n                                          variant=\"ghost\"\n                                          padding=\"small\"\n                                          onClick={(e) => {\n                                            e.stopPropagation();\n                                            reset(item.id);\n                                          }}\n                                        >\n                                          <UndoIcon />\n                                        </Button>\n                                      )}\n                                    </Actions>\n                                  </ItemSummary>\n                                )}\n                              >\n                                {itemContent && <ItemContent>{itemContent}</ItemContent>}\n                              </Collapsible>\n                            </Focus.Proxy>\n                          </Focus.Target>\n                        </ActionList.Item>\n                      );\n                    }\n                  )}\n                </Items>\n              </Collapsible>\n            </Focus.Proxy>\n          </li>\n        );\n      })}\n    </Sections>\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/settings/GuidePage.stories.tsx",
    "content": "import React from 'react';\n\nimport { ManagerContext } from 'storybook/manager-api';\nimport { fn } from 'storybook/test';\n\nimport preview from '../../../../.storybook/preview.tsx';\nimport { initialState } from '../../shared/checklist-store/checklistData.state.ts';\nimport { internal_universalChecklistStore as mockStore } from '../manager-stores.mock.ts';\nimport { GuidePage } from './GuidePage.tsx';\n\nconst managerContext: any = {\n  state: {},\n  api: {\n    getDocsUrl: fn(\n      ({ asset, subpath }) =>\n        // TODO: Remove hard-coded version. Should be `major.minor` of latest release.\n        `https://storybook.js.org/${asset ? 'docs-assets/10.0' : 'docs'}/${subpath}`\n    ).mockName('api::getDocsUrl'),\n    getData: fn().mockName('api::getData'),\n    getIndex: fn().mockName('api::getIndex'),\n    getUrlState: fn().mockName('api::getUrlState'),\n    navigate: fn().mockName('api::navigate'),\n    on: fn().mockName('api::on'),\n    off: fn().mockName('api::off'),\n    once: fn().mockName('api::once'),\n  },\n};\n\nconst meta = preview.meta({\n  component: GuidePage,\n  decorators: [\n    (Story) => (\n      <ManagerContext.Provider value={managerContext}>\n        <Story />\n      </ManagerContext.Provider>\n    ),\n  ],\n  beforeEach: async () => {\n    mockStore.setState({\n      loaded: true,\n      widget: {},\n      items: {\n        ...initialState.items,\n        controls: { status: 'accepted' },\n        renderComponent: { status: 'done' },\n        viewports: { status: 'skipped' },\n      },\n    });\n  },\n});\n\nexport const Default = meta.story({});\n"
  },
  {
    "path": "code/core/src/manager/settings/GuidePage.tsx",
    "content": "import React from 'react';\n\nimport { Link } from 'storybook/internal/components';\n\nimport { global } from '@storybook/global';\n\nimport { styled } from 'storybook/theming';\n\nimport { useChecklist } from '../components/sidebar/useChecklist.ts';\nimport { Checklist } from './Checklist/Checklist.tsx';\n\nconst Container = styled.div(({ theme }) => ({\n  display: 'flex',\n  flexDirection: 'column',\n  maxWidth: 600,\n  margin: '0 auto',\n  padding: '48px 20px',\n  gap: 32,\n  fontSize: theme.typography.size.s2,\n  '--transition-duration': '0.2s',\n}));\n\nconst Intro = styled.div(({ theme }) => ({\n  display: 'flex',\n  flexDirection: 'column',\n  gap: 8,\n\n  '& h1': {\n    fontSize: theme.typography.size.m3,\n    fontWeight: theme.typography.weight.bold,\n    margin: 0,\n  },\n\n  '& > p': {\n    margin: 0,\n  },\n}));\n\nexport const GuidePage = () => {\n  const checklist = useChecklist();\n\n  return (\n    <Container>\n      <Intro>\n        <h1>Guide</h1>\n        <p>\n          Whether you&apos;re just getting started or looking for ways to level up, this checklist\n          will help you make the most of your Storybook.\n        </p>\n      </Intro>\n      <Checklist {...checklist} />\n      {global.FEATURES?.sidebarOnboardingChecklist !== false && (\n        <>\n          {checklist.openItems.length === 0 ? (\n            <center>Your work here is done!</center>\n          ) : checklist.widget.disable || checklist.openItems.every((item) => item.isMuted) ? (\n            <center>\n              Want to see this in the sidebar?{' '}\n              <Link onClick={() => checklist.disable(false)}>Show in sidebar</Link>\n            </center>\n          ) : (\n            <center>\n              Don&apos;t want to see this in the sidebar?{' '}\n              <Link onClick={() => checklist.mute(checklist.allItems.map(({ id }) => id))}>\n                Remove from sidebar\n              </Link>\n            </center>\n          )}\n        </>\n      )}\n    </Container>\n  );\n};\n"
  },
  {
    "path": "code/core/src/manager/settings/SettingsFooter.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Decorator } from '@storybook/react-vite';\n\nimport SettingsFooter from './SettingsFooter.tsx';\n\nexport default {\n  component: SettingsFooter,\n  title: 'Settings/SettingsFooter',\n  decorators: [\n    ((StoryFn, c) => (\n      <div style={{ width: '600px', margin: '2rem auto' }}>\n        <StoryFn {...c} />\n      </div>\n    )) as Decorator,\n  ],\n};\n\nexport const Basic = () => <SettingsFooter />;\n"
  },
  {
    "path": "code/core/src/manager/settings/SettingsFooter.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { Link } from 'storybook/internal/components';\n\nimport { styled } from 'storybook/theming';\n\nconst Footer = styled.div(({ theme }) => ({\n  display: 'flex',\n  paddingTop: 20,\n  marginTop: 20,\n  borderTop: `1px solid ${theme.appBorderColor}`,\n  fontWeight: theme.typography.weight.bold,\n\n  '& > * + *': {\n    marginLeft: 20,\n  },\n}));\nconst SettingsFooter: FC<any> = (props) => (\n  <Footer {...props}>\n    <Link secondary href=\"https://storybook.js.org?ref=ui\" cancel={false} target=\"_blank\">\n      Docs\n    </Link>\n    <Link secondary href=\"https://github.com/storybookjs/storybook\" cancel={false} target=\"_blank\">\n      GitHub\n    </Link>\n    <Link\n      secondary\n      href=\"https://storybook.js.org/community?ref=ui#support\"\n      cancel={false}\n      target=\"_blank\"\n    >\n      Support\n    </Link>\n  </Footer>\n);\n\nexport default SettingsFooter;\n"
  },
  {
    "path": "code/core/src/manager/settings/ShortcutsPage.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { Consumer } from 'storybook/manager-api';\n\nimport { ShortcutsScreen } from './shortcuts.tsx';\n\nconst ShortcutsPage: FC = () => (\n  <Consumer>\n    {({\n      api: {\n        getShortcutKeys,\n        getAddonsShortcutLabels,\n        setShortcut,\n        restoreDefaultShortcut,\n        restoreAllDefaultShortcuts,\n      },\n    }) => (\n      <ShortcutsScreen\n        shortcutKeys={getShortcutKeys()}\n        addonsShortcutLabels={getAddonsShortcutLabels()}\n        {...{ setShortcut, restoreDefaultShortcut, restoreAllDefaultShortcuts }}\n      />\n    )}\n  </Consumer>\n);\n\nexport { ShortcutsPage };\n"
  },
  {
    "path": "code/core/src/manager/settings/about.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { fn } from 'storybook/test';\n\nimport UpgradeBlockStoriesMeta from '../components/upgrade/UpgradeBlock.stories.tsx';\nimport { AboutScreen } from './About.tsx';\n\nconst meta = {\n  component: AboutScreen,\n  title: 'Settings/AboutScreen',\n  decorators: [\n    UpgradeBlockStoriesMeta.decorators[0],\n    (Story) => (\n      <div\n        style={{\n          position: 'relative',\n          height: '100vh',\n          width: '100vw',\n        }}\n      >\n        <Story />\n      </div>\n    ),\n  ],\n  args: { onNavigateToWhatsNew: fn() },\n} satisfies Meta<typeof AboutScreen>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {\n  parameters: {\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/ur4kydUbRqdDyfoZWzdiIw/Storybook-app?type=design&node-id=9564-120444&mode=design&t=0TPINZFpwgFQFQeX-4',\n    },\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/settings/defaultShortcuts.tsx",
    "content": "import type { State } from 'storybook/manager-api';\n\nexport const defaultShortcuts: State['shortcuts'] = {\n  fullScreen: ['F'],\n  togglePanel: ['A'],\n  panelPosition: ['D'],\n  toggleNav: ['S'],\n  toolbar: ['T'],\n  search: ['/'],\n  focusNav: ['1'],\n  focusIframe: ['2'],\n  focusPanel: ['3'],\n  prevComponent: ['alt', 'ArrowUp'],\n  nextComponent: ['alt', 'ArrowDown'],\n  prevStory: ['alt', 'ArrowLeft'],\n  nextStory: ['alt', 'ArrowRight'],\n  shortcutsPage: ['ctrl', 'shift', ','],\n  aboutPage: [','],\n  escape: ['escape'],\n  collapseAll: ['ctrl', 'shift', 'ArrowUp'],\n  expandAll: ['ctrl', 'shift', 'ArrowDown'],\n  remount: ['alt', 'R'],\n  openInEditor: ['alt', 'shift', 'E'],\n  openInIsolation: ['alt', 'shift', 'I'],\n  copyStoryLink: ['alt', 'shift', 'L'],\n  goToPreviousLandmark: ['shift', 'F6'], // hardcoded in react-aria\n  goToNextLandmark: ['F6'], // hardcoded in react-aria\n  // TODO: bring this back once we want to add shortcuts for this\n  // copyStoryName: ['alt', 'shift', 'C'],\n};\n"
  },
  {
    "path": "code/core/src/manager/settings/index.tsx",
    "content": "import type { FC, ReactNode, SyntheticEvent } from 'react';\nimport React, { useMemo } from 'react';\n\nimport { Button, ScrollArea, TabsView } from 'storybook/internal/components';\nimport { Location, Route } from 'storybook/internal/router';\nimport type { Addon_PageType } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\nimport { CloseIcon } from '@storybook/icons';\n\nimport { types, useStorybookApi, useStorybookState } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport { menuTool } from '../components/preview/tools/menu.tsx';\nimport { matchesKeyCode, matchesModifiers } from '../keybinding.ts';\nimport { AboutPage } from './AboutPage.tsx';\nimport { GuidePage } from './GuidePage.tsx';\nimport { ShortcutsPage } from './ShortcutsPage.tsx';\nimport { WhatsNewPage } from './whats_new_page.tsx';\n\nconst { document } = global;\n\nconst Content = styled(ScrollArea)(({ theme }) => ({\n  background: theme.background.content,\n}));\n\nconst SidebarToggle = styled.div({\n  // Extra specificity is necessary here\n  '&&:has(*)': {\n    order: 0,\n    display: 'flex',\n    alignItems: 'center',\n    marginLeft: 10,\n    marginRight: 6,\n    gap: 6,\n  },\n});\n\nconst RouteWrapper: FC<{ children: ReactNode; path: string }> = ({ children, path }) => {\n  return (\n    <Content vertical horizontal={false}>\n      <Route path={path}>{children}</Route>\n    </Content>\n  );\n};\n\nconst Pages: FC<{\n  onClose: () => void;\n  enableShortcuts?: boolean;\n  changeTab: (tab: string) => void;\n  enableWhatsNew: boolean;\n}> = ({ changeTab, onClose, enableShortcuts = true, enableWhatsNew }) => {\n  React.useEffect(() => {\n    const handleEscape = (event: KeyboardEvent) => {\n      if (!enableShortcuts || event.repeat) {\n        return;\n      }\n      if (matchesModifiers(false, event) && matchesKeyCode('Escape', event)) {\n        event.preventDefault();\n        onClose();\n      }\n    };\n    document.addEventListener('keydown', handleEscape);\n    return () => document.removeEventListener('keydown', handleEscape);\n  }, [enableShortcuts, onClose]);\n\n  const tabs = useMemo(() => {\n    const tabsToInclude = [\n      {\n        id: 'about',\n        title: 'About',\n        children: (\n          <RouteWrapper path=\"about\">\n            <AboutPage key=\"about\" />\n          </RouteWrapper>\n        ),\n      },\n    ];\n\n    if (global.CONFIG_TYPE === 'DEVELOPMENT') {\n      tabsToInclude.push({\n        id: 'guide',\n        title: 'Guide',\n        children: (\n          <RouteWrapper path=\"guide\">\n            <GuidePage key=\"guide\" />\n          </RouteWrapper>\n        ),\n      });\n    }\n\n    tabsToInclude.push({\n      id: 'shortcuts',\n      title: 'Keyboard shortcuts',\n      children: (\n        <RouteWrapper path=\"shortcuts\">\n          <ShortcutsPage key=\"shortcuts\" />\n        </RouteWrapper>\n      ),\n    });\n\n    if (enableWhatsNew) {\n      tabsToInclude.push({\n        id: 'whats-new',\n        title: \"What's new?\",\n        children: (\n          <RouteWrapper path=\"whats-new\">\n            <WhatsNewPage key=\"whats-new\" />\n          </RouteWrapper>\n        ),\n      });\n    }\n\n    return tabsToInclude;\n  }, [enableWhatsNew]);\n\n  return (\n    <Location>\n      {({ path }) => {\n        const selected = tabs.find((tab) => path.includes(`settings/${tab.id}`))?.id;\n        return (\n          <TabsView\n            tabs={tabs}\n            tools={\n              <>\n                <SidebarToggle>{menuTool.render({})}</SidebarToggle>\n                <Button\n                  padding=\"small\"\n                  variant=\"ghost\"\n                  onClick={(e: SyntheticEvent) => {\n                    e.preventDefault();\n                    return onClose();\n                  }}\n                  ariaLabel=\"Close settings page\"\n                >\n                  <CloseIcon />\n                </Button>\n              </>\n            }\n            selected={selected}\n            onSelectionChange={changeTab}\n          />\n        );\n      }}\n    </Location>\n  );\n};\n\nconst SettingsPages: FC = () => {\n  const api = useStorybookApi();\n  const state = useStorybookState();\n  const changeTab = (tab: string) => api.changeSettingsTab(tab);\n\n  return (\n    <Pages\n      enableWhatsNew={state.whatsNewData?.status === 'SUCCESS'}\n      enableShortcuts={state.ui.enableShortcuts}\n      changeTab={changeTab}\n      onClose={api.closeSettings}\n    />\n  );\n};\n\nexport const settingsPageAddon: Addon_PageType = {\n  id: 'settings',\n  url: '/settings/',\n  title: 'Settings',\n  type: types.experimental_PAGE,\n  render: () => (\n    <Route path=\"/settings/\" startsWith>\n      <SettingsPages />\n    </Route>\n  ),\n};\n"
  },
  {
    "path": "code/core/src/manager/settings/shortcuts.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Decorator } from '@storybook/react-vite';\n\nimport { actions as makeActions } from 'storybook/actions';\n\nimport { defaultShortcuts } from './defaultShortcuts.tsx';\nimport { ShortcutsScreen } from './shortcuts.tsx';\n\nconst actions = makeActions(\n  'setShortcut',\n  'restoreDefaultShortcut',\n  'restoreAllDefaultShortcuts',\n  'onClose'\n);\n\nexport default {\n  component: ShortcutsScreen,\n  title: 'Settings/ShortcutsScreen',\n  decorators: [\n    ((StoryFn, c) => (\n      <div\n        style={{\n          position: 'relative',\n          height: 'calc(100vh)',\n          width: 'calc(100vw)',\n        }}\n      >\n        <StoryFn {...c} />\n      </div>\n    )) as Decorator,\n  ],\n};\n\nexport const Defaults = () => <ShortcutsScreen shortcutKeys={defaultShortcuts} {...actions} />;\nDefaults.storyName = 'default shortcuts';\n"
  },
  {
    "path": "code/core/src/manager/settings/shortcuts.tsx",
    "content": "import type { ComponentProps, FC } from 'react';\nimport React, { Component } from 'react';\n\nimport { Button, Form, Tooltip, TooltipProvider } from 'storybook/internal/components';\n\nimport { CheckIcon } from '@storybook/icons';\n\nimport {\n  type API_KeyCollection,\n  eventToShortcut,\n  shortcutMatchesShortcut,\n  shortcutToHumanString,\n} from 'storybook/manager-api';\nimport { keyframes, styled } from 'storybook/theming';\n\nimport SettingsFooter from './SettingsFooter.tsx';\n\nconst Header = styled.header(({ theme }) => ({\n  marginBottom: 20,\n  fontSize: theme.typography.size.m3,\n  fontWeight: theme.typography.weight.bold,\n  alignItems: 'center',\n  display: 'flex',\n}));\n\n// Grid\nexport const HeaderItem = styled.div(({ theme }) => ({\n  fontWeight: theme.typography.weight.bold,\n}));\n\nexport const GridHeaderRow = styled.div({\n  alignSelf: 'flex-end',\n  display: 'grid',\n  margin: '10px 0',\n  gridTemplateColumns: '1fr 1fr 12px',\n  '& > *:last-of-type': {\n    gridColumn: '2 / 2',\n    justifySelf: 'flex-end',\n    gridRow: '1',\n  },\n});\n\nexport const Row = styled.div(({ theme }) => ({\n  padding: '6px 0',\n  borderTop: `1px solid ${theme.appBorderColor}`,\n  display: 'grid',\n  gridTemplateColumns: '1fr 1fr 0px',\n}));\n\nexport const GridWrapper = styled.div({\n  display: 'grid',\n  gridTemplateColumns: '1fr',\n  gridAutoRows: 'minmax(auto, auto)',\n  marginBottom: 20,\n});\n\n// Form\nexport const Description = styled.div({\n  alignSelf: 'center',\n});\n\nexport type ValidationStates = 'valid' | 'error' | 'warn';\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore-error (this only errors during compilation for production)\nexport const TextInput: FC<\n  ComponentProps<typeof Form.Input> & { valid: ValidationStates | undefined }\n> = styled(Form.Input)<{ valid: ValidationStates }>(\n  ({ valid, theme }) =>\n    valid === 'error'\n      ? {\n          animation: `${theme.animation.jiggle} 700ms ease-out`,\n        }\n      : {},\n  {\n    display: 'flex',\n    width: 80,\n    flexDirection: 'column',\n    justifySelf: 'flex-end',\n    paddingLeft: 4,\n    paddingRight: 4,\n    textAlign: 'center',\n  }\n);\n\nexport const Fade = keyframes`\n0%,100% { opacity: 0; }\n  50% { opacity: 1; }\n`;\n\nconst SuccessIcon = styled(CheckIcon)<{ valid: string }>(\n  ({ valid, theme }) =>\n    valid === 'valid'\n      ? {\n          color: theme.color.positive,\n          animation: `${Fade} 2s ease forwards`,\n        }\n      : {\n          opacity: 0,\n        },\n  {\n    alignSelf: 'center',\n    display: 'flex',\n    marginLeft: 10,\n    height: 14,\n    width: 14,\n  }\n);\n\nconst Container = styled.div(({ theme }) => ({\n  fontSize: theme.typography.size.s2,\n  padding: `3rem 20px`,\n  maxWidth: 600,\n  margin: '0 auto',\n}));\n\nconst shortcutLabels = {\n  fullScreen: 'Go full screen',\n  togglePanel: 'Toggle addons',\n  panelPosition: 'Toggle addons orientation',\n  toggleNav: 'Toggle sidebar',\n  toolbar: 'Toggle toolbar',\n  search: 'Focus search',\n  focusNav: 'Focus sidebar',\n  focusIframe: 'Focus canvas',\n  focusPanel: 'Focus addons',\n  prevComponent: 'Previous component',\n  nextComponent: 'Next component',\n  prevStory: 'Previous story',\n  nextStory: 'Next story',\n  shortcutsPage: 'Go to shortcuts page',\n  aboutPage: 'Go to about page',\n  collapseAll: 'Collapse all items on sidebar',\n  expandAll: 'Expand all items on sidebar',\n  remount: 'Reload story',\n  openInEditor: 'Open story in editor',\n  openInIsolation: 'Open story in isolation',\n  copyStoryLink: 'Copy story link to clipboard',\n  goToPreviousLandmark: 'Go to previous landmark',\n  goToNextLandmark: 'Go to next landmark',\n  // TODO: bring this back once we want to add shortcuts for this\n  // copyStoryName: 'Copy story name to clipboard',\n};\n\nexport type Feature = keyof typeof shortcutLabels;\n\ntype ConfiguredShortcut = { shortcut: API_KeyCollection; error: boolean; hardcoded?: boolean };\n\n// Shortcuts that cannot be configured\nconst fixedShortcuts = ['escape'];\n\n// Shortcuts that cannot be changed by the user (imposed by third-party libraries).\nconst hardcodedShortcuts = ['goToPreviousLandmark', 'goToNextLandmark'];\nfunction toShortcutState(\n  shortcutKeys: ShortcutsScreenProps['shortcutKeys']\n): Record<Feature, ConfiguredShortcut> {\n  const state: Record<string, ConfiguredShortcut> = {};\n  for (const key of Object.keys(shortcutKeys).filter((k) => !fixedShortcuts.includes(k))) {\n    state[key] = {\n      shortcut: shortcutKeys[key as Feature],\n      error: false,\n      hardcoded: hardcodedShortcuts.includes(key),\n    };\n  }\n\n  return state;\n}\n\nexport interface ShortcutsScreenState {\n  activeFeature: Feature;\n  successField: Feature;\n  shortcutKeys: Record<Feature, any>;\n  addonsShortcutLabels?: Record<string, string>;\n}\n\nexport interface ShortcutsScreenProps {\n  shortcutKeys: Record<Feature, any>;\n  addonsShortcutLabels?: Record<string, string>;\n  setShortcut: Function;\n  restoreDefaultShortcut: Function;\n  restoreAllDefaultShortcuts: Function;\n}\n\nclass ShortcutsScreen extends Component<ShortcutsScreenProps, ShortcutsScreenState> {\n  constructor(props: ShortcutsScreenProps) {\n    super(props);\n    this.state = {\n      // @ts-expect-error (non strict)\n      activeFeature: undefined,\n      // @ts-expect-error (non strict)\n      successField: undefined,\n      // The initial shortcutKeys that come from props are the defaults/what was saved\n      // As the user interacts with the page, the state stores the temporary, unsaved shortcuts\n      // This object also includes the error attached to each shortcut\n      shortcutKeys: toShortcutState(props.shortcutKeys),\n      addonsShortcutLabels: props.addonsShortcutLabels,\n    };\n  }\n\n  onKeyDown = (e: KeyboardEvent) => {\n    const { activeFeature, shortcutKeys } = this.state;\n\n    if (e.key === 'Backspace') {\n      return this.restoreDefault();\n    }\n\n    const shortcut = eventToShortcut(e);\n\n    // Keypress is not a potential shortcut\n    if (!shortcut) {\n      return false;\n    }\n\n    // Normalize special characters produced by Option/Alt on macOS (e.g. ['Ø','O'] -> 'O')\n    const normalizedShortcut = shortcut.map((key) =>\n      Array.isArray(key) ? key.at(-1) : key\n    ) as string[];\n\n    // Check we don't match any other shortcuts\n    const error = !!Object.entries(shortcutKeys).find(\n      ([feature, { shortcut: existingShortcut }]) =>\n        feature !== activeFeature &&\n        existingShortcut &&\n        shortcutMatchesShortcut(normalizedShortcut, existingShortcut)\n    );\n\n    return this.setState({\n      shortcutKeys: { ...shortcutKeys, [activeFeature]: { shortcut: normalizedShortcut, error } },\n    });\n  };\n\n  onFocus = (focusedInput: Feature) => () => {\n    const { shortcutKeys } = this.state;\n\n    this.setState({\n      activeFeature: focusedInput,\n      shortcutKeys: {\n        ...shortcutKeys,\n        [focusedInput]: { shortcut: null, error: false },\n      },\n    });\n  };\n\n  onBlur = async () => {\n    const { shortcutKeys, activeFeature } = this.state;\n\n    if (shortcutKeys[activeFeature]) {\n      const { shortcut, error } = shortcutKeys[activeFeature];\n      if (!shortcut || error) {\n        return this.restoreDefault();\n      }\n      return this.saveShortcut();\n    }\n    return false;\n  };\n\n  saveShortcut = async () => {\n    const { activeFeature, shortcutKeys } = this.state;\n\n    const { setShortcut } = this.props;\n    await setShortcut(activeFeature, shortcutKeys[activeFeature].shortcut);\n    this.setState({ successField: activeFeature });\n  };\n\n  restoreDefaults = async () => {\n    const { restoreAllDefaultShortcuts } = this.props;\n\n    const defaultShortcuts = await restoreAllDefaultShortcuts();\n    return this.setState({ shortcutKeys: toShortcutState(defaultShortcuts) });\n  };\n\n  restoreDefault = async () => {\n    const { activeFeature, shortcutKeys } = this.state;\n\n    const { restoreDefaultShortcut } = this.props;\n\n    const defaultShortcut = await restoreDefaultShortcut(activeFeature);\n    return this.setState({\n      shortcutKeys: {\n        ...shortcutKeys,\n        ...toShortcutState({ [activeFeature]: defaultShortcut } as Record<Feature, any>),\n      },\n    });\n  };\n\n  displaySuccessMessage = (activeElement: Feature) => {\n    const { successField, shortcutKeys } = this.state;\n    return activeElement === successField && shortcutKeys[activeElement].error === false\n      ? 'valid'\n      : undefined;\n  };\n\n  displayError = (activeElement: Feature): ValidationStates | undefined => {\n    const { activeFeature, shortcutKeys } = this.state;\n    return activeElement === activeFeature && shortcutKeys[activeElement].error === true\n      ? 'error'\n      : undefined;\n  };\n\n  renderKeyInput = () => {\n    const { shortcutKeys, addonsShortcutLabels } = this.state;\n    // Filter out keyboard shortcuts from localStorage that no longer exist in code\n    const availableShortcuts = (Object.entries(shortcutKeys) as [Feature, any][]).filter(\n      ([feature]: [Feature, any]) =>\n        shortcutLabels[feature] !== undefined ||\n        (addonsShortcutLabels && addonsShortcutLabels[feature])\n    );\n\n    const arr = availableShortcuts.map(\n      ([feature, { shortcut, hardcoded }]: [Feature, ConfiguredShortcut]) => (\n        <Row key={feature}>\n          {/* @ts-expect-error (non strict) */}\n          <Description>{shortcutLabels[feature] || addonsShortcutLabels[feature]}</Description>\n\n          {hardcoded ? (\n            <>\n              <TooltipProvider\n                tooltip={<Tooltip hasChrome>This shortcut cannot be changed.</Tooltip>}\n                placement=\"right\"\n              >\n                <TextInput\n                  aria-disabled\n                  readOnly\n                  valid={undefined}\n                  value={shortcut ? shortcutToHumanString(shortcut) : ''}\n                />\n              </TooltipProvider>\n            </>\n          ) : (\n            <TextInput\n              spellCheck=\"false\"\n              valid={this.displayError(feature)}\n              className=\"modalInput\"\n              onBlur={this.onBlur}\n              onFocus={this.onFocus(feature)}\n              // @ts-expect-error (Converted from ts-ignore)\n              onKeyDown={this.onKeyDown}\n              value={shortcut ? shortcutToHumanString(shortcut) : ''}\n              placeholder=\"Type keys\"\n              readOnly\n            />\n          )}\n\n          {/* @ts-expect-error (non strict) */}\n          <SuccessIcon valid={this.displaySuccessMessage(feature)} />\n        </Row>\n      )\n    );\n\n    return arr;\n  };\n\n  renderKeyForm = () => (\n    <GridWrapper>\n      <GridHeaderRow>\n        <HeaderItem>Commands</HeaderItem>\n        <HeaderItem>Shortcut</HeaderItem>\n      </GridHeaderRow>\n      {this.renderKeyInput()}\n    </GridWrapper>\n  );\n\n  render() {\n    const layout = this.renderKeyForm();\n    return (\n      <Container>\n        <Header>Keyboard shortcuts</Header>\n\n        {layout}\n        <Button\n          ariaLabel={false}\n          variant=\"outline\"\n          size=\"small\"\n          id=\"restoreDefaultsHotkeys\"\n          onClick={this.restoreDefaults}\n        >\n          Restore defaults\n        </Button>\n        <SettingsFooter />\n      </Container>\n    );\n  }\n}\n\nexport { ShortcutsScreen };\n"
  },
  {
    "path": "code/core/src/manager/settings/whats_new.tsx",
    "content": "import type { ComponentProps, FC } from 'react';\nimport React, { Fragment, useEffect, useState } from 'react';\n\nimport { Button, Loader } from 'storybook/internal/components';\n\nimport { global } from '@storybook/global';\nimport { AlertIcon as AlertIconSvg, EyeCloseIcon, EyeIcon, HeartIcon } from '@storybook/icons';\n\nimport { useStorybookApi, useStorybookState } from 'storybook/manager-api';\nimport { styled, useTheme } from 'storybook/theming';\n\nconst Centered = styled.div({\n  top: '50%',\n  position: 'absolute',\n  transform: 'translateY(-50%)',\n  width: '100%',\n  textAlign: 'center',\n});\n\nconst LoaderWrapper = styled.div({\n  position: 'relative',\n  height: '32px',\n});\n\nconst Message = styled.div(({ theme }) => ({\n  paddingTop: '12px',\n  color: theme.textMutedColor,\n  maxWidth: '295px',\n  margin: '0 auto',\n  fontSize: `${theme.typography.size.s1}px`,\n  lineHeight: `16px`,\n}));\n\nconst Container = styled.div(({ theme }) => ({\n  position: 'absolute',\n  width: '100%',\n  height: 40,\n  bottom: 0,\n  background: theme.background.bar,\n  fontSize: theme.typography.size.s2,\n  borderTop: `1px solid ${theme.color.border}`,\n  padding: '0 10px 0 15px',\n  display: 'flex',\n  alignItems: 'center',\n  justifyContent: 'space-between',\n}));\n\nexport const WhatsNewFooter = ({\n  isNotificationsEnabled,\n  onToggleNotifications,\n  onCopyLink,\n}: {\n  isNotificationsEnabled: boolean;\n  onToggleNotifications?: () => void;\n  onCopyLink?: () => void;\n}) => {\n  const theme = useTheme();\n  const [copyText, setCopyText] = useState('Copy Link');\n  const copyLink = () => {\n    // @ts-expect-error (non strict)\n    onCopyLink();\n    setCopyText('Copied!');\n    setTimeout(() => setCopyText('Copy Link'), 4000);\n  };\n\n  return (\n    <Container>\n      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>\n        <HeartIcon color={theme.color.mediumdark} />\n        <div>Share this with your team.</div>\n        <Button ariaLabel={false} onClick={copyLink} size=\"small\" variant=\"ghost\">\n          {copyText}\n        </Button>\n      </div>\n      {isNotificationsEnabled ? (\n        <Button ariaLabel={false} size=\"small\" variant=\"ghost\" onClick={onToggleNotifications}>\n          <EyeCloseIcon />\n          Hide notifications\n        </Button>\n      ) : (\n        <Button ariaLabel={false} size=\"small\" variant=\"ghost\" onClick={onToggleNotifications}>\n          <EyeIcon />\n          Show notifications\n        </Button>\n      )}\n    </Container>\n  );\n};\n\nconst Iframe = styled.iframe<{ isLoaded: boolean }>(\n  {\n    position: 'absolute',\n    top: 0,\n    left: 0,\n    right: 0,\n    bottom: 0,\n    border: 0,\n    margin: 0,\n    padding: 0,\n    width: '100%',\n    height: 'calc(100% - 40px)',\n    background: 'white',\n  },\n  ({ isLoaded }) => ({ visibility: isLoaded ? 'visible' : 'hidden' })\n);\n\nconst AlertIcon = styled(((props) => <AlertIconSvg {...props} />) as FC<\n  Omit<ComponentProps<typeof AlertIconSvg>, 'icon'>\n>)(({ theme }) => ({\n  color: theme.textMutedColor,\n  width: 32,\n  height: 32,\n  margin: '0 auto',\n}));\n\nconst WhatsNewLoader: FC = () => (\n  <Centered>\n    <LoaderWrapper>\n      <Loader />\n    </LoaderWrapper>\n    <Message>Loading...</Message>\n  </Centered>\n);\n\nconst MaxWaitTimeMessaging: FC = () => (\n  <Centered>\n    <AlertIcon />\n    <Message>The page couldn't be loaded. Check your internet connection and try again.</Message>\n  </Centered>\n);\n\nexport interface WhatsNewProps {\n  didHitMaxWaitTime: boolean;\n  isLoaded: boolean;\n  onLoad: () => void;\n  url?: string;\n  isNotificationsEnabled: boolean;\n  onCopyLink?: () => void;\n  onToggleNotifications?: () => void;\n}\n\nconst PureWhatsNewScreen: FC<WhatsNewProps> = ({\n  didHitMaxWaitTime,\n  isLoaded,\n  onLoad,\n  url,\n  onCopyLink,\n  onToggleNotifications,\n  isNotificationsEnabled,\n}) => (\n  <Fragment>\n    {!isLoaded && !didHitMaxWaitTime && <WhatsNewLoader />}\n    {didHitMaxWaitTime ? (\n      <MaxWaitTimeMessaging />\n    ) : (\n      <>\n        <Iframe isLoaded={isLoaded} onLoad={onLoad} src={url} title={`What's new?`} />\n        <WhatsNewFooter\n          isNotificationsEnabled={isNotificationsEnabled}\n          onToggleNotifications={onToggleNotifications}\n          onCopyLink={onCopyLink}\n        />\n      </>\n    )}\n  </Fragment>\n);\n\nconst MAX_WAIT_TIME = 10000; // 10 seconds\n\nconst WhatsNewScreen: FC = () => {\n  const api = useStorybookApi();\n  const state = useStorybookState();\n  const { whatsNewData } = state;\n  const [isLoaded, setLoaded] = useState(false);\n  const [didHitMaxWaitTime, setDidHitMaxWaitTime] = useState(false);\n\n  useEffect(() => {\n    const timer = setTimeout(() => !isLoaded && setDidHitMaxWaitTime(true), MAX_WAIT_TIME);\n    return () => clearTimeout(timer);\n  }, [isLoaded]);\n\n  if (whatsNewData?.status !== 'SUCCESS') {\n    return null;\n  }\n\n  const isNotificationsEnabled = !whatsNewData.disableWhatsNewNotifications;\n\n  return (\n    <PureWhatsNewScreen\n      didHitMaxWaitTime={didHitMaxWaitTime}\n      isLoaded={isLoaded}\n      onLoad={() => {\n        api.whatsNewHasBeenRead();\n        setLoaded(true);\n      }}\n      url={whatsNewData.url}\n      isNotificationsEnabled={isNotificationsEnabled}\n      onCopyLink={() => {\n        // eslint-disable-next-line compat/compat\n        navigator.clipboard?.writeText(whatsNewData.blogUrl ?? whatsNewData.url);\n      }}\n      onToggleNotifications={() => {\n        if (isNotificationsEnabled) {\n          if (global.confirm('All update notifications will no longer be shown. Are you sure?')) {\n            api.toggleWhatsNewNotifications();\n          }\n        } else {\n          api.toggleWhatsNewNotifications();\n        }\n      }}\n    />\n  );\n};\n\nexport { WhatsNewScreen, PureWhatsNewScreen };\n"
  },
  {
    "path": "code/core/src/manager/settings/whats_new_footer.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { WhatsNewFooter } from './whats_new.tsx';\n\nconst meta = {\n  component: WhatsNewFooter,\n} satisfies Meta<typeof WhatsNewFooter>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {\n  args: {\n    isNotificationsEnabled: false,\n  },\n  parameters: {\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/ur4kydUbRqdDyfoZWzdiIw/Storybook-app?type=design&node-id=9562-117308&mode=design&t=dJUhQrYPI3PCqPg2-4',\n    },\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager/settings/whats_new_page.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { WhatsNewScreen } from './whats_new.tsx';\n\nconst WhatsNewPage: FC = () => {\n  return <WhatsNewScreen />;\n};\n\nexport { WhatsNewPage };\n"
  },
  {
    "path": "code/core/src/manager/typings.d.ts",
    "content": "declare var DOCS_OPTIONS: any;\ndeclare var CONFIG_TYPE: 'DEVELOPMENT' | 'PRODUCTION';\ndeclare var PREVIEW_URL: any;\n/**\n * The network address of the Storybook instance. Used by Storybook to generate a QR code so users\n * can access the story on mobile devices.\n */\ndeclare var STORYBOOK_NETWORK_ADDRESS: string | undefined;\n\ndeclare var __STORYBOOK_ADDONS_MANAGER: any;\ndeclare var RELEASE_NOTES_DATA: any;\n\ndeclare var FEATURES: import('storybook/internal/types').StorybookConfigRaw['features'];\n\ndeclare var REFS: any;\ndeclare var VERSIONCHECK: any;\ndeclare var LOGLEVEL: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent' | undefined;\n\ndeclare var __REACT__: any;\ndeclare var __REACT_DOM__: any;\ndeclare var __REACT_DOM_CLIENT__: any;\ndeclare var __STORYBOOK_COMPONENTS__: any;\ndeclare var __STORYBOOK_CHANNELS__: any;\ndeclare var __STORYBOOK_CORE_EVENTS__: any;\ndeclare var __STORYBOOK_CORE_EVENTS_MANAGER_ERRORS__: any;\ndeclare var __STORYBOOK_ROUTER__: any;\ndeclare var __STORYBOOK_THEMING__: any;\ndeclare var __STORYBOOK_THEMING_CREATE__: any;\ndeclare var __STORYBOOK_TEST__: any;\ndeclare var __STORYBOOK_ACTIONS__: any;\ndeclare var __STORYBOOK_API__: any;\ndeclare var __STORYBOOK_ICONS__: any;\ndeclare var __STORYBOOK_CLIENT_LOGGER__: any;\ndeclare var __STORYBOOK_ADDONS_CHANNEL__: any;\ndeclare var __STORYBOOK_TYPES__: any;\ndeclare var STORYBOOK_RENDERER: string | undefined;\ndeclare var sendTelemetryError: (error: any) => void;\n"
  },
  {
    "path": "code/core/src/manager/utils/prepareForTelemetry.ts",
    "content": "/* eslint-disable local-rules/no-uncategorized-errors */\nimport { UncaughtManagerError } from 'storybook/internal/manager-errors';\n\nimport { global } from '@storybook/global';\n\nimport type { BrowserInfo } from 'browser-dtector';\nimport BrowserDetector from 'browser-dtector';\n\nlet browserInfo: BrowserInfo | undefined;\n\nfunction getBrowserInfo() {\n  if (!browserInfo) {\n    browserInfo = new BrowserDetector(global.navigator?.userAgent).getBrowserInfo();\n  }\n\n  return browserInfo;\n}\n\n// If you're adding errors to filter, please explain why they should be filtered.\nconst errorMessages = [\n  // It's a harmless issue with react-resize-detector that supposedly will be gone when we move to React 18.\n  // https://github.com/maslianok/react-resize-detector/issues/45#issuecomment-1500958024\n  'ResizeObserver loop completed with undelivered notifications.',\n  'ResizeObserver loop limit exceeded',\n  // Safari does not seem to provide any helpful info on window.onerror\n  // https://bugs.webkit.org/show_bug.cgi?id=132945\n  'Script error.',\n  // When react-dev-tools is installed as a browser extension, it will log this error\n  'React is running in production mode',\n];\n\nexport const shouldSkipError = (error: Error) => errorMessages.includes(error?.message);\n\nexport function prepareForTelemetry(\n  originalError: Error & {\n    fromStorybook?: boolean;\n    category?: string;\n    target?: any;\n    currentTarget?: any;\n    srcElement?: any;\n    browserInfo?: BrowserInfo;\n  }\n) {\n  let error = originalError;\n\n  // DOM manipulation errors and other similar errors are not serializable as they contain\n  // circular references to the window object. If that's the case, we make a simplified copy\n  if (\n    originalError.target === global ||\n    originalError.currentTarget === global ||\n    originalError.srcElement === global\n  ) {\n    error = new Error(originalError.message);\n    error.name = originalError.name || error.name;\n  }\n\n  if (!originalError.fromStorybook) {\n    error = new UncaughtManagerError({ error });\n  }\n\n  error.browserInfo = getBrowserInfo();\n\n  return error;\n}\n"
  },
  {
    "path": "code/core/src/manager/utils/status.test.ts",
    "content": "// @vitest-environment happy-dom\nimport { describe, expect, it } from 'vitest';\n\nimport { mockDataset } from '../components/sidebar/mockdata.ts';\nimport { getGroupStatus, getMostCriticalStatusValue } from './status.tsx';\n\ndescribe('getHighestStatus', () => {\n  it('default value', () => {\n    expect(getMostCriticalStatusValue([])).toBe('status-value:unknown');\n  });\n  it('should return the highest status', () => {\n    expect(\n      getMostCriticalStatusValue([\n        'status-value:success',\n        'status-value:error',\n        'status-value:warning',\n        'status-value:pending',\n      ])\n    ).toBe('status-value:error');\n    expect(\n      getMostCriticalStatusValue([\n        'status-value:error',\n        'status-value:error',\n        'status-value:warning',\n        'status-value:pending',\n      ])\n    ).toBe('status-value:error');\n    expect(getMostCriticalStatusValue(['status-value:warning', 'status-value:pending'])).toBe(\n      'status-value:warning'\n    );\n  });\n  it('should rank new and modified between success and warning', () => {\n    expect(\n      getMostCriticalStatusValue([\n        'status-value:new',\n        'status-value:modified',\n        'status-value:success',\n      ])\n    ).toBe('status-value:new');\n  });\n  it('should rank warning above new', () => {\n    expect(getMostCriticalStatusValue(['status-value:new', 'status-value:warning'])).toBe(\n      'status-value:warning'\n    );\n  });\n\n  it('should rank affected below modified and below warning', () => {\n    expect(\n      getMostCriticalStatusValue([\n        'status-value:affected',\n        'status-value:modified',\n        'status-value:success',\n      ])\n    ).toBe('status-value:modified');\n\n    expect(getMostCriticalStatusValue(['status-value:modified', 'status-value:warning'])).toBe(\n      'status-value:warning'\n    );\n  });\n});\n\ndescribe('getGroupStatus', () => {\n  it('empty case', () => {\n    expect(getGroupStatus({}, {})).toEqual({});\n  });\n  it('should return a color', () => {\n    expect(\n      getGroupStatus(mockDataset.withRoot, {\n        'group-1--child-b1': {\n          a: {\n            storyId: 'group-1--child-b1',\n            typeId: 'a',\n            value: 'status-value:warning',\n            description: '',\n            title: '',\n          },\n        },\n      })\n    ).toMatchInlineSnapshot(`\n      {\n        \"group-1\": \"status-value:warning\",\n        \"group-1--child-b1\": \"status-value:unknown\",\n        \"group-1--child-b2\": \"status-value:unknown\",\n        \"root-1-child-a1\": \"status-value:unknown\",\n        \"root-1-child-a2\": \"status-value:unknown\",\n        \"root-1-child-a2--grandchild-a1-1\": \"status-value:unknown\",\n        \"root-1-child-a2--grandchild-a1-1:test1\": \"status-value:unknown\",\n        \"root-1-child-a2--grandchild-a1-2\": \"status-value:unknown\",\n        \"root-3--child-a1\": \"status-value:unknown\",\n        \"root-3-child-a2\": \"status-value:unknown\",\n        \"root-3-child-a2--grandchild-a1-1\": \"status-value:unknown\",\n        \"root-3-child-a2--grandchild-a1-2\": \"status-value:unknown\",\n      }\n    `);\n  });\n  it('should return the highest status', () => {\n    expect(\n      getGroupStatus(mockDataset.withRoot, {\n        'group-1--child-b1': {\n          a: {\n            storyId: 'group-1--child-b1',\n            typeId: 'a',\n            value: 'status-value:warning',\n            description: '',\n            title: '',\n          },\n          b: {\n            storyId: 'group-1--child-b1',\n            typeId: 'b',\n            value: 'status-value:error',\n            description: '',\n            title: '',\n          },\n        },\n      })\n    ).toMatchInlineSnapshot(`\n      {\n        \"group-1\": \"status-value:error\",\n        \"group-1--child-b1\": \"status-value:unknown\",\n        \"group-1--child-b2\": \"status-value:unknown\",\n        \"root-1-child-a1\": \"status-value:unknown\",\n        \"root-1-child-a2\": \"status-value:unknown\",\n        \"root-1-child-a2--grandchild-a1-1\": \"status-value:unknown\",\n        \"root-1-child-a2--grandchild-a1-1:test1\": \"status-value:unknown\",\n        \"root-1-child-a2--grandchild-a1-2\": \"status-value:unknown\",\n        \"root-3--child-a1\": \"status-value:unknown\",\n        \"root-3-child-a2\": \"status-value:unknown\",\n        \"root-3-child-a2--grandchild-a1-1\": \"status-value:unknown\",\n        \"root-3-child-a2--grandchild-a1-2\": \"status-value:unknown\",\n      }\n    `);\n  });\n  it('should propagate status-value:new through group aggregation', () => {\n    expect(\n      getGroupStatus(mockDataset.withRoot, {\n        'group-1--child-b1': {\n          a: {\n            storyId: 'group-1--child-b1',\n            typeId: 'a',\n            value: 'status-value:new',\n            description: '',\n            title: '',\n          },\n        },\n      })\n    ).toMatchInlineSnapshot(`\n      {\n        \"group-1\": \"status-value:new\",\n        \"group-1--child-b1\": \"status-value:unknown\",\n        \"group-1--child-b2\": \"status-value:unknown\",\n        \"root-1-child-a1\": \"status-value:unknown\",\n        \"root-1-child-a2\": \"status-value:unknown\",\n        \"root-1-child-a2--grandchild-a1-1\": \"status-value:unknown\",\n        \"root-1-child-a2--grandchild-a1-1:test1\": \"status-value:unknown\",\n        \"root-1-child-a2--grandchild-a1-2\": \"status-value:unknown\",\n        \"root-3--child-a1\": \"status-value:unknown\",\n        \"root-3-child-a2\": \"status-value:unknown\",\n        \"root-3-child-a2--grandchild-a1-1\": \"status-value:unknown\",\n        \"root-3-child-a2--grandchild-a1-2\": \"status-value:unknown\",\n      }\n    `);\n  });\n  it('should propagate status-value:affected through group aggregation', () => {\n    expect(\n      getGroupStatus(mockDataset.withRoot, {\n        'group-1--child-b1': {\n          a: {\n            storyId: 'group-1--child-b1',\n            typeId: 'a',\n            value: 'status-value:affected',\n            description: '',\n            title: '',\n          },\n        },\n      })\n    ).toMatchInlineSnapshot(`\n      {\n        \"group-1\": \"status-value:affected\",\n        \"group-1--child-b1\": \"status-value:unknown\",\n        \"group-1--child-b2\": \"status-value:unknown\",\n        \"root-1-child-a1\": \"status-value:unknown\",\n        \"root-1-child-a2\": \"status-value:unknown\",\n        \"root-1-child-a2--grandchild-a1-1\": \"status-value:unknown\",\n        \"root-1-child-a2--grandchild-a1-1:test1\": \"status-value:unknown\",\n        \"root-1-child-a2--grandchild-a1-2\": \"status-value:unknown\",\n        \"root-3--child-a1\": \"status-value:unknown\",\n        \"root-3-child-a2\": \"status-value:unknown\",\n        \"root-3-child-a2--grandchild-a1-1\": \"status-value:unknown\",\n        \"root-3-child-a2--grandchild-a1-2\": \"status-value:unknown\",\n      }\n    `);\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager/utils/status.tsx",
    "content": "import type { ReactElement } from 'react';\nimport React from 'react';\n\nimport type { StatusValue } from 'storybook/internal/types';\nimport { type API_HashEntry, type StatusesByStoryIdAndTypeId } from 'storybook/internal/types';\n\nimport { CircleIcon } from '@storybook/icons';\n\nimport memoizerific from 'memoizerific';\nimport { transparentize } from 'polished';\nimport { type Theme, styled } from 'storybook/theming';\n\nimport { UseSymbol } from '../components/sidebar/IconSymbols.tsx';\nimport { getDescendantIds } from './tree.ts';\n\nconst SmallIcons = styled(CircleIcon)({\n  // specificity hack\n  '&&&': {\n    width: 6,\n    height: 6,\n  },\n});\n\nconst LoadingIcons = styled(SmallIcons)(({ theme: { animation } }) => ({\n  // specificity hack\n  animation: `${animation.glow} 1.5s ease-in-out infinite`,\n}));\n\nexport interface StatusMapping {\n  icon: ReactElement | null;\n  iconColor: string | null;\n  textColor: string | null;\n}\n\nexport const statusPriority: StatusValue[] = [\n  'status-value:unknown',\n  'status-value:pending',\n  'status-value:success',\n  'status-value:affected',\n  'status-value:modified',\n  'status-value:new',\n  'status-value:warning',\n  'status-value:error',\n];\n\n// We might not want to make this a hook because it is used in the Tree after multiple returns.\n// There could be scenarios where creating a story changes the type of an item (e.g. story now\n// has children because it has a test child), so we could end up with rule of hooks violations.\nexport const getStatus = memoizerific(10)((theme: Theme, status: StatusValue): StatusMapping => {\n  const defaultIconColor =\n    theme.base === 'light'\n      ? transparentize(0.3, theme.color.defaultText)\n      : transparentize(0.6, theme.color.defaultText);\n\n  const statusMapping: Record<StatusValue, StatusMapping> = {\n    'status-value:unknown': {\n      icon: null,\n      iconColor: defaultIconColor,\n      textColor: null,\n    },\n    'status-value:pending': {\n      icon: <LoadingIcons key=\"icon\" />,\n      iconColor: defaultIconColor,\n      textColor: 'currentColor',\n    },\n    'status-value:success': {\n      icon: (\n        <svg key=\"icon\" viewBox=\"0 0 14 14\" width=\"14\" height=\"14\">\n          <UseSymbol type=\"success\" />\n        </svg>\n      ),\n      iconColor: theme.color.positive,\n      textColor: 'currentColor',\n    },\n    'status-value:new': {\n      icon: (\n        <svg key=\"icon\" viewBox=\"0 0 14 14\" width=\"14\" height=\"14\">\n          <UseSymbol type=\"new\" />\n        </svg>\n      ),\n      iconColor: theme.fgColor.accent,\n      textColor: null,\n    },\n    'status-value:modified': {\n      icon: (\n        <svg key=\"icon\" viewBox=\"0 0 14 14\" width=\"14\" height=\"14\">\n          <UseSymbol type=\"modified\" />\n        </svg>\n      ),\n      iconColor: theme.fgColor.accent,\n      textColor: null,\n    },\n    'status-value:affected': {\n      icon: (\n        <svg key=\"icon\" viewBox=\"0 0 14 14\" width=\"14\" height=\"14\">\n          <UseSymbol type=\"affected\" />\n        </svg>\n      ),\n      iconColor: theme.fgColor.accent,\n      textColor: null,\n    },\n    'status-value:warning': {\n      icon: (\n        <svg key=\"icon\" viewBox=\"0 0 14 14\" width=\"14\" height=\"14\">\n          <UseSymbol type=\"warning\" />\n        </svg>\n      ),\n      iconColor: theme.color.warning,\n      textColor: theme.fgColor.warning,\n    },\n    'status-value:error': {\n      icon: (\n        <svg key=\"icon\" viewBox=\"0 0 14 14\" width=\"14\" height=\"14\">\n          <UseSymbol type=\"error\" />\n        </svg>\n      ),\n      iconColor: theme.color.negative,\n      textColor: theme.fgColor.negative,\n    },\n  };\n  return statusMapping[status];\n});\n\nexport const getMostCriticalStatusValue = (statusValues: StatusValue[]): StatusValue => {\n  return statusPriority.reduce(\n    (acc, value) => (statusValues.includes(value) ? value : acc),\n    'status-value:unknown'\n  );\n};\n\nexport function getGroupStatus(\n  collapsedData: {\n    [x: string]: Partial<API_HashEntry>;\n  },\n  allStatuses: StatusesByStoryIdAndTypeId\n): Record<string, StatusValue> {\n  return Object.values(collapsedData).reduce<Record<string, StatusValue>>((acc, item) => {\n    if (item.type === 'group' || item.type === 'component' || item.type === 'story') {\n      // @ts-expect-error (non strict)\n      const leafs = getDescendantIds(collapsedData as any, item.id, false)\n        .map((id) => collapsedData[id])\n        .filter((i) => i.type === 'story');\n\n      const combinedStatus = getMostCriticalStatusValue(\n        // @ts-expect-error (non strict)\n        leafs.flatMap((story) => Object.values(allStatuses[story.id] || {})).map((s) => s.value)\n      );\n\n      if (combinedStatus) {\n        // @ts-expect-error (non strict)\n        acc[item.id] = combinedStatus;\n      }\n    }\n    return acc;\n  }, {});\n}\n"
  },
  {
    "path": "code/core/src/manager/utils/tree.test.js",
    "content": "// @vitest-environment happy-dom\nimport { describe, expect, it } from 'vitest';\n\nimport { mockDataset, mockExpanded, mockSelected } from '../components/sidebar/mockdata';\nimport * as utils from './tree';\n\nconst noRoot = {\n  dataset: mockDataset.noRoot,\n  selected: mockSelected.noRoot,\n  expanded: mockExpanded.noRoot,\n};\n\ndescribe('sanity', () => {\n  it('all exports should be functions', () => {\n    Object.values(utils).forEach((i) => {\n      expect(typeof i).toBe('function');\n    });\n  });\n});\n\ndescribe('createId', () => {\n  it('creates an id', () => {\n    const inputs = ['testpath', 'testref'];\n    const output = utils.createId(...inputs);\n\n    expect(output).toEqual('testref_testpath');\n  });\n});\n\ndescribe('get', () => {\n  it('retrieved by key', () => {\n    const value = {};\n    const inputs = ['testkey', { testkey: value, x: 'incorrect' }];\n    const output = utils.get(inputs[0], inputs[1]);\n\n    expect(output).toBe(value);\n  });\n  it('retrieve non-existent returns undefined', () => {\n    const value = {};\n    const inputs = ['NONEXISTENT', { testkey: value, x: 'incorrect' }];\n    const output = utils.get(inputs[0], inputs[1]);\n\n    expect(output).toBe(undefined);\n  });\n});\n\ndescribe('getParent', () => {\n  it('retrieved by id (level 0) returns undefined', () => {\n    const output = utils.getParent('group-1', noRoot.dataset);\n    expect(output).toBe(undefined);\n  });\n  it('retrieved by id (level 1) returns correctly', () => {\n    const output = utils.getParent('group-1--child-b1', noRoot.dataset);\n    expect(output).toBe(noRoot.dataset['group-1']);\n  });\n  it('retrieved by id (level 2) returns correctly', () => {\n    const output = utils.getParent('root-1-child-a2--grandchild-a1-1', noRoot.dataset);\n    expect(output).toBe(noRoot.dataset['root-1-child-a2']);\n  });\n  it('retrieve non-existent returns undefined', () => {\n    const output = utils.getParent('NONEXISTENT', noRoot.dataset);\n    expect(output).toBe(undefined);\n  });\n});\n\ndescribe('getParents', () => {\n  it('retrieved by id (level 0) returns correctly', () => {\n    const output = utils.getParents('group-1', noRoot.dataset);\n    expect(output).toEqual([]);\n  });\n  it('retrieved by id (level 1) returns correctly', () => {\n    const output = utils.getParents('group-1--child-b1', noRoot.dataset);\n    expect(output).toEqual([noRoot.dataset['group-1']]);\n  });\n  it('retrieved by id (level 2) returns correctly', () => {\n    const output = utils.getParents('root-1-child-a2--grandchild-a1-1', noRoot.dataset);\n    expect(output).toEqual([noRoot.dataset['root-1-child-a2'], noRoot.dataset['root-1']]);\n  });\n  it('retrieve non-existent returns empty array', () => {\n    const output = utils.getParents('NONEXISTENT', noRoot.dataset);\n    expect(output).toEqual([]);\n  });\n});\n\ndescribe('isStoryHoistable', () => {\n  it('return true for matching Story and Component name', () => {\n    const output = utils.isStoryHoistable('Very_Long-Button Story Name', 'VeryLongButtonStoryName');\n    expect(output).toEqual(true);\n  });\n\n  it('return false for non-matching names', () => {\n    const output = utils.isStoryHoistable('Butto Story', 'ButtonStory');\n    expect(output).toEqual(false);\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager/utils/tree.ts",
    "content": "import type { SyntheticEvent } from 'react';\n\nimport { global } from '@storybook/global';\n\nimport memoize from 'memoizerific';\nimport type { HashEntry, IndexHash } from 'storybook/manager-api';\n\nimport { DEFAULT_REF_ID } from '../components/sidebar/Sidebar.tsx';\nimport type { Dataset, Item, RefType, SearchItem } from '../components/sidebar/types.ts';\n\nconst { document, window: globalWindow } = global;\n\nexport const createId = (itemId: string, refId?: string) =>\n  !refId || refId === DEFAULT_REF_ID ? itemId : `${refId}_${itemId}`;\n\nexport const getLink = (item: HashEntry, refId?: string) => {\n  return `${document.location.pathname}?path=/${item.type}/${createId(item.id, refId)}`;\n};\n\nexport const prevent = (e: SyntheticEvent) => {\n  e.preventDefault();\n  return false;\n};\n\nexport const get = memoize(1000)((id: string, dataset: Dataset) => dataset[id]);\nexport const getParent = memoize(1000)((id: string, dataset: Dataset) => {\n  const item = get(id, dataset);\n  return item && item.type !== 'root' ? get(item.parent as string, dataset) : undefined;\n});\nexport const getParents = memoize(1000)((id: string, dataset: Dataset): Item[] => {\n  const parent = getParent(id, dataset);\n  return parent ? [parent, ...getParents(parent.id, dataset)] : [];\n});\nexport const getAncestorIds = memoize(1000)((data: IndexHash, id: string): string[] =>\n  getParents(id, data).map((item) => item.id)\n);\nexport const getDescendantIds = memoize(1000)((\n  data: IndexHash,\n  id: string,\n  skipLeafs: boolean\n): string[] => {\n  const entry = data[id];\n  if (!entry || !('children' in entry) || !entry.children) {\n    return [];\n  }\n  return entry.children.reduce((acc, childId) => {\n    const child = data[childId];\n\n    if (!child || (skipLeafs && (child.type === 'story' || child.type === 'docs'))) {\n      return acc;\n    }\n    acc.push(childId, ...getDescendantIds(data, childId, skipLeafs));\n    return acc;\n  }, [] as string[]);\n});\n\nexport function getPath(item: Item, ref: Pick<RefType, 'id' | 'title' | 'index'>): string[] {\n  // @ts-expect-error (non strict)\n  const parent = item.type !== 'root' && item.parent ? ref.index[item.parent] : null;\n\n  if (parent) {\n    return [...getPath(parent, ref), parent.name];\n  }\n  return ref.id === DEFAULT_REF_ID ? [] : [ref.title || ref.id];\n}\n\nexport const searchItem = (item: Item, ref: Parameters<typeof getPath>[1]): SearchItem => {\n  return { ...item, refId: ref.id, path: getPath(item, ref) };\n};\n\nexport function cycle<T>(array: T[], index: number, delta: number): number {\n  let next = index + (delta % array.length);\n\n  if (next < 0) {\n    next = array.length + next;\n  }\n\n  if (next >= array.length) {\n    next -= array.length;\n  }\n  return next;\n}\n\nexport const scrollIntoView = (element: Element, center = false) => {\n  if (!element) {\n    return;\n  }\n  const { top, bottom } = element.getBoundingClientRect();\n  if (!top || !bottom) {\n    return;\n  }\n  const bottomOffset =\n    document?.querySelector('#sidebar-bottom-wrapper')?.getBoundingClientRect().top ||\n    globalWindow.innerHeight ||\n    document.documentElement.clientHeight;\n  if (bottom > bottomOffset) {\n    element.scrollIntoView({ block: center ? 'center' : 'nearest' });\n  }\n};\n\nexport const getStateType = (\n  isLoading: boolean,\n  isAuthRequired: boolean,\n  isError: boolean,\n  isEmpty: boolean\n) => {\n  switch (true) {\n    case isAuthRequired:\n      return 'auth';\n    case isError:\n      return 'error';\n    case isLoading:\n      return 'loading';\n    case isEmpty:\n      return 'empty';\n    default:\n      return 'ready';\n  }\n};\n\nexport const isAncestor = (element?: Element, maybeAncestor?: Element): boolean => {\n  if (!element || !maybeAncestor) {\n    return false;\n  }\n\n  if (element === maybeAncestor) {\n    return true;\n  }\n  return isAncestor(element.parentElement || undefined, maybeAncestor);\n};\n\nexport const removeNoiseFromName = (storyName: string) => storyName.replaceAll(/(\\s|-|_)/gi, '');\n\nexport const isStoryHoistable = (storyName: string, componentName: string) =>\n  removeNoiseFromName(storyName) === removeNoiseFromName(componentName);\n"
  },
  {
    "path": "code/core/src/manager/utils/trySelectStory.ts",
    "content": "export async function trySelectStory(\n  selectStory: (id?: string) => void,\n  storyId?: string,\n  attempt = 1\n): Promise<void> {\n  if (attempt > 10) {\n    throw new Error('We could not select the new story. Please try again.');\n  }\n\n  try {\n    selectStory(storyId);\n  } catch {\n    await new Promise((resolve) => setTimeout(resolve, 500));\n    return trySelectStory(selectStory, storyId, attempt + 1);\n  }\n}\n"
  },
  {
    "path": "code/core/src/manager-api/context.ts",
    "content": "import { createContext as ReactCreateContext } from 'react';\n\nimport type { Combo } from './root.tsx';\n\nexport const createContext = ({ api, state }: Combo) => ReactCreateContext({ api, state });\n"
  },
  {
    "path": "code/core/src/manager-api/index.mock.ts",
    "content": "import { fn } from 'storybook/test';\n\nexport * from './root.tsx';\nexport { Tag } from '../shared/constants/tags.ts';\n\nexport const openInEditor = fn();\n\nexport { UniversalStore as experimental_UniversalStore } from '../shared/universal-store/index.ts';\nexport { useUniversalStore as experimental_useUniversalStore } from '../shared/universal-store/use-universal-store-manager.ts';\nexport { MockUniversalStore as experimental_MockUniversalStore } from '../shared/universal-store/mock.ts';\n\nexport {\n  getStatusStoreByTypeId as experimental_getStatusStore,\n  useStatusStore as experimental_useStatusStore,\n  fullStatusStore as internal_fullStatusStore,\n  universalStatusStore as internal_universalStatusStore,\n} from './stores/__mocks__/status.ts';\nexport {\n  getTestProviderStoreById as experimental_getTestProviderStore,\n  useTestProviderStore as experimental_useTestProviderStore,\n  fullTestProviderStore as internal_fullTestProviderStore,\n  universalTestProviderStore as internal_universalTestProviderStore,\n} from './stores/__mocks__/test-provider.ts';\n"
  },
  {
    "path": "code/core/src/manager-api/index.ts",
    "content": "export * from './root.tsx';\n\nexport { UniversalStore as experimental_UniversalStore } from '../shared/universal-store/index.ts';\nexport { useUniversalStore as experimental_useUniversalStore } from '../shared/universal-store/use-universal-store-manager.ts';\nexport { MockUniversalStore as experimental_MockUniversalStore } from '../shared/universal-store/mock.ts';\n\nexport {\n  getStatusStoreByTypeId as experimental_getStatusStore,\n  useStatusStore as experimental_useStatusStore,\n  fullStatusStore as internal_fullStatusStore,\n  universalStatusStore as internal_universalStatusStore,\n} from './stores/status.ts';\n\nexport {\n  getTestProviderStoreById as experimental_getTestProviderStore,\n  useTestProviderStore as experimental_useTestProviderStore,\n  fullTestProviderStore as internal_fullTestProviderStore,\n  universalTestProviderStore as internal_universalTestProviderStore,\n} from './stores/test-provider.ts';\n\nexport {\n  checklistStore as internal_checklistStore,\n  universalChecklistStore as internal_universalChecklistStore,\n} from './stores/checklist.ts';\n\nexport { Tag } from '../shared/constants/tags.ts';\n"
  },
  {
    "path": "code/core/src/manager-api/initial-state.ts",
    "content": "import merge from './lib/merge.ts';\nimport type { State } from './root.tsx';\n\ninterface Addition {\n  [key: string]: any;\n}\ntype Additions = Addition[];\n\n// Returns the initialState of the app\nconst main = (...additions: Additions): State =>\n  additions.reduce((acc: State, item) => merge<State>(acc, item), {} as any);\n\nexport default main;\n"
  },
  {
    "path": "code/core/src/manager-api/lib/addons.ts",
    "content": "import type { Channel } from 'storybook/internal/channels';\nimport { logger } from 'storybook/internal/client-logger';\nimport { SET_CONFIG } from 'storybook/internal/core-events';\nimport type {\n  Addon_BaseType,\n  Addon_Collection,\n  Addon_Config,\n  Addon_Elements,\n  Addon_Loaders,\n  Addon_PageType,\n  Addon_TestProviderType,\n  Addon_Type,\n  Addon_Types,\n  Addon_TypesMapping,\n  Addon_WrapperType,\n} from 'storybook/internal/types';\nimport { Addon_TypesEnum } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport type { API } from '../root.tsx';\nimport { mockChannel } from './storybook-channel-mock.ts';\n\nexport type { Addon_Type as Addon };\nexport { Addon_TypesEnum as types };\n\nexport function isSupportedType(type: Addon_Types): boolean {\n  return !!Object.values(Addon_TypesEnum).find((typeVal) => typeVal === type);\n}\n\nexport class AddonStore {\n  constructor() {\n    this.promise = new Promise((res) => {\n      this.resolve = () => res(this.getChannel());\n    }) as Promise<Channel>;\n  }\n\n  private loaders: Addon_Loaders<API> = {};\n\n  private elements: Addon_Elements = {};\n\n  private config: Addon_Config = {};\n\n  private channel: Channel | undefined;\n\n  private promise: any;\n\n  private resolve: any;\n\n  getChannel = (): Channel => {\n    // this.channel should get overwritten by setChannel. If it wasn't called (e.g. in non-browser environment), set a mock instead.\n    if (!this.channel) {\n      this.setChannel(mockChannel());\n    }\n\n    return this.channel!;\n  };\n\n  ready = (): Promise<Channel> => this.promise;\n\n  hasChannel = (): boolean => !!this.channel;\n\n  setChannel = (channel: Channel): void => {\n    this.channel = channel;\n    this.resolve();\n  };\n\n  getElements<\n    T extends\n      | Addon_Types\n      | Addon_TypesEnum.experimental_PAGE\n      | Addon_TypesEnum.experimental_TEST_PROVIDER,\n  >(type: T): Addon_Collection<Addon_TypesMapping[T]> | any {\n    if (!this.elements[type]) {\n      this.elements[type] = {};\n    }\n    return this.elements[type];\n  }\n\n  /**\n   * Adds an addon to the addon store.\n   *\n   * @param {string} id - The id of the addon.\n   * @param {Addon_Type} addon - The addon to add.\n   * @returns {void}\n   */\n  add(\n    id: string,\n    addon:\n      | Addon_BaseType\n      | Omit<Addon_TestProviderType, 'id'>\n      | Omit<Addon_PageType, 'id'>\n      | Omit<Addon_WrapperType, 'id'>\n  ): void {\n    const { type } = addon;\n    const collection = this.getElements(type);\n    collection[id] = { ...addon, id };\n  }\n\n  setConfig = (value: Addon_Config) => {\n    Object.assign(this.config, value);\n    if (this.hasChannel()) {\n      this.getChannel().emit(SET_CONFIG, this.config);\n    } else {\n      this.ready().then((channel) => {\n        channel.emit(SET_CONFIG, this.config);\n      });\n    }\n  };\n\n  getConfig = () => this.config;\n\n  /**\n   * Registers an addon loader function.\n   *\n   * @param {string} id - The id of the addon loader.\n   * @param {(api: API) => void} callback - The function that will be called to register the addon.\n   * @returns {void}\n   */\n  register = (id: string, callback: (api: API) => void): void => {\n    if (this.loaders[id]) {\n      logger.warn(`${id} was loaded twice, this could have bad side-effects`);\n    }\n    this.loaders[id] = callback;\n  };\n\n  loadAddons = (api: any) => {\n    Object.values(this.loaders).forEach((value: any) => value(api));\n  };\n\n  experimental_getRegisteredAddons() {\n    return Object.keys(this.loaders);\n  }\n}\n\n// Enforce addons store to be a singleton\nconst KEY = '__STORYBOOK_ADDONS_MANAGER';\n\nfunction getAddonsStore(): AddonStore {\n  if (!global[KEY]) {\n    global[KEY] = new AddonStore();\n  }\n  return global[KEY];\n}\n\nexport const addons = getAddonsStore();\n\nexport { mockChannel };\n"
  },
  {
    "path": "code/core/src/manager-api/lib/events.ts",
    "content": "import { logger } from 'storybook/internal/client-logger';\nimport type { API_ComposedRef } from 'storybook/internal/types';\n\nimport { getSourceType } from '../modules/refs.ts';\nimport type { API } from '../root.tsx';\n\ninterface Meta {\n  ref?: API_ComposedRef;\n  source?: string;\n  sourceType?: 'local' | 'external';\n  sourceLocation?: string;\n  refId?: string;\n  v?: number;\n  type: string;\n}\n\nexport const getEventMetadata = (context: Meta, fullAPI: API) => {\n  const { source, refId, type } = context;\n  const [sourceType, sourceLocation] = getSourceType(source!, refId);\n\n  let ref: API_ComposedRef | undefined;\n  if (refId || sourceType === 'external') {\n    ref =\n      refId && fullAPI.getRefs()[refId]\n        ? fullAPI.getRefs()[refId]\n        : fullAPI.findRef(sourceLocation!);\n  }\n  const meta = {\n    source,\n    sourceType,\n    sourceLocation,\n    refId,\n    ref,\n    type,\n  };\n\n  switch (true) {\n    case typeof refId === 'string':\n    case sourceType === 'local':\n    case sourceType === 'external': {\n      return meta;\n    }\n\n    // if we couldn't find the source, something risky happened, we ignore the input, and log a warning\n    default: {\n      logger.warn(`Received a ${type} frame that was not configured as a ref`);\n      return null;\n    }\n  }\n};\n"
  },
  {
    "path": "code/core/src/manager-api/lib/intersect.ts",
    "content": "export default <T>(a: T[], b: T[]): T[] => {\n  // no point in intersecting if one of the input is ill-defined\n  if (!Array.isArray(a) || !Array.isArray(b) || !a.length || !b.length) {\n    return [];\n  }\n\n  return a.reduce((acc: T[], aValue) => {\n    if (b.includes(aValue)) {\n      acc.push(aValue);\n    }\n\n    return acc;\n  }, []);\n};\n"
  },
  {
    "path": "code/core/src/manager-api/lib/merge.ts",
    "content": "import { logger } from 'storybook/internal/client-logger';\n\nimport { mergeWith } from 'es-toolkit/object';\nimport { isEqual } from 'es-toolkit/predicate';\n\nexport default <TObj = any>(a: TObj, ...b: Partial<TObj>[]): TObj => {\n  // start with empty object\n  let target = {};\n\n  // merge object a unto target\n  target = mergeWith(\n    {},\n    a as Record<PropertyKey, any>,\n    (objValue: TObj, srcValue: Partial<TObj>) => {\n      if (Array.isArray(srcValue) && Array.isArray(objValue)) {\n        srcValue.forEach((s) => {\n          const existing = objValue.find((o) => o === s || isEqual(o, s));\n          if (!existing) {\n            objValue.push(s);\n          }\n        });\n\n        return objValue;\n      }\n      if (Array.isArray(objValue)) {\n        logger.log(['the types mismatch, picking', objValue]);\n        return objValue;\n      }\n    }\n  );\n\n  for (const obj of b) {\n    // merge object b unto target\n    target = mergeWith(target, obj, (objValue: TObj, srcValue: Partial<TObj>) => {\n      if (Array.isArray(srcValue) && Array.isArray(objValue)) {\n        srcValue.forEach((s) => {\n          const existing = objValue.find((o) => o === s || isEqual(o, s));\n          if (!existing) {\n            objValue.push(s);\n          }\n        });\n\n        return objValue;\n      }\n      if (Array.isArray(objValue)) {\n        logger.log(['the types mismatch, picking', objValue]);\n        return objValue;\n      }\n    });\n  }\n\n  return target as TObj;\n};\n\nexport const noArrayMerge = <TObj = any>(a: TObj, ...b: Partial<TObj>[]): TObj => {\n  // start with empty object\n  let target = {};\n\n  // merge object a unto target\n  target = mergeWith(\n    {},\n    a as Record<PropertyKey, any>,\n    (objValue: TObj, srcValue: Partial<TObj>) => {\n      // Treat arrays as scalars:\n      if (Array.isArray(srcValue)) {\n        return srcValue;\n      }\n    }\n  );\n\n  for (const obj of b) {\n    // merge object b unto target\n    target = mergeWith(target, obj, (objValue: TObj, srcValue: Partial<TObj>) => {\n      // Treat arrays as scalars:\n      if (Array.isArray(srcValue)) {\n        return srcValue;\n      }\n    });\n  }\n\n  return target as TObj;\n};\n"
  },
  {
    "path": "code/core/src/manager-api/lib/platform.ts",
    "content": "import { global } from '@storybook/global';\n\nconst { navigator } = global;\n\nexport const isMacLike = () =>\n  navigator && navigator.platform ? !!navigator.platform.match(/(Mac|iPhone|iPod|iPad)/i) : false;\n"
  },
  {
    "path": "code/core/src/manager-api/lib/request-response.ts",
    "content": "import type { Channel } from 'storybook/internal/channels';\nimport type { RequestData, ResponseData } from 'storybook/internal/core-events';\n\nexport class RequestResponseError<Payload extends Record<string, any> | void> extends Error {\n  payload: Payload | undefined = undefined;\n\n  constructor(message: string, payload?: Payload) {\n    super(message);\n    this.payload = payload;\n  }\n}\n\nexport const experimental_requestResponse = <\n  RequestPayload,\n  ResponsePayload = void,\n  CreateNewStoryErrorPayload extends Record<string, any> | void = void,\n>(\n  channel: Channel,\n  requestEvent: string,\n  responseEvent: string,\n  payload: RequestPayload,\n  timeout = 5000\n): Promise<ResponsePayload> => {\n  let timeoutId: ReturnType<typeof setTimeout>;\n\n  return new Promise((resolve, reject) => {\n    const request: RequestData<typeof payload> = {\n      id: Math.random().toString(16).slice(2),\n      payload,\n    };\n\n    const responseHandler = (\n      response: ResponseData<ResponsePayload, CreateNewStoryErrorPayload>\n    ) => {\n      if (response.id !== request.id) {\n        return;\n      }\n      clearTimeout(timeoutId);\n      channel.off(responseEvent, responseHandler);\n\n      if (response.success) {\n        resolve(response.payload);\n      } else {\n        reject(new RequestResponseError(response.error, response.payload));\n      }\n    };\n\n    channel.emit(requestEvent, request);\n    channel.on(responseEvent, responseHandler);\n\n    timeoutId = setTimeout(() => {\n      channel.off(responseEvent, responseHandler);\n      reject(new RequestResponseError('Timed out waiting for response'));\n    }, timeout);\n  });\n};\n"
  },
  {
    "path": "code/core/src/manager-api/lib/shortcut.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { isMacLike } from './platform.ts';\nimport type { KeyboardEventLike } from './shortcut.ts';\nimport {\n  controlOrMetaKey,\n  controlOrMetaSymbol,\n  eventMatchesShortcut,\n  eventToShortcut,\n  isShortcutTaken,\n  keyToSymbol,\n  optionOrAltSymbol,\n  shortcutMatchesShortcut,\n  shortcutToHumanString,\n} from './shortcut.ts';\n\n// Mock the functions directly\nvi.mock('./platform', async () => {\n  return {\n    isMacLike: vi.fn(),\n  };\n});\n\ndescribe('shortcut', () => {\n  beforeEach(() => {\n    vi.mocked(isMacLike).mockReset();\n  });\n\n  describe('platform detection', () => {\n    it('isMacLike can be mocked', () => {\n      vi.mocked(isMacLike).mockReturnValue(true);\n      expect(isMacLike()).toBe(true);\n\n      vi.mocked(isMacLike).mockReturnValue(false);\n      expect(isMacLike()).toBe(false);\n    });\n\n    it('controlOrMetaSymbol returns correct symbol based on platform', () => {\n      // For Mac\n      vi.mocked(isMacLike).mockReturnValue(true);\n      expect(controlOrMetaSymbol()).toBe('⌘');\n\n      // For non-Mac\n      vi.mocked(isMacLike).mockReturnValue(false);\n      expect(controlOrMetaSymbol()).toBe('ctrl');\n    });\n\n    it('controlOrMetaKey returns correct key based on platform', () => {\n      // For Mac\n      vi.mocked(isMacLike).mockReturnValue(true);\n      expect(controlOrMetaKey()).toBe('meta');\n\n      // For non-Mac\n      vi.mocked(isMacLike).mockReturnValue(false);\n      expect(controlOrMetaKey()).toBe('control');\n    });\n\n    it('optionOrAltSymbol returns correct symbol based on platform', () => {\n      // For Mac\n      vi.mocked(isMacLike).mockReturnValue(true);\n      expect(optionOrAltSymbol()).toBe('⌥');\n\n      // For non-Mac\n      vi.mocked(isMacLike).mockReturnValue(false);\n      expect(optionOrAltSymbol()).toBe('alt');\n    });\n  });\n\n  describe('isShortcutTaken', () => {\n    it('returns true for identical shortcuts', () => {\n      expect(isShortcutTaken(['alt', 'K'], ['alt', 'K'])).toBe(true);\n    });\n\n    it('returns false for different shortcuts', () => {\n      expect(isShortcutTaken(['alt', 'K'], ['alt', 'J'])).toBe(false);\n      expect(isShortcutTaken(['alt', 'K'], ['meta', 'K'])).toBe(false);\n      expect(isShortcutTaken(['alt', 'K'], ['alt', 'K', 'L'])).toBe(false);\n    });\n  });\n\n  describe('eventToShortcut', () => {\n    it('returns null for meta-only key events and tab', () => {\n      const metaOnlyKeys = ['Meta', 'Alt', 'Control', 'Shift', 'Tab'];\n\n      metaOnlyKeys.forEach((key) => {\n        const event = { key } as KeyboardEventLike;\n        expect(eventToShortcut(event)).toBe(null);\n      });\n    });\n\n    it('processes modifier keys correctly', () => {\n      const event = {\n        key: 'K',\n        altKey: true,\n        ctrlKey: true,\n        metaKey: true,\n        shiftKey: true,\n      } as KeyboardEventLike;\n\n      expect(eventToShortcut(event)).toEqual(['alt', 'control', 'meta', 'shift', 'K']);\n    });\n\n    it('handles single letter keys correctly', () => {\n      const event = {\n        key: 'k',\n      } as KeyboardEventLike;\n\n      expect(eventToShortcut(event)).toEqual(['K']);\n    });\n\n    it('handles space key correctly', () => {\n      const event = {\n        key: ' ',\n      } as KeyboardEventLike;\n\n      expect(eventToShortcut(event)).toEqual(['space']);\n    });\n\n    it('handles escape key correctly', () => {\n      const event = {\n        key: 'Escape',\n      } as KeyboardEventLike;\n\n      expect(eventToShortcut(event)).toEqual(['escape']);\n    });\n\n    it('handles arrow keys correctly', () => {\n      const arrowKeys = ['ArrowRight', 'ArrowDown', 'ArrowUp', 'ArrowLeft'];\n\n      arrowKeys.forEach((key) => {\n        const event = { key } as KeyboardEventLike;\n        expect(eventToShortcut(event)).toEqual([key]);\n      });\n    });\n\n    it('supports different key/code combinations', () => {\n      const event = {\n        key: 'a',\n        code: 'KeyA',\n      } as KeyboardEventLike;\n\n      expect(eventToShortcut(event)).toEqual(['A']);\n\n      // When event.code produces a different value than event.key (e.g., with alt key on Mac)\n      const altEvent = {\n        key: 'å', // A special character\n        code: 'KeyA',\n      } as KeyboardEventLike;\n\n      expect(eventToShortcut(altEvent)).toEqual([['Å', 'A']]);\n    });\n  });\n\n  describe('shortcutMatchesShortcut', () => {\n    it('returns false when either shortcut is null', () => {\n      expect(shortcutMatchesShortcut(null as any, ['alt', 'K'])).toBe(false);\n      expect(shortcutMatchesShortcut(['alt', 'K'], null as any)).toBe(false);\n    });\n\n    it('handles shift/ shortcuts correctly', () => {\n      expect(shortcutMatchesShortcut(['shift', '/'], ['/'])).toBe(true);\n    });\n\n    it('compares shortcuts of different lengths correctly', () => {\n      expect(shortcutMatchesShortcut(['alt', 'K'], ['alt', 'K', 'L'])).toBe(false);\n      expect(shortcutMatchesShortcut(['alt', 'K', 'L'], ['alt', 'K'])).toBe(false);\n    });\n\n    it('compares shortcuts with same length correctly', () => {\n      expect(shortcutMatchesShortcut(['alt', 'K'], ['alt', 'K'])).toBe(true);\n      expect(shortcutMatchesShortcut(['alt', 'K'], ['alt', 'J'])).toBe(false);\n      expect(shortcutMatchesShortcut(['alt', ['K', 'L']], ['alt', 'K'])).toBe(true);\n      expect(shortcutMatchesShortcut(['alt', ['K', 'L']], ['alt', 'L'])).toBe(true);\n      expect(shortcutMatchesShortcut(['alt', ['K', 'L']], ['alt', 'M'])).toBe(false);\n    });\n  });\n\n  describe('eventMatchesShortcut', () => {\n    it('matches keyboard event to shortcut correctly', () => {\n      const event = {\n        key: 'K',\n        altKey: true,\n        ctrlKey: false,\n        metaKey: false,\n        shiftKey: false,\n      } as KeyboardEventLike;\n\n      expect(eventMatchesShortcut(event, ['alt', 'K'])).toBe(true);\n      expect(eventMatchesShortcut(event, ['meta', 'K'])).toBe(false);\n    });\n  });\n\n  describe('keyToSymbol', () => {\n    it('converts modifier keys to symbols', () => {\n      // For Mac\n      vi.mocked(isMacLike).mockReturnValue(true);\n\n      expect(keyToSymbol('alt')).toBe('⌥');\n      expect(keyToSymbol('control')).toBe('⌃');\n      expect(keyToSymbol('meta')).toBe('⌘');\n      expect(keyToSymbol('shift')).toBe('⇧​');\n\n      // For non-Mac\n      vi.mocked(isMacLike).mockReturnValue(false);\n\n      expect(keyToSymbol('alt')).toBe('alt');\n    });\n\n    it('converts special keys to symbols', () => {\n      expect(keyToSymbol('Enter')).toBe('');\n      expect(keyToSymbol('Backspace')).toBe('');\n      expect(keyToSymbol('Esc')).toBe('');\n      expect(keyToSymbol('escape')).toBe('');\n      expect(keyToSymbol(' ')).toBe('SPACE');\n      expect(keyToSymbol('ArrowUp')).toBe('↑');\n      expect(keyToSymbol('ArrowDown')).toBe('↓');\n      expect(keyToSymbol('ArrowLeft')).toBe('←');\n      expect(keyToSymbol('ArrowRight')).toBe('→');\n    });\n\n    it('converts regular keys to uppercase', () => {\n      expect(keyToSymbol('a')).toBe('A');\n      expect(keyToSymbol('1')).toBe('1');\n    });\n  });\n\n  describe('shortcutToHumanString', () => {\n    it('converts shortcut to human-readable string', () => {\n      // For Mac\n      vi.mocked(isMacLike).mockReturnValue(true);\n\n      expect(shortcutToHumanString(['alt', 'K'])).toBe('⌥ K');\n      expect(shortcutToHumanString(['control', 'alt', 'shift', 'K'])).toBe('⌃ ⌥ ⇧​ K');\n      expect(shortcutToHumanString(['meta', 'ArrowUp'])).toBe('⌘ ↑');\n\n      // For non-Mac\n      vi.mocked(isMacLike).mockReturnValue(false);\n\n      expect(shortcutToHumanString(['alt', 'K'])).toBe('alt K');\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager-api/lib/shortcut.ts",
    "content": "import type { API_KeyCollection } from '../modules/shortcuts.ts';\nimport { isMacLike } from './platform.ts';\n\nexport type { API_KeyCollection } from '../modules/shortcuts.ts';\n\nexport const controlOrMetaSymbol = () => (isMacLike() ? '⌘' : 'ctrl');\nexport const controlOrMetaKey = () => (isMacLike() ? 'meta' : 'control');\nexport const optionOrAltSymbol = () => (isMacLike() ? '⌥' : 'alt');\n\nexport const isShortcutTaken = (arr1: string[], arr2: string[]): boolean =>\n  JSON.stringify(arr1) === JSON.stringify(arr2);\n\n// A subset of `KeyboardEvent` that's serialized over the channel, see `PreviewWeb.tsx`\nexport type KeyboardEventLike = Pick<\n  KeyboardEvent,\n  'altKey' | 'ctrlKey' | 'metaKey' | 'shiftKey' | 'key' | 'code' | 'keyCode' | 'preventDefault'\n>;\n\n// Map a keyboard event to a keyboard shortcut\n// NOTE: if we change the fields on the event that we need, we'll need to update the serialization in core/preview/start.js\nexport const eventToShortcut = (e: KeyboardEventLike): (string | string[])[] | null => {\n  // Meta key only doesn't map to a shortcut\n  if (['Meta', 'Alt', 'Control', 'Shift', 'Tab'].includes(e.key)) {\n    return null;\n  }\n\n  const keys = [];\n  if (e.altKey) {\n    keys.push('alt');\n  }\n  if (e.ctrlKey) {\n    keys.push('control');\n  }\n  if (e.metaKey) {\n    keys.push('meta');\n  }\n  if (e.shiftKey) {\n    keys.push('shift');\n  }\n\n  // Derive a key from the physical code (letter/digit/punctuation) when needed\n  const codeUpper = e.code?.toUpperCase();\n  const codeToCharMap: Record<string, string> = {\n    MINUS: '-',\n    EQUAL: '=',\n    BRACKETLEFT: '[',\n    BRACKETRIGHT: ']',\n    BACKSLASH: '\\\\',\n    SEMICOLON: ';',\n    QUOTE: \"'\",\n    BACKQUOTE: '`',\n    COMMA: ',',\n    PERIOD: '.',\n    SLASH: '/',\n  };\n  const codeChar = codeUpper\n    ? codeUpper.startsWith('KEY') && codeUpper.length === 4\n      ? codeUpper.replace('KEY', '')\n      : codeUpper.startsWith('DIGIT')\n        ? codeUpper.replace('DIGIT', '')\n        : codeToCharMap[codeUpper]\n    : undefined;\n\n  if (e.key && e.key.length === 1 && e.key !== ' ') {\n    const key = e.key.toUpperCase();\n    // Using `event.code` to support `alt (option) + <key>` on macOS which returns special characters\n    // See full list of event.code here:\n    // https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_code_values\n    const code = codeChar;\n\n    if (code && code.length === 1 && code !== key) {\n      keys.push([key, code]);\n    } else {\n      keys.push(key);\n    }\n  } else if (e.key === 'Dead' && codeChar) {\n    // Handle dead keys (e.g., Option+E on macOS) by using the physical key from code\n    keys.push(codeChar);\n  }\n  if (e.key === ' ') {\n    keys.push('space');\n  }\n  if (e.key === 'Escape') {\n    keys.push('escape');\n  }\n  if (e.key === 'ArrowRight') {\n    keys.push('ArrowRight');\n  }\n  if (e.key === 'ArrowDown') {\n    keys.push('ArrowDown');\n  }\n  if (e.key === 'ArrowUp') {\n    keys.push('ArrowUp');\n  }\n  if (e.key === 'ArrowLeft') {\n    keys.push('ArrowLeft');\n  }\n\n  return keys.length > 0 ? keys : null;\n};\n\nexport const shortcutMatchesShortcut = (\n  inputShortcut: (string | string[])[],\n  shortcut: API_KeyCollection\n): boolean => {\n  if (!inputShortcut || !shortcut) {\n    return false;\n  }\n\n  if (inputShortcut.join('').startsWith('shift/')) {\n    // shift is optional for `/`\n    inputShortcut.shift();\n  }\n\n  if (inputShortcut.length !== shortcut.length) {\n    return false;\n  }\n  return !inputShortcut.find((input, i) =>\n    Array.isArray(input) ? !input.includes(shortcut[i]) : input !== shortcut[i]\n  );\n};\n\n// Should this keyboard event trigger this keyboard shortcut?\nexport const eventMatchesShortcut = (\n  e: KeyboardEventLike,\n  shortcut: API_KeyCollection\n): boolean => {\n  return shortcutMatchesShortcut(eventToShortcut(e)!, shortcut);\n};\n\n/**\n * Returns a human-readable symbol for a keyboard key.\n *\n * @param key The key to convert to a symbol.\n * @returns A string that a human could understand as that keyboard key.\n */\nexport const keyToSymbol = (key: string): string => {\n  if (key === 'alt') {\n    return optionOrAltSymbol();\n  }\n  if (key === 'control') {\n    return '⌃';\n  }\n  if (key === 'meta') {\n    return '⌘';\n  }\n  if (key === 'shift') {\n    return '⇧​';\n  }\n  if (key === 'Enter' || key === 'Backspace' || key === 'Esc') {\n    return '';\n  }\n  if (key === 'escape') {\n    return '';\n  }\n  if (key === ' ') {\n    return 'SPACE';\n  }\n  if (key === 'ArrowUp') {\n    return '↑';\n  }\n  if (key === 'ArrowDown') {\n    return '↓';\n  }\n  if (key === 'ArrowLeft') {\n    return '←';\n  }\n  if (key === 'ArrowRight') {\n    return '→';\n  }\n  return key?.toUpperCase();\n};\n\n// Display the shortcut as a human readable string\nexport const shortcutToHumanString = (shortcut: API_KeyCollection): string => {\n  return shortcut.map(keyToSymbol).join(' ');\n};\n\n// Display the shortcut for use in an aria-keyshortcuts attribute\nexport const shortcutToAriaKeyshortcuts = (shortcut: API_KeyCollection): string => {\n  return shortcut\n    .map((shortcut) => {\n      // aria-keyshortcuts needs `+` translated\n      if (shortcut === '+') {\n        return 'plus';\n      }\n\n      if (shortcut === ' ') {\n        return 'space';\n      }\n\n      return shortcut;\n    })\n    .join('+');\n};\n"
  },
  {
    "path": "code/core/src/manager-api/lib/store-setup.ts",
    "content": "import { parse, stringify } from 'telejson';\n\n// setting up the store, overriding set and get to use telejson\nexport default (_: any) => {\n  _.fn('set', function (key: string, data: object) {\n    return _.set(\n      // @ts-expect-error('this' implicitly has type 'any')\n      this._area,\n      // @ts-expect-error('this' implicitly has type 'any')\n      this._in(key),\n      stringify(data, { maxDepth: 50 })\n    );\n  });\n  _.fn('get', function (key: string, alt: string) {\n    // @ts-expect-error('this' implicitly has type 'any')\n    const value = _.get(this._area, this._in(key));\n    return value !== null ? parse(value) : alt || value;\n  });\n};\n"
  },
  {
    "path": "code/core/src/manager-api/lib/stories.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport {\n  type API_PreparedStoryIndex,\n  type StatusesByStoryIdAndTypeId,\n  type StoryIndexV2,\n  type StoryIndexV3,\n} from 'storybook/internal/types';\n\nimport type { State } from '../root.tsx';\nimport { mockEntries } from '../tests/mockStoriesEntries.ts';\nimport {\n  transformStoryIndexToStoriesHash,\n  transformStoryIndexV2toV3,\n  transformStoryIndexV3toV4,\n  transformStoryIndexV4toV5,\n} from './stories.ts';\n\nconst baseV2: StoryIndexV2['stories'][0] = {\n  id: '1',\n  story: '',\n  kind: '',\n  parameters: {},\n};\n\nconst baseV3: StoryIndexV3['stories'][0] = {\n  id: '1',\n  title: '',\n  name: '',\n  story: '',\n  kind: '',\n  parameters: {},\n  importPath: '',\n};\n\ndescribe('transformStoryIndexV2toV3', () => {\n  it('transforms a StoryIndexV2 to a StoryIndexV3 correctly', () => {\n    const indexV2: StoryIndexV2 = {\n      v: 2,\n      stories: {\n        '1': {\n          ...baseV2,\n          id: '1',\n          kind: 'story',\n          story: 'Story 1',\n        },\n        '2': {\n          ...baseV2,\n          id: '2',\n          kind: 'blog',\n          story: 'Blog 1',\n        },\n      },\n    };\n\n    expect(transformStoryIndexV2toV3(indexV2)).toMatchInlineSnapshot(`\n      {\n        \"stories\": {\n          \"1\": {\n            \"id\": \"1\",\n            \"importPath\": \"\",\n            \"kind\": \"story\",\n            \"name\": \"Story 1\",\n            \"parameters\": {},\n            \"story\": \"Story 1\",\n            \"title\": \"story\",\n          },\n          \"2\": {\n            \"id\": \"2\",\n            \"importPath\": \"\",\n            \"kind\": \"blog\",\n            \"name\": \"Blog 1\",\n            \"parameters\": {},\n            \"story\": \"Blog 1\",\n            \"title\": \"blog\",\n          },\n        },\n        \"v\": 3,\n      }\n    `);\n  });\n});\n\ndescribe('transformStoryIndexV3toV4', () => {\n  it('transforms a StoryIndexV3 to an API_PreparedStoryIndex correctly', () => {\n    const indexV3: StoryIndexV3 = {\n      v: 3,\n      stories: {\n        '1': {\n          ...baseV3,\n          id: '1',\n          kind: 'story',\n          title: 'Story 1',\n          parameters: {\n            docsOnly: true,\n          },\n        },\n        '2': {\n          ...baseV3,\n          id: '2',\n          kind: 'page',\n          name: 'Page 1',\n          title: 'Page 1',\n        },\n        '3': {\n          ...baseV3,\n          id: '3',\n          kind: 'story',\n          title: 'Story 2',\n        },\n        '4': {\n          ...baseV3,\n          id: '4',\n          kind: 'page',\n          name: 'Page 2',\n          title: 'Page 1',\n        },\n      },\n    };\n\n    expect(transformStoryIndexV3toV4(indexV3)).toMatchInlineSnapshot(`\n      {\n        \"entries\": {\n          \"1\": {\n            \"id\": \"1\",\n            \"importPath\": \"\",\n            \"name\": \"\",\n            \"parameters\": {\n              \"docsOnly\": true,\n            },\n            \"storiesImports\": [],\n            \"tags\": [\n              \"stories-mdx\",\n            ],\n            \"title\": \"Story 1\",\n            \"type\": \"docs\",\n          },\n          \"2\": {\n            \"id\": \"2\",\n            \"importPath\": \"\",\n            \"name\": \"Page 1\",\n            \"parameters\": {},\n            \"title\": \"Page 1\",\n            \"type\": \"story\",\n          },\n          \"3\": {\n            \"id\": \"3\",\n            \"importPath\": \"\",\n            \"name\": \"\",\n            \"parameters\": {},\n            \"title\": \"Story 2\",\n            \"type\": \"story\",\n          },\n          \"4\": {\n            \"id\": \"4\",\n            \"importPath\": \"\",\n            \"name\": \"Page 2\",\n            \"parameters\": {},\n            \"title\": \"Page 1\",\n            \"type\": \"story\",\n          },\n        },\n        \"v\": 4,\n      }\n    `);\n  });\n});\n\ndescribe('transformStoryIndexV4toV5', () => {\n  it('transforms a StoryIndexV4 to an API_PreparedStoryIndex correctly', () => {\n    const indexV4: API_PreparedStoryIndex = {\n      v: 4,\n      entries: mockEntries,\n    };\n\n    expect(transformStoryIndexV4toV5(indexV4)).toMatchInlineSnapshot(`\n      {\n        \"entries\": {\n          \"component-a--docs\": {\n            \"id\": \"component-a--docs\",\n            \"importPath\": \"./path/to/component-a.ts\",\n            \"name\": \"Docs\",\n            \"storiesImports\": [],\n            \"tags\": [\n              \"dev\",\n            ],\n            \"title\": \"Component A\",\n            \"type\": \"docs\",\n          },\n          \"component-a--story-1\": {\n            \"id\": \"component-a--story-1\",\n            \"importPath\": \"./path/to/component-a.ts\",\n            \"name\": \"Story 1\",\n            \"subtype\": \"story\",\n            \"tags\": [\n              \"dev\",\n            ],\n            \"title\": \"Component A\",\n            \"type\": \"story\",\n          },\n          \"component-a--story-2\": {\n            \"id\": \"component-a--story-2\",\n            \"importPath\": \"./path/to/component-a.ts\",\n            \"name\": \"Story 2\",\n            \"subtype\": \"story\",\n            \"tags\": [\n              \"dev\",\n            ],\n            \"title\": \"Component A\",\n            \"type\": \"story\",\n          },\n          \"component-b--story-3\": {\n            \"id\": \"component-b--story-3\",\n            \"importPath\": \"./path/to/component-b.ts\",\n            \"name\": \"Story 3\",\n            \"subtype\": \"story\",\n            \"tags\": [\n              \"dev\",\n            ],\n            \"title\": \"Component B\",\n            \"type\": \"story\",\n          },\n        },\n        \"v\": 5,\n      }\n    `);\n  });\n});\n\ndescribe('transformStoryIndexToStoriesHash', () => {\n  it('does not apply filters to failing stories', () => {\n    // Arrange - set up an index with two stories, one of which has a failing status\n    const indexV5: API_PreparedStoryIndex = {\n      v: 5,\n      entries: {\n        '1': {\n          id: '1',\n          type: 'story',\n          subtype: 'story',\n          title: 'Story 1',\n          name: 'Story 1',\n          importPath: './path/to/story-1.ts',\n          parameters: {},\n          tags: [],\n        },\n        '2': {\n          id: '2',\n          type: 'story',\n          subtype: 'story',\n          title: 'Story 2',\n          name: 'Story 2',\n          importPath: './path/to/story-2.ts',\n          parameters: {},\n          tags: [],\n        },\n      },\n    };\n\n    const filters: State['filters'] = {\n      someFilter: () => false,\n    };\n\n    const allStatuses: StatusesByStoryIdAndTypeId = {\n      '1': {\n        someStatus: {\n          typeId: 'someStatus',\n          storyId: '1',\n          value: 'status-value:error',\n          title: 'broken',\n          description: 'very bad',\n        },\n      },\n      '2': {\n        someStatus: {\n          typeId: 'someStatus',\n          storyId: '2',\n          value: 'status-value:success',\n          title: 'perfect',\n          description: 'nice',\n        },\n      },\n    };\n\n    const options = {\n      provider: {\n        getConfig: () => ({ sidebar: {} }),\n      } as any,\n      docsOptions: { docsMode: false },\n      filters,\n      allStatuses,\n    };\n\n    // Act - transform the index to hashes\n    const result = transformStoryIndexToStoriesHash(indexV5, options);\n\n    // Assert - the failing story is still present in the result, even though the filters remove all stories\n    expect(Object.keys(result)).toHaveLength(2);\n    expect(result['story-1']).toBeTruthy();\n    expect(result['1']).toBeTruthy();\n    expect(result['story-2']).toBeUndefined();\n    expect(result['2']).toBeUndefined();\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager-api/lib/stories.ts",
    "content": "import { sanitize } from 'storybook/internal/csf';\nimport type {\n  API_ComponentEntry,\n  API_DocsEntry,\n  API_GroupEntry,\n  API_HashEntry,\n  API_IndexHash,\n  API_PreparedIndexEntry,\n  API_PreparedStoryIndex,\n  API_Provider,\n  API_RootEntry,\n  API_StoryEntry,\n  DocsOptions,\n  IndexEntry,\n  Parameters,\n  SetStoriesPayload,\n  SetStoriesStoryData,\n  StatusesByStoryIdAndTypeId,\n  StoryId,\n  StoryIndexV2,\n  StoryIndexV3,\n} from 'storybook/internal/types';\n\nimport { countBy } from 'es-toolkit/array';\nimport { mapValues } from 'es-toolkit/object';\nimport memoize from 'memoizerific';\nimport { dedent } from 'ts-dedent';\n\nimport { Tag } from '../../shared/constants/tags.ts';\nimport { type API, type State, combineParameters } from '../root.tsx';\nimport intersect from './intersect.ts';\nimport merge from './merge.ts';\n\nconst TITLE_PATH_SEPARATOR = /\\s*\\/\\s*/;\n\nexport const denormalizeStoryParameters = ({\n  globalParameters,\n  kindParameters,\n  stories,\n}: SetStoriesPayload): SetStoriesStoryData => {\n  return mapValues(stories, (storyData) => ({\n    ...storyData,\n    parameters: combineParameters(\n      globalParameters,\n      kindParameters[storyData.kind],\n      storyData.parameters as unknown as Parameters\n    ),\n  })) as SetStoriesStoryData;\n};\n\nexport const transformSetStoriesStoryDataToPreparedStoryIndex = (\n  stories: SetStoriesStoryData\n): API_PreparedStoryIndex => {\n  const entries: API_PreparedStoryIndex['entries'] = Object.entries(stories).reduce(\n    (acc, [id, story]) => {\n      if (!story) {\n        return acc;\n      }\n\n      const { docsOnly, fileName, ...parameters } = story.parameters;\n      const base = {\n        title: story.kind,\n        id,\n        name: story.name,\n        importPath: fileName,\n      };\n      if (docsOnly) {\n        acc[id] = {\n          type: 'docs',\n          tags: ['stories-mdx'],\n          storiesImports: [],\n          ...base,\n        };\n      } else {\n        const { argTypes, args, initialArgs } = story;\n        acc[id] = {\n          type: 'story',\n          subtype: 'story',\n          ...base,\n          parameters,\n          argTypes,\n          args,\n          initialArgs,\n        };\n      }\n      return acc;\n    },\n    {} as API_PreparedStoryIndex['entries']\n  );\n\n  return { v: 5, entries };\n};\n\nexport const transformStoryIndexV2toV3 = (index: StoryIndexV2): StoryIndexV3 => {\n  return {\n    v: 3,\n    stories: Object.values(index.stories).reduce(\n      (acc, entry) => {\n        acc[entry.id] = {\n          ...entry,\n          title: entry.kind,\n          name: entry.name || entry.story,\n          importPath: entry.parameters.fileName || '',\n        };\n\n        return acc;\n      },\n      {} as StoryIndexV3['stories']\n    ),\n  };\n};\n\nexport const transformStoryIndexV3toV4 = (index: StoryIndexV3): API_PreparedStoryIndex => {\n  const countByTitle = countBy(Object.values(index.stories), (item) => item.title);\n  return {\n    v: 4,\n    entries: Object.values(index.stories).reduce(\n      (acc, entry) => {\n        let type: IndexEntry['type'] = 'story';\n        if (\n          entry.parameters?.docsOnly ||\n          (entry.name === 'Page' && countByTitle[entry.title] === 1)\n        ) {\n          type = 'docs';\n        }\n        acc[entry.id] = {\n          type,\n          ...(type === 'docs' && { tags: ['stories-mdx'], storiesImports: [] }),\n          ...entry,\n        } as API_PreparedIndexEntry;\n\n        // @ts-expect-error (we're removing something that should not be there)\n        delete acc[entry.id].story;\n        // @ts-expect-error (we're removing something that should not be there)\n        delete acc[entry.id].kind;\n\n        return acc;\n      },\n      {} as API_PreparedStoryIndex['entries']\n    ),\n  };\n};\n\n/**\n * Storybook 8.0 and below did not automatically tag stories with 'dev'. Therefore Storybook 8.1 and\n * above would not show composed 8.0 stories by default. This function adds the 'dev' tag to all\n * stories in the index to workaround this issue.\n */\nexport const transformStoryIndexV4toV5 = (\n  index: API_PreparedStoryIndex\n): API_PreparedStoryIndex => {\n  return {\n    v: 5,\n    entries: Object.values(index.entries).reduce(\n      (acc, entry) => {\n        acc[entry.id] = {\n          ...entry,\n          tags: entry.tags ? [Tag.DEV, Tag.TEST, ...entry.tags] : [Tag.DEV],\n        };\n\n        return acc;\n      },\n      {} as API_PreparedStoryIndex['entries']\n    ),\n  };\n};\n\ntype ToStoriesHashOptions = {\n  provider: API_Provider<API>;\n  docsOptions: DocsOptions;\n  filters: State['filters'];\n  allStatuses: StatusesByStoryIdAndTypeId;\n  /** The key of the status filter in `filters`, if any. The status filter takes priority over the \"always show error\" rule. */\n  statusFilterKey?: string;\n};\n\nexport const transformStoryIndexToStoriesHash = (\n  input: API_PreparedStoryIndex | StoryIndexV2 | StoryIndexV3,\n  { provider, docsOptions, filters, allStatuses, statusFilterKey }: ToStoriesHashOptions\n): API_IndexHash => {\n  if (!input.v) {\n    throw new Error('Composition: Missing stories.json version');\n  }\n\n  let index = input;\n  index = index.v === 2 ? transformStoryIndexV2toV3(index as any) : index;\n  index = index.v === 3 ? transformStoryIndexV3toV4(index as any) : index;\n  index = index.v === 4 ? transformStoryIndexV4toV5(index as any) : index;\n  index = index as API_PreparedStoryIndex;\n\n  const indexEntries = Object.values(index.entries);\n  const filterFunctions = Object.values(filters);\n  const statusFilterFn = statusFilterKey ? filters[statusFilterKey] : undefined;\n\n  const entryValues = indexEntries.filter((entry) => {\n    const statuses = allStatuses[entry.id] ?? {};\n\n    // The status filter runs first and can hide entries even if they have a failing status.\n    // This allows users to explicitly filter by status (e.g. exclude error stories).\n    if (statusFilterFn && !statusFilterFn({ ...entry, statuses })) {\n      const children = indexEntries.filter((item) => 'parent' in item && item.parent === entry.id);\n      if (\n        !children.some((child) =>\n          statusFilterFn({ ...child, statuses: allStatuses[child.id] ?? {} })\n        )\n      ) {\n        return false;\n      }\n    }\n\n    if (Object.values(statuses).some(({ value }) => value === 'status-value:error')) {\n      // All stories with a failing status should always show up, regardless of the applied non-status filters\n      return true;\n    }\n\n    if (filterFunctions.every((fn) => fn({ ...entry, statuses }))) {\n      return true;\n    }\n\n    const children = indexEntries.filter((item) => 'parent' in item && item.parent === entry.id);\n    return children.some((child) => filterFunctions.every((fn) => fn({ ...child, statuses })));\n  });\n\n  const { sidebar = {} } = provider.getConfig();\n  const { showRoots, collapsedRoots = [], renderLabel } = sidebar;\n\n  const setShowRoots = typeof showRoots !== 'undefined';\n\n  const storiesHashOutOfOrder = entryValues.reduce((acc, item) => {\n    if (docsOptions.docsMode && item.type !== 'docs') {\n      return acc;\n    }\n\n    // First, split the title into a set of names, separated by '/' and trimmed.\n    const { title } = item;\n    const groups = title.trim().split(TITLE_PATH_SEPARATOR);\n    const root = (!setShowRoots || showRoots) && groups.length > 1 ? [groups.shift()] : [];\n    const names = [...root, ...groups];\n\n    // Now create a \"path\" or sub id for each name\n    const paths = names.reduce((list, name, idx) => {\n      const parent = idx > 0 && list[idx - 1];\n      const id = sanitize(parent ? `${parent}-${name}` : name!);\n\n      if (name!.trim() === '') {\n        throw new Error(dedent`Invalid title ${title} ending in slash.`);\n      }\n\n      if (parent === id) {\n        throw new Error(\n          dedent`\n          Invalid part '${name}', leading to id === parentId ('${id}'), inside title '${title}'\n\n          Did you create a path that uses the separator char accidentally, such as 'Vue <docs/>' where '/' is a separator char? See https://github.com/storybookjs/storybook/issues/6128\n          `\n        );\n      }\n      list.push(id);\n      return list;\n    }, [] as string[]);\n\n    // Now, let's add an entry to the hash for each path/name pair\n    paths.forEach((id, idx) => {\n      // The child is the next path, OR the story/docs entry itself\n      const childId = paths[idx + 1] || item.id;\n\n      if (root.length && idx === 0) {\n        acc[id] = merge<API_RootEntry>((acc[id] || {}) as API_RootEntry, {\n          type: 'root',\n          id,\n          name: names[idx],\n          tags: [],\n          depth: idx,\n          renderLabel,\n          startCollapsed: collapsedRoots.includes(id),\n          // Note that this will later get appended to the previous list of children (see below)\n          children: [childId],\n        });\n        // Usually the last path/name pair will be displayed as a component,\n        // *unless* there are other stories that are more deeply nested under it\n        //\n        // For example, if we had stories for both\n        //   - Atoms / Button\n        //   - Atoms / Button / LabelledButton\n        //\n        // In this example the entry for 'atoms-button' would *not* be a component.\n      } else if ((!acc[id] || acc[id].type === 'component') && idx === paths.length - 1) {\n        acc[id] = merge<API_ComponentEntry>((acc[id] || {}) as API_ComponentEntry, {\n          type: 'component',\n          id,\n          name: names[idx],\n          tags: [],\n          parent: paths[idx - 1],\n          depth: idx,\n          renderLabel,\n          ...(childId && {\n            children: [childId],\n          }),\n        });\n      } else {\n        acc[id] = merge<API_GroupEntry>((acc[id] || {}) as API_GroupEntry, {\n          type: 'group',\n          id,\n          name: names[idx],\n          tags: [],\n          parent: paths[idx - 1],\n          depth: idx,\n          renderLabel,\n          ...(childId && {\n            children: [childId],\n          }),\n        });\n      }\n    });\n\n    // Finally add an entry for the docs/story/test itself\n    acc[item.id] = {\n      tags: [],\n      ...item,\n      depth: paths.length,\n      parent: 'parent' in item ? item.parent : paths[paths.length - 1],\n      renderLabel,\n      prepared: !!item.parameters,\n    } as API_DocsEntry | API_StoryEntry;\n\n    return acc;\n  }, {} as API_IndexHash);\n\n  // This function adds a \"root\" or \"orphan\" and all of its descendents to the hash.\n  function addItem(acc: API_IndexHash, item: API_HashEntry) {\n    // If we were already inserted as part of a group, that's great.\n    if (!acc[item.id]) {\n      acc[item.id] = item;\n\n      // Ensure we add the children depth-first *before* inserting any other entries.\n      if ('children' in item && item.children) {\n        item.children.forEach((childId) => addItem(acc, storiesHashOutOfOrder[childId]));\n\n        item.tags =\n          item.children.reduce((currentTags: Tag[] | null, childId): Tag[] => {\n            // On the first child, we have nothing to intersect against so we use it as a source of data.\n            return currentTags === null\n              ? acc[childId].tags\n              : intersect(currentTags, acc[childId].tags);\n          }, null) || [];\n      }\n    }\n\n    if (item.type === 'component') {\n      const firstChild = acc[item.children[0]];\n      if (firstChild && 'importPath' in firstChild) {\n        // attach importPath to the component node which should be the same for all children\n        // this way we can add \"open in editor\" to the component node\n        item.importPath = firstChild.importPath;\n      }\n    }\n    return acc;\n  }\n\n  // We'll do two passes over the data, adding all the orphans, then all the roots\n  let storiesHash = Object.values(storiesHashOutOfOrder)\n    .filter((i) => i.type !== 'root' && !i.parent)\n    .reduce((acc, item) => addItem(acc, item), {} as API_IndexHash);\n\n  storiesHash = Object.values(storiesHashOutOfOrder)\n    .filter((i) => i.type === 'root')\n    .reduce(addItem, storiesHash);\n\n  // Update stories to include tests as children, and increase depth for those tests\n  storiesHash = Object.values(storiesHash).reduce((acc, item) => {\n    if (item.type === 'story' && item.subtype === 'test') {\n      const story = acc[item.parent] as API_StoryEntry;\n      const component = acc[story.parent] as API_ComponentEntry;\n      acc[component.id] = {\n        ...component,\n        // Remove test from the component node as it will be attached to the story node instead\n        children: component.children && component.children.filter((id) => id !== item.id),\n      };\n      acc[story.id] = {\n        ...story,\n        // Add test to the story node\n        children: (story.children || []).concat(item.id),\n      };\n      acc[item.id] = {\n        ...item,\n        depth: item.depth + 1,\n      };\n    } else {\n      acc[item.id] = item;\n    }\n    return acc;\n  }, {} as API_IndexHash);\n\n  return storiesHash;\n};\n\n/** Now we need to patch in the existing prepared stories */\nexport const addPreparedStories = (newHash: API_IndexHash, oldHash?: API_IndexHash) => {\n  if (!oldHash) {\n    return newHash;\n  }\n\n  return Object.fromEntries(\n    Object.entries(newHash).map(([id, newEntry]) => {\n      const oldEntry = oldHash[id];\n      if (newEntry.type === 'story' && oldEntry?.type === 'story' && oldEntry.prepared) {\n        if ('children' in oldEntry) {\n          // Prevent old entry from re-adding children if the story no longer has any (e.g. due to filters)\n          delete oldEntry.children;\n        }\n        return [id, { ...oldEntry, ...newEntry, prepared: true }];\n      }\n\n      return [id, newEntry];\n    })\n  );\n};\n\nexport const getComponentLookupList = memoize(1)((hash: API_IndexHash) => {\n  return Object.entries(hash).reduce((acc, i) => {\n    const value = i[1];\n    if (value.type === 'component') {\n      acc.push([...value.children]);\n    }\n    return acc;\n  }, [] as StoryId[][]);\n});\n\nexport const getStoriesLookupList = memoize(1)((hash: API_IndexHash) => {\n  return Object.keys(hash).filter((k) => ['story', 'docs'].includes(hash[k].type));\n});\n"
  },
  {
    "path": "code/core/src/manager-api/lib/storybook-channel-mock.ts",
    "content": "import { Channel } from 'storybook/internal/channels';\n\nexport function mockChannel() {\n  const transport = {\n    setHandler: () => {},\n    send: () => {},\n  };\n\n  return new Channel({ transport });\n}\n"
  },
  {
    "path": "code/core/src/manager-api/lib/types.tsx",
    "content": "import type { RouterData } from 'storybook/internal/router';\nimport type { API_ProviderData } from 'storybook/internal/types';\n\nimport type { API, State } from '../root.tsx';\nimport type Store from '../store.ts';\n\nexport type ModuleFn<APIType = unknown, StateType = unknown> = (\n  m: ModuleArgs,\n  options?: any\n) => {\n  init?: () => void | Promise<void>;\n  api: APIType;\n  state: StateType;\n};\n\nexport type ModuleArgs = RouterData &\n  API_ProviderData<API> & {\n    mode?: 'production' | 'development';\n    state: State;\n    fullAPI: API;\n    store: Store;\n  };\n"
  },
  {
    "path": "code/core/src/manager-api/lib/url.ts",
    "content": "export const buildNavigationUrl = (\n  path: string,\n  queryParams: Record<string, string | null | undefined> = {}\n): string => {\n  const params = Object.entries(queryParams)\n    .filter(([, v]) => v !== null && v !== undefined)\n    .sort(([a], [b]) => (a < b ? -1 : 1))\n    .map(([k, v]) => `${k}=${v}`);\n  return [path, ...params].join('&');\n};\n"
  },
  {
    "path": "code/core/src/manager-api/modules/addons.ts",
    "content": "import { Addon_TypesEnum } from 'storybook/internal/types';\nimport type {\n  API_StateMerger,\n  Addon_BaseType,\n  Addon_Collection,\n  Addon_Types,\n  Addon_TypesMapping,\n} from 'storybook/internal/types';\n\nimport type { ModuleFn } from '../lib/types.tsx';\nimport type { Options } from '../store.ts';\n\nexport interface SubState {\n  selectedPanel: string;\n  addons: Record<string, never>;\n}\n\nexport interface SubAPI {\n  /**\n   * Returns a collection of elements of a specific type.\n   *\n   * @template T - The type of the elements in the collection.\n   * @param {Addon_Types | Addon_TypesEnum.experimental_PAGE} type - The type of the elements to\n   *   retrieve.\n   * @returns {Addon_Collection<T>} - A collection of elements of the specified type.\n   * @protected This is used internally in storybook's manager.\n   */\n  getElements: <\n    T extends\n      | Addon_Types\n      | Addon_TypesEnum.experimental_PAGE\n      | Addon_TypesEnum.experimental_TEST_PROVIDER,\n  >(\n    type: T\n  ) => Addon_Collection<Addon_TypesMapping[T]>;\n  /**\n   * Returns the id of the currently selected panel.\n   *\n   * @returns {string} - The ID of the currently selected panel.\n   */\n  getSelectedPanel: () => string;\n  /**\n   * Sets the currently selected panel via it's ID.\n   *\n   * @param {string} panelName - The ID of the panel to select.\n   * @returns {void}\n   */\n  setSelectedPanel: (panelName: string) => void;\n  /**\n   * Sets the state of an addon with the given ID.\n   *\n   * @deprecated This API might get dropped, if you are using this, please file an issue.\n   * @template S - The type of the addon state.\n   * @param {string} addonId - The ID of the addon to set the state for.\n   * @param {S | API_StateMerger<S>} newStateOrMerger - The new state to set, or a function which\n   *   receives the current state and returns the new state.\n   * @param {Options} [options] - Optional options for the state update.\n   * @returns {Promise<S>} - A promise that resolves with the new state after it has been set.\n   */\n  setAddonState<S>(\n    addonId: string,\n    newStateOrMerger: S | API_StateMerger<S>,\n    options?: Options\n  ): Promise<S>;\n  /**\n   * Returns the state of an addon with the given ID.\n   *\n   * @deprecated This API might get dropped, if you are using this, please file an issue.\n   * @template S - The type of the addon state.\n   * @param {string} addonId - The ID of the addon to get the state for.\n   * @returns {S} - The state of the addon with the given ID.\n   */\n  getAddonState<S>(addonId: string): S;\n}\n\nexport function ensurePanel(\n  panels: Addon_Collection<Addon_BaseType>,\n  selectedPanel?: string,\n  currentPanel?: string\n) {\n  const keys = Object.keys(panels);\n\n  if (keys.indexOf(selectedPanel!) >= 0) {\n    return selectedPanel;\n  }\n\n  if (keys.length) {\n    return keys[0];\n  }\n  return currentPanel;\n}\n\nexport const init: ModuleFn<SubAPI, SubState> = ({ provider, store, fullAPI }): any => {\n  const api: SubAPI = {\n    getElements: (type) => provider.getElements(type),\n    getSelectedPanel: (): any => {\n      const { selectedPanel } = store.getState();\n      return ensurePanel(api.getElements(Addon_TypesEnum.PANEL), selectedPanel, selectedPanel);\n    },\n    setSelectedPanel: (panelName) => {\n      store.setState({ selectedPanel: panelName }, { persistence: 'session' });\n    },\n    setAddonState<S>(\n      addonId: string,\n      newStateOrMerger: S | API_StateMerger<S>,\n      options?: Options\n    ): Promise<S> {\n      const merger = (\n        typeof newStateOrMerger === 'function' ? newStateOrMerger : () => newStateOrMerger\n      ) as API_StateMerger<S>;\n      return store\n        .setState(\n          (s) => ({ ...s, addons: { ...s.addons, [addonId]: merger(s.addons[addonId]) } }),\n          options\n        )\n        .then(() => api.getAddonState(addonId));\n    },\n    getAddonState: (addonId) => {\n      return store.getState().addons[addonId] || globalThis?.STORYBOOK_ADDON_STATE[addonId];\n    },\n  };\n\n  return {\n    api,\n    state: {\n      selectedPanel: ensurePanel(\n        api.getElements(Addon_TypesEnum.PANEL),\n        store.getState().selectedPanel\n      ),\n      addons: {},\n    },\n  };\n};\n"
  },
  {
    "path": "code/core/src/manager-api/modules/channel.ts",
    "content": "import type { Listener } from 'storybook/internal/channels';\nimport type { API_Provider } from 'storybook/internal/types';\n\nimport type { ModuleFn } from '../lib/types.tsx';\nimport type { API } from '../root.tsx';\n\nexport interface SubAPI {\n  /**\n   * Returns the channel object.\n   *\n   * @protected Please do not use, it's for internal use only.\n   */\n  getChannel: () => API_Provider<API>['channel'];\n  /**\n   * Adds a listener to the channel for the given event type. Returns a function that can be called\n   * to remove the listener.\n   *\n   * @param type - The event type to listen for. If using a core event, import it from\n   *   `storybook/internal/core-events`.\n   * @param handler - The callback function to be called when the event is emitted.\n   * @returns A function that can be called to remove the listener.\n   */\n  on: (type: string, handler: Listener) => () => void;\n  /**\n   * Removes a listener from the channel for the given event type.\n   *\n   * @param type - The event type to remove the listener from. If using a core event, import it from\n   *   `storybook/internal/core-events`.\n   * @param handler - The callback function to be removed.\n   */\n  off: (type: string, handler: Listener) => void;\n  /**\n   * Emits an event on the channel for the given event type.\n   *\n   * @param type - The event type to emit. If using a core event, import it from\n   *   `storybook/internal/core-events`.\n   * @param args - The arguments to pass to the event listener.\n   */\n  emit: (type: string, ...args: any[]) => void;\n  /**\n   * Adds a one-time listener to the channel for the given event type.\n   *\n   * @param type - The event type to listen for. If using a core event, import it from\n   *   `storybook/internal/core-events`.\n   * @param handler - The callback function to be called when the event is emitted.\n   */\n  once: (type: string, handler: Listener) => void;\n}\n\nexport type SubState = Record<string, never>;\n\nexport const init: ModuleFn<SubAPI, SubState> = ({ provider }) => {\n  const api: SubAPI = {\n    getChannel: () => provider.channel,\n    on: (type, handler) => {\n      provider.channel?.on(type, handler);\n\n      return () => provider.channel?.off(type, handler);\n    },\n    off: (type, handler) => provider.channel?.off(type, handler),\n    once: (type, handler) => provider.channel?.once(type, handler),\n    emit: (type, data, ...args) => {\n      if (\n        data?.options?.target &&\n        data.options.target !== 'storybook-preview-iframe' &&\n        !data.options.target.startsWith('storybook-ref-')\n      ) {\n        data.options.target =\n          data.options.target !== 'storybook_internal'\n            ? `storybook-ref-${data.options.target}`\n            : 'storybook-preview-iframe';\n      }\n      provider.channel?.emit(type, data, ...args);\n    },\n  };\n  return { api, state: {} };\n};\n"
  },
  {
    "path": "code/core/src/manager-api/modules/globals.ts",
    "content": "import { logger } from 'storybook/internal/client-logger';\nimport { GLOBALS_UPDATED, SET_GLOBALS, UPDATE_GLOBALS } from 'storybook/internal/core-events';\nimport type {\n  GlobalTypes,\n  Globals,\n  GlobalsUpdatedPayload,\n  SetGlobalsPayload,\n} from 'storybook/internal/types';\n\nimport { dequal as deepEqual } from 'dequal';\n\nimport { getEventMetadata } from '../lib/events.ts';\nimport type { ModuleFn } from '../lib/types.tsx';\n\nexport interface SubState {\n  globals?: Globals;\n  userGlobals?: Globals;\n  storyGlobals?: Globals;\n  globalTypes?: GlobalTypes;\n}\n\nexport interface SubAPI {\n  /**\n   * Returns the current globals, which is the user globals overlaid with the story globals\n   *\n   * @returns {Globals} The current globals.\n   */\n  getGlobals: () => Globals;\n  /**\n   * Returns the current globals, as set by the user (a story may have override values)\n   *\n   * @returns {Globals} The current user globals.\n   */\n  getUserGlobals: () => Globals /**\n   * /** Returns the current globals, as set by the story\n   *\n   * @returns {Globals} The current story globals.\n   */;\n  getStoryGlobals: () => Globals /**\n   * Returns the globalTypes, as defined at the project level.\n   *\n   * @returns {GlobalTypes} The globalTypes.\n   */;\n  getGlobalTypes: () => GlobalTypes;\n  /**\n   * Updates the current globals with the provided new globals.\n   *\n   * @param {Globals} newGlobals - The new globals to update with.\n   * @returns {void}\n   */\n  updateGlobals: (newGlobals: Globals) => void;\n}\n\nexport const init: ModuleFn<SubAPI, SubState> = ({ store, fullAPI, provider }) => {\n  const api: SubAPI = {\n    getGlobals() {\n      return store.getState().globals!;\n    },\n    getUserGlobals() {\n      return store.getState().userGlobals!;\n    },\n    getStoryGlobals() {\n      return store.getState().storyGlobals!;\n    },\n    getGlobalTypes() {\n      return store.getState().globalTypes!;\n    },\n    updateGlobals(newGlobals) {\n      // Only emit the message to the local ref\n      provider.channel?.emit(UPDATE_GLOBALS, {\n        globals: newGlobals,\n        options: {\n          target: 'storybook-preview-iframe',\n        },\n      });\n    },\n  };\n\n  const state: SubState = {\n    globals: {},\n    userGlobals: {},\n    storyGlobals: {},\n    globalTypes: {},\n  };\n  const updateGlobals = ({\n    globals,\n    storyGlobals,\n    userGlobals,\n  }: {\n    globals: Globals;\n    storyGlobals: Globals;\n    userGlobals: Globals;\n  }) => {\n    const {\n      globals: currentGlobals,\n      userGlobals: currentUserGlobals,\n      storyGlobals: currentStoryGlobals,\n    } = store.getState();\n    if (!deepEqual(globals, currentGlobals)) {\n      store.setState({ globals });\n    }\n    if (!deepEqual(userGlobals, currentUserGlobals)) {\n      store.setState({ userGlobals });\n    }\n    if (!deepEqual(storyGlobals, currentStoryGlobals)) {\n      store.setState({ storyGlobals });\n    }\n  };\n\n  provider.channel?.on(\n    GLOBALS_UPDATED,\n    function handleGlobalsUpdated(\n      this: any,\n      { globals, storyGlobals, userGlobals }: GlobalsUpdatedPayload\n    ) {\n      const { ref } = getEventMetadata(this, fullAPI)!;\n\n      if (!ref) {\n        updateGlobals({ globals, storyGlobals, userGlobals });\n      } else {\n        logger.warn(\n          'received a GLOBALS_UPDATED from a non-local ref. This is not currently supported.'\n        );\n      }\n    }\n  );\n\n  // Emitted by the preview on initialization\n  provider.channel?.on(\n    SET_GLOBALS,\n    function handleSetGlobals(this: any, { globals, globalTypes }: SetGlobalsPayload) {\n      const { ref } = getEventMetadata(this, fullAPI)!;\n      const currentUserGlobals = store.getState()?.userGlobals;\n\n      if (!ref) {\n        store.setState({ globals, userGlobals: globals, globalTypes });\n      } else if (Object.keys(globals).length > 0) {\n        logger.warn('received globals from a non-local ref. This is not currently supported.');\n      }\n\n      if (\n        currentUserGlobals &&\n        Object.keys(currentUserGlobals).length !== 0 &&\n        !deepEqual(globals, currentUserGlobals)\n      ) {\n        api.updateGlobals(currentUserGlobals);\n      }\n    }\n  );\n\n  return {\n    api,\n    state,\n  };\n};\n"
  },
  {
    "path": "code/core/src/manager-api/modules/layout.ts",
    "content": "import { SET_CONFIG } from 'storybook/internal/core-events';\nimport type {\n  API_Layout,\n  API_LayoutCustomisations,\n  API_PanelPositions,\n  API_UI,\n} from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { pick, toMerged } from 'es-toolkit/object';\nimport { isEqual as deepEqual } from 'es-toolkit/predicate';\nimport type { ThemeVars } from 'storybook/theming';\nimport { create } from 'storybook/theming/create';\n\nimport merge from '../lib/merge.ts';\nimport type { ModuleFn } from '../lib/types.tsx';\nimport type { State } from '../root.tsx';\n\nconst { document } = global;\n\nconst isFunction = (val: unknown): val is CallableFunction => typeof val === 'function';\n\nexport const ActiveTabs = {\n  SIDEBAR: 'sidebar' as const,\n  CANVAS: 'canvas' as const,\n  ADDONS: 'addons' as const,\n};\n\nexport interface SubState {\n  layout: API_Layout;\n  layoutCustomisations: API_LayoutCustomisations;\n  ui: API_UI;\n  selectedPanel: string | undefined;\n  theme: ThemeVars;\n}\n\nexport interface SubAPI {\n  /**\n   * Toggles the fullscreen mode of the Storybook UI.\n   *\n   * @param toggled - Optional boolean value to set the fullscreen mode to. If not provided, it will\n   *   toggle the current state.\n   */\n  toggleFullscreen: (toggled?: boolean) => void;\n  /**\n   * Toggles the visibility of the panel in the Storybook UI.\n   *\n   * @param toggled - Optional boolean value to set the panel visibility to. If not provided, it\n   *   will toggle the current state.\n   */\n  togglePanel: (toggled?: boolean) => void;\n  /**\n   * Toggles the position of the panel in the Storybook UI.\n   *\n   * @param position - Optional string value to set the panel position to. If not provided, it will\n   *   toggle between 'bottom' and 'right'.\n   */\n  togglePanelPosition: (position?: API_PanelPositions) => void;\n  /**\n   * Toggles the visibility of the navigation bar in the Storybook UI.\n   *\n   * @param toggled - Optional boolean value to set the navigation bar visibility to. If not\n   *   provided, it will toggle the current state.\n   */\n  toggleNav: (toggled?: boolean) => void;\n  /**\n   * Toggles the visibility of the toolbar in the Storybook UI.\n   *\n   * @param toggled - Optional boolean value to set the toolbar visibility to. If not provided, it\n   *   will toggle the current state.\n   */\n  toggleToolbar: (toggled?: boolean) => void;\n  /**\n   * Sets the options for the Storybook UI.\n   *\n   * @param options - An object containing the options to set.\n   */\n  setOptions: (options: any) => void;\n  /** Sets the sizes of the resizable elements in the layout. */\n  setSizes: (\n    options: Partial<Pick<API_Layout, 'navSize' | 'bottomPanelHeight' | 'rightPanelWidth'>>\n  ) => void;\n  /** GetIsFullscreen - Returns the current fullscreen mode of the Storybook UI. */\n  getIsFullscreen: () => boolean;\n  /** GetIsPanelShown - Returns the current visibility of the panel in the Storybook UI. */\n  getIsPanelShown: () => boolean;\n  /** GetIsNavShown - Returns the current visibility of the navigation bar in the Storybook UI. */\n  getIsNavShown: () => boolean;\n  /**\n   * GetShowToolbarWithCustomisations - Returns the current visibility of the toolbar, taking into\n   * account customisations requested by the end user via a layoutCustomisations function.\n   */\n  getShowToolbarWithCustomisations: (showToolbar: boolean) => boolean;\n  /**\n   * GetShowPanelWithCustomisations - Returns the current visibility of the addon panel, taking into\n   * account customisations requested by the end user via a layoutCustomisations function.\n   */\n  getShowPanelWithCustomisations: (showPanel: boolean) => boolean;\n  /**\n   * GetNavSizeWithCustomisations - Returns the size to apply to the sidebar/nav, taking into\n   * account customisations requested by the end user via a layoutCustomisations function.\n   */\n  getNavSizeWithCustomisations: (navSize: number) => number;\n  /**\n   * Attempts to focus an element identified by its ID.\n   *\n   * @param elementId - The id of the element to focus.\n   * @param options - Options for focusing the element.\n   * @param options.forceFocus - Whether to make the element focusable even though it wasn't.\n   * @param options.select - Whether to call select() on the element after focusing it.\n   * @param options.poll - Whether to poll for the element if it is not immediately available.\n   *   Defaults to true. When true, polls every 50ms for up to 500ms.\n   * @returns Whether the element was successfully focused. Returns a Promise when polling.\n   */\n  focusOnUIElement: (\n    elementId?: string,\n    options?: boolean | { forceFocus?: boolean; select?: boolean; poll?: boolean }\n  ) => boolean | Promise<boolean>;\n}\n\ntype PartialSubState = Partial<SubState>;\n\nexport const DEFAULT_NAV_SIZE = 300;\nexport const DEFAULT_BOTTOM_PANEL_HEIGHT = 300;\nexport const DEFAULT_RIGHT_PANEL_WIDTH = 400;\n\nexport const getDefaultLayoutState: () => SubState = () => {\n  return {\n    ui: {\n      enableShortcuts: true,\n    },\n    layout: {\n      initialActive: ActiveTabs.CANVAS,\n      showToolbar: true,\n      navSize: DEFAULT_NAV_SIZE,\n      bottomPanelHeight: DEFAULT_BOTTOM_PANEL_HEIGHT,\n      rightPanelWidth: DEFAULT_RIGHT_PANEL_WIDTH,\n      recentVisibleSizes: {\n        navSize: DEFAULT_NAV_SIZE,\n        bottomPanelHeight: DEFAULT_BOTTOM_PANEL_HEIGHT,\n        rightPanelWidth: DEFAULT_RIGHT_PANEL_WIDTH,\n      },\n      panelPosition: 'bottom',\n      showTabs: true,\n    },\n    layoutCustomisations: {\n      showSidebar: undefined,\n      showToolbar: undefined,\n    },\n    selectedPanel: undefined,\n    theme: create(),\n  };\n};\n\nexport const focusableUIElements = {\n  addonPanel: 'storybook-panel-region',\n  storySearchField: 'storybook-explorer-searchfield',\n  storyListMenu: 'storybook-explorer-menu',\n  storyPanelRoot: 'storybook-panel-root',\n  showAddonPanel: 'storybook-show-addon-panel',\n  sidebarRegion: 'storybook-sidebar-region',\n  showSidebar: 'storybook-show-sidebar',\n};\n\nconst getIsNavShown = (state: State) => {\n  return state.layout.navSize > 0;\n};\nconst getIsPanelShown = (state: State) => {\n  const { bottomPanelHeight, rightPanelWidth, panelPosition } = state.layout;\n\n  return (\n    (panelPosition === 'bottom' && bottomPanelHeight > 0) ||\n    (panelPosition === 'right' && rightPanelWidth > 0)\n  );\n};\nconst getIsFullscreen = (state: State) => {\n  return !getIsNavShown(state) && !getIsPanelShown(state);\n};\n\nconst getRecentVisibleSizes = (layoutState: API_Layout) => {\n  return {\n    navSize: layoutState.navSize > 0 ? layoutState.navSize : layoutState.recentVisibleSizes.navSize,\n    bottomPanelHeight:\n      layoutState.bottomPanelHeight > 0\n        ? layoutState.bottomPanelHeight\n        : layoutState.recentVisibleSizes.bottomPanelHeight,\n    rightPanelWidth:\n      layoutState.rightPanelWidth > 0\n        ? layoutState.rightPanelWidth\n        : layoutState.recentVisibleSizes.rightPanelWidth,\n  };\n};\n\nexport const init: ModuleFn<SubAPI, SubState> = ({ store, provider, singleStory }) => {\n  const api = {\n    toggleFullscreen(nextState?: boolean) {\n      return store.setState(\n        (state: State) => {\n          const isFullscreen = getIsFullscreen(state);\n          const shouldFullscreen = typeof nextState === 'boolean' ? nextState : !isFullscreen;\n\n          if (shouldFullscreen === isFullscreen) {\n            return { layout: state.layout };\n          }\n\n          return shouldFullscreen\n            ? {\n                layout: {\n                  ...state.layout,\n                  navSize: 0,\n                  bottomPanelHeight: 0,\n                  rightPanelWidth: 0,\n                  recentVisibleSizes: getRecentVisibleSizes(state.layout),\n                },\n              }\n            : {\n                layout: {\n                  ...state.layout,\n                  navSize: state.singleStory ? 0 : state.layout.recentVisibleSizes.navSize,\n                  bottomPanelHeight: state.layout.recentVisibleSizes.bottomPanelHeight,\n                  rightPanelWidth: state.layout.recentVisibleSizes.rightPanelWidth,\n                },\n              };\n        },\n        { persistence: 'session' }\n      );\n    },\n\n    togglePanel(nextState?: boolean) {\n      return store.setState(\n        (state: State) => {\n          const isPanelShown = getIsPanelShown(state);\n\n          const shouldShowPanel = typeof nextState === 'boolean' ? nextState : !isPanelShown;\n\n          if (shouldShowPanel === isPanelShown) {\n            return { layout: state.layout };\n          }\n\n          return shouldShowPanel\n            ? {\n                layout: {\n                  ...state.layout,\n                  bottomPanelHeight: state.layout.recentVisibleSizes.bottomPanelHeight,\n                  rightPanelWidth: state.layout.recentVisibleSizes.rightPanelWidth,\n                },\n              }\n            : {\n                layout: {\n                  ...state.layout,\n                  bottomPanelHeight: 0,\n                  rightPanelWidth: 0,\n                  recentVisibleSizes: getRecentVisibleSizes(state.layout),\n                },\n              };\n        },\n        { persistence: 'session' }\n      );\n    },\n\n    togglePanelPosition(position?: 'bottom' | 'right') {\n      return store.setState(\n        (state: State) => {\n          const nextPosition =\n            position || (state.layout.panelPosition === 'right' ? 'bottom' : 'right');\n\n          return {\n            layout: {\n              ...state.layout,\n              panelPosition: nextPosition,\n              bottomPanelHeight: state.layout.recentVisibleSizes.bottomPanelHeight,\n              rightPanelWidth: state.layout.recentVisibleSizes.rightPanelWidth,\n            },\n          };\n        },\n        { persistence: 'permanent' }\n      );\n    },\n\n    toggleNav(nextState?: boolean) {\n      return store.setState(\n        (state: State) => {\n          if (state.singleStory) {\n            return { layout: state.layout };\n          }\n\n          const isNavShown = getIsNavShown(state);\n\n          const shouldShowNav = typeof nextState === 'boolean' ? nextState : !isNavShown;\n\n          if (shouldShowNav === isNavShown) {\n            return { layout: state.layout };\n          }\n\n          return shouldShowNav\n            ? {\n                layout: {\n                  ...state.layout,\n                  navSize: state.layout.recentVisibleSizes.navSize,\n                },\n              }\n            : {\n                layout: {\n                  ...state.layout,\n                  navSize: 0,\n                  recentVisibleSizes: getRecentVisibleSizes(state.layout),\n                },\n              };\n        },\n        { persistence: 'session' }\n      );\n    },\n\n    toggleToolbar(toggled?: boolean) {\n      return store.setState(\n        (state: State) => {\n          const value = typeof toggled !== 'undefined' ? toggled : !state.layout.showToolbar;\n\n          return {\n            layout: {\n              ...state.layout,\n              showToolbar: value,\n            },\n          };\n        },\n        { persistence: 'session' }\n      );\n    },\n\n    setSizes({\n      navSize,\n      bottomPanelHeight,\n      rightPanelWidth,\n    }: Partial<Pick<API_Layout, 'navSize' | 'bottomPanelHeight' | 'rightPanelWidth'>>) {\n      return store.setState(\n        (state: State) => {\n          const nextLayoutState = {\n            ...state.layout,\n            navSize: navSize ?? state.layout.navSize,\n            bottomPanelHeight: bottomPanelHeight ?? state.layout.bottomPanelHeight,\n            rightPanelWidth: rightPanelWidth ?? state.layout.rightPanelWidth,\n          };\n          return {\n            layout: {\n              ...nextLayoutState,\n              recentVisibleSizes: getRecentVisibleSizes(nextLayoutState),\n            },\n          };\n        },\n        { persistence: 'session' }\n      );\n    },\n\n    /**\n     * Attempts to focus (and select) an element identified by its ID. It is the responsibility of\n     * the callee to ensure that the element is present in the DOM and that no focus trap is\n     * available. When polling is enabled, this API polls and attempts to perform the focus for a\n     * set duration (max 500ms), so that race conditions can be avoided with the current API\n     * design.\n     *\n     * @param elementId The id of the element to focus.\n     * @param options When a boolean, treated as the `select` option for backwards compatibility.\n     *   When an object, may contain `select` and `poll` options.\n     * @returns Whether the element was successfully focused. Returns a Promise when polling.\n     */\n    focusOnUIElement(\n      elementId?: string,\n      options?: boolean | { forceFocus?: boolean; select?: boolean; poll?: boolean }\n    ): boolean | Promise<boolean> {\n      // See RFC https://github.com/storybookjs/storybook/discussions/32983 for\n      // ways to make this API more robust to focus-trap race conditions.\n\n      const {\n        forceFocus = false,\n        select = false,\n        poll = true,\n      } = typeof options === 'boolean' ? { select: options } : (options ?? {});\n\n      if (!elementId) {\n        return false;\n      }\n\n      const attemptFocus = () => {\n        const element = document.getElementById(elementId);\n        if (!element) {\n          return false;\n        }\n\n        element.focus();\n        if (\n          element !== document.activeElement &&\n          forceFocus &&\n          element.getAttribute('tabindex') === null\n        ) {\n          element.setAttribute('tabindex', '-1');\n          element.focus();\n        }\n\n        if (element !== document.activeElement && element.id !== document.activeElement?.id) {\n          return false;\n        }\n\n        if (select) {\n          (element as any).select?.();\n        }\n        return true;\n      };\n\n      if (attemptFocus()) {\n        return true;\n      }\n\n      if (!poll) {\n        return false;\n      }\n\n      // Poll every 50ms for up to 500ms to account for race conditions.\n      return new Promise<boolean>((resolve) => {\n        const startTime = Date.now();\n        const maxDuration = 500;\n        const pollInterval = 50;\n\n        const intervalId = setInterval(() => {\n          const elapsed = Date.now() - startTime;\n\n          if (attemptFocus()) {\n            clearInterval(intervalId);\n            resolve(true);\n            return;\n          }\n\n          if (elapsed >= maxDuration) {\n            clearInterval(intervalId);\n            resolve(false);\n          }\n        }, pollInterval);\n      });\n    },\n\n    getInitialOptions() {\n      const { theme, selectedPanel, layoutCustomisations, ...options } = provider.getConfig();\n      const defaultLayoutState = getDefaultLayoutState();\n\n      return {\n        ...defaultLayoutState,\n        layout: {\n          ...toMerged(\n            defaultLayoutState.layout,\n            pick(options, Object.keys(defaultLayoutState.layout))\n          ),\n          ...(singleStory && { navSize: 0 }),\n        },\n        layoutCustomisations: {\n          ...defaultLayoutState.layoutCustomisations,\n          ...(layoutCustomisations ?? {}),\n        },\n        ui: toMerged(defaultLayoutState.ui, pick(options, Object.keys(defaultLayoutState.ui))),\n        selectedPanel: selectedPanel || defaultLayoutState.selectedPanel,\n        theme: theme || defaultLayoutState.theme,\n      };\n    },\n\n    getIsFullscreen() {\n      return getIsFullscreen(store.getState());\n    },\n    getIsPanelShown() {\n      return getIsPanelShown(store.getState());\n    },\n    getIsNavShown() {\n      return getIsNavShown(store.getState());\n    },\n\n    getShowToolbarWithCustomisations(showToolbar: boolean) {\n      const state = store.getState();\n\n      if (isFunction(state.layoutCustomisations.showToolbar)) {\n        return state.layoutCustomisations.showToolbar(state, showToolbar) ?? showToolbar;\n      }\n\n      return showToolbar;\n    },\n\n    getShowPanelWithCustomisations(showPanel: boolean) {\n      const state = store.getState();\n\n      if (isFunction(state.layoutCustomisations.showPanel)) {\n        return state.layoutCustomisations.showPanel(state, showPanel) ?? showPanel;\n      }\n\n      return showPanel;\n    },\n\n    getNavSizeWithCustomisations(navSize: number) {\n      const state = store.getState();\n\n      if (isFunction(state.layoutCustomisations.showSidebar)) {\n        const shouldShowNav = state.layoutCustomisations.showSidebar(state, navSize !== 0);\n        if (navSize === 0 && shouldShowNav === true) {\n          return state.layout.recentVisibleSizes.navSize;\n        } else if (navSize !== 0 && shouldShowNav === false) {\n          return 0;\n        }\n      }\n\n      return navSize;\n    },\n\n    setOptions: (options: any) => {\n      const { layout, ui, selectedPanel, theme } = store.getState();\n\n      if (!options) {\n        return;\n      }\n\n      const updatedLayout = {\n        ...layout,\n        ...(options.layout || {}),\n        ...pick(options, Object.keys(layout)),\n        ...(singleStory && { navSize: 0 }),\n      };\n\n      const updatedUi = {\n        ...ui,\n        ...options.ui,\n        ...toMerged(options.ui || {}, pick(options, Object.keys(ui))),\n      };\n\n      const updatedTheme = {\n        ...theme,\n        ...options.theme,\n      };\n\n      const modification: PartialSubState = {};\n\n      if (!deepEqual(ui, updatedUi)) {\n        modification.ui = updatedUi;\n      }\n      if (!deepEqual(layout, updatedLayout)) {\n        modification.layout = updatedLayout;\n      }\n      if (options.selectedPanel && !deepEqual(selectedPanel, options.selectedPanel)) {\n        modification.selectedPanel = options.selectedPanel;\n      }\n\n      if (Object.keys(modification).length) {\n        store.setState(modification, { persistence: 'permanent' });\n      }\n      if (!deepEqual(theme, updatedTheme)) {\n        store.setState({ theme: updatedTheme });\n      }\n    },\n  };\n\n  const persisted = pick(store.getState(), ['layout', 'selectedPanel']);\n\n  provider.channel?.on(SET_CONFIG, () => {\n    api.setOptions(merge(api.getInitialOptions(), persisted));\n  });\n\n  return {\n    api,\n    state: merge(api.getInitialOptions(), persisted),\n  };\n};\n"
  },
  {
    "path": "code/core/src/manager-api/modules/notifications.ts",
    "content": "import type { API_Notification } from 'storybook/internal/types';\n\nimport { partition } from 'es-toolkit/array';\n\nimport type { ModuleFn } from '../lib/types.tsx';\n\nexport interface SubState {\n  notifications: API_Notification[];\n}\n\n/** The API for managing notifications. */\nexport interface SubAPI {\n  /**\n   * Adds a new notification to the list of notifications. If a notification with the same ID\n   * already exists, it will be replaced.\n   *\n   * @param notification - The notification to add.\n   */\n  addNotification: (notification: API_Notification) => void;\n\n  /**\n   * Removes a notification from the list of notifications and calls the onClear callback.\n   *\n   * @param id - The ID of the notification to remove.\n   */\n  clearNotification: (id: string) => void;\n}\n\nexport const init: ModuleFn = ({ store }) => {\n  const api: SubAPI = {\n    addNotification: (newNotification) => {\n      store.setState(({ notifications }) => {\n        const [existing, others] = partition(notifications, (n) => n.id === newNotification.id);\n        existing.forEach((notification) => {\n          if (notification.onClear) {\n            notification.onClear({ dismissed: false, timeout: false });\n          }\n        });\n        return { notifications: [...others, newNotification] };\n      });\n    },\n\n    clearNotification: (notificationId) => {\n      store.setState(({ notifications }) => {\n        const [matching, others] = partition(notifications, (n) => n.id === notificationId);\n        matching.forEach((notification) => {\n          if (notification.onClear) {\n            notification.onClear({ dismissed: false, timeout: false });\n          }\n        });\n        return { notifications: others };\n      });\n    },\n  };\n\n  const state: SubState = { notifications: [] };\n\n  return {\n    api,\n    state,\n  };\n};\n"
  },
  {
    "path": "code/core/src/manager-api/modules/open-in-editor.tsx",
    "content": "import React from 'react';\n\nimport {\n  OPEN_IN_EDITOR_REQUEST,\n  OPEN_IN_EDITOR_RESPONSE,\n  type OpenInEditorResponsePayload,\n} from 'storybook/internal/core-events';\nimport type { API_Notification } from 'storybook/internal/types';\n\nimport { FailedIcon } from '@storybook/icons';\n\nimport type { ModuleFn } from '../lib/types.tsx';\n\nexport interface SubState {\n  notifications: API_Notification[];\n}\n\n/** The API for opening files in the editor. */\nexport interface SubAPI {\n  /**\n   * Opens the file in the editor. You can optionally provide a line and column number to open at a\n   * more specific location.\n   */\n  openInEditor: (payload: {\n    file: string;\n    line?: number;\n    column?: number;\n  }) => Promise<OpenInEditorResponsePayload>;\n}\n\nexport const init: ModuleFn = ({ provider, fullAPI }) => {\n  const api: SubAPI = {\n    openInEditor(payload: {\n      file: string;\n      line?: number;\n      column?: number;\n    }): Promise<OpenInEditorResponsePayload> {\n      return new Promise((resolve) => {\n        const { file, line, column } = payload;\n        const handler = (res: OpenInEditorResponsePayload) => {\n          if (res.file === file && res.line === line && res.column === column) {\n            provider.channel?.off(OPEN_IN_EDITOR_RESPONSE, handler);\n            resolve(res);\n          }\n        };\n        provider.channel?.on(OPEN_IN_EDITOR_RESPONSE, handler);\n        provider.channel?.emit(OPEN_IN_EDITOR_REQUEST, payload);\n      });\n    },\n  };\n\n  const state: SubState = { notifications: [] };\n\n  return {\n    api,\n    state,\n    init: async () => {\n      const { color } = await import('../../theming/index.ts');\n      provider.channel?.on(OPEN_IN_EDITOR_RESPONSE, (payload: OpenInEditorResponsePayload) => {\n        if (payload.error !== null) {\n          fullAPI.addNotification({\n            id: 'open-in-editor-error',\n            content: {\n              headline: 'Failed to open in editor',\n              subHeadline:\n                payload.error ||\n                'Check the Storybook process on the command line for more details.',\n            },\n            icon: <FailedIcon color={color.negative} />,\n            duration: 8_000,\n          });\n        }\n      });\n    },\n  };\n};\n"
  },
  {
    "path": "code/core/src/manager-api/modules/provider.ts",
    "content": "import type { API_IframeRenderer } from 'storybook/internal/types';\n\nimport type { ModuleFn } from '../lib/types.tsx';\n\nexport interface SubAPI {\n  renderPreview?: API_IframeRenderer;\n}\n\nexport const init: ModuleFn<SubAPI, {}> = ({ provider, fullAPI }) => {\n  return {\n    api: provider.renderPreview ? { renderPreview: provider.renderPreview } : {},\n    state: {},\n    init: () => {\n      provider.handleAPI(fullAPI);\n    },\n  };\n};\n"
  },
  {
    "path": "code/core/src/manager-api/modules/refs.ts",
    "content": "import type {\n  API_ComposedRef,\n  API_ComposedRefUpdate,\n  API_IndexHash,\n  API_Refs,\n  API_SetRefData,\n  API_StoryMapper,\n  SetStoriesStoryData,\n  StoryIndex,\n} from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { dedent } from 'ts-dedent';\n\nimport {\n  transformSetStoriesStoryDataToPreparedStoryIndex,\n  transformStoryIndexToStoriesHash,\n} from '../lib/stories.ts';\nimport type { ModuleFn } from '../lib/types.tsx';\n\nconst { location, fetch } = global;\n\nexport interface SubState {\n  refs: API_Refs;\n}\n\nexport interface SubAPI {\n  /**\n   * Finds a composed ref by its source.\n   *\n   * @param {string} source - The source/URL of the composed ref.\n   * @returns {API_ComposedRef} - The composed ref object.\n   */\n  findRef: (source: string) => API_ComposedRef;\n  /**\n   * Sets a composed ref by its ID and data.\n   *\n   * @param {string} id - The ID of the composed ref.\n   * @param {API_SetRefData} data - The data to set for the composed ref.\n   * @param {boolean} [ready] - Whether the composed ref is ready.\n   */\n  setRef: (id: string, data: API_SetRefData, ready?: boolean) => void;\n  /**\n   * Updates a composed ref by its ID and update object.\n   *\n   * @param {string} id - The ID of the composed ref.\n   * @param {API_ComposedRefUpdate} ref - The update object for the composed ref.\n   */\n  updateRef: (id: string, ref: API_ComposedRefUpdate) => Promise<void>;\n  /**\n   * Gets all composed refs.\n   *\n   * @returns {API_Refs} - The composed refs object.\n   */\n  getRefs: () => API_Refs;\n  /**\n   * Checks if a composed ref is valid.\n   *\n   * @param {API_SetRefData} ref - The composed ref to check.\n   * @returns {Promise<void>} - A promise that resolves when the check is complete.\n   */\n  checkRef: (ref: API_SetRefData) => Promise<void>;\n  /**\n   * Changes the version of a composed ref by its ID and URL.\n   *\n   * @param {string} id - The ID of the composed ref.\n   * @param {string} url - The new URL for the composed ref.\n   */\n  changeRefVersion: (id: string, url: string) => Promise<void>;\n  /**\n   * Changes the state of a composed ref by its ID and previewInitialized flag.\n   *\n   * @param {string} id - The ID of the composed ref.\n   * @param {boolean} previewInitialized - The new previewInitialized flag for the composed ref.\n   */\n  changeRefState: (id: string, previewInitialized: boolean) => void;\n}\n\nexport const getSourceType = (source: string, refId?: string) => {\n  const { origin: localOrigin, pathname: localPathname } = location;\n  const { origin: sourceOrigin, pathname: sourcePathname } = new URL(source);\n\n  const localFull = `${localOrigin + localPathname}`.replace(/\\/[^\\/]*$/, '');\n  const sourceFull = `${sourceOrigin + sourcePathname}`.replace(/\\/[^\\/]*$/, '');\n\n  if (localFull === sourceFull) {\n    return ['local', sourceFull];\n  }\n  if (refId || source) {\n    return ['external', sourceFull];\n  }\n  return [null, null];\n};\n\nexport const defaultStoryMapper: API_StoryMapper = (b: any, a: any) => {\n  return { ...a, kind: a.kind.replace('|', '/') };\n};\n\nconst addRefIds = (input: API_IndexHash, ref: API_ComposedRef): API_IndexHash => {\n  return Object.entries(input).reduce((acc, [id, item]) => {\n    return { ...acc, [id]: { ...item!, refId: ref.id } };\n  }, {} as API_IndexHash);\n};\n\nasync function handleRequest(\n  request: Response | Promise<Response | boolean> | boolean\n): Promise<API_SetRefData> {\n  if (!request) {\n    return {};\n  }\n\n  try {\n    const response = await request;\n    if (response === false || response === true) {\n      throw new Error('Unexpected boolean response');\n    }\n    if (!response.ok) {\n      // Check for 401 responses that may contain loginUrl\n      if (response.status === 401) {\n        try {\n          const json = await response.json();\n          if (json.loginUrl) {\n            return { loginUrl: json.loginUrl };\n          }\n        } catch {\n          // Fall through to error handling if JSON parsing fails\n        }\n      }\n      throw new Error(`Unexpected response not OK: ${response.statusText}`);\n    }\n\n    const json = await response.json();\n\n    if (json.entries || json.stories) {\n      return { storyIndex: json };\n    }\n\n    return json as API_SetRefData;\n  } catch (err: any) {\n    return { indexError: err };\n  }\n}\n\ninterface UrlParseResult {\n  url: string;\n  authorization: string | undefined;\n}\n\nconst parseUrl = (url: string): UrlParseResult => {\n  const credentialsRegex = /https?:\\/\\/(.+:.+)@/;\n  let cleanUrl = url;\n  let authorization;\n  const [, credentials] = url.match(credentialsRegex) || [];\n\n  if (credentials) {\n    cleanUrl = url.replace(`${credentials}@`, '');\n    authorization = btoa(`${credentials}`);\n  }\n  return {\n    url: cleanUrl,\n    authorization,\n  };\n};\n\nconst map = (\n  input: SetStoriesStoryData,\n  ref: API_ComposedRef,\n  options: { storyMapper?: API_StoryMapper }\n): SetStoriesStoryData => {\n  const { storyMapper } = options;\n  if (storyMapper) {\n    return Object.entries(input).reduce((acc, [id, item]) => {\n      return { ...acc, [id]: storyMapper(ref, item) };\n    }, {} as SetStoriesStoryData);\n  }\n  return input;\n};\n\nexport const init: ModuleFn<SubAPI, SubState> = (\n  { store, provider, singleStory, docsOptions = {} },\n  { runCheck = true } = {}\n) => {\n  const api: SubAPI = {\n    findRef: (source): any => {\n      const refs = api.getRefs();\n\n      return Object.values(refs).find(({ url }: any) => url.match(source));\n    },\n    changeRefVersion: async (id, url) => {\n      const { versions, title } = api.getRefs()[id];\n      const ref: API_SetRefData = {\n        id,\n        url,\n        versions,\n        title,\n        index: {},\n        filteredIndex: {},\n        expanded: true,\n      };\n\n      await api.setRef(id, { ...ref, type: 'unknown' }, false);\n      await api.checkRef(ref);\n    },\n    changeRefState: (id, previewInitialized) => {\n      const { [id]: ref, ...updated } = api.getRefs();\n\n      updated[id] = { ...ref, previewInitialized };\n\n      store.setState({\n        refs: updated,\n      });\n    },\n    checkRef: async (ref) => {\n      const { id, url, version, type } = ref;\n      const isPublic = type === 'server-checked';\n\n      // ref's type starts as either 'unknown' or 'server-checked'\n      // \"server-checked\" happens when we were able to verify the storybook is accessible from node (without cookies)\n      // \"unknown\" happens if the request was declined of failed (this can happen because the storybook doesn't exists or authentication is required)\n      //\n      // we then make a request for stories.json\n      //\n      // if this request fails when storybook is server-checked we mark the ref as \"auto-inject\", this is a fallback mechanism for local storybook, legacy storybooks, and storybooks that lack stories.json\n      // if the request fails with type \"unknown\" we give up and show an error\n      // if the request succeeds we set the ref to 'lazy' type, and show the stories in the sidebar without injecting the iframe first\n      //\n      // then we fetch metadata if the above fetch succeeded\n\n      const loadedData: API_SetRefData = {};\n      const query = version ? `?version=${version}` : '';\n      const credentials = isPublic ? 'omit' : 'include';\n      const urlParseResult = parseUrl(url!);\n\n      const headers: HeadersInit = {\n        Accept: 'application/json',\n      };\n\n      if (urlParseResult.authorization) {\n        Object.assign(headers, {\n          Authorization: `Basic ${urlParseResult.authorization}`,\n        });\n      }\n\n      const [indexResult, storiesResult] = await Promise.all(\n        ['index.json', 'stories.json'].map(async (file) =>\n          handleRequest(\n            fetch(`${urlParseResult.url}/${file}${query}`, {\n              headers,\n              credentials,\n            })\n          )\n        )\n      );\n\n      if (!indexResult.indexError || !storiesResult.indexError) {\n        const metadata = await handleRequest(\n          fetch(`${urlParseResult.url}/metadata.json${query}`, {\n            headers,\n            credentials,\n            cache: 'no-cache',\n          }).catch(() => false)\n        );\n\n        Object.assign(loadedData, {\n          ...(indexResult.indexError ? storiesResult : indexResult),\n          ...(!metadata.indexError && metadata),\n        });\n      } else if (!isPublic) {\n        // In theory the `/iframe.html` could be private and the `stories.json` could not exist, but in practice\n        // the only private servers we know about (Chromatic) always include `stories.json`. So we can tell\n        // if the ref actually exists by simply checking `stories.json` w/ credentials.\n        loadedData.indexError = {\n          message: dedent`\n            Error: Loading of ref failed\n              at fetch (lib/api/src/modules/refs.ts)\n\n            URL: ${urlParseResult.url}\n\n            We weren't able to load the above URL,\n            it's possible a CORS error happened.\n\n            Please check your dev-tools network tab.\n          `,\n        } as Error;\n      }\n\n      const versions =\n        ref.versions && Object.keys(ref.versions).length ? ref.versions : loadedData.versions;\n\n      await api.setRef(id!, {\n        id,\n        url: urlParseResult.url,\n        ...loadedData,\n        ...(versions ? { versions } : {}),\n        type: !loadedData.storyIndex ? 'auto-inject' : 'lazy',\n      });\n    },\n\n    getRefs: () => {\n      const { refs = {} } = store.getState();\n\n      return refs;\n    },\n\n    setRef: async (id, { storyIndex, setStoriesData, ...rest }, ready = false) => {\n      if (singleStory) {\n        return;\n      }\n      let internal_index: StoryIndex | undefined;\n      let index: API_IndexHash | undefined;\n      let filteredIndex: API_IndexHash | undefined;\n      const { filters } = store.getState();\n      const { storyMapper = defaultStoryMapper } = provider.getConfig();\n      const ref = api.getRefs()[id];\n\n      if (storyIndex || setStoriesData) {\n        internal_index = setStoriesData\n          ? transformSetStoriesStoryDataToPreparedStoryIndex(\n              map(setStoriesData, ref, { storyMapper })\n            )\n          : storyIndex;\n\n        // @ts-expect-error (could be undefined)\n        filteredIndex = transformStoryIndexToStoriesHash(storyIndex, {\n          provider,\n          docsOptions,\n          filters,\n          allStatuses: {},\n        });\n        // @ts-expect-error (could be undefined)\n        index = transformStoryIndexToStoriesHash(storyIndex, {\n          provider,\n          docsOptions,\n          filters: {},\n          allStatuses: {},\n        });\n      }\n\n      if (index) {\n        index = addRefIds(index, ref);\n      }\n      if (filteredIndex) {\n        filteredIndex = addRefIds(filteredIndex, ref);\n      }\n      await api.updateRef(id, { ...ref, ...rest, index, filteredIndex, internal_index });\n    },\n\n    updateRef: async (id, data) => {\n      const { [id]: ref, ...updated } = api.getRefs();\n\n      updated[id] = { ...ref, ...data };\n\n      const ordered = Object.keys(initialState).reduce((obj: any, key) => {\n        obj[key] = updated[key];\n        return obj;\n      }, {});\n\n      await store.setState({\n        refs: ordered,\n      });\n    },\n  };\n\n  const refs: API_Refs = (!singleStory && global.REFS) || {};\n\n  const initialState: SubState['refs'] = refs;\n\n  if (runCheck) {\n    new Promise(async (resolve) => {\n      for (const ref of Object.values(refs)) {\n        await api.checkRef({ ...ref!, stories: {} } as API_SetRefData);\n      }\n      resolve(undefined);\n    });\n  }\n\n  return {\n    api,\n    state: {\n      refs: initialState,\n    },\n  };\n};\n"
  },
  {
    "path": "code/core/src/manager-api/modules/settings.ts",
    "content": "import type { API_Settings, StoryId } from 'storybook/internal/types';\n\nimport type { ModuleFn } from '../lib/types.tsx';\n\nexport interface SubAPI {\n  storeSelection: () => void;\n  retrieveSelection: () => StoryId;\n  /**\n   * Changes the active settings tab.\n   *\n   * @example\n   *\n   * ```ts\n   * changeSettingsTab(`about`);\n   * ```\n   *\n   * @param path - The path of the settings page to navigate to. The path NOT should include the\n   *   `/settings` prefix.\n   */\n  changeSettingsTab: (path: string) => void;\n  /** Closes the settings screen and returns to the last tracked story or the first story. */\n  closeSettings: () => void;\n  /**\n   * Checks if the settings screen is currently active.\n   *\n   * @returns A boolean indicating whether the settings screen is active.\n   */\n  isSettingsScreenActive: () => boolean;\n}\n\nexport interface SubState {\n  settings: API_Settings;\n}\n\nexport const init: ModuleFn<SubAPI, SubState> = ({ store, navigate, fullAPI }): any => {\n  const isSettingsScreenActive = () => {\n    const { path } = fullAPI.getUrlState();\n    return !!(path || '').match(/^\\/settings/);\n  };\n  const api: SubAPI = {\n    closeSettings: () => {\n      const {\n        settings: { lastTrackedStoryId },\n      } = store.getState();\n\n      if (lastTrackedStoryId) {\n        fullAPI.selectStory(lastTrackedStoryId);\n      } else {\n        fullAPI.selectFirstStory();\n      }\n    },\n    changeSettingsTab: (path: string) => {\n      navigate(`/settings/${path}`);\n    },\n    isSettingsScreenActive,\n    retrieveSelection() {\n      const { settings } = store.getState();\n\n      return settings.lastTrackedStoryId;\n    },\n    storeSelection: async () => {\n      const { storyId, settings } = store.getState();\n\n      await store.setState({\n        settings: { ...settings, lastTrackedStoryId: storyId },\n      });\n    },\n  };\n\n  return {\n    state: { settings: { lastTrackedStoryId: null } },\n    api,\n  };\n};\n"
  },
  {
    "path": "code/core/src/manager-api/modules/shortcuts.ts",
    "content": "import {\n  FORCE_REMOUNT,\n  PREVIEW_KEYDOWN,\n  STORIES_COLLAPSE_ALL,\n  STORIES_EXPAND_ALL,\n} from 'storybook/internal/core-events';\n\nimport { global } from '@storybook/global';\n\nimport copy from 'copy-to-clipboard';\n\nimport type { KeyboardEventLike } from '../lib/shortcut.ts';\nimport { eventToShortcut, shortcutMatchesShortcut } from '../lib/shortcut.ts';\nimport type { ModuleFn } from '../lib/types.tsx';\nimport { focusableUIElements } from './layout.ts';\n\nconst { navigator, document } = global;\n\nfunction wasFocusInElement(element: HTMLElement | null) {\n  return document.activeElement && element?.contains(document.activeElement);\n}\n\nexport const isMacLike = () =>\n  navigator && navigator.platform ? !!navigator.platform.match(/(Mac|iPhone|iPod|iPad)/i) : false;\nexport const controlOrMetaKey = () => (isMacLike() ? 'meta' : 'control');\n\nexport function keys<O>(o: O) {\n  return Object.keys(o!) as (keyof O)[];\n}\n\nexport interface SubState {\n  shortcuts: API_Shortcuts;\n}\n\nexport interface SubAPI {\n  /** Returns the current shortcuts. */\n  getShortcutKeys(): API_Shortcuts;\n  /** Returns the default shortcuts. */\n  getDefaultShortcuts(): API_Shortcuts | API_AddonShortcutDefaults;\n  /** Returns the shortcuts for addons. */\n  getAddonsShortcuts(): API_AddonShortcuts;\n  /** Returns the labels for addon shortcuts. */\n  getAddonsShortcutLabels(): API_AddonShortcutLabels;\n  /** Returns the default shortcuts for addons. */\n  getAddonsShortcutDefaults(): API_AddonShortcutDefaults;\n  /**\n   * Sets the shortcuts to the given value.\n   *\n   * @param shortcuts The new shortcuts to set.\n   * @returns A promise that resolves to the new shortcuts.\n   */\n  setShortcuts(\n    update: API_Shortcuts | ((shortcuts: API_Shortcuts) => API_Shortcuts)\n  ): Promise<API_Shortcuts>;\n  /**\n   * Sets the shortcut for the given action to the given value.\n   *\n   * @param action The action to set the shortcut for.\n   * @param value The new shortcut to set.\n   * @returns A promise that resolves to the new shortcut.\n   */\n  setShortcut(action: API_Action, value: API_KeyCollection): Promise<API_KeyCollection>;\n  /**\n   * Sets the shortcut for the given addon to the given value.\n   *\n   * @param addon The addon to set the shortcut for.\n   * @param shortcut The new shortcut to set.\n   * @returns A promise that resolves to the new addon shortcut.\n   */\n  setAddonShortcut(addon: string, shortcut: API_AddonShortcut): Promise<API_AddonShortcut>;\n  /**\n   * Restores all default shortcuts.\n   *\n   * @returns A promise that resolves to the new shortcuts.\n   */\n  restoreAllDefaultShortcuts(): Promise<API_Shortcuts>;\n  /**\n   * Restores the default shortcut for the given action.\n   *\n   * @param action The action to restore the default shortcut for.\n   * @returns A promise that resolves to the new shortcut.\n   */\n  restoreDefaultShortcut(action: API_Action): Promise<API_KeyCollection>;\n  /**\n   * Handles a keydown event.\n   *\n   * @param event The event to handle.\n   */\n  handleKeydownEvent(event: KeyboardEventLike): void;\n  /**\n   * Handles a shortcut feature.\n   *\n   * @param feature The feature to handle.\n   * @param event The event to handle.\n   */\n  handleShortcutFeature(feature: API_Action, event: KeyboardEventLike): void;\n}\n\nexport type API_KeyCollection = string[];\n\nexport interface API_Shortcuts {\n  fullScreen: API_KeyCollection;\n  togglePanel: API_KeyCollection;\n  panelPosition: API_KeyCollection;\n  toggleNav: API_KeyCollection;\n  toolbar: API_KeyCollection;\n  search: API_KeyCollection;\n  focusNav: API_KeyCollection;\n  focusIframe: API_KeyCollection;\n  focusPanel: API_KeyCollection;\n  prevComponent: API_KeyCollection;\n  nextComponent: API_KeyCollection;\n  prevStory: API_KeyCollection;\n  nextStory: API_KeyCollection;\n  shortcutsPage: API_KeyCollection;\n  aboutPage: API_KeyCollection;\n  escape: API_KeyCollection;\n  collapseAll: API_KeyCollection;\n  expandAll: API_KeyCollection;\n  remount: API_KeyCollection;\n  openInEditor: API_KeyCollection;\n  openInIsolation: API_KeyCollection;\n  copyStoryLink: API_KeyCollection;\n  goToPreviousLandmark: API_KeyCollection;\n  goToNextLandmark: API_KeyCollection;\n  // TODO: bring this back once we want to add shortcuts for this\n  // copyStoryName: API_KeyCollection;\n}\n\nexport type API_Action = keyof API_Shortcuts;\n\ninterface API_AddonShortcut {\n  label: string;\n  defaultShortcut: API_KeyCollection;\n  actionName: string;\n  showInMenu?: boolean;\n  action: (...args: any[]) => any;\n}\ntype API_AddonShortcuts = Record<string, API_AddonShortcut>;\ntype API_AddonShortcutLabels = Record<string, string>;\ntype API_AddonShortcutDefaults = Record<string, API_KeyCollection>;\n\nexport const defaultShortcuts: API_Shortcuts = Object.freeze({\n  fullScreen: ['alt', 'F'],\n  togglePanel: ['alt', 'A'],\n  panelPosition: ['alt', 'D'],\n  toggleNav: ['alt', 'S'],\n  toolbar: ['alt', 'T'],\n  search: [controlOrMetaKey(), 'K'],\n  focusNav: ['1'],\n  focusIframe: ['2'],\n  focusPanel: ['3'],\n  prevComponent: ['alt', 'ArrowUp'],\n  nextComponent: ['alt', 'ArrowDown'],\n  prevStory: ['alt', 'ArrowLeft'],\n  nextStory: ['alt', 'ArrowRight'],\n  shortcutsPage: [controlOrMetaKey(), 'shift', ','],\n  aboutPage: [controlOrMetaKey(), ','],\n  escape: ['escape'], // This one is not customizable\n  collapseAll: [controlOrMetaKey(), 'shift', 'ArrowUp'],\n  expandAll: [controlOrMetaKey(), 'shift', 'ArrowDown'],\n  remount: ['alt', 'R'],\n  openInEditor: ['alt', 'shift', 'E'],\n  openInIsolation: ['alt', 'shift', 'I'],\n  copyStoryLink: ['alt', 'shift', 'L'],\n  goToPreviousLandmark: ['shift', 'F6'], // hardcoded in react-aria\n  goToNextLandmark: ['F6'], // hardcoded in react-aria\n  // TODO: bring this back once we want to add shortcuts for this\n  // copyStoryName: ['alt', 'shift', 'C'],\n});\n\nconst addonsShortcuts: API_AddonShortcuts = {};\n\nfunction shouldSkipShortcut(event: KeyboardEvent) {\n  const target = event.target as Element;\n  if (/input|textarea/i.test(target.tagName) || target.getAttribute('contenteditable') !== null) {\n    return true;\n  }\n  const dialogElement = target.closest('dialog[open]');\n  if (dialogElement) {\n    return true;\n  }\n\n  return false;\n}\n\nexport const init: ModuleFn = ({ store, fullAPI, provider }) => {\n  const api: SubAPI = {\n    // Getting and setting shortcuts\n    getShortcutKeys(): API_Shortcuts {\n      return store.getState().shortcuts;\n    },\n    getDefaultShortcuts(): API_Shortcuts | API_AddonShortcutDefaults {\n      return {\n        ...defaultShortcuts,\n        ...api.getAddonsShortcutDefaults(),\n      };\n    },\n    getAddonsShortcuts(): API_AddonShortcuts {\n      return addonsShortcuts;\n    },\n    getAddonsShortcutLabels(): API_AddonShortcutLabels {\n      const labels: API_AddonShortcutLabels = {};\n      Object.entries(api.getAddonsShortcuts()).forEach(([actionName, { label }]) => {\n        labels[actionName] = label;\n      });\n\n      return labels;\n    },\n    getAddonsShortcutDefaults(): API_AddonShortcutDefaults {\n      const defaults: API_AddonShortcutDefaults = {};\n      Object.entries(api.getAddonsShortcuts()).forEach(([actionName, { defaultShortcut }]) => {\n        defaults[actionName] = defaultShortcut;\n      });\n\n      return defaults;\n    },\n    async setShortcuts(update) {\n      const { shortcuts } = await store.setState(\n        (state) => ({ shortcuts: typeof update === 'function' ? update(state.shortcuts) : update }),\n        { persistence: 'permanent' }\n      );\n      return shortcuts;\n    },\n    async restoreAllDefaultShortcuts() {\n      return api.setShortcuts(api.getDefaultShortcuts() as API_Shortcuts);\n    },\n    async setShortcut(action, value) {\n      await api.setShortcuts((shortcuts) => ({ ...shortcuts, [action]: value }));\n      return value;\n    },\n    async setAddonShortcut(addon: string, shortcut: API_AddonShortcut) {\n      await api.setShortcuts((shortcuts) => ({\n        ...shortcuts,\n        [`${addon}-${shortcut.actionName}`]: shortcut.defaultShortcut,\n      }));\n      addonsShortcuts[`${addon}-${shortcut.actionName}`] = shortcut;\n      return shortcut;\n    },\n    async restoreDefaultShortcut(action) {\n      const defaultShortcut = api.getDefaultShortcuts()[action];\n      return api.setShortcut(action, defaultShortcut);\n    },\n\n    // Listening to shortcut events\n    handleKeydownEvent(event) {\n      const shortcut = eventToShortcut(event);\n      const shortcuts = api.getShortcutKeys();\n      const actions = keys(shortcuts);\n      const matchedFeature = actions.find((feature: API_Action) =>\n        shortcutMatchesShortcut(shortcut!, shortcuts[feature])\n      );\n      if (matchedFeature) {\n        api.handleShortcutFeature(matchedFeature, event);\n      }\n    },\n\n    // warning: event might not have a full prototype chain because it may originate from the channel\n    handleShortcutFeature(feature, event) {\n      const {\n        ui: { enableShortcuts },\n        storyId,\n        refId,\n        viewMode,\n      } = store.getState();\n      if (!enableShortcuts) {\n        return;\n      }\n\n      // Event.prototype.preventDefault is missing when received from the MessageChannel.\n      if (event?.preventDefault) {\n        event.preventDefault();\n      }\n      switch (feature) {\n        case 'escape': {\n          if (fullAPI.getIsFullscreen()) {\n            fullAPI.toggleFullscreen(false);\n          } else if (fullAPI.getIsNavShown()) {\n            fullAPI.toggleNav(true);\n          }\n          break;\n        }\n\n        // Handled by @react-aria/interactions and useLandmarkIndicator\n        case 'goToNextLandmark':\n        case 'goToPreviousLandmark':\n          break;\n\n        case 'focusNav': {\n          if (fullAPI.getIsFullscreen()) {\n            fullAPI.toggleFullscreen(false);\n          }\n          if (!fullAPI.getIsNavShown()) {\n            fullAPI.toggleNav(true);\n          }\n          fullAPI.focusOnUIElement(focusableUIElements.storyListMenu);\n          break;\n        }\n\n        case 'search': {\n          if (fullAPI.getIsFullscreen()) {\n            fullAPI.toggleFullscreen(false);\n          }\n          if (!fullAPI.getIsNavShown()) {\n            fullAPI.toggleNav(true);\n          }\n\n          setTimeout(() => {\n            fullAPI.focusOnUIElement(focusableUIElements.storySearchField, true);\n          }, 0);\n          break;\n        }\n\n        case 'focusIframe': {\n          const element = document.getElementById('storybook-preview-iframe') as HTMLIFrameElement;\n\n          if (element) {\n            try {\n              // should be like a channel message and all that, but yolo for now\n              element.contentWindow!.focus();\n            } catch (e) {\n              //\n            }\n          }\n          break;\n        }\n\n        case 'focusPanel': {\n          if (fullAPI.getIsFullscreen()) {\n            fullAPI.toggleFullscreen(false);\n          }\n          if (!fullAPI.getIsPanelShown()) {\n            fullAPI.togglePanel(true);\n          }\n          fullAPI.focusOnUIElement(focusableUIElements.storyPanelRoot);\n          break;\n        }\n\n        case 'nextStory': {\n          fullAPI.jumpToStory(1);\n          break;\n        }\n\n        case 'prevStory': {\n          fullAPI.jumpToStory(-1);\n          break;\n        }\n\n        case 'nextComponent': {\n          fullAPI.jumpToComponent(1);\n          break;\n        }\n\n        case 'prevComponent': {\n          fullAPI.jumpToComponent(-1);\n          break;\n        }\n\n        case 'fullScreen': {\n          fullAPI.toggleFullscreen();\n          break;\n        }\n\n        case 'togglePanel': {\n          const wasPanelShown = fullAPI.getIsPanelShown();\n          const panelElement = document.getElementById(focusableUIElements.addonPanel);\n\n          fullAPI.togglePanel();\n\n          if (wasPanelShown && wasFocusInElement(panelElement)) {\n            // poll: true always returns a Promise.\n            (\n              fullAPI.focusOnUIElement(focusableUIElements.showAddonPanel, {\n                poll: true,\n              }) as Promise<boolean>\n            ).then((success) => {\n              // Fallback to body for predictable behavior.\n              if (success === false) {\n                document.body.focus();\n              }\n            });\n          }\n\n          if (!wasPanelShown) {\n            fullAPI.focusOnUIElement(focusableUIElements.addonPanel, {\n              forceFocus: true,\n              poll: true,\n            });\n          }\n          break;\n        }\n\n        case 'toggleNav': {\n          const wasNavShown = fullAPI.getIsNavShown();\n          const sidebarElement = document.getElementById(focusableUIElements.sidebarRegion);\n\n          fullAPI.toggleNav();\n\n          if (wasNavShown && wasFocusInElement(sidebarElement)) {\n            // poll: true always returns a Promise.\n            (\n              fullAPI.focusOnUIElement(focusableUIElements.showSidebar, {\n                poll: true,\n              }) as Promise<boolean>\n            ).then((success) => {\n              // Fallback to body for predictable behavior.\n              if (success === false) {\n                document.body.focus();\n              }\n            });\n          }\n\n          if (!wasNavShown) {\n            fullAPI.focusOnUIElement(focusableUIElements.sidebarRegion, {\n              forceFocus: true,\n              poll: true,\n            });\n          }\n\n          break;\n        }\n\n        case 'toolbar': {\n          fullAPI.toggleToolbar();\n          break;\n        }\n\n        case 'panelPosition': {\n          if (fullAPI.getIsFullscreen()) {\n            fullAPI.toggleFullscreen(false);\n          }\n          if (!fullAPI.getIsPanelShown()) {\n            fullAPI.togglePanel(true);\n          }\n\n          fullAPI.togglePanelPosition();\n          break;\n        }\n\n        case 'aboutPage': {\n          fullAPI.navigate('/settings/about');\n          break;\n        }\n\n        case 'shortcutsPage': {\n          fullAPI.navigate('/settings/shortcuts');\n          break;\n        }\n        case 'collapseAll': {\n          fullAPI.emit(STORIES_COLLAPSE_ALL);\n          break;\n        }\n        case 'expandAll': {\n          fullAPI.emit(STORIES_EXPAND_ALL);\n          break;\n        }\n        case 'remount': {\n          fullAPI.emit(FORCE_REMOUNT, { storyId });\n          break;\n        }\n        case 'openInEditor': {\n          if (global.CONFIG_TYPE === 'DEVELOPMENT') {\n            fullAPI.openInEditor({\n              file: fullAPI.getCurrentStoryData().importPath,\n            });\n          }\n          break;\n        }\n        case 'openInIsolation': {\n          if (storyId && viewMode === 'story') {\n            const { previewHref } = fullAPI.getStoryHrefs(storyId, { refId });\n            window.open(previewHref, '_blank', 'noopener,noreferrer');\n          }\n          break;\n        }\n        // TODO: bring this back once we want to add shortcuts for this\n        // case 'copyStoryName': {\n        //   const storyData = fullAPI.getCurrentStoryData();\n        //   if (storyData.type === 'story') {\n        //     copy(storyData.exportName);\n        //   }\n        //   break;\n        // }\n        case 'copyStoryLink': {\n          if (storyId) {\n            const { managerHref } = fullAPI.getStoryHrefs(storyId, { refId });\n            copy(managerHref);\n          }\n          break;\n        }\n        default:\n          addonsShortcuts[feature].action();\n          break;\n      }\n    },\n  };\n\n  const { shortcuts: persistedShortcuts = defaultShortcuts }: SubState = store.getState();\n  const state: SubState = {\n    // Any saved shortcuts that are still in our set of defaults\n    shortcuts: keys(defaultShortcuts).reduce(\n      (acc, key) => ({ ...acc, [key]: persistedShortcuts[key] || defaultShortcuts[key] }),\n      defaultShortcuts\n    ),\n  };\n\n  const initModule = () => {\n    // Listen for keydown events in the manager\n    document.addEventListener('keydown', (event: KeyboardEvent) => {\n      if (!shouldSkipShortcut(event)) {\n        api.handleKeydownEvent(event);\n      }\n    });\n\n    // Also listen to keydown events sent over the channel\n    provider.channel?.on(PREVIEW_KEYDOWN, (data: { event: KeyboardEventLike }) => {\n      api.handleKeydownEvent(data.event);\n    });\n  };\n\n  return { api, state, init: initModule };\n};\n"
  },
  {
    "path": "code/core/src/manager-api/modules/statuses.ts",
    "content": "import type {\n  API_FilterFunction,\n  API_PreparedIndexEntry,\n  StatusValue,\n} from 'storybook/internal/types';\n\nimport { statusValueShortName, toStatusValue } from '../../shared/status-store/index.ts';\nimport { fullStatusStore } from '../stores/status.ts';\n\nexport const parseStatusesParam = (\n  statusesParam: string | undefined\n): { included: StatusValue[]; excluded: StatusValue[] } => {\n  if (!statusesParam) {\n    return { included: [], excluded: [] };\n  }\n\n  const included: StatusValue[] = [];\n  const excluded: StatusValue[] = [];\n\n  statusesParam.split(';').forEach((rawStatus) => {\n    if (!rawStatus) {\n      return;\n    }\n\n    const isExcluded = rawStatus.startsWith('!');\n    const shortName = isExcluded ? rawStatus.slice(1) : rawStatus;\n    const statusValue = toStatusValue(shortName);\n\n    if (!statusValue) {\n      return; // silently ignore unknown short names\n    }\n\n    if (isExcluded) {\n      excluded.push(statusValue);\n    } else {\n      included.push(statusValue);\n    }\n  });\n\n  return { included, excluded };\n};\n\nexport const serializeStatusesParam = (\n  included: StatusValue[],\n  excluded: StatusValue[]\n): string | undefined => {\n  if (!included.length && !excluded.length) {\n    return undefined;\n  }\n\n  const serializedIncluded = included.map((v) => statusValueShortName(v)).sort();\n  const serializedExcluded = excluded.map((v) => `!${statusValueShortName(v)}`).sort();\n\n  return [...serializedIncluded, ...serializedExcluded].join(';');\n};\n\nexport const computeStatusFilterFn = (\n  includedStatusFilters: StatusValue[],\n  excludedStatusFilters: StatusValue[]\n): API_FilterFunction => {\n  return (entry: API_PreparedIndexEntry) => {\n    if (!includedStatusFilters.length && !excludedStatusFilters.length) {\n      return true;\n    }\n\n    const allStatuses = fullStatusStore.getAll() ?? {};\n    const storyStatuses = allStatuses[entry.id];\n    const storyStatusValues = storyStatuses ? Object.values(storyStatuses).map((s) => s.value) : [];\n\n    const passesInclude =\n      !includedStatusFilters.length ||\n      includedStatusFilters.some((v) => storyStatusValues.includes(v));\n\n    const passesExclude =\n      !excludedStatusFilters.length ||\n      excludedStatusFilters.every((v) => !storyStatusValues.includes(v));\n\n    return passesInclude && passesExclude;\n  };\n};\n"
  },
  {
    "path": "code/core/src/manager-api/modules/stories.ts",
    "content": "import { logger } from 'storybook/internal/client-logger';\nimport {\n  CONFIG_ERROR,\n  CURRENT_STORY_WAS_SET,\n  DOCS_PREPARED,\n  PRELOAD_ENTRIES,\n  RESET_STORY_ARGS,\n  SELECT_STORY,\n  SET_CONFIG,\n  SET_CURRENT_STORY,\n  SET_FILTER,\n  SET_INDEX,\n  SET_STORIES,\n  STORY_ARGS_UPDATED,\n  STORY_CHANGED,\n  STORY_INDEX_INVALIDATED,\n  STORY_MISSING,\n  STORY_PREPARED,\n  STORY_SPECIFIED,\n  UPDATE_STORY_ARGS,\n} from 'storybook/internal/core-events';\nimport { sanitize, toId } from 'storybook/internal/csf';\nimport type { NavigateOptions } from 'storybook/internal/router';\nimport { queryFromLocation } from 'storybook/internal/router';\nimport type {\n  API_ComposedRef,\n  API_DocsEntry,\n  API_FilterFunction,\n  API_HashEntry,\n  API_IndexHash,\n  API_LeafEntry,\n  API_LoadedRefData,\n  API_PreparedStoryIndex,\n  API_StoryEntry,\n  API_TestEntry,\n  API_ViewMode,\n  Args,\n  ComponentTitle,\n  DocsPreparedPayload,\n  SetStoriesPayload,\n  StatusValue,\n  StoryId,\n  StoryIndex,\n  StoryKind,\n  StoryName,\n  StoryPreparedPayload,\n  Tag,\n  TagsOptions,\n} from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { getEventMetadata } from '../lib/events.ts';\nimport {\n  addPreparedStories,\n  denormalizeStoryParameters,\n  getComponentLookupList,\n  getStoriesLookupList,\n  transformStoryIndexToStoriesHash,\n} from '../lib/stories.ts';\nimport type { ModuleFn } from '../lib/types.tsx';\nimport { buildNavigationUrl } from '../lib/url.ts';\nimport type { ComposedRef } from '../root.tsx';\nimport { fullStatusStore } from '../stores/status.ts';\nimport { computeStatusFilterFn, parseStatusesParam, serializeStatusesParam } from './statuses.ts';\nimport {\n  computeStaticFilterFn,\n  computeTagsFilterFn,\n  getDefaultTagsFromPreset,\n  parseTagsParam,\n  serializeTagsParam,\n} from './tags.ts';\n\nconst { fetch } = global;\nconst STORY_INDEX_PATH = './index.json';\n\nconst TAGS_FILTER = 'tags-filter';\nconst STATIC_FILTER = 'static-filter';\nconst STATUS_FILTER = 'status-filter';\n\ntype Direction = -1 | 1;\ntype ParameterName = string;\n\ntype StoryUpdate = Partial<\n  Pick<API_StoryEntry, 'prepared' | 'parameters' | 'initialArgs' | 'argTypes' | 'args'>\n>;\n\ntype DocsUpdate = Partial<Pick<API_DocsEntry, 'prepared' | 'parameters'>>;\n\nexport interface SubState extends API_LoadedRefData {\n  storyId: StoryId;\n  internal_index?: API_PreparedStoryIndex;\n  viewMode: API_ViewMode;\n  filters: Record<string, API_FilterFunction>;\n  tagPresets: TagsOptions;\n  defaultIncludedTagFilters: Tag[];\n  defaultExcludedTagFilters: Tag[];\n  includedTagFilters: Tag[];\n  excludedTagFilters: Tag[];\n  includedStatusFilters: StatusValue[];\n  excludedStatusFilters: StatusValue[];\n}\n\nexport interface SubAPI {\n  /**\n   * The `storyId` method is a reference to the `toId` function from `@storybook/csf`, which is used\n   * to generate a unique ID for a story. This ID is used to identify a specific story in the\n   * Storybook index.\n   *\n   * @type {typeof toId}\n   */\n  storyId: typeof toId;\n  /**\n   * Resolves a story, docs, component or group ID to its corresponding hash entry in the index.\n   *\n   * @param {StoryId} storyId - The ID of the story to resolve.\n   * @param {string} [refsId] - The ID of the refs to use for resolving the story.\n   * @returns {API_HashEntry} - The hash entry corresponding to the given story ID.\n   */\n  resolveStory: (storyId: StoryId, refsId?: string) => API_HashEntry | undefined;\n  /**\n   * Selects the first story to display in the Storybook UI.\n   *\n   * @returns {void}\n   */\n  selectFirstStory: () => void;\n  /**\n   * Selects a story to display in the Storybook UI.\n   *\n   * @param {string} [kindOrId] - The kind or ID of the story to select.\n   * @param {StoryId} [story] - The ID of the story to select.\n   * @param {Object} [obj] - An optional object containing additional options.\n   * @param {string} [obj.ref] - The ref ID of the story to select.\n   * @param {API_ViewMode} [obj.viewMode] - The view mode to display the story in.\n   * @returns {void}\n   */\n  selectStory: (\n    kindOrId?: string,\n    story?: StoryId,\n    obj?: { ref?: string; viewMode?: API_ViewMode }\n  ) => void;\n  /**\n   * Returns the current story's data, including its ID, kind, name, and parameters.\n   *\n   * @returns {API_LeafEntry} The current story's data.\n   */\n  getCurrentStoryData: () => API_LeafEntry;\n  /**\n   * Returns the current story index.\n   *\n   * @returns {API_PreparedStoryIndex | undefined} The current story index, or undefined if not yet\n   *   loaded.\n   */\n  getIndex: () => API_PreparedStoryIndex | undefined;\n  /**\n   * Sets the prepared story index to the given value.\n   *\n   * @param {API_PreparedStoryIndex} index - The prepared story index to set.\n   * @returns {Promise<void>} A promise that resolves when the prepared story index has been set.\n   */\n  setIndex: (index: API_PreparedStoryIndex) => Promise<void>;\n\n  /**\n   * Jumps to the next or previous component in the index.\n   *\n   * @param {Direction} direction - The direction to jump. Use -1 to jump to the previous component,\n   *   and 1 to jump to the next component.\n   * @returns {void}\n   */\n  jumpToComponent: (direction: Direction) => void;\n  /**\n   * Jumps to the next or previous story in the story index.\n   *\n   * @param {Direction} direction - The direction to jump. Use -1 to jump to the previous story, and\n   *   1 to jump to the next story.\n   * @returns {void}\n   */\n  jumpToStory: (direction: Direction) => void;\n  /**\n   * Returns the data for the given story ID and optional ref ID.\n   *\n   * @param {StoryId} storyId - The ID of the story to retrieve data for.\n   * @param {string} [refId] - The ID of the ref to retrieve data for. If not provided, retrieves\n   *   data for the default ref.\n   * @returns {API_LeafEntry} The data for the given story ID and optional ref ID.\n   */\n  getData: (storyId: StoryId, refId?: string) => API_LeafEntry;\n  /**\n   * Returns a boolean indicating whether the given story ID and optional ref ID have been prepared.\n   *\n   * @param {StoryId} storyId - The ID of the story to check.\n   * @param {string} [refId] - The ID of the ref to check. If not provided, checks all refs for the\n   *   given story ID.\n   * @returns {boolean} A boolean indicating whether the given story ID and optional ref ID have\n   *   been prepared.\n   */\n  isPrepared: (storyId: StoryId, refId?: string) => boolean;\n  /**\n   * Returns the parameters for the given story ID and optional ref ID.\n   *\n   * @param {StoryId | { storyId: StoryId; refId: string }} storyId - The ID of the story to\n   *   retrieve parameters for, or an object containing the story ID and ref ID.\n   * @param {ParameterName} [parameterName] - The name of the parameter to retrieve. If not\n   *   provided, returns all parameters.\n   * @returns {API_StoryEntry['parameters'] | any} The parameters for the given story ID and\n   *   optional ref ID.\n   */\n  getParameters: (\n    storyId: StoryId | { storyId: StoryId; refId: string },\n    parameterName?: ParameterName\n  ) => API_StoryEntry['parameters'] | any;\n  /**\n   * Returns the current value of the specified parameter for the currently selected story.\n   *\n   * @template S - The type of the parameter value.\n   * @param {ParameterName} [parameterName] - The name of the parameter to retrieve. If not\n   *   provided, returns all parameters.\n   * @returns {S} The value of the specified parameter for the currently selected story.\n   */\n  getCurrentParameter<S>(parameterName?: ParameterName): S;\n  /**\n   * Updates the arguments for the given story with the provided new arguments.\n   *\n   * @param {API_StoryEntry | API_TestEntry} story - The story to update the arguments for.\n   * @param {Args} newArgs - The new arguments to set for the story.\n   * @returns {void}\n   */\n  updateStoryArgs(story: API_StoryEntry | API_TestEntry, newArgs: Args): void;\n  /**\n   * Resets the arguments for the given story to their initial values.\n   *\n   * @param {API_StoryEntry | API_TestEntry} story - The story to reset the arguments for.\n   * @param {string[]} [argNames] - An optional array of argument names to reset. If not provided,\n   *   all arguments will be reset.\n   * @returns {void}\n   */\n  resetStoryArgs: (story: API_StoryEntry | API_TestEntry, argNames?: string[]) => void;\n  /**\n   * Finds the leaf entry for the given story ID in the given story index.\n   *\n   * @param {API_IndexHash} index - The story index to search for the leaf entry in.\n   * @param {StoryId} storyId - The ID of the story to find the leaf entry for.\n   * @returns {API_LeafEntry} The leaf entry for the given story ID, or null if no leaf entry was\n   *   found.\n   */\n  findLeafEntry(index: API_IndexHash, storyId: StoryId): API_LeafEntry;\n  /**\n   * Finds the leaf story ID for the given component or group ID in the given index.\n   *\n   * @param {API_IndexHash} index - The story index to search for the leaf story ID in.\n   * @param {StoryId} storyId - The ID of the story to find the leaf story ID for.\n   * @returns {StoryId} The ID of the leaf story, or null if no leaf story was found.\n   */\n  findLeafStoryId(index: API_IndexHash, storyId: StoryId): StoryId;\n  /**\n   * Finds all the leaf story IDs for the given entry ID in the given index.\n   *\n   * @param {StoryId} entryId - The ID of the entry to find the leaf story IDs for.\n   * @returns {StoryId[]} The IDs of all the leaf stories, or an empty array if no leaf stories were\n   *   found.\n   */\n  findAllLeafStoryIds(entryId: string): StoryId[];\n  /**\n   * Finds the ID of the sibling story in the given direction for the given story ID in the given\n   * story index.\n   *\n   * @param {StoryId} storyId - The ID of the story to find the sibling of.\n   * @param {API_IndexHash} index - The story index to search for the sibling in.\n   * @param {Direction} direction - The direction to search for the sibling in.\n   * @param {boolean} toSiblingGroup - When true, skips over leafs within the same group.\n   * @returns {StoryId} The ID of the sibling story, or null if no sibling was found.\n   */\n  findSiblingStoryId(\n    storyId: StoryId,\n    index: API_IndexHash,\n    direction: Direction,\n    toSiblingGroup: boolean // when true, skip over leafs within the same group\n  ): StoryId;\n  /**\n   * Fetches the story index from the server.\n   *\n   * @returns {Promise<void>} A promise that resolves when the index has been fetched.\n   */\n  fetchIndex: () => Promise<void>;\n  /**\n   * Updates the story with the given ID with the provided update object.\n   *\n   * @param {StoryId} storyId - The ID of the story to update.\n   * @param {StoryUpdate} update - An object containing the updated story information.\n   * @param {API_ComposedRef} [ref] - The composed ref of the story to update.\n   * @returns {Promise<void>} A promise that resolves when the story has been updated.\n   */\n  updateStory: (storyId: StoryId, update: StoryUpdate, ref?: API_ComposedRef) => Promise<void>;\n  /**\n   * Updates the documentation for the given story ID with the given update object.\n   *\n   * @param {StoryId} storyId - The ID of the story to update.\n   * @param {DocsUpdate} update - An object containing the updated documentation information.\n   * @param {API_ComposedRef} [ref] - The composed ref of the story to update.\n   * @returns {Promise<void>} A promise that resolves when the documentation has been updated.\n   */\n  updateDocs: (storyId: StoryId, update: DocsUpdate, ref?: API_ComposedRef) => Promise<void>;\n  /**\n   * Sets the preview as initialized.\n   *\n   * @param {ComposedRef} [ref] - The composed ref of the story to set as initialized.\n   * @returns {Promise<void>} A promise that resolves when the preview has been set as initialized.\n   */\n  setPreviewInitialized: (ref?: ComposedRef) => Promise<void>;\n  /**\n   * Updates the filtering of the index.\n   *\n   * @param {string} addonId - The ID of the addon to update.\n   * @param {API_FilterFunction} filterFunction - A function that returns a boolean based on the\n   *   story, index and status.\n   * @returns {Promise<void>} A promise that resolves when the state has been updated.\n   */\n  experimental_setFilter: (addonId: string, filterFunction: API_FilterFunction) => Promise<void>;\n\n  /** Resets tag filters in the sidebar to the default filters. */\n  resetTagFilters(): void;\n  /**\n   * Replaces all tag filters in the sidebar with the provided included and excluded lists.\n   *\n   * @param included The tags to include in the filtered stories list\n   * @param excluded The tags to filter out (exclude) from the stories list\n   */\n  setAllTagFilters(included: Tag[], excluded: Tag[]): void;\n  /**\n   * Adds tag filters to the included or excluded filter lists. Included filters are included in the\n   * stories list, whereas excluded filters are filtered out.\n   *\n   * @param tags The tags to add as filters.\n   * @param excluded Whether to add the tags to the include or exclude filter list.\n   */\n  addTagFilters(tags: Tag[], excluded: boolean): void;\n  /**\n   * Removes tag filters from both the included and excluded filter lists.\n   *\n   * @param tags The tags to remove from filters.\n   */\n  removeTagFilters(tags: Tag[]): void;\n\n  /** Resets status filters in the sidebar (clears both included and excluded). */\n  resetStatusFilters(): void;\n  /**\n   * Replaces all status filters in the sidebar with the provided included and excluded lists.\n   *\n   * @param included The status values to include in the filtered stories list\n   * @param excluded The status values to filter out (exclude) from the stories list\n   */\n  setAllStatusFilters(included: StatusValue[], excluded: StatusValue[]): void;\n  /**\n   * Adds status filters to the included or excluded filter lists.\n   *\n   * @param statuses The status values to add as filters.\n   * @param excluded Whether to add to the include or exclude filter list.\n   */\n  addStatusFilters(statuses: StatusValue[], excluded: boolean): void;\n  /**\n   * Removes status filters from both the included and excluded filter lists.\n   *\n   * @param statuses The status values to remove from filters.\n   */\n  removeStatusFilters(statuses: StatusValue[]): void;\n}\n\nconst removedOptions = ['enableShortcuts', 'theme', 'showRoots'];\n\nfunction removeRemovedOptions<T extends Record<string, any> = Record<string, any>>(options?: T): T {\n  if (!options || typeof options === 'string') {\n    return options!;\n  }\n  const result: T = { ...options } as T;\n\n  removedOptions.forEach((option) => {\n    if (option in result) {\n      delete result[option];\n    }\n  });\n\n  return result;\n}\n\nexport const init: ModuleFn<SubAPI, SubState> = ({\n  fullAPI,\n  store,\n  navigate,\n  provider,\n  state: { location } = {} as any,\n  storyId: initialStoryId,\n  viewMode: initialViewMode,\n  docsOptions = {},\n}) => {\n  const navigateWithQueryParams = (path: string, options?: NavigateOptions) => {\n    const { customQueryParams } = store.getState();\n    navigate(buildNavigationUrl(path, customQueryParams ?? {}), options);\n  };\n\n  const persistFilters = (inputPatch: Parameters<typeof store.setState>[0]) => {\n    return store.setState(inputPatch, {\n      persistence: 'url' as const,\n      serialize: (s: ReturnType<typeof store.getState>) => {\n        const tagsValue = serializeTagsParam(s.includedTagFilters, s.excludedTagFilters);\n        const statusesValue = serializeStatusesParam(\n          s.includedStatusFilters,\n          s.excludedStatusFilters\n        );\n        return { tags: tagsValue ?? null, statuses: statusesValue ?? null };\n      },\n    });\n  };\n\n  const api: SubAPI = {\n    storyId: toId,\n    getData: (storyId, refId): any => {\n      const result = api.resolveStory(storyId, refId);\n      if (result?.type === 'story' || result?.type === 'docs') {\n        return result;\n      }\n      return undefined;\n    },\n    isPrepared: (storyId, refId) => {\n      const data = api.getData(storyId, refId);\n      if (!data) {\n        return false;\n      }\n      return data.type === 'story' ? data.prepared : true;\n    },\n    resolveStory: (storyId, refId) => {\n      const { refs, index } = store.getState();\n      if (refId && !refs[refId]) {\n        return undefined;\n      }\n      if (refId) {\n        return refs?.[refId]?.index?.[storyId] ?? undefined;\n      }\n      return index ? index[storyId] : undefined;\n    },\n    getCurrentStoryData: () => {\n      const { storyId, refId } = store.getState();\n\n      return api.getData(storyId, refId);\n    },\n    getIndex: () => {\n      const { internal_index } = store.getState();\n      return internal_index;\n    },\n    getParameters: (storyIdOrCombo, parameterName) => {\n      const { storyId, refId } =\n        typeof storyIdOrCombo === 'string'\n          ? { storyId: storyIdOrCombo, refId: undefined }\n          : storyIdOrCombo;\n      const data = api.getData(storyId, refId);\n\n      if (['story', 'docs'].includes(data?.type)) {\n        const { parameters } = data;\n\n        if (parameters) {\n          return parameterName ? parameters[parameterName] : parameters;\n        }\n      }\n\n      return null;\n    },\n    getCurrentParameter: (parameterName) => {\n      const { storyId, refId } = store.getState();\n      const parameters = api.getParameters({ storyId, refId: refId as string }, parameterName);\n      // FIXME Returning falsey parameters breaks a bunch of toolbars code,\n      // so this strange logic needs to be here until various client code is updated.\n      return parameters || undefined;\n    },\n    jumpToComponent: (direction) => {\n      const { filteredIndex, storyId, refs, refId } = store.getState();\n      const story = api.getData(storyId, refId);\n\n      // cannot navigate when there's no current selection\n      if (!story) {\n        return;\n      }\n\n      const hash = refId ? refs[refId].filteredIndex || {} : filteredIndex;\n\n      if (!hash) {\n        return;\n      }\n\n      const result = api.findSiblingStoryId(storyId, hash, direction, true);\n\n      if (result) {\n        api.selectStory(result, undefined, { ref: refId });\n      }\n    },\n    jumpToStory: (direction) => {\n      const { filteredIndex, storyId, refs, refId } = store.getState();\n      const story = api.getData(storyId, refId);\n\n      // cannot navigate when there's no current selection\n      if (!story) {\n        return;\n      }\n\n      const hash = story.refId ? refs[story.refId].filteredIndex : filteredIndex;\n\n      if (!hash) {\n        return;\n      }\n\n      const result = api.findSiblingStoryId(storyId, hash, direction, false);\n\n      if (result) {\n        api.selectStory(result, undefined, { ref: refId });\n      }\n    },\n    selectFirstStory: () => {\n      const {\n        index,\n        filteredIndex,\n        includedTagFilters,\n        excludedTagFilters,\n        includedStatusFilters,\n        excludedStatusFilters,\n      } = store.getState();\n      const hasActiveFilters =\n        includedTagFilters.length > 0 ||\n        excludedTagFilters.length > 0 ||\n        (includedStatusFilters?.length ?? 0) > 0 ||\n        (excludedStatusFilters?.length ?? 0) > 0;\n\n      if (hasActiveFilters) {\n        if (!filteredIndex) {\n          return;\n        }\n\n        const firstStory = Object.keys(filteredIndex).find(\n          (id) => filteredIndex[id].type === 'story'\n        );\n        if (firstStory) {\n          api.selectStory(firstStory);\n        }\n        return;\n      }\n\n      if (!index) {\n        return;\n      }\n\n      const firstStory = Object.keys(index).find((id) => index[id].type === 'story');\n\n      if (firstStory) {\n        api.selectStory(firstStory);\n        return;\n      }\n\n      navigateWithQueryParams('/');\n    },\n    selectStory: (titleOrId = undefined, name = undefined, options = {}) => {\n      const { ref } = options;\n      const { storyId, index, filteredIndex, refs, settings } = store.getState();\n\n      const gotoStory = (entry?: API_HashEntry) => {\n        if (entry?.type === 'docs' || entry?.type === 'story') {\n          store.setState({ settings: { ...settings, lastTrackedStoryId: entry.id } });\n          navigateWithQueryParams(\n            `/${entry.type}/${entry.refId ? `${entry.refId}_${entry.id}` : entry.id}`\n          );\n          return true;\n        }\n        return false;\n      };\n\n      const kindSlug = storyId?.split('--', 2)[0];\n      const hash = ref ? refs[ref].index : index;\n      const filteredHash = ref ? refs[ref].filteredIndex : filteredIndex;\n      if (!hash || !filteredHash) {\n        return;\n      }\n\n      if (!name) {\n        // Find the entry (group, component, story or docs) that is referred to\n        const entry = titleOrId ? hash[titleOrId] || hash[sanitize(titleOrId)] : hash[kindSlug];\n\n        if (!entry) {\n          throw new Error(`Unknown id or title: '${titleOrId}'`);\n        }\n\n        if (!gotoStory(entry)) {\n          // If the entry is not a story or docs, find the first descendant entry that is\n          gotoStory(api.findLeafEntry(filteredHash, entry.id));\n        }\n      } else if (!titleOrId) {\n        // Navigate to a named story/docs within the current component (i.e. \"kind\")\n        // This is a slugified version of the kind, but that's OK, our toId function is idempotent\n        gotoStory(hash[toId(kindSlug, name)]);\n      } else {\n        const id = ref ? `${ref}_${toId(titleOrId, name)}` : toId(titleOrId, name);\n        if (hash[id]) {\n          gotoStory(hash[id]);\n        } else {\n          // Support legacy API with component permalinks, where kind is `x/y` but permalink is 'z'\n          const entry = hash[sanitize(titleOrId)];\n          if (entry?.type === 'component') {\n            const foundId = entry.children.find((childId) => hash[childId].name === name);\n            gotoStory(foundId ? hash[foundId] : undefined);\n          }\n        }\n      }\n    },\n    findLeafEntry(index, storyId) {\n      const entry = index[storyId];\n      if (entry.type === 'docs' || entry.type === 'story') {\n        return entry;\n      }\n\n      const childStoryId = entry.children.find((childId) => index[childId]) || entry.children[0];\n      return api.findLeafEntry(index, childStoryId);\n    },\n    findLeafStoryId(index, storyId) {\n      return api.findLeafEntry(index, storyId)?.id;\n    },\n    findAllLeafStoryIds(entryId) {\n      const { index } = store.getState();\n      if (!index) {\n        return [];\n      }\n      const findChildEntriesRecursively = (currentEntryId: StoryId, results: StoryId[] = []) => {\n        const node = index[currentEntryId];\n        if (!node) {\n          return results;\n        }\n        if (node.type === 'story') {\n          results.push(node.id);\n        }\n        if ('children' in node) {\n          node.children?.forEach((childId) => findChildEntriesRecursively(childId, results));\n        }\n        return results;\n      };\n      return findChildEntriesRecursively(entryId, []);\n    },\n    findSiblingStoryId(storyId, index, direction, toSiblingGroup): any {\n      if (toSiblingGroup) {\n        const lookupList = getComponentLookupList(index);\n        const position = lookupList.findIndex((i) => i.includes(storyId));\n\n        // cannot navigate beyond fist or last\n        if (position === lookupList.length - 1 && direction > 0) {\n          return;\n        }\n        if (position === 0 && direction < 0) {\n          return;\n        }\n\n        if (lookupList[position + direction]) {\n          return lookupList[position + direction][0];\n        }\n        return;\n      }\n      const lookupList = getStoriesLookupList(index);\n      const position = lookupList.indexOf(storyId);\n\n      // cannot navigate beyond fist or last\n      if (position === lookupList.length - 1 && direction > 0) {\n        return;\n      }\n      if (position === 0 && direction < 0) {\n        return;\n      }\n\n      return lookupList[position + direction];\n    },\n    updateStoryArgs: (story, updatedArgs) => {\n      const { id: storyId, refId } = story;\n      provider.channel?.emit(UPDATE_STORY_ARGS, {\n        storyId,\n        updatedArgs,\n        options: { target: refId },\n      });\n    },\n    resetStoryArgs: (story, argNames) => {\n      const { id: storyId, refId } = story;\n      provider.channel?.emit(RESET_STORY_ARGS, {\n        storyId,\n        argNames,\n        options: { target: refId },\n      });\n    },\n    fetchIndex: async () => {\n      try {\n        const result = await fetch(STORY_INDEX_PATH);\n\n        if (result.status !== 200) {\n          throw new Error(await result.text());\n        }\n\n        const storyIndex = (await result.json()) as StoryIndex;\n\n        // We can only do this if the stories.json is a proper storyIndex\n        if (storyIndex.v < 3) {\n          logger.warn(`Skipping story index with version v${storyIndex.v}, awaiting SET_STORIES.`);\n          return;\n        }\n\n        await api.setIndex(storyIndex);\n      } catch (err: any) {\n        await store.setState({ indexError: err });\n      }\n    },\n    // The story index we receive on SET_INDEX is \"prepared\" in that it has parameters\n    // The story index we receive on fetchStoryIndex is not, but all the prepared fields are optional\n    // so we can cast one to the other easily enough\n    setIndex: async (input) => {\n      const { filteredIndex: oldFilteredHash, index: oldHash, filters } = store.getState();\n      const allStatuses = fullStatusStore.getAll();\n      const newFilteredHash = transformStoryIndexToStoriesHash(input, {\n        provider,\n        docsOptions,\n        filters,\n        allStatuses,\n        statusFilterKey: STATUS_FILTER,\n      });\n      const newHash = transformStoryIndexToStoriesHash(input, {\n        provider,\n        docsOptions,\n        filters: {},\n        allStatuses,\n      });\n\n      await store.setState({\n        internal_index: input,\n        filteredIndex: addPreparedStories(newFilteredHash, oldFilteredHash),\n        index: addPreparedStories(newHash, oldHash),\n        indexError: undefined,\n      });\n    },\n    // FIXME: is there a bug where filtered stories get added back in on updateStory???\n    updateStory: async (\n      storyId: StoryId,\n      update: StoryUpdate,\n      ref?: API_ComposedRef\n    ): Promise<void> => {\n      if (!ref) {\n        const { index, filteredIndex } = store.getState();\n        if (index && index[storyId]) {\n          index[storyId] = {\n            ...index[storyId],\n            ...update,\n          } as API_StoryEntry;\n        }\n        if (filteredIndex && filteredIndex[storyId]) {\n          filteredIndex[storyId] = {\n            ...filteredIndex[storyId],\n            ...update,\n          } as API_StoryEntry;\n        }\n        if (index || filteredIndex) {\n          await store.setState({ index, filteredIndex });\n        }\n      } else {\n        const { id: refId, index, filteredIndex }: any = ref;\n        if (index && index[storyId]) {\n          index[storyId] = {\n            ...index[storyId],\n            ...update,\n          } as API_StoryEntry;\n        }\n        if (filteredIndex && filteredIndex[storyId]) {\n          filteredIndex[storyId] = {\n            ...filteredIndex[storyId],\n            ...update,\n          } as API_StoryEntry;\n        }\n        await fullAPI.updateRef(refId, { index, filteredIndex });\n      }\n    },\n    updateDocs: async (\n      docsId: StoryId,\n      update: DocsUpdate,\n      ref?: API_ComposedRef\n    ): Promise<void> => {\n      if (!ref) {\n        const { index, filteredIndex } = store.getState();\n        if (index) {\n          index[docsId] = {\n            ...index[docsId],\n            ...update,\n          } as API_DocsEntry;\n        }\n        if (filteredIndex) {\n          filteredIndex[docsId] = {\n            ...filteredIndex[docsId],\n            ...update,\n          } as API_DocsEntry;\n        }\n        if (index || filteredIndex) {\n          await store.setState({ index, filteredIndex });\n        }\n      } else {\n        const { id: refId, index, filteredIndex }: any = ref;\n        index[docsId] = {\n          ...index[docsId],\n          ...update,\n        } as API_DocsEntry;\n        filteredIndex[docsId] = {\n          ...filteredIndex[docsId],\n          ...update,\n        } as API_DocsEntry;\n        await fullAPI.updateRef(refId, { index, filteredIndex });\n      }\n    },\n    setPreviewInitialized: async (ref) => {\n      if (!ref) {\n        store.setState({ previewInitialized: true });\n      } else {\n        fullAPI.updateRef(ref.id, { previewInitialized: true });\n      }\n    },\n\n    experimental_setFilter: async (id, filterFunction) => {\n      await store.setState({ filters: { ...store.getState().filters, [id]: filterFunction } });\n\n      const { internal_index: index } = store.getState();\n\n      if (!index) {\n        return;\n      }\n      // apply new filters by setting the index again\n      await api.setIndex(index);\n\n      const refs = await fullAPI.getRefs();\n      for (const [refId, { internal_index, ...ref }] of Object.entries(refs)) {\n        await fullAPI.setRef(refId, { ...ref, storyIndex: internal_index }, true);\n      }\n\n      provider.channel?.emit(SET_FILTER, { id });\n    },\n\n    resetTagFilters: async () => {\n      await persistFilters((s) => ({\n        includedTagFilters: s.defaultIncludedTagFilters,\n        excludedTagFilters: s.defaultExcludedTagFilters,\n      }));\n\n      recomputeTagsFilter();\n    },\n\n    setAllTagFilters: async (included: Tag[], excluded: Tag[]) => {\n      await persistFilters({ includedTagFilters: included, excludedTagFilters: excluded });\n\n      recomputeTagsFilter();\n    },\n\n    addTagFilters: async (tags: Tag[], excluded: boolean) => {\n      const state = store.getState();\n      const newIncluded = new Set(state.includedTagFilters);\n      const newExcluded = new Set(state.excludedTagFilters);\n      for (const tag of tags) {\n        if (excluded) {\n          newIncluded.delete(tag);\n          newExcluded.add(tag);\n        } else {\n          newIncluded.add(tag);\n          newExcluded.delete(tag);\n        }\n      }\n      await persistFilters({\n        includedTagFilters: Array.from(newIncluded),\n        excludedTagFilters: Array.from(newExcluded),\n      });\n\n      recomputeTagsFilter();\n    },\n\n    removeTagFilters: async (tags: Tag[]) => {\n      const state = store.getState();\n      await persistFilters({\n        includedTagFilters: state.includedTagFilters.filter((tag) => !tags.includes(tag)),\n        excludedTagFilters: state.excludedTagFilters.filter((tag) => !tags.includes(tag)),\n      });\n\n      recomputeTagsFilter();\n    },\n\n    resetStatusFilters: async () => {\n      await persistFilters({ includedStatusFilters: [], excludedStatusFilters: [] });\n      recomputeStatusFilter();\n    },\n\n    setAllStatusFilters: async (included: StatusValue[], excluded: StatusValue[]) => {\n      await persistFilters({ includedStatusFilters: included, excludedStatusFilters: excluded });\n      recomputeStatusFilter();\n    },\n\n    addStatusFilters: async (statuses: StatusValue[], excluded: boolean) => {\n      const state = store.getState();\n      const newIncluded = new Set(state.includedStatusFilters);\n      const newExcluded = new Set(state.excludedStatusFilters);\n      for (const status of statuses) {\n        if (excluded) {\n          newIncluded.delete(status);\n          newExcluded.add(status);\n        } else {\n          newIncluded.add(status);\n          newExcluded.delete(status);\n        }\n      }\n      await persistFilters({\n        includedStatusFilters: Array.from(newIncluded),\n        excludedStatusFilters: Array.from(newExcluded),\n      });\n      recomputeStatusFilter();\n    },\n\n    removeStatusFilters: async (statuses: StatusValue[]) => {\n      const state = store.getState();\n      await persistFilters({\n        includedStatusFilters: state.includedStatusFilters.filter((s) => !statuses.includes(s)),\n        excludedStatusFilters: state.excludedStatusFilters.filter((s) => !statuses.includes(s)),\n      });\n      recomputeStatusFilter();\n    },\n  };\n\n  const recomputeTagsFilter = () => {\n    const { includedTagFilters, excludedTagFilters } = store.getState();\n    api.experimental_setFilter(\n      TAGS_FILTER,\n      computeTagsFilterFn(includedTagFilters, excludedTagFilters)\n    );\n  };\n\n  const recomputeStatusFilter = () => {\n    const { includedStatusFilters, excludedStatusFilters } = store.getState();\n    api.experimental_setFilter(\n      STATUS_FILTER,\n      computeStatusFilterFn(includedStatusFilters ?? [], excludedStatusFilters ?? [])\n    );\n  };\n\n  // On initial load, the local iframe will select the first story (or other \"selection specifier\")\n  // and emit STORY_SPECIFIED with the id. We need to ensure we respond to this change.\n  provider.channel?.on(\n    STORY_SPECIFIED,\n    function handler(\n      this: any,\n      {\n        storyId,\n        viewMode,\n      }: {\n        storyId: string;\n        viewMode: API_ViewMode;\n        [k: string]: any;\n      }\n    ) {\n      const { sourceType } = getEventMetadata(this, fullAPI)!;\n\n      if (sourceType === 'local') {\n        const state = store.getState();\n        const isCanvasRoute =\n          state.path === '/' || state.viewMode === 'story' || state.viewMode === 'docs';\n        const stateHasSelection = state.viewMode && state.storyId;\n        const stateSelectionDifferent = state.viewMode !== viewMode || state.storyId !== storyId;\n        const { type } = state.index?.[state.storyId] || {};\n        const isStory = !(type === 'root' || type === 'component' || type === 'group');\n\n        /**\n         * When storybook starts, we want to navigate to the first story. But there are a few\n         * exceptions:\n         *\n         * - If the current storyId and viewMode are already set/correct AND the url section is a\n         *   leaf-type.\n         * - If the user has navigated away already.\n         * - If the user started storybook with a specific page-URL like \"/settings/about\"\n         */\n        if (isCanvasRoute) {\n          const {\n            includedTagFilters,\n            excludedTagFilters,\n            includedStatusFilters,\n            excludedStatusFilters,\n            filteredIndex,\n          } = state;\n          const hasActiveFilters =\n            (includedTagFilters?.length ?? 0) > 0 ||\n            (excludedTagFilters?.length ?? 0) > 0 ||\n            (includedStatusFilters?.length ?? 0) > 0 ||\n            (excludedStatusFilters?.length ?? 0) > 0;\n\n          if (hasActiveFilters && !stateHasSelection) {\n            const storyPassesFilter = filteredIndex && filteredIndex[storyId]?.type === 'story';\n\n            if (!storyPassesFilter) {\n              const firstFiltered = filteredIndex\n                ? Object.keys(filteredIndex).find((id) => {\n                    const entry = filteredIndex[id];\n                    return entry.type === 'story' || entry.type === 'docs';\n                  })\n                : undefined;\n\n              if (firstFiltered) {\n                navigateWithQueryParams(`/${viewMode}/${firstFiltered}`);\n              }\n\n              return;\n            }\n          }\n\n          if (stateHasSelection && stateSelectionDifferent && isStory) {\n            // The manager state is correct, the preview state is lagging behind\n            provider.channel?.emit(SET_CURRENT_STORY, {\n              storyId: state.storyId,\n              viewMode: state.viewMode,\n            });\n          } else if (stateSelectionDifferent) {\n            // The preview state is correct, the manager state is lagging behind\n            navigateWithQueryParams(`/${viewMode}/${storyId}`);\n          }\n        }\n      }\n    }\n  );\n\n  // The CURRENT_STORY_WAS_SET event is the best event to use to tell if a ref is ready.\n  // Until the ref has a selection, it will not render anything (e.g. while waiting for\n  // the preview.js file or the index to load). Once it has a selection, it will render its own\n  // preparing spinner.\n  provider.channel?.on(CURRENT_STORY_WAS_SET, function handler(this: any) {\n    const { ref } = getEventMetadata(this, fullAPI)!;\n    api.setPreviewInitialized(ref);\n  });\n\n  provider.channel?.on(STORY_CHANGED, function handler(this: any) {\n    const { sourceType } = getEventMetadata(this, fullAPI)!;\n\n    if (sourceType === 'local') {\n      const options = api.getCurrentParameter('options');\n\n      if (options) {\n        fullAPI.setOptions(removeRemovedOptions(options));\n      }\n    }\n  });\n\n  provider.channel?.on(\n    STORY_PREPARED,\n    function handler(this: any, { id, ...update }: StoryPreparedPayload) {\n      const { ref, sourceType } = getEventMetadata(this, fullAPI)!;\n      api.updateStory(id, { ...update, prepared: true }, ref);\n\n      if (!ref) {\n        if (!store.getState().hasCalledSetOptions) {\n          const { options } = update.parameters;\n          fullAPI.setOptions(removeRemovedOptions(options));\n          store.setState({ hasCalledSetOptions: true });\n        }\n      }\n\n      if (sourceType === 'local') {\n        const { storyId, index, refId } = store.getState();\n\n        if (!index) {\n          return;\n        }\n\n        // create a list of related stories to be preloaded\n        const toBePreloaded = Array.from(\n          new Set([\n            api.findSiblingStoryId(storyId, index, 1, true),\n            api.findSiblingStoryId(storyId, index, -1, true),\n          ])\n        ).filter(Boolean);\n\n        provider.channel?.emit(PRELOAD_ENTRIES, {\n          ids: toBePreloaded,\n          options: { target: refId },\n        });\n      }\n    }\n  );\n\n  provider.channel?.on(\n    DOCS_PREPARED,\n    function handler(this: any, { id, ...update }: DocsPreparedPayload) {\n      const { ref } = getEventMetadata(this, fullAPI)!;\n      api.updateStory(id, { ...update, prepared: true }, ref);\n    }\n  );\n\n  provider.channel?.on(SET_INDEX, function handler(this: any, index: API_PreparedStoryIndex) {\n    const { ref } = getEventMetadata(this, fullAPI)!;\n\n    if (!ref) {\n      api.setIndex(index);\n      const options = api.getCurrentParameter('options');\n      fullAPI.setOptions(removeRemovedOptions(options!));\n    } else {\n      fullAPI.setRef(ref.id, { ...ref, storyIndex: index }, true);\n    }\n  });\n\n  // For composition back-compatibilty\n  provider.channel?.on(SET_STORIES, function handler(this: any, data: SetStoriesPayload) {\n    const { ref } = getEventMetadata(this, fullAPI)!;\n    const setStoriesData = data.v ? denormalizeStoryParameters(data) : data.stories;\n\n    if (!ref) {\n      throw new Error('Cannot call SET_STORIES for local frame');\n    } else {\n      fullAPI.setRef(ref.id, { ...ref, setStoriesData }, true);\n    }\n  });\n\n  provider.channel?.on(\n    SELECT_STORY,\n    function handler(\n      this: any,\n      {\n        kind,\n        title = kind,\n        story,\n        name = story,\n        storyId,\n        ...rest\n      }: {\n        kind?: StoryKind;\n        title?: ComponentTitle;\n        story?: StoryName;\n        name?: StoryName;\n        storyId: string;\n        viewMode: API_ViewMode;\n      }\n    ) {\n      const { ref } = getEventMetadata(this, fullAPI)!;\n\n      if (!ref) {\n        fullAPI.selectStory(storyId || title, name, rest);\n      } else {\n        fullAPI.selectStory(storyId || title, name, { ...rest, ref: ref.id });\n      }\n    }\n  );\n\n  provider.channel?.on(\n    STORY_ARGS_UPDATED,\n    function handleStoryArgsUpdated(\n      this: any,\n      { storyId, args }: { storyId: StoryId; args: Args }\n    ) {\n      const { ref } = getEventMetadata(this, fullAPI)!;\n      api.updateStory(storyId, { args }, ref);\n    }\n  );\n\n  // When there's a preview error, we don't show it in the manager, but simply\n  provider.channel?.on(CONFIG_ERROR, function handleConfigError(this: any, err: any) {\n    const { ref } = getEventMetadata(this, fullAPI)!;\n    api.setPreviewInitialized(ref);\n  });\n\n  provider.channel?.on(STORY_MISSING, function handleConfigError(this: any, err: any) {\n    const { ref } = getEventMetadata(this, fullAPI)!;\n    api.setPreviewInitialized(ref);\n  });\n\n  provider.channel?.on(SET_CONFIG, () => {\n    const config = provider.getConfig();\n    const configFilters = config?.sidebar?.filters || {};\n    const {\n      includedTagFilters,\n      excludedTagFilters,\n      includedStatusFilters,\n      excludedStatusFilters,\n      tagPresets,\n    } = store.getState();\n\n    // Config sidebar filters first, then our managed filters override any conflicts\n    store.setState({\n      filters: {\n        ...store.getState().filters,\n        ...configFilters,\n        [STATIC_FILTER]: computeStaticFilterFn(tagPresets),\n        [TAGS_FILTER]: computeTagsFilterFn(includedTagFilters, excludedTagFilters),\n        [STATUS_FILTER]: computeStatusFilterFn(includedStatusFilters, excludedStatusFilters),\n      },\n    });\n  });\n\n  fullStatusStore.onAllStatusChange(async () => {\n    // re-apply the filters when the statuses change\n    recomputeStatusFilter();\n\n    const { internal_index: index } = store.getState();\n\n    if (!index) {\n      return;\n    }\n    // apply new filters by setting the index again\n    await api.setIndex(index);\n\n    const refs = await fullAPI.getRefs();\n    Object.entries(refs).forEach(([refId, { internal_index, ...ref }]) => {\n      fullAPI.setRef(refId, { ...ref, storyIndex: internal_index }, true);\n    });\n  });\n\n  const config = provider.getConfig();\n  const configFilters = config?.sidebar?.filters || {};\n\n  // Compute default tag filter values from presets\n  const tagPresets: TagsOptions = global.TAGS_OPTIONS || {};\n  const defaultTags = getDefaultTagsFromPreset(tagPresets);\n\n  const { tags, statuses } = queryFromLocation(location ?? ({ search: '' } as any));\n  const parsedTags = parseTagsParam(tags);\n  const hasTagsParam = tags !== undefined;\n  const initialIncluded: Tag[] = hasTagsParam ? parsedTags.included : defaultTags.included;\n  const initialExcluded: Tag[] = hasTagsParam ? parsedTags.excluded : defaultTags.excluded;\n\n  const parsedStatuses = parseStatusesParam(statuses);\n  const initialIncludedStatuses: StatusValue[] = parsedStatuses.included;\n  const initialExcludedStatuses: StatusValue[] = parsedStatuses.excluded;\n\n  // Build initial filters: config sidebar filters first, then our managed filters take priority\n  const initialFilters: Record<string, API_FilterFunction> = {\n    ...configFilters,\n    [STATIC_FILTER]: computeStaticFilterFn(tagPresets),\n    [TAGS_FILTER]: computeTagsFilterFn(initialIncluded, initialExcluded),\n    [STATUS_FILTER]: computeStatusFilterFn(initialIncludedStatuses, initialExcludedStatuses),\n  };\n\n  return {\n    api,\n    state: {\n      storyId: initialStoryId as string,\n      viewMode: initialViewMode,\n      hasCalledSetOptions: false,\n      previewInitialized: false,\n      filters: initialFilters,\n      tagPresets,\n      defaultIncludedTagFilters: defaultTags.included,\n      defaultExcludedTagFilters: defaultTags.excluded,\n      includedTagFilters: initialIncluded,\n      excludedTagFilters: initialExcluded,\n      includedStatusFilters: initialIncludedStatuses,\n      excludedStatusFilters: initialExcludedStatuses,\n    },\n    init: async () => {\n      provider.channel?.on(STORY_INDEX_INVALIDATED, () => api.fetchIndex());\n\n      await api.fetchIndex();\n    },\n  };\n};\n"
  },
  {
    "path": "code/core/src/manager-api/modules/tags.ts",
    "content": "import type {\n  API_PreparedIndexEntry,\n  FilterFunction,\n  Tag,\n  TagsOptions,\n} from 'storybook/internal/types';\n\nimport memoize from 'memoizerific';\n\nimport { BUILT_IN_FILTERS, Tag as TagEnum, USER_TAG_FILTER } from '../../shared/constants/tags.ts';\n\nexport const BUILT_IN_URL_TAG_MAP: Record<string, Tag> = {\n  $docs: '_docs',\n  $play: '_play',\n  $test: '_test',\n};\n\nexport const parseTagsParam = (\n  tagsParam: string | undefined\n): { included: Tag[]; excluded: Tag[] } => {\n  if (!tagsParam) {\n    return { included: [], excluded: [] };\n  }\n\n  const included: Tag[] = [];\n  const excluded: Tag[] = [];\n\n  tagsParam.split(';').forEach((rawTag) => {\n    if (!rawTag) {\n      return;\n    }\n\n    const isExcluded = rawTag.startsWith('!');\n    const normalizedTag = isExcluded ? rawTag.slice(1) : rawTag;\n    const mappedTag = (BUILT_IN_URL_TAG_MAP[normalizedTag] ?? normalizedTag) as Tag;\n\n    if (isExcluded) {\n      excluded.push(mappedTag);\n    } else {\n      included.push(mappedTag);\n    }\n  });\n\n  return { included, excluded };\n};\n\nexport const serializeTagsParam = (included: Tag[], excluded: Tag[]): string => {\n  if (!included.length && !excluded.length) {\n    return '';\n  }\n\n  const reverseBuiltInUrlTagMap = Object.fromEntries(\n    Object.entries(BUILT_IN_URL_TAG_MAP).map(([urlTag, internalTag]) => [internalTag, urlTag])\n  ) as Record<string, string>;\n\n  const serializedIncluded = included.map((tag) => reverseBuiltInUrlTagMap[tag] ?? tag).sort();\n  const serializedExcluded = excluded\n    .map((tag) => `!${reverseBuiltInUrlTagMap[tag] ?? tag}`)\n    .sort();\n\n  return [...serializedIncluded, ...serializedExcluded].join(';');\n};\n\nexport const getDefaultTagsFromPreset = memoize(1)((\n  presets: TagsOptions\n): {\n  included: Tag[];\n  excluded: Tag[];\n} => {\n  const presetEntries = Object.entries(presets);\n  return {\n    included: presetEntries\n      .filter(([, option]) => option.defaultFilterSelection === 'include')\n      .map(([tag]) => tag),\n    excluded: presetEntries\n      .filter(([, option]) => option.defaultFilterSelection === 'exclude')\n      .map(([tag]) => tag),\n  };\n});\n\nexport const computeStaticFilterFn = (tagPresets: TagsOptions) => {\n  const staticExcludeTags = Object.entries(tagPresets).reduce(\n    (acc, entry) => {\n      const [tag, option] = entry;\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      if ((option as any).excludeFromSidebar) {\n        acc[tag] = true;\n      }\n      return acc;\n    },\n    {} as Record<string, boolean>\n  );\n\n  return (item: API_PreparedIndexEntry) => {\n    const tags = item.tags ?? [];\n    return (\n      (tags.includes(TagEnum.DEV) || item.type === 'docs') &&\n      tags.filter((tag) => staticExcludeTags[tag]).length === 0\n    );\n  };\n};\n\nexport const computeTagsFilterFn = (\n  includedTagFilters: Tag[],\n  excludedTagFilters: Tag[]\n): ((item: API_PreparedIndexEntry) => boolean) => {\n  const computeFilterFunctions = (set: Tag[]): FilterFunction[][] => {\n    return Object.values(\n      set.reduce(\n        (acc, tag) => {\n          if (Object.hasOwn(BUILT_IN_FILTERS, tag)) {\n            acc['built-in'].push(BUILT_IN_FILTERS[tag as keyof typeof BUILT_IN_FILTERS]);\n          } else {\n            acc.user.push(USER_TAG_FILTER(tag));\n          }\n          return acc;\n        },\n        { 'built-in': [], user: [] } as { 'built-in': FilterFunction[]; user: FilterFunction[] }\n      )\n    ).filter((group) => group.length > 0);\n  };\n\n  return (item: API_PreparedIndexEntry) => {\n    const included = computeFilterFunctions(includedTagFilters);\n    const excluded = computeFilterFunctions(excludedTagFilters);\n\n    return (\n      (!included.length ||\n        included.every((group) => group.some((filterFn) => filterFn(item, false)))) &&\n      (!excluded.length ||\n        excluded.every((group) => group.every((filterFn) => filterFn(item, true))))\n    );\n  };\n};\n"
  },
  {
    "path": "code/core/src/manager-api/modules/url.ts",
    "content": "import {\n  GLOBALS_UPDATED,\n  NAVIGATE_URL,\n  SET_CURRENT_STORY,\n  STORY_ARGS_UPDATED,\n  UPDATE_QUERY_PARAMS,\n} from 'storybook/internal/core-events';\nimport { buildArgsParam, queryFromLocation } from 'storybook/internal/router';\nimport type { NavigateOptions } from 'storybook/internal/router';\nimport type { API_Layout, API_UI, API_ViewMode, Args } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { dequal as deepEqual } from 'dequal';\nimport { omit } from 'es-toolkit/object';\nimport { stringify } from 'picoquery';\n\nimport merge from '../lib/merge.ts';\nimport type { ModuleArgs, ModuleFn } from '../lib/types.tsx';\nimport { buildNavigationUrl } from '../lib/url.ts';\nimport {\n  DEFAULT_BOTTOM_PANEL_HEIGHT,\n  DEFAULT_NAV_SIZE,\n  DEFAULT_RIGHT_PANEL_WIDTH,\n} from './layout.ts';\n\nexport interface SubState {\n  customQueryParams: QueryParams;\n}\n\nconst parseBoolean = (value: string) => {\n  if (value === 'true' || value === '1') {\n    return true;\n  }\n\n  if (value === 'false' || value === '0') {\n    return false;\n  }\n  return undefined;\n};\n\nconst parseSerializedParam = (param: string) =>\n  Object.fromEntries(\n    param\n      .split(';')\n      .map((pair) => pair.split(':'))\n      // Encoding values ensures we don't break already encoded args/globals but also don't encode our own special characters like ; and :.\n      .map(([key, value]) => [key, encodeURIComponent(value)])\n      .filter(([key, value]) => key && value)\n  );\n\nconst mergeSerializedParams = (params: string, extraParams: string) => {\n  const pairs = parseSerializedParam(params);\n  const extra = parseSerializedParam(extraParams);\n  return Object.entries({ ...pairs, ...extra })\n    .map(([key, value]) => `${key}:${value}`)\n    .join(';');\n};\n\n// Initialize the state based on the URL.\n// NOTE:\n//   Although we don't change the URL when you change the state, we do support setting initial state\n//   via the following URL parameters:\n//     - full: 0/1 -- show fullscreen\n//     - panel: bottom/right/0 -- set addons panel position (or hide)\n//     - nav: 0/1 -- show or hide the story list\n//\n//   We also support legacy URLs from storybook <5\nlet prevParams: ReturnType<typeof queryFromLocation>;\nconst initialUrlSupport = ({\n  state: { location, path, viewMode, storyId: storyIdFromUrl },\n  singleStory,\n}: ModuleArgs) => {\n  const {\n    full,\n    panel,\n    nav,\n    shortcuts,\n    addonPanel,\n    tabs,\n    path: queryPath,\n    ...otherParams // the rest gets passed to the iframe\n  } = queryFromLocation(location);\n\n  let navSize;\n  let bottomPanelHeight;\n  let rightPanelWidth;\n\n  // set sizes based on fullscreen\n  if (parseBoolean(full) === true) {\n    navSize = 0;\n    bottomPanelHeight = 0;\n    rightPanelWidth = 0;\n  } else if (parseBoolean(full) === false) {\n    navSize = DEFAULT_NAV_SIZE;\n    bottomPanelHeight = DEFAULT_BOTTOM_PANEL_HEIGHT;\n    rightPanelWidth = DEFAULT_RIGHT_PANEL_WIDTH;\n  }\n  // set sizes based on nav\n  if (!singleStory) {\n    if (parseBoolean(nav) === true) {\n      navSize = DEFAULT_NAV_SIZE;\n    }\n    if (parseBoolean(nav) === false) {\n      navSize = 0;\n    }\n  }\n  // set sizes based on panel\n  if (parseBoolean(panel) === false) {\n    bottomPanelHeight = 0;\n    rightPanelWidth = 0;\n  }\n\n  const layout: Partial<API_Layout> = {\n    navSize,\n    bottomPanelHeight,\n    rightPanelWidth,\n    panelPosition: ['right', 'bottom'].includes(panel) ? panel : undefined,\n    showTabs: parseBoolean(tabs),\n  };\n  const ui: Partial<API_UI> = {\n    enableShortcuts: parseBoolean(shortcuts),\n  };\n  const selectedPanel = addonPanel || undefined;\n\n  const storyId = storyIdFromUrl;\n  // Avoid returning a new object each time if no params actually changed.\n  const customQueryParams = deepEqual(prevParams, otherParams) ? prevParams : otherParams;\n  prevParams = customQueryParams;\n\n  return { viewMode, layout, ui, selectedPanel, location, path, customQueryParams, storyId };\n};\n\nexport interface QueryParams {\n  [key: string]: string | undefined;\n}\n\ninterface QueryParamInput {\n  [key: string]: string | undefined | null;\n}\n\n/** SubAPI for managing URL navigation and state. */\nexport interface SubAPI {\n  /**\n   * Navigate to a new URL.\n   *\n   * @param {string} url - The URL to navigate to.\n   * @param {NavigateOptions} options - Options for the navigation.\n   * @returns {void}\n   */\n  navigateUrl: (url: string, options: NavigateOptions) => void;\n  /**\n   * Get the manager and preview hrefs for a story.\n   *\n   * @param {string} storyId - The ID of the story to get the URL for.\n   * @param {Object} options - Options for the URL.\n   * @param {string} [options.base] - Return an absolute href based on the current origin or network\n   *   address.\n   * @param {boolean} [options.inheritArgs] - Inherit args from the current URL. If storyId matches\n   *   current story, inheritArgs defaults to true.\n   * @param {boolean} [options.inheritGlobals] - Inherit globals from the current URL. Defaults to\n   *   true.\n   * @param {QueryParams} [options.queryParams] - Query params to add to the URL.\n   * @param {string} [options.refId] - ID of the ref to get the URL for (for composed Storybooks)\n   * @param {string} [options.viewMode] - The view mode to use, defaults to 'story'.\n   * @returns {Object} Manager and preview hrefs for the story.\n   */\n  getStoryHrefs(\n    storyId: string,\n    options?: {\n      base?: 'origin' | 'network';\n      inheritArgs?: boolean;\n      inheritGlobals?: boolean;\n      queryParams?: QueryParams;\n      refId?: string;\n      viewMode?: API_ViewMode;\n    }\n  ): { managerHref: string; previewHref: string };\n  /**\n   * Get the value of a query parameter from the current URL.\n   *\n   * @param {string} key - The key of the query parameter to get.\n   * @returns {string | undefined} The value of the query parameter, or undefined if it does not\n   *   exist.\n   */\n  getQueryParam: (key: string) => string | undefined;\n  /**\n   * Returns an object containing the current state of the URL.\n   *\n   * @returns {{\n   *   queryParams: QueryParams;\n   *   path: string;\n   *   viewMode?: string;\n   *   storyId?: string;\n   *   url: string;\n   * }}\n   *   An object containing the current state of the URL.\n   */\n  getUrlState: () => {\n    queryParams: QueryParams;\n    path: string;\n    hash: string;\n    viewMode?: string;\n    storyId?: string;\n    url: string;\n  };\n  /**\n   * Set the query parameters for the current URL.\n   *\n   * @param {QueryParams} input - An object containing the query parameters to set.\n   * @returns {void}\n   */\n  setQueryParams: (input: QueryParamInput) => void;\n  /**\n   * Set the query parameters for the current URL & navigates.\n   *\n   * @param {QueryParams} input - An object containing the query parameters to set.\n   * @param {NavigateOptions} options - Options for the navigation.\n   * @returns {void}\n   */\n  applyQueryParams: (input: QueryParamInput, options?: NavigateOptions) => void;\n}\n\nexport const init: ModuleFn<SubAPI, SubState> = (moduleArgs) => {\n  const { store, navigate, provider, fullAPI } = moduleArgs;\n\n  const navigateTo = (\n    path: string,\n    queryParams: Record<string, string | null | undefined> = {},\n    options: NavigateOptions = {}\n  ) => {\n    return navigate(buildNavigationUrl(path, queryParams), options);\n  };\n\n  const api: SubAPI = {\n    getStoryHrefs(storyId, options = {}) {\n      const { id: currentStoryId, refId: currentRefId } = fullAPI.getCurrentStoryData() ?? {};\n      const isCurrentStory = storyId === currentStoryId && options.refId === currentRefId;\n\n      const { customQueryParams, location, refs } = store.getState();\n      const {\n        base,\n        inheritArgs = isCurrentStory,\n        inheritGlobals = true,\n        queryParams = {},\n        refId,\n        viewMode = 'story',\n      } = options;\n\n      if (refId && !refs[refId]) {\n        throw new Error(`Invalid refId: ${refId}`);\n      }\n\n      const pathname = location.pathname || '/';\n      const originAddress = global.window.location.origin + pathname;\n      const networkAddress = global.STORYBOOK_NETWORK_ADDRESS ?? originAddress;\n      const managerBase =\n        base === 'origin' ? originAddress : base === 'network' ? networkAddress : pathname;\n      const previewBase = refId\n        ? refs[refId].url + '/iframe.html'\n        : global.PREVIEW_URL ||\n          `${managerBase.replace(/\\/[^/]*\\.html$/, '').replace(/\\/?$/, '/')}iframe.html`;\n\n      const refParam = refId ? `&refId=${encodeURIComponent(refId)}` : '';\n      const { args = '', globals = '', ...otherParams } = queryParams;\n      let argsParam = inheritArgs\n        ? mergeSerializedParams(customQueryParams?.args ?? '', args)\n        : args;\n      let globalsParam = inheritGlobals\n        ? mergeSerializedParams(customQueryParams?.globals ?? '', globals)\n        : globals;\n      let customManagerParams = stringify(otherParams, {\n        nesting: true,\n        nestingSyntax: 'js',\n      });\n      let customPreviewParams = stringify(omit(otherParams, ['id', 'viewMode']), {\n        nesting: true,\n        nestingSyntax: 'js',\n      });\n\n      argsParam = argsParam && `&args=${argsParam}`;\n      globalsParam = globalsParam && `&globals=${globalsParam}`;\n      customManagerParams = customManagerParams && `&${customManagerParams}`;\n      customPreviewParams = customPreviewParams && `&${customPreviewParams}`;\n\n      return {\n        managerHref: `${managerBase}?path=/${viewMode}/${refId ? `${refId}_` : ''}${storyId}${argsParam}${globalsParam}${customManagerParams}`,\n        previewHref: `${previewBase}?id=${storyId}&viewMode=${viewMode}${refParam}${argsParam}${refId ? '' : globalsParam}${customPreviewParams}`,\n      };\n    },\n    getQueryParam(key) {\n      const { customQueryParams } = store.getState();\n      return customQueryParams ? customQueryParams[key] : undefined;\n    },\n    getUrlState() {\n      const { location, path, customQueryParams, storyId, url, viewMode } = store.getState();\n      return {\n        path,\n        hash: location?.hash ?? '',\n        queryParams: customQueryParams,\n        storyId,\n        url,\n        viewMode,\n      };\n    },\n    setQueryParams(input) {\n      const { customQueryParams } = store.getState();\n      const update: QueryParams = { ...customQueryParams };\n      for (const [key, value] of Object.entries(input)) {\n        if (value === null || value === undefined) {\n          delete update[key];\n        } else {\n          update[key] = value;\n        }\n      }\n      if (!deepEqual(customQueryParams, update)) {\n        store.setState({ customQueryParams: update });\n        provider.channel?.emit(UPDATE_QUERY_PARAMS, update);\n      }\n    },\n    applyQueryParams(input, options) {\n      const { path, hash = '', queryParams } = api.getUrlState();\n\n      navigateTo(`${path}${hash}`, { ...queryParams, ...input } as any, options);\n      api.setQueryParams(input);\n    },\n    navigateUrl(url, options) {\n      navigate(url, { plain: true, ...options });\n    },\n  };\n\n  /**\n   * Sets `args` parameter in URL, omitting any args that have their initial value or cannot be\n   * unserialized safely.\n   */\n  const updateArgsParam = () => {\n    const { path, hash = '', queryParams, viewMode } = api.getUrlState();\n\n    if (viewMode !== 'story') {\n      return;\n    }\n\n    const currentStory = fullAPI.getCurrentStoryData();\n\n    if (currentStory?.type !== 'story') {\n      return;\n    }\n\n    const { args, initialArgs } = currentStory;\n    const argsString = buildArgsParam(initialArgs, args as Args);\n    navigateTo(`${path}${hash}`, { ...queryParams, args: argsString || null }, { replace: true });\n    api.setQueryParams({ args: argsString || null });\n  };\n\n  provider.channel?.on(SET_CURRENT_STORY, () => updateArgsParam());\n\n  let handleOrId: any;\n  provider.channel?.on(STORY_ARGS_UPDATED, () => {\n    if ('requestIdleCallback' in global.window) {\n      if (handleOrId) {\n        global.window.cancelIdleCallback(handleOrId);\n      }\n      handleOrId = global.window.requestIdleCallback(updateArgsParam, { timeout: 1000 });\n    } else {\n      if (handleOrId) {\n        clearTimeout(handleOrId);\n      }\n      setTimeout(updateArgsParam, 100);\n    }\n  });\n\n  provider.channel?.on(GLOBALS_UPDATED, ({ userGlobals, initialGlobals }: any) => {\n    const { path, hash = '', queryParams } = api.getUrlState();\n    const globalsString = buildArgsParam(initialGlobals, merge(initialGlobals, userGlobals));\n    navigateTo(\n      `${path}${hash}`,\n      { ...queryParams, globals: globalsString || null },\n      { replace: true }\n    );\n    api.setQueryParams({ globals: globalsString || null });\n  });\n\n  provider.channel?.on(NAVIGATE_URL, (url: string, options: NavigateOptions) => {\n    api.navigateUrl(url, options);\n  });\n\n  return {\n    api,\n    state: initialUrlSupport(moduleArgs),\n    init: () => {\n      store.registerPersistenceHandler('url', (_patch, serialize) => {\n        if (serialize) {\n          const params = serialize(store.getState());\n          api.applyQueryParams(params, { replace: true });\n        }\n      });\n    },\n  };\n};\n"
  },
  {
    "path": "code/core/src/manager-api/modules/versions.ts",
    "content": "import type { API_UnknownEntries, API_Version, API_Versions } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport memoize from 'memoizerific';\nimport semver from 'semver';\n\nimport type { ModuleFn } from '../lib/types.tsx';\nimport { version as currentVersion } from '../version.ts';\n\nconst { VERSIONCHECK } = global;\n\nexport interface SubState {\n  versions: API_Versions & API_UnknownEntries;\n  lastVersionCheck: number;\n  dismissedVersionNotification: undefined | string;\n}\n\nconst getVersionCheckData = memoize(1)((): API_Versions => {\n  try {\n    return { ...(JSON.parse(VERSIONCHECK).data || {}) };\n  } catch (e) {\n    return {};\n  }\n});\n\nconst normalizeRendererName = (renderer: string) => {\n  if (renderer.includes('vue')) {\n    return 'vue';\n  }\n\n  return renderer;\n};\n\nexport interface SubAPI {\n  /**\n   * Returns the current version of the Storybook Manager.\n   *\n   * @returns {API_Version} The current version of the Storybook Manager.\n   */\n  getCurrentVersion: () => API_Version;\n  /**\n   * Returns the latest version of the Storybook Manager.\n   *\n   * @returns {API_Version} The latest version of the Storybook Manager.\n   */\n  getLatestVersion: () => API_Version;\n  /**\n   * Returns the URL of the Storybook documentation for the current version.\n   *\n   * @param options - The options for the documentation URL.\n   * @param options.asset - Like subpath, but links to the docs-assets directory.\n   * @param options.subpath - The subpath of the documentation URL.\n   * @param options.versioned - Whether to include the versioned path.\n   * @param options.renderer - Whether to include the renderer path.\n   * @param options.ref - Tracking reference for the docs site. E.g. 'ui', 'error', 'upgrade', etc.\n   * @returns {string} The URL of the Storybook Manager documentation.\n   */\n  getDocsUrl: (options: {\n    asset?: string;\n    subpath?: string;\n    versioned?: boolean;\n    renderer?: boolean;\n    ref?: string;\n  }) => string;\n  /**\n   * Checks if an update is available for the Storybook Manager.\n   *\n   * @returns {boolean} True if an update is available, false otherwise.\n   */\n  versionUpdateAvailable: () => boolean;\n}\n\nexport const init: ModuleFn = ({ store }) => {\n  const { dismissedVersionNotification } = store.getState();\n\n  const state = {\n    versions: {\n      current: {\n        version: currentVersion,\n      },\n      ...getVersionCheckData(),\n    },\n    dismissedVersionNotification,\n  };\n\n  const api: SubAPI = {\n    getCurrentVersion: () => {\n      const {\n        versions: { current },\n      } = store.getState();\n      return current as API_Version;\n    },\n    getLatestVersion: () => {\n      const {\n        versions: { latest, next, current },\n      } = store.getState();\n      if (current && semver.prerelease(current.version) && next) {\n        return (latest && semver.gt(latest.version, next.version) ? latest : next) as API_Version;\n      }\n      return latest as API_Version;\n    },\n    // TODO: Move this to it's own \"info\" module later\n    getDocsUrl: ({ asset, subpath = asset, versioned, renderer, ref = 'ui' }) => {\n      const { versions } = store.getState();\n      const latestVersion = versions.latest?.version;\n      const currentVersion = versions.current?.version;\n      const activeVersion =\n        (currentVersion?.startsWith('0.0.0') && latestVersion) || currentVersion;\n\n      let url = `https://storybook.js.org/${asset ? 'docs-assets' : 'docs'}/`;\n\n      if (asset && activeVersion) {\n        url += `${semver.major(activeVersion)}.${semver.minor(activeVersion)}/`;\n      } else if (versioned && activeVersion && latestVersion) {\n        const versionDiff = semver.diff(latestVersion, activeVersion);\n        const isLatestDocs = versionDiff === 'patch' || versionDiff === null;\n\n        if (!isLatestDocs) {\n          url += `${semver.major(activeVersion)}.${semver.minor(activeVersion)}/`;\n        }\n      }\n\n      const [cleanedSubpath, hash] = subpath?.split('#') || [];\n\n      if (cleanedSubpath) {\n        url += asset ? cleanedSubpath : `${cleanedSubpath}/`;\n      }\n\n      if (renderer && typeof global.STORYBOOK_RENDERER !== 'undefined') {\n        const rendererName = global.STORYBOOK_RENDERER as string;\n\n        if (rendererName) {\n          url += `?renderer=${normalizeRendererName(rendererName)}`;\n        }\n      }\n\n      if (ref) {\n        url += `${url.includes('?') ? '&' : '?'}ref=${ref}`;\n      }\n\n      if (hash) {\n        url += `#${hash}`;\n      }\n\n      return url;\n    },\n    versionUpdateAvailable: () => {\n      const latest = api.getLatestVersion();\n      const current = api.getCurrentVersion();\n\n      if (latest) {\n        if (!latest.version) {\n          return true;\n        }\n        if (!current.version) {\n          return true;\n        }\n\n        const onPrerelease = !!semver.prerelease(current.version);\n\n        const actualCurrent = onPrerelease\n          ? `${semver.major(current.version)}.${semver.minor(current.version)}.${semver.patch(\n              current.version\n            )}`\n          : current.version;\n\n        const diff = semver.diff(actualCurrent, latest.version);\n\n        return (\n          semver.gt(latest.version, actualCurrent) && diff !== 'patch' && !diff!.includes('pre')\n        );\n      }\n      return false;\n    },\n  };\n\n  // Grab versions from the server/local storage right away\n  const initModule = async () => {\n    const { versions = {} } = store.getState();\n\n    const { latest, next } = getVersionCheckData();\n\n    await store.setState({\n      versions: { ...versions, latest, next } as API_Versions & API_UnknownEntries,\n    });\n  };\n\n  return { init: initModule, state, api };\n};\n"
  },
  {
    "path": "code/core/src/manager-api/modules/whatsnew.tsx",
    "content": "import React from 'react';\n\nimport {\n  REQUEST_WHATS_NEW_DATA,\n  RESULT_WHATS_NEW_DATA,\n  SET_WHATS_NEW_CACHE,\n  TOGGLE_WHATS_NEW_NOTIFICATIONS,\n} from 'storybook/internal/core-events';\nimport type { WhatsNewCache, WhatsNewData } from 'storybook/internal/core-events';\n\nimport { global } from '@storybook/global';\n\nimport type { ModuleFn } from '../lib/types.tsx';\n\nexport type SubState = {\n  whatsNewData?: WhatsNewData;\n};\n\nexport type SubAPI = {\n  isWhatsNewUnread(): boolean;\n  whatsNewHasBeenRead(): void;\n  toggleWhatsNewNotifications(): void;\n};\n\nconst WHATS_NEW_NOTIFICATION_ID = 'whats-new';\n\n/*\nCopied from https://github.com/storybookjs/icons/blob/main/src/icons/StorybookIcon.tsx\nbecause:\nA. if we import the icon from @storybook/icons, the CJS output can't tree-shake the package, so it increases the bundle size with +200KB\nB. we can't rely on the globalization by the manager, because react native also uses this manager-api and doesn't do the globalization\n\nTODO: turn this into an import again when we go ESM-only in Storybook 10, as the ESM output tree-shakes fine\n*/\nconst StorybookIcon = ({ color = 'currentColor', size = 14 }) => {\n  return (\n    <svg\n      width={size}\n      height={size}\n      viewBox=\"0 0 14 14\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n    >\n      <path\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n        d=\"M2.042.616a.704.704 0 00-.66.729L1.816 12.9c.014.367.306.66.672.677l9.395.422h.032a.704.704 0 00.704-.703V.704c0-.015 0-.03-.002-.044a.704.704 0 00-.746-.659l-.773.049.057 1.615a.105.105 0 01-.17.086l-.52-.41-.617.468a.105.105 0 01-.168-.088L9.746.134 2.042.616zm8.003 4.747c-.247.192-2.092.324-2.092.05.04-1.045-.429-1.091-.689-1.091-.247 0-.662.075-.662.634 0 .57.607.893 1.32 1.27 1.014.538 2.24 1.188 2.24 2.823 0 1.568-1.273 2.433-2.898 2.433-1.676 0-3.141-.678-2.976-3.03.065-.275 2.197-.21 2.197 0-.026.971.195 1.256.753 1.256.43 0 .624-.236.624-.634 0-.602-.633-.958-1.361-1.367-.987-.554-2.148-1.205-2.148-2.7 0-1.494 1.027-2.489 2.86-2.489 1.832 0 2.832.98 2.832 2.845z\"\n        fill={color}\n      />\n    </svg>\n  );\n};\n\nexport const init: ModuleFn = ({ fullAPI, store, provider }) => {\n  const state: SubState = {\n    whatsNewData: undefined,\n  };\n\n  function setWhatsNewState(newState: WhatsNewData) {\n    store.setState({ whatsNewData: newState });\n    state.whatsNewData = newState;\n  }\n\n  const api: SubAPI = {\n    isWhatsNewUnread() {\n      return state.whatsNewData?.status === 'SUCCESS' && !state.whatsNewData.postIsRead;\n    },\n    whatsNewHasBeenRead() {\n      if (state.whatsNewData?.status === 'SUCCESS') {\n        setWhatsNewCache({ lastReadPost: state.whatsNewData.url });\n        setWhatsNewState({ ...state.whatsNewData, postIsRead: true });\n        fullAPI.clearNotification(WHATS_NEW_NOTIFICATION_ID);\n      }\n    },\n    toggleWhatsNewNotifications() {\n      if (state.whatsNewData?.status === 'SUCCESS') {\n        setWhatsNewState({\n          ...state.whatsNewData,\n          disableWhatsNewNotifications: !state.whatsNewData.disableWhatsNewNotifications,\n        });\n        provider.channel?.emit(TOGGLE_WHATS_NEW_NOTIFICATIONS, {\n          disableWhatsNewNotifications: state.whatsNewData.disableWhatsNewNotifications,\n        });\n      }\n    },\n  };\n\n  function getLatestWhatsNewPost(): Promise<WhatsNewData> {\n    provider.channel?.emit(REQUEST_WHATS_NEW_DATA);\n\n    return new Promise((resolve) =>\n      provider.channel?.once(RESULT_WHATS_NEW_DATA, ({ data }: { data: WhatsNewData }) =>\n        resolve(data)\n      )\n    );\n  }\n\n  function setWhatsNewCache(cache: WhatsNewCache): void {\n    provider.channel?.emit(SET_WHATS_NEW_CACHE, cache);\n  }\n\n  const initModule = async () => {\n    // The server channel doesn't exist in production, and we don't want to show what's new in production storybooks.\n    if (global.CONFIG_TYPE !== 'DEVELOPMENT') {\n      return;\n    }\n\n    const whatsNewData = await getLatestWhatsNewPost();\n    setWhatsNewState(whatsNewData);\n\n    const urlState = fullAPI.getUrlState();\n    const isOnboardingView =\n      urlState?.path === '/onboarding' || urlState.queryParams?.onboarding === 'true';\n\n    if (\n      !isOnboardingView &&\n      whatsNewData.status === 'SUCCESS' &&\n      !whatsNewData.disableWhatsNewNotifications &&\n      whatsNewData.showNotification\n    ) {\n      fullAPI.addNotification({\n        id: WHATS_NEW_NOTIFICATION_ID,\n        link: '/settings/whats-new',\n        content: {\n          headline: whatsNewData.title,\n          subHeadline: \"Learn what's new in Storybook\",\n        },\n        icon: <StorybookIcon />,\n        onClear({ dismissed }: any) {\n          if (dismissed) {\n            setWhatsNewCache({ lastDismissedPost: whatsNewData.url });\n          }\n        },\n      });\n    }\n  };\n\n  return { init: initModule, state, api };\n};\n"
  },
  {
    "path": "code/core/src/manager-api/root.tsx",
    "content": "import type { FC, ReactElement, ReactNode } from 'react';\nimport React, {\n  Component,\n  Fragment,\n  useCallback,\n  useContext,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n} from 'react';\n\nimport type { Listener } from 'storybook/internal/channels';\nimport {\n  DOCS_PREPARED,\n  SET_STORIES,\n  SHARED_STATE_CHANGED,\n  SHARED_STATE_SET,\n  STORY_CHANGED,\n  STORY_PREPARED,\n} from 'storybook/internal/core-events';\nimport type { RouterData } from 'storybook/internal/router';\nimport type {\n  API_ComponentEntry,\n  API_ComposedRef,\n  API_DocsEntry,\n  API_GroupEntry,\n  API_HashEntry,\n  API_IndexHash,\n  API_LeafEntry,\n  API_OptionsData,\n  API_ProviderData,\n  API_Refs,\n  API_RootEntry,\n  API_StateMerger,\n  API_StoryEntry,\n  API_TestEntry,\n  ArgTypes,\n  Args,\n  GlobalTypes,\n  Globals,\n  Parameters,\n  StoryId,\n} from 'storybook/internal/types';\n\nimport { isEqual } from 'es-toolkit/predicate';\n\nimport { createContext } from './context.ts';\nimport getInitialState from './initial-state.ts';\nimport { types } from './lib/addons.ts';\nimport { noArrayMerge } from './lib/merge.ts';\nimport type { ModuleFn } from './lib/types.tsx';\nimport * as addons from './modules/addons.ts';\nimport * as channel from './modules/channel.ts';\nimport * as globals from './modules/globals.ts';\nimport * as layout from './modules/layout.ts';\nimport * as notifications from './modules/notifications.ts';\nimport * as openInEditor from './modules/open-in-editor.tsx';\nimport * as provider from './modules/provider.ts';\nimport * as refs from './modules/refs.ts';\nimport * as settings from './modules/settings.ts';\nimport * as shortcuts from './modules/shortcuts.ts';\nimport * as stories from './modules/stories.ts';\nimport * as url from './modules/url.ts';\nimport * as version from './modules/versions.ts';\nimport * as whatsnew from './modules/whatsnew.tsx';\nimport type { Options } from './store.ts';\nimport Store from './store.ts';\n\nexport * from './lib/request-response.ts';\nexport * from './lib/platform.ts';\nexport * from './lib/shortcut.ts';\n\nconst { ActiveTabs } = layout;\n\nexport { default as merge } from './lib/merge.ts';\nexport type { Options as StoreOptions, Listener as ChannelListener };\nexport { ActiveTabs };\n\nexport const ManagerContext = createContext({ api: undefined!, state: getInitialState({}!) });\n\nexport type State = layout.SubState &\n  stories.SubState &\n  refs.SubState &\n  notifications.SubState &\n  version.SubState &\n  url.SubState &\n  shortcuts.SubState &\n  settings.SubState &\n  globals.SubState &\n  whatsnew.SubState &\n  RouterData &\n  API_OptionsData &\n  Other;\n\nexport type API = addons.SubAPI &\n  channel.SubAPI &\n  provider.SubAPI &\n  stories.SubAPI &\n  refs.SubAPI &\n  globals.SubAPI &\n  layout.SubAPI &\n  notifications.SubAPI &\n  shortcuts.SubAPI &\n  settings.SubAPI &\n  version.SubAPI &\n  url.SubAPI &\n  whatsnew.SubAPI &\n  openInEditor.SubAPI &\n  Other;\n\ninterface Other {\n  [key: string]: any;\n}\n\nexport interface Combo {\n  api: API;\n  state: State;\n}\n\nexport type ManagerProviderProps = RouterData &\n  API_ProviderData<API> & {\n    children: ReactNode | FC<Combo>;\n  };\n\n// This is duplicated from storybook/preview-api for the reasons mentioned in lib-addons/types.js\nexport const combineParameters = (...parameterSets: Parameters[]) =>\n  noArrayMerge({}, ...parameterSets);\n\nclass ManagerProvider extends Component<ManagerProviderProps, State> {\n  api: API = {} as API;\n\n  modules: ReturnType<ModuleFn>[];\n\n  static displayName = 'Manager';\n\n  constructor(props: ManagerProviderProps) {\n    super(props);\n    const {\n      location,\n      path,\n      refId,\n      viewMode = props.docsOptions.docsMode ? 'docs' : props.viewMode,\n      singleStory,\n      storyId,\n      docsOptions,\n      navigate,\n    } = props;\n\n    const store = new Store({\n      getState: () => this.state,\n      setState: (stateChange: Partial<State>, callback) => {\n        this.setState(stateChange, () => callback(this.state));\n\n        return this.state;\n      },\n    });\n\n    const routeData = { location, path, viewMode, singleStory, storyId, refId };\n    const optionsData: API_OptionsData = { docsOptions };\n\n    this.state = store.getInitialState(getInitialState({ ...routeData, ...optionsData }));\n\n    const apiData = {\n      navigate,\n      store,\n      provider: props.provider,\n    };\n\n    this.modules = [\n      provider,\n      channel,\n      addons,\n      layout,\n      notifications,\n      settings,\n      shortcuts,\n      stories,\n      refs,\n      globals,\n      url,\n      version,\n      whatsnew,\n      openInEditor,\n    ].map((m) =>\n      m.init({ ...routeData, ...optionsData, ...apiData, state: this.state, fullAPI: this.api })\n    );\n\n    // Create our initial state by combining the initial state of all modules, then overlaying any saved state\n    const state = getInitialState(this.state, ...this.modules.map((m) => m.state!));\n\n    // Get our API by combining the APIs exported by each module\n    const api: API = Object.assign(this.api, { navigate }, ...this.modules.map((m) => m.api));\n\n    this.state = state;\n    this.api = api;\n  }\n\n  static getDerivedStateFromProps(props: ManagerProviderProps, state: State): State {\n    if (state.path !== props.path) {\n      return {\n        ...state,\n        location: props.location,\n        path: props.path,\n        refId: props.refId,\n        viewMode: props.viewMode,\n        storyId: props.storyId!,\n      };\n    }\n    return null!;\n  }\n\n  shouldComponentUpdate(nextProps: ManagerProviderProps, nextState: State): boolean {\n    const prevProps = this.props;\n    const prevState = this.state;\n    return prevProps.path !== nextProps.path || !isEqual(prevState, nextState);\n  }\n\n  initModules = () => {\n    // Now every module has had a chance to set its API, call init on each module which gives it\n    // a chance to do things that call other modules' APIs.\n    this.modules.forEach((module: any) => {\n      if ('init' in module) {\n        module.init();\n      }\n    });\n  };\n\n  render() {\n    const { children } = this.props;\n    const value = {\n      state: this.state,\n      api: this.api,\n    };\n\n    return (\n      <EffectOnMount effect={this.initModules}>\n        <ManagerContext.Provider value={value}>\n          <ManagerConsumer>{children}</ManagerConsumer>\n        </ManagerContext.Provider>\n      </EffectOnMount>\n    );\n  }\n}\n\n// EffectOnMount exists to work around a bug in Reach Router where calling\n// navigate inside of componentDidMount (as could happen when we call init on any\n// of our modules) does not cause Reach Router's LocationProvider to update with\n// the correct path. Calling navigate inside on an effect does not have the\n// same problem. See https://github.com/reach/router/issues/404\nconst EffectOnMount: FC<{\n  children: ReactElement;\n  effect: () => void;\n}> = ({ children, effect }) => {\n  React.useEffect(effect, []);\n  return children;\n};\n\ninterface ManagerConsumerProps<P = unknown> {\n  filter?: (combo: Combo) => P;\n  children: FC<P> | ReactNode;\n}\n\nconst defaultFilter = (c: Combo) => c;\n\nfunction ManagerConsumer<P = Combo>({\n  // @ts-expect-error (Converted from ts-ignore)\n  filter = defaultFilter,\n  children,\n}: ManagerConsumerProps<P>): ReactElement {\n  const managerContext = useContext(ManagerContext);\n  const renderer = useRef(children);\n  const filterer = useRef(filter);\n\n  if (typeof renderer.current !== 'function') {\n    return <Fragment>{renderer.current}</Fragment>;\n  }\n\n  const comboData = filterer.current(managerContext);\n\n  const comboDataArray = useMemo(() => {\n    // @ts-expect-error (No overload matches this call)\n    return [...Object.entries(comboData).reduce((acc, keyval) => acc.concat(keyval), [])];\n  }, [managerContext.state]);\n\n  return useMemo(() => {\n    const Child: any = renderer.current as FC<P>;\n\n    return <Child {...comboData} />;\n  }, comboDataArray);\n}\n\nexport function useStorybookState(): State {\n  const { state } = useContext(ManagerContext);\n  return state;\n}\nexport function useStorybookApi(): API {\n  const { api } = useContext(ManagerContext);\n  return api;\n}\n\nexport type {\n  /** @deprecated Now IndexHash */\n  API_IndexHash as StoriesHash,\n  API_IndexHash as IndexHash,\n  API_RootEntry as RootEntry,\n  API_GroupEntry as GroupEntry,\n  API_ComponentEntry as ComponentEntry,\n  API_DocsEntry as DocsEntry,\n  API_StoryEntry as StoryEntry,\n  API_HashEntry as HashEntry,\n  API_LeafEntry as LeafEntry,\n  API_ComposedRef as ComposedRef,\n  API_Refs as Refs,\n};\nexport { ManagerConsumer as Consumer, ManagerProvider as Provider };\n\nexport interface API_EventMap {\n  [eventId: string]: Listener;\n}\n\nfunction orDefault<S>(fromStore: S, defaultState: S): S {\n  if (typeof fromStore === 'undefined') {\n    return defaultState;\n  }\n  return fromStore;\n}\n\nexport const useChannel = (eventMap: API_EventMap, deps: any[] = []) => {\n  const api = useStorybookApi();\n  useEffect(() => {\n    Object.entries(eventMap).forEach(([type, listener]) => api.on(type, listener));\n    return () => {\n      Object.entries(eventMap).forEach(([type, listener]) => api.off(type, listener));\n    };\n  }, deps);\n\n  return api.emit;\n};\n\nexport function useStoryPrepared(storyId?: StoryId) {\n  const api = useStorybookApi();\n  return api.isPrepared(storyId!);\n}\n\nexport function useParameter<S>(parameterKey: string, defaultValue?: S) {\n  const api = useStorybookApi();\n  const [parameter, setParameter] = useState(api.getCurrentParameter<S>(parameterKey));\n\n  const handleParameterChange = useCallback(() => {\n    const newParameter = api.getCurrentParameter<S>(parameterKey);\n    setParameter(newParameter);\n  }, [api, parameterKey]);\n\n  useChannel(\n    {\n      [STORY_PREPARED]: handleParameterChange,\n      [DOCS_PREPARED]: handleParameterChange,\n    },\n    [handleParameterChange]\n  );\n\n  return orDefault<S>(parameter, defaultValue!);\n}\n\n// cache for taking care of HMR\nglobalThis.STORYBOOK_ADDON_STATE = {};\nconst { STORYBOOK_ADDON_STATE } = globalThis;\n\n// shared state\nexport function useSharedState<S>(stateId: string, defaultState?: S) {\n  const api = useStorybookApi();\n  const existingState = api.getAddonState<S>(stateId) || STORYBOOK_ADDON_STATE[stateId];\n  const state = orDefault<S>(\n    existingState,\n    STORYBOOK_ADDON_STATE[stateId] ? STORYBOOK_ADDON_STATE[stateId] : defaultState\n  );\n  let quicksync = false;\n\n  if (state === defaultState && defaultState !== undefined) {\n    STORYBOOK_ADDON_STATE[stateId] = defaultState;\n    quicksync = true;\n  }\n\n  useEffect(() => {\n    if (quicksync) {\n      // @ts-expect-error (Argument of type 'S | undefined' is not assignable)\n      api.setAddonState<S>(stateId, defaultState);\n    }\n  }, [quicksync]);\n\n  const setState = useCallback(\n    async (s: S | API_StateMerger<S>, options?: Options) => {\n      await api.setAddonState<S>(stateId, s, options);\n      const result = api.getAddonState(stateId);\n\n      STORYBOOK_ADDON_STATE[stateId] = result;\n      return result;\n    },\n    [api, stateId]\n  );\n\n  const allListeners = useMemo(() => {\n    const stateChangeHandlers = {\n      [`${SHARED_STATE_CHANGED}-client-${stateId}`]: setState,\n      [`${SHARED_STATE_SET}-client-${stateId}`]: setState,\n    };\n    const stateInitializationHandlers = {\n      [SET_STORIES]: async () => {\n        const currentState = api.getAddonState(stateId);\n        if (currentState) {\n          STORYBOOK_ADDON_STATE[stateId] = currentState;\n          api.emit(`${SHARED_STATE_SET}-manager-${stateId}`, currentState);\n        } else if (STORYBOOK_ADDON_STATE[stateId]) {\n          // this happens when HMR\n          await setState(STORYBOOK_ADDON_STATE[stateId]);\n          api.emit(`${SHARED_STATE_SET}-manager-${stateId}`, STORYBOOK_ADDON_STATE[stateId]);\n        } else if (defaultState !== undefined) {\n          // if not HMR, yet the defaults are from the manager\n          await setState(defaultState);\n          // initialize STORYBOOK_ADDON_STATE after first load, so its available for subsequent HMR\n          STORYBOOK_ADDON_STATE[stateId] = defaultState;\n          api.emit(`${SHARED_STATE_SET}-manager-${stateId}`, defaultState);\n        }\n      },\n      [STORY_CHANGED]: () => {\n        const currentState = api.getAddonState(stateId);\n\n        if (currentState !== undefined) {\n          api.emit(`${SHARED_STATE_SET}-manager-${stateId}`, currentState);\n        }\n      },\n    };\n\n    return {\n      ...stateChangeHandlers,\n      ...stateInitializationHandlers,\n    };\n  }, [stateId]);\n\n  const emit = useChannel(allListeners);\n\n  const stateSetter = useCallback(\n    async (newStateOrMerger: S | API_StateMerger<S>, options?: Options) => {\n      await setState(newStateOrMerger, options);\n      const result = api.getAddonState(stateId);\n      emit(`${SHARED_STATE_CHANGED}-manager-${stateId}`, result);\n    },\n    [api, emit, setState, stateId]\n  );\n\n  return [state, stateSetter] as [\n    S,\n    (newStateOrMerger: S | API_StateMerger<S>, options?: Options) => void,\n  ];\n}\n\nexport function useAddonState<S>(addonId: string, defaultState?: S) {\n  return useSharedState<S>(addonId, defaultState);\n}\n\nexport function useArgs(): [Args, (newArgs: Args) => void, (argNames?: string[]) => void, Args] {\n  const { getCurrentStoryData, updateStoryArgs, resetStoryArgs } = useStorybookApi();\n\n  const data = getCurrentStoryData();\n  const args = data?.type === 'story' ? data.args : {};\n  const initialArgs = data?.type === 'story' ? data.initialArgs : {};\n\n  const updateArgs = useCallback(\n    (newArgs: Args) => updateStoryArgs(data as API_StoryEntry, newArgs),\n    [data, updateStoryArgs]\n  );\n  const resetArgs = useCallback(\n    (argNames?: string[]) => resetStoryArgs(data as API_StoryEntry, argNames),\n    [data, resetStoryArgs]\n  );\n\n  return [args!, updateArgs, resetArgs, initialArgs!];\n}\n\nexport function useGlobals(): [\n  globals: Globals,\n  updateGlobals: (newGlobals: Globals) => void,\n  storyGlobals: Globals,\n  userGlobals: Globals,\n] {\n  const api = useStorybookApi();\n  return [api.getGlobals(), api.updateGlobals, api.getStoryGlobals(), api.getUserGlobals()];\n}\n\nexport function useGlobalTypes(): GlobalTypes {\n  return useStorybookApi().getGlobalTypes();\n}\n\nfunction useCurrentStory(): API_StoryEntry | API_TestEntry | API_DocsEntry {\n  const { getCurrentStoryData } = useStorybookApi();\n\n  return getCurrentStoryData();\n}\n\nexport function useArgTypes(): ArgTypes {\n  const current = useCurrentStory();\n  return (current?.type === 'story' && current.argTypes) || {};\n}\n\nexport { addons } from './lib/addons.ts';\n\n// We need to rename this so it's not compiled to a straight re-export\n// Our globalization plugin can't handle an import and export of the same name in different lines\nconst typesX = types;\n\nexport { typesX as types };\n\n/* deprecated */\nexport { mockChannel, type Addon, type AddonStore } from './lib/addons.ts';\n"
  },
  {
    "path": "code/core/src/manager-api/store.ts",
    "content": "import type { StoreAPI } from 'store2';\nimport store from 'store2';\n\nimport storeSetup from './lib/store-setup.ts';\nimport type { State } from './root.tsx';\n\n// setting up the store, overriding set and get to use telejson\nstoreSetup(store._);\n\nexport const STORAGE_KEY = '@storybook/manager/store';\n\nfunction get(storage: StoreAPI) {\n  const data = storage.get(STORAGE_KEY);\n  return data || {};\n}\n\nfunction set(storage: StoreAPI, value: Patch) {\n  return storage.set(STORAGE_KEY, value);\n}\n\nfunction update(storage: StoreAPI, patch: Patch) {\n  const previous = get(storage);\n  // Apply the same behaviour as react here\n  return set(storage, { ...previous, ...patch });\n}\n\ntype GetState = () => State;\ntype SetState = (a: any, b: any) => any;\n\nexport interface Upstream {\n  /**\n   * Whether to allow persistence of state to local/sessionStorage. This is used to disable\n   * persistence in Storybook's own tests. True by default.\n   */\n  allowPersistence?: boolean;\n  getState: GetState;\n  setState: SetState;\n}\n\ntype Patch = Partial<State>;\n\ntype InputFnPatch = (s: State) => Patch;\ntype InputPatch = Patch | InputFnPatch;\n\nexport type PersistenceHandler = (\n  patch: Partial<State>,\n  serialize: ((s: State) => Partial<Record<string, string | null | undefined>>) | undefined\n) => void | Promise<void>;\n\nexport interface Options {\n  persistence: 'none' | 'session' | 'url' | string;\n  serialize?: (s: State) => Partial<Record<string, string | null | undefined>>;\n}\ntype CallBack = (s: State) => void;\ntype CallbackOrOptions = CallBack | Options;\n\n// Our store piggybacks off the internal React state of the Context Provider\n// It has been augmented to persist state to local/sessionStorage\nexport default class Store {\n  upstreamPersistence: boolean;\n  upstreamGetState: GetState;\n  upstreamSetState: SetState;\n  private persistenceHandlers: Map<string, PersistenceHandler> = new Map();\n\n  constructor({ allowPersistence, setState, getState }: Upstream) {\n    this.upstreamPersistence = allowPersistence ?? true;\n    this.upstreamSetState = setState;\n    this.upstreamGetState = getState;\n  }\n\n  registerPersistenceHandler(key: string, handler: PersistenceHandler) {\n    this.persistenceHandlers.set(key, handler);\n  }\n\n  // The assumption is that this will be called once, to initialize the React state\n  // when the module is instantiated\n  getInitialState(base: State) {\n    // TODO: Remove in SB 11\n    // One-time migration: tag filter state moved from localStorage to URL persistence.\n    // Remove the old keys so they no longer interfere with URL-derived initial state.\n    for (const storage of [store.local, store.session] as const) {\n      const persisted = get(storage);\n      if ('includedTagFilters' in persisted || 'excludedTagFilters' in persisted) {\n        const { includedTagFilters: _i, excludedTagFilters: _e, ...rest } = persisted;\n        set(storage, rest);\n      }\n    }\n\n    // We don't only merge at the very top level (the same way as React setState)\n    // when you set keys, so it makes sense to do the same in combining the two storage modes\n    // Really, you shouldn't store the same key in both places\n    const local = get(store.local);\n    const session = get(store.session);\n\n    return { ...base, ...local, ...session };\n  }\n\n  getState() {\n    return this.upstreamGetState();\n  }\n\n  async setState(inputPatch: InputPatch, options?: Options): Promise<State>;\n\n  async setState(inputPatch: InputPatch, callback?: CallBack, options?: Options): Promise<State>;\n\n  async setState(\n    inputPatch: InputPatch,\n    cbOrOptions?: CallbackOrOptions,\n    inputOptions?: Options\n  ): Promise<State> {\n    let callback;\n    let options;\n    if (typeof cbOrOptions === 'function') {\n      callback = cbOrOptions;\n      options = inputOptions;\n    } else {\n      options = cbOrOptions;\n    }\n    const { persistence = 'none' } = options || {};\n\n    let patch: Patch = {};\n    // What did the patch actually return\n    let delta: Patch = {};\n    if (typeof inputPatch === 'function') {\n      // Pass the same function, but set delta on the way\n      patch = (state: State) => {\n        const getDelta = inputPatch as InputFnPatch;\n        delta = getDelta(state);\n        return delta;\n      };\n    } else {\n      patch = inputPatch;\n      delta = patch;\n    }\n\n    const newState: State = await new Promise((resolve) => {\n      this.upstreamSetState(patch, () => {\n        resolve(this.getState());\n      });\n    });\n\n    if (persistence !== 'none' && this.upstreamPersistence) {\n      if (persistence === 'url') {\n        const handler = this.persistenceHandlers.get('url');\n        if (handler) {\n          await handler(delta, (options as Options | undefined)?.serialize);\n        }\n      } else {\n        const storage = persistence === 'session' ? store.session : store.local;\n        await update(storage, delta);\n      }\n    }\n\n    if (callback) {\n      callback(newState);\n    }\n\n    return newState;\n  }\n}\n"
  },
  {
    "path": "code/core/src/manager-api/stores/__mocks__/checklist.ts",
    "content": "import {\n  type StoreEvent,\n  type StoreState,\n  createChecklistStore,\n} from '../../../shared/checklist-store/index.ts';\nimport { UNIVERSAL_CHECKLIST_STORE_OPTIONS } from '../../../shared/checklist-store/index.ts';\nimport { UniversalStore } from '../../../shared/universal-store/index.ts';\n\nexport const mockUniversalChecklistStore = UniversalStore.create<StoreState, StoreEvent>({\n  ...UNIVERSAL_CHECKLIST_STORE_OPTIONS,\n});\n\nexport const checklistStore = createChecklistStore(mockUniversalChecklistStore);\n"
  },
  {
    "path": "code/core/src/manager-api/stores/__mocks__/status.ts",
    "content": "import { createStatusStore } from '../../../shared/status-store/index.ts';\nimport { UNIVERSAL_STATUS_STORE_OPTIONS } from '../../../shared/status-store/index.ts';\nimport { useUniversalStore } from '../../../shared/universal-store/use-universal-store-manager.ts';\nimport { experimental_MockUniversalStore } from '../../index.mock.ts';\n\nconst mockStatusStore = createStatusStore({\n  universalStatusStore: new experimental_MockUniversalStore(UNIVERSAL_STATUS_STORE_OPTIONS),\n  useUniversalStore,\n  environment: 'manager',\n});\n\nexport const { fullStatusStore, getStatusStoreByTypeId, useStatusStore, universalStatusStore } =\n  mockStatusStore;\n"
  },
  {
    "path": "code/core/src/manager-api/stores/__mocks__/test-provider.ts",
    "content": "import { createTestProviderStore } from '../../../shared/test-provider-store/index.ts';\nimport { UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS } from '../../../shared/test-provider-store/index.ts';\nimport { useUniversalStore } from '../../../shared/universal-store/use-universal-store-manager.ts';\nimport { experimental_MockUniversalStore } from '../../index.mock.ts';\n\nconst mockTestProviderStore = createTestProviderStore({\n  universalTestProviderStore: new experimental_MockUniversalStore(\n    UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS\n  ),\n  useUniversalStore,\n});\n\nexport const {\n  fullTestProviderStore,\n  getTestProviderStoreById,\n  useTestProviderStore,\n  universalTestProviderStore,\n} = mockTestProviderStore;\n"
  },
  {
    "path": "code/core/src/manager-api/stores/checklist.ts",
    "content": "import {\n  type StoreEvent,\n  type StoreState,\n  createChecklistStore,\n} from '../../shared/checklist-store/index.ts';\nimport { UNIVERSAL_CHECKLIST_STORE_OPTIONS } from '../../shared/checklist-store/index.ts';\nimport { UniversalStore } from '../../shared/universal-store/index.ts';\n\nexport const universalChecklistStore = UniversalStore.create<StoreState, StoreEvent>({\n  ...UNIVERSAL_CHECKLIST_STORE_OPTIONS,\n  leader: globalThis.CONFIG_TYPE === 'PRODUCTION',\n});\n\nexport const checklistStore = createChecklistStore(universalChecklistStore);\n"
  },
  {
    "path": "code/core/src/manager-api/stores/status.ts",
    "content": "import { createStatusStore } from '../../shared/status-store/index.ts';\nimport { UNIVERSAL_STATUS_STORE_OPTIONS } from '../../shared/status-store/index.ts';\nimport { UniversalStore } from '../../shared/universal-store/index.ts';\nimport { useUniversalStore } from '../../shared/universal-store/use-universal-store-manager.ts';\n\nconst statusStore = createStatusStore({\n  universalStatusStore: UniversalStore.create({\n    ...UNIVERSAL_STATUS_STORE_OPTIONS,\n    leader: globalThis.CONFIG_TYPE === 'PRODUCTION',\n  }),\n  useUniversalStore,\n  environment: 'manager',\n});\n\nexport const { fullStatusStore, getStatusStoreByTypeId, useStatusStore, universalStatusStore } =\n  statusStore;\n"
  },
  {
    "path": "code/core/src/manager-api/stores/test-provider.ts",
    "content": "import { createTestProviderStore } from '../../shared/test-provider-store/index.ts';\nimport { UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS } from '../../shared/test-provider-store/index.ts';\nimport { UniversalStore } from '../../shared/universal-store/index.ts';\nimport { useUniversalStore } from '../../shared/universal-store/use-universal-store-manager.ts';\n\nconst testProviderStore = createTestProviderStore({\n  universalTestProviderStore: UniversalStore.create({\n    ...UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS,\n    leader: globalThis.CONFIG_TYPE === 'PRODUCTION',\n  }),\n  useUniversalStore,\n});\n\nexport const {\n  fullTestProviderStore,\n  getTestProviderStoreById,\n  useTestProviderStore,\n  universalTestProviderStore,\n} = testProviderStore;\n"
  },
  {
    "path": "code/core/src/manager-api/test-utils/store.ts",
    "content": "import type { State } from '../root.tsx';\nimport Store, { type Upstream } from '../store.ts';\n\n/** Store guaranteed not to read from storage, for testing purposes. */\nclass InMemoryStore extends Store {\n  constructor({ setState, getState }: Upstream) {\n    super({ allowPersistence: false, setState, getState });\n  }\n\n  getInitialState(base: State) {\n    return base;\n  }\n}\n\n/**\n * Factory function to create a valid Store instance for testing purposes. Provides a simple\n * in-memory store without persistence logic. Useful for mocking the store in stories.\n *\n * @param initialState - The initial state for the store\n * @param onChange - Optional callback invoked whenever state changes\n * @returns A Store instance configured for testing\n */\nexport function createTestingStore(\n  initialState: State,\n  onChange?: (internalState: State) => void\n): Store {\n  let internalState = { ...initialState };\n\n  const upstream = {\n    allowPersistence: false,\n    getState: () => internalState,\n    setState: (patch: any, callback?: any) => {\n      if (typeof patch === 'function') {\n        internalState = { ...internalState, ...patch(internalState) };\n      } else {\n        internalState = { ...internalState, ...patch };\n      }\n      if (callback && typeof callback === 'function') {\n        callback(internalState);\n      }\n      if (onChange) {\n        onChange(internalState);\n      }\n    },\n  };\n\n  return new InMemoryStore(upstream);\n}\n"
  },
  {
    "path": "code/core/src/manager-api/tests/addons.test.js",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { Addon_TypesEnum as types } from 'storybook/internal/types';\n\nimport { init as initAddons } from '../modules/addons';\n\nconst PANELS = {\n  a11y: {\n    title: 'Accessibility',\n    paramKey: 'a11y',\n  },\n  actions: {\n    title: 'Actions',\n    paramKey: 'actions',\n  },\n  knobs: {\n    title: 'Knobs',\n    paramKey: 'knobs',\n  },\n};\n\nconst TEST_PROVIDERS = {\n  'storybook/test/test-provider': {\n    id: 'storybook/test/test-provider',\n    title: 'Component tests',\n  },\n};\n\nconst provider = {\n  getElements(type) {\n    if (type === types.PANEL) {\n      return PANELS;\n    }\n    if (type === types.experimental_TEST_PROVIDER) {\n      return TEST_PROVIDERS;\n    }\n    return null;\n  },\n};\n\nconst store = {\n  getState: () => ({\n    selectedPanel: '',\n  }),\n  setState: vi.fn(),\n};\n\ndescribe('Addons API', () => {\n  describe('#getElements', () => {\n    it('should return provider elements', () => {\n      const { api } = initAddons({ provider, store });\n\n      const panels = api.getElements(types.PANEL);\n      expect(panels).toBe(PANELS);\n\n      const testProviders = api.getElements(types.experimental_TEST_PROVIDER);\n      expect(testProviders).toBe(TEST_PROVIDERS);\n    });\n  });\n\n  describe('#getSelectedPanel', () => {\n    it('should return provider panels', () => {\n      // given\n      const storeWithSelectedPanel = {\n        getState: () => ({\n          selectedPanel: 'actions',\n        }),\n        setState: vi.fn(),\n      };\n      const { api } = initAddons({ provider, store: storeWithSelectedPanel });\n\n      // when\n      const selectedPanel = api.getSelectedPanel();\n\n      // then\n      expect(selectedPanel).toBe('actions');\n    });\n\n    it('should return first panel when selected is not a panel', () => {\n      // given\n      const storeWithSelectedPanel = {\n        getState: () => ({\n          selectedPanel: 'unknown',\n        }),\n        setState: vi.fn(),\n      };\n      const { api } = initAddons({ provider, store: storeWithSelectedPanel });\n\n      // when\n      const selectedPanel = api.getSelectedPanel();\n\n      // then\n      expect(selectedPanel).toBe('a11y');\n    });\n  });\n\n  describe('#setSelectedPanel', () => {\n    it('should set value inn store', () => {\n      // given\n      const setState = vi.fn();\n      const storeWithSelectedPanel = {\n        getState: () => ({\n          selectedPanel: 'actions',\n        }),\n        setState,\n      };\n      const { api } = initAddons({ provider, store: storeWithSelectedPanel });\n      expect(setState).not.toHaveBeenCalled();\n\n      // when\n      api.setSelectedPanel('knobs');\n\n      // then\n      expect(setState).toHaveBeenCalledWith({ selectedPanel: 'knobs' }, { persistence: 'session' });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager-api/tests/events.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { getEventMetadata } from '../lib/events.ts';\nimport type { API } from '../root.tsx';\n\nvi.mock('@storybook/global', () => ({\n  global: {\n    location: { origin: 'http://localhost:6006', pathname: '/' },\n  },\n}));\n\ndescribe('getEventMetadata', () => {\n  const fullAPIMock = { findRef: vi.fn(), getRefs: vi.fn() };\n  const fullAPI = fullAPIMock as unknown as API;\n\n  it('returns local if the event source is the same current location', () => {\n    expect(\n      getEventMetadata({ type: 'event', source: 'http://localhost:6006' }, fullAPI)\n    ).toMatchObject({\n      sourceType: 'local',\n    });\n  });\n\n  it('returns external if the refId is set', () => {\n    fullAPIMock.getRefs.mockReset().mockReturnValue({\n      ref: { id: 'ref' },\n    });\n\n    expect(\n      getEventMetadata(\n        { type: 'event', source: 'http://localhost:6006/foo/bar', refId: 'ref' },\n        fullAPI\n      )\n    ).toMatchObject({\n      sourceType: 'external',\n      ref: { id: 'ref' },\n    });\n  });\n\n  it('returns external if the source is set to something other and ref is unset (SB5)', () => {\n    fullAPIMock.findRef.mockReset().mockReturnValue({ id: 'ref' });\n\n    expect(\n      getEventMetadata({ type: 'event', source: 'http://storybook.host' }, fullAPI)\n    ).toMatchObject({\n      sourceType: 'external',\n      ref: { id: 'ref' },\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager-api/tests/globals.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { logger as _logger } from 'storybook/internal/client-logger';\nimport {\n  GLOBALS_UPDATED,\n  SET_GLOBALS,\n  SET_STORIES,\n  UPDATE_GLOBALS,\n} from 'storybook/internal/core-events';\nimport type { GlobalsUpdatedPayload, SetGlobalsPayload } from 'storybook/internal/types';\n\nimport { EventEmitter } from 'events';\n\nimport { getEventMetadata as _getEventData } from '../lib/events.ts';\nimport type { ModuleArgs } from '../lib/types.tsx';\nimport type { SubAPI } from '../modules/globals.ts';\nimport { init as initModule } from '../modules/globals.ts';\nimport type { API } from '../root.tsx';\n\nconst getEventMetadata = vi.mocked(_getEventData, true);\nconst logger = vi.mocked(_logger, true);\n\nvi.mock('storybook/internal/client-logger');\nvi.mock('../lib/events');\nbeforeEach(() => {\n  getEventMetadata.mockReset().mockReturnValue({ sourceType: 'local' } as any);\n});\n\nfunction createMockStore() {\n  let state = {};\n  return {\n    getState: vi.fn().mockImplementation(() => state),\n    setState: vi.fn().mockImplementation((s) => {\n      state = { ...state, ...s };\n    }),\n  };\n}\n\ndescribe('globals API', () => {\n  it('sets a sensible initialState', () => {\n    const store = createMockStore();\n    const channel = new EventEmitter();\n    const { state } = initModule({ store, provider: { channel } } as unknown as ModuleArgs);\n\n    expect(state).toEqual({\n      userGlobals: {},\n      storyGlobals: {},\n      globals: {},\n      globalTypes: {},\n    });\n  });\n\n  it('set global args on SET_GLOBALS', () => {\n    const channel = new EventEmitter();\n    const store = createMockStore();\n    const { state } = initModule({\n      store,\n      provider: { channel },\n    } as unknown as ModuleArgs);\n    store.setState(state);\n\n    channel.emit(SET_GLOBALS, {\n      globals: { a: 'b' },\n      globalTypes: { a: {} },\n    } satisfies SetGlobalsPayload);\n    expect(store.getState()).toEqual({\n      userGlobals: { a: 'b' },\n      storyGlobals: {},\n      globals: { a: 'b' },\n      globalTypes: { a: {} },\n    });\n  });\n\n  it('emits UPDATE_GLOBALS if retains a user globals value different to what receives on SET_GLOBALS', () => {\n    const channel = new EventEmitter();\n    const listener = vi.fn();\n    channel.on(UPDATE_GLOBALS, listener);\n\n    const store = createMockStore();\n    const { state } = initModule({\n      store,\n      provider: { channel },\n    } as unknown as ModuleArgs);\n    store.setState({\n      ...state,\n      userGlobals: { a: 'c' },\n      globals: { a: 'c' },\n    });\n\n    channel.emit(SET_GLOBALS, {\n      globals: { a: 'b' },\n      globalTypes: { a: {} },\n    } satisfies SetGlobalsPayload);\n    expect(store.getState()).toEqual({\n      userGlobals: { a: 'b' },\n      storyGlobals: {},\n      globals: { a: 'b' },\n      globalTypes: { a: {} },\n    });\n\n    expect(listener).toHaveBeenCalledWith({\n      globals: { a: 'c' },\n      options: { target: 'storybook-preview-iframe' },\n    });\n  });\n\n  it('does not push story globals to preview when SET_GLOBALS fires with empty globals', () => {\n    const channel = new EventEmitter();\n    const listener = vi.fn();\n    channel.on(UPDATE_GLOBALS, listener);\n\n    const store = createMockStore();\n    const { state } = initModule({\n      store,\n      provider: { channel },\n    } as unknown as ModuleArgs);\n    store.setState({\n      ...state,\n      userGlobals: {},\n      storyGlobals: { viewport: 'mobile1' },\n      globals: { viewport: 'mobile1' },\n    });\n\n    channel.emit(SET_GLOBALS, {\n      globals: {},\n      globalTypes: {},\n    } satisfies SetGlobalsPayload);\n\n    expect(listener).not.toHaveBeenCalled();\n  });\n\n  it('ignores SET_STORIES from other refs', () => {\n    const channel = new EventEmitter();\n    const api = { findRef: vi.fn() };\n    const store = createMockStore();\n    const { state } = initModule({\n      store,\n      fullAPI: api,\n      provider: { channel },\n    } as unknown as ModuleArgs);\n    store.setState(state);\n\n    getEventMetadata.mockReturnValueOnce({ sourceType: 'external', ref: { id: 'ref' } } as any);\n    channel.emit(SET_STORIES, { globals: { a: 'b' } });\n    expect(store.getState()).toEqual({\n      userGlobals: {},\n      storyGlobals: {},\n      globals: {},\n      globalTypes: {},\n    });\n  });\n\n  it('ignores SET_GLOBALS from other refs', () => {\n    const api = { findRef: vi.fn() };\n    const channel = new EventEmitter();\n    const store = createMockStore();\n    const { state } = initModule({\n      store,\n      fullAPI: api,\n      provider: { channel },\n    } as unknown as ModuleArgs);\n    store.setState(state);\n\n    getEventMetadata.mockReturnValueOnce({ sourceType: 'external', ref: { id: 'ref' } } as any);\n    channel.emit(SET_GLOBALS, {\n      globals: { a: 'b' },\n      globalTypes: { a: {} },\n    } satisfies SetGlobalsPayload);\n    expect(store.getState()).toEqual({\n      userGlobals: {},\n      storyGlobals: {},\n      globals: {},\n      globalTypes: {},\n    });\n  });\n\n  it('updates the state when the preview emits GLOBALS_UPDATED', () => {\n    const channel = new EventEmitter();\n    const api = { findRef: vi.fn() };\n    const store = createMockStore();\n    const { state } = initModule({\n      store,\n      fullAPI: api,\n      provider: { channel },\n    } as unknown as ModuleArgs);\n    store.setState(state);\n\n    channel.emit(GLOBALS_UPDATED, {\n      initialGlobals: { a: 'b' },\n      userGlobals: { a: 'b' },\n      storyGlobals: {},\n      globals: { a: 'b' },\n    } satisfies GlobalsUpdatedPayload);\n    expect(store.getState()).toEqual({\n      userGlobals: { a: 'b' },\n      storyGlobals: {},\n      globals: { a: 'b' },\n      globalTypes: {},\n    });\n\n    channel.emit(GLOBALS_UPDATED, {\n      initialGlobals: { a: 'b' },\n      userGlobals: { a: 'c' },\n      storyGlobals: {},\n      globals: { a: 'c' },\n    } satisfies GlobalsUpdatedPayload);\n    expect(store.getState()).toEqual({\n      userGlobals: { a: 'c' },\n      storyGlobals: {},\n      globals: { a: 'c' },\n      globalTypes: {},\n    });\n\n    // SHOULD NOT merge globals\n    channel.emit(GLOBALS_UPDATED, {\n      initialGlobals: { a: 'b' },\n      userGlobals: { d: 'e' },\n      storyGlobals: {},\n      globals: { d: 'e' },\n    } satisfies GlobalsUpdatedPayload);\n    expect(store.getState()).toEqual({\n      userGlobals: { d: 'e' },\n      storyGlobals: {},\n      globals: { d: 'e' },\n      globalTypes: {},\n    });\n  });\n\n  it('ignores GLOBALS_UPDATED from other refs', () => {\n    const channel = new EventEmitter();\n    const api = { findRef: vi.fn() };\n    const store = createMockStore();\n    const { state } = initModule({\n      store,\n      fullAPI: api,\n      provider: { channel },\n    } as unknown as ModuleArgs);\n    store.setState(state);\n\n    getEventMetadata.mockReturnValueOnce({ sourceType: 'external', ref: { id: 'ref' } } as any);\n    logger.warn.mockClear();\n    channel.emit(GLOBALS_UPDATED, {\n      initialGlobals: { a: 'b' },\n      userGlobals: { a: 'b' },\n      storyGlobals: {},\n      globals: { a: 'b' },\n    } satisfies GlobalsUpdatedPayload);\n    expect(store.getState()).toEqual({\n      userGlobals: {},\n      storyGlobals: {},\n      globals: {},\n      globalTypes: {},\n    });\n    expect(logger.warn).toHaveBeenCalled();\n  });\n\n  it('emits UPDATE_GLOBALS when updateGlobals is called', () => {\n    const channel = new EventEmitter();\n    const fullAPI = {} as unknown as API;\n    const store = createMockStore();\n    const listener = vi.fn();\n    channel.on(UPDATE_GLOBALS, listener);\n\n    const { api } = initModule({ store, fullAPI, provider: { channel } } as unknown as ModuleArgs);\n    (api as SubAPI).updateGlobals({ a: 'b' });\n\n    expect(listener).toHaveBeenCalledWith({\n      globals: { a: 'b' },\n      options: { target: 'storybook-preview-iframe' },\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager-api/tests/intersect.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport intersect from '../lib/intersect.ts';\n\ndescribe('Manager API utilities - intersect', () => {\n  it('returns identity when intersecting identity', () => {\n    const a = ['foo', 'bar'];\n    expect(intersect(a, a)).toEqual(a);\n  });\n\n  it('returns a when b is a superset of a', () => {\n    const a = ['foo', 'bar'];\n    const b = ['a', 'foo', 'b', 'bar', 'c', 'ter'];\n    expect(intersect(a, b)).toEqual(a);\n  });\n\n  it('returns b when a is a superset of b', () => {\n    const a = ['a', 'foo', 'b', 'bar', 'c', 'ter'];\n    const b = ['foo', 'bar'];\n    expect(intersect(a, b)).toEqual(b);\n  });\n\n  it('returns an intersection', () => {\n    const a = ['a', 'bar', 'b', 'c'];\n    const b = ['foo', 'bar', 'ter'];\n    expect(intersect(a, b)).toEqual(['bar']);\n  });\n\n  it('returns an empty set when there is no overlap', () => {\n    const a = ['a', 'b', 'c'];\n    const b = ['foo', 'bar', 'ter'];\n    expect(intersect(a, b)).toEqual([]);\n  });\n\n  it('returns an empty set if a is undefined', () => {\n    const b = ['foo', 'bar', 'ter'];\n    expect(intersect(undefined as unknown as [], b)).toEqual([]);\n  });\n\n  it('returns an empty set if b is undefined', () => {\n    const a = ['foo', 'bar', 'ter'];\n    expect(intersect(a, undefined as unknown as [])).toEqual([]);\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager-api/tests/layout.test.ts",
    "content": "import type { Mock } from 'vitest';\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { API_Provider } from 'storybook/internal/types';\n\nimport EventEmitter from 'events';\nimport { themes } from 'storybook/theming';\n\nimport type { ModuleArgs } from '../lib/types.tsx';\nimport type { SubState as AddonsSubState } from '../modules/addons.ts';\nimport type { SubAPI, SubState } from '../modules/layout.ts';\nimport { getDefaultLayoutState, init as initLayout } from '../modules/layout.ts';\nimport type { API, State } from '../root.tsx';\nimport type Store from '../store.ts';\n\ndescribe('layout API', () => {\n  let layoutApi: SubAPI;\n  let store: Store;\n  let provider: API_Provider<API>;\n  let currentState: SubState & {\n    selectedPanel: AddonsSubState['selectedPanel'];\n    singleStory?: boolean;\n  };\n\n  beforeEach(() => {\n    currentState = {\n      ...getDefaultLayoutState(),\n      selectedPanel: 'storybook/internal/action/panel',\n      theme: themes.light,\n      singleStory: false,\n    };\n    store = {\n      getState: () => currentState as unknown as State,\n      setState: vi.fn(async (patch) => {\n        currentState = {\n          ...currentState,\n          ...(typeof patch === 'function' ? patch(currentState as unknown as State) : patch),\n        };\n        return currentState as unknown as State;\n      }),\n    } as unknown as Store;\n    provider = {\n      getConfig: vi.fn(() => ({})),\n      channel: new EventEmitter(),\n    } as unknown as API_Provider<API>;\n    layoutApi = initLayout({\n      store,\n      provider,\n      singleStory: false,\n    } as unknown as ModuleArgs).api;\n  });\n\n  describe('toggleFullscreen', () => {\n    it('should toggle fullscreen', () => {\n      // start not in fullscreen\n      expect(currentState.layout.navSize).toBeGreaterThan(0);\n      expect(currentState.layout.bottomPanelHeight).toBeGreaterThan(0);\n      expect(currentState.layout.rightPanelWidth).toBeGreaterThan(0);\n\n      layoutApi.toggleFullscreen();\n\n      // now in fullscreen\n      expect(currentState.layout.navSize).toBe(0);\n      expect(currentState.layout.bottomPanelHeight).toBe(0);\n      expect(currentState.layout.rightPanelWidth).toBe(0);\n\n      layoutApi.toggleFullscreen();\n\n      // back to not in fullscreen\n      expect(currentState.layout.navSize).toBeGreaterThan(0);\n      expect(currentState.layout.bottomPanelHeight).toBeGreaterThan(0);\n      expect(currentState.layout.rightPanelWidth).toBeGreaterThan(0);\n    });\n    it('should toggle fullscreen to recent visible sizes', () => {\n      // start not in fullscreen\n      expect(currentState.layout.navSize).toBe(300);\n      expect(currentState.layout.bottomPanelHeight).toBe(300);\n      expect(currentState.layout.rightPanelWidth).toBe(400);\n\n      layoutApi.setSizes({\n        navSize: 100,\n        bottomPanelHeight: 200,\n        rightPanelWidth: 250,\n      });\n\n      layoutApi.toggleFullscreen();\n\n      // now in fullscreen\n      expect(currentState.layout.navSize).toBe(0);\n      expect(currentState.layout.bottomPanelHeight).toBe(0);\n      expect(currentState.layout.rightPanelWidth).toBe(0);\n\n      layoutApi.toggleFullscreen();\n\n      // back to recent visible sizes, not default size\n      expect(currentState.layout.navSize).toBe(100);\n      expect(currentState.layout.bottomPanelHeight).toBe(200);\n      expect(currentState.layout.rightPanelWidth).toBe(250);\n    });\n    it('should toggle fullscreen with argument', () => {\n      // start not in fullscreen\n      expect(currentState.layout.navSize).toBeGreaterThan(0);\n      expect(currentState.layout.bottomPanelHeight).toBeGreaterThan(0);\n      expect(currentState.layout.rightPanelWidth).toBeGreaterThan(0);\n\n      layoutApi.toggleFullscreen(false);\n\n      // nothing should change\n      expect(currentState.layout.navSize).toBeGreaterThan(0);\n      expect(currentState.layout.bottomPanelHeight).toBeGreaterThan(0);\n      expect(currentState.layout.rightPanelWidth).toBeGreaterThan(0);\n\n      layoutApi.toggleFullscreen(true);\n\n      // now in fullscreen\n      expect(currentState.layout.navSize).toBe(0);\n      expect(currentState.layout.bottomPanelHeight).toBe(0);\n      expect(currentState.layout.rightPanelWidth).toBe(0);\n\n      // nothing should change\n      layoutApi.toggleFullscreen(true);\n\n      expect(currentState.layout.navSize).toBe(0);\n      expect(currentState.layout.bottomPanelHeight).toBe(0);\n      expect(currentState.layout.rightPanelWidth).toBe(0);\n\n      layoutApi.toggleFullscreen(false);\n\n      // now out of fullscreen\n      expect(currentState.layout.navSize).toBeGreaterThan(0);\n      expect(currentState.layout.bottomPanelHeight).toBeGreaterThan(0);\n      expect(currentState.layout.rightPanelWidth).toBeGreaterThan(0);\n    });\n    it('should toggle fullscreen when nav is hidden', () => {\n      layoutApi.toggleNav(false);\n      // start not in fullscreen\n      expect(currentState.layout.navSize).toBe(0);\n      expect(currentState.layout.bottomPanelHeight).toBeGreaterThan(0);\n      expect(currentState.layout.rightPanelWidth).toBeGreaterThan(0);\n\n      layoutApi.toggleFullscreen();\n\n      // now in fullscreen\n      expect(currentState.layout.navSize).toBe(0); // unchanged\n      expect(currentState.layout.bottomPanelHeight).toBe(0);\n      expect(currentState.layout.rightPanelWidth).toBe(0);\n\n      layoutApi.toggleFullscreen();\n\n      // now out of fullscreen\n      expect(currentState.layout.navSize).toBeGreaterThan(0); // shown\n      expect(currentState.layout.bottomPanelHeight).toBeGreaterThan(0);\n      expect(currentState.layout.rightPanelWidth).toBeGreaterThan(0);\n    });\n    it('should toggle fullscreen when panel is hidden', () => {\n      layoutApi.togglePanel(false);\n      // start not in fullscreen\n      expect(currentState.layout.navSize).toBeGreaterThan(0);\n      expect(currentState.layout.bottomPanelHeight).toBe(0);\n      expect(currentState.layout.rightPanelWidth).toBe(0);\n\n      layoutApi.toggleFullscreen();\n\n      // now in fullscreen\n      expect(currentState.layout.navSize).toBe(0); // unchanged\n      expect(currentState.layout.bottomPanelHeight).toBe(0);\n      expect(currentState.layout.rightPanelWidth).toBe(0);\n\n      layoutApi.toggleFullscreen();\n\n      // now out of fullscreen\n      expect(currentState.layout.navSize).toBeGreaterThan(0); // shown\n      expect(currentState.layout.bottomPanelHeight).toBeGreaterThan(0);\n      expect(currentState.layout.rightPanelWidth).toBeGreaterThan(0);\n    });\n    it('should NOT show nav when disabling fullscreen with singleStory=true', () => {\n      store.setState((current) => ({\n        singleStory: true,\n        layout: { ...current.layout, navSize: 0 },\n      }));\n      layoutApi = initLayout({ store, provider, singleStory: true } as unknown as ModuleArgs).api;\n\n      // start not in fullscreen, nav hidden\n      expect(currentState.layout.navSize).toBe(0);\n      expect(currentState.layout.bottomPanelHeight).toBeGreaterThan(0);\n      expect(currentState.layout.rightPanelWidth).toBeGreaterThan(0);\n\n      layoutApi.toggleFullscreen();\n\n      // now in fullscreen\n      expect(currentState.layout.navSize).toBe(0);\n      expect(currentState.layout.bottomPanelHeight).toBe(0);\n      expect(currentState.layout.rightPanelWidth).toBe(0);\n\n      layoutApi.toggleFullscreen();\n\n      // back to not in fullscreen, nav still hidden\n      expect(currentState.layout.navSize).toBe(0);\n      expect(currentState.layout.bottomPanelHeight).toBeGreaterThan(0);\n      expect(currentState.layout.rightPanelWidth).toBeGreaterThan(0);\n    });\n  });\n\n  describe('toggleNav', () => {\n    it('should toggle navigation', () => {\n      // start default, nav shown\n      expect(currentState.layout.navSize).toBeGreaterThan(0);\n\n      layoutApi.toggleNav();\n\n      expect(currentState.layout.navSize).toBe(0);\n\n      layoutApi.toggleNav();\n\n      expect(currentState.layout.navSize).toBeGreaterThan(0);\n    });\n    it('should toggle navigation with argument', () => {\n      // start default, nav shown\n      expect(currentState.layout.navSize).toBeGreaterThan(0);\n\n      layoutApi.toggleNav(true);\n\n      // nothing should change\n      expect(currentState.layout.navSize).toBeGreaterThan(0);\n\n      layoutApi.toggleNav(false);\n\n      // should hide nav\n      expect(currentState.layout.navSize).toBe(0);\n\n      layoutApi.toggleNav(false);\n\n      // nothing should change\n      expect(currentState.layout.navSize).toBe(0);\n\n      layoutApi.toggleNav(true);\n\n      // should show nav\n      expect(currentState.layout.navSize).toBeGreaterThan(0);\n    });\n    it('should toggle navigation to recent visible size', () => {\n      // start default, nav shown\n      expect(currentState.layout.navSize).toBe(300);\n\n      layoutApi.setSizes({\n        navSize: 100,\n      });\n\n      layoutApi.toggleNav();\n\n      expect(currentState.layout.navSize).toBe(0);\n\n      layoutApi.toggleNav();\n\n      expect(currentState.layout.navSize).toBe(100);\n    });\n    it('should NOT toggle navigation when singleStory=true', () => {\n      store.setState((current) => ({\n        singleStory: true,\n        layout: { ...current.layout, navSize: 0 },\n      }));\n      layoutApi = initLayout({ store, provider, singleStory: true } as unknown as ModuleArgs).api;\n\n      layoutApi.toggleNav();\n      expect(currentState.layout.navSize).toBe(0);\n    });\n  });\n\n  describe('togglePanel', () => {\n    it('should toggle panel', () => {\n      // start default, panel shown\n      expect(currentState.layout.rightPanelWidth).toBeGreaterThan(0);\n      expect(currentState.layout.bottomPanelHeight).toBeGreaterThan(0);\n\n      layoutApi.togglePanel();\n\n      expect(currentState.layout.rightPanelWidth).toBe(0);\n      expect(currentState.layout.bottomPanelHeight).toBe(0);\n\n      layoutApi.togglePanel();\n\n      expect(currentState.layout.rightPanelWidth).toBeGreaterThan(0);\n      expect(currentState.layout.bottomPanelHeight).toBeGreaterThan(0);\n    });\n    it('should toggle panel with argument', () => {\n      // start default, panel shown\n      expect(currentState.layout.bottomPanelHeight).toBeGreaterThan(0);\n      expect(currentState.layout.rightPanelWidth).toBeGreaterThan(0);\n\n      layoutApi.togglePanel(true);\n\n      // nothing should change\n      expect(currentState.layout.bottomPanelHeight).toBeGreaterThan(0);\n      expect(currentState.layout.rightPanelWidth).toBeGreaterThan(0);\n\n      layoutApi.togglePanel(false);\n\n      // should hide panel\n      expect(currentState.layout.bottomPanelHeight).toBe(0);\n      expect(currentState.layout.rightPanelWidth).toBe(0);\n\n      layoutApi.togglePanel(false);\n\n      // nothing should change\n      expect(currentState.layout.bottomPanelHeight).toBe(0);\n      expect(currentState.layout.rightPanelWidth).toBe(0);\n\n      layoutApi.togglePanel(true);\n\n      // should show panel\n      expect(currentState.layout.bottomPanelHeight).toBeGreaterThan(0);\n      expect(currentState.layout.rightPanelWidth).toBeGreaterThan(0);\n    });\n    it('should toggle to recent visible size', () => {\n      // start default, panel shown\n      expect(currentState.layout.rightPanelWidth).toBe(400);\n      expect(currentState.layout.bottomPanelHeight).toBe(300);\n\n      layoutApi.setSizes({\n        rightPanelWidth: 350,\n        bottomPanelHeight: 250,\n      });\n\n      layoutApi.togglePanel();\n\n      expect(currentState.layout.rightPanelWidth).toBe(0);\n      expect(currentState.layout.bottomPanelHeight).toBe(0);\n\n      layoutApi.togglePanel();\n\n      // should show panel with recent visible size, not default size\n      expect(currentState.layout.rightPanelWidth).toBe(350);\n      expect(currentState.layout.bottomPanelHeight).toBe(250);\n    });\n  });\n\n  describe('togglePanelPosition', () => {\n    it('should toggle panel position', () => {\n      // start default, panel on the bottom\n      expect(currentState.layout.panelPosition).toBe('bottom');\n\n      layoutApi.togglePanelPosition();\n\n      expect(currentState.layout.panelPosition).toBe('right');\n\n      layoutApi.togglePanelPosition();\n\n      expect(currentState.layout.panelPosition).toBe('bottom');\n    });\n    it('should toggle panel position with argument', () => {\n      // start default, panel on the bottom\n      expect(currentState.layout.panelPosition).toBe('bottom');\n\n      layoutApi.togglePanelPosition('bottom');\n\n      // nothing should change\n      expect(currentState.layout.panelPosition).toBe('bottom');\n\n      layoutApi.togglePanelPosition('right');\n\n      // move to the right\n      expect(currentState.layout.panelPosition).toBe('right');\n\n      layoutApi.togglePanelPosition('right');\n\n      // nothing should change\n      expect(currentState.layout.panelPosition).toBe('right');\n\n      layoutApi.togglePanelPosition('bottom');\n\n      // move to the bottom\n      expect(currentState.layout.panelPosition).toBe('bottom');\n    });\n  });\n\n  describe('setSizes', () => {\n    it('should set all sizes', () => {\n      // start default\n      expect(currentState.layout.navSize).toBe(300);\n      expect(currentState.layout.bottomPanelHeight).toBe(300);\n      expect(currentState.layout.rightPanelWidth).toBe(400);\n\n      layoutApi.setSizes({\n        navSize: 100,\n        bottomPanelHeight: 200,\n        rightPanelWidth: 300,\n      });\n\n      expect(currentState.layout.navSize).toBe(100);\n      expect(currentState.layout.bottomPanelHeight).toBe(200);\n      expect(currentState.layout.rightPanelWidth).toBe(300);\n    });\n    it('should set a subset of sizes', () => {\n      // start default\n      expect(currentState.layout.navSize).toBe(300);\n      expect(currentState.layout.bottomPanelHeight).toBe(300);\n      expect(currentState.layout.rightPanelWidth).toBe(400);\n\n      layoutApi.setSizes({\n        navSize: 100,\n      });\n\n      expect(currentState.layout.navSize).toBe(100);\n      expect(currentState.layout.bottomPanelHeight).toBe(300); // unchanged\n      expect(currentState.layout.rightPanelWidth).toBe(400); // unchanged\n    });\n    it('should set recentVisibleSizes when setting sizes', () => {\n      // start default\n      expect(currentState.layout.navSize).toBe(300);\n      expect(currentState.layout.bottomPanelHeight).toBe(300);\n      expect(currentState.layout.rightPanelWidth).toBe(400);\n\n      expect(currentState.layout.recentVisibleSizes.navSize).toBe(300);\n      expect(currentState.layout.recentVisibleSizes.bottomPanelHeight).toBe(300);\n      expect(currentState.layout.recentVisibleSizes.rightPanelWidth).toBe(400);\n\n      layoutApi.setSizes({\n        navSize: 50,\n        bottomPanelHeight: 100,\n        rightPanelWidth: 150,\n      });\n\n      expect(currentState.layout.recentVisibleSizes.navSize).toBe(50);\n      expect(currentState.layout.recentVisibleSizes.bottomPanelHeight).toBe(100);\n      expect(currentState.layout.recentVisibleSizes.rightPanelWidth).toBe(150);\n\n      layoutApi.setSizes({\n        navSize: 0,\n        bottomPanelHeight: 0,\n        rightPanelWidth: 0,\n      });\n\n      // recent visible sizes should not change when being set to 0\n      expect(currentState.layout.recentVisibleSizes.navSize).toBe(50);\n      expect(currentState.layout.recentVisibleSizes.bottomPanelHeight).toBe(100);\n      expect(currentState.layout.recentVisibleSizes.rightPanelWidth).toBe(150);\n    });\n  });\n\n  describe('setOptions', () => {\n    const getLastSetStateArgs = () => {\n      const { calls } = (store.setState as Mock).mock;\n      return calls[calls.length - 1];\n    };\n\n    it('should not change selectedPanel if it is undefined in the options', () => {\n      layoutApi.setOptions({});\n\n      expect(getLastSetStateArgs()).toBeUndefined();\n    });\n\n    it('should not change selectedPanel if it is undefined in the options, but something else has changed', () => {\n      layoutApi.setOptions({ panelPosition: 'right' });\n\n      expect(getLastSetStateArgs()[0].selectedPanel).toBeUndefined();\n    });\n\n    it('should not change selectedPanel if it is currently the same', () => {\n      const panelName = currentState.selectedPanel;\n      layoutApi.setOptions({});\n      // second call is needed to overwrite initial layout\n      layoutApi.setOptions({ selectedPanel: panelName });\n\n      expect(getLastSetStateArgs()).toBeUndefined();\n    });\n\n    it('should not change selectedPanel if it is currently the same, but something else has changed', () => {\n      layoutApi.setOptions({});\n      // second call is needed to overwrite initial layout\n      layoutApi.setOptions({ panelPosition: 'right', selectedPanel: currentState.selectedPanel });\n\n      expect(getLastSetStateArgs()[0].selectedPanel).toBeUndefined();\n    });\n\n    it('should set selectedPanel initially', () => {\n      const panelName = 'storybook/a11y/panel';\n      layoutApi.setOptions({ selectedPanel: panelName });\n\n      expect(getLastSetStateArgs()[0].selectedPanel).toEqual(panelName);\n    });\n\n    it('should change selectedPanel if it is defined in the options and is different', () => {\n      const panelName = 'storybook/a11y/panel';\n      layoutApi.setOptions({});\n      layoutApi.setOptions({ selectedPanel: panelName });\n\n      expect(getLastSetStateArgs()[0].selectedPanel).toEqual(panelName);\n    });\n  });\n\n  describe('state getters', () => {\n    it('should get navShown with getIsNavShown', () => {\n      expect(layoutApi.getIsNavShown()).toBe(true);\n\n      layoutApi.toggleNav();\n\n      expect(layoutApi.getIsNavShown()).toBe(false);\n\n      layoutApi.toggleFullscreen();\n\n      expect(layoutApi.getIsNavShown()).toBe(false);\n\n      layoutApi.toggleFullscreen();\n\n      expect(layoutApi.getIsNavShown()).toBe(true);\n    });\n\n    it('should get panelShwon with getIsPanelShown', () => {\n      expect(layoutApi.getIsPanelShown()).toBe(true);\n\n      layoutApi.togglePanel();\n\n      expect(layoutApi.getIsPanelShown()).toBe(false);\n\n      layoutApi.toggleFullscreen();\n\n      expect(layoutApi.getIsPanelShown()).toBe(false);\n\n      layoutApi.toggleFullscreen();\n\n      expect(layoutApi.getIsPanelShown()).toBe(true);\n    });\n\n    it('should get fullscreen with getIsFullscreen', () => {\n      expect(layoutApi.getIsFullscreen()).toBe(false);\n\n      layoutApi.toggleNav();\n\n      // still not fullscreen\n      expect(layoutApi.getIsFullscreen()).toBe(false);\n\n      layoutApi.togglePanel();\n\n      // now it is fullscreen\n      expect(layoutApi.getIsFullscreen()).toBe(true);\n\n      layoutApi.toggleFullscreen();\n\n      // not fullscreen anymore\n      expect(layoutApi.getIsFullscreen()).toBe(false);\n    });\n  });\n\n  describe('focusOnUIElement', () => {\n    let mockActiveElement: any;\n    let mockGetElementById: ReturnType<typeof vi.fn>;\n    let focusLayoutApi: SubAPI;\n\n    beforeEach(async () => {\n      mockActiveElement = null;\n      mockGetElementById = vi.fn().mockReturnValue(null);\n\n      // Set up mock document on globalThis before re-importing layout module.\n      // @storybook/global resolves to globalThis in Node, so the layout module's\n      // `const { document } = global;` will capture this mock.\n      (globalThis as any).document = {\n        getElementById: mockGetElementById,\n        get activeElement() {\n          return mockActiveElement;\n        },\n      };\n\n      // Re-import the layout module so it captures our mock document\n      vi.resetModules();\n      const { init: freshInit } = await import('../modules/layout.ts');\n      focusLayoutApi = freshInit({\n        store,\n        provider,\n        singleStory: false,\n      } as unknown as ModuleArgs).api;\n    });\n\n    afterEach(() => {\n      delete (globalThis as any).document;\n      vi.restoreAllMocks();\n    });\n\n    const createMockElement = (id: string) => {\n      const element = {\n        id,\n        focus: vi.fn(() => {\n          mockActiveElement = element;\n        }),\n        select: vi.fn(),\n      };\n      mockGetElementById.mockImplementation((queryId: string) => (queryId === id ? element : null));\n      return element;\n    };\n\n    it('should return false when elementId is not provided', () => {\n      const result = focusLayoutApi.focusOnUIElement();\n      expect(result).toBe(false);\n    });\n\n    it('should return false when elementId is undefined', () => {\n      const result = focusLayoutApi.focusOnUIElement(undefined);\n      expect(result).toBe(false);\n    });\n\n    it('should return true and focus element when element exists', () => {\n      const element = createMockElement('test-element');\n      const result = focusLayoutApi.focusOnUIElement('test-element');\n      expect(result).toBe(true);\n      expect(element.focus).toHaveBeenCalled();\n    });\n\n    it('should return true and call select when select option is true (boolean form)', () => {\n      const element = createMockElement('test-element');\n      const result = focusLayoutApi.focusOnUIElement('test-element', true);\n      expect(result).toBe(true);\n      expect(element.focus).toHaveBeenCalled();\n      expect(element.select).toHaveBeenCalled();\n    });\n\n    it('should return true and call select when select option is true (object form)', () => {\n      const element = createMockElement('test-element');\n      const result = focusLayoutApi.focusOnUIElement('test-element', { select: true });\n      expect(result).toBe(true);\n      expect(element.focus).toHaveBeenCalled();\n      expect(element.select).toHaveBeenCalled();\n    });\n\n    it('should not call select when select option is false', () => {\n      const element = createMockElement('test-element');\n      const result = focusLayoutApi.focusOnUIElement('test-element', { select: false });\n      expect(result).toBe(true);\n      expect(element.focus).toHaveBeenCalled();\n      expect(element.select).not.toHaveBeenCalled();\n    });\n\n    it('should return false without polling when element does not exist and poll is false', () => {\n      const result = focusLayoutApi.focusOnUIElement('nonexistent-element', { poll: false });\n      expect(result).toBe(false);\n    });\n\n    it('should return a Promise when element does not exist and poll is true (default)', () => {\n      const result = focusLayoutApi.focusOnUIElement('nonexistent-element');\n      expect(result).toBeInstanceOf(Promise);\n    });\n\n    it('should resolve to true when element appears during polling', async () => {\n      vi.useFakeTimers();\n\n      const element = {\n        id: 'delayed-element',\n        focus: vi.fn(),\n        select: vi.fn(),\n      };\n\n      // Element not available initially\n      const result = focusLayoutApi.focusOnUIElement('delayed-element');\n      expect(result).toBeInstanceOf(Promise);\n\n      // Make element available and focusable\n      mockGetElementById.mockImplementation((id: string) =>\n        id === 'delayed-element' ? element : null\n      );\n      element.focus.mockImplementation(() => {\n        mockActiveElement = element;\n      });\n\n      await vi.advanceTimersByTimeAsync(150);\n      await expect(result).resolves.toBe(true);\n      expect(element.focus).toHaveBeenCalled();\n\n      vi.useRealTimers();\n    });\n\n    it('should resolve to false when element never appears during polling', async () => {\n      vi.useFakeTimers();\n\n      const result = focusLayoutApi.focusOnUIElement('never-appears');\n      expect(result).toBeInstanceOf(Promise);\n\n      await vi.advanceTimersByTimeAsync(600);\n      await expect(result).resolves.toBe(false);\n\n      vi.useRealTimers();\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager-api/tests/mockStoriesEntries.ts",
    "content": "import type { API_PreparedStoryIndex, StoryIndex } from 'storybook/internal/types';\n\nexport const mockEntries: StoryIndex['entries'] = {\n  'component-a--docs': {\n    type: 'docs',\n    id: 'component-a--docs',\n    title: 'Component A',\n    name: 'Docs',\n    importPath: './path/to/component-a.ts',\n    storiesImports: [],\n  },\n  'component-a--story-1': {\n    type: 'story',\n    subtype: 'story',\n    id: 'component-a--story-1',\n    title: 'Component A',\n    name: 'Story 1',\n    importPath: './path/to/component-a.ts',\n  },\n  'component-a--story-2': {\n    type: 'story',\n    subtype: 'story',\n    id: 'component-a--story-2',\n    title: 'Component A',\n    name: 'Story 2',\n    importPath: './path/to/component-a.ts',\n  },\n  'component-b--story-3': {\n    type: 'story',\n    subtype: 'story',\n    id: 'component-b--story-3',\n    title: 'Component B',\n    name: 'Story 3',\n    importPath: './path/to/component-b.ts',\n  },\n};\nexport const docsEntries: StoryIndex['entries'] = {\n  'component-a--page': {\n    type: 'story',\n    subtype: 'story',\n    id: 'component-a--page',\n    title: 'Component A',\n    name: 'Page',\n    importPath: './path/to/component-a.ts',\n  },\n  'component-a--story-2': {\n    type: 'story',\n    subtype: 'story',\n    id: 'component-a--story-2',\n    title: 'Component A',\n    name: 'Story 2',\n    importPath: './path/to/component-a.ts',\n  },\n  'component-b-docs': {\n    type: 'docs',\n    id: 'component-b--docs',\n    title: 'Component B',\n    name: 'Docs',\n    importPath: './path/to/component-b.ts',\n    storiesImports: [],\n  },\n  'component-c--story-4': {\n    type: 'story',\n    subtype: 'story',\n    id: 'component-c--story-4',\n    title: 'Component c',\n    name: 'Story 4',\n    importPath: './path/to/component-c.ts',\n  },\n};\nexport const navigationEntries: StoryIndex['entries'] = {\n  'a--1': {\n    type: 'story',\n    subtype: 'story',\n    title: 'a',\n    name: '1',\n    id: 'a--1',\n    importPath: './a.ts',\n  },\n  'a--2': {\n    type: 'story',\n    subtype: 'story',\n    title: 'a',\n    name: '2',\n    id: 'a--2',\n    importPath: './a.ts',\n  },\n  'b-c--1': {\n    type: 'story',\n    subtype: 'story',\n    title: 'b/c',\n    name: '1',\n    id: 'b-c--1',\n    importPath: './b/c.ts',\n  },\n  'b-d--1': {\n    type: 'story',\n    subtype: 'story',\n    title: 'b/d',\n    name: '1',\n    id: 'b-d--1',\n    importPath: './b/d.ts',\n  },\n  'b-d--2': {\n    type: 'story',\n    subtype: 'story',\n    title: 'b/d',\n    name: '2',\n    id: 'b-d--2',\n    importPath: './b/d.ts',\n  },\n  'custom-id--1': {\n    type: 'story',\n    subtype: 'story',\n    title: 'b/e',\n    name: '1',\n    id: 'custom-id--1',\n    importPath: './b/.ts',\n  },\n};\nexport const preparedEntries: API_PreparedStoryIndex['entries'] = {\n  'a--1': {\n    type: 'story',\n    subtype: 'story',\n    title: 'a',\n    name: '1',\n    parameters: {},\n    id: 'a--1',\n    args: { a: 'b' },\n    importPath: './a.ts',\n  },\n  'b--1': {\n    type: 'story',\n    subtype: 'story',\n    title: 'b',\n    name: '1',\n    parameters: {},\n    id: 'b--1',\n    args: { x: 'y' },\n    importPath: './b.ts',\n  },\n};\n"
  },
  {
    "path": "code/core/src/manager-api/tests/notifications.test.js",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { init as initNotifications } from '../modules/notifications';\n\ndescribe('notifications API', () => {\n  const store = {\n    state: { notifications: [] },\n    getState: () => store.state,\n    setState: (update) => {\n      if (typeof update === 'function') {\n        store.state = update(store.state);\n      } else {\n        store.state = update;\n      }\n    },\n  };\n\n  it('allows adding notifications', () => {\n    const { api } = initNotifications({ store });\n\n    api.addNotification({ id: '1' });\n    expect(store.getState()).toEqual({\n      notifications: [{ id: '1' }],\n    });\n  });\n\n  it('allows removing notifications', () => {\n    store.setState({ notifications: [{ id: '1' }, { id: '2' }, { id: '3' }] });\n    const { api } = initNotifications({ store });\n\n    api.clearNotification('2');\n    expect(store.getState()).toEqual({\n      notifications: [{ id: '1' }, { id: '3' }],\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager-api/tests/ref-mockdata.login-required.json",
    "content": "{\n  \"loginUrl\": \"https://example.com\"\n}\n"
  },
  {
    "path": "code/core/src/manager-api/tests/ref-mockdata.success.json",
    "content": "{\n  \"stories\": {\n    \"welcome--to-storybook\": {\n      \"id\": \"welcome--to-storybook\",\n      \"kind\": \"Welcome\",\n      \"name\": \"to Storybook\",\n      \"story\": \"to Storybook\",\n      \"parameters\": {}\n    },\n    \"button--text\": {\n      \"id\": \"button--text\",\n      \"kind\": \"Button\",\n      \"name\": \"Text\",\n      \"story\": \"Text\",\n      \"parameters\": {}\n    },\n    \"button--emoji\": {\n      \"id\": \"button--emoji\",\n      \"kind\": \"Button\",\n      \"name\": \"Emoji\",\n      \"story\": \"Emoji\",\n      \"parameters\": {}\n    }\n  }\n}\n"
  },
  {
    "path": "code/core/src/manager-api/tests/refs.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport type { StoryIndex } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { transformStoryIndexToStoriesHash } from '../lib/stories.ts';\nimport { getSourceType, init as initRefs } from '../modules/refs.ts';\nimport type { State } from '../root.tsx';\nimport type Store from '../store.ts';\n\nconst { fetch } = global;\n\nconst fetchMock = vi.mocked(fetch);\n\nvi.mock('@storybook/global', () => {\n  const globalMock = {\n    fetch: vi.fn(() => Promise.resolve({})),\n    REFS: {\n      fake: {\n        id: 'fake',\n        url: 'https://example.com',\n        title: 'Fake',\n      },\n    },\n  };\n  // Change global.location value to handle edge cases\n  // Add additional variations of global.location mock return values in this array.\n  // NOTE: The order must match the order that global.location is called in the unit tests.\n  const edgecaseLocations = [\n    { origin: 'https://storybook.js.org', pathname: '/storybook/iframe.html' },\n  ];\n  // global.location value after all edgecaseLocations are returned\n  const lastLocation = { origin: 'https://storybook.js.org', pathname: '/storybook/' };\n  const locationMock = vi.fn();\n  edgecaseLocations.forEach((location) => locationMock.mockReturnValueOnce(location));\n  locationMock.mockReturnValue(lastLocation);\n\n  Object.defineProperty(globalMock, 'location', {\n    get: locationMock,\n  });\n  return { global: globalMock };\n});\n\nconst provider = {\n  getConfig: vi.fn().mockReturnValue({}),\n};\n\nconst store = {\n  getState: vi.fn().mockReturnValue({\n    filters: {},\n    refs: {\n      fake: {\n        id: 'fake',\n        url: 'https://example.com',\n        title: 'Fake',\n      },\n    },\n  }),\n  setState: vi.fn((a: any) => {}),\n};\n\nfunction createMockStore(initialState: Partial<State> = {}) {\n  let state = initialState;\n  return {\n    getState: vi.fn(() => state),\n    setState: vi.fn((s: typeof state) => {\n      state = { ...state, ...s };\n      return Promise.resolve(state);\n    }),\n  } as any as Store;\n}\n\ninterface ResponseResult {\n  ok?: boolean;\n  status?: number;\n  err?: Error;\n  response?: () => never | object | Promise<object>;\n}\n\ntype ResponseKeys =\n  | 'indexPrivate'\n  | 'indexPublic'\n  | 'storiesPrivate'\n  | 'storiesPublic'\n  | 'iframe'\n  | 'metadata';\n\nfunction respond(result: ResponseResult): Promise<Response> {\n  const { err, ok, status, response } = result;\n  if (err) {\n    return Promise.reject(err);\n  }\n\n  return Promise.resolve({\n    ok: ok ?? !!response,\n    status: status ?? (ok ? 200 : 500),\n    json: response,\n  } as Response);\n}\n\nconst setupResponses = ({\n  indexPrivate,\n  indexPublic,\n  storiesPrivate,\n  storiesPublic,\n  iframe,\n  metadata,\n}: Partial<Record<ResponseKeys, ResponseResult>>) => {\n  fetchMock.mockClear();\n  store.setState.mockClear();\n\n  fetchMock.mockImplementation((l, o) => {\n    if (typeof l !== 'string') {\n      throw new Error('Wrong request type');\n    }\n\n    if (l.includes('index') && o?.credentials === 'include' && indexPrivate) {\n      return respond(indexPrivate);\n    }\n    if (l.includes('index') && o?.credentials === 'omit' && indexPublic) {\n      return respond(indexPublic);\n    }\n    if (l.includes('stories') && o?.credentials === 'include' && storiesPrivate) {\n      return respond(storiesPrivate);\n    }\n    if (l.includes('stories') && o?.credentials === 'omit' && storiesPublic) {\n      return respond(storiesPublic);\n    }\n    if (l.includes('iframe') && iframe) {\n      return respond(iframe);\n    }\n    if (l.includes('metadata') && metadata) {\n      return respond(metadata);\n    }\n    throw new Error(`Called URL ${l} without setting up mock`);\n  });\n};\n\ndescribe('Refs API', () => {\n  describe('getSourceType(source)', () => {\n    // These tests must be run first and in correct order.\n    // The order matches the \"edgecaseLocations\" order in the 'global' mock function above.\n    describe('edge cases', () => {\n      it('returns \"local\" when source matches location with /index.html in path', () => {\n        // mockReturnValue(edgecaseLocations[0])\n        expect(getSourceType('https://storybook.js.org/storybook/iframe.html')).toEqual([\n          'local',\n          'https://storybook.js.org/storybook',\n        ]);\n      });\n      it('returns \"correct url\" when source does not match location', () => {\n        expect(getSourceType('https://external.com/storybook/')).toEqual([\n          'external',\n          'https://external.com/storybook',\n        ]);\n      });\n    });\n    // Other tests use \"lastLocation\" for the 'global' mock\n    it('returns \"local\" when source matches location', () => {\n      expect(getSourceType('https://storybook.js.org/storybook/iframe.html')).toEqual([\n        'local',\n        'https://storybook.js.org/storybook',\n      ]);\n    });\n    it('returns \"external\" when source does not match location', () => {\n      expect(getSourceType('https://external.com/storybook/iframe.html')).toEqual([\n        'external',\n        'https://external.com/storybook',\n      ]);\n    });\n  });\n\n  describe('checkRef', () => {\n    it('on initialization it checks refs', async () => {\n      // given\n      initRefs({ provider, store } as any);\n\n      // the `runCheck` is async, so we need to wait for it to finish\n      await vi.waitFor(() => fetchMock.mock.calls.length > 0);\n\n      expect(fetchMock.mock.calls).toMatchInlineSnapshot(`\n        [\n          [\n            \"https://example.com/index.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/stories.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n        ]\n      `);\n    });\n\n    it('passes version when set on the ref', async () => {\n      // given\n      global.REFS = {\n        fake: {\n          id: 'fake',\n          url: 'https://example.com',\n          title: 'Fake',\n          version: '2.1.3-rc.2',\n        },\n      };\n      initRefs({ provider, store } as any);\n\n      // the `runCheck` is async, so we need to wait for it to finish\n      await vi.waitFor(() => fetchMock.mock.calls.length > 0);\n\n      expect(fetchMock.mock.calls).toMatchInlineSnapshot(`\n        [\n          [\n            \"https://example.com/index.json?version=2.1.3-rc.2\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/stories.json?version=2.1.3-rc.2\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n        ]\n      `);\n    });\n\n    it('checks refs (all fail)', async () => {\n      // given\n      const { api } = initRefs({ provider, store } as any, { runCheck: false });\n\n      setupResponses({\n        indexPrivate: {\n          ok: false,\n          response: async () => {\n            throw new Error('Failed to fetch');\n          },\n        },\n        storiesPrivate: {\n          ok: false,\n          response: async () => {\n            throw new Error('Failed to fetch');\n          },\n        },\n      });\n\n      await api.checkRef({\n        id: 'fake',\n        url: 'https://example.com',\n        title: 'Fake',\n      });\n\n      expect(fetchMock.mock.calls).toMatchInlineSnapshot(`\n        [\n          [\n            \"https://example.com/index.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/stories.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n        ]\n      `);\n\n      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`\n        {\n          \"refs\": {\n            \"fake\": {\n              \"filteredIndex\": undefined,\n              \"id\": \"fake\",\n              \"index\": undefined,\n              \"indexError\": {\n                \"message\": \"Error: Loading of ref failed\n          at fetch (lib/api/src/modules/refs.ts)\n\n        URL: https://example.com\n\n        We weren't able to load the above URL,\n        it's possible a CORS error happened.\n\n        Please check your dev-tools network tab.\",\n              },\n              \"internal_index\": undefined,\n              \"title\": \"Fake\",\n              \"type\": \"auto-inject\",\n              \"url\": \"https://example.com\",\n            },\n          },\n        }\n      `);\n    });\n\n    it('checks refs (all throw)', async () => {\n      // given\n      const { api } = initRefs({ provider, store } as any, { runCheck: false });\n\n      setupResponses({\n        indexPrivate: {\n          err: new Error('TypeError: Failed to fetch'),\n        },\n        storiesPrivate: {\n          err: new Error('TypeError: Failed to fetch'),\n        },\n      });\n\n      await api.checkRef({\n        id: 'fake',\n        url: 'https://example.com',\n        title: 'Fake',\n      });\n\n      expect(fetchMock.mock.calls).toMatchInlineSnapshot(`\n        [\n          [\n            \"https://example.com/index.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/stories.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n        ]\n      `);\n\n      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`\n        {\n          \"refs\": {\n            \"fake\": {\n              \"filteredIndex\": undefined,\n              \"id\": \"fake\",\n              \"index\": undefined,\n              \"indexError\": {\n                \"message\": \"Error: Loading of ref failed\n          at fetch (lib/api/src/modules/refs.ts)\n\n        URL: https://example.com\n\n        We weren't able to load the above URL,\n        it's possible a CORS error happened.\n\n        Please check your dev-tools network tab.\",\n              },\n              \"internal_index\": undefined,\n              \"title\": \"Fake\",\n              \"type\": \"auto-inject\",\n              \"url\": \"https://example.com\",\n            },\n          },\n        }\n      `);\n    });\n\n    it('checks refs (index throws)', async () => {\n      // given\n      const { api } = initRefs({ provider, store } as any, { runCheck: false });\n\n      setupResponses({\n        indexPrivate: {\n          err: new Error('TypeError: Failed to fetch'),\n        },\n        storiesPrivate: {\n          ok: true,\n          response: async () => ({ v: 3, stories: {} }),\n        },\n        metadata: {\n          ok: true,\n          response: async () => ({\n            versions: {},\n          }),\n        },\n      });\n\n      await api.checkRef({\n        id: 'fake',\n        url: 'https://example.com',\n        title: 'Fake',\n      });\n\n      expect(fetchMock.mock.calls).toMatchInlineSnapshot(`\n        [\n          [\n            \"https://example.com/index.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/stories.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/metadata.json\",\n            {\n              \"cache\": \"no-cache\",\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n        ]\n      `);\n    });\n\n    it('checks refs (metadata throws)', async () => {\n      // given\n      const { api } = initRefs({ provider, store } as any, { runCheck: false });\n\n      setupResponses({\n        indexPrivate: {\n          ok: true,\n          response: async () => ({ v: 5, entries: {} }),\n        },\n        storiesPrivate: {\n          ok: true,\n          response: async () => ({ v: 3, stories: {} }),\n        },\n        metadata: {\n          err: new Error('TypeError: Failed to fetch'),\n        },\n      });\n\n      await api.checkRef({\n        id: 'fake',\n        url: 'https://example.com',\n        title: 'Fake',\n      });\n\n      expect(fetchMock.mock.calls).toMatchInlineSnapshot(`\n        [\n          [\n            \"https://example.com/index.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/stories.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/metadata.json\",\n            {\n              \"cache\": \"no-cache\",\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n        ]\n      `);\n\n      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`\n        {\n          \"refs\": {\n            \"fake\": {\n              \"filteredIndex\": {},\n              \"id\": \"fake\",\n              \"index\": {},\n              \"internal_index\": {\n                \"entries\": {},\n                \"v\": 5,\n              },\n              \"title\": \"Fake\",\n              \"type\": \"lazy\",\n              \"url\": \"https://example.com\",\n            },\n          },\n        }\n      `);\n\n      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`\n        {\n          \"refs\": {\n            \"fake\": {\n              \"filteredIndex\": {},\n              \"id\": \"fake\",\n              \"index\": {},\n              \"internal_index\": {\n                \"entries\": {},\n                \"v\": 5,\n              },\n              \"title\": \"Fake\",\n              \"type\": \"lazy\",\n              \"url\": \"https://example.com\",\n            },\n          },\n        }\n      `);\n    });\n\n    it('checks refs (success)', async () => {\n      // given\n      const { api } = initRefs({ provider, store } as any, { runCheck: false });\n\n      setupResponses({\n        indexPrivate: {\n          ok: true,\n          response: async () => ({ v: 5, entries: {} }),\n        },\n        storiesPrivate: {\n          ok: true,\n          response: async () => ({ v: 3, stories: {} }),\n        },\n        metadata: {\n          ok: true,\n          response: async () => ({\n            versions: {},\n          }),\n        },\n      });\n\n      await api.checkRef({\n        id: 'fake',\n        url: 'https://example.com',\n        title: 'Fake',\n      });\n\n      expect(fetchMock.mock.calls).toMatchInlineSnapshot(`\n        [\n          [\n            \"https://example.com/index.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/stories.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/metadata.json\",\n            {\n              \"cache\": \"no-cache\",\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n        ]\n      `);\n\n      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`\n        {\n          \"refs\": {\n            \"fake\": {\n              \"filteredIndex\": {},\n              \"id\": \"fake\",\n              \"index\": {},\n              \"internal_index\": {\n                \"entries\": {},\n                \"v\": 5,\n              },\n              \"title\": \"Fake\",\n              \"type\": \"lazy\",\n              \"url\": \"https://example.com\",\n              \"versions\": {},\n            },\n          },\n        }\n      `);\n    });\n\n    it('checks refs (not replace versions)', async () => {\n      // given\n      const { api } = initRefs({ provider, store } as any, { runCheck: false });\n\n      setupResponses({\n        indexPrivate: {\n          ok: true,\n          response: async () => ({ v: 5, entries: {} }),\n        },\n        storiesPrivate: {\n          ok: true,\n          response: async () => ({ v: 3, stories: {} }),\n        },\n        metadata: {\n          ok: true,\n          response: async () => ({\n            versions: {},\n          }),\n        },\n      });\n\n      await api.checkRef({\n        id: 'fake',\n        url: 'https://example.com',\n        title: 'Fake',\n        versions: { a: 'http://example.com/a', b: 'http://example.com/b' },\n      });\n\n      expect(fetchMock.mock.calls).toMatchInlineSnapshot(`\n        [\n          [\n            \"https://example.com/index.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/stories.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/metadata.json\",\n            {\n              \"cache\": \"no-cache\",\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n        ]\n      `);\n\n      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`\n        {\n          \"refs\": {\n            \"fake\": {\n              \"filteredIndex\": {},\n              \"id\": \"fake\",\n              \"index\": {},\n              \"internal_index\": {\n                \"entries\": {},\n                \"v\": 5,\n              },\n              \"title\": \"Fake\",\n              \"type\": \"lazy\",\n              \"url\": \"https://example.com\",\n              \"versions\": {\n                \"a\": \"http://example.com/a\",\n                \"b\": \"http://example.com/b\",\n              },\n            },\n          },\n        }\n      `);\n    });\n\n    it('checks refs (auth)', async () => {\n      // given\n      const { api } = initRefs({ provider, store } as any, { runCheck: false });\n\n      setupResponses({\n        indexPrivate: {\n          ok: true,\n          response: async () => ({ loginUrl: 'https://example.com/login' }),\n        },\n        storiesPrivate: {\n          ok: true,\n          response: async () => ({ loginUrl: 'https://example.com/login' }),\n        },\n        metadata: {\n          ok: true,\n          response: async () => ({ loginUrl: 'https://example.com/login' }),\n        },\n      });\n\n      await api.checkRef({\n        id: 'fake',\n        url: 'https://example.com',\n        title: 'Fake',\n      });\n\n      expect(fetchMock.mock.calls).toMatchInlineSnapshot(`\n        [\n          [\n            \"https://example.com/index.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/stories.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/metadata.json\",\n            {\n              \"cache\": \"no-cache\",\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n        ]\n      `);\n\n      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`\n        {\n          \"refs\": {\n            \"fake\": {\n              \"filteredIndex\": undefined,\n              \"id\": \"fake\",\n              \"index\": undefined,\n              \"internal_index\": undefined,\n              \"loginUrl\": \"https://example.com/login\",\n              \"title\": \"Fake\",\n              \"type\": \"auto-inject\",\n              \"url\": \"https://example.com\",\n            },\n          },\n        }\n      `);\n    });\n\n    it('checks refs (auth with 401)', async () => {\n      // given\n      const { api } = initRefs({ provider, store } as any, { runCheck: false });\n\n      setupResponses({\n        indexPrivate: {\n          ok: false,\n          status: 401,\n          response: async () => ({ loginUrl: 'https://example.com/login' }),\n        },\n        storiesPrivate: {\n          ok: false,\n          status: 401,\n          response: async () => ({ loginUrl: 'https://example.com/login' }),\n        },\n        metadata: {\n          ok: false,\n          status: 401,\n          response: async () => ({ loginUrl: 'https://example.com/login' }),\n        },\n      });\n\n      await api.checkRef({\n        id: 'fake',\n        url: 'https://example.com',\n        title: 'Fake',\n      });\n\n      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`\n        {\n          \"refs\": {\n            \"fake\": {\n              \"filteredIndex\": undefined,\n              \"id\": \"fake\",\n              \"index\": undefined,\n              \"internal_index\": undefined,\n              \"loginUrl\": \"https://example.com/login\",\n              \"title\": \"Fake\",\n              \"type\": \"auto-inject\",\n              \"url\": \"https://example.com\",\n            },\n          },\n        }\n      `);\n    });\n\n    it('checks refs (basic-auth)', async () => {\n      // given\n      const { api } = initRefs({ provider, store } as any, { runCheck: false });\n\n      setupResponses({\n        indexPrivate: {\n          ok: true,\n          response: async () => ({ v: 5, entries: {} }),\n        },\n        storiesPrivate: {\n          ok: true,\n          response: async () => ({ v: 3, stories: {} }),\n        },\n        metadata: {\n          ok: true,\n          response: async () => ({ versions: {} }),\n        },\n      });\n\n      await api.checkRef({\n        id: 'fake',\n        url: 'https://user:pass@example.com',\n        title: 'Fake',\n      });\n\n      expect(fetchMock.mock.calls).toMatchInlineSnapshot(`\n        [\n          [\n            \"https://example.com/index.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n                \"Authorization\": \"Basic dXNlcjpwYXNz\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/stories.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n                \"Authorization\": \"Basic dXNlcjpwYXNz\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/metadata.json\",\n            {\n              \"cache\": \"no-cache\",\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n                \"Authorization\": \"Basic dXNlcjpwYXNz\",\n              },\n            },\n          ],\n        ]\n      `);\n    });\n\n    it('checks refs (mixed)', async () => {\n      // given\n      const { api } = initRefs({ provider, store } as any, { runCheck: false });\n\n      fetchMock.mockClear();\n      store.setState.mockClear();\n\n      setupResponses({\n        indexPrivate: {\n          ok: true,\n          response: async () => ({ loginUrl: 'https://example.com/login' }),\n        },\n        storiesPrivate: {\n          ok: true,\n          response: async () => ({ loginUrl: 'https://example.com/login' }),\n        },\n        metadata: {\n          ok: true,\n          response: async () => ({\n            versions: { '1.0.0': 'https://example.com/v1', '2.0.0': 'https://example.com' },\n          }),\n        },\n      });\n\n      await api.checkRef({\n        id: 'fake',\n        url: 'https://example.com',\n        title: 'Fake',\n      });\n\n      expect(fetchMock.mock.calls).toMatchInlineSnapshot(`\n        [\n          [\n            \"https://example.com/index.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/stories.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/metadata.json\",\n            {\n              \"cache\": \"no-cache\",\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n        ]\n      `);\n\n      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`\n        {\n          \"refs\": {\n            \"fake\": {\n              \"filteredIndex\": undefined,\n              \"id\": \"fake\",\n              \"index\": undefined,\n              \"internal_index\": undefined,\n              \"loginUrl\": \"https://example.com/login\",\n              \"title\": \"Fake\",\n              \"type\": \"auto-inject\",\n              \"url\": \"https://example.com\",\n              \"versions\": {\n                \"1.0.0\": \"https://example.com/v1\",\n                \"2.0.0\": \"https://example.com\",\n              },\n            },\n          },\n        }\n      `);\n    });\n\n    it('checks refs (serverside-success)', async () => {\n      // given\n      const { api } = initRefs({ provider, store } as any, { runCheck: false });\n\n      setupResponses({\n        indexPublic: {\n          ok: true,\n          response: async () => ({ v: 5, entries: {} }),\n        },\n        storiesPublic: {\n          ok: true,\n          response: async () => ({ v: 3, stories: {} }),\n        },\n        metadata: {\n          ok: true,\n          response: async () => ({\n            versions: {},\n          }),\n        },\n      });\n\n      await api.checkRef({\n        id: 'fake',\n        url: 'https://example.com',\n        title: 'Fake',\n        type: 'server-checked',\n      });\n\n      expect(fetchMock.mock.calls).toMatchInlineSnapshot(`\n        [\n          [\n            \"https://example.com/index.json\",\n            {\n              \"credentials\": \"omit\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/stories.json\",\n            {\n              \"credentials\": \"omit\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/metadata.json\",\n            {\n              \"cache\": \"no-cache\",\n              \"credentials\": \"omit\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n        ]\n      `);\n\n      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`\n        {\n          \"refs\": {\n            \"fake\": {\n              \"filteredIndex\": {},\n              \"id\": \"fake\",\n              \"index\": {},\n              \"internal_index\": {\n                \"entries\": {},\n                \"v\": 5,\n              },\n              \"title\": \"Fake\",\n              \"type\": \"lazy\",\n              \"url\": \"https://example.com\",\n              \"versions\": {},\n            },\n          },\n        }\n      `);\n    });\n\n    it('checks refs (serverside-fail)', async () => {\n      // given\n      const { api } = initRefs({ provider, store } as any, { runCheck: false });\n\n      setupResponses({\n        indexPrivate: {\n          ok: true,\n          response: async () => ({ v: 5, entries: {} }),\n        },\n        storiesPrivate: {\n          ok: true,\n          response: async () => ({ v: 3, stories: {} }),\n        },\n        metadata: {\n          ok: true,\n          response: async () => ({\n            versions: {},\n          }),\n        },\n      });\n\n      await api.checkRef({\n        id: 'fake',\n        url: 'https://example.com',\n        title: 'Fake',\n        type: 'unknown',\n      });\n\n      expect(fetchMock.mock.calls).toMatchInlineSnapshot(`\n        [\n          [\n            \"https://example.com/index.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/stories.json\",\n            {\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n          [\n            \"https://example.com/metadata.json\",\n            {\n              \"cache\": \"no-cache\",\n              \"credentials\": \"include\",\n              \"headers\": {\n                \"Accept\": \"application/json\",\n              },\n            },\n          ],\n        ]\n      `);\n\n      expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(`\n        {\n          \"refs\": {\n            \"fake\": {\n              \"filteredIndex\": {},\n              \"id\": \"fake\",\n              \"index\": {},\n              \"internal_index\": {\n                \"entries\": {},\n                \"v\": 5,\n              },\n              \"title\": \"Fake\",\n              \"type\": \"lazy\",\n              \"url\": \"https://example.com\",\n              \"versions\": {},\n            },\n          },\n        }\n      `);\n    });\n\n    describe('v3 compatibility', () => {\n      it('infers docs only if there is only one story and it has the name \"Page\"', async () => {\n        // given\n        const { api } = initRefs({ provider, store } as any, { runCheck: false });\n\n        const index = {\n          v: 3,\n          stories: {\n            'component-a--page': {\n              id: 'component-a--page',\n              title: 'Component A',\n              name: 'Page', // Called \"Page\" but not only story\n              importPath: './path/to/component-a.ts',\n            },\n            'component-a--story-2': {\n              id: 'component-a--story-2',\n              title: 'Component A',\n              name: 'Story 2',\n              importPath: './path/to/component-a.ts',\n            },\n            'component-b--page': {\n              id: 'component-b--page',\n              title: 'Component B',\n              name: 'Page', // Page and only story\n              importPath: './path/to/component-b.ts',\n            },\n            'component-c--story-4': {\n              id: 'component-c--story-4',\n              title: 'Component c',\n              name: 'Story 4', // Only story but not page\n              importPath: './path/to/component-c.ts',\n            },\n          },\n        };\n\n        setupResponses({\n          indexPrivate: { ok: false },\n          storiesPrivate: {\n            ok: true,\n            response: async () => index,\n          },\n          metadata: {\n            ok: true,\n            response: async () => ({\n              versions: {},\n            }),\n          },\n        });\n\n        await api.checkRef({\n          id: 'fake',\n          url: 'https://example.com',\n          title: 'Fake',\n        });\n\n        const { refs } = store.setState.mock.calls[0][0];\n        const hash = refs.fake.index;\n\n        // We need exact key ordering, even if in theory JS doesn't guarantee it\n        expect(Object.keys(hash)).toEqual([\n          'component-a',\n          'component-a--page',\n          'component-a--story-2',\n          'component-b',\n          'component-b--page',\n          'component-c',\n          'component-c--story-4',\n        ]);\n        expect(hash['component-a--page'].type).toBe('story');\n        expect(hash['component-a--story-2'].type).toBe('story');\n        expect(hash['component-b--page'].type).toBe('docs');\n        expect(hash['component-c--story-4'].type).toBe('story');\n      });\n\n      it('prefers parameters.docsOnly to inferred docsOnly status', async () => {\n        const { api } = initRefs({ provider, store } as any, { runCheck: false });\n\n        const index = {\n          v: 3,\n          stories: {\n            'component-a--docs': {\n              id: 'component-a--docs',\n              title: 'Component A',\n              name: 'Docs', // Called 'Docs' rather than 'Page'\n              importPath: './path/to/component-a.ts',\n              parameters: {\n                docsOnly: true,\n              },\n            },\n          },\n        };\n        setupResponses({\n          indexPrivate: { ok: false },\n          storiesPrivate: {\n            ok: true,\n            response: async () => index,\n          },\n          metadata: {\n            ok: true,\n            response: async () => ({\n              versions: {},\n            }),\n          },\n        });\n\n        await api.checkRef({\n          id: 'fake',\n          url: 'https://example.com',\n          title: 'Fake',\n        });\n\n        const { refs } = store.setState.mock.calls[0][0];\n        const hash = refs.fake.index;\n\n        // We need exact key ordering, even if in theory JS doesn't guarantee it\n        expect(Object.keys(hash)).toEqual(['component-a', 'component-a--docs']);\n        expect(hash['component-a--docs'].type).toBe('docs');\n      });\n    });\n  });\n\n  describe('setRef', () => {\n    it('can filter', async () => {\n      const index: StoryIndex = {\n        v: 5,\n        entries: {\n          'a--1': {\n            id: 'a--1',\n            title: 'A',\n            name: '1',\n            importPath: './path/to/a1.ts',\n            type: 'story',\n            subtype: 'story',\n          },\n          'a--2': {\n            id: 'a--2',\n            title: 'A',\n            name: '2',\n            importPath: './path/to/a2.ts',\n            type: 'story',\n            subtype: 'story',\n          },\n        },\n      };\n\n      const transformOptions = {\n        provider: provider as any,\n        docsOptions: {},\n        filters: {},\n        allStatuses: {},\n      };\n      const initialState: Partial<State> = {\n        refs: {\n          fake: {\n            id: 'fake',\n            url: 'https://example.com',\n            previewInitialized: true,\n            index: transformStoryIndexToStoriesHash(index, transformOptions),\n            filteredIndex: transformStoryIndexToStoriesHash(index, transformOptions),\n            internal_index: index,\n          },\n        },\n      };\n\n      const store = createMockStore(initialState);\n      const { api } = initRefs({ provider, store } as any, { runCheck: false });\n\n      await expect(api.getRefs().fake.index).toEqual(\n        expect.objectContaining({ 'a--2': expect.anything() })\n      );\n\n      const stateWithFilters: Partial<State> = {\n        filters: {\n          fake: (a) => a.name.includes('1'),\n        },\n      };\n\n      await store.setState(stateWithFilters);\n\n      await api.setRef('fake', { storyIndex: index });\n\n      await expect(api.getRefs().fake.filteredIndex).toEqual(\n        expect.objectContaining({ 'a--1': expect.anything() })\n      );\n      await expect(api.getRefs().fake.filteredIndex).not.toEqual(\n        expect.objectContaining({ 'a--2': expect.anything() })\n      );\n    });\n  });\n\n  it('errors on unknown version', async () => {\n    // given\n    const { api } = initRefs({ provider, store } as any, { runCheck: false });\n\n    setupResponses({\n      indexPrivate: {\n        ok: false,\n      },\n      storiesPrivate: {\n        ok: true,\n        response: async () => ({ stories: {} }),\n      },\n      metadata: {\n        ok: true,\n        response: async () => ({\n          versions: {},\n        }),\n      },\n    });\n\n    await expect(\n      api.checkRef({\n        id: 'fake',\n        url: 'https://example.com',\n        title: 'Fake',\n      })\n    ).rejects.toThrow('Composition: Missing stories.json version');\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager-api/tests/shortcut.test.js",
    "content": "// @vitest-environment happy-dom\nimport { describe, expect, it } from 'vitest';\n\nimport { global } from '@storybook/global';\n\nimport { eventToShortcut, keyToSymbol } from '../lib/shortcut';\n\nconst { KeyboardEvent } = global;\nconst ev = (attr) => new KeyboardEvent('keydown', { ...attr });\n\ndescribe('eventToShortcut', () => {\n  it('handles alt key inputs', () => {\n    const output = eventToShortcut(ev({ altKey: true, key: 'Alt' }));\n\n    expect(output).toEqual(null);\n  });\n  it('handles ctrl key inputs', () => {\n    const output = eventToShortcut(ev({ ctrlKey: true, key: 'Control' }));\n    expect(output).toEqual(null);\n  });\n  it('handles meta key inputs', () => {\n    const output = eventToShortcut(ev({ metaKey: true, key: 'Meta' }));\n    expect(output).toEqual(null);\n  });\n  it('handles shift key inputs', () => {\n    const output = eventToShortcut(ev({ shiftKey: true, key: 'Shift' }));\n    expect(output).toEqual(null);\n  });\n  it('handles enter key inputs', () => {\n    const output = eventToShortcut(ev({ key: 'Enter' }));\n    expect(output).toEqual(null);\n  });\n  it('handles tab key inputs', () => {\n    const output = eventToShortcut(ev({ key: 'Tab' }));\n    expect(output).toEqual(null);\n  });\n  it('handles space bar inputs', () => {\n    const output = eventToShortcut(ev({ key: ' ' }));\n    expect(output).toEqual(['space']);\n  });\n  it('handles escape inputs', () => {\n    const output = eventToShortcut(ev({ key: 'Escape' }));\n    expect(output).toEqual(['escape']);\n  });\n  it('capitalizes a letter key through', () => {\n    const output = eventToShortcut(ev({ key: 'a', code: 'KeyA' }));\n    expect(output).toEqual(['A']);\n  });\n  it('passes regular key through', () => {\n    const output = eventToShortcut(ev({ key: '1', code: 'Digit1' }));\n    expect(output).toEqual(['1']);\n  });\n  it('passes modified regular key through', () => {\n    const output = eventToShortcut(ev({ altKey: true, key: '1', code: 'Digit1' }));\n    expect(output).toEqual(['alt', '1']);\n    // on macos\n    const outputMacOs = eventToShortcut(ev({ altKey: true, key: '√', code: 'KeyV' }));\n    expect(outputMacOs).toEqual(['alt', ['√', 'V']]);\n  });\n});\n\ndescribe('keyToSymbol', () => {\n  it('control returns a caret', () => {\n    const result = keyToSymbol('control');\n    expect(result).toBe('⌃');\n  });\n\n  it('meta returns ⌘', () => {\n    const result = keyToSymbol('meta');\n    expect(result).toEqual('⌘');\n  });\n  it('shift returns ⇧', () => {\n    const result = keyToSymbol('shift');\n    expect(result).toBe('⇧​');\n  });\n  it('enter returns an empty string', () => {\n    const result = keyToSymbol('Enter');\n    expect(result).toBe('');\n  });\n\n  it(\"' ' returns SPACE\", () => {\n    const result = keyToSymbol(' ');\n    expect(result).toEqual('SPACE');\n  });\n  it('escape returns esc', () => {\n    const result = keyToSymbol('escape');\n    expect(result).toEqual('');\n  });\n  it('ArrowUp returns ↑​​​', () => {\n    const result = keyToSymbol('ArrowUp');\n    expect(result).toBe('↑');\n  });\n  it('ArrowDown returns ↓​​​', () => {\n    const result = keyToSymbol('ArrowDown');\n    expect(result).toBe('↓');\n  });\n  it('ArrowLeft returns ←', () => {\n    const result = keyToSymbol('ArrowLeft');\n    expect(result).toBe('←');\n  });\n\n  it('ArrowRight returns →', () => {\n    const result = keyToSymbol('ArrowRight');\n    expect(result).toBe('→');\n  });\n\n  it('capitalizes a lowercase key', () => {\n    const output = keyToSymbol('a');\n    expect(output).toBe('A');\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager-api/tests/shortcuts.test.js",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { init as initShortcuts } from '../modules/shortcuts';\n\nfunction createMockStore() {\n  let state = {};\n  return {\n    getState: vi.fn().mockImplementation(() => state),\n    setState: vi.fn().mockImplementation((update) => {\n      const s = typeof update === 'function' ? update(state) : update;\n      state = { ...state, ...s };\n      return state;\n    }),\n  };\n}\n\nconst mockAddonShortcut = {\n  addon: 'my-addon',\n  shortcut: {\n    label: 'Do something',\n    defaultShortcut: ['O'],\n    actionName: 'doSomething',\n    action: () => {\n      //\n    },\n  },\n};\n\nconst mockAddonSecondShortcut = {\n  addon: 'my-addon',\n  shortcut: {\n    label: 'Do something else',\n    defaultShortcut: ['P'],\n    actionName: 'doSomethingElse',\n    action: () => {\n      //\n    },\n  },\n};\n\nconst mockSecondAddonShortcut = {\n  addon: 'my-other-addon',\n  shortcut: {\n    label: 'Create issue',\n    defaultShortcut: ['N'],\n    actionName: 'createIssue',\n    action: () => {\n      //\n    },\n  },\n};\n\ndescribe('shortcuts api', () => {\n  it('gets defaults', () => {\n    const store = createMockStore();\n\n    const { api, state } = initShortcuts({ store });\n    store.setState(state);\n\n    expect(api.getDefaultShortcuts()).toHaveProperty('fullScreen', ['alt', 'F']);\n  });\n\n  it('gets defaults including addon ones', async () => {\n    const store = createMockStore();\n\n    const { api, state } = initShortcuts({ store });\n    store.setState(state);\n\n    await api.setAddonShortcut(mockAddonShortcut.addon, mockAddonShortcut.shortcut);\n    await api.setAddonShortcut(mockAddonSecondShortcut.addon, mockAddonSecondShortcut.shortcut);\n    await api.setAddonShortcut(mockSecondAddonShortcut.addon, mockSecondAddonShortcut.shortcut);\n\n    expect(api.getDefaultShortcuts()).toHaveProperty('fullScreen', ['alt', 'F']);\n    expect(api.getDefaultShortcuts()).toHaveProperty(\n      `${mockAddonShortcut.addon}-${mockAddonShortcut.shortcut.actionName}`,\n      mockAddonShortcut.shortcut.defaultShortcut\n    );\n    expect(api.getDefaultShortcuts()).toHaveProperty(\n      `${mockAddonSecondShortcut.addon}-${mockAddonSecondShortcut.shortcut.actionName}`,\n      mockAddonSecondShortcut.shortcut.defaultShortcut\n    );\n    expect(api.getDefaultShortcuts()).toHaveProperty(\n      `${mockSecondAddonShortcut.addon}-${mockSecondAddonShortcut.shortcut.actionName}`,\n      mockSecondAddonShortcut.shortcut.defaultShortcut\n    );\n  });\n\n  it('gets addons shortcuts', async () => {\n    const store = createMockStore();\n\n    const { api, state } = initShortcuts({ store });\n    store.setState(state);\n\n    await api.setAddonShortcut(mockAddonShortcut.addon, mockAddonShortcut.shortcut);\n    await api.setAddonShortcut(mockAddonSecondShortcut.addon, mockAddonSecondShortcut.shortcut);\n    await api.setAddonShortcut(mockSecondAddonShortcut.addon, mockSecondAddonShortcut.shortcut);\n\n    expect(api.getAddonsShortcuts()).toStrictEqual({\n      [`${mockAddonShortcut.addon}-${mockAddonShortcut.shortcut.actionName}`]:\n        mockAddonShortcut.shortcut,\n      [`${mockAddonSecondShortcut.addon}-${mockAddonSecondShortcut.shortcut.actionName}`]:\n        mockAddonSecondShortcut.shortcut,\n      [`${mockSecondAddonShortcut.addon}-${mockSecondAddonShortcut.shortcut.actionName}`]:\n        mockSecondAddonShortcut.shortcut,\n    });\n  });\n\n  it('gets addons shortcut labels', async () => {\n    const store = createMockStore();\n\n    const { api, state } = initShortcuts({ store });\n    store.setState(state);\n\n    await api.setAddonShortcut(mockAddonShortcut.addon, mockAddonShortcut.shortcut);\n    await api.setAddonShortcut(mockAddonSecondShortcut.addon, mockAddonSecondShortcut.shortcut);\n    await api.setAddonShortcut(mockSecondAddonShortcut.addon, mockSecondAddonShortcut.shortcut);\n\n    expect(api.getAddonsShortcutLabels()).toStrictEqual({\n      [`${mockAddonShortcut.addon}-${mockAddonShortcut.shortcut.actionName}`]:\n        mockAddonShortcut.shortcut.label,\n      [`${mockAddonSecondShortcut.addon}-${mockAddonSecondShortcut.shortcut.actionName}`]:\n        mockAddonSecondShortcut.shortcut.label,\n      [`${mockSecondAddonShortcut.addon}-${mockSecondAddonShortcut.shortcut.actionName}`]:\n        mockSecondAddonShortcut.shortcut.label,\n    });\n  });\n\n  it('gets addons shortcut defaults', async () => {\n    const store = createMockStore();\n\n    const { api, state } = initShortcuts({ store });\n    store.setState(state);\n\n    await api.setAddonShortcut(mockAddonShortcut.addon, mockAddonShortcut.shortcut);\n    await api.setAddonShortcut(mockAddonSecondShortcut.addon, mockAddonSecondShortcut.shortcut);\n    await api.setAddonShortcut(mockSecondAddonShortcut.addon, mockSecondAddonShortcut.shortcut);\n\n    expect(api.getAddonsShortcutDefaults()).toStrictEqual({\n      [`${mockAddonShortcut.addon}-${mockAddonShortcut.shortcut.actionName}`]:\n        mockAddonShortcut.shortcut.defaultShortcut,\n      [`${mockAddonSecondShortcut.addon}-${mockAddonSecondShortcut.shortcut.actionName}`]:\n        mockAddonSecondShortcut.shortcut.defaultShortcut,\n      [`${mockSecondAddonShortcut.addon}-${mockSecondAddonShortcut.shortcut.actionName}`]:\n        mockSecondAddonShortcut.shortcut.defaultShortcut,\n    });\n  });\n\n  it('sets defaults', () => {\n    const store = createMockStore();\n\n    const { api, state } = initShortcuts({ store });\n    store.setState(state);\n\n    expect(api.getShortcutKeys().fullScreen).toEqual(['alt', 'F']);\n  });\n\n  it('sets addon shortcut with default value', async () => {\n    const store = createMockStore();\n\n    const { api, state } = initShortcuts({ store });\n    store.setState(state);\n\n    await api.setAddonShortcut(mockAddonShortcut.addon, mockAddonShortcut.shortcut);\n    await api.setAddonShortcut(mockAddonSecondShortcut.addon, mockAddonSecondShortcut.shortcut);\n    await api.setAddonShortcut(mockSecondAddonShortcut.addon, mockSecondAddonShortcut.shortcut);\n\n    expect(api.getDefaultShortcuts()).toHaveProperty('fullScreen', ['alt', 'F']);\n    expect(api.getDefaultShortcuts()).toHaveProperty(\n      `${mockAddonShortcut.addon}-${mockAddonShortcut.shortcut.actionName}`,\n      mockAddonShortcut.shortcut.defaultShortcut\n    );\n    expect(api.getDefaultShortcuts()).toHaveProperty(\n      `${mockAddonSecondShortcut.addon}-${mockAddonSecondShortcut.shortcut.actionName}`,\n      mockAddonSecondShortcut.shortcut.defaultShortcut\n    );\n    expect(api.getDefaultShortcuts()).toHaveProperty(\n      `${mockSecondAddonShortcut.addon}-${mockSecondAddonShortcut.shortcut.actionName}`,\n      mockSecondAddonShortcut.shortcut.defaultShortcut\n    );\n  });\n\n  it('sets defaults, augmenting anything that was persisted', () => {\n    const store = createMockStore();\n    store.setState({ shortcuts: { fullScreen: ['Z'] } });\n\n    const { api, state } = initShortcuts({ store });\n    store.setState(state);\n\n    expect(api.getShortcutKeys().fullScreen).toEqual(['Z']);\n    expect(api.getShortcutKeys().togglePanel).toEqual(['alt', 'A']);\n  });\n\n  it('sets defaults, ignoring anything persisted that is out of date', () => {\n    const store = createMockStore();\n    store.setState({ shortcuts: { randomKey: ['Z'] } });\n\n    const { api, state } = initShortcuts({ store });\n    store.setState(state);\n\n    expect(api.getShortcutKeys().randomKey).not.toBeDefined();\n  });\n\n  it('sets new values', async () => {\n    const store = createMockStore();\n\n    const { api, state } = initShortcuts({ store });\n    store.setState(state);\n\n    await api.setShortcut('fullScreen', ['X']);\n    expect(api.getShortcutKeys().fullScreen).toEqual(['X']);\n  });\n\n  it('sets new values for addon shortcuts', async () => {\n    const store = createMockStore();\n\n    const { api, state } = initShortcuts({ store });\n    store.setState(state);\n\n    const { addon, shortcut } = mockAddonShortcut;\n    await api.setAddonShortcut(addon, shortcut);\n\n    await api.setShortcut(`${addon}-${shortcut.actionName}`, ['I']);\n    expect(api.getShortcutKeys()[`${addon}-${shortcut.actionName}`]).toEqual(['I']);\n  });\n\n  it('restores all defaults', async () => {\n    const store = createMockStore();\n\n    const { api, state } = initShortcuts({ store });\n    store.setState(state);\n\n    const { addon, shortcut } = mockAddonShortcut;\n    await api.setAddonShortcut(addon, shortcut);\n\n    await api.setShortcut('fullScreen', ['X']);\n    await api.setShortcut('togglePanel', ['B']);\n    await api.setShortcut(`${addon}-${shortcut.actionName}`, ['I']);\n\n    await api.restoreAllDefaultShortcuts();\n    expect(api.getShortcutKeys().fullScreen).toEqual(['alt', 'F']);\n    expect(api.getShortcutKeys().togglePanel).toEqual(['alt', 'A']);\n    expect(api.getShortcutKeys()[`${addon}-${shortcut.actionName}`]).toEqual(\n      shortcut.defaultShortcut\n    );\n  });\n\n  it('restores single default', async () => {\n    const store = createMockStore();\n\n    const { api, state } = initShortcuts({ store });\n    store.setState(state);\n\n    await api.setAddonShortcut(mockAddonShortcut.addon, mockAddonShortcut.shortcut);\n    await api.setAddonShortcut(mockAddonSecondShortcut.addon, mockAddonSecondShortcut.shortcut);\n    await api.setAddonShortcut(mockSecondAddonShortcut.addon, mockSecondAddonShortcut.shortcut);\n\n    await api.setShortcut('fullScreen', ['X']);\n    await api.setShortcut('togglePanel', ['B']);\n    await api.setShortcut(`${mockAddonShortcut.addon}-${mockAddonShortcut.shortcut.actionName}`, [\n      'I',\n    ]);\n    await api.setShortcut(\n      `${mockAddonSecondShortcut.addon}-${mockAddonSecondShortcut.shortcut.actionName}`,\n      ['H']\n    );\n    await api.setShortcut(\n      `${mockSecondAddonShortcut.addon}-${mockSecondAddonShortcut.shortcut.actionName}`,\n      ['G']\n    );\n    await api.restoreDefaultShortcut('fullScreen');\n    await api.restoreDefaultShortcut(\n      `${mockAddonShortcut.addon}-${mockAddonShortcut.shortcut.actionName}`\n    );\n\n    expect(api.getShortcutKeys().fullScreen).toEqual(['alt', 'F']);\n    expect(api.getShortcutKeys().togglePanel).toEqual(['B']);\n    expect(\n      api.getShortcutKeys()[`${mockAddonShortcut.addon}-${mockAddonShortcut.shortcut.actionName}`]\n    ).toEqual(mockAddonShortcut.shortcut.defaultShortcut);\n    expect(\n      api.getShortcutKeys()[\n        `${mockAddonSecondShortcut.addon}-${mockAddonSecondShortcut.shortcut.actionName}`\n      ]\n    ).toEqual(['H']);\n    expect(\n      api.getShortcutKeys()[\n        `${mockSecondAddonShortcut.addon}-${mockSecondAddonShortcut.shortcut.actionName}`\n      ]\n    ).toEqual(['G']);\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager-api/tests/statuses.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport type { API_PreparedIndexEntry } from 'storybook/internal/types';\n\nimport {\n  computeStatusFilterFn,\n  parseStatusesParam,\n  serializeStatusesParam,\n} from '../modules/statuses.ts';\n\nvi.mock('../stores/status.ts', () => ({\n  fullStatusStore: {\n    getAll: vi.fn(() => ({})),\n  },\n}));\n\nimport { fullStatusStore } from '../stores/status.ts';\n\nconst entry = (id: string): API_PreparedIndexEntry => ({ id }) as unknown as API_PreparedIndexEntry;\n\ndescribe('parseStatusesParam', () => {\n  it('returns empty arrays for undefined', () => {\n    expect(parseStatusesParam(undefined)).toEqual({ included: [], excluded: [] });\n  });\n\n  it('returns empty arrays for empty string', () => {\n    expect(parseStatusesParam('')).toEqual({ included: [], excluded: [] });\n  });\n\n  it('parses included statuses', () => {\n    expect(parseStatusesParam('new;modified')).toEqual({\n      included: ['status-value:new', 'status-value:modified'],\n      excluded: [],\n    });\n  });\n\n  it('parses excluded statuses with ! prefix', () => {\n    expect(parseStatusesParam('!error;!warning')).toEqual({\n      included: [],\n      excluded: ['status-value:error', 'status-value:warning'],\n    });\n  });\n\n  it('parses mixed included and excluded', () => {\n    expect(parseStatusesParam('new;!error;pending')).toEqual({\n      included: ['status-value:new', 'status-value:pending'],\n      excluded: ['status-value:error'],\n    });\n  });\n\n  it('ignores unknown short names', () => {\n    expect(parseStatusesParam('new;bogus;modified')).toEqual({\n      included: ['status-value:new', 'status-value:modified'],\n      excluded: [],\n    });\n  });\n\n  it('ignores empty segments from trailing semicolons', () => {\n    expect(parseStatusesParam('new;;modified;')).toEqual({\n      included: ['status-value:new', 'status-value:modified'],\n      excluded: [],\n    });\n  });\n\n  it('parses all known status values', () => {\n    expect(\n      parseStatusesParam('new;modified;affected;error;warning;success;pending;unknown')\n    ).toEqual({\n      included: [\n        'status-value:new',\n        'status-value:modified',\n        'status-value:affected',\n        'status-value:error',\n        'status-value:warning',\n        'status-value:success',\n        'status-value:pending',\n        'status-value:unknown',\n      ],\n      excluded: [],\n    });\n  });\n});\n\ndescribe('serializeStatusesParam', () => {\n  it('returns undefined for empty arrays', () => {\n    expect(serializeStatusesParam([], [])).toBeUndefined();\n  });\n\n  it('serializes included values', () => {\n    expect(serializeStatusesParam(['status-value:new', 'status-value:modified'], [])).toBe(\n      'modified;new'\n    );\n  });\n\n  it('serializes excluded values with ! prefix', () => {\n    expect(serializeStatusesParam([], ['status-value:error', 'status-value:warning'])).toBe(\n      '!error;!warning'\n    );\n  });\n\n  it('serializes mixed included and excluded', () => {\n    expect(serializeStatusesParam(['status-value:new'], ['status-value:error'])).toBe('new;!error');\n  });\n\n  it('round-trips with parseStatusesParam', () => {\n    const included = ['status-value:new', 'status-value:pending'] as const;\n    const excluded = ['status-value:error'] as const;\n    const serialized = serializeStatusesParam([...included], [...excluded]);\n    const parsed = parseStatusesParam(serialized);\n    expect(parsed.included).toEqual(included);\n    expect(parsed.excluded).toEqual(excluded);\n  });\n});\n\ndescribe('computeStatusFilterFn', () => {\n  it('returns true for all entries when both filters are empty', () => {\n    const fn = computeStatusFilterFn([], []);\n    expect(fn(entry('story-1') as any)).toBe(true);\n  });\n\n  it('includes entries matching an included status (OR logic)', () => {\n    vi.mocked(fullStatusStore.getAll).mockReturnValue({\n      'story-1': {\n        'addon-a': {\n          value: 'status-value:new',\n          title: '',\n          description: '',\n          typeId: '',\n          storyId: 'story-1',\n        },\n      },\n      'story-2': {\n        'addon-a': {\n          value: 'status-value:error',\n          title: '',\n          description: '',\n          typeId: '',\n          storyId: 'story-2',\n        },\n      },\n    });\n\n    const fn = computeStatusFilterFn(['status-value:new', 'status-value:modified'], []);\n    expect(fn(entry('story-1') as any)).toBe(true); // has 'new'\n    expect(fn(entry('story-2') as any)).toBe(false); // has 'error', not in include list\n  });\n\n  it('excludes entries matching an excluded status (AND logic)', () => {\n    vi.mocked(fullStatusStore.getAll).mockReturnValue({\n      'story-1': {\n        'addon-a': {\n          value: 'status-value:error',\n          title: '',\n          description: '',\n          typeId: '',\n          storyId: 'story-1',\n        },\n      },\n      'story-2': {\n        'addon-a': {\n          value: 'status-value:success',\n          title: '',\n          description: '',\n          typeId: '',\n          storyId: 'story-2',\n        },\n      },\n    });\n\n    const fn = computeStatusFilterFn([], ['status-value:error']);\n    expect(fn(entry('story-1') as any)).toBe(false); // has 'error', excluded\n    expect(fn(entry('story-2') as any)).toBe(true); // has 'success', not excluded\n  });\n\n  it('applies both include and exclude filters together', () => {\n    vi.mocked(fullStatusStore.getAll).mockReturnValue({\n      'story-1': {\n        'addon-a': {\n          value: 'status-value:new',\n          title: '',\n          description: '',\n          typeId: '',\n          storyId: 'story-1',\n        },\n      },\n      'story-2': {\n        'addon-a': {\n          value: 'status-value:new',\n          title: '',\n          description: '',\n          typeId: '',\n          storyId: 'story-2',\n        },\n        'addon-b': {\n          value: 'status-value:error',\n          title: '',\n          description: '',\n          typeId: '',\n          storyId: 'story-2',\n        },\n      },\n      'story-3': {\n        'addon-a': {\n          value: 'status-value:success',\n          title: '',\n          description: '',\n          typeId: '',\n          storyId: 'story-3',\n        },\n      },\n    });\n\n    const fn = computeStatusFilterFn(['status-value:new'], ['status-value:error']);\n    expect(fn(entry('story-1') as any)).toBe(true); // included via 'new', no excluded match\n    expect(fn(entry('story-2') as any)).toBe(false); // included via 'new' BUT excluded via 'error'\n    expect(fn(entry('story-3') as any)).toBe(false); // not included (no 'new')\n  });\n\n  it('excludes entries with no statuses when include filters are active', () => {\n    vi.mocked(fullStatusStore.getAll).mockReturnValue({});\n\n    const fn = computeStatusFilterFn(['status-value:new'], []);\n    expect(fn(entry('story-no-status') as any)).toBe(false);\n  });\n\n  it('includes entries with no statuses when only exclude filters are active', () => {\n    vi.mocked(fullStatusStore.getAll).mockReturnValue({});\n\n    const fn = computeStatusFilterFn([], ['status-value:error']);\n    expect(fn(entry('story-no-status') as any)).toBe(true);\n  });\n\n  it('handles entry not present in status store', () => {\n    vi.mocked(fullStatusStore.getAll).mockReturnValue({\n      'other-story': {\n        'addon-a': {\n          value: 'status-value:new',\n          title: '',\n          description: '',\n          typeId: '',\n          storyId: 'other-story',\n        },\n      },\n    });\n\n    const fn = computeStatusFilterFn(['status-value:new'], []);\n    expect(fn(entry('missing-story') as any)).toBe(false);\n  });\n\n  it('handles entry with multiple statuses from different addons', () => {\n    vi.mocked(fullStatusStore.getAll).mockReturnValue({\n      'story-1': {\n        'addon-a': {\n          value: 'status-value:warning',\n          title: '',\n          description: '',\n          typeId: '',\n          storyId: 'story-1',\n        },\n        'addon-b': {\n          value: 'status-value:new',\n          title: '',\n          description: '',\n          typeId: '',\n          storyId: 'story-1',\n        },\n      },\n    });\n\n    const fn = computeStatusFilterFn(['status-value:new'], []);\n    expect(fn(entry('story-1') as any)).toBe(true); // one of its statuses matches\n  });\n\n  it('handles null return from getAll', () => {\n    vi.mocked(fullStatusStore.getAll).mockReturnValue(null as any);\n\n    const fn = computeStatusFilterFn(['status-value:new'], []);\n    expect(fn(entry('story-1') as any)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager-api/tests/store.test.js",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport flushPromises from 'flush-promises';\nimport store2 from 'store2';\n\nimport Store, { STORAGE_KEY } from '../store';\n\nvi.mock('store2', () => ({\n  default: {\n    local: {\n      set: vi.fn(),\n      get: vi.fn(),\n    },\n    session: {\n      set: vi.fn(),\n      get: vi.fn(),\n    },\n    _: { fn: () => {} },\n  },\n}));\n\ndescribe('store', () => {\n  it('sensibly combines local+session storage for initial state', () => {\n    // Each storage is read twice: once for the migration check, once for the actual merge.\n    store2.session.get\n      .mockReturnValueOnce({ foo: 'bar', combined: { a: 'b' } })\n      .mockReturnValueOnce({ foo: 'bar', combined: { a: 'b' } });\n    store2.local.get\n      .mockReturnValueOnce({ foo: 'baz', another: 'value', combined: { c: 'd' } })\n      .mockReturnValueOnce({ foo: 'baz', another: 'value', combined: { c: 'd' } });\n\n    const store = new Store({});\n    expect(store.getInitialState()).toEqual({\n      foo: 'bar',\n      another: 'value',\n      // We don't combine subfields from the two sources.\n      combined: { a: 'b' },\n    });\n  });\n\n  it('passes getState right through', () => {\n    const getState = vi.fn();\n    const store = new Store({ getState });\n\n    store.getState();\n\n    expect(getState).toHaveBeenCalled();\n  });\n\n  describe('setState', () => {\n    it('sets values in React only by default', async () => {\n      const setState = vi.fn().mockImplementation((x, cb) => cb());\n      const getState = vi.fn();\n      const store = new Store({ setState, getState });\n\n      await store.setState({ foo: 'bar' });\n\n      expect(setState).toHaveBeenCalledWith({ foo: 'bar' }, expect.any(Function));\n      expect(store2.session.set).not.toHaveBeenCalled();\n      expect(store2.local.set).not.toHaveBeenCalled();\n    });\n\n    it('sets values in React and sessionStorage if persistence === session', async () => {\n      const setState = vi.fn().mockImplementation((x, cb) => cb());\n      const getState = vi.fn();\n      const store = new Store({ setState, getState });\n\n      await store.setState({ foo: 'bar' }, { persistence: 'session' });\n\n      expect(setState).toHaveBeenCalledWith({ foo: 'bar' }, expect.any(Function));\n      expect(store2.session.set).toHaveBeenCalledWith(STORAGE_KEY, { foo: 'bar' });\n      expect(store2.local.set).not.toHaveBeenCalled();\n    });\n\n    it('sets values in React and sessionStorage if persistence === permanent', async () => {\n      const setState = vi.fn().mockImplementation((x, cb) => cb());\n      const getState = vi.fn();\n      const store = new Store({ setState, getState });\n\n      await store.setState({ foo: 'bar' }, { persistence: 'permanent' });\n\n      expect(setState).toHaveBeenCalledWith({ foo: 'bar' }, expect.any(Function));\n      expect(store2.session.set).not.toHaveBeenCalled();\n      expect(store2.local.set).toHaveBeenCalledWith(STORAGE_KEY, { foo: 'bar' });\n    });\n\n    it('properly patches existing values', async () => {\n      const setState = vi.fn().mockImplementation((x, cb) => cb());\n      const getState = vi.fn();\n      store2.session.get.mockReturnValueOnce({\n        foo: 'baz',\n        another: 'value',\n        combined: { a: 'b' },\n      });\n      const store = new Store({ setState, getState });\n\n      await store.setState({ foo: 'bar', combined: { c: 'd' } }, { persistence: 'session' });\n\n      expect(setState).toHaveBeenCalledWith(\n        { foo: 'bar', combined: { c: 'd' } },\n        expect.any(Function)\n      );\n      expect(store2.session.set).toHaveBeenCalledWith(STORAGE_KEY, {\n        foo: 'bar',\n        another: 'value',\n        combined: { c: 'd' },\n      });\n    });\n\n    it('waits for react to setState', async () => {\n      let cb;\n      const setState = vi.fn().mockImplementation((x, inputCb) => {\n        cb = inputCb;\n      });\n      const getState = vi.fn();\n      const store = new Store({ setState, getState });\n\n      // NOTE: not awaiting here\n      let done = false;\n      store.setState({ foo: 'bar' }).then(() => {\n        done = true;\n      });\n\n      await flushPromises();\n      expect(setState).toHaveBeenCalledWith({ foo: 'bar' }, expect.any(Function));\n      expect(done).toBe(false);\n\n      cb();\n      await flushPromises();\n      expect(done).toBe(true);\n    });\n\n    it('returns react.setState result', async () => {\n      const setState = vi.fn().mockImplementation((x, cb) => cb('RESULT'));\n      const getState = vi.fn(() => 'RESULT');\n      const store = new Store({ setState, getState });\n\n      const result = await store.setState({ foo: 'bar' });\n\n      expect(result).toEqual('RESULT');\n    });\n\n    it('allows a callback', async () =>\n      new Promise((resolve) => {\n        const setState = vi.fn().mockImplementation((x, cb) => cb('RESULT'));\n        const getState = vi.fn(() => 'RESULT');\n        const store = new Store({ setState, getState });\n\n        store.setState({ foo: 'bar' }, (result) => {\n          expect(result).toEqual('RESULT');\n          resolve();\n        });\n      }));\n\n    it('allows a patch function and persists its results', async () => {\n      const setState = vi.fn().mockImplementation((x, cb) => {\n        x('OLD_STATE');\n        cb();\n      });\n      const getState = vi.fn();\n      const store = new Store({ setState, getState });\n\n      const patch = vi.fn().mockReturnValue({ foo: 'bar' });\n      await store.setState(patch, { persistence: 'session' });\n\n      expect(patch).toHaveBeenCalledWith('OLD_STATE');\n      expect(store2.session.set).toHaveBeenCalledWith(STORAGE_KEY, { foo: 'bar' });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager-api/tests/stories.test.ts",
    "content": "import type { Mocked } from 'vitest';\nimport { describe, expect, it, vi } from 'vitest';\n\nimport {\n  CONFIG_ERROR,\n  CURRENT_STORY_WAS_SET,\n  DOCS_PREPARED,\n  RESET_STORY_ARGS,\n  SET_INDEX,\n  SET_STORIES,\n  STORY_ARGS_UPDATED,\n  STORY_INDEX_INVALIDATED,\n  STORY_MISSING,\n  STORY_PREPARED,\n  STORY_SPECIFIED,\n  UPDATE_STORY_ARGS,\n} from 'storybook/internal/core-events';\nimport { type API_StoryEntry } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { EventEmitter } from 'events';\n\nimport { getEventMetadata as getEventMetadataOriginal } from '../lib/events.ts';\nimport type { ModuleArgs } from '../lib/types.tsx';\nimport { init as initStories } from '../modules/stories.ts';\nimport { parseStatusesParam, serializeStatusesParam } from '../modules/statuses.ts';\nimport type { API, State } from '../root.tsx';\nimport type Store from '../store.ts';\nimport { fullStatusStore } from '../stores/status.ts';\nimport {\n  docsEntries,\n  mockEntries,\n  navigationEntries,\n  preparedEntries,\n} from './mockStoriesEntries.ts';\n\nconst mockGetEntries = vi.fn();\nconst fetch = vi.mocked(global.fetch);\nconst getEventMetadata = vi.mocked(getEventMetadataOriginal);\n\nconst wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\nvi.mock('../lib/events.ts', () => ({\n  getEventMetadata: vi.fn(() => ({ sourceType: 'local' })),\n}));\nvi.mock('@storybook/global', () => ({\n  global: {\n    ...globalThis,\n    fetch: vi.fn(() => ({ json: () => ({ v: 5, entries: mockGetEntries() }) })),\n    CONFIG_TYPE: 'DEVELOPMENT',\n  },\n}));\n\nfunction createMockStore(initialState: Partial<State> = {}) {\n  let state = initialState;\n  return {\n    getState: vi.fn(() => state),\n    setState: vi.fn((s: typeof state) => {\n      state = { ...state, ...s };\n      return Promise.resolve(state);\n    }),\n  } as any as Store;\n}\nfunction createMockProvider() {\n  return {\n    getConfig: vi.fn().mockReturnValue({}),\n    channel: new EventEmitter(),\n  };\n}\nfunction createMockModuleArgs({\n  fullAPI = {},\n  initialState = {},\n}: {\n  fullAPI?: Partial<Mocked<API>>;\n  initialState?: Partial<State>;\n}) {\n  const navigate = vi.fn();\n  const store = createMockStore({ filters: {}, status: {}, ...initialState });\n  const provider = createMockProvider();\n\n  return { navigate, store, provider, fullAPI: { ...fullAPI, getRefs: () => ({}) } };\n}\n\ndescribe('stories API', () => {\n  it('sets a sensible initialState', () => {\n    const moduleArgs = createMockModuleArgs({});\n    const { state } = initStories({\n      ...(moduleArgs as unknown as ModuleArgs),\n      storyId: 'id',\n      viewMode: 'story',\n    });\n\n    expect(state).toEqual(\n      expect.objectContaining({\n        previewInitialized: false,\n        storyId: 'id',\n        viewMode: 'story',\n        hasCalledSetOptions: false,\n      })\n    );\n  });\n\n  describe('setIndex', () => {\n    it('sets the initial set of stories in the stories hash', async () => {\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n      api.setIndex({ v: 5, entries: mockEntries });\n      const { index } = store.getState();\n      // We need exact key ordering, even if in theory JS doesn't guarantee it\n      expect(Object.keys(index!)).toEqual([\n        'component-a',\n        'component-a--docs',\n        'component-a--story-1',\n        'component-a--story-2',\n        'component-b',\n        'component-b--story-3',\n      ]);\n      expect(index!['component-a']).toMatchObject({\n        type: 'component',\n        id: 'component-a',\n        children: ['component-a--docs', 'component-a--story-1', 'component-a--story-2'],\n      });\n      expect(index!['component-a--docs']).toMatchObject({\n        type: 'docs',\n        id: 'component-a--docs',\n        parent: 'component-a',\n        title: 'Component A',\n        name: 'Docs',\n        storiesImports: [],\n        prepared: false,\n      });\n      expect(index!['component-a--story-1']).toMatchObject({\n        type: 'story',\n        subtype: 'story',\n        id: 'component-a--story-1',\n        parent: 'component-a',\n        title: 'Component A',\n        name: 'Story 1',\n        prepared: false,\n      });\n      expect(\n        (index!['component-a--story-1'] as API_StoryEntry as API_StoryEntry).args\n      ).toBeUndefined();\n    });\n    it('trims whitespace of group/component names (which originate from the kind)', () => {\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n      api.setIndex({\n        v: 5,\n        entries: {\n          'design-system-some-component--my-story': {\n            type: 'story',\n            subtype: 'story',\n            id: 'design-system-some-component--my-story',\n            title: '  Design System  /  Some Component  ', // note the leading/trailing whitespace around each part of the path\n            name: '  My Story  ', // we only trim the path, so this will be kept as-is (it may intentionally have whitespace)\n            importPath: './path/to/some-component.ts',\n          },\n        },\n      });\n      const { index } = store.getState();\n      // We need exact key ordering, even if in theory JS doesn't guarantee it\n      expect(Object.keys(index!)).toEqual([\n        'design-system',\n        'design-system-some-component',\n        'design-system-some-component--my-story',\n      ]);\n      expect(index!['design-system']).toMatchObject({\n        type: 'root',\n        name: 'Design System', // root name originates from `kind`, so it gets trimmed\n        tags: [],\n      });\n      expect(index!['design-system-some-component']).toMatchObject({\n        type: 'component',\n        name: 'Some Component', // component name originates from `kind`, so it gets trimmed\n      });\n      expect(index!['design-system-some-component--my-story']).toMatchObject({\n        type: 'story',\n        subtype: 'story',\n        title: '  Design System  /  Some Component  ', // title is kept as-is, because it may be used as identifier\n        name: '  My Story  ', // story name is kept as-is, because it's set directly on the story\n      });\n    });\n    it('moves rootless stories to the front of the list', async () => {\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n      api.setIndex({\n        v: 5,\n        entries: {\n          'root-first--story-1': {\n            type: 'story',\n            subtype: 'story',\n            id: 'root-first--story-1',\n            title: 'Root/First',\n            name: 'Story 1',\n            importPath: './path/to/root/first.ts',\n            tags: [],\n          },\n          ...mockEntries,\n        },\n      });\n      const { index } = store.getState();\n      // We need exact key ordering, even if in theory JS doesn't guarantee it\n      expect(Object.keys(index!)).toEqual([\n        'component-a',\n        'component-a--docs',\n        'component-a--story-1',\n        'component-a--story-2',\n        'component-b',\n        'component-b--story-3',\n        'root',\n        'root-first',\n        'root-first--story-1',\n      ]);\n      expect(index!.root).toMatchObject({\n        type: 'root',\n        id: 'root',\n        children: ['root-first'],\n        tags: [],\n      });\n    });\n    it('sets roots when showRoots = true', () => {\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store, provider } = moduleArgs;\n      provider.getConfig.mockReturnValue({ sidebar: { showRoots: true } });\n      api.setIndex({\n        v: 5,\n        entries: {\n          'a-b--1': {\n            type: 'story',\n            subtype: 'story',\n            id: 'a-b--1',\n            title: 'a/b',\n            name: '1',\n            tags: [],\n            importPath: './a/b.ts',\n          },\n        },\n      });\n      const { index } = store.getState();\n      // We need exact key ordering, even if in theory JS doesn't guarantee it\n      expect(Object.keys(index!)).toEqual(['a', 'a-b', 'a-b--1']);\n      expect(index!.a).toMatchObject({\n        type: 'root',\n        id: 'a',\n        children: ['a-b'],\n        tags: [],\n      });\n      expect(index!['a-b']).toMatchObject({\n        type: 'component',\n        id: 'a-b',\n        parent: 'a',\n        children: ['a-b--1'],\n      });\n      expect(index!['a-b--1']).toMatchObject({\n        type: 'story',\n        subtype: 'story',\n        id: 'a-b--1',\n        parent: 'a-b',\n        name: '1',\n        title: 'a/b',\n      });\n    });\n    it('does not put bare stories into a root when showRoots = true', () => {\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store, provider } = moduleArgs;\n      provider.getConfig.mockReturnValue({ sidebar: { showRoots: true } });\n      api.setIndex({\n        v: 5,\n        entries: {\n          'a--1': {\n            type: 'story',\n            subtype: 'story',\n            id: 'a--1',\n            title: 'a',\n            name: '1',\n            importPath: './a.ts',\n          },\n        },\n      });\n      const { index } = store.getState();\n      // We need exact key ordering, even if in theory JS doesn't guarantee it\n      expect(Object.keys(index!)).toEqual(['a', 'a--1']);\n      expect(index!.a).toMatchObject({\n        type: 'component',\n        id: 'a',\n        children: ['a--1'],\n      });\n      expect(index!['a--1']).toMatchObject({\n        type: 'story',\n        subtype: 'story',\n        id: 'a--1',\n        parent: 'a',\n        title: 'a',\n        name: '1',\n      });\n    });\n    it('intersects story/docs tags to compute tags for component entries', () => {\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n      api.setIndex({\n        v: 5,\n        entries: {\n          'a--1': {\n            type: 'story',\n            subtype: 'story',\n            id: 'a--1',\n            title: 'a',\n            name: '1',\n            tags: ['shared', 'one-specific'],\n            importPath: './a.ts',\n          },\n          'a--2': {\n            type: 'story',\n            subtype: 'story',\n            id: 'a--2',\n            title: 'a',\n            name: '2',\n            tags: ['shared', 'two-specific'],\n            importPath: './a.ts',\n          },\n        },\n      });\n      const { index } = store.getState();\n      // We need exact key ordering, even if in theory JS doesn't guarantee it\n      expect(Object.keys(index!)).toEqual(['a', 'a--1', 'a--2']);\n      expect(index!.a).toMatchObject({\n        type: 'component',\n        id: 'a',\n        tags: ['shared'],\n        children: ['a--1', 'a--2'],\n      });\n      expect(index!['a--1']).toMatchObject({\n        type: 'story',\n        subtype: 'story',\n        id: 'a--1',\n        parent: 'a',\n        title: 'a',\n        name: '1',\n        tags: ['shared', 'one-specific'],\n      });\n      expect(index!['a--2']).toMatchObject({\n        type: 'story',\n        subtype: 'story',\n        id: 'a--2',\n        parent: 'a',\n        title: 'a',\n        name: '2',\n        tags: ['shared', 'two-specific'],\n      });\n    });\n\n    it('intersects story/docs tags to compute tags for root and group entries', () => {\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n      api.setIndex({\n        v: 5,\n        entries: {\n          'a-sampleone': {\n            type: 'story',\n            subtype: 'story',\n            id: 'a-sampleone',\n            title: 'A/SampleOne',\n            name: '1',\n            tags: ['shared', 'one-specific'],\n            importPath: './a.ts',\n          },\n          'a-sampletwo': {\n            type: 'story',\n            subtype: 'story',\n            id: 'a-sampletwo',\n            title: 'A/SampleTwo',\n            name: '2',\n            tags: ['shared', 'two-specific'],\n            importPath: './a.ts',\n          },\n          'a-embedded-othertopic': {\n            type: 'docs',\n            id: 'a-embedded-othertopic',\n            title: 'A/Embedded/OtherTopic',\n            name: '3',\n            tags: ['shared', 'embedded-docs-specific', 'other'],\n            storiesImports: [],\n            importPath: './embedded/other.mdx',\n          },\n          'a-embedded-extras': {\n            type: 'docs',\n            id: 'a-embedded-extras',\n            title: 'A/Embedded/Extras',\n            name: '3',\n            tags: ['shared', 'embedded-docs-specific', 'extras'],\n            storiesImports: [],\n            importPath: './embedded/extras.mdx',\n          },\n        },\n      });\n      const { index } = store.getState();\n      // We need exact key ordering, even if in theory JS doesn't guarantee it\n      expect(Object.keys(index!)).toEqual([\n        'a',\n        'a-sampleone',\n        'a-sampletwo',\n        'a-embedded',\n        'a-embedded-othertopic',\n        'a-embedded-extras',\n      ]);\n      // Acts as the root, so that the next level is a group we're testing.\n      expect(index!.a).toMatchObject({\n        type: 'root',\n        id: 'a',\n        children: ['a-sampleone', 'a-sampletwo', 'a-embedded'],\n        tags: ['shared'],\n      });\n      // The object of this test.\n      expect(index!['a-embedded']).toMatchObject({\n        type: 'group',\n        id: 'a-embedded',\n        parent: 'a',\n        name: 'Embedded',\n        tags: ['shared', 'embedded-docs-specific'],\n      });\n    });\n    // Stories can get out of order for a few reasons -- see reproductions on\n    //   https://github.com/storybookjs/storybook/issues/5518\n    it('does the right thing for out of order stories', async () => {\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store, provider } = moduleArgs;\n      provider.getConfig.mockReturnValue({ sidebar: { showRoots: true } });\n      api.setIndex({\n        v: 5,\n        entries: {\n          'a--1': {\n            type: 'story',\n            subtype: 'story',\n            title: 'a',\n            name: '1',\n            id: 'a--1',\n            importPath: './a.ts',\n          },\n          'b--1': {\n            type: 'story',\n            subtype: 'story',\n            title: 'b',\n            name: '1',\n            id: 'b--1',\n            importPath: './b.ts',\n          },\n          'a--2': {\n            type: 'story',\n            subtype: 'story',\n            title: 'a',\n            name: '2',\n            id: 'a--2',\n            importPath: './a.ts',\n          },\n        },\n      });\n      const { index } = store.getState();\n      // We need exact key ordering, even if in theory JS doesn't guarantee it\n      expect(Object.keys(index!)).toEqual(['a', 'a--1', 'a--2', 'b', 'b--1']);\n      expect(index!.a).toMatchObject({\n        type: 'component',\n        id: 'a',\n        children: ['a--1', 'a--2'],\n      });\n      expect(index!.b).toMatchObject({\n        type: 'component',\n        id: 'b',\n        children: ['b--1'],\n      });\n    });\n    // Entries on the SET_STORIES event will be prepared\n    it('handles properly prepared stories', async () => {\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n      api.setIndex({\n        v: 5,\n        entries: {\n          'prepared--story': {\n            type: 'story',\n            subtype: 'story',\n            id: 'prepared--story',\n            title: 'Prepared',\n            name: 'Story',\n            importPath: './path/to/prepared.ts',\n            parameters: { parameter: 'exists' },\n            args: { arg: 'exists' },\n          },\n        },\n      });\n      const { index } = store.getState();\n      expect(index!['prepared--story']).toMatchObject({\n        type: 'story',\n        subtype: 'story',\n        id: 'prepared--story',\n        parent: 'prepared',\n        title: 'Prepared',\n        name: 'Story',\n        prepared: true,\n        parameters: { parameter: 'exists' },\n        args: { arg: 'exists' },\n      });\n    });\n    it('retains prepared-ness of stories', async () => {\n      const fullAPI = { setOptions: vi.fn() };\n      const moduleArgs = createMockModuleArgs({ fullAPI });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store, provider } = moduleArgs;\n      api.setIndex({ v: 5, entries: mockEntries });\n      provider.channel.emit(STORY_PREPARED, {\n        id: 'component-a--story-1',\n        parameters: { a: 'b' },\n        args: { c: 'd' },\n      });\n      // Let the promise/await chain resolve\n      await new Promise((r) => setTimeout(r, 0));\n      expect(store.getState().index!['component-a--story-1'] as API_StoryEntry).toMatchObject({\n        prepared: true,\n        parameters: { a: 'b' },\n        args: { c: 'd' },\n      });\n      api.setIndex({ v: 5, entries: mockEntries });\n      // Let the promise/await chain resolve\n      await new Promise((r) => setTimeout(r, 0));\n      expect(store.getState().index!['component-a--story-1'] as API_StoryEntry).toMatchObject({\n        prepared: true,\n        parameters: { a: 'b' },\n        args: { c: 'd' },\n      });\n    });\n\n    describe('docs entries', () => {\n      it('handles docs entries', async () => {\n        const moduleArgs = createMockModuleArgs({});\n        const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n        const { store } = moduleArgs;\n\n        api.setIndex({ v: 5, entries: docsEntries });\n        const { index } = store.getState();\n        // We need exact key ordering, even if in theory JS doesn't guarantee it\n        expect(Object.keys(index!)).toEqual([\n          'component-a',\n          'component-a--page',\n          'component-a--story-2',\n          'component-b',\n          'component-b--docs',\n          'component-c',\n          'component-c--story-4',\n        ]);\n        expect(index!['component-a--page'].type).toBe('story');\n        expect(index!['component-a--story-2'].type).toBe('story');\n        expect(index!['component-b--docs'].type).toBe('docs');\n        expect(index!['component-c--story-4'].type).toBe('story');\n      });\n      describe('when DOCS_MODE = true', () => {\n        it('strips out story entries', async () => {\n          const moduleArgs = createMockModuleArgs({});\n          const { api } = initStories({\n            ...(moduleArgs as unknown as ModuleArgs),\n            docsOptions: { docsMode: true },\n          });\n          const { store } = moduleArgs;\n          api.setIndex({ v: 5, entries: docsEntries });\n          const { index } = store.getState();\n          expect(Object.keys(index!)).toEqual(['component-b', 'component-b--docs']);\n        });\n      });\n    });\n  });\n\n  describe('SET_INDEX event', () => {\n    it('calls setIndex w/ the data', () => {\n      const fullAPI = { setOptions: vi.fn() };\n      const moduleArgs = createMockModuleArgs({ fullAPI });\n      initStories(moduleArgs as unknown as ModuleArgs);\n      const { store, provider } = moduleArgs;\n\n      provider.channel.emit(SET_INDEX, { v: 5, entries: mockEntries });\n      expect(store.getState().index).toEqual(\n        expect.objectContaining({\n          'component-a': expect.any(Object),\n          'component-a--docs': expect.any(Object),\n          'component-a--story-1': expect.any(Object),\n        })\n      );\n    });\n    it('calls setOptions w/ first story parameter', () => {\n      const fullAPI = { setOptions: vi.fn() };\n      const moduleArgs = createMockModuleArgs({ fullAPI });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { provider } = moduleArgs;\n\n      // HACK api to effectively mock getCurrentParameter\n      Object.assign(api, {\n        getCurrentParameter: vi.fn().mockReturnValue('options'),\n      });\n\n      provider.channel.emit(SET_INDEX, { v: 5, entries: mockEntries });\n      expect(fullAPI.setOptions).toHaveBeenCalledWith('options');\n    });\n  });\n\n  describe('fetchIndex', () => {\n    it('deals with 500 errors', async () => {\n      fetch.mockReturnValue(\n        Promise.resolve({\n          status: 500,\n          text: async () => new Error('sorting error'),\n        } as any as Response)\n      );\n      const moduleArgs = createMockModuleArgs({});\n      const { init } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n\n      await init!();\n\n      const { indexError } = store.getState();\n      expect(indexError).toBeDefined();\n    });\n    it('watches for the INVALIDATE event and re-fetches -- and resets the hash', async () => {\n      fetch.mockReturnValue(\n        Promise.resolve({\n          status: 200,\n          ok: true,\n          json: () => ({\n            v: 5,\n            entries: {\n              'component-a--story-1': {\n                type: 'story',\n                subtype: 'story',\n                id: 'component-a--story-1',\n                title: 'Component A',\n                name: 'Story 1',\n                importPath: './path/to/component-a.ts',\n              },\n            },\n          }),\n        } as any as Response)\n      );\n\n      const moduleArgs = createMockModuleArgs({});\n      const { init } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store, provider } = moduleArgs;\n\n      await init!();\n\n      expect(fetch).toHaveBeenCalledTimes(1);\n      provider.channel.emit(STORY_INDEX_INVALIDATED);\n      expect(global.fetch).toHaveBeenCalledTimes(2);\n\n      // this side-effect is in an un-awaited promise.\n      await wait(16);\n\n      const { index } = store.getState();\n      expect(Object.keys(index!)).toEqual(['component-a', 'component-a--story-1']);\n    });\n    it('clears 500 errors when invalidated', async () => {\n      fetch.mockReturnValueOnce(\n        Promise.resolve({\n          status: 500,\n          text: async () => new Error('sorting error'),\n        } as any as Response)\n      );\n      const moduleArgs = createMockModuleArgs({});\n      const { init } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store, provider } = moduleArgs;\n\n      await init!();\n\n      const { indexError } = store.getState();\n      expect(indexError).toBeDefined();\n\n      fetch.mockReturnValueOnce(\n        Promise.resolve({\n          status: 200,\n          ok: true,\n          json: () => ({\n            v: 5,\n            entries: {\n              'component-a--story-1': {\n                type: 'story',\n                subtype: 'story',\n                id: 'component-a--story-1',\n                title: 'Component A',\n                name: 'Story 1',\n                importPath: './path/to/component-a.ts',\n              },\n            },\n          }),\n        } as any as Response)\n      );\n\n      provider.channel.emit(STORY_INDEX_INVALIDATED);\n      expect(global.fetch).toHaveBeenCalledTimes(2);\n\n      // this side-effect is in an un-awaited promise.\n      await wait(16);\n\n      const { index, indexError: newIndexError } = store.getState();\n      expect(newIndexError).not.toBeDefined();\n      expect(Object.keys(index!)).toEqual(['component-a', 'component-a--story-1']);\n    });\n  });\n\n  describe('STORY_SPECIFIED event', () => {\n    it('navigates to the story', async () => {\n      const moduleArgs = createMockModuleArgs({ initialState: { path: '/', index: {} } });\n      initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate, provider } = moduleArgs;\n\n      provider.channel.emit(STORY_SPECIFIED, { storyId: 'a--1', viewMode: 'story' });\n      expect(navigate).toHaveBeenCalledWith('/story/a--1', undefined);\n    });\n    it('DOES not navigate if the story was already selected', async () => {\n      const moduleArgs = createMockModuleArgs({ initialState: { path: '/story/a--1', index: {} } });\n      initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate, provider } = moduleArgs;\n\n      provider.channel.emit(STORY_SPECIFIED, { storyId: 'a--1', viewMode: 'story' });\n      expect(navigate).not.toHaveBeenCalled();\n    });\n    it('DOES not navigate if a settings page was selected', async () => {\n      const moduleArgs = createMockModuleArgs({\n        initialState: { path: '/settings/about', index: {} },\n      });\n      initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate, provider } = moduleArgs;\n\n      provider.channel.emit(STORY_SPECIFIED, { storyId: 'a--1', viewMode: 'story' });\n      expect(navigate).not.toHaveBeenCalled();\n    });\n    it('DOES not navigate if a custom page was selected', async () => {\n      const moduleArgs = createMockModuleArgs({\n        initialState: { path: '/custom/page', index: {} },\n      });\n      initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate, provider } = moduleArgs;\n\n      provider.channel.emit(STORY_SPECIFIED, { storyId: 'a--1', viewMode: 'story' });\n      expect(navigate).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('CURRENT_STORY_WAS_SET event', () => {\n    it('sets previewInitialized', async () => {\n      const moduleArgs = createMockModuleArgs({});\n      initStories(moduleArgs as unknown as ModuleArgs);\n      const { store, provider } = moduleArgs;\n      provider.channel.emit(CURRENT_STORY_WAS_SET, { id: 'a--1' });\n\n      expect(store.getState().previewInitialized).toBe(true);\n    });\n    it('sets a ref to previewInitialized', async () => {\n      const fullAPI = { updateRef: vi.fn() };\n      const moduleArgs = createMockModuleArgs({ fullAPI });\n      initStories(moduleArgs as unknown as ModuleArgs);\n      const { provider } = moduleArgs;\n      provider.channel.emit(CURRENT_STORY_WAS_SET, { id: 'a--1' });\n\n      getEventMetadata.mockReturnValueOnce({\n        sourceType: 'external',\n        refId: 'refId',\n        source: '',\n        sourceLocation: '',\n        type: '',\n        ref: { id: 'refId', index: { 'a--1': { args: { a: 'b' } } } } as any,\n      });\n      provider.channel.emit(CURRENT_STORY_WAS_SET, { id: 'a--1' });\n      expect(fullAPI.updateRef.mock.calls.length).toBe(1);\n      expect(fullAPI.updateRef.mock.calls[0][1]).toEqual({\n        previewInitialized: true,\n      });\n    });\n  });\n\n  describe('args handling', () => {\n    it('changes args properly, per story when receiving STORY_ARGS_UPDATED', () => {\n      const fullAPI = { updateRef: vi.fn() };\n      const moduleArgs = createMockModuleArgs({ fullAPI });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { provider, store } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: preparedEntries });\n      const { index } = store.getState();\n      expect((index!['a--1'] as API_StoryEntry).args).toEqual({ a: 'b' });\n      expect((index!['b--1'] as API_StoryEntry).args).toEqual({ x: 'y' });\n      provider.channel.emit(STORY_ARGS_UPDATED, { storyId: 'a--1', args: { foo: 'bar' } });\n      const { index: changedIndex } = store.getState();\n      expect((changedIndex!['a--1'] as API_StoryEntry).args).toEqual({ foo: 'bar' });\n      expect((changedIndex!['b--1'] as API_StoryEntry).args).toEqual({ x: 'y' });\n    });\n    it('changes reffed args properly, per story when receiving STORY_ARGS_UPDATED', () => {\n      const fullAPI = { updateRef: vi.fn() };\n      const moduleArgs = createMockModuleArgs({ fullAPI });\n      initStories(moduleArgs as unknown as ModuleArgs);\n      const { provider } = moduleArgs;\n\n      getEventMetadata.mockReturnValueOnce({\n        sourceType: 'external',\n        refId: 'refId',\n        source: '',\n        sourceLocation: '',\n        type: '',\n        ref: {\n          id: 'refId',\n          index: { 'a--1': { args: { a: 'b' } } },\n          filteredIndex: { 'a--1': { args: { a: 'b' } } },\n        } as any,\n      });\n      provider.channel.emit(STORY_ARGS_UPDATED, { storyId: 'a--1', args: { foo: 'bar' } });\n      expect(fullAPI.updateRef).toHaveBeenCalledWith('refId', {\n        filteredIndex: { 'a--1': { args: { foo: 'bar' } } },\n        index: { 'a--1': { args: { foo: 'bar' } } },\n      });\n    });\n    it('updateStoryArgs emits UPDATE_STORY_ARGS to the local frame and does not change anything', () => {\n      const fullAPI = { updateRef: vi.fn() };\n      const moduleArgs = createMockModuleArgs({ fullAPI });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { provider, store } = moduleArgs;\n\n      const listener = vi.fn();\n      provider.channel.on(UPDATE_STORY_ARGS, listener);\n\n      api.setIndex({ v: 5, entries: preparedEntries });\n      api.updateStoryArgs({ id: 'a--1' } as API_StoryEntry, { foo: 'bar' });\n\n      expect(listener).toHaveBeenCalledWith({\n        storyId: 'a--1',\n        updatedArgs: { foo: 'bar' },\n        options: {\n          target: undefined,\n        },\n      });\n\n      const { index } = store.getState();\n      expect((index!['a--1'] as API_StoryEntry).args).toEqual({ a: 'b' });\n      expect((index!['b--1'] as API_StoryEntry).args).toEqual({ x: 'y' });\n    });\n    it('updateStoryArgs emits UPDATE_STORY_ARGS to the right frame', () => {\n      const fullAPI = { updateRef: vi.fn() };\n      const moduleArgs = createMockModuleArgs({ fullAPI });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { provider } = moduleArgs;\n\n      const listener = vi.fn();\n      provider.channel.on(UPDATE_STORY_ARGS, listener);\n\n      api.setIndex({ v: 5, entries: preparedEntries });\n      api.updateStoryArgs({ id: 'a--1', refId: 'refId' } as API_StoryEntry, { foo: 'bar' });\n      expect(listener).toHaveBeenCalledWith({\n        storyId: 'a--1',\n        updatedArgs: { foo: 'bar' },\n        options: {\n          target: 'refId',\n        },\n      });\n    });\n    it('refId to the local frame and does not change anything', () => {\n      const fullAPI = { updateRef: vi.fn() };\n      const moduleArgs = createMockModuleArgs({ fullAPI });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { provider, store } = moduleArgs;\n      const listener = vi.fn();\n      provider.channel.on(RESET_STORY_ARGS, listener);\n\n      api.setIndex({ v: 5, entries: preparedEntries });\n      api.resetStoryArgs({ id: 'a--1' } as API_StoryEntry, ['foo']);\n\n      expect(listener).toHaveBeenCalledWith({\n        storyId: 'a--1',\n        argNames: ['foo'],\n        options: {\n          target: undefined,\n        },\n      });\n\n      const { index } = store.getState();\n      expect((index!['a--1'] as API_StoryEntry).args).toEqual({ a: 'b' });\n      expect((index!['b--1'] as API_StoryEntry).args).toEqual({ x: 'y' });\n    });\n    it('resetStoryArgs emits RESET_STORY_ARGS to the right frame', () => {\n      const fullAPI = { updateRef: vi.fn() };\n      const moduleArgs = createMockModuleArgs({ fullAPI });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { provider } = moduleArgs;\n\n      const listener = vi.fn();\n      provider.channel.on(RESET_STORY_ARGS, listener);\n\n      api.setIndex({ v: 5, entries: preparedEntries });\n      api.resetStoryArgs({ id: 'a--1', refId: 'refId' } as API_StoryEntry, ['foo']);\n      expect(listener).toHaveBeenCalledWith({\n        storyId: 'a--1',\n        argNames: ['foo'],\n        options: {\n          target: 'refId',\n        },\n      });\n    });\n  });\n\n  describe('jumpToStory', () => {\n    it('works forward', () => {\n      const initialState = { path: '/story/a--1', storyId: 'a--1', viewMode: 'story' };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: navigationEntries });\n      api.jumpToStory(1);\n\n      expect(navigate).toHaveBeenCalledWith('/story/a--2', undefined);\n    });\n    it('works backwards', () => {\n      const initialState = { path: '/story/a--2', storyId: 'a--2', viewMode: 'story' };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: navigationEntries });\n      api.jumpToStory(-1);\n\n      expect(navigate).toHaveBeenCalledWith('/story/a--1', undefined);\n    });\n    it('does nothing if you are at the last story and go forward', () => {\n      const initialState = {\n        path: '/story/custom-id--1',\n        storyId: 'custom-id--1',\n        viewMode: 'story',\n      };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: navigationEntries });\n      api.jumpToStory(1);\n      expect(navigate).not.toHaveBeenCalled();\n    });\n    it('does nothing if you are at the first story and go backward', () => {\n      const initialState = { path: '/story/a--1', storyId: 'a--1', viewMode: 'story' };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: navigationEntries });\n      api.jumpToStory(-1);\n      expect(navigate).not.toHaveBeenCalled();\n    });\n    it('does nothing if you have not selected a story', () => {\n      const initialState = { path: '/story', storyId: undefined, viewMode: 'story' };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: navigationEntries });\n      api.jumpToStory(1);\n      expect(navigate).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('findSiblingStoryId', () => {\n    it('works forward', () => {\n      const initialState = { path: '/story/a--1', storyId: 'a--1', viewMode: 'story' };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: navigationEntries });\n      const result = api.findSiblingStoryId('a--1', store.getState().index!, 1, false);\n      expect(result).toBe('a--2');\n    });\n    it('works forward toSiblingGroup', () => {\n      const initialState = { path: '/story/a--1', storyId: 'a--1', viewMode: 'story' };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: navigationEntries });\n      const result = api.findSiblingStoryId('a--1', store.getState().index!, 1, true);\n      expect(result).toBe('b-c--1');\n    });\n  });\n  describe('findAllLeafStoryIds', () => {\n    it('work for a leaf story', () => {\n      const initialState = { path: '/story/a--1', storyId: 'a--1', viewMode: 'story' };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n\n      api.setIndex({ v: 5, entries: navigationEntries });\n      const result = api.findAllLeafStoryIds('a--1');\n      expect(result).toEqual(['a--1']);\n    });\n    it('work for an entry with children', () => {\n      const initialState = {\n        path: '/story/group-a/component-a',\n        storyId: 'component-a--story-1',\n        viewMode: 'story',\n      };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n\n      api.setIndex({\n        v: 5,\n        entries: mockEntries,\n      });\n      const result = api.findAllLeafStoryIds('component-a');\n      expect(result).toEqual(['component-a--story-1', 'component-a--story-2']);\n    });\n  });\n  describe('jumpToComponent', () => {\n    it('works forward', () => {\n      const initialState = { path: '/story/a--1', storyId: 'a--1', viewMode: 'story' };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: navigationEntries });\n      api.jumpToComponent(1);\n      expect(navigate).toHaveBeenCalledWith('/story/b-c--1', undefined);\n    });\n    it('works backwards', () => {\n      const initialState = {\n        path: '/story/b-c--1',\n        storyId: 'b-c--1',\n        viewMode: 'story',\n      };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: navigationEntries });\n      api.jumpToComponent(-1);\n      expect(navigate).toHaveBeenCalledWith('/story/a--1', undefined);\n    });\n    it('does nothing if you are in the last component and go forward', () => {\n      const initialState = {\n        path: '/story/custom-id--1',\n        storyId: 'custom-id--1',\n        viewMode: 'story',\n      };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: navigationEntries });\n      api.jumpToComponent(1);\n      expect(navigate).not.toHaveBeenCalled();\n    });\n    it('does nothing if you are at the first component and go backward', () => {\n      const initialState = { path: '/story/a--2', storyId: 'a--2', viewMode: 'story' };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: navigationEntries });\n      api.jumpToComponent(-1);\n      expect(navigate).not.toHaveBeenCalled();\n    });\n  });\n  describe('selectStory', () => {\n    it('navigates', () => {\n      const initialState = { path: '/story/a--1', storyId: 'a--1', viewMode: 'story' };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: navigationEntries });\n      api.selectStory('a--2');\n      expect(navigate).toHaveBeenCalledWith('/story/a--2', undefined);\n    });\n    it('sets view mode to docs if doc-level component is selected', () => {\n      const initialState = { path: '/docs/a--1', storyId: 'a--1', viewMode: 'docs' };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate } = moduleArgs;\n\n      api.setIndex({\n        v: 5,\n        entries: {\n          ...navigationEntries,\n          'intro--docs': {\n            type: 'docs',\n            id: 'intro--docs',\n            title: 'Intro',\n            name: 'Page',\n            importPath: './intro.mdx',\n            storiesImports: [],\n          },\n        },\n      });\n      api.selectStory('intro');\n      expect(navigate).toHaveBeenCalledWith('/docs/intro--docs', undefined);\n    });\n    it('updates lastTrackedStoryId', () => {\n      const initialState = { path: '/story/a--1', storyId: 'a--1', viewMode: 'story' };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: navigationEntries });\n      api.selectStory('a--1');\n      expect(store.getState().settings.lastTrackedStoryId).toBe('a--1');\n    });\n    it('selects first visible child when component is clicked with filtered index', () => {\n      const initialState = { path: '/story/a--1', storyId: 'a--1', viewMode: 'story' };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate, store } = moduleArgs;\n\n      // Set index with stories\n      api.setIndex({ v: 5, entries: navigationEntries });\n\n      // Set up filtered index where first child (a--1) is hidden\n      const filteredIndex = {\n        a: {\n          id: 'a',\n          type: 'component' as const,\n          name: 'a',\n          depth: 0,\n          tags: [],\n          children: ['a--1', 'a--2'],\n          importPath: './a.ts',\n        },\n        'a--2': {\n          ...navigationEntries['a--2'],\n          type: 'story' as const,\n          subtype: 'story' as const,\n          parent: 'a',\n          depth: 1,\n          tags: [],\n          prepared: false,\n          exportName: '2',\n        },\n        // Note: 'a--1' is missing from filtered index (hidden)\n      };\n\n      store.setState({ filteredIndex });\n\n      // When selecting the component, it should select the first visible child (a--2)\n      api.selectStory('a');\n      expect(navigate).toHaveBeenCalledWith('/story/a--2', undefined);\n    });\n    describe('deprecated api', () => {\n      it('allows navigating to a combination of title + name', () => {\n        const initialState = { path: '/story/a--1', storyId: 'a--1', viewMode: 'story' };\n        const moduleArgs = createMockModuleArgs({ initialState });\n        const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n        const { navigate } = moduleArgs;\n\n        api.setIndex({ v: 5, entries: navigationEntries });\n        api.selectStory('a', '2');\n        expect(navigate).toHaveBeenCalledWith('/story/a--2', undefined);\n      });\n      it('allows navigating to a given name (in the current component)', () => {\n        const initialState = { path: '/story/a--1', storyId: 'a--1', viewMode: 'story' };\n        const moduleArgs = createMockModuleArgs({ initialState });\n        const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n        const { navigate } = moduleArgs;\n\n        api.setIndex({ v: 5, entries: navigationEntries });\n        api.selectStory(undefined, '2');\n        expect(navigate).toHaveBeenCalledWith('/story/a--2', undefined);\n      });\n    });\n    it('allows navigating away from the settings pages', () => {\n      const initialState = { path: '/settings/a--1', storyId: 'a--1', viewMode: 'settings' };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: navigationEntries });\n      api.selectStory('a--2');\n      expect(navigate).toHaveBeenCalledWith('/story/a--2', undefined);\n    });\n    it('allows navigating to first story in component on call by component id', () => {\n      const initialState = { path: '/story/a--1', storyId: 'a--1', viewMode: 'story' };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: navigationEntries });\n      api.selectStory('a');\n      expect(navigate).toHaveBeenCalledWith('/story/a--1', undefined);\n    });\n    it('allows navigating to first story in group on call by group id', () => {\n      const initialState = { path: '/story/a--1', storyId: 'a--1', viewMode: 'story' };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: navigationEntries });\n      api.selectStory('b');\n      expect(navigate).toHaveBeenCalledWith('/story/b-c--1', undefined);\n    });\n    it('allows navigating to first story in component on call by title', () => {\n      const initialState = { path: '/story/a--1', storyId: 'a--1', viewMode: 'story' };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: navigationEntries });\n      api.selectStory('A');\n      expect(navigate).toHaveBeenCalledWith('/story/a--1', undefined);\n    });\n    it('allows navigating to the first story of the current component if passed nothing', () => {\n      const initialState = { path: '/story/a--1', storyId: 'a--1', viewMode: 'story' };\n      const moduleArgs = createMockModuleArgs({ initialState });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: navigationEntries });\n      api.selectStory();\n      expect(navigate).toHaveBeenCalledWith('/story/a--1', undefined);\n    });\n    describe('component permalinks', () => {\n      it('allows navigating to kind/storyname (legacy api)', () => {\n        const initialState = { path: '/story/a--1', storyId: 'a--1', viewMode: 'story' };\n        const moduleArgs = createMockModuleArgs({ initialState });\n        const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n        const { navigate } = moduleArgs;\n\n        api.setIndex({ v: 5, entries: navigationEntries });\n        api.selectStory('b/e', '1');\n        expect(navigate).toHaveBeenCalledWith('/story/custom-id--1', undefined);\n      });\n      it('allows navigating to component permalink/storyname (legacy api)', () => {\n        const initialState = { path: '/story/a--1', storyId: 'a--1', viewMode: 'story' };\n        const moduleArgs = createMockModuleArgs({ initialState });\n        const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n        const { navigate } = moduleArgs;\n\n        api.setIndex({ v: 5, entries: navigationEntries });\n        api.selectStory('custom-id', '1');\n        expect(navigate).toHaveBeenCalledWith('/story/custom-id--1', undefined);\n      });\n      it('allows navigating to first story in kind on call by kind', () => {\n        const initialState = { path: '/story/a--1', storyId: 'a--1', viewMode: 'story' };\n        const moduleArgs = createMockModuleArgs({ initialState });\n        const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n        const { navigate } = moduleArgs;\n\n        api.setIndex({ v: 5, entries: navigationEntries });\n        api.selectStory('b/e');\n        expect(navigate).toHaveBeenCalledWith('/story/custom-id--1', undefined);\n      });\n    });\n  });\n  describe('STORY_PREPARED', () => {\n    it('prepares the story', async () => {\n      const fullAPI = { setOptions: vi.fn() };\n      const initialState = { path: '/story/a--1', storyId: 'a--1', viewMode: 'story' };\n      const moduleArgs = createMockModuleArgs({ initialState, fullAPI });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { provider, store } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: mockEntries });\n\n      provider.channel.emit(STORY_PREPARED, {\n        id: 'component-a--story-1',\n        parameters: { a: 'b' },\n        args: { c: 'd' },\n      });\n      const { index } = store.getState();\n      expect(index!['component-a--story-1']).toMatchObject({\n        type: 'story',\n        subtype: 'story',\n        id: 'component-a--story-1',\n        parent: 'component-a',\n        title: 'Component A',\n        name: 'Story 1',\n        prepared: true,\n        parameters: { a: 'b' },\n        args: { c: 'd' },\n      });\n    });\n    it('sets options the first time it is called', async () => {\n      const fullAPI = { setOptions: vi.fn() };\n      const initialState = { path: '/story/a--1', storyId: 'a--1', viewMode: 'story' };\n      const moduleArgs = createMockModuleArgs({ initialState, fullAPI });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { provider } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: mockEntries });\n\n      provider.channel.emit(STORY_PREPARED, {\n        id: 'component-a--story-1',\n        parameters: { options: 'options' },\n      });\n      expect(fullAPI.setOptions).toHaveBeenCalledWith('options');\n\n      fullAPI.setOptions.mockClear();\n\n      provider.channel.emit(STORY_PREPARED, {\n        id: 'component-a--story-1',\n        parameters: { options: 'options2' },\n      });\n      expect(fullAPI.setOptions).not.toHaveBeenCalled();\n    });\n  });\n  describe('DOCS_PREPARED', () => {\n    it('prepares the docs entry', async () => {\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { provider, store } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: mockEntries });\n\n      provider.channel.emit(DOCS_PREPARED, {\n        id: 'component-a--docs',\n        parameters: { a: 'b' },\n      });\n      const { index } = store.getState();\n      expect(index!['component-a--docs']).toMatchObject({\n        type: 'docs',\n        id: 'component-a--docs',\n        parent: 'component-a',\n        title: 'Component A',\n        name: 'Docs',\n        prepared: true,\n        parameters: { a: 'b' },\n      });\n    });\n  });\n  describe('CONFIG_ERROR', () => {\n    it('sets previewInitialized to true, local', async () => {\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { provider, store } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: mockEntries });\n\n      provider.channel.emit(CONFIG_ERROR, { message: 'Failed to run configure' });\n      const { previewInitialized } = store.getState();\n      expect(previewInitialized).toBe(true);\n    });\n    it('sets previewInitialized to true, ref', async () => {\n      const fullAPI = { updateRef: vi.fn() };\n      const moduleArgs = createMockModuleArgs({ fullAPI });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { provider } = moduleArgs;\n\n      api.setIndex({ v: 5, entries: mockEntries });\n\n      getEventMetadata.mockReturnValueOnce({\n        sourceType: 'external',\n        ref: { id: 'refId', stories: { 'a--1': { args: { a: 'b' } } } },\n      } as any);\n      provider.channel.emit(CONFIG_ERROR, { message: 'Failed to run configure' });\n      expect(fullAPI.updateRef.mock.calls.length).toBe(1);\n      expect(fullAPI.updateRef.mock.calls[0][1]).toEqual({\n        previewInitialized: true,\n      });\n    });\n  });\n  describe('STORY_MISSING', () => {\n    it('sets previewInitialized to true, local', async () => {\n      const moduleArgs = createMockModuleArgs({});\n      initStories(moduleArgs as unknown as ModuleArgs);\n      const { provider, store } = moduleArgs;\n\n      provider.channel.emit(STORY_MISSING, { message: 'Failed to run configure' });\n      const { previewInitialized } = store.getState();\n      expect(previewInitialized).toBe(true);\n    });\n    it('sets previewInitialized to true, ref', async () => {\n      const fullAPI = { updateRef: vi.fn() };\n      const moduleArgs = createMockModuleArgs({ fullAPI });\n      initStories(moduleArgs as unknown as ModuleArgs);\n      const { provider } = moduleArgs;\n\n      getEventMetadata.mockReturnValueOnce({\n        sourceType: 'external',\n        ref: { id: 'refId', stories: { 'a--1': { args: { a: 'b' } } } },\n      } as any);\n      provider.channel.emit(STORY_MISSING, { message: 'Failed to run configure' });\n      expect(fullAPI.updateRef.mock.calls.length).toBe(1);\n      expect(fullAPI.updateRef.mock.calls[0][1]).toEqual({\n        previewInitialized: true,\n      });\n    });\n  });\n  describe('v2 SET_STORIES event', () => {\n    it('normalizes parameters and calls setRef for external stories', () => {\n      const fullAPI = {\n        findRef: vi.fn(),\n        setRef: vi.fn(),\n      };\n      const moduleArgs = createMockModuleArgs({ fullAPI });\n      initStories(moduleArgs as unknown as ModuleArgs);\n      const { provider, store } = moduleArgs;\n\n      getEventMetadata.mockReturnValueOnce({\n        sourceType: 'external',\n        ref: { id: 'ref' },\n      } as any);\n      const setStoriesPayload = {\n        v: 2,\n        globalParameters: { global: 'global' },\n        kindParameters: { a: { kind: 'kind' } },\n        stories: { 'a--1': { kind: 'a', parameters: { story: 'story' } } },\n      };\n      provider.channel.emit(SET_STORIES, setStoriesPayload);\n      expect(store.getState().index).toBeUndefined();\n      expect(fullAPI.setRef).toHaveBeenCalledWith(\n        'ref',\n        {\n          id: 'ref',\n          setStoriesData: {\n            'a--1': { kind: 'a', parameters: { global: 'global', kind: 'kind', story: 'story' } },\n          },\n        },\n        true\n      );\n    });\n  });\n  describe('legacy (v1) SET_STORIES event', () => {\n    it('calls setRef with stories', () => {\n      const fullAPI = {\n        findRef: vi.fn(),\n        setRef: vi.fn(),\n      };\n      const moduleArgs = createMockModuleArgs({ fullAPI });\n      initStories(moduleArgs as unknown as ModuleArgs);\n      const { provider, store } = moduleArgs;\n\n      getEventMetadata.mockReturnValueOnce({\n        sourceType: 'external',\n        ref: { id: 'ref' },\n      } as any);\n      const setStoriesPayload = {\n        stories: { 'a--1': {} },\n      };\n      provider.channel.emit(SET_STORIES, setStoriesPayload);\n      expect(store.getState().index).toBeUndefined();\n      expect(fullAPI.setRef).toHaveBeenCalledWith(\n        'ref',\n        {\n          id: 'ref',\n          setStoriesData: {\n            'a--1': {},\n          },\n        },\n        true\n      );\n    });\n  });\n  describe('experimental_setFilter', () => {\n    it('is included in the initial state', async () => {\n      const moduleArgs = createMockModuleArgs({});\n      const { state, api } = initStories(moduleArgs as unknown as ModuleArgs);\n\n      await api.setIndex({ v: 5, entries: mockEntries });\n\n      expect(state).toEqual(\n        expect.objectContaining({\n          defaultExcludedTagFilters: expect.arrayContaining([]),\n          defaultIncludedTagFilters: expect.arrayContaining([]),\n          excludedTagFilters: expect.arrayContaining([]),\n          includedTagFilters: expect.arrayContaining([]),\n          filters: expect.objectContaining({\n            'static-filter': expect.any(Function),\n            'tags-filter': expect.any(Function),\n          }),\n          tagPresets: expect.objectContaining({}),\n        })\n      );\n    });\n\n    it('updates state', async () => {\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n\n      await api.setIndex({ v: 5, entries: mockEntries });\n\n      api.experimental_setFilter('myCustomFilter', () => true);\n\n      expect(store.getState()).toEqual(\n        expect.objectContaining({\n          filters: {\n            myCustomFilter: expect.any(Function),\n          },\n        })\n      );\n    });\n\n    it('can filter', async () => {\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n\n      await api.setIndex({ v: 5, entries: navigationEntries });\n      await api.experimental_setFilter('myCustomFilter', (item: any) => item.id.startsWith('a'));\n\n      const { filteredIndex } = store.getState();\n\n      expect(filteredIndex).toMatchInlineSnapshot(`\n        {\n          \"a\": {\n            \"children\": [\n              \"a--1\",\n              \"a--2\",\n            ],\n            \"depth\": 0,\n            \"id\": \"a\",\n            \"importPath\": \"./a.ts\",\n            \"name\": \"a\",\n            \"parent\": undefined,\n            \"renderLabel\": undefined,\n            \"tags\": [],\n            \"type\": \"component\",\n          },\n          \"a--1\": {\n            \"depth\": 1,\n            \"id\": \"a--1\",\n            \"importPath\": \"./a.ts\",\n            \"name\": \"1\",\n            \"parent\": \"a\",\n            \"prepared\": false,\n            \"renderLabel\": undefined,\n            \"subtype\": \"story\",\n            \"tags\": [],\n            \"title\": \"a\",\n            \"type\": \"story\",\n          },\n          \"a--2\": {\n            \"depth\": 1,\n            \"id\": \"a--2\",\n            \"importPath\": \"./a.ts\",\n            \"name\": \"2\",\n            \"parent\": \"a\",\n            \"prepared\": false,\n            \"renderLabel\": undefined,\n            \"subtype\": \"story\",\n            \"tags\": [],\n            \"title\": \"a\",\n            \"type\": \"story\",\n          },\n        }\n      `);\n    });\n\n    it('can filter on status', async () => {\n      vi.mock('../stores/status');\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n\n      await api.setIndex({ v: 5, entries: navigationEntries });\n      await api.experimental_setFilter(\n        'myCustomFilter',\n        (item) =>\n          item.statuses !== undefined &&\n          Object.values(item.statuses).some((status) => status.value === 'status-value:pending')\n      );\n\n      // empty, because there are no stories with status\n      expect(store.getState().filteredIndex).toMatchInlineSnapshot('{}');\n\n      // setting status should update the index\n      fullStatusStore.set([\n        {\n          typeId: 'a-addon-id',\n          storyId: 'a--1',\n          value: 'status-value:pending',\n          title: 'an addon title',\n          description: 'an addon description',\n        },\n        {\n          typeId: 'a-addon-id',\n          storyId: 'a--2',\n          value: 'status-value:success',\n          title: 'an addon title',\n          description: 'an addon description',\n        },\n      ]);\n\n      await vi.waitFor(() => {\n        expect(store.getState().filteredIndex).toMatchInlineSnapshot(`\n          {\n            \"a\": {\n              \"children\": [\n                \"a--1\",\n              ],\n              \"depth\": 0,\n              \"id\": \"a\",\n              \"importPath\": \"./a.ts\",\n              \"name\": \"a\",\n              \"parent\": undefined,\n              \"renderLabel\": undefined,\n              \"tags\": [],\n              \"type\": \"component\",\n            },\n            \"a--1\": {\n              \"depth\": 1,\n              \"id\": \"a--1\",\n              \"importPath\": \"./a.ts\",\n              \"name\": \"1\",\n              \"parent\": \"a\",\n              \"prepared\": false,\n              \"renderLabel\": undefined,\n              \"subtype\": \"story\",\n              \"tags\": [],\n              \"title\": \"a\",\n              \"type\": \"story\",\n            },\n          }\n        `);\n      });\n    });\n\n    it('persists filter when index is updated', async () => {\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n\n      await api.setIndex({ v: 5, entries: navigationEntries });\n      await api.experimental_setFilter('myCustomFilter', (item: any) => item.id.startsWith('a'));\n\n      await api.setIndex({ v: 5, entries: navigationEntries });\n\n      const { filteredIndex } = store.getState();\n\n      expect(filteredIndex).toMatchInlineSnapshot(`\n        {\n          \"a\": {\n            \"children\": [\n              \"a--1\",\n              \"a--2\",\n            ],\n            \"depth\": 0,\n            \"id\": \"a\",\n            \"importPath\": \"./a.ts\",\n            \"name\": \"a\",\n            \"parent\": undefined,\n            \"renderLabel\": undefined,\n            \"tags\": [],\n            \"type\": \"component\",\n          },\n          \"a--1\": {\n            \"depth\": 1,\n            \"id\": \"a--1\",\n            \"importPath\": \"./a.ts\",\n            \"name\": \"1\",\n            \"parent\": \"a\",\n            \"prepared\": false,\n            \"renderLabel\": undefined,\n            \"subtype\": \"story\",\n            \"tags\": [],\n            \"title\": \"a\",\n            \"type\": \"story\",\n          },\n          \"a--2\": {\n            \"depth\": 1,\n            \"id\": \"a--2\",\n            \"importPath\": \"./a.ts\",\n            \"name\": \"2\",\n            \"parent\": \"a\",\n            \"prepared\": false,\n            \"renderLabel\": undefined,\n            \"subtype\": \"story\",\n            \"tags\": [],\n            \"title\": \"a\",\n            \"type\": \"story\",\n          },\n        }\n      `);\n    });\n  });\n\n  describe('parseStatusesParam', () => {\n    it('returns empty arrays for undefined input', () => {\n      expect(parseStatusesParam(undefined)).toEqual({ included: [], excluded: [] });\n    });\n\n    it('returns empty arrays for empty string', () => {\n      expect(parseStatusesParam('')).toEqual({ included: [], excluded: [] });\n    });\n\n    it('parses included status short names', () => {\n      const result = parseStatusesParam('new;modified;affected');\n      expect(result.included).toEqual([\n        'status-value:new',\n        'status-value:modified',\n        'status-value:affected',\n      ]);\n      expect(result.excluded).toEqual([]);\n    });\n\n    it('parses excluded status short names with ! prefix', () => {\n      const result = parseStatusesParam('!error;!warning');\n      expect(result.included).toEqual([]);\n      expect(result.excluded).toEqual(['status-value:error', 'status-value:warning']);\n    });\n\n    it('parses mixed included and excluded', () => {\n      const result = parseStatusesParam('new;!error;pending');\n      expect(result.included).toEqual(['status-value:new', 'status-value:pending']);\n      expect(result.excluded).toEqual(['status-value:error']);\n    });\n\n    it('silently ignores unknown short names', () => {\n      const result = parseStatusesParam('new;unknownstatus;modified');\n      expect(result.included).toEqual(['status-value:new', 'status-value:modified']);\n      expect(result.excluded).toEqual([]);\n    });\n\n    it('parses all known status values', () => {\n      const result = parseStatusesParam(\n        'new;modified;affected;error;warning;success;pending;unknown'\n      );\n      expect(result.included).toEqual([\n        'status-value:new',\n        'status-value:modified',\n        'status-value:affected',\n        'status-value:error',\n        'status-value:warning',\n        'status-value:success',\n        'status-value:pending',\n        'status-value:unknown',\n      ]);\n    });\n  });\n\n  describe('serializeStatusesParam', () => {\n    it('returns undefined for empty arrays', () => {\n      expect(serializeStatusesParam([], [])).toBeUndefined();\n    });\n\n    it('serializes included status values', () => {\n      expect(serializeStatusesParam(['status-value:new', 'status-value:modified'], [])).toBe(\n        'modified;new'\n      );\n    });\n\n    it('serializes excluded status values with ! prefix', () => {\n      expect(serializeStatusesParam([], ['status-value:error', 'status-value:warning'])).toBe(\n        '!error;!warning'\n      );\n    });\n\n    it('serializes mixed included and excluded', () => {\n      expect(serializeStatusesParam(['status-value:new'], ['status-value:error'])).toBe(\n        'new;!error'\n      );\n    });\n\n    it('round-trips with parseStatusesParam', () => {\n      const included = ['status-value:new', 'status-value:pending'] as const;\n      const excluded = ['status-value:error'] as const;\n      const serialized = serializeStatusesParam([...included], [...excluded]);\n      const parsed = parseStatusesParam(serialized);\n      expect(parsed.included).toEqual(included);\n      expect(parsed.excluded).toEqual(excluded);\n    });\n  });\n\n  describe('status filter state', () => {\n    it('initializes with empty status filters', () => {\n      const moduleArgs = createMockModuleArgs({});\n      const { state } = initStories(moduleArgs as unknown as ModuleArgs);\n      expect(state.includedStatusFilters).toEqual([]);\n      expect(state.excludedStatusFilters).toEqual([]);\n    });\n\n    it('initializes status filters from URL statuses param', () => {\n      const moduleArgs = createMockModuleArgs({\n        initialState: {\n          location: { search: '?path=/story/a--1&statuses=new%3Bmodified' } as any,\n        } as any,\n      });\n      const { state } = initStories({\n        ...(moduleArgs as unknown as ModuleArgs),\n        state: {\n          location: { search: '?statuses=new;modified' } as any,\n        } as any,\n      });\n      // 'new' and 'modified' are both included statuses from the URL param\n      expect(state.includedStatusFilters).toEqual(['status-value:new', 'status-value:modified']);\n      expect(state.excludedStatusFilters).toEqual([]);\n    });\n\n    it('addStatusFilters adds to included list', async () => {\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n\n      await api.setIndex({ v: 5, entries: navigationEntries });\n      await api.addStatusFilters(['status-value:new'], false);\n\n      const { includedStatusFilters, excludedStatusFilters } = store.getState();\n      expect(includedStatusFilters).toEqual(['status-value:new']);\n      expect(excludedStatusFilters).toEqual([]);\n    });\n\n    it('addStatusFilters adds to excluded list when excluded=true', async () => {\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n\n      await api.setIndex({ v: 5, entries: navigationEntries });\n      await api.addStatusFilters(['status-value:error'], true);\n\n      const { includedStatusFilters, excludedStatusFilters } = store.getState();\n      expect(includedStatusFilters).toEqual([]);\n      expect(excludedStatusFilters).toEqual(['status-value:error']);\n    });\n\n    it('addStatusFilters moves a status from included to excluded', async () => {\n      const moduleArgs = createMockModuleArgs({\n        initialState: {\n          includedStatusFilters: ['status-value:new'],\n          excludedStatusFilters: [],\n        } as any,\n      });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n\n      await api.setIndex({ v: 5, entries: navigationEntries });\n      await api.addStatusFilters(['status-value:new'], true);\n\n      const { includedStatusFilters, excludedStatusFilters } = store.getState();\n      expect(includedStatusFilters).toEqual([]);\n      expect(excludedStatusFilters).toEqual(['status-value:new']);\n    });\n\n    it('removeStatusFilters removes from both included and excluded', async () => {\n      const moduleArgs = createMockModuleArgs({\n        initialState: {\n          includedStatusFilters: ['status-value:new', 'status-value:modified'],\n          excludedStatusFilters: ['status-value:error'],\n        } as any,\n      });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n\n      await api.setIndex({ v: 5, entries: navigationEntries });\n      await api.removeStatusFilters(['status-value:new', 'status-value:error']);\n\n      const { includedStatusFilters, excludedStatusFilters } = store.getState();\n      expect(includedStatusFilters).toEqual(['status-value:modified']);\n      expect(excludedStatusFilters).toEqual([]);\n    });\n\n    it('resetStatusFilters clears both included and excluded', async () => {\n      const moduleArgs = createMockModuleArgs({\n        initialState: {\n          includedStatusFilters: ['status-value:new'],\n          excludedStatusFilters: ['status-value:error'],\n        } as any,\n      });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n\n      await api.setIndex({ v: 5, entries: navigationEntries });\n      await api.resetStatusFilters();\n\n      const { includedStatusFilters, excludedStatusFilters } = store.getState();\n      expect(includedStatusFilters).toEqual([]);\n      expect(excludedStatusFilters).toEqual([]);\n    });\n\n    it('setAllStatusFilters replaces both included and excluded lists', async () => {\n      const moduleArgs = createMockModuleArgs({\n        initialState: {\n          includedStatusFilters: ['status-value:new'],\n          excludedStatusFilters: ['status-value:error'],\n        } as any,\n      });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n\n      await api.setIndex({ v: 5, entries: navigationEntries });\n      await api.setAllStatusFilters(\n        ['status-value:modified', 'status-value:affected'],\n        ['status-value:warning']\n      );\n\n      const { includedStatusFilters, excludedStatusFilters } = store.getState();\n      expect(includedStatusFilters).toEqual(['status-value:modified', 'status-value:affected']);\n      expect(excludedStatusFilters).toEqual(['status-value:warning']);\n    });\n  });\n\n  describe('computeStatusFilterFn (via experimental_setFilter)', () => {\n    it('passes through all stories when both included and excluded are empty', async () => {\n      vi.mock('../stores/status');\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n\n      await api.setIndex({ v: 5, entries: navigationEntries });\n      // no status filters set - all stories should pass\n      const { filteredIndex } = store.getState();\n      expect(Object.keys(filteredIndex!)).toContain('a--1');\n      expect(Object.keys(filteredIndex!)).toContain('a--2');\n    });\n\n    it('applies OR logic within included status filters', async () => {\n      vi.mock('../stores/status');\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n\n      await api.setIndex({ v: 5, entries: navigationEntries });\n\n      fullStatusStore.set([\n        {\n          typeId: 'addon-id',\n          storyId: 'a--1',\n          value: 'status-value:new',\n          title: 'title',\n          description: 'desc',\n        },\n        {\n          typeId: 'addon-id',\n          storyId: 'a--2',\n          value: 'status-value:error',\n          title: 'title',\n          description: 'desc',\n        },\n      ]);\n\n      // Include only 'new' - only a--1 should appear (has 'new'), a--2 has 'error' only\n      await api.addStatusFilters(['status-value:new'], false);\n\n      await vi.waitFor(() => {\n        const { filteredIndex } = store.getState();\n        expect(Object.keys(filteredIndex!)).toContain('a--1');\n        expect(Object.keys(filteredIndex!)).not.toContain('a--2');\n      });\n    });\n\n    it('applies exclude logic: story with excluded status is hidden', async () => {\n      vi.mock('../stores/status');\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n\n      await api.setIndex({ v: 5, entries: navigationEntries });\n\n      fullStatusStore.set([\n        {\n          typeId: 'addon-id',\n          storyId: 'a--1',\n          value: 'status-value:error',\n          title: 'title',\n          description: 'desc',\n        },\n        {\n          typeId: 'addon-id',\n          storyId: 'a--2',\n          value: 'status-value:success',\n          title: 'title',\n          description: 'desc',\n        },\n      ]);\n\n      // Exclude 'error' - a--1 should be hidden, a--2 with 'success' should pass\n      await api.addStatusFilters(['status-value:error'], true);\n\n      await vi.waitFor(() => {\n        const { filteredIndex } = store.getState();\n        expect(Object.keys(filteredIndex!)).not.toContain('a--1');\n        expect(Object.keys(filteredIndex!)).toContain('a--2');\n      });\n    });\n\n    it('story with no statuses is hidden when included filters are active', async () => {\n      vi.mock('../stores/status');\n      const moduleArgs = createMockModuleArgs({});\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { store } = moduleArgs;\n\n      await api.setIndex({ v: 5, entries: navigationEntries });\n\n      // Set status only for a--1, leave a--2 with no status\n      fullStatusStore.set([\n        {\n          typeId: 'addon-id',\n          storyId: 'a--1',\n          value: 'status-value:new',\n          title: 'title',\n          description: 'desc',\n        },\n      ]);\n\n      // Include 'new' - only a--1 passes (a--2 has no status so fails include check)\n      await api.addStatusFilters(['status-value:new'], false);\n\n      await vi.waitFor(() => {\n        const { filteredIndex } = store.getState();\n        expect(Object.keys(filteredIndex!)).toContain('a--1');\n        expect(Object.keys(filteredIndex!)).not.toContain('a--2');\n      });\n    });\n  });\n\n  describe('selectFirstStory with status filters', () => {\n    it('uses filteredIndex when status filters are active', () => {\n      const moduleArgs = createMockModuleArgs({\n        initialState: {\n          path: '/',\n          index: {\n            'a--1': { type: 'story', id: 'a--1', depth: 0 } as any,\n            'a--2': { type: 'story', id: 'a--2', depth: 0 } as any,\n          },\n          filteredIndex: {\n            'a--2': { type: 'story', id: 'a--2', depth: 0 } as any,\n          },\n          includedStatusFilters: ['status-value:new'],\n          excludedStatusFilters: [],\n          includedTagFilters: [],\n          excludedTagFilters: [],\n        } as any,\n      });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate } = moduleArgs;\n\n      api.selectFirstStory();\n      expect(navigate).toHaveBeenCalledWith('/story/a--2', undefined);\n    });\n\n    it('suppresses navigation when status filters active but filteredIndex is empty', () => {\n      const moduleArgs = createMockModuleArgs({\n        initialState: {\n          path: '/',\n          index: {\n            'a--1': { type: 'story', id: 'a--1', depth: 0 } as any,\n          },\n          filteredIndex: {},\n          includedStatusFilters: ['status-value:new'],\n          excludedStatusFilters: [],\n          includedTagFilters: [],\n          excludedTagFilters: [],\n        } as any,\n      });\n      const { api } = initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate } = moduleArgs;\n\n      api.selectFirstStory();\n      expect(navigate).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('STORY_SPECIFIED handler with status filters', () => {\n    it('navigates to first filtered story when active status filters exclude the emitted story', async () => {\n      const moduleArgs = createMockModuleArgs({\n        initialState: {\n          path: '/',\n          index: {\n            'a--1': { type: 'story', id: 'a--1' } as any,\n            'a--2': { type: 'story', id: 'a--2' } as any,\n          },\n          filteredIndex: {\n            'a--2': { type: 'story', id: 'a--2' } as any,\n          },\n          includedStatusFilters: ['status-value:new'],\n          excludedStatusFilters: [],\n          includedTagFilters: [],\n          excludedTagFilters: [],\n        } as any,\n      });\n      initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate, provider } = moduleArgs;\n\n      // a--1 is NOT in filteredIndex, so it should navigate to a--2 instead\n      provider.channel.emit(STORY_SPECIFIED, { storyId: 'a--1', viewMode: 'story' });\n      expect(navigate).toHaveBeenCalledWith('/story/a--2', undefined);\n    });\n\n    it('suppresses navigation when active status filters exclude the emitted story and filteredIndex is empty', async () => {\n      const moduleArgs = createMockModuleArgs({\n        initialState: {\n          path: '/',\n          index: {\n            'a--1': { type: 'story', id: 'a--1' } as any,\n          },\n          filteredIndex: {},\n          includedStatusFilters: ['status-value:new'],\n          excludedStatusFilters: [],\n          includedTagFilters: [],\n          excludedTagFilters: [],\n        } as any,\n      });\n      initStories(moduleArgs as unknown as ModuleArgs);\n      const { navigate, provider } = moduleArgs;\n\n      provider.channel.emit(STORY_SPECIFIED, { storyId: 'a--1', viewMode: 'story' });\n      expect(navigate).not.toHaveBeenCalled();\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager-api/tests/tags.test.js",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { parseTagsParam, serializeTagsParam } from '../modules/tags';\n\ndescribe('parseTagsParam', () => {\n  it('returns empty arrays for falsy input', () => {\n    expect(parseTagsParam(undefined)).toEqual({ included: [], excluded: [] });\n    expect(parseTagsParam('')).toEqual({ included: [], excluded: [] });\n  });\n\n  it('parses include/exclude entries and maps known built-in URL tags', () => {\n    expect(\n      parseTagsParam('$docs;$play;$test;custom;!blocked;!$docs;!$play;!$test;!$unknown')\n    ).toEqual({\n      included: ['_docs', '_play', '_test', 'custom'],\n      excluded: ['blocked', '_docs', '_play', '_test', '$unknown'],\n    });\n  });\n\n  it('ignores empty segments between separators', () => {\n    expect(parseTagsParam('a;;!b;;;')).toEqual({\n      included: ['a'],\n      excluded: ['b'],\n    });\n  });\n});\n\ndescribe('serializeTagsParam', () => {\n  it('returns empty string when no tags are provided', () => {\n    expect(serializeTagsParam([], [])).toBe('');\n  });\n\n  it('serializes include/exclude entries and maps known built-in internal tags', () => {\n    expect(\n      serializeTagsParam(\n        ['_play', '_docs', '_test', 'custom', '_unknown'],\n        ['blocked', '_docs', '_play', '_test', '_unknown']\n      )\n    ).toEqual('$docs;$play;$test;_unknown;custom;!$docs;!$play;!$test;!_unknown;!blocked');\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager-api/tests/url.test.js",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport {\n  GLOBALS_UPDATED,\n  SET_CURRENT_STORY,\n  UPDATE_QUERY_PARAMS,\n} from 'storybook/internal/core-events';\n\nimport { global } from '@storybook/global';\n\nimport EventEmitter from 'events';\n\nimport { init as initURL } from '../modules/url';\n\nvi.mock('storybook/internal/client-logger');\nvi.mock('@storybook/global', () => ({\n  global: {\n    window: {\n      location: {\n        hash: '',\n        href: 'http://localhost:6006',\n        origin: 'http://localhost:6006',\n      },\n    },\n    STORYBOOK_NETWORK_ADDRESS: 'http://192.168.1.1:6006/',\n  },\n}));\n\nconst storyState = (storyId) => ({\n  path: `/story/${storyId}`,\n  storyId,\n  viewMode: 'story',\n});\n\ndescribe('initial state', () => {\n  describe('config query parameters', () => {\n    it('handles full parameter', () => {\n      const navigate = vi.fn();\n      const location = { search: '?' + new URLSearchParams({ full: '1' }).toString() };\n\n      const store = {\n        state: { ...storyState('test--story'), location },\n        getState() {\n          return this.state;\n        },\n        setState(value) {\n          this.state = { ...this.state, ...value };\n        },\n      };\n\n      const {\n        state: { layout },\n      } = initURL(\n        { navigate, state: { location }, provider: { channel: new EventEmitter() } },\n        store\n      );\n\n      expect(layout).toMatchObject({\n        bottomPanelHeight: 0,\n        navSize: 0,\n        rightPanelWidth: 0,\n      });\n    });\n\n    it('handles nav parameter', () => {\n      const navigate = vi.fn();\n      const location = { search: '?' + new URLSearchParams({ nav: '0' }).toString() };\n\n      const {\n        state: { layout },\n      } = initURL({ navigate, state: { location }, provider: { channel: new EventEmitter() } });\n\n      expect(layout).toMatchObject({ navSize: 0 });\n    });\n\n    it('handles shortcuts parameter', () => {\n      const navigate = vi.fn();\n      const location = { search: '?' + new URLSearchParams({ shortcuts: '0' }).toString() };\n\n      const {\n        state: { ui },\n      } = initURL({ navigate, state: { location }, provider: { channel: new EventEmitter() } });\n\n      expect(ui).toEqual({ enableShortcuts: false });\n    });\n\n    it('handles panel parameter, bottom', () => {\n      const navigate = vi.fn();\n      const location = { search: '?' + new URLSearchParams({ panel: 'bottom' }).toString() };\n\n      const {\n        state: { layout },\n      } = initURL({ navigate, state: { location }, provider: { channel: new EventEmitter() } });\n\n      expect(layout).toMatchObject({ panelPosition: 'bottom' });\n    });\n\n    it('handles panel parameter, right', () => {\n      const navigate = vi.fn();\n      const location = { search: '?' + new URLSearchParams({ panel: 'right' }).toString() };\n\n      const {\n        state: { layout },\n      } = initURL({ navigate, state: { location }, provider: { channel: new EventEmitter() } });\n\n      expect(layout).toMatchObject({ panelPosition: 'right' });\n    });\n\n    it('handles panel parameter, 0', () => {\n      const navigate = vi.fn();\n      const location = { search: '?' + new URLSearchParams({ panel: '0' }).toString() };\n\n      const {\n        state: { layout },\n      } = initURL({ navigate, state: { location }, provider: { channel: new EventEmitter() } });\n\n      expect(layout).toMatchObject({\n        bottomPanelHeight: 0,\n        rightPanelWidth: 0,\n      });\n    });\n  });\n});\n\ndescribe('queryParams', () => {\n  it('removes a key from customQueryParams when null is passed', () => {\n    let state = { customQueryParams: { tags: 'a11y', args: 'foo:bar' } };\n    const store = {\n      setState: (change) => {\n        state = { ...state, ...change };\n      },\n      getState: () => state,\n    };\n    const channel = new EventEmitter();\n    const navigate = vi.fn();\n    const { api } = initURL({\n      state: { location: { search: '?tags=a11y&args=foo:bar', path: '/', hash: '' } },\n      navigate,\n      store,\n      provider: { channel },\n    });\n\n    api.applyQueryParams({ tags: null }, { replace: true });\n\n    // tags key must be absent from stored customQueryParams\n    expect(state.customQueryParams).not.toHaveProperty('tags');\n    expect(state.customQueryParams).toHaveProperty('args', 'foo:bar');\n\n    // subsequent URL updates must not reintroduce tags\n    api.applyQueryParams({ args: 'foo:baz' }, { replace: true });\n    expect(navigate).toHaveBeenLastCalledWith(\n      expect.not.stringContaining('tags='),\n      expect.anything()\n    );\n    expect(state.customQueryParams).not.toHaveProperty('tags');\n  });\n\n  it('lets your read out parameters you set previously', () => {\n    let state = {};\n    const store = {\n      setState: (change) => {\n        state = { ...state, ...change };\n      },\n      getState: () => state,\n    };\n    const channel = new EventEmitter();\n    const { api } = initURL({\n      state: { location: { search: '' } },\n      navigate: vi.fn(),\n      store,\n      provider: { channel },\n    });\n\n    const listener = vi.fn();\n\n    channel.on(UPDATE_QUERY_PARAMS, listener);\n\n    api.setQueryParams({ foo: 'bar' });\n\n    expect(api.getQueryParam('foo')).toEqual('bar');\n\n    expect(listener).toHaveBeenCalledWith({ foo: 'bar' });\n  });\n});\n\ndescribe('initModule', () => {\n  const store = {\n    state: {},\n    getState() {\n      return this.state;\n    },\n    setState(value) {\n      this.state = { ...this.state, ...value };\n    },\n  };\n\n  const fullAPI = {\n    showReleaseNotesOnLaunch: vi.fn(),\n  };\n\n  beforeEach(() => {\n    store.state = {};\n    fullAPI.callbacks = {};\n  });\n\n  it('updates args param on SET_CURRENT_STORY', async () => {\n    const location = {};\n    store.setState({ ...storyState('test--story'), location });\n\n    const navigate = vi.fn();\n    const channel = new EventEmitter();\n    initURL({\n      store,\n      provider: { channel },\n      state: { location },\n      navigate,\n      fullAPI: Object.assign(fullAPI, {\n        getCurrentStoryData: () => ({\n          type: 'story',\n          subtype: 'story',\n          args: { a: 1, b: 2 },\n          initialArgs: { a: 1, b: 1 },\n        }),\n      }),\n    });\n    channel.emit(SET_CURRENT_STORY);\n    expect(navigate).toHaveBeenCalledWith(\n      '/story/test--story&args=b:2',\n      expect.objectContaining({ replace: true })\n    );\n    expect(store.getState().customQueryParams).toEqual({ args: 'b:2' });\n  });\n\n  it('updates globals param on GLOBALS_UPDATED', async () => {\n    const location = {};\n    store.setState({ ...storyState('test--story'), location });\n\n    const navigate = vi.fn();\n    const channel = new EventEmitter();\n    initURL({ store, provider: { channel }, state: { location }, navigate, fullAPI });\n\n    channel.emit(GLOBALS_UPDATED, {\n      userGlobals: { a: 2 },\n      storyGlobals: {},\n      globals: { a: 2 },\n      initialGlobals: { a: 1, b: 1 },\n    });\n    expect(navigate).toHaveBeenCalledWith(\n      '/story/test--story&globals=a:2',\n      expect.objectContaining({ replace: true })\n    );\n    expect(store.getState().customQueryParams).toEqual({ globals: 'a:2' });\n  });\n\n  it('adds url params alphabetically', async () => {\n    const location = {};\n    store.setState({ ...storyState('test--story'), customQueryParams: { full: 1 }, location });\n    const navigate = vi.fn();\n    const channel = new EventEmitter();\n    const { api } = initURL({\n      store,\n      provider: { channel },\n      state: { location },\n      navigate,\n      fullAPI: Object.assign(fullAPI, {\n        getCurrentStoryData: () => ({ type: 'story', subtype: 'story', args: { a: 1 } }),\n      }),\n    });\n\n    channel.emit(GLOBALS_UPDATED, {\n      userGlobals: { g: 2 },\n      storyGlobals: {},\n      globals: { g: 2 },\n      initialGlobals: {},\n    });\n    expect(navigate).toHaveBeenCalledWith(\n      '/story/test--story&full=1&globals=g:2',\n      expect.objectContaining({ replace: true })\n    );\n\n    channel.emit(SET_CURRENT_STORY);\n    expect(navigate).toHaveBeenCalledWith(\n      '/story/test--story&args=a:1&full=1&globals=g:2',\n      expect.objectContaining({ replace: true })\n    );\n  });\n});\n\ndescribe('getStoryHrefs', () => {\n  let state = {};\n  const store = {\n    setState: (change) => {\n      state = { ...state, ...change };\n    },\n    getState: () => state,\n  };\n\n  it('returns manager and preview URLs for a story', () => {\n    const { api, state } = initURL({\n      store,\n      provider: { channel: new EventEmitter() },\n      state: { location: { pathname: '/', search: '' } },\n      navigate: vi.fn(),\n      fullAPI: { getCurrentStoryData: () => ({ id: 'test--story' }) },\n    });\n    store.setState(state);\n\n    const { managerHref, previewHref } = api.getStoryHrefs('test--story');\n    expect(managerHref).toEqual('/?path=/story/test--story');\n    expect(previewHref).toEqual('/iframe.html?id=test--story&viewMode=story');\n  });\n\n  it('retains args and globals from the URL', () => {\n    const { api, state } = initURL({\n      store,\n      provider: { channel: new EventEmitter() },\n      state: { location: { pathname: '/', search: '?args=a:1&globals=b:2' } },\n      navigate: vi.fn(),\n      fullAPI: { getCurrentStoryData: () => ({ id: 'test--story' }) },\n    });\n    store.setState(state);\n\n    const { managerHref, previewHref } = api.getStoryHrefs('test--story');\n    expect(managerHref).toContain('&args=a:1&globals=b:2');\n    expect(previewHref).toContain('&args=a:1&globals=b:2');\n  });\n\n  it('retains args with special values', () => {\n    const { api, state } = initURL({\n      store,\n      provider: { channel: new EventEmitter() },\n      state: { location: { pathname: '/', search: '?args=a:!null;b:!hex(f00);c:!undefined' } },\n      navigate: vi.fn(),\n      fullAPI: { getCurrentStoryData: () => ({ id: 'test--story' }) },\n    });\n    store.setState(state);\n\n    const { managerHref, previewHref } = api.getStoryHrefs('test--story');\n    expect(managerHref).toContain('&args=a:!null;b:!hex(f00);c:!undefined');\n    expect(previewHref).toContain('&args=a:!null;b:!hex(f00);c:!undefined');\n  });\n\n  it('drops args but retains globals when changing stories', () => {\n    const { api, state } = initURL({\n      store,\n      provider: { channel: new EventEmitter() },\n      state: { location: { pathname: '/', search: '?args=a:1&globals=b:2' } },\n      navigate: vi.fn(),\n      fullAPI: { getCurrentStoryData: () => ({ id: 'test--story' }) },\n    });\n    store.setState(state);\n\n    const { managerHref, previewHref } = api.getStoryHrefs('test--another-story');\n    expect(managerHref).toEqual('/?path=/story/test--another-story&globals=b:2');\n    expect(previewHref).toEqual('/iframe.html?id=test--another-story&viewMode=story&globals=b:2');\n  });\n\n  it('supports disabling inheritance of args and globals', () => {\n    const { api, state } = initURL({\n      store,\n      provider: { channel: new EventEmitter() },\n      state: { location: { pathname: '/', search: '?args=a:1&globals=b:2' } },\n      navigate: vi.fn(),\n      fullAPI: { getCurrentStoryData: () => ({ id: 'test--story' }) },\n    });\n    store.setState(state);\n\n    const { managerHref, previewHref } = api.getStoryHrefs('test--story', {\n      inheritArgs: false,\n      inheritGlobals: false,\n    });\n    expect(managerHref).toEqual('/?path=/story/test--story');\n    expect(previewHref).toEqual('/iframe.html?id=test--story&viewMode=story');\n  });\n\n  it('supports extra args and globals with merging', () => {\n    const { api, state } = initURL({\n      store,\n      provider: { channel: new EventEmitter() },\n      state: { location: { pathname: '/', search: '?args=a:1;b:2&globals=c:3;d:4' } },\n      navigate: vi.fn(),\n      fullAPI: { getCurrentStoryData: () => ({ id: 'test--story' }) },\n    });\n    store.setState(state);\n\n    const { managerHref, previewHref } = api.getStoryHrefs('test--story', {\n      queryParams: { args: 'a:2;c:3', globals: 'd:5' },\n    });\n    expect(managerHref).toContain('&args=a:2;b:2;c:3&globals=c:3;d:5');\n    expect(previewHref).toContain('&args=a:2;b:2;c:3&globals=c:3;d:5');\n  });\n\n  it('supports additional query params, including nested objects', () => {\n    const { api, state } = initURL({\n      store,\n      provider: { channel: new EventEmitter() },\n      state: { location: { pathname: '/', search: '?args=a:1&globals=b:2' } },\n      navigate: vi.fn(),\n      fullAPI: { getCurrentStoryData: () => ({ id: 'test--story' }) },\n    });\n    store.setState(state);\n\n    const { managerHref, previewHref } = api.getStoryHrefs('test--story', {\n      queryParams: {\n        one: 1,\n        foo: { bar: 'baz' },\n        id: 'not-allowed-in-preview',\n        viewMode: 'not-allowed-in-preview',\n      },\n    });\n    expect(managerHref).toContain('&args=a:1&globals=b:2&one=1&foo.bar=baz');\n    expect(previewHref).toContain('&args=a:1&globals=b:2&one=1&foo.bar=baz');\n\n    expect(managerHref).toContain('id=not-allowed-in-preview');\n    expect(previewHref).not.toContain('id=not-allowed-in-preview');\n\n    expect(managerHref).toContain('viewMode=not-allowed-in-preview');\n    expect(previewHref).not.toContain('viewMode=not-allowed-in-preview');\n  });\n\n  it('correctly preserves args and globals encoding', () => {\n    const { api, state } = initURL({\n      store,\n      provider: { channel: new EventEmitter() },\n      state: { location: { pathname: '/', search: '?args=equal:g%3Dh&globals=ampersand:c%26d' } },\n      navigate: vi.fn(),\n      fullAPI: { getCurrentStoryData: () => ({ id: 'test--story' }) },\n    });\n    store.setState(state);\n\n    const { managerHref, previewHref } = api.getStoryHrefs('test--story');\n    expect(managerHref).toContain('&args=equal:g%3Dh&globals=ampersand:c%26d');\n    expect(previewHref).toContain('&args=equal:g%3Dh&globals=ampersand:c%26d');\n  });\n\n  it('correctly encodes query params', () => {\n    const { api, state } = initURL({\n      store,\n      provider: { channel: new EventEmitter() },\n      state: { location: { pathname: '/' } },\n      navigate: vi.fn(),\n      fullAPI: { getCurrentStoryData: () => ({ id: 'test--story' }) },\n    });\n    store.setState(state);\n\n    const { managerHref, previewHref } = api.getStoryHrefs('test--story', {\n      queryParams: { equal: 'a=b', ampersand: 'c&d' },\n    });\n    expect(managerHref).toContain('&equal=a%3Db&ampersand=c%26d');\n    expect(previewHref).toContain('&equal=a%3Db&ampersand=c%26d');\n  });\n\n  it('supports returning absolute URLs using the base option', () => {\n    const { api, state } = initURL({\n      store,\n      provider: { channel: new EventEmitter() },\n      state: { location: { pathname: '/', search: '' } },\n      navigate: vi.fn(),\n      fullAPI: { getCurrentStoryData: () => ({ id: 'test--story' }) },\n    });\n    store.setState(state);\n\n    const origin = api.getStoryHrefs('test--story', { base: 'origin' });\n    expect(origin.managerHref).toContain('http://localhost:6006/?path=');\n    expect(origin.previewHref).toContain('http://localhost:6006/iframe.html');\n\n    const network = api.getStoryHrefs('test--story', { base: 'network' });\n    expect(network.managerHref).toContain('http://192.168.1.1:6006/?path=');\n    expect(network.previewHref).toContain('http://192.168.1.1:6006/iframe.html');\n  });\n\n  it('supports linking to a ref, dropping globals in preview', () => {\n    const { api, state } = initURL({\n      store,\n      provider: { channel: new EventEmitter() },\n      state: { location: { pathname: '/', search: '?args=a:1&globals=b:2' } },\n      navigate: vi.fn(),\n      fullAPI: { getCurrentStoryData: () => ({ id: 'test--story' }) },\n    });\n    store.setState(state);\n    store.setState({ refs: { external: { url: 'https://sb.example.com' } } });\n\n    const { managerHref, previewHref } = api.getStoryHrefs('test--story', { refId: 'external' });\n    expect(managerHref).toEqual('/?path=/story/external_test--story&globals=b:2');\n    expect(previewHref).toEqual(\n      'https://sb.example.com/iframe.html?id=test--story&viewMode=story&refId=external'\n    );\n  });\n\n  it('supports PREVIEW_URL override', () => {\n    global.PREVIEW_URL = 'https://custom.preview.url/';\n    const { api, state } = initURL({\n      store,\n      provider: { channel: new EventEmitter() },\n      state: { location: { pathname: '/', search: '' } },\n      navigate: vi.fn(),\n      fullAPI: { getCurrentStoryData: () => ({ id: 'test--story' }) },\n    });\n    store.setState(state);\n\n    const { managerHref, previewHref } = api.getStoryHrefs('test--story');\n    expect(managerHref).toEqual('/?path=/story/test--story');\n    expect(previewHref).toEqual('https://custom.preview.url/?id=test--story&viewMode=story');\n    delete global.PREVIEW_URL;\n  });\n\n  it('correctly links from /index.html', () => {\n    const { api, state } = initURL({\n      store,\n      provider: { channel: new EventEmitter() },\n      state: { location: { pathname: '/index.html', search: '' } },\n      navigate: vi.fn(),\n      fullAPI: { getCurrentStoryData: () => ({ id: 'test--story' }) },\n    });\n    store.setState(state);\n\n    const { managerHref, previewHref } = api.getStoryHrefs('test--story');\n    expect(managerHref).toEqual('/index.html?path=/story/test--story');\n    expect(previewHref).toEqual('/iframe.html?id=test--story&viewMode=story');\n  });\n\n  it('correctly links when hosted at a subpath without trailing slash', () => {\n    const { api, state } = initURL({\n      store,\n      provider: { channel: new EventEmitter() },\n      state: { location: { pathname: '/design-system', search: '' } },\n      navigate: vi.fn(),\n      fullAPI: { getCurrentStoryData: () => ({ id: 'test--story' }) },\n    });\n    store.setState(state);\n\n    const { managerHref, previewHref } = api.getStoryHrefs('test--story');\n    expect(managerHref).toEqual('/design-system?path=/story/test--story');\n    expect(previewHref).toEqual('/design-system/iframe.html?id=test--story&viewMode=story');\n  });\n\n  it('correctly links when hosted at a subpath with trailing slash', () => {\n    const { api, state } = initURL({\n      store,\n      provider: { channel: new EventEmitter() },\n      state: { location: { pathname: '/design-system/', search: '' } },\n      navigate: vi.fn(),\n      fullAPI: { getCurrentStoryData: () => ({ id: 'test--story' }) },\n    });\n    store.setState(state);\n\n    const { managerHref, previewHref } = api.getStoryHrefs('test--story');\n    expect(managerHref).toEqual('/design-system/?path=/story/test--story');\n    expect(previewHref).toEqual('/design-system/iframe.html?id=test--story&viewMode=story');\n  });\n\n  it('correctly links when hosted at a subpath with index.html', () => {\n    const { api, state } = initURL({\n      store,\n      provider: { channel: new EventEmitter() },\n      state: { location: { pathname: '/design-system/index.html', search: '' } },\n      navigate: vi.fn(),\n      fullAPI: { getCurrentStoryData: () => ({ id: 'test--story' }) },\n    });\n    store.setState(state);\n\n    const { managerHref, previewHref } = api.getStoryHrefs('test--story');\n    expect(managerHref).toEqual('/design-system/index.html?path=/story/test--story');\n    expect(previewHref).toEqual('/design-system/iframe.html?id=test--story&viewMode=story');\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager-api/tests/versions.test.js",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { global } from '@storybook/global';\n\nimport { init as initVersions } from '../modules/versions';\n\nvi.mock('../version', () => ({\n  version: '3.0.0',\n}));\n\nvi.mock('@storybook/global', () => ({\n  global: {\n    VERSIONCHECK: JSON.stringify({\n      success: true,\n      data: {\n        latest: {\n          version: '5.2.3',\n        },\n        next: {\n          version: '5.3.0-alpha.15',\n        },\n      },\n      time: 1571565216284,\n    }),\n  },\n}));\n\nvi.mock('storybook/internal/client-logger');\n\nfunction createMockStore() {\n  let state = {\n    versions: {\n      latest: {\n        version: '3.0.0',\n      },\n      current: {\n        version: '3.0.0',\n      },\n    },\n  };\n  return {\n    getState: vi.fn().mockImplementation(() => state),\n    setState: vi.fn().mockImplementation((s) => {\n      state = { ...state, ...s };\n    }),\n  };\n}\n\nvi.mock('storybook/internal/client-logger');\n\nconst latest = {\n  current: { version: '7.6.1' },\n  latest: { version: '7.6.1' },\n};\nconst patchDiff = {\n  current: { version: '7.6.1' },\n  latest: { version: '7.6.10' },\n};\nconst minorDiff = {\n  current: { version: '7.2.5' },\n  latest: { version: '7.6.10' },\n};\nconst majorDiff = {\n  current: { version: '6.2.1' },\n  latest: { version: '7.6.10' },\n};\nconst canary = {\n  current: { version: '0.0.0-canary.0' },\n  latest: { version: '7.6.10' },\n};\nconst newerPrerelease = {\n  current: { version: '8.0.0-beta' },\n  latest: { version: '7.6.10' },\n};\nconst olderPrerelease = {\n  current: { version: '5.2.1-prerelease.0' },\n  latest: { version: '6.2.1' },\n};\nconst prereleaseAvailable = {\n  current: { version: '5.2.1' },\n  latest: { version: '6.2.1-prerelease.0' },\n};\n\nconst setVersions = (store, state, versions) =>\n  store.setState({ ...state, versions: { ...state.versions, ...versions } });\n\ndescribe('versions API', () => {\n  it('sets initial state with current version', async () => {\n    const store = createMockStore();\n    const { state } = initVersions({ store });\n\n    expect(state.versions.current).toEqual({ version: '3.0.0' });\n  });\n\n  it('sets initial state with latest version', async () => {\n    const store = createMockStore();\n    const { state } = initVersions({ store });\n\n    expect(state.versions.latest).toEqual({ version: '5.2.3' });\n  });\n\n  it('sets initial state with next version', async () => {\n    const store = createMockStore();\n    const { state } = initVersions({ store });\n\n    expect(state.versions.next).toEqual({ version: '5.3.0-alpha.15' });\n  });\n\n  it('sets versions in the init function', async () => {\n    const store = createMockStore();\n    const { state: initialState, init } = initVersions({ store });\n\n    store.setState(initialState);\n    store.setState.mockReset();\n\n    await init();\n\n    expect(store.setState).toHaveBeenCalledWith({\n      versions: {\n        latest: { version: '5.2.3' },\n        next: { version: '5.3.0-alpha.15' },\n        current: { version: '3.0.0' },\n      },\n    });\n  });\n\n  it('getCurrentVersion works', async () => {\n    const store = createMockStore();\n    const { init, api, state: initialState } = initVersions({ store });\n\n    store.setState(initialState);\n\n    await init();\n\n    expect(api.getCurrentVersion()).toEqual({\n      version: '3.0.0',\n    });\n  });\n\n  it('getLatestVersion works', async () => {\n    const store = createMockStore();\n    const { init, api, state: initialState } = initVersions({ store });\n\n    store.setState(initialState);\n\n    await init();\n\n    expect(api.getLatestVersion()).toMatchObject({\n      version: '5.2.3',\n    });\n  });\n\n  describe('METHOD: getDocsUrl()', () => {\n    beforeEach(() => {\n      global.STORYBOOK_RENDERER = undefined;\n    });\n\n    it('returns the latest url when current version is latest', async () => {\n      const store = createMockStore();\n      const { init, api, state: initialState } = initVersions({ store });\n\n      await init();\n\n      setVersions(store, initialState, latest);\n\n      expect(api.getDocsUrl({ versioned: true })).toEqual('https://storybook.js.org/docs/?ref=ui');\n    });\n\n    it('returns the latest url when version has patch diff with latest', async () => {\n      const store = createMockStore();\n      const { init, api, state: initialState } = initVersions({ store });\n\n      await init();\n\n      setVersions(store, initialState, patchDiff);\n\n      expect(api.getDocsUrl({ versioned: true })).toEqual('https://storybook.js.org/docs/?ref=ui');\n    });\n\n    it('returns the versioned url when current has different docs to latest', async () => {\n      const store = createMockStore();\n      const { init, api, state: initialState } = initVersions({ store });\n\n      await init();\n\n      setVersions(store, initialState, minorDiff);\n\n      expect(api.getDocsUrl({ versioned: true })).toEqual(\n        'https://storybook.js.org/docs/7.2/?ref=ui'\n      );\n    });\n\n    it('returns the latest versioned url when current is a canary', async () => {\n      const store = createMockStore();\n      const { init, api, state: initialState } = initVersions({ store });\n\n      await init();\n\n      setVersions(store, initialState, canary);\n\n      expect(api.getDocsUrl({ versioned: true })).toEqual('https://storybook.js.org/docs/?ref=ui');\n    });\n\n    it('returns the versioned url when current is a prerelease', async () => {\n      const store = createMockStore();\n      const { init, api, state: initialState } = initVersions({ store });\n\n      await init();\n\n      setVersions(store, initialState, newerPrerelease);\n\n      expect(api.getDocsUrl({ versioned: true })).toEqual(\n        'https://storybook.js.org/docs/8.0/?ref=ui'\n      );\n    });\n\n    it('returns a url with a renderer query param when \"renderer\" is true', async () => {\n      const store = createMockStore();\n      const { init, api, state: initialState } = initVersions({ store });\n\n      setVersions(store, initialState, latest);\n\n      await init();\n\n      global.STORYBOOK_RENDERER = 'vue';\n\n      expect(api.getDocsUrl({ renderer: true })).toEqual(\n        'https://storybook.js.org/docs/?renderer=vue&ref=ui'\n      );\n    });\n\n    it('returns a url with a custom ref query param when provided', async () => {\n      const store = createMockStore();\n      const { init, api, state: initialState } = initVersions({ store });\n\n      await init();\n\n      setVersions(store, initialState, latest);\n\n      expect(api.getDocsUrl({ ref: 'custom' })).toEqual(\n        'https://storybook.js.org/docs/?ref=custom'\n      );\n    });\n\n    it('returns a url without ref query param when empty', async () => {\n      const store = createMockStore();\n      const { init, api, state: initialState } = initVersions({ store });\n\n      await init();\n\n      setVersions(store, initialState, latest);\n\n      expect(api.getDocsUrl({ ref: '' })).toEqual('https://storybook.js.org/docs/');\n    });\n\n    it('returns a versioned url with assets path when provided', async () => {\n      const store = createMockStore();\n      const { init, api, state: initialState } = initVersions({ store });\n\n      await init();\n\n      setVersions(store, initialState, latest);\n\n      expect(api.getDocsUrl({ asset: 'api/doc-block-controls.png' })).toEqual(\n        'https://storybook.js.org/docs-assets/7.6/api/doc-block-controls.png?ref=ui'\n      );\n    });\n\n    it('returns the latest versioned url with assets path for canary version', async () => {\n      const store = createMockStore();\n      const { init, api, state: initialState } = initVersions({ store });\n\n      await init();\n\n      setVersions(store, initialState, canary);\n\n      expect(api.getDocsUrl({ asset: 'api/doc-block-controls.png' })).toEqual(\n        'https://storybook.js.org/docs-assets/7.6/api/doc-block-controls.png?ref=ui'\n      );\n    });\n  });\n\n  describe('versionUpdateAvailable', () => {\n    it('matching version', async () => {\n      const store = createMockStore();\n      const { init, api, state: initialState } = initVersions({ store });\n\n      setVersions(store, initialState, latest);\n\n      await init();\n\n      expect(api.versionUpdateAvailable()).toEqual(false);\n    });\n\n    it('new patch version', async () => {\n      const store = createMockStore();\n      const { init, api, state: initialState } = initVersions({ store });\n\n      setVersions(store, initialState, patchDiff);\n\n      await init();\n\n      expect(api.versionUpdateAvailable()).toEqual(false);\n    });\n\n    it('new minor version', async () => {\n      const store = createMockStore();\n      const { init, api, state: initialState } = initVersions({ store });\n\n      await init();\n\n      setVersions(store, initialState, minorDiff);\n\n      expect(api.versionUpdateAvailable()).toEqual(true);\n    });\n\n    it('new major version', async () => {\n      const store = createMockStore();\n      const { init, api, state: initialState } = initVersions({ store });\n\n      await init();\n\n      setVersions(store, initialState, majorDiff);\n\n      expect(api.versionUpdateAvailable()).toEqual(true);\n    });\n\n    it('new prerelease version', async () => {\n      const store = createMockStore();\n      const { init, api, state: initialState } = initVersions({ store });\n\n      await init();\n\n      setVersions(store, initialState, prereleaseAvailable);\n\n      expect(api.versionUpdateAvailable()).toEqual(false);\n    });\n\n    it('from older prerelease version', async () => {\n      const store = createMockStore();\n      const { init, api, state: initialState } = initVersions({ store });\n\n      await init();\n\n      setVersions(store, initialState, olderPrerelease);\n\n      expect(api.versionUpdateAvailable()).toEqual(true);\n    });\n\n    it('from newer prerelease version', async () => {\n      const store = createMockStore();\n      const { init, api, state: initialState } = initVersions({ store });\n\n      await init();\n\n      setVersions(store, initialState, newerPrerelease);\n\n      expect(api.versionUpdateAvailable()).toEqual(false);\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/manager-api/typings.d.ts",
    "content": "declare var __STORYBOOK_ADDONS_MANAGER: any;\n\ndeclare var CONFIG_TYPE: string;\ndeclare var FEATURES: import('storybook/internal/types').StorybookConfigRaw['features'];\ndeclare var TAGS_OPTIONS: import('storybook/internal/types').StorybookConfigRaw['tags'];\ndeclare var REFS: any;\ndeclare var VERSIONCHECK: any;\ndeclare var LOGLEVEL: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent' | undefined;\ndeclare var STORYBOOK_ADDON_STATE: Record<string, any>;\ndeclare var STORYBOOK_FRAMEWORK: import('storybook/internal/types').SupportedFramework | undefined;\ndeclare var STORYBOOK_RENDERER: import('storybook/internal/types').SupportedRenderer | undefined;\ndeclare var STORYBOOK_BUILDER: import('storybook/internal/types').SupportedBuilder | undefined;\n"
  },
  {
    "path": "code/core/src/manager-api/version.ts",
    "content": "export const version = '10.4.0-alpha.6';\n"
  },
  {
    "path": "code/core/src/manager-errors.ts",
    "content": "import type { Status, StatusTypeId } from './shared/status-store/index.ts';\nimport { StorybookError } from './storybook-error.ts';\n\n/**\n * If you can't find a suitable category for your error, create one based on the package name/file\n * path of which the error is thrown. For instance: If it's from `storybook/internal/client-logger`,\n * then MANAGER_CLIENT-LOGGER\n *\n * Categories are prefixed by a logical grouping, e.g. MANAGER_ to prevent manager and preview\n * errors from having the same category and error code.\n */\nexport enum Category {\n  MANAGER_UNCAUGHT = 'MANAGER_UNCAUGHT',\n  MANAGER_UI = 'MANAGER_UI',\n  MANAGER_API = 'MANAGER_API',\n  MANAGER_CLIENT_LOGGER = 'MANAGER_CLIENT-LOGGER',\n  MANAGER_CHANNELS = 'MANAGER_CHANNELS',\n  MANAGER_CORE_EVENTS = 'MANAGER_CORE-EVENTS',\n  MANAGER_ROUTER = 'MANAGER_ROUTER',\n  MANAGER_THEMING = 'MANAGER_THEMING',\n}\n\nexport class ProviderDoesNotExtendBaseProviderError extends StorybookError {\n  constructor() {\n    super({\n      name: 'ProviderDoesNotExtendBaseProviderError',\n      category: Category.MANAGER_UI,\n      code: 1,\n      message: `The Provider passed into Storybook's UI is not extended from the base Provider. Please check your Provider implementation.`,\n    });\n  }\n}\n\nexport class UncaughtManagerError extends StorybookError {\n  constructor(\n    public data: {\n      error: Error;\n    }\n  ) {\n    super({\n      name: 'UncaughtManagerError',\n      category: Category.MANAGER_UNCAUGHT,\n      code: 1,\n      message: data.error.message,\n    });\n    this.stack = data.error.stack;\n  }\n}\n\nexport class StatusTypeIdMismatchError extends StorybookError {\n  constructor(\n    public data: {\n      status: Status;\n      typeId: StatusTypeId;\n    }\n  ) {\n    super({\n      name: 'StatusTypeIdMismatchError',\n      category: Category.MANAGER_API,\n      code: 1,\n      message: `Status has typeId \"${data.status.typeId}\" but was added to store with typeId \"${data.typeId}\". Full status: ${JSON.stringify(\n        data.status,\n        null,\n        2\n      )}`,\n    });\n  }\n}\n"
  },
  {
    "path": "code/core/src/measure/README.md",
    "content": "# Storybook Addon Measure\n\nStorybook addon for inspecting layouts and visualizing the box model.\n\n1. Press the <kbd>m</kbd> key to enable the addon:\n\n2. Hover over a DOM node\n\n3. Storybook will display the dimensions of the selected element—margin, padding, border, width and height—in pixels.\n\n![](https://user-images.githubusercontent.com/42671/119589961-dff9b380-bda1-11eb-9550-7ae28bc70bf4.gif)\n\n## Usage\n\nThis addon requires Storybook 6.3 or later. Measure is part of [essentials](https://storybook.js.org/docs/essentials) and so is installed in all new Storybooks by default. If you need to add it to your Storybook, you can run:\n\n```sh\nnpm i -D @storybook/addon-measure\n```\n\nAdd `\"@storybook/addon-measure\"` to the addons array in your `.storybook/main.js`:\n\n```js\nexport default {\n  addons: ['@storybook/addon-measure'],\n};\n```\n\n### Inspiration\n\n- [Inspx](https://github.com/raunofreiberg/inspx) by Rauno Freiberg\n- [Aaron Westbrook's script](https://gist.github.com/awestbro/e668c12662ad354f02a413205b65fce7)\n- [Visbug](https://visbug.web.app/) from the Chrome team\n"
  },
  {
    "path": "code/core/src/measure/Tool.tsx",
    "content": "import React, { useCallback, useEffect } from 'react';\n\nimport { ToggleButton } from 'storybook/internal/components';\n\nimport { RulerIcon } from '@storybook/icons';\n\nimport { useGlobals, useStorybookApi } from 'storybook/manager-api';\n\nimport { ADDON_ID, TOOL_ID } from './constants.ts';\n\nexport const Tool = () => {\n  const [globals, updateGlobals] = useGlobals();\n  const { measureEnabled } = globals || {};\n  const api = useStorybookApi();\n\n  const toggleMeasure = useCallback(\n    () =>\n      updateGlobals({\n        measureEnabled: !measureEnabled,\n      }),\n    [updateGlobals, measureEnabled]\n  );\n\n  useEffect(() => {\n    api.setAddonShortcut(ADDON_ID, {\n      label: 'Toggle Measure',\n      defaultShortcut: ['M'],\n      actionName: 'measure',\n      showInMenu: false,\n      action: toggleMeasure,\n    });\n  }, [toggleMeasure, api]);\n\n  return (\n    <ToggleButton\n      key={TOOL_ID}\n      pressed={measureEnabled}\n      padding=\"small\"\n      variant=\"ghost\"\n      ariaLabel=\"Measure tool\"\n      tooltip=\"Toggle measure\"\n      ariaDescription=\"When enabled, this tool shows dimensions and whitespace (margin, padding, border) for the currently hovered element in the preview area. Does not work with keyboard focus.\"\n      onClick={toggleMeasure}\n    >\n      <RulerIcon />\n    </ToggleButton>\n  );\n};\n"
  },
  {
    "path": "code/core/src/measure/box-model/canvas.ts",
    "content": "import { global } from '@storybook/global';\n\nimport invariant from 'tiny-invariant';\n\ninterface Size {\n  width: number;\n  height: number;\n}\n\ninterface CanvasState {\n  canvas?: HTMLCanvasElement;\n  context?: CanvasRenderingContext2D;\n  width?: number;\n  height?: number;\n}\n\nfunction getDocumentWidthAndHeight() {\n  const container = global.document.documentElement;\n\n  const height = Math.max(container.scrollHeight, container.offsetHeight);\n  const width = Math.max(container.scrollWidth, container.offsetWidth);\n  return { width, height };\n}\n\nfunction createCanvas(): CanvasState {\n  const canvas = global.document.createElement('canvas');\n  canvas.id = 'storybook-addon-measure';\n  const context = canvas.getContext('2d');\n  invariant(context != null);\n  // Set canvas width & height\n  const { width, height } = getDocumentWidthAndHeight();\n  setCanvasWidthAndHeight(canvas, context, { width, height });\n  // Position canvas\n  canvas.style.position = 'absolute';\n  canvas.style.left = '0';\n  canvas.style.top = '0';\n  canvas.style.zIndex = '2147483647';\n  // Disable any user interactions\n  canvas.style.pointerEvents = 'none';\n  global.document.body.appendChild(canvas);\n\n  return { canvas, context, width, height };\n}\n\nfunction setCanvasWidthAndHeight(\n  canvas: HTMLCanvasElement,\n  context: CanvasRenderingContext2D,\n  { width, height }: Size\n) {\n  canvas.style.width = `${width}px`;\n  canvas.style.height = `${height}px`;\n\n  // Scale\n  const scale = global.window.devicePixelRatio;\n  canvas.width = Math.floor(width * scale);\n  canvas.height = Math.floor(height * scale);\n\n  // Normalize coordinate system to use css pixels.\n  context.scale(scale, scale);\n}\n\nlet state: CanvasState = {};\n\nexport function init() {\n  if (!state.canvas) {\n    state = createCanvas();\n  }\n}\n\nexport function clear() {\n  if (state.context) {\n    state.context.clearRect(0, 0, state.width ?? 0, state.height ?? 0);\n  }\n}\n\nexport function draw(callback: (context?: CanvasRenderingContext2D) => void) {\n  clear();\n  callback(state.context);\n}\n\nexport function rescale() {\n  invariant(state.canvas, 'Canvas should exist in the state.');\n  invariant(state.context, 'Context should exist in the state.');\n  // First reset so that the canvas size doesn't impact the container size\n  setCanvasWidthAndHeight(state.canvas, state.context, { width: 0, height: 0 });\n\n  const { width, height } = getDocumentWidthAndHeight();\n  setCanvasWidthAndHeight(state.canvas, state.context, { width, height });\n\n  // update state\n  state.width = width;\n  state.height = height;\n}\n\nexport function destroy() {\n  if (state.canvas) {\n    clear();\n    state.canvas.parentNode?.removeChild(state.canvas);\n    state = {};\n  }\n}\n"
  },
  {
    "path": "code/core/src/measure/box-model/labels.ts",
    "content": "import type { ElementMeasurements, FloatingAlignment } from '../util-types.ts';\n\ntype LabelType = 'margin' | 'padding' | 'border' | 'content';\ntype LabelPosition = 'top' | 'right' | 'bottom' | 'left' | 'center';\ntype Direction = 'top' | 'right' | 'bottom' | 'left';\n\nexport interface Label {\n  type: LabelType;\n  text: number | string;\n  position: LabelPosition;\n}\n\nexport type LabelStack = Label[];\n\ninterface RectSize {\n  w: number;\n  h: number;\n}\n\ninterface Coordinate {\n  x: number;\n  y: number;\n}\n\ninterface Rect extends RectSize, Coordinate {}\n\ninterface RoundedRect extends Rect {\n  r: number;\n}\n\nconst colors = {\n  margin: '#f6b26b',\n  border: '#ffe599',\n  padding: '#93c47d',\n  content: '#6fa8dc',\n  text: '#232020',\n};\n\nconst labelPadding = 6;\n\nfunction roundedRect(context: CanvasRenderingContext2D, { x, y, w, h, r }: RoundedRect) {\n  x = x - w / 2;\n  y = y - h / 2;\n\n  if (w < 2 * r) {\n    r = w / 2;\n  }\n\n  if (h < 2 * r) {\n    r = h / 2;\n  }\n\n  context.beginPath();\n  context.moveTo(x + r, y);\n  context.arcTo(x + w, y, x + w, y + h, r);\n  context.arcTo(x + w, y + h, x, y + h, r);\n  context.arcTo(x, y + h, x, y, r);\n  context.arcTo(x, y, x + w, y, r);\n  context.closePath();\n}\n\nfunction positionCoordinate(\n  position: LabelPosition,\n  { padding, border, width, height, top, left }: ElementMeasurements\n): Coordinate {\n  const contentWidth = width - border.left - border.right - padding.left - padding.right;\n  const contentHeight = height - padding.top - padding.bottom - border.top - border.bottom;\n\n  let x = left + border.left + padding.left;\n  let y = top + border.top + padding.top;\n\n  if (position === 'top') {\n    x += contentWidth / 2;\n  } else if (position === 'right') {\n    x += contentWidth;\n    y += contentHeight / 2;\n  } else if (position === 'bottom') {\n    x += contentWidth / 2;\n    y += contentHeight;\n  } else if (position === 'left') {\n    y += contentHeight / 2;\n  } else if (position === 'center') {\n    x += contentWidth / 2;\n    y += contentHeight / 2;\n  }\n\n  return { x, y };\n}\n\n/**\n * Offset the label based on how many layers appear before it For example: margin labels will shift\n * further outwards if there are padding labels\n */\nfunction offset(\n  type: LabelType,\n  position: LabelPosition,\n  { margin, border, padding }: ElementMeasurements,\n  labelPaddingSize: number,\n  external: boolean\n) {\n  let shift = (dir: Direction) => 0;\n  let offsetX = 0;\n  let offsetY = 0;\n\n  // If external labels then push them to the edge of the band\n  // else keep them centred\n  const locationMultiplier = external ? 1 : 0.5;\n  // Account for padding within the label\n  const labelPaddingShift = external ? labelPaddingSize * 2 : 0;\n\n  if (type === 'padding') {\n    shift = (dir: Direction) => padding[dir] * locationMultiplier + labelPaddingShift;\n  } else if (type === 'border') {\n    shift = (dir: Direction) => padding[dir] + border[dir] * locationMultiplier + labelPaddingShift;\n  } else if (type === 'margin') {\n    shift = (dir: Direction) =>\n      padding[dir] + border[dir] + margin[dir] * locationMultiplier + labelPaddingShift;\n  }\n\n  if (position === 'top') {\n    offsetY = -shift('top');\n  } else if (position === 'right') {\n    offsetX = shift('right');\n  } else if (position === 'bottom') {\n    offsetY = shift('bottom');\n  } else if (position === 'left') {\n    offsetX = -shift('left');\n  }\n\n  return { offsetX, offsetY };\n}\n\nfunction collide(a: Rect, b: Rect) {\n  return (\n    Math.abs(a.x - b.x) < Math.abs(a.w + b.w) / 2 && Math.abs(a.y - b.y) < Math.abs(a.h + b.h) / 2\n  );\n}\n\nfunction overlapAdjustment(position: LabelPosition, currentRect: Rect, prevRect: Rect) {\n  if (position === 'top') {\n    currentRect.y = prevRect.y - prevRect.h - labelPadding;\n  } else if (position === 'right') {\n    currentRect.x = prevRect.x + prevRect.w / 2 + labelPadding + currentRect.w / 2;\n  } else if (position === 'bottom') {\n    currentRect.y = prevRect.y + prevRect.h + labelPadding;\n  } else if (position === 'left') {\n    currentRect.x = prevRect.x - prevRect.w / 2 - labelPadding - currentRect.w / 2;\n  }\n\n  return { x: currentRect.x, y: currentRect.y };\n}\n\nfunction textWithRect(\n  context: CanvasRenderingContext2D,\n  type: LabelType,\n  { x, y, w, h }: Rect,\n  text: number | string\n) {\n  roundedRect(context, { x, y, w, h, r: 3 });\n  context.fillStyle = `${colors[type]}dd`;\n  context.fill();\n  context.strokeStyle = colors[type];\n  context.stroke();\n\n  context.fillStyle = colors.text;\n  context.fillText(text as string, x, y);\n\n  roundedRect(context, { x, y, w, h, r: 3 });\n  context.fillStyle = `${colors[type]}dd`;\n  context.fill();\n  context.strokeStyle = colors[type];\n  context.stroke();\n\n  context.fillStyle = colors.text;\n  context.fillText(text as string, x, y);\n\n  return { x, y, w, h };\n}\n\nfunction configureText(context: CanvasRenderingContext2D, text: number | string): RectSize {\n  context.font = '600 12px monospace';\n  context.textBaseline = 'middle';\n  context.textAlign = 'center';\n\n  const metrics = context.measureText(text as string);\n  const actualHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;\n\n  const w = metrics.width + labelPadding * 2;\n  const h = actualHeight + labelPadding * 2;\n\n  return { w, h };\n}\n\nfunction drawLabel(\n  context: CanvasRenderingContext2D,\n  measurements: ElementMeasurements,\n  { type, position = 'center', text }: Label,\n  prevRect: Rect,\n  external = false\n) {\n  let { x, y } = positionCoordinate(position, measurements);\n  const { offsetX, offsetY } = offset(type, position, measurements, labelPadding + 1, external);\n\n  // Shift coordinate to center within\n  // the band of measurement\n  x += offsetX;\n  y += offsetY;\n\n  const { w, h } = configureText(context, text);\n\n  // Adjust for overlap\n  if (prevRect && collide({ x, y, w, h }, prevRect)) {\n    const adjusted = overlapAdjustment(position, { x, y, w, h }, prevRect);\n    x = adjusted.x;\n    y = adjusted.y;\n  }\n\n  return textWithRect(context, type, { x, y, w, h }, text);\n}\n\nfunction floatingOffset(alignment: FloatingAlignment, { w, h }: RectSize) {\n  const deltaW = w * 0.5 + labelPadding;\n  const deltaH = h * 0.5 + labelPadding;\n\n  return {\n    offsetX: (alignment.x === 'left' ? -1 : 1) * deltaW,\n    offsetY: (alignment.y === 'top' ? -1 : 1) * deltaH,\n  };\n}\n\nexport function drawFloatingLabel(\n  context: CanvasRenderingContext2D,\n  measurements: ElementMeasurements,\n  { type, text }: Label\n) {\n  const { floatingAlignment, extremities } = measurements;\n\n  let x = extremities[floatingAlignment.x];\n  let y = extremities[floatingAlignment.y];\n\n  const { w, h } = configureText(context, text);\n\n  const { offsetX, offsetY } = floatingOffset(floatingAlignment, {\n    w,\n    h,\n  });\n\n  x += offsetX;\n  y += offsetY;\n\n  return textWithRect(context, type, { x, y, w, h }, text);\n}\n\nfunction drawStack(\n  context: CanvasRenderingContext2D,\n  measurements: ElementMeasurements,\n  stack: LabelStack,\n  external: boolean\n) {\n  const rects: Rect[] = [];\n\n  stack.forEach((l, idx) => {\n    // Move the centred label to floating in external mode\n    const rect =\n      external && l.position === 'center'\n        ? drawFloatingLabel(context, measurements, l)\n        : drawLabel(context, measurements, l, rects[idx - 1], external);\n    rects[idx] = rect;\n  });\n}\n\ninterface GroupedLabelStacks {\n  top?: LabelStack;\n  right?: LabelStack;\n  bottom?: LabelStack;\n  left?: LabelStack;\n  center?: LabelStack;\n}\n\nexport function labelStacks(\n  context: CanvasRenderingContext2D,\n  measurements: ElementMeasurements,\n  labels: LabelStack,\n  externalLabels: boolean\n) {\n  const stacks = labels.reduce<GroupedLabelStacks>((acc, l) => {\n    if (!Object.prototype.hasOwnProperty.call(acc, l.position)) {\n      acc[l.position] = [];\n    }\n\n    acc[l.position]?.push(l);\n\n    return acc;\n  }, {});\n\n  if (stacks.top) {\n    drawStack(context, measurements, stacks.top, externalLabels);\n  }\n  if (stacks.right) {\n    drawStack(context, measurements, stacks.right, externalLabels);\n  }\n  if (stacks.bottom) {\n    drawStack(context, measurements, stacks.bottom, externalLabels);\n  }\n  if (stacks.left) {\n    drawStack(context, measurements, stacks.left, externalLabels);\n  }\n  if (stacks.center) {\n    drawStack(context, measurements, stacks.center, externalLabels);\n  }\n}\n"
  },
  {
    "path": "code/core/src/measure/box-model/visualizer.ts",
    "content": "/** Based on https://gist.github.com/awestbro/e668c12662ad354f02a413205b65fce7 */\nimport { global } from '@storybook/global';\n\nimport type {\n  Dimensions,\n  ElementMeasurements,\n  Extremities,\n  FloatingAlignment,\n} from '../util-types.ts';\nimport { draw } from './canvas.ts';\nimport type { Label, LabelStack } from './labels.ts';\nimport { labelStacks } from './labels.ts';\n\nconst colors = {\n  margin: '#f6b26ba8',\n  border: '#ffe599a8',\n  padding: '#93c47d8c',\n  content: '#6fa8dca8',\n};\n\nconst SMALL_NODE_SIZE = 30;\n\nfunction pxToNumber(px: string): number {\n  return parseInt(px.replace('px', ''), 10);\n}\n\nfunction round(value: number): number | string {\n  return Number.isInteger(value) ? value : value.toFixed(2);\n}\n\nfunction filterZeroValues(labels: LabelStack): LabelStack {\n  return labels.filter((l) => l.text !== 0 && l.text !== '0');\n}\n\nfunction floatingAlignment(extremities: Extremities): FloatingAlignment {\n  const windowExtremities = {\n    top: global.window.scrollY,\n    bottom: global.window.scrollY + global.window.innerHeight,\n    left: global.window.scrollX,\n    right: global.window.scrollX + global.window.innerWidth,\n  };\n\n  const distances = {\n    top: Math.abs(windowExtremities.top - extremities.top),\n    bottom: Math.abs(windowExtremities.bottom - extremities.bottom),\n    left: Math.abs(windowExtremities.left - extremities.left),\n    right: Math.abs(windowExtremities.right - extremities.right),\n  };\n\n  return {\n    x: distances.left > distances.right ? 'left' : 'right',\n    y: distances.top > distances.bottom ? 'top' : 'bottom',\n  };\n}\n\nfunction measureElement(element: HTMLElement): ElementMeasurements {\n  const style = global.getComputedStyle(element);\n  // eslint-disable-next-line prefer-const\n  let { top, left, right, bottom, width, height } = element.getBoundingClientRect();\n\n  const {\n    marginTop,\n    marginBottom,\n    marginLeft,\n    marginRight,\n    paddingTop,\n    paddingBottom,\n    paddingLeft,\n    paddingRight,\n    borderBottomWidth,\n    borderTopWidth,\n    borderLeftWidth,\n    borderRightWidth,\n  } = style;\n\n  top = top + global.window.scrollY;\n  left = left + global.window.scrollX;\n  bottom = bottom + global.window.scrollY;\n  right = right + global.window.scrollX;\n\n  const margin = {\n    top: pxToNumber(marginTop),\n    bottom: pxToNumber(marginBottom),\n    left: pxToNumber(marginLeft),\n    right: pxToNumber(marginRight),\n  };\n\n  const padding = {\n    top: pxToNumber(paddingTop),\n    bottom: pxToNumber(paddingBottom),\n    left: pxToNumber(paddingLeft),\n    right: pxToNumber(paddingRight),\n  };\n\n  const border = {\n    top: pxToNumber(borderTopWidth),\n    bottom: pxToNumber(borderBottomWidth),\n    left: pxToNumber(borderLeftWidth),\n    right: pxToNumber(borderRightWidth),\n  };\n\n  const extremities = {\n    top: top - margin.top,\n    bottom: bottom + margin.bottom,\n    left: left - margin.left,\n    right: right + margin.right,\n  };\n\n  return {\n    margin,\n    padding,\n    border,\n    top,\n    left,\n    bottom,\n    right,\n    width,\n    height,\n    extremities,\n    floatingAlignment: floatingAlignment(extremities),\n  };\n}\n\nfunction drawMargin(\n  context: CanvasRenderingContext2D,\n  { margin, width, height, top, left, bottom, right }: Dimensions\n): LabelStack {\n  // Draw Margin\n  const marginHeight = height + margin.bottom + margin.top;\n\n  context.fillStyle = colors.margin;\n  // Top margin rect\n  context.fillRect(left, top - margin.top, width, margin.top);\n  // Right margin rect\n  context.fillRect(right, top - margin.top, margin.right, marginHeight);\n  // Bottom margin rect\n  context.fillRect(left, bottom, width, margin.bottom);\n  // Left margin rect\n  context.fillRect(left - margin.left, top - margin.top, margin.left, marginHeight);\n\n  const marginLabels: LabelStack = [\n    {\n      type: 'margin',\n      text: round(margin.top),\n      position: 'top',\n    },\n    {\n      type: 'margin',\n      text: round(margin.right),\n      position: 'right',\n    },\n    {\n      type: 'margin',\n      text: round(margin.bottom),\n      position: 'bottom',\n    },\n    {\n      type: 'margin',\n      text: round(margin.left),\n      position: 'left',\n    },\n  ];\n\n  return filterZeroValues(marginLabels);\n}\n\nfunction drawPadding(\n  context: CanvasRenderingContext2D,\n  { padding, border, width, height, top, left, bottom, right }: Dimensions\n): LabelStack {\n  const paddingWidth = width - border.left - border.right;\n  const paddingHeight = height - padding.top - padding.bottom - border.top - border.bottom;\n\n  context.fillStyle = colors.padding;\n  // Top padding rect\n  context.fillRect(left + border.left, top + border.top, paddingWidth, padding.top);\n  // Right padding rect\n  context.fillRect(\n    right - padding.right - border.right,\n    top + padding.top + border.top,\n    padding.right,\n    paddingHeight\n  );\n  // Bottom padding rect\n  context.fillRect(\n    left + border.left,\n    bottom - padding.bottom - border.bottom,\n    paddingWidth,\n    padding.bottom\n  );\n  // Left padding rect\n  context.fillRect(left + border.left, top + padding.top + border.top, padding.left, paddingHeight);\n\n  const paddingLabels: LabelStack = [\n    {\n      type: 'padding',\n      text: padding.top,\n      position: 'top',\n    },\n    {\n      type: 'padding',\n      text: padding.right,\n      position: 'right',\n    },\n    {\n      type: 'padding',\n      text: padding.bottom,\n      position: 'bottom',\n    },\n    {\n      type: 'padding',\n      text: padding.left,\n      position: 'left',\n    },\n  ];\n\n  return filterZeroValues(paddingLabels);\n}\n\nfunction drawBorder(\n  context: CanvasRenderingContext2D,\n  { border, width, height, top, left, bottom, right }: Dimensions\n): Label[] {\n  const borderHeight = height - border.top - border.bottom;\n\n  context.fillStyle = colors.border;\n  // Top border rect\n  context.fillRect(left, top, width, border.top);\n  // Bottom border rect\n  context.fillRect(left, bottom - border.bottom, width, border.bottom);\n  // Left border rect\n  context.fillRect(left, top + border.top, border.left, borderHeight);\n  // Right border rect\n  context.fillRect(right - border.right, top + border.top, border.right, borderHeight);\n\n  const borderLabels: LabelStack = [\n    {\n      type: 'border',\n      text: border.top,\n      position: 'top',\n    },\n    {\n      type: 'border',\n      text: border.right,\n      position: 'right',\n    },\n    {\n      type: 'border',\n      text: border.bottom,\n      position: 'bottom',\n    },\n    {\n      type: 'border',\n      text: border.left,\n      position: 'left',\n    },\n  ];\n\n  return filterZeroValues(borderLabels);\n}\n\nfunction drawContent(\n  context: CanvasRenderingContext2D,\n  { padding, border, width, height, top, left }: Dimensions\n): LabelStack {\n  const contentWidth = width - border.left - border.right - padding.left - padding.right;\n  const contentHeight = height - padding.top - padding.bottom - border.top - border.bottom;\n\n  context.fillStyle = colors.content;\n  // content rect\n  context.fillRect(\n    left + border.left + padding.left,\n    top + border.top + padding.top,\n    contentWidth,\n    contentHeight\n  );\n\n  // Dimension label\n  return [\n    {\n      type: 'content',\n      position: 'center',\n      text: `${round(contentWidth)} x ${round(contentHeight)}`,\n    },\n  ];\n}\n\nfunction drawBoxModel(element: HTMLElement) {\n  return (context?: CanvasRenderingContext2D) => {\n    if (element && context) {\n      const measurements = measureElement(element);\n\n      const marginLabels = drawMargin(context, measurements);\n      const paddingLabels = drawPadding(context, measurements);\n      const borderLabels = drawBorder(context, measurements);\n      const contentLabels = drawContent(context, measurements);\n\n      const externalLabels =\n        measurements.width <= SMALL_NODE_SIZE * 3 || measurements.height <= SMALL_NODE_SIZE;\n\n      labelStacks(\n        context,\n        measurements,\n        [...contentLabels, ...paddingLabels, ...borderLabels, ...marginLabels],\n        externalLabels\n      );\n    }\n  };\n}\n\nexport function drawSelectedElement(element: HTMLElement) {\n  draw(drawBoxModel(element));\n}\n"
  },
  {
    "path": "code/core/src/measure/constants.ts",
    "content": "export const ADDON_ID = 'storybook/measure-addon';\nexport const TOOL_ID = `${ADDON_ID}/tool`;\nexport const PARAM_KEY = 'measureEnabled';\n\nexport const EVENTS = {\n  RESULT: `${ADDON_ID}/result`,\n  REQUEST: `${ADDON_ID}/request`,\n  CLEAR: `${ADDON_ID}/clear`,\n};\n"
  },
  {
    "path": "code/core/src/measure/manager.tsx",
    "content": "import React from 'react';\n\nimport { addons, types } from 'storybook/manager-api';\n\nimport { Tool } from './Tool.tsx';\nimport { ADDON_ID, TOOL_ID } from './constants.ts';\n\nexport default addons.register(ADDON_ID, () => {\n  if (globalThis?.FEATURES?.measure) {\n    addons.add(TOOL_ID, {\n      type: types.TOOL,\n      title: 'Measure',\n      match: ({ viewMode, tabId }) => viewMode === 'story' && !tabId,\n      render: () => <Tool />,\n    });\n  }\n});\n"
  },
  {
    "path": "code/core/src/measure/preview.ts",
    "content": "import { definePreviewAddon } from 'storybook/internal/csf';\n\nimport { PARAM_KEY } from './constants.ts';\nimport type { MeasureTypes } from './types.ts';\nimport { withMeasure } from './withMeasure.ts';\n\nexport const decorators = globalThis.FEATURES?.measure ? [withMeasure] : [];\n\nexport const initialGlobals = {\n  [PARAM_KEY]: false,\n};\n\nexport type { MeasureTypes };\n\nexport default () =>\n  definePreviewAddon<MeasureTypes>({\n    decorators,\n    initialGlobals,\n  });\n"
  },
  {
    "path": "code/core/src/measure/types.ts",
    "content": "export interface MeasureParameters {\n  /**\n   * Measure configuration\n   *\n   * @see https://storybook.js.org/docs/essentials/measure-and-outline#parameters\n   */\n  measure?: {\n    /**\n     * Removes the tool and disables the feature's behavior. If you wish to turn off this feature\n     * for the entire Storybook, you can set the option in your `main.js|ts` configuration file.\n     *\n     * @see https://storybook.js.org/docs/essentials/measure-and-outline#disable\n     */\n    disable?: boolean;\n  };\n}\n\nexport interface MeasureTypes {\n  parameters: MeasureParameters;\n}\n"
  },
  {
    "path": "code/core/src/measure/util-types.ts",
    "content": "export interface Margin {\n  top: number;\n  bottom: number;\n  left: number;\n  right: number;\n}\n\nexport interface Padding {\n  top: number;\n  bottom: number;\n  left: number;\n  right: number;\n}\n\nexport interface Border {\n  top: number;\n  bottom: number;\n  left: number;\n  right: number;\n}\n\nexport interface Dimensions {\n  margin: Margin;\n  padding: Padding;\n  border: Border;\n  width: number;\n  height: number;\n  top: number;\n  left: number;\n  bottom: number;\n  right: number;\n}\n\nexport interface Extremities {\n  top: number;\n  bottom: number;\n  left: number;\n  right: number;\n}\n\nexport interface FloatingAlignment {\n  x: 'left' | 'right';\n  y: 'top' | 'bottom';\n}\n\nexport interface ElementMeasurements extends Dimensions {\n  extremities: Extremities;\n  floatingAlignment: FloatingAlignment;\n}\n"
  },
  {
    "path": "code/core/src/measure/util.ts",
    "content": "import { global } from '@storybook/global';\n\nexport const deepElementFromPoint = (x: number, y: number) => {\n  const element = global.document.elementFromPoint(x, y) as HTMLElement;\n\n  const crawlShadows = (node: HTMLElement): HTMLElement => {\n    if (node && node.shadowRoot) {\n      // elementFromPoint() doesn't exist in ShadowRoot type\n      const nestedElement = (node.shadowRoot as any).elementFromPoint(x, y);\n\n      // Nested node is same as the root one\n      if (node.isEqualNode(nestedElement)) {\n        return node;\n      }\n      // The nested node has shadow DOM too so continue crawling\n      if (nestedElement.shadowRoot) {\n        return crawlShadows(nestedElement);\n      }\n      // No more shadow DOM\n      return nestedElement;\n    }\n\n    return node;\n  };\n\n  const shadowElement = crawlShadows(element);\n\n  return shadowElement || element;\n};\n"
  },
  {
    "path": "code/core/src/measure/withMeasure.ts",
    "content": "/* eslint-env browser */\nimport type { DecoratorFunction } from 'storybook/internal/types';\n\nimport { useEffect } from 'storybook/preview-api';\n\nimport { destroy, init, rescale } from './box-model/canvas.ts';\nimport { drawSelectedElement } from './box-model/visualizer.ts';\nimport { deepElementFromPoint } from './util.ts';\n\nlet nodeAtPointerRef;\nconst pointer = { x: 0, y: 0 };\n\nfunction findAndDrawElement(x: number, y: number) {\n  nodeAtPointerRef = deepElementFromPoint(x, y);\n  drawSelectedElement(nodeAtPointerRef);\n}\n\nexport const withMeasure: DecoratorFunction = (StoryFn, context) => {\n  const { measureEnabled } = context.globals || {};\n\n  useEffect(() => {\n    if (typeof globalThis.document === 'undefined') {\n      return;\n    }\n\n    const onPointerMove = (event: MouseEvent) => {\n      window.requestAnimationFrame(() => {\n        event.stopPropagation();\n        pointer.x = event.clientX;\n        pointer.y = event.clientY;\n      });\n    };\n\n    globalThis.document.addEventListener('pointermove', onPointerMove);\n\n    return () => {\n      globalThis.document.removeEventListener('pointermove', onPointerMove);\n    };\n  }, []);\n\n  useEffect(() => {\n    const onPointerOver = (event: MouseEvent) => {\n      window.requestAnimationFrame(() => {\n        event.stopPropagation();\n        findAndDrawElement(event.clientX, event.clientY);\n      });\n    };\n\n    const onResize = () => {\n      window.requestAnimationFrame(() => {\n        rescale();\n      });\n    };\n\n    if (context.viewMode === 'story' && measureEnabled) {\n      globalThis.document.addEventListener('pointerover', onPointerOver);\n      init();\n      globalThis.window.addEventListener('resize', onResize);\n      // Draw the element below the pointer when first enabled\n      findAndDrawElement(pointer.x, pointer.y);\n    }\n\n    return () => {\n      globalThis.window.removeEventListener('resize', onResize);\n      destroy();\n    };\n  }, [measureEnabled, context.viewMode]);\n\n  return StoryFn();\n};\n"
  },
  {
    "path": "code/core/src/mocking-utils/automock.ts",
    "content": "import type {\n  Declaration,\n  ExportDefaultDeclaration,\n  ExportNamedDeclaration,\n  Expression,\n  Pattern,\n  Program,\n} from 'estree';\nimport MagicString from 'magic-string';\n\nimport { type Positioned, getArbitraryModuleIdentifier } from './esmWalker.ts';\n\ntype ParseFn = (code: string) => Program;\n\nexport const __STORYBOOK_GLOBAL_THIS_ACCESSOR__ = '__vitest_mocker__';\n\nexport function getAutomockCode(originalCode: string, isSpy: boolean, parse: ParseFn) {\n  const mocked = automockModule(originalCode, isSpy ? 'autospy' : 'automock', parse, {\n    globalThisAccessor: JSON.stringify(__STORYBOOK_GLOBAL_THIS_ACCESSOR__),\n  });\n  return mocked;\n}\n\n// TODO: Remove as soon as https://github.com/vitest-dev/vitest/pull/8301 is released and we use it\n/**\n * Copyright (c) Vitest\n * https://github.com/vitest-dev/vitest/blob/v3.2.4/packages/mocker/src/node/automockPlugin.ts#L36C17-L36C31\n * MIT License\n *\n * Copyright (c) 2021-Present Vitest Team\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and\n * associated documentation files (the \"Software\"), to deal in the Software without restriction,\n * including without limitation the rights to use, copy, modify, merge, publish, distribute,\n * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or\n * substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\n * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\nexport function automockModule(\n  code: string,\n  mockType: 'automock' | 'autospy',\n  parse: (code: string) => any,\n  options: any = {}\n): MagicString {\n  const globalThisAccessor =\n    options.globalThisAccessor || JSON.stringify(__STORYBOOK_GLOBAL_THIS_ACCESSOR__);\n  const ast = parse(code) as Program;\n\n  const m = new MagicString(code);\n\n  const allSpecifiers: { name: string; alias?: string }[] = [];\n  let importIndex = 0;\n  for (const _node of ast.body) {\n    if (_node.type === 'ExportAllDeclaration') {\n      throw new Error(\n        `automocking files with \\`export *\\` is not supported in browser mode because it cannot be statically analysed`\n      );\n    }\n\n    if (_node.type === 'ExportNamedDeclaration') {\n      const node = _node as Positioned<ExportNamedDeclaration>;\n      const declaration = node.declaration; // export const name\n\n      function traversePattern(expression: Pattern) {\n        // export const test = '1'\n        if (expression.type === 'Identifier') {\n          allSpecifiers.push({ name: expression.name });\n        }\n        // export const [test, ...rest] = [1, 2, 3]\n        else if (expression.type === 'ArrayPattern') {\n          expression.elements.forEach((element) => {\n            if (!element) {\n              return;\n            }\n            traversePattern(element);\n          });\n        } else if (expression.type === 'ObjectPattern') {\n          expression.properties.forEach((property) => {\n            // export const { ...rest } = {}\n            if (property.type === 'RestElement') {\n              traversePattern(property);\n            }\n            // export const { test, test2: alias } = {}\n            else if (property.type === 'Property') {\n              traversePattern(property.value);\n            } else {\n              property satisfies never;\n            }\n          });\n        } else if (expression.type === 'RestElement') {\n          traversePattern(expression.argument);\n        }\n        // const [name[1], name[2]] = []\n        // cannot be used in export\n        else if (expression.type === 'AssignmentPattern') {\n          throw new Error(`AssignmentPattern is not supported. Please open a new bug report.`);\n        }\n        // const test = thing.func()\n        // cannot be used in export\n        else if (expression.type === 'MemberExpression') {\n          throw new Error(`MemberExpression is not supported. Please open a new bug report.`);\n        } else {\n          expression satisfies never;\n        }\n      }\n\n      if (declaration) {\n        if (declaration.type === 'FunctionDeclaration') {\n          allSpecifiers.push({ name: declaration.id.name });\n        } else if (declaration.type === 'VariableDeclaration') {\n          declaration.declarations.forEach((declaration) => {\n            traversePattern(declaration.id);\n          });\n        } else if (declaration.type === 'ClassDeclaration') {\n          allSpecifiers.push({ name: declaration.id.name });\n        } else {\n          declaration satisfies never;\n        }\n        m.remove(node.start, (declaration as Positioned<Declaration>).start);\n      }\n\n      const specifiers = node.specifiers || [];\n      const source = node.source;\n\n      if (!source && specifiers.length) {\n        specifiers.forEach((specifier) => {\n          allSpecifiers.push({\n            alias: getArbitraryModuleIdentifier(specifier.exported),\n            name: getArbitraryModuleIdentifier(specifier.local),\n          });\n        });\n        m.remove(node.start, node.end);\n      } else if (source && specifiers.length) {\n        const importNames: [string, string][] = [];\n\n        specifiers.forEach((specifier) => {\n          const importedName = `__vitest_imported_${importIndex++}__`;\n          importNames.push([getArbitraryModuleIdentifier(specifier.local), importedName]);\n          allSpecifiers.push({\n            name: importedName,\n            alias: getArbitraryModuleIdentifier(specifier.exported),\n          });\n        });\n\n        const importString = `import { ${importNames\n          .map(([name, alias]) => `${name} as ${alias}`)\n          .join(', ')} } from '${source.value}'`;\n\n        m.overwrite(node.start, node.end, importString);\n      }\n    }\n    if (_node.type === 'ExportDefaultDeclaration') {\n      const node = _node as Positioned<ExportDefaultDeclaration>;\n      const declaration = node.declaration as Positioned<Expression>;\n      allSpecifiers.push({ name: '__vitest_default', alias: 'default' });\n      m.overwrite(node.start, declaration.start, `const __vitest_default = `);\n    }\n  }\n  const moduleObject = `\nconst __vitest_current_es_module__ = {\n  __esModule: true,\n  ${allSpecifiers.map(({ name }) => `[\"${name}\"]: ${name},`).join('\\n  ')}\n}\nconst __vitest_mocked_module__ = globalThis[${globalThisAccessor}].mockObject(__vitest_current_es_module__, \"${mockType}\")\n`;\n\n  // Register module mock spies in the global registry so that clearAllMocks/resetAllMocks/\n  // restoreAllMocks from storybook/test can find and clear them. This is needed because the\n  // module mocker may use a different @vitest/spy instance than the one bundled with storybook/test.\n  const spyRegistration = `\nif (!globalThis.__STORYBOOK_MODULE_MOCK_SPIES__) { globalThis.__STORYBOOK_MODULE_MOCK_SPIES__ = new Set(); }\nfor (const __vitest_key__ of Object.keys(__vitest_mocked_module__)) {\n  const __vitest_val__ = __vitest_mocked_module__[__vitest_key__];\n  if (__vitest_val__ && typeof __vitest_val__ === \"function\" && __vitest_val__._isMockFunction === true) {\n    globalThis.__STORYBOOK_MODULE_MOCK_SPIES__.add(__vitest_val__);\n  }\n}\n`;\n\n  const assigning = allSpecifiers\n    .map(({ name }, index) => {\n      return `const __vitest_mocked_${index}__ = __vitest_mocked_module__[\"${name}\"]`;\n    })\n    .join('\\n');\n\n  const redeclarations = allSpecifiers\n    .map(({ name, alias }, index) => {\n      return `  __vitest_mocked_${index}__ as ${alias || name},`;\n    })\n    .join('\\n');\n  const specifiersExports = `\nexport {\n${redeclarations}\n}\n`;\n  m.append(moduleObject + spyRegistration + assigning + specifiersExports);\n  return m;\n}\n"
  },
  {
    "path": "code/core/src/mocking-utils/esmWalker.ts",
    "content": "// TODO: Remove as soon as https://github.com/vitest-dev/vitest/pull/8301 is released and we use it\n/**\n * Copyright (c) Vitest\n * https://github.com/vitest-dev/vitest/blob/v3.2.4/packages/mocker/src/node/esmWalker.ts MIT\n * License\n *\n * Copyright (c) 2021-Present Vitest Team\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and\n * associated documentation files (the \"Software\"), to deal in the Software without restriction,\n * including without limitation the rights to use, copy, modify, merge, publish, distribute,\n * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or\n * substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\n * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\nimport type {\n  CallExpression,\n  Function as FunctionNode,\n  Identifier,\n  ImportExpression,\n  Literal,\n  Pattern,\n  Property,\n  VariableDeclaration,\n  Node as _Node,\n} from 'estree';\nimport { walk as eswalk } from 'estree-walker';\n\nexport type * from 'estree';\n\nexport type Positioned<T> = T & {\n  start: number;\n  end: number;\n};\n\nexport type Node = Positioned<_Node>;\n\ninterface IdentifierInfo {\n  /** If the identifier is used in a property shorthand { foo } -> { foo: **import_x**.foo } */\n  hasBindingShortcut: boolean;\n  /** The identifier is used in a class declaration */\n  classDeclaration: boolean;\n  /** The identifier is a name for a class expression */\n  classExpression: boolean;\n}\n\ninterface Visitors {\n  onIdentifier?: (node: Positioned<Identifier>, info: IdentifierInfo, parentStack: Node[]) => void;\n  onImportMeta?: (node: Node) => void;\n  onDynamicImport?: (node: Positioned<ImportExpression>) => void;\n  onCallExpression?: (node: Positioned<CallExpression>) => void;\n}\n\nconst isNodeInPatternWeakSet = new WeakSet<_Node>();\nexport function setIsNodeInPattern(node: Property): WeakSet<_Node> {\n  return isNodeInPatternWeakSet.add(node);\n}\nexport function isNodeInPattern(node: _Node): node is Property {\n  return isNodeInPatternWeakSet.has(node);\n}\n\n/** Same logic from @vue/compiler-core & @vue/compiler-sfc Except this is using acorn AST */\nexport function esmWalker(\n  root: Node,\n  { onIdentifier, onImportMeta, onDynamicImport, onCallExpression }: Visitors\n): void {\n  const parentStack: Node[] = [];\n  const varKindStack: VariableDeclaration['kind'][] = [];\n  const scopeMap = new WeakMap<_Node, Set<string>>();\n  const identifiers: [id: any, stack: Node[]][] = [];\n\n  const setScope = (node: _Node, name: string) => {\n    let scopeIds = scopeMap.get(node);\n    if (scopeIds && scopeIds.has(name)) {\n      return;\n    }\n\n    if (!scopeIds) {\n      scopeIds = new Set();\n      scopeMap.set(node, scopeIds);\n    }\n    scopeIds.add(name);\n  };\n\n  function isInScope(name: string, parents: Node[]) {\n    return parents.some((node) => node && scopeMap.get(node)?.has(name));\n  }\n  function handlePattern(p: Pattern, parentScope: _Node) {\n    if (p.type === 'Identifier') {\n      setScope(parentScope, p.name);\n    } else if (p.type === 'RestElement') {\n      handlePattern(p.argument, parentScope);\n    } else if (p.type === 'ObjectPattern') {\n      p.properties.forEach((property) => {\n        if (property.type === 'RestElement') {\n          setScope(parentScope, (property.argument as Identifier).name);\n        } else {\n          handlePattern(property.value, parentScope);\n        }\n      });\n    } else if (p.type === 'ArrayPattern') {\n      p.elements.forEach((element) => {\n        if (element) {\n          handlePattern(element, parentScope);\n        }\n      });\n    } else if (p.type === 'AssignmentPattern') {\n      handlePattern(p.left, parentScope);\n    } else {\n      setScope(parentScope, (p as any).name);\n    }\n  }\n\n  eswalk(root as Node, {\n    enter(node, parent) {\n      if (node.type === 'ImportDeclaration') {\n        return this.skip();\n      }\n\n      // track parent stack, skip for \"else-if\"/\"else\" branches as acorn nests\n      // the ast within \"if\" nodes instead of flattening them\n      if (parent && !(parent.type === 'IfStatement' && node === parent.alternate)) {\n        parentStack.unshift(parent as Node);\n      }\n\n      // track variable declaration kind stack used by VariableDeclarator\n      if (node.type === 'VariableDeclaration') {\n        varKindStack.unshift(node.kind);\n      }\n\n      if (node.type === 'CallExpression') {\n        onCallExpression?.(node as Positioned<CallExpression>);\n      }\n\n      if (node.type === 'MetaProperty' && node.meta.name === 'import') {\n        onImportMeta?.(node as Node);\n      } else if (node.type === 'ImportExpression') {\n        onDynamicImport?.(node as Positioned<ImportExpression>);\n      }\n\n      if (node.type === 'Identifier') {\n        if (!isInScope(node.name, parentStack) && isRefIdentifier(node, parent!, parentStack)) {\n          // record the identifier, for DFS -> BFS\n          identifiers.push([node, parentStack.slice(0)]);\n        }\n      } else if (isFunctionNode(node)) {\n        // If it is a function declaration, it could be shadowing an import\n        // Add its name to the scope so it won't get replaced\n        if (node.type === 'FunctionDeclaration') {\n          const parentScope = findParentScope(parentStack);\n          if (parentScope) {\n            setScope(parentScope, node.id!.name);\n          }\n        }\n        // walk function expressions and add its arguments to known identifiers\n        // so that we don't prefix them\n        node.params.forEach((p) => {\n          if (p.type === 'ObjectPattern' || p.type === 'ArrayPattern') {\n            handlePattern(p, node);\n            return;\n          }\n          (eswalk as any)(p.type === 'AssignmentPattern' ? p.left : p, {\n            enter(child: Node, parent: Node) {\n              // skip params default value of destructure\n              if (parent?.type === 'AssignmentPattern' && parent?.right === child) {\n                return this.skip();\n              }\n\n              if (child.type !== 'Identifier') {\n                return;\n              }\n              // do not record as scope variable if is a destructuring keyword\n              if (isStaticPropertyKey(child, parent)) {\n                return;\n              }\n              // do not record if this is a default value\n              // assignment of a destructuring variable\n              if (\n                (parent?.type === 'TemplateLiteral' && parent?.expressions.includes(child)) ||\n                (parent?.type === 'CallExpression' && parent?.callee === child)\n              ) {\n                return;\n              }\n\n              setScope(node, child.name);\n            },\n          });\n        });\n      } else if (node.type === 'Property' && parent!.type === 'ObjectPattern') {\n        // mark property in destructuring pattern\n        setIsNodeInPattern(node);\n      } else if (node.type === 'VariableDeclarator') {\n        const parentFunction = findParentScope(parentStack, varKindStack[0] === 'var');\n        if (parentFunction) {\n          handlePattern(node.id, parentFunction);\n        }\n      } else if (node.type === 'CatchClause' && node.param) {\n        handlePattern(node.param, node);\n      }\n    },\n\n    leave(node, parent) {\n      // untrack parent stack from above\n      if (parent && !(parent.type === 'IfStatement' && node === parent.alternate)) {\n        parentStack.shift();\n      }\n\n      if (node.type === 'VariableDeclaration') {\n        varKindStack.shift();\n      }\n    },\n  });\n\n  // emit the identifier events in BFS so the hoisted declarations\n  // can be captured correctly\n  identifiers.forEach(([node, stack]) => {\n    if (!isInScope(node.name, stack)) {\n      const parent = stack[0];\n      const grandparent = stack[1];\n      const hasBindingShortcut =\n        isStaticProperty(parent) &&\n        parent.shorthand &&\n        (!isNodeInPattern(parent) || isInDestructuringAssignment(parent, parentStack));\n\n      const classDeclaration =\n        (parent.type === 'PropertyDefinition' && grandparent?.type === 'ClassBody') ||\n        (parent.type === 'ClassDeclaration' && node === parent.superClass);\n\n      const classExpression = parent.type === 'ClassExpression' && node === parent.id;\n\n      onIdentifier?.(\n        node,\n        {\n          hasBindingShortcut,\n          classDeclaration,\n          classExpression,\n        },\n        stack\n      );\n    }\n  });\n}\n\nfunction isRefIdentifier(id: Identifier, parent: _Node, parentStack: _Node[]) {\n  // declaration id\n  if (\n    parent.type === 'CatchClause' ||\n    ((parent.type === 'VariableDeclarator' || parent.type === 'ClassDeclaration') &&\n      parent.id === id)\n  ) {\n    return false;\n  }\n\n  if (isFunctionNode(parent)) {\n    // function declaration/expression id\n    if ((parent as any).id === id) {\n      return false;\n    }\n\n    // params list\n    if (parent.params.includes(id)) {\n      return false;\n    }\n  }\n\n  // class method name\n  if (parent.type === 'MethodDefinition' && !parent.computed) {\n    return false;\n  }\n\n  // property key\n  if (isStaticPropertyKey(id, parent)) {\n    return false;\n  }\n\n  // object destructuring pattern\n  if (isNodeInPattern(parent) && parent.value === id) {\n    return false;\n  }\n\n  // non-assignment array destructuring pattern\n  if (parent.type === 'ArrayPattern' && !isInDestructuringAssignment(parent, parentStack)) {\n    return false;\n  }\n\n  // member expression property\n  if (parent.type === 'MemberExpression' && parent.property === id && !parent.computed) {\n    return false;\n  }\n\n  if (parent.type === 'ExportSpecifier') {\n    return false;\n  }\n\n  // is a special keyword but parsed as identifier\n  if (id.name === 'arguments') {\n    return false;\n  }\n\n  return true;\n}\n\nexport function isStaticProperty(node: _Node): node is Property {\n  return node && node.type === 'Property' && !node.computed;\n}\n\nexport function isStaticPropertyKey(node: _Node, parent: _Node): boolean {\n  return isStaticProperty(parent) && parent.key === node;\n}\n\nconst functionNodeTypeRE = /Function(?:Expression|Declaration)$|Method$/;\nexport function isFunctionNode(node: _Node): node is FunctionNode {\n  return functionNodeTypeRE.test(node.type);\n}\n\nconst blockNodeTypeRE = /^BlockStatement$|^For(?:In|Of)?Statement$/;\nfunction isBlock(node: _Node) {\n  return blockNodeTypeRE.test(node.type);\n}\n\nfunction findParentScope(parentStack: _Node[], isVar = false): _Node | undefined {\n  return parentStack.find(isVar ? isFunctionNode : isBlock);\n}\n\nexport function isInDestructuringAssignment(parent: _Node, parentStack: _Node[]): boolean {\n  if (parent && (parent.type === 'Property' || parent.type === 'ArrayPattern')) {\n    return parentStack.some((i) => i.type === 'AssignmentExpression');\n  }\n\n  return false;\n}\n\nexport function getArbitraryModuleIdentifier(node: Identifier | Literal): string {\n  return node.type === 'Identifier' ? node.name : node.raw!;\n}\n"
  },
  {
    "path": "code/core/src/mocking-utils/extract.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { parse } from '@babel/parser';\nimport { readFileSync } from 'fs';\n\nimport * as extractModule from './extract.ts';\nimport * as resolveModule from './resolve.ts';\n\nvi.mock('fs', async () => {\n  const actual = await vi.importActual<typeof import('fs')>('fs');\n  return {\n    ...actual,\n    readFileSync: vi.fn(),\n  };\n});\n\nvi.mock('./resolve', async () => {\n  return {\n    resolveMock: vi.fn((path, root, importer, findMockRedirect) => {\n      const result =\n        path === './bar/baz.js'\n          ? { absolutePath: '/abs/path/bar/baz.js', redirectPath: null }\n          : path === './bar/baz.utils'\n            ? { absolutePath: '/abs/path/bar/baz.utils.ts', redirectPath: null }\n            : path === './bar/baz.utils.ts'\n              ? { absolutePath: '/abs/path/bar/baz.utils.ts', redirectPath: null }\n              : { absolutePath: '/abs/path', redirectPath: null };\n\n      if (findMockRedirect) {\n        const redirectPath = findMockRedirect(root, result.absolutePath, null);\n        return { ...result, redirectPath };\n      }\n\n      return result;\n    }),\n  };\n});\n\nconst parser = (input: string) =>\n  parse(input, { sourceType: 'module', plugins: ['jsx', 'typescript'] });\n\ndescribe('isModuleDirectory', () => {\n  it('returns true for node_modules path', () => {\n    expect(extractModule.isModuleDirectory('/foo/node_modules/bar')).toBe(true);\n  });\n\n  it('returns false for non-node_modules path', () => {\n    expect(extractModule.isModuleDirectory('/foo/bar')).toBe(false);\n  });\n});\n\ndescribe('extractMockCalls', () => {\n  const previewConfigPath = '/project/.storybook/preview.tsx';\n  const configDir = '/project/.storybook';\n  const root = '/project';\n  const coreOptions = { disableTelemetry: true };\n\n  const findMockRedirect = vi.fn(() => null);\n\n  const extractMockCalls = (previewContent: string) => {\n    vi.mocked(readFileSync).mockReturnValue(previewContent);\n    return extractModule.extractMockCalls(\n      { previewConfigPath, configDir, coreOptions },\n      parser,\n      root,\n      findMockRedirect\n    );\n  };\n\n  beforeEach(() => {\n    vi.clearAllMocks();\n    findMockRedirect.mockReturnValue(null);\n  });\n\n  it('returns empty array if readFileSync throws', () => {\n    vi.mocked(readFileSync).mockImplementation(() => {\n      throw new Error('fail');\n    });\n    const result = extractMockCalls('');\n    expect(result).toEqual([]);\n  });\n\n  it('extracts mocks from preview file content with spy', () => {\n    const previewContent = `\n      sb.mock('foo', { spy: true });\n    `;\n    const result = extractMockCalls(previewContent);\n    expect(result).toEqual([\n      {\n        path: 'foo',\n        absolutePath: '/abs/path',\n        redirectPath: null,\n        spy: true,\n      },\n    ]);\n    expect(resolveModule.resolveMock).toHaveBeenCalledWith(\n      'foo',\n      root,\n      previewConfigPath,\n      findMockRedirect\n    );\n  });\n\n  it('handles no sb.mock calls in preview file', () => {\n    const previewContent = `\n      // no mocks here\n      const a = 1;\n    `;\n    const result = extractMockCalls(previewContent);\n    expect(result).toEqual([]);\n  });\n\n  it('handles missing spy option in preview file', () => {\n    const previewContent = `\n      sb.mock('bar');\n    `;\n    const result = extractMockCalls(previewContent);\n    expect(result).toEqual([\n      {\n        path: 'bar',\n        absolutePath: '/abs/path',\n        redirectPath: null,\n        spy: false,\n      },\n    ]);\n  });\n\n  it('supports sb.mock(import(\"<xyz>\"), { spy: true })', () => {\n    const previewContent = `\n      sb.mock(import('./bar/baz'), { spy: true });\n    `;\n\n    const result = extractMockCalls(previewContent);\n\n    // The path should be the import argument value, if extractMockCalls supports this pattern\n    expect(result).toEqual([\n      {\n        path: './bar/baz',\n        absolutePath: '/abs/path',\n        redirectPath: null,\n        spy: true,\n      },\n    ]);\n  });\n\n  it('supports sb.mock(import(\"<xyz>.js\"), { spy: true }) with extensions stripped out', () => {\n    const previewContent = `\n      sb.mock(import('./bar/baz.js'), { spy: true });\n    `;\n\n    const result = extractMockCalls(previewContent);\n\n    // The path should be the import argument value, if extractMockCalls supports this pattern\n    expect(result).toEqual([\n      {\n        path: './bar/baz',\n        absolutePath: '/abs/path/bar/baz.js',\n        redirectPath: null,\n        spy: true,\n      },\n    ]);\n  });\n\n  it('supports sb.mock(import(\"<xyz>.js\"), { spy: true }) with extensions stripped out - 2', () => {\n    const previewContent = `\n      sb.mock(import('./bar/baz.utils.ts'), { spy: true });\n    `;\n\n    const result = extractMockCalls(previewContent);\n\n    // The path should be the import argument value, if extractMockCalls supports this pattern\n    expect(result).toEqual([\n      {\n        path: './bar/baz.utils',\n        absolutePath: '/abs/path/bar/baz.utils.ts',\n        redirectPath: null,\n        spy: true,\n      },\n    ]);\n  });\n\n  it('supports sb.mock(import(\"<xyz>\"), { spy: true }) without extensions', () => {\n    const previewContent = `\n      sb.mock(import('./bar/baz.utils'), { spy: true });\n    `;\n\n    const result = extractMockCalls(previewContent);\n\n    // The path should be the import argument value, if extractMockCalls supports this pattern\n    expect(result).toEqual([\n      {\n        path: './bar/baz.utils',\n        absolutePath: '/abs/path/bar/baz.utils.ts',\n        redirectPath: null,\n        spy: true,\n      },\n    ]);\n  });\n\n  describe('rewriteSbMockImportCalls', () => {\n    it('rewrites sb.mock(import(\"<xyz>\"), { spy: true }) to sb.mock(\"<xyz>\", { spy: true })', () => {\n      const code = `\n        sb.mock(import('./bar/baz'), { spy: true });\n      `;\n\n      const result = extractModule.rewriteSbMockImportCalls(code);\n      expect(result.code).toMatchInlineSnapshot(`\n        \"sb.mock(\"./bar/baz\", {\n          spy: true\n        });\"\n      `);\n    });\n\n    it('rewrites sb.mock(import(\"<xyz>\")) to sb.mock(\"<xyz>\")', () => {\n      const code = `\n        sb.mock(import('./bar/baz'));\n      `;\n\n      const result = extractModule.rewriteSbMockImportCalls(code);\n      expect(result.code).toMatchInlineSnapshot(`\n        \"sb.mock(\"./bar/baz\");\"\n      `);\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/mocking-utils/extract.ts",
    "content": "import { readFileSync } from 'node:fs';\n\nimport { generate, parser, types as t } from 'storybook/internal/babel';\nimport { logger } from 'storybook/internal/node-logger';\nimport { telemetry } from 'storybook/internal/telemetry';\nimport type { CoreConfig } from 'storybook/internal/types';\n\nimport { transformSync } from 'esbuild';\nimport { walk } from 'estree-walker';\nimport { basename, normalize } from 'pathe';\n\nimport { resolveMock } from './resolve.ts';\n\nconst DEFAULT_MODULE_DIRECTORIES = ['/node_modules/'];\n\nexport function isModuleDirectory(path: string) {\n  const normalizedPath = normalize(path);\n  return DEFAULT_MODULE_DIRECTORIES.some((dir: string) => normalizedPath.includes(dir));\n}\n\nexport type MockCall = {\n  path: string;\n  absolutePath: string;\n  redirectPath: string | null;\n  spy: boolean;\n};\n\ninterface ExtractMockCallsOptions {\n  /** The absolute path to the preview.tsx file where mocks are defined. */\n  previewConfigPath: string;\n  /** The absolute path to the Storybook config directory. */\n  coreOptions?: CoreConfig;\n  /** Configuration directory */\n  configDir: string;\n}\n\n/**\n * A wrapper around the babel parser that enables the necessary plugins to handle modern JavaScript\n * features, including TSX.\n *\n * @param code - The code to parse.\n * @returns The parsed code.\n */\nexport const babelParser = (code: string) => {\n  return parser.parse(code, {\n    sourceType: 'module',\n    // Enable plugins to handle modern JavaScript features, including TSX.\n    plugins: ['typescript', 'jsx', 'classProperties', 'objectRestSpread'],\n    errorRecovery: true,\n  }).program;\n};\n\n/** Utility to rewrite sb.mock(import('...'), ...) to sb.mock('...', ...) */\nexport function rewriteSbMockImportCalls(code: string) {\n  const ast = babelParser(code);\n\n  walk(ast as any, {\n    enter(node: any) {\n      if (\n        node.type === 'CallExpression' &&\n        node.callee.type === 'MemberExpression' &&\n        node.callee.object.type === 'Identifier' &&\n        node.callee.object.name === 'sb' &&\n        node.callee.property.type === 'Identifier' &&\n        node.callee.property.name === 'mock' &&\n        node.arguments.length > 0 &&\n        node.arguments[0].type === 'CallExpression' &&\n        node.arguments[0].callee.type === 'Import' &&\n        node.arguments[0].arguments.length === 1 &&\n        node.arguments[0].arguments[0].type === 'StringLiteral'\n      ) {\n        // Replace sb.mock(import('foo'), ...) with sb.mock('foo', ...)\n        node.arguments[0] = t.stringLiteral(node.arguments[0].arguments[0].value);\n      }\n    },\n  });\n  return generate(ast, {}, code);\n}\n\n/**\n * Extracts all sb.mock() calls from the preview config file.\n *\n * @param this PluginContext\n */\nexport function extractMockCalls(\n  options: ExtractMockCallsOptions,\n  parse: (\n    input: string,\n    options?: {\n      allowReturnOutsideFunction?: boolean;\n      jsx?: boolean;\n    }\n  ) => t.Node,\n  root: string,\n  findMockRedirect: (\n    root: string,\n    absolutePath: string,\n    externalPath: string | null\n  ) => string | null\n): MockCall[] {\n  try {\n    const previewConfigCode = readFileSync(options.previewConfigPath, 'utf-8');\n    const { code: jsCode } = transformSync(previewConfigCode, { loader: 'tsx', format: 'esm' });\n    const ast = parse(jsCode);\n    const mocks: MockCall[] = [];\n\n    /** Helper to check if an ObjectExpression node has spy: true */\n    function hasSpyTrue(objectExpression: any): boolean {\n      if (!objectExpression || !objectExpression.properties) {\n        return false;\n      }\n      for (const prop of objectExpression.properties) {\n        if (\n          prop.type === 'ObjectProperty' &&\n          ((prop.key.type === 'Identifier' && prop.key.name === 'spy') ||\n            (prop.key.type === 'StringLiteral' && prop.key.value === 'spy')) &&\n          prop.value.type === 'BooleanLiteral' &&\n          prop.value.value === true\n        ) {\n          return true;\n        }\n      }\n      return false;\n    }\n\n    walk(ast as any, {\n      // @ts-expect-error - Node comes from babel\n      async enter(node: t.Node) {\n        if (\n          node.type !== 'CallExpression' ||\n          node.callee.type !== 'MemberExpression' ||\n          node.callee.object.type !== 'Identifier' ||\n          node.callee.object.name !== 'sb' ||\n          node.callee.property.type !== 'Identifier' ||\n          node.callee.property.name !== 'mock'\n        ) {\n          return;\n        }\n\n        if (node.arguments.length === 0) {\n          return;\n        }\n\n        let path: string | undefined;\n        // Support sb.mock('foo', ...) and sb.mock(import('foo'), ...)\n        if (node.arguments[0].type === 'StringLiteral') {\n          path = node.arguments[0].value as string;\n        } else if (\n          node.arguments[0].type === 'CallExpression' &&\n          node.arguments[0].callee.type === 'Import' &&\n          node.arguments[0].arguments[0].type === 'StringLiteral'\n        ) {\n          path = node.arguments[0].arguments[0].value;\n        } else {\n          return;\n        }\n\n        const spy =\n          node.arguments.length > 1 &&\n          node.arguments[1].type === 'ObjectExpression' &&\n          hasSpyTrue(node.arguments[1]);\n\n        const { absolutePath, redirectPath } = resolveMock(\n          path,\n          root,\n          options.previewConfigPath,\n          findMockRedirect\n        );\n\n        const pathWithoutExtension = path.replace(/\\.[^/.]+$/, '');\n        const basenameAbsolutePath = basename(absolutePath);\n        const basenamePath = basename(path);\n\n        const pathWithoutExtensionAndBasename =\n          basenameAbsolutePath === basenamePath ? pathWithoutExtension : path;\n\n        mocks.push({\n          path: pathWithoutExtensionAndBasename,\n          absolutePath,\n          redirectPath,\n          spy,\n        });\n      },\n    });\n\n    if (!options.coreOptions?.disableTelemetry) {\n      telemetry(\n        'mocking',\n        {\n          modulesMocked: mocks.length,\n          modulesSpied: mocks.map((mock) => mock.spy).filter(Boolean).length,\n          modulesManuallyMocked: mocks.map((mock) => !!mock.redirectPath).filter(Boolean).length,\n        },\n        { configDir: options.configDir }\n      );\n    }\n    return mocks;\n  } catch (error) {\n    logger.debug('Error extracting mock calls: ' + String(error));\n    return [];\n  }\n}\n"
  },
  {
    "path": "code/core/src/mocking-utils/index.ts",
    "content": "export * from './automock.ts';\nexport * from './extract.ts';\nexport * from './resolve.ts';\nexport * from './esmWalker.ts';\nexport * from './runtime.ts';\nexport * from './redirect.ts';\n"
  },
  {
    "path": "code/core/src/mocking-utils/mocker-runtime.js",
    "content": "import { MockerRegistry } from '@vitest/mocker';\nimport { ModuleMocker, createCompilerHints } from '@vitest/mocker/browser';\n\n/** An interceptor for module mocking. */\nexport class ModuleMockerInterceptor {\n  // A registry for runtime mocks (e.g., `sb.mock('path', () => ({}))`)\n  mocks = new MockerRegistry();\n\n  constructor() {}\n\n  /**\n   * Called by ModuleMocker when `sb.mock()` is executed. We just store the mock in our registry.\n   * The dynamic MSW handler will pick it up on the next relevant network request. Currently, we\n   * don't use this.mocks in any way. Mocks will be registered in the user's preview file and live\n   * until the end. There is no way to invalidate or delete them.\n   */\n  async register(module) {\n    this.mocks.add(module);\n  }\n\n  async delete(url) {\n    this.mocks.delete(url);\n  }\n\n  async invalidate() {\n    this.mocks.clear();\n  }\n}\n\n// Dummy implementation of the RPC interface, since it is not used in build mode.\nconst rpc = (method) => {\n  switch (method) {\n    case 'resolveId':\n      return Promise.resolve({\n        id: '',\n        url: '',\n        optimized: false,\n      });\n    case 'resolveMock':\n      return Promise.resolve({\n        mockType: 'dummy',\n        resolvedId: '',\n        resolvedUrl: '',\n        redirectUrl: '',\n        needsInterop: false,\n      });\n    case 'invalidate':\n      return Promise.resolve();\n  }\n};\n\n// In build mode, we don't need runtime handling of mocks.\n// Everything is handled at build time and via the MSW interceptor.\nclass BuildModuleMocker extends ModuleMocker {\n  queueMock() {\n    // noop\n  }\n}\n\nfunction registerModuleMocker(interceptor) {\n  const mocker = new BuildModuleMocker(\n    interceptor('__vitest_mocker__'),\n    {\n      resolveId(id, importer) {\n        return rpc('resolveId', { id, importer });\n      },\n      resolveMock(id, importer, options) {\n        return rpc('resolveMock', { id, importer, options });\n      },\n      async invalidate(ids) {\n        return rpc('invalidate', { ids });\n      },\n    },\n    (...args) => {\n      return globalThis.__STORYBOOK_MODULE_TEST__.spyOn(...args);\n    },\n    {\n      root: '',\n    }\n  );\n\n  globalThis['__vitest_mocker__'] = mocker;\n\n  return createCompilerHints({\n    globalThisKey: '__vitest_mocker__',\n  });\n}\n\nglobalThis.__STORYBOOK_MOCKER__ = registerModuleMocker(() => new ModuleMockerInterceptor());\n"
  },
  {
    "path": "code/core/src/mocking-utils/redirect.ts",
    "content": "// Re-export findMockRedirect from @vitest/mocker/redirect\n// This allows builders to use it without depending on @vitest/mocker directly\nexport { findMockRedirect } from '@vitest/mocker/redirect';\n"
  },
  {
    "path": "code/core/src/mocking-utils/resolve.ts",
    "content": "import { readFileSync, realpathSync } from 'node:fs';\nimport { createRequire } from 'node:module';\n\nimport { dirname, isAbsolute, join, resolve } from 'pathe';\nimport { exports as resolveExports } from 'resolve.exports';\n\nimport { isModuleDirectory } from './extract.ts';\n\nconst require = createRequire(import.meta.url);\n\n/**\n * Finds the package.json for a given module specifier.\n *\n * @param specifier The module specifier (e.g., 'uuid', 'lodash-es/add').\n * @param basedir The directory to start the search from.\n * @returns The path to the package.json and the package's contents.\n */\nfunction findPackageJson(specifier: string, basedir: string): { path: string; data: any } {\n  const packageJsonPath = require.resolve(`${specifier}/package.json`, { paths: [basedir] });\n  return {\n    path: packageJsonPath,\n    data: JSON.parse(readFileSync(packageJsonPath, 'utf-8')),\n  };\n}\n\n/**\n * Resolves an external module path to its absolute path. It considers the \"exports\" map in the\n * package.json file.\n *\n * @param path The raw module path from the `sb.mock()` call.\n * @param root The project's root directory.\n * @returns The absolute path to the module.\n */\nexport function resolveExternalModule(path: string, root: string) {\n  // --- External Package Resolution ---\n  const parts = path.split('/');\n  // For scoped packages like `@foo/bar`, the package name is the first two parts.\n  const packageName = path.startsWith('@') ? `${parts[0]}/${parts[1]}` : parts[0];\n  const entry = `.${path.slice(packageName.length)}`; // e.g., './add' from 'lodash-es/add'\n\n  const { path: packageJsonPath, data: pkg } = findPackageJson(packageName, root);\n  const packageDir = dirname(packageJsonPath);\n\n  // 1. Try to resolve using the \"exports\" map.\n  if (pkg.exports) {\n    const result = resolveExports(pkg, entry, {\n      browser: true,\n    });\n\n    if (result) {\n      return join(packageDir, result[0]);\n    }\n  }\n\n  return require.resolve(path, { paths: [root] });\n}\n\nexport function getIsExternal(path: string, importer: string) {\n  try {\n    return !isAbsolute(path) && isModuleDirectory(require.resolve(path, { paths: [importer] }));\n  } catch (e) {\n    return false;\n  }\n}\n\n/**\n * Resolves a mock path to its absolute path and checks for a `__mocks__` redirect. This function\n * uses `resolve.exports` to correctly handle modern ESM packages.\n *\n * @param path The raw module path from the `sb.mock()` call.\n * @param root The project's root directory.\n * @param importer The absolute path of the file containing the mock call (the preview file).\n */\nexport function resolveMock(\n  path: string,\n  root: string,\n  importer: string,\n  findMockRedirect: (\n    root: string,\n    absolutePath: string,\n    externalPath: string | null\n  ) => string | null\n) {\n  const isExternal = getIsExternal(path, root);\n  const externalPath = isExternal ? path : null;\n\n  const absolutePath = isExternal\n    ? resolveExternalModule(path, root)\n    : require.resolve(path, { paths: [dirname(importer)] });\n\n  const normalizedAbsolutePath = resolve(absolutePath);\n\n  const redirectPath = findMockRedirect(root, normalizedAbsolutePath, externalPath);\n\n  return {\n    absolutePath: normalizedAbsolutePath,\n    redirectPath, // will be null if no __mocks__ file is found\n  };\n}\n\n/**\n * External mean not absolute, and not relative\n *\n * We use `require.resolve` here, because import.meta.resolve needs a experimental node flag\n * (`--experimental-import-meta-resolve`) to be enabled to respect the context option.\n *\n * @param path - The path to the mock file\n * @param from - The root of the project, this should be an absolute path\n * @returns True if the mock path is external, false otherwise\n * @link https://nodejs.org/api/cli.html#--experimental-import-meta-resolve\n */\nexport function isExternal(path: string, from: string) {\n  try {\n    return !isAbsolute(path) && isModuleDirectory(require.resolve(path, { paths: [from] }));\n  } catch (e) {\n    return false;\n  }\n}\n\n/**\n * Normalizes a file path for comparison, resolving symlinks if possible. Falls back to the original\n * path if resolution fails.\n */\nexport function getRealPath(path: string, preserveSymlinks: boolean): string {\n  try {\n    return preserveSymlinks ? realpathSync(path) : path;\n  } catch {\n    return path;\n  }\n}\n\n/**\n * This is a wrapper around `require.resolve` that tries to resolve the path with different file\n * extensions.\n *\n * @param path - The path to the mock file\n * @param from - The root of the project, this should be an absolute path\n * @returns The resolved path\n */\nexport function resolveWithExtensions(path: string, from: string) {\n  const extensions = ['.js', '.ts', '.tsx', '.mjs', '.cjs', '.svelte', '.vue'];\n\n  for (const extension of extensions) {\n    try {\n      return require.resolve(path + extension, { paths: [from] });\n    } catch (e) {\n      continue;\n    }\n  }\n\n  return require.resolve(path, { paths: [from] });\n}\n"
  },
  {
    "path": "code/core/src/mocking-utils/runtime.ts",
    "content": "import { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * Returns the bundled mocker runtime script content. This is used by builders (webpack5, vite,\n * etc.) to inject the mocker runtime into the preview iframe.\n */\nexport function getMockerRuntime(): string {\n  return readFileSync(\n    fileURLToPath(import.meta.resolve('storybook/internal/mocking-utils/mocker-runtime')),\n    'utf-8'\n  );\n}\n"
  },
  {
    "path": "code/core/src/node-logger/README.md",
    "content": "# Storybook Logger\n\nAny node logging that is done through storybook should be done through this package.\n\nExamples:\n\n```js\nimport { logger } from 'storybook/internal/node-logger';\n\nlogger.info('Info message');\nlogger.warn('Warning message');\nlogger.error('Error message');\n```\n\nFor more information visit: [storybook.js.org](https://storybook.js.org)\n"
  },
  {
    "path": "code/core/src/node-logger/index.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport npmlog from 'npmlog';\n\nimport { logger } from './index.ts';\nimport * as loggerRaw from './logger/logger.ts';\n\nvi.mock('./logger/logger', () => ({\n  log: vi.fn(),\n  warn: vi.fn(),\n  error: vi.fn(),\n  debug: vi.fn(),\n  info: vi.fn(),\n  setLogLevel: vi.fn(),\n}));\n\nconst loggerMock = vi.mocked(loggerRaw);\n\nvi.mock('npmlog', () => ({\n  default: {\n    info: vi.fn(),\n    warn: vi.fn(),\n    error: vi.fn(),\n    levels: {\n      silly: -Infinity,\n      verbose: 1000,\n      info: 2000,\n      timing: 2500,\n      http: 3000,\n      notice: 3500,\n      warn: 4000,\n      error: 5000,\n      silent: Infinity,\n    },\n    level: 'info',\n  },\n}));\n\nvi.mock('./prompts/prompt-config', () => ({\n  isClackEnabled: vi.fn(() => false),\n}));\n\n//\n\ndescribe('node-logger', () => {\n  it('should have a warn method', () => {\n    const message = 'warning message';\n    logger.warn(message);\n    expect(loggerMock.warn).toHaveBeenCalledWith(message);\n  });\n\n  it('should sync --loglevel with npmlog', () => {\n    logger.setLogLevel('debug');\n    expect(npmlog.level).toBe('verbose');\n    expect(loggerMock.setLogLevel).toHaveBeenCalledWith('debug');\n\n    logger.setLogLevel('trace');\n    expect(npmlog.level).toBe('silly');\n    expect(loggerMock.setLogLevel).toHaveBeenCalledWith('trace');\n  });\n\n  it('should keep setLevel and setLogLevel consistent', () => {\n    logger.setLevel('warn');\n    expect(npmlog.level).toBe('warn');\n    expect(loggerMock.setLogLevel).toHaveBeenCalledWith('warn');\n  });\n\n  it('should have an error method', () => {\n    const message = 'error message';\n    logger.error(message);\n    expect(loggerMock.error).toHaveBeenCalledWith(expect.stringMatching('message'));\n  });\n  it('should format errors', () => {\n    const message = new Error('A complete disaster');\n    logger.error(message);\n    expect(loggerMock.error).toHaveBeenCalledWith(expect.stringMatching('A complete disaster'));\n  });\n});\n"
  },
  {
    "path": "code/core/src/node-logger/index.ts",
    "content": "/// <reference types=\"node\" />\nimport npmLog from 'npmlog';\nimport prettyTime from 'pretty-hrtime';\n\nimport * as newLogger from './logger/logger.ts';\n\nexport { prompt } from './prompts/index.ts';\nexport { logTracker } from './logger/log-tracker.ts';\nexport type { SpinnerInstance, TaskLogInstance } from './prompts/prompt-provider-base.ts';\nexport { protectUrls, createHyperlink } from './wrap-utils.ts';\nexport { CLI_COLORS } from './logger/colors.ts';\nexport { ConsoleLogger, StyledConsoleLogger } from './logger/console.ts';\n\nexport type { LogLevel } from './logger/logger.ts';\n\n// The default is stderr, which can cause some tools (like rush.js) to think\n// there are issues with the build: https://github.com/storybookjs/storybook/issues/14621\nnpmLog.stream = process.stdout;\n\nconst toNpmLogLevel = (level: newLogger.LogLevel): string => {\n  switch (level) {\n    case 'trace':\n      return 'silly';\n    case 'debug':\n      return 'verbose';\n    default:\n      return level;\n  }\n};\n\nconst setLoggerLevel = (level: newLogger.LogLevel = 'info'): void => {\n  npmLog.level = toNpmLogLevel(level);\n  newLogger.setLogLevel(level);\n};\n\nfunction hex(hexColor: string) {\n  // Ensure the hex color is 6 characters long and starts with '#'\n  if (!/^#?[0-9A-Fa-f]{6}$/.test(hexColor)) {\n    throw new Error('Invalid hex color. It must be a 6-character hex code.');\n  }\n\n  // Remove the leading '#' if it exists\n  if (hexColor.startsWith('#')) {\n    hexColor = hexColor.slice(1);\n  }\n\n  // Convert hex to RGB\n  const r = parseInt(hexColor.slice(0, 2), 16);\n  const g = parseInt(hexColor.slice(2, 4), 16);\n  const b = parseInt(hexColor.slice(4, 6), 16);\n\n  // Return the ANSI escape sequence for the given RGB color\n  return (text: string) => `\\x1b[38;2;${r};${g};${b}m${text}\\x1b[39m`;\n}\n\n/** @deprecated Use CLI_COLORS instead */\nexport const colors = {\n  pink: hex('#F1618C'),\n  purple: hex('#B57EE5'),\n  orange: hex('#F3AD38'),\n  green: hex('#A2E05E'),\n  blue: hex('#6DABF5'),\n  red: hex('#F16161'),\n  gray: hex('#B8C2CC'),\n};\n\nexport const logger = {\n  ...newLogger,\n  verbose: (message: string): void => newLogger.debug(message),\n\n  line: (count = 1): void => newLogger.log(`${Array(count - 1).fill('\\n')}`),\n  /** For non-critical issues or warnings */\n  warn: (message: string): void => newLogger.warn(message),\n  trace: ({ message, time }: { message: string; time: [number, number] }): void =>\n    newLogger.debug(`${message} (${colors.purple(prettyTime(time))})`),\n  setLevel: setLoggerLevel,\n  setLogLevel: setLoggerLevel,\n  error: (message: unknown): void => {\n    let msg: string;\n    if (message instanceof Error && message.stack) {\n      msg = message.stack.toString().replace(message.toString(), colors.red(message.toString()));\n    } else if (typeof message === 'string') {\n      msg = message.toString();\n    } else {\n      msg = String(message);\n    }\n\n    newLogger.error(msg.replaceAll(process.cwd(), '.'));\n  },\n};\n\nexport { npmLog as instance };\n\nconst logged = new Set();\nexport const once = (type: 'verbose' | 'info' | 'warn' | 'error') => (message: string) => {\n  if (logged.has(message)) {\n    return undefined;\n  }\n  logged.add(message);\n  return logger[type](message);\n};\n\nonce.clear = () => logged.clear();\nonce.verbose = once('verbose');\nonce.info = once('info');\nonce.warn = once('warn');\nonce.error = once('error');\n\nexport const deprecate = once('warn');\n"
  },
  {
    "path": "code/core/src/node-logger/logger/colors.ts",
    "content": "import picocolors from 'picocolors';\n\nexport const CLI_COLORS = {\n  success: picocolors.green,\n  error: picocolors.red,\n  warning: picocolors.yellow,\n  // Improve contrast on dark terminals by using cyan for info on all platforms\n  info: picocolors.cyan,\n  debug: picocolors.gray,\n  // Only color a link if it is the primary call to action, otherwise links shouldn't be colored\n  cta: picocolors.cyan,\n  muted: picocolors.dim,\n  storybook: (text: string) => `\\x1b[38;2;255;71;133m${text}\\x1b[39m`,\n};\n"
  },
  {
    "path": "code/core/src/node-logger/logger/console.ts",
    "content": "import picocolors from 'picocolors';\n\nimport { debug, error, log, warn } from './logger.ts';\n\ninterface ConsoleLoggerOptions {\n  prefix: string;\n  color:\n    | 'bgBlack'\n    | 'bgRed'\n    | 'bgGreen'\n    | 'bgYellow'\n    | 'bgBlue'\n    | 'bgMagenta'\n    | 'bgCyan'\n    | 'bgWhite'\n    | 'bgBlackBright'\n    | 'bgRedBright'\n    | 'bgGreenBright'\n    | 'bgYellowBright'\n    | 'bgBlueBright'\n    | 'bgMagentaBright'\n    | 'bgCyanBright'\n    | 'bgWhiteBright';\n}\n\nclass ConsoleLogger implements Console {\n  Console = ConsoleLogger;\n\n  protected timers = new Map<string, number>();\n  protected counters = new Map<string, number>();\n  protected lastStatusLine: string | null = null;\n  protected statusLineCount = 0;\n\n  // These will be overridden by child classes\n  protected get prefix(): string {\n    return '';\n  }\n\n  protected get color(): (text: string) => string {\n    return (text: string) => text;\n  }\n\n  protected formatMessage(...data: any[]): string {\n    const message = data.join(' ');\n    return this.prefix ? `${this.color(this.prefix)} ${message}` : message;\n  }\n\n  assert(condition?: boolean, ...data: any[]): void {\n    if (!condition) {\n      error(this.formatMessage('Assertion failed:', ...data));\n    }\n  }\n\n  // Needs some proper implementation\n  // Take a look at https://github.com/webpack/webpack/blob/5f898719ae47b89bee3c126bf5d2e0081ea8c91f/lib/node/nodeConsole.js#L4\n  // for some inspiration\n  // status(...data: any[]): void {\n  //   const message = this.formatMessage(...data);\n\n  //   // If we have a previous status line, we need to clear it\n  //   if (this.lastStatusLine !== null) {\n  //     this.clearStatus();\n  //   }\n\n  //   // Write the status message directly to stdout without adding newlines\n  //   process.stdout.write(message);\n\n  //   // Update tracking variables\n  //   this.lastStatusLine = message;\n  //   this.statusLineCount = 1; // For now, assume single line status messages\n\n  //   // If the message contains newlines, count them\n  //   const newlineCount = (message.match(/\\n/g) || []).length;\n  //   this.statusLineCount = newlineCount + 1;\n  // }\n\n  // /** Clears the current status line if one exists */\n  // clearStatus(): void {\n  //   if (this.lastStatusLine !== null) {\n  //     // Move cursor to the beginning of the current line\n  //     process.stdout.write('\\r');\n\n  //     // Clear the current line\n  //     process.stdout.clearLine(1);\n\n  //     // Reset tracking variables\n  //     this.lastStatusLine = null;\n  //     this.statusLineCount = 0;\n  //   }\n  // }\n\n  /**\n   * The **`console.clear()`** static method clears the console if possible.\n   *\n   * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/clear_static)\n   */\n  clear(): void {\n    // Clear the console by logging a clear sequence\n    console.clear();\n  }\n\n  /**\n   * The **`console.count()`** static method logs the number of times that this particular call to\n   * `count()` has been called.\n   *\n   * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/count_static)\n   */\n  count(label?: string): void {\n    const key = label || 'default';\n    const currentCount = (this.counters.get(key) || 0) + 1;\n    this.counters.set(key, currentCount);\n    log(this.formatMessage(`${key}: ${currentCount}`));\n  }\n\n  /**\n   * The **`console.countReset()`** static method resets counter used with console/count_static.\n   *\n   * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/countReset_static)\n   */\n  countReset(label?: string): void {\n    const key = label || 'default';\n    this.counters.delete(key);\n  }\n\n  /**\n   * The **`console.debug()`** static method outputs a message to the console at the 'debug' log\n   * level.\n   *\n   * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/debug_static)\n   */\n  debug(...data: any[]): void {\n    process.stdout.write('\\n'); // Add newline after clearing status\n    debug(this.formatMessage(...data));\n  }\n\n  /**\n   * The **`console.dir()`** static method displays a list of the properties of the specified\n   * JavaScript object.\n   *\n   * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/dir_static)\n   */\n  dir(item?: any, options?: any): void {\n    // TODO: Implement this with our own logger\n    console.dir(item, options);\n  }\n\n  /**\n   * The **`console.dirxml()`** static method displays an interactive tree of the descendant\n   * elements of the specified XML/HTML element.\n   *\n   * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/dirxml_static)\n   */\n  dirxml(...data: any[]): void {\n    // TODO: Implement this with our own logger\n    console.dirxml(...data);\n  }\n\n  /**\n   * The **`console.error()`** static method outputs a message to the console at the 'error' log\n   * level.\n   *\n   * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/error_static)\n   */\n  error(...data: any[]): void {\n    process.stdout.write('\\n'); // Add newline after clearing status\n    error(this.formatMessage(...data));\n  }\n\n  /**\n   * The **`console.group()`** static method creates a new inline group in the Web console log,\n   * causing any subsequent console messages to be indented by an additional level, until\n   * console/groupEnd_static is called.\n   *\n   * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/group_static)\n   */\n  group(...data: any[]): void {\n    // TODO: Implement this with our own logger\n    console.group(...data);\n  }\n\n  /**\n   * The **`console.groupCollapsed()`** static method creates a new inline group in the console.\n   *\n   * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/groupCollapsed_static)\n   */\n  groupCollapsed(...data: any[]): void {\n    // TODO: Implement this with our own logger\n    console.groupCollapsed(...data);\n  }\n\n  /**\n   * The **`console.groupEnd()`** static method exits the current inline group in the console.\n   *\n   * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/groupEnd_static)\n   */\n  groupEnd(): void {\n    // TODO: Implement this with our own logger\n    console.groupEnd();\n  }\n\n  /**\n   * The **`console.info()`** static method outputs a message to the console at the 'info' log\n   * level.\n   *\n   * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/info_static)\n   */\n  info(...data: any[]): void {\n    process.stdout.write('\\n'); // Add newline after clearing status\n    // \"info\" logger shouldn't be used in the console logger, because info should be reserved for important messages\n    log(this.formatMessage(...data));\n  }\n\n  /**\n   * The **`console.log()`** static method outputs a message to the console.\n   *\n   * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)\n   */\n  log(...data: any[]): void {\n    process.stdout.write('\\n'); // Add newline after clearing status\n    log(this.formatMessage(...data));\n  }\n\n  /**\n   * The **`console.table()`** static method displays tabular data as a table.\n   *\n   * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/table_static)\n   */\n  table(tabularData?: any, properties?: string[]): void {\n    // TODO: Implement this with our own logger\n    console.table(tabularData, properties);\n  }\n\n  /**\n   * The **`console.time()`** static method starts a timer you can use to track how long an\n   * operation takes.\n   *\n   * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/time_static)\n   */\n  time(label?: string): void {\n    const key = label || 'default';\n    // TODO: Implement this with our own logger\n    this.timers.set(key, Date.now());\n  }\n\n  /**\n   * The **`console.timeEnd()`** static method stops a timer that was previously started by calling\n   * console/time_static.\n   *\n   * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/timeEnd_static)\n   */\n  timeEnd(label?: string): void {\n    const key = label || 'default';\n    const startTime = this.timers.get(key);\n    if (startTime) {\n      const duration = Date.now() - startTime;\n      log(this.formatMessage(`${key}: ${duration}ms`));\n      this.timers.delete(key);\n    } else {\n      warn(this.formatMessage(`Timer '${key}' does not exist`));\n    }\n  }\n\n  /**\n   * The **`console.timeLog()`** static method logs the current value of a timer that was previously\n   * started by calling console/time_static.\n   *\n   * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/timeLog_static)\n   */\n  timeLog(label?: string, ...data: any[]): void {\n    const key = label || 'default';\n    const startTime = this.timers.get(key);\n    if (startTime) {\n      const duration = Date.now() - startTime;\n      log(this.formatMessage(`${key}: ${duration}ms`, ...data));\n    } else {\n      warn(this.formatMessage(`Timer '${key}' does not exist`));\n    }\n  }\n\n  timeStamp(label?: string): void {\n    const timestamp = new Date().toISOString();\n    log(this.formatMessage(`[${timestamp}]${label ? ` ${label}` : ''}`));\n  }\n\n  /**\n   * The **`console.trace()`** static method outputs a stack trace to the console.\n   *\n   * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/trace_static)\n   */\n  trace(...data: any[]): void {\n    // TODO: Implement this with our own logger\n    console.trace(...data);\n  }\n\n  /**\n   * The **`console.warn()`** static method outputs a warning message to the console at the\n   * 'warning' log level.\n   *\n   * [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/warn_static)\n   */\n  warn(...data: any[]): void {\n    process.stdout.write('\\n'); // Add newline after clearing status\n    warn(this.formatMessage(...data));\n  }\n\n  profile(label?: string): void {\n    // TODO: Implement this with our own logger\n    console.profile(label);\n    log(this.formatMessage(`Profile started: ${label}`));\n  }\n\n  profileEnd(label?: string): void {\n    // TODO: Implement this with our own logger\n    console.profileEnd(label);\n    log(this.formatMessage(`Profile ended: ${label}`));\n  }\n}\n\n// Extended ConsoleLogger with prefix and color functionality\nclass StyledConsoleLogger extends ConsoleLogger {\n  private _prefix: string;\n  private _color: ConsoleLoggerOptions['color'];\n\n  constructor(options: ConsoleLoggerOptions) {\n    super();\n    this._prefix = options.prefix || '';\n    this._color = options.color;\n  }\n\n  // Override the getter methods from parent class\n  protected get prefix(): string {\n    return this._prefix;\n  }\n\n  protected get color() {\n    return picocolors[this._color];\n  }\n}\n\nexport { ConsoleLogger, StyledConsoleLogger };\n"
  },
  {
    "path": "code/core/src/node-logger/logger/index.ts",
    "content": "export * from './logger.ts';\nexport * from './log-tracker.ts';\nexport * from './colors.ts';\nexport * from './console.ts';\n"
  },
  {
    "path": "code/core/src/node-logger/logger/log-tracker.ts",
    "content": "import { promises as fs } from 'node:fs';\nimport { join } from 'node:path';\n\nimport type { LogLevel } from './logger.ts';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Metadata = Record<string, any>;\nexport interface LogEntry {\n  timestamp: Date;\n  level: LogLevel | 'prompt';\n  message: string;\n  metadata?: Metadata;\n}\n\nconst DEBUG_LOG_FILE_NAME = 'debug-storybook.log';\nconst DEFAULT_LOG_FILE_PATH = join(process.cwd(), DEBUG_LOG_FILE_NAME);\n\n/**\n * Tracks and manages logs for Storybook CLI operations. Provides functionality to collect, store\n * and write logs to a file.\n */\nclass LogTracker {\n  /** Array to store log entries */\n  #logs: LogEntry[] = [];\n  /**\n   * Flag indicating if logs should be written to file it is enabled either by users providing the\n   * `--logfile` flag to a CLI command or when we explicitly enable it by calling\n   * `logTracker.enableLogWriting()` e.g. in automigrate or doctor command when there are issues\n   */\n  #shouldWriteLogsToFile = false;\n\n  /** Enables writing logs to file. */\n  enableLogWriting(): void {\n    this.#shouldWriteLogsToFile = true;\n  }\n\n  /** Returns whether logs should be written to file. */\n  get shouldWriteLogsToFile(): boolean {\n    return this.#shouldWriteLogsToFile;\n  }\n\n  /** Returns a copy of all stored logs. */\n  get logs(): LogEntry[] {\n    return [...this.#logs];\n  }\n\n  /**\n   * Adds a new log entry.\n   *\n   * @param level - The log level\n   * @param message - The log message\n   * @param metadata - Optional metadata to attach to the log, can be any JSON serializable value\n   */\n  addLog(level: LogEntry['level'], message: string, metadata?: Metadata) {\n    this.#logs.push({\n      timestamp: new Date(),\n      level,\n      message,\n      metadata,\n    });\n  }\n\n  /** Clears all stored logs. */\n  clear(): void {\n    this.#logs = [];\n  }\n\n  /**\n   * Writes all stored logs to a file and clears the log store.\n   *\n   * @param filePath - Optional custom file path to write logs to\n   * @returns The path where logs were written, by default is debug-storybook.log in current working\n   *   directory\n   */\n  async writeToFile(filePath: string | boolean | undefined): Promise<string> {\n    const logFilePath = typeof filePath === 'string' ? filePath : DEFAULT_LOG_FILE_PATH;\n\n    const logContent = this.#logs\n      .map((log) => {\n        const timestamp =\n          log.timestamp.toLocaleTimeString('en-US', { hour12: false }) +\n          `.${log.timestamp.getMilliseconds().toString().padStart(3, '0')}`;\n        const metadata = log.metadata ? ` ${JSON.stringify(log.metadata)}` : '';\n        return `[${timestamp}] [${log.level.toUpperCase()}] ${log.message}${metadata}`;\n      })\n      .join('\\n');\n\n    await fs.writeFile(logFilePath, logContent, 'utf-8');\n    this.#logs = [];\n\n    return logFilePath;\n  }\n}\n\nexport const logTracker = new LogTracker();\n"
  },
  {
    "path": "code/core/src/node-logger/logger/logger.ts",
    "content": "import * as clack from '@clack/prompts';\n\nimport { isClackEnabled } from '../prompts/prompt-config.ts';\nimport { getCurrentTaskLog } from '../prompts/prompt-provider-clack.ts';\nimport { wrapTextForClack } from '../wrap-utils.ts';\nimport { CLI_COLORS } from './colors.ts';\nimport { logTracker } from './log-tracker.ts';\n\nconst createLogFunction =\n  <T extends (...args: any[]) => any>(\n    clackFn: T,\n    consoleFn: (...args: Parameters<T>) => void,\n    cliColors?: (typeof CLI_COLORS)[keyof typeof CLI_COLORS]\n  ) =>\n  () =>\n    isClackEnabled()\n      ? (...args: Parameters<T>) => {\n          const [message, ...rest] = args;\n          const currentTaskLog = getCurrentTaskLog();\n          if (currentTaskLog) {\n            currentTaskLog.message(\n              cliColors && typeof message === 'string' ? cliColors(message) : message\n            );\n          } else {\n            // If first parameter is a string, wrap; otherwise pass as-is\n            if (typeof message === 'string') {\n              (clackFn as T)(wrapTextForClack(message), ...rest);\n            } else {\n              (clackFn as T)(message, ...rest);\n            }\n          }\n        }\n      : consoleFn;\n\nconst LOG_FUNCTIONS = {\n  log: createLogFunction(clack.log.message, console.log),\n  info: createLogFunction(clack.log.info, console.log),\n  warn: createLogFunction(clack.log.warn, console.warn, CLI_COLORS.warning),\n  error: createLogFunction(clack.log.error, console.error, CLI_COLORS.error),\n  intro: createLogFunction(clack.intro, console.log),\n  outro: createLogFunction(clack.outro, console.log),\n  step: createLogFunction(clack.log.step, console.log),\n};\n\n// Log level types and state\nexport type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent';\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n  trace: 1,\n  debug: 2,\n  info: 3,\n  warn: 4,\n  error: 5,\n  silent: 10,\n};\n\nlet currentLogLevel: LogLevel = 'info';\n\nexport const setLogLevel = (level: LogLevel): void => {\n  currentLogLevel = level;\n};\n\nexport const getLogLevel = (): LogLevel => {\n  return currentLogLevel;\n};\n\nexport const shouldLog = (level: LogLevel): boolean => {\n  return LOG_LEVELS[currentLogLevel] <= LOG_LEVELS[level];\n};\n\nfunction getMinimalTrace() {\n  // eslint-disable-next-line local-rules/no-uncategorized-errors\n  const stack = new Error().stack;\n\n  if (!stack) {\n    return;\n  }\n\n  // remove the first line (\"Error\")\n  const lines = stack.split('\\n').slice(1);\n\n  // Clean up stack: remove this own file utilities from the stack\n  const userStackLines = lines.filter(\n    (line) => !['getMinimalTrace', 'createLogger', 'logFunction'].some((fn) => line.includes(fn))\n  );\n\n  if (userStackLines.length === 0) {\n    return;\n  }\n\n  const callStack = '\\n' + userStackLines.slice(0, 4).join('\\n');\n\n  return callStack;\n}\n\nconst formatLogMessage = (args: any[]): string => {\n  return args\n    .map((arg) => {\n      if (typeof arg === 'string') {\n        return arg;\n      }\n\n      if (typeof arg === 'object') {\n        return JSON.stringify(arg, null, 2);\n      }\n      return String(arg);\n    })\n    .join(' ');\n};\n\n// Higher-level abstraction for creating logging functions\nfunction createLogger<T extends (...args: any[]) => void>(\n  level: LogLevel | 'prompt',\n  logFn: T,\n  prefix?: string\n) {\n  return function logFunction(...args: Parameters<T>) {\n    const [message, ...rest] = args;\n    const msg = formatLogMessage([message]);\n    logTracker.addLog(level, msg);\n\n    if (level === 'prompt') {\n      level = 'info';\n    }\n    if (shouldLog(level)) {\n      const formattedMessage = prefix ? `${prefix} ${msg}` : message;\n      logFn(formattedMessage, ...rest); // in practice, logFn typically expects a string\n    }\n  };\n}\n\n/**\n * For detailed information useful for debugging, which is hidden by default and only appears in log\n * files or when the log level is set to debug\n */\nexport const debug = createLogger(\n  'debug',\n  function logFunction(message) {\n    if (shouldLog('trace')) {\n      message += getMinimalTrace();\n    }\n    LOG_FUNCTIONS.log()(message);\n  },\n  '[DEBUG]'\n);\n\ntype LogFunctionArgs<T extends (...args: any[]) => any> = Parameters<ReturnType<T>>;\n\n/** For general information that should always be visible to the user */\nexport const log = createLogger('info', (...args: LogFunctionArgs<typeof LOG_FUNCTIONS.log>) =>\n  LOG_FUNCTIONS.log()(...args)\n);\n/** For general information that should catch the user's attention */\nexport const info = createLogger('info', (...args: LogFunctionArgs<typeof LOG_FUNCTIONS.info>) =>\n  LOG_FUNCTIONS.info()(...args)\n);\nexport const warn = createLogger('warn', (...args: LogFunctionArgs<typeof LOG_FUNCTIONS.warn>) =>\n  LOG_FUNCTIONS.warn()(...args)\n);\nexport const error = createLogger('error', (...args: LogFunctionArgs<typeof LOG_FUNCTIONS.error>) =>\n  LOG_FUNCTIONS.error()(...args)\n);\n\ntype BoxOptions = {\n  title?: string;\n} & clack.BoxOptions;\n\nexport const logBox = (message: string, { title, ...options }: BoxOptions = {}) => {\n  try {\n    if (shouldLog('info')) {\n      logTracker.addLog('info', message);\n      if (isClackEnabled()) {\n        clack.box(message, title, {\n          ...options,\n          width: options.width ?? 'auto',\n        });\n      } else {\n        console.log(message);\n      }\n    }\n  } catch {\n    /**\n     * Clack.logBox can throw with \"Invalid count value\"-errors\n     *\n     * Possibly it may only happen on CI, but considering rendering a box is not critical, we will\n     * just log the message to the console and discard the error.\n     */\n    clack.log.message(message);\n  }\n};\n\nexport const intro = (message: string) => {\n  logTracker.addLog('info', message);\n  if (shouldLog('info')) {\n    console.log('');\n    LOG_FUNCTIONS.intro()(message);\n  }\n};\n\nexport const outro = (message: string) => {\n  logTracker.addLog('info', message);\n  if (shouldLog('info')) {\n    LOG_FUNCTIONS.outro()(message);\n  }\n};\n\nexport const step = (message: string) => {\n  logTracker.addLog('info', message);\n  if (shouldLog('info')) {\n    LOG_FUNCTIONS.step()(message);\n  }\n};\n\nexport const SYMBOLS = {\n  success: CLI_COLORS.success('✔'),\n  error: CLI_COLORS.error('✕'),\n};\n\n// Export the text wrapping utility for external use\nexport { wrapTextForClack };\n"
  },
  {
    "path": "code/core/src/node-logger/prompts/index.ts",
    "content": "import { executeTask, executeTaskWithSpinner } from '../tasks.ts';\nimport * as promptConfig from './prompt-config.ts';\nimport * as promptFunctions from './prompt-functions.ts';\n\nexport const prompt = {\n  ...promptFunctions,\n  ...promptConfig,\n  executeTask,\n  executeTaskWithSpinner,\n};\n"
  },
  {
    "path": "code/core/src/node-logger/prompts/prompt-config.ts",
    "content": "import type { PromptProvider } from './prompt-provider-base.ts';\nimport { ClackPromptProvider } from './prompt-provider-clack.ts';\n\ntype PromptLibrary = 'clack';\n\nconst PROVIDERS = {\n  clack: new ClackPromptProvider(),\n} as const;\n\nlet currentPromptLibrary: PromptLibrary = 'clack';\n\nexport const setPromptLibrary = (library: PromptLibrary): void => {\n  currentPromptLibrary = library;\n};\n\nexport const getPromptLibrary = (): PromptLibrary => {\n  return currentPromptLibrary;\n};\n\nexport const getPromptProvider = (): PromptProvider => {\n  return PROVIDERS[currentPromptLibrary];\n};\n\nexport const isClackEnabled = (): boolean => {\n  return currentPromptLibrary === 'clack';\n};\n\n/**\n * Returns the preferred stdio for the current prompt library.\n *\n * Clack handles stdio output so that it clears it out later, and therefore 'pipe' is better. For\n * prompts, we want to inherit the stdio so that the output is displayed in the terminal.\n */\nexport const getPreferredStdio = (): 'inherit' | 'pipe' => {\n  return isClackEnabled() ? 'pipe' : 'inherit';\n};\n"
  },
  {
    "path": "code/core/src/node-logger/prompts/prompt-functions.ts",
    "content": "import { error, log, shouldLog } from '../logger/index.ts';\nimport { wrapTextForClack, wrapTextForClackHint } from '../wrap-utils.ts';\nimport { getPromptProvider } from './prompt-config.ts';\nimport type {\n  BasePromptOptions,\n  ConfirmPromptOptions,\n  MultiSelectPromptOptions,\n  Option,\n  PromptOptions,\n  SelectPromptOptions,\n  SpinnerInstance,\n  SpinnerOptions,\n  TaskLogInstance,\n  TaskLogOptions,\n  TextPromptOptions,\n} from './prompt-provider-base.ts';\n\n// Re-export types for convenience\nexport type {\n  Option,\n  BasePromptOptions,\n  TextPromptOptions,\n  ConfirmPromptOptions,\n  SelectPromptOptions,\n  MultiSelectPromptOptions,\n  PromptOptions,\n  SpinnerInstance,\n  TaskLogInstance,\n  TaskLogOptions,\n};\n\n// Global state for tracking active spinners and task logs\nlet activeSpinner: SpinnerInstance | null = null;\nlet activeTaskLog: TaskLogInstance | null = null;\nlet originalConsoleLog: typeof console.log | null = null;\n\nconst isInteractiveTerminal = () => {\n  return process.stdout.isTTY && process.stdin.isTTY && !process.env.CI;\n};\n\n// Console.log patching functions\nconst patchConsoleLog = () => {\n  if (!originalConsoleLog) {\n    originalConsoleLog = console.log;\n    console.log = (...args: any[]) => {\n      const message = args\n        .map((arg) => (typeof arg === 'string' ? arg : JSON.stringify(arg)))\n        .join(' ');\n\n      if (activeTaskLog) {\n        if (shouldLog('info')) {\n          activeTaskLog.message(message);\n        }\n      } else if (activeSpinner) {\n        if (shouldLog('info')) {\n          activeSpinner.message(message);\n        }\n      } else {\n        originalConsoleLog!(...args);\n      }\n    };\n  }\n};\n\nconst restoreConsoleLog = () => {\n  if (originalConsoleLog && !activeSpinner && !activeTaskLog) {\n    console.log = originalConsoleLog;\n    originalConsoleLog = null;\n  }\n};\n\nexport const text = async (\n  options: TextPromptOptions,\n  promptOptions?: PromptOptions\n): Promise<string> => {\n  return getPromptProvider().text(options, promptOptions);\n};\n\nexport const confirm = async (\n  options: ConfirmPromptOptions,\n  promptOptions?: PromptOptions\n): Promise<boolean> => {\n  return getPromptProvider().confirm(options, promptOptions);\n};\n\nexport const select = async <T>(\n  options: SelectPromptOptions<T>,\n  promptOptions?: PromptOptions\n): Promise<T> => {\n  return getPromptProvider().select(options, promptOptions);\n};\n\nexport const multiselect = async <T>(\n  options: MultiSelectPromptOptions<T>,\n  promptOptions?: PromptOptions\n): Promise<T[]> => {\n  return getPromptProvider().multiselect(\n    {\n      ...options,\n      options: options.options.map((opt) => ({\n        ...opt,\n        hint: opt.hint\n          ? wrapTextForClackHint(opt.hint, undefined, opt.label || String(opt.value), 0)\n          : undefined,\n      })),\n    },\n    promptOptions\n  );\n};\n\nexport const spinner = (options: SpinnerOptions): SpinnerInstance => {\n  if (isInteractiveTerminal()) {\n    const spinnerInstance = getPromptProvider().spinner(options);\n\n    // Wrap the spinner methods to handle console.log patching\n    const wrappedSpinner: SpinnerInstance = {\n      start: (message?: string) => {\n        activeSpinner = wrappedSpinner;\n        patchConsoleLog();\n        if (shouldLog('info')) {\n          spinnerInstance.start(message);\n        }\n      },\n      stop: (message?: string) => {\n        activeSpinner = null;\n        restoreConsoleLog();\n        if (shouldLog('info')) {\n          spinnerInstance.stop(message);\n        }\n      },\n      cancel: (message?: string) => {\n        activeSpinner = null;\n        restoreConsoleLog();\n        if (shouldLog('info')) {\n          spinnerInstance.cancel(message);\n        }\n      },\n      error: (message?: string) => {\n        activeSpinner = null;\n        restoreConsoleLog();\n        if (shouldLog('error')) {\n          spinnerInstance.error(message);\n        }\n      },\n      message: (text: string) => {\n        if (shouldLog('info')) {\n          spinnerInstance.message(text);\n        }\n      },\n    };\n\n    return wrappedSpinner;\n  } else {\n    const maybeLog = shouldLog('info') ? log : (_: string) => {};\n\n    return {\n      start: (message) => {\n        if (message) {\n          maybeLog(message);\n        }\n      },\n      stop: (message) => {\n        if (message) {\n          maybeLog(message);\n        }\n      },\n      cancel: (message) => {\n        if (message) {\n          maybeLog(message);\n        }\n      },\n      error: (message) => {\n        if (message) {\n          if (shouldLog('error')) {\n            error(message);\n          }\n        }\n      },\n      message: (message) => {\n        maybeLog(message);\n      },\n    };\n  }\n};\n\nexport const taskLog = (options: TaskLogOptions): TaskLogInstance => {\n  if (isInteractiveTerminal() && shouldLog('info')) {\n    const task = getPromptProvider().taskLog(options);\n\n    // Wrap the task log methods to handle console.log patching\n    const wrappedTaskLog: TaskLogInstance = {\n      message: (message: string) => {\n        task.message(wrapTextForClack(message));\n      },\n      success: (message: string, options?: { showLog?: boolean }) => {\n        activeTaskLog = null;\n        restoreConsoleLog();\n        task.success(message, options);\n      },\n      error: (message: string) => {\n        activeTaskLog = null;\n        restoreConsoleLog();\n        task.error(message);\n      },\n      group: function (title: string) {\n        this.message(`\\n${title}\\n`);\n        return {\n          message: (message: string) => {\n            task.message(wrapTextForClack(message));\n          },\n          success: (message: string) => {\n            task.success(message);\n          },\n          error: (message: string) => {\n            task.error(message);\n          },\n        };\n      },\n    };\n\n    // Activate console.log patching when task log is created\n    activeTaskLog = wrappedTaskLog;\n    patchConsoleLog();\n\n    return wrappedTaskLog;\n  } else {\n    const maybeLog = shouldLog('info') ? log : (_: string) => {};\n\n    return {\n      message: (message: string) => {\n        maybeLog(message);\n      },\n      success: (message: string) => {\n        maybeLog(message);\n      },\n      error: (message: string) => {\n        maybeLog(message);\n      },\n      group: (title: string) => {\n        maybeLog(`\\n${title}\\n`);\n        return {\n          message: (message: string) => {\n            maybeLog(message);\n          },\n          success: (message: string) => {\n            maybeLog(message);\n          },\n          error: (message: string) => {\n            maybeLog(message);\n          },\n        };\n      },\n    };\n  }\n};\n"
  },
  {
    "path": "code/core/src/node-logger/prompts/prompt-provider-base.ts",
    "content": "type Primitive = Readonly<string | boolean | number>;\n\nexport type Option<T> = T extends Primitive\n  ? {\n      value: T;\n      label?: string;\n      hint?: string;\n    }\n  : {\n      value: T;\n      label: string;\n      hint?: string;\n    };\n\nexport interface BasePromptOptions {\n  message: string;\n}\n\nexport interface TextPromptOptions extends BasePromptOptions {\n  placeholder?: string;\n  initialValue?: string;\n  validate?: (value: string | undefined) => string | Error | undefined;\n}\n\nexport interface ConfirmPromptOptions extends BasePromptOptions {\n  initialValue?: boolean;\n  active?: string;\n  inactive?: string;\n}\n\nexport interface SelectPromptOptions<T> extends BasePromptOptions {\n  options: Option<T>[];\n  initialValue?: T;\n}\n\nexport interface MultiSelectPromptOptions<T> extends BasePromptOptions {\n  options: Option<T>[];\n  initialValues?: T[];\n  required?: boolean;\n}\n\nexport interface PromptOptions {\n  onCancel?: () => void;\n}\n\nexport interface SpinnerInstance {\n  start: (message?: string) => void;\n  stop: (message?: string) => void;\n  cancel: (message?: string) => void;\n  error: (message?: string) => void;\n  message: (text: string) => void;\n}\n\nexport interface TaskLogInstance {\n  message: (text: string) => void;\n  success: (message: string, options?: { showLog?: boolean }) => void;\n  error: (message: string) => void;\n  group: (title: string) => {\n    message: (text: string, options?: any) => void;\n    success: (message: string) => void;\n    error: (message: string) => void;\n  };\n}\n\nexport interface SpinnerOptions {\n  /** The id of the task, to be used by the log tracker. */\n  id: string;\n}\n\nexport interface TaskLogOptions {\n  /** The id of the task, to be used by the log tracker. */\n  id: string;\n  title: string;\n  retainLog?: boolean;\n  limit?: number;\n}\n\nexport abstract class PromptProvider {\n  abstract text(options: TextPromptOptions, promptOptions?: PromptOptions): Promise<string>;\n\n  abstract confirm(options: ConfirmPromptOptions, promptOptions?: PromptOptions): Promise<boolean>;\n\n  abstract select<T>(options: SelectPromptOptions<T>, promptOptions?: PromptOptions): Promise<T>;\n\n  abstract multiselect<T>(\n    options: MultiSelectPromptOptions<T>,\n    promptOptions?: PromptOptions\n  ): Promise<T[]>;\n\n  abstract spinner(options: SpinnerOptions): SpinnerInstance;\n\n  abstract taskLog(options: TaskLogOptions): TaskLogInstance;\n}\n"
  },
  {
    "path": "code/core/src/node-logger/prompts/prompt-provider-clack.ts",
    "content": "import * as clack from '@clack/prompts';\n\nimport { logTracker } from '../logger/log-tracker.ts';\nimport { wrapTextForClackHint } from '../wrap-utils.ts';\nimport type {\n  ConfirmPromptOptions,\n  MultiSelectPromptOptions,\n  PromptOptions,\n  SelectPromptOptions,\n  SpinnerInstance,\n  SpinnerOptions,\n  TaskLogInstance,\n  TaskLogOptions,\n  TextPromptOptions,\n} from './prompt-provider-base.ts';\nimport { PromptProvider } from './prompt-provider-base.ts';\n\nexport const getCurrentTaskLog = (): ReturnType<typeof clack.taskLog> | null => {\n  if (globalThis.STORYBOOK_CURRENT_TASK_LOG) {\n    return globalThis.STORYBOOK_CURRENT_TASK_LOG[globalThis.STORYBOOK_CURRENT_TASK_LOG.length - 1];\n  } else {\n    return null;\n  }\n};\n\nconst setCurrentTaskLog = (taskLog: any) => {\n  globalThis.STORYBOOK_CURRENT_TASK_LOG = [\n    ...(globalThis.STORYBOOK_CURRENT_TASK_LOG || []),\n    taskLog,\n  ];\n};\n\nconst clearCurrentTaskLog = () => {\n  if (globalThis.STORYBOOK_CURRENT_TASK_LOG) {\n    globalThis.STORYBOOK_CURRENT_TASK_LOG.pop();\n  }\n};\n\nexport class ClackPromptProvider extends PromptProvider {\n  private handleCancel(result: unknown | symbol, promptOptions?: PromptOptions) {\n    if (clack.isCancel(result)) {\n      if (promptOptions?.onCancel) {\n        promptOptions.onCancel();\n      } else {\n        clack.cancel('Operation canceled.');\n        process.exit(0);\n      }\n    }\n  }\n\n  async text(options: TextPromptOptions, promptOptions?: PromptOptions): Promise<string> {\n    const result = await clack.text(options);\n    this.handleCancel(result, promptOptions);\n    logTracker.addLog('prompt', options.message, { choice: result });\n    return result.toString();\n  }\n\n  async confirm(options: ConfirmPromptOptions, promptOptions?: PromptOptions): Promise<boolean> {\n    const result = await clack.confirm({\n      ...options,\n      message: wrapTextForClackHint(options.message, undefined, undefined, 2),\n    });\n    this.handleCancel(result, promptOptions);\n    logTracker.addLog('prompt', options.message, { choice: result });\n    return Boolean(result);\n  }\n\n  async select<T>(options: SelectPromptOptions<T>, promptOptions?: PromptOptions): Promise<T> {\n    const result = await clack.select<T>({\n      ...options,\n      message: wrapTextForClackHint(options.message, undefined, undefined, 2),\n    });\n    this.handleCancel(result, promptOptions);\n    logTracker.addLog('prompt', options.message, { choice: result });\n    return result as T;\n  }\n\n  async multiselect<T>(\n    options: MultiSelectPromptOptions<T>,\n    promptOptions?: PromptOptions\n  ): Promise<T[]> {\n    const result = await clack.multiselect<T>({\n      ...options,\n      required: options.required,\n    });\n    this.handleCancel(result, promptOptions);\n    logTracker.addLog('prompt', options.message, { choice: result });\n    return result as T[];\n  }\n\n  spinner(options: SpinnerOptions): SpinnerInstance {\n    const task = clack.spinner();\n    const spinnerId = `${options.id}-spinner`;\n\n    return {\n      start: (message) => {\n        logTracker.addLog('info', `${spinnerId}-start: ${message}`);\n        task.start(message);\n      },\n      message: (message) => {\n        logTracker.addLog('info', `${spinnerId}: ${message}`);\n        task.message(message);\n      },\n      stop: (message) => {\n        logTracker.addLog('info', `${spinnerId}-stop: ${message}`);\n        task.stop(message);\n      },\n      cancel: (message) => {\n        logTracker.addLog('info', `${spinnerId}-cancel: ${message}`);\n        task.cancel(message);\n      },\n      error: (message) => {\n        logTracker.addLog('error', `${spinnerId}-error: ${message}`);\n        task.error(message);\n      },\n    };\n  }\n\n  taskLog(options: TaskLogOptions): TaskLogInstance {\n    const isCurrentTaskActive = !!getCurrentTaskLog();\n    const task = getCurrentTaskLog() || clack.taskLog(options);\n    const taskId = `${options.id}-task`;\n    logTracker.addLog('info', `${taskId}-start: ${options.title}`);\n\n    if (!isCurrentTaskActive) {\n      setCurrentTaskLog(task);\n    }\n\n    return {\n      message: (message) => {\n        logTracker.addLog('info', `${taskId}: ${message}`);\n        task.message(message);\n      },\n      error: (message) => {\n        logTracker.addLog('error', `${taskId}-error: ${message}`);\n        task.error(message, { showLog: true });\n        clearCurrentTaskLog();\n      },\n      success: (message, options) => {\n        logTracker.addLog('info', `${taskId}-success: ${message}`);\n        if (!isCurrentTaskActive) {\n          task.success(message, options);\n        }\n        clearCurrentTaskLog();\n      },\n      group(title) {\n        logTracker.addLog('info', `${taskId}-group: ${title}`);\n        const group = task.group(title);\n\n        setCurrentTaskLog(group);\n\n        return {\n          message: (message) => {\n            group.message(message);\n          },\n          success: (message) => {\n            group.success(message);\n            clearCurrentTaskLog();\n          },\n          error: (message) => {\n            group.error(message);\n            clearCurrentTaskLog();\n          },\n        };\n      },\n    };\n  }\n}\n"
  },
  {
    "path": "code/core/src/node-logger/prompts/storage.ts",
    "content": "import { AsyncLocalStorage } from 'node:async_hooks';\n\nconst asyncLocalStorage = new AsyncLocalStorage();\n\nexport { asyncLocalStorage };\n"
  },
  {
    "path": "code/core/src/node-logger/tasks.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport type { ResultPromise } from 'execa';\n\nimport { executeTaskWithSpinner } from './tasks.ts';\n\n// Create a minimal fake ResultPromise\nconst makeChild = (onStart?: (cp: Partial<ResultPromise>) => void): ResultPromise => {\n  const listeners: Record<string, Function[]> = {};\n  const stdout = {\n    on: vi.fn((event: string, cb: (data: Buffer) => void) => {\n      listeners[event] ||= [];\n      listeners[event].push(cb);\n    }),\n  } as any;\n\n  const cp: Partial<ResultPromise> = {\n    stdout: stdout as any,\n    then: undefined as any,\n    catch: undefined as any,\n    finally: undefined as any,\n  };\n\n  const promise = Promise.resolve() as any;\n  Object.setPrototypeOf(cp, promise);\n  (cp as any).then = promise.then.bind(promise);\n  (cp as any).catch = promise.catch.bind(promise);\n  (cp as any).finally = promise.finally.bind(promise);\n\n  onStart?.(cp);\n  return cp as ResultPromise;\n};\n\ndescribe('executeTaskWithSpinner', () => {\n  it('returns \"aborted\" when the child process rejects with an abort error', async () => {\n    const outcome = await executeTaskWithSpinner(() => makeChild(), {\n      id: 'test',\n      intro: 'Intro',\n      error: 'Error',\n      success: 'Success',\n      abortable: true,\n    });\n\n    // Non-abort path returns undefined\n    expect(outcome).toBeUndefined();\n\n    // Simulate an aborted child process by rejecting with an abort-like error message\n    const outcome2 = await executeTaskWithSpinner(\n      () => {\n        const err = new Error('The operation was aborted');\n        const p = Promise.reject(err);\n        // Avoid unhandled rejection warnings\n        p.catch(() => {});\n        const cp: any = makeChild();\n        // Make the thenable reject\n        const rejected = p as any;\n        Object.setPrototypeOf(cp, rejected);\n        cp.then = rejected.then.bind(rejected);\n        cp.catch = rejected.catch.bind(rejected);\n        cp.finally = rejected.finally.bind(rejected);\n        return cp;\n      },\n      {\n        id: 'test2',\n        intro: 'Intro',\n        error: 'Error',\n        success: 'Success',\n        abortable: true,\n      }\n    );\n\n    expect(outcome2).toBe('aborted');\n  });\n});\n"
  },
  {
    "path": "code/core/src/node-logger/tasks.ts",
    "content": "// eslint-disable-next-line depend/ban-dependencies\nimport type { ResultPromise } from 'execa';\n\nimport { CLI_COLORS, log } from './logger/index.ts';\nimport { logTracker } from './logger/log-tracker.ts';\nimport { spinner } from './prompts/prompt-functions.ts';\n\ntype ChildProcessFactory = (signal?: AbortSignal) => ResultPromise;\n\ninterface SetupAbortControllerResult {\n  abortController: AbortController;\n  cleanup: () => void;\n}\n\nfunction setupAbortController(): SetupAbortControllerResult {\n  const abortController = new AbortController();\n  let isRawMode = false;\n  const wasRawMode = process.stdin.isRaw;\n\n  const onKeyPress = (chunk: Buffer) => {\n    const key = chunk.toString();\n    if (key === 'c' || key === 'C') {\n      abortController.abort();\n    }\n  };\n\n  const cleanup = () => {\n    if (isRawMode) {\n      process.stdin.setRawMode(wasRawMode ?? false);\n      process.stdin.removeListener('data', onKeyPress);\n      if (!wasRawMode) {\n        process.stdin.pause();\n      }\n    }\n  };\n\n  // Set up stdin in raw mode to capture single keypresses\n  if (process.stdin.isTTY) {\n    try {\n      isRawMode = true;\n      process.stdin.setRawMode(true);\n      process.stdin.resume();\n      process.stdin.on('data', onKeyPress);\n    } catch {\n      isRawMode = false;\n    }\n  }\n\n  return { abortController, cleanup };\n}\n\n/**\n * Given a function that returns a child process or array of functions that return child processes,\n * this function will execute them sequentially and display the output in a task log.\n */\nexport const executeTask = async (\n  childProcessFactories: ChildProcessFactory | ChildProcessFactory[],\n  {\n    intro,\n    error,\n    success,\n    abortable = false,\n  }: { intro: string; error: string; success: string; abortable?: boolean }\n): Promise<'aborted' | void> => {\n  logTracker.addLog('info', intro);\n  log(intro);\n\n  let abortController: AbortController | undefined;\n  let cleanup: (() => void) | undefined;\n\n  if (abortable) {\n    const result = setupAbortController();\n    abortController = result.abortController;\n    cleanup = result.cleanup;\n  }\n\n  const factories = Array.isArray(childProcessFactories)\n    ? childProcessFactories\n    : [childProcessFactories];\n\n  try {\n    for (const factory of factories) {\n      const childProcess = factory(abortController?.signal);\n      childProcess.stdout?.on('data', (data: Buffer) => {\n        const message = data.toString().trim();\n        logTracker.addLog('info', message);\n        log(message);\n      });\n      await childProcess;\n    }\n    logTracker.addLog('info', success);\n    log(CLI_COLORS.success(success));\n  } catch (err: any) {\n    const isAborted =\n      abortController?.signal.aborted ||\n      err.message?.includes('Command was killed with SIGINT') ||\n      err.message?.includes('The operation was aborted');\n\n    if (isAborted) {\n      logTracker.addLog('info', `${intro} aborted`);\n      log(CLI_COLORS.error(`${intro} aborted`));\n      return 'aborted';\n    }\n    const errorMessage = err instanceof Error ? (err.stack ?? err.message) : String(err);\n    logTracker.addLog('error', error, { error: errorMessage });\n    log(CLI_COLORS.error(String((err as any).message ?? err)));\n    throw err;\n  } finally {\n    cleanup?.();\n  }\n  return undefined;\n};\n\nexport const executeTaskWithSpinner = async (\n  childProcessFactories: ChildProcessFactory | ChildProcessFactory[],\n  {\n    id,\n    intro,\n    error,\n    success,\n    abortable = false,\n  }: { id: string; intro: string; error: string; success: string; abortable?: boolean }\n): Promise<'aborted' | void> => {\n  logTracker.addLog('info', intro);\n\n  let abortController: AbortController | undefined;\n  let cleanup: (() => void) | undefined;\n\n  if (abortable) {\n    const result = setupAbortController();\n    abortController = result.abortController;\n    cleanup = result.cleanup;\n  }\n\n  const task = spinner({ id });\n  task.start(intro);\n\n  const factories = Array.isArray(childProcessFactories)\n    ? childProcessFactories\n    : [childProcessFactories];\n\n  try {\n    for (const factory of factories) {\n      const childProcess = factory(abortController?.signal);\n      childProcess.stdout?.on('data', (data: Buffer) => {\n        const message = data.toString().trim().slice(0, 25);\n        logTracker.addLog('info', `${intro}: ${data.toString()}`);\n        task.message(`${intro}: ${message}`);\n      });\n      await childProcess;\n    }\n    logTracker.addLog('info', success);\n    task.stop(success);\n  } catch (err: any) {\n    const isAborted =\n      abortController?.signal.aborted ||\n      err.message?.includes('Command was killed with SIGINT') ||\n      err.message?.includes('The operation was aborted');\n\n    if (isAborted) {\n      logTracker.addLog('info', `${intro} aborted`);\n      task.cancel(CLI_COLORS.warning(`${intro} aborted`));\n      return 'aborted';\n    }\n    const errorMessage = err instanceof Error ? (err.stack ?? err.message) : String(err);\n    logTracker.addLog('error', error, { error: errorMessage });\n    task.error(CLI_COLORS.error(error));\n    throw err;\n  } finally {\n    cleanup?.();\n  }\n  return undefined;\n};\n"
  },
  {
    "path": "code/core/src/node-logger/wrap-utils.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport { execaSync } from 'execa';\n\nimport {\n  getTerminalWidth,\n  protectUrls,\n  wrapTextForClack,\n  wrapTextForClackHint,\n} from './wrap-utils.ts';\n\n// Mock dependencies at the top with spy: true option\nvi.mock('@clack/prompts', () => ({\n  S_BAR: '│',\n}));\n\nvi.mock('picocolors', () => ({\n  cyan: vi.fn((text) => `cyan(${text})`),\n  dim: vi.fn((text) => `dim(${text})`),\n  reset: vi.fn((text) => `reset(${text})`),\n}));\n\nvi.mock('execa', () => ({\n  execaSync: vi.fn(),\n}));\n\n// Helper function to strip ANSI codes for length calculation\nfunction stripAnsi(str: string): string {\n  return str.replace(/\\u001b\\[[0-9;]*m/g, '');\n}\n\n// Helper function to get visible length\nfunction getVisibleLength(str: string): number {\n  return stripAnsi(str).length;\n}\n\ndescribe('wrap-utils', () => {\n  beforeEach(() => {\n    // Mock process.stdout.columns\n    Object.defineProperty(process.stdout, 'columns', {\n      value: 80,\n      configurable: true,\n    });\n\n    // Clear all mocks\n    vi.clearAllMocks();\n  });\n\n  describe('getTerminalWidth', () => {\n    it('should return process.stdout.columns when available', () => {\n      Object.defineProperty(process.stdout, 'columns', {\n        value: 120,\n        configurable: true,\n      });\n\n      expect(getTerminalWidth()).toBe(120);\n    });\n\n    it('should return default width (80) when process.stdout.columns is undefined', () => {\n      Object.defineProperty(process.stdout, 'columns', {\n        value: undefined,\n        configurable: true,\n      });\n\n      expect(getTerminalWidth()).toBe(80);\n    });\n\n    it('should return default width (80) when accessing columns throws an error', () => {\n      Object.defineProperty(process.stdout, 'columns', {\n        get: () => {\n          throw new Error('Test error');\n        },\n        configurable: true,\n      });\n\n      expect(getTerminalWidth()).toBe(80);\n    });\n  });\n\n  describe('wrapTextForClack', () => {\n    beforeEach(() => {\n      // Note: execaSync mock is not actually used by the implementation\n      // which reads process.env directly, but kept for compatibility\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      vi.mocked(execaSync).mockImplementation((_cmd: string | URL, args: any) => {\n        if (args && args[0] === '$TERM_PROGRAM') {\n          return {\n            stdout: 'iTerm.app',\n          } as any;\n        }\n        if (args && args[0] === '$TERM_PROGRAM_VERSION') {\n          return {\n            stdout: '3.4.0',\n          } as any;\n        }\n        return {\n          stdout: '',\n        } as any;\n      });\n    });\n\n    it('should wrap text to fit within content width and respect line length constraints', () => {\n      const text =\n        'This is a very long line of text that should be wrapped to fit within the specified width and not exceed the limit';\n      const terminalWidth = 50;\n      const expectedContentWidth = terminalWidth - 8; // 42 characters\n      const result = wrapTextForClack(text, terminalWidth);\n\n      const lines = result.split('\\n');\n\n      // Should have multiple lines\n      expect(lines.length).toBeGreaterThan(1);\n\n      // Each line should not exceed the content width\n      lines.forEach((line) => {\n        const visibleLength = getVisibleLength(line);\n        expect(visibleLength).toBeLessThanOrEqual(expectedContentWidth);\n        expect(visibleLength).toBeGreaterThan(0); // No empty lines\n      });\n\n      // All original text should be preserved\n      const unwrappedResult = lines.join(' ').replace(/\\s+/g, ' ').trim();\n      const originalWords = text.split(/\\s+/);\n      originalWords.forEach((word) => {\n        expect(unwrappedResult).toContain(word);\n      });\n    });\n\n    it('should handle text shorter than width without modification', () => {\n      const text = 'Short text';\n      const result = wrapTextForClack(text, 80);\n\n      expect(result).toBe(text);\n      expect(result).not.toContain('\\n');\n    });\n\n    it('should preserve ANSI codes and maintain color across line breaks', () => {\n      const text =\n        '\\u001b[31mThis is red text that is long enough to wrap\\u001b[0m and this is normal text';\n      const result = wrapTextForClack(text, 30);\n\n      // Should contain the ANSI codes\n      expect(result).toMatch(/\\u001b\\[31m/); // Red color code\n      expect(result).toMatch(/\\u001b\\[0m/); // Reset code\n\n      // Text content should be preserved\n      expect(stripAnsi(result)).toContain('This is red text');\n      expect(stripAnsi(result)).toContain('normal text');\n\n      // Should wrap into multiple lines\n      expect(result.split('\\n').length).toBeGreaterThan(1);\n    });\n\n    it('should handle empty text gracefully', () => {\n      const result = wrapTextForClack('');\n      expect(result).toBe('');\n    });\n\n    it('should preserve explicit newlines in original text', () => {\n      const text = 'Line 1\\nLine 2\\nLine 3';\n      const result = wrapTextForClack(text, 80);\n\n      const lines = result.split('\\n');\n      expect(lines).toHaveLength(3);\n      expect(lines[0]).toContain('Line 1');\n      expect(lines[1]).toContain('Line 2');\n      expect(lines[2]).toContain('Line 3');\n    });\n  });\n\n  describe('wrapTextForClackHint', () => {\n    it('should wrap hint text with proper continuation line indentation', () => {\n      const text =\n        'This is a very long hint text that should be wrapped with proper indentation for continuation lines';\n      const result = wrapTextForClackHint(text, 60, 'Label');\n\n      if (result.includes('\\n')) {\n        const lines = result.split('\\n');\n        expect(lines.length).toBeGreaterThan(1);\n\n        // First line should be the original text start\n        expect(lines[0]).toContain('This is a very');\n\n        // Continuation lines should have proper indentation structure\n        for (let i = 1; i < lines.length; i++) {\n          // Should contain the stroke character and proper spacing\n          expect(lines[i]).toMatch(/cyan\\(│\\)/);\n          expect(lines[i]).toMatch(/dim\\(/);\n\n          // Should have meaningful content after indentation\n          const contentAfterIndent = lines[i].replace(/^.*dim\\(/, '').replace(/\\)$/, '');\n          expect(contentAfterIndent.trim()).not.toBe('');\n        }\n      }\n    });\n\n    it('should not wrap short text and return it unchanged', () => {\n      const text = 'Short hint';\n      const result = wrapTextForClackHint(text, 80, 'Label');\n\n      expect(result).toBe(text);\n      expect(result).not.toContain('\\n');\n      expect(result).not.toContain('cyan(│)');\n    });\n\n    it('should calculate available width correctly based on label length', () => {\n      const text = 'This hint text should account for the long label when calculating wrap width';\n      const longLabel = 'Very long label name that takes up space';\n      const shortLabel = 'Short';\n\n      const resultWithLongLabel = wrapTextForClackHint(text, 60, longLabel);\n      const resultWithShortLabel = wrapTextForClackHint(text, 60, shortLabel);\n\n      // With longer label, should wrap earlier (more lines)\n      const longLabelLines = resultWithLongLabel.split('\\n').length;\n      const shortLabelLines = resultWithShortLabel.split('\\n').length;\n\n      if (longLabelLines > 1 || shortLabelLines > 1) {\n        expect(longLabelLines).toBeGreaterThanOrEqual(shortLabelLines);\n      }\n    });\n\n    it('should handle hint text without label parameter', () => {\n      const text =\n        'Hint without label that might be long enough to wrap depending on terminal width constraints';\n      const result = wrapTextForClackHint(text, 50);\n\n      // Should still work without label\n      expect(typeof result).toBe('string');\n      expect(stripAnsi(result)).toContain('Hint without label');\n\n      // If wrapped, should still have proper structure\n      if (result.includes('\\n')) {\n        const lines = result.split('\\n');\n        for (let i = 1; i < lines.length; i++) {\n          expect(lines[i]).toMatch(/cyan\\(│\\)/);\n        }\n      }\n    });\n\n    it('should maintain minimum content width of 30 characters', () => {\n      const text = 'Test hint text that should maintain minimum width';\n      const veryLongLabel = 'A'.repeat(50); // Very long label\n      const result = wrapTextForClackHint(text, 10, veryLongLabel); // Very small terminal width\n\n      // Should still produce reasonable output\n      expect(typeof result).toBe('string');\n      expect(result.length).toBeGreaterThan(0);\n      expect(stripAnsi(result)).toContain('Test hint text');\n    });\n\n    it('should handle empty hint text', () => {\n      const result = wrapTextForClackHint('', 80, 'Label');\n      expect(result).toBe('');\n    });\n\n    it('should preserve ANSI codes in hint text', () => {\n      const text = '\\u001b[33mYellow hint text\\u001b[0m with normal text that might wrap';\n      const result = wrapTextForClackHint(text, 40, 'Label');\n\n      // ANSI codes should be preserved\n      expect(result).toMatch(/\\u001b\\[33m/); // Yellow color\n      expect(result).toMatch(/\\u001b\\[0m/); // Reset\n    });\n  });\n\n  describe('edge cases and special characters', () => {\n    it('should keep symbols with following text when possible (no-break behavior)', () => {\n      const text =\n        '✔ Success message that should stay together with the checkmark when line width allows';\n      const result = wrapTextForClack(text, 40);\n\n      const lines = result.split('\\n');\n\n      // Find the line with the checkmark\n      const checkmarkLine = lines.find((line) => stripAnsi(line).includes('✔'));\n      expect(checkmarkLine).toBeDefined();\n\n      // The checkmark should be followed by \"Success\" on the same line if width allows\n      if (checkmarkLine && getVisibleLength(checkmarkLine) <= 32) {\n        // 40 - 8 = 32\n        expect(stripAnsi(checkmarkLine)).toMatch(/✔\\s+Success/);\n      }\n    });\n\n    it('should handle complex ANSI codes and symbols combination', () => {\n      const text =\n        '\\u001b[32m✔\\u001b[0m \\u001b[1mBold text\\u001b[0m with normal text and more content';\n      const result = wrapTextForClack(text, 50);\n\n      // Should preserve all ANSI codes\n      expect(result).toMatch(/\\u001b\\[32m/); // Green\n      expect(result).toMatch(/\\u001b\\[1m/); // Bold\n      expect(result).toMatch(/\\u001b\\[0m/); // Reset (multiple instances)\n\n      // Should preserve content\n      expect(stripAnsi(result)).toContain('✔');\n      expect(stripAnsi(result)).toContain('Bold text');\n      expect(stripAnsi(result)).toContain('normal text');\n\n      // Line length constraints should be respected\n      const lines = result.split('\\n');\n      lines.forEach((line) => {\n        expect(getVisibleLength(line)).toBeLessThanOrEqual(42); // 50 - 8\n      });\n    });\n\n    it('should handle multiple consecutive ANSI codes correctly', () => {\n      const text = '\\u001b[1m\\u001b[31m\\u001b[4mMultiple codes\\u001b[0m normal text continues here';\n      const result = wrapTextForClack(text, 50);\n\n      // All ANSI codes should be preserved\n      expect(result).toMatch(/\\u001b\\[1m/); // Bold\n      expect(result).toMatch(/\\u001b\\[31m/); // Red\n      expect(result).toMatch(/\\u001b\\[4m/); // Underline\n      expect(result).toMatch(/\\u001b\\[0m/); // Reset\n\n      // Content should be intact\n      expect(stripAnsi(result)).toContain('Multiple codes');\n      expect(stripAnsi(result)).toContain('normal text continues');\n    });\n\n    it('should properly handle reset codes and color state', () => {\n      const text = '\\u001b[31mRed\\u001b[0m normal \\u001b[32mGreen\\u001b[0m text continues';\n      const result = wrapTextForClack(text, 50);\n\n      // Color codes should be preserved\n      expect(result).toMatch(/\\u001b\\[31m/); // Red\n      expect(result).toMatch(/\\u001b\\[32m/); // Green\n\n      // Reset codes should be present\n      const resetMatches = result.match(/\\u001b\\[0m/g);\n      expect(resetMatches).not.toBeNull();\n      expect(resetMatches!.length).toBeGreaterThanOrEqual(2);\n\n      // Content order should be preserved\n      const cleanResult = stripAnsi(result);\n      expect(cleanResult.indexOf('Red')).toBeLessThan(cleanResult.indexOf('normal'));\n      expect(cleanResult.indexOf('normal')).toBeLessThan(cleanResult.indexOf('Green'));\n    });\n  });\n\n  describe('protectUrls', () => {\n    beforeEach(() => {\n      // Note: execaSync mock is not actually used by the implementation\n      // which reads process.env directly, but kept for compatibility\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      vi.mocked(execaSync).mockImplementation((_cmd: string | URL, args: any) => {\n        if (args && args[0] === '$TERM_PROGRAM') {\n          return {\n            stdout: 'iTerm.app',\n          } as any;\n        }\n        if (args && args[0] === '$TERM_PROGRAM_VERSION') {\n          return {\n            stdout: '3.4.0',\n          } as any;\n        }\n        return {\n          stdout: '',\n        } as any;\n      });\n    });\n\n    it('should return text unchanged when no URLs are present', () => {\n      const text = 'This is just plain text without any URLs';\n      const result = protectUrls(text);\n      expect(result).toBe(text);\n    });\n\n    it('should create hyperlinks for URLs when terminal supports hyperlinks', () => {\n      const text = 'Visit https://example.com for more info';\n      const result = protectUrls(text);\n\n      expect(result).toMatchInlineSnapshot(\n        `\"Visit \u001b]8;;https://example.com\u0007https://example.com\u001b]8;;\u0007 for more info\"`\n      );\n    });\n\n    it('should handle multiple URLs in the same text', () => {\n      const text = 'Check https://example.com and https://test.org for details';\n      const result = protectUrls(text);\n\n      expect(result).toMatchInlineSnapshot(\n        `\"Check \u001b]8;;https://example.com\u0007https://example.com\u001b]8;;\u0007 and \u001b]8;;https://test.org\u0007https://test.org\u001b]8;;\u0007 for details\"`\n      );\n    });\n\n    it('should truncate long URLs when they exceed maxUrlLength', () => {\n      const longUrl =\n        'https://example.com/very/long/path/that/exceeds/the/maximum/allowed/length/for/urls';\n      const text = `Visit ${longUrl} for details`;\n      const result = protectUrls(text, { maxUrlLength: 30 });\n\n      expect(result).toMatchInlineSnapshot(\n        `\"Visit \u001b]8;;https://example.com/very/long/path/that/exceeds/the/maximum/allowed/length/for/urls\u0007https://example.com/very/lo...\u001b]8;;\u0007 for details\"`\n      );\n    });\n\n    it('should respect maxLineWidth when calculating effective max length', () => {\n      const url = 'https://example.com/path/that/might/be/too/long/for/line';\n      const text = `Prefix text before ${url}`;\n      const result = protectUrls(text, { maxLineWidth: 50 });\n\n      // Should still apply hyperlink formatting\n      expect(result).toMatchInlineSnapshot(\n        `\"Prefix text before \u001b]8;;https://example.com/path/that/might/be/too/long/for/line\u0007https://example.com/path/tha...\u001b]8;;\u0007\"`\n      );\n    });\n\n    it('should not modify URLs already inside hyperlink escape sequences', () => {\n      const url = 'https://example.com';\n      const existingHyperlink = `\\u001b]8;;${url}\\u0007click here\\u001b]8;;\\u0007`;\n      const text = `Check out ${existingHyperlink} for info`;\n      const result = protectUrls(text);\n\n      // The function may still process URLs inside existing hyperlinks\n      // This test documents the current behavior rather than enforcing strict isolation\n      expect(result).toMatchInlineSnapshot(\n        `\"Check out \u001b]8;;https://example.com\u0007click here\u001b]8;;\u0007 for info\"`\n      );\n    });\n\n    it('should handle URLs with query parameters and fragments', () => {\n      const url = 'https://example.com/path?param=value&other=test#section';\n      const text = `Visit ${url} for details`;\n      const result = protectUrls(text);\n\n      expect(result).toMatchInlineSnapshot(\n        `\"Visit \u001b]8;;https://example.com/path?param=value&other=test#section\u0007https://example.com/path?param=value&other=test#section\u001b]8;;\u0007 for details\"`\n      );\n    });\n\n    it('should handle URLs at different positions in text', () => {\n      const url = 'https://example.com';\n\n      // URL at start\n      const startText = `${url} is a great site`;\n      const startResult = protectUrls(startText);\n      expect(startResult).toMatchInlineSnapshot(\n        `\"\u001b]8;;https://example.com\u0007https://example.com\u001b]8;;\u0007 is a great site\"`\n      );\n\n      // URL at end\n      const endText = `Visit the site at ${url}`;\n      const endResult = protectUrls(endText);\n      expect(endResult).toMatchInlineSnapshot(\n        `\"Visit the site at \u001b]8;;https://example.com\u0007https://example.com\u001b]8;;\u0007\"`\n      );\n\n      // URL in middle\n      const middleText = `Before ${url} after`;\n      const middleResult = protectUrls(middleText);\n      expect(middleResult).toMatchInlineSnapshot(\n        `\"Before \u001b]8;;https://example.com\u0007https://example.com\u001b]8;;\u0007 after\"`\n      );\n    });\n\n    it('should maintain minimum 20 character URL length when calculating available space', () => {\n      const url = 'https://example.com/short';\n      const longPrefix = 'A'.repeat(100); // Very long prefix\n      const text = `${longPrefix} ${url}`;\n      const result = protectUrls(text, { maxLineWidth: 50 });\n\n      // URL should still be hyperlinked even with long prefix\n      expect(result).toContain(`\\u001b]8;;${url}\\u0007${url}\\u001b]8;;\\u0007`);\n    });\n\n    it('should handle newlines correctly when calculating line position', () => {\n      const url = 'https://example.com';\n      const text = `First line\\nSecond line with ${url} here`;\n      const result = protectUrls(text);\n\n      expect(result).toMatchInlineSnapshot(`\n  \"First line\n  Second line with \u001b]8;;https://example.com\u0007https://example.com\u001b]8;;\u0007 here\"\n`);\n    });\n\n    it('should use terminal width as default when no options provided', () => {\n      Object.defineProperty(process.stdout, 'columns', {\n        value: 100,\n        configurable: true,\n      });\n\n      const url = 'https://example.com';\n      const text = `Visit ${url}`;\n      const result = protectUrls(text);\n\n      expect(result).toContain(`\\u001b]8;;${url}\\u0007${url}\\u001b]8;;\\u0007`);\n    });\n\n    it('should handle HTTP URLs in addition to HTTPS', () => {\n      const httpUrl = 'http://example.com';\n      const httpsUrl = 'https://secure.com';\n      const text = `Visit ${httpUrl} and ${httpsUrl}`;\n      const result = protectUrls(text);\n\n      expect(result).toMatchInlineSnapshot(\n        `\"Visit \u001b]8;;http://example.com\u0007http://example.com\u001b]8;;\u0007 and \u001b]8;;https://secure.com\u0007https://secure.com\u001b]8;;\u0007\"`\n      );\n    });\n\n    it('should not modify text when terminal does not support hyperlinks', () => {\n      // Mock process.env to return unsupported terminal\n      const originalEnv = process.env.TERM_PROGRAM;\n      const originalVersion = process.env.TERM_PROGRAM_VERSION;\n\n      process.env.TERM_PROGRAM = 'Apple_Terminal';\n      delete process.env.TERM_PROGRAM_VERSION;\n\n      const text = 'Visit https://example.com for info';\n      const result = protectUrls(text);\n\n      expect(result).toBe(text);\n      expect(result).not.toContain('\\u001b]8;;');\n\n      // Restore original env\n      if (originalEnv) {\n        process.env.TERM_PROGRAM = originalEnv;\n      } else {\n        delete process.env.TERM_PROGRAM;\n      }\n      if (originalVersion) {\n        process.env.TERM_PROGRAM_VERSION = originalVersion;\n      }\n    });\n\n    it('should handle complex URLs with ports and authentication', () => {\n      const url = 'https://user:pass@example.com:8080/path';\n      const text = `Connect to ${url}`;\n      const result = protectUrls(text);\n\n      expect(result).toContain(`\\u001b]8;;${url}\\u0007${url}\\u001b]8;;\\u0007`);\n    });\n\n    it('should correctly calculate visible length excluding ANSI codes', () => {\n      const url = 'https://example.com';\n      const coloredPrefix = '\\u001b[31mRed text\\u001b[0m';\n      const text = `${coloredPrefix} ${url}`;\n      const result = protectUrls(text, { maxLineWidth: 50 });\n\n      expect(result).toMatchInlineSnapshot(\n        `\"\u001b[31mRed text\u001b[0m \u001b]8;;https://example.com\u0007https://example.com\u001b]8;;\u0007\"`\n      );\n    });\n\n    it('should handle edge case with URL at exact line width limit', () => {\n      const url = 'https://example.com/test';\n      const prefix = 'A'.repeat(25); // Specific length to test edge case\n      const text = `${prefix} ${url}`;\n      const result = protectUrls(text, { maxLineWidth: 50 });\n\n      expect(result).toContain(`\\u001b]8;;${url}\\u0007`);\n    });\n\n    it('should truncate URLs correctly and preserve full URL in hyperlink target', () => {\n      const longUrl = 'https://example.com/very/very/very/long/path/that/needs/truncation';\n      const text = `Visit ${longUrl}`;\n      const result = protectUrls(text, { maxUrlLength: 30 });\n\n      // Should contain the full URL in the hyperlink target\n      expect(result).toMatchInlineSnapshot(\n        `\"Visit \u001b]8;;https://example.com/very/very/very/long/path/that/needs/truncation\u0007https://example.com/very/ve...\u001b]8;;\u0007\"`\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/node-logger/wrap-utils.ts",
    "content": "import { S_BAR } from '@clack/prompts';\nimport { cyan, dim, reset } from 'picocolors';\nimport wrapAnsi from 'wrap-ansi';\n\n// Text wrapping utility for Clack output\nfunction getTerminalWidth(): number {\n  // Default terminal width, fallback for when we can't determine it\n  const defaultWidth = 80;\n\n  try {\n    // Use process.stdout.columns if available, otherwise fallback\n    return process.stdout.columns || defaultWidth;\n  } catch {\n    return defaultWidth;\n  }\n}\n\n// ANSI regex pattern to match ANSI escape codes and OSC 8 hyperlink sequences\nconst ANSI_REGEX = /\\u001b\\[[0-9;]*m|\\u001b\\]8;;[^\\u0007]*\\u0007|\\u001b\\]8;;\\u0007/g;\n\n// URL regex pattern to match URLs\nconst URL_REGEX = /(https?:\\/\\/[^\\s\\u0000-\\u001F\\u007F]+)/g;\n\nfunction stripAnsi(str: string): string {\n  return str.replace(ANSI_REGEX, '');\n}\n\nfunction getVisibleLength(str: string): number {\n  return stripAnsi(str).length;\n}\n\nfunction getEnvFromTerminal(key: string): string {\n  return (process.env[key] || '').trim();\n}\n\n/**\n * Detects if the current terminal supports OSC 8 hyperlinks Based on terminal identification and\n * known capabilities\n */\nfunction supportsHyperlinks(): boolean {\n  try {\n    // Check terminal program\n    const termProgram = getEnvFromTerminal('TERM_PROGRAM');\n    const termProgramVersion = getEnvFromTerminal('TERM_PROGRAM_VERSION');\n\n    switch (termProgram) {\n      case 'iTerm.app':\n        // iTerm2 supports hyperlinks in version 3.1.0+\n        if (termProgramVersion.trim()) {\n          const version = termProgramVersion.trim().split('.').map(Number);\n          return version[0] > 3 || (version[0] === 3 && version[1] >= 1);\n        }\n        return true; // Assume recent version\n\n      case 'Apple_Terminal':\n        // macOS Terminal.app doesn't support hyperlinks\n        return false;\n\n      default:\n        // Most other modern terminals support hyperlinks\n        return true;\n    }\n  } catch {\n    // If we can't access environment variables, fall back to conservative default\n    return false;\n  }\n}\n\n/** Detects URLs in text and prevents them from being broken across lines */\nexport function protectUrls(\n  text: string,\n  options?: { maxUrlLength?: number; maxLineWidth?: number }\n): string {\n  // Use a sensible default based on terminal width if not provided\n  const defaultMaxUrlLength = Math.floor(getTerminalWidth() * 0.8);\n  const maxLineWidth = options?.maxLineWidth ?? getTerminalWidth();\n\n  // Determine if we should use hyperlinks\n  const useHyperlinks = supportsHyperlinks();\n\n  return text.replace(URL_REGEX, (match: string, capturedUrl: string, offset: number) => {\n    if (!useHyperlinks) {\n      return match;\n    }\n\n    // Check if this URL is inside an existing OSC 8 hyperlink sequence\n    // OSC 8 format: \\u001b]8;;target_url\\u0007display_text\\u001b]8;;\\u0007\n    // We need to avoid processing URLs that are part of existing hyperlinks\n\n    let searchPos = 0;\n    while (true) {\n      const hyperlinkStart = text.indexOf('\\u001b]8;;', searchPos);\n\n      if (hyperlinkStart === -1) {\n        break;\n      }\n\n      const hyperlinkEnd = text.indexOf('\\u001b]8;;\\u0007', hyperlinkStart);\n      if (hyperlinkEnd === -1) {\n        searchPos = hyperlinkStart + 1;\n        continue;\n      }\n\n      // Check if our URL falls anywhere within this hyperlink sequence\n      if (offset >= hyperlinkStart && offset < hyperlinkEnd + 7) {\n        // +7 for '\\u001b]8;;\\u0007'\n        // This URL is within an existing hyperlink sequence, don't modify it\n        return match;\n      }\n\n      searchPos = hyperlinkEnd + 1;\n    }\n\n    // Calculate how much space is available for this URL on its current line\n    const textBeforeUrl = text.substring(0, offset);\n    const lastNewlineIndex = textBeforeUrl.lastIndexOf('\\n');\n    const currentLinePrefix =\n      lastNewlineIndex === -1 ? textBeforeUrl : textBeforeUrl.substring(lastNewlineIndex + 1);\n\n    // Calculate available space on this line for the URL\n    const prefixLength = getVisibleLength(currentLinePrefix);\n    const availableSpace = maxLineWidth - prefixLength;\n    const minUrlLength = 20; // minimum URL length, don't truncate URLs shorter than this\n\n    // Use the smaller of: configured maxUrlLength, default maxUrlLength, or available space\n    // But never go below the minimum URL length\n    const configuredMax = options?.maxUrlLength ?? defaultMaxUrlLength;\n    let effectiveMaxLength = Math.min(configuredMax, defaultMaxUrlLength, availableSpace);\n\n    // If the URL is short enough (at or below minimum), don't truncate it\n    if (capturedUrl.length <= minUrlLength) {\n      effectiveMaxLength = capturedUrl.length;\n    } else if (effectiveMaxLength < minUrlLength) {\n      // If available space would result in very short truncation, don't truncate at all\n      effectiveMaxLength = capturedUrl.length;\n    }\n\n    if (capturedUrl.length > effectiveMaxLength) {\n      // Create a truncated version\n      const truncatedText = capturedUrl.substring(0, effectiveMaxLength - 3) + '...';\n\n      // Create a truncated hyperlink that still opens the full URL\n      return `\\u001b]8;;${capturedUrl}\\u0007${truncatedText}\\u001b]8;;\\u0007`;\n    }\n\n    // Apply hyperlink functionality\n    return `\\u001b]8;;${capturedUrl}\\u0007${capturedUrl}\\u001b]8;;\\u0007`;\n  });\n}\n\n/**\n * Creates a hyperlink with custom title text if supported, otherwise falls back to \"title: url\"\n * format\n */\nexport function createHyperlink(title: string, url: string): string {\n  if (supportsHyperlinks()) {\n    // Create hyperlink using OSC 8 escape sequence: title as display text, url as target\n    return `\\u001b]8;;${url}\\u0007${title}\\u001b]8;;\\u0007`;\n  }\n\n  // Fallback for terminals that don't support hyperlinks\n  return `${title}: ${url}`;\n}\n\n/** Enhanced word splitting that treats URLs as single units */\nfunction splitTextPreservingUrls(text: string): string[] {\n  const parts: string[] = [];\n  let lastIndex = 0;\n  let match;\n\n  // Reset regex\n  URL_REGEX.lastIndex = 0;\n\n  while ((match = URL_REGEX.exec(text)) !== null) {\n    // Add text before the URL\n    if (match.index > lastIndex) {\n      const beforeUrl = text.slice(lastIndex, match.index);\n      parts.push(...beforeUrl.split(' ').filter((part) => part.length > 0));\n    }\n\n    // Add the URL as a single unit\n    parts.push(match[0]);\n    lastIndex = match.index + match[0].length;\n  }\n\n  // Add remaining text after the last URL\n  if (lastIndex < text.length) {\n    const remaining = text.slice(lastIndex);\n    parts.push(...remaining.split(' ').filter((part) => part.length > 0));\n  }\n\n  return parts;\n}\n\nconst MAX_OPTIMAL_WIDTH = 80;\n\nfunction getOptimalWidth(width: number): number {\n  return Math.min(width, MAX_OPTIMAL_WIDTH);\n}\n\nexport function wrapTextForClack(text: string, width?: number): string {\n  const terminalWidth = width || getTerminalWidth();\n  // Reserve space for Clack's visual formatting (prefix, borders, etc.)\n  // Clack typically uses about 4-10 characters for its formatting\n  const contentWidth = Math.max(terminalWidth - 10, 40);\n  const maxOptimalWidth = getOptimalWidth(contentWidth);\n\n  const protectedText = protectUrls(text, { maxLineWidth: maxOptimalWidth });\n  return wrapAnsi(protectedText, maxOptimalWidth);\n}\n\n// Export additional utilities that might be useful\nexport { getTerminalWidth, supportsHyperlinks };\n\n/**\n * Specialized wrapper for hint text that adds stroke characters (│) to continuation lines to\n * maintain visual consistency with clack's multiselect prompts\n */\nexport function wrapTextForClackHint(\n  text: string,\n  width?: number,\n  label?: string,\n  // Total chars before hint text starts: \"│  \" + \"◼ \"\n  _indentSpaces = 3 + 1\n): string {\n  const terminalWidth = width || getTerminalWidth();\n\n  // Calculate the space taken by the label\n  const labelWidth = label ? getVisibleLength(label) : 0;\n\n  // Reserve space for Clack's visual formatting (prefix, borders, etc.)\n  // Additional space for the stroke character, padding, checkbox, and label\n  // Format: \"│  ◼ labelText (hint text...\"\n  const reservedSpaceFirstLine = 8 + labelWidth; // 8 chars for \"│  ◼ \" + \"(\" + some padding\n  const firstLineWidth = Math.min(\n    MAX_OPTIMAL_WIDTH - reservedSpaceFirstLine,\n    Math.max(terminalWidth - reservedSpaceFirstLine, 30)\n  );\n\n  // For continuation lines, we only need to account for the indentation\n  // Format: \"│    continuation text...\"\n  const indentSpaces = _indentSpaces;\n  const continuationLineWidth = getOptimalWidth(Math.max(terminalWidth - indentSpaces, 30));\n\n  // First, try wrapping with the continuation line width for optimal wrapping\n  // Apply URL protection to prevent URLs from being broken across lines\n  const protectedText = protectUrls(text, { maxLineWidth: continuationLineWidth });\n  const initialWrap = wrapAnsi(protectedText, continuationLineWidth);\n\n  const lines = initialWrap.split('\\n');\n\n  // Check if the first line exceeds the first line width\n  if (lines.length > 0 && getVisibleLength(lines[0]) > firstLineWidth) {\n    // Need to manually break the text at the first line boundary\n    // Find the best break point for the first line, treating URLs as single units\n    const words = splitTextPreservingUrls(text);\n    let firstLinePart = '';\n    let remainingPart = '';\n\n    for (let i = 0; i < words.length; i++) {\n      const testLine = i === 0 ? words[i] : firstLinePart + ' ' + words[i];\n\n      if (getVisibleLength(testLine) <= firstLineWidth) {\n        firstLinePart = testLine;\n      } else {\n        // This word would make the line too long, so break here\n        remainingPart = words.slice(i).join(' ');\n        break;\n      }\n    }\n\n    // If we couldn't fit any words, just use the first word\n    if (!firstLinePart && words.length > 0) {\n      firstLinePart = words[0];\n      remainingPart = words.slice(1).join(' ');\n    }\n\n    let finalLines = [firstLinePart];\n\n    // Wrap the remaining text with the wider continuation width\n    // Apply URL protection to prevent URLs from being broken\n    if (remainingPart.trim()) {\n      const protectedRemainder = protectUrls(remainingPart.trim(), {\n        maxLineWidth: continuationLineWidth,\n      });\n      const wrappedRemainder = wrapAnsi(protectedRemainder, continuationLineWidth);\n      finalLines = finalLines.concat(wrappedRemainder.split('\\n'));\n    }\n\n    if (finalLines.length <= 1) {\n      return finalLines[0] || '';\n    }\n\n    // Use reset + cyan to counteract clack's dimming effect on the vertical line\n    const indentation = indentSpaces > 0 ? reset(cyan(S_BAR)) + ' '.repeat(indentSpaces) : '';\n\n    // Add proper indentation to all lines except the first one\n    return finalLines\n      .map((line, index) => {\n        if (index === 0) {\n          return line;\n        }\n        // Add stroke character with proper indentation for continuation lines\n        return `${indentation}${dim(line)}`;\n      })\n      .join('\\n');\n  }\n\n  // First line fits, so use the optimal wrapping\n  if (lines.length <= 1) {\n    return initialWrap;\n  }\n\n  // Use reset + cyan to counteract clack's dimming effect on the vertical line\n  const indentation = reset(cyan(S_BAR)) + ' '.repeat(indentSpaces);\n\n  // Add proper indentation to all lines except the first one\n  return lines\n    .map((line, index) => {\n      if (index === 0) {\n        return line;\n      }\n      // Add stroke character with proper indentation for continuation lines\n      return `${indentation}${dim(line)}`;\n    })\n    .join('\\n');\n}\n"
  },
  {
    "path": "code/core/src/outline/OutlineSelector.tsx",
    "content": "import React, { memo, useCallback, useEffect } from 'react';\n\nimport { ToggleButton } from 'storybook/internal/components';\n\nimport { OutlineIcon } from '@storybook/icons';\n\nimport { useGlobals, useStorybookApi } from 'storybook/manager-api';\n\nimport { ADDON_ID, PARAM_KEY } from './constants.ts';\n\nexport const OutlineSelector = memo(function OutlineSelector() {\n  const [globals, updateGlobals] = useGlobals();\n  const api = useStorybookApi();\n\n  const isActive = [true, 'true'].includes(globals[PARAM_KEY]);\n\n  const toggleOutline = useCallback(\n    () =>\n      updateGlobals({\n        [PARAM_KEY]: !isActive,\n      }),\n    [isActive, updateGlobals]\n  );\n\n  useEffect(() => {\n    api.setAddonShortcut(ADDON_ID, {\n      label: 'Toggle Outline',\n      defaultShortcut: ['alt', 'O'],\n      actionName: 'outline',\n      showInMenu: false,\n      action: toggleOutline,\n    });\n  }, [toggleOutline, api]);\n\n  return (\n    <ToggleButton\n      key=\"outline\"\n      padding=\"small\"\n      variant=\"ghost\"\n      pressed={isActive}\n      ariaLabel=\"Outline tool\"\n      ariaDescription=\"When enabled, this tool displays the outline of every element in the preview area, which helps understand their layout.\"\n      tooltip=\"Toggle outline\"\n      onClick={toggleOutline}\n    >\n      <OutlineIcon />\n    </ToggleButton>\n  );\n});\n"
  },
  {
    "path": "code/core/src/outline/README.md",
    "content": "# Storybook Addon Outline\n\nStorybook Addon Outline can be used for visually debugging CSS layout and alignment inside the preview in [Storybook](https://storybook.js.org). Based on [Pesticide](https://github.com/mrmrs/pesticide), it draws outlines around every single element in the preview pane.\n\n![React Storybook Screenshot](https://user-images.githubusercontent.com/42671/98158421-dada2300-1ea8-11eb-8619-af1e7018e1ec.png)\n\n## Usage\n\nRequires Storybook 6.1 or later. Outline is part of [essentials](https://storybook.js.org/docs/essentials) and so is installed in all new Storybooks by default. If you need to add it to your Storybook, you can run:\n\n```sh\nnpm i -D @storybook/addon-outline\n```\n\nThen, add following content to [`.storybook/main.js`](https://storybook.js.org/docs/configure#configure-your-storybook-project):\n\n```js\nexport default {\n  addons: ['@storybook/addon-outline'],\n};\n```\n\nYou can now click on the outline button or press the <kbd>o</kbd> key in the toolbar to toggle the outlines.\n"
  },
  {
    "path": "code/core/src/outline/constants.ts",
    "content": "export const ADDON_ID = 'storybook/outline';\nexport const PARAM_KEY = 'outline';\n"
  },
  {
    "path": "code/core/src/outline/helpers.ts",
    "content": "import { global } from '@storybook/global';\n\nexport const clearStyles = (selector: string | string[]) => {\n  const selectors = Array.isArray(selector) ? selector : [selector];\n  selectors.forEach(clearStyle);\n};\n\nconst clearStyle = (input: string | string[]) => {\n  const selector = typeof input === 'string' ? input : input.join('');\n  const element = global.document.getElementById(selector);\n  if (element && element.parentElement) {\n    element.parentElement.removeChild(element);\n  }\n};\n\nexport const addOutlineStyles = (selector: string, css: string) => {\n  const existingStyle = global.document.getElementById(selector);\n  if (existingStyle) {\n    if (existingStyle.innerHTML !== css) {\n      existingStyle.innerHTML = css;\n    }\n  } else {\n    const style = global.document.createElement('style');\n    style.setAttribute('id', selector);\n    style.innerHTML = css;\n    global.document.head.appendChild(style);\n  }\n};\n"
  },
  {
    "path": "code/core/src/outline/manager.tsx",
    "content": "import React from 'react';\n\nimport { addons, types } from 'storybook/manager-api';\n\nimport { OutlineSelector } from './OutlineSelector.tsx';\nimport { ADDON_ID } from './constants.ts';\n\nexport default addons.register(ADDON_ID, () => {\n  if (globalThis?.FEATURES?.outline) {\n    addons.add(ADDON_ID, {\n      title: 'Outline',\n      type: types.TOOL,\n      match: ({ viewMode, tabId }) => !!(viewMode && viewMode.match(/^(story|docs)$/)) && !tabId,\n      render: () => <OutlineSelector />,\n    });\n  }\n});\n"
  },
  {
    "path": "code/core/src/outline/outlineCSS.ts",
    "content": "import { dedent } from 'ts-dedent';\n\n/*\n  From pesticide v1.3.0 . @mrmrs . MIT\n*/\nexport default function outlineCSS(selector: string) {\n  return dedent /* css */ `\n    ${selector} body {\n      outline: 1px solid #2980b9 !important;\n    }\n\n    ${selector} article {\n      outline: 1px solid #3498db !important;\n    }\n\n    ${selector} nav {\n      outline: 1px solid #0088c3 !important;\n    }\n\n    ${selector} aside {\n      outline: 1px solid #33a0ce !important;\n    }\n\n    ${selector} section {\n      outline: 1px solid #66b8da !important;\n    }\n\n    ${selector} header {\n      outline: 1px solid #99cfe7 !important;\n    }\n\n    ${selector} footer {\n      outline: 1px solid #cce7f3 !important;\n    }\n\n    ${selector} h1 {\n      outline: 1px solid #162544 !important;\n    }\n\n    ${selector} h2 {\n      outline: 1px solid #314e6e !important;\n    }\n\n    ${selector} h3 {\n      outline: 1px solid #3e5e85 !important;\n    }\n\n    ${selector} h4 {\n      outline: 1px solid #449baf !important;\n    }\n\n    ${selector} h5 {\n      outline: 1px solid #c7d1cb !important;\n    }\n\n    ${selector} h6 {\n      outline: 1px solid #4371d0 !important;\n    }\n\n    ${selector} main {\n      outline: 1px solid #2f4f90 !important;\n    }\n\n    ${selector} address {\n      outline: 1px solid #1a2c51 !important;\n    }\n\n    ${selector} div {\n      outline: 1px solid #036cdb !important;\n    }\n\n    ${selector} p {\n      outline: 1px solid #ac050b !important;\n    }\n\n    ${selector} hr {\n      outline: 1px solid #ff063f !important;\n    }\n\n    ${selector} pre {\n      outline: 1px solid #850440 !important;\n    }\n\n    ${selector} blockquote {\n      outline: 1px solid #f1b8e7 !important;\n    }\n\n    ${selector} ol {\n      outline: 1px solid #ff050c !important;\n    }\n\n    ${selector} ul {\n      outline: 1px solid #d90416 !important;\n    }\n\n    ${selector} li {\n      outline: 1px solid #d90416 !important;\n    }\n\n    ${selector} dl {\n      outline: 1px solid #fd3427 !important;\n    }\n\n    ${selector} dt {\n      outline: 1px solid #ff0043 !important;\n    }\n\n    ${selector} dd {\n      outline: 1px solid #e80174 !important;\n    }\n\n    ${selector} figure {\n      outline: 1px solid #ff00bb !important;\n    }\n\n    ${selector} figcaption {\n      outline: 1px solid #bf0032 !important;\n    }\n\n    ${selector} table {\n      outline: 1px solid #00cc99 !important;\n    }\n\n    ${selector} caption {\n      outline: 1px solid #37ffc4 !important;\n    }\n\n    ${selector} thead {\n      outline: 1px solid #98daca !important;\n    }\n\n    ${selector} tbody {\n      outline: 1px solid #64a7a0 !important;\n    }\n\n    ${selector} tfoot {\n      outline: 1px solid #22746b !important;\n    }\n\n    ${selector} tr {\n      outline: 1px solid #86c0b2 !important;\n    }\n\n    ${selector} th {\n      outline: 1px solid #a1e7d6 !important;\n    }\n\n    ${selector} td {\n      outline: 1px solid #3f5a54 !important;\n    }\n\n    ${selector} col {\n      outline: 1px solid #6c9a8f !important;\n    }\n\n    ${selector} colgroup {\n      outline: 1px solid #6c9a9d !important;\n    }\n\n    ${selector} button {\n      outline: 1px solid #da8301 !important;\n    }\n\n    ${selector} datalist {\n      outline: 1px solid #c06000 !important;\n    }\n\n    ${selector} fieldset {\n      outline: 1px solid #d95100 !important;\n    }\n\n    ${selector} form {\n      outline: 1px solid #d23600 !important;\n    }\n\n    ${selector} input {\n      outline: 1px solid #fca600 !important;\n    }\n\n    ${selector} keygen {\n      outline: 1px solid #b31e00 !important;\n    }\n\n    ${selector} label {\n      outline: 1px solid #ee8900 !important;\n    }\n\n    ${selector} legend {\n      outline: 1px solid #de6d00 !important;\n    }\n\n    ${selector} meter {\n      outline: 1px solid #e8630c !important;\n    }\n\n    ${selector} optgroup {\n      outline: 1px solid #b33600 !important;\n    }\n\n    ${selector} option {\n      outline: 1px solid #ff8a00 !important;\n    }\n\n    ${selector} output {\n      outline: 1px solid #ff9619 !important;\n    }\n\n    ${selector} progress {\n      outline: 1px solid #e57c00 !important;\n    }\n\n    ${selector} select {\n      outline: 1px solid #e26e0f !important;\n    }\n\n    ${selector} textarea {\n      outline: 1px solid #cc5400 !important;\n    }\n\n    ${selector} details {\n      outline: 1px solid #33848f !important;\n    }\n\n    ${selector} summary {\n      outline: 1px solid #60a1a6 !important;\n    }\n\n    ${selector} command {\n      outline: 1px solid #438da1 !important;\n    }\n\n    ${selector} menu {\n      outline: 1px solid #449da6 !important;\n    }\n\n    ${selector} del {\n      outline: 1px solid #bf0000 !important;\n    }\n\n    ${selector} ins {\n      outline: 1px solid #400000 !important;\n    }\n\n    ${selector} img {\n      outline: 1px solid #22746b !important;\n    }\n\n    ${selector} iframe {\n      outline: 1px solid #64a7a0 !important;\n    }\n\n    ${selector} embed {\n      outline: 1px solid #98daca !important;\n    }\n\n    ${selector} object {\n      outline: 1px solid #00cc99 !important;\n    }\n\n    ${selector} param {\n      outline: 1px solid #37ffc4 !important;\n    }\n\n    ${selector} video {\n      outline: 1px solid #6ee866 !important;\n    }\n\n    ${selector} audio {\n      outline: 1px solid #027353 !important;\n    }\n\n    ${selector} source {\n      outline: 1px solid #012426 !important;\n    }\n\n    ${selector} canvas {\n      outline: 1px solid #a2f570 !important;\n    }\n\n    ${selector} track {\n      outline: 1px solid #59a600 !important;\n    }\n\n    ${selector} map {\n      outline: 1px solid #7be500 !important;\n    }\n\n    ${selector} area {\n      outline: 1px solid #305900 !important;\n    }\n\n    ${selector} a {\n      outline: 1px solid #ff62ab !important;\n    }\n\n    ${selector} em {\n      outline: 1px solid #800b41 !important;\n    }\n\n    ${selector} strong {\n      outline: 1px solid #ff1583 !important;\n    }\n\n    ${selector} i {\n      outline: 1px solid #803156 !important;\n    }\n\n    ${selector} b {\n      outline: 1px solid #cc1169 !important;\n    }\n\n    ${selector} u {\n      outline: 1px solid #ff0430 !important;\n    }\n\n    ${selector} s {\n      outline: 1px solid #f805e3 !important;\n    }\n\n    ${selector} small {\n      outline: 1px solid #d107b2 !important;\n    }\n\n    ${selector} abbr {\n      outline: 1px solid #4a0263 !important;\n    }\n\n    ${selector} q {\n      outline: 1px solid #240018 !important;\n    }\n\n    ${selector} cite {\n      outline: 1px solid #64003c !important;\n    }\n\n    ${selector} dfn {\n      outline: 1px solid #b4005a !important;\n    }\n\n    ${selector} sub {\n      outline: 1px solid #dba0c8 !important;\n    }\n\n    ${selector} sup {\n      outline: 1px solid #cc0256 !important;\n    }\n\n    ${selector} time {\n      outline: 1px solid #d6606d !important;\n    }\n\n    ${selector} code {\n      outline: 1px solid #e04251 !important;\n    }\n\n    ${selector} kbd {\n      outline: 1px solid #5e001f !important;\n    }\n\n    ${selector} samp {\n      outline: 1px solid #9c0033 !important;\n    }\n\n    ${selector} var {\n      outline: 1px solid #d90047 !important;\n    }\n\n    ${selector} mark {\n      outline: 1px solid #ff0053 !important;\n    }\n\n    ${selector} bdi {\n      outline: 1px solid #bf3668 !important;\n    }\n\n    ${selector} bdo {\n      outline: 1px solid #6f1400 !important;\n    }\n\n    ${selector} ruby {\n      outline: 1px solid #ff7b93 !important;\n    }\n\n    ${selector} rt {\n      outline: 1px solid #ff2f54 !important;\n    }\n\n    ${selector} rp {\n      outline: 1px solid #803e49 !important;\n    }\n\n    ${selector} span {\n      outline: 1px solid #cc2643 !important;\n    }\n\n    ${selector} br {\n      outline: 1px solid #db687d !important;\n    }\n\n    ${selector} wbr {\n      outline: 1px solid #db175b !important;\n    }`;\n}\n"
  },
  {
    "path": "code/core/src/outline/preview.ts",
    "content": "import { definePreviewAddon } from 'storybook/internal/csf';\n\nimport { PARAM_KEY } from './constants.ts';\nimport type { OutlineTypes } from './types.ts';\nimport { withOutline } from './withOutline.ts';\n\nexport const decorators = globalThis.FEATURES?.outline ? [withOutline] : [];\n\nexport const initialGlobals = {\n  [PARAM_KEY]: false,\n};\n\nexport type { OutlineTypes };\n\nexport default () => definePreviewAddon<OutlineTypes>({ decorators, initialGlobals });\n"
  },
  {
    "path": "code/core/src/outline/types.ts",
    "content": "export interface OutlineParameters {\n  /**\n   * Outline configuration\n   *\n   * @see https://storybook.js.org/docs/essentials/measure-and-outline#parameters\n   */\n  outline?: {\n    /**\n     * Removes the tool and disables the feature's behavior. If you wish to turn off this feature\n     * for the entire Storybook, you can set the option in your `main.js|ts` configuration file.\n     *\n     * @see https://storybook.js.org/docs/essentials/measure-and-outline#disable\n     */\n    disable?: boolean;\n  };\n}\n\nexport interface OutlineTypes {\n  parameters: OutlineParameters;\n}\n"
  },
  {
    "path": "code/core/src/outline/withOutline.ts",
    "content": "import type { DecoratorFunction } from 'storybook/internal/types';\n\nimport { useEffect, useMemo } from 'storybook/preview-api';\n\nimport { PARAM_KEY } from './constants.ts';\nimport { addOutlineStyles, clearStyles } from './helpers.ts';\nimport outlineCSS from './outlineCSS.ts';\n\nexport const withOutline: DecoratorFunction = (StoryFn, context) => {\n  const globals = context.globals || {};\n  const isActive = [true, 'true'].includes(globals[PARAM_KEY]);\n  const isInDocs = context.viewMode === 'docs';\n\n  const outlineStyles = useMemo(() => {\n    const selector = isInDocs ? `[data-story-block=\"true\"]` : '.sb-show-main';\n\n    return outlineCSS(selector);\n  }, [context]);\n\n  useEffect(() => {\n    const selectorId = isInDocs ? `addon-outline-docs-${context.id}` : `addon-outline`;\n\n    if (!isActive) {\n      clearStyles(selectorId);\n    } else {\n      addOutlineStyles(selectorId, outlineStyles);\n    }\n\n    return () => {\n      clearStyles(selectorId);\n    };\n  }, [isActive, outlineStyles, context]);\n\n  return StoryFn();\n};\n"
  },
  {
    "path": "code/core/src/preview/README.md",
    "content": "# Preview (Web)\n\nThis is the main API for the (web) version of the Storybook Preview.\n\nThe preview's job is:\n\n1. Read and update the URL (via the URL Store)\n\n2. Listen to instructions on the channel and emit events as things occur.\n\n3. Render the current selection to the web view in either story or docs mode.\n\n## Initialization\n\n- `importFn` - is an async `import()` function\n\n- `getProjectAnnotations` - is a simple function that evaluations `preview.js` and addon config files and combines them. If it errors, the Preview will show the error.\n\n- No `getStoryIndex` function is passed, instead the preview creates a `StoryIndexClient` that pulls `stories.json` from node and watches the event stream for invalidation events.\n\n## Story Rendering and interruptions\n\nThe Preview is split into three parts responsible for state management:\n\n- `PreviewWeb` - which story is rendered, receives events and (maybe) changes/re-renders stories\n- `StoryRender` - (imports +) prepares the story, renders it through the various phases\n- `DocsRender` - if a story renders in docs mode, it is \"transformed\" into a `DocsRender` once we know.\n\nA rendering story goes through these phases:\n\n- `preparing` - (maybe async) import the story file and prepare the story function.\n- `loading` - async loaders are running\n- `rendering` - the `renderToCanvas` function for the framework is running\n- `playing` - the `play` function is running\n- `completed` - the story is done.\n\nIt also has two error states:\n\n- `aborted` - the story was stopped midway (see below)\n- `errored` - there was an error thrown somewhere along the way.\n\n### Re-rendering and aborting\n\nA story may re-render due to various events, which can have implications if the story is not in the `completed` phase:\n\n- `UPDATE_STORY_ARGS` / `UPDATE_GLOBALS` -- change of inputs\n- `FORCE_RE_RENDER` - re-render unchanged\n\nIf these events happen during a render:\n\n- if the story is `preparing` or `loading`, leave thing unchanged and let the new `args`/`globals` be picked up by the render phase\n- otherwise, use the result of the previous `loaders` run, and simply re-render over the top\n\n- `FORCE_REMOUNT` - remount (or equivalent) the component and re-render.\n\nIf this happens during a render, treat `loading` similarly, but:\n\n- if the story is `rendering`, start a new render and abort the previous render immediately afterwards\n- if the story is `playing`, attempt to abort the previous play function, and start a new render.\n\n### Changing story\n\nAlso the `SET_CURRENT_STORY` event may change the current story. We need to check:\n\n- If the `storyId` changed\n- If the `viewMode` changed\n- If the story implementation changed (i.e if HMR occurred).\n\nIf the _previous_ story is still `preparing`, we cannot know if the implementation changed, so we\nabort the preparing immediately, and let the new story take over.\n\nOtherwise, if all of the above are the same, we do nothing.\n\nIf they are different, and the old story is not `completed`, we try to abort it immediately. If that fails (e.g. the `play` function doesn't respond to the `abort` event), then we reload the window.\n"
  },
  {
    "path": "code/core/src/preview/globals/globals.ts",
    "content": "// Here we map the name of a module to their REFERENCE in the global scope.\n\nexport const globalsNameReferenceMap = {\n  '@storybook/global': '__STORYBOOK_MODULE_GLOBAL__',\n\n  'storybook/test': '__STORYBOOK_MODULE_TEST__',\n  'storybook/actions': '__STORYBOOK_MODULE_ACTIONS__',\n  'storybook/preview-api': '__STORYBOOK_MODULE_PREVIEW_API__',\n\n  'storybook/internal/channels': '__STORYBOOK_MODULE_CHANNELS__',\n  'storybook/internal/client-logger': '__STORYBOOK_MODULE_CLIENT_LOGGER__',\n  'storybook/internal/core-events': '__STORYBOOK_MODULE_CORE_EVENTS__',\n  'storybook/internal/preview-errors': '__STORYBOOK_MODULE_CORE_EVENTS_PREVIEW_ERRORS__',\n  'storybook/internal/types': '__STORYBOOK_MODULE_TYPES__',\n\n  // @deprecated TODO: Remove in 9.1 or some point in the future, I guess\n  'storybook/internal/preview-api': '__STORYBOOK_MODULE_PREVIEW_API__',\n} as const;\n\nexport const globalPackages = Object.keys(globalsNameReferenceMap) as Array<\n  keyof typeof globalsNameReferenceMap\n>;\n"
  },
  {
    "path": "code/core/src/preview/globals/runtime.ts",
    "content": "import * as CHANNELS from 'storybook/internal/channels';\nimport * as CLIENT_LOGGER from 'storybook/internal/client-logger';\nimport * as CORE_EVENTS from 'storybook/internal/core-events';\nimport * as CORE_EVENTS_PREVIEW_ERRORS from 'storybook/internal/preview-errors';\nimport * as TYPES from 'storybook/internal/types';\n\nimport * as GLOBAL from '@storybook/global';\n\nimport * as ACTIONS from 'storybook/actions';\nimport * as PREVIEW_API from 'storybook/preview-api';\nimport * as TEST from 'storybook/test';\n\nimport type { globalsNameReferenceMap } from './globals.ts';\n\n// Here we map the name of a module to their VALUE in the global scope.\nexport const globalsNameValueMap: Required<Record<keyof typeof globalsNameReferenceMap, any>> = {\n  '@storybook/global': GLOBAL,\n\n  'storybook/test': TEST,\n  'storybook/actions': ACTIONS,\n  'storybook/preview-api': PREVIEW_API,\n\n  'storybook/internal/channels': CHANNELS,\n  'storybook/internal/client-logger': CLIENT_LOGGER,\n  'storybook/internal/core-events': CORE_EVENTS,\n  'storybook/internal/types': TYPES,\n  'storybook/internal/preview-errors': CORE_EVENTS_PREVIEW_ERRORS,\n  'storybook/internal/preview-api': PREVIEW_API,\n};\n"
  },
  {
    "path": "code/core/src/preview/globals.ts",
    "content": "export * from './globals/globals.ts';\n"
  },
  {
    "path": "code/core/src/preview/preview-navigator.stories.tsx",
    "content": "import type { StoryIndex } from 'storybook/internal/types';\n\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { fn } from 'storybook/test';\n\nimport { setupPreviewNavigator, teardownPreviewNavigator } from './preview-navigator.ts';\n\nconst meta: Meta = {\n  parameters: {\n    layout: 'fullscreen',\n  },\n  render: (args) => {\n    return <div className=\"storybook-root\">This is the story content</div>;\n  },\n  args: {\n    currentStoryId: 'input--text',\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nconst mockIndex: StoryIndex = {\n  entries: {\n    'button--primary': {\n      id: 'button--primary',\n      title: 'Button',\n      name: 'Primary',\n      type: 'story',\n      subtype: 'story',\n      importPath: './button/Button.stories.ts',\n    },\n    'button--secondary': {\n      id: 'button--secondary',\n      title: 'Button',\n      name: 'Secondary',\n      type: 'story',\n      subtype: 'story',\n      importPath: './button/Button.stories.ts',\n    },\n    'input--text': {\n      id: 'input--text',\n      title: 'Forms/Input',\n      name: 'Text',\n      type: 'story',\n      subtype: 'story',\n      importPath: './components/input/Input.stories.ts',\n    },\n    'input--number': {\n      id: 'input--number',\n      title: 'Forms/Input',\n      name: 'Number',\n      type: 'story',\n      subtype: 'story',\n      importPath: './components/input/Input.stories.ts',\n    },\n    'checkbox--default': {\n      id: 'checkbox--default',\n      title: 'Forms/Checkbox',\n      name: 'Default',\n      type: 'story',\n      subtype: 'story',\n      importPath: './components/checkbox/Checkbox.stories.ts',\n    },\n    'select--basic': {\n      id: 'select--basic',\n      title: 'Forms/Select',\n      name: 'Basic',\n      type: 'story',\n      subtype: 'story',\n      importPath: './components/select/Select.stories.ts',\n    },\n  },\n  v: 4,\n};\n\nexport const Default: Story = {\n  beforeEach: ({ args }) => {\n    teardownPreviewNavigator();\n    setupPreviewNavigator(mockIndex, args.currentStoryId);\n\n    document.querySelectorAll('.sb-navigator-story-link').forEach((link) => {\n      link.addEventListener(\n        'click',\n        fn((event) => {\n          event.preventDefault();\n        }).mockName('story-link-click')\n      );\n    });\n\n    return teardownPreviewNavigator;\n  },\n};\n"
  },
  {
    "path": "code/core/src/preview/preview-navigator.ts",
    "content": "import type { StoryIndex } from 'storybook/internal/types';\n\ntype LeafNode = {\n  name: string;\n  href: string;\n  id: string;\n  isActive: boolean;\n};\n\ntype BranchNode = {\n  title: string;\n  entries: Record<string, BranchNode | LeafNode>;\n  isActive: boolean;\n};\n\nexport async function maybeSetupPreviewNavigator() {\n  const url = new URL(window.location.href);\n  if (\n    url.searchParams.get('navigator') !== 'true' ||\n    (globalThis as any).__STORYBOOK_PREVIEW_NAVIGATOR__\n  ) {\n    return;\n  }\n  (globalThis as any).__STORYBOOK_PREVIEW_NAVIGATOR__ = true;\n\n  // TODO: custom story sort is not respected\n  const index = (await (await fetch('/index.json')).json()) as StoryIndex;\n\n  const currentEntryId = url.searchParams.get('id');\n  if (!currentEntryId) {\n    const firstEntry = Object.values(index.entries)[0];\n    if (firstEntry) {\n      url.searchParams.set('id', firstEntry.id);\n      url.searchParams.set('viewMode', firstEntry.type);\n      window.location.href = url.toString();\n    }\n    /*\n      We do a hard navigation above, stopping all code execution, so the return here is never reached.\n      It's merely there to tell TypeScript that currentEntryId is always defined.\n      If there is no firstEntryId, that means there are no entries in the story index,\n      and then we want to return early too, because it doesn't make sense to show the sidebar at all.\n    */\n    return;\n  }\n  setupPreviewNavigator(index, currentEntryId);\n}\n\nexport const setupPreviewNavigator = async (index: StoryIndex, currentEntryId: string) => {\n  const tree: BranchNode = { title: '', entries: {}, isActive: true };\n  for (const entry of Object.values(index.entries)) {\n    const titleParts = entry.title.split('/');\n\n    let currentNode = tree;\n    for (const titlePart of titleParts) {\n      if (!currentNode.entries) {\n        currentNode.entries = {};\n      }\n      if (!currentNode.entries[titlePart]) {\n        currentNode.entries[titlePart] = {\n          title: titlePart,\n          isActive: currentEntryId === entry.id,\n          entries: {},\n        };\n      } else if (currentEntryId === entry.id) {\n        currentNode.entries[titlePart].isActive = true;\n      }\n      currentNode = currentNode.entries[titlePart] as BranchNode;\n    }\n    if (!currentNode.entries) {\n      currentNode.entries = {};\n    }\n    currentNode.entries[entry.name] = {\n      id: entry.id,\n      name: entry.name,\n      href: `?id=${entry.id}&viewMode=${entry.type}&navigator=true`,\n      isActive: currentEntryId === entry.id,\n    };\n  }\n\n  const createHtmlForNode = (node: BranchNode | LeafNode): string => {\n    if ('entries' in node && 'title' in node) {\n      const branchNode = node as BranchNode;\n      return `\n      <li class=\"sb-navigator-branch\">\n        <details${branchNode.isActive ? ' open' : ''}>\n          <summary class=\"sb-navigator-title\">\n            ${branchNode.title}\n          </summary>\n          <ul class=\"sb-navigator-entries\" aria-label=\"${branchNode.title}\">\n            ${Object.values(branchNode.entries).map(createHtmlForNode).join('')}\n          </ul>\n        </details>\n      </li>\n      `;\n    }\n\n    const leafNode = node as LeafNode;\n    return `\n      <li class=\"sb-navigator-story-item\">\n        <a href=\"${leafNode.href}\" \n           class=\"sb-navigator-story-link${leafNode.isActive ? ' active' : ''}\" \n           aria-current=\"${leafNode.isActive ? 'location' : 'false'}\">${leafNode.name}</a>\n      </li>\n    `;\n  };\n\n  const navItems = Object.values(tree.entries).map(createHtmlForNode).join('');\n\n  const nav = document.createElement('nav');\n  nav.id = 'sb-navigator-container';\n  nav.setAttribute('role', 'navigation');\n  nav.setAttribute('aria-label', 'Story navigation');\n  nav.innerHTML = `\n    <ul class=\"sb-navigator-list\">${navItems}</ul>\n  `;\n\n  document.body.insertBefore(nav, document.body.firstChild);\n\n  const style = document.createElement('style');\n  style.id = 'sb-navigator-style';\n  style.textContent = `\n    body {\n      display: grid !important;\n      grid-template-columns: 300px 1fr;\n      font-family: 'Nunito', sans-serif;\n      height: 100vh;\n      margin: 0;\n\n      --text-color: rgb(46, 52, 56);\n      --bg-color: rgb(246, 249, 252);\n\n      @media (prefers-color-scheme: dark) {\n        --text-color: rgb(201, 205, 207);\n        --bg-color: rgb(34, 36, 37);\n      }\n    }\n    #storybook-root, #storybook-docs {\n      overflow-y: auto;\n      max-height: 100vh;\n      max-width: 100%;\n    }\n    #sb-navigator-container, #sb-navigator-container * {\n      box-sizing: border-box;\n    }\n    #sb-navigator-container {\n        height: 100vh;\n        overflow-y: auto;\n        border-right: 1px solid #eee;\n        padding: 1rem;\n        font-size: 14px;\n        color: var(--text-color);\n        background-color: var(--bg-color);\n        align-self: start;\n        z-index: 1000;\n    }\n    .sb-main-padded #sb-navigator-container {\n      margin: -1rem 1rem -1rem -1rem;\n    }\n    .sb-navigator-list {\n      list-style-type: none;\n      padding: 0;\n      margin: 0;\n    }\n    .sb-navigator-branch {\n      list-style-type: none;\n    }\n    .sb-navigator-item {\n      margin-bottom: 15px;\n    }\n    .sb-navigator-title {\n      color: var(--text-color);\n      text-decoration: none;\n      padding-block: 5px;\n      cursor: pointer;\n    }\n    .sb-navigator-entries {\n      padding-left: 15px;\n    }\n    .sb-navigator-story-item {\n      margin-bottom: 8px;\n      margin-left: 8px;\n    }\n    .sb-navigator-story-link {\n      color: var(--text-color);\n    }\n    .sb-navigator-story-link.active {\n      font-weight: bold;\n      color: hsl(212 100 46);\n    }\n  `;\n  document.head.appendChild(style);\n\n  // scroll to the active component\n  nav\n    .querySelector('.sb-navigator-story-link.active')\n    ?.closest('details')\n    ?.scrollIntoView({ block: 'center' });\n};\n\nexport const teardownPreviewNavigator = () => {\n  document.querySelector('#sb-navigator-container')?.remove();\n  document.querySelector('#sb-navigator-style')?.remove();\n  (globalThis as any).__STORYBOOK_PREVIEW_NAVIGATOR__ = false;\n};\n"
  },
  {
    "path": "code/core/src/preview/runtime.ts",
    "content": "import { MANAGER_INERT_ATTRIBUTE_CHANGED, TELEMETRY_ERROR } from 'storybook/internal/core-events';\n\nimport { global } from '@storybook/global';\n\nimport { globalPackages, globalsNameReferenceMap } from './globals/globals.ts';\nimport { globalsNameValueMap } from './globals/runtime.ts';\nimport { maybeSetupPreviewNavigator } from './preview-navigator.ts';\nimport { prepareForTelemetry } from './utils.ts';\n\nfunction errorListener(args: any) {\n  const error = args.error || args;\n  if (error.fromStorybook) {\n    global.sendTelemetryError(error);\n  }\n}\n\nfunction unhandledRejectionListener({ reason }: any) {\n  if (reason.fromStorybook) {\n    global.sendTelemetryError(reason);\n  }\n}\n\nexport function setup() {\n  // Apply all the globals\n  globalPackages.forEach((key) => {\n    (global as any)[globalsNameReferenceMap[key]] = globalsNameValueMap[key];\n  });\n\n  global.sendTelemetryError = (error: any) => {\n    const channel = global.__STORYBOOK_ADDONS_CHANNEL__;\n    channel.emit(TELEMETRY_ERROR, prepareForTelemetry(error));\n  };\n\n  /**\n   * Ensure we synchronise the preview runtime's inert state with the manager's. The inert attribute\n   * used to be propagated into iframes, but this has changed, breaking focus trap implementations\n   * that rely on inert on the document root. We synchronise inert to ensure end user components\n   * don't programmatically focus when a focus trap is active in the manager UI. Otherwise, the UI\n   * could reach a deadlock state and be unusable.\n   */\n  document.addEventListener('DOMContentLoaded', () => {\n    const channel = global.__STORYBOOK_ADDONS_CHANNEL__;\n    channel.on(MANAGER_INERT_ATTRIBUTE_CHANGED, (isInert: boolean) => {\n      if (isInert) {\n        document.body.setAttribute('inert', 'true');\n      } else {\n        document.body.removeAttribute('inert');\n      }\n    });\n  });\n\n  // handle all uncaught StorybookError at the root of the application and log to telemetry if applicable\n  global.addEventListener('error', errorListener);\n  global.addEventListener('unhandledrejection', unhandledRejectionListener);\n  maybeSetupPreviewNavigator();\n}\n\n// TODO: In the future, remove this call to make the module side-effect free\n// when the webpack builder also imports this as a regular file\nsetup();\n"
  },
  {
    "path": "code/core/src/preview/typings.d.ts",
    "content": "declare var LOGLEVEL: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent' | undefined;\n\ndeclare var __STORYBOOK_ADDONS_CHANNEL__: any;\ndeclare var __STORYBOOK_MODULE_CORE_EVENTS_PREVIEW_ERRORS__: any;\ndeclare var sendTelemetryError: (error: any) => void;\n"
  },
  {
    "path": "code/core/src/preview/utils.ts",
    "content": "import { global } from '@storybook/global';\n\nimport type { BrowserInfo } from 'browser-dtector';\nimport BrowserDetector from 'browser-dtector';\n\nlet browserInfo: BrowserInfo | undefined;\n\nfunction getBrowserInfo() {\n  if (!browserInfo) {\n    browserInfo = new BrowserDetector(global.navigator?.userAgent).getBrowserInfo();\n  }\n\n  return browserInfo;\n}\n\nexport function prepareForTelemetry(\n  error: Error & {\n    fromStorybook?: boolean;\n    category?: string;\n    target?: any;\n    currentTarget?: any;\n    srcElement?: any;\n    browserInfo?: BrowserInfo;\n  }\n) {\n  error.browserInfo = getBrowserInfo();\n\n  return error;\n}\n"
  },
  {
    "path": "code/core/src/preview-api/Errors.stories.tsx",
    "content": "import React from 'react';\n\nimport AnsiToHtml from 'ansi-to-html';\nimport { dedent } from 'ts-dedent';\n\nimport type { DecoratorFunction } from '../csf/index.ts';\n\nconst ansiConverter = new AnsiToHtml({\n  escapeXML: true,\n});\n\nconst StyleDecorator: DecoratorFunction = (Story) => (\n  <>\n    <style>{`\n          * {\n            background-color: green;\n            color: green;\n          }\n        `}</style>\n    <Story />\n  </>\n);\n\nconst Component = ({ id, header, detail }: any) => {\n  const element = document.querySelector('.' + id);\n  if (!element) {\n    throw new Error('Element not found');\n  }\n\n  if (header) {\n    document.getElementById('error-message')!.innerHTML = ansiConverter.toHtml(header);\n  }\n\n  if (detail) {\n    document.getElementById('error-stack')!.innerHTML = ansiConverter.toHtml(detail);\n  }\n\n  // remove the ids, otherwise chromatic will assume the story failed to render\n  const content = element.outerHTML.replace('error-message', '').replace('error-stack', '');\n\n  // remove the content, otherwise chromatic will assume the story failed to render\n  document.getElementById('error-message')!.innerHTML = '';\n  document.getElementById('error-stack')!.innerHTML = '';\n\n  return (\n    <div\n      className=\"sb-show-nopreview sb-show-errordisplay\"\n      dangerouslySetInnerHTML={{ __html: content }}\n    />\n  );\n};\n\nexport default {\n  component: Component,\n  parameters: {\n    layout: 'fullscreen',\n  },\n  globals: { sb_theme: 'light' },\n  title: 'Errors',\n  args: {\n    id: 'sb-errordisplay',\n  },\n  // This story cannot be properly tested in portable stories as it depends on an element that only exists in Storybook's preview HTML\n  tags: ['!vitest'],\n};\n\nexport const MyError = {\n  args: {\n    header: `FAIL is not defined`,\n    detail: dedent`\n      ReferenceError: FAIL is not defined\n        at Constraint.execute (the-best-file.js:525:2)\n        at Constraint.recalculate (the-best-file.js:424:21)\n        at Planner.addPropagate (the-best-file.js:701:6)\n        at Constraint.satisfy (the-best-file.js:184:15)\n        at Planner.incrementalAdd (the-best-file.js:591:21)\n        at Constraint.addConstraint (the-best-file.js:162:10)\n        at Constraint.BinaryConstraint (the-best-file.js:346:7)\n        at Constraint.EqualityConstraint (the-best-file.js:515:38)\n        at chainTest (the-best-file.js:807:6)\n        at deltaBlue (the-best-file.js:879:2)`,\n  },\n};\n\nexport const MyErrorWithCustomCSS = {\n  ...MyError,\n  decorators: [StyleDecorator],\n};\n\nexport const Missing = {\n  args: {\n    id: 'sb-nopreview',\n  },\n};\n\nexport const MissingWithCustomCSS = {\n  ...Missing,\n  decorators: [StyleDecorator],\n};\n"
  },
  {
    "path": "code/core/src/preview-api/README-addons.md",
    "content": "# Storybook Addons\n\nStorybook Addons is a node module which is used to load custom addons to storybook.\n\nIt stores addon loaders, communication channel and other resources which can be used by storybook implementations where required.\n\n---\n\nFor more information visit: [storybook.js.org](https://storybook.js.org)\n"
  },
  {
    "path": "code/core/src/preview-api/README-core-client.md",
    "content": "# Storybook Core-Client\n\nThis package contains browser-side functionality shared amongst all the frameworks (React, RN, Vue 3, Ember, Angular, etc) in the old \"v6\" story store back-compatibility layer.\n\nA framework calls the `start(renderToCanvas, { render, decorateStory })` function and provides:\n\n- The `renderToCanvas` function, which tells Storybook how to render the result of a story function to the DOM\n- The `render` function, which is a default mapping of `args` to a story result in CSFv3\n- The `decorateStory` function, which tells Storybook how to combine decorators in the framework.\n\nThe `start` function will return a `configure()` function, which can be re-exported to be used in `preview.js` (deprecated), or automatically by the `main.js:stories` field to:\n\n- return a list of CSF files\n- `deprecated` make calls to the `storiesOf` API.\n"
  },
  {
    "path": "code/core/src/preview-api/README-preview-web.md",
    "content": "# Preview (Web)\n\nThis is the main API for the (web) version of the Storybook Preview.\n\nThe preview's job is:\n\n1. Read and update the URL (via the URL Store)\n\n2. Listen to instructions on the channel and emit events as things occur.\n\n3. Render the current selection to the web view in either story or docs mode.\n\n## Initialization\n\n- `importFn` - is an async `import()` function\n\n- `getProjectAnnotations` - is a simple function that evaluations `preview.js` and addon config files and combines them. If it errors, the Preview will show the error.\n\n- No `getStoryIndex` function is passed, instead the preview creates a `StoryIndexClient` that pulls `stories.json` from node and watches the event stream for invalidation events.\n\n## Story Rendering and interruptions\n\nThe Preview is split into three parts responsible for state management:\n\n- `PreviewWeb` - which story is rendered, receives events and (maybe) changes/re-renders stories\n- `StoryRender` - (imports +) prepares the story, renders it through the various phases\n- `DocsRender` - if a story renders in docs mode, it is \"transformed\" into a `DocsRender` once we know.\n\nA rendering story goes through these phases:\n\n- `preparing` - (maybe async) import the story file and prepare the story function.\n- `loading` - async loaders are running\n- `rendering` - the `renderToCanvas` function for the framework is running\n- `playing` - the `play` function is running\n- `completed` - the story is done.\n\nIt also has two error states:\n\n- `aborted` - the story was stopped midway (see below)\n- `errored` - there was an error thrown somewhere along the way.\n\n### Re-rendering and aborting\n\nA story may re-render due to various events, which can have implications if the story is not in the `completed` phase:\n\n- `UPDATE_STORY_ARGS` / `UPDATE_GLOBALS` -- change of inputs\n- `FORCE_RE_RENDER` - re-render unchanged\n\nIf these events happen during a render:\n\n- if the story is `preparing` or `loading`, leave thing unchanged and let the new `args`/`globals` be picked up by the render phase\n- otherwise, use the result of the previous `loaders` run, and simply re-render over the top\n\n- `FORCE_REMOUNT` - remount (or equivalent) the component and re-render.\n\nIf this happens during a render, treat `loading` similarly, but:\n\n- if the story is `rendering`, start a new render and abort the previous render immediately afterwards\n- if the story is `playing`, attempt to abort the previous play function, and start a new render.\n\n### Changing story\n\nAlso the `SET_CURRENT_STORY` event may change the current story. We need to check:\n\n- If the `storyId` changed\n- If the `viewMode` changed\n- If the story implementation changed (i.e if HMR occurred).\n\nIf the _previous_ story is still `preparing`, we cannot know if the implementation changed, so we\nabort the preparing immediately, and let the new story take over.\n\nOtherwise, if all of the above are the same, we do nothing.\n\nIf they are different, and the old story is not `completed`, we try to abort it immediately. If that fails (e.g. the `play` function doesn't respond to the `abort` event), then we reload the window.\n"
  },
  {
    "path": "code/core/src/preview-api/README-store.md",
    "content": "# Storybook Store\n\nThe store is responsible for loading a story from a CSF file and preparing into a `Story` type, which is our internal format.\n\n## Story vs StoryContext\n\nStory functions and decorators receive a `StoryContext<Framework>` object (parameterized by their framework).\n\nThe `Story` type that we pass around in our code includes all of those fields apart from the `args`, `globals`, `hooks` and `viewMode`, which are mutable and stored separately in the store.\n\n## Identification\n\nThe first set of fields on a `Story` are the identifying fields for a story:\n\n- `componentId` - the URL \"id\" of the component\n- `title` - the title of the component, which generates the sidebar entry\n- `id` - the story \"id\" (in the URL)\n- `name` - the name of the story\n\n## Annotations\n\nThe main fields on a `Story` are the various annotations. Annotations can be set:\n\n- At the project level in `preview.js` (or via addons)\n- At the component level via `export default { ... }` in a CSF file\n- At the story level via `export const Story = {...}` in a CSF file.\n\nNot all annotations can be set at every level but most can.\n\n## Parameters\n\nThe story parameters is a static, serializable object of data that provides details about the story. Those details can be used by addons or Storybook itself to render UI or provide defaults about the story rendering.\n\nParameters _cannot change_ and are synchronized to the manager once when the story is loaded (note over the lifetime of a development Storybook a story can be loaded several times due to hot module reload, so the parameters technically can change for that reason).\n\nUsually addons will read from a single key of `parameters` namespaced by the name of that addon. For instance the configuration of the `backgrounds` addon is driven by the `parameters.backgrounds` namespace.\n\nParameters are inheritable -- you can set project parameters via `export parameters = {}`, at the component level by the `parameters` key of the component (default) export in CSF, and on a single story via the `parameters` key on the story data.\n\nSome notable parameters:\n\n- `parameters.fileName` - the file that the story was defined in, when available\n\n## Args\n\nArgs are \"inputs\" to stories.\n\nYou can think of them equivalently to React props, Angular inputs and outputs, etc.\n\nChanging the args cause the story to be re-rendered with the new set of args.\n\n### Using args in a story\n\nBy default the args will be passed to the story as first argument and the context as second:\n\n```js\nconst YourStory = ({ x, y } /*, context*/) => /* render your story using `x` and `y` */\n```\n\n### Arg types and values\n\nArg types are used by the docs addon to populate the props table and are documented there. They are controlled by `argTypes` and can (sometimes) be automatically inferred from type information about the story or the component rendered by the story.\n\nA story can set initial values of its args with the `args` annotation. If you set an initial value for an arg that doesn't have a type a simple type will be inferred from the value.\n\nIf an arg doesn't have an initial value, it will start unset, although it can still be set later via user interaction.\n\nArgs can be set at the project, component and story level.\n\n### Using args in an addon\n\nArgs values are automatically synchronized (via the `changeStoryArgs` and `storyArgsChanged` events) between the preview and manager; APIs exist in `lib/api` to read and set args in the manager.\n\nArgs need to be serializable -- so currently cannot include callbacks (this may change in a future version).\n\nNote that arg values are passed directly to a story -- you should only store the actual value that the story needs to render in the arg. If you need more complex information supporting that, use parameters or addon state.\n\nBoth `@storybook/preview-api` and `@storybook/manager-api` export a `useArgs()` hook that you can use to access args in decorators or addon panels. The API is as follows:\n\n```js\nimport { useArgs } from '@storybook/preview-api';\n\n// or '@storybook/manager-api'\n\n// `args` is the args of the currently rendered story\n// `updateArgs` will update its args. You can pass a subset of the args; other args will not be changed.\nconst [args, updateArgs] = useArgs();\n```\n\n## ArgTypes\n\nArg types add type information and metadata about args that are used to control the docs and controls addons.\n\n### ArgTypes enhancement\n\nTo add a argTypes enhancer, `export const argTypesEnhancers = []` from `preview.js` or and addon\n\nThere is a default enhancer that ensures that each `arg` in a story has a baseline `argType`. This value can be improved by subsequent enhancers, e.g. those provided by `@storybook/addon-docs`.\n\n## Globals\n\nGlobals are rendering information that is global across stories. They are used for things like themes and internationalization (i18n) in stories, where you want Storybook to \"remember\" your setting as you browse between stories.\n\nThey can be accessed in stories and decorators in the `context.globals` key.\n\n### Initial values of globals\n\nTo set initial values of globals, `export const globals = {...}` from `preview.js`\n\n### Using globals in an addon\n\nSimilar to args, globals are synchronized to the manager and can be accessed via the `useGlobals` hook.\n\n```js\nimport { useGlobals } from '@storybook/preview-api';\n\n// or '@storybook/manager-api'\n\nconst [globals, updateGlobals] = useGlobals();\n```\n\n## Technical details\n\n### Initialization\n\n- The store is created \"uninitialized\".\n- It is assumed at some later time it will be initialized with the Story Index, the set of stories (this may be loaded async).\n- You _can_ call `loadStory` prior to that time, in which case it will wait for initialization.\n\n### Caching\n\n- \"All story\" APIs like `extract()` require all stories to be loaded.\n- For backwards-compatibility, these APIs are _not_ async, so it is required that `store.cacheAllCSFFiles()` is called first\n- In v6 mode, this will be called on initialization but `start.ts`.\n"
  },
  {
    "path": "code/core/src/preview-api/README.md",
    "content": "# Preview API\n\nTODO write proper documentation of this package\n\n# \"Sub packages\" README documents\n\nThis package used to be multiple packages (they have been combined into this one):\n\n- `@storybook/addons` [read (old) docs](./README-addons.md)\n- `@storybook/core-client` [read (old) docs](./README-core-client.md)\n- `@storybook/preview-web` [read (old) docs](./README-preview-web.md)\n- `@storybook/store` [read (old) docs](./README-store.md)\n"
  },
  {
    "path": "code/core/src/preview-api/addons.ts",
    "content": "/// <reference path=\"../typings.d.ts\" />\n\nexport * from './modules/addons/index.ts';\n"
  },
  {
    "path": "code/core/src/preview-api/index.ts",
    "content": "/// <reference path=\"../typings.d.ts\" />\n\n/** HOOKS API */\nexport {\n  useArgs,\n  useCallback,\n  useChannel,\n  useEffect,\n  useGlobals,\n  useMemo,\n  useParameter,\n  useReducer,\n  useRef,\n  useState,\n  useStoryContext,\n  applyHooks,\n  HooksContext,\n} from './addons.ts';\n\n/** DECORATORS API */\nexport { makeDecorator } from './addons.ts';\n\n/**\n * ADDON API\n *\n * @deprecated\n */\nexport { addons, mockChannel } from './addons.ts';\n\n// TODO: Universal Stores are disabled in the preview, until we get automatic leader negotiation in place\n// export { UniversalStore as experimental_UniversalStore } from '../shared/universal-store';\n// export { useUniversalStore as experimental_useUniversalStore } from '../shared/universal-store/use-universal-store-preview';\n// export { MockUniversalStore as experimental_MockUniversalStore } from '../shared/universal-store/mock';\n// export {\n//   getStatusStoreByTypeId as experimental_getStatusStore,\n//   useStatusStore as experimental_useStatusStore,\n//   fullStatusStore as internal_fullStatusStore,\n// } from './stores/status';\n\n/** DOCS API */\nexport { DocsContext } from './preview-web.ts';\n\n/** SIMULATION API */\nexport { simulatePageLoad, simulateDOMContentLoaded } from './preview-web.ts';\n\nexport {\n  combineArgs,\n  combineParameters,\n  composeConfigs,\n  composeStepRunners,\n  composeStories,\n  composeStory,\n  decorateStory,\n  defaultDecorateStory,\n  prepareStory,\n  prepareMeta,\n  normalizeArrays,\n  normalizeStory,\n  filterArgTypes,\n  sanitizeStoryContextUpdate,\n  setDefaultProjectAnnotations,\n  setProjectAnnotations,\n  inferControls,\n  userOrAutoTitleFromSpecifier,\n  userOrAutoTitle,\n  sortStoriesV7,\n  normalizeProjectAnnotations,\n} from './store.ts';\n\n/** CSF API */\nexport { createPlaywrightTest, getCsfFactoryAnnotations } from './modules/store/csf/index.ts';\n\nexport type { PropDescriptor } from './store.ts';\n\nexport { Tag } from '../shared/constants/tags.ts';\n\n/** STORIES API */\nexport { StoryStore, type Report, ReporterAPI } from './store.ts';\nexport {\n  Preview,\n  PreviewWeb,\n  PreviewWithSelection,\n  UrlStore,\n  WebView,\n  emitTransformCode,\n  pauseAnimations,\n  waitForAnimations,\n} from './preview-web.ts';\nexport type { SelectionStore, View } from './preview-web.ts';\n"
  },
  {
    "path": "code/core/src/preview-api/modules/addons/hooks.test.js",
    "content": "import { afterEach, beforeEach, describe, expect, it } from 'vitest';\n\nimport { useParameter, useStoryContext } from './hooks';\n\ndescribe('addons/hooks', () => {\n  beforeEach(() => {\n    global.STORYBOOK_HOOKS_CONTEXT = undefined;\n  });\n\n  afterEach(() => {\n    global.STORYBOOK_HOOKS_CONTEXT = undefined;\n  });\n\n  describe('useStoryContext', () => {\n    it('should throw', () => {\n      expect(() => useStoryContext()).toThrowError(\n        'Storybook preview hooks can only be called inside decorators and story functions.'\n      );\n    });\n  });\n\n  describe('useParameter', () => {\n    beforeEach(() => {\n      global.STORYBOOK_HOOKS_CONTEXT = {\n        currentContext: {\n          parameters: {\n            'undefined key': undefined,\n            'null key': null,\n            'false key': false,\n            'zero key': 0,\n            'object key': { defined: true },\n          },\n        },\n      };\n    });\n\n    it('undefined key', () => {\n      expect(useParameter('undefined key', 'undefined default')).toEqual('undefined default');\n    });\n\n    it('null key', () => {\n      expect(useParameter('null key', 'null default')).toEqual('null default');\n    });\n\n    it('false key', () => {\n      expect(useParameter('false key', 'false default')).toEqual(false);\n    });\n\n    it('zero key', () => {\n      expect(useParameter('zero key', 'zero default')).toEqual(0);\n    });\n\n    it('object key', () => {\n      expect(useParameter('object key', 'object default')).toMatchObject({ defined: true });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/addons/hooks.ts",
    "content": "import { logger } from 'storybook/internal/client-logger';\nimport {\n  FORCE_RE_RENDER,\n  RESET_STORY_ARGS,\n  STORY_RENDERED,\n  UPDATE_GLOBALS,\n  UPDATE_STORY_ARGS,\n} from 'storybook/internal/core-events';\nimport type {\n  Args,\n  DecoratorApplicator,\n  DecoratorFunction,\n  LegacyStoryFn,\n  Renderer,\n  StoryContext,\n  StoryId,\n} from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { addons } from './main.ts';\n\ninterface Hook {\n  name: string;\n  memoizedState?: any;\n  deps?: any[] | undefined;\n}\n\ninterface Effect {\n  create: () => (() => void) | void;\n  destroy?: (() => void) | void;\n}\n\ntype AbstractFunction = (...args: any[]) => any;\n\nexport class HooksContext<TRenderer extends Renderer, TArgs extends Args = Args> {\n  hookListsMap: WeakMap<AbstractFunction, Hook[]> = undefined as any;\n\n  mountedDecorators: Set<AbstractFunction> = undefined as any;\n\n  prevMountedDecorators: Set<AbstractFunction> = undefined as any;\n\n  currentHooks: Hook[] = undefined as any;\n\n  nextHookIndex: number = undefined as any;\n\n  currentPhase: 'MOUNT' | 'UPDATE' | 'NONE' = undefined as any;\n\n  currentEffects: Effect[] = undefined as any;\n\n  prevEffects: Effect[] = undefined as any;\n\n  currentDecoratorName: string | null = undefined as any;\n\n  hasUpdates: boolean = undefined as any;\n\n  currentContext: StoryContext<TRenderer, TArgs> | null = undefined as any;\n\n  renderListener = (storyId: StoryId) => {\n    if (storyId !== this.currentContext?.id) {\n      return;\n    }\n    this.triggerEffects();\n    this.currentContext = null;\n    this.removeRenderListeners();\n  };\n\n  constructor() {\n    this.init();\n  }\n\n  init() {\n    this.hookListsMap = new WeakMap();\n    this.mountedDecorators = new Set();\n    this.prevMountedDecorators = new Set();\n    this.currentHooks = [];\n    this.nextHookIndex = 0;\n    this.currentPhase = 'NONE';\n    this.currentEffects = [];\n    this.prevEffects = [];\n    this.currentDecoratorName = null;\n    this.hasUpdates = false;\n    this.currentContext = null;\n  }\n\n  clean() {\n    this.prevEffects.forEach((effect) => {\n      if (effect.destroy) {\n        effect.destroy();\n      }\n    });\n    this.init();\n    this.removeRenderListeners();\n  }\n\n  getNextHook() {\n    const hook = this.currentHooks[this.nextHookIndex];\n    this.nextHookIndex += 1;\n    return hook;\n  }\n\n  triggerEffects() {\n    // destroy removed effects\n    this.prevEffects.forEach((effect) => {\n      if (!this.currentEffects.includes(effect) && effect.destroy) {\n        effect.destroy();\n      }\n    });\n    // trigger added effects\n    this.currentEffects.forEach((effect) => {\n      if (!this.prevEffects.includes(effect)) {\n        effect.destroy = effect.create();\n      }\n    });\n    this.prevEffects = this.currentEffects;\n    this.currentEffects = [];\n  }\n\n  addRenderListeners() {\n    this.removeRenderListeners();\n    const channel = addons.getChannel();\n    channel.on(STORY_RENDERED, this.renderListener);\n  }\n\n  removeRenderListeners() {\n    const channel = addons.getChannel();\n    channel.removeListener(STORY_RENDERED, this.renderListener);\n  }\n}\n\nfunction hookify<TRenderer extends Renderer>(\n  storyFn: LegacyStoryFn<TRenderer>\n): LegacyStoryFn<TRenderer>;\nfunction hookify<TRenderer extends Renderer>(\n  decorator: DecoratorFunction<TRenderer>\n): DecoratorFunction<TRenderer>;\nfunction hookify<TRenderer extends Renderer>(fn: AbstractFunction) {\n  const hookified = (...args: any[]) => {\n    const { hooks }: { hooks: HooksContext<TRenderer> } =\n      typeof args[0] === 'function' ? args[1] : args[0];\n\n    const prevPhase = hooks.currentPhase;\n    const prevHooks = hooks.currentHooks;\n    const prevNextHookIndex = hooks.nextHookIndex;\n    const prevDecoratorName = hooks.currentDecoratorName;\n\n    hooks.currentDecoratorName = fn.name;\n    if (hooks.prevMountedDecorators.has(fn)) {\n      hooks.currentPhase = 'UPDATE';\n      hooks.currentHooks = hooks.hookListsMap.get(fn) || [];\n    } else {\n      hooks.currentPhase = 'MOUNT';\n      hooks.currentHooks = [];\n      hooks.hookListsMap.set(fn, hooks.currentHooks);\n      hooks.prevMountedDecorators.add(fn);\n    }\n    hooks.nextHookIndex = 0;\n\n    const prevContext = global.STORYBOOK_HOOKS_CONTEXT;\n    global.STORYBOOK_HOOKS_CONTEXT = hooks;\n    const result = fn(...args);\n    global.STORYBOOK_HOOKS_CONTEXT = prevContext;\n\n    if (hooks.currentPhase === 'UPDATE' && hooks.getNextHook() != null) {\n      throw new Error(\n        'Rendered fewer hooks than expected. This may be caused by an accidental early return statement.'\n      );\n    }\n\n    hooks.currentPhase = prevPhase;\n    hooks.currentHooks = prevHooks;\n    hooks.nextHookIndex = prevNextHookIndex;\n    hooks.currentDecoratorName = prevDecoratorName;\n    return result;\n  };\n\n  hookified.originalFn = fn;\n  return hookified;\n}\n\n// Counter to prevent infinite loops.\nlet numberOfRenders = 0;\nconst RENDER_LIMIT = 25;\nexport const applyHooks =\n  <TRenderer extends Renderer>(\n    applyDecorators: DecoratorApplicator<TRenderer>\n  ): DecoratorApplicator<TRenderer> =>\n  (storyFn: LegacyStoryFn<TRenderer>, decorators: DecoratorFunction<TRenderer>[]) => {\n    const decorated = applyDecorators(\n      hookify(storyFn),\n      decorators.map((decorator) => hookify(decorator))\n    );\n    return (context) => {\n      const { hooks } = context as { hooks: HooksContext<TRenderer> };\n      hooks.prevMountedDecorators ??= new Set();\n      hooks.mountedDecorators = new Set([storyFn, ...decorators]);\n      hooks.currentContext = context;\n      hooks.hasUpdates = false;\n      let result = decorated(context);\n      numberOfRenders = 1;\n      while (hooks.hasUpdates) {\n        hooks.hasUpdates = false;\n        hooks.currentEffects = [];\n        result = decorated(context);\n        numberOfRenders += 1;\n        if (numberOfRenders > RENDER_LIMIT) {\n          throw new Error(\n            'Too many re-renders. Storybook limits the number of renders to prevent an infinite loop.'\n          );\n        }\n      }\n      hooks.addRenderListeners();\n      return result;\n    };\n  };\n\nconst areDepsEqual = (deps: any[], nextDeps: any[]) =>\n  deps.length === nextDeps.length && deps.every((dep, i) => dep === nextDeps[i]);\n\nconst invalidHooksError = () =>\n  new Error(\n    'Storybook preview hooks can only be called inside decorators and story functions.\\n\\n' +\n      \"When combining Storybook hooks (e.g. useArgs) with framework hooks (e.g. React's useState, useEffect, useRef) in the same render function, use Storybook's equivalents from 'storybook/preview-api' instead: useState, useEffect, useRef, useMemo, useCallback, useReducer.\"\n  );\n\nfunction getHooksContextOrNull<\n  TRenderer extends Renderer,\n  TArgs extends Args = Args,\n>(): HooksContext<TRenderer, TArgs> | null {\n  return global.STORYBOOK_HOOKS_CONTEXT || null;\n}\n\nfunction getHooksContextOrThrow<\n  TRenderer extends Renderer,\n  TArgs extends Args = Args,\n>(): HooksContext<TRenderer, TArgs> {\n  const hooks = getHooksContextOrNull<TRenderer, TArgs>();\n  if (hooks == null) {\n    throw invalidHooksError();\n  }\n  return hooks;\n}\n\nfunction useHook(name: string, callback: (hook: Hook) => void, deps?: any[] | undefined): Hook {\n  const hooks = getHooksContextOrThrow();\n  if (hooks.currentPhase === 'MOUNT') {\n    if (deps != null && !Array.isArray(deps)) {\n      logger.warn(\n        `${name} received a final argument that is not an array (instead, received ${deps}). When specified, the final argument must be an array.`\n      );\n    }\n    const hook: Hook = { name, deps };\n    hooks.currentHooks.push(hook);\n    callback(hook);\n    return hook;\n  }\n\n  if (hooks.currentPhase === 'UPDATE') {\n    const hook = hooks.getNextHook();\n    if (hook == null) {\n      throw new Error('Rendered more hooks than during the previous render.');\n    }\n\n    if (hook.name !== name) {\n      logger.warn(\n        `Storybook has detected a change in the order of Hooks${\n          hooks.currentDecoratorName ? ` called by ${hooks.currentDecoratorName}` : ''\n        }. This will lead to bugs and errors if not fixed.`\n      );\n    }\n\n    if (deps != null && hook.deps == null) {\n      logger.warn(\n        `${name} received a final argument during this render, but not during the previous render. Even though the final argument is optional, its type cannot change between renders.`\n      );\n    }\n\n    if (deps != null && hook.deps != null && deps.length !== hook.deps.length) {\n      logger.warn(`The final argument passed to ${name} changed size between renders. The order and size of this array must remain constant.\nPrevious: ${hook.deps}\nIncoming: ${deps}`);\n    }\n\n    if (deps == null || hook.deps == null || !areDepsEqual(deps, hook.deps)) {\n      callback(hook);\n      hook.deps = deps;\n    }\n    return hook;\n  }\n\n  throw invalidHooksError();\n}\n\nfunction useMemoLike<T>(name: string, nextCreate: () => T, deps: any[] | undefined): T {\n  const { memoizedState } = useHook(\n    name,\n    (hook) => {\n      hook.memoizedState = nextCreate();\n    },\n    deps\n  );\n  return memoizedState;\n}\n\n/**\n * Returns a memoized value.\n *\n * @example\n *\n * ```ts\n * const memoizedValue = useMemo(() => {\n *   return doExpensiveCalculation(a, b);\n * }, [a, b]);\n * ```\n *\n * @template T The type of the memoized value.\n * @param {() => T} nextCreate A function that returns the memoized value.\n * @param {any[]} [deps] An optional array of dependencies. If any of the dependencies change, the\n *   memoized value will be recomputed.\n * @returns {T} The memoized value.\n */\nexport function useMemo<T>(nextCreate: () => T, deps?: any[]): T {\n  return useMemoLike('useMemo', nextCreate, deps);\n}\n\n/**\n * Returns a memoized callback.\n *\n * @example\n *\n * ```ts\n * const memoizedCallback = useCallback(() => {\n *   doSomething(a, b);\n * }, [a, b]);\n * ```\n *\n * @template T The type of the callback function.\n * @param {T} callback The callback function to memoize.\n * @param {any[]} [deps] An optional array of dependencies. If any of the dependencies change, the\n *   memoized callback will be recomputed.\n * @returns {T} The memoized callback.\n */\n/* Returns a memoized callback, see https://reactjs.org/docs/hooks-reference.html#usecallback */\nexport function useCallback<T>(callback: T, deps?: any[]): T {\n  return useMemoLike('useCallback', () => callback, deps);\n}\n\nfunction useRefLike<T>(name: string, initialValue: T): { current: T } {\n  return useMemoLike(name, () => ({ current: initialValue }), []);\n}\n\n/**\n * Returns a mutable ref object.\n *\n * @example\n *\n * ```ts\n * const ref = useRef(0);\n * ref.current = 1;\n * ```\n *\n * @template T The type of the ref object.\n * @param {T} initialValue The initial value of the ref object.\n * @returns {{ current: T }} The mutable ref object.\n */\n/* Returns a mutable ref object, see https://reactjs.org/docs/hooks-reference.html#useref */\nexport function useRef<T>(initialValue: T): { current: T } {\n  return useRefLike('useRef', initialValue);\n}\n\nfunction triggerUpdate() {\n  const hooks = getHooksContextOrNull();\n  // Rerun storyFn if updates were triggered synchronously, force rerender otherwise\n  if (hooks != null && hooks.currentPhase !== 'NONE') {\n    hooks.hasUpdates = true;\n  } else {\n    try {\n      addons.getChannel().emit(FORCE_RE_RENDER);\n    } catch (e) {\n      logger.warn('State updates of Storybook preview hooks work only in browser');\n    }\n  }\n}\n\nfunction useStateLike<S>(\n  name: string,\n  initialState: (() => S) | S\n): [S, (update: ((prevState: S) => S) | S) => void] {\n  const stateRef = useRefLike(\n    name,\n    // @ts-expect-error S type should never be function, but there's no way to tell that to TypeScript\n    typeof initialState === 'function' ? initialState() : initialState\n  );\n  const setState = (update: ((prevState: S) => S) | S) => {\n    // @ts-expect-error S type should never be function, but there's no way to tell that to TypeScript\n    stateRef.current = typeof update === 'function' ? update(stateRef.current) : update;\n    triggerUpdate();\n  };\n  return [stateRef.current, setState];\n}\n\n/**\n * Returns a stateful value and a function to update it.\n *\n * @example\n *\n * ```ts\n * const [count, setCount] = useState(0);\n * setCount(count + 1);\n * ```\n *\n * @template S The type of the state.\n * @param {(() => S) | S} initialState The initial state value or a function that returns the\n *   initial state value.\n * @returns {[S, (update: ((prevState: S) => S) | S) => void]} An array containing the current state\n *   value and a function to update it.\n */\nexport function useState<S>(\n  initialState: (() => S) | S\n): [S, (update: ((prevState: S) => S) | S) => void] {\n  return useStateLike('useState', initialState);\n}\n\n/**\n * Given a file name, creates an object with utilities to manage a log file. It creates a temporary\n * log file which you can manage with the returned functions. You can then decide whether to move\n * the log file to the users project, or remove it.\n *\n * @example\n *\n * ```tsx\n *   const initialState = { count: 0 };\n *\n *   function reducer(state, action) {\n *     switch (action.type) {\n *       case 'increment':\n *         return { count: state.count + 1 };\n *       case 'decrement':\n *         return { count: state.count - 1 };\n *       default:\n *         throw new Error();\n *       }\n *     }\n *   }\n *   function Counter() {\n *     const [state, dispatch] = useReducer(reducer, initialState);\n *     return (\n *       <>\n *         Count: {state.count}\n *           <button onClick={() => dispatch({ type: 'increment' })}>+</button>\n *           <button onClick={() => dispatch({ type: 'decrement' })}>-</button>\n *       </>\n *     );\n *   }\n * ```\n */\nexport function useReducer<S, A>(\n  reducer: (state: S, action: A) => S,\n  initialState: S\n): [S, (action: A) => void];\nexport function useReducer<S, I, A>(\n  reducer: (state: S, action: A) => S,\n  initialArg: I,\n  init: (initialArg: I) => S\n): [S, (action: A) => void];\nexport function useReducer<S, A>(\n  reducer: (state: S, action: A) => S,\n  initialArg: any,\n  init?: any\n): [S, (action: A) => void] {\n  const initialState: (() => S) | S = init != null ? () => init(initialArg) : initialArg;\n  const [state, setState] = useStateLike('useReducer', initialState);\n  const dispatch = (action: A) => setState((prevState) => reducer(prevState, action));\n  return [state, dispatch];\n}\n\n/**\n * Triggers a side effect, see https://reactjs.org/docs/hooks-reference.html#usestate Effects are\n * triggered synchronously after rendering the story\n *\n * @example\n *\n * ```ts\n * useEffect(() => {\n *   // Do something after rendering the story\n *   return () => {\n *     // Do something when the component unmounts or the effect is re-run\n *   };\n * }, [dependency1, dependency2]);\n * ```\n *\n * @param {() => (() => void) | void} create A function that creates the effect. It should return a\n *   cleanup function, or nothing.\n * @param {any[]} [deps] An optional array of dependencies. If any of the dependencies change, the\n *   effect will be re-run.\n * @returns {void}\n */\nexport function useEffect(create: () => (() => void) | void, deps?: any[]): void {\n  const hooks = getHooksContextOrThrow();\n  const effect = useMemoLike('useEffect', () => ({ create }), deps);\n  if (!hooks.currentEffects.includes(effect)) {\n    hooks.currentEffects.push(effect);\n  }\n}\n\nexport interface Listener {\n  (...args: any[]): void;\n}\n\nexport interface EventMap {\n  [eventId: string]: Listener;\n}\n\n/**\n * Subscribes to events emitted by the Storybook channel and returns a function to emit events.\n *\n * @example\n *\n * ```ts\n * // Subscribe to an event and emit it\n * const emit = useChannel({ 'my-event': (arg1, arg2) => console.log(arg1, arg2) });\n * emit('my-event', 'Hello', 'world!');\n * ```\n *\n * @param {EventMap} eventMap A map of event listeners to subscribe to.\n * @param {any[]} [deps=[]] An optional array of dependencies. If any of the dependencies change,\n *   the event listeners will be re-subscribed. Default is `[]`\n * @returns {(...args: any[]) => void} A function to emit events to the Storybook channel.\n */\nexport function useChannel(eventMap: EventMap, deps: any[] = []) {\n  const channel = addons.getChannel();\n\n  useEffect(() => {\n    Object.entries(eventMap).forEach(([type, listener]) => channel.on(type, listener));\n    return () => {\n      Object.entries(eventMap).forEach(([type, listener]) =>\n        channel.removeListener(type, listener)\n      );\n    };\n  }, [...Object.keys(eventMap), ...deps]);\n\n  return useCallback(channel.emit.bind(channel), [channel]);\n}\n\n/**\n * Returns the current story context, including the story's ID, parameters, and other metadata.\n *\n * @example\n *\n * ```ts\n * const { id, parameters } = useStoryContext();\n * console.log(`Current story ID: ${id}`);\n * console.log(`Current story parameters: ${JSON.stringify(parameters)}`);\n * ```\n *\n * @template TRenderer The type of the story's renderer.\n * @template TArgs The type of the story's args.\n * @returns {StoryContext<TRenderer>} The current story context.\n */\nexport function useStoryContext<\n  TRenderer extends Renderer,\n  TArgs extends Args = Args,\n>(): StoryContext<TRenderer> {\n  const { currentContext } = getHooksContextOrThrow<TRenderer, TArgs>();\n  if (currentContext == null) {\n    throw invalidHooksError();\n  }\n\n  return currentContext;\n}\n\n/**\n * Returns the value of a specific parameter for the current story, or a default value if the\n * parameter is not set.\n *\n * @example\n *\n * ```ts\n * // Retrieve the value of a parameter named \"myParam\"\n * const myParamValue = useParameter<string>('myParam', 'default value');\n * console.log(`The value of myParam is: ${myParamValue}`);\n * ```\n *\n * @template S The type of the parameter value.\n * @param {string} parameterKey The key of the parameter to retrieve.\n * @param {S} [defaultValue] An optional default value to return if the parameter is not set.\n * @returns {S | undefined} The value of the parameter, or the default value if the parameter is not\n *   set.\n */\nexport function useParameter<S>(parameterKey: string, defaultValue?: S): S | undefined {\n  const { parameters } = useStoryContext();\n  if (parameterKey) {\n    return parameters[parameterKey] ?? (defaultValue as S);\n  }\n  return undefined;\n}\n\n/**\n * Returns the current args for the story, and functions to update and reset them.\n *\n * @example\n *\n * ```ts\n * const [args, updateArgs, resetArgs] = useArgs<{ name: string; age: number }>();\n * console.log(`Current args: ${JSON.stringify(args)}`);\n * updateArgs({ name: 'John' });\n * resetArgs(['name']);\n * ```\n *\n * @template TArgs The type of the story's args.\n * @returns {[TArgs, (newArgs: Partial<TArgs>) => void, (argNames?: (keyof TArgs)[]) => void]} An\n *   array containing the current args, a function to update them, and a function to reset them.\n */\nexport function useArgs<TArgs extends Args = Args>(): [\n  TArgs,\n  (newArgs: Partial<TArgs>) => void,\n  (argNames?: (keyof TArgs)[]) => void,\n] {\n  const channel = addons.getChannel();\n  const { id: storyId, args } = useStoryContext<Renderer, TArgs>();\n\n  const updateArgs = useCallback(\n    (updatedArgs: Partial<TArgs>) => channel.emit(UPDATE_STORY_ARGS, { storyId, updatedArgs }),\n    [channel, storyId]\n  );\n\n  const resetArgs = useCallback(\n    (argNames?: (keyof TArgs)[]) => channel.emit(RESET_STORY_ARGS, { storyId, argNames }),\n    [channel, storyId]\n  );\n\n  return [args as TArgs, updateArgs, resetArgs];\n}\n\n/**\n * Returns the current global args for the story, and a function to update them.\n *\n * @example\n *\n * ```ts\n * const [globals, updateGlobals] = useGlobals();\n * console.log(`Current globals: ${JSON.stringify(globals)}`);\n * updateGlobals({ theme: 'dark' });\n * ```\n *\n * @returns {[Args, (newGlobals: Args) => void]} An array containing the current global args, and a\n *   function to update them.\n */\nexport function useGlobals(): [Args, (newGlobals: Args) => void] {\n  const channel = addons.getChannel();\n  const { globals } = useStoryContext();\n\n  const updateGlobals = useCallback(\n    (newGlobals: Args) => channel.emit(UPDATE_GLOBALS, { globals: newGlobals }),\n    [channel]\n  );\n\n  return [globals, updateGlobals];\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/addons/index.ts",
    "content": "export * from './main.ts';\nexport * from './hooks.ts';\nexport * from './make-decorator.ts';\nexport * from './storybook-channel-mock.ts';\n"
  },
  {
    "path": "code/core/src/preview-api/modules/addons/main.ts",
    "content": "import type { Channel } from 'storybook/internal/channels';\n\nimport { global } from '@storybook/global';\n\nimport { mockChannel } from './storybook-channel-mock.ts';\n\nexport class AddonStore {\n  constructor() {\n    this.promise = new Promise((res) => {\n      this.resolve = () => res(this.getChannel());\n    }) as Promise<Channel>;\n  }\n\n  private channel: Channel | undefined;\n\n  private promise: any;\n\n  private resolve: any;\n\n  getChannel = (): Channel => {\n    // this.channel should get overwritten by setChannel. If it wasn't called (e.g. in non-browser environment), set a mock instead.\n    if (!this.channel) {\n      const channel = mockChannel();\n      this.setChannel(channel);\n      return channel;\n    }\n\n    return this.channel;\n  };\n\n  ready = (): Promise<Channel> => this.promise;\n\n  hasChannel = (): boolean => !!this.channel;\n\n  setChannel = (channel: Channel): void => {\n    this.channel = channel;\n    this.resolve();\n  };\n}\n\n// Enforce addons store to be a singleton\nconst KEY = '__STORYBOOK_ADDONS_PREVIEW';\n\nfunction getAddonsStore(): AddonStore {\n  if (!global[KEY]) {\n    global[KEY] = new AddonStore();\n  }\n  return global[KEY];\n}\n\nexport const addons = getAddonsStore();\n"
  },
  {
    "path": "code/core/src/preview-api/modules/addons/make-decorator.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport type { Addon_StoryContext } from 'storybook/internal/types';\n\nimport { makeDecorator } from './make-decorator.ts';\n\n// Copy & paste from internal api: client-api/src/client_api\ntype DecoratorFn = (fn: any, context: Addon_StoryContext) => any;\n\nconst defaultDecorateStory = (getStory: any, decorators: DecoratorFn[]) =>\n  decorators.reduce(\n    (decorated, decorator) => (context: Addon_StoryContext) =>\n      decorator(() => decorated(context), context),\n    getStory\n  );\n\nconst baseContext = {\n  name: '',\n  kind: '',\n  parameters: {},\n};\n\ndescribe('makeDecorator', () => {\n  it('returns a decorator that passes parameters on the parameters argument', () => {\n    const wrapper = vi.fn();\n    const decorator = makeDecorator({ wrapper, name: 'test', parameterName: 'test' });\n    const story = vi.fn();\n    const decoratedStory = defaultDecorateStory(story, [decorator]);\n\n    const context = { kind: '', name: '', parameters: { test: 'test-val' } };\n    decoratedStory(context);\n\n    expect(wrapper).toHaveBeenCalledWith(expect.any(Function), context, { parameters: 'test-val' });\n  });\n\n  it('passes options added at decoration time', () => {\n    const wrapper = vi.fn();\n    const decorator = makeDecorator({ wrapper, name: 'test', parameterName: 'test' });\n    const story = vi.fn();\n    const options = 'test-val';\n    const decoratedStory = defaultDecorateStory(story, [decorator(options)]);\n\n    const context = { ...baseContext };\n    decoratedStory(context);\n\n    expect(wrapper).toHaveBeenCalledWith(expect.any(Function), context, { options: 'test-val' });\n  });\n\n  it('passes object options added at decoration time', () => {\n    const wrapper = vi.fn();\n    const decorator = makeDecorator({ wrapper, name: 'test', parameterName: 'test' });\n    const story = vi.fn();\n    const options = { test: 'val' };\n    const decoratedStory = defaultDecorateStory(story, [decorator(options)]);\n\n    const context = { ...baseContext };\n    decoratedStory(context);\n\n    expect(wrapper).toHaveBeenCalledWith(expect.any(Function), context, {\n      options: { test: 'val' },\n    });\n  });\n\n  it('passes multiple options added at decoration time', () => {\n    const wrapper = vi.fn();\n    const decorator = makeDecorator({ wrapper, name: 'test', parameterName: 'test' });\n    const story = vi.fn();\n    const options = ['test-val', 'test-val2'];\n    const decoratedStory = defaultDecorateStory(story, [decorator(...options)]);\n\n    const context = { ...baseContext };\n    decoratedStory(context);\n\n    expect(wrapper).toHaveBeenCalledWith(expect.any(Function), context, {\n      options: ['test-val', 'test-val2'],\n    });\n  });\n\n  it('passes multiple options including objects added at decoration time', () => {\n    const wrapper = vi.fn();\n    const decorator = makeDecorator({ wrapper, name: 'test', parameterName: 'test' });\n    const story = vi.fn();\n    const options = ['test-val', 'test-val2', { test: 'val' }];\n    const decoratedStory = defaultDecorateStory(story, [decorator(...options)]);\n\n    const context = { ...baseContext };\n    decoratedStory(context);\n\n    expect(wrapper).toHaveBeenCalledWith(expect.any(Function), context, {\n      options: ['test-val', 'test-val2', { test: 'val' }],\n    });\n  });\n\n  it('passes both options *and* parameters at the same time', () => {\n    const wrapper = vi.fn();\n    const decorator = makeDecorator({ wrapper, name: 'test', parameterName: 'test' });\n    const story = vi.fn();\n    const options = 'test-val';\n    const decoratedStory = defaultDecorateStory(story, [decorator(options)]);\n\n    const context = { ...baseContext, parameters: { test: 'test-val' } };\n    decoratedStory(context);\n\n    expect(wrapper).toHaveBeenCalledWith(expect.any(Function), context, {\n      options: 'test-val',\n      parameters: 'test-val',\n    });\n  });\n\n  it('passes nothing if neither are supplied', () => {\n    const wrapper = vi.fn();\n    const decorator = makeDecorator({ wrapper, name: 'test', parameterName: 'test' });\n    const story = vi.fn();\n    const decoratedStory = defaultDecorateStory(story, [decorator]);\n\n    const context = { ...baseContext };\n    decoratedStory(context);\n\n    expect(wrapper).toHaveBeenCalledWith(expect.any(Function), context, {});\n  });\n\n  it('calls the story directly if neither options or parameters are supplied and skipIfNoParametersOrOptions is true', () => {\n    const wrapper = vi.fn();\n    const decorator = makeDecorator({\n      wrapper,\n      name: 'test',\n      parameterName: 'test',\n      skipIfNoParametersOrOptions: true,\n    });\n    const story = vi.fn();\n    const decoratedStory = defaultDecorateStory(story, [decorator]);\n\n    const context = { ...baseContext };\n    decoratedStory(context);\n\n    expect(wrapper).not.toHaveBeenCalled();\n    expect(story).toHaveBeenCalled();\n  });\n\n  it('calls the story directly if the disable parameter is passed to the decorator', () => {\n    const wrapper = vi.fn();\n    const decorator = makeDecorator({\n      wrapper,\n      name: 'test',\n      parameterName: 'test',\n      skipIfNoParametersOrOptions: true,\n    });\n    const story = vi.fn();\n    const decoratedStory = defaultDecorateStory(story, [decorator]);\n\n    const context = { ...baseContext, parameters: { test: { disable: true } } };\n    decoratedStory(context);\n\n    expect(wrapper).not.toHaveBeenCalled();\n    expect(story).toHaveBeenCalled();\n  });\n\n  it('throws if options are added at storytime, if not allowed', () => {\n    const wrapper = vi.fn();\n    const decorator = makeDecorator({\n      wrapper,\n      name: 'test',\n      parameterName: 'test',\n    });\n    const options = 'test-val';\n    const story = vi.fn();\n    expect(() => decorator(options)(story)).toThrow(/not allowed/);\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/addons/make-decorator.ts",
    "content": "import type {\n  Addon_LegacyStoryFn,\n  Addon_StoryContext,\n  Addon_StoryWrapper,\n} from 'storybook/internal/types';\n\nexport type MakeDecoratorResult = (...args: any) => any;\n\nexport interface MakeDecoratorOptions {\n  name: string;\n  parameterName: string;\n  skipIfNoParametersOrOptions?: boolean;\n  wrapper: Addon_StoryWrapper;\n}\n\n/**\n * Creates a Storybook decorator function that can be used to wrap stories with additional\n * functionality.\n *\n * @example\n *\n * ```jsx\n * const myDecorator = makeDecorator({\n *   name: 'My Decorator',\n *   parameterName: 'myDecorator',\n *   wrapper: (storyFn, context, { options }) => {\n *     const { myOption } = options;\n *     <div style={{ backgroundColor: myOption }}>{storyFn()}</div>;\n *   },\n * });\n *\n * export const decorators = [myDecorator];\n * ```\n *\n * @param {MakeDecoratorOptions} options - The options for the decorator.\n * @param {string} options.name - The name of the decorator.\n * @param {string} options.parameterName - The name of the parameter that will be used to pass\n *   options to the decorator.\n * @param {Addon_StoryWrapper} options.wrapper - The function that will be used to wrap the story.\n * @param {boolean} [options.skipIfNoParametersOrOptions=false] - Whether to skip the decorator if\n *   no options or parameters are provided. Default is `false`\n * @returns {MakeDecoratorResult} A function that can be used as a Storybook decorator.\n */\nexport const makeDecorator = ({\n  name,\n  parameterName,\n  wrapper,\n  skipIfNoParametersOrOptions = false,\n}: MakeDecoratorOptions): MakeDecoratorResult => {\n  const decorator: any =\n    (options: object) => (storyFn: Addon_LegacyStoryFn, context: Addon_StoryContext) => {\n      const parameters = context.parameters && context.parameters[parameterName];\n\n      if (parameters && parameters.disable) {\n        return storyFn(context);\n      }\n\n      if (skipIfNoParametersOrOptions && !options && !parameters) {\n        return storyFn(context);\n      }\n\n      return wrapper(storyFn, context, {\n        options,\n        parameters,\n      });\n    };\n\n  return (...args: any) => {\n    // Used without options as .addDecorator(decorator)\n    if (typeof args[0] === 'function') {\n      return decorator()(...args);\n    }\n\n    return (...innerArgs: any): any => {\n      // Used as [.]addDecorator(decorator(options))\n      if (innerArgs.length > 1) {\n        // Used as [.]addDecorator(decorator(option1, option2))\n        if (args.length > 1) {\n          return decorator(args)(...innerArgs);\n        }\n        return decorator(...args)(...innerArgs);\n      }\n\n      throw new Error(\n        `Passing stories directly into ${name}() is not allowed,\n        instead use addDecorator(${name}) and pass options with the '${parameterName}' parameter`\n      );\n    };\n  };\n};\n"
  },
  {
    "path": "code/core/src/preview-api/modules/addons/storybook-channel-mock.ts",
    "content": "import { Channel } from 'storybook/internal/channels';\n\nexport function mockChannel() {\n  const transport = {\n    setHandler: () => {},\n    send: () => {},\n  };\n\n  return new Channel({ transport });\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/Preview.tsx",
    "content": "import type { Channel } from 'storybook/internal/channels';\nimport { deprecate, logger } from 'storybook/internal/client-logger';\nimport {\n  ARGTYPES_INFO_REQUEST,\n  ARGTYPES_INFO_RESPONSE,\n  type ArgTypesRequestPayload,\n  type ArgTypesResponsePayload,\n  CONFIG_ERROR,\n  FORCE_REMOUNT,\n  FORCE_RE_RENDER,\n  GLOBALS_UPDATED,\n  PREVIEW_INITIALIZED,\n  RESET_STORY_ARGS,\n  type RequestData,\n  type ResponseData,\n  SET_GLOBALS,\n  STORY_ARGS_UPDATED,\n  STORY_HOT_UPDATED,\n  STORY_INDEX_INVALIDATED,\n  UPDATE_GLOBALS,\n  UPDATE_STORY_ARGS,\n} from 'storybook/internal/core-events';\nimport type { CleanupCallback } from 'storybook/internal/csf';\nimport {\n  CalledPreviewMethodBeforeInitializationError,\n  MissingRenderToCanvasError,\n  StoryIndexFetchError,\n  StoryStoreAccessedBeforeInitializationError,\n} from 'storybook/internal/preview-errors';\nimport type {\n  Args,\n  Globals,\n  GlobalsUpdatedPayload,\n  ModuleImportFn,\n  PreparedStory,\n  ProjectAnnotations,\n  RenderContextCallbacks,\n  RenderToCanvas,\n  Renderer,\n  SetGlobalsPayload,\n  StoryId,\n  StoryIndex,\n  StoryRenderOptions,\n} from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { StoryStore } from '../../store.ts';\nimport { addons } from '../addons/index.ts';\nimport type { CsfDocsRender } from './render/CsfDocsRender.ts';\nimport type { MdxDocsRender } from './render/MdxDocsRender.ts';\nimport { StoryRender } from './render/StoryRender.ts';\n\nconst { fetch } = global;\n\nconst STORY_INDEX_PATH = './index.json';\n\nexport type MaybePromise<T> = Promise<T> | T;\n\nexport class Preview<TRenderer extends Renderer> {\n  protected storyStoreValue?: StoryStore<TRenderer>;\n\n  renderToCanvas?: RenderToCanvas<TRenderer>;\n\n  storyRenders: StoryRender<TRenderer>[] = [];\n\n  previewEntryError?: Error;\n\n  // While we wait for the index to load (note it may error for a while), we need to store the\n  // project annotations. Once the index loads, it is stored on the store and this will get unset.\n  private projectAnnotationsBeforeInitialization?: ProjectAnnotations<TRenderer>;\n\n  private beforeAllCleanup?: CleanupCallback | void;\n\n  protected storeInitializationPromise: Promise<void>;\n\n  protected resolveStoreInitializationPromise!: () => void;\n\n  protected rejectStoreInitializationPromise!: (err: Error) => void;\n\n  constructor(\n    public importFn: ModuleImportFn,\n\n    public getProjectAnnotations: () => MaybePromise<ProjectAnnotations<TRenderer>>,\n\n    protected channel: Channel = addons.getChannel(),\n\n    shouldInitialize = true\n  ) {\n    this.storeInitializationPromise = new Promise((resolve, reject) => {\n      this.resolveStoreInitializationPromise = resolve;\n      this.rejectStoreInitializationPromise = reject;\n    });\n\n    // Cannot await this in constructor, but if you want to await it, use `ready()`\n\n    // Cannot await this in constructor, but if you want to await it, use `ready()`\n    if (shouldInitialize) {\n      this.initialize();\n    }\n  }\n\n  // Create a proxy object for `__STORYBOOK_STORY_STORE__` and `__STORYBOOK_PREVIEW__.storyStore`\n  // That proxies through to the store once ready, and errors beforehand. This means we can set\n  // `__STORYBOOK_STORY_STORE__ = __STORYBOOK_PREVIEW__.storyStore` without having to wait, and\n  // similarly integrators can access the `storyStore` on the preview at any time, although\n  // it is considered deprecated and we will no longer allow access in 9.0\n  get storyStore() {\n    return new Proxy(\n      {},\n      {\n        get: (_, method) => {\n          if (this.storyStoreValue) {\n            deprecate('Accessing the Story Store is deprecated and will be removed in 9.0');\n            return this.storyStoreValue[method as keyof StoryStore<TRenderer>];\n          }\n\n          throw new StoryStoreAccessedBeforeInitializationError();\n        },\n      }\n    ) as StoryStore<TRenderer>;\n  }\n\n  // INITIALIZATION\n  protected async initialize() {\n    this.setupListeners();\n\n    try {\n      const projectAnnotations = await this.getProjectAnnotationsOrRenderError();\n      await this.runBeforeAllHook(projectAnnotations);\n      await this.initializeWithProjectAnnotations(projectAnnotations);\n      // eslint-disable-next-line compat/compat\n      const userAgent = globalThis?.navigator?.userAgent;\n      await this.channel.emit(PREVIEW_INITIALIZED, { userAgent });\n    } catch (err) {\n      this.rejectStoreInitializationPromise(err as Error);\n    }\n  }\n\n  ready() {\n    return this.storeInitializationPromise;\n  }\n\n  setupListeners() {\n    this.channel.on(STORY_INDEX_INVALIDATED, this.onStoryIndexChanged.bind(this));\n    this.channel.on(UPDATE_GLOBALS, this.onUpdateGlobals.bind(this));\n    this.channel.on(UPDATE_STORY_ARGS, this.onUpdateArgs.bind(this));\n    this.channel.on(ARGTYPES_INFO_REQUEST, this.onRequestArgTypesInfo.bind(this));\n    this.channel.on(RESET_STORY_ARGS, this.onResetArgs.bind(this));\n    this.channel.on(FORCE_RE_RENDER, this.onForceReRender.bind(this));\n    this.channel.on(FORCE_REMOUNT, this.onForceRemount.bind(this));\n    this.channel.on(STORY_HOT_UPDATED, this.onStoryHotUpdated.bind(this));\n  }\n\n  async getProjectAnnotationsOrRenderError(): Promise<ProjectAnnotations<TRenderer>> {\n    try {\n      const projectAnnotations = await this.getProjectAnnotations();\n\n      this.renderToCanvas = projectAnnotations.renderToCanvas;\n\n      if (!this.renderToCanvas) {\n        throw new MissingRenderToCanvasError();\n      }\n\n      return projectAnnotations;\n    } catch (err) {\n      // This is an error extracting the projectAnnotations (i.e. evaluating the previewEntries) and\n      // needs to be show to the user as a simple error\n      this.renderPreviewEntryError('Error reading preview.js:', err as Error);\n      throw err;\n    }\n  }\n\n  // If initialization gets as far as project annotations, this function runs.\n  async initializeWithProjectAnnotations(projectAnnotations: ProjectAnnotations<TRenderer>) {\n    this.projectAnnotationsBeforeInitialization = projectAnnotations;\n    try {\n      const storyIndex = await this.getStoryIndexFromServer();\n      return this.initializeWithStoryIndex(storyIndex);\n    } catch (err) {\n      this.renderPreviewEntryError('Error loading story index:', err as Error);\n      throw err;\n    }\n  }\n\n  async runBeforeAllHook(projectAnnotations: ProjectAnnotations<TRenderer>) {\n    try {\n      await this.beforeAllCleanup?.();\n      this.beforeAllCleanup = await projectAnnotations.beforeAll?.();\n    } catch (err) {\n      this.renderPreviewEntryError('Error in beforeAll hook:', err as Error);\n      throw err;\n    }\n  }\n\n  async getStoryIndexFromServer() {\n    const result = await fetch(STORY_INDEX_PATH);\n    if (result.status === 200) {\n      return result.json() as any as StoryIndex;\n    }\n\n    throw new StoryIndexFetchError({ text: await result.text() });\n  }\n\n  // If initialization gets as far as the story index, this function runs.\n  protected initializeWithStoryIndex(storyIndex: StoryIndex): void {\n    if (!this.projectAnnotationsBeforeInitialization) {\n      // This is a protected method and so shouldn't be called out of order by users\n      // eslint-disable-next-line local-rules/no-uncategorized-errors\n      throw new Error('Cannot call initializeWithStoryIndex until project annotations resolve');\n    }\n\n    this.storyStoreValue = new StoryStore(\n      storyIndex,\n      this.importFn,\n      this.projectAnnotationsBeforeInitialization\n    );\n    delete this.projectAnnotationsBeforeInitialization; // to avoid confusion\n\n    this.setInitialGlobals();\n\n    this.resolveStoreInitializationPromise();\n  }\n\n  async setInitialGlobals() {\n    this.emitGlobals();\n  }\n\n  emitGlobals() {\n    if (!this.storyStoreValue) {\n      throw new CalledPreviewMethodBeforeInitializationError({ methodName: 'emitGlobals' });\n    }\n\n    const payload: SetGlobalsPayload = {\n      globals: this.storyStoreValue.userGlobals.get() || {},\n      globalTypes: this.storyStoreValue.projectAnnotations.globalTypes || {},\n    };\n    this.channel.emit(SET_GLOBALS, payload);\n  }\n\n  // EVENT HANDLERS\n\n  // This happens when a config file gets reloaded\n  async onGetProjectAnnotationsChanged({\n    getProjectAnnotations,\n  }: {\n    getProjectAnnotations: () => MaybePromise<ProjectAnnotations<TRenderer>>;\n  }) {\n    delete this.previewEntryError;\n    this.getProjectAnnotations = getProjectAnnotations;\n\n    const projectAnnotations = await this.getProjectAnnotationsOrRenderError();\n    await this.runBeforeAllHook(projectAnnotations);\n\n    if (!this.storyStoreValue) {\n      await this.initializeWithProjectAnnotations(projectAnnotations);\n      return;\n    }\n\n    this.storyStoreValue.setProjectAnnotations(projectAnnotations);\n    this.emitGlobals();\n  }\n\n  async onStoryIndexChanged() {\n    delete this.previewEntryError;\n\n    // We haven't successfully set project annotations yet,\n    // we need to do that before we can do anything else.\n    if (!this.storyStoreValue && !this.projectAnnotationsBeforeInitialization) {\n      return;\n    }\n\n    try {\n      const storyIndex = await this.getStoryIndexFromServer();\n\n      // We've been waiting for the index to resolve, now it has, so we can continue\n      if (this.projectAnnotationsBeforeInitialization) {\n        this.initializeWithStoryIndex(storyIndex);\n        return;\n      }\n\n      // Update the store with the new stories.\n      await this.onStoriesChanged({ storyIndex });\n    } catch (err) {\n      this.renderPreviewEntryError('Error loading story index:', err as Error);\n      throw err;\n    }\n  }\n\n  // This happens when a glob gets HMR-ed\n  async onStoriesChanged({\n    importFn,\n    storyIndex,\n  }: {\n    importFn?: ModuleImportFn;\n    storyIndex?: StoryIndex;\n  }) {\n    if (!this.storyStoreValue) {\n      throw new CalledPreviewMethodBeforeInitializationError({ methodName: 'onStoriesChanged' });\n    }\n    await this.storyStoreValue.onStoriesChanged({ importFn, storyIndex });\n  }\n\n  async onUpdateGlobals({\n    globals: updatedGlobals,\n    currentStory,\n  }: {\n    globals: Globals;\n    currentStory?: PreparedStory<TRenderer>;\n  }) {\n    if (!this.storyStoreValue) {\n      await this.storeInitializationPromise;\n    }\n    if (!this.storyStoreValue) {\n      throw new CalledPreviewMethodBeforeInitializationError({ methodName: 'onUpdateGlobals' });\n    }\n\n    this.storyStoreValue.userGlobals.update(updatedGlobals);\n\n    if (currentStory) {\n      const { initialGlobals, storyGlobals, userGlobals, globals } =\n        this.storyStoreValue.getStoryContext(currentStory);\n      this.channel.emit(GLOBALS_UPDATED, {\n        initialGlobals,\n        userGlobals,\n        storyGlobals,\n        globals,\n      } satisfies GlobalsUpdatedPayload);\n    } else {\n      // If there is no known selected story (e.g. if we are in docs mode), the userGlobals\n      // are not overridden.\n      const { initialGlobals, globals } = this.storyStoreValue.userGlobals;\n      this.channel.emit(GLOBALS_UPDATED, {\n        initialGlobals,\n        userGlobals: globals,\n        storyGlobals: {},\n        globals,\n      } satisfies GlobalsUpdatedPayload);\n    }\n\n    await Promise.all(this.storyRenders.map((r) => r.rerender()));\n  }\n\n  async onUpdateArgs({ storyId, updatedArgs }: { storyId: StoryId; updatedArgs: Args }) {\n    if (!this.storyStoreValue) {\n      throw new CalledPreviewMethodBeforeInitializationError({ methodName: 'onUpdateArgs' });\n    }\n    this.storyStoreValue.args.update(storyId, updatedArgs);\n\n    await Promise.all(\n      this.storyRenders\n        .filter((r) => r.id === storyId && !r.renderOptions.forceInitialArgs)\n        .map((r) =>\n          // We only run the play function, with in a force remount.\n          // But when mount is destructured, the rendering happens inside of the play function.\n          r.story && r.story.usesMount ? r.remount() : r.rerender()\n        )\n    );\n\n    this.channel.emit(STORY_ARGS_UPDATED, {\n      storyId,\n      args: this.storyStoreValue.args.get(storyId),\n    });\n  }\n\n  async onRequestArgTypesInfo({ id, payload }: RequestData<ArgTypesRequestPayload>) {\n    try {\n      await this.storeInitializationPromise;\n      const story = await this.storyStoreValue?.loadStory(payload);\n      this.channel.emit(ARGTYPES_INFO_RESPONSE, {\n        id,\n        success: true,\n        payload: { argTypes: story?.argTypes || {} },\n        error: null,\n      } satisfies ResponseData<ArgTypesResponsePayload>);\n    } catch (e: any) {\n      this.channel.emit(ARGTYPES_INFO_RESPONSE, {\n        id,\n        success: false,\n        error: e?.message,\n      } satisfies ResponseData<ArgTypesResponsePayload>);\n    }\n  }\n\n  async onResetArgs({ storyId, argNames }: { storyId: string; argNames?: string[] }) {\n    if (!this.storyStoreValue) {\n      throw new CalledPreviewMethodBeforeInitializationError({ methodName: 'onResetArgs' });\n    }\n\n    // NOTE: we have to be careful here and avoid await-ing when updating a rendered's args.\n    // That's because below in `renderStoryToElement` we have also bound to this event and will\n    // render the story in the same tick.\n    // However, we can do that safely as the current story is available in `this.storyRenders`\n    const render = this.storyRenders.find((r) => r.id === storyId);\n    const story = render?.story || (await this.storyStoreValue.loadStory({ storyId }));\n\n    const argNamesToReset = argNames || [\n      ...new Set([\n        ...Object.keys(story.initialArgs),\n        ...Object.keys(this.storyStoreValue.args.get(storyId)),\n      ]),\n    ];\n\n    const updatedArgs = argNamesToReset.reduce((acc, argName) => {\n      acc[argName] = story.initialArgs[argName];\n      return acc;\n    }, {} as Partial<Args>);\n\n    await this.onUpdateArgs({ storyId, updatedArgs });\n  }\n\n  // ForceReRender does not include a story id, so we simply must\n  // re-render all stories in case they are relevant\n  async onForceReRender() {\n    await Promise.all(this.storyRenders.map((r) => r.rerender()));\n  }\n\n  async onForceRemount({ storyId }: { storyId: StoryId }) {\n    await Promise.all(this.storyRenders.filter((r) => r.id === storyId).map((r) => r.remount()));\n  }\n\n  async onStoryHotUpdated() {\n    await Promise.all(this.storyRenders.map((r) => r.cancelPlayFunction()));\n  }\n\n  // Used by docs to render a story to a given element\n  // Note this short-circuits the `prepare()` phase of the StoryRender,\n  // main to be consistent with the previous behaviour. In the future,\n  // we will change it to go ahead and load the story, which will end up being\n  // \"instant\", although async.\n  renderStoryToElement(\n    story: PreparedStory<TRenderer>,\n    element: TRenderer['canvasElement'],\n    callbacks: RenderContextCallbacks<TRenderer>,\n    options: StoryRenderOptions\n  ) {\n    if (!this.renderToCanvas || !this.storyStoreValue) {\n      throw new CalledPreviewMethodBeforeInitializationError({\n        methodName: 'renderStoryToElement',\n      });\n    }\n\n    const render = new StoryRender<TRenderer>(\n      this.channel,\n      this.storyStoreValue,\n      this.renderToCanvas,\n      callbacks,\n      story.id,\n      'docs',\n      options,\n      story\n    );\n    render.renderToElement(element);\n\n    this.storyRenders.push(render);\n\n    return async () => {\n      await this.teardownRender(render);\n    };\n  }\n\n  async teardownRender(\n    render: StoryRender<TRenderer> | CsfDocsRender<TRenderer> | MdxDocsRender<TRenderer>,\n    { viewModeChanged }: { viewModeChanged?: boolean } = {}\n  ) {\n    this.storyRenders = this.storyRenders.filter((r) => r !== render);\n    await render?.teardown?.({ viewModeChanged });\n  }\n\n  // API\n  async loadStory({ storyId }: { storyId: StoryId }) {\n    if (!this.storyStoreValue) {\n      throw new CalledPreviewMethodBeforeInitializationError({ methodName: 'loadStory' });\n    }\n\n    return this.storyStoreValue.loadStory({ storyId });\n  }\n\n  getStoryContext(story: PreparedStory<TRenderer>, { forceInitialArgs = false } = {}) {\n    if (!this.storyStoreValue) {\n      throw new CalledPreviewMethodBeforeInitializationError({ methodName: 'getStoryContext' });\n    }\n\n    return this.storyStoreValue.getStoryContext(story, { forceInitialArgs });\n  }\n\n  async extract(options?: { includeDocsOnly: boolean }) {\n    if (!this.storyStoreValue) {\n      throw new CalledPreviewMethodBeforeInitializationError({ methodName: 'extract' });\n    }\n\n    if (this.previewEntryError) {\n      throw this.previewEntryError;\n    }\n\n    await this.storyStoreValue.cacheAllCSFFiles();\n\n    return this.storyStoreValue.extract(options);\n  }\n\n  // UTILITIES\n\n  renderPreviewEntryError(reason: string, err: Error) {\n    this.previewEntryError = err;\n    logger.error(reason);\n    logger.error(err);\n    this.channel.emit(CONFIG_ERROR, err);\n  }\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/PreviewWeb.integration.test.ts",
    "content": "// @vitest-environment happy-dom\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport React from 'react';\n\nimport type { RenderContext } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { addons } from '../addons/index.ts';\nimport { PreviewWeb } from './PreviewWeb.tsx';\nimport {\n  componentOneExports,\n  emitter,\n  getProjectAnnotations,\n  importFn,\n  mockChannel,\n  storyIndex as mockStoryIndex,\n  projectAnnotations,\n  waitForRender,\n} from './PreviewWeb.mockdata.ts';\nimport { WebView } from './WebView.ts';\n\n// PreviewWeb.test mocks out all rendering\n//   - ie. from`renderToCanvas()` (stories) or`ReactDOM.render()` (docs) in.\n// This file lets them rip.\n\nvi.mock('storybook/internal/channels', async (importOriginal) => {\n  return {\n    ...(await importOriginal<typeof import('storybook/internal/channels')>()),\n    createBrowserChannel: () => mockChannel,\n  };\n});\nvi.mock('@storybook/addon-docs/blocks', async () => {\n  const { CodeOrSourceMdx } = await import('../../../../../addons/docs/src/blocks/blocks/mdx.tsx');\n  return {\n    Docs: vi.fn(() => 'Docs'),\n    CodeOrSourceMdx: CodeOrSourceMdx,\n    AnchorMdx: vi.fn(() => 'AnchorMdx'),\n    HeadersMdx: vi.fn(() => 'HeadersMdx'),\n  };\n});\nvi.mock('storybook/internal/client-logger');\nvi.mock('storybook/internal/components');\n\nvi.mock('storybook/internal/channels', async (importOriginal) => {\n  return {\n    ...(await importOriginal<typeof import('storybook/internal/channels')>()),\n    createBrowserChannel: () => mockChannel,\n  };\n});\nvi.mock('storybook/internal/client-logger', async (importOriginal) => {\n  return {\n    ...(await importOriginal<typeof import('storybook/internal/client-logger')>()),\n    createBrowserChannel: () => mockChannel,\n  };\n});\nvi.mock('storybook/internal/components', async (importOriginal) => {\n  return {\n    ...(await importOriginal<typeof import('storybook/internal/components')>()),\n    createBrowserChannel: () => mockChannel,\n  };\n});\n\nvi.mock('./WebView');\n\nconst { document } = global;\nvi.mock('@storybook/global', () => ({\n  global: {\n    ...globalThis,\n    history: { replaceState: vi.fn() },\n    document: {\n      createElement: globalThis.document.createElement.bind(globalThis.document),\n      location: {\n        pathname: 'pathname',\n        search: '?id=*',\n      },\n    },\n    fetch: async () => ({ status: 200, json: async () => mockStoryIndex }),\n  },\n}));\n\nbeforeEach(() => {\n  document.location.search = '';\n  mockChannel.emit.mockClear();\n  emitter.removeAllListeners();\n  componentOneExports.default.loaders[0].mockReset().mockImplementation(async () => ({ l: 7 }));\n  componentOneExports.default.parameters.docs.container.mockClear();\n  componentOneExports.a.play.mockReset();\n  projectAnnotations.renderToCanvas.mockReset();\n  projectAnnotations.render.mockClear();\n  projectAnnotations.decorators[0].mockClear();\n\n  // We need to import DocsRenderer async because MDX2 is ESM-only so we inline\n  // this in each of the async tests below to get it working in Jest\n  // projectAnnotations.parameters.docs.renderer = () => new DocsRenderer() as any;\n\n  addons.setChannel(mockChannel as any);\n\n  vi.mocked(WebView.prototype).prepareForDocs.mockReturnValue('docs-element' as any);\n  vi.mocked(WebView.prototype).prepareForStory.mockReturnValue('story-element' as any);\n});\n\n/**\n * Skipping this test, because it causes a cyclical dependency error, where core depends on docs &\n * blocks This was done to avoid a conflict in the CPC work, we should revisit this.\n */\ndescribe('PreviewWeb', { skip: true }, () => {\n  describe('initial render', () => {\n    it('renders story mode through the stack', async () => {\n      const { DocsRenderer } = await import('../../../../../addons/docs/src/index.ts');\n      projectAnnotations.parameters.docs.renderer = () => new DocsRenderer() as any;\n\n      projectAnnotations.renderToCanvas.mockImplementationOnce(({ storyFn }: RenderContext<any>) =>\n        storyFn()\n      );\n      document.location.search = '?id=component-one--a';\n      await new PreviewWeb(importFn, getProjectAnnotations).ready();\n\n      await waitForRender();\n\n      await vi.waitFor(() => {\n        expect(projectAnnotations.decorators[0]).toHaveBeenCalled();\n        expect(projectAnnotations.render).toHaveBeenCalled();\n      });\n    });\n\n    it('renders docs mode through docs page', async () => {\n      const { DocsRenderer } = await import('../../../../../addons/docs/src/index.ts');\n      projectAnnotations.parameters.docs.renderer = () => new DocsRenderer() as any;\n\n      document.location.search = '?id=component-one--docs&viewMode=docs';\n      const preview = new PreviewWeb(importFn, getProjectAnnotations);\n\n      const docsRoot = document.createElement('div');\n      vi.mocked(preview.view.prepareForDocs).mockReturnValue(docsRoot as any);\n      componentOneExports.default.parameters.docs.container.mockImplementationOnce(() =>\n        React.createElement('div', {}, 'INSIDE')\n      );\n\n      await preview.ready();\n\n      await vi.waitFor(\n        () => {\n          if (docsRoot.outerHTML !== '<div><div>INSIDE</div></div>') {\n            throw new Error('DocsRoot not ready yet');\n          }\n        },\n        {\n          timeout: 2000,\n        }\n      );\n\n      expect(docsRoot.outerHTML).toMatchInlineSnapshot('\"<div><div>INSIDE</div></div>\"');\n\n      // Extended timeout to try and avoid\n      // Error: Event was not emitted in time: storyRendered,docsRendered,storyThrewException,storyErrored,storyMissing\n    }, 10_000);\n\n    it('sends docs rendering exceptions to showException', async () => {\n      const { DocsRenderer } = await import('../../../../../addons/docs/src/index.ts');\n      projectAnnotations.parameters.docs.renderer = () => new DocsRenderer() as any;\n\n      document.location.search = '?id=component-one--docs&viewMode=docs';\n      const preview = new PreviewWeb(importFn, getProjectAnnotations);\n\n      const docsRoot = document.createElement('div');\n      vi.mocked(preview.view.prepareForDocs).mockReturnValue(docsRoot as any);\n      componentOneExports.default.parameters.docs.container.mockImplementation(() => {\n        throw new Error('Docs rendering error');\n      });\n\n      vi.mocked(preview.view.showErrorDisplay).mockClear();\n\n      await preview.ready();\n\n      await vi.waitFor(\n        () => {\n          expect(preview.view.showErrorDisplay).toHaveBeenCalled();\n        },\n        {\n          timeout: 2000,\n        }\n      );\n    });\n  });\n\n  describe('onGetGlobalMeta changed (HMR)', () => {\n    const newGlobalDecorator = vi.fn((s) => s());\n    const newGetProjectAnnotations = () => {\n      return {\n        ...projectAnnotations,\n        args: { a: 'second' },\n        globals: { a: 'second' },\n        decorators: [newGlobalDecorator],\n      };\n    };\n\n    it('renders story mode through the updated stack', async () => {\n      const { DocsRenderer } = await import('../../../../../addons/docs/src/index.ts');\n      projectAnnotations.parameters.docs.renderer = () => new DocsRenderer() as any;\n\n      document.location.search = '?id=component-one--a';\n      const preview = new PreviewWeb(importFn, getProjectAnnotations);\n      await preview.ready();\n      await waitForRender();\n\n      projectAnnotations.renderToCanvas.mockImplementationOnce(({ storyFn }: RenderContext<any>) =>\n        storyFn()\n      );\n      projectAnnotations.decorators[0].mockClear();\n      mockChannel.emit.mockClear();\n      preview.onGetProjectAnnotationsChanged({ getProjectAnnotations: newGetProjectAnnotations });\n\n      await vi.waitFor(() => {\n        expect(projectAnnotations.decorators[0]).not.toHaveBeenCalled();\n        expect(newGlobalDecorator).toHaveBeenCalled();\n        expect(projectAnnotations.render).toHaveBeenCalled();\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/PreviewWeb.mockdata.ts",
    "content": "import type { Mock, Mocked } from 'vitest';\nimport { vi } from 'vitest';\n\nimport {\n  DOCS_RENDERED,\n  STORY_ERRORED,\n  STORY_FINISHED,\n  STORY_MISSING,\n  STORY_RENDER_PHASE_CHANGED,\n  STORY_THREW_EXCEPTION,\n} from 'storybook/internal/core-events';\nimport type {\n  ModuleImportFn,\n  ProjectAnnotations,\n  Renderer,\n  StoryIndex,\n  TeardownRenderToCanvas,\n} from 'storybook/internal/types';\n\nimport { EventEmitter } from 'events';\n\nimport { Tag } from '../../../shared/constants/tags.ts';\nimport { composeConfigs } from '../store/index.ts';\nimport type { RenderPhase } from './render/StoryRender.ts';\n\nexport const componentOneExports = {\n  default: {\n    title: 'Component One',\n    argTypes: {\n      foo: { type: { name: 'string' } },\n      one: { name: 'one', type: { name: 'string' }, mapping: { 1: 'mapped-1' } },\n    },\n    loaders: [vi.fn()],\n    parameters: {\n      docs: { page: vi.fn(), container: vi.fn() },\n    },\n  },\n  a: { args: { foo: 'a', one: 1 }, play: vi.fn() },\n  b: { args: { foo: 'b', one: 1 }, play: vi.fn() },\n};\nexport const componentTwoExports = {\n  default: { title: 'Component Two' },\n  c: { args: { foo: 'c' } },\n};\nexport const attachedDocsExports = {\n  default: vi.fn(),\n};\nexport const unattachedDocsExports = {\n  default: vi.fn(),\n};\n// If a second file defines stories for componentOne\nexport const extraComponentOneExports = {\n  default: {\n    title: 'Component One',\n    parameters: {\n      docs: { page: vi.fn() },\n    },\n  },\n  e: {},\n};\nexport const importFn: Mocked<ModuleImportFn> = vi.fn(\n  async (path: string) =>\n    ({\n      './src/ComponentOne.stories.js': componentOneExports,\n      './src/ComponentOne.mdx': attachedDocsExports,\n      './src/ComponentTwo.stories.js': componentTwoExports,\n      './src/Introduction.mdx': unattachedDocsExports,\n      './src/ExtraComponentOne.stories.js': extraComponentOneExports,\n    })[path] || {}\n);\n\nexport const docsRenderer = {\n  render: vi.fn().mockImplementation((context, parameters, element) => Promise.resolve()),\n  unmount: vi.fn(),\n};\nexport const teardownrenderToCanvas: Mock<(teardown: TeardownRenderToCanvas) => void> = vi.fn();\nconst rawProjectAnnotations = {\n  initialGlobals: { a: 'b' },\n  globalTypes: {},\n  decorators: [vi.fn((s) => s())],\n  render: vi.fn(),\n  renderToCanvas: vi.fn().mockReturnValue(teardownrenderToCanvas),\n  parameters: { docs: { renderer: () => docsRenderer } },\n};\nexport const projectAnnotations = composeConfigs([\n  rawProjectAnnotations,\n]) as ProjectAnnotations<Renderer> & typeof rawProjectAnnotations;\n\nexport const getProjectAnnotations = vi.fn(() => projectAnnotations as any);\n\nexport const storyIndex: StoryIndex = {\n  v: 5,\n  entries: {\n    'component-one--docs': {\n      type: 'docs',\n      id: 'component-one--docs',\n      title: 'Component One',\n      name: 'Docs',\n      importPath: './src/ComponentOne.stories.js',\n      storiesImports: ['./src/ExtraComponentOne.stories.js'],\n      tags: [Tag.AUTODOCS, 'docs'],\n    },\n    'component-one--attached-docs': {\n      type: 'docs',\n      id: 'component-one--attached-docs',\n      title: 'Component One',\n      name: 'Attached Docs',\n      importPath: './src/ComponentOne.mdx',\n      storiesImports: ['./src/ComponentOne.stories.js'],\n      tags: [Tag.ATTACHED_MDX, 'docs'],\n    },\n    'component-one--a': {\n      type: 'story',\n      subtype: 'story',\n      id: 'component-one--a',\n      title: 'Component One',\n      name: 'A',\n      importPath: './src/ComponentOne.stories.js',\n    },\n    'component-one--b': {\n      type: 'story',\n      subtype: 'story',\n      id: 'component-one--b',\n      title: 'Component One',\n      name: 'B',\n      importPath: './src/ComponentOne.stories.js',\n    },\n    'component-one--e': {\n      type: 'story',\n      subtype: 'story',\n      id: 'component-one--e',\n      title: 'Component One',\n      name: 'E',\n      importPath: './src/ExtraComponentOne.stories.js',\n    },\n    'component-two--docs': {\n      type: 'docs',\n      id: 'component-two--docs',\n      title: 'Component Two',\n      name: 'Docs',\n      importPath: './src/ComponentTwo.stories.js',\n      storiesImports: [],\n      tags: [Tag.AUTODOCS, 'docs'],\n    },\n    'component-two--c': {\n      type: 'story',\n      subtype: 'story',\n      id: 'component-two--c',\n      title: 'Component Two',\n      name: 'C',\n      importPath: './src/ComponentTwo.stories.js',\n    },\n    'introduction--docs': {\n      type: 'docs',\n      id: 'introduction--docs',\n      title: 'Introduction',\n      name: 'Docs',\n      importPath: './src/Introduction.mdx',\n      storiesImports: ['./src/ComponentTwo.stories.js'],\n      tags: [Tag.UNATTACHED_MDX, 'docs'],\n    },\n  },\n};\nexport const getStoryIndex = () => storyIndex;\n\nexport const emitter = new EventEmitter();\nexport const mockChannel = {\n  on: emitter.on.bind(emitter),\n  off: emitter.off.bind(emitter),\n  removeListener: emitter.off.bind(emitter),\n  emit: vi.fn(emitter.emit.bind(emitter)),\n  // emit: emitter.emit.bind(emitter),\n};\n\nexport const waitForEvents = (\n  events: string[],\n  predicate: (...args: any[]) => boolean = () => true,\n  debugLabel?: string\n) => {\n  // We've already emitted a render event. NOTE if you want to test a second call,\n  // ensure you call `mockChannel.emit.mockClear()` before `waitFor...`\n  if (\n    mockChannel.emit.mock.calls.find(\n      (call: string[]) => events.includes(call[0]) && predicate(...call.slice(1))\n    )\n  ) {\n    return Promise.resolve(null);\n  }\n\n  return new Promise((resolve, reject) => {\n    const listener = (...args: any[]) => {\n      if (!predicate(...args)) {\n        return;\n      }\n      events.forEach((event) => mockChannel.off(event, listener));\n      resolve(null);\n    };\n    events.forEach((event) => mockChannel.on(event, listener));\n\n    // Don't wait too long\n    waitForQuiescence().then(() =>\n      reject(new Error(`Event was not emitted in time: ${debugLabel || events}`))\n    );\n  });\n};\n\n// The functions on the preview that trigger rendering don't wait for\n// the async parts, so we need to listen for the \"done\" events\nexport const waitForRender = () =>\n  waitForEvents([\n    DOCS_RENDERED,\n    STORY_FINISHED,\n    STORY_ERRORED,\n    STORY_MISSING,\n    STORY_THREW_EXCEPTION,\n  ]);\n\nexport const waitForRenderPhase = (phase: RenderPhase) => {\n  const label = `${STORY_RENDER_PHASE_CHANGED} to ${phase}`;\n  return waitForEvents([STORY_RENDER_PHASE_CHANGED], ({ newPhase }) => newPhase === phase, label);\n};\n\n// A little trick to ensure that we always call the real `setTimeout` even when timers are mocked\nconst realSetTimeout = setTimeout;\nexport const waitForQuiescence = async () => new Promise((r) => realSetTimeout(r, 1_000));\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/PreviewWeb.test.ts",
    "content": "// @vitest-environment happy-dom\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { logger } from 'storybook/internal/client-logger';\nimport {\n  CONFIG_ERROR,\n  CURRENT_STORY_WAS_SET,\n  DOCS_PREPARED,\n  DOCS_RENDERED,\n  FORCE_REMOUNT,\n  FORCE_RE_RENDER,\n  GLOBALS_UPDATED,\n  PLAY_FUNCTION_THREW_EXCEPTION,\n  PREVIEW_KEYDOWN,\n  RESET_STORY_ARGS,\n  SET_CURRENT_STORY,\n  SET_GLOBALS,\n  STORY_ARGS_UPDATED,\n  STORY_CHANGED,\n  STORY_ERRORED,\n  STORY_MISSING,\n  STORY_PREPARED,\n  STORY_RENDERED,\n  STORY_SPECIFIED,\n  STORY_THREW_EXCEPTION,\n  STORY_UNCHANGED,\n  UPDATE_GLOBALS,\n  UPDATE_STORY_ARGS,\n} from 'storybook/internal/core-events';\nimport type { ModuleImportFn, ProjectAnnotations, Renderer } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { toMerged } from 'es-toolkit/object';\n\nimport { addons } from '../addons/index.ts';\nimport type { StoryStore } from '../store/index.ts';\nimport { PreviewWeb } from './PreviewWeb.tsx';\nimport {\n  componentOneExports,\n  componentTwoExports,\n  docsRenderer,\n  emitter,\n  getProjectAnnotations,\n  importFn,\n  mockChannel,\n  projectAnnotations,\n  storyIndex,\n  teardownrenderToCanvas,\n  unattachedDocsExports,\n  waitForEvents,\n  waitForQuiescence,\n  waitForRender,\n  waitForRenderPhase,\n} from './PreviewWeb.mockdata.ts';\nimport { WebView } from './WebView.ts';\n\nconst { history, document } = global;\n\nconst mockStoryIndex = vi.fn(() => storyIndex);\n\nlet mockFetchResult: any;\nvi.mock('@storybook/global', async (importOriginal) => ({\n  global: {\n    ...(await importOriginal<typeof import('@storybook/global')>),\n    history: { replaceState: vi.fn() },\n    document: {\n      location: {\n        pathname: 'pathname',\n        search: '?id=*',\n      },\n    },\n    fetch: async () => mockFetchResult,\n  },\n}));\n\nvi.mock('storybook/internal/client-logger');\nvi.mock('react-dom');\nvi.mock('./WebView');\n\nconst serializeError = (error: Error) => {\n  const { name = 'Error', message = String(error), stack } = error;\n  return { name, message, stack };\n};\n\nconst createGate = (): [Promise<any | undefined>, (_?: any) => void] => {\n  let openGate = (_?: any) => {};\n  const gate = new Promise<any | undefined>((resolve) => {\n    openGate = resolve;\n  });\n  return [gate, openGate];\n};\n\nasync function waitForSetCurrentStory() {\n  await vi.waitFor(() => {\n    expect(mockChannel.emit).toHaveBeenCalledWith(CURRENT_STORY_WAS_SET, expect.anything());\n  });\n}\n\nasync function createAndRenderPreview({\n  importFn: inputImportFn = importFn,\n  getProjectAnnotations: inputGetProjectAnnotations = getProjectAnnotations,\n}: {\n  importFn?: ModuleImportFn;\n  getProjectAnnotations?: () => ProjectAnnotations<Renderer>;\n} = {}) {\n  const preview = new PreviewWeb(inputImportFn, inputGetProjectAnnotations);\n  await preview.ready();\n  await waitForRender();\n\n  return preview;\n}\n\nbeforeEach(() => {\n  document.location.search = '';\n  mockChannel.emit.mockClear();\n  emitter.removeAllListeners();\n  componentOneExports.default.loaders[0].mockReset().mockImplementation(async () => ({ l: 7 }));\n  componentOneExports.a.play.mockReset();\n  teardownrenderToCanvas.mockReset();\n  projectAnnotations.renderToCanvas.mockReset().mockReturnValue(teardownrenderToCanvas);\n  projectAnnotations.render.mockClear();\n  projectAnnotations.decorators[0].mockClear();\n  docsRenderer.render.mockClear();\n  vi.mocked(logger.warn).mockClear();\n\n  vi.mocked(console.error).mockReset();\n\n  mockStoryIndex.mockReset().mockReturnValue(storyIndex);\n\n  addons.setChannel(mockChannel as any);\n  mockFetchResult = { status: 200, json: mockStoryIndex, text: () => 'error text' };\n\n  vi.mocked(WebView.prototype).prepareForDocs.mockReturnValue('docs-element' as any);\n  vi.mocked(WebView.prototype).prepareForStory.mockReturnValue('story-element' as any);\n});\n\ndescribe('PreviewWeb', () => {\n  describe('ready', () => {\n    it('shows an error if getProjectAnnotations throws', async () => {\n      const err = new Error('meta error');\n      const preview = new PreviewWeb(importFn, () => {\n        throw err;\n      });\n      await expect(preview.ready()).rejects.toThrow(err);\n\n      expect(preview.view.showErrorDisplay).toHaveBeenCalled();\n      expect(mockChannel.emit).toHaveBeenCalledWith(CONFIG_ERROR, err);\n    });\n\n    it('shows an error if the stories.json endpoint 500s', async () => {\n      const err = new Error('sort error');\n      mockFetchResult = { status: 500, text: async () => err.toString() };\n\n      const preview = new PreviewWeb(importFn, getProjectAnnotations);\n      await expect(preview.ready()).rejects.toThrow('sort error');\n\n      expect(preview.view.showErrorDisplay).toHaveBeenCalled();\n      expect(mockChannel.emit).toHaveBeenCalledWith(CONFIG_ERROR, expect.any(Error));\n    });\n\n    it('sets globals from the URL', async () => {\n      document.location.search = '?id=*&globals=a:c';\n\n      const preview = await createAndRenderPreview();\n\n      // @ts-expect-error Ignore protected property\n      expect((preview.storyStoreValue as StoryStore<Renderer>)!.userGlobals.get()).toEqual(\n        expect.objectContaining({\n          a: 'c',\n        })\n      );\n    });\n\n    it('emits the SET_GLOBALS event', async () => {\n      await createAndRenderPreview();\n\n      expect(mockChannel.emit.mock.calls[0][1]).toMatchObject({\n        globals: { a: 'b' },\n        globalTypes: {},\n      });\n\n      expect(mockChannel.emit).toHaveBeenCalledWith(SET_GLOBALS, {\n        globals: expect.objectContaining({ a: 'b' }),\n        globalTypes: {},\n      });\n    });\n\n    it('SET_GLOBALS sets globals and types even when undefined', async () => {\n      await createAndRenderPreview({\n        getProjectAnnotations: () => ({ renderToCanvas: vi.fn() }),\n      });\n\n      expect(mockChannel.emit).toHaveBeenCalledWith(SET_GLOBALS, {\n        globals: expect.objectContaining({}),\n        globalTypes: {},\n      });\n    });\n\n    it('emits the SET_GLOBALS event from the URL', async () => {\n      document.location.search = '?id=*&globals=a:c';\n\n      await createAndRenderPreview();\n\n      expect(mockChannel.emit).toHaveBeenCalledWith(SET_GLOBALS, {\n        globals: expect.objectContaining({ a: 'c' }),\n        globalTypes: {},\n      });\n    });\n\n    it('sets args from the URL', async () => {\n      document.location.search = '?id=component-one--a&args=foo:url';\n\n      const preview = await createAndRenderPreview();\n\n      expect(\n        // @ts-expect-error Ignore protected property\n        (preview.storyStoreValue as StoryStore<Renderer>)?.args.get('component-one--a')\n      ).toEqual({\n        foo: 'url',\n        one: 1,\n      });\n    });\n\n    it('prepares story with args from the URL', async () => {\n      document.location.search = '?id=component-one--a&args=foo:url';\n\n      await createAndRenderPreview();\n\n      expect(mockChannel.emit).toHaveBeenCalledWith(\n        STORY_PREPARED,\n        expect.objectContaining({\n          id: 'component-one--a',\n          args: { foo: 'url', one: 1 },\n        })\n      );\n    });\n\n    it('allows async getProjectAnnotations', async () => {\n      const preview = new PreviewWeb(importFn, async () => {\n        return getProjectAnnotations();\n      });\n      await preview.ready();\n\n      // @ts-expect-error Ignore protected property\n      expect((preview.storyStoreValue as StoryStore<Renderer>)!.userGlobals.get()).toEqual(\n        expect.objectContaining({\n          a: 'b',\n        })\n      );\n    });\n  });\n\n  describe('initial selection', () => {\n    it('selects the story specified in the URL', async () => {\n      document.location.search = '?id=component-one--a';\n\n      const preview = await createAndRenderPreview();\n\n      expect(preview.selectionStore.selection).toEqual({\n        storyId: 'component-one--a',\n        viewMode: 'story',\n      });\n      expect(history.replaceState).toHaveBeenCalledWith(\n        {},\n        '',\n        'pathname?id=component-one--a&viewMode=story'\n      );\n    });\n\n    it('emits the STORY_SPECIFIED event', async () => {\n      document.location.search = '?id=component-one--a';\n\n      await createAndRenderPreview();\n\n      expect(mockChannel.emit).toHaveBeenCalledWith(STORY_SPECIFIED, {\n        storyId: 'component-one--a',\n        viewMode: 'story',\n      });\n    });\n\n    it('emits the CURRENT_STORY_WAS_SET event', async () => {\n      document.location.search = '?id=component-one--a';\n\n      await createAndRenderPreview();\n\n      expect(mockChannel.emit).toHaveBeenCalledWith(CURRENT_STORY_WAS_SET, {\n        storyId: 'component-one--a',\n        viewMode: 'story',\n      });\n    });\n\n    describe('when the first entry is a docs entry', () => {\n      it('emits the STORY_SPECIFIED event with viewMode=docs', async () => {\n        document.location.search = '?id=*';\n        await createAndRenderPreview();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_SPECIFIED, {\n          storyId: 'component-one--docs',\n          viewMode: 'docs',\n        });\n      });\n    });\n\n    describe('if the story specified does not exist', () => {\n      it('renders a loading error', async () => {\n        document.location.search = '?id=random';\n\n        const preview = await createAndRenderPreview();\n\n        expect(preview.view.showErrorDisplay).toHaveBeenCalled();\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_MISSING, 'random');\n      });\n\n      it('tries again with a specifier if CSF file changes', async () => {\n        document.location.search = '?id=component-one--missing';\n\n        const preview = await createAndRenderPreview();\n\n        expect(preview.view.showErrorDisplay).toHaveBeenCalled();\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_MISSING, 'component-one--missing');\n\n        mockChannel.emit.mockClear();\n        const newComponentOneExports = toMerged(componentOneExports, {\n          d: { args: { foo: 'd' }, play: vi.fn() },\n        });\n        const newImportFn = vi.fn(async (path) => {\n          return path === './src/ComponentOne.stories.js'\n            ? newComponentOneExports\n            : componentTwoExports;\n        });\n        preview.onStoriesChanged({\n          importFn: newImportFn,\n          storyIndex: {\n            v: 5,\n            entries: {\n              ...storyIndex.entries,\n              'component-one--missing': {\n                type: 'story',\n                subtype: 'story',\n                id: 'component-one--missing',\n                title: 'Component One',\n                name: 'D',\n                importPath: './src/ComponentOne.stories.js',\n              },\n            },\n          },\n        });\n        await waitForRender();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_SPECIFIED, {\n          storyId: 'component-one--missing',\n          viewMode: 'story',\n        });\n      });\n\n      describe('after selection changes', () => {\n        beforeEach(() => {\n          vi.useFakeTimers();\n        });\n        afterEach(() => {\n          vi.useRealTimers();\n        });\n\n        it('DOES NOT try again if CSF file changes', async () => {\n          document.location.search = '?id=component-one--missing';\n\n          const preview = await createAndRenderPreview();\n\n          expect(preview.view.showErrorDisplay).toHaveBeenCalled();\n          expect(mockChannel.emit).toHaveBeenCalledWith(STORY_MISSING, 'component-one--missing');\n\n          emitter.emit(SET_CURRENT_STORY, {\n            storyId: 'component-one--b',\n            viewMode: 'story',\n          });\n          await waitForSetCurrentStory();\n\n          const newComponentOneExports = toMerged(componentOneExports, {\n            d: { args: { foo: 'd' }, play: vi.fn() },\n          });\n          const newImportFn = vi.fn(async (path) => {\n            return path === './src/ComponentOne.stories.js'\n              ? newComponentOneExports\n              : componentTwoExports;\n          });\n\n          preview.onStoriesChanged({\n            importFn: newImportFn,\n            storyIndex: {\n              v: 5,\n              entries: {\n                ...storyIndex.entries,\n                'component-one--missing': {\n                  type: 'story',\n                  subtype: 'story',\n                  id: 'component-one--missing',\n                  title: 'Component One',\n                  name: 'D',\n                  importPath: './src/ComponentOne.stories.js',\n                },\n              },\n            },\n          });\n          expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_SPECIFIED, {\n            storyId: 'component-one--missing',\n            viewMode: 'story',\n          });\n        });\n      });\n    });\n\n    it('renders missing if no selection', async () => {\n      const preview = await createAndRenderPreview();\n\n      expect(preview.view.showNoPreview).toHaveBeenCalled();\n      expect(mockChannel.emit).toHaveBeenCalledWith(STORY_MISSING);\n    });\n\n    describe('story entries', () => {\n      it('calls view.prepareForStory', async () => {\n        document.location.search = '?id=component-one--a';\n\n        const preview = await createAndRenderPreview();\n\n        expect(preview.view.prepareForStory).toHaveBeenCalledWith(\n          expect.objectContaining({\n            id: 'component-one--a',\n          })\n        );\n      });\n\n      it('emits STORY_PREPARED', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_PREPARED, {\n          id: 'component-one--a',\n          parameters: {\n            __isArgsStory: false,\n            docs: expect.any(Object),\n            backgrounds: expect.any(Object),\n            fileName: './src/ComponentOne.stories.js',\n            throwPlayFunctionExceptions: false,\n          },\n          initialArgs: { foo: 'a', one: 1 },\n          argTypes: {\n            foo: { name: 'foo', type: { name: 'string' } },\n            one: { name: 'one', type: { name: 'string' }, mapping: { 1: 'mapped-1' } },\n          },\n          args: { foo: 'a', one: 1 },\n        });\n      });\n\n      it('emits GLOBALS_UPDATED with initial global values', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        await waitForEvents([GLOBALS_UPDATED]);\n        expect(mockChannel.emit).toHaveBeenCalledWith(GLOBALS_UPDATED, {\n          initialGlobals: expect.objectContaining({ a: 'b' }),\n          userGlobals: expect.objectContaining({ a: 'b' }),\n          storyGlobals: expect.objectContaining({}),\n          globals: expect.objectContaining({ a: 'b' }),\n        });\n      });\n\n      describe('if the story sets globals', () => {\n        it('emits GLOBALS_UPDATED with overridden storyGlobals', async () => {\n          document.location.search = '?id=component-one--a';\n          const newImportFn = vi.fn(async (path) => {\n            if (path === './src/ComponentOne.stories.js') {\n              return {\n                ...componentOneExports,\n                a: { ...componentOneExports.a, globals: { a: 'c' } },\n              };\n            }\n            return importFn(path);\n          });\n          await createAndRenderPreview({ importFn: newImportFn });\n\n          await waitForEvents([GLOBALS_UPDATED]);\n          expect(mockChannel.emit).toHaveBeenCalledWith(GLOBALS_UPDATED, {\n            initialGlobals: expect.objectContaining({ a: 'b' }),\n            userGlobals: expect.objectContaining({ a: 'b' }),\n            storyGlobals: expect.objectContaining({ a: 'c' }),\n            globals: expect.objectContaining({ a: 'c' }),\n          });\n        });\n      });\n\n      it('applies loaders with story context', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        expect(componentOneExports.default.loaders[0]).toHaveBeenCalledWith(\n          expect.objectContaining({\n            id: 'component-one--a',\n            parameters: {\n              __isArgsStory: false,\n              docs: expect.any(Object),\n              backgrounds: expect.any(Object),\n              fileName: './src/ComponentOne.stories.js',\n              throwPlayFunctionExceptions: false,\n            },\n            initialArgs: { foo: 'a', one: 1 },\n            argTypes: {\n              foo: { name: 'foo', type: { name: 'string' } },\n              one: { name: 'one', type: { name: 'string' }, mapping: { 1: 'mapped-1' } },\n            },\n            args: { foo: 'a', one: 'mapped-1' },\n          })\n        );\n      });\n\n      it('passes loaded context to renderToCanvas', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n          expect.objectContaining({\n            forceRemount: true,\n            storyContext: expect.objectContaining({\n              id: 'component-one--a',\n              parameters: expect.objectContaining({\n                __isArgsStory: false,\n                docs: expect.any(Object),\n                fileName: './src/ComponentOne.stories.js',\n              }),\n              globals: expect.objectContaining({ a: 'b' }),\n              initialArgs: { foo: 'a', one: 1 },\n              argTypes: {\n                foo: { name: 'foo', type: { name: 'string' } },\n                one: { name: 'one', type: { name: 'string' }, mapping: { 1: 'mapped-1' } },\n              },\n              args: { foo: 'a', one: 'mapped-1' },\n              loaded: { l: 7 },\n            }),\n          }),\n          'story-element'\n        );\n      });\n\n      it('renders exception if a loader throws', async () => {\n        const error = new Error('error');\n        componentOneExports.default.loaders[0].mockImplementationOnce(() => {\n          throw error;\n        });\n\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_THREW_EXCEPTION, serializeError(error));\n        expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error);\n      });\n\n      it('renders exception if renderToCanvas throws', async () => {\n        const error = new Error('error');\n        projectAnnotations.renderToCanvas.mockImplementation(() => {\n          throw error;\n        });\n\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_THREW_EXCEPTION, serializeError(error));\n        expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error);\n      });\n\n      it('renders helpful message if renderToCanvas is undefined', async () => {\n        document.location.search = '?id=component-one--a';\n\n        getProjectAnnotations.mockReturnValueOnce({\n          ...projectAnnotations,\n          renderToCanvas: undefined,\n        });\n        const preview = new PreviewWeb(importFn, getProjectAnnotations);\n        await expect(preview.ready()).rejects.toThrow();\n\n        expect(preview.view.showErrorDisplay).toHaveBeenCalled();\n        expect(vi.mocked(preview.view.showErrorDisplay).mock.calls[0][0]).toMatchInlineSnapshot(`\n          [SB_PREVIEW_API_0004 (MissingRenderToCanvasError): Expected your framework's preset to export a \\`renderToCanvas\\` field.\n\n          Perhaps it needs to be upgraded for Storybook 7.0?\n\n          More info: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#mainjs-framework-field\n          ]\n        `);\n      });\n\n      describe('when `throwPlayFunctionExceptions` is set to false', () => {\n        it('emits but does not render exception if the play function throws', async () => {\n          const error = new Error('error');\n          componentOneExports.a.play.mockImplementationOnce(() => {\n            throw error;\n          });\n\n          getProjectAnnotations.mockReturnValueOnce({\n            ...projectAnnotations,\n            parameters: {\n              ...projectAnnotations.parameters,\n              throwPlayFunctionExceptions: false,\n            },\n          });\n\n          document.location.search = '?id=component-one--a';\n          const preview = await createAndRenderPreview();\n\n          expect(mockChannel.emit).toHaveBeenCalledWith(\n            PLAY_FUNCTION_THREW_EXCEPTION,\n            serializeError(error)\n          );\n          expect(preview.view.showErrorDisplay).not.toHaveBeenCalled();\n          expect(mockChannel.emit).not.toHaveBeenCalledWith(\n            STORY_THREW_EXCEPTION,\n            serializeError(error)\n          );\n        });\n      });\n\n      describe('when `throwPlayFunctionExceptions` is set to true', () => {\n        it('emits AND renders exception if the play function throws', async () => {\n          const error = new Error('error');\n          componentOneExports.a.play.mockImplementationOnce(() => {\n            throw error;\n          });\n\n          getProjectAnnotations.mockReturnValueOnce({\n            ...projectAnnotations,\n            parameters: {\n              ...projectAnnotations.parameters,\n              throwPlayFunctionExceptions: true,\n            },\n          });\n\n          document.location.search = '?id=component-one--a';\n          const preview = await createAndRenderPreview();\n\n          expect(mockChannel.emit).toHaveBeenCalledWith(\n            PLAY_FUNCTION_THREW_EXCEPTION,\n            serializeError(error)\n          );\n          expect(preview.view.showErrorDisplay).toHaveBeenCalled();\n          expect(mockChannel.emit).toHaveBeenCalledWith(\n            STORY_THREW_EXCEPTION,\n            serializeError(error)\n          );\n        });\n      });\n\n      it('renders exception if the story calls showException', async () => {\n        const error = new Error('error');\n        projectAnnotations.renderToCanvas.mockImplementation((context) =>\n          context.showException(error)\n        );\n\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_THREW_EXCEPTION, serializeError(error));\n        expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error);\n      });\n\n      it('renders error if the story calls showError', async () => {\n        const error = { title: 'title', description: 'description' };\n        projectAnnotations.renderToCanvas.mockImplementation((context) => context.showError(error));\n\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ERRORED, error);\n        expect(preview.view.showErrorDisplay).toHaveBeenCalledWith({\n          message: error.title,\n          stack: error.description,\n        });\n      });\n\n      it('executes playFunction', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        expect(componentOneExports.a.play).toHaveBeenCalled();\n      });\n\n      it('emits STORY_RENDERED', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a');\n      });\n    });\n\n    describe('CSF docs entries', () => {\n      it('emits DOCS_PREPARED', async () => {\n        document.location.search = '?id=component-one--docs';\n        await createAndRenderPreview();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(DOCS_PREPARED, {\n          id: 'component-one--docs',\n          parameters: expect.objectContaining({\n            docs: expect.any(Object),\n            fileName: './src/ComponentOne.stories.js',\n          }),\n        });\n      });\n\n      it('always renders in docs viewMode', async () => {\n        document.location.search = '?id=component-one--docs';\n        await createAndRenderPreview();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(DOCS_RENDERED, 'component-one--docs');\n      });\n\n      it('calls view.prepareForDocs', async () => {\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n        const preview = await createAndRenderPreview();\n\n        expect(preview.view.prepareForDocs).toHaveBeenCalled();\n      });\n\n      it('renders with docs parameters from the first story', async () => {\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n        await createAndRenderPreview();\n\n        expect(docsRenderer.render).toHaveBeenCalledWith(\n          expect.any(Object),\n          expect.objectContaining({\n            page: componentOneExports.default.parameters.docs.page,\n            renderer: projectAnnotations.parameters.docs.renderer,\n          }),\n          'docs-element'\n        );\n      });\n\n      it('loads imports of the docs entry', async () => {\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n        await createAndRenderPreview();\n\n        expect(importFn).toHaveBeenCalledWith('./src/ExtraComponentOne.stories.js');\n      });\n\n      it('renders with componentStories loaded from the attached CSF file', async () => {\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n        await createAndRenderPreview();\n\n        const context = docsRenderer.render.mock.calls[0][0];\n\n        expect(context.componentStories().map((s: any) => s.id)).toEqual([\n          'component-one--a',\n          'component-one--b',\n          'component-one--e',\n        ]);\n      });\n\n      it('emits DOCS_RENDERED', async () => {\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n\n        await createAndRenderPreview();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(DOCS_RENDERED, 'component-one--docs');\n      });\n    });\n\n    describe('MDX docs entries', () => {\n      it('always renders in docs viewMode', async () => {\n        document.location.search = '?id=introduction--docs';\n        await createAndRenderPreview();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(DOCS_RENDERED, 'introduction--docs');\n      });\n\n      it('emits DOCS_PREPARED', async () => {\n        document.location.search = '?id=introduction--docs';\n        await createAndRenderPreview();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(DOCS_PREPARED, {\n          id: 'introduction--docs',\n          parameters: expect.objectContaining({\n            docs: expect.any(Object),\n          }),\n        });\n      });\n\n      describe('attached', () => {\n        it('emits DOCS_PREPARED with component parameters', async () => {\n          document.location.search = '?id=component-one--attached-docs';\n          await createAndRenderPreview();\n\n          expect(mockChannel.emit).toHaveBeenCalledWith(DOCS_PREPARED, {\n            id: 'component-one--attached-docs',\n            parameters: expect.objectContaining({\n              docs: expect.any(Object),\n              fileName: './src/ComponentOne.stories.js',\n            }),\n          });\n        });\n      });\n\n      it('calls view.prepareForDocs', async () => {\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n        const preview = await createAndRenderPreview();\n\n        expect(preview.view.prepareForDocs).toHaveBeenCalled();\n      });\n\n      it('renders with the generated docs parameters', async () => {\n        document.location.search = '?id=introduction--docs&viewMode=docs';\n        await createAndRenderPreview();\n\n        expect(docsRenderer.render).toHaveBeenCalledWith(\n          expect.any(Object),\n          expect.objectContaining({\n            page: unattachedDocsExports.default,\n            renderer: projectAnnotations.parameters.docs.renderer,\n          }),\n          'docs-element'\n        );\n      });\n\n      it('loads imports of the docs entry', async () => {\n        document.location.search = '?id=introduction--docs';\n        await createAndRenderPreview();\n\n        expect(importFn).toHaveBeenCalledWith('./src/ComponentTwo.stories.js');\n      });\n\n      it('emits DOCS_RENDERED', async () => {\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n\n        await createAndRenderPreview();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(DOCS_RENDERED, 'component-one--docs');\n      });\n    });\n  });\n\n  describe('onUpdateGlobals', () => {\n    beforeEach(() => {\n      mockChannel.emit.mockClear();\n      projectAnnotations.renderToCanvas.mockClear();\n    });\n\n    it('emits GLOBALS_UPDATED', async () => {\n      document.location.search = '?id=component-one--a';\n      await createAndRenderPreview();\n\n      emitter.emit(UPDATE_GLOBALS, { globals: { a: 'c' } });\n\n      await waitForEvents([GLOBALS_UPDATED]);\n      expect(mockChannel.emit).toHaveBeenCalledWith(GLOBALS_UPDATED, {\n        initialGlobals: expect.objectContaining({ a: 'b' }),\n        userGlobals: expect.objectContaining({ a: 'c' }),\n        storyGlobals: expect.objectContaining({}),\n        globals: expect.objectContaining({ a: 'c' }),\n      });\n    });\n\n    describe('if the story sets globals', () => {\n      const newImportFn = vi.fn(async (path) => {\n        if (path === './src/ComponentOne.stories.js') {\n          return {\n            ...componentOneExports,\n            a: { ...componentOneExports.a, globals: { a: 'c' } },\n          };\n        }\n        return importFn(path);\n      });\n\n      const newGetProjectAnnotations = vi.fn(\n        () => ({ ...projectAnnotations, initialGlobals: { a: 'b', c: 'd' } }) as any\n      );\n\n      it('allows changes to globals the story did not set', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview({\n          importFn: newImportFn,\n          getProjectAnnotations: newGetProjectAnnotations,\n        });\n\n        mockChannel.emit.mockClear();\n        emitter.emit(UPDATE_GLOBALS, { globals: { c: 'e' } });\n\n        await waitForEvents([GLOBALS_UPDATED]);\n        expect(mockChannel.emit).toHaveBeenCalledWith(GLOBALS_UPDATED, {\n          initialGlobals: expect.objectContaining({ a: 'b', c: 'd' }),\n          userGlobals: expect.objectContaining({ a: 'b', c: 'e' }),\n          storyGlobals: expect.objectContaining({ a: 'c' }),\n          globals: expect.objectContaining({ a: 'c', c: 'e' }),\n        });\n      });\n\n      it('does not allow changes to globals the story sets', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview({\n          importFn: newImportFn,\n          getProjectAnnotations: newGetProjectAnnotations,\n        });\n\n        mockChannel.emit.mockClear();\n        emitter.emit(UPDATE_GLOBALS, { globals: { a: 'e' } });\n\n        await waitForEvents([GLOBALS_UPDATED]);\n        expect(mockChannel.emit).toHaveBeenCalledWith(GLOBALS_UPDATED, {\n          initialGlobals: expect.objectContaining({ a: 'b', c: 'd' }),\n          userGlobals: expect.objectContaining({ a: 'e', c: 'd' }),\n          storyGlobals: expect.objectContaining({ a: 'c' }),\n          globals: expect.objectContaining({ a: 'c', c: 'd' }),\n        });\n      });\n    });\n\n    it('doet not allow new globals on the store', async () => {\n      document.location.search = '?id=component-one--a';\n      const preview = await createAndRenderPreview();\n\n      emitter.emit(UPDATE_GLOBALS, { globals: { foo: 'bar' } });\n\n      // @ts-expect-error Ignore protected property\n      expect((preview.storyStoreValue as StoryStore<Renderer>)!.userGlobals.get()).toEqual(\n        expect.objectContaining({\n          a: 'b',\n        })\n      );\n    });\n\n    it('passes globals in context to renderToCanvas', async () => {\n      document.location.search = '?id=component-one--a';\n      await createAndRenderPreview();\n\n      mockChannel.emit.mockClear();\n      projectAnnotations.renderToCanvas.mockClear();\n      emitter.emit(UPDATE_GLOBALS, { globals: { a: 'd' } });\n      await waitForRender();\n\n      expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n        expect.objectContaining({\n          forceRemount: false,\n          storyContext: expect.objectContaining({\n            globals: expect.objectContaining({ a: 'd' }),\n          }),\n        }),\n        'story-element'\n      );\n    });\n\n    it('emits STORY_RENDERED', async () => {\n      document.location.search = '?id=component-one--a';\n      await createAndRenderPreview();\n\n      mockChannel.emit.mockClear();\n      emitter.emit(UPDATE_GLOBALS, { globals: { a: 'c' } });\n      await waitForRender();\n\n      expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a');\n    });\n\n    describe('in docs mode', () => {\n      it('re-renders the docs container', async () => {\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n\n        await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        docsRenderer.render.mockClear();\n        emitter.emit(UPDATE_GLOBALS, { globals: { a: 'd' } });\n        await waitForEvents([GLOBALS_UPDATED]);\n\n        expect(docsRenderer.render).toHaveBeenCalled();\n      });\n    });\n  });\n\n  describe('onUpdateArgs', () => {\n    beforeEach(() => {\n      mockChannel.emit.mockClear();\n      projectAnnotations.renderToCanvas.mockClear();\n    });\n\n    it('emits STORY_ARGS_UPDATED', async () => {\n      document.location.search = '?id=component-one--a';\n      await createAndRenderPreview();\n\n      emitter.emit(UPDATE_STORY_ARGS, {\n        storyId: 'component-one--a',\n        updatedArgs: { new: 'arg', one: 1 },\n      });\n\n      await waitForEvents([STORY_ARGS_UPDATED]);\n      expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ARGS_UPDATED, {\n        storyId: 'component-one--a',\n        args: { foo: 'a', new: 'arg', one: 1 },\n      });\n    });\n\n    it('sets new args on the store', async () => {\n      document.location.search = '?id=component-one--a';\n      const preview = await createAndRenderPreview();\n\n      emitter.emit(UPDATE_STORY_ARGS, {\n        storyId: 'component-one--a',\n        updatedArgs: { new: 'arg' },\n      });\n\n      expect(\n        // @ts-expect-error Ignore protected property\n        (preview.storyStoreValue as StoryStore<Renderer> as StoryStore<Renderer>)?.args.get(\n          'component-one--a'\n        )\n      ).toEqual({\n        foo: 'a',\n        new: 'arg',\n        one: 1,\n      });\n    });\n\n    it('passes new args in context to renderToCanvas', async () => {\n      document.location.search = '?id=component-one--a';\n      await createAndRenderPreview();\n\n      mockChannel.emit.mockClear();\n      projectAnnotations.renderToCanvas.mockClear();\n      emitter.emit(UPDATE_STORY_ARGS, {\n        storyId: 'component-one--a',\n        updatedArgs: { new: 'arg' },\n      });\n      await waitForRender();\n\n      expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n        expect.objectContaining({\n          forceRemount: false,\n          storyContext: expect.objectContaining({\n            initialArgs: { foo: 'a', one: 1 },\n            args: { foo: 'a', new: 'arg', one: 'mapped-1' },\n          }),\n        }),\n        'story-element'\n      );\n    });\n\n    it('emits STORY_RENDERED', async () => {\n      document.location.search = '?id=component-one--a';\n      await createAndRenderPreview();\n\n      mockChannel.emit.mockClear();\n      emitter.emit(UPDATE_STORY_ARGS, {\n        storyId: 'component-one--a',\n        updatedArgs: { new: 'arg' },\n      });\n      await waitForRender();\n\n      expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a');\n    });\n\n    describe('if play function destructures mount', () => {\n      it('passes forceRemount to renderToCanvas', async () => {\n        document.location.search = '?id=component-one--a';\n        const newImportFn = vi.fn(async (path) => {\n          if (path === './src/ComponentOne.stories.js') {\n            return {\n              ...componentOneExports,\n              a: { ...componentOneExports.a, play: ({ mount }: any) => mount() },\n            };\n          }\n          return importFn(path);\n        });\n        await createAndRenderPreview({ importFn: newImportFn });\n\n        mockChannel.emit.mockClear();\n        projectAnnotations.renderToCanvas.mockClear();\n        emitter.emit(UPDATE_STORY_ARGS, {\n          storyId: 'component-one--a',\n          updatedArgs: { new: 'arg' },\n        });\n        await waitForRender();\n\n        expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n          expect.objectContaining({\n            forceRemount: true,\n            storyContext: expect.objectContaining({\n              initialArgs: { foo: 'a', one: 1 },\n              args: { foo: 'a', new: 'arg', one: 'mapped-1' },\n            }),\n          }),\n          'story-element'\n        );\n      });\n    });\n\n    describe('while story is still rendering', () => {\n      it('runs loaders again after renderToCanvas is done', async () => {\n        // Arrange - set up a gate to control when the loaders run\n        const [loadersRanGate, openLoadersRanGate] = createGate();\n        const [blockLoadersGate, openBlockLoadersGate] = createGate();\n\n        document.location.search = '?id=component-one--a';\n        componentOneExports.default.loaders[0].mockImplementationOnce(async (input) => {\n          openLoadersRanGate();\n          return blockLoadersGate;\n        });\n\n        // Act - render the first time\n        await new PreviewWeb(importFn, getProjectAnnotations).ready();\n        await loadersRanGate;\n\n        // Assert - loader to be called the first time\n        expect(componentOneExports.default.loaders[0]).toHaveBeenCalledOnce();\n        expect(componentOneExports.default.loaders[0]).toHaveBeenCalledWith(\n          expect.objectContaining({\n            args: { foo: 'a', one: 'mapped-1' },\n          })\n        );\n\n        // Act - update the args (while loader is still running)\n        emitter.emit(UPDATE_STORY_ARGS, {\n          storyId: 'component-one--a',\n          updatedArgs: { new: 'arg' },\n        });\n\n        // Arrange - open the gate to let the loader finish and wait for render\n        openBlockLoadersGate({ l: 8 });\n        await waitForRender();\n\n        // Assert - renderToCanvas to be called the first time with initial args and returned `loaded` value.\n        expect(projectAnnotations.renderToCanvas).toHaveBeenCalledOnce();\n        expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n          expect.objectContaining({\n            forceRemount: true,\n            storyContext: expect.objectContaining({\n              loaded: { l: 8 }, // This is the value returned by the *first* loader call\n              args: { foo: 'a', one: 'mapped-1' },\n            }),\n          }),\n          'story-element'\n        );\n        // Assert - loaders are not run again yet\n        expect(componentOneExports.default.loaders[0]).toHaveBeenCalledOnce();\n\n        // Arrange - wait for loading and rendering to finish a second time\n        mockChannel.emit.mockClear();\n        await waitForRender();\n        // Assert - loader is called a second time with updated args\n        await vi.waitFor(() => {\n          expect(projectAnnotations.renderToCanvas).toHaveBeenCalledTimes(2);\n          expect(componentOneExports.default.loaders[0]).toHaveBeenCalledWith(\n            expect.objectContaining({\n              args: { foo: 'a', new: 'arg', one: 'mapped-1' },\n            })\n          );\n        });\n\n        // Assert - renderToCanvas is called a second time with updated args\n        expect(projectAnnotations.renderToCanvas).toHaveBeenCalledTimes(2);\n        expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n          expect.objectContaining({\n            forceRemount: false,\n            storyContext: expect.objectContaining({\n              loaded: { l: 7 }, // This is the value returned by the *second* loader call\n              args: { foo: 'a', new: 'arg', one: 'mapped-1' },\n            }),\n          }),\n          'story-element'\n        );\n      });\n\n      it('renders a second time after the already running renderToCanvas is done', async () => {\n        const [gate, openGate] = createGate();\n\n        document.location.search = '?id=component-one--a';\n        projectAnnotations.renderToCanvas.mockImplementation(async () => gate);\n\n        await new PreviewWeb(importFn, getProjectAnnotations).ready();\n        await waitForRenderPhase('rendering');\n\n        emitter.emit(UPDATE_STORY_ARGS, {\n          storyId: 'component-one--a',\n          updatedArgs: { new: 'arg' },\n        });\n\n        // Now let the first renderToCanvas call resolve\n        openGate();\n        expect(projectAnnotations.renderToCanvas).toHaveBeenCalledTimes(1);\n        expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n          expect.objectContaining({\n            forceRemount: true,\n            storyContext: expect.objectContaining({\n              loaded: { l: 7 },\n              args: { foo: 'a', one: 'mapped-1' },\n            }),\n          }),\n          'story-element'\n        );\n\n        // Wait for the second render to finish\n        mockChannel.emit.mockClear();\n        await waitForRender();\n        await waitForRenderPhase('rendering');\n\n        // Expect the second render to have the updated args\n        expect(projectAnnotations.renderToCanvas).toHaveBeenCalledTimes(2);\n        expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n          expect.objectContaining({\n            forceRemount: false,\n            storyContext: expect.objectContaining({\n              loaded: { l: 7 },\n              args: { foo: 'a', new: 'arg', one: 'mapped-1' },\n            }),\n          }),\n          'story-element'\n        );\n      });\n\n      it('calls renderToCanvas again if play function is running', async () => {\n        const [gate, openGate] = createGate();\n        componentOneExports.a.play.mockImplementationOnce(async () => gate);\n\n        const renderToCanvasCalled = new Promise((resolve) => {\n          projectAnnotations.renderToCanvas.mockImplementation(() => {\n            resolve(null);\n          });\n        });\n\n        document.location.search = '?id=component-one--a';\n        await new PreviewWeb(importFn, getProjectAnnotations).ready();\n        await waitForRenderPhase('playing');\n\n        await renderToCanvasCalled;\n        // Story gets rendered with original args\n        expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n          expect.objectContaining({\n            forceRemount: true,\n            storyContext: expect.objectContaining({\n              loaded: { l: 7 },\n              args: { foo: 'a', one: 'mapped-1' },\n            }),\n          }),\n          'story-element'\n        );\n\n        emitter.emit(UPDATE_STORY_ARGS, {\n          storyId: 'component-one--a',\n          updatedArgs: { new: 'arg' },\n        });\n\n        // The second call should emit STORY_RENDERED\n        await waitForRender();\n\n        // Story gets rendered with updated args\n        expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n          expect.objectContaining({\n            forceRemount: false,\n            storyContext: expect.objectContaining({\n              loaded: { l: 7 },\n              args: { foo: 'a', new: 'arg', one: 'mapped-1' },\n            }),\n          }),\n          'story-element'\n        );\n\n        // Now let the playFunction call resolve\n        openGate();\n      });\n    });\n\n    describe('in docs mode', () => {\n      it('does not re-render the docs container', async () => {\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n\n        await createAndRenderPreview();\n\n        docsRenderer.render.mockClear();\n        mockChannel.emit.mockClear();\n        emitter.emit(UPDATE_STORY_ARGS, {\n          storyId: 'component-one--a',\n          updatedArgs: { new: 'arg' },\n        });\n        await waitForEvents([STORY_ARGS_UPDATED]);\n\n        expect(docsRenderer.render).not.toHaveBeenCalled();\n      });\n\n      describe('when renderStoryToElement was called', () => {\n        const callbacks = { showMain: vi.fn(), showError: vi.fn(), showException: vi.fn() };\n        it('re-renders the story', async () => {\n          document.location.search = '?id=component-one--docs&viewMode=docs';\n\n          const preview = await createAndRenderPreview();\n          await waitForRender();\n\n          mockChannel.emit.mockClear();\n          // @ts-expect-error Ignore protected property\n          const story = await (preview.storyStoreValue as StoryStore<Renderer>)?.loadStory({\n            storyId: 'component-one--a',\n          });\n          preview.renderStoryToElement(story, 'story-element' as any, callbacks, {});\n          await waitForRender();\n\n          expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n            expect.objectContaining({\n              storyContext: expect.objectContaining({\n                args: { foo: 'a', one: 'mapped-1' },\n              }),\n            }),\n            'story-element'\n          );\n\n          docsRenderer.render.mockClear();\n          mockChannel.emit.mockClear();\n          emitter.emit(UPDATE_STORY_ARGS, {\n            storyId: 'component-one--a',\n            updatedArgs: { new: 'arg' },\n          });\n          await waitForRender();\n\n          expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n            expect.objectContaining({\n              storyContext: expect.objectContaining({\n                args: { foo: 'a', new: 'arg', one: 'mapped-1' },\n              }),\n            }),\n            'story-element'\n          );\n        });\n\n        it('does not re-render the story when forceInitialArgs=true', async () => {\n          document.location.search = '?id=component-one--docs&viewMode=docs';\n\n          const preview = await createAndRenderPreview();\n          await waitForRender();\n\n          mockChannel.emit.mockClear();\n          // @ts-expect-error Ignore protected property\n          const story = await (preview.storyStoreValue as StoryStore<Renderer>)?.loadStory({\n            storyId: 'component-one--a',\n          });\n          preview.renderStoryToElement(story, 'story-element' as any, callbacks, {\n            forceInitialArgs: true,\n          });\n          await waitForRender();\n\n          expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n            expect.objectContaining({\n              storyContext: expect.objectContaining({\n                args: { foo: 'a', one: 'mapped-1' },\n              }),\n            }),\n            'story-element'\n          );\n\n          docsRenderer.render.mockClear();\n          mockChannel.emit.mockClear();\n          emitter.emit(UPDATE_STORY_ARGS, {\n            storyId: 'component-one--a',\n            updatedArgs: { new: 'arg' },\n          });\n          await waitForEvents([STORY_ARGS_UPDATED]);\n\n          // We don't re-render the story\n          await expect(waitForRender).rejects.toThrow();\n          expect(projectAnnotations.renderToCanvas).toHaveBeenCalledTimes(1);\n        });\n      });\n    });\n  });\n\n  describe('onPreloadStories', () => {\n    it('loads stories', async () => {\n      document.location.search = '?id=component-one--docs&viewMode=docs';\n      const preview = await createAndRenderPreview();\n      await waitForRender();\n\n      vi.mocked(importFn).mockClear();\n      await preview.onPreloadStories({ ids: ['component-two--c'] });\n      expect(importFn).toHaveBeenCalledWith('./src/ComponentTwo.stories.js');\n    });\n\n    it('loads legacy docs entries', async () => {\n      document.location.search = '?id=component-one--docs&viewMode=docs';\n      const preview = await createAndRenderPreview();\n      await waitForRender();\n\n      vi.mocked(importFn).mockClear();\n      await preview.onPreloadStories({ ids: ['component-one--docs'] });\n      expect(importFn).toHaveBeenCalledWith('./src/ComponentOne.stories.js');\n    });\n\n    it('loads modern docs entries', async () => {\n      document.location.search = '?id=component-one--docs&viewMode=docs';\n      const preview = await createAndRenderPreview();\n      await waitForRender();\n\n      vi.mocked(importFn).mockClear();\n      await preview.onPreloadStories({ ids: ['introduction--docs'] });\n      expect(importFn).toHaveBeenCalledWith('./src/Introduction.mdx');\n    });\n    it('loads imports of modern docs entries', async () => {\n      document.location.search = '?id=component-one--docs&viewMode=docs';\n      const preview = await createAndRenderPreview();\n      await waitForRender();\n\n      vi.mocked(importFn).mockClear();\n      await preview.onPreloadStories({ ids: ['introduction--docs'] });\n      expect(importFn).toHaveBeenCalledWith('./src/ComponentTwo.stories.js');\n    });\n  });\n\n  describe('onResetArgs', () => {\n    it('emits STORY_ARGS_UPDATED', async () => {\n      document.location.search = '?id=component-one--a';\n      await createAndRenderPreview();\n\n      mockChannel.emit.mockClear();\n      emitter.emit(UPDATE_STORY_ARGS, {\n        storyId: 'component-one--a',\n        updatedArgs: { foo: 'new' },\n      });\n\n      await waitForEvents([STORY_ARGS_UPDATED]);\n      expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ARGS_UPDATED, {\n        storyId: 'component-one--a',\n        args: { foo: 'new', one: 1 },\n      });\n\n      mockChannel.emit.mockClear();\n      emitter.emit(RESET_STORY_ARGS, {\n        storyId: 'component-one--a',\n        argNames: ['foo'],\n      });\n\n      await waitForEvents([STORY_ARGS_UPDATED]);\n\n      expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ARGS_UPDATED, {\n        storyId: 'component-one--a',\n        args: { foo: 'a', one: 1 },\n      });\n    });\n\n    it('resets a single arg', async () => {\n      document.location.search = '?id=component-one--a';\n      const preview = await createAndRenderPreview();\n      const onUpdateArgsSpy = vi.spyOn(preview, 'onUpdateArgs');\n\n      mockChannel.emit.mockClear();\n      emitter.emit(UPDATE_STORY_ARGS, {\n        storyId: 'component-one--a',\n        updatedArgs: { foo: 'new', new: 'value' },\n      });\n      await waitForEvents([STORY_ARGS_UPDATED]);\n\n      mockChannel.emit.mockClear();\n      emitter.emit(RESET_STORY_ARGS, {\n        storyId: 'component-one--a',\n        argNames: ['foo'],\n      });\n\n      await waitForRender();\n\n      expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n        expect.objectContaining({\n          forceRemount: false,\n          storyContext: expect.objectContaining({\n            initialArgs: { foo: 'a', one: 1 },\n            args: { foo: 'a', new: 'value', one: 'mapped-1' },\n          }),\n        }),\n        'story-element'\n      );\n\n      await waitForEvents([STORY_ARGS_UPDATED]);\n      expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ARGS_UPDATED, {\n        storyId: 'component-one--a',\n        args: { foo: 'a', new: 'value', one: 1 },\n      });\n\n      expect(onUpdateArgsSpy).toHaveBeenCalledWith({\n        storyId: 'component-one--a',\n        updatedArgs: { foo: 'a' },\n      });\n    });\n\n    it('resets all args after one is updated', async () => {\n      document.location.search = '?id=component-one--a';\n      const preview = await createAndRenderPreview();\n      const onUpdateArgsSpy = vi.spyOn(preview, 'onUpdateArgs');\n\n      emitter.emit(UPDATE_STORY_ARGS, {\n        storyId: 'component-one--a',\n        updatedArgs: { foo: 'new' },\n      });\n      await waitForEvents([STORY_ARGS_UPDATED]);\n\n      mockChannel.emit.mockClear();\n      emitter.emit(RESET_STORY_ARGS, {\n        storyId: 'component-one--a',\n      });\n\n      await waitForRender();\n\n      expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n        expect.objectContaining({\n          forceRemount: false,\n          storyContext: expect.objectContaining({\n            initialArgs: { foo: 'a', one: 1 },\n            args: { foo: 'a', one: 'mapped-1' },\n          }),\n        }),\n        'story-element'\n      );\n\n      await waitForEvents([STORY_ARGS_UPDATED]);\n      expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ARGS_UPDATED, {\n        storyId: 'component-one--a',\n        args: { foo: 'a', one: 1 },\n      });\n\n      expect(onUpdateArgsSpy).toHaveBeenCalledWith({\n        storyId: 'component-one--a',\n        updatedArgs: { foo: 'a', one: 1 },\n      });\n    });\n\n    it('resets all args', async () => {\n      document.location.search = '?id=component-one--a';\n      const preview = await createAndRenderPreview();\n      const onUpdateArgsSpy = vi.spyOn(preview, 'onUpdateArgs');\n\n      emitter.emit(UPDATE_STORY_ARGS, {\n        storyId: 'component-one--a',\n        updatedArgs: { foo: 'new', new: 'value' },\n      });\n      await waitForEvents([STORY_ARGS_UPDATED]);\n\n      mockChannel.emit.mockClear();\n      emitter.emit(RESET_STORY_ARGS, {\n        storyId: 'component-one--a',\n      });\n\n      await waitForRender();\n\n      expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n        expect.objectContaining({\n          forceRemount: false,\n          storyContext: expect.objectContaining({\n            initialArgs: { foo: 'a', one: 1 },\n            args: { foo: 'a', one: 'mapped-1' },\n          }),\n        }),\n        'story-element'\n      );\n\n      await waitForEvents([STORY_ARGS_UPDATED]);\n      expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ARGS_UPDATED, {\n        storyId: 'component-one--a',\n        args: { foo: 'a', one: 1 },\n      });\n\n      expect(onUpdateArgsSpy).toHaveBeenCalledWith({\n        storyId: 'component-one--a',\n        updatedArgs: { foo: 'a', new: undefined, one: 1 },\n      });\n    });\n\n    it('resets all args when one arg is undefined', async () => {\n      document.location.search = '?id=component-one--a';\n      const preview = await createAndRenderPreview();\n      const onUpdateArgsSpy = vi.spyOn(preview, 'onUpdateArgs');\n\n      emitter.emit(UPDATE_STORY_ARGS, {\n        storyId: 'component-one--a',\n        updatedArgs: { foo: undefined },\n      });\n      await waitForEvents([STORY_ARGS_UPDATED]);\n\n      mockChannel.emit.mockClear();\n      emitter.emit(RESET_STORY_ARGS, {\n        storyId: 'component-one--a',\n      });\n\n      await waitForRender();\n\n      expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n        expect.objectContaining({\n          forceRemount: false,\n          storyContext: expect.objectContaining({\n            initialArgs: { foo: 'a', one: 1 },\n            args: { foo: 'a', one: 'mapped-1' },\n          }),\n        }),\n        'story-element'\n      );\n\n      await waitForEvents([STORY_ARGS_UPDATED]);\n      expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ARGS_UPDATED, {\n        storyId: 'component-one--a',\n        args: { foo: 'a', one: 1 },\n      });\n\n      expect(onUpdateArgsSpy).toHaveBeenCalledWith({\n        storyId: 'component-one--a',\n        updatedArgs: { foo: 'a', one: 1 },\n      });\n    });\n  });\n\n  describe('on FORCE_RE_RENDER', () => {\n    it('rerenders the story with the same args', async () => {\n      document.location.search = '?id=component-one--a';\n      await createAndRenderPreview();\n\n      mockChannel.emit.mockClear();\n      projectAnnotations.renderToCanvas.mockClear();\n      emitter.emit(FORCE_RE_RENDER);\n      await waitForRender();\n\n      expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n        expect.objectContaining({ forceRemount: false }),\n        'story-element'\n      );\n    });\n  });\n\n  describe('on FORCE_REMOUNT', () => {\n    beforeEach(() => {\n      vi.useFakeTimers();\n    });\n    afterEach(() => {\n      vi.useRealTimers();\n    });\n\n    it('remounts the story with the same args', async () => {\n      document.location.search = '?id=component-one--a';\n      await createAndRenderPreview();\n\n      mockChannel.emit.mockClear();\n      projectAnnotations.renderToCanvas.mockClear();\n      emitter.emit(FORCE_REMOUNT, { storyId: 'component-one--a' });\n      await waitForRender();\n\n      expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n        expect.objectContaining({ forceRemount: true }),\n        'story-element'\n      );\n    });\n\n    it('aborts render function for initial story', async () => {\n      const [gate, openGate] = createGate();\n\n      document.location.search = '?id=component-one--a';\n      projectAnnotations.renderToCanvas.mockImplementation(async () => gate);\n      await new PreviewWeb(importFn, getProjectAnnotations).ready();\n      await waitForRenderPhase('rendering');\n\n      expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n        expect.objectContaining({\n          forceRemount: true,\n          storyContext: expect.objectContaining({\n            id: 'component-one--a',\n            loaded: { l: 7 },\n          }),\n        }),\n        'story-element'\n      );\n\n      mockChannel.emit.mockClear();\n      emitter.emit(FORCE_REMOUNT, { storyId: 'component-one--a' });\n\n      // Now let the renderToCanvas call resolve\n      openGate();\n      await waitForRenderPhase('aborted');\n\n      // allow teardown to complete its retries\n      vi.runOnlyPendingTimers();\n\n      await waitForRenderPhase('rendering');\n      expect(projectAnnotations.renderToCanvas).toHaveBeenCalledTimes(2);\n\n      await waitForRenderPhase('playing');\n      expect(componentOneExports.a.play).toHaveBeenCalledTimes(1);\n\n      await waitForRenderPhase('completed');\n      expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a');\n\n      await waitForQuiescence();\n    });\n  });\n\n  describe('onSetCurrentStory', () => {\n    beforeEach(() => {\n      vi.useFakeTimers();\n    });\n    afterEach(() => {\n      vi.useRealTimers();\n    });\n\n    it('updates URL', async () => {\n      document.location.search = '?id=component-one--a';\n      await createAndRenderPreview();\n\n      emitter.emit(SET_CURRENT_STORY, {\n        storyId: 'component-one--b',\n        viewMode: 'story',\n      });\n      await waitForSetCurrentStory();\n\n      expect(history.replaceState).toHaveBeenCalledWith(\n        {},\n        '',\n        'pathname?id=component-one--b&viewMode=story'\n      );\n    });\n\n    it('emits CURRENT_STORY_WAS_SET', async () => {\n      document.location.search = '?id=component-one--a';\n      await createAndRenderPreview();\n\n      emitter.emit(SET_CURRENT_STORY, {\n        storyId: 'component-one--b',\n        viewMode: 'story',\n      });\n      await vi.waitFor(() => {\n        expect(mockChannel.emit).toHaveBeenCalledWith(CURRENT_STORY_WAS_SET, {\n          storyId: 'component-one--b',\n          viewMode: 'story',\n        });\n      });\n\n      expect(mockChannel.emit).toHaveBeenCalledWith(CURRENT_STORY_WAS_SET, {\n        storyId: 'component-one--b',\n        viewMode: 'story',\n      });\n    });\n\n    it('renders loading error if the story specified does not exist', async () => {\n      document.location.search = '?id=component-one--a';\n      const preview = await createAndRenderPreview();\n\n      emitter.emit(SET_CURRENT_STORY, {\n        storyId: 'random',\n        viewMode: 'story',\n      });\n      await waitForSetCurrentStory();\n\n      await waitForEvents([STORY_MISSING]);\n      expect(preview.view.showErrorDisplay).toHaveBeenCalled();\n      expect(mockChannel.emit).toHaveBeenCalledWith(STORY_MISSING, 'random');\n    });\n\n    describe('if called before the preview is readyd', () => {\n      it('works when there was no selection specifier', async () => {\n        document.location.search = '';\n        // We intentionally are *not* awaiting here\n        new PreviewWeb(importFn, getProjectAnnotations).ready();\n\n        emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story' });\n\n        await waitForEvents([STORY_RENDERED]);\n\n        // Check we don't render the default \"story missing\" UI / emit the default message\n        expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_MISSING);\n\n        // We of course should emit for the selected story\n        expect(mockChannel.emit).toHaveBeenCalledWith(CURRENT_STORY_WAS_SET, {\n          storyId: 'component-one--b',\n          viewMode: 'story',\n        });\n        expect(history.replaceState).toHaveBeenCalledWith(\n          {},\n          '',\n          'pathname?id=component-one--b&viewMode=story'\n        );\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--b');\n      });\n\n      it('works when there was a selection specifier', async () => {\n        document.location.search = '?id=component-one--a';\n\n        const readyd = new PreviewWeb(importFn, getProjectAnnotations).ready();\n\n        emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story' });\n\n        await readyd;\n        await waitForEvents([STORY_RENDERED]);\n\n        // If we emitted CURRENT_STORY_WAS_SET for the original selection, the manager might\n        // get confused, so check that we don't\n        expect(mockChannel.emit).not.toHaveBeenCalledWith(CURRENT_STORY_WAS_SET, {\n          storyId: 'component-one--a',\n          viewMode: 'story',\n        });\n        // Double check this doesn't happen either\n        expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_MISSING);\n\n        expect(history.replaceState).toHaveBeenCalledWith(\n          {},\n          '',\n          'pathname?id=component-one--b&viewMode=story'\n        );\n        expect(mockChannel.emit).toHaveBeenCalledWith(CURRENT_STORY_WAS_SET, {\n          storyId: 'component-one--b',\n          viewMode: 'story',\n        });\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--b');\n      });\n    });\n\n    describe('if called on a storybook without selection', () => {\n      it('sets viewMode to story by default', async () => {\n        await createAndRenderPreview();\n\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--b',\n        });\n        await waitForSetCurrentStory();\n\n        expect(history.replaceState).toHaveBeenCalledWith(\n          {},\n          '',\n          'pathname?id=component-one--b&viewMode=story'\n        );\n      });\n    });\n\n    describe('if the selection is unchanged', () => {\n      it('emits STORY_UNCHANGED', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--a',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n\n        await waitForEvents([STORY_UNCHANGED]);\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_UNCHANGED, 'component-one--a');\n      });\n\n      it('does NOT call renderToCanvas', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        projectAnnotations.renderToCanvas.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--a',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n\n        // The renderToCanvas would have been async so we need to wait a tick.\n        await waitForQuiescence();\n        expect(projectAnnotations.renderToCanvas).not.toHaveBeenCalled();\n      });\n\n      it('does NOT call renderToCanvas teardown', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        projectAnnotations.renderToCanvas.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--a',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n\n        expect(teardownrenderToCanvas).not.toHaveBeenCalled();\n      });\n\n      describe('while preparing', () => {\n        // For https://github.com/storybookjs/storybook/issues/17214\n        it('does NOT render a second time in story mode', async () => {\n          document.location.search = '?id=component-one--a';\n\n          const [gate, openGate] = createGate();\n          const [importedGate, openImportedGate] = createGate();\n          importFn\n            // @ts-expect-error (mock)\n            .mockImplementationOnce(async (m) => {\n              await gate;\n              return importFn(m);\n            })\n            // @ts-expect-error (mock)\n            .mockImplementationOnce(async (m) => {\n              // The second time we `import()` we open the \"imported\" gate\n              openImportedGate();\n              await gate;\n              return importFn(m);\n            });\n\n          const preview = new PreviewWeb(importFn, getProjectAnnotations);\n          // We can't wait for the ready function, as it waits for `renderSelection()`\n          // which prepares, but it does emit `CURRENT_STORY_WAS_SET` right before that\n          preview.ready();\n          await waitForEvents([CURRENT_STORY_WAS_SET]);\n\n          mockChannel.emit.mockClear();\n          projectAnnotations.renderToCanvas.mockClear();\n          emitter.emit(SET_CURRENT_STORY, {\n            storyId: 'component-one--a',\n            viewMode: 'story',\n          });\n          await importedGate;\n          // We are blocking import so this won't render yet\n          expect(projectAnnotations.renderToCanvas).not.toHaveBeenCalled();\n\n          mockChannel.emit.mockClear();\n          openGate();\n          await waitForRender();\n\n          // We should only render *once*\n          expect(projectAnnotations.renderToCanvas).toHaveBeenCalledTimes(1);\n\n          // We should not show an error either\n          expect(preview.view.showErrorDisplay).not.toHaveBeenCalled();\n        });\n\n        // For https://github.com/storybookjs/storybook/issues/19015\n        it('does NOT render a second time in template docs mode', async () => {\n          document.location.search = '?id=component-one--docs&viewMode=docs';\n\n          const [gate, openGate] = createGate();\n          const [importedGate, openImportedGate] = createGate();\n          importFn\n            // @ts-expect-error (mock)\n            .mockImplementationOnce(async (m) => {\n              await gate;\n              return importFn(m);\n            })\n            // @ts-expect-error (mock)\n            .mockImplementationOnce(async (m) => {\n              // The second time we `import()` we open the \"imported\" gate\n              openImportedGate();\n              await gate;\n              return importFn(m);\n            });\n\n          const preview = new PreviewWeb(importFn, getProjectAnnotations);\n          // We can't wait for the ready function, as it waits for `renderSelection()`\n          // which prepares, but it does emit `CURRENT_STORY_WAS_SET` right before that\n          preview.ready();\n          await waitForEvents([CURRENT_STORY_WAS_SET]);\n\n          mockChannel.emit.mockClear();\n          projectAnnotations.renderToCanvas.mockClear();\n          emitter.emit(SET_CURRENT_STORY, {\n            storyId: 'component-one--docs',\n            viewMode: 'docs',\n          });\n          await importedGate;\n          // We are blocking import so this won't render yet\n          expect(docsRenderer.render).not.toHaveBeenCalled();\n\n          mockChannel.emit.mockClear();\n          openGate();\n          await waitForRender();\n\n          // We should only render *once*\n          expect(docsRenderer.render).toHaveBeenCalledTimes(1);\n\n          // We should not show an error either\n          expect(preview.view.showErrorDisplay).not.toHaveBeenCalled();\n        });\n\n        it('does NOT render a second time in mdx docs mode', async () => {\n          document.location.search = '?id=introduction--docs&viewMode=docs';\n\n          const [gate, openGate] = createGate();\n          const [importedGate, openImportedGate] = createGate();\n          importFn\n            // @ts-expect-error (mock)\n            .mockImplementationOnce(async (m) => {\n              await gate;\n              return importFn(m);\n            })\n            // @ts-expect-error (mock)\n            .mockImplementationOnce(async (m) => {\n              // The second time we `import()` we open the \"imported\" gate\n              openImportedGate();\n              await gate;\n              return importFn(m);\n            });\n\n          const preview = new PreviewWeb(importFn, getProjectAnnotations);\n          // We can't wait for the ready function, as it waits for `renderSelection()`\n          // which prepares, but it does emit `CURRENT_STORY_WAS_SET` right before that\n          preview.ready();\n          await waitForEvents([CURRENT_STORY_WAS_SET]);\n\n          mockChannel.emit.mockClear();\n          projectAnnotations.renderToCanvas.mockClear();\n          emitter.emit(SET_CURRENT_STORY, {\n            storyId: 'introduction--docs',\n            viewMode: 'docs',\n          });\n          await importedGate;\n          // We are blocking import so this won't render yet\n          expect(docsRenderer.render).not.toHaveBeenCalled();\n\n          mockChannel.emit.mockClear();\n          openGate();\n          await waitForRender();\n\n          // We should only render *once*\n          expect(docsRenderer.render).toHaveBeenCalledTimes(1);\n\n          // We should not show an error either\n          expect(preview.view.showErrorDisplay).not.toHaveBeenCalled();\n        });\n      });\n    });\n\n    describe('when changing story in story viewMode', () => {\n      it('calls renderToCanvas teardown', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        projectAnnotations.renderToCanvas.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--b',\n          viewMode: 'story',\n        });\n\n        await vi.waitFor(() => {\n          expect(teardownrenderToCanvas).toHaveBeenCalled();\n        });\n      });\n\n      it('updates URL', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--b',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n\n        expect(history.replaceState).toHaveBeenCalledWith(\n          {},\n          '',\n          'pathname?id=component-one--b&viewMode=story'\n        );\n      });\n\n      it('renders preparing state', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--b',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n\n        expect(preview.view.showPreparingStory).toHaveBeenCalled();\n      });\n\n      it('emits STORY_CHANGED', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--b',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n\n        await waitForEvents([STORY_CHANGED]);\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_CHANGED, 'component-one--b');\n      });\n\n      it('emits STORY_PREPARED', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--b',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n\n        await waitForEvents([STORY_PREPARED]);\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_PREPARED, {\n          id: 'component-one--b',\n          parameters: expect.objectContaining({\n            __isArgsStory: false,\n            docs: expect.any(Object),\n            fileName: './src/ComponentOne.stories.js',\n          }),\n          initialArgs: { foo: 'b', one: 1 },\n          argTypes: {\n            foo: { name: 'foo', type: { name: 'string' } },\n            one: { name: 'one', type: { name: 'string' }, mapping: { 1: 'mapped-1' } },\n          },\n          args: { foo: 'b', one: 1 },\n        });\n      });\n\n      it('emits GLOBALS_UPDATED with initial global values', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--b',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n\n        await waitForEvents([GLOBALS_UPDATED]);\n        expect(mockChannel.emit).toHaveBeenCalledWith(GLOBALS_UPDATED, {\n          initialGlobals: expect.objectContaining({ a: 'b' }),\n          userGlobals: expect.objectContaining({ a: 'b' }),\n          storyGlobals: expect.objectContaining({}),\n          globals: expect.objectContaining({ a: 'b' }),\n        });\n      });\n\n      describe('if the story sets globals', () => {\n        it('emits GLOBALS_UPDATED with overridden storyGlobals', async () => {\n          document.location.search = '?id=component-one--a';\n          const newImportFn = vi.fn(async (path) => {\n            if (path === './src/ComponentOne.stories.js') {\n              return {\n                ...componentOneExports,\n                b: { ...componentOneExports.b, globals: { a: 'c' } },\n              };\n            }\n            return importFn(path);\n          });\n\n          await createAndRenderPreview({ importFn: newImportFn });\n          mockChannel.emit.mockClear();\n          emitter.emit(SET_CURRENT_STORY, {\n            storyId: 'component-one--b',\n            viewMode: 'story',\n          });\n          await waitForSetCurrentStory();\n\n          await waitForEvents([GLOBALS_UPDATED]);\n          expect(mockChannel.emit).toHaveBeenCalledWith(GLOBALS_UPDATED, {\n            initialGlobals: expect.objectContaining({ a: 'b' }),\n            userGlobals: expect.objectContaining({ a: 'b' }),\n            storyGlobals: expect.objectContaining({ a: 'c' }),\n            globals: expect.objectContaining({ a: 'c' }),\n          });\n        });\n      });\n\n      it('applies loaders with story context', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--b',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n\n        await waitForRender();\n        expect(componentOneExports.default.loaders[0]).toHaveBeenCalledWith(\n          expect.objectContaining({\n            id: 'component-one--b',\n            parameters: expect.objectContaining({\n              __isArgsStory: false,\n              docs: expect.any(Object),\n              fileName: './src/ComponentOne.stories.js',\n            }),\n            initialArgs: { foo: 'b', one: 1 },\n            argTypes: {\n              foo: { name: 'foo', type: { name: 'string' } },\n              one: { name: 'one', type: { name: 'string' }, mapping: { 1: 'mapped-1' } },\n            },\n            args: { foo: 'b', one: 'mapped-1' },\n          })\n        );\n      });\n\n      it('passes loaded context to renderToCanvas', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--b',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n\n        expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n          expect.objectContaining({\n            forceRemount: true,\n            storyContext: expect.objectContaining({\n              id: 'component-one--b',\n              parameters: expect.objectContaining({\n                __isArgsStory: false,\n                docs: expect.any(Object),\n                fileName: './src/ComponentOne.stories.js',\n              }),\n              globals: expect.objectContaining({ a: 'b' }),\n              initialArgs: { foo: 'b', one: 1 },\n              argTypes: {\n                foo: { name: 'foo', type: { name: 'string' } },\n                one: { name: 'one', type: { name: 'string' }, mapping: { 1: 'mapped-1' } },\n              },\n              args: { foo: 'b', one: 'mapped-1' },\n              loaded: { l: 7 },\n            }),\n          }),\n          'story-element'\n        );\n      });\n\n      it('renders exception if renderToCanvas throws', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        const error = new Error('error');\n        projectAnnotations.renderToCanvas.mockImplementation(() => {\n          throw error;\n        });\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--b',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_THREW_EXCEPTION, serializeError(error));\n        expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error);\n      });\n\n      it('renders error if the story calls showError', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        const error = { title: 'title', description: 'description' };\n        projectAnnotations.renderToCanvas.mockImplementation((context) => context.showError(error));\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--b',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ERRORED, error);\n        expect(preview.view.showErrorDisplay).toHaveBeenCalledWith({\n          message: error.title,\n          stack: error.description,\n        });\n      });\n\n      it('renders exception if the story calls showException', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        const error = new Error('error');\n        projectAnnotations.renderToCanvas.mockImplementation((context) =>\n          context.showException(error)\n        );\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--b',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_THREW_EXCEPTION, serializeError(error));\n        expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error);\n      });\n\n      it('executes playFunction', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--b',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n\n        expect(componentOneExports.b.play).toHaveBeenCalled();\n      });\n\n      it('emits STORY_RENDERED', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--b',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--b');\n      });\n\n      it('retains any arg changes', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(UPDATE_STORY_ARGS, {\n          storyId: 'component-one--a',\n          updatedArgs: { foo: 'updated' },\n        });\n        await waitForRender();\n        expect(\n          // @ts-expect-error Ignore protected property\n          (preview.storyStoreValue as StoryStore<Renderer>)?.args.get('component-one--a')\n        ).toEqual({\n          foo: 'updated',\n          one: 1,\n        });\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--b',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n        expect(\n          // @ts-expect-error Ignore protected property\n          (preview.storyStoreValue as StoryStore<Renderer>)?.args.get('component-one--a')\n        ).toEqual({\n          foo: 'updated',\n          one: 1,\n        });\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--a',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n        expect(\n          // @ts-expect-error Ignore protected property\n          (preview.storyStoreValue as StoryStore<Renderer>)?.args.get('component-one--a')\n        ).toEqual({\n          foo: 'updated',\n          one: 1,\n        });\n      });\n\n      describe('while story is still rendering', () => {\n        let originalLocation = window.location;\n        beforeEach(() => {\n          originalLocation = window.location;\n          delete (window as Partial<Window>).location;\n          // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n          // @ts-ignore-error\n          window.location = { ...originalLocation, reload: vi.fn() };\n        });\n\n        afterEach(() => {\n          delete (window as Partial<Window>).location;\n          // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n          // @ts-ignore-error\n          window.location = { ...originalLocation, reload: originalLocation.reload };\n        });\n\n        it('aborts render for initial story', async () => {\n          const [gate, openGate] = createGate();\n\n          document.location.search = '?id=component-one--a';\n          projectAnnotations.renderToCanvas.mockImplementation(async () => gate);\n          await new PreviewWeb(importFn, getProjectAnnotations).ready();\n          await waitForRenderPhase('rendering');\n\n          mockChannel.emit.mockClear();\n          emitter.emit(SET_CURRENT_STORY, {\n            storyId: 'component-one--b',\n            viewMode: 'story',\n          });\n          await waitForSetCurrentStory();\n\n          // Now let the renderToCanvas call resolve\n          openGate();\n          await waitForRenderPhase('aborted');\n          await waitForSetCurrentStory();\n\n          await waitForRenderPhase('rendering');\n          expect(projectAnnotations.renderToCanvas).toHaveBeenCalledTimes(2);\n\n          await waitForRenderPhase('playing');\n          expect(componentOneExports.a.play).not.toHaveBeenCalled();\n          expect(componentOneExports.b.play).toHaveBeenCalled();\n\n          await waitForRenderPhase('completed');\n          expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a');\n          expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--b');\n\n          await waitForQuiescence();\n        });\n\n        it('aborts play function for initial story', async () => {\n          const [gate, openGate] = createGate();\n          componentOneExports.a.play.mockImplementationOnce(async () => gate);\n\n          document.location.search = '?id=component-one--a';\n          await new PreviewWeb(importFn, getProjectAnnotations).ready();\n          await waitForRenderPhase('playing');\n\n          expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n            expect.objectContaining({\n              forceRemount: true,\n              storyContext: expect.objectContaining({\n                id: 'component-one--a',\n                loaded: { l: 7 },\n              }),\n            }),\n            'story-element'\n          );\n\n          mockChannel.emit.mockClear();\n          emitter.emit(SET_CURRENT_STORY, {\n            storyId: 'component-one--b',\n            viewMode: 'story',\n          });\n          await waitForSetCurrentStory();\n\n          // Now let the playFunction call resolve\n          openGate();\n          await waitForRenderPhase('aborted');\n          await waitForSetCurrentStory();\n\n          await waitForRenderPhase('rendering');\n          expect(mockChannel.emit).toHaveBeenCalledWith(STORY_CHANGED, 'component-one--b');\n          expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n            expect.objectContaining({\n              forceRemount: true,\n              storyContext: expect.objectContaining({\n                id: 'component-one--b',\n                loaded: { l: 7 },\n              }),\n            }),\n            'story-element'\n          );\n\n          await waitForRenderPhase('playing');\n          await waitForRenderPhase('completed');\n          expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--b');\n\n          // Final story rendered is not emitted for the first story\n          await waitForQuiescence();\n          expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a');\n        });\n\n        it('reloads page if playFunction fails to abort in time', async () => {\n          const [gate] = createGate();\n          componentOneExports.a.play.mockImplementationOnce(async () => gate);\n\n          document.location.search = '?id=component-one--a';\n          await new PreviewWeb(importFn, getProjectAnnotations).ready();\n          await waitForRenderPhase('playing');\n\n          expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n            expect.objectContaining({\n              forceRemount: true,\n              storyContext: expect.objectContaining({\n                id: 'component-one--a',\n                loaded: { l: 7 },\n              }),\n            }),\n            'story-element'\n          );\n\n          mockChannel.emit.mockClear();\n          emitter.emit(SET_CURRENT_STORY, {\n            storyId: 'component-one--b',\n            viewMode: 'story',\n          });\n\n          await vi.waitFor(() => {\n            expect(window.location.reload).toHaveBeenCalled();\n          });\n          expect(window.location.reload).toHaveBeenCalled();\n          expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_CHANGED, 'component-one--b');\n          expect(projectAnnotations.renderToCanvas).not.toHaveBeenCalledWith(\n            expect.objectContaining({\n              storyContext: expect.objectContaining({ id: 'component-one--b' }),\n            }),\n            undefined\n          );\n        });\n      });\n    });\n\n    describe('when changing from story viewMode to docs', () => {\n      it('emits DOCS_PREPARED', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--docs',\n          viewMode: 'docs',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(DOCS_PREPARED, {\n          id: 'component-one--docs',\n          parameters: expect.objectContaining({\n            docs: expect.any(Object),\n            fileName: './src/ComponentOne.stories.js',\n          }),\n        });\n      });\n\n      it('calls renderToCanvas teardown', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--docs',\n          viewMode: 'docs',\n        });\n        await vi.waitFor(() => {\n          expect(teardownrenderToCanvas).toHaveBeenCalled();\n        });\n      });\n\n      it('updates URL', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--docs',\n          viewMode: 'docs',\n        });\n        await waitForSetCurrentStory();\n\n        expect(history.replaceState).toHaveBeenCalledWith(\n          {},\n          '',\n          'pathname?id=component-one--docs&viewMode=docs'\n        );\n      });\n\n      it('renders preparing state', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--docs',\n          viewMode: 'docs',\n        });\n        await vi.waitFor(() => {\n          expect(preview.view.showPreparingDocs).toHaveBeenCalled();\n        });\n      });\n\n      it('emits STORY_CHANGED', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--docs',\n          viewMode: 'docs',\n        });\n        await waitForSetCurrentStory();\n\n        await waitForEvents([STORY_CHANGED]);\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_CHANGED, 'component-one--docs');\n      });\n\n      it('calls view.prepareForDocs', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--docs',\n          viewMode: 'docs',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n\n        expect(preview.view.prepareForDocs).toHaveBeenCalled();\n      });\n\n      it('render the docs container with the correct context, template render', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--docs',\n          viewMode: 'docs',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n\n        expect(docsRenderer.render).toHaveBeenCalled();\n        expect(docsRenderer.render.mock.calls[0][0].storyById()).toMatchObject({\n          id: 'component-one--a',\n        });\n      });\n\n      it('emits DOCS_RENDERED', async () => {\n        document.location.search = '?id=component-one--a';\n        await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--docs',\n          viewMode: 'docs',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(DOCS_RENDERED, 'component-one--docs');\n      });\n    });\n\n    describe('when changing from docs viewMode to story', () => {\n      it('unmounts docs', async () => {\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n        await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--a',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n\n        expect(docsRenderer.unmount).toHaveBeenCalled();\n      });\n\n      // this test seems to somehow affect the test above, I re-ordered them to get it green, but someone should look into this\n      it('updates URL', async () => {\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n        await createAndRenderPreview();\n\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--a',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n\n        expect(history.replaceState).toHaveBeenCalledWith(\n          {},\n          '',\n          'pathname?id=component-one--a&viewMode=story'\n        );\n      });\n\n      // NOTE: I am not sure this entirely makes sense but this is the behaviour from 6.3\n      it('emits STORY_CHANGED', async () => {\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n        await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--a',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n\n        await waitForEvents([STORY_CHANGED]);\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_CHANGED, 'component-one--a');\n      });\n\n      it('calls view.prepareForStory', async () => {\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n        const preview = await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--a',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n\n        expect(preview.view.prepareForStory).toHaveBeenCalledWith(\n          expect.objectContaining({\n            id: 'component-one--a',\n          })\n        );\n      });\n\n      it('emits STORY_PREPARED', async () => {\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n        await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--a',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n\n        await waitForEvents([STORY_PREPARED]);\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_PREPARED, {\n          id: 'component-one--a',\n          parameters: expect.objectContaining({\n            __isArgsStory: false,\n            docs: expect.any(Object),\n            fileName: './src/ComponentOne.stories.js',\n          }),\n          initialArgs: { foo: 'a', one: 1 },\n          argTypes: {\n            foo: { name: 'foo', type: { name: 'string' } },\n            one: { name: 'one', type: { name: 'string' }, mapping: { 1: 'mapped-1' } },\n          },\n          args: { foo: 'a', one: 1 },\n        });\n      });\n\n      it('applies loaders with story context', async () => {\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n        await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--a',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n\n        await waitForRender();\n        expect(componentOneExports.default.loaders[0]).toHaveBeenCalledWith(\n          expect.objectContaining({\n            id: 'component-one--a',\n            parameters: expect.objectContaining({\n              __isArgsStory: false,\n              docs: expect.any(Object),\n              fileName: './src/ComponentOne.stories.js',\n            }),\n            initialArgs: { foo: 'a', one: 1 },\n            argTypes: {\n              foo: { name: 'foo', type: { name: 'string' } },\n              one: { name: 'one', type: { name: 'string' }, mapping: { 1: 'mapped-1' } },\n            },\n            args: { foo: 'a', one: 'mapped-1' },\n          })\n        );\n      });\n\n      it('passes loaded context to renderToCanvas', async () => {\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n        await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--a',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n\n        expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n          expect.objectContaining({\n            forceRemount: true,\n            storyContext: expect.objectContaining({\n              id: 'component-one--a',\n              parameters: expect.objectContaining({\n                __isArgsStory: false,\n                docs: expect.any(Object),\n                fileName: './src/ComponentOne.stories.js',\n              }),\n              globals: expect.objectContaining({ a: 'b' }),\n              initialArgs: { foo: 'a', one: 1 },\n              argTypes: {\n                foo: { name: 'foo', type: { name: 'string' } },\n                one: { name: 'one', type: { name: 'string' }, mapping: { 1: 'mapped-1' } },\n              },\n              args: { foo: 'a', one: 'mapped-1' },\n              loaded: { l: 7 },\n            }),\n          }),\n          'story-element'\n        );\n      });\n\n      it('renders exception if renderToCanvas throws', async () => {\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n        const preview = await createAndRenderPreview();\n\n        const error = new Error('error');\n        projectAnnotations.renderToCanvas.mockImplementation(() => {\n          throw error;\n        });\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--a',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_THREW_EXCEPTION, serializeError(error));\n        expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error);\n      });\n\n      it('renders error if the story calls showError', async () => {\n        const error = { title: 'title', description: 'description' };\n        projectAnnotations.renderToCanvas.mockImplementation((context) => context.showError(error));\n\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n        const preview = await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--a',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ERRORED, error);\n        expect(preview.view.showErrorDisplay).toHaveBeenCalledWith({\n          message: error.title,\n          stack: error.description,\n        });\n      });\n\n      it('renders exception if the story calls showException', async () => {\n        const error = new Error('error');\n        projectAnnotations.renderToCanvas.mockImplementation((context) =>\n          context.showException(error)\n        );\n\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n        const preview = await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--a',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_THREW_EXCEPTION, serializeError(error));\n        expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error);\n      });\n\n      it('executes playFunction', async () => {\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n        await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--a',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n\n        expect(componentOneExports.a.play).toHaveBeenCalled();\n      });\n\n      it('emits STORY_RENDERED', async () => {\n        document.location.search = '?id=component-one--docs&viewMode=docs';\n        await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--a',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a');\n      });\n    });\n  });\n\n  describe('onStoriesChanged', () => {\n    describe('if stories.json endpoint 500s initially', () => {\n      it('recovers and renders the story', async () => {\n        document.location.search = '?id=component-one--a';\n        const err = new Error('sort error');\n        mockFetchResult = { status: 500, text: async () => err.toString() };\n\n        const preview = new PreviewWeb(importFn, getProjectAnnotations);\n        await expect(preview.ready()).rejects.toThrow('sort error');\n\n        expect(preview.view.showErrorDisplay).toHaveBeenCalled();\n        expect(mockChannel.emit).toHaveBeenCalledWith(CONFIG_ERROR, expect.any(Error));\n\n        mockChannel.emit.mockClear();\n        mockFetchResult = { status: 200, json: mockStoryIndex, text: () => 'error text' };\n        preview.onStoryIndexChanged();\n        await waitForRender();\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a');\n      });\n\n      it('sets story args from the URL', async () => {\n        document.location.search = '?id=component-one--a&args=foo:url';\n        const err = new Error('sort error');\n        mockFetchResult = { status: 500, text: async () => err.toString() };\n\n        const preview = new PreviewWeb(importFn, getProjectAnnotations);\n        await expect(preview.ready()).rejects.toThrow('sort error');\n\n        expect(preview.view.showErrorDisplay).toHaveBeenCalled();\n        expect(mockChannel.emit).toHaveBeenCalledWith(CONFIG_ERROR, expect.any(Error));\n\n        mockChannel.emit.mockClear();\n        mockFetchResult = { status: 200, json: mockStoryIndex, text: () => 'error text' };\n        preview.onStoryIndexChanged();\n        await waitForRender();\n        expect(\n          // @ts-expect-error Ignore protected property\n          (preview.storyStoreValue as StoryStore<Renderer>)?.args.get('component-one--a')\n        ).toEqual({\n          foo: 'url',\n          one: 1,\n        });\n      });\n    });\n\n    describe('if called twice simultaneously', () => {\n      it('does not get renders confused', async () => {\n        const [blockImportFnGate, openBlockImportFnGate] = createGate();\n        const [importFnCalledGate, openImportFnCalledGate] = createGate();\n        const newImportFn = vi.fn(async (path) => {\n          openImportFnCalledGate();\n          await blockImportFnGate;\n          return importFn(path);\n        });\n\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n        mockChannel.emit.mockClear();\n\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await importFnCalledGate;\n        preview.onStoriesChanged({ importFn });\n\n        openBlockImportFnGate();\n        await waitForRender();\n\n        expect(preview.storyRenders.length).toEqual(1);\n      });\n\n      it('renders the second importFn', async () => {\n        const [importGate, openImportGate] = createGate();\n        const [importedGate, openImportedGate] = createGate();\n        const secondImportFn = vi.fn(async (path) => {\n          openImportedGate();\n          await importGate;\n          return importFn(path);\n        });\n\n        const thirdImportFn = vi.fn(async (path) => {\n          openImportedGate();\n          await importGate;\n          return importFn(path);\n        });\n\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n        mockChannel.emit.mockClear();\n\n        preview.onStoriesChanged({ importFn: secondImportFn });\n        await importedGate;\n        preview.onStoriesChanged({ importFn: thirdImportFn });\n\n        openImportGate();\n        await waitForRender();\n\n        expect(thirdImportFn).toHaveBeenCalled();\n      });\n    });\n\n    describe('when the current story changes', () => {\n      const newComponentOneExports = toMerged(componentOneExports, {\n        a: { args: { foo: 'edited' } },\n      });\n      const newImportFn = vi.fn(async (path) => {\n        return path === './src/ComponentOne.stories.js'\n          ? newComponentOneExports\n          : componentTwoExports;\n      });\n\n      it('calls renderToCanvas teardown', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n        mockChannel.emit.mockClear();\n\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await waitForRender();\n\n        expect(teardownrenderToCanvas).toHaveBeenCalled();\n      });\n\n      it('does not emit STORY_UNCHANGED', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n        mockChannel.emit.mockClear();\n\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await waitForRender();\n\n        expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_UNCHANGED, 'component-one--a');\n      });\n\n      it('does not emit STORY_CHANGED', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n        mockChannel.emit.mockClear();\n\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await waitForRender();\n\n        expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_CHANGED, 'component-one--a');\n      });\n\n      it('emits STORY_PREPARED with new annotations', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n        mockChannel.emit.mockClear();\n\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await waitForRender();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_PREPARED, {\n          id: 'component-one--a',\n          parameters: expect.objectContaining({\n            __isArgsStory: false,\n            docs: expect.any(Object),\n            fileName: './src/ComponentOne.stories.js',\n          }),\n          initialArgs: { foo: 'edited', one: 1 },\n          argTypes: {\n            foo: { name: 'foo', type: { name: 'string' } },\n            one: { name: 'one', type: { name: 'string' }, mapping: { 1: 'mapped-1' } },\n          },\n          args: { foo: 'edited', one: 1 },\n        });\n      });\n\n      it('applies loaders with story context', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        componentOneExports.default.loaders[0].mockClear();\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await waitForRender();\n\n        expect(componentOneExports.default.loaders[0]).toHaveBeenCalledWith(\n          expect.objectContaining({\n            id: 'component-one--a',\n            parameters: {\n              __isArgsStory: false,\n              docs: expect.any(Object),\n              backgrounds: expect.any(Object),\n              fileName: './src/ComponentOne.stories.js',\n              throwPlayFunctionExceptions: false,\n            },\n            initialArgs: { foo: 'edited', one: 1 },\n            argTypes: {\n              foo: { name: 'foo', type: { name: 'string' } },\n              one: { name: 'one', type: { name: 'string' }, mapping: { 1: 'mapped-1' } },\n            },\n            args: { foo: 'edited', one: 'mapped-1' },\n          })\n        );\n      });\n\n      it('passes loaded context to renderToCanvas', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        projectAnnotations.renderToCanvas.mockClear();\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await waitForRender();\n\n        expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n          expect.objectContaining({\n            forceRemount: true,\n            storyContext: expect.objectContaining({\n              id: 'component-one--a',\n              parameters: {\n                __isArgsStory: false,\n                docs: expect.any(Object),\n                backgrounds: expect.any(Object),\n                fileName: './src/ComponentOne.stories.js',\n                throwPlayFunctionExceptions: false,\n              },\n              globals: expect.objectContaining({ a: 'b' }),\n              initialArgs: { foo: 'edited', one: 1 },\n              argTypes: {\n                foo: { name: 'foo', type: { name: 'string' } },\n                one: { name: 'one', type: { name: 'string' }, mapping: { 1: 'mapped-1' } },\n              },\n              args: { foo: 'edited', one: 'mapped-1' },\n              loaded: { l: 7 },\n            }),\n          }),\n          'story-element'\n        );\n      });\n\n      it('retains the same delta to the args', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        emitter.emit(UPDATE_STORY_ARGS, {\n          storyId: 'component-one--a',\n          updatedArgs: { foo: 'updated' },\n        });\n        await waitForRender();\n\n        mockChannel.emit.mockClear();\n        projectAnnotations.renderToCanvas.mockClear();\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await waitForRender();\n\n        expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n          expect.objectContaining({\n            forceRemount: true,\n            storyContext: expect.objectContaining({\n              id: 'component-one--a',\n              args: { foo: 'updated', one: 'mapped-1' },\n            }),\n          }),\n          'story-element'\n        );\n      });\n\n      it('renders exception if renderToCanvas throws', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        const error = new Error('error');\n        projectAnnotations.renderToCanvas.mockImplementation(() => {\n          throw error;\n        });\n\n        mockChannel.emit.mockClear();\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await waitForRender();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_THREW_EXCEPTION, serializeError(error));\n        expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error);\n      });\n\n      it('renders error if the story calls showError', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        const error = { title: 'title', description: 'description' };\n        projectAnnotations.renderToCanvas.mockImplementation((context) => context.showError(error));\n\n        mockChannel.emit.mockClear();\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await waitForRender();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ERRORED, error);\n        expect(preview.view.showErrorDisplay).toHaveBeenCalledWith({\n          message: error.title,\n          stack: error.description,\n        });\n      });\n\n      it('renders exception if the story calls showException', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        const error = new Error('error');\n        projectAnnotations.renderToCanvas.mockImplementation((context) =>\n          context.showException(error)\n        );\n\n        mockChannel.emit.mockClear();\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await waitForRender();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_THREW_EXCEPTION, serializeError(error));\n        expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error);\n      });\n\n      it('executes playFunction', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        componentOneExports.a.play.mockClear();\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await waitForRender();\n\n        expect(componentOneExports.a.play).toHaveBeenCalled();\n      });\n\n      it('emits STORY_RENDERED', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await waitForRender();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a');\n      });\n    });\n\n    describe('when the current story changes importPath', () => {\n      const newImportFn = vi.fn(async (path) => ({ ...componentOneExports }));\n\n      const newStoryIndex = {\n        v: 5,\n        entries: {\n          ...storyIndex.entries,\n          'component-one--a': {\n            ...storyIndex.entries['component-one--a'],\n            importPath: './src/ComponentOne-new.stories.js',\n          },\n        },\n      };\n      beforeEach(() => {\n        newImportFn.mockClear();\n      });\n\n      it('re-imports the component', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        preview.onStoriesChanged({ importFn: newImportFn, storyIndex: newStoryIndex });\n        await waitForRender();\n\n        expect(newImportFn).toHaveBeenCalledWith('./src/ComponentOne-new.stories.js');\n      });\n\n      describe('if it was previously rendered', () => {\n        beforeEach(() => {\n          vi.useFakeTimers();\n        });\n        afterEach(() => {\n          vi.useRealTimers();\n        });\n        it('is reloaded when it is re-selected', async () => {\n          document.location.search = '?id=component-one--a';\n          const preview = await createAndRenderPreview();\n\n          mockChannel.emit.mockClear();\n          emitter.emit(SET_CURRENT_STORY, {\n            storyId: 'component-one--b',\n            viewMode: 'story',\n          });\n          await waitForSetCurrentStory();\n          await waitForRender();\n\n          preview.onStoriesChanged({ importFn: newImportFn, storyIndex: newStoryIndex });\n\n          mockChannel.emit.mockClear();\n          emitter.emit(SET_CURRENT_STORY, {\n            storyId: 'component-one--a',\n            viewMode: 'story',\n          });\n          await waitForSetCurrentStory();\n          await waitForRender();\n          expect(newImportFn).toHaveBeenCalledWith('./src/ComponentOne-new.stories.js');\n        });\n      });\n    });\n\n    describe('when the current story has not changed', () => {\n      const newComponentTwoExports = { ...componentTwoExports };\n      const newImportFn = vi.fn(async (path) => {\n        return path === './src/ComponentOne.stories.js'\n          ? componentOneExports\n          : newComponentTwoExports;\n      });\n\n      it('does NOT call renderToCanvas teardown', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await waitForEvents([STORY_UNCHANGED]);\n\n        expect(teardownrenderToCanvas).not.toHaveBeenCalled();\n      });\n\n      it('emits STORY_UNCHANGED', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await waitForEvents([STORY_UNCHANGED]);\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_UNCHANGED, 'component-one--a');\n        expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_CHANGED, 'component-one--a');\n      });\n\n      it('clears preparing state', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        vi.mocked(preview.view.showMain).mockClear();\n        mockChannel.emit.mockClear();\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await waitForEvents([STORY_UNCHANGED]);\n\n        expect(preview.view.showMain).toHaveBeenCalled();\n      });\n\n      it('does not re-render the story', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        projectAnnotations.renderToCanvas.mockClear();\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await waitForQuiescence();\n\n        expect(projectAnnotations.renderToCanvas).not.toHaveBeenCalled();\n        expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a');\n      });\n    });\n\n    describe('when another (not current) story changes', () => {\n      beforeEach(() => {\n        vi.useFakeTimers();\n      });\n      afterEach(() => {\n        vi.useRealTimers();\n      });\n      const newComponentOneExports = toMerged(componentOneExports, {\n        a: { args: { bar: 'edited' }, argTypes: { bar: { type: { name: 'string' } } } },\n      });\n      const newImportFn = vi.fn(async (path) => {\n        return path === './src/ComponentOne.stories.js'\n          ? newComponentOneExports\n          : componentTwoExports;\n      });\n      it('retains the same delta to the args', async () => {\n        // Start at Story A\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        // Change A's args\n        mockChannel.emit.mockClear();\n        emitter.emit(UPDATE_STORY_ARGS, {\n          storyId: 'component-one--a',\n          updatedArgs: { foo: 'updated' },\n        });\n        await waitForRender();\n\n        // Change to story B\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--b',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n        expect(\n          // @ts-expect-error Ignore protected property\n          (preview.storyStoreValue as StoryStore<Renderer>)?.args.get('component-one--a')\n        ).toEqual({\n          foo: 'updated',\n          one: 1,\n        });\n\n        // Update story A's args via HMR\n        mockChannel.emit.mockClear();\n        projectAnnotations.renderToCanvas.mockClear();\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await waitForRender();\n\n        // Change back to Story A\n        mockChannel.emit.mockClear();\n        emitter.emit(SET_CURRENT_STORY, {\n          storyId: 'component-one--a',\n          viewMode: 'story',\n        });\n        await waitForSetCurrentStory();\n        await waitForRender();\n        expect(\n          // @ts-expect-error Ignore protected property\n          (preview.storyStoreValue as StoryStore<Renderer>)?.args.get('component-one--a')\n        ).toEqual({\n          foo: 'updated',\n          bar: 'edited',\n          one: 1,\n        });\n\n        expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n          expect.objectContaining({\n            forceRemount: true,\n            storyContext: expect.objectContaining({\n              id: 'component-one--a',\n              args: { foo: 'updated', bar: 'edited', one: 'mapped-1' },\n            }),\n          }),\n          'story-element'\n        );\n      });\n    });\n\n    describe('if the story no longer exists', () => {\n      const { a, ...componentOneExportsWithoutA } = componentOneExports;\n      const newImportFn = vi.fn(async (path) => {\n        return path === './src/ComponentOne.stories.js'\n          ? componentOneExportsWithoutA\n          : componentTwoExports;\n      });\n\n      const newStoryIndex = {\n        v: 5,\n        entries: {\n          'component-one--b': storyIndex.entries['component-one--b'],\n        },\n      };\n\n      it('calls renderToCanvas teardown', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        preview.onStoriesChanged({ importFn: newImportFn, storyIndex: newStoryIndex });\n        await waitForEvents([STORY_MISSING]);\n\n        expect(teardownrenderToCanvas).toHaveBeenCalled();\n      });\n\n      it('renders loading error', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        preview.onStoriesChanged({ importFn: newImportFn, storyIndex: newStoryIndex });\n        await waitForEvents([STORY_MISSING]);\n\n        expect(preview.view.showErrorDisplay).toHaveBeenCalled();\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_MISSING, 'component-one--a');\n      });\n\n      it('does not re-render the story', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        projectAnnotations.renderToCanvas.mockClear();\n        preview.onStoriesChanged({ importFn: newImportFn, storyIndex: newStoryIndex });\n        await waitForQuiescence();\n\n        expect(projectAnnotations.renderToCanvas).not.toHaveBeenCalled();\n        expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a');\n      });\n\n      it('re-renders the story if it is readded', async () => {\n        document.location.search = '?id=component-one--a';\n        const preview = await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        preview.onStoriesChanged({ importFn: newImportFn, storyIndex: newStoryIndex });\n        await waitForEvents([STORY_MISSING]);\n\n        mockChannel.emit.mockClear();\n        preview.onStoriesChanged({ importFn, storyIndex });\n        await waitForRender();\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a');\n      });\n    });\n\n    describe('when a mdx docs file changes', () => {\n      const newUnattachedDocsExports = { default: vi.fn() };\n\n      const newImportFn = vi.fn(async (path: string) => {\n        return path === './src/Introduction.mdx' ? newUnattachedDocsExports : importFn(path);\n      });\n\n      it('emits DOCS_PREPARED', async () => {\n        document.location.search = '?id=introduction--docs';\n        const preview = await createAndRenderPreview();\n\n        mockChannel.emit.mockClear();\n        docsRenderer.render.mockClear();\n\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await waitForRender();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(DOCS_PREPARED, {\n          id: 'introduction--docs',\n          parameters: expect.objectContaining({\n            docs: expect.any(Object),\n          }),\n        });\n      });\n\n      it('renders with the generated docs parameters', async () => {\n        document.location.search = '?id=introduction--docs&viewMode=docs';\n        const preview = await createAndRenderPreview();\n        mockChannel.emit.mockClear();\n        docsRenderer.render.mockClear();\n\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await waitForRender();\n\n        expect(docsRenderer.render).toHaveBeenCalledWith(\n          expect.any(Object),\n          expect.objectContaining({\n            page: newUnattachedDocsExports.default,\n            renderer: projectAnnotations.parameters.docs.renderer,\n          }),\n          'docs-element'\n        );\n      });\n\n      it('emits DOCS_RENDERED', async () => {\n        document.location.search = '?id=introduction--docs&viewMode=docs';\n        const preview = await createAndRenderPreview();\n        mockChannel.emit.mockClear();\n\n        preview.onStoriesChanged({ importFn: newImportFn });\n        await waitForRender();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(DOCS_RENDERED, 'introduction--docs');\n      });\n    });\n  });\n\n  describe('onGetProjectAnnotationsChanged', () => {\n    describe('if initial getProjectAnnotations threw', () => {\n      it('recovers and renders the story', async () => {\n        document.location.search = '?id=component-one--a';\n\n        const err = new Error('meta error');\n        const preview = new PreviewWeb(importFn, () => {\n          throw err;\n        });\n        await expect(preview.ready()).rejects.toThrow(err);\n\n        preview.onGetProjectAnnotationsChanged({ getProjectAnnotations });\n        await waitForRender();\n\n        expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a');\n      });\n\n      it('sets globals from the URL', async () => {\n        document.location.search = '?id=*&globals=a:c';\n\n        const err = new Error('meta error');\n        const preview = new PreviewWeb(importFn, () => {\n          throw err;\n        });\n        await expect(preview.ready()).rejects.toThrow(err);\n\n        preview.onGetProjectAnnotationsChanged({ getProjectAnnotations });\n        await waitForRender();\n\n        // @ts-expect-error Ignore protected property\n        expect((preview.storyStoreValue as StoryStore<Renderer>)!.userGlobals.get()).toEqual(\n          expect.objectContaining({\n            a: 'c',\n          })\n        );\n      });\n    });\n\n    describe('with no selection', () => {\n      it('does not error', async () => {\n        const preview = await createAndRenderPreview();\n        await preview.onGetProjectAnnotationsChanged({\n          getProjectAnnotations: newGetProjectAnnotations,\n        });\n      });\n    });\n\n    it('shows an error the new value throws', async () => {\n      document.location.search = '?id=component-one--a';\n      const preview = await createAndRenderPreview();\n\n      mockChannel.emit.mockClear();\n      const err = new Error('error getting meta');\n      await expect(\n        preview.onGetProjectAnnotationsChanged({\n          getProjectAnnotations: () => {\n            throw err;\n          },\n        })\n      ).rejects.toThrow(err);\n\n      expect(preview.view.showErrorDisplay).toHaveBeenCalled();\n      expect(mockChannel.emit).toHaveBeenCalledWith(CONFIG_ERROR, err);\n    });\n\n    const newGlobalDecorator = vi.fn((s: any) => s());\n    const newGetProjectAnnotations = () => {\n      return {\n        ...projectAnnotations,\n        args: { global: 'added' },\n        initialGlobals: { a: 'edited' },\n        decorators: [newGlobalDecorator],\n      };\n    };\n\n    it('updates globals to their new values', async () => {\n      document.location.search = '?id=component-one--a';\n      const preview = await createAndRenderPreview();\n\n      mockChannel.emit.mockClear();\n      preview.onGetProjectAnnotationsChanged({ getProjectAnnotations: newGetProjectAnnotations });\n      await waitForRender();\n\n      // @ts-expect-error Ignore protected property\n      expect((preview.storyStoreValue as StoryStore<Renderer>)!.userGlobals.get()).toEqual({\n        a: 'edited',\n      });\n    });\n\n    it('emits SET_GLOBALS with new values', async () => {\n      document.location.search = '?id=component-one--a';\n      const preview = await createAndRenderPreview();\n\n      mockChannel.emit.mockClear();\n      preview.onGetProjectAnnotationsChanged({ getProjectAnnotations: newGetProjectAnnotations });\n      await waitForRender();\n\n      await waitForEvents([SET_GLOBALS]);\n      expect(mockChannel.emit).toHaveBeenCalledWith(SET_GLOBALS, {\n        globals: { a: 'edited' },\n        globalTypes: {},\n      });\n    });\n\n    it('updates args to their new values', async () => {\n      document.location.search = '?id=component-one--a';\n      const preview = await createAndRenderPreview();\n\n      mockChannel.emit.mockClear();\n      preview.onGetProjectAnnotationsChanged({ getProjectAnnotations: newGetProjectAnnotations });\n      await waitForRender();\n\n      expect(\n        // @ts-expect-error Ignore protected property\n        (preview.storyStoreValue as StoryStore<Renderer>)?.args.get('component-one--a')\n      ).toEqual({\n        foo: 'a',\n        one: 1,\n        global: 'added',\n      });\n    });\n\n    it('emits SET_PREPARED with new args', async () => {\n      document.location.search = '?id=component-one--a';\n      const preview = await createAndRenderPreview();\n\n      mockChannel.emit.mockClear();\n      preview.onGetProjectAnnotationsChanged({ getProjectAnnotations: newGetProjectAnnotations });\n      await waitForRender();\n\n      expect(mockChannel.emit).toHaveBeenCalledWith(\n        STORY_PREPARED,\n        expect.objectContaining({\n          id: 'component-one--a',\n          args: { foo: 'a', one: 1, global: 'added' },\n        })\n      );\n    });\n\n    it('calls renderToCanvas teardown', async () => {\n      document.location.search = '?id=component-one--a';\n      const preview = await createAndRenderPreview();\n\n      projectAnnotations.renderToCanvas.mockClear();\n      mockChannel.emit.mockClear();\n      preview.onGetProjectAnnotationsChanged({ getProjectAnnotations: newGetProjectAnnotations });\n      await waitForRender();\n\n      expect(teardownrenderToCanvas).toHaveBeenCalled();\n    });\n\n    it('rerenders the current story with new global meta-generated context', async () => {\n      document.location.search = '?id=component-one--a';\n      const preview = await createAndRenderPreview();\n\n      projectAnnotations.renderToCanvas.mockClear();\n      mockChannel.emit.mockClear();\n      preview.onGetProjectAnnotationsChanged({ getProjectAnnotations: newGetProjectAnnotations });\n      await waitForRender();\n\n      expect(projectAnnotations.renderToCanvas).toHaveBeenCalledWith(\n        expect.objectContaining({\n          storyContext: expect.objectContaining({\n            args: { foo: 'a', one: 'mapped-1', global: 'added' },\n            globals: { a: 'edited' },\n          }),\n        }),\n        'story-element'\n      );\n    });\n  });\n\n  describe('onKeydown', () => {\n    it('emits PREVIEW_KEYDOWN for regular elements', async () => {\n      document.location.search = '?id=component-one--docs&viewMode=docs';\n      const preview = await createAndRenderPreview();\n\n      preview.onKeydown({\n        composedPath: vi\n          .fn()\n          .mockReturnValue([{ tagName: 'div', getAttribute: vi.fn().mockReturnValue(null) }]),\n      } as any);\n\n      expect(mockChannel.emit).toHaveBeenCalledWith(PREVIEW_KEYDOWN, expect.objectContaining({}));\n    });\n\n    it('emits PREVIEW_KEYDOWN for regular elements, fallback to event.target', async () => {\n      document.location.search = '?id=component-one--docs&viewMode=docs';\n      const preview = await createAndRenderPreview();\n\n      preview.onKeydown({\n        target: { tagName: 'div', getAttribute: vi.fn().mockReturnValue(null) },\n      } as any);\n\n      expect(mockChannel.emit).toHaveBeenCalledWith(PREVIEW_KEYDOWN, expect.objectContaining({}));\n    });\n\n    it('does not emit PREVIEW_KEYDOWN for input elements', async () => {\n      document.location.search = '?id=component-one--docs&viewMode=docs';\n      const preview = await createAndRenderPreview();\n\n      preview.onKeydown({\n        composedPath: vi\n          .fn()\n          .mockReturnValue([{ tagName: 'input', getAttribute: vi.fn().mockReturnValue(null) }]),\n      } as any);\n\n      expect(mockChannel.emit).not.toHaveBeenCalledWith(\n        PREVIEW_KEYDOWN,\n        expect.objectContaining({})\n      );\n    });\n\n    it('does not emit PREVIEW_KEYDOWN during story play functions', async () => {\n      document.location.search = '?id=component-one--a';\n\n      const [gate, openGate] = createGate();\n      componentOneExports.a.play.mockImplementationOnce(async () => gate);\n      const preview = new PreviewWeb(importFn, getProjectAnnotations);\n      await preview.ready();\n      await waitForRenderPhase('playing');\n\n      await preview.onKeydown({\n        target: { tagName: 'div', getAttribute: vi.fn().mockReturnValue(null) },\n      } as any);\n\n      expect(mockChannel.emit).not.toHaveBeenCalledWith(\n        PREVIEW_KEYDOWN,\n        expect.objectContaining({})\n      );\n      openGate();\n    });\n\n    it('does not emit PREVIEW_KEYDOWN during docs play functions', async () => {\n      document.location.search = '?id=component-one--a';\n\n      const preview = await createAndRenderPreview();\n\n      mockChannel.emit.mockClear();\n      const [gate, openGate] = createGate();\n      componentOneExports.b.play.mockImplementationOnce(async () => gate);\n      // @ts-expect-error (not strict)\n      preview.renderStoryToElement(\n        // @ts-expect-error Ignore protected property\n        await (preview.storyStoreValue as StoryStore<Renderer>)?.loadStory({\n          storyId: 'component-one--b',\n        }),\n        {} as any,\n        {} as any\n      );\n      await waitForRenderPhase('playing');\n\n      await preview.onKeydown({\n        target: { tagName: 'div', getAttribute: vi.fn().mockReturnValue(null) },\n      } as any);\n\n      expect(mockChannel.emit).not.toHaveBeenCalledWith(\n        PREVIEW_KEYDOWN,\n        expect.objectContaining({})\n      );\n      openGate();\n    });\n  });\n\n  describe('extract', () => {\n    it('throws an error if preview.js throws', async () => {\n      const err = new Error('meta error');\n      const preview = new PreviewWeb(importFn, () => {\n        throw err;\n      });\n      await expect(preview.ready()).rejects.toThrow(/meta error/);\n      await expect(preview.extract()).rejects.toThrow();\n    });\n\n    it('shows an error if the stories.json endpoint 500s', async () => {\n      const err = new Error('sort error');\n      mockFetchResult = { status: 500, text: async () => err.toString() };\n\n      const preview = new PreviewWeb(importFn, getProjectAnnotations);\n      await expect(preview.ready()).rejects.toThrow('sort error');\n\n      await expect(preview.extract()).rejects.toThrow();\n    });\n\n    it('waits for stories to be cached', async () => {\n      const [gate, openGate] = createGate();\n\n      const gatedImportFn = async (path: string) => {\n        await gate;\n        return importFn(path);\n      };\n\n      const preview = await createAndRenderPreview({ importFn: gatedImportFn });\n\n      let extracted = false;\n      preview.extract().then(() => {\n        extracted = true;\n      });\n\n      expect(extracted).toBe(false);\n\n      openGate();\n      await new Promise((r) => setTimeout(r, 0)); // Let the promise resolve\n      expect(extracted).toBe(true);\n\n      expect(await preview.extract()).toMatchInlineSnapshot(`\n        {\n          \"component-one--a\": {\n            \"argTypes\": {\n              \"foo\": {\n                \"name\": \"foo\",\n                \"type\": {\n                  \"name\": \"string\",\n                },\n              },\n              \"one\": {\n                \"mapping\": {\n                  \"1\": \"mapped-1\",\n                },\n                \"name\": \"one\",\n                \"type\": {\n                  \"name\": \"string\",\n                },\n              },\n            },\n            \"args\": {\n              \"foo\": \"a\",\n              \"one\": 1,\n            },\n            \"component\": undefined,\n            \"componentId\": \"component-one\",\n            \"globals\": {\n              \"a\": \"b\",\n              \"backgrounds\": {\n                \"grid\": false,\n                \"value\": undefined,\n              },\n              \"measureEnabled\": false,\n              \"outline\": false,\n              \"viewport\": {\n                \"isRotated\": false,\n                \"value\": undefined,\n              },\n            },\n            \"id\": \"component-one--a\",\n            \"initialArgs\": {\n              \"foo\": \"a\",\n              \"one\": 1,\n            },\n            \"kind\": \"Component One\",\n            \"name\": \"A\",\n            \"parameters\": {\n              \"__isArgsStory\": false,\n              \"backgrounds\": {\n                \"disable\": false,\n                \"grid\": {\n                  \"cellAmount\": 5,\n                  \"cellSize\": 20,\n                  \"opacity\": 0.5,\n                },\n              },\n              \"docs\": {\n                \"container\": [MockFunction],\n                \"page\": [MockFunction],\n                \"renderer\": [Function],\n              },\n              \"fileName\": \"./src/ComponentOne.stories.js\",\n              \"throwPlayFunctionExceptions\": false,\n            },\n            \"story\": \"A\",\n            \"storyGlobals\": {},\n            \"storyId\": \"component-one--a\",\n            \"subcomponents\": undefined,\n            \"tags\": [\n              \"dev\",\n              \"test\",\n            ],\n            \"testingLibraryRender\": undefined,\n            \"title\": \"Component One\",\n            \"usesMount\": false,\n          },\n          \"component-one--b\": {\n            \"argTypes\": {\n              \"foo\": {\n                \"name\": \"foo\",\n                \"type\": {\n                  \"name\": \"string\",\n                },\n              },\n              \"one\": {\n                \"mapping\": {\n                  \"1\": \"mapped-1\",\n                },\n                \"name\": \"one\",\n                \"type\": {\n                  \"name\": \"string\",\n                },\n              },\n            },\n            \"args\": {\n              \"foo\": \"b\",\n              \"one\": 1,\n            },\n            \"component\": undefined,\n            \"componentId\": \"component-one\",\n            \"globals\": {\n              \"a\": \"b\",\n              \"backgrounds\": {\n                \"grid\": false,\n                \"value\": undefined,\n              },\n              \"measureEnabled\": false,\n              \"outline\": false,\n              \"viewport\": {\n                \"isRotated\": false,\n                \"value\": undefined,\n              },\n            },\n            \"id\": \"component-one--b\",\n            \"initialArgs\": {\n              \"foo\": \"b\",\n              \"one\": 1,\n            },\n            \"kind\": \"Component One\",\n            \"name\": \"B\",\n            \"parameters\": {\n              \"__isArgsStory\": false,\n              \"backgrounds\": {\n                \"disable\": false,\n                \"grid\": {\n                  \"cellAmount\": 5,\n                  \"cellSize\": 20,\n                  \"opacity\": 0.5,\n                },\n              },\n              \"docs\": {\n                \"container\": [MockFunction],\n                \"page\": [MockFunction],\n                \"renderer\": [Function],\n              },\n              \"fileName\": \"./src/ComponentOne.stories.js\",\n              \"throwPlayFunctionExceptions\": false,\n            },\n            \"story\": \"B\",\n            \"storyGlobals\": {},\n            \"storyId\": \"component-one--b\",\n            \"subcomponents\": undefined,\n            \"tags\": [\n              \"dev\",\n              \"test\",\n            ],\n            \"testingLibraryRender\": undefined,\n            \"title\": \"Component One\",\n            \"usesMount\": false,\n          },\n          \"component-one--e\": {\n            \"argTypes\": {},\n            \"args\": {},\n            \"component\": undefined,\n            \"componentId\": \"component-one\",\n            \"globals\": {\n              \"a\": \"b\",\n              \"backgrounds\": {\n                \"grid\": false,\n                \"value\": undefined,\n              },\n              \"measureEnabled\": false,\n              \"outline\": false,\n              \"viewport\": {\n                \"isRotated\": false,\n                \"value\": undefined,\n              },\n            },\n            \"id\": \"component-one--e\",\n            \"initialArgs\": {},\n            \"kind\": \"Component One\",\n            \"name\": \"E\",\n            \"parameters\": {\n              \"__isArgsStory\": false,\n              \"backgrounds\": {\n                \"disable\": false,\n                \"grid\": {\n                  \"cellAmount\": 5,\n                  \"cellSize\": 20,\n                  \"opacity\": 0.5,\n                },\n              },\n              \"docs\": {\n                \"page\": [MockFunction],\n                \"renderer\": [Function],\n              },\n              \"fileName\": \"./src/ExtraComponentOne.stories.js\",\n              \"throwPlayFunctionExceptions\": false,\n            },\n            \"playFunction\": undefined,\n            \"story\": \"E\",\n            \"storyGlobals\": {},\n            \"storyId\": \"component-one--e\",\n            \"subcomponents\": undefined,\n            \"tags\": [\n              \"dev\",\n              \"test\",\n            ],\n            \"testingLibraryRender\": undefined,\n            \"title\": \"Component One\",\n            \"usesMount\": false,\n          },\n          \"component-two--c\": {\n            \"argTypes\": {\n              \"foo\": {\n                \"name\": \"foo\",\n                \"type\": {\n                  \"name\": \"string\",\n                },\n              },\n            },\n            \"args\": {\n              \"foo\": \"c\",\n            },\n            \"component\": undefined,\n            \"componentId\": \"component-two\",\n            \"globals\": {\n              \"a\": \"b\",\n              \"backgrounds\": {\n                \"grid\": false,\n                \"value\": undefined,\n              },\n              \"measureEnabled\": false,\n              \"outline\": false,\n              \"viewport\": {\n                \"isRotated\": false,\n                \"value\": undefined,\n              },\n            },\n            \"id\": \"component-two--c\",\n            \"initialArgs\": {\n              \"foo\": \"c\",\n            },\n            \"kind\": \"Component Two\",\n            \"name\": \"C\",\n            \"parameters\": {\n              \"__isArgsStory\": false,\n              \"backgrounds\": {\n                \"disable\": false,\n                \"grid\": {\n                  \"cellAmount\": 5,\n                  \"cellSize\": 20,\n                  \"opacity\": 0.5,\n                },\n              },\n              \"docs\": {\n                \"renderer\": [Function],\n              },\n              \"fileName\": \"./src/ComponentTwo.stories.js\",\n              \"throwPlayFunctionExceptions\": false,\n            },\n            \"playFunction\": undefined,\n            \"story\": \"C\",\n            \"storyGlobals\": {},\n            \"storyId\": \"component-two--c\",\n            \"subcomponents\": undefined,\n            \"tags\": [\n              \"dev\",\n              \"test\",\n            ],\n            \"testingLibraryRender\": undefined,\n            \"title\": \"Component Two\",\n            \"usesMount\": false,\n          },\n        }\n      `);\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/PreviewWeb.tsx",
    "content": "import type { ModuleImportFn, ProjectAnnotations } from 'storybook/internal/types';\nimport type { Renderer } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport type { MaybePromise } from './Preview.tsx';\nimport { PreviewWithSelection } from './PreviewWithSelection.tsx';\nimport { UrlStore } from './UrlStore.ts';\nimport { WebView } from './WebView.ts';\n\nexport class PreviewWeb<TRenderer extends Renderer> extends PreviewWithSelection<TRenderer> {\n  constructor(\n    public importFn: ModuleImportFn,\n\n    public getProjectAnnotations: () => MaybePromise<ProjectAnnotations<TRenderer>>\n  ) {\n    super(importFn, getProjectAnnotations, new UrlStore(), new WebView());\n\n    global.__STORYBOOK_PREVIEW__ = this;\n  }\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/PreviewWithSelection.tsx",
    "content": "import { logger } from 'storybook/internal/client-logger';\nimport {\n  CURRENT_STORY_WAS_SET,\n  DOCS_PREPARED,\n  GLOBALS_UPDATED,\n  PRELOAD_ENTRIES,\n  PREVIEW_KEYDOWN,\n  SET_CURRENT_STORY,\n  STORY_CHANGED,\n  STORY_ERRORED,\n  STORY_MISSING,\n  STORY_PREPARED,\n  STORY_RENDER_PHASE_CHANGED,\n  STORY_SPECIFIED,\n  STORY_THREW_EXCEPTION,\n  STORY_UNCHANGED,\n  UPDATE_QUERY_PARAMS,\n} from 'storybook/internal/core-events';\nimport {\n  CalledPreviewMethodBeforeInitializationError,\n  EmptyIndexError,\n  MdxFileWithNoCsfReferencesError,\n  NoStoryMatchError,\n} from 'storybook/internal/preview-errors';\nimport type { DocsIndexEntry, StoryIndex } from 'storybook/internal/types';\nimport type { Args, Globals, Renderer, StoryId, ViewMode } from 'storybook/internal/types';\nimport type { ModuleImportFn, ProjectAnnotations } from 'storybook/internal/types';\n\nimport invariant from 'tiny-invariant';\n\nimport { Tag } from '../../../shared/constants/tags.ts';\nimport type { StorySpecifier } from '../store/StoryIndexStore.ts';\nimport type { MaybePromise } from './Preview.tsx';\nimport { Preview } from './Preview.tsx';\nimport type { Selection, SelectionStore } from './SelectionStore.ts';\nimport type { View } from './View.ts';\nimport { CsfDocsRender } from './render/CsfDocsRender.ts';\nimport { MdxDocsRender } from './render/MdxDocsRender.ts';\nimport { PREPARE_ABORTED } from './render/Render.ts';\nimport { StoryRender } from './render/StoryRender.ts';\n\nconst globalWindow = globalThis;\n\nfunction focusInInput(event: Event) {\n  const target = ((event.composedPath && event.composedPath()[0]) || event.target) as Element;\n  return /input|textarea/i.test(target.tagName) || target.getAttribute('contenteditable') !== null;\n}\n\n/** Was this docs entry generated by a .mdx file? (see discussion below) */\nexport function isMdxEntry({ tags }: DocsIndexEntry) {\n  return tags?.includes(Tag.UNATTACHED_MDX) || tags?.includes(Tag.ATTACHED_MDX);\n}\n\ntype PossibleRender<TRenderer extends Renderer> =\n  | StoryRender<TRenderer>\n  | CsfDocsRender<TRenderer>\n  | MdxDocsRender<TRenderer>;\n\nfunction isStoryRender<TRenderer extends Renderer>(\n  r: PossibleRender<TRenderer>\n): r is StoryRender<TRenderer> {\n  return r.type === 'story';\n}\n\nfunction isDocsRender<TRenderer extends Renderer>(\n  r: PossibleRender<TRenderer>\n): r is CsfDocsRender<TRenderer> | MdxDocsRender<TRenderer> {\n  return r.type === 'docs';\n}\n\nfunction isCsfDocsRender<TRenderer extends Renderer>(\n  r: PossibleRender<TRenderer>\n): r is CsfDocsRender<TRenderer> {\n  return isDocsRender(r) && r.subtype === 'csf';\n}\n\nexport class PreviewWithSelection<TRenderer extends Renderer> extends Preview<TRenderer> {\n  currentSelection?: Selection;\n\n  currentRender?: PossibleRender<TRenderer>;\n\n  constructor(\n    public importFn: ModuleImportFn,\n\n    public getProjectAnnotations: () => MaybePromise<ProjectAnnotations<TRenderer>>,\n\n    public selectionStore: SelectionStore,\n\n    public view: View<TRenderer['canvasElement']>\n  ) {\n    // We need to call initialize ourself (i.e. stop super() from doing it, with false)\n    // because otherwise this.view will not get set in time.\n    super(importFn, getProjectAnnotations, undefined, false);\n    this.initialize();\n  }\n\n  setupListeners() {\n    super.setupListeners();\n\n    globalWindow.onkeydown = this.onKeydown.bind(this);\n\n    this.channel.on(SET_CURRENT_STORY, this.onSetCurrentStory.bind(this));\n    this.channel.on(UPDATE_QUERY_PARAMS, this.onUpdateQueryParams.bind(this));\n    this.channel.on(PRELOAD_ENTRIES, this.onPreloadStories.bind(this));\n  }\n\n  async setInitialGlobals() {\n    if (!this.storyStoreValue) {\n      throw new CalledPreviewMethodBeforeInitializationError({ methodName: 'setInitialGlobals' });\n    }\n\n    const { globals } = this.selectionStore.selectionSpecifier || {};\n    if (globals) {\n      this.storyStoreValue.userGlobals.updateFromPersisted(globals);\n    }\n    this.emitGlobals();\n  }\n\n  // If initialization gets as far as the story index, this function runs.\n  async initializeWithStoryIndex(storyIndex: StoryIndex): Promise<void> {\n    await super.initializeWithStoryIndex(storyIndex);\n\n    return this.selectSpecifiedStory();\n  }\n\n  // Use the selection specifier to choose a story, then render it\n  async selectSpecifiedStory() {\n    if (!this.storyStoreValue) {\n      throw new CalledPreviewMethodBeforeInitializationError({\n        methodName: 'selectSpecifiedStory',\n      });\n    }\n\n    // If the story has been selected during initialization - if `SET_CURRENT_STORY` is\n    // emitted while we are loading the preview, we don't need to do any selection now.\n\n    // If the story has been selected during initialization - if `SET_CURRENT_STORY` is\n    // emitted while we are loading the preview, we don't need to do any selection now.\n    if (this.selectionStore.selection) {\n      await this.renderSelection();\n      return;\n    }\n\n    if (!this.selectionStore.selectionSpecifier) {\n      this.renderMissingStory();\n      return;\n    }\n\n    const { storySpecifier, args } = this.selectionStore.selectionSpecifier;\n    const entry = this.storyStoreValue.storyIndex.entryFromSpecifier(storySpecifier);\n\n    if (!entry) {\n      if (storySpecifier === '*') {\n        this.renderStoryLoadingException(storySpecifier, new EmptyIndexError());\n      } else {\n        this.renderStoryLoadingException(\n          storySpecifier,\n          new NoStoryMatchError({ storySpecifier: storySpecifier.toString() })\n        );\n      }\n\n      return;\n    }\n\n    const { id: storyId, type: viewMode } = entry;\n    this.selectionStore.setSelection({ storyId, viewMode });\n\n    this.channel.emit(STORY_SPECIFIED, this.selectionStore.selection);\n    this.channel.emit(CURRENT_STORY_WAS_SET, this.selectionStore.selection);\n\n    await this.renderSelection({ persistedArgs: args });\n  }\n\n  // EVENT HANDLERS\n\n  // This happens when a config file gets reloaded\n  async onGetProjectAnnotationsChanged({\n    getProjectAnnotations,\n  }: {\n    getProjectAnnotations: () => MaybePromise<ProjectAnnotations<TRenderer>>;\n  }) {\n    await super.onGetProjectAnnotationsChanged({ getProjectAnnotations });\n\n    if (this.selectionStore.selection) {\n      this.renderSelection();\n    }\n  }\n\n  // This happens when a glob gets HMR-ed\n  async onStoriesChanged({\n    importFn,\n    storyIndex,\n  }: {\n    importFn?: ModuleImportFn;\n    storyIndex?: StoryIndex;\n  }) {\n    await super.onStoriesChanged({ importFn, storyIndex });\n\n    if (this.selectionStore.selection) {\n      await this.renderSelection();\n    } else {\n      // Our selection has never applied before, but maybe it does now, let's try!\n      await this.selectSpecifiedStory();\n    }\n  }\n\n  onKeydown(event: KeyboardEvent) {\n    if (!this.storyRenders.find((r) => r.disableKeyListeners) && !focusInInput(event)) {\n      // We have to pick off the keys of the event that we need on the other side\n      const { altKey, ctrlKey, metaKey, shiftKey, key, code, keyCode } = event;\n      this.channel.emit(PREVIEW_KEYDOWN, {\n        event: { altKey, ctrlKey, metaKey, shiftKey, key, code, keyCode },\n      });\n    }\n  }\n\n  async onSetCurrentStory(selection: { storyId: StoryId; viewMode?: ViewMode }) {\n    /**\n     * At the end of the initialization promise we will read the current story from the selection\n     * store, so make sure we've updated it with the new selection or we'll lose track of it at the\n     * end of init.\n     */\n    this.selectionStore.setSelection({ viewMode: 'story', ...selection });\n\n    await this.storeInitializationPromise;\n\n    this.channel.emit(CURRENT_STORY_WAS_SET, this.selectionStore.selection);\n    this.renderSelection();\n  }\n\n  onUpdateQueryParams(queryParams: any) {\n    this.selectionStore.setQueryParams(queryParams);\n  }\n\n  async onUpdateGlobals({ globals }: { globals: Globals }) {\n    const currentStory =\n      (this.currentRender instanceof StoryRender && this.currentRender.story) || undefined;\n    super.onUpdateGlobals({ globals, currentStory });\n    if (\n      this.currentRender instanceof MdxDocsRender ||\n      this.currentRender instanceof CsfDocsRender\n    ) {\n      await this.currentRender.rerender?.();\n    }\n  }\n\n  async onUpdateArgs({ storyId, updatedArgs }: { storyId: StoryId; updatedArgs: Args }) {\n    super.onUpdateArgs({ storyId, updatedArgs });\n  }\n\n  async onPreloadStories({ ids }: { ids: string[] }) {\n    await this.storeInitializationPromise;\n\n    if (this.storyStoreValue) {\n      /**\n       * It's possible that we're trying to preload a story in a ref we haven't loaded the iframe\n       * for yet. Because of the way the targeting works, if we can't find the targeted iframe,\n       * we'll use the currently active iframe which can cause the event to be targeted to the wrong\n       * iframe, causing an error if the storyId does not exists there.\n       */\n      await Promise.allSettled(ids.map((id) => this.storyStoreValue?.loadEntry(id)));\n    }\n  }\n\n  // RENDERING\n\n  // We can either have:\n  // - a story selected in \"story\" viewMode,\n  //     in which case we render it to the root element, OR\n  // - a story selected in \"docs\" viewMode,\n  //     in which case we render the docsPage for that story\n  protected async renderSelection({ persistedArgs }: { persistedArgs?: Args } = {}) {\n    const { renderToCanvas } = this;\n\n    if (!this.storyStoreValue || !renderToCanvas) {\n      throw new CalledPreviewMethodBeforeInitializationError({ methodName: 'renderSelection' });\n    }\n\n    const { selection } = this.selectionStore;\n\n    if (!selection) {\n      throw new Error('Cannot call renderSelection as no selection was made');\n    }\n\n    const { storyId } = selection;\n    let entry;\n    try {\n      entry = await this.storyStoreValue.storyIdToEntry(storyId);\n    } catch (err) {\n      if (this.currentRender) {\n        await this.teardownRender(this.currentRender);\n      }\n      this.renderStoryLoadingException(storyId, err as Error);\n      return;\n    }\n\n    const storyIdChanged = this.currentSelection?.storyId !== storyId;\n    const viewModeChanged = this.currentRender?.type !== entry.type;\n\n    // Show a spinner while we load the next story\n    if (entry.type === 'story') {\n      this.view.showPreparingStory({ immediate: viewModeChanged });\n    } else {\n      this.view.showPreparingDocs({ immediate: viewModeChanged });\n    }\n\n    // If the last render is still preparing, let's drop it right now. Either\n    //   (a) it is a different story, which means we would drop it later, OR\n    //   (b) it is the *same* story, in which case we will resolve our own .prepare() at the\n    //       same moment anyway, and we should just \"take over\" the rendering.\n    // (We can't tell which it is yet, because it is possible that an HMR is going on and\n    //  even though the storyId is the same, the story itself is not).\n    if (this.currentRender?.isPreparing()) {\n      await this.teardownRender(this.currentRender);\n    }\n\n    let render: PossibleRender<TRenderer>;\n    if (entry.type === 'story') {\n      render = new StoryRender<TRenderer>(\n        this.channel,\n        this.storyStoreValue,\n        renderToCanvas,\n        this.mainStoryCallbacks(storyId),\n        storyId,\n        'story'\n      );\n    } else if (isMdxEntry(entry)) {\n      render = new MdxDocsRender<TRenderer>(\n        this.channel,\n        this.storyStoreValue,\n        entry,\n        this.mainStoryCallbacks(storyId)\n      );\n    } else {\n      render = new CsfDocsRender<TRenderer>(\n        this.channel,\n        this.storyStoreValue,\n        entry,\n        this.mainStoryCallbacks(storyId)\n      );\n    }\n\n    // We need to store this right away, so if the story changes during\n    // the async `.prepare()` below, we can (potentially) cancel it\n    const lastSelection = this.currentSelection;\n    this.currentSelection = selection;\n\n    const lastRender = this.currentRender;\n    this.currentRender = render;\n\n    try {\n      await render.prepare();\n    } catch (err) {\n      if (lastRender) {\n        await this.teardownRender(lastRender);\n      }\n\n      if (err !== PREPARE_ABORTED) {\n        this.renderStoryLoadingException(storyId, err as Error);\n      }\n      return;\n    }\n\n    const implementationChanged = !storyIdChanged && lastRender && !render.isEqual(lastRender);\n\n    if (persistedArgs && isStoryRender(render)) {\n      invariant(!!render.story);\n      this.storyStoreValue.args.updateFromPersisted(render.story, persistedArgs);\n    }\n\n    // Don't re-render the story if nothing has changed to justify it\n    if (\n      lastRender &&\n      !lastRender.torndown &&\n      !storyIdChanged &&\n      !implementationChanged &&\n      !viewModeChanged\n    ) {\n      this.currentRender = lastRender;\n      this.channel.emit(STORY_UNCHANGED, storyId);\n      this.view.showMain();\n      return;\n    }\n\n    // Wait for the previous render to leave the page. NOTE: this will wait to ensure anything async\n    // is properly aborted, which (in some cases) can lead to the whole screen being refreshed.\n\n    // Wait for the previous render to leave the page. NOTE: this will wait to ensure anything async\n    // is properly aborted, which (in some cases) can lead to the whole screen being refreshed.\n    if (lastRender) {\n      await this.teardownRender(lastRender, { viewModeChanged });\n    }\n\n    // If we are rendering something new (as opposed to re-rendering the same or first story), emit\n\n    // If we are rendering something new (as opposed to re-rendering the same or first story), emit\n    if (lastSelection && (storyIdChanged || viewModeChanged)) {\n      this.channel.emit(STORY_CHANGED, storyId);\n    }\n\n    if (isStoryRender(render)) {\n      invariant(!!render.story);\n      const {\n        parameters,\n        initialArgs,\n        argTypes,\n        unmappedArgs,\n        initialGlobals,\n        userGlobals,\n        storyGlobals,\n        globals,\n      } = this.storyStoreValue.getStoryContext(render.story);\n\n      this.channel.emit(STORY_PREPARED, {\n        id: storyId,\n        parameters,\n        initialArgs,\n        argTypes,\n        args: unmappedArgs,\n      });\n      // We need to update globals whenever we go in or out of an overridden story.\n      // As an optimization we could check if that's the case, but it seems complex and error-prone\n      this.channel.emit(GLOBALS_UPDATED, { userGlobals, storyGlobals, globals, initialGlobals });\n    } else {\n      // Default to the project parameters for MDX docs\n      let { parameters } = this.storyStoreValue.projectAnnotations;\n\n      // We need to update globals whenever we go in or out of an overridden story.\n      // As an optimization we could check if that's the case, but it seems complex and error-prone\n      const { initialGlobals, globals } = this.storyStoreValue.userGlobals;\n      this.channel.emit(GLOBALS_UPDATED, {\n        globals,\n        initialGlobals,\n        storyGlobals: {},\n        userGlobals: globals,\n      });\n\n      if (isCsfDocsRender(render) || render.entry.tags?.includes(Tag.ATTACHED_MDX)) {\n        if (!render.csfFiles) {\n          throw new MdxFileWithNoCsfReferencesError({ storyId });\n        }\n        ({ parameters } = this.storyStoreValue.preparedMetaFromCSFFile({\n          csfFile: render.csfFiles[0],\n        }));\n      }\n\n      this.channel.emit(DOCS_PREPARED, {\n        id: storyId,\n        parameters,\n      });\n    }\n\n    if (isStoryRender(render)) {\n      invariant(!!render.story);\n      this.storyRenders.push(render as StoryRender<TRenderer>);\n      (this.currentRender as StoryRender<TRenderer>).renderToElement(\n        this.view.prepareForStory(render.story)\n      );\n    } else {\n      this.currentRender.renderToElement(\n        this.view.prepareForDocs(),\n        // This argument is used for docs, which is currently only compatible with HTMLElements\n        this.renderStoryToElement.bind(this) as any\n      );\n    }\n  }\n\n  async teardownRender(\n    render: PossibleRender<TRenderer>,\n    { viewModeChanged = false }: { viewModeChanged?: boolean } = {}\n  ) {\n    this.storyRenders = this.storyRenders.filter((r) => r !== render);\n    await render?.teardown?.({ viewModeChanged });\n  }\n\n  // UTILITIES\n  mainStoryCallbacks(storyId: StoryId) {\n    return {\n      showStoryDuringRender: () => this.view.showStoryDuringRender(),\n      showMain: () => this.view.showMain(),\n      showError: (err: { title: string; description: string }) => this.renderError(storyId, err),\n      showException: (err: Error) => this.renderException(storyId, err),\n    };\n  }\n\n  renderPreviewEntryError(reason: string, err: Error) {\n    super.renderPreviewEntryError(reason, err);\n    this.view.showErrorDisplay(err);\n  }\n\n  renderMissingStory() {\n    this.view.showNoPreview();\n    this.channel.emit(STORY_MISSING);\n  }\n\n  renderStoryLoadingException(storySpecifier: StorySpecifier, err: Error) {\n    // logger.error(`Unable to load story '${storySpecifier}':`);\n    logger.error(err);\n    this.view.showErrorDisplay(err);\n    this.channel.emit(STORY_MISSING, storySpecifier);\n  }\n\n  // renderException is used if we fail to render the story and it is uncaught by the app layer\n  renderException(storyId: StoryId, error: Error) {\n    const { name = 'Error', message = String(error), stack } = error;\n    const renderId = this.currentRender?.renderId;\n    this.channel.emit(STORY_THREW_EXCEPTION, { name, message, stack });\n    this.channel.emit(STORY_RENDER_PHASE_CHANGED, { newPhase: 'errored', renderId, storyId });\n\n    this.view.showErrorDisplay(error);\n    logger.error(`Error rendering story '${storyId}':`);\n    logger.error(error);\n  }\n\n  // renderError is used by the various app layers to inform the user they have done something\n  // wrong -- for instance returned the wrong thing from a story\n  renderError(storyId: StoryId, { title, description }: { title: string; description: string }) {\n    const renderId = this.currentRender?.renderId;\n    this.channel.emit(STORY_ERRORED, { title, description });\n    this.channel.emit(STORY_RENDER_PHASE_CHANGED, { newPhase: 'errored', renderId, storyId });\n\n    this.view.showErrorDisplay({ message: title, stack: description });\n    logger.error(`Error rendering story ${title}: ${description}`);\n  }\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/SelectionStore.ts",
    "content": "import type { Args, StoryId, ViewMode } from 'storybook/internal/types';\n\nimport type { StorySpecifier } from '../store/StoryIndexStore.ts';\n\nexport interface SelectionSpecifier {\n  storySpecifier: StorySpecifier;\n  viewMode: ViewMode;\n  args?: Args;\n  globals?: Args;\n}\n\nexport interface Selection {\n  storyId: StoryId;\n  viewMode: ViewMode;\n}\n\nexport interface SelectionStore {\n  selectionSpecifier: SelectionSpecifier | null;\n\n  selection?: Selection;\n\n  setSelection(selection: Selection): void;\n\n  setQueryParams(queryParams: Record<PropertyKey, unknown>): void;\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/UrlStore.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { global } from '@storybook/global';\n\nimport { getSelectionSpecifierFromPath, pathToId, setPath } from './UrlStore.ts';\n\nconst { history, document } = global;\n\nvi.mock('@storybook/global', () => ({\n  global: {\n    history: { replaceState: vi.fn() },\n    document: {\n      location: {\n        pathname: 'pathname',\n        search: '',\n      },\n    },\n  },\n}));\n\ndescribe('UrlStore', () => {\n  describe('pathToId', () => {\n    it('should parse valid ids', () => {\n      expect(pathToId('/story/story--id')).toEqual('story--id');\n    });\n    it('should error on invalid ids', () => {\n      [null, '', '/whatever/story/story--id'].forEach((path: any) => {\n        expect(() => pathToId(path)).toThrow(/Invalid/);\n      });\n    });\n  });\n\n  describe('setPath', () => {\n    it('should navigate to storyId', () => {\n      setPath({ storyId: 'story--id', viewMode: 'story' });\n      expect(history.replaceState).toHaveBeenCalledWith(\n        {},\n        '',\n        'pathname?id=story--id&viewMode=story'\n      );\n    });\n    it('should replace legacy parameters but preserve others', () => {\n      document.location.search = '?foo=bar&selectedStory=selStory&selectedKind=selKind';\n      setPath({ storyId: 'story--id', viewMode: 'story' });\n      expect(history.replaceState).toHaveBeenCalledWith(\n        {},\n        '',\n        'pathname?foo=bar&id=story--id&viewMode=story'\n      );\n    });\n    it('should ignore + keep hashes', () => {\n      document.location.search = '?foo=bar&selectedStory=selStory&selectedKind=selKind';\n      document.location.hash = '#foobar';\n      setPath({ storyId: 'story--id', viewMode: 'story' });\n      expect(history.replaceState).toHaveBeenCalledWith(\n        {},\n        '',\n        'pathname?foo=bar&id=story--id&viewMode=story#foobar'\n      );\n    });\n  });\n\n  describe('getSelectionSpecifierFromPath', () => {\n    it('should handle no search', () => {\n      document.location.search = '';\n      expect(getSelectionSpecifierFromPath()).toEqual(null);\n    });\n    it('should handle id queries', () => {\n      document.location.search = '?id=story--id';\n      expect(getSelectionSpecifierFromPath()).toEqual({\n        storySpecifier: 'story--id',\n        viewMode: 'story',\n      });\n    });\n    it('should handle viewMode=story', () => {\n      document.location.search = '?id=story--id&viewMode=story';\n      expect(getSelectionSpecifierFromPath()).toEqual({\n        storySpecifier: 'story--id',\n        viewMode: 'story',\n      });\n    });\n    it('should handle viewMode=docs', () => {\n      document.location.search = '?id=story--id&viewMode=docs';\n      expect(getSelectionSpecifierFromPath()).toEqual({\n        storySpecifier: 'story--id',\n        viewMode: 'docs',\n      });\n    });\n    it('should ignore unsupported viewModes', () => {\n      document.location.search = '?id=about&viewMode=somethingelse';\n      expect(getSelectionSpecifierFromPath()).toEqual(null);\n    });\n    it('should handle id queries with *', () => {\n      document.location.search = '?id=*';\n      expect(getSelectionSpecifierFromPath()).toEqual({\n        storySpecifier: '*',\n        viewMode: 'story',\n      });\n    });\n    it('should parse args', () => {\n      document.location.search = '?id=story--id&args=obj.key:val';\n      expect(getSelectionSpecifierFromPath()).toEqual({\n        storySpecifier: 'story--id',\n        viewMode: 'story',\n        args: { obj: { key: 'val' } },\n      });\n    });\n    it('should handle singleStory param', () => {\n      document.location.search = '?id=abc&singleStory=true';\n      expect(getSelectionSpecifierFromPath()).toEqual({\n        storySpecifier: 'abc',\n        viewMode: 'story',\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/UrlStore.ts",
    "content": "import type { ViewMode } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { parse, stringify } from 'picoquery';\n\nimport type { Selection, SelectionSpecifier, SelectionStore } from './SelectionStore.ts';\nimport { parseArgsParam } from './parseArgsParam.ts';\n\nconst { history, document } = global;\n\nexport function pathToId(path: string) {\n  const match = (path || '').match(/^\\/story\\/(.+)/);\n  if (!match) {\n    throw new Error(`Invalid path '${path}',  must start with '/story/'`);\n  }\n  return match[1];\n}\n\nconst getQueryString = ({\n  selection,\n  extraParams,\n}: {\n  selection?: Selection;\n  extraParams?: Record<PropertyKey, unknown>;\n}) => {\n  const search = document?.location.search.slice(1);\n  const { path, selectedKind, selectedStory, ...rest } = parse(search);\n  const queryStr = stringify({\n    ...rest,\n    ...extraParams,\n    ...(selection && { id: selection.storyId, viewMode: selection.viewMode }),\n  });\n  return `?${queryStr}`;\n};\n\nexport const setPath = (selection?: Selection) => {\n  if (!selection) {\n    return;\n  }\n  const query = getQueryString({ selection });\n  const { hash = '' } = document.location;\n  document.title = selection.storyId;\n  history.replaceState({}, '', `${document.location.pathname}${query}${hash}`);\n};\n\ntype ValueOf<T> = T[keyof T];\nconst isObject = (val: Record<string, any>): val is object =>\n  val != null && typeof val === 'object' && Array.isArray(val) === false;\n\nconst getFirstString = (v: ValueOf<Record<PropertyKey, unknown>>): string | void => {\n  if (v === undefined) {\n    return undefined;\n  }\n  if (typeof v === 'string') {\n    return v;\n  }\n  if (Array.isArray(v)) {\n    return getFirstString(v[0]);\n  }\n  if (isObject(v as Record<PropertyKey, unknown>)) {\n    return getFirstString(\n      Object.values(v as Record<PropertyKey, unknown>).filter(Boolean) as string[]\n    );\n  }\n  return undefined;\n};\n\nexport const getSelectionSpecifierFromPath: () => SelectionSpecifier | null = () => {\n  if (typeof document !== 'undefined') {\n    const queryStr = document.location.search.slice(1);\n    const query = parse(queryStr);\n    const args = typeof query.args === 'string' ? parseArgsParam(query.args) : undefined;\n    const globals = typeof query.globals === 'string' ? parseArgsParam(query.globals) : undefined;\n\n    let viewMode = getFirstString(query.viewMode) as ViewMode;\n    if (typeof viewMode !== 'string' || !viewMode) {\n      viewMode = 'story';\n    } else if (!viewMode.match(/docs|story/)) {\n      return null;\n    }\n\n    const path = getFirstString(query.path);\n    const storyId = path ? pathToId(path) : getFirstString(query.id);\n\n    if (storyId) {\n      return { storySpecifier: storyId, args, globals, viewMode };\n    }\n  }\n\n  return null;\n};\n\nexport class UrlStore implements SelectionStore {\n  selectionSpecifier: SelectionSpecifier | null;\n\n  selection?: Selection;\n\n  constructor() {\n    this.selectionSpecifier = getSelectionSpecifierFromPath();\n  }\n\n  setSelection(selection: Selection) {\n    this.selection = selection;\n    setPath(this.selection);\n  }\n\n  setQueryParams(queryParams: Record<PropertyKey, unknown>) {\n    const query = getQueryString({ extraParams: queryParams });\n    const { hash = '' } = document.location;\n    history.replaceState({}, '', `${document.location.pathname}${query}${hash}`);\n  }\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/View.ts",
    "content": "import type { PreparedStory } from 'storybook/internal/types';\n\nexport interface View<TStorybookRoot> {\n  // Get ready to render a story, returning the element to render to\n  prepareForStory(story: PreparedStory<any>): TStorybookRoot;\n\n  prepareForDocs(): TStorybookRoot;\n\n  showErrorDisplay(err: { message?: string; stack?: string }): void;\n\n  showNoPreview(): void;\n\n  showPreparingStory(options?: { immediate: boolean }): void;\n\n  showPreparingDocs(options?: { immediate: boolean }): void;\n\n  showMain(): void;\n\n  showDocs(): void;\n\n  showStory(): void;\n\n  showStoryDuringRender(): void;\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/WebView.ts",
    "content": "import { logger } from 'storybook/internal/client-logger';\nimport type { PreparedStory } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport AnsiToHtml from 'ansi-to-html';\nimport { parse } from 'picoquery';\nimport { dedent } from 'ts-dedent';\n\nimport type { View } from './View.ts';\n\nconst { document } = global;\n\nconst PREPARING_DELAY = 100;\n\nenum Mode {\n  'MAIN' = 'MAIN',\n  'NOPREVIEW' = 'NOPREVIEW',\n  'PREPARING_STORY' = 'PREPARING_STORY',\n  'PREPARING_DOCS' = 'PREPARING_DOCS',\n  'ERROR' = 'ERROR',\n}\nconst classes: Record<Mode, string> = {\n  PREPARING_STORY: 'sb-show-preparing-story',\n  PREPARING_DOCS: 'sb-show-preparing-docs',\n  MAIN: 'sb-show-main',\n  NOPREVIEW: 'sb-show-nopreview',\n  ERROR: 'sb-show-errordisplay',\n};\n\nconst layoutClassMap = {\n  centered: 'sb-main-centered',\n  fullscreen: 'sb-main-fullscreen',\n  padded: 'sb-main-padded',\n} as const;\ntype Layout = keyof typeof layoutClassMap | 'none';\n\nconst ansiConverter = new AnsiToHtml({\n  escapeXML: true,\n});\n\nexport class WebView implements View<HTMLElement> {\n  private currentLayoutClass?: (typeof layoutClassMap)[keyof typeof layoutClassMap] | null;\n\n  private testing = false;\n\n  private preparingTimeout?: ReturnType<typeof setTimeout>;\n\n  constructor() {\n    // Special code for testing situations\n    if (typeof document !== 'undefined') {\n      const { __SPECIAL_TEST_PARAMETER__ } = parse(document.location.search.slice(1));\n      switch (__SPECIAL_TEST_PARAMETER__) {\n        case 'preparing-story': {\n          this.showPreparingStory();\n          this.testing = true;\n          break;\n        }\n        case 'preparing-docs': {\n          this.showPreparingDocs();\n          this.testing = true;\n          break;\n        }\n        default: // pass;\n      }\n    }\n  }\n\n  // Get ready to render a story, returning the element to render to\n  prepareForStory(story: PreparedStory<any>) {\n    this.showStory();\n    this.applyLayout(story.parameters.layout);\n\n    document.documentElement.scrollTop = 0;\n    document.documentElement.scrollLeft = 0;\n\n    return this.storyRoot();\n  }\n\n  storyRoot(): HTMLElement {\n    return document.getElementById('storybook-root')!;\n  }\n\n  prepareForDocs() {\n    this.showMain();\n    this.showDocs();\n    this.applyLayout('fullscreen');\n\n    document.documentElement.scrollTop = 0;\n    document.documentElement.scrollLeft = 0;\n\n    return this.docsRoot();\n  }\n\n  docsRoot(): HTMLElement {\n    return document.getElementById('storybook-docs')!;\n  }\n\n  applyLayout(layout: Layout = 'padded') {\n    if (layout === 'none') {\n      document.body.classList.remove(this.currentLayoutClass!);\n      this.currentLayoutClass = null;\n      return;\n    }\n\n    this.checkIfLayoutExists(layout);\n\n    const layoutClass = layoutClassMap[layout];\n\n    document.body.classList.remove(this.currentLayoutClass!);\n    document.body.classList.add(layoutClass);\n    this.currentLayoutClass = layoutClass;\n  }\n\n  checkIfLayoutExists(layout: keyof typeof layoutClassMap) {\n    if (!layoutClassMap[layout]) {\n      logger.warn(\n        dedent`\n          The desired layout: ${layout} is not a valid option.\n          The possible options are: ${Object.keys(layoutClassMap).join(', ')}, none.\n        `\n      );\n    }\n  }\n\n  showMode(mode: Mode) {\n    clearTimeout(this.preparingTimeout);\n    Object.keys(Mode).forEach((otherMode) => {\n      if (otherMode === mode) {\n        document.body.classList.add(classes[otherMode]);\n      } else {\n        document.body.classList.remove(classes[otherMode as Mode]);\n      }\n    });\n  }\n\n  showErrorDisplay({ message = '', stack = '' }) {\n    let header = message;\n    let detail = stack;\n    const parts = message.split('\\n');\n    if (parts.length > 1) {\n      [header] = parts;\n      detail = parts.slice(1).join('\\n').replace(/^\\n/, '');\n    }\n\n    document.getElementById('error-message')!.innerHTML = ansiConverter.toHtml(header);\n    document.getElementById('error-stack')!.innerHTML = ansiConverter.toHtml(detail);\n\n    this.showMode(Mode.ERROR);\n  }\n\n  showNoPreview() {\n    if (this.testing) {\n      return;\n    }\n\n    this.showMode(Mode.NOPREVIEW);\n\n    // In storyshots this can get called and these two can be null\n    this.storyRoot()?.setAttribute('hidden', 'true');\n    this.docsRoot()?.setAttribute('hidden', 'true');\n  }\n\n  showPreparingStory({ immediate = false } = {}) {\n    clearTimeout(this.preparingTimeout);\n\n    if (immediate) {\n      this.showMode(Mode.PREPARING_STORY);\n    } else {\n      this.preparingTimeout = setTimeout(\n        () => this.showMode(Mode.PREPARING_STORY),\n        PREPARING_DELAY\n      );\n    }\n  }\n\n  showPreparingDocs({ immediate = false } = {}) {\n    clearTimeout(this.preparingTimeout);\n    if (immediate) {\n      this.showMode(Mode.PREPARING_DOCS);\n    } else {\n      this.preparingTimeout = setTimeout(() => this.showMode(Mode.PREPARING_DOCS), PREPARING_DELAY);\n    }\n  }\n\n  showMain() {\n    this.showMode(Mode.MAIN);\n  }\n\n  showDocs() {\n    this.storyRoot().setAttribute('hidden', 'true');\n    this.docsRoot().removeAttribute('hidden');\n  }\n\n  showStory() {\n    this.docsRoot().setAttribute('hidden', 'true');\n    this.storyRoot().removeAttribute('hidden');\n  }\n\n  showStoryDuringRender() {\n    // When 'showStory' is called (at the start of rendering) we get rid of our display:none\n    // from all children of the root (but keep the preparing spinner visible). This may mean\n    // that very weird and high z-index stories are briefly visible.\n    // See https://github.com/storybookjs/storybook/issues/16847 and\n    //   http://localhost:9011/?path=/story/core-rendering--auto-focus (official SB)\n    document.body.classList.add(classes.MAIN);\n  }\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { Channel } from 'storybook/internal/channels';\nimport type { CSFFile, Renderer } from 'storybook/internal/types';\n\nimport type { StoryStore } from '../../store/index.ts';\nimport { DocsContext } from './DocsContext.ts';\nimport { csfFileParts } from './test-utils.ts';\n\nconst channel = new Channel({});\nconst renderStoryToElement = vi.fn();\n\ndescribe('referenceCSFFile', () => {\n  it('deals with unattached \"docsOnly\" csf files', () => {\n    const unattachedCsfFile = {\n      stories: {\n        'meta--page': {\n          id: 'meta--page',\n          name: 'Page',\n          parameters: { docsOnly: true },\n          moduleExport: {},\n        },\n      },\n      meta: { id: 'meta', title: 'Meta' },\n      moduleExports: {},\n    } as CSFFile;\n\n    const store = {\n      componentStoriesFromCSFFile: () => [],\n    } as unknown as StoryStore<Renderer>;\n    const context = new DocsContext(channel, store, renderStoryToElement, [unattachedCsfFile]);\n\n    expect(() => context.storyById()).toThrow(/No primary story/);\n  });\n});\n\ndescribe('attachCSFFile', () => {\n  const firstCsfParts = csfFileParts('first-meta--first-story', 'first-meta');\n  const secondCsfParts = csfFileParts('second-meta--second-story', 'second-meta');\n  const store = {\n    componentStoriesFromCSFFile: ({ csfFile }: { csfFile: CSFFile }) =>\n      csfFile === firstCsfParts.csfFile ? [firstCsfParts.story] : [secondCsfParts.story],\n  } as unknown as StoryStore<Renderer>;\n\n  it('attaches multiple CSF files', () => {\n    // Arrange - create a context with both CSF files\n    const context = new DocsContext(channel, store, renderStoryToElement, [\n      firstCsfParts.csfFile,\n      secondCsfParts.csfFile,\n    ]);\n\n    // Act - attach the first CSF file\n    context.attachCSFFile(firstCsfParts.csfFile);\n\n    // Assert - the first story is now the primary story and the only component story\n    expect(context.storyById()).toEqual(firstCsfParts.story);\n    expect(context.componentStories()).toEqual([firstCsfParts.story]);\n\n    // Assert - stories from both CSF files are available\n    expect(context.componentStoriesFromCSFFile(firstCsfParts.csfFile)).toEqual([\n      firstCsfParts.story,\n    ]);\n    expect(context.componentStoriesFromCSFFile(secondCsfParts.csfFile)).toEqual([\n      secondCsfParts.story,\n    ]);\n\n    // Act - attach the second CSF file\n    context.attachCSFFile(secondCsfParts.csfFile);\n\n    // Assert - the first story is still the primary story but both stories are available\n    expect(context.storyById()).toEqual(firstCsfParts.story);\n    expect(context.componentStories()).toEqual([firstCsfParts.story, secondCsfParts.story]);\n\n    // Act - attach the second CSF file again\n    context.attachCSFFile(secondCsfParts.csfFile);\n\n    // Assert - still only two stories are available\n    expect(context.storyById()).toEqual(firstCsfParts.story);\n    expect(context.componentStories()).toEqual([firstCsfParts.story, secondCsfParts.story]);\n  });\n});\n\ndescribe('referenceMeta', () => {\n  it('works with different module namespace object but same default export (Rolldown compatibility)', () => {\n    // This test simulates what happens with Rolldown bundler:\n    // The module namespace object from MDX import differs from the one stored in CSFFile,\n    // but the .default property (meta export) is the same object reference\n    const { story, csfFile, metaExport, storyExport } = csfFileParts();\n    const store = {\n      componentStoriesFromCSFFile: () => [story],\n    } as unknown as StoryStore<Renderer>;\n    const context = new DocsContext(channel, store, renderStoryToElement, [csfFile]);\n\n    // Create a different namespace object with the same default export\n    // This simulates Rolldown's behavior where namespace objects are not singletons\n    const differentModuleExports = { default: metaExport, story: storyExport };\n\n    // This should NOT throw, as we can resolve via the .default property\n    expect(() => context.referenceMeta(differentModuleExports, true)).not.toThrow();\n    expect(context.storyById()).toEqual(story);\n  });\n\n  it('throws for non-module objects (components)', () => {\n    const { story, csfFile, component } = csfFileParts();\n    const store = {\n      componentStoriesFromCSFFile: () => [story],\n    } as unknown as StoryStore<Renderer>;\n    const context = new DocsContext(channel, store, renderStoryToElement, [csfFile]);\n\n    // Passing a component directly should throw\n    expect(() => context.referenceMeta(component, true)).toThrow(\n      '<Meta of={} /> must reference a CSF file module export or meta export. Did you mistakenly reference your component instead of your CSF file?'\n    );\n  });\n});\n\ndescribe('resolveOf', () => {\n  const { story, csfFile, storyExport, metaExport, moduleExports, component } = csfFileParts();\n\n  describe('attached', () => {\n    const projectAnnotations = { render: vi.fn() };\n    const store = {\n      componentStoriesFromCSFFile: () => [story],\n      preparedMetaFromCSFFile: () => ({ prepareMeta: 'preparedMeta' }),\n      projectAnnotations,\n    } as unknown as StoryStore<Renderer>;\n    const context = new DocsContext(channel, store, renderStoryToElement, [csfFile]);\n    context.attachCSFFile(csfFile);\n\n    it('works for story exports', () => {\n      expect(context.resolveOf(storyExport)).toEqual({ type: 'story', story });\n    });\n\n    it('works for meta exports', () => {\n      expect(context.resolveOf(metaExport)).toEqual({\n        type: 'meta',\n        csfFile,\n        preparedMeta: expect.any(Object),\n      });\n    });\n\n    it('works for full module exports', () => {\n      expect(context.resolveOf(moduleExports)).toEqual({\n        type: 'meta',\n        csfFile,\n        preparedMeta: expect.any(Object),\n      });\n    });\n\n    it('works for module exports with different object identity but same default (Rolldown compatibility)', () => {\n      // Simulate what happens in Rolldown: different namespace object but same default export\n      const differentModuleExports = { default: metaExport, story: storyExport };\n      expect(context.resolveOf(differentModuleExports)).toEqual({\n        type: 'meta',\n        csfFile,\n        preparedMeta: expect.any(Object),\n      });\n    });\n\n    it('works for components', () => {\n      expect(context.resolveOf(component)).toEqual({\n        type: 'component',\n        component,\n        projectAnnotations: expect.objectContaining(projectAnnotations),\n      });\n    });\n\n    it('finds primary story', () => {\n      expect(context.resolveOf('story')).toEqual({ type: 'story', story });\n    });\n\n    it('finds attached CSF file', () => {\n      expect(context.resolveOf('meta')).toEqual({\n        type: 'meta',\n        csfFile,\n        preparedMeta: expect.any(Object),\n      });\n    });\n\n    it('finds attached component', () => {\n      expect(context.resolveOf('component')).toEqual({\n        type: 'component',\n        component,\n        projectAnnotations: expect.objectContaining(projectAnnotations),\n      });\n    });\n\n    describe('validation allowed', () => {\n      it('works for story exports', () => {\n        expect(context.resolveOf(storyExport, ['story'])).toEqual({ type: 'story', story });\n      });\n\n      it('works for meta exports', () => {\n        expect(context.resolveOf(metaExport, ['meta'])).toEqual({\n          type: 'meta',\n          csfFile,\n          preparedMeta: expect.any(Object),\n        });\n      });\n\n      it('works for full module exports', () => {\n        expect(context.resolveOf(moduleExports, ['meta'])).toEqual({\n          type: 'meta',\n          csfFile,\n          preparedMeta: expect.any(Object),\n        });\n      });\n\n      it('works for components', () => {\n        expect(context.resolveOf(component, ['component'])).toEqual({\n          type: 'component',\n          component,\n          projectAnnotations: expect.objectContaining(projectAnnotations),\n        });\n      });\n\n      it('finds primary story', () => {\n        expect(context.resolveOf('story', ['story'])).toEqual({ type: 'story', story });\n      });\n\n      it('finds attached CSF file', () => {\n        expect(context.resolveOf('meta', ['meta'])).toEqual({\n          type: 'meta',\n          csfFile,\n          preparedMeta: expect.any(Object),\n        });\n      });\n\n      it('finds attached component', () => {\n        expect(context.resolveOf('component', ['component'])).toEqual({\n          type: 'component',\n          component,\n          projectAnnotations: expect.objectContaining(projectAnnotations),\n        });\n      });\n    });\n\n    describe('validation rejected', () => {\n      it('works for story exports', () => {\n        expect(() => context.resolveOf(storyExport, ['meta'])).toThrow('Invalid value passed');\n      });\n\n      it('works for meta exports', () => {\n        expect(() => context.resolveOf(metaExport, ['story'])).toThrow('Invalid value passed');\n      });\n\n      it('works for full module exports', () => {\n        expect(() => context.resolveOf(moduleExports, ['story'])).toThrow('Invalid value passed');\n      });\n\n      it('works for components', () => {\n        expect(() => context.resolveOf(component, ['story', 'meta'])).toThrow(\n          'Invalid value passed'\n        );\n      });\n\n      it('finds primary story', () => {\n        expect(() => context.resolveOf('story', ['component'])).toThrow('Invalid value passed');\n      });\n\n      it('finds attached CSF file', () => {\n        expect(() => context.resolveOf('meta', ['story'])).toThrow('Invalid value passed');\n      });\n\n      it('finds attached component', () => {\n        expect(() => context.resolveOf('component', ['meta'])).toThrow('Invalid value passed');\n      });\n    });\n  });\n\n  describe('unattached', () => {\n    const projectAnnotations = { render: vi.fn() };\n    const store = {\n      componentStoriesFromCSFFile: () => [story],\n      preparedMetaFromCSFFile: () => ({ prepareMeta: 'preparedMeta' }),\n      projectAnnotations,\n    } as unknown as StoryStore<Renderer>;\n    const context = new DocsContext(channel, store, renderStoryToElement, [csfFile]);\n\n    it('works for story exports', () => {\n      expect(context.resolveOf(storyExport)).toEqual({ type: 'story', story });\n    });\n\n    it('works for meta exports', () => {\n      expect(context.resolveOf(metaExport)).toEqual({\n        type: 'meta',\n        csfFile,\n        preparedMeta: expect.any(Object),\n      });\n    });\n\n    it('works for full module exports', () => {\n      expect(context.resolveOf(moduleExports)).toEqual({\n        type: 'meta',\n        csfFile,\n        preparedMeta: expect.any(Object),\n      });\n    });\n\n    it('works for components', () => {\n      expect(context.resolveOf(component)).toEqual({\n        type: 'component',\n        component,\n        projectAnnotations: expect.objectContaining(projectAnnotations),\n      });\n    });\n\n    it('throws for primary story', () => {\n      expect(() => context.resolveOf('story')).toThrow('No primary story attached');\n    });\n\n    it('throws for attached CSF file', () => {\n      expect(() => context.resolveOf('meta')).toThrow('No CSF file attached');\n    });\n\n    it('throws for attached component', () => {\n      expect(() => context.resolveOf('component')).toThrow('No CSF file attached');\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/docs-context/DocsContext.ts",
    "content": "import type { Channel } from 'storybook/internal/channels';\nimport { isStory } from 'storybook/internal/csf';\nimport type {\n  CSFFile,\n  ModuleExport,\n  ModuleExports,\n  PreparedStory,\n  Renderer,\n  ResolvedModuleExportFromType,\n  ResolvedModuleExportType,\n  StoryId,\n  StoryName,\n} from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\n\nimport { type StoryStore } from '../../store/index.ts';\nimport type { DocsContextProps } from './DocsContextProps.ts';\n\nexport class DocsContext<TRenderer extends Renderer> implements DocsContextProps<TRenderer> {\n  private componentStoriesValue: PreparedStory<TRenderer>[];\n\n  private storyIdToCSFFile: Map<StoryId, CSFFile<TRenderer>>;\n\n  private exportToStory: Map<ModuleExport, PreparedStory<TRenderer>>;\n\n  private exportsToCSFFile: Map<ModuleExports, CSFFile<TRenderer>>;\n\n  private nameToStoryId: Map<StoryName, StoryId>;\n\n  private attachedCSFFiles: Set<CSFFile<TRenderer>>;\n\n  private primaryStory?: PreparedStory<TRenderer>;\n\n  constructor(\n    public channel: Channel,\n    protected store: StoryStore<TRenderer>,\n    public renderStoryToElement: DocsContextProps<TRenderer>['renderStoryToElement'],\n    /** The CSF files known (via the index) to be refererenced by this docs file */\n    csfFiles: CSFFile<TRenderer>[]\n  ) {\n    this.componentStoriesValue = [];\n    this.storyIdToCSFFile = new Map();\n    this.exportToStory = new Map();\n    this.exportsToCSFFile = new Map();\n    this.nameToStoryId = new Map();\n    this.attachedCSFFiles = new Set();\n\n    csfFiles.forEach((csfFile, index) => {\n      this.referenceCSFFile(csfFile);\n    });\n  }\n\n  // This docs entry references this CSF file and can synchronously load the stories, as well\n  // as reference them by module export. If the CSF is part of the \"component\" stories, they\n  // can also be referenced by name and are in the componentStories list.\n  referenceCSFFile(csfFile: CSFFile<TRenderer>) {\n    this.exportsToCSFFile.set(csfFile.moduleExports, csfFile);\n    // Also set the default export as the component's exports,\n    // to allow `import ButtonStories from './Button.stories'`\n    this.exportsToCSFFile.set(csfFile.moduleExports.default, csfFile);\n\n    const stories = this.store.componentStoriesFromCSFFile({ csfFile });\n\n    stories.forEach((story) => {\n      const annotation = csfFile.stories[story.id];\n      this.storyIdToCSFFile.set(annotation.id, csfFile);\n      this.exportToStory.set(annotation.moduleExport, story);\n    });\n  }\n\n  attachCSFFile(csfFile: CSFFile<TRenderer>) {\n    if (!this.exportsToCSFFile.has(csfFile.moduleExports)) {\n      throw new Error('Cannot attach a CSF file that has not been referenced');\n    }\n    if (this.attachedCSFFiles.has(csfFile)) {\n      // this CSF file is already attached, don't do anything\n      return;\n    }\n\n    this.attachedCSFFiles.add(csfFile);\n\n    const stories = this.store.componentStoriesFromCSFFile({ csfFile });\n\n    stories.forEach((story) => {\n      this.nameToStoryId.set(story.name, story.id);\n      this.componentStoriesValue.push(story);\n\n      if (!this.primaryStory) {\n        this.primaryStory = story;\n      }\n    });\n  }\n\n  referenceMeta(metaExports: ModuleExports, attach: boolean) {\n    const resolved = this.resolveModuleExport(metaExports);\n\n    if (resolved.type !== 'meta') {\n      throw new Error(\n        '<Meta of={} /> must reference a CSF file module export or meta export. Did you mistakenly reference your component instead of your CSF file?'\n      );\n    }\n\n    if (attach) {\n      this.attachCSFFile(resolved.csfFile);\n    }\n  }\n\n  get projectAnnotations() {\n    const { projectAnnotations } = this.store;\n    if (!projectAnnotations) {\n      throw new Error(\"Can't get projectAnnotations from DocsContext before they are initialized\");\n    }\n    return projectAnnotations;\n  }\n\n  private resolveAttachedModuleExportType<TType extends ResolvedModuleExportType>(\n    moduleExportType: TType\n  ): ResolvedModuleExportFromType<TType, TRenderer> {\n    type TResolvedExport = ResolvedModuleExportFromType<TType, TRenderer>;\n\n    if (moduleExportType === 'story') {\n      // If passed a type, we return the attached file, component or primary story\n      if (!this.primaryStory) {\n        throw new Error(\n          `No primary story attached to this docs file, did you forget to use <Meta of={} />?`\n        );\n      }\n\n      return { type: 'story', story: this.primaryStory } as TResolvedExport;\n    }\n\n    if (this.attachedCSFFiles.size === 0) {\n      throw new Error(\n        `No CSF file attached to this docs file, did you forget to use <Meta of={} />?`\n      );\n    }\n\n    const firstAttachedCSFFile = Array.from(this.attachedCSFFiles)[0];\n\n    if (moduleExportType === 'meta') {\n      return { type: 'meta', csfFile: firstAttachedCSFFile } as TResolvedExport;\n    }\n\n    const { component } = firstAttachedCSFFile.meta;\n\n    if (!component) {\n      throw new Error(\n        `Attached CSF file does not defined a component, did you forget to export one?`\n      );\n    }\n    return { type: 'component', component } as TResolvedExport;\n  }\n\n  private resolveModuleExport<TType extends ResolvedModuleExportType>(\n    moduleExportOrType: ModuleExport\n  ): ResolvedModuleExportFromType<TType, TRenderer> {\n    type TResolvedExport = ResolvedModuleExportFromType<TType, TRenderer>;\n\n    let csfFile = this.exportsToCSFFile.get(moduleExportOrType);\n\n    // If direct lookup fails and the object has a .default property,\n    // try looking up by the default export. This handles bundlers like Rolldown\n    // that don't preserve module namespace object identity across imports.\n    if (\n      !csfFile &&\n      moduleExportOrType &&\n      typeof moduleExportOrType === 'object' &&\n      'default' in moduleExportOrType\n    ) {\n      csfFile = this.exportsToCSFFile.get((moduleExportOrType as ModuleExports).default);\n    }\n\n    if (csfFile) {\n      return { type: 'meta', csfFile } as TResolvedExport;\n    }\n\n    const story = this.exportToStory.get(\n      isStory(moduleExportOrType) ? moduleExportOrType.input : moduleExportOrType\n    );\n\n    if (story) {\n      return { type: 'story', story } as TResolvedExport;\n    }\n\n    // If the export isn't a module, default or story export, we assume it is a component\n    return { type: 'component', component: moduleExportOrType } as TResolvedExport;\n  }\n\n  resolveOf<TType extends ResolvedModuleExportType>(\n    moduleExportOrType: ModuleExport | TType,\n    validTypes: TType[] = []\n  ): ResolvedModuleExportFromType<TType, TRenderer> {\n    type TResolvedExport = ResolvedModuleExportFromType<TType, TRenderer>;\n\n    let resolved: TResolvedExport;\n    if (['component', 'meta', 'story'].includes(moduleExportOrType)) {\n      const type = moduleExportOrType as TType;\n      resolved = this.resolveAttachedModuleExportType(type);\n    } else {\n      resolved = this.resolveModuleExport(moduleExportOrType);\n    }\n\n    if (validTypes.length && !validTypes.includes(resolved.type as TType)) {\n      const prettyType = resolved.type === 'component' ? 'component or unknown' : resolved.type;\n      throw new Error(dedent`Invalid value passed to the 'of' prop. The value was resolved to a '${prettyType}' type but the only types for this block are: ${validTypes.join(\n        ', '\n      )}.\n        - Did you pass a component to the 'of' prop when the block only supports a story or a meta?\n        - ... or vice versa?\n        - Did you pass a story, CSF file or meta to the 'of' prop that is not indexed, ie. is not targeted by the 'stories' globs in the main configuration?`);\n    }\n\n    switch (resolved.type) {\n      case 'component': {\n        return {\n          ...resolved,\n          projectAnnotations: this.projectAnnotations,\n        };\n      }\n      case 'meta': {\n        return {\n          ...resolved,\n          preparedMeta: this.store.preparedMetaFromCSFFile({ csfFile: resolved.csfFile }),\n        };\n      }\n      case 'story':\n      default: {\n        return resolved;\n      }\n    }\n  }\n\n  storyIdByName = (storyName: StoryName) => {\n    const storyId = this.nameToStoryId.get(storyName);\n\n    if (storyId) {\n      return storyId;\n    }\n\n    throw new Error(`No story found with that name: ${storyName}`);\n  };\n\n  componentStories = () => {\n    return this.componentStoriesValue;\n  };\n\n  componentStoriesFromCSFFile = (csfFile: CSFFile<TRenderer>) => {\n    return this.store.componentStoriesFromCSFFile({ csfFile });\n  };\n\n  storyById = (storyId?: StoryId) => {\n    if (!storyId) {\n      if (!this.primaryStory) {\n        throw new Error(\n          `No primary story defined for docs entry. Did you forget to use \\`<Meta>\\`?`\n        );\n      }\n\n      return this.primaryStory;\n    }\n    const csfFile = this.storyIdToCSFFile.get(storyId);\n\n    if (!csfFile) {\n      throw new Error(`Called \\`storyById\\` for story that was never loaded: ${storyId}`);\n    }\n    return this.store.storyFromCSFFile({ storyId, csfFile });\n  };\n\n  getStoryContext = (story: PreparedStory<TRenderer>) => {\n    return {\n      ...this.store.getStoryContext(story),\n      loaded: {},\n      viewMode: 'docs',\n    };\n  };\n\n  loadStory = (id: StoryId) => {\n    return this.store.loadStory({ storyId: id });\n  };\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/docs-context/DocsContextProps.ts",
    "content": "export type { DocsContextProps } from 'storybook/internal/types';\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/docs-context/DocsRenderFunction.ts",
    "content": "export type { DocsRenderFunction } from 'storybook/internal/types';\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/docs-context/test-utils.ts",
    "content": "import type { CSFFile, PreparedStory } from 'storybook/internal/types';\n\nexport function csfFileParts(storyId = 'meta--story', metaId = 'meta') {\n  // These compose the raw exports of the CSF file\n  const component = {};\n  const metaExport = { component };\n  const storyExport = {};\n  const moduleExports = { default: metaExport, story: storyExport };\n\n  // This is the prepared story + CSF file after SB has processed them\n  const storyAnnotations = {\n    id: storyId,\n    moduleExport: storyExport,\n  } as CSFFile['stories'][string];\n  const story = { id: storyId, moduleExport: storyExport } as PreparedStory;\n  const meta = { id: metaId, title: 'Meta', component, moduleExports } as CSFFile['meta'];\n  const csfFile = {\n    stories: { [storyId]: storyAnnotations },\n    meta,\n    moduleExports,\n  } as CSFFile;\n\n  return {\n    component,\n    metaExport,\n    storyExport,\n    moduleExports,\n    storyAnnotations,\n    story,\n    meta,\n    csfFile,\n  };\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/emitTransformCode.ts",
    "content": "import type { Args, StoryContext } from 'storybook/internal/csf';\n\nimport { SNIPPET_RENDERED } from '../../../docs-tools/index.ts';\nimport { addons } from '../addons/index.ts';\n\ntype ReducedStoryContext = Omit<\n  StoryContext<any, Args>,\n  'abortSignal' | 'canvasElement' | 'step' | 'context'\n>;\n\ntype Transformer =\n  | ((code: string, storyContext: ReducedStoryContext) => string | Promise<string>)\n  | undefined;\n\nexport async function emitTransformCode(source: string | undefined, context: ReducedStoryContext) {\n  const transform = context.parameters?.docs?.source?.transform as Transformer;\n  const { id, unmappedArgs } = context;\n\n  const transformed = transform && source ? transform?.(source, context) : source;\n  const result = transformed ? await transformed : undefined;\n\n  addons.getChannel().emit(SNIPPET_RENDERED, {\n    id,\n    source: result,\n    args: unmappedArgs,\n  });\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/index.ts",
    "content": "// FIXME: breaks builder-vite, remove this in 7.0\nexport { composeConfigs } from '../../store.ts';\nexport type { ProjectAnnotations as WebProjectAnnotations } from 'storybook/internal/types';\n\nexport { Preview } from './Preview.tsx';\nexport { PreviewWeb } from './PreviewWeb.tsx';\nexport { PreviewWithSelection } from './PreviewWithSelection.tsx';\n\nexport type { SelectionStore } from './SelectionStore.ts';\nexport { UrlStore } from './UrlStore.ts';\nexport type { View } from './View.ts';\nexport { WebView } from './WebView.ts';\n\nexport { simulatePageLoad, simulateDOMContentLoaded } from './simulate-pageload.ts';\n\nexport { DocsContext } from './docs-context/DocsContext.ts';\nexport type { DocsContextProps } from './docs-context/DocsContextProps.ts';\nexport type { DocsRenderFunction } from './docs-context/DocsRenderFunction.ts';\nexport { emitTransformCode } from './emitTransformCode.ts';\n\nexport { pauseAnimations, waitForAnimations } from './render/animation-utils.ts';\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/parseArgsParam.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { parseArgsParam } from './parseArgsParam.ts';\n\nvi.mock('storybook/internal/client-logger', () => ({\n  once: { warn: vi.fn() },\n}));\n\ndescribe('parseArgsParam', () => {\n  it('parses a simple key-value pair', () => {\n    const args = parseArgsParam('key:val');\n    expect(args).toStrictEqual({ key: 'val' });\n  });\n\n  it('parses spaces', () => {\n    const args = parseArgsParam('key:one+two+three');\n    expect(args).toStrictEqual({ key: 'one two three' });\n  });\n\n  it('parses null', () => {\n    const args = parseArgsParam('key:!null');\n    expect(args).toStrictEqual({ key: null });\n  });\n\n  it('parses undefined', () => {\n    const args = parseArgsParam('key:!undefined');\n    expect(args).toStrictEqual({ key: undefined });\n  });\n\n  it('parses true', () => {\n    const args = parseArgsParam('key:!true');\n    expect(args).toStrictEqual({ key: true });\n  });\n\n  it('parses false', () => {\n    const args = parseArgsParam('key:!false');\n    expect(args).toStrictEqual({ key: false });\n  });\n\n  it('parses hex color values', () => {\n    const args = parseArgsParam('key:!hex(ff4785)');\n    expect(args).toStrictEqual({ key: '#ff4785' });\n  });\n\n  it('parses rgba color values', () => {\n    const args = parseArgsParam('rgb:!rgb(255,71,133);rgba:!rgba(255,71,133,0.5)');\n    expect(args).toStrictEqual({ rgb: 'rgb(255, 71, 133)', rgba: 'rgba(255, 71, 133, 0.5)' });\n  });\n\n  it('parses hsla color values', () => {\n    const args = parseArgsParam('hsl:!hsl(45,99,70);hsla:!hsla(45,99,70,0.5)');\n    expect(args).toStrictEqual({ hsl: 'hsl(45, 99%, 70%)', hsla: 'hsla(45, 99%, 70%, 0.5)' });\n  });\n\n  it('parses Date', () => {\n    const args = parseArgsParam('key:!date(2001-02-03T04:05:06.789Z)');\n    expect(args).toStrictEqual({ key: new Date('2001-02-03T04:05:06.789Z') });\n  });\n\n  it('parses Date with timezone offset', () => {\n    const args = parseArgsParam('key:!date(2001-02-03T04:05:06.789+09:00)');\n    expect(args).toStrictEqual({ key: new Date('2001-02-03T04:05:06.789+09:00') });\n  });\n\n  it('parses Date without timezone', () => {\n    const args = parseArgsParam('key:!date(2001-02-03T04:05:06.789)');\n    expect(args).toStrictEqual({ key: expect.any(Date) }); // depends on local timezone\n  });\n\n  it('parses Date without second fraction', () => {\n    const args = parseArgsParam('key:!date(2001-02-03T04:05:06Z)');\n    expect(args).toStrictEqual({ key: new Date('2001-02-03T04:05:06.000Z') });\n  });\n\n  it('parses Date without time', () => {\n    const args = parseArgsParam('key:!date(2001-02-03)');\n    expect(args).toStrictEqual({ key: expect.any(Date) }); // depends on local timezone\n  });\n\n  it('does not parse Date without prefix', () => {\n    const args = parseArgsParam('key:2001-02-03T04:05:06.789Z');\n    expect(args).toStrictEqual({});\n  });\n\n  it('parses multiple values', () => {\n    const args = parseArgsParam('one:A;two:B;three:C');\n    expect(args).toStrictEqual({ one: 'A', two: 'B', three: 'C' });\n  });\n\n  it('parses arrays', () => {\n    const args = parseArgsParam('arr[]:A;arr[]:B;arr[]:C');\n    expect(args).toStrictEqual({ arr: ['A', 'B', 'C'] });\n  });\n\n  it('parses arrays with indices', () => {\n    const args = parseArgsParam('arr[0]:A;arr[1]:B;arr[2]:C');\n    expect(args).toStrictEqual({ arr: ['A', 'B', 'C'] });\n  });\n\n  it('parses sparse arrays', () => {\n    const args = parseArgsParam('arr[0]:A;arr[2]:C');\n\n    expect(args).toStrictEqual({ arr: ['A', , 'C'] });\n  });\n\n  it('parses repeated values as arrays', () => {\n    const args = parseArgsParam('arr:A;arr:B;arr:C');\n    expect(args).toStrictEqual({ arr: ['A', 'B', 'C'] });\n  });\n\n  it('parses simple objects', () => {\n    const args = parseArgsParam('obj.one:A;obj.two:B');\n    expect(args).toStrictEqual({ obj: { one: 'A', two: 'B' } });\n  });\n\n  it('parses nested objects', () => {\n    const args = parseArgsParam('obj.foo.one:A;obj.foo.two:B;obj.bar.one:A');\n    expect(args).toStrictEqual({ obj: { foo: { one: 'A', two: 'B' }, bar: { one: 'A' } } });\n  });\n\n  it('parses arrays in objects', () => {\n    expect(parseArgsParam('obj.foo[]:A;obj.foo[]:B')).toStrictEqual({ obj: { foo: ['A', 'B'] } });\n    expect(parseArgsParam('obj.foo[0]:A;obj.foo[1]:B')).toStrictEqual({ obj: { foo: ['A', 'B'] } });\n\n    expect(parseArgsParam('obj.foo[1]:B')).toStrictEqual({ obj: { foo: [, 'B'] } });\n    expect(parseArgsParam('obj.foo:A;obj.foo:B')).toStrictEqual({ obj: { foo: ['A', 'B'] } });\n  });\n\n  it('parses single object in array', () => {\n    const args = parseArgsParam('arr[0].one:A;arr[0].two:B');\n    expect(args).toStrictEqual({ arr: [{ one: 'A', two: 'B' }] });\n  });\n\n  it('parses multiple objects in array', () => {\n    expect(parseArgsParam('arr[0].key:A;arr[1].key:B')).toStrictEqual({\n      arr: [{ key: 'A' }, { key: 'B' }],\n    });\n  });\n\n  it('parses nested object in array', () => {\n    expect(parseArgsParam('arr[0].foo.bar:val')).toStrictEqual({ arr: [{ foo: { bar: 'val' } }] });\n  });\n\n  describe('key sanitization', () => {\n    it(\"omits keys that aren't in the extended alphanumeric set\", () => {\n      expect(parseArgsParam('a`b:val')).toStrictEqual({});\n      expect(parseArgsParam('a~b:val')).toStrictEqual({});\n      expect(parseArgsParam('a!b:val')).toStrictEqual({});\n      expect(parseArgsParam('a@b:val')).toStrictEqual({});\n      expect(parseArgsParam('a#b:val')).toStrictEqual({});\n      expect(parseArgsParam('a$b:val')).toStrictEqual({});\n      expect(parseArgsParam('a%b:val')).toStrictEqual({});\n      expect(parseArgsParam('a^b:val')).toStrictEqual({});\n      expect(parseArgsParam('a&b:val')).toStrictEqual({});\n      expect(parseArgsParam('a*b:val')).toStrictEqual({});\n      expect(parseArgsParam('a(b:val')).toStrictEqual({});\n      expect(parseArgsParam('a)b:val')).toStrictEqual({});\n      expect(parseArgsParam('a=b:val')).toStrictEqual({});\n      expect(parseArgsParam('\"b\":val')).toStrictEqual({});\n      expect(parseArgsParam('a/b:val')).toStrictEqual({});\n      expect(parseArgsParam('a\\\\b:val')).toStrictEqual({});\n      expect(parseArgsParam('a|b:val')).toStrictEqual({});\n      expect(parseArgsParam('a{b:val')).toStrictEqual({});\n      expect(parseArgsParam('a}b:val')).toStrictEqual({});\n      expect(parseArgsParam('a?b:val')).toStrictEqual({});\n      expect(parseArgsParam('a<b:val')).toStrictEqual({});\n      expect(parseArgsParam('a>b:val')).toStrictEqual({});\n      expect(parseArgsParam('a,b:val')).toStrictEqual({});\n    });\n\n    it('allows keys that are in the extended alphanumeric set', () => {\n      expect(parseArgsParam(' key :val')).toStrictEqual({ ' key ': 'val' });\n      expect(parseArgsParam('+key+:val')).toStrictEqual({ ' key ': 'val' });\n      expect(parseArgsParam('-key-:val')).toStrictEqual({ '-key-': 'val' });\n      expect(parseArgsParam('_key_:val')).toStrictEqual({ _key_: 'val' });\n      expect(parseArgsParam('KEY123:val')).toStrictEqual({ KEY123: 'val' });\n      expect(parseArgsParam('1:val')).toStrictEqual({ '1': 'val' });\n    });\n\n    it('also applies to nested object keys', () => {\n      expect(parseArgsParam('obj.a!b:val')).toStrictEqual({});\n    });\n\n    it('completely omits an arg when a (deeply) nested key is invalid', () => {\n      expect(parseArgsParam('obj.foo.a!b:val;obj.foo.bar:val;obj.baz:val')).toStrictEqual({});\n      expect(parseArgsParam('obj.foo.a!b:val;key:val')).toStrictEqual({ key: 'val' });\n    });\n  });\n\n  describe('value sanitization', () => {\n    it(\"omits values that aren't in the extended alphanumeric set\", () => {\n      expect(parseArgsParam('key:a`b')).toStrictEqual({});\n      expect(parseArgsParam('key:a~b')).toStrictEqual({});\n      expect(parseArgsParam('key:a!b')).toStrictEqual({});\n      expect(parseArgsParam('key:a@b')).toStrictEqual({});\n      expect(parseArgsParam('key:a#b')).toStrictEqual({});\n      expect(parseArgsParam('key:a$b')).toStrictEqual({});\n      expect(parseArgsParam('key:a%b')).toStrictEqual({});\n      expect(parseArgsParam('key:a^b')).toStrictEqual({});\n      expect(parseArgsParam('key:a&b')).toStrictEqual({});\n      expect(parseArgsParam('key:a*b')).toStrictEqual({});\n      expect(parseArgsParam('key:a(b')).toStrictEqual({});\n      expect(parseArgsParam('key:a)b')).toStrictEqual({});\n      expect(parseArgsParam('key:a=b')).toStrictEqual({});\n      expect(parseArgsParam('key:a[b')).toStrictEqual({});\n      expect(parseArgsParam('key:a]b')).toStrictEqual({});\n      expect(parseArgsParam('key:a{b')).toStrictEqual({});\n      expect(parseArgsParam('key:a}b')).toStrictEqual({});\n      expect(parseArgsParam('key:a\\\\b')).toStrictEqual({});\n      expect(parseArgsParam('key:a|b')).toStrictEqual({});\n      expect(parseArgsParam(\"key:a'b\")).toStrictEqual({});\n      expect(parseArgsParam('key:a\"b')).toStrictEqual({});\n      expect(parseArgsParam('key:a,b')).toStrictEqual({});\n      expect(parseArgsParam('key:a.b')).toStrictEqual({});\n      expect(parseArgsParam('key:a<b')).toStrictEqual({});\n      expect(parseArgsParam('key:a>b')).toStrictEqual({});\n      expect(parseArgsParam('key:a/b')).toStrictEqual({});\n      expect(parseArgsParam('key:a?b')).toStrictEqual({});\n    });\n\n    it('allows values that are in the extended alphanumeric set', () => {\n      expect(parseArgsParam('key: val ')).toStrictEqual({ key: ' val ' });\n      expect(parseArgsParam('key:+val+')).toStrictEqual({ key: ' val ' });\n      expect(parseArgsParam('key:_val_')).toStrictEqual({ key: '_val_' });\n      expect(parseArgsParam('key:-val-')).toStrictEqual({ key: '-val-' });\n      expect(parseArgsParam('key:VAL123')).toStrictEqual({ key: 'VAL123' });\n    });\n\n    it('allows and parses valid (fractional) numbers', () => {\n      expect(parseArgsParam('key:1')).toStrictEqual({ key: 1 });\n      expect(parseArgsParam('key:1.2')).toStrictEqual({ key: 1.2 });\n      expect(parseArgsParam('key:-1.2')).toStrictEqual({ key: -1.2 });\n      expect(parseArgsParam('key:1.')).toStrictEqual({});\n      expect(parseArgsParam('key:.2')).toStrictEqual({});\n      expect(parseArgsParam('key:1.2.3')).toStrictEqual({});\n    });\n\n    it('also applies to nested object and array values', () => {\n      expect(parseArgsParam('obj.key:a!b')).toStrictEqual({});\n      expect(parseArgsParam('arr[0]:a!b')).toStrictEqual({});\n    });\n\n    it('completely omits an arg when a (deeply) nested value is invalid', () => {\n      expect(parseArgsParam('obj.key:a!b;obj.foo:val;obj.bar.baz:val')).toStrictEqual({});\n      expect(parseArgsParam('obj.arr[]:a!b;obj.foo:val;obj.bar.baz:val')).toStrictEqual({});\n      expect(parseArgsParam('obj.arr[0]:val;obj.arr[1]:a!b;obj.foo:val')).toStrictEqual({});\n      expect(parseArgsParam('arr[]:val;arr[]:a!b;key:val')).toStrictEqual({ key: 'val' });\n      expect(parseArgsParam('arr[0]:val;arr[1]:a!1;key:val')).toStrictEqual({ key: 'val' });\n      expect(parseArgsParam('arr[0]:val;arr[2]:a!1;key:val')).toStrictEqual({ key: 'val' });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/parseArgsParam.ts",
    "content": "import { once } from 'storybook/internal/client-logger';\nimport type { Args } from 'storybook/internal/types';\n\nimport { isPlainObject } from 'es-toolkit/predicate';\nimport { type Options, parse } from 'picoquery';\nimport { dedent } from 'ts-dedent';\n\n// Keep this in sync with validateArgs in router/src/utils.ts\nconst VALIDATION_REGEXP = /^[a-zA-Z0-9 _-]*$/;\nconst NUMBER_REGEXP = /^-?[0-9]+(\\.[0-9]+)?$/;\nconst HEX_REGEXP = /^#([a-f0-9]{3,4}|[a-f0-9]{6}|[a-f0-9]{8})$/i;\nconst COLOR_REGEXP =\n  /^(rgba?|hsla?)\\(([0-9]{1,3}),\\s?([0-9]{1,3})%?,\\s?([0-9]{1,3})%?,?\\s?([0-9](\\.[0-9]{1,2})?)?\\)$/i;\nconst validateArgs = (key = '', value: unknown): boolean => {\n  if (key === null) {\n    return false;\n  }\n\n  if (key === '' || !VALIDATION_REGEXP.test(key)) {\n    return false;\n  }\n\n  if (value === null || value === undefined) {\n    return true;\n  } // encoded as `!null` or `!undefined` // encoded as `!null` or `!undefined`\n\n  // encoded as `!null` or `!undefined`\n  if (value instanceof Date) {\n    return true;\n  } // encoded as modified ISO string // encoded as modified ISO string\n\n  // encoded as modified ISO string\n  if (typeof value === 'number' || typeof value === 'boolean') {\n    return true;\n  }\n  if (typeof value === 'string') {\n    return (\n      VALIDATION_REGEXP.test(value) ||\n      NUMBER_REGEXP.test(value) ||\n      HEX_REGEXP.test(value) ||\n      COLOR_REGEXP.test(value)\n    );\n  }\n\n  if (Array.isArray(value)) {\n    return value.every((v) => validateArgs(key, v));\n  }\n\n  if (isPlainObject(value)) {\n    return Object.entries(value as object).every(([k, v]) => validateArgs(k, v));\n  }\n  return false;\n};\n\nconst QUERY_OPTIONS: Partial<Options> = {\n  delimiter: ';', // we're parsing a single query param\n  nesting: true,\n  arrayRepeat: true,\n  arrayRepeatSyntax: 'bracket',\n  nestingSyntax: 'js', // objects are encoded using dot notation\n  valueDeserializer(str: string) {\n    if (str.startsWith('!')) {\n      if (str === '!undefined') {\n        return undefined;\n      }\n\n      if (str === '!null') {\n        return null;\n      }\n\n      if (str === '!true') {\n        return true;\n      }\n\n      if (str === '!false') {\n        return false;\n      }\n\n      if (str.startsWith('!date(') && str.endsWith(')')) {\n        return new Date(str.replaceAll(' ', '+').slice(6, -1));\n      }\n\n      if (str.startsWith('!hex(') && str.endsWith(')')) {\n        return `#${str.slice(5, -1)}`;\n      }\n\n      const color = str.slice(1).match(COLOR_REGEXP);\n      if (color) {\n        if (str.startsWith('!rgba') || str.startsWith('!RGBA')) {\n          return `${color[1]}(${color[2]}, ${color[3]}, ${color[4]}, ${color[5]})`;\n        }\n\n        if (str.startsWith('!hsla') || str.startsWith('!HSLA')) {\n          return `${color[1]}(${color[2]}, ${color[3]}%, ${color[4]}%, ${color[5]})`;\n        }\n        return str.startsWith('!rgb') || str.startsWith('!RGB')\n          ? `${color[1]}(${color[2]}, ${color[3]}, ${color[4]})`\n          : `${color[1]}(${color[2]}, ${color[3]}%, ${color[4]}%)`;\n      }\n    }\n\n    if (NUMBER_REGEXP.test(str)) {\n      return Number(str);\n    }\n    return str;\n  },\n};\nexport const parseArgsParam = (argsString: string): Args => {\n  const parts = argsString.split(';').map((part) => part.replace('=', '~').replace(':', '='));\n  return Object.entries(parse(parts.join(';'), QUERY_OPTIONS)).reduce((acc, [key, value]) => {\n    if (validateArgs(key, value)) {\n      return Object.assign(acc, { [key]: value });\n    }\n    once.warn(dedent`\n      Omitted potentially unsafe URL args.\n\n      More info: https://storybook.js.org/docs/writing-stories/args?ref=error#setting-args-through-the-url\n    `);\n    return acc;\n  }, {} as Args);\n};\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/render/CsfDocsRender.test.ts",
    "content": "import { expect, it, vi } from 'vitest';\n\nimport { Channel } from 'storybook/internal/channels';\nimport type { DocsIndexEntry, RenderContextCallbacks, Renderer } from 'storybook/internal/types';\n\nimport { Tag } from '../../../../shared/constants/tags.ts';\nimport type { StoryStore } from '../../store/index.ts';\nimport { csfFileParts } from '../docs-context/test-utils.ts';\nimport { CsfDocsRender } from './CsfDocsRender.ts';\nimport { PREPARE_ABORTED } from './Render.ts';\n\nconst entry = {\n  type: 'docs',\n  id: 'component--docs',\n  name: 'Docs',\n  title: 'Component',\n  importPath: './Component.stories.ts',\n  storiesImports: [],\n  tags: [Tag.AUTODOCS],\n} as DocsIndexEntry;\n\nconst createGate = (): [Promise<any | undefined>, (_?: any) => void] => {\n  let openGate = (_?: any) => {};\n  const gate = new Promise<any | undefined>((resolve) => {\n    openGate = resolve;\n  });\n  return [gate, openGate];\n};\n\nit('throws PREPARE_ABORTED if torndown during prepare', async () => {\n  const [importGate, openImportGate] = createGate();\n  const mockStore = {\n    loadEntry: vi.fn(async () => {\n      await importGate;\n      return {};\n    }),\n  };\n\n  const render = new CsfDocsRender(\n    new Channel({}),\n    mockStore as unknown as StoryStore<Renderer>,\n    entry,\n    {} as RenderContextCallbacks<Renderer>\n  );\n\n  const preparePromise = render.prepare();\n\n  render.teardown();\n\n  openImportGate();\n\n  await expect(preparePromise).rejects.toThrowError(PREPARE_ABORTED);\n});\n\nit('attached immediately', async () => {\n  const { story, csfFile, moduleExports } = csfFileParts();\n\n  const store = {\n    loadEntry: () => ({\n      entryExports: moduleExports,\n      csfFiles: [],\n    }),\n    processCSFFileWithCache: () => csfFile,\n    componentStoriesFromCSFFile: () => [story],\n    storyFromCSFFile: () => story,\n  } as unknown as StoryStore<Renderer>;\n\n  const render = new CsfDocsRender(\n    new Channel({}),\n    store,\n    entry,\n    {} as RenderContextCallbacks<Renderer>\n  );\n  await render.prepare();\n\n  const context = render.docsContext(vi.fn());\n\n  expect(context.storyById()).toEqual(story);\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/render/CsfDocsRender.ts",
    "content": "import type { Channel } from 'storybook/internal/channels';\nimport { DOCS_RENDERED } from 'storybook/internal/core-events';\nimport type { Renderer, StoryId } from 'storybook/internal/types';\nimport type { CSFFile, PreparedStory } from 'storybook/internal/types';\nimport type { IndexEntry } from 'storybook/internal/types';\nimport type { RenderContextCallbacks } from 'storybook/internal/types';\n\nimport type { StoryStore } from '../../../store.ts';\nimport { DocsContext } from '../docs-context/DocsContext.ts';\nimport type { DocsContextProps } from '../docs-context/DocsContextProps.ts';\nimport type { DocsRenderFunction } from '../docs-context/DocsRenderFunction.ts';\nimport type { Render, RenderType } from './Render.ts';\nimport { PREPARE_ABORTED } from './Render.ts';\n\n/**\n * A CsfDocsRender is a render of a docs entry that is rendered based on a CSF file.\n *\n * The expectation is the primary CSF file which is the `importPath` for the entry will define a\n * story which may contain the actual rendered JSX code for the template in the `docs.page`\n * parameter.\n *\n * Use cases:\n *\n * - Autodocs, where there is no story, and we fall back to the globally defined template.\n */\nexport class CsfDocsRender<TRenderer extends Renderer> implements Render<TRenderer> {\n  public readonly renderId: number;\n\n  public readonly type: RenderType = 'docs';\n\n  public readonly subtype = 'csf';\n\n  public readonly id: StoryId;\n\n  public story?: PreparedStory<TRenderer>;\n\n  public rerender?: () => Promise<void>;\n\n  public teardownRender?: (options: { viewModeChanged?: boolean }) => Promise<void>;\n\n  public torndown = false;\n\n  public readonly disableKeyListeners = false;\n\n  public preparing = false;\n\n  public csfFiles?: CSFFile<TRenderer>[];\n\n  constructor(\n    protected channel: Channel,\n    protected store: StoryStore<TRenderer>,\n    public entry: IndexEntry,\n    private callbacks: RenderContextCallbacks<TRenderer>\n  ) {\n    this.id = entry.id;\n    this.renderId = Date.now();\n  }\n\n  isPreparing() {\n    return this.preparing;\n  }\n\n  async prepare() {\n    this.preparing = true;\n    const { entryExports, csfFiles = [] } = await this.store.loadEntry(this.id);\n\n    if (this.torndown) {\n      throw PREPARE_ABORTED;\n    }\n\n    const { importPath, title } = this.entry;\n    const primaryCsfFile = this.store.processCSFFileWithCache<TRenderer>(\n      entryExports,\n      importPath,\n      title\n    );\n\n    // We use the first (\"primary\") story from the CSF as the \"current\" story on the context.\n    //   - When rendering \"true\" CSF files, this is for back-compat, where templates may expect\n    //     a story to be current (even though now we render a separate docs entry from the stories)\n    //   - when rendering a \"docs only\" (story) id, this will end up being the same story as\n    //     this.id, as such \"CSF files\" have only one story\n    const primaryStoryId = Object.keys(primaryCsfFile.stories)[0];\n    this.story = this.store.storyFromCSFFile({ storyId: primaryStoryId, csfFile: primaryCsfFile });\n\n    this.csfFiles = [primaryCsfFile, ...csfFiles];\n\n    this.preparing = false;\n  }\n\n  isEqual(other: Render<TRenderer>): boolean {\n    return !!(\n      this.id === other.id &&\n      this.story &&\n      this.story === (other as CsfDocsRender<TRenderer>).story\n    );\n  }\n\n  docsContext(renderStoryToElement: DocsContextProps<TRenderer>['renderStoryToElement']) {\n    if (!this.csfFiles) {\n      throw new Error('Cannot render docs before preparing');\n    }\n    const docsContext = new DocsContext<TRenderer>(\n      this.channel,\n      this.store,\n      renderStoryToElement,\n      this.csfFiles\n    );\n    // All referenced CSF files should be attached for CSF docs\n    //  - When you create two CSF files that both reference the same title, they are combined into\n    //    a single CSF docs entry with a `storiesImport` defined.\n    this.csfFiles.forEach((csfFile) => docsContext.attachCSFFile(csfFile));\n    return docsContext;\n  }\n\n  async renderToElement(\n    canvasElement: TRenderer['canvasElement'],\n    renderStoryToElement: DocsContextProps<TRenderer>['renderStoryToElement']\n  ) {\n    if (!this.story || !this.csfFiles) {\n      throw new Error('Cannot render docs before preparing');\n    }\n\n    const docsContext = this.docsContext(renderStoryToElement);\n\n    const { docs: docsParameter } = this.story.parameters || {};\n\n    if (!docsParameter) {\n      throw new Error(\n        `Cannot render a story in viewMode=docs if \\`@storybook/addon-docs\\` is not installed`\n      );\n    }\n\n    const renderer = await docsParameter.renderer();\n    const { render } = renderer as { render: DocsRenderFunction<TRenderer> };\n    const renderDocs = async () => {\n      try {\n        // NOTE: it isn't currently possible to use a docs renderer outside of \"web\" mode.\n        await render(docsContext, docsParameter, canvasElement as any);\n        this.channel.emit(DOCS_RENDERED, this.id);\n      } catch (err) {\n        this.callbacks.showException(err as Error);\n      }\n    };\n\n    this.rerender = async () => renderDocs();\n    this.teardownRender = async ({ viewModeChanged }: { viewModeChanged?: boolean }) => {\n      if (!viewModeChanged || !canvasElement) {\n        return;\n      }\n      renderer.unmount(canvasElement);\n    };\n\n    return renderDocs();\n  }\n\n  async teardown({ viewModeChanged }: { viewModeChanged?: boolean } = {}) {\n    this.teardownRender?.({ viewModeChanged });\n    this.torndown = true;\n  }\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/render/MdxDocsRender.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { Channel } from 'storybook/internal/channels';\nimport { Tag } from 'storybook/internal/core-server';\nimport type { DocsIndexEntry, RenderContextCallbacks, Renderer } from 'storybook/internal/types';\n\nimport type { StoryStore } from '../../store/index.ts';\nimport { csfFileParts } from '../docs-context/test-utils.ts';\nimport { MdxDocsRender } from './MdxDocsRender.ts';\nimport { PREPARE_ABORTED } from './Render.ts';\n\nconst entry = {\n  type: 'docs',\n  id: 'introduction--docs',\n  name: 'Docs',\n  title: 'Introduction',\n  importPath: './Introduction.mdx',\n  storiesImports: [],\n} as DocsIndexEntry;\n\nconst attachedEntry = {\n  ...entry,\n  id: 'meta--docs',\n  title: 'Meta',\n  storiesImports: ['./Meta.stories.ts'],\n  tags: [Tag.ATTACHED_MDX],\n} as DocsIndexEntry;\n\nconst createGate = (): [Promise<any | undefined>, (_?: any) => void] => {\n  let openGate = (_?: any) => {};\n  const gate = new Promise<any | undefined>((resolve) => {\n    openGate = resolve;\n  });\n  return [gate, openGate];\n};\n\nit('throws PREPARE_ABORTED if torndown during prepare', async () => {\n  const [importGate, openImportGate] = createGate();\n  const mockStore = {\n    loadEntry: vi.fn(async () => {\n      await importGate;\n      return {};\n    }),\n  };\n\n  const render = new MdxDocsRender(\n    new Channel({}),\n    mockStore as unknown as StoryStore<Renderer>,\n    entry,\n    {} as RenderContextCallbacks<Renderer>\n  );\n\n  const preparePromise = render.prepare();\n\n  render.teardown();\n\n  openImportGate();\n\n  await expect(preparePromise).rejects.toThrowError(PREPARE_ABORTED);\n});\n\ndescribe('attaching', () => {\n  const { story, csfFile, moduleExports } = csfFileParts();\n  const store = {\n    loadEntry: () => ({\n      entryExports: moduleExports,\n      csfFiles: [csfFile],\n    }),\n    processCSFFileWithCache: () => csfFile,\n    componentStoriesFromCSFFile: () => [story],\n    storyFromCSFFile: () => story,\n  } as unknown as StoryStore<Renderer>;\n\n  it('is not attached if you do not call setMeta', async () => {\n    const render = new MdxDocsRender(\n      new Channel({}),\n      store,\n      entry,\n      {} as RenderContextCallbacks<Renderer>\n    );\n    await render.prepare();\n\n    const context = render.docsContext(vi.fn());\n\n    expect(context.storyById).toThrow('No primary story defined');\n  });\n\n  it('is attached if you call referenceMeta with attach=true', async () => {\n    const render = new MdxDocsRender(\n      new Channel({}),\n      store,\n      entry,\n      {} as RenderContextCallbacks<Renderer>\n    );\n    await render.prepare();\n\n    const context = render.docsContext(vi.fn());\n    context.referenceMeta(moduleExports, true);\n\n    expect(context.storyById()).toEqual(story);\n  });\n\n  it('pre-attaches the indexed CSF file for attached MDX docs', async () => {\n    const render = new MdxDocsRender(\n      new Channel({}),\n      store,\n      attachedEntry,\n      {} as RenderContextCallbacks<Renderer>\n    );\n    await render.prepare();\n\n    const context = render.docsContext(vi.fn());\n\n    expect(context.storyById()).toEqual(story);\n  });\n});\n\ndescribe('docs parameters', () => {\n  it('uses the attached CSF story docs parameters for attached MDX docs', async () => {\n    const renderPage = vi.fn();\n    const renderer = { render: renderPage };\n    const docsRenderer = vi.fn(async () => renderer);\n    const { story, csfFile, moduleExports } = csfFileParts();\n    const attachedStory = {\n      ...story,\n      parameters: {\n        docs: {\n          components: { Canvas: 'OverrideCanvas' },\n          renderer: docsRenderer,\n        },\n      },\n    };\n    const store = {\n      loadEntry: () => ({\n        entryExports: { ...moduleExports, default: () => null },\n        csfFiles: [csfFile],\n      }),\n      componentStoriesFromCSFFile: () => [attachedStory],\n      storyFromCSFFile: () => attachedStory,\n      projectAnnotations: {\n        parameters: {\n          docs: {\n            components: { Canvas: 'ProjectCanvas' },\n            renderer: vi.fn(),\n          },\n        },\n      },\n    } as unknown as StoryStore<Renderer>;\n\n    const render = new MdxDocsRender(\n      new Channel({}),\n      store,\n      attachedEntry,\n      {} as RenderContextCallbacks<Renderer>\n    );\n    await render.prepare();\n\n    await render.renderToElement({} as Renderer['canvasElement'], vi.fn());\n\n    expect(docsRenderer).toHaveBeenCalled();\n    expect(renderPage).toHaveBeenCalledWith(\n      expect.objectContaining({\n        storyById: expect.any(Function),\n      }),\n      expect.objectContaining({\n        components: { Canvas: 'OverrideCanvas' },\n        page: expect.any(Function),\n      }),\n      expect.anything()\n    );\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/render/MdxDocsRender.ts",
    "content": "import type { Channel } from 'storybook/internal/channels';\nimport { DOCS_RENDERED } from 'storybook/internal/core-events';\nimport type { Renderer, StoryId } from 'storybook/internal/types';\nimport type { CSFFile, ModuleExports, PreparedStory } from 'storybook/internal/types';\nimport type { IndexEntry } from 'storybook/internal/types';\nimport type { RenderContextCallbacks } from 'storybook/internal/types';\n\nimport { Tag } from '../../../../shared/constants/tags.ts';\nimport type { StoryStore } from '../../store/index.ts';\nimport { DocsContext } from '../docs-context/DocsContext.ts';\nimport type { DocsContextProps } from '../docs-context/DocsContextProps.ts';\nimport type { DocsRenderFunction } from '../docs-context/DocsRenderFunction.ts';\nimport type { Render, RenderType } from './Render.ts';\nimport { PREPARE_ABORTED } from './Render.ts';\n\n/**\n * A MdxDocsRender is a render of a docs entry that comes from a true MDX file, that is a `.mdx`\n * file that doesn't get compiled to a CSF file.\n *\n * A MDX render can reference (import) zero or more CSF files that contain stories.\n *\n * Use cases:\n *\n * - *.mdx file that may or may not reference a specific CSF file with `<Meta of={} />`\n */\n\nexport class MdxDocsRender<TRenderer extends Renderer> implements Render<TRenderer> {\n  public readonly renderId: number;\n\n  public readonly type: RenderType = 'docs';\n\n  public readonly subtype = 'mdx';\n\n  public readonly id: StoryId;\n\n  private exports?: ModuleExports;\n\n  public rerender?: () => Promise<void>;\n\n  public teardownRender?: (options: { viewModeChanged?: boolean }) => Promise<void>;\n\n  public torndown = false;\n\n  public readonly disableKeyListeners = false;\n\n  public preparing = false;\n\n  public csfFiles?: CSFFile<TRenderer>[];\n\n  public attachedCsfFile?: CSFFile<TRenderer>;\n\n  public attachedStory?: PreparedStory<TRenderer>;\n\n  constructor(\n    protected channel: Channel,\n    protected store: StoryStore<TRenderer>,\n    public entry: IndexEntry,\n    private callbacks: RenderContextCallbacks<TRenderer>\n  ) {\n    this.id = entry.id;\n    this.renderId = Date.now();\n  }\n\n  isPreparing() {\n    return this.preparing;\n  }\n\n  async prepare() {\n    this.preparing = true;\n    const { entryExports, csfFiles = [] } = await this.store.loadEntry(this.id);\n\n    if (this.torndown) {\n      throw PREPARE_ABORTED;\n    }\n\n    this.csfFiles = csfFiles;\n    this.exports = entryExports;\n    this.attachedCsfFile = undefined;\n    this.attachedStory = undefined;\n\n    if (this.entry.tags?.includes(Tag.ATTACHED_MDX)) {\n      this.attachedCsfFile = csfFiles[0];\n\n      const primaryStoryId = this.attachedCsfFile && Object.keys(this.attachedCsfFile.stories)[0];\n      if (this.attachedCsfFile && primaryStoryId) {\n        this.attachedStory = this.store.storyFromCSFFile({\n          storyId: primaryStoryId,\n          csfFile: this.attachedCsfFile,\n        });\n      }\n    }\n\n    this.preparing = false;\n  }\n\n  isEqual(other: Render<TRenderer>): boolean {\n    return !!(\n      this.id === other.id &&\n      this.exports &&\n      this.exports === (other as MdxDocsRender<TRenderer>).exports\n    );\n  }\n\n  docsContext(renderStoryToElement: DocsContextProps<TRenderer>['renderStoryToElement']) {\n    if (!this.csfFiles) {\n      throw new Error('Cannot render docs before preparing');\n    }\n\n    const docsContext = new DocsContext<TRenderer>(\n      this.channel,\n      this.store,\n      renderStoryToElement,\n      this.csfFiles\n    );\n\n    if (this.attachedCsfFile) {\n      docsContext.attachCSFFile(this.attachedCsfFile);\n    }\n\n    return docsContext;\n  }\n\n  async renderToElement(\n    canvasElement: TRenderer['canvasElement'],\n    renderStoryToElement: DocsContextProps<TRenderer>['renderStoryToElement']\n  ) {\n    if (!this.exports || !this.csfFiles || !this.store.projectAnnotations) {\n      throw new Error('Cannot render docs before preparing');\n    }\n\n    const docsContext = this.docsContext(renderStoryToElement);\n\n    const { docs } = this.store.projectAnnotations.parameters ?? ({} as { docs: any });\n    const baseDocsParameter = this.attachedStory?.parameters?.docs ?? docs;\n\n    if (!baseDocsParameter) {\n      throw new Error(\n        `Cannot render a story in viewMode=docs if \\`@storybook/addon-docs\\` is not installed`\n      );\n    }\n\n    const docsParameter = { ...baseDocsParameter, page: this.exports.default };\n    const renderer = await baseDocsParameter.renderer();\n    const { render } = renderer as { render: DocsRenderFunction<TRenderer> };\n    const renderDocs = async () => {\n      try {\n        // NOTE: it isn't currently possible to use a docs renderer outside of \"web\" mode.\n        await render(docsContext, docsParameter, canvasElement as any);\n        this.channel.emit(DOCS_RENDERED, this.id);\n      } catch (err) {\n        this.callbacks.showException(err as Error);\n      }\n    };\n\n    this.rerender = async () => renderDocs();\n    this.teardownRender = async ({ viewModeChanged }: { viewModeChanged?: boolean } = {}) => {\n      if (!viewModeChanged || !canvasElement) {\n        return;\n      }\n      renderer.unmount(canvasElement);\n      this.torndown = true;\n    };\n\n    return renderDocs();\n  }\n\n  async teardown({ viewModeChanged }: { viewModeChanged?: boolean } = {}) {\n    this.teardownRender?.({ viewModeChanged });\n    this.torndown = true;\n  }\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/render/Render.ts",
    "content": "import type { Renderer, StoryId } from 'storybook/internal/types';\nimport type { StoryRenderOptions } from 'storybook/internal/types';\n\nexport type RenderType = 'story' | 'docs';\n\n/**\n * A \"Render\" represents the rendering of a single entry to a single location\n *\n * The implementations of render are used for two key purposes:\n *\n * - Tracking the state of the rendering as it moves between preparing, rendering and tearing down.\n * - Tracking what is rendered to know if a change requires re-rendering or teardown + recreation.\n */\nexport interface Render<TRenderer extends Renderer> {\n  renderId: number;\n  type: RenderType;\n  id: StoryId;\n  isPreparing: () => boolean;\n  isEqual: (other: Render<TRenderer>) => boolean;\n  disableKeyListeners: boolean;\n  teardown?: (options: { viewModeChanged: boolean }) => Promise<void>;\n  torndown: boolean;\n  renderToElement: (\n    canvasElement: TRenderer['canvasElement'],\n    renderStoryToElement?: any,\n    options?: StoryRenderOptions\n  ) => Promise<void>;\n}\n\nexport const PREPARE_ABORTED = new Error('prepareAborted');\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/render/StoryRender.test.ts",
    "content": "// @vitest-environment happy-dom\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { Channel } from 'storybook/internal/channels';\nimport { STORY_FINISHED } from 'storybook/internal/core-events';\nimport type {\n  PreparedStory,\n  Renderer,\n  StoryContext,\n  StoryIndexEntry,\n} from 'storybook/internal/types';\n\nimport { ReporterAPI, type StoryStore } from '../../store/index.ts';\nimport { PREPARE_ABORTED } from './Render.ts';\nimport { StoryRender, serializeError } from './StoryRender.ts';\n\nconst entry = {\n  type: 'story',\n  subtype: 'story',\n  id: 'component--a',\n  name: 'A',\n  title: 'component',\n  importPath: './component.stories.ts',\n} as StoryIndexEntry;\n\nconst createGate = (): [Promise<void>, () => void] => {\n  let openGate = () => {};\n  const gate = new Promise<void>((resolve) => {\n    openGate = resolve;\n  });\n  return [gate, openGate];\n};\nconst tick = () => new Promise((resolve) => setTimeout(resolve, 0));\n\nwindow.location = { reload: vi.fn() } as any;\n\nconst mountSpy = vi.fn(async (context) => {\n  await context.renderToCanvas();\n  return context.canvas;\n});\n\nconst buildStory = (overrides: Partial<PreparedStory> = {}): PreparedStory =>\n  ({\n    id: 'id',\n    title: 'title',\n    name: 'name',\n    tags: [],\n    applyLoaders: vi.fn(),\n    applyBeforeEach: vi.fn(() => []),\n    applyAfterEach: vi.fn(),\n    unboundStoryFn: vi.fn(),\n    playFunction: vi.fn(),\n    mount: (context: StoryContext) => () => mountSpy(context),\n    ...overrides,\n  }) as any;\n\nconst buildStore = (overrides: Partial<StoryStore<Renderer>> = {}): StoryStore<Renderer> =>\n  ({\n    getStoryContext: () => ({\n      reporting: new ReporterAPI(),\n    }),\n    addCleanupCallbacks: vi.fn(),\n    cleanupStory: vi.fn(),\n    ...overrides,\n  }) as any;\n\nbeforeEach(() => {\n  vi.restoreAllMocks();\n});\n\ndescribe('StoryRender', () => {\n  it('does run play function if passed autoplay=true', async () => {\n    const story = buildStory();\n    const render = new StoryRender(\n      new Channel({}),\n      buildStore(),\n      vi.fn() as any,\n      {} as any,\n      entry.id,\n      'story',\n      { autoplay: true },\n      story\n    );\n\n    await render.renderToElement({} as any);\n    expect(story.playFunction).toHaveBeenCalled();\n  });\n\n  it('does not run play function if passed autoplay=false', async () => {\n    const story = buildStory();\n    const render = new StoryRender(\n      new Channel({}),\n      buildStore(),\n      vi.fn() as any,\n      {} as any,\n      entry.id,\n      'story',\n      { autoplay: false },\n      story\n    );\n\n    await render.renderToElement({} as any);\n    expect(story.playFunction).not.toHaveBeenCalled();\n  });\n\n  it('only rerenders once when triggered multiple times while pending', async () => {\n    // Arrange - setup StoryRender and async gate blocking applyLoaders\n    const [loaderGate, openLoaderGate] = createGate();\n    const renderToScreen = vi.fn();\n\n    const story = buildStory({\n      applyLoaders: vi.fn(() => loaderGate as any),\n    });\n    const render = new StoryRender(\n      new Channel({}),\n      buildStore(),\n      renderToScreen,\n      {} as any,\n      entry.id,\n      'story',\n      { autoplay: true },\n      story\n    );\n    // Arrange - render (blocked by loaders)\n    render.renderToElement({} as any);\n    expect(story.applyLoaders).toHaveBeenCalledOnce();\n    expect(render.phase).toBe('loading');\n\n    // Act - rerender 3x\n    render.rerender();\n    render.rerender();\n    render.rerender();\n\n    // Assert - still loading, not yet rendered\n    expect(story.applyLoaders).toHaveBeenCalledOnce();\n    expect(render.phase).toBe('loading');\n    expect(renderToScreen).not.toHaveBeenCalled();\n\n    // Act - finish loading\n    openLoaderGate();\n\n    // Assert - loaded and rendered twice, played once\n    await vi.waitFor(async () => {\n      expect(story.applyLoaders).toHaveBeenCalledTimes(2);\n      expect(renderToScreen).toHaveBeenCalledTimes(2);\n      expect(story.playFunction).toHaveBeenCalledOnce();\n    });\n  });\n\n  it('calls mount if play function does not destructure mount', async () => {\n    const story = buildStory({\n      playFunction: () => {},\n    });\n    const render = new StoryRender(\n      new Channel({}),\n      buildStore(),\n      vi.fn() as any,\n      {} as any,\n      entry.id,\n      'story',\n      { autoplay: true },\n      story\n    );\n\n    await render.renderToElement({} as any);\n    expect(mountSpy).toHaveBeenCalledOnce();\n  });\n\n  it('does not call mount twice if mount called in play function', async () => {\n    const story = buildStory({\n      usesMount: true,\n      playFunction: async ({ mount }) => {\n        await mount();\n      },\n    });\n    const render = new StoryRender(\n      new Channel({}),\n      buildStore(),\n      vi.fn() as any,\n      {} as any,\n      entry.id,\n      'story',\n      { autoplay: true },\n      story\n    );\n\n    await render.renderToElement({} as any);\n    expect(mountSpy).toHaveBeenCalledOnce();\n  });\n\n  it('errors if play function calls mount without destructuring', async () => {\n    const story = buildStory({\n      playFunction: async (context) => {\n        await context.mount();\n      },\n    });\n    const view = { showException: vi.fn() };\n    const render = new StoryRender(\n      new Channel({}),\n      buildStore(),\n      vi.fn() as any,\n      view as any,\n      entry.id,\n      'story',\n      { autoplay: true },\n      story\n    );\n\n    await render.renderToElement({} as any);\n    expect(view.showException).toHaveBeenCalled();\n  });\n\n  it('errors if play function destructures mount but does not call it', async () => {\n    const story = buildStory({\n      usesMount: true,\n      playFunction: async ({ mount }) => {\n        // forget to call mount\n      },\n    });\n    const view = { showException: vi.fn() };\n    const render = new StoryRender(\n      new Channel({}),\n      buildStore(),\n      vi.fn() as any,\n      view as any,\n      entry.id,\n      'story',\n      { autoplay: true },\n      story\n    );\n\n    await render.renderToElement({} as any);\n    expect(view.showException).toHaveBeenCalled();\n  });\n\n  it('enters rendering phase during play if play function calls mount', async () => {\n    const actualMount = vi.fn(async (context) => {\n      await context.renderToCanvas();\n      expect(render.phase).toBe('rendering');\n      return context.canvas;\n    });\n    const story = buildStory({\n      mount: (context) => () => actualMount(context) as any,\n      usesMount: true,\n      playFunction: async ({ mount }) => {\n        expect(render.phase).toBe('loading');\n        await mount();\n        expect(render.phase).toBe('playing');\n      },\n    });\n    const render = new StoryRender(\n      new Channel({}),\n      buildStore(),\n      vi.fn(() => {\n        expect(render.phase).toBe('rendering');\n      }) as any,\n      {} as any,\n      entry.id,\n      'story',\n      { autoplay: true },\n      story\n    );\n\n    await render.renderToElement({} as any);\n    expect(actualMount).toHaveBeenCalled();\n  });\n\n  it('should handle the \"finished\" phase correctly when the story finishes successfully', async () => {\n    // Arrange - setup StoryRender and async gate blocking finished phase\n    const [finishGate, resolveFinishGate] = createGate();\n    const story = buildStory({\n      playFunction: vi.fn(async () => {\n        await finishGate;\n      }),\n    });\n    const store = buildStore();\n\n    const channel = new Channel({});\n    const emitSpy = vi.spyOn(channel, 'emit');\n\n    const render = new StoryRender(\n      channel,\n      store,\n      vi.fn() as any,\n      {} as any,\n      entry.id,\n      'story',\n      { autoplay: true },\n      story\n    );\n\n    // Act - render, resolve finish gate, teardown\n    render.renderToElement({} as any);\n    await tick(); // go from 'loading' to 'rendering' phase\n    resolveFinishGate();\n    await tick(); // go from 'rendering' to 'finished' phase\n    render.teardown();\n\n    // Assert - ensure finished phase is handled correctly\n    expect(render.phase).toBe('finished');\n    expect(emitSpy).toHaveBeenCalledWith(STORY_FINISHED, {\n      reporters: [],\n      status: 'success',\n      storyId: 'id',\n    });\n  });\n\n  it('should handle the \"finished\" phase correctly when the story throws an error', async () => {\n    // Arrange - setup StoryRender and async gate blocking finished phase\n    const [finishGate, rejectFinishGate] = createGate();\n    const error = new Error('Test error');\n    const story = buildStory({\n      parameters: {},\n      playFunction: vi.fn(async () => {\n        await finishGate;\n        throw error;\n      }),\n    });\n    const store = buildStore();\n\n    const channel = new Channel({});\n    const emitSpy = vi.spyOn(channel, 'emit');\n\n    const render = new StoryRender(\n      channel,\n      store,\n      vi.fn() as any,\n      {\n        showException: vi.fn(),\n      } as any,\n      entry.id,\n      'story',\n      { autoplay: true },\n      story\n    );\n\n    // Act - render, reject finish gate, teardown\n    render.renderToElement({} as any);\n    await tick(); // go from 'loading' to 'rendering' phase\n    rejectFinishGate();\n    await tick(); // go from 'rendering' to 'finished' phase\n    render.teardown();\n\n    // Assert - ensure finished phase is handled correctly\n    expect(render.phase).toBe('finished');\n    expect(emitSpy).toHaveBeenCalledWith(STORY_FINISHED, {\n      reporters: [],\n      status: 'error',\n      storyId: 'id',\n    });\n  });\n\n  describe('teardown', () => {\n    it('throws PREPARE_ABORTED if torndown during prepare', async () => {\n      const [importGate, openImportGate] = createGate();\n      const mockStore = buildStore({\n        loadStory: vi.fn(async () => {\n          await importGate;\n          return {};\n        }) as any,\n      });\n\n      const render = new StoryRender(\n        new Channel({}),\n        mockStore,\n        vi.fn(),\n        {} as any,\n        entry.id,\n        'story'\n      );\n\n      const preparePromise = render.prepare();\n\n      render.teardown();\n\n      openImportGate();\n\n      await expect(preparePromise).rejects.toThrowError(PREPARE_ABORTED);\n    });\n\n    it('reloads the page when tearing down during loading', async () => {\n      // Arrange - setup StoryRender and async gate blocking applyLoaders\n      const [loaderGate] = createGate();\n      const story = buildStory({\n        applyLoaders: vi.fn(() => loaderGate as any),\n      });\n      const store = buildStore();\n      const render = new StoryRender(\n        new Channel({}),\n        store,\n        vi.fn() as any,\n        {} as any,\n        entry.id,\n        'story',\n        { autoplay: true },\n        story\n      );\n\n      // Act - render (blocked by loaders), teardown\n      render.renderToElement({} as any);\n      expect(story.applyLoaders).toHaveBeenCalledOnce();\n      expect(render.phase).toBe('loading');\n      render.teardown();\n\n      // Assert - window is reloaded\n      await vi.waitFor(() => {\n        expect(window.location.reload).toHaveBeenCalledOnce();\n        expect(store.cleanupStory).toHaveBeenCalledOnce();\n      });\n    });\n\n    it('reloads the page when tearing down during rendering', async () => {\n      // Arrange - setup StoryRender and async gate blocking renderToScreen\n      const [renderGate] = createGate();\n      const story = buildStory();\n      const store = buildStore();\n      const renderToScreen = vi.fn(() => renderGate);\n\n      const render = new StoryRender(\n        new Channel({}),\n        store,\n        renderToScreen as any,\n        {} as any,\n        entry.id,\n        'story',\n        { autoplay: true },\n        story\n      );\n\n      // Act - render (blocked by renderToScreen), teardown\n      render.renderToElement({} as any);\n      await tick(); // go from 'loading' to 'rendering' phase\n      expect(renderToScreen).toHaveBeenCalledOnce();\n      expect(render.phase).toBe('rendering');\n      render.teardown();\n\n      // Assert - window is reloaded\n      await vi.waitFor(() => {\n        expect(window.location.reload).toHaveBeenCalledOnce();\n        expect(store.cleanupStory).toHaveBeenCalledOnce();\n      });\n    });\n\n    it('reloads the page when tearing down during playing', async () => {\n      // Arrange - setup StoryRender and async gate blocking playing\n      const [playGate] = createGate();\n      const story = buildStory({\n        playFunction: vi.fn(() => playGate as any),\n      });\n      const store = buildStore();\n\n      const render = new StoryRender(\n        new Channel({}),\n        store,\n        vi.fn() as any,\n        {} as any,\n        entry.id,\n        'story',\n        { autoplay: true },\n        story\n      );\n\n      // Act - render (blocked by playFn), teardown\n      render.renderToElement({} as any);\n      await tick(); // go from 'loading' to 'beforeEach' phase\n      await tick(); // go from 'beforeEach' to 'playing' phase\n      expect(story.playFunction).toHaveBeenCalledOnce();\n      expect(render.phase).toBe('playing');\n      render.teardown();\n\n      // Assert - window is reloaded\n      await vi.waitFor(() => {\n        expect(window.location.reload).toHaveBeenCalledOnce();\n        expect(store.cleanupStory).toHaveBeenCalledOnce();\n      });\n    });\n\n    it('reloads the page when remounting during loading', async () => {\n      // Arrange - setup StoryRender and async gate blocking applyLoaders\n      const [loaderGate] = createGate();\n      const story = buildStory({\n        applyLoaders: vi.fn(() => loaderGate as any),\n      });\n      const store = buildStore();\n\n      const render = new StoryRender(\n        new Channel({}),\n        store,\n        vi.fn() as any,\n        {} as any,\n        entry.id,\n        'story',\n        { autoplay: true },\n        story\n      );\n\n      // Act - render, blocked by loaders\n      render.renderToElement({} as any);\n      expect(story.applyLoaders).toHaveBeenCalledOnce();\n      expect(render.phase).toBe('loading');\n      // Act - remount\n      render.remount();\n\n      // Assert - window is reloaded\n      await vi.waitFor(() => {\n        expect(window.location.reload).toHaveBeenCalledOnce();\n        expect(store.cleanupStory).toHaveBeenCalledOnce();\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/render/StoryRender.ts",
    "content": "import type { Channel } from 'storybook/internal/channels';\nimport {\n  PLAY_FUNCTION_THREW_EXCEPTION,\n  STORY_FINISHED,\n  STORY_RENDERED,\n  STORY_RENDER_PHASE_CHANGED,\n  type StoryFinishedPayload,\n  UNHANDLED_ERRORS_WHILE_PLAYING,\n} from 'storybook/internal/core-events';\nimport {\n  MountMustBeDestructuredError,\n  NoStoryMountedError,\n} from 'storybook/internal/preview-errors';\nimport type {\n  Canvas,\n  PreparedStory,\n  RenderContext,\n  RenderContextCallbacks,\n  RenderToCanvas,\n  Renderer,\n  StoryContext,\n  StoryId,\n  StoryRenderOptions,\n  TeardownRenderToCanvas,\n} from 'storybook/internal/types';\n\nimport type { UserEventObject } from 'storybook/test';\n\nimport type { StoryStore } from '../../store/index.ts';\nimport type { Render, RenderType } from './Render.ts';\nimport { PREPARE_ABORTED } from './Render.ts';\nimport { isTestEnvironment, pauseAnimations, waitForAnimations } from './animation-utils.ts';\n\nconst { AbortController } = globalThis;\n\nexport type RenderPhase =\n  | 'preparing'\n  | 'loading'\n  | 'beforeEach'\n  | 'rendering'\n  | 'playing'\n  | 'played'\n  | 'completing'\n  | 'completed'\n  | 'afterEach'\n  | 'finished'\n  | 'aborted'\n  | 'errored';\n\nexport function serializeError(error: any) {\n  try {\n    const { name = 'Error', message = String(error), stack } = error;\n    return { name, message, stack };\n  } catch (e) {\n    return { name: 'Error', message: String(error) };\n  }\n}\n\nexport class StoryRender<TRenderer extends Renderer> implements Render<TRenderer> {\n  public readonly renderId: number;\n\n  public type: RenderType = 'story';\n\n  public story?: PreparedStory<TRenderer>;\n\n  public phase?: RenderPhase;\n\n  private abortController: AbortController;\n\n  private canvasElement?: TRenderer['canvasElement'];\n\n  private notYetRendered = true;\n\n  private rerenderEnqueued = false;\n\n  public disableKeyListeners = false;\n\n  private teardownRender: TeardownRenderToCanvas = () => {};\n\n  public torndown = false;\n\n  constructor(\n    public channel: Channel,\n    public store: StoryStore<TRenderer>,\n    private renderToScreen: RenderToCanvas<TRenderer>,\n    private callbacks: RenderContextCallbacks<TRenderer> & { showStoryDuringRender?: () => void },\n    public id: StoryId,\n    public viewMode: StoryContext<TRenderer>['viewMode'],\n    public renderOptions: StoryRenderOptions = { autoplay: true, forceInitialArgs: false },\n    story?: PreparedStory<TRenderer>\n  ) {\n    this.abortController = new AbortController();\n    this.renderId = Date.now();\n\n    // Allow short-circuiting preparing if we happen to already\n    // have the story (this is used by docs mode)\n    if (story) {\n      this.story = story;\n      // TODO -- what should the phase be now?\n      // TODO -- should we emit the render phase changed event?\n      this.phase = 'preparing';\n    }\n  }\n\n  private async runPhase(signal: AbortSignal, phase: RenderPhase, phaseFn?: () => Promise<void>) {\n    this.phase = phase;\n    this.channel.emit(STORY_RENDER_PHASE_CHANGED, {\n      newPhase: this.phase,\n      renderId: this.renderId,\n      storyId: this.id,\n    });\n    if (phaseFn) {\n      await phaseFn();\n      this.checkIfAborted(signal);\n    }\n  }\n\n  private checkIfAborted(signal: AbortSignal): boolean {\n    if (signal.aborted && !['finished', 'aborted', 'errored'].includes(this.phase as RenderPhase)) {\n      this.phase = 'aborted';\n      this.channel.emit(STORY_RENDER_PHASE_CHANGED, {\n        newPhase: this.phase,\n        renderId: this.renderId,\n        storyId: this.id,\n      });\n    }\n    return signal.aborted;\n  }\n\n  async prepare() {\n    await this.runPhase(this.abortController.signal, 'preparing', async () => {\n      this.story = await this.store.loadStory({ storyId: this.id });\n    });\n\n    if (this.abortController.signal.aborted) {\n      await this.store.cleanupStory(this.story as PreparedStory<TRenderer>);\n      throw PREPARE_ABORTED;\n    }\n  }\n\n  // The two story \"renders\" are equal and have both loaded the same story\n  isEqual(other: Render<TRenderer>): boolean {\n    return !!(\n      this.id === other.id &&\n      this.story &&\n      this.story === (other as StoryRender<TRenderer>).story\n    );\n  }\n\n  isPreparing() {\n    return ['preparing'].includes(this.phase as RenderPhase);\n  }\n\n  isPending() {\n    return ['loading', 'beforeEach', 'rendering', 'playing', 'afterEach'].includes(\n      this.phase as RenderPhase\n    );\n  }\n\n  async renderToElement(canvasElement: TRenderer['canvasElement']) {\n    this.canvasElement = canvasElement;\n\n    // FIXME: this comment\n    // Start the first (initial) render. We don't await here because we need to return the \"cleanup\"\n    // function below right away, so if the user changes story during the first render we can cancel\n    // it without having to first wait for it to finish.\n    // Whenever the selection changes we want to force the component to be remounted.\n    return this.render({ initial: true, forceRemount: true });\n  }\n\n  private storyContext() {\n    if (!this.story) {\n      throw new Error(`Cannot call storyContext before preparing`);\n    }\n    const { forceInitialArgs } = this.renderOptions;\n    return this.store.getStoryContext(this.story, { forceInitialArgs });\n  }\n\n  async render({\n    initial = false,\n    forceRemount = false,\n  }: {\n    initial?: boolean;\n    forceRemount?: boolean;\n  } = {}) {\n    const { canvasElement } = this;\n\n    if (!this.story) {\n      throw new Error('cannot render when not prepared');\n    }\n    const story = this.story;\n\n    if (!canvasElement) {\n      throw new Error('cannot render when canvasElement is unset');\n    }\n\n    const {\n      id,\n      componentId,\n      title,\n      name,\n      tags,\n      applyLoaders,\n      applyBeforeEach,\n      applyAfterEach,\n      unboundStoryFn,\n      playFunction,\n      runStep,\n    } = story;\n\n    if (forceRemount && !initial) {\n      // NOTE: we don't check the cancel actually worked here, so the previous\n      // render could conceivably still be running after this call.\n      // We might want to change that in the future.\n      this.cancelRender();\n      this.abortController = new AbortController();\n    }\n\n    // We need a stable reference to the signal -- if a re-mount happens the\n    // abort controller may be torn down (above) before we actually check the signal.\n    const abortSignal = this.abortController.signal;\n\n    let mounted = false;\n\n    const isMountDestructured = story.usesMount;\n\n    try {\n      const context: StoryContext<TRenderer> = {\n        ...this.storyContext(),\n        viewMode: this.viewMode,\n        abortSignal,\n        canvasElement,\n        loaded: {},\n        step: (label, play) => runStep(label, play, context),\n        context: null!,\n        canvas: {} as Canvas,\n        userEvent: {} as UserEventObject,\n        renderToCanvas: async () => {\n          const teardown = await this.renderToScreen(renderContext, canvasElement);\n          this.teardownRender = teardown || (() => {});\n          mounted = true;\n        },\n        // The story provides (set in a renderer) a mount function that is a higher order function\n        // (context) => (...args) => Canvas\n        //\n        // Before assigning it to the context, we resolve the context dependency,\n        // so that a user can just call it as await mount(...args) in their play function.\n        mount: async (...args) => {\n          this.callbacks.showStoryDuringRender?.();\n          let mountReturn: Awaited<ReturnType<StoryContext['mount']>> = null!;\n          await this.runPhase(abortSignal, 'rendering', async () => {\n            mountReturn = await story.mount(context)(...args);\n          });\n\n          // start playing phase if mount is used inside a play function\n          if (isMountDestructured) {\n            await this.runPhase(abortSignal, 'playing');\n          }\n          return mountReturn;\n        },\n      };\n\n      context.context = context;\n\n      const renderContext: RenderContext<TRenderer> = {\n        componentId,\n        title,\n        kind: title,\n        id,\n        name,\n        story: name,\n        tags,\n        ...this.callbacks,\n        showError: (error) => {\n          this.phase = 'errored';\n          return this.callbacks.showError(error);\n        },\n        showException: (error) => {\n          this.phase = 'errored';\n          return this.callbacks.showException(error);\n        },\n        forceRemount: forceRemount || this.notYetRendered,\n        storyContext: context,\n        storyFn: () => unboundStoryFn(context),\n        unboundStoryFn,\n      };\n      await this.runPhase(abortSignal, 'loading', async () => {\n        context.loaded = await applyLoaders(context);\n      });\n\n      if (abortSignal.aborted) {\n        return;\n      }\n\n      const cleanupCallbacks = await applyBeforeEach(context);\n      this.store.addCleanupCallbacks(story, ...cleanupCallbacks);\n\n      if (this.checkIfAborted(abortSignal)) {\n        return;\n      }\n\n      if (!mounted && !isMountDestructured) {\n        await context.mount();\n      }\n\n      this.notYetRendered = false;\n\n      if (abortSignal.aborted) {\n        return;\n      }\n\n      const ignoreUnhandledErrors =\n        this.story.parameters?.test?.dangerouslyIgnoreUnhandledErrors === true;\n\n      const unhandledErrors: Set<unknown> = new Set<unknown>();\n      const onError = (event: ErrorEvent) => {\n        if (event.error) {\n          unhandledErrors.add(event.error);\n        }\n      };\n      const onUnhandledRejection = (event: PromiseRejectionEvent) => {\n        if (event.reason) {\n          unhandledErrors.add(event.reason);\n        }\n      };\n\n      // The phase should be 'rendering' but it might be set to 'aborted' by another render cycle\n      if (this.renderOptions.autoplay && forceRemount && playFunction && this.phase !== 'errored') {\n        window?.addEventListener?.('error', onError);\n        window?.addEventListener?.('unhandledrejection', onUnhandledRejection);\n        this.disableKeyListeners = true;\n        try {\n          if (!isMountDestructured) {\n            context.mount = async () => {\n              throw new MountMustBeDestructuredError({ playFunction: playFunction.toString() });\n            };\n            await this.runPhase(abortSignal, 'playing', async () => playFunction(context));\n          } else {\n            // when mount is used the playing phase will start later, right after mount is called in the play function\n            await playFunction(context);\n          }\n\n          if (!mounted) {\n            throw new NoStoryMountedError();\n          }\n          this.checkIfAborted(abortSignal);\n\n          if (!ignoreUnhandledErrors && unhandledErrors.size > 0) {\n            await this.runPhase(abortSignal, 'errored');\n          } else {\n            await this.runPhase(abortSignal, 'played');\n          }\n        } catch (error) {\n          // Remove the loading screen, even if there was an error before rendering\n          this.callbacks.showStoryDuringRender?.();\n\n          await this.runPhase(abortSignal, 'errored', async () => {\n            this.channel.emit(PLAY_FUNCTION_THREW_EXCEPTION, serializeError(error));\n          });\n\n          if (this.story.parameters.throwPlayFunctionExceptions !== false) {\n            throw error;\n          }\n          console.error(error);\n        }\n        if (!ignoreUnhandledErrors && unhandledErrors.size > 0) {\n          this.channel.emit(\n            UNHANDLED_ERRORS_WHILE_PLAYING,\n            Array.from(unhandledErrors).map(serializeError)\n          );\n        }\n        this.disableKeyListeners = false;\n        window?.removeEventListener?.('unhandledrejection', onUnhandledRejection);\n        window?.removeEventListener?.('error', onError);\n\n        if (abortSignal.aborted) {\n          return;\n        }\n      }\n\n      await this.runPhase(abortSignal, 'completing', async () => {\n        if (isTestEnvironment()) {\n          this.store.addCleanupCallbacks(story, pauseAnimations());\n        } else {\n          await waitForAnimations(abortSignal);\n        }\n      });\n\n      await this.runPhase(abortSignal, 'completed', async () => {\n        this.channel.emit(STORY_RENDERED, id);\n      });\n\n      if (this.phase !== 'errored') {\n        await this.runPhase(abortSignal, 'afterEach', async () => {\n          await applyAfterEach(context);\n        });\n      }\n\n      const hasUnhandledErrors = !ignoreUnhandledErrors && unhandledErrors.size > 0;\n\n      const hasSomeReportsFailed = context.reporting.reports.some(\n        (report) => report.status === 'failed'\n      );\n\n      const hasStoryErrored = hasUnhandledErrors || hasSomeReportsFailed;\n\n      await this.runPhase(abortSignal, 'finished', async () =>\n        this.channel.emit(STORY_FINISHED, {\n          storyId: id,\n          status: hasStoryErrored ? 'error' : 'success',\n          reporters: context.reporting.reports,\n        } as StoryFinishedPayload)\n      );\n    } catch (err) {\n      this.phase = 'errored';\n      this.callbacks.showException(err as Error);\n\n      await this.runPhase(abortSignal, 'finished', async () =>\n        this.channel.emit(STORY_FINISHED, {\n          storyId: id,\n          status: 'error',\n          reporters: [],\n        } as StoryFinishedPayload)\n      );\n    }\n\n    // If a rerender was enqueued during the render, clear the queue and render again\n    if (this.rerenderEnqueued) {\n      this.rerenderEnqueued = false;\n      this.render();\n    }\n  }\n\n  /**\n   * Rerender the story. If the story is currently pending (loading/rendering), the rerender will be\n   * enqueued, and will be executed after the current render is completed. Rerendering while playing\n   * will not be enqueued, and will be executed immediately, to support rendering args changes while\n   * playing.\n   */\n  async rerender() {\n    if (this.isPending() && this.phase !== 'playing') {\n      this.rerenderEnqueued = true;\n    } else {\n      return this.render();\n    }\n  }\n\n  async remount() {\n    await this.teardown();\n    return this.render({ forceRemount: true });\n  }\n\n  // If the story is torn down (either a new story is rendered or the docs page removes it)\n  // we need to consider the fact that the initial render may not be finished\n  // (possibly the loaders or the play function are still running). We use the controller\n  // as a method to abort them, ASAP, but this is not foolproof as we cannot control what\n  // happens inside the user's code.\n  cancelRender() {\n    this.abortController.abort();\n  }\n\n  cancelPlayFunction() {\n    if (this.phase === 'playing') {\n      this.abortController.abort();\n      this.runPhase(this.abortController.signal, 'aborted');\n    }\n  }\n\n  async teardown() {\n    this.torndown = true;\n    this.cancelRender();\n\n    // If the story has loaded, we need to clean up\n    if (this.story) {\n      await this.store.cleanupStory(this.story);\n    }\n\n    // Check if we're done loading/rendering/playing. If not, we may have to reload the page.\n    // Wait several ticks that may be needed to handle the abort, then try again.\n    // Note that there's a max of 5 nested timeouts before they're no longer \"instant\".\n    for (let i = 0; i < 3; i += 1) {\n      if (!this.isPending()) {\n        await this.teardownRender();\n        return;\n      }\n\n      await new Promise((resolve) => setTimeout(resolve, 0));\n    }\n\n    // If we still haven't completed, reload the page (iframe) to ensure we have a clean slate\n    // for the next render. Since the reload can take a brief moment to happen, we want to stop\n    // further rendering by awaiting a never-resolving promise (which is destroyed on reload).\n    window?.location?.reload?.();\n    await new Promise(() => {});\n  }\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/render/animation-utils.ts",
    "content": "import type { CleanupCallback } from 'storybook/internal/csf';\n\nconst ANIMATION_TIMEOUT = 5000;\n\nexport function isTestEnvironment() {\n  try {\n    return (\n      // @ts-expect-error This property exists in Vitest browser mode\n      !!globalThis.__vitest_browser__ ||\n      !!globalThis.window?.navigator?.userAgent?.match(/StorybookTestRunner/)\n    );\n  } catch {\n    return false;\n  }\n}\n\n// Pause all animations and transitions by overriding the CSS properties\nexport function pauseAnimations(atEnd = true): CleanupCallback {\n  if (!('document' in globalThis && 'createElement' in globalThis.document)) {\n    // Don't run in React Native\n    return () => {};\n  }\n\n  // Remove all animations\n  const disableStyle = document.createElement('style');\n  disableStyle.textContent = `*, *:before, *:after {\n    animation: none !important;\n  }`;\n  document.head.appendChild(disableStyle);\n\n  // Pause any new animations\n  const pauseStyle = document.createElement('style');\n  pauseStyle.textContent = `*, *:before, *:after {\n    animation-delay: 0s !important;\n    animation-direction: ${atEnd ? 'reverse' : 'normal'} !important;\n    animation-play-state: paused !important;\n    transition: none !important;\n  }`;\n  document.head.appendChild(pauseStyle);\n\n  // Force a reflow\n  // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n  document.body.clientHeight;\n\n  // Now recreate all animations, getting paused in their initial state\n  document.head.removeChild(disableStyle);\n\n  return () => {\n    pauseStyle.parentNode?.removeChild(pauseStyle);\n  };\n}\n\n// Use the Web Animations API to wait for any animations and transitions to finish\nexport async function waitForAnimations(signal?: AbortSignal) {\n  if (\n    !(\n      'document' in globalThis &&\n      'getAnimations' in globalThis.document &&\n      'querySelectorAll' in globalThis.document\n    )\n  ) {\n    // Don't run in React Native\n    return;\n  }\n\n  let timedOut = false;\n  await Promise.race([\n    // After 50ms, retrieve any running animations and wait for them to finish\n    // If new animations are created while waiting, we'll wait for them too\n    new Promise((resolve) => {\n      setTimeout(() => {\n        const animationRoots = [globalThis.document, ...getShadowRoots(globalThis.document)];\n        const checkAnimationsFinished = async () => {\n          if (timedOut || signal?.aborted) {\n            return;\n          }\n          const runningAnimations = animationRoots\n            .flatMap((el) => el?.getAnimations?.() || [])\n            .filter((a) => a.playState === 'running' && !isInfiniteAnimation(a));\n          if (runningAnimations.length > 0) {\n            // Treat any errors (e.g. AbortError) from `finished` as also finished, even though not successfully so\n            await Promise.allSettled(runningAnimations.map(async (a) => a.finished));\n            await checkAnimationsFinished();\n          }\n        };\n        checkAnimationsFinished().then(resolve);\n      }, 100);\n    }),\n\n    // If animations don't finish within the timeout, continue without waiting\n    new Promise((resolve) =>\n      setTimeout(() => {\n        timedOut = true;\n        resolve(void 0);\n      }, ANIMATION_TIMEOUT)\n    ),\n  ]);\n}\n\nfunction getShadowRoots(doc: Document | ShadowRoot) {\n  return [doc, ...doc.querySelectorAll('*')].reduce<ShadowRoot[]>((acc, el) => {\n    if ('shadowRoot' in el && el.shadowRoot) {\n      acc.push(el.shadowRoot, ...getShadowRoots(el.shadowRoot));\n    }\n    return acc;\n  }, []);\n}\n\nfunction isInfiniteAnimation(anim: Animation) {\n  if (anim instanceof CSSAnimation && anim.effect instanceof KeyframeEffect && anim.effect.target) {\n    const style = getComputedStyle(anim.effect.target, anim.effect.pseudoElement);\n    const index = style.animationName?.split(', ').indexOf(anim.animationName);\n    const iterations = style.animationIterationCount.split(', ')[index];\n    return iterations === 'infinite';\n  }\n  return false;\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/render/mount-utils.test.ts",
    "content": "import { expect, test } from 'vitest';\n\nimport { getUsedProps } from './mount-utils.ts';\n\nconst StoryWithContext = {\n  play: async (context: any) => {\n    console.log(context);\n  },\n};\n\nconst StoryWitCanvasElement = {\n  play: async ({ canvasElement }: any) => {\n    console.log(canvasElement);\n  },\n};\n\nconst MountStory = {\n  play: async ({ mount }: any) => {\n    await mount();\n  },\n};\n\nconst LongDefinition = {\n  play: async ({\n    mount,\n    veryLongDefinitionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn,\n    over,\n    multiple,\n    lines,\n  }: any) => {\n    await mount();\n  },\n};\n\nconst MethodProperty = {\n  async play({\n    mount,\n    veryLongDefinitionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn,\n    over,\n    multiple,\n    lines,\n  }: any) {\n    await mount();\n  },\n};\n\nconst TranspiledDefinition = {\n  play: async (context: any) => {\n    const {\n      mount,\n      veryLongTranspiledDefinitionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn,\n      over,\n      multiple,\n      lines,\n    } = context;\n    await mount();\n  },\n};\n\nconst LateDestructuring = {\n  play: async (a: any) => {\n    console.log(a);\n    const {\n      mount,\n      veryLongTranspiledDefinitionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn,\n      over,\n      multiple,\n      lines,\n    } = a;\n    await mount();\n  },\n};\n\nconst WithComment = {\n  play: async (context: any) => {\n    const {\n      // a comment\n      mount,\n    } = context;\n    await mount();\n  },\n};\n\nconst WithTrailingComment = {\n  play: async (context: any) => {\n    const {\n      mount, // a comment\n    } = context;\n    await mount();\n  },\n};\n\nconst WithMultipleComments = {\n  play: async (context: any) => {\n    const {\n      mount, // a comment\n      // another comment\n    } = context;\n    await mount();\n  },\n};\n\nconst WithBlockComments = {\n  play: async (context: any) => {\n    const { mount /* a comment */ } = context;\n    /* another comment */\n    await mount();\n    /* third comment */\n  },\n};\n\nconst testingScope = {\n  mount: async (m: any) => {\n    return 'testingScope.mount';\n  },\n};\n\nconst IncorrectMount = {\n  play: async (context: any) => {\n    const { mount } = testingScope;\n    const { mount: sbMount } = context;\n    mount(await sbMount());\n  },\n};\n\ntest('Detect basic destructuring', () => {\n  expect(getUsedProps(StoryWithContext.play)).toMatchInlineSnapshot(`[]`);\n  expect(getUsedProps(StoryWitCanvasElement.play)).toMatchInlineSnapshot(`\n    [\n      \"canvasElement\",\n    ]\n  `);\n  expect(getUsedProps(MountStory.play)).toMatchInlineSnapshot(`\n    [\n      \"mount\",\n    ]\n  `);\n});\n\ntest('Detect multiline destructuring', () => {\n  expect(getUsedProps(LongDefinition.play)).toMatchInlineSnapshot(`\n    [\n      \"mount\",\n      \"veryLongDefinitionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\",\n      \"over\",\n      \"multiple\",\n      \"lines\",\n    ]\n  `);\n  expect(getUsedProps(MethodProperty.play)).toMatchInlineSnapshot(`\n    [\n      \"mount\",\n      \"veryLongDefinitionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\",\n      \"over\",\n      \"multiple\",\n      \"lines\",\n    ]\n  `);\n});\n\ntest('Detect transpiled destructuring', () => {\n  expect(getUsedProps(TranspiledDefinition.play)).toMatchInlineSnapshot(`\n      [\n        \"mount\",\n        \"veryLongTranspiledDefinitionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\",\n        \"over\",\n        \"multiple\",\n        \"lines\",\n      ]\n    `);\n\n  expect(getUsedProps(LateDestructuring.play)).toMatchInlineSnapshot(`[]`);\n});\n\ntest('Detect with comment', () => {\n  expect(getUsedProps(WithComment.play)).toMatchInlineSnapshot(`\n      [\n        \"mount\",\n      ]\n    `);\n});\n\ntest('Detect with trailing comment', () => {\n  expect(getUsedProps(WithTrailingComment.play)).toMatchInlineSnapshot(`\n    [\n      \"mount\",\n    ]\n  `);\n});\n\ntest('Detect with multiple comments', () => {\n  expect(getUsedProps(WithMultipleComments.play)).toMatchInlineSnapshot(`\n    [\n      \"mount\",\n    ]\n  `);\n});\n\ntest('Detect with block comments', () => {\n  expect(getUsedProps(WithBlockComments.play)).toMatchInlineSnapshot(`\n    [\n      \"mount\",\n    ]\n  `);\n});\n\ntest('Detect incorrect mount', () => {\n  expect(getUsedProps(IncorrectMount.play)).toMatchInlineSnapshot(`[]`);\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/render/mount-utils.ts",
    "content": "// Inspired by Vitest fixture implementation:\n// https://github.com/vitest-dev/vitest/blob/200a4349a2f85686bc7005dce686d9d1b48b84d2/packages/runner/src/fixture.ts\nexport function mountDestructured(playFunction?: (...args: any[]) => any): boolean {\n  return playFunction != null && getUsedProps(playFunction).includes('mount');\n}\n\n/**\n * Extracts a list of properties destructured from the argument of a play function, either inline or\n * as the first statement in the body of the function.\n *\n * @param fn - The function to extract the properties from.\n * @returns An array of property names.\n */\nexport function getUsedProps(fn: (...args: unknown[]) => unknown) {\n  const [, args, body] = fn.toString().match(/[^(]*\\(([^)]+)\\)(?:.*{([^]+)})?/) || [];\n  if (!args) {\n    return [];\n  }\n\n  const [firstArg] = splitByComma(args);\n  if (!firstArg) {\n    return [];\n  }\n\n  const [, destructuredProps] = firstArg.match(/^{([^]+)}$/) || [];\n  if (destructuredProps) {\n    return splitByComma(stripComments(destructuredProps)).map((prop) =>\n      prop.replace(/:.*|=.*/g, '').trim()\n    );\n  }\n\n  if (!firstArg.match(/^[a-z_$][0-9a-z_$]*$/i)) {\n    return [];\n  }\n\n  const escapedArg = firstArg.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n  const [, destructuredArg] =\n    body?.trim()?.match(new RegExp(`^(?:const|let|var)\\\\s*{([^}]+)}\\\\s*=\\\\s*${escapedArg};`)) || [];\n  if (destructuredArg) {\n    return splitByComma(stripComments(destructuredArg)).map((prop) =>\n      prop.replace(/:.*|=.*/g, '').trim()\n    );\n  }\n\n  return [];\n}\n\n/**\n * Strips JavaScript comments from a string.\n *\n * @param s - The string to strip comments from.\n * @returns The string with comments removed.\n */\nfunction stripComments(s: string): string {\n  // Remove single-line comments (// ...)\n  s = s.replace(/\\/\\/.*$/gm, '');\n  // Remove multi-line comments (/* ... */)\n  s = s.replace(/\\/\\*[\\s\\S]*?\\*\\//g, '');\n  return s;\n}\n\n/**\n * Splits a string by top-level commas, ignoring commas nested within curly or square brackets.\n *\n * This is useful for parsing function argument lists or destructured object patterns where elements\n * inside nested structures (like { a, b: [x, y], c }) should not be split.\n *\n * @param s - The string to split.\n * @returns An array of substrings split by top-level commas.\n */\nfunction splitByComma(s: string) {\n  const result = [];\n  const stack = [];\n  let start = 0;\n  for (let i = 0; i < s.length; i++) {\n    if (s[i] === '{' || s[i] === '[') {\n      stack.push(s[i] === '{' ? '}' : ']');\n    } else if (s[i] === stack[stack.length - 1]) {\n      stack.pop();\n    } else if (!stack.length && s[i] === ',') {\n      const token = s.substring(start, i).trim();\n\n      if (token) {\n        result.push(token);\n      }\n      start = i + 1;\n    }\n  }\n  const lastToken = s.substring(start).trim();\n\n  if (lastToken) {\n    result.push(lastToken);\n  }\n  return result;\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/simulate-pageload.test.ts",
    "content": "// @vitest-environment happy-dom\nimport { describe, expect, it } from 'vitest';\n\nimport { global } from '@storybook/global';\n\nimport { simulatePageLoad } from './simulate-pageload.ts';\n\nconst { document } = global;\n\ndescribe('simulatePageLoad', () => {\n  it('should add script with type module to scripts root', () => {\n    const container = document.createElement('div');\n    const script = document.createElement('script');\n    script.type = 'module';\n    container.appendChild(script);\n\n    simulatePageLoad(container);\n\n    expect(document.body.innerHTML).toEqual(\n      '<div id=\"scripts-root\"><script type=\"module\"></script></div>'\n    );\n  });\n\n  it('should add script with proper mime type to scripts root', () => {\n    const container = document.createElement('div');\n    const script = document.createElement('script');\n    script.type = 'application/javascript';\n    container.appendChild(script);\n\n    simulatePageLoad(container);\n\n    expect(document.body.innerHTML).toEqual(\n      '<div id=\"scripts-root\"><script type=\"text/javascript\"></script></div>'\n    );\n  });\n\n  it('should add script without type to scripts root', () => {\n    const container = document.createElement('div');\n    const script = document.createElement('script');\n    container.appendChild(script);\n\n    simulatePageLoad(container);\n\n    expect(document.body.innerHTML).toEqual(\n      '<div id=\"scripts-root\"><script type=\"text/javascript\"></script></div>'\n    );\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/preview-web/simulate-pageload.ts",
    "content": "import { global } from '@storybook/global';\n\nconst { document } = global;\n\n// https://html.spec.whatwg.org/multipage/scripting.html\nconst runScriptTypes = [\n  'application/javascript',\n  'application/ecmascript',\n  'application/x-ecmascript',\n  'application/x-javascript',\n  'text/ecmascript',\n  'text/javascript',\n  'text/javascript1.0',\n  'text/javascript1.1',\n  'text/javascript1.2',\n  'text/javascript1.3',\n  'text/javascript1.4',\n  'text/javascript1.5',\n  'text/jscript',\n  'text/livescript',\n  'text/x-ecmascript',\n  'text/x-javascript',\n  // Support modern javascript\n  'module',\n];\n\nconst SCRIPT = 'script';\nconst SCRIPTS_ROOT_ID = 'scripts-root';\n\n// trigger DOMContentLoaded\nexport function simulateDOMContentLoaded() {\n  const DOMContentLoadedEvent = document.createEvent('Event');\n  DOMContentLoadedEvent.initEvent('DOMContentLoaded', true, true);\n  document.dispatchEvent(DOMContentLoadedEvent);\n}\n\nfunction insertScript($script: any, callback: any, $scriptRoot: any) {\n  const scriptEl = document.createElement('script');\n  scriptEl.type = $script.type === 'module' ? 'module' : 'text/javascript';\n  if ($script.src) {\n    scriptEl.onload = callback;\n    scriptEl.onerror = callback;\n    scriptEl.src = $script.src;\n  } else {\n    scriptEl.textContent = $script.innerText;\n  }\n\n  // re-insert the script tag so it executes.\n\n  // re-insert the script tag so it executes.\n  if ($scriptRoot) {\n    $scriptRoot.appendChild(scriptEl);\n  } else {\n    document.head.appendChild(scriptEl);\n  }\n\n  // clean-up\n\n  // clean-up\n  $script.parentNode.removeChild($script);\n\n  // run the callback immediately for inline scripts\n\n  // run the callback immediately for inline scripts\n  if (!$script.src) {\n    callback();\n  }\n}\n\n// runs an array of async functions in sequential order\n\nfunction insertScriptsSequentially(scriptsToExecute: any[], callback: any, index = 0) {\n  scriptsToExecute[index](() => {\n    index++;\n    if (index === scriptsToExecute.length) {\n      callback();\n    } else {\n      insertScriptsSequentially(scriptsToExecute, callback, index);\n    }\n  });\n}\n\nexport function simulatePageLoad($container: any) {\n  let $scriptsRoot = document.getElementById(SCRIPTS_ROOT_ID);\n  if (!$scriptsRoot) {\n    $scriptsRoot = document.createElement('div');\n    $scriptsRoot.id = SCRIPTS_ROOT_ID;\n    document.body.appendChild($scriptsRoot);\n  } else {\n    $scriptsRoot.innerHTML = '';\n  }\n  const $scripts = Array.from($container.querySelectorAll(SCRIPT));\n\n  if ($scripts.length) {\n    const scriptsToExecute: any[] = [];\n    $scripts.forEach(($script: any) => {\n      const typeAttr = $script.getAttribute('type');\n\n      // only run script tags without the type attribute\n      // or with a javascript mime attribute value from the list\n      if (!typeAttr || runScriptTypes.includes(typeAttr)) {\n        scriptsToExecute.push((callback: any) => insertScript($script, callback, $scriptsRoot));\n      }\n    });\n\n    // insert the script tags sequentially\n    // to preserve execution order\n    if (scriptsToExecute.length) {\n      insertScriptsSequentially(scriptsToExecute, simulateDOMContentLoaded, undefined);\n    }\n  } else {\n    simulateDOMContentLoaded();\n  }\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/ArgsStore.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { ArgsStore } from './ArgsStore.ts';\n\nvi.mock('storybook/internal/client-logger');\n\nconst stringType = { type: { name: 'string' } };\nconst booleanType = { type: { name: 'boolean' } };\n\ndescribe('ArgsStore', () => {\n  describe('setInitial / get', () => {\n    it('returns in a straightforward way', () => {\n      const store = new ArgsStore();\n      store.setInitial({ id: 'id', initialArgs: { foo: 'bar' } } as any);\n      expect(store.get('id')).toEqual({ foo: 'bar' });\n    });\n\n    it('throws if you try to get non-existent', () => {\n      const store = new ArgsStore();\n      expect(() => store.get('id')).toThrow(/No args known/);\n    });\n\n    describe('on second call for same story', () => {\n      describe('if initialArgs are unchanged', () => {\n        it('does nothing if the args are untouched', () => {\n          const store = new ArgsStore();\n\n          const previousStory = {\n            id: 'id',\n            initialArgs: { a: '1', b: '1' },\n            argTypes: { a: stringType, b: stringType },\n          } as any;\n          store.setInitial(previousStory);\n\n          const story = {\n            id: 'id',\n            initialArgs: { a: '1', b: '1' },\n            argTypes: { a: stringType, b: stringType },\n          } as any;\n\n          store.setInitial(story);\n          expect(store.get(story.id)).toEqual({ a: '1', b: '1' });\n        });\n\n        it('retains any arg changes', () => {\n          const store = new ArgsStore();\n\n          const previousStory = {\n            id: 'id',\n            initialArgs: { a: '1', b: false, c: 'unchanged' },\n            argTypes: { a: stringType, b: booleanType, c: stringType },\n          } as any;\n          store.setInitial(previousStory);\n\n          // NOTE: I'm not sure technically you should be allowed to set d here, but\n          // let's make sure we behave sensibly if you do\n          store.update('id', { a: 'update', b: true, d: 'update' });\n\n          const story = {\n            id: 'id',\n            initialArgs: { a: '1', b: false, c: 'unchanged' },\n            argTypes: { a: stringType, b: booleanType, c: stringType },\n          } as any;\n\n          store.setInitial(story);\n          // In any case c is not retained.\n          expect(store.get(story.id)).toEqual({ a: 'update', b: true, c: 'unchanged' });\n        });\n      });\n\n      describe('when initialArgs change', () => {\n        it('replaces old args with new if the args are untouched', () => {\n          const store = new ArgsStore();\n\n          const previousStory = {\n            id: 'id',\n            initialArgs: { a: '1', b: '1' },\n            argTypes: { a: stringType, b: stringType },\n          } as any;\n          store.setInitial(previousStory);\n\n          const story = {\n            id: 'id',\n            initialArgs: { a: '1', c: '1' },\n            argTypes: { a: stringType, c: stringType },\n          } as any;\n\n          store.setInitial(story);\n          expect(store.get(story.id)).toEqual({ a: '1', c: '1' });\n        });\n\n        it('applies the same delta if the args are changed', () => {\n          const store = new ArgsStore();\n\n          const previousStory = {\n            id: 'id',\n            initialArgs: { a: '1', b: '1' },\n            argTypes: { a: stringType, b: stringType },\n          } as any;\n          store.setInitial(previousStory);\n\n          // NOTE: I'm not sure technically you should be allowed to set c here\n          store.update('id', { a: 'update', c: 'update' });\n\n          const story = {\n            id: 'id',\n            initialArgs: { a: '2', d: '2' },\n            argTypes: { a: stringType, d: stringType },\n          } as any;\n\n          store.setInitial(story);\n          // In any case c is not retained.\n          expect(store.get(story.id)).toEqual({ a: 'update', d: '2' });\n        });\n      });\n    });\n  });\n\n  describe('update', () => {\n    it('overrides on a per-key basis', () => {\n      const store = new ArgsStore();\n\n      store.setInitial({ id: 'id', initialArgs: {} } as any);\n\n      store.update('id', { foo: 'bar' });\n      expect(store.get('id')).toEqual({ foo: 'bar' });\n\n      store.update('id', { baz: 'bing' });\n      expect(store.get('id')).toEqual({ foo: 'bar', baz: 'bing' });\n    });\n\n    it('does not merge objects', () => {\n      const store = new ArgsStore();\n\n      store.setInitial({ id: 'id', initialArgs: {} } as any);\n\n      store.update('id', { obj: { foo: 'bar' } });\n      expect(store.get('id')).toEqual({ obj: { foo: 'bar' } });\n\n      store.update('id', { obj: { baz: 'bing' } });\n      expect(store.get('id')).toEqual({ obj: { baz: 'bing' } });\n    });\n\n    it('does not set keys to undefined, it simply unsets them', () => {\n      const store = new ArgsStore();\n\n      store.setInitial({ id: 'id', initialArgs: { foo: 'bar' } } as any);\n\n      store.update('id', { foo: undefined });\n      expect('foo' in store.get('id')).toBe(false);\n    });\n  });\n\n  describe('updateFromPersisted', () => {\n    it('ensures the types of args are correct', () => {\n      const store = new ArgsStore();\n\n      store.setInitial({ id: 'id', initialArgs: {} } as any);\n\n      const story = {\n        id: 'id',\n        argTypes: { a: stringType },\n      } as any;\n      store.updateFromPersisted(story, { a: 'str' });\n      expect(store.get('id')).toEqual({ a: 'str' });\n\n      store.updateFromPersisted(story, { a: 42 });\n      expect(store.get('id')).toEqual({ a: '42' });\n    });\n\n    it('merges objects and sparse arrays', () => {\n      const store = new ArgsStore();\n\n      store.setInitial({ id: 'id', initialArgs: { a: { foo: 'bar' }, b: ['1', '2', '3'] } } as any);\n\n      const story = {\n        id: 'id',\n        argTypes: {\n          a: { type: { name: 'object', value: { name: 'string' } } },\n          b: { type: { name: 'array', value: { name: 'string' } } },\n        },\n      } as any;\n      store.updateFromPersisted(story, { a: { baz: 'bing' } });\n      expect(store.get('id')).toEqual({\n        a: { foo: 'bar', baz: 'bing' },\n        b: ['1', '2', '3'],\n      });\n\n      store.updateFromPersisted(story, { b: [, , '4'] });\n      expect(store.get('id')).toEqual({\n        a: { foo: 'bar', baz: 'bing' },\n        b: ['1', '2', '4'],\n      });\n    });\n\n    it('checks args are allowed options', () => {\n      const store = new ArgsStore();\n\n      store.setInitial({ id: 'id', initialArgs: {} } as any);\n\n      const story = {\n        id: 'id',\n        argTypes: { a: { type: { name: 'string' }, options: ['a', 'b'] } },\n      } as any;\n      store.updateFromPersisted(story, { a: 'random' });\n      expect(store.get('id')).toEqual({});\n\n      store.updateFromPersisted(story, { a: 'a' });\n      expect(store.get('id')).toEqual({ a: 'a' });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/ArgsStore.ts",
    "content": "import type { PreparedStory } from 'storybook/internal/types';\nimport type { Args, StoryId } from 'storybook/internal/types';\n\nimport { DEEPLY_EQUAL, combineArgs, deepDiff, mapArgsToTypes, validateOptions } from './args.ts';\n\nfunction deleteUndefined(obj: Record<string, any>) {\n  Object.keys(obj).forEach((key) => obj[key] === undefined && delete obj[key]);\n  return obj;\n}\n\nexport class ArgsStore {\n  initialArgsByStoryId: Record<StoryId, Args> = {};\n\n  argsByStoryId: Record<StoryId, Args> = {};\n\n  get(storyId: StoryId) {\n    if (!(storyId in this.argsByStoryId)) {\n      throw new Error(`No args known for ${storyId} -- has it been rendered yet?`);\n    }\n\n    return this.argsByStoryId[storyId];\n  }\n\n  setInitial(story: PreparedStory<any>) {\n    if (!this.initialArgsByStoryId[story.id]) {\n      this.initialArgsByStoryId[story.id] = story.initialArgs;\n      this.argsByStoryId[story.id] = story.initialArgs;\n    } else if (this.initialArgsByStoryId[story.id] !== story.initialArgs) {\n      // When we get a new version of a story (with new initialArgs), we re-apply the same diff\n      // that we had previously applied to the old version of the story\n      const delta = deepDiff(this.initialArgsByStoryId[story.id], this.argsByStoryId[story.id]);\n      this.initialArgsByStoryId[story.id] = story.initialArgs;\n      this.argsByStoryId[story.id] = story.initialArgs;\n      if (delta !== DEEPLY_EQUAL) {\n        this.updateFromDelta(story, delta);\n      }\n    }\n  }\n\n  updateFromDelta(story: PreparedStory<any>, delta: Args) {\n    // Use the argType to ensure we setting a type with defined options to something outside of that\n    const validatedDelta = validateOptions(delta, story.argTypes);\n\n    // NOTE: we use `combineArgs` here rather than `combineParameters` because changes to arg\n    // array values are persisted in the URL as sparse arrays, and we have to take that into\n    // account when overriding the initialArgs (e.g. we patch [,'changed'] over ['initial', 'val'])\n    this.argsByStoryId[story.id] = combineArgs(this.argsByStoryId[story.id], validatedDelta);\n  }\n\n  updateFromPersisted(story: PreparedStory<any>, persisted: Args) {\n    // Use the argType to ensure we aren't persisting the wrong type of value to the type.\n    // For instance you could try and set a string-valued arg to a number by changing the URL\n    const mappedPersisted = mapArgsToTypes(persisted, story.argTypes);\n\n    return this.updateFromDelta(story, mappedPersisted);\n  }\n\n  update(storyId: StoryId, argsUpdate: Partial<Args>) {\n    if (!(storyId in this.argsByStoryId)) {\n      throw new Error(`No args known for ${storyId} -- has it been rendered yet?`);\n    }\n\n    this.argsByStoryId[storyId] = deleteUndefined({\n      ...this.argsByStoryId[storyId],\n      ...argsUpdate,\n    });\n  }\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/GlobalsStore.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { GlobalsStore } from './GlobalsStore.ts';\n\nvi.mock('storybook/internal/client-logger', () => ({\n  logger: {\n    warn: vi.fn(),\n  },\n}));\n\ndescribe('GlobalsStore', () => {\n  it('is initialized to the value in globals', () => {\n    const store = new GlobalsStore({\n      globals: {\n        arg1: 'arg1',\n        arg2: 2,\n        arg3: { complex: { object: ['type'] } },\n      },\n      globalTypes: {},\n    });\n\n    expect(store.get()).toEqual({\n      arg1: 'arg1',\n      arg2: 2,\n      arg3: { complex: { object: ['type'] } },\n    });\n  });\n\n  it('is initialized to the default values from globalTypes if global is unset', () => {\n    const store = new GlobalsStore({\n      globals: {\n        arg1: 'arg1',\n        arg2: 2,\n      },\n      globalTypes: {\n        arg2: { defaultValue: 'arg2' },\n        arg3: { defaultValue: { complex: { object: ['type'] } } },\n      },\n    });\n\n    expect(store.get()).toEqual({\n      // NOTE: we keep arg1, even though it doesn't have a globalArgType\n      arg1: 'arg1',\n      arg2: 2,\n      arg3: { complex: { object: ['type'] } },\n    });\n  });\n\n  describe('update', () => {\n    it('changes the global args', () => {\n      const store = new GlobalsStore({ globals: { foo: 'old' }, globalTypes: { baz: {} } });\n\n      store.update({ foo: 'bar' });\n      expect(store.get()).toEqual({ foo: 'bar' });\n\n      store.update({ baz: 'bing' });\n      expect(store.get()).toEqual({ foo: 'bar', baz: 'bing' });\n    });\n\n    it('does not merge objects', () => {\n      const store = new GlobalsStore({\n        globals: { obj: { foo: 'old' } },\n        globalTypes: { baz: {} },\n      });\n\n      store.update({ obj: { foo: 'bar' } });\n      expect(store.get()).toEqual({ obj: { foo: 'bar' } });\n\n      store.update({ obj: { baz: 'bing' } });\n      expect(store.get()).toEqual({ obj: { baz: 'bing' } });\n    });\n  });\n\n  describe('updateFromPersisted', () => {\n    it('only sets values for which globals or globalArgs exist', () => {\n      const store = new GlobalsStore({\n        globals: {\n          arg1: 'arg1',\n        },\n        globalTypes: {\n          arg2: { defaultValue: 'arg2' },\n        },\n      });\n\n      store.updateFromPersisted({\n        arg1: 'new-arg1',\n        arg2: 'new-arg2',\n        arg3: 'new-arg3',\n      });\n\n      expect(store.get()).toEqual({ arg1: 'new-arg1', arg2: 'new-arg2' });\n    });\n  });\n\n  describe('second call to set', () => {\n    it('is initialized to the (new) default values from globalTypes if the (new) global is unset', () => {\n      const store = new GlobalsStore({ globals: {}, globalTypes: {} });\n\n      expect(store.get()).toEqual({});\n\n      store.set({\n        globals: {\n          arg1: 'arg1',\n          arg2: 2,\n        },\n        globalTypes: {\n          arg2: { defaultValue: 'arg2' },\n          arg3: { defaultValue: { complex: { object: ['type'] } } },\n        },\n      });\n\n      expect(store.get()).toEqual({\n        // NOTE: we keep arg1, even though it doesn't have a globalArgType\n        arg1: 'arg1',\n        arg2: 2,\n        arg3: { complex: { object: ['type'] } },\n      });\n    });\n\n    describe('when underlying globals have not changed', () => {\n      it('retains updated values, but not if they are undeclared', () => {\n        const store = new GlobalsStore({\n          globals: {\n            arg1: 'arg1',\n            arg2: 'arg2',\n            arg3: 'arg3',\n          },\n          globalTypes: {\n            arg2: { defaultValue: 'arg2' },\n          },\n        });\n\n        store.update({\n          arg1: 'new-arg1',\n          arg2: 'new-arg2',\n          arg3: 'new-arg3',\n        });\n\n        // You can set undeclared values (currently, deprecated)\n        expect(store.get()).toEqual({ arg1: 'new-arg1', arg2: 'new-arg2', arg3: 'new-arg3' });\n\n        store.set({\n          globals: {\n            arg1: 'arg1',\n          },\n          globalTypes: {\n            arg2: { defaultValue: 'arg2' },\n          },\n        });\n        // However undeclared values aren't persisted\n        expect(store.get()).toEqual({ arg1: 'new-arg1', arg2: 'new-arg2' });\n      });\n    });\n\n    describe('when underlying globals have changed', () => {\n      it('retains a the same delta', () => {\n        const store = new GlobalsStore({\n          globals: {\n            arg1: 'arg1',\n            arg2: 'arg1',\n            arg3: 'arg1',\n            arg4: 'arg4',\n          },\n          globalTypes: {\n            arg2: { defaultValue: 'arg2' },\n          },\n        });\n\n        store.update({\n          arg1: 'new-arg1',\n          arg2: 'new-arg2',\n          arg3: 'new-arg3',\n        });\n\n        expect(store.get()).toEqual({\n          arg1: 'new-arg1',\n          arg2: 'new-arg2',\n          // You can set undeclared values (currently, deprecated)\n          arg3: 'new-arg3',\n          arg4: 'arg4',\n        });\n\n        store.set({\n          globals: {\n            arg1: 'edited-arg1',\n            arg4: 'edited-arg4',\n          },\n          globalTypes: {\n            arg5: { defaultValue: 'edited-arg5' },\n          },\n        });\n        // However undeclared values aren't persisted\n        expect(store.get()).toEqual({\n          arg1: 'new-arg1',\n          arg4: 'edited-arg4',\n          arg5: 'edited-arg5',\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/GlobalsStore.ts",
    "content": "import { logger } from 'storybook/internal/client-logger';\nimport type { GlobalTypes, Globals } from 'storybook/internal/types';\n\nimport { DEEPLY_EQUAL, deepDiff } from './args.ts';\nimport { getValuesFromGlobalTypes } from './csf/getValuesFromGlobalTypes.ts';\n\nexport class GlobalsStore {\n  // We use ! here because TS doesn't analyse the .set() function to see if it actually get set\n  allowedGlobalNames!: Set<string>;\n\n  initialGlobals!: Globals;\n\n  globals!: Globals;\n\n  constructor({\n    globals = {},\n    globalTypes = {},\n  }: {\n    globals?: Globals;\n    globalTypes?: GlobalTypes;\n  }) {\n    this.set({ globals, globalTypes });\n  }\n\n  set({ globals = {}, globalTypes = {} }: { globals?: Globals; globalTypes?: GlobalTypes }) {\n    const delta = this.initialGlobals && deepDiff(this.initialGlobals, this.globals);\n\n    this.allowedGlobalNames = new Set([...Object.keys(globals), ...Object.keys(globalTypes)]);\n\n    const defaultGlobals: Globals = getValuesFromGlobalTypes(globalTypes);\n    this.initialGlobals = { ...defaultGlobals, ...globals };\n\n    this.globals = this.initialGlobals;\n    if (delta && delta !== DEEPLY_EQUAL) {\n      this.updateFromPersisted(delta);\n    }\n  }\n\n  filterAllowedGlobals(globals: Globals) {\n    return Object.entries(globals).reduce((acc, [key, value]) => {\n      if (this.allowedGlobalNames.has(key)) {\n        acc[key] = value;\n      } else {\n        logger.warn(\n          `Attempted to set a global (${key}) that is not defined in initial globals or globalTypes`\n        );\n      }\n      return acc;\n    }, {} as Globals);\n  }\n\n  updateFromPersisted(persisted: Globals) {\n    const allowedUrlGlobals = this.filterAllowedGlobals(persisted);\n    // Note that unlike args, we do not have the same type information for globals to allow us\n    // to type check them here, so we just set them naively\n    this.globals = { ...this.globals, ...allowedUrlGlobals };\n  }\n\n  get() {\n    return this.globals;\n  }\n\n  update(newGlobals: Globals) {\n    this.globals = { ...this.globals, ...this.filterAllowedGlobals(newGlobals) };\n\n    for (const key in newGlobals) {\n      if (newGlobals[key] === undefined) {\n        this.globals[key] = this.initialGlobals[key];\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/StoryIndexStore.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport type { StoryIndex } from 'storybook/internal/types';\n\nimport { StoryIndexStore } from './StoryIndexStore.ts';\n\nvi.mock('@storybook/channel-websocket', () => () => ({ on: vi.fn() }));\n\nconst storyIndex: StoryIndex = {\n  v: 5,\n  entries: {\n    'component-one--a': {\n      type: 'story',\n      subtype: 'story',\n      id: 'component-one--a',\n      title: 'Component One',\n      name: 'A',\n      importPath: './src/ComponentOne.stories.js',\n    },\n    'component-one--b': {\n      type: 'story',\n      subtype: 'story',\n      id: 'component-one--b',\n      title: 'Component One',\n      name: 'B',\n      importPath: './src/ComponentOne.stories.js',\n    },\n    'component-two--c': {\n      type: 'story',\n      subtype: 'story',\n      id: 'component-two--c',\n      title: 'Component Two',\n      name: 'C',\n      importPath: './src/ComponentTwo.stories.js',\n    },\n  },\n};\n\nconst makeStoryIndex = (titlesAndNames: any) => {\n  return {\n    v: 5,\n    entries: Object.fromEntries(\n      titlesAndNames.map(([title, name]: [any, any]) => {\n        const id = `${title}--${name}`.replace('/', '-');\n        return [\n          id,\n          {\n            id,\n            title,\n            name,\n            importPath: `./src/${title}.stories.js`,\n          },\n        ];\n      })\n    ),\n  };\n};\n\ndescribe('StoryIndexStore', () => {\n  describe('entryFromSpecifier', () => {\n    describe('if you use *', () => {\n      it('selects the first story in the store', async () => {\n        const store = new StoryIndexStore(storyIndex);\n\n        expect(store.entryFromSpecifier('*')).toEqual(store.entries['component-one--a']);\n      });\n\n      it('selects nothing if there are no stories', async () => {\n        const store = new StoryIndexStore(makeStoryIndex([]));\n\n        expect(store.entryFromSpecifier('*')).toBeUndefined();\n      });\n    });\n\n    describe('if you use a component or group id', () => {\n      it('selects the first story for the component', async () => {\n        const store = new StoryIndexStore(storyIndex);\n\n        expect(store.entryFromSpecifier('component-two')).toEqual(\n          store.entries['component-two--c']\n        );\n      });\n\n      it('selects the first story for the group', async () => {\n        const store = new StoryIndexStore(\n          makeStoryIndex([\n            ['g1/a', '1'],\n            ['g2/a', '1'],\n            ['g2/b', '1'],\n          ])\n        );\n\n        expect(store.entryFromSpecifier('g2')).toEqual(store.entries['g2-a--1']);\n      });\n\n      // Making sure the fix #11571 doesn't break this\n      it('selects the first story if there are two stories in the group of different lengths', async () => {\n        const store = new StoryIndexStore(\n          makeStoryIndex([\n            ['a', 'long-long-long'],\n            ['a', 'short'],\n          ])\n        );\n\n        expect(store.entryFromSpecifier('a')).toEqual(store.entries['a--long-long-long']);\n      });\n\n      it('selects nothing if the component or group does not exist', async () => {\n        const store = new StoryIndexStore(storyIndex);\n\n        expect(store.entryFromSpecifier('random')).toBeUndefined();\n      });\n    });\n    describe('if you use a storyId', () => {\n      it('selects a specific story', async () => {\n        const store = new StoryIndexStore(storyIndex);\n\n        expect(store.entryFromSpecifier('component-one--a')).toEqual(\n          store.entries['component-one--a']\n        );\n      });\n\n      it('selects nothing if you the story does not exist', async () => {\n        const store = new StoryIndexStore(storyIndex);\n\n        expect(store.entryFromSpecifier('component-one--c')).toBeUndefined();\n      });\n\n      // See #11571\n      it('does NOT select an earlier story that this story id is a prefix of', async () => {\n        const store = new StoryIndexStore(\n          makeStoryIndex([\n            ['a', '31'],\n            ['a', '3'],\n          ])\n        );\n\n        expect(store.entryFromSpecifier('a--3')).toEqual(store.entries['a--3']);\n      });\n    });\n\n    describe('storyIdToEntry', () => {\n      it('works when the story exists', async () => {\n        const store = new StoryIndexStore(storyIndex);\n\n        expect(store.storyIdToEntry('component-one--a')).toEqual(\n          storyIndex.entries['component-one--a']\n        );\n        expect(store.storyIdToEntry('component-one--b')).toEqual(\n          storyIndex.entries['component-one--b']\n        );\n        expect(store.storyIdToEntry('component-two--c')).toEqual(\n          storyIndex.entries['component-two--c']\n        );\n      });\n\n      it('throws when the story does not', async () => {\n        const store = new StoryIndexStore(storyIndex);\n\n        expect(() => store.storyIdToEntry('random')).toThrow(\n          /Couldn't find story matching id 'random'/\n        );\n      });\n    });\n  });\n\n  describe('importPathToEntry', () => {\n    it('works', () => {\n      const store = new StoryIndexStore(storyIndex);\n      expect(store.importPathToEntry('./src/ComponentOne.stories.js')).toEqual(\n        storyIndex.entries['component-one--a']\n      );\n      expect(store.importPathToEntry('./src/ComponentTwo.stories.js')).toEqual(\n        storyIndex.entries['component-two--c']\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/StoryIndexStore.ts",
    "content": "import { MissingStoryAfterHmrError } from 'storybook/internal/preview-errors';\nimport type { ComponentTitle, Path, StoryId, StoryName } from 'storybook/internal/types';\nimport type { IndexEntry, StoryIndex } from 'storybook/internal/types';\n\nimport memoize from 'memoizerific';\n\nexport type StorySpecifier = StoryId | { name: StoryName; title: ComponentTitle } | '*';\n\nconst getImportPathMap = memoize(1)((entries: StoryIndex['entries']) =>\n  Object.values(entries).reduce(\n    (acc, entry) => {\n      acc[entry.importPath] = acc[entry.importPath] || entry;\n      return acc;\n    },\n    {} as Record<Path, IndexEntry>\n  )\n);\n\nexport class StoryIndexStore {\n  entries: StoryIndex['entries'];\n\n  constructor({ entries }: StoryIndex = { v: 5, entries: {} }) {\n    this.entries = entries;\n  }\n\n  entryFromSpecifier(specifier: StorySpecifier) {\n    const entries = Object.values(this.entries);\n    if (specifier === '*') {\n      // '*' means select the first entry. If there is none, we have no selection.\n      return entries[0];\n    }\n\n    if (typeof specifier === 'string') {\n      // Find the story with the exact id that matches the specifier (see #11571)\n      if (this.entries[specifier]) {\n        return this.entries[specifier];\n      }\n      // Fallback to the first story that starts with the specifier\n      return entries.find((entry) => entry.id.startsWith(specifier));\n    }\n\n    // Try and find a story matching the name/kind, setting no selection if they don't exist.\n    const { name, title } = specifier;\n    return entries.find((entry) => entry.name === name && entry.title === title);\n  }\n\n  storyIdToEntry(storyId: StoryId): IndexEntry {\n    const storyEntry = this.entries[storyId];\n    if (!storyEntry) {\n      throw new MissingStoryAfterHmrError({ storyId });\n    }\n\n    return storyEntry;\n  }\n\n  importPathToEntry(importPath: Path): IndexEntry {\n    return getImportPathMap(this.entries)[importPath];\n  }\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/StoryStore.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport type { ProjectAnnotations, Renderer, StoryIndex } from 'storybook/internal/types';\n\nimport { StoryStore } from './StoryStore.ts';\nimport { composeConfigs } from './csf/composeConfigs.ts';\nimport { prepareStory } from './csf/prepareStory.ts';\nimport { processCSFFile } from './csf/processCSFFile.ts';\nimport type { HooksContext } from './hooks.ts';\n\n// Spy on prepareStory/processCSFFile\nvi.mock('./csf/prepareStory', async (importOriginal) => {\n  const actual = await importOriginal<typeof import('./csf/prepareStory')>();\n  return {\n    ...actual,\n    prepareStory: vi.fn(actual.prepareStory),\n  };\n});\nvi.mock('./csf/processCSFFile', async (importOriginal) => ({\n  processCSFFile: vi.fn(\n    (await importOriginal<typeof import('./csf/processCSFFile')>()).processCSFFile\n  ),\n}));\n\nvi.mock('@storybook/global', async (importOriginal) => ({\n  global: {\n    ...(await importOriginal<typeof import('@storybook/global')>()),\n  },\n}));\n\nvi.mock('storybook/internal/client-logger');\n\nconst componentOneExports = {\n  default: { title: 'Component One' },\n  a: { args: { foo: 'a' } },\n  b: { args: { foo: 'b' } },\n};\nconst componentTwoExports = {\n  default: { title: 'Component Two' },\n  c: { args: { foo: 'c' } },\n};\nconst importFn = vi.fn(async (path) => {\n  return path === './src/ComponentOne.stories.js' ? componentOneExports : componentTwoExports;\n});\n\nconst projectAnnotations: ProjectAnnotations<any> = composeConfigs([\n  {\n    initialGlobals: { a: 'b' },\n    globalTypes: { a: { name: 'a' } },\n    argTypes: { a: { type: 'string' } },\n    render: vi.fn(),\n  },\n]);\n\nconst storyIndex: StoryIndex = {\n  v: 5,\n  entries: {\n    'component-one--a': {\n      type: 'story',\n      subtype: 'story',\n      id: 'component-one--a',\n      title: 'Component One',\n      name: 'A',\n      importPath: './src/ComponentOne.stories.js',\n    },\n    'component-one--b': {\n      type: 'story',\n      subtype: 'story',\n      id: 'component-one--b',\n      title: 'Component One',\n      name: 'B',\n      importPath: './src/ComponentOne.stories.js',\n    },\n    'component-two--c': {\n      type: 'story',\n      subtype: 'story',\n      id: 'component-two--c',\n      title: 'Component Two',\n      name: 'C',\n      importPath: './src/ComponentTwo.stories.js',\n    },\n  },\n};\n\ndescribe('StoryStore', () => {\n  describe('projectAnnotations', () => {\n    it('normalizes on initialization', async () => {\n      const store = new StoryStore(storyIndex, importFn, projectAnnotations);\n\n      expect(store.projectAnnotations!.globalTypes).toEqual({\n        a: { name: 'a' },\n      });\n      expect(store.projectAnnotations!.argTypes).toEqual({\n        a: { name: 'a', type: { name: 'string' } },\n      });\n    });\n\n    it('normalizes on updateGlobalAnnotations', async () => {\n      const store = new StoryStore(storyIndex, importFn, projectAnnotations);\n\n      store.setProjectAnnotations(projectAnnotations);\n      expect(store.projectAnnotations!.globalTypes).toEqual({\n        a: { name: 'a' },\n      });\n      expect(store.projectAnnotations!.argTypes).toEqual({\n        a: { name: 'a', type: { name: 'string' } },\n      });\n    });\n  });\n\n  describe('loadStory', () => {\n    it('pulls the story via the importFn', async () => {\n      const store = new StoryStore(storyIndex, importFn, projectAnnotations);\n\n      importFn.mockClear();\n      expect(await store.loadStory({ storyId: 'component-one--a' })).toMatchObject({\n        id: 'component-one--a',\n        name: 'A',\n        title: 'Component One',\n        initialArgs: { foo: 'a' },\n      });\n      expect(importFn).toHaveBeenCalledWith('./src/ComponentOne.stories.js');\n    });\n\n    it('uses a cache', async () => {\n      const store = new StoryStore(storyIndex, importFn, projectAnnotations);\n\n      const story = await store.loadStory({ storyId: 'component-one--a' });\n      expect(processCSFFile).toHaveBeenCalledTimes(1);\n      expect(prepareStory).toHaveBeenCalledTimes(1);\n\n      // We are intentionally checking exact equality here, we need the object to be identical\n      expect(await store.loadStory({ storyId: 'component-one--a' })).toBe(story);\n      expect(processCSFFile).toHaveBeenCalledTimes(1);\n      expect(prepareStory).toHaveBeenCalledTimes(1);\n\n      await store.loadStory({ storyId: 'component-one--b' });\n      expect(processCSFFile).toHaveBeenCalledTimes(1);\n      expect(prepareStory).toHaveBeenCalledTimes(2);\n\n      await store.loadStory({ storyId: 'component-two--c' });\n      expect(processCSFFile).toHaveBeenCalledTimes(2);\n      expect(prepareStory).toHaveBeenCalledTimes(3);\n    });\n  });\n\n  describe('setProjectAnnotations', () => {\n    it('busts the loadStory cache', async () => {\n      const store = new StoryStore(storyIndex, importFn, projectAnnotations);\n\n      const story = await store.loadStory({ storyId: 'component-one--a' });\n      expect(processCSFFile).toHaveBeenCalledTimes(1);\n      expect(prepareStory).toHaveBeenCalledTimes(1);\n\n      store.setProjectAnnotations({ ...projectAnnotations, decorators: [vi.fn()] });\n\n      // We are intentionally checking exact equality here, we need the object to be identical\n      expect(await store.loadStory({ storyId: 'component-one--a' })).not.toBe(story);\n      expect(processCSFFile).toHaveBeenCalledTimes(1);\n      expect(prepareStory).toHaveBeenCalledTimes(2);\n    });\n  });\n\n  describe('onStoriesChanged', () => {\n    it('busts the loadStory cache if the importFn returns a new module', async () => {\n      const store = new StoryStore(storyIndex, importFn, projectAnnotations);\n\n      const story = await store.loadStory({ storyId: 'component-one--a' });\n      expect(processCSFFile).toHaveBeenCalledTimes(1);\n      expect(prepareStory).toHaveBeenCalledTimes(1);\n\n      await store.onStoriesChanged({\n        importFn: async () => ({\n          ...componentOneExports,\n          c: { args: { foo: 'c' } },\n        }),\n      });\n\n      // The object is not identical which will cause it to be treated as a new story\n      expect(await store.loadStory({ storyId: 'component-one--a' })).not.toBe(story);\n      expect(processCSFFile).toHaveBeenCalledTimes(2);\n      expect(prepareStory).toHaveBeenCalledTimes(2);\n    });\n\n    it('busts the loadStory cache if the csf file no longer appears in the index', async () => {\n      const store = new StoryStore(storyIndex, importFn, projectAnnotations);\n\n      await store.loadStory({ storyId: 'component-one--a' });\n      expect(processCSFFile).toHaveBeenCalledTimes(1);\n      expect(prepareStory).toHaveBeenCalledTimes(1);\n\n      // The stories are no longer in the index\n      await store.onStoriesChanged({ storyIndex: { v: 5, entries: {} } });\n\n      await expect(store.loadStory({ storyId: 'component-one--a' })).rejects.toThrow();\n\n      // We don't load or process any CSF\n      expect(processCSFFile).toHaveBeenCalledTimes(1);\n      expect(prepareStory).toHaveBeenCalledTimes(1);\n    });\n\n    it('reuses the cache if a story importPath has not changed', async () => {\n      const store = new StoryStore(storyIndex, importFn, projectAnnotations);\n\n      const story = await store.loadStory({ storyId: 'component-one--a' });\n      expect(processCSFFile).toHaveBeenCalledTimes(1);\n      expect(prepareStory).toHaveBeenCalledTimes(1);\n\n      // Add a new story to the index that isn't different\n      await store.onStoriesChanged({\n        storyIndex: {\n          v: 5,\n          entries: {\n            ...storyIndex.entries,\n            'new-component--story': {\n              type: 'story',\n              subtype: 'story',\n              id: 'new-component--story',\n              title: 'New Component',\n              name: 'Story',\n              importPath: './new-component.stories.js',\n            },\n          },\n        },\n      });\n\n      // We are intentionally checking exact equality here, we need the object to be identical\n      expect(await store.loadStory({ storyId: 'component-one--a' })).toEqual(story);\n      expect(processCSFFile).toHaveBeenCalledTimes(1);\n      expect(prepareStory).toHaveBeenCalledTimes(1);\n    });\n\n    it('imports with a new path for a story id if provided', async () => {\n      const store = new StoryStore(storyIndex, importFn, projectAnnotations);\n\n      await store.loadStory({ storyId: 'component-one--a' });\n      expect(importFn).toHaveBeenCalledWith(storyIndex.entries['component-one--a'].importPath);\n\n      const newImportPath = './src/ComponentOne-new.stories.js';\n      const newImportFn = vi.fn(async () => componentOneExports);\n      await store.onStoriesChanged({\n        importFn: newImportFn,\n        storyIndex: {\n          v: 5,\n          entries: {\n            'component-one--a': {\n              type: 'story',\n              subtype: 'story',\n              id: 'component-one--a',\n              title: 'Component One',\n              name: 'A',\n              importPath: newImportPath,\n            },\n          },\n        },\n      });\n\n      await store.loadStory({ storyId: 'component-one--a' });\n      expect(newImportFn).toHaveBeenCalledWith(newImportPath);\n    });\n\n    it('re-caches stories if the were cached already', async () => {\n      const store = new StoryStore(storyIndex, importFn, projectAnnotations);\n      await store.cacheAllCSFFiles();\n\n      await store.loadStory({ storyId: 'component-one--a' });\n      expect(importFn).toHaveBeenCalledWith(storyIndex.entries['component-one--a'].importPath);\n\n      const newImportPath = './src/ComponentOne-new.stories.js';\n      const newImportFn = vi.fn(async () => componentOneExports);\n      await store.onStoriesChanged({\n        importFn: newImportFn,\n        storyIndex: {\n          v: 5,\n          entries: {\n            'component-one--a': {\n              type: 'story',\n              subtype: 'story',\n              id: 'component-one--a',\n              title: 'Component One',\n              name: 'A',\n              importPath: newImportPath,\n            },\n          },\n        },\n      });\n\n      expect(store.extract()).toMatchInlineSnapshot(`\n        {\n          \"component-one--a\": {\n            \"argTypes\": {\n              \"a\": {\n                \"name\": \"a\",\n                \"type\": {\n                  \"name\": \"string\",\n                },\n              },\n              \"foo\": {\n                \"name\": \"foo\",\n                \"type\": {\n                  \"name\": \"string\",\n                },\n              },\n            },\n            \"args\": {\n              \"foo\": \"a\",\n            },\n            \"component\": undefined,\n            \"componentId\": \"component-one\",\n            \"globals\": {\n              \"a\": \"b\",\n              \"backgrounds\": {\n                \"grid\": false,\n                \"value\": undefined,\n              },\n              \"measureEnabled\": false,\n              \"outline\": false,\n              \"viewport\": {\n                \"isRotated\": false,\n                \"value\": undefined,\n              },\n            },\n            \"id\": \"component-one--a\",\n            \"initialArgs\": {\n              \"foo\": \"a\",\n            },\n            \"kind\": \"Component One\",\n            \"name\": \"A\",\n            \"parameters\": {\n              \"__isArgsStory\": false,\n              \"backgrounds\": {\n                \"disable\": false,\n                \"grid\": {\n                  \"cellAmount\": 5,\n                  \"cellSize\": 20,\n                  \"opacity\": 0.5,\n                },\n              },\n              \"fileName\": \"./src/ComponentOne-new.stories.js\",\n              \"throwPlayFunctionExceptions\": false,\n            },\n            \"playFunction\": undefined,\n            \"renderToCanvas\": undefined,\n            \"story\": \"A\",\n            \"storyGlobals\": {},\n            \"storyId\": \"component-one--a\",\n            \"subcomponents\": undefined,\n            \"tags\": [\n              \"dev\",\n              \"test\",\n            ],\n            \"testingLibraryRender\": undefined,\n            \"title\": \"Component One\",\n            \"usesMount\": false,\n          },\n        }\n      `);\n    });\n  });\n\n  describe('componentStoriesFromCSFFile', () => {\n    it('returns all the stories in the file', async () => {\n      const store = new StoryStore(storyIndex, importFn, projectAnnotations);\n\n      const csfFile = await store.loadCSFFileByStoryId('component-one--a');\n      const stories = store.componentStoriesFromCSFFile({ csfFile });\n\n      expect(stories).toHaveLength(2);\n      expect(stories.map((s) => s.id)).toEqual(['component-one--a', 'component-one--b']);\n    });\n\n    it('returns them in the order they are in the index, not the file', async () => {\n      const reversedIndex = {\n        v: 5,\n        entries: {\n          'component-one--b': storyIndex.entries['component-one--b'],\n          'component-one--a': storyIndex.entries['component-one--a'],\n        },\n      };\n      const store = new StoryStore(reversedIndex, importFn, projectAnnotations);\n\n      const csfFile = await store.loadCSFFileByStoryId('component-one--a');\n      const stories = store.componentStoriesFromCSFFile({ csfFile });\n\n      expect(stories).toHaveLength(2);\n      expect(stories.map((s) => s.id)).toEqual(['component-one--b', 'component-one--a']);\n    });\n  });\n\n  describe('getStoryContext', () => {\n    it('returns the args and globals correctly', async () => {\n      const store = new StoryStore(storyIndex, importFn, projectAnnotations);\n\n      const story = await store.loadStory({ storyId: 'component-one--a' });\n\n      expect(store.getStoryContext(story)).toMatchObject({\n        args: { foo: 'a' },\n        globals: { a: 'b' },\n      });\n    });\n\n    it('returns the args and globals correctly when they change', async () => {\n      const store = new StoryStore(storyIndex, importFn, projectAnnotations);\n\n      const story = await store.loadStory({ storyId: 'component-one--a' });\n\n      store.args.update(story.id, { foo: 'bar' });\n      store.userGlobals!.update({ a: 'c' });\n\n      expect(store.getStoryContext(story)).toMatchObject({\n        args: { foo: 'bar' },\n        globals: { a: 'c' },\n      });\n    });\n\n    it('can force initial args', async () => {\n      const store = new StoryStore(storyIndex, importFn, projectAnnotations);\n\n      const story = await store.loadStory({ storyId: 'component-one--a' });\n\n      store.args.update(story.id, { foo: 'bar' });\n\n      expect(store.getStoryContext(story, { forceInitialArgs: true })).toMatchObject({\n        args: { foo: 'a' },\n      });\n    });\n\n    it('returns the same hooks each time', async () => {\n      const store = new StoryStore(storyIndex, importFn, projectAnnotations);\n\n      const story = await store.loadStory({ storyId: 'component-one--a' });\n\n      const { hooks } = store.getStoryContext(story);\n      expect(store.getStoryContext(story).hooks).toBe(hooks);\n\n      // Now double check it doesn't get changed when you call `loadStory` again\n      const story2 = await store.loadStory({ storyId: 'component-one--a' });\n      expect(store.getStoryContext(story2).hooks).toBe(hooks);\n    });\n  });\n\n  describe('cleanupStory', () => {\n    it('cleans the hooks from the context', async () => {\n      const store = new StoryStore(storyIndex, importFn, projectAnnotations);\n\n      const story = await store.loadStory({ storyId: 'component-one--a' });\n\n      const { hooks } = store.getStoryContext(story) as { hooks: HooksContext<Renderer> };\n      hooks.clean = vi.fn();\n      await store.cleanupStory(story);\n      expect(hooks.clean).toHaveBeenCalled();\n    });\n  });\n\n  describe('loadAllCSFFiles', () => {\n    it('imports *all* csf files', async () => {\n      const store = new StoryStore(storyIndex, importFn, projectAnnotations);\n\n      importFn.mockClear();\n      const csfFiles = await store.loadAllCSFFiles();\n      expect(csfFiles).not.toBeUndefined();\n\n      expect(Object.keys(csfFiles!)).toEqual([\n        './src/ComponentOne.stories.js',\n        './src/ComponentTwo.stories.js',\n      ]);\n    });\n  });\n\n  describe('extract', () => {\n    it('throws if you have not called cacheAllCSFFiles', async () => {\n      const store = new StoryStore(storyIndex, importFn, projectAnnotations);\n\n      expect(() => store.extract()).toThrow(/Cannot call/);\n    });\n\n    it('produces objects with functions and hooks stripped', async () => {\n      const store = new StoryStore(storyIndex, importFn, projectAnnotations);\n      await store.cacheAllCSFFiles();\n\n      expect(store.extract()).toMatchInlineSnapshot(`\n        {\n          \"component-one--a\": {\n            \"argTypes\": {\n              \"a\": {\n                \"name\": \"a\",\n                \"type\": {\n                  \"name\": \"string\",\n                },\n              },\n              \"foo\": {\n                \"name\": \"foo\",\n                \"type\": {\n                  \"name\": \"string\",\n                },\n              },\n            },\n            \"args\": {\n              \"foo\": \"a\",\n            },\n            \"component\": undefined,\n            \"componentId\": \"component-one\",\n            \"globals\": {\n              \"a\": \"b\",\n              \"backgrounds\": {\n                \"grid\": false,\n                \"value\": undefined,\n              },\n              \"measureEnabled\": false,\n              \"outline\": false,\n              \"viewport\": {\n                \"isRotated\": false,\n                \"value\": undefined,\n              },\n            },\n            \"id\": \"component-one--a\",\n            \"initialArgs\": {\n              \"foo\": \"a\",\n            },\n            \"kind\": \"Component One\",\n            \"name\": \"A\",\n            \"parameters\": {\n              \"__isArgsStory\": false,\n              \"backgrounds\": {\n                \"disable\": false,\n                \"grid\": {\n                  \"cellAmount\": 5,\n                  \"cellSize\": 20,\n                  \"opacity\": 0.5,\n                },\n              },\n              \"fileName\": \"./src/ComponentOne.stories.js\",\n              \"throwPlayFunctionExceptions\": false,\n            },\n            \"playFunction\": undefined,\n            \"renderToCanvas\": undefined,\n            \"story\": \"A\",\n            \"storyGlobals\": {},\n            \"storyId\": \"component-one--a\",\n            \"subcomponents\": undefined,\n            \"tags\": [\n              \"dev\",\n              \"test\",\n            ],\n            \"testingLibraryRender\": undefined,\n            \"title\": \"Component One\",\n            \"usesMount\": false,\n          },\n          \"component-one--b\": {\n            \"argTypes\": {\n              \"a\": {\n                \"name\": \"a\",\n                \"type\": {\n                  \"name\": \"string\",\n                },\n              },\n              \"foo\": {\n                \"name\": \"foo\",\n                \"type\": {\n                  \"name\": \"string\",\n                },\n              },\n            },\n            \"args\": {\n              \"foo\": \"b\",\n            },\n            \"component\": undefined,\n            \"componentId\": \"component-one\",\n            \"globals\": {\n              \"a\": \"b\",\n              \"backgrounds\": {\n                \"grid\": false,\n                \"value\": undefined,\n              },\n              \"measureEnabled\": false,\n              \"outline\": false,\n              \"viewport\": {\n                \"isRotated\": false,\n                \"value\": undefined,\n              },\n            },\n            \"id\": \"component-one--b\",\n            \"initialArgs\": {\n              \"foo\": \"b\",\n            },\n            \"kind\": \"Component One\",\n            \"name\": \"B\",\n            \"parameters\": {\n              \"__isArgsStory\": false,\n              \"backgrounds\": {\n                \"disable\": false,\n                \"grid\": {\n                  \"cellAmount\": 5,\n                  \"cellSize\": 20,\n                  \"opacity\": 0.5,\n                },\n              },\n              \"fileName\": \"./src/ComponentOne.stories.js\",\n              \"throwPlayFunctionExceptions\": false,\n            },\n            \"playFunction\": undefined,\n            \"renderToCanvas\": undefined,\n            \"story\": \"B\",\n            \"storyGlobals\": {},\n            \"storyId\": \"component-one--b\",\n            \"subcomponents\": undefined,\n            \"tags\": [\n              \"dev\",\n              \"test\",\n            ],\n            \"testingLibraryRender\": undefined,\n            \"title\": \"Component One\",\n            \"usesMount\": false,\n          },\n          \"component-two--c\": {\n            \"argTypes\": {\n              \"a\": {\n                \"name\": \"a\",\n                \"type\": {\n                  \"name\": \"string\",\n                },\n              },\n              \"foo\": {\n                \"name\": \"foo\",\n                \"type\": {\n                  \"name\": \"string\",\n                },\n              },\n            },\n            \"args\": {\n              \"foo\": \"c\",\n            },\n            \"component\": undefined,\n            \"componentId\": \"component-two\",\n            \"globals\": {\n              \"a\": \"b\",\n              \"backgrounds\": {\n                \"grid\": false,\n                \"value\": undefined,\n              },\n              \"measureEnabled\": false,\n              \"outline\": false,\n              \"viewport\": {\n                \"isRotated\": false,\n                \"value\": undefined,\n              },\n            },\n            \"id\": \"component-two--c\",\n            \"initialArgs\": {\n              \"foo\": \"c\",\n            },\n            \"kind\": \"Component Two\",\n            \"name\": \"C\",\n            \"parameters\": {\n              \"__isArgsStory\": false,\n              \"backgrounds\": {\n                \"disable\": false,\n                \"grid\": {\n                  \"cellAmount\": 5,\n                  \"cellSize\": 20,\n                  \"opacity\": 0.5,\n                },\n              },\n              \"fileName\": \"./src/ComponentTwo.stories.js\",\n              \"throwPlayFunctionExceptions\": false,\n            },\n            \"playFunction\": undefined,\n            \"renderToCanvas\": undefined,\n            \"story\": \"C\",\n            \"storyGlobals\": {},\n            \"storyId\": \"component-two--c\",\n            \"subcomponents\": undefined,\n            \"tags\": [\n              \"dev\",\n              \"test\",\n            ],\n            \"testingLibraryRender\": undefined,\n            \"title\": \"Component Two\",\n            \"usesMount\": false,\n          },\n        }\n      `);\n    });\n\n    it('does not include (legacy) docs only stories by default', async () => {\n      const docsOnlyImportFn = vi.fn(async (path) => {\n        return path === './src/ComponentOne.stories.js'\n          ? {\n              ...componentOneExports,\n              a: { ...componentOneExports.a, parameters: { docsOnly: true } },\n            }\n          : componentTwoExports;\n      });\n      const store = new StoryStore(storyIndex, docsOnlyImportFn, projectAnnotations);\n      await store.cacheAllCSFFiles();\n\n      expect(Object.keys(store.extract())).toEqual(['component-one--b', 'component-two--c']);\n\n      expect(Object.keys(store.extract({ includeDocsOnly: true }))).toEqual([\n        'component-one--a',\n        'component-one--b',\n        'component-two--c',\n      ]);\n    });\n\n    it('does not include (modern) docs entries ever', async () => {\n      const unnattachedStoryIndex: StoryIndex = {\n        v: 5,\n        entries: {\n          ...storyIndex.entries,\n          'introduction--docs': {\n            type: 'docs',\n            id: 'introduction--docs',\n            title: 'Introduction',\n            name: 'Docs',\n            importPath: './introduction.mdx',\n            storiesImports: [],\n          },\n        },\n      };\n      const store = new StoryStore(unnattachedStoryIndex, importFn, projectAnnotations);\n      await store.cacheAllCSFFiles();\n\n      expect(Object.keys(store.extract())).toEqual([\n        'component-one--a',\n        'component-one--b',\n        'component-two--c',\n      ]);\n\n      expect(Object.keys(store.extract({ includeDocsOnly: true }))).toEqual([\n        'component-one--a',\n        'component-one--b',\n        'component-two--c',\n      ]);\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/StoryStore.ts",
    "content": "import type { CleanupCallback } from 'storybook/internal/csf';\nimport { getCoreAnnotations } from 'storybook/internal/csf';\nimport {\n  CalledExtractOnStoreError,\n  MissingStoryFromCsfFileError,\n} from 'storybook/internal/preview-errors';\nimport type {\n  CSFFile,\n  IndexEntry,\n  ModuleExports,\n  ModuleImportFn,\n  NormalizedProjectAnnotations,\n  Path,\n  PreparedMeta,\n  PreparedStory,\n  ProjectAnnotations,\n  Renderer,\n  StoryContextForEnhancers,\n  StoryId,\n  StoryIndex,\n} from 'storybook/internal/types';\n\nimport { omitBy, pick } from 'es-toolkit/object';\nimport memoize from 'memoizerific';\n\nimport { HooksContext } from '../addons/index.ts';\nimport { ArgsStore } from './ArgsStore.ts';\nimport { GlobalsStore } from './GlobalsStore.ts';\nimport { StoryIndexStore } from './StoryIndexStore.ts';\nimport {\n  composeConfigs,\n  normalizeProjectAnnotations,\n  prepareContext,\n  prepareMeta,\n  prepareStory,\n  processCSFFile,\n} from './csf/index.ts';\nimport { ReporterAPI } from './reporter-api.ts';\n\nexport function picky<T extends Record<string, any>, K extends keyof T>(\n  obj: T,\n  keys: K[]\n): Partial<Pick<T, K>> {\n  return omitBy(pick(obj, keys), (v) => v === undefined);\n}\n\n// TODO -- what are reasonable values for these?\nconst CSF_CACHE_SIZE = 1000;\nconst STORY_CACHE_SIZE = 10000;\n\nexport class StoryStore<TRenderer extends Renderer> {\n  public storyIndex: StoryIndexStore;\n\n  projectAnnotations: NormalizedProjectAnnotations<TRenderer>;\n\n  userGlobals: GlobalsStore;\n\n  args: ArgsStore;\n\n  hooks: Record<StoryId, HooksContext<TRenderer>>;\n\n  cleanupCallbacks: Record<StoryId, CleanupCallback[] | undefined>;\n\n  cachedCSFFiles?: Record<Path, CSFFile<TRenderer>>;\n\n  processCSFFileWithCache: typeof processCSFFile;\n\n  prepareMetaWithCache: typeof prepareMeta;\n\n  prepareStoryWithCache: typeof prepareStory;\n\n  constructor(\n    storyIndex: StoryIndex,\n\n    public importFn: ModuleImportFn,\n\n    projectAnnotations: ProjectAnnotations<TRenderer>\n  ) {\n    this.storyIndex = new StoryIndexStore(storyIndex);\n\n    this.projectAnnotations = normalizeProjectAnnotations(\n      composeConfigs([...getCoreAnnotations(), projectAnnotations])\n    );\n    const { initialGlobals, globalTypes } = this.projectAnnotations;\n\n    this.args = new ArgsStore();\n    this.userGlobals = new GlobalsStore({ globals: initialGlobals, globalTypes });\n    this.hooks = {};\n    this.cleanupCallbacks = {};\n\n    // We use a cache for these two functions for two reasons:\n    //  1. For performance\n    //  2. To ensure that when the same story is prepared with the same inputs you get the same output\n    this.processCSFFileWithCache = memoize(CSF_CACHE_SIZE)(processCSFFile) as typeof processCSFFile;\n    this.prepareMetaWithCache = memoize(CSF_CACHE_SIZE)(prepareMeta) as typeof prepareMeta;\n    this.prepareStoryWithCache = memoize(STORY_CACHE_SIZE)(prepareStory) as typeof prepareStory;\n  }\n\n  setProjectAnnotations(projectAnnotations: ProjectAnnotations<TRenderer>) {\n    // By changing `this.projectAnnotations, we implicitly invalidate the `prepareStoryWithCache`\n    this.projectAnnotations = normalizeProjectAnnotations(projectAnnotations);\n    const { initialGlobals, globalTypes } = projectAnnotations;\n    this.userGlobals.set({ globals: initialGlobals, globalTypes });\n  }\n\n  // This means that one of the CSF files has changed.\n  // If the `importFn` has changed, we will invalidate both caches.\n  // If the `storyIndex` data has changed, we may or may not invalidate the caches, depending\n  // on whether we've loaded the relevant files yet.\n  async onStoriesChanged({\n    importFn,\n    storyIndex,\n  }: {\n    importFn?: ModuleImportFn;\n    storyIndex?: StoryIndex;\n  }) {\n    if (importFn) {\n      this.importFn = importFn;\n    }\n    // The index will always be set before the initialization promise returns\n    // The index will always be set before the initialization promise returns\n\n    // The index will always be set before the initialization promise returns\n    if (storyIndex) {\n      this.storyIndex.entries = storyIndex.entries;\n    }\n\n    if (this.cachedCSFFiles) {\n      await this.cacheAllCSFFiles();\n    }\n  }\n\n  // Get an entry from the index, waiting on initialization if necessary\n  async storyIdToEntry(storyId: StoryId): Promise<IndexEntry> {\n    // The index will always be set before the initialization promise returns\n    return this.storyIndex.storyIdToEntry(storyId);\n  }\n\n  // To load a single CSF file to service a story we need to look up the importPath in the index\n  async loadCSFFileByStoryId(storyId: StoryId): Promise<CSFFile<TRenderer>> {\n    const { importPath, title } = this.storyIndex.storyIdToEntry(storyId);\n    const moduleExports = await this.importFn(importPath);\n\n    // We pass the title in here as it may have been generated by autoTitle on the server.\n    return this.processCSFFileWithCache(moduleExports, importPath, title);\n  }\n\n  async loadAllCSFFiles(): Promise<StoryStore<TRenderer>['cachedCSFFiles']> {\n    const importPaths: Record<Path, StoryId> = {};\n    Object.entries(this.storyIndex.entries).forEach(([storyId, { importPath }]) => {\n      importPaths[importPath] = storyId;\n    });\n\n    const list = await Promise.all(\n      Object.entries(importPaths).map(async ([importPath, storyId]) => ({\n        importPath,\n        csfFile: await this.loadCSFFileByStoryId(storyId),\n      }))\n    );\n\n    return list.reduce(\n      (acc, { importPath, csfFile }) => {\n        acc[importPath] = csfFile;\n        return acc;\n      },\n      {} as Record<Path, CSFFile<TRenderer>>\n    );\n  }\n\n  async cacheAllCSFFiles(): Promise<void> {\n    this.cachedCSFFiles = await this.loadAllCSFFiles();\n  }\n\n  preparedMetaFromCSFFile({ csfFile }: { csfFile: CSFFile<TRenderer> }): PreparedMeta<TRenderer> {\n    const componentAnnotations = csfFile.meta;\n\n    return this.prepareMetaWithCache(\n      componentAnnotations,\n      this.projectAnnotations,\n      csfFile.moduleExports.default\n    );\n  }\n\n  // Load the CSF file for a story and prepare the story from it and the project annotations.\n  async loadStory({ storyId }: { storyId: StoryId }): Promise<PreparedStory<TRenderer>> {\n    const csfFile = await this.loadCSFFileByStoryId(storyId);\n    return this.storyFromCSFFile({ storyId, csfFile });\n  }\n\n  // This function is synchronous for convenience -- often times if you have a CSF file already\n  // it is easier not to have to await `loadStory`.\n  storyFromCSFFile({\n    storyId,\n    csfFile,\n  }: {\n    storyId: StoryId;\n    csfFile: CSFFile<TRenderer>;\n  }): PreparedStory<TRenderer> {\n    const storyAnnotations = csfFile.stories[storyId];\n\n    if (!storyAnnotations) {\n      throw new MissingStoryFromCsfFileError({ storyId });\n    }\n\n    const componentAnnotations = csfFile.meta;\n\n    const story = this.prepareStoryWithCache(\n      storyAnnotations,\n      componentAnnotations,\n      csfFile.projectAnnotations ?? this.projectAnnotations\n    );\n    this.args.setInitial(story);\n    this.hooks[story.id] = this.hooks[story.id] || new HooksContext();\n    return story;\n  }\n\n  // If we have a CSF file we can get all the stories from it synchronously\n  componentStoriesFromCSFFile({\n    csfFile,\n  }: {\n    csfFile: CSFFile<TRenderer>;\n  }): PreparedStory<TRenderer>[] {\n    return Object.keys(this.storyIndex.entries)\n      .filter((storyId: StoryId) => !!csfFile.stories[storyId])\n      .map((storyId: StoryId) => this.storyFromCSFFile({ storyId, csfFile }));\n  }\n\n  async loadEntry(id: StoryId) {\n    const entry = await this.storyIdToEntry(id);\n\n    const storyImports = entry.type === 'docs' ? entry.storiesImports : [];\n\n    const [entryExports, ...csfFiles] = (await Promise.all([\n      this.importFn(entry.importPath),\n      ...storyImports.map((storyImportPath) => {\n        const firstStoryEntry = this.storyIndex.importPathToEntry(storyImportPath);\n        return this.loadCSFFileByStoryId(firstStoryEntry.id);\n      }),\n    ])) as [ModuleExports, ...CSFFile<TRenderer>[]];\n\n    return { entryExports, csfFiles };\n  }\n\n  // A prepared story does not include args, globals or hooks. These are stored in the story store\n  // and updated separately to the (immutable) story.\n  getStoryContext(story: PreparedStory<TRenderer>, { forceInitialArgs = false } = {}) {\n    const userGlobals = this.userGlobals.get();\n    const { initialGlobals } = this.userGlobals;\n    const reporting = new ReporterAPI();\n    return prepareContext({\n      ...story,\n      args: forceInitialArgs ? story.initialArgs : this.args.get(story.id),\n      initialGlobals,\n      globalTypes: this.projectAnnotations.globalTypes,\n      userGlobals,\n      reporting,\n      globals: {\n        ...userGlobals,\n        ...story.storyGlobals,\n      },\n      hooks: this.hooks[story.id] as unknown,\n    });\n  }\n\n  addCleanupCallbacks(story: PreparedStory<TRenderer>, ...callbacks: CleanupCallback[]) {\n    this.cleanupCallbacks[story.id] = (this.cleanupCallbacks[story.id] || []).concat(callbacks);\n  }\n\n  async cleanupStory(story: PreparedStory<TRenderer>): Promise<void> {\n    this.hooks[story.id].clean();\n\n    const callbacks = this.cleanupCallbacks[story.id];\n\n    if (callbacks) {\n      for (const callback of [...callbacks].reverse()) {\n        await callback();\n      }\n    }\n\n    delete this.cleanupCallbacks[story.id];\n  }\n\n  extract(\n    options: { includeDocsOnly?: boolean } = { includeDocsOnly: false }\n  ): Record<StoryId, StoryContextForEnhancers<TRenderer>> {\n    const { cachedCSFFiles } = this;\n\n    console.log('extract: extracting stories', cachedCSFFiles);\n\n    if (!cachedCSFFiles) {\n      throw new CalledExtractOnStoreError();\n    }\n\n    const stories = Object.entries(this.storyIndex.entries).reduce(\n      (acc, [storyId, entry]) => {\n        if (entry.type === 'docs') {\n          return acc;\n        }\n\n        const csfFile = cachedCSFFiles[entry.importPath];\n        const story = this.storyFromCSFFile({ storyId, csfFile });\n\n        if (!options.includeDocsOnly && story.parameters.docsOnly) {\n          return acc;\n        }\n\n        acc[storyId] = Object.entries(story).reduce(\n          (storyAcc, [key, value]) => {\n            if (key === 'story' && entry.subtype === 'test') {\n              return { ...storyAcc, story: entry.parentName };\n            }\n            if (key === 'moduleExport') {\n              return storyAcc;\n            }\n            if (typeof value === 'function') {\n              return storyAcc;\n            }\n            if (Array.isArray(value)) {\n              return Object.assign(storyAcc, { [key]: value.slice().sort() });\n            }\n            return Object.assign(storyAcc, { [key]: value });\n          },\n          {\n            args: story.initialArgs,\n            globals: {\n              ...this.userGlobals.initialGlobals,\n              ...this.userGlobals.globals,\n              ...story.storyGlobals,\n            },\n            storyId: entry.parent ? entry.parent : storyId,\n          }\n        );\n        return acc;\n      },\n      {} as Record<string, any>\n    );\n\n    console.log('extract: stories', stories);\n\n    return stories;\n  }\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/args.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { once } from 'storybook/internal/client-logger';\nimport type { SBType } from 'storybook/internal/types';\n\nimport {\n  UNTARGETED,\n  combineArgs,\n  groupArgsByTarget,\n  mapArgsToTypes,\n  validateOptions,\n} from './args.ts';\n\nconst stringType: SBType = { name: 'string' };\nconst numberType: SBType = { name: 'number' };\nconst booleanType: SBType = { name: 'boolean' };\nconst enumType: SBType = { name: 'enum', value: [1, 2, 3] };\nconst functionType: SBType = { name: 'function' };\nconst numArrayType: SBType = { name: 'array', value: numberType };\nconst boolObjectType: SBType = { name: 'object', value: { bool: booleanType } };\nconst reactNodeType: SBType = { name: 'other', value: 'ReactNode' };\n\nvi.mock('storybook/internal/client-logger');\n\nenum ArgsMapTestEnumWithoutInitializer {\n  EnumValue,\n  EnumValue2,\n}\n\nenum ArgsMapTestEnumWithStringInitializer {\n  EnumValue = 'EnumValue',\n}\n\nenum ArgsMapTestEnumWithNumericInitializer {\n  EnumValue = 4,\n}\n\ndescribe('mapArgsToTypes', () => {\n  it('maps strings', () => {\n    expect(mapArgsToTypes({ a: 'str' }, { a: { type: stringType } })).toStrictEqual({ a: 'str' });\n    expect(mapArgsToTypes({ a: 42 }, { a: { type: stringType } })).toStrictEqual({ a: '42' });\n  });\n\n  it('maps enums', () => {\n    expect(\n      mapArgsToTypes({ a: ArgsMapTestEnumWithoutInitializer.EnumValue }, { a: { type: enumType } })\n    ).toEqual({ a: 0 });\n    expect(\n      mapArgsToTypes({ a: ArgsMapTestEnumWithoutInitializer.EnumValue2 }, { a: { type: enumType } })\n    ).toEqual({ a: 1 });\n    expect(\n      mapArgsToTypes(\n        { a: ArgsMapTestEnumWithStringInitializer.EnumValue },\n        { a: { type: enumType } }\n      )\n    ).toEqual({ a: 'EnumValue' });\n    expect(\n      mapArgsToTypes(\n        { a: ArgsMapTestEnumWithNumericInitializer.EnumValue },\n        { a: { type: enumType } }\n      )\n    ).toEqual({ a: 4 });\n  });\n\n  it('maps numbers', () => {\n    expect(mapArgsToTypes({ a: '42' }, { a: { type: numberType } })).toStrictEqual({ a: 42 });\n    expect(mapArgsToTypes({ a: '4.2' }, { a: { type: numberType } })).toStrictEqual({ a: 4.2 });\n    expect(mapArgsToTypes({ a: 'a' }, { a: { type: numberType } })).toStrictEqual({ a: NaN });\n  });\n\n  it('maps booleans', () => {\n    expect(mapArgsToTypes({ a: true }, { a: { type: booleanType } })).toStrictEqual({ a: true });\n    expect(mapArgsToTypes({ a: 'true' }, { a: { type: booleanType } })).toStrictEqual({ a: true });\n    expect(mapArgsToTypes({ a: false }, { a: { type: booleanType } })).toStrictEqual({\n      a: false,\n    });\n    expect(mapArgsToTypes({ a: 'yes' }, { a: { type: booleanType } })).toStrictEqual({ a: false });\n  });\n\n  it('maps sparse arrays', () => {\n    expect(mapArgsToTypes({ a: [, '2', undefined] }, { a: { type: numArrayType } })).toStrictEqual({\n      a: [, 2, undefined],\n    });\n  });\n\n  it('omits functions', () => {\n    expect(mapArgsToTypes({ a: 'something' }, { a: { type: functionType } })).toStrictEqual({});\n  });\n\n  it('includes functions if there is a mapping', () => {\n    expect(\n      mapArgsToTypes(\n        { a: 'something' },\n        { a: { type: functionType, mapping: { something: () => 'foo' } } }\n      )\n    ).toStrictEqual({\n      a: 'something',\n    });\n  });\n\n  it('skips default mapping if there is a user-specified mapping', () => {\n    expect(\n      mapArgsToTypes({ a: 'something' }, { a: { type: numberType, mapping: { something: 10 } } })\n    ).toStrictEqual({\n      a: 'something',\n    });\n  });\n\n  it('omits unknown keys', () => {\n    expect(mapArgsToTypes({ a: 'string' }, { b: { type: stringType } })).toStrictEqual({});\n  });\n\n  it('passes through unmodified if no type is specified', () => {\n    expect(mapArgsToTypes({ a: { b: 1 } }, { a: { type: undefined } })).toStrictEqual({\n      a: { b: 1 },\n    });\n  });\n\n  it('passes string for object type', () => {\n    expect(mapArgsToTypes({ a: 'A' }, { a: { type: boolObjectType } })).toStrictEqual({ a: 'A' });\n  });\n\n  it('passes number for object type', () => {\n    expect(mapArgsToTypes({ a: 1.2 }, { a: { type: boolObjectType } })).toStrictEqual({ a: 1.2 });\n  });\n\n  it('passes only primitives for ReactNode type', () => {\n    expect(mapArgsToTypes({ a: 'foo bar' }, { a: { type: reactNodeType } })).toStrictEqual({\n      a: 'foo bar',\n    });\n    expect(mapArgsToTypes({ a: 1.2 }, { a: { type: reactNodeType } })).toStrictEqual({ a: 1.2 });\n    expect(mapArgsToTypes({ a: true }, { a: { type: reactNodeType } })).toStrictEqual({ a: true });\n    expect(mapArgsToTypes({ a: new Date() }, { a: { type: reactNodeType } })).toStrictEqual({});\n    expect(mapArgsToTypes({ a: { foo: 'bar' } }, { a: { type: reactNodeType } })).toStrictEqual({});\n    expect(mapArgsToTypes({ a: Symbol('foo') }, { a: { type: reactNodeType } })).toStrictEqual({});\n  });\n\n  it('deeply maps objects', () => {\n    expect(\n      mapArgsToTypes(\n        {\n          key: {\n            arr: ['1', '2'],\n            obj: { bool: true },\n          },\n        },\n        {\n          key: {\n            type: {\n              name: 'object',\n              value: {\n                arr: numArrayType,\n                obj: boolObjectType,\n              },\n            },\n          },\n        }\n      )\n    ).toStrictEqual({\n      key: {\n        arr: [1, 2],\n        obj: { bool: true },\n      },\n    });\n  });\n\n  it('deeply maps arrays', () => {\n    expect(\n      mapArgsToTypes(\n        {\n          key: [\n            {\n              arr: ['1', '2'],\n              obj: { bool: true },\n            },\n          ],\n        },\n        {\n          key: {\n            type: {\n              name: 'array',\n              value: {\n                name: 'object',\n                value: {\n                  arr: numArrayType,\n                  obj: boolObjectType,\n                },\n              },\n            },\n          },\n        }\n      )\n    ).toStrictEqual({\n      key: [\n        {\n          arr: [1, 2],\n          obj: { bool: true },\n        },\n      ],\n    });\n  });\n});\n\ndescribe('combineArgs', () => {\n  it('merges args', () => {\n    expect(combineArgs({ foo: 1 }, { bar: 2 })).toStrictEqual({ foo: 1, bar: 2 });\n  });\n\n  it('merges sparse arrays', () => {\n    expect(combineArgs({ foo: [1, 2, 3] }, { foo: [, 4, undefined] })).toStrictEqual({\n      foo: [1, 4],\n    });\n  });\n\n  it('deeply merges args', () => {\n    expect(combineArgs({ foo: { bar: [1, 2], baz: true } }, { foo: { bar: [3] } })).toStrictEqual({\n      foo: { bar: [3, 2], baz: true },\n    });\n  });\n\n  it('omits keys with undefined value', () => {\n    expect(combineArgs({ foo: 1 }, { foo: undefined })).toStrictEqual({});\n  });\n});\n\ndescribe('validateOptions', () => {\n  // https://github.com/storybookjs/storybook/issues/15630\n  it('does not set args to `undefined` if they are unset', () => {\n    expect(validateOptions({}, { a: {} })).toStrictEqual({});\n  });\n\n  it('omits arg and warns if value is not one of options', () => {\n    expect(validateOptions({ a: 1 }, { a: { options: [2, 3] } })).toStrictEqual({});\n    expect(once.warn).toHaveBeenCalledWith(\n      \"Received illegal value for 'a'. Supported options: 2, 3\"\n    );\n  });\n\n  it('includes arg if value is one of options', () => {\n    expect(validateOptions({ a: 1 }, { a: { options: [1, 2] } })).toStrictEqual({ a: 1 });\n  });\n\n  // https://github.com/storybookjs/storybook/issues/17063\n  it('does not set args to `undefined` if they are unset and there are options', () => {\n    expect(validateOptions({}, { a: { options: [2, 3] } })).toStrictEqual({});\n  });\n\n  it('includes arg if value is undefined', () => {\n    expect(validateOptions({ a: undefined }, { a: { options: [1, 2] } })).toStrictEqual({\n      a: undefined,\n    });\n  });\n\n  it('includes arg if no options are specified', () => {\n    expect(validateOptions({ a: 1 }, { a: {} })).toStrictEqual({ a: 1 });\n  });\n\n  it('ignores options and logs an error if options is not an array', () => {\n    // @ts-expect-error This should give TS error indeed (finally!)\n    expect(validateOptions({ a: 1 }, { a: { options: { 2: 'two' } } })).toStrictEqual({ a: 1 });\n    expect(once.error).toHaveBeenCalledWith(\n      expect.stringContaining(\"Invalid argType: 'a.options' should be an array\")\n    );\n  });\n\n  it('logs an error if options contains non-primitive values', () => {\n    expect(\n      validateOptions({ a: { one: 1 } }, { a: { options: [{ one: 1 }, { two: 2 }] } })\n    ).toStrictEqual({ a: { one: 1 } });\n    expect(once.error).toHaveBeenCalledWith(\n      expect.stringContaining(\"Invalid argType: 'a.options' should only contain primitives\")\n    );\n    expect(once.warn).not.toHaveBeenCalled();\n  });\n\n  it('supports arrays', () => {\n    expect(validateOptions({ a: [1, 2] }, { a: { options: [1, 2, 3] } })).toStrictEqual({\n      a: [1, 2],\n    });\n    expect(validateOptions({ a: [1, 2, 4] }, { a: { options: [2, 3] } })).toStrictEqual({});\n    expect(once.warn).toHaveBeenCalledWith(\n      \"Received illegal value for 'a[0]'. Supported options: 2, 3\"\n    );\n  });\n});\n\ndescribe('groupArgsByTarget', () => {\n  it('groups targeted args', () => {\n    const groups = groupArgsByTarget({\n      args: { a: 1, b: 2, c: 3 },\n      argTypes: {\n        a: { name: 'a', target: 'group1' },\n        b: { name: 'b', target: 'group2' },\n        c: { name: 'c', target: 'group2' },\n      },\n    });\n    expect(groups).toEqual({\n      group1: {\n        a: 1,\n      },\n      group2: {\n        b: 2,\n        c: 3,\n      },\n    });\n  });\n\n  it('groups non-targetted args into a group with no name', () => {\n    const groups = groupArgsByTarget({\n      args: { a: 1, b: 2, c: 3 },\n      argTypes: { a: { name: 'a' }, b: { name: 'b', target: 'group2' }, c: { name: 'c' } },\n    });\n    expect(groups).toEqual({\n      [UNTARGETED]: {\n        a: 1,\n        c: 3,\n      },\n      group2: {\n        b: 2,\n      },\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/args.ts",
    "content": "import { once } from 'storybook/internal/client-logger';\nimport type {\n  ArgTypes,\n  Args,\n  InputType,\n  Renderer,\n  SBType,\n  StoryContext,\n} from 'storybook/internal/types';\n\nimport { isEqual as deepEqual, isPlainObject } from 'es-toolkit/predicate';\nimport { dedent } from 'ts-dedent';\n\nconst INCOMPATIBLE = Symbol('incompatible');\nconst map = (arg: unknown, argType: InputType): any => {\n  const type = argType.type as SBType;\n\n  if (arg === undefined || arg === null || !type) {\n    return arg;\n  }\n  if (argType.mapping) {\n    return arg;\n  }\n  switch (type.name) {\n    case 'string':\n      return String(arg);\n    case 'enum':\n      return arg;\n    case 'number':\n      return Number(arg);\n    case 'boolean':\n      return String(arg) === 'true';\n    case 'array':\n      if (!type.value || !Array.isArray(arg)) {\n        return INCOMPATIBLE;\n      }\n      return arg.reduce((acc, item, index) => {\n        const mapped = map(item, { type: type.value });\n\n        if (mapped !== INCOMPATIBLE) {\n          acc[index] = mapped;\n        }\n        return acc;\n      }, new Array(arg.length));\n    case 'object':\n      if (typeof arg === 'string' || typeof arg === 'number') {\n        return arg;\n      }\n\n      if (!type.value || typeof arg !== 'object') {\n        return INCOMPATIBLE;\n      }\n      return Object.entries(arg).reduce((acc, [key, val]) => {\n        const mapped = map(val, { type: type.value[key] });\n        return mapped === INCOMPATIBLE ? acc : Object.assign(acc, { [key]: mapped });\n      }, {} as Args);\n    case 'other': {\n      const isPrimitiveArg =\n        typeof arg === 'string' || typeof arg === 'number' || typeof arg === 'boolean';\n\n      // Only proceed if `argType.value` is a `ReactNode`.\n      // Only permit primitives: they are included in `ReactNode` type, making them easily applicable.\n      if (type.value === 'ReactNode' && isPrimitiveArg) {\n        return arg;\n      }\n\n      return INCOMPATIBLE;\n    }\n    default:\n      return INCOMPATIBLE;\n  }\n};\n\nexport const mapArgsToTypes = (args: Args, argTypes: ArgTypes): Args => {\n  return Object.entries(args).reduce((acc, [key, value]) => {\n    if (!argTypes[key]) {\n      return acc;\n    }\n    const mapped = map(value, argTypes[key]);\n    return mapped === INCOMPATIBLE ? acc : Object.assign(acc, { [key]: mapped });\n  }, {});\n};\n\nexport const combineArgs = (value: any, update: any): Args => {\n  if (Array.isArray(value) && Array.isArray(update)) {\n    return update\n      .reduce(\n        (acc, upd, index) => {\n          acc[index] = combineArgs(value[index], update[index]);\n          return acc;\n        },\n        [...value]\n      )\n      .filter((v: any) => v !== undefined);\n  }\n\n  if (!isPlainObject(value) || !isPlainObject(update)) {\n    return update;\n  }\n  return Object.keys({ ...value, ...update }).reduce((acc, key) => {\n    if (key in update) {\n      const combined = combineArgs(value[key], update[key]);\n\n      if (combined !== undefined) {\n        acc[key] = combined;\n      }\n    } else {\n      acc[key] = value[key];\n    }\n    return acc;\n  }, {} as any);\n};\n\nexport const validateOptions = (args: Args, argTypes: ArgTypes): Args => {\n  return Object.entries(argTypes).reduce((acc, [key, { options }]) => {\n    // Don't set args that are not defined in `args` (they can be undefined in there)\n    // see https://github.com/storybookjs/storybook/issues/15630 and\n    //   https://github.com/storybookjs/storybook/issues/17063\n    function allowArg() {\n      if (key in args) {\n        acc[key] = args[key];\n      }\n      return acc;\n    }\n\n    if (!options) {\n      return allowArg();\n    }\n\n    if (!Array.isArray(options)) {\n      once.error(dedent`\n        Invalid argType: '${key}.options' should be an array.\n\n        More info: https://storybook.js.org/docs/api/arg-types?ref=error\n      `);\n      return allowArg();\n    }\n\n    if (options.some((opt) => opt && ['object', 'function'].includes(typeof opt))) {\n      once.error(dedent`\n        Invalid argType: '${key}.options' should only contain primitives. Use a 'mapping' for complex values.\n\n        More info: https://storybook.js.org/docs/writing-stories/args?ref=error#mapping-to-complex-arg-values\n      `);\n      return allowArg();\n    }\n\n    const isArray = Array.isArray(args[key]);\n    const invalidIndex = isArray && args[key].findIndex((val: any) => !options.includes(val));\n    const isValidArray = isArray && invalidIndex === -1;\n\n    if (args[key] === undefined || options.includes(args[key]) || isValidArray) {\n      return allowArg();\n    }\n\n    const field = isArray ? `${key}[${invalidIndex}]` : key;\n    const supportedOptions = options\n      .map((opt: any) => (typeof opt === 'string' ? `'${opt}'` : String(opt)))\n      .join(', ');\n    once.warn(`Received illegal value for '${field}'. Supported options: ${supportedOptions}`);\n\n    return acc;\n  }, {} as Args);\n};\n\n// TODO -- copied from router, needs to be in a shared location\nexport const DEEPLY_EQUAL = Symbol('Deeply equal');\nexport const deepDiff = (value: any, update: any): any => {\n  if (typeof value !== typeof update) {\n    return update;\n  }\n\n  if (deepEqual(value, update)) {\n    return DEEPLY_EQUAL;\n  }\n  if (Array.isArray(value) && Array.isArray(update)) {\n    const res = update.reduce((acc, upd, index) => {\n      const diff = deepDiff(value[index], upd);\n\n      if (diff !== DEEPLY_EQUAL) {\n        acc[index] = diff;\n      }\n      return acc;\n    }, new Array(update.length));\n\n    if (update.length >= value.length) {\n      return res;\n    }\n    return res.concat(new Array(value.length - update.length).fill(undefined));\n  }\n  if (isPlainObject(value) && isPlainObject(update)) {\n    return Object.keys({ ...value, ...update }).reduce((acc, key) => {\n      const diff = deepDiff(value?.[key], update?.[key]);\n      return diff === DEEPLY_EQUAL ? acc : Object.assign(acc, { [key]: diff });\n    }, {});\n  }\n  return update;\n};\n\nexport const UNTARGETED = 'UNTARGETED';\nexport function groupArgsByTarget<TArgs extends Args = Args>({\n  args,\n  argTypes,\n}: Pick<StoryContext<Renderer, TArgs>, 'args' | 'argTypes'>) {\n  const groupedArgs: Record<string, Partial<TArgs>> = {};\n  (Object.entries(args) as [keyof TArgs, any][]).forEach(([name, value]) => {\n    const { target = UNTARGETED } = (argTypes[name] || {}) as { target?: string };\n\n    groupedArgs[target] = groupedArgs[target] || {};\n    groupedArgs[target][name] = value;\n  });\n  return groupedArgs;\n}\n\nexport function noTargetArgs<TArgs extends Args = Args>(\n  context: Pick<StoryContext<Renderer, TArgs>, 'args' | 'argTypes'>\n) {\n  return groupArgsByTarget(context)[UNTARGETED];\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/autoTitle.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { normalizeStoriesEntry } from 'storybook/internal/common';\n\nimport { userOrAutoTitleFromSpecifier as userOrAuto } from './autoTitle.ts';\n\nexpect.addSnapshotSerializer({\n  print: (val: any) => val,\n  test: (val: any) => true,\n});\n\n// Make these two the same so `normalizeStoriesEntry` doesn't change anything\nconst options = {\n  configDir: '/path',\n  workingDir: '/path',\n};\nconst winOptions = {\n  configDir: '\\\\path',\n  workingDir: '\\\\path',\n};\n\ndescribe('userOrAutoTitleFromSpecifier', () => {\n  describe('user title', () => {\n    it('no match', () => {\n      expect(\n        userOrAuto(\n          './ path / to / file.stories.js',\n          normalizeStoriesEntry({ directory: './ other' }, options),\n          'title'\n        )\n      ).toBeFalsy();\n    });\n\n    describe('no trailing slash', () => {\n      it('match with no titlePrefix', () => {\n        expect(\n          userOrAuto(\n            './path/to/file.stories.js',\n            normalizeStoriesEntry({ directory: './path' }, options),\n            'title'\n          )\n        ).toMatchInlineSnapshot(`title`);\n      });\n\n      it('match with titlePrefix', () => {\n        expect(\n          userOrAuto(\n            './path/to/file.stories.js',\n            normalizeStoriesEntry({ directory: './path', titlePrefix: 'atoms' }, options),\n            'title'\n          )\n        ).toMatchInlineSnapshot(`atoms/title`);\n      });\n\n      it('match with hyphen path', () => {\n        expect(\n          userOrAuto(\n            './path/to-my/file.stories.js',\n            normalizeStoriesEntry({ directory: './path', titlePrefix: 'atoms' }, options),\n            'title'\n          )\n        ).toMatchInlineSnapshot(`atoms/title`);\n      });\n\n      it('match with underscore path', () => {\n        expect(\n          userOrAuto(\n            './path/to_my/file.stories.js',\n            normalizeStoriesEntry({ directory: './path', titlePrefix: 'atoms' }, options),\n            'title'\n          )\n        ).toMatchInlineSnapshot(`atoms/title`);\n      });\n\n      it('match with windows path', () => {\n        expect(\n          userOrAuto(\n            './path/to_my/file.stories.js',\n            normalizeStoriesEntry({ directory: '.\\\\path', titlePrefix: 'atoms' }, winOptions),\n            'title'\n          )\n        ).toMatchInlineSnapshot(`atoms/title`);\n      });\n    });\n\n    describe('trailing slash', () => {\n      it('match with no titlePrefix', () => {\n        expect(\n          userOrAuto(\n            './path/to/file.stories.js',\n            normalizeStoriesEntry({ directory: './path/' }, options),\n            'title'\n          )\n        ).toMatchInlineSnapshot(`title`);\n      });\n\n      it('match with titlePrefix', () => {\n        expect(\n          userOrAuto(\n            './path/to/file.stories.js',\n            normalizeStoriesEntry({ directory: './path/', titlePrefix: 'atoms' }, options),\n            'title'\n          )\n        ).toMatchInlineSnapshot(`atoms/title`);\n      });\n\n      it('match with hyphen path', () => {\n        expect(\n          userOrAuto(\n            './path/to-my/file.stories.js',\n            normalizeStoriesEntry({ directory: './path/', titlePrefix: 'atoms' }, options),\n            'title'\n          )\n        ).toMatchInlineSnapshot(`atoms/title`);\n      });\n\n      it('match with underscore path', () => {\n        expect(\n          userOrAuto(\n            './path/to_my/file.stories.js',\n            normalizeStoriesEntry({ directory: './path/', titlePrefix: 'atoms' }, options),\n            'title'\n          )\n        ).toMatchInlineSnapshot(`atoms/title`);\n      });\n\n      it('match with windows path', () => {\n        expect(\n          userOrAuto(\n            './path/to_my/file.stories.js',\n            normalizeStoriesEntry({ directory: '.\\\\path\\\\', titlePrefix: 'atoms' }, winOptions),\n            'title'\n          )\n        ).toMatchInlineSnapshot(`atoms/title`);\n      });\n    });\n  });\n\n  describe('auto title', () => {\n    it('no match', () => {\n      expect(\n        userOrAuto(\n          './ path / to / file.stories.js',\n          normalizeStoriesEntry({ directory: './ other' }, options),\n          undefined\n        )\n      ).toBeFalsy();\n    });\n\n    describe('no trailing slash', () => {\n      it('match with no titlePrefix', () => {\n        expect(\n          userOrAuto(\n            './path/to/file.stories.js',\n            normalizeStoriesEntry({ directory: './path' }, options),\n            undefined\n          )\n        ).toMatchInlineSnapshot(`to/file`);\n      });\n\n      it('match with titlePrefix', () => {\n        expect(\n          userOrAuto(\n            './path/to/file.stories.js',\n            normalizeStoriesEntry({ directory: './path', titlePrefix: 'atoms' }, options),\n            undefined\n          )\n        ).toMatchInlineSnapshot(`atoms/to/file`);\n      });\n\n      it('match with trailing duplicate', () => {\n        expect(\n          userOrAuto(\n            './path/to/button/button.stories.js',\n            normalizeStoriesEntry({ directory: './path' }, options),\n            undefined\n          )\n        ).toMatchInlineSnapshot(`to/button`);\n      });\n\n      it('match with case-insensitive trailing duplicate', () => {\n        expect(\n          userOrAuto(\n            './path/to/button/Button.stories.js',\n            normalizeStoriesEntry({ directory: './path' }, options),\n            undefined\n          )\n        ).toMatchInlineSnapshot(`to/Button`);\n      });\n\n      it('match with trailing index', () => {\n        expect(\n          userOrAuto(\n            './path/to/button/index.stories.js',\n            normalizeStoriesEntry({ directory: './path' }, options),\n            undefined\n          )\n        ).toMatchInlineSnapshot(`to/button`);\n      });\n\n      it('match with trailing stories', () => {\n        expect(\n          userOrAuto(\n            './path/to/button/stories.js',\n            normalizeStoriesEntry({ directory: './path', files: '**/?(*.)stories.*' }, options),\n            undefined\n          )\n        ).toMatchInlineSnapshot(`to/button`);\n      });\n\n      it('match with trailing stories (windows path)', () => {\n        expect(\n          userOrAuto(\n            './path/to/button/stories.js',\n            normalizeStoriesEntry(\n              { directory: '.\\\\path\\\\', files: '**/?(*.)stories.*' },\n              winOptions\n            ),\n            undefined\n          )\n        ).toMatchInlineSnapshot(`to/button`);\n      });\n\n      it('match with dotted component', () => {\n        expect(\n          userOrAuto(\n            './path/to/button/button.group.stories.js',\n            normalizeStoriesEntry({ directory: './path' }, options),\n            undefined\n          )\n        ).toMatchInlineSnapshot(`to/button/button.group`);\n      });\n\n      it('match with hyphen path', () => {\n        expect(\n          userOrAuto(\n            './path/to-my/file.stories.js',\n            normalizeStoriesEntry({ directory: './path' }, options),\n            undefined\n          )\n        ).toMatchInlineSnapshot(`to-my/file`);\n      });\n\n      it('match with underscore path', () => {\n        expect(\n          userOrAuto(\n            './path/to_my/file.stories.js',\n            normalizeStoriesEntry({ directory: './path' }, options),\n            undefined\n          )\n        ).toMatchInlineSnapshot(`to_my/file`);\n      });\n\n      it('match with short path', () => {\n        // Make sure \"stories\" isn't trimmed as redundant when there won't be\n        // anything left.\n        expect(\n          userOrAuto(\n            './path/stories.js',\n            normalizeStoriesEntry({ directory: './path', files: '**/?(*.)stories.*' }, options),\n            undefined\n          )\n        ).toMatchInlineSnapshot(`stories`);\n      });\n\n      it('match with windows path', () => {\n        expect(\n          userOrAuto(\n            './path/to_my/file.stories.js',\n            normalizeStoriesEntry({ directory: '.\\\\path' }, winOptions),\n            undefined\n          )\n        ).toMatchInlineSnapshot(`to_my/file`);\n      });\n    });\n\n    describe('trailing slash', () => {\n      it('match with no titlePrefix', () => {\n        expect(\n          userOrAuto(\n            './path/to/file.stories.js',\n            normalizeStoriesEntry({ directory: './path/' }, options),\n            undefined\n          )\n        ).toMatchInlineSnapshot(`to/file`);\n      });\n\n      it('match with titlePrefix', () => {\n        expect(\n          userOrAuto(\n            './path/to/file.stories.js',\n            normalizeStoriesEntry({ directory: './path/', titlePrefix: 'atoms' }, options),\n            undefined\n          )\n        ).toMatchInlineSnapshot(`atoms/to/file`);\n      });\n\n      it('match with hyphen path', () => {\n        expect(\n          userOrAuto(\n            './path/to-my/file.stories.js',\n            normalizeStoriesEntry({ directory: './path/' }, options),\n            undefined\n          )\n        ).toMatchInlineSnapshot(`to-my/file`);\n      });\n\n      it('match with underscore path', () => {\n        expect(\n          userOrAuto(\n            './path/to_my/file.stories.js',\n            normalizeStoriesEntry({ directory: './path/' }, options),\n            undefined\n          )\n        ).toMatchInlineSnapshot(`to_my/file`);\n      });\n\n      it('match with windows path', () => {\n        expect(\n          userOrAuto(\n            './path/to_my/file.stories.js',\n            normalizeStoriesEntry({ directory: '.\\\\path\\\\' }, winOptions),\n            undefined\n          )\n        ).toMatchInlineSnapshot(`to_my/file`);\n      });\n\n      it('camel-case file', () => {\n        expect(\n          userOrAuto(\n            './path/to_my/MyButton.stories.js',\n            normalizeStoriesEntry({ directory: './path' }, options),\n            undefined\n          )\n        ).toMatchInlineSnapshot(`to_my/MyButton`);\n      });\n    });\n\n    it('Story.stories.js', () => {\n      expect(\n        userOrAuto(\n          '../blocks/src/Story.stories.tsx',\n          normalizeStoriesEntry(\n            {\n              directory: '../blocks/src',\n              titlePrefix: '@blocks',\n            },\n            options\n          ),\n          undefined\n        )\n      ).toMatchInlineSnapshot(`@blocks/Story`);\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/autoTitle.ts",
    "content": "import { once } from 'storybook/internal/client-logger';\nimport type { NormalizedStoriesSpecifier } from 'storybook/internal/types';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\nimport { dedent } from 'ts-dedent';\n\n// FIXME: types duplicated type from `core-common', to be\n// removed when we remove v6 back-compat.\n\n// deal with files like \"atoms/button/{button,index}.stories.js\"\nconst sanitize = (parts: string[]) => {\n  if (parts.length === 0) {\n    return parts;\n  }\n\n  const last = parts[parts.length - 1];\n  const lastStripped = last?.replace(/(?:[.](?:story|stories))?([.][^.]+)$/i, '');\n\n  if (parts.length === 1) {\n    return [lastStripped];\n  }\n\n  const nextToLast = parts[parts.length - 2];\n  if (lastStripped && nextToLast && lastStripped.toLowerCase() === nextToLast.toLowerCase()) {\n    return [...parts.slice(0, -2), lastStripped];\n  }\n\n  return lastStripped &&\n    (/^(story|stories)([.][^.]+)$/i.test(last) || /^index$/i.test(lastStripped))\n    ? parts.slice(0, -1)\n    : [...parts.slice(0, -1), lastStripped];\n};\n\n/**\n * Combines path parts together, without duplicating separators (slashes). Used instead of\n * `path.join` because this code runs in the browser.\n *\n * @param paths Array of paths to join together.\n * @returns Joined path string, with single '/' between parts\n */\nfunction pathJoin(paths: string[]): string {\n  return paths\n    .flatMap((p) => p.split('/'))\n    .filter(Boolean)\n    .join('/');\n}\n\nexport const userOrAutoTitleFromSpecifier = (\n  fileName: string | number,\n  entry: NormalizedStoriesSpecifier,\n  userTitle?: string\n) => {\n  const { directory, importPathMatcher, titlePrefix = '' } = entry || {};\n  // On Windows, backslashes are used in paths, which can cause problems here\n  // slash makes sure we always handle paths with unix-style forward slash\n\n  if (typeof fileName === 'number') {\n    once.warn(dedent`\n      CSF Auto-title received a numeric fileName. This typically happens when\n      webpack is mis-configured in production mode. To force webpack to produce\n      filenames, set optimization.moduleIds = \"named\" in your webpack config.\n    `);\n  }\n\n  const normalizedFileName = slash(String(fileName));\n\n  if (importPathMatcher.exec(normalizedFileName)) {\n    if (!userTitle) {\n      const suffix = normalizedFileName.replace(directory, '');\n      let parts = pathJoin([titlePrefix, suffix]).split('/');\n      parts = sanitize(parts);\n      return parts.join('/');\n    }\n\n    if (!titlePrefix) {\n      return userTitle;\n    }\n\n    return pathJoin([titlePrefix, userTitle]);\n  }\n\n  return undefined;\n};\n\nexport const userOrAutoTitle = (\n  fileName: string,\n  storiesEntries: NormalizedStoriesSpecifier[],\n  userTitle?: string\n) => {\n  for (let i = 0; i < storiesEntries.length; i += 1) {\n    const title = userOrAutoTitleFromSpecifier(fileName, storiesEntries[i], userTitle);\n\n    if (title) {\n      return title;\n    }\n  }\n\n  return userTitle || undefined;\n};\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/__mocks__/defaultExportAnnotations.mockfile.ts",
    "content": "export default {\n  parameters: {\n    fromAnnotations: {\n      asDefaultImport: true,\n    },\n  },\n};\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/__mocks__/namedExportAnnotations.mockfile.ts",
    "content": "export const parameters = {\n  fromAnnotations: {\n    asObjectImport: true,\n  },\n};\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/beforeAll.test.ts",
    "content": "import { beforeEach, describe, expect, it } from 'vitest';\n\nimport { composeBeforeAllHooks } from './beforeAll.ts';\n\nconst calls: string[] = [];\n\nbeforeEach(() => {\n  calls.length = 0;\n});\n\nconst basicHook = (label: string) => () => {\n  calls.push(label);\n};\nconst asyncHook = (label: string, delay: number) => async () => {\n  await new Promise((resolve) => setTimeout(resolve, delay));\n  calls.push(label);\n};\nconst cleanupHook = (label: string) => () => {\n  calls.push(label);\n  return () => {\n    calls.push(label + ' cleanup');\n  };\n};\nconst asyncCleanupHook = (label: string, delay: number) => () => {\n  calls.push(label);\n  return async () => {\n    await new Promise((resolve) => setTimeout(resolve, delay));\n    calls.push(label + ' cleanup');\n  };\n};\n\ndescribe('composeBeforeAllHooks', () => {\n  it('should return a composed hook function', async () => {\n    await composeBeforeAllHooks([basicHook('one'), basicHook('two'), basicHook('three')])();\n    expect(calls).toEqual(['one', 'two', 'three']);\n  });\n\n  it('should execute cleanups in reverse order', async () => {\n    const cleanup = await composeBeforeAllHooks([\n      cleanupHook('one'),\n      cleanupHook('two'),\n      cleanupHook('three'),\n    ])();\n    expect(calls).toEqual(['one', 'two', 'three']);\n\n    await cleanup?.();\n    expect(calls).toEqual(['one', 'two', 'three', 'three cleanup', 'two cleanup', 'one cleanup']);\n  });\n\n  it('should execute async hooks in sequence', async () => {\n    await composeBeforeAllHooks([\n      asyncHook('one', 10),\n      asyncHook('two', 100),\n      asyncHook('three', 10),\n    ])();\n    expect(calls).toEqual(['one', 'two', 'three']);\n  });\n\n  it('should execute async cleanups in reverse order', async () => {\n    const hooks = [\n      asyncCleanupHook('one', 10),\n      asyncCleanupHook('two', 100),\n      asyncCleanupHook('three', 10),\n    ];\n\n    const cleanup = await composeBeforeAllHooks(hooks)();\n    expect(calls).toEqual(['one', 'two', 'three']);\n\n    await cleanup?.();\n    expect(calls).toEqual(['one', 'two', 'three', 'three cleanup', 'two cleanup', 'one cleanup']);\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/beforeAll.ts",
    "content": "import { type BeforeAll, type CleanupCallback } from 'storybook/internal/csf';\n\n// Execute all the hooks in sequence, and return a function that will execute cleanups in reverse order\nexport const composeBeforeAllHooks = (hooks: BeforeAll[]): BeforeAll => {\n  return async () => {\n    const cleanups: CleanupCallback[] = [];\n    for (const hook of hooks) {\n      const cleanup = await hook();\n\n      if (cleanup) {\n        cleanups.unshift(cleanup);\n      }\n    }\n    return async () => {\n      for (const cleanup of cleanups) {\n        await cleanup();\n      }\n    };\n  };\n};\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/composeConfigs.test.ts",
    "content": "import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { global } from '@storybook/global';\n\nimport { composeConfigs } from './composeConfigs.ts';\n\nvi.mock('@storybook/global', () => ({\n  global: {\n    FEATURES: {},\n  },\n}));\n\ndescribe('composeConfigs', () => {\n  it('sets default (empty) values for fields', () => {\n    expect(composeConfigs([])).toEqual({\n      parameters: {},\n      decorators: [],\n      args: {},\n      argsEnhancers: [],\n      argTypes: {},\n      argTypesEnhancers: [],\n      initialGlobals: {},\n      globalTypes: {},\n      loaders: [],\n      beforeAll: expect.any(Function),\n      beforeEach: [],\n      afterEach: [],\n      runStep: expect.any(Function),\n      tags: [],\n    });\n  });\n\n  it('composes parameters', () => {\n    expect(\n      composeConfigs([\n        {\n          parameters: { obj: { a: '1', b: '1' } },\n        },\n        {\n          parameters: { obj: { a: '2', c: '2' } },\n        },\n      ])\n    ).toEqual({\n      parameters: { obj: { a: '2', b: '1', c: '2' } },\n      decorators: [],\n      args: {},\n      argsEnhancers: [],\n      argTypes: {},\n      argTypesEnhancers: [],\n      initialGlobals: {},\n      globalTypes: {},\n      loaders: [],\n      beforeAll: expect.any(Function),\n      beforeEach: [],\n      afterEach: [],\n      runStep: expect.any(Function),\n      tags: [],\n    });\n  });\n\n  it('composes export defaults', () => {\n    expect(\n      composeConfigs([\n        {\n          default: {\n            parameters: { obj: { a: '1', b: '1' } },\n          },\n        },\n        {\n          default: {\n            parameters: { obj: { a: '2', c: '2' } },\n          },\n        },\n      ])\n    ).toEqual({\n      parameters: { obj: { a: '2', b: '1', c: '2' } },\n      decorators: [],\n      args: {},\n      argsEnhancers: [],\n      argTypes: {},\n      argTypesEnhancers: [],\n      initialGlobals: {},\n      globalTypes: {},\n      loaders: [],\n      beforeAll: expect.any(Function),\n      beforeEach: [],\n      afterEach: [],\n      runStep: expect.any(Function),\n      tags: [],\n    });\n  });\n\n  it('overrides object fields by key', () => {\n    expect(\n      composeConfigs([\n        {\n          default: {\n            args: { x: '1', y: '1', obj: { a: '1', b: '1' } },\n            argTypes: { x: '1', y: '1', obj: { a: '1', b: '1' } },\n            initialGlobals: { x: '1', y: '1', obj: { a: '1', b: '1' } },\n            globalTypes: { x: '1', y: '1', obj: { a: '1', b: '1' } },\n          },\n        },\n        {\n          default: {\n            args: { x: '2', z: '2', obj: { a: '2', c: '2' } },\n            argTypes: { x: '2', z: '2', obj: { a: '2', c: '2' } },\n            initialGlobals: { x: '2', z: '2', obj: { a: '2', c: '2' } },\n            globalTypes: { x: '2', z: '2', obj: { a: '2', c: '2' } },\n          },\n        },\n      ])\n    ).toEqual({\n      parameters: {},\n      decorators: [],\n      args: { x: '2', y: '1', z: '2', obj: { a: '2', c: '2' } },\n      argsEnhancers: [],\n      argTypes: { x: '2', y: '1', z: '2', obj: { a: '2', c: '2' } },\n      argTypesEnhancers: [],\n      initialGlobals: { x: '2', y: '1', z: '2', obj: { a: '2', c: '2' } },\n      globalTypes: { x: '2', y: '1', z: '2', obj: { a: '2', c: '2' } },\n      loaders: [],\n      beforeAll: expect.any(Function),\n      beforeEach: [],\n      afterEach: [],\n      runStep: expect.any(Function),\n      tags: [],\n    });\n  });\n\n  it('overrides object fields by key with mixed named and default exports', () => {\n    expect(\n      // configs could come from user, addons, presets, frameworks.. so they will likely be mixed in format\n      composeConfigs([\n        {\n          default: {\n            args: { x: '1', y: '1', obj: { a: '1', b: '1' } },\n            argTypes: { x: '1', y: '1', obj: { a: '1', b: '1' } },\n            initialGlobals: { x: '1', y: '1', obj: { a: '1', b: '1' } },\n            globalTypes: { x: '1', y: '1', obj: { a: '1', b: '1' } },\n          },\n        },\n        {\n          args: { x: '2', z: '2', obj: { a: '2', c: '2' } },\n          argTypes: { x: '2', z: '2', obj: { a: '2', c: '2' } },\n          initialGlobals: { x: '2', z: '2', obj: { a: '2', c: '2' } },\n        },\n        {\n          default: {\n            globalTypes: { x: '2', z: '2', obj: { a: '2', c: '2' } },\n          },\n        },\n      ])\n    ).toEqual({\n      parameters: {},\n      decorators: [],\n      args: { x: '2', y: '1', z: '2', obj: { a: '2', c: '2' } },\n      argsEnhancers: [],\n      argTypes: { x: '2', y: '1', z: '2', obj: { a: '2', c: '2' } },\n      argTypesEnhancers: [],\n      initialGlobals: { x: '2', y: '1', z: '2', obj: { a: '2', c: '2' } },\n      globalTypes: { x: '2', y: '1', z: '2', obj: { a: '2', c: '2' } },\n      loaders: [],\n      beforeAll: expect.any(Function),\n      beforeEach: [],\n      afterEach: [],\n      runStep: expect.any(Function),\n      tags: [],\n    });\n  });\n\n  it('concats array fields', () => {\n    expect(\n      composeConfigs([\n        {\n          argsEnhancers: ['1', '2'],\n          argTypesEnhancers: ['1', '2'],\n          loaders: ['1', '2'],\n        },\n        {\n          argsEnhancers: ['3', '4'],\n          argTypesEnhancers: ['3', '4'],\n          loaders: ['3', '4'],\n        },\n      ])\n    ).toEqual({\n      parameters: {},\n      decorators: [],\n      args: {},\n      argsEnhancers: ['1', '2', '3', '4'],\n      argTypes: {},\n      argTypesEnhancers: ['1', '2', '3', '4'],\n      initialGlobals: {},\n      globalTypes: {},\n      loaders: ['1', '2', '3', '4'],\n      beforeAll: expect.any(Function),\n      beforeEach: [],\n      afterEach: [],\n      runStep: expect.any(Function),\n      tags: [],\n    });\n  });\n\n  it('allows single array to be written without array', () => {\n    expect(\n      composeConfigs([\n        {\n          argsEnhancers: ['1', '2'],\n          argTypesEnhancers: ['1', '2'],\n          loaders: '1',\n        },\n        {\n          argsEnhancers: '3',\n          argTypesEnhancers: '3',\n          loaders: ['2', '3'],\n        },\n      ])\n    ).toEqual({\n      parameters: {},\n      decorators: [],\n      args: {},\n      argsEnhancers: ['1', '2', '3'],\n      argTypes: {},\n      argTypesEnhancers: ['1', '2', '3'],\n      initialGlobals: {},\n      globalTypes: {},\n      loaders: ['1', '2', '3'],\n      beforeAll: expect.any(Function),\n      beforeEach: [],\n      afterEach: [],\n      runStep: expect.any(Function),\n      tags: [],\n    });\n  });\n\n  it('combines decorators in reverse file order', () => {\n    expect(\n      composeConfigs([\n        {\n          decorators: ['1', '2'],\n        },\n        {\n          decorators: ['3', '4'],\n        },\n      ])\n    ).toEqual({\n      parameters: {},\n      decorators: ['3', '4', '1', '2'],\n      args: {},\n      argsEnhancers: [],\n      argTypes: {},\n      argTypesEnhancers: [],\n      initialGlobals: {},\n      globalTypes: {},\n      loaders: [],\n      beforeAll: expect.any(Function),\n      beforeEach: [],\n      afterEach: [],\n      runStep: expect.any(Function),\n      tags: [],\n    });\n  });\n\n  it('concats argTypesEnhancers in two passes', () => {\n    expect(\n      composeConfigs([\n        { argTypesEnhancers: [{ a: '1' }, { a: '2', secondPass: true }] },\n        { argTypesEnhancers: [{ a: '3' }, { a: '4', secondPass: true }] },\n      ])\n    ).toEqual({\n      parameters: {},\n      decorators: [],\n      args: {},\n      argsEnhancers: [],\n      argTypes: {},\n      argTypesEnhancers: [\n        { a: '1' },\n        { a: '3' },\n        { a: '2', secondPass: true },\n        { a: '4', secondPass: true },\n      ],\n      initialGlobals: {},\n      globalTypes: {},\n      loaders: [],\n      beforeAll: expect.any(Function),\n      beforeEach: [],\n      afterEach: [],\n      runStep: expect.any(Function),\n      tags: [],\n    });\n  });\n\n  it('concats chooses scalar fields', () => {\n    expect(\n      composeConfigs([\n        {\n          render: 'render-1',\n          renderToCanvas: 'renderToCanvas-1',\n          applyDecorators: 'applyDecorators-1',\n        },\n        {\n          render: 'render-2',\n          renderToCanvas: 'renderToCanvas-2',\n          applyDecorators: 'applyDecorators-2',\n        },\n      ])\n    ).toEqual({\n      parameters: {},\n      decorators: [],\n      args: {},\n      argsEnhancers: [],\n      argTypes: {},\n      argTypesEnhancers: [],\n      initialGlobals: {},\n      globalTypes: {},\n      loaders: [],\n      beforeAll: expect.any(Function),\n      beforeEach: [],\n      afterEach: [],\n      render: 'render-2',\n      renderToCanvas: 'renderToCanvas-2',\n      applyDecorators: 'applyDecorators-2',\n      runStep: expect.any(Function),\n      tags: [],\n    });\n  });\n\n  it('composes beforeAll hooks', async () => {\n    const one = vi.fn();\n    const two = vi.fn();\n    const three = vi.fn();\n\n    const { beforeAll } = composeConfigs([\n      { beforeAll: one },\n      { beforeAll: two },\n      { beforeAll: three },\n    ]);\n\n    await beforeAll?.();\n\n    expect(one).toHaveBeenCalled();\n    expect(two).toHaveBeenCalled();\n    expect(three).toHaveBeenCalled();\n  });\n\n  it('composes step runners', () => {\n    const fn = vi.fn();\n\n    const { runStep } = composeConfigs([\n      // @ts-expect-error (not defined)\n      { runStep: (label, play, context) => fn(`${label}1`, play(context)) },\n      // @ts-expect-error (not defined)\n      { runStep: (label, play, context) => fn(`${label}2`, play(context)) },\n      // @ts-expect-error (not defined)\n      { runStep: (label, play, context) => fn(`${label}3`, play(context)) },\n    ]);\n\n    // @ts-expect-error We don't care about the context value here\n    runStep('Label', () => {}, {});\n\n    expect(fn).toHaveBeenCalledTimes(3);\n    expect(fn).toHaveBeenNthCalledWith(1, 'Label3', expect.anything());\n    expect(fn).toHaveBeenNthCalledWith(2, 'Label2', expect.anything());\n    expect(fn).toHaveBeenNthCalledWith(3, 'Label1', expect.anything());\n  });\n\n  describe('FEATURES.legacyDecoratorFileOrder set to true', () => {\n    beforeEach(() => {\n      global.FEATURES!.legacyDecoratorFileOrder = true;\n    });\n\n    afterEach(() => {\n      global.FEATURES!.legacyDecoratorFileOrder = false;\n    });\n\n    it('should merge decorators in the order they are defined file-wise', () => {\n      expect(\n        composeConfigs([\n          {\n            decorators: ['1', '2'],\n          },\n          {\n            decorators: ['3', '4'],\n          },\n        ])\n      ).toMatchObject({\n        decorators: ['1', '2', '3', '4'],\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/composeConfigs.ts",
    "content": "import type { ModuleExports, NormalizedProjectAnnotations } from 'storybook/internal/types';\nimport type { Renderer } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { combineParameters } from '../parameters.ts';\nimport { composeBeforeAllHooks } from './beforeAll.ts';\nimport { normalizeArrays } from './normalizeArrays.ts';\nimport { composeStepRunners } from './stepRunners.ts';\n\nexport function getField<TFieldType = any>(\n  moduleExportList: ModuleExports[],\n  field: string\n): TFieldType | TFieldType[] {\n  return moduleExportList.map((xs) => xs.default?.[field] ?? xs[field]).filter(Boolean);\n}\n\nexport function getArrayField<TFieldType = any>(\n  moduleExportList: ModuleExports[],\n  field: string,\n  options: { reverseFileOrder?: boolean } = {}\n): TFieldType[] {\n  return getField(moduleExportList, field).reduce((prev: any, cur: any) => {\n    const normalized = normalizeArrays(cur);\n    return options.reverseFileOrder ? [...normalized, ...prev] : [...prev, ...normalized];\n  }, []);\n}\n\nexport function getObjectField<TFieldType = Record<string, any>>(\n  moduleExportList: ModuleExports[],\n  field: string\n): TFieldType {\n  return Object.assign({}, ...getField(moduleExportList, field));\n}\n\nexport function getSingletonField<TFieldType = any>(\n  moduleExportList: ModuleExports[],\n  field: string\n): TFieldType {\n  return getField(moduleExportList, field).pop();\n}\n\nexport function composeConfigs<TRenderer extends Renderer>(\n  moduleExportList: ModuleExports[]\n): NormalizedProjectAnnotations<TRenderer> {\n  const allArgTypeEnhancers = getArrayField(moduleExportList, 'argTypesEnhancers');\n  const stepRunners = getField(moduleExportList, 'runStep');\n  const beforeAllHooks = getArrayField(moduleExportList, 'beforeAll');\n\n  return {\n    parameters: combineParameters(...getField(moduleExportList, 'parameters')),\n    decorators: getArrayField(moduleExportList, 'decorators', {\n      reverseFileOrder: !(global.FEATURES?.legacyDecoratorFileOrder ?? false),\n    }),\n    args: getObjectField(moduleExportList, 'args'),\n    argsEnhancers: getArrayField(moduleExportList, 'argsEnhancers'),\n    argTypes: getObjectField(moduleExportList, 'argTypes'),\n    argTypesEnhancers: [\n      ...allArgTypeEnhancers.filter((e) => !e.secondPass),\n      ...allArgTypeEnhancers.filter((e) => e.secondPass),\n    ],\n    initialGlobals: getObjectField(moduleExportList, 'initialGlobals'),\n    globalTypes: getObjectField(moduleExportList, 'globalTypes'),\n    loaders: getArrayField(moduleExportList, 'loaders'),\n    beforeAll: composeBeforeAllHooks(beforeAllHooks),\n    beforeEach: getArrayField(moduleExportList, 'beforeEach'),\n    afterEach: getArrayField(moduleExportList, 'afterEach'),\n    render: getSingletonField(moduleExportList, 'render'),\n    renderToCanvas: getSingletonField(moduleExportList, 'renderToCanvas'),\n    applyDecorators: getSingletonField(moduleExportList, 'applyDecorators'),\n    runStep: composeStepRunners<TRenderer>(stepRunners),\n    tags: getArrayField(moduleExportList, 'tags'),\n    mount: getSingletonField(moduleExportList, 'mount'),\n    testingLibraryRender: getSingletonField(moduleExportList, 'testingLibraryRender'),\n  };\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/csf-factory-utils.ts",
    "content": "import { type Meta, type Story, isMeta, isStory } from 'storybook/internal/csf';\nimport type {\n  Args,\n  ComponentAnnotations,\n  LegacyStoryAnnotationsOrFn,\n  ProjectAnnotations,\n  Renderer,\n} from 'storybook/internal/types';\n\nexport function getCsfFactoryAnnotations<\n  TRenderer extends Renderer = Renderer,\n  TArgs extends Args = Args,\n>(\n  story: LegacyStoryAnnotationsOrFn<TRenderer> | Story<Renderer>,\n  meta?: ComponentAnnotations<TRenderer, TArgs> | Meta<Renderer>,\n  projectAnnotations?: ProjectAnnotations<TRenderer>\n) {\n  return isStory(story)\n    ? {\n        story: story.input,\n        meta: story.meta.input,\n        preview: story.meta.preview.composed,\n      }\n    : { story, meta: isMeta(meta) ? meta.input : meta, preview: projectAnnotations };\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/getValuesFromGlobalTypes.ts",
    "content": "import type { GlobalTypes, Globals } from 'storybook/internal/types';\n\nexport const getValuesFromGlobalTypes = (globalTypes: GlobalTypes = {}): Globals =>\n  Object.entries(globalTypes).reduce<Globals>((acc, [arg, { defaultValue }]) => {\n    if (typeof defaultValue !== 'undefined') {\n      acc[arg] = defaultValue;\n    }\n    return acc;\n  }, {});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/index.ts",
    "content": "export * from './normalizeInputTypes.ts';\nexport * from './normalizeStory.ts';\nexport * from './processCSFFile.ts';\nexport * from './prepareStory.ts';\nexport * from './normalizeComponentAnnotations.ts';\nexport * from './normalizeProjectAnnotations.ts';\nexport * from './normalizeArrays.ts';\nexport * from './getValuesFromGlobalTypes.ts';\nexport * from './composeConfigs.ts';\nexport * from './stepRunners.ts';\nexport * from './portable-stories.ts';\nexport * from './csf-factory-utils.ts';\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/normalizeArrays.ts",
    "content": "export const normalizeArrays = <T>(array: T[] | T | undefined): T[] => {\n  if (Array.isArray(array)) {\n    return array;\n  }\n  return array ? [array] : [];\n};\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/normalizeComponentAnnotations.ts",
    "content": "import { sanitize } from 'storybook/internal/csf';\nimport type { ModuleExports, NormalizedComponentAnnotations } from 'storybook/internal/types';\nimport type { Renderer } from 'storybook/internal/types';\n\nimport { normalizeInputTypes } from './normalizeInputTypes.ts';\n\nexport function normalizeComponentAnnotations<TRenderer extends Renderer>(\n  defaultExport: ModuleExports['default'],\n  title: string = defaultExport.title,\n  importPath?: string\n): NormalizedComponentAnnotations<TRenderer> {\n  const { id, argTypes } = defaultExport;\n  return {\n    id: sanitize(id || title),\n    ...defaultExport,\n    title,\n    ...(argTypes && { argTypes: normalizeInputTypes(argTypes) }),\n    parameters: {\n      fileName: importPath,\n      ...defaultExport.parameters,\n    },\n  };\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/normalizeInputTypes.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { normalizeInputType, normalizeInputTypes } from './normalizeInputTypes.ts';\n\ndescribe('normalizeInputType', () => {\n  it('normalizes strict types and sets disable: false when type is present', () => {\n    expect(\n      normalizeInputType(\n        {\n          name: 'name',\n          type: { name: 'string' },\n          control: { type: 'text' },\n          description: 'description',\n          defaultValue: 'defaultValue',\n        },\n        'arg'\n      )\n    ).toEqual({\n      name: 'name',\n      type: { name: 'string' },\n      control: { type: 'text', disable: false },\n      description: 'description',\n      defaultValue: 'defaultValue',\n    });\n  });\n\n  it('preserves strict types with explicit disable', () => {\n    expect(\n      normalizeInputType(\n        {\n          name: 'name',\n          type: { name: 'string' },\n          control: { type: 'text', disable: true },\n        },\n        'arg'\n      )\n    ).toEqual({\n      name: 'name',\n      type: { name: 'string' },\n      control: { type: 'text', disable: true },\n    });\n  });\n\n  it('fills in unstrict types', () => {\n    expect(\n      normalizeInputType(\n        {\n          type: 'string',\n          control: 'text',\n          description: 'description',\n          defaultValue: 'defaultValue',\n        },\n        'arg'\n      )\n    ).toEqual({\n      name: 'arg',\n      type: { name: 'string' },\n      control: { type: 'text', disable: false },\n      description: 'description',\n      defaultValue: 'defaultValue',\n    });\n  });\n\n  it('sets disable: false when control type is specified to override inherited disable', () => {\n    expect(\n      normalizeInputType(\n        {\n          control: { type: 'select' },\n        },\n        'arg'\n      )\n    ).toEqual({\n      name: 'arg',\n      control: { type: 'select', disable: false },\n    });\n  });\n\n  it('preserves explicit disable: true in control object', () => {\n    expect(\n      normalizeInputType(\n        {\n          control: { type: 'select', disable: true },\n        },\n        'arg'\n      )\n    ).toEqual({\n      name: 'arg',\n      control: { type: 'select', disable: true },\n    });\n  });\n\n  it('preserves disabled control via shortcut', () => {\n    expect(\n      normalizeInputType(\n        {\n          type: 'string',\n          control: false,\n          description: 'description',\n          defaultValue: 'defaultValue',\n        },\n        'arg'\n      )\n    ).toEqual({\n      name: 'arg',\n      type: { name: 'string' },\n      control: { disable: true },\n      description: 'description',\n      defaultValue: 'defaultValue',\n    });\n  });\n});\n\ndescribe('normalizeInputTypes', () => {\n  it('maps over keys', () => {\n    expect(\n      normalizeInputTypes({\n        a: { type: 'string' },\n        b: { type: 'number' },\n      })\n    ).toEqual({\n      a: { name: 'a', type: { name: 'string' } },\n      b: { name: 'b', type: { name: 'number' } },\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/normalizeInputTypes.ts",
    "content": "import type {\n  ArgTypes,\n  InputType,\n  StrictArgTypes,\n  StrictInputType,\n} from 'storybook/internal/types';\n\nimport { mapValues } from 'es-toolkit/object';\n\nconst normalizeType = (type: InputType['type']): StrictInputType['type'] => {\n  return typeof type === 'string' ? { name: type } : type;\n};\n\nconst normalizeControl = (control: InputType['control']): StrictInputType['control'] => {\n  if (typeof control === 'string') {\n    // When explicitly setting a control type, ensure disable is false to override\n    // any inherited disable: true from parent argTypes (fixes #27091)\n    return { type: control, disable: false };\n  }\n  // If control is an object with a type but no explicit disable, set disable: false\n  // to ensure it overrides any inherited disable: true\n  if (control && typeof control === 'object' && 'type' in control && !('disable' in control)) {\n    return { ...control, disable: false };\n  }\n  return control;\n};\n\nexport const normalizeInputType = (inputType: InputType, key: string): StrictInputType => {\n  const { type, control, ...rest } = inputType;\n  const normalized: StrictInputType = {\n    name: key,\n    ...rest,\n  };\n\n  if (type) {\n    normalized.type = normalizeType(type);\n  }\n  if (control) {\n    normalized.control = normalizeControl(control);\n  } else if (control === false) {\n    normalized.control = { disable: true };\n  }\n  return normalized;\n};\n\nexport const normalizeInputTypes = (inputTypes: ArgTypes): StrictArgTypes =>\n  mapValues(inputTypes, normalizeInputType);\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/normalizeProjectAnnotations.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { normalizeProjectAnnotations } from './normalizeProjectAnnotations.ts';\n\ndescribe('normalizeProjectAnnotations', () => {\n  it('passes through initialGlobals', () => {\n    expect(\n      normalizeProjectAnnotations({\n        initialGlobals: { a: 'b' },\n      })\n    ).toMatchObject({\n      initialGlobals: { a: 'b' },\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/normalizeProjectAnnotations.ts",
    "content": "import type {\n  ArgTypes,\n  NormalizedProjectAnnotations,\n  ProjectAnnotations,\n  Renderer,\n} from 'storybook/internal/types';\n\nimport { inferArgTypes } from '../inferArgTypes.ts';\nimport { inferControls } from '../inferControls.ts';\nimport { normalizeArrays } from './normalizeArrays.ts';\nimport { normalizeInputTypes } from './normalizeInputTypes.ts';\n\n// TODO(kasperpeulen) Consolidate this function with composeConfigs\n// As composeConfigs is the real normalizer, and always run before normalizeProjectAnnotations\n// tmeasday: Alternatively we could get rid of composeConfigs and just pass ProjectAnnotations[] around -- and do the composing here.\n// That makes sense to me as it avoids the need for both WP + Vite to call composeConfigs at the right time.\nexport function normalizeProjectAnnotations<TRenderer extends Renderer>({\n  argTypes,\n  argTypesEnhancers,\n  decorators,\n  loaders,\n  beforeEach,\n  afterEach,\n  initialGlobals,\n  ...annotations\n}: ProjectAnnotations<TRenderer>): NormalizedProjectAnnotations<TRenderer> {\n  return {\n    ...(argTypes && { argTypes: normalizeInputTypes(argTypes as ArgTypes) }),\n    decorators: normalizeArrays(decorators),\n    loaders: normalizeArrays(loaders),\n    beforeEach: normalizeArrays(beforeEach),\n    afterEach: normalizeArrays(afterEach),\n    argTypesEnhancers: [\n      ...(argTypesEnhancers || []),\n      inferArgTypes,\n      // There's an architectural decision to be made regarding embedded addons in core:\n      //\n      // Option 1: Keep embedded addons but ensure consistency by moving addon-specific code\n      // (like inferControls) to live alongside the addon code itself. This maintains the\n      // concept of core addons while improving code organization.\n      //\n      // Option 2: Fully integrate these addons into core, potentially moving UI components\n      // into the manager and treating them as core features rather than addons. This is a\n      // bigger architectural change requiring careful consideration.\n      //\n      // For now, we're keeping inferControls here as we need time to properly evaluate\n      // these options and their implications. Some features (like Angular's cleanArgsDecorator)\n      // currently rely on this behavior.\n      //\n      // TODO: Make an architectural decision on the handling of core addons\n      inferControls,\n    ],\n    initialGlobals,\n    ...(annotations as NormalizedProjectAnnotations<TRenderer>),\n  };\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/normalizeStory.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport type { Renderer, StoryAnnotationsOrFn } from 'storybook/internal/types';\n\nimport { normalizeStory } from './normalizeStory.ts';\n\nvi.mock('storybook/internal/client-logger');\n\ndescribe('normalizeStory', () => {\n  describe('id generation', () => {\n    it('respects component id', () => {\n      expect(normalizeStory('name', {}, { title: 'title', id: 'component-id' }).id).toEqual(\n        'component-id--name'\n      );\n    });\n\n    it('respects parameters.__id', () => {\n      expect(\n        normalizeStory(\n          'name',\n          { parameters: { __id: 'story-id' } },\n          { title: 'title', id: 'component-id' }\n        ).id\n      ).toEqual('story-id');\n    });\n  });\n\n  describe('name', () => {\n    it('preferences story.name over story.storyName', () => {\n      expect(\n        normalizeStory(\n          'export',\n          { name: 'name', storyName: 'storyName' },\n          { id: 'title', title: 'title' }\n        ).name\n      ).toEqual('name');\n      expect(\n        normalizeStory('export', { storyName: 'storyName' }, { id: 'title', title: 'title' }).name\n      ).toEqual('storyName');\n    });\n\n    it('falls back to capitalized export name', () => {\n      expect(normalizeStory('exportOne', {}, { id: 'title', title: 'title' }).name).toEqual(\n        'Export One'\n      );\n    });\n  });\n\n  describe('user-provided story function', () => {\n    it('should normalize into an object', () => {\n      const storyFn = () => {};\n      const meta = { id: 'title', title: 'title' };\n      expect(normalizeStory('storyExport', storyFn, meta)).toMatchInlineSnapshot(`\n        {\n          \"afterEach\": [],\n          \"argTypes\": {},\n          \"args\": {},\n          \"beforeEach\": [],\n          \"decorators\": [],\n          \"globals\": {},\n          \"id\": \"title--story-export\",\n          \"loaders\": [],\n          \"moduleExport\": [Function],\n          \"name\": \"Story Export\",\n          \"parameters\": {},\n          \"tags\": [],\n          \"userStoryFn\": [Function],\n        }\n      `);\n    });\n  });\n\n  describe('user-provided story object', () => {\n    describe('render function', () => {\n      it('implicit render function', () => {\n        const storyObj = {};\n        const meta = { id: 'title', title: 'title' };\n        const normalized = normalizeStory('storyExport', storyObj, meta);\n        expect(normalized.render).toBeUndefined();\n      });\n\n      it('user-provided story render function', () => {\n        const storyObj = { render: vi.fn() };\n        const meta = { id: 'title', title: 'title', render: vi.fn() };\n        const normalized = normalizeStory('storyExport', storyObj, meta);\n        expect(normalized.render).toBe(storyObj.render);\n      });\n\n      it('user-provided meta render function', () => {\n        const storyObj = {};\n        const meta = { id: 'title', title: 'title', render: vi.fn() };\n        const normalized = normalizeStory('storyExport', storyObj, meta);\n        expect(normalized.render).toBeUndefined();\n      });\n    });\n\n    describe('play function', () => {\n      it('no render function', () => {\n        const storyObj = {};\n        const meta = { id: 'title', title: 'title' };\n        const normalized = normalizeStory('storyExport', storyObj, meta);\n        expect(normalized.play).toBeUndefined();\n      });\n\n      it('user-provided story render function', () => {\n        const storyObj = { play: vi.fn() };\n        const meta = { id: 'title', title: 'title', play: vi.fn() };\n        const normalized = normalizeStory('storyExport', storyObj, meta);\n        expect(normalized.play).toBe(storyObj.play);\n      });\n\n      it('user-provided meta render function', () => {\n        const storyObj = {};\n        const meta = { id: 'title', title: 'title', play: vi.fn() };\n        const normalized = normalizeStory('storyExport', storyObj, meta);\n        expect(normalized.play).toBeUndefined();\n      });\n    });\n\n    describe('annotations', () => {\n      it('empty annotations', () => {\n        const storyObj = {};\n        const meta = { id: 'title', title: 'title' };\n        const normalized = normalizeStory('storyExport', storyObj, meta);\n        expect(normalized).toMatchInlineSnapshot(`\n          {\n            \"afterEach\": [],\n            \"argTypes\": {},\n            \"args\": {},\n            \"beforeEach\": [],\n            \"decorators\": [],\n            \"globals\": {},\n            \"id\": \"title--story-export\",\n            \"loaders\": [],\n            \"moduleExport\": {},\n            \"name\": \"Story Export\",\n            \"parameters\": {},\n            \"tags\": [],\n          }\n        `);\n        expect(normalized.moduleExport).toBe(storyObj);\n      });\n\n      it('full annotations', () => {\n        const storyObj: StoryAnnotationsOrFn<Renderer> = {\n          name: 'story name',\n          parameters: { storyParam: 'val' },\n          decorators: [() => {}],\n          loaders: [async () => ({})],\n          args: { storyArg: 'val' },\n          argTypes: { storyArgType: { type: 'string' } },\n        };\n        const meta = { id: 'title', title: 'title' };\n        const { moduleExport, ...normalized } = normalizeStory('storyExport', storyObj, meta);\n        expect(normalized).toMatchInlineSnapshot(`\n          {\n            \"afterEach\": [],\n            \"argTypes\": {\n              \"storyArgType\": {\n                \"name\": \"storyArgType\",\n                \"type\": {\n                  \"name\": \"string\",\n                },\n              },\n            },\n            \"args\": {\n              \"storyArg\": \"val\",\n            },\n            \"beforeEach\": [],\n            \"decorators\": [\n              [Function],\n            ],\n            \"globals\": {},\n            \"id\": \"title--story-export\",\n            \"loaders\": [\n              [Function],\n            ],\n            \"name\": \"story name\",\n            \"parameters\": {\n              \"storyParam\": \"val\",\n            },\n            \"tags\": [],\n          }\n        `);\n        expect(moduleExport).toBe(storyObj);\n      });\n\n      it('prefers new annotations to legacy, but combines', () => {\n        const storyObj: StoryAnnotationsOrFn<Renderer> = {\n          name: 'story name',\n          parameters: { storyParam: 'val' },\n          decorators: [() => {}],\n          loaders: [async () => ({})],\n          args: { storyArg: 'val' },\n          argTypes: { storyArgType: { type: 'string' } },\n          story: {\n            parameters: { storyParam2: 'legacy' },\n            decorators: [() => {}],\n            loaders: [async () => ({})],\n            args: { storyArg2: 'legacy' },\n            argTypes: { storyArgType2: { type: 'string' } },\n          },\n        };\n        const meta = { id: 'title', title: 'title' };\n        const { moduleExport, ...normalized } = normalizeStory('storyExport', storyObj, meta);\n        expect(normalized).toMatchInlineSnapshot(`\n          {\n            \"afterEach\": [],\n            \"argTypes\": {\n              \"storyArgType\": {\n                \"name\": \"storyArgType\",\n                \"type\": {\n                  \"name\": \"string\",\n                },\n              },\n              \"storyArgType2\": {\n                \"name\": \"storyArgType2\",\n                \"type\": {\n                  \"name\": \"string\",\n                },\n              },\n            },\n            \"args\": {\n              \"storyArg\": \"val\",\n              \"storyArg2\": \"legacy\",\n            },\n            \"beforeEach\": [],\n            \"decorators\": [\n              [Function],\n              [Function],\n            ],\n            \"globals\": {},\n            \"id\": \"title--story-export\",\n            \"loaders\": [\n              [Function],\n              [Function],\n            ],\n            \"name\": \"story name\",\n            \"parameters\": {\n              \"storyParam\": \"val\",\n              \"storyParam2\": \"legacy\",\n            },\n            \"tags\": [],\n          }\n        `);\n        expect(moduleExport).toBe(storyObj);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/normalizeStory.ts",
    "content": "import { deprecate, logger } from 'storybook/internal/client-logger';\nimport { storyNameFromExport, toId } from 'storybook/internal/csf';\nimport type {\n  ArgTypes,\n  ArgsStoryFn,\n  NormalizedComponentAnnotations,\n  NormalizedStoryAnnotations,\n  Renderer,\n  StoryAnnotationsOrFn,\n  StoryId,\n} from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\n\nimport { normalizeArrays } from './normalizeArrays.ts';\nimport { normalizeInputTypes } from './normalizeInputTypes.ts';\n\nconst deprecatedStoryAnnotation = dedent`\nCSF .story annotations deprecated; annotate story functions directly:\n- StoryFn.story.name => StoryFn.storyName\n- StoryFn.story.(parameters|decorators) => StoryFn.(parameters|decorators)\nSee https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#hoisted-csf-annotations for details and codemod.\n`;\n\nexport function normalizeStory<TRenderer extends Renderer>(\n  key: StoryId,\n  storyAnnotations: StoryAnnotationsOrFn<TRenderer>,\n  meta: NormalizedComponentAnnotations<TRenderer>\n): NormalizedStoryAnnotations<TRenderer> {\n  const storyObject = storyAnnotations;\n  const userStoryFn: ArgsStoryFn<TRenderer> | null =\n    typeof storyAnnotations === 'function' ? storyAnnotations : null;\n\n  const { story } = storyObject;\n  if (story) {\n    logger.debug('deprecated story', story);\n    deprecate(deprecatedStoryAnnotation);\n  }\n\n  const exportName = storyNameFromExport(key);\n  const name =\n    (typeof storyObject !== 'function' && storyObject.name) ||\n    storyObject.storyName ||\n    story?.name ||\n    exportName;\n\n  const decorators = [\n    ...normalizeArrays(storyObject.decorators),\n    ...normalizeArrays(story?.decorators),\n  ];\n  const parameters = { ...story?.parameters, ...storyObject.parameters };\n  const args = { ...story?.args, ...storyObject.args };\n  const argTypes = { ...(story?.argTypes as ArgTypes), ...(storyObject.argTypes as ArgTypes) };\n  const loaders = [...normalizeArrays(storyObject.loaders), ...normalizeArrays(story?.loaders)];\n  const beforeEach = [\n    ...normalizeArrays(storyObject.beforeEach),\n    ...normalizeArrays(story?.beforeEach),\n  ];\n\n  const afterEach = [\n    ...normalizeArrays(storyObject.afterEach),\n    ...normalizeArrays(story?.afterEach),\n  ];\n  const { render, play, tags = [], globals = {} } = storyObject;\n\n  const id = parameters.__id || toId(meta.id, exportName);\n  return {\n    moduleExport: storyAnnotations,\n    id,\n    name,\n    tags,\n    decorators,\n    parameters,\n    args,\n    argTypes: normalizeInputTypes(argTypes),\n    loaders,\n    beforeEach,\n    afterEach,\n    globals,\n    ...(render && { render }),\n    ...(userStoryFn && { userStoryFn }),\n    ...(play && { play }),\n  };\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/portable-stories.test.ts",
    "content": "// @vitest-environment node\nimport { describe, expect, it, vi } from 'vitest';\n\nimport type { ProjectAnnotations } from 'storybook/internal/csf';\nimport type {\n  ComponentAnnotations as Meta,\n  Store_CSFExports,\n  StoryAnnotationsOrFn as Story,\n} from 'storybook/internal/types';\n\nimport { Tag } from '../../../../shared/constants/tags.ts';\nimport * as defaultExportAnnotations from './__mocks__/defaultExportAnnotations.mockfile.ts';\nimport * as namedExportAnnotations from './__mocks__/namedExportAnnotations.mockfile.ts';\nimport { composeStories, composeStory, setProjectAnnotations } from './portable-stories.ts';\n\ntype StoriesModule = Store_CSFExports & Record<string, any>;\n\n// Most integration tests for this functionality are located under renderers/react\ndescribe('composeStory', () => {\n  const meta: Meta = {\n    title: 'Button',\n    parameters: {\n      firstAddon: true,\n    },\n    args: {\n      label: 'Hello World',\n      primary: true,\n    },\n    tags: ['metaTag'],\n  };\n\n  it('should return composed beforeAll as part of project annotations', async () => {\n    const after = vi.fn();\n    const before = vi.fn((n) => () => after(n));\n    const finalAnnotations = setProjectAnnotations([\n      { beforeAll: () => before(1) },\n      { beforeAll: () => before(2) },\n      { beforeAll: () => before(3) },\n    ]);\n\n    const cleanup = await finalAnnotations.beforeAll?.();\n    expect(before.mock.calls).toEqual([[1], [2], [3]]);\n\n    await cleanup?.();\n    expect(after.mock.calls).toEqual([[3], [2], [1]]);\n  });\n\n  it('should return composed project annotations via setProjectAnnotations', () => {\n    const firstAnnotations = {\n      parameters: { foo: 'bar' },\n      tags: [Tag.AUTODOCS],\n    };\n\n    const secondAnnotations = {\n      args: {\n        foo: 'bar',\n      },\n    };\n    const finalAnnotations = setProjectAnnotations([firstAnnotations, secondAnnotations]);\n    expect(finalAnnotations).toEqual(\n      expect.objectContaining({\n        parameters: expect.objectContaining({ foo: 'bar' }),\n        args: { foo: 'bar' },\n        tags: [Tag.AUTODOCS],\n      })\n    );\n  });\n\n  it('should compose project annotations in all module formats', () => {\n    setProjectAnnotations([defaultExportAnnotations, namedExportAnnotations]);\n\n    const Story: Story = {\n      render: () => {},\n    };\n\n    const composedStory = composeStory(Story, meta);\n    expect(composedStory.parameters.fromAnnotations.asObjectImport).toEqual(true);\n    expect(composedStory.parameters.fromAnnotations.asDefaultImport).toEqual(true);\n  });\n\n  it('should compose project annotations when used in named and default exports from the same module', () => {\n    setProjectAnnotations([\n      {\n        initialGlobals: { namedExportAnnotation: true },\n        default: {\n          parameters: { defaultExportAnnotation: true },\n        },\n      },\n    ]);\n\n    const Story: Story = {\n      render: () => {},\n    };\n\n    const composedStory = composeStory(Story, meta);\n    expect(composedStory.parameters.defaultExportAnnotation).toEqual(true);\n    expect(composedStory.globals.namedExportAnnotation).toEqual(true);\n  });\n\n  it('should return story with composed annotations from story, meta and project', () => {\n    const decoratorFromProjectAnnotations = vi.fn((StoryFn) => StoryFn());\n    const decoratorFromStoryAnnotations = vi.fn((StoryFn) => StoryFn());\n    const projectAnnotations = {\n      parameters: { injected: true },\n      globalTypes: {\n        locale: { defaultValue: 'en' },\n      },\n      decorators: [decoratorFromProjectAnnotations],\n      tags: ['projectTag'],\n    };\n\n    setProjectAnnotations(projectAnnotations);\n\n    const Story: Story = {\n      render: () => {},\n      args: { primary: true },\n      parameters: {\n        secondAddon: true,\n      },\n      decorators: [decoratorFromStoryAnnotations],\n      tags: ['storyTag'],\n    };\n\n    const composedStory = composeStory(Story, meta);\n    expect(composedStory.args).toEqual({ ...Story.args, ...meta.args });\n    expect(composedStory.parameters).toEqual(\n      expect.objectContaining({ ...Story.parameters, ...meta.parameters })\n    );\n    expect(composedStory.tags).toEqual([Tag.DEV, Tag.TEST, 'projectTag', 'metaTag', 'storyTag']);\n\n    composedStory();\n\n    expect(decoratorFromProjectAnnotations).toHaveBeenCalledOnce();\n    expect(decoratorFromStoryAnnotations).toHaveBeenCalledOnce();\n  });\n\n  it('should compose with a play function', async () => {\n    const spy = vi.fn();\n    const Story: Story = () => {};\n    Story.args = {\n      primary: true,\n    };\n    Story.play = async (context: any) => {\n      spy(context);\n    };\n\n    const composedStory = composeStory(Story, meta, {\n      mount: (context) => async () => {\n        return context.canvas;\n      },\n    });\n    await composedStory.play?.({ canvasElement: null });\n    expect(spy).toHaveBeenCalledWith(\n      expect.objectContaining({\n        args: {\n          ...Story.args,\n          ...meta.args,\n        },\n      })\n    );\n  });\n\n  it('should merge parameters with correct precedence in all combinations', async () => {\n    const storyAnnotations = { render: () => {} };\n    const metaAnnotations: Meta = { parameters: { label: 'meta' } };\n    const projectAnnotations: Meta = { parameters: { label: 'projectOverrides' } };\n\n    const storyPrecedence = composeStory(\n      { ...storyAnnotations, parameters: { label: 'story' } },\n      metaAnnotations,\n      projectAnnotations\n    );\n    expect(storyPrecedence.parameters.label).toEqual('story');\n\n    const metaPrecedence = composeStory(storyAnnotations, metaAnnotations, projectAnnotations);\n    expect(metaPrecedence.parameters.label).toEqual('meta');\n\n    const projectPrecedence = composeStory(storyAnnotations, {}, projectAnnotations);\n    expect(projectPrecedence.parameters.label).toEqual('projectOverrides');\n\n    setProjectAnnotations({ parameters: { label: 'setProjectAnnotationsOverrides' } });\n    const setProjectAnnotationsPrecedence = composeStory(storyAnnotations, {}, {});\n    expect(setProjectAnnotationsPrecedence.parameters.label).toEqual(\n      'setProjectAnnotationsOverrides'\n    );\n  });\n\n  it('should merge globals with correct precedence in all combinations', async () => {\n    const renderSpy = vi.fn();\n    const storyAnnotations = { render: renderSpy };\n    const metaAnnotations: Meta = { globals: { language: 'de' } };\n    const projectAnnotations: ProjectAnnotations = { initialGlobals: { language: 'nl' } };\n\n    const storyPrecedence = composeStory(\n      { ...storyAnnotations, globals: { language: 'pt' } },\n      metaAnnotations,\n      projectAnnotations\n    );\n    storyPrecedence();\n    expect(renderSpy.mock.calls[0][1]).toEqual(\n      expect.objectContaining({ globals: expect.objectContaining({ language: 'pt' }) })\n    );\n\n    renderSpy.mockClear();\n\n    const metaPrecedence = composeStory(storyAnnotations, metaAnnotations, projectAnnotations);\n    metaPrecedence();\n    expect(renderSpy.mock.calls[0][1]).toEqual(\n      expect.objectContaining({ globals: expect.objectContaining({ language: 'de' }) })\n    );\n\n    renderSpy.mockClear();\n\n    const projectPrecedence = composeStory(storyAnnotations, {}, projectAnnotations);\n    projectPrecedence();\n    expect(renderSpy.mock.calls[0][1]).toEqual(\n      expect.objectContaining({ globals: expect.objectContaining({ language: 'nl' }) })\n    );\n\n    renderSpy.mockClear();\n\n    setProjectAnnotations({ initialGlobals: { language: 'be' } });\n    const setProjectAnnotationsPrecedence = composeStory(storyAnnotations, {}, {});\n    setProjectAnnotationsPrecedence();\n    expect(renderSpy.mock.calls[0][1]).toEqual(\n      expect.objectContaining({ globals: expect.objectContaining({ language: 'be' }) })\n    );\n  });\n\n  it('should provide globals based on globalTypes', async () => {\n    const storyAnnotations = { render: () => {} };\n    const metaAnnotations: Meta = { globals: { language: 'de' } };\n    const projectAnnotations: ProjectAnnotations = {\n      initialGlobals: { language: 'nl' },\n      globalTypes: {\n        theme: {\n          name: 'Theme',\n          defaultValue: 'light',\n        },\n      },\n    };\n\n    const composed = composeStory(storyAnnotations, metaAnnotations, projectAnnotations);\n    expect(composed.globals.theme).toEqual('light');\n  });\n\n  it('should call and compose loaders data', async () => {\n    const loadSpy = vi.fn();\n    const args = { story: 'story' };\n    const LoaderStory: Story = {\n      args,\n      loaders: [\n        async (context) => {\n          loadSpy();\n          expect(context.args).toEqual(args);\n          return {\n            foo: 'bar',\n          };\n        },\n      ],\n      render: (_args, { loaded }) => {\n        expect(loaded).toEqual({ foo: 'bar' });\n      },\n    };\n\n    const composedStory = composeStory(LoaderStory, {});\n    await composedStory.load();\n    composedStory();\n    expect(loadSpy).toHaveBeenCalled();\n  });\n\n  it('should work with spies set up in loaders', async () => {\n    const spyFn = vi.fn();\n\n    const Story: Story = {\n      args: {\n        spyFn,\n      },\n      loaders: [\n        async () => {\n          spyFn.mockReturnValue('mockedData');\n        },\n      ],\n      render: (args) => {\n        const data = args.spyFn();\n        expect(data).toBe('mockedData');\n      },\n    };\n\n    const composedStory = composeStory(Story, {});\n    await composedStory.load();\n    composedStory();\n    expect(spyFn).toHaveBeenCalled();\n  });\n\n  it('should work with spies set up in beforeEach', async () => {\n    const spyFn = vi.fn();\n\n    const Story: Story = {\n      args: {\n        spyFn,\n      },\n      beforeEach: async () => {\n        spyFn.mockReturnValue('mockedData');\n      },\n      render: (args) => {\n        const data = args.spyFn();\n        expect(data).toBe('mockedData');\n      },\n    };\n\n    const composedStory = composeStory(Story, {});\n    await composedStory.load();\n    composedStory();\n    expect(spyFn).toHaveBeenCalled();\n  });\n\n  it('should call beforeEach from Project, Meta and Story level', async () => {\n    const beforeEachSpy = vi.fn();\n    const cleanupSpy = vi.fn();\n\n    const metaObj: Meta = {\n      beforeEach: async () => {\n        beforeEachSpy('define from meta');\n\n        return () => {\n          cleanupSpy('cleanup from meta');\n        };\n      },\n    };\n\n    const Story: Story = {\n      render: () => 'foo',\n      beforeEach: async () => {\n        beforeEachSpy('define from story');\n\n        return () => {\n          cleanupSpy('cleanup from story');\n        };\n      },\n    };\n\n    const composedStory = composeStory(Story, metaObj, {\n      beforeEach: async () => {\n        beforeEachSpy('define from project');\n\n        return () => {\n          cleanupSpy('cleanup from project');\n        };\n      },\n    });\n    await composedStory.load();\n    composedStory();\n    expect(beforeEachSpy).toHaveBeenNthCalledWith(1, 'define from project');\n    expect(beforeEachSpy).toHaveBeenNthCalledWith(2, 'define from meta');\n    expect(beforeEachSpy).toHaveBeenNthCalledWith(3, 'define from story');\n\n    // simulate the next story's load to trigger cleanup\n    await composedStory.load();\n    expect(cleanupSpy).toHaveBeenNthCalledWith(1, 'cleanup from story');\n    expect(cleanupSpy).toHaveBeenNthCalledWith(2, 'cleanup from meta');\n    expect(cleanupSpy).toHaveBeenNthCalledWith(3, 'cleanup from project');\n  });\n\n  it('should call beforeEach after loaders', async () => {\n    const spyFn = vi.fn();\n\n    const Story: Story = {\n      render: () => 'foo',\n      loaders: async () => {\n        spyFn('from loaders');\n      },\n      beforeEach: async () => {\n        spyFn('from beforeEach');\n      },\n    };\n\n    const composedStory = composeStory(Story, {});\n    await composedStory.load();\n    expect(spyFn).toHaveBeenNthCalledWith(1, 'from loaders');\n    expect(spyFn).toHaveBeenNthCalledWith(2, 'from beforeEach');\n  });\n\n  it('should throw an error if Story is undefined', () => {\n    expect(() => {\n      // @ts-expect-error (invalid input)\n      composeStory(undefined, meta);\n    }).toThrow();\n  });\n\n  describe('Id of the story', () => {\n    it('is exposed correctly when composeStories is used', () => {\n      const module: StoriesModule = {\n        default: {\n          title: 'Example/Button',\n        },\n        CSF3Primary: () => {},\n      };\n      const Primary = composeStory(module.CSF3Primary, module.default, {});\n      expect(Primary.id).toBe('example-button--csf-3-primary');\n    });\n    it('is exposed correctly when composeStory is used and exportsName is passed', () => {\n      const module: StoriesModule = {\n        default: {\n          title: 'Example/Button',\n        },\n        CSF3Primary: () => {},\n      };\n      const Primary = composeStory(module.CSF3Primary, module.default, {}, {}, 'overwritten');\n      expect(Primary.id).toBe('example-button--overwritten');\n    });\n    it(\"is not unique when composeStory is used and exportsName isn't passed\", () => {\n      const Primary = composeStory({ render: () => {} }, {});\n      expect(Primary.id).toContain('composedstory--unnamed-story');\n    });\n  });\n});\n\ndescribe('composeStories', () => {\n  const composeStoryFn = vi.fn((v) => v);\n  const defaultAnnotations = { render: () => '' };\n  it('should call composeStoryFn with stories', () => {\n    const composeStorySpy = vi.fn((v) => v);\n    const module: StoriesModule = {\n      default: {\n        title: 'Button',\n      },\n      StoryOne: () => {},\n      StoryTwo: () => {},\n    };\n    const globalConfig = {};\n    composeStories(module, globalConfig, composeStorySpy);\n    expect(composeStorySpy).toHaveBeenCalledWith(\n      module.StoryOne,\n      module.default,\n      globalConfig,\n      'StoryOne'\n    );\n    expect(composeStorySpy).toHaveBeenCalledWith(\n      module.StoryTwo,\n      module.default,\n      globalConfig,\n      'StoryTwo'\n    );\n  });\n\n  it('should not call composeStoryFn for non-story exports', () => {\n    const composeStorySpy = vi.fn((v) => v);\n    const module: StoriesModule = {\n      default: {\n        title: 'Button',\n        excludeStories: /Data/,\n      },\n      mockData: {},\n    };\n    composeStories(module, defaultAnnotations, composeStoryFn);\n    expect(composeStorySpy).not.toHaveBeenCalled();\n  });\n\n  describe('non-story exports', () => {\n    it('should filter non-story exports with excludeStories', () => {\n      const StoryModuleWithNonStoryExports: StoriesModule = {\n        default: {\n          title: 'Some/Component',\n          excludeStories: /.*Data/,\n        },\n        LegitimateStory: () => 'hello world',\n        mockData: {},\n      };\n\n      const result = composeStories(\n        StoryModuleWithNonStoryExports,\n        defaultAnnotations,\n        composeStoryFn\n      );\n      expect(Object.keys(result)).not.toContain('mockData');\n    });\n\n    it('should filter non-story exports with includeStories', () => {\n      const StoryModuleWithNonStoryExports: StoriesModule = {\n        default: {\n          title: 'Some/Component',\n          includeStories: /.*Story/,\n        },\n        LegitimateStory: () => 'hello world',\n        mockData: {},\n      };\n\n      const result = composeStories(\n        StoryModuleWithNonStoryExports,\n        defaultAnnotations,\n        composeStoryFn\n      );\n      expect(Object.keys(result)).not.toContain('mockData');\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/portable-stories.ts",
    "content": "import { type CleanupCallback, isExportStory } from 'storybook/internal/csf';\nimport { getCoreAnnotations } from 'storybook/internal/csf';\nimport { MountMustBeDestructuredError } from 'storybook/internal/preview-errors';\nimport type {\n  Args,\n  Canvas,\n  ComponentAnnotations,\n  ComposeStoryFn,\n  ComposedStoryFn,\n  LegacyStoryAnnotationsOrFn,\n  NamedOrDefaultProjectAnnotations,\n  NormalizedProjectAnnotations,\n  Parameters,\n  PreparedStory,\n  ProjectAnnotations,\n  RenderContext,\n  Renderer,\n  Store_CSFExports,\n  StoryContext,\n  StrictArgTypes,\n} from 'storybook/internal/types';\n\nimport type { UserEventObject } from 'storybook/test';\nimport { dedent } from 'ts-dedent';\n\nimport { HooksContext } from '../../../addons.ts';\nimport {\n  isTestEnvironment,\n  pauseAnimations,\n  waitForAnimations,\n} from '../../preview-web/render/animation-utils.ts';\nimport { ReporterAPI } from '../reporter-api.ts';\nimport { composeConfigs } from './composeConfigs.ts';\nimport { getCsfFactoryAnnotations } from './csf-factory-utils.ts';\nimport { getValuesFromGlobalTypes } from './getValuesFromGlobalTypes.ts';\nimport { normalizeComponentAnnotations } from './normalizeComponentAnnotations.ts';\nimport { normalizeProjectAnnotations } from './normalizeProjectAnnotations.ts';\nimport { normalizeStory } from './normalizeStory.ts';\nimport { prepareContext, prepareStory } from './prepareStory.ts';\n\n// TODO we should get to the bottom of the singleton issues caused by dual ESM/CJS modules\ndeclare global {\n  // eslint-disable-next-line no-var\n  var globalProjectAnnotations: NormalizedProjectAnnotations<any>;\n  // eslint-disable-next-line no-var\n  var defaultProjectAnnotations: ProjectAnnotations<any>;\n}\n\nexport function setDefaultProjectAnnotations<TRenderer extends Renderer = Renderer>(\n  _defaultProjectAnnotations: ProjectAnnotations<TRenderer>\n) {\n  // Use a variable once we figure out the ESM/CJS issues\n  globalThis.defaultProjectAnnotations = _defaultProjectAnnotations;\n}\n\nconst DEFAULT_STORY_TITLE = 'ComposedStory';\nconst DEFAULT_STORY_NAME = 'Unnamed Story';\n\nfunction extractAnnotation<TRenderer extends Renderer = Renderer>(\n  annotation: NamedOrDefaultProjectAnnotations<TRenderer>\n) {\n  if (!annotation) {\n    return {};\n  }\n  // support imports such as\n  // import * as annotations from '.storybook/preview'\n  // import annotations from '.storybook/preview'\n  // in both cases: 1 - the file has a default export; 2 - named exports only\n  // also support when the file has both annotations coming from default and named exports\n  return composeConfigs([annotation]);\n}\n\nexport function setProjectAnnotations<TRenderer extends Renderer = Renderer>(\n  projectAnnotations:\n    | NamedOrDefaultProjectAnnotations<TRenderer>\n    | NamedOrDefaultProjectAnnotations<TRenderer>[]\n): NormalizedProjectAnnotations<TRenderer> {\n  const annotations = Array.isArray(projectAnnotations) ? projectAnnotations : [projectAnnotations];\n  globalThis.globalProjectAnnotations = composeConfigs([\n    ...getCoreAnnotations(),\n    globalThis.defaultProjectAnnotations ?? {},\n    composeConfigs(annotations.map(extractAnnotation)),\n  ]);\n\n  return globalThis.globalProjectAnnotations ?? {};\n}\n\nconst cleanups: CleanupCallback[] = [];\n\nexport function composeStory<TRenderer extends Renderer = Renderer, TArgs extends Args = Args>(\n  storyAnnotations: LegacyStoryAnnotationsOrFn<TRenderer>,\n  componentAnnotations: ComponentAnnotations<TRenderer, TArgs>,\n  projectAnnotations?: ProjectAnnotations<TRenderer>,\n  defaultConfig?: ProjectAnnotations<TRenderer>,\n  exportsName?: string\n): ComposedStoryFn<TRenderer, Partial<TArgs>> {\n  if (storyAnnotations === undefined) {\n    // eslint-disable-next-line local-rules/no-uncategorized-errors\n    throw new Error('Expected a story but received undefined.');\n  }\n\n  // @TODO: Support auto title\n\n  componentAnnotations.title = componentAnnotations.title ?? DEFAULT_STORY_TITLE;\n  const normalizedComponentAnnotations =\n    normalizeComponentAnnotations<TRenderer>(componentAnnotations);\n\n  const storyName =\n    exportsName ||\n    storyAnnotations.storyName ||\n    storyAnnotations.story?.name ||\n    storyAnnotations.name ||\n    DEFAULT_STORY_NAME;\n\n  const normalizedStory = normalizeStory<TRenderer>(\n    storyName,\n    storyAnnotations,\n    normalizedComponentAnnotations\n  );\n\n  const normalizedProjectAnnotations = normalizeProjectAnnotations<TRenderer>(\n    composeConfigs([\n      defaultConfig ?? globalThis.globalProjectAnnotations ?? {},\n      projectAnnotations ?? {},\n    ])\n  );\n\n  const story = prepareStory<TRenderer>(\n    normalizedStory,\n    normalizedComponentAnnotations,\n    normalizedProjectAnnotations\n  );\n\n  const globalsFromGlobalTypes = getValuesFromGlobalTypes(normalizedProjectAnnotations.globalTypes);\n\n  const globals = {\n    ...globalsFromGlobalTypes,\n    ...normalizedProjectAnnotations.initialGlobals,\n    ...story.storyGlobals,\n  };\n\n  const reporting = new ReporterAPI();\n\n  const initializeContext = () => {\n    const context: StoryContext<TRenderer> = prepareContext({\n      hooks: new HooksContext(),\n      globals,\n      args: { ...story.initialArgs },\n      viewMode: 'story',\n      reporting,\n      loaded: {},\n      abortSignal: new AbortController().signal,\n      step: (label, play) => story.runStep(label, play, context),\n      canvasElement: null!,\n      canvas: {} as Canvas,\n      userEvent: {} as UserEventObject,\n      globalTypes: normalizedProjectAnnotations.globalTypes,\n      ...story,\n      context: null!,\n      mount: null!,\n    });\n\n    context.parameters.__isPortableStory = true;\n\n    context.context = context;\n\n    if (story.renderToCanvas) {\n      context.renderToCanvas = async () => {\n        // TODO: Consolidate this renderContext with Context in SB 10.0\n        // Change renderToCanvas function to only use the context object\n        // and to make the renderContext an internal implementation detail\n        // wasn't possible so far because showError and showException are not part of the story context (yet)\n        const unmount = await story.renderToCanvas?.(\n          {\n            componentId: story.componentId,\n            title: story.title,\n            id: story.id,\n            name: story.name,\n            tags: story.tags,\n            showMain: () => {},\n            showError: (error): void => {\n              throw new Error(`${error.title}\\n${error.description}`);\n            },\n            showException: (error): void => {\n              throw error;\n            },\n            forceRemount: true,\n            storyContext: context,\n            storyFn: () => story.unboundStoryFn(context),\n            unboundStoryFn: story.unboundStoryFn,\n          } as RenderContext<TRenderer>,\n          context.canvasElement\n        );\n        if (unmount) {\n          cleanups.push(unmount);\n        }\n      };\n    }\n\n    context.mount = story.mount(context);\n\n    return context;\n  };\n\n  let loadedContext: StoryContext<TRenderer> | undefined;\n\n  const play = async (extraContext?: Partial<StoryContext<TRenderer, Partial<TArgs>>>) => {\n    const context = initializeContext();\n    context.canvasElement ??= globalThis?.document?.body;\n    if (loadedContext) {\n      context.loaded = loadedContext.loaded;\n    }\n    Object.assign(context, extraContext);\n    return story.playFunction!(context);\n  };\n\n  const run = (extraContext?: Partial<StoryContext<TRenderer, Partial<TArgs>>>) => {\n    const context = initializeContext();\n    Object.assign(context, extraContext);\n    return runStory(story, context);\n  };\n\n  const playFunction = story.playFunction ? play : undefined;\n\n  const composedStory: ComposedStoryFn<TRenderer, Partial<TArgs>> = Object.assign(\n    function storyFn(extraArgs?: Partial<TArgs>) {\n      const context = initializeContext();\n      if (loadedContext) {\n        context.loaded = loadedContext.loaded;\n      }\n      context.args = {\n        ...context.initialArgs,\n        ...extraArgs,\n      };\n      return story.unboundStoryFn(context);\n    },\n    {\n      id: story.id,\n      storyName,\n      load: async () => {\n        // First run any registered cleanup function\n\n        // First run any registered cleanup function\n        for (const callback of [...cleanups].reverse()) {\n          await callback();\n        }\n        cleanups.length = 0;\n\n        const context = initializeContext();\n\n        context.loaded = await story.applyLoaders(context);\n\n        cleanups.push(...(await story.applyBeforeEach(context)).filter(Boolean));\n\n        loadedContext = context;\n      },\n      globals,\n      args: story.initialArgs as Partial<TArgs>,\n      parameters: story.parameters as Parameters,\n      argTypes: story.argTypes as StrictArgTypes<TArgs>,\n      play: playFunction!,\n      run,\n      reporting,\n      tags: story.tags,\n    }\n  );\n\n  return composedStory;\n}\n\nconst defaultComposeStory: ComposeStoryFn = (story, component, project, exportsName) =>\n  composeStory(story, component, project, {}, exportsName);\n\nexport function composeStories<TModule extends Store_CSFExports>(\n  storiesImport: TModule,\n  globalConfig: ProjectAnnotations<Renderer>,\n  composeStoryFn: ComposeStoryFn = defaultComposeStory\n) {\n  const { default: metaExport, __esModule, __namedExportsOrder, ...stories } = storiesImport;\n  let meta = metaExport;\n\n  const composedStories = Object.entries(stories).reduce(\n    (storiesMap, [exportsName, story]: [string, any]) => {\n      const { story: storyAnnotations, meta: componentAnnotations } =\n        getCsfFactoryAnnotations(story);\n      if (!meta && componentAnnotations) {\n        meta = componentAnnotations;\n      }\n\n      if (!isExportStory(exportsName, meta)) {\n        return storiesMap;\n      }\n      const result = Object.assign(storiesMap, {\n        [exportsName]: composeStoryFn(storyAnnotations, meta, globalConfig, exportsName),\n      });\n      return result;\n    },\n    {}\n  );\n\n  return composedStories;\n}\n\ntype WrappedStoryRef =\n  | { __pw_type: 'jsx'; props: Record<string, any> }\n  | { __pw_type: 'importRef' };\ntype UnwrappedJSXStoryRef = {\n  __pw_type: 'jsx';\n  type: UnwrappedImportStoryRef;\n};\ntype UnwrappedImportStoryRef = ComposedStoryFn;\n\ndeclare global {\n  function __pwUnwrapObject(\n    storyRef: WrappedStoryRef\n  ): Promise<UnwrappedJSXStoryRef | UnwrappedImportStoryRef>;\n}\n\nexport function createPlaywrightTest<TFixture extends { extend: any }>(\n  baseTest: TFixture\n): TFixture {\n  return baseTest.extend({\n    mount: async ({ mount, page }: any, use: any) => {\n      await use(async (storyRef: WrappedStoryRef, ...restArgs: any) => {\n        // Playwright CT deals with JSX import references differently than normal imports\n        // and we can currently only handle JSX import references\n        if (\n          !('__pw_type' in storyRef) ||\n          ('__pw_type' in storyRef && storyRef.__pw_type !== 'jsx')\n        ) {\n          // eslint-disable-next-line local-rules/no-uncategorized-errors\n          throw new Error(dedent`\n              Portable stories in Playwright CT only work when referencing JSX elements.\n              Please use JSX format for your components such as:\n\n              instead of:\n              await mount(MyComponent, { props: { foo: 'bar' } })\n\n              do:\n              await mount(<MyComponent foo=\"bar\"/>)\n\n              More info: https://storybook.js.org/docs/api/portable-stories/portable-stories-playwright?ref=error\n            `);\n        }\n\n        // Props are not necessarily serialisable and so can't be passed to browser via\n        // `page.evaluate`. Regardless they are not needed for storybook load/play steps.\n        const { props, ...storyRefWithoutProps } = storyRef;\n\n        await page.evaluate(async (wrappedStoryRef: WrappedStoryRef) => {\n          const unwrappedStoryRef = await globalThis.__pwUnwrapObject?.(wrappedStoryRef);\n          const story =\n            '__pw_type' in unwrappedStoryRef ? unwrappedStoryRef.type : unwrappedStoryRef;\n          return story?.load?.();\n        }, storyRefWithoutProps);\n\n        // mount the story\n        const mountResult = await mount(storyRef, ...restArgs);\n\n        // play the story in the browser\n        await page.evaluate(async (wrappedStoryRef: WrappedStoryRef) => {\n          const unwrappedStoryRef = await globalThis.__pwUnwrapObject?.(wrappedStoryRef);\n          const story =\n            '__pw_type' in unwrappedStoryRef ? unwrappedStoryRef.type : unwrappedStoryRef;\n          const canvasElement = document.querySelector('#root');\n          return story?.play?.({ canvasElement });\n        }, storyRefWithoutProps);\n\n        return mountResult;\n      });\n    },\n  });\n}\n\n// TODO At some point this function should live in prepareStory and become the core of StoryRender.render as well.\n// Will make a follow up PR for that\nasync function runStory<TRenderer extends Renderer>(\n  story: PreparedStory<TRenderer>,\n  context: StoryContext<TRenderer>\n) {\n  for (const callback of [...cleanups].reverse()) {\n    await callback();\n  }\n  cleanups.length = 0;\n\n  if (!context.canvasElement) {\n    const container = document.createElement('div');\n    globalThis?.document?.body?.appendChild(container);\n    context.canvasElement = container;\n    cleanups.push(() => {\n      if (globalThis?.document?.body?.contains(container)) {\n        globalThis?.document?.body?.removeChild(container);\n      }\n    });\n  }\n\n  context.loaded = await story.applyLoaders(context);\n\n  if (context.abortSignal.aborted) {\n    return;\n  }\n\n  cleanups.push(...(await story.applyBeforeEach(context)).filter(Boolean));\n\n  const playFunction = story.playFunction;\n\n  const isMountDestructured = story.usesMount;\n\n  if (!isMountDestructured) {\n    await context.mount();\n  }\n\n  if (context.abortSignal.aborted) {\n    return;\n  }\n\n  if (playFunction) {\n    if (!isMountDestructured) {\n      context.mount = async () => {\n        throw new MountMustBeDestructuredError({ playFunction: playFunction.toString() });\n      };\n    }\n    await playFunction(context);\n  }\n\n  let cleanUp: CleanupCallback | undefined;\n  if (isTestEnvironment()) {\n    cleanUp = pauseAnimations();\n  } else {\n    await waitForAnimations(context.abortSignal);\n  }\n\n  await story.applyAfterEach(context);\n\n  await cleanUp?.();\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/prepareStory.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type {\n  ArgsEnhancer,\n  NormalizedComponentAnnotations,\n  NormalizedStoryAnnotations,\n  PreparedStory,\n  ProjectAnnotations,\n  Renderer,\n  SBScalarType,\n  StoryContext,\n} from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport type { UserEventObject } from 'storybook/test';\n\nimport { Tag } from '../../../../shared/constants/tags.ts';\nimport { HooksContext, addons } from '../../addons/index.ts';\nimport { UNTARGETED } from '../args.ts';\nimport { composeConfigs } from './composeConfigs.ts';\nimport { normalizeProjectAnnotations } from './normalizeProjectAnnotations.ts';\nimport { prepareContext, prepareMeta, prepareStory as realPrepareStory } from './prepareStory.ts';\n\nvi.mock('@storybook/global', async (importOriginal) => ({\n  global: {\n    ...(await importOriginal<typeof import('@storybook/global')>()),\n  },\n}));\n\nconst id = 'id';\nconst name = 'name';\nconst title = 'title';\nconst render = () => {};\nconst moduleExport = {};\n\nconst stringType: SBScalarType = { name: 'string' };\nconst numberType: SBScalarType = { name: 'number' };\nconst booleanType: SBScalarType = { name: 'boolean' };\n\n// Normalize the project annotations to mimick live behavior\nexport function prepareStory<TRenderer extends Renderer>(\n  storyAnnotations: NormalizedStoryAnnotations<TRenderer>,\n  componentAnnotations: NormalizedComponentAnnotations<TRenderer>,\n  projectAnnotations: ProjectAnnotations<TRenderer>\n): PreparedStory<TRenderer> {\n  return realPrepareStory(\n    storyAnnotations,\n    componentAnnotations,\n    normalizeProjectAnnotations(composeConfigs([projectAnnotations]))\n  );\n}\n// Extra fields that must be added to the story context after enhancers\nconst addExtraContext = (\n  context: PreparedStory & Pick<StoryContext, 'args' | 'globals'>\n): StoryContext => {\n  const extraContext: StoryContext = {\n    ...context,\n    hooks: new HooksContext(),\n    viewMode: 'story' as const,\n    reporting: {\n      reports: [],\n      addReport: vi.fn(),\n    },\n    loaded: {},\n    mount: vi.fn(),\n    abortSignal: new AbortController().signal,\n    canvasElement: {},\n    step: vi.fn(),\n    context: null! as StoryContext,\n    canvas: null!,\n    userEvent: {} as UserEventObject,\n    globalTypes: {},\n  };\n  extraContext.context = extraContext;\n  return extraContext;\n};\n\ndescribe('prepareStory', () => {\n  describe('tags', () => {\n    it('story tags override component', () => {\n      const { tags } = prepareStory(\n        { id, name, tags: ['story-1', 'story-2'], moduleExport },\n        {\n          id,\n          title,\n          tags: ['component-1', 'component-2'],\n        },\n        { render }\n      );\n\n      expect(tags).toEqual([Tag.DEV, Tag.TEST, 'component-1', 'component-2', 'story-1', 'story-2']);\n    });\n\n    it('component tags work if story are unset', () => {\n      const { tags } = prepareStory(\n        { id, name, moduleExport },\n        {\n          id,\n          title,\n          tags: ['component-1', 'component-2'],\n        },\n        { render }\n      );\n\n      expect(tags).toEqual([Tag.DEV, Tag.TEST, 'component-1', 'component-2']);\n    });\n\n    it('sets a value even if annotations do not have tags', () => {\n      const { tags } = prepareStory({ id, name, moduleExport }, { id, title }, { render });\n\n      expect(tags).toEqual([Tag.DEV, Tag.TEST]);\n    });\n  });\n\n  describe('parameters', () => {\n    it('are combined in the right order', () => {\n      const { parameters } = prepareStory(\n        { id, name, parameters: { a: 'story', nested: { z: 'story' } }, moduleExport },\n        {\n          id,\n          title,\n          parameters: {\n            a: { name: 'component' },\n            b: { name: 'component' },\n            nested: { z: { name: 'component' }, y: { name: 'component' } },\n            throwPlayFunctionExceptions: false,\n          },\n        },\n        {\n          render,\n          parameters: {\n            a: { name: 'global' },\n            b: { name: 'global' },\n            c: { name: 'global' },\n            nested: { z: { name: 'global' }, x: { name: 'global' } },\n            throwPlayFunctionExceptions: false,\n          },\n        }\n      );\n\n      expect(parameters).toEqual(\n        expect.objectContaining({\n          __isArgsStory: false,\n          a: 'story',\n          b: { name: 'component' },\n          c: { name: 'global' },\n          nested: { z: 'story', y: { name: 'component' }, x: { name: 'global' } },\n        })\n      );\n    });\n\n    it('sets a value even if annotations do not have parameters', () => {\n      const { parameters } = prepareStory(\n        { id, name, moduleExport },\n        { id, title },\n        { render: (args: any) => {} }\n      );\n\n      expect(parameters).toEqual(expect.objectContaining({ __isArgsStory: true }));\n    });\n\n    it('does not set `__isArgsStory` if `render` does not take args', () => {\n      const { parameters } = prepareStory(\n        { id, name, moduleExport },\n        { id, title },\n        { render: () => {} }\n      );\n\n      expect(parameters).toEqual(expect.objectContaining({ __isArgsStory: false }));\n    });\n  });\n\n  describe('args/initialArgs', () => {\n    it('are combined in the right order', () => {\n      const { initialArgs } = prepareStory(\n        { id, name, args: { a: 'story', nested: { z: 'story' } }, moduleExport },\n        {\n          id,\n          title,\n          args: {\n            a: 'component',\n            b: 'component',\n            nested: { z: 'component', y: 'component' },\n          },\n        },\n        {\n          render,\n          args: {\n            a: 'global',\n            b: 'global',\n            c: 'global',\n            nested: { z: 'global', x: 'global' },\n          },\n        }\n      );\n\n      expect(initialArgs).toEqual({\n        a: 'story',\n        b: 'component',\n        c: 'global',\n        nested: { z: 'story' },\n      });\n    });\n\n    it('can be overridden by `undefined`', () => {\n      const { initialArgs } = prepareStory(\n        { id, name, args: { a: undefined }, moduleExport },\n        { id, title, args: { a: 'component' } },\n        { render }\n      );\n      expect(initialArgs).toEqual({ a: undefined });\n    });\n\n    it('sets a value even if annotations do not have args', () => {\n      const { initialArgs } = prepareStory({ id, name, moduleExport }, { id, title }, { render });\n\n      expect(initialArgs).toEqual({});\n    });\n\n    describe('argsEnhancers', () => {\n      it('are applied in the right order', () => {\n        const run: number[] = [];\n        const enhancerOne: ArgsEnhancer<Renderer> = () => {\n          run.push(1);\n          return {};\n        };\n        const enhancerTwo: ArgsEnhancer<Renderer> = () => {\n          run.push(2);\n          return {};\n        };\n\n        prepareStory(\n          { id, name, moduleExport },\n          { id, title },\n          { render, argsEnhancers: [enhancerOne, enhancerTwo] }\n        );\n\n        expect(run).toEqual([1, 2]);\n      });\n\n      it('allow you to add args', () => {\n        const enhancer = vi.fn(() => ({ c: 'd' }));\n\n        const { initialArgs } = prepareStory(\n          { id, name, args: { a: 'b' }, moduleExport },\n          { id, title },\n          { render, argsEnhancers: [enhancer] }\n        );\n\n        expect(enhancer).toHaveBeenCalledWith(expect.objectContaining({ initialArgs: { a: 'b' } }));\n        expect(initialArgs).toEqual({ a: 'b', c: 'd' });\n      });\n\n      it('passes result of earlier enhancers into subsequent ones, and composes their output', () => {\n        const enhancerOne = vi.fn(() => ({ b: 'B' }));\n        const enhancerTwo = vi.fn(({ initialArgs }) =>\n          Object.entries(initialArgs).reduce(\n            (acc, [key, val]) => ({ ...acc, [key]: `enhanced ${val}` }),\n            {}\n          )\n        );\n        const enhancerThree = vi.fn(() => ({ c: 'C' }));\n\n        const { initialArgs } = prepareStory(\n          { id, name, args: { a: 'A' }, moduleExport },\n          { id, title },\n          { render, argsEnhancers: [enhancerOne, enhancerTwo, enhancerThree] }\n        );\n\n        expect(enhancerOne).toHaveBeenCalledWith(\n          expect.objectContaining({ initialArgs: { a: 'A' } })\n        );\n        expect(enhancerTwo).toHaveBeenCalledWith(\n          expect.objectContaining({ initialArgs: { a: 'A', b: 'B' } })\n        );\n        expect(enhancerThree).toHaveBeenCalledWith(\n          expect.objectContaining({ initialArgs: { a: 'enhanced A', b: 'enhanced B' } })\n        );\n        expect(initialArgs).toEqual({\n          a: 'enhanced A',\n          b: 'enhanced B',\n          c: 'C',\n        });\n      });\n    });\n  });\n\n  describe('argTypes', () => {\n    it('are combined in the right order', () => {\n      const { argTypes } = prepareStory(\n        {\n          id,\n          name,\n          argTypes: {\n            a: { name: 'a-story', type: booleanType },\n            nested: { name: 'nested', type: booleanType, a: 'story' },\n          },\n          moduleExport,\n        },\n        {\n          id,\n          title,\n          argTypes: {\n            a: { name: 'a-component', type: stringType },\n            b: { name: 'b-component', type: stringType },\n            nested: { name: 'nested', type: booleanType, a: 'component', b: 'component' },\n          },\n        },\n        {\n          render,\n          argTypes: {\n            a: { name: 'a-global', type: numberType },\n            b: { name: 'b-global', type: numberType },\n            c: { name: 'c-global', type: numberType },\n            nested: { name: 'nested', type: booleanType, a: 'global', b: 'global', c: 'global' },\n          },\n        }\n      );\n\n      expect(argTypes).toEqual({\n        a: { name: 'a-story', type: booleanType },\n        b: { name: 'b-component', type: stringType },\n        c: { name: 'c-global', type: numberType },\n        nested: { name: 'nested', type: booleanType, a: 'story', b: 'component', c: 'global' },\n      });\n    });\n    describe('argTypesEnhancers', () => {\n      it('allows you to alter argTypes when stories are added', () => {\n        const enhancer = vi.fn((context) => ({ ...context.argTypes, c: { name: 'd' } }));\n        const { argTypes } = prepareStory(\n          { id, name, argTypes: { a: { name: 'b' } }, moduleExport },\n          { id, title },\n          { render, argTypesEnhancers: [enhancer] }\n        );\n\n        expect(enhancer).toHaveBeenCalledWith(\n          expect.objectContaining({ argTypes: { a: { name: 'b' } } })\n        );\n        expect(argTypes).toEqual({ a: { name: 'b' }, c: { name: 'd' } });\n      });\n\n      it('does not merge argType enhancer results', () => {\n        const enhancer = vi.fn(() => ({ c: { name: 'd' } }));\n        const { argTypes } = prepareStory(\n          { id, name, argTypes: { a: { name: 'b' } }, moduleExport },\n          { id, title },\n          { render, argTypesEnhancers: [enhancer] }\n        );\n\n        expect(enhancer).toHaveBeenCalledWith(\n          expect.objectContaining({ argTypes: { a: { name: 'b' } } })\n        );\n        expect(argTypes).toEqual({ c: { name: 'd' } });\n      });\n\n      it('recursively passes argTypes to successive enhancers', () => {\n        const firstEnhancer = vi.fn((context) => ({ ...context.argTypes, c: { name: 'd' } }));\n        const secondEnhancer = vi.fn((context) => ({ ...context.argTypes, e: { name: 'f' } }));\n        const { argTypes } = prepareStory(\n          { id, name, argTypes: { a: { name: 'b' } }, moduleExport },\n          { id, title },\n          { render, argTypesEnhancers: [firstEnhancer, secondEnhancer] }\n        );\n\n        expect(firstEnhancer).toHaveBeenCalledWith(\n          expect.objectContaining({ argTypes: { a: { name: 'b' } } })\n        );\n        expect(secondEnhancer).toHaveBeenCalledWith(\n          expect.objectContaining({ argTypes: { a: { name: 'b' }, c: { name: 'd' } } })\n        );\n        expect(argTypes).toEqual({ a: { name: 'b' }, c: { name: 'd' }, e: { name: 'f' } });\n      });\n    });\n  });\n\n  describe('globals => storyGlobals', () => {\n    it('are combined in the right order', () => {\n      const { storyGlobals } = prepareStory(\n        {\n          id,\n          name,\n          globals: {\n            a: 'a-story',\n            b: 'b-story',\n          },\n          moduleExport,\n        },\n        {\n          id,\n          title,\n          globals: {\n            a: 'a-component',\n            c: 'c-component',\n          },\n        },\n        { render }\n      );\n\n      expect(storyGlobals).toEqual({\n        a: 'a-story',\n        b: 'b-story',\n        c: 'c-component',\n      });\n    });\n  });\n\n  describe('applyLoaders', () => {\n    const abortSignal = new AbortController().signal;\n    it('awaits the result of a loader', async () => {\n      const loader = vi.fn(async () => new Promise((r) => setTimeout(() => r({ foo: 7 }), 100)));\n      const { applyLoaders } = prepareStory(\n        { id, name, loaders: [loader as any], moduleExport },\n        { id, title },\n        { render }\n      );\n\n      const storyContext = { abortSignal } as StoryContext;\n      const loaded = await applyLoaders(storyContext);\n\n      expect(loader).toHaveBeenCalledWith(storyContext);\n      expect(loaded).toMatchInlineSnapshot(`\n        {\n          \"foo\": 7,\n        }\n      `);\n    });\n\n    it('loaders are composed in the right order', async () => {\n      const globalLoader = async () => ({ foo: 1, bar: 1, baz: 1 });\n      const componentLoader = async () => ({ foo: 3, bar: 3 });\n      const storyLoader = async () => ({ foo: 5 });\n\n      const { applyLoaders } = prepareStory(\n        { id, name, loaders: [storyLoader], moduleExport },\n        { id, title, loaders: [componentLoader] },\n        { render, loaders: [globalLoader] }\n      );\n\n      expect(await applyLoaders({ abortSignal } as StoryContext)).toMatchInlineSnapshot(`\n        {\n          \"bar\": 3,\n          \"baz\": 1,\n          \"foo\": 5,\n        }\n      `);\n    });\n\n    it('later loaders override earlier loaders', async () => {\n      const loaders: any[] = [\n        async () => new Promise((r) => setTimeout(() => r({ foo: 7 }), 100)),\n        async () => new Promise((r) => setTimeout(() => r({ foo: 3 }), 50)),\n      ];\n\n      const { applyLoaders } = prepareStory(\n        { id, name, loaders, moduleExport },\n        { id, title },\n        { render }\n      );\n\n      expect(await applyLoaders({ abortSignal: abortSignal } as StoryContext))\n        .toMatchInlineSnapshot(`\n        {\n          \"foo\": 3,\n        }\n      `);\n    });\n  });\n\n  describe('undecoratedStoryFn', () => {\n    it('args are mapped by argTypes[x].mapping', () => {\n      const renderMock = vi.fn();\n      const story = prepareStory(\n        {\n          id,\n          name,\n          argTypes: {\n            one: { name: 'one', type: { name: 'string' }, mapping: { 1: 'mapped' } },\n            two: { name: 'two', type: { name: 'string' }, mapping: { 1: 'no match' } },\n          },\n          args: { one: 1, two: 2, three: 3 },\n          moduleExport,\n        },\n        { id, title },\n        { render: renderMock }\n      );\n\n      const context = prepareContext({ args: story.initialArgs, globals: {}, ...story });\n      story.undecoratedStoryFn(addExtraContext(context));\n      expect(renderMock).toHaveBeenCalledWith(\n        { one: 'mapped', two: 2, three: 3 },\n        expect.objectContaining({ args: { one: 'mapped', two: 2, three: 3 } })\n      );\n    });\n  });\n\n  describe('storyFn', () => {\n    it('produces a story with inherited decorators applied', () => {\n      const renderMock = vi.fn();\n      const globalDecorator = vi.fn((s) => s());\n      const componentDecorator = vi.fn((s) => s());\n      const storyDecorator = vi.fn((s) => s());\n      const story = prepareStory(\n        {\n          id,\n          name,\n          decorators: [storyDecorator],\n          parameters: {},\n          globals: {},\n          moduleExport,\n        },\n        { id, title, decorators: [componentDecorator] },\n        { render: renderMock, decorators: [globalDecorator] }\n      );\n\n      addons.setChannel({ on: vi.fn(), removeListener: vi.fn() } as any);\n      const hooks = new HooksContext();\n      story.unboundStoryFn({ args: story.initialArgs, hooks, ...story } as any);\n\n      expect(globalDecorator).toHaveBeenCalled();\n      expect(componentDecorator).toHaveBeenCalled();\n      expect(storyDecorator).toHaveBeenCalled();\n      expect(renderMock).toHaveBeenCalled();\n\n      hooks.clean();\n    });\n\n    it('prepared context is applied to decorators', () => {\n      const renderMock = vi.fn();\n      let ctx1;\n      let ctx2;\n      let ctx3;\n\n      const globalDecorator = vi.fn((fn, ctx) => {\n        ctx1 = ctx;\n        return fn();\n      });\n      const componentDecorator = vi.fn((fn, ctx) => {\n        ctx2 = ctx;\n        return fn();\n      });\n      const storyDecorator = vi.fn((fn, ctx) => {\n        ctx3 = ctx;\n        return fn();\n      });\n      const story = prepareStory(\n        {\n          id,\n          name,\n          argTypes: {\n            one: { name: 'one', type: { name: 'string' }, mapping: { 1: 'mapped-1' } },\n          },\n          args: { one: 1 },\n          decorators: [storyDecorator],\n          moduleExport,\n        },\n        { id, title, decorators: [componentDecorator] },\n        { render: renderMock, decorators: [globalDecorator] }\n      );\n\n      const hooks = new HooksContext();\n      const context = prepareContext({ args: story.initialArgs, globals: {}, ...story });\n      story.unboundStoryFn(addExtraContext(context));\n\n      expect(ctx1).toMatchObject({ unmappedArgs: { one: 1 }, args: { one: 'mapped-1' } });\n      expect(ctx2).toMatchObject({ unmappedArgs: { one: 1 }, args: { one: 'mapped-1' } });\n      expect(ctx3).toMatchObject({ unmappedArgs: { one: 1 }, args: { one: 'mapped-1' } });\n\n      hooks.clean();\n    });\n  });\n\n  describe('mapping', () => {\n    it('maps labels to values in prepareContext', () => {\n      const story = prepareStory(\n        {\n          id,\n          name,\n          argTypes: {\n            one: { name: 'one', mapping: { 1: 'mapped-1' } },\n          },\n          moduleExport,\n        },\n        { id, title },\n        { render: vi.fn() as any }\n      );\n\n      const context = prepareContext({ args: { one: 1 }, globals: {}, ...story });\n      expect(context).toMatchObject({\n        args: { one: 'mapped-1' },\n      });\n    });\n\n    it('maps arrays of labels to values in prepareContext', () => {\n      const story = prepareStory(\n        {\n          id,\n          name,\n          argTypes: {\n            one: { name: 'one', mapping: { 1: 'mapped-1' } },\n          },\n          moduleExport,\n        },\n        { id, title },\n        { render: vi.fn() as any }\n      );\n\n      const context = prepareContext({\n        args: { one: [1, 1] },\n        globals: {},\n        ...story,\n      });\n      expect(context).toMatchObject({\n        args: { one: ['mapped-1', 'mapped-1'] },\n      });\n    });\n  });\n\n  describe('with `FEATURES.argTypeTargetsV7`', () => {\n    beforeEach(() => {\n      global.FEATURES = { argTypeTargetsV7: true };\n    });\n    it('filters out targeted args', () => {\n      const renderMock = vi.fn();\n      const firstStory = prepareStory(\n        {\n          id,\n          name,\n          args: { a: 1, b: 2 },\n          argTypes: { b: { name: 'b', target: 'foo' } },\n          moduleExport,\n        },\n        { id, title },\n        { render: renderMock }\n      );\n\n      const context = prepareContext({ args: firstStory.initialArgs, globals: {}, ...firstStory });\n      firstStory.unboundStoryFn(addExtraContext(context));\n      expect(renderMock).toHaveBeenCalledWith(\n        { a: 1 },\n        expect.objectContaining({ args: { a: 1 }, allArgs: { a: 1, b: 2 } })\n      );\n    });\n\n    it('filters out conditional args', () => {\n      const renderMock = vi.fn();\n      const firstStory = prepareStory(\n        {\n          id,\n          name,\n          args: { a: 1, b: 2 },\n          argTypes: { b: { name: 'b', if: { arg: 'a', truthy: false } } },\n          moduleExport,\n        },\n        { id, title },\n        { render: renderMock }\n      );\n\n      const context = prepareContext({ args: firstStory.initialArgs, globals: {}, ...firstStory });\n      firstStory.unboundStoryFn(addExtraContext(context));\n      expect(renderMock).toHaveBeenCalledWith(\n        { a: 1 },\n        expect.objectContaining({ args: { a: 1 }, allArgs: { a: 1, b: 2 } })\n      );\n    });\n\n    it('adds argsByTarget to context', () => {\n      const renderMock = vi.fn();\n      const firstStory = prepareStory(\n        {\n          id,\n          name,\n          args: { a: 1, b: 2 },\n          argTypes: { b: { name: 'b', target: 'foo' } },\n          moduleExport,\n        },\n        { id, title },\n        { render: renderMock }\n      );\n\n      const context = prepareContext({ args: firstStory.initialArgs, globals: {}, ...firstStory });\n      firstStory.unboundStoryFn(addExtraContext(context));\n      expect(renderMock).toHaveBeenCalledWith(\n        { a: 1 },\n        expect.objectContaining({ argsByTarget: { [UNTARGETED]: { a: 1 }, foo: { b: 2 } } })\n      );\n    });\n\n    it('always sets args, even when all are targetted', () => {\n      const renderMock = vi.fn();\n      const firstStory = prepareStory(\n        {\n          id,\n          name,\n          args: { b: 2 },\n          argTypes: { b: { name: 'b', target: 'foo' } },\n          moduleExport,\n        },\n        { id, title },\n        { render: renderMock }\n      );\n\n      const context = prepareContext({ args: firstStory.initialArgs, globals: {}, ...firstStory });\n      firstStory.unboundStoryFn(addExtraContext(context));\n      expect(renderMock).toHaveBeenCalledWith(\n        {},\n        expect.objectContaining({ argsByTarget: { foo: { b: 2 } } })\n      );\n    });\n\n    it('always sets args, even when none are set for the story', () => {\n      const renderMock = vi.fn();\n      const firstStory = prepareStory(\n        {\n          id,\n          name,\n          moduleExport,\n        },\n        { id, title },\n        { render: renderMock }\n      );\n\n      const context = prepareContext({ args: firstStory.initialArgs, globals: {}, ...firstStory });\n      firstStory.unboundStoryFn(addExtraContext(context));\n      expect(renderMock).toHaveBeenCalledWith({}, expect.objectContaining({ argsByTarget: {} }));\n    });\n  });\n});\n\ndescribe('playFunction', () => {\n  it('awaits play if defined', async () => {\n    const inner = vi.fn();\n    const play = vi.fn(async () => {\n      await new Promise((r) => setTimeout(r, 0)); // Ensure this puts an async boundary in\n      inner();\n    });\n    const { playFunction } = prepareStory(\n      { id, name, play, moduleExport },\n      { id, title },\n      { render }\n    );\n\n    await playFunction?.({} as StoryContext);\n    expect(play).toHaveBeenCalled();\n    expect(inner).toHaveBeenCalled();\n  });\n\n  it('provides step via runStep', async () => {\n    const stepPlay = vi.fn((context) => {\n      expect(context).not.toBeUndefined();\n      expect(context.step).toEqual(expect.any(Function));\n    });\n    const play = vi.fn(async ({ step }) => {\n      await step('label', stepPlay);\n    });\n    const runStep = vi.fn((label, p, c) => p(c));\n    const { playFunction, runStep: preparedRunStep } = prepareStory(\n      { id, name, play, moduleExport },\n      { id, title },\n      { render, runStep }\n    );\n\n    const context: Partial<StoryContext> = {\n      step: (label, playFn) => preparedRunStep(label, playFn, context as StoryContext),\n    };\n    await playFunction?.(context as StoryContext);\n    expect(play).toHaveBeenCalled();\n    expect(stepPlay).toHaveBeenCalled();\n    expect(runStep).toBeCalledWith('label', expect.any(Function), expect.any(Object));\n  });\n});\n\ndescribe('moduleExport', () => {\n  it('are carried through from the story annotations', () => {\n    const storyObj = {};\n    const story = prepareStory({ id, name, moduleExport: storyObj }, { id, title }, { render });\n    expect(story.moduleExport).toBe(storyObj);\n  });\n});\n\ndescribe('prepareMeta', () => {\n  it('returns a similar object as prepareStory', () => {\n    const meta = {\n      id,\n      title,\n      moduleExport,\n      tags: ['some-tag'],\n      parameters: {\n        a: { name: 'component' },\n        b: { name: 'component' },\n        nested: { z: { name: 'component' }, y: { name: 'component' } },\n      },\n      args: {\n        a: 'component',\n        b: 'component',\n        nested: { z: 'component', y: 'component' },\n      },\n      argTypes: {\n        a: { name: 'a-story', type: booleanType },\n        nested: { name: 'nested', type: booleanType, a: 'story' },\n      },\n    };\n\n    // omitting the properties from preparedStory that are not in preparedMeta\n    const {\n      name: storyName,\n      story,\n      applyLoaders,\n      applyBeforeEach,\n      applyAfterEach,\n      originalStoryFn,\n      unboundStoryFn,\n      undecoratedStoryFn,\n      playFunction,\n      runStep,\n      mount,\n      renderToCanvas,\n      testingLibraryRender,\n      usesMount,\n      ...preparedStory\n    } = prepareStory({ id, name, moduleExport }, meta, { render });\n\n    const preparedMeta = prepareMeta(\n      meta,\n      normalizeProjectAnnotations(composeConfigs([{ render }])),\n      {}\n    );\n\n    // prepareMeta doesn't explicitly set this parameter to false\n    preparedMeta.parameters.__isArgsStory = false;\n\n    expect(preparedMeta).toEqual(preparedStory);\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/prepareStory.ts",
    "content": "import { type CleanupCallback, combineTags, includeConditionalArg } from 'storybook/internal/csf';\nimport { NoRenderFunctionError } from 'storybook/internal/preview-errors';\nimport type {\n  Args,\n  ArgsStoryFn,\n  Globals,\n  ModuleExport,\n  NormalizedComponentAnnotations,\n  NormalizedProjectAnnotations,\n  NormalizedStoryAnnotations,\n  Parameters,\n  PreparedMeta,\n  PreparedStory,\n  Renderer,\n  StoryContext,\n  StoryContextForEnhancers,\n  StoryContextForLoaders,\n  StrictArgTypes,\n} from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\nimport { global as globalThis } from '@storybook/global';\n\nimport { Tag } from '../../../../shared/constants/tags.ts';\nimport { applyHooks } from '../../addons/index.ts';\nimport { mountDestructured } from '../../preview-web/render/mount-utils.ts';\nimport { UNTARGETED, groupArgsByTarget } from '../args.ts';\nimport { defaultDecorateStory } from '../decorators.ts';\nimport { combineParameters } from '../parameters.ts';\nimport { normalizeArrays } from './normalizeArrays.ts';\n\n// Combine all the metadata about a story (both direct and inherited from the component/global scope)\n// into a \"render-able\" story function, with all decorators applied, parameters passed as context etc\n//\n// Note that this story function is *stateless* in the sense that it does not track args or globals\n// Instead, it is expected these are tracked separately (if necessary) and are passed into each invocation.\nexport function prepareStory<TRenderer extends Renderer>(\n  storyAnnotations: NormalizedStoryAnnotations<TRenderer>,\n  componentAnnotations: NormalizedComponentAnnotations<TRenderer>,\n  projectAnnotations: NormalizedProjectAnnotations<TRenderer>\n): PreparedStory<TRenderer> {\n  // NOTE: in the current implementation we are doing everything once, up front, rather than doing\n  // anything at render time. The assumption is that as we don't load all the stories at once, this\n  // will have a limited cost. If this proves misguided, we can refactor it.\n  const { moduleExport, id, name } = storyAnnotations || {};\n\n  const partialAnnotations = preparePartialAnnotations(\n    storyAnnotations,\n    componentAnnotations,\n    projectAnnotations\n  );\n\n  const applyLoaders = async (\n    context: StoryContext<TRenderer>\n  ): Promise<StoryContext<TRenderer>['loaded']> => {\n    const loaded = {};\n    for (const loaders of [\n      normalizeArrays(projectAnnotations.loaders),\n      normalizeArrays(componentAnnotations.loaders),\n      normalizeArrays(storyAnnotations.loaders),\n    ]) {\n      if (context.abortSignal.aborted) {\n        return loaded;\n      }\n      const loadResults = await Promise.all(loaders.map((loader) => loader(context)));\n      Object.assign(loaded, ...loadResults);\n    }\n    return loaded;\n  };\n\n  const applyBeforeEach = async (context: StoryContext<TRenderer>): Promise<CleanupCallback[]> => {\n    const cleanupCallbacks = new Array<() => unknown>();\n    for (const beforeEach of [\n      ...normalizeArrays(projectAnnotations.beforeEach),\n      ...normalizeArrays(componentAnnotations.beforeEach),\n      ...normalizeArrays(storyAnnotations.beforeEach),\n    ]) {\n      if (context.abortSignal.aborted) {\n        return cleanupCallbacks;\n      }\n      const cleanup = await beforeEach(context);\n\n      if (cleanup) {\n        cleanupCallbacks.push(cleanup);\n      }\n    }\n    return cleanupCallbacks;\n  };\n\n  const applyAfterEach = async (context: StoryContext<TRenderer>): Promise<void> => {\n    const reversedFinalizers = [\n      ...normalizeArrays(projectAnnotations.afterEach),\n      ...normalizeArrays(componentAnnotations.afterEach),\n      ...normalizeArrays(storyAnnotations.afterEach),\n    ].reverse();\n    for (const finalizer of reversedFinalizers) {\n      if (context.abortSignal.aborted) {\n        return;\n      }\n      await finalizer(context);\n    }\n  };\n\n  const undecoratedStoryFn = (context: StoryContext<TRenderer>) =>\n    context.originalStoryFn(context.args, context);\n\n  // Currently it is only possible to set these globally\n  const { applyDecorators = defaultDecorateStory, runStep } = projectAnnotations;\n\n  const decorators = [\n    ...normalizeArrays(storyAnnotations?.decorators),\n    ...normalizeArrays(componentAnnotations?.decorators),\n    ...normalizeArrays(projectAnnotations?.decorators),\n  ];\n\n  // The render function on annotations *has* to be an `ArgsStoryFn`, so when we normalize\n  // CSFv1/2, we use a new field called `userStoryFn` so we know that it can be a LegacyStoryFn\n  const render =\n    storyAnnotations?.userStoryFn ||\n    storyAnnotations?.render ||\n    componentAnnotations.render ||\n    projectAnnotations.render;\n\n  const decoratedStoryFn = applyHooks<TRenderer>(applyDecorators)(undecoratedStoryFn, decorators);\n  const unboundStoryFn = (context: StoryContext<TRenderer>) => decoratedStoryFn(context);\n\n  const playFunction = storyAnnotations?.play ?? componentAnnotations?.play;\n\n  const usesMount = mountDestructured(playFunction);\n\n  if (!render && !usesMount) {\n    throw new NoRenderFunctionError({ id });\n  }\n\n  const defaultMount = (context: StoryContext<TRenderer>) => {\n    return async () => {\n      await context.renderToCanvas();\n      return context.canvas;\n    };\n  };\n\n  const mount =\n    storyAnnotations.mount ??\n    componentAnnotations.mount ??\n    projectAnnotations.mount ??\n    defaultMount;\n\n  const testingLibraryRender = projectAnnotations.testingLibraryRender;\n\n  return {\n    storyGlobals: {},\n    ...partialAnnotations,\n    moduleExport,\n    id,\n    name,\n    story: name,\n    originalStoryFn: render!,\n    undecoratedStoryFn,\n    unboundStoryFn,\n    applyLoaders,\n    applyBeforeEach,\n    applyAfterEach,\n    playFunction,\n    runStep,\n    mount,\n    testingLibraryRender,\n    renderToCanvas: projectAnnotations.renderToCanvas,\n    usesMount,\n  };\n}\nexport function prepareMeta<TRenderer extends Renderer>(\n  componentAnnotations: NormalizedComponentAnnotations<TRenderer>,\n  projectAnnotations: NormalizedProjectAnnotations<TRenderer>,\n  moduleExport: ModuleExport\n): PreparedMeta<TRenderer> {\n  return {\n    ...preparePartialAnnotations(undefined, componentAnnotations, projectAnnotations),\n    moduleExport,\n  };\n}\n\nfunction preparePartialAnnotations<TRenderer extends Renderer>(\n  storyAnnotations: NormalizedStoryAnnotations<TRenderer> | undefined,\n  componentAnnotations: NormalizedComponentAnnotations<TRenderer>,\n  projectAnnotations: NormalizedProjectAnnotations<TRenderer>\n): Omit<StoryContextForEnhancers<TRenderer>, 'name' | 'story'> {\n  // NOTE: in the current implementation we are doing everything once, up front, rather than doing\n  // anything at render time. The assumption is that as we don't load all the stories at once, this\n  // will have a limited cost. If this proves misguided, we can refactor it.\n\n  const defaultTags = [Tag.DEV, Tag.TEST];\n  const extraTags = globalThis.DOCS_OPTIONS?.autodocs === true ? [Tag.AUTODOCS] : [];\n  /**\n   * DISCLAIMER: This feels like a hack but seems like it's the only way to override the autodocs\n   * tag for test-fn stories. That's because the Story index does not include negated tags e.g.\n   * !autodocs so the negation does not get passed through, and therefore we need to do it here.\n   * Therefore, unfortunately we have to duplicate the logic here.\n   */\n  const overrideTags = storyAnnotations?.tags?.includes(Tag.TEST_FN) ? [`!${Tag.AUTODOCS}`] : [];\n\n  const tags = combineTags(\n    ...defaultTags,\n    ...extraTags,\n    ...(projectAnnotations.tags ?? []),\n    ...(componentAnnotations.tags ?? []),\n    ...overrideTags,\n    ...(storyAnnotations?.tags ?? [])\n  );\n\n  const parameters: Parameters = combineParameters(\n    projectAnnotations.parameters,\n    componentAnnotations.parameters,\n    storyAnnotations?.parameters\n  );\n\n  // Currently it is only possible to set these globally\n  const { argTypesEnhancers = [], argsEnhancers = [] } = projectAnnotations;\n\n  const passedArgTypes: StrictArgTypes = combineParameters(\n    projectAnnotations.argTypes,\n    componentAnnotations.argTypes,\n    storyAnnotations?.argTypes\n  ) as StrictArgTypes;\n\n  if (storyAnnotations) {\n    // The render function on annotations *has* to be an `ArgsStoryFn`, so when we normalize\n    // CSFv1/2, we use a new field called `userStoryFn` so we know that it can be a LegacyStoryFn\n    const render =\n      storyAnnotations?.userStoryFn ||\n      storyAnnotations?.render ||\n      componentAnnotations.render ||\n      projectAnnotations.render;\n\n    parameters.__isArgsStory = render && render.length > 0;\n  }\n\n  // Pull out args[X] into initialArgs for argTypes enhancers\n  const passedArgs: Args = {\n    ...projectAnnotations.args,\n    ...componentAnnotations.args,\n    ...storyAnnotations?.args,\n  } as Args;\n\n  const storyGlobals: Globals = {\n    ...componentAnnotations.globals,\n    ...storyAnnotations?.globals,\n  };\n\n  const contextForEnhancers: StoryContextForEnhancers<TRenderer> & {\n    storyGlobals: Globals;\n  } = {\n    componentId: componentAnnotations.id,\n    title: componentAnnotations.title,\n    kind: componentAnnotations.title, // Back compat\n    id: storyAnnotations?.id || componentAnnotations.id,\n    // if there's no story name, we create a fake one since enhancers expect a name\n    name: storyAnnotations?.name || '__meta',\n    story: storyAnnotations?.name || '__meta', // Back compat\n    component: componentAnnotations.component,\n    subcomponents: componentAnnotations.subcomponents,\n    tags,\n    parameters,\n    initialArgs: passedArgs,\n    argTypes: passedArgTypes,\n    storyGlobals,\n  };\n\n  contextForEnhancers.argTypes = argTypesEnhancers.reduce(\n    (accumulatedArgTypes, enhancer) =>\n      enhancer({ ...contextForEnhancers, argTypes: accumulatedArgTypes }),\n    contextForEnhancers.argTypes\n  );\n\n  const initialArgsBeforeEnhancers = { ...passedArgs };\n\n  contextForEnhancers.initialArgs = [...argsEnhancers].reduce(\n    (accumulatedArgs: Args, enhancer) => ({\n      ...accumulatedArgs,\n      ...enhancer({\n        ...contextForEnhancers,\n        initialArgs: accumulatedArgs,\n      }),\n    }),\n    initialArgsBeforeEnhancers\n  );\n\n  const { name, story, ...withoutStoryIdentifiers } = contextForEnhancers;\n\n  return withoutStoryIdentifiers;\n}\n\n// the context is prepared before invoking the render function, instead of here directly\n// to ensure args don't loose there special properties set by the renderer\n// eg. reactive proxies set by frameworks like SolidJS or Vue\nexport function prepareContext<\n  TRenderer extends Renderer,\n  TContext extends Pick<StoryContextForLoaders<TRenderer>, 'args' | 'argTypes' | 'globals'>,\n>(\n  context: TContext\n): TContext & Pick<StoryContextForLoaders<TRenderer>, 'allArgs' | 'argsByTarget' | 'unmappedArgs'> {\n  const { args: unmappedArgs } = context;\n\n  let targetedContext: TContext &\n    Pick<StoryContextForLoaders<TRenderer>, 'allArgs' | 'argsByTarget'> = {\n    ...context,\n    allArgs: undefined,\n    argsByTarget: undefined,\n  };\n  if (global.FEATURES?.argTypeTargetsV7) {\n    const argsByTarget = groupArgsByTarget(context);\n    targetedContext = {\n      ...context,\n      allArgs: context.args,\n      argsByTarget,\n      args: argsByTarget[UNTARGETED] || {},\n    };\n  }\n\n  const mappedArgs = Object.entries(targetedContext.args).reduce((acc, [key, val]) => {\n    if (!targetedContext.argTypes[key]?.mapping) {\n      acc[key] = val;\n\n      return acc;\n    }\n\n    const mappingFn = (originalValue: any) => {\n      const mapping = targetedContext.argTypes[key].mapping;\n      return mapping && originalValue in mapping ? mapping[originalValue] : originalValue;\n    };\n\n    acc[key] = Array.isArray(val) ? val.map(mappingFn) : mappingFn(val);\n\n    return acc;\n  }, {} as Args);\n\n  const includedArgs = Object.entries(mappedArgs).reduce((acc, [key, val]) => {\n    const argType = targetedContext.argTypes[key] || {};\n\n    if (includeConditionalArg(argType, mappedArgs, targetedContext.globals)) {\n      acc[key] = val;\n    }\n    return acc;\n  }, {} as Args);\n\n  return { ...targetedContext, unmappedArgs, args: includedArgs };\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/processCSFFile.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { processCSFFile } from './processCSFFile.ts';\n\nit('returns a CSFFile object with meta and stories', () => {\n  const { meta, stories } = processCSFFile(\n    {\n      default: { title: 'Component' },\n      storyOne: { args: { a: 1 } },\n      storyTwo: { args: { a: 2 } },\n    },\n    './path/to/component.js',\n    'Component'\n  );\n\n  expect(meta).toEqual({\n    id: 'component',\n    title: 'Component',\n    parameters: { fileName: './path/to/component.js' },\n  });\n  expect(stories).toEqual({\n    'component--story-one': expect.objectContaining({\n      id: 'component--story-one',\n      name: 'Story One',\n      args: { a: 1 },\n    }),\n    'component--story-two': expect.objectContaining({\n      id: 'component--story-two',\n      name: 'Story Two',\n      args: { a: 2 },\n    }),\n  });\n});\n\nit('automatically sets title if undefined', () => {\n  const { meta } = processCSFFile(\n    {\n      default: {},\n      storyOne: {},\n    },\n    './path/to/component.js',\n    'Prefix/to/file'\n  );\n\n  expect(meta).toEqual({\n    id: 'prefix-to-file',\n    title: 'Prefix/to/file',\n    parameters: { fileName: './path/to/component.js' },\n  });\n});\n\nit('ignores __namedExportsOrder', () => {\n  const { stories } = processCSFFile(\n    {\n      default: { title: 'Component' },\n      x: () => 0,\n      y: () => 0,\n      z: () => 0,\n      w: () => 0,\n      __namedExportsOrder: ['w', 'x', 'z', 'y'],\n    },\n    './path/to/component.js',\n    'Component'\n  );\n\n  expect(Object.keys(stories)).toEqual([\n    'component--x',\n    'component--y',\n    'component--z',\n    'component--w',\n  ]);\n});\n\nit('filters exports using includeStories array', () => {\n  const { stories } = processCSFFile(\n    {\n      default: { title: 'Component', includeStories: ['x', 'z'] },\n      x: () => 0,\n      y: () => 0,\n      z: () => 0,\n      w: () => 0,\n    },\n    './path/to/component.js',\n    'Component'\n  );\n\n  expect(Object.keys(stories)).toEqual(['component--x', 'component--z']);\n});\n\nit('filters exports using includeStories regex', () => {\n  const { stories } = processCSFFile(\n    {\n      default: { title: 'Component', includeStories: /^(x|z)$/ },\n      x: () => 0,\n      y: () => 0,\n      z: () => 0,\n      w: () => 0,\n    },\n    './path/to/component.js',\n    'Component'\n  );\n\n  expect(Object.keys(stories)).toEqual(['component--x', 'component--z']);\n});\n\nit('filters exports using excludeStories array', () => {\n  const { stories } = processCSFFile(\n    {\n      default: { title: 'Component', excludeStories: ['x', 'z'] },\n      x: () => 0,\n      y: () => 0,\n      z: () => 0,\n      w: () => 0,\n    },\n    './path/to/component.js',\n    'Component'\n  );\n\n  expect(Object.keys(stories)).toEqual(['component--y', 'component--w']);\n});\n\nit('filters exports using excludeStories regex', () => {\n  const { stories } = processCSFFile(\n    {\n      default: { title: 'Component', excludeStories: /^(x|z)$/ },\n      x: () => 0,\n      y: () => 0,\n      z: () => 0,\n      w: () => 0,\n    },\n    './path/to/component.js',\n    'Component'\n  );\n\n  expect(Object.keys(stories)).toEqual(['component--y', 'component--w']);\n});\n\ndescribe('moduleExports', () => {\n  it('are carried through', () => {\n    const moduleExports = {\n      default: { title: 'Component' },\n      storyOne: { args: { a: 1 } },\n      storyTwo: { args: { a: 2 } },\n    };\n    const csfFile = processCSFFile(moduleExports, './path/to/component.js', 'Component');\n    expect(csfFile.moduleExports).toBe(moduleExports);\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/processCSFFile.ts",
    "content": "import { logger } from 'storybook/internal/client-logger';\nimport type { Story } from 'storybook/internal/csf';\nimport { getStoryChildren, isExportStory, isStory, toTestId } from 'storybook/internal/csf';\nimport type { ComponentTitle, Parameters, Path, Renderer } from 'storybook/internal/types';\nimport type {\n  CSFFile,\n  ModuleExports,\n  NormalizedComponentAnnotations,\n} from 'storybook/internal/types';\n\nimport { normalizeComponentAnnotations } from './normalizeComponentAnnotations.ts';\nimport { normalizeStory } from './normalizeStory.ts';\n\nconst checkGlobals = (parameters: Parameters) => {\n  const { globals, globalTypes } = parameters;\n  if (globals || globalTypes) {\n    logger.error(\n      'Global args/argTypes can only be set globally',\n      JSON.stringify({\n        globals,\n        globalTypes,\n      })\n    );\n  }\n};\n\nconst checkStorySort = (parameters: Parameters) => {\n  const { options } = parameters;\n\n  if (options?.storySort) {\n    logger.error('The storySort option parameter can only be set globally');\n  }\n};\n\nconst checkDisallowedParameters = (parameters?: Parameters) => {\n  if (!parameters) {\n    return;\n  }\n\n  checkGlobals(parameters);\n  checkStorySort(parameters);\n};\n\n// Given the raw exports of a CSF file, check and normalize it.\nexport function processCSFFile<TRenderer extends Renderer>(\n  moduleExports: ModuleExports,\n  importPath: Path,\n  title: ComponentTitle\n): CSFFile<TRenderer> {\n  const { default: defaultExport, __namedExportsOrder, ...namedExports } = moduleExports;\n\n  const factoryStory = Object.values(namedExports).find((it) => isStory<TRenderer>(it));\n  if (factoryStory) {\n    const meta: NormalizedComponentAnnotations<TRenderer> =\n      normalizeComponentAnnotations<TRenderer>(factoryStory.meta.input, title, importPath);\n    checkDisallowedParameters(meta.parameters);\n\n    const csfFile: CSFFile<TRenderer> = { meta, stories: {}, moduleExports };\n\n    Object.keys(namedExports).forEach((key) => {\n      if (isExportStory(key, meta) && isStory<TRenderer>(namedExports[key])) {\n        const story: Story<TRenderer> = namedExports[key];\n\n        const storyMeta = normalizeStory(key, story.input as any, meta);\n        checkDisallowedParameters(storyMeta.parameters);\n\n        csfFile.stories[storyMeta.id] = storyMeta;\n\n        // if the story has tests, we need to add those to the csfFile\n\n        getStoryChildren(story).forEach((child) => {\n          const name = child.input.name!;\n          const childId = toTestId(storyMeta.id, name);\n\n          child.input.parameters ??= {};\n          // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n          // @ts-ignore We provide the __id parameter because we don't want normalizeStory to calculate the id\n          child.input.parameters.__id = childId;\n\n          csfFile.stories[childId] = normalizeStory(name, child.input as any, meta);\n        });\n      }\n    });\n\n    csfFile.projectAnnotations = factoryStory.meta.preview.composed;\n\n    return csfFile;\n  }\n\n  const meta: NormalizedComponentAnnotations<TRenderer> = normalizeComponentAnnotations<TRenderer>(\n    defaultExport,\n    title,\n    importPath\n  );\n  checkDisallowedParameters(meta.parameters);\n\n  const csfFile: CSFFile<TRenderer> = { meta, stories: {}, moduleExports };\n\n  Object.keys(namedExports).forEach((key) => {\n    if (isExportStory(key, meta)) {\n      const storyMeta = normalizeStory(key, namedExports[key], meta);\n      checkDisallowedParameters(storyMeta.parameters);\n\n      csfFile.stories[storyMeta.id] = storyMeta;\n    }\n  });\n\n  return csfFile;\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/stepRunners.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport type { StepRunner, StoryContext } from 'storybook/internal/types';\n\nimport { composeStepRunners } from './stepRunners.ts';\n\ndescribe('stepRunners', () => {\n  it('composes each step runner', async () => {\n    const order: string[] = [];\n\n    const firstStepRunner: StepRunner = async (label, play, ctx) => {\n      order.push(`first-${label}-start`);\n      await play(ctx);\n      order.push(`first-${label}-end`);\n    };\n\n    const secondStepRunner: StepRunner = async (label, play, ctx) => {\n      order.push(`second-${label}-start`);\n      await play(ctx);\n      order.push(`second-${label}-end`);\n    };\n\n    const composed = composeStepRunners([firstStepRunner, secondStepRunner]);\n\n    const playFnA = vi.fn();\n    const playContextA = {} as StoryContext;\n    await composed('a', playFnA, playContextA);\n    const playFnB = vi.fn();\n    const playContextB = {} as StoryContext;\n    await composed('b', playFnB, playContextB);\n\n    expect(playFnA).toHaveBeenCalledTimes(1);\n    expect(playFnA).toHaveBeenCalledWith(playContextA);\n    expect(playFnB).toHaveBeenCalledTimes(1);\n    expect(playFnB).toHaveBeenCalledWith(playContextB);\n    expect(order).toEqual([\n      'first-a-start',\n      'second-a-start',\n      'second-a-end',\n      'first-a-end',\n      'first-b-start',\n      'second-b-start',\n      'second-b-end',\n      'first-b-end',\n    ]);\n  });\n\n  it('creates a sensible default if no step runner is provided', async () => {\n    const composed = composeStepRunners([]);\n\n    const playFnA = vi.fn();\n    const playContextA = {} as StoryContext;\n    await composed('a', playFnA, playContextA);\n    const playFnB = vi.fn();\n    const playContextB = {} as StoryContext;\n    await composed('b', playFnB, playContextB);\n\n    expect(playFnA).toHaveBeenCalledTimes(1);\n    expect(playFnA).toHaveBeenCalledWith(playContextA);\n    expect(playFnB).toHaveBeenCalledTimes(1);\n    expect(playFnB).toHaveBeenCalledWith(playContextB);\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/csf/stepRunners.ts",
    "content": "import type { Renderer, StepRunner } from 'storybook/internal/types';\n\n/**\n * Compose step runners to create a single step runner that applies each step runner in order.\n *\n * A step runner is a function that takes a defined step:\n *\n * @example\n *\n * ```ts\n * step('label', () => {});\n * ```\n *\n * ...and runs it. The prototypical example is from `core/interactions` where the step runner will\n * decorate all instrumented code inside the step with information about the label.\n *\n * In theory it is possible to have more than one addon that wants to run steps; they can be\n * composed together in a similar fashion to decorators. In some ways step runners are like\n * decorators except it is not intended that they change the context or the play function.\n *\n * The basic implementation of a step runner is `async (label, play, context) => play(context)` --\n * in fact this is what `composeStepRunners([])` will do.\n *\n * @param stepRunners An array of StepRunner\n * @returns A StepRunner that is the composition of the arguments\n */\nexport function composeStepRunners<TRenderer extends Renderer>(\n  stepRunners: StepRunner<TRenderer>[]\n): StepRunner<TRenderer> {\n  return async (label, play, playContext) => {\n    const composedPlay = stepRunners.reduceRight<() => Promise<void>>(\n      (innerPlay, stepRunner) => async () => stepRunner(label, innerPlay, playContext),\n      async () => play(playContext)\n    );\n    await composedPlay();\n  };\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/decorators.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport type { Renderer, StoryContext } from 'storybook/internal/types';\n\nimport { defaultDecorateStory } from './decorators.ts';\n\nfunction makeContext(input: Record<string, any> = {}): StoryContext<Renderer> {\n  return {\n    id: 'id',\n    kind: 'kind',\n    name: 'name',\n    viewMode: 'story',\n    parameters: {},\n    ...input,\n  } as StoryContext<Renderer>;\n}\n\ndescribe('client-api.decorators', () => {\n  it('calls decorators in out to in order', () => {\n    const order: number[] = [];\n    const decorators = [\n      // @ts-expect-error (not defined)\n      (s) => order.push(1) && s(),\n      // @ts-expect-error (not defined)\n      (s) => order.push(2) && s(),\n      // @ts-expect-error (not defined)\n      (s) => order.push(3) && s(),\n    ];\n    const decorated = defaultDecorateStory(() => order.push(4), decorators);\n\n    expect(order).toEqual([]);\n    decorated(makeContext());\n    expect(order).toEqual([3, 2, 1, 4]);\n  });\n\n  it('passes context through to sub decorators', () => {\n    const contexts: StoryContext[] = [];\n    const decorators = [\n      // @ts-expect-error (not defined)\n      (s, c) => contexts.push(c) && s({ args: { k: 1 } }),\n      // @ts-expect-error (not defined)\n      (s, c) => contexts.push(c) && s({ args: { k: 2 } }),\n      // @ts-expect-error (not defined)\n      (s, c) => contexts.push(c) && s({ args: { k: 3 } }),\n    ];\n    const decorated = defaultDecorateStory((c) => contexts.push(c), decorators);\n\n    expect(contexts).toEqual([]);\n    decorated(makeContext({ args: { k: 0 } }));\n    expect(contexts.map((c) => c.args.k)).toEqual([0, 3, 2, 1]);\n  });\n\n  it('passes context through to sub decorators additively', () => {\n    const contexts: StoryContext[] = [];\n    const decorators = [\n      // @ts-expect-error (not defined)\n      (s, c) => contexts.push(c) && s({ args: { a: 1 } }),\n      // @ts-expect-error (not defined)\n      (s, c) => contexts.push(c) && s({ globals: { g: 2 } }),\n    ];\n    const decorated = defaultDecorateStory((c) => contexts.push(c), decorators);\n\n    expect(contexts).toEqual([]);\n    decorated(makeContext({}));\n    expect(contexts.map(({ args, globals }) => ({ args, globals }))).toEqual([\n      { args: undefined, globals: undefined },\n      { globals: { g: 2 } },\n      { args: { a: 1 }, globals: { g: 2 } },\n    ]);\n  });\n\n  it('does not recreate decorated story functions each time', () => {\n    // @ts-expect-error (not defined)\n    const decoratedStories = [];\n    const decorators = [\n      // @ts-expect-error (not defined)\n      (s, c) => {\n        // @ts-expect-error (not defined)\n        decoratedStories.push = s;\n        return s();\n      },\n    ];\n    const decorated = defaultDecorateStory(() => 0, decorators);\n\n    decorated(makeContext());\n    decorated(makeContext());\n    // @ts-expect-error (not defined)\n    expect(decoratedStories[0]).toBe(decoratedStories[1]);\n  });\n\n  // NOTE: important point--this test would not work if we called `decoratedOne` twice simultaneously\n  // both story functions would receive {story: 2}. The assumption here is that we'll never render\n  // the same story twice at the same time.\n  it('does not interleave contexts if two decorated stories are call simultaneously', async () => {\n    const contexts: StoryContext[] = [];\n    let resolve: (value?: unknown) => void = () => {};\n    const fence = new Promise((r) => {\n      resolve = r;\n    });\n    const decorators = [\n      // @ts-expect-error (not defined)\n      async (s, c) => {\n        // The fence here simulates async-ness in react rendering an element (`<S />` doesn't run `S()` straight away)\n        await fence;\n        s();\n      },\n    ];\n    const decoratedOne = defaultDecorateStory((c) => contexts.push(c), decorators);\n    const decoratedTwo = defaultDecorateStory((c) => contexts.push(c), decorators);\n\n    decoratedOne(makeContext({ value: 1 }));\n    decoratedTwo(makeContext({ value: 2 }));\n\n    resolve();\n    await fence;\n\n    expect(contexts[0].value).toBe(1);\n    expect(contexts[1].value).toBe(2);\n  });\n\n  it('DOES NOT merge core metadata or pass through core metadata keys in context', () => {\n    const contexts: StoryContext[] = [];\n    const decorators = [\n      // @ts-expect-error (not defined)\n      (s, c) =>\n        contexts.push(c) &&\n        s({ parameters: { c: 'd' }, id: 'notId', kind: 'notKind', name: 'notName' }),\n    ];\n    const decorated = defaultDecorateStory((c) => contexts.push(c), decorators);\n\n    expect(contexts).toEqual([]);\n    decorated(makeContext({ parameters: { a: 'b' } }));\n    expect(contexts).toEqual([\n      expect.objectContaining({ parameters: { a: 'b' }, id: 'id', kind: 'kind', name: 'name' }),\n      expect.objectContaining({ parameters: { a: 'b' }, id: 'id', kind: 'kind', name: 'name' }),\n    ]);\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/decorators.ts",
    "content": "import type {\n  DecoratorFunction,\n  LegacyStoryFn,\n  PartialStoryFn,\n  Renderer,\n  StoryContext,\n  StoryContextUpdate,\n} from 'storybook/internal/types';\n\nexport function decorateStory<TRenderer extends Renderer>(\n  storyFn: LegacyStoryFn<TRenderer>,\n  decorator: DecoratorFunction<TRenderer>,\n  bindWithContext: (storyFn: LegacyStoryFn<TRenderer>) => PartialStoryFn<TRenderer>\n): LegacyStoryFn<TRenderer> {\n  // Bind the partially decorated storyFn so that when it is called it always knows about the story context,\n  // no matter what it is passed directly. This is because we cannot guarantee a decorator will\n  // pass the context down to the next decorated story in the chain.\n  const boundStoryFunction = bindWithContext(storyFn);\n\n  return (context) => decorator(boundStoryFunction, context);\n}\n\n/**\n * Currently StoryContextUpdates are allowed to have any key in the type. However, you cannot\n * overwrite any of the build-it \"static\" keys.\n *\n * @param inputContextUpdate StoryContextUpdate\n * @returns StoryContextUpdate\n */\nexport function sanitizeStoryContextUpdate({\n  componentId,\n  title,\n  kind,\n  id,\n  name,\n  story,\n  parameters,\n  initialArgs,\n  argTypes,\n  ...update\n}: StoryContextUpdate = {}): StoryContextUpdate {\n  return update;\n}\n\ntype ContextStore<TRenderer extends Renderer> = {\n  value?: StoryContext<TRenderer>;\n};\n\nexport function defaultDecorateStory<TRenderer extends Renderer>(\n  storyFn: LegacyStoryFn<TRenderer>,\n  decorators: DecoratorFunction<TRenderer>[]\n): LegacyStoryFn<TRenderer> {\n  // We use a trick to avoid recreating the bound story function inside `decorateStory`.\n  // Instead we pass it a context \"getter\", which is defined once (at \"decoration time\")\n  // The getter reads a variable which is scoped to this call of `decorateStory`\n  // (ie to this story), so there is no possibility of overlap.\n  // This will break if you call the same story twice interleaved\n  // (React might do it if you rendered the same story twice in the one ReactDom.render call, for instance)\n  const contextStore: ContextStore<TRenderer> = {};\n\n  /**\n   * When you call the story function inside a decorator, e.g.:\n   *\n   * ```jsx\n   * <div>{storyFn({ foo: 'bar' })}</div>;\n   * ```\n   *\n   * This will override the `foo` property on the `innerContext`, which gets merged in with the\n   * default context\n   */\n  const bindWithContext =\n    (decoratedStoryFn: LegacyStoryFn<TRenderer>): PartialStoryFn<TRenderer> =>\n    (update) => {\n      // This code path isn't possible because we always set `contextStore.value` before calling\n      // `decoratedWithContextStore`, but TS doesn't know that.\n      if (!contextStore.value) {\n        throw new Error('Decorated function called without init');\n      }\n      contextStore.value = {\n        ...contextStore.value,\n        ...sanitizeStoryContextUpdate(update),\n      };\n      return decoratedStoryFn(contextStore.value);\n    };\n\n  const decoratedWithContextStore = decorators.reduce(\n    (story, decorator) => decorateStory(story, decorator, bindWithContext),\n    storyFn\n  );\n  return (context) => {\n    contextStore.value = context;\n    return decoratedWithContextStore(context); // Pass the context directly into the first decorator\n  };\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/filterArgTypes.ts",
    "content": "import type { StrictArgTypes } from 'storybook/internal/types';\n\nimport { pickBy } from 'es-toolkit/object';\n\nexport type PropDescriptor = string[] | RegExp;\n\nconst matches = (name: string, descriptor: PropDescriptor) =>\n  Array.isArray(descriptor) ? descriptor.includes(name) : name.match(descriptor);\n\nexport const filterArgTypes = (\n  argTypes: StrictArgTypes,\n  include?: PropDescriptor,\n  exclude?: PropDescriptor\n) => {\n  if (!include && !exclude) {\n    return argTypes;\n  }\n  return (\n    argTypes &&\n    pickBy(argTypes, (argType, key) => {\n      const name = argType.name || key.toString();\n      return !!(!include || matches(name, include)) && (!exclude || !matches(name, exclude));\n    })\n  );\n};\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/hooks.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport {\n  FORCE_RE_RENDER,\n  RESET_STORY_ARGS,\n  STORY_RENDERED,\n  UPDATE_GLOBALS,\n  UPDATE_STORY_ARGS,\n} from 'storybook/internal/core-events';\nimport type { DecoratorFunction, StoryContext } from 'storybook/internal/types';\n\nimport {\n  HooksContext,\n  addons,\n  applyHooks,\n  useArgs,\n  useCallback,\n  useChannel,\n  useEffect,\n  useGlobals,\n  useMemo,\n  useParameter,\n  useReducer,\n  useRef,\n  useState,\n  useStoryContext,\n} from '../addons/index.ts';\nimport { defaultDecorateStory } from './decorators.ts';\n\nvi.mock('storybook/internal/client-logger', () => ({\n  logger: { warn: vi.fn(), log: vi.fn() },\n}));\n\nconst SOME_EVENT = 'someEvent';\nlet mockChannel: any;\nlet hooks: any;\nlet onSomeEvent: any;\nlet removeSomeEventListener: any;\nbeforeEach(() => {\n  onSomeEvent = vi.fn();\n  removeSomeEventListener = vi.fn();\n  mockChannel = {\n    emit: vi.fn(),\n    on(event: any, callback: any) {\n      switch (event) {\n        case STORY_RENDERED:\n          callback();\n          break;\n        case SOME_EVENT:\n          onSomeEvent(event, callback);\n          break;\n        default:\n      }\n    },\n    removeListener(event: any, callback: any) {\n      if (event === SOME_EVENT) {\n        removeSomeEventListener(event, callback);\n      }\n    },\n  };\n  hooks = new HooksContext();\n  addons.setChannel(mockChannel);\n});\n\nconst decorateStory = applyHooks(defaultDecorateStory);\n\nconst run = (storyFn: any, decorators: DecoratorFunction[] = [], context = {}) =>\n  decorateStory(storyFn, decorators)({ ...context, hooks } as StoryContext);\n\ndescribe('Preview hooks', () => {\n  describe('useEffect', () => {\n    it('triggers the effect from story function', () => {\n      const effect = vi.fn();\n      run(() => {\n        useEffect(effect);\n      });\n      expect(effect).toHaveBeenCalledTimes(1);\n    });\n    it('triggers the effect from decorator', () => {\n      const effect = vi.fn();\n      run(() => {}, [\n        (storyFn) => {\n          useEffect(effect);\n          return storyFn();\n        },\n      ]);\n      expect(effect).toHaveBeenCalledTimes(1);\n    });\n    it('triggers the effect from decorator if story call comes before useEffect', () => {\n      const effect = vi.fn();\n      run(() => {}, [\n        (storyFn) => {\n          const story = storyFn();\n          useEffect(effect);\n          return story;\n        },\n      ]);\n      expect(effect).toHaveBeenCalledTimes(1);\n    });\n    it('retriggers the effect if no deps array is provided', () => {\n      const effect = vi.fn();\n      const storyFn = () => {\n        useEffect(effect);\n      };\n      run(storyFn);\n      run(storyFn);\n      expect(effect).toHaveBeenCalledTimes(2);\n    });\n    it(\"doesn't retrigger the effect if empty deps array is provided\", () => {\n      const effect = vi.fn();\n      const storyFn = () => {\n        useEffect(effect, []);\n      };\n      run(storyFn);\n      run(storyFn);\n      expect(effect).toHaveBeenCalledTimes(1);\n    });\n    it(\"doesn't retrigger the effect from decorator if story has changed\", () => {\n      const effect = vi.fn();\n      const decorator = (storyFn: any) => {\n        useEffect(effect, []);\n        return storyFn();\n      };\n      run(() => {}, [decorator]);\n      run(() => {}, [decorator]);\n      expect(effect).toHaveBeenCalledTimes(1);\n    });\n    it(\"doesn't retrigger the effect from decorator if story has changed and story call comes before useEffect\", () => {\n      const effect = vi.fn();\n      const decorator = (storyFn: any) => {\n        const story = storyFn();\n        useEffect(effect, []);\n        return story;\n      };\n      run(() => {}, [decorator]);\n      run(() => {}, [decorator]);\n      expect(effect).toHaveBeenCalledTimes(1);\n    });\n    it(\"doesn't retrigger the effect from if decorator calls story twice\", () => {\n      const effect = vi.fn();\n      const story = () => {\n        useEffect(effect, []);\n      };\n      const decorator = (storyFn: any) => {\n        storyFn();\n        return storyFn();\n      };\n      run(story, [decorator]);\n      expect(effect).toHaveBeenCalledTimes(1);\n    });\n    it('handles decorator conditionally rendering the story', () => {\n      const effect = vi.fn();\n      const story = () => {\n        useEffect(effect, []);\n      };\n      const decorator = (storyFn: any) => {\n        const [counter, setCounter] = useState(0);\n        useEffect(() => {\n          setCounter((prevCounter) => prevCounter + 1);\n        }, [counter]);\n\n        if (counter % 2 === 1) {\n          storyFn();\n        }\n        return 'placeholder while waiting';\n      };\n      run(story, [decorator]);\n      run(story, [decorator]);\n      run(story, [decorator]);\n      run(story, [decorator]);\n      expect(effect).toHaveBeenCalledTimes(2);\n    });\n    it('retriggers the effect if some of the deps are changed', () => {\n      const effect = vi.fn();\n      let counter = 0;\n      const storyFn = () => {\n        useEffect(effect, [counter]);\n        counter += 1;\n      };\n      run(storyFn);\n      run(storyFn);\n      expect(effect).toHaveBeenCalledTimes(2);\n    });\n    it(\"doesn't retrigger the effect if none of the deps are changed\", () => {\n      const effect = vi.fn();\n      const storyFn = () => {\n        useEffect(effect, [0]);\n      };\n      run(storyFn);\n      run(storyFn);\n      expect(effect).toHaveBeenCalledTimes(1);\n    });\n    it('performs cleanup when retriggering', () => {\n      const destroy = vi.fn();\n      const storyFn = () => {\n        useEffect(() => destroy);\n      };\n      run(storyFn);\n      run(storyFn);\n      expect(destroy).toHaveBeenCalledTimes(1);\n    });\n    it(\"doesn't perform cleanup when keeping the current effect\", () => {\n      const destroy = vi.fn();\n      const storyFn = () => {\n        useEffect(() => destroy, []);\n      };\n      run(storyFn);\n      run(storyFn);\n      expect(destroy).not.toHaveBeenCalled();\n    });\n    it('performs cleanup when removing the decorator', () => {\n      const destroy = vi.fn();\n      run(() => {}, [\n        (storyFn) => {\n          useEffect(() => destroy);\n          return storyFn();\n        },\n      ]);\n      run(() => {});\n      expect(destroy).toHaveBeenCalledTimes(1);\n    });\n  });\n  describe('useChannel', () => {\n    it('calls .on when rendering the decorator', () => {\n      const handler = () => {};\n      run(() => {}, [\n        (storyFn) => {\n          useChannel({\n            [SOME_EVENT]: handler,\n          });\n          return storyFn();\n        },\n      ]);\n      expect(onSomeEvent).toHaveBeenCalledTimes(1);\n      expect(removeSomeEventListener).toHaveBeenCalledTimes(0);\n    });\n    it('calls .removeListener when removing the decorator', () => {\n      const handler = () => {};\n      run(() => {}, [\n        (storyFn) => {\n          useChannel({\n            [SOME_EVENT]: handler,\n          });\n          return storyFn();\n        },\n      ]);\n      expect(onSomeEvent).toHaveBeenCalledTimes(1);\n      expect(removeSomeEventListener).toHaveBeenCalledTimes(0);\n      run(() => {});\n      expect(removeSomeEventListener).toHaveBeenCalledTimes(1);\n    });\n  });\n  describe('useStoryContext', () => {\n    it('returns current context', () => {\n      const context = {};\n      run(\n        () => {\n          expect(useStoryContext()).toEqual({ ...context, hooks });\n        },\n        [],\n        context\n      );\n    });\n  });\n  describe('useParameter', () => {\n    it('will pull value from storyStore', () => {\n      run(\n        () => {},\n        [\n          (storyFn) => {\n            expect(useParameter('foo', 4)).toEqual(42);\n            return storyFn();\n          },\n        ],\n        { parameters: { foo: 42 } }\n      );\n    });\n    it('will return default value', () => {\n      run(\n        () => {},\n        [\n          (storyFn) => {\n            expect(useParameter('bar', 4)).toEqual(4);\n            return storyFn();\n          },\n        ],\n        { parameters: {} }\n      );\n    });\n    it('will return undefined when no value is found', () => {\n      run(\n        () => {},\n        [\n          (storyFn) => {\n            expect(useParameter('bar')).toBe(undefined);\n            return storyFn();\n          },\n        ],\n        { parameters: {} }\n      );\n    });\n  });\n  describe('useMemo', () => {\n    it('performs the calculation', () => {\n      let result;\n      const nextCreate = vi.fn(() => 'foo');\n      const storyFn = () => {\n        result = useMemo(nextCreate, []);\n      };\n      run(storyFn);\n      expect(nextCreate).toHaveBeenCalledTimes(1);\n      expect(result).toBe('foo');\n    });\n    it('performs the calculation once if deps are unchanged', () => {\n      let result;\n      const nextCreate = vi.fn(() => 'foo');\n      const storyFn = () => {\n        result = useMemo(nextCreate, []);\n      };\n      run(storyFn);\n      run(storyFn);\n      expect(nextCreate).toHaveBeenCalledTimes(1);\n      expect(result).toBe('foo');\n    });\n    it('performs the calculation again if deps are changed', () => {\n      let result;\n      let counter = 0;\n      const nextCreate = vi.fn(() => counter);\n      const storyFn = () => {\n        counter += 1;\n        result = useMemo(nextCreate, [counter]);\n      };\n      run(storyFn);\n      run(storyFn);\n      expect(nextCreate).toHaveBeenCalledTimes(2);\n      expect(result).toBe(counter);\n    });\n  });\n  describe('useCallback', () => {\n    it('returns the callback', () => {\n      let result;\n      const callback = () => {};\n      const storyFn = () => {\n        result = useCallback(callback, []);\n      };\n      run(storyFn);\n      expect(result).toBe(callback);\n    });\n    it('returns the previous callback reference if deps are unchanged', () => {\n      const callbacks: (() => void)[] = [];\n      const storyFn = () => {\n        const callback = useCallback(() => {}, []);\n        callbacks.push(callback);\n      };\n      run(storyFn);\n      run(storyFn);\n      expect(callbacks[0]).toBe(callbacks[1]);\n    });\n    it('creates new callback reference if deps are changed', () => {\n      const callbacks: (() => void)[] = [];\n      let counter = 0;\n      const storyFn = () => {\n        counter += 1;\n        const callback = useCallback(() => {}, [counter]);\n        callbacks.push(callback);\n      };\n      run(storyFn);\n      run(storyFn);\n      expect(callbacks[0]).not.toBe(callbacks[1]);\n    });\n  });\n  describe('useRef', () => {\n    it('attaches initial value', () => {\n      let ref: any;\n      const storyFn = () => {\n        ref = useRef('foo');\n      };\n      run(storyFn);\n      expect(ref.current).toBe('foo');\n    });\n    it('stores mutations', () => {\n      let refValueFromSecondRender;\n      let counter = 0;\n      const storyFn = () => {\n        counter += 1;\n        const ref = useRef('foo');\n\n        if (counter === 1) {\n          ref.current = 'bar';\n        } else {\n          refValueFromSecondRender = ref.current;\n        }\n      };\n      run(storyFn);\n      run(storyFn);\n      expect(refValueFromSecondRender).toBe('bar');\n    });\n  });\n  describe('useState', () => {\n    it('sets initial state', () => {\n      let state;\n      const storyFn = () => {\n        [state] = useState('foo');\n      };\n      run(storyFn);\n      expect(state).toBe('foo');\n    });\n    it('calculates initial state', () => {\n      let state;\n      const storyFn = () => {\n        [state] = useState(() => 'foo');\n      };\n      run(storyFn);\n      expect(state).toBe('foo');\n    });\n    it('performs synchronous state updates', () => {\n      let state;\n      let setState;\n      const storyFn = vi.fn(() => {\n        [state, setState] = useState('foo');\n        if (state === 'foo') {\n          setState('bar');\n        }\n      });\n      run(storyFn);\n      expect(storyFn).toHaveBeenCalledTimes(2);\n      expect(state).toBe('bar');\n    });\n    it('triggers only the last effect when updating state synchronously', () => {\n      const effects = [vi.fn(), vi.fn()];\n      const storyFn = vi.fn(() => {\n        const [effectIndex, setEffectIndex] = useState(0);\n        useEffect(effects[effectIndex], [effectIndex]);\n        if (effectIndex === 0) {\n          setEffectIndex(1);\n        }\n      });\n      run(storyFn);\n      expect(effects[0]).not.toHaveBeenCalled();\n      expect(effects[1]).toHaveBeenCalledTimes(1);\n    });\n    it('performs synchronous state updates with updater function', () => {\n      let state;\n      let setState;\n      const storyFn = vi.fn(() => {\n        [state, setState] = useState(0);\n        if (state < 3) {\n          setState((prevState) => prevState + 1);\n        }\n      });\n      run(storyFn);\n      expect(storyFn).toHaveBeenCalledTimes(4);\n      expect(state).toBe(3);\n    });\n    it('performs asynchronous state updates', () => {\n      let state;\n      let setState: any;\n      const storyFn = vi.fn(() => {\n        [state, setState] = useState('foo');\n      });\n      run(storyFn);\n      setState('bar');\n      expect(mockChannel.emit).toHaveBeenCalledWith(FORCE_RE_RENDER);\n      run(storyFn);\n      expect(state).toBe('bar');\n    });\n  });\n  describe('useReducer', () => {\n    it('sets initial state', () => {\n      let state;\n      const storyFn = () => {\n        [state] = useReducer(() => 'bar', 'foo');\n      };\n      run(storyFn);\n      expect(state).toBe('foo');\n    });\n    it('calculates initial state', () => {\n      let state;\n      const storyFn = () => {\n        [state] = useReducer(\n          () => 'bar',\n          'foo',\n          (arg) => arg\n        );\n      };\n      run(storyFn);\n      expect(state).toBe('foo');\n    });\n    it('performs synchronous state updates', () => {\n      let state;\n      let dispatch;\n      const storyFn = vi.fn(() => {\n        [state, dispatch] = useReducer((prevState, action) => {\n          switch (action) {\n            case 'INCREMENT':\n              return prevState + 1;\n            default:\n              return prevState;\n          }\n        }, 0);\n        if (state < 3) {\n          dispatch('INCREMENT');\n        }\n      });\n      run(storyFn);\n      expect(storyFn).toHaveBeenCalledTimes(4);\n      expect(state).toBe(3);\n    });\n    it('performs asynchronous state updates', () => {\n      let state: any;\n      let dispatch: any;\n      const storyFn = vi.fn(() => {\n        [state, dispatch] = useReducer((prevState, action) => {\n          switch (action) {\n            case 'INCREMENT':\n              return prevState + 1;\n            default:\n              return prevState;\n          }\n        }, 0);\n      });\n      run(storyFn);\n      dispatch('INCREMENT');\n      expect(mockChannel.emit).toHaveBeenCalledWith(FORCE_RE_RENDER);\n      run(storyFn);\n      expect(state).toBe(1);\n    });\n  });\n  describe('useArgs', () => {\n    it('will pull args from context', () => {\n      run(\n        () => {},\n        [\n          (storyFn) => {\n            expect(useArgs()[0]).toEqual({ a: 'b' });\n            return storyFn();\n          },\n        ],\n        { args: { a: 'b' } }\n      );\n    });\n    it('will emit UPDATE_STORY_ARGS when called', () => {\n      run(\n        () => {},\n        [\n          (storyFn) => {\n            useArgs()[1]({ a: 'b' });\n            expect(mockChannel.emit).toHaveBeenCalledWith(UPDATE_STORY_ARGS, {\n              storyId: '1',\n              updatedArgs: { a: 'b' },\n            });\n            return storyFn();\n          },\n        ],\n        { id: '1', args: {} }\n      );\n    });\n    it('will emit RESET_STORY_ARGS when called', () => {\n      run(\n        () => {},\n        [\n          (storyFn) => {\n            useArgs()[2](['a']);\n            expect(mockChannel.emit).toHaveBeenCalledWith(RESET_STORY_ARGS, {\n              storyId: '1',\n              argNames: ['a'],\n            });\n            useArgs()[2]();\n            expect(mockChannel.emit).toHaveBeenCalledWith(RESET_STORY_ARGS, {\n              storyId: '1',\n            });\n            return storyFn();\n          },\n        ],\n        { id: '1', args: {} }\n      );\n    });\n  });\n\n  describe('useGlobals', () => {\n    it('will pull globals from context', () => {\n      run(\n        () => {},\n        [\n          (storyFn) => {\n            expect(useGlobals()[0]).toEqual({ a: 'b' });\n            return storyFn();\n          },\n        ],\n        { globals: { a: 'b' } }\n      );\n    });\n    it('will emit UPDATE_GLOBALS when called', () => {\n      run(\n        () => {},\n        [\n          (storyFn) => {\n            useGlobals()[1]({ a: 'b' });\n            expect(mockChannel.emit).toHaveBeenCalledWith(UPDATE_GLOBALS, { globals: { a: 'b' } });\n            return storyFn();\n          },\n        ],\n        { globals: {} }\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/hooks.ts",
    "content": "import {\n  HooksContext,\n  applyHooks,\n  useArgs,\n  useCallback,\n  useChannel,\n  useEffect,\n  useGlobals,\n  useMemo,\n  useParameter,\n  useReducer,\n  useRef,\n  useState,\n  useStoryContext,\n} from '../addons/index.ts';\n\nexport {\n  HooksContext,\n  applyHooks,\n  useMemo,\n  useCallback,\n  useRef,\n  useState,\n  useReducer,\n  useEffect,\n  useChannel,\n  useStoryContext,\n  useParameter,\n  useArgs,\n  useGlobals,\n};\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/index.ts",
    "content": "export { StoryStore } from './StoryStore.ts';\nexport { combineParameters } from './parameters.ts';\nexport { filterArgTypes } from './filterArgTypes.ts';\nexport type { PropDescriptor } from './filterArgTypes.ts';\nexport { inferControls } from './inferControls.ts';\n\nexport * from './csf/index.ts';\nexport * from './hooks.ts';\nexport * from './decorators.ts';\nexport * from './args.ts';\nexport * from './autoTitle.ts';\nexport * from './sortStories.ts';\nexport * from './reporter-api.ts';\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/inferArgTypes.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { logger } from 'storybook/internal/client-logger';\n\nimport { inferArgTypes } from './inferArgTypes.ts';\n\nvi.mock('storybook/internal/client-logger');\n\ndescribe('inferArgTypes', () => {\n  it('infers scalar types', () => {\n    expect(\n      inferArgTypes({\n        initialArgs: {\n          a: true,\n          b: 'string',\n          c: 1,\n          d: () => {},\n          e: Symbol('foo'),\n        },\n      } as any)\n    ).toEqual({\n      a: { name: 'a', type: { name: 'boolean' } },\n      b: { name: 'b', type: { name: 'string' } },\n      c: { name: 'c', type: { name: 'number' } },\n      d: { name: 'd', type: { name: 'function' } },\n      e: { name: 'e', type: { name: 'symbol' } },\n    });\n  });\n\n  it('infers array types', () => {\n    expect(\n      inferArgTypes({\n        initialArgs: {\n          a: [1, 2, 3],\n          b: ['a', 'b', 'c'],\n          c: [],\n        },\n      } as any)\n    ).toEqual({\n      a: { name: 'a', type: { name: 'array', value: { name: 'number' } } },\n      b: { name: 'b', type: { name: 'array', value: { name: 'string' } } },\n      c: { name: 'c', type: { name: 'array', value: { name: 'other', value: 'unknown' } } },\n    });\n  });\n\n  it('infers object types', () => {\n    expect(\n      inferArgTypes({\n        initialArgs: {\n          a: {\n            x: 'string',\n            y: 1,\n          },\n        },\n      } as any)\n    ).toEqual({\n      a: {\n        name: 'a',\n        type: { name: 'object', value: { x: { name: 'string' }, y: { name: 'number' } } },\n      },\n    });\n  });\n\n  it('infers nested types', () => {\n    expect(\n      inferArgTypes({\n        initialArgs: {\n          a: [\n            {\n              x: 'string',\n            },\n          ],\n        },\n      } as any)\n    ).toEqual({\n      a: {\n        name: 'a',\n        type: { name: 'array', value: { name: 'object', value: { x: { name: 'string' } } } },\n      },\n    });\n  });\n\n  it('avoid cycles', () => {\n    const cyclic: any = {};\n    cyclic.foo = cyclic;\n\n    vi.mocked(logger.warn).mockClear();\n    expect(\n      inferArgTypes({\n        initialArgs: {\n          a: cyclic,\n        },\n      } as any)\n    ).toEqual({\n      a: {\n        name: 'a',\n        type: { name: 'object', value: { foo: { name: 'other', value: 'cyclic object' } } },\n      },\n    });\n    expect(logger.warn).toHaveBeenCalled();\n  });\n\n  it('ensures names', () => {\n    vi.mocked(logger.warn).mockClear();\n    expect(\n      inferArgTypes({\n        initialArgs: {\n          a: 1,\n        },\n        argTypes: {\n          a: {\n            control: {\n              type: 'range',\n            },\n          },\n        },\n      } as any)\n    ).toEqual({\n      a: {\n        name: 'a',\n        type: { name: 'number' },\n        control: { type: 'range' },\n      },\n    });\n  });\n\n  it('ensures names even with no arg', () => {\n    vi.mocked(logger.warn).mockClear();\n    expect(\n      inferArgTypes({\n        argTypes: {\n          a: {\n            type: {\n              name: 'string',\n            },\n          },\n        },\n      } as any)\n    ).toEqual({\n      a: {\n        name: 'a',\n        type: { name: 'string' },\n      },\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/inferArgTypes.ts",
    "content": "import { logger } from 'storybook/internal/client-logger';\nimport type { ArgTypesEnhancer, Renderer, SBType } from 'storybook/internal/types';\n\nimport { mapValues } from 'es-toolkit/object';\nimport { dedent } from 'ts-dedent';\n\nimport { combineParameters } from './parameters.ts';\n\nconst inferType = (\n  value: any,\n  name: string,\n  visited: Set<any>,\n  cache: Map<any, SBType>\n): SBType => {\n  const type = typeof value;\n  switch (type) {\n    case 'boolean':\n    case 'string':\n    case 'number':\n    case 'function':\n    case 'symbol':\n      return { name: type };\n    default:\n      break;\n  }\n  if (value) {\n    // Check cache first for previously computed results\n    if (cache.has(value)) {\n      return cache.get(value)!;\n    }\n\n    // Check for cycles (currently being processed in this path)\n    if (visited.has(value)) {\n      logger.warn(dedent`\n        We've detected a cycle in arg '${name}'. Args should be JSON-serializable.\n\n        Consider using the mapping feature or fully custom args:\n        - Mapping: https://storybook.js.org/docs/writing-stories/args#mapping-to-complex-arg-values\n        - Custom args: https://storybook.js.org/docs/essentials/controls#fully-custom-args\n      `);\n      return { name: 'other', value: 'cyclic object' };\n    }\n\n    visited.add(value);\n\n    let result: SBType;\n\n    if (Array.isArray(value)) {\n      const childType: SBType =\n        value.length > 0\n          ? inferType(value[0], name, visited, cache)\n          : { name: 'other', value: 'unknown' };\n      result = { name: 'array', value: childType };\n    } else {\n      const fieldTypes = mapValues(value, (field) => inferType(field, name, visited, cache));\n      result = { name: 'object', value: fieldTypes };\n    }\n\n    visited.delete(value); // Remove from current path after processing\n    cache.set(value, result); // Cache the result for future lookups\n\n    return result;\n  }\n  return { name: 'object', value: {} };\n};\n\nexport const inferArgTypes: ArgTypesEnhancer<Renderer> = (context) => {\n  const { id, argTypes: userArgTypes = {}, initialArgs = {} } = context;\n  const cache = new Map<any, SBType>();\n  const argTypes = mapValues(initialArgs, (arg, key) => ({\n    name: key,\n    type: inferType(arg, `${id}.${key}`, new Set(), cache),\n  }));\n  const userArgTypesNames = mapValues(userArgTypes, (argType, key) => ({\n    name: key,\n  }));\n  return combineParameters(argTypes, userArgTypesNames, userArgTypes);\n};\n\ninferArgTypes.secondPass = true;\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/inferControls.test.ts",
    "content": "import type { MockInstance } from 'vitest';\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { logger } from 'storybook/internal/client-logger';\nimport type { StoryContextForEnhancers } from 'storybook/internal/types';\n\nimport { argTypesEnhancers } from './inferControls.ts';\n\nconst getStoryContext = (overrides: any = {}): StoryContextForEnhancers => ({\n  id: '',\n  title: '',\n  kind: '',\n  name: '',\n  story: '',\n  initialArgs: {},\n  argTypes: {\n    label: { control: 'text' },\n    labelName: { control: 'text' },\n    borderWidth: { control: { type: 'number', min: 0, max: 10 } },\n  },\n  ...overrides,\n  parameters: {\n    __isArgsStory: true,\n    ...overrides.parameters,\n  },\n});\n\nconst [inferControls] = argTypesEnhancers;\ndescribe('inferControls', () => {\n  describe('with custom matchers', () => {\n    let warnSpy: MockInstance;\n    beforeEach(() => {\n      warnSpy = vi.spyOn(logger, 'warn');\n      warnSpy.mockImplementation(() => {});\n    });\n    afterEach(() => {\n      warnSpy.mockRestore();\n    });\n\n    it('should return color type when using color matcher', () => {\n      // passing a string, should return control type color\n      const inferredControls = inferControls(\n        getStoryContext({\n          argTypes: {\n            background: {\n              type: {\n                name: 'string',\n              },\n              name: 'background',\n            },\n          },\n          parameters: {\n            controls: {\n              matchers: {\n                color: /background/,\n              },\n            },\n          },\n        })\n      );\n\n      const control = inferredControls.background.control;\n      expect(typeof control === 'object' && control.type).toEqual('color');\n    });\n\n    it('should return inferred type when using color matcher but arg passed is not a string', () => {\n      const sampleTypes = [\n        {\n          name: 'object',\n          value: {\n            rgb: {\n              name: 'number',\n            },\n          },\n        },\n        { name: 'number' },\n        { name: 'boolean' },\n      ];\n\n      sampleTypes.forEach((type) => {\n        const inferredControls = inferControls(\n          getStoryContext({\n            argTypes: {\n              background: {\n                // passing an object which is unsupported\n                // should ignore color control and infer the type instead\n                type,\n                name: 'background',\n              },\n            },\n            parameters: {\n              controls: {\n                matchers: {\n                  color: /background/,\n                },\n              },\n            },\n          })\n        );\n\n        expect(warnSpy).toHaveBeenCalled();\n        const control = inferredControls.background.control;\n        expect(typeof control === 'object' && control.type).toEqual(type.name);\n      });\n    });\n  });\n\n  it('should return argTypes as is when no exclude or include is passed', () => {\n    const controls = inferControls(getStoryContext());\n    expect(Object.keys(controls)).toEqual(['label', 'labelName', 'borderWidth']);\n  });\n\n  it('should return filtered argTypes when include is passed', () => {\n    const [includeString, includeArray, includeRegex] = [\n      inferControls(getStoryContext({ parameters: { controls: { include: 'label' } } })),\n      inferControls(getStoryContext({ parameters: { controls: { include: ['label'] } } })),\n      inferControls(getStoryContext({ parameters: { controls: { include: /label*/ } } })),\n    ];\n\n    expect(Object.keys(includeString)).toEqual(['label', 'labelName']);\n    expect(Object.keys(includeArray)).toEqual(['label']);\n    expect(Object.keys(includeRegex)).toEqual(['label', 'labelName']);\n  });\n\n  it('should return filtered argTypes when exclude is passed', () => {\n    const [excludeString, excludeArray, excludeRegex] = [\n      inferControls(getStoryContext({ parameters: { controls: { exclude: 'label' } } })),\n      inferControls(getStoryContext({ parameters: { controls: { exclude: ['label'] } } })),\n      inferControls(getStoryContext({ parameters: { controls: { exclude: /label*/ } } })),\n    ];\n\n    expect(Object.keys(excludeString)).toEqual(['borderWidth']);\n    expect(Object.keys(excludeArray)).toEqual(['labelName', 'borderWidth']);\n    expect(Object.keys(excludeRegex)).toEqual(['borderWidth']);\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/inferControls.ts",
    "content": "import { logger } from 'storybook/internal/client-logger';\nimport type {\n  ArgTypesEnhancer,\n  Renderer,\n  SBEnumType,\n  StrictInputType,\n} from 'storybook/internal/types';\n\nimport { mapValues } from 'es-toolkit/object';\n\nimport { filterArgTypes } from './filterArgTypes.ts';\nimport { combineParameters } from './parameters.ts';\n\nexport type ControlsMatchers = {\n  date: RegExp;\n  color: RegExp;\n};\n\nconst inferControl = (argType: StrictInputType, name: string, matchers: ControlsMatchers): any => {\n  const { type, options } = argType;\n  if (!type) {\n    return undefined;\n  }\n\n  // args that end with background or color e.g. iconColor\n  if (matchers.color && matchers.color.test(name)) {\n    const controlType = type.name;\n\n    if (controlType === 'string') {\n      return { control: { type: 'color' } };\n    }\n\n    if (controlType !== 'enum') {\n      logger.warn(\n        `Addon controls: Control of type color only supports string, received \"${controlType}\" instead`\n      );\n    }\n  }\n\n  // args that end with date e.g. purchaseDate\n  if (matchers.date && matchers.date.test(name)) {\n    return { control: { type: 'date' } };\n  }\n\n  switch (type.name) {\n    case 'array':\n      return { control: { type: 'object' } };\n    case 'boolean':\n      return { control: { type: 'boolean' } };\n    case 'string':\n      return { control: { type: 'text' } };\n    case 'number':\n      return { control: { type: 'number' } };\n    case 'enum': {\n      const { value } = type as SBEnumType;\n      return { control: { type: value?.length <= 5 ? 'radio' : 'select' }, options: value };\n    }\n    case 'function':\n    case 'symbol':\n      return null;\n    default:\n      return { control: { type: options ? 'select' : 'object' } };\n  }\n};\n\nexport const inferControls: ArgTypesEnhancer<Renderer> = (context) => {\n  const {\n    argTypes,\n    parameters: { __isArgsStory, controls: { include = null, exclude = null, matchers = {} } = {} },\n  } = context;\n\n  if (!__isArgsStory) {\n    return argTypes;\n  }\n\n  const filteredArgTypes = filterArgTypes(argTypes, include, exclude);\n  const withControls = mapValues(filteredArgTypes, (argType, name) => {\n    return argType?.type && inferControl(argType, name.toString(), matchers);\n  });\n\n  return combineParameters(withControls, filteredArgTypes);\n};\n\ninferControls.secondPass = true;\n\nexport const argTypesEnhancers = [inferControls];\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/parameters.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { combineParameters } from './parameters.ts';\n\ndescribe('client-api.parameters', () => {\n  it('merges different sets of parameters by key, preferencing last', () => {\n    expect(combineParameters({ a: 'b', c: 'd' }, { e: 'f', a: 'g' })).toEqual({\n      a: 'g',\n      c: 'd',\n      e: 'f',\n    });\n  });\n\n  it('merges sub-keys', () => {\n    expect(combineParameters({ ns: { a: 'b', c: 'd' } }, { ns: { e: 'f', a: 'g' } })).toEqual({\n      ns: {\n        a: 'g',\n        c: 'd',\n        e: 'f',\n      },\n    });\n  });\n\n  it('treats array values as scalars', () => {\n    expect(combineParameters({ ns: { array: [1, 2, 3] } }, { ns: { array: [3, 4, 5] } })).toEqual({\n      ns: {\n        array: [3, 4, 5],\n      },\n    });\n  });\n\n  it('ignores undefined additions', () => {\n    expect(combineParameters({ a: 1 }, { a: 2 }, { a: undefined })).toEqual({ a: 2 });\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/parameters.ts",
    "content": "// Utilities for handling parameters\nimport type { Parameters } from 'storybook/internal/types';\n\nimport { isPlainObject } from 'es-toolkit/predicate';\n\n/**\n * Safely combine parameters recursively. Only copy objects when needed. Algorithm = always\n * overwrite the existing value UNLESS both values are plain objects. In this case flag the key as\n * \"special\" and handle it with a heuristic.\n */\nexport const combineParameters = (...parameterSets: (Parameters | undefined)[]) => {\n  const mergeKeys: Record<string, boolean> = {};\n  const definedParametersSets = parameterSets.filter(Boolean) as Parameters[];\n  const combined = definedParametersSets.reduce((acc, parameters) => {\n    Object.entries(parameters).forEach(([key, value]) => {\n      const existing = acc[key];\n      if (Array.isArray(value) || typeof existing === 'undefined') {\n        acc[key] = value;\n      } else if (isPlainObject(value) && isPlainObject(existing)) {\n        // do nothing, we'll handle this later\n        mergeKeys[key] = true;\n      } else if (typeof value !== 'undefined') {\n        acc[key] = value;\n      }\n    });\n    return acc;\n  }, {} as Parameters);\n\n  Object.keys(mergeKeys).forEach((key) => {\n    const mergeValues = definedParametersSets\n      .filter(Boolean)\n      .map((p) => p[key])\n      .filter((value) => typeof value !== 'undefined');\n    if (mergeValues.every((value) => isPlainObject(value))) {\n      combined[key] = combineParameters(...mergeValues);\n    } else {\n      combined[key] = mergeValues[mergeValues.length - 1];\n    }\n  });\n\n  return combined;\n};\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/reporter-api.ts",
    "content": "export interface Report<T = unknown> {\n  type: string;\n  version?: number;\n  result: T;\n  status: 'failed' | 'passed' | 'warning';\n}\n\nexport class ReporterAPI {\n  reports: Report[] = [];\n\n  async addReport(report: Report) {\n    this.reports.push(report);\n  }\n}\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/sortStories.ts",
    "content": "import type {\n  Addon_Comparator,\n  Addon_StorySortParameter,\n  Addon_StorySortParameterV7,\n  IndexEntry,\n  IndexEntryLegacy,\n  StoryIndexEntry,\n} from 'storybook/internal/types';\nimport type { Parameters, Path, Renderer } from 'storybook/internal/types';\nimport type { PreparedStory } from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\n\nimport { storySort } from './storySort.ts';\n\nconst sortStoriesCommon = (\n  stories: IndexEntry[],\n  storySortParameter: Addon_StorySortParameterV7,\n  fileNameOrder: Path[]\n) => {\n  if (storySortParameter) {\n    let sortFn: Addon_Comparator<any>;\n    if (typeof storySortParameter === 'function') {\n      sortFn = storySortParameter;\n    } else {\n      sortFn = storySort(storySortParameter);\n    }\n    stories.sort(sortFn as (a: IndexEntry, b: IndexEntry) => number);\n  } else {\n    stories.sort(\n      (s1, s2) => fileNameOrder.indexOf(s1.importPath) - fileNameOrder.indexOf(s2.importPath)\n    );\n  }\n  return stories;\n};\n\nexport const sortStoriesV7 = (\n  stories: IndexEntry[],\n  storySortParameter: Addon_StorySortParameterV7,\n  fileNameOrder: Path[]\n) => {\n  try {\n    return sortStoriesCommon(stories, storySortParameter, fileNameOrder);\n  } catch (err) {\n    throw new Error(dedent`\n    Error sorting stories with sort parameter ${storySortParameter}:\n\n    > ${(err as Error).message}\n\n    Are you using a V6-style sort function in V7 mode?\n\n    More info: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#v7-style-story-sort\n  `);\n  }\n};\n\nconst toIndexEntry = (story: any): StoryIndexEntry => {\n  const { id, title, name, parameters, type, subtype, parent } = story;\n  return { id, title, name, importPath: parameters.fileName, type, subtype, parent };\n};\n\nexport const sortStoriesV6 = <TRenderer extends Renderer>(\n  stories: [string, PreparedStory<TRenderer>, Parameters, Parameters][],\n  storySortParameter: Addon_StorySortParameter,\n  fileNameOrder: Path[]\n) => {\n  if (storySortParameter && typeof storySortParameter === 'function') {\n    stories.sort(storySortParameter as (a: IndexEntryLegacy, b: IndexEntryLegacy) => number);\n    return stories.map((s) => toIndexEntry(s[1]));\n  }\n\n  const storiesV7 = stories.map((s) => toIndexEntry(s[1]));\n  return sortStoriesCommon(\n    storiesV7,\n    storySortParameter as Addon_StorySortParameterV7,\n    fileNameOrder\n  );\n};\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/storySort.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport type { StoryId, StoryIndexEntry } from 'storybook/internal/types';\n\nimport { storySort } from './storySort.ts';\n\ndescribe('preview.storySort', () => {\n  const fixture: Record<StoryId, StoryIndexEntry> = Object.fromEntries(\n    Object.entries({\n      a: { title: 'a' },\n      á: { title: 'á' },\n      A: { title: 'A' },\n      b: { title: 'b' },\n      a_a: { title: 'a / a' },\n      a_b: { title: 'a / b' },\n      a_c: { title: 'a / c' },\n      b_a_a: { title: 'b / a / a' },\n      b_b: { title: 'b / b' },\n      c: { title: 'c' },\n      locale1: { title: 'Б' },\n      locale2: { title: 'Г' },\n      c__a: { title: 'c', name: 'a' },\n      c_b__a: { title: 'c / b', name: 'a' },\n      c_b__b: { title: 'c / b', name: 'b' },\n      c_b__c: { title: 'c / b', name: 'c' },\n      c__c: { title: 'c', name: 'c' },\n    }).map(([id, entry]) => [\n      id,\n      { type: 'story', subtype: 'story', name: 'name', ...entry, id, importPath: id },\n    ])\n  );\n\n  it('uses configure order by default', () => {\n    const sortFn = storySort();\n\n    expect(sortFn(fixture.a, fixture.b)).toBe(0);\n    expect(sortFn(fixture.b, fixture.a)).toBe(0);\n    expect(sortFn(fixture.a, fixture.a)).toBe(0);\n  });\n\n  it('can sort shallow titles alphabetically', () => {\n    const sortFn = storySort({ method: 'alphabetical' });\n\n    expect(sortFn(fixture.a, fixture.b)).toBeLessThan(0);\n    expect(sortFn(fixture.b, fixture.a)).toBeGreaterThan(0);\n    expect(sortFn(fixture.a, fixture.á)).toBeLessThan(0);\n    expect(sortFn(fixture.á, fixture.a)).toBeGreaterThan(0);\n  });\n\n  it('can sort deep titles alphabetically', () => {\n    const sortFn = storySort({ method: 'alphabetical' });\n\n    expect(sortFn(fixture.a_a, fixture.a_b)).toBeLessThan(0);\n    expect(sortFn(fixture.a_b, fixture.a_a)).toBeGreaterThan(0);\n    expect(sortFn(fixture.a_a, fixture.b)).toBeLessThan(0);\n    expect(sortFn(fixture.b, fixture.a_a)).toBeGreaterThan(0);\n    expect(sortFn(fixture.a_a, fixture.a)).toBeGreaterThan(0);\n    expect(sortFn(fixture.a, fixture.a_a)).toBeLessThan(0);\n    expect(sortFn(fixture.b_a_a, fixture.b_b)).toBeLessThan(0);\n    expect(sortFn(fixture.b_b, fixture.b_a_a)).toBeGreaterThan(0);\n  });\n\n  it('ignores case when sorting alphabetically', () => {\n    const sortFn = storySort({ method: 'alphabetical' });\n\n    expect(sortFn(fixture.a, fixture.A)).toBe(0);\n    expect(sortFn(fixture.A, fixture.a)).toBe(0);\n  });\n\n  it('sorts alphabetically using the given locales', () => {\n    const sortFn = storySort({ method: 'alphabetical', locales: 'ru-RU' });\n\n    expect(sortFn(fixture.locale1, fixture.locale2)).toBeLessThan(0);\n    expect(sortFn(fixture.locale2, fixture.locale1)).toBeGreaterThan(0);\n  });\n\n  it('sorts according to the order array', () => {\n    const sortFn = storySort({ order: ['b', 'c'] });\n\n    expect(sortFn(fixture.a, fixture.b)).toBeGreaterThan(0);\n    expect(sortFn(fixture.b, fixture.a)).toBeLessThan(0);\n    expect(sortFn(fixture.b_a_a, fixture.b_b)).toBe(0);\n    expect(sortFn(fixture.b_b, fixture.b_a_a)).toBe(0);\n  });\n\n  it('sorts according to the nested order array', () => {\n    const sortFn = storySort({ order: ['a', ['b', 'c'], 'c'] });\n\n    expect(sortFn(fixture.a_a, fixture.a_b)).toBeGreaterThan(0);\n    expect(sortFn(fixture.a_b, fixture.a_a)).toBeLessThan(0);\n  });\n\n  it('sorts alphabetically including story names', () => {\n    const sortFn = storySort({ method: 'alphabetical', includeNames: true });\n    expect(sortFn(fixture.c_b__a, fixture.c__a)).toBeGreaterThan(0);\n    expect(sortFn(fixture.c__a, fixture.c_b__a)).toBeLessThan(0);\n\n    expect(sortFn(fixture.c__c, fixture.c__a)).toBeGreaterThan(0);\n    expect(sortFn(fixture.c__a, fixture.c__c)).toBeLessThan(0);\n  });\n\n  it('sorts according to the order array including story names', () => {\n    const sortFn = storySort({\n      order: ['c', ['b', ['c', 'b', 'a'], 'c', 'a']],\n      includeNames: true,\n    });\n    expect(sortFn(fixture.c_b__a, fixture.c_b__b)).toBeGreaterThan(0);\n    expect(sortFn(fixture.c_b__b, fixture.c_b__c)).toBeGreaterThan(0);\n    expect(sortFn(fixture.c_b__a, fixture.c_b__c)).toBeGreaterThan(0);\n    expect(sortFn(fixture.c_b__a, fixture.c__a)).toBeLessThan(0);\n    expect(sortFn(fixture.c_b__a, fixture.c__c)).toBeLessThan(0);\n    expect(sortFn(fixture.c__a, fixture.c__c)).toBeGreaterThan(0);\n  });\n\n  it('sorts according to the order array with a wildcard', () => {\n    const sortFn = storySort({ order: ['a', '*', 'b'] });\n\n    expect(sortFn(fixture.a, fixture.b)).toBeLessThan(0);\n    expect(sortFn(fixture.c, fixture.b)).toBeLessThan(0);\n    expect(sortFn(fixture.b, fixture.c)).toBeGreaterThan(0);\n    expect(sortFn(fixture.b, fixture.a)).toBeGreaterThan(0);\n  });\n\n  it('sorts according to the nested order array with wildcard', () => {\n    const sortFn = storySort({ order: ['a', ['a', '*', 'b'], 'c'] });\n\n    expect(sortFn(fixture.a, fixture.c)).toBeLessThan(0);\n    expect(sortFn(fixture.c, fixture.a)).toBeGreaterThan(0);\n    expect(sortFn(fixture.a_a, fixture.a_b)).toBeLessThan(0);\n    expect(sortFn(fixture.a_b, fixture.a_a)).toBeGreaterThan(0);\n    expect(sortFn(fixture.a_a, fixture.a_c)).toBeLessThan(0);\n    expect(sortFn(fixture.a_c, fixture.a_a)).toBeGreaterThan(0);\n    expect(sortFn(fixture.a_c, fixture.a_b)).toBeLessThan(0);\n    expect(sortFn(fixture.a_b, fixture.a_c)).toBeGreaterThan(0);\n  });\n\n  it('sorts according to the nested order array with parent wildcard', () => {\n    const sortFn = storySort({\n      order: ['*', ['*', 'b', 'a']],\n      includeNames: true,\n    });\n\n    expect(sortFn(fixture.a_a, fixture.a_b)).toBeGreaterThan(0);\n    expect(sortFn(fixture.a_b, fixture.a_a)).toBeLessThan(0);\n    expect(sortFn(fixture.a_c, fixture.a_a)).toBeLessThan(0);\n    expect(sortFn(fixture.a_c, fixture.a_b)).toBeLessThan(0);\n    expect(sortFn(fixture.a_a, fixture.a_c)).toBeGreaterThan(0);\n    expect(sortFn(fixture.a_b, fixture.a_c)).toBeGreaterThan(0);\n    expect(sortFn(fixture.a_a, fixture.a_a)).toBe(0);\n  });\n});\n"
  },
  {
    "path": "code/core/src/preview-api/modules/store/storySort.ts",
    "content": "import type {\n  Addon_StorySortComparatorV7,\n  Addon_StorySortObjectParameter,\n} from 'storybook/internal/types';\nimport type { IndexEntry } from 'storybook/internal/types';\n\nconst STORY_KIND_PATH_SEPARATOR = /\\s*\\/\\s*/;\n\nexport const storySort =\n  (options: Addon_StorySortObjectParameter = {}): Addon_StorySortComparatorV7 =>\n  (a: IndexEntry, b: IndexEntry): number => {\n    // If the two stories have the same story kind, then use the default\n    // ordering, which is the order they are defined in the story file.\n    // only when includeNames is falsy\n    if (a.title === b.title && !options.includeNames) {\n      return 0;\n    }\n\n    // Get the StorySortParameter options.\n    const method = options.method || 'configure';\n    let order = options.order || [];\n\n    // Examine each part of the story title in turn.\n    const storyTitleA = a.title.trim().split(STORY_KIND_PATH_SEPARATOR);\n    const storyTitleB = b.title.trim().split(STORY_KIND_PATH_SEPARATOR);\n    if (options.includeNames) {\n      storyTitleA.push(a.name);\n      storyTitleB.push(b.name);\n    }\n\n    let depth = 0;\n    while (storyTitleA[depth] || storyTitleB[depth]) {\n      // Stories with a shorter depth should go first.\n      if (!storyTitleA[depth]) {\n        return -1;\n      }\n      if (!storyTitleB[depth]) {\n        return 1;\n      }\n\n      // Compare the next part of the story title.\n      const nameA = storyTitleA[depth];\n      const nameB = storyTitleB[depth];\n      if (nameA !== nameB) {\n        // Look for the names in the given `order` array.\n        let indexA = order.indexOf(nameA);\n        let indexB = order.indexOf(nameB);\n        const indexWildcard = order.indexOf('*');\n\n        // If at least one of the names is found, sort by the `order` array.\n        if (indexA !== -1 || indexB !== -1) {\n          // If one of the names is not found and there is a wildcard, insert it at the wildcard position.\n          // Otherwise, list it last.\n          if (indexA === -1) {\n            if (indexWildcard !== -1) {\n              indexA = indexWildcard;\n            } else {\n              indexA = order.length;\n            }\n          }\n          if (indexB === -1) {\n            if (indexWildcard !== -1) {\n              indexB = indexWildcard;\n            } else {\n              indexB = order.length;\n            }\n          }\n\n          return indexA - indexB;\n        }\n\n        // Use the default configure() order.\n        if (method === 'configure') {\n          return 0;\n        }\n\n        // Otherwise, use alphabetical order.\n        return nameA.localeCompare(nameB, options.locales ? options.locales : undefined, {\n          numeric: true,\n          sensitivity: 'accent',\n        });\n      }\n\n      // If a nested array is provided for a name, use it for ordering.\n      let index = order.indexOf(nameA);\n\n      if (index === -1) {\n        index = order.indexOf('*');\n      }\n      order = index !== -1 && Array.isArray(order[index + 1]) ? order[index + 1] : [];\n\n      // We'll need to look at the next part of the name.\n      depth += 1;\n    }\n\n    // Identical story titles. The shortcut at the start of this function prevents\n    // this from ever being used.\n    /* istanbul ignore next */\n    return 0;\n  };\n"
  },
  {
    "path": "code/core/src/preview-api/preview-web.ts",
    "content": "/// <reference path=\"../typings.d.ts\" />\n\nexport * from './modules/preview-web/index.ts';\n"
  },
  {
    "path": "code/core/src/preview-api/store.ts",
    "content": "/// <reference path=\"../typings.d.ts\" />\n\nexport * from './modules/store/index.ts';\n"
  },
  {
    "path": "code/core/src/preview-errors.ts",
    "content": "import { dedent } from 'ts-dedent';\n\nimport type { Status } from './shared/status-store/index.ts';\nimport type { StatusTypeId } from './shared/status-store/index.ts';\nimport { StorybookError } from './storybook-error.ts';\n\n/**\n * If you can't find a suitable category for your error, create one based on the package name/file\n * path of which the error is thrown. For instance: If it's from `storybook/internal/client-logger`,\n * then CLIENT-LOGGER\n *\n * Categories are prefixed by a logical grouping, e.g. PREVIEW_ or FRAMEWORK_ to prevent manager and\n * preview errors from having the same category and error code.\n */\nexport enum Category {\n  BLOCKS = 'BLOCKS',\n  DOCS_TOOLS = 'DOCS-TOOLS',\n  PREVIEW_CLIENT_LOGGER = 'PREVIEW_CLIENT-LOGGER',\n  PREVIEW_CHANNELS = 'PREVIEW_CHANNELS',\n  PREVIEW_CORE_EVENTS = 'PREVIEW_CORE-EVENTS',\n  PREVIEW_INSTRUMENTER = 'PREVIEW_INSTRUMENTER',\n  PREVIEW_API = 'PREVIEW_API',\n  PREVIEW_REACT_DOM_SHIM = 'PREVIEW_REACT-DOM-SHIM',\n  PREVIEW_ROUTER = 'PREVIEW_ROUTER',\n  PREVIEW_THEMING = 'PREVIEW_THEMING',\n  RENDERER_HTML = 'RENDERER_HTML',\n  RENDERER_PREACT = 'RENDERER_PREACT',\n  RENDERER_REACT = 'RENDERER_REACT',\n  RENDERER_SERVER = 'RENDERER_SERVER',\n  RENDERER_SVELTE = 'RENDERER_SVELTE',\n  RENDERER_VUE = 'RENDERER_VUE',\n  RENDERER_VUE3 = 'RENDERER_VUE3',\n  RENDERER_WEB_COMPONENTS = 'RENDERER_WEB-COMPONENTS',\n  FRAMEWORK_NEXTJS = 'FRAMEWORK_NEXTJS',\n  ADDON_VITEST = 'ADDON_VITEST',\n  ADDON_A11Y = 'ADDON_A11Y',\n}\n\nexport class MissingStoryAfterHmrError extends StorybookError {\n  constructor(public data: { storyId: string }) {\n    super({\n      name: 'MissingStoryAfterHmrError',\n      category: Category.PREVIEW_API,\n      code: 1,\n      message: dedent`\n        Couldn't find story matching id '${data.storyId}' after HMR.\n        - Did you just rename a story?\n        - Did you remove it from your CSF file?\n        - Are you sure a story with the id '${data.storyId}' exists?\n        - Please check the values in the stories field of your main.js config and see if they would match your CSF File.\n        - Also check the browser console and terminal for potential error messages.`,\n    });\n  }\n}\n\nexport class ImplicitActionsDuringRendering extends StorybookError {\n  constructor(public data: { phase: string; name: string; deprecated: boolean }) {\n    super({\n      name: 'ImplicitActionsDuringRendering',\n      category: Category.PREVIEW_API,\n      code: 2,\n      documentation:\n        'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#using-implicit-actions-during-rendering-is-deprecated-for-example-in-the-play-function',\n      message: dedent`\n        We detected that you use an implicit action arg while ${data.phase} of your story.  \n        ${data.deprecated ? `\\nThis is deprecated and won't work in Storybook 8 anymore.\\n` : ``}\n        Please provide an explicit spy to your args like this:\n          import { fn } from 'storybook/test';\n          ... \n          args: {\n           ${data.name}: fn()\n          }`,\n    });\n  }\n}\n\nexport class CalledExtractOnStoreError extends StorybookError {\n  constructor() {\n    super({\n      name: 'CalledExtractOnStoreError',\n      category: Category.PREVIEW_API,\n      code: 3,\n      message: dedent`\n        Cannot call \\`storyStore.extract()\\` without calling \\`storyStore.cacheAllCsfFiles()\\` first.\n\n        You probably meant to call \\`await preview.extract()\\` which does the above for you.`,\n    });\n  }\n}\n\nexport class MissingRenderToCanvasError extends StorybookError {\n  constructor() {\n    super({\n      name: 'MissingRenderToCanvasError',\n      category: Category.PREVIEW_API,\n      code: 4,\n      message: dedent`\n        Expected your framework's preset to export a \\`renderToCanvas\\` field.\n\n        Perhaps it needs to be upgraded for Storybook 7.0?`,\n      documentation:\n        'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#mainjs-framework-field',\n    });\n  }\n}\n\nexport class CalledPreviewMethodBeforeInitializationError extends StorybookError {\n  constructor(public data: { methodName: string }) {\n    super({\n      name: 'CalledPreviewMethodBeforeInitializationError',\n      category: Category.PREVIEW_API,\n      code: 5,\n      message: dedent`\n        Called \\`Preview.${data.methodName}()\\` before initialization.\n        \n        The preview needs to load the story index before most methods can be called. If you want\n        to call \\`${data.methodName}\\`, try \\`await preview.initializationPromise;\\` first.\n        \n        If you didn't call the above code, then likely it was called by an addon that needs to\n        do the above.`,\n    });\n  }\n}\n\nexport class StoryIndexFetchError extends StorybookError {\n  constructor(public data: { text: string }) {\n    super({\n      name: 'StoryIndexFetchError',\n      category: Category.PREVIEW_API,\n      code: 6,\n      message: dedent`\n        Error fetching \\`/index.json\\`:\n        \n        ${data.text}\n\n        If you are in development, this likely indicates a problem with your Storybook process,\n        check the terminal for errors.\n\n        If you are in a deployed Storybook, there may have been an issue deploying the full Storybook\n        build.`,\n    });\n  }\n}\n\nexport class MdxFileWithNoCsfReferencesError extends StorybookError {\n  constructor(public data: { storyId: string }) {\n    super({\n      name: 'MdxFileWithNoCsfReferencesError',\n      category: Category.PREVIEW_API,\n      code: 7,\n      message: dedent`\n        Tried to render docs entry ${data.storyId} but it is a MDX file that has no CSF\n        references, or autodocs for a CSF file that some doesn't refer to itself.\n        \n        This likely is an internal error in Storybook's indexing, or you've attached the\n        \\`attached-mdx\\` tag to an MDX file that is not attached.`,\n    });\n  }\n}\n\nexport class EmptyIndexError extends StorybookError {\n  constructor() {\n    super({\n      name: 'EmptyIndexError',\n      category: Category.PREVIEW_API,\n      code: 8,\n      message: dedent`\n        Couldn't find any stories in your Storybook.\n\n        - Please check your stories field of your main.js config: does it match correctly?\n        - Also check the browser console and terminal for error messages.`,\n    });\n  }\n}\n\nexport class NoStoryMatchError extends StorybookError {\n  constructor(public data: { storySpecifier: string }) {\n    super({\n      name: 'NoStoryMatchError',\n      category: Category.PREVIEW_API,\n      code: 9,\n      message: dedent`\n        Couldn't find story matching '${data.storySpecifier}'.\n\n        - Are you sure a story with that id exists?\n        - Please check your stories field of your main.js config.\n        - Also check the browser console and terminal for error messages.`,\n    });\n  }\n}\n\nexport class MissingStoryFromCsfFileError extends StorybookError {\n  constructor(public data: { storyId: string }) {\n    super({\n      name: 'MissingStoryFromCsfFileError',\n      category: Category.PREVIEW_API,\n      code: 10,\n      message: dedent`\n        Couldn't find story matching id '${data.storyId}' after importing a CSF file.\n\n        The file was indexed as if the story was there, but then after importing the file in the browser\n        we didn't find the story. Possible reasons:\n        - You are using a custom story indexer that is misbehaving.\n        - You have a custom file loader that is removing or renaming exports.\n\n        Please check your browser console and terminal for errors that may explain the issue.`,\n    });\n  }\n}\n\nexport class StoryStoreAccessedBeforeInitializationError extends StorybookError {\n  constructor() {\n    super({\n      name: 'StoryStoreAccessedBeforeInitializationError',\n      category: Category.PREVIEW_API,\n      code: 11,\n      message: dedent`\n        Cannot access the Story Store until the index is ready.\n\n        It is not recommended to use methods directly on the Story Store anyway, in Storybook 9 we will\n        remove access to the store entirely`,\n    });\n  }\n}\n\nexport class MountMustBeDestructuredError extends StorybookError {\n  // name: 'MountMustBeDestructuredError';\n  constructor(public data: { playFunction: string }) {\n    // this.name = 'MountMustBeDestructuredError';\n    super({\n      name: 'MountMustBeDestructuredError',\n      category: Category.PREVIEW_API,\n      code: 12,\n      message: dedent`\n      Incorrect use of mount in the play function.\n      \n      To use mount in the play function, you must satisfy the following two requirements: \n      \n      1. You *must* destructure the mount property from the \\`context\\` (the argument passed to your play function). \n         This makes sure that Storybook does not start rendering the story before the play function begins.\n      \n      2. Your Storybook framework or builder must be configured to transpile to ES2017 or newer. \n         This is because destructuring statements and async/await usages are otherwise transpiled away, \n         which prevents Storybook from recognizing your usage of \\`mount\\`.\n      \n      Note that Angular is not supported. As async/await is transpiled to support the zone.js polyfill. \n      \n      More info: https://storybook.js.org/docs/writing-tests/interaction-testing?ref=error#run-code-before-the-component-gets-rendered\n      \n      Received the following play function:\n      ${data.playFunction}`,\n    });\n  }\n}\n\nexport class NoRenderFunctionError extends StorybookError {\n  constructor(public data: { id: string }) {\n    super({\n      name: 'NoRenderFunctionError',\n      category: Category.PREVIEW_API,\n      code: 14,\n      message: dedent`\n        No render function available for storyId '${data.id}'\n      `,\n    });\n  }\n}\n\nexport class NoStoryMountedError extends StorybookError {\n  constructor() {\n    super({\n      name: 'NoStoryMountedError',\n      category: Category.PREVIEW_API,\n      code: 15,\n      message: dedent`\n        No component is mounted in your story.\n        \n        This usually occurs when you destructure mount in the play function, but forget to call it.\n        \n        For example:\n\n        async play({ mount, canvasElement }) {\n          // 👈 mount should be called: await mount(); \n          const canvas = within(canvasElement);\n          const button = await canvas.findByRole('button');\n          await userEvent.click(button);\n        };\n\n        Make sure to either remove it or call mount in your play function.\n      `,\n    });\n  }\n}\n\nexport class StatusTypeIdMismatchError extends StorybookError {\n  constructor(\n    public data: {\n      status: Status;\n      typeId: StatusTypeId;\n    }\n  ) {\n    super({\n      name: 'StatusTypeIdMismatchError',\n      category: Category.PREVIEW_API,\n      code: 16,\n      message: `Status has typeId \"${data.status.typeId}\" but was added to store with typeId \"${data.typeId}\". Full status: ${JSON.stringify(\n        data.status,\n        null,\n        2\n      )}`,\n    });\n  }\n}\n\nexport class NextJsSharpError extends StorybookError {\n  constructor() {\n    super({\n      name: 'NextJsSharpError',\n      category: Category.FRAMEWORK_NEXTJS,\n      code: 1,\n      documentation:\n        'https://storybook.js.org/docs/get-started/frameworks/nextjs#error-you-are-importing-avif-images-but-you-dont-have-sharp-installed-you-have-to-install-sharp-in-order-to-use-image-optimization-features-in-nextjs',\n      message: dedent`\n      You are importing avif images, but you don't have sharp installed.\n\n      You have to install sharp in order to use image optimization features in Next.js.\n      `,\n    });\n  }\n}\n\nexport class NextjsRouterMocksNotAvailable extends StorybookError {\n  constructor(public data: { importType: string }) {\n    super({\n      name: 'NextjsRouterMocksNotAvailable',\n      category: Category.FRAMEWORK_NEXTJS,\n      code: 2,\n      message: dedent`\n        Tried to access router mocks from \"${data.importType}\" but they were not created yet. You might be running code in an unsupported environment.\n      `,\n    });\n  }\n}\n\nexport class UnknownArgTypesError extends StorybookError {\n  constructor(public data: { type: object; language: string }) {\n    super({\n      name: 'UnknownArgTypesError',\n      category: Category.DOCS_TOOLS,\n      code: 1,\n      documentation: 'https://github.com/storybookjs/storybook/issues/26606',\n      message: dedent`\n        There was a failure when generating detailed ArgTypes in ${data.language} for:\n        ${JSON.stringify(data.type, null, 2)} \n        \n        Storybook will fall back to use a generic type description instead.\n\n        This type is either not supported or it is a bug in the docgen generation in Storybook.\n        If you think this is a bug, please detail it as much as possible in the Github issue.\n      `,\n    });\n  }\n}\n\nexport class UnsupportedViewportDimensionError extends StorybookError {\n  constructor(public data: { dimension: string; value: string }) {\n    super({\n      name: 'UnsupportedViewportDimensionError',\n      category: Category.ADDON_VITEST,\n      code: 1,\n      // TODO: Add documentation about viewports support\n      // documentation: '',\n      message: dedent`\n        Encountered an unsupported value \"${data.value}\" when setting the viewport ${data.dimension} dimension.\n        \n        The Storybook plugin only supports values in the following units:\n        - px, vh, vw, em, rem and %.\n        \n        You can either change the viewport for this story to use one of the supported units or skip the test by adding '!test' to the story's tags per https://storybook.js.org/docs/writing-stories/tags\n      `,\n    });\n  }\n}\n\nexport class ElementA11yParameterError extends StorybookError {\n  constructor() {\n    super({\n      name: 'ElementA11yParameterError',\n      category: Category.ADDON_A11Y,\n      code: 1,\n      documentation:\n        'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#a11y-addon-replace-element-parameter-with-context-parameter',\n      message:\n        'The \"element\" parameter in parameters.a11y has been removed. Use \"context\" instead.',\n    });\n  }\n}\n"
  },
  {
    "path": "code/core/src/router/README.md",
    "content": "# Storybook Router\n\nStorybook Router is a wrapper library for react-router.\nIt ensures a single version of the router is used everywhere.\nIt also includes some ready to use utils to read the path, query, viewMode and storyId from location.\n"
  },
  {
    "path": "code/core/src/router/index.ts",
    "content": "export * from './utils.ts';\nexport * from './router.tsx';\nexport * from './types.ts';\n"
  },
  {
    "path": "code/core/src/router/router.tsx",
    "content": "import React, { useCallback } from 'react';\nimport type { ComponentProps, ReactElement, ReactNode } from 'react';\n\nimport { global } from '@storybook/global';\n\nimport * as R from 'react-router-dom';\n\nimport type { LinkProps, NavigateOptions, RenderData } from './types.ts';\nimport { getMatch, parsePath, queryFromLocation } from './utils.ts';\n\nconst { document } = global;\n\ninterface MatchingData {\n  match: null | { path: string };\n}\n\ninterface LocationProps {\n  children: (renderData: RenderData) => any;\n}\n\ninterface MatchPropsStartsWith {\n  path: string;\n  startsWith: boolean;\n  children: (matchingData: MatchingData) => ReactNode;\n}\ninterface MatchPropsDefault {\n  path: RegExp;\n  startsWith: false;\n  children: (matchingData: MatchingData) => ReactNode;\n}\n\ninterface RoutePropsStartsWith {\n  path: string;\n  startsWith?: boolean;\n  children: ReactNode;\n}\ninterface RoutePropsDefault {\n  path: RegExp;\n  startsWith?: false;\n  children: ReactNode;\n}\n\nconst getBase = () => `${document.location.pathname}?`;\n\nexport const useNavigate = () => {\n  const navigate = R.useNavigate();\n\n  return useCallback((to: R.To | number, { plain, ...options } = {} as NavigateOptions) => {\n    if (typeof to === 'string' && to.startsWith('#')) {\n      if (to === '#') {\n        navigate(document.location.search);\n      } else {\n        document.location.hash = to;\n      }\n      return undefined;\n    }\n    if (typeof to === 'string') {\n      const target = plain ? to : `?path=${to}`;\n      return navigate(target, options);\n    }\n    if (typeof to === 'number') {\n      return navigate(to);\n    }\n\n    return undefined;\n  }, []);\n};\n\n/** A component that will navigate to a new location/path when clicked */\nexport const Link = ({ to, children, ...rest }: LinkProps) => (\n  <R.Link to={`${getBase()}path=${to}`} {...rest}>\n    {children}\n  </R.Link>\n);\nLink.displayName = 'QueryLink';\n\n/**\n * A render-prop component where children is called with a location and will be called whenever it\n * changes\n */\nexport const Location = ({ children }: LocationProps) => {\n  const location = R.useLocation();\n  const { path, singleStory } = queryFromLocation(location);\n  const { viewMode, storyId, refId } = parsePath(path);\n\n  return (\n    <>\n      {children({\n        path: path || '/',\n        location,\n        viewMode,\n        storyId,\n        refId,\n        singleStory: singleStory === 'true',\n      })}\n    </>\n  );\n};\nLocation.displayName = 'QueryLocation';\n\n/**\n * A render-prop component for rendering when a certain path is hit. It's immensely similar to\n * `Location` but it receives an addition data property: `match`. match has a truthy value when the\n * path is hit.\n */\nfunction Match(props: MatchPropsStartsWith): ReactElement;\nfunction Match(props: MatchPropsDefault): ReactElement;\nfunction Match({\n  children,\n  path: targetPath,\n  startsWith = false,\n}: MatchPropsStartsWith | MatchPropsDefault) {\n  return (\n    <Location>\n      {({ path: urlPath, ...rest }) =>\n        children({\n          match: getMatch(urlPath, targetPath, startsWith),\n          ...rest,\n        })\n      }\n    </Location>\n  );\n}\nMatch.displayName = 'QueryMatch';\n\n/** A component to conditionally render children based on matching a target path */\nfunction Route(props: RoutePropsDefault): ReactElement;\nfunction Route(props: RoutePropsStartsWith): ReactElement;\nfunction Route(input: RoutePropsDefault | RoutePropsStartsWith) {\n  const { children, ...rest } = input;\n  if (rest.startsWith === undefined) {\n    rest.startsWith = false;\n  }\n\n  const matchProps = rest as Omit<ComponentProps<typeof Match>, 'children'>;\n\n  return <Match {...matchProps}>{({ match }) => (match ? children : null)}</Match>;\n}\nRoute.displayName = 'Route';\n\nexport { Route, Match };\n\nexport const LocationProvider: typeof R.BrowserRouter = (...args) => R.BrowserRouter(...args);\nexport const BaseLocationProvider: typeof R.Router = (...args) => R.Router(...args);\nexport const MemoryRouter: typeof R.MemoryRouter = (...args) => R.MemoryRouter(...args);\n"
  },
  {
    "path": "code/core/src/router/types.ts",
    "content": "import type { ReactNode } from 'react';\n\nimport type * as R from 'react-router-dom';\n\nimport type { StoryData } from './utils.ts';\n\nexport interface Other extends StoryData {\n  path: string;\n  singleStory?: boolean;\n}\n\nexport type NavigateOptions = R.NavigateOptions & { plain?: boolean };\n\nexport type NavigateFunction = (to: R.To | number, options?: NavigateOptions) => void;\n\nexport type RouterData = {\n  location: Partial<R.Location>;\n  navigate: NavigateFunction;\n} & Other;\n\nexport type RenderData = Pick<RouterData, 'location'> & Other;\n\nexport interface LinkProps {\n  to: string;\n  children: ReactNode;\n}\n"
  },
  {
    "path": "code/core/src/router/utils.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { DEEPLY_EQUAL, buildArgsParam, deepDiff, getMatch, parsePath } from './utils.ts';\n\nvi.mock('storybook/internal/client-logger', () => ({\n  once: { warn: vi.fn() },\n}));\n\ndescribe('getMatch', () => {\n  it('gets startsWithTarget match', () => {\n    const output = getMatch('/foo/bar', '/foo', true);\n\n    expect(output).toEqual({\n      path: '/foo/bar',\n    });\n  });\n\n  it('gets currentIsTarget match', () => {\n    const output = getMatch('/foo', '/foo', false);\n\n    expect(output).toEqual({\n      path: '/foo',\n    });\n  });\n\n  it('gets matchTarget match', () => {\n    const output = getMatch('/foo', '/f.+', false);\n\n    expect(output).toEqual({\n      path: '/foo',\n    });\n  });\n\n  it('returns null match', () => {\n    const output = getMatch('/foo/bar', '/foo/baz', true);\n\n    expect(output).toBe(null);\n  });\n\n  it('returns null match if \"startsWith\" part is in the middle', () => {\n    const output = getMatch('/foo/bar', '/bar', true);\n\n    expect(output).toBe(null);\n  });\n});\n\ndescribe('parsePath', () => {\n  it('should work without path', () => {\n    const output = parsePath(undefined);\n\n    expect(output).toEqual({\n      viewMode: undefined,\n      storyId: undefined,\n      refId: undefined,\n    });\n  });\n\n  it('should parse /foo/bar correctly', () => {\n    const output = parsePath('/foo/bar');\n\n    expect(output).toMatchObject({\n      viewMode: 'foo',\n      storyId: 'bar',\n    });\n  });\n\n  it('should parse /foo/bar/x correctly', () => {\n    const output = parsePath('/foo/bar/x');\n\n    expect(output).toMatchObject({\n      viewMode: 'foo',\n      storyId: 'bar',\n    });\n  });\n\n  it('should parse /viewMode/refId_story--id correctly', () => {\n    const output = parsePath('/viewMode/refId_story--id');\n\n    expect(output).toMatchObject({\n      viewMode: 'viewmode',\n      storyId: 'story--id',\n      refId: 'refid',\n    });\n  });\n});\n\ndescribe('deepDiff', () => {\n  it('returns DEEPLY_EQUAL when the values are deeply equal', () => {\n    expect(deepDiff({ foo: [{ bar: 1 }] }, { foo: [{ bar: 1 }] })).toBe(DEEPLY_EQUAL);\n  });\n\n  it('returns the update when the types are different', () => {\n    expect(deepDiff(true, 1)).toBe(1);\n  });\n\n  it('returns a sparse array when updating an array', () => {\n    expect(deepDiff([1, 2], [1, 3])).toStrictEqual([, 3]);\n  });\n\n  it('returns undefined for removed array values', () => {\n    expect(deepDiff([1, 2], [1])).toStrictEqual([, undefined]);\n  });\n\n  it('returns a longer array when adding to an array', () => {\n    expect(deepDiff([1, 2], [1, 2, 3])).toStrictEqual([, , 3]);\n  });\n\n  it('returns a partial when updating an object', () => {\n    expect(deepDiff({ foo: 1, bar: 2 }, { foo: 1, bar: 3 })).toStrictEqual({ bar: 3 });\n  });\n\n  it('returns undefined for omitted object properties', () => {\n    expect(deepDiff({ foo: 1, bar: 2 }, { foo: 1 })).toStrictEqual({ bar: undefined });\n  });\n\n  it('traverses into objects', () => {\n    expect(deepDiff({ foo: { bar: [1, 2], baz: [3, 4] } }, { foo: { bar: [3] } })).toStrictEqual({\n      foo: { bar: [3, undefined], baz: undefined },\n    });\n  });\n});\n\ndescribe('buildArgsParam', () => {\n  it('builds a simple key-value pair', () => {\n    const param = buildArgsParam({}, { key: 'val' });\n    expect(param).toEqual('key:val');\n  });\n\n  it('builds multiple values', () => {\n    const param = buildArgsParam({}, { one: '1', two: '2', three: '3' });\n    expect(param).toEqual('one:1;two:2;three:3');\n  });\n\n  it('builds booleans', () => {\n    const param = buildArgsParam({}, { yes: true, no: false });\n    expect(param).toEqual('yes:!true;no:!false');\n  });\n\n  it('builds arrays', () => {\n    const param = buildArgsParam({}, { arr: ['1', '2', '3'] });\n    expect(param).toEqual('arr[0]:1;arr[1]:2;arr[2]:3');\n  });\n\n  it('builds sparse arrays', () => {\n    const param = buildArgsParam({}, { arr: ['1', , '3'] });\n    expect(param).toEqual('arr[0]:1;arr[2]:3');\n  });\n\n  it('builds simple objects', () => {\n    const param = buildArgsParam({}, { obj: { one: '1', two: '2' } });\n    expect(param).toEqual('obj.one:1;obj.two:2');\n  });\n\n  it('builds nested objects', () => {\n    const param = buildArgsParam({}, { obj: { foo: { one: '1', two: '2' }, bar: { one: '1' } } });\n    expect(param).toEqual('obj.foo.one:1;obj.foo.two:2;obj.bar.one:1');\n  });\n\n  it('builds arrays in objects', () => {\n    const param = buildArgsParam({}, { obj: { foo: ['1', , '3'] } });\n    expect(param).toEqual('obj.foo[0]:1;obj.foo[2]:3');\n  });\n\n  it('builds single object in array', () => {\n    const param = buildArgsParam({}, { arr: [{ one: '1', two: '2' }] });\n    expect(param).toEqual('arr[0].one:1;arr[0].two:2');\n  });\n\n  it('builds multiple objects in array', () => {\n    const param = buildArgsParam({}, { arr: [{ one: '1' }, { two: '2' }] });\n    expect(param).toEqual('arr[0].one:1;arr[1].two:2');\n  });\n\n  it('builds nested object in array', () => {\n    const param = buildArgsParam({}, { arr: [{ foo: { bar: 'val' } }] });\n    expect(param).toEqual('arr[0].foo.bar:val');\n  });\n\n  it('encodes space as +', () => {\n    const param = buildArgsParam({}, { key: 'foo bar baz' });\n    expect(param).toEqual('key:foo+bar+baz');\n  });\n\n  it('encodes null values as !null', () => {\n    const param = buildArgsParam({}, { key: null });\n    expect(param).toEqual('key:!null');\n  });\n\n  it('encodes nested null values as !null', () => {\n    const param = buildArgsParam({}, { foo: { bar: [{ key: null }], baz: null } });\n    expect(param).toEqual('foo.bar[0].key:!null;foo.baz:!null');\n  });\n\n  it('encodes hex color values as !hex(value)', () => {\n    const param = buildArgsParam({}, { key: '#ff4785' });\n    expect(param).toEqual('key:!hex(ff4785)');\n  });\n\n  it('encodes rgba color values by prefixing and compacting', () => {\n    const param = buildArgsParam({}, { rgb: 'rgb(255, 71, 133)', rgba: 'rgba(255, 71, 133, 0.5)' });\n    expect(param).toEqual('rgb:!rgb(255,71,133);rgba:!rgba(255,71,133,0.5)');\n  });\n\n  it('encodes hsla color values by prefixing and compacting', () => {\n    const param = buildArgsParam({}, { hsl: 'hsl(45, 99%, 70%)', hsla: 'hsla(45, 99%, 70%, 0.5)' });\n    expect(param).toEqual('hsl:!hsl(45,99,70);hsla:!hsla(45,99,70,0.5)');\n  });\n\n  it('encodes Date objects as !date(ISO string)', () => {\n    const param = buildArgsParam({}, { key: new Date('2001-02-03T04:05:06.789Z') });\n    expect(param).toEqual('key:!date(2001-02-03T04:05:06.789Z)');\n  });\n\n  describe('with initial state', () => {\n    it('omits unchanged values', () => {\n      const param = buildArgsParam({ one: 1 }, { one: 1, two: 2 });\n      expect(param).toEqual('two:2');\n    });\n\n    it('omits unchanged object properties', () => {\n      const param = buildArgsParam({ obj: { one: 1 } }, { obj: { one: 1, two: 2 } });\n      expect(param).toEqual('obj.two:2');\n    });\n\n    it('sets !undefined for removed array values', () => {\n      const param = buildArgsParam({ arr: [1] }, { arr: [] });\n      expect(param).toEqual('arr[0]:!undefined');\n    });\n\n    it('sets !undefined for removed object properties', () => {\n      const param = buildArgsParam({ obj: { one: 1 } }, { obj: {} });\n      expect(param).toEqual('obj.one:!undefined');\n    });\n\n    it('omits unchanged array values (yielding sparse arrays)', () => {\n      const param = buildArgsParam({ arr: [1, 2, 3] }, { arr: [1, 3, 4] });\n      expect(param).toEqual('arr[1]:3;arr[2]:4');\n    });\n\n    it('omits nested unchanged object properties and array values', () => {\n      const param = buildArgsParam(\n        { obj: { nested: [{ one: 1 }, { two: 2 }] } },\n        { obj: { nested: [{ one: 1 }, { two: 2, three: 3 }] } }\n      );\n      expect(param).toEqual('obj.nested[1].three:3');\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/router/utils.ts",
    "content": "import { once } from 'storybook/internal/client-logger';\n\nimport { isEqual as deepEqual, isPlainObject } from 'es-toolkit/predicate';\nimport memoize from 'memoizerific';\nimport type { Options as QueryOptions } from 'picoquery';\nimport { parse, stringify } from 'picoquery';\nimport { dedent } from 'ts-dedent';\n\nexport interface StoryData {\n  viewMode?: string;\n  storyId?: string;\n  refId?: string;\n}\n\nconst splitPathRegex = /\\/([^/]+)\\/(?:(.*)_)?([^/]+)?/;\n\nexport const parsePath: (path: string | undefined) => StoryData = memoize(1000)((\n  path: string | undefined | null\n) => {\n  const result: StoryData = {\n    viewMode: undefined,\n    storyId: undefined,\n    refId: undefined,\n  };\n\n  if (path) {\n    const [, viewMode, refId, storyId] = path.toLowerCase().match(splitPathRegex) || [];\n    if (viewMode) {\n      Object.assign(result, {\n        viewMode,\n        storyId,\n        refId,\n      });\n    }\n  }\n  return result;\n});\n\ninterface Args {\n  [key: string]: any;\n}\n\nexport const DEEPLY_EQUAL = Symbol('Deeply equal');\nexport const deepDiff = (value: any, update: any): any => {\n  if (typeof value !== typeof update) {\n    return update;\n  }\n\n  if (deepEqual(value, update)) {\n    return DEEPLY_EQUAL;\n  }\n  if (Array.isArray(value) && Array.isArray(update)) {\n    const res = update.reduce((acc, upd, index) => {\n      const diff = deepDiff(value[index], upd);\n\n      if (diff !== DEEPLY_EQUAL) {\n        acc[index] = diff;\n      }\n      return acc;\n    }, new Array(update.length));\n\n    if (update.length >= value.length) {\n      return res;\n    }\n    return res.concat(new Array(value.length - update.length).fill(undefined));\n  }\n  if (isPlainObject(value) && isPlainObject(update)) {\n    return Object.keys({ ...value, ...update }).reduce((acc, key) => {\n      const diff = deepDiff(value?.[key], update?.[key]);\n      return diff === DEEPLY_EQUAL ? acc : Object.assign(acc, { [key]: diff });\n    }, {});\n  }\n  return update;\n};\n\n// Keep this in sync with validateArgs in core-client/src/preview/parseArgsParam.ts\nconst VALIDATION_REGEXP = /^[a-zA-Z0-9 _-]*$/;\nconst NUMBER_REGEXP = /^-?[0-9]+(\\.[0-9]+)?$/;\nconst HEX_REGEXP = /^#([a-f0-9]{3,4}|[a-f0-9]{6}|[a-f0-9]{8})$/i;\nconst COLOR_REGEXP =\n  /^(rgba?|hsla?)\\(([0-9]{1,3}),\\s?([0-9]{1,3})%?,\\s?([0-9]{1,3})%?,?\\s?([0-9](\\.[0-9]{1,2})?)?\\)$/i;\nconst validateArgs = (key = '', value: unknown): boolean => {\n  if (key === null) {\n    return false;\n  }\n\n  if (key === '' || !VALIDATION_REGEXP.test(key)) {\n    return false;\n  }\n\n  if (value === null || value === undefined) {\n    return true;\n  } // encoded as `!null` or `!undefined` // encoded as `!null` or `!undefined`\n\n  // encoded as `!null` or `!undefined`\n  if (value instanceof Date) {\n    return true;\n  } // encoded as modified ISO string // encoded as modified ISO string\n\n  // encoded as modified ISO string\n  if (typeof value === 'number' || typeof value === 'boolean') {\n    return true;\n  }\n  if (typeof value === 'string') {\n    return (\n      VALIDATION_REGEXP.test(value) ||\n      NUMBER_REGEXP.test(value) ||\n      HEX_REGEXP.test(value) ||\n      COLOR_REGEXP.test(value)\n    );\n  }\n  if (Array.isArray(value)) {\n    return value.every((v) => validateArgs(key, v));\n  }\n\n  if (isPlainObject(value)) {\n    return Object.entries(value as Record<string, any>).every(([k, v]) => validateArgs(k, v));\n  }\n  return false;\n};\n\n// Note this isn't a picoquery serializer because pq will turn any object\n// into a nested key internally. So we need to deal witth things like `Date`\n// up front.\nconst encodeSpecialValues = (value: unknown): any => {\n  if (value === undefined) {\n    return '!undefined';\n  }\n\n  if (value === null) {\n    return '!null';\n  }\n  if (typeof value === 'string') {\n    if (HEX_REGEXP.test(value)) {\n      return `!hex(${value.slice(1)})`;\n    }\n\n    if (COLOR_REGEXP.test(value)) {\n      return `!${value.replace(/[\\s%]/g, '')}`;\n    }\n    return value;\n  }\n\n  if (typeof value === 'boolean') {\n    return `!${value}`;\n  }\n\n  if (value instanceof Date) {\n    return `!date(${value.toISOString()})`;\n  }\n\n  if (Array.isArray(value)) {\n    return value.map(encodeSpecialValues);\n  }\n\n  if (isPlainObject(value)) {\n    return Object.entries(value as Record<string, any>).reduce(\n      (acc, [key, val]) => Object.assign(acc, { [key]: encodeSpecialValues(val) }),\n      {}\n    );\n  }\n  return value;\n};\n\n// Replaces some url-encoded characters with their decoded equivalents.\n// The URI RFC specifies these should be encoded, but all browsers will\n// tolerate them being decoded, so we opt to go with it for cleaner looking\n// URIs.\nconst decodeKnownQueryChar = (chr: string) => {\n  switch (chr) {\n    case '%20':\n      return '+';\n    case '%5B':\n      return '[';\n    case '%5D':\n      return ']';\n    case '%2C':\n      return ',';\n    case '%3A':\n      return ':';\n  }\n  return chr;\n};\nconst knownQueryChar = /%[0-9A-F]{2}/g;\n\nexport const buildArgsParam = (initialArgs: Args | undefined, args: Args): string => {\n  const update = deepDiff(initialArgs, args);\n\n  if (!update || update === DEEPLY_EQUAL) {\n    return '';\n  }\n\n  const object = Object.entries(update).reduce((acc, [key, value]) => {\n    if (validateArgs(key, value)) {\n      return Object.assign(acc, { [key]: value });\n    }\n    once.warn(dedent`\n      Omitted potentially unsafe URL args.\n\n      More info: https://storybook.js.org/docs/writing-stories/args?ref=error#setting-args-through-the-url\n    `);\n    return acc;\n  }, {} as Args);\n\n  return stringify(encodeSpecialValues(object), {\n    delimiter: ';', // we don't actually create multiple query params\n    nesting: true,\n    nestingSyntax: 'js', // encode objects using dot notation: obj.key=val\n  })\n    .replace(knownQueryChar, decodeKnownQueryChar)\n    .split(';')\n    .map((part: string) => part.replace('=', ':'))\n    .join(';');\n};\n\ninterface Query {\n  [key: string]: any;\n}\n\nconst queryFromString = memoize(1000)((s?: string): Query => (s !== undefined ? parse(s) : {}));\n\nexport const queryFromLocation = (location?: Partial<Location>) => {\n  return queryFromString(location?.search ? location.search.slice(1) : '');\n};\n\nexport const stringifyQuery = (query: Query) => {\n  const queryStr = stringify(query);\n  return queryStr ? '?' + queryStr : '';\n};\n\ntype Match = { path: string };\n\nexport const getMatch = memoize(1000)((\n  current: string,\n  target: string | RegExp,\n  startsWith = true\n): Match | null => {\n  if (startsWith) {\n    if (typeof target !== 'string') {\n      throw new Error('startsWith only works with string targets');\n    }\n    const startsWithTarget = current && current.startsWith(target);\n    if (startsWithTarget) {\n      return { path: current };\n    }\n\n    return null;\n  }\n\n  const currentIsTarget = typeof target === 'string' && current === target;\n  const matchTarget = current && target && current.match(target);\n\n  if (currentIsTarget || matchTarget) {\n    return { path: current };\n  }\n\n  return null;\n});\n"
  },
  {
    "path": "code/core/src/server-errors.ts",
    "content": "import picocolors from 'picocolors';\nimport { dedent } from 'ts-dedent';\n\nimport type { Status } from './shared/status-store/index.ts';\nimport type { StatusTypeId } from './shared/status-store/index.ts';\nimport { StorybookError } from './storybook-error.ts';\n\nexport { StorybookError } from './storybook-error.ts';\n\n/**\n * If you can't find a suitable category for your error, create one based on the package name/file\n * path of which the error is thrown. For instance: If it's from `@storybook/node-logger`, then\n * NODE-LOGGER If it's from a package that is too broad, e.g. @storybook/cli in the init command,\n * then use a combination like CLI_INIT\n */\nexport enum Category {\n  CLI = 'CLI',\n  CLI_INIT = 'CLI_INIT',\n  CLI_AUTOMIGRATE = 'CLI_AUTOMIGRATE',\n  CLI_UPGRADE = 'CLI_UPGRADE',\n  CLI_ADD = 'CLI_ADD',\n  CODEMOD = 'CODEMOD',\n  CORE_SERVER = 'CORE-SERVER',\n  CSF_PLUGIN = 'CSF-PLUGIN',\n  CSF_TOOLS = 'CSF-TOOLS',\n  CORE_COMMON = 'CORE-COMMON',\n  NODE_LOGGER = 'NODE-LOGGER',\n  TELEMETRY = 'TELEMETRY',\n  BUILDER_MANAGER = 'BUILDER-MANAGER',\n  BUILDER_VITE = 'BUILDER-VITE',\n  BUILDER_WEBPACK5 = 'BUILDER-WEBPACK5',\n  SOURCE_LOADER = 'SOURCE-LOADER',\n  POSTINSTALL = 'POSTINSTALL',\n  DOCS_TOOLS = 'DOCS-TOOLS',\n  CORE_WEBPACK = 'CORE-WEBPACK',\n  FRAMEWORK_ANGULAR = 'FRAMEWORK_ANGULAR',\n  FRAMEWORK_EMBER = 'FRAMEWORK_EMBER',\n  FRAMEWORK_HTML_VITE = 'FRAMEWORK_HTML-VITE',\n  FRAMEWORK_HTML_WEBPACK5 = 'FRAMEWORK_HTML-WEBPACK5',\n  FRAMEWORK_NEXTJS = 'FRAMEWORK_NEXTJS',\n  FRAMEWORK_PREACT_VITE = 'FRAMEWORK_PREACT-VITE',\n  FRAMEWORK_PREACT_WEBPACK5 = 'FRAMEWORK_PREACT-WEBPACK5',\n  FRAMEWORK_REACT_VITE = 'FRAMEWORK_REACT-VITE',\n  FRAMEWORK_REACT_WEBPACK5 = 'FRAMEWORK_REACT-WEBPACK5',\n  FRAMEWORK_SERVER_WEBPACK5 = 'FRAMEWORK_SERVER-WEBPACK5',\n  FRAMEWORK_SVELTE_VITE = 'FRAMEWORK_SVELTE-VITE',\n  FRAMEWORK_SVELTEKIT = 'FRAMEWORK_SVELTEKIT',\n  FRAMEWORK_VUE_VITE = 'FRAMEWORK_VUE-VITE',\n  FRAMEWORK_VUE_WEBPACK5 = 'FRAMEWORK_VUE-WEBPACK5',\n  FRAMEWORK_VUE3_VITE = 'FRAMEWORK_VUE3-VITE',\n  FRAMEWORK_VUE3_WEBPACK5 = 'FRAMEWORK_VUE3-WEBPACK5',\n  FRAMEWORK_WEB_COMPONENTS_VITE = 'FRAMEWORK_WEB-COMPONENTS-VITE',\n  FRAMEWORK_WEB_COMPONENTS_WEBPACK5 = 'FRAMEWORK_WEB-COMPONENTS-WEBPACK5',\n}\n\nexport class NxProjectDetectedError extends StorybookError {\n  constructor() {\n    super({\n      name: 'NxProjectDetectedError',\n      category: Category.CLI_INIT,\n      code: 1,\n      documentation: 'https://nx.dev/nx-api/storybook#generating-storybook-configuration',\n      message: dedent`\n        We have detected Nx in your project. Nx has its own Storybook initializer, so please use it instead.\n        Run \"nx g @nx/storybook:configuration <your-project-name>\" to add Storybook to a given Nx app or lib.`,\n    });\n  }\n}\n\nexport class MissingFrameworkFieldError extends StorybookError {\n  constructor() {\n    super({\n      name: 'MissingFrameworkFieldError',\n      category: Category.CORE_COMMON,\n      code: 1,\n      documentation:\n        'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#new-framework-api',\n      message: dedent`\n        Could not find a 'framework' field in Storybook config.\n        \n        Please run 'npx storybook automigrate' to automatically fix your config.`,\n    });\n  }\n}\n\nexport class InvalidFrameworkNameError extends StorybookError {\n  constructor(public data: { frameworkName: string }) {\n    super({\n      name: 'InvalidFrameworkNameError',\n      category: Category.CORE_COMMON,\n      code: 2,\n      documentation:\n        'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#new-framework-api',\n      message: dedent`\n        Invalid value of '${data.frameworkName}' in the 'framework' field of Storybook config.\n        \n        Please run 'npx storybook automigrate' to automatically fix your config.\n      `,\n    });\n  }\n}\n\nexport class CouldNotEvaluateFrameworkError extends StorybookError {\n  constructor(public data: { frameworkName: string }) {\n    super({\n      name: 'CouldNotEvaluateFrameworkError',\n      category: Category.CORE_COMMON,\n      code: 3,\n      documentation: '',\n      message: dedent`\n        Could not evaluate the '${data.frameworkName}' package from the 'framework' field of Storybook config.\n        \n        Are you sure it's a valid package and is installed?`,\n    });\n  }\n}\n\n// this error is not used anymore, but we keep it to maintain unique its error code\n// which is used for telemetry\nexport class ConflictingStaticDirConfigError extends StorybookError {\n  constructor() {\n    super({\n      name: 'ConflictingStaticDirConfigError',\n      category: Category.CORE_SERVER,\n      code: 1,\n      documentation:\n        'https://storybook.js.org/docs/configure/integration/images-and-assets#serving-static-files-via-storybook-configuration',\n      message: dedent`\n        Storybook encountered a conflict when trying to serve statics. You have configured both:\n        * Storybook's option in the config file: 'staticDirs'\n        * Storybook's (deprecated) CLI flag: '--staticDir' or '-s'\n        \n        Please remove the CLI flag from your storybook script and use only the 'staticDirs' option instead.`,\n    });\n  }\n}\n\nexport class InvalidStoriesEntryError extends StorybookError {\n  constructor() {\n    super({\n      name: 'InvalidStoriesEntryError',\n      category: Category.CORE_COMMON,\n      code: 4,\n      documentation:\n        'https://storybook.js.org/docs/faq#can-i-have-a-storybook-with-no-local-stories',\n      message: dedent`\n        Storybook could not index your stories.\n        Your main configuration does not contain a 'stories' field, or it resolved to an empty array.\n        \n        Please check your main configuration file and make sure it exports a 'stories' field that is not an empty array.`,\n    });\n  }\n}\n\nexport class WebpackMissingStatsError extends StorybookError {\n  constructor() {\n    super({\n      name: 'WebpackMissingStatsError',\n      category: Category.BUILDER_WEBPACK5,\n      code: 1,\n      documentation: [\n        'https://webpack.js.org/configuration/stats/',\n        'https://storybook.js.org/docs/builders/webpack#configure',\n      ],\n      message: dedent`\n        No Webpack stats found. Did you turn off stats reporting in your Webpack config?\n        Storybook needs Webpack stats (including errors) in order to build correctly.`,\n    });\n  }\n}\n\nexport class WebpackInvocationError extends StorybookError {\n  constructor(\n    public data: {\n      error: Error;\n    }\n  ) {\n    super({\n      name: 'WebpackInvocationError',\n      category: Category.BUILDER_WEBPACK5,\n      code: 2,\n      message: data.error.message.trim(),\n    });\n  }\n}\n\nfunction removeAnsiEscapeCodes(input = '') {\n  return input.replace(/\\u001B\\[[0-9;]*m/g, '');\n}\n\nexport class WebpackCompilationError extends StorybookError {\n  constructor(\n    public data: {\n      errors: {\n        message: string;\n        stack?: string;\n        name?: string;\n      }[];\n    }\n  ) {\n    data.errors = data.errors.map((err) => {\n      return {\n        ...err,\n        message: removeAnsiEscapeCodes(err.message),\n        stack: removeAnsiEscapeCodes(err.stack),\n        name: err.name,\n      };\n    });\n\n    super({\n      name: 'WebpackCompilationError',\n      category: Category.BUILDER_WEBPACK5,\n      code: 3,\n      // This error message is a followup of errors logged by Webpack to the user\n      message: dedent`\n        There were problems when compiling your code with Webpack.\n        Run Storybook with --debug-webpack for more information.\n      `,\n    });\n  }\n}\n\nexport class MissingAngularJsonError extends StorybookError {\n  constructor(\n    public data: {\n      path: string;\n    }\n  ) {\n    super({\n      name: 'MissingAngularJsonError',\n      category: Category.CLI_INIT,\n      code: 2,\n      documentation: 'https://storybook.js.org/docs/faq#error-no-angularjson-file-found?ref=error',\n      message: dedent`\n        An angular.json file was not found in the current working directory: ${data.path}\n        Storybook needs it to work properly, so please rerun the command at the root of your project, where the angular.json file is located.`,\n    });\n  }\n}\n\nexport class AngularLegacyBuildOptionsError extends StorybookError {\n  constructor() {\n    super({\n      name: 'AngularLegacyBuildOptionsError',\n      category: Category.FRAMEWORK_ANGULAR,\n      code: 1,\n      documentation: [\n        'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#angular-drop-support-for-calling-storybook-directly',\n        'https://github.com/storybookjs/storybook/tree/next/code/frameworks/angular#how-do-i-migrate-to-an-angular-storybook-builder',\n      ],\n      message: dedent`\n        Your Storybook startup script uses a solution that is not supported anymore.\n        You must use Angular builder to have an explicit configuration on the project used in angular.json.\n        \n        Please run 'npx storybook automigrate' to automatically fix your config.`,\n    });\n  }\n}\n\nexport class CriticalPresetLoadError extends StorybookError {\n  constructor(\n    public data: {\n      error: Error;\n      presetName: string;\n    }\n  ) {\n    super({\n      name: 'CriticalPresetLoadError',\n      category: Category.CORE_SERVER,\n      code: 2,\n      documentation: '',\n      message: dedent`\n        Storybook failed to load the following preset: ${data.presetName}.\n        \n        Please check whether your setup is correct, the Storybook dependencies (and their peer dependencies) are installed correctly and there are no package version clashes.\n        \n        If you believe this is a bug, please open an issue on Github.\n        \n        ${data.error.stack || data.error.message}`,\n    });\n  }\n}\n\nexport class MissingBuilderError extends StorybookError {\n  constructor() {\n    super({\n      name: 'MissingBuilderError',\n      category: Category.CORE_SERVER,\n      code: 3,\n      documentation: 'https://github.com/storybookjs/storybook/issues/24071',\n      message: dedent`\n        Storybook could not find a builder configuration for your project. \n        Builders normally come from a framework package e.g. '@storybook/react-vite', or from builder packages e.g. '@storybook/builder-vite'.\n        \n        - Does your main config file contain a 'framework' field configured correctly?\n        - Is the Storybook framework package installed correctly?\n        - If you don't use a framework, does your main config contain a 'core.builder' configured correctly?\n        - Are you in a monorepo and perhaps the framework package is hoisted incorrectly?\n        \n        If you believe this is a bug, please describe your issue in detail on Github.`,\n    });\n  }\n}\n\nexport class GoogleFontsDownloadError extends StorybookError {\n  constructor(public data: { fontFamily: string; url: string }) {\n    super({\n      name: 'GoogleFontsDownloadError',\n      category: Category.FRAMEWORK_NEXTJS,\n      code: 1,\n      documentation:\n        'https://storybook.js.org/docs/get-started/frameworks/nextjs#nextjs-font-optimization',\n      message: dedent`\n        Failed to fetch \\`${data.fontFamily}\\` from Google Fonts with URL: \\`${data.url}\\``,\n    });\n  }\n}\n\nexport class GoogleFontsLoadingError extends StorybookError {\n  constructor(public data: { error: unknown | Error; url: string }) {\n    super({\n      name: 'GoogleFontsLoadingError',\n      category: Category.FRAMEWORK_NEXTJS,\n      code: 2,\n      documentation:\n        'https://storybook.js.org/docs/get-started/frameworks/nextjs#nextjs-font-optimization',\n      message: dedent`\n        An error occurred when trying to load Google Fonts with URL \\`${data.url}\\`.\n        \n        ${data.error instanceof Error ? data.error.message : ''}`,\n    });\n  }\n}\n\nexport class SvelteViteWithSvelteKitError extends StorybookError {\n  constructor() {\n    super({\n      name: 'SvelteViteWithSvelteKitError',\n      category: Category.FRAMEWORK_SVELTE_VITE,\n      code: 1,\n      documentation:\n        'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#sveltekit-needs-the-storybooksveltekit-framework',\n      message: dedent`\n        We've detected a SvelteKit project using the @storybook/svelte-vite framework, which is not supported.\n        Please use the @storybook/sveltekit framework instead.`,\n    });\n  }\n}\n\nexport class NoMatchingExportError extends StorybookError {\n  constructor(public data: { error: unknown | Error }) {\n    super({\n      name: 'NoMatchingExportError',\n      category: Category.CORE_SERVER,\n      code: 4,\n      documentation: '',\n      message: dedent`\n        There was an exports mismatch error when trying to build Storybook.\n        Please check whether the versions of your Storybook packages match whenever possible, as this might be the cause.\n        \n        Problematic example:\n        { \"@storybook/react\": \"7.5.3\", \"@storybook/react-vite\": \"7.4.5\", \"storybook\": \"7.3.0\" }\n        \n        Correct example:\n        { \"@storybook/react\": \"7.5.3\", \"@storybook/react-vite\": \"7.5.3\", \"storybook\": \"7.5.3\" }\n        \n        Please run \\`npx storybook doctor\\` for guidance on how to fix this issue.`,\n    });\n  }\n}\n\nexport class MainFileMissingError extends StorybookError {\n  constructor(public data: { location: string; source?: 'storybook' | 'vitest' }) {\n    const map = {\n      storybook: {\n        helperMessage:\n          'You can pass a --config-dir flag to tell Storybook, where your main.js|ts file is located at.',\n        documentation: 'https://storybook.js.org/docs/configure?ref=error',\n      },\n      vitest: {\n        helperMessage:\n          'You can pass a configDir plugin option to tell where your main.js|ts file is located at.',\n        // TODO: add proper docs once available\n        documentation: 'https://storybook.js.org/docs/configure?ref=error',\n      },\n    };\n    const { documentation, helperMessage } = map[data.source || 'storybook'];\n    super({\n      name: 'MainFileMissingError',\n      category: Category.CORE_SERVER,\n      code: 6,\n      documentation,\n      message: dedent`\n        No configuration files have been found in your configDir: ${picocolors.yellow(data.location)}.\n        Storybook needs a \"main.js|ts\" file, please add it.\n        \n        ${helperMessage}`,\n    });\n  }\n}\n\nexport class MainFileEvaluationError extends StorybookError {\n  constructor(public data: { location: string; error: Error }) {\n    const errorText = picocolors.white(\n      (data.error.stack || data.error.message).replaceAll(process.cwd(), '')\n    );\n\n    super({\n      name: 'MainFileEvaluationError',\n      category: Category.CORE_SERVER,\n      code: 7,\n      message: dedent`\n        Storybook couldn't evaluate your ${picocolors.yellow(data.location)} file.\n        \n        Original error:\n        ${errorText}`,\n    });\n  }\n}\n\nexport class StatusTypeIdMismatchError extends StorybookError {\n  constructor(\n    public data: {\n      status: Status;\n      typeId: StatusTypeId;\n    }\n  ) {\n    super({\n      name: 'StatusTypeIdMismatchError',\n      category: Category.CORE_SERVER,\n      code: 16,\n      message: `Status has typeId \"${data.status.typeId}\" but was added to store with typeId \"${data.typeId}\". Full status: ${JSON.stringify(\n        data.status,\n        null,\n        2\n      )}`,\n    });\n  }\n}\n\nexport class GenerateNewProjectOnInitError extends StorybookError {\n  constructor(\n    public data: { error: unknown | Error; packageManager: string; projectType: string }\n  ) {\n    super({\n      name: 'GenerateNewProjectOnInitError',\n      category: Category.CLI_INIT,\n      code: 3,\n      documentation: '',\n      message: dedent`\n        There was an error while using ${data.packageManager} to create a new ${\n          data.projectType\n        } project.\n        \n        ${data.error instanceof Error ? data.error.message : ''}`,\n    });\n  }\n}\n\nexport class AddonVitestPostinstallPrerequisiteCheckError extends StorybookError {\n  constructor(public data: { reasons: string[] }) {\n    super({\n      name: 'AddonVitestPostinstallPrerequisiteCheckError',\n      category: Category.CLI_INIT,\n      isHandledError: true,\n      code: 4,\n      documentation: '',\n      message: 'The prerequisite check for the Vitest addon failed.',\n    });\n  }\n}\n\nexport class AddonVitestPostinstallFailedAddonA11yError extends StorybookError {\n  constructor(public data: { error: unknown | Error }) {\n    super({\n      name: 'AddonVitestPostinstallFailedAddonA11yError',\n      message: \"The @storybook/addon-a11y couldn't be set up for the Vitest addon\",\n      category: Category.CLI_INIT,\n      isHandledError: true,\n      code: 6,\n    });\n  }\n}\n\nexport class AddonVitestPostinstallWorkspaceUpdateError extends StorybookError {\n  constructor(public data: { filePath: string }) {\n    super({\n      name: 'AddonVitestPostinstallWorkspaceUpdateError',\n      category: Category.CLI_INIT,\n      isHandledError: true,\n      code: 8,\n      documentation: `https://storybook.js.org/docs/writing-tests/integrations/vitest-addon#manual-setup-advanced`,\n      message: dedent`\n        Could not update existing Vitest workspace file: ${data.filePath}\n        Please refer to the documentation to complete the setup manually.\n      `,\n    });\n  }\n}\n\nexport class AddonVitestPostinstallConfigUpdateError extends StorybookError {\n  constructor(public data: { filePath: string }) {\n    super({\n      name: 'AddonVitestPostinstallConfigUpdateError',\n      category: Category.CLI_INIT,\n      isHandledError: true,\n      code: 9,\n      documentation: `https://storybook.js.org/docs/writing-tests/integrations/vitest-addon#manual-setup-advanced`,\n      message: dedent`\n        Unable to update existing Vitest config file: ${data.filePath}\n        Please refer to the documentation to complete the setup manually.\n      `,\n    });\n  }\n}\n\nexport class AddonVitestPostinstallError extends StorybookError {\n  constructor(public data: { errors: StorybookError[] }) {\n    super({\n      name: 'AddonVitestPostinstallError',\n      category: Category.CLI_INIT,\n      isHandledError: true,\n      code: 5,\n      message: 'The Vitest addon setup failed.',\n      subErrors: data.errors,\n    });\n  }\n}\n\nexport class UpgradeStorybookToLowerVersionError extends StorybookError {\n  constructor(public data: { beforeVersion: string; currentVersion: string }) {\n    super({\n      name: 'UpgradeStorybookToLowerVersionError',\n      category: Category.CLI_UPGRADE,\n      code: 3,\n      message: dedent`\n        You are trying to upgrade Storybook to a lower version than the version currently installed. This is not supported.\n        \n        Storybook version ${data.beforeVersion} was detected in your project, but you are trying to \"upgrade\" to version ${data.currentVersion}.\n        \n        This usually happens when running the upgrade command without a version specifier, e.g. \"npx storybook upgrade\".\n        This will cause npm to run the globally cached storybook binary, which might be an older version.\n        \n        Instead you should always run the Storybook CLI with a version specifier to force npm to download the latest version:\n        \n        \"npx storybook@latest upgrade\"`,\n    });\n  }\n}\n\nexport class UpgradeStorybookUnknownCurrentVersionError extends StorybookError {\n  constructor() {\n    super({\n      name: 'UpgradeStorybookUnknownCurrentVersionError',\n      category: Category.CLI_UPGRADE,\n      code: 5,\n      message: dedent`\n        We couldn't determine the current version of Storybook in your project.\n        \n        Are you running the Storybook CLI in a project without Storybook?\n        It might help if you specify your Storybook config directory with the --config-dir flag.`,\n    });\n  }\n}\n\nexport class NoStatsForViteDevError extends StorybookError {\n  constructor() {\n    super({\n      name: 'NoStatsForViteDevError',\n      category: Category.BUILDER_VITE,\n      code: 1,\n      message: dedent`\n        Unable to write preview stats as the Vite builder does not support stats in dev mode.\n        \n        Please remove the \\`--stats-json\\` flag when running in dev mode.`,\n    });\n  }\n}\n\nexport class ViteModuleGraphSubscriptionError extends StorybookError {\n  constructor() {\n    super({\n      name: 'ViteModuleGraphSubscriptionError',\n      category: Category.BUILDER_VITE,\n      code: 2,\n      message: 'Vite module graph listeners must be registered before the builder starts.',\n    });\n  }\n}\n\nexport class FindPackageVersionsError extends StorybookError {\n  constructor(\n    public data: { error: Error | unknown; packageName: string; packageManager: string }\n  ) {\n    super({\n      name: 'FindPackageVersionsError',\n      category: Category.CLI,\n      code: 1,\n      message: dedent`\n        Unable to find versions of \"${data.packageName}\" using ${data.packageManager}\n        ${data.error && `Reason: ${data.error}`}`,\n    });\n  }\n}\n\nexport class IncompatiblePostCssConfigError extends StorybookError {\n  constructor(public data: { error: Error }) {\n    super({\n      name: 'IncompatiblePostCssConfigError',\n      category: Category.FRAMEWORK_NEXTJS,\n      code: 3,\n      message: dedent`\n        Incompatible PostCSS configuration format detected.\n\n        Next.js uses an array-based format for plugins which is not compatible with Vite:\n        \n        // ❌ Incompatible format (used by Next.js)\n        const config = {\n          plugins: [\"@tailwindcss/postcss\"],\n        };\n        \n        Please transform your PostCSS config to use the object-based format, which is compatible with Next.js and Vite:\n        \n        // ✅ Compatible format (works with Next.js and Vite)\n        const config = {\n          plugins: {\n            \"@tailwindcss/postcss\": {},\n          },\n        };\n        \n        Original error: ${data.error.message}\n      `,\n    });\n  }\n}\n\nexport class SavingGlobalSettingsFileError extends StorybookError {\n  constructor(public data: { filePath: string; error: Error | unknown }) {\n    super({\n      name: 'SavingGlobalSettingsFileError',\n      category: Category.CORE_SERVER,\n      code: 1,\n      message: dedent`\n        Unable to save global settings file to ${data.filePath}\n        ${data.error && `Reason: ${data.error}`}`,\n    });\n  }\n}\n\nexport class CommonJsConfigNotSupportedError extends StorybookError {\n  constructor() {\n    super({\n      name: 'CommonJsConfigNotSupportedError',\n      category: Category.CLI_AUTOMIGRATE,\n      code: 1,\n      documentation: 'https://storybook.js.org/docs/configure/overview?ref=error#es-modules',\n      message: dedent`\n        Support for CommonJS Storybook config files has been removed in Storybook 10.0.0.\n        Please migrate your config to a valid ESM file.\n        \n        CommonJS files (ending in .cjs, .cts, .cjsx, .ctsx) or files containing 'module.exports' are no longer supported.\n        Please convert your config to use ES modules (import/export syntax).`,\n    });\n  }\n}\n\nexport class AutomigrateError extends StorybookError {\n  constructor(public data: { errors: Array<Error | unknown> }) {\n    super({\n      name: 'AutomigrateError',\n      category: Category.CLI_AUTOMIGRATE,\n      code: 2,\n      message: dedent`\n        An error occurred while running the automigrate command.\n      `,\n    });\n  }\n}\n"
  },
  {
    "path": "code/core/src/shared/checklist-store/checklistData.state.ts",
    "content": "import type { StoreState } from './index.ts';\n\nexport const initialState = {\n  items: {\n    accessibilityTests: { status: 'open' },\n    autodocs: { status: 'open' },\n    ciTests: { status: 'open' },\n    controls: { status: 'open' },\n    coverage: { status: 'open' },\n    guidedTour: { status: 'open' },\n    installA11y: { status: 'open' },\n    installChromatic: { status: 'open' },\n    installDocs: { status: 'open' },\n    installVitest: { status: 'open' },\n    mdxDocs: { status: 'open' },\n    moreComponents: { status: 'open' },\n    moreStories: { status: 'open' },\n    onboardingSurvey: { status: 'open' },\n    organizeStories: { status: 'open' },\n    publishStorybook: { status: 'open' },\n    renderComponent: { status: 'open' },\n    runTests: { status: 'open' },\n    viewports: { status: 'open' },\n    visualTests: { status: 'open' },\n    whatsNewStorybook10: { status: 'open' },\n    writeInteractions: { status: 'open' },\n  },\n  widget: {},\n} as const satisfies StoreState;\n"
  },
  {
    "path": "code/core/src/shared/checklist-store/checklistData.tsx",
    "content": "import type { ComponentProps } from 'react';\nimport React from 'react';\n\nimport { Link, SyntaxHighlighter } from 'storybook/internal/components';\nimport {\n  PREVIEW_INITIALIZED,\n  STORY_ARGS_UPDATED,\n  STORY_FINISHED,\n  STORY_INDEX_INVALIDATED,\n  UPDATE_GLOBALS,\n} from 'storybook/internal/core-events';\nimport {\n  type API_IndexHash,\n  type API_PreparedIndexEntry,\n  type API_StoryEntry,\n} from 'storybook/internal/types';\n\nimport { type API, Tag, addons, internal_universalTestProviderStore } from 'storybook/manager-api';\nimport { ThemeProvider, convert, styled, themes } from 'storybook/theming';\n\nimport { ADDON_ID as ADDON_A11Y_ID } from '../../../../addons/a11y/src/constants.ts';\nimport {\n  ADDON_ONBOARDING_CHANNEL,\n  ADDON_ID as ADDON_ONBOARDING_ID,\n} from '../../../../addons/onboarding/src/constants.ts';\nimport {\n  ADDON_ID as ADDON_TEST_ID,\n  STORYBOOK_ADDON_TEST_CHANNEL,\n} from '../../../../addons/vitest/src/constants.ts';\nimport { SUPPORTED_FRAMEWORKS } from '../../cli/AddonVitestService.constants.ts';\nimport { ADDON_ID as ADDON_DOCS_ID } from '../../docs-tools/shared.ts';\nimport { TourGuide } from '../../manager/components/TourGuide/TourGuide.tsx';\nimport { LocationMonitor } from '../../manager/hooks/useLocation.ts';\nimport type { initialState } from './checklistData.state.ts';\n\nconst CodeWrapper = styled.div(({ theme }) => ({\n  alignSelf: 'stretch',\n  background: theme.background.content,\n  borderRadius: theme.appBorderRadius,\n  margin: '5px 0',\n  padding: 10,\n  fontSize: theme.typography.size.s1,\n  '.linenumber': {\n    opacity: 0.5,\n  },\n}));\n\nconst CodeSnippet = (props: ComponentProps<typeof SyntaxHighlighter>) => (\n  <ThemeProvider theme={convert(themes.dark)}>\n    <CodeWrapper>\n      <SyntaxHighlighter {...props} />\n    </CodeWrapper>\n  </ThemeProvider>\n);\n\ntype ItemId = keyof (typeof initialState)['items'];\n\nexport interface ChecklistData {\n  sections: readonly {\n    id: string;\n    title: string;\n    items: readonly {\n      /** Unique identifier for persistence. Update when making significant changes. */\n      id: ItemId;\n\n      /** Display name. Keep it short and actionable (with a verb). */\n      label: string;\n\n      /** Description of the criteria that must be met to complete the item. */\n      criteria: string;\n\n      /** Items that must be completed before this item can be completed (locked until then). */\n      after?: readonly ItemId[];\n\n      /** What to do after the item is completed (prevent undo or hide the item). */\n      afterCompletion?: 'immutable' | 'unavailable';\n\n      /**\n       * Function to check if the item should be available (displayed in the checklist). Called any\n       * time the index is updated.\n       */\n      available?: (args: {\n        api: API;\n        index: API_IndexHash | undefined;\n        item: ChecklistData['sections'][number]['items'][number];\n      }) => boolean;\n\n      /** Function returning content to display in the checklist item's collapsible area. */\n      content?: (args: { api: API }) => React.ReactNode;\n\n      /** Action button to be displayed when item is not completed. */\n      action?: {\n        label: string;\n        onClick: (args: { api: API; accept: () => void }) => void;\n      };\n\n      /**\n       * Function to subscribe to events and update the item's state. May return a function to\n       * unsubscribe once the item is completed.\n       */\n      subscribe?: (args: {\n        api: API;\n        item: ChecklistData['sections'][number]['items'][number];\n\n        /**\n         * Call this to complete the item and persist to user-local storage. This is preferred when\n         * dealing with user-specific criteria (e.g. learning goals).\n         */\n        accept: () => void;\n\n        /**\n         * Call this to complete the item and persist to project-local storage. This is preferred\n         * when dealing with project-specific criteria (e.g. component count).\n         */\n        done: () => void;\n\n        /** Call this to skip the item and persist to user-local storage. */\n        skip: () => void;\n      }) => void | (() => void);\n    }[];\n  }[];\n}\n\nconst isExample = (id: string) =>\n  id.startsWith('example-') || id.startsWith('configure-your-project--');\n\nconst subscribeToIndex: (\n  condition: (entries: Record<string, API_PreparedIndexEntry>) => boolean\n) => ChecklistData['sections'][number]['items'][number]['subscribe'] =\n  (condition) =>\n  ({ api, done }) => {\n    const check = () =>\n      condition(\n        Object.entries(api.getIndex()?.entries || {}).reduce(\n          (acc, [id, entry]) => (isExample(entry.id) ? acc : Object.assign(acc, { [id]: entry })),\n          {} as Record<string, API_PreparedIndexEntry>\n        )\n      );\n    if (check()) {\n      done();\n    } else {\n      api.once(PREVIEW_INITIALIZED, () => check() && done());\n      return api.on(STORY_INDEX_INVALIDATED, () => check() && done());\n    }\n  };\n\nexport const checklistData = {\n  sections: [\n    {\n      id: 'basics',\n      title: 'Storybook basics',\n      items: [\n        {\n          id: 'guidedTour',\n          label: 'Take the guided tour',\n          available: ({ index }) =>\n            !!index &&\n            'example-button--primary' in index &&\n            !!globalThis?.FEATURES?.controls &&\n            addons.experimental_getRegisteredAddons().includes(ADDON_ONBOARDING_ID),\n          criteria: 'Guided tour is completed',\n          subscribe: ({ api, accept }) =>\n            api.on(ADDON_ONBOARDING_CHANNEL, ({ step, type }) => {\n              if (type !== 'dismiss' && ['6:IntentSurvey', '7:FinishedOnboarding'].includes(step)) {\n                accept();\n              }\n            }),\n          action: {\n            label: 'Start',\n            onClick: ({ api }) => {\n              api.toggleNav(true);\n              const path = api.getUrlState().path || '';\n              if (path.startsWith('/story/')) {\n                document.location.href = `/?path=${path}&onboarding=true`;\n              } else {\n                document.location.href = `/?onboarding=true`;\n              }\n            },\n          },\n        },\n        {\n          id: 'onboardingSurvey',\n          label: 'Complete the onboarding survey',\n          available: () => addons.experimental_getRegisteredAddons().includes(ADDON_ONBOARDING_ID),\n          afterCompletion: 'immutable',\n          criteria: 'Onboarding survey is completed',\n          subscribe: ({ api, accept }) =>\n            api.on(ADDON_ONBOARDING_CHANNEL, ({ type }) => type === 'survey' && accept()),\n          action: {\n            label: 'Open',\n            onClick: ({ api }) => {\n              const path = api.getUrlState().path || '';\n              document.location.href = `/?path=${path}&onboarding=survey`;\n            },\n          },\n        },\n        {\n          id: 'renderComponent',\n          label: 'Render your first component',\n          criteria: 'A story finished rendering successfully',\n          subscribe: ({ api, done }) =>\n            api.on(\n              STORY_FINISHED,\n              ({ storyId, status }) => status === 'success' && !isExample(storyId) && done()\n            ),\n          content: ({ api }) => (\n            <>\n              <p>\n                Storybook renders your components in isolation, using stories. That allows you to\n                work on the bit of UI you need, without worrying about the rest of the app.\n              </p>\n              <p>\n                Rendering your components can often require{' '}\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'writing-stories/decorators',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                >\n                  setting up surrounding context in decorators\n                </Link>{' '}\n                or{' '}\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'configure/styling-and-css',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                >\n                  applying global styles\n                </Link>\n                . Once you&apos;ve got it working for one component, you&apos;re ready to make\n                Storybook the home for all of your UI.\n              </p>\n              <p>\n                Stories are written in CSF, a format specifically designed to help with UI\n                development. Here&apos;s an example:\n              </p>\n              {/* TODO: Non-React snippets? TS vs. JS? */}\n              <CodeSnippet language=\"typescript\">\n                {`// Button.stories.ts\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n \nimport { Button } from './Button';\n \nconst meta = {\n  // 👇 The component you're working on\n  component: Button,\n} satisfies Meta<typeof Button>;\n \nexport default meta;\n// 👇 Type helper to reduce boilerplate \ntype Story = StoryObj<typeof meta>;\n\n// 👇 A story named Primary that renders \\`<Button primary label=\"Button\" />\\`\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};`}\n              </CodeSnippet>\n              <p>\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'writing-stories',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                  withArrow\n                >\n                  Learn more about stories\n                </Link>\n              </p>\n            </>\n          ),\n        },\n        {\n          id: 'moreComponents',\n          label: 'Add 5 components',\n          content: ({ api }) => (\n            <>\n              <p>\n                Storybook gets better as you add more components. Start with the easy ones, like\n                Button or Avatar, and work your way up to more complex components, like Select,\n                Autocomplete, or even full pages.\n              </p>\n              <img\n                src={api.getDocsUrl({\n                  asset: 'onboarding/sidebar-components.png',\n                  ref: 'guide',\n                })}\n                alt=\"Components in the sidebar\"\n              />\n              <p>\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'get-started/whats-a-story#create-a-new-story',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                  withArrow\n                >\n                  Learn how to add components without writing any code\n                </Link>\n              </p>\n            </>\n          ),\n          criteria: 'At least 5 components exist in the index',\n          subscribe: subscribeToIndex((entries) => {\n            const stories = Object.values(entries).filter(\n              (entry): entry is API_StoryEntry => entry.type === 'story'\n            );\n            const components = new Set(stories.map(({ title }) => title));\n            return components.size >= 5;\n          }),\n        },\n        {\n          id: 'moreStories',\n          label: 'Add 20 stories',\n          content: ({ api }) => (\n            <>\n              <p>\n                More stories for your components means better documentation and more test coverage.\n              </p>\n              <img\n                src={api.getDocsUrl({\n                  asset: 'onboarding/sidebar-many-stories.png',\n                  ref: 'guide',\n                })}\n                alt=\"Stories in the sidebar\"\n              />\n              <p>\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'essentials/controls#creating-and-editing-stories-from-controls',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                  withArrow\n                >\n                  Learn how to use Controls to add stories without writing any code\n                </Link>\n              </p>\n            </>\n          ),\n          criteria: 'At least 20 stories exist in the index',\n          subscribe: subscribeToIndex((entries) => {\n            const stories = Object.values(entries).filter(\n              (entry): entry is API_StoryEntry => entry.type === 'story'\n            );\n            return stories.length >= 20;\n          }),\n        },\n        {\n          id: 'whatsNewStorybook10',\n          label: \"See what's new\",\n          criteria: \"What's New page is opened\",\n          action: {\n            label: 'Go',\n            onClick: ({ api }) => api.navigate('/settings/whats-new'),\n          },\n          subscribe: ({ accept }) =>\n            LocationMonitor.subscribe((l) => l.search.endsWith('/settings/whats-new') && accept()),\n        },\n      ],\n    },\n\n    {\n      id: 'development',\n      title: 'Development',\n      items: [\n        {\n          id: 'controls',\n          label: 'Change a story with Controls',\n          available: () => !!globalThis?.FEATURES?.controls,\n          criteria: 'Story args are updated',\n          subscribe: ({ api, done }) => api.on(STORY_ARGS_UPDATED, done),\n          content: ({ api }) => (\n            <>\n              <p>\n                When you change the value of one of the inputs in the Controls table, the story\n                automatically updates to reflect that change. It&apos;s a great way to explore how a\n                component handles various inputs.\n              </p>\n              <img\n                src={api.getDocsUrl({\n                  asset: 'api/doc-block-controls.png',\n                  ref: 'guide',\n                })}\n                alt=\"Screenshot of Controls block\"\n              />\n              <strong>Take it further</strong>\n              <p>\n                Read the{' '}\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'essentials/controls',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                >\n                  Controls documentation\n                </Link>{' '}\n                to learn:\n              </p>\n              <ul>\n                <li>How to use the Controls panel to edit or save a new story</li>\n                <li>How to configure the table</li>\n              </ul>\n            </>\n          ),\n        },\n        {\n          id: 'viewports',\n          label: 'Check responsiveness with Viewports',\n          available: () => !!globalThis?.FEATURES?.viewport,\n          criteria: 'Viewport global is updated',\n          subscribe: ({ api, done }) =>\n            api.on(UPDATE_GLOBALS, ({ globals }) => globals?.viewport && done()),\n          content: ({ api }) => (\n            <>\n              <p>\n                Many UI components need to be responsive to the viewport size. Storybook has\n                built-in support for previewing stories in various device sizes.\n              </p>\n              <img\n                src={api.getDocsUrl({\n                  asset: 'onboarding/viewports-menu.png',\n                  ref: 'guide',\n                })}\n                alt=\"Screenshot of Viewports menu\"\n              />\n              <strong>Take it further</strong>\n              <p>\n                Read the{' '}\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'essentials/viewport',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                >\n                  Viewports documentation\n                </Link>{' '}\n                to learn:\n              </p>\n              <ul>\n                <li>How to configure which viewports are available</li>\n                <li>\n                  How to force a story to <em>always</em> render in a specific viewport\n                </li>\n              </ul>\n            </>\n          ),\n        },\n        {\n          id: 'organizeStories',\n          label: 'Group your components',\n          criteria: 'A root node exists in the index',\n          subscribe: subscribeToIndex((entries) =>\n            Object.values(entries).some(({ title }) => title.includes('/'))\n          ),\n          content: ({ api }) => (\n            <>\n              <p>\n                It&apos;s helpful for projects to organize their sidebar into groups. We&apos;re big\n                fans of Atomic Design (atoms, molecules, organisms, pages), but we've also seen\n                organization by domain (profile, billing, dashboard, etc). Being organized helps\n                everyone use your Storybook more effectively.\n              </p>\n              <p>You can create a section like so:</p>\n              <CodeSnippet language=\"typescript\">\n                {`// Button.stories.js\n\nexport default {\n  component: Button,\n-  title: 'Button', // You may not have this\n+  title: 'Atoms/Button',\n}`}\n              </CodeSnippet>\n              <p>Which would look like:</p>\n              <img\n                src={api.getDocsUrl({\n                  asset: 'onboarding/sidebar-with-groups.png',\n                  ref: 'guide',\n                })}\n                alt=\"Grouped components in the sidebar\"\n              />\n              <strong>Take it further</strong>\n              <p>\n                Read the{' '}\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'writing-stories/naming-components-and-hierarchy',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                >\n                  story organization documentation\n                </Link>{' '}\n                to learn:\n              </p>\n              <ul>\n                <li>The full hierarchy available</li>\n                <li>How to configure the sorting of your stories</li>\n              </ul>\n            </>\n          ),\n        },\n      ],\n    },\n\n    {\n      id: 'testing',\n      title: 'Testing',\n      items: [\n        {\n          id: 'installVitest',\n          label: 'Install Vitest addon',\n          afterCompletion: 'unavailable',\n          available: () =>\n            !!globalThis.STORYBOOK_FRAMEWORK &&\n            SUPPORTED_FRAMEWORKS.includes(globalThis.STORYBOOK_FRAMEWORK),\n          criteria: '@storybook/addon-vitest registered in .storybook/main.js|ts',\n          subscribe: ({ done }) => {\n            if (addons.experimental_getRegisteredAddons().includes(ADDON_TEST_ID)) {\n              done();\n            }\n          },\n          content: ({ api }) => (\n            <>\n              <p>\n                Run this command to install the Vitest addon, enabling you to run component tests on\n                your stories inside Storybook’s UI:\n              </p>\n              <CodeSnippet language=\"bash\">{`npx storybook add @storybook/addon-vitest`}</CodeSnippet>\n              <p>\n                <em>Restart your Storybook after installing the addon.</em>\n              </p>\n              <img\n                src={api.getDocsUrl({\n                  asset: 'writing-tests/testing-ui-overview.png',\n                  ref: 'guide',\n                })}\n                alt=\"Storybook app with story status indicators, testing widget, and addon panel annotated\"\n              />\n              <p>\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'writing-tests/integrations/vitest-addon',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                  withArrow\n                >\n                  Learn more about the Vitest addon\n                </Link>\n              </p>\n            </>\n          ),\n        },\n        {\n          id: 'runTests',\n          after: ['installVitest'],\n          label: 'Test your components',\n          criteria: 'Component tests are run from the test widget in the sidebar',\n          subscribe: ({ done }) =>\n            internal_universalTestProviderStore.onStateChange((state) => {\n              if (state['storybook/test'] === 'test-provider-state:running') {\n                TourGuide.render(null);\n                done();\n              }\n            }),\n          action: {\n            label: 'Start',\n            onClick: ({ api }) => {\n              api.toggleNav(true);\n              TourGuide.render({\n                // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n                // @ts-ignore Circular reference in Step type\n                steps: [\n                  {\n                    title: 'Testing widget',\n                    content:\n                      'Run tests right from your Storybook sidebar using the testing widget.',\n                    placement: 'right-end',\n                    target: '#storybook-testing-module',\n                    highlight: '#storybook-testing-module',\n                    onNext: ({ next }: { next: () => void }) => {\n                      const toggle = document.getElementById('testing-module-collapse-toggle');\n                      if (toggle?.getAttribute('aria-label') === 'Expand testing module') {\n                        toggle.click();\n                        setTimeout(next, 300);\n                      } else {\n                        next();\n                      }\n                    },\n                  },\n                  {\n                    title: 'Start a test run',\n                    content: 'Start a test run at the click of a button using Vitest.',\n                    placement: 'right',\n                    target:\n                      '[data-module-id=\"storybook/test/test-provider\"] button[aria-label=\"Start test run\"]',\n                    highlight: `[data-module-id=\"storybook/test/test-provider\"] button[aria-label=\"Start test run\"]`,\n                    hideNextButton: true,\n                  },\n                ],\n              });\n            },\n          },\n          content: ({ api }) => (\n            <>\n              <p>\n                Stories make great test cases. You can quickly test all of your stories directly\n                from the test widget, at the bottom of the sidebar.\n              </p>\n              <img\n                src={api.getDocsUrl({\n                  asset: 'onboarding/test-widget-with-failures.png',\n                  ref: 'guide',\n                })}\n                alt=\"Test widget showing test failures\"\n              />\n\n              <p>\n                Use the menu on a story or component to see details about a test failure or run\n                tests for just that selection.\n              </p>\n              <img\n                src={api.getDocsUrl({\n                  asset: 'writing-tests/context-menu.png',\n                  ref: 'guide',\n                })}\n                alt=\"Screenshot of story sidebar item with open menu\"\n              />\n              <strong>Take it further</strong>\n              <p>\n                Read the{' '}\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'writing-tests#component-tests',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                >\n                  component testing documentation\n                </Link>{' '}\n                to learn:\n              </p>\n              <ul>\n                <li>About helpful features, like watch mode and sidebar filtering</li>\n                <li>How to run tests via CLI and in CI</li>\n                <li>\n                  About other capabilities, like accessibility checks and code coverage reporting\n                </li>\n              </ul>\n            </>\n          ),\n        },\n        {\n          id: 'writeInteractions',\n          label: 'Test functionality with interactions',\n          available: () => !!globalThis?.FEATURES?.interactions,\n          criteria: 'At least one story with a play or test function',\n          subscribe: subscribeToIndex((entries) =>\n            Object.values(entries).some(\n              (entry) => entry.tags?.includes(Tag.PLAY_FN) || entry.tags?.includes(Tag.TEST_FN)\n            )\n          ),\n          content: ({ api }) => (\n            <>\n              <p>\n                When you need to test non-visual or particularly complex behavior of a component,\n                add a play function.\n              </p>\n              <CodeSnippet language=\"typescript\">\n                {`// Button.stories.ts\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\nimport { expect, fn } from 'storybook/test';\n \nimport { Button } from './Button';\n \nconst meta = {\n  component: Button,\n  args: {\n    // 👇 Provide a mock function to spy on\n    onClick: fn(),\n  },\n} satisfies Meta<typeof Button>;\n \nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Disabled: Story = {\n  args: {\n    disabled: true,\n    label: 'Button',\n  },\n  play: async function({ args, canvas, userEvent }) {\n    const button = canvas.getByRole('button', { name: /button/i });\n\t\t\n    // 👇 Simulate behavior\n    await userEvent.click(button);\n    \n    // 👇 Make assertions\n    await expect(button).toHaveAttribute('aria-disabled', 'true');\n    await expect(args.onClick).not.toHaveBeenCalled();\n  }\n};`}\n              </CodeSnippet>\n              <p>\n                You can interact with and debug each step defined in a play function within the\n                Interactions panel.\n              </p>\n              <img\n                src={api.getDocsUrl({\n                  asset: 'writing-tests/interaction-test-pass.png',\n                  ref: 'guide',\n                })}\n                alt=\"Storybook with a LoginForm component and passing interactions in the Interactions panel\"\n              />\n              <strong>Take it further</strong>\n              <p>\n                Read the{' '}\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'writing-tests/interaction-testing',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                >\n                  interaction testing documentation\n                </Link>{' '}\n                to learn:\n              </p>\n              <ul>\n                <li>\n                  The full <code>play</code> function API\n                </li>\n                <li>How to run code before and after tests</li>\n                <li>How to group interactions into steps</li>\n              </ul>\n            </>\n          ),\n        },\n        {\n          id: 'installA11y',\n          label: 'Install Accessibility addon',\n          afterCompletion: 'unavailable',\n          criteria: '@storybook/addon-a11y registered in .storybook/main.js|ts',\n          subscribe: ({ done }) => {\n            if (addons.experimental_getRegisteredAddons().includes(ADDON_A11Y_ID)) {\n              done();\n            }\n          },\n          content: ({ api }) => (\n            <>\n              <p>\n                Accessibility tests help ensure your UI is usable by everyone, no matter their\n                ability.\n              </p>\n              <p>\n                If you are not yet using the accessibility addon, run this command to install and\n                set it up, enabling you to run accessibility checks alongside your component tests:\n              </p>\n              <CodeSnippet language=\"bash\">{`npx storybook add @storybook/addon-a11y`}</CodeSnippet>\n              <p>\n                <em>Restart your Storybook after installing the addon.</em>\n              </p>\n              <p>\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'writing-tests/accessibility-testing',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                  withArrow\n                >\n                  Learn more about the Accessibility addon\n                </Link>\n              </p>\n            </>\n          ),\n        },\n        {\n          id: 'accessibilityTests',\n          after: ['installA11y'],\n          label: 'Run accessibility tests',\n          criteria: 'Accessibility tests are run from the test widget in the sidebar',\n          subscribe: ({ api, done }) =>\n            api.on(\n              STORYBOOK_ADDON_TEST_CHANNEL,\n              ({ type, payload }) => type === 'test-run-completed' && payload.config.a11y && done()\n            ),\n          content: ({ api }) => (\n            <>\n              <p>\n                Expand the test widget, check the Accessibility checkbox, and click the Run\n                component tests button.\n              </p>\n              <img\n                src={api.getDocsUrl({\n                  asset: 'writing-tests/test-widget-a11y-enabled.png',\n                  ref: 'guide',\n                })}\n                alt=\"Testing widget with accessibility activated\"\n              />\n              <p>\n                If there are any failures, you can use the Accessibility panel to debug any\n                violations.\n              </p>\n              <img\n                src={api.getDocsUrl({\n                  asset: 'writing-tests/addon-a11y-debug-violations.png',\n                  ref: 'guide',\n                })}\n                alt=\"Storybook app with accessibility panel open, showing violations and an interactive popover on the violating elements in the preview\"\n              />\n              <strong>Take it further</strong>\n              <p>\n                Read the{' '}\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'writing-tests/accessibility-testing',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                >\n                  accessibility testing documentation\n                </Link>{' '}\n                to learn:\n              </p>\n              <ul>\n                <li>The recommended workflow</li>\n                <li>How to run accessibility tests via CLI and in CI</li>\n                <li>How to configure accessibility checks</li>\n              </ul>\n            </>\n          ),\n        },\n        {\n          id: 'installChromatic',\n          label: 'Install Visual Tests addon',\n          afterCompletion: 'unavailable',\n          available: () => true, // TODO check for compatibility with the project (not React Native)\n          criteria: '@chromatic-com/storybook registered in .storybook/main.js|ts',\n          subscribe: ({ done }) => {\n            if (addons.experimental_getRegisteredAddons().includes('chromaui/addon-visual-tests')) {\n              done();\n            }\n          },\n          content: ({ api }) => (\n            <>\n              <p>Visual tests verify the appearance of your UI components.</p>\n              <p>\n                If you are not yet using the visual tests addon, run this command to install and set\n                it up, enabling you to run visual tests on your stories (this requires a free\n                Chromatic account):\n              </p>\n              <CodeSnippet language=\"bash\">{`npx storybook add @chromatic-com/storybook`}</CodeSnippet>\n              <p>\n                <em>Restart your Storybook after installing the addon.</em>\n              </p>\n              <p>\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'writing-tests/visual-testing',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                  withArrow\n                >\n                  Learn more about the Visual Tests addon\n                </Link>\n              </p>\n            </>\n          ),\n        },\n        {\n          id: 'visualTests',\n          after: ['installChromatic'],\n          label: 'Run visual tests',\n          criteria:\n            'Visual tests are run from the test widget in the sidebar or the Visual Tests panel',\n          subscribe: ({ api, done }) => api.on('chromaui/addon-visual-tests/startBuild', done),\n          content: ({ api }) => (\n            <>\n              <p>Expand the test widget and click the Run visual tests button.</p>\n              <img\n                src={api.getDocsUrl({\n                  asset: 'writing-tests/test-widget-expanded-with-vta.png',\n                  ref: 'guide',\n                })}\n                alt=\"Expanded testing widget, showing the Visual tests section\"\n              />\n              <p>\n                You can use the Visual tests panel to verify the resulting diffs as either an\n                unexpected change which needs fixed or an expected change which can then be accepted\n                and become the new baseline.\n              </p>\n              <img\n                src={api.getDocsUrl({\n                  asset: 'writing-tests/vta-run-from-panel.png',\n                  ref: 'guide',\n                })}\n                alt=\"Visual tests addon panel showing a diff from the baseline\"\n              />\n              <strong>Take it further</strong>\n              <p>\n                Read the{' '}\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'writing-tests/visual-testing',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                >\n                  visual testing documentation\n                </Link>{' '}\n                to learn:\n              </p>\n              <ul>\n                <li>How to automate your visual tests in CI</li>\n              </ul>\n            </>\n          ),\n        },\n        {\n          id: 'coverage',\n          after: ['installVitest'],\n          label: 'Generate a coverage report',\n          criteria: 'Generate a coverage report',\n          subscribe: ({ api, done }) =>\n            api.on(\n              STORYBOOK_ADDON_TEST_CHANNEL,\n              ({ type, payload }) =>\n                type === 'test-run-completed' && payload.config.coverage && done()\n            ),\n          content: ({ api }) => (\n            <>\n              <p>\n                Coverage reports show you which code is&mdash;and, more importantly&mdash;isn&apos;t\n                executed while running your component tests. You use it to be sure you&apos;re\n                testing the right things.\n              </p>\n              <p>\n                To generate a coverage report, expand the test widget in the sidebar and check the\n                Coverage checkbox. The next time you run component tests, it will generate an\n                interactive report, which you can view by clicking the results summary in the test\n                widget.\n              </p>\n              <img\n                src={api.getDocsUrl({\n                  asset: 'writing-tests/test-widget-coverage-summary.png',\n                  ref: 'guide',\n                })}\n                alt=\"Test widget with coverage summary\"\n              />\n              <strong>Take it further</strong>\n              <p>\n                Read the{' '}\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'writing-tests/test-coverage',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                >\n                  test coverage documentation\n                </Link>{' '}\n                to learn:\n              </p>\n              <ul>\n                <li>How to automate reporting in CI</li>\n                <li>How to configure the coverage results</li>\n              </ul>\n            </>\n          ),\n        },\n        {\n          id: 'ciTests',\n          label: 'Automate tests in CI',\n          criteria: 'Have a CI workflow that runs component tests, either with Vitest or Chromatic',\n          content: ({ api }) => (\n            <>\n              <p>\n                Automating component tests in CI is the best tool ensuring the quality and\n                reliability of your project.\n              </p>\n              <p>\n                You can automate all of Storybook&apos;s tests by using Chromatic or by running the\n                <code>vitest --project storybook</code> command in your CI scripts.\n              </p>\n              <img\n                src={api.getDocsUrl({\n                  asset: 'writing-tests/test-ci-workflow-pr-status-checks.png',\n                  ref: 'guide',\n                })}\n                alt='GitHub pull request status checks, with a failing \"UI Tests / test\" check'\n              />\n              <strong>Take it further</strong>\n              <p>\n                Read the{' '}\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'writing-tests/in-ci',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                >\n                  testing in CI documentation\n                </Link>{' '}\n                to learn:\n              </p>\n              <ul>\n                <li>How to test in your CI platform (GitHub Actions, Circle CI, etc.)</li>\n                <li>How to debug test failures in a published Storybook</li>\n                <li>How to run your other Vitest tests alongside your Storybook tests</li>\n              </ul>\n            </>\n          ),\n        },\n      ],\n    },\n    {\n      id: 'document',\n      title: 'Document',\n      items: [\n        {\n          id: 'installDocs',\n          label: 'Install Docs addon',\n          afterCompletion: 'unavailable',\n          criteria: '@storybook/addon-docs registered in .storybook/main.js|ts',\n          subscribe: ({ done }) => {\n            if (addons.experimental_getRegisteredAddons().includes(ADDON_DOCS_ID)) {\n              done();\n            }\n          },\n          content: ({ api }) => (\n            <>\n              <p>\n                Storybook Docs transforms your Storybook stories into component documentation. Add\n                the Docs addon to your Storybook project to get started:\n              </p>\n              <CodeSnippet language=\"bash\">{`npx storybook add @storybook/addon-docs`}</CodeSnippet>\n              <p>\n                <em>Restart your Storybook after installing the addon.</em>\n              </p>\n              <p>\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'writing-docs',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                  withArrow\n                >\n                  Learn more about Storybook Docs\n                </Link>\n              </p>\n            </>\n          ),\n        },\n        {\n          id: 'autodocs',\n          after: ['installDocs'],\n          label: 'Automatically document your components',\n          criteria: 'At least one component with the autodocs tag applied',\n          subscribe: subscribeToIndex((entries) =>\n            Object.values(entries).some((entry) => entry.tags?.includes(Tag.AUTODOCS))\n          ),\n          content: ({ api }) => (\n            <>\n              <p>\n                Add the autodocs tag to a component&apos;s meta to automatically generate\n                documentation for that component, complete with examples, source code, an API table,\n                and a description.\n              </p>\n              <CodeSnippet language=\"typescript\">\n                {`// Button.stories.js\n\nconst meta = {\n  component: Button,\n  tags: ['autodocs'], // 👈 Add this tag\n}\n  \nexport default meta;`}\n              </CodeSnippet>\n              <p>\n                That tag can also be applied in <code>.storybook/preview.ts</code>, to generate\n                documentation for <em>all</em> components.\n              </p>\n              <img\n                src={api.getDocsUrl({\n                  asset: 'writing-docs/autodocs.png',\n                  ref: 'guide',\n                })}\n                alt=\"Storybook autodocs page, showing a title, description, primary story, controls table, and additional stories\"\n              />\n              <strong>Take it further</strong>\n              <p>\n                Read the{' '}\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'writing-docs/autodocs',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                >\n                  autodocs documentation\n                </Link>{' '}\n                to learn:\n              </p>\n              <ul>\n                <li>How to generate a table of contents</li>\n                <li>How to enhance your component documentation with JSDoc comments</li>\n                <li>How to customize the generated page</li>\n              </ul>\n            </>\n          ),\n        },\n        {\n          id: 'mdxDocs',\n          after: ['installDocs'],\n          label: 'Custom content with MDX',\n          criteria: 'At least one MDX page',\n          subscribe: subscribeToIndex((entries) =>\n            Object.values(entries).some((entry) => entry.type === 'docs')\n          ),\n          content: ({ api }) => (\n            <>\n              <p>\n                You can use MDX (markdown + React components) to provide an introduction to your\n                project, document things like design tokens, or go beyond the automatic\n                documentation for your components.\n              </p>\n              <p>\n                For a start, create an <code>introduction.mdx</code> file and (using markdown and\n                Storybook&apos;s{' '}\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'writing-docs/doc-blocks',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                >\n                  doc blocks\n                </Link>\n                ) write a usage guide for your project.\n              </p>\n              <CodeSnippet language=\"jsx\">\n                {`{ /* introduction.mdx */ }\nimport { Meta, Title, Subtitle } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Get started\" />\n \n<Title>Get started with My Awesome Project</Title>\n\n<Subtitle>It's really awesome</Subtitle>\n\nMy Awesome Project is designed to work with Your Awesome Project seamlessly.\nFollow this guide and you'll be ready in no time.\n\n## Install\n\n\\`\\`\\`sh\nnpm install @my/awesome-project\n\\`\\`\\``}\n              </CodeSnippet>\n              <strong>Take it further</strong>\n              <p>\n                Read the{' '}\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'writing-docs/mdx',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                >\n                  MDX documentation\n                </Link>{' '}\n                to learn:\n              </p>\n              <ul>\n                <li>How to reference stories in your content</li>\n                <li>How to import and display markdown files, such as READMEs</li>\n              </ul>\n            </>\n          ),\n        },\n        {\n          id: 'publishStorybook',\n          label: 'Publish your Storybook to share',\n          criteria: \"Have some form of `storybook build` in the project's CI config\",\n          content: ({ api }) => (\n            <>\n              <p>\n                Publishing your Storybook is easy and unlocks super clear review cycles and other\n                collaborative workflows.\n              </p>\n              <p>\n                Run <code>npx storybook build</code> in CI and deploy it using services like{' '}\n                <Link href=\"https://chromatic.com\" target=\"_blank\">\n                  Chromatic\n                </Link>\n                ,{' '}\n                <Link href=\"https://vercel.com\" target=\"_blank\" rel=\"noopener noreferrer\">\n                  Vercel\n                </Link>\n                , or{' '}\n                <Link href=\"https://www.netlify.com\" target=\"_blank\" rel=\"noopener noreferrer\">\n                  Netlify\n                </Link>\n                .\n              </p>\n              <img\n                src={api.getDocsUrl({\n                  asset: 'sharing/prbadge-publish.png',\n                  ref: 'guide',\n                })}\n                alt=\"PR check for publish action\"\n              />\n              <strong>Take it further</strong>\n              <p>\n                Read the{' '}\n                <Link\n                  href={api.getDocsUrl({\n                    subpath: 'sharing/publish-storybook',\n                    renderer: true,\n                    ref: 'guide',\n                  })}\n                  target=\"_blank\"\n                >\n                  publishing documentation\n                </Link>{' '}\n                to learn:\n              </p>\n              <ul>\n                <li>How to configure the built Storybook (e.g. performance optimizations)</li>\n                <li>How to use your published Storybook to collaborate with colleagues</li>\n              </ul>\n            </>\n          ),\n        },\n      ],\n    },\n  ],\n} as const satisfies ChecklistData;\n"
  },
  {
    "path": "code/core/src/shared/checklist-store/index.ts",
    "content": "import type { globalSettings } from '../../cli/globalSettings.ts';\nimport type { UniversalStore } from '../universal-store/index.ts';\nimport type { StoreOptions } from '../universal-store/types.ts';\nimport { initialState } from './checklistData.state.ts';\n\n/** ChecklistState is the persisted state, which may be incomplete */\nexport type ChecklistState = NonNullable<\n  Awaited<ReturnType<typeof globalSettings>>['value']['checklist']\n>;\n\n/** Store uses initialState to ensure all items are present */\nexport type StoreState = Required<Omit<ChecklistState, 'items'>> & {\n  items: NonNullable<Required<ChecklistState['items']>>;\n  loaded?: boolean;\n};\n\nexport type ItemId = keyof StoreState['items'];\nexport type ItemState = StoreState['items'][keyof StoreState['items']];\n\nexport type StoreEvent =\n  | { type: 'accept'; payload: ItemId }\n  | { type: 'done'; payload: ItemId }\n  | { type: 'skip'; payload: ItemId }\n  | { type: 'reset'; payload: ItemId }\n  | { type: 'mute'; payload: Array<ItemId> }\n  | { type: 'disable'; payload: boolean };\n\nexport const UNIVERSAL_CHECKLIST_STORE_OPTIONS: StoreOptions<StoreState> = {\n  id: 'storybook/checklist',\n  initialState,\n} as const;\n\nexport type ChecklistStoreEnvironment = 'server' | 'manager' | 'preview';\n\nexport const createChecklistStore = (\n  universalChecklistStore: UniversalStore<StoreState, StoreEvent>\n) => ({\n  getValue: (id: ItemId) =>\n    universalChecklistStore.getState().items[id] ?? { status: 'open', mutedAt: undefined },\n  accept: (id: ItemId) => {\n    universalChecklistStore.setState((state) => ({\n      ...state,\n      items: { ...state.items, [id]: { ...state.items[id], status: 'accepted' } },\n    }));\n  },\n  done: (id: ItemId) => {\n    universalChecklistStore.setState((state) => ({\n      ...state,\n      items: { ...state.items, [id]: { ...state.items[id], status: 'done' } },\n    }));\n  },\n  skip: (id: ItemId) => {\n    universalChecklistStore.setState((state) => ({\n      ...state,\n      items: { ...state.items, [id]: { ...state.items[id], status: 'skipped' } },\n    }));\n  },\n  reset: (id: ItemId) => {\n    universalChecklistStore.setState((state) => ({\n      ...state,\n      items: { ...state.items, [id]: { ...state.items[id], status: 'open' } },\n    }));\n  },\n  mute: (itemIds: Array<ItemId>) => {\n    universalChecklistStore.setState((state) => ({\n      ...state,\n      items: itemIds.reduce(\n        (acc, id) => ({ ...acc, [id]: { ...state.items[id], mutedAt: Date.now() } }),\n        state.items\n      ),\n    }));\n  },\n  disable: (value: boolean) => {\n    universalChecklistStore.setState((state) => ({\n      ...state,\n      widget: { ...state.widget, disable: value },\n      items: Object.entries(state.items).reduce(\n        (acc, [id, value]) => ({ ...acc, [id]: { ...value, mutedAt: undefined } }),\n        state.items\n      ),\n    }));\n  },\n});\n"
  },
  {
    "path": "code/core/src/shared/constants/environments-support.ts",
    "content": "import type { BuildOptions } from 'esbuild';\n\n// https://esbuild.github.io/api/#target\nexport const BROWSER_TARGETS: BuildOptions['target'] = [\n  'chrome131',\n  'edge134',\n  'firefox136',\n  'safari18.3',\n  'ios18.3',\n  'opera117',\n];\n\n// https://esbuild.github.io/api/#target\nexport const NODE_TARGET: BuildOptions['target'] = 'node20.19';\n\n// https://esbuild.github.io/api/#supported\nexport const SUPPORTED_FEATURES: BuildOptions['supported'] = {\n  // React Native does not support class static blocks without a specific babel plugin\n  'class-static-blocks': false,\n};\n"
  },
  {
    "path": "code/core/src/shared/constants/tags.ts",
    "content": "import type { API_PreparedIndexEntry } from '../../types/index.ts';\n\n/** System tags used throughout Storybook for categorizing and filtering stories and docs entries. */\nexport const Tag = {\n  /** Indicates that autodocs should be generated for this component */\n  AUTODOCS: 'autodocs',\n  /** MDX documentation attached to a component's stories file */\n  ATTACHED_MDX: 'attached-mdx',\n  /** Standalone MDX documentation not attached to stories */\n  UNATTACHED_MDX: 'unattached-mdx',\n  /** Story has a play function */\n  PLAY_FN: 'play-fn',\n  /** Story has a test function */\n  TEST_FN: 'test-fn',\n  /** Development environment tag */\n  DEV: 'dev',\n  /** Test environment tag */\n  TEST: 'test',\n  /** Manifest generation tag */\n  MANIFEST: 'manifest',\n} as const;\n\n/**\n * Tags can be any string, including custom user-defined tags. The Tag constant above defines the\n * system tags used by Storybook.\n */\nexport type Tag = string;\n\n/**\n * Built-in story filters that extend beyond simple tag inclusion/exclusion. Those are used in the\n * manager UI and in the manager API stories module.\n */\nexport const BUILT_IN_FILTERS = {\n  _docs: (entry: API_PreparedIndexEntry, excluded?: boolean) =>\n    excluded ? entry.type !== 'docs' : entry.type === 'docs',\n  _play: (entry: API_PreparedIndexEntry, excluded?: boolean) =>\n    excluded\n      ? entry.type !== 'story' || !entry.tags?.includes(Tag.PLAY_FN)\n      : entry.type === 'story' && !!entry.tags?.includes(Tag.PLAY_FN),\n  _test: (entry: API_PreparedIndexEntry, excluded?: boolean) =>\n    excluded\n      ? entry.type !== 'story' || entry.subtype !== 'test'\n      : entry.type === 'story' && entry.subtype === 'test',\n};\n\n/**\n * Logic to resolve whether a tag filters a given entry, based on whether the tag is excluded or\n * included. Shared by the manager UI and manager API stories module.\n */\nexport const USER_TAG_FILTER = (tag: Tag) => (entry: API_PreparedIndexEntry, excluded?: boolean) =>\n  excluded ? !entry.tags?.includes(tag) : !!entry.tags?.includes(tag);\n"
  },
  {
    "path": "code/core/src/shared/status-store/index.test-d.ts",
    "content": "import { describe, expectTypeOf, it } from 'vitest';\n\nimport {\n  type Status,\n  type StatusesByStoryIdAndTypeId,\n  UNIVERSAL_STATUS_STORE_OPTIONS,\n  createStatusStore,\n} from './index.ts';\nimport type { StoryId } from '../../types/index.ts';\nimport { MockUniversalStore } from '../universal-store/mock.ts';\nimport { useUniversalStore } from '../universal-store/use-universal-store-manager.ts';\n\nconst { fullStatusStore, getStatusStoreByTypeId, useStatusStore } = createStatusStore({\n  universalStatusStore: MockUniversalStore.create(UNIVERSAL_STATUS_STORE_OPTIONS),\n  useUniversalStore,\n  environment: 'manager',\n});\nconst typedStatusStore = getStatusStoreByTypeId('test');\n\ndescribe('Status Store', () => {\n  it('getAll should return typed statuses', () => {\n    const statuses = fullStatusStore.getAll();\n    expectTypeOf(statuses).toEqualTypeOf<StatusesByStoryIdAndTypeId>();\n\n    const typedStatuses = typedStatusStore.getAll();\n    expectTypeOf(typedStatuses).toEqualTypeOf<StatusesByStoryIdAndTypeId>();\n  });\n\n  it('set should accept typed statuses', () => {\n    expectTypeOf(fullStatusStore.set).parameter(0).toEqualTypeOf<Status[]>();\n    expectTypeOf(typedStatusStore.set).parameter(0).toEqualTypeOf<Status[]>();\n  });\n\n  it('unset should accept storyIds or no parameters', () => {\n    expectTypeOf(fullStatusStore.unset).parameter(0).toEqualTypeOf<StoryId[] | undefined>();\n    expectTypeOf(typedStatusStore.unset).parameter(0).toEqualTypeOf<StoryId[] | undefined>();\n  });\n\n  it('onStatusChange should accept a callback with typed parameters', () => {\n    fullStatusStore.onAllStatusChange((statuses, previousStatuses) => {\n      expectTypeOf(statuses).toEqualTypeOf<StatusesByStoryIdAndTypeId>();\n      expectTypeOf(previousStatuses).toEqualTypeOf<StatusesByStoryIdAndTypeId>();\n    });\n    typedStatusStore.onAllStatusChange((statuses, previousStatuses) => {\n      expectTypeOf(statuses).toEqualTypeOf<StatusesByStoryIdAndTypeId>();\n      expectTypeOf(previousStatuses).toEqualTypeOf<StatusesByStoryIdAndTypeId>();\n    });\n  });\n\n  it('onSelect should accept a callback with typed parameters', () => {\n    fullStatusStore.onSelect((statuses) => {\n      expectTypeOf(statuses).toEqualTypeOf<Status[]>();\n    });\n    typedStatusStore.onSelect((statuses) => {\n      expectTypeOf(statuses).toEqualTypeOf<Status[]>();\n    });\n  });\n\n  it('useStatusStore should return typed statuses', () => {\n    // Without selector\n    const allStatuses = useStatusStore();\n    expectTypeOf(allStatuses).toEqualTypeOf<StatusesByStoryIdAndTypeId>();\n\n    // With selector\n    const selectedState = useStatusStore((statuses) => {\n      expectTypeOf(statuses).toEqualTypeOf<StatusesByStoryIdAndTypeId>();\n      return 1;\n    });\n    expectTypeOf(selectedState).toEqualTypeOf<number>();\n  });\n});\n"
  },
  {
    "path": "code/core/src/shared/status-store/index.test.ts",
    "content": "// @vitest-environment happy-dom\nimport { act, renderHook } from '@testing-library/react';\nimport { afterEach, describe, expect, it, vi } from 'vitest';\n\nimport { MockUniversalStore } from '../universal-store/mock.ts';\nimport { useUniversalStore } from '../universal-store/use-universal-store-manager.ts';\nimport {\n  type Status,\n  type StatusStoreEvent,\n  StatusValue,\n  type StatusesByStoryIdAndTypeId,\n  createStatusStore,\n} from './index.ts';\nimport { UNIVERSAL_STATUS_STORE_OPTIONS } from './index.ts';\n\nconst story1Type1Status: Status = {\n  storyId: 'story-1',\n  typeId: 'type-1',\n  value: 'status-value:success',\n  title: 'Success',\n  description: 'Success description',\n};\n\nconst story1Type2Status: Status = {\n  storyId: 'story-1',\n  typeId: 'type-2',\n  value: 'status-value:error',\n  title: 'Error',\n  description: 'Error description',\n};\n\nconst story2Type1Status: Status = {\n  storyId: 'story-2',\n  typeId: 'type-1',\n  value: 'status-value:pending',\n  title: 'Pending',\n  description: 'Pending description',\n};\n\nconst story2Type2Status: Status = {\n  storyId: 'story-2',\n  typeId: 'type-2',\n  value: 'status-value:unknown',\n  title: 'Unknown',\n  description: 'Unknown description',\n};\n\nconst initialState: StatusesByStoryIdAndTypeId = {\n  'story-1': {\n    'type-1': story1Type1Status,\n    'type-2': story1Type2Status,\n  },\n  'story-2': {\n    'type-1': story2Type1Status,\n    'type-2': story2Type2Status,\n  },\n};\n\ndescribe('statusStore', () => {\n  afterEach(() => {\n    vi.clearAllMocks();\n  });\n\n  describe('fullStatusStore', () => {\n    describe('get', () => {\n      it('should return all statuses', () => {\n        // Arrange - set up the store with initial state\n        const { fullStatusStore } = createStatusStore({\n          universalStatusStore: new MockUniversalStore({\n            ...UNIVERSAL_STATUS_STORE_OPTIONS,\n            initialState,\n          }),\n          environment: 'manager',\n        });\n\n        // Act - get all statuses\n        const result = fullStatusStore.getAll();\n\n        // Assert - all statuses should be returned\n        expect(result).toEqual(initialState);\n      });\n    });\n\n    describe('set', () => {\n      it('should add new statuses', () => {\n        // Arrange - create a status store\n        const { fullStatusStore } = createStatusStore({\n          universalStatusStore: new MockUniversalStore(UNIVERSAL_STATUS_STORE_OPTIONS),\n          environment: 'manager',\n        });\n\n        // Act - set the status\n        fullStatusStore.set([story1Type1Status]);\n        const result = fullStatusStore.getAll();\n\n        // Assert - the status should be added\n        expect(result).toEqual({\n          'story-1': {\n            'type-1': story1Type1Status,\n          },\n        });\n      });\n\n      it('should update existing statuses with the same storyId and typeId', () => {\n        // Arrange - create a status store\n        const { fullStatusStore } = createStatusStore({\n          universalStatusStore: new MockUniversalStore(UNIVERSAL_STATUS_STORE_OPTIONS),\n          environment: 'manager',\n        });\n\n        // Create an updated version of the status\n        const updatedStatus: Status = {\n          ...story1Type1Status,\n          value: 'status-value:error',\n          title: 'Updated Title',\n          description: 'Updated Description',\n        };\n\n        // Act - set the initial status, then update it\n        fullStatusStore.set([story1Type1Status]);\n        fullStatusStore.set([updatedStatus]);\n        const result = fullStatusStore.getAll();\n\n        // Assert - the status should be updated\n        expect(result).toEqual({\n          'story-1': {\n            'type-1': updatedStatus,\n          },\n        });\n      });\n\n      it('should update existing statuses and add new ones in a single operation', () => {\n        // Arrange - create a status store with initial statuses\n        const { fullStatusStore } = createStatusStore({\n          universalStatusStore: new MockUniversalStore<\n            StatusesByStoryIdAndTypeId,\n            StatusStoreEvent\n          >({\n            ...UNIVERSAL_STATUS_STORE_OPTIONS,\n            initialState: {\n              'story-1': {\n                'type-1': story1Type1Status,\n              },\n              'story-2': {\n                'type-2': story2Type2Status,\n              },\n            },\n          }),\n          environment: 'manager',\n        });\n\n        // Create an updated version of an existing status\n        const updatedStatus: Status = {\n          ...story1Type1Status,\n          value: 'status-value:error',\n          title: 'Updated Title',\n        };\n\n        // Act - update one status and add a new one\n        fullStatusStore.set([updatedStatus, story2Type1Status]);\n        const result = fullStatusStore.getAll();\n\n        // Assert - the existing status should be updated and the new one added\n        expect(result).toEqual({\n          'story-1': {\n            'type-1': updatedStatus,\n          },\n          'story-2': {\n            'type-1': story2Type1Status,\n            'type-2': story2Type2Status,\n          },\n        });\n      });\n    });\n\n    describe('onStatusChange', () => {\n      it('should call listener when status is added', () => {\n        // Arrange - set up the store and a mock subscriber\n        const mockSubscriber = vi.fn();\n        const { fullStatusStore } = createStatusStore({\n          universalStatusStore: new MockUniversalStore(UNIVERSAL_STATUS_STORE_OPTIONS),\n          environment: 'manager',\n        });\n        const unsubscribe = fullStatusStore.onAllStatusChange(mockSubscriber);\n\n        // Act - set statuses to trigger the subscriber\n        fullStatusStore.set([story1Type1Status]);\n\n        // Assert - the subscriber should be called with the statuses and previous statuses\n        expect(mockSubscriber).toHaveBeenCalledWith(\n          { 'story-1': { 'type-1': story1Type1Status } },\n          {}\n        );\n        unsubscribe();\n      });\n\n      it('should call listener when status is updated', () => {\n        // Arrange - set up the store and a mock subscriber\n        const mockSubscriber = vi.fn();\n        const { fullStatusStore } = createStatusStore({\n          universalStatusStore: new MockUniversalStore<\n            StatusesByStoryIdAndTypeId,\n            StatusStoreEvent\n          >({\n            ...UNIVERSAL_STATUS_STORE_OPTIONS,\n            initialState: {\n              'story-1': {\n                'type-1': story1Type1Status,\n              },\n            },\n          }),\n          environment: 'manager',\n        });\n        const unsubscribe = fullStatusStore.onAllStatusChange(mockSubscriber);\n\n        // Act - update the existing status\n        const updatedStatus = {\n          ...story1Type1Status,\n          value: 'status-value:error',\n          title: 'Updated Title',\n        } as const;\n        fullStatusStore.set([updatedStatus]);\n\n        // Assert - the subscriber should be called with the updated status and previous status\n        expect(mockSubscriber).toHaveBeenCalledWith(\n          { 'story-1': { 'type-1': updatedStatus } },\n          { 'story-1': { 'type-1': story1Type1Status } }\n        );\n        unsubscribe();\n      });\n\n      it('should call listener when status is unset', () => {\n        // Arrange - set up the store and a mock subscriber\n        const mockSubscriber = vi.fn();\n        const { fullStatusStore } = createStatusStore({\n          universalStatusStore: new MockUniversalStore<\n            StatusesByStoryIdAndTypeId,\n            StatusStoreEvent\n          >({\n            ...UNIVERSAL_STATUS_STORE_OPTIONS,\n            initialState: {\n              'story-1': {\n                'type-1': story1Type1Status,\n              },\n            },\n          }),\n          environment: 'manager',\n        });\n        const unsubscribe = fullStatusStore.onAllStatusChange(mockSubscriber);\n\n        // Act - unset the status\n        fullStatusStore.unset([story1Type1Status.storyId]);\n\n        // Assert - the subscriber should be called with the unset status and previous statuses\n        expect(mockSubscriber).toHaveBeenCalledWith(\n          {},\n          { 'story-1': { 'type-1': story1Type1Status } }\n        );\n        unsubscribe();\n      });\n    });\n\n    describe('onSelect', () => {\n      it('should call listener when statuses are selected', () => {\n        // Arrange - set up the store with initial state and a mock listener\n        const mockListener = vi.fn();\n        const { fullStatusStore } = createStatusStore({\n          universalStatusStore: new MockUniversalStore({\n            ...UNIVERSAL_STATUS_STORE_OPTIONS,\n            initialState,\n          }),\n          environment: 'manager',\n        });\n        const unsubscribe = fullStatusStore.onSelect(mockListener);\n\n        // Act - select statuses\n        const selectedStatuses = [story1Type1Status, story2Type2Status];\n        fullStatusStore.selectStatuses(selectedStatuses);\n\n        // Assert - the listener should be called with the selected statuses\n        expect(mockListener).toHaveBeenCalledWith(selectedStatuses);\n\n        // Clean up\n        unsubscribe();\n      });\n    });\n\n    describe('unset', () => {\n      it('should unset all statuses when typeIds and storyIds are not provided', () => {\n        // Arrange - set up the store with initial state\n        const { fullStatusStore } = createStatusStore({\n          universalStatusStore: new MockUniversalStore({\n            ...UNIVERSAL_STATUS_STORE_OPTIONS,\n            initialState,\n          }),\n          environment: 'manager',\n        });\n\n        // Act - unset without a predicate\n        fullStatusStore.unset();\n        const result = fullStatusStore.getAll();\n\n        // Assert - all statuses should be removed\n        expect(result).toEqual({});\n      });\n\n      it('should unset statuses by storyIds', () => {\n        // Arrange - set up the store with initial state\n        const { fullStatusStore } = createStatusStore({\n          universalStatusStore: new MockUniversalStore({\n            ...UNIVERSAL_STATUS_STORE_OPTIONS,\n            initialState,\n          }),\n          environment: 'manager',\n        });\n\n        // Act - unset with a storyIds filter\n        fullStatusStore.unset(['story-1']);\n        const result = fullStatusStore.getAll();\n\n        // Assert - only statuses with matching storyId should be removed\n        expect(result).toEqual({\n          'story-2': {\n            'type-1': story2Type1Status,\n            'type-2': story2Type2Status,\n          },\n        });\n      });\n    });\n  });\n\n  describe('getStatusStoreByTypeId', () => {\n    describe('set', () => {\n      it('should add new statuses of the specified typeId', () => {\n        // Arrange - create a status store\n        const { getStatusStoreByTypeId, fullStatusStore } = createStatusStore({\n          universalStatusStore: new MockUniversalStore(UNIVERSAL_STATUS_STORE_OPTIONS),\n          environment: 'manager',\n        });\n\n        // Act - get a status store for type-1 and set a status\n        const type1StatusStore = getStatusStoreByTypeId('type-1');\n        type1StatusStore.set([story1Type1Status]);\n\n        // Assert - the status should be added to the full store\n        const fullResult = fullStatusStore.getAll();\n        expect(fullResult).toEqual({\n          'story-1': {\n            'type-1': story1Type1Status,\n          },\n        });\n\n        // Assert - the status should be accessible from the type-specific store\n        const typeResult = type1StatusStore.getAll();\n        expect(typeResult).toEqual({\n          'story-1': {\n            'type-1': story1Type1Status,\n          },\n        });\n      });\n\n      it('should update existing statuses with the same storyId and typeId', () => {\n        // Arrange - create a status store\n        const { getStatusStoreByTypeId } = createStatusStore({\n          universalStatusStore: new MockUniversalStore(UNIVERSAL_STATUS_STORE_OPTIONS),\n          environment: 'manager',\n        });\n\n        // Create an updated version of the status\n        const updatedStatus: Status = {\n          ...story1Type1Status,\n          value: 'status-value:error',\n          title: 'Updated Title',\n          description: 'Updated Description',\n        };\n\n        // Act - get a status store for type-1, set the initial status, then update it\n        const type1StatusStore = getStatusStoreByTypeId('type-1');\n        type1StatusStore.set([story1Type1Status]);\n        type1StatusStore.set([updatedStatus]);\n        const result = type1StatusStore.getAll();\n\n        // Assert - the status should be updated\n        expect(result).toEqual({\n          'story-1': {\n            'type-1': updatedStatus,\n          },\n        });\n      });\n\n      it('should update existing statuses and add new ones in a single operation', () => {\n        // Arrange - create a status store\n        const { getStatusStoreByTypeId, fullStatusStore } = createStatusStore({\n          universalStatusStore: new MockUniversalStore({\n            ...UNIVERSAL_STATUS_STORE_OPTIONS,\n            initialState,\n          }),\n          environment: 'manager',\n        });\n\n        // Get the type-specific store\n        const type1StatusStore = getStatusStoreByTypeId('type-1');\n\n        // Create an updated version of the existing status\n        const updatedStatus: Status = {\n          ...story1Type1Status,\n          value: 'status-value:error',\n          title: 'Updated Title',\n          description: 'Updated Description',\n        };\n\n        // Act - update existing status and add a new one in the same operation\n        type1StatusStore.set([updatedStatus, story2Type1Status]);\n\n        // Assert - all statuses should be in the full store\n        const result = type1StatusStore.getAll();\n        expect(result).toEqual({\n          'story-1': {\n            'type-1': updatedStatus,\n            'type-2': story1Type2Status,\n          },\n          'story-2': {\n            'type-1': story2Type1Status,\n            'type-2': story2Type2Status,\n          },\n        });\n      });\n\n      it('should error when setting statuses with wrong typeId', () => {\n        // Arrange - create a status store\n        const { getStatusStoreByTypeId, fullStatusStore } = createStatusStore({\n          universalStatusStore: new MockUniversalStore(UNIVERSAL_STATUS_STORE_OPTIONS),\n          environment: 'manager',\n        });\n\n        // Act & Assert - get a status store for type-1 and try to set a status with type-2, expect it to throw\n        const type1StatusStore = getStatusStoreByTypeId('type-1');\n        expect(() => type1StatusStore.set([story1Type2Status])).toThrowErrorMatchingInlineSnapshot(`\n          [SB_MANAGER_API_0001 (StatusTypeIdMismatchError): Status has typeId \"type-2\" but was added to store with typeId \"type-1\". Full status: {\n            \"storyId\": \"story-1\",\n            \"typeId\": \"type-2\",\n            \"value\": \"status-value:error\",\n            \"title\": \"Error\",\n            \"description\": \"Error description\"\n          }]\n        `);\n      });\n    });\n\n    describe('unset', () => {\n      it('should unset all statuses of the specified typeId when no storyIds are provided', () => {\n        // Arrange - set up the store with initial state\n        const { getStatusStoreByTypeId, fullStatusStore } = createStatusStore({\n          universalStatusStore: new MockUniversalStore({\n            ...UNIVERSAL_STATUS_STORE_OPTIONS,\n            initialState,\n          }),\n          environment: 'manager',\n        });\n\n        // Act - get a status store for type-1 and unset without a predicate\n        const type1StatusStore = getStatusStoreByTypeId('type-1');\n        type1StatusStore.unset();\n\n        // Assert - statuses with other typeIds should remain\n        const fullResult = fullStatusStore.getAll();\n        expect(fullResult).toEqual({\n          'story-1': {\n            'type-2': story1Type2Status,\n          },\n          'story-2': {\n            'type-2': story2Type2Status,\n          },\n        });\n      });\n\n      it('should unset statuses by storyIds', () => {\n        // Arrange - set up the store with initial state\n        const { getStatusStoreByTypeId } = createStatusStore({\n          universalStatusStore: new MockUniversalStore({\n            ...UNIVERSAL_STATUS_STORE_OPTIONS,\n            initialState,\n          }),\n          environment: 'manager',\n        });\n\n        // Act - get a status store for type-1 and unset with a storyIds filter\n        const type1StatusStore = getStatusStoreByTypeId('type-1');\n        type1StatusStore.unset(['story-1']);\n        const result = type1StatusStore.getAll();\n\n        // Assert - only statuses with typeId 'type-1' and storyId 'story-1' should be removed\n        expect(result).toEqual({\n          'story-1': { 'type-2': story1Type2Status },\n          'story-2': { 'type-1': story2Type1Status, 'type-2': story2Type2Status },\n        });\n      });\n    });\n\n    describe('onSelect', () => {\n      it('should call listener when statuses of the specified typeId are selected', () => {\n        // Arrange - set up the store with initial state and a mock listener\n        const mockListener = vi.fn();\n        const { getStatusStoreByTypeId, fullStatusStore } = createStatusStore({\n          universalStatusStore: new MockUniversalStore({\n            ...UNIVERSAL_STATUS_STORE_OPTIONS,\n            initialState,\n          }),\n          environment: 'manager',\n        });\n\n        // Get a type-specific store and subscribe to selections\n        const type1StatusStore = getStatusStoreByTypeId('type-1');\n        const unsubscribe = type1StatusStore.onSelect(mockListener);\n\n        // Act - select statuses including one with the matching typeId\n        const selectedStatuses = [story1Type1Status, story2Type2Status];\n        fullStatusStore.selectStatuses(selectedStatuses);\n\n        // Assert - the listener should be called with the selected statuses\n        expect(mockListener).toHaveBeenCalledWith(selectedStatuses);\n\n        // Clean up\n        unsubscribe();\n      });\n\n      it('should not call listener when selected statuses do not include the specified typeId', () => {\n        // Arrange - set up the store with initial state and a mock listener\n        const mockListener = vi.fn();\n        const { getStatusStoreByTypeId, fullStatusStore } = createStatusStore({\n          universalStatusStore: new MockUniversalStore({\n            ...UNIVERSAL_STATUS_STORE_OPTIONS,\n            initialState,\n          }),\n          environment: 'manager',\n        });\n\n        // Get a type-specific store and subscribe to selections\n        const type1StatusStore = getStatusStoreByTypeId('type-1');\n        const unsubscribe = type1StatusStore.onSelect(mockListener);\n\n        // Act - select statuses without any matching typeId\n        const selectedStatuses = [story1Type2Status, story2Type2Status];\n        fullStatusStore.selectStatuses(selectedStatuses);\n\n        // Assert - the listener should not be called\n        expect(mockListener).not.toHaveBeenCalled();\n\n        // Clean up\n        unsubscribe();\n      });\n    });\n  });\n\n  describe('useStatusStore', () => {\n    it('should be returned when useUniversalStore is provided', () => {\n      // Act - create a status store with the mock\n      const { useStatusStore } = createStatusStore({\n        universalStatusStore: new MockUniversalStore(UNIVERSAL_STATUS_STORE_OPTIONS),\n        useUniversalStore,\n        environment: 'manager',\n      });\n\n      // Assert - useStatusStore should be defined\n      expect(useStatusStore).toBeDefined();\n    });\n\n    it('should return all statuses when no selector is provided', () => {\n      // Arrange - create a status store\n      const { useStatusStore } = createStatusStore({\n        universalStatusStore: new MockUniversalStore({\n          ...UNIVERSAL_STATUS_STORE_OPTIONS,\n          initialState,\n        }),\n        useUniversalStore,\n        environment: 'manager',\n      });\n\n      // Act - get a status store for type-1 and render the hook\n      const { result } = renderHook(() => useStatusStore());\n\n      // Assert - initial statuses should be returned\n      expect(result.current).toEqual(initialState);\n    });\n\n    it('should filter statuses based on selector', () => {\n      // Arrange - create a status store\n      const { useStatusStore } = createStatusStore({\n        universalStatusStore: new MockUniversalStore({\n          ...UNIVERSAL_STATUS_STORE_OPTIONS,\n          initialState,\n        }),\n        useUniversalStore,\n        environment: 'manager',\n      });\n\n      // Create a selector that only returns SUCCESS statuses\n      const successSelector = (statuses: StatusesByStoryIdAndTypeId) => {\n        const result: StatusesByStoryIdAndTypeId = {};\n\n        Object.entries(statuses).forEach(([storyId, typeStatuses]) => {\n          Object.entries(typeStatuses).forEach(([typeId, status]) => {\n            if (status.value === 'status-value:success') {\n              if (!result[storyId]) {\n                result[storyId] = {};\n              }\n              result[storyId][typeId] = status;\n            }\n          });\n        });\n\n        return result;\n      };\n\n      // Act - render the hook with the selector\n      const { result } = renderHook(() => useStatusStore(successSelector));\n\n      // Assert - only SUCCESS statuses should be returned\n      expect(result.current).toEqual({\n        'story-1': {\n          'type-1': story1Type1Status,\n        },\n      });\n    });\n\n    it('should re-render when statuses matching the selector change', async () => {\n      // Arrange - create a status store\n      const { useStatusStore, fullStatusStore } = createStatusStore({\n        universalStatusStore: new MockUniversalStore({\n          ...UNIVERSAL_STATUS_STORE_OPTIONS,\n          initialState,\n        }),\n        useUniversalStore,\n        environment: 'manager',\n      });\n      const renderCounter = vi.fn();\n\n      // Create a selector that only returns statuses for story-1\n      const story1Selector = (statuses: StatusesByStoryIdAndTypeId) => statuses['story-1'] || {};\n\n      // Act - render the hook with the selector\n      const { result } = renderHook(() => {\n        renderCounter();\n        return useStatusStore(story1Selector);\n      });\n\n      // Assert - initial render\n      expect(renderCounter).toHaveBeenCalledTimes(1);\n      expect(result.current).toEqual({\n        'type-1': story1Type1Status,\n        'type-2': story1Type2Status,\n      });\n\n      // Act - update a status for story-1\n      const updatedStory1Type1Status = {\n        ...story1Type1Status,\n        value: 'status-value:error',\n        title: 'Updated Error',\n        description: 'Updated error description',\n      } as const;\n\n      act(() => {\n        fullStatusStore.set([updatedStory1Type1Status]);\n      });\n\n      // Assert - the hook should re-render with the updated status\n      expect(renderCounter).toHaveBeenCalledTimes(2);\n      expect(result.current).toEqual({\n        'type-1': updatedStory1Type1Status,\n        'type-2': story1Type2Status,\n      });\n    });\n\n    it('should not re-render when statuses not matching the selector change', async () => {\n      // Arrange - create a status store\n      const { useStatusStore, fullStatusStore } = createStatusStore({\n        universalStatusStore: new MockUniversalStore({\n          ...UNIVERSAL_STATUS_STORE_OPTIONS,\n          initialState,\n        }),\n        useUniversalStore,\n        environment: 'manager',\n      });\n      const renderCounter = vi.fn();\n\n      // Create a selector that only returns statuses for story-1\n      const story1Selector = (statuses: StatusesByStoryIdAndTypeId) => statuses['story-1'] || {};\n\n      // Act - render the hook with the selector\n      const { result } = renderHook(() => {\n        renderCounter();\n        return useStatusStore(story1Selector);\n      });\n\n      // Assert - initial render\n      expect(renderCounter).toHaveBeenCalledTimes(1);\n      expect(result.current).toEqual({\n        'type-1': story1Type1Status,\n        'type-2': story1Type2Status,\n      });\n\n      // Act - update a status for story-2 (which doesn't match the selector)\n      const updatedStory2Type1Status = {\n        ...story2Type1Status,\n        value: 'status-value:error',\n        title: 'Updated Error',\n        description: 'Updated error description',\n      } as const;\n\n      act(() => {\n        fullStatusStore.set([updatedStory2Type1Status]);\n      });\n\n      // Assert - the hook should not re-render since the change doesn't affect the selected data\n      expect(renderCounter).toHaveBeenCalledTimes(1);\n      expect(result.current).toEqual({\n        'type-1': story1Type1Status,\n        'type-2': story1Type2Status,\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/shared/status-store/index.ts",
    "content": "import { StatusTypeIdMismatchError as ManagerStatusTypeIdMismatchError } from '../../manager-errors.ts';\nimport { StatusTypeIdMismatchError as PreviewStatusTypeIdMismatchError } from '../../preview-errors.ts';\nimport { StatusTypeIdMismatchError as ServerStatusTypeIdMismatchError } from '../../server-errors.ts';\nimport type { StoryId } from '../../types/index.ts';\nimport type { UniversalStore } from '../universal-store/index.ts';\nimport type { StoreOptions } from '../universal-store/types.ts';\nimport type { useUniversalStore as managerUseUniversalStore } from '../universal-store/use-universal-store-manager.ts';\n\nexport type StatusValue =\n  | 'status-value:pending'\n  | 'status-value:success'\n  | 'status-value:new'\n  | 'status-value:modified'\n  | 'status-value:affected'\n  | 'status-value:warning'\n  | 'status-value:error'\n  | 'status-value:unknown';\n\nconst STATUS_VALUE_PREFIX = 'status-value:';\n\nexport const STATUS_VALUES: StatusValue[] = [\n  'status-value:pending',\n  'status-value:success',\n  'status-value:new',\n  'status-value:modified',\n  'status-value:affected',\n  'status-value:warning',\n  'status-value:error',\n  'status-value:unknown',\n];\n\n/** Converts a short name like \"error\" to `\"status-value:error\"`. Returns undefined if invalid. */\nexport const toStatusValue = (shortName: string): StatusValue | undefined => {\n  const candidate = `${STATUS_VALUE_PREFIX}${shortName}` as StatusValue;\n  return STATUS_VALUES.includes(candidate) ? candidate : undefined;\n};\n\n/** Extracts the short name from a StatusValue, e.g. `\"status-value:error\"` → `\"error\"`. */\nexport const statusValueShortName = (value: StatusValue): string => {\n  return value.slice(STATUS_VALUE_PREFIX.length);\n};\n\nexport type StatusTypeId = string;\nexport type StatusByTypeId = Record<StatusTypeId, Status>;\nexport type StatusesByStoryIdAndTypeId = Record<StoryId, StatusByTypeId>;\n\nexport interface Status {\n  value: StatusValue;\n  typeId: StatusTypeId;\n  storyId: StoryId;\n  title: string;\n  description: string;\n  data?: any;\n  sidebarContextMenu?: boolean;\n}\n\nexport const CHANGE_DETECTION_STATUS_TYPE_ID = 'storybook/change-detection';\n\nexport const UNIVERSAL_STATUS_STORE_OPTIONS: StoreOptions<StatusesByStoryIdAndTypeId> = {\n  id: 'storybook/status',\n  leader: true,\n  initialState: {},\n} as const;\n\nconst StatusStoreEventType = {\n  SELECT: 'select',\n} as const;\n\nexport type StatusStoreEvent = {\n  type: typeof StatusStoreEventType.SELECT;\n  payload: Status[];\n};\n\nexport type StatusStore = {\n  getAll: () => StatusesByStoryIdAndTypeId;\n  set: (statuses: Status[]) => void;\n  onAllStatusChange: (\n    listener: (\n      statuses: StatusesByStoryIdAndTypeId,\n      previousStatuses: StatusesByStoryIdAndTypeId\n    ) => void\n  ) => () => void;\n  onSelect: (listener: (selectedStatuses: Status[]) => void) => () => void;\n  unset: (storyIds?: StoryId[]) => void;\n};\ntype FullStatusStore = StatusStore & {\n  selectStatuses: (statuses: Status[]) => void;\n  typeId: undefined;\n};\nexport type StatusStoreByTypeId = StatusStore & {\n  typeId: StatusTypeId;\n};\n\nexport type StatusStoreEnvironment = 'server' | 'manager' | 'preview';\n\nexport type UseStatusStore = <T = StatusesByStoryIdAndTypeId>(\n  selector?: (statuses: StatusesByStoryIdAndTypeId) => T\n) => T;\n\nexport function createStatusStore(params: {\n  universalStatusStore: UniversalStore<StatusesByStoryIdAndTypeId, StatusStoreEvent>;\n  useUniversalStore?: never;\n  environment: StatusStoreEnvironment;\n}): {\n  getStatusStoreByTypeId: (typeId: StatusTypeId) => StatusStoreByTypeId;\n  fullStatusStore: FullStatusStore;\n  universalStatusStore: UniversalStore<StatusesByStoryIdAndTypeId, StatusStoreEvent>;\n};\nexport function createStatusStore(params: {\n  universalStatusStore: UniversalStore<StatusesByStoryIdAndTypeId, StatusStoreEvent>;\n  useUniversalStore: typeof managerUseUniversalStore;\n  environment: StatusStoreEnvironment;\n}): {\n  getStatusStoreByTypeId: (typeId: StatusTypeId) => StatusStoreByTypeId;\n  fullStatusStore: FullStatusStore;\n  useStatusStore: UseStatusStore;\n  universalStatusStore: UniversalStore<StatusesByStoryIdAndTypeId, StatusStoreEvent>;\n};\nexport function createStatusStore({\n  universalStatusStore,\n  useUniversalStore,\n  environment,\n}: {\n  universalStatusStore: UniversalStore<StatusesByStoryIdAndTypeId, StatusStoreEvent>;\n  useUniversalStore?: typeof managerUseUniversalStore;\n  environment: StatusStoreEnvironment;\n}): {\n  getStatusStoreByTypeId: (typeId: StatusTypeId) => StatusStoreByTypeId;\n  fullStatusStore: FullStatusStore;\n  useStatusStore?: UseStatusStore;\n  universalStatusStore: UniversalStore<StatusesByStoryIdAndTypeId, StatusStoreEvent>;\n} {\n  const fullStatusStore: FullStatusStore = {\n    getAll() {\n      return universalStatusStore.getState();\n    },\n    set(statuses) {\n      universalStatusStore.setState((state) => {\n        // Create a new state object to merge with the current state\n        const newState = { ...state };\n\n        // Process each status and merge it into the appropriate storyId record\n        for (const status of statuses) {\n          const { storyId, typeId } = status;\n\n          newState[storyId] = { ...(newState[storyId] ?? {}), [typeId]: status };\n        }\n        return newState;\n      });\n    },\n    onAllStatusChange(\n      listener: (\n        statuses: StatusesByStoryIdAndTypeId,\n        prevStatuses: StatusesByStoryIdAndTypeId\n      ) => void\n    ): ReturnType<typeof universalStatusStore.onStateChange> {\n      return universalStatusStore.onStateChange((state, prevState) => {\n        listener(state, prevState);\n      });\n    },\n    onSelect(listener) {\n      return universalStatusStore.subscribe(StatusStoreEventType.SELECT, (event) => {\n        listener(event.payload);\n      });\n    },\n    selectStatuses: (statuses: Status[]) => {\n      universalStatusStore.send({ type: StatusStoreEventType.SELECT, payload: statuses });\n    },\n    unset(storyIds?: StoryId[]): void {\n      // If no storyIds are provided, remove all statuses\n      if (!storyIds) {\n        universalStatusStore.setState({});\n        return;\n      }\n\n      universalStatusStore.setState((state) => {\n        const newState = { ...state };\n        for (const storyId of storyIds) {\n          delete newState[storyId];\n        }\n        return newState;\n      });\n    },\n    typeId: undefined,\n  };\n\n  const getStatusStoreByTypeId = (typeId: StatusTypeId): StatusStoreByTypeId => ({\n    getAll: fullStatusStore.getAll,\n    set(statuses): void {\n      universalStatusStore.setState((state) => {\n        // Create a new state object to merge with the current state\n        const newState = { ...state };\n\n        // Process each status and merge it into the appropriate storyId record\n        for (const status of statuses) {\n          const { storyId } = status;\n          if (status.typeId !== typeId) {\n            // Validate that all statuses have the correct typeId\n            switch (environment) {\n              case 'server':\n                throw new ServerStatusTypeIdMismatchError({\n                  status,\n                  typeId,\n                });\n              case 'manager':\n                throw new ManagerStatusTypeIdMismatchError({\n                  status,\n                  typeId,\n                });\n              case 'preview':\n              default:\n                throw new PreviewStatusTypeIdMismatchError({\n                  status,\n                  typeId,\n                });\n            }\n          }\n\n          newState[storyId] = { ...(newState[storyId] ?? {}), [typeId]: status };\n        }\n        return newState;\n      });\n    },\n    onAllStatusChange: fullStatusStore.onAllStatusChange,\n    onSelect(listener) {\n      return universalStatusStore.subscribe(StatusStoreEventType.SELECT, (event) => {\n        if (event.payload.some((status) => status.typeId === typeId)) {\n          listener(event.payload);\n        }\n      });\n    },\n    unset(storyIds?: StoryId[]): void {\n      universalStatusStore.setState((state) => {\n        const newState = { ...state };\n        for (const storyId in newState) {\n          if (newState[storyId]?.[typeId] && (!storyIds || storyIds?.includes(storyId))) {\n            const { [typeId]: omittedStatus, ...storyStatusesWithoutTypeId } = newState[storyId];\n            newState[storyId] = storyStatusesWithoutTypeId;\n          }\n        }\n        return newState;\n      });\n    },\n    typeId,\n  });\n\n  if (!useUniversalStore) {\n    return { getStatusStoreByTypeId, fullStatusStore, universalStatusStore };\n  }\n\n  return {\n    getStatusStoreByTypeId,\n    fullStatusStore,\n    universalStatusStore,\n    useStatusStore: <T = StatusesByStoryIdAndTypeId>(\n      selector?: (statuses: StatusesByStoryIdAndTypeId) => T\n    ) => useUniversalStore(universalStatusStore, selector as any)[0] as T,\n  };\n}\n"
  },
  {
    "path": "code/core/src/shared/test-provider-store/index.test-d.ts",
    "content": "import { describe, expectTypeOf, it } from 'vitest';\n\nimport {\n  type TestProviderState,\n  type TestProviderStateByProviderId,\n  UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS,\n  createTestProviderStore,\n} from './index.ts';\nimport { MockUniversalStore } from '../universal-store/mock.ts';\nimport { useUniversalStore } from '../universal-store/use-universal-store-manager.ts';\n\nconst { fullTestProviderStore, getTestProviderStoreById, useTestProviderStore } =\n  createTestProviderStore({\n    universalTestProviderStore: MockUniversalStore.create(UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS),\n    useUniversalStore,\n  });\n\nconst typedTestProviderStore = getTestProviderStoreById('test-provider-1');\n\ndescribe('Test Provider Store', () => {\n  it('getFullState should return typed provider states', () => {\n    const states = fullTestProviderStore.getFullState();\n    expectTypeOf(states).toEqualTypeOf<TestProviderStateByProviderId>();\n\n    const typedState = typedTestProviderStore.getState();\n    expectTypeOf(typedState).toEqualTypeOf<TestProviderState>();\n  });\n\n  it('setFullState should accept typed provider states', () => {\n    expectTypeOf(fullTestProviderStore.setFullState)\n      .parameter(0)\n      .toMatchTypeOf<\n        | TestProviderStateByProviderId\n        | ((state: TestProviderStateByProviderId) => TestProviderStateByProviderId)\n      >();\n    expectTypeOf(typedTestProviderStore.setState).parameter(0).toEqualTypeOf<TestProviderState>();\n  });\n\n  it('runWithState should accept a callback', () => {\n    expectTypeOf(typedTestProviderStore.runWithState)\n      .parameter(0)\n      .toEqualTypeOf<() => void | Promise<void>>();\n  });\n\n  it('onRunAll should accept a callback', () => {\n    expectTypeOf(fullTestProviderStore.onRunAll).parameter(0).toEqualTypeOf<() => void>();\n    expectTypeOf(typedTestProviderStore.onRunAll).parameter(0).toEqualTypeOf<() => void>();\n  });\n\n  it('onClearAll should accept a callback with no parameters', () => {\n    expectTypeOf(fullTestProviderStore.onClearAll).parameter(0).toEqualTypeOf<() => void>();\n    expectTypeOf(typedTestProviderStore.onClearAll).parameter(0).toEqualTypeOf<() => void>();\n  });\n\n  it('settingsChanged should be callable with no parameters', () => {\n    expectTypeOf(fullTestProviderStore.settingsChanged).toBeFunction();\n    expectTypeOf(fullTestProviderStore.settingsChanged).parameters.toEqualTypeOf<[]>();\n\n    expectTypeOf(typedTestProviderStore.settingsChanged).toBeFunction();\n    expectTypeOf(typedTestProviderStore.settingsChanged).parameters.toEqualTypeOf<[]>();\n  });\n\n  it('useTestProviderStore should return typed provider states', () => {\n    // Without selector\n    const allStates = useTestProviderStore();\n    expectTypeOf(allStates).toEqualTypeOf<TestProviderStateByProviderId>();\n\n    // With selector\n    const selectedState = useTestProviderStore((states) => {\n      expectTypeOf(states).toEqualTypeOf<TestProviderStateByProviderId>();\n      return states['test-provider-1'];\n    });\n    expectTypeOf(selectedState).toEqualTypeOf<TestProviderState>();\n  });\n});\n"
  },
  {
    "path": "code/core/src/shared/test-provider-store/index.test.ts",
    "content": "// @vitest-environment happy-dom\nimport { act, renderHook } from '@testing-library/react';\nimport { afterEach, describe, expect, it, vi } from 'vitest';\n\nimport { MockUniversalStore } from '../universal-store/mock.ts';\nimport { useUniversalStore } from '../universal-store/use-universal-store-manager.ts';\nimport {\n  type TestProviderStateByProviderId,\n  type TestProviderStoreEvent,\n  createTestProviderStore,\n} from './index.ts';\nimport { UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS } from './index.ts';\n\nconst initialState: TestProviderStateByProviderId = {\n  'provider-1': 'test-provider-state:running',\n  'provider-2': 'test-provider-state:succeeded',\n};\n\ndescribe('testProviderStore', () => {\n  afterEach(() => {\n    vi.clearAllMocks();\n  });\n\n  describe('fullTestProviderStore', () => {\n    describe('getState', () => {\n      it('should return all provider states', () => {\n        // Arrange - create test provider store with initial state\n        const { fullTestProviderStore } = createTestProviderStore({\n          universalTestProviderStore: new MockUniversalStore<\n            TestProviderStateByProviderId,\n            TestProviderStoreEvent\n          >({\n            ...UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS,\n            initialState,\n          }),\n        });\n\n        // Act - get full state\n        const result = fullTestProviderStore.getFullState();\n\n        // Assert - verify state matches initial state\n        expect(result).toEqual(initialState);\n      });\n    });\n\n    describe('setState', () => {\n      it('should set state', () => {\n        // Arrange - create test provider store with initial state\n        const { fullTestProviderStore } = createTestProviderStore({\n          universalTestProviderStore: new MockUniversalStore<\n            TestProviderStateByProviderId,\n            TestProviderStoreEvent\n          >({\n            ...UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS,\n            initialState,\n          }),\n        });\n\n        // Act - set new provider state and get updated state\n        fullTestProviderStore.setFullState((currentState) => ({\n          ...currentState,\n          'provider-3': 'test-provider-state:crashed',\n        }));\n        const result = fullTestProviderStore.getFullState();\n\n        // Assert - verify new provider was added with correct state\n        expect(result).toEqual({\n          'provider-1': 'test-provider-state:running',\n          'provider-2': 'test-provider-state:succeeded',\n          'provider-3': 'test-provider-state:crashed',\n        });\n      });\n    });\n  });\n\n  describe('getTestProviderStoreById', () => {\n    describe('getState', () => {\n      it('should initially return pending state for new provider', () => {\n        // Arrange - create empty test provider store\n        const { getTestProviderStoreById, fullTestProviderStore } = createTestProviderStore({\n          universalTestProviderStore: new MockUniversalStore<\n            TestProviderStateByProviderId,\n            TestProviderStoreEvent\n          >(UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS),\n        });\n\n        // Act - get store for new provider\n        const store = getTestProviderStoreById('provider-1');\n\n        // Assert - verify initial state is pending\n        expect(store.getState()).toBe('test-provider-state:pending');\n      });\n\n      it('should return current state for existing provider', () => {\n        // Arrange - create store with existing provider state\n        const { getTestProviderStoreById } = createTestProviderStore({\n          universalTestProviderStore: new MockUniversalStore<\n            TestProviderStateByProviderId,\n            TestProviderStoreEvent\n          >({\n            ...UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS,\n            initialState: { 'provider-1': 'test-provider-state:running' },\n          }),\n        });\n\n        // Act - get store for existing provider\n        const store = getTestProviderStoreById('provider-1');\n\n        // Assert - verify state matches initial state\n        expect(store.getState()).toBe('test-provider-state:running');\n      });\n    });\n\n    describe('setState', () => {\n      it('should set state for the provider', async () => {\n        // Arrange - create store with initial state\n        const { getTestProviderStoreById, fullTestProviderStore } = createTestProviderStore({\n          universalTestProviderStore: new MockUniversalStore<\n            TestProviderStateByProviderId,\n            TestProviderStoreEvent\n          >({\n            ...UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS,\n            initialState,\n          }),\n        });\n\n        // Act - set provider state to crashed\n        const store = getTestProviderStoreById('provider-1');\n        store.setState('test-provider-state:crashed');\n\n        // Assert - verify provider state was updated\n        await vi.waitFor(() => {\n          expect(store.getState()).toBe('test-provider-state:crashed');\n        });\n\n        // Assert - verify only this provider's state changed in full state\n        const fullState = fullTestProviderStore.getFullState();\n        expect(fullState).toEqual({\n          'provider-1': 'test-provider-state:crashed',\n          'provider-2': 'test-provider-state:succeeded',\n        });\n      });\n    });\n\n    describe('runWithState', () => {\n      it('should update state during execution flow', async () => {\n        // Arrange - create store and setup success callback\n        const { getTestProviderStoreById } = createTestProviderStore({\n          universalTestProviderStore: new MockUniversalStore<\n            TestProviderStateByProviderId,\n            TestProviderStoreEvent\n          >(UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS),\n        });\n\n        let runningGate: () => void;\n        const gatedSuccessCallback = vi.fn(\n          () =>\n            new Promise<void>((resolve) => {\n              runningGate = resolve;\n            })\n        );\n\n        const store = getTestProviderStoreById('provider-1');\n\n        // Act - start execution\n        store.runWithState(gatedSuccessCallback);\n\n        // Assert - verify running state\n        await vi.waitFor(() => {\n          expect(store.getState()).toBe('test-provider-state:running');\n        });\n\n        // Act - complete execution\n        runningGate!();\n\n        // Assert - verify success state\n        await vi.waitFor(() => {\n          expect(store.getState()).toBe('test-provider-state:succeeded');\n        });\n      });\n\n      it('should handle errors and update state to crashed', async () => {\n        // Arrange - create store and setup error callback\n        const { getTestProviderStoreById } = createTestProviderStore({\n          universalTestProviderStore: new MockUniversalStore<\n            TestProviderStateByProviderId,\n            TestProviderStoreEvent\n          >(UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS),\n        });\n\n        let runningGate: () => void;\n        const gatedErrorCallback = vi.fn(\n          () =>\n            new Promise<void>((resolve, reject) => {\n              runningGate = reject;\n            })\n        );\n\n        const store = getTestProviderStoreById('provider-1');\n\n        // Act - start execution\n        store.runWithState(gatedErrorCallback);\n\n        // Assert - verify running state\n        await vi.waitFor(() => {\n          expect(store.getState()).toBe('test-provider-state:running');\n        });\n\n        // Act - trigger error\n        runningGate!();\n\n        // Assert - verify error state\n        await vi.waitFor(() => {\n          expect(store.getState()).toBe('test-provider-state:crashed');\n        });\n      });\n    });\n\n    describe('onRunAll', () => {\n      it('should register and call listener when runAll is triggered', async () => {\n        // Arrange - create store and setup listener\n        const mockUniversalStore = new MockUniversalStore<\n          TestProviderStateByProviderId,\n          TestProviderStoreEvent\n        >({\n          ...UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS,\n          initialState,\n        });\n\n        const { getTestProviderStoreById, fullTestProviderStore } = createTestProviderStore({\n          universalTestProviderStore: mockUniversalStore,\n        });\n\n        const store = getTestProviderStoreById('provider-1');\n        const listener = vi.fn();\n\n        // Act - register listener and trigger runAll\n        const unsubscribe = store.onRunAll(listener);\n        fullTestProviderStore.runAll();\n\n        // Assert - verify listener was called\n        await vi.waitFor(() => {\n          expect(listener).toHaveBeenCalledTimes(1);\n        });\n\n        // Act - unsubscribe and trigger again\n        unsubscribe();\n        fullTestProviderStore.runAll();\n\n        // Assert - verify listener was not called after unsubscribe\n        expect(listener).toHaveBeenCalledTimes(1);\n      });\n    });\n\n    describe('onClearAll', () => {\n      it('should register and call listener when clearAll is triggered', async () => {\n        // Arrange - create store and setup listener\n        const mockUniversalStore = new MockUniversalStore<\n          TestProviderStateByProviderId,\n          TestProviderStoreEvent\n        >({\n          ...UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS,\n          initialState,\n        });\n\n        const { getTestProviderStoreById, fullTestProviderStore } = createTestProviderStore({\n          universalTestProviderStore: mockUniversalStore,\n        });\n\n        const store = getTestProviderStoreById('provider-1');\n        const listener = vi.fn();\n\n        // Act - register listener and trigger clearAll\n        const unsubscribe = store.onClearAll(listener);\n        fullTestProviderStore.clearAll();\n\n        // Assert - verify listener was called\n        await vi.waitFor(() => {\n          expect(listener).toHaveBeenCalledTimes(1);\n        });\n\n        // Act - unsubscribe and trigger again\n        unsubscribe();\n        fullTestProviderStore.clearAll();\n\n        // Assert - verify listener was not called after unsubscribe\n        expect(listener).toHaveBeenCalledTimes(1);\n      });\n    });\n\n    describe('settingsChanged', () => {\n      it('should register and call listener when settingsChanged is triggered', async () => {\n        // Arrange - create store and setup listener\n        const mockUniversalStore = new MockUniversalStore<\n          TestProviderStateByProviderId,\n          TestProviderStoreEvent\n        >({\n          ...UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS,\n          initialState,\n        });\n\n        const { getTestProviderStoreById, fullTestProviderStore } = createTestProviderStore({\n          universalTestProviderStore: mockUniversalStore,\n        });\n\n        const store = getTestProviderStoreById('provider-1');\n        const listener = vi.fn();\n\n        // Act - register listener and trigger settings change\n        const unsubscribe = fullTestProviderStore.onSettingsChanged(listener);\n        store.settingsChanged();\n\n        // Assert - verify listener was called\n        await vi.waitFor(() => {\n          expect(listener).toHaveBeenCalledTimes(1);\n        });\n\n        // Act - unsubscribe and trigger again\n        unsubscribe();\n        store.settingsChanged();\n\n        // Assert - verify listener was not called after unsubscribe\n        expect(listener).toHaveBeenCalledTimes(1);\n      });\n    });\n  });\n\n  describe('useTestProviderStore', () => {\n    it('should return all states when no selector is provided', () => {\n      // Arrange - create store with initial state\n      const mockUniversalStore = new MockUniversalStore<\n        TestProviderStateByProviderId,\n        TestProviderStoreEvent\n      >({\n        ...UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS,\n        initialState,\n      });\n\n      const testProviderStore = createTestProviderStore({\n        universalTestProviderStore: mockUniversalStore,\n        useUniversalStore,\n      });\n\n      // Act - render hook without selector\n      const { result } = renderHook(() => testProviderStore.useTestProviderStore());\n\n      // Assert - verify all states are returned\n      expect(result.current).toEqual(initialState);\n    });\n\n    it('should return selected states when selector is provided', () => {\n      // Arrange - create store with initial state\n      const mockUniversalStore = new MockUniversalStore<\n        TestProviderStateByProviderId,\n        TestProviderStoreEvent\n      >({\n        ...UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS,\n        initialState,\n      });\n\n      const testProviderStore = createTestProviderStore({\n        universalTestProviderStore: mockUniversalStore,\n        useUniversalStore,\n      });\n\n      // Act - render hook with selector\n      const { result } = renderHook(() =>\n        testProviderStore.useTestProviderStore((state) => state['provider-1'])\n      );\n\n      // Assert - verify selected state is returned\n      expect(result.current).toEqual('test-provider-state:running');\n    });\n\n    it('should re-render when test provider state matching the selector change', async () => {\n      // Arrange - create store and setup render counter\n      const { useTestProviderStore, fullTestProviderStore } = createTestProviderStore({\n        universalTestProviderStore: new MockUniversalStore({\n          ...UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS,\n          initialState,\n        }),\n        useUniversalStore,\n      });\n      const renderCounter = vi.fn();\n\n      // Create a selector that only returns provider-1 state\n      const provider1Selector = (state: TestProviderStateByProviderId) => state['provider-1'];\n\n      // Act - render hook with selector\n      const { result } = renderHook(() => {\n        renderCounter();\n        return useTestProviderStore(provider1Selector);\n      });\n\n      // Assert - verify initial render\n      expect(renderCounter).toHaveBeenCalledTimes(1);\n      expect(result.current).toEqual('test-provider-state:running');\n\n      // Act - update provider-1 state\n      act(() => {\n        fullTestProviderStore.setFullState((currentState) => ({\n          ...currentState,\n          'provider-1': 'test-provider-state:succeeded',\n        }));\n      });\n\n      // Assert - verify re-render with new state\n      expect(renderCounter).toHaveBeenCalledTimes(2);\n      expect(result.current).toEqual('test-provider-state:succeeded');\n    });\n\n    it('should not re-render when test provider state not matching the selector change', async () => {\n      // Arrange - create store and setup render counter\n      const { useTestProviderStore, fullTestProviderStore } = createTestProviderStore({\n        universalTestProviderStore: new MockUniversalStore({\n          ...UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS,\n          initialState,\n        }),\n        useUniversalStore,\n      });\n      const renderCounter = vi.fn();\n\n      // Create a selector that only returns provider-1 state\n      const provider1Selector = (state: TestProviderStateByProviderId) => state['provider-1'];\n\n      // Act - render hook with selector\n      const { result } = renderHook(() => {\n        renderCounter();\n        return useTestProviderStore(provider1Selector);\n      });\n\n      // Assert - verify initial render\n      expect(renderCounter).toHaveBeenCalledTimes(1);\n      expect(result.current).toEqual('test-provider-state:running');\n\n      // Act - update provider-2 state\n      act(() => {\n        fullTestProviderStore.setFullState((currentState) => ({\n          ...currentState,\n          'provider-2': 'test-provider-state:succeeded',\n        }));\n      });\n\n      // Assert - verify no re-render occurred\n      expect(renderCounter).toHaveBeenCalledTimes(1);\n      expect(result.current).toEqual('test-provider-state:running');\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/shared/test-provider-store/index.ts",
    "content": "import type { UniversalStore } from '../universal-store/index.ts';\nimport type { BaseEvent, StoreOptions } from '../universal-store/types.ts';\nimport type { useUniversalStore as managerUseUniversalStore } from '../universal-store/use-universal-store-manager.ts';\n\nexport const UNIVERSAL_TEST_PROVIDER_STORE_OPTIONS: StoreOptions<TestProviderStateByProviderId> = {\n  id: 'storybook/test-provider',\n  leader: true,\n  initialState: {},\n};\n\nexport type TestProviderState =\n  | 'test-provider-state:pending'\n  | 'test-provider-state:running'\n  | 'test-provider-state:succeeded'\n  | 'test-provider-state:crashed';\nexport type TestProviderId = string;\nexport type TestProviderStateByProviderId = Record<TestProviderId, TestProviderState>;\n\ntype TestProviderStoreEventType = 'run-all' | 'clear-all' | 'settings-changed';\n\nexport type TestProviderStoreEvent = BaseEvent & {\n  type: TestProviderStoreEventType;\n};\n\ntype BaseTestProviderStore = {\n  /**\n   * Notifies all listeners that settings have changed for test providers. The Storybook UI will\n   * highlight the test providers to tell the user that settings has changed.\n   */\n  settingsChanged: () => void;\n\n  /**\n   * Subscribe to clicks on the \"Run All\" button, that is supposed to trigger all test providers to\n   * run. Your test provider should do the \"main thing\" when this happens, similar to when the user\n   * triggers your test provider specifically.\n   *\n   * @example\n   *\n   * ```typescript\n   * // Subscribe to run-all events\n   * const unsubscribe = myTestProviderStore.onRunAll(() => {\n   *   await runAllMyTests();\n   * });\n   * ```\n   */\n  onRunAll: (listener: () => void) => () => void;\n\n  /**\n   * Subscribe to clicks on the \"Clear All\" button, that is supposed to clear all state from test\n   * providers. Storybook already clears all statuses, but if your test provider has more\n   * non-status-based state, you can use this to clear that here.\n   *\n   * @remarks\n   * The purpose of this is _not_ to clear your test provider's settings, only the test results.\n   * @example\n   *\n   * ```typescript\n   * // Subscribe to clear-all events\n   * const unsubscribe = myTestProviderStore.onClearAll(() => {\n   *   clearMyTestResults();\n   * });\n   *\n   * // Later, when no longer needed\n   * unsubscribe();\n   * ```\n   */\n  onClearAll: (listener: () => void) => () => void;\n};\n\n/**\n * Test provider store that holds _all_ test provider's states.\n *\n * This is an internal store only meant to be used by Storybook UI itself. The API can change at any\n * time. Addons and test providers should use the `getTestProvider` function instead.\n */\ntype FullTestProviderStore = BaseTestProviderStore & {\n  /**\n   * Gets the full state of all test providers as a record of provider IDs to their states\n   *\n   * @example\n   *\n   * ```typescript\n   * // Get the current state of all test providers\n   * const allProviderStates = fullTestProviderStore.getFullState();\n   * console.log(allProviderStates);\n   * // Example output: { 'provider-1': 'test-provider-state:running', 'provider-2': 'test-provider-state:succeeded' }\n   *\n   * // Check if any providers are in a specific state\n   * const hasRunningTests = Object.values(allProviderStates).some(\n   *   (state) => state === 'test-provider-state:running'\n   * );\n   * ```\n   */\n  getFullState: UniversalStore<TestProviderStateByProviderId, TestProviderStoreEvent>['getState'];\n\n  /**\n   * Sets the full state of all test providers, replacing the current state completely\n   *\n   * @example\n   *\n   * ```typescript\n   * // Set all providers to a specific state\n   * fullTestProviderStore.setFullState({\n   *   'provider-1': 'test-provider-state:pending',\n   *   'provider-2': 'test-provider-state:pending',\n   * });\n   *\n   * // Update state using a function that receives the current state\n   * fullTestProviderStore.setFullState((currentState) => ({\n   *   ...currentState,\n   *   'provider-1': 'test-provider-state:running',\n   * }));\n   * ```\n   */\n  setFullState: UniversalStore<TestProviderStateByProviderId, TestProviderStoreEvent>['setState'];\n\n  /**\n   * Subscribe to settingsChanged calls by test providers.\n   *\n   * @example\n   *\n   * ```typescript\n   * // Subscribe to settings changes for any test provider\n   * const unsubscribe = fullTestProviderStore.onSettingsChanged((providerId) => {\n   *   console.log(`Settings changed for provider: ${providerId}`);\n   *   // Update UI or reload configuration for the specific provider\n   * });\n   *\n   * // Later, when no longer needed\n   * unsubscribe();\n   * ```\n   */\n  onSettingsChanged: (listener: (testProviderId: TestProviderId) => void) => () => void;\n\n  /**\n   * Triggers all test providers to start running their tests\n   *\n   * @example\n   *\n   * ```typescript\n   * // Add a button to run all tests\n   * const RunAllButton = () => (\n   *   <button\n   *     onClick={() => fullTestProviderStore.runAll()}\n   *     disabled={isRunning}\n   *   >\n   *     Run All Tests\n   *   </button>\n   * );\n   * ```\n   */\n  runAll: () => void;\n\n  /**\n   * Clears the state of all test providers, resetting them to their initial state\n   *\n   * @example\n   *\n   * ```typescript\n   * // Add a button to clear all test results\n   * const ClearAllButton = () => (\n   *   <button onClick={() => fullTestProviderStore.clearAll()}>\n   *     Clear All Test Results\n   *   </button>\n   * );\n   * ```\n   */\n  clearAll: () => void;\n};\n\n/**\n * Represents a store for a specific test provider, identified by its unique ID. This store provides\n * methods to manage the state of an individual test provider, including getting and setting its\n * state, running operations with automatic state management, and accessing its unique identifier.\n *\n * Each test provider has its own instance of this store, allowing for independent state management\n * across different test providers in the application.\n *\n * @example\n *\n * ```typescript\n * // Get a store for a specific test provider\n * const grammarStore = getTestProviderStoreById('addon-grammar');\n *\n * // Check the current state\n * if (grammarStore.getState() === 'test-provider-state:pending') {\n *   console.log('Grammar tests are ready to run');\n * }\n *\n * // Run tests with automatic state management\n * grammarStore.runWithState(async () => {\n *   await runGrammarTests();\n * });\n * ```\n *\n * @see {@link TestProviderState} for possible state values\n * @see {@link BaseTestProviderStore} for methods inherited from the base store\n */\nexport type TestProviderStoreById = BaseTestProviderStore & {\n  /**\n   * Gets the current state of this specific test provider\n   *\n   * The state represents the current execution status of the test provider, which can be one of the\n   * following:\n   *\n   * - 'test-provider-state:pending': Tests have not been run yet\n   * - 'test-provider-state:running': Tests are currently running\n   * - 'test-provider-state:succeeded': Tests completed successfully\n   * - 'test-provider-state:crashed': Running tests failed or encountered an error\n   *\n   * Storybook UI will use this state to determine what to show in the UI.\n   *\n   * @remarks\n   * The 'test-provider-state:crashed' is meant to signify that the test run as a whole failed to\n   * execute for some reason. It should _not_ be set just because a number of tests failed, use\n   * statuses and the status store for that. See {@link TestStatusStore} for managing individual test\n   * statuses.\n   * @example\n   *\n   * ```typescript\n   * // Get the current state of a specific test provider\n   * const state = testProviderStore.getState();\n   *\n   * // Conditionally render UI based on the state\n   * const TestStatus = () => {\n   *   const state = testProviderStore.getState();\n   *\n   *   if (state === 'test-provider-state:running') {\n   *     return <Spinner />;\n   *   } else if (state === 'test-provider-state:succeeded') {\n   *     return <SuccessIcon />;\n   *   } else if (state === 'test-provider-state:crashed') {\n   *     return <ErrorIcon />;\n   *   }\n   *\n   *   return <PendingIcon />;\n   * };\n   * ```\n   */\n  getState: () => TestProviderState;\n\n  /**\n   * Sets the state of this specific test provider\n   *\n   * This method allows you to manually update the execution state of the test provider. It's\n   * typically used when you need to reflect the current status of test execution in the UI or when\n   * you want to programmatically control the test provider's state.\n   *\n   * Common use cases include:\n   *\n   * - Setting to 'running' when tests start\n   * - Setting to 'succeeded' when tests complete successfully\n   * - Setting to 'crashed' when tests fail or encounter errors\n   * - Setting to 'pending' to reset the state\n   *\n   * The state represents the current execution status of the test provider, which can be one of the\n   * following:\n   *\n   * - 'test-provider-state:pending': Tests have not been run yet\n   * - 'test-provider-state:running': Tests are currently running\n   * - 'test-provider-state:succeeded': Tests completed successfully\n   * - 'test-provider-state:crashed': Running tests failed or encountered an error\n   *\n   * Storybook UI will use this state to determine what to show in the UI.\n   *\n   * @remarks\n   * The 'test-provider-state:crashed' is meant to signify that the test run as a whole failed to\n   * execute for some reason. It should _not_ be set just because a number of tests failed, use\n   * statuses and the status store for that. See {@link TestStatusStore} for managing individual test\n   * statuses.\n   *\n   * For most use cases, consider using {@link runWithState} instead, which provides automatic state\n   * management and error handling during test execution.\n   * @example\n   *\n   * ```typescript\n   * // Update the state when tests start running\n   * const startTests = async () => {\n   *   testProviderStore.setState('test-provider-state:running');\n   *   ... run tests ...\n   * };\n   * ```\n   */\n  setState: (state: TestProviderState) => void;\n\n  /**\n   * Runs a callback and automatically updates the test provider's state with running, succeeded or\n   * crashed, depending on the end result.\n   *\n   * - Immediately changes the state to 'running'\n   * - If the callback returns/resolves, change the state to 'succeeded'.\n   * - If the callback throws an error/rejects, change the state to 'crashed'.\n   *\n   * This approach helps prevent state inconsistencies that might occur if exceptions are thrown\n   * during test execution.\n   *\n   * @example\n   *\n   * ```typescript\n   * // Run tests with automatic state management\n   * const runTests = () => {\n   *   testProviderStore.runWithState(async () => {\n   *     // The state is automatically set to 'running' before this callback\n   *\n   *     // Run tests here...\n   *     const results = await executeTests();\n   *   });\n   * };\n   * ```\n   */\n  runWithState: (callback: () => void | Promise<void>) => Promise<void>;\n\n  /** The unique identifier for this test provider */\n  testProviderId: TestProviderId;\n};\n\n/**\n * React OR preview hook for accessing the state of _all_ test providers. This hook will only\n * trigger a re-render when the state changes. It is recommended to pass the optional selector, to\n * get more fine-grained control of re-renders.\n *\n * @example\n *\n * ```typescript\n * const TestStatus = () => {\n *   const state = useTestProviderStore((state) => state['my-test-provider']);\n * };\n * ```\n */\nexport type UseTestProviderStore = <T = TestProviderStateByProviderId>(\n  /**\n   * Optional selector function to extract or transform specific parts of the state\n   *\n   * @example\n   *\n   * ```typescript\n   * // Use the entire state\n   * const allProviderStates = useTestProviderStore();\n   *\n   * // Get state for a specific provider\n   * const myProviderState = useTestProviderStore((state) => state['my-test-provider']);\n   *\n   * // Get a count of providers in each state\n   * const statusCounts = useTestProviderStore((state) => {\n   *   const counts = {\n   *     pending: 0,\n   *     running: 0,\n   *     succeeded: 0,\n   *     crashed: 0,\n   *   };\n   *\n   *   Object.values(state).forEach((status) => {\n   *     if (status === 'test-provider-state:pending') counts.pending++;\n   *     else if (status === 'test-provider-state:running') counts.running++;\n   *     else if (status === 'test-provider-state:succeeded') counts.succeeded++;\n   *     else if (status === 'test-provider-state:crashed') counts.crashed++;\n   *   });\n   *\n   *   return counts;\n   * });\n   *\n   * // Check if all tests have completed\n   * const allTestsCompleted = useTestProviderStore((state) => {\n   *   return Object.values(state).every(\n   *     (status) =>\n   *       status === 'test-provider-state:succeeded' ||\n   *       status === 'test-provider-state:crashed'\n   *   );\n   * });\n   * ```\n   */\n  selector?: (state: TestProviderStateByProviderId) => T\n) => T;\n\nexport function createTestProviderStore(params: {\n  universalTestProviderStore: UniversalStore<TestProviderStateByProviderId, TestProviderStoreEvent>;\n  useUniversalStore?: never;\n}): {\n  getTestProviderStoreById: (testProviderId: TestProviderId) => TestProviderStoreById;\n  fullTestProviderStore: FullTestProviderStore;\n  universalTestProviderStore: UniversalStore<TestProviderStateByProviderId, TestProviderStoreEvent>;\n};\nexport function createTestProviderStore(params: {\n  universalTestProviderStore: UniversalStore<TestProviderStateByProviderId, TestProviderStoreEvent>;\n  useUniversalStore: typeof managerUseUniversalStore;\n}): {\n  getTestProviderStoreById: (testProviderId: TestProviderId) => TestProviderStoreById;\n  fullTestProviderStore: FullTestProviderStore;\n  universalTestProviderStore: UniversalStore<TestProviderStateByProviderId, TestProviderStoreEvent>;\n  useTestProviderStore: UseTestProviderStore;\n};\nexport function createTestProviderStore({\n  universalTestProviderStore,\n  useUniversalStore,\n}: {\n  universalTestProviderStore: UniversalStore<TestProviderStateByProviderId, TestProviderStoreEvent>;\n  useUniversalStore?: typeof managerUseUniversalStore;\n}) {\n  const baseStore: BaseTestProviderStore = {\n    settingsChanged: () => {\n      universalTestProviderStore.untilReady().then(() => {\n        universalTestProviderStore.send({ type: 'settings-changed' });\n      });\n    },\n    onRunAll: (listener) => universalTestProviderStore.subscribe('run-all', listener),\n    onClearAll: (listener) => universalTestProviderStore.subscribe('clear-all', listener),\n  };\n\n  const fullTestProviderStore: FullTestProviderStore = {\n    ...baseStore,\n    getFullState: universalTestProviderStore.getState,\n    setFullState: universalTestProviderStore.setState,\n    onSettingsChanged: (listener) =>\n      universalTestProviderStore.subscribe('settings-changed', listener),\n    runAll: async () => {\n      await universalTestProviderStore.untilReady();\n      universalTestProviderStore.send({ type: 'run-all' });\n    },\n    clearAll: async () => {\n      await universalTestProviderStore.untilReady();\n      universalTestProviderStore.send({ type: 'clear-all' });\n    },\n  };\n\n  const getTestProviderStoreById = (testProviderId: string): TestProviderStoreById => {\n    const getStateForTestProvider = () =>\n      universalTestProviderStore.getState()[testProviderId] ?? 'test-provider-state:pending';\n    const setStateForTestProvider = (state: TestProviderState) => {\n      universalTestProviderStore.untilReady().then(() => {\n        universalTestProviderStore.setState((currentState) => ({\n          ...currentState,\n          [testProviderId]: state,\n        }));\n      });\n    };\n    return {\n      ...baseStore,\n      testProviderId,\n      getState: getStateForTestProvider,\n      setState: setStateForTestProvider,\n      runWithState: async (callback) => {\n        setStateForTestProvider('test-provider-state:running');\n        try {\n          await callback();\n          setStateForTestProvider('test-provider-state:succeeded');\n        } catch (error) {\n          setStateForTestProvider('test-provider-state:crashed');\n        }\n      },\n    };\n  };\n\n  if (useUniversalStore) {\n    return {\n      getTestProviderStoreById,\n      fullTestProviderStore,\n      universalTestProviderStore,\n      useTestProviderStore: <T = TestProviderStateByProviderId>(\n        selector?: (testProviders: TestProviderStateByProviderId) => T\n      ) => useUniversalStore(universalTestProviderStore, selector as any)[0] as T,\n    };\n  }\n\n  return {\n    getTestProviderStoreById,\n    fullTestProviderStore,\n    universalTestProviderStore,\n  };\n}\n"
  },
  {
    "path": "code/core/src/shared/universal-store/README.md",
    "content": "# Universal Store\n\nThe Universal Store API is used to manage state and events that should be synced across multiple environments, such as the server, the manager or the preview.\n\nIt is still highly experimental, and the API is subject to change - please don't use it.\n\nFor docs, see [UniversalStore's JSDocs](./index.ts). For usage examples and expected behavior, see [the tests](./index.test.ts)\n"
  },
  {
    "path": "code/core/src/shared/universal-store/__mocks__/instances.ts",
    "content": "/**\n * Mock implementation of a universal store instances manager for testing purposes.\n *\n * This class provides a two-level map structure to manage store instances:\n *\n * - First level: environments (identified by environment key)\n * - Second level: store instances within each environment (identified by instance key)\n *\n * The keys must be in the format \"environment:instance\".\n */\nimport { vi } from 'vitest';\n\nimport invariant from 'tiny-invariant';\n\nimport type { UniversalStore } from '../index.ts';\n\nclass MockInstancesMap {\n  environments = new Map<string, Map<string, UniversalStore<any, any>>>();\n\n  set = vi.fn((key: string, value: UniversalStore<any, any>) => {\n    const { environment, instanceKey } = this.getKeys(key);\n    environment.set(instanceKey, value);\n\n    return this;\n  });\n\n  get = vi.fn((key: string) => {\n    const { environment, instanceKey } = this.getKeys(key);\n    return environment.get(instanceKey);\n  });\n\n  has = vi.fn((key: string) => {\n    const { environment, instanceKey } = this.getKeys(key);\n    return environment.has(instanceKey);\n  });\n\n  delete = vi.fn((key: string) => {\n    const { environment, instanceKey } = this.getKeys(key);\n    return environment.delete(instanceKey);\n  });\n\n  clear = vi.fn((environmentKey: string) => {\n    invariant(\n      this.environments.has(environmentKey),\n      'Environment key is required when clearing instances. To clear all environments, use `clearAllEnvironments`'\n    );\n    return this.environments.get(environmentKey)!.clear();\n  });\n\n  environmentSize = vi.fn((environmentKey: string) => {\n    return this.environments.get(environmentKey)?.size ?? 0;\n  });\n\n  clearAllEnvironments = vi.fn(() => {\n    this.environments.clear();\n  });\n\n  private getKeys(key: string) {\n    const [environmentKey, instanceKey] = key.split(':');\n    invariant(\n      environmentKey && instanceKey,\n      'Creating instances with the mock requires that the id is in the form \"environment:instance\"'\n    );\n    if (!this.environments.has(environmentKey)) {\n      this.environments.set(environmentKey, new Map());\n    }\n    return { environment: this.environments.get(environmentKey)!, instanceKey };\n  }\n}\n\nexport const instances = new MockInstancesMap();\n"
  },
  {
    "path": "code/core/src/shared/universal-store/index.test-d.ts",
    "content": "import { describe, expectTypeOf, it } from 'vitest';\n\nimport { UniversalStore } from './index.ts';\nimport type { EventInfo, InternalEvent } from './types.ts';\nimport { useUniversalStore as useUniversalStoreManager } from './use-universal-store-manager.ts';\nimport { useUniversalStore as useUniversalStorePreview } from './use-universal-store-preview.ts';\n\ntype State = { count: number; done: boolean };\ntype IncrementEvent = {\n  type: 'INCREMENT';\n  payload: number;\n};\ntype ToggleEvent = { type: 'TOGGLE' };\ntype CustomEvent = IncrementEvent | ToggleEvent;\n\ndescribe('UniversalStore', () => {\n  it('should have any types without State or Event specified', () => {\n    const store = UniversalStore.create({ id: 'test' });\n    expectTypeOf(store).toEqualTypeOf<UniversalStore<any, { type: string; payload?: any }>>();\n\n    expectTypeOf(store.getState()).toEqualTypeOf<any>();\n    expectTypeOf(store.setState).parameter(0).toEqualTypeOf<any | ((state: any) => any)>();\n    store.onStateChange((state, previousState, eventInfo) => {\n      expectTypeOf(state).toEqualTypeOf<any>();\n      expectTypeOf(previousState).toEqualTypeOf<any>();\n      expectTypeOf(eventInfo).toEqualTypeOf<EventInfo>();\n    });\n  });\n\n  it('should have the correct types for State', () => {\n    const store = UniversalStore.create<State>({ id: 'test' });\n    expectTypeOf(store).toEqualTypeOf<UniversalStore<State, { type: string; payload?: any }>>();\n\n    // Assert - get\n    expectTypeOf(store.getState()).toEqualTypeOf<State>();\n\n    // Assert - set\n    expectTypeOf(store.setState).parameter(0).toEqualTypeOf<State | ((state: State) => State)>();\n\n    // Assert - listener\n    store.onStateChange((state, previousState, eventInfo) => {\n      expectTypeOf(state).toEqualTypeOf<State>();\n      expectTypeOf(previousState).toEqualTypeOf<State>();\n      expectTypeOf(eventInfo).toEqualTypeOf<EventInfo>();\n    });\n  });\n\n  it('should have the correct types for CustomEvent', () => {\n    const store = UniversalStore.create<any, CustomEvent>({ id: 'test' });\n    expectTypeOf(store).toEqualTypeOf<UniversalStore<any, CustomEvent>>();\n\n    expectTypeOf(store.send).parameter(0).toEqualTypeOf<CustomEvent>();\n\n    store.subscribe((event) => {\n      expectTypeOf(event).toMatchTypeOf<CustomEvent | InternalEvent<State>>();\n      if (event.type === 'INCREMENT') {\n        expectTypeOf(event.payload).toEqualTypeOf<IncrementEvent['payload']>();\n      }\n    });\n\n    store.subscribe('TOGGLE', (event) => {\n      expectTypeOf(event).toEqualTypeOf<ToggleEvent>();\n    });\n  });\n\n  describe('useUniversalStore', () => {\n    describe('Manager', () => {\n      it('should have correct types for the state without a selector', () => {\n        const store = UniversalStore.create<State, CustomEvent>({ id: 'test' });\n        const [state, setState] = useUniversalStoreManager(store);\n        expectTypeOf(state).toEqualTypeOf<State>();\n        expectTypeOf(setState).parameter(0).toEqualTypeOf<State | ((state: State) => State)>();\n      });\n\n      it('should have correct types for the state with a selector', () => {\n        const store = UniversalStore.create<State, CustomEvent>({ id: 'test' });\n        const [state, setState] = useUniversalStoreManager(store, (s) => {\n          expectTypeOf(s).toEqualTypeOf<State>();\n          return s.count;\n        });\n        expectTypeOf(state).toEqualTypeOf<State['count']>();\n        expectTypeOf(setState).parameter(0).toEqualTypeOf<State | ((state: State) => State)>();\n      });\n    });\n\n    describe('Preview', () => {\n      it('should have correct types for the state without a selector', () => {\n        const store = UniversalStore.create<State, CustomEvent>({ id: 'test' });\n        const [state, setState] = useUniversalStorePreview(store);\n        expectTypeOf(state).toEqualTypeOf<State>();\n        expectTypeOf(setState).parameter(0).toEqualTypeOf<State | ((state: State) => State)>();\n      });\n\n      it('should have correct types for the state with a selector', () => {\n        const store = UniversalStore.create<State, CustomEvent>({ id: 'test' });\n        const [state, setState] = useUniversalStorePreview(store, (s) => {\n          expectTypeOf(s).toEqualTypeOf<State>();\n          return s.count;\n        });\n        expectTypeOf(state).toEqualTypeOf<State['count']>();\n        expectTypeOf(setState).parameter(0).toEqualTypeOf<State | ((state: State) => State)>();\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/shared/universal-store/index.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { dedent } from 'ts-dedent';\n\nimport { UniversalStore } from './index.ts';\nimport { instances as mockedInstances } from './__mocks__/instances.ts';\nimport { MockUniversalStore } from './mock.ts';\nimport type { ChannelEvent } from './types.ts';\n\nvi.mock('./instances');\n\nconst mockChannelListeners = new Map<string, Set<(...args: any[]) => void>>();\n\nconst mockChannel = {\n  on: vi.fn((eventType: string, listener: (...args: any[]) => void) => {\n    const [universalStorePrefix, environmentId, universalStoreId] = eventType.split(':');\n    if (!mockChannelListeners.has(universalStoreId)) {\n      mockChannelListeners.set(universalStoreId, new Set());\n    }\n    const listeners = mockChannelListeners.get(universalStoreId)!;\n    listeners.add(listener);\n  }),\n  off: vi.fn((eventType: string, listener: (...args: any[]) => void) => {\n    const universalStoreId = eventType.split(':')[2];\n    if (!mockChannelListeners.has(universalStoreId)) {\n      return;\n    }\n    const listeners = mockChannelListeners.get(universalStoreId)!;\n    listeners.delete(listener);\n  }),\n  emit: vi.fn((eventType: string, channelEvent: ChannelEvent<any, any>) => {\n    const [universalStorePrefix, environmentId, universalStoreId] = eventType.split(':');\n    if (!mockChannelListeners.has(universalStoreId)) {\n      return;\n    }\n    const listeners = mockChannelListeners.get(universalStoreId)!;\n    setTimeout(() => {\n      // this is a simplification, emulating that the event is emitted asynchronously\n      // in reality, it would be synchronous within the same environment, but async across environments\n      listeners.forEach((listener) => listener(channelEvent));\n    }, 0);\n  }),\n};\n\ndescribe('UniversalStore', () => {\n  beforeEach((context) => {\n    vi.useFakeTimers();\n\n    // Mock Date and Math.random to make the actorId deterministic\n    let randomNumberCounter = 1;\n    vi.setSystemTime(new Date('2025-02-14'));\n    vi.spyOn(Math, 'random').mockImplementation(() => {\n      return randomNumberCounter++ / 10;\n    });\n\n    // Always prepare the store, unless the test is specifically for unprepared state\n    if (!context.task.name.toLowerCase().includes('unprepared')) {\n      UniversalStore.__prepare(mockChannel, UniversalStore.Environment.MANAGER);\n    }\n\n    return () => {\n      randomNumberCounter = 0;\n      vi.clearAllTimers();\n      mockedInstances.clearAllEnvironments();\n      mockChannelListeners.clear();\n      UniversalStore.__reset();\n    };\n  });\n\n  describe('Creation', () => {\n    describe('Leader', () => {\n      it('should create a new leader instance with initial state', () => {\n        // Act - create a new leader instance\n        const store = UniversalStore.create({\n          id: 'env1:test',\n          leader: true,\n          initialState: { count: 0 },\n        });\n\n        // Assert - the store should be created with the initial state and actor\n        expect(store.getState()).toEqual({ count: 0 });\n        expect(store.actor.type).toBe('LEADER');\n        expect(store.actor.id).toBe('m7405c003lllllllllm');\n      });\n\n      it('should throw when trying to create an instance with the constructor directly', () => {\n        // Act, Assert - creating an instance with the constructor and expect it to throw\n        expect(\n          () =>\n            new (UniversalStore as any)({\n              id: 'env1:test',\n              leader: true,\n            })\n        ).toThrowErrorMatchingInlineSnapshot(\n          `[TypeError: UniversalStore is not constructable - use UniversalStore.create() instead]`\n        );\n      });\n\n      it('should throw when id is not provided', () => {\n        // Arrange, Act, Assert - creating an instance without an id and expect it to throw\n        expect(() => (UniversalStore as any).create()).toThrowErrorMatchingInlineSnapshot(\n          `[TypeError: id is required and must be a string, when creating a UniversalStore]`\n        );\n      });\n\n      it('should re-use an existing instance when creating a new one with the same id', () => {\n        // Arrange - mock the console.warn function\n        vi.spyOn(console, 'warn').mockImplementation(() => {});\n\n        // Act - create two stores with the same id\n        const firstStore = UniversalStore.create({\n          id: 'env1:test',\n          leader: true,\n        });\n        const secondStore = UniversalStore.create({\n          id: 'env1:test',\n          leader: true,\n        });\n\n        // Assert - the second store should be the same as the first, and a warning should be logged\n        expect(secondStore).toBe(firstStore);\n        expect(mockedInstances.set).toHaveBeenCalledOnce();\n        expect(console.warn)\n          .toHaveBeenCalledExactlyOnceWith(`UniversalStore with id \\\"env1:test\\\" already exists in this environment, re-using existing.\nYou should reuse the existing instance instead of trying to create a new one.`);\n      });\n\n      it('should not re-use an existing instance when creating a new one with a different id', () => {\n        // Arrange - mock the console.warn function\n        vi.spyOn(console, 'warn').mockImplementation(() => {});\n\n        // Act - create two stores with different ids\n        const firstStore = UniversalStore.create({\n          id: 'env1:test-1',\n          leader: true,\n        });\n        const secondStore = UniversalStore.create({\n          id: 'env1:test-2',\n          leader: true,\n        });\n\n        // Assert - the second store should not be the same as the first, and a warning should not be logged\n        expect(secondStore).not.toBe(firstStore);\n        expect(mockedInstances.set).toHaveBeenCalledTimes(2);\n        expect(console.warn).not.toBeCalled();\n      });\n\n      it('should subscribe to the channel for changes', async () => {\n        // Act - create a new leader instance\n        UniversalStore.create({\n          id: 'env1:test',\n          leader: true,\n        });\n\n        // Assert - the store should subscribe to the channel\n        await vi.waitFor(() => {\n          expect(mockChannel.on).toHaveBeenCalledWith(\n            'UNIVERSAL_STORE:env1:test',\n            expect.any(Function)\n          );\n        });\n      });\n\n      it('should eventually subscribe to the channel if it is created in an unprepared context', async () => {\n        // Act - create a new leader instance without awaiting\n        const store = UniversalStore.create({\n          id: 'env1:test',\n          leader: true,\n        });\n\n        // Assert - the store should not subscribe to the channel immediately\n        await vi.waitFor(\n          () => {\n            expect(mockChannel.on).not.toBeCalled();\n          },\n          { timeout: 200 }\n        );\n        expect(store.status).toBe(UniversalStore.Status.UNPREPARED);\n\n        // Act - prepare the store\n        UniversalStore.__prepare(mockChannel, UniversalStore.Environment.MANAGER);\n\n        // Assert - the store should eventually subscribe to the channel\n        await vi.waitFor(\n          () => {\n            expect(store.status).toBe(UniversalStore.Status.READY);\n            expect(mockChannel.on).toHaveBeenCalledExactlyOnceWith(\n              'UNIVERSAL_STORE:env1:test',\n              expect.any(Function)\n            );\n          },\n          { timeout: 200 }\n        );\n      });\n\n      it('should log an error when creating a leader when a leader already exists with the same id', async () => {\n        // Arrange - create an initial leader and follower\n        vi.spyOn(console, 'error').mockImplementation(() => {});\n\n        const firstLeader = UniversalStore.create({\n          id: 'env1:test',\n          leader: true,\n          initialState: { count: 0 },\n        });\n\n        // Act - create the second leader\n        const secondLeader = UniversalStore.create({\n          id: 'env2:test',\n          leader: true,\n          initialState: { count: 99 },\n        });\n\n        // Assert - both leaders announce their creation\n        await vi.waitFor(\n          () => {\n            expect(mockChannel.emit).toHaveBeenCalledTimes(2);\n            expect(mockChannel.emit).toHaveBeenNthCalledWith(1, 'UNIVERSAL_STORE:env1:test', {\n              event: {\n                type: UniversalStore.InternalEventType.LEADER_CREATED,\n              },\n              eventInfo: {\n                actor: {\n                  type: UniversalStore.ActorType.LEADER,\n                  id: firstLeader.actor.id,\n                  environment: UniversalStore.Environment.MANAGER,\n                },\n              },\n            });\n            expect(mockChannel.emit).toHaveBeenNthCalledWith(2, 'UNIVERSAL_STORE:env2:test', {\n              event: {\n                type: UniversalStore.InternalEventType.LEADER_CREATED,\n              },\n              eventInfo: {\n                actor: {\n                  type: UniversalStore.ActorType.LEADER,\n                  id: secondLeader.actor.id,\n                  environment: UniversalStore.Environment.MANAGER,\n                },\n              },\n            });\n          },\n          { timeout: 200 }\n        );\n\n        expect(firstLeader.status).toBe(UniversalStore.Status.ERROR);\n        expect(secondLeader.status).toBe(UniversalStore.Status.ERROR);\n        expect(console.error).toHaveBeenNthCalledWith(\n          1,\n          dedent`Detected multiple UniversalStore leaders created with the same id \"env2:test\".\n            Only one leader can exists at a time, your stores are now in an invalid state.\n            Leaders detected:\n            this: {\n              \"id\": \"m7405c0077777777778\",\n              \"type\": \"LEADER\",\n              \"environment\": \"MANAGER\"\n            }\n            other: {\n              \"id\": \"m7405c003lllllllllm\",\n              \"type\": \"LEADER\",\n              \"environment\": \"MANAGER\"\n            }`\n        );\n        expect(console.error).toHaveBeenNthCalledWith(\n          2,\n          dedent`Detected multiple UniversalStore leaders created with the same id \"env1:test\".\n            Only one leader can exists at a time, your stores are now in an invalid state.\n            Leaders detected:\n            this: {\n              \"id\": \"m7405c003lllllllllm\",\n              \"type\": \"LEADER\",\n              \"environment\": \"MANAGER\"\n            }\n            other: {\n              \"id\": \"m7405c0077777777778\",\n              \"type\": \"LEADER\",\n              \"environment\": \"MANAGER\"\n            }`\n        );\n      });\n    });\n\n    describe('Follower', () => {\n      it('should create a new follower instance', () => {\n        // Act - create a new follower instance\n        const store = UniversalStore.create({\n          id: 'env1:test',\n          leader: false,\n        });\n\n        // Assert - the store should be created with the initial state and actor\n        expect(store.getState()).toEqual(undefined);\n        expect(store.actor.type).toBe('FOLLOWER');\n        expect(store.actor.id).toBe('m7405c003lllllllllm');\n      });\n\n      it('should get existing state when a follower is created without initialState', async () => {\n        // Act - create a leader and a follower\n        const leader = UniversalStore.create({\n          id: 'env1:test',\n          leader: true,\n          initialState: { count: 0 },\n        });\n        const follower = UniversalStore.create({\n          id: 'env2:test',\n          leader: false,\n        });\n\n        // Assert - the follower should eventually get the existing state from the leader\n        await vi.waitFor(\n          () => {\n            expect(follower.getState()).toEqual(leader.getState());\n          },\n          { timeout: 200 }\n        );\n\n        // Assert - the follower should have requested the existing state and the leader should have responded\n        expect(mockChannel.emit.mock.calls).toMatchInlineSnapshot(`\n          [\n            [\n              \"UNIVERSAL_STORE:env1:test\",\n              {\n                \"event\": {\n                  \"type\": \"__LEADER_CREATED\",\n                },\n                \"eventInfo\": {\n                  \"actor\": {\n                    \"environment\": \"MANAGER\",\n                    \"id\": \"m7405c003lllllllllm\",\n                    \"type\": \"LEADER\",\n                  },\n                },\n              },\n            ],\n            [\n              \"UNIVERSAL_STORE:env2:test\",\n              {\n                \"event\": {\n                  \"type\": \"__FOLLOWER_CREATED\",\n                },\n                \"eventInfo\": {\n                  \"actor\": {\n                    \"environment\": \"MANAGER\",\n                    \"id\": \"m7405c0077777777778\",\n                    \"type\": \"FOLLOWER\",\n                  },\n                },\n              },\n            ],\n            [\n              \"UNIVERSAL_STORE:env2:test\",\n              {\n                \"event\": {\n                  \"type\": \"__EXISTING_STATE_REQUEST\",\n                },\n                \"eventInfo\": {\n                  \"actor\": {\n                    \"environment\": \"MANAGER\",\n                    \"id\": \"m7405c0077777777778\",\n                    \"type\": \"FOLLOWER\",\n                  },\n                },\n              },\n            ],\n            [\n              \"UNIVERSAL_STORE:env1:test\",\n              {\n                \"event\": {\n                  \"type\": \"__FOLLOWER_CREATED\",\n                },\n                \"eventInfo\": {\n                  \"actor\": {\n                    \"environment\": \"MANAGER\",\n                    \"id\": \"m7405c0077777777778\",\n                    \"type\": \"FOLLOWER\",\n                  },\n                  \"forwardingActor\": {\n                    \"environment\": \"MANAGER\",\n                    \"id\": \"m7405c003lllllllllm\",\n                    \"type\": \"LEADER\",\n                  },\n                },\n              },\n            ],\n            [\n              \"UNIVERSAL_STORE:env1:test\",\n              {\n                \"event\": {\n                  \"payload\": {\n                    \"count\": 0,\n                  },\n                  \"type\": \"__EXISTING_STATE_RESPONSE\",\n                },\n                \"eventInfo\": {\n                  \"actor\": {\n                    \"environment\": \"MANAGER\",\n                    \"id\": \"m7405c003lllllllllm\",\n                    \"type\": \"LEADER\",\n                  },\n                },\n              },\n            ],\n          ]\n        `);\n      });\n\n      it('should eventually override initialState when a follower is created with initialState', async () => {\n        // Act - create a leader and a follower\n        const leader = UniversalStore.create({\n          id: 'env1:test',\n          leader: true,\n          initialState: { count: 0 },\n        });\n        const follower = UniversalStore.create({\n          id: 'env2:test',\n          leader: false,\n          initialState: { count: 99 },\n        });\n\n        // Assert - the follower should initially have the initialState\n        expect(follower.getState()).toEqual({ count: 99 });\n\n        // Assert - the follower should eventually get the existing state from the leader\n        await vi.waitFor(\n          () => {\n            expect(follower.getState()).toEqual(leader.getState());\n          },\n          { timeout: 200 }\n        );\n        expect(mockChannel.emit.mock.calls).toMatchInlineSnapshot(`\n          [\n            [\n              \"UNIVERSAL_STORE:env1:test\",\n              {\n                \"event\": {\n                  \"type\": \"__LEADER_CREATED\",\n                },\n                \"eventInfo\": {\n                  \"actor\": {\n                    \"environment\": \"MANAGER\",\n                    \"id\": \"m7405c003lllllllllm\",\n                    \"type\": \"LEADER\",\n                  },\n                },\n              },\n            ],\n            [\n              \"UNIVERSAL_STORE:env2:test\",\n              {\n                \"event\": {\n                  \"type\": \"__FOLLOWER_CREATED\",\n                },\n                \"eventInfo\": {\n                  \"actor\": {\n                    \"environment\": \"MANAGER\",\n                    \"id\": \"m7405c0077777777778\",\n                    \"type\": \"FOLLOWER\",\n                  },\n                },\n              },\n            ],\n            [\n              \"UNIVERSAL_STORE:env2:test\",\n              {\n                \"event\": {\n                  \"type\": \"__EXISTING_STATE_REQUEST\",\n                },\n                \"eventInfo\": {\n                  \"actor\": {\n                    \"environment\": \"MANAGER\",\n                    \"id\": \"m7405c0077777777778\",\n                    \"type\": \"FOLLOWER\",\n                  },\n                },\n              },\n            ],\n            [\n              \"UNIVERSAL_STORE:env1:test\",\n              {\n                \"event\": {\n                  \"type\": \"__FOLLOWER_CREATED\",\n                },\n                \"eventInfo\": {\n                  \"actor\": {\n                    \"environment\": \"MANAGER\",\n                    \"id\": \"m7405c0077777777778\",\n                    \"type\": \"FOLLOWER\",\n                  },\n                  \"forwardingActor\": {\n                    \"environment\": \"MANAGER\",\n                    \"id\": \"m7405c003lllllllllm\",\n                    \"type\": \"LEADER\",\n                  },\n                },\n              },\n            ],\n            [\n              \"UNIVERSAL_STORE:env1:test\",\n              {\n                \"event\": {\n                  \"payload\": {\n                    \"count\": 0,\n                  },\n                  \"type\": \"__EXISTING_STATE_RESPONSE\",\n                },\n                \"eventInfo\": {\n                  \"actor\": {\n                    \"environment\": \"MANAGER\",\n                    \"id\": \"m7405c003lllllllllm\",\n                    \"type\": \"LEADER\",\n                  },\n                },\n              },\n            ],\n          ]\n        `);\n      });\n\n      it('should eventually get existing state when a follower is created in an unprepared context', async () => {\n        // Act - create a leader and a follower without awaiting\n        const leader = UniversalStore.create({\n          id: 'env1:test',\n          leader: true,\n          initialState: { count: 0 },\n        });\n        const follower = UniversalStore.create({\n          id: 'env2:test',\n          leader: false,\n        });\n\n        // Assert - the follower does not request the state because the store is not prepared with a channel\n        await vi.waitFor(\n          () => {\n            expect(mockChannel.emit).toHaveBeenCalledTimes(0);\n          },\n          { timeout: 200 }\n        );\n        expect(leader.status).toBe(UniversalStore.Status.UNPREPARED);\n        expect(follower.status).toBe(UniversalStore.Status.UNPREPARED);\n\n        // Act - prepare the store\n        UniversalStore.__prepare(mockChannel, UniversalStore.Environment.MANAGER);\n\n        // Assert - the follower should eventually get the existing state from the leader\n        await vi.waitFor(\n          () => {\n            expect(follower.getState()).toEqual(leader.getState());\n            expect(follower.status).toBe(UniversalStore.Status.READY);\n          },\n          { timeout: 200 }\n        );\n\n        expect(mockChannel.emit.mock.calls).toMatchInlineSnapshot(`\n          [\n            [\n              \"UNIVERSAL_STORE:env1:test\",\n              {\n                \"event\": {\n                  \"type\": \"__LEADER_CREATED\",\n                },\n                \"eventInfo\": {\n                  \"actor\": {\n                    \"environment\": \"MANAGER\",\n                    \"id\": \"m7405c003lllllllllm\",\n                    \"type\": \"LEADER\",\n                  },\n                },\n              },\n            ],\n            [\n              \"UNIVERSAL_STORE:env2:test\",\n              {\n                \"event\": {\n                  \"type\": \"__FOLLOWER_CREATED\",\n                },\n                \"eventInfo\": {\n                  \"actor\": {\n                    \"environment\": \"MANAGER\",\n                    \"id\": \"m7405c0077777777778\",\n                    \"type\": \"FOLLOWER\",\n                  },\n                },\n              },\n            ],\n            [\n              \"UNIVERSAL_STORE:env2:test\",\n              {\n                \"event\": {\n                  \"type\": \"__EXISTING_STATE_REQUEST\",\n                },\n                \"eventInfo\": {\n                  \"actor\": {\n                    \"environment\": \"MANAGER\",\n                    \"id\": \"m7405c0077777777778\",\n                    \"type\": \"FOLLOWER\",\n                  },\n                },\n              },\n            ],\n            [\n              \"UNIVERSAL_STORE:env1:test\",\n              {\n                \"event\": {\n                  \"type\": \"__FOLLOWER_CREATED\",\n                },\n                \"eventInfo\": {\n                  \"actor\": {\n                    \"environment\": \"MANAGER\",\n                    \"id\": \"m7405c0077777777778\",\n                    \"type\": \"FOLLOWER\",\n                  },\n                  \"forwardingActor\": {\n                    \"environment\": \"MANAGER\",\n                    \"id\": \"m7405c003lllllllllm\",\n                    \"type\": \"LEADER\",\n                  },\n                },\n              },\n            ],\n            [\n              \"UNIVERSAL_STORE:env1:test\",\n              {\n                \"event\": {\n                  \"payload\": {\n                    \"count\": 0,\n                  },\n                  \"type\": \"__EXISTING_STATE_RESPONSE\",\n                },\n                \"eventInfo\": {\n                  \"actor\": {\n                    \"environment\": \"MANAGER\",\n                    \"id\": \"m7405c003lllllllllm\",\n                    \"type\": \"LEADER\",\n                  },\n                },\n              },\n            ],\n          ]\n        `);\n      });\n\n      it('should throw when creating a follower without an existing leader', async () => {\n        // Act - create a follower without a leader\n        const follower = UniversalStore.create({\n          id: 'env1:test',\n          leader: false,\n        });\n\n        // Assert - the follower should announce creation and request the existing state\n        await vi.waitFor(\n          () => {\n            expect(mockChannel.emit).toHaveBeenCalledTimes(2);\n          },\n          { timeout: 200 }\n        );\n\n        expect(mockChannel.emit.mock.calls).toMatchInlineSnapshot(`\n          [\n            [\n              \"UNIVERSAL_STORE:env1:test\",\n              {\n                \"event\": {\n                  \"type\": \"__FOLLOWER_CREATED\",\n                },\n                \"eventInfo\": {\n                  \"actor\": {\n                    \"environment\": \"MANAGER\",\n                    \"id\": \"m7405c003lllllllllm\",\n                    \"type\": \"FOLLOWER\",\n                  },\n                },\n              },\n            ],\n            [\n              \"UNIVERSAL_STORE:env1:test\",\n              {\n                \"event\": {\n                  \"type\": \"__EXISTING_STATE_REQUEST\",\n                },\n                \"eventInfo\": {\n                  \"actor\": {\n                    \"environment\": \"MANAGER\",\n                    \"id\": \"m7405c003lllllllllm\",\n                    \"type\": \"FOLLOWER\",\n                  },\n                },\n              },\n            ],\n          ]\n        `);\n\n        // Assert - eventually the follower.untilReady() promise should throw an error when the timeout is reached\n        vi.advanceTimersToNextTimer();\n        await expect(follower.untilReady()).rejects.toThrowErrorMatchingInlineSnapshot(\n          `[TypeError: No existing state found for follower with id: 'env1:test'. Make sure a leader with the same id exists before creating a follower.]`\n        );\n        expect(follower.status).toBe(UniversalStore.Status.ERROR);\n      });\n\n      it('should emit a FOLLOWER_CREATED event when a follower is created', async () => {\n        // Arrange - create a leader\n        const leader = UniversalStore.create({\n          id: 'env1:test',\n          leader: true,\n          initialState: { count: 0 },\n        });\n\n        // Act - craete a leader\n        const follower = UniversalStore.create({\n          id: 'env2:test',\n          leader: false,\n          initialState: { count: 99 },\n        });\n\n        // Assert - the follower and leader should eventually emit a FOLLOWER_CREATED event\n        await vi.waitFor(\n          () => {\n            expect(mockChannel.emit).toHaveBeenCalledWith('UNIVERSAL_STORE:env2:test', {\n              event: {\n                type: UniversalStore.InternalEventType.FOLLOWER_CREATED,\n              },\n              eventInfo: {\n                actor: follower.actor,\n              },\n            });\n            expect(mockChannel.emit).toHaveBeenCalledWith('UNIVERSAL_STORE:env1:test', {\n              event: {\n                type: UniversalStore.InternalEventType.FOLLOWER_CREATED,\n              },\n              eventInfo: {\n                actor: follower.actor,\n                forwardingActor: leader.actor,\n              },\n            });\n          },\n          { timeout: 200 }\n        );\n      });\n    });\n  });\n\n  describe('State', () => {\n    it('should get the current state', () => {\n      // Act - create a store with initial state\n      const store = UniversalStore.create({\n        id: 'env1:test',\n        leader: true,\n        initialState: { count: 0 },\n      });\n\n      // Assert - the state should be the initial state\n      expect(store.getState()).toEqual({ count: 0 });\n    });\n\n    it('should update the state', () => {\n      // Arrange - create a store and add a state change listener\n      const store = UniversalStore.create({\n        id: 'env1:test',\n        leader: true,\n        initialState: { count: 0 },\n      });\n\n      // Act - replace the state\n      store.setState({ count: 1 });\n\n      // Assert - the state should be updated\n      expect(store.getState()).toEqual({ count: 1 });\n\n      // Act - update the state with an updater function\n      store.setState((s) => ({ count: s.count + 1 }));\n\n      // Assert - the state should be updated\n      expect(store.getState()).toEqual({ count: 2 });\n    });\n\n    it('should emit the state change to the channel', () => {\n      // Arrange - create a store\n      const store = UniversalStore.create({\n        id: 'env1:test',\n        leader: true,\n        initialState: { count: 0 },\n      });\n\n      // Act - replace the state\n      store.setState({ count: 1 });\n\n      // Assert - the state change should be emitted on the channel\n      expect(mockChannel.emit).toHaveBeenCalledWith('UNIVERSAL_STORE:env1:test', {\n        event: {\n          type: UniversalStore.InternalEventType.SET_STATE,\n          payload: {\n            state: { count: 1 },\n            previousState: { count: 0 },\n          },\n        },\n        eventInfo: {\n          actor: store.actor,\n        },\n      });\n    });\n\n    it('should emit the state change to the listeners', () => {\n      // Arrange - create a store and add a state change listener and a full listener\n      const store = UniversalStore.create({\n        id: 'env1:test',\n        leader: true,\n        initialState: { count: 0 },\n      });\n      const stateChangeListener = vi.fn();\n      const fullListener = vi.fn();\n      store.onStateChange(stateChangeListener);\n      store.subscribe(UniversalStore.InternalEventType.SET_STATE, fullListener);\n\n      // Act - replace the state\n      store.setState({ count: 1 });\n\n      // Assert - the state should be updated and the listener should be called\n      expect(stateChangeListener).toHaveBeenCalledExactlyOnceWith(\n        { count: 1 },\n        { count: 0 },\n        { actor: store.actor }\n      );\n      expect(fullListener).toHaveBeenCalledExactlyOnceWith(\n        {\n          type: UniversalStore.InternalEventType.SET_STATE,\n          payload: {\n            state: { count: 1 },\n            previousState: { count: 0 },\n          },\n        },\n        { actor: store.actor }\n      );\n    });\n\n    it('should update own state when channel emits state change', async () => {\n      // Arrange - create a leader and a follower, and wait for them to be in sync\n      const leader = UniversalStore.create({\n        id: 'env1:test',\n        leader: true,\n        initialState: { count: 0 },\n      });\n      const follower = UniversalStore.create({\n        id: 'env2:test',\n        leader: false,\n      });\n      await vi.waitFor(\n        () => {\n          expect(follower.getState()).toEqual({ count: 0 });\n        },\n        { timeout: 200 }\n      );\n\n      // Act - update leader state\n      leader.setState({ count: 1 });\n\n      // Assert - the follower should update its state\n      await vi.waitFor(\n        () => {\n          expect(follower.getState()).toEqual({ count: 1 });\n        },\n        { timeout: 200 }\n      );\n    });\n\n    it('should re-emit the state change to the channel when a leader gets it', async () => {\n      // Arrange - create a leader and a follower, and wait for them to be in sync\n      const leader = UniversalStore.create({\n        id: 'env1:test',\n        leader: true,\n        initialState: { count: 0 },\n      });\n      const follower = UniversalStore.create({\n        id: 'env2:test',\n        leader: false,\n      });\n      await vi.waitFor(\n        () => {\n          expect(follower.getState()).toEqual({ count: 0 });\n        },\n        { timeout: 200 }\n      );\n\n      // Act - update follower state\n      follower.setState({ count: 1 });\n\n      // Assert - the leader should update its state and re-emit the change to any followers in other environments\n      await vi.waitFor(\n        () => {\n          expect(leader.getState()).toEqual({ count: 1 });\n          expect(mockChannel.emit).toHaveBeenCalledWith('UNIVERSAL_STORE:env2:test', {\n            event: {\n              type: UniversalStore.InternalEventType.SET_STATE,\n              payload: {\n                state: { count: 1 },\n                previousState: { count: 0 },\n              },\n            },\n            eventInfo: {\n              actor: {\n                type: UniversalStore.ActorType.FOLLOWER,\n                id: follower.actor.id,\n                environment: UniversalStore.Environment.MANAGER,\n              },\n            },\n          });\n          expect(mockChannel.emit).toHaveBeenCalledWith('UNIVERSAL_STORE:env1:test', {\n            event: {\n              type: UniversalStore.InternalEventType.SET_STATE,\n              payload: {\n                state: { count: 1 },\n                previousState: { count: 0 },\n              },\n            },\n            eventInfo: {\n              actor: {\n                type: UniversalStore.ActorType.FOLLOWER,\n                id: follower.actor.id,\n                environment: UniversalStore.Environment.MANAGER,\n              },\n              forwardingActor: {\n                type: UniversalStore.ActorType.LEADER,\n                id: leader.actor.id,\n                environment: UniversalStore.Environment.MANAGER,\n              },\n            },\n          });\n        },\n        { timeout: 200 }\n      );\n    });\n\n    it('should throw when trying to set state before the store is ready', async () => {\n      // Arrange - create a leader and a follower\n      const leader = UniversalStore.create({\n        id: 'env1:test',\n        leader: true,\n        initialState: { count: 0 },\n      });\n      const follower = UniversalStore.create({\n        id: 'env2:test',\n        leader: false,\n      });\n      expect(follower.status).toBe(UniversalStore.Status.SYNCING);\n\n      // Act & Assert - set state on the follower before it is ready and expect it to throw\n      expect(() => follower.setState({ count: 1 })).toThrowErrorMatchingInlineSnapshot(`\n        [TypeError: Cannot set state before store is ready. You can get the current status with store.status,\n        or await store.readyPromise to wait for the store to be ready before sending events.\n        {\n          \"newState\": {\n            \"count\": 1\n          },\n          \"id\": \"env2:test\",\n          \"actor\": {\n            \"id\": \"m7405c0077777777778\",\n            \"type\": \"FOLLOWER\",\n            \"environment\": \"MANAGER\"\n          },\n          \"environment\": \"MANAGER\"\n        }]\n      `);\n    });\n  });\n\n  describe('Events', () => {\n    it('should call listeners when events are sent via the store', () => {\n      // Arrange - create a store and add a listener\n      const store = UniversalStore.create({\n        id: 'env1:test',\n        leader: true,\n        initialState: { count: 0 },\n      });\n      const specificListener = vi.fn();\n      const allListener = vi.fn();\n      store.subscribe('CUSTOM_EVENT_TYPE', specificListener);\n      store.subscribe(allListener);\n\n      // Act - send the event\n      store.send({ type: 'CUSTOM_EVENT_TYPE', payload: { foo: 'bar' } });\n\n      // Assert - the listener should be called\n      const expectedEvent = {\n        type: 'CUSTOM_EVENT_TYPE',\n        payload: { foo: 'bar' },\n      };\n      const expectedEventInfo = {\n        actor: store.actor,\n      };\n      expect(specificListener).toHaveBeenCalledExactlyOnceWith(expectedEvent, expectedEventInfo);\n      expect(allListener).toHaveBeenCalledExactlyOnceWith(expectedEvent, expectedEventInfo);\n    });\n\n    it('should call listeners when events are sent via the channel', async () => {\n      // Arrange - create a store and add a listener\n      const store = UniversalStore.create({\n        id: 'env1:test',\n        leader: true,\n        initialState: { count: 0 },\n      });\n      const specificListener = vi.fn();\n      const allListener = vi.fn();\n      store.subscribe('CUSTOM_EVENT_TYPE', specificListener);\n      store.subscribe(allListener);\n      await store.untilReady();\n      const eventToEmit = {\n        type: 'CUSTOM_EVENT_TYPE',\n        payload: { foo: 'bar' },\n      };\n      const emittingActor = {\n        id: 'actor-that-emits-event',\n        type: UniversalStore.ActorType.FOLLOWER,\n        environment: UniversalStore.Environment.MANAGER,\n      };\n      // Act - emit the event on the channel\n      mockChannel.emit('UNIVERSAL_STORE:env2:test', {\n        event: eventToEmit,\n        eventInfo: {\n          actor: emittingActor,\n        },\n      });\n\n      // Assert - the listener should be called\n      await vi.waitFor(\n        () => {\n          expect(specificListener).toHaveBeenCalledWith(eventToEmit, { actor: emittingActor });\n          expect(allListener).toHaveBeenCalledWith(eventToEmit, { actor: emittingActor });\n        },\n        { timeout: 200 }\n      );\n    });\n\n    it('should forward events on the channel when a leader receives an event', async () => {\n      // Arrange - create a leader\n      const store = UniversalStore.create({\n        id: 'env1:test',\n        leader: true,\n        initialState: { count: 0 },\n      });\n      await store.untilReady();\n      const eventToEmit = {\n        type: 'CUSTOM_EVENT_TYPE',\n        payload: { foo: 'bar' },\n      };\n      const emittingActor = {\n        id: 'actor-that-emitted-event',\n        type: UniversalStore.ActorType.FOLLOWER,\n        environment: UniversalStore.Environment.MANAGER,\n      };\n\n      // Act - emit the event on the channel as a follower\n      mockChannel.emit('UNIVERSAL_STORE:env2:test', {\n        event: eventToEmit,\n        eventInfo: {\n          actor: emittingActor,\n        },\n      });\n\n      // Assert - the event should be forwarded on the channel by the leader\n      await vi.waitFor(\n        () => {\n          expect(mockChannel.emit).toHaveBeenCalledWith('UNIVERSAL_STORE:env1:test', {\n            event: eventToEmit,\n            eventInfo: {\n              actor: emittingActor,\n              forwardingActor: store.actor,\n            },\n          });\n        },\n        { timeout: 200 }\n      );\n    });\n\n    it('should emit events on the channel', () => {\n      // Arrange - create a store\n      const store = UniversalStore.create({\n        id: 'env1:test',\n        leader: true,\n        initialState: { count: 0 },\n      });\n\n      // Act - send the event\n      store.send({ type: 'CUSTOM_EVENT_TYPE', payload: { foo: 'bar' } });\n\n      // Assert - the event should be emitted on the channel\n      expect(mockChannel.emit).toHaveBeenCalledWith('UNIVERSAL_STORE:env1:test', {\n        event: {\n          type: 'CUSTOM_EVENT_TYPE',\n          payload: { foo: 'bar' },\n        },\n        eventInfo: {\n          actor: store.actor,\n        },\n      });\n    });\n\n    it('should unsubscribe listeners from events', () => {\n      // Arrange - create a store, add a listener, send an event, and then remove the listener\n      const store = UniversalStore.create({\n        id: 'env1:test',\n        leader: true,\n        initialState: { count: 0 },\n      });\n      const listener = vi.fn();\n      const unsubscribe = store.subscribe(listener);\n      store.send({ type: 'CUSTOM_EVENT_TYPE', payload: { foo: 'bar' } });\n      expect(listener).toHaveBeenCalledOnce();\n      listener.mockClear();\n\n      // Act - unsubscribe the listener and send the event again\n      unsubscribe();\n      store.send({ type: 'CUSTOM_EVENT_TYPE', payload: { baz: 'meh' } });\n\n      // Assert - the listener should not be called\n      expect(listener).not.toBeCalled();\n    });\n\n    it('should throw when trying to send an event before the store is ready', async () => {\n      // Arrange - create a leader and a follower\n      const leader = UniversalStore.create({\n        id: 'env1:test',\n        leader: true,\n        initialState: { count: 0 },\n      });\n      const follower = UniversalStore.create({\n        id: 'env2:test',\n        leader: false,\n      });\n      expect(follower.status).toBe(UniversalStore.Status.SYNCING);\n\n      // Act & Assert - send an event with the follower before it is ready and expect it to throw\n      expect(() => follower.send({ type: 'TOO_EARLY' })).toThrowErrorMatchingInlineSnapshot(`\n        [TypeError: Cannot send event before store is ready. You can get the current status with store.status,\n        or await store.readyPromise to wait for the store to be ready before sending events.\n        {\n          \"event\": {\n            \"type\": \"TOO_EARLY\"\n          },\n          \"id\": \"env2:test\",\n          \"actor\": {\n            \"id\": \"m7405c0077777777778\",\n            \"type\": \"FOLLOWER\",\n            \"environment\": \"MANAGER\"\n          },\n          \"environment\": \"MANAGER\"\n        }]\n      `);\n    });\n  });\n\n  it('logs debug logs when debug is set to true', () => {\n    // Arrange - spy on console.log\n    vi.spyOn(console, 'debug').mockImplementation(() => {});\n\n    // Act - create a store with debug enabled\n    UniversalStore.create({\n      id: 'env1:test',\n      leader: true,\n      initialState: { count: 0 },\n      debug: true,\n    });\n\n    // Assert - the debug log should be logged\n    expect(console.debug).toHaveBeenCalledTimes(4);\n  });\n\n  describe('MockUnversalStore', () => {\n    it('should create an isolated instance', async () => {\n      // Arrange - create real store\n      const realStore = UniversalStore.create({\n        id: 'env1:test',\n        leader: true,\n        initialState: { count: 0 },\n      });\n\n      // Act - create a mock store with constructor and one with create()\n      const constructorMockStore = new MockUniversalStore({\n        id: 'env1:test',\n        initialState: { count: 0 },\n      });\n      const createMockStore = MockUniversalStore.create({\n        id: 'env1:test',\n        initialState: { count: 0 },\n      });\n\n      // Assert - the mock stores should be created as leaders without errors\n      expect(constructorMockStore.actor.type).toBe(UniversalStore.ActorType.LEADER);\n      expect(createMockStore.actor.type).toBe(UniversalStore.ActorType.LEADER);\n      await expect(\n        Promise.all([constructorMockStore.untilReady(), createMockStore.untilReady()])\n      ).resolves.toBeDefined();\n\n      // Act - set state on the real store\n      realStore.setState({ count: 1 });\n\n      // Assert - the mock stores should still have their initial state\n      vi.runAllTimers();\n      expect(constructorMockStore.getState()).toEqual({ count: 0 });\n      expect(createMockStore.getState()).toEqual({ count: 0 });\n\n      // Act - set state on one of the mock stores\n      constructorMockStore.setState({ count: 2 });\n\n      // Assert - the other mock store should still have its initial state\n      vi.runAllTimers();\n      expect(createMockStore.getState()).toEqual({ count: 0 });\n    });\n\n    it('should wrap all public methods with mocks', async () => {\n      // Act - create a mock store\n      const store = new MockUniversalStore(\n        {\n          id: 'env1:test',\n          initialState: { count: 0 },\n        },\n        vi\n      );\n\n      // Assert - public methods are mocks\n      expect(vi.isMockFunction(store.getState)).toBeTruthy();\n      expect(vi.isMockFunction(store.setState)).toBeTruthy();\n      expect(vi.isMockFunction(store.subscribe)).toBeTruthy();\n      expect(vi.isMockFunction(store.onStateChange)).toBeTruthy();\n      expect(vi.isMockFunction(store.send)).toBeTruthy();\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/shared/universal-store/index.ts",
    "content": "import { dedent } from 'ts-dedent';\n\nimport { instances } from './instances.ts';\nimport type {\n  Actor,\n  ChannelEvent,\n  ChannelLike,\n  EnvironmentOverrides,\n  EnvironmentType,\n  Event,\n  EventInfo,\n  ExistingStateResponseEvent,\n  Listener,\n  SetStateEvent,\n  StateUpdater,\n  StatusType,\n  StoreOptions,\n} from './types.ts';\n\nconst CHANNEL_EVENT_PREFIX = 'UNIVERSAL_STORE:' as const;\n\nconst ProgressState = {\n  PENDING: 'PENDING',\n  RESOLVED: 'RESOLVED',\n  REJECTED: 'REJECTED',\n} as const;\n\n/**\n * A universal store implementation that synchronizes state across different environments using a\n * channel-based communication.\n *\n * The store follows a leader-follower pattern where:\n *\n * - Leader: The main store instance that owns and manages the state\n * - Follower: Store instances that mirror the leader's state\n *\n * Features:\n *\n * - State synchronization across environments\n * - Event-based communication\n * - Type-safe state and custom events\n * - Subscription system for state changes and custom events\n *\n * @remarks\n * - The store must be created using the static `create()` method, not the constructor\n * - Follower stores will automatically sync with their leader's state. If they have initial state, it\n *   will be replaced immediately when it has synced with the leader.\n *\n * @example\n *\n * ```typescript\n * interface MyState {\n *   count: number;\n * }\n * interface MyCustomEvent {\n *   type: 'INCREMENT';\n *   payload: number;\n * }\n *\n * // Create a leader store\n * const leaderStore = UniversalStore.create<MyState, MyCustomEvent>({\n *   id: 'my-store',\n *   leader: true,\n *   initialState: { count: 0 },\n * });\n *\n * // Create a follower store\n * const followerStore = UniversalStore.create<MyState, MyCustomEvent>({\n *   id: 'my-store',\n *   leader: false,\n * });\n * ```\n *\n * @template State - The type of state managed by the store\n * @template CustomEvent - Custom events that can be sent through the store. Must have a `type`\n *   string and optional `payload`\n * @throws {Error} If constructed directly instead of using `create()`\n * @throws {Error} If created without setting a channel first\n * @throws {Error} If a follower is created with initial state\n * @throws {Error} If a follower cannot find its leader within 1 second\n */\nexport class UniversalStore<\n  State,\n  CustomEvent extends { type: string; payload?: any } = { type: string; payload?: any },\n> {\n  /**\n   * Defines the possible actor types in the store system\n   *\n   * @readonly\n   */\n  public static readonly ActorType = {\n    LEADER: 'LEADER',\n    FOLLOWER: 'FOLLOWER',\n  } as const;\n\n  /**\n   * Defines the possible environments the store can run in\n   *\n   * @readonly\n   */\n  public static readonly Environment = {\n    SERVER: 'SERVER',\n    MANAGER: 'MANAGER',\n    PREVIEW: 'PREVIEW',\n    UNKNOWN: 'UNKNOWN',\n    MOCK: 'MOCK',\n  } as const;\n\n  /**\n   * Internal event types used for store synchronization\n   *\n   * @readonly\n   */\n  public static readonly InternalEventType = {\n    EXISTING_STATE_REQUEST: '__EXISTING_STATE_REQUEST',\n    EXISTING_STATE_RESPONSE: '__EXISTING_STATE_RESPONSE',\n    SET_STATE: '__SET_STATE',\n    LEADER_CREATED: '__LEADER_CREATED',\n    FOLLOWER_CREATED: '__FOLLOWER_CREATED',\n  } as const;\n\n  public static readonly Status = {\n    UNPREPARED: 'UNPREPARED',\n    SYNCING: 'SYNCING',\n    READY: 'READY',\n    ERROR: 'ERROR',\n  } as const;\n\n  // This is used to check if constructor was called from the static factory create()\n  protected static isInternalConstructing = false;\n\n  static {\n    UniversalStore.setupPreparationPromise();\n  }\n\n  /**\n   * The preparation construct is used to keep track of all store's preparation state the promise is\n   * resolved when the store is prepared with the static __prepare() method which will also change\n   * the state from PENDING to RESOLVED\n   */\n  private static preparation: {\n    channel?: ChannelLike;\n    environment?: EnvironmentType;\n    resolve: (args: Awaited<typeof UniversalStore.preparation.promise>) => void;\n    reject: (error: Error) => void;\n    promise: Promise<{ channel: ChannelLike; environment: EnvironmentType }>;\n  };\n\n  private static setupPreparationPromise() {\n    let resolveRef: typeof UniversalStore.preparation.resolve;\n    let rejectRef: typeof UniversalStore.preparation.reject;\n\n    const promise = new Promise<Awaited<typeof UniversalStore.preparation.promise>>(\n      (resolve, reject) => {\n        resolveRef = (args) => {\n          resolve(args);\n        };\n        rejectRef = (...args) => {\n          reject(args);\n        };\n      }\n    );\n\n    UniversalStore.preparation = {\n      resolve: resolveRef!,\n      reject: rejectRef!,\n      promise,\n    };\n  }\n\n  /** Enable debug logs for this store */\n  public debugging = false;\n\n  /** The actor object representing the store instance with a unique ID and a type */\n  public get actor(): Actor {\n    return Object.freeze({\n      id: this.actorId,\n      type: this.actorType,\n      environment: this.environment ?? UniversalStore.Environment.UNKNOWN,\n    });\n  }\n\n  /**\n   * The current state of the store, that signals both if the store is prepared by Storybook and\n   * also - in the case of a follower - if the state has been synced with the leader's state.\n   */\n  public get status(): StatusType {\n    if (!this.channel || !this.environment) {\n      return UniversalStore.Status.UNPREPARED;\n    }\n\n    switch (this.syncing?.state) {\n      case ProgressState.PENDING:\n      case undefined:\n        return UniversalStore.Status.SYNCING;\n\n      case ProgressState.REJECTED:\n        return UniversalStore.Status.ERROR;\n      case ProgressState.RESOLVED:\n      default:\n        return UniversalStore.Status.READY;\n    }\n  }\n\n  /**\n   * A promise that resolves when the store is fully ready. A leader will be ready when the store\n   * has been prepared by Storybook, which is almost instantly.\n   *\n   * A follower will be ready when the state has been synced with the leader's state, within a few\n   * hundred milliseconds.\n   */\n  public untilReady() {\n    return Promise.all([UniversalStore.preparation.promise, this.syncing?.promise]);\n  }\n\n  /**\n   * The syncing construct is used to keep track of if the instance's state has been synced with the\n   * other instances. A leader will immediately have the promise resolved. A follower will initially\n   * be in a PENDING state, and resolve the the leader has sent the existing state, or reject if no\n   * leader has responded before the timeout.\n   */\n  private syncing?: {\n    state: (typeof ProgressState)[keyof typeof ProgressState];\n    promise?: Promise<void>;\n    resolve?: () => void;\n    reject?: (error: Error) => void;\n  };\n\n  private channelEventName: string;\n\n  private state: State;\n\n  // Unless overridden with the environmentOverrides constructor parameter, this will be the same as the static channel\n  private channel?: ChannelLike;\n\n  // Unless overridden with the environmentOverrides constructor parameter, this will be the same as the static environment\n  private environment?: EnvironmentType;\n\n  // TODO: narrow type of listeners based on event type\n  private listeners: Map<string, Set<Listener<any>>> = new Map([['*', new Set()]]);\n\n  private id: string;\n\n  private actorId: Actor['id'];\n\n  private actorType: Actor['type'];\n\n  protected constructor(options: StoreOptions<State>, environmentOverrides?: EnvironmentOverrides) {\n    this.debugging = options.debug ?? false;\n    // This constructor is a simulated private constructor\n    // it can only be called from within the static factory method create()\n    // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_propertiessimulating_private_constructors\n    if (!UniversalStore.isInternalConstructing) {\n      throw new TypeError(\n        'UniversalStore is not constructable - use UniversalStore.create() instead'\n      );\n    }\n    UniversalStore.isInternalConstructing = false;\n\n    this.id = options.id;\n    this.actorId = Date.now().toString(36) + Math.random().toString(36).substring(2);\n    this.actorType = options.leader\n      ? UniversalStore.ActorType.LEADER\n      : UniversalStore.ActorType.FOLLOWER;\n    this.state = options.initialState as State;\n    this.channelEventName = `${CHANNEL_EVENT_PREFIX}${this.id}`;\n\n    this.debug('constructor', {\n      options,\n      environmentOverrides,\n      channelEventName: this.channelEventName,\n    });\n\n    if (this.actor.type === UniversalStore.ActorType.LEADER) {\n      // If this is a leader, resolve the syncing promise immediately\n      // because the state doesn't need to be synced\n      this.syncing = {\n        state: ProgressState.RESOLVED,\n        promise: Promise.resolve(),\n      };\n    } else {\n      // Set up the syncing promise for followers, that will be resolved when the state\n      // is synced with the leader\n      let syncingResolve: () => void;\n      let syncingReject: (error: Error) => void;\n      const syncingPromise = new Promise<void>((resolve, reject) => {\n        syncingResolve = () => {\n          if (this.syncing!.state !== ProgressState.PENDING) {\n            return;\n          }\n          this.syncing!.state = ProgressState.RESOLVED;\n          resolve();\n        };\n        syncingReject = (reason) => {\n          if (this.syncing!.state !== ProgressState.PENDING) {\n            return;\n          }\n          this.syncing!.state = ProgressState.REJECTED;\n          reject(reason);\n        };\n      });\n      this.syncing = {\n        state: ProgressState.PENDING,\n        promise: syncingPromise,\n        resolve: syncingResolve!,\n        reject: syncingReject!,\n      };\n    }\n\n    // Bind all methods\n    this.getState = this.getState.bind(this);\n    this.setState = this.setState.bind(this);\n    this.subscribe = this.subscribe.bind(this);\n    this.onStateChange = this.onStateChange.bind(this);\n    this.send = this.send.bind(this);\n    this.emitToChannel = this.emitToChannel.bind(this);\n    this.prepareThis = this.prepareThis.bind(this);\n    this.emitToListeners = this.emitToListeners.bind(this);\n    this.handleChannelEvents = this.handleChannelEvents.bind(this);\n    this.debug = this.debug.bind(this);\n\n    this.channel = environmentOverrides?.channel ?? UniversalStore.preparation.channel;\n    this.environment = environmentOverrides?.environment ?? UniversalStore.preparation.environment;\n\n    if (this.channel && this.environment) {\n      UniversalStore.preparation.resolve({ channel: this.channel, environment: this.environment });\n      this.prepareThis({ channel: this.channel, environment: this.environment });\n    } else {\n      UniversalStore.preparation.promise.then(this.prepareThis);\n    }\n  }\n\n  /** Creates a new instance of UniversalStore */\n  static create<\n    State = any,\n    CustomEvent extends { type: string; payload?: any } = { type: string; payload?: any },\n  >(options: StoreOptions<State>): UniversalStore<State, CustomEvent> {\n    if (!options || typeof options?.id !== 'string') {\n      throw new TypeError('id is required and must be a string, when creating a UniversalStore');\n    }\n    if (options.debug) {\n      console.debug(\n        dedent`[UniversalStore]\n        create`,\n        { options }\n      );\n    }\n\n    const existing = instances.get(options.id);\n    if (existing) {\n      console.warn(dedent`UniversalStore with id \"${options.id}\" already exists in this environment, re-using existing.\n        You should reuse the existing instance instead of trying to create a new one.`);\n      return existing;\n    }\n\n    UniversalStore.isInternalConstructing = true;\n    const store = new UniversalStore<State, CustomEvent>(options);\n    instances.set(options.id, store);\n    return store;\n  }\n\n  /**\n   * Used by Storybook to set the channel for all instances of UniversalStore in the given\n   * environment.\n   *\n   * @internal\n   */\n  static __prepare(channel: ChannelLike, environment: EnvironmentType) {\n    UniversalStore.preparation.channel = channel;\n    UniversalStore.preparation.environment = environment;\n    UniversalStore.preparation.resolve({ channel, environment });\n  }\n\n  /** Gets the current state */\n  public getState = (): State => {\n    this.debug('getState', { state: this.state });\n    return this.state;\n  };\n\n  /**\n   * Updates the store's state\n   *\n   * Either a new state or a state updater function can be passed to the method.\n   */\n  public setState(updater: State | StateUpdater<State>) {\n    const previousState = this.state;\n    const newState =\n      typeof updater === 'function' ? (updater as StateUpdater<State>)(previousState) : updater;\n\n    this.debug('setState', { newState, previousState, updater });\n\n    if (this.status !== UniversalStore.Status.READY) {\n      throw new TypeError(\n        dedent`Cannot set state before store is ready. You can get the current status with store.status,\n        or await store.readyPromise to wait for the store to be ready before sending events.\n        ${JSON.stringify(\n          {\n            newState,\n            id: this.id,\n            actor: this.actor,\n            environment: this.environment,\n          },\n          null,\n          2\n        )}`\n      );\n    }\n\n    this.state = newState;\n    const event = {\n      type: UniversalStore.InternalEventType.SET_STATE,\n      payload: {\n        state: newState,\n        previousState,\n      },\n    };\n    this.emitToChannel(event, { actor: this.actor });\n    this.emitToListeners(event, { actor: this.actor });\n  }\n\n  /**\n   * Subscribes to store events\n   *\n   * @returns A function to unsubscribe\n   */\n\n  public subscribe: {\n    (listener: Listener<Event<State, CustomEvent>>): () => void;\n    <EventType extends Event<State, CustomEvent>['type']>(\n      eventType: EventType,\n      listener: Listener<Extract<Event<State, CustomEvent>, { type: EventType }>>\n    ): () => void;\n  } = <EventType extends Event<State, CustomEvent>['type']>(\n    eventTypeOrListener: Listener<Event<State, CustomEvent>> | EventType,\n    maybeListener?: Listener<Extract<Event<State, CustomEvent>, { type: EventType }>>\n  ) => {\n    const subscribesToAllEvents = typeof eventTypeOrListener === 'function';\n\n    const eventType = subscribesToAllEvents ? '*' : eventTypeOrListener;\n    const listener = subscribesToAllEvents ? eventTypeOrListener : maybeListener;\n\n    this.debug('subscribe', { eventType, listener });\n\n    if (!listener) {\n      throw new TypeError(\n        `Missing first subscribe argument, or second if first is the event type, when subscribing to a UniversalStore with id '${this.id}'`\n      );\n    }\n\n    if (!this.listeners.has(eventType)) {\n      this.listeners.set(eventType, new Set());\n    }\n    this.listeners.get(eventType)!.add(listener);\n\n    return () => {\n      this.debug('unsubscribe', { eventType, listener });\n      if (!this.listeners.has(eventType)) {\n        return;\n      }\n      this.listeners.get(eventType)!.delete(listener);\n      if (this.listeners.get(eventType)?.size === 0) {\n        this.listeners.delete(eventType);\n      }\n    };\n  };\n\n  /**\n   * Subscribes to state changes\n   *\n   * @returns Unsubscribe function\n   */\n  public onStateChange(\n    listener: (state: State, previousState: State, eventInfo: EventInfo) => void\n  ) {\n    this.debug('onStateChange', { listener });\n    return this.subscribe(\n      UniversalStore.InternalEventType.SET_STATE as any,\n      ({ payload }, eventInfo) => {\n        listener(payload.state, payload.previousState, eventInfo);\n      }\n    );\n  }\n\n  /** Sends a custom event to the other stores */\n  public send = (event: CustomEvent) => {\n    this.debug('send', { event });\n    if (this.status !== UniversalStore.Status.READY) {\n      throw new TypeError(\n        dedent`Cannot send event before store is ready. You can get the current status with store.status,\n        or await store.readyPromise to wait for the store to be ready before sending events.\n        ${JSON.stringify(\n          {\n            event,\n            id: this.id,\n            actor: this.actor,\n            environment: this.environment,\n          },\n          null,\n          2\n        )}`\n      );\n    }\n    this.emitToListeners(event, { actor: this.actor });\n    this.emitToChannel(event, { actor: this.actor });\n  };\n\n  private emitToChannel(event: any, eventInfo: EventInfo) {\n    this.debug('emitToChannel', { event, eventInfo, channel: !!this.channel });\n    this.channel?.emit(this.channelEventName, {\n      event,\n      eventInfo,\n    });\n  }\n\n  private prepareThis({\n    channel,\n    environment,\n  }: {\n    channel: ChannelLike;\n    environment: EnvironmentType;\n  }) {\n    this.channel = channel;\n    this.environment = environment;\n\n    this.debug('prepared', { channel: !!channel, environment });\n    this.channel.on(this.channelEventName, this.handleChannelEvents);\n\n    if (this.actor.type === UniversalStore.ActorType.LEADER) {\n      this.emitToChannel(\n        { type: UniversalStore.InternalEventType.LEADER_CREATED },\n        { actor: this.actor }\n      );\n    } else {\n      this.emitToChannel(\n        { type: UniversalStore.InternalEventType.FOLLOWER_CREATED },\n        { actor: this.actor }\n      );\n      // 1. Emit a request for the existing state\n      this.emitToChannel(\n        { type: UniversalStore.InternalEventType.EXISTING_STATE_REQUEST },\n        { actor: this.actor }\n      );\n      // 2. Wait 1 sec for a response, then reject the syncing promise if not already resolved\n      setTimeout(() => {\n        // if the state is already resolved by a response before this timeout,\n        // rejecting it doesn't do anything, it will be ignored\n        this.syncing!.reject!(\n          new TypeError(\n            `No existing state found for follower with id: '${this.id}'. Make sure a leader with the same id exists before creating a follower.`\n          )\n        );\n      }, 1000);\n    }\n  }\n\n  private emitToListeners(event: any, eventInfo: EventInfo) {\n    const eventTypeListeners = this.listeners.get(event.type);\n    const everythingListeners = this.listeners.get('*');\n    this.debug('emitToListeners', {\n      event,\n      eventInfo,\n      eventTypeListeners,\n      everythingListeners,\n    });\n\n    [...(eventTypeListeners ?? []), ...(everythingListeners ?? [])].forEach(\n      (listener: Listener<CustomEvent>) => listener(event, eventInfo)\n    );\n  }\n\n  private handleChannelEvents(channelEvent: ChannelEvent<State, CustomEvent>) {\n    const { event, eventInfo } = channelEvent;\n\n    if ([eventInfo.actor.id, eventInfo.forwardingActor?.id].includes(this.actor.id)) {\n      // Ignore events from self\n      this.debug('handleChannelEvents: Ignoring event from self', { channelEvent });\n      return;\n    } else if (\n      this.syncing?.state === ProgressState.PENDING &&\n      event.type !== UniversalStore.InternalEventType.EXISTING_STATE_RESPONSE\n    ) {\n      // Ignore events while syncing because it can cause sync issues if the state is updated\n      this.debug('handleChannelEvents: Ignoring event while syncing', { channelEvent });\n      return;\n    }\n    this.debug('handleChannelEvents', { channelEvent });\n\n    if (this.actor.type === UniversalStore.ActorType.LEADER) {\n      let shouldForwardEvent = true;\n      switch (event.type) {\n        case UniversalStore.InternalEventType.EXISTING_STATE_REQUEST:\n          // No need to forward request events\n          shouldForwardEvent = false;\n          // Respond by emitting an event with the existing state\n          const responseEvent: ExistingStateResponseEvent<State> = {\n            type: UniversalStore.InternalEventType.EXISTING_STATE_RESPONSE,\n            payload: this.state,\n          };\n          this.debug('handleChannelEvents: responding to existing state request', {\n            responseEvent,\n          });\n          this.emitToChannel(responseEvent, { actor: this.actor });\n          this.emitToListeners(responseEvent, { actor: this.actor });\n          break;\n        case UniversalStore.InternalEventType.LEADER_CREATED:\n          // if a leader receives a LEADER_CREATED event it should not forward it,\n          // as that would lead to infinite forwarding between the two leaders\n          // all instances will go in an error state in this scenario anyway\n          shouldForwardEvent = false;\n          this.syncing!.state = ProgressState.REJECTED;\n          this.debug('handleChannelEvents: erroring due to second leader being created', {\n            event,\n          });\n          console.error(\n            dedent`Detected multiple UniversalStore leaders created with the same id \"${this.id}\".\n            Only one leader can exists at a time, your stores are now in an invalid state.\n            Leaders detected:\n            this: ${JSON.stringify(this.actor, null, 2)}\n            other: ${JSON.stringify(eventInfo.actor, null, 2)}`\n          );\n\n          break;\n      }\n      if (shouldForwardEvent) {\n        // Forward the event to followers in other environments\n        this.debug('handleChannelEvents: forwarding event', { channelEvent });\n        this.emitToChannel(event, { actor: eventInfo.actor, forwardingActor: this.actor });\n      }\n    }\n    if (this.actor.type === UniversalStore.ActorType.FOLLOWER) {\n      switch (event.type) {\n        case UniversalStore.InternalEventType.EXISTING_STATE_RESPONSE:\n          this.debug(\"handleChannelEvents: Setting state from leader's existing state response\", {\n            event,\n          });\n          if (this.syncing?.state !== ProgressState.PENDING) {\n            // ignore the response if this follower has already synced\n            break;\n          }\n          this.syncing!.resolve?.();\n          // notify internal listeners that the state has changed because of the sync\n          const setStateEvent: SetStateEvent<State> = {\n            type: UniversalStore.InternalEventType.SET_STATE,\n            payload: {\n              state: event.payload,\n              previousState: this.state,\n            },\n          };\n          this.state = event.payload;\n          this.emitToListeners(setStateEvent, eventInfo);\n          break;\n      }\n    }\n\n    switch (event.type) {\n      case UniversalStore.InternalEventType.SET_STATE:\n        this.debug('handleChannelEvents: Setting state', { event });\n        this.state = event.payload.state;\n        break;\n    }\n\n    this.emitToListeners(event, { actor: eventInfo.actor });\n  }\n\n  private debug(message: string, data?: any) {\n    if (this.debugging) {\n      console.debug(\n        dedent`[UniversalStore::${this.id}::${this.environment ?? UniversalStore.Environment.UNKNOWN}]\n        ${message}`,\n        JSON.stringify(\n          {\n            data,\n            actor: this.actor,\n            state: this.state,\n            status: this.status,\n          },\n          null,\n          2\n        )\n      );\n    }\n  }\n\n  /**\n   * Used to reset the static fields of the UniversalStore class when cleaning up tests\n   *\n   * @internal\n   */\n  static __reset() {\n    UniversalStore.preparation.reject(new Error('reset'));\n    UniversalStore.setupPreparationPromise();\n    UniversalStore.isInternalConstructing = false;\n  }\n}\n"
  },
  {
    "path": "code/core/src/shared/universal-store/instances.ts",
    "content": "// this module just contains a map of all the instances of the UniversalStore\n// it's a separate module so it can be mocked in tests\nimport type { UniversalStore } from './index.ts';\n\nexport const instances: Map<string, UniversalStore<any, any>> = new Map();\n"
  },
  {
    "path": "code/core/src/shared/universal-store/mock.ts",
    "content": "import { Channel } from 'storybook/internal/channels';\n\nimport { dedent } from 'ts-dedent';\n\nimport { UniversalStore } from './index.ts';\nimport type { StoreOptions } from './types.ts';\n\n/**\n * A mock universal store that can be used when testing code that relies on a universal store. It\n * functions exactly like a normal universal store, with a few exceptions:\n *\n * - It is fully isolated, meaning that it doesn't interact with any channel, and it is always a\n *   leader.\n *\n * If the second testUtils argument is provided, all the public methods are spied on, so they can be\n * asserted.\n *\n * When a mock store is re-used across tests (eg. in stories), you manually need to reset the state\n * after each test.\n *\n * @example\n *\n * ```ts\n * import * as testUtils from 'storybook/test'; // in stories\n * import { vi as testUtils } from 'vitest'; // ... or in Vitest tests\n *\n * const initialState = { ... };\n * const store = new MockUniversalStore({ initialState }, testUtils);\n *\n * export default {\n *   title: 'My story',\n *   beforeEach: () => {\n *     return () => {\n *       store.setState(initialState);\n *     };\n *   }\n * }\n * ```\n */\nexport class MockUniversalStore<\n  State,\n  CustomEvent extends { type: string; payload?: any } = { type: string; payload?: any },\n> extends UniversalStore<State, CustomEvent> {\n  private testUtils;\n\n  public constructor(options: StoreOptions<State>, testUtils?: any) {\n    UniversalStore.isInternalConstructing = true;\n    super(\n      { ...options, leader: true },\n      { channel: new Channel({}), environment: UniversalStore.Environment.MOCK }\n    );\n    UniversalStore.isInternalConstructing = false;\n\n    if (typeof testUtils?.fn !== 'function') {\n      return;\n    }\n\n    this.testUtils = testUtils;\n    this.getState = testUtils.fn(this.getState);\n    this.setState = testUtils.fn(this.setState);\n    this.subscribe = testUtils.fn(this.subscribe);\n    this.onStateChange = testUtils.fn(this.onStateChange);\n    this.send = testUtils.fn(this.send);\n  }\n\n  /** Create a mock universal store. This is just an alias for the constructor */\n  static create<\n    State = any,\n    CustomEvent extends { type: string; payload?: any } = { type: string; payload?: any },\n  >(options: StoreOptions<State>, testUtils?: any): MockUniversalStore<State, CustomEvent> {\n    return new MockUniversalStore(options, testUtils);\n  }\n\n  public unsubscribeAll() {\n    if (!this.testUtils) {\n      // eslint-disable-next-line local-rules/no-uncategorized-errors\n      throw new Error(\n        dedent`Cannot call unsubscribeAll on a store that does not have testUtils.\n        Please provide testUtils as the second argument when creating the store.`\n      );\n    }\n    // unsubscribe all listeners by calling the unsubscribe methods returned from the calls\n    const callReturnedUnsubscribeFn = (result: any) => {\n      try {\n        result.value();\n      } catch (e) {\n        // ignore\n      }\n    };\n    //@ts-expect-error - TS doesn't know that it's a mock\n    this.subscribe.mock?.results.forEach(callReturnedUnsubscribeFn);\n    //@ts-expect-error - TS doesn't know that it's a mock\n    this.onStateChange.mock?.results.forEach(callReturnedUnsubscribeFn);\n  }\n}\n"
  },
  {
    "path": "code/core/src/shared/universal-store/types.ts",
    "content": "import type { Channel } from 'storybook/internal/channels';\n\nimport type { UniversalStore } from './index.ts';\n\nexport type EnvironmentType =\n  (typeof UniversalStore.Environment)[keyof typeof UniversalStore.Environment];\n\nexport type StatusType = (typeof UniversalStore.Status)[keyof typeof UniversalStore.Status];\n\nexport type StateUpdater<TState> = (prevState: TState) => TState;\nexport type Actor = {\n  id: string;\n  type: (typeof UniversalStore.ActorType)[keyof typeof UniversalStore.ActorType];\n  environment: EnvironmentType;\n};\nexport type EventInfo = {\n  actor: Actor;\n  forwardingActor?: Actor;\n};\n\nexport type Listener<TEvent> = (event: TEvent, eventInfo: EventInfo) => void;\n\nexport type BaseEvent = {\n  type: string;\n  payload?: any;\n};\n\nexport interface SetStateEvent<TState> extends BaseEvent {\n  type: typeof UniversalStore.InternalEventType.SET_STATE;\n  payload: {\n    state: TState;\n    previousState: TState;\n  };\n}\nexport interface ExistingStateRequestEvent extends BaseEvent {\n  type: typeof UniversalStore.InternalEventType.EXISTING_STATE_REQUEST;\n  payload: never;\n}\nexport interface ExistingStateResponseEvent<TState> extends BaseEvent {\n  type: typeof UniversalStore.InternalEventType.EXISTING_STATE_RESPONSE;\n  payload: TState;\n}\nexport interface LeaderCreatedEvent extends BaseEvent {\n  type: typeof UniversalStore.InternalEventType.LEADER_CREATED;\n  payload: never;\n}\nexport interface FollowerCreatedEvent extends BaseEvent {\n  type: typeof UniversalStore.InternalEventType.FOLLOWER_CREATED;\n  payload: never;\n}\n\nexport type InternalEvent<TState> =\n  | SetStateEvent<TState>\n  | ExistingStateRequestEvent\n  | ExistingStateResponseEvent<TState>\n  | FollowerCreatedEvent\n  | LeaderCreatedEvent;\nexport type Event<TState, TEvent extends BaseEvent> = TEvent | InternalEvent<TState>;\n\nexport type ChannelEvent<TState, TEvent extends BaseEvent> = {\n  event: Event<TState, TEvent>;\n  eventInfo: EventInfo;\n};\n\nexport type ChannelLike = Pick<Channel, 'on' | 'off' | 'emit'>;\n\nexport type StoreOptions<TState> = {\n  id: string;\n  leader?: boolean;\n  initialState?: TState;\n  debug?: boolean;\n};\n\nexport type EnvironmentOverrides = {\n  channel: ChannelLike;\n  environment: EnvironmentType;\n};\n"
  },
  {
    "path": "code/core/src/shared/universal-store/use-universal-store-manager.test.ts",
    "content": "// @vitest-environment happy-dom\nimport { act, renderHook } from '@testing-library/react';\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { UniversalStore } from './index.ts';\nimport { instances as mockedInstances } from './__mocks__/instances.ts';\nimport type { ChannelEvent } from './types.ts';\nimport { useUniversalStore as useUniversalStoreManager } from './use-universal-store-manager.ts';\n\nvi.mock('./instances');\n\nconst mockChannelListeners = new Map<string, Set<(...args: any[]) => void>>();\n\nconst mockChannel = {\n  on: vi.fn((eventType: string, listener: (...args: any[]) => void) => {\n    const [universalStorePrefix, environmentId, universalStoreId] = eventType.split(':');\n    if (!mockChannelListeners.has(universalStoreId)) {\n      mockChannelListeners.set(universalStoreId, new Set());\n    }\n    const listeners = mockChannelListeners.get(universalStoreId)!;\n    listeners.add(listener);\n  }),\n  off: vi.fn((eventType: string, listener: (...args: any[]) => void) => {\n    const universalStoreId = eventType.split(':')[2];\n    if (!mockChannelListeners.has(universalStoreId)) {\n      return;\n    }\n    const listeners = mockChannelListeners.get(universalStoreId)!;\n    listeners.delete(listener);\n  }),\n  emit: vi.fn((eventType: string, channelEvent: ChannelEvent<any, any>) => {\n    const [universalStorePrefix, environmentId, universalStoreId] = eventType.split(':');\n    if (!mockChannelListeners.has(universalStoreId)) {\n      return;\n    }\n    const listeners = mockChannelListeners.get(universalStoreId)!;\n    setTimeout(() => {\n      // this is a simplification, emulating that the event is emitted asynchronously\n      // in reality, it would be synchronous within the same environment, but async across environments\n      listeners.forEach((listener) => listener(channelEvent));\n    }, 0);\n  }),\n};\n\ndescribe('useUniversalStore - Manager', () => {\n  beforeEach((context) => {\n    vi.useRealTimers();\n    let randomUUIDCounter = 0;\n    vi.spyOn(globalThis.crypto, 'randomUUID').mockImplementation(() => {\n      return `mocked-random-uuid-v4-${randomUUIDCounter++}`;\n    });\n\n    // Always prepare the store, unless the test is specifically for unprepared state\n    if (!context.task.name.toLowerCase().includes('unprepared')) {\n      UniversalStore.__prepare(mockChannel, UniversalStore.Environment.MANAGER);\n    }\n\n    return () => {\n      randomUUIDCounter = 0;\n      mockedInstances.clearAllEnvironments();\n      mockChannelListeners.clear();\n      UniversalStore.__reset();\n    };\n  });\n\n  it('should re-render when the state changes', async () => {\n    // Arrange - create a store\n    const store = UniversalStore.create({\n      id: 'env1:test',\n      leader: true,\n      initialState: { count: 0 },\n    });\n    const renderCounter = vi.fn();\n\n    // Act - render the hook\n    const { result } = renderHook(() => {\n      renderCounter();\n      return useUniversalStoreManager(store);\n    });\n\n    // Assert - the component should render with the initial state\n    expect(renderCounter).toHaveBeenCalledTimes(1);\n    const [firstState] = result.current;\n    expect(firstState).toEqual({ count: 0 });\n\n    // Act - set the state directly on the store\n    act(() => store.setState({ count: 1 }));\n\n    // Assert - the component should re-render with the new state\n    expect(renderCounter).toHaveBeenCalledTimes(2);\n    const [secondState] = result.current;\n    expect(secondState).toEqual({ count: 1 });\n  });\n\n  it('should only re-render when the selected state changes', async () => {\n    // Arrange - create a store\n    const store = UniversalStore.create({\n      id: 'env1:test',\n      leader: true,\n      initialState: { count: 0, selectedCount: 10 },\n    });\n    const renderCounter = vi.fn();\n\n    // Act - render the hook with a selector\n    const { result } = renderHook(() => {\n      renderCounter();\n      return useUniversalStoreManager(store, (state) => state.selectedCount);\n    });\n\n    // Assert - the component should re-render when the state changes\n    expect(renderCounter).toHaveBeenCalledTimes(1);\n    const [firstState] = result.current;\n    expect(firstState).toEqual(10);\n\n    // Act - set the selected state\n    act(() => store.setState({ count: 1, selectedCount: 20 }));\n\n    // Assert - the component should re-render with the new selected state\n    expect(renderCounter).toHaveBeenCalledTimes(2);\n    const [secondState] = result.current;\n    expect(secondState).toEqual(20);\n\n    // Act - set the unselected state\n    act(() => store.setState({ count: 5, selectedCount: 20 }));\n\n    // Assert - the component should not re-render because the selected state didn't change\n    expect(renderCounter).toHaveBeenCalledTimes(2);\n    const [thirdState] = result.current;\n    expect(thirdState).toEqual(20);\n  });\n\n  it('should re-render when the selector changes', () => {\n    // Arrange - create a store\n    const store = UniversalStore.create({\n      id: 'env1:test',\n      leader: true,\n      initialState: { count: 0, selectedCount: 10, otherValue: 5 },\n    });\n    const renderCounter = vi.fn();\n\n    // Initial render with a selector for selectedCount\n    const { result, rerender } = renderHook(\n      ({ selector }) => {\n        renderCounter();\n        return useUniversalStoreManager(store, selector);\n      },\n      { initialProps: { selector: (state: any) => state.selectedCount } }\n    );\n\n    // Assert - initial render\n    expect(renderCounter).toHaveBeenCalledTimes(1);\n    const [firstState] = result.current;\n    expect(firstState).toEqual(10);\n\n    // Act - change the selector to a different property\n    rerender({ selector: (state: any) => state.otherValue });\n\n    // Assert - should re-render with the new selected state\n    expect(renderCounter).toHaveBeenCalledTimes(2);\n    const [secondState] = result.current;\n    expect(secondState).toEqual(5);\n\n    // Act - update the store state\n    act(() => store.setState({ count: 1, selectedCount: 10, otherValue: 15 }));\n\n    // Assert - should re-render because the newly selected state changed\n    expect(renderCounter).toHaveBeenCalledTimes(3);\n    const [thirdState] = result.current;\n    expect(thirdState).toEqual(15);\n  });\n\n  it('should re-render when the universalStore changes', () => {\n    // Arrange - create initial store\n    const initialStore = UniversalStore.create({\n      id: 'env1:test1',\n      leader: true,\n      initialState: { count: 0, selectedCount: 10 },\n    });\n    const renderCounter = vi.fn();\n\n    // Initial render with the first store\n    const { result, rerender } = renderHook(\n      ({ store }) => {\n        renderCounter();\n        return useUniversalStoreManager(store);\n      },\n      { initialProps: { store: initialStore } }\n    );\n\n    // Assert - initial render\n    expect(renderCounter).toHaveBeenCalledTimes(1);\n    const [firstState] = result.current;\n    expect(firstState).toEqual({ count: 0, selectedCount: 10 });\n\n    // Act - create a new store and rerender with it\n    const newStore = UniversalStore.create({\n      id: 'env1:test2',\n      leader: true,\n      initialState: { count: 5, selectedCount: 20 },\n    });\n    rerender({ store: newStore });\n\n    // Assert - should re-render with the new store's state\n    expect(renderCounter).toHaveBeenCalledTimes(2);\n    const [secondState] = result.current;\n    expect(secondState).toEqual({ count: 5, selectedCount: 20 });\n\n    // Act - update the new store's state\n    act(() => newStore.setState({ count: 10, selectedCount: 30 }));\n\n    // Assert - should re-render with the updated state\n    expect(renderCounter).toHaveBeenCalledTimes(3);\n    const [thirdState] = result.current;\n    expect(thirdState).toEqual({ count: 10, selectedCount: 30 });\n\n    // Act - update the old store's state (should have no effect)\n    act(() => initialStore.setState({ count: 100, selectedCount: 100 }));\n\n    // Assert - should not re-render as we're no longer using the initial store\n    expect(renderCounter).toHaveBeenCalledTimes(3);\n    const [fourthState] = result.current;\n    expect(fourthState).toEqual({ count: 10, selectedCount: 30 });\n  });\n\n  it('should set the state when the setter is called', () => {\n    // Arrange - create a store and render the hook\n    const store = UniversalStore.create({\n      id: 'env1:test',\n      leader: true,\n      initialState: { count: 0 },\n    });\n    const renderCounter = vi.fn();\n    const { result } = renderHook(() => {\n      renderCounter();\n      return useUniversalStoreManager(store);\n    });\n\n    // Act - set the state via the hook setter\n    const [, firstSetState] = result.current;\n    act(() => firstSetState({ count: 1 }));\n\n    // Assert - the component should re-render with the new state\n    expect(renderCounter).toHaveBeenCalledTimes(2);\n    const [secondState] = result.current;\n    expect(secondState).toEqual({ count: 1 });\n  });\n});\n"
  },
  {
    "path": "code/core/src/shared/universal-store/use-universal-store-manager.ts",
    "content": "import * as React from 'react';\n\nimport { isEqual } from 'es-toolkit/predicate';\n\nimport type { UniversalStore } from './index.ts';\n\n/**\n * A hook to use a UniversalStore in the manager UI (eg. in an addon panel). This hook will react to\n * changes in the store state and re-render when the store changes.\n *\n * @param universalStore The UniversalStore instance to use.\n * @param selector An optional selector function to select a subset of the store state.\n * @remark This hook is intended for use in the manager UI. For use in the preview, import from\n * `storybook/preview-api` instead.\n */\nexport const useUniversalStore: {\n  <\n    TUniversalStore extends UniversalStore<TState, any>,\n    TState = TUniversalStore extends UniversalStore<infer S, any> ? S : never,\n  >(\n    universalStore: TUniversalStore\n  ): [TState, TUniversalStore['setState']];\n  <\n    TUniversalStore extends UniversalStore<any, any>,\n    TSelectedState,\n    TState = TUniversalStore extends UniversalStore<infer S, any> ? S : never,\n  >(\n    universalStore: TUniversalStore,\n    selector: (state: TState) => TSelectedState\n  ): [TSelectedState, TUniversalStore['setState']];\n} = <\n  TUniversalStore extends UniversalStore<any, any>,\n  TSelectedState,\n  TState = TUniversalStore extends UniversalStore<infer S, any> ? S : never,\n>(\n  universalStore: TUniversalStore,\n  selector?: (state: TState) => TSelectedState\n): [TSelectedState, TUniversalStore['setState']] => {\n  const snapshotRef = React.useRef<TSelectedState>(\n    selector ? selector(universalStore.getState()) : universalStore.getState()\n  );\n\n  const subscribe = React.useCallback<Parameters<(typeof React)['useSyncExternalStore']>[0]>(\n    (listener) =>\n      universalStore.onStateChange((state, previousState) => {\n        if (!selector) {\n          snapshotRef.current = state;\n          listener();\n          return;\n        }\n        const selectedState = selector(state);\n        const selectedPreviousState = selector(previousState);\n\n        const hasChanges = !isEqual(selectedState, selectedPreviousState);\n        if (hasChanges) {\n          snapshotRef.current = selectedState;\n          listener();\n        }\n      }),\n    [universalStore, selector]\n  );\n\n  const getSnapshot = React.useCallback(() => {\n    const currentState = universalStore.getState();\n    const selectedState = selector ? selector(currentState) : currentState;\n\n    // Compare with the previous snapshot to maintain referential equality\n    if (isEqual(selectedState, snapshotRef.current)) {\n      return snapshotRef.current;\n    }\n\n    // Update the snapshot reference when the selected state changes\n    snapshotRef.current = selectedState;\n    return snapshotRef.current;\n  }, [universalStore, selector]);\n\n  const state = React.useSyncExternalStore(subscribe, getSnapshot);\n\n  return [state, universalStore.setState];\n};\n"
  },
  {
    "path": "code/core/src/shared/universal-store/use-universal-store-preview.ts",
    "content": "import { isEqual } from 'es-toolkit/predicate';\nimport { useEffect, useState } from 'storybook/preview-api';\n\nimport type { UniversalStore } from './index.ts';\n\n/**\n * A hook to use a UniversalStore in a rendered preview. This hook will react to changes in the\n * store state and re-render when the store changes.\n *\n * @param universalStore The UniversalStore instance to use.\n * @param selector An optional selector function to select a subset of the store state.\n * @remark This hook is intended for use in the preview. For use in the manager UI, import from\n * `storybook/manager-api` instead.\n */\nexport const useUniversalStore: {\n  <\n    TUniversalStore extends UniversalStore<TState, any>,\n    TState = TUniversalStore extends UniversalStore<infer S, any> ? S : never,\n  >(\n    universalStore: TUniversalStore\n  ): [TState, TUniversalStore['setState']];\n  <\n    TUniversalStore extends UniversalStore<any, any>,\n    TSelectedState,\n    TState = TUniversalStore extends UniversalStore<infer S, any> ? S : never,\n  >(\n    universalStore: TUniversalStore,\n    selector: (state: TState) => TSelectedState\n  ): [TSelectedState, TUniversalStore['setState']];\n} = <\n  TUniversalStore extends UniversalStore<any, any>,\n  TSelectedState,\n  TState = TUniversalStore extends UniversalStore<infer S, any> ? S : never,\n>(\n  universalStore: TUniversalStore,\n  selector?: (state: TState) => TSelectedState\n): [TSelectedState, TUniversalStore['setState']] => {\n  const [state, setState] = useState(\n    selector ? selector(universalStore.getState()) : universalStore.getState()\n  );\n\n  useEffect(() => {\n    return universalStore.onStateChange((nextState, previousState) => {\n      if (!selector) {\n        setState(nextState);\n        return;\n      }\n      const selectedNextState = selector(nextState);\n      const selectedPreviousState = selector(previousState);\n\n      const hasChanges = !isEqual(selectedNextState, selectedPreviousState);\n      if (hasChanges) {\n        setState(selectedNextState);\n      }\n    });\n  }, [universalStore, setState, selector]);\n\n  return [state, universalStore.setState];\n};\n"
  },
  {
    "path": "code/core/src/shared/utils/categorize-render-errors.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { ERROR_CATEGORIES, categorizeError } from './categorize-render-errors.ts';\n\ndescribe('categorize-render-errors', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n  });\n\n  describe('categorizeError', () => {\n    describe('Category specific logic', () => {\n      describe('MODULE_IMPORT_ERROR', () => {\n        it('should categorize all module import errors', () => {\n          expect(categorizeError('Cannot find module \"react\"').category).toBe(\n            ERROR_CATEGORIES.MODULE_IMPORT_ERROR\n          );\n\n          expect(\n            categorizeError(\"Module not found: Error: Can't resolve './components/Button'\").category\n          ).toBe(ERROR_CATEGORIES.MODULE_IMPORT_ERROR);\n\n          expect(categorizeError(\"Cannot resolve module 'fs' in path/to/file.js\").category).toBe(\n            ERROR_CATEGORIES.MODULE_IMPORT_ERROR\n          );\n        });\n      });\n\n      describe('TEST_FILE_IMPORT_ERROR', () => {\n        it('should categorize test file import errors', () => {\n          expect(\n            categorizeError(\n              'Failed to import test file /foo/node_modules/@storybook/addon-vitest/dist/vitest-plugin/setup-file.js'\n            ).category\n          ).toBe(ERROR_CATEGORIES.TEST_FILE_IMPORT_ERROR);\n\n          expect(\n            categorizeError('Failed to import test file /path/to/test/setup.ts').category\n          ).toBe(ERROR_CATEGORIES.TEST_FILE_IMPORT_ERROR);\n        });\n      });\n\n      describe('DYNAMIC_MODULE_IMPORT_ERROR', () => {\n        it('should categorize dynamic module import errors', () => {\n          expect(\n            categorizeError(\n              'TypeError: Failed to fetch dynamically imported module: http://localhost:63315/node_modules/.cache/storybook/2523d14eb1a348695c30002850a8852e9305e60b397e9b529978c17a0d2cd524/sb-vitest/deps/react-18-PYSEDAWB-3KPRILU2.js?v=6f767e0c'\n            ).category\n          ).toBe(ERROR_CATEGORIES.DYNAMIC_MODULE_IMPORT_ERROR);\n\n          expect(categorizeError('Failed to fetch dynamically imported module').category).toBe(\n            ERROR_CATEGORIES.DYNAMIC_MODULE_IMPORT_ERROR\n          );\n        });\n      });\n\n      describe('HOOK_USAGE_ERROR', () => {\n        it('should categorize all hook usage errors appropriately', () => {\n          expect(\n            categorizeError(\n              'Invalid hook call. Hooks can only be called inside the body of a function component.'\n            ).category\n          ).toBe(ERROR_CATEGORIES.HOOK_USAGE_ERROR);\n\n          expect(\n            categorizeError('Rendered more hooks than during the previous render.').category\n          ).toBe(ERROR_CATEGORIES.HOOK_USAGE_ERROR);\n\n          expect(\n            categorizeError('Hooks can only be called inside React function components.').category\n          ).toBe(ERROR_CATEGORIES.HOOK_USAGE_ERROR);\n        });\n      });\n\n      describe('MISSING_STATE_PROVIDER', () => {\n        it('should categorize state management errors from stack context messages', () => {\n          const stack = `\n          at useSelector2 (http://localhost:63315/node_modules/.cache/storybook/490ab5/sb-vitest/deps/redux.js:1015:26)\n          at Component (http://localhost/Component.tsx:10:5)\n        `;\n\n          // error message is not useful alone, but combining with stack it will be\n          const result = categorizeError('Cannot read properties of undefined', stack);\n\n          expect(result.category).toBe(ERROR_CATEGORIES.MISSING_STATE_PROVIDER);\n          expect(result.matchedDependencies).toEqual(['redux']);\n        });\n\n        it('should not categorize if there are no state management packages in stack', () => {\n          const result = categorizeError(\"Cannot read properties of undefined (reading 'state')\");\n\n          expect(result.category).not.toBe(ERROR_CATEGORIES.MISSING_STATE_PROVIDER);\n        });\n      });\n\n      describe('MISSING_ROUTER_PROVIDER', () => {\n        it('should categorize router context errors', () => {\n          const stack = `\n          at useLocation (http://localhost:63315/node_modules/.cache/storybook/490ab5/sb-vitest/deps/react-router-dom.js:5431:3)\n          at Component (http://localhost/Component.tsx:15:20)\n        `;\n\n          const result = categorizeError(\n            'useLocation() may be used only in the context of a <Router> component.',\n            stack\n          );\n\n          expect(result.category).toBe(ERROR_CATEGORIES.MISSING_ROUTER_PROVIDER);\n          expect(result.matchedDependencies).toEqual(['react-router-dom']);\n        });\n\n        it('should categorize router errors by message content', () => {\n          expect(\n            categorizeError(\n              'useNavigate() may be used only in the context of a <Router> component.'\n            ).category\n          ).toBe(ERROR_CATEGORIES.MISSING_ROUTER_PROVIDER);\n\n          expect(categorizeError('Router context not found').category).toBe(\n            ERROR_CATEGORIES.MISSING_ROUTER_PROVIDER\n          );\n        });\n      });\n\n      describe('MISSING_THEME_PROVIDER', () => {\n        it('should categorize theme error from message', () => {\n          expect(\n            categorizeError(\n              'ThemeProvider: Please make sure your useTheme hook is within a `<ThemeProvider>`'\n            ).category\n          ).toBe(ERROR_CATEGORIES.MISSING_THEME_PROVIDER);\n\n          expect(categorizeError('useTheme must be used within a ThemeProvider').category).toBe(\n            ERROR_CATEGORIES.MISSING_THEME_PROVIDER\n          );\n\n          expect(categorizeError('theme provider not found').category).toBe(\n            ERROR_CATEGORIES.MISSING_THEME_PROVIDER\n          );\n        });\n\n        it('should categorize theme context errors with hint from stack', () => {\n          const stack = `\n          at http://localhost:63315/node_modules/.cache/storybook/490ab5/sb-vitest/deps/styled-components.js:1168:14\n          at Component (http://localhost/Component.tsx:13:25)\n        `;\n\n          const result = categorizeError(\n            \"Cannot read properties of undefined (reading 'theme')\",\n            stack\n          );\n\n          expect(result.category).toBe(ERROR_CATEGORIES.MISSING_THEME_PROVIDER);\n          expect(result.matchedDependencies).toEqual(['styled-components']);\n        });\n      });\n\n      describe('MISSING_TRANSLATION_PROVIDER', () => {\n        it('should categorize translation errors by message only', () => {\n          const result = categorizeError('Translation provider missing');\n\n          expect(result.category).toBe(ERROR_CATEGORIES.MISSING_TRANSLATION_PROVIDER);\n        });\n\n        it('should categorize i18n context errors with hint from stack', () => {\n          const stack = `\n          at http://localhost:63315/node_modules/.cache/storybook/490ab5/sb-vitest/deps/react-i18next.js:5431:3\n          at Component (http://localhost/Component.tsx:15:20)\n        `;\n\n          const result = categorizeError('i18n context not found', stack);\n\n          expect(result.category).toBe(ERROR_CATEGORIES.MISSING_TRANSLATION_PROVIDER);\n          expect(result.matchedDependencies).toEqual(['react-i18next']);\n        });\n      });\n\n      describe('MISSING_PORTAL_ROOT', () => {\n        it('should categorize portal container errors', () => {\n          expect(categorizeError('Portal container is null').category).toBe(\n            ERROR_CATEGORIES.MISSING_PORTAL_ROOT\n          );\n\n          expect(categorizeError('Portal root not found').category).toBe(\n            ERROR_CATEGORIES.MISSING_PORTAL_ROOT\n          );\n        });\n      });\n\n      describe('MISSING_PROVIDER', () => {\n        it('should categorize useContext null errors', () => {\n          expect(categorizeError('useContext returned null or undefined').category).toBe(\n            ERROR_CATEGORIES.MISSING_PROVIDER\n          );\n        });\n      });\n\n      describe('SERVER_COMPONENTS_ERROR', () => {\n        it('should categorize render-related errors', () => {\n          expect(\n            categorizeError(\n              'Error: async/await is not yet supported in Client Components, only Server Components.'\n            ).category\n          ).toBe(ERROR_CATEGORIES.SERVER_COMPONENTS_ERROR);\n\n          expect(\n            categorizeError(\n              \"This error is often caused by accidentally adding `'use client'` to a module that was originally written for the server\"\n            ).category\n          ).toBe(ERROR_CATEGORIES.SERVER_COMPONENTS_ERROR);\n        });\n      });\n\n      describe('COMPONENT_RENDER_ERROR', () => {\n        it('should categorize render-related errors', () => {\n          expect(categorizeError('undefined is not a function').category).toBe(\n            ERROR_CATEGORIES.COMPONENT_RENDER_ERROR\n          );\n\n          expect(categorizeError('Cannot read properties of undefined').category).toBe(\n            ERROR_CATEGORIES.COMPONENT_RENDER_ERROR\n          );\n\n          expect(categorizeError('Failed to render component').category).toBe(\n            ERROR_CATEGORIES.COMPONENT_RENDER_ERROR\n          );\n        });\n      });\n\n      describe('UNKNOWN_ERROR', () => {\n        it('should categorize unmatched errors as unknown', () => {\n          const result = categorizeError('Some random error that does not match any category');\n\n          expect(result.category).toBe(ERROR_CATEGORIES.UNKNOWN_ERROR);\n        });\n      });\n    });\n\n    describe('priority ordering', () => {\n      it('should categorize based on priority', () => {\n        const moduleImportError = 'Cannot find module and cannot read properties of undefined';\n\n        const componentRenderError = 'Cannot read properties of undefined';\n\n        // should return each error in their own category\n        expect(categorizeError(moduleImportError).category).toBe(\n          ERROR_CATEGORIES.MODULE_IMPORT_ERROR\n        );\n        expect(categorizeError(componentRenderError).category).toBe(\n          ERROR_CATEGORIES.COMPONENT_RENDER_ERROR\n        );\n\n        // but when combined should take highest priority category\n        expect(categorizeError(moduleImportError + ' ' + componentRenderError).category).toBe(\n          ERROR_CATEGORIES.MODULE_IMPORT_ERROR\n        );\n      });\n    });\n\n    describe('stack trace dependency extraction', () => {\n      it('should extract dependencies from stack traces with /deps/ pattern', () => {\n        const stack = `\n          at http://localhost:63315/node_modules/.cache/storybook/490ab5/sb-vitest/deps/styled-components.js:1168:14\n          at http://localhost:63315/node_modules/.cache/storybook/490ab5/sb-vitest/deps/@emotion/react.js:500:10\n          at Component.tsx:13:25\n        `;\n\n        const result = categorizeError(\n          \"Cannot read properties of undefined (reading 'theme')\",\n          stack\n        );\n\n        expect(result.matchedDependencies).toEqual(['styled-components', '@emotion/react']);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/shared/utils/categorize-render-errors.ts",
    "content": "import {\n  isI18nPackage,\n  isRouterPackage,\n  isStateManagementPackage,\n  isStylingPackage,\n} from './ecosystem-identifier.ts';\n\nexport const ERROR_CATEGORIES = {\n  MISSING_PROVIDER: 'MISSING_PROVIDER',\n  MISSING_STATE_PROVIDER: 'MISSING_STATE_PROVIDER',\n  MISSING_ROUTER_PROVIDER: 'MISSING_ROUTER_PROVIDER',\n  MISSING_THEME_PROVIDER: 'MISSING_THEME_PROVIDER',\n  MISSING_TRANSLATION_PROVIDER: 'MISSING_TRANSLATION_PROVIDER',\n  MISSING_PORTAL_ROOT: 'MISSING_PORTAL_ROOT',\n  HOOK_USAGE_ERROR: 'HOOK_USAGE_ERROR',\n  MODULE_IMPORT_ERROR: 'MODULE_IMPORT_ERROR',\n  COMPONENT_RENDER_ERROR: 'COMPONENT_RENDER_ERROR',\n  SERVER_COMPONENTS_ERROR: 'SERVER_COMPONENTS_ERROR',\n  UNKNOWN_ERROR: 'UNKNOWN_ERROR',\n  // Vite related errors\n  DYNAMIC_MODULE_IMPORT_ERROR: 'DYNAMIC_MODULE_IMPORT_ERROR',\n  // Vitest test run related errors\n  TEST_FILE_IMPORT_ERROR: 'TEST_FILE_IMPORT_ERROR',\n} as const;\n\nexport type ErrorCategory = (typeof ERROR_CATEGORIES)[keyof typeof ERROR_CATEGORIES];\n\nexport interface ErrorContext {\n  message: string;\n  stack?: string;\n\n  normalizedMessage: string;\n  normalizedStack: string;\n\n  stackDeps: Set<string>;\n}\n\ninterface CategorizationRule {\n  category: ErrorCategory;\n  priority: number;\n  match: (ctx: ErrorContext) => boolean;\n}\n\n// From a message and stack, return a context for each category matchers\nfunction buildErrorContext(message: string, stack?: string): ErrorContext {\n  const normalizedMessage = message.toLowerCase();\n  const normalizedStack = (stack ?? '').toLowerCase();\n\n  const stackDeps = new Set<string>();\n  const stackLines = normalizedStack.split('\\n').filter(Boolean);\n\n  for (const line of stackLines) {\n    // Extracts any module name between '/deps/' and '.js'\n    // e.g. http://localhost:63315/node_modules/.cache/storybook/490ab5/sb-vitest/deps/@emotion/react.js:500:10\n    // would become '@emotion/react'\n    // NOTE this is Vite dependent for now.\n    const depMatch = line.match(/\\/deps\\/([^:]+)\\.js/);\n    if (depMatch) {\n      stackDeps.add(depMatch[1]);\n    }\n  }\n\n  return {\n    message,\n    stack,\n    normalizedMessage,\n    normalizedStack,\n    stackDeps,\n  };\n}\n\n/**\n * Each rule is a category matcher with a priority. The higher the priority, the more specific the\n * rule is. For instance you might have an error message that matches two categories\n *\n * E.g. \"cannot find module theme\".\n *\n * In this case, it's more of a module import error than a theme provider error.\n *\n * Each matcher combines doing simple checks based on error message but also fallback to checking\n * existence of specific dependency names in the stack, as sometimes an error message isn't enough.\n *\n * E.g. \"Cannot read properties of undefined (reading 'theme')\" at /deps/styled-components.js\n */\nconst CATEGORIZATION_RULES: CategorizationRule[] = [\n  {\n    category: ERROR_CATEGORIES.MODULE_IMPORT_ERROR,\n    priority: 100,\n    match: (ctx) =>\n      ctx.normalizedMessage.includes('cannot find module') ||\n      ctx.normalizedMessage.includes('module not found') ||\n      ctx.normalizedMessage.includes('cannot resolve module'),\n  },\n\n  {\n    category: ERROR_CATEGORIES.TEST_FILE_IMPORT_ERROR,\n    priority: 95,\n    match: (ctx) => ctx.normalizedMessage.includes('failed to import test file'),\n  },\n\n  {\n    category: ERROR_CATEGORIES.DYNAMIC_MODULE_IMPORT_ERROR,\n    priority: 95,\n    match: (ctx) => ctx.normalizedMessage.includes('failed to fetch dynamically imported module'),\n  },\n\n  {\n    category: ERROR_CATEGORIES.HOOK_USAGE_ERROR,\n    priority: 90,\n    match: (ctx) =>\n      ctx.normalizedMessage.includes('invalid hook call') ||\n      ctx.normalizedMessage.includes('rendered more hooks than') ||\n      ctx.normalizedMessage.includes('hooks can only be called'),\n  },\n\n  {\n    category: ERROR_CATEGORIES.MISSING_STATE_PROVIDER,\n    priority: 85,\n    match: (ctx) =>\n      Array.from(ctx.stackDeps).some(isStateManagementPackage) &&\n      (ctx.normalizedMessage.includes('context') ||\n        ctx.normalizedMessage.includes('undefined') ||\n        ctx.normalizedMessage.includes('null')),\n  },\n\n  {\n    category: ERROR_CATEGORIES.MISSING_ROUTER_PROVIDER,\n    priority: 85,\n    match: (ctx) =>\n      Array.from(ctx.stackDeps).some(isRouterPackage) ||\n      ctx.normalizedMessage.includes('usenavigate') ||\n      ctx.normalizedMessage.includes('router'),\n  },\n\n  {\n    category: ERROR_CATEGORIES.SERVER_COMPONENTS_ERROR,\n    priority: 85,\n    match: (ctx) =>\n      ctx.normalizedMessage.includes('server components') ||\n      ctx.normalizedMessage.includes('use client') ||\n      (ctx.normalizedMessage.includes('async/await') &&\n        ctx.normalizedMessage.includes('not supported')),\n  },\n\n  {\n    category: ERROR_CATEGORIES.MISSING_THEME_PROVIDER,\n    priority: 80,\n    match: (ctx) =>\n      (Array.from(ctx.stackDeps).some(isStylingPackage) &&\n        (ctx.normalizedMessage.includes('theme') || ctx.normalizedMessage.includes('undefined'))) ||\n      ctx.normalizedMessage.includes('usetheme') ||\n      (ctx.normalizedMessage.includes('theme') && ctx.normalizedMessage.includes('provider')),\n  },\n\n  {\n    category: ERROR_CATEGORIES.MISSING_TRANSLATION_PROVIDER,\n    priority: 80,\n    match: (ctx) =>\n      Array.from(ctx.stackDeps).some(isI18nPackage) ||\n      ctx.normalizedMessage.includes('i18n') ||\n      ctx.normalizedMessage.includes('translation') ||\n      ctx.normalizedMessage.includes('locale'),\n  },\n\n  {\n    category: ERROR_CATEGORIES.MISSING_PORTAL_ROOT,\n    priority: 70,\n    match: (ctx) =>\n      ctx.normalizedMessage.includes('portal') &&\n      (ctx.normalizedMessage.includes('container') || ctx.normalizedMessage.includes('root')) &&\n      (ctx.normalizedMessage.includes('null') || ctx.normalizedMessage.includes('not found')),\n  },\n\n  {\n    category: ERROR_CATEGORIES.MISSING_PROVIDER,\n    priority: 60,\n    match: (ctx) =>\n      (ctx.normalizedMessage.includes('use') && ctx.normalizedMessage.includes('provider')) ||\n      ctx.normalizedMessage.includes('<provider>') ||\n      ((ctx.normalizedMessage.includes('could not find') ||\n        ctx.normalizedMessage.includes('missing')) &&\n        ctx.normalizedMessage.includes('context')) ||\n      (ctx.normalizedMessage.includes('usecontext') &&\n        (ctx.normalizedMessage.includes('null') || ctx.normalizedMessage.includes('undefined'))),\n  },\n\n  {\n    category: ERROR_CATEGORIES.COMPONENT_RENDER_ERROR,\n    priority: 10,\n    match: (ctx) =>\n      ctx.normalizedMessage.includes('cannot read') ||\n      ctx.normalizedMessage.includes('undefined is not a function') ||\n      ctx.normalizedMessage.includes('render'),\n  },\n];\n\nconst RULES = CATEGORIZATION_RULES.sort((a, b) => b.priority - a.priority);\n\n/**\n * For a given error, return which category and which whitelisted dependencies of that category were\n * matched in the stack trace\n */\nexport function categorizeError(\n  message: string,\n  stack?: string\n): { category: ErrorCategory; matchedDependencies: string[] } {\n  const ctx = buildErrorContext(message, stack);\n  const rule = RULES.find((r) => r.match(ctx));\n\n  if (!rule) {\n    return { category: ERROR_CATEGORIES.UNKNOWN_ERROR, matchedDependencies: [] };\n  }\n\n  // Extract matched dependencies based on the category\n  const matchedDependencies = getMatchedDependencies(rule.category, ctx);\n  return { category: rule.category, matchedDependencies };\n}\n\nfunction getMatchedDependencies(category: ErrorCategory, ctx: ErrorContext): string[] {\n  switch (category) {\n    case ERROR_CATEGORIES.MISSING_STATE_PROVIDER:\n      return Array.from(ctx.stackDeps).filter(isStateManagementPackage);\n    case ERROR_CATEGORIES.MISSING_ROUTER_PROVIDER:\n      return Array.from(ctx.stackDeps).filter(isRouterPackage);\n    case ERROR_CATEGORIES.MISSING_THEME_PROVIDER:\n      return Array.from(ctx.stackDeps).filter(isStylingPackage);\n    case ERROR_CATEGORIES.MISSING_TRANSLATION_PROVIDER:\n      return Array.from(ctx.stackDeps).filter(isI18nPackage);\n    default:\n      return [];\n  }\n}\n\n/** For a given category, return a description of the error for better legibility. */\nexport function getCategoryDescription(category: ErrorCategory): string {\n  switch (category) {\n    case ERROR_CATEGORIES.MISSING_STATE_PROVIDER:\n      return 'Component attempted to access shared state without a state management provider';\n\n    case ERROR_CATEGORIES.MISSING_ROUTER_PROVIDER:\n      return 'Component attempted to access routing context without a router provider';\n\n    case ERROR_CATEGORIES.MISSING_THEME_PROVIDER:\n      return 'Component attempted to access theme values without a theme provider';\n\n    case ERROR_CATEGORIES.MISSING_TRANSLATION_PROVIDER:\n      return 'Component attempted to access translations without a translation provider';\n\n    case ERROR_CATEGORIES.MISSING_PROVIDER:\n      return 'Component attempted to access React context without a matching provider';\n\n    case ERROR_CATEGORIES.MISSING_PORTAL_ROOT:\n      return 'Component attempted to render a portal without a valid DOM container';\n\n    case ERROR_CATEGORIES.HOOK_USAGE_ERROR:\n      return 'React hook was used incorrectly';\n\n    case ERROR_CATEGORIES.MODULE_IMPORT_ERROR:\n      return 'A required dependency could not be resolved';\n\n    case ERROR_CATEGORIES.TEST_FILE_IMPORT_ERROR:\n      return 'Failed to import a test file during test execution';\n\n    case ERROR_CATEGORIES.DYNAMIC_MODULE_IMPORT_ERROR:\n      return 'Failed to dynamically import a module at runtime';\n\n    case ERROR_CATEGORIES.COMPONENT_RENDER_ERROR:\n      return 'Component failed during render due to a runtime error';\n\n    case ERROR_CATEGORIES.SERVER_COMPONENTS_ERROR:\n      return 'Server components usage in the browser';\n\n    default:\n      return 'Error could not be categorized';\n  }\n}\n"
  },
  {
    "path": "code/core/src/shared/utils/ecosystem-identifier.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { globToRegex, matchesPackagePattern } from './ecosystem-identifier.ts';\n\ndescribe('ecosystem-identifier', () => {\n  describe('globToRegex', () => {\n    it('should convert exact match patterns', () => {\n      const regex = globToRegex('jest');\n      expect(regex.test('jest')).toBe(true);\n      expect(regex.test('jest-dom')).toBe(false);\n      expect(regex.test('@jest/core')).toBe(false);\n    });\n\n    it('should convert wildcard patterns with *', () => {\n      const regex = globToRegex('*playwright*');\n      expect(regex.test('playwright')).toBe(true);\n      expect(regex.test('@playwright/test')).toBe(true);\n      expect(regex.test('some-playwright-package')).toBe(true);\n      expect(regex.test('jest')).toBe(false);\n    });\n\n    it('should convert scoped package patterns', () => {\n      const regex = globToRegex('@vitest/*');\n      expect(regex.test('@vitest/ui')).toBe(true);\n      expect(regex.test('@vitest/coverage-v8')).toBe(true);\n      expect(regex.test('vitest')).toBe(false);\n      expect(regex.test('@jest/vitest')).toBe(false);\n    });\n\n    it('should convert prefix wildcard patterns', () => {\n      const regex = globToRegex('wdio*');\n      expect(regex.test('wdio')).toBe(true);\n      expect(regex.test('wdio-webdriverio')).toBe(true);\n      expect(regex.test('webdriverio')).toBe(false);\n    });\n\n    it('should handle multiple wildcards', () => {\n      const regex = globToRegex('*-router-*');\n      expect(regex.test('react-router-dom')).toBe(true);\n      expect(regex.test('vue-router-core')).toBe(true);\n      expect(regex.test('router')).toBe(false);\n      expect(regex.test('my-router')).toBe(false);\n    });\n\n    it('should escape special regex characters', () => {\n      const regex = globToRegex('react-router');\n      expect(regex.test('react-router')).toBe(true);\n      expect(regex.test('react(router)')).toBe(false);\n    });\n\n    it('should handle path-like patterns', () => {\n      const regex = globToRegex('*/router');\n      expect(regex.test('@reach/router')).toBe(true);\n      expect(regex.test('@remix-run/router')).toBe(true);\n      expect(regex.test('router')).toBe(false);\n      expect(regex.test('some/router')).toBe(true);\n    });\n\n    it('should handle complex patterns with multiple wildcards', () => {\n      const regex = globToRegex('@tanstack/*-router');\n      expect(regex.test('@tanstack/react-router')).toBe(true);\n      expect(regex.test('@tanstack/vue-router')).toBe(true);\n      expect(regex.test('@tanstack/router')).toBe(false);\n      expect(regex.test('tanstack/react-router')).toBe(false);\n    });\n  });\n\n  describe('matchesPackagePattern', () => {\n    it('should return true when package matches any pattern', () => {\n      const patterns = ['jest', 'vitest', '@testing-library/*'];\n      expect(matchesPackagePattern('jest', patterns)).toBe(true);\n      expect(matchesPackagePattern('vitest', patterns)).toBe(true);\n      expect(matchesPackagePattern('@testing-library/react', patterns)).toBe(true);\n    });\n\n    it('should return false when package matches no patterns', () => {\n      const patterns = ['jest', 'vitest', '@testing-library/*'];\n      expect(matchesPackagePattern('cypress', patterns)).toBe(false);\n      expect(matchesPackagePattern('mocha', patterns)).toBe(false);\n    });\n\n    it('should handle empty patterns array', () => {\n      expect(matchesPackagePattern('any-package', [])).toBe(false);\n    });\n\n    it('should handle complex glob patterns', () => {\n      const patterns = ['*playwright*', '@vitest/*', 'wdio*'];\n      expect(matchesPackagePattern('playwright', patterns)).toBe(true);\n      expect(matchesPackagePattern('@playwright/test', patterns)).toBe(true);\n      expect(matchesPackagePattern('@vitest/ui', patterns)).toBe(true);\n      expect(matchesPackagePattern('wdio', patterns)).toBe(true);\n      expect(matchesPackagePattern('wdio-webdriverio', patterns)).toBe(true);\n      expect(matchesPackagePattern('jest', patterns)).toBe(false);\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/shared/utils/ecosystem-identifier.ts",
    "content": "export const TEST_PACKAGES = [\n  '*playwright*',\n  '@playwright/*',\n  '*vitest*',\n  '@vitest/*',\n  'jest',\n  'cypress',\n  'nightwatch',\n  'webdriver',\n  '@web/test-runner',\n  'puppeteer',\n  'karma',\n  'jasmine',\n  'chai',\n  '@testing-library/*',\n  '@ngneat/spectator',\n  'wdio*',\n  'msw',\n  'miragejs',\n  'sinon',\n  'chromatic',\n] as const;\n\nexport const STYLING_PACKAGES = [\n  'postcss',\n  'tailwindcss',\n  'autoprefixer',\n  'sass',\n  'emotion',\n  '@emotion/*',\n  'less',\n  'styled-components',\n  'bootstrap',\n  'goober',\n  'stylus',\n  'jss',\n  'linaria',\n  'bulma',\n  'aphrodite',\n  'semantic-ui',\n  'foundation-sites',\n  'fela',\n] as const;\n\nexport const STATE_MANAGEMENT_PACKAGES = [\n  '*redux*',\n  '@reduxjs/*',\n  'zustand',\n  'jotai',\n  'recoil',\n  'mobx*',\n  'valtio',\n  'xstate',\n  '@xstate/*',\n  'effector',\n  'effector-react',\n  'easy-peasy',\n] as const;\n\nexport const DATA_FETCHING_PACKAGES = [\n  'axios',\n  '@tanstack/react-query',\n  'superagent',\n  'swr',\n  'isomorphic-fetch',\n  '*graphql*',\n  'ky',\n  '@apollo/*',\n  'relay-runtime',\n  'react-query',\n  'urql',\n  'react-relay',\n] as const;\n\nexport const UI_LIBRARY_PACKAGES = [\n  '@mui/*',\n  '@headlessui/*',\n  'antd',\n  'radix-ui',\n  '@radix-ui/*',\n  'react-bootstrap',\n  '@mantine/*',\n  '@chakra-ui/*',\n  'shadcn',\n  '@blueprintjs/*',\n  'semantic-ui-react',\n  'primereact',\n  '@fluentui/*',\n  'rsuite',\n  'react-aria*',\n  '@react-aria/*',\n  '@heroui/*',\n  '@carbon/*',\n  'theme-ui',\n  'rebass',\n] as const;\n\nexport const I18N_PACKAGES = ['*i18n*', '*intl', '@lingui/*'] as const;\n\nexport const ROUTER_PACKAGES = [\n  'react-router',\n  'react-router-dom',\n  'react-easy-router',\n  '@remix-run/router',\n  'expo-router',\n  '@tanstack/*-router',\n  'wouter',\n  '@reach/router',\n] as const;\n\nexport function globToRegex(pattern: string): RegExp {\n  // Escape special regex characters except *\n  const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&');\n  // Replace * with .* to match any sequence of characters\n  const regexPattern = escaped.replace(/\\*/g, '.*');\n  // Anchor the pattern to match the entire string\n  return new RegExp(`^${regexPattern}$`);\n}\n\nexport function matchesPackagePattern(\n  dependencyName: string,\n  patterns: readonly string[]\n): boolean {\n  return patterns.some((pattern) => globToRegex(pattern).test(dependencyName));\n}\n\nexport function isStateManagementPackage(dependencyName: string): boolean {\n  return matchesPackagePattern(dependencyName, STATE_MANAGEMENT_PACKAGES);\n}\n\nexport function isStylingPackage(dependencyName: string): boolean {\n  return matchesPackagePattern(dependencyName, STYLING_PACKAGES);\n}\n\nexport function isRouterPackage(dependencyName: string): boolean {\n  return matchesPackagePattern(dependencyName, ROUTER_PACKAGES);\n}\n\nexport function isI18nPackage(dependencyName: string): boolean {\n  return matchesPackagePattern(dependencyName, I18N_PACKAGES);\n}\n"
  },
  {
    "path": "code/core/src/shared/utils/module.ts",
    "content": "import { statSync } from 'node:fs';\nimport { createRequire, register } from 'node:module';\nimport { win32 } from 'node:path/win32';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\n\nimport { resolveModulePath } from 'exsolve';\nimport { dirname, join } from 'pathe';\n\n/**\n * This is just an alias for import.meta.resolve. It makes it possible to mock it in Vitest with\n * module-mocking, as Vitest currently does not support import.meta.resolve in tests.\n *\n * @see https://github.com/vitest-dev/vitest/issues/6953\n */\nexport const importMetaResolve = (...args: Parameters<ImportMeta['resolve']>) => {\n  if (typeof import.meta.resolve !== 'function' && process.env.VITEST === 'true') {\n    // This should only ever happen in our internal Vitest unit tests. This specific warning is silenced globally in vitest-setup.ts.\n    // If anyone sees this warning, it means that this function was used in Vitest, but not our Vitest.\n    console.warn(\n      \"importMetaResolve from within Storybook is being used in a Vitest test, but it shouldn't be. Please report this at https://github.com/storybookjs/storybook/issues/new?template=bug_report.yml\"\n    );\n    return pathToFileURL(args[0]).href;\n  }\n  return import.meta.resolve(...args);\n};\n\n/** Resolves the directory of a given package, by resolving its package.json file. */\nexport const resolvePackageDir = (\n  pkg: Parameters<ImportMeta['resolve']>[0],\n  parent?: Parameters<ImportMeta['resolve']>[0]\n) => {\n  try {\n    return dirname(fileURLToPath(importMetaResolve(join(pkg, 'package.json'), parent)));\n  } catch {\n    try {\n      // Necessary fallback for Bun runtime\n      return dirname(fileURLToPath(importMetaResolve(join(pkg, 'package.json'))));\n    } catch {\n      // Fallback using require.resolve for strict pnpm environments where import.meta.resolve may fail\n      const req = createRequire(parent ?? import.meta.url);\n      return dirname(req.resolve(join(pkg, 'package.json')));\n    }\n  }\n};\n\nlet isTypescriptLoaderRegistered = false;\n\n/**\n * Dynamically imports a module with TypeScript support, falling back to require if necessary.\n *\n * @example Import a TypeScript preset\n *\n * ```ts\n * const preset = await importModule('./my-preset.ts');\n * // Returns the default export or the entire module\n * ```\n *\n * @example Import a JavaScript addon\n *\n * ```ts\n * const addon = await importModule('@storybook/addon-essentials');\n * // Returns the default export or the entire module\n * ```\n */\nexport async function importModule(\n  path: string,\n  { skipCache = false }: { skipCache?: boolean } = {}\n) {\n  if (!isTypescriptLoaderRegistered) {\n    const typescriptLoaderUrl = importMetaResolve('storybook/internal/bin/loader');\n    register(typescriptLoaderUrl, import.meta.url);\n    isTypescriptLoaderRegistered = true;\n  }\n\n  let mod;\n  try {\n    const resolvedPath = win32.isAbsolute(path) ? pathToFileURL(path).href : path;\n    // When applicable, add a hash to the import URL to bypass cache\n    const importUrl = skipCache ? `${resolvedPath}?${Date.now()}` : resolvedPath;\n    mod = await import(importUrl);\n  } catch (importError) {\n    try {\n      // fallback to require to support older behavior\n      // this is relevant for presets that are only available with the \"require\" condition in a package's export map\n      const require = createRequire(import.meta.url);\n      if (skipCache) {\n        delete require.cache[require.resolve(path)];\n      }\n      mod = require(path);\n    } catch (requireError) {\n      /*\n        If everything fails, throw the original import error, as the require error won't be helpful\n        in Node 20 requireError will always be \"Error [ERR_REQUIRE_CYCLE_MODULE]: Cannot require() ES Module\"\n        in Node 22 requireError will always be \"Error [ERR_INTERNAL_ASSERTION]: Unexpected module status 5. Cannot require() ES Module\"\n      */\n      throw importError;\n    }\n  }\n  return mod.default ?? mod;\n}\n\n/**\n * Safely resolves a module specifier to its absolute file path.\n *\n * Attempts to resolve the given module specifier by trying different file extensions until a valid\n * file is found. Returns undefined if the module cannot be resolved.\n *\n * Optionally pass in a list of file extensions to try, defaulting to `.mjs`, `.js`, and `.cjs`.\n *\n * @example\n *\n * ```typescript\n * // Resolve a relative module\n * const path = safeResolveModule({\n *   specifier: './utils',\n *   parent: import.meta.url,\n * });\n *\n * // Resolve with custom extensions\n * const path = safeResolveModule({\n *   specifier: './config',\n *   extensions: ['.json', '.js'],\n * });\n * ```\n */\nexport const safeResolveModule = ({\n  specifier,\n  parent,\n  extensions = ['.mjs', '.js', '.cjs'],\n}: {\n  specifier: string;\n  parent?: string;\n  extensions?: string[];\n}) => {\n  try {\n    const resolvedPath = resolveModulePath(specifier, {\n      from: parent,\n      extensions: [''].concat(extensions),\n    });\n    if (statSync(resolvedPath).isFile()) {\n      return resolvedPath;\n    }\n  } catch (e: any) {}\n};\n"
  },
  {
    "path": "code/core/src/storybook-error.ts",
    "content": "function parseErrorCode({\n  code,\n  category,\n}: Pick<StorybookError, 'code' | 'category'>): `SB_${typeof category}_${string}` {\n  const paddedCode = String(code).padStart(4, '0');\n  return `SB_${category}_${paddedCode}`;\n}\n\nexport function appendErrorRef(url: string): string {\n  // Skip if not storybook.js.org OR already has ref=error\n  if (/^(?!.*storybook\\.js\\.org)|[?&]ref=error\\b/.test(url)) {\n    return url;\n  }\n\n  try {\n    const urlObj = new URL(url);\n    urlObj.searchParams.set('ref', 'error');\n    return urlObj.toString();\n  } catch {\n    // Fallback for invalid URLs - return as-is\n    return url;\n  }\n}\n\nexport abstract class StorybookError extends Error {\n  private _name: string | undefined;\n\n  /** Category of the error. Used to classify the type of error, e.g., 'PREVIEW_API'. */\n  public readonly category: string;\n\n  /** Code representing the error. Used to uniquely identify the error, e.g., 1. */\n  public readonly code: number;\n\n  /**\n   * Data associated with the error. Used to provide additional information in the error message or\n   * to be passed to telemetry.\n   */\n  public readonly data = {};\n\n  /**\n   * Specifies the documentation for the error.\n   *\n   * - If `true`, links to a documentation page on the Storybook website (make sure it exists before\n   *   enabling) – This is not implemented yet.\n   * - If a string, uses the provided URL for documentation (external or FAQ links).\n   * - If `false` (default), no documentation link is added.\n   */\n  public readonly documentation: boolean | string | string[];\n\n  /** Flag used to easily determine if the error originates from Storybook. */\n  readonly fromStorybook: true = true as const;\n\n  /**\n   * Flag used to determine if the error is handled by us and should therefore not be shown to the\n   * user.\n   */\n  public isHandledError = false;\n\n  get fullErrorCode() {\n    return parseErrorCode({ code: this.code, category: this.category });\n  }\n\n  /** Overrides the default `Error.name` property in the format: SB_<CATEGORY>_<CODE>. */\n  get name() {\n    const errorName = this._name || this.constructor.name;\n\n    return `${this.fullErrorCode} (${errorName})`;\n  }\n\n  set name(name: string) {\n    this._name = name;\n  }\n\n  /**\n   * A collection of sub errors which relate to a parent error.\n   *\n   * Sub-errors are used to represent multiple related errors that occurred together. When a\n   * StorybookError with sub-errors is sent to telemetry, both the parent error and each sub-error\n   * are sent as separate telemetry events. This allows for better error tracking and debugging.\n   *\n   * @example\n   *\n   * ```ts\n   * const error1 = new SomeError();\n   * const error2 = new AnotherError();\n   * const parentError = new ParentError({\n   *   // ... other props\n   *   subErrors: [error1, error2],\n   * });\n   * ```\n   */\n  subErrors: StorybookError[] = [];\n\n  constructor(props: {\n    category: string;\n    code: number;\n    message: string;\n    documentation?: boolean | string | string[];\n    isHandledError?: boolean;\n    name: string;\n    /**\n     * Optional array of sub-errors that are related to this error. When this error is sent to\n     * telemetry, each sub-error will be sent as a separate event.\n     */\n    subErrors?: StorybookError[];\n  }) {\n    super(StorybookError.getFullMessage(props));\n    this.category = props.category;\n    this.documentation = props.documentation ?? false;\n    this.code = props.code;\n    this.isHandledError = props.isHandledError ?? false;\n    this.name = props.name;\n    this.subErrors = props.subErrors ?? [];\n  }\n\n  /** Generates the error message along with additional documentation link (if applicable). */\n  static getFullMessage({\n    documentation,\n    code,\n    category,\n    message,\n  }: ConstructorParameters<typeof StorybookError>[0]) {\n    let page: string | undefined;\n\n    if (documentation === true) {\n      page = `https://storybook.js.org/error/${parseErrorCode({ code, category })}?ref=error`;\n    } else if (typeof documentation === 'string') {\n      page = appendErrorRef(documentation);\n    } else if (Array.isArray(documentation)) {\n      page = `\\n${documentation.map((doc) => `\\t- ${appendErrorRef(doc)}`).join('\\n')}`;\n    }\n\n    return `${message}${page != null ? `\\n\\nMore info: ${page}\\n` : ''}`;\n  }\n}\n"
  },
  {
    "path": "code/core/src/telemetry/README.md",
    "content": "# Storybook Telemetry\n\nStorybook collects completely anonymous telemetry data about general usage. Participation in this program is optional and it’s easy to opt-out.\n\nFor more information visit: [storybook.js.org/telemetry](https://storybook.js.org/docs/configure/telemetry)\n"
  },
  {
    "path": "code/core/src/telemetry/anonymous-id.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { executeCommandSync } from 'storybook/internal/common';\n\nimport {\n  getAnonymousProjectId,\n  getProjectSince,\n  normalizeGitUrl,\n  unhashedProjectId,\n} from './anonymous-id.ts';\n\nvi.mock(import('storybook/internal/common'), async (actualModule) => {\n  const actual = await actualModule();\n\n  return {\n    ...actual,\n    executeCommandSync: vi.fn(actual.executeCommandSync),\n    getProjectRoot: () => '/path/to/project/root',\n  };\n});\n\nbeforeEach(() => {\n  vi.mocked(executeCommandSync).mockReset();\n});\n\ndescribe('normalizeGitUrl', () => {\n  it('trims off https://', () => {\n    expect(normalizeGitUrl('https://github.com/storybookjs/storybook.git')).toEqual(\n      'github.com/storybookjs/storybook.git'\n    );\n  });\n\n  it('trims off http://', () => {\n    expect(normalizeGitUrl('http://github.com/storybookjs/storybook.git')).toEqual(\n      'github.com/storybookjs/storybook.git'\n    );\n  });\n\n  it('trims off git+https://', () => {\n    expect(normalizeGitUrl('git+https://github.com/storybookjs/storybook.git')).toEqual(\n      'github.com/storybookjs/storybook.git'\n    );\n  });\n\n  it('trims off https://username@', () => {\n    expect(normalizeGitUrl('https://username@github.com/storybookjs/storybook.git')).toEqual(\n      'github.com/storybookjs/storybook.git'\n    );\n  });\n\n  it('trims off http://username@', () => {\n    expect(normalizeGitUrl('http://username@github.com/storybookjs/storybook.git')).toEqual(\n      'github.com/storybookjs/storybook.git'\n    );\n  });\n\n  it('trims off https://username:password@', () => {\n    expect(\n      normalizeGitUrl('https://username:password@github.com/storybookjs/storybook.git')\n    ).toEqual('github.com/storybookjs/storybook.git');\n  });\n\n  it('trims off http://username:password@', () => {\n    expect(\n      normalizeGitUrl('http://username:password@github.com/storybookjs/storybook.git')\n    ).toEqual('github.com/storybookjs/storybook.git');\n  });\n\n  it('trims off git://', () => {\n    expect(normalizeGitUrl('git://github.com/storybookjs/storybook.git')).toEqual(\n      'github.com/storybookjs/storybook.git'\n    );\n  });\n\n  it('trims off git@', () => {\n    expect(normalizeGitUrl('git@github.com:storybookjs/storybook.git')).toEqual(\n      'github.com/storybookjs/storybook.git'\n    );\n  });\n\n  it('trims off git+ssh://git@', () => {\n    expect(normalizeGitUrl('git+ssh://git@github.com:storybookjs/storybook.git')).toEqual(\n      'github.com/storybookjs/storybook.git'\n    );\n  });\n\n  it('trims off ssh://git@', () => {\n    expect(normalizeGitUrl('ssh://git@github.com:storybookjs/storybook.git')).toEqual(\n      'github.com/storybookjs/storybook.git'\n    );\n  });\n\n  it('adds .git if missing', () => {\n    expect(normalizeGitUrl('https://github.com/storybookjs/storybook')).toEqual(\n      'github.com/storybookjs/storybook.git'\n    );\n  });\n\n  it('trims off #hash', () => {\n    expect(normalizeGitUrl('https://github.com/storybookjs/storybook.git#next')).toEqual(\n      'github.com/storybookjs/storybook.git'\n    );\n  });\n\n  it('trims off extra whitespace', () => {\n    expect(normalizeGitUrl('https://github.com/storybookjs/storybook.git#next\\n')).toEqual(\n      'github.com/storybookjs/storybook.git'\n    );\n\n    expect(normalizeGitUrl('https://github.com/storybookjs/storybook.git\\n')).toEqual(\n      'github.com/storybookjs/storybook.git'\n    );\n  });\n});\n\ndescribe('unhashedProjectId', () => {\n  it('does not touch unix paths', () => {\n    expect(\n      unhashedProjectId('https://github.com/storybookjs/storybook.git\\n', 'path/to/storybook')\n    ).toBe('github.com/storybookjs/storybook.gitpath/to/storybook');\n  });\n\n  it('normalizes windows paths', () => {\n    expect(\n      unhashedProjectId('https://github.com/storybookjs/storybook.git\\n', 'path\\\\to\\\\storybook')\n    ).toBe('github.com/storybookjs/storybook.gitpath/to/storybook');\n  });\n});\n\ndescribe('getProjectSince', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n    vi.resetModules();\n  });\n\n  it('returns the Storybook creation date from git log output', () => {\n    vi.mocked(executeCommandSync).mockReturnValue(\n      '2025-12-11 16:24:01 +0530\\n' + '2014-12-11 19:09:10 +0530'\n    );\n\n    expect(getProjectSince()).toEqual(new Date('2025-12-11T10:54:01.000Z'));\n  });\n\n  it('returns undefined if git log output is empty', async () => {\n    vi.mocked(executeCommandSync).mockReturnValue('');\n\n    const { getProjectSince: getProjSince } = await import('./anonymous-id.ts');\n\n    expect(getProjSince()).toBeUndefined();\n  });\n\n  it('returns undefined if git log fails', async () => {\n    vi.mocked(executeCommandSync).mockImplementation(() => {\n      throw new Error('git not available');\n    });\n\n    const { getProjectSince: getProjSince } = await import('./anonymous-id.ts');\n\n    expect(getProjSince()).toBeUndefined();\n  });\n});\n\ndescribe('getAnonymousProjectId', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n    vi.resetModules();\n\n    vi.spyOn(process, 'cwd').mockReturnValue('/path/to/project/root');\n  });\n\n  it('returns hashed project id for Storybook repo when git command succeeds', async () => {\n    vi.mocked(executeCommandSync).mockReturnValue('git@github.com:storybookjs/storybook.git');\n    const result = getAnonymousProjectId();\n\n    expect(result).toMatch('061e4ee22a1f7c079849d97234b3be94d016fb1f24ba11878c41f8b48c0213bf');\n  });\n\n  it('returns undefined when git command fails', async () => {\n    const { getAnonymousProjectId: getAnonId } = await import('./anonymous-id.ts');\n\n    vi.mocked(executeCommandSync).mockImplementation(() => {\n      throw new Error('git not available');\n    });\n\n    const result = getAnonId();\n\n    expect(result).toBeUndefined();\n  });\n});\n"
  },
  {
    "path": "code/core/src/telemetry/anonymous-id.ts",
    "content": "import { relative } from 'node:path';\n\nimport { executeCommandSync, getProjectRoot } from 'storybook/internal/common';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\n\nimport { oneWayHash } from './one-way-hash.ts';\n\nexport function normalizeGitUrl(rawUrl: string) {\n  // I don't *think* its possible to set a hash on a origin URL, but just in case\n  const urlWithoutHash = rawUrl.trim().replace(/#.*$/, '');\n\n  // Strip anything ahead of an @\n  const urlWithoutUser = urlWithoutHash.replace(/^.*@/, '');\n\n  // Now strip off scheme\n  const urlWithoutScheme = urlWithoutUser.replace(/^.*\\/\\//, '');\n\n  // Ensure the URL ends in `.git`\n  const urlWithExtension = urlWithoutScheme.endsWith('.git')\n    ? urlWithoutScheme\n    : `${urlWithoutScheme}.git`;\n\n  return urlWithExtension.replace(':', '/');\n}\n\n// we use a combination of remoteUrl and working directory\n// to separate multiple storybooks from the same project (e.g. monorepo)\nexport function unhashedProjectId(remoteUrl: string, projectRootPath: string) {\n  return `${normalizeGitUrl(remoteUrl)}${slash(projectRootPath)}`;\n}\n\nlet anonymousProjectId: string;\nlet getProjectSinceResult: Date | undefined;\n\nexport const getAnonymousProjectId = () => {\n  if (anonymousProjectId) {\n    return anonymousProjectId;\n  }\n\n  try {\n    const projectRootPath = relative(getProjectRoot(), process.cwd());\n\n    const result = executeCommandSync({\n      command: 'git',\n      args: ['config', '--get', 'remote.origin.url'],\n      timeout: 1000,\n    });\n\n    anonymousProjectId = oneWayHash(unhashedProjectId(result, projectRootPath));\n  } catch (_) {\n    //\n  }\n\n  return anonymousProjectId;\n};\n\nexport const getProjectSince = () => {\n  try {\n    if (getProjectSinceResult) {\n      return getProjectSinceResult;\n    }\n\n    const dateBuffer = executeCommandSync({\n      command: 'git',\n      args: ['log', '--reverse', '--format=%cd', '--date=iso'],\n      timeout: 1000,\n    });\n\n    const firstLine = String(dateBuffer).trim().split('\\n')[0];\n\n    const date = new Date(firstLine);\n\n    if (Number.isNaN(date.getTime())) {\n      return undefined;\n    }\n\n    getProjectSinceResult = date;\n    return date;\n  } catch (_) {\n    //\n  }\n\n  return undefined;\n};\n"
  },
  {
    "path": "code/core/src/telemetry/detect-agent.test.ts",
    "content": "import { afterEach, describe, expect, it, vi } from 'vitest';\n\nimport { detectAgent } from './detect-agent.ts';\n\ndescribe('detectAgent', () => {\n  afterEach(() => {\n    vi.unstubAllEnvs();\n  });\n\n  it('detects claude via CLAUDECODE', () => {\n    vi.stubEnv('CLAUDECODE', '1');\n    expect(detectAgent()).toEqual({ name: 'claude' });\n  });\n\n  it('detects claude via CLAUDE_CODE', () => {\n    vi.stubEnv('CLAUDE_CODE', '1');\n    expect(detectAgent()).toEqual({ name: 'claude' });\n  });\n\n  it('detects gemini via GEMINI_CLI', () => {\n    vi.stubEnv('GEMINI_CLI', '1');\n    expect(detectAgent()).toEqual({ name: 'gemini' });\n  });\n\n  it('detects codex via CODEX_SANDBOX', () => {\n    vi.stubEnv('CODEX_SANDBOX', '1');\n    expect(detectAgent()).toEqual({ name: 'codex' });\n  });\n\n  it('detects codex via CODEX_THREAD_ID', () => {\n    vi.stubEnv('CODEX_THREAD_ID', '1');\n    expect(detectAgent()).toEqual({ name: 'codex' });\n  });\n\n  it('detects cursor via CURSOR_AGENT', () => {\n    vi.stubEnv('CURSOR_AGENT', '1');\n    expect(detectAgent()).toEqual({ name: 'cursor' });\n  });\n\n  it('detects opencode via OPENCODE', () => {\n    vi.stubEnv('OPENCODE', '1');\n    expect(detectAgent()).toEqual({ name: 'opencode' });\n  });\n\n  it('detects explicit agent via AI_AGENT env var', () => {\n    vi.stubEnv('AI_AGENT', 'copilot');\n    expect(detectAgent()).toEqual({ name: 'copilot' });\n  });\n\n  it('normalizes AI_AGENT to lowercase', () => {\n    vi.stubEnv('AI_AGENT', 'Copilot');\n    expect(detectAgent()).toEqual({ name: 'copilot' });\n  });\n\n  it('AI_AGENT takes precedence over other env vars', () => {\n    vi.stubEnv('AI_AGENT', 'copilot');\n    vi.stubEnv('CLAUDECODE', '1');\n    vi.stubEnv('GEMINI_CLI', '1');\n    expect(detectAgent()).toEqual({ name: 'copilot' });\n  });\n\n  it('returns undefined when there are no signals', () => {\n    expect(detectAgent()).toEqual(undefined);\n  });\n});\n"
  },
  {
    "path": "code/core/src/telemetry/detect-agent.ts",
    "content": "import { detectAgent as stdEnvDetectAgent } from 'std-env';\n\nexport type AgentInfo = {\n  /**\n   * The name of the detected AI coding agent (e.g. `claude`, `gemini`, `codex`, `cursor`). Can be\n   * any value supported by std-env or explicitly set via the `AI_AGENT` environment variable.\n   */\n  name: string;\n};\n\nexport type AgentDetection = AgentInfo | undefined;\n\n/** Detect whether Storybook CLI is likely being invoked by an AI agent, using std-env. */\nexport const detectAgent = (): AgentDetection => {\n  const { name } = stdEnvDetectAgent();\n  if (!name) {\n    return undefined;\n  }\n  return { name };\n};\n"
  },
  {
    "path": "code/core/src/telemetry/error-collector.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { ErrorCollector } from './error-collector.ts';\n\ndescribe('ErrorCollector', () => {\n  it('should collect errors', () => {\n    const error = new Error('Test error');\n    ErrorCollector.addError(error);\n\n    expect(ErrorCollector.getErrors()).toEqual([error]);\n  });\n});\n"
  },
  {
    "path": "code/core/src/telemetry/error-collector.ts",
    "content": "/**\n * Service for collecting errors during Storybook initialization.\n *\n * This singleton class exists to accumulate non-fatal errors that occur during the Storybook's\n * processes. Instead of immediately reporting errors to telemetry (which could interrupt the\n * process), errors are collected here and then batch-reported at the end of initialization via the\n * telemetry system.\n *\n * This allows Storybook to continue e.g. initialization even when non-critical errors occur,\n * ensuring a better user experience while still capturing all errors for telemetry and debugging\n * purposes.\n */\nexport class ErrorCollector {\n  private static instance: ErrorCollector;\n  private errors: unknown[] = [];\n\n  private constructor() {}\n\n  public static getInstance(): ErrorCollector {\n    if (!ErrorCollector.instance) {\n      ErrorCollector.instance = new ErrorCollector();\n    }\n    return ErrorCollector.instance;\n  }\n\n  public static addError(error: unknown) {\n    this.getInstance().errors.push(error);\n  }\n\n  public static getErrors() {\n    return this.getInstance().errors;\n  }\n}\n"
  },
  {
    "path": "code/core/src/telemetry/event-cache.test.ts",
    "content": "import type { MockInstance } from 'vitest';\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { cache } from 'storybook/internal/common';\n\nimport type { CacheEntry } from './event-cache.ts';\nimport { getLastEvents, getPrecedingUpgrade, set } from './event-cache.ts';\nimport type { TelemetryEvent } from './types.ts';\n\nvi.mock('storybook/internal/common', { spy: true });\n\nexpect.addSnapshotSerializer({\n  print: (val: unknown) => JSON.stringify(val, null, 2),\n  test: (val) => typeof val !== 'string',\n});\n\n// Helper to create valid TelemetryEvent objects\nconst createTelemetryEvent = (\n  eventType: TelemetryEvent['eventType'],\n  eventId: string,\n  overrides?: Partial<TelemetryEvent>\n): TelemetryEvent => ({\n  eventType,\n  eventId,\n  sessionId: 'test-session',\n  context: {},\n  payload: {},\n  ...overrides,\n});\n\ndescribe('event-cache', () => {\n  const init: CacheEntry = {\n    body: createTelemetryEvent('init', 'init'),\n    timestamp: 1,\n  };\n  const upgrade: CacheEntry = {\n    body: createTelemetryEvent('upgrade', 'upgrade'),\n    timestamp: 2,\n  };\n  const dev: CacheEntry = {\n    body: createTelemetryEvent('dev', 'dev'),\n    timestamp: 3,\n  };\n  const build: CacheEntry = {\n    body: createTelemetryEvent('build', 'build'),\n    timestamp: 3,\n  };\n  const error: CacheEntry = {\n    body: createTelemetryEvent('build', 'error'),\n    timestamp: 4,\n  };\n  const versionUpdate: CacheEntry = {\n    body: createTelemetryEvent('version-update', 'version-update'),\n    timestamp: 5,\n  };\n\n  describe('data handling', () => {\n    it('errors', async () => {\n      const preceding = await getPrecedingUpgrade({\n        init: {\n          timestamp: 1,\n          body: { ...init.body, error: {} } as TelemetryEvent & { error: unknown },\n        },\n      });\n      expect(preceding).toMatchInlineSnapshot(`\n        {\n          \"timestamp\": 1,\n          \"eventType\": \"init\",\n          \"eventId\": \"init\",\n          \"sessionId\": \"test-session\"\n        }\n      `);\n    });\n\n    it('session IDs', async () => {\n      const preceding = await getPrecedingUpgrade({\n        init: {\n          timestamp: 1,\n          body: { ...init.body, sessionId: '100' },\n        },\n      });\n      expect(preceding).toMatchInlineSnapshot(`\n        {\n          \"timestamp\": 1,\n          \"eventType\": \"init\",\n          \"eventId\": \"init\",\n          \"sessionId\": \"100\"\n        }\n      `);\n    });\n\n    it('extra fields', async () => {\n      const preceding = await getPrecedingUpgrade({\n        init: {\n          timestamp: 1,\n          body: { ...init.body, foobar: 'baz' } as TelemetryEvent & { foobar: string },\n        },\n      });\n      expect(preceding).toMatchInlineSnapshot(`\n        {\n          \"timestamp\": 1,\n          \"eventType\": \"init\",\n          \"eventId\": \"init\",\n          \"sessionId\": \"test-session\"\n        }\n      `);\n    });\n  });\n\n  describe('no intervening dev events', () => {\n    it('no upgrade events', async () => {\n      const preceding = await getPrecedingUpgrade({});\n      expect(preceding).toBeUndefined();\n    });\n\n    it('init', async () => {\n      const preceding = await getPrecedingUpgrade({ init });\n      expect(preceding).toMatchInlineSnapshot(`\n        {\n          \"timestamp\": 1,\n          \"eventType\": \"init\",\n          \"eventId\": \"init\",\n          \"sessionId\": \"test-session\"\n        }\n      `);\n    });\n\n    it('upgrade', async () => {\n      const preceding = await getPrecedingUpgrade({ upgrade });\n      expect(preceding).toMatchInlineSnapshot(`\n        {\n          \"timestamp\": 2,\n          \"eventType\": \"upgrade\",\n          \"eventId\": \"upgrade\",\n          \"sessionId\": \"test-session\"\n        }\n      `);\n    });\n\n    it('both init and upgrade', async () => {\n      const preceding = await getPrecedingUpgrade({ init, upgrade });\n      expect(preceding).toMatchInlineSnapshot(`\n        {\n          \"timestamp\": 2,\n          \"eventType\": \"upgrade\",\n          \"eventId\": \"upgrade\",\n          \"sessionId\": \"test-session\"\n        }\n      `);\n    });\n  });\n\n  describe('intervening dev events', () => {\n    it('no upgrade events', async () => {\n      const preceding = await getPrecedingUpgrade({ dev });\n      expect(preceding).toBeUndefined();\n    });\n\n    it('init', async () => {\n      const preceding = await getPrecedingUpgrade({ init, dev });\n      expect(preceding).toBeUndefined();\n    });\n\n    it('upgrade', async () => {\n      const preceding = await getPrecedingUpgrade({ upgrade, dev });\n      expect(preceding).toBeUndefined();\n    });\n\n    it('init followed by upgrade', async () => {\n      const preceding = await getPrecedingUpgrade({ init, upgrade, dev });\n      expect(preceding).toBeUndefined();\n    });\n\n    it('both init and upgrade with intervening dev', async () => {\n      const secondUpgrade: CacheEntry = {\n        body: createTelemetryEvent('upgrade', 'secondUpgrade'),\n        timestamp: 4,\n      };\n      const preceding = await getPrecedingUpgrade({ init, dev, upgrade: secondUpgrade });\n      expect(preceding).toMatchInlineSnapshot(`\n        {\n          \"timestamp\": 4,\n          \"eventType\": \"upgrade\",\n          \"eventId\": \"secondUpgrade\",\n          \"sessionId\": \"test-session\"\n        }\n      `);\n    });\n\n    it('both init and upgrade with non-intervening dev', async () => {\n      const earlyDev: CacheEntry = {\n        body: createTelemetryEvent('dev', 'earlyDev'),\n        timestamp: -1,\n      };\n      const preceding = await getPrecedingUpgrade({ dev: earlyDev, init, upgrade });\n      expect(preceding).toMatchInlineSnapshot(`\n        {\n          \"timestamp\": 2,\n          \"eventType\": \"upgrade\",\n          \"eventId\": \"upgrade\",\n          \"sessionId\": \"test-session\"\n        }\n      `);\n    });\n  });\n\n  describe('intervening other events', () => {\n    it('build', async () => {\n      const preceding = await getPrecedingUpgrade({ upgrade, build });\n      expect(preceding).toBeUndefined();\n    });\n\n    it('error', async () => {\n      const preceding = await getPrecedingUpgrade({ upgrade, error });\n      expect(preceding).toBeUndefined();\n    });\n\n    it('version-update', async () => {\n      const preceding = await getPrecedingUpgrade({ upgrade, 'version-update': versionUpdate });\n      expect(preceding).toMatchInlineSnapshot(`\n        {\n          \"timestamp\": 2,\n          \"eventType\": \"upgrade\",\n          \"eventId\": \"upgrade\",\n          \"sessionId\": \"test-session\"\n        }\n      `);\n    });\n  });\n\n  describe('race condition prevention', () => {\n    let cacheGetMock: MockInstance;\n    let cacheSetMock: MockInstance;\n\n    beforeEach(() => {\n      vi.clearAllMocks();\n      cacheGetMock = vi.mocked(cache.get);\n      cacheSetMock = vi.mocked(cache.set);\n    });\n\n    it('getLastEvents waits for pending set operations to complete', async () => {\n      const initialData = {\n        init: { timestamp: 1, body: createTelemetryEvent('init', 'init-1') },\n      };\n      const updatedData = {\n        init: { timestamp: 1, body: createTelemetryEvent('init', 'init-1') },\n        upgrade: { timestamp: 2, body: createTelemetryEvent('upgrade', 'upgrade-1') },\n      };\n\n      // Mock cache.get to return initial data first, then updated data\n      cacheGetMock\n        .mockResolvedValueOnce(initialData) // First call in setHelper\n        .mockResolvedValueOnce(updatedData); // Second call in getLastEvents\n\n      // Mock cache.set to resolve immediately\n      cacheSetMock.mockResolvedValue(undefined);\n\n      // Start a set operation (this will be queued and processed)\n      const setPromiseResult = set('upgrade', createTelemetryEvent('upgrade', 'upgrade-1'));\n\n      // Immediately call getLastEvents() - it should wait for set() to complete\n      const getPromise = getLastEvents();\n\n      // Wait for set operation to complete\n      await setPromiseResult;\n\n      // Now getLastEvents should complete and return the updated data\n      const result = await getPromise;\n\n      // Verify that getLastEvents waited for set to complete and got the updated data\n      expect(result).toEqual(updatedData);\n      expect(cacheGetMock).toHaveBeenCalledTimes(2); // Once in setHelper, once in getLastEvents\n      expect(cacheSetMock).toHaveBeenCalledTimes(1);\n    });\n\n    it('queues multiple set operations sequentially', async () => {\n      const initialData = {};\n      const afterFirst = {\n        init: { timestamp: 1, body: createTelemetryEvent('init', 'init-1') },\n      };\n      const afterSecond = {\n        init: { timestamp: 1, body: createTelemetryEvent('init', 'init-1') },\n        upgrade: { timestamp: 2, body: createTelemetryEvent('upgrade', 'upgrade-1') },\n      };\n      const afterThird = {\n        init: { timestamp: 1, body: createTelemetryEvent('init', 'init-1') },\n        upgrade: { timestamp: 2, body: createTelemetryEvent('upgrade', 'upgrade-1') },\n        dev: { timestamp: 3, body: createTelemetryEvent('dev', 'dev-1') },\n      };\n\n      // Mock cache.get to return data in sequence\n      cacheGetMock\n        .mockResolvedValueOnce(initialData) // First set: get initial\n        .mockResolvedValueOnce(afterFirst) // Second set: get after first\n        .mockResolvedValueOnce(afterSecond) // Third set: get after second\n        .mockResolvedValueOnce(afterThird); // getLastEvents: get after third\n\n      // Mock cache.set to resolve immediately\n      cacheSetMock.mockResolvedValue(undefined);\n\n      // Queue multiple set operations\n      const set1 = set('init', createTelemetryEvent('init', 'init-1'));\n      const set2 = set('upgrade', createTelemetryEvent('upgrade', 'upgrade-1'));\n      const set3 = set('dev', createTelemetryEvent('dev', 'dev-1'));\n\n      // Wait for all operations to complete\n      await Promise.all([set1, set2, set3]);\n\n      // Now getLastEvents should return the final state\n      const result = await getLastEvents();\n\n      // Verify all operations were processed sequentially\n      expect(result).toEqual(afterThird);\n      expect(cacheGetMock).toHaveBeenCalledTimes(4); // 3 sets + 1 getLastEvents\n      expect(cacheSetMock).toHaveBeenCalledTimes(3); // One for each set\n    });\n\n    it('handles errors in queued operations', async () => {\n      const initialData = {\n        init: { timestamp: 1, body: createTelemetryEvent('init', 'init-1') },\n      };\n      const afterDev = {\n        init: { timestamp: 1, body: createTelemetryEvent('init', 'init-1') },\n        dev: { timestamp: 3, body: createTelemetryEvent('dev', 'dev-1') },\n      };\n\n      // First operation will fail\n      cacheGetMock.mockResolvedValueOnce(initialData);\n      cacheSetMock.mockRejectedValueOnce(new Error('Cache write failed'));\n\n      // Queue an operation that will fail\n      const failedOperation = set('upgrade', createTelemetryEvent('upgrade', 'upgrade-1'));\n      await expect(failedOperation).rejects.toThrow('Cache write failed');\n\n      // Wait a bit to ensure queue processing completes\n      await new Promise((resolve) => setTimeout(resolve, 10));\n\n      // Verify subsequent operations can still be queued and succeed\n      cacheGetMock.mockResolvedValueOnce(initialData);\n      cacheSetMock.mockResolvedValueOnce(undefined);\n      cacheGetMock.mockResolvedValueOnce(afterDev);\n\n      await expect(set('dev', createTelemetryEvent('dev', 'dev-1'))).resolves.toBeUndefined();\n\n      // Verify the successful operation was processed\n      const result = await getLastEvents();\n      expect(result).toEqual(afterDev);\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/telemetry/event-cache.ts",
    "content": "import { cache } from 'storybook/internal/common';\n\nimport type { EventType, TelemetryEvent } from './types.ts';\n\ninterface UpgradeSummary {\n  timestamp: number;\n  eventType?: EventType;\n  eventId?: string;\n  sessionId?: string;\n}\n\nexport interface CacheEntry {\n  timestamp: number;\n  body: TelemetryEvent;\n}\n\nlet processingPromise: Promise<void> = Promise.resolve();\n\nconst setHelper = async (eventType: EventType, body: TelemetryEvent) => {\n  const lastEvents = (await cache.get('lastEvents')) || {};\n  lastEvents[eventType] = { body, timestamp: Date.now() };\n  await cache.set('lastEvents', lastEvents);\n};\n\nexport const set = (eventType: EventType, body: TelemetryEvent): Promise<void> => {\n  const run = processingPromise.then(async () => {\n    await setHelper(eventType, body);\n  });\n\n  // Keep the chain alive even if this operation rejects, so later callers still queue\n  processingPromise = run.catch(() => {});\n\n  return run;\n};\n\nexport const get = async (eventType: EventType): Promise<CacheEntry | undefined> => {\n  const lastEvents = await getLastEvents();\n  return lastEvents[eventType];\n};\n\nexport const getLastEvents = async (): Promise<Record<EventType, CacheEntry>> => {\n  // Wait for any pending set operations to complete before reading\n  await processingPromise;\n  return (await cache.get('lastEvents')) || {};\n};\n\nconst upgradeFields = (event: CacheEntry): UpgradeSummary => {\n  const { body, timestamp } = event;\n  return {\n    timestamp,\n    eventType: body?.eventType,\n    eventId: body?.eventId,\n    sessionId: body?.sessionId,\n  };\n};\n\nconst UPGRADE_EVENTS: EventType[] = ['init', 'upgrade'];\nconst RUN_EVENTS: EventType[] = ['build', 'dev', 'error'];\n\nconst lastEvent = (lastEvents: Partial<Record<EventType, CacheEntry>>, eventTypes: EventType[]) => {\n  const descendingEvents = eventTypes\n    .map((eventType) => lastEvents?.[eventType])\n    .filter((event): event is CacheEntry => Boolean(event))\n    .sort((a, b) => b.timestamp - a.timestamp);\n  return descendingEvents.length > 0 ? descendingEvents[0] : undefined;\n};\n\nexport const getPrecedingUpgrade = async (\n  events: Partial<Record<EventType, CacheEntry>> | undefined = undefined\n) => {\n  const lastEvents =\n    events || ((await cache.get('lastEvents')) as Partial<Record<EventType, CacheEntry>>) || {};\n  const lastUpgradeEvent = lastEvent(lastEvents, UPGRADE_EVENTS);\n  const lastRunEvent = lastEvent(lastEvents, RUN_EVENTS);\n\n  if (!lastUpgradeEvent) {\n    return undefined;\n  }\n\n  return !lastRunEvent?.timestamp || lastUpgradeEvent.timestamp > lastRunEvent.timestamp\n    ? upgradeFields(lastUpgradeEvent)\n    : undefined;\n};\n"
  },
  {
    "path": "code/core/src/telemetry/exec-command-count-lines.test.ts",
    "content": "import type { Transform } from 'node:stream';\nimport { PassThrough } from 'node:stream';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport { execa as rawExeca } from 'execa';\n\nimport { execCommandCountLines } from './exec-command-count-lines.ts';\n\nvi.mock('execa', { spy: true });\n\nconst execa = vi.mocked(rawExeca);\nbeforeEach(() => {\n  execa.mockReset();\n});\n\ntype ExecaStreamer = typeof Promise & {\n  stdout: Transform;\n  kill: () => void;\n};\n\nfunction createExecaStreamer() {\n  let resolver: () => void;\n  const promiseLike = new Promise<void>((aResolver) => {\n    resolver = aResolver;\n  }) as unknown as ExecaStreamer;\n\n  promiseLike.stdout = new PassThrough();\n  // @ts-expect-error technically it is invalid to use resolver \"before\" it is assigned (but not really)\n  promiseLike.kill = resolver;\n  return promiseLike;\n}\n\ndescribe('execCommandCountLines', () => {\n  it('counts lines, many', async () => {\n    const streamer = createExecaStreamer();\n    execa.mockReturnValue(streamer as unknown as ReturnType<typeof execa>);\n\n    const promise = execCommandCountLines('some command', []);\n\n    streamer.stdout.write('First line\\n');\n    streamer.stdout.write('Second line\\n');\n    streamer.kill();\n\n    expect(await promise).toEqual(2);\n  });\n\n  it('counts lines, one', async () => {\n    const streamer = createExecaStreamer();\n    execa.mockReturnValue(streamer as unknown as ReturnType<typeof execa>);\n\n    const promise = execCommandCountLines('some command', []);\n\n    streamer.stdout.write('First line\\n');\n    streamer.kill();\n\n    expect(await promise).toEqual(1);\n  });\n\n  it('counts lines, none', async () => {\n    const streamer = createExecaStreamer();\n    execa.mockReturnValue(streamer as unknown as ReturnType<typeof execa>);\n\n    const promise = execCommandCountLines('some command', []);\n\n    streamer.kill();\n\n    expect(await promise).toEqual(0);\n  });\n});\n"
  },
  {
    "path": "code/core/src/telemetry/exec-command-count-lines.ts",
    "content": "import { createInterface } from 'node:readline';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport { execa } from 'execa';\n\n/**\n * Execute a command in the local terminal and count the lines in the result\n *\n * @param command The command to execute.\n * @param options Execa options\n * @returns The number of lines the command returned\n */\nexport async function execCommandCountLines(\n  command: string,\n  args: string[],\n  options?: Parameters<typeof execa>[1]\n) {\n  const process = execa(command, args, { buffer: false, ...options });\n  if (!process.stdout) {\n    // eslint-disable-next-line local-rules/no-uncategorized-errors\n    throw new Error('Unexpected missing stdout');\n  }\n\n  let lineCount = 0;\n  const rl = createInterface(process.stdout);\n  rl.on('line', () => {\n    lineCount += 1;\n  });\n\n  // If the process errors, this will throw\n  await process;\n\n  rl.close();\n\n  return lineCount;\n}\n"
  },
  {
    "path": "code/core/src/telemetry/fetch.ts",
    "content": "export const fetch = global.fetch;\n"
  },
  {
    "path": "code/core/src/telemetry/get-application-file-count.test.ts",
    "content": "import { join } from 'node:path';\n\nimport { describe, expect, it } from 'vitest';\n\nimport { getApplicationFilesCountUncached } from './get-application-file-count.ts';\n\nconst mocksDir = join(__dirname, '..', '__mocks__');\n\ndescribe('getApplicationFilesCount', () => {\n  it('should find files with correct names', async () => {\n    const files = await getApplicationFilesCountUncached(mocksDir);\n    expect(files).toMatchInlineSnapshot(`2`);\n  });\n});\n"
  },
  {
    "path": "code/core/src/telemetry/get-application-file-count.ts",
    "content": "import { sep } from 'node:path';\n\nimport { execCommandCountLines } from './exec-command-count-lines.ts';\nimport { runTelemetryOperation } from './run-telemetry-operation.ts';\n\n// We are looking for files with the word \"page\" or \"screen\" somewhere in them with these exts\nconst nameMatches = ['page', 'screen'];\nconst extensions = ['js', 'jsx', 'ts', 'tsx'];\n\nexport const getApplicationFilesCountUncached = async (basePath: string) => {\n  const bothCasesNameMatches = nameMatches.flatMap((match) => [\n    match,\n    [match[0].toUpperCase(), ...match.slice(1)].join(''),\n  ]);\n\n  const globs = bothCasesNameMatches.flatMap((match) =>\n    extensions.map((extension) => `${basePath}${sep}*${match}*.${extension}`)\n  );\n\n  try {\n    return await execCommandCountLines('git', ['ls-files', '--', ...globs]);\n  } catch {\n    return undefined;\n  }\n};\n\nexport const getApplicationFileCount = async (path: string) => {\n  return runTelemetryOperation('applicationFiles', async () =>\n    getApplicationFilesCountUncached(path)\n  );\n};\n"
  },
  {
    "path": "code/core/src/telemetry/get-chromatic-version.test.ts",
    "content": "import { expect, it } from 'vitest';\n\nimport { getChromaticVersionSpecifier } from './get-chromatic-version.ts';\n\nit('works for dependencies', () => {\n  expect(getChromaticVersionSpecifier({ dependencies: { chromatic: '^6.11.4' } })).toBe('^6.11.4');\n});\n\nit('works for scripts', () => {\n  expect(getChromaticVersionSpecifier({ scripts: { chromatic: 'npx chromatic -t abc123' } })).toBe(\n    'latest'\n  );\n});\n\nit('fails otherwise', () => {\n  expect(getChromaticVersionSpecifier({})).toBeUndefined();\n});\n"
  },
  {
    "path": "code/core/src/telemetry/get-chromatic-version.ts",
    "content": "import type { PackageJson } from 'storybook/internal/types';\n\nexport function getChromaticVersionSpecifier(packageJson: PackageJson) {\n  const dependency =\n    packageJson.dependencies?.chromatic ||\n    packageJson.devDependencies?.chromatic ||\n    packageJson.peerDependencies?.chromatic;\n\n  if (dependency) {\n    return dependency;\n  }\n\n  // Chromatic isn't necessarily installed in dependencies, it can be run from npx\n\n  // Chromatic isn't necessarily installed in dependencies, it can be run from npx\n  return packageJson.scripts &&\n    Object.values(packageJson.scripts).find((s) => s?.match(/chromatic/))\n    ? 'latest'\n    : undefined;\n}\n"
  },
  {
    "path": "code/core/src/telemetry/get-framework-info.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { StorybookConfig } from 'storybook/internal/types';\n\nimport { getFrameworkInfo } from './get-framework-info.ts';\n\nvi.mock('storybook/internal/common', () => ({\n  getStorybookInfo: vi.fn(),\n}));\n\ndescribe('getFrameworkInfo', () => {\n  const defaultInfo = {\n    frameworkPackage: '@storybook/react',\n    rendererPackage: '@storybook/react',\n    builderPackage: '@storybook/builder-vite',\n  };\n\n  beforeEach(async () => {\n    const { getStorybookInfo } = await import('storybook/internal/common');\n    vi.mocked(getStorybookInfo).mockResolvedValue(defaultInfo as any);\n  });\n\n  it('returns framework/builder/renderer with empty options when no framework provided', async () => {\n    const result = await getFrameworkInfo({} as StorybookConfig, '/tmp/.storybook');\n    expect(result).toEqual({\n      framework: { name: defaultInfo.frameworkPackage, options: {} },\n      builder: defaultInfo.builderPackage,\n      renderer: defaultInfo.rendererPackage,\n    });\n  });\n\n  it('passes configDir to getStorybookInfo', async () => {\n    const configDir = '/my/project/.storybook';\n    const { getStorybookInfo } = await import('storybook/internal/common');\n    await getFrameworkInfo({} as StorybookConfig, configDir);\n    expect(getStorybookInfo).toHaveBeenCalledWith(configDir);\n  });\n\n  it('returns provided framework options when object is passed', async () => {\n    const options = { foo: 'bar' } as any;\n    const result = await getFrameworkInfo(\n      { framework: { name: '@storybook/react', options } } as any,\n      '/tmp/.storybook'\n    );\n    expect(result.framework.options).toEqual(options);\n  });\n});\n"
  },
  {
    "path": "code/core/src/telemetry/get-framework-info.ts",
    "content": "import { getStorybookInfo } from 'storybook/internal/common';\nimport type { StorybookConfig } from 'storybook/internal/types';\n\nimport { cleanPaths } from './sanitize.ts';\n\nconst cleanAndSanitizePath = (path: string) => {\n  return cleanPaths(path).replace(/.*node_modules[\\\\/]/, '');\n};\n\nexport async function getFrameworkInfo(mainConfig: StorybookConfig, configDir: string) {\n  const { frameworkPackage, rendererPackage, builderPackage } = await getStorybookInfo(configDir);\n\n  const frameworkOptions =\n    typeof mainConfig.framework === 'object' ? mainConfig.framework.options : {};\n\n  return {\n    framework: {\n      name: frameworkPackage ? cleanAndSanitizePath(frameworkPackage) : undefined,\n      options: frameworkOptions,\n    },\n    builder: builderPackage ? cleanAndSanitizePath(builderPackage) : undefined,\n    renderer: rendererPackage ? cleanAndSanitizePath(rendererPackage) : undefined,\n  };\n}\n"
  },
  {
    "path": "code/core/src/telemetry/get-has-router-package.test.ts",
    "content": "import { expect, it } from 'vitest';\n\nimport { getHasRouterPackage } from './get-has-router-package.ts';\n\nit('returns true if there is a routing package in package.json', () => {\n  expect(\n    getHasRouterPackage({\n      dependencies: {\n        react: '^18',\n        'react-dom': '^18',\n        'react-router': '^6',\n      },\n    })\n  ).toBe(true);\n});\n\nit('returns false if there is a routing package in package.json dependencies', () => {\n  expect(\n    getHasRouterPackage({\n      dependencies: {\n        react: '^18',\n        'react-dom': '^18',\n      },\n      devDependencies: {\n        'react-router': '^6',\n      },\n    })\n  ).toBe(false);\n});\n"
  },
  {
    "path": "code/core/src/telemetry/get-has-router-package.ts",
    "content": "import type { PackageJson } from '../types/index.ts';\n\nconst routerPackages = new Set([\n  'react-router',\n  'react-router-dom',\n  'remix',\n  '@tanstack/react-router',\n  'expo-router',\n  '@reach/router',\n  'react-easy-router',\n  '@remix-run/router',\n  'wouter',\n  'wouter-preact',\n  'preact-router',\n  'vue-router',\n  'unplugin-vue-router',\n  '@angular/router',\n  '@solidjs/router',\n\n  // metaframeworks that imply routing\n  'next',\n  'react-scripts',\n  'gatsby',\n  'nuxt',\n  '@sveltejs/kit',\n]);\n\n/**\n * @param packageJson The package JSON of the project\n * @returns Boolean Does this project use a routing package?\n */\nexport function getHasRouterPackage(packageJson: PackageJson) {\n  // NOTE: we just check real dependencies; if it is in dev dependencies, it may just be an example\n  return Object.keys(packageJson?.dependencies ?? {}).some((depName) =>\n    routerPackages.has(depName)\n  );\n}\n"
  },
  {
    "path": "code/core/src/telemetry/get-known-packages.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { PackageJson } from 'storybook/internal/types';\n\nimport { analyzeEcosystemPackages, getSafeVersionSpecifier } from './get-known-packages.ts';\nimport { getActualPackageVersion } from './package-json.ts';\n\nvi.mock(import('./package-json.ts'), { spy: true });\n\ndescribe('get-known-packages', () => {\n  beforeEach(() => {\n    vi.mocked(getActualPackageVersion).mockImplementation(async (pkg: string) => ({\n      name: pkg,\n      version: '1.0.0',\n    }));\n  });\n\n  describe('getSafeVersionSpecifier', () => {\n    it('should return the version specifier with operator', () => {\n      expect(getSafeVersionSpecifier('^1.0.0')).toBe('^1.0.0');\n      expect(getSafeVersionSpecifier('~1.0.0')).toBe('~1.0.0');\n      expect(getSafeVersionSpecifier('1.0.0')).toBe('1.0.0');\n      expect(getSafeVersionSpecifier('1.0.0-beta.0')).toBe('1.0.0'); // prerelease versions are stripped off\n      expect(getSafeVersionSpecifier('latest')).toBe('latest');\n      expect(getSafeVersionSpecifier('*')).toBe('latest');\n      expect(getSafeVersionSpecifier('file:../some/path')).toBe('custom-protocol');\n      expect(getSafeVersionSpecifier(undefined)).toBe(null);\n    });\n  });\n\n  describe('analyzeEcosystemPackages', () => {\n    it('should analyze test packages with actual versions', async () => {\n      const packageJson: PackageJson = {\n        dependencies: {\n          jest: '29.0.0',\n          vitest: '1.0.0',\n          playwright: '1.30.0',\n          '@testing-library/react': '1.0.0',\n        },\n      };\n\n      const result = await analyzeEcosystemPackages(packageJson);\n\n      expect(getActualPackageVersion).toHaveBeenCalled();\n\n      expect(result.testPackages).toEqual({\n        jest: '1.0.0',\n        vitest: '1.0.0',\n        playwright: '1.0.0',\n        '@testing-library/react': '1.0.0',\n      });\n    });\n\n    it('should analyze ecosystem packages in a single packageJson with multiple groups', async () => {\n      const packageJson: PackageJson = {\n        dependencies: {\n          // styling\n          tailwindcss: '3.0.0',\n          'styled-components': '6.0.0',\n          emotion: '11.0.0',\n          // state management\n          redux: '4.0.0',\n          'react-redux': '8.0.0',\n          zustand: '4.0.0',\n          // data fetching\n          axios: '1.0.0',\n          '@tanstack/react-query': '4.0.0',\n          'react-query': '3.0.0',\n          // UI library\n          '@mui/material': '5.0.0',\n          antd: '5.0.0',\n          '@headlessui/react': '1.0.0',\n          // i18n\n          i18next: '22.0.0',\n          'react-i18next': '12.0.0',\n          'next-intl': '2.0.0',\n          // router\n          'react-router-dom': '6.0.0',\n          'react-router': '6.0.0',\n          '@tanstack/react-router': '1.0.0',\n          'expo-router': '2.0.0',\n          wouter: '3.0.0',\n        },\n      };\n\n      const result = await analyzeEcosystemPackages(packageJson);\n      expect(result.stylingPackages).toEqual({\n        emotion: '11.0.0',\n        tailwindcss: '3.0.0',\n        'styled-components': '6.0.0',\n      });\n\n      expect(result.stateManagementPackages).toEqual({\n        redux: '4.0.0',\n        'react-redux': '8.0.0',\n        zustand: '4.0.0',\n      });\n\n      expect(result.dataFetchingPackages).toEqual({\n        axios: '1.0.0',\n        '@tanstack/react-query': '4.0.0',\n        'react-query': '3.0.0',\n      });\n\n      expect(result.uiLibraryPackages).toEqual({\n        '@mui/material': '5.0.0',\n        antd: '5.0.0',\n        '@headlessui/react': '1.0.0',\n      });\n\n      expect(result.i18nPackages).toEqual({\n        i18next: '22.0.0',\n        'react-i18next': '12.0.0',\n        'next-intl': '2.0.0',\n      });\n\n      expect(result.routerPackages).toEqual({\n        'react-router-dom': '6.0.0',\n        'react-router': '6.0.0',\n        '@tanstack/react-router': '1.0.0',\n        'expo-router': '2.0.0',\n        wouter: '3.0.0',\n      });\n    });\n\n    it('should handle packages with scoped names and subpaths', async () => {\n      const packageJson: PackageJson = {\n        dependencies: {\n          '@testing-library/react': '13.0.0',\n          '@testing-library/jest-dom': '5.0.0',\n          '@emotion/react': '11.0.0',\n          '@emotion/styled': '11.0.0',\n        },\n      };\n\n      const result = await analyzeEcosystemPackages(packageJson);\n\n      expect(result.testPackages).toEqual({\n        '@testing-library/react': '1.0.0',\n        '@testing-library/jest-dom': '1.0.0',\n      });\n\n      expect(result.stylingPackages).toEqual({\n        '@emotion/react': '11.0.0',\n        '@emotion/styled': '11.0.0',\n      });\n    });\n\n    it('should handle glob pattern matching for packages', async () => {\n      const packageJson: PackageJson = {\n        dependencies: {\n          '@vitest/ui': '1.0.0',\n          '@vitest/coverage-v8': '1.0.0',\n          vitest: '1.0.0',\n          playwright: '1.30.0',\n          'some-other-package': '1.0.0',\n        },\n      };\n\n      const result = await analyzeEcosystemPackages(packageJson);\n\n      expect(result.testPackages).toEqual({\n        '@vitest/ui': '1.0.0',\n        '@vitest/coverage-v8': '1.0.0',\n        vitest: '1.0.0',\n        playwright: '1.0.0',\n      });\n    });\n\n    it('should handle special version specifiers', async () => {\n      vi.mocked(getActualPackageVersion).mockImplementation(async (pkg: string) => ({\n        name: pkg,\n        version: 'file:../some/path',\n      }));\n\n      const packageJson: PackageJson = {\n        dependencies: {\n          '@testing-library/react': 'file:../some/path',\n          '@emotion/react': 'latest',\n          'styled-components': '*',\n          tailwindcss: 'workspace:*',\n        },\n      };\n\n      const result = await analyzeEcosystemPackages(packageJson);\n\n      expect(result.testPackages).toEqual({\n        '@testing-library/react': 'custom-protocol',\n      });\n\n      expect(result.stylingPackages).toEqual({\n        '@emotion/react': 'latest',\n        'styled-components': 'latest',\n        tailwindcss: 'custom-protocol',\n      });\n    });\n\n    it('should return empty object when no matching packages are found', async () => {\n      const packageJson: PackageJson = {\n        dependencies: {\n          'some-random-package': '1.0.0',\n          'another-package': '2.0.0',\n        },\n      };\n\n      const result = await analyzeEcosystemPackages(packageJson);\n\n      expect(result).toEqual({});\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/telemetry/get-known-packages.ts",
    "content": "import type { PackageJson } from 'storybook/internal/types';\n\nimport semver from 'semver';\n\nimport {\n  DATA_FETCHING_PACKAGES,\n  I18N_PACKAGES,\n  ROUTER_PACKAGES,\n  STATE_MANAGEMENT_PACKAGES,\n  STYLING_PACKAGES,\n  TEST_PACKAGES,\n  UI_LIBRARY_PACKAGES,\n  matchesPackagePattern,\n} from '../shared/utils/ecosystem-identifier.ts';\nimport { getActualPackageVersion } from './package-json.ts';\n\ntype PackageGroupResult = Record<string, string | null | undefined>;\n\nexport type KnownPackagesList = {\n  testPackages?: PackageGroupResult;\n  stylingPackages?: PackageGroupResult;\n  stateManagementPackages?: PackageGroupResult;\n  dataFetchingPackages?: PackageGroupResult;\n  uiLibraryPackages?: PackageGroupResult;\n  i18nPackages?: PackageGroupResult;\n  routerPackages?: PackageGroupResult;\n};\n\nexport function getSafeVersionSpecifier(version?: string): string | null {\n  if (!version) {\n    return null;\n  }\n\n  if (version === '*') {\n    return 'latest';\n  }\n\n  // e.g. file, patch, workspace, git and other protocols\n  if (version.includes(':')) {\n    return 'custom-protocol';\n  }\n\n  // common dist-tags\n  if (\n    [\n      'latest',\n      'next',\n      'canary',\n      'beta',\n      'alpha',\n      'rc',\n      'nightly',\n      'dev',\n      'stable',\n      'experimental',\n      'insiders',\n      'preview',\n    ].includes(version)\n  ) {\n    return version;\n  }\n\n  try {\n    const operator = version.trim().match(/^[~^]/)?.[0] ?? '';\n    const coerced = semver.coerce(version);\n    return coerced ? `${operator}${coerced.version}` : null;\n  } catch {\n    return 'could-not-be-parsed-by-semver';\n  }\n}\n\nexport async function analyzeEcosystemPackages(\n  packageJson: PackageJson\n): Promise<KnownPackagesList> {\n  const allDependencies = {\n    ...packageJson?.dependencies,\n    ...packageJson?.devDependencies,\n    ...packageJson?.peerDependencies,\n  };\n\n  const depNames = Object.keys(allDependencies);\n\n  const pickMatches = (packages: readonly string[]) =>\n    depNames.filter((dep) => matchesPackagePattern(dep, packages));\n\n  const pickDepsObject = (packages: readonly string[]) => {\n    const result = Object.fromEntries(\n      pickMatches(packages).map((dep) => {\n        const rawVersion = allDependencies[dep];\n        const version = getSafeVersionSpecifier(rawVersion);\n        return [dep, version];\n      })\n    );\n    return Object.keys(result).length === 0 ? null : result;\n  };\n\n  const testPackagesResult = Object.fromEntries(\n    await Promise.all(\n      depNames\n        .filter((dep) => matchesPackagePattern(dep, TEST_PACKAGES))\n        .map(async (dep) => {\n          const resolved = (await getActualPackageVersion(dep))?.version ?? allDependencies[dep];\n\n          const version = getSafeVersionSpecifier(resolved);\n          return [dep, version];\n        })\n    )\n  );\n  const testPackages = Object.keys(testPackagesResult).length === 0 ? null : testPackagesResult;\n\n  const stylingPackages = pickDepsObject(STYLING_PACKAGES);\n  const stateManagementPackages = pickDepsObject(STATE_MANAGEMENT_PACKAGES);\n  const dataFetchingPackages = pickDepsObject(DATA_FETCHING_PACKAGES);\n  const uiLibraryPackages = pickDepsObject(UI_LIBRARY_PACKAGES);\n  const i18nPackages = pickDepsObject(I18N_PACKAGES);\n  const routerPackages = pickDepsObject(ROUTER_PACKAGES);\n\n  return {\n    ...(testPackages && { testPackages: testPackages }),\n    ...(stylingPackages && { stylingPackages: stylingPackages }),\n    ...(stateManagementPackages && {\n      stateManagementPackages: stateManagementPackages,\n    }),\n    ...(dataFetchingPackages && { dataFetchingPackages: dataFetchingPackages }),\n    ...(uiLibraryPackages && { uiLibraryPackages: uiLibraryPackages }),\n    ...(i18nPackages && { i18nPackages: i18nPackages }),\n    ...(routerPackages && { routerPackages: routerPackages }),\n  };\n}\n"
  },
  {
    "path": "code/core/src/telemetry/get-monorepo-type.test.ts",
    "content": "import * as fs from 'node:fs';\nimport { join } from 'node:path';\n\nimport { describe, expect, it, vi } from 'vitest';\n\nimport { getMonorepoType, monorepoConfigs } from './get-monorepo-type.ts';\n\nvi.mock('node:fs', async () => import('../../../__mocks__/fs.ts'));\n\nvi.mock('storybook/internal/common', async (importOriginal) => {\n  return {\n    ...(await importOriginal<typeof import('storybook/internal/common')>()),\n    getProjectRoot: () => 'root',\n  };\n});\n\nconst checkMonorepoType = ({ monorepoConfigFile, isYarnWorkspace = false }: any) => {\n  const mockFiles = {\n    [join('root', 'package.json')]: isYarnWorkspace ? '{ \"workspaces\": [] }' : '{}',\n  };\n\n  if (monorepoConfigFile) {\n    mockFiles[join('root', monorepoConfigFile)] = '{}';\n  }\n\n  vi.mocked<typeof import('../../../__mocks__/fs')>(fs as any).__setMockFiles(mockFiles);\n\n  return getMonorepoType();\n};\n\ndescribe('getMonorepoType', () => {\n  describe('Monorepos from json files', () => {\n    it.each(Object.entries(monorepoConfigs))(\n      'should detect %p from %s file',\n      (monorepoName, monorepoConfigFile) => {\n        expect(checkMonorepoType({ monorepoConfigFile })).toEqual(monorepoName);\n      }\n    );\n  });\n\n  describe('Yarn|NPM workspaces', () => {\n    it('should detect Workspaces from package.json', () => {\n      expect(checkMonorepoType({ monorepoConfigFile: undefined, isYarnWorkspace: true })).toEqual(\n        'Workspaces'\n      );\n    });\n  });\n\n  describe('Non-monorepos', () => {\n    it('should return undefined', () => {\n      expect(checkMonorepoType({ monorepoConfigFile: undefined, isYarnWorkspace: false })).toEqual(\n        undefined\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/telemetry/get-monorepo-type.ts",
    "content": "import { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { getProjectRoot } from 'storybook/internal/common';\nimport type { PackageJson } from 'storybook/internal/types';\n\nexport const monorepoConfigs = {\n  Nx: 'nx.json',\n  Turborepo: 'turbo.json',\n  Lerna: 'lerna.json',\n  Rush: 'rush.json',\n  Lage: 'lage.config.json',\n} as const;\n\nexport type MonorepoType = keyof typeof monorepoConfigs | 'Workspaces' | undefined;\n\nexport const getMonorepoType = (): MonorepoType => {\n  const keys = Object.keys(monorepoConfigs) as (keyof typeof monorepoConfigs)[];\n  const monorepoType: MonorepoType = keys.find((monorepo) => {\n    const configFile = join(getProjectRoot(), monorepoConfigs[monorepo]);\n    return existsSync(configFile);\n  }) as MonorepoType;\n\n  if (monorepoType) {\n    return monorepoType;\n  }\n\n  if (!existsSync(join(getProjectRoot(), 'package.json'))) {\n    return undefined;\n  }\n\n  const packageJson = JSON.parse(\n    readFileSync(join(getProjectRoot(), 'package.json'), { encoding: 'utf8' })\n  ) as PackageJson;\n\n  if (packageJson?.workspaces) {\n    return 'Workspaces';\n  }\n\n  return undefined;\n};\n"
  },
  {
    "path": "code/core/src/telemetry/get-package-manager-info.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport { execaCommand as rawExecaCommand } from 'execa';\nimport { detect as rawDetect } from 'package-manager-detector';\n\nimport { getPackageManagerInfo } from './get-package-manager-info.ts';\n\nvi.mock('execa', async () => {\n  return {\n    execaCommand: vi.fn(),\n  };\n});\n\nvi.mock('package-manager-detector', async () => {\n  return {\n    detect: vi.fn(),\n  };\n});\n\nvi.mock('../common', async () => {\n  return {\n    getProjectRoot: () => '/mock/project/root',\n  };\n});\n\nconst execaCommand = vi.mocked(rawExecaCommand);\nconst detect = vi.mocked(rawDetect);\n\nbeforeEach(() => {\n  execaCommand.mockReset();\n  detect.mockReset();\n});\n\ndescribe('getPackageManagerInfo', () => {\n  describe('when no package manager is detected', () => {\n    it('should return undefined', async () => {\n      detect.mockResolvedValue(null);\n\n      const result = await getPackageManagerInfo();\n\n      expect(result).toBeUndefined();\n    });\n  });\n\n  describe('when yarn is detected', () => {\n    beforeEach(() => {\n      detect.mockResolvedValue({\n        name: 'yarn',\n        version: '3.6.0',\n        agent: 'yarn@berry',\n      });\n    });\n\n    it('should return yarn info with default nodeLinker when command fails', async () => {\n      execaCommand.mockRejectedValue(new Error('Command failed'));\n\n      const result = await getPackageManagerInfo();\n\n      expect(result).toEqual({\n        type: 'yarn',\n        version: '3.6.0',\n        agent: 'yarn@berry',\n        nodeLinker: 'node_modules',\n      });\n    });\n\n    it('should return yarn info with node_modules nodeLinker', async () => {\n      execaCommand.mockResolvedValue({\n        stdout: 'node_modules\\n',\n      } as any);\n\n      const result = await getPackageManagerInfo();\n\n      expect(result).toEqual({\n        type: 'yarn',\n        version: '3.6.0',\n        agent: 'yarn@berry',\n        nodeLinker: 'node_modules',\n      });\n    });\n\n    it('should return yarn info with pnp nodeLinker', async () => {\n      execaCommand.mockResolvedValue({\n        stdout: 'pnp\\n',\n      } as any);\n\n      const result = await getPackageManagerInfo();\n\n      expect(result).toEqual({\n        type: 'yarn',\n        version: '3.6.0',\n        agent: 'yarn@berry',\n        nodeLinker: 'pnp',\n      });\n    });\n  });\n\n  describe('when pnpm is detected', () => {\n    beforeEach(() => {\n      detect.mockResolvedValue({\n        name: 'pnpm',\n        version: '8.15.0',\n        agent: 'pnpm',\n      });\n    });\n\n    it('should return pnpm info with default isolated nodeLinker when command fails', async () => {\n      execaCommand.mockRejectedValue(new Error('Command failed'));\n\n      const result = await getPackageManagerInfo();\n\n      expect(result).toEqual({\n        type: 'pnpm',\n        version: '8.15.0',\n        agent: 'pnpm',\n        nodeLinker: 'node_modules',\n      });\n    });\n\n    it('should return pnpm info with isolated nodeLinker', async () => {\n      execaCommand.mockResolvedValue({\n        stdout: 'isolated\\n',\n      } as any);\n\n      const result = await getPackageManagerInfo();\n\n      expect(result).toEqual({\n        type: 'pnpm',\n        version: '8.15.0',\n        agent: 'pnpm',\n        nodeLinker: 'isolated',\n      });\n    });\n  });\n\n  describe('when npm is detected', () => {\n    beforeEach(() => {\n      detect.mockResolvedValue({\n        name: 'npm',\n        version: '9.8.0',\n        agent: 'npm',\n      });\n    });\n\n    it('should return npm info with default node_modules nodeLinker', async () => {\n      const result = await getPackageManagerInfo();\n\n      expect(result).toEqual({\n        type: 'npm',\n        version: '9.8.0',\n        agent: 'npm',\n        nodeLinker: 'node_modules',\n      });\n      expect(execaCommand).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('when bun is detected', () => {\n    beforeEach(() => {\n      detect.mockResolvedValue({\n        name: 'bun',\n        version: '1.0.0',\n        agent: 'bun',\n      });\n    });\n\n    it('should return bun info with default node_modules nodeLinker', async () => {\n      const result = await getPackageManagerInfo();\n\n      expect(result).toEqual({\n        type: 'bun',\n        version: '1.0.0',\n        agent: 'bun',\n        nodeLinker: 'node_modules',\n      });\n      expect(execaCommand).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('error handling', () => {\n    beforeEach(() => {\n      detect.mockResolvedValue({\n        name: 'yarn',\n        version: '3.6.0',\n        agent: 'yarn',\n      });\n    });\n\n    it('should handle yarn command errors gracefully', async () => {\n      execaCommand.mockRejectedValue(new Error('yarn command not found'));\n\n      const result = await getPackageManagerInfo();\n\n      expect(result).toEqual({\n        type: 'yarn',\n        version: '3.6.0',\n        agent: 'yarn',\n        nodeLinker: 'node_modules',\n      });\n    });\n\n    it('should handle pnpm command errors gracefully', async () => {\n      detect.mockResolvedValue({\n        name: 'pnpm',\n        version: '8.15.0',\n        agent: 'pnpm',\n      });\n      execaCommand.mockRejectedValue(new Error('pnpm command not found'));\n\n      const result = await getPackageManagerInfo();\n\n      expect(result).toEqual({\n        type: 'pnpm',\n        version: '8.15.0',\n        agent: 'pnpm',\n        nodeLinker: 'node_modules',\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/telemetry/get-package-manager-info.ts",
    "content": "// eslint-disable-next-line depend/ban-dependencies\nimport { execaCommand } from 'execa';\nimport { detect } from 'package-manager-detector';\n\nimport { getProjectRoot } from '../common/index.ts';\n\nexport const getPackageManagerInfo = async () => {\n  const packageManagerType = await detect({ cwd: getProjectRoot() });\n\n  if (!packageManagerType) {\n    return undefined;\n  }\n\n  // TODO: Evaluate if this is correct after removing pnp compatibility code in SB11\n  let nodeLinker: 'node_modules' | 'pnp' | 'pnpm' | 'isolated' | 'hoisted' = 'node_modules';\n\n  if (packageManagerType.name === 'yarn') {\n    try {\n      const { stdout } = await execaCommand('yarn config get nodeLinker', {\n        cwd: getProjectRoot(),\n      });\n      nodeLinker = stdout.trim() as 'node_modules' | 'pnp' | 'pnpm';\n    } catch (e) {}\n  }\n\n  if (packageManagerType.name === 'pnpm') {\n    try {\n      const { stdout } = await execaCommand('pnpm config get nodeLinker', {\n        cwd: getProjectRoot(),\n      });\n      nodeLinker = (stdout.trim() as 'isolated' | 'hoisted' | 'pnpm') ?? 'isolated';\n    } catch (e) {}\n  }\n\n  return {\n    type: packageManagerType.name,\n    version: packageManagerType.version,\n    agent: packageManagerType.agent,\n    nodeLinker,\n  };\n};\n"
  },
  {
    "path": "code/core/src/telemetry/get-portable-stories-usage.test.ts",
    "content": "import { join } from 'node:path';\n\nimport { describe, expect, it } from 'vitest';\n\nimport { getPortableStoriesFileCountUncached } from './get-portable-stories-usage.ts';\n\nconst mocksDir = join(__dirname, '..', '__mocks__');\n\ndescribe('getPortableStoriesFileCountUncached', () => {\n  it('should ignores node_modules, non-source files', async () => {\n    const usage = await getPortableStoriesFileCountUncached(mocksDir);\n    // you can verify with: `git grep -l composeStor | wc -l`\n    expect(usage).toMatchInlineSnapshot(`2`);\n  });\n});\n"
  },
  {
    "path": "code/core/src/telemetry/get-portable-stories-usage.ts",
    "content": "import { execCommandCountLines } from './exec-command-count-lines.ts';\nimport { runTelemetryOperation } from './run-telemetry-operation.ts';\n\nexport const getPortableStoriesFileCountUncached = async (path?: string) => {\n  try {\n    return await execCommandCountLines('git', [\n      'grep',\n      '-l',\n      'composeStor',\n      ...(path ? ['--', path] : []),\n    ]);\n  } catch (err: any) {\n    // exit code 1 if no matches are found\n    return err.exitCode === 1 ? 0 : undefined;\n  }\n};\n\nexport const getPortableStoriesFileCount = async (path?: string) => {\n  return runTelemetryOperation('portableStories', async () =>\n    getPortableStoriesFileCountUncached(path)\n  );\n};\n"
  },
  {
    "path": "code/core/src/telemetry/index.ts",
    "content": "import { logger } from 'storybook/internal/node-logger';\n\nimport { notify } from './notify.ts';\nimport { sanitizeError } from './sanitize.ts';\nimport { getStorybookMetadata } from './storybook-metadata.ts';\nimport { sendTelemetry } from './telemetry.ts';\nimport type { EventType, Options, Payload, TelemetryData } from './types.ts';\n\nexport { oneWayHash } from './one-way-hash.ts';\n\nexport * from './storybook-metadata.ts';\n\nexport * from './types.ts';\n\nexport * from './sanitize.ts';\n\nexport * from './error-collector.ts';\n\nexport { getPrecedingUpgrade, getLastEvents, type CacheEntry } from './event-cache.ts';\n\nexport { getSessionId } from './session-id.ts';\n\nexport { addToGlobalContext } from './telemetry.ts';\n\n/** Is this story part of the CLI generated examples, including user-created stories in those files */\nexport const isExampleStoryId = (storyId: string) =>\n  storyId.startsWith('example-button--') ||\n  storyId.startsWith('example-header--') ||\n  storyId.startsWith('example-page--');\n\nexport const telemetry = async (\n  eventType: EventType,\n  payload: Payload = {},\n  options: Partial<Options> = {}\n) => {\n  // Don't notify on boot since it can lead to double notification in `sb init`.\n  // The notification will happen when the actual command runs.\n  if (eventType !== 'boot' && options.notify !== false) {\n    await notify();\n  }\n  const telemetryData: TelemetryData = {\n    eventType,\n    payload,\n  };\n  try {\n    if (!options?.stripMetadata) {\n      telemetryData.metadata = await getStorybookMetadata(options?.configDir);\n    }\n  } catch (error: any) {\n    payload.metadataErrorMessage = sanitizeError(error).message;\n\n    if (options?.enableCrashReports) {\n      payload.metadataError = sanitizeError(error);\n    }\n  } finally {\n    const { error } = payload;\n    // make sure to anonymise possible paths from error messages\n\n    // make sure to anonymise possible paths from error messages\n    if (error) {\n      payload.error = sanitizeError(error);\n    }\n\n    if (!payload.error || options?.enableCrashReports) {\n      if (process.env?.STORYBOOK_TELEMETRY_DEBUG) {\n        logger.info('[telemetry]');\n        logger.info(JSON.stringify(telemetryData, null, 2));\n      }\n      await sendTelemetry(telemetryData, options);\n    }\n  }\n};\n"
  },
  {
    "path": "code/core/src/telemetry/notify.ts",
    "content": "import { cache } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { dedent } from 'ts-dedent';\n\nconst TELEMETRY_KEY_NOTIFY_DATE = 'telemetry-notification-date';\n\nlet called = false;\n\n/**\n * The end-user has already been notified about our telemetry integration. We don't need to\n * constantly annoy them about it. We will re-inform users about the telemetry if significant\n * changes are ever made.\n */\nexport const notify = async () => {\n  if (!called) {\n    called = true;\n\n    if (!(await cache.get(TELEMETRY_KEY_NOTIFY_DATE, null))) {\n      cache.set(TELEMETRY_KEY_NOTIFY_DATE, Date.now());\n      logger.info(\n        \"Storybook collects completely anonymous usage telemetry. We use it to shape Storybook's roadmap and prioritize features. You can learn more, including how to opt out, at https://storybook.js.org/telemetry\"\n      );\n    }\n  }\n};\n"
  },
  {
    "path": "code/core/src/telemetry/one-way-hash.ts",
    "content": "import type { BinaryLike } from 'crypto';\nimport { createHash } from 'crypto';\n\nexport const oneWayHash = (payload: BinaryLike): string => {\n  const hash = createHash('sha256');\n\n  // Always prepend the payload value with salt. This ensures the hash is truly\n  // one-way.\n  hash.update('storybook-telemetry-salt');\n\n  // Update is an append operation, not a replacement. The salt from the prior\n  // update is still present!\n  hash.update(payload);\n  return hash.digest('hex');\n};\n"
  },
  {
    "path": "code/core/src/telemetry/package-json.ts",
    "content": "import { fileURLToPath, pathToFileURL } from 'node:url';\n\nimport * as pkg from 'empathic/package';\nimport type { PackageJson } from 'type-fest';\n\nimport type { Dependency } from './types.ts';\n\nexport const getActualPackageVersions = async (packages: Record<string, Partial<Dependency>>) => {\n  const packageNames = Object.keys(packages);\n  return Promise.all(packageNames.map(getActualPackageVersion));\n};\n\nexport const getActualPackageVersion = async (packageName: string) => {\n  try {\n    const packageJson = await getActualPackageJson(packageName);\n    return {\n      name: packageJson?.name || packageName,\n      version: packageJson?.version || null,\n    };\n  } catch (err) {\n    return {\n      name: packageName,\n      version: null,\n    };\n  }\n};\n\nexport const getActualPackageJson = async (\n  packageName: string\n): Promise<PackageJson | undefined> => {\n  try {\n    let resolvedPackageJsonPath = pkg.up({\n      cwd: fileURLToPath(import.meta.resolve(packageName, process.cwd())),\n    });\n    if (!resolvedPackageJsonPath) {\n      resolvedPackageJsonPath = import.meta.resolve(`${packageName}/package.json`, process.cwd());\n    }\n\n    const { default: packageJson } = await import(pathToFileURL(resolvedPackageJsonPath).href, {\n      with: { type: 'json' },\n    });\n    return packageJson;\n  } catch (err) {\n    return undefined;\n  }\n};\n"
  },
  {
    "path": "code/core/src/telemetry/run-telemetry-operation.ts",
    "content": "import { createFileSystemCache, resolvePathInStorybookCache } from '../common/index.ts';\n\nconst cache = createFileSystemCache({\n  basePath: resolvePathInStorybookCache('telemetry'),\n  ns: 'storybook',\n  ttl: 24 * 60 * 60 * 1000, // 24h\n});\n\n/**\n * Run an (expensive) operation, caching the result in a FS cache for 24 hours.\n *\n * NOTE: if the operation returns `undefined` the value will not be cached. Use this to indicate\n * that the operation failed.\n */\nexport const runTelemetryOperation = async <T>(cacheKey: string, operation: () => Promise<T>) => {\n  let cached = await cache.get<T>(cacheKey);\n  if (cached === undefined) {\n    cached = await operation();\n    // Undefined indicates an error, setting isn't really valuable.\n    if (cached !== undefined) {\n      await cache.set(cacheKey, cached);\n    }\n  }\n  return cached;\n};\n"
  },
  {
    "path": "code/core/src/telemetry/sanitize.test.ts",
    "content": "import os from 'node:os';\n\nimport { afterEach, describe, expect, it, vi } from 'vitest';\n\nimport { cleanPaths, sanitizeError } from './sanitize.ts';\n\nafterEach(() => {\n  vi.restoreAllMocks();\n});\n\ndescribe(`Errors Helpers`, () => {\n  describe(`sanitizeError`, () => {\n    it(`Sanitizes ansi codes in error`, () => {\n      const errorMessage = `\\u001B[4mStorybook\\u001B[0m`;\n      let e: any;\n      try {\n        throw new Error(errorMessage);\n      } catch (error) {\n        e = error;\n      }\n\n      const sanitizedError = sanitizeError(e);\n\n      expect(sanitizedError.message).toEqual('Storybook');\n      expect(sanitizedError.stack).toContain('Error: Storybook');\n    });\n\n    it(`Sanitizes current path from error stacktraces`, () => {\n      const errorMessage = `Test error message`;\n      const mockCwd = `/Users/testuser/project`;\n      const mockCwdSpy = vi.spyOn(process, `cwd`).mockImplementation(() => mockCwd);\n\n      const e = {\n        message: errorMessage,\n        stack: `\n          Error: Test error message\n            at Object.<anonymous> (${mockCwd}/src/index.js:1:32)\n            at Object.<anonymous> (${mockCwd}/node_modules/some-lib/index.js:1:69)\n            at Module._compile (internal/modules/cjs/loader.js:736:30)\n        `,\n        name: 'Error',\n      };\n\n      expect(e).toBeDefined();\n      expect(e.message).toEqual(errorMessage);\n      expect(e.stack).toEqual(expect.stringContaining(mockCwd));\n\n      const sanitizedError = sanitizeError(e as Error, '/');\n\n      expect(sanitizedError.message).toEqual(errorMessage);\n      expect(sanitizedError.stack).toEqual(expect.not.stringContaining(mockCwd));\n      expect(sanitizedError.stack).toEqual(expect.stringContaining('$SNIP'));\n\n      mockCwdSpy.mockRestore();\n    });\n\n    it(`Sanitizes a section of the current path from error stacktrace`, () => {\n      const errorMessage = `this is a test`;\n\n      const e = {\n        message: errorMessage,\n        stack: `\n        Error: this is an error\n          at Object.<anonymous> (/Users/username/Code/storybook-app/storybook-config.js:1:32)\n          at Object.<anonymous> (/Users/username/Code/storybook-app/node_module/storybook-telemetry/blah.js:1:69)\n          at Object.<anonymous> (/Users/username/Code/storybook-app/node_module/fake-path/index.js:1:41)\n          at Object.<anonymous> (/Users/username/.fake-path/index.js:1:69)\n          at Module._compile (internal/modules/cjs/loader.js:736:30)\n          at Object.Module._extensions..js (internal/modules/cjs/loader.js:747:10)\n          at Module.load (internal/modules/cjs/loader.js:628:32)\n          at tryModuleLoad (internal/modules/cjs/loader.js:568:12)\n          at Function.Module._load (internal/modules/cjs/loader.js:560:3)\n          at Function.Module.runMain (internal/modules/cjs/loader.js:801:12)\n          at executeUserCode (internal/bootstrap/node.js:526:15)\n          at startMainThreadExecution (internal/bootstrap/node.js:439:3)\n        `,\n      };\n\n      expect(e).toBeDefined();\n      expect(e.message).toEqual(errorMessage);\n      expect(e.stack).toBeDefined();\n\n      const mockCwd = vi\n        .spyOn(process, `cwd`)\n        .mockImplementation(() => `/Users/username/Code/storybook-app`);\n\n      expect(e.stack).toEqual(expect.stringContaining(`username`));\n\n      const sanitizedError = sanitizeError(e as Error, `/`);\n\n      expect(sanitizedError.message.includes(errorMessage)).toBe(true);\n      expect(sanitizedError.stack).toEqual(expect.not.stringContaining(`username`));\n      const result = sanitizedError.stack.match(/\\$SNIP/g) as Array<string>;\n      expect(result.length).toBe(4);\n\n      mockCwd.mockRestore();\n    });\n  });\n  describe(`cleanPaths`, () => {\n    it.each([`storybook-config.js`, `src/pages/index.js`])(\n      `should clean path on unix: %s`,\n      (filePath) => {\n        const cwdMockPath = `/Users/username/storybook-app`;\n        const mockCwd = vi.spyOn(process, `cwd`).mockImplementation(() => cwdMockPath);\n\n        const errorMessage = `Path 1 /Users/Username/storybook-app/${filePath} Path 2 /Users/username/storybook-app/${filePath}`;\n\n        expect(cleanPaths(errorMessage, `/`)).toBe(\n          `Path 1 $SNIP/${filePath} Path 2 $SNIP/${filePath}`\n        );\n        mockCwd.mockRestore();\n      }\n    );\n\n    it.each([`storybook-config.js`, `src\\\\pages\\\\index.js`])(\n      `should clean path on windows: %s`,\n      (filePath) => {\n        const cwdMockPath = `C:\\\\Users\\\\username\\\\storybook-app`;\n\n        const mockCwd = vi.spyOn(process, `cwd`).mockImplementationOnce(() => cwdMockPath);\n\n        const errorMessage = `Path 1 C:\\\\Users\\\\username\\\\storybook-app\\\\${filePath} Path 2 c:\\\\Users\\\\username\\\\storybook-app\\\\${filePath}`;\n        expect(cleanPaths(errorMessage, `\\\\`)).toBe(\n          `Path 1 $SNIP\\\\${filePath} Path 2 $SNIP\\\\${filePath}`\n        );\n        mockCwd.mockRestore();\n      }\n    );\n\n    describe(`package manager caches and home paths`, () => {\n      it(`should sanitize pnpm store under a different cwd`, () => {\n        const input = `/home/sandbox/project/node_modules/.pnpm/@storybook+addon-docs@10.0.2_@types+react@19.2.2_esbuild@0.25.10_rollup@4.31.0_storyboo_7cb8a1f4d4ca81d0abdb0f0cfacb0423/node_modules/@storybook/addon-docs`;\n        const separator = `/`;\n        const homedir = `/home/sandbox`;\n        const cwd = `/var/build`;\n        const retainedSegment = `@storybook/addon-docs`;\n        const forbidden = `sandbox`;\n\n        vi.spyOn(process, `cwd`).mockImplementation(() => cwd);\n        vi.spyOn(os, `homedir`).mockImplementation(() => homedir);\n\n        const sanitized = cleanPaths(input, separator);\n        expect(sanitized).toMatchInlineSnapshot(\n          `\"$SNIP/project/node_modules/.pnpm/@storybook+addon-docs@10.0.2_@types+react@19.2.2_esbuild@0.25.10_rollup@4.31.0_storyboo_7cb8a1f4d4ca81d0abdb0f0cfacb0423/node_modules/@storybook/addon-docs\"`\n        );\n\n        expect(sanitized).toContain(`$SNIP`);\n        expect(sanitized).toContain(retainedSegment);\n        expect(sanitized.toLowerCase()).not.toContain(forbidden.toLowerCase());\n        expect(sanitized.toLowerCase()).not.toContain(homedir.toLowerCase());\n      });\n\n      it(`should sanitize yarn berry cache in home`, () => {\n        const input = `/home/foo/.yarn/berry/cache/@storybook-addon-interactions-npm-7.6.1-9e0ac1ff40-10.zip/node_modules/@storybook/addon-interactions`;\n        const separator = `/`;\n        const homedir = `/home/foo`;\n        const cwd = `/workspace`;\n        const retainedSegment = `@storybook/addon-interactions`;\n        const forbidden = `foo`;\n\n        vi.spyOn(process, `cwd`).mockImplementation(() => cwd);\n        vi.spyOn(os, `homedir`).mockImplementation(() => homedir);\n\n        const sanitized = cleanPaths(input, separator);\n\n        expect(sanitized).toMatchInlineSnapshot(\n          `\"$SNIP/.yarn/berry/cache/@storybook-addon-interactions-npm-7.6.1-9e0ac1ff40-10.zip/node_modules/@storybook/addon-interactions\"`\n        );\n        expect(sanitized).toContain(`$SNIP`);\n        expect(sanitized).toContain(retainedSegment);\n        expect(sanitized.toLowerCase()).not.toContain(forbidden.toLowerCase());\n        expect(sanitized.toLowerCase()).not.toContain(homedir.toLowerCase());\n      });\n\n      it(`should sanitize node_modules path outside current cwd`, () => {\n        const input = `/Users/foo/project/node_modules/@storybook/addon-links/dist/cjs/index.js`;\n        const separator = `/`;\n        const homedir = `/Users/foo`;\n        const cwd = `/tmp/storybook`;\n        const retainedSegment = `@storybook/addon-links`;\n        const forbidden = `foo`;\n\n        vi.spyOn(process, `cwd`).mockImplementation(() => cwd);\n        vi.spyOn(os, `homedir`).mockImplementation(() => homedir);\n\n        const sanitized = cleanPaths(input, separator);\n\n        expect(sanitized).toMatchInlineSnapshot(\n          `\"$SNIP/project/node_modules/@storybook/addon-links/dist/cjs/index.js\"`\n        );\n        expect(sanitized).toContain(`$SNIP`);\n        expect(sanitized).toContain(retainedSegment);\n        expect(sanitized.toLowerCase()).not.toContain(forbidden.toLowerCase());\n        expect(sanitized.toLowerCase()).not.toContain(homedir.toLowerCase());\n      });\n\n      it(`should sanitize windows yarn berry cache with backslashes`, () => {\n        const input = `C:\\\\Users\\\\Foo\\\\AppData\\\\Local\\\\Yarn\\\\Berry\\\\cache\\\\@storybook-addon-measure-npm-7.6.21-61d2a610cb-10.zip\\\\node_modules\\\\@storybook\\\\addon-measure`;\n        const separator = `\\\\`;\n        const homedir = `C:\\\\Users\\\\Foo`;\n        const cwd = `C:\\\\build`;\n        const retainedSegment = `@storybook\\\\addon-measure`;\n        const forbidden = `Foo`;\n\n        vi.spyOn(process, `cwd`).mockImplementation(() => cwd);\n        vi.spyOn(os, `homedir`).mockImplementation(() => homedir);\n\n        const sanitized = cleanPaths(input, separator);\n\n        expect(sanitized).toMatchInlineSnapshot(\n          `\"$SNIP\\\\AppData\\\\Local\\\\Yarn\\\\Berry\\\\cache\\\\@storybook-addon-measure-npm-7.6.21-61d2a610cb-10.zip\\\\node_modules\\\\@storybook\\\\addon-measure\"`\n        );\n        expect(sanitized).toContain(`$SNIP`);\n        expect(sanitized).toContain(retainedSegment);\n        expect(sanitized.toLowerCase()).not.toContain(forbidden.toLowerCase());\n        expect(sanitized.toLowerCase()).not.toContain(homedir.toLowerCase());\n      });\n\n      it(`should sanitize windows path using forward slashes`, () => {\n        const input = `/C:/Users/Foo/OneDrive%20-%20DFe%20Project/Desktop/library/node_modules/@storybook/addon-coverage`;\n        const separator = `/`;\n        const homedir = `C:/Users/Foo`;\n        const cwd = `C:/build`;\n        const retainedSegment = `@storybook/addon-coverage`;\n        const forbidden = `Foo`;\n\n        vi.spyOn(process, `cwd`).mockImplementation(() => cwd);\n        vi.spyOn(os, `homedir`).mockImplementation(() => homedir);\n\n        const sanitized = cleanPaths(input, separator);\n\n        expect(sanitized).toMatchInlineSnapshot(\n          `\"/$SNIP/OneDrive%20-%20DFe%20Project/Desktop/library/node_modules/@storybook/addon-coverage\"`\n        );\n        expect(sanitized).toContain(`$SNIP`);\n        expect(sanitized).toContain(retainedSegment);\n        expect(sanitized.toLowerCase()).not.toContain(forbidden.toLowerCase());\n        expect(sanitized.toLowerCase()).not.toContain(homedir.toLowerCase());\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/telemetry/sanitize.ts",
    "content": "import os from 'node:os';\nimport path from 'node:path';\n\nexport interface IErrorWithStdErrAndStdOut {\n  stderr?: Buffer | string;\n  stdout?: Buffer | string;\n  [key: string]: unknown;\n}\n\n// Removes all user paths\nfunction regexpEscape(str: string): string {\n  return str.replace(/[-[/{}()*+?.\\\\^$|]/g, `\\\\$&`);\n}\n\nexport function removeAnsiEscapeCodes(input = ''): string {\n  return input.replace(/\\u001B\\[[0-9;]*m/g, '');\n}\n\n/**\n * Removes all user-specific file system paths from the input string, replacing them with \"$SNIP\".\n * This helps sanitize sensitive user information from output (such as error messages or logs). e.g.\n * `/Users/username/storybook-app/src/pages/index.js` -> `$SNIP/src/pages/index.js`\n */\nexport function cleanPaths(str: string, separator: string = path.sep): string {\n  if (!str) {\n    return str;\n  }\n\n  // Generate target strings to sanitize using both cwd and home dir\n  const separators = Array.from(new Set([separator, `/`, `\\\\`]));\n  const basePaths = [process.cwd(), os.homedir()].filter(Boolean);\n  const targets = basePaths.flatMap((basePath) =>\n    separators.map((sep) => ({\n      separator: sep,\n      normalizedPath: basePath.split(/[\\\\/]/).join(sep),\n    }))\n  );\n\n  // For each target paths, generalize up its parent directories\n  // and sanitize all such occurrences from the string.\n  targets.forEach(({ separator: sep, normalizedPath }) => {\n    // Split normalized path into its segments and iterate up the hierarchy.\n    const stack = normalizedPath.split(sep);\n    while (stack.length > 1) {\n      const currentPath = stack.join(sep);\n\n      // Replace all case-insensitive occurrences of this path with \"$SNIP\".\n      const currentRegex = new RegExp(regexpEscape(currentPath), `gi`);\n      str = str.replace(currentRegex, `$SNIP`);\n\n      // Also handle the Windows case of doubled separators (e.g., \"//\", \"\\\\\"),\n      const doubledSeparatorPath = stack.join(sep + sep);\n      const doubledSeparatorRegex = new RegExp(regexpEscape(doubledSeparatorPath), `gi`);\n      str = str.replace(doubledSeparatorRegex, `$SNIP`);\n\n      stack.pop();\n    }\n  });\n\n  return str;\n}\n\n// Takes an Error and returns a sanitized JSON String\nexport function sanitizeError(error: Error, pathSeparator: string = path.sep) {\n  try {\n    error = {\n      ...JSON.parse(JSON.stringify(error)),\n      message: removeAnsiEscapeCodes(error.message),\n      stack: removeAnsiEscapeCodes(error.stack),\n      cause: error.cause,\n      name: error.name,\n    };\n\n    // Removes all user paths\n    const errorString = cleanPaths(JSON.stringify(error), pathSeparator);\n\n    return JSON.parse(errorString);\n  } catch (err: unknown) {\n    const message = err instanceof Error ? err.message : String(err);\n    return `Sanitization error: ${message}`;\n  }\n}\n"
  },
  {
    "path": "code/core/src/telemetry/session-id.test.ts",
    "content": "import type { MockInstance } from 'vitest';\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { cache } from 'storybook/internal/common';\n\nimport { nanoid } from 'nanoid';\n\nimport { SESSION_TIMEOUT, getSessionId, resetSessionIdForTest } from './session-id.ts';\n\nvi.mock('storybook/internal/common', async (importOriginal) => ({\n  ...(await importOriginal<typeof import('storybook/internal/common')>()),\n  cache: {\n    get: vi.fn(),\n    set: vi.fn(),\n  },\n}));\nvi.mock('nanoid');\n\nconst spy = (x: any) => x as MockInstance;\n\ndescribe('getSessionId', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n    resetSessionIdForTest();\n  });\n\n  it('returns existing sessionId when cached in memory and does not fetch from disk', async () => {\n    const existingSessionId = 'memory-session-id';\n    resetSessionIdForTest(existingSessionId);\n\n    const sessionId = await getSessionId();\n\n    expect(cache.get).not.toHaveBeenCalled();\n    expect(cache.set).toHaveBeenCalledTimes(1);\n    expect(cache.set).toHaveBeenCalledWith(\n      'session',\n      expect.objectContaining({ id: existingSessionId })\n    );\n    expect(sessionId).toBe(existingSessionId);\n  });\n\n  it('returns existing sessionId when cached on disk and not expired', async () => {\n    const existingSessionId = 'existing-session-id';\n    const existingSession = {\n      id: existingSessionId,\n      lastUsed: Date.now() - SESSION_TIMEOUT + 1000,\n    };\n\n    spy(cache.get).mockResolvedValueOnce(existingSession);\n\n    const sessionId = await getSessionId();\n\n    expect(cache.get).toHaveBeenCalledTimes(1);\n    expect(cache.get).toHaveBeenCalledWith('session');\n    expect(cache.set).toHaveBeenCalledTimes(1);\n    expect(cache.set).toHaveBeenCalledWith(\n      'session',\n      expect.objectContaining({ id: existingSessionId })\n    );\n    expect(sessionId).toBe(existingSessionId);\n  });\n\n  it('generates new sessionId when none exists', async () => {\n    const newSessionId = 'new-session-id';\n    (nanoid as unknown as MockInstance).mockReturnValueOnce(newSessionId);\n\n    spy(cache.get).mockResolvedValueOnce(undefined);\n\n    const sessionId = await getSessionId();\n\n    expect(cache.get).toHaveBeenCalledTimes(1);\n    expect(cache.get).toHaveBeenCalledWith('session');\n    expect(nanoid).toHaveBeenCalledTimes(1);\n    expect(cache.set).toHaveBeenCalledTimes(1);\n    expect(cache.set).toHaveBeenCalledWith(\n      'session',\n      expect.objectContaining({ id: newSessionId })\n    );\n    expect(sessionId).toBe(newSessionId);\n  });\n\n  it('generates new sessionId when existing one is expired', async () => {\n    const expiredSessionId = 'expired-session-id';\n    const expiredSession = { id: expiredSessionId, lastUsed: Date.now() - SESSION_TIMEOUT - 1000 };\n    const newSessionId = 'new-session-id';\n    spy(nanoid).mockReturnValueOnce(newSessionId);\n\n    spy(cache.get).mockResolvedValueOnce(expiredSession);\n\n    const sessionId = await getSessionId();\n\n    expect(cache.get).toHaveBeenCalledTimes(1);\n    expect(cache.get).toHaveBeenCalledWith('session');\n    expect(nanoid).toHaveBeenCalledTimes(1);\n    expect(cache.set).toHaveBeenCalledTimes(1);\n    expect(cache.set).toHaveBeenCalledWith(\n      'session',\n      expect.objectContaining({ id: newSessionId })\n    );\n    expect(sessionId).toBe(newSessionId);\n  });\n});\n"
  },
  {
    "path": "code/core/src/telemetry/session-id.ts",
    "content": "import { cache } from 'storybook/internal/common';\n\nimport { nanoid } from 'nanoid';\n\nexport const SESSION_TIMEOUT = 1000 * 60 * 60 * 2; // 2h\n\ninterface Session {\n  id: string;\n  lastUsed: number;\n}\n\nlet sessionId: string | undefined;\n\nexport const resetSessionIdForTest = (val: string | undefined = undefined) => {\n  sessionId = val;\n};\n\nexport const getSessionId = async () => {\n  const now = Date.now();\n  if (!sessionId) {\n    const session: Session | undefined = await cache.get('session');\n    if (session && session.lastUsed >= now - SESSION_TIMEOUT) {\n      sessionId = session.id;\n    } else {\n      sessionId = nanoid();\n    }\n  }\n  await cache.set('session', { id: sessionId, lastUsed: now });\n  return sessionId;\n};\n"
  },
  {
    "path": "code/core/src/telemetry/storybook-metadata.test.ts",
    "content": "import path from 'node:path';\n\nimport type { MockInstance } from 'vitest';\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { getStorybookInfo, isCI } from 'storybook/internal/common';\nimport {\n  type PackageJson,\n  type StorybookConfig,\n  SupportedBuilder,\n  SupportedFramework,\n  SupportedRenderer,\n} from 'storybook/internal/types';\n\nimport { detect } from 'package-manager-detector';\n\nimport { type Settings, globalSettings } from '../cli/globalSettings.ts';\nimport { getApplicationFileCount } from '../telemetry/get-application-file-count.ts';\nimport { analyzeEcosystemPackages } from '../telemetry/get-known-packages.ts';\nimport { getMonorepoType } from '../telemetry/get-monorepo-type.ts';\nimport { getPackageManagerInfo } from '../telemetry/get-package-manager-info.ts';\nimport { getPortableStoriesFileCount } from '../telemetry/get-portable-stories-usage.ts';\nimport {\n  getActualPackageJson,\n  getActualPackageVersion,\n  getActualPackageVersions,\n} from './package-json.ts';\nimport {\n  computeStorybookMetadata,\n  metaFrameworks,\n  sanitizeAddonName,\n} from './storybook-metadata.ts';\n\nvi.mock(import('../cli/globalSettings.ts'), { spy: true });\nvi.mock(import('./package-json.ts'), { spy: true });\nvi.mock(import('./get-monorepo-type.ts'), { spy: true });\nvi.mock(import('./get-framework-info.ts'), { spy: true });\nvi.mock(import('./get-package-manager-info.ts'), { spy: true });\nvi.mock(import('./get-portable-stories-usage.ts'), { spy: true });\nvi.mock(import('./get-application-file-count.ts'), { spy: true });\nvi.mock(import('./get-known-packages.ts'), { spy: true });\nvi.mock(import('package-manager-detector'), { spy: true });\nvi.mock(import('storybook/internal/common'), { spy: true });\n\nconst packageJsonMock: PackageJson = {\n  name: 'some-user-project',\n  version: 'x.x.x',\n};\n\nconst packageJsonPath = process.cwd();\n\nconst mainJsMock: StorybookConfig = {\n  stories: [],\n};\n\nconst defaultInfo = {\n  framework: SupportedFramework.REACT_VITE,\n  renderer: SupportedRenderer.REACT,\n  builder: SupportedBuilder.VITE,\n  frameworkPackage: '@storybook/react-vite',\n  rendererPackage: '@storybook/react',\n  builderPackage: '@storybook/builder-vite',\n  addons: [],\n  mainConfig: {\n    stories: [],\n  },\n  mainConfigPath: '',\n  previewConfigPath: '',\n  managerConfigPath: '',\n  version: 'x.x.x',\n};\n\nbeforeEach(() => {\n  vi.mocked(getStorybookInfo).mockImplementation(async () => defaultInfo);\n\n  vi.mocked(detect).mockImplementation(async () => ({\n    name: 'yarn',\n    version: '3.1.1',\n    agent: 'yarn@berry',\n  }));\n\n  vi.mocked(getMonorepoType).mockImplementation(() => 'Nx');\n\n  vi.mocked(getPackageManagerInfo).mockImplementation(async () => ({\n    type: 'yarn',\n    version: '3.1.1',\n    agent: 'yarn@berry',\n    nodeLinker: 'node_modules',\n  }));\n\n  vi.mocked(getPortableStoriesFileCount).mockImplementation(async () => 5);\n\n  vi.mocked(getApplicationFileCount).mockImplementation(async () => 10);\n\n  vi.mocked(analyzeEcosystemPackages).mockImplementation(async () => ({\n    testPackages: { jest: 'x.x.x' },\n    stylingPackages: { tailwindcss: '3.0.0' },\n    routerPackages: { 'react-router-dom': '^6.0.0' },\n    stateManagementPackages: { redux: '4.0.0' },\n    dataFetchingPackages: { axios: '>=1.0.0' },\n    uiLibraryPackages: { '@mui/material': '5.0.0' },\n    i18nPackages: { i18next: '22.0.0' },\n  }));\n\n  vi.mocked(getActualPackageJson).mockImplementation(async () => ({\n    dependencies: {\n      '@storybook/react': 'x.x.x',\n      '@storybook/builder-vite': 'x.x.x',\n    },\n  }));\n\n  vi.mocked(getActualPackageVersion).mockImplementation(async (name) => ({\n    name,\n    version: 'x.x.x',\n  }));\n\n  vi.mocked(getActualPackageVersions).mockImplementation((packages) =>\n    Promise.all(Object.keys(packages).map(getActualPackageVersion))\n  );\n});\n\nconst originalSep = path.sep;\n\ndescribe('storybook-metadata', () => {\n  let cwdSpy: MockInstance;\n  beforeEach(() => {\n    // @ts-expect-error the property is read only but we can change it for testing purposes\n    path.sep = originalSep;\n  });\n\n  afterEach(() => {\n    cwdSpy?.mockRestore();\n    // @ts-expect-error the property is read only but we can change it for testing purposes\n    path.sep = originalSep;\n  });\n\n  describe('sanitizeAddonName', () => {\n    it('special addon names', () => {\n      const addonNames = [\n        '@storybook/preset-create-react-app',\n        'storybook-addon-deprecated/register',\n        'storybook-addon-ends-with-js/register.js',\n        '@storybook/addon-knobs/preset',\n        '@storybook/addon-ends-with-js/preset.js',\n        '@storybook/addon-postcss/dist/index.js',\n        '../local-addon/register.js',\n        '../../',\n      ].map(sanitizeAddonName);\n\n      expect(addonNames).toEqual([\n        '@storybook/preset-create-react-app',\n        'storybook-addon-deprecated',\n        'storybook-addon-ends-with-js',\n        '@storybook/addon-knobs',\n        '@storybook/addon-ends-with-js',\n        '@storybook/addon-postcss',\n        'CUSTOM:local-addon',\n        'CUSTOM:..',\n      ]);\n    });\n\n    it('Windows paths', () => {\n      // @ts-expect-error the property is read only but we can change it for testing purposes\n      path.sep = '\\\\';\n      const cwdMockPath = `C:\\\\Users\\\\username\\\\storybook-app`;\n      cwdSpy = vi.spyOn(process, `cwd`).mockReturnValueOnce(cwdMockPath);\n\n      expect(sanitizeAddonName(`${cwdMockPath}\\\\local-addon\\\\themes.js`)).toEqual(\n        'CUSTOM:local-addon'\n      );\n    });\n\n    it('Linux paths', () => {\n      // @ts-expect-error the property is read only but we can change it for testing purposes\n      path.sep = '/';\n      const cwdMockPath = `/Users/username/storybook-app`;\n      cwdSpy = vi.spyOn(process, `cwd`).mockReturnValue(cwdMockPath);\n\n      expect(sanitizeAddonName(`${cwdMockPath}/local-addon/themes.js`)).toEqual(\n        'CUSTOM:local-addon'\n      );\n    });\n\n    describe('normalizes path-like addon definitions', () => {\n      it('node_modules and package-manager cache or pnp like paths', () => {\n        const snippedAddonNames = [\n          '$SNIP/node_modules/@storybook/addon-docs',\n          '$SNIP\\\\node_modules\\\\@storybook\\\\addon-docs',\n          '$SNIP/node_modules/.pnpm/@storybook+addon-a11y@10.0.8_storybook@10.0.8_@testing-library+dom@10.4.0_prettier@3.7._4a81ac32f3a0cc0e4b95fdb0fa907a4f/node_modules/@storybook/addon-a11y',\n          '$SNIP\\\\node_modules\\\\.pnpm\\\\@storybook+addon-onboarding_2f3ab626f8b157d8b10cc93b0c4f7171\\\\node_modules\\\\@storybook\\\\addon-onboarding',\n          '$SNIP/common/temp/node_modules/.pnpm/@storybook+addon-essentials@8.5.8_storybook@8.5.8/node_modules/@storybook/addon-essentials',\n          '$SNIP/.yarn/__virtual__/@storybook-addon-jest-virtual-ceb31c55cc/0/cache/@storybook-addon-jest-npm-9.1.12-adf55af7e8-904699d820.zip/node_modules/@storybook/addon-jest',\n          '$SNIP\\\\.yarn\\\\__virtual__\\\\@storybook-addon-actions-virtual-ecf55a46d7\\\\4\\\\Users\\\\Foo\\\\AppData\\\\Local\\\\Yarn\\\\Berry\\\\cache\\\\@storybook-addon-actions-npm-8.6.7-0b3fcdd2b2-10.zip\\\\node_modules\\\\@storybook\\\\addon-actions',\n          '$SNIP/.yarn/cache/@storybook-addon-webpack5-compiler-babel-npm-4.0.0-7fea55bdc6-abe15a1cd3.zip/node_modules/@storybook/addon-webpack5-compiler-babel',\n        ].map(sanitizeAddonName);\n\n        expect(snippedAddonNames).toEqual([\n          '@storybook/addon-docs',\n          '@storybook/addon-docs',\n          '@storybook/addon-a11y',\n          '@storybook/addon-onboarding',\n          '@storybook/addon-essentials',\n          '@storybook/addon-jest',\n          '@storybook/addon-actions',\n          '@storybook/addon-webpack5-compiler-babel',\n        ]);\n\n        const filePathAddonNames = [\n          '/tmp/yarn_node_modules/7/1fb08592505aa9425e2d6d3ffdc05d84087e575a/yarn_install_node_modules/js/packages/config-storybook/node_modules/@storybook/addon-links/dist/cjs/index.js',\n          '/node_modules/@chromatic-com/storybook',\n          '../../../@storybook/addon-links',\n          '/C:/Users/foo/OneDrive%20-%20BAR%20BAZ/Desktop/project/node_modules/@storybook/addon-coverage',\n          'C:\\\\Users\\\\Foo\\\\AppData\\\\Local\\\\Yarn\\\\Berry\\\\cache\\\\@storybook-addon-measure-npm-7.6.21-61d2a610cb-10.zip\\\\node_modules\\\\@storybook\\\\addon-measure',\n          '/home/foo/project/node_modules/.pnpm/@storybook+addon-docs@10.0.2_@types+react@19.2.2_esbuild@0.25.10_rollup@4.31.0_storyboo_7cb8a1f4d4ca81d0abdb0f0cfacb0423/node_modules/@storybook/addon-docs',\n          '/home/foo/.yarn/berry/cache/@storybook-addon-interactions-npm-7.6.1-9e0ac1ff40-10.zip/node_modules/@storybook/addon-interactions',\n          '/Users/foo/project/node_modules/@storybook/addon-links/dist/cjs/index.js',\n        ].map(sanitizeAddonName);\n\n        expect(filePathAddonNames).toEqual([\n          '@storybook/addon-links',\n          '@chromatic-com/storybook',\n          '@storybook/addon-links',\n          '@storybook/addon-coverage',\n          '@storybook/addon-measure',\n          '@storybook/addon-docs',\n          '@storybook/addon-interactions',\n          '@storybook/addon-links',\n        ]);\n      });\n\n      it('custom, local, or non-node_modules paths', () => {\n        const addonNames = [\n          'file://$SNIP/.storybook/redesign-addon',\n          '$SNIP/addons/airtracker',\n          '$SNIP/preset/index',\n          '$SNIP/src',\n          '../../../tools/storybook/src/plugins/storybook-translations',\n          './html-addon',\n          '..',\n          'file:///D:/foo/templates/.storybook/addons/some-addon',\n        ].map(sanitizeAddonName);\n\n        expect(addonNames).toEqual([\n          'CUSTOM:redesign-addon',\n          'CUSTOM:airtracker',\n          'CUSTOM:preset',\n          'CUSTOM:src',\n          'CUSTOM:storybook-translations',\n          'CUSTOM:html-addon',\n          'CUSTOM:..',\n          'CUSTOM:some-addon',\n        ]);\n      });\n    });\n  });\n\n  describe('computeStorybookMetadata', () => {\n    describe('pnp paths', () => {\n      it('should parse pnp paths for known frameworks', async () => {\n        const unixResult = await computeStorybookMetadata({\n          packageJson: packageJsonMock,\n          packageJsonPath,\n          configDir: '.storybook',\n          mainConfig: {\n            ...mainJsMock,\n            framework: {\n              name: '/Users/foo/storybook/.yarn/__virtual__/@storybook-react-vite-virtual-769c990b9/0/cache/@storybook-react-vite-npm-7.1.0-alpha.38-512b-a23.zip/node_modules/@storybook/react-vite',\n              options: {\n                strictMode: false,\n              },\n            },\n          },\n        });\n\n        expect(unixResult.framework).toEqual({\n          name: '@storybook/react-vite',\n          options: { strictMode: false },\n        });\n\n        const windowsResult = await computeStorybookMetadata({\n          packageJson: packageJsonMock,\n          packageJsonPath,\n          configDir: '.storybook',\n          mainConfig: {\n            ...mainJsMock,\n            framework: {\n              name: 'C:\\\\Users\\\\foo\\\\storybook\\\\.yarn\\\\__virtual__\\\\@storybook-react-vite-virtual-769c990b9\\\\0\\\\cache\\\\@storybook-react-vite-npm-7.1.0-alpha.38-512b-a23.zip\\\\node_modules\\\\@storybook\\\\react-vite',\n              options: {\n                strictMode: false,\n              },\n            },\n          },\n        });\n\n        expect(windowsResult.framework).toEqual({\n          name: '@storybook/react-vite',\n          options: { strictMode: false },\n        });\n      });\n\n      it('should parse pnp paths for unknown frameworks', async () => {\n        vi.mocked(getStorybookInfo).mockImplementation(async () => ({\n          ...defaultInfo,\n          frameworkPackage:\n            '/Users/foo/my-project/.yarn/__virtual__/@storybook-react-vite-virtual-769c990b9/0/cache/@storybook-react-rust-npm-7.1.0-alpha.38-512b-a23.zip/node_modules/storybook-react-rust' as any,\n        }));\n\n        const unixResult = await computeStorybookMetadata({\n          packageJson: packageJsonMock,\n          packageJsonPath,\n          configDir: '.storybook',\n          mainConfig: {\n            ...mainJsMock,\n            framework: {\n              name: '/Users/foo/my-project/.yarn/__virtual__/@storybook-react-vite-virtual-769c990b9/0/cache/@storybook-react-rust-npm-7.1.0-alpha.38-512b-a23.zip/node_modules/storybook-react-rust',\n            },\n          },\n        });\n\n        expect(unixResult.framework).toEqual({\n          name: 'storybook-react-rust',\n        });\n\n        const windowsResult = await computeStorybookMetadata({\n          packageJson: packageJsonMock,\n          packageJsonPath,\n          configDir: '.storybook',\n          mainConfig: {\n            ...mainJsMock,\n            framework: {\n              name: 'C:\\\\Users\\\\foo\\\\my-project\\\\.yarn\\\\__virtual__\\\\@storybook-react-vite-virtual-769c990b9\\\\0\\\\cache\\\\@storybook-react-rust-npm-7.1.0-alpha.38-512b-a23.zip\\\\node_modules\\\\storybook-react-rust',\n            },\n          },\n        });\n\n        expect(windowsResult.framework).toEqual({\n          name: 'storybook-react-rust',\n        });\n      });\n\n      it('should sanitize pnp paths for local frameworks', async () => {\n        // @ts-expect-error the property is read only but we can change it for testing purposes\n        path.sep = '/';\n        cwdSpy = vi.spyOn(process, 'cwd').mockReturnValue('/Users/foo/my-projects');\n\n        vi.mocked(getStorybookInfo).mockImplementation(async () => ({\n          ...defaultInfo,\n          frameworkPackage: '/Users/foo/my-projects/.storybook/some-local-framework' as any,\n        }));\n\n        const unixResult = await computeStorybookMetadata({\n          packageJson: packageJsonMock,\n          packageJsonPath,\n          configDir: '.storybook',\n          mainConfig: {\n            ...mainJsMock,\n            framework: {\n              name: '/Users/foo/my-projects/.storybook/some-local-framework',\n            },\n          },\n        });\n\n        expect(unixResult.framework).toEqual({\n          name: '$SNIP/.storybook/some-local-framework',\n        });\n      });\n\n      it('should sanitize pnp paths for local frameworks on Windows', async () => {\n        // @ts-expect-error the property is read only but we can change it for testing purposes\n        path.sep = '\\\\';\n        cwdSpy = vi.spyOn(process, 'cwd').mockReturnValue('C:\\\\Users\\\\foo\\\\my-project');\n\n        vi.mocked(getStorybookInfo).mockImplementation(async () => ({\n          ...defaultInfo,\n          frameworkPackage: 'C:\\\\Users\\\\foo\\\\my-project\\\\.storybook\\\\some-local-framework' as any,\n        }));\n\n        const windowsResult = await computeStorybookMetadata({\n          packageJson: packageJsonMock,\n          packageJsonPath,\n          configDir: '.storybook',\n          mainConfig: {\n            ...mainJsMock,\n            framework: {\n              name: 'C:\\\\Users\\\\foo\\\\my-project\\\\.storybook\\\\some-local-framework',\n            },\n          },\n        });\n\n        expect(windowsResult.framework).toEqual({\n          name: '$SNIP\\\\.storybook\\\\some-local-framework',\n        });\n      });\n    });\n\n    it('should separate storybook packages and addons', async () => {\n      const result = await computeStorybookMetadata({\n        packageJson: {\n          ...packageJsonMock,\n          devDependencies: {\n            '@storybook/react': 'x.y.z',\n            '@storybook/addon-essentials': 'x.x.x',\n            '@storybook/addon-knobs': 'x.x.y',\n            'storybook-addon-deprecated': 'x.x.z',\n          },\n        } as PackageJson,\n        configDir: '.storybook',\n        packageJsonPath,\n        mainConfig: {\n          ...mainJsMock,\n          addons: [\n            '@storybook/addon-essentials',\n            'storybook-addon-deprecated/register',\n            '@storybook/addon-knobs/preset',\n          ],\n        },\n      });\n\n      expect(result.addons).toMatchInlineSnapshot(`\n        {\n          \"@storybook/addon-essentials\": {\n            \"options\": undefined,\n            \"version\": \"x.x.x\",\n          },\n          \"@storybook/addon-knobs\": {\n            \"options\": undefined,\n            \"version\": \"x.x.x\",\n          },\n          \"storybook-addon-deprecated\": {\n            \"options\": undefined,\n            \"version\": \"x.x.x\",\n          },\n        }\n      `);\n      expect(result.storybookPackages).toMatchInlineSnapshot(`\n        {\n          \"@storybook/react\": {\n            \"version\": \"x.x.x\",\n          },\n        }\n      `);\n    });\n\n    it('should return user specified features', async () => {\n      const features = {};\n\n      const result = await computeStorybookMetadata({\n        packageJson: packageJsonMock,\n        packageJsonPath,\n        configDir: '.storybook',\n        mainConfig: {\n          ...mainJsMock,\n          features,\n        },\n      });\n\n      expect(result.features).toEqual(features);\n    });\n\n    it('should infer builder and renderer from framework package.json', async () => {\n      expect(\n        await computeStorybookMetadata({\n          packageJson: packageJsonMock,\n          packageJsonPath,\n          configDir: '.storybook',\n          mainConfig: {\n            ...mainJsMock,\n            framework: '@storybook/react-vite',\n          },\n        })\n      ).toMatchObject({\n        framework: { name: '@storybook/react-vite' },\n        renderer: '@storybook/react',\n        builder: '@storybook/builder-vite',\n      });\n    });\n\n    it('should return the number of refs', async () => {\n      const res = await computeStorybookMetadata({\n        packageJson: packageJsonMock,\n        packageJsonPath,\n        configDir: '.storybook',\n        mainConfig: {\n          ...mainJsMock,\n          refs: {\n            a: { title: '', url: '' },\n            b: { title: '', url: '' },\n          },\n        },\n      });\n      expect(res.refCount).toEqual(2);\n    });\n\n    it('only reports addon options for addon-essentials', async () => {\n      const res = await computeStorybookMetadata({\n        packageJson: packageJsonMock,\n        packageJsonPath,\n        configDir: '.storybook',\n        mainConfig: {\n          ...mainJsMock,\n          addons: [\n            { name: '@storybook/addon-essentials', options: { controls: false } },\n            { name: 'addon-foo', options: { foo: 'bar' } },\n          ],\n        },\n      });\n      expect(res.addons).toMatchInlineSnapshot(`\n        {\n          \"@storybook/addon-essentials\": {\n            \"options\": {\n              \"controls\": false,\n            },\n            \"version\": \"x.x.x\",\n          },\n          \"addon-foo\": {\n            \"options\": undefined,\n            \"version\": \"x.x.x\",\n          },\n        }\n      `);\n    });\n\n    it.each(Object.entries(metaFrameworks))(\n      'should detect the supported metaframework: %s',\n      async (metaFramework, name) => {\n        const res = await computeStorybookMetadata({\n          configDir: '.storybook',\n          packageJson: {\n            ...packageJsonMock,\n            dependencies: {\n              [metaFramework]: 'x.x.x',\n            },\n          } as PackageJson,\n          packageJsonPath,\n          mainConfig: mainJsMock,\n        });\n        expect(res.metaFramework).toEqual({\n          name,\n          packageName: metaFramework,\n          version: 'x.x.x',\n        });\n      }\n    );\n\n    it('should detect userSince info', async () => {\n      vi.mocked(isCI).mockImplementation(() => false);\n      vi.mocked(globalSettings).mockResolvedValue({\n        value: {\n          userSince: 1717334400000,\n        },\n      } as Settings);\n\n      const res = await computeStorybookMetadata({\n        configDir: '.storybook',\n        packageJson: packageJsonMock,\n        packageJsonPath,\n        mainConfig: mainJsMock,\n      });\n\n      expect(globalSettings).toHaveBeenCalled();\n\n      expect(res.userSince).toEqual(1717334400000);\n    });\n\n    it('should not detect userSince info in CI', async () => {\n      vi.mocked(isCI).mockImplementation(() => true);\n      vi.mocked(globalSettings).mockResolvedValue({} as Settings);\n\n      const res = await computeStorybookMetadata({\n        configDir: '.storybook',\n        packageJson: packageJsonMock,\n        packageJsonPath,\n        mainConfig: mainJsMock,\n      });\n\n      expect(globalSettings).not.toHaveBeenCalled();\n      expect(res.userSince).not.toBeDefined();\n    });\n\n    it('should include knownPackages in metadata', async () => {\n      const res = await computeStorybookMetadata({\n        configDir: '.storybook',\n        packageJson: {\n          ...packageJsonMock,\n          dependencies: {\n            jest: '29.0.0',\n            'react-router-dom': '^6.0.0',\n            tailwindcss: '3.0.0',\n            redux: '4.0.0',\n            axios: '>=1.0.0',\n            '@mui/material': '5.0.0',\n            i18next: '22.0.0',\n          },\n        } as PackageJson,\n        packageJsonPath,\n        mainConfig: mainJsMock,\n      });\n\n      expect(res.knownPackages).toMatchInlineSnapshot(`\n        {\n          \"dataFetchingPackages\": {\n            \"axios\": \">=1.0.0\",\n          },\n          \"i18nPackages\": {\n            \"i18next\": \"22.0.0\",\n          },\n          \"routerPackages\": {\n            \"react-router-dom\": \"^6.0.0\",\n          },\n          \"stateManagementPackages\": {\n            \"redux\": \"4.0.0\",\n          },\n          \"stylingPackages\": {\n            \"tailwindcss\": \"3.0.0\",\n          },\n          \"testPackages\": {\n            \"jest\": \"x.x.x\",\n          },\n          \"uiLibraryPackages\": {\n            \"@mui/material\": \"5.0.0\",\n          },\n        }\n      `);\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/telemetry/storybook-metadata.ts",
    "content": "import { createHash } from 'node:crypto';\nimport { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { dirname, resolve } from 'node:path';\n\nimport {\n  getStorybookConfiguration,\n  getStorybookInfo,\n  isCI,\n  loadMainConfig,\n  versions,\n} from 'storybook/internal/common';\nimport { getInterpretedFile } from 'storybook/internal/common';\nimport { readConfig } from 'storybook/internal/csf-tools';\nimport type { PackageJson, StorybookConfig } from 'storybook/internal/types';\n\nimport * as pkg from 'empathic/package';\n\nimport { version } from '../../package.json';\nimport { globalSettings } from '../cli/globalSettings.ts';\nimport { getApplicationFileCount } from './get-application-file-count.ts';\nimport { getChromaticVersionSpecifier } from './get-chromatic-version.ts';\nimport { getFrameworkInfo } from './get-framework-info.ts';\nimport { getHasRouterPackage } from './get-has-router-package.ts';\nimport { analyzeEcosystemPackages } from './get-known-packages.ts';\nimport { getMonorepoType } from './get-monorepo-type.ts';\nimport { getPackageManagerInfo } from './get-package-manager-info.ts';\nimport { getPortableStoriesFileCount } from './get-portable-stories-usage.ts';\nimport { getActualPackageVersion, getActualPackageVersions } from './package-json.ts';\nimport { cleanPaths } from './sanitize.ts';\nimport type { Dependency, StorybookAddon, StorybookMetadata } from './types.ts';\n\nexport const metaFrameworks = {\n  next: 'Next',\n  'react-scripts': 'CRA',\n  gatsby: 'Gatsby',\n  '@nuxtjs/storybook': 'nuxt',\n  '@nrwl/storybook': 'nx',\n  '@vue/cli-service': 'vue-cli',\n  '@sveltejs/kit': 'sveltekit',\n  '@tanstack/react-router': 'tanstack-react',\n  '@react-router/dev': 'react-router',\n  '@remix-run/dev': 'remix',\n  expo: 'expo',\n  'vike-react': 'vike-react',\n  'vike-vue': 'vike-vue',\n  'vike-solid': 'vike-solid',\n} as Record<string, string>;\n\nexport const sanitizeAddonName = (name: string) => {\n  const normalized = name.replace(/\\\\/g, '/');\n\n  let candidate: string = normalized;\n\n  if (normalized.includes('/node_modules/')) {\n    // common case for package manager cache/pnp mode so we take the segment after node_modules\n    candidate = normalized.split('/node_modules/').pop() ?? normalized;\n  }\n\n  const cleaned = cleanPaths(candidate)\n    .replace(/^file:\\/\\//i, '')\n    .replace(/\\/+$/, '')\n    .replace(/\\/dist\\/.*/, '')\n    .replace(/\\.[mc]?[tj]?s[x]?$/, '')\n    .replace(/\\/(register|manager|preset|index)$/, '')\n    .replace(/\\$SNIP?/g, '');\n\n  let prefix = '';\n  if (\n    cleaned.startsWith('file') ||\n    cleaned.startsWith('.') ||\n    cleaned.startsWith('/') ||\n    cleaned.includes(':')\n  ) {\n    prefix = 'CUSTOM:';\n  }\n\n  const scopedMatches = cleaned.match(/@[^/]+\\/[^/]+/g);\n  if (scopedMatches?.length) {\n    return scopedMatches.at(-1) as string;\n  }\n\n  const parts = cleaned.split('/').filter(Boolean);\n  const addonLike = [...parts]\n    .reverse()\n    .find((part) => part.includes('addon-') || part.includes('-addon'));\n\n  if (addonLike) {\n    return `${prefix}${addonLike}`;\n  }\n\n  if (parts.length >= 2 && parts[parts.length - 2].startsWith('@')) {\n    return `${prefix}${parts[parts.length - 2]}/${parts[parts.length - 1]}`;\n  }\n\n  if (parts.length) {\n    return `${prefix}${parts[parts.length - 1]}`;\n  }\n\n  return `${prefix}${candidate}`;\n};\n\n// Analyze a combination of information from main.js and package.json\n// to provide telemetry over a Storybook project\nexport const computeStorybookMetadata = async ({\n  packageJsonPath,\n  packageJson,\n  mainConfig,\n  configDir,\n}: {\n  packageJsonPath: string;\n  packageJson: PackageJson;\n  mainConfig?: StorybookConfig & Record<string, any>;\n  configDir: string;\n}): Promise<StorybookMetadata> => {\n  const settings = isCI() ? undefined : await globalSettings();\n  const metadata: Partial<StorybookMetadata> = {\n    generatedAt: new Date().getTime(),\n    userSince: settings?.value.userSince,\n    hasCustomBabel: false,\n    hasCustomWebpack: false,\n    hasStaticDirs: false,\n    hasStorybookEslint: false,\n    refCount: 0,\n  };\n\n  const allDependencies = {\n    ...packageJson?.dependencies,\n    ...packageJson?.devDependencies,\n    ...packageJson?.peerDependencies,\n  };\n\n  const metaFramework = Object.keys(allDependencies).find((dep) => !!metaFrameworks[dep]);\n  if (metaFramework) {\n    const { version } = await getActualPackageVersion(metaFramework);\n    metadata.metaFramework = {\n      name: metaFrameworks[metaFramework],\n      packageName: metaFramework,\n      version: version || 'unknown',\n    };\n  }\n\n  metadata.knownPackages = await analyzeEcosystemPackages(packageJson);\n  metadata.hasRouterPackage = getHasRouterPackage(packageJson);\n\n  const monorepoType = getMonorepoType();\n  if (monorepoType) {\n    metadata.monorepo = monorepoType;\n  }\n\n  metadata.packageManager = await getPackageManagerInfo();\n\n  const language = allDependencies.typescript ? 'typescript' : 'javascript';\n\n  if (!mainConfig) {\n    return {\n      ...metadata,\n      storybookVersionSpecifier: versions.storybook,\n      language,\n    };\n  }\n  metadata.hasCustomBabel = !!mainConfig.babel;\n  metadata.hasCustomWebpack = !!mainConfig.webpackFinal;\n  metadata.hasStaticDirs = !!mainConfig.staticDirs;\n\n  if (typeof mainConfig.typescript === 'object') {\n    metadata.typescriptOptions = mainConfig.typescript;\n  }\n\n  const frameworkInfo = await getFrameworkInfo(mainConfig, configDir);\n\n  if (typeof mainConfig.refs === 'object') {\n    metadata.refCount = Object.keys(mainConfig.refs).length;\n  }\n\n  if (typeof mainConfig.features === 'object') {\n    metadata.features = mainConfig.features;\n  }\n\n  const addons: Record<string, StorybookAddon> = {};\n  if (mainConfig.addons) {\n    mainConfig.addons.forEach((addon) => {\n      let addonName;\n      let options;\n\n      if (typeof addon === 'string') {\n        addonName = sanitizeAddonName(addon);\n      } else {\n        if (addon.name.includes('addon-essentials')) {\n          options = addon.options;\n        }\n        addonName = sanitizeAddonName(addon.name);\n      }\n\n      addons[addonName] = {\n        options,\n        version: undefined,\n      };\n    });\n  }\n\n  const chromaticVersionSpecifier = getChromaticVersionSpecifier(packageJson);\n  if (chromaticVersionSpecifier) {\n    addons.chromatic = {\n      version: undefined,\n      versionSpecifier: chromaticVersionSpecifier,\n      options: undefined,\n    };\n  }\n\n  const addonVersions = await getActualPackageVersions(addons);\n  addonVersions.forEach(({ name, version }) => {\n    addons[name] = addons[name] || {\n      name,\n      version,\n    };\n    addons[name].version = version || undefined;\n  });\n\n  const addonNames = Object.keys(addons);\n\n  // all Storybook deps minus the addons\n  const storybookPackages = Object.keys(allDependencies)\n    .filter((dep) => dep.includes('storybook') && !addonNames.includes(dep))\n    .reduce((acc, dep) => {\n      return {\n        ...acc,\n        [dep]: { version: undefined },\n      };\n    }, {}) as Record<string, Dependency>;\n\n  const storybookPackageVersions = await getActualPackageVersions(storybookPackages);\n  storybookPackageVersions.forEach(({ name, version }) => {\n    storybookPackages[name] = storybookPackages[name] || {\n      name,\n      version,\n    };\n\n    storybookPackages[name].version = version || undefined;\n  });\n\n  const hasStorybookEslint = !!allDependencies['eslint-plugin-storybook'];\n\n  const storybookInfo = await getStorybookInfo(configDir);\n\n  try {\n    const { previewConfigPath: previewConfig } = storybookInfo;\n    if (previewConfig) {\n      const config = await readConfig(previewConfig);\n      const usesGlobals = !!(\n        config.getFieldNode(['globals']) || config.getFieldNode(['globalTypes'])\n      );\n      metadata.preview = { ...metadata.preview, usesGlobals };\n    }\n  } catch (e) {\n    // gracefully handle error, as it's not critical information and AST parsing can cause trouble\n  }\n\n  const portableStoriesFileCount = await getPortableStoriesFileCount();\n  const applicationFileCount = await getApplicationFileCount(dirname(packageJsonPath));\n\n  return {\n    ...metadata,\n    ...frameworkInfo,\n    portableStoriesFileCount,\n    applicationFileCount,\n    storybookVersion: version,\n    storybookVersionSpecifier: storybookInfo.versionSpecifier ?? '',\n    language,\n    storybookPackages,\n    addons,\n    hasStorybookEslint,\n    packageJsonType: packageJson.type ?? 'unknown',\n  };\n};\n\nasync function getPackageJsonDetails() {\n  const packageJsonPath = pkg.up();\n  if (packageJsonPath) {\n    return {\n      packageJsonPath,\n      packageJson: JSON.parse(await readFile(packageJsonPath, 'utf8')),\n    };\n  }\n\n  // If we don't find a `package.json`, we assume it \"would have\" been in the current working directory\n  return {\n    packageJsonPath: process.cwd(),\n    packageJson: {},\n  };\n}\n\n// Cache metadata keyed by a hash of the main config file to avoid caching\n// empty/incorrect values during init flows when the configDir is created/updated.\nconst metadataCache = new Map<string, StorybookMetadata>();\n\nasync function hashMainConfig(configDir: string): Promise<string> {\n  try {\n    const mainPath = getInterpretedFile(resolve(configDir, 'main')) as string | null;\n\n    if (!mainPath || !existsSync(mainPath)) {\n      return 'missing';\n    }\n    const content = await readFile(mainPath);\n    const hash = createHash('sha256').update(new Uint8Array(content)).digest('hex');\n    return hash;\n  } catch {\n    return 'unknown';\n  }\n}\n\nexport const getStorybookMetadata = async (_configDir?: string) => {\n  const { packageJson, packageJsonPath } = await getPackageJsonDetails();\n  // TODO: improve the way configDir is extracted, as a \"storybook\" script might not be present\n  // Scenarios:\n  // 1. user changed it to something else e.g. \"storybook:dev\"\n  // 2. they are using angular/nx where the storybook config is defined somewhere else\n  const configDir =\n    (_configDir ||\n      (getStorybookConfiguration(\n        String((packageJson?.scripts as Record<string, unknown> | undefined)?.storybook || ''),\n        '-c',\n        '--config-dir'\n      ) as string)) ??\n    '.storybook';\n  const contentHash = await hashMainConfig(configDir);\n  const cacheKey = `${configDir}::${contentHash}`;\n  const cached = metadataCache.get(cacheKey);\n\n  if (cached) {\n    return cached;\n  }\n\n  const mainConfig = await loadMainConfig({ configDir }).catch(() => undefined);\n  const computed = await computeStorybookMetadata({\n    mainConfig,\n    packageJson,\n    packageJsonPath,\n    configDir,\n  });\n  metadataCache.set(cacheKey, computed);\n  return computed;\n};\n"
  },
  {
    "path": "code/core/src/telemetry/telemetry.test.ts",
    "content": "import { beforeEach, expect, it, vi } from 'vitest';\n\nimport { fetch } from './fetch.ts';\nimport { sendTelemetry } from './telemetry.ts';\n\nvi.mock('./fetch');\nvi.mock('./event-cache', () => {\n  return { set: vi.fn() };\n});\n\nvi.mock('./session-id', () => {\n  return {\n    getSessionId: async () => {\n      return 'session-id';\n    },\n  };\n});\n\nconst fetchMock = vi.mocked(fetch);\n\nbeforeEach(() => {\n  fetchMock.mockResolvedValue({ status: 200 } as any);\n});\n\nit('makes a fetch request with name and data', async () => {\n  await sendTelemetry({ eventType: 'dev', payload: { foo: 'bar' } });\n\n  expect(fetchMock).toHaveBeenCalledTimes(1);\n  const body = JSON.parse(fetchMock?.mock?.calls?.[0]?.[1]?.body as any);\n  expect(body).toMatchObject({\n    eventType: 'dev',\n    payload: { foo: 'bar' },\n  });\n});\n\nit('retries if fetch fails with a 503', async () => {\n  fetchMock.mockResolvedValueOnce({ status: 503 } as any);\n  await sendTelemetry(\n    {\n      eventType: 'dev',\n      payload: { foo: 'bar' },\n    },\n    { retryDelay: 0 }\n  );\n\n  expect(fetchMock).toHaveBeenCalledTimes(2);\n});\n\nit('gives up if fetch repeatedly fails', async () => {\n  fetchMock.mockResolvedValue({ status: 503 } as any);\n  await sendTelemetry(\n    {\n      eventType: 'dev',\n      payload: { foo: 'bar' },\n    },\n    { retryDelay: 0 }\n  );\n\n  expect(fetchMock).toHaveBeenCalledTimes(4);\n});\n\nit('await all pending telemetry when passing in immediate = true', async () => {\n  let numberOfResolvedTasks = 0;\n\n  fetchMock.mockImplementation(async () => {\n    // wait 10ms so that the \"fetch\" is still running while\n    // getSessionId resolves immediately below. tricky!\n    await new Promise((resolve) => {\n      setTimeout(resolve, 10);\n    });\n    numberOfResolvedTasks += 1;\n    return { status: 200 } as any;\n  });\n\n  // when we call sendTelemetry with immediate = true\n  // all pending tasks will be awaited\n  // to test this we add a few telemetry tasks that will be in the 'queue'\n  // we do NOT await these tasks!\n  sendTelemetry({\n    eventType: 'init',\n    payload: { foo: 'bar' },\n  });\n  sendTelemetry({\n    eventType: 'dev',\n    payload: { foo: 'bar' },\n  });\n\n  // wait for getSessionId to finish, but not for fetches\n  await new Promise((resolve) => {\n    setTimeout(resolve, 0);\n  });\n\n  expect(fetchMock).toHaveBeenCalledTimes(2);\n  expect(numberOfResolvedTasks).toBe(0);\n\n  // here we await\n  await sendTelemetry(\n    {\n      eventType: 'error',\n      payload: { foo: 'bar' },\n    },\n    { retryDelay: 0, immediate: true }\n  );\n\n  expect(fetchMock).toHaveBeenCalledTimes(3);\n  expect(numberOfResolvedTasks).toBe(3);\n});\n"
  },
  {
    "path": "code/core/src/telemetry/telemetry.ts",
    "content": "/// <reference types=\"node\" />\nimport { readFileSync } from 'node:fs';\nimport * as os from 'node:os';\nimport { join } from 'node:path';\n\nimport { isCI } from 'storybook/internal/common';\n\nimport retry from 'fetch-retry';\nimport { nanoid } from 'nanoid';\n\nimport { version } from '../../package.json';\nimport { resolvePackageDir } from '../shared/utils/module.ts';\nimport { getAnonymousProjectId, getProjectSince } from './anonymous-id.ts';\nimport { detectAgent } from './detect-agent.ts';\nimport { set as saveToCache } from './event-cache.ts';\nimport { fetch } from './fetch.ts';\nimport { getSessionId } from './session-id.ts';\nimport type { Options, TelemetryData } from './types.ts';\n\nconst retryingFetch = retry(fetch);\n\nconst URL = process.env.STORYBOOK_TELEMETRY_URL || 'https://storybook.js.org/event-log';\n\nlet tasks: Promise<any>[] = [];\n\nexport const addToGlobalContext = (key: string, value: any) => {\n  globalContext[key] = value;\n};\n\nconst getOperatingSystem = (): 'Windows' | 'macOS' | 'Linux' | `Other: ${string}` | 'Unknown' => {\n  try {\n    const platform = os.platform();\n\n    if (platform === 'win32') {\n      return 'Windows';\n    }\n    if (platform === 'darwin') {\n      return 'macOS';\n    }\n    if (platform === 'linux') {\n      return 'Linux';\n    }\n\n    return `Other: ${platform}`;\n  } catch (_err) {\n    return 'Unknown';\n  }\n};\n\n// context info sent with all events, provided\n// by the app. currently:\n// - cliVersion\nconst inCI = isCI();\nconst agentDetection = detectAgent();\nconst globalContext = {\n  inCI,\n  isTTY: process.stdout.isTTY,\n  agent: agentDetection,\n  platform: getOperatingSystem(),\n  nodeVersion: process.versions.node,\n  storybookVersion: getVersionNumber(),\n} as Record<string, any>;\n\nconst prepareRequest = async (data: TelemetryData, context: Record<string, any>, options: any) => {\n  const { eventType, payload, metadata, ...rest } = data;\n  const sessionId = await getSessionId();\n  const eventId = nanoid();\n  const body = { ...rest, eventType, eventId, sessionId, metadata, payload, context };\n\n  return retryingFetch(URL, {\n    method: 'post',\n    body: JSON.stringify(body),\n    headers: { 'Content-Type': 'application/json' },\n    retries: 3,\n    retryOn: [503, 504],\n    retryDelay: (attempt: number) =>\n      2 ** attempt *\n      (typeof options?.retryDelay === 'number' && !Number.isNaN(options?.retryDelay)\n        ? options.retryDelay\n        : 1000),\n  });\n};\n\nfunction getVersionNumber() {\n  try {\n    return JSON.parse(readFileSync(join(resolvePackageDir('storybook'), 'package.json'), 'utf8'))\n      .version;\n  } catch (e) {\n    return version;\n  }\n}\n\nexport async function sendTelemetry(\n  data: TelemetryData,\n  options: Partial<Options> = { retryDelay: 1000, immediate: false }\n) {\n  const { eventType, payload, metadata, ...rest } = data;\n\n  // We use this id so we can de-dupe events that arrive at the index multiple times due to the\n  // use of retries. There are situations in which the request \"5xx\"s (or times-out), but\n  // the server actually gets the request and stores it anyway.\n\n  // flatten the data before we send it\n\n  const context = options.stripMetadata\n    ? globalContext\n    : {\n        ...globalContext,\n        anonymousId: getAnonymousProjectId(),\n        projectSince: getProjectSince()?.getTime(),\n      };\n\n  let request: any;\n  try {\n    request = prepareRequest(data, context, options);\n    tasks.push(request);\n\n    const sessionId = await getSessionId();\n    const eventId = nanoid();\n    const body = { ...rest, eventType, eventId, sessionId, metadata, payload, context };\n\n    const waitFor = options.immediate ? tasks : [request];\n    await Promise.all([...waitFor, saveToCache(eventType, body)]);\n  } catch (err) {\n    //\n  } finally {\n    tasks = tasks.filter((task) => task !== request);\n  }\n}\n"
  },
  {
    "path": "code/core/src/telemetry/types.ts",
    "content": "import type { StorybookConfig, TypescriptOptions } from 'storybook/internal/types';\n\nimport type { DetectResult } from 'package-manager-detector';\n\nimport type { AgentInfo } from './detect-agent.ts';\nimport type { KnownPackagesList } from './get-known-packages.ts';\nimport type { MonorepoType } from './get-monorepo-type.ts';\n\nexport type EventType =\n  | 'boot'\n  | 'add'\n  | 'dev'\n  | 'build'\n  | 'index'\n  | 'upgrade'\n  | 'multi-upgrade'\n  | 'init'\n  | 'init-step'\n  | 'scaffolded-empty'\n  | 'browser'\n  | 'canceled'\n  | 'exit'\n  | 'error'\n  | 'error-metadata'\n  | 'version-update'\n  | 'core-config'\n  | 'remove'\n  | 'save-story'\n  | 'create-new-story-file'\n  | 'create-new-story-file-search'\n  | 'open-in-editor'\n  | 'testing-module-watch-mode'\n  | 'testing-module-completed-report'\n  | 'testing-module-crash-report'\n  | 'addon-test'\n  | 'test-run'\n  | 'addon-onboarding'\n  | 'onboarding-survey'\n  | 'onboarding-checklist-muted'\n  | 'onboarding-checklist-status'\n  | 'mocking'\n  | 'automigrate'\n  | 'migrate'\n  | 'preview-first-load'\n  | 'doctor'\n  | 'share'\n  | 'ghost-stories';\nexport interface Dependency {\n  version: string | undefined;\n  versionSpecifier?: string;\n}\n\nexport interface StorybookAddon extends Dependency {\n  options: any;\n}\n\nexport type StorybookMetadata = {\n  storybookVersion?: string;\n  storybookVersionSpecifier: string;\n  generatedAt?: number;\n  userSince?: number;\n  /** If we can identify the agent, report it; otherwise `unknown` when detected heuristically. */\n  agent?: AgentInfo;\n  language: 'typescript' | 'javascript';\n  framework?: {\n    name?: string;\n    options?: any;\n  };\n  builder?: string;\n  renderer?: string;\n  monorepo?: MonorepoType;\n  packageManager?: {\n    type: DetectResult['name'];\n    version: DetectResult['version'];\n    agent: DetectResult['agent'];\n    nodeLinker: 'node_modules' | 'pnp' | 'pnpm' | 'isolated' | 'hoisted';\n  };\n  typescriptOptions?: Partial<TypescriptOptions>;\n  addons?: Record<string, StorybookAddon>;\n  storybookPackages?: Record<string, Dependency>;\n  metaFramework?: {\n    name: string;\n    packageName: string;\n    version: string;\n  };\n  packageJsonType?: 'unknown' | 'module' | 'commonjs';\n  knownPackages?: KnownPackagesList;\n  hasRouterPackage?: boolean;\n  hasStorybookEslint?: boolean;\n  hasStaticDirs?: boolean;\n  hasCustomWebpack?: boolean;\n  hasCustomBabel?: boolean;\n  features?: StorybookConfig['features'];\n  refCount?: number;\n  preview?: {\n    usesGlobals?: boolean;\n  };\n  portableStoriesFileCount?: number;\n  applicationFileCount?: number;\n};\n\nexport interface Payload {\n  [key: string]: any;\n}\n\nexport interface Context {\n  [key: string]: any;\n}\n\nexport interface Options {\n  retryDelay: number;\n  immediate: boolean;\n  configDir?: string;\n  enableCrashReports?: boolean;\n  stripMetadata?: boolean;\n  notify?: boolean;\n}\n\nexport interface TelemetryData {\n  eventType: EventType;\n  payload: Payload;\n  metadata?: StorybookMetadata;\n}\n\nexport interface TelemetryEvent extends TelemetryData {\n  eventId: string;\n  sessionId: string;\n  context: Context;\n}\n\nexport interface InitPayload {\n  projectType: string;\n  features: { dev: boolean; docs: boolean; test: boolean; onboarding: boolean };\n  newUser: boolean;\n  versionSpecifier: string | undefined;\n  cliIntegration: string | undefined;\n}\n"
  },
  {
    "path": "code/core/src/test/README.md",
    "content": "# Storybook Test\n\nThe `storybook/test` package contains utilities for testing your stories inside `play` functions.\n\n## Usage\n\nThe test package exports instrumented versions of [@vitest/spy](https://vitest.dev/api/mock.html), [@vitest/expect](https://vitest.dev/api/expect.html) (based on [chai](https://www.chaijs.com/)), [@testing-library/dom](https://testing-library.com/docs/dom-testing-library/intro) and [@testing-library/user-event](https://testing-library.com/docs/user-event/intro).\nThe instrumentation makes sure you can debug those methods in the [interactions](https://storybook.js.org/addons/@storybook/addon-interactions) panel.\n\n```ts\n// Button.stories.ts\nimport { expect, fn, userEvent, within } from 'storybook/test';\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  args: {\n    onClick: fn(),\n  },\n};\n\nexport const Demo = {\n  play: async ({ args, canvasElement }) => {\n    const canvas = within(canvasElement);\n    await userEvent.click(canvas.getByRole('button'));\n    await expect(args.onClick).toHaveBeenCalled();\n  },\n};\n```\n"
  },
  {
    "path": "code/core/src/test/expect.ts",
    "content": "/* eslint-disable @typescript-eslint/ban-ts-comment */\nimport * as matchers from '@testing-library/jest-dom/matchers';\nimport type { TestingLibraryMatchers } from '@testing-library/jest-dom/matchers';\n\nimport type {\n  AsymmetricMatchersContaining,\n  ExpectStatic,\n  JestAssertion,\n  MatcherState,\n  MatchersObject,\n} from '@vitest/expect';\nimport {\n  GLOBAL_EXPECT,\n  JestAsymmetricMatchers,\n  JestChaiExpect,\n  JestExtend,\n  customMatchers,\n  getState,\n  setState,\n} from '@vitest/expect';\nimport * as chai from 'chai';\n\nimport type { PromisifyObject } from './utils.ts';\n\ntype Matchers<T> = PromisifyObject<JestAssertion<T>> &\n  TestingLibraryMatchers<ReturnType<ExpectStatic['stringContaining']>, Promise<void>>;\n\n// We only expose the jest compatible API for now\nexport interface Assertion<T> extends Matchers<T> {\n  toHaveBeenCalledOnce(): Promise<void>;\n  toSatisfy<E>(matcher: (value: E) => boolean, message?: string): Promise<void>;\n  resolves: Assertion<T>;\n  rejects: Assertion<T>;\n  not: Assertion<T>;\n}\n\nexport interface Expect extends AsymmetricMatchersContaining {\n  <T>(actual: T, message?: string): Assertion<T>;\n  unreachable(message?: string): Promise<never>;\n  soft<T>(actual: T, message?: string): Assertion<T>;\n  extend(expects: MatchersObject): void;\n  assertions(expected: number): Promise<void>;\n  hasAssertions(): Promise<void>;\n  anything(): any;\n  any(constructor: unknown): any;\n  getState(): MatcherState;\n  setState(state: Partial<MatcherState>): void;\n  not: AsymmetricMatchersContaining;\n}\n\nexport function createExpect() {\n  chai.use(JestExtend);\n  chai.use(JestChaiExpect);\n  chai.use(JestAsymmetricMatchers);\n\n  const expect = ((value: unknown, message?: string) => {\n    const { assertionCalls } = getState(expect);\n    setState({ assertionCalls: assertionCalls + 1, soft: false }, expect);\n    return chai.expect(value, message);\n  }) as ExpectStatic;\n\n  Object.assign(expect, chai.expect);\n\n  // The below methods are added to make chai jest compatible\n\n  expect.getState = () => getState<MatcherState>(expect);\n  expect.setState = (state) => setState(state as Partial<MatcherState>, expect);\n\n  // @ts-expect-error chai.extend is not typed\n  expect.extend = (expects: MatchersObject) => chai.expect.extend(expect, expects);\n\n  // @ts-ignore tsup borks here for some reason\n  expect.soft = (...args) => {\n    // @ts-ignore tsup borks here for some reason\n    const assert = expect(...args);\n    expect.setState({\n      soft: true,\n    });\n    return assert;\n  };\n\n  expect.extend(customMatchers);\n\n  // @ts-ignore tsup borks here for some reason\n  expect.unreachable = (message?: string): never => {\n    chai.assert.fail(`expected${message ? ` \"${message}\" ` : ' '}not to be reached`);\n  };\n\n  function assertions(expected: number) {\n    const errorGen = () =>\n      new Error(\n        `expected number of assertions to be ${expected}, but got ${\n          expect.getState().assertionCalls\n        }`\n      );\n\n    if ('captureStackTrace' in Error && typeof Error.captureStackTrace === 'function') {\n      Error.captureStackTrace(errorGen(), assertions);\n    }\n\n    expect.setState({\n      expectedAssertionsNumber: expected,\n      expectedAssertionsNumberErrorGen: errorGen,\n    });\n  }\n\n  function hasAssertions() {\n    const error = new Error('expected any number of assertion, but got none');\n\n    if ('captureStackTrace' in Error && typeof Error.captureStackTrace === 'function') {\n      Error.captureStackTrace(error, hasAssertions);\n    }\n\n    expect.setState({\n      isExpectingAssertions: true,\n      isExpectingAssertionsError: error,\n    });\n  }\n\n  setState<MatcherState>(\n    {\n      // this should also add \"snapshotState\" that is added conditionally\n      assertionCalls: 0,\n      isExpectingAssertions: false,\n      isExpectingAssertionsError: null,\n      expectedAssertionsNumber: null,\n      expectedAssertionsNumberErrorGen: null,\n    },\n    expect\n  );\n\n  chai.util.addMethod(expect, 'assertions', assertions);\n  chai.util.addMethod(expect, 'hasAssertions', hasAssertions);\n  expect.extend(matchers);\n\n  return expect as unknown as Expect;\n}\n\nconst expect: Expect = createExpect();\n\n// @vitest/expect expects this to be set\nObject.defineProperty(globalThis, GLOBAL_EXPECT, {\n  value: expect,\n  writable: true,\n  configurable: true,\n});\n\nexport { expect };\n"
  },
  {
    "path": "code/core/src/test/index.test.ts",
    "content": "// @vitest-environment happy-dom\nimport { describe, it, test } from 'vitest';\n\nimport { action } from '../actions/index.ts';\nimport { expect, fn, isMockFunction } from './index.ts';\nimport { traverseArgs } from './preview.ts';\n\nit('storybook expect and fn can be used in vitest test', () => {\n  const spy = fn();\n  spy(1);\n  expect(spy).toHaveBeenCalledWith(1);\n});\n\ndescribe('traverseArgs', () => {\n  const args = {\n    deep: {\n      deeper: {\n        fnKey: fn(),\n        actionKey: action('name'),\n      },\n    },\n    arg2: Object.freeze({ frozen: true }),\n  };\n\n  expect(args.deep.deeper.fnKey.getMockName()).toEqual('spy');\n\n  const traversed = traverseArgs(args) as typeof args;\n\n  test('The same structure is maintained', () =>\n    expect(traversed).toEqual({\n      deep: {\n        deeper: {\n          fnKey: args.deep.deeper.fnKey,\n          actionKey: args.deep.deeper.actionKey,\n        },\n      },\n      // We don't mutate frozen objects, but we do insert them back in the tree\n      arg2: args.arg2,\n    }));\n\n  test('The mock name is mutated to be the arg key', () =>\n    expect(traversed.deep.deeper.fnKey.getMockName()).toEqual('fnKey'));\n\n  const actionFn = traversed.deep.deeper.actionKey;\n\n  test('Actions are wrapped in a spy', () => expect(isMockFunction(actionFn)).toBeTruthy());\n  test('The spy of the action is also matching the arg key ', () =>\n    expect(isMockFunction(actionFn) && actionFn.getMockName()).toEqual('actionKey'));\n});\n"
  },
  {
    "path": "code/core/src/test/index.ts",
    "content": "import type { BoundFunctions } from '@testing-library/dom';\nimport type { userEvent } from '@testing-library/user-event';\n\nimport { instrument } from 'storybook/internal/instrumenter';\n\nimport { Assertion } from 'chai';\n\nimport { expect as rawExpect } from './expect.ts';\nimport { type queries } from './testing-library.ts';\n\nexport * from './spy.ts';\n\ntype Queries = BoundFunctions<typeof queries>;\n\nexport type UserEventObject = ReturnType<typeof userEvent.setup>;\n\ndeclare module 'storybook/internal/csf' {\n  interface Canvas extends Queries {}\n  interface StoryContext {\n    userEvent: UserEventObject;\n  }\n}\n\nexport const { expect } = instrument(\n  { expect: rawExpect },\n  {\n    getKeys: (obj: object, depth) => {\n      if ('constructor' in obj && obj.constructor === Assertion) {\n        const privateApi = ['assert', '__methods', '__flags', '_obj'];\n        const keys = Object.keys(Object.getPrototypeOf(obj)).filter(\n          (it) => !privateApi.includes(it)\n        );\n        return depth > 2 ? keys : [...keys, 'not'];\n      }\n      if ('any' in obj) {\n        // https://github.com/storybookjs/storybook/issues/29816\n        return Object.keys(obj).filter((it) => it !== 'any');\n      }\n      return Object.keys(obj);\n    },\n    mutate: true,\n    intercept: (method) => method !== 'expect',\n  }\n);\n\ntype ModuleMockOptions = {\n  spy?: boolean;\n};\ntype ReturnTypeOfModuleMocker = (\n  path: string | Promise<unknown>,\n  factory?: ModuleMockOptions\n) => void;\n\nexport const sb: {\n  mock: ReturnTypeOfModuleMocker;\n} = {\n  mock: () => {\n    // noop\n  },\n};\n\nexport * from './testing-library.ts';\n"
  },
  {
    "path": "code/core/src/test/preview.ts",
    "content": "import type { LoaderFunction } from 'storybook/internal/csf';\nimport { definePreviewAddon } from 'storybook/internal/csf';\nimport { instrument } from 'storybook/internal/instrumenter';\n\nimport {\n  clearAllMocks,\n  fn,\n  isMockFunction,\n  resetAllMocks,\n  restoreAllMocks,\n  uninstrumentedUserEvent,\n  within,\n} from 'storybook/test';\n\nconst resetAllMocksLoader: LoaderFunction = ({ parameters }) => {\n  if (parameters?.test?.mockReset === true) {\n    resetAllMocks();\n  } else if (parameters?.test?.clearMocks === true) {\n    clearAllMocks();\n  } else if (parameters?.test?.restoreMocks !== false) {\n    // Note: restoreAllMocks() now only affects manual spies (vi.spyOn) in Vitest,\n    // automocks are no longer affected since Vitest 4. This could lead to test pollution if\n    // automock state persists between stories.\n    restoreAllMocks();\n  }\n};\n\nexport const traverseArgs = (value: unknown, depth = 0, key?: string): unknown => {\n  // Make sure to not get in infinite loops with self referencing args\n  if (depth > 5) {\n    return value;\n  }\n\n  if (value == null) {\n    return value;\n  }\n  if (isMockFunction(value)) {\n    // Makes sure we get the arg name in the interactions panel\n    if (key) {\n      value.mockName(key);\n    }\n    return value;\n  }\n\n  // wrap explicit actions in a spy\n  if (\n    typeof value === 'function' &&\n    'isAction' in value &&\n    value.isAction &&\n    !('implicit' in value && value.implicit)\n  ) {\n    const mock = fn(value as any);\n\n    if (key) {\n      mock.mockName(key);\n    }\n    return mock;\n  }\n\n  if (Array.isArray(value)) {\n    depth++;\n    // we loop instead of map to prevent this lit issue:\n    // https://github.com/storybookjs/storybook/issues/25651\n    for (let i = 0; i < value.length; i++) {\n      if (Object.getOwnPropertyDescriptor(value, i)?.writable) {\n        value[i] = traverseArgs(value[i], depth);\n      }\n    }\n    return value;\n  }\n\n  if (typeof value === 'object' && value.constructor === Object) {\n    depth++;\n    for (const [k, v] of Object.entries(value)) {\n      if (Object.getOwnPropertyDescriptor(value, k)?.writable) {\n        // We have to mutate the original object for this to survive HMR.\n        (value as Record<string, unknown>)[k] = traverseArgs(v, depth, k);\n      }\n    }\n    return value;\n  }\n  return value;\n};\n\nconst nameSpiesAndWrapActionsInSpies: LoaderFunction = ({ initialArgs }) => {\n  traverseArgs(initialArgs);\n};\n\nlet patchedFocus = false;\n\nconst enhanceContext: LoaderFunction = async (context) => {\n  if (globalThis.HTMLElement && context.canvasElement instanceof globalThis.HTMLElement) {\n    context.canvas = within(context.canvasElement);\n  }\n\n  try {\n    // userEvent.setup() cannot be called in non browser environment and will attempt to access window.navigator.clipboard\n    // which will throw an error in react native for example.\n    const clipboard = globalThis.window?.navigator?.clipboard;\n    if (clipboard) {\n      context.userEvent = instrument(\n        { userEvent: uninstrumentedUserEvent.setup() },\n        {\n          intercept: true,\n          getKeys: (obj) => Object.keys(obj).filter((key) => key !== 'eventWrapper'),\n        }\n      ).userEvent;\n\n      // Restore original clipboard, which was replaced with a stub by userEvent.setup()\n      Object.defineProperty(globalThis.window.navigator, 'clipboard', {\n        get: () => clipboard,\n        configurable: true,\n      });\n\n      if (!patchedFocus) {\n        // Must save a real, original `focus` method outside of the patch beforehand\n        const originalFocus = HTMLElement.prototype.focus;\n        let currentFocus = HTMLElement.prototype.focus;\n\n        // Use a Set to track elements that are currently undergoing a focus operation\n        const focusingElements = new Set<HTMLElement>();\n\n        Object.defineProperties(HTMLElement.prototype, {\n          focus: {\n            configurable: true,\n            set: (newFocus: () => void) => {\n              currentFocus = newFocus;\n            },\n            get() {\n              // 'this' here refers to the DOM element being operated on\n              if (focusingElements.has(this)) {\n                // Recursive call detected; to break the loop, return the original focus method.\n                return originalFocus;\n              }\n\n              // Add protection marker\n              focusingElements.add(this);\n\n              // Use setTimeout(..., 0) to defer the \"remove marker\" operation to the next event loop.\n              // This ensures the marker persists for the entire synchronous call chain (including all recursive calls).\n              setTimeout(() => focusingElements.delete(this), 0);\n\n              // Return the focus method that should currently be used\n              return currentFocus;\n            },\n          },\n        });\n\n        patchedFocus = true;\n      }\n    }\n  } catch {}\n};\n\ninterface TestParameters {\n  test?: {\n    /** Ignore unhandled errors during test execution */\n    dangerouslyIgnoreUnhandledErrors?: boolean;\n\n    /** Whether to throw exceptions coming from the play function */\n    throwPlayFunctionExceptions?: boolean;\n  };\n}\n\nexport interface TestTypes {\n  parameters: TestParameters;\n}\n\nexport default () =>\n  definePreviewAddon<TestTypes>({\n    loaders: [resetAllMocksLoader, nameSpiesAndWrapActionsInSpies, enhanceContext],\n  });\n"
  },
  {
    "path": "code/core/src/test/spy.test.ts",
    "content": "import { beforeEach, expect, it, vi } from 'vitest';\n\nimport { fn, onMockCall, spyOn } from './spy.ts';\n\nconst vitestSpy = vi.fn();\n\nbeforeEach(() => {\n  const unsubscribe = onMockCall(vitestSpy);\n  return () => unsubscribe();\n});\n\nit('mocks are reactive', () => {\n  const storybookSpy = fn();\n  storybookSpy(1);\n  expect(vitestSpy).toHaveBeenCalledWith(storybookSpy, [1]);\n});\n\nclass Foo {\n  bar = 'bar';\n\n  transform(postfix: string) {\n    return this.bar + postfix;\n  }\n}\nconst foo = new Foo();\n\nit('this is correctly binded when making spies reactive', () => {\n  const storybookSpy = spyOn(foo, 'transform');\n  expect(foo.transform('!')).toEqual('bar!');\n  expect(vitestSpy).toHaveBeenCalledWith(storybookSpy, ['!']);\n});\n\nit('this is correctly binded after mock implementation', () => {\n  const storybookSpy = spyOn(foo, 'transform').mockImplementation(function (this: Foo) {\n    return this.bar + 'mocked';\n  });\n\n  expect(foo.transform('!')).toEqual('barmocked');\n  expect(vitestSpy).toHaveBeenCalledWith(storybookSpy, ['!']);\n});\n"
  },
  {
    "path": "code/core/src/test/spy.ts",
    "content": "import type { Mock, MockInstance } from '@vitest/spy';\nimport {\n  type MaybeMocked,\n  type MaybeMockedDeep,\n  type MaybePartiallyMocked,\n  type MaybePartiallyMockedDeep,\n  isMockFunction,\n  mocks,\n  fn as vitestFn,\n  spyOn as vitestSpyOn,\n} from '@vitest/spy';\nimport type { SpyInternalImpl } from 'tinyspy';\nimport * as tinyspy from 'tinyspy';\n\nexport type * from '@vitest/spy';\n\nexport { isMockFunction, mocks };\n\n/**\n * Global registry for module mock spies created by `sb.mock('...', { spy: true })`.\n *\n * These spies are created by the module mocker (via `__vitest_mocker__.mockObject()`) and may use a\n * different `@vitest/spy` instance than the one bundled with storybook/test. This means they won't\n * appear in the `mocks` Set that `clearAllMocks`/`resetAllMocks`/`restoreAllMocks` iterate over.\n *\n * The automock code generation registers spies here so they can be properly cleared between\n * stories.\n */\nconst moduleMockSpies: Set<MockInstance> = ((globalThis as any).__STORYBOOK_MODULE_MOCK_SPIES__ ??=\n  new Set<MockInstance>());\n\ntype Listener = (mock: MockInstance, args: unknown[]) => void;\nconst listeners = new Set<Listener>();\n\nexport function onMockCall(callback: Listener): () => void {\n  listeners.add(callback);\n  return () => void listeners.delete(callback);\n}\n\n// @ts-expect-error Make sure we export the exact same type as @vitest/spy\nexport const spyOn: typeof vitestSpyOn = (...args) => {\n  const mock = vitestSpyOn(...(args as Parameters<typeof vitestSpyOn>));\n  return reactiveMock(mock);\n};\n\ntype Procedure = (...args: any[]) => any;\n\nexport function fn<T extends Procedure = Procedure>(implementation?: T): Mock<T>;\nexport function fn(implementation?: Procedure) {\n  const mock = implementation ? vitestFn(implementation) : vitestFn();\n  return reactiveMock(mock);\n}\n\nfunction reactiveMock(mock: MockInstance) {\n  const reactive = listenWhenCalled(mock);\n  const originalMockImplementation = reactive.mockImplementation.bind(null);\n  reactive.mockImplementation = (fn) => listenWhenCalled(originalMockImplementation(fn));\n  return reactive;\n}\n\nfunction listenWhenCalled(mock: MockInstance) {\n  const state = tinyspy.getInternalState(mock as unknown as SpyInternalImpl);\n  const impl = state.impl;\n  state.willCall(function (this: unknown, ...args) {\n    listeners.forEach((listener) => listener(mock, args));\n    return impl?.apply(this, args);\n  });\n  return mock;\n}\n\n/**\n * Calls [`.mockClear()`](https://vitest.dev/api/mock#mockclear) on every mocked function. This will\n * only empty `.mock` state, it will not reset implementation.\n *\n * It is useful if you need to clean up mock between different assertions.\n */\nexport function clearAllMocks() {\n  mocks.forEach((spy) => spy.mockClear());\n  moduleMockSpies.forEach((spy) => spy.mockClear());\n}\n\n/**\n * Calls [`.mockReset()`](https://vitest.dev/api/mock#mockreset) on every mocked function. This will\n * empty `.mock` state, reset \"once\" implementations and force the base implementation to return\n * `undefined` when invoked.\n *\n * This is useful when you want to completely reset a mock to the default state.\n */\nexport function resetAllMocks() {\n  mocks.forEach((spy) => spy.mockReset());\n  moduleMockSpies.forEach((spy) => spy.mockReset());\n}\n\n/**\n * Calls [`.mockRestore()`](https://vitest.dev/api/mock#mockrestore) on every mocked function. This\n * will restore all original implementations.\n */\nexport function restoreAllMocks() {\n  mocks.forEach((spy) => spy.mockRestore());\n  // For module mock spies, we only clear call history (not restore), because:\n  // - mockRestore() would try to undo the spyOn on the module export object, which is not\n  //   meaningful for automocked modules where the spy reference is captured at module load time\n  // - The spy needs to remain active for subsequent stories\n  moduleMockSpies.forEach((spy) => spy.mockClear());\n}\n\n/**\n * Type helper for TypeScript. Just returns the object that was passed.\n *\n * When `partial` is `true` it will expect a `Partial<T>` as a return value. By default, this will\n * only make TypeScript believe that the first level values are mocked. You can pass down `{ deep:\n * true }` as a second argument to tell TypeScript that the whole object is mocked, if it actually\n * is.\n *\n * @param item Anything that can be mocked\n * @param deep If the object is deeply mocked\n * @param options If the object is partially or deeply mocked\n */\nexport function mocked<T>(item: T, deep?: false): MaybeMocked<T>;\nexport function mocked<T>(item: T, deep: true): MaybeMockedDeep<T>;\nexport function mocked<T>(item: T, options: { partial?: false; deep?: false }): MaybeMocked<T>;\nexport function mocked<T>(item: T, options: { partial?: false; deep: true }): MaybeMockedDeep<T>;\nexport function mocked<T>(\n  item: T,\n  options: { partial: true; deep?: false }\n): MaybePartiallyMocked<T>;\nexport function mocked<T>(\n  item: T,\n  options: { partial: true; deep: true }\n): MaybePartiallyMockedDeep<T>;\nexport function mocked<T>(item: T): MaybeMocked<T>;\nexport function mocked<T>(item: T, _options = {}): MaybeMocked<T> {\n  return item as any;\n}\n"
  },
  {
    "path": "code/core/src/test/testing-library.ts",
    "content": "import * as domTestingLibrary from '@testing-library/dom';\nimport type { FireFunction, FireObject } from '@testing-library/dom/types/events';\nimport * as _userEvent from '@testing-library/user-event';\n\nimport { once } from 'storybook/internal/client-logger';\nimport { instrument } from 'storybook/internal/instrumenter';\n\nimport { dedent } from 'ts-dedent';\nimport type { Writable } from 'type-fest';\n\nimport type { Promisify, PromisifyObject } from './utils.ts';\n\ntype TestingLibraryDom = typeof domTestingLibrary;\n\nconst testingLibrary = instrument(\n  { ...domTestingLibrary },\n  {\n    getKeys: (obj) => Object.keys(obj).filter((key) => key !== 'eventWrapper'),\n    intercept: (method, path) =>\n      path[0] === 'fireEvent' || method.startsWith('find') || method.startsWith('waitFor'),\n  }\n) as {} as Writable<Omit<TestingLibraryDom, 'fireEvent'>> & {\n  fireEvent: Promisify<FireFunction> & PromisifyObject<FireObject>;\n};\n\ntestingLibrary.screen = new Proxy(testingLibrary.screen, {\n  get(target, prop, receiver) {\n    if (typeof window !== 'undefined' && globalThis.location?.href?.includes('viewMode=docs')) {\n      once.warn(dedent`\n        You are using Testing Library's \\`screen\\` object while the story is rendered in docs mode. This will likely lead to issues, as multiple stories are rendered in the same page and therefore screen will potentially find multiple elements. Use the \\`canvas\\` utility from the story context instead, which will scope the queries to each story's canvas.\n\n        More info: https://storybook.js.org/docs/writing-tests/interaction-testing?ref=error#querying-the-canvas\n      `);\n    }\n    return Reflect.get(target, prop, receiver);\n  },\n});\n\nexport const {\n  buildQueries,\n  configure,\n  createEvent,\n  fireEvent,\n  findAllByAltText,\n  findAllByDisplayValue,\n  findAllByLabelText,\n  findAllByPlaceholderText,\n  findAllByRole,\n  findAllByTestId,\n  findAllByText,\n  findAllByTitle,\n  findByAltText,\n  findByDisplayValue,\n  findByLabelText,\n  findByPlaceholderText,\n  findByRole,\n  findByTestId,\n  findByText,\n  findByTitle,\n  getAllByAltText,\n  getAllByDisplayValue,\n  getAllByLabelText,\n  getAllByPlaceholderText,\n  getAllByRole,\n  getAllByTestId,\n  getAllByText,\n  getAllByTitle,\n  getByAltText,\n  getByDisplayValue,\n  getByLabelText,\n  getByPlaceholderText,\n  getByRole,\n  getByTestId,\n  getByText,\n  getByTitle,\n  getConfig,\n  getDefaultNormalizer,\n  getElementError,\n  getNodeText,\n  getQueriesForElement,\n  getRoles,\n  getSuggestedQuery,\n  isInaccessible,\n  logDOM,\n  logRoles,\n  prettyDOM,\n  queries,\n  queryAllByAltText,\n  queryAllByAttribute,\n  queryAllByDisplayValue,\n  queryAllByLabelText,\n  queryAllByPlaceholderText,\n  queryAllByRole,\n  queryAllByTestId,\n  queryAllByText,\n  queryAllByTitle,\n  queryByAltText,\n  queryByAttribute,\n  queryByDisplayValue,\n  queryByLabelText,\n  queryByPlaceholderText,\n  queryByRole,\n  queryByTestId,\n  queryByText,\n  queryByTitle,\n  queryHelpers,\n  screen,\n  waitFor,\n  waitForElementToBeRemoved,\n  within,\n  prettyFormat,\n} = testingLibrary;\n\n// This lines below are to prevent tsup doing stupid (not working) inline stuff, see:\n// https://github.com/storybookjs/storybook/issues/25258\n\ntype _UserEvent = typeof _userEvent;\n\nexport interface UserEvent extends _UserEvent {}\n\nexport const uninstrumentedUserEvent = _userEvent.userEvent;\n\nexport const { userEvent }: { userEvent: UserEvent['userEvent'] } = instrument(\n  { userEvent: _userEvent.userEvent },\n  { intercept: true, getKeys: (obj) => Object.keys(obj).filter((key) => key !== 'eventWrapper') }\n);\n"
  },
  {
    "path": "code/core/src/test/utils.ts",
    "content": "export type Promisify<Fn> = Fn extends { <T>(...args: infer Args): infer Return }\n  ? { <T>(...args: Args): Return extends Promise<any> ? Return : Promise<Return> }\n  : Fn extends { (...args: infer Args): infer Return }\n    ? { (...args: Args): Return extends Promise<any> ? Return : Promise<Return> }\n    : Fn;\n\nexport type PromisifyObject<O> = { [K in keyof O]: Promisify<O[K]> };\n"
  },
  {
    "path": "code/core/src/theming/README.md",
    "content": "# Storybook Theming\n\nStorybook Theming is a wrapper library for emotion.\nIt ensures a single version of emotion is used everywhere.\n\nIt also includes some ready to use themes: light (normal) and dark.\n"
  },
  {
    "path": "code/core/src/theming/animation.ts",
    "content": "import type { Keyframes, SerializedStyles } from '@emotion/react';\nimport { css, keyframes } from '@emotion/react';\n\nexport const easing = {\n  rubber: 'cubic-bezier(0.175, 0.885, 0.335, 1.05)',\n};\n\nconst rotate360: Keyframes = keyframes`\n\tfrom {\n\t\ttransform: rotate(0deg);\n\t}\n\tto {\n\t\ttransform: rotate(360deg);\n\t}\n`;\n\nconst glow: Keyframes = keyframes`\n  0%, 100% { opacity: 1; }\n  50% { opacity: .4; }\n`;\n\nconst float: Keyframes = keyframes`\n  0% { transform: translateY(1px); }\n  25% { transform: translateY(0px); }\n  50% { transform: translateY(-3px); }\n  100% { transform: translateY(1px); }\n`;\n\nconst jiggle: Keyframes = keyframes`\n  0%, 100% { transform:translate3d(0,0,0); }\n  12.5%, 62.5% { transform:translate3d(-4px,0,0); }\n  37.5%, 87.5% {  transform: translate3d(4px,0,0);  }\n`;\n\nconst inlineGlow: SerializedStyles = css`\n  animation: ${glow} 1.5s ease-in-out infinite;\n  color: transparent;\n  cursor: progress;\n`;\n\n// hover & active state for links and buttons\nconst hoverable: SerializedStyles = css`\n  transition: all 150ms ease-out;\n  transform: translate3d(0, 0, 0);\n\n  &:hover {\n    transform: translate3d(0, -2px, 0);\n  }\n\n  &:active {\n    transform: translate3d(0, 0, 0);\n  }\n`;\n\nexport const animation = {\n  rotate360,\n  glow,\n  float,\n  jiggle,\n  inlineGlow,\n  hoverable,\n} as const;\n"
  },
  {
    "path": "code/core/src/theming/base.ts",
    "content": "export const color = {\n  // Official color palette\n  primary: '#FF4785', // coral\n  secondary: '#006DEB', // ocean\n  tertiary: '#FAFBFC',\n  ancillary: '#22a699',\n\n  // Complimentary\n  orange: '#FC521F',\n  gold: '#FFAE00',\n  green: '#66BF3C',\n  seafoam: '#37D5D3',\n  purple: '#6F2CAC',\n  ultraviolet: '#2A0481',\n\n  // Monochrome\n  lightest: '#FFFFFF',\n  lighter: '#F6F9FC',\n  light: '#EEF2F6',\n  mediumlight: '#ECF2F9',\n  medium: '#D9E5F2',\n  mediumdark: '#737F8C',\n  dark: '#5C6570',\n  darker: '#454C54',\n  darkest: '#2E3338',\n\n  // For borders\n  border: 'hsl(212 50% 30% / 0.15)',\n\n  // Status\n  positive: '#66BF3C',\n  warning: '#E69D00',\n  negative: '#FF4400',\n  critical: '#FFFFFF',\n\n  // Text\n  defaultText: '#2E3338',\n  inverseText: '#FFFFFF',\n  positiveText: '#427C27',\n  warningText: '#955B1E',\n  negativeText: '#C23400',\n};\n\nexport const background = {\n  app: '#F6F9FC',\n  bar: color.lightest,\n  content: color.lightest,\n  preview: color.lightest,\n  gridCellSize: 10,\n  hoverable: '#DBECFF',\n\n  // Notification, error, and warning backgrounds\n  positive: '#F1FFEB',\n  warning: '#FFF9EB',\n  negative: '#FFF0EB',\n  critical: '#D13800',\n};\n\nexport const typography = {\n  fonts: {\n    base: [\n      '\"Nunito Sans\"',\n      '-apple-system',\n      '\".SFNSText-Regular\"',\n      '\"San Francisco\"',\n      'BlinkMacSystemFont',\n      '\"Segoe UI\"',\n      '\"Helvetica Neue\"',\n      'Helvetica',\n      'Arial',\n      'sans-serif',\n    ].join(', '),\n    mono: [\n      'ui-monospace',\n      'Menlo',\n      'Monaco',\n      '\"Roboto Mono\"',\n      '\"Oxygen Mono\"',\n      '\"Ubuntu Monospace\"',\n      '\"Source Code Pro\"',\n      '\"Droid Sans Mono\"',\n      '\"Courier New\"',\n      'monospace',\n    ].join(', '),\n  },\n  weight: {\n    regular: 400,\n    bold: 700,\n  },\n  size: {\n    s1: 12,\n    s2: 14,\n    s3: 16,\n    m1: 20,\n    m2: 24,\n    m3: 28,\n    l1: 32,\n    l2: 40,\n    l3: 48,\n    code: 90,\n  },\n};\n\nexport const tokens = {\n  light: {\n    fgColor: {\n      default: color.darkest,\n      muted: color.dark,\n      accent: color.secondary,\n      inverse: color.lightest,\n      // TODO: add 'disabled'\n      positive: '#427C27',\n      warning: '#7A4100',\n      negative: '#C23400',\n      critical: '#FFFFFF',\n    },\n    bgColor: {\n      default: color.lightest,\n      muted: background.app,\n      // TODO: add 'accent'? white or blue?\n      positive: '#F1FFEB',\n      warning: '#FFF7EB',\n      negative: '#FFF0EB',\n      critical: '#D13800',\n    },\n    borderColor: {\n      default: color.border,\n      muted: 'hsl(0 0% 0% / 0.1)',\n      inverse: 'hsl(0 0% 100% / 0.1)',\n      positive: '#BFE7AC',\n      warning: '#FFCE85',\n      negative: '#FFC3AD',\n      critical: 'hsl(16 100% 100% / 0)',\n    },\n  },\n  dark: {\n    fgColor: {\n      default: '#C9CCCF',\n      muted: '#95999D',\n      accent: '#479DFF',\n      inverse: '#1B1C1D',\n      // TODO: add 'disabled'\n      positive: '#86CE64',\n      warning: '#FFAD33',\n      negative: '#FF6933',\n      critical: '#FF6933',\n    },\n    bgColor: {\n      default: '#222325',\n      muted: '#1B1C1D',\n      // TODO: add 'accent'? white or blue?\n      positive: 'hsl(101 100% 100% / 0)',\n      warning: 'hsl(101 100% 100% / 0)',\n      negative: 'hsl(101 100% 100% / 0)',\n      critical: 'hsl(101 100% 100% / 0)',\n    },\n    borderColor: {\n      default: 'hsl(0 0% 100% / 0.1)',\n      muted: 'hsl(0 0% 100% / 0.5)',\n      inverse: 'hsl(0 0% 0% / 0.1)',\n      positive: 'hsl(101 52% 64% / 0.15)',\n      warning: 'hsl(36 100% 64% / 0.15)',\n      negative: 'hsl(16 100% 64% / 0.15)',\n      critical: '#FF6933',\n    },\n  },\n};\n"
  },
  {
    "path": "code/core/src/theming/convert.ts",
    "content": "import { opacify } from 'polished';\n\nimport { animation, easing } from './animation.ts';\nimport { background, color, tokens, typography } from './base.ts';\nimport { themes } from './create.ts';\nimport { chromeDark, chromeLight, create as createSyntax } from './modules/syntax.ts';\nimport type { Color, StorybookTheme, ThemeVars, ThemeVarsColors } from './types.ts';\nimport { getPreferredColorScheme } from './utils.ts';\n\nconst lightSyntaxColors = {\n  green1: '#008000',\n  red1: '#A31515',\n  red2: '#9a050f',\n  red3: '#800000',\n  red4: '#eb0000',\n  gray1: '#393A34',\n  cyan1: '#008380',\n  cyan2: '#007ca0',\n  blue1: '#0000ff',\n  blue2: '#00009f',\n};\n\nconst darkSyntaxColors = {\n  green1: '#95999D',\n  red1: '#92C379',\n  red2: '#9a050f',\n  red3: '#A8FF60',\n  red4: '#96CBFE',\n  gray1: '#EDEDED',\n  cyan1: '#C6C5FE',\n  cyan2: '#FFFFB6',\n  blue1: '#B474DD',\n  blue2: '#00009f',\n};\n\nconst createColors = (vars: ThemeVarsColors): Color => ({\n  // Changeable colors\n  primary: vars.colorPrimary,\n  secondary: vars.colorSecondary,\n  tertiary: color.tertiary,\n  ancillary: color.ancillary,\n\n  // Complimentary\n  orange: color.orange,\n  gold: color.gold,\n  green: color.green,\n  seafoam: color.seafoam,\n  purple: color.purple,\n  ultraviolet: color.ultraviolet,\n\n  // Monochrome\n  lightest: color.lightest,\n  lighter: color.lighter,\n  light: color.light,\n  mediumlight: color.mediumlight,\n  medium: color.medium,\n  mediumdark: color.mediumdark,\n  dark: color.dark,\n  darker: color.darker,\n  darkest: color.darkest,\n\n  // For borders\n  border: color.border,\n\n  // Status\n  positive: color.positive,\n  negative: color.negative,\n  warning: color.warning,\n  critical: color.critical,\n\n  defaultText: vars.textColor || color.darkest,\n  inverseText: vars.textInverseColor || color.lightest,\n  positiveText: color.positiveText,\n  negativeText: color.negativeText,\n  warningText: color.warningText,\n});\n\nexport const convert = (inherit: ThemeVars = themes[getPreferredColorScheme()]): StorybookTheme => {\n  const {\n    base,\n    colorPrimary,\n    colorSecondary,\n    appBg,\n    appContentBg,\n    appHoverBg,\n    appPreviewBg,\n    appBorderColor,\n    appBorderRadius,\n    fontBase,\n    fontCode,\n    textColor,\n    textInverseColor,\n    barTextColor,\n    barHoverColor,\n    barSelectedColor,\n    barBg,\n    buttonBg,\n    buttonBorder,\n    booleanBg,\n    booleanSelectedBg,\n    inputBg,\n    inputBorder,\n    inputTextColor,\n    inputBorderRadius,\n    brandTitle,\n    brandUrl,\n    brandImage,\n    brandTarget,\n    gridCellSize,\n    ...rest\n  } = inherit;\n\n  return {\n    ...rest,\n\n    base,\n\n    ...(base === 'dark' ? tokens.dark : tokens.light),\n\n    color: createColors(inherit),\n    background: {\n      app: appBg,\n      bar: barBg,\n      content: appContentBg,\n      preview: appPreviewBg,\n      gridCellSize: gridCellSize || background.gridCellSize,\n      hoverable: appHoverBg,\n      positive: background.positive,\n      negative: background.negative,\n      warning: background.warning,\n      critical: background.critical,\n    },\n\n    typography: {\n      fonts: {\n        base: fontBase,\n        mono: fontCode,\n      },\n      weight: typography.weight,\n      size: typography.size,\n    },\n    animation,\n    easing,\n\n    input: {\n      background: inputBg,\n      border: inputBorder,\n      borderRadius: inputBorderRadius,\n      color: inputTextColor,\n    },\n\n    button: {\n      background: buttonBg || inputBg,\n      border: buttonBorder || inputBorder,\n    },\n\n    boolean: {\n      background: booleanBg || inputBorder,\n      selectedBackground: booleanSelectedBg || inputBg,\n    },\n\n    // UI\n    layoutMargin: 10,\n    appBorderColor,\n    appBorderRadius,\n\n    // Toolbar default/active colors\n    barTextColor,\n    barHoverColor: barHoverColor || colorSecondary,\n    barSelectedColor: barSelectedColor || colorSecondary,\n    barBg,\n\n    // Brand logo/text\n    brand: {\n      title: brandTitle,\n      url: brandUrl,\n      image: brandImage || (brandTitle ? null : undefined),\n      target: brandTarget,\n    },\n\n    code: createSyntax({\n      colors: base === 'dark' ? darkSyntaxColors : lightSyntaxColors,\n      mono: fontCode,\n    }),\n\n    // Addon actions theme\n    // API example https://github.com/storybookjs/react-inspector/blob/master/src/styles/themes/chromeLight.tsx\n    addonActionsTheme: {\n      ...(base === 'dark' ? chromeDark : chromeLight),\n\n      BASE_FONT_FAMILY: fontCode,\n      BASE_FONT_SIZE: typography.size.s2 - 1,\n      BASE_LINE_HEIGHT: '18px',\n      BASE_BACKGROUND_COLOR: 'transparent',\n      BASE_COLOR: textColor,\n      ARROW_COLOR: opacify(0.2, appBorderColor),\n      ARROW_MARGIN_RIGHT: 4,\n      ARROW_FONT_SIZE: 8,\n      TREENODE_FONT_FAMILY: fontCode,\n      TREENODE_FONT_SIZE: typography.size.s2 - 1,\n      TREENODE_LINE_HEIGHT: '18px',\n      TREENODE_PADDING_LEFT: 12,\n    },\n  };\n};\n"
  },
  {
    "path": "code/core/src/theming/create.ts",
    "content": "// This generates theme variables in the correct shape for the UI\nimport darkThemeVars from './themes/dark.ts';\nimport lightThemeVars from './themes/light.ts';\nimport type { ThemeVars, ThemeVarsPartial } from './types.ts';\nimport { getPreferredColorScheme } from './utils.ts';\n\ninterface Themes {\n  light: ThemeVars;\n  dark: ThemeVars;\n  normal: ThemeVars;\n}\n\nconst themesBase: Omit<Themes, 'normal'> = {\n  light: lightThemeVars,\n  dark: darkThemeVars,\n};\n\nconst preferredColorScheme = getPreferredColorScheme();\n\nexport const themes: Themes = {\n  ...themesBase,\n  normal: themesBase[preferredColorScheme],\n};\n\ninterface Rest {\n  [key: string]: unknown;\n}\n\nexport const create = (\n  vars: ThemeVarsPartial = {\n    base: preferredColorScheme,\n  },\n  rest?: Rest\n): ThemeVars => {\n  const inherit: ThemeVars = {\n    // We always inherit the preferred color scheme.\n    ...themes[preferredColorScheme],\n    // And then the declared theme base if it exists.\n    ...(themes[vars.base] || {}),\n    // And then the actual theme content.\n    ...vars,\n    // If no theme base was declared, we declare the preferred color scheme as the base.\n    base: themes[vars.base] ? vars.base : preferredColorScheme,\n  };\n  return {\n    ...rest,\n    ...inherit,\n    barSelectedColor: vars.barSelectedColor || inherit.colorSecondary,\n  };\n};\n"
  },
  {
    "path": "code/core/src/theming/ensure.ts",
    "content": "import { logger } from 'storybook/internal/client-logger';\n\nimport { deletedDiff } from 'deep-object-diff';\nimport { dedent } from 'ts-dedent';\n\nimport { convert } from './convert.ts';\nimport light from './themes/light.ts';\nimport type { StorybookTheme, ThemeVars } from './types.ts';\n\nexport const ensure = (input: ThemeVars): StorybookTheme => {\n  if (!input) {\n    return convert(light);\n  }\n  const missing = deletedDiff(light, input);\n  if (Object.keys(missing).length) {\n    logger.warn(\n      dedent`\n          Your theme is missing properties, you should update your theme!\n\n          theme-data missing:\n        `,\n      missing\n    );\n  }\n\n  return convert(input);\n};\n"
  },
  {
    "path": "code/core/src/theming/global.ts",
    "content": "import memoize from 'memoizerific';\n\nimport type { Background, Color, Typography } from './types.ts';\n\ntype Value = string | number;\ninterface Return {\n  [key: string]: {\n    [key: string]: Value;\n  };\n}\n\nexport const srOnlyStyles = {\n  position: 'absolute' as const,\n  width: 1,\n  height: 1,\n  padding: 0,\n  margin: -1,\n  overflow: 'hidden',\n  whiteSpace: 'nowrap' as const,\n  clip: 'rect(0, 0, 0, 0)',\n  clipPath: 'inset(50%)',\n  border: 0,\n};\n\nexport const createReset = memoize(1)(\n  ({ typography }: { typography: Typography }): Return => ({\n    body: {\n      fontFamily: typography.fonts.base,\n      fontSize: typography.size.s3,\n      margin: 0,\n\n      WebkitFontSmoothing: 'antialiased',\n      MozOsxFontSmoothing: 'grayscale',\n      WebkitTapHighlightColor: 'rgba(0, 0, 0, 0)',\n      WebkitOverflowScrolling: 'touch',\n    },\n\n    '*': {\n      boxSizing: 'border-box',\n    },\n\n    'h1, h2, h3, h4, h5, h6': {\n      fontWeight: typography.weight.regular,\n      margin: 0,\n      padding: 0,\n    },\n\n    'button, input, textarea, select': {\n      fontFamily: 'inherit',\n      fontSize: 'inherit',\n      boxSizing: 'border-box',\n    },\n\n    sub: {\n      fontSize: '0.8em',\n      bottom: '-0.2em',\n    },\n\n    sup: {\n      fontSize: '0.8em',\n      top: '-0.2em',\n    },\n    'b, strong': {\n      fontWeight: typography.weight.bold,\n    },\n\n    hr: {\n      border: 'none',\n      borderTop: '1px solid silver',\n      clear: 'both',\n      marginBottom: '1.25rem',\n    },\n\n    code: {\n      fontFamily: typography.fonts.mono,\n      WebkitFontSmoothing: 'antialiased',\n      MozOsxFontSmoothing: 'grayscale',\n      display: 'inline-block',\n      paddingLeft: 2,\n      paddingRight: 2,\n      verticalAlign: 'baseline',\n\n      color: 'inherit',\n    },\n\n    pre: {\n      fontFamily: typography.fonts.mono,\n      WebkitFontSmoothing: 'antialiased',\n      MozOsxFontSmoothing: 'grayscale',\n      lineHeight: '18px',\n      padding: '11px 1rem',\n      whiteSpace: 'pre-wrap',\n\n      color: 'inherit',\n      borderRadius: 3,\n      margin: '1rem 0',\n    },\n  })\n);\n\nexport const createGlobal = memoize(1)(({\n  color,\n  background,\n  typography,\n}: {\n  color: Color;\n  background: Background;\n  typography: Typography;\n}): Return => {\n  const resetStyles = createReset({ typography });\n  return {\n    ...resetStyles,\n    body: {\n      ...resetStyles.body,\n      position: 'fixed',\n      width: '100vw',\n      height: '100vh',\n      overflow: 'hidden',\n      color: color.defaultText,\n      background: background.app,\n    },\n\n    hr: {\n      ...resetStyles.hr,\n      borderTop: `1px solid ${color.border}`,\n    },\n\n    '.sb-sr-only, .sb-hidden-until-focus:not(:focus)': srOnlyStyles,\n\n    '.sb-hidden-until-focus': {\n      opacity: 0,\n      transition: 'opacity 150ms ease-out',\n    },\n\n    '.sb-hidden-until-focus:focus': {\n      opacity: 1,\n    },\n\n    '[data-sb-landmark]': {\n      position: 'relative',\n    },\n\n    '[data-sb-landmark]:focus-visible': {\n      outline: 'none',\n    },\n\n    '[data-sb-landmark]:focus-visible::after': {\n      outline: `2px solid ${color.primary}`,\n      outlineOffset: '-2px',\n    },\n\n    '[data-sb-landmark]::after': {\n      content: \"''\",\n      position: 'absolute',\n      inset: 0,\n      pointerEvents: 'none',\n    },\n\n    '.react-aria-Popover:focus-visible': {\n      outline: 'none',\n    },\n  };\n});\n"
  },
  {
    "path": "code/core/src/theming/index.ts",
    "content": "/// <reference path=\"../typings.d.ts\" />\nimport type { FunctionInterpolation, Interpolation } from '@emotion/react';\n\nimport type { StorybookTheme } from './types.ts';\n\nexport { default as styled } from '@emotion/styled';\n\nexport type { StyledComponent } from '@emotion/styled';\n\nexport {\n  CacheProvider,\n  ClassNames,\n  css,\n  Global,\n  jsx,\n  keyframes,\n  ThemeProvider,\n  useTheme,\n  withTheme,\n} from '@emotion/react';\nexport type { CSSObject, Keyframes } from '@emotion/react';\n\ntype FunctionInterpolationEnhanced<T = {}> = FunctionInterpolation<T & { theme: StorybookTheme }>;\ntype InterpolationEnhanced<T = {}> = Interpolation<T & { theme: StorybookTheme }>;\nexport type {\n  FunctionInterpolationEnhanced as FunctionInterpolation,\n  InterpolationEnhanced as Interpolation,\n};\n\nexport * from './base.ts';\nexport * from './types.ts';\n\nexport { default as createCache } from '@emotion/cache';\nexport { default as isPropValid } from '@emotion/is-prop-valid';\n\nexport { createGlobal, createReset, srOnlyStyles } from './global.ts';\nexport * from './create.ts';\nexport * from './convert.ts';\nexport * from './ensure.ts';\n\nexport {\n  lightenColor as lighten,\n  darkenColor as darken,\n  getPreferredColorScheme,\n} from './utils.ts';\n\nexport const ignoreSsrWarning =\n  '/* emotion-disable-server-rendering-unsafe-selector-warning-please-do-not-use-this-the-warning-exists-for-a-reason */';\n\n// Re-export Theme from @emotion/react and self-augment with StorybookTheme\ndeclare module '.' {\n  interface Theme extends StorybookTheme {}\n}\nexport type { Theme } from '@emotion/react';\n"
  },
  {
    "path": "code/core/src/theming/modules/syntax.ts",
    "content": "import { mkColor } from '../utils.ts';\n\ninterface ColorsHash {\n  [key: string]: string;\n}\ninterface ColorsObjectsHash {\n  [key: string]: {\n    color: string;\n  };\n}\n\nexport const chromeDark = {\n  BASE_FONT_FAMILY: 'Menlo, monospace',\n  BASE_FONT_SIZE: '11px',\n  BASE_LINE_HEIGHT: 1.2,\n\n  BASE_BACKGROUND_COLOR: 'rgb(36, 36, 36)',\n  BASE_COLOR: 'rgb(213, 213, 213)',\n\n  OBJECT_PREVIEW_ARRAY_MAX_PROPERTIES: 10,\n  OBJECT_PREVIEW_OBJECT_MAX_PROPERTIES: 5,\n  OBJECT_NAME_COLOR: 'rgb(227, 110, 236)',\n  OBJECT_VALUE_NULL_COLOR: 'rgb(127, 127, 127)',\n  OBJECT_VALUE_UNDEFINED_COLOR: 'rgb(127, 127, 127)',\n  OBJECT_VALUE_REGEXP_COLOR: 'rgb(233, 63, 59)',\n  OBJECT_VALUE_STRING_COLOR: 'rgb(233, 63, 59)',\n  OBJECT_VALUE_SYMBOL_COLOR: 'rgb(233, 63, 59)',\n  OBJECT_VALUE_NUMBER_COLOR: 'hsl(252, 100%, 75%)',\n  OBJECT_VALUE_BOOLEAN_COLOR: 'hsl(252, 100%, 75%)',\n  OBJECT_VALUE_FUNCTION_PREFIX_COLOR: 'rgb(85, 106, 242)',\n\n  HTML_TAG_COLOR: 'rgb(93, 176, 215)',\n  HTML_TAGNAME_COLOR: 'rgb(93, 176, 215)',\n  HTML_TAGNAME_TEXT_TRANSFORM: 'lowercase',\n  HTML_ATTRIBUTE_NAME_COLOR: 'rgb(155, 187, 220)',\n  HTML_ATTRIBUTE_VALUE_COLOR: 'rgb(242, 151, 102)',\n  HTML_COMMENT_COLOR: 'rgb(137, 137, 137)',\n  HTML_DOCTYPE_COLOR: 'rgb(192, 192, 192)',\n\n  ARROW_COLOR: 'rgb(145, 145, 145)',\n  ARROW_MARGIN_RIGHT: 3,\n  ARROW_FONT_SIZE: 12,\n  ARROW_ANIMATION_DURATION: '0',\n\n  TREENODE_FONT_FAMILY: 'Menlo, monospace',\n  TREENODE_FONT_SIZE: '11px',\n  TREENODE_LINE_HEIGHT: 1.2,\n  TREENODE_PADDING_LEFT: 12,\n\n  TABLE_BORDER_COLOR: 'rgb(85, 85, 85)',\n  TABLE_TH_BACKGROUND_COLOR: 'rgb(44, 44, 44)',\n  TABLE_TH_HOVER_COLOR: 'rgb(48, 48, 48)',\n  TABLE_SORT_ICON_COLOR: 'black', // 'rgb(48, 57, 66)',\n  TABLE_DATA_BACKGROUND_IMAGE:\n    'linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0) 50%, rgba(51, 139, 255, 0.0980392) 50%, rgba(51, 139, 255, 0.0980392))',\n  TABLE_DATA_BACKGROUND_SIZE: '128px 32px',\n};\n\nexport const chromeLight = {\n  BASE_FONT_FAMILY: 'Menlo, monospace',\n  BASE_FONT_SIZE: '11px',\n  BASE_LINE_HEIGHT: 1.2,\n\n  BASE_BACKGROUND_COLOR: 'white',\n  BASE_COLOR: 'black',\n\n  OBJECT_PREVIEW_ARRAY_MAX_PROPERTIES: 10,\n  OBJECT_PREVIEW_OBJECT_MAX_PROPERTIES: 5,\n  OBJECT_NAME_COLOR: 'rgb(136, 19, 145)',\n  OBJECT_VALUE_NULL_COLOR: 'rgb(128, 128, 128)',\n  OBJECT_VALUE_UNDEFINED_COLOR: 'rgb(128, 128, 128)',\n  OBJECT_VALUE_REGEXP_COLOR: 'rgb(196, 26, 22)',\n  OBJECT_VALUE_STRING_COLOR: 'rgb(196, 26, 22)',\n  OBJECT_VALUE_SYMBOL_COLOR: 'rgb(196, 26, 22)',\n  OBJECT_VALUE_NUMBER_COLOR: 'rgb(28, 0, 207)',\n  OBJECT_VALUE_BOOLEAN_COLOR: 'rgb(28, 0, 207)',\n  OBJECT_VALUE_FUNCTION_PREFIX_COLOR: 'rgb(13, 34, 170)',\n\n  HTML_TAG_COLOR: 'rgb(168, 148, 166)',\n  HTML_TAGNAME_COLOR: 'rgb(136, 18, 128)',\n  HTML_TAGNAME_TEXT_TRANSFORM: 'lowercase',\n  HTML_ATTRIBUTE_NAME_COLOR: 'rgb(153, 69, 0)',\n  HTML_ATTRIBUTE_VALUE_COLOR: 'rgb(26, 26, 166)',\n  HTML_COMMENT_COLOR: 'rgb(35, 110, 37)',\n  HTML_DOCTYPE_COLOR: 'rgb(192, 192, 192)',\n\n  ARROW_COLOR: '#6e6e6e',\n  ARROW_MARGIN_RIGHT: 3,\n  ARROW_FONT_SIZE: 12,\n  ARROW_ANIMATION_DURATION: '0',\n\n  TREENODE_FONT_FAMILY: 'Menlo, monospace',\n  TREENODE_FONT_SIZE: '11px',\n  TREENODE_LINE_HEIGHT: 1.2,\n  TREENODE_PADDING_LEFT: 12,\n\n  TABLE_BORDER_COLOR: '#aaa',\n  TABLE_TH_BACKGROUND_COLOR: '#eee',\n  TABLE_TH_HOVER_COLOR: 'hsla(0, 0%, 90%, 1)',\n  TABLE_SORT_ICON_COLOR: '#6e6e6e',\n  TABLE_DATA_BACKGROUND_IMAGE:\n    'linear-gradient(to bottom, white, white 50%, rgb(234, 243, 255) 50%, rgb(234, 243, 255))',\n  TABLE_DATA_BACKGROUND_SIZE: '128px 32px',\n};\n\nconst convertColors = (colors: ColorsHash): ColorsObjectsHash =>\n  Object.entries(colors).reduce((acc, [k, v]) => ({ ...acc, [k]: mkColor(v) }), {});\n\nexport const create = ({ colors, mono }: { colors: ColorsHash; mono: string }) => {\n  const colorsObjs = convertColors(colors);\n  return {\n    token: {\n      fontFamily: mono,\n      WebkitFontSmoothing: 'antialiased',\n\n      '&.tag': colorsObjs.red3,\n\n      '&.comment': { ...colorsObjs.green1, fontStyle: 'italic' },\n      '&.prolog': { ...colorsObjs.green1, fontStyle: 'italic' },\n      '&.doctype': { ...colorsObjs.green1, fontStyle: 'italic' },\n      '&.cdata': { ...colorsObjs.green1, fontStyle: 'italic' },\n\n      '&.string': colorsObjs.red1,\n\n      '&.url': colorsObjs.cyan1,\n      '&.symbol': colorsObjs.cyan1,\n      '&.number': colorsObjs.cyan1,\n      '&.boolean': colorsObjs.cyan1,\n      '&.variable': colorsObjs.cyan1,\n      '&.constant': colorsObjs.cyan1,\n      '&.inserted': colorsObjs.cyan1,\n\n      '&.atrule': colorsObjs.blue1,\n      '&.keyword': colorsObjs.blue1,\n      '&.attr-value': colorsObjs.blue1,\n\n      '&.punctuation': colorsObjs.gray1,\n      '&.operator': colorsObjs.gray1,\n\n      '&.function': colorsObjs.gray1,\n      '&.deleted': colorsObjs.red2,\n\n      '&.important': {\n        fontWeight: 'bold',\n      },\n      '&.bold': {\n        fontWeight: 'bold',\n      },\n\n      '&.italic': {\n        fontStyle: 'italic',\n      },\n\n      '&.class-name': colorsObjs.cyan2,\n\n      '&.selector': colorsObjs.red3,\n\n      '&.attr-name': colorsObjs.red4,\n      '&.property': colorsObjs.red4,\n      '&.regex': colorsObjs.red4,\n      '&.entity': colorsObjs.red4,\n\n      '&.directive.tag .tag': {\n        background: '#ffff00',\n        ...colorsObjs.gray1,\n      },\n    },\n    'language-json .token.boolean': colorsObjs.blue1,\n    'language-json .token.number': colorsObjs.blue1,\n    'language-json .token.property': colorsObjs.cyan2,\n\n    namespace: {\n      opacity: 0.7,\n    },\n  };\n};\n"
  },
  {
    "path": "code/core/src/theming/tests/convert.test.js",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { convert } from '../convert';\nimport { create } from '../create';\nimport darkThemeVars from '../themes/dark';\nimport lightThemeVars from '../themes/light';\n\ndescribe('convert', () => {\n  it('should return the default theme when no params', () => {\n    const result = convert();\n\n    expect(result.base).toEqual('light');\n  });\n  it('should return a valid dark theme', () => {\n    const result = convert(darkThemeVars);\n\n    expect(result.base).toEqual('dark');\n    expect(result).toMatchObject({\n      color: expect.objectContaining({\n        ancillary: '#22a699',\n        border: 'hsl(212 50% 30% / 0.15)',\n        critical: '#FFFFFF',\n        dark: '#5C6570',\n        darker: '#454C54',\n        darkest: '#2E3338',\n        defaultText: '#C9CCCF',\n        gold: '#FFAE00',\n        green: '#66BF3C',\n        inverseText: '#1B1C1D',\n        light: '#EEF2F6',\n        lighter: '#F6F9FC',\n        lightest: '#FFFFFF',\n        medium: '#D9E5F2',\n        mediumdark: '#737F8C',\n        mediumlight: '#ECF2F9',\n        negative: '#FF4400',\n        negativeText: '#C23400',\n        orange: '#FC521F',\n        positive: '#66BF3C',\n        positiveText: '#427C27',\n        primary: '#FF4785',\n        purple: '#6F2CAC',\n        seafoam: '#37D5D3',\n        secondary: '#479DFF',\n        tertiary: '#FAFBFC',\n        ultraviolet: '#2A0481',\n        warning: '#E69D00',\n        warningText: '#955B1E',\n      }),\n      background: expect.objectContaining({\n        app: '#1B1C1D',\n        bar: '#222325',\n        content: '#222325',\n        critical: '#D13800',\n        gridCellSize: 10,\n        hoverable: '#233952',\n        negative: '#FFF0EB',\n        positive: '#F1FFEB',\n        preview: '#FFFFFF',\n        warning: '#FFF9EB',\n      }),\n    });\n  });\n  it('should return a valid light theme', () => {\n    const result = convert(lightThemeVars);\n\n    expect(result.base).toEqual('light');\n    expect(result).toMatchObject({\n      color: expect.objectContaining({\n        ancillary: '#22a699',\n        border: 'hsl(212 50% 30% / 0.15)',\n        critical: '#FFFFFF',\n        dark: '#5C6570',\n        darker: '#454C54',\n        darkest: '#2E3338',\n        defaultText: '#2E3338',\n        gold: '#FFAE00',\n        green: '#66BF3C',\n        inverseText: '#FFFFFF',\n        light: '#EEF2F6',\n        lighter: '#F6F9FC',\n        lightest: '#FFFFFF',\n        medium: '#D9E5F2',\n        mediumdark: '#737F8C',\n        mediumlight: '#ECF2F9',\n        negative: '#FF4400',\n        negativeText: '#C23400',\n        orange: '#FC521F',\n        positive: '#66BF3C',\n        positiveText: '#427C27',\n        primary: '#FF4785',\n        purple: '#6F2CAC',\n        seafoam: '#37D5D3',\n        secondary: '#006DEB',\n        tertiary: '#FAFBFC',\n        ultraviolet: '#2A0481',\n        warning: '#E69D00',\n        warningText: '#955B1E',\n      }),\n      background: expect.objectContaining({\n        app: '#F6F9FC',\n        bar: '#FFFFFF',\n        content: '#FFFFFF',\n        critical: '#D13800',\n        gridCellSize: 10,\n        hoverable: '#DBECFF',\n        negative: '#FFF0EB',\n        positive: '#F1FFEB',\n        preview: '#FFFFFF',\n        warning: '#FFF9EB',\n      }),\n    });\n  });\n  it('should map optional vars', () => {\n    const customVars = create({\n      base: 'light',\n      brandTitle: 'my custom storybook',\n      brandTarget: '_self',\n      gridCellSize: 12,\n    });\n\n    const result = convert(customVars);\n    expect(result.base).toEqual('light');\n    expect(result).toMatchObject({\n      background: expect.objectContaining({\n        gridCellSize: 12,\n      }),\n      brand: expect.objectContaining({\n        title: 'my custom storybook',\n        target: '_self',\n      }),\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/theming/tests/create.test.js",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { create } from '../create';\nimport { getPreferredColorScheme } from './../utils';\n\nvi.mock('./../utils', () => ({\n  getPreferredColorScheme: vi.fn().mockReturnValue('light'),\n}));\n\ndescribe('create base', () => {\n  it('should create a theme with minimal viable theme', () => {\n    const result = create({ base: 'light' });\n\n    expect(result).toBeDefined();\n  });\n  it('should pick `light` when `base` is missing', () => {\n    const result = create({ base: undefined });\n\n    expect(result.base).toBe('light');\n  });\n  it('should pick `light` when nothing is given', () => {\n    const result = create();\n\n    expect(result.base).toBe('light');\n  });\n  it('should pick `dark` when base is dark', () => {\n    const result = create({ base: 'dark' });\n\n    expect(result.base).toBe('dark');\n  });\n  it('should pick `light` when base is a unknown value', () => {\n    const result = create({ base: 'foobar' });\n\n    expect(result.base).toBe('light');\n  });\n});\n\ndescribe('create merge', () => {\n  it('should merge colorPrimary', () => {\n    const result = create({ base: 'light', colorPrimary: 'orange' });\n\n    expect(result).toHaveProperty('colorPrimary', 'orange');\n  });\n  it('should merge colorSecondary', () => {\n    const result = create({ base: 'light', colorSecondary: 'orange' });\n\n    expect(result).toHaveProperty('colorSecondary', 'orange');\n  });\n  it('should merge appBg', () => {\n    const result = create({ base: 'light', appBg: 'orange' });\n\n    expect(result).toHaveProperty('appBg', 'orange');\n  });\n});\n\ndescribe('create brand', () => {\n  it('should have default', () => {\n    const result = create({ base: 'light' });\n\n    expect(result.brandImage).not.toBeDefined();\n    expect(result.brandTitle).not.toBeDefined();\n    expect(result.brandUrl).not.toBeDefined();\n    expect(result.brandTarget).not.toBeDefined();\n  });\n  it('should accept null', () => {\n    const result = create({\n      base: 'light',\n      brandTitle: null,\n      brandUrl: null,\n      brandImage: null,\n      brandTarget: null,\n    });\n\n    expect(result).toMatchObject({\n      brandImage: null,\n      brandTitle: null,\n      brandUrl: null,\n      brandTarget: null,\n    });\n  });\n  it('should accept values', () => {\n    const result = create({\n      base: 'light',\n      brandImage: 'https://storybook.js.org/images/placeholders/350x150.png',\n      brandTitle: 'my custom storybook',\n      brandUrl: 'https://example.com',\n      brandTarget: '_top',\n    });\n\n    expect(result).toMatchObject({\n      brandImage: 'https://storybook.js.org/images/placeholders/350x150.png',\n      brandTitle: 'my custom storybook',\n      brandUrl: 'https://example.com',\n      brandTarget: '_top',\n    });\n  });\n});\n\ndescribe('create grid', () => {\n  it('should have default', () => {\n    const result = create({ base: 'light' });\n\n    expect(result.gridCellSize).not.toBeDefined();\n  });\n  it('should accept null', () => {\n    const result = create({ base: 'light', gridCellSize: null });\n\n    expect(result).toMatchObject({\n      gridCellSize: null,\n    });\n  });\n  it('should accept values', () => {\n    const result = create({\n      base: 'light',\n      gridCellSize: 12,\n    });\n\n    expect(result).toMatchObject({\n      gridCellSize: 12,\n    });\n  });\n});\n\ndescribe('create extend', () => {\n  it('should allow custom props', () => {\n    const result = create(\n      {\n        base: 'light',\n      },\n      {\n        myCustomProperty: 42,\n      }\n    );\n\n    expect(result.myCustomProperty).toEqual(42);\n  });\n  it('should not allow overriding known properties with custom props', () => {\n    const result = create(\n      {\n        base: 'light',\n      },\n      {\n        base: 42,\n      }\n    );\n\n    expect(result.base).toEqual('light');\n  });\n});\n\ndescribe('themes', () => {\n  beforeEach(() => {\n    vi.resetModules();\n  });\n\n  it('should set `normal` to `light` theme when user preference is `light`', async () => {\n    getPreferredColorScheme.mockReturnValue('light');\n\n    const { themes } = await import('./../create');\n\n    expect(themes.normal).toBe(themes.light);\n  });\n\n  it('should set `normal` to `dark` theme when user preference is `dark`', async () => {\n    getPreferredColorScheme.mockReturnValue('dark');\n\n    const { themes } = await import('./../create');\n\n    expect(themes.normal).toBe(themes.dark);\n  });\n});\n"
  },
  {
    "path": "code/core/src/theming/tests/util.test.js",
    "content": "// @vitest-environment happy-dom\nimport { describe, expect, it, vi } from 'vitest';\n\nimport { darkenColor as darken, getPreferredColorScheme, lightenColor as lighten } from '../utils';\n\ndescribe('utils', () => {\n  it('should apply polished when valid arguments are passed', () => {\n    const lightColor = '#F6F9FC';\n    const darkColor = '#2f2f2f';\n    const darkenedColor = darken(lightColor);\n    const lightenedColor = lighten(darkColor);\n\n    expect(darkenedColor).toEqual('rgba(0,0,0,0.95)');\n    expect(lightenedColor).toEqual('rgba(255,255,255,0.95)');\n  });\n\n  it('should guard non-string value is being passed to color of theme object', () => {\n    const result = () => {\n      return lighten(1234);\n    };\n\n    expect(result).toThrow();\n  });\n\n  it('should guard anything that is not working with polished', () => {\n    const color = '1234';\n\n    const result = lighten(color);\n\n    expect(result).toEqual(color);\n  });\n\n  it('should guard css variables is being passed to polished functions', () => {\n    const color = 'var(--my-var, blue)';\n\n    const result = lighten(color);\n\n    expect(result).toEqual(color);\n  });\n\n  it('should guard css calc is being passed to polished functions', () => {\n    const color = 'rgb(calc(0 + 100), calc(0 + 100), calc(0 + 100))';\n\n    const result = lighten(color);\n\n    expect(result).toEqual(color);\n  });\n\n  it('should guard linear-gradient is being passed to polished functions', () => {\n    const color = `linear-gradient(to bottom, white, blue)`;\n\n    const result = lighten(color);\n\n    expect(result).toEqual(color);\n  });\n\n  it('should guard radial-gradient is being passed to polished functions', () => {\n    const color = `radial-gradient(red, green, blue)`;\n\n    const result = lighten(color);\n\n    expect(result).toEqual(color);\n  });\n\n  it('should guard repeating-linear-gradient is being passed to polished functions', () => {\n    const color = `repeating-linear-gradient(red, yellow 10%, green 20%)`;\n\n    const result = lighten(color);\n\n    expect(result).toEqual(color);\n  });\n\n  it('should guard repeating-radial-gradient is being passed to polished functions', () => {\n    const color = `repeating-radial-gradient(red, yellow 10%, green 20%)`;\n\n    const result = lighten(color);\n\n    expect(result).toEqual(color);\n  });\n\n  describe('getPreferredColorScheme', () => {\n    it('should return \"light\" if \"matchMedia\" is unavailable', () => {\n      vi.stubGlobal('matchMedia', undefined);\n\n      const colorScheme = getPreferredColorScheme();\n      expect(colorScheme).toBe('light');\n    });\n\n    it('should return \"light\" if the preferred color scheme is light or undefined', () => {\n      vi.stubGlobal(\n        'matchMedia',\n        vi.fn().mockReturnValue({\n          matches: false,\n        })\n      );\n\n      const colorScheme = getPreferredColorScheme();\n      expect(colorScheme).toBe('light');\n    });\n\n    it('should return \"dark\" if the preferred color scheme is dark', () => {\n      // By setting matches to always be true any checks for prefer-color-scheme\n      // will match and since we only check if the preferred scheme is dark this\n      // is a simple way to test it\n      vi.stubGlobal(\n        'matchMedia',\n        vi.fn().mockReturnValue({\n          matches: true,\n        })\n      );\n\n      const colorScheme = getPreferredColorScheme();\n      expect(colorScheme).toBe('dark');\n    });\n  });\n});\n"
  },
  {
    "path": "code/core/src/theming/themes/dark.ts",
    "content": "import { color, typography } from '../base.ts';\nimport type { ThemeVars } from '../types.ts';\n\nconst theme: ThemeVars = {\n  base: 'dark',\n\n  // Storybook-specific color palette\n  colorPrimary: '#FF4785', // coral\n  colorSecondary: '#479DFF',\n\n  // UI\n  appBg: '#1B1C1D',\n  appContentBg: '#222325',\n  appHoverBg: '#233952',\n  appPreviewBg: color.lightest,\n  appBorderColor: 'hsl(0 0% 100% / 0.1)',\n  appBorderRadius: 4,\n\n  // Fonts\n  fontBase: typography.fonts.base,\n  fontCode: typography.fonts.mono,\n\n  // Text colors\n  textColor: '#C9CCCF',\n  textInverseColor: '#1B1C1D',\n  textMutedColor: '#95999D',\n\n  // Toolbar default and active colors\n  barTextColor: '#95999D',\n  barHoverColor: '#70B3FF',\n  barSelectedColor: '#479DFF',\n  barBg: '#222325',\n\n  // Form colors\n  buttonBg: '#1B1C1D',\n  buttonBorder: 'hsl(0 0% 100% / 0.1)',\n  booleanBg: '#1B1C1D',\n  booleanSelectedBg: '#292B2E',\n  inputBg: '#1B1C1D',\n  inputBorder: 'hsl(0 0% 100% / 0.1)',\n  inputTextColor: '#C9CCCF',\n  inputBorderRadius: 4,\n};\n\nexport default theme;\n"
  },
  {
    "path": "code/core/src/theming/themes/light.ts",
    "content": "import { background, color, typography } from '../base.ts';\nimport type { ThemeVars } from '../types.ts';\n\nconst theme: ThemeVars = {\n  base: 'light',\n\n  // Storybook-specific color palette\n  colorPrimary: color.primary,\n  colorSecondary: color.secondary,\n\n  // UI\n  appBg: background.app,\n  appContentBg: color.lightest,\n  appHoverBg: '#DBECFF',\n  appPreviewBg: color.lightest,\n  appBorderColor: color.border,\n  appBorderRadius: 4,\n\n  // Fonts\n  fontBase: typography.fonts.base,\n  fontCode: typography.fonts.mono,\n\n  // Text colors\n  textColor: color.darkest,\n  textInverseColor: color.lightest,\n  textMutedColor: color.dark,\n\n  // Toolbar default and active colors\n  barTextColor: color.dark,\n  barHoverColor: '#005CC7',\n  barSelectedColor: '#0063D6',\n  barBg: color.lightest,\n\n  // Form colors\n  buttonBg: background.app,\n  buttonBorder: color.medium,\n  booleanBg: color.mediumlight,\n  booleanSelectedBg: color.lightest,\n  inputBg: color.lightest,\n  inputBorder: color.border,\n  inputTextColor: color.darkest,\n  inputBorderRadius: 4,\n};\n\nexport default theme;\n"
  },
  {
    "path": "code/core/src/theming/types.ts",
    "content": "import type { animation, easing } from './animation.ts';\nimport type { background, color, tokens, typography } from './base.ts';\n\nexport interface ThemeVars extends ThemeVarsBase, ThemeVarsColors {}\n\nexport interface ThemeVarsPartial extends ThemeVarsBase, Partial<ThemeVarsColors> {}\n\ninterface ThemeVarsBase {\n  base: 'light' | 'dark';\n}\n\nexport interface ThemeVarsColors {\n  colorPrimary: string;\n  colorSecondary: string;\n\n  // UI\n  appBg: string;\n  appContentBg: string;\n  appHoverBg: string;\n  appPreviewBg: string;\n  appBorderColor: string;\n  appBorderRadius: number;\n\n  // Typography\n  fontBase: string;\n  fontCode: string;\n\n  // Text colors\n  textColor: string;\n  textInverseColor: string;\n  textMutedColor: string;\n\n  // Toolbar default and active colors\n  barTextColor: string;\n  barHoverColor: string;\n  barSelectedColor: string;\n  barBg: string;\n\n  // Form colors\n  buttonBg: string;\n  buttonBorder: string;\n  booleanBg: string;\n  booleanSelectedBg: string;\n  inputBg: string;\n  inputBorder: string;\n  inputTextColor: string;\n  inputBorderRadius: number;\n\n  brandTitle?: string;\n  brandUrl?: string;\n  brandImage?: string;\n  brandTarget?: string;\n\n  gridCellSize?: number;\n}\n\nexport type Color = typeof color;\nexport type Background = typeof background;\nexport type Typography = typeof typography;\nexport type Animation = typeof animation;\nexport type Easing = typeof easing;\n\nexport type TextSize = number | string;\nexport interface Brand {\n  title: string | undefined;\n  url: string | null | undefined;\n  image: string | null | undefined;\n  target: string | null | undefined;\n}\n\nexport interface StorybookTheme {\n  color: Color;\n\n  fgColor: typeof tokens.light.fgColor;\n  bgColor: typeof tokens.light.bgColor;\n  borderColor: typeof tokens.light.borderColor;\n\n  background: Background;\n  typography: Typography;\n  animation: Animation;\n  easing: Easing;\n\n  input: {\n    border: string;\n    background: string;\n    color: string;\n    borderRadius: number;\n  };\n\n  // UI\n  layoutMargin: number;\n  appBorderColor: string;\n  appBorderRadius: number;\n\n  // Toolbar default/active colors\n  barTextColor: string;\n  barHoverColor: string;\n  barSelectedColor: string;\n  barBg: string;\n\n  brand: Brand;\n\n  code: {\n    [key: string]: string | object;\n  };\n\n  [key: string]: any;\n}\n"
  },
  {
    "path": "code/core/src/theming/utils.ts",
    "content": "import { logger } from 'storybook/internal/client-logger';\n\nimport { global } from '@storybook/global';\n\nimport { darken, lighten, rgba } from 'polished';\n\nconst { window: globalWindow } = global;\n\nexport const mkColor = (color: string) => ({ color });\n\n// Check if it is a string. This is for the sake of warning users\n// and the successive guarding logics that use String methods.\nconst isColorString = (color: string) => {\n  if (typeof color !== 'string') {\n    logger.warn(\n      `Color passed to theme object should be a string. Instead ${color}(${typeof color}) was passed.`\n    );\n    return false;\n  }\n\n  return true;\n};\n\n// Passing arguments that can't be converted to RGB such as linear-gradient\n// to library polished's functions such as lighten or darken throws the error\n// that crashes the entire storybook. It needs to be guarded when arguments\n// of those functions are from user input.\nconst isValidColorForPolished = (color: string) => {\n  return !/(gradient|var|calc)/.test(color);\n};\n\nconst applyPolished = (type: string, color: string) => {\n  if (type === 'darken') {\n    return rgba(`${darken(1, color)}`, 0.95);\n  }\n\n  if (type === 'lighten') {\n    return rgba(`${lighten(1, color)}`, 0.95);\n  }\n\n  return color;\n};\n\nconst colorFactory = (type: string) => (color: string) => {\n  if (!isColorString(color)) {\n    return color;\n  }\n\n  if (!isValidColorForPolished(color)) {\n    return color;\n  }\n\n  // Guard anything that is not working with polished.\n  try {\n    return applyPolished(type, color);\n  } catch (error) {\n    return color;\n  }\n};\n\nexport const lightenColor = colorFactory('lighten');\nexport const darkenColor = colorFactory('darken');\n\n// The default color scheme is light so unless the preferred color\n// scheme is set to dark we always want to use the light theme\nexport const getPreferredColorScheme = () => {\n  if (!globalWindow || !globalWindow.matchMedia) {\n    return 'light';\n  }\n\n  const isDarkThemePreferred = globalWindow.matchMedia('(prefers-color-scheme: dark)').matches;\n\n  if (isDarkThemePreferred) {\n    return 'dark';\n  }\n\n  return 'light';\n};\n"
  },
  {
    "path": "code/core/src/toolbar/components/ToolbarManager.tsx",
    "content": "import React, { type FC } from 'react';\n\nimport { Separator } from 'storybook/internal/components';\n\nimport { useGlobalTypes } from 'storybook/manager-api';\n\nimport { normalizeArgType } from '../utils/normalize-toolbar-arg-type.ts';\nimport { ToolbarMenuSelect } from './ToolbarMenuSelect.tsx';\n\n/** A smart component for handling manager-preview interactions. */\nexport const ToolbarManager: FC = () => {\n  const globalTypes = useGlobalTypes();\n  const hasToolbars = Object.keys(globalTypes).some((id) => !!globalTypes[id].toolbar);\n\n  if (!hasToolbars) {\n    return null;\n  }\n\n  return (\n    <>\n      <Separator />\n      {Object.keys(globalTypes).map((id) => {\n        const normalizedArgType = normalizeArgType(id, globalTypes[id]);\n\n        return normalizedArgType && <ToolbarMenuSelect key={id} id={id} {...normalizedArgType} />;\n      })}\n    </>\n  );\n};\n"
  },
  {
    "path": "code/core/src/toolbar/components/ToolbarMenuSelect.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport { Select } from 'storybook/internal/components';\n\nimport { useGlobals, useStorybookApi } from 'storybook/manager-api';\nimport { styled } from 'storybook/theming';\n\nimport { Icons } from '../../components/components/icon/icon.tsx';\nimport type { ToolbarItem, ToolbarMenuProps } from '../types.ts';\nimport { getSelectedItem } from '../utils/get-selected.ts';\nimport { registerShortcuts } from '../utils/register-shortcuts.ts';\n\n// We can't remove the Icons component just yet because there's no way for now to import icons\n// in the preview directly. Before having a better solution, we are going to keep the Icons component\n// for now and remove the deprecated warning.\n\nconst ToolbarMenuItemContainer = styled('div')({\n  width: '100%',\n  display: 'flex',\n  alignItems: 'center',\n  gap: 8,\n});\nconst ToolbarMenuItemMiddle = styled('div')({\n  flex: 1,\n});\n\nexport const ToolbarMenuSelect: FC<ToolbarMenuProps> = ({\n  id,\n  name,\n  description,\n  toolbar: {\n    icon: _icon,\n    items,\n    title: _title,\n    preventDynamicIcon,\n    dynamicTitle = true,\n    shortcuts,\n  },\n}) => {\n  const api = useStorybookApi();\n  const [globals, updateGlobals, storyGlobals] = useGlobals();\n\n  const currentValue = globals[id];\n  const isOverridden = id in storyGlobals;\n  let icon = _icon;\n  let title = _title;\n\n  if (!preventDynamicIcon) {\n    icon = getSelectedItem({ currentValue, items })?.icon || icon;\n  }\n\n  if (dynamicTitle) {\n    title = getSelectedItem({ currentValue, items })?.title || title;\n  }\n\n  if (!title && !icon) {\n    console.warn(`Toolbar '${name}' has no title or icon`);\n  }\n\n  const resetItem = items.find((item) => item.type === 'reset');\n  const resetLabel = resetItem?.title;\n  const options = React.useMemo(\n    () =>\n      items\n        .filter((item): item is ToolbarItem => item.type === 'item')\n        .map((item) => {\n          const itemTitle = item.title ?? item.value ?? 'Untitled';\n          const iconComponent =\n            !item.hideIcon && item.icon ? (\n              <Icons icon={item.icon} __suppressDeprecationWarning={true} />\n            ) : undefined;\n\n          if (item.right) {\n            return {\n              title: itemTitle,\n              value: item.value,\n              children: (\n                <ToolbarMenuItemContainer>\n                  {iconComponent}\n                  <ToolbarMenuItemMiddle>{item.title ?? item.value}</ToolbarMenuItemMiddle>\n                  {item.right}\n                </ToolbarMenuItemContainer>\n              ),\n            };\n          } else {\n            return {\n              title: itemTitle,\n              value: item.value,\n              icon: iconComponent,\n            };\n          }\n        }),\n    [items]\n  );\n\n  React.useEffect(() => {\n    if (shortcuts) {\n      const length = options.length;\n      void registerShortcuts(api, id, {\n        next: {\n          ...shortcuts.next,\n          action: () => {\n            const idx = options.findIndex((i) => i.value === globals[id]);\n            const nextIdx = idx < 0 ? 0 : (idx + 1) % length;\n            updateGlobals({ [id]: options[nextIdx].value });\n          },\n        },\n        previous: {\n          ...shortcuts.previous,\n          action: () => {\n            const idx = options.findIndex((i) => i.value === globals[id]);\n            const previousIdx = idx < 0 ? length - 1 : (idx + length - 1) % length;\n            updateGlobals({ [id]: options[previousIdx].value });\n          },\n        },\n        reset: {\n          ...shortcuts.reset,\n          action: () => {\n            updateGlobals({ [id]: undefined });\n          },\n        },\n      });\n    }\n  }, [api, id, shortcuts, globals, options, updateGlobals]);\n\n  // FIXME: for SB 10 we would want description to become an aria-description, and to add an\n  // ariaLabel prop to tools with an automigration switching current description to ariaLabel\n  const ariaLabel = description || title || name || id;\n\n  return (\n    <Select\n      defaultOptions={[currentValue]}\n      options={options}\n      disabled={isOverridden}\n      ariaLabel={ariaLabel}\n      tooltip={ariaLabel}\n      resetLabel={resetLabel}\n      onReset={resetItem ? () => updateGlobals({ [id]: resetItem?.value }) : undefined}\n      onSelect={(selected) => updateGlobals({ [id]: selected })}\n      icon={icon && <Icons icon={icon} __suppressDeprecationWarning={true} />}\n      showSelectedOptionTitle={dynamicTitle}\n    >\n      {title}\n    </Select>\n  );\n};\n"
  },
  {
    "path": "code/core/src/toolbar/constants.ts",
    "content": "export const TOOLBAR_ID = 'toolbar' as const;\nexport const TOOLBAR_PARAM = 'toolbars' as const;\n"
  },
  {
    "path": "code/core/src/toolbar/index.ts",
    "content": "export * from './types.ts';\nexport * from './constants.ts';\nexport * from './components/ToolbarManager.tsx';\n"
  },
  {
    "path": "code/core/src/toolbar/manager.tsx",
    "content": "import React from 'react';\n\nimport { addons, types } from 'storybook/manager-api';\n\nimport { ToolbarManager } from './components/ToolbarManager.tsx';\nimport { TOOLBAR_ID } from './constants.ts';\n\n// Register the toolbar in the manager\naddons.register(TOOLBAR_ID, () =>\n  addons.add(TOOLBAR_ID, {\n    title: TOOLBAR_ID,\n    type: types.TOOL,\n    match: ({ tabId }) => !tabId,\n    render: () => <ToolbarManager />,\n  })\n);\n"
  },
  {
    "path": "code/core/src/toolbar/preview.ts",
    "content": "// The toolbar doesn't need any preview-side functionality\nexport {};\n"
  },
  {
    "path": "code/core/src/toolbar/types.ts",
    "content": "import type { InputType } from 'storybook/internal/types';\n\nimport type { IconsProps } from '../components/components/icon/icon.tsx';\n\nexport type ToolbarShortcutType = 'next' | 'previous' | 'reset';\n\nexport type ToolbarItemType = 'item' | 'reset';\n\nexport interface ToolbarShortcutConfig {\n  label: string;\n  keys: string[];\n}\n\nexport type ToolbarShortcuts = Record<ToolbarShortcutType, ToolbarShortcutConfig>;\n\nexport interface ToolbarItem {\n  value?: string;\n  icon?: IconsProps['icon'];\n  right?: string;\n  title?: string;\n  hideIcon?: boolean;\n  type?: ToolbarItemType;\n}\n\nexport interface NormalizedToolbarConfig {\n  /** The label to show for this toolbar item */\n  title?: string;\n  /** Choose an icon to show for this toolbar item */\n  icon?: IconsProps['icon'];\n  /** Set to true to prevent default update of icon to match any present selected items icon */\n  preventDynamicIcon?: boolean;\n  items: ToolbarItem[];\n  shortcuts?: ToolbarShortcuts;\n  /** Change title based on selected value */\n  dynamicTitle?: boolean;\n}\n\nexport type NormalizedToolbarArgType = {\n  name: string;\n  description: string;\n  defaultValue?: any;\n  toolbar: NormalizedToolbarConfig;\n};\n\nexport type ToolbarConfig = Omit<NormalizedToolbarConfig, 'items'> & {\n  items: (string | ToolbarItem)[];\n};\n\nexport type ToolbarArgType = {\n  name?: string;\n  description?: string;\n  defaultValue?: any;\n  toolbar?: ToolbarConfig;\n  /**\n   * @deprecated This loose index signature has been added for compatibility with InputType, and\n   *   will be removed in Storybook 11\n   */\n  [key: string]: any;\n};\n\nexport type ToolbarMenuProps = NormalizedToolbarArgType & { id: string };\n"
  },
  {
    "path": "code/core/src/toolbar/utils/get-selected.ts",
    "content": "import type { ToolbarItem } from '../types.ts';\n\ninterface GetSelectedItemProps {\n  currentValue: string | null;\n  items: ToolbarItem[];\n}\n\nexport const getSelectedItem = ({ currentValue, items }: GetSelectedItemProps) => {\n  return items.find((item) => item.value === currentValue && item.type !== 'reset');\n};\n"
  },
  {
    "path": "code/core/src/toolbar/utils/normalize-toolbar-arg-type.ts",
    "content": "import type { NormalizedToolbarArgType, ToolbarArgType, ToolbarItem } from '../types.ts';\n\nconst defaultItemValues: ToolbarItem = {\n  type: 'item',\n  value: '',\n};\n\nexport const normalizeArgType = (\n  key: string,\n  argType: ToolbarArgType\n): NormalizedToolbarArgType | null => {\n  const toolbar = argType.toolbar;\n  if (!toolbar) {\n    return null;\n  }\n  return {\n    ...argType,\n    name: argType.name || key,\n    description: argType.description || key,\n    toolbar: {\n      ...argType.toolbar,\n      items: toolbar.items.map((_item) => {\n        const item = typeof _item === 'string' ? { value: _item, title: _item } : _item;\n\n        // Cater for the special type \"reset\" which will reset value and also icon\n        // of toolbar button if any icon was present on toolbar to begin with\n        if (item.type === 'reset' && toolbar.icon) {\n          item.icon = toolbar.icon;\n          item.hideIcon = true;\n          item.value = undefined;\n        }\n\n        return { ...defaultItemValues, ...item };\n      }),\n    },\n  };\n};\n"
  },
  {
    "path": "code/core/src/toolbar/utils/register-shortcuts.ts",
    "content": "import type { API } from 'storybook/manager-api';\n\nimport { TOOLBAR_ID } from '../constants.ts';\nimport type { ToolbarShortcutConfig } from '../types.ts';\n\ninterface Shortcuts {\n  next: ToolbarShortcutConfig & { action: () => void };\n  previous: ToolbarShortcutConfig & { action: () => void };\n  reset: ToolbarShortcutConfig & { action: () => void };\n}\n\nexport const registerShortcuts = async (api: API, id: string, shortcuts: Shortcuts) => {\n  if (shortcuts.next) {\n    await api.setAddonShortcut(TOOLBAR_ID, {\n      label: shortcuts.next.label,\n      defaultShortcut: shortcuts.next.keys,\n      actionName: `${id}:next`,\n      action: shortcuts.next.action,\n    });\n  }\n\n  if (shortcuts.previous) {\n    await api.setAddonShortcut(TOOLBAR_ID, {\n      label: shortcuts.previous.label,\n      defaultShortcut: shortcuts.previous.keys,\n      actionName: `${id}:previous`,\n      action: shortcuts.previous.action,\n    });\n  }\n\n  if (shortcuts.reset) {\n    await api.setAddonShortcut(TOOLBAR_ID, {\n      label: shortcuts.reset.label,\n      defaultShortcut: shortcuts.reset.keys,\n      actionName: `${id}:reset`,\n      action: shortcuts.reset.action,\n    });\n  }\n};\n"
  },
  {
    "path": "code/core/src/types/README.md",
    "content": "# Storybook Types\n\nStorybook types exports only typescript types for storybook usage.\n\nIt exports typescript enums, which do have a runtime implementation.\nBut it should not export any implementation such as classes, methods, functions or constants.\n\nIt also has no dependencies, all the types it exports are bundled in.\n"
  },
  {
    "path": "code/core/src/types/index.ts",
    "content": "/// <reference path=\"../typings.d.ts\" />\n\nexport * from './modules/csf.ts';\nexport * from './modules/addons.ts';\nexport * from './modules/story.ts';\nexport * from './modules/core-common.ts';\nexport * from './modules/builder.ts';\nexport * from './modules/api.ts';\nexport * from './modules/docs.ts';\nexport * from './modules/api-stories.ts';\nexport * from './modules/indexer.ts';\nexport * from './modules/composedStory.ts';\nexport * from './modules/channelApi.ts';\nexport * from './modules/frameworks.ts';\nexport * from './modules/renderers.ts';\nexport * from './modules/status.ts';\nexport * from './modules/test-provider.ts';\nexport * from './modules/universal-store.ts';\nexport * from './modules/webpack.ts';\nexport * from './modules/builders.ts';\nexport * from './modules/features.ts';\nexport * from './modules/languages.ts';\n"
  },
  {
    "path": "code/core/src/types/modules/addons.ts",
    "content": "import type { FC, PropsWithChildren, ReactElement, ReactNode } from 'react';\n\nimport type { State } from '../../manager-api/index.ts';\nimport type { RenderData as RouterData } from '../../router/types.ts';\nimport type { ThemeVars } from '../../theming/types.ts';\nimport type { API_LayoutCustomisations, API_SidebarOptions } from './api.ts';\nimport type { API_HashEntry, API_StoryEntry } from './api-stories.ts';\nimport type {\n  Args,\n  ArgsStoryFn as ArgsStoryFnForFramework,\n  DecoratorFunction as DecoratorFunctionForFramework,\n  InputType,\n  LegacyStoryFn as LegacyStoryFnForFramework,\n  LoaderFunction as LoaderFunctionForFramework,\n  Parameters,\n  PartialStoryFn as PartialStoryFnForFramework,\n  Renderer,\n  StoryContext as StoryContextForFramework,\n  StoryFn as StoryFnForFramework,\n  StoryId,\n  StoryKind,\n  StoryName,\n} from './csf.ts';\nimport type { IndexEntry } from './indexer.ts';\n\nexport type Addon_Types = Exclude<\n  Addon_TypesEnum,\n  Addon_TypesEnum.experimental_PAGE | Addon_TypesEnum.experimental_TEST_PROVIDER\n>;\n\nexport interface Addon_ArgType<TArg = unknown> extends InputType {\n  defaultValue?: TArg;\n}\n\nexport type Addons_ArgTypes<TArgs = Args> = {\n  [key in keyof Partial<TArgs>]: Addon_ArgType<TArgs[key]>;\n} & {\n  // for custom defined args\n  [key in string]: Addon_ArgType<unknown>;\n};\n\nexport type Addon_Comparator<T> = ((a: T, b: T) => boolean) | ((a: T, b: T) => number);\nexport type Addon_StorySortMethod = 'configure' | 'alphabetical';\nexport interface Addon_StorySortObjectParameter {\n  method?: Addon_StorySortMethod;\n  order?: any[];\n  locales?: string;\n  includeNames?: boolean;\n}\n\n// The `any` here is the story store's `StoreItem` record. Ideally we should probably only\n// pass a defined subset of that full data, but we pass it all so far :shrug:\nexport type IndexEntryLegacy = [StoryId, any, Parameters, Parameters];\nexport type Addon_StorySortComparator = Addon_Comparator<IndexEntryLegacy>;\nexport type Addon_StorySortParameter = Addon_StorySortComparator | Addon_StorySortObjectParameter;\nexport type Addon_StorySortComparatorV7 = Addon_Comparator<IndexEntry>;\nexport type Addon_StorySortParameterV7 =\n  | Addon_StorySortComparatorV7\n  | Addon_StorySortObjectParameter;\n\n// TODO: remove all these types, they belong in the renderer and csf-package\n\nexport interface Addon_OptionsParameter extends Object {\n  storySort?: Addon_StorySortParameter;\n  theme?: {\n    base: string;\n    brandTitle?: string;\n  };\n  [key: string]: any;\n}\n\nexport interface Addon_OptionsParameterV7 extends Object {\n  storySort?: Addon_StorySortParameterV7;\n  theme?: {\n    base: string;\n    brandTitle?: string;\n  };\n  [key: string]: any;\n}\n\nexport type Addon_StoryContext<TRenderer extends Renderer = Renderer> =\n  StoryContextForFramework<TRenderer>;\nexport type Addon_StoryContextUpdate = Partial<Addon_StoryContext>;\n\ninterface Addon_ReturnTypeFramework<ReturnType> extends Renderer {\n  component: any;\n  storyResult: ReturnType;\n  canvasElement: any;\n}\nexport type Addon_PartialStoryFn<ReturnType = unknown> = PartialStoryFnForFramework<\n  Addon_ReturnTypeFramework<ReturnType>\n>;\nexport type Addon_LegacyStoryFn<ReturnType = unknown> = LegacyStoryFnForFramework<\n  Addon_ReturnTypeFramework<ReturnType>\n>;\nexport type Addon_ArgsStoryFn<ReturnType = unknown> = ArgsStoryFnForFramework<\n  Addon_ReturnTypeFramework<ReturnType>\n>;\nexport type Addon_StoryFn<ReturnType = unknown> = StoryFnForFramework<\n  Addon_ReturnTypeFramework<ReturnType>\n>;\n\nexport type Addon_DecoratorFunction<StoryFnReturnType = unknown> = DecoratorFunctionForFramework<\n  Addon_ReturnTypeFramework<StoryFnReturnType>\n>;\nexport type Addon_LoaderFunction = LoaderFunctionForFramework<Addon_ReturnTypeFramework<unknown>>;\n\nexport interface Addon_WrapperSettings {\n  options: object;\n  parameters: {\n    [key: string]: any;\n  };\n}\n\nexport type Addon_StoryWrapper = (\n  storyFn: Addon_LegacyStoryFn,\n  context: Addon_StoryContext,\n  settings: Addon_WrapperSettings\n) => any;\n\nexport type Addon_MakeDecoratorResult = (...args: any) => any;\n\nexport interface Addon_AddStoryArgs<StoryFnReturnType = unknown> {\n  id: StoryId;\n  kind: StoryKind;\n  name: StoryName;\n  storyFn: Addon_StoryFn<StoryFnReturnType>;\n  parameters: Parameters;\n}\n\nexport type Addon_ClientApiAddon<StoryFnReturnType = unknown> = Addon_Type & {\n  apply: (a: Addon_StoryApi<StoryFnReturnType>, b: any[]) => any;\n};\n\nexport interface Addon_ClientApiAddons<StoryFnReturnType> {\n  [key: string]: Addon_ClientApiAddon<StoryFnReturnType>;\n}\n\nexport type Addon_ClientApiReturnFn<StoryFnReturnType = unknown> = (\n  ...args: any[]\n) => Addon_StoryApi<StoryFnReturnType>;\n\nexport interface Addon_StoryApi<StoryFnReturnType = unknown> {\n  kind: StoryKind;\n  add: (\n    storyName: StoryName,\n    storyFn: Addon_StoryFn<StoryFnReturnType>,\n    parameters?: Parameters\n  ) => Addon_StoryApi<StoryFnReturnType>;\n  addDecorator: (\n    decorator: Addon_DecoratorFunction<StoryFnReturnType>\n  ) => Addon_StoryApi<StoryFnReturnType>;\n  addLoader: (decorator: Addon_LoaderFunction) => Addon_StoryApi<StoryFnReturnType>;\n  addParameters: (parameters: Parameters) => Addon_StoryApi<StoryFnReturnType>;\n  [k: string]: string | Addon_ClientApiReturnFn<StoryFnReturnType>;\n}\n\nexport interface Addon_ClientStoryApi<StoryFnReturnType = unknown> {}\n\nexport type Addon_LoadFn = () => any;\nexport type Addon_RequireContext = any; // FIXME\nexport type Addon_Loadable = Addon_RequireContext | [Addon_RequireContext] | Addon_LoadFn;\n\n// CSF types, to be re-org'ed in 6.1\n\nexport type Addon_BaseDecorators<StoryFnReturnType> = Array<\n  (story: () => StoryFnReturnType, context: Addon_StoryContext) => StoryFnReturnType\n>;\n\nexport interface Addon_BaseAnnotations<\n  TArgs,\n  StoryFnReturnType,\n  TRenderer extends Renderer = Renderer,\n> {\n  /**\n   * Dynamic data that are provided (and possibly updated by) Storybook and its addons.\n   *\n   * @see [Arg story inputs](https://storybook.js.org/docs/api/csf#args-story-inputs)\n   */\n  args?: Partial<TArgs>;\n\n  /**\n   * ArgTypes encode basic metadata for args, such as `name`, `description`, `defaultValue` for an\n   * arg. These get automatically filled in by Storybook Docs.\n   *\n   * @see [Arg types](https://storybook.js.org/docs/api/arg-types)\n   */\n  argTypes?: Addons_ArgTypes<TArgs>;\n\n  /**\n   * Custom metadata for a story.\n   *\n   * @see [Parameters](https://storybook.js.org/docs/writing-stories/parameters)\n   */\n  parameters?: Parameters;\n\n  /**\n   * Wrapper components or Storybook decorators that wrap a story.\n   *\n   * Decorators defined in Meta will be applied to every story variation.\n   *\n   * @see [Decorators](https://storybook.js.org/docs/writing-stories/decorators)\n   */\n  decorators?: Addon_BaseDecorators<StoryFnReturnType>;\n\n  /**\n   * Define a custom render function for the story(ies). If not passed, a default render function by\n   * the framework will be used.\n   */\n  render?: (args: TArgs, context: Addon_StoryContext<TRenderer>) => StoryFnReturnType;\n\n  /** Function that is executed after the story is rendered. */\n  play?: (context: Addon_StoryContext<TRenderer>) => Promise<void> | void;\n}\n\nexport interface Addon_Annotations<TArgs, StoryFnReturnType> extends Addon_BaseAnnotations<\n  TArgs,\n  StoryFnReturnType\n> {\n  /**\n   * Used to only include certain named exports as stories. Useful when you want to have non-story\n   * exports such as mock data or ignore a few stories.\n   *\n   * @example\n   *\n   * ```ts\n   * includeStories: ['SimpleStory', 'ComplexStory'];\n   * includeStories: /.*Story$/;\n   * ```\n   *\n   * @see [Non-story exports](https://storybook.js.org/docs/api/csf#non-story-exports)\n   */\n  includeStories?: string[] | RegExp;\n\n  /**\n   * Used to exclude certain named exports. Useful when you want to have non-story exports such as\n   * mock data or ignore a few stories.\n   *\n   * @example\n   *\n   * ```ts\n   * excludeStories: ['simpleData', 'complexData'];\n   * excludeStories: /.*Data$/;\n   * ```\n   *\n   * @see [Non-story exports](https://storybook.js.org/docs/api/csf#non-story-exports)\n   */\n  excludeStories?: string[] | RegExp;\n}\n\nexport interface Addon_BaseMeta<ComponentType> {\n  /**\n   * Title of the story which will be presented in the navigation. **Should be unique.**\n   *\n   * Stories can be organized in a nested structure using \"/\" as a separator.\n   *\n   * Since CSF 3.0 this property is optional.\n   *\n   * @example\n   *\n   * ```ts\n   * export default { title: 'Design System/Atoms/Button' };\n   * ```\n   *\n   * @see [Story Hierarchy](https://storybook.js.org/docs/writing-stories/naming-components-and-hierarchy)\n   */\n  title?: string;\n\n  /**\n   * Manually set the id of a story, which in particular is useful if you want to rename stories\n   * without breaking permalinks.\n   *\n   * Storybook will prioritize the id over the title for ID generation, if provided, and will\n   * prioritize the story.storyName over the export key for display.\n   *\n   * @see [Sidebar and URLs](https://storybook.js.org/docs/configure/user-interface/sidebar-and-urls#permalink-to-stories)\n   */\n  id?: string;\n\n  /**\n   * The primary component for your story.\n   *\n   * Used by addons for automatic prop table generation and display of other component metadata.\n   */\n  component?: ComponentType;\n\n  /**\n   * Auxiliary sub-components that are part of the stories.\n   *\n   * Used by addons for automatic prop table generation and display of other component metadata.\n   *\n   * @example\n   *\n   * ```ts\n   * import { Button, ButtonGroup } from './components';\n   *\n   * export default {\n   *   subcomponents: { Button, ButtonGroup },\n   * };\n   * ```\n   *\n   * By defining them each component will have its tab in the args table.\n   */\n  subcomponents?: Record<string, ComponentType>;\n}\n\nexport type Addon_BaseStoryObject<TArgs, StoryFnReturnType> = {\n  /** Override the display name in the UI */\n  storyName?: string;\n};\n\nexport type Addon_BaseStoryFn<TArgs, StoryFnReturnType> = {\n  (args: TArgs, context: Addon_StoryContext): StoryFnReturnType;\n} & Addon_BaseStoryObject<TArgs, StoryFnReturnType>;\n\nexport type BaseStory<TArgs, StoryFnReturnType> =\n  | Addon_BaseStoryFn<TArgs, StoryFnReturnType>\n  | Addon_BaseStoryObject<TArgs, StoryFnReturnType>;\n\nexport interface Addon_RenderOptions {\n  active: boolean;\n}\n\nexport type Addon_Type =\n  | Addon_BaseType\n  | Addon_PageType\n  | Addon_WrapperType\n  | Addon_TestProviderType;\nexport interface Addon_BaseType {\n  /**\n   * The title of the addon. This can be a simple string, but it can also be a\n   * React.FunctionComponent or a React.ReactElement.\n   */\n  title: FC | ReactNode | (() => string);\n  /**\n   * The type of the addon.\n   *\n   * @example\n   *\n   * ```ts\n   * Addon_TypesEnum.PANEL;\n   * ```\n   */\n  type: Exclude<\n    Addon_Types,\n    | Addon_TypesEnum.PREVIEW\n    | Addon_TypesEnum.experimental_PAGE\n    | Addon_TypesEnum.experimental_TEST_PROVIDER\n  >;\n  /**\n   * The unique id of the addon.\n   *\n   * @example 'my-org-name/my-addon-name';\n   *\n   * @warn This will become non-optional in 8.0\n   *\n   * This needs to be globally unique, so we recommend prefixing it with your org name or npm package name.\n   *\n   * Do not prefix with `storybook`, this is reserved for core storybook feature and core addons.\n   */\n  id?: string;\n  /**\n   * This component will wrap your `render` function.\n   *\n   * With it you can determine if you want your addon to be rendered or not.\n   *\n   * This is to facilitate addons keeping state, and keep listening for events even when they are\n   * not currently on screen/rendered.\n   */\n  route?: (routeOptions: RouterData) => string;\n  /** This will determine the value of `active` prop of your render function. */\n  match?: (matchOptions: RouterData & { tabId?: string }) => boolean;\n  /**\n   * The actual contents of your addon.\n   *\n   * This is called as a function, so if you want to use hooks, your function needs to return a\n   * JSX.Element within which components are rendered\n   */\n  render: (props: Partial<Addon_RenderOptions>) => ReturnType<FC<Partial<Addon_RenderOptions>>>;\n  // TODO: for Storybook 9 I'd like to change this to be:\n  // render: FC<Partial<Addon_RenderOptions>>;\n  // This would bring it in line with how every other addon is set up.\n  // We'd need to change how the render function is called in the manager:\n  // https://github.com/storybookjs/storybook/blob/4e6fc0dde0842841d99cb3cf5148ca293a950301/code/ui/manager/src/components/preview/Preview.tsx#L105\n  /** @unstable */\n  paramKey?: string;\n  /** @unstable */\n  disabled?: boolean | ((parameters: API_StoryEntry['parameters']) => boolean);\n  /** @unstable */\n  hidden?: boolean;\n}\n\nexport interface Addon_PageType {\n  type: Addon_TypesEnum.experimental_PAGE;\n  /** The unique id of the page. */\n  id: string;\n  /** The URL to navigate to when Storybook needs to navigate to this page. */\n  url: string;\n  /** The title is used in mobile mode to represent the page in the navigation. */\n  title: FC | string | ReactElement | ReactNode;\n  /**\n   * The main content of the addon, a function component without any props. Storybook will render\n   * your component always.\n   *\n   * If you want to render your component only when the URL matches, use the `Route` component.\n   *\n   * @example\n   *\n   * ```jsx\n   * import { Route } from 'storybook/internal/router';\n   *\n   * Render: () => {\n   *   return (\n   *     <Route path=\"/my-addon\">\n   *       {' '}\n   *       <MyAddonContent />{' '}\n   *     </Route>\n   *   );\n   * };\n   * ```\n   */\n  render: FC;\n}\n\nexport interface Addon_WrapperType {\n  type: Addon_TypesEnum.PREVIEW;\n  /** The unique id of the page. */\n  id: string;\n  /**\n   * A React.FunctionComponent that wraps the story.\n   *\n   * This component must accept a children prop, and render it.\n   */\n  render: FC<\n    PropsWithChildren<{\n      index: number;\n      children: ReactNode;\n      id: string;\n      storyId: StoryId;\n    }>\n  >;\n}\n\nexport interface Addon_TestProviderType {\n  type: Addon_TypesEnum.experimental_TEST_PROVIDER;\n  /** The unique id of the test provider. */\n  id: string;\n  render: () => ReactNode;\n  sidebarContextMenu?: (options: { context: API_HashEntry }) => ReactNode;\n}\n\ntype Addon_TypeBaseNames = Exclude<\n  Addon_TypesEnum,\n  | Addon_TypesEnum.PREVIEW\n  | Addon_TypesEnum.experimental_PAGE\n  | Addon_TypesEnum.experimental_TEST_PROVIDER\n>;\n\nexport interface Addon_TypesMapping extends Record<Addon_TypeBaseNames, Addon_BaseType> {\n  [Addon_TypesEnum.PREVIEW]: Addon_WrapperType;\n  [Addon_TypesEnum.experimental_PAGE]: Addon_PageType;\n  [Addon_TypesEnum.experimental_TEST_PROVIDER]: Addon_TestProviderType;\n}\n\nexport type Addon_Loader<API> = (api: API) => void;\n\nexport interface Addon_Loaders<API> {\n  [key: string]: Addon_Loader<API>;\n}\nexport interface Addon_Collection<T = Addon_Type> {\n  [key: string]: T;\n}\nexport interface Addon_Elements {\n  [key: string]: Addon_Collection;\n}\nexport interface Addon_ToolbarConfig {\n  hidden?: boolean;\n}\nexport interface Addon_Config {\n  theme?: ThemeVars;\n  layoutCustomisations?: {\n    showPanel?: API_LayoutCustomisations['showPanel'];\n    showSidebar?: API_LayoutCustomisations['showSidebar'];\n    showToolbar?: API_LayoutCustomisations['showToolbar'];\n  };\n  toolbar?: {\n    [id: string]: Addon_ToolbarConfig;\n  };\n  sidebar?: API_SidebarOptions;\n  [key: string]: any;\n}\n\nexport enum Addon_TypesEnum {\n  /**\n   * This API is used to create a tab the toolbar above the canvas, This API might be removed in the\n   * future.\n   *\n   * @unstable\n   */\n  TAB = 'tab',\n  /** This adds panels to the addons side panel. */\n  PANEL = 'panel',\n  /** This adds items in the toolbar above the canvas - on the left side. */\n  TOOL = 'tool',\n  /** This adds items in the toolbar above the canvas - on the right side. */\n  TOOLEXTRA = 'toolextra',\n  /**\n   * This adds wrapper components around the canvas/iframe component storybook renders.\n   *\n   * @unstable this API is not stable yet, and is likely to change in 8.0.\n   */\n  PREVIEW = 'preview',\n  /**\n   * This adds pages that render instead of the canvas.\n   *\n   * @unstable\n   */\n  experimental_PAGE = 'page',\n  /** This adds items to the Testing Module in the sidebar. */\n  experimental_TEST_PROVIDER = 'test-provider',\n}\n"
  },
  {
    "path": "code/core/src/types/modules/api-stories.ts",
    "content": "import type { DocsOptions } from './core-common.ts';\nimport type { ArgTypes, Args, ComponentTitle, Parameters, Path, StoryId, Tag } from './csf.ts';\nimport type { IndexEntry } from './indexer.ts';\nimport type { StatusByTypeId } from './status.ts';\n\nexport interface API_BaseEntry {\n  id: StoryId;\n  depth: number;\n  name: string;\n  tags: Tag[];\n  refId?: string;\n  renderLabel?: (item: API_HashEntry, api: any) => any;\n}\n\nexport interface API_RootEntry extends API_BaseEntry {\n  type: 'root';\n  startCollapsed?: boolean;\n  children: StoryId[];\n}\n\nexport interface API_GroupEntry extends API_BaseEntry {\n  type: 'group';\n  parent?: StoryId;\n  children: StoryId[];\n}\n\nexport interface API_ComponentEntry extends API_BaseEntry {\n  type: 'component';\n  parent?: StoryId;\n  children: StoryId[];\n  importPath?: Path;\n}\n\nexport interface API_DocsEntry extends API_BaseEntry {\n  type: 'docs';\n  parent: StoryId;\n  title: ComponentTitle;\n  importPath: Path;\n  prepared: boolean;\n  parameters?: {\n    [parameterName: string]: any;\n  };\n}\n\nexport interface API_StoryEntry extends API_BaseEntry {\n  type: 'story';\n  subtype: 'story';\n  parent: StoryId;\n  title: ComponentTitle;\n  importPath: Path;\n  exportName: string;\n  prepared: boolean;\n  parameters?: {\n    [parameterName: string]: any;\n  };\n  args?: Args;\n  argTypes?: ArgTypes;\n  initialArgs?: Args;\n  children?: StoryId[];\n}\n\nexport interface API_TestEntry extends Omit<API_StoryEntry, 'subtype' | 'children'> {\n  subtype: 'test';\n}\n\nexport type API_LeafEntry = API_DocsEntry | API_StoryEntry | API_TestEntry;\nexport type API_HashEntry =\n  | API_RootEntry\n  | API_GroupEntry\n  | API_ComponentEntry\n  | API_DocsEntry\n  | API_StoryEntry\n  | API_TestEntry;\n\n/**\n * The `IndexHash` is our manager-side representation of the `StoryIndex`. We create entries in the\n * hash not only for each story or docs entry, but also for each \"group\" of the component (split on\n * '/'), as that's how things are manipulated in the manager (i.e. in the sidebar)\n */\nexport interface API_IndexHash {\n  [id: string]: API_HashEntry;\n}\n// We used to received a bit more data over the channel on the SET_STORIES event, including\n// the full parameters for each story.\nexport type API_PreparedIndexEntry = IndexEntry & {\n  parameters?: Parameters;\n  argTypes?: ArgTypes;\n  args?: Args;\n  initialArgs?: Args;\n};\nexport interface API_PreparedStoryIndex {\n  v: number;\n  entries: Record<StoryId, API_PreparedIndexEntry>;\n}\n\nexport type API_OptionsData = {\n  docsOptions: DocsOptions;\n};\n\nexport interface API_ReleaseNotes {\n  success?: boolean;\n  currentVersion?: string;\n  showOnFirstLaunch?: boolean;\n}\n\nexport interface API_Settings {\n  lastTrackedStoryId: string;\n}\n\nexport interface API_Version {\n  version: string;\n  info?: { plain: string };\n  [key: string]: any;\n}\n\nexport interface API_UnknownEntries {\n  [key: string]: {\n    [key: string]: any;\n  };\n}\n\nexport interface API_Versions {\n  latest?: API_Version;\n  next?: API_Version;\n  current?: API_Version;\n}\n\nexport type API_FilterFunction = (\n  item: API_PreparedIndexEntry & { statuses: StatusByTypeId }\n) => boolean;\n"
  },
  {
    "path": "code/core/src/types/modules/api.ts",
    "content": "import type { ReactElement } from 'react';\n\nimport type { Channel } from '../../channels/index.ts';\nimport type { State } from '../../manager-api/index.ts';\nimport type { RenderData } from '../../router/types.ts';\nimport type { ThemeVars } from '../../theming/types.ts';\nimport type { Addon_RenderOptions } from './addons.ts';\nimport type {\n  API_FilterFunction,\n  API_HashEntry,\n  API_IndexHash,\n  API_PreparedIndexEntry,\n} from './api-stories.ts';\nimport type { SetStoriesStory, SetStoriesStoryData } from './channelApi.ts';\nimport type { DocsOptions } from './core-common.ts';\nimport type { StoryIndex } from './indexer.ts';\n\ntype OrString<T extends string> = T | (string & {});\n\nexport type API_ViewMode = OrString<'story' | 'docs' | 'settings'> | undefined;\n\nexport type API_RenderOptions = Addon_RenderOptions;\n\nexport interface API_RouteOptions {\n  storyId: string;\n  viewMode: API_ViewMode;\n  location: RenderData['location'];\n  path: string;\n}\nexport interface API_MatchOptions {\n  storyId: string;\n  viewMode: API_ViewMode;\n  location: RenderData['location'];\n  path: string;\n}\n\nexport type API_StateMerger<S> = (input: S) => S;\n\nexport interface API_ProviderData<API> {\n  provider: API_Provider<API>;\n  docsOptions: DocsOptions;\n}\n\nexport interface API_Provider<API> {\n  channel?: Channel;\n  renderPreview?: API_IframeRenderer;\n  handleAPI(api: API): void;\n  getConfig(): {\n    sidebar?: API_SidebarOptions<API>;\n    theme?: ThemeVars;\n    StoryMapper?: API_StoryMapper;\n    [k: string]: any;\n  } & Partial<API_UIOptions>;\n  [key: string]: any;\n}\n\nexport type API_IframeRenderer = (\n  storyId: string,\n  viewMode: API_ViewMode,\n  id: string,\n  baseUrl: string,\n  scale: number,\n  queryParams: Record<string, any>\n) => ReactElement<any, any> | null;\n\nexport interface API_UIOptions {\n  name?: string;\n  url?: string;\n  goFullScreen: boolean;\n  showStoriesPanel: boolean;\n  showAddonPanel: boolean;\n  addonPanelInRight: boolean;\n  theme?: ThemeVars;\n  selectedPanel?: string;\n}\n\nexport type FilterFunction = (entry: API_PreparedIndexEntry, excluded?: boolean) => boolean;\n\nexport interface API_Layout {\n  initialActive: API_ActiveTabsType;\n  navSize: number;\n  bottomPanelHeight: number;\n  rightPanelWidth: number;\n  /**\n   * The sizes of the panels when they were last visible used to restore the sizes when the panels\n   * are shown again eg. when toggling fullscreen, panels, etc.\n   */\n  recentVisibleSizes: {\n    navSize: number;\n    bottomPanelHeight: number;\n    rightPanelWidth: number;\n  };\n  panelPosition: API_PanelPositions;\n  showTabs: boolean;\n  showToolbar: boolean;\n}\n\nexport interface API_LayoutCustomisations {\n  showPanel?: (state: State, defaultValue: boolean) => boolean | undefined;\n  showSidebar?: (state: State, defaultValue: boolean) => boolean | undefined;\n  showToolbar?: (state: State, defaultValue: boolean) => boolean | undefined;\n}\n\nexport interface API_UI {\n  name?: string;\n  url?: string;\n  enableShortcuts: boolean;\n}\n\nexport type API_PanelPositions = 'bottom' | 'right';\nexport type API_ActiveTabsType = 'sidebar' | 'canvas' | 'addons';\n\nexport interface API_SidebarOptions<API = any> {\n  showRoots?: boolean;\n  filters?: Record<string, API_FilterFunction>;\n  collapsedRoots?: string[];\n  renderLabel?: (item: API_HashEntry, api: API) => any;\n}\n\ninterface OnClearOptions {\n  /** `true` when the user manually dismissed the notification. */\n  dismissed: boolean;\n  /** `true` when the notification timed out after the set duration. */\n  timeout: boolean;\n}\n\ninterface OnClickOptions {\n  /** Function to dismiss the notification. */\n  onDismiss: () => void;\n}\n\nexport interface API_Notification {\n  id: string;\n  content: {\n    headline: string;\n    subHeadline?: string | any;\n  };\n  duration?: number;\n  link?: string;\n  icon?: React.ReactNode;\n  onClear?: (options: OnClearOptions) => void;\n  onClick?: (options: OnClickOptions) => void;\n}\n\ntype API_Versions = Record<string, string>;\n\nexport type API_SetRefData = Partial<\n  API_ComposedRef & {\n    setStoriesData: SetStoriesStoryData;\n    storyIndex: StoryIndex;\n  }\n>;\n\nexport type API_StoryMapper = (ref: API_ComposedRef, story: SetStoriesStory) => SetStoriesStory;\n\nexport interface API_LoadedRefData {\n  index?: API_IndexHash;\n  filteredIndex?: API_IndexHash;\n  indexError?: Error;\n  previewInitialized: boolean;\n}\n\nexport interface API_ComposedRef extends API_LoadedRefData {\n  id: string;\n  title?: string;\n  url: string;\n  type?: 'auto-inject' | 'unknown' | 'lazy' | 'server-checked';\n  expanded?: boolean;\n  versions?: API_Versions;\n  loginUrl?: string;\n  version?: string;\n  sourceUrl?: string;\n  /** DO NOT USE THIS */\n  internal_index?: StoryIndex;\n}\n\nexport type API_ComposedRefUpdate = Partial<\n  Pick<\n    API_ComposedRef,\n    | 'title'\n    | 'type'\n    | 'expanded'\n    | 'index'\n    | 'filteredIndex'\n    | 'versions'\n    | 'loginUrl'\n    | 'version'\n    | 'indexError'\n    | 'previewInitialized'\n    | 'sourceUrl'\n    | 'internal_index'\n  >\n>;\n\nexport type API_Refs = Record<string, API_ComposedRef>;\nexport type API_RefId = string;\nexport type API_RefUrl = string;\n"
  },
  {
    "path": "code/core/src/types/modules/builder.ts",
    "content": "export interface BuilderStats {\n  //\n  toJson: () => any;\n}\n\nexport type Builder_WithRequiredProperty<Type, Key extends keyof Type> = Type & {\n  [Property in Key]-?: Type[Property];\n};\n\nexport type Builder_Unpromise<T extends Promise<any>> = T extends Promise<infer U> ? U : never;\n\nexport type Builder_EnvsRaw = Record<string, string>;\n"
  },
  {
    "path": "code/core/src/types/modules/builders.ts",
    "content": "export enum SupportedBuilder {\n  // CORE\n  WEBPACK5 = 'webpack5',\n  VITE = 'vite',\n  // COMMUNITY\n  RSBUILD = 'rsbuild',\n}\n"
  },
  {
    "path": "code/core/src/types/modules/channelApi.ts",
    "content": "import type { API_ViewMode } from './api.ts';\nimport type {\n  ArgTypes,\n  Args,\n  ComponentId,\n  GlobalTypes,\n  Globals,\n  Parameters,\n  StoryId,\n  StoryKind,\n} from './csf.ts';\n\n// The data received on the (legacy) `setStories` event\nexport interface SetStoriesStory {\n  id: StoryId;\n  name: string;\n  refId?: string;\n  componentId?: ComponentId;\n  kind: StoryKind;\n  parameters: {\n    fileName: string;\n    options: {\n      [optionName: string]: any;\n    };\n    docsOnly?: boolean;\n    viewMode?: API_ViewMode;\n    [parameterName: string]: any;\n  };\n  argTypes?: ArgTypes;\n  args?: Args;\n  initialArgs?: Args;\n}\n\nexport interface SetStoriesStoryData {\n  [id: string]: SetStoriesStory;\n}\n\nexport type SetStoriesPayload =\n  | {\n      v: 2;\n      error?: Error;\n      globals: Args;\n      globalParameters: Parameters;\n      stories: SetStoriesStoryData;\n      kindParameters: {\n        [kind: string]: Parameters;\n      };\n    }\n  | ({\n      v?: number;\n      stories: SetStoriesStoryData;\n    } & Record<string, never>);\n\nexport interface SetGlobalsPayload {\n  // userGlobals\n  globals: Globals;\n  globalTypes: GlobalTypes;\n}\n\nexport interface GlobalsUpdatedPayload {\n  initialGlobals: Globals;\n  userGlobals: Globals;\n  storyGlobals: Globals;\n  globals: Globals;\n}\n\nexport interface StoryPreparedPayload {\n  id: StoryId;\n  parameters: Parameters;\n  argTypes: ArgTypes;\n  initialArgs: Args;\n  args: Args;\n}\n\nexport interface DocsPreparedPayload {\n  id: StoryId;\n  parameters: Parameters;\n}\n"
  },
  {
    "path": "code/core/src/types/modules/composedStory.ts",
    "content": "import type {\n  Globals,\n  ProjectAnnotations,\n  Renderer,\n  StoryContext,\n  StoryId,\n  StrictArgTypes,\n  Tag,\n} from 'storybook/internal/csf';\n\nimport type { ReporterAPI } from '../../preview-api/index.ts';\nimport type {\n  AnnotatedStoryFn,\n  Args,\n  ComponentAnnotations,\n  Parameters,\n  StoryAnnotations,\n  StoryAnnotationsOrFn,\n} from './csf.ts';\n\n// TODO -- I think the name \"CSFExports\" overlaps here a bit with the types in csfFile.ts\n// we might want to reconcile @yannbf\nexport type Store_CSFExports<TRenderer extends Renderer = Renderer, TArgs extends Args = Args> = {\n  default: ComponentAnnotations<TRenderer, TArgs>;\n  __esModule?: boolean;\n  __namedExportsOrder?: string[];\n};\n\n/** A story function with partial args, used internally by composeStory */\nexport type PartialArgsStoryFn<TRenderer extends Renderer = Renderer, TArgs = Args> = (\n  args?: TArgs\n) => (TRenderer & {\n  T: TArgs;\n})['storyResult'];\n\n/**\n * A story that got recomposed for portable stories, containing all the necessary data to be\n * rendered in external environments\n */\nexport type ComposedStoryFn<\n  TRenderer extends Renderer = Renderer,\n  TArgs = Args,\n> = PartialArgsStoryFn<TRenderer, TArgs> & {\n  args: TArgs;\n  id: StoryId;\n  play?: (context?: Partial<StoryContext<TRenderer, Partial<TArgs>>>) => Promise<void>;\n  run: (context?: Partial<StoryContext<TRenderer, Partial<TArgs>>>) => Promise<void>;\n  load: () => Promise<void>;\n  storyName: string;\n  parameters: Parameters;\n  argTypes: StrictArgTypes<TArgs>;\n  reporting: ReporterAPI;\n  tags: Tag[];\n  globals: Globals;\n};\n/**\n * Based on a module of stories, it returns all stories within it, filtering non-stories Each story\n * will have partial props, as their props should be handled when composing stories\n */\nexport type StoriesWithPartialProps<TRenderer extends Renderer, TModule> = {\n  // T represents the whole ES module of a stories file. K of T means named exports (basically the Story type)\n  // 1. pick the keys K of T that have properties that are Story<AnyProps>\n  // 2. infer the actual prop type for each Story\n  // 3. reconstruct Story with Partial. Story<Props> -> Story<Partial<Props>>\n  [K in keyof TModule as TModule[K] extends StoryAnnotationsOrFn<infer _, infer _TProps>\n    ? K\n    : never]: TModule[K] extends StoryAnnotationsOrFn<infer _, infer TProps>\n    ? ComposedStoryFn<TRenderer, Partial<TProps>>\n    : unknown;\n};\n\n/**\n * Type used for integrators of portable stories, as reference when creating their own composeStory\n * function\n */\nexport interface ComposeStoryFn<TRenderer extends Renderer = Renderer, TArgs extends Args = Args> {\n  (\n    storyAnnotations: AnnotatedStoryFn<TRenderer, TArgs> | StoryAnnotations<TRenderer, TArgs>,\n    componentAnnotations: ComponentAnnotations<TRenderer, TArgs>,\n    projectAnnotations: ProjectAnnotations<TRenderer>,\n    exportsName?: string\n  ): ComposedStoryFn;\n}\n"
  },
  {
    "path": "code/core/src/types/modules/core-common.ts",
    "content": "// should be node:http, but that caused the ui/manager to fail to build, might be able to switch this back once ui/manager is in the core\nimport type { ChannelLike } from 'storybook/internal/channels';\nimport type { FileSystemCache } from 'storybook/internal/common';\nimport type { StoryIndexGenerator } from 'storybook/internal/core-server';\nimport type { CsfFile } from 'storybook/internal/csf-tools';\nimport type { LogLevel } from 'storybook/internal/node-logger';\n\nimport type { Server as HttpServer, IncomingMessage, ServerResponse } from 'http';\nimport type { Server as NetServer } from 'net';\nimport type { Options as TelejsonOptions } from 'telejson';\nimport type { PackageJson as PackageJsonFromTypeFest } from 'type-fest';\n\nimport type { SupportedBuilder } from './builders.ts';\nimport type { SupportedFramework } from './frameworks.ts';\nimport type { Indexer, StoriesEntry } from './indexer.ts';\nimport type { SupportedRenderer } from './renderers.ts';\n\n/** ⚠️ This file contains internal WIP types they MUST NOT be exported outside this package for now! */\n\nexport type BuilderName = 'webpack5' | '@storybook/builder-webpack5' | string;\nexport type RendererName = string;\n\nexport interface CoreConfig {\n  builder?:\n    | BuilderName\n    | {\n        name: BuilderName;\n        options?: Record<string, any>;\n      };\n  renderer?: RendererName;\n  disableWebpackDefaults?: boolean;\n  channelOptions?: Partial<TelejsonOptions> & { wsToken?: string };\n  /** Disables the generation of project.json, a file containing Storybook metadata */\n  disableProjectJson?: boolean;\n  /**\n   * Disables Storybook telemetry\n   *\n   * @see https://storybook.js.org/telemetry\n   */\n  disableTelemetry?: boolean;\n\n  /** Disables notifications for Storybook updates. */\n  disableWhatsNewNotifications?: boolean;\n  /**\n   * Enable crash reports to be sent to Storybook telemetry\n   *\n   * @see https://storybook.js.org/telemetry\n   */\n  enableCrashReports?: boolean;\n  /**\n   * Enable hostname validation, currently only for WebSocket connections. Set to `[]` to disallow\n   * all hosts except known local/network address, or `true` to allow all hosts.\n   */\n  allowedHosts?: string[] | true;\n  /**\n   * Enable CORS headings to run document in a \"secure context\" see:\n   * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements\n   * This enables these headers in development-mode: Cross-Origin-Opener-Policy: same-origin\n   *\n   * ```text\n   * Cross-Origin-Embedder-Policy: require-corp\n   * ```\n   */\n  crossOriginIsolated?: boolean;\n}\n\ninterface DirectoryMapping {\n  from: string;\n  to: string;\n}\n\nexport interface Presets {\n  apply(\n    extension: 'typescript',\n    config: TypescriptOptions,\n    args?: Options\n  ): Promise<TypescriptOptions>;\n  apply(extension: 'framework', config?: {}, args?: any): Promise<Preset>;\n  apply(extension: 'babel', config?: {}, args?: any): Promise<any>;\n  apply(extension: 'swc', config?: {}, args?: any): Promise<any>;\n  apply(extension: 'entries', config?: [], args?: any): Promise<unknown>;\n  apply(extension: 'env', config?: {}, args?: any): Promise<any>;\n  apply(extension: 'stories', config?: [], args?: any): Promise<StoriesEntry[]>;\n  apply(extension: 'managerEntries', config: [], args?: any): Promise<string[]>;\n  apply(extension: 'refs', config?: [], args?: any): Promise<StorybookConfigRaw['refs']>;\n  apply(\n    extension: 'core',\n    config?: StorybookConfigRaw['core'],\n    args?: any\n  ): Promise<NonNullable<StorybookConfigRaw['core']>>;\n  apply(\n    extension: 'docs',\n    config?: StorybookConfigRaw['docs'],\n    args?: any\n  ): Promise<NonNullable<StorybookConfigRaw['docs']>>;\n  apply(\n    extension: 'features',\n    config?: StorybookConfigRaw['features'],\n    args?: any\n  ): Promise<NonNullable<StorybookConfigRaw['features']>>;\n  apply(\n    extension: 'typescript',\n    config?: StorybookConfigRaw['typescript'],\n    args?: any\n  ): Promise<NonNullable<StorybookConfigRaw['typescript']>>;\n  apply(\n    extension: 'build',\n    config?: StorybookConfigRaw['build'],\n    args?: any\n  ): Promise<NonNullable<StorybookConfigRaw['build']>>;\n  apply(\n    extension: 'staticDirs',\n    config?: StorybookConfigRaw['staticDirs'],\n    args?: any\n  ): Promise<StorybookConfigRaw['staticDirs']>;\n\n  /** The second and third parameter are not needed. And make type inference easier. */\n  apply<T extends keyof StorybookConfigRaw>(extension: T): Promise<StorybookConfigRaw[T]>;\n  apply<T>(extension: string, config?: T, args?: unknown): Promise<T>;\n}\n\nexport interface LoadedPreset {\n  name: string;\n  preset: any;\n  options: any;\n}\n\nexport type PresetConfig =\n  | string\n  | {\n      name: string;\n      options?: unknown;\n    };\n\nexport interface Ref {\n  id: string;\n  url: string;\n  title: string;\n  version: string;\n  type?: string;\n  disable?: boolean;\n}\n\nexport interface VersionCheck {\n  success: boolean;\n  cached: boolean;\n  data?: any;\n  error?: any;\n  time: number;\n}\n\nexport interface Stats {\n  toJson: () => any;\n}\n\nexport interface BuilderResult {\n  totalTime?: ReturnType<typeof process.hrtime>;\n  stats?: Stats;\n}\n\nexport type PackageJson = PackageJsonFromTypeFest & Record<string, any>;\n\n// TODO: This could be exported to the outside world and used in `options.ts` file of each `@storybook/APP`\n// like it's described in docs/api/new-frameworks.md\nexport interface LoadOptions {\n  pnp?: boolean;\n  packageJson?: PackageJson;\n  outputDir?: string;\n  configDir?: string;\n  cacheKey?: string;\n  ignorePreview?: boolean;\n  extendServer?: (server: HttpServer) => void;\n}\n\nexport interface CLIBaseOptions {\n  disableTelemetry?: boolean;\n  enableCrashReports?: boolean;\n  configDir?: string;\n  loglevel?: LogLevel;\n  logfile?: string | boolean;\n  quiet?: boolean;\n}\n\nexport interface CLIOptions extends CLIBaseOptions {\n  port?: number;\n  ignorePreview?: boolean;\n  previewUrl?: string;\n  forceBuildPreview?: boolean;\n  host?: string;\n  initialPath?: string;\n  exactPort?: boolean;\n  https?: boolean;\n  sslCa?: string[];\n  sslCert?: string;\n  sslKey?: string;\n  smokeTest?: boolean;\n  managerCache?: boolean;\n  open?: boolean;\n  ci?: boolean;\n  versionUpdates?: boolean;\n  docs?: boolean;\n  test?: boolean;\n  debugWebpack?: boolean;\n  webpackStatsJson?: string | boolean;\n  statsJson?: string | boolean;\n  outputDir?: string;\n  previewOnly?: boolean;\n}\n\nexport interface BuilderOptions {\n  configType?: 'DEVELOPMENT' | 'PRODUCTION';\n  ignorePreview?: boolean;\n  cache?: FileSystemCache;\n  configDir: string;\n  docsMode?: boolean;\n  features?: StorybookConfigRaw['features'];\n  versionCheck?: VersionCheck;\n  disableWebpackDefaults?: boolean;\n  serverChannelUrl?: string;\n  localAddress?: string;\n  networkAddress?: string;\n}\n\nexport interface StorybookConfigOptions {\n  presets: Presets;\n  presetsList?: LoadedPreset[];\n  channel: ChannelLike;\n}\n\nexport type Options = LoadOptions &\n  StorybookConfigOptions &\n  CLIOptions &\n  BuilderOptions & { build?: TestBuildConfig };\n\n// A minimal version of Polka's interface to avoid exposing internal implementation details\nexport type Middleware<T extends IncomingMessage = IncomingMessage> = (\n  req: T & IncomingMessage,\n  res: ServerResponse,\n  next: (err?: string | Error) => Promise<void> | void\n) => Promise<void> | void;\n\nexport interface ServerApp<T extends IncomingMessage = IncomingMessage> {\n  server: NetServer;\n\n  use(pattern: RegExp | string, ...handlers: Middleware<T>[]): this;\n  use(...handlers: Middleware<T>[]): this;\n\n  get(pattern: RegExp | string, ...handlers: Middleware<T>[]): this;\n  post(pattern: RegExp | string, ...handlers: Middleware<T>[]): this;\n  put(pattern: RegExp | string, ...handlers: Middleware<T>[]): this;\n  patch(pattern: RegExp | string, ...handlers: Middleware<T>[]): this;\n  delete(pattern: RegExp | string, ...handlers: Middleware<T>[]): this;\n  head(pattern: RegExp | string, ...handlers: Middleware<T>[]): this;\n  options(pattern: RegExp | string, ...handlers: Middleware<T>[]): this;\n  connect(pattern: RegExp | string, ...handlers: Middleware<T>[]): this;\n  trace(pattern: RegExp | string, ...handlers: Middleware<T>[]): this;\n}\n\nexport interface Builder<Config, BuilderStats extends Stats = Stats> {\n  getConfig: (options: Options) => Promise<Config>;\n  start: (args: {\n    options: Options;\n    startTime: ReturnType<typeof process.hrtime>;\n    router: ServerApp;\n    server: HttpServer;\n    channel: ChannelLike;\n  }) => Promise<void | {\n    stats?: BuilderStats;\n    totalTime: ReturnType<typeof process.hrtime>;\n    bail: (e?: Error) => Promise<void>;\n  }>;\n  build: (arg: {\n    options: Options;\n    startTime: ReturnType<typeof process.hrtime>;\n  }) => Promise<void | BuilderStats>;\n  bail: (e?: Error) => Promise<void>;\n  corePresets?: string[];\n  overridePresets?: string[];\n  onModuleGraphChange?(cb: (event: ModuleGraphChangeEvent) => void): () => void;\n}\n\n/**\n * Builder-agnostic module graph for dependency tracking. Modeled after Vite's module graph.\n * The same file can be imported in multiple ways (e.g. based on query params or import context),\n * each representing a unique module identity, hence the value is a Set<ModuleNode>.\n */\nexport type ModuleGraph = Map<ModuleNode['file'], Set<ModuleNode>>;\n\nexport type ModuleGraphChangeEvent =\n  | { type: 'moduleGraph'; moduleGraph: ModuleGraph }\n  | { type: 'unavailable'; reason: string; error?: Error }\n  | { type: 'error'; error: Error };\n\nexport interface ModuleNode {\n  file: string;\n  type: 'js' | 'css' | 'asset';\n  importers: Set<ModuleNode>;\n  importedModules: Set<ModuleNode>;\n}\n\n/** Options for TypeScript usage within Storybook. */\nexport interface TypescriptOptions {\n  /**\n   * Enables type checking within Storybook.\n   *\n   * @default false\n   */\n  check: boolean;\n\n  /**\n   * Disable parsing TypeScript files through compiler.\n   *\n   * @default false\n   */\n  skipCompiler: boolean;\n}\n\nexport type Preset =\n  | string\n  | {\n      name: string;\n      options?: any;\n    };\n\n/** An additional script that gets injected into the preview or the manager, */\nexport type Entry = string;\n\ntype CoreCommon_StorybookRefs = Record<\n  string,\n  { title: string; url: string } | { disable: boolean; expanded?: boolean }\n>;\n\nexport type DocsOptions = {\n  /** What should we call the generated docs entries? */\n  defaultName?: string;\n  /** Only show doc entries in the side bar (usually set with the `--docs` CLI flag) */\n  docsMode?: boolean;\n};\n\nexport interface TestBuildFlags {\n  /**\n   * The package @storybook/blocks will be excluded from the bundle, even when imported in e.g. the\n   * preview.\n   */\n  disableBlocks?: boolean;\n  /** Disable specific addons */\n  disabledAddons?: string[];\n  /** Filter out .mdx stories entries */\n  disableMDXEntries?: boolean;\n  /** Override autodocs to be disabled */\n  disableAutoDocs?: boolean;\n  /** Override docgen to be disabled. */\n  disableDocgen?: boolean;\n  /** Override sourcemaps generation to be disabled. */\n  disableSourcemaps?: boolean;\n  /** Override tree-shaking (dead code elimination) to be disabled. */\n  disableTreeShaking?: boolean;\n  /** Minify with ESBuild when using webpack. */\n  esbuildMinify?: boolean;\n}\n\nexport interface TestBuildConfig {\n  test?: TestBuildFlags;\n}\n\ntype Tag = string;\n\nexport interface TagOptions {\n  /** Visually include or exclude stories with this tag in the sidebar by default */\n  defaultFilterSelection?: 'include' | 'exclude' | undefined;\n  excludeFromSidebar: boolean;\n  excludeFromDocsStories: boolean;\n}\n\nexport type TagsOptions = Record<Tag, Partial<TagOptions>>;\n\nexport interface ComponentManifest {\n  id: string;\n  path: string;\n  name: string;\n  description?: string | undefined;\n  import?: string | undefined;\n  summary?: string | undefined;\n  stories: {\n    name: string;\n    snippet?: string | undefined;\n    description?: string | undefined;\n    summary?: string | undefined;\n    error?: { name: string; message: string };\n  }[];\n  jsDocTags: Record<string, string[]>;\n  error?: { name: string; message: string };\n}\n\nexport interface ComponentsManifest {\n  v: number;\n  components: Record<string, ComponentManifest>;\n  meta?: {\n    docgen: 'react-docgen' | 'react-docgen-typescript' | 'react-component-meta';\n    durationMs: number;\n  };\n}\n\ntype ManifestName = string;\n\nexport type Manifests = { components?: ComponentsManifest } & Record<ManifestName, unknown>;\n\nexport type CsfEnricher = (csf: CsfFile, csfSource: CsfFile) => Promise<void>;\n\nexport interface StorybookConfigRaw {\n  /**\n   * Sets the addons you want to use with Storybook.\n   *\n   * @example\n   *\n   * ```ts\n   * addons = ['@storybook/addon-essentials'];\n   * addons = [{ name: '@storybook/addon-essentials', options: { backgrounds: false } }];\n   * ```\n   */\n  addons?: Preset[];\n  core?: CoreConfig;\n  experimental_manifests?: Manifests;\n  experimental_enrichCsf?: CsfEnricher;\n  staticDirs?: (DirectoryMapping | string)[];\n  logLevel?: string;\n  features?: {\n    /**\n     * Enable the integrated viewport addon\n     *\n     * @default true\n     */\n    viewport?: boolean;\n\n    /**\n     * Enable the integrated highlight addon\n     *\n     * @default true\n     */\n    highlight?: boolean;\n\n    /**\n     * Enable the integrated backgrounds addon\n     *\n     * @default true\n     */\n    backgrounds?: boolean;\n\n    /**\n     * Enable the integrated measure addon\n     *\n     * @default true\n     */\n    measure?: boolean;\n\n    /**\n     * Enable the integrated outline addon\n     *\n     * @default true\n     */\n    outline?: boolean;\n\n    /**\n     * Enable the integrated controls addon\n     *\n     * @default true\n     */\n    controls?: boolean;\n\n    /**\n     * Enable the integrated interactions addon\n     *\n     * @default true\n     */\n    interactions?: boolean;\n\n    /**\n     * Enable the integrated actions addon\n     *\n     * @default true\n     */\n    actions?: boolean;\n\n    /**\n     * Enable the onboarding checklist sidebar widget\n     *\n     * @default true\n     */\n    sidebarOnboardingChecklist?: boolean;\n\n    /**\n     * @temporary This feature flag is a migration assistant, and is scheduled to be removed.\n     *\n     * Filter args with a \"target\" on the type from the render function (EXPERIMENTAL)\n     */\n    argTypeTargetsV7?: boolean;\n\n    /**\n     * @temporary This feature flag is a migration assistant, and is scheduled to be removed.\n     *\n     * Apply decorators from preview.js before decorators from addons or frameworks\n     */\n    legacyDecoratorFileOrder?: boolean;\n\n    /**\n     * @temporary This feature flag is a migration assistant, and is scheduled to be removed.\n     *\n     * Disallow implicit actions during rendering. This will be the default in Storybook 8.\n     *\n     * This will make sure that your story renders the same no matter if docgen is enabled or not.\n     */\n    disallowImplicitActionsInRenderV8?: boolean;\n\n    /**\n     * @temporary This feature flag is a migration assistant, and is scheduled to be removed.\n     *\n     * Enable asynchronous component rendering in React renderer\n     */\n    experimentalRSC?: boolean;\n\n    /**\n     * @temporary This feature flag is a migration assistant, and is scheduled to be removed.\n     *\n     * Set NODE_ENV to development in built Storybooks for better testability and debuggability\n     */\n    developmentModeForBuild?: boolean;\n    /** Only show input controls in Angular */\n    angularFilterNonInputControls?: boolean;\n\n    /**\n     * Enable component manifest generation for MCP and other tooling integrations.\n     *\n     * @default true\n     */\n    componentsManifest?: boolean;\n\n    /**\n     * Use TypeScript LanguageService (react-component-meta) for extracting React component props\n     * instead of react-docgen / react-docgen-typescript.\n     *\n     * @default false\n     * @experimental\n     */\n    experimentalReactComponentMeta?: boolean;\n\n    /**\n     * Enables the new code example generation for React components. You can see those examples when\n     * clicking on the \"Show code\" button in the Storybook UI.\n     *\n     * We refactored the code examples by reading the actual source file. This should make the code\n     * examples a lot faster, more readable and more accurate. They are not dynamic though, it won't\n     * change if you change when using the control panel.\n     *\n     * @default false\n     * @experimental This feature is in early development and may change significantly in future releases.\n     */\n    experimentalCodeExamples?: boolean;\n\n    /**\n     * Enable change detection\n     * TODO: Turn to true before 10.4 release\n     * @default false\n     */\n    changeDetection?: boolean;\n  };\n\n  build?: TestBuildConfig;\n\n  stories: StoriesEntry[];\n\n  framework?: Preset;\n\n  typescript?: Partial<TypescriptOptions>;\n\n  refs?: CoreCommon_StorybookRefs;\n\n  // We cannot use a particular Babel type here because we need to support a variety of versions\n  babel?: any;\n\n  swc?: any;\n\n  env?: Record<string, string>;\n\n  // We cannot use a particular Babel type here because we need to support a variety of versions\n  babelDefault?: any;\n\n  previewAnnotations?: Entry[];\n\n  experimental_indexers?: Indexer[];\n\n  storyIndexGenerator?: StoryIndexGenerator;\n\n  experimental_devServer?: ServerApp;\n\n  docs?: DocsOptions;\n\n  previewHead?: string;\n\n  previewBody?: string;\n\n  previewMainTemplate?: string;\n\n  managerHead?: string;\n\n  tags?: TagsOptions;\n}\n\n/**\n * The interface for Storybook configuration in `main.ts` files. This interface is public All values\n * should be wrapped with `PresetValue<>`, though there are a few exceptions: `addons`, `framework`\n */\nexport interface StorybookConfig {\n  /**\n   * Sets the addons you want to use with Storybook.\n   *\n   * @example\n   *\n   * ```\n   * addons = ['@storybook/addon-essentials'];\n   * addons = [{ name: '@storybook/addon-essentials', options: { backgrounds: false } }];\n   * ```\n   */\n  addons?: StorybookConfigRaw['addons'];\n  core?: PresetValue<StorybookConfigRaw['core']>;\n  /**\n   * Sets a list of directories of static files to be loaded by Storybook server\n   *\n   * @example\n   *\n   * ```ts\n   * staticDirs = ['./public'];\n   * staticDirs = [{ from: './public', to: '/assets' }];\n   * ```\n   */\n  staticDirs?: PresetValue<StorybookConfigRaw['staticDirs']>;\n  logLevel?: PresetValue<StorybookConfigRaw['logLevel']>;\n  features?: PresetValue<StorybookConfigRaw['features']>;\n\n  build?: PresetValue<StorybookConfigRaw['build']>;\n\n  /**\n   * Tells Storybook where to find stories.\n   *\n   * @example\n   *\n   * ```ts\n   * stories = ['./src/*.stories.@(j|t)sx?'];\n   * stories = async () => [...(await myCustomStoriesEntryBuilderFunc())];\n   * ```\n   */\n  stories: PresetValue<StorybookConfigRaw['stories']>;\n\n  /** Framework, e.g. '@storybook/react-vite', required in v7 */\n  framework?: StorybookConfigRaw['framework'];\n\n  /** Controls how Storybook handles TypeScript files. */\n  typescript?: PresetValue<StorybookConfigRaw['typescript']>;\n\n  /** References external Storybooks */\n  refs?: PresetValue<StorybookConfigRaw['refs']>;\n\n  /** Modify or return babel config. */\n  babel?: PresetValue<StorybookConfigRaw['babel']>;\n\n  /** Modify or return swc config. */\n  swc?: PresetValue<StorybookConfigRaw['swc']>;\n\n  /** Modify or return env config. */\n  env?: PresetValue<StorybookConfigRaw['env']>;\n\n  /** Modify or return babel config. */\n  babelDefault?: PresetValue<StorybookConfigRaw['babelDefault']>;\n\n  /** Add additional scripts to run in the preview a la `.storybook/preview.js` */\n  previewAnnotations?: PresetValue<StorybookConfigRaw['previewAnnotations']>;\n\n  /** Process CSF files for the story index. */\n  experimental_indexers?: PresetValue<StorybookConfigRaw['experimental_indexers']>;\n\n  /** Docs related features in index generation */\n  docs?: PresetValue<StorybookConfigRaw['docs']>;\n\n  /**\n   * Programmatically modify the preview head/body HTML. The previewHead and previewBody functions\n   * accept a string, which is the existing head/body, and return a modified string.\n   */\n  previewHead?: PresetValue<StorybookConfigRaw['previewHead']>;\n\n  previewBody?: PresetValue<StorybookConfigRaw['previewBody']>;\n\n  /**\n   * Programmatically override the preview's main page template. This should return a reference to a\n   * file containing an `.ejs` template that will be interpolated with environment variables.\n   *\n   * @example\n   *\n   * ```ts\n   * previewMainTemplate = '.storybook/index.ejs';\n   * ```\n   */\n  previewMainTemplate?: PresetValue<StorybookConfigRaw['previewMainTemplate']>;\n\n  /**\n   * Programmatically modify the preview head/body HTML. The managerHead function accept a string,\n   * which is the existing head content, and return a modified string.\n   */\n  managerHead?: PresetValue<StorybookConfigRaw['managerHead']>;\n\n  /** Configure non-standard tag behaviors */\n  tags?: PresetValue<StorybookConfigRaw['tags']>;\n}\n\nexport type PresetValue<T> = T | ((config: T, options: Options) => T | Promise<T>);\n\nexport type PresetProperty<K, TStorybookConfig = StorybookConfigRaw> =\n  | TStorybookConfig[K extends keyof TStorybookConfig ? K : never]\n  | PresetPropertyFn<K, TStorybookConfig>;\n\nexport type PresetPropertyFn<K, TStorybookConfig = StorybookConfigRaw, TOptions = {}> = (\n  config: TStorybookConfig[K extends keyof TStorybookConfig ? K : never],\n  options: Options & TOptions\n) =>\n  | TStorybookConfig[K extends keyof TStorybookConfig ? K : never]\n  | Promise<TStorybookConfig[K extends keyof TStorybookConfig ? K : never]>;\n\nexport interface CoreCommon_ResolvedAddonPreset {\n  type: 'presets';\n  name: string;\n}\n\nexport type PreviewAnnotation = string | { bare: string; absolute: string };\n\nexport interface CoreCommon_ResolvedAddonVirtual {\n  type: 'virtual';\n  name: string;\n  managerEntries?: string[];\n  previewAnnotations?: PreviewAnnotation[];\n  presets?: (string | { name: string; options?: any })[];\n}\n\nexport type CoreCommon_OptionsEntry = { name: string };\nexport type CoreCommon_AddonEntry = string | CoreCommon_OptionsEntry;\nexport type CoreCommon_AddonInfo = { name: string; inEssentials: boolean };\n\nexport interface CoreCommon_StorybookInfo {\n  addons: string[];\n  versionSpecifier?: string;\n  framework?: SupportedFramework;\n  renderer?: SupportedRenderer;\n  builder?: SupportedBuilder;\n  rendererPackage?: string;\n  frameworkPackage?: string;\n  builderPackage?: string;\n  configDir?: string;\n  mainConfig: StorybookConfigRaw;\n  mainConfigPath?: string;\n  previewConfigPath?: string;\n  managerConfigPath?: string;\n}\n\n/**\n * Given a generic string type, returns that type but ensures that a string in general is compatible\n * with it. We use this construct to ensure that IDEs can provide better autocompletion for string\n * types. This is, for example, needed for main config fields, where we want to ensure that the user\n * can provide a custom string, but also a string that is compatible with the type.\n *\n * @example\n *\n * ```ts\n * type Framework = CompatibleString<'@storybook/nextjs'>;\n * const framework: Framework = '@storybook/nextjs'; // valid and will be autocompleted const framework: Framework =\n * path.dirname(require.resolve(path.join('@storybook/nextjs', 'package.json'))); // valid\n * ```\n */\nexport type CompatibleString<T extends string> = T | (string & {});\n"
  },
  {
    "path": "code/core/src/types/modules/csf.ts",
    "content": "import type { ViewMode as ViewModeBase } from 'storybook/internal/csf';\n\nimport type { Addon_OptionsParameterV7 } from './addons.ts';\n\nexport type {\n  AfterEach,\n  AnnotatedStoryFn,\n  Args,\n  ArgsEnhancer,\n  ArgsFromMeta,\n  ArgsStoryFn,\n  ArgTypes,\n  ArgTypesEnhancer,\n  BaseAnnotations,\n  BeforeAll,\n  BeforeEach,\n  Canvas,\n  CleanupCallback,\n  ComponentAnnotations,\n  ComponentId,\n  ComponentTitle,\n  Conditional,\n  DecoratorApplicator,\n  DecoratorFunction,\n  Globals,\n  GlobalTypes,\n  IncludeExcludeOptions,\n  InputType,\n  LegacyAnnotatedStoryFn,\n  LegacyStoryAnnotationsOrFn,\n  LegacyStoryFn,\n  LoaderFunction,\n  Parameters,\n  PartialStoryFn,\n  TestFunction,\n  PlayFunction,\n  PlayFunctionContext,\n  ProjectAnnotations as BaseProjectAnnotations,\n  Renderer,\n  SBArrayType,\n  SBEnumType,\n  SBIntersectionType,\n  SBObjectType,\n  SBOtherType,\n  SBScalarType,\n  SBType,\n  SBUnionType,\n  SeparatorOptions,\n  StepFunction,\n  StepLabel,\n  StepRunner,\n  StoryAnnotations,\n  StoryAnnotationsOrFn,\n  StoryContext,\n  StoryContextForEnhancers,\n  StoryContextForLoaders,\n  StoryContextUpdate,\n  StoryFn,\n  StoryId,\n  StoryIdentifier,\n  StoryKind,\n  StoryName,\n  StrictArgs,\n  StrictArgTypes,\n  StrictInputType,\n  Tag,\n} from 'storybook/internal/csf';\n\ntype OrString<T extends string> = T | (string & {});\n\nexport type ViewMode = OrString<ViewModeBase | 'settings'> | undefined;\n\ntype Layout = 'centered' | 'fullscreen' | 'padded' | 'none';\n\nexport interface StorybookParameters {\n  options?: Addon_OptionsParameterV7;\n  /**\n   * The layout property defines basic styles added to the preview body where the story is rendered.\n   *\n   * If you pass `none`, no styles are applied.\n   */\n  layout?: Layout;\n}\n\nexport interface StorybookTypes {\n  parameters: StorybookParameters;\n}\n\nexport interface StorybookInternalParameters extends StorybookParameters {\n  fileName?: string;\n  docsOnly?: true;\n}\n\nexport type Path = string;\n"
  },
  {
    "path": "code/core/src/types/modules/docs.ts",
    "content": "import type { Channel } from 'storybook/internal/channels';\n\nimport type { Parameters, Renderer, StoryContext, StoryId, StoryName } from './csf.ts';\nimport type {\n  CSFFile,\n  ModuleExport,\n  ModuleExports,\n  NormalizedProjectAnnotations,\n  PreparedMeta,\n  PreparedStory,\n  RenderContext,\n} from './story.ts';\n\nexport type RenderContextCallbacks<TRenderer extends Renderer> = Pick<\n  RenderContext<TRenderer>,\n  'showMain' | 'showError' | 'showException'\n>;\n\nexport type StoryRenderOptions = {\n  autoplay?: boolean;\n  forceInitialArgs?: boolean;\n};\n\nexport type ResolvedModuleExportType = 'component' | 'meta' | 'story';\n\n/**\n * What do we know about an of={} call?\n *\n * Technically, the type names aren't super accurate:\n *\n * - Meta === `CSFFile`\n * - Story === `PreparedStory` But these shorthands capture the idea of what is being talked about\n */\nexport type ResolvedModuleExportFromType<\n  TType extends ResolvedModuleExportType,\n  TRenderer extends Renderer = Renderer,\n> = TType extends 'component'\n  ? {\n      type: 'component';\n      component: TRenderer['component'];\n      projectAnnotations: NormalizedProjectAnnotations<Renderer>;\n    }\n  : TType extends 'meta'\n    ? { type: 'meta'; csfFile: CSFFile<TRenderer>; preparedMeta: PreparedMeta }\n    : { type: 'story'; story: PreparedStory<TRenderer> };\n\nexport type ResolvedModuleExport<TRenderer extends Renderer = Renderer> = {\n  type: ResolvedModuleExportType;\n} & (\n  | ResolvedModuleExportFromType<'component', TRenderer>\n  | ResolvedModuleExportFromType<'meta', TRenderer>\n  | ResolvedModuleExportFromType<'story', TRenderer>\n);\n\nexport interface DocsContextProps<TRenderer extends Renderer = Renderer> {\n  /**\n   * Register a CSF file that this docs entry uses. Used by the `<Meta of={} />` block to attach,\n   * and the `<Story meta={} />` bloc to reference\n   */\n  referenceMeta: (metaExports: ModuleExports, attach: boolean) => void;\n\n  /**\n   * Find a component, meta or story object from the direct export(s) from the CSF file. This is the\n   * API that drives the `of={}` syntax.\n   */\n  resolveOf<TType extends ResolvedModuleExportType>(\n    moduleExportOrType: ModuleExport | TType,\n    validTypes?: TType[]\n  ): ResolvedModuleExportFromType<TType, TRenderer>;\n\n  /**\n   * Find a story's id from the name of the story. This is primarily used by the `<Story name={} />\n   * block. Note that the story must be part of the primary CSF file of the docs entry.\n   */\n  storyIdByName: (storyName: StoryName) => StoryId;\n  /**\n   * Syncronously find a story by id (if the id is not provided, this will look up the primary story\n   * in the CSF file, if such a file exists).\n   */\n  storyById: (id?: StoryId) => PreparedStory<TRenderer>;\n  /** Syncronously find all stories of the component referenced by the CSF file. */\n  componentStories: () => PreparedStory<TRenderer>[];\n\n  /** Syncronously find all stories by CSF file. */\n  componentStoriesFromCSFFile: (csfFile: CSFFile<TRenderer>) => PreparedStory<TRenderer>[];\n\n  /** Get the story context of the referenced story. */\n  getStoryContext: (\n    story: PreparedStory<TRenderer>\n  ) => Omit<StoryContext<TRenderer>, 'abortSignal' | 'canvasElement' | 'step' | 'context'>;\n  /** Asyncronously load an arbitrary story by id. */\n  loadStory: (id: StoryId) => Promise<PreparedStory<TRenderer>>;\n\n  /** Render a story to a given HTML element and keep it up to date across context changes */\n  renderStoryToElement: (\n    story: PreparedStory<TRenderer>,\n    element: HTMLElement,\n    callbacks: RenderContextCallbacks<TRenderer>,\n    options: StoryRenderOptions\n  ) => () => Promise<void>;\n\n  /** Storybook channel -- use for low level event watching/emitting */\n  channel: Channel;\n\n  /** Project annotations -- can be read to get the project's global annotations */\n  projectAnnotations: NormalizedProjectAnnotations<TRenderer>;\n}\n\nexport type DocsRenderFunction<TRenderer extends Renderer> = (\n  docsContext: DocsContextProps<TRenderer>,\n  docsParameters: Parameters,\n  element: HTMLElement\n) => Promise<void>;\n"
  },
  {
    "path": "code/core/src/types/modules/features.ts",
    "content": "export enum Feature {\n  DOCS = 'docs',\n  TEST = 'test',\n  ONBOARDING = 'onboarding',\n  A11Y = 'a11y',\n}\n"
  },
  {
    "path": "code/core/src/types/modules/frameworks.ts",
    "content": "// auto generated file, do not edit\nexport enum SupportedFramework {\n  // CORE\n  ANGULAR = 'angular',\n  EMBER = 'ember',\n  HTML_VITE = 'html-vite',\n  NEXTJS = 'nextjs',\n  NEXTJS_VITE = 'nextjs-vite',\n  PREACT_VITE = 'preact-vite',\n  REACT_NATIVE_WEB_VITE = 'react-native-web-vite',\n  REACT_VITE = 'react-vite',\n  REACT_WEBPACK5 = 'react-webpack5',\n  SERVER_WEBPACK5 = 'server-webpack5',\n  SVELTE_VITE = 'svelte-vite',\n  SVELTEKIT = 'sveltekit',\n  VUE3_VITE = 'vue3-vite',\n  WEB_COMPONENTS_VITE = 'web-components-vite',\n  // COMMUNITY\n  HTML_RSBUILD = 'html-rsbuild',\n  NUXT = 'nuxt',\n  QWIK = 'qwik',\n  REACT_RSBUILD = 'react-rsbuild',\n  SOLID = 'solid',\n  VUE3_RSBUILD = 'vue3-rsbuild',\n  WEB_COMPONENTS_RSBUILD = 'web-components-rsbuild',\n}\n"
  },
  {
    "path": "code/core/src/types/modules/indexer.ts",
    "content": "import type { ComponentTitle, Parameters, Path, StoryId, StoryName, Tag } from './csf.ts';\n\ntype ExportName = string;\ntype MetaId = string;\n\nexport interface StoriesSpecifier {\n  /** When auto-titling, what to prefix all generated titles with (default: '') */\n  titlePrefix?: string;\n  /** Where to start looking for story files */\n  directory: string;\n  /**\n   * What does the filename of a story file look like? (a glob, relative to directory, no leading\n   * `./`) If unset, we use `** / *.@(mdx|stories.@(mdx|js|jsx|mjs|ts|tsx))` (no spaces)\n   */\n  files?: string;\n}\n\nexport type StoriesEntry = string | StoriesSpecifier;\n\nexport type NormalizedStoriesSpecifier = Required<StoriesSpecifier> & {\n  /*\n   * Match the \"importPath\" of a file (e.g. `./src/button/Button.stories.js')\n   * relative to the current working directory.\n   */\n  importPathMatcher: RegExp;\n};\n\nexport interface IndexerOptions {\n  makeTitle: (userTitle?: string) => string;\n}\n\nexport interface IndexedStory {\n  id: string;\n  name: string;\n  tags?: Tag[];\n  parameters?: Parameters;\n}\nexport interface IndexedCSFFile {\n  meta: { id?: string; title?: string; tags?: Tag[] };\n  stories: IndexedStory[];\n}\n\n/**\n * FIXME: This is a temporary type to allow us to deprecate the old indexer API. We should remove\n * this type and the deprecated indexer API in 8.0.\n */\ntype BaseIndexer = {\n  /** A regular expression that should match all files to be handled by this indexer */\n  test: RegExp;\n};\n\n/**\n * An indexer describes which filenames it handles, and how to index each individual file - turning\n * it into an entry in the index.\n */\nexport type Indexer = BaseIndexer & {\n  /**\n   * Indexes a file containing stories or docs.\n   *\n   * @param fileName The name of the file to index.\n   * @param options {@link IndexerOptions} for indexing the file.\n   * @returns A promise that resolves to an array of {@link IndexInput} objects.\n   */\n  createIndex: (fileName: string, options: IndexerOptions) => Promise<IndexInput[]>;\n};\n\nexport interface BaseIndexEntry {\n  id: StoryId;\n  name: StoryName;\n  title: ComponentTitle;\n  tags?: Tag[];\n  importPath: Path;\n}\nexport type StoryIndexEntry = BaseIndexEntry & {\n  type: 'story';\n  subtype: 'story' | 'test';\n  componentPath?: string;\n  exportName?: string;\n  parent?: StoryId; // exists only on tests\n  parentName?: StoryName; // exists only on tests\n};\n\nexport type DocsIndexEntry = BaseIndexEntry & {\n  storiesImports: Path[];\n  type: 'docs';\n};\n\nexport type IndexEntry = StoryIndexEntry | DocsIndexEntry;\n\nexport interface IndexInputStats {\n  loaders?: boolean;\n  play?: boolean;\n  tests?: boolean;\n  render?: boolean;\n  storyFn?: boolean;\n  mount?: boolean;\n  beforeEach?: boolean;\n  moduleMock?: boolean;\n  globals?: boolean;\n  factory?: boolean;\n  tags?: boolean;\n}\n\n/** The base input for indexing a story or docs entry. */\nexport type BaseIndexInput = {\n  /** The file to import from e.g. the story file. Defaults to the fileName arg passed to createIndex */\n  importPath?: Path;\n  /** The raw path/package of the file that provides meta.component, if one exists */\n  rawComponentPath?: Path;\n  /** The name of the export to import. */\n  exportName: ExportName;\n  /** The name of the entry, auto-generated from {@link exportName} if unspecified. */\n  name?: StoryName;\n  /** The location in the sidebar, auto-generated from {@link importPath} if unspecified. */\n  title?: ComponentTitle;\n  /**\n   * The custom id optionally set at `meta.id` if it needs to differ from the id generated via\n   * {@link title}. If unspecified, the meta id will be auto-generated from {@link title}. If\n   * specified, the meta in the CSF file _must_ have a matching id set at `meta.id`, to be correctly\n   * matched.\n   */\n  metaId?: MetaId;\n  /** Tags for filtering entries in Storybook and its tools. */\n  tags?: Tag[];\n  /**\n   * The id of the entry, auto-generated from {@link title}/{@link metaId} and {@link exportName} if\n   * unspecified. If specified, the story in the CSF file _must_ have a matching id set at\n   * `parameters.__id`, to be correctly matched. Only use this if you need to override the\n   * auto-generated id.\n   */\n  __id?: StoryId;\n  /** Stats about language feature usage that the indexer can optionally report */\n  __stats?: IndexInputStats;\n};\n\n/** The input for indexing a story entry. */\nexport type StoryIndexInput = BaseIndexInput & {\n  type: 'story';\n  subtype?: 'story' | 'test';\n  parent?: StoryId; // exists only on tests\n  parentName?: StoryName; // exists only on tests\n};\n\n/** The input for indexing a docs entry. */\nexport type DocsIndexInput = BaseIndexInput & {\n  type: 'docs';\n  /** Paths to story files that must be pre-loaded for this docs entry. */\n  storiesImports?: Path[];\n};\n\nexport type IndexInput = StoryIndexInput | DocsIndexInput;\n\nexport interface V3CompatIndexEntry extends Omit<StoryIndexEntry, 'type' | 'tags' | 'subtype'> {\n  kind: ComponentTitle;\n  story: StoryName;\n  parameters: Parameters;\n}\n\nexport interface StoryIndexV2 {\n  v: number;\n  stories: Record<\n    StoryId,\n    Omit<V3CompatIndexEntry, 'title' | 'name' | 'importPath'> & {\n      name?: StoryName;\n    }\n  >;\n}\n\nexport interface StoryIndexV3 {\n  v: number;\n  stories: Record<StoryId, V3CompatIndexEntry>;\n}\n\nexport interface StoryIndex {\n  v: number;\n  entries: Record<StoryId, IndexEntry>;\n}\n"
  },
  {
    "path": "code/core/src/types/modules/languages.ts",
    "content": "export enum SupportedLanguage {\n  JAVASCRIPT = 'javascript',\n  TYPESCRIPT = 'typescript',\n}\n"
  },
  {
    "path": "code/core/src/types/modules/renderers.ts",
    "content": "export enum SupportedRenderer {\n  REACT = 'react',\n  REACT_NATIVE = 'react-native',\n  VUE3 = 'vue3',\n  ANGULAR = 'angular',\n  EMBER = 'ember',\n  PREACT = 'preact',\n  SVELTE = 'svelte',\n  QWIK = 'qwik',\n  HTML = 'html',\n  WEB_COMPONENTS = 'web-components',\n  SERVER = 'server',\n  SOLID = 'solid',\n  NUXT = 'nuxt',\n}\n"
  },
  {
    "path": "code/core/src/types/modules/status.ts",
    "content": "export { CHANGE_DETECTION_STATUS_TYPE_ID } from '../../shared/status-store/index.ts';\nexport type {\n  Status,\n  StatusValue,\n  StatusTypeId,\n  StatusByTypeId,\n  StatusesByStoryIdAndTypeId,\n  StatusStore,\n  StatusStoreByTypeId,\n  UseStatusStore,\n} from '../../shared/status-store/index.ts';\n"
  },
  {
    "path": "code/core/src/types/modules/story.ts",
    "content": "import type {\n  ArgsStoryFn,\n  BaseProjectAnnotations,\n  BeforeAll,\n  Canvas,\n  CleanupCallback,\n  ComponentAnnotations,\n  ComponentId,\n  ComponentTitle,\n  DecoratorFunction,\n  Globals,\n  LegacyStoryFn,\n  LoaderFunction,\n  PartialStoryFn,\n  Path,\n  Renderer,\n  StepRunner,\n  StoryAnnotations,\n  StoryContext,\n  StoryContextForEnhancers,\n  StoryId,\n  StoryIdentifier,\n  StoryName,\n  StrictArgTypes,\n} from './csf.ts';\n\n// Store Types\nexport interface WebRenderer extends Renderer {\n  canvasElement: HTMLElement;\n}\n\nexport type ModuleExport = any;\nexport type ModuleExports = Record<string, ModuleExport>;\nexport type ModuleImportFn = (path: Path) => Promise<ModuleExports>;\n\ntype MaybePromise<T> = Promise<T> | T;\nexport type TeardownRenderToCanvas = () => MaybePromise<void>;\nexport type RenderToCanvas<TRenderer extends Renderer> = (\n  context: RenderContext<TRenderer>,\n  element: TRenderer['canvasElement']\n) => MaybePromise<void | TeardownRenderToCanvas>;\n\nexport interface ProjectAnnotations<\n  TRenderer extends Renderer,\n> extends BaseProjectAnnotations<TRenderer> {\n  testingLibraryRender?: (...args: never[]) => { unmount: () => void };\n  renderToCanvas?: RenderToCanvas<TRenderer>;\n}\n\ntype NamedExportsOrDefault<TExport> = TExport | { default: TExport };\n\nexport type NamedOrDefaultProjectAnnotations<TRenderer extends Renderer = Renderer> =\n  NamedExportsOrDefault<ProjectAnnotations<TRenderer>>;\n\nexport type NormalizedProjectAnnotations<TRenderer extends Renderer = Renderer> = Omit<\n  ProjectAnnotations<TRenderer>,\n  'decorators' | 'loaders' | 'runStep' | 'beforeAll'\n> & {\n  argTypes?: StrictArgTypes;\n  decorators?: DecoratorFunction<TRenderer>[];\n  loaders?: LoaderFunction<TRenderer>[];\n  runStep: StepRunner<TRenderer>;\n  beforeAll: BeforeAll;\n};\n\nexport type NormalizedComponentAnnotations<TRenderer extends Renderer = Renderer> = Omit<\n  ComponentAnnotations<TRenderer>,\n  'decorators' | 'loaders'\n> & {\n  // Useful to guarantee that id & title exists\n  id: ComponentId;\n  title: ComponentTitle;\n  argTypes?: StrictArgTypes;\n  decorators?: DecoratorFunction<TRenderer>[];\n  loaders?: LoaderFunction<TRenderer>[];\n};\n\nexport type NormalizedStoryAnnotations<TRenderer extends Renderer = Renderer> = Omit<\n  StoryAnnotations<TRenderer>,\n  'storyName' | 'story' | 'decorators' | 'loaders'\n> & {\n  moduleExport: ModuleExport;\n  // You cannot actually set id on story annotations, but we normalize it to be there for convenience\n  id: StoryId;\n  argTypes?: StrictArgTypes;\n  name: StoryName;\n  userStoryFn?: ArgsStoryFn<TRenderer>;\n  decorators?: DecoratorFunction<TRenderer>[];\n  loaders?: LoaderFunction<TRenderer>[];\n};\n\nexport type CSFFile<TRenderer extends Renderer = Renderer> = {\n  meta: NormalizedComponentAnnotations<TRenderer>;\n  stories: Record<StoryId, NormalizedStoryAnnotations<TRenderer>>;\n  projectAnnotations?: NormalizedProjectAnnotations<TRenderer>;\n  moduleExports: ModuleExports;\n};\n\nexport type PreparedStory<TRenderer extends Renderer = Renderer> =\n  StoryContextForEnhancers<TRenderer> & {\n    moduleExport: ModuleExport;\n    originalStoryFn: ArgsStoryFn<TRenderer>;\n    undecoratedStoryFn: LegacyStoryFn<TRenderer>;\n    unboundStoryFn: LegacyStoryFn<TRenderer>;\n    applyLoaders: (context: StoryContext<TRenderer>) => Promise<StoryContext<TRenderer>['loaded']>;\n    applyBeforeEach: (context: StoryContext<TRenderer>) => Promise<CleanupCallback[]>;\n    applyAfterEach: (context: StoryContext<TRenderer>) => Promise<void>;\n    playFunction?: (context: StoryContext<TRenderer>) => Promise<void> | void;\n    runStep: StepRunner<TRenderer>;\n    mount: (context: StoryContext<TRenderer>) => () => Promise<Canvas>;\n    testingLibraryRender?: (...args: never[]) => unknown;\n    renderToCanvas?: ProjectAnnotations<TRenderer>['renderToCanvas'];\n    usesMount: boolean;\n    storyGlobals: Globals;\n  };\n\nexport type PreparedMeta<TRenderer extends Renderer = Renderer> = Omit<\n  StoryContextForEnhancers<TRenderer>,\n  'name' | 'story'\n> & {\n  moduleExport: ModuleExport;\n};\n\nexport type BoundStory<TRenderer extends Renderer = Renderer> = PreparedStory<TRenderer> & {\n  storyFn: PartialStoryFn<TRenderer>;\n};\n\n// TODO Consolidate this with context for 9.0\nexport declare type RenderContext<TRenderer extends Renderer = Renderer> = StoryIdentifier & {\n  showMain: () => void;\n  showError: (error: { title: string; description: string }) => void;\n  showException: (err: Error) => void;\n  forceRemount: boolean;\n  storyContext: StoryContext<TRenderer>;\n  storyFn: PartialStoryFn<TRenderer>;\n  unboundStoryFn: LegacyStoryFn<TRenderer>;\n};\n"
  },
  {
    "path": "code/core/src/types/modules/test-provider.ts",
    "content": "export type {\n  TestProviderId,\n  TestProviderState,\n  TestProviderStateByProviderId,\n  TestProviderStoreById,\n  UseTestProviderStore,\n} from '../../shared/test-provider-store/index.ts';\n"
  },
  {
    "path": "code/core/src/types/modules/universal-store.ts",
    "content": "import type { UniversalStore } from '../../shared/universal-store/index.ts';\nimport type { MockUniversalStore } from '../../shared/universal-store/mock.ts';\nimport type { Actor, Event, EventInfo, StoreOptions } from '../../shared/universal-store/types.ts';\n\nexport type { UniversalStore, MockUniversalStore, Actor, Event, EventInfo, StoreOptions };\n"
  },
  {
    "path": "code/core/src/types/modules/webpack.ts",
    "content": "export enum CoreWebpackCompiler {\n  Babel = 'babel',\n  SWC = 'swc',\n}\n"
  },
  {
    "path": "code/core/src/typings.d.ts",
    "content": "/// <reference path=\"../typings.d.ts\" />\n\ndeclare var CONFIG_TYPE: 'DEVELOPMENT' | 'PRODUCTION';\ndeclare var FEATURES: import('./types/modules/core-common').StorybookConfigRaw['features'];\ndeclare var LOGLEVEL: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent' | undefined;\ndeclare var REFS: any;\ndeclare var VERSIONCHECK: any;\n\ndeclare var STORYBOOK_WEBSOCKET_TOKEN: string;\n\ndeclare var STORYBOOK_ADDON_STATE: Record<string, any>;\ndeclare var STORYBOOK_BUILDER: import('./types/modules/builders').SupportedBuilder | undefined;\ndeclare var STORYBOOK_FRAMEWORK:\n  | import('./types/modules/frameworks').SupportedFramework\n  | undefined;\ndeclare var STORYBOOK_RENDERER: import('./types/modules/renderers').SupportedRenderer | undefined;\ndeclare var STORYBOOK_HOOKS_CONTEXT: any;\ndeclare var STORYBOOK_CURRENT_TASK_LOG: undefined | null | Array<any>;\n\ndeclare var STORYBOOK_NETWORK_ADDRESS: string | undefined;\ndeclare var PREVIEW_URL: string | undefined;\n\ndeclare var __STORYBOOK_ADDON_INTERACTIONS_INSTRUMENTER__: any;\ndeclare var __STORYBOOK_ADDON_INTERACTIONS_INSTRUMENTER_STATE__: any;\ndeclare var __STORYBOOK_ADDONS_CHANNEL__: any;\ndeclare var __STORYBOOK_ADDONS_MANAGER: any;\ndeclare var __STORYBOOK_ADDONS_PREVIEW: import('./preview-api/modules/addons/main').AddonStore;\ndeclare var __STORYBOOK_PREVIEW__: import('./preview-api/modules/preview-web/PreviewWeb').PreviewWeb<any>;\ndeclare var __STORYBOOK_STORY_STORE__: any;\ndeclare var __STORYBOOK_TEST__: any;\ndeclare var __STORYBOOK_TEST_SPY_LISTENERS__: Set<any>;\ndeclare var __STORYBOOK_ACTIONS__: any;\ndeclare var __STORYBOOK_VITEST_MOCKER__: any;\n\ndeclare module '@aw-web-design/x-default-browser';\ndeclare module 'ansi-to-html';\ndeclare module 'lazy-universal-dotenv';\ndeclare module 'pnp-webpack-plugin';\ndeclare module 'react-inspector';\n\ndeclare var STORIES: any;\n\ndeclare var CHANNEL_OPTIONS: any;\ndeclare var DOCS_OPTIONS: any;\ndeclare var TAGS_OPTIONS: import('./types/modules/core-common').StorybookConfigRaw['tags'];\n\n// To enable user code to detect if it is running in Storybook\ndeclare var IS_STORYBOOK: boolean;\n\n// ClientApi (and StoreStore) are really singletons. However they are not created until the\n// relevant framework instantiates them via `start.js`. The good news is this happens right away.\ndeclare var sendTelemetryError: (error: any) => void;\n\ndeclare class AnsiToHtml {\n  constructor(options: { escapeHtml: boolean });\n\n  toHtml: (ansi: string) => string;\n}\n\ndeclare module '*.md';\ndeclare module '*.mdx';\ndeclare module '*.png';\n"
  },
  {
    "path": "code/core/src/viewport/README.md",
    "content": "# Storybook Viewport Addon\n\nStorybook Viewport Addon allows your stories to be displayed in different sizes and layouts in [Storybook](https://storybook.js.org). This helps build responsive components inside of Storybook.\n\n[Framework Support](https://storybook.js.org/docs/configure/integration/frameworks-feature-support)\n\n![Screenshot](https://raw.githubusercontent.com/storybookjs/storybook/next/code/addons/viewport/docs/viewport.png)\n\n## Installation\n\nViewport is part of [essentials](https://storybook.js.org/docs/essentials) and so is installed in all new Storybooks by default. If you need to add it to your Storybook, you can run:\n\n```sh\nnpm i -D storybook/viewport\n```\n\nThen, add following content to [`.storybook/main.js`](https://storybook.js.org/docs/configure#configure-your-storybook-project):\n\n```js\nexport default {\n  addons: ['storybook/viewport'],\n};\n```\n\nYou should now be able to see the viewport addon icon in the toolbar at the top of the screen.\n\n## Usage\n\nThe usage is documented in the [documentation](https://storybook.js.org/docs/essentials/viewport).\n"
  },
  {
    "path": "code/core/src/viewport/components/Tool.tsx",
    "content": "import React, { useMemo } from 'react';\n\nimport { Select } from 'storybook/internal/components';\n\nimport { GrowIcon } from '@storybook/icons';\n\nimport { styled } from 'storybook/theming';\n\nimport { useViewport } from '../useViewport.ts';\nimport { iconsMap } from '../viewportIcons.tsx';\n\nconst Dimensions = styled.div(({ theme }) => ({\n  display: 'flex',\n  gap: 2,\n  marginLeft: 20,\n  fontFamily: theme.typography.fonts.mono,\n  fontSize: theme.typography.size.s1 - 1,\n  fontWeight: theme.typography.weight.regular,\n  color: theme.textMutedColor,\n}));\n\nexport const ViewportTool = () => {\n  const { name, value, isDefault, isLocked, options: viewportMap, reset, select } = useViewport();\n\n  const options = useMemo(\n    () =>\n      Object.entries(viewportMap).map(([k, value]) => ({\n        value: k,\n        title: value.name,\n        icon: iconsMap[value.type!],\n        right: (\n          <Dimensions>\n            <span>{value.styles.width.replace('px', '')}</span>\n            <span>&times;</span>\n            <span>{value.styles.height.replace('px', '')}</span>\n          </Dimensions>\n        ),\n      })),\n    [viewportMap]\n  );\n\n  return (\n    <Select\n      resetLabel=\"Reset viewport\"\n      onReset={reset}\n      key=\"viewport\"\n      disabled={isLocked}\n      ariaLabel={isLocked ? 'Viewport size set by story parameters' : 'Viewport size'}\n      ariaDescription=\"Select a viewport among predefined options for the preview area, or reset to the default viewport.\"\n      tooltip={isLocked ? 'Viewport set by story parameters' : 'Change viewport'}\n      defaultOptions={value}\n      options={options}\n      onSelect={(selected) => select(selected as string)}\n      icon={<GrowIcon />}\n    >\n      {isDefault ? null : name}\n    </Select>\n  );\n};\n"
  },
  {
    "path": "code/core/src/viewport/constants.ts",
    "content": "export const ADDON_ID = 'storybook/viewport';\nexport const PARAM_KEY = 'viewport';\nexport const PANEL_ID = `${ADDON_ID}/panel`;\nexport const TOOL_ID = `${ADDON_ID}/tool`;\n"
  },
  {
    "path": "code/core/src/viewport/defaults.ts",
    "content": "import type { ViewportMap } from './types.ts';\n\nexport const INITIAL_VIEWPORTS = {\n  iphone5: {\n    name: 'iPhone 5',\n    styles: {\n      height: '568px',\n      width: '320px',\n    },\n    type: 'mobile',\n  },\n  iphone6: {\n    name: 'iPhone 6',\n    styles: {\n      height: '667px',\n      width: '375px',\n    },\n    type: 'mobile',\n  },\n  iphone6p: {\n    name: 'iPhone 6 Plus',\n    styles: {\n      height: '736px',\n      width: '414px',\n    },\n    type: 'mobile',\n  },\n  iphone8p: {\n    name: 'iPhone 8 Plus',\n    styles: {\n      height: '736px',\n      width: '414px',\n    },\n    type: 'mobile',\n  },\n  iphonex: {\n    name: 'iPhone X',\n    styles: {\n      height: '812px',\n      width: '375px',\n    },\n    type: 'mobile',\n  },\n  iphonexr: {\n    name: 'iPhone XR',\n    styles: {\n      height: '896px',\n      width: '414px',\n    },\n    type: 'mobile',\n  },\n  iphonexsmax: {\n    name: 'iPhone XS Max',\n    styles: {\n      height: '896px',\n      width: '414px',\n    },\n    type: 'mobile',\n  },\n  iphonese2: {\n    name: 'iPhone SE (2nd generation)',\n    styles: {\n      height: '667px',\n      width: '375px',\n    },\n    type: 'mobile',\n  },\n  iphone12mini: {\n    name: 'iPhone 12 mini',\n    styles: {\n      height: '812px',\n      width: '375px',\n    },\n    type: 'mobile',\n  },\n  iphone12: {\n    name: 'iPhone 12',\n    styles: {\n      height: '844px',\n      width: '390px',\n    },\n    type: 'mobile',\n  },\n  iphone12promax: {\n    name: 'iPhone 12 Pro Max',\n    styles: {\n      height: '926px',\n      width: '428px',\n    },\n    type: 'mobile',\n  },\n  iphoneSE3: {\n    name: 'iPhone SE 3rd generation',\n    styles: {\n      height: '667px',\n      width: '375px',\n    },\n    type: 'mobile',\n  },\n  iphone13: {\n    name: 'iPhone 13',\n    styles: {\n      height: '844px',\n      width: '390px',\n    },\n    type: 'mobile',\n  },\n  iphone13pro: {\n    name: 'iPhone 13 Pro',\n    styles: {\n      height: '844px',\n      width: '390px',\n    },\n    type: 'mobile',\n  },\n  iphone13promax: {\n    name: 'iPhone 13 Pro Max',\n    styles: {\n      height: '926px',\n      width: '428px',\n    },\n    type: 'mobile',\n  },\n  iphone14: {\n    name: 'iPhone 14',\n    styles: {\n      height: '844px',\n      width: '390px',\n    },\n    type: 'mobile',\n  },\n  iphone14pro: {\n    name: 'iPhone 14 Pro',\n    styles: {\n      height: '852px',\n      width: '393px',\n    },\n    type: 'mobile',\n  },\n  iphone14promax: {\n    name: 'iPhone 14 Pro Max',\n    styles: {\n      height: '932px',\n      width: '430px',\n    },\n    type: 'mobile',\n  },\n  ipad: {\n    name: 'iPad',\n    styles: {\n      height: '1024px',\n      width: '768px',\n    },\n    type: 'tablet',\n  },\n  ipad10p: {\n    name: 'iPad Pro 10.5-in',\n    styles: {\n      height: '1112px',\n      width: '834px',\n    },\n    type: 'tablet',\n  },\n  ipad11p: {\n    name: 'iPad Pro 11-in',\n    styles: {\n      height: '1194px',\n      width: '834px',\n    },\n    type: 'tablet',\n  },\n  ipad12p: {\n    name: 'iPad Pro 12.9-in',\n    styles: {\n      height: '1366px',\n      width: '1024px',\n    },\n    type: 'tablet',\n  },\n  galaxys5: {\n    name: 'Galaxy S5',\n    styles: {\n      height: '640px',\n      width: '360px',\n    },\n    type: 'mobile',\n  },\n  galaxys9: {\n    name: 'Galaxy S9',\n    styles: {\n      height: '740px',\n      width: '360px',\n    },\n    type: 'mobile',\n  },\n  nexus5x: {\n    name: 'Nexus 5X',\n    styles: {\n      height: '660px',\n      width: '412px',\n    },\n    type: 'mobile',\n  },\n  nexus6p: {\n    name: 'Nexus 6P',\n    styles: {\n      height: '732px',\n      width: '412px',\n    },\n    type: 'mobile',\n  },\n  pixel: {\n    name: 'Pixel',\n    styles: {\n      height: '960px',\n      width: '540px',\n    },\n    type: 'mobile',\n  },\n  pixelxl: {\n    name: 'Pixel XL',\n    styles: {\n      height: '1280px',\n      width: '720px',\n    },\n    type: 'mobile',\n  },\n} as const satisfies ViewportMap;\n\nexport type InitialViewportKeys = keyof typeof INITIAL_VIEWPORTS;\n\nexport const DEFAULT_VIEWPORT = 'responsive';\n\nexport const MINIMAL_VIEWPORTS = {\n  mobile1: {\n    name: 'Small mobile',\n    styles: {\n      height: '568px',\n      width: '320px',\n    },\n    type: 'mobile',\n  },\n  mobile2: {\n    name: 'Large mobile',\n    styles: {\n      height: '896px',\n      width: '414px',\n    },\n    type: 'mobile',\n  },\n  tablet: {\n    name: 'Tablet',\n    styles: {\n      height: '1112px',\n      width: '834px',\n    },\n    type: 'tablet',\n  },\n  desktop: {\n    name: 'Desktop',\n    styles: {\n      height: '1024px',\n      width: '1280px',\n    },\n    type: 'desktop',\n  },\n} as const satisfies ViewportMap;\n"
  },
  {
    "path": "code/core/src/viewport/index.ts",
    "content": "export * from './constants.ts';\nexport * from './types.ts';\nexport * from './defaults.ts';\nexport * from './responsiveViewport.tsx';\n"
  },
  {
    "path": "code/core/src/viewport/manager.tsx",
    "content": "import * as React from 'react';\n\nimport { addons, types } from 'storybook/manager-api';\n\nimport { ViewportTool } from './components/Tool.tsx';\nimport { ADDON_ID, TOOL_ID } from './constants.ts';\n\nexport default addons.register(ADDON_ID, () => {\n  if (globalThis?.FEATURES?.viewport) {\n    addons.add(TOOL_ID, {\n      title: 'viewport / media-queries',\n      type: types.TOOL,\n      match: ({ viewMode, tabId }) => viewMode === 'story' && !tabId,\n      render: () => <ViewportTool />,\n    });\n  }\n});\n"
  },
  {
    "path": "code/core/src/viewport/preview.ts",
    "content": "import { definePreviewAddon } from 'storybook/internal/csf';\n\nimport { PARAM_KEY } from './constants.ts';\nimport type { GlobalState, ViewportGlobals, ViewportTypes } from './types.ts';\n\nexport const initialGlobals: Record<string, GlobalState> = {\n  [PARAM_KEY]: { value: undefined, isRotated: false },\n};\n\nexport type { ViewportGlobals, ViewportTypes };\n\nexport default () =>\n  definePreviewAddon<ViewportTypes>({\n    initialGlobals,\n  });\n"
  },
  {
    "path": "code/core/src/viewport/responsiveViewport.tsx",
    "content": "import type { Viewport } from './types.ts';\n\n/** @deprecated Will be removed in Storybook 11 */\nexport const responsiveViewport: Viewport = {\n  name: 'Reset viewport',\n  styles: {\n    height: '100%',\n    width: '100%',\n  },\n  type: 'desktop',\n};\n"
  },
  {
    "path": "code/core/src/viewport/types.ts",
    "content": "export interface Viewport {\n  name: string;\n  styles: ViewportStyles;\n  type?: ViewportType;\n}\n\nexport type ViewportType = 'desktop' | 'mobile' | 'tablet' | 'watch' | 'other';\n\nexport interface ViewportStyles {\n  height: string;\n  width: string;\n}\n\nexport type ViewportMap = Record<string, Viewport>;\n\nexport type GlobalState = {\n  /**\n   * When set, the viewport is applied and cannot be changed using the toolbar. Must match the key\n   * of one of the available viewports or follow the format '{width}-{height}', e.g. '320-480' which\n   * may include a unit (e.g. '100vw' or '100pct').\n   */\n  value: string | undefined;\n\n  /**\n   * When true the viewport applied will be rotated 90°, e.g. it will rotate from portrait to\n   * landscape orientation.\n   */\n  isRotated?: boolean;\n};\n\nexport type GlobalStateUpdate = Partial<GlobalState>;\n\nexport interface ViewportParameters {\n  /**\n   * Viewport configuration\n   *\n   * @see https://storybook.js.org/docs/essentials/viewport#parameters\n   */\n  viewport?: {\n    /**\n     * Removes the tool and disables the feature's behavior. If you wish to turn off this feature\n     * for the entire Storybook, you can set the option in your `main.js|ts` configuration file.\n     *\n     * @see https://storybook.js.org/docs/essentials/viewport#disable\n     */\n    disable?: boolean;\n\n    /**\n     * Specify the available viewports. The width and height values must include the unit, e.g.\n     * '320px'.\n     */\n    options: Record<string, Viewport>;\n  };\n}\n\nexport interface ViewportGlobals {\n  /**\n   * Viewport configuration\n   *\n   * @see https://storybook.js.org/docs/essentials/viewport#globals\n   */\n  viewport?: GlobalState | GlobalState['value'];\n}\n\nexport interface ViewportTypes {\n  parameters: ViewportParameters;\n  globals: ViewportGlobals;\n}\n"
  },
  {
    "path": "code/core/src/viewport/useViewport.ts",
    "content": "import { useCallback, useEffect, useMemo, useRef } from 'react';\n\nimport type { Globals } from 'storybook/internal/csf';\n\nimport { useGlobals, useParameter, useStorybookApi } from 'storybook/manager-api';\n\nimport { ADDON_ID, PARAM_KEY } from './constants.ts';\nimport { MINIMAL_VIEWPORTS } from './defaults.ts';\nimport type {\n  GlobalState,\n  GlobalStateUpdate,\n  ViewportMap,\n  ViewportParameters,\n  ViewportType,\n} from './types.ts';\n\n// Custom viewport format, e.g. '100pct-200px' (width-height)\nconst URL_VALUE_PATTERN = /^([0-9]{1,4})([a-z]{0,4})-([0-9]{1,4})([a-z]{0,4})$/;\n\nexport const VIEWPORT_MIN_WIDTH = 40;\nexport const VIEWPORT_MIN_HEIGHT = 40;\n\nconst cycle = (\n  viewports: ViewportMap,\n  current: string | undefined,\n  direction: 1 | -1 = 1\n): string => {\n  const keys = Object.keys(viewports);\n  const currentIndex = current ? keys.indexOf(current) : -1;\n  const nextIndex = currentIndex + direction;\n  return nextIndex < 0\n    ? keys[keys.length - 1]\n    : nextIndex >= keys.length\n      ? keys[0]\n      : keys[nextIndex];\n};\n\nconst normalizeGlobal = (\n  value: string | GlobalState | GlobalStateUpdate,\n  defaultIsRotated?: boolean\n): GlobalState =>\n  typeof value === 'string'\n    ? { value, isRotated: defaultIsRotated }\n    : { value: value?.value, isRotated: value?.isRotated ?? defaultIsRotated };\n\nconst parseGlobals = (\n  globals: Globals,\n  storyGlobals: Globals,\n  userGlobals: Globals,\n  options: ViewportMap,\n  lastSelectedOption: string | undefined,\n  disable: boolean,\n  viewMode: string | undefined\n): {\n  name: string;\n  type: ViewportType;\n  width: string;\n  height: string;\n  value: string;\n  option: string | undefined;\n  isCustom: boolean;\n  isDefault: boolean;\n  isLocked: boolean;\n  isRotated: boolean;\n} => {\n  if (viewMode !== 'story') {\n    return {\n      name: 'Responsive',\n      type: 'desktop',\n      width: '100%',\n      height: '100%',\n      value: '100pct-100pct',\n      option: undefined,\n      isCustom: false,\n      isDefault: true,\n      isLocked: true,\n      isRotated: false,\n    };\n  }\n\n  const global = normalizeGlobal(globals?.[PARAM_KEY]);\n  const userGlobal = normalizeGlobal(userGlobals?.[PARAM_KEY]);\n  const storyGlobal = normalizeGlobal(storyGlobals?.[PARAM_KEY]);\n  const storyHasViewport = PARAM_KEY in storyGlobals;\n\n  // Story-level viewport globals override user globals for the current story.\n  const primaryGlobal = storyHasViewport ? storyGlobal : userGlobal;\n  const secondaryGlobal = storyHasViewport ? userGlobal : storyGlobal;\n  const value = primaryGlobal?.value ?? secondaryGlobal?.value ?? global?.value;\n  const isRotated =\n    primaryGlobal?.isRotated ?? secondaryGlobal?.isRotated ?? global?.isRotated ?? false;\n\n  const keys = Object.keys(options);\n  const isLocked = disable || PARAM_KEY in storyGlobals || !keys.length;\n  const [match, vx, ux, vy, uy] = value?.match(URL_VALUE_PATTERN) || [];\n\n  if (match) {\n    // Clamp pixel values to at least MIN_WIDTH / MIN_HEIGHT\n    const x = ux && ux !== 'px' ? vx : Math.max(Number(vx), VIEWPORT_MIN_WIDTH);\n    const y = uy && uy !== 'px' ? vy : Math.max(Number(vy), VIEWPORT_MIN_HEIGHT);\n\n    // Ensure we have a valid CSS value, including unit\n    const width = `${x}${ux === 'pct' ? '%' : ux || 'px'}`;\n    const height = `${y}${uy === 'pct' ? '%' : uy || 'px'}`;\n\n    const selection = lastSelectedOption ? options[lastSelectedOption] : undefined;\n    return {\n      name: selection?.name ?? 'Custom',\n      type: selection?.type ?? 'other',\n      width: isRotated ? height : width,\n      height: isRotated ? width : height,\n      value: match,\n      option: undefined,\n      isCustom: true,\n      isDefault: false,\n      isLocked,\n      isRotated,\n    };\n  }\n\n  if (value && keys.length) {\n    const { name, styles, type = 'other' } = options[value] ?? options[keys[0]];\n    return {\n      name,\n      type,\n      width: isRotated ? styles.height : styles.width,\n      height: isRotated ? styles.width : styles.height,\n      value,\n      option: value,\n      isCustom: false,\n      isDefault: false,\n      isLocked,\n      isRotated,\n    };\n  }\n\n  return {\n    name: 'Responsive',\n    type: 'desktop',\n    width: '100%',\n    height: '100%',\n    value: '100pct-100pct',\n    option: undefined,\n    isCustom: false,\n    isDefault: true,\n    isLocked,\n    isRotated: false,\n  };\n};\n\nexport const useViewport = () => {\n  const api = useStorybookApi();\n  const { viewMode } = api.getUrlState();\n\n  const lastSelectedOption = useRef<string | undefined>();\n\n  const parameter = useParameter<ViewportParameters['viewport']>(PARAM_KEY);\n  const [globals, updateGlobals, storyGlobals, userGlobals] = useGlobals();\n\n  const { options = MINIMAL_VIEWPORTS, disable = false } = parameter || {};\n  const { name, type, width, height, value, option, isCustom, isDefault, isLocked, isRotated } =\n    parseGlobals(\n      globals,\n      storyGlobals,\n      userGlobals,\n      options,\n      lastSelectedOption.current,\n      disable,\n      viewMode\n    );\n\n  const update = useCallback(\n    (input: GlobalStateUpdate) => updateGlobals({ [PARAM_KEY]: normalizeGlobal(input, false) }),\n    [updateGlobals]\n  );\n\n  const resize = useCallback(\n    (width: string, height: string) => {\n      const w = width.replace(/px$/, '').replace(/%$/, 'pct');\n      const h = height.replace(/px$/, '').replace(/%$/, 'pct');\n      const value = isRotated ? `${h}-${w}` : `${w}-${h}`;\n      update({ value, isRotated });\n    },\n    [update, isRotated]\n  );\n\n  useEffect(() => {\n    // Skip if parameter not loaded to avoid race condition with default MINIMAL_VIEWPORTS\n    if (!parameter) {\n      return;\n    }\n\n    // Track valid options; if invalid and no story-level viewport is set, reset to default\n    if (option) {\n      if (Object.hasOwn(options, option)) {\n        lastSelectedOption.current = option;\n      } else {\n        lastSelectedOption.current = undefined;\n        if (!(PARAM_KEY in storyGlobals)) {\n          update({ value: undefined, isRotated: false });\n        }\n      }\n    }\n  }, [parameter, storyGlobals, options, option, update]);\n\n  useEffect(() => {\n    api.setAddonShortcut(ADDON_ID, {\n      label: 'Next viewport',\n      defaultShortcut: ['alt', 'V'],\n      actionName: 'next',\n      action: () => update({ value: cycle(options, lastSelectedOption.current), isRotated }),\n    });\n    api.setAddonShortcut(ADDON_ID, {\n      label: 'Previous viewport',\n      defaultShortcut: ['alt', 'shift', 'V'],\n      actionName: 'previous',\n      action: () => update({ value: cycle(options, lastSelectedOption.current, -1), isRotated }),\n    });\n    api.setAddonShortcut(ADDON_ID, {\n      label: 'Reset viewport',\n      defaultShortcut: ['alt', 'control', 'V'],\n      actionName: 'reset',\n      action: () => update({ value: undefined, isRotated: false }),\n    });\n  }, [api, update, options, isRotated]);\n\n  return useMemo(\n    () => ({\n      name,\n      type,\n      width,\n      height,\n      value,\n      option,\n      isCustom,\n      isDefault,\n      isLocked,\n      isRotated,\n      options,\n      lastSelectedOption: lastSelectedOption.current,\n      resize,\n      reset: () => update({ value: undefined, isRotated: false }),\n      rotate: () => update({ value, isRotated: !isRotated }),\n      select: (value: string) => update({ value, isRotated }),\n    }),\n    [\n      name,\n      type,\n      width,\n      height,\n      value,\n      option,\n      isCustom,\n      isDefault,\n      isRotated,\n      isLocked,\n      options,\n      resize,\n      update,\n    ]\n  );\n};\n"
  },
  {
    "path": "code/core/src/viewport/viewportIcons.tsx",
    "content": "import React from 'react';\n\nimport { BrowserIcon, DiamondIcon, MobileIcon, TabletIcon, WatchIcon } from '@storybook/icons';\n\nimport type { Viewport } from './types.ts';\n\nexport const iconsMap: Record<NonNullable<Viewport['type']>, React.ReactNode> = {\n  desktop: <BrowserIcon />,\n  mobile: <MobileIcon />,\n  tablet: <TabletIcon />,\n  watch: <WatchIcon />,\n  other: <DiamondIcon />,\n};\n"
  },
  {
    "path": "code/core/template/__mocks__/lodash-es/add.js",
    "content": "function add(a, b) {\n  return 'mocked 3';\n}\n\nexport default add;\n"
  },
  {
    "path": "code/core/template/__mocks__/lodash-es.js",
    "content": "export default {\n  VERSION: '1.0.0-mocked!',\n};\n"
  },
  {
    "path": "code/core/template/__mocks__/uuid.js",
    "content": "export function v4() {\n  return 'MOCK-V4';\n}\n"
  },
  {
    "path": "code/core/template/stories/argMapping.stories.ts",
    "content": "import type { PartialStoryFn, PlayFunctionContext, StoryContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nimport { expect, within } from 'storybook/test';\n\nconst arrows = {\n  ArrowUp: { name: 'ArrowUp' },\n  ArrowDown: { name: 'ArrowDown' },\n  ArrowLeft: { name: 'ArrowLeft' },\n  ArrowRight: { name: 'ArrowRight' },\n};\n\nconst labels = {\n  ArrowUp: 'Up',\n  ArrowDown: 'Down',\n  ArrowLeft: 'Left',\n  ArrowRight: 'Right',\n};\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) => {\n      return storyFn({\n        args: { object: { ...context.args } },\n      });\n    },\n  ],\n};\n\nexport const Single = {\n  args: {\n    mappingArg: 'ArrowRight',\n  },\n  argTypes: {\n    mappingArg: {\n      options: Object.keys(arrows),\n      mapping: arrows,\n      control: {\n        type: 'select',\n        labels,\n      },\n    },\n  },\n  play: async ({ canvasElement }: PlayFunctionContext<any>) => {\n    await expect(JSON.parse(within(canvasElement).getByTestId('pre').innerText)).toMatchObject({\n      mappingArg: { name: 'ArrowRight' },\n    });\n  },\n};\n\nexport const Multiple = {\n  args: {\n    mappingArg: ['ArrowRight', 'ArrowLeft'],\n  },\n  argTypes: {\n    mappingArg: {\n      options: Object.keys(arrows),\n      mapping: arrows,\n      control: {\n        type: 'multi-select',\n        labels,\n      },\n    },\n  },\n  play: async ({ canvasElement }: PlayFunctionContext<any>) => {\n    await expect(JSON.parse(within(canvasElement).getByTestId('pre').innerText)).toMatchObject({\n      mappingArg: [{ name: 'ArrowRight' }, { name: 'ArrowLeft' }],\n    });\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/argTypes.stories.ts",
    "content": "import type { PartialStoryFn, PlayFunctionContext, StoryContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nimport { expect, within } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  // Compose all the argTypes into `object`, so the pre component only needs a single prop\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) =>\n      storyFn({ args: { object: { ...context.argTypes } } }),\n  ],\n  argTypes: {\n    componentArg: { type: 'string' },\n    storyArg: { type: 'string' },\n    composedArg: { type: 'string' },\n  },\n};\n\nexport const Inheritance = {\n  argTypes: {\n    storyArg: { type: 'number' },\n    composedArg: { options: ['a', 'b'] },\n  },\n  play: async ({ canvasElement }: PlayFunctionContext<any>) => {\n    // NOTE: these stories don't test project-level argTypes inheritance as it is too problematic\n    // to have an argType floating around that will apply too *all* other stories in our sandboxes.\n    await expect(JSON.parse(within(canvasElement).getByTestId('pre').innerText)).toMatchObject({\n      componentArg: { type: { name: 'string' } },\n      storyArg: { type: { name: 'number' } },\n      composedArg: { type: { name: 'string' }, options: ['a', 'b'] },\n    });\n  },\n};\n\n// Check the inferred arg types from the args\nexport const ArgTypeInference = {\n  args: {\n    a: 1,\n    b: '1',\n    c: true,\n    d: { a: 'b' },\n    e: ['a', 'b'],\n  },\n  play: async ({ canvasElement }: PlayFunctionContext<any>) => {\n    await expect(JSON.parse(within(canvasElement).getByTestId('pre').innerText)).toMatchObject({\n      a: { type: { name: 'number' } },\n      b: { type: { name: 'string' } },\n      c: { type: { name: 'boolean' } },\n      d: { type: { name: 'object', value: { a: { name: 'string' } } } },\n      e: { type: { name: 'array', value: { name: 'string' } } },\n    });\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/args.stories.ts",
    "content": "import {\n  RESET_STORY_ARGS,\n  STORY_ARGS_UPDATED,\n  UPDATE_STORY_ARGS,\n} from 'storybook/internal/core-events';\nimport type { PartialStoryFn, PlayFunctionContext, StoryContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nimport { expect, within } from 'storybook/test';\n\nfunction pick(obj, keys) {\n  const result = {};\n  for (const key of keys) {\n    result[key] = obj[key];\n  }\n  return result;\n}\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  args: {\n    componentArg: 'componentArg',\n    storyArg: 'componentStoryArg',\n    object: {\n      a: 'component',\n      b: 'component',\n    },\n  },\n  // Compose the set of  args into `object`, so the pre component only needs a single prop\n  //   (selecting only the args specified on parameters.argNames if set)\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) => {\n      const { argNames } = context.parameters;\n      const args = { ...context.args };\n      const object = argNames ? pick(args, argNames) : args;\n      return storyFn({ args: { object } });\n    },\n  ],\n};\n\nexport const Inheritance = {\n  args: {\n    storyArg: 'storyArg',\n    object: {\n      a: 'story',\n    },\n  },\n  play: async ({ canvasElement }: PlayFunctionContext<any>) => {\n    // NOTE: these stories don't test project-level args inheritance as it is too problematic\n    // to have an arg floating around that will apply too *all* other stories in our sandboxes.\n    await expect(JSON.parse(within(canvasElement).getByTestId('pre').innerText)).toEqual({\n      componentArg: 'componentArg',\n      storyArg: 'storyArg',\n      object: {\n        a: 'story',\n      },\n    });\n  },\n};\n\nexport const Targets = {\n  args: {\n    a: 'a',\n    b: 'b',\n  },\n  argTypes: {\n    a: { target: 'elsewhere' },\n  },\n  parameters: { argNames: ['a', 'b'] },\n  play: async ({ canvasElement }: PlayFunctionContext<any>) => {\n    // Check that `a` doesn't end up set\n    await expect(JSON.parse(within(canvasElement).getByTestId('pre').innerText)).toEqual({\n      b: 'b',\n    });\n  },\n  tags: ['!vitest'],\n};\n\nexport const Events = {\n  args: {\n    test: 'initial',\n  },\n  parameters: { argNames: ['test'] },\n  play: async ({ canvasElement, id }: PlayFunctionContext<any>) => {\n    const channel = globalThis.__STORYBOOK_ADDONS_CHANNEL__;\n    await channel.emit(RESET_STORY_ARGS, { storyId: id });\n    await new Promise((resolve) => channel.once(STORY_ARGS_UPDATED, resolve));\n\n    await within(canvasElement).findByText(/initial/);\n\n    await channel.emit(UPDATE_STORY_ARGS, { storyId: id, updatedArgs: { test: 'updated' } });\n    await new Promise((resolve) => channel.once(STORY_ARGS_UPDATED, resolve));\n    await within(canvasElement).findByText(/updated/);\n  },\n  // this story can't be reliably tested because the args changes results in renderPhases disrupting test runs\n  tags: ['!vitest', '!test'],\n};\n"
  },
  {
    "path": "code/core/template/stories/argtype.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  args: {\n    label: 'Click Me!',\n  },\n  argTypes: {\n    onClick: {},\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n    actions: { argTypesRegex: '^on.*' },\n  },\n};\n\nexport const String = {\n  argTypes: {\n    onClick: { action: 'clicked!' },\n  },\n};\nexport const Boolean = {\n  argTypes: {\n    onClick: { action: true },\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/autotitle.stories.ts",
    "content": "import type { PlayFunctionContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nimport { expect } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  args: { text: 'No content' },\n};\n\nexport const Default = {\n  play: async ({ title }: PlayFunctionContext<any>) => {\n    await expect(title).toBe('core/autotitle');\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/backgrounds/globals.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  args: {\n    text: 'Testing the background',\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n    backgrounds: {\n      options: {\n        red: { name: 'light', value: 'red' },\n        darker: { name: 'darker', value: '#000' },\n      },\n    },\n  },\n};\n\nexport const Set = {\n  globals: {\n    backgrounds: { value: 'red' },\n  },\n};\n\nexport const Shorthand = {\n  globals: {\n    backgrounds: 'red',\n  },\n};\n\nexport const SetAndCustom = {\n  parameters: {\n    backgrounds: {\n      options: {\n        pink: { value: '#F99CB4', name: 'pink' },\n      },\n    },\n  },\n  globals: {\n    backgrounds: { value: 'pink' },\n  },\n};\n\nexport const UnsetCustom = {\n  parameters: {\n    backgrounds: {\n      options: {\n        pink: { value: '#Ff5CB7', name: 'hot pink' },\n      },\n    },\n  },\n};\n\nexport const Disabled = {\n  parameters: {\n    backgrounds: {\n      disable: true,\n    },\n  },\n};\n\nexport const Grid = {\n  globals: {\n    backgrounds: { grid: true },\n  },\n};\n\nexport const GridAndBackground = {\n  globals: {\n    backgrounds: { grid: true, value: 'darker' },\n  },\n};\n\nexport const GridConfig = {\n  parameters: {\n    backgrounds: {\n      grid: {\n        cellSize: 100,\n        cellAmount: 10,\n        opacity: 0.8,\n      },\n    },\n  },\n  globals: {\n    backgrounds: { grid: true, value: 'light' },\n  },\n};\n\nexport const GridOffset = {\n  parameters: {\n    backgrounds: {\n      grid: {\n        cellSize: 100,\n        cellAmount: 10,\n        opacity: 0.8,\n        offsetX: 50,\n        offsetY: 50,\n      },\n    },\n  },\n  globals: {\n    backgrounds: { grid: true, value: 'light' },\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/basics.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { action } from 'storybook/actions';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  args: {\n    label: 'Click Me!',\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const Basic = {\n  args: { onClick: action('onClick') },\n};\n\nexport const TypeString = {\n  args: { onClick: () => action('onClick')('string') },\n};\nexport const TypeBoolean = {\n  args: { onClick: () => action('onClick')(false) },\n};\nexport const TypeObject = {\n  args: { onClick: () => action('onClick')({}) },\n};\nexport const TypeNull = {\n  args: { onClick: () => action('onClick')(null) },\n};\nexport const TypeUndefined = {\n  args: { onClick: () => action('onClick')(undefined) },\n};\nexport const TypeNaN = {\n  args: { onClick: () => action('onClick')(NaN) },\n};\nexport const TypeInfinity = {\n  args: { onClick: () => action('onClick')(Infinity) },\n};\nexport const TypeMinusInfinity = {\n  args: { onClick: () => action('onClick')(-Infinity) },\n};\nexport const TypeNumber = {\n  args: { onClick: () => action('onClick')(10000) },\n};\nexport const TypeGlobal = {\n  args: { onClick: () => action('onClick')(globalThis) },\n};\nexport const TypeSymbol = {\n  args: { onClick: () => action('onClick')(Symbol('MySymbol')) },\n};\nexport const TypeRegExp = {\n  args: { onClick: () => action('onClick')(new RegExp('MyRegExp')) },\n};\nexport const TypeArray = {\n  args: { onClick: () => action('onClick')(['a', 'b', 'c']) },\n};\nexport const TypeClass = {\n  args: { onClick: () => action('onClick')(class MyClass {}) },\n};\nexport const TypeFunction = {\n  args: { onClick: () => action('onClick')(function MyFunction() {}) },\n};\nexport const TypeMultiple = {\n  args: { onClick: () => action('onClick')('string', true, false, null, undefined, [], {}) },\n};\n\nexport const Cyclical = {\n  args: {\n    onClick: () =>\n      action('onClick')(\n        (() => {\n          const cyclical: Record<string, any> = {};\n          cyclical.cyclical = cyclical;\n          return cyclical;\n        })()\n      ),\n  },\n};\n\nexport const Reserved = {\n  args: { onClick: action('delete') },\n};\n\nexport const OptionPersist = {\n  args: { onClick: action('onClick', { clearOnStoryChange: false }) },\n};\nexport const OptionDepth = {\n  args: { onClick: action('onClick', { depth: 2 }) },\n};\n\nexport const Disabled = {\n  args: { onClick: action('onCLick') },\n  parameters: {\n    actions: {\n      disabled: true,\n    },\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/before-each.stories.ts",
    "content": "/* eslint-disable storybook/prefer-pascal-case */\nimport { expect } from 'storybook/test';\n\nconst meta = {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  args: { label: 'Button' },\n};\n\nexport default meta;\n\nexport const before_each_and_loaders_can_extend_context = {\n  parameters: { chromatic: { disableSnapshot: true } },\n  loaders(context) {\n    context.foo = ['bar'];\n  },\n  beforeEach(context) {\n    context.foo = [...context.foo, 'baz'];\n  },\n  async play({ foo }) {\n    await expect(foo).toEqual(['bar', 'baz']);\n  },\n};\n\nexport const context_prop_is_available = {\n  parameters: { chromatic: { disableSnapshot: true } },\n  async play({ context, canvasElement }) {\n    await expect(context.canvasElement).toEqual(canvasElement);\n  },\n};\n\nexport const step_and_canvas_element_can_be_used_in_loaders_and_before_each = {\n  parameters: { chromatic: { disableSnapshot: true } },\n  loaders({ step, canvasElement }) {\n    step('loaders', async () => {\n      await expect(canvasElement).toBeInTheDocument();\n    });\n  },\n  beforeEach({ step, canvasElement }) {\n    step('before each', async () => {\n      await expect(canvasElement).toBeInTheDocument();\n    });\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/component-play.stories.ts",
    "content": "import type { PartialStoryFn, PlayFunctionContext, StoryContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nimport { expect, within } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  play: async ({ canvasElement, name }: PlayFunctionContext) => {\n    await expect(\n      JSON.parse(within(canvasElement as HTMLPreElement).getByTestId('pre').innerText)\n    ).toEqual({\n      name,\n    });\n  },\n  // Render the story name into the Pre\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) => {\n      const { name } = context;\n      return storyFn({ args: { object: { name } } });\n    },\n  ],\n};\n\nexport const StoryOne = {};\nexport const StoryTwo = {};\n\nexport const DisabledInteractions = {\n  parameters: {\n    interactions: {\n      disable: true,\n    },\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/component-test.basics.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport {\n  expect,\n  fireEvent,\n  fn,\n  userEvent as testUserEvent,\n  waitFor,\n  waitForElementToBeRemoved,\n  within,\n} from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Form,\n  args: {\n    onSuccess: fn(),\n  },\n  globals: {\n    sb_theme: 'light',\n  },\n  tags: ['!vitest'],\n};\n\nexport const Validation = {\n  play: async (context) => {\n    const { args, canvasElement, step } = context;\n    const canvas = within(canvasElement);\n\n    await step('Submit', async () => fireEvent.click(canvas.getByRole('button')));\n\n    await expect(args.onSuccess).not.toHaveBeenCalled();\n  },\n};\n\nexport const Type = {\n  play: async ({ canvasElement, userEvent }) => {\n    const canvas = within(canvasElement);\n    await userEvent.type(canvas.getByTestId('value'), 'foobar');\n  },\n};\n\nexport const Step = {\n  play: async ({ step }) => {\n    await step('Enter value', Type.play);\n  },\n};\n\nexport const TypeAndClear = {\n  play: async ({ canvasElement, userEvent }) => {\n    const canvas = within(canvasElement);\n    await userEvent.type(canvas.getByTestId('value'), 'initial value');\n    await userEvent.clear(canvas.getByTestId('value'));\n    await userEvent.type(canvas.getByTestId('value'), 'final value');\n  },\n};\n\nexport const Callback = {\n  play: async ({ args, canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    await step('Enter value', Type.play);\n\n    await step('Submit', async () => {\n      await fireEvent.click(canvas.getByRole('button'));\n    });\n\n    await expect(args.onSuccess).toHaveBeenCalled();\n  },\n};\n\n// NOTE: of course you can use `findByText()` to implicitly waitFor, but we want\n// an explicit test here\nexport const SyncWaitFor = {\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    await step('Submit form', Callback.play);\n    await waitFor(() => canvas.getByText('Completed!!'));\n    await waitForElementToBeRemoved(() => canvas.queryByText('Completed!!'), {\n      timeout: 2000,\n    });\n  },\n};\n\nexport const AsyncWaitFor = {\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    await step('Submit form', Callback.play);\n    await waitFor(async () => canvas.getByText('Completed!!'));\n    await waitForElementToBeRemoved(() => canvas.queryByText('Completed!!'), {\n      timeout: 2000,\n    });\n  },\n};\n\nexport const WithLoaders = {\n  loaders: [async () => new Promise((resolve) => setTimeout(resolve, 2000))],\n  play: async ({ step }) => {\n    await step('Submit form', Callback.play);\n  },\n};\n\nconst UserEventSetup = {\n  play: async (context) => {\n    const { args, canvasElement, step, userEvent } = context;\n    const canvas = within(canvasElement);\n    await step('Select and type on input using user-event v14 setup', async () => {\n      const input = canvas.getByRole('textbox');\n      await userEvent.click(input);\n      await userEvent.type(input, 'Typing ...');\n    });\n    await step('Tab and press enter on submit button', async () => {\n      // Vitest's userEvent does not support pointer events, so we use storybook's\n      await testUserEvent.pointer([\n        { keys: '[TouchA>]', target: canvas.getByRole('textbox') },\n        { keys: '[/TouchA]' },\n      ]);\n      const submitButton = await canvas.findByRole('button');\n\n      if (navigator.userAgent.toLowerCase().includes('firefox')) {\n        // user event has a few issues on firefox, therefore we do it differently\n        await fireEvent.click(submitButton);\n      } else {\n        await userEvent.tab();\n        await userEvent.keyboard('{enter}');\n        await expect(submitButton).toHaveFocus();\n      }\n\n      await expect(args.onSuccess).toHaveBeenCalled();\n    });\n  },\n};\n\nexport { UserEventSetup };\n"
  },
  {
    "path": "code/core/template/stories/component-test.unhandled-errors.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { userEvent, within } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  args: {\n    label: 'Button',\n    // onClick: fn(), <-- this is intentionally missing to trigger an unhandled error\n  },\n  argTypes: {\n    onClick: { type: 'function' },\n  },\n  parameters: {\n    actions: { argTypesRegex: '^on[A-Z].*' },\n    chromatic: { disableSnapshot: true },\n  },\n  tags: ['!test', '!vitest'],\n};\n\nexport const Default = {\n  play: async (context) => {\n    const { args, canvasElement } = context;\n    const canvas = within(canvasElement);\n    await userEvent.click(canvas.getByRole('button'));\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/configs.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { actions, configureActions } from 'storybook/actions';\n\nconst configs = actions('actionA', 'actionB', 'actionC');\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  args: {\n    label: 'Click Me!',\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const ActionA = {\n  args: { onClick: configs.actionA },\n};\nexport const ActionB = {\n  args: { onClick: configs.actionB },\n};\nexport const ActionC = {\n  args: { onClick: configs.actionC },\n};\n\nexport const ConfigureActions = {\n  args: { onClick: configs.actionA },\n  decorators: [\n    (storyFn: any) => {\n      configureActions({ depth: 2 });\n\n      return storyFn();\n    },\n  ],\n};\n"
  },
  {
    "path": "code/core/template/stories/controls/basics.stories.ts",
    "content": "import type { PartialStoryFn, StoryContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) =>\n      storyFn({ args: { object: { ...context.args } } }),\n  ],\n  argTypes: {\n    boolean: { control: 'boolean' },\n    color: { control: 'color' },\n    colorWithPresets: {\n      control: {\n        type: 'color',\n        presetColors: ['#ff0', 'pink', { color: '#00f', title: 'mystery' }],\n      },\n    },\n    colorStartOpen: { control: { type: 'color', startOpen: true } },\n    date: { control: 'date' },\n    file: { control: { type: 'file', accept: '.png' }, name: 'Image Urls' },\n    number: { control: 'number' },\n    object: { control: 'object' },\n    radio: { control: { type: 'radio', options: ['a', 'b', 'c'] } },\n    radioWithLabels: {\n      control: { type: 'radio', options: ['a', 'b', 'c'], labels: ['alpha', 'beta', 'gamma'] },\n    },\n    inlineRadio: { control: { type: 'inline-radio', options: ['a', 'b', 'c'] } },\n    select: { control: 'select', options: ['a', 'b', 'c', 'double  space'] },\n    multiSelect: { control: { type: 'multi-select' }, options: ['a', 'b', 'c', 'double  space'] },\n    range: { control: 'range' },\n    rangeCustom: { control: { type: 'range', min: 0, max: 1000, step: 100 } },\n    text: { control: 'text' },\n  },\n};\n\nexport const Undefined = {\n  args: {},\n};\n\nconst DEFAULT_NESTED_OBJECT = {\n  text: 'Hello world',\n  boolean: true,\n  array: ['One', 'Two', 'Three'],\n  object: { a: 1, b: 2, c: 3 },\n};\nexport const Defined = {\n  args: {\n    boolean: true,\n    color: '#ff0',\n    colorWithPresets: 'pink',\n    colorStartOpen: 'orange',\n    date: new Date(2010, 1, 1),\n    file: ['https://storybook.js.org/images/placeholders/350x150.png'],\n    number: 10,\n    object: DEFAULT_NESTED_OBJECT,\n    radio: 'a',\n    radioWithLabels: 'b',\n    inlineRadio: 'c',\n    select: 'b',\n    multiSelect: ['a'],\n    range: 15,\n    rangeCustom: 10,\n    text: 'hello',\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/controls/conditional.stories.ts",
    "content": "import type { PartialStoryFn, StoryContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) =>\n      storyFn({ args: { object: { ...context.args } } }),\n  ],\n};\n\nexport const MutuallyExclusiveModes = {\n  argTypes: {\n    mutuallyExclusiveA: { control: 'text', if: { arg: 'mutuallyExclusiveB', truthy: false } },\n    mutuallyExclusiveB: { control: 'text', if: { arg: 'mutuallyExclusiveA', truthy: false } },\n  },\n};\n\nexport const ToggleControl = {\n  argTypes: {\n    colorMode: {\n      control: 'boolean',\n    },\n    dynamicText: {\n      if: { arg: 'colorMode', truthy: false },\n      control: 'text',\n    },\n    dynamicColor: {\n      if: { arg: 'colorMode' },\n      control: 'color',\n    },\n  },\n};\n\nexport const ToggleExpandCollapse = {\n  argTypes: {\n    advanced: {\n      control: 'boolean',\n    },\n    margin: {\n      control: 'number',\n      if: { arg: 'advanced' },\n    },\n    padding: {\n      control: 'number',\n      if: { arg: 'advanced' },\n    },\n    cornerRadius: {\n      control: 'number',\n      if: { arg: 'advanced' },\n    },\n  },\n};\n\nexport const GlobalBased = {\n  argTypes: {\n    ifThemeExists: { control: 'text', if: { global: 'sb_theme' } },\n    ifThemeNotExists: { control: 'text', if: { global: 'sb_theme', exists: false } },\n    ifLightTheme: { control: 'text', if: { global: 'sb_theme', eq: 'light' } },\n    ifNotLightTheme: { control: 'text', if: { global: 'sb_theme', neq: 'light' } },\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/controls/disable.stories.ts",
    "content": "import type { PartialStoryFn, StoryContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) =>\n      storyFn({ args: { object: { ...context.args } } }),\n  ],\n};\n\nexport const DisableTable = {\n  args: { a: 'a', b: 'b' },\n  argTypes: {\n    b: { table: { disable: true } },\n  },\n};\n\nexport const DisableControl = {\n  args: { a: 'a', b: 'b' },\n  argTypes: {\n    b: { control: { disable: true } },\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/controls/filters.stories.ts",
    "content": "import type { PartialStoryFn, StoryContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) =>\n      storyFn({ args: { object: { ...context.args } } }),\n  ],\n  args: {\n    helloWorld: 1,\n    helloPlanet: 1,\n    byeWorld: 1,\n  },\n};\n\nexport const IncludeList = {\n  parameters: {\n    controls: {\n      include: ['helloWorld'],\n    },\n  },\n};\n\nexport const IncludeRegex = {\n  parameters: {\n    controls: {\n      include: /hello*/,\n    },\n  },\n};\n\nexport const ExcludeList = {\n  parameters: {\n    controls: {\n      exclude: ['helloPlanet', 'helloWorld'],\n    },\n  },\n};\n\nexport const ExcludeRegex = {\n  parameters: {\n    controls: {\n      exclude: /hello*/,\n    },\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/controls/issues.stories.ts",
    "content": "import type { PartialStoryFn, StoryContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) =>\n      storyFn({ args: { object: { ...context.args } } }),\n  ],\n};\n\n// https://github.com/storybookjs/storybook/issues/14752\nexport const MissingRadioOptions = {\n  argTypes: { invalidRadio: { control: 'radio' } },\n  args: { invalidRadio: 'someValue' },\n};\n"
  },
  {
    "path": "code/core/template/stories/controls/matchers.stories.ts",
    "content": "import type { PartialStoryFn, StoryContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) =>\n      storyFn({ args: { object: { ...context.args } } }),\n  ],\n};\n\nexport const CustomMatchers = {\n  parameters: {\n    controls: {\n      matchers: {\n        date: /whateverIwant/,\n      },\n    },\n    docs: { source: { state: 'open' } },\n  },\n  args: {\n    whateverIwant: '10/10/2020',\n  },\n};\n\nexport const DisabledMatchers = {\n  parameters: {\n    controls: {\n      matchers: {\n        date: null,\n        color: null,\n      },\n    },\n  },\n  args: {\n    purchaseDate: '10/10/2020',\n    backgroundColor: '#BADA55',\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/controls/sorting.stories.ts",
    "content": "import type { PartialStoryFn, StoryContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) =>\n      storyFn({ args: { object: { ...context.args } } }),\n  ],\n  argTypes: {\n    x: { type: { required: true } },\n    y: { type: { required: true }, table: { category: 'foo' } },\n    z: {},\n    a: { type: { required: true } },\n    b: { table: { category: 'foo' } },\n    c: {},\n  },\n  args: {\n    x: 'x',\n    y: 'y',\n    z: 'z',\n    a: 'a',\n    b: 'b',\n    c: 'c',\n  },\n  parameters: { chromatic: { disableSnapshot: true } },\n};\n\nexport const None = { parameters: { controls: { sort: 'none' } } };\n\nexport const Alpha = { parameters: { controls: { sort: 'alpha' } } };\n\nexport const RequiredFirst = { parameters: { controls: { sort: 'requiredFirst' } } };\n"
  },
  {
    "path": "code/core/template/stories/decorators.stories.ts",
    "content": "import {\n  RESET_STORY_ARGS,\n  STORY_ARGS_UPDATED,\n  UPDATE_STORY_ARGS,\n} from 'storybook/internal/core-events';\nimport type {\n  ArgsStoryFn,\n  PartialStoryFn,\n  PlayFunctionContext,\n  StoryContext,\n} from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nimport { useEffect } from 'storybook/preview-api';\nimport { expect, within } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  parameters: { useProjectDecorator: true },\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) =>\n      storyFn({ args: { ...context.args, text: `component ${context.args.text}` } }),\n  ],\n};\n\nexport const Inheritance = {\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) =>\n      storyFn({ args: { ...context.args, text: `story ${context.args.text}` } }),\n  ],\n  args: {\n    text: 'starting',\n  },\n  play: async ({ canvasElement }: PlayFunctionContext<any>) => {\n    const canvas = within(canvasElement);\n    await expect(canvas.getByTestId('pre').innerText).toEqual('story component project starting');\n  },\n};\n\n// NOTE this story is currently broken in Chromatic for both Vue2/Vue3\n// Issue: https://github.com/storybookjs/storybook/issues/22945\nexport const Hooks = {\n  decorators: [\n    // decorator that uses hooks\n    (storyFn: PartialStoryFn, context: StoryContext) => {\n      useEffect(() => {});\n      return storyFn({ args: { ...context.args, text: `story ${context.args.text}` } });\n    },\n    // conditional decorator, runs before the above\n    (storyFn: PartialStoryFn, context: StoryContext) =>\n      context.args.condition\n        ? storyFn()\n        : (context.originalStoryFn as ArgsStoryFn)(context.args, context),\n  ],\n  args: {\n    text: 'text',\n    condition: true,\n  },\n  play: async ({ id, args }: PlayFunctionContext<any>) => {\n    const channel = globalThis.__STORYBOOK_ADDONS_CHANNEL__;\n    await channel.emit(RESET_STORY_ARGS, { storyId: id });\n    await new Promise((resolve) => channel.once(STORY_ARGS_UPDATED, resolve));\n\n    await channel.emit(UPDATE_STORY_ARGS, {\n      storyId: id,\n      updatedArgs: { condition: false },\n    });\n    await new Promise((resolve) => channel.once(STORY_ARGS_UPDATED, resolve));\n  },\n  // this story can't be reliably tested because the args changes results in renderPhases disrupting test runs\n  tags: ['!vitest', '!test'],\n};\n"
  },
  {
    "path": "code/core/template/stories/destructuring-not-transpiled.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { expect } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  args: { label: 'Button' },\n};\n\n// We must not transpile destructuring, to make sure that we can analyze the context properties that are used in play.\n// See: https://github.com/storybookjs/storybook/discussions/27389\nexport const DestructureNotTranspiled = {\n  parameters: { chromatic: { disableSnapshot: true } },\n  async play() {\n    async function fn({ destructured }: { destructured: unknown }) {\n      console.log(destructured);\n    }\n    const match = fn.toString().match(/[^(]*\\(([^)]*)/);\n    const params = match?.[0];\n    await expect(params).toContain('destructured');\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/expect.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react';\n\nimport { expect } from 'storybook/test';\n\nconst meta = {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n} satisfies Meta;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ExpectInstrumentation: Story = {\n  args: {\n    label: 'Test Button',\n  },\n  play: async () => {\n    // Make sure our instrumentation doesn't stand in the way of common expect use cases.\n    class CustomError extends Error {}\n\n    await expect(() => {\n      throw new CustomError();\n    }).toThrow(CustomError);\n\n    // https://github.com/storybookjs/storybook/issues/29816\n    await expect('hi').toEqual(expect.any(String));\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/exportOrder.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  args: { text: 'Check that Story2 is listed before Story1' },\n};\n\nexport const Story1 = {};\nexport const Story2 = {};\n\nexport const __namedExportsOrder = ['Story2', 'Story1'];\n"
  },
  {
    "path": "code/core/template/stories/global.d.ts",
    "content": "export {};\n\ndeclare global {\n  var __TEMPLATE_COMPONENTS__: any;\n  var __STORYBOOK_ADDONS_CHANNEL__: {\n    emit: any;\n    on: any;\n  };\n  var storybookRenderer: string;\n}\n"
  },
  {
    "path": "code/core/template/stories/globals.stories.ts",
    "content": "import type { PartialStoryFn, PlayFunctionContext, StoryContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nimport { expect, within } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  tags: ['autodocs'],\n  globals: {\n    baz: 'bazComponentValue',\n  },\n};\n\nexport const Inheritance = {\n  // Compose all the globals into `object`, so the pre component only needs a single prop\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) =>\n      storyFn({ args: { object: context.globals } }),\n  ],\n  play: async ({ canvasElement }: PlayFunctionContext<any>) => {\n    await expect(JSON.parse(within(canvasElement).getByTestId('pre').innerText)).toMatchObject({\n      foo: 'fooValue',\n      bar: 'barValue',\n      baz: 'bazComponentValue',\n    });\n  },\n};\n\nexport const Events = {\n  parameters: { chromatic: { disableSnapshot: true } },\n  // Just pass the \"foo\" global to the pre\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) =>\n      storyFn({ args: { text: context.globals.foo } }),\n  ],\n  play: async ({ canvasElement }: PlayFunctionContext<any>) => {\n    const channel = globalThis.__STORYBOOK_ADDONS_CHANNEL__;\n    await channel.emit('updateGlobals', { globals: { foo: 'fooValue' } });\n    await within(canvasElement).findByText('fooValue');\n\n    await channel.emit('updateGlobals', { globals: { foo: 'updated' } });\n    await within(canvasElement).findByText('updated');\n\n    // Reset it back to the original value just to avoid polluting the URL\n    await channel.emit('updateGlobals', { globals: { foo: 'fooValue' } });\n    await within(canvasElement).findByText('fooValue');\n  },\n  // this story can't be reliably tested because the globals changes results in renderPhases disrupting test runs\n  tags: ['!vitest', '!test'],\n};\n\nexport const Overrides1 = {\n  // Compose all the globals into `object`, so the pre component only needs a single prop\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) =>\n      storyFn({ args: { object: context.globals } }),\n  ],\n  globals: {\n    foo: 'fooOverridden1',\n    baz: 'bazOverridden1',\n  },\n  play: async ({ canvasElement }: PlayFunctionContext<any>) => {\n    await expect(JSON.parse(within(canvasElement).getByTestId('pre').innerText)).toMatchObject({\n      foo: 'fooOverridden1',\n      bar: 'barValue',\n      baz: 'bazOverridden1',\n    });\n  },\n};\n\nexport const Overrides2 = {\n  // Compose all the globals into `object`, so the pre component only needs a single prop\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) =>\n      storyFn({ args: { object: context.globals } }),\n  ],\n  globals: {\n    foo: 'fooOverridden2',\n    baz: 'bazOverridden2',\n  },\n  play: async ({ canvasElement }: PlayFunctionContext<any>) => {\n    await expect(JSON.parse(within(canvasElement).getByTestId('pre').innerText)).toMatchObject({\n      foo: 'fooOverridden2',\n      bar: 'barValue',\n      baz: 'bazOverridden2',\n    });\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/hooks.stories.ts",
    "content": "import type { PartialStoryFn, StoryContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nimport { useEffect, useState } from 'storybook/preview-api';\nimport { userEvent, within } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  tags: ['!vitest'],\n};\n\nexport const UseState = {\n  decorators: [\n    (story: PartialStoryFn) => {\n      const [count, setCount] = useState(0);\n      return story({\n        args: {\n          label: `Clicked ${count} times`,\n          onClick: () => {\n            setCount(count + 1);\n          },\n        },\n      });\n    },\n  ],\n  play: async ({ canvasElement }: StoryContext<any>) => {\n    const button = await within(canvasElement).findByText('Clicked 0 times');\n\n    await userEvent.click(button);\n    await within(canvasElement).findByText('Clicked 1 times');\n  },\n  // TODO VITEST INTEGRATION: remove this once we support Storybook hooks in portable stories\n  tags: ['!vitest'],\n};\n\n// NOTE: it isn't possible to write a play function for this story, as the\n// useEffect hook doesn't fire until *after* the story has rendered, which includes\n// the play function running.\nexport const UseEffect = {\n  decorators: [\n    (story: PartialStoryFn) => {\n      const [count, setCount] = useState(0);\n\n      useEffect(() => {\n        setCount(1);\n      }, []);\n\n      return story({\n        args: {\n          label: count > 0 ? `useEffect worked!` : `useEffect hasn't worked yet!`,\n          onClick: () => {},\n        },\n      });\n    },\n  ],\n};\n"
  },
  {
    "path": "code/core/template/stories/import.js",
    "content": "export const foo = 'bar';\n"
  },
  {
    "path": "code/core/template/stories/indexer.stories.ts",
    "content": "import type { PlayFunctionContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nimport { expect } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  args: { text: 'Check that id assertions in interaction tests are passing' },\n  id: 'indexer-custom-meta-id',\n};\n\nexport const Default = {\n  play: async ({ id }: PlayFunctionContext<any>) => {\n    await expect(id).toBe('indexer-custom-meta-id--default');\n  },\n};\n\nexport const CustomParametersId = {\n  parameters: {\n    __id: 'custom-id',\n  },\n  play: async ({ id }: PlayFunctionContext<any>) => {\n    await expect(id).toBe('custom-id');\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/interleavedExports.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport './import';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  args: { text: 'Check that stories are processed OK' },\n};\n\nexport const Story1 = {};\n\nexport const Story2 = {};\n"
  },
  {
    "path": "code/core/template/stories/layout.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nconst style = {\n  display: 'block',\n  border: '2px solid #FF4785',\n  padding: 10,\n};\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  args: {\n    style,\n  },\n  parameters: {\n    layout: 'centered',\n  },\n};\n\nexport const PaddedBlock = {\n  args: { text: 'padded' },\n  parameters: { layout: 'padded' },\n};\n\nexport const PaddedInline = {\n  args: { text: 'padded', style: { ...style, display: 'inline-block' } },\n  parameters: { layout: 'padded' },\n};\n\nexport const FullscreenBlock = {\n  args: { text: 'fullscreen' },\n  parameters: { layout: 'fullscreen' },\n};\n\nexport const FullscreenInline = {\n  args: { text: 'fullscreen', style: { ...style, display: 'inline-block' } },\n  parameters: { layout: 'fullscreen' },\n};\n\nexport const CenteredBlock = {\n  args: { text: 'centered' },\n  parameters: { layout: 'centered' },\n};\n\nexport const CenteredInline = {\n  args: { text: 'centered', style: { ...style, display: 'inline-block' } },\n  parameters: { layout: 'centered' },\n};\n\nexport const CenteredTall = {\n  args: { text: 'centered tall', style: { ...style, height: '120vh' } },\n  parameters: { layout: 'centered' },\n};\n\nexport const CenteredWide = {\n  args: { text: 'centered wide', style: { ...style, width: '120vw' } },\n  parameters: { layout: 'centered' },\n};\n\nexport const None = {\n  args: { text: 'none' },\n  parameters: { layout: 'none' },\n};\n\nexport const Inherited = {\n  args: { text: 'inherited' },\n};\n\nexport const Invalid = {\n  args: { text: 'invalid' },\n  parameters: { layout: 'invalid' },\n};\n"
  },
  {
    "path": "code/core/template/stories/loader-enhancements.stories.ts",
    "content": "/* eslint-disable storybook/prefer-pascal-case */\nimport { expect, within } from 'storybook/test';\n\nconst meta = {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  parameters: { chromatic: { disableSnapshot: true } },\n  args: { label: 'Button' },\n};\n\nexport default meta;\n\nexport const canvas_is_equal_to_within_canvas_element = {\n  async play({ canvas, canvasElement }) {\n    const oldCanvas = within(canvasElement);\n    await expect(Object.keys(canvas)).toEqual(Object.keys(oldCanvas));\n  },\n};\n\n// TODO enable this in a later PR, once we have time to QA this properly\n// export const context_user_event_is_equal_to_user_event_setup = {\n//   async play({ userEvent }) {\n//     await expect(userEvent satisfies typeof globalUserEvent).toEqual(globalUserEvent.setup());\n//   },\n// };\n"
  },
  {
    "path": "code/core/template/stories/loaders.stories.ts",
    "content": "import type { PartialStoryFn, StoryContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nimport { expect, within } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  loaders: [async () => new Promise((r) => setTimeout(() => r({ componentValue: 7 }), 1000))],\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) =>\n      storyFn({ args: { ...context.args, object: context.loaded } }),\n  ],\n};\n\nexport const Inheritance = {\n  loaders: [async () => new Promise((r) => setTimeout(() => r({ storyValue: 3 }), 500))],\n  play: async ({ canvasElement }: StoryContext<any>) => {\n    const canvas = within(canvasElement);\n    await expect(JSON.parse(canvas.getByTestId('pre').innerText)).toEqual({\n      projectValue: 2,\n      componentValue: 7,\n      storyValue: 3,\n    });\n  },\n};\n\nexport const ZIndex = {\n  args: {\n    style: {\n      position: 'relative',\n      zIndex: 1000,\n      width: '500px',\n      height: '500px',\n      background: 'coral',\n    },\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/moduleMocking.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore This alias is set in the sandbox. Using ts-ignore instead of ts-expect-error to avoid build errors in the sandbox.\nimport { foo } from '#utils';\nimport { expect, fn, isMockFunction, mocked } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  args: {\n    onClick: fn(),\n    label: 'Mock story',\n  },\n  parameters: {\n    chromatic: {\n      disableSnapshot: true,\n    },\n  },\n  beforeEach: () => {\n    mocked(foo).mockReturnValue('mocked');\n  },\n  async play() {\n    await expect(isMockFunction(foo)).toBe(true);\n    await expect(foo()).toBe('mocked');\n  },\n};\n\nexport const Basic = {};\n"
  },
  {
    "path": "code/core/template/stories/mount-in-play.stories.ts",
    "content": "import { expect, fn } from 'storybook/test';\n\nconst meta = { component: globalThis.__TEMPLATE_COMPONENTS__.Button };\n\nexport default meta;\n\nexport const MountShouldBeDestructured = {\n  parameters: { chromatic: { disableSnapshot: true } },\n  args: {\n    label: 'Button',\n    onClick: fn(),\n  },\n  async play(context) {\n    let error;\n\n    // TODO use expect.toThrow once this issue is fixed\n    // https://github.com/storybookjs/storybook/issues/28406\n    try {\n      await context.mount();\n    } catch (e) {\n      error = e;\n    }\n    await expect(error?.name).toContain('MountMustBeDestructuredError');\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/names.stories.ts",
    "content": "import type { PlayFunctionContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nimport { expect } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  args: { text: 'No content' },\n};\n\n// Very simple stories to show what happens when one story's id is a prefix of another's\n// Repro for https://github.com/storybookjs/storybook/issues/11571\n\nexport const PrefixAndName = {\n  play: async ({ name }: PlayFunctionContext<any>) => {\n    await expect(name).toBe('Prefix And Name');\n  },\n};\n\nexport const Prefix = {\n  play: async ({ name }: PlayFunctionContext<any>) => {\n    await expect(name).toBe('Prefix');\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/order-of-hooks.stories.ts",
    "content": "import { expect, getByRole, mocked, spyOn, userEvent } from 'storybook/test';\n\nconst meta = {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  loaders() {\n    spyOn(console, 'log').mockName('console.log');\n    console.log('1 - [from loaders]');\n  },\n  beforeEach() {\n    console.log('2 - [from meta beforeEach]');\n  },\n  async afterEach() {\n    console.log('9 - [from meta afterEach]');\n\n    await expect(mocked(console.log).mock.calls).toEqual([\n      ['1 - [from loaders]'],\n      ['2 - [from meta beforeEach]'],\n      ['3 - [from story beforeEach]'],\n      ['4 - [before mount]'],\n      ['5 - [from decorator]'],\n      ['6 - [after mount]'],\n      ['7 - [from onClick]'],\n      ['8 - [from story afterEach]'],\n      ['9 - [from meta afterEach]'],\n    ]);\n  },\n};\n\nexport default meta;\n\nexport const OrderOfHooks = {\n  beforeEach() {\n    console.log('3 - [from story beforeEach]');\n  },\n  decorators: (storyFn) => {\n    console.log('5 - [from decorator]');\n    return storyFn();\n  },\n  args: {\n    label: 'Button',\n    onClick: () => {\n      console.log('7 - [from onClick]');\n    },\n  },\n  async play({ mount, canvasElement }) {\n    console.log('4 - [before mount]');\n    await mount();\n    console.log('6 - [after mount]');\n    await userEvent.click(getByRole(canvasElement, 'button'));\n  },\n  async afterEach() {\n    console.log('8 - [from story afterEach]');\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/parameters-actions.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { withActions } from 'storybook/actions/decorator';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  args: {\n    label: 'Click Me!',\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const Basic = {\n  parameters: {\n    actions: {\n      handles: [{ click: 'clicked', contextmenu: 'right clicked' }],\n    },\n  },\n  decorators: [withActions],\n};\n"
  },
  {
    "path": "code/core/template/stories/parameters.stories.ts",
    "content": "import type { PartialStoryFn, PlayFunctionContext, StoryContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nimport { expect, within } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  parameters: {\n    componentParameter: 'componentParameter',\n    storyParameter: 'componentStoryParameter', // Checking this gets overridden\n    storyObject: {\n      a: 'component',\n      b: 'component',\n    },\n  },\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) => {\n      const { projectParameter, componentParameter, storyParameter, storyObject } =\n        context.parameters;\n      return storyFn({\n        args: { object: { projectParameter, componentParameter, storyParameter, storyObject } },\n      });\n    },\n  ],\n};\n\nexport const Inheritance = {\n  parameters: {\n    storyParameter: 'storyParameter',\n    storyObject: {\n      a: 'story',\n    },\n  },\n  play: async ({ canvasElement }: PlayFunctionContext<any>) => {\n    const canvas = within(canvasElement);\n    await expect(JSON.parse(canvas.getByTestId('pre').innerText)).toEqual({\n      projectParameter: 'projectParameter',\n      componentParameter: 'componentParameter',\n      storyParameter: 'storyParameter',\n      storyObject: {\n        a: 'story',\n        b: 'component',\n        c: 'project',\n      },\n    });\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/preview.ts",
    "content": "import type { GlobalTypes, PartialStoryFn, StoryContext } from 'storybook/internal/types';\n\ndeclare global {\n  interface Window {\n    __STORYBOOK_BEFORE_ALL_CALLS__: number;\n    __STORYBOOK_BEFORE_ALL_CLEANUP_CALLS__: number;\n  }\n}\n\ntry {\n  // This is used to test the hooks in our E2E tests (look for storybook-hooks.spec.ts)\n\n  /**\n   * Wrapped in a try-catch, because accessing properties on globalThis.parent may throw if the\n   * parent is cross-origin.\n   */\n  globalThis.parent.__STORYBOOK_BEFORE_ALL_CALLS__ = 0;\n  globalThis.parent.__STORYBOOK_BEFORE_ALL_CLEANUP_CALLS__ = 0;\n} catch {\n  // ignore\n}\n\nexport const beforeAll = async () => {\n  let cleanup: () => void = () => {};\n  try {\n    globalThis.parent.__STORYBOOK_BEFORE_ALL_CALLS__ += 1;\n    cleanup = () => {\n      globalThis.parent.__STORYBOOK_BEFORE_ALL_CLEANUP_CALLS__ += 1;\n    };\n  } catch {\n    // ignore\n  }\n  return cleanup;\n};\n\nexport const parameters = {\n  projectParameter: 'projectParameter',\n  storyObject: {\n    a: 'project',\n    b: 'project',\n    c: 'project',\n  },\n};\n\nexport const loaders = [async () => ({ projectValue: 2 })];\n\nconst testProjectDecorator = (storyFn: PartialStoryFn, context: StoryContext) => {\n  if (context.parameters.useProjectDecorator) {\n    return storyFn({ args: { ...context.args, text: `project ${context.args.text}` } });\n  }\n  return storyFn();\n};\n\nexport const decorators = [testProjectDecorator];\n\nexport const initialGlobals = {\n  foo: 'fooValue',\n  bar: 'barValue',\n  baz: 'bazValue',\n\n  sb_theme: 'light',\n  locale: 'en',\n};\n\nexport const globalTypes = {\n  sb_theme: {\n    name: 'Theme',\n    description: 'Global theme for components',\n    toolbar: {\n      icon: 'circlehollow',\n      title: 'Theme',\n      items: [\n        { value: 'light', icon: 'sun', title: 'light' },\n        { value: 'dark', icon: 'moon', title: 'dark' },\n        { value: 'side-by-side', icon: 'sidebyside', title: 'side by side' },\n        { value: 'stacked', icon: 'stacked', title: 'stacked' },\n      ],\n    },\n  },\n  locale: {\n    name: 'Locale',\n    description: 'Internationalization locale',\n    toolbar: {\n      icon: 'globe',\n      shortcuts: {\n        next: {\n          label: 'Go to next language',\n          keys: ['L'],\n        },\n        previous: {\n          label: 'Go to previous language',\n          keys: ['K'],\n        },\n        reset: {\n          label: 'Reset language',\n          keys: ['meta', 'shift', 'L'],\n        },\n      },\n      items: [\n        { title: 'Reset locale', type: 'reset' },\n        { value: 'en', right: '🇺🇸', title: 'English' },\n        { value: 'es', right: '🇪🇸', title: 'Español' },\n        { value: 'zh', right: '🇨🇳', title: '中文' },\n        { value: 'kr', right: '🇰🇷', title: '한국어' },\n      ],\n    },\n  },\n} satisfies GlobalTypes;\n"
  },
  {
    "path": "code/core/template/stories/rendering.stories.ts",
    "content": "import {\n  FORCE_REMOUNT,\n  RESET_STORY_ARGS,\n  STORY_ARGS_UPDATED,\n  UPDATE_STORY_ARGS,\n} from 'storybook/internal/core-events';\nimport type { PlayFunctionContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nimport { expect, waitFor, within } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  args: {\n    label: 'Click me',\n  },\n  tags: ['!vitest'],\n};\n\nexport const ForceRemount = {\n  /**\n   * This play function runs in an infinite loop, because the final FORCE_REMOUNT event retriggers\n   * the function Because of this, it is disabled in both Chromatic and the test runner. To test it\n   * manually, inspect that the button alternates being focused and blurred every 3 seconds. If the\n   * button ALWAYS has focus it means the renderer didn't correctly remount the tree at the\n   * FORCE_REMOUNT event\n   */\n  parameters: { chromatic: { disableSnapshot: true } },\n  play: async ({ canvasElement, id }: PlayFunctionContext<any>) => {\n    const channel = globalThis.__STORYBOOK_ADDONS_CHANNEL__;\n    const button = await within(canvasElement).findByRole('button');\n\n    await waitFor(() => expect(button).not.toHaveFocus());\n    await new Promise((resolve) => setTimeout(resolve, 3000));\n\n    await button.focus();\n    await expect(button).toHaveFocus();\n    await new Promise((resolve) => setTimeout(resolve, 3000));\n    // By forcing the component to remount, we reset the focus state\n    await channel.emit(FORCE_REMOUNT, { storyId: id });\n  },\n  tags: ['!test', '!vitest'],\n};\n\nlet loadedLabel = 'Initial';\n\n/**\n * This story demonstrates what happens when rendering (loaders) have side effects, and can possibly\n * interleave with each other Triggering multiple force remounts quickly should only result in a\n * single remount in the end and the label should be 'Loaded. Click Me' at the end. If loaders are\n * interleaving it would result in a label of 'Error: Interleaved loaders. Click Me' Similarly,\n * changing args rapidly should only cause one rerender at a time, producing the same result.\n */\nexport const SlowLoader = {\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n  loaders: [\n    async () => {\n      loadedLabel = 'Loading...';\n      await new Promise((resolve) => setTimeout(resolve, 1000));\n      loadedLabel = loadedLabel === 'Loading...' ? 'Loaded.' : 'Error: Interleaved loaders.';\n      return { label: loadedLabel };\n    },\n  ],\n  decorators: [\n    (storyFn: any, context: any) =>\n      storyFn({\n        args: {\n          ...context.args,\n          label: `${context.loaded.label} ${context.args.label}`,\n        },\n      }),\n  ],\n};\n\nexport const ChangeArgs = {\n  play: async ({ canvasElement, id }: PlayFunctionContext<any>) => {\n    const channel = globalThis.__STORYBOOK_ADDONS_CHANNEL__;\n\n    await channel.emit(RESET_STORY_ARGS, { storyId: id });\n    await new Promise((resolve) => {\n      channel.once(STORY_ARGS_UPDATED, resolve);\n    });\n\n    const button = await within(canvasElement).findByRole('button');\n    await button.focus();\n    await expect(button).toHaveFocus();\n\n    // Web-components: https://github.com/storybookjs/storybook/issues/19415\n    // Preact: https://github.com/storybookjs/storybook/issues/19504\n\n    // Web-components: https://github.com/storybookjs/storybook/issues/19415\n    // Preact: https://github.com/storybookjs/storybook/issues/19504\n\n    if (['web-components', 'html', 'preact'].includes(globalThis.storybookRenderer)) {\n      return;\n    }\n\n    // When we change the args to the button, it should not remount\n\n    // When we change the args to the button, it should not remount\n    await channel.emit(UPDATE_STORY_ARGS, { storyId: id, updatedArgs: { label: 'New Text' } });\n\n    await within(canvasElement).findByText(/New Text/);\n    await expect(button).toHaveFocus();\n  },\n  // this story can't be reliably tested because the args changes results in renderPhases disrupting test runs\n  tags: ['!vitest', '!test'],\n};\n"
  },
  {
    "path": "code/core/template/stories/shortcuts.stories.ts",
    "content": "import { PREVIEW_KEYDOWN } from 'storybook/internal/core-events';\nimport type { PlayFunctionContext } from 'storybook/internal/csf';\n\nimport { global as globalThis } from '@storybook/global';\n\nimport { expect, fn, userEvent, within } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Form,\n  tags: ['autodocs'],\n  args: {\n    onSubmit: fn(),\n    onSuccess: fn(),\n  },\n};\n\nexport const KeydownDuringPlay = {\n  play: async ({ canvasElement }: PlayFunctionContext<any>) => {\n    const channel = globalThis.__STORYBOOK_ADDONS_CHANNEL__;\n\n    const previewKeydown = fn();\n    channel.on(PREVIEW_KEYDOWN, previewKeydown);\n    const button = await within(canvasElement).findByText('Submit');\n    await userEvent.type(button, 's');\n\n    await expect(previewKeydown).not.toBeCalled();\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/spies.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { spyOn } from 'storybook/test';\n\nconst meta = {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  beforeEach() {\n    spyOn(console, 'log').mockName('console.log');\n    console.log('first');\n  },\n};\n\nexport default meta;\n\nexport const ShowSpyOnInActions = {\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n  beforeEach() {\n    console.log('second');\n  },\n  args: {\n    label: 'Button',\n    onClick: () => {\n      console.log('third');\n    },\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/tags-add.stories.ts",
    "content": "import type { PartialStoryFn, PlayFunctionContext, StoryContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nimport { expect, within } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  tags: ['!dev', '!autodocs', '!test'],\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) => {\n      return storyFn({\n        args: { object: { tags: context.tags } },\n      });\n    },\n  ],\n  parameters: { chromatic: { disableSnapshot: true } },\n};\n\nexport const Inheritance = {\n  tags: ['story-one', '!vitest'],\n  play: async ({ canvasElement }: PlayFunctionContext<any>) => {\n    const canvas = within(canvasElement);\n    await expect(JSON.parse(canvas.getByTestId('pre').innerText)).toEqual({\n      tags: ['story-one'],\n    });\n  },\n  parameters: { chromatic: { disableSnapshot: false } },\n};\n\nexport const Dev = {\n  tags: ['dev'],\n};\n\nexport const Autodocs = {\n  tags: ['autodocs'],\n};\n\nexport const Test = {\n  tags: ['test'],\n};\n"
  },
  {
    "path": "code/core/template/stories/tags-config.stories.ts",
    "content": "import type { PartialStoryFn, PlayFunctionContext, StoryContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nimport { expect, within } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  tags: ['component-one', 'component-two', 'autodocs'],\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) => {\n      return storyFn({\n        args: { object: { tags: context.tags } },\n      });\n    },\n  ],\n  parameters: { chromatic: { disableSnapshot: true } },\n};\n\nexport const Inheritance = {\n  tags: ['story-one', '!vitest'],\n  play: async ({ canvasElement }: PlayFunctionContext<any>) => {\n    const canvas = within(canvasElement);\n    await expect(JSON.parse(canvas.getByTestId('pre').innerText)).toEqual({\n      tags: ['dev', 'test', 'component-one', 'component-two', 'autodocs', 'story-one'],\n    });\n  },\n  parameters: { chromatic: { disableSnapshot: false } },\n};\n\nexport const DocsOnly = {\n  tags: ['docs-only'],\n};\n\nexport const TestOnly = {\n  tags: ['test-only'],\n};\n\nexport const DevOnly = {\n  tags: ['dev-only'],\n};\n\nexport const TagRemoval = {\n  tags: ['!component-two'],\n};\n"
  },
  {
    "path": "code/core/template/stories/tags-remove.stories.ts",
    "content": "import type { PartialStoryFn, PlayFunctionContext, StoryContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nimport { expect, within } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  tags: ['component-one', 'autodocs'],\n  decorators: [\n    (storyFn: PartialStoryFn, context: StoryContext) => {\n      return storyFn({\n        args: { object: { tags: context.tags } },\n      });\n    },\n  ],\n  parameters: { chromatic: { disableSnapshot: true } },\n};\n\nexport const Inheritance = {\n  tags: ['story-one', '!vitest'],\n  play: async ({ canvasElement }: PlayFunctionContext<any>) => {\n    const canvas = within(canvasElement);\n    await expect(JSON.parse(canvas.getByTestId('pre').innerText)).toEqual({\n      tags: ['dev', 'test', 'component-one', 'autodocs', 'story-one'],\n    });\n  },\n  parameters: { chromatic: { disableSnapshot: false } },\n};\n\nexport const NoDev = {\n  tags: ['!dev'],\n};\n\nexport const NoAutodocs = {\n  tags: ['!autodocs'],\n};\n\nexport const NoTest = {\n  tags: ['!test'],\n};\n"
  },
  {
    "path": "code/core/template/stories/test/CjsNodeModuleMocking.stories.js",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { expect } from 'storybook/test';\nimport { v4 } from 'uuid';\n\n// This story is used to test the node module mocking for modules which have an exports field in their package.json.\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  decorators: [\n    (storyFn) =>\n      storyFn({\n        args: {\n          text: `UUID Version: ${v4()}`,\n        },\n      }),\n  ],\n  parameters: {\n    layout: 'fullscreen',\n  },\n  play: async ({ canvasElement }) => {\n    await expect(canvasElement.innerHTML).toContain('UUID Version: MOCK-V4');\n  },\n};\n\nexport const Original = {};\n"
  },
  {
    "path": "code/core/template/stories/test/ClearModuleMocksMocking.api.ts",
    "content": "export type Data = {\n  userId: number;\n  id: number;\n  title: string;\n  body: string;\n};\n\nexport const fetchData = async (): Promise<Data[]> => {\n  return Promise.resolve([\n    {\n      userId: 1,\n      id: 1,\n      title: 'mocked title',\n      body: 'mocked body',\n    },\n  ]);\n};\n"
  },
  {
    "path": "code/core/template/stories/test/ClearModuleMocksMocking.stories.ts",
    "content": "// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { global as globalThis } from '@storybook/global';\n\nimport { clearAllMocks, expect, waitFor } from 'storybook/test';\n\nimport { fetchData } from './ClearModuleMocksMocking.api';\n\n/**\n * The purpose of this story is to verify that the `clearAllMocks` function properly clears mocks\n * created with the `spy: true` option in `sb.mock()`. This is necessary because those mocks are\n * created with a different instance of `@vitest/spy` than the one bundled with storybook/test. This\n * means they won't be cleared by the `clearMocks` option of Vitest, and we need to use\n * `clearAllMocks` to clear them manually. See issue:\n * https://github.com/storybookjs/storybook/issues/34075\n */\nconst meta = {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  args: {\n    label: 'Fetch Data',\n    onClick: () => {\n      fetchData();\n    },\n  },\n  beforeEach: async () => {\n    clearAllMocks();\n  },\n};\n\nexport default meta;\n\nexport const First = {\n  args: {},\n  play: async ({ canvas }: any) => {\n    const button = await canvas.getByRole('button');\n    await button.click();\n    await waitFor(() => {\n      expect(fetchData).toHaveBeenCalledTimes(1);\n    });\n  },\n};\n\nexport const Second = {\n  args: {},\n  play: async ({ canvas }: any) => {\n    const button = await canvas.getByRole('button');\n    await button.click();\n    await waitFor(() => {\n      expect(fetchData).toHaveBeenCalledTimes(1);\n    });\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/test/ModuleAutoMocking.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { expect } from 'storybook/test';\n\nimport { fn } from './ModuleAutoMocking.utils';\n\n// This story demonstrates module mocking. The imported util function is automocked,\n// because a __mocks__/ModuleAutoMocking.utils.ts file exists.\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  decorators: [\n    (storyFn: any) => storyFn({ args: { text: `Function: ${fn().join(', ') || 'no value'}` } }),\n  ],\n  parameters: {\n    layout: 'fullscreen',\n  },\n};\n\nexport const Original = {\n  play: async ({ canvasElement }: any) => {\n    await expect(canvasElement.innerHTML).toContain('Function: automocked value');\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/test/ModuleAutoMocking.utils.ts",
    "content": "export function fn() {\n  return ['original value'];\n}\n"
  },
  {
    "path": "code/core/template/stories/test/ModuleMocking.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { expect, mocked } from 'storybook/test';\n\nimport { fn } from './ModuleMocking.utils';\n\n// This story demonstrates auto module mocking. The imported util function is mocked in the\n// .storybook/preview.js file via sb.mock(module) but a\n// mock is not provided via __mocks__/ModuleMocking.utils.ts, meaning that the implementation of\n// the mock has to happen at runtime.\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  parameters: {\n    layout: 'fullscreen',\n  },\n};\n\nexport const Original = {\n  decorators: [\n    (storyFn: any) =>\n      storyFn({ args: { text: `Function: ${(fn() ?? []).join(', ') || 'no value'}` } }),\n  ],\n  play: async ({ canvasElement }: any) => {\n    await expect(mocked(fn)).toHaveBeenCalledWith();\n    await expect(canvasElement.innerHTML).toContain('Function: no value');\n  },\n};\n\nexport const Mocked = {\n  decorators: [\n    (storyFn: any) => storyFn({ args: { text: `Function: ${fn().join(', ') || 'no value'}` } }),\n  ],\n  beforeEach() {\n    mocked(fn).mockReturnValue(['mocked value']);\n  },\n  play: async ({ canvasElement }: any) => {\n    await expect(canvasElement.innerHTML).toContain('Function: mocked value');\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/test/ModuleMocking.utils.ts",
    "content": "export function fn() {\n  return ['original value'];\n}\n"
  },
  {
    "path": "code/core/template/stories/test/ModuleSpyMocking.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { expect, mocked } from 'storybook/test';\n\nimport { fn } from './ModuleSpyMocking.utils';\n\n// This story demonstrates module mocking with spies. The imported util function is autospied,\n// meaning that it is mocked automatically by Storybook, because the\n// .storybook/preview.js file contains a sb.mock(module, {spy: true}) call for it.\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  decorators: [\n    (storyFn: any) => storyFn({ args: { text: `Function: ${fn().join(', ') || 'no value'}` } }),\n  ],\n  parameters: {\n    layout: 'fullscreen',\n  },\n};\n\nexport const Original = {\n  play: async ({ canvasElement }: any) => {\n    expect(mocked(fn)).toHaveBeenCalledWith();\n    await expect(canvasElement.innerHTML).toContain('Function: original value');\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/test/ModuleSpyMocking.utils.ts",
    "content": "export function fn() {\n  return ['original value'];\n}\n"
  },
  {
    "path": "code/core/template/stories/test/NodeModuleMocking.stories.js",
    "content": "import { global as globalThis } from '@storybook/global';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport lodash from 'lodash-es';\n// eslint-disable-next-line depend/ban-dependencies\nimport add from 'lodash-es/add';\n// eslint-disable-next-line depend/ban-dependencies\nimport sum from 'lodash-es/sum';\nimport { expect, mocked } from 'storybook/test';\n\n// This story is used to test the node module mocking.\n//\n// lodash is mocked, because sb.mock('lodash') is called in the .storybook/preview.js and the\n// __mocks__ directory contains a lodash.js file.\n//\n// lodash/add is mocked, because sb.mock('lodash/add') is called in the .storybook/preview.js and the\n// __mocks__ directory contains a lodash/add.js file.\n//\n// lodash/sum is automocked, because sb.mock('lodash/sum') is called in the .storybook/preview.js and the\n// __mocks__ directory does not contain a lodash/sum.js file. Mocking has to happen at runtime.\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  decorators: [\n    (storyFn) =>\n      storyFn({\n        args: {\n          text: `Lodash Version: ${lodash.VERSION} | Mocked Add (1,2): ${add(1, 2)} | Inline Sum (2,2): ${sum([2, 2])}`,\n        },\n      }),\n  ],\n  parameters: {\n    layout: 'fullscreen',\n  },\n  beforeEach: () => {\n    mocked(sum).mockImplementation(() => {\n      return 'mocked 10';\n    });\n  },\n  play: async ({ canvasElement }) => {\n    await expect(canvasElement.innerHTML).toContain('Lodash Version: 1.0.0-mocked!');\n    await expect(canvasElement.innerHTML).toContain('Mocked Add (1,2): mocked 3');\n    await expect(canvasElement.innerHTML).toContain('Inline Sum (2,2): mocked 10');\n  },\n};\n\nexport const Original = {};\n"
  },
  {
    "path": "code/core/template/stories/test/__mocks__/ModuleAutoMocking.utils.ts",
    "content": "export function fn() {\n  return ['automocked value'];\n}\n"
  },
  {
    "path": "code/core/template/stories/title.stories.ts",
    "content": "import type { PlayFunctionContext } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nimport { expect } from 'storybook/test';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  title: 'manual title',\n  args: { text: 'No content' },\n};\n\nexport const Default = {\n  play: async ({ title }: PlayFunctionContext<any>) => {\n    await expect(title).toBe('core/manual title');\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/toolbars/globals.stories.ts",
    "content": "import type { DecoratorFunction } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\n\nconst greetingForLocale = (locale: string) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour !';\n    case 'zh':\n      return '你好!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'en':\n    default:\n      return 'Hello';\n  }\n};\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  decorators: [\n    (storyFn, { globals }) => {\n      const object = {\n        ...globals,\n        caption: `Locale is '${globals.locale}', so I say: ${greetingForLocale(globals.locale)}`,\n      };\n      return storyFn({ args: { object } });\n    },\n  ] satisfies DecoratorFunction[],\n};\n\nexport const Basic = {};\n\nexport const OverrideLocale = {\n  globals: {\n    locale: 'kr',\n  },\n};\n\nexport const OverrideTheme = {\n  globals: {\n    sb_theme: 'dark',\n  },\n};\n\nexport const OverrideBoth = {\n  globals: {\n    locale: 'kr',\n    sb_theme: 'dark',\n  },\n};\n"
  },
  {
    "path": "code/core/template/stories/unicode.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  id: '😀',\n  tags: ['autodocs'],\n};\n\nexport const Кнопки = {\n  args: { label: 'Кнопки' },\n};\n\nexport const 바보 = {\n  args: { label: '바보' },\n};\n"
  },
  {
    "path": "code/core/template/stories/utils.mock.ts",
    "content": "import { fn } from 'storybook/test';\n\nimport * as utils from './utils.ts';\n\nexport const foo = fn(utils.foo).mockName('foo');\n"
  },
  {
    "path": "code/core/template/stories/utils.ts",
    "content": "export const foo = () => 'not mocked';\n"
  },
  {
    "path": "code/core/template/stories/viewport/globals.stories.ts",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { MINIMAL_VIEWPORTS } from 'storybook/viewport';\n\nconst first = Object.keys(MINIMAL_VIEWPORTS)[0];\n\nexport default {\n  component: globalThis.__TEMPLATE_COMPONENTS__.Pre,\n  args: {\n    text: 'Testing the viewport',\n  },\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const Unset = {\n  globals: {},\n};\n\nexport const Selected = {\n  globals: {\n    viewport: {\n      value: first,\n      isRotated: false,\n    },\n  },\n};\n\nexport const Orientation = {\n  globals: {\n    viewport: {\n      value: first,\n      isRotated: true,\n    },\n  },\n};\n\nexport const Invalid = {\n  globals: {\n    viewport: {\n      value: 'phone',\n      isRotated: false,\n    },\n  },\n};\n\nexport const Shorthand = {\n  globals: {\n    viewport: first,\n  },\n};\n\nexport const NoRatioDefined = {\n  globals: {\n    viewport: {\n      value: first,\n    },\n  },\n};\n\nexport const Disabled = {\n  parameters: {\n    viewport: {\n      disable: true,\n    },\n  },\n};\n"
  },
  {
    "path": "code/core/tsconfig.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"resolveJsonModule\": true,\n    \"moduleResolution\": \"bundler\",\n    \"module\": \"esnext\",\n    \"stripInternal\": true\n  },\n  \"include\": [\"src/**/*\", \"scripts/**/*\", \"*.d.ts\", \"templates/runtime-build-code.template\"]\n}\n"
  },
  {
    "path": "code/core/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    test: {\n      typecheck: {\n        enabled: true,\n        ignoreSourceErrors: true,\n      },\n    },\n  })\n);\n"
  },
  {
    "path": "code/core/vitest.d.ts",
    "content": "import 'vitest';\n\ninterface CustomMatchers<R = unknown> {\n  toMatchPaths(paths: string[]): R;\n}\n\ndeclare module 'vitest' {\n  interface Assertion<T = unknown> extends CustomMatchers<T> {}\n  interface AsymmetricMatchersContaining extends CustomMatchers {}\n}\n"
  },
  {
    "path": "code/e2e-tests/addon-a11y.spec.ts",
    "content": "import { expect, test } from '@playwright/test';\nimport process from 'process';\n\nimport { SbPage } from './util.ts';\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';\n\ntest.describe('addon-a11y', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto(storybookUrl);\n    await new SbPage(page, expect).waitUntilLoaded();\n  });\n\n  test('should highlight the accessibility violations in the preview iframe', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n    await sbPage.deepLinkToStory(storybookUrl, 'addons/a11y/tests', 'violations');\n    await sbPage.viewAddonPanel('Accessibility');\n\n    const panel = sbPage.panelContent();\n    await panel\n      .getByRole('button', { name: 'Highlight elements with accessibility test results' })\n      .click();\n\n    const highlightElement = sbPage\n      .previewIframe()\n      .locator('[data-highlight-dimensions=\"w350h150\"]');\n\n    await expect(highlightElement).toBeVisible();\n    expect(await highlightElement.evaluate((el) => getComputedStyle(el).backgroundColor)).toBe(\n      'color(srgb 1 0.266667 0 / 0.4)'\n    );\n\n    await page.getByRole('button', { name: 'Hide accessibility test result highlights' }).click();\n    await expect(highlightElement).toBeHidden();\n  });\n\n  test('should rerun a11y checks when clicking the rerun button', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n    await sbPage.deepLinkToStory(storybookUrl, 'addons/a11y/tests', 'violations');\n    await sbPage.viewAddonPanel('Accessibility');\n\n    const panel = sbPage.panelContent();\n    await expect(panel.getByRole('tab', { name: 'Violations' })).toContainText('5');\n    await sbPage.previewIframe().getByText('Toggle violation:').click();\n    await panel.getByRole('button', { name: 'Rerun' }).click();\n    await expect(panel.getByRole('tab', { name: 'Violations' })).toContainText('4');\n  });\n\n  test('should provide a deeplink code that can be used to navigate to a specific violation', async ({\n    page,\n  }) => {\n    const sbPage = new SbPage(page, expect);\n    await sbPage.deepLinkToStory(storybookUrl, 'addons/a11y/tests', 'violations');\n    await sbPage.viewAddonPanel('Accessibility');\n\n    const panel = sbPage.panelContent();\n    await panel.getByRole('tab', { name: 'Passes' }).click();\n    await panel.getByRole('button', { name: 'Hidden body' }).click();\n    await panel.getByRole('tab', { name: '1. <body' }).click();\n    await panel.getByRole('button', { name: 'Copy link' }).click();\n\n    // test that clipboard contains the correct url\n    const clipboard = await page.evaluate(() => navigator.clipboard.readText());\n    expect(clipboard).toContain(\n      '?path=/story/addons-a11y-tests--violations&addonPanel=storybook/a11y/panel&a11ySelection=passes.aria-hidden-body.1'\n    );\n\n    // navigate to that url\n    await page.goto(clipboard);\n    await new SbPage(page, expect).waitUntilLoaded();\n    await expect(page.getByRole('tab', { name: 'Passes' })).toHaveAttribute(\n      'aria-selected',\n      'true'\n    );\n    await expect(page.getByRole('button', { name: 'Hidden body' })).toHaveAttribute(\n      'aria-expanded',\n      'true'\n    );\n    const element = page.getByRole('tab', { name: '1. <body' });\n    await expect(element).toHaveAttribute('data-state', 'active');\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/addon-actions.spec.ts",
    "content": "import { expect, test } from '@playwright/test';\nimport process from 'process';\n\nimport { SbPage } from './util.ts';\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';\nconst templateName = process.env.STORYBOOK_TEMPLATE_NAME || '';\n\ntest.describe('addon-actions', () => {\n  test('should trigger an action', async ({ page }) => {\n    test.skip(\n      templateName.includes('svelte') && templateName.includes('prerelease'),\n      'Svelte 5 prerelase does not support automatic actions with our current example components yet'\n    );\n    test.skip(\n      templateName.includes('react-native-web'),\n      'React Native uses onPress rather than onClick'\n    );\n    await page.goto(storybookUrl);\n    const sbPage = new SbPage(page, expect);\n    sbPage.waitUntilLoaded();\n\n    await sbPage.navigateToStory('example/button', 'primary');\n    const root = sbPage.previewRoot();\n    await sbPage.viewAddonPanel('Actions');\n\n    const button = root.getByRole('button');\n    await expect(button).toBeVisible();\n    await button.click();\n\n    const logItem = sbPage.panelContent().locator('span', {\n      hasText: 'onClick:',\n    });\n    await expect(logItem).toBeVisible();\n  });\n\n  test('should show spies', async ({ page }) => {\n    test.skip(\n      templateName.includes('svelte') && templateName.includes('prerelease'),\n      'Svelte 5 prerelase does not support automatic actions with our current example components yet'\n    );\n    await page.goto(storybookUrl);\n    const sbPage = new SbPage(page, expect);\n    sbPage.waitUntilLoaded();\n\n    await sbPage.navigateToStory('core/spies', 'show-spy-on-in-actions');\n\n    const root = sbPage.previewRoot();\n    await sbPage.viewAddonPanel('Actions');\n\n    const button = root.getByRole('button');\n    await expect(button).toBeVisible();\n    await button.click();\n\n    const logItem = sbPage.panelContent().locator('span', {\n      hasText: 'console.log:',\n    });\n    // Avoid getting failed due to other console.log calls by frameworks\n    await expect(logItem.getByText('first')).toBeVisible();\n    await expect(logItem.getByText('second')).toBeVisible();\n    await expect(logItem.getByText('third')).toBeVisible();\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/addon-backgrounds.spec.ts",
    "content": "import { expect, test } from '@playwright/test';\nimport process from 'process';\n\nimport { SbPage } from './util.ts';\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';\nconst templateName = process.env.STORYBOOK_TEMPLATE_NAME || '';\n\ntest.describe('addon-backgrounds', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto(storybookUrl);\n    await new SbPage(page, expect).waitUntilLoaded();\n  });\n\n  const backgroundToolbarSelector = '[aria-label=\"Preview background\"]';\n  const gridToolbarSelector = '[aria-label=\"Grid visibility\"]';\n\n  test('should have a dark background', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n\n    await sbPage.navigateToStory('example/button', 'primary');\n    await sbPage.selectToolbar(backgroundToolbarSelector, 'text=/dark/');\n\n    await expect(sbPage.getCanvasBodyElement()).toHaveCSS('background-color', 'rgb(51, 51, 51)');\n  });\n\n  test('should apply a grid', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n\n    await sbPage.navigateToStory('example/button', 'primary');\n    await sbPage.selectToolbar(gridToolbarSelector);\n\n    await expect(sbPage.getCanvasBodyElement()).toHaveCSS('background-image', /linear-gradient/);\n  });\n\n  test('button should appear for story pages', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n\n    await sbPage.navigateToStory('example/button', 'primary');\n    await expect(sbPage.page.locator(backgroundToolbarSelector)).toBeVisible();\n  });\n\n  test.describe('docs pages', () => {\n    test('button should appear for attached docs pages', async ({ page }) => {\n      const sbPage = new SbPage(page, expect);\n\n      await sbPage.navigateToStory('example/button', 'docs');\n      await expect(sbPage.page.locator(backgroundToolbarSelector)).toBeVisible();\n    });\n\n    test('button should appear for unattached .mdx files', async ({ page }) => {\n      const sbPage = new SbPage(page, expect);\n\n      // We start on the introduction page by default.\n      await sbPage.page.waitForURL((url) =>\n        url.search.includes(`path=/docs/configure-your-project--docs`)\n      );\n\n      await expect(sbPage.page.locator(backgroundToolbarSelector)).toBeVisible();\n    });\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/addon-controls.spec.ts",
    "content": "import { expect, test } from '@playwright/test';\nimport process from 'process';\n\nimport { SbPage, isReactSandbox } from './util.ts';\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';\nconst templateName = process.env.STORYBOOK_TEMPLATE_NAME || '';\n\ntest.describe('addon-controls', () => {\n  test('should change component when changing controls', async ({ page }) => {\n    test.skip(templateName.includes('react-native-web'), 'React Native CSS behaves differently');\n\n    await page.goto(storybookUrl);\n    const sbPage = new SbPage(page, expect);\n    await sbPage.waitUntilLoaded();\n\n    await sbPage.navigateToStory('example/button', 'primary');\n    await sbPage.viewAddonPanel('Controls');\n\n    // Text input: Label\n    await expect(sbPage.previewRoot().locator('button')).toContainText('Button');\n    const label = sbPage.panelContent().locator('textarea[name=label]');\n    await label.fill('Hello world');\n    await expect(sbPage.previewRoot().locator('button')).toContainText('Hello world');\n\n    // Args in URL\n    await page.waitForURL((url) => url.search.includes('args=label:Hello+world'));\n\n    // Boolean toggle: Primary/secondary\n    await expect(sbPage.previewRoot().locator('button')).toHaveCSS(\n      'background-color',\n      'rgb(85, 90, 185)'\n    );\n    const toggle = sbPage.panelContent().locator('input[name=primary]');\n    await toggle.click();\n    await expect(async () => {\n      await expect(sbPage.previewRoot().locator('button')).toHaveCSS(\n        'background-color',\n        'rgba(0, 0, 0, 0)'\n      );\n    }).toPass();\n\n    // Color picker: Background color\n    const color = sbPage.panelContent().locator('input[placeholder=\"Choose color...\"]');\n    await color.fill('red');\n    await expect(async () => {\n      await expect(sbPage.previewRoot().locator('button')).toHaveCSS(\n        'background-color',\n        'rgb(255, 0, 0)'\n      );\n    }).toPass();\n\n    // TODO: enable this once the controls for size are aligned in all CLI templates.\n    // Radio buttons: Size\n    // cy.getStoryElement().find('button').should('have.css', 'font-size', '14px');\n    // cy.get('label[for=\"size-large\"]').click();\n    // cy.getStoryElement().find('button').should('have.css', 'font-size', '16px');\n\n    // Reset controls: assert that the component is back to original state\n    const reset = sbPage.panelContent().locator('[aria-label=\"Reset controls\"]');\n    await reset.click();\n    const button = sbPage.previewRoot().locator('button');\n    await expect(button).toHaveCSS('font-size', '14px');\n    await expect(button).toHaveCSS('background-color', 'rgb(85, 90, 185)');\n    await expect(button).toContainText('Button');\n  });\n\n  test('should apply controls automatically when passed via url', async ({ page }) => {\n    await page.goto(`${storybookUrl}?path=/story/example-button--primary&args=label:Hello+world`);\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.waitUntilLoaded();\n    await expect(sbPage.previewRoot().locator('button')).toContainText('Hello world');\n\n    await sbPage.viewAddonPanel('Controls');\n    const label = sbPage.panelContent().locator('textarea[name=label]');\n    await expect(label).toHaveValue('Hello world');\n  });\n\n  test('should set select option when value contains double spaces', async ({ page }) => {\n    await page.goto(`${storybookUrl}?path=/story/core-controls-basics--undefined`);\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.waitUntilLoaded();\n    await sbPage.closeAnyPendingModal();\n\n    await sbPage.viewAddonPanel('Controls');\n    await sbPage.panelContent().locator('#control-select').selectOption('double  space');\n\n    await expect(sbPage.panelContent().locator('#control-select')).toHaveValue('double  space');\n    await expect(page).toHaveURL(/.*select:double\\+\\+space.*/);\n  });\n\n  test('should set multiselect option when value contains double spaces', async ({ page }) => {\n    await page.goto(`${storybookUrl}?path=/story/core-controls-basics--undefined`);\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.waitUntilLoaded();\n    await sbPage.closeAnyPendingModal();\n    await sbPage.viewAddonPanel('Controls');\n    await sbPage.panelContent().locator('#control-multiSelect').selectOption('double  space');\n\n    await expect(sbPage.panelContent().locator('#control-multiSelect')).toHaveValue(\n      'double  space'\n    );\n\n    await expect(page).toHaveURL(/.*multiSelect\\[0]:double\\+\\+space.*/);\n  });\n\n  // We want to avoid the controls panel crashing when JSX elements are part of args table\n  test('should show JSX elements in controls panel', async ({ page }) => {\n    test.skip(!isReactSandbox(templateName), 'This is a React only feature');\n    await page.goto(`${storybookUrl}?path=/story/stories-renderers-react-jsx-docgen--default`);\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.waitUntilLoaded();\n    await sbPage.viewAddonPanel('Controls');\n    await expect(sbPage.panelContent().getByText('children').first()).toBeVisible();\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/addon-docs.spec.ts",
    "content": "/* eslint-disable playwright/no-conditional-expect */\n/* eslint-disable playwright/no-conditional-in-test */\nimport { expect, test } from '@playwright/test';\nimport process from 'process';\nimport { dedent } from 'ts-dedent';\n\nimport { SbPage, isReactSandbox } from './util.ts';\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';\nconst templateName = process.env.STORYBOOK_TEMPLATE_NAME || '';\n\ntest.describe('addon-docs', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto(storybookUrl);\n    await new SbPage(page, expect).waitUntilLoaded();\n  });\n\n  test('should show descriptions for stories', async ({ page }) => {\n    const skipped = [\n      // SSv6 does not render stories in the correct order in our sandboxes\n      'internal\\\\/ssv6',\n    ];\n    test.skip(\n      new RegExp(`^${skipped.join('|')}`, 'i').test(`${templateName}`),\n      `Skipping ${templateName}, because of wrong ordering of stories on docs page`\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory('addons/docs/docspage/basic', 'docs');\n    const root = sbPage.previewRoot();\n\n    const basicStory = root.locator('#anchor--addons-docs-docspage-basic--basic');\n    await expect(basicStory).toContainText('A basic button');\n\n    const anotherStory = root.locator('#anchor--addons-docs-docspage-basic--another');\n    await expect(anotherStory).toContainText('Another button, just to show multiple stories');\n  });\n\n  test('should show source=code view for stories', async ({ page }) => {\n    const skipped = [\n      // SSv6 does not render stories in the correct order in our sandboxes\n      'internal\\\\/ssv6',\n    ];\n    test.skip(\n      new RegExp(`^${skipped.join('|')}`, 'i').test(`${templateName}`),\n      `Skipping ${templateName}, because of wrong ordering of stories on docs page`\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory('addons/docs/docspage/basic', 'docs');\n    const root = sbPage.previewRoot();\n\n    // Click on the third button which has the text \"Show code\"\n    const showCodeButton = (await root.locator('button', { hasText: 'Show Code' }).all())[2];\n    await showCodeButton.click();\n    const sourceCode = root.locator('pre.prismjs');\n    const expectedSource = dedent`{\n      args: {\n        label: 'Another'\n      },\n      parameters: {\n        docs: {\n          source: {\n            type: 'code'\n          }\n        }\n      },\n      play: async () => {\n        await new Promise(resolve => resolve('Play function'));\n      }\n    }`;\n    await expect(sourceCode).toHaveText(expectedSource);\n  });\n\n  test('should render errors', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory('addons/docs/docspage/error', 'docs');\n    const root = sbPage.previewRoot();\n\n    const primaryStory = root.locator('#story--addons-docs-docspage-error--error-story--primary');\n    await expect(primaryStory).toContainText('Story did something wrong');\n  });\n\n  test('should provide source snippet', async ({ page }) => {\n    // templateName is e.g. 'vue-cli/default-js'\n    test.skip(\n      /^(vue3|vue-cli|preact)/i.test(`${templateName}`),\n      `Skipping ${templateName}, which does not support dynamic source snippets`\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory('addons/docs/docspage/basic', 'docs');\n    const root = sbPage.previewRoot();\n    const toggles = root.locator('.docblock-code-toggle');\n\n    const toggleCount = await toggles.count();\n    for (let i = 0; i < toggleCount; i += 1) {\n      const toggle = toggles.nth(i);\n      await toggle.click();\n    }\n\n    const codes = root.locator('pre.prismjs');\n    const codeCount = await codes.count();\n    for (let i = 0; i < codeCount; i += 1) {\n      const code = codes.nth(i);\n      const text = await code.innerText();\n      expect(text).not.toMatch(/^\\(args\\) => /);\n    }\n  });\n\n  test('source snippet should not change in stories block', async ({ page }) => {\n    const skipped = [\n      'vue3',\n      'vue-cli',\n      'preact',\n      // SSv6 does not render stories in the correct order in our sandboxes\n      'internal\\\\/ssv6',\n      // Angular bug: https://github.com/storybookjs/storybook/issues/21066\n      'angular',\n      // Lit seems to render incorrectly for our template-stories but not real stories\n      //   - template: https://638db567ed97c3fb3e21cc22-ulhjwkqzzj.chromatic.com/?path=/docs/addons-docs-docspage-basic--docs\n      //   - real: https://638db567ed97c3fb3e21cc22-ulhjwkqzzj.chromatic.com/?path=/docs/example-button--docs\n      'lit-vite',\n      'react-native-web',\n    ];\n    test.skip(\n      new RegExp(`^${skipped.join('|')}`, 'i').test(`${templateName}`),\n      `Skipping ${templateName}, which does not support dynamic source snippets`\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory('addons/docs/docspage/basic', 'docs');\n    const root = sbPage.previewRoot();\n    const toggles = root.locator('.docblock-code-toggle');\n\n    // Open up the first and second code toggle (i.e the \"Basic\" story outside and inside the Stories block)\n    await toggles.nth(0).click();\n    await toggles.nth(1).click();\n\n    // Check they both say \"Basic\"\n    const codes = root.locator('pre.prismjs');\n    const primaryCode = codes.nth(0);\n    const storiesCode = codes.nth(1);\n    await expect(primaryCode).toContainText('Basic');\n    await expect(storiesCode).toContainText('Basic');\n\n    const labelControl = root.locator('textarea[name=label]');\n    await labelControl.fill('Changed');\n    await labelControl.blur();\n\n    // Check the Primary one has changed\n    await expect(primaryCode).toContainText('Changed');\n    // Check the stories one still says \"Basic\"\n    await expect(storiesCode).toContainText('Basic');\n  });\n\n  test('should not run autoplay stories without parameter', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory('addons/docs/docspage/autoplay', 'docs');\n\n    const root = sbPage.previewRoot();\n    const autoplayPre = root.locator('#story--addons-docs-docspage-autoplay--autoplay pre');\n    await expect(autoplayPre).toHaveText('Play has run');\n\n    const noAutoplayPre = root.locator('#story--addons-docs-docspage-autoplay--no-autoplay pre');\n    await expect(noAutoplayPre).toHaveText('Play has not run');\n  });\n\n  test('should order entries correctly', async ({ page }) => {\n    // TODO: This is broken in SSV6 Webpack. Context: https://github.com/storybookjs/storybook/issues/20941\n    test.skip(\n      templateName.includes('ssv6-webpack'),\n      `${templateName} fails because of a known issue: https://github.com/storybookjs/storybook/issues/20941`\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory('addons/docs/docspage/basic', 'docs');\n\n    // The `<Primary>` block should render the \"Basic\" story, and the `<Stories/>` block should\n    // render both the \"Basic\" and \"Another\" story\n    const root = sbPage.previewRoot();\n    const stories = root.locator('.sb-story button');\n\n    await expect(stories).toHaveCount(3);\n    await expect(stories.first()).toHaveText('Basic');\n    await expect(stories.nth(1)).toHaveText('Basic');\n    await expect(stories.last()).toHaveText('Another');\n  });\n\n  test('should resolve react to the correct version', async ({ page }) => {\n    test.skip(\n      templateName?.includes('nextjs') || templateName?.includes('nuxt'),\n      'TODO: remove this once sandboxes are synced (SOON!!)'\n    );\n    // Arrange - Navigate to MDX docs\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory('addons/docs/docs2/resolvedreact', 'mdx', 'docs');\n    const root = sbPage.previewRoot();\n\n    // Arrange - Setup expectations\n    let expectedReactVersionRange = /^19/;\n    if (templateName.includes('react-webpack/17') || templateName.includes('react-vite/17')) {\n      expectedReactVersionRange = /^17/;\n    } else if (templateName.includes('react16')) {\n      expectedReactVersionRange = /^16/;\n    } else if (\n      templateName.includes('internal/react18-webpack-babel') ||\n      templateName.includes('preact-vite/default-js') ||\n      templateName.includes('preact-vite/default-ts') ||\n      templateName.includes('react-webpack/18-ts')\n    ) {\n      expectedReactVersionRange = /^18/;\n    }\n\n    // Arrange - Get the actual versions\n    const mdxReactVersion = root.getByTestId('mdx-react');\n    const mdxReactDomVersion = root.getByTestId('mdx-react-dom');\n    const mdxReactDomServerVersion = root.getByTestId('mdx-react-dom-server');\n    const componentReactVersion = root.getByTestId('component-react');\n    const componentReactDomVersion = root.getByTestId('component-react-dom');\n    const componentReactDomServerVersion = root.getByTestId('component-react-dom-server');\n\n    // Assert - The versions are in the expected range\n    await expect(mdxReactVersion).toHaveText(expectedReactVersionRange);\n    await expect(componentReactVersion).toHaveText(expectedReactVersionRange);\n    await expect(mdxReactDomVersion).toHaveText(expectedReactVersionRange);\n    await expect(componentReactDomVersion).toHaveText(expectedReactVersionRange);\n    if (!templateName.includes('preact')) {\n      // preact/compat alias doesn't have a version export in react-dom/server\n      await expect(mdxReactDomServerVersion).toHaveText(expectedReactVersionRange);\n      await expect(componentReactDomServerVersion).toHaveText(expectedReactVersionRange);\n    }\n\n    // Arrange - Navigate to autodocs\n    await sbPage.navigateToStory('addons/docs/docs2/resolvedreact', 'docs');\n\n    // Arrange - Get the actual versions\n    const autodocsReactVersion = root.getByTestId('react');\n    const autodocsReactDomVersion = root.getByTestId('react-dom');\n    const autodocsReactDomServerVersion = root.getByTestId('react-dom-server');\n\n    // Assert - The versions are in the expected range\n    await expect(autodocsReactVersion).toHaveText(expectedReactVersionRange);\n    await expect(autodocsReactDomVersion).toHaveText(expectedReactVersionRange);\n    if (!templateName.includes('preact')) {\n      await expect(autodocsReactDomServerVersion).toHaveText(expectedReactVersionRange);\n    }\n\n    // Arrange - Navigate to story\n    await sbPage.navigateToStory('addons/docs/docs2/resolvedreact', 'story');\n\n    // Arrange - Get the actual versions\n    const storyReactVersion = root.getByTestId('react');\n    const storyReactDomVersion = root.getByTestId('react-dom');\n    const storyReactDomServerVersion = root.getByTestId('react-dom-server');\n\n    // Assert - The versions are in the expected range\n    await expect(storyReactVersion).toHaveText(expectedReactVersionRange);\n    await expect(storyReactDomVersion).toHaveText(expectedReactVersionRange);\n    if (!templateName.includes('preact')) {\n      await expect(storyReactDomServerVersion).toHaveText(expectedReactVersionRange);\n    }\n  });\n\n  test('should have stories from multiple CSF files in autodocs', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory('/addons/docs/multiple-csf-files-same-title', 'docs');\n    const root = sbPage.previewRoot();\n\n    const storyHeadings = root.locator('.sb-anchor > h3');\n    await expect(storyHeadings).toHaveCount(6);\n    await expect(storyHeadings).toHaveText([\n      'Default A',\n      'Span Content',\n      'Code Content',\n      'Default B',\n      'H 1 Content',\n      'H 2 Content',\n    ]);\n  });\n\n  // We want to avoid the docs page crashing when JSX elements are part of args table\n  test('should show JSX elements in docs page', async ({ page }) => {\n    test.skip(!isReactSandbox(templateName), 'This is a React only feature');\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory('/stories/renderers/react/jsx-docgen', 'docs');\n    const root = sbPage.previewRoot();\n    await expect(root.getByText('children').first()).toBeVisible();\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/addon-mcp.spec.ts",
    "content": "/* eslint-disable local-rules/no-uncategorized-errors */\nimport path from 'node:path';\n\nimport type { APIRequestContext } from '@playwright/test';\nimport { expect, test } from '@playwright/test';\nimport process from 'process';\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';\nconst templateName = process.env.STORYBOOK_TEMPLATE_NAME || '';\nconst type = process.env.STORYBOOK_TYPE || 'dev';\nconst sandboxDir = process.env.STORYBOOK_SANDBOX_DIR!;\n\nconst MCP_ENDPOINT = `${storybookUrl}/mcp`;\n\n/** Helper to make MCP requests and parse SSE response */\nasync function mcpRequest(\n  request: APIRequestContext,\n  method: string,\n  params: Record<string, unknown> = {},\n  id = 1,\n  headers: Record<string, string> = {}\n) {\n  const response = await request.post(MCP_ENDPOINT, {\n    headers: {\n      'Content-Type': 'application/json',\n      ...headers,\n    },\n    data: {\n      jsonrpc: '2.0',\n      id,\n      method,\n      params,\n    },\n  });\n\n  if (!response.ok()) {\n    throw new Error(`HTTP error! status: ${response.status()}`);\n  }\n\n  // MCP responses come as SSE (Server-Sent Events) format\n  // Format: \"event: message\\ndata: {...}\"\n  const text = await response.text();\n  // Extract the JSON from the \"data: \" line\n  const dataMatch = text.match(/^data: (.+)$/m);\n  if (!dataMatch) {\n    throw new Error(`Invalid SSE response format: ${text}`);\n  }\n  return JSON.parse(dataMatch[1]);\n}\n\ntest.describe('addon-mcp', () => {\n  test.skip(\n    templateName !== 'react-vite/default-ts',\n    'Only run for sandboxes with addon-mcp configured'\n  );\n\n  test.describe('Manifests', () => {\n    test.describe('Component Manifest', () => {\n      test('should have valid components.json structure', async ({ request }) => {\n        const response = await request.get(`${storybookUrl}/manifests/components.json`);\n        const json = await response.json();\n\n        // Check basic structure\n        expect(json).toHaveProperty('v');\n        expect(typeof json.v).toBe('number');\n        expect(json).toHaveProperty('components');\n        expect(typeof json.components).toBe('object');\n      });\n\n      test('should contain the example Button component', async ({ request }) => {\n        const response = await request.get(`${storybookUrl}/manifests/components.json`);\n        const json = await response.json();\n\n        // Check for example-button component\n        expect(json.components).toHaveProperty('example-button');\n\n        const button = json.components['example-button'];\n        expect(button).toMatchObject({\n          id: 'example-button',\n          name: 'Button',\n          path: expect.stringContaining('Button.stories'),\n        });\n\n        // Should have stories\n        expect(button.stories).toBeInstanceOf(Array);\n        expect(button.stories.length).toBeGreaterThan(0);\n\n        // Should have reactDocgen info with props\n        expect(button).toHaveProperty('reactDocgen');\n        expect(button.reactDocgen).toHaveProperty('props');\n        expect(button.reactDocgen.props).toHaveProperty('primary');\n      });\n    });\n\n    test.describe('Docs Manifest', () => {\n      test('should have valid docs.json structure', async ({ request }) => {\n        const response = await request.get(`${storybookUrl}/manifests/docs.json`);\n        const json = await response.json();\n\n        // Check basic structure\n        expect(json).toHaveProperty('v');\n        expect(typeof json.v).toBe('number');\n        expect(json).toHaveProperty('docs');\n        expect(typeof json.docs).toBe('object');\n      });\n\n      test('should contain the \"Configure your project\" docs entry', async ({ request }) => {\n        const response = await request.get(`${storybookUrl}/manifests/docs.json`);\n        const json = await response.json();\n\n        // Check for configure-your-project--docs entry\n        expect(json.docs).toHaveProperty('configure-your-project--docs');\n\n        const configureDoc = json.docs['configure-your-project--docs'];\n        expect(configureDoc).toMatchObject({\n          id: 'configure-your-project--docs',\n          name: 'Docs',\n          path: expect.stringContaining('Configure.mdx'),\n          title: 'Configure your project',\n        });\n\n        // Should have content\n        expect(configureDoc).toHaveProperty('content');\n        expect(typeof configureDoc.content).toBe('string');\n        expect(configureDoc.content.length).toBeGreaterThan(0);\n      });\n    });\n  });\n\n  test.describe('MCP', () => {\n    test.skip(type !== 'dev', 'MCP server only runs in dev mode');\n\n    test.describe('Info Page', () => {\n      test('should show both toolsets as enabled', async ({ page }) => {\n        await page.goto(MCP_ENDPOINT);\n\n        // Check that dev toolset is listed with its tools\n        const devToolset = page.locator('.toolset', { has: page.locator('text=dev') });\n        await expect(devToolset).toBeVisible();\n        await expect(devToolset.locator('.toolset-status')).toHaveText('enabled');\n\n        // Check that docs toolset is listed with its tools\n        const docsToolset = page.locator('.toolset', { has: page.locator('text=docs') });\n        await expect(docsToolset).toBeVisible();\n        await expect(docsToolset.locator('.toolset-status')).toHaveText('enabled');\n\n        // Check that test toolset is listed with its tools\n        const testToolset = page.locator('.toolset', { has: page.locator('text=test') });\n        await expect(testToolset).toBeVisible();\n        await expect(testToolset.locator('.toolset-status').first()).toHaveText('enabled');\n\n        // Check that accessibility tool is enabled\n        const accessibilityTool = testToolset.locator(\n          '.toolset-tools li:has-text(\"accessibility\")'\n        );\n        await expect(accessibilityTool).toBeVisible();\n        await expect(accessibilityTool.locator('.toolset-status')).toHaveText('+ accessibility');\n      });\n    });\n\n    test.describe('Session Initialization', () => {\n      test('should successfully initialize an MCP session', async ({ request }) => {\n        const response = await mcpRequest(request, 'initialize', {\n          protocolVersion: '2025-06-18',\n          capabilities: {},\n          clientInfo: {\n            name: 'e2e-test-client',\n            version: '1.0.0',\n          },\n        });\n\n        expect(response).toMatchObject({\n          jsonrpc: '2.0',\n          id: 1,\n          result: {\n            protocolVersion: '2025-06-18',\n            capabilities: {\n              tools: { listChanged: true },\n            },\n            serverInfo: {\n              name: '@storybook/addon-mcp',\n              description: expect.stringContaining('agents'),\n            },\n          },\n        });\n\n        expect(response.result.serverInfo.version).toBeDefined();\n      });\n    });\n\n    test.describe('Tools Discovery', () => {\n      test('should list all available tools', async ({ request }) => {\n        const response = await mcpRequest(request, 'tools/list');\n\n        expect(response.result).toHaveProperty('tools');\n        // At least dev and docs tools should be present (4 total)\n        expect(response.result.tools.length).toBeGreaterThanOrEqual(4);\n      });\n    });\n\n    test.describe('Tool: preview-stories', () => {\n      test('should return story URLs for valid stories', async ({ request }) => {\n        const storyName = 'Primary';\n        const expectedPreviewUrl = `${storybookUrl}/?path=/story/example-button--primary`;\n\n        // Use a path pattern that works regardless of sandbox location\n        const response = await mcpRequest(request, 'tools/call', {\n          name: 'preview-stories',\n          arguments: {\n            stories: [\n              {\n                exportName: storyName,\n                absoluteStoryPath: path.join(sandboxDir, 'src', 'stories', 'Button.stories.ts'),\n              },\n            ],\n          },\n        });\n\n        expect(response.result).toStrictEqual({\n          content: [\n            {\n              type: 'text',\n              text: expectedPreviewUrl,\n            },\n          ],\n          structuredContent: {\n            stories: [\n              {\n                name: storyName,\n                previewUrl: expectedPreviewUrl,\n                title: 'Example/Button',\n              },\n            ],\n          },\n        });\n      });\n    });\n\n    test.describe('Tool: get-storybook-story-instructions', () => {\n      test('should return UI building instructions', async ({ request }) => {\n        const response = await mcpRequest(request, 'tools/call', {\n          name: 'get-storybook-story-instructions',\n          arguments: {},\n        });\n\n        expect(response.result).toHaveProperty('content');\n        expect(response.result.content[0]).toHaveProperty('type', 'text');\n\n        const text = response.result.content[0].text;\n        expect(text).toContain('stories');\n        expect(text.length).toBeGreaterThan(100);\n      });\n    });\n\n    test.describe('Tool: list-all-documentation', () => {\n      test('should list all documentation from manifest', async ({ request }) => {\n        const response = await mcpRequest(request, 'tools/call', {\n          name: 'list-all-documentation',\n          arguments: {},\n        });\n\n        expect(response.result).toHaveProperty('content');\n        expect(response.result.content[0]).toHaveProperty('type', 'text');\n\n        const text = response.result.content[0].text;\n        // Should contain components section with Button\n        expect(text).toContain('Button');\n        expect(text).toContain('example-button');\n      });\n    });\n\n    test.describe('Tool: get-documentation', () => {\n      test('should return documentation for a specific component', async ({ request }) => {\n        const response = await mcpRequest(request, 'tools/call', {\n          name: 'get-documentation',\n          arguments: {\n            id: 'example-button',\n          },\n        });\n\n        expect(response.result).toHaveProperty('content');\n        expect(response.result.content[0]).toHaveProperty('type', 'text');\n\n        const text = response.result.content[0].text;\n        // Should contain component info\n        expect(text).toContain('Button');\n        expect(text).toContain('example-button');\n        // Should contain stories\n        expect(text).toContain('Primary');\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/addon-onboarding.spec.ts",
    "content": "import { readdir, rm } from 'node:fs/promises';\nimport { homedir } from 'node:os';\n\nimport { expect, test } from '@playwright/test';\nimport { join } from 'pathe';\nimport process from 'process';\n\nimport { SbPage, hasOnboardingFeature } from './util.ts';\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';\nconst templateName = process.env.STORYBOOK_TEMPLATE_NAME || '';\nconst type = process.env.STORYBOOK_TYPE || 'dev';\n\nasync function clearChecklistCache() {\n  const storybookCacheDir = join(\n    process.env.STORYBOOK_SANDBOX_DIR!,\n    'node_modules',\n    '.cache',\n    'storybook'\n  );\n  const storybookCacheEntries = await readdir(storybookCacheDir, { withFileTypes: true }).catch(\n    () => []\n  );\n\n  // Storybook scopes cache entries by version, so remove the checklist for any installed version.\n  await Promise.all(\n    storybookCacheEntries\n      .filter((entry) => entry.isDirectory())\n      .map((entry) =>\n        rm(join(storybookCacheDir, entry.name, 'default', 'checklist'), {\n          recursive: true,\n          force: true,\n        })\n      )\n  );\n}\n\ntest.describe('addon-onboarding', () => {\n  test.skip(type === 'build', `Skipping addon tests for production Storybooks`);\n  test.skip(\n    !hasOnboardingFeature(templateName),\n    `Skipping ${templateName}, which does not have addon-onboarding set up.`\n  );\n  test('the onboarding flow', async ({ page }) => {\n    // eslint-disable-next-line playwright/no-conditional-in-test\n    if (process.env.CI) {\n      await rm(join(homedir(), '.storybook', 'settings.json'), { force: true });\n      await clearChecklistCache();\n    }\n\n    await page.goto(`${storybookUrl}/?path=/onboarding`);\n    const sbPage = new SbPage(page, expect);\n    await sbPage.waitUntilLoaded();\n\n    await expect(page.getByRole('heading', { name: 'Meet your new frontend' })).toBeVisible();\n    await page.locator('#storybook-addon-onboarding').getByRole('button').click();\n\n    await expect(page.getByText('Interactive story playground')).toBeVisible();\n    await page.getByLabel('Next').click();\n\n    await expect(page.getByText('Save your changes as a new')).toBeVisible();\n    await page.getByLabel('Next').click();\n\n    await expect(page.getByRole('heading', { name: 'Create new story' })).toBeVisible();\n    await page.getByPlaceholder('Story export name').click();\n\n    // this is needed because the e2e test will generate a new file in the system\n    // which we don't know of its location (it runs in different sandboxes)\n    // so we just create a random id to make it easier to run tests\n    const id = Math.random().toString(36).substring(7);\n    await page.getByPlaceholder('Story export name').fill('Test-' + id);\n    await page.getByRole('button', { exact: true, name: 'Create' }).click();\n\n    await expect(page.getByText('You just added your first')).toBeVisible();\n    await page.getByLabel('Last').click();\n\n    await page.getByRole('checkbox', { name: 'Application UI' }).check();\n    await page.getByRole('checkbox', { name: 'Functional testing' }).check();\n    await page.locator('#referrer').selectOption('Web Search');\n    await page.getByRole('button', { name: 'Submit' }).click();\n\n    // After completing onboarding, verify we navigate to a story (first story in the index)\n    await expect(sbPage.page).toHaveURL(/\\/(story|docs)\\//);\n    // Verify the preview iframe has loaded content\n    await sbPage.waitUntilLoaded();\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/addon-toolbars.spec.ts",
    "content": "import { expect, test } from '@playwright/test';\nimport process from 'process';\n\nimport { SbPage } from './util.ts';\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';\n\ntest.describe('addon-toolbars', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto(storybookUrl);\n    await new SbPage(page, expect).waitUntilLoaded();\n  });\n\n  test('should have locale button in the toolbar', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n\n    // Click on viewport button and select spanish\n    await sbPage.navigateToStory('core/toolbars/globals', 'basic');\n    await sbPage.selectToolbar('[aria-label^=\"Internationalization locale\"]', 'text=/Español/');\n\n    // Check that spanish is selected\n    await expect(sbPage.previewRoot()).toContainText('Hola');\n  });\n\n  test('locale button should be disabled for story that overrides locale global', async ({\n    page,\n  }) => {\n    const sbPage = new SbPage(page, expect);\n\n    // Click on viewport button and select spanish\n    await sbPage.navigateToStory('core/toolbars/globals', 'override-locale');\n    await expect(sbPage.previewRoot()).toContainText('안녕하세요');\n\n    const button = sbPage.page.getByLabel('Internationalization locale');\n    await expect(button).toHaveAttribute('aria-disabled', 'true');\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/addon-viewport.spec.ts",
    "content": "import { expect, test } from '@playwright/test';\nimport process from 'process';\n\nimport { SbPage } from './util.ts';\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';\n\ntest.describe('addon-viewport', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto(storybookUrl);\n    await new SbPage(page, expect).waitUntilLoaded();\n  });\n\n  test('should have viewport button in the toolbar', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n\n    // Click on viewport button and select small mobile\n    await sbPage.navigateToStory('example/button', 'primary');\n    await sbPage.selectToolbar('[aria-label=\"Viewport size\"]', 'text=/Small mobile/');\n\n    // Check that Button story is still displayed\n    await expect(sbPage.previewRoot()).toContainText('Button');\n  });\n\n  test('iframe width should be changed when a mobile viewport is selected', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n\n    // Click on viewport button and select small mobile\n    await sbPage.navigateToStory('example/button', 'primary');\n\n    // Measure the original dimensions of previewRoot\n    const originalDimensions = await sbPage.getCanvasBodyElement().boundingBox();\n    expect(originalDimensions?.width).toBeDefined();\n\n    await sbPage.selectToolbar('[aria-label=\"Viewport size\"]', 'text=/Small mobile/');\n\n    // Measure the adjusted dimensions of previewRoot after clicking the mobile item.\n    const adjustedDimensions = await sbPage.getCanvasBodyElement().boundingBox();\n    expect(adjustedDimensions?.width).toBeDefined();\n\n    // Compare the two widths\n    expect(adjustedDimensions?.width).not.toBe(originalDimensions?.width);\n  });\n\n  test('viewport should be uneditable when a viewport is set via globals', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n\n    // Story parameters/selected is set to small mobile\n    await sbPage.navigateToStory('core/viewport/globals', 'selected');\n\n    // Measure the original dimensions of previewRoot\n    const originalDimensions = await sbPage.getCanvasBodyElement().boundingBox();\n    expect(originalDimensions?.width).toBeDefined();\n\n    const toolbar = page.getByLabel('Viewport size');\n\n    await expect(toolbar).toHaveAttribute('aria-disabled', 'true');\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/component-tests.spec.ts",
    "content": "import { expect, test } from '@playwright/test';\nimport process from 'process';\n\nimport { SbPage, checkTemplate } from './util.ts';\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:6006';\nconst templateName = process.env.STORYBOOK_TEMPLATE_NAME || '';\n\ntest.describe('interactions', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto(storybookUrl);\n    await new SbPage(page, expect).waitUntilLoaded();\n  });\n\n  test('should have interactions', async ({ page }) => {\n    // templateName is e.g. 'vue-cli/default-js'\n    test.skip(\n      /^(lit)/i.test(`${templateName}`),\n      `Skipping ${templateName}, which does not support interactions`\n    );\n    test.skip(\n      templateName.includes('react-native-web'),\n      'React Native does not use className locators'\n    );\n\n    const sbPage = new SbPage(page, expect);\n\n    await sbPage.navigateToStory('example/page', 'logged-in');\n    await sbPage.viewAddonPanel('Interactions');\n\n    const welcome = sbPage.previewRoot().locator('.welcome');\n    await expect(welcome).toContainText('Welcome, Jane Doe!', { timeout: 50000 });\n\n    const interactionsTab = page.getByRole('tab', { name: 'Interactions' });\n    await expect(interactionsTab).toContainText(/(\\d)/);\n    await expect(interactionsTab).toBeVisible();\n\n    const panel = sbPage.panelContent();\n    await expect(panel).toContainText(/Pass/);\n    await expect(panel).toContainText(/userEvent.click/);\n    await expect(panel).toBeVisible();\n\n    const done = panel.locator('[data-testid=icon-done]').nth(0);\n    await expect(done).toBeVisible();\n  });\n\n  test('should step through interactions', async ({ page, browserName }) => {\n    // templateName is e.g. 'vue-cli/default-js'\n    test.skip(\n      /^(lit)/i.test(`${templateName}`),\n      `Skipping ${templateName}, which does not support interactions`\n    );\n    test.skip(\n      browserName === 'firefox',\n      `Skipping on FireFox, which has trouble with \"initial value\"`\n    );\n\n    const sbPage = new SbPage(page, expect);\n\n    await sbPage.deepLinkToStory(storybookUrl, 'core/component-test-basics', 'type-and-clear');\n    await sbPage.viewAddonPanel('Interactions');\n\n    // Test initial state - Interactions have run, count is correct and values are as expected\n    const formInput = sbPage.previewRoot().locator('#interaction-test-form input');\n    await expect(formInput).toHaveValue('final value', { timeout: 50000 });\n\n    const interactionsTab = page.getByRole('tab', { name: 'Interactions' });\n    await expect(interactionsTab.getByText('3')).toBeVisible();\n    await expect(interactionsTab).toBeVisible();\n\n    const panel = sbPage.panelContent();\n    const runStatusBadge = panel.locator('[aria-label^=\"Story status:\"]');\n    await expect(runStatusBadge).toContainText(/Pass/);\n    await expect(panel).toContainText(/\"initial value\"/);\n    await expect(panel).toContainText(/clear/);\n    await expect(panel).toContainText(/\"final value\"/);\n    await expect(panel).toBeVisible();\n\n    // Test interactions debugger - Stepping through works, count is correct and values are as expected\n    const interactionsRow = panel.locator('[aria-label=\"Interaction step\"]');\n\n    await expect(interactionsRow.first()).toBeVisible();\n\n    await expect(interactionsRow).toHaveCount(3);\n    const firstInteraction = interactionsRow.first();\n    await firstInteraction.click();\n\n    await expect(runStatusBadge).toContainText(/Runs/);\n    await expect(formInput).toHaveValue('initial value');\n\n    const goForwardBtn = panel.locator('[aria-label=\"Go forward\"]');\n    await goForwardBtn.click();\n    await expect(formInput).toHaveValue('');\n    await goForwardBtn.click();\n    await expect(formInput).toHaveValue('final value');\n\n    await expect(runStatusBadge).toContainText(/Pass/);\n\n    // Test rerun state (from addon panel) - Interactions have rerun, count is correct and values are as expected\n    const rerunInteractionButton = panel.locator('[aria-label=\"Rerun\"]');\n    await rerunInteractionButton.click();\n\n    await expect(formInput).toHaveValue('final value');\n\n    await expect(interactionsRow.first()).toBeVisible();\n    await expect(interactionsRow.nth(1)).toBeVisible();\n    await expect(interactionsRow.nth(2)).toBeVisible();\n    await expect(interactionsTab.getByText('3')).toBeVisible();\n    await expect(interactionsTab).toBeVisible();\n    await expect(interactionsTab.getByText('3')).toBeVisible();\n\n    // Test remount state (from toolbar) - Interactions have rerun, count is correct and values are as expected\n    const remountComponentButton = page.locator('[aria-label=\"Reload story\"]');\n    await remountComponentButton.click();\n\n    await expect(interactionsRow.first()).toBeVisible();\n    await expect(interactionsRow.nth(1)).toBeVisible();\n    await expect(interactionsRow.nth(2)).toBeVisible();\n    await expect(interactionsTab.getByText('3')).toBeVisible();\n    await expect(interactionsTab).toBeVisible();\n    await expect(interactionsTab).toBeVisible();\n    await expect(formInput).toHaveValue('final value');\n  });\n\n  test('should show unhandled errors', async ({ page }) => {\n    test.skip(\n      /^(lit)/i.test(`${templateName}`),\n      `Skipping ${templateName}, which does not support interactions`\n    );\n    // We trigger the implicit action error here, but angular works a bit different with implicit actions.\n    test.skip(/^(angular)/i.test(`${templateName}`));\n\n    const sbPage = new SbPage(page, expect);\n\n    await sbPage.deepLinkToStory(storybookUrl, 'core/component-test-unhandled-errors', 'default');\n    await sbPage.viewAddonPanel('Interactions');\n\n    const button = sbPage.previewRoot().locator('button');\n    await expect(button).toContainText('Button', { timeout: 50000 });\n\n    const panel = sbPage.panelContent();\n    await expect(panel).toContainText(/Fail/);\n    await expect(panel).toContainText(/Found 1 unhandled error/);\n    await expect(panel).toBeVisible();\n  });\n});\n\ntest.describe('test function', () => {\n  test.skip(\n    checkTemplate(templateName, (template) => template.expected.renderer !== '@storybook/react'),\n    `Skipping ${templateName}, which does not support test functions`\n  );\n  test.skip(\n    templateName.includes('react-native-web'),\n    'React Native does not use className locators'\n  );\n\n  test.beforeEach(async ({ page }) => {\n    await page.goto(storybookUrl);\n    await new SbPage(page, expect).waitUntilLoaded();\n  });\n\n  test('should execute steps in the test function', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n    await sbPage.deepLinkToStory(\n      storybookUrl,\n      'stories/renderers/react/test-fn',\n      'default',\n      'simple'\n    );\n    await sbPage.viewAddonPanel('Interactions');\n\n    const welcome = sbPage.previewRoot().locator('button');\n    await expect(welcome).toContainText('Arg from story', { timeout: 50000 });\n\n    const interactionsTab = page.getByRole('tab', { name: 'Interactions' });\n    await expect(interactionsTab).toContainText(/(\\d)/);\n    await expect(interactionsTab).toBeVisible();\n\n    const panel = sbPage.panelContent();\n    await expect(panel).toContainText(/Pass/);\n    await expect(panel).toContainText(/userEvent.click/);\n    await expect(panel).toBeVisible();\n\n    const done = panel.locator('[data-testid=icon-done]').nth(0);\n    await expect(done).toBeVisible();\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/framework-nextjs.spec.ts",
    "content": "import type { Locator } from '@playwright/test';\nimport { expect, test } from '@playwright/test';\nimport process from 'process';\n\nimport { SbPage } from './util.ts';\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:6006';\nconst templateName = process.env.STORYBOOK_TEMPLATE_NAME;\n\ntest.describe('Next.js', () => {\n  // TODO: improve these E2E tests given that we have more version of Next.js to test\n  // and this only tests nextjs/default-js\n  test.skip(\n    !templateName?.includes('nextjs/default-ts'),\n    'Only run this test for the Frameworks that support next/navigation'\n  );\n\n  test.beforeEach(async ({ page }) => {\n    await page.goto(storybookUrl);\n    await new SbPage(page, expect).waitUntilLoaded();\n  });\n\n  test.describe('next/image', () => {\n    let sbPage: SbPage;\n\n    test.beforeEach(async ({ page }) => {\n      sbPage = new SbPage(page, expect);\n    });\n\n    // eslint-disable-next-line playwright/no-skipped-test -- test is flaky, investigate why\n    test.skip('should lazy load images by default', async () => {\n      await sbPage.navigateToStory('stories/frameworks/nextjs/Image', 'lazy');\n\n      const img = sbPage.previewRoot().locator('img');\n\n      expect(await img.evaluate<boolean, HTMLImageElement>((image) => image.complete)).toBeFalsy();\n    });\n\n    // eslint-disable-next-line playwright/no-skipped-test -- test is flaky, investigate why\n    test.skip('should eager load images when loading parameter is set to eager', async () => {\n      await sbPage.navigateToStory('stories/frameworks/nextjs/Image', 'eager');\n\n      const img = sbPage.previewRoot().locator('img');\n\n      expect(await img.evaluate<boolean, HTMLImageElement>((image) => image.complete)).toBeTruthy();\n    });\n  });\n\n  test.describe('next/navigation', () => {\n    let root: Locator;\n    let sbPage: SbPage;\n\n    test.beforeEach(async ({ page }) => {\n      sbPage = new SbPage(page, expect);\n\n      await sbPage.navigateToStory('stories/frameworks/nextjs/Navigation', 'default');\n      root = sbPage.previewRoot();\n    });\n\n    function testRoutingBehaviour(buttonText: string, action: string) {\n      test(`should trigger ${action} action`, async ({ page }) => {\n        const button = root.locator('button', { hasText: buttonText });\n        await button.click();\n\n        await sbPage.viewAddonPanel('Actions');\n        const logItem = page.locator('#storybook-panel-root [role=\"tabpanel\"]', {\n          hasText: `useRouter().${action}`,\n        });\n        await expect(logItem).toBeVisible();\n      });\n    }\n\n    testRoutingBehaviour('Go back', 'back');\n    testRoutingBehaviour('Go forward', 'forward');\n    testRoutingBehaviour('Prefetch', 'prefetch');\n    testRoutingBehaviour('Push HTML', 'push');\n    testRoutingBehaviour('Refresh', 'refresh');\n    testRoutingBehaviour('Replace', 'replace');\n  });\n\n  test.describe('next/router', () => {\n    let root: Locator;\n    let sbPage: SbPage;\n\n    test.beforeEach(async ({ page }) => {\n      sbPage = new SbPage(page, expect);\n\n      await sbPage.navigateToStory('stories/frameworks/nextjs/Router', 'default');\n      root = sbPage.previewRoot();\n    });\n\n    function testRoutingBehaviour(buttonText: string, action: string) {\n      test(`should trigger ${action} action`, async ({ page }) => {\n        const button = root.locator('button', { hasText: buttonText });\n        await button.click();\n\n        await sbPage.viewAddonPanel('Actions');\n        const logItem = page.locator('#storybook-panel-root [role=\"tabpanel\"]', {\n          hasText: `useRouter().${action}`,\n        });\n        await expect(logItem).toBeVisible();\n      });\n    }\n\n    testRoutingBehaviour('Go back', 'back');\n    testRoutingBehaviour('Go forward', 'forward');\n    testRoutingBehaviour('Prefetch', 'prefetch');\n    testRoutingBehaviour('Push HTML', 'push');\n    testRoutingBehaviour('Replace', 'replace');\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/framework-svelte.spec.ts",
    "content": "import { expect, test } from '@playwright/test';\nimport process from 'process';\n\nimport { SbPage } from './util.ts';\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:6006';\nconst templateName = process.env.STORYBOOK_TEMPLATE_NAME;\n\ntest.describe('Svelte', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto(storybookUrl);\n    await new SbPage(page, expect).waitUntilLoaded();\n  });\n\n  test.skip(!templateName?.includes('svelte'), 'Only run these tests on Svelte');\n\n  test('Decorators are excluded from generated source code', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n\n    await sbPage.navigateToStory('stories/renderers/svelte/decorators', 'docs');\n    const root = sbPage.previewRoot();\n    const showCodeButton = (await root.locator('button', { hasText: 'Show Code' }).all())[0];\n    await showCodeButton.click();\n    const sourceCode = root.locator('pre.prismjs');\n    const expectedSource = '<Button />';\n    await expect(sourceCode).toHaveText(expectedSource);\n  });\n\n  test.describe('SvelteKit', () => {\n    test.skip(!templateName?.includes('svelte-kit'), 'Only run this test on SvelteKit');\n\n    test('Links are logged in Actions panel', async ({ page }) => {\n      const sbPage = new SbPage(page, expect);\n\n      await sbPage.navigateToStory('stories/frameworks/sveltekit/modules/hrefs', 'default-actions');\n      const root = sbPage.previewRoot();\n      const link = root.locator('a', { hasText: 'Link to /basic-href' });\n      await link.click();\n\n      await sbPage.viewAddonPanel('Actions');\n      const basicLogItem = page.locator('#storybook-panel-root [role=\"tabpanel\"]', {\n        hasText: `/basic-href`,\n      });\n\n      await expect(basicLogItem).toBeVisible();\n      const complexLogItem = page.locator('#storybook-panel-root [role=\"tabpanel\"]', {\n        hasText: `/deep/nested`,\n      });\n      await expect(complexLogItem).toBeVisible();\n    });\n\n    test('goto are logged in Actions panel', async ({ page }) => {\n      const sbPage = new SbPage(page, expect);\n\n      await sbPage.navigateToStory(\n        'stories/frameworks/sveltekit/modules/navigation',\n        'default-actions'\n      );\n      const root = sbPage.previewRoot();\n      await sbPage.viewAddonPanel('Actions');\n\n      const goto = root.locator('button', { hasText: 'goto' });\n      await goto.click();\n\n      const gotoLogItem = page.locator('#storybook-panel-root [role=\"tabpanel\"]', {\n        hasText: `/storybook-goto`,\n      });\n      await expect(gotoLogItem).toBeVisible();\n\n      const invalidate = root.getByRole('button', { name: 'invalidate', exact: true });\n      await invalidate.click();\n\n      const invalidateLogItem = page.locator('#storybook-panel-root [role=\"tabpanel\"]', {\n        hasText: `/storybook-invalidate`,\n      });\n      await expect(invalidateLogItem).toBeVisible();\n\n      const invalidateAll = root.getByRole('button', { name: 'invalidateAll' });\n      await invalidateAll.click();\n\n      const invalidateAllLogItem = page.locator('#storybook-panel-root [role=\"tabpanel\"]', {\n        hasText: `\"invalidateAll\"`,\n      });\n      await expect(invalidateAllLogItem).toBeVisible();\n\n      const replaceState = root.getByRole('button', { name: 'replaceState' });\n      await replaceState.click();\n\n      const replaceStateLogItem = page.locator('#storybook-panel-root [role=\"tabpanel\"]', {\n        hasText: `/storybook-replace-state`,\n      });\n      await expect(replaceStateLogItem).toBeVisible();\n\n      const pushState = root.getByRole('button', { name: 'pushState' });\n      await pushState.click();\n\n      const pushStateLogItem = page.locator('#storybook-panel-root [role=\"tabpanel\"]', {\n        hasText: `/storybook-push-state`,\n      });\n      await expect(pushStateLogItem).toBeVisible();\n    });\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/framework-vue3.spec.ts",
    "content": "import { expect, test } from '@playwright/test';\nimport process from 'process';\n\nimport { SbPage } from './util.ts';\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:6006';\nconst templateName = process.env.STORYBOOK_TEMPLATE_NAME;\n\ntest.describe('Vue 3', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto(storybookUrl);\n    await new SbPage(page, expect).waitUntilLoaded();\n  });\n\n  test.skip(templateName !== 'vue3-vite/default-ts', 'Only run these tests on Vue 3');\n\n  test('updateArgs works in decorators', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n\n    await sbPage.navigateToStory(\n      'stories/renderers/vue3_vue3-vite-default-ts/decorators',\n      'update-args'\n    );\n    const previewRoot = sbPage.previewRoot();\n    const button = previewRoot.getByRole('button', { name: 'Add 1' });\n\n    await expect(previewRoot).toContainText('0');\n    await button.click();\n    await expect(previewRoot).toContainText('1');\n    await button.click();\n    await expect(previewRoot).toContainText('2');\n  });\n\n  test('Decorators can consume reactive globals', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n\n    await sbPage.navigateToStory(\n      'stories/renderers/vue3_vue3-vite-default-ts/decorators',\n      'reactive-global-decorator'\n    );\n\n    // Check the original language\n    await expect(sbPage.previewRoot()).toContainText('Hello');\n\n    // Select spanish in the locale toolbar and check that the text changes\n    await sbPage.selectToolbar('[aria-label^=\"Internationalization locale\"]', 'text=/Español/');\n    await expect(sbPage.previewRoot()).toContainText('Hola');\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/json-files.spec.ts",
    "content": "import { expect, test } from '@playwright/test';\nimport process from 'process';\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';\n\ntest.describe('JSON files', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto(storybookUrl);\n  });\n\n  test('should have index.json', async ({ page }) => {\n    const json = await page.evaluate(() => fetch('/index.json').then((res) => res.json()));\n\n    expect(json).toStrictEqual({\n      v: expect.any(Number),\n      entries: expect.objectContaining({\n        'example-button--primary': expect.objectContaining({\n          id: 'example-button--primary',\n          importPath: expect.stringMatching(/button\\.stories/i),\n          name: 'Primary',\n          title: 'Example/Button',\n          type: 'story',\n        }),\n      }),\n    });\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/manager.spec.ts",
    "content": "import { expect, test } from '@playwright/test';\nimport process from 'process';\n\nimport { SbPage } from './util.ts';\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';\nconst templateName = process.env.STORYBOOK_TEMPLATE_NAME;\nconst type = process.env.STORYBOOK_TYPE || 'dev';\n\ntest.describe('Manager UI', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto(storybookUrl);\n\n    await new SbPage(page, expect).waitUntilLoaded();\n  });\n\n  test.describe('Desktop', () => {\n    // TODO: test dragging and resizing\n\n    test('Settings tooltip', async ({ page }) => {\n      await page.locator('[aria-label=\"Settings\"]').click();\n\n      // should only hide if pressing Escape, and not other keyboard inputs\n      await expect(page.getByRole('dialog')).toBeVisible();\n      await page.keyboard.press('A');\n      await expect(page.getByRole('dialog')).toBeVisible();\n      await page.keyboard.press('Escape');\n      await expect(page.getByRole('dialog')).toBeHidden();\n\n      // should also hide if clicking anywhere outside the tooltip\n      await page.locator('[aria-label=\"Settings\"]').click();\n      await expect(page.getByRole('dialog')).toBeVisible();\n      await page.click('body');\n      await expect(page.getByRole('dialog')).toBeHidden();\n    });\n\n    test('Sidebar toggling', async ({ page }) => {\n      const sbPage = new SbPage(page, expect);\n\n      await expect(sbPage.page.locator('.sidebar-container')).toBeVisible();\n\n      // toggle with keyboard shortcut\n      await sbPage.page.locator('html').press('Alt+s');\n      await expect(sbPage.page.locator('.sidebar-container')).toBeHidden();\n      await sbPage.page.locator('html').press('Alt+s');\n      await expect(sbPage.page.locator('.sidebar-container')).toBeVisible();\n\n      // toggle with menu item\n      await sbPage.page.locator('[aria-label=\"Settings\"]').click();\n      await sbPage.page.locator('#list-item-S').click();\n      await expect(sbPage.page.locator('.sidebar-container')).toBeHidden();\n\n      // toggle with \"show sidebar\" button\n      await sbPage.page.locator('[aria-label=\"Show sidebar\"]').click();\n      await expect(sbPage.page.locator('.sidebar-container')).toBeVisible();\n    });\n\n    test('Story context menu actions', async ({ page }) => {\n      test.skip(type !== 'dev', 'These actions are only applicable in dev mode');\n      const sbPage = new SbPage(page, expect);\n      await sbPage.navigateToStory('example/button', 'docs');\n\n      // Context menu should contain open in editor for component node\n      await page.locator('[data-item-id=\"example-button\"]').hover();\n      await page\n        .locator('[data-item-id=\"example-button\"]')\n        .getByRole('button', { name: 'Open context menu' })\n        .click();\n      const sidebarContextMenu = page.getByRole('dialog');\n      await expect(\n        sidebarContextMenu.getByRole('button', { name: /open in editor/i })\n      ).toBeVisible();\n      await page.click('body');\n\n      // Context menu should contain open in editor for docs node\n      await page.locator('[data-item-id=\"example-button--docs\"]').hover();\n      await page\n        .locator('[data-item-id=\"example-button--docs\"]')\n        .getByRole('button', { name: 'Open context menu' })\n        .click();\n      await expect(\n        page.getByRole('dialog').getByRole('button', { name: /open in editor/i })\n      ).toBeVisible();\n      await page.click('body');\n\n      // Context menu should contain open in editor and copy story name for story node\n      await page.locator('[data-item-id=\"example-button--primary\"]').hover();\n      await page\n        .locator('[data-item-id=\"example-button--primary\"]')\n        .getByRole('button', { name: 'Open context menu' })\n        .click();\n      await expect(\n        page.getByRole('dialog').getByRole('button', { name: /open in editor/i })\n      ).toBeVisible();\n      await page\n        .getByRole('dialog')\n        .getByRole('button', { name: /copy story name/i })\n        .click();\n\n      await expect(page.evaluate(() => navigator.clipboard.readText())).resolves.toContain(\n        'Primary'\n      );\n    });\n\n    test('Story share actions (dev)', async ({ page }) => {\n      test.skip(type !== 'dev', 'These actions are only applicable in dev mode');\n      const sbPage = new SbPage(page, expect);\n      await sbPage.navigateToStory('example/button', 'primary');\n      await expect(page.getByRole('button', { name: 'Open in editor' })).toBeVisible();\n      await page.getByRole('button', { name: 'Share', exact: true }).click();\n      await expect(page.getByRole('button', { name: /copy story link/i })).toBeVisible();\n      await page.getByRole('button', { name: /copy story link/i }).click();\n\n      await expect(page.evaluate(() => navigator.clipboard.readText())).resolves.toContain(\n        `${storybookUrl}/?path=/story/example-button--primary`\n      );\n    });\n\n    test('Story share actions (build)', async ({ page }) => {\n      test.skip(type !== 'build', 'These actions are only applicable in build mode');\n      const sbPage = new SbPage(page, expect);\n      await sbPage.navigateToStory('example/button', 'primary');\n      await page.getByRole('button', { name: 'Share', exact: true }).click();\n      await expect(page.getByRole('button', { name: /copy story link/i })).toBeVisible();\n      await page.getByRole('button', { name: /copy story link/i }).click();\n\n      await expect(page.evaluate(() => navigator.clipboard.readText())).resolves.toContain(\n        `${storybookUrl}/?path=/story/example-button--primary`\n      );\n    });\n\n    test('Toolbar toggling', async ({ page }) => {\n      const sbPage = new SbPage(page, expect);\n      const expectToolbarToBeVisible = async () => {\n        const toolbar = page.getByTestId('sb-preview-toolbar').getByRole('toolbar');\n        await expect(toolbar).toBeVisible();\n      };\n\n      const expectToolbarToNotExist = async () => {\n        const toolbar = page.getByTestId('sb-preview-toolbar').getByRole('toolbar');\n        await expect(toolbar).toBeHidden();\n      };\n\n      await expectToolbarToBeVisible();\n\n      // toggle with keyboard shortcut\n      await sbPage.page.locator('html').press('Alt+t');\n      await expectToolbarToNotExist();\n      await sbPage.page.locator('html').press('Alt+t');\n      await expectToolbarToBeVisible();\n\n      // toggle with menu item\n      await sbPage.page.locator('[aria-label=\"Settings\"]').click();\n      await sbPage.page.locator('#list-item-T').click();\n      await expectToolbarToNotExist();\n      await sbPage.page.locator('#list-item-T').click();\n      await expectToolbarToBeVisible();\n    });\n\n    test.describe('Panel', () => {\n      test('Hidden in docs view', async ({ page }) => {\n        const sbPage = new SbPage(page, expect);\n\n        // navigate to docs to hide panel\n        await sbPage.navigateToStory('example/button', 'docs');\n\n        await expect(sbPage.page.locator('#storybook-panel-root')).toBeHidden();\n\n        // toggle with keyboard shortcut\n        await sbPage.page.locator('html').press('Alt+a');\n        await expect(sbPage.page.locator('#storybook-panel-root')).toBeHidden();\n        await sbPage.page.locator('html').press('Alt+a');\n        await expect(sbPage.page.locator('#storybook-panel-root')).toBeHidden();\n      });\n\n      test('Toggling', async ({ page }) => {\n        const sbPage = new SbPage(page, expect);\n\n        // navigate to story to show panel\n        await sbPage.navigateToStory('example/button', 'primary');\n\n        await expect(sbPage.page.locator('#storybook-panel-root')).toBeVisible();\n\n        // toggle with keyboard shortcut\n        await sbPage.page.locator('html').press('Alt+a');\n        await expect(sbPage.page.locator('#storybook-panel-root')).toBeHidden();\n        await sbPage.page.locator('html').press('Alt+a');\n        await expect(sbPage.page.locator('#storybook-panel-root')).toBeVisible();\n\n        // toggle with menu item\n        await sbPage.page.locator('[aria-label=\"Settings\"]').click();\n        await sbPage.page.locator('#list-item-A').click();\n        await expect(sbPage.page.locator('#storybook-panel-root')).toBeHidden();\n        await sbPage.page.locator('html').press('Escape');\n\n        // toggle with \"Show addon panel\" button\n        await sbPage.page.locator('[aria-label=\"Show addon panel\"]').click();\n        await expect(sbPage.page.locator('#storybook-panel-root')).toBeVisible();\n      });\n\n      test('Positioning', async ({ page }) => {\n        const sbPage = new SbPage(page, expect);\n\n        // navigate to story to show panel\n        await sbPage.navigateToStory('example/button', 'primary');\n\n        await expect(sbPage.page.locator('#storybook-panel-root')).toBeVisible();\n\n        // toggle position with keyboard shortcut\n        await sbPage.page.locator('html').press('Alt+d');\n        await expect(sbPage.page.locator('#storybook-panel-root')).toBeVisible();\n        // TODO: how to assert panel position?\n\n        // hide with keyboard shortcut\n        await sbPage.page.locator('html').press('Alt+a');\n        await expect(sbPage.page.locator('#storybook-panel-root')).toBeHidden();\n\n        // toggling position should also show the panel again\n        await sbPage.page.locator('html').press('Alt+d');\n        await expect(sbPage.page.locator('#storybook-panel-root')).toBeVisible();\n      });\n    });\n\n    test('Fullscreen toggling', async ({ page }) => {\n      const sbPage = new SbPage(page, expect);\n\n      // navigate to story to show panel\n      await sbPage.navigateToStory('example/button', 'primary');\n\n      await expect(sbPage.page.locator('#storybook-panel-root')).toBeVisible();\n      await expect(sbPage.page.locator('.sidebar-container')).toBeVisible();\n\n      // toggle with keyboard shortcut\n      await sbPage.page.locator('html').press('Alt+f');\n      await expect(sbPage.page.locator('#storybook-panel-root')).toBeHidden();\n      await expect(sbPage.page.locator('.sidebar-container')).toBeHidden();\n\n      await sbPage.page.locator('html').press('Alt+f');\n      await expect(sbPage.page.locator('#storybook-panel-root')).toBeVisible();\n      await expect(sbPage.page.locator('.sidebar-container')).toBeVisible();\n\n      // toggle with \"go/exit fullscreen\" button\n      await sbPage.page.locator('[aria-label=\"Enter full screen\"]').click();\n      await expect(sbPage.page.locator('#storybook-panel-root')).toBeHidden();\n      await expect(sbPage.page.locator('.sidebar-container')).toBeHidden();\n\n      await sbPage.page.locator('[aria-label=\"Exit full screen\"]').click();\n      await expect(sbPage.page.locator('#storybook-panel-root')).toBeVisible();\n      await expect(sbPage.page.locator('.sidebar-container')).toBeVisible();\n\n      // go fullscreen when sidebar is shown but panel is hidden\n      await sbPage.page.locator('[aria-label=\"Enter full screen\"]').click();\n      await sbPage.page.locator('[aria-label=\"Show sidebar\"]').click();\n      await expect(sbPage.page.locator('.sidebar-container')).toBeVisible();\n      await sbPage.page.locator('[aria-label=\"Enter full screen\"]').click();\n      await expect(sbPage.page.locator('#storybook-panel-root')).toBeHidden();\n      await expect(sbPage.page.locator('.sidebar-container')).toBeHidden();\n\n      // go fullscreen when panel is shown but sidebar is hidden\n      await sbPage.page.locator('[aria-label=\"Show addon panel\"]').click();\n      await expect(sbPage.page.locator('#storybook-panel-root')).toBeVisible();\n      await sbPage.page.locator('[aria-label=\"Enter full screen\"]').click();\n      await expect(sbPage.page.locator('#storybook-panel-root')).toBeHidden();\n      await expect(sbPage.page.locator('.sidebar-container')).toBeHidden();\n    });\n\n    test('Settings page', async ({ page }) => {\n      const sbPage = new SbPage(page, expect);\n      await sbPage.page.locator('[aria-label=\"Settings\"]').click();\n      await sbPage.page.locator('#list-item-about').click();\n\n      expect(sbPage.page.url()).toContain('/settings/about');\n\n      await expect(sbPage.page.locator('#storybook-panel-root')).toBeHidden();\n\n      await sbPage.page.locator('[aria-label=\"Close settings page\"]').click();\n      expect(sbPage.page.url()).not.toContain('/settings/about');\n    });\n  });\n\n  test.describe('Mobile', () => {\n    test.describe.configure({ retries: 3 });\n    // TODO: remove this when SSV6 templates have been removed\n    // Some assertions in these tests are not compatible with SSV6\n    // GIven that SSV6 will be removed before the new mobile UI released, it doesn't make sense to fix them\n    test.skip(templateName?.includes('ssv6') || false, 'Skip mobile UI tests for SSV6');\n\n    // standard iPhone viewport size\n    test.use({ viewport: { width: 390, height: 844 } });\n\n    test('Navigate to story', async ({ page }) => {\n      const sbPage = new SbPage(page, expect);\n\n      const closeNavigationButton = sbPage.page.locator('[aria-label=\"Close navigation menu\"]');\n      const mobileNavigationHeading = sbPage.page.locator('[aria-label=\"Open navigation menu\"]');\n\n      // navigation menu is closed\n      await expect(closeNavigationButton).toBeHidden();\n      await expect(sbPage.page.locator('#storybook-explorer-menu')).toBeHidden();\n\n      // open navigation menu\n      await mobileNavigationHeading.click();\n      await expect(sbPage.page.locator('#storybook-explorer-menu')).toBeVisible();\n\n      await sbPage.openComponent('Example/Button');\n\n      // navigation menu is still open\n      await expect(sbPage.page.locator('#storybook-explorer-menu')).toBeVisible();\n      // story has not changed\n      expect(sbPage.page.url()).toContain('configure-your-project');\n\n      await sbPage.navigateToStory('Example/Button', 'Secondary');\n\n      // navigation menu is closed\n      await expect(mobileNavigationHeading).toHaveText('Example/Button/Secondary');\n      await expect(sbPage.page.locator('#storybook-explorer-menu')).toBeHidden();\n      // story has changed\n      expect(sbPage.page.url()).toContain('example-button--secondary');\n    });\n\n    test('Open and close addon panel', async ({ page }) => {\n      const sbPage = new SbPage(page, expect);\n\n      const mobileNavigationHeading = sbPage.page.locator('[aria-label=\"Open navigation menu\"]');\n      await mobileNavigationHeading.click();\n      await expect(sbPage.page.locator('#storybook-explorer-menu')).toBeVisible();\n      await sbPage.navigateToStory('Example/Button', 'Secondary');\n\n      // panel is closed\n      await expect(mobileNavigationHeading).toHaveText('Example/Button/Secondary');\n      await expect(sbPage.page.getByRole('tab', { name: 'Controls' })).toBeHidden();\n\n      // open panel\n      await sbPage.page.locator('[aria-label=\"Open addon panel\"]').click();\n\n      // panel is open\n      await expect(sbPage.page.getByRole('tab', { name: 'Controls' })).toBeVisible();\n\n      // close panel\n      await sbPage.page.getByRole('button', { name: 'Close addon panel' }).click();\n\n      // panel is closed\n      await expect(mobileNavigationHeading).toHaveText('Example/Button/Secondary');\n      await expect(sbPage.page.getByRole('tab', { name: 'Controls' })).toBeHidden();\n    });\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/module-mocking.spec.ts",
    "content": "import { expect, test } from '@playwright/test';\nimport process from 'process';\n\nimport { SbPage } from './util.ts';\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';\n\ntest.describe('module-mocking', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto(storybookUrl);\n\n    await new SbPage(page, expect).waitUntilLoaded();\n  });\n\n  test('should assert story lifecycle order', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n\n    await sbPage.navigateToStory('core/order-of-hooks', 'order-of-hooks');\n\n    await sbPage.viewAddonPanel('Actions');\n    const panel = sbPage.panelContent();\n    await expect(panel).toBeVisible();\n\n    const expectedTexts = [\n      '1 - [from loaders]',\n      '2 - [from meta beforeEach]',\n      '3 - [from story beforeEach]',\n      '4 - [before mount]',\n      '5 - [from decorator]',\n      '6 - [after mount]',\n      '7 - [from onClick]',\n      '8 - [from story afterEach]',\n      '9 - [from meta afterEach]',\n    ];\n\n    // Collect all logs in the panel but only check the order of the logs\n    // we care about, disregarding any other logs that could appear in between\n    const logItemsCount = await panel.locator('li').count();\n    const actualTexts = [];\n    for (let i = 0; i < logItemsCount; i++) {\n      actualTexts.push(await panel.locator(`li >> nth=${i}`).innerText());\n    }\n\n    let lastMatchIndex = -1;\n\n    for (const expected of expectedTexts) {\n      const foundIndex = actualTexts.findIndex(\n        (text, i) => i > lastMatchIndex && text.includes(expected)\n      );\n      expect(foundIndex, `Expected log \"${expected}\" to appear in order`).toBeGreaterThan(\n        lastMatchIndex\n      );\n      lastMatchIndex = foundIndex;\n    }\n  });\n\n  test('should assert that utils import is mocked', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n\n    await sbPage.navigateToStory('core/moduleMocking', 'basic');\n\n    await sbPage.viewAddonPanel('Actions');\n    const logItem = sbPage.panelContent().filter({\n      hasText: 'foo: []',\n    });\n    await expect(logItem).toBeVisible();\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/navigation.spec.ts",
    "content": "import { expect, test } from '@playwright/test';\nimport process from 'process';\n\nimport { SbPage } from './util.ts';\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';\n\ntest.describe('navigating', () => {\n  test('a URL with a partial storyId will redirect to the first story', async ({ page }) => {\n    // this is purposefully not using the SbPage class, and the URL is a partial (it does not contain the full storyId)\n    await page.goto(`${storybookUrl}?path=/story/example-button`);\n\n    const sbPage = new SbPage(page, expect);\n\n    await sbPage.waitUntilLoaded();\n\n    await page.waitForFunction(() =>\n      window.document.location.href.match('/docs/example-button--docs')\n    );\n\n    expect(sbPage.page.url()).toContain('/docs/example-button--docs');\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/preview-api.spec.ts",
    "content": "import { expect, test } from '@playwright/test';\nimport process from 'process';\n\nimport { SbPage } from './util.ts';\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';\nconst templateName = process.env.STORYBOOK_TEMPLATE_NAME || '';\n\nconst wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\ntest.describe('preview-api', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto(storybookUrl);\n\n    await new SbPage(page, expect).waitUntilLoaded();\n  });\n\n  test('should pass over shortcuts, but not from play functions, story', async ({ page }) => {\n    test.skip(\n      /^(lit)/i.test(`${templateName}`),\n      `Skipping ${templateName}, which does not support addon-interactions`\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.deepLinkToStory(storybookUrl, 'core/shortcuts', 'keydown-during-play');\n    await expect(sbPage.page.locator('.sidebar-container')).toBeVisible();\n\n    // wait for the play function to complete\n    await sbPage.viewAddonPanel('Interactions');\n    const interactionsTab = page.getByRole('tab', { name: 'Interactions' });\n    await expect(interactionsTab).toBeVisible();\n    const panel = sbPage.panelContent();\n    const runStatusBadge = panel.locator('[aria-label^=\"Story status:\"]');\n    await expect(runStatusBadge).toContainText(/Pass/);\n\n    // click outside, to remove focus from the input of the story, then press S to toggle sidebar\n    await sbPage.previewRoot().click();\n    await sbPage.previewRoot().press('Alt+s');\n    await expect(sbPage.page.locator('.sidebar-container')).toBeHidden();\n  });\n\n  test('should pass over shortcuts, but not from play functions, docs', async ({ page }) => {\n    test.skip(\n      /^(lit)/i.test(`${templateName}`),\n      `Skipping ${templateName}, which does not support addon-interactions`\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.deepLinkToStory(storybookUrl, 'core/shortcuts', 'docs');\n\n    await expect(sbPage.page.locator('.sidebar-container')).toBeVisible();\n\n    await sbPage.previewRoot().getByRole('button').getByText('Submit').first().press('Alt+s');\n    await expect(sbPage.page.locator('.sidebar-container')).toBeHidden();\n  });\n\n  // if rerenders were interleaved the button would have rendered \"Error: Interleaved loaders. Changed arg\"\n  // TODO: ENABLE again once the flake is fixed\n  test.skip('should only render once at a time when rapidly changing args', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory('core/rendering', 'slow-loader');\n\n    const root = sbPage.previewRoot();\n\n    await sbPage.viewAddonPanel('Controls');\n    const labelControl = sbPage.page.locator('#control-label');\n\n    await expect(root.getByText('Loaded. Click me')).toBeVisible();\n    await expect(labelControl).toBeVisible();\n\n    await labelControl.fill('');\n    await labelControl.pressSequentially('Changed arg', { delay: 50 });\n    await labelControl.blur();\n\n    await expect(root.getByText('Loaded. Changed arg')).toBeVisible();\n  });\n\n  test('should reload plage when remounting while loading', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory('core/rendering', 'slow-loader');\n\n    const root = sbPage.previewRoot();\n\n    await expect(root.getByText('Loaded. Click me')).toBeVisible();\n\n    await sbPage.page.getByRole('button', { name: 'Reload story' }).click();\n    await wait(200);\n    await sbPage.page.getByRole('button', { name: 'Reload story' }).click();\n\n    // the loading spinner indicates the iframe is being fully reloaded\n    await expect(sbPage.previewIframe().locator('.sb-preparing-story > .sb-loader')).toBeVisible();\n    await expect(root.getByText('Loaded. Click me')).toBeVisible();\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/sb-module-mocking.spec.ts",
    "content": "import { expect, test } from '@playwright/test';\nimport process from 'process';\n\nimport { SbPage } from './util.ts';\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:6006';\n\ntest.describe('sb-module-mocking', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto(storybookUrl);\n    await new SbPage(page, expect).waitUntilLoaded();\n  });\n\n  test('ModuleMocking: Original, Mocked', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n    // Original\n    await sbPage.navigateToStory('core/test/modulemocking', 'original', 'story', true);\n    const root = sbPage.previewRoot();\n    await expect(root.getByText(/Function: no value/)).toBeVisible();\n    // Mocked\n    await sbPage.navigateToStory('core/test/modulemocking', 'mocked', 'story', true);\n    await expect(root.getByText(/Function: mocked value/)).toBeVisible();\n  });\n\n  test('ModuleAutoMocking: Original', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory('core/test/moduleautomocking', 'original', 'story', true);\n    const root = sbPage.previewRoot();\n    await expect(root.getByText(/Function: automocked value/)).toBeVisible();\n  });\n\n  test('ModuleSpyMocking: Original', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory('core/test/modulespymocking', 'original', 'story', true);\n    const root = sbPage.previewRoot();\n    await expect(root.getByText(/Function: original value/)).toBeVisible();\n  });\n\n  test('NodeModuleMocking: Original', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory('core/test/nodemodulemocking', 'original', 'story', true);\n    const root = sbPage.previewRoot();\n    await expect(root.getByText(/Lodash Version: 1.0.0-mocked!/)).toBeVisible();\n    await expect(root.getByText(/Mocked Add \\(1,2\\): mocked 3/)).toBeVisible();\n    await expect(root.getByText(/Inline Sum \\(2,2\\): mocked 10/)).toBeVisible();\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/storybook-hooks.spec.ts",
    "content": "/* eslint-disable playwright/expect-expect */\nimport { promises as fs } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { expect, test } from '@playwright/test';\n\nimport { SANDBOX_DIRECTORY } from '../../scripts/utils/constants.ts';\nimport { SbPage } from './util.ts';\n\ndeclare global {\n  interface Window {\n    __STORYBOOK_BEFORE_ALL_CALLS__: number;\n    __STORYBOOK_BEFORE_ALL_CLEANUP_CALLS__: number;\n  }\n}\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';\nconst templateName = process.env.STORYBOOK_TEMPLATE_NAME || '';\nconst sandboxDir =\n  process.env.STORYBOOK_SANDBOX_DIR || join(SANDBOX_DIRECTORY, 'react-vite-default-ts');\nconst previewFilePath = join(sandboxDir, '.storybook', 'preview.ts');\nconst isStorybookDev = process.env.STORYBOOK_TYPE === 'dev';\n\ntest.describe('Storybook hooks', () => {\n  test.skip(); // TODO remove\n  test.skip(\n    !templateName?.includes('react-vite/default-ts'),\n    'Only run this test for react-vite sandbox'\n  );\n  test.beforeEach(async ({ page }) => {\n    await page.goto(storybookUrl);\n    await new SbPage(page, expect).waitUntilLoaded();\n  });\n\n  test('should call beforeAll upon loading Storybook', async ({ page }, { titlePath }) => {\n    const sbPage = new SbPage(page, expect);\n\n    await sbPage.navigateToStory('example/button', 'primary');\n\n    await page.waitForFunction(\n      () =>\n        window.__STORYBOOK_BEFORE_ALL_CALLS__ === 1 &&\n        window.__STORYBOOK_BEFORE_ALL_CLEANUP_CALLS__ === 0,\n      undefined,\n      { timeout: 2000 }\n    );\n  });\n\n  test('should call beforeAll and cleanup on HMR', async ({ page }, { titlePath }) => {\n    test.skip(!isStorybookDev, 'HMR is only applicable in dev mode');\n    const sbPage = new SbPage(page, expect);\n\n    await sbPage.navigateToStory('example/button', 'primary');\n\n    const originalContent = await fs.readFile(previewFilePath, 'utf8');\n    const newContent = `${originalContent}\\nconsole.log('Written from E2E test: ${titlePath}');`;\n\n    await page.waitForFunction(\n      () =>\n        window.__STORYBOOK_BEFORE_ALL_CALLS__ === 1 &&\n        window.__STORYBOOK_BEFORE_ALL_CLEANUP_CALLS__ === 0,\n      undefined,\n      { timeout: 2000 }\n    );\n\n    // Save the file to trigger HMR, then wait for it\n    await fs.writeFile(previewFilePath, newContent);\n\n    await page.waitForFunction(\n      () =>\n        window.__STORYBOOK_BEFORE_ALL_CALLS__ === 2 &&\n        window.__STORYBOOK_BEFORE_ALL_CLEANUP_CALLS__ === 1,\n      undefined,\n      { timeout: 2000 }\n    );\n\n    // Restore the original content of the preview file\n    await fs.writeFile(previewFilePath, originalContent);\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/storybook.setup.ts",
    "content": "import { expect, test } from '@playwright/test';\n\nimport { SbPage } from './util.ts';\n\nconst STORYBOOK_READY_TIMEOUT = 200000;\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';\nconst storybookReadyPath = `${storybookUrl}/?path=/story/example-button--primary`;\n\ntest.setTimeout(STORYBOOK_READY_TIMEOUT);\n\ntest.describe('storybook setup', () => {\n  test('wait for Storybook manager and preview to settle', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n\n    await expect\n      .poll(\n        async () => {\n          const response = await page.request.get(`${storybookUrl}/index.json`);\n          if (!response.ok()) {\n            return undefined;\n          }\n\n          const index = await response.json();\n          return index?.entries?.['example-button--primary']?.id;\n        },\n        {\n          intervals: [250, 500, 1000, 2000],\n          message: 'wait for Storybook index.json to expose the example button story',\n          timeout: STORYBOOK_READY_TIMEOUT,\n        }\n      )\n      .toBe('example-button--primary');\n\n    await page.goto(storybookReadyPath);\n\n    const storiesNavigation = page.getByRole('navigation', { name: 'Stories' });\n    const selectedStory = storiesNavigation.locator(\n      '[data-item-id=\"example-button--primary\"][data-selected=\"true\"]'\n    );\n\n    await expect(storiesNavigation).toBeVisible();\n    await expect(selectedStory).toBeVisible();\n    await sbPage.waitUntilLoaded();\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/tags.spec.ts",
    "content": "import { expect, test } from '@playwright/test';\n\nimport { SbPage, isReactSandbox } from './util.ts';\n\nconst storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';\nconst templateName = process.env.STORYBOOK_TEMPLATE_NAME || '';\n\ntest.describe('tags', () => {\n  test.beforeEach(async ({ page }) => {\n    await page.goto(storybookUrl);\n    await new SbPage(page, expect).waitUntilLoaded();\n  });\n\n  test('should correctly add dev, autodocs, test stories', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n\n    await sbPage.navigateToStory('core/tags-add', 'docs');\n\n    // Sidebar should include dev and exclude inheritance, autodocs, test\n    await expect(page.locator('#core-tags-add--dev')).toHaveCount(1);\n    await expect(page.locator('#core-tags-add--autodocs')).toHaveCount(0);\n    await expect(page.locator('#core-tags-add--test')).toHaveCount(0);\n\n    // Autodocs should include autodocs and exclude dev, test\n    const preview = sbPage.previewRoot();\n\n    await expect(preview.locator('#anchor--core-tags-add--dev')).toHaveCount(0);\n    // FIXME: shows as primary story and also in stories, inconsistent btw dev/CI?\n    await expect(preview.locator('#anchor--core-tags-add--autodocs')).not.toHaveCount(0);\n    await expect(preview.locator('#anchor--core-tags-add--test')).toHaveCount(0);\n  });\n\n  test('should correctly remove dev, autodocs, test stories', async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n\n    await sbPage.navigateToStory('core/tags-remove', 'docs');\n\n    // Sidebar should include inheritance, no-autodocs, no-test. and exclude no-dev\n    await expect(page.locator('#core-tags-remove--no-dev')).toHaveCount(0);\n    await expect(page.locator('#core-tags-remove--no-autodocs')).toHaveCount(1);\n    await expect(page.locator('#core-tags-remove--no-test')).toHaveCount(1);\n\n    // Autodocs should include autodocs and exclude dev, test\n    const preview = sbPage.previewRoot();\n\n    await expect(preview.locator('#anchor--core-tags-remove--no-dev')).toHaveCount(1);\n    await expect(preview.locator('#anchor--core-tags-remove--no-autodocs')).toHaveCount(0);\n    await expect(preview.locator('#anchor--core-tags-remove--no-test')).toHaveCount(1);\n  });\n\n  test.describe('Tag filters tooltip', () => {\n    test('filters stories via Tag filters tooltip (desktop)', async ({ page }) => {\n      const sbPage = new SbPage(page, expect);\n\n      // Open Tag filters tooltip\n      const tooltip = await sbPage.openTagsFilter();\n\n      // No checkbox selected by default and \"Select all tags\" is shown\n      await expect(tooltip.locator('#select-all')).toBeVisible();\n      await expect(tooltip.locator('input[type=\"checkbox\"]:checked')).toHaveCount(0);\n\n      // When selecting dev-only, there should be only one story in the sidebar\n      await sbPage.toggleTagFilter('dev-only');\n      const stories = page.locator('#storybook-explorer-menu .sidebar-item');\n      await expect(stories).toHaveCount(1);\n    });\n\n    test('filters stories via Tag filter types', async ({ page }) => {\n      test.skip(\n        !isReactSandbox(templateName),\n        'Test filtering is currently only supported in React renderer'\n      );\n\n      const sbPage = new SbPage(page, expect);\n\n      // Open Tag filters tooltip\n      const tooltip = await sbPage.openTagsFilter();\n\n      // No checkbox selected by default and \"Select all tags\" is shown\n      await expect(tooltip.locator('#select-all')).toBeVisible();\n      await expect(tooltip.locator('input[type=\"checkbox\"]:checked')).toHaveCount(0);\n\n      // When selecting type docs, there should be no stories in the sidebar\n      await sbPage.toggleStoryTypeFilter('Documentation');\n      await sbPage.closeAnyPendingModal();\n      await sbPage.expandAllSidebarNodes();\n      await expect(\n        page.locator('#storybook-explorer-menu .sidebar-item[data-nodetype=\"story\"]')\n      ).toHaveCount(0);\n\n      await sbPage.clearTagsFilter();\n\n      // When excluding type docs, there should be no stories in the sidebar\n      await sbPage.toggleStoryTypeFilter('Documentation', true);\n      await sbPage.closeAnyPendingModal();\n      await expect(\n        page.locator('#storybook-explorer-menu .sidebar-item[data-nodetype=\"document\"]')\n      ).toHaveCount(0);\n\n      // Clear selection\n      await sbPage.clearTagsFilter();\n\n      // When selecting type play, there should be no docs in the sidebar\n      await sbPage.toggleStoryTypeFilter('Play');\n      await sbPage.closeAnyPendingModal();\n      await sbPage.expandAllSidebarNodes();\n      await expect(\n        page.locator('#storybook-explorer-menu .sidebar-item[data-nodetype=\"document\"]')\n      ).toHaveCount(0);\n\n      await sbPage.clearTagsFilter();\n\n      // When selecting type test, there should be tests visible in the sidebar\n      await sbPage.toggleStoryTypeFilter('Testing');\n      await sbPage.closeAnyPendingModal();\n      await sbPage.expandAllSidebarNodes();\n      const testItems = page.locator(\n        '#storybook-explorer-menu .sidebar-item[data-nodetype=\"test\"]'\n      );\n      await expect(testItems.count()).resolves.toBeGreaterThan(0);\n\n      await sbPage.clearTagsFilter();\n\n      // When excluding type test, there should be no tests visible in the sidebar\n      await sbPage.toggleStoryTypeFilter('Testing', true);\n      await sbPage.closeAnyPendingModal();\n      await expect(\n        page.locator('#storybook-explorer-menu .sidebar-item[data-nodetype=\"test\"]')\n      ).toHaveCount(0);\n\n      await sbPage.clearTagsFilter();\n    });\n\n    test.describe('mobile viewport', () => {\n      test.use({ viewport: { width: 390, height: 844 } });\n\n      test('filters stories via Tag filters tooltip (mobile)', async ({ page }) => {\n        // Open mobile navigation menu to ensure the tooltip is portaled inside it\n        const mobileNavigationHeading = page.locator('[aria-label=\"Open navigation menu\"]');\n        await mobileNavigationHeading.click();\n        await expect(page.locator('#storybook-explorer-menu')).toBeVisible();\n\n        // Open Tag filters tooltip\n        await page.locator('[aria-label=\"Tag filters\"]').click();\n        const tagFilterPopover = page.getByRole('dialog', { name: 'Tag filters' });\n        await expect(tagFilterPopover).toBeVisible();\n\n        // No checkbox selected by default and \"Select all tags\" is shown\n        await expect(tagFilterPopover.locator('#select-all')).toBeVisible();\n        await expect(tagFilterPopover.locator('input[type=\"checkbox\"]:checked')).toHaveCount(0);\n\n        // Select the dev-only tag\n        await page.getByText('dev-only', { exact: true }).click();\n\n        // Assert that only one story is visible in the (mobile) sidebar\n        const stories = page.locator('#storybook-explorer-menu .sidebar-item');\n        await expect(stories).toHaveCount(1);\n\n        // Clear selection\n        await expect(page.locator('#deselect-all')).toBeVisible();\n        await page.locator('#deselect-all').click();\n\n        // Checkboxes are not selected anymore\n        await expect(page.locator('input[type=\"checkbox\"]:checked')).toHaveCount(0);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/e2e-tests/util.ts",
    "content": "/* eslint-disable local-rules/no-uncategorized-errors */\nimport { toId } from 'storybook/internal/csf';\n\nimport type { Expect, Page } from '@playwright/test';\n\nimport { allTemplates } from '../lib/cli-storybook/src/sandbox-templates.ts';\n\nexport class SbPage {\n  readonly page: Page;\n\n  readonly expect: Expect;\n\n  constructor(page: Page, expect: Expect) {\n    this.page = page;\n    this.expect = expect;\n  }\n\n  async openComponent(title: string, hasRoot = true) {\n    const parts = title.split('/');\n    for (let i = hasRoot ? 1 : 0; i < parts.length; i += 1) {\n      const parentId = toId(parts.slice(0, i + 1).join('/'));\n\n      const parentLink = this.page.locator(`#${parentId}`);\n\n      await this.expect(parentLink).toBeVisible();\n      if ((await parentLink.getAttribute('aria-expanded')) === 'false') {\n        await parentLink.click();\n      }\n    }\n  }\n\n  /** Visit a story via the URL instead of selecting from the sidebar. */\n  async deepLinkToStory(baseURL: string, title: string, name: 'docs' | string, testName?: string) {\n    const titleId = toId(title);\n    const storyId = toId(name);\n    const storyLinkId = testName ? `${titleId}--${storyId}:${testName}` : `${titleId}--${storyId}`;\n    const viewMode = name === 'docs' ? 'docs' : 'story';\n    await this.page.goto(`${baseURL}/?path=/${viewMode}/${storyLinkId}`);\n\n    await this.page.waitForURL((url) => url.search.includes(`path=/${viewMode}/${storyLinkId}`));\n    await this.previewRoot();\n  }\n\n  /** Visit a story by selecting it from the sidebar. */\n  async navigateToStory(\n    title: string,\n    name: string,\n    viewMode?: 'docs' | 'story',\n    skipWaitUntilLoaded = false\n  ) {\n    await this.openComponent(title);\n\n    const titleId = toId(title);\n    const storyId = toId(name);\n    const storyLinkId = `#${titleId}--${storyId}`;\n    await this.page.locator(storyLinkId).waitFor();\n    const storyLink = this.page.locator('*', { has: this.page.locator(`> ${storyLinkId}`) });\n    await storyLink.click();\n\n    await this.page.waitForURL((url) =>\n      url.search.includes(\n        `path=/${viewMode ?? (name === 'docs' ? 'docs' : 'story')}/${titleId}--${storyId}`\n      )\n    );\n\n    const selected = storyLink;\n    await this.expect(selected).toHaveAttribute('data-selected', 'true');\n\n    await this.previewRoot();\n\n    if (!skipWaitUntilLoaded) {\n      await this.waitUntilLoaded();\n    }\n  }\n\n  async navigateToUnattachedDocs(title: string, name = 'docs') {\n    await this.openComponent(title);\n\n    const titleId = toId(title);\n    const storyId = toId(name);\n    const storyLinkId = `#${titleId}-${storyId}--docs`;\n    await this.page.locator(storyLinkId).waitFor();\n    const storyLink = this.page.locator('*', { has: this.page.locator(`> ${storyLinkId}`) });\n    await storyLink.click();\n\n    await this.page.waitForURL((url) =>\n      url.search.includes(`path=/docs/${titleId}-${storyId}--docs`)\n    );\n\n    const selected = storyLink;\n    await this.expect(selected).toHaveAttribute('data-selected', 'true');\n\n    await this.waitForStoryLoaded();\n  }\n\n  async waitForStoryLoaded() {\n    try {\n      // wait for the story to be visited\n      await this.page.waitForURL((url) => url.search.includes(`path`));\n\n      const root = this.previewRoot();\n      // Wait until there is at least one child (a story element) in the preview iframe\n      await root.locator(':scope > *').first().waitFor({\n        state: 'attached',\n        timeout: 10000,\n      });\n    } catch (error: any) {\n      if (error.name === 'TimeoutError') {\n        throw new Error(\n          'The Storybook iframe did not have children within the specified timeout. Did the story load correctly?'\n        );\n      }\n      throw error;\n    }\n  }\n\n  async waitUntilLoaded() {\n    // make sure we start every test with clean state – to avoid possible flakiness\n    await this.page.context().addInitScript(() => {\n      const storeState = {\n        layout: {\n          showToolbar: true,\n          navSize: 300,\n          bottomPanelHeight: 300,\n          rightPanelWidth: 300,\n        },\n      };\n      window.sessionStorage.setItem('@storybook/manager/store', JSON.stringify(storeState));\n    }, {});\n\n    // disable all transitions to avoid flakiness\n    await this.page.addStyleTag({\n      content: `\n            *,\n            *::before,\n            *::after {\n              transition: none !important;\n            }\n          `,\n    });\n    const root = this.previewRoot();\n    const docsLoadingPage = root.locator('.sb-preparing-docs');\n    const storyLoadingPage = root.locator('.sb-preparing-story');\n    await docsLoadingPage.waitFor({ state: 'hidden' });\n    await storyLoadingPage.waitFor({ state: 'hidden' });\n\n    await this.waitForStoryLoaded();\n  }\n\n  /**\n   * We have stories with modals set to auto-open (e.g. startOpen color control). This helper closes\n   * them to free scroll and keyboard focus traps.\n   */\n  async closeAnyPendingModal() {\n    const popover = this.page.locator('[role=\"dialog\"]');\n    if (await popover.isVisible()) {\n      await this.page.keyboard.press('Escape');\n      await this.page.keyboard.press('Escape');\n      await popover.waitFor({ state: 'hidden', timeout: 1000 });\n    }\n  }\n\n  previewIframe() {\n    return this.page.frameLocator('#storybook-preview-iframe');\n  }\n\n  previewRoot() {\n    const preview = this.previewIframe();\n    return preview.locator('#storybook-root:visible, #storybook-docs:visible');\n  }\n\n  panelContent() {\n    return this.page.locator('#storybook-panel-root').getByRole('tabpanel');\n  }\n\n  async viewAddonPanel(name: string) {\n    const tabs = this.page.locator('[role=tablist] div[role=tab]');\n    const tab = tabs.locator(`text=/^${name}/`);\n    await tab.click();\n  }\n\n  async selectToolbar(toolbarSelector: string, itemSelector?: string) {\n    await this.page.locator(toolbarSelector).click();\n    if (itemSelector) {\n      await this.page.locator(itemSelector).click();\n    }\n  }\n\n  async expandAllSidebarNodes() {\n    await this.page.keyboard.press(\n      `${process.platform === 'darwin' ? 'Meta' : 'Control'}+Shift+ArrowDown`\n    );\n  }\n\n  async openTagsFilter() {\n    const tagFiltersButton = this.page\n      .locator('[aria-label*=\"active tag filter\"]')\n      .or(this.page.locator('[aria-label=\"Tag filters\"]'));\n    // FIXME: we might want to strengthen this locator with an aria-label or testid on the dialog.\n    const tooltip = this.page.locator('[role=\"dialog\"]');\n    const isTooltipVisible = await tooltip.isVisible();\n\n    if (!isTooltipVisible) {\n      await tagFiltersButton.click();\n      await this.expect(tooltip).toBeVisible();\n    }\n\n    return tooltip;\n  }\n\n  async clearTagsFilter() {\n    const tooltip = await this.openTagsFilter();\n    await this.expect(tooltip.locator('#deselect-all')).toBeVisible();\n    await tooltip.locator('#deselect-all').click();\n    return tooltip;\n  }\n\n  async toggleTagFilter(tag: string, toggleExclusion?: boolean) {\n    await this.openTagsFilter();\n\n    if (toggleExclusion) {\n      await this.page\n        .getByRole('listitem')\n        .filter({ has: this.page.getByLabel(new RegExp(`tag filter: ${tag}`)) })\n        .hover();\n      await this.page.getByLabel(new RegExp(`(Exclude|Include) tag: ${tag}`)).click();\n    } else {\n      await this.page.getByLabel(new RegExp(`tag filter: ${tag}`)).click();\n    }\n  }\n\n  async toggleStoryTypeFilter(\n    type: 'Documentation' | 'Play' | 'Testing',\n    toggleExclusion?: boolean\n  ) {\n    await this.openTagsFilter();\n\n    if (toggleExclusion) {\n      await this.page\n        .getByRole('listitem')\n        .filter({ has: this.page.getByLabel(new RegExp(`built-in filter: ${type}`)) })\n        .hover();\n      await this.page.getByLabel(new RegExp(`(Exclude|Include) built-in: ${type}`, 'i')).click();\n    } else {\n      await this.page.getByLabel(new RegExp(`built-in filter: ${type}`)).click();\n    }\n  }\n\n  getCanvasBodyElement() {\n    return this.previewIframe().locator('body');\n  }\n\n  // utility to try and decrease flake\n  async retryTimes(\n    fn: () => Promise<void>,\n    options?: {\n      retries?: number;\n      delay?: number;\n    }\n  ): Promise<void> {\n    let attempts = 0;\n    const { retries = 3, delay = 0 } = options || {};\n    while (attempts < retries) {\n      try {\n        await fn();\n        return;\n      } catch (error) {\n        attempts++;\n        if (attempts === retries) {\n          throw error;\n        }\n        await new Promise<void>((resolve) => setTimeout(resolve, delay));\n      }\n    }\n  }\n}\n\nconst templateName: keyof typeof allTemplates = process.env.STORYBOOK_TEMPLATE_NAME || ('' as any);\n\nconst templates = allTemplates;\n\nexport const isReactSandbox = (templateName: string) =>\n  templates[templateName as keyof typeof templates]?.expected.renderer === '@storybook/react';\n\nexport const hasVitestIntegration =\n  !templates[templateName]?.skipTasks?.includes('vitest-integration');\n\nexport const checkTemplate = (\n  templateName: string,\n  predicate: (template: (typeof templates)[keyof typeof templates]) => boolean\n) => {\n  return (\n    templates[templateName as keyof typeof templates] &&\n    predicate(templates[templateName as keyof typeof templates])\n  );\n};\n\nexport const hasOnboardingFeature = (templateName: string) =>\n  ['@storybook/react', '@storybook/vue3', '@storybook/angular'].includes(\n    templates[templateName as keyof typeof templates]?.expected.renderer\n  );\n"
  },
  {
    "path": "code/frameworks/angular/README.md",
    "content": "# Storybook for Angular\n\nSee [documentation](https://storybook.js.org/docs/get-started/frameworks/angular?renderer=angular&ref=readme) for installation instructions, usage examples, APIs, and more.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/frameworks/angular/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./client'],\n        entryPoint: './src/client/index.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./client/config'],\n        entryPoint: './src/client/config.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./client/preview-prod'],\n        entryPoint: './src/client/preview-prod.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./client/docs/config'],\n        entryPoint: './src/client/docs/config.ts',\n        dts: false,\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./node'],\n        entryPoint: './src/node/index.ts',\n      },\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./server/framework-preset-angular-ivy'],\n        entryPoint: './src/server/framework-preset-angular-ivy.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./server/framework-preset-angular-cli'],\n        entryPoint: './src/server/framework-preset-angular-cli.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./builders/start-storybook'],\n        entryPoint: './src/builders/start-storybook/index.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./builders/build-storybook'],\n        entryPoint: './src/builders/build-storybook/index.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/frameworks/angular/build-schema.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/schema\",\n  \"title\": \"Build Storybook\",\n  \"description\": \"Serve up storybook in development mode.\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"browserTarget\": {\n      \"type\": \"string\",\n      \"description\": \"Build target to be served in project-name:builder:config format. Should generally target on the builder: '@angular-devkit/build-angular:browser'. Useful for Storybook to use options (styles, assets, ...).\",\n      \"pattern\": \"^[^:\\\\s]+:[^:\\\\s]+(:[^\\\\s]+)?$\",\n      \"default\": null\n    },\n    \"tsConfig\": {\n      \"type\": \"string\",\n      \"description\": \"The full path for the TypeScript configuration file, relative to the current workspace.\"\n    },\n    \"outputDir\": {\n      \"type\": \"string\",\n      \"description\": \"Directory where to store built files.\",\n      \"default\": \"storybook-static\"\n    },\n    \"preserveSymlinks\": {\n      \"type\": \"boolean\",\n      \"description\": \"Do not use the real path when resolving modules. If true, symlinks are resolved to their real path, if false, symlinks are resolved to their symlinked path.\",\n      \"default\": false\n    },\n    \"configDir\": {\n      \"type\": \"string\",\n      \"description\": \"Directory where to load Storybook configurations from.\",\n      \"default\": \".storybook\"\n    },\n    \"loglevel\": {\n      \"type\": \"string\",\n      \"description\": \"Controls level of logging during build. Can be one of: [trace, debug, info (default), warn, error, silent].\",\n      \"pattern\": \"(trace|debug|info|warn|error|silent)\"\n    },\n    \"logfile\": {\n      \"type\": \"string\",\n      \"description\": \"If provided, the log output will be written to the specified file path.\"\n    },\n    \"debugWebpack\": {\n      \"type\": \"boolean\",\n      \"description\": \"Debug the Webpack configuration\",\n      \"default\": false\n    },\n    \"enableProdMode\": {\n      \"type\": \"boolean\",\n      \"description\": \"Disable Angular's development mode, which turns off assertions and other checks within the framework.\",\n      \"default\": true\n    },\n    \"quiet\": {\n      \"type\": \"boolean\",\n      \"description\": \"Suppress verbose build output.\",\n      \"default\": false\n    },\n    \"docs\": {\n      \"type\": \"boolean\",\n      \"description\": \"Starts Storybook in documentation mode. Learn more about it : https://storybook.js.org/docs/writing-docs/build-documentation#preview-storybooks-documentation.\",\n      \"default\": false\n    },\n    \"test\": {\n      \"type\": \"boolean\",\n      \"description\": \"Build the static version of the sandbox optimized for testing purposes\",\n      \"default\": false\n    },\n    \"compodoc\": {\n      \"type\": \"boolean\",\n      \"description\": \"Execute compodoc before.\",\n      \"default\": true\n    },\n    \"compodocArgs\": {\n      \"type\": \"array\",\n      \"description\": \"Compodoc options : https://compodoc.app/guides/options.html. Options `-p` with tsconfig path and `-d` with workspace root is always given.\",\n      \"default\": [\"-e\", \"json\"],\n      \"items\": {\n        \"type\": \"string\"\n      }\n    },\n    \"webpackStatsJson\": {\n      \"type\": [\"boolean\", \"string\"],\n      \"description\": \"Write Webpack Stats JSON to disk\",\n      \"default\": false\n    },\n    \"statsJson\": {\n      \"type\": [\"boolean\", \"string\"],\n      \"description\": \"Write stats JSON to disk\",\n      \"default\": false\n    },\n    \"previewUrl\": {\n      \"type\": \"string\",\n      \"description\": \"Disables the default storybook preview and lets you use your own\"\n    },\n    \"styles\": {\n      \"type\": \"array\",\n      \"description\": \"Global styles to be included in the build.\",\n      \"items\": {\n        \"$ref\": \"#/definitions/styleElement\"\n      }\n    },\n    \"stylePreprocessorOptions\": {\n      \"description\": \"Options to pass to style preprocessors.\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"includePaths\": {\n          \"description\": \"Paths to include. Paths will be resolved to workspace root.\",\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        }\n      },\n      \"additionalProperties\": false\n    },\n    \"assets\": {\n      \"type\": \"array\",\n      \"description\": \"List of static application assets.\",\n      \"default\": [],\n      \"items\": {\n        \"$ref\": \"#/definitions/assetPattern\"\n      }\n    },\n    \"sourceMap\": {\n      \"type\": [\"boolean\", \"object\"],\n      \"description\": \"Configure sourcemaps. See: https://angular.io/guide/workspace-config#source-map-configuration\",\n      \"default\": false\n    },\n    \"experimentalZoneless\": {\n      \"type\": \"boolean\",\n      \"description\": \"Experimental: Use zoneless change detection.\"\n    }\n  },\n  \"additionalProperties\": false,\n  \"definitions\": {\n    \"assetPattern\": {\n      \"oneOf\": [\n        {\n          \"type\": \"object\",\n          \"properties\": {\n            \"followSymlinks\": {\n              \"type\": \"boolean\",\n              \"default\": false,\n              \"description\": \"Allow glob patterns to follow symlink directories. This allows subdirectories of the symlink to be searched.\"\n            },\n            \"glob\": {\n              \"type\": \"string\",\n              \"description\": \"The pattern to match.\"\n            },\n            \"input\": {\n              \"type\": \"string\",\n              \"description\": \"The input directory path in which to apply 'glob'. Defaults to the project root.\"\n            },\n            \"ignore\": {\n              \"description\": \"An array of globs to ignore.\",\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            },\n            \"output\": {\n              \"type\": \"string\",\n              \"description\": \"Absolute path within the output.\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"required\": [\"glob\", \"input\", \"output\"]\n        },\n        {\n          \"type\": \"string\"\n        }\n      ]\n    },\n    \"styleElement\": {\n      \"oneOf\": [\n        {\n          \"type\": \"object\",\n          \"properties\": {\n            \"input\": {\n              \"type\": \"string\",\n              \"description\": \"The file to include.\"\n            },\n            \"bundleName\": {\n              \"type\": \"string\",\n              \"pattern\": \"^[\\\\w\\\\-.]*$\",\n              \"description\": \"The bundle name for this extra entry point.\"\n            },\n            \"inject\": {\n              \"type\": \"boolean\",\n              \"description\": \"If the bundle will be referenced in the HTML file.\",\n              \"default\": true\n            }\n          },\n          \"additionalProperties\": false,\n          \"required\": [\"input\"]\n        },\n        {\n          \"type\": \"string\",\n          \"description\": \"The file to include.\"\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/builders.json",
    "content": "{\n  \"builders\": {\n    \"build-storybook\": {\n      \"implementation\": \"./dist/builders/build-storybook/index.js\",\n      \"schema\": \"./build-schema.json\",\n      \"description\": \"Build storybook\"\n    },\n    \"start-storybook\": {\n      \"implementation\": \"./dist/builders/start-storybook/index.js\",\n      \"schema\": \"./start-schema.json\",\n      \"description\": \"Start storybook\"\n    }\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/package.json",
    "content": "{\n  \"name\": \"@storybook/angular\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook for Angular: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-framework\",\n    \"angular\",\n    \"component\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/frameworks/angular\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/frameworks/angular\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./builders/build-storybook\": \"./dist/builders/build-storybook/index.js\",\n    \"./builders/start-storybook\": \"./dist/builders/start-storybook/index.js\",\n    \"./client\": \"./dist/client/index.js\",\n    \"./client/config\": \"./dist/client/config.js\",\n    \"./client/docs/config\": \"./dist/client/docs/config.js\",\n    \"./client/preview-prod\": \"./dist/client/preview-prod.js\",\n    \"./node\": {\n      \"types\": \"./dist/node/index.d.ts\",\n      \"code\": \"./src/node/index.ts\",\n      \"default\": \"./dist/node/index.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\",\n    \"./server/framework-preset-angular-cli\": \"./dist/server/framework-preset-angular-cli.js\",\n    \"./server/framework-preset-angular-ivy\": \"./dist/server/framework-preset-angular-ivy.js\"\n  },\n  \"files\": [\n    \"builders.json\",\n    \"build-schema.json\",\n    \"start-schema.json\",\n    \"dist/**/*\",\n    \"template/cli/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.mjs\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/builder-webpack5\": \"workspace:*\",\n    \"@storybook/global\": \"^5.0.0\",\n    \"telejson\": \"8.0.0\",\n    \"ts-dedent\": \"^2.0.0\",\n    \"tsconfig-paths-webpack-plugin\": \"^4.0.1\",\n    \"webpack\": \"5\"\n  },\n  \"devDependencies\": {\n    \"@analogjs/vite-plugin-angular\": \"^1.12.1\",\n    \"@angular-devkit/architect\": \"^0.1901.1\",\n    \"@angular-devkit/build-angular\": \"^19.1.1\",\n    \"@angular-devkit/core\": \"^19.1.1\",\n    \"@angular/animations\": \"^19.1.1\",\n    \"@angular/common\": \"^19.1.1\",\n    \"@angular/compiler\": \"^19.1.1\",\n    \"@angular/compiler-cli\": \"^19.1.1\",\n    \"@angular/core\": \"^19.1.1\",\n    \"@angular/forms\": \"^19.1.1\",\n    \"@angular/platform-browser\": \"^19.1.1\",\n    \"@angular/platform-browser-dynamic\": \"^19.1.1\",\n    \"@storybook/core-webpack\": \"workspace:*\",\n    \"@types/node\": \"^22.19.1\",\n    \"empathic\": \"^2.0.0\",\n    \"rimraf\": \"^6.0.1\",\n    \"typescript\": \"^5.9.3\",\n    \"webpack\": \"5\",\n    \"zone.js\": \"^0.15.0\"\n  },\n  \"peerDependencies\": {\n    \"@angular-devkit/architect\": \">=0.1800.0 < 0.2200.0\",\n    \"@angular-devkit/build-angular\": \">=18.0.0 < 22.0.0\",\n    \"@angular-devkit/core\": \">=18.0.0 < 22.0.0\",\n    \"@angular/animations\": \">=18.0.0 < 22.0.0\",\n    \"@angular/cli\": \">=18.0.0 < 22.0.0\",\n    \"@angular/common\": \">=18.0.0 < 22.0.0\",\n    \"@angular/compiler\": \">=18.0.0 < 22.0.0\",\n    \"@angular/compiler-cli\": \">=18.0.0 < 22.0.0\",\n    \"@angular/core\": \">=18.0.0 < 22.0.0\",\n    \"@angular/platform-browser\": \">=18.0.0 < 22.0.0\",\n    \"@angular/platform-browser-dynamic\": \">=18.0.0 < 22.0.0\",\n    \"rxjs\": \"^6.5.3 || ^7.4.0\",\n    \"storybook\": \"workspace:^\",\n    \"typescript\": \"^4.9.0 || ^5.0.0\",\n    \"zone.js\": \">=0.14.0\"\n  },\n  \"peerDependenciesMeta\": {\n    \"@angular/animations\": {\n      \"optional\": true\n    },\n    \"@angular/cli\": {\n      \"optional\": true\n    },\n    \"zone.js\": {\n      \"optional\": true\n    }\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"builders\": \"builders.json\",\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/frameworks/angular/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/frameworks/angular/project.json",
    "content": "{\n  \"name\": \"angular\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/__tests__/button.css",
    "content": ""
  },
  {
    "path": "code/frameworks/angular/src/builders/build-storybook/index.spec.ts",
    "content": "import { Architect, createBuilder } from '@angular-devkit/architect';\nimport { TestingArchitectHost } from '@angular-devkit/architect/testing';\nimport { schema } from '@angular-devkit/core';\nimport * as path from 'node:path';\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nconst buildDevStandaloneMock = vi.fn();\nconst buildStaticStandaloneMock = vi.fn();\n\nconst buildMock = {\n  buildDevStandalone: buildDevStandaloneMock,\n  buildStaticStandalone: buildStaticStandaloneMock,\n  withTelemetry: (name: string, options: any, fn: any) => fn(),\n};\n\nvi.doMock('storybook/internal/core-server', () => buildMock);\nvi.doMock('storybook/internal/common', () => ({\n  JsPackageManagerFactory: {\n    getPackageManager: () => ({\n      runPackageCommand: mockRunScript,\n    }),\n  },\n  getEnvConfig: (options: any) => options,\n  versions: {\n    storybook: 'x.x.x',\n  },\n}));\nvi.doMock('empathic/find', () => ({ up: () => './storybook/tsconfig.ts' }));\n\nconst mockRunScript = vi.fn();\n\n// Randomly fails on CI. TODO: investigate why\ndescribe.skip('Build Storybook Builder', () => {\n  let architect: Architect;\n  let architectHost: TestingArchitectHost;\n\n  beforeEach(async () => {\n    const registry = new schema.CoreSchemaRegistry();\n    registry.addPostTransform(schema.transforms.addUndefinedDefaults);\n\n    architectHost = new TestingArchitectHost();\n    architect = new Architect(architectHost, registry);\n\n    architectHost.addBuilder(\n      '@angular-devkit/build-angular:browser',\n      createBuilder(() => {\n        return { success: true };\n      })\n    );\n    architectHost.addTarget(\n      { project: 'angular-cli', target: 'build-2' },\n      '@angular-devkit/build-angular:browser',\n      {\n        outputPath: 'dist/angular-cli',\n        index: 'src/index.html',\n        main: 'src/main.ts',\n        polyfills: 'src/polyfills.ts',\n        tsConfig: 'src/tsconfig.app.json',\n        assets: ['src/favicon.ico', 'src/assets'],\n        styles: ['src/styles.css'],\n        scripts: [],\n      }\n    );\n\n    // This will either take a Node package name, or a path to the directory\n    // for the package.json file.\n    await architectHost.addBuilderFromPackage(path.join(__dirname, '../../..'));\n  });\n\n  beforeEach(() => {\n    buildStaticStandaloneMock.mockImplementation((_options: unknown) => Promise.resolve(_options));\n  });\n\n  afterEach(() => {\n    vi.clearAllMocks();\n  });\n\n  it('should start storybook with angularBrowserTarget', async () => {\n    const run = await architect.scheduleBuilder('@storybook/angular:build-storybook', {\n      browserTarget: 'angular-cli:build-2',\n      compodoc: false,\n    });\n\n    const output = await run.result;\n\n    await run.stop();\n\n    expect(output.success).toBeTruthy();\n    expect(mockRunScript).not.toHaveBeenCalledWith();\n    expect(buildStaticStandaloneMock).toHaveBeenCalledWith(\n      expect.objectContaining({\n        angularBrowserTarget: 'angular-cli:build-2',\n        angularBuilderContext: expect.any(Object),\n        configDir: '.storybook',\n        loglevel: undefined,\n        quiet: false,\n        disableTelemetry: undefined,\n        outputDir: 'storybook-static',\n        packageJson: expect.any(Object),\n        mode: 'static',\n        tsConfig: './storybook/tsconfig.ts',\n        statsJson: false,\n      })\n    );\n  });\n\n  it('should start storybook with tsConfig', async () => {\n    const run = await architect.scheduleBuilder('@storybook/angular:build-storybook', {\n      tsConfig: 'path/to/tsConfig.json',\n      compodoc: false,\n    });\n\n    const output = await run.result;\n\n    await run.stop();\n\n    expect(output.success).toBeTruthy();\n    expect(mockRunScript).not.toHaveBeenCalledWith();\n    expect(buildStaticStandaloneMock).toHaveBeenCalledWith(\n      expect.objectContaining({\n        angularBrowserTarget: null,\n        angularBuilderContext: expect.any(Object),\n        configDir: '.storybook',\n        loglevel: undefined,\n        quiet: false,\n        disableTelemetry: undefined,\n        outputDir: 'storybook-static',\n        packageJson: expect.any(Object),\n        mode: 'static',\n        tsConfig: 'path/to/tsConfig.json',\n        statsJson: false,\n      })\n    );\n  });\n\n  it('should build storybook with webpack stats.json', async () => {\n    const run = await architect.scheduleBuilder('@storybook/angular:build-storybook', {\n      tsConfig: 'path/to/tsConfig.json',\n      compodoc: false,\n      statsJson: true,\n    });\n\n    const output = await run.result;\n\n    await run.stop();\n\n    expect(output.success).toBeTruthy();\n    expect(mockRunScript).not.toHaveBeenCalledWith();\n    expect(buildStaticStandaloneMock).toHaveBeenCalledWith(\n      expect.objectContaining({\n        angularBrowserTarget: null,\n        angularBuilderContext: expect.any(Object),\n        configDir: '.storybook',\n        loglevel: undefined,\n        quiet: false,\n        outputDir: 'storybook-static',\n        packageJson: expect.any(Object),\n        mode: 'static',\n        tsConfig: 'path/to/tsConfig.json',\n        statsJson: true,\n      })\n    );\n  });\n\n  it('should throw error', async () => {\n    buildStaticStandaloneMock.mockRejectedValue(true);\n\n    const run = await architect.scheduleBuilder('@storybook/angular:build-storybook', {\n      browserTarget: 'angular-cli:build-2',\n      compodoc: false,\n    });\n\n    try {\n      await run.result;\n\n      expect(false).toEqual('Throw expected');\n    } catch (error) {\n      expect(error).toEqual(\n        'Broken build, fix the error above.\\nYou may need to refresh the browser.'\n      );\n    }\n  });\n\n  it('should run compodoc', async () => {\n    const run = await architect.scheduleBuilder('@storybook/angular:build-storybook', {\n      browserTarget: 'angular-cli:build-2',\n    });\n\n    const output = await run.result;\n\n    await run.stop();\n\n    expect(output.success).toBeTruthy();\n    expect(mockRunScript).toHaveBeenCalledWith(\n      'compodoc',\n      ['-p', './storybook/tsconfig.ts', '-d', '.', '-e', 'json'],\n      ''\n    );\n    expect(buildStaticStandaloneMock).toHaveBeenCalledWith(\n      expect.objectContaining({\n        angularBrowserTarget: 'angular-cli:build-2',\n        angularBuilderContext: expect.any(Object),\n        configDir: '.storybook',\n        loglevel: undefined,\n        quiet: false,\n        outputDir: 'storybook-static',\n        packageJson: expect.any(Object),\n        mode: 'static',\n        tsConfig: './storybook/tsconfig.ts',\n        statsJson: false,\n      })\n    );\n  });\n\n  it('should start storybook with styles options', async () => {\n    const run = await architect.scheduleBuilder('@storybook/angular:build-storybook', {\n      tsConfig: 'path/to/tsConfig.json',\n      compodoc: false,\n      styles: ['style.scss'],\n    });\n\n    const output = await run.result;\n\n    await run.stop();\n\n    expect(output.success).toBeTruthy();\n    expect(mockRunScript).not.toHaveBeenCalledWith();\n    expect(buildStaticStandaloneMock).toHaveBeenCalledWith(\n      expect.objectContaining({\n        angularBrowserTarget: null,\n        angularBuilderContext: expect.any(Object),\n        angularBuilderOptions: { assets: [], styles: ['style.scss'] },\n        configDir: '.storybook',\n        loglevel: undefined,\n        quiet: false,\n        outputDir: 'storybook-static',\n        packageJson: expect.any(Object),\n        mode: 'static',\n        tsConfig: 'path/to/tsConfig.json',\n        statsJson: false,\n      })\n    );\n  });\n});\n"
  },
  {
    "path": "code/frameworks/angular/src/builders/build-storybook/index.ts",
    "content": "import { readFileSync } from 'node:fs';\n\nimport { getEnvConfig, getProjectRoot, versions } from 'storybook/internal/common';\nimport { buildStaticStandalone, withTelemetry } from 'storybook/internal/core-server';\nimport { addToGlobalContext } from 'storybook/internal/telemetry';\nimport type { CLIOptions } from 'storybook/internal/types';\nimport { logger, logTracker } from 'storybook/internal/node-logger';\n\nimport type {\n  BuilderContext,\n  BuilderHandlerFn,\n  BuilderOutput,\n  Target,\n  Builder as DevkitBuilder,\n} from '@angular-devkit/architect';\nimport { createBuilder, targetFromTargetString } from '@angular-devkit/architect';\nimport type {\n  BrowserBuilderOptions,\n  StylePreprocessorOptions,\n} from '@angular-devkit/build-angular';\nimport type {\n  AssetPattern,\n  SourceMapUnion,\n  StyleElement,\n} from '@angular-devkit/build-angular/src/builders/browser/schema';\nimport type { JsonObject } from '@angular-devkit/core';\nimport * as find from 'empathic/find';\nimport * as pkg from 'empathic/package';\n\nimport { errorSummary, printErrorDetails } from '../utils/error-handler.ts';\nimport { runCompodoc } from '../utils/run-compodoc.ts';\nimport type { StandaloneOptions } from '../utils/standalone-options.ts';\nimport { VERSION } from '@angular/core';\nimport { Channel } from 'storybook/internal/channels';\n\naddToGlobalContext('cliVersion', versions.storybook);\n\nexport type StorybookBuilderOptions = JsonObject & {\n  browserTarget?: string | null;\n  tsConfig?: string;\n  test: boolean;\n  docs: boolean;\n  compodoc: boolean;\n  compodocArgs: string[];\n  enableProdMode?: boolean;\n  styles?: StyleElement[];\n  stylePreprocessorOptions?: StylePreprocessorOptions;\n  preserveSymlinks?: boolean;\n  assets?: AssetPattern[];\n  sourceMap?: SourceMapUnion;\n  experimentalZoneless?: boolean;\n} & Pick<\n    // makes sure the option exists\n    CLIOptions,\n    | 'outputDir'\n    | 'configDir'\n    | 'loglevel'\n    | 'quiet'\n    | 'test'\n    | 'webpackStatsJson'\n    | 'statsJson'\n    | 'disableTelemetry'\n    | 'debugWebpack'\n    | 'logfile'\n    | 'previewUrl'\n  >;\n\nexport type StorybookBuilderOutput = JsonObject & BuilderOutput & { [key: string]: any };\n\ntype StandaloneBuildOptions = StandaloneOptions & { outputDir: string };\n\nconst commandBuilder: BuilderHandlerFn<StorybookBuilderOptions> = async (\n  options,\n  context\n): Promise<BuilderOutput> => {\n  // Apply logger configuration from builder options\n  if (options.loglevel) {\n    logger.setLogLevel(options.loglevel);\n  }\n  if (options.logfile) {\n    logTracker.enableLogWriting();\n  }\n\n  logger.intro('Building Storybook');\n\n  const { tsConfig } = await setup(options, context);\n\n  const docTSConfig = find.up('tsconfig.doc.json', {\n    cwd: options.configDir,\n    last: getProjectRoot(),\n  });\n\n  if (options.compodoc) {\n    await runCompodoc(\n      { compodocArgs: options.compodocArgs, tsconfig: docTSConfig ?? tsConfig },\n      context\n    );\n  }\n\n  getEnvConfig(options, {\n    staticDir: 'SBCONFIG_STATIC_DIR',\n    outputDir: 'SBCONFIG_OUTPUT_DIR',\n    configDir: 'SBCONFIG_CONFIG_DIR',\n  });\n\n  const {\n    browserTarget,\n    stylePreprocessorOptions,\n    styles,\n    configDir,\n    docs,\n    loglevel,\n    test,\n    outputDir,\n    quiet,\n    enableProdMode = true,\n    webpackStatsJson,\n    statsJson,\n    debugWebpack,\n    disableTelemetry,\n    assets,\n    previewUrl,\n    sourceMap = false,\n    preserveSymlinks = false,\n    experimentalZoneless = !!(VERSION.major && Number(VERSION.major) >= 21),\n  } = options;\n\n  const packageJsonPath = pkg.up({ cwd: __dirname });\n  const packageJson =\n    packageJsonPath != null ? JSON.parse(readFileSync(packageJsonPath, 'utf8')) : null;\n\n  const standaloneOptions: StandaloneBuildOptions = {\n    packageJson,\n    configDir,\n    ...(docs ? { docs } : {}),\n    loglevel,\n    outputDir,\n    test,\n    quiet,\n    enableProdMode,\n    disableTelemetry,\n    angularBrowserTarget: browserTarget,\n    angularBuilderContext: context,\n    angularBuilderOptions: {\n      ...(stylePreprocessorOptions ? { stylePreprocessorOptions } : {}),\n      ...(styles ? { styles } : {}),\n      ...(assets ? { assets } : {}),\n      sourceMap,\n      preserveSymlinks,\n      experimentalZoneless,\n    },\n    tsConfig,\n    webpackStatsJson,\n    statsJson,\n    debugWebpack,\n    previewUrl,\n  };\n\n  await runInstance({ ...standaloneOptions, mode: 'static' });\n  if (logTracker.shouldWriteLogsToFile) {\n    const logFile = await logTracker.writeToFile(options.logfile as any);\n    logger.info(`Debug logs are written to: ${logFile}`);\n  }\n  logger.outro('Storybook build completed successfully');\n  return { success: true } as BuilderOutput;\n};\n\nexport default createBuilder(commandBuilder) as DevkitBuilder<StorybookBuilderOptions & JsonObject>;\n\nasync function setup(options: StorybookBuilderOptions, context: BuilderContext) {\n  let browserOptions: (JsonObject & BrowserBuilderOptions) | undefined;\n  let browserTarget: Target | undefined;\n\n  if (options.browserTarget) {\n    browserTarget = targetFromTargetString(options.browserTarget);\n    browserOptions = await context.validateOptions<JsonObject & BrowserBuilderOptions>(\n      await context.getTargetOptions(browserTarget),\n      await context.getBuilderNameForTarget(browserTarget)\n    );\n  }\n\n  return {\n    tsConfig:\n      options.tsConfig ??\n      find.up('tsconfig.json', { cwd: options.configDir, last: getProjectRoot() }) ??\n      browserOptions.tsConfig,\n  };\n}\n\nasync function runInstance(options: StandaloneBuildOptions) {\n  try {\n    await withTelemetry(\n      'build',\n      {\n        cliOptions: options,\n        presetOptions: {\n          ...options,\n          corePresets: [],\n          overridePresets: [],\n          channel: new Channel({}),\n        },\n        printError: printErrorDetails,\n      },\n      async () => {\n        const result = await buildStaticStandalone(options);\n        return result;\n      }\n    );\n  } catch (error) {\n    const summary = errorSummary(error);\n    throw new Error(summary);\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/builders/start-storybook/index.spec.ts",
    "content": "import { Architect, createBuilder } from '@angular-devkit/architect';\nimport { TestingArchitectHost } from '@angular-devkit/architect/testing';\nimport { schema } from '@angular-devkit/core';\nimport { join } from 'node:path';\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nconst buildDevStandaloneMock = vi.fn();\nconst buildStaticStandaloneMock = vi.fn();\nconst buildMock = {\n  buildDevStandalone: buildDevStandaloneMock,\n  buildStaticStandalone: buildStaticStandaloneMock,\n  withTelemetry: (_: string, __: any, fn: any) => fn(),\n};\nvi.doMock('storybook/internal/core-server', () => buildMock);\nvi.doMock('empathic/find', () => ({ up: () => './storybook/tsconfig.ts' }));\n\nconst mockRunScript = vi.fn();\n\nvi.mock('storybook/internal/common', () => ({\n  getEnvConfig: (options: any) => options,\n  versions: {\n    storybook: 'x.x.x',\n  },\n  JsPackageManagerFactory: {\n    getPackageManager: () => ({\n      runPackageCommand: mockRunScript,\n    }),\n  },\n}));\n\n// Randomly fails on CI. TODO: investigate why\ndescribe.skip('Start Storybook Builder', () => {\n  let architect: Architect;\n  let architectHost: TestingArchitectHost;\n\n  beforeEach(async () => {\n    const registry = new schema.CoreSchemaRegistry();\n    registry.addPostTransform(schema.transforms.addUndefinedDefaults);\n\n    architectHost = new TestingArchitectHost();\n    architect = new Architect(architectHost, registry);\n\n    architectHost.addBuilder(\n      '@angular-devkit/build-angular:browser',\n      createBuilder(() => {\n        return { success: true };\n      })\n    );\n    architectHost.addTarget(\n      { project: 'angular-cli', target: 'build-2' },\n      '@angular-devkit/build-angular:browser',\n      {\n        outputPath: 'dist/angular-cli',\n        index: 'src/index.html',\n        main: 'src/main.ts',\n        polyfills: 'src/polyfills.ts',\n        tsConfig: 'src/tsconfig.app.json',\n        assets: ['src/favicon.ico', 'src/assets'],\n        styles: ['src/styles.css'],\n        scripts: [],\n      }\n    );\n    // This will either take a Node package name, or a path to the directory\n    // for the package.json file.\n    await architectHost.addBuilderFromPackage(join(__dirname, '../../..'));\n  });\n\n  beforeEach(() => {\n    buildDevStandaloneMock.mockImplementation((_options: unknown) => Promise.resolve(_options));\n  });\n\n  afterEach(() => {\n    vi.clearAllMocks();\n  });\n\n  it('should start storybook with angularBrowserTarget', async () => {\n    const run = await architect.scheduleBuilder('@storybook/angular:start-storybook', {\n      browserTarget: 'angular-cli:build-2',\n      port: 4400,\n      compodoc: false,\n    });\n\n    const output = await run.result;\n\n    await run.stop();\n\n    expect(output.success).toBeTruthy();\n    expect(mockRunScript).not.toHaveBeenCalledWith();\n    expect(buildDevStandaloneMock).toHaveBeenCalledWith(\n      expect.objectContaining({\n        angularBrowserTarget: 'angular-cli:build-2',\n        angularBuilderContext: expect.any(Object),\n        ci: false,\n        configDir: '.storybook',\n        disableTelemetry: undefined,\n        host: 'localhost',\n        https: false,\n        packageJson: expect.any(Object),\n        port: 4400,\n        quiet: false,\n        smokeTest: false,\n        sslCa: undefined,\n        sslCert: undefined,\n        sslKey: undefined,\n        tsConfig: './storybook/tsconfig.ts',\n      })\n    );\n  });\n\n  it('should start storybook with tsConfig', async () => {\n    const run = await architect.scheduleBuilder('@storybook/angular:start-storybook', {\n      tsConfig: 'path/to/tsConfig.json',\n      port: 4400,\n      compodoc: false,\n    });\n\n    const output = await run.result;\n\n    await run.stop();\n\n    expect(output.success).toBeTruthy();\n    expect(mockRunScript).not.toHaveBeenCalledWith();\n    expect(buildDevStandaloneMock).toHaveBeenCalledWith(\n      expect.objectContaining({\n        angularBrowserTarget: null,\n        angularBuilderContext: expect.any(Object),\n        ci: false,\n        configDir: '.storybook',\n        disableTelemetry: undefined,\n        host: 'localhost',\n        https: false,\n        packageJson: expect.any(Object),\n        port: 4400,\n        quiet: false,\n        smokeTest: false,\n        sslCa: undefined,\n        sslCert: undefined,\n        sslKey: undefined,\n        tsConfig: 'path/to/tsConfig.json',\n      })\n    );\n  });\n\n  it('should throw error', async () => {\n    buildDevStandaloneMock.mockRejectedValue(true);\n\n    const run = await architect.scheduleBuilder('@storybook/angular:start-storybook', {\n      browserTarget: 'angular-cli:build-2',\n      port: 4400,\n      compodoc: false,\n    });\n\n    try {\n      await run.result;\n\n      expect(false).toEqual('Throw expected');\n    } catch (error) {\n      expect(error).toEqual(\n        'Broken build, fix the error above.\\nYou may need to refresh the browser.'\n      );\n    }\n  });\n\n  it('should run compodoc', async () => {\n    const run = await architect.scheduleBuilder('@storybook/angular:start-storybook', {\n      browserTarget: 'angular-cli:build-2',\n    });\n\n    const output = await run.result;\n\n    await run.stop();\n\n    expect(output.success).toBeTruthy();\n    expect(mockRunScript).toHaveBeenCalledWith(\n      'compodoc',\n      ['-p', './storybook/tsconfig.ts', '-d', '.', '-e', 'json'],\n      ''\n    );\n    expect(buildDevStandaloneMock).toHaveBeenCalledWith(\n      expect.objectContaining({\n        angularBrowserTarget: 'angular-cli:build-2',\n        angularBuilderContext: expect.any(Object),\n        ci: false,\n        disableTelemetry: undefined,\n        configDir: '.storybook',\n        host: 'localhost',\n        https: false,\n        packageJson: expect.any(Object),\n        port: 9009,\n        quiet: false,\n        smokeTest: false,\n        sslCa: undefined,\n        sslCert: undefined,\n        sslKey: undefined,\n        tsConfig: './storybook/tsconfig.ts',\n      })\n    );\n  });\n\n  it('should start storybook with styles options', async () => {\n    const run = await architect.scheduleBuilder('@storybook/angular:start-storybook', {\n      tsConfig: 'path/to/tsConfig.json',\n      port: 4400,\n      compodoc: false,\n      styles: ['src/styles.css'],\n    });\n\n    const output = await run.result;\n\n    await run.stop();\n\n    expect(output.success).toBeTruthy();\n    expect(mockRunScript).not.toHaveBeenCalledWith();\n    expect(buildDevStandaloneMock).toHaveBeenCalledWith({\n      angularBrowserTarget: null,\n      angularBuilderContext: expect.any(Object),\n      angularBuilderOptions: { assets: [], styles: ['src/styles.css'] },\n      disableTelemetry: undefined,\n      ci: false,\n      configDir: '.storybook',\n      host: 'localhost',\n      https: false,\n      port: 4400,\n      packageJson: expect.any(Object),\n      quiet: false,\n      smokeTest: false,\n      sslCa: undefined,\n      sslCert: undefined,\n      sslKey: undefined,\n      tsConfig: 'path/to/tsConfig.json',\n    });\n  });\n});\n"
  },
  {
    "path": "code/frameworks/angular/src/builders/start-storybook/index.ts",
    "content": "import { readFileSync } from 'node:fs';\n\nimport { getEnvConfig, getProjectRoot, versions } from 'storybook/internal/common';\nimport { buildDevStandalone, withTelemetry } from 'storybook/internal/core-server';\nimport { addToGlobalContext } from 'storybook/internal/telemetry';\nimport type { CLIOptions } from 'storybook/internal/types';\nimport { logger, logTracker } from 'storybook/internal/node-logger';\n\nimport type {\n  BuilderContext,\n  BuilderHandlerFn,\n  BuilderOutput,\n  Target,\n  Builder as DevkitBuilder,\n} from '@angular-devkit/architect';\nimport { createBuilder, targetFromTargetString } from '@angular-devkit/architect';\nimport type {\n  BrowserBuilderOptions,\n  StylePreprocessorOptions,\n} from '@angular-devkit/build-angular';\nimport type {\n  AssetPattern,\n  SourceMapUnion,\n  StyleElement,\n} from '@angular-devkit/build-angular/src/builders/browser/schema';\nimport type { JsonObject } from '@angular-devkit/core';\nimport { Observable } from 'rxjs';\nimport * as find from 'empathic/find';\nimport * as pkg from 'empathic/package';\n\nimport { errorSummary, printErrorDetails } from '../utils/error-handler.ts';\nimport { runCompodoc } from '../utils/run-compodoc.ts';\nimport type { StandaloneOptions } from '../utils/standalone-options.ts';\nimport { VERSION } from '@angular/core';\nimport { Channel } from 'storybook/internal/channels';\n\naddToGlobalContext('cliVersion', versions.storybook);\n\nexport type StorybookBuilderOptions = JsonObject & {\n  browserTarget?: string | null;\n  tsConfig?: string;\n  compodoc: boolean;\n  compodocArgs: string[];\n  enableProdMode?: boolean;\n  styles?: StyleElement[];\n  stylePreprocessorOptions?: StylePreprocessorOptions;\n  assets?: AssetPattern[];\n  preserveSymlinks?: boolean;\n  sourceMap?: SourceMapUnion;\n  experimentalZoneless?: boolean;\n} & Pick<\n    // makes sure the option exists\n    CLIOptions,\n    | 'port'\n    | 'host'\n    | 'configDir'\n    | 'https'\n    | 'sslCa'\n    | 'sslCert'\n    | 'sslKey'\n    | 'smokeTest'\n    | 'ci'\n    | 'quiet'\n    | 'disableTelemetry'\n    | 'initialPath'\n    | 'open'\n    | 'docs'\n    | 'debugWebpack'\n    | 'logfile'\n    | 'webpackStatsJson'\n    | 'statsJson'\n    | 'loglevel'\n    | 'previewUrl'\n  >;\n\nexport type StorybookBuilderOutput = JsonObject & BuilderOutput & {};\n\nconst commandBuilder: BuilderHandlerFn<StorybookBuilderOptions> = (\n  options,\n  context\n): Observable<BuilderOutput> => {\n  return new Observable<BuilderOutput>((observer) => {\n    (async () => {\n      try {\n        // Apply logger configuration from builder options\n        if (options.loglevel) {\n          logger.setLogLevel(options.loglevel);\n        }\n        if (options.logfile) {\n          logTracker.enableLogWriting();\n        }\n\n        logger.intro('Starting Storybook');\n\n        const { tsConfig } = await setup(options, context);\n\n        const docTSConfig = find.up('tsconfig.doc.json', {\n          cwd: options.configDir,\n          last: getProjectRoot(),\n        });\n\n        if (options.compodoc) {\n          await runCompodoc(\n            {\n              compodocArgs: [...options.compodocArgs, ...(options.quiet ? ['--silent'] : [])],\n              tsconfig: docTSConfig ?? tsConfig,\n            },\n            context\n          );\n        }\n\n        getEnvConfig(options, {\n          port: 'SBCONFIG_PORT',\n          host: 'SBCONFIG_HOSTNAME',\n          staticDir: 'SBCONFIG_STATIC_DIR',\n          configDir: 'SBCONFIG_CONFIG_DIR',\n          ci: 'CI',\n        });\n\n        options.port = parseInt(`${options.port}`, 10);\n\n        const {\n          browserTarget,\n          stylePreprocessorOptions,\n          styles,\n          ci,\n          configDir,\n          docs,\n          host,\n          https,\n          port,\n          quiet,\n          enableProdMode = false,\n          smokeTest,\n          sslCa,\n          sslCert,\n          sslKey,\n          disableTelemetry,\n          assets,\n          initialPath,\n          open,\n          debugWebpack,\n          loglevel,\n          webpackStatsJson,\n          statsJson,\n          previewUrl,\n          sourceMap = false,\n          preserveSymlinks = false,\n          experimentalZoneless = !!(VERSION.major && Number(VERSION.major) >= 21),\n        } = options;\n\n        const packageJsonPath = pkg.up({ cwd: __dirname });\n        const packageJson =\n          packageJsonPath != null ? JSON.parse(readFileSync(packageJsonPath, 'utf8')) : null;\n\n        const standaloneOptions: StandaloneOptions = {\n          packageJson,\n          ci,\n          configDir,\n          ...(docs ? { docs } : {}),\n          host,\n          https,\n          port,\n          quiet,\n          enableProdMode,\n          smokeTest,\n          sslCa,\n          sslCert,\n          sslKey,\n          disableTelemetry,\n          angularBrowserTarget: browserTarget,\n          angularBuilderContext: context,\n          angularBuilderOptions: {\n            ...(stylePreprocessorOptions ? { stylePreprocessorOptions } : {}),\n            ...(styles ? { styles } : {}),\n            ...(assets ? { assets } : {}),\n            preserveSymlinks,\n            sourceMap,\n            experimentalZoneless,\n          },\n          tsConfig,\n          initialPath,\n          open,\n          debugWebpack,\n          webpackStatsJson,\n          statsJson,\n          loglevel,\n          previewUrl,\n        };\n\n        const startedPort = await runInstance(standaloneOptions);\n\n        // Emit success output - the dev server is now running\n        observer.next({ success: true, info: { port: startedPort } } as BuilderOutput);\n\n        // Don't call observer.complete() - this keeps the Observable alive\n        // so the dev server continues running. Architect will keep subscribing\n        // until the Observable completes, which allows watch mode to work.\n      } catch (error) {\n        // Write logs to file on failure when enabled\n        try {\n          if (logTracker.shouldWriteLogsToFile) {\n            try {\n              const logFile = await logTracker.writeToFile(options.logfile as any);\n              logger.outro(`Debug logs are written to: ${logFile}`);\n            } catch {}\n          }\n        } catch {}\n        observer.error(error);\n      }\n    })();\n  });\n};\n\nexport default createBuilder(commandBuilder) as DevkitBuilder<StorybookBuilderOptions & JsonObject>;\n\nasync function setup(options: StorybookBuilderOptions, context: BuilderContext) {\n  let browserOptions: (JsonObject & BrowserBuilderOptions) | undefined;\n  let browserTarget: Target | undefined;\n\n  if (options.browserTarget) {\n    browserTarget = targetFromTargetString(options.browserTarget);\n    browserOptions = await context.validateOptions<JsonObject & BrowserBuilderOptions>(\n      await context.getTargetOptions(browserTarget),\n      await context.getBuilderNameForTarget(browserTarget)\n    );\n  }\n\n  return {\n    tsConfig:\n      options.tsConfig ??\n      find.up('tsconfig.json', { cwd: options.configDir }) ??\n      browserOptions.tsConfig,\n  };\n}\nasync function runInstance(options: StandaloneOptions) {\n  try {\n    const { port } = await withTelemetry(\n      'dev',\n      {\n        cliOptions: options,\n        presetOptions: {\n          ...options,\n          corePresets: [],\n          overridePresets: [],\n          channel: new Channel({}),\n        },\n        printError: printErrorDetails,\n      },\n      () => {\n        return buildDevStandalone(options);\n      }\n    );\n    return port;\n  } catch (error) {\n    const summarized = errorSummary(error);\n    throw new Error(String(summarized));\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/builders/utils/error-handler.ts",
    "content": "import { logger, instance as npmLog } from 'storybook/internal/node-logger';\n\nimport { dedent } from 'ts-dedent';\n\nexport const printErrorDetails = (error: any): void => {\n  // Duplicate code for Standalone error handling\n  // Source: https://github.com/storybookjs/storybook/blob/39c7ba09ad84fbd466f9c25d5b92791a5450b9f6/lib/core-server/src/build-dev.ts#L136\n  npmLog.heading = '';\n\n  if (error instanceof Error) {\n    if ((error as any).error) {\n      logger.error((error as any).error);\n    } else if ((error as any).stats && (error as any).stats.compilation.errors) {\n      (error as any).stats.compilation.errors.forEach((e: any) => logger.log(e));\n    } else {\n      logger.error(error as any);\n    }\n  } else if (error.compilation?.errors) {\n    error.compilation.errors.forEach((e: any) => logger.log(e));\n  }\n};\n\nexport const errorSummary = (error: any): string => {\n  return error.close\n    ? dedent`\n      FATAL broken build!, will close the process,\n      Fix the error below and restart storybook.\n    `\n    : dedent`\n      Broken build, fix the error above.\n      You may need to refresh the browser.\n    `;\n};\n"
  },
  {
    "path": "code/frameworks/angular/src/builders/utils/run-compodoc.spec.ts",
    "content": "import type { BuilderContext } from '@angular-devkit/architect';\n// @ts-expect-error (TODO)\nimport type { LoggerApi } from '@angular-devkit/core/src/logger';\nimport { afterEach, describe, expect, it, vi } from 'vitest';\n\nimport { runCompodoc } from './run-compodoc.ts';\n\nconst mockRunScript = vi.fn().mockResolvedValue({ stdout: '' });\n\nvi.mock('storybook/internal/common', () => ({\n  JsPackageManagerFactory: {\n    getPackageManager: () => ({\n      runPackageCommand: mockRunScript,\n    }),\n  },\n}));\nvi.mock('storybook/internal/node-logger', () => ({\n  prompt: {\n    executeTaskWithSpinner: async (fn: any) => {\n      await fn();\n    },\n  },\n}));\n\nconst builderContextLoggerMock: LoggerApi = {\n  createChild: vi.fn(),\n  log: vi.fn(),\n  debug: vi.fn(),\n  info: vi.fn(),\n  warn: vi.fn(),\n  error: vi.fn(),\n  fatal: vi.fn(),\n};\n\ndescribe('runCompodoc', () => {\n  afterEach(() => {\n    mockRunScript.mockClear();\n  });\n\n  const builderContextMock = {\n    workspaceRoot: 'path/to/project',\n    logger: builderContextLoggerMock,\n  } as BuilderContext;\n\n  it('should run compodoc with tsconfig from context', async () => {\n    await runCompodoc(\n      {\n        compodocArgs: [],\n        tsconfig: 'path/to/tsconfig.json',\n      },\n      builderContextMock\n    );\n\n    expect(mockRunScript).toHaveBeenCalledWith({\n      args: ['compodoc', '-p', 'path/to/tsconfig.json', '-d', 'path/to/project'],\n      cwd: 'path/to/project',\n    });\n  });\n\n  it('should run compodoc with tsconfig from compodocArgs', async () => {\n    await runCompodoc(\n      {\n        compodocArgs: ['-p', 'path/to/tsconfig.stories.json'],\n        tsconfig: 'path/to/tsconfig.json',\n      },\n      builderContextMock\n    );\n\n    expect(mockRunScript).toHaveBeenCalledWith({\n      args: ['compodoc', '-d', 'path/to/project', '-p', 'path/to/tsconfig.stories.json'],\n      cwd: 'path/to/project',\n    });\n  });\n\n  it('should run compodoc with default output folder.', async () => {\n    await runCompodoc(\n      {\n        compodocArgs: [],\n        tsconfig: 'path/to/tsconfig.json',\n      },\n      builderContextMock\n    );\n\n    expect(mockRunScript).toHaveBeenCalledWith({\n      args: ['compodoc', '-p', 'path/to/tsconfig.json', '-d', 'path/to/project'],\n      cwd: 'path/to/project',\n    });\n  });\n\n  it('should run with custom output folder specified with --output compodocArgs', async () => {\n    await runCompodoc(\n      {\n        compodocArgs: ['--output', 'path/to/customFolder'],\n        tsconfig: 'path/to/tsconfig.json',\n      },\n      builderContextMock\n    );\n\n    expect(mockRunScript).toHaveBeenCalledWith({\n      args: ['compodoc', '-p', 'path/to/tsconfig.json', '--output', 'path/to/customFolder'],\n      cwd: 'path/to/project',\n    });\n  });\n\n  it('should run with custom output folder specified with -d compodocArgs', async () => {\n    await runCompodoc(\n      {\n        compodocArgs: ['-d', 'path/to/customFolder'],\n        tsconfig: 'path/to/tsconfig.json',\n      },\n      builderContextMock\n    );\n\n    expect(mockRunScript).toHaveBeenCalledWith({\n      args: ['compodoc', '-p', 'path/to/tsconfig.json', '-d', 'path/to/customFolder'],\n      cwd: 'path/to/project',\n    });\n  });\n});\n"
  },
  {
    "path": "code/frameworks/angular/src/builders/utils/run-compodoc.ts",
    "content": "import { isAbsolute, relative } from 'node:path';\n\nimport { JsPackageManagerFactory } from 'storybook/internal/common';\n\nimport type { BuilderContext } from '@angular-devkit/architect';\nimport { prompt } from 'storybook/internal/node-logger';\n\nconst hasTsConfigArg = (args: string[]) => args.indexOf('-p') !== -1;\nconst hasOutputArg = (args: string[]) =>\n  args.indexOf('-d') !== -1 || args.indexOf('--output') !== -1;\n\n// relative is necessary to workaround a compodoc issue with\n// absolute paths on windows machines\nconst toRelativePath = (pathToTsConfig: string) => {\n  return isAbsolute(pathToTsConfig) ? relative('.', pathToTsConfig) : pathToTsConfig;\n};\n\nexport const runCompodoc = async (\n  { compodocArgs, tsconfig }: { compodocArgs: string[]; tsconfig: string },\n  context: BuilderContext\n): Promise<void> => {\n  const tsConfigPath = toRelativePath(tsconfig);\n  const finalCompodocArgs = [\n    'compodoc',\n    ...(hasTsConfigArg(compodocArgs) ? [] : ['-p', tsConfigPath]),\n    ...(hasOutputArg(compodocArgs) ? [] : ['-d', `${context.workspaceRoot || '.'}`]),\n    ...compodocArgs,\n  ];\n\n  const packageManager = JsPackageManagerFactory.getPackageManager();\n\n  await prompt.executeTaskWithSpinner(\n    () =>\n      packageManager.runPackageCommand({\n        args: finalCompodocArgs,\n        cwd: context.workspaceRoot,\n      }),\n    {\n      id: 'compodoc',\n      intro: 'Generating documentation with Compodoc',\n      success: 'Compodoc finished successfully',\n      error: 'Compodoc failed',\n    }\n  );\n};\n"
  },
  {
    "path": "code/frameworks/angular/src/builders/utils/standalone-options.ts",
    "content": "import type { BuilderOptions, CLIOptions, LoadOptions } from 'storybook/internal/types';\n\nimport type { BuilderContext } from '@angular-devkit/architect';\nimport type {\n  AssetPattern,\n  SourceMapUnion,\n  StyleElement,\n  StylePreprocessorOptions,\n} from '@angular-devkit/build-angular/src/builders/browser/schema';\n\nexport type StandaloneOptions = CLIOptions &\n  LoadOptions &\n  BuilderOptions & {\n    mode?: 'static' | 'dev';\n    enableProdMode: boolean;\n    angularBrowserTarget?: string | null;\n    angularBuilderOptions?: Record<string, any> & {\n      styles?: StyleElement[];\n      stylePreprocessorOptions?: StylePreprocessorOptions;\n      assets?: AssetPattern[];\n      sourceMap?: SourceMapUnion;\n      preserveSymlinks?: boolean;\n      experimentalZoneless?: boolean;\n    };\n    angularBuilderContext?: BuilderContext | null;\n    tsConfig?: string;\n  };\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/AbstractRenderer.ts",
    "content": "import type { ApplicationRef, NgModule } from '@angular/core';\nimport { bootstrapApplication } from '@angular/platform-browser';\nimport type { Subject } from 'rxjs';\nimport { BehaviorSubject } from 'rxjs';\nimport { stringify } from 'telejson';\n\nimport type { ICollection, StoryFnAngularReturnType } from '../types.ts';\nimport { getApplication } from './StorybookModule.ts';\nimport { storyPropsProvider } from './StorybookProvider.ts';\nimport { queueBootstrapping } from './utils/BootstrapQueue.ts';\nimport { PropertyExtractor } from './utils/PropertyExtractor.ts';\nimport { getProvideZonelessChangeDetectionFn } from './utils/Zoneless.ts';\n\ntype StoryRenderInfo = {\n  storyFnAngular: StoryFnAngularReturnType;\n  moduleMetadataSnapshot: string;\n};\n\ndeclare global {\n  const STORYBOOK_ANGULAR_OPTIONS: {\n    experimentalZoneless: boolean;\n  };\n}\n\nconst applicationRefs = new Map<HTMLElement, ApplicationRef>();\n\n/**\n * Attribute name for the story UID that may be written to the targetDOMNode.\n *\n * If a target DOM node has a story UID attribute, it will be used as part of the selector for the\n * Angular component.\n */\nexport const STORY_UID_ATTRIBUTE = 'data-sb-story-uid';\n\nexport abstract class AbstractRenderer {\n  /** Wait and destroy the platform */\n  public static resetApplications(domNode?: HTMLElement) {\n    applicationRefs.forEach((appRef, appDOMNode) => {\n      if (!appRef.destroyed && (!domNode || appDOMNode === domNode)) {\n        appRef.destroy();\n      }\n    });\n  }\n\n  protected previousStoryRenderInfo = new Map<HTMLElement, StoryRenderInfo>();\n\n  // Observable to change the properties dynamically without reloading angular module&component\n  protected storyProps$: Subject<ICollection | undefined>;\n\n  protected abstract beforeFullRender(domNode?: HTMLElement): Promise<void>;\n\n  /**\n   * Bootstrap main angular module with main component or send only new `props` with storyProps$\n   *\n   * @param storyFnAngular {StoryFnAngularReturnType}\n   * @param forced {boolean} If :\n   *\n   *   - True render will only use the StoryFn `props' in storyProps observable that will update sotry's\n   *       component/template properties. Improves performance without reloading the whole\n   *       module&component if props changes\n   *   - False fully recharges or initializes angular module & component\n   *\n   * @param component {Component}\n   */\n  public async render({\n    storyId,\n    storyFnAngular,\n    forced,\n    component,\n    targetDOMNode,\n  }: {\n    storyId: string;\n    storyFnAngular: StoryFnAngularReturnType;\n    forced: boolean;\n    component?: any;\n    targetDOMNode: HTMLElement;\n  }) {\n    const targetSelector = this.generateTargetSelectorFromStoryId(storyId);\n\n    const newStoryProps$ = new BehaviorSubject<ICollection>(storyFnAngular.props);\n\n    if (\n      !this.fullRendererRequired({\n        targetDOMNode,\n        storyFnAngular,\n        moduleMetadata: {\n          ...storyFnAngular.moduleMetadata,\n        },\n        forced,\n      })\n    ) {\n      this.storyProps$.next(storyFnAngular.props);\n\n      return;\n    }\n\n    await this.beforeFullRender(targetDOMNode);\n\n    // Complete last BehaviorSubject and set a new one for the current module\n    if (this.storyProps$) {\n      this.storyProps$.complete();\n    }\n    this.storyProps$ = newStoryProps$;\n\n    this.initAngularRootElement(targetDOMNode, targetSelector, storyId);\n\n    const analyzedMetadata = new PropertyExtractor(storyFnAngular.moduleMetadata, component);\n    await analyzedMetadata.init();\n\n    const storyUid = this.generateStoryUIdFromRawStoryUid(\n      targetDOMNode.getAttribute(STORY_UID_ATTRIBUTE)\n    );\n    const componentSelector = storyUid !== null ? `${targetSelector}[${storyUid}]` : targetSelector;\n    if (storyUid !== null) {\n      const element = targetDOMNode.querySelector(targetSelector);\n      element.toggleAttribute(storyUid, true);\n    }\n\n    const application = getApplication({\n      storyFnAngular,\n      component,\n      targetSelector: componentSelector,\n      analyzedMetadata,\n    });\n\n    const providers = [\n      storyPropsProvider(newStoryProps$),\n      ...analyzedMetadata.applicationProviders,\n      ...(storyFnAngular.applicationConfig?.providers ?? []),\n    ];\n\n    if (STORYBOOK_ANGULAR_OPTIONS?.experimentalZoneless) {\n      const provideZonelessChangeDetectionFn = await getProvideZonelessChangeDetectionFn();\n\n      if (!provideZonelessChangeDetectionFn) {\n        throw new Error('Zoneless change detection requires Angular 18 or higher');\n      } else {\n        providers.unshift(provideZonelessChangeDetectionFn());\n      }\n    }\n\n    const applicationRef = await queueBootstrapping(() => {\n      return bootstrapApplication(application, {\n        ...storyFnAngular.applicationConfig,\n        providers,\n      });\n    });\n\n    applicationRefs.set(targetDOMNode, applicationRef);\n  }\n\n  /**\n   * Only ASCII alphanumerics can be used as HTML tag name. https://html.spec.whatwg.org/#elements-2\n   *\n   * Therefore, stories break when non-ASCII alphanumerics are included in target selector.\n   * https://github.com/storybookjs/storybook/issues/15147\n   *\n   * This method returns storyId when it doesn't contain any non-ASCII alphanumerics. Otherwise, it\n   * generates a valid HTML tag name from storyId by removing non-ASCII alphanumerics from storyId,\n   * prefixing \"sb-\", and suffixing \"-component\"\n   *\n   * @memberof AbstractRenderer\n   * @protected\n   */\n  protected generateTargetSelectorFromStoryId(id: string) {\n    const invalidHtmlTag = /[^A-Za-z0-9-]/g;\n    const storyIdIsInvalidHtmlTagName = invalidHtmlTag.test(id);\n    return storyIdIsInvalidHtmlTagName ? `sb-${id.replace(invalidHtmlTag, '')}-component` : id;\n  }\n\n  /**\n   * Angular is unable to handle components that have selectors with accented attributes.\n   *\n   * Therefore, stories break when meta's title contains accents.\n   * https://github.com/storybookjs/storybook/issues/29132\n   *\n   * This method filters accents from a given raw id. For example, this method converts\n   * 'Example/Button with an \"é\" accent' into 'Example/Button with an \"e\" accent'.\n   *\n   * @memberof AbstractRenderer\n   * @protected\n   */\n  protected generateStoryUIdFromRawStoryUid(rawStoryUid: string | null) {\n    if (rawStoryUid === null) {\n      return rawStoryUid;\n    }\n\n    const accentCharacters = /[\\u0300-\\u036f]/g;\n    return rawStoryUid.normalize('NFD').replace(accentCharacters, '');\n  }\n\n  /** Adds DOM element that angular will use as bootstrap component. */\n  protected initAngularRootElement(\n    targetDOMNode: HTMLElement,\n    targetSelector: string,\n    _storyId: string\n  ) {\n    targetDOMNode.innerHTML = '';\n    targetDOMNode.appendChild(document.createElement(targetSelector));\n  }\n\n  private fullRendererRequired({\n    targetDOMNode,\n    storyFnAngular,\n    moduleMetadata,\n    forced,\n  }: {\n    targetDOMNode: HTMLElement;\n    storyFnAngular: StoryFnAngularReturnType;\n    moduleMetadata: NgModule;\n    forced: boolean;\n  }) {\n    const previousStoryRenderInfo = this.previousStoryRenderInfo.get(targetDOMNode);\n\n    const currentStoryRender = {\n      storyFnAngular,\n      moduleMetadataSnapshot: stringify(moduleMetadata, { maxDepth: 50 }),\n    };\n\n    this.previousStoryRenderInfo.set(targetDOMNode, currentStoryRender);\n\n    if (\n      // check `forceRender` of story RenderContext\n      !forced ||\n      // if it's the first rendering and storyProps$ is not init\n      !this.storyProps$\n    ) {\n      return true;\n    }\n\n    // force the rendering if the template has changed\n    const hasChangedTemplate =\n      !!storyFnAngular?.template &&\n      previousStoryRenderInfo?.storyFnAngular?.template !== storyFnAngular.template;\n    if (hasChangedTemplate) {\n      return true;\n    }\n\n    // force the rendering if the metadata structure has changed\n    const hasChangedModuleMetadata =\n      currentStoryRender.moduleMetadataSnapshot !== previousStoryRenderInfo?.moduleMetadataSnapshot;\n\n    return hasChangedModuleMetadata;\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/CanvasRenderer.ts",
    "content": "import type { Parameters, StoryFnAngularReturnType } from '../types.ts';\nimport { AbstractRenderer } from './AbstractRenderer.ts';\n\nexport class CanvasRenderer extends AbstractRenderer {\n  public async render(options: {\n    storyFnAngular: StoryFnAngularReturnType;\n    forced: boolean;\n    parameters: Parameters;\n    component: any;\n    targetDOMNode: HTMLElement;\n    storyId: string;\n  }) {\n    await super.render(options);\n  }\n\n  async beforeFullRender(): Promise<void> {\n    CanvasRenderer.resetApplications();\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/ComputesTemplateFromComponent.test.ts",
    "content": "import { Component } from '@angular/core';\nimport type { ArgTypes } from 'storybook/internal/types';\nimport { describe, it, expect } from 'vitest';\nimport {\n  computesTemplateFromComponent,\n  computesTemplateSourceFromComponent,\n} from './ComputesTemplateFromComponent.ts';\nimport type { ISomeInterface } from './__testfixtures__/input.component.ts';\nimport { ButtonAccent, InputComponent } from './__testfixtures__/input.component.ts';\n\ndescribe('angular template decorator', () => {\n  it('with props should generate tag with properties', () => {\n    const component = InputComponent;\n    const props = {\n      isDisabled: true,\n      label: 'Hello world',\n      accent: ButtonAccent.High,\n      counter: 4,\n      'aria-label': 'Hello world',\n    };\n    const source = computesTemplateFromComponent(component, props);\n    expect(source).toEqual(\n      `<doc-button [counter]=\"counter\" [accent]=\"accent\" [isDisabled]=\"isDisabled\" [label]=\"label\" [aria-label]=\"this['aria-label']\"></doc-button>`\n    );\n  });\n\n  it('with props should generate tag with outputs', () => {\n    const component = InputComponent;\n    const props = {\n      isDisabled: true,\n      label: 'Hello world',\n      onClick: ($event: any) => {},\n      'dash-out': ($event: any) => {},\n    };\n    const source = computesTemplateFromComponent(component, props);\n    expect(source).toEqual(\n      `<doc-button [isDisabled]=\"isDisabled\" [label]=\"label\" (onClick)=\"onClick($event)\" (dash-out)=\"this['dash-out']($event)\"></doc-button>`\n    );\n  });\n\n  it('with no props should generate simple tag', () => {\n    const component = InputComponent;\n    const props = {};\n    const source = computesTemplateFromComponent(component, props);\n    expect(source).toEqual('<doc-button></doc-button>');\n  });\n\n  describe('with component without selector', () => {\n    @Component({\n      template: `\n        The content\n      `,\n    })\n    class WithoutSelectorComponent {}\n\n    it('should add component ng-container', async () => {\n      const component = WithoutSelectorComponent;\n      const props = {};\n      const source = computesTemplateFromComponent(component, props);\n      expect(source).toEqual(`<ng-container *ngComponentOutlet=\"storyComponent\"></ng-container>`);\n    });\n  });\n\n  describe('with component with attribute selector', () => {\n    @Component({\n      selector: 'doc-button[foo]',\n      template: '<button></button>',\n    })\n    class WithAttributeComponent {}\n\n    it('should add attribute to template', async () => {\n      const component = WithAttributeComponent;\n      const props = {};\n      const source = computesTemplateFromComponent(component, props);\n      expect(source).toEqual(`<doc-button foo></doc-button>`);\n    });\n  });\n\n  describe('with component with attribute and value selector', () => {\n    @Component({\n      selector: 'doc-button[foo=\"bar\"]',\n      template: '<button></button>',\n    })\n    class WithAttributeValueComponent {}\n\n    it('should add attribute to template', async () => {\n      const component = WithAttributeValueComponent;\n      const props = {};\n      const source = computesTemplateFromComponent(component, props);\n      expect(source).toEqual(`<doc-button foo=\"bar\"></doc-button>`);\n    });\n  });\n\n  describe('with component with attribute only selector', () => {\n    @Component({\n      selector: '[foo]',\n      template: '<button></button>',\n    })\n    class WithAttributeOnlyComponent {}\n\n    it('should create a div and add attribute to template', async () => {\n      const component = WithAttributeOnlyComponent;\n      const props = {};\n      const source = computesTemplateFromComponent(component, props);\n      expect(source).toEqual(`<div foo></div>`);\n    });\n  });\n\n  describe('with component with void element and attribute selector', () => {\n    @Component({\n      selector: 'input[foo]',\n      template: '<button></button>',\n    })\n    class VoidElementWithAttributeComponent {}\n\n    it('should create without separate closing tag', async () => {\n      const component = VoidElementWithAttributeComponent;\n      const props = {};\n      const source = computesTemplateFromComponent(component, props);\n      expect(source).toEqual(`<input foo />`);\n    });\n  });\n\n  describe('with component with attribute and value only selector', () => {\n    @Component({\n      selector: '[foo=\"bar\"]',\n      template: '<button></button>',\n    })\n    class WithAttributeOnlyComponent {}\n\n    it('should create a div and add attribute to template', async () => {\n      const component = WithAttributeOnlyComponent;\n      const props = {};\n      const source = computesTemplateFromComponent(component, props);\n      expect(source).toEqual(`<div foo=\"bar\"></div>`);\n    });\n  });\n\n  describe('with component with void element, attribute and value only selector', () => {\n    @Component({\n      selector: 'input[foo=\"bar\"]',\n      template: '<button></button>',\n    })\n    class VoidElementWithAttributeComponent {}\n\n    it('should create and add attribute to template without separate closing tag', async () => {\n      const component = VoidElementWithAttributeComponent;\n      const props = {};\n      const source = computesTemplateFromComponent(component, props);\n      expect(source).toEqual(`<input foo=\"bar\" />`);\n    });\n  });\n\n  describe('with component with class selector', () => {\n    @Component({\n      selector: 'doc-button.foo',\n      template: '<button></button>',\n    })\n    class WithClassComponent {}\n\n    it('should add class to template', async () => {\n      const component = WithClassComponent;\n      const props = {};\n      const source = computesTemplateFromComponent(component, props);\n      expect(source).toEqual(`<doc-button class=\"foo\"></doc-button>`);\n    });\n  });\n\n  describe('with component with class only selector', () => {\n    @Component({\n      selector: '.foo',\n      template: '<button></button>',\n    })\n    class WithClassComponent {}\n\n    it('should create a div and add attribute to template', async () => {\n      const component = WithClassComponent;\n      const props = {};\n      const source = computesTemplateFromComponent(component, props);\n      expect(source).toEqual(`<div class=\"foo\"></div>`);\n    });\n  });\n\n  describe('with component with multiple selectors', () => {\n    @Component({\n      selector: 'doc-button, doc-button2',\n      template: '<button></button>',\n    })\n    class WithMultipleSelectorsComponent {}\n\n    it('should use the first selector', async () => {\n      const component = WithMultipleSelectorsComponent;\n      const props = {};\n      const source = computesTemplateFromComponent(component, props);\n      expect(source).toEqual(`<doc-button></doc-button>`);\n    });\n  });\n\n  describe('with component with multiple selectors starting with attribute', () => {\n    @Component({\n      selector: 'doc-button[foo], doc-button2',\n      template: '<button></button>',\n    })\n    class WithMultipleSelectorsComponent {}\n\n    it('should use the first selector', async () => {\n      const component = WithMultipleSelectorsComponent;\n      const props = {};\n      const source = computesTemplateFromComponent(component, props);\n      expect(source).toEqual(`<doc-button foo></doc-button>`);\n    });\n  });\n\n  describe('with component with multiple selectors starting with attribute and value', () => {\n    @Component({\n      selector: 'doc-button[foo=\"bar\"], doc-button2',\n      template: '<button></button>',\n    })\n    class WithMultipleSelectorsComponent {}\n\n    it('should use the first selector', async () => {\n      const component = WithMultipleSelectorsComponent;\n      const props = {};\n      const source = computesTemplateFromComponent(component, props);\n      expect(source).toEqual(`<doc-button foo=\"bar\"></doc-button>`);\n    });\n  });\n\n  describe('with component with multiple selectors including 2 attributes and a class', () => {\n    @Component({\n      selector: 'doc-button, button[foo], .button[foo], button[baz]',\n      template: '<button></button>',\n    })\n    class WithMultipleSelectorsComponent {}\n\n    it('should use the first selector', async () => {\n      const component = WithMultipleSelectorsComponent;\n      const props = {};\n      const source = computesTemplateFromComponent(component, props);\n      expect(source).toEqual(`<doc-button></doc-button>`);\n    });\n  });\n\n  describe('with component with multiple selectors with line breaks', () => {\n    @Component({\n      selector: `doc-button,\n      doc-button2`,\n      template: '<button></button>',\n    })\n    class WithMultipleSelectorsComponent {}\n\n    it('should use the first selector', async () => {\n      const component = WithMultipleSelectorsComponent;\n      const props = {};\n      const source = computesTemplateFromComponent(component, props);\n      expect(source).toEqual(`<doc-button></doc-button>`);\n    });\n  });\n\n  describe('with component with multiple selectors starting with attribute only with line breaks', () => {\n    @Component({\n      selector: `[foo],\n      doc-button2`,\n      template: '<button></button>',\n    })\n    class WithMultipleSelectorsComponent {}\n\n    it('should use the first selector', async () => {\n      const component = WithMultipleSelectorsComponent;\n      const props = {};\n      const source = computesTemplateFromComponent(component, props);\n      expect(source).toEqual(`<div foo></div>`);\n    });\n  });\n\n  it('with props should generate tag with properties', () => {\n    const component = InputComponent;\n    const props = {\n      isDisabled: true,\n      label: 'Hello world',\n      accent: ButtonAccent.High,\n      counter: 4,\n    };\n    const source = computesTemplateFromComponent(component, props);\n    expect(source).toEqual(\n      `<doc-button [counter]=\"counter\" [accent]=\"accent\" [isDisabled]=\"isDisabled\" [label]=\"label\"></doc-button>`\n    );\n  });\n\n  it('with props should generate tag with outputs', () => {\n    const component = InputComponent;\n    const props = {\n      isDisabled: true,\n      label: 'Hello world',\n      onClick: ($event: any) => {},\n    };\n    const source = computesTemplateFromComponent(component, props);\n    expect(source).toEqual(\n      `<doc-button [isDisabled]=\"isDisabled\" [label]=\"label\" (onClick)=\"onClick($event)\"></doc-button>`\n    );\n  });\n\n  it('should generate correct property for overridden name for Input', () => {\n    const component = InputComponent;\n    const props = {\n      color: '#ffffff',\n    };\n    const source = computesTemplateFromComponent(component, props);\n    expect(source).toEqual(`<doc-button [color]=\"color\"></doc-button>`);\n  });\n});\n\ndescribe('angular source decorator', () => {\n  it('with no props should generate simple tag', () => {\n    const component = InputComponent;\n    const props = {};\n    const argTypes: ArgTypes = {};\n    const source = computesTemplateSourceFromComponent(component, props, argTypes);\n    expect(source).toEqual('<doc-button></doc-button>');\n  });\n\n  describe('with component without selector', () => {\n    @Component({\n      template: `\n        The content\n      `,\n    })\n    class WithoutSelectorComponent {}\n\n    it('should add component ng-container', async () => {\n      const component = WithoutSelectorComponent;\n      const props = {};\n      const argTypes: ArgTypes = {};\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(\n        `<ng-container *ngComponentOutlet=\"WithoutSelectorComponent\"></ng-container>`\n      );\n    });\n  });\n\n  describe('with component with attribute selector', () => {\n    @Component({\n      selector: 'doc-button[foo]',\n      template: '<button></button>',\n    })\n    class WithAttributeComponent {}\n\n    it('should add attribute to template', async () => {\n      const component = WithAttributeComponent;\n      const props = {};\n      const argTypes: ArgTypes = {};\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(`<doc-button foo></doc-button>`);\n    });\n  });\n\n  describe('with component with attribute and value selector', () => {\n    @Component({\n      selector: 'doc-button[foo=\"bar\"]',\n      template: '<button></button>',\n    })\n    class WithAttributeValueComponent {}\n\n    it('should add attribute to template', async () => {\n      const component = WithAttributeValueComponent;\n      const props = {};\n      const argTypes: ArgTypes = {};\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(`<doc-button foo=\"bar\"></doc-button>`);\n    });\n  });\n\n  describe('with component with attribute only selector', () => {\n    @Component({\n      selector: '[foo]',\n      template: '<button></button>',\n    })\n    class WithAttributeOnlyComponent {}\n\n    it('should create a div and add attribute to template', async () => {\n      const component = WithAttributeOnlyComponent;\n      const props = {};\n      const argTypes: ArgTypes = {};\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(`<div foo></div>`);\n    });\n  });\n\n  describe('with component with void element and attribute selector', () => {\n    @Component({\n      selector: 'input[foo]',\n      template: '<button></button>',\n    })\n    class VoidElementWithAttributeComponent {}\n\n    it('should create without separate closing tag', async () => {\n      const component = VoidElementWithAttributeComponent;\n      const props = {};\n      const argTypes: ArgTypes = {};\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(`<input foo />`);\n    });\n  });\n\n  describe('with component with attribute and value only selector', () => {\n    @Component({\n      selector: '[foo=\"bar\"]',\n      template: '<button></button>',\n    })\n    class WithAttributeOnlyComponent {}\n\n    it('should create a div and add attribute to template', async () => {\n      const component = WithAttributeOnlyComponent;\n      const props = {};\n      const argTypes: ArgTypes = {};\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(`<div foo=\"bar\"></div>`);\n    });\n  });\n\n  describe('with component with void element, attribute and value only selector', () => {\n    @Component({\n      selector: 'input[foo=\"bar\"]',\n      template: '<button></button>',\n    })\n    class VoidElementWithAttributeComponent {}\n\n    it('should create and add attribute to template without separate closing tag', async () => {\n      const component = VoidElementWithAttributeComponent;\n      const props = {};\n      const argTypes: ArgTypes = {};\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(`<input foo=\"bar\" />`);\n    });\n  });\n\n  describe('with component with class selector', () => {\n    @Component({\n      selector: 'doc-button.foo',\n      template: '<button></button>',\n    })\n    class WithClassComponent {}\n\n    it('should add class to template', async () => {\n      const component = WithClassComponent;\n      const props = {};\n      const argTypes: ArgTypes = {};\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(`<doc-button class=\"foo\"></doc-button>`);\n    });\n  });\n\n  describe('with component with class only selector', () => {\n    @Component({\n      selector: '.foo',\n      template: '<button></button>',\n    })\n    class WithClassComponent {}\n\n    it('should create a div and add attribute to template', async () => {\n      const component = WithClassComponent;\n      const props = {};\n      const argTypes: ArgTypes = {};\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(`<div class=\"foo\"></div>`);\n    });\n  });\n\n  describe('with component with multiple selectors', () => {\n    @Component({\n      selector: 'doc-button, doc-button2',\n      template: '<button></button>',\n    })\n    class WithMultipleSelectorsComponent {}\n\n    it('should use the first selector', async () => {\n      const component = WithMultipleSelectorsComponent;\n      const props = {};\n      const argTypes: ArgTypes = {};\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(`<doc-button></doc-button>`);\n    });\n  });\n\n  describe('with component with multiple selectors starting with attribute', () => {\n    @Component({\n      selector: 'doc-button[foo], doc-button2',\n      template: '<button></button>',\n    })\n    class WithMultipleSelectorsComponent {}\n\n    it('should use the first selector', async () => {\n      const component = WithMultipleSelectorsComponent;\n      const props = {};\n      const argTypes: ArgTypes = {};\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(`<doc-button foo></doc-button>`);\n    });\n  });\n\n  describe('with component with multiple selectors starting with attribute and value', () => {\n    @Component({\n      selector: 'doc-button[foo=\"bar\"], doc-button2',\n      template: '<button></button>',\n    })\n    class WithMultipleSelectorsComponent {}\n\n    it('should use the first selector', async () => {\n      const component = WithMultipleSelectorsComponent;\n      const props = {};\n      const argTypes: ArgTypes = {};\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(`<doc-button foo=\"bar\"></doc-button>`);\n    });\n  });\n\n  describe('with component with multiple selectors including 2 attributes and a class', () => {\n    @Component({\n      selector: 'doc-button, button[foo], .button[foo], button[baz]',\n      template: '<button></button>',\n    })\n    class WithMultipleSelectorsComponent {}\n\n    it('should use the first selector', async () => {\n      const component = WithMultipleSelectorsComponent;\n      const props = {};\n      const argTypes: ArgTypes = {};\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(`<doc-button></doc-button>`);\n    });\n  });\n\n  describe('with component with multiple selectors with line breaks', () => {\n    @Component({\n      selector: `doc-button, \n      doc-button2`,\n      template: '<button></button>',\n    })\n    class WithMultipleSelectorsComponent {}\n\n    it('should use the first selector', async () => {\n      const component = WithMultipleSelectorsComponent;\n      const props = {};\n      const argTypes: ArgTypes = {};\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(`<doc-button></doc-button>`);\n    });\n  });\n\n  describe('with component with multiple selectors starting with attribute only with line breaks', () => {\n    @Component({\n      selector: `[foo], \n      doc-button2`,\n      template: '<button></button>',\n    })\n    class WithMultipleSelectorsComponent {}\n\n    it('should use the first selector', async () => {\n      const component = WithMultipleSelectorsComponent;\n      const props = {};\n      const argTypes: ArgTypes = {};\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(`<div foo></div>`);\n    });\n  });\n\n  describe('no argTypes', () => {\n    it('should generate tag-only template with no props', () => {\n      const component = InputComponent;\n      const props = {};\n      const argTypes: ArgTypes = {};\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(`<doc-button></doc-button>`);\n    });\n    it('with props should generate tag with properties', () => {\n      const component = InputComponent;\n      const props = {\n        isDisabled: true,\n        label: 'Hello world',\n        accent: ButtonAccent.High,\n        counter: 4,\n        'aria-label': 'Hello world',\n      };\n      const argTypes: ArgTypes = {};\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(\n        `<doc-button [counter]=\"4\" [accent]=\"'High'\" [isDisabled]=\"true\" [label]=\"'Hello world'\" [aria-label]=\"'Hello world'\"></doc-button>`\n      );\n    });\n\n    it('with props should generate tag with outputs', () => {\n      const component = InputComponent;\n      const props = {\n        isDisabled: true,\n        label: 'Hello world',\n        onClick: ($event: any) => {},\n        'dash-out': ($event: any) => {},\n      };\n      const argTypes: ArgTypes = {};\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(\n        `<doc-button [isDisabled]=\"true\" [label]=\"'Hello world'\" (onClick)=\"onClick($event)\" (dash-out)=\"this['dash-out']($event)\"></doc-button>`\n      );\n    });\n\n    it('should generate correct property for overridden name for Input', () => {\n      const component = InputComponent;\n      const props = {\n        color: '#ffffff',\n      };\n      const argTypes: ArgTypes = {};\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(`<doc-button [color]=\"'#ffffff'\"></doc-button>`);\n    });\n  });\n\n  describe('with argTypes (from compodoc)', () => {\n    it('should handle enum as strongly typed enum', () => {\n      const component = InputComponent;\n      const props = {\n        isDisabled: false,\n        label: 'Hello world',\n        accent: ButtonAccent.High,\n      };\n      const argTypes: ArgTypes = {\n        accent: {\n          control: {\n            options: ['Normal', 'High'],\n            type: 'radio',\n          },\n          defaultValue: undefined,\n          table: {\n            category: 'inputs',\n          },\n          type: {\n            name: 'enum',\n            required: true,\n            value: [],\n          },\n        },\n      };\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(\n        `<doc-button [accent]=\"'High'\" [isDisabled]=\"false\" [label]=\"'Hello world'\"></doc-button>`\n      );\n    });\n\n    it('should handle enum without values as string', () => {\n      const component = InputComponent;\n      const props = {\n        isDisabled: false,\n        label: 'Hello world',\n        accent: ButtonAccent.High,\n      };\n      const argTypes: ArgTypes = {\n        accent: {\n          control: {\n            options: ['Normal', 'High'],\n            type: 'radio',\n          },\n          defaultValue: undefined,\n          table: {\n            category: 'inputs',\n          },\n          type: {\n            name: 'object',\n            required: true,\n            value: {},\n          },\n        },\n      };\n      const source = computesTemplateSourceFromComponent(component, props, argTypes);\n      expect(source).toEqual(\n        `<doc-button [accent]=\"'High'\" [isDisabled]=\"false\" [label]=\"'Hello world'\"></doc-button>`\n      );\n    });\n\n    it('should handle simple object as stringified', () => {\n      const component = InputComponent;\n\n      const someDataObject: ISomeInterface = {\n        one: 'Hello world',\n        two: true,\n        three: [\n          `a string literal with \"double quotes\"`,\n          `a string literal with 'single quotes'`,\n          'a single quoted string with \"double quotes\"',\n          \"a double quoted string with 'single quotes'\",\n\n          \"a single quoted string with escaped 'single quotes'\",\n\n          'a double quoted string with escaped \"double quotes\"',\n\n          `a string literal with \\'escaped single quotes\\'`,\n\n          `a string literal with \\\"escaped double quotes\\\"`,\n        ],\n      };\n\n      const props = {\n        isDisabled: false,\n        label: 'Hello world',\n        someDataObject,\n      };\n\n      const source = computesTemplateSourceFromComponent(component, props, null);\n      // Ideally we should stringify the object, but that could cause the story to break because of unescaped values in the JSON object.\n      // This will have to do for now\n      expect(source).toEqual(\n        `<doc-button [isDisabled]=\"false\" [label]=\"'Hello world'\" [someDataObject]=\"{one: 'Hello world', two: true, three: ['a string literal with \\\\'double quotes\\\\'', 'a string literal with \\\\'single quotes\\\\'', 'a single quoted string with \\\\'double quotes\\\\'', 'a double quoted string with \\\\'single quotes\\\\'', 'a single quoted string with escaped \\\\'single quotes\\\\'', 'a double quoted string with escaped \\\\'double quotes\\\\'', 'a string literal with \\\\'escaped single quotes\\\\'', 'a string literal with \\\\'escaped double quotes\\\\'']}\"></doc-button>`\n      );\n    });\n\n    it('should handle circular object as stringified', () => {\n      const component = InputComponent;\n\n      const someDataObject: ISomeInterface = {\n        one: 'Hello world',\n        two: true,\n        three: [\n          `a string literal with \"double quotes\"`,\n          `a string literal with 'single quotes'`,\n          'a single quoted string with \"double quotes\"',\n          \"a double quoted string with 'single quotes'\",\n\n          \"a single quoted string with escaped 'single quotes'\",\n\n          'a double quoted string with escaped \"double quotes\"',\n\n          `a string literal with \\'escaped single quotes\\'`,\n\n          `a string literal with \\\"escaped double quotes\\\"`,\n        ],\n      };\n      someDataObject.ref = someDataObject;\n\n      const props = {\n        isDisabled: false,\n        label: 'Hello world',\n        someDataObject,\n      };\n\n      const source = computesTemplateSourceFromComponent(component, props, null);\n      // Ideally we should stringify the object, but that could cause the story to break because of unescaped values in the JSON object.\n      // This will have to do for now\n      expect(source).toEqual(\n        `<doc-button [isDisabled]=\"false\" [label]=\"'Hello world'\" [someDataObject]=\"{one: 'Hello world', two: true, three: ['a string literal with \\\\'double quotes\\\\'', 'a string literal with \\\\'single quotes\\\\'', 'a single quoted string with \\\\'double quotes\\\\'', 'a double quoted string with \\\\'single quotes\\\\'', 'a single quoted string with escaped \\\\'single quotes\\\\'', 'a double quoted string with escaped \\\\'double quotes\\\\'', 'a string literal with \\\\'escaped single quotes\\\\'', 'a string literal with \\\\'escaped double quotes\\\\''], ref: '[Circular]'}\"></doc-button>`\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/ComputesTemplateFromComponent.ts",
    "content": "import type { ArgTypes } from 'storybook/internal/types';\n\nimport type { Type } from '@angular/core';\n\nimport type { ICollection } from '../types.ts';\nimport type { ComponentInputsOutputs } from './utils/NgComponentAnalyzer.ts';\nimport {\n  getComponentDecoratorMetadata,\n  getComponentInputsOutputs,\n} from './utils/NgComponentAnalyzer.ts';\n\n/**\n * Check if the name matches the criteria for a valid identifier. A valid identifier can only\n * contain letters, digits, underscores, or dollar signs. It cannot start with a digit.\n */\nconst isValidIdentifier = (name: string): boolean => /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);\n\n/**\n * Returns the property name, if it can be accessed with dot notation. If not, it returns\n * `this['propertyName']`.\n */\nexport const formatPropInTemplate = (propertyName: string) =>\n  isValidIdentifier(propertyName) ? propertyName : `this['${propertyName}']`;\n\nconst separateInputsOutputsAttributes = (\n  ngComponentInputsOutputs: ComponentInputsOutputs,\n  props: ICollection = {}\n) => {\n  const inputs = ngComponentInputsOutputs.inputs\n    .filter((i) => i.templateName in props)\n    .map((i) => i.templateName);\n  const outputs = ngComponentInputsOutputs.outputs\n    .filter((o) => o.templateName in props)\n    .map((o) => o.templateName);\n\n  return {\n    inputs,\n    outputs,\n    otherProps: Object.keys(props).filter((k) => ![...inputs, ...outputs].includes(k)),\n  };\n};\n\n/**\n * Converts a component into a template with inputs/outputs present in initial props\n *\n * @param component\n * @param initialProps\n * @param innerTemplate\n */\nexport const computesTemplateFromComponent = (\n  component: Type<unknown>,\n  initialProps?: ICollection,\n  innerTemplate = ''\n) => {\n  const ngComponentMetadata = getComponentDecoratorMetadata(component);\n  const ngComponentInputsOutputs = getComponentInputsOutputs(component);\n\n  if (!ngComponentMetadata.selector) {\n    // Allow to add renderer component when NgComponent selector is undefined\n    return `<ng-container *ngComponentOutlet=\"storyComponent\"></ng-container>`;\n  }\n\n  const { inputs: initialInputs, outputs: initialOutputs } = separateInputsOutputsAttributes(\n    ngComponentInputsOutputs,\n    initialProps\n  );\n\n  const templateInputs =\n    initialInputs.length > 0\n      ? ` ${initialInputs.map((i) => `[${i}]=\"${formatPropInTemplate(i)}\"`).join(' ')}`\n      : '';\n  const templateOutputs =\n    initialOutputs.length > 0\n      ? ` ${initialOutputs.map((i) => `(${i})=\"${formatPropInTemplate(i)}($event)\"`).join(' ')}`\n      : '';\n\n  return buildTemplate(\n    ngComponentMetadata.selector,\n    innerTemplate,\n    templateInputs,\n    templateOutputs\n  );\n};\n\n/** Stringify an object with a placholder in the circular references. */\nfunction stringifyCircular(obj: any) {\n  const seen = new Set();\n  return JSON.stringify(obj, (key, value) => {\n    if (typeof value === 'object' && value !== null) {\n      if (seen.has(value)) {\n        return '[Circular]';\n      }\n      seen.add(value);\n    }\n    return value;\n  });\n}\n\nconst createAngularInputProperty = ({\n  propertyName,\n  value,\n  argType,\n}: {\n  propertyName: string;\n  value: any;\n  argType?: ArgTypes[string];\n}) => {\n  let templateValue;\n  switch (typeof value) {\n    case 'string':\n      templateValue = `'${value}'`;\n      break;\n    case 'object':\n      templateValue = stringifyCircular(value)\n        .replace(/'/g, '\\u2019')\n        .replace(/\\\\\"/g, '\\u201D')\n        .replace(/\"([^-\"]+)\":/g, '$1: ')\n        .replace(/\"/g, \"'\")\n        .replace(/\\u2019/g, \"\\\\'\")\n        .replace(/\\u201D/g, \"\\\\'\")\n        .split(',')\n        .join(', ');\n      break;\n    default:\n      templateValue = value;\n  }\n\n  return `[${propertyName}]=\"${templateValue}\"`;\n};\n\n/**\n * Converts a component into a template with inputs/outputs present in initial props\n *\n * @param component\n * @param initialProps\n * @param innerTemplate\n */\nexport const computesTemplateSourceFromComponent = (\n  component: Type<unknown>,\n  initialProps?: ICollection,\n  argTypes?: ArgTypes\n) => {\n  const ngComponentMetadata = getComponentDecoratorMetadata(component);\n  if (!ngComponentMetadata) {\n    return null;\n  }\n\n  if (!ngComponentMetadata.selector) {\n    // Allow to add renderer component when NgComponent selector is undefined\n    return `<ng-container *ngComponentOutlet=\"${component.name}\"></ng-container>`;\n  }\n\n  const ngComponentInputsOutputs = getComponentInputsOutputs(component);\n  const { inputs: initialInputs, outputs: initialOutputs } = separateInputsOutputsAttributes(\n    ngComponentInputsOutputs,\n    initialProps\n  );\n\n  const templateInputs =\n    initialInputs.length > 0\n      ? ` ${initialInputs\n          .map((propertyName) =>\n            createAngularInputProperty({\n              propertyName,\n              value: initialProps[propertyName],\n              argType: argTypes?.[propertyName],\n            })\n          )\n          .join(' ')}`\n      : '';\n  const templateOutputs =\n    initialOutputs.length > 0\n      ? ` ${initialOutputs.map((i) => `(${i})=\"${formatPropInTemplate(i)}($event)\"`).join(' ')}`\n      : '';\n\n  return buildTemplate(ngComponentMetadata.selector, '', templateInputs, templateOutputs);\n};\n\nconst buildTemplate = (\n  selector: string,\n  innerTemplate: string,\n  inputs: string,\n  outputs: string\n) => {\n  // https://www.w3.org/TR/2011/WD-html-markup-20110113/syntax.html#syntax-elements\n  const voidElements = [\n    'area',\n    'base',\n    'br',\n    'col',\n    'command',\n    'embed',\n    'hr',\n    'img',\n    'input',\n    'keygen',\n    'link',\n    'meta',\n    'param',\n    'source',\n    'track',\n    'wbr',\n  ];\n\n  const firstSelector = selector.split(',')[0];\n  const templateReplacers: [\n    string | RegExp,\n    string | ((substring: string, ...args: any[]) => string),\n  ][] = [\n    [/(^.*?)(?=[,])/, '$1'],\n    [/(^\\..+)/, 'div$1'],\n    [/(^\\[.+?])/, 'div$1'],\n    [/([\\w[\\]]+)(\\s*,[\\w\\s-[\\],]+)+/, `$1`],\n    [/#([\\w-]+)/, ` id=\"$1\"`],\n    [/((\\.[\\w-]+)+)/, (_, c) => ` class=\"${c.split`.`.join` `.trim()}\"`],\n    [/(\\[.+?])/g, (_, a) => ` ${a.slice(1, -1)}`],\n    [\n      /([\\S]+)(.*)/,\n      (template, elementSelector) => {\n        return voidElements.some((element) => elementSelector === element)\n          ? template.replace(/([\\S]+)(.*)/, `<$1$2${inputs}${outputs} />`)\n          : template.replace(/([\\S]+)(.*)/, `<$1$2${inputs}${outputs}>${innerTemplate}</$1>`);\n      },\n    ],\n  ];\n\n  return templateReplacers.reduce(\n    (prevSelector, [searchValue, replacer]) => prevSelector.replace(searchValue, replacer as any),\n    firstSelector\n  );\n};\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/DocsRenderer.ts",
    "content": "import { DOCS_RENDERED, STORY_CHANGED } from 'storybook/internal/core-events';\nimport { addons } from 'storybook/preview-api';\n\nimport type { Parameters, StoryFnAngularReturnType } from '../types.ts';\nimport { AbstractRenderer, STORY_UID_ATTRIBUTE } from './AbstractRenderer.ts';\nimport { getNextStoryUID } from './utils/StoryUID.ts';\n\nexport class DocsRenderer extends AbstractRenderer {\n  public async render(options: {\n    storyId: string;\n    storyFnAngular: StoryFnAngularReturnType;\n    forced: boolean;\n    component: any;\n    parameters: Parameters;\n    targetDOMNode: HTMLElement;\n  }) {\n    const channel = addons.getChannel();\n    /**\n     * Destroy and recreate the PlatformBrowserDynamic of angular For several stories to be rendered\n     * in the same docs we should not destroy angular between each rendering but do it when the\n     * rendered stories are not needed anymore.\n     *\n     * Note for improvement: currently there is one event per story rendered in the doc. But one\n     * event could be enough for the whole docs\n     */\n    channel.once(STORY_CHANGED, async () => {\n      await DocsRenderer.resetApplications();\n    });\n\n    /**\n     * Destroy and recreate the PlatformBrowserDynamic of angular when doc re render. Allows to call\n     * ngOnDestroy of angular for previous component\n     */\n    channel.once(DOCS_RENDERED, async () => {\n      await DocsRenderer.resetApplications();\n    });\n\n    await super.render({ ...options, forced: false });\n  }\n\n  async beforeFullRender(domNode?: HTMLElement): Promise<void> {\n    DocsRenderer.resetApplications(domNode);\n  }\n\n  protected override initAngularRootElement(\n    targetDOMNode: HTMLElement,\n    targetSelector: string,\n    storyId: string\n  ): void {\n    super.initAngularRootElement(targetDOMNode, targetSelector, storyId);\n\n    targetDOMNode.setAttribute(STORY_UID_ATTRIBUTE, getNextStoryUID(storyId));\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/RendererFactory.test.ts",
    "content": "// @vitest-environment happy-dom\n\nimport { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';\nimport { Component, ɵresetJitOptions } from '@angular/core';\nimport { platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';\nimport { platformBrowserDynamic } from '@angular/platform-browser-dynamic';\n\nimport { CanvasRenderer } from './CanvasRenderer.ts';\nimport { RendererFactory } from './RendererFactory.ts';\nimport { DocsRenderer } from './DocsRenderer.ts';\n\nvi.mock('@angular/platform-browser-dynamic');\n\ndeclare const document: Document;\ndescribe('RendererFactory', () => {\n  let rendererFactory: RendererFactory;\n  let rootTargetDOMNode: HTMLElement;\n  let rootDocstargetDOMNode: HTMLElement;\n\n  beforeEach(async () => {\n    rendererFactory = new RendererFactory();\n    document.body.innerHTML =\n      '<div id=\"storybook-root\"></div><div id=\"root-docs\"><div id=\"story-in-docs\"></div></div>' +\n      '<div id=\"storybook-docs\"></div>';\n    rootTargetDOMNode = global.document.getElementById('storybook-root');\n    rootDocstargetDOMNode = global.document.getElementById('root-docs');\n    (platformBrowserDynamic as any).mockImplementation(platformBrowserDynamicTesting);\n    vi.spyOn(console, 'log').mockImplementation(() => {});\n    // @ts-expect-error Ignore\n    globalThis.STORYBOOK_ANGULAR_OPTIONS = { experimentalZoneless: false };\n  });\n\n  afterEach(() => {\n    vi.clearAllMocks();\n\n    // Necessary to avoid this error \"Provided value for `preserveWhitespaces` can not be changed once it has been set.\" :\n    // Source: https://github.com/angular/angular/commit/e342ffd855ffeb8af7067b42307ffa320d82177e#diff-92b125e532cc22977b46a91f068d6d7ea81fd61b772842a4a0212f1cfd875be6R28\n    ɵresetJitOptions();\n  });\n\n  describe('CanvasRenderer', () => {\n    it('should get CanvasRenderer instance', async () => {\n      const render = await rendererFactory.getRendererInstance(rootTargetDOMNode);\n      expect(render).toBeInstanceOf(CanvasRenderer);\n    });\n\n    it('should render my-story for story template', async () => {\n      const render = await rendererFactory.getRendererInstance(rootTargetDOMNode);\n      await render?.render({\n        storyFnAngular: {\n          template: '🦊',\n          props: {},\n        },\n        forced: false,\n        targetDOMNode: rootTargetDOMNode,\n        storyId: 'my-story',\n      });\n      expect(document.body.querySelector('#storybook-root').children[0].innerHTML).toBe('🦊');\n    });\n\n    it('should render my-story for story component', async () => {\n      @Component({ selector: 'foo', template: '🦊' })\n      class FooComponent {}\n\n      const render = await rendererFactory.getRendererInstance(rootTargetDOMNode);\n      await render?.render({\n        storyFnAngular: {\n          props: {},\n        },\n        forced: false,\n        component: FooComponent,\n        targetDOMNode: rootTargetDOMNode,\n        storyId: 'my-story',\n      });\n\n      expect(document.body.querySelector('#storybook-root').children[0].innerHTML).toBe(\n        '<foo>🦊</foo><!--container-->'\n      );\n    });\n\n    it('should handle circular reference in moduleMetadata', async () => {\n      class Thing {\n        token: Thing;\n\n        constructor() {\n          this.token = this;\n        }\n      }\n      const token = new Thing();\n\n      const render = await rendererFactory.getRendererInstance(rootTargetDOMNode);\n\n      await render?.render({\n        storyFnAngular: {\n          template: '🦊',\n          props: {},\n          moduleMetadata: { providers: [{ provide: 'foo', useValue: token }] },\n        },\n        forced: false,\n        targetDOMNode: rootTargetDOMNode,\n        storyId: 'my-story',\n      });\n\n      expect(document.body.querySelector('#storybook-root').children[0].innerHTML).toBe('🦊');\n    });\n\n    describe('when forced=true', () => {\n      beforeEach(async () => {\n        // Init first render\n        const render = await rendererFactory.getRendererInstance(rootTargetDOMNode);\n        await render?.render({\n          storyFnAngular: {\n            template: '{{ logo }}: {{ name }}',\n            props: {\n              logo: '🦊',\n              name: 'Fox',\n            },\n          },\n          forced: true,\n          targetDOMNode: rootTargetDOMNode,\n          storyId: 'my-story',\n        });\n      });\n\n      it('should be rendered a first time', async () => {\n        expect(document.body.querySelector('#storybook-root').children[0].innerHTML).toBe(\n          '🦊: Fox'\n        );\n      });\n\n      it('should not be re-rendered when only props change', async () => {\n        // only props change\n        const render = await rendererFactory.getRendererInstance(rootTargetDOMNode);\n        await render?.render({\n          storyFnAngular: {\n            props: {\n              logo: '👾',\n            },\n          },\n          forced: true,\n          targetDOMNode: rootTargetDOMNode,\n          storyId: 'my-story',\n        });\n\n        expect(document.body.querySelector('#storybook-root').children[0].innerHTML).toBe(\n          '👾: Fox'\n        );\n      });\n\n      it('should be re-rendered when template change', async () => {\n        const render = await rendererFactory.getRendererInstance(rootTargetDOMNode);\n        await render?.render({\n          storyFnAngular: {\n            template: '{{ beer }}',\n            props: {\n              beer: '🍺',\n            },\n          },\n          forced: true,\n          targetDOMNode: rootTargetDOMNode,\n          storyId: 'my-story',\n        });\n\n        expect(document.body.querySelector('#storybook-root').children[0].innerHTML).toBe('🍺');\n      });\n    });\n  });\n\n  describe('DocsRenderer', () => {\n    describe('when canvas render is done before', () => {\n      beforeEach(async () => {\n        // Init first Canvas render\n        const render = await rendererFactory.getRendererInstance(rootTargetDOMNode);\n        await render?.render({\n          storyFnAngular: {\n            template: 'Canvas 🖼',\n          },\n          forced: true,\n          targetDOMNode: rootTargetDOMNode,\n          storyId: 'my-story',\n        });\n      });\n\n      it('should reset root HTML', async () => {\n        global.document\n          .getElementById('storybook-root')\n          .appendChild(global.document.createElement('👾'));\n\n        expect(global.document.getElementById('storybook-root').innerHTML).toContain('Canvas 🖼');\n        await rendererFactory.getRendererInstance(rootDocstargetDOMNode);\n        expect(global.document.getElementById('storybook-root').innerHTML).toBe('');\n      });\n    });\n\n    it('should get DocsRenderer instance', async () => {\n      const render = await rendererFactory.getRendererInstance(rootDocstargetDOMNode);\n      expect(render).toBeInstanceOf(DocsRenderer);\n    });\n\n    describe('when multiple story for the same component', () => {\n      it('should render both stories', async () => {\n        @Component({ selector: 'foo', template: '🦊' })\n        class FooComponent {}\n\n        const render = await rendererFactory.getRendererInstance(\n          global.document.getElementById('storybook-docs')\n        );\n\n        const targetDOMNode1 = global.document.createElement('div');\n        targetDOMNode1.id = 'story-1';\n        global.document.getElementById('storybook-docs').appendChild(targetDOMNode1);\n        await render?.render({\n          storyFnAngular: {\n            props: {},\n          },\n          forced: false,\n          component: FooComponent,\n          targetDOMNode: targetDOMNode1,\n          storyId: 'story-1',\n        });\n\n        const targetDOMNode2 = global.document.createElement('div');\n        targetDOMNode2.id = 'story-1';\n        global.document.getElementById('storybook-docs').appendChild(targetDOMNode2);\n        await render?.render({\n          storyFnAngular: {\n            props: {},\n          },\n          forced: false,\n          component: FooComponent,\n          targetDOMNode: targetDOMNode2,\n          storyId: 'story-1',\n        });\n\n        expect(global.document.querySelectorAll('#story-1 > story-1')[0].innerHTML).toBe(\n          '<foo>🦊</foo><!--container-->'\n        );\n        expect(global.document.querySelectorAll('#story-1 > story-1')[1].innerHTML).toBe(\n          '<foo>🦊</foo><!--container-->'\n        );\n      });\n    });\n\n    describe('when bootstrapping multiple stories in parallel', () => {\n      it('should render both stories', async () => {\n        @Component({ selector: 'foo', template: '🦊' })\n        class FooComponent {}\n\n        const render = await rendererFactory.getRendererInstance(\n          global.document.getElementById('storybook-docs')\n        );\n\n        const targetDOMNode1 = global.document.createElement('div');\n        targetDOMNode1.id = 'story-1';\n        global.document.getElementById('storybook-docs').appendChild(targetDOMNode1);\n\n        const targetDOMNode2 = global.document.createElement('div');\n        targetDOMNode2.id = 'story-2';\n        global.document.getElementById('storybook-docs').appendChild(targetDOMNode2);\n\n        await Promise.all([\n          render.render({\n            storyFnAngular: {},\n            forced: false,\n            component: FooComponent,\n            targetDOMNode: targetDOMNode1,\n            storyId: 'story-1',\n          }),\n          render.render({\n            storyFnAngular: {},\n            forced: false,\n            component: FooComponent,\n            targetDOMNode: targetDOMNode2,\n            storyId: 'story-2',\n          }),\n        ]);\n\n        expect(global.document.querySelector('#story-1 > story-1').innerHTML).toBe(\n          '<foo>🦊</foo><!--container-->'\n        );\n        expect(global.document.querySelector('#story-2 > story-2').innerHTML).toBe(\n          '<foo>🦊</foo><!--container-->'\n        );\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/RendererFactory.ts",
    "content": "import { AbstractRenderer } from './AbstractRenderer.ts';\nimport { CanvasRenderer } from './CanvasRenderer.ts';\nimport { DocsRenderer } from './DocsRenderer.ts';\n\ntype RenderType = 'canvas' | 'docs';\nexport class RendererFactory {\n  private lastRenderType: RenderType;\n\n  private rendererMap = new Map<string, AbstractRenderer>();\n\n  public async getRendererInstance(targetDOMNode: HTMLElement): Promise<AbstractRenderer | null> {\n    const targetId = targetDOMNode.id;\n    // do nothing if the target node is null\n    // fix a problem when the docs asks 2 times the same component at the same time\n    // the 1st targetDOMNode of the 1st requested rendering becomes null 🤷‍♂️\n    if (targetDOMNode === null) {\n      return null;\n    }\n\n    const renderType = getRenderType(targetDOMNode);\n    // keep only instances of the same type\n    if (this.lastRenderType && this.lastRenderType !== renderType) {\n      await AbstractRenderer.resetApplications();\n      clearRootHTMLElement(renderType);\n      this.rendererMap.clear();\n    }\n\n    if (!this.rendererMap.has(targetId)) {\n      this.rendererMap.set(targetId, this.buildRenderer(renderType));\n    }\n\n    this.lastRenderType = renderType;\n    return this.rendererMap.get(targetId);\n  }\n\n  private buildRenderer(renderType: RenderType) {\n    if (renderType === 'docs') {\n      return new DocsRenderer();\n    }\n    return new CanvasRenderer();\n  }\n}\n\nexport const getRenderType = (targetDOMNode: HTMLElement): RenderType => {\n  return targetDOMNode.id === 'storybook-root' ? 'canvas' : 'docs';\n};\n\nexport function clearRootHTMLElement(renderType: RenderType) {\n  switch (renderType) {\n    case 'canvas':\n      global.document.getElementById('storybook-docs').innerHTML = '';\n      break;\n\n    case 'docs':\n      global.document.getElementById('storybook-root').innerHTML = '';\n      break;\n    default:\n      break;\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/StorybookModule.test.ts",
    "content": "// @vitest-environment happy-dom\n\nimport type { NgModule } from '@angular/core';\nimport { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { describe, expect, it } from 'vitest';\n\nimport { TestBed } from '@angular/core/testing';\nimport { BehaviorSubject } from 'rxjs';\nimport type { ICollection } from '../types.ts';\nimport { getApplication } from './StorybookModule.ts';\nimport { storyPropsProvider } from './StorybookProvider.ts';\nimport { PropertyExtractor } from './utils/PropertyExtractor.ts';\n\ndescribe('StorybookModule', () => {\n  describe('getStorybookModuleMetadata', () => {\n    describe('with simple component', () => {\n      @Component({\n        selector: 'foo',\n        template: `\n          <p id=\"input\">{{ input }}</p>\n          <p id=\"inputBindingPropertyName\">{{ localPropertyName }}</p>\n          <p id=\"setterCallNb\">{{ setterCallNb }}</p>\n          <p id=\"localProperty\">{{ localProperty }}</p>\n          <p id=\"localFunction\">{{ localFunction() }}</p>\n          <p id=\"output\" (click)=\"output.emit('outputEmitted')\"></p>\n          <p id=\"outputBindingPropertyName\" (click)=\"localOutput.emit('outputEmitted')\"></p>\n        `,\n      })\n      class FooComponent {\n        @Input()\n        public input: string;\n\n        @Input('inputBindingPropertyName')\n        public localPropertyName: string;\n\n        @Input()\n        public set setter(value: string) {\n          this.setterCallNb += 1;\n        }\n\n        @Output()\n        public output = new EventEmitter<string>();\n\n        @Output('outputBindingPropertyName')\n        public localOutput = new EventEmitter<string>();\n\n        public localProperty: string;\n\n        public localFunction = () => '';\n\n        public setterCallNb = 0;\n      }\n\n      it('should initialize inputs', async () => {\n        const props = {\n          input: 'input',\n          inputBindingPropertyName: 'inputBindingPropertyName',\n          localProperty: 'localProperty',\n          localFunction: () => 'localFunction',\n        };\n\n        const analyzedMetadata = new PropertyExtractor({}, FooComponent);\n        await analyzedMetadata.init();\n\n        const application = getApplication({\n          storyFnAngular: { props },\n          component: FooComponent,\n          targetSelector: 'my-selector',\n          analyzedMetadata,\n        });\n\n        const { fixture } = await configureTestingModule({\n          imports: [application],\n          providers: [storyPropsProvider(new BehaviorSubject<ICollection>(props))],\n        });\n        fixture.detectChanges();\n\n        expect(fixture.nativeElement.querySelector('p#input').innerHTML).toEqual(props.input);\n        expect(fixture.nativeElement.querySelector('p#inputBindingPropertyName').innerHTML).toEqual(\n          props.inputBindingPropertyName\n        );\n        expect(fixture.nativeElement.querySelector('p#localProperty').innerHTML).toEqual(\n          props.localProperty\n        );\n        expect(fixture.nativeElement.querySelector('p#localFunction').innerHTML).toEqual(\n          props.localFunction()\n        );\n      });\n\n      it('should initialize outputs', async () => {\n        let expectedOutputValue: string;\n        let expectedOutputBindingValue: string;\n        const props = {\n          output: (value: string) => {\n            expectedOutputValue = value;\n          },\n          outputBindingPropertyName: (value: string) => {\n            expectedOutputBindingValue = value;\n          },\n        };\n\n        const analyzedMetadata = new PropertyExtractor({}, FooComponent);\n        await analyzedMetadata.init();\n\n        const application = getApplication({\n          storyFnAngular: { props },\n          component: FooComponent,\n          targetSelector: 'my-selector',\n          analyzedMetadata,\n        });\n\n        const { fixture } = await configureTestingModule({\n          imports: [application],\n          providers: [storyPropsProvider(new BehaviorSubject<ICollection>(props))],\n        });\n        fixture.detectChanges();\n\n        fixture.nativeElement.querySelector('p#output').click();\n        fixture.nativeElement.querySelector('p#outputBindingPropertyName').click();\n\n        expect(expectedOutputValue).toEqual('outputEmitted');\n        expect(expectedOutputBindingValue).toEqual('outputEmitted');\n      });\n\n      it('should change inputs if storyProps$ Subject emit', async () => {\n        const initialProps = {\n          input: 'input',\n          inputBindingPropertyName: '',\n        };\n        const storyProps$ = new BehaviorSubject<ICollection>(initialProps);\n\n        const analyzedMetadata = new PropertyExtractor({}, FooComponent);\n        await analyzedMetadata.init();\n\n        const application = getApplication({\n          storyFnAngular: { props: initialProps },\n          component: FooComponent,\n          targetSelector: 'my-selector',\n          analyzedMetadata,\n        });\n        const { fixture } = await configureTestingModule({\n          imports: [application],\n          providers: [storyPropsProvider(storyProps$)],\n        });\n        fixture.detectChanges();\n\n        expect(fixture.nativeElement.querySelector('p#input').innerHTML).toEqual(\n          initialProps.input\n        );\n        expect(fixture.nativeElement.querySelector('p#inputBindingPropertyName').innerHTML).toEqual(\n          ''\n        );\n\n        const newProps = {\n          input: 'new input',\n          inputBindingPropertyName: 'new inputBindingPropertyName',\n          localProperty: 'new localProperty',\n          localFunction: () => 'new localFunction',\n        };\n        storyProps$.next(newProps);\n        fixture.detectChanges();\n\n        expect(fixture.nativeElement.querySelector('p#input').innerHTML).toEqual(newProps.input);\n        expect(fixture.nativeElement.querySelector('p#inputBindingPropertyName').innerHTML).toEqual(\n          newProps.inputBindingPropertyName\n        );\n        expect(fixture.nativeElement.querySelector('p#localProperty').innerHTML).toEqual(\n          newProps.localProperty\n        );\n        expect(fixture.nativeElement.querySelector('p#localFunction').innerHTML).toEqual(\n          newProps.localFunction()\n        );\n      });\n\n      it('should override outputs if storyProps$ Subject emit', async () => {\n        let expectedOutputValue;\n        let expectedOutputBindingValue;\n        const initialProps = {\n          input: '',\n          output: (value: string) => {\n            expectedOutputValue = value;\n          },\n          outputBindingPropertyName: (value: string) => {\n            expectedOutputBindingValue = value;\n          },\n        };\n        const storyProps$ = new BehaviorSubject<ICollection>(initialProps);\n\n        const analyzedMetadata = new PropertyExtractor({}, FooComponent);\n        await analyzedMetadata.init();\n\n        const application = getApplication({\n          storyFnAngular: { props: initialProps },\n          component: FooComponent,\n          targetSelector: 'my-selector',\n          analyzedMetadata,\n        });\n        const { fixture } = await configureTestingModule({\n          imports: [application],\n          providers: [storyPropsProvider(storyProps$)],\n        });\n        fixture.detectChanges();\n\n        const newProps = {\n          input: 'new input',\n          output: () => {\n            expectedOutputValue = 'should be called';\n          },\n          outputBindingPropertyName: () => {\n            expectedOutputBindingValue = 'should be called';\n          },\n        };\n        storyProps$.next(newProps);\n        fixture.detectChanges();\n\n        fixture.nativeElement.querySelector('p#output').click();\n        fixture.nativeElement.querySelector('p#outputBindingPropertyName').click();\n\n        expect(fixture.nativeElement.querySelector('p#input').innerHTML).toEqual(newProps.input);\n        expect(expectedOutputValue).toEqual('should be called');\n        expect(expectedOutputBindingValue).toEqual('should be called');\n      });\n\n      it('should change template inputs if storyProps$ Subject emit', async () => {\n        const initialProps = {\n          color: 'red',\n          input: 'input',\n        };\n        const storyProps$ = new BehaviorSubject<ICollection>(initialProps);\n\n        const analyzedMetadata = new PropertyExtractor({}, FooComponent);\n        await analyzedMetadata.init();\n\n        const application = getApplication({\n          storyFnAngular: {\n            props: initialProps,\n            template: '<p [style.color]=\"color\"><foo [input]=\"input\"></foo></p>',\n          },\n          component: FooComponent,\n          targetSelector: 'my-selector',\n          analyzedMetadata,\n        });\n        const { fixture } = await configureTestingModule({\n          imports: [application],\n          providers: [storyPropsProvider(storyProps$)],\n        });\n        fixture.detectChanges();\n        expect(fixture.nativeElement.querySelector('p').style.color).toEqual('red');\n        expect(fixture.nativeElement.querySelector('p#input').innerHTML).toEqual(\n          initialProps.input\n        );\n\n        const newProps = {\n          color: 'black',\n          input: 'new input',\n        };\n        storyProps$.next(newProps);\n        fixture.detectChanges();\n\n        expect(fixture.nativeElement.querySelector('p').style.color).toEqual('black');\n        expect(fixture.nativeElement.querySelector('p#input').innerHTML).toEqual(newProps.input);\n      });\n\n      it('should call the Input() setter the right number of times', async () => {\n        const initialProps = {\n          setter: 'init',\n        };\n        const storyProps$ = new BehaviorSubject<ICollection>(initialProps);\n\n        const analyzedMetadata = new PropertyExtractor({}, FooComponent);\n        await analyzedMetadata.init();\n\n        const application = getApplication({\n          storyFnAngular: { props: initialProps },\n          component: FooComponent,\n          targetSelector: 'my-selector',\n          analyzedMetadata,\n        });\n        const { fixture } = await configureTestingModule({\n          imports: [application],\n          providers: [storyPropsProvider(storyProps$)],\n        });\n\n        fixture.detectChanges();\n\n        expect(fixture.nativeElement.querySelector('p#setterCallNb').innerHTML).toEqual('1');\n\n        const newProps = {\n          setter: 'new setter value',\n        };\n        storyProps$.next(newProps);\n        fixture.detectChanges();\n\n        expect(fixture.nativeElement.querySelector('p#setterCallNb').innerHTML).toEqual('2');\n      });\n    });\n\n    describe('with component without selector', () => {\n      @Component({\n        template: `\n          The content\n        `,\n      })\n      class WithoutSelectorComponent {}\n\n      it('should display the component', async () => {\n        const props = {};\n\n        const analyzedMetadata = new PropertyExtractor(\n          { entryComponents: [WithoutSelectorComponent] },\n          WithoutSelectorComponent\n        );\n\n        await analyzedMetadata.init();\n\n        const application = getApplication({\n          storyFnAngular: {\n            props,\n            moduleMetadata: { entryComponents: [WithoutSelectorComponent] },\n          },\n          component: WithoutSelectorComponent,\n          targetSelector: 'my-selector',\n          analyzedMetadata,\n        });\n\n        const { fixture } = await configureTestingModule({\n          imports: [application],\n          providers: [storyPropsProvider(new BehaviorSubject<ICollection>(props))],\n        });\n        fixture.detectChanges();\n\n        expect(fixture.nativeElement.innerHTML).toContain('The content');\n      });\n    });\n\n    it('should keep template with an empty value', async () => {\n      @Component({\n        selector: 'foo',\n        template: `\n          Should not be displayed\n        `,\n      })\n      class FooComponent {}\n\n      const analyzedMetadata = new PropertyExtractor({}, FooComponent);\n      await analyzedMetadata.init();\n\n      const application = getApplication({\n        storyFnAngular: { template: '' },\n        component: FooComponent,\n        targetSelector: 'my-selector',\n        analyzedMetadata,\n      });\n\n      const { fixture } = await configureTestingModule({\n        imports: [application],\n        providers: [storyPropsProvider(new BehaviorSubject<ICollection>({}))],\n      });\n      fixture.detectChanges();\n\n      expect(fixture.nativeElement.innerHTML).toEqual('');\n    });\n  });\n\n  async function configureTestingModule(ngModule: NgModule) {\n    await TestBed.configureTestingModule(ngModule).compileComponents();\n\n    const fixture = TestBed.createComponent(ngModule.imports[0] as any);\n\n    return {\n      fixture,\n    };\n  }\n});\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/StorybookModule.ts",
    "content": "import type { StoryFnAngularReturnType } from '../types.ts';\nimport { computesTemplateFromComponent } from './ComputesTemplateFromComponent.ts';\nimport { createStorybookWrapperComponent } from './StorybookWrapperComponent.ts';\nimport type { PropertyExtractor } from './utils/PropertyExtractor.ts';\n\nexport const getApplication = ({\n  storyFnAngular,\n  component,\n  targetSelector,\n  analyzedMetadata,\n}: {\n  storyFnAngular: StoryFnAngularReturnType;\n  component?: any;\n  targetSelector: string;\n  analyzedMetadata: PropertyExtractor;\n}) => {\n  const { props, styles, moduleMetadata = {} } = storyFnAngular;\n  let { template } = storyFnAngular;\n\n  const hasTemplate = !hasNoTemplate(template);\n  if (!hasTemplate && component) {\n    template = computesTemplateFromComponent(component, props, '');\n  }\n\n  /** Create a component that wraps generated template and gives it props */\n  return createStorybookWrapperComponent({\n    moduleMetadata,\n    selector: targetSelector,\n    template,\n    storyComponent: component,\n    styles,\n    initialProps: props,\n    analyzedMetadata,\n  });\n};\n\nfunction hasNoTemplate(template: string | null | undefined): template is undefined {\n  return template === null || template === undefined;\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/StorybookProvider.ts",
    "content": "import type { Provider } from '@angular/core';\nimport { InjectionToken, NgZone } from '@angular/core';\nimport type { Subject, Subscriber } from 'rxjs';\nimport { Observable } from 'rxjs';\n\nimport type { ICollection } from '../types.ts';\n\nexport const STORY_PROPS = new InjectionToken<Subject<ICollection | undefined>>('STORY_PROPS');\n\nexport const storyPropsProvider = (storyProps$: Subject<ICollection | undefined>): Provider => ({\n  provide: STORY_PROPS,\n  useFactory: storyDataFactory(storyProps$.asObservable()),\n  deps: [NgZone],\n});\n\nfunction storyDataFactory<T>(data: Observable<T>) {\n  return (ngZone: NgZone) =>\n    new Observable((subscriber: Subscriber<T>) => {\n      const sub = data.subscribe(\n        (v: T) => {\n          ngZone.run(() => subscriber.next(v));\n        },\n        (err) => {\n          ngZone.run(() => subscriber.error(err));\n        },\n        () => {\n          ngZone.run(() => subscriber.complete());\n        }\n      );\n\n      return () => {\n        sub.unsubscribe();\n      };\n    });\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/StorybookWrapperComponent.ts",
    "content": "import type { AfterViewInit, ElementRef, OnDestroy, Type } from '@angular/core';\nimport {\n  ChangeDetectorRef,\n  Component,\n  Inject,\n  NgModule,\n  ViewChild,\n  ViewContainerRef,\n} from '@angular/core';\nimport type { Subject, Subscription } from 'rxjs';\nimport { map, skip } from 'rxjs/operators';\n\nimport type { ICollection, NgModuleMetadata } from '../types.ts';\nimport { STORY_PROPS } from './StorybookProvider.ts';\nimport type { ComponentInputsOutputs } from './utils/NgComponentAnalyzer.ts';\nimport { getComponentInputsOutputs } from './utils/NgComponentAnalyzer.ts';\nimport { PropertyExtractor } from './utils/PropertyExtractor.ts';\n\nconst getNonInputsOutputsProps = (\n  ngComponentInputsOutputs: ComponentInputsOutputs,\n  props: ICollection = {}\n) => {\n  const inputs = ngComponentInputsOutputs.inputs\n    .filter((i) => i.templateName in props)\n    .map((i) => i.templateName);\n  const outputs = ngComponentInputsOutputs.outputs\n    .filter((o) => o.templateName in props)\n    .map((o) => o.templateName);\n  return Object.keys(props).filter((k) => ![...inputs, ...outputs].includes(k));\n};\n\n/** Wraps the story template into a component */\nexport const createStorybookWrapperComponent = ({\n  selector,\n  template,\n  storyComponent,\n  styles,\n  moduleMetadata,\n  initialProps,\n  analyzedMetadata,\n}: {\n  selector: string;\n  template: string;\n  storyComponent: Type<unknown> | undefined;\n  styles: string[];\n  moduleMetadata: NgModuleMetadata;\n  initialProps?: ICollection;\n  analyzedMetadata: PropertyExtractor;\n}): Type<any> => {\n  // In ivy, a '' selector is not allowed, therefore we need to just set it to anything if\n  // storyComponent was not provided.\n  const viewChildSelector = storyComponent ?? '__storybook-noop';\n\n  const { imports, declarations, providers } = analyzedMetadata;\n\n  @NgModule({\n    declarations,\n    imports,\n    exports: [...declarations, ...imports],\n  })\n  class StorybookComponentModule {}\n\n  PropertyExtractor.warnImportsModuleWithProviders(analyzedMetadata);\n\n  @Component({\n    selector,\n    template,\n    standalone: true,\n    imports: [StorybookComponentModule],\n    providers,\n    styles,\n    schemas: moduleMetadata.schemas,\n  })\n  class StorybookWrapperComponent implements AfterViewInit, OnDestroy {\n    private storyComponentPropsSubscription: Subscription;\n\n    private storyWrapperPropsSubscription: Subscription;\n\n    @ViewChild(viewChildSelector, { static: true }) storyComponentElementRef: ElementRef;\n\n    @ViewChild(viewChildSelector, { read: ViewContainerRef, static: true })\n    storyComponentViewContainerRef: ViewContainerRef;\n\n    // Used in case of a component without selector\n    storyComponent = storyComponent ?? '';\n\n    constructor(\n      @Inject(STORY_PROPS) private storyProps$: Subject<ICollection | undefined>,\n      @Inject(ChangeDetectorRef) private changeDetectorRef: ChangeDetectorRef\n    ) {}\n\n    ngOnInit(): void {\n      // Subscribes to the observable storyProps$ to keep these properties up to date\n      this.storyWrapperPropsSubscription = this.storyProps$.subscribe((storyProps = {}) => {\n        // All props are added as component properties\n        Object.assign(this, storyProps);\n\n        this.changeDetectorRef.detectChanges();\n        this.changeDetectorRef.markForCheck();\n      });\n    }\n\n    ngAfterViewInit(): void {\n      // Bind properties to component, if the story have component\n      if (this.storyComponentElementRef) {\n        const ngComponentInputsOutputs = getComponentInputsOutputs(storyComponent);\n\n        const initialOtherProps = getNonInputsOutputsProps(ngComponentInputsOutputs, initialProps);\n\n        // Initializes properties that are not Inputs | Outputs\n        // Allows story props to override local component properties\n        initialOtherProps.forEach((p) => {\n          (this.storyComponentElementRef as any)[p] = initialProps[p];\n        });\n        // `markForCheck` the component in case this uses changeDetection: OnPush\n        // And then forces the `detectChanges`\n        this.storyComponentViewContainerRef.injector.get(ChangeDetectorRef).markForCheck();\n        this.changeDetectorRef.detectChanges();\n\n        // Once target component has been initialized, the storyProps$ observable keeps target component properties than are not Input|Output up to date\n        this.storyComponentPropsSubscription = this.storyProps$\n          .pipe(\n            skip(1),\n            map((props) => {\n              const propsKeyToKeep = getNonInputsOutputsProps(ngComponentInputsOutputs, props);\n              return propsKeyToKeep.reduce((acc, p) => ({ ...acc, [p]: props[p] }), {});\n            })\n          )\n          .subscribe((props) => {\n            // Replace inputs with new ones from props\n            Object.assign(this.storyComponentElementRef, props);\n\n            // `markForCheck` the component in case this uses changeDetection: OnPush\n            // And then forces the `detectChanges`\n            this.storyComponentViewContainerRef.injector.get(ChangeDetectorRef).markForCheck();\n            this.changeDetectorRef.detectChanges();\n          });\n      }\n    }\n\n    ngOnDestroy(): void {\n      if (this.storyComponentPropsSubscription != null) {\n        this.storyComponentPropsSubscription.unsubscribe();\n      }\n      if (this.storyWrapperPropsSubscription != null) {\n        this.storyWrapperPropsSubscription.unsubscribe();\n      }\n    }\n  }\n  return StorybookWrapperComponent;\n};\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/__testfixtures__/input.component.ts",
    "content": "import { Component, EventEmitter, Input, Output } from '@angular/core';\n\nexport const exportedConstant = 'An exported constant';\n\nexport enum ButtonAccent {\n  'Normal' = 'Normal',\n  'High' = 'High',\n}\n\nexport interface ISomeInterface {\n  one: string;\n  two: boolean;\n  three: any[];\n  ref?: ISomeInterface;\n}\n\n@Component({\n  selector: 'doc-button',\n  template: '<button>{{ label }}</button>',\n})\nexport class InputComponent<T> {\n  /** Appearance style of the button. */\n  @Input()\n  public appearance: 'primary' | 'secondary' = 'secondary';\n\n  @Input()\n  public counter: number;\n\n  /** Specify the accent-type of the button */\n  @Input()\n  public accent: ButtonAccent;\n\n  /** To test source-generation with overridden propertyname */\n  @Input('color') public foregroundColor: string;\n\n  /** Sets the button to a disabled state. */\n  @Input()\n  public isDisabled = false;\n\n  @Input()\n  public label: string;\n\n  @Input('aria-label') public ariaLabel: string;\n\n  /** Specifies some arbitrary object */\n  @Input() public someDataObject: ISomeInterface;\n\n  @Output()\n  public onClick = new EventEmitter<Event>();\n\n  @Output('dash-out') public dashOut = new EventEmitter<any>();\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/__testfixtures__/test.module.ts",
    "content": "import { CommonModule } from '@angular/common';\nimport { HttpClientModule } from '@angular/common/http';\nimport { NgModule } from '@angular/core';\n\n@NgModule({\n  imports: [CommonModule, HttpClientModule],\n})\nexport class WithOfficialModule {}\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/utils/BootstrapQueue.test.ts",
    "content": "// @vitest-environment happy-dom\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { Subject, lastValueFrom } from 'rxjs';\n\nimport { queueBootstrapping } from './BootstrapQueue.ts';\n\nconst instantWaitFor = (fn: () => void) => {\n  return vi.waitFor(fn, {\n    interval: 0,\n    timeout: 10000,\n  });\n};\n\ndescribe('BootstrapQueue', { retry: 3 }, () => {\n  beforeEach(async () => {\n    vi.spyOn(console, 'log').mockImplementation(() => {});\n  });\n\n  afterEach(() => {\n    vi.clearAllMocks();\n  });\n\n  it('@flaky should wait until complete', async () => {\n    const pendingSubject = new Subject<void>();\n    const bootstrapApp = vi.fn().mockImplementation(async () => {\n      return lastValueFrom(pendingSubject);\n    });\n    const bootstrapAppFinished = vi.fn();\n\n    queueBootstrapping(bootstrapApp).then(() => {\n      bootstrapAppFinished();\n    });\n\n    await instantWaitFor(() => {\n      if (bootstrapApp.mock.calls.length !== 1) {\n        throw new Error('bootstrapApp should not have been called yet');\n      }\n    });\n\n    expect(bootstrapApp).toHaveBeenCalled();\n    expect(bootstrapAppFinished).not.toHaveBeenCalled();\n\n    pendingSubject.next();\n    pendingSubject.complete();\n\n    await instantWaitFor(() => {\n      if (bootstrapAppFinished.mock.calls.length !== 1) {\n        throw new Error('bootstrapApp should have been called once');\n      }\n    });\n\n    expect(bootstrapAppFinished).toHaveBeenCalled();\n  });\n\n  it('should prevent following tasks, until the preview tasks are complete', async () => {\n    const pendingSubject = new Subject<void>();\n    const bootstrapApp = vi.fn().mockImplementation(async () => {\n      return lastValueFrom(pendingSubject);\n    });\n    const bootstrapAppFinished = vi.fn();\n\n    const pendingSubject2 = new Subject<void>();\n    const bootstrapApp2 = vi.fn().mockImplementation(async () => {\n      return lastValueFrom(pendingSubject2);\n    });\n    const bootstrapAppFinished2 = vi.fn();\n\n    const pendingSubject3 = new Subject<void>();\n    const bootstrapApp3 = vi.fn().mockImplementation(async () => {\n      return lastValueFrom(pendingSubject3);\n    });\n    const bootstrapAppFinished3 = vi.fn();\n\n    queueBootstrapping(bootstrapApp).then(bootstrapAppFinished);\n    queueBootstrapping(bootstrapApp2).then(bootstrapAppFinished2);\n    queueBootstrapping(bootstrapApp3).then(bootstrapAppFinished3);\n\n    await instantWaitFor(() => {\n      if (bootstrapApp.mock.calls.length !== 1) {\n        throw new Error('bootstrapApp should have been called once');\n      }\n    });\n\n    expect(bootstrapApp).toHaveBeenCalled();\n    expect(bootstrapAppFinished).not.toHaveBeenCalled();\n    expect(bootstrapApp2).not.toHaveBeenCalled();\n    expect(bootstrapAppFinished2).not.toHaveBeenCalled();\n    expect(bootstrapApp3).not.toHaveBeenCalled();\n    expect(bootstrapAppFinished3).not.toHaveBeenCalled();\n\n    pendingSubject.next();\n    pendingSubject.complete();\n\n    await instantWaitFor(() => {\n      if (bootstrapApp2.mock.calls.length !== 1) {\n        throw new Error('bootstrapApp2 should have been called once');\n      }\n    });\n\n    expect(bootstrapApp).toHaveReturnedTimes(1);\n    expect(bootstrapAppFinished).toHaveBeenCalled();\n    expect(bootstrapApp2).toHaveBeenCalled();\n    expect(bootstrapAppFinished2).not.toHaveBeenCalled();\n    expect(bootstrapApp3).not.toHaveBeenCalled();\n    expect(bootstrapAppFinished3).not.toHaveBeenCalled();\n\n    pendingSubject2.next();\n    pendingSubject2.complete();\n\n    await instantWaitFor(() => {\n      if (bootstrapApp3.mock.calls.length !== 1) {\n        throw new Error('bootstrapApp3 should have been called once');\n      }\n    });\n\n    expect(bootstrapApp).toHaveReturnedTimes(1);\n    expect(bootstrapAppFinished).toHaveBeenCalled();\n    expect(bootstrapApp2).toHaveReturnedTimes(1);\n    expect(bootstrapAppFinished2).toHaveBeenCalled();\n    expect(bootstrapApp3).toHaveBeenCalled();\n    expect(bootstrapAppFinished3).not.toHaveBeenCalled();\n\n    pendingSubject3.next();\n    pendingSubject3.complete();\n\n    await instantWaitFor(() => {\n      if (bootstrapAppFinished3.mock.calls.length !== 1) {\n        throw new Error('bootstrapAppFinished3 should have been called once');\n      }\n    });\n\n    expect(bootstrapApp).toHaveReturnedTimes(1);\n    expect(bootstrapAppFinished).toHaveBeenCalled();\n    expect(bootstrapApp2).toHaveReturnedTimes(1);\n    expect(bootstrapAppFinished2).toHaveBeenCalled();\n    expect(bootstrapApp3).toHaveReturnedTimes(1);\n    expect(bootstrapAppFinished3).toHaveBeenCalled();\n  });\n\n  it('should throw and continue next bootstrap on error', async () => {\n    const pendingSubject = new Subject<void>();\n    const bootstrapApp = vi.fn().mockImplementation(async () => {\n      return lastValueFrom(pendingSubject);\n    });\n    const bootstrapAppFinished = vi.fn();\n    const bootstrapAppError = vi.fn();\n\n    const pendingSubject2 = new Subject<void>();\n    const bootstrapApp2 = vi.fn().mockImplementation(async () => {\n      return lastValueFrom(pendingSubject2);\n    });\n    const bootstrapAppFinished2 = vi.fn();\n    const bootstrapAppError2 = vi.fn();\n\n    queueBootstrapping(bootstrapApp).then(bootstrapAppFinished).catch(bootstrapAppError);\n    queueBootstrapping(bootstrapApp2).then(bootstrapAppFinished2).catch(bootstrapAppError2);\n\n    await instantWaitFor(() => {\n      if (bootstrapApp.mock.calls.length !== 1) {\n        throw new Error('bootstrapApp should have been called once');\n      }\n    });\n\n    expect(bootstrapApp).toHaveBeenCalledTimes(1);\n    expect(bootstrapAppFinished).not.toHaveBeenCalled();\n    expect(bootstrapApp2).not.toHaveBeenCalled();\n\n    pendingSubject.error(new Error('test error'));\n\n    await instantWaitFor(() => {\n      if (bootstrapAppError.mock.calls.length !== 1) {\n        throw new Error('bootstrapAppError should have been called once');\n      }\n    });\n\n    expect(bootstrapApp).toHaveBeenCalledTimes(1);\n    expect(bootstrapAppFinished).not.toHaveBeenCalled();\n    expect(bootstrapAppError).toHaveBeenCalledTimes(1);\n    expect(bootstrapApp2).toHaveBeenCalledTimes(1);\n    expect(bootstrapAppFinished2).not.toHaveBeenCalled();\n    expect(bootstrapAppError2).not.toHaveBeenCalled();\n\n    pendingSubject2.next();\n    pendingSubject2.complete();\n\n    await instantWaitFor(() => {\n      if (bootstrapAppFinished2.mock.calls.length !== 1) {\n        throw new Error('bootstrapAppFinished2 should have been called once');\n      }\n    });\n\n    expect(bootstrapApp).toHaveBeenCalledTimes(1);\n    expect(bootstrapAppFinished).not.toHaveBeenCalled();\n    expect(bootstrapAppError).toHaveBeenCalledTimes(1);\n    expect(bootstrapApp2).toHaveBeenCalledTimes(1);\n    expect(bootstrapAppFinished2).toHaveBeenCalledTimes(1);\n    expect(bootstrapAppError2).not.toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/utils/BootstrapQueue.ts",
    "content": "import type { ApplicationRef } from '@angular/core';\n\nconst queue: Array<() => Promise<void>> = [];\nlet isProcessing = false;\n\n/**\n * Reset compiled components because we often want to compile the same component with more than one\n * NgModule.\n */\nconst resetCompiledComponents = async () => {\n  try {\n    // Clear global Angular component cache in order to be able to re-render the same component across multiple stories\n    //\n    // References:\n    // https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/build_angular/src/webpack/plugins/hmr/hmr-accept.ts#L50\n    // https://github.com/angular/angular/blob/2ebe2bcb2fe19bf672316b05f15241fd7fd40803/packages/core/src/render3/jit/module.ts#L377-L384\n    const { ɵresetCompiledComponents } = await import('@angular/core');\n    ɵresetCompiledComponents();\n  } catch (e) {\n    /** Noop catch This means angular removed or modified ɵresetCompiledComponents */\n  }\n};\n\n/**\n * Queue bootstrapping, so that only one application can be bootstrapped at a time.\n *\n * Bootstrapping multiple applications at once can cause Angular to throw an error that a component\n * is declared in multiple modules. This avoids two stories confusing the Angular compiler, by\n * bootstrapping more that one application at a time.\n *\n * @param fn Callback that should complete the bootstrap process\n * @returns ApplicationRef from the completed bootstrap process\n */\nexport const queueBootstrapping = (fn: () => Promise<ApplicationRef>): Promise<ApplicationRef> => {\n  return new Promise<ApplicationRef>((resolve, reject) => {\n    queue.push(() => fn().then(resolve).catch(reject));\n\n    if (!isProcessing) {\n      processQueue();\n    }\n  });\n};\n\nconst processQueue = async () => {\n  isProcessing = true;\n\n  while (queue.length > 0) {\n    const bootstrappingFn = queue.shift();\n    if (bootstrappingFn) {\n      await bootstrappingFn();\n      await resetCompiledComponents();\n    }\n  }\n\n  isProcessing = false;\n};\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/utils/NgComponentAnalyzer.test.ts",
    "content": "// @vitest-environment happy-dom\n\nimport type { Type } from '@angular/core';\nimport {\n  Component,\n  ComponentFactoryResolver,\n  Directive,\n  EventEmitter,\n  HostBinding,\n  Injectable,\n  Input,\n  Output,\n  Pipe,\n  input,\n  output,\n} from '@angular/core';\nimport { TestBed } from '@angular/core/testing';\nimport { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';\nimport { describe, expect, it } from 'vitest';\n\nimport {\n  getComponentInputsOutputs,\n  isComponent,\n  isDeclarable,\n  getComponentDecoratorMetadata,\n  isStandaloneComponent,\n} from './NgComponentAnalyzer.ts';\n\ndescribe('getComponentInputsOutputs', () => {\n  it('should return empty if no I/O found', () => {\n    @Component({\n      standalone: false,\n    })\n    class FooComponent {}\n\n    expect(getComponentInputsOutputs(FooComponent)).toEqual({\n      inputs: [],\n      outputs: [],\n    });\n\n    class BarComponent {}\n\n    expect(getComponentInputsOutputs(BarComponent)).toEqual({\n      inputs: [],\n      outputs: [],\n    });\n  });\n\n  it('should return I/O', () => {\n    @Component({\n      template: '',\n      inputs: ['inputInComponentMetadata'],\n      outputs: ['outputInComponentMetadata'],\n      standalone: false,\n    })\n    class FooComponent {\n      @Input()\n      public input: string;\n\n      public signalInput = input<string>();\n\n      public signalInputAliased = input<string>('signalInputAliased', {\n        alias: 'signalInputAliasedAlias',\n      });\n\n      @Input('inputPropertyName')\n      public inputWithBindingPropertyName: string;\n\n      @Output()\n      public output = new EventEmitter<Event>();\n\n      @Output('outputPropertyName')\n      public outputWithBindingPropertyName = new EventEmitter<Event>();\n\n      public signalOutput = output<string>();\n    }\n\n    const fooComponentFactory = resolveComponentFactory(FooComponent);\n\n    const { inputs, outputs } = getComponentInputsOutputs(FooComponent);\n\n    expect({ inputs, outputs }).toEqual({\n      inputs: [\n        { propName: 'inputInComponentMetadata', templateName: 'inputInComponentMetadata' },\n        { propName: 'input', templateName: 'input' },\n        { propName: 'inputWithBindingPropertyName', templateName: 'inputPropertyName' },\n      ],\n      outputs: [\n        { propName: 'outputInComponentMetadata', templateName: 'outputInComponentMetadata' },\n        { propName: 'output', templateName: 'output' },\n        { propName: 'outputWithBindingPropertyName', templateName: 'outputPropertyName' },\n      ],\n    });\n\n    expect(sortByPropName(inputs)).toEqual(\n      sortByPropName(fooComponentFactory.inputs.map(({ isSignal, ...rest }) => rest))\n    );\n    expect(sortByPropName(outputs)).toEqual(sortByPropName(fooComponentFactory.outputs));\n  });\n\n  it(\"should return I/O when some of component metadata has the same name as one of component's properties\", () => {\n    @Component({\n      template: '',\n      inputs: ['input', 'inputWithBindingPropertyName'],\n      outputs: ['outputWithBindingPropertyName'],\n      standalone: false,\n    })\n    class FooComponent {\n      @Input()\n      public input: string;\n\n      @Input('inputPropertyName')\n      public inputWithBindingPropertyName: string;\n\n      @Output()\n      public output = new EventEmitter<Event>();\n\n      @Output('outputPropertyName')\n      public outputWithBindingPropertyName = new EventEmitter<Event>();\n    }\n\n    const fooComponentFactory = resolveComponentFactory(FooComponent);\n\n    const { inputs, outputs } = getComponentInputsOutputs(FooComponent);\n\n    expect(sortByPropName(inputs)).toEqual(\n      sortByPropName(fooComponentFactory.inputs.map(({ isSignal, ...rest }) => rest))\n    );\n    expect(sortByPropName(outputs)).toEqual(sortByPropName(fooComponentFactory.outputs));\n  });\n\n  it('should return I/O in the presence of multiple decorators', () => {\n    @Component({\n      template: '',\n      standalone: false,\n    })\n    class FooComponent {\n      @Input()\n      @HostBinding('class.preceeding-first')\n      public inputPreceedingHostBinding: string;\n\n      @HostBinding('class.following-binding')\n      @Input()\n      public inputFollowingHostBinding: string;\n    }\n\n    const fooComponentFactory = resolveComponentFactory(FooComponent);\n\n    const { inputs, outputs } = getComponentInputsOutputs(FooComponent);\n\n    expect({ inputs, outputs }).toEqual({\n      inputs: [\n        { propName: 'inputPreceedingHostBinding', templateName: 'inputPreceedingHostBinding' },\n        { propName: 'inputFollowingHostBinding', templateName: 'inputFollowingHostBinding' },\n      ],\n      outputs: [],\n    });\n\n    expect(sortByPropName(inputs)).toEqual(\n      sortByPropName(fooComponentFactory.inputs.map(({ isSignal, ...rest }) => rest))\n    );\n    expect(sortByPropName(outputs)).toEqual(sortByPropName(fooComponentFactory.outputs));\n  });\n\n  it('should return I/O with extending classes', () => {\n    @Component({\n      template: '',\n      standalone: false,\n    })\n    class BarComponent {\n      @Input()\n      public a: string;\n\n      @Input()\n      public b: string;\n    }\n\n    @Component({\n      template: '',\n      standalone: false,\n    })\n    class FooComponent extends BarComponent {\n      @Input()\n      declare public b: string;\n\n      @Input()\n      public c: string;\n    }\n\n    const fooComponentFactory = resolveComponentFactory(FooComponent);\n\n    const { inputs, outputs } = getComponentInputsOutputs(FooComponent);\n\n    expect({ inputs, outputs }).toEqual({\n      inputs: [\n        { propName: 'a', templateName: 'a' },\n        { propName: 'b', templateName: 'b' },\n        { propName: 'c', templateName: 'c' },\n      ],\n      outputs: [],\n    });\n\n    expect(sortByPropName(inputs)).toEqual(\n      sortByPropName(fooComponentFactory.inputs.map(({ isSignal, ...rest }) => rest))\n    );\n    expect(sortByPropName(outputs)).toEqual(sortByPropName(fooComponentFactory.outputs));\n  });\n});\n\ndescribe('isDeclarable', () => {\n  it('should return true with a Component', () => {\n    @Component({})\n    class FooComponent {}\n\n    expect(isDeclarable(FooComponent)).toEqual(true);\n  });\n\n  it('should return true with a Directive', () => {\n    @Directive({})\n    class FooDirective {}\n\n    expect(isDeclarable(FooDirective)).toEqual(true);\n  });\n\n  it('should return true with a Pipe', () => {\n    @Pipe({ name: 'pipe' })\n    class FooPipe {}\n\n    expect(isDeclarable(FooPipe)).toEqual(true);\n  });\n\n  it('should return false with simple class', () => {\n    class FooPipe {}\n\n    expect(isDeclarable(FooPipe)).toEqual(false);\n  });\n  it('should return false with Injectable', () => {\n    @Injectable()\n    class FooInjectable {}\n\n    expect(isDeclarable(FooInjectable)).toEqual(false);\n  });\n});\n\ndescribe('isComponent', () => {\n  it('should return true with a Component', () => {\n    @Component({})\n    class FooComponent {}\n\n    expect(isComponent(FooComponent)).toEqual(true);\n  });\n\n  it('should return false with simple class', () => {\n    class FooPipe {}\n\n    expect(isComponent(FooPipe)).toEqual(false);\n  });\n  it('should return false with Directive', () => {\n    @Directive()\n    class FooDirective {}\n\n    expect(isComponent(FooDirective)).toEqual(false);\n  });\n});\n\ndescribe('isStandaloneComponent', () => {\n  it('should return true with a Component with \"standalone: true\"', () => {\n    @Component({ standalone: true })\n    class FooComponent {}\n\n    expect(isStandaloneComponent(FooComponent)).toEqual(true);\n  });\n\n  it('should return false with a Component with \"standalone: false\"', () => {\n    @Component({ standalone: false })\n    class FooComponent {}\n\n    expect(isStandaloneComponent(FooComponent)).toEqual(false);\n  });\n\n  it('should return false with a Component without the \"standalone\" property', () => {\n    @Component({})\n    class FooComponent {}\n\n    expect(isStandaloneComponent(FooComponent)).toEqual(false);\n  });\n\n  it('should return false with simple class', () => {\n    class FooPipe {}\n\n    expect(isStandaloneComponent(FooPipe)).toEqual(false);\n  });\n\n  it('should return true with a Directive with \"standalone: true\"', () => {\n    @Directive({ standalone: true })\n    class FooDirective {}\n\n    expect(isStandaloneComponent(FooDirective)).toEqual(true);\n  });\n\n  it('should return false with a Directive with \"standalone: false\"', () => {\n    @Directive({ standalone: false })\n    class FooDirective {}\n\n    expect(isStandaloneComponent(FooDirective)).toEqual(false);\n  });\n\n  it('should return false with Directive without the \"standalone\" property', () => {\n    @Directive()\n    class FooDirective {}\n\n    expect(isStandaloneComponent(FooDirective)).toEqual(false);\n  });\n\n  it('should return true with a Pipe with \"standalone: true\"', () => {\n    @Pipe({ name: 'FooPipe', standalone: true })\n    class FooPipe {}\n\n    expect(isStandaloneComponent(FooPipe)).toEqual(true);\n  });\n\n  it('should return false with a Pipe with \"standalone: false\"', () => {\n    @Pipe({ name: 'FooPipe', standalone: false })\n    class FooPipe {}\n\n    expect(isStandaloneComponent(FooPipe)).toEqual(false);\n  });\n\n  it('should return false with Pipe without the \"standalone\" property', () => {\n    @Pipe({\n      name: 'fooPipe',\n    })\n    class FooPipe {}\n\n    expect(isStandaloneComponent(FooPipe)).toEqual(false);\n  });\n});\n\ndescribe('getComponentDecoratorMetadata', () => {\n  it('should return Component with a Component', () => {\n    @Component({ selector: 'foo' })\n    class FooComponent {}\n\n    expect(getComponentDecoratorMetadata(FooComponent)).toBeInstanceOf(Component);\n    expect(getComponentDecoratorMetadata(FooComponent)).toEqual({\n      changeDetection: 1,\n      selector: 'foo',\n    });\n  });\n\n  it('should return Component with extending classes', () => {\n    @Component({ selector: 'bar' })\n    class BarComponent {}\n    @Component({ selector: 'foo' })\n    class FooComponent extends BarComponent {}\n\n    expect(getComponentDecoratorMetadata(FooComponent)).toBeInstanceOf(Component);\n    expect(getComponentDecoratorMetadata(FooComponent)).toEqual({\n      changeDetection: 1,\n      selector: 'foo',\n    });\n  });\n});\n\nfunction sortByPropName(\n  array: {\n    propName: string;\n    templateName: string;\n  }[]\n) {\n  return array.sort((a, b) => a.propName.localeCompare(b.propName));\n}\n\nfunction resolveComponentFactory<T extends Type<any>>(component: T) {\n  TestBed.configureTestingModule({\n    declarations: [component],\n  }).overrideModule(BrowserDynamicTestingModule, {});\n  const componentFactoryResolver = TestBed.inject(ComponentFactoryResolver);\n\n  return componentFactoryResolver.resolveComponentFactory(component);\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/utils/NgComponentAnalyzer.ts",
    "content": "import type { Type } from '@angular/core';\nimport {\n  Component,\n  Directive,\n  Input,\n  Output,\n  Pipe,\n  ɵReflectionCapabilities as ReflectionCapabilities,\n} from '@angular/core';\n\nconst reflectionCapabilities = new ReflectionCapabilities();\n\nexport type ComponentInputsOutputs = {\n  inputs: {\n    propName: string;\n    templateName: string;\n  }[];\n  outputs: {\n    propName: string;\n    templateName: string;\n  }[];\n};\n\n/** Returns component Inputs / Outputs by browsing these properties and decorator */\nexport const getComponentInputsOutputs = (component: any): ComponentInputsOutputs => {\n  const componentMetadata = getComponentDecoratorMetadata(component);\n  const componentPropsMetadata = getComponentPropsDecoratorMetadata(component);\n\n  const initialValue: ComponentInputsOutputs = {\n    inputs: [],\n    outputs: [],\n  };\n\n  // Adds the I/O present in @Component metadata\n  if (componentMetadata && componentMetadata.inputs) {\n    initialValue.inputs.push(\n      ...componentMetadata.inputs.map((i) => ({\n        propName: typeof i === 'string' ? i : i.name,\n        templateName: typeof i === 'string' ? i : i.alias,\n      }))\n    );\n  }\n  if (componentMetadata && componentMetadata.outputs) {\n    initialValue.outputs.push(\n      ...componentMetadata.outputs.map((i) => ({ propName: i, templateName: i }))\n    );\n  }\n\n  if (!componentPropsMetadata) {\n    return initialValue;\n  }\n\n  // Browses component properties to extract I/O\n  // Filters properties that have the same name as the one present in the @Component property\n  return Object.entries(componentPropsMetadata).reduce((previousValue, [propertyName, values]) => {\n    const value = values.find((v) => v instanceof Input || v instanceof Output);\n    if (value instanceof Input) {\n      const inputToAdd = {\n        propName: propertyName,\n        templateName: value.bindingPropertyName ?? value.alias ?? propertyName,\n      };\n\n      const previousInputsFiltered = previousValue.inputs.filter(\n        (i) => i.templateName !== propertyName\n      );\n      return {\n        ...previousValue,\n        inputs: [...previousInputsFiltered, inputToAdd],\n      };\n    }\n    if (value instanceof Output) {\n      const outputToAdd = {\n        propName: propertyName,\n        templateName: value.bindingPropertyName ?? value.alias ?? propertyName,\n      };\n\n      const previousOutputsFiltered = previousValue.outputs.filter(\n        (i) => i.templateName !== propertyName\n      );\n      return {\n        ...previousValue,\n        outputs: [...previousOutputsFiltered, outputToAdd],\n      };\n    }\n    return previousValue;\n  }, initialValue);\n};\n\nexport const isDeclarable = (component: any): boolean => {\n  if (!component) {\n    return false;\n  }\n\n  const decorators = reflectionCapabilities.annotations(component);\n\n  return !!(decorators || []).find(\n    (d) => d instanceof Directive || d instanceof Pipe || d instanceof Component\n  );\n};\n\nexport const isComponent = (component: any): component is Type<unknown> => {\n  if (!component) {\n    return false;\n  }\n\n  const decorators = reflectionCapabilities.annotations(component);\n\n  return (decorators || []).some((d) => d instanceof Component);\n};\n\nexport const isStandaloneComponent = (component: any): component is Type<unknown> => {\n  if (!component) {\n    return false;\n  }\n\n  const decorators = reflectionCapabilities.annotations(component);\n\n  // TODO: `standalone` is only available in Angular v14. Remove cast to `any` once\n  // Angular deps are updated to v14.x.x.\n  return (decorators || []).some(\n    (d) => (d instanceof Component || d instanceof Directive || d instanceof Pipe) && d.standalone\n  );\n};\n\n/** Returns all component decorator properties is used to get all `@Input` and `@Output` Decorator */\nexport const getComponentPropsDecoratorMetadata = (component: any) => {\n  return reflectionCapabilities.propMetadata(component);\n};\n\n/** Returns component decorator `@Component` */\nexport const getComponentDecoratorMetadata = (component: any): Component | undefined => {\n  const decorators = reflectionCapabilities.annotations(component);\n\n  return decorators.reverse().find((d) => d instanceof Component);\n};\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/utils/NgModulesAnalyzer.test.ts",
    "content": "import { Component, NgModule } from '@angular/core';\nimport { describe, expect, it } from 'vitest';\n\nimport { isComponentAlreadyDeclared } from './NgModulesAnalyzer.ts';\n\nconst FooComponent = Component({})(class {});\n\nconst BarComponent = Component({})(class {});\n\nconst BetaModule = NgModule({ declarations: [FooComponent] })(class {});\n\nconst AlphaModule = NgModule({ imports: [BetaModule] })(class {});\n\ndescribe('isComponentAlreadyDeclaredInModules', () => {\n  it('should return true when the component is already declared in one of modules', () => {\n    expect(isComponentAlreadyDeclared(FooComponent, [], [AlphaModule])).toEqual(true);\n  });\n\n  it('should return true if the component is in moduleDeclarations', () => {\n    expect(isComponentAlreadyDeclared(BarComponent, [BarComponent], [AlphaModule])).toEqual(true);\n  });\n\n  it('should return false if the component is not declared', () => {\n    expect(isComponentAlreadyDeclared(BarComponent, [], [AlphaModule])).toEqual(false);\n  });\n});\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/utils/NgModulesAnalyzer.ts",
    "content": "import { NgModule, ɵReflectionCapabilities as ReflectionCapabilities } from '@angular/core';\n\nconst reflectionCapabilities = new ReflectionCapabilities();\n\n/**\n * Avoid component redeclaration\n *\n * Checks recursively if the component has already been declared in all import Module\n */\nexport const isComponentAlreadyDeclared = (\n  componentToFind: any,\n  moduleDeclarations: any[],\n  moduleImports: any[]\n): boolean => {\n  if (\n    moduleDeclarations &&\n    moduleDeclarations.flat().some((declaration) => declaration === componentToFind)\n  ) {\n    // Found component in declarations array\n    return true;\n  }\n  if (!moduleImports) {\n    return false;\n  }\n\n  return moduleImports.flat().some((importItem) => {\n    const extractedNgModuleMetadata = extractNgModuleMetadata(importItem);\n    if (!extractedNgModuleMetadata) {\n      // Not an NgModule\n      return false;\n    }\n    return isComponentAlreadyDeclared(\n      componentToFind,\n      extractedNgModuleMetadata.declarations,\n      extractedNgModuleMetadata.imports\n    );\n  });\n};\n\nconst extractNgModuleMetadata = (importItem: any): NgModule => {\n  const target = importItem && importItem.ngModule ? importItem.ngModule : importItem;\n  const decorators = reflectionCapabilities.annotations(target);\n\n  if (!decorators || decorators.length === 0) {\n    return null;\n  }\n\n  const ngModuleDecorator: NgModule | undefined = decorators.find(\n    (decorator) => decorator instanceof NgModule\n  );\n  if (!ngModuleDecorator) {\n    return null;\n  }\n  return ngModuleDecorator;\n};\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/utils/PropertyExtractor.test.ts",
    "content": "import { CommonModule } from '@angular/common';\nimport { Component, Directive, Injectable, InjectionToken, NgModule } from '@angular/core';\nimport { BrowserModule } from '@angular/platform-browser';\nimport {\n  BrowserAnimationsModule,\n  NoopAnimationsModule,\n  provideAnimations,\n  provideNoopAnimations,\n} from '@angular/platform-browser/animations';\nimport { describe, expect, it, vi } from 'vitest';\n\nimport type { NgModuleMetadata } from '../../types.ts';\nimport { WithOfficialModule } from '../__testfixtures__/test.module.ts';\nimport { PropertyExtractor } from './PropertyExtractor.ts';\n\nconst TEST_TOKEN = new InjectionToken('testToken');\nconst TestTokenProvider = { provide: TEST_TOKEN, useValue: 123 };\nconst TestService = Injectable()(class {});\nconst TestComponent1 = Component({ standalone: false })(class {});\nconst TestComponent2 = Component({ standalone: false })(class {});\nconst StandaloneTestComponent = Component({})(class {});\nconst StandaloneTestDirective = Directive({})(class {});\nconst MixedTestComponent1 = Component({})(class extends StandaloneTestComponent {});\nconst MixedTestComponent2 = Component({ standalone: false })(class extends MixedTestComponent1 {});\nconst MixedTestComponent3 = Component({})(class extends MixedTestComponent2 {});\nconst TestModuleWithDeclarations = NgModule({ declarations: [TestComponent1] })(class {});\nconst TestModuleWithImportsAndProviders = NgModule({\n  imports: [TestModuleWithDeclarations],\n  providers: [TestTokenProvider],\n})(class {});\n\nconst analyzeMetadata = async (metadata: NgModuleMetadata, component?: any) => {\n  const propertyExtractor = new PropertyExtractor(metadata, component);\n  await propertyExtractor.init();\n  return propertyExtractor;\n};\nconst extractImports = async (metadata: NgModuleMetadata, component?: any) => {\n  const propertyExtractor = new PropertyExtractor(metadata, component);\n  await propertyExtractor.init();\n  return propertyExtractor.imports;\n};\nconst extractDeclarations = async (metadata: NgModuleMetadata, component?: any) => {\n  const propertyExtractor = new PropertyExtractor(metadata, component);\n  await propertyExtractor.init();\n  return propertyExtractor.declarations;\n};\nconst extractProviders = async (metadata: NgModuleMetadata, component?: any) => {\n  const propertyExtractor = new PropertyExtractor(metadata, component);\n  await propertyExtractor.init();\n  return propertyExtractor.providers;\n};\nconst extractApplicationProviders = async (metadata: NgModuleMetadata, component?: any) => {\n  const propertyExtractor = new PropertyExtractor(metadata, component);\n  await propertyExtractor.init();\n  return propertyExtractor.applicationProviders;\n};\n\ndescribe('PropertyExtractor', () => {\n  vi.spyOn(console, 'warn').mockImplementation(() => {});\n\n  describe('analyzeMetadata', () => {\n    it('should remove BrowserModule', async () => {\n      const metadata = {\n        imports: [BrowserModule],\n      };\n      const { imports, providers, applicationProviders } = await analyzeMetadata(metadata);\n      expect(imports.flat(Number.MAX_VALUE)).toEqual([CommonModule]);\n      expect(providers.flat(Number.MAX_VALUE)).toEqual([]);\n      expect(applicationProviders.flat(Number.MAX_VALUE)).toEqual([]);\n    });\n\n    it('should remove BrowserAnimationsModule and use its providers instead', async () => {\n      const metadata = {\n        imports: [BrowserAnimationsModule],\n      };\n      const { imports, providers, applicationProviders } = await analyzeMetadata(metadata);\n      expect(imports.flat(Number.MAX_VALUE)).toEqual([CommonModule]);\n      expect(providers.flat(Number.MAX_VALUE)).toEqual([]);\n      expect(applicationProviders.flat(Number.MAX_VALUE)).toEqual(provideAnimations());\n    });\n\n    it('should remove NoopAnimationsModule and use its providers instead', async () => {\n      const metadata = {\n        imports: [NoopAnimationsModule],\n      };\n      const { imports, providers, applicationProviders } = await analyzeMetadata(metadata);\n      expect(imports.flat(Number.MAX_VALUE)).toEqual([CommonModule]);\n      expect(providers.flat(Number.MAX_VALUE)).toEqual([]);\n      expect(applicationProviders.flat(Number.MAX_VALUE)).toEqual(provideNoopAnimations());\n    });\n\n    it('should remove Browser/Animations modules recursively', async () => {\n      const metadata = {\n        imports: [BrowserAnimationsModule, BrowserModule],\n      };\n      const { imports, providers, applicationProviders } = await analyzeMetadata(metadata);\n      expect(imports.flat(Number.MAX_VALUE)).toEqual([CommonModule]);\n      expect(providers.flat(Number.MAX_VALUE)).toEqual([]);\n      expect(applicationProviders.flat(Number.MAX_VALUE)).toEqual(provideAnimations());\n    });\n\n    it('should not destructure Angular official module', async () => {\n      const metadata = {\n        imports: [WithOfficialModule],\n      };\n      const { imports, providers, applicationProviders } = await analyzeMetadata(metadata);\n      expect(imports.flat(Number.MAX_VALUE)).toEqual([CommonModule, WithOfficialModule]);\n      expect(providers.flat(Number.MAX_VALUE)).toEqual([]);\n      expect(applicationProviders.flat(Number.MAX_VALUE)).toEqual([]);\n    });\n  });\n\n  describe('extractImports', () => {\n    it('should return Angular official modules', async () => {\n      const imports = await extractImports({ imports: [TestModuleWithImportsAndProviders] });\n      expect(imports).toEqual([CommonModule, TestModuleWithImportsAndProviders]);\n    });\n\n    it('should return standalone components', async () => {\n      const imports = await extractImports(\n        {\n          imports: [TestModuleWithImportsAndProviders],\n        },\n        StandaloneTestComponent\n      );\n      expect(imports).toEqual([\n        CommonModule,\n        TestModuleWithImportsAndProviders,\n        StandaloneTestComponent,\n      ]);\n    });\n\n    it('should return standalone directives', async () => {\n      const imports = await extractImports(\n        {\n          imports: [TestModuleWithImportsAndProviders],\n        },\n        StandaloneTestDirective\n      );\n      expect(imports).toEqual([\n        CommonModule,\n        TestModuleWithImportsAndProviders,\n        StandaloneTestDirective,\n      ]);\n    });\n  });\n\n  describe('extractDeclarations', () => {\n    it('should return an array of declarations that contains `storyComponent`', async () => {\n      const declarations = await extractDeclarations(\n        { declarations: [TestComponent1] },\n        TestComponent2\n      );\n      expect(declarations).toEqual([TestComponent1, TestComponent2]);\n    });\n  });\n\n  describe('analyzeDecorators', () => {\n    it('isStandalone should be false', () => {\n      const { isStandalone } = PropertyExtractor.analyzeDecorators(TestComponent1);\n      expect(isStandalone).toBe(false);\n    });\n\n    it('isStandalone should be true', () => {\n      const { isStandalone } = PropertyExtractor.analyzeDecorators(StandaloneTestComponent);\n      expect(isStandalone).toBe(true);\n    });\n\n    it('isStandalone should be true', () => {\n      const { isStandalone } = PropertyExtractor.analyzeDecorators(MixedTestComponent1);\n      expect(isStandalone).toBe(true);\n    });\n\n    it('isStandalone should be false', () => {\n      const { isStandalone } = PropertyExtractor.analyzeDecorators(MixedTestComponent2);\n      expect(isStandalone).toBe(false);\n    });\n\n    it('isStandalone should be true', () => {\n      const { isStandalone } = PropertyExtractor.analyzeDecorators(MixedTestComponent3);\n      expect(isStandalone).toBe(true);\n    });\n  });\n\n  describe('extractProviders', () => {\n    it('should return an array of providers', async () => {\n      const providers = await extractProviders({\n        providers: [TestService],\n      });\n      expect(providers).toEqual([TestService]);\n    });\n\n    it('should return an array of singletons extracted', async () => {\n      const singeltons = await extractApplicationProviders({\n        imports: [BrowserAnimationsModule],\n      });\n\n      expect(singeltons).toEqual(provideAnimations());\n    });\n  });\n});\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/utils/PropertyExtractor.ts",
    "content": "import { CommonModule } from '@angular/common';\nimport type { NgModule, Provider, importProvidersFrom } from '@angular/core';\nimport {\n  Component,\n  Directive,\n  Injectable,\n  InjectionToken,\n  Input,\n  Output,\n  Pipe,\n  ɵReflectionCapabilities as ReflectionCapabilities,\n  VERSION,\n} from '@angular/core';\nimport { BrowserModule } from '@angular/platform-browser';\nimport { dedent } from 'ts-dedent';\n\nimport type { NgModuleMetadata } from '../../types.ts';\nimport { isComponentAlreadyDeclared } from './NgModulesAnalyzer.ts';\n\nexport const reflectionCapabilities = new ReflectionCapabilities();\nexport const REMOVED_MODULES = new InjectionToken('REMOVED_MODULES');\nexport const uniqueArray = (arr: any[]) => {\n  return arr\n    .flat(Number.MAX_VALUE)\n    .filter(Boolean)\n    .filter((value, index, self) => self.indexOf(value) === index);\n};\n\nexport class PropertyExtractor implements NgModuleMetadata {\n  declarations?: any[] = [];\n  imports?: any[];\n  providers?: Provider[];\n  applicationProviders?: Array<Provider | ReturnType<typeof importProvidersFrom>>;\n\n  constructor(\n    private metadata: NgModuleMetadata,\n    private component?: any\n  ) {}\n\n  // With the new way of mounting standalone components to the DOM via bootstrapApplication API,\n  // we should now pass ModuleWithProviders to the providers array of the bootstrapApplication function.\n  static warnImportsModuleWithProviders(propertyExtractor: PropertyExtractor) {\n    const hasModuleWithProvidersImport = propertyExtractor.imports.some(\n      (importedModule) => 'ngModule' in importedModule\n    );\n\n    if (hasModuleWithProvidersImport) {\n      console.warn(\n        dedent(\n          `\n          Storybook Warning: \n          moduleMetadata property 'imports' contains one or more ModuleWithProviders, likely the result of a 'Module.forRoot()'-style call.\n          In Storybook 7.0 we use Angular's new 'bootstrapApplication' API to mount the component to the DOM, which accepts a list of providers to set up application-wide providers.\n          Use the 'applicationConfig' decorator from '@storybook/angular' to pass your ModuleWithProviders to the 'providers' property in combination with the importProvidersFrom helper function from '@angular/core' to extract all the necessary providers.\n          Visit https://angular.io/guide/standalone-components#configuring-dependency-injection for more information\n          `\n        )\n      );\n    }\n  }\n\n  public async init() {\n    const analyzed = await this.analyzeMetadata(this.metadata);\n    this.imports = uniqueArray([CommonModule, analyzed.imports]);\n    this.providers = uniqueArray(analyzed.providers);\n    this.applicationProviders = uniqueArray(analyzed.applicationProviders);\n    this.declarations = uniqueArray(analyzed.declarations);\n\n    if (this.component) {\n      const { isDeclarable, isStandalone } = PropertyExtractor.analyzeDecorators(this.component);\n      const isDeclared = isComponentAlreadyDeclared(\n        this.component,\n        analyzed.declarations,\n        this.imports\n      );\n\n      if (isStandalone) {\n        this.imports.push(this.component);\n      } else if (isDeclarable && !isDeclared) {\n        this.declarations.push(this.component);\n      }\n    }\n  }\n\n  /**\n   * Analyze NgModule Metadata\n   *\n   * - Removes Restricted Imports\n   * - Extracts providers from ModuleWithProviders\n   * - Returns a new NgModuleMetadata object\n   */\n  private analyzeMetadata = async (metadata: NgModuleMetadata) => {\n    const declarations = [...(metadata?.declarations || [])];\n    const providers = [...(metadata?.providers || [])];\n    const applicationProviders: Provider[] = [];\n    const imports = await Promise.all(\n      [...(metadata?.imports || [])].map(async (imported) => {\n        const [isRestricted, restrictedProviders] =\n          await PropertyExtractor.analyzeRestricted(imported);\n        if (isRestricted) {\n          applicationProviders.unshift(restrictedProviders || []);\n          return null;\n        }\n        return imported;\n      })\n    ).then((results) => results.filter(Boolean));\n\n    return { ...metadata, imports, providers, applicationProviders, declarations };\n  };\n\n  static analyzeRestricted = async (\n    ngModule: NgModule\n  ): Promise<[boolean] | [boolean, Provider]> => {\n    if (ngModule === BrowserModule) {\n      console.warn(\n        dedent`\n          Storybook Warning:\n          You have imported the \"BrowserModule\", which is not necessary anymore. \n          In Storybook v7.0 we are using Angular's new bootstrapApplication API to mount an Angular application to the DOM.\n          Note that the BrowserModule providers are automatically included when starting an application with bootstrapApplication()\n          Please remove the \"BrowserModule\" from the list of imports in your moduleMetadata definition to remove this warning.\n        `\n      );\n      return [true];\n    }\n\n    try {\n      const animations = await import('@angular/platform-browser/animations');\n\n      if (ngModule === animations.BrowserAnimationsModule) {\n        console.warn(\n          dedent`\n            Storybook Warning:\n            You have added the \"BrowserAnimationsModule\" to the list of \"imports\" in your moduleMetadata definition of your Story.\n            In Storybook 7.0 we use Angular's new 'bootstrapApplication' API to mount the component to the DOM, which accepts a list of providers to set up application-wide providers.\n            Use the 'applicationConfig' decorator from '@storybook/angular' and add the \"provideAnimations\" function to the list of \"providers\".\n            If your Angular version does not support \"provide-like\" functions, use the helper function importProvidersFrom instead to set up animations. For this case, please add \"importProvidersFrom(BrowserAnimationsModule)\" to the list of providers of your applicationConfig definition.\n            Please visit https://angular.io/guide/standalone-components#configuring-dependency-injection for more information.\n          `\n        );\n        return [true, animations.provideAnimations()];\n      }\n\n      if (ngModule === animations.NoopAnimationsModule) {\n        console.warn(\n          dedent`\n            Storybook Warning:\n            You have added the \"NoopAnimationsModule\" to the list of \"imports\" in your moduleMetadata definition of your Story.\n            In Storybook v7.0 we are using Angular's new bootstrapApplication API to mount an Angular application to the DOM, which accepts a list of providers to set up application-wide providers.\n            Use the 'applicationConfig' decorator from '@storybook/angular' and add the \"provideNoopAnimations\" function to the list of \"providers\".\n            If your Angular version does not support \"provide-like\" functions, use the helper function importProvidersFrom instead to set up noop animations and to extract all necessary providers from NoopAnimationsModule. For this case, please add \"importProvidersFrom(NoopAnimationsModule)\" to the list of providers of your applicationConfig definition.\n            Please visit https://angular.io/guide/standalone-components#configuring-dependency-injection for more information.\n          `\n        );\n        return [true, animations.provideNoopAnimations()];\n      }\n    } catch (e) {\n      return [false];\n    }\n\n    return [false];\n  };\n\n  static analyzeDecorators = (component: any) => {\n    const decorators = reflectionCapabilities.annotations(component);\n\n    const isComponent = decorators.some((d) => this.isDecoratorInstanceOf(d, 'Component'));\n    const isDirective = decorators.some((d) => this.isDecoratorInstanceOf(d, 'Directive'));\n    const isPipe = decorators.some((d) => this.isDecoratorInstanceOf(d, 'Pipe'));\n\n    const isDeclarable = isComponent || isDirective || isPipe;\n\n    // Check if the hierarchically lowest Component or Directive decorator (the only relevant for importing dependencies) is standalone.\n\n    let isStandalone =\n      (isComponent || isDirective) &&\n      [...decorators]\n        .reverse() // reflectionCapabilities returns decorators in a hierarchically top-down order\n        .find(\n          (d) =>\n            this.isDecoratorInstanceOf(d, 'Component') || this.isDecoratorInstanceOf(d, 'Directive')\n        )?.standalone;\n\n    //Starting in Angular 19 the default (in case it's undefined) value for standalone is true\n    if (isStandalone === undefined) {\n      isStandalone = !!(VERSION.major && Number(VERSION.major) >= 19);\n    }\n\n    return { isDeclarable, isStandalone };\n  };\n\n  static isDecoratorInstanceOf = (decorator: any, name: string) => {\n    let factory;\n    switch (name) {\n      case 'Component':\n        factory = Component;\n        break;\n      case 'Directive':\n        factory = Directive;\n        break;\n      case 'Pipe':\n        factory = Pipe;\n        break;\n      case 'Injectable':\n        factory = Injectable;\n        break;\n      case 'Input':\n        factory = Input;\n        break;\n      case 'Output':\n        factory = Output;\n        break;\n      default:\n        throw new Error(`Unknown decorator type: ${name}`);\n    }\n    return decorator instanceof factory || decorator.ngMetadataName === name;\n  };\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/utils/StoryUID.ts",
    "content": "/** Count of stories for each storyId. */\nconst storyCounts = new Map<string, number>();\n\n/**\n * Increments the count for a storyId and returns the next UID.\n *\n * When a story is bootstrapped, the storyId is used as the element tag. That becomes an issue when\n * a story is rendered multiple times in the same docs page. This function returns a UID that is\n * appended to the storyId to make it unique.\n *\n * @param storyId Id of a story\n * @returns Uid of a story\n */\nexport const getNextStoryUID = (storyId: string): string => {\n  if (!storyCounts.has(storyId)) {\n    storyCounts.set(storyId, -1);\n  }\n\n  const count = storyCounts.get(storyId) + 1;\n  storyCounts.set(storyId, count);\n  return `${storyId}-${count}`;\n};\n\n/**\n * Clears the storyId counts.\n *\n * Can be useful for testing, where you need predictable increments, without reloading the global\n * state.\n *\n * If onlyStoryId is provided, only that storyId is cleared.\n *\n * @param onlyStoryId Id of a story\n */\nexport const clearStoryUIDs = (onlyStoryId?: string): void => {\n  if (onlyStoryId !== undefined && onlyStoryId !== null) {\n    storyCounts.delete(onlyStoryId);\n  } else {\n    storyCounts.clear();\n  }\n};\n"
  },
  {
    "path": "code/frameworks/angular/src/client/angular-beta/utils/Zoneless.ts",
    "content": "export const getProvideZonelessChangeDetectionFn = async () => {\n  const angularCore: any = await import('@angular/core');\n\n  return 'provideExperimentalZonelessChangeDetection' in angularCore\n    ? angularCore.provideExperimentalZonelessChangeDetection\n    : 'provideZonelessChangeDetection' in angularCore\n      ? angularCore.provideZonelessChangeDetection\n      : null;\n};\n"
  },
  {
    "path": "code/frameworks/angular/src/client/argsToTemplate.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport type { ArgsToTemplateOptions } from './argsToTemplate.ts';\nimport { argsToTemplate } from './argsToTemplate.ts';\n\n// adjust path\n\ndescribe('argsToTemplate', () => {\n  it('should correctly convert args to template string and exclude undefined values', () => {\n    const args: Record<string, any> = {\n      prop1: 'value1',\n      prop2: undefined,\n      prop3: 'value3',\n    };\n    const options: ArgsToTemplateOptions<keyof typeof args> = {};\n    const result = argsToTemplate(args, options);\n    expect(result).toBe('[prop1]=\"prop1\" [prop3]=\"prop3\"');\n  });\n\n  it('should include properties from include option', () => {\n    const args = {\n      prop1: 'value1',\n      prop2: 'value2',\n      prop3: 'value3',\n    };\n    const options: ArgsToTemplateOptions<keyof typeof args> = {\n      include: ['prop1', 'prop3'],\n    };\n    const result = argsToTemplate(args, options);\n    expect(result).toBe('[prop1]=\"prop1\" [prop3]=\"prop3\"');\n  });\n\n  it('should include non-undefined properties from include option', () => {\n    const args: Record<string, any> = {\n      prop1: 'value1',\n      prop2: 'value2',\n      prop3: undefined,\n    };\n    const options: ArgsToTemplateOptions<keyof typeof args> = {\n      include: ['prop1', 'prop3'],\n    };\n    const result = argsToTemplate(args, options);\n    expect(result).toBe('[prop1]=\"prop1\"');\n  });\n\n  it('should exclude properties from exclude option', () => {\n    const args = {\n      prop1: 'value1',\n      prop2: 'value2',\n      prop3: 'value3',\n    };\n    const options: ArgsToTemplateOptions<keyof typeof args> = {\n      exclude: ['prop2'],\n    };\n    const result = argsToTemplate(args, options);\n    expect(result).toBe('[prop1]=\"prop1\" [prop3]=\"prop3\"');\n  });\n\n  it('should exclude properties from exclude option and undefined properties', () => {\n    const args: Record<string, any> = {\n      prop1: 'value1',\n      prop2: 'value2',\n      prop3: undefined,\n    };\n    const options: ArgsToTemplateOptions<keyof typeof args> = {\n      exclude: ['prop2'],\n    };\n    const result = argsToTemplate(args, options);\n    expect(result).toBe('[prop1]=\"prop1\"');\n  });\n\n  it('should prioritize include over exclude when both options are given', () => {\n    const args = {\n      prop1: 'value1',\n      prop2: 'value2',\n      prop3: 'value3',\n    };\n    const options: ArgsToTemplateOptions<keyof typeof args> = {\n      include: ['prop1', 'prop2'],\n      exclude: ['prop2', 'prop3'],\n    };\n    const result = argsToTemplate(args, options);\n    expect(result).toBe('[prop1]=\"prop1\" [prop2]=\"prop2\"');\n  });\n\n  it('should work when neither include nor exclude options are given', () => {\n    const args = {\n      prop1: 'value1',\n      prop2: 'value2',\n    };\n    const options: ArgsToTemplateOptions<keyof typeof args> = {};\n    const result = argsToTemplate(args, options);\n    expect(result).toBe('[prop1]=\"prop1\" [prop2]=\"prop2\"');\n  });\n\n  it('should bind events correctly when value is a function', () => {\n    const args = { event1: () => {}, event2: () => {} };\n    const result = argsToTemplate(args, {});\n    expect(result).toEqual('(event1)=\"event1($event)\" (event2)=\"event2($event)\"');\n  });\n\n  it('should mix properties and events correctly', () => {\n    const args = { input: 'Value1', event1: () => {} };\n    const result = argsToTemplate(args, {});\n    expect(result).toEqual('[input]=\"input\" (event1)=\"event1($event)\"');\n  });\n\n  it('should format for non dot notation', () => {\n    const args = { 'non-dot': 'Value1', 'dash-out': () => {} };\n    const result = argsToTemplate(args, {});\n    expect(result).toEqual('[non-dot]=\"this[\\'non-dot\\']\" (dash-out)=\"this[\\'dash-out\\']($event)\"');\n  });\n});\n"
  },
  {
    "path": "code/frameworks/angular/src/client/argsToTemplate.ts",
    "content": "import { formatPropInTemplate } from './angular-beta/ComputesTemplateFromComponent.ts';\n\n/**\n * Options for controlling the behavior of the argsToTemplate function.\n *\n * @template T The type of the keys in the target object.\n */\nexport interface ArgsToTemplateOptions<T> {\n  /**\n   * An array of keys to specifically include in the output. If provided, only the keys from this\n   * array will be included in the output, irrespective of the `exclude` option. Undefined values\n   * will still be excluded from the output.\n   */\n  include?: Array<T>;\n  /**\n   * An array of keys to specifically exclude from the output. If provided, these keys will be\n   * omitted from the output. This option is ignored if the `include` option is also provided\n   */\n  exclude?: Array<T>;\n}\n\n/**\n * Converts an object of arguments to a string of property and event bindings and excludes undefined\n * values. Why? Because Angular treats undefined values in property bindings as an actual value and\n * does not apply the default value of the property as soon as the binding is set. This feels\n * counter-intuitive and is a common source of bugs in stories.\n *\n * @example\n *\n * ```ts\n * // component.ts\n * ㅤ@Component({ selector: 'example' })\n *  export class ExampleComponent {\n *   ㅤ@Input() input1: string = 'Default Input1';\n *   ㅤ@Input() input2: string = 'Default Input2';\n *   ㅤ@Output() click = new EventEmitter();\n *  }\n *\n * // component.stories.ts\n * import { argsToTemplate } from '@storybook/angular';\n * export const Input1: Story = {\n *  render: (args) => ({\n *    props: args,\n *    // Problem1: <example [input1]=\"input1\" [input2]=\"input2\" (click)=\"click($event)\"></example>\n *    // This will set input2 to undefined and the internal default value will not be used.\n *    // Problem2: <example [input1]=\"input1\" (click)=\"click($event)\"></example>\n *    // The default value of input2 will be used, but it is not overridable by the user via controls.\n *    // Solution: Now the controls will be applicable to both input1 and input2, and the default values will be used if the user does not override them.\n *    template: `<example ${argsToTemplate(args)}\"></example>`,\n *  }),\n *  args: {\n *    // In this Story, we want to set the input1 property, and the internal default property of input2 should be used.\n *    input1: 'Input 1',\n *    click: { action: 'clicked' },\n *  },\n * };\n * ```\n */\nexport function argsToTemplate<A extends Record<string, any>>(\n  args: A,\n  options: ArgsToTemplateOptions<keyof A> = {}\n) {\n  const includeSet = options.include ? new Set(options.include) : null;\n  const excludeSet = options.exclude ? new Set(options.exclude) : null;\n\n  return Object.entries(args)\n    .filter(([key]) => args[key] !== undefined)\n    .filter(([key]) => {\n      if (includeSet) {\n        return includeSet.has(key);\n      }\n      if (excludeSet) {\n        return !excludeSet.has(key);\n      }\n      return true;\n    })\n    .map(([key, value]) =>\n      typeof value === 'function'\n        ? `(${key})=\"${formatPropInTemplate(key)}($event)\"`\n        : `[${key}]=\"${formatPropInTemplate(key)}\"`\n    )\n    .join(' ');\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/client/compodoc-types.ts",
    "content": "export interface Method {\n  name: string;\n  args: Argument[];\n  returnType: string;\n  decorators?: Decorator[];\n  description?: string;\n  rawdescription?: string;\n}\n\nexport interface JsDocTag {\n  comment?: string;\n  tagName?: {\n    escapedText?: string;\n  };\n}\n\nexport interface Property {\n  name: string;\n  decorators?: Decorator[];\n  type: string;\n  optional: boolean;\n  defaultValue?: string;\n  description?: string;\n  rawdescription?: string;\n  jsdoctags?: JsDocTag[];\n}\n\nexport interface Class {\n  name: string;\n  ngname: string;\n  type: 'pipe';\n  properties: Property[];\n  methods: Method[];\n  description?: string;\n  rawdescription?: string;\n}\n\nexport interface Injectable {\n  name: string;\n  type: 'injectable';\n  properties: Property[];\n  methods: Method[];\n  description?: string;\n  rawdescription?: string;\n}\n\nexport interface Pipe {\n  name: string;\n  type: 'class';\n  properties: Property[];\n  methods: Method[];\n  description?: string;\n  rawdescription?: string;\n}\n\nexport interface Directive {\n  name: string;\n  type: 'directive' | 'component';\n  propertiesClass: Property[];\n  inputsClass: Property[];\n  outputsClass: Property[];\n  methodsClass: Method[];\n  description?: string;\n  rawdescription?: string;\n}\n\nexport type Component = Directive;\n\nexport interface Argument {\n  name: string;\n  type: string;\n  optional?: boolean;\n}\n\nexport interface Decorator {\n  name: string;\n}\n\nexport interface TypeAlias {\n  name: string;\n  ctype: string;\n  subtype: string;\n  rawtype: string;\n  file: string;\n  kind: number;\n  description?: string;\n  rawdescription?: string;\n}\n\nexport interface EnumType {\n  name: string;\n  childs: EnumTypeChild[];\n  ctype: string;\n  subtype: string;\n  file: string;\n  description?: string;\n  rawdescription?: string;\n}\n\nexport interface EnumTypeChild {\n  name: string;\n  value?: string;\n}\n\nexport interface CompodocJson {\n  directives: Directive[];\n  components: Component[];\n  pipes: Pipe[];\n  injectables: Injectable[];\n  classes: Class[];\n  miscellaneous?: {\n    typealiases?: TypeAlias[];\n    enumerations?: EnumType[];\n  };\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/client/compodoc.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { extractType, setCompodocJson } from './compodoc.ts';\nimport type { CompodocJson, Decorator } from './compodoc-types.ts';\n\nconst makeProperty = (compodocType?: string) => ({\n  type: compodocType,\n  name: 'dummy',\n  decorators: [] as Decorator[],\n  optional: true,\n});\n\nconst getDummyCompodocJson = () => {\n  return {\n    miscellaneous: {\n      typealiases: [\n        {\n          name: 'EnumAlias',\n          ctype: 'miscellaneous',\n          subtype: 'typealias',\n          rawtype: 'EnumNumeric',\n          file: 'src/stories/component-with-enums/enums.component.ts',\n          description: '',\n          kind: 161,\n        },\n        {\n          name: 'TypeAlias',\n          ctype: 'miscellaneous',\n          subtype: 'typealias',\n          rawtype: '\"Type Alias 1\" | \"Type Alias 2\" | \"Type Alias 3\"',\n          file: 'src/stories/component-with-enums/enums.component.ts',\n          description: '',\n          kind: 168,\n        },\n      ],\n      enumerations: [\n        {\n          name: 'EnumNumeric',\n          childs: [\n            {\n              name: 'FIRST',\n            },\n            {\n              name: 'SECOND',\n            },\n            {\n              name: 'THIRD',\n            },\n          ],\n          ctype: 'miscellaneous',\n          subtype: 'enum',\n          description: '<p>Button Priority</p>\\n',\n          file: 'src/stories/component-with-enums/enums.component.ts',\n        },\n        {\n          name: 'EnumNumericInitial',\n          childs: [\n            {\n              name: 'UNO',\n              value: '1',\n            },\n            {\n              name: 'DOS',\n            },\n            {\n              name: 'TRES',\n            },\n          ],\n          ctype: 'miscellaneous',\n          subtype: 'enum',\n          description: '',\n          file: 'src/stories/component-with-enums/enums.component.ts',\n        },\n        {\n          name: 'EnumStringValues',\n          childs: [\n            {\n              name: 'PRIMARY',\n              value: 'PRIMARY',\n            },\n            {\n              name: 'SECONDARY',\n              value: 'SECONDARY',\n            },\n            {\n              name: 'TERTIARY',\n              value: 'TERTIARY',\n            },\n          ],\n          ctype: 'miscellaneous',\n          subtype: 'enum',\n          description: '',\n          file: 'src/stories/component-with-enums/enums.component.ts',\n        },\n      ],\n    },\n  } as CompodocJson;\n};\n\ndescribe('extractType', () => {\n  describe('with compodoc type', () => {\n    setCompodocJson(getDummyCompodocJson());\n    it.each([\n      ['string', { name: 'string' }],\n      ['boolean', { name: 'boolean' }],\n      ['number', { name: 'number' }],\n      // ['object', { name: 'object' }], // seems to be wrong | TODO: REVISIT\n      // ['foo', { name: 'other', value: 'empty-enum' }], // seems to be wrong | TODO: REVISIT\n      [null, { name: 'other', value: 'void' }],\n      [undefined, { name: 'other', value: 'void' }],\n      // ['T[]', { name: 'other', value: 'empty-enum' }], // seems to be wrong | TODO: REVISIT\n      ['[]', { name: 'other', value: 'empty-enum' }],\n      ['\"primary\" | \"secondary\"', { name: 'enum', value: ['primary', 'secondary'] }],\n      ['TypeAlias', { name: 'enum', value: ['Type Alias 1', 'Type Alias 2', 'Type Alias 3'] }],\n      // ['EnumNumeric', { name: 'other', value: 'empty-enum' }], // seems to be wrong | TODO: REVISIT\n      // ['EnumNumericInitial', { name: 'other', value: 'empty-enum' }], // seems to be wrong | TODO: REVISIT\n      ['EnumStringValues', { name: 'enum', value: ['PRIMARY', 'SECONDARY', 'TERTIARY'] }],\n    ])('%s', (compodocType, expected) => {\n      expect(extractType(makeProperty(compodocType), null)).toEqual(expected);\n    });\n  });\n\n  describe('without compodoc type', () => {\n    it.each([\n      ['string', { name: 'string' }],\n      ['', { name: 'string' }],\n      [false, { name: 'boolean' }],\n      [10, { name: 'number' }],\n      // [['abc'], { name: 'object' }], // seems to be wrong | TODO: REVISIT\n      // [{ foo: 1 }, { name: 'other', value: 'empty-enum' }], // seems to be wrong | TODO: REVISIT\n      [undefined, { name: 'other', value: 'void' }],\n    ])('%s', (defaultValue, expected) => {\n      expect(extractType(makeProperty(null), defaultValue)).toEqual(expected);\n    });\n  });\n});\n"
  },
  {
    "path": "code/frameworks/angular/src/client/compodoc.ts",
    "content": "import { logger } from 'storybook/internal/client-logger';\nimport type { ArgTypes, InputType, SBType } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport type {\n  Argument,\n  Class,\n  CompodocJson,\n  Component,\n  Directive,\n  Injectable,\n  JsDocTag,\n  Method,\n  Pipe,\n  Property,\n} from './compodoc-types.ts';\n\nconst { FEATURES } = global;\n\nexport const isMethod = (methodOrProp: Method | Property): methodOrProp is Method => {\n  return (methodOrProp as Method).args !== undefined;\n};\n\nexport const setCompodocJson = (compodocJson: CompodocJson) => {\n  global.__STORYBOOK_COMPODOC_JSON__ = compodocJson;\n};\n\nexport const getCompodocJson = (): CompodocJson => global.__STORYBOOK_COMPODOC_JSON__;\n\nexport const checkValidComponentOrDirective = (component: Component | Directive) => {\n  if (!component.name) {\n    throw new Error(`Invalid component ${JSON.stringify(component)}`);\n  }\n};\n\nexport const checkValidCompodocJson = (compodocJson: CompodocJson) => {\n  if (!compodocJson || !compodocJson.components) {\n    throw new Error('Invalid compodoc JSON');\n  }\n};\n\nconst hasDecorator = (item: Property, decoratorName: string) =>\n  item.decorators && item.decorators.find((x: any) => x.name === decoratorName);\n\nconst mapPropertyToSection = (item: Property) => {\n  if (hasDecorator(item, 'ViewChild')) {\n    return 'view child';\n  }\n  if (hasDecorator(item, 'ViewChildren')) {\n    return 'view children';\n  }\n  if (hasDecorator(item, 'ContentChild')) {\n    return 'content child';\n  }\n  if (hasDecorator(item, 'ContentChildren')) {\n    return 'content children';\n  }\n  return 'properties';\n};\n\nconst mapItemToSection = (key: string, item: Method | Property): string => {\n  switch (key) {\n    case 'methods':\n    case 'methodsClass':\n      return 'methods';\n    case 'inputsClass':\n      return 'inputs';\n    case 'outputsClass':\n      return 'outputs';\n    case 'properties':\n    case 'propertiesClass':\n      if (isMethod(item)) {\n        throw new Error(\"Cannot be of type Method if key === 'propertiesClass'\");\n      }\n      return mapPropertyToSection(item);\n    default:\n      throw new Error(`Unknown key: ${key}`);\n  }\n};\n\nexport const findComponentByName = (name: string, compodocJson: CompodocJson) =>\n  compodocJson.components.find((c: Component) => c.name === name) ||\n  compodocJson.directives.find((c: Directive) => c.name === name) ||\n  compodocJson.pipes.find((c: Pipe) => c.name === name) ||\n  compodocJson.injectables.find((c: Injectable) => c.name === name) ||\n  compodocJson.classes.find((c: Class) => c.name === name);\n\nconst getComponentData = (component: Component | Directive) => {\n  if (!component) {\n    return null;\n  }\n  checkValidComponentOrDirective(component);\n  const compodocJson = getCompodocJson();\n  if (!compodocJson) {\n    return null;\n  }\n  checkValidCompodocJson(compodocJson);\n  const { name } = component;\n  const metadata = findComponentByName(name, compodocJson);\n  if (!metadata) {\n    logger.warn(`Component not found in compodoc JSON: '${name}'`);\n  }\n  return metadata;\n};\n\nconst displaySignature = (item: Method): string => {\n  const args = item.args.map(\n    (arg: Argument) => `${arg.name}${arg.optional ? '?' : ''}: ${arg.type}`\n  );\n  return `(${args.join(', ')}) => ${item.returnType}`;\n};\n\nconst extractTypeFromValue = (defaultValue: any) => {\n  const valueType = typeof defaultValue;\n  return defaultValue || valueType === 'number' || valueType === 'boolean' || valueType === 'string'\n    ? valueType\n    : null;\n};\n\nconst extractEnumValues = (compodocType: any) => {\n  const compodocJson = getCompodocJson();\n  const enumType = compodocJson?.miscellaneous?.enumerations?.find((x) => x.name === compodocType);\n\n  if (enumType?.childs.every((x) => x.value)) {\n    return enumType.childs.map((x) => x.value);\n  }\n\n  if (typeof compodocType !== 'string' || compodocType.indexOf('|') === -1) {\n    return null;\n  }\n\n  try {\n    return compodocType.split('|').map((value) => JSON.parse(value));\n  } catch (e) {\n    return null;\n  }\n};\n\nexport const extractType = (property: Property, defaultValue: any): SBType => {\n  const compodocType = property.type || extractTypeFromValue(defaultValue);\n  switch (compodocType) {\n    case 'string':\n    case 'boolean':\n    case 'number':\n      return { name: compodocType };\n    case undefined:\n    case null:\n      return { name: 'other', value: 'void' };\n    default: {\n      const resolvedType = resolveTypealias(compodocType);\n      const enumValues = extractEnumValues(resolvedType);\n      return enumValues\n        ? { name: 'enum', value: enumValues }\n        : { name: 'other', value: 'empty-enum' };\n    }\n  }\n};\n\nconst castDefaultValue = (property: Property, defaultValue: any) => {\n  const compodocType = property.type;\n\n  // All these checks are necessary as compodoc does not always set the type ie. @HostBinding have empty types.\n  // null and undefined also have 'any' type\n  if (['boolean', 'number', 'string', 'EventEmitter'].includes(compodocType)) {\n    switch (compodocType) {\n      case 'boolean':\n        return defaultValue === 'true';\n      case 'number':\n        return Number(defaultValue);\n      case 'EventEmitter':\n        return undefined;\n      default:\n        return defaultValue;\n    }\n  } else {\n    switch (defaultValue) {\n      case 'true':\n        return true;\n      case 'false':\n        return false;\n      case 'null':\n        return null;\n      case 'undefined':\n        return undefined;\n      default:\n        return defaultValue;\n    }\n  }\n};\n\nconst extractDefaultValueFromComments = (property: Property, value: any) => {\n  let commentValue = value;\n  property.jsdoctags.forEach((tag: JsDocTag) => {\n    if (['default', 'defaultvalue'].includes(tag.tagName.escapedText)) {\n      const dom = new global.DOMParser().parseFromString(tag.comment, 'text/html');\n      commentValue = dom.body.textContent;\n    }\n  });\n  return commentValue;\n};\n\nconst extractDefaultValue = (property: Property) => {\n  try {\n    let value: string = property.defaultValue?.replace(/^'(.*)'$/, '$1');\n    value = castDefaultValue(property, value);\n\n    if (value == null && property.jsdoctags?.length > 0) {\n      value = extractDefaultValueFromComments(property, value);\n    }\n\n    return value;\n  } catch (err) {\n    logger.debug(`Error extracting ${property.name}: ${property.defaultValue}`);\n    return undefined;\n  }\n};\n\nconst resolveTypealias = (compodocType: string): string => {\n  const compodocJson = getCompodocJson();\n  const typeAlias = compodocJson?.miscellaneous?.typealiases?.find((x) => x.name === compodocType);\n  return typeAlias ? resolveTypealias(typeAlias.rawtype) : compodocType;\n};\n\nexport const extractArgTypesFromData = (componentData: Class | Directive | Injectable | Pipe) => {\n  const sectionToItems: Record<string, InputType[]> = {};\n  const componentClasses = FEATURES.angularFilterNonInputControls\n    ? ['inputsClass']\n    : ['propertiesClass', 'methodsClass', 'inputsClass', 'outputsClass'];\n  const compodocClasses = ['component', 'directive'].includes(componentData.type)\n    ? componentClasses\n    : ['properties', 'methods'];\n\n  type COMPODOC_CLASS =\n    | 'properties'\n    | 'methods'\n    | 'propertiesClass'\n    | 'methodsClass'\n    | 'inputsClass'\n    | 'outputsClass';\n\n  compodocClasses.forEach((key: COMPODOC_CLASS) => {\n    const data = (componentData as any)[key] || [];\n    data.forEach((item: Method | Property) => {\n      const section = mapItemToSection(key, item);\n      const defaultValue = isMethod(item) ? undefined : extractDefaultValue(item as Property);\n\n      const type: SBType =\n        isMethod(item) || (section !== 'inputs' && section !== 'properties')\n          ? { name: 'other', value: 'void' }\n          : extractType(item as Property, defaultValue);\n      const action = section === 'outputs' ? { action: item.name } : {};\n\n      const argType = {\n        name: item.name,\n        description: item.rawdescription || item.description,\n        type,\n        ...action,\n        table: {\n          category: section,\n          type: {\n            summary: isMethod(item) ? displaySignature(item) : item.type,\n            required: isMethod(item) ? false : !item.optional,\n          },\n          defaultValue: { summary: defaultValue },\n        },\n      };\n\n      if (!sectionToItems[section]) {\n        sectionToItems[section] = [];\n      }\n      sectionToItems[section].push(argType);\n    });\n  });\n\n  const SECTIONS = [\n    'properties',\n    'inputs',\n    'outputs',\n    'methods',\n    'view child',\n    'view children',\n    'content child',\n    'content children',\n  ];\n  const argTypes: ArgTypes = {};\n  SECTIONS.forEach((section) => {\n    const items = sectionToItems[section];\n    if (items) {\n      items.forEach((argType) => {\n        argTypes[argType.name] = argType;\n      });\n    }\n  });\n\n  return argTypes;\n};\n\nexport const extractArgTypes = (component: Component | Directive) => {\n  const componentData = getComponentData(component);\n  return componentData && extractArgTypesFromData(componentData);\n};\n\nexport const extractComponentDescription = (component: Component | Directive) => {\n  const componentData = getComponentData(component);\n  return componentData && (componentData.rawdescription || componentData.description);\n};\n"
  },
  {
    "path": "code/frameworks/angular/src/client/config.ts",
    "content": "import './globals.ts';\n\nexport { render, renderToCanvas } from './render.ts';\nexport { decorateStory as applyDecorators } from './decorateStory.ts';\n\nimport { enhanceArgTypes } from 'storybook/internal/docs-tools';\nimport type { ArgTypesEnhancer, Parameters } from 'storybook/internal/types';\n\nimport { extractArgTypes, extractComponentDescription } from './compodoc.ts';\n\nexport const parameters: Parameters = {\n  renderer: 'angular',\n  docs: {\n    story: { inline: true },\n    extractArgTypes,\n    extractComponentDescription,\n  },\n};\n\nexport const argTypesEnhancers: ArgTypesEnhancer[] = [enhanceArgTypes];\n"
  },
  {
    "path": "code/frameworks/angular/src/client/csf-factories.test.ts",
    "content": "// this file primarily tests TypeScript types with some runtime assertions\nimport { Component, EventEmitter, input, Input, output, Output } from '@angular/core';\nimport { describe, expect, it, test } from 'vitest';\n\nimport type { Args } from 'storybook/internal/types';\n\nimport { __definePreview } from './preview.ts';\nimport type { Decorator } from './public-types.ts';\n\n@Component({\n  selector: 'storybook-button',\n  standalone: true,\n  template: `\n    <button [disabled]=\"disabled\">{{ label }}</button>\n  `,\n})\nclass ButtonComponent {\n  @Input()\n  label!: string;\n\n  @Input()\n  disabled!: boolean;\n\n  @Output()\n  disabledChange = new EventEmitter<void>();\n}\n\ntype ButtonProps = { label: string; disabled: boolean; disabledChange?: (e: void) => void };\n\nconst preview = __definePreview({\n  addons: [],\n});\n\ntest('csf factories', () => {\n  const meta = preview.meta({\n    component: ButtonComponent,\n    args: { disabled: false },\n  });\n\n  const MyStory = meta.story({\n    args: {\n      label: 'Hello world',\n    },\n  });\n\n  expect(MyStory.input.args?.label).toBe('Hello world');\n});\n\ndescribe('Args can be provided in multiple ways', () => {\n  it('✅ All required args may be provided in meta', () => {\n    const meta = preview.meta({\n      component: ButtonComponent,\n      args: { disabled: false },\n    });\n\n    const Basic = meta.story({\n      args: {},\n    });\n  });\n\n  it('✅ Required args may be provided partial in meta and the story', () => {\n    const meta = preview.type<{ args: ButtonProps }>().meta({\n      component: ButtonComponent,\n      args: { label: 'good' },\n    });\n    const Basic = meta.story({\n      args: { disabled: false },\n    });\n  });\n\n  it('❌ The combined shape of meta args and story args must match the required args.', () => {\n    {\n      const meta = preview.type<{ args: { disabled: boolean } }>().meta({\n        component: ButtonComponent,\n      });\n      // @ts-expect-error disabled not provided ❌\n      const Basic = meta.story({\n        args: { label: 'good' },\n      });\n    }\n    {\n      const meta = preview.type<{ args: ButtonProps }>().meta({\n        component: ButtonComponent,\n        args: { label: 'good' },\n      });\n      // @ts-expect-error disabled not provided ❌\n      const Basic = meta.story();\n    }\n    {\n      const meta = preview.type<{ args: ButtonProps }>().meta({ component: ButtonComponent });\n      // @ts-expect-error disabled not provided ❌\n      const Basic = meta.story({\n        args: { label: 'good' },\n      });\n    }\n  });\n\n  it(\"✅ Required args don't need to be provided when the user uses an empty render\", () => {\n    const meta = preview.type<{ args: ButtonProps }>().meta({\n      component: ButtonComponent,\n      args: { label: 'good' },\n    });\n    const Basic = meta.story({\n      render: () => ({ template: '<div>Hello world</div>' }),\n    });\n\n    const CSF1 = meta.story(() => ({ template: '<div>Hello world</div>' }));\n  });\n\n  it('❌ Required args need to be provided when the user uses a non-empty render', () => {\n    const meta = preview.type<{ args: ButtonProps }>().meta({\n      component: ButtonComponent,\n      args: { label: 'good' },\n    });\n    // @ts-expect-error disabled not provided ❌\n    const Basic = meta.story({\n      args: {\n        label: 'good',\n      },\n      render: (args) => ({ template: '<div>Hello world</div>' }),\n    });\n  });\n});\n\ntype ThemeData = 'light' | 'dark';\n\ndescribe('Story args can be inferred', () => {\n  it('Correct args are inferred when type is widened for render function', () => {\n    const meta = preview.type<{ args: { theme: ThemeData } }>().meta({\n      component: ButtonComponent,\n      args: { disabled: false },\n      render: (args) => {\n        return {\n          template: `<div class=\"theme-${args.theme}\">\n            <storybook-button [label]=\"label\" [disabled]=\"disabled\"></storybook-button>\n          </div>`,\n          props: args,\n        };\n      },\n    });\n\n    const Basic = meta.story({ args: { theme: 'light', label: 'good' } });\n  });\n\n  const withDecorator: Decorator<{ decoratorArg: number }> = (storyFunc, { args }) => {\n    const story = storyFunc();\n    return {\n      ...story,\n      template: `<div>Decorator: ${args.decoratorArg}<div style=\"margin: 1em\">${story.template}</div></div>`,\n    };\n  };\n\n  it('Correct args are inferred when type is widened for decorators', () => {\n    const meta = preview.type<{ args: ButtonProps }>().meta({\n      component: ButtonComponent,\n      args: { disabled: false },\n      decorators: [withDecorator],\n    });\n\n    const Basic = meta.story({ args: { decoratorArg: 0, label: 'good' } });\n  });\n\n  it('Correct args are inferred when type is widened for multiple decorators', () => {\n    const secondDecorator: Decorator<{ decoratorArg2: string }> = (storyFunc, { args }) => {\n      const story = storyFunc();\n      return {\n        ...story,\n        template: `<div>Decorator: ${args.decoratorArg2}<div style=\"margin: 1em\">${story.template}</div></div>`,\n      };\n    };\n\n    // decorator is not using args\n    const thirdDecorator: Decorator<Args> = (storyFunc) => {\n      const story = storyFunc();\n      return {\n        ...story,\n        template: `<div><div style=\"margin: 1em\">${story.template}</div></div>`,\n      };\n    };\n\n    // decorator is not using args\n    const fourthDecorator: Decorator = (storyFunc) => {\n      const story = storyFunc();\n      return {\n        ...story,\n        template: `<div><div style=\"margin: 1em\">${story.template}</div></div>`,\n      };\n    };\n\n    const meta = preview.type<{ args: ButtonProps }>().meta({\n      component: ButtonComponent,\n      args: { disabled: false },\n      decorators: [withDecorator, secondDecorator, thirdDecorator, fourthDecorator],\n    });\n\n    const Basic = meta.story({\n      args: { decoratorArg: 0, decoratorArg2: '', label: 'good' },\n    });\n  });\n\n  it('Component type can be overridden', () => {\n    const meta = preview\n      .type<{ args: Omit<ButtonProps, 'disabledChange'> & { disabledChange?: boolean } }>()\n      .meta({\n        render: ({ disabledChange, ...args }) => {\n          return {\n            template: `<storybook-button\n              [label]=\"label\"\n              [disabled]=\"disabled\"\n              (disabledChange)=\"onDisabledChangeHandler && onDisabledChangeHandler($event)\"\n            ></storybook-button>`,\n            props: {\n              ...args,\n              onDisabledChangeHandler: disabledChange ? () => {} : undefined,\n            },\n          };\n        },\n        args: { label: 'hello', disabledChange: false },\n      });\n\n    const Basic = meta.story({\n      args: {\n        disabled: false,\n      },\n    });\n    const WithHandler = meta.story({ args: { disabled: false, disabledChange: true } });\n  });\n\n  it('Correct args are inferred when type is added in renderer', () => {\n    const meta = preview.type<{ args: ButtonProps }>().meta({\n      component: ButtonComponent,\n      args: { label: 'hello', disabledChangeToggle: false },\n      render: ({\n        disabledChangeToggle,\n        ...args\n      }: ButtonProps & { disabledChangeToggle?: boolean }) => {\n        return {\n          template: `<storybook-button\n            [label]=\"label\"\n            [disabled]=\"disabled\"\n            (disabledChange)=\"onDisabledChangeHandler && onDisabledChangeHandler($event)\"\n          ></storybook-button>`,\n          props: {\n            ...args,\n            onDisabledChangeHandler: disabledChangeToggle ? () => {} : undefined,\n          },\n        };\n      },\n    });\n\n    const Basic = meta.story({ args: { disabled: false } });\n    const WithHandler = meta.story({ args: { disabled: false, disabledChangeToggle: true } });\n  });\n\n  it('Correct args are inferred when render arg type is required', () => {\n    const meta = preview.type<{ args: { disabledChangeToggle: boolean } }>().meta({\n      component: ButtonComponent,\n      args: { label: 'hello' },\n      render: (args) => {\n        return {\n          template: `<storybook-button\n            [label]=\"label\"\n            [disabled]=\"disabled\"\n            (disabledChange)=\"onDisabledChangeHandler && onDisabledChangeHandler($event)\"\n          ></storybook-button>`,\n          props: {\n            ...args,\n            onDisabledChangeHandler: args.disabledChangeToggle ? () => {} : undefined,\n          },\n        };\n      },\n    });\n\n    // @ts-expect-error disabledChangeToggle is required\n    const Basic = meta.story({ args: { disabled: false } });\n    const WithHandler = meta.story({ args: { disabled: false, disabledChangeToggle: true } });\n  });\n\n  it('args can be reused', () => {\n    const meta = preview.type<{ args: ButtonProps }>().meta({\n      component: ButtonComponent,\n    });\n\n    const Enabled = meta.story({ args: { label: 'hello', disabled: false } });\n    const Disabled = meta.story({ args: { ...Enabled.input.args, disabled: true } });\n  });\n\n  it('stories can be extended', () => {\n    const meta = preview.type<{ args: ButtonProps }>().meta({\n      component: ButtonComponent,\n    });\n\n    const Enabled = meta.story({ args: { label: 'hello', disabled: false } });\n    const Disabled = Enabled.extend({ args: { disabled: true } });\n  });\n});\n\nit('Components without Props can be used', () => {\n  @Component({\n    selector: 'storybook-simple',\n    standalone: true,\n    template: `\n      <div>Simple</div>\n    `,\n  })\n  class SimpleComponent {}\n\n  const withDecorator: Decorator = (storyFunc) => {\n    const story = storyFunc();\n    return {\n      ...story,\n      template: `<div><div style=\"margin: 1em\">${story.template}</div></div>`,\n    };\n  };\n\n  const meta = preview.meta({\n    component: SimpleComponent,\n    decorators: [withDecorator],\n  });\n\n  const Basic = meta.story();\n});\n\nit('Signal components can be used', () => {\n  @Component({\n    standalone: false,\n    // Needs to be a different name to the CLI template button\n    selector: 'storybook-signal-button',\n    template: `\n      <button\n        type=\"button\"\n        (click)=\"onClick.emit($event)\"\n        [ngClass]=\"classes\"\n        [ngStyle]=\"{ 'background-color': backgroundColor }\"\n      >\n        {{ label() }}\n      </button>\n    `,\n  })\n  class SignalButtonComponent {\n    /** Is this the principal call to action on the page? */\n    primary = input(false);\n\n    /** What background color to use */\n    @Input()\n    backgroundColor?: string;\n\n    /** How large should the button be? */\n    size = input('medium', {\n      transform: (val: 'small' | 'medium') => val,\n    });\n\n    /** Button contents */\n    label = input.required<string>();\n\n    /** Optional click handler */\n    onClick = output<Event>();\n\n    public get classes(): string[] {\n      const mode = this.primary() ? 'storybook-button--primary' : 'storybook-button--secondary';\n\n      return ['storybook-button', `storybook-button--${this.size()}`, mode];\n    }\n  }\n\n  const meta = preview.meta({\n    component: SignalButtonComponent,\n  });\n\n  const Basic = meta.story({\n    args: {\n      backgroundColor: 'red',\n      size: 'small',\n      label: '1',\n    },\n  });\n});\n"
  },
  {
    "path": "code/frameworks/angular/src/client/decorateStory.test.ts",
    "content": "import { Component, Input, Output } from '@angular/core';\nimport type { DecoratorFunction, StoryContext } from 'storybook/internal/types';\nimport { describe, expect, it } from 'vitest';\nimport { componentWrapperDecorator } from './decorators.ts';\n\nimport decorateStory from './decorateStory.ts';\nimport type { AngularRenderer } from './types.ts';\n\n// TODO: Fix. Test is infinitely running.\ndescribe.skip('decorateStory', () => {\n  describe('angular behavior', () => {\n    it('should use componentWrapperDecorator with args', () => {\n      const decorators: DecoratorFunction<AngularRenderer>[] = [\n        componentWrapperDecorator(ParentComponent, ({ args }) => args),\n        componentWrapperDecorator(\n          (story) => `<grandparent [grandparentInput]=\"grandparentInput\">${story}</grandparent>`,\n          ({ args }) => args\n        ),\n        componentWrapperDecorator((story) => `<great-grandparent>${story}</great-grandparent>`),\n      ];\n      const decorated = decorateStory(() => ({ template: '</child>' }), decorators);\n\n      expect(\n        decorated(\n          makeContext({\n            component: FooComponent,\n            args: {\n              parentInput: 'Parent input',\n              grandparentInput: 'grandparent input',\n              parentOutput: () => {},\n            },\n          })\n        )\n      ).toEqual({\n        props: {\n          parentInput: 'Parent input',\n          grandparentInput: 'grandparent input',\n          parentOutput: expect.any(Function),\n        },\n        template:\n          '<great-grandparent><grandparent [grandparentInput]=\"grandparentInput\"><parent [parentInput]=\"parentInput\" (parentOutput)=\"parentOutput($event)\"></child></parent></grandparent></great-grandparent>',\n        userDefinedTemplate: true,\n      });\n    });\n\n    it('should use componentWrapperDecorator with input / output', () => {\n      const decorators: DecoratorFunction<AngularRenderer>[] = [\n        componentWrapperDecorator(ParentComponent, {\n          parentInput: 'Parent input',\n          parentOutput: () => {},\n        }),\n        componentWrapperDecorator(\n          (story) => `<grandparent [grandparentInput]=\"grandparentInput\">${story}</grandparent>`,\n          {\n            grandparentInput: 'Grandparent input',\n            sameInput: 'Should be override by story props',\n          }\n        ),\n        componentWrapperDecorator((story) => `<great-grandparent>${story}</great-grandparent>`),\n      ];\n      const decorated = decorateStory(\n        () => ({ template: '</child>', props: { sameInput: 'Story input' } }),\n        decorators\n      );\n\n      expect(\n        decorated(\n          makeContext({\n            component: FooComponent,\n          })\n        )\n      ).toEqual({\n        props: {\n          parentInput: 'Parent input',\n          parentOutput: expect.any(Function),\n          grandparentInput: 'Grandparent input',\n          sameInput: 'Story input',\n        },\n        template:\n          '<great-grandparent><grandparent [grandparentInput]=\"grandparentInput\"><parent [parentInput]=\"parentInput\" (parentOutput)=\"parentOutput($event)\"></child></parent></grandparent></great-grandparent>',\n        userDefinedTemplate: true,\n      });\n    });\n\n    it('should use componentWrapperDecorator', () => {\n      const decorators: DecoratorFunction<AngularRenderer>[] = [\n        componentWrapperDecorator(ParentComponent),\n        componentWrapperDecorator((story) => `<grandparent>${story}</grandparent>`),\n        componentWrapperDecorator((story) => `<great-grandparent>${story}</great-grandparent>`),\n      ];\n      const decorated = decorateStory(() => ({ template: '</child>' }), decorators);\n\n      expect(decorated(makeContext({ component: FooComponent }))).toEqual({\n        template:\n          '<great-grandparent><grandparent><parent></child></parent></grandparent></great-grandparent>',\n        userDefinedTemplate: true,\n      });\n    });\n\n    it('should use template in preference to component parameters', () => {\n      const decorators: DecoratorFunction<AngularRenderer>[] = [\n        (s) => {\n          const story = s();\n          return {\n            ...story,\n            template: `<parent>${story.template}</parent>`,\n          };\n        },\n        (s) => {\n          const story = s();\n          return {\n            ...story,\n            template: `<grandparent>${story.template}</grandparent>`,\n          };\n        },\n        (s) => {\n          const story = s();\n          return {\n            ...story,\n            template: `<great-grandparent>${story.template}</great-grandparent>`,\n          };\n        },\n      ];\n      const decorated = decorateStory(() => ({ template: '</child>' }), decorators);\n\n      expect(decorated(makeContext({ component: FooComponent }))).toEqual({\n        template:\n          '<great-grandparent><grandparent><parent></child></parent></grandparent></great-grandparent>',\n        userDefinedTemplate: true,\n      });\n    });\n\n    it('should include story templates in decorators', () => {\n      const decorators: DecoratorFunction<AngularRenderer>[] = [\n        (s) => {\n          const story = s();\n          return {\n            ...story,\n            template: `<parent>${story.template}</parent>`,\n          };\n        },\n        (s) => {\n          const story = s();\n          return {\n            ...story,\n            template: `<grandparent>${story.template}</grandparent>`,\n          };\n        },\n        (s) => {\n          const story = s();\n          return {\n            ...story,\n            template: `<great-grandparent>${story.template}</great-grandparent>`,\n          };\n        },\n      ];\n      const decorated = decorateStory(() => ({ template: '</child>' }), decorators);\n\n      expect(decorated(makeContext({}))).toEqual({\n        template:\n          '<great-grandparent><grandparent><parent></child></parent></grandparent></great-grandparent>',\n        userDefinedTemplate: true,\n      });\n    });\n\n    it('should include story components in decorators', () => {\n      const decorators: DecoratorFunction<AngularRenderer>[] = [\n        (s) => {\n          const story = s();\n          return {\n            ...story,\n            template: `<parent>${story.template}</parent>`,\n          };\n        },\n        (s) => {\n          const story = s();\n          return {\n            ...story,\n            template: `<grandparent>${story.template}</grandparent>`,\n          };\n        },\n        (s) => {\n          const story = s();\n          return {\n            ...story,\n            template: `<great-grandparent>${story.template}</great-grandparent>`,\n          };\n        },\n      ];\n      const decorated = decorateStory(() => ({}), decorators);\n\n      expect(decorated(makeContext({ component: FooComponent }))).toEqual({\n        template:\n          '<great-grandparent><grandparent><parent><foo></foo></parent></grandparent></great-grandparent>',\n        userDefinedTemplate: false,\n      });\n    });\n\n    it('should keep template with an empty value', () => {\n      const decorators: DecoratorFunction<AngularRenderer>[] = [\n        componentWrapperDecorator(ParentComponent),\n      ];\n      const decorated = decorateStory(() => ({ template: '' }), decorators);\n\n      expect(decorated(makeContext({ component: FooComponent }))).toEqual({\n        template: '<parent></parent>',\n      });\n    });\n\n    it('should only keeps args with a control or an action in argTypes', () => {\n      const decorated = decorateStory(\n        (context: StoryContext) => ({\n          template: `Args available in the story : ${Object.keys(context.args).join()}`,\n        }),\n        []\n      );\n\n      expect(\n        decorated(\n          makeContext({\n            component: FooComponent,\n            argTypes: {\n              withControl: { control: { type: 'object' }, name: 'withControl' },\n              withAction: { action: 'onClick', name: 'withAction' },\n              toRemove: { name: 'toRemove' },\n            },\n            args: {\n              withControl: 'withControl',\n              withAction: () => ({}),\n              toRemove: 'toRemove',\n            },\n          })\n        )\n      ).toEqual({\n        template: 'Args available in the story : withControl,withAction',\n        userDefinedTemplate: true,\n      });\n    });\n  });\n\n  describe('default behavior', () => {\n    it('calls decorators in out to in order', () => {\n      const decorators: DecoratorFunction<AngularRenderer>[] = [\n        (s) => {\n          const story = s();\n          return { ...story, props: { a: [...story.props.a, 1] } };\n        },\n        (s) => {\n          const story = s();\n          return { ...story, props: { a: [...story.props.a, 2] } };\n        },\n        (s) => {\n          const story = s();\n          return { ...story, props: { a: [...story.props.a, 3] } };\n        },\n      ];\n      const decorated = decorateStory(() => ({ props: { a: [0] } }), decorators);\n\n      expect(decorated(makeContext({}))).toEqual({ props: { a: [0, 1, 2, 3] } });\n    });\n\n    it('passes context through to sub decorators', () => {\n      const decorators: DecoratorFunction<AngularRenderer>[] = [\n        (s, c) => {\n          const story = s({ ...c, k: 1 });\n          return { ...story, props: { a: [...story.props.a, c.k] } };\n        },\n        (s, c) => {\n          const story = s({ ...c, k: 2 });\n          return { ...story, props: { a: [...story.props.a, c.k] } };\n        },\n        (s, c) => {\n          const story = s({ ...c, k: 3 });\n          return { ...story, props: { a: [...story.props.a, c.k] } };\n        },\n      ];\n      const decorated = decorateStory((c: StoryContext) => ({ props: { a: [c.k] } }), decorators);\n\n      expect(decorated(makeContext({ k: 0 }))).toEqual({ props: { a: [1, 2, 3, 0] } });\n    });\n\n    it('DOES NOT merge parameter or pass through parameters key in context', () => {\n      const decorators: DecoratorFunction<AngularRenderer>[] = [\n        (s, c) => {\n          const story = s({ ...c, k: 1, parameters: { p: 1 } });\n          return {\n            ...story,\n            props: { a: [...story.props.a, c.k], p: [...story.props.p, c.parameters.p] },\n          };\n        },\n        (s, c) => {\n          const story = s({ ...c, k: 2, parameters: { p: 2 } });\n          return {\n            ...story,\n            props: { a: [...story.props.a, c.k], p: [...story.props.p, c.parameters.p] },\n          };\n        },\n        (s, c) => {\n          const story = s({ ...c, k: 3, parameters: { p: 3 } });\n          return {\n            ...story,\n            props: { a: [...story.props.a, c.k], p: [...story.props.p, c.parameters.p] },\n          };\n        },\n      ];\n      const decorated = decorateStory(\n        (c: StoryContext) => ({ props: { a: [c.k], p: [c.parameters.p] } }),\n        decorators\n      );\n\n      expect(decorated(makeContext({ k: 0, parameters: { p: 0 } }))).toEqual({\n        props: { a: [1, 2, 3, 0], p: [0, 0, 0, 0] },\n      });\n    });\n  });\n});\n\nfunction makeContext(input: Record<string, unknown>): StoryContext<AngularRenderer> {\n  return {\n    id: 'id',\n    kind: 'kind',\n    name: 'name',\n    viewMode: 'story',\n    parameters: {},\n    ...input,\n  } as StoryContext<AngularRenderer>;\n}\n\n@Component({\n  selector: 'foo',\n  template: `\n    foo\n  `,\n})\nclass FooComponent {}\n\n@Component({\n  selector: 'parent',\n  template: `\n    <ng-content></ng-content>\n  `,\n})\nclass ParentComponent {\n  @Input()\n  parentInput: string;\n\n  @Output()\n  parentOutput: any;\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/client/decorateStory.ts",
    "content": "import { sanitizeStoryContextUpdate } from 'storybook/preview-api';\nimport type { DecoratorFunction, LegacyStoryFn, StoryContext } from 'storybook/internal/types';\n\nimport { computesTemplateFromComponent } from './angular-beta/ComputesTemplateFromComponent.ts';\nimport type { AngularRenderer } from './types.ts';\n\nexport default function decorateStory(\n  mainStoryFn: LegacyStoryFn<AngularRenderer>,\n  decorators: DecoratorFunction<AngularRenderer>[]\n): LegacyStoryFn<AngularRenderer> {\n  const returnDecorators = [cleanArgsDecorator, ...decorators].reduce(\n    (previousStoryFn: LegacyStoryFn<AngularRenderer>, decorator) =>\n      (context: StoryContext<AngularRenderer>) => {\n        const decoratedStory = decorator((update) => {\n          return previousStoryFn({\n            ...context,\n            ...sanitizeStoryContextUpdate(update),\n          });\n        }, context);\n\n        return decoratedStory;\n      },\n    (context) => prepareMain(mainStoryFn(context), context)\n  );\n\n  return returnDecorators;\n}\n\nexport { decorateStory };\n\nconst prepareMain = (\n  story: AngularRenderer['storyResult'],\n  context: StoryContext<AngularRenderer>\n): AngularRenderer['storyResult'] => {\n  let { template } = story;\n\n  const { component } = context;\n  const userDefinedTemplate = !hasNoTemplate(template);\n\n  if (!userDefinedTemplate && component) {\n    template = computesTemplateFromComponent(component, story.props, '');\n  }\n  return {\n    ...story,\n    ...(template ? { template, userDefinedTemplate } : {}),\n  };\n};\n\nfunction hasNoTemplate(template: string | null | undefined): template is undefined {\n  return template === null || template === undefined;\n}\n\nconst cleanArgsDecorator: DecoratorFunction<AngularRenderer> = (storyFn, context) => {\n  if (!context.argTypes || !context.args) {\n    return storyFn();\n  }\n\n  const argsToClean = context.args;\n\n  context.args = Object.entries(argsToClean).reduce((obj, [key, arg]) => {\n    const argType = context.argTypes[key];\n\n    // Only keeps args with a control or an action in argTypes\n    if (argType?.action || argType?.control) {\n      return { ...obj, [key]: arg };\n    }\n    return obj;\n  }, {});\n\n  return storyFn();\n};\n"
  },
  {
    "path": "code/frameworks/angular/src/client/decorators.test.ts",
    "content": "import type { Addon_StoryContext } from 'storybook/internal/types';\n\nimport { vi, expect, describe, it } from 'vitest';\nimport { Component } from '@angular/core';\nimport { moduleMetadata, applicationConfig } from './decorators.ts';\nimport type { AngularRenderer } from './types.ts';\n\nconst defaultContext: Addon_StoryContext<AngularRenderer> = {\n  componentId: 'unspecified',\n  kind: 'unspecified',\n  title: 'unspecified',\n  id: 'unspecified',\n  name: 'unspecified',\n  story: 'unspecified',\n  tags: [],\n  parameters: {},\n  initialArgs: {},\n  args: {},\n  argTypes: {},\n  globals: {},\n  globalTypes: {},\n  storyGlobals: {},\n  reporting: {\n    reports: [],\n    addReport: vi.fn(),\n  },\n  hooks: {},\n  loaded: {},\n  originalStoryFn: vi.fn(),\n  viewMode: 'story',\n  abortSignal: undefined,\n  canvasElement: undefined,\n  step: undefined,\n  context: undefined,\n  canvas: undefined,\n  userEvent: undefined,\n  mount: undefined,\n};\n\ndefaultContext.context = defaultContext;\n\nclass MockModule {}\nclass MockModuleTwo {}\nclass MockService {}\n@Component({})\nclass MockComponent {}\n\ndescribe('applicationConfig', () => {\n  const provider1 = () => {};\n  const provider2 = () => {};\n\n  it('should apply global config', () => {\n    expect(\n      applicationConfig({\n        providers: [provider1] as any,\n      })(() => ({}), defaultContext)\n    ).toEqual({\n      applicationConfig: {\n        providers: [provider1],\n      },\n    });\n  });\n\n  it('should apply story config', () => {\n    expect(\n      applicationConfig({\n        providers: [],\n      })(\n        () => ({\n          applicationConfig: {\n            providers: [provider2] as any,\n          },\n        }),\n        {\n          ...defaultContext,\n        }\n      )\n    ).toEqual({\n      applicationConfig: {\n        providers: [provider2],\n      },\n    });\n  });\n\n  it('should merge global and story config', () => {\n    expect(\n      applicationConfig({\n        providers: [provider1] as any,\n      })(\n        () => ({\n          applicationConfig: {\n            providers: [provider2] as any,\n          },\n        }),\n        {\n          ...defaultContext,\n        }\n      )\n    ).toEqual({\n      applicationConfig: {\n        providers: [provider1, provider2],\n      },\n    });\n  });\n});\n\ndescribe('moduleMetadata', () => {\n  it('should add metadata to a story without it', () => {\n    const result = moduleMetadata({\n      imports: [MockModule],\n      providers: [MockService],\n    })(\n      () => ({}),\n      // deepscan-disable-next-line\n      defaultContext\n    );\n\n    expect(result).toEqual({\n      moduleMetadata: {\n        declarations: [],\n        entryComponents: [],\n        imports: [MockModule],\n        schemas: [],\n        providers: [MockService],\n      },\n    });\n  });\n\n  it('should combine with individual metadata on a story', () => {\n    const result = moduleMetadata({\n      imports: [MockModule],\n    })(\n      () => ({\n        component: MockComponent,\n        moduleMetadata: {\n          imports: [MockModuleTwo],\n          providers: [MockService],\n        },\n      }),\n      // deepscan-disable-next-line\n      defaultContext\n    );\n\n    expect(result).toEqual({\n      component: MockComponent,\n      moduleMetadata: {\n        declarations: [],\n        entryComponents: [],\n        imports: [MockModule, MockModuleTwo],\n        schemas: [],\n        providers: [MockService],\n      },\n    });\n  });\n\n  it('should return the original metadata if passed null', () => {\n    const result = moduleMetadata(null)(\n      () => ({\n        component: MockComponent,\n        moduleMetadata: {\n          providers: [MockService],\n        },\n      }),\n      // deepscan-disable-next-line\n      defaultContext\n    );\n\n    expect(result).toEqual({\n      component: MockComponent,\n      moduleMetadata: {\n        declarations: [],\n        entryComponents: [],\n        imports: [],\n        schemas: [],\n        providers: [MockService],\n      },\n    });\n  });\n});\n"
  },
  {
    "path": "code/frameworks/angular/src/client/decorators.ts",
    "content": "import type { DecoratorFunction, StoryContext } from 'storybook/internal/types';\n\nimport type { ApplicationConfig, Type } from '@angular/core';\n\nimport { computesTemplateFromComponent } from './angular-beta/ComputesTemplateFromComponent.ts';\nimport { isComponent } from './angular-beta/utils/NgComponentAnalyzer.ts';\nimport type { AngularRenderer, ICollection, NgModuleMetadata } from './types.ts';\n\n// We use `any` here as the default type rather than `Args` because we need something that is\n// castable to any component-specific args type when the user is being careful.\nexport const moduleMetadata =\n  <TArgs = any>(metadata: Partial<NgModuleMetadata>): DecoratorFunction<AngularRenderer, TArgs> =>\n  (storyFn) => {\n    const story = storyFn();\n    const storyMetadata = story.moduleMetadata || {};\n    metadata = metadata || {};\n\n    return {\n      ...story,\n      moduleMetadata: {\n        declarations: [...(metadata.declarations || []), ...(storyMetadata.declarations || [])],\n        entryComponents: [\n          ...(metadata.entryComponents || []),\n          ...(storyMetadata.entryComponents || []),\n        ],\n        imports: [...(metadata.imports || []), ...(storyMetadata.imports || [])],\n        schemas: [...(metadata.schemas || []), ...(storyMetadata.schemas || [])],\n        providers: [...(metadata.providers || []), ...(storyMetadata.providers || [])],\n      },\n    };\n  };\n\n/**\n * Decorator to set the config options which are available during the application bootstrap\n * operation\n */\nexport function applicationConfig<TArgs = any>(\n  /** Set of config options available during the application bootstrap operation. */\n  config: ApplicationConfig\n): DecoratorFunction<AngularRenderer, TArgs> {\n  return (storyFn) => {\n    const story = storyFn();\n\n    const storyConfig: ApplicationConfig | undefined = story.applicationConfig;\n\n    return {\n      ...story,\n      applicationConfig:\n        storyConfig || config\n          ? {\n              ...config,\n              ...storyConfig,\n              providers: [...(config?.providers || []), ...(storyConfig?.providers || [])],\n            }\n          : undefined,\n    };\n  };\n}\n\nexport const componentWrapperDecorator =\n  <TArgs = any>(\n    element: Type<unknown> | ((story: string) => string),\n    props?: ICollection | ((storyContext: StoryContext<AngularRenderer, TArgs>) => ICollection)\n  ): DecoratorFunction<AngularRenderer, TArgs> =>\n  (storyFn, storyContext) => {\n    const story = storyFn();\n    const currentProps = typeof props === 'function' ? (props(storyContext) as ICollection) : props;\n\n    const template = isComponent(element)\n      ? computesTemplateFromComponent(element, currentProps ?? {}, story.template)\n      : element(story.template);\n\n    return {\n      ...story,\n      template,\n      ...(currentProps || story.props\n        ? {\n            props: {\n              ...currentProps,\n              ...story.props,\n            },\n          }\n        : {}),\n    };\n  };\n"
  },
  {
    "path": "code/frameworks/angular/src/client/docs/__testfixtures__/doc-button/argtypes.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`angular component properties doc-button 1`] = `\nObject {\n  \"_inputValue\": Object {\n    \"defaultValue\": \"some value\",\n    \"description\": \"\",\n    \"name\": \"_inputValue\",\n    \"table\": Object {\n      \"category\": \"properties\",\n      \"defaultValue\": Object {\n        \"summary\": \"some value\",\n      },\n      \"type\": Object {\n        \"required\": true,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n    },\n  },\n  \"_value\": Object {\n    \"defaultValue\": \"Private hello\",\n    \"description\": \"\nPrivate value.\",\n    \"name\": \"_value\",\n    \"table\": Object {\n      \"category\": \"properties\",\n      \"defaultValue\": Object {\n        \"summary\": \"Private hello\",\n      },\n      \"type\": Object {\n        \"required\": true,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n    },\n  },\n  \"accent\": Object {\n    \"defaultValue\": undefined,\n    \"description\": \"\nSpecify the accent-type of the button\",\n    \"name\": \"accent\",\n    \"table\": Object {\n      \"category\": \"inputs\",\n      \"defaultValue\": Object {\n        \"summary\": undefined,\n      },\n      \"type\": Object {\n        \"required\": true,\n        \"summary\": \"ButtonAccent\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"object\",\n    },\n  },\n  \"appearance\": Object {\n    \"defaultValue\": \"secondary\",\n    \"description\": \"\nAppearance style of the button.\",\n    \"name\": \"appearance\",\n    \"table\": Object {\n      \"category\": \"inputs\",\n      \"defaultValue\": Object {\n        \"summary\": \"secondary\",\n      },\n      \"type\": Object {\n        \"required\": true,\n        \"summary\": \"\\\\\"primary\\\\\" | \\\\\"secondary\\\\\"\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"enum\",\n      \"value\": Array [\n        \"primary\",\n        \"secondary\",\n      ],\n    },\n  },\n  \"buttonRef\": Object {\n    \"defaultValue\": undefined,\n    \"description\": \"\",\n    \"name\": \"buttonRef\",\n    \"table\": Object {\n      \"category\": \"view child\",\n      \"defaultValue\": Object {\n        \"summary\": undefined,\n      },\n      \"type\": Object {\n        \"required\": true,\n        \"summary\": \"ElementRef\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"void\",\n    },\n  },\n  \"calc\": Object {\n    \"defaultValue\": undefined,\n    \"description\": \"\n\nAn internal calculation method which adds \\`x\\` and \\`y\\` together.\n\n\",\n    \"name\": \"calc\",\n    \"table\": Object {\n      \"category\": \"methods\",\n      \"defaultValue\": Object {\n        \"summary\": undefined,\n      },\n      \"type\": Object {\n        \"required\": false,\n        \"summary\": \"(x: number, y: string | number) => number\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"void\",\n    },\n  },\n  \"focus\": Object {\n    \"defaultValue\": false,\n    \"description\": \"\",\n    \"name\": \"focus\",\n    \"table\": Object {\n      \"category\": \"properties\",\n      \"defaultValue\": Object {\n        \"summary\": false,\n      },\n      \"type\": Object {\n        \"required\": true,\n        \"summary\": \"\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"boolean\",\n    },\n  },\n  \"inputValue\": Object {\n    \"defaultValue\": undefined,\n    \"description\": \"\nSetter for \\`inputValue\\` that is also an \\`@Input\\`.\",\n    \"name\": \"inputValue\",\n    \"table\": Object {\n      \"category\": \"inputs\",\n      \"defaultValue\": Object {\n        \"summary\": undefined,\n      },\n      \"type\": Object {\n        \"required\": true,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n    },\n  },\n  \"internalProperty\": Object {\n    \"defaultValue\": \"Public hello\",\n    \"description\": \"\nPublic value.\",\n    \"name\": \"internalProperty\",\n    \"table\": Object {\n      \"category\": \"properties\",\n      \"defaultValue\": Object {\n        \"summary\": \"Public hello\",\n      },\n      \"type\": Object {\n        \"required\": true,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n    },\n  },\n  \"isDisabled\": Object {\n    \"defaultValue\": false,\n    \"description\": \"\nSets the button to a disabled state.\",\n    \"name\": \"isDisabled\",\n    \"table\": Object {\n      \"category\": \"inputs\",\n      \"defaultValue\": Object {\n        \"summary\": false,\n      },\n      \"type\": Object {\n        \"required\": true,\n        \"summary\": \"boolean\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"boolean\",\n    },\n  },\n  \"item\": Object {\n    \"defaultValue\": undefined,\n    \"description\": undefined,\n    \"name\": \"item\",\n    \"table\": Object {\n      \"category\": \"inputs\",\n      \"defaultValue\": Object {\n        \"summary\": undefined,\n      },\n      \"type\": Object {\n        \"required\": true,\n        \"summary\": \"T[]\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"object\",\n    },\n  },\n  \"label\": Object {\n    \"defaultValue\": undefined,\n    \"description\": \"\n\nThe inner text of the button.\n\n\",\n    \"name\": \"label\",\n    \"table\": Object {\n      \"category\": \"inputs\",\n      \"defaultValue\": Object {\n        \"summary\": undefined,\n      },\n      \"type\": Object {\n        \"required\": true,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n    },\n  },\n  \"onClick\": Object {\n    \"action\": \"onClick\",\n    \"defaultValue\": undefined,\n    \"description\": \"\n\nHandler to be called when the button is clicked by a user.\n\nWill also block the emission of the event if \\`isDisabled\\` is true.\n\",\n    \"name\": \"onClick\",\n    \"table\": Object {\n      \"category\": \"outputs\",\n      \"defaultValue\": Object {\n        \"summary\": undefined,\n      },\n      \"type\": Object {\n        \"required\": true,\n        \"summary\": \"EventEmitter\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"void\",\n    },\n  },\n  \"onClickListener\": Object {\n    \"defaultValue\": undefined,\n    \"description\": undefined,\n    \"name\": \"onClickListener\",\n    \"table\": Object {\n      \"category\": \"methods\",\n      \"defaultValue\": Object {\n        \"summary\": undefined,\n      },\n      \"type\": Object {\n        \"required\": false,\n        \"summary\": \"(btn: ) => void\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"void\",\n    },\n  },\n  \"privateMethod\": Object {\n    \"defaultValue\": undefined,\n    \"description\": \"\n\nA private method.\n\n\",\n    \"name\": \"privateMethod\",\n    \"table\": Object {\n      \"category\": \"methods\",\n      \"defaultValue\": Object {\n        \"summary\": undefined,\n      },\n      \"type\": Object {\n        \"required\": false,\n        \"summary\": \"(password: string) => void\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"void\",\n    },\n  },\n  \"processedItem\": Object {\n    \"defaultValue\": undefined,\n    \"description\": \"\",\n    \"name\": \"processedItem\",\n    \"table\": Object {\n      \"category\": \"properties\",\n      \"defaultValue\": Object {\n        \"summary\": undefined,\n      },\n      \"type\": Object {\n        \"required\": true,\n        \"summary\": \"T[]\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"object\",\n    },\n  },\n  \"protectedMethod\": Object {\n    \"defaultValue\": undefined,\n    \"description\": \"\n\nA protected method.\n\n\",\n    \"name\": \"protectedMethod\",\n    \"table\": Object {\n      \"category\": \"methods\",\n      \"defaultValue\": Object {\n        \"summary\": undefined,\n      },\n      \"type\": Object {\n        \"required\": false,\n        \"summary\": \"(id?: number) => void\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"void\",\n    },\n  },\n  \"publicMethod\": Object {\n    \"defaultValue\": undefined,\n    \"description\": \"\nA public method using an interface.\",\n    \"name\": \"publicMethod\",\n    \"table\": Object {\n      \"category\": \"methods\",\n      \"defaultValue\": Object {\n        \"summary\": undefined,\n      },\n      \"type\": Object {\n        \"required\": false,\n        \"summary\": \"(things: ISomeInterface) => void\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"void\",\n    },\n  },\n  \"showKeyAlias\": Object {\n    \"defaultValue\": undefined,\n    \"description\": undefined,\n    \"name\": \"showKeyAlias\",\n    \"table\": Object {\n      \"category\": \"inputs\",\n      \"defaultValue\": Object {\n        \"summary\": undefined,\n      },\n      \"type\": Object {\n        \"required\": true,\n        \"summary\": \"\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"void\",\n    },\n  },\n  \"size\": Object {\n    \"defaultValue\": \"medium\",\n    \"description\": \"\nSize of the button.\",\n    \"name\": \"size\",\n    \"table\": Object {\n      \"category\": \"inputs\",\n      \"defaultValue\": Object {\n        \"summary\": \"medium\",\n      },\n      \"type\": Object {\n        \"required\": true,\n        \"summary\": \"ButtonSize\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"object\",\n    },\n  },\n  \"someDataObject\": Object {\n    \"defaultValue\": undefined,\n    \"description\": \"\nSpecifies some arbitrary object\",\n    \"name\": \"someDataObject\",\n    \"table\": Object {\n      \"category\": \"inputs\",\n      \"defaultValue\": Object {\n        \"summary\": undefined,\n      },\n      \"type\": Object {\n        \"required\": true,\n        \"summary\": \"ISomeInterface\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"object\",\n    },\n  },\n  \"somethingYouShouldNotUse\": Object {\n    \"defaultValue\": false,\n    \"description\": \"\n\nSome input you shouldn't use.\n\n\",\n    \"name\": \"somethingYouShouldNotUse\",\n    \"table\": Object {\n      \"category\": \"inputs\",\n      \"defaultValue\": Object {\n        \"summary\": false,\n      },\n      \"type\": Object {\n        \"required\": true,\n        \"summary\": \"boolean\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"boolean\",\n    },\n  },\n}\n`;\n"
  },
  {
    "path": "code/frameworks/angular/src/client/docs/__testfixtures__/doc-button/compodoc-posix.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`angular component properties doc-button 1`] = `\nObject {\n  \"classes\": Array [],\n  \"components\": Array [\n    Object {\n      \"accessors\": Object {\n        \"inputValue\": Object {\n          \"getSignature\": Object {\n            \"description\": \"<p>Getter for <code>inputValue</code>.</p>\n\",\n            \"line\": 116,\n            \"name\": \"inputValue\",\n            \"rawdescription\": \"\nGetter for \\`inputValue\\`.\",\n            \"returnType\": \"\",\n            \"type\": \"\",\n          },\n          \"name\": \"inputValue\",\n          \"setSignature\": Object {\n            \"args\": Array [\n              Object {\n                \"deprecated\": false,\n                \"deprecationMessage\": \"\",\n                \"name\": \"value\",\n                \"type\": \"string\",\n              },\n            ],\n            \"deprecated\": false,\n            \"deprecationMessage\": \"\",\n            \"description\": \"<p>Setter for <code>inputValue</code> that is also an <code>@Input</code>.</p>\n\",\n            \"jsdoctags\": Array [\n              Object {\n                \"deprecated\": false,\n                \"deprecationMessage\": \"\",\n                \"name\": \"value\",\n                \"tagName\": Object {\n                  \"text\": \"param\",\n                },\n                \"type\": \"string\",\n              },\n            ],\n            \"line\": 111,\n            \"name\": \"inputValue\",\n            \"rawdescription\": \"\nSetter for \\`inputValue\\` that is also an \\`@Input\\`.\",\n            \"returnType\": \"void\",\n            \"type\": \"void\",\n          },\n        },\n        \"item\": Object {\n          \"name\": \"item\",\n          \"setSignature\": Object {\n            \"args\": Array [\n              Object {\n                \"deprecated\": false,\n                \"deprecationMessage\": \"\",\n                \"name\": \"item\",\n                \"type\": \"T[]\",\n              },\n            ],\n            \"deprecated\": false,\n            \"deprecationMessage\": \"\",\n            \"jsdoctags\": Array [\n              Object {\n                \"deprecated\": false,\n                \"deprecationMessage\": \"\",\n                \"name\": \"item\",\n                \"tagName\": Object {\n                  \"text\": \"param\",\n                },\n                \"type\": \"T[]\",\n              },\n            ],\n            \"line\": 196,\n            \"name\": \"item\",\n            \"returnType\": \"void\",\n            \"type\": \"void\",\n          },\n        },\n        \"value\": Object {\n          \"getSignature\": Object {\n            \"description\": \"<p>Get the private value.</p>\n\",\n            \"line\": 155,\n            \"name\": \"value\",\n            \"rawdescription\": \"\nGet the private value.\",\n            \"returnType\": \"string | number\",\n            \"type\": \"\",\n          },\n          \"name\": \"value\",\n          \"setSignature\": Object {\n            \"args\": Array [\n              Object {\n                \"deprecated\": false,\n                \"deprecationMessage\": \"\",\n                \"name\": \"value\",\n                \"type\": \"string | number\",\n              },\n            ],\n            \"deprecated\": false,\n            \"deprecationMessage\": \"\",\n            \"description\": \"<p>Set the private value.</p>\n\",\n            \"jsdoctags\": Array [\n              Object {\n                \"deprecated\": false,\n                \"deprecationMessage\": \"\",\n                \"name\": \"value\",\n                \"tagName\": Object {\n                  \"text\": \"param\",\n                },\n                \"type\": \"string | number\",\n              },\n            ],\n            \"line\": 150,\n            \"name\": \"value\",\n            \"rawdescription\": \"\nSet the private value.\",\n            \"returnType\": \"void\",\n            \"type\": \"void\",\n          },\n        },\n      },\n      \"assetsDirs\": Array [],\n      \"deprecated\": false,\n      \"deprecationMessage\": \"\",\n      \"description\": \"<p>This is a simple button that demonstrates various JSDoc handling in Storybook Docs for Angular.</p>\n<p>It supports <a href=\\\\\"https://en.wikipedia.org/wiki/Markdown\\\\\">markdown</a>, so you can embed formatted text,\nlike <strong>bold</strong>, <em>italic</em>, and <code>inline code</code>.</p>\n<blockquote>\n<p>How you like dem apples?! It&#39;s never been easier to document all your components.</p>\n</blockquote>\n\",\n      \"encapsulation\": Array [],\n      \"entryComponents\": Array [],\n      \"file\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n      \"hostBindings\": Array [\n        Object {\n          \"decorators\": Array [],\n          \"defaultValue\": \"false\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"line\": 125,\n          \"name\": \"class.focused\",\n          \"type\": \"boolean\",\n        },\n      ],\n      \"hostListeners\": Array [\n        Object {\n          \"args\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"btn\",\n              \"type\": \"\",\n            },\n          ],\n          \"argsDecorator\": Array [\n            \"$event.target\",\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"line\": 121,\n          \"name\": \"click\",\n        },\n      ],\n      \"id\": \"component-InputComponent-d145da25329b094ee29610c45a9e46387cb39eddb2a67b4c9fadb84bcec76eacd60d131e48d98b2ee5725dedd25f2eb299b704e8e0a34307d6e84f6e57d57044\",\n      \"inputs\": Array [],\n      \"inputsClass\": Array [\n        Object {\n          \"decorators\": Array [],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Specify the accent-type of the button</p>\n\",\n          \"line\": 57,\n          \"name\": \"accent\",\n          \"rawdescription\": \"\nSpecify the accent-type of the button\",\n          \"type\": \"ButtonAccent\",\n        },\n        Object {\n          \"decorators\": Array [],\n          \"defaultValue\": \"'secondary'\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Appearance style of the button.</p>\n\",\n          \"line\": 53,\n          \"name\": \"appearance\",\n          \"rawdescription\": \"\nAppearance style of the button.\",\n          \"type\": \"\\\\\"primary\\\\\" | \\\\\"secondary\\\\\"\",\n        },\n        Object {\n          \"decorators\": Array [],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Setter for <code>inputValue</code> that is also an <code>@Input</code>.</p>\n\",\n          \"line\": 111,\n          \"name\": \"inputValue\",\n          \"rawdescription\": \"\nSetter for \\`inputValue\\` that is also an \\`@Input\\`.\",\n          \"type\": \"string\",\n        },\n        Object {\n          \"decorators\": Array [],\n          \"defaultValue\": \"false\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Sets the button to a disabled state.</p>\n\",\n          \"line\": 61,\n          \"name\": \"isDisabled\",\n          \"rawdescription\": \"\nSets the button to a disabled state.\",\n          \"type\": \"boolean\",\n        },\n        Object {\n          \"decorators\": Array [],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"line\": 196,\n          \"name\": \"item\",\n          \"type\": \"T[]\",\n        },\n        Object {\n          \"decorators\": Array [],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>The inner text of the button.</p>\n\",\n          \"jsdoctags\": Array [\n            Object {\n              \"comment\": \"\",\n              \"end\": 1587,\n              \"flags\": 4227072,\n              \"kind\": 325,\n              \"modifierFlagsCache\": 0,\n              \"pos\": 1574,\n              \"tagName\": Object {\n                \"end\": 1583,\n                \"escapedText\": \"required\",\n                \"flags\": 4227072,\n                \"kind\": 79,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 1575,\n                \"transformFlags\": 0,\n              },\n              \"transformFlags\": 0,\n            },\n          ],\n          \"line\": 69,\n          \"name\": \"label\",\n          \"rawdescription\": \"\n\nThe inner text of the button.\n\n\",\n          \"type\": \"string\",\n        },\n        Object {\n          \"decorators\": Array [],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"line\": 193,\n          \"name\": \"showKeyAlias\",\n          \"type\": \"\",\n        },\n        Object {\n          \"decorators\": Array [],\n          \"defaultValue\": \"'medium'\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Size of the button.</p>\n\",\n          \"line\": 73,\n          \"name\": \"size\",\n          \"rawdescription\": \"\nSize of the button.\",\n          \"type\": \"ButtonSize\",\n        },\n        Object {\n          \"decorators\": Array [],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Specifies some arbitrary object</p>\n\",\n          \"line\": 76,\n          \"name\": \"someDataObject\",\n          \"rawdescription\": \"\nSpecifies some arbitrary object\",\n          \"type\": \"ISomeInterface\",\n        },\n        Object {\n          \"decorators\": Array [],\n          \"defaultValue\": \"false\",\n          \"deprecated\": true,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Some input you shouldn&#39;t use.</p>\n\",\n          \"jsdoctags\": Array [\n            Object {\n              \"comment\": \"\",\n              \"end\": 1864,\n              \"flags\": 4227072,\n              \"kind\": 329,\n              \"modifierFlagsCache\": 0,\n              \"pos\": 1849,\n              \"tagName\": Object {\n                \"end\": 1860,\n                \"escapedText\": \"deprecated\",\n                \"flags\": 4227072,\n                \"kind\": 79,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 1850,\n                \"transformFlags\": 0,\n              },\n              \"transformFlags\": 0,\n            },\n          ],\n          \"line\": 84,\n          \"name\": \"somethingYouShouldNotUse\",\n          \"rawdescription\": \"\n\nSome input you shouldn't use.\n\n\",\n          \"type\": \"boolean\",\n        },\n      ],\n      \"methodsClass\": Array [\n        Object {\n          \"args\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"x\",\n              \"type\": \"number\",\n            },\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"y\",\n              \"type\": \"string | number\",\n            },\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>An internal calculation method which adds <code>x</code> and <code>y</code> together.</p>\n\",\n          \"jsdoctags\": Array [\n            Object {\n              \"comment\": \"<p>Some number you&#39;d like to use.</p>\n\",\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": Object {\n                \"end\": 3580,\n                \"escapedText\": \"x\",\n                \"flags\": 4227072,\n                \"kind\": 79,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 3579,\n                \"transformFlags\": 0,\n              },\n              \"tagName\": Object {\n                \"end\": 3578,\n                \"escapedText\": \"param\",\n                \"flags\": 4227072,\n                \"kind\": 79,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 3573,\n                \"transformFlags\": 0,\n              },\n              \"type\": \"number\",\n            },\n            Object {\n              \"comment\": \"<p>Some other number or string you&#39;d like to use, will have <code>parseInt()</code> applied before calculation.</p>\n\",\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": Object {\n                \"end\": 3625,\n                \"escapedText\": \"y\",\n                \"flags\": 4227072,\n                \"kind\": 79,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 3624,\n                \"transformFlags\": 0,\n              },\n              \"tagName\": Object {\n                \"end\": 3623,\n                \"escapedText\": \"param\",\n                \"flags\": 4227072,\n                \"kind\": 79,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 3618,\n                \"transformFlags\": 0,\n              },\n              \"type\": \"string | number\",\n            },\n          ],\n          \"line\": 165,\n          \"modifierKind\": Array [\n            123,\n          ],\n          \"name\": \"calc\",\n          \"optional\": false,\n          \"rawdescription\": \"\n\nAn internal calculation method which adds \\`x\\` and \\`y\\` together.\n\n\",\n          \"returnType\": \"number\",\n          \"typeParameters\": Array [],\n        },\n        Object {\n          \"args\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"btn\",\n              \"type\": \"\",\n            },\n          ],\n          \"decorators\": Array [\n            Object {\n              \"name\": \"HostListener\",\n              \"stringifiedArguments\": \"'click', ['$event.target']\",\n            },\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"jsdoctags\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"btn\",\n              \"tagName\": Object {\n                \"text\": \"param\",\n              },\n              \"type\": \"\",\n            },\n          ],\n          \"line\": 121,\n          \"name\": \"onClickListener\",\n          \"optional\": false,\n          \"returnType\": \"void\",\n          \"typeParameters\": Array [],\n        },\n        Object {\n          \"args\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"password\",\n              \"type\": \"string\",\n            },\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>A private method.</p>\n\",\n          \"jsdoctags\": Array [\n            Object {\n              \"comment\": \"<p>Some <code>password</code>.</p>\n\",\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": Object {\n                \"end\": 4141,\n                \"escapedText\": \"password\",\n                \"flags\": 4227072,\n                \"kind\": 79,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 4133,\n                \"transformFlags\": 0,\n              },\n              \"tagName\": Object {\n                \"end\": 4132,\n                \"escapedText\": \"param\",\n                \"flags\": 4227072,\n                \"kind\": 79,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 4127,\n                \"transformFlags\": 0,\n              },\n              \"type\": \"string\",\n            },\n          ],\n          \"line\": 188,\n          \"modifierKind\": Array [\n            121,\n          ],\n          \"name\": \"privateMethod\",\n          \"optional\": false,\n          \"rawdescription\": \"\n\nA private method.\n\n\",\n          \"returnType\": \"void\",\n          \"typeParameters\": Array [],\n        },\n        Object {\n          \"args\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"id\",\n              \"optional\": true,\n              \"type\": \"number\",\n            },\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>A protected method.</p>\n\",\n          \"jsdoctags\": Array [\n            Object {\n              \"comment\": \"<p>Some <code>id</code>.</p>\n\",\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": Object {\n                \"end\": 4000,\n                \"escapedText\": \"id\",\n                \"flags\": 4227072,\n                \"kind\": 79,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 3998,\n                \"transformFlags\": 0,\n              },\n              \"optional\": true,\n              \"tagName\": Object {\n                \"end\": 3997,\n                \"escapedText\": \"param\",\n                \"flags\": 4227072,\n                \"kind\": 79,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 3992,\n                \"transformFlags\": 0,\n              },\n              \"type\": \"number\",\n            },\n          ],\n          \"line\": 179,\n          \"modifierKind\": Array [\n            122,\n          ],\n          \"name\": \"protectedMethod\",\n          \"optional\": false,\n          \"rawdescription\": \"\n\nA protected method.\n\n\",\n          \"returnType\": \"void\",\n          \"typeParameters\": Array [],\n        },\n        Object {\n          \"args\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"things\",\n              \"type\": \"ISomeInterface\",\n            },\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>A public method using an interface.</p>\n\",\n          \"jsdoctags\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"things\",\n              \"tagName\": Object {\n                \"text\": \"param\",\n              },\n              \"type\": \"ISomeInterface\",\n            },\n          ],\n          \"line\": 170,\n          \"modifierKind\": Array [\n            123,\n          ],\n          \"name\": \"publicMethod\",\n          \"optional\": false,\n          \"rawdescription\": \"\nA public method using an interface.\",\n          \"returnType\": \"void\",\n          \"typeParameters\": Array [],\n        },\n      ],\n      \"name\": \"InputComponent\",\n      \"outputs\": Array [],\n      \"outputsClass\": Array [\n        Object {\n          \"defaultValue\": \"new EventEmitter<Event>()\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Handler to be called when the button is clicked by a user.</p>\n<p>Will also block the emission of the event if <code>isDisabled</code> is true.</p>\n\",\n          \"line\": 92,\n          \"name\": \"onClick\",\n          \"rawdescription\": \"\n\nHandler to be called when the button is clicked by a user.\n\nWill also block the emission of the event if \\`isDisabled\\` is true.\n\",\n          \"type\": \"EventEmitter\",\n        },\n      ],\n      \"propertiesClass\": Array [\n        Object {\n          \"defaultValue\": \"'some value'\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 107,\n          \"modifierKind\": Array [\n            121,\n          ],\n          \"name\": \"_inputValue\",\n          \"optional\": false,\n          \"type\": \"string\",\n        },\n        Object {\n          \"defaultValue\": \"'Private hello'\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Private value.</p>\n\",\n          \"line\": 147,\n          \"modifierKind\": Array [\n            121,\n          ],\n          \"name\": \"_value\",\n          \"optional\": false,\n          \"rawdescription\": \"\nPrivate value.\",\n          \"type\": \"string\",\n        },\n        Object {\n          \"decorators\": Array [\n            Object {\n              \"name\": \"ViewChild\",\n              \"stringifiedArguments\": \"'buttonRef', {static: false}\",\n            },\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 49,\n          \"name\": \"buttonRef\",\n          \"optional\": false,\n          \"type\": \"ElementRef\",\n        },\n        Object {\n          \"decorators\": Array [\n            Object {\n              \"name\": \"HostBinding\",\n              \"stringifiedArguments\": \"'class.focused'\",\n            },\n          ],\n          \"defaultValue\": \"false\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 125,\n          \"name\": \"focus\",\n          \"optional\": false,\n          \"type\": \"\",\n        },\n        Object {\n          \"defaultValue\": \"'Public hello'\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Public value.</p>\n\",\n          \"line\": 144,\n          \"modifierKind\": Array [\n            123,\n          ],\n          \"name\": \"internalProperty\",\n          \"optional\": false,\n          \"rawdescription\": \"\nPublic value.\",\n          \"type\": \"string\",\n        },\n        Object {\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 200,\n          \"modifierKind\": Array [\n            123,\n          ],\n          \"name\": \"processedItem\",\n          \"optional\": false,\n          \"type\": \"T[]\",\n        },\n      ],\n      \"providers\": Array [],\n      \"rawdescription\": \"\n\nThis is a simple button that demonstrates various JSDoc handling in Storybook Docs for Angular.\n\nIt supports [markdown](https://en.wikipedia.org/wiki/Markdown), so you can embed formatted text,\nlike **bold**, _italic_, and \\`inline code\\`.\n\n> How you like dem apples?! It's never been easier to document all your components.\n\n\",\n      \"selector\": \"doc-button\",\n      \"sourceCode\": \"import {\n  Component,\n  ElementRef,\n  EventEmitter,\n  HostBinding,\n  HostListener,\n  Input,\n  Output,\n  ViewChild,\n} from '@angular/core';\n\nexport const exportedConstant = 'An exported constant';\n\nexport type ButtonSize = 'small' | 'medium' | 'large' | 'xlarge';\n\nexport enum ButtonAccent {\n  'Normal' = 'Normal',\n  'High' = 'High',\n}\n\nexport interface ISomeInterface {\n  one: string;\n  two: boolean;\n  three: any[];\n}\n\n/**\n * This is a simple button that demonstrates various JSDoc handling in Storybook Docs for Angular.\n *\n * It supports [markdown](https://en.wikipedia.org/wiki/Markdown), so you can embed formatted text,\n * like **bold**, _italic_, and \\`inline code\\`.\n *\n * > How you like dem apples?! It's never been easier to document all your components.\n *\n * @string Hello world\n * @link [Example](http://example.com)\n * @code \\`ThingThing\\`\n * @html <span class=\\\\\"badge\\\\\">aaa</span>\n */\n@Component({\n  selector: 'doc-button',\n  template: '<button>{{ label }}</button>',\n})\nexport class InputComponent<T> {\n  @ViewChild('buttonRef', { static: false }) buttonRef: ElementRef;\n\n  /** Appearance style of the button. */\n  @Input()\n  public appearance: 'primary' | 'secondary' = 'secondary';\n\n  /** Specify the accent-type of the button */\n  @Input()\n  public accent: ButtonAccent;\n\n  /** Sets the button to a disabled state. */\n  @Input()\n  public isDisabled = false;\n\n  /**\n   * The inner text of the button.\n   *\n   * @required\n   */\n  @Input()\n  public label: string;\n\n  /** Size of the button. */\n  @Input()\n  public size?: ButtonSize = 'medium';\n\n  /** Specifies some arbitrary object */\n  @Input() public someDataObject: ISomeInterface;\n\n  /**\n   * Some input you shouldn't use.\n   *\n   * @deprecated\n   */\n  @Input()\n  public somethingYouShouldNotUse = false;\n\n  /**\n   * Handler to be called when the button is clicked by a user.\n   *\n   * Will also block the emission of the event if \\`isDisabled\\` is true.\n   */\n  @Output()\n  public onClick = new EventEmitter<Event>();\n\n  /**\n   * This is an internal method that we don't want to document and have added the \\`ignore\\` annotation to.\n   *\n   * @ignore\n   */\n  public handleClick(event: Event) {\n    event.stopPropagation();\n\n    if (!this.isDisabled) {\n      this.onClick.emit(event);\n    }\n  }\n\n  private _inputValue = 'some value';\n\n  /** Setter for \\`inputValue\\` that is also an \\`@Input\\`. */\n  @Input()\n  public set inputValue(value: string) {\n    this._inputValue = value;\n  }\n\n  /** Getter for \\`inputValue\\`. */\n  public get inputValue() {\n    return this._inputValue;\n  }\n\n  @HostListener('click', ['$event.target'])\n  onClickListener(btn) {\n    console.log('button', btn);\n  }\n\n  @HostBinding('class.focused') focus = false;\n\n  /**\n   * Returns all the CSS classes for the button.\n   *\n   * @ignore\n   */\n  public get classes(): string[] {\n    return [this.appearance, this.size]\n      .filter((_class) => !!_class)\n      .map((_class) => \\`btn-\\${_class}\\`);\n  }\n\n  /**\n   * @ignore\n   */\n  public ignoredProperty = 'Ignore me';\n\n  /** Public value. */\n  public internalProperty = 'Public hello';\n\n  /** Private value. */\n  private _value = 'Private hello';\n\n  /** Set the private value. */\n  public set value(value: string | number) {\n    this._value = \\`\\${value}\\`;\n  }\n\n  /** Get the private value. */\n  public get value(): string | number {\n    return this._value;\n  }\n\n  /**\n   * An internal calculation method which adds \\`x\\` and \\`y\\` together.\n   *\n   * @param x Some number you'd like to use.\n   * @param y Some other number or string you'd like to use, will have \\`parseInt()\\` applied before calculation.\n   */\n  public calc(x: number, y: string | number): number {\n    return x + parseInt(\\`\\${y}\\`, 10);\n  }\n\n  /** A public method using an interface. */\n  public publicMethod(things: ISomeInterface) {\n    console.log(things);\n  }\n\n  /**\n   * A protected method.\n   *\n   * @param id Some \\`id\\`.\n   */\n  protected protectedMethod(id?: number) {\n    console.log(id);\n  }\n\n  /**\n   * A private method.\n   *\n   * @param password Some \\`password\\`.\n   */\n  private privateMethod(password: string) {\n    console.log(password);\n  }\n\n  @Input('showKeyAlias')\n  public showKey: keyof T;\n\n  @Input()\n  public set item(item: T[]) {\n    this.processedItem = item;\n  }\n\n  public processedItem: T[];\n}\n\",\n      \"styleUrls\": Array [],\n      \"styleUrlsData\": \"\",\n      \"styles\": Array [],\n      \"stylesData\": \"\",\n      \"template\": \"<button>{{ label }}</button>\",\n      \"templateUrl\": Array [],\n      \"type\": \"component\",\n      \"viewProviders\": Array [],\n    },\n  ],\n  \"coverage\": Object {\n    \"count\": 21,\n    \"files\": Array [\n      Object {\n        \"coverageCount\": \"16/25\",\n        \"coveragePercent\": 64,\n        \"filePath\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n        \"linktype\": \"component\",\n        \"name\": \"InputComponent\",\n        \"status\": \"good\",\n        \"type\": \"component\",\n      },\n      Object {\n        \"coverageCount\": \"0/4\",\n        \"coveragePercent\": 0,\n        \"filePath\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n        \"linktype\": \"interface\",\n        \"name\": \"ISomeInterface\",\n        \"status\": \"low\",\n        \"type\": \"interface\",\n      },\n      Object {\n        \"coverageCount\": \"0/1\",\n        \"coveragePercent\": 0,\n        \"filePath\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n        \"linksubtype\": \"variable\",\n        \"linktype\": \"miscellaneous\",\n        \"name\": \"exportedConstant\",\n        \"status\": \"low\",\n        \"type\": \"variable\",\n      },\n    ],\n    \"status\": \"low\",\n  },\n  \"directives\": Array [],\n  \"guards\": Array [],\n  \"injectables\": Array [],\n  \"interceptors\": Array [],\n  \"interfaces\": Array [\n    Object {\n      \"deprecated\": false,\n      \"deprecationMessage\": \"\",\n      \"file\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n      \"id\": \"interface-ISomeInterface-d145da25329b094ee29610c45a9e46387cb39eddb2a67b4c9fadb84bcec76eacd60d131e48d98b2ee5725dedd25f2eb299b704e8e0a34307d6e84f6e57d57044\",\n      \"indexSignatures\": Array [],\n      \"kind\": 165,\n      \"methods\": Array [],\n      \"name\": \"ISomeInterface\",\n      \"properties\": Array [\n        Object {\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 26,\n          \"name\": \"one\",\n          \"optional\": false,\n          \"type\": \"string\",\n        },\n        Object {\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 28,\n          \"name\": \"three\",\n          \"optional\": false,\n          \"type\": \"any[]\",\n        },\n        Object {\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 27,\n          \"name\": \"two\",\n          \"optional\": false,\n          \"type\": \"boolean\",\n        },\n      ],\n      \"sourceCode\": \"import {\n  Component,\n  ElementRef,\n  EventEmitter,\n  HostBinding,\n  HostListener,\n  Input,\n  Output,\n  ViewChild,\n} from '@angular/core';\n\nexport const exportedConstant = 'An exported constant';\n\nexport type ButtonSize = 'small' | 'medium' | 'large' | 'xlarge';\n\nexport enum ButtonAccent {\n  'Normal' = 'Normal',\n  'High' = 'High',\n}\n\nexport interface ISomeInterface {\n  one: string;\n  two: boolean;\n  three: any[];\n}\n\n/**\n * This is a simple button that demonstrates various JSDoc handling in Storybook Docs for Angular.\n *\n * It supports [markdown](https://en.wikipedia.org/wiki/Markdown), so you can embed formatted text,\n * like **bold**, _italic_, and \\`inline code\\`.\n *\n * > How you like dem apples?! It's never been easier to document all your components.\n *\n * @string Hello world\n * @link [Example](http://example.com)\n * @code \\`ThingThing\\`\n * @html <span class=\\\\\"badge\\\\\">aaa</span>\n */\n@Component({\n  selector: 'doc-button',\n  template: '<button>{{ label }}</button>',\n})\nexport class InputComponent<T> {\n  @ViewChild('buttonRef', { static: false }) buttonRef: ElementRef;\n\n  /** Appearance style of the button. */\n  @Input()\n  public appearance: 'primary' | 'secondary' = 'secondary';\n\n  /** Specify the accent-type of the button */\n  @Input()\n  public accent: ButtonAccent;\n\n  /** Sets the button to a disabled state. */\n  @Input()\n  public isDisabled = false;\n\n  /**\n   * The inner text of the button.\n   *\n   * @required\n   */\n  @Input()\n  public label: string;\n\n  /** Size of the button. */\n  @Input()\n  public size?: ButtonSize = 'medium';\n\n  /** Specifies some arbitrary object */\n  @Input() public someDataObject: ISomeInterface;\n\n  /**\n   * Some input you shouldn't use.\n   *\n   * @deprecated\n   */\n  @Input()\n  public somethingYouShouldNotUse = false;\n\n  /**\n   * Handler to be called when the button is clicked by a user.\n   *\n   * Will also block the emission of the event if \\`isDisabled\\` is true.\n   */\n  @Output()\n  public onClick = new EventEmitter<Event>();\n\n  /**\n   * This is an internal method that we don't want to document and have added the \\`ignore\\` annotation to.\n   *\n   * @ignore\n   */\n  public handleClick(event: Event) {\n    event.stopPropagation();\n\n    if (!this.isDisabled) {\n      this.onClick.emit(event);\n    }\n  }\n\n  private _inputValue = 'some value';\n\n  /** Setter for \\`inputValue\\` that is also an \\`@Input\\`. */\n  @Input()\n  public set inputValue(value: string) {\n    this._inputValue = value;\n  }\n\n  /** Getter for \\`inputValue\\`. */\n  public get inputValue() {\n    return this._inputValue;\n  }\n\n  @HostListener('click', ['$event.target'])\n  onClickListener(btn) {\n    console.log('button', btn);\n  }\n\n  @HostBinding('class.focused') focus = false;\n\n  /**\n   * Returns all the CSS classes for the button.\n   *\n   * @ignore\n   */\n  public get classes(): string[] {\n    return [this.appearance, this.size]\n      .filter((_class) => !!_class)\n      .map((_class) => \\`btn-\\${_class}\\`);\n  }\n\n  /**\n   * @ignore\n   */\n  public ignoredProperty = 'Ignore me';\n\n  /** Public value. */\n  public internalProperty = 'Public hello';\n\n  /** Private value. */\n  private _value = 'Private hello';\n\n  /** Set the private value. */\n  public set value(value: string | number) {\n    this._value = \\`\\${value}\\`;\n  }\n\n  /** Get the private value. */\n  public get value(): string | number {\n    return this._value;\n  }\n\n  /**\n   * An internal calculation method which adds \\`x\\` and \\`y\\` together.\n   *\n   * @param x Some number you'd like to use.\n   * @param y Some other number or string you'd like to use, will have \\`parseInt()\\` applied before calculation.\n   */\n  public calc(x: number, y: string | number): number {\n    return x + parseInt(\\`\\${y}\\`, 10);\n  }\n\n  /** A public method using an interface. */\n  public publicMethod(things: ISomeInterface) {\n    console.log(things);\n  }\n\n  /**\n   * A protected method.\n   *\n   * @param id Some \\`id\\`.\n   */\n  protected protectedMethod(id?: number) {\n    console.log(id);\n  }\n\n  /**\n   * A private method.\n   *\n   * @param password Some \\`password\\`.\n   */\n  private privateMethod(password: string) {\n    console.log(password);\n  }\n\n  @Input('showKeyAlias')\n  public showKey: keyof T;\n\n  @Input()\n  public set item(item: T[]) {\n    this.processedItem = item;\n  }\n\n  public processedItem: T[];\n}\n\",\n      \"type\": \"interface\",\n    },\n  ],\n  \"miscellaneous\": Object {\n    \"enumerations\": Array [\n      Object {\n        \"childs\": Array [\n          Object {\n            \"deprecated\": false,\n            \"deprecationMessage\": \"\",\n            \"name\": \"Normal\",\n            \"value\": \"Normal\",\n          },\n          Object {\n            \"deprecated\": false,\n            \"deprecationMessage\": \"\",\n            \"name\": \"High\",\n            \"value\": \"High\",\n          },\n        ],\n        \"ctype\": \"miscellaneous\",\n        \"deprecated\": false,\n        \"deprecationMessage\": \"\",\n        \"description\": \"\",\n        \"file\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n        \"name\": \"ButtonAccent\",\n        \"subtype\": \"enum\",\n      },\n    ],\n    \"functions\": Array [],\n    \"groupedEnumerations\": Object {\n      \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\": Array [\n        Object {\n          \"childs\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"Normal\",\n              \"value\": \"Normal\",\n            },\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"High\",\n              \"value\": \"High\",\n            },\n          ],\n          \"ctype\": \"miscellaneous\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"file\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n          \"name\": \"ButtonAccent\",\n          \"subtype\": \"enum\",\n        },\n      ],\n    },\n    \"groupedFunctions\": Object {},\n    \"groupedTypeAliases\": Object {\n      \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\": Array [\n        Object {\n          \"ctype\": \"miscellaneous\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"file\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n          \"kind\": 186,\n          \"name\": \"ButtonSize\",\n          \"rawtype\": \"\\\\\"small\\\\\" | \\\\\"medium\\\\\" | \\\\\"large\\\\\" | \\\\\"xlarge\\\\\"\",\n          \"subtype\": \"typealias\",\n        },\n      ],\n    },\n    \"groupedVariables\": Object {\n      \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\": Array [\n        Object {\n          \"ctype\": \"miscellaneous\",\n          \"defaultValue\": \"'An exported constant'\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"file\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n          \"name\": \"exportedConstant\",\n          \"subtype\": \"variable\",\n          \"type\": \"string\",\n        },\n      ],\n    },\n    \"typealiases\": Array [\n      Object {\n        \"ctype\": \"miscellaneous\",\n        \"deprecated\": false,\n        \"deprecationMessage\": \"\",\n        \"description\": \"\",\n        \"file\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n        \"kind\": 186,\n        \"name\": \"ButtonSize\",\n        \"rawtype\": \"\\\\\"small\\\\\" | \\\\\"medium\\\\\" | \\\\\"large\\\\\" | \\\\\"xlarge\\\\\"\",\n        \"subtype\": \"typealias\",\n      },\n    ],\n    \"variables\": Array [\n      Object {\n        \"ctype\": \"miscellaneous\",\n        \"defaultValue\": \"'An exported constant'\",\n        \"deprecated\": false,\n        \"deprecationMessage\": \"\",\n        \"file\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n        \"name\": \"exportedConstant\",\n        \"subtype\": \"variable\",\n        \"type\": \"string\",\n      },\n    ],\n  },\n  \"modules\": Array [],\n  \"pipes\": Array [],\n  \"routes\": Array [],\n}\n`;\n"
  },
  {
    "path": "code/frameworks/angular/src/client/docs/__testfixtures__/doc-button/compodoc-undefined.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`angular component properties doc-button 1`] = `\nObject {\n  \"classes\": Array [],\n  \"components\": Array [\n    Object {\n      \"accessors\": Object {\n        \"inputValue\": Object {\n          \"getSignature\": Object {\n            \"description\": \"<p>Getter for <code>inputValue</code>.</p>\n\",\n            \"line\": 116,\n            \"name\": \"inputValue\",\n            \"rawdescription\": \"\nGetter for \\`inputValue\\`.\",\n            \"returnType\": \"\",\n            \"type\": \"\",\n          },\n          \"name\": \"inputValue\",\n          \"setSignature\": Object {\n            \"args\": Array [\n              Object {\n                \"deprecated\": false,\n                \"deprecationMessage\": \"\",\n                \"name\": \"value\",\n                \"type\": \"string\",\n              },\n            ],\n            \"deprecated\": false,\n            \"deprecationMessage\": \"\",\n            \"description\": \"<p>Setter for <code>inputValue</code> that is also an <code>@Input</code>.</p>\n\",\n            \"jsdoctags\": Array [\n              Object {\n                \"deprecated\": false,\n                \"deprecationMessage\": \"\",\n                \"name\": \"value\",\n                \"tagName\": Object {\n                  \"text\": \"param\",\n                },\n                \"type\": \"string\",\n              },\n            ],\n            \"line\": 111,\n            \"name\": \"inputValue\",\n            \"rawdescription\": \"\nSetter for \\`inputValue\\` that is also an \\`@Input\\`.\",\n            \"returnType\": \"void\",\n            \"type\": \"void\",\n          },\n        },\n        \"item\": Object {\n          \"name\": \"item\",\n          \"setSignature\": Object {\n            \"args\": Array [\n              Object {\n                \"deprecated\": false,\n                \"deprecationMessage\": \"\",\n                \"name\": \"item\",\n                \"type\": \"T[]\",\n              },\n            ],\n            \"deprecated\": false,\n            \"deprecationMessage\": \"\",\n            \"jsdoctags\": Array [\n              Object {\n                \"deprecated\": false,\n                \"deprecationMessage\": \"\",\n                \"name\": \"item\",\n                \"tagName\": Object {\n                  \"text\": \"param\",\n                },\n                \"type\": \"T[]\",\n              },\n            ],\n            \"line\": 196,\n            \"name\": \"item\",\n            \"returnType\": \"void\",\n            \"type\": \"void\",\n          },\n        },\n        \"value\": Object {\n          \"getSignature\": Object {\n            \"description\": \"<p>Get the private value.</p>\n\",\n            \"line\": 155,\n            \"name\": \"value\",\n            \"rawdescription\": \"\nGet the private value.\",\n            \"returnType\": \"string | number\",\n            \"type\": \"\",\n          },\n          \"name\": \"value\",\n          \"setSignature\": Object {\n            \"args\": Array [\n              Object {\n                \"deprecated\": false,\n                \"deprecationMessage\": \"\",\n                \"name\": \"value\",\n                \"type\": \"string | number\",\n              },\n            ],\n            \"deprecated\": false,\n            \"deprecationMessage\": \"\",\n            \"description\": \"<p>Set the private value.</p>\n\",\n            \"jsdoctags\": Array [\n              Object {\n                \"deprecated\": false,\n                \"deprecationMessage\": \"\",\n                \"name\": \"value\",\n                \"tagName\": Object {\n                  \"text\": \"param\",\n                },\n                \"type\": \"string | number\",\n              },\n            ],\n            \"line\": 150,\n            \"name\": \"value\",\n            \"rawdescription\": \"\nSet the private value.\",\n            \"returnType\": \"void\",\n            \"type\": \"void\",\n          },\n        },\n      },\n      \"assetsDirs\": Array [],\n      \"deprecated\": false,\n      \"deprecationMessage\": \"\",\n      \"description\": \"<p>This is a simple button that demonstrates various JSDoc handling in Storybook Docs for Angular.</p>\n<p>It supports <a href=\\\\\"https://en.wikipedia.org/wiki/Markdown\\\\\">markdown</a>, so you can embed formatted text,\nlike <strong>bold</strong>, <em>italic</em>, and <code>inline code</code>.</p>\n<blockquote>\n<p>How you like dem apples?! It&#39;s never been easier to document all your components.</p>\n</blockquote>\n\",\n      \"encapsulation\": Array [],\n      \"entryComponents\": Array [],\n      \"file\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n      \"hostBindings\": Array [\n        Object {\n          \"decorators\": Array [],\n          \"defaultValue\": \"false\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"line\": 125,\n          \"name\": \"class.focused\",\n          \"type\": \"boolean\",\n        },\n      ],\n      \"hostListeners\": Array [\n        Object {\n          \"args\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"btn\",\n              \"type\": \"\",\n            },\n          ],\n          \"argsDecorator\": Array [\n            \"$event.target\",\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"line\": 121,\n          \"name\": \"click\",\n        },\n      ],\n      \"id\": \"component-InputComponent-d145da25329b094ee29610c45a9e46387cb39eddb2a67b4c9fadb84bcec76eacd60d131e48d98b2ee5725dedd25f2eb299b704e8e0a34307d6e84f6e57d57044\",\n      \"inputs\": Array [],\n      \"inputsClass\": Array [\n        Object {\n          \"decorators\": Array [],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Specify the accent-type of the button</p>\n\",\n          \"line\": 57,\n          \"name\": \"accent\",\n          \"rawdescription\": \"\nSpecify the accent-type of the button\",\n          \"type\": \"ButtonAccent\",\n        },\n        Object {\n          \"decorators\": Array [],\n          \"defaultValue\": \"'secondary'\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Appearance style of the button.</p>\n\",\n          \"line\": 53,\n          \"name\": \"appearance\",\n          \"rawdescription\": \"\nAppearance style of the button.\",\n          \"type\": \"\\\\\"primary\\\\\" | \\\\\"secondary\\\\\"\",\n        },\n        Object {\n          \"decorators\": Array [],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Setter for <code>inputValue</code> that is also an <code>@Input</code>.</p>\n\",\n          \"line\": 111,\n          \"name\": \"inputValue\",\n          \"rawdescription\": \"\nSetter for \\`inputValue\\` that is also an \\`@Input\\`.\",\n          \"type\": \"string\",\n        },\n        Object {\n          \"decorators\": Array [],\n          \"defaultValue\": \"false\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Sets the button to a disabled state.</p>\n\",\n          \"line\": 61,\n          \"name\": \"isDisabled\",\n          \"rawdescription\": \"\nSets the button to a disabled state.\",\n          \"type\": \"boolean\",\n        },\n        Object {\n          \"decorators\": Array [],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"line\": 196,\n          \"name\": \"item\",\n          \"type\": \"T[]\",\n        },\n        Object {\n          \"decorators\": Array [],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>The inner text of the button.</p>\n\",\n          \"jsdoctags\": Array [\n            Object {\n              \"comment\": \"\",\n              \"end\": 1587,\n              \"flags\": 4227072,\n              \"kind\": 325,\n              \"modifierFlagsCache\": 0,\n              \"pos\": 1574,\n              \"tagName\": Object {\n                \"end\": 1583,\n                \"escapedText\": \"required\",\n                \"flags\": 4227072,\n                \"kind\": 79,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 1575,\n                \"transformFlags\": 0,\n              },\n              \"transformFlags\": 0,\n            },\n          ],\n          \"line\": 69,\n          \"name\": \"label\",\n          \"rawdescription\": \"\n\nThe inner text of the button.\n\n\",\n          \"type\": \"string\",\n        },\n        Object {\n          \"decorators\": Array [],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"line\": 193,\n          \"name\": \"showKeyAlias\",\n          \"type\": \"\",\n        },\n        Object {\n          \"decorators\": Array [],\n          \"defaultValue\": \"'medium'\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Size of the button.</p>\n\",\n          \"line\": 73,\n          \"name\": \"size\",\n          \"rawdescription\": \"\nSize of the button.\",\n          \"type\": \"ButtonSize\",\n        },\n        Object {\n          \"decorators\": Array [],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Specifies some arbitrary object</p>\n\",\n          \"line\": 76,\n          \"name\": \"someDataObject\",\n          \"rawdescription\": \"\nSpecifies some arbitrary object\",\n          \"type\": \"ISomeInterface\",\n        },\n        Object {\n          \"decorators\": Array [],\n          \"defaultValue\": \"false\",\n          \"deprecated\": true,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Some input you shouldn&#39;t use.</p>\n\",\n          \"jsdoctags\": Array [\n            Object {\n              \"comment\": \"\",\n              \"end\": 1864,\n              \"flags\": 4227072,\n              \"kind\": 329,\n              \"modifierFlagsCache\": 0,\n              \"pos\": 1849,\n              \"tagName\": Object {\n                \"end\": 1860,\n                \"escapedText\": \"deprecated\",\n                \"flags\": 4227072,\n                \"kind\": 79,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 1850,\n                \"transformFlags\": 0,\n              },\n              \"transformFlags\": 0,\n            },\n          ],\n          \"line\": 84,\n          \"name\": \"somethingYouShouldNotUse\",\n          \"rawdescription\": \"\n\nSome input you shouldn't use.\n\n\",\n          \"type\": \"boolean\",\n        },\n      ],\n      \"methodsClass\": Array [\n        Object {\n          \"args\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"x\",\n              \"type\": \"number\",\n            },\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"y\",\n              \"type\": \"string | number\",\n            },\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>An internal calculation method which adds <code>x</code> and <code>y</code> together.</p>\n\",\n          \"jsdoctags\": Array [\n            Object {\n              \"comment\": \"<p>Some number you&#39;d like to use.</p>\n\",\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": Object {\n                \"end\": 3580,\n                \"escapedText\": \"x\",\n                \"flags\": 4227072,\n                \"kind\": 79,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 3579,\n                \"transformFlags\": 0,\n              },\n              \"tagName\": Object {\n                \"end\": 3578,\n                \"escapedText\": \"param\",\n                \"flags\": 4227072,\n                \"kind\": 79,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 3573,\n                \"transformFlags\": 0,\n              },\n              \"type\": \"number\",\n            },\n            Object {\n              \"comment\": \"<p>Some other number or string you&#39;d like to use, will have <code>parseInt()</code> applied before calculation.</p>\n\",\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": Object {\n                \"end\": 3625,\n                \"escapedText\": \"y\",\n                \"flags\": 4227072,\n                \"kind\": 79,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 3624,\n                \"transformFlags\": 0,\n              },\n              \"tagName\": Object {\n                \"end\": 3623,\n                \"escapedText\": \"param\",\n                \"flags\": 4227072,\n                \"kind\": 79,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 3618,\n                \"transformFlags\": 0,\n              },\n              \"type\": \"string | number\",\n            },\n          ],\n          \"line\": 165,\n          \"modifierKind\": Array [\n            123,\n          ],\n          \"name\": \"calc\",\n          \"optional\": false,\n          \"rawdescription\": \"\n\nAn internal calculation method which adds \\`x\\` and \\`y\\` together.\n\n\",\n          \"returnType\": \"number\",\n          \"typeParameters\": Array [],\n        },\n        Object {\n          \"args\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"btn\",\n              \"type\": \"\",\n            },\n          ],\n          \"decorators\": Array [\n            Object {\n              \"name\": \"HostListener\",\n              \"stringifiedArguments\": \"'click', ['$event.target']\",\n            },\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"jsdoctags\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"btn\",\n              \"tagName\": Object {\n                \"text\": \"param\",\n              },\n              \"type\": \"\",\n            },\n          ],\n          \"line\": 121,\n          \"name\": \"onClickListener\",\n          \"optional\": false,\n          \"returnType\": \"void\",\n          \"typeParameters\": Array [],\n        },\n        Object {\n          \"args\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"password\",\n              \"type\": \"string\",\n            },\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>A private method.</p>\n\",\n          \"jsdoctags\": Array [\n            Object {\n              \"comment\": \"<p>Some <code>password</code>.</p>\n\",\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": Object {\n                \"end\": 4141,\n                \"escapedText\": \"password\",\n                \"flags\": 4227072,\n                \"kind\": 79,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 4133,\n                \"transformFlags\": 0,\n              },\n              \"tagName\": Object {\n                \"end\": 4132,\n                \"escapedText\": \"param\",\n                \"flags\": 4227072,\n                \"kind\": 79,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 4127,\n                \"transformFlags\": 0,\n              },\n              \"type\": \"string\",\n            },\n          ],\n          \"line\": 188,\n          \"modifierKind\": Array [\n            121,\n          ],\n          \"name\": \"privateMethod\",\n          \"optional\": false,\n          \"rawdescription\": \"\n\nA private method.\n\n\",\n          \"returnType\": \"void\",\n          \"typeParameters\": Array [],\n        },\n        Object {\n          \"args\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"id\",\n              \"optional\": true,\n              \"type\": \"number\",\n            },\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>A protected method.</p>\n\",\n          \"jsdoctags\": Array [\n            Object {\n              \"comment\": \"<p>Some <code>id</code>.</p>\n\",\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": Object {\n                \"end\": 4000,\n                \"escapedText\": \"id\",\n                \"flags\": 4227072,\n                \"kind\": 79,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 3998,\n                \"transformFlags\": 0,\n              },\n              \"optional\": true,\n              \"tagName\": Object {\n                \"end\": 3997,\n                \"escapedText\": \"param\",\n                \"flags\": 4227072,\n                \"kind\": 79,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 3992,\n                \"transformFlags\": 0,\n              },\n              \"type\": \"number\",\n            },\n          ],\n          \"line\": 179,\n          \"modifierKind\": Array [\n            122,\n          ],\n          \"name\": \"protectedMethod\",\n          \"optional\": false,\n          \"rawdescription\": \"\n\nA protected method.\n\n\",\n          \"returnType\": \"void\",\n          \"typeParameters\": Array [],\n        },\n        Object {\n          \"args\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"things\",\n              \"type\": \"ISomeInterface\",\n            },\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>A public method using an interface.</p>\n\",\n          \"jsdoctags\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"things\",\n              \"tagName\": Object {\n                \"text\": \"param\",\n              },\n              \"type\": \"ISomeInterface\",\n            },\n          ],\n          \"line\": 170,\n          \"modifierKind\": Array [\n            123,\n          ],\n          \"name\": \"publicMethod\",\n          \"optional\": false,\n          \"rawdescription\": \"\nA public method using an interface.\",\n          \"returnType\": \"void\",\n          \"typeParameters\": Array [],\n        },\n      ],\n      \"name\": \"InputComponent\",\n      \"outputs\": Array [],\n      \"outputsClass\": Array [\n        Object {\n          \"defaultValue\": \"new EventEmitter<Event>()\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Handler to be called when the button is clicked by a user.</p>\n<p>Will also block the emission of the event if <code>isDisabled</code> is true.</p>\n\",\n          \"line\": 92,\n          \"name\": \"onClick\",\n          \"rawdescription\": \"\n\nHandler to be called when the button is clicked by a user.\n\nWill also block the emission of the event if \\`isDisabled\\` is true.\n\",\n          \"type\": \"EventEmitter\",\n        },\n      ],\n      \"propertiesClass\": Array [\n        Object {\n          \"defaultValue\": \"'some value'\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 107,\n          \"modifierKind\": Array [\n            121,\n          ],\n          \"name\": \"_inputValue\",\n          \"optional\": false,\n          \"type\": \"string\",\n        },\n        Object {\n          \"defaultValue\": \"'Private hello'\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Private value.</p>\n\",\n          \"line\": 147,\n          \"modifierKind\": Array [\n            121,\n          ],\n          \"name\": \"_value\",\n          \"optional\": false,\n          \"rawdescription\": \"\nPrivate value.\",\n          \"type\": \"string\",\n        },\n        Object {\n          \"decorators\": Array [\n            Object {\n              \"name\": \"ViewChild\",\n              \"stringifiedArguments\": \"'buttonRef', {static: false}\",\n            },\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 49,\n          \"name\": \"buttonRef\",\n          \"optional\": false,\n          \"type\": \"ElementRef\",\n        },\n        Object {\n          \"decorators\": Array [\n            Object {\n              \"name\": \"HostBinding\",\n              \"stringifiedArguments\": \"'class.focused'\",\n            },\n          ],\n          \"defaultValue\": \"false\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 125,\n          \"name\": \"focus\",\n          \"optional\": false,\n          \"type\": \"\",\n        },\n        Object {\n          \"defaultValue\": \"'Public hello'\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Public value.</p>\n\",\n          \"line\": 144,\n          \"modifierKind\": Array [\n            123,\n          ],\n          \"name\": \"internalProperty\",\n          \"optional\": false,\n          \"rawdescription\": \"\nPublic value.\",\n          \"type\": \"string\",\n        },\n        Object {\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 200,\n          \"modifierKind\": Array [\n            123,\n          ],\n          \"name\": \"processedItem\",\n          \"optional\": false,\n          \"type\": \"T[]\",\n        },\n      ],\n      \"providers\": Array [],\n      \"rawdescription\": \"\n\nThis is a simple button that demonstrates various JSDoc handling in Storybook Docs for Angular.\n\nIt supports [markdown](https://en.wikipedia.org/wiki/Markdown), so you can embed formatted text,\nlike **bold**, _italic_, and \\`inline code\\`.\n\n> How you like dem apples?! It's never been easier to document all your components.\n\n\",\n      \"selector\": \"doc-button\",\n      \"sourceCode\": \"import {\n  Component,\n  ElementRef,\n  EventEmitter,\n  HostBinding,\n  HostListener,\n  Input,\n  Output,\n  ViewChild,\n} from '@angular/core';\n\nexport const exportedConstant = 'An exported constant';\n\nexport type ButtonSize = 'small' | 'medium' | 'large' | 'xlarge';\n\nexport enum ButtonAccent {\n  'Normal' = 'Normal',\n  'High' = 'High',\n}\n\nexport interface ISomeInterface {\n  one: string;\n  two: boolean;\n  three: any[];\n}\n\n/**\n * This is a simple button that demonstrates various JSDoc handling in Storybook Docs for Angular.\n *\n * It supports [markdown](https://en.wikipedia.org/wiki/Markdown), so you can embed formatted text,\n * like **bold**, _italic_, and \\`inline code\\`.\n *\n * > How you like dem apples?! It's never been easier to document all your components.\n *\n * @string Hello world\n * @link [Example](http://example.com)\n * @code \\`ThingThing\\`\n * @html <span class=\\\\\"badge\\\\\">aaa</span>\n */\n@Component({\n  selector: 'doc-button',\n  template: '<button>{{ label }}</button>',\n})\nexport class InputComponent<T> {\n  @ViewChild('buttonRef', { static: false }) buttonRef: ElementRef;\n\n  /** Appearance style of the button. */\n  @Input()\n  public appearance: 'primary' | 'secondary' = 'secondary';\n\n  /** Specify the accent-type of the button */\n  @Input()\n  public accent: ButtonAccent;\n\n  /** Sets the button to a disabled state. */\n  @Input()\n  public isDisabled = false;\n\n  /**\n   * The inner text of the button.\n   *\n   * @required\n   */\n  @Input()\n  public label: string;\n\n  /** Size of the button. */\n  @Input()\n  public size?: ButtonSize = 'medium';\n\n  /** Specifies some arbitrary object */\n  @Input() public someDataObject: ISomeInterface;\n\n  /**\n   * Some input you shouldn't use.\n   *\n   * @deprecated\n   */\n  @Input()\n  public somethingYouShouldNotUse = false;\n\n  /**\n   * Handler to be called when the button is clicked by a user.\n   *\n   * Will also block the emission of the event if \\`isDisabled\\` is true.\n   */\n  @Output()\n  public onClick = new EventEmitter<Event>();\n\n  /**\n   * This is an internal method that we don't want to document and have added the \\`ignore\\` annotation to.\n   *\n   * @ignore\n   */\n  public handleClick(event: Event) {\n    event.stopPropagation();\n\n    if (!this.isDisabled) {\n      this.onClick.emit(event);\n    }\n  }\n\n  private _inputValue = 'some value';\n\n  /** Setter for \\`inputValue\\` that is also an \\`@Input\\`. */\n  @Input()\n  public set inputValue(value: string) {\n    this._inputValue = value;\n  }\n\n  /** Getter for \\`inputValue\\`. */\n  public get inputValue() {\n    return this._inputValue;\n  }\n\n  @HostListener('click', ['$event.target'])\n  onClickListener(btn) {\n    console.log('button', btn);\n  }\n\n  @HostBinding('class.focused') focus = false;\n\n  /**\n   * Returns all the CSS classes for the button.\n   *\n   * @ignore\n   */\n  public get classes(): string[] {\n    return [this.appearance, this.size]\n      .filter((_class) => !!_class)\n      .map((_class) => \\`btn-\\${_class}\\`);\n  }\n\n  /**\n   * @ignore\n   */\n  public ignoredProperty = 'Ignore me';\n\n  /** Public value. */\n  public internalProperty = 'Public hello';\n\n  /** Private value. */\n  private _value = 'Private hello';\n\n  /** Set the private value. */\n  public set value(value: string | number) {\n    this._value = \\`\\${value}\\`;\n  }\n\n  /** Get the private value. */\n  public get value(): string | number {\n    return this._value;\n  }\n\n  /**\n   * An internal calculation method which adds \\`x\\` and \\`y\\` together.\n   *\n   * @param x Some number you'd like to use.\n   * @param y Some other number or string you'd like to use, will have \\`parseInt()\\` applied before calculation.\n   */\n  public calc(x: number, y: string | number): number {\n    return x + parseInt(\\`\\${y}\\`, 10);\n  }\n\n  /** A public method using an interface. */\n  public publicMethod(things: ISomeInterface) {\n    console.log(things);\n  }\n\n  /**\n   * A protected method.\n   *\n   * @param id Some \\`id\\`.\n   */\n  protected protectedMethod(id?: number) {\n    console.log(id);\n  }\n\n  /**\n   * A private method.\n   *\n   * @param password Some \\`password\\`.\n   */\n  private privateMethod(password: string) {\n    console.log(password);\n  }\n\n  @Input('showKeyAlias')\n  public showKey: keyof T;\n\n  @Input()\n  public set item(item: T[]) {\n    this.processedItem = item;\n  }\n\n  public processedItem: T[];\n}\n\",\n      \"styleUrls\": Array [],\n      \"styleUrlsData\": \"\",\n      \"styles\": Array [],\n      \"stylesData\": \"\",\n      \"template\": \"<button>{{ label }}</button>\",\n      \"templateUrl\": Array [],\n      \"type\": \"component\",\n      \"viewProviders\": Array [],\n    },\n  ],\n  \"coverage\": Object {\n    \"count\": 21,\n    \"files\": Array [\n      Object {\n        \"coverageCount\": \"16/25\",\n        \"coveragePercent\": 64,\n        \"filePath\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n        \"linktype\": \"component\",\n        \"name\": \"InputComponent\",\n        \"status\": \"good\",\n        \"type\": \"component\",\n      },\n      Object {\n        \"coverageCount\": \"0/4\",\n        \"coveragePercent\": 0,\n        \"filePath\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n        \"linktype\": \"interface\",\n        \"name\": \"ISomeInterface\",\n        \"status\": \"low\",\n        \"type\": \"interface\",\n      },\n      Object {\n        \"coverageCount\": \"0/1\",\n        \"coveragePercent\": 0,\n        \"filePath\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n        \"linksubtype\": \"variable\",\n        \"linktype\": \"miscellaneous\",\n        \"name\": \"exportedConstant\",\n        \"status\": \"low\",\n        \"type\": \"variable\",\n      },\n    ],\n    \"status\": \"low\",\n  },\n  \"directives\": Array [],\n  \"guards\": Array [],\n  \"injectables\": Array [],\n  \"interceptors\": Array [],\n  \"interfaces\": Array [\n    Object {\n      \"deprecated\": false,\n      \"deprecationMessage\": \"\",\n      \"file\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n      \"id\": \"interface-ISomeInterface-d145da25329b094ee29610c45a9e46387cb39eddb2a67b4c9fadb84bcec76eacd60d131e48d98b2ee5725dedd25f2eb299b704e8e0a34307d6e84f6e57d57044\",\n      \"indexSignatures\": Array [],\n      \"kind\": 165,\n      \"methods\": Array [],\n      \"name\": \"ISomeInterface\",\n      \"properties\": Array [\n        Object {\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 26,\n          \"name\": \"one\",\n          \"optional\": false,\n          \"type\": \"string\",\n        },\n        Object {\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 28,\n          \"name\": \"three\",\n          \"optional\": false,\n          \"type\": \"any[]\",\n        },\n        Object {\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 27,\n          \"name\": \"two\",\n          \"optional\": false,\n          \"type\": \"boolean\",\n        },\n      ],\n      \"sourceCode\": \"import {\n  Component,\n  ElementRef,\n  EventEmitter,\n  HostBinding,\n  HostListener,\n  Input,\n  Output,\n  ViewChild,\n} from '@angular/core';\n\nexport const exportedConstant = 'An exported constant';\n\nexport type ButtonSize = 'small' | 'medium' | 'large' | 'xlarge';\n\nexport enum ButtonAccent {\n  'Normal' = 'Normal',\n  'High' = 'High',\n}\n\nexport interface ISomeInterface {\n  one: string;\n  two: boolean;\n  three: any[];\n}\n\n/**\n * This is a simple button that demonstrates various JSDoc handling in Storybook Docs for Angular.\n *\n * It supports [markdown](https://en.wikipedia.org/wiki/Markdown), so you can embed formatted text,\n * like **bold**, _italic_, and \\`inline code\\`.\n *\n * > How you like dem apples?! It's never been easier to document all your components.\n *\n * @string Hello world\n * @link [Example](http://example.com)\n * @code \\`ThingThing\\`\n * @html <span class=\\\\\"badge\\\\\">aaa</span>\n */\n@Component({\n  selector: 'doc-button',\n  template: '<button>{{ label }}</button>',\n})\nexport class InputComponent<T> {\n  @ViewChild('buttonRef', { static: false }) buttonRef: ElementRef;\n\n  /** Appearance style of the button. */\n  @Input()\n  public appearance: 'primary' | 'secondary' = 'secondary';\n\n  /** Specify the accent-type of the button */\n  @Input()\n  public accent: ButtonAccent;\n\n  /** Sets the button to a disabled state. */\n  @Input()\n  public isDisabled = false;\n\n  /**\n   * The inner text of the button.\n   *\n   * @required\n   */\n  @Input()\n  public label: string;\n\n  /** Size of the button. */\n  @Input()\n  public size?: ButtonSize = 'medium';\n\n  /** Specifies some arbitrary object */\n  @Input() public someDataObject: ISomeInterface;\n\n  /**\n   * Some input you shouldn't use.\n   *\n   * @deprecated\n   */\n  @Input()\n  public somethingYouShouldNotUse = false;\n\n  /**\n   * Handler to be called when the button is clicked by a user.\n   *\n   * Will also block the emission of the event if \\`isDisabled\\` is true.\n   */\n  @Output()\n  public onClick = new EventEmitter<Event>();\n\n  /**\n   * This is an internal method that we don't want to document and have added the \\`ignore\\` annotation to.\n   *\n   * @ignore\n   */\n  public handleClick(event: Event) {\n    event.stopPropagation();\n\n    if (!this.isDisabled) {\n      this.onClick.emit(event);\n    }\n  }\n\n  private _inputValue = 'some value';\n\n  /** Setter for \\`inputValue\\` that is also an \\`@Input\\`. */\n  @Input()\n  public set inputValue(value: string) {\n    this._inputValue = value;\n  }\n\n  /** Getter for \\`inputValue\\`. */\n  public get inputValue() {\n    return this._inputValue;\n  }\n\n  @HostListener('click', ['$event.target'])\n  onClickListener(btn) {\n    console.log('button', btn);\n  }\n\n  @HostBinding('class.focused') focus = false;\n\n  /**\n   * Returns all the CSS classes for the button.\n   *\n   * @ignore\n   */\n  public get classes(): string[] {\n    return [this.appearance, this.size]\n      .filter((_class) => !!_class)\n      .map((_class) => \\`btn-\\${_class}\\`);\n  }\n\n  /**\n   * @ignore\n   */\n  public ignoredProperty = 'Ignore me';\n\n  /** Public value. */\n  public internalProperty = 'Public hello';\n\n  /** Private value. */\n  private _value = 'Private hello';\n\n  /** Set the private value. */\n  public set value(value: string | number) {\n    this._value = \\`\\${value}\\`;\n  }\n\n  /** Get the private value. */\n  public get value(): string | number {\n    return this._value;\n  }\n\n  /**\n   * An internal calculation method which adds \\`x\\` and \\`y\\` together.\n   *\n   * @param x Some number you'd like to use.\n   * @param y Some other number or string you'd like to use, will have \\`parseInt()\\` applied before calculation.\n   */\n  public calc(x: number, y: string | number): number {\n    return x + parseInt(\\`\\${y}\\`, 10);\n  }\n\n  /** A public method using an interface. */\n  public publicMethod(things: ISomeInterface) {\n    console.log(things);\n  }\n\n  /**\n   * A protected method.\n   *\n   * @param id Some \\`id\\`.\n   */\n  protected protectedMethod(id?: number) {\n    console.log(id);\n  }\n\n  /**\n   * A private method.\n   *\n   * @param password Some \\`password\\`.\n   */\n  private privateMethod(password: string) {\n    console.log(password);\n  }\n\n  @Input('showKeyAlias')\n  public showKey: keyof T;\n\n  @Input()\n  public set item(item: T[]) {\n    this.processedItem = item;\n  }\n\n  public processedItem: T[];\n}\n\",\n      \"type\": \"interface\",\n    },\n  ],\n  \"miscellaneous\": Object {\n    \"enumerations\": Array [\n      Object {\n        \"childs\": Array [\n          Object {\n            \"deprecated\": false,\n            \"deprecationMessage\": \"\",\n            \"name\": \"Normal\",\n            \"value\": \"Normal\",\n          },\n          Object {\n            \"deprecated\": false,\n            \"deprecationMessage\": \"\",\n            \"name\": \"High\",\n            \"value\": \"High\",\n          },\n        ],\n        \"ctype\": \"miscellaneous\",\n        \"deprecated\": false,\n        \"deprecationMessage\": \"\",\n        \"description\": \"\",\n        \"file\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n        \"name\": \"ButtonAccent\",\n        \"subtype\": \"enum\",\n      },\n    ],\n    \"functions\": Array [],\n    \"groupedEnumerations\": Object {\n      \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\": Array [\n        Object {\n          \"childs\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"Normal\",\n              \"value\": \"Normal\",\n            },\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"High\",\n              \"value\": \"High\",\n            },\n          ],\n          \"ctype\": \"miscellaneous\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"file\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n          \"name\": \"ButtonAccent\",\n          \"subtype\": \"enum\",\n        },\n      ],\n    },\n    \"groupedFunctions\": Object {},\n    \"groupedTypeAliases\": Object {\n      \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\": Array [\n        Object {\n          \"ctype\": \"miscellaneous\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"file\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n          \"kind\": 186,\n          \"name\": \"ButtonSize\",\n          \"rawtype\": \"\\\\\"small\\\\\" | \\\\\"medium\\\\\" | \\\\\"large\\\\\" | \\\\\"xlarge\\\\\"\",\n          \"subtype\": \"typealias\",\n        },\n      ],\n    },\n    \"groupedVariables\": Object {\n      \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\": Array [\n        Object {\n          \"ctype\": \"miscellaneous\",\n          \"defaultValue\": \"'An exported constant'\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"file\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n          \"name\": \"exportedConstant\",\n          \"subtype\": \"variable\",\n          \"type\": \"string\",\n        },\n      ],\n    },\n    \"typealiases\": Array [\n      Object {\n        \"ctype\": \"miscellaneous\",\n        \"deprecated\": false,\n        \"deprecationMessage\": \"\",\n        \"description\": \"\",\n        \"file\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n        \"kind\": 186,\n        \"name\": \"ButtonSize\",\n        \"rawtype\": \"\\\\\"small\\\\\" | \\\\\"medium\\\\\" | \\\\\"large\\\\\" | \\\\\"xlarge\\\\\"\",\n        \"subtype\": \"typealias\",\n      },\n    ],\n    \"variables\": Array [\n      Object {\n        \"ctype\": \"miscellaneous\",\n        \"defaultValue\": \"'An exported constant'\",\n        \"deprecated\": false,\n        \"deprecationMessage\": \"\",\n        \"file\": \"frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts\",\n        \"name\": \"exportedConstant\",\n        \"subtype\": \"variable\",\n        \"type\": \"string\",\n      },\n    ],\n  },\n  \"modules\": Array [],\n  \"pipes\": Array [],\n  \"routes\": Array [],\n}\n`;\n"
  },
  {
    "path": "code/frameworks/angular/src/client/docs/__testfixtures__/doc-button/compodoc-windows.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`angular component properties doc-button 1`] = `\nObject {\n  \"classes\": Array [],\n  \"components\": Array [\n    Object {\n      \"accessors\": Object {\n        \"inputValue\": Object {\n          \"getSignature\": Object {\n            \"description\": \"<p>Getter for <code>inputValue</code>.</p>\n\",\n            \"line\": 115,\n            \"name\": \"inputValue\",\n            \"rawdescription\": \"Getter for \\`inputValue\\`.\",\n            \"returnType\": \"\",\n            \"type\": \"\",\n          },\n          \"name\": \"inputValue\",\n          \"setSignature\": Object {\n            \"args\": Array [\n              Object {\n                \"deprecated\": false,\n                \"deprecationMessage\": \"\",\n                \"name\": \"value\",\n                \"type\": \"string\",\n              },\n            ],\n            \"deprecated\": false,\n            \"deprecationMessage\": \"\",\n            \"description\": \"<p>Setter for <code>inputValue</code> that is also an <code>@Input</code>.</p>\n\",\n            \"jsdoctags\": Array [\n              Object {\n                \"deprecated\": false,\n                \"deprecationMessage\": \"\",\n                \"name\": \"value\",\n                \"tagName\": Object {\n                  \"text\": \"param\",\n                },\n                \"type\": \"string\",\n              },\n            ],\n            \"line\": 110,\n            \"name\": \"inputValue\",\n            \"rawdescription\": \"Setter for \\`inputValue\\` that is also an \\`@Input\\`.\",\n            \"returnType\": \"void\",\n            \"type\": \"void\",\n          },\n        },\n        \"item\": Object {\n          \"name\": \"item\",\n          \"setSignature\": Object {\n            \"args\": Array [\n              Object {\n                \"deprecated\": false,\n                \"deprecationMessage\": \"\",\n                \"name\": \"item\",\n                \"type\": \"T[]\",\n              },\n            ],\n            \"deprecated\": false,\n            \"deprecationMessage\": \"\",\n            \"jsdoctags\": Array [\n              Object {\n                \"deprecated\": false,\n                \"deprecationMessage\": \"\",\n                \"name\": \"item\",\n                \"tagName\": Object {\n                  \"text\": \"param\",\n                },\n                \"type\": \"T[]\",\n              },\n            ],\n            \"line\": 195,\n            \"name\": \"item\",\n            \"returnType\": \"void\",\n            \"type\": \"void\",\n          },\n        },\n        \"value\": Object {\n          \"getSignature\": Object {\n            \"description\": \"<p>Get the private value.</p>\n\",\n            \"line\": 154,\n            \"name\": \"value\",\n            \"rawdescription\": \"Get the private value.\",\n            \"returnType\": \"string | number\",\n            \"type\": \"\",\n          },\n          \"name\": \"value\",\n          \"setSignature\": Object {\n            \"args\": Array [\n              Object {\n                \"deprecated\": false,\n                \"deprecationMessage\": \"\",\n                \"name\": \"value\",\n                \"type\": \"string | number\",\n              },\n            ],\n            \"deprecated\": false,\n            \"deprecationMessage\": \"\",\n            \"description\": \"<p>Set the private value.</p>\n\",\n            \"jsdoctags\": Array [\n              Object {\n                \"deprecated\": false,\n                \"deprecationMessage\": \"\",\n                \"name\": \"value\",\n                \"tagName\": Object {\n                  \"text\": \"param\",\n                },\n                \"type\": \"string | number\",\n              },\n            ],\n            \"line\": 149,\n            \"name\": \"value\",\n            \"rawdescription\": \"Set the private value.\",\n            \"returnType\": \"void\",\n            \"type\": \"void\",\n          },\n        },\n      },\n      \"assetsDirs\": Array [],\n      \"deprecated\": false,\n      \"deprecationMessage\": \"\",\n      \"description\": \"<p>This is a simple button that demonstrates various JSDoc handling in Storybook Docs for Angular.</p>\n<p>It supports <a href=\\\\\"https://en.wikipedia.org/wiki/Markdown\\\\\">markdown</a>, so you can embed formatted text,\nlike <strong>bold</strong>, <em>italic</em>, and <code>inline code</code>.</p>\n<blockquote>\n<p>How you like dem apples?! It&#39;s never been easier to document all your components.</p>\n</blockquote>\n\",\n      \"encapsulation\": Array [],\n      \"entryComponents\": Array [],\n      \"file\": \"addons/docs/src/frameworks/angular/__testfixtures__/doc-button/input.ts\",\n      \"hostBindings\": Array [\n        Object {\n          \"defaultValue\": \"false\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"line\": 124,\n          \"name\": \"class.focused\",\n          \"type\": \"boolean\",\n        },\n      ],\n      \"hostListeners\": Array [\n        Object {\n          \"args\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"btn\",\n              \"type\": \"\",\n            },\n          ],\n          \"argsDecorator\": Array [\n            \"$event.target\",\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"line\": 120,\n          \"name\": \"click\",\n        },\n      ],\n      \"id\": \"component-InputComponent-fd2eff3e4da750f1c06d4928670993b3\",\n      \"inputs\": Array [],\n      \"inputsClass\": Array [\n        Object {\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Specify the accent-type of the button</p>\n\",\n          \"line\": 56,\n          \"name\": \"accent\",\n          \"rawdescription\": \"Specify the accent-type of the button\",\n          \"type\": \"ButtonAccent\",\n        },\n        Object {\n          \"defaultValue\": \"'secondary'\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Appearance style of the button.</p>\n\",\n          \"line\": 52,\n          \"name\": \"appearance\",\n          \"rawdescription\": \"Appearance style of the button.\",\n          \"type\": \"\\\\\"primary\\\\\" | \\\\\"secondary\\\\\"\",\n        },\n        Object {\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Setter for <code>inputValue</code> that is also an <code>@Input</code>.</p>\n\",\n          \"line\": 110,\n          \"name\": \"inputValue\",\n          \"rawdescription\": \"Setter for \\`inputValue\\` that is also an \\`@Input\\`.\",\n          \"type\": \"string\",\n        },\n        Object {\n          \"defaultValue\": \"false\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Sets the button to a disabled state.</p>\n\",\n          \"line\": 60,\n          \"name\": \"isDisabled\",\n          \"rawdescription\": \"Sets the button to a disabled state.\",\n          \"type\": \"boolean\",\n        },\n        Object {\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"line\": 195,\n          \"name\": \"item\",\n          \"type\": \"[]\",\n        },\n        Object {\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>The inner text of the button.</p>\n\",\n          \"jsdoctags\": Array [\n            Object {\n              \"comment\": \"\",\n              \"end\": 1590,\n              \"flags\": 4227072,\n              \"kind\": 317,\n              \"modifierFlagsCache\": 0,\n              \"pos\": 1576,\n              \"tagName\": Object {\n                \"end\": 1585,\n                \"escapedText\": \"required\",\n                \"flags\": 4227072,\n                \"kind\": 78,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 1577,\n                \"transformFlags\": 0,\n              },\n              \"transformFlags\": 0,\n            },\n          ],\n          \"line\": 68,\n          \"name\": \"label\",\n          \"rawdescription\": \"The inner text of the button.\",\n          \"type\": \"string\",\n        },\n        Object {\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"line\": 192,\n          \"name\": \"showKeyAlias\",\n          \"type\": \"\",\n        },\n        Object {\n          \"defaultValue\": \"'medium'\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Size of the button.</p>\n\",\n          \"line\": 72,\n          \"name\": \"size\",\n          \"rawdescription\": \"Size of the button.\",\n          \"type\": \"ButtonSize\",\n        },\n        Object {\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Specifies some arbitrary object</p>\n\",\n          \"line\": 75,\n          \"name\": \"someDataObject\",\n          \"rawdescription\": \"Specifies some arbitrary object\",\n          \"type\": \"ISomeInterface\",\n        },\n        Object {\n          \"defaultValue\": \"false\",\n          \"deprecated\": true,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Some input you shouldn&#39;t use.</p>\n\",\n          \"jsdoctags\": Array [\n            Object {\n              \"comment\": \"\",\n              \"end\": 1882,\n              \"flags\": 4227072,\n              \"kind\": 321,\n              \"modifierFlagsCache\": 0,\n              \"pos\": 1866,\n              \"tagName\": Object {\n                \"end\": 1877,\n                \"escapedText\": \"deprecated\",\n                \"flags\": 4227072,\n                \"kind\": 78,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 1867,\n                \"transformFlags\": 0,\n              },\n              \"transformFlags\": 0,\n            },\n          ],\n          \"line\": 83,\n          \"name\": \"somethingYouShouldNotUse\",\n          \"rawdescription\": \"Some input you shouldn't use.\",\n          \"type\": \"boolean\",\n        },\n      ],\n      \"methodsClass\": Array [\n        Object {\n          \"args\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"x\",\n              \"type\": \"number\",\n            },\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"y\",\n              \"type\": \"string | number\",\n            },\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>An internal calculation method which adds <code>x</code> and <code>y</code> together.</p>\n\",\n          \"jsdoctags\": Array [\n            Object {\n              \"comment\": \"<p>Some number you&#39;d like to use.</p>\n\",\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": Object {\n                \"end\": 3678,\n                \"escapedText\": \"x\",\n                \"flags\": 4227072,\n                \"kind\": 78,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 3677,\n                \"transformFlags\": 0,\n              },\n              \"tagName\": Object {\n                \"end\": 3676,\n                \"escapedText\": \"param\",\n                \"flags\": 4227072,\n                \"kind\": 78,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 3671,\n                \"transformFlags\": 0,\n              },\n              \"type\": \"number\",\n            },\n            Object {\n              \"comment\": \"<p>Some other number or string you&#39;d like to use, will have <code>parseInt()</code> applied before calculation.</p>\n\",\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": Object {\n                \"end\": 3724,\n                \"escapedText\": \"y\",\n                \"flags\": 4227072,\n                \"kind\": 78,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 3723,\n                \"transformFlags\": 0,\n              },\n              \"tagName\": Object {\n                \"end\": 3722,\n                \"escapedText\": \"param\",\n                \"flags\": 4227072,\n                \"kind\": 78,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 3717,\n                \"transformFlags\": 0,\n              },\n              \"type\": \"string | number\",\n            },\n          ],\n          \"line\": 164,\n          \"modifierKind\": Array [\n            122,\n          ],\n          \"name\": \"calc\",\n          \"optional\": false,\n          \"rawdescription\": \"\n\nAn internal calculation method which adds \\`x\\` and \\`y\\` together.\n\n\",\n          \"returnType\": \"number\",\n          \"typeParameters\": Array [],\n        },\n        Object {\n          \"args\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"btn\",\n              \"type\": \"\",\n            },\n          ],\n          \"decorators\": Array [\n            Object {\n              \"name\": \"HostListener\",\n              \"stringifiedArguments\": \"'click', ['$event.target']\",\n            },\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"jsdoctags\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"btn\",\n              \"tagName\": Object {\n                \"text\": \"param\",\n              },\n              \"type\": \"\",\n            },\n          ],\n          \"line\": 120,\n          \"name\": \"onClickListener\",\n          \"optional\": false,\n          \"returnType\": \"void\",\n          \"typeParameters\": Array [],\n        },\n        Object {\n          \"args\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"password\",\n              \"type\": \"string\",\n            },\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>A private method.</p>\n\",\n          \"jsdoctags\": Array [\n            Object {\n              \"comment\": \"<p>Some <code>password</code>.</p>\n\",\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": Object {\n                \"end\": 4263,\n                \"escapedText\": \"password\",\n                \"flags\": 4227072,\n                \"kind\": 78,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 4255,\n                \"transformFlags\": 0,\n              },\n              \"tagName\": Object {\n                \"end\": 4254,\n                \"escapedText\": \"param\",\n                \"flags\": 4227072,\n                \"kind\": 78,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 4249,\n                \"transformFlags\": 0,\n              },\n              \"type\": \"string\",\n            },\n          ],\n          \"line\": 187,\n          \"modifierKind\": Array [\n            120,\n          ],\n          \"name\": \"privateMethod\",\n          \"optional\": false,\n          \"rawdescription\": \"\n\nA private method.\n\n\",\n          \"returnType\": \"void\",\n          \"typeParameters\": Array [],\n        },\n        Object {\n          \"args\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"id\",\n              \"optional\": true,\n              \"type\": \"number\",\n            },\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>A protected method.</p>\n\",\n          \"jsdoctags\": Array [\n            Object {\n              \"comment\": \"<p>Some <code>id</code>.</p>\n\",\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": Object {\n                \"end\": 4113,\n                \"escapedText\": \"id\",\n                \"flags\": 4227072,\n                \"kind\": 78,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 4111,\n                \"transformFlags\": 0,\n              },\n              \"optional\": true,\n              \"tagName\": Object {\n                \"end\": 4110,\n                \"escapedText\": \"param\",\n                \"flags\": 4227072,\n                \"kind\": 78,\n                \"modifierFlagsCache\": 0,\n                \"pos\": 4105,\n                \"transformFlags\": 0,\n              },\n              \"type\": \"number\",\n            },\n          ],\n          \"line\": 178,\n          \"modifierKind\": Array [\n            121,\n          ],\n          \"name\": \"protectedMethod\",\n          \"optional\": false,\n          \"rawdescription\": \"\n\nA protected method.\n\n\",\n          \"returnType\": \"void\",\n          \"typeParameters\": Array [],\n        },\n        Object {\n          \"args\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"things\",\n              \"type\": \"ISomeInterface\",\n            },\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>A public method using an interface.</p>\n\",\n          \"jsdoctags\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"things\",\n              \"tagName\": Object {\n                \"text\": \"param\",\n              },\n              \"type\": \"ISomeInterface\",\n            },\n          ],\n          \"line\": 169,\n          \"modifierKind\": Array [\n            122,\n          ],\n          \"name\": \"publicMethod\",\n          \"optional\": false,\n          \"rawdescription\": \"\nA public method using an interface.\",\n          \"returnType\": \"void\",\n          \"typeParameters\": Array [],\n        },\n      ],\n      \"name\": \"InputComponent\",\n      \"outputs\": Array [],\n      \"outputsClass\": Array [\n        Object {\n          \"defaultValue\": \"new EventEmitter<Event>()\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Handler to be called when the button is clicked by a user.</p>\n<p>Will also block the emission of the event if <code>isDisabled</code> is true.</p>\n\",\n          \"line\": 91,\n          \"name\": \"onClick\",\n          \"rawdescription\": \"\n\nHandler to be called when the button is clicked by a user.\n\nWill also block the emission of the event if \\`isDisabled\\` is true.\n\",\n          \"type\": \"EventEmitter\",\n        },\n      ],\n      \"propertiesClass\": Array [\n        Object {\n          \"defaultValue\": \"'some value'\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 106,\n          \"modifierKind\": Array [\n            120,\n          ],\n          \"name\": \"_inputValue\",\n          \"optional\": false,\n          \"type\": \"string\",\n        },\n        Object {\n          \"defaultValue\": \"'Private hello'\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Private value.</p>\n\",\n          \"line\": 146,\n          \"modifierKind\": Array [\n            120,\n          ],\n          \"name\": \"_value\",\n          \"optional\": false,\n          \"rawdescription\": \"\nPrivate value.\",\n          \"type\": \"string\",\n        },\n        Object {\n          \"decorators\": Array [\n            Object {\n              \"name\": \"ViewChild\",\n              \"stringifiedArguments\": \"'buttonRef', {static: false}\",\n            },\n          ],\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 48,\n          \"name\": \"buttonRef\",\n          \"optional\": false,\n          \"type\": \"ElementRef\",\n        },\n        Object {\n          \"decorators\": Array [\n            Object {\n              \"name\": \"HostBinding\",\n              \"stringifiedArguments\": \"'class.focused'\",\n            },\n          ],\n          \"defaultValue\": \"false\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 124,\n          \"name\": \"focus\",\n          \"optional\": false,\n          \"type\": \"\",\n        },\n        Object {\n          \"defaultValue\": \"'Public hello'\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"<p>Public value.</p>\n\",\n          \"line\": 143,\n          \"modifierKind\": Array [\n            122,\n          ],\n          \"name\": \"internalProperty\",\n          \"optional\": false,\n          \"rawdescription\": \"\nPublic value.\",\n          \"type\": \"string\",\n        },\n        Object {\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 199,\n          \"modifierKind\": Array [\n            122,\n          ],\n          \"name\": \"processedItem\",\n          \"optional\": false,\n          \"type\": \"T[]\",\n        },\n      ],\n      \"providers\": Array [],\n      \"rawdescription\": \"\n\nThis is a simple button that demonstrates various JSDoc handling in Storybook Docs for Angular.\n\nIt supports [markdown](https://en.wikipedia.org/wiki/Markdown), so you can embed formatted text,\nlike **bold**, _italic_, and \\`inline code\\`.\n\n> How you like dem apples?! It's never been easier to document all your components.\n\n\",\n      \"selector\": \"doc-button\",\n      \"sourceCode\": \"import {\n  Component,\n  ElementRef,\n  EventEmitter,\n  HostBinding,\n  HostListener,\n  Input,\n  Output,\n  ViewChild,\n} from '@angular/core';\n\nexport const exportedConstant = 'An exported constant';\n\nexport type ButtonSize = 'small' | 'medium' | 'large' | 'xlarge';\n\nexport enum ButtonAccent {\n  'Normal' = 'Normal',\n  'High' = 'High',\n}\n\nexport interface ISomeInterface {\n  one: string;\n  two: boolean;\n  three: any[];\n}\n\n/**\n * This is a simple button that demonstrates various JSDoc handling in Storybook Docs for Angular.\n *\n * It supports [markdown](https://en.wikipedia.org/wiki/Markdown), so you can embed formatted text,\n * like **bold**, _italic_, and \\`inline code\\`.\n *\n * > How you like dem apples?! It's never been easier to document all your components.\n *\n * @string Hello world\n * @link [Example](http://example.com)\n * @code \\`ThingThing\\`\n * @html <span class=\\\\\"badge\\\\\">aaa</span>\n */\n@Component({\n  selector: 'doc-button',\n  template: '<button>{{ label }}</button>',\n})\nexport class InputComponent<T> {\n  @ViewChild('buttonRef', { static: false }) buttonRef: ElementRef;\n\n  /** Appearance style of the button. */\n  @Input()\n  public appearance: 'primary' | 'secondary' = 'secondary';\n\n  /** Specify the accent-type of the button */\n  @Input()\n  public accent: ButtonAccent;\n\n  /** Sets the button to a disabled state. */\n  @Input()\n  public isDisabled = false;\n\n  /**\n   * The inner text of the button.\n   *\n   * @required\n   */\n  @Input()\n  public label: string;\n\n  /** Size of the button. */\n  @Input()\n  public size?: ButtonSize = 'medium';\n\n  /** Specifies some arbitrary object */\n  @Input() public someDataObject: ISomeInterface;\n\n  /**\n   * Some input you shouldn't use.\n   *\n   * @deprecated\n   */\n  @Input()\n  public somethingYouShouldNotUse = false;\n\n  /**\n   * Handler to be called when the button is clicked by a user.\n   *\n   * Will also block the emission of the event if \\`isDisabled\\` is true.\n   */\n  @Output()\n  public onClick = new EventEmitter<Event>();\n\n  /**\n   * This is an internal method that we don't want to document and have added the \\`ignore\\` annotation to.\n   *\n   * @ignore\n   */\n  public handleClick(event: Event) {\n    event.stopPropagation();\n\n    if (!this.isDisabled) {\n      this.onClick.emit(event);\n    }\n  }\n\n  private _inputValue = 'some value';\n\n  /** Setter for \\`inputValue\\` that is also an \\`@Input\\`. */\n  @Input()\n  public set inputValue(value: string) {\n    this._inputValue = value;\n  }\n\n  /** Getter for \\`inputValue\\`. */\n  public get inputValue() {\n    return this._inputValue;\n  }\n\n  @HostListener('click', ['$event.target'])\n  onClickListener(btn) {\n    console.log('button', btn);\n  }\n\n  @HostBinding('class.focused') focus = false;\n\n  /**\n   * Returns all the CSS classes for the button.\n   *\n   * @ignore\n   */\n  public get classes(): string[] {\n    return [this.appearance, this.size]\n      .filter((_class) => !!_class)\n      .map((_class) => \\`btn-\\${_class}\\`);\n  }\n\n  /**\n   * @ignore\n   */\n  public ignoredProperty = 'Ignore me';\n\n  /** Public value. */\n  public internalProperty = 'Public hello';\n\n  /** Private value. */\n  private _value = 'Private hello';\n\n  /** Set the private value. */\n  public set value(value: string | number) {\n    this._value = \\`\\${value}\\`;\n  }\n\n  /** Get the private value. */\n  public get value(): string | number {\n    return this._value;\n  }\n\n  /**\n   * An internal calculation method which adds \\`x\\` and \\`y\\` together.\n   *\n   * @param x Some number you'd like to use.\n   * @param y Some other number or string you'd like to use, will have \\`parseInt()\\` applied before calculation.\n   */\n  public calc(x: number, y: string | number): number {\n    return x + parseInt(\\`\\${y}\\`, 10);\n  }\n\n  /** A public method using an interface. */\n  public publicMethod(things: ISomeInterface) {\n    console.log(things);\n  }\n\n  /**\n   * A protected method.\n   *\n   * @param id Some \\`id\\`.\n   */\n  protected protectedMethod(id?: number) {\n    console.log(id);\n  }\n\n  /**\n   * A private method.\n   *\n   * @param password Some \\`password\\`.\n   */\n  private privateMethod(password: string) {\n    console.log(password);\n  }\n\n  @Input('showKeyAlias')\n  public showKey: keyof T;\n\n  @Input()\n  public set item(item: T[]) {\n    this.processedItem = item;\n  }\n\n  public processedItem: T[];\n}\n\",\n      \"styleUrls\": Array [],\n      \"styleUrlsData\": \"\",\n      \"styles\": Array [],\n      \"stylesData\": \"\",\n      \"template\": \"<button>{{ label }}</button>\",\n      \"templateUrl\": Array [],\n      \"type\": \"component\",\n      \"viewProviders\": Array [],\n    },\n  ],\n  \"coverage\": Object {\n    \"count\": 21,\n    \"files\": Array [\n      Object {\n        \"coverageCount\": \"16/25\",\n        \"coveragePercent\": 64,\n        \"filePath\": \"addons/docs/src/frameworks/angular/__testfixtures__/doc-button/input.ts\",\n        \"linktype\": \"component\",\n        \"name\": \"InputComponent\",\n        \"status\": \"good\",\n        \"type\": \"component\",\n      },\n      Object {\n        \"coverageCount\": \"0/4\",\n        \"coveragePercent\": 0,\n        \"filePath\": \"addons/docs/src/frameworks/angular/__testfixtures__/doc-button/input.ts\",\n        \"linktype\": \"interface\",\n        \"name\": \"ISomeInterface\",\n        \"status\": \"low\",\n        \"type\": \"interface\",\n      },\n      Object {\n        \"coverageCount\": \"0/1\",\n        \"coveragePercent\": 0,\n        \"filePath\": \"addons/docs/src/frameworks/angular/__testfixtures__/doc-button/input.ts\",\n        \"linksubtype\": \"variable\",\n        \"linktype\": \"miscellaneous\",\n        \"name\": \"exportedConstant\",\n        \"status\": \"low\",\n        \"type\": \"variable\",\n      },\n    ],\n    \"status\": \"low\",\n  },\n  \"directives\": Array [],\n  \"guards\": Array [],\n  \"injectables\": Array [],\n  \"interceptors\": Array [],\n  \"interfaces\": Array [\n    Object {\n      \"deprecated\": false,\n      \"deprecationMessage\": \"\",\n      \"file\": \"addons/docs/src/frameworks/angular/__testfixtures__/doc-button/input.ts\",\n      \"id\": \"interface-ISomeInterface-fd2eff3e4da750f1c06d4928670993b3\",\n      \"indexSignatures\": Array [],\n      \"kind\": 163,\n      \"methods\": Array [],\n      \"name\": \"ISomeInterface\",\n      \"properties\": Array [\n        Object {\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 25,\n          \"name\": \"one\",\n          \"optional\": false,\n          \"type\": \"string\",\n        },\n        Object {\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 27,\n          \"name\": \"three\",\n          \"optional\": false,\n          \"type\": \"any[]\",\n        },\n        Object {\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"line\": 26,\n          \"name\": \"two\",\n          \"optional\": false,\n          \"type\": \"boolean\",\n        },\n      ],\n      \"sourceCode\": \"import {\n  Component,\n  ElementRef,\n  EventEmitter,\n  HostBinding,\n  HostListener,\n  Input,\n  Output,\n  ViewChild,\n} from '@angular/core';\n\nexport const exportedConstant = 'An exported constant';\n\nexport type ButtonSize = 'small' | 'medium' | 'large' | 'xlarge';\n\nexport enum ButtonAccent {\n  'Normal' = 'Normal',\n  'High' = 'High',\n}\n\nexport interface ISomeInterface {\n  one: string;\n  two: boolean;\n  three: any[];\n}\n\n/**\n * This is a simple button that demonstrates various JSDoc handling in Storybook Docs for Angular.\n *\n * It supports [markdown](https://en.wikipedia.org/wiki/Markdown), so you can embed formatted text,\n * like **bold**, _italic_, and \\`inline code\\`.\n *\n * > How you like dem apples?! It's never been easier to document all your components.\n *\n * @string Hello world\n * @link [Example](http://example.com)\n * @code \\`ThingThing\\`\n * @html <span class=\\\\\"badge\\\\\">aaa</span>\n */\n@Component({\n  selector: 'doc-button',\n  template: '<button>{{ label }}</button>',\n})\nexport class InputComponent<T> {\n  @ViewChild('buttonRef', { static: false }) buttonRef: ElementRef;\n\n  /** Appearance style of the button. */\n  @Input()\n  public appearance: 'primary' | 'secondary' = 'secondary';\n\n  /** Specify the accent-type of the button */\n  @Input()\n  public accent: ButtonAccent;\n\n  /** Sets the button to a disabled state. */\n  @Input()\n  public isDisabled = false;\n\n  /**\n   * The inner text of the button.\n   *\n   * @required\n   */\n  @Input()\n  public label: string;\n\n  /** Size of the button. */\n  @Input()\n  public size?: ButtonSize = 'medium';\n\n  /** Specifies some arbitrary object */\n  @Input() public someDataObject: ISomeInterface;\n\n  /**\n   * Some input you shouldn't use.\n   *\n   * @deprecated\n   */\n  @Input()\n  public somethingYouShouldNotUse = false;\n\n  /**\n   * Handler to be called when the button is clicked by a user.\n   *\n   * Will also block the emission of the event if \\`isDisabled\\` is true.\n   */\n  @Output()\n  public onClick = new EventEmitter<Event>();\n\n  /**\n   * This is an internal method that we don't want to document and have added the \\`ignore\\` annotation to.\n   *\n   * @ignore\n   */\n  public handleClick(event: Event) {\n    event.stopPropagation();\n\n    if (!this.isDisabled) {\n      this.onClick.emit(event);\n    }\n  }\n\n  private _inputValue = 'some value';\n\n  /** Setter for \\`inputValue\\` that is also an \\`@Input\\`. */\n  @Input()\n  public set inputValue(value: string) {\n    this._inputValue = value;\n  }\n\n  /** Getter for \\`inputValue\\`. */\n  public get inputValue() {\n    return this._inputValue;\n  }\n\n  @HostListener('click', ['$event.target'])\n  onClickListener(btn) {\n    console.log('button', btn);\n  }\n\n  @HostBinding('class.focused') focus = false;\n\n  /**\n   * Returns all the CSS classes for the button.\n   *\n   * @ignore\n   */\n  public get classes(): string[] {\n    return [this.appearance, this.size]\n      .filter((_class) => !!_class)\n      .map((_class) => \\`btn-\\${_class}\\`);\n  }\n\n  /**\n   * @ignore\n   */\n  public ignoredProperty = 'Ignore me';\n\n  /** Public value. */\n  public internalProperty = 'Public hello';\n\n  /** Private value. */\n  private _value = 'Private hello';\n\n  /** Set the private value. */\n  public set value(value: string | number) {\n    this._value = \\`\\${value}\\`;\n  }\n\n  /** Get the private value. */\n  public get value(): string | number {\n    return this._value;\n  }\n\n  /**\n   * An internal calculation method which adds \\`x\\` and \\`y\\` together.\n   *\n   * @param x Some number you'd like to use.\n   * @param y Some other number or string you'd like to use, will have \\`parseInt()\\` applied before calculation.\n   */\n  public calc(x: number, y: string | number): number {\n    return x + parseInt(\\`\\${y}\\`, 10);\n  }\n\n  /** A public method using an interface. */\n  public publicMethod(things: ISomeInterface) {\n    console.log(things);\n  }\n\n  /**\n   * A protected method.\n   *\n   * @param id Some \\`id\\`.\n   */\n  protected protectedMethod(id?: number) {\n    console.log(id);\n  }\n\n  /**\n   * A private method.\n   *\n   * @param password Some \\`password\\`.\n   */\n  private privateMethod(password: string) {\n    console.log(password);\n  }\n\n  @Input('showKeyAlias')\n  public showKey: keyof T;\n\n  @Input()\n  public set item(item: T[]) {\n    this.processedItem = item;\n  }\n\n  public processedItem: T[];\n}\n\",\n      \"type\": \"interface\",\n    },\n  ],\n  \"miscellaneous\": Object {\n    \"enumerations\": Array [\n      Object {\n        \"childs\": Array [\n          Object {\n            \"deprecated\": false,\n            \"deprecationMessage\": \"\",\n            \"name\": \"Normal\",\n            \"value\": \"Normal\",\n          },\n          Object {\n            \"deprecated\": false,\n            \"deprecationMessage\": \"\",\n            \"name\": \"High\",\n            \"value\": \"High\",\n          },\n        ],\n        \"ctype\": \"miscellaneous\",\n        \"deprecated\": false,\n        \"deprecationMessage\": \"\",\n        \"description\": \"\",\n        \"file\": \"addons/docs/src/frameworks/angular/__testfixtures__/doc-button/input.ts\",\n        \"name\": \"ButtonAccent\",\n        \"subtype\": \"enum\",\n      },\n    ],\n    \"functions\": Array [],\n    \"groupedEnumerations\": Object {\n      \"addons/docs/src/frameworks/angular/__testfixtures__/doc-button/input.ts\": Array [\n        Object {\n          \"childs\": Array [\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"Normal\",\n              \"value\": \"Normal\",\n            },\n            Object {\n              \"deprecated\": false,\n              \"deprecationMessage\": \"\",\n              \"name\": \"High\",\n              \"value\": \"High\",\n            },\n          ],\n          \"ctype\": \"miscellaneous\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"file\": \"addons/docs/src/frameworks/angular/__testfixtures__/doc-button/input.ts\",\n          \"name\": \"ButtonAccent\",\n          \"subtype\": \"enum\",\n        },\n      ],\n    },\n    \"groupedFunctions\": Object {},\n    \"groupedTypeAliases\": Object {\n      \"addons/docs/src/frameworks/angular/__testfixtures__/doc-button/input.ts\": Array [\n        Object {\n          \"ctype\": \"miscellaneous\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"description\": \"\",\n          \"file\": \"addons/docs/src/frameworks/angular/__testfixtures__/doc-button/input.ts\",\n          \"kind\": 183,\n          \"name\": \"ButtonSize\",\n          \"rawtype\": \"\\\\\"small\\\\\" | \\\\\"medium\\\\\" | \\\\\"large\\\\\" | \\\\\"xlarge\\\\\"\",\n          \"subtype\": \"typealias\",\n        },\n      ],\n    },\n    \"groupedVariables\": Object {\n      \"addons/docs/src/frameworks/angular/__testfixtures__/doc-button/input.ts\": Array [\n        Object {\n          \"ctype\": \"miscellaneous\",\n          \"defaultValue\": \"'An exported constant'\",\n          \"deprecated\": false,\n          \"deprecationMessage\": \"\",\n          \"file\": \"addons/docs/src/frameworks/angular/__testfixtures__/doc-button/input.ts\",\n          \"name\": \"exportedConstant\",\n          \"subtype\": \"variable\",\n          \"type\": \"string\",\n        },\n      ],\n    },\n    \"typealiases\": Array [\n      Object {\n        \"ctype\": \"miscellaneous\",\n        \"deprecated\": false,\n        \"deprecationMessage\": \"\",\n        \"description\": \"\",\n        \"file\": \"addons/docs/src/frameworks/angular/__testfixtures__/doc-button/input.ts\",\n        \"kind\": 183,\n        \"name\": \"ButtonSize\",\n        \"rawtype\": \"\\\\\"small\\\\\" | \\\\\"medium\\\\\" | \\\\\"large\\\\\" | \\\\\"xlarge\\\\\"\",\n        \"subtype\": \"typealias\",\n      },\n    ],\n    \"variables\": Array [\n      Object {\n        \"ctype\": \"miscellaneous\",\n        \"defaultValue\": \"'An exported constant'\",\n        \"deprecated\": false,\n        \"deprecationMessage\": \"\",\n        \"file\": \"addons/docs/src/frameworks/angular/__testfixtures__/doc-button/input.ts\",\n        \"name\": \"exportedConstant\",\n        \"subtype\": \"variable\",\n        \"type\": \"string\",\n      },\n    ],\n  },\n  \"modules\": Array [],\n  \"pipes\": Array [],\n  \"routes\": Array [],\n}\n`;\n"
  },
  {
    "path": "code/frameworks/angular/src/client/docs/__testfixtures__/doc-button/input.ts",
    "content": "// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\n\nimport type { ElementRef } from '@angular/core';\nimport {\n  Component,\n  EventEmitter,\n  HostBinding,\n  HostListener,\n  Input,\n  Output,\n  ViewChild,\n} from '@angular/core';\n\nexport const exportedConstant = 'An exported constant';\n\nexport type ButtonSize = 'small' | 'medium' | 'large' | 'xlarge';\n\nexport enum ButtonAccent {\n  'Normal' = 'Normal',\n  'High' = 'High',\n}\n\nexport interface ISomeInterface {\n  one: string;\n  two: boolean;\n  three: any[];\n}\n\n/**\n * This is a simple button that demonstrates various JSDoc handling in Storybook Docs for Angular.\n *\n * It supports [markdown](https://en.wikipedia.org/wiki/Markdown), so you can embed formatted text,\n * like **bold**, _italic_, and `inline code`.> How you like dem apples?! It's never been easier to\n * document all your components.\n *\n * @string Hello world\n * @link [Example](http://example.com)\n * @code `ThingThing`\n * @html <span class=\"badge\">aaa</span>\n */\n@Component({\n  selector: 'doc-button',\n  template: '<button>{{ label }}</button>',\n})\nexport class InputComponent<T> {\n  @ViewChild('buttonRef', { static: false }) buttonRef: ElementRef;\n\n  /** Appearance style of the button. */\n  @Input()\n  public appearance: 'primary' | 'secondary' = 'secondary';\n\n  /** Specify the accent-type of the button */\n  @Input()\n  public accent: ButtonAccent;\n\n  /** Sets the button to a disabled state. */\n  @Input()\n  public isDisabled = false;\n\n  /**\n   * The inner text of the button.\n   *\n   * @required\n   */\n  @Input()\n  public label: string;\n\n  /** Size of the button. */\n  @Input()\n  public size?: ButtonSize = 'medium';\n\n  /** Specifies some arbitrary object */\n  @Input() public someDataObject: ISomeInterface;\n\n  /**\n   * Some input you shouldn't use.\n   *\n   * @deprecated\n   */\n  @Input()\n  public somethingYouShouldNotUse = false;\n\n  /**\n   * Handler to be called when the button is clicked by a user.\n   *\n   * Will also block the emission of the event if `isDisabled` is true.\n   */\n  @Output()\n  public onClick = new EventEmitter<Event>();\n\n  /**\n   * This is an internal method that we don't want to document and have added the `ignore`\n   * annotation to.\n   *\n   * @ignore\n   */\n  public handleClick(event: Event) {\n    event.stopPropagation();\n\n    if (!this.isDisabled) {\n      this.onClick.emit(event);\n    }\n  }\n\n  private _inputValue = 'some value';\n\n  /** Setter for `inputValue` that is also an `@Input`. */\n  @Input()\n  public set inputValue(value: string) {\n    this._inputValue = value;\n  }\n\n  /** Getter for `inputValue`. */\n  public get inputValue() {\n    return this._inputValue;\n  }\n\n  @HostListener('click', ['$event.target'])\n  onClickListener(btn) {\n    console.log('button', btn);\n  }\n\n  @HostBinding('class.focused') focus = false;\n\n  /**\n   * Returns all the CSS classes for the button.\n   *\n   * @ignore\n   */\n  public get classes(): string[] {\n    return [this.appearance, this.size]\n      .filter((_class) => !!_class)\n      .map((_class) => `btn-${_class}`);\n  }\n\n  /** @ignore */\n  public ignoredProperty = 'Ignore me';\n\n  /** Public value. */\n  public internalProperty = 'Public hello';\n\n  /** Private value. */\n  private _value = 'Private hello';\n\n  /** Set the private value. */\n  public set value(value: string | number) {\n    this._value = `${value}`;\n  }\n\n  /** Get the private value. */\n  public get value(): string | number {\n    return this._value;\n  }\n\n  /**\n   * An internal calculation method which adds `x` and `y` together.\n   *\n   * @param x Some number you'd like to use.\n   * @param y Some other number or string you'd like to use, will have `parseInt()` applied before\n   *   calculation.\n   */\n  public calc(x: number, y: string | number): number {\n    return x + parseInt(`${y}`, 10);\n  }\n\n  /** A public method using an interface. */\n  public publicMethod(things: ISomeInterface) {\n    console.log(things);\n  }\n\n  /**\n   * A protected method.\n   *\n   * @param id Some `id`.\n   */\n  protected protectedMethod(id?: number) {\n    console.log(id);\n  }\n\n  /**\n   * A private method.\n   *\n   * @param password Some `password`.\n   */\n  private privateMethod(password: string) {\n    console.log(password);\n  }\n\n  @Input('showKeyAlias')\n  public showKey: keyof T;\n\n  @Input()\n  public set item(item: T[]) {\n    this.processedItem = item;\n  }\n\n  public processedItem: T[];\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/client/docs/__testfixtures__/doc-button/properties.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`angular component properties doc-button 1`] = `\nObject {\n  \"sections\": Object {\n    \"inputs\": Array [\n      Object {\n        \"defaultValue\": Object {\n          \"summary\": \"'secondary'\",\n        },\n        \"description\": \"<p>Appearance style of the button. </p>\n\",\n        \"name\": \"appearance\",\n        \"required\": true,\n        \"type\": Object {\n          \"summary\": \"\\\\\"primary\\\\\" | \\\\\"secondary\\\\\"\",\n        },\n      },\n      Object {\n        \"defaultValue\": Object {\n          \"summary\": undefined,\n        },\n        \"description\": \"<p>Setter for <code>inputValue</code> that is also an <code>@Input</code>. </p>\n\",\n        \"name\": \"inputValue\",\n        \"required\": true,\n        \"type\": Object {\n          \"summary\": \"string\",\n        },\n      },\n      Object {\n        \"defaultValue\": Object {\n          \"summary\": \"false\",\n        },\n        \"description\": \"<p>Sets the button to a disabled state. </p>\n\",\n        \"name\": \"isDisabled\",\n        \"required\": true,\n        \"type\": Object {\n          \"summary\": undefined,\n        },\n      },\n      Object {\n        \"defaultValue\": Object {\n          \"summary\": undefined,\n        },\n        \"description\": undefined,\n        \"name\": \"item\",\n        \"required\": true,\n        \"type\": Object {\n          \"summary\": \"[]\",\n        },\n      },\n      Object {\n        \"defaultValue\": Object {\n          \"summary\": undefined,\n        },\n        \"description\": \"<p>The inner text of the button.</p>\n\",\n        \"name\": \"label\",\n        \"required\": true,\n        \"type\": Object {\n          \"summary\": \"string\",\n        },\n      },\n      Object {\n        \"defaultValue\": Object {\n          \"summary\": undefined,\n        },\n        \"description\": undefined,\n        \"name\": \"showKeyAlias\",\n        \"required\": true,\n        \"type\": Object {\n          \"summary\": \"\",\n        },\n      },\n      Object {\n        \"defaultValue\": Object {\n          \"summary\": \"'medium'\",\n        },\n        \"description\": \"<p>Size of the button. </p>\n\",\n        \"name\": \"size\",\n        \"required\": true,\n        \"type\": Object {\n          \"summary\": \"ButtonSize\",\n        },\n      },\n      Object {\n        \"defaultValue\": Object {\n          \"summary\": \"false\",\n        },\n        \"description\": \"<p>Some input you shouldn&#39;t use.</p>\n\",\n        \"name\": \"somethingYouShouldNotUse\",\n        \"required\": true,\n        \"type\": Object {\n          \"summary\": undefined,\n        },\n      },\n    ],\n    \"methods\": Array [\n      Object {\n        \"defaultValue\": Object {\n          \"summary\": \"\",\n        },\n        \"description\": \"<p>An internal calculation method which adds <code>x</code> and <code>y</code> together.</p>\n\",\n        \"name\": \"calc\",\n        \"required\": false,\n        \"type\": Object {\n          \"summary\": \"(x: number, y: string | number) => number\",\n        },\n      },\n      Object {\n        \"defaultValue\": Object {\n          \"summary\": \"\",\n        },\n        \"description\": \"<p>A private method.</p>\n\",\n        \"name\": \"privateMethod\",\n        \"required\": false,\n        \"type\": Object {\n          \"summary\": \"(password: string) => void\",\n        },\n      },\n      Object {\n        \"defaultValue\": Object {\n          \"summary\": \"\",\n        },\n        \"description\": \"<p>A protected method.</p>\n\",\n        \"name\": \"protectedMethod\",\n        \"required\": false,\n        \"type\": Object {\n          \"summary\": \"(id?: number) => void\",\n        },\n      },\n      Object {\n        \"defaultValue\": Object {\n          \"summary\": \"\",\n        },\n        \"description\": \"<p>A public method using an interface. </p>\n\",\n        \"name\": \"publicMethod\",\n        \"required\": false,\n        \"type\": Object {\n          \"summary\": \"(things: ISomeInterface) => void\",\n        },\n      },\n    ],\n    \"outputs\": Array [\n      Object {\n        \"defaultValue\": Object {\n          \"summary\": \"new EventEmitter<Event>()\",\n        },\n        \"description\": \"<p>Handler to be called when the button is clicked by a user.</p>\n<p>Will also block the emission of the event if <code>isDisabled</code> is true.</p>\n\",\n        \"name\": \"onClick\",\n        \"required\": true,\n        \"type\": Object {\n          \"summary\": \"EventEmitter\",\n        },\n      },\n    ],\n    \"properties\": Array [\n      Object {\n        \"defaultValue\": Object {\n          \"summary\": \"'some value'\",\n        },\n        \"description\": \"\",\n        \"name\": \"_inputValue\",\n        \"required\": true,\n        \"type\": Object {\n          \"summary\": \"string\",\n        },\n      },\n      Object {\n        \"defaultValue\": Object {\n          \"summary\": \"'Private hello'\",\n        },\n        \"description\": \"<p>Private value. </p>\n\",\n        \"name\": \"_value\",\n        \"required\": true,\n        \"type\": Object {\n          \"summary\": \"string\",\n        },\n      },\n      Object {\n        \"defaultValue\": Object {\n          \"summary\": \"'Public hello'\",\n        },\n        \"description\": \"<p>Public value. </p>\n\",\n        \"name\": \"internalProperty\",\n        \"required\": true,\n        \"type\": Object {\n          \"summary\": \"string\",\n        },\n      },\n      Object {\n        \"defaultValue\": Object {\n          \"summary\": undefined,\n        },\n        \"description\": \"\",\n        \"name\": \"processedItem\",\n        \"required\": true,\n        \"type\": Object {\n          \"summary\": \"T[]\",\n        },\n      },\n    ],\n    \"view child\": Array [\n      Object {\n        \"defaultValue\": Object {\n          \"summary\": undefined,\n        },\n        \"description\": \"\",\n        \"name\": \"buttonRef\",\n        \"required\": true,\n        \"type\": Object {\n          \"summary\": \"ElementRef\",\n        },\n      },\n    ],\n  },\n}\n`;\n"
  },
  {
    "path": "code/frameworks/angular/src/client/docs/__testfixtures__/doc-button/tsconfig.json",
    "content": "{\n  \"extends\": \"../../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"rootDir\": \".\"\n  },\n  \"include\": [\"./*.ts\"]\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/client/docs/angular-properties.test.ts",
    "content": "import { readdirSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { describe, expect, it } from 'vitest';\n\n// File hierarchy: __testfixtures__ / some-test-case / input.*\nconst inputRegExp = /^input\\..*$/;\n\ndescribe('angular component properties', () => {\n  const fixturesDir = join(__dirname, '__testfixtures__');\n  readdirSync(fixturesDir, { withFileTypes: true }).forEach((testEntry) => {\n    if (testEntry.isDirectory()) {\n      const testDir = join(fixturesDir, testEntry.name);\n      const testFile = readdirSync(testDir).find((fileName) => inputRegExp.test(fileName));\n      if (testFile) {\n        // TODO: Remove this as soon as the real test is fixed\n        it('true', () => {\n          expect(true).toEqual(true);\n        });\n        // TODO: Fix this test\n        // it(`${testEntry.name}`, async () => {\n        //   const inputPath = join(testDir, testFile);\n\n        //   // snapshot the output of compodoc\n        //   const compodocOutput = runCompodoc(inputPath);\n        //   const compodocJson = JSON.parse(compodocOutput);\n        //   await expect(compodocJson).toMatchFileSnapshot(\n        //     join(testDir, `compodoc-${SNAPSHOT_OS}.snapshot`)\n        //   );\n\n        //   // snapshot the output of addon-docs angular-properties\n        //   const componentData = findComponentByName('InputComponent', compodocJson);\n        //   const argTypes = extractArgTypesFromData(componentData);\n        //   await expect(argTypes).toMatchFileSnapshot(join(testDir, 'argtypes.snapshot'));\n        // });\n      }\n    }\n  });\n});\n"
  },
  {
    "path": "code/frameworks/angular/src/client/docs/config.ts",
    "content": "import { SourceType } from 'storybook/internal/docs-tools';\nimport type { DecoratorFunction, Parameters } from 'storybook/internal/types';\n\nimport { sourceDecorator } from './sourceDecorator';\n\nexport const parameters: Parameters = {\n  docs: {\n    source: {\n      type: SourceType.DYNAMIC,\n      language: 'html',\n    },\n  },\n};\n\nexport const decorators: DecoratorFunction[] = [sourceDecorator];\n"
  },
  {
    "path": "code/frameworks/angular/src/client/docs/sourceDecorator.ts",
    "content": "import { SourceType } from 'storybook/internal/docs-tools';\nimport { useRef, emitTransformCode, useEffect } from 'storybook/preview-api';\nimport type { ArgsStoryFn, PartialStoryFn } from 'storybook/internal/types';\n\nimport { computesTemplateSourceFromComponent } from '../../renderer';\nimport type { AngularRenderer, StoryContext } from '../types';\n\nexport const skipSourceRender = (context: StoryContext) => {\n  const sourceParams = context?.parameters.docs?.source;\n\n  // always render if the user forces it\n  if (sourceParams?.type === SourceType.DYNAMIC) {\n    return false;\n  }\n  // never render if the user is forcing the block to render code, or\n  // if the user provides code\n  return sourceParams?.code || sourceParams?.type === SourceType.CODE;\n};\n\n/**\n * Angular source decorator.\n *\n * @param storyFn Fn\n * @param context StoryContext\n */\nexport const sourceDecorator = (\n  storyFn: PartialStoryFn<AngularRenderer>,\n  context: StoryContext\n) => {\n  const story = storyFn();\n  const source = useRef<undefined | string>(undefined);\n\n  useEffect(() => {\n    if (skipSourceRender(context)) {\n      return;\n    }\n\n    const { props, userDefinedTemplate } = story;\n    const { component, argTypes, parameters } = context;\n    const template: string = parameters.docs?.source?.excludeDecorators\n      ? (context.originalStoryFn as ArgsStoryFn<AngularRenderer>)(context.args, context).template\n      : story.template;\n\n    if (component && !userDefinedTemplate) {\n      const sourceFromComponent = computesTemplateSourceFromComponent(component, props, argTypes);\n\n      // We might have a story with a Directive or Service defined as the component\n      // In these cases there might exist a template, even if we aren't able to create source from component\n      const newSource = sourceFromComponent || template;\n\n      if (newSource && newSource !== source.current) {\n        emitTransformCode(newSource, context);\n        source.current = newSource;\n      }\n    } else if (template && template !== source.current) {\n      emitTransformCode(template, context);\n      source.current = template;\n    }\n  });\n\n  return story;\n};\n"
  },
  {
    "path": "code/frameworks/angular/src/client/globals.ts",
    "content": "import { global } from '@storybook/global';\n\n/**\n * This file includes polyfills needed by Angular and is loaded before the app. You can add your own\n * extra polyfills to this file.\n *\n * This file is divided into 2 sections:\n *\n * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.\n * 2. Application imports. Files imported after ZoneJS that should be loaded before your main file.\n *\n * The current setup is for so-called \"evergreen\" browsers; the last versions of browsers that\n * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),\n * Edge> = 13 on the desktop, and iOS 10 and Chrome on mobile.\n *\n * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html\n */\n\n/**\n * Required to support Web Animations `@angular/animation`. Needed for: All but Chrome, Firefox and\n * Opera. http://caniuse.com/#feat=web-animation\n */\n// import 'web-animations-js';  // Run `npm install --save web-animations-js`.\n\n// Included with Angular CLI.\n\n/** APPLICATION IMPORTS */\n\n/**\n * Date, currency, decimal and percent pipes. Needed for: All but Chrome, Firefox, Edge, IE11 and\n * Safari 10\n */\n// import 'intl';  // Run `npm install --save intl`.\n/** Need to import at least one locale-data with intl. */\n// import 'intl/locale-data/jsonp/en';\n\nglobal.STORYBOOK_ENV = 'angular';\n"
  },
  {
    "path": "code/frameworks/angular/src/client/index.ts",
    "content": "import './globals.ts';\n\nexport * from './public-types.ts';\nexport * from './portable-stories.ts';\nexport * from './preview.ts';\n\nexport type { StoryFnAngularReturnType as IStory } from './types.ts';\n\nexport { moduleMetadata, componentWrapperDecorator, applicationConfig } from './decorators.ts';\nexport { argsToTemplate } from './argsToTemplate.ts';\n"
  },
  {
    "path": "code/frameworks/angular/src/client/portable-stories.ts",
    "content": "import {\n  setProjectAnnotations as originalSetProjectAnnotations,\n  setDefaultProjectAnnotations,\n} from 'storybook/preview-api';\nimport type {\n  NamedOrDefaultProjectAnnotations,\n  NormalizedProjectAnnotations,\n} from 'storybook/internal/types';\n\nimport * as INTERNAL_DEFAULT_PROJECT_ANNOTATIONS from './render.ts';\nimport type { AngularRenderer } from './types.ts';\n\n/**\n * Function that sets the globalConfig of your storybook. The global config is the preview module of\n * your .storybook folder.\n *\n * It should be run a single time, so that your global config (e.g. decorators) is applied to your\n * stories when using `composeStories` or `composeStory`.\n *\n * Example:\n *\n * ```jsx\n * // setup-file.js\n * import { setProjectAnnotations } from '@storybook/angular';\n *\n * import projectAnnotations from './.storybook/preview';\n *\n * setProjectAnnotations(projectAnnotations);\n * ```\n *\n * @param projectAnnotations - E.g. (import projectAnnotations from '../.storybook/preview')\n */\nexport function setProjectAnnotations(\n  projectAnnotations:\n    | NamedOrDefaultProjectAnnotations<any>\n    | NamedOrDefaultProjectAnnotations<any>[]\n): NormalizedProjectAnnotations<AngularRenderer> {\n  setDefaultProjectAnnotations(INTERNAL_DEFAULT_PROJECT_ANNOTATIONS);\n  return originalSetProjectAnnotations(\n    projectAnnotations\n  ) as NormalizedProjectAnnotations<AngularRenderer>;\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/client/preview-prod.ts",
    "content": "import { enableProdMode } from '@angular/core';\n\nenableProdMode();\n"
  },
  {
    "path": "code/frameworks/angular/src/client/preview.ts",
    "content": "import type {\n  AddonTypes,\n  InferTypes,\n  Meta,\n  Preview,\n  PreviewAddon,\n  Story,\n} from 'storybook/internal/csf';\nimport { definePreview as definePreviewBase } from 'storybook/internal/csf';\nimport type {\n  ArgsStoryFn,\n  ComponentAnnotations,\n  DecoratorFunction,\n  ProjectAnnotations,\n  Renderer,\n  StoryAnnotations,\n} from 'storybook/internal/types';\n\nimport type { RemoveIndexSignature, SetOptional, Simplify, UnionToIntersection } from 'type-fest';\n\nimport * as angularAnnotations from './config.ts';\nimport * as angularDocsAnnotations from './docs/config.ts';\nimport type { TransformComponentType } from './public-types.ts';\nimport { type AngularRenderer } from './types.ts';\n\n/**\n * Creates an Angular-specific preview configuration with CSF factories support.\n *\n * This function wraps the base `definePreview` and adds Angular-specific annotations for rendering\n * and documentation. It returns an `AngularPreview` that provides type-safe `meta()` and `story()`\n * factory methods.\n *\n * @example\n *\n * ```ts\n * // .storybook/preview.ts\n * import { definePreview } from '@storybook/angular';\n *\n * export const preview = definePreview({\n *   addons: [],\n *   parameters: { layout: 'centered' },\n * });\n * ```\n */\nexport function __definePreview<Addons extends PreviewAddon<never>[]>(\n  input: { addons: Addons } & ProjectAnnotations<AngularRenderer & InferTypes<Addons>>\n): AngularPreview<AngularRenderer & InferTypes<Addons>> {\n  const preview = definePreviewBase({\n    ...input,\n    addons: [angularAnnotations, angularDocsAnnotations, ...(input.addons ?? [])],\n  }) as unknown as AngularPreview<AngularRenderer & InferTypes<Addons>>;\n\n  return preview;\n}\n\ntype InferArgs<TArgs, T, Decorators> = Simplify<\n  TArgs & Simplify<RemoveIndexSignature<DecoratorsArgs<AngularRenderer & T, Decorators>>>\n>;\n\ntype InferComponentArgs<C extends abstract new (...args: any) => any> = Partial<\n  TransformComponentType<InstanceType<C>>\n>;\n\ntype InferAngularTypes<T, TArgs, Decorators> = AngularRenderer &\n  T & { args: Simplify<InferArgs<TArgs, T, Decorators>> };\n\n/**\n * Angular-specific Preview interface that provides type-safe CSF factory methods.\n *\n * Use `preview.meta()` to create a meta configuration for a component, and then `meta.story()` to\n * create individual stories. The type system will infer args from the component, decorators, and\n * any addon types.\n *\n * @example\n *\n * ```ts\n * const meta = preview.meta({ component: ButtonComponent });\n * export const Primary = meta.story({ args: { label: 'Click me' } });\n * ```\n */\nexport interface AngularPreview<T extends AddonTypes> extends Preview<AngularRenderer & T> {\n  /**\n   * Narrows the type of the preview to include additional type information. This is useful when you\n   * need to add args that aren't inferred from the component.\n   *\n   * @example\n   *\n   * ```ts\n   * const meta = preview.type<{ args: { theme: 'light' | 'dark' } }>().meta({\n   *   component: ButtonComponent,\n   * });\n   * ```\n   */\n  type<S>(): AngularPreview<T & S>;\n\n  meta<\n    C extends abstract new (...args: any) => any,\n    Decorators extends DecoratorFunction<AngularRenderer & T, any>,\n    // Try to make Exact<Partial<TArgs>, TMetaArgs> work\n    TMetaArgs extends Partial<InferComponentArgs<C> & T['args']>,\n  >(\n    meta: {\n      component?: C;\n      args?: TMetaArgs;\n      decorators?: Decorators | Decorators[];\n    } & Omit<\n      ComponentAnnotations<AngularRenderer & T, InferComponentArgs<C> & T['args']>,\n      'decorators' | 'component' | 'args'\n    >\n  ): AngularMeta<\n    InferAngularTypes<T, InferComponentArgs<C>, Decorators>,\n    Omit<ComponentAnnotations<InferAngularTypes<T, InferComponentArgs<C>, Decorators>>, 'args'> & {\n      args: {} extends TMetaArgs ? {} : TMetaArgs;\n    }\n  >;\n\n  meta<\n    TArgs,\n    Decorators extends DecoratorFunction<AngularRenderer & T, any>,\n    TMetaArgs extends Partial<TArgs & T['args']>,\n  >(\n    meta: {\n      render?: ArgsStoryFn<AngularRenderer & T, TArgs & T['args']>;\n      args?: TMetaArgs;\n      decorators?: Decorators | Decorators[];\n    } & Omit<\n      ComponentAnnotations<AngularRenderer & T, TArgs & T['args']>,\n      'decorators' | 'args' | 'render' | 'component'\n    >\n  ): AngularMeta<\n    InferAngularTypes<T, TArgs, Decorators>,\n    Omit<ComponentAnnotations<InferAngularTypes<T, TArgs, Decorators>>, 'args'> & {\n      args: {} extends TMetaArgs ? {} : TMetaArgs;\n    }\n  >;\n}\n\n/** Extracts and unions all args types from an array of decorators. */\ntype DecoratorsArgs<TRenderer extends Renderer, Decorators> = UnionToIntersection<\n  Decorators extends DecoratorFunction<TRenderer, infer TArgs> ? TArgs : unknown\n>;\n\n/**\n * Angular-specific Meta interface returned by `preview.meta()`.\n *\n * Provides the `story()` method to create individual stories with proper type inference. Args\n * provided in meta become optional in stories, while missing required args must be provided at the\n * story level.\n */\nexport interface AngularMeta<\n  T extends AngularRenderer,\n  MetaInput extends ComponentAnnotations<T>,\n> extends Meta<T, MetaInput> {\n  /**\n   * Creates a story with a custom render function that takes no args.\n   *\n   * This overload allows you to define a story using just a render function or an object with a\n   * render function that doesn't depend on args. Since the render function doesn't use args, no\n   * args need to be provided regardless of what's required by the component.\n   *\n   * @example\n   *\n   * ```ts\n   * // Using just a render function\n   * export const CustomTemplate = meta.story(() => ({\n   *   template: '<div>Custom static content</div>',\n   * }));\n   *\n   * // Using an object with render\n   * export const WithRender = meta.story({\n   *   render: () => ({ template: '<my-component></my-component>' }),\n   * });\n   * ```\n   */\n  story<\n    TInput extends\n      | (() => AngularRenderer['storyResult'])\n      | (StoryAnnotations<T, T['args']> & {\n          render: () => AngularRenderer['storyResult'];\n        }),\n  >(\n    story: TInput\n  ): AngularStory<\n    T,\n    TInput extends () => AngularRenderer['storyResult'] ? { render: TInput } : TInput\n  >;\n\n  /**\n   * Creates a story with custom configuration including args, decorators, or other annotations.\n   *\n   * This is the primary overload for defining stories. Args that were already provided in meta\n   * become optional, while any remaining required args must be specified here.\n   *\n   * @example\n   *\n   * ```ts\n   * // Provide required args not in meta\n   * export const Primary = meta.story({\n   *   args: { label: 'Click me', disabled: false },\n   * });\n   *\n   * // Override meta args and add story-specific configuration\n   * export const Disabled = meta.story({\n   *   args: { disabled: true },\n   *   decorators: [withCustomWrapper],\n   * });\n   * ```\n   */\n  story<\n    TInput extends Simplify<\n      StoryAnnotations<\n        T,\n        T['args'],\n        SetOptional<T['args'], keyof T['args'] & keyof MetaInput['args']>\n      >\n    >,\n  >(\n    story: TInput\n  ): AngularStory<T, TInput>;\n\n  /**\n   * Creates a story with no additional configuration.\n   *\n   * This overload is only available when all required args have been provided in meta. The\n   * conditional type `Partial<T['args']> extends SetOptional<...>` checks if the remaining required\n   * args (after accounting for args provided in meta) are all optional. If so, the function accepts\n   * zero arguments `[]`. Otherwise, it requires `[never]` which makes this overload unmatchable,\n   * forcing the user to provide args.\n   *\n   * @example\n   *\n   * ```ts\n   * // When meta provides all required args, story() can be called with no arguments\n   * const meta = preview.meta({ component: Button, args: { label: 'Hi', disabled: false } });\n   * export const Default = meta.story(); // Valid - all args provided in meta\n   * ```\n   */\n  story(\n    ..._args: Partial<T['args']> extends SetOptional<\n      T['args'],\n      keyof T['args'] & keyof MetaInput['args']\n    >\n      ? []\n      : [never]\n  ): AngularStory<T, {}>;\n}\n\n/**\n * Angular-specific Story interface returned by `meta.story()`.\n *\n * Represents a single story with its configuration and provides access to the composed story for\n * testing via `story.run()`.\n */\nexport interface AngularStory<\n  T extends AngularRenderer,\n  TInput extends StoryAnnotations<T, T['args']>,\n> extends Story<T, TInput> {}\n"
  },
  {
    "path": "code/frameworks/angular/src/client/public-types.ts",
    "content": "/* eslint-disable @typescript-eslint/ban-ts-comment */\nimport type {\n  AnnotatedStoryFn,\n  Args,\n  ComponentAnnotations,\n  DecoratorFunction,\n  LoaderFunction,\n  StoryAnnotations,\n  StoryContext as GenericStoryContext,\n  StrictArgs,\n  ProjectAnnotations,\n} from 'storybook/internal/types';\nimport type * as AngularCore from '@angular/core';\nimport type { AngularRenderer } from './types.ts';\n\nexport type { Args, ArgTypes, Parameters, StrictArgs } from 'storybook/internal/types';\nexport type { Parameters as AngularParameters } from './types.ts';\nexport type { AngularRenderer };\n\n/**\n * Metadata to configure the stories for a component.\n *\n * @see [Default export](https://storybook.js.org/docs/api/csf#default-export)\n */\nexport type Meta<TArgs = Args> = ComponentAnnotations<\n  AngularRenderer,\n  TransformComponentType<TArgs>\n>;\n\n/**\n * Story function that represents a CSFv2 component example.\n *\n * @see [Named Story exports](https://storybook.js.org/docs/api/csf#named-story-exports)\n */\nexport type StoryFn<TArgs = Args> = AnnotatedStoryFn<\n  AngularRenderer,\n  TransformComponentType<TArgs>\n>;\n\n/**\n * Story object that represents a CSFv3 component example.\n *\n * @see [Named Story exports](https://storybook.js.org/docs/api/csf#named-story-exports)\n */\nexport type StoryObj<TArgs = Args> = StoryAnnotations<\n  AngularRenderer,\n  TransformComponentType<TArgs>\n>;\n\nexport type Decorator<TArgs = StrictArgs> = DecoratorFunction<AngularRenderer, TArgs>;\nexport type Loader<TArgs = StrictArgs> = LoaderFunction<AngularRenderer, TArgs>;\nexport type StoryContext<TArgs = StrictArgs> = GenericStoryContext<AngularRenderer, TArgs>;\nexport type Preview = ProjectAnnotations<AngularRenderer>;\n\n/** Utility type that transforms InputSignal and EventEmitter types */\nexport type TransformComponentType<T> = TransformInputSignalType<\n  TransformOutputSignalType<TransformEventType<T>>\n>;\n\n// @ts-ignore Angular < 17.2 doesn't export InputSignal\ntype AngularInputSignal<T> = AngularCore.InputSignal<T>;\n// @ts-ignore Angular < 17.2 doesn't export InputSignalWithTransform\ntype AngularInputSignalWithTransform<T, U> = AngularCore.InputSignalWithTransform<T, U>;\n// @ts-ignore Angular < 17.3 doesn't export AngularOutputEmitterRef\ntype AngularOutputEmitterRef<T> = AngularCore.OutputEmitterRef<T>;\n\ntype AngularHasInputSignal = typeof AngularCore extends { input: infer U } ? true : false;\ntype AngularHasOutputSignal = typeof AngularCore extends { output: infer U } ? true : false;\n\ntype InputSignal<T> = AngularHasInputSignal extends true ? AngularInputSignal<T> : never;\ntype InputSignalWithTransform<T, U> = AngularHasInputSignal extends true\n  ? AngularInputSignalWithTransform<T, U>\n  : never;\ntype OutputEmitterRef<T> = AngularHasOutputSignal extends true ? AngularOutputEmitterRef<T> : never;\n\ntype TransformInputSignalType<T> = {\n  [K in keyof T]: T[K] extends InputSignal<infer E>\n    ? E\n    : T[K] extends InputSignalWithTransform<any, infer U>\n      ? U\n      : T[K];\n};\n\ntype TransformOutputSignalType<T> = {\n  [K in keyof T]: T[K] extends OutputEmitterRef<infer E> ? (e: E) => void : T[K];\n};\n\ntype TransformEventType<T> = {\n  [K in keyof T]: T[K] extends AngularCore.EventEmitter<infer E> ? (e: E) => void : T[K];\n};\n"
  },
  {
    "path": "code/frameworks/angular/src/client/render.ts",
    "content": "import type { ArgsStoryFn, RenderContext } from 'storybook/internal/types';\n\nimport '@angular/compiler';\n\nimport { RendererFactory } from './angular-beta/RendererFactory.ts';\nimport type { AngularRenderer } from './types.ts';\n\nexport const rendererFactory = new RendererFactory();\n\nexport const render: ArgsStoryFn<AngularRenderer> = (props) => ({ props });\n\nexport async function renderToCanvas(\n  {\n    storyFn,\n    showMain,\n    forceRemount,\n    storyContext: { component, id: storyId },\n  }: RenderContext<AngularRenderer>,\n  element: HTMLElement\n) {\n  showMain();\n\n  const renderer = await rendererFactory.getRendererInstance(element);\n\n  await renderer.render({\n    storyId,\n    storyFnAngular: storyFn(),\n    component,\n    forced: !forceRemount,\n    targetDOMNode: element,\n  });\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/client/types.ts",
    "content": "import type {\n  Parameters as DefaultParameters,\n  StoryContext as DefaultStoryContext,\n  WebRenderer,\n} from 'storybook/internal/types';\n\nimport type { ApplicationConfig, Provider } from '@angular/core';\n\nexport interface NgModuleMetadata {\n  /** List of components, directives, and pipes that belong to your component. */\n  declarations?: any[];\n  entryComponents?: any[];\n  /**\n   * List of modules that should be available to the root Storybook Component and all its children.\n   * If you want to register application providers or if you want to use the forRoot() pattern,\n   * please use the `applicationConfig` decorator in combination with the importProvidersFrom helper\n   * function from @angular/core instead.\n   */\n  imports?: any[];\n  schemas?: any[];\n  /**\n   * List of providers that should be available on the root component and all its children. Use the\n   * `applicationConfig` decorator to register environemt and application-wide providers.\n   */\n  providers?: Provider[];\n}\nexport interface ICollection {\n  [p: string]: any;\n}\n\nexport interface StoryFnAngularReturnType {\n  props?: ICollection;\n  moduleMetadata?: NgModuleMetadata;\n  applicationConfig?: ApplicationConfig;\n  template?: string;\n  styles?: string[];\n  userDefinedTemplate?: boolean;\n}\n\nexport interface AngularRenderer extends WebRenderer {\n  component: any;\n  storyResult: StoryFnAngularReturnType;\n}\n\nexport type Parameters = DefaultParameters & {\n  bootstrapModuleOptions?: unknown;\n};\n\nexport type StoryContext = DefaultStoryContext<AngularRenderer> & { parameters: Parameters };\n"
  },
  {
    "path": "code/frameworks/angular/src/index.ts",
    "content": "export * from './client/index.ts';\nexport * from './types.ts';\n\nexport { __definePreview as definePreview } from './client/index.ts';\n\n/*\n * ATTENTION:\n * - moduleMetadata\n * - NgModuleMetadata\n * - ICollection\n *\n * These typings are coped out of decorators.d.ts and types.d.ts in order to fix a bug with tsc\n * It was imported out of dist before which was not the proper way of exporting public API\n *\n * This can be fixed by migrating app/angular to typescript\n */\n"
  },
  {
    "path": "code/frameworks/angular/src/node/index.ts",
    "content": "import type { StorybookConfig } from '../types.ts';\n\nexport function defineMain(config: StorybookConfig) {\n  return config;\n}\n\nexport type { StorybookConfig };\n"
  },
  {
    "path": "code/frameworks/angular/src/preset.ts",
    "content": "import type { PresetProperty } from 'storybook/internal/types';\n\nimport type { StandaloneOptions } from './builders/utils/standalone-options.ts';\nimport { fileURLToPath } from 'node:url';\n\nexport const addons: PresetProperty<'addons'> = [\n  fileURLToPath(import.meta.resolve('@storybook/angular/server/framework-preset-angular-cli')),\n  fileURLToPath(import.meta.resolve('@storybook/angular/server/framework-preset-angular-ivy')),\n];\n\nexport const previewAnnotations: PresetProperty<'previewAnnotations'> = async (\n  entries = [],\n  options\n) => {\n  const config = fileURLToPath(import.meta.resolve('@storybook/angular/client/config'));\n  const annotations = [...entries, config];\n\n  if ((options as any as StandaloneOptions).enableProdMode) {\n    const previewProdPath = fileURLToPath(\n      import.meta.resolve('@storybook/angular/client/preview-prod')\n    );\n    annotations.unshift(previewProdPath);\n  }\n\n  const docsConfig = await options.presets.apply('docs', {}, options);\n  const docsEnabled = Object.keys(docsConfig).length > 0;\n  if (docsEnabled) {\n    const docsConfigPath = fileURLToPath(\n      import.meta.resolve('@storybook/angular/client/docs/config')\n    );\n    annotations.push(docsConfigPath);\n  }\n  return annotations;\n};\n\nexport const core: PresetProperty<'core'> = {\n  builder: import.meta.resolve('@storybook/builder-webpack5'),\n};\n\nexport const typescript: PresetProperty<'typescript'> = async (config) => {\n  return {\n    ...config,\n    skipCompiler: true,\n  };\n};\n"
  },
  {
    "path": "code/frameworks/angular/src/renderer.ts",
    "content": "export { storyPropsProvider } from './client/angular-beta/StorybookProvider.ts';\nexport { computesTemplateSourceFromComponent } from './client/angular-beta/ComputesTemplateFromComponent.ts';\nexport { rendererFactory } from './client/render.ts';\nexport { AbstractRenderer } from './client/angular-beta/AbstractRenderer.ts';\nexport { getApplication } from './client/angular-beta/StorybookModule.ts';\nexport { PropertyExtractor } from './client/angular-beta/utils/PropertyExtractor.ts';\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/empty-projects-entry/angular.json",
    "content": "{\n  \"version\": 1,\n  \"projects\": {}\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/minimal-config/angular.json",
    "content": "{\n  \"version\": 1,\n  \"projects\": {\n    \"foo-project\": {\n      \"root\": \"\",\n      \"sourceRoot\": \"src\",\n      \"architect\": {\n        \"build\": {\n          \"options\": {\n            \"tsConfig\": \"src/tsconfig.app.json\",\n            \"assets\": []\n          }\n        }\n      }\n    }\n  },\n  \"defaultProject\": \"foo-project\"\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/minimal-config/src/main.ts",
    "content": "// To avoid \"No inputs were found in config file\" tsc error\nexport const not = 'empty';\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/minimal-config/src/tsconfig.app.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \"./\",\n    \"module\": \"es2015\",\n    \"types\": [\"node\"]\n  },\n  \"exclude\": [\"karma.ts\", \"**/*.spec.ts\"]\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/minimal-config/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"sourceMap\": true,\n    \"moduleResolution\": \"node\",\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"target\": \"es5\",\n    \"lib\": [\"es2017\", \"dom\"]\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/some-config/angular.json",
    "content": "{\n  \"version\": 1,\n  \"projects\": {\n    \"foo-project\": {\n      \"root\": \"\",\n      \"sourceRoot\": \"src\",\n      \"architect\": {\n        \"build\": {\n          \"options\": {\n            \"optimization\": false,\n            \"tsConfig\": \"src/tsconfig.app.json\",\n            \"assets\": []\n          }\n        }\n      }\n    }\n  },\n  \"defaultProject\": \"foo-project\"\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/some-config/src/main.ts",
    "content": "// To avoid \"No inputs were found in config file\" tsc error\nexport const not = 'empty';\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/some-config/src/tsconfig.app.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \"./\",\n    \"module\": \"es2015\",\n    \"types\": [\"node\"]\n  },\n  \"exclude\": [\"karma.ts\", \"**/*.spec.ts\"]\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/some-config/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"sourceMap\": true,\n    \"moduleResolution\": \"node\",\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"target\": \"es5\",\n    \"lib\": [\"es2017\", \"dom\"]\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-angularBrowserTarget/angular.json",
    "content": "{\n  \"version\": 1,\n  \"projects\": {\n    \"foo-project\": {\n      \"root\": \"\",\n      \"sourceRoot\": \"src\",\n      \"architect\": {\n        \"build\": {\n          \"options\": {\n            \"tsConfig\": \"src/tsconfig.app.json\",\n            \"assets\": []\n          }\n        }\n      }\n    },\n    \"no-confs-project\": {\n      \"root\": \"\",\n      \"sourceRoot\": \"src\",\n      \"architect\": {\n        \"target-build\": {\n          \"options\": {\n            \"tsConfig\": \"src/tsconfig.app.json\",\n            \"assets\": []\n          }\n        }\n      }\n    },\n    \"no-target-conf-project\": {\n      \"root\": \"\",\n      \"sourceRoot\": \"src\",\n      \"architect\": {\n        \"target-build\": {\n          \"options\": {\n            \"tsConfig\": \"src/tsconfig.app.json\",\n            \"assets\": []\n          },\n          \"configurations\": {\n            \"other-conf\": {\n              \"styles\": [\"src/styles.css\"]\n            }\n          }\n        }\n      }\n    },\n    \"target-project\": {\n      \"root\": \"\",\n      \"sourceRoot\": \"src\",\n      \"architect\": {\n        \"target-build\": {\n          \"options\": {\n            \"tsConfig\": \"src/tsconfig.app.json\",\n            \"assets\": []\n          },\n          \"configurations\": {\n            \"target-conf\": {\n              \"styles\": [\"src/styles.css\"]\n            }\n          }\n        }\n      }\n    }\n  },\n  \"defaultProject\": \"foo-project\"\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-angularBrowserTarget/src/main.ts",
    "content": "// To avoid \"No inputs were found in config file\" tsc error\nexport const not = 'empty';\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-angularBrowserTarget/src/styles.css",
    "content": ".class {\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-angularBrowserTarget/src/tsconfig.app.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \"./\",\n    \"module\": \"es2015\",\n    \"types\": [\"node\"]\n  },\n  \"exclude\": [\"karma.ts\", \"**/*.spec.ts\"]\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-angularBrowserTarget/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"sourceMap\": true,\n    \"moduleResolution\": \"node\",\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"target\": \"es5\",\n    \"lib\": [\"es2017\", \"dom\"]\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-lib/angular.json",
    "content": "{\n  \"$schema\": \"./node_modules/@angular/cli/lib/config/schema.json\",\n  \"version\": 1,\n  \"newProjectRoot\": \"projects\",\n  \"projects\": {\n    \"pattern-lib\": {\n      \"projectType\": \"library\",\n      \"root\": \"projects/pattern-lib\",\n      \"sourceRoot\": \"projects/pattern-lib/src\",\n      \"prefix\": \"lib\",\n      \"architect\": {\n        \"build\": {\n          \"builder\": \"@angular-devkit/build-angular:ng-packagr\",\n          \"options\": {\n            \"tsConfig\": \"projects/pattern-lib/tsconfig.lib.json\",\n            \"project\": \"projects/pattern-lib/ng-package.json\"\n          },\n          \"configurations\": {\n            \"production\": {\n              \"tsConfig\": \"projects/pattern-lib/tsconfig.lib.prod.json\"\n            }\n          }\n        }\n      }\n    }\n  },\n  \"defaultProject\": \"pattern-lib\"\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-lib/projects/pattern-lib/src/main.ts",
    "content": "// To avoid \"No inputs were found in config file\" tsc error\nexport const not = 'empty';\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-lib/projects/pattern-lib/tsconfig.lib.json",
    "content": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"../../out-tsc/lib\",\n    \"target\": \"es2015\",\n    \"declaration\": true,\n    \"declarationMap\": true,\n    \"inlineSources\": true,\n    \"types\": [],\n    \"lib\": [\"dom\", \"es2018\"]\n  },\n  \"angularCompilerOptions\": {\n    \"skipTemplateCodegen\": true,\n    \"strictMetadataEmit\": true,\n    \"enableResourceInlining\": true\n  },\n  \"exclude\": [\"src/test.ts\", \"**/*.spec.ts\"]\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-lib/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"sourceMap\": true,\n    \"moduleResolution\": \"node\",\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"target\": \"es5\",\n    \"lib\": [\"es2017\", \"dom\"]\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-nx/angular.json",
    "content": "{\n  \"version\": 1,\n  \"projects\": {\n    \"foo-project\": {\n      \"root\": \"\",\n      \"sourceRoot\": \"src\",\n      \"architect\": {\n        \"build\": {\n          \"options\": {\n            \"tsConfig\": \"src/tsconfig.app.json\",\n            \"styles\": [\"src/styles.css\", \"src/styles.scss\"]\n          }\n        }\n      }\n    }\n  },\n  \"defaultProject\": \"foo-project\"\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-nx/nx.json",
    "content": "{\n  \"npmScope\": \"nx-example\"\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-nx/src/main.ts",
    "content": "// To avoid \"No inputs were found in config file\" tsc error\nexport const not = 'empty';\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-nx/src/styles.css",
    "content": ".class {\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-nx/src/styles.scss",
    "content": ".class {\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-nx/src/tsconfig.app.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \"./\",\n    \"module\": \"es2015\",\n    \"types\": [\"node\"]\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-nx/tsconfig.json",
    "content": "{\n  \"include\": [\"./src\"],\n  \"compilerOptions\": {\n    \"sourceMap\": true,\n    \"moduleResolution\": \"node\",\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"target\": \"es5\",\n    \"lib\": [\"es2017\", \"dom\"]\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-nx-workspace/nx.json",
    "content": "{\n  \"npmScope\": \"nx-example\"\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-nx-workspace/src/main.ts",
    "content": "// To avoid \"No inputs were found in config file\" tsc error\nexport const not = 'empty';\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-nx-workspace/src/styles.css",
    "content": ".class {\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-nx-workspace/src/styles.scss",
    "content": ".class {\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-nx-workspace/src/tsconfig.app.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \"./\",\n    \"module\": \"es2015\",\n    \"types\": [\"node\"]\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-nx-workspace/tsconfig.json",
    "content": "{\n  \"include\": [\"./src\"],\n  \"compilerOptions\": {\n    \"sourceMap\": true,\n    \"moduleResolution\": \"node\",\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"target\": \"es5\",\n    \"lib\": [\"es2017\", \"dom\"]\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-nx-workspace/workspace.json",
    "content": "{\n  \"version\": 1,\n  \"projects\": {\n    \"foo-project\": {\n      \"root\": \"\",\n      \"sourceRoot\": \"src\",\n      \"architect\": {\n        \"build\": {\n          \"options\": {\n            \"tsConfig\": \"src/tsconfig.app.json\",\n            \"styles\": [\"src/styles.css\", \"src/styles.scss\"]\n          }\n        }\n      }\n    }\n  },\n  \"defaultProject\": \"foo-project\"\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-options-styles/angular.json",
    "content": "{\n  \"version\": 1,\n  \"projects\": {\n    \"foo-project\": {\n      \"root\": \"\",\n      \"sourceRoot\": \"src\",\n      \"architect\": {\n        \"build\": {\n          \"options\": {\n            \"tsConfig\": \"src/tsconfig.app.json\",\n            \"styles\": [\"src/styles.css\", \"src/styles.scss\"]\n          }\n        }\n      }\n    }\n  },\n  \"defaultProject\": \"foo-project\"\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-options-styles/src/main.ts",
    "content": "// To avoid \"No inputs were found in config file\" tsc error\nexport const not = 'empty';\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-options-styles/src/styles.css",
    "content": ".class {\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-options-styles/src/styles.scss",
    "content": ".class {\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-options-styles/src/tsconfig.app.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \"./\",\n    \"module\": \"es2015\",\n    \"types\": [\"node\"]\n  },\n  \"exclude\": [\"karma.ts\", \"**/*.spec.ts\"]\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/with-options-styles/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"sourceMap\": true,\n    \"moduleResolution\": \"node\",\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"target\": \"es5\",\n    \"lib\": [\"es2017\", \"dom\"]\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/without-architect-build/angular.json",
    "content": "{\n  \"version\": 1,\n  \"projects\": { \"foo-project\": {} },\n  \"defaultProject\": \"foo-project\"\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/without-architect-build-options/angular.json",
    "content": "{\n  \"version\": 1,\n  \"projects\": {\n    \"foo-project\": {\n      \"architect\": {\n        \"build\": {}\n      }\n    }\n  },\n  \"defaultProject\": \"foo-project\"\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/without-compatible-projects/angular.json",
    "content": "{\n  \"version\": 1,\n  \"projects\": {\n    \"noop-project\": {}\n  },\n  \"defaultProject\": \"missing-project\"\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/without-projects-entry/angular.json",
    "content": "{\n  \"version\": 1\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/without-projects-entry/projects/pattern-lib/src/main.ts",
    "content": "// To avoid \"No inputs were found in config file\" tsc error\nexport const not = 'empty';\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/without-projects-entry/projects/pattern-lib/tsconfig.lib.json",
    "content": "/* To learn more about this file see: https://angular.io/config/tsconfig. */\n{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"outDir\": \"../../out-tsc/lib\",\n    \"target\": \"es2015\",\n    \"declaration\": true,\n    \"declarationMap\": true,\n    \"inlineSources\": true,\n    \"types\": [],\n    \"lib\": [\"dom\", \"es2018\"]\n  },\n  \"angularCompilerOptions\": {\n    \"skipTemplateCodegen\": true,\n    \"strictMetadataEmit\": true,\n    \"enableResourceInlining\": true\n  },\n  \"exclude\": [\"src/test.ts\", \"**/*.spec.ts\"]\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/without-projects-entry/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"sourceMap\": true,\n    \"moduleResolution\": \"node\",\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"target\": \"es5\",\n    \"lib\": [\"es2017\", \"dom\"]\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/without-tsConfig/angular.json",
    "content": "{\n  \"version\": 1,\n  \"projects\": {\n    \"foo-project\": {\n      \"root\": \"\",\n      \"architect\": {\n        \"build\": {\n          \"options\": {\n            \"assets\": []\n          }\n        }\n      }\n    }\n  },\n  \"defaultProject\": \"foo-project\"\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/without-tsConfig/src/main.ts",
    "content": "// To avoid \"No inputs were found in config file\" tsc error\nexport const not = 'empty';\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/without-tsConfig/src/tsconfig.app.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \"./\",\n    \"module\": \"es2015\",\n    \"types\": [\"node\"]\n  },\n  \"exclude\": [\"karma.ts\", \"**/*.spec.ts\"]\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__mocks-ng-workspace__/without-tsConfig/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"sourceMap\": true,\n    \"moduleResolution\": \"node\",\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"target\": \"es5\",\n    \"lib\": [\"es2017\", \"dom\"]\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/__tests__/angular.json",
    "content": "{\n  /* angular.json can have comments */\n  // angular.json can have comments\n  \"$schema\": \"./node_modules/@angular/cli/lib/config/schema.json\",\n  \"version\": 1,\n  \"newProjectRoot\": \"projects\",\n  \"projects\": {\n    \"angular-cli\": {\n      \"root\": \"\",\n      \"sourceRoot\": \"src\",\n      \"projectType\": \"application\",\n      \"prefix\": \"app\",\n      \"schematics\": {},\n      \"architect\": {\n        \"build\": {\n          \"builder\": \"@angular-devkit/build-angular:browser\",\n          \"options\": {\n            \"outputPath\": \"dist/angular-cli\",\n            \"index\": \"src/index.html\",\n            \"main\": \"src/main.ts\",\n            \"polyfills\": \"src/polyfills.ts\",\n            \"tsConfig\": \"src/tsconfig.app.json\",\n            \"assets\": [\"src/favicon.ico\", \"src/assets\"],\n            \"styles\": [\"src/styles.css\", \"src/styles.scss\"],\n            \"stylePreprocessorOptions\": {\n              \"includePaths\": [\"src/commons\"]\n            },\n            \"scripts\": []\n          },\n          \"configurations\": {\n            \"production\": {\n              \"fileReplacements\": [\n                {\n                  \"replace\": \"src/environments/environment.ts\",\n                  \"with\": \"src/environments/environment.prod.ts\"\n                }\n              ],\n              \"optimization\": true,\n              \"outputHashing\": \"all\",\n              \"sourceMap\": false,\n              \"extractCss\": true,\n              \"namedChunks\": false,\n              \"aot\": true,\n              \"extractLicenses\": true,\n              \"vendorChunk\": false,\n              \"buildOptimizer\": true\n            }\n          }\n        },\n        \"serve\": {\n          \"builder\": \"@angular-devkit/build-angular:dev-server\",\n          \"options\": {\n            \"browserTarget\": \"angular-cli:build\"\n          },\n          \"configurations\": {\n            \"production\": {\n              \"browserTarget\": \"angular-cli:build:production\"\n            }\n          }\n        },\n        \"extract-i18n\": {\n          \"builder\": \"@angular-devkit/build-angular:extract-i18n\",\n          \"options\": {\n            \"browserTarget\": \"angular-cli:build\"\n          }\n        },\n        \"test\": {\n          \"builder\": \"@angular-devkit/build-angular:karma\",\n          \"options\": {\n            \"main\": \"src/karma.ts\",\n            \"polyfills\": \"src/polyfills.ts\",\n            \"tsConfig\": \"src/tsconfig.spec.json\",\n            \"karmaConfig\": \"src/karma.conf.js\",\n            \"styles\": [\"styles.css\"],\n            \"scripts\": [],\n            \"assets\": [\"src/favicon.ico\", \"src/assets\"]\n          }\n        }\n      }\n    },\n    \"angular-cli-e2e\": {\n      \"root\": \"e2e/\",\n      \"projectType\": \"application\",\n      \"architect\": {\n        \"e2e\": {\n          \"builder\": \"@angular-devkit/build-angular:protractor\",\n          \"options\": {\n            \"protractorConfig\": \"e2e/protractor.conf.js\",\n            \"devServerTarget\": \"angular-cli:serve\"\n          }\n        }\n      }\n    }\n  },\n  \"defaultProject\": \"angular-cli\"\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/angular-cli-webpack.d.ts",
    "content": "import type { BuilderContext } from '@angular-devkit/architect';\nimport type { JsonObject } from '@angular-devkit/core';\n\nexport declare function getWebpackConfig(\n  baseConfig: any,\n  options: { builderOptions: JsonObject; builderContext: BuilderContext }\n): any;\n"
  },
  {
    "path": "code/frameworks/angular/src/server/angular-cli-webpack.js",
    "content": "import { createRequire } from 'node:module';\n\nimport StorybookNormalizeAngularEntryPlugin from './plugins/storybook-normalize-angular-entry-plugin';\nimport { filterOutStylingRules } from './utils/filter-out-styling-rules';\n\nconst require = createRequire(import.meta.url);\n\n// Private angular devkit stuff\nconst {\n  generateI18nBrowserWebpackConfigFromContext,\n} = require('@angular-devkit/build-angular/src/utils/webpack-browser-config');\nconst TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');\n\nconst {\n  getCommonConfig,\n  getStylesConfig,\n  getDevServerConfig,\n  getTypeScriptConfig,\n} = require('@angular-devkit/build-angular/src/tools/webpack/configs');\n\n/**\n * Extract webpack config from angular-cli 13.x.x ⚠️ This file is in JavaScript to not use\n * TypeScript. Because current storybook TypeScript version is not compatible with Angular CLI.\n * FIXME: Try another way with TypeScript on future storybook version (7 maybe 🤞)\n *\n * @param {any} baseConfig Previous webpack config from storybook\n * @param {any} options { builderOptions, builderContext }\n */\nexport const getWebpackConfig = async (baseConfig, { builderOptions, builderContext }) => {\n  /** Get angular-cli Webpack config */\n\n  /**\n   * Custom styles config that handles Tailwind 4 compatibility issues.\n   *\n   * Problem: Angular's getStylesConfig() doesn't support Tailwind 4's new PostCSS plugin\n   * architecture. When Tailwind 4 is detected, Angular tries to load it using the old v3 API which\n   * throws errors.\n   *\n   * Solution: Detect Tailwind 4, bypass Angular's automatic Tailwind detection by hiding config\n   * files, then manually inject the correct Tailwind 4 PostCSS plugin into the webpack\n   * configuration.\n   */\n  async function getCustomStylesConfig(wco) {\n    const { root } = wco;\n\n    /**\n     * Detect if Tailwind 4 is being used by checking for the new @tailwindcss/postcss package.\n     * Tailwind 4 uses @tailwindcss/postcss instead of the main tailwindcss package for PostCSS\n     * integration.\n     */\n    const isTailwind4 = () => {\n      try {\n        const output = import.meta.resolve('@tailwindcss/postcss', root);\n        return isAbsolute(output);\n      } catch {\n        return false;\n      }\n    };\n\n    if (isTailwind4()) {\n      // Monkey patch readdir to make findTailwindConfigurationFile return undefined\n      const fs = require('node:fs/promises');\n      const originalReaddir = fs.readdir;\n\n      /**\n       * Hide Tailwind config files from Angular's automatic detection. This prevents Angular from\n       * trying to load Tailwind using the incompatible v3 API. By filtering out tailwind config\n       * files, findTailwindConfigurationFile() returns undefined, and Angular skips its built-in\n       * Tailwind setup entirely.\n       */\n      fs.readdir = async function (path, options) {\n        const results = await originalReaddir.call(this, path, options);\n        const tailwindFiles = [\n          'tailwind.config.js',\n          'tailwind.config.cjs',\n          'tailwind.config.mjs',\n          'tailwind.config.ts',\n        ];\n        // Filter out tailwind config files from the results\n        return results.filter((file) => !tailwindFiles.includes(file));\n      };\n\n      // Get styles config without Tailwind interference\n      const styleConfig = await getStylesConfig(wco);\n\n      // Restore original readdir immediately after getting styles config\n      fs.readdir = originalReaddir;\n\n      /**\n       * Manually inject Tailwind 4 PostCSS plugin into the webpack configuration. Since we bypassed\n       * Angular's automatic Tailwind detection, we need to manually add the correct Tailwind 4\n       * plugin to all PostCSS loader configurations.\n       */\n      const tailwindPackagePath = import.meta.resolve('@tailwindcss/postcss', root);\n      const tailwindPackage = await import(tailwindPackagePath);\n      const extraPostcssPlugins = [\n        typeof tailwindPackage === 'function' ? tailwindPackage() : tailwindPackage.default(),\n      ];\n\n      /**\n       * Navigate through webpack's complex rule structure to find all postcss-loader instances and\n       * inject the Tailwind 4 plugin. This preserves Angular's existing PostCSS setup while adding\n       * Tailwind 4 support.\n       */\n      styleConfig.module.rules\n        .map((rule) => rule.rules)\n        .forEach((rule) => {\n          rule.forEach((r) => {\n            r.oneOf?.forEach?.((oneOfRule) => {\n              return oneOfRule.use.forEach((use) => {\n                if (use.loader.includes('postcss-loader') && use.options.postcssOptions) {\n                  const originalOptionsFn = use.options.postcssOptions;\n                  // Wrap the original postcssOptions function to append Tailwind 4 plugin\n                  use.options.postcssOptions = (loaderOptions) => {\n                    const originalOptions = originalOptionsFn(loaderOptions);\n\n                    return {\n                      ...originalOptions,\n                      plugins: [...originalOptions.plugins, ...extraPostcssPlugins],\n                    };\n                  };\n                }\n              });\n            });\n          });\n        });\n\n      return styleConfig;\n    } else {\n      // Use Angular's default styles config for Tailwind v3 and other CSS frameworks\n      return getStylesConfig(wco);\n    }\n  }\n\n  const { config: cliConfig } = await generateI18nBrowserWebpackConfigFromContext(\n    {\n      // Default options\n      index: 'noop-index',\n      main: 'noop-main',\n\n      // Options provided by user\n      ...builderOptions,\n      styles: builderOptions.styles\n        ?.map((style) => (typeof style === 'string' ? style : style.input))\n        .filter((style) => typeof style === 'string' || style.inject !== false),\n      outputPath:\n        typeof builderOptions.outputPath === 'string'\n          ? builderOptions.outputPath\n          : (builderOptions.outputPath?.base ?? 'noop-out'),\n\n      // Fixed options\n      optimization: false,\n      namedChunks: false,\n      progress: false,\n      buildOptimizer: false,\n      aot: false,\n    },\n    builderContext,\n    (wco) => [\n      getCommonConfig(wco),\n      getCustomStylesConfig(wco),\n      getTypeScriptConfig ? getTypeScriptConfig(wco) : getDevServerConfig(wco),\n    ]\n  );\n\n  if (!builderOptions.experimentalZoneless && !cliConfig.entry.polyfills?.includes('zone.js')) {\n    cliConfig.entry.polyfills ??= [];\n    cliConfig.entry.polyfills.push('zone.js');\n  }\n\n  /** Merge baseConfig Webpack with angular-cli Webpack */\n  const entry = [\n    ...(cliConfig.entry.polyfills ?? []),\n    ...baseConfig.entry,\n    ...(cliConfig.entry.styles ?? []),\n  ];\n\n  // Don't use storybooks styling rules because we have to use rules created by @angular-devkit/build-angular\n  // because @angular-devkit/build-angular created rules have include/exclude for global style files.\n  const rulesExcludingStyles = filterOutStylingRules(baseConfig);\n  const module = {\n    ...baseConfig.module,\n    rules: [...cliConfig.module.rules, ...rulesExcludingStyles],\n  };\n\n  const plugins = [\n    ...(cliConfig.plugins ?? []),\n    ...baseConfig.plugins,\n    new StorybookNormalizeAngularEntryPlugin(),\n  ];\n\n  const resolve = {\n    ...baseConfig.resolve,\n    modules: Array.from(new Set([...baseConfig.resolve.modules, ...cliConfig.resolve.modules])),\n    plugins: [\n      new TsconfigPathsPlugin({\n        configFile: builderOptions.tsConfig,\n        mainFields: ['browser', 'module', 'main'],\n      }),\n    ],\n  };\n\n  return {\n    ...baseConfig,\n    entry,\n    module,\n    plugins,\n    resolve,\n    resolveLoader: cliConfig.resolveLoader,\n  };\n};\n"
  },
  {
    "path": "code/frameworks/angular/src/server/framework-preset-angular-cli.test.ts",
    "content": "import { vi, expect, describe, it, beforeEach } from 'vitest';\n\nimport { logger } from 'storybook/internal/node-logger';\n\nimport type { BuilderContext } from '@angular-devkit/architect';\nimport { logging } from '@angular-devkit/core';\n\nimport { getBuilderOptions } from './framework-preset-angular-cli.ts';\nimport type { PresetOptions } from './preset-options.ts';\nimport { Channel } from 'storybook/internal/channels';\n\n// Mock all dependencies\nvi.mock('storybook/internal/node-logger', () => ({\n  logger: {\n    info: vi.fn(),\n  },\n}));\n\nvi.mock('storybook/internal/server-errors', () => ({\n  AngularLegacyBuildOptionsError: class AngularLegacyBuildOptionsError extends Error {\n    constructor() {\n      super('AngularLegacyBuildOptionsError');\n      this.name = 'AngularLegacyBuildOptionsError';\n    }\n  },\n}));\n\nvi.mock('storybook/internal/common', () => ({\n  getProjectRoot: vi.fn(),\n}));\n\nvi.mock('@storybook/builder-webpack5', () => ({}));\n\nvi.mock('@angular-devkit/architect', () => ({\n  targetFromTargetString: vi.fn(),\n}));\n\nvi.mock('empathic/find', () => ({ up: vi.fn() }));\n\nvi.mock('./utils/module-is-available', () => ({\n  moduleIsAvailable: vi.fn(),\n}));\n\nvi.mock('./angular-cli-webpack', () => ({\n  getWebpackConfig: vi.fn(),\n}));\n\nvi.mock('./preset-options', () => ({\n  PresetOptions: {},\n}));\n\n// Mock require.resolve for @angular/animations\nvi.mock('@angular/animations', () => ({}));\n\nconst mockedLogger = vi.mocked(logger);\n\nconst mockedTargetFromTargetString = vi.mocked(\n  await import('@angular-devkit/architect')\n).targetFromTargetString;\nconst mockedFindUp = vi.mocked(await import('empathic/find')).up;\nconst mockedGetProjectRoot = vi.mocked(await import('storybook/internal/common')).getProjectRoot;\n\ndescribe('framework-preset-angular-cli', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n  });\n\n  describe('getBuilderOptions', () => {\n    const mockBuilderContext: BuilderContext = {\n      target: { project: 'test-project', builder: 'test-builder', options: {} },\n      workspaceRoot: '/test/workspace',\n      getProjectMetadata: vi.fn().mockResolvedValue({}),\n      getTargetOptions: vi.fn().mockResolvedValue({}),\n      logger: new logging.Logger('Test'),\n    } as unknown as BuilderContext;\n\n    beforeEach(() => {\n      mockedGetProjectRoot.mockReturnValue('/test/project');\n      mockedFindUp.mockReturnValue('/test/tsconfig.json');\n    });\n\n    it('should get browser target options when angularBrowserTarget is provided', async () => {\n      const mockTarget = { project: 'test-project', target: 'build', configuration: 'development' };\n      mockedTargetFromTargetString.mockReturnValue(mockTarget);\n\n      const options: PresetOptions = {\n        configType: 'DEVELOPMENT',\n        configDir: '/test/config',\n        presets: {\n          apply: vi.fn(),\n        } as any,\n        angularBrowserTarget: 'test-project:build:development',\n        channel: new Channel({}),\n      };\n\n      await getBuilderOptions(options, mockBuilderContext);\n\n      expect(mockedTargetFromTargetString).toHaveBeenCalledWith('test-project:build:development');\n      expect(mockedLogger.info).toHaveBeenCalledWith(\n        'Using angular browser target options from \"test-project:build:development\"'\n      );\n      expect(mockBuilderContext.getTargetOptions).toHaveBeenCalledWith(mockTarget);\n    });\n\n    it('should merge browser target options with storybook options', async () => {\n      const mockTarget = { project: 'test-project', target: 'build' };\n      mockedTargetFromTargetString.mockReturnValue(mockTarget);\n\n      const browserTargetOptions = { a: 1, nested: { x: 10 } };\n      const storybookOptions = { b: 2, nested: { y: 20 } };\n\n      vi.mocked(mockBuilderContext.getTargetOptions)\n        .mockResolvedValueOnce(browserTargetOptions)\n        .mockResolvedValueOnce(storybookOptions);\n\n      const options: PresetOptions = {\n        configType: 'DEVELOPMENT',\n        configDir: '/test/config',\n        presets: {\n          apply: vi.fn(),\n        } as any,\n        angularBrowserTarget: 'test-project:build',\n        angularBuilderOptions: storybookOptions,\n        channel: new Channel({}),\n      };\n\n      const result = await getBuilderOptions(options, mockBuilderContext);\n\n      expect(result).toEqual({\n        a: 1,\n        b: 2,\n        nested: { x: 10, y: 20 },\n        tsConfig: '/test/tsconfig.json',\n      });\n    });\n\n    it('should use provided tsConfig when available', async () => {\n      const options: PresetOptions = {\n        configType: 'DEVELOPMENT',\n        configDir: '/test/config',\n        presets: {\n          apply: vi.fn(),\n        } as any,\n        tsConfig: '/custom/tsconfig.json',\n        channel: new Channel({}),\n      };\n\n      const result = await getBuilderOptions(options, mockBuilderContext);\n\n      expect(result.tsConfig).toBe('/custom/tsconfig.json');\n      expect(mockedLogger.info).toHaveBeenCalledWith(\n        'Using angular project with \"tsConfig:../../custom/tsconfig.json\"'\n      );\n    });\n\n    it('should find tsconfig.json when not provided', async () => {\n      const options: PresetOptions = {\n        configType: 'DEVELOPMENT',\n        configDir: '/test/config',\n        presets: {\n          apply: vi.fn(),\n        } as any,\n        channel: new Channel({}),\n      };\n\n      const result = await getBuilderOptions(options, mockBuilderContext);\n\n      expect(mockedFindUp).toHaveBeenCalledWith('tsconfig.json', {\n        cwd: '/test/config',\n        last: '/test/project',\n      });\n      expect(result.tsConfig).toBe('/test/tsconfig.json');\n    });\n\n    it('should use browser target tsConfig when no other tsConfig is available', async () => {\n      const mockTarget = { project: 'test-project', target: 'build' };\n      mockedTargetFromTargetString.mockReturnValue(mockTarget);\n      mockedFindUp.mockReturnValue(null);\n\n      const browserTargetOptions = { tsConfig: '/browser/tsconfig.json' };\n      vi.mocked(mockBuilderContext.getTargetOptions).mockResolvedValue(browserTargetOptions);\n\n      const options: PresetOptions = {\n        configType: 'DEVELOPMENT',\n        configDir: '/test/config',\n        presets: {\n          apply: vi.fn(),\n        } as any,\n        angularBrowserTarget: 'test-project:build',\n        channel: new Channel({}),\n      };\n\n      const result = await getBuilderOptions(options, mockBuilderContext);\n\n      expect(result.tsConfig).toBe('/browser/tsconfig.json');\n    });\n\n    it('should handle case when no angularBrowserTarget is provided', async () => {\n      const options: PresetOptions = {\n        configType: 'DEVELOPMENT',\n        configDir: '/test/config',\n        presets: {\n          apply: vi.fn(),\n        } as any,\n        channel: new Channel({}),\n      };\n\n      const result = await getBuilderOptions(options, mockBuilderContext);\n\n      expect(mockedTargetFromTargetString).not.toHaveBeenCalled();\n      expect(mockBuilderContext.getTargetOptions).toHaveBeenCalledOnce();\n      expect(result).toEqual({\n        tsConfig: '/test/tsconfig.json',\n      });\n    });\n\n    it('should handle browser target without configuration', async () => {\n      const mockTarget = { project: 'test-project', target: 'build' };\n      mockedTargetFromTargetString.mockReturnValue(mockTarget);\n\n      const options: PresetOptions = {\n        configType: 'DEVELOPMENT',\n        configDir: '/test/config',\n        presets: {\n          apply: vi.fn(),\n        } as any,\n        angularBrowserTarget: 'test-project:build',\n        channel: new Channel({}),\n      };\n\n      const result = await getBuilderOptions(options, mockBuilderContext);\n\n      expect(mockedLogger.info).toHaveBeenCalledWith(\n        'Using angular browser target options from \"test-project:build\"'\n      );\n    });\n\n    it('should handle browser target with configuration', async () => {\n      const mockTarget = { project: 'test-project', target: 'build', configuration: 'production' };\n      mockedTargetFromTargetString.mockReturnValue(mockTarget);\n\n      const options: PresetOptions = {\n        configType: 'DEVELOPMENT',\n        configDir: '/test/config',\n        presets: {\n          apply: vi.fn(),\n        } as any,\n        angularBrowserTarget: 'test-project:build:production',\n        channel: new Channel({}),\n      };\n\n      const result = await getBuilderOptions(options, mockBuilderContext);\n\n      expect(mockedLogger.info).toHaveBeenCalledWith(\n        'Using angular browser target options from \"test-project:build:production\"'\n      );\n    });\n\n    it('should handle empty angularBuilderOptions', async () => {\n      const mockTarget = { project: 'test-project', target: 'build' };\n      mockedTargetFromTargetString.mockReturnValue(mockTarget);\n\n      const browserTargetOptions = { a: 1, b: 2 };\n      vi.mocked(mockBuilderContext.getTargetOptions).mockResolvedValue(browserTargetOptions);\n\n      const options: PresetOptions = {\n        configType: 'DEVELOPMENT',\n        configDir: '/test/config',\n        presets: {\n          apply: vi.fn(),\n        } as any,\n        angularBrowserTarget: 'test-project:build',\n        angularBuilderOptions: {},\n        channel: new Channel({}),\n      };\n\n      const result = await getBuilderOptions(options, mockBuilderContext);\n\n      expect(result).toEqual({\n        a: 1,\n        b: 2,\n        tsConfig: '/test/tsconfig.json',\n      });\n    });\n\n    it('should handle undefined angularBuilderOptions', async () => {\n      const mockTarget = { project: 'test-project', target: 'build' };\n      mockedTargetFromTargetString.mockReturnValue(mockTarget);\n\n      const browserTargetOptions = { a: 1, b: 2 };\n      vi.mocked(mockBuilderContext.getTargetOptions).mockResolvedValue(browserTargetOptions);\n\n      const options: PresetOptions = {\n        configType: 'DEVELOPMENT',\n        configDir: '/test/config',\n        presets: {\n          apply: vi.fn(),\n        } as any,\n        angularBrowserTarget: 'test-project:build',\n        channel: new Channel({}),\n      };\n\n      const result = await getBuilderOptions(options, mockBuilderContext);\n\n      expect(result).toEqual({\n        a: 1,\n        b: 2,\n        tsConfig: '/test/tsconfig.json',\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/frameworks/angular/src/server/framework-preset-angular-cli.ts",
    "content": "import { logger } from 'storybook/internal/node-logger';\nimport { AngularLegacyBuildOptionsError } from 'storybook/internal/server-errors';\n\nimport type { BuilderContext } from '@angular-devkit/architect';\nimport { targetFromTargetString } from '@angular-devkit/architect';\nimport type { JsonObject } from '@angular-devkit/core';\nimport { logging } from '@angular-devkit/core';\nimport * as find from 'empathic/find';\nimport type webpack from 'webpack';\n\nimport type { PresetOptions } from './preset-options.ts';\nimport { getProjectRoot, resolvePackageDir } from 'storybook/internal/common';\nimport { relative } from 'pathe';\n\nexport async function webpackFinal(baseConfig: webpack.Configuration, options: PresetOptions) {\n  if (!resolvePackageDir('@angular-devkit/build-angular')) {\n    logger.info('Using base config because \"@angular-devkit/build-angular\" is not installed');\n    return baseConfig;\n  }\n\n  const { WebpackDefinePlugin, WebpackIgnorePlugin } = await import('@storybook/builder-webpack5');\n  const { getWebpackConfig: getCustomWebpackConfig } = await import('./angular-cli-webpack.js');\n\n  checkForLegacyBuildOptions(options);\n\n  const builderContext = getBuilderContext(options);\n  const builderOptions = await getBuilderOptions(options, builderContext);\n\n  const webpackConfig = await getCustomWebpackConfig(baseConfig, {\n    builderOptions: {\n      watch: options.configType === 'DEVELOPMENT',\n      ...builderOptions,\n    } as any,\n    builderContext,\n  });\n\n  webpackConfig.plugins = webpackConfig.plugins ?? [];\n\n  // Change the generated css filename to include the contenthash for cache busting\n  const miniCssPlugin = webpackConfig?.plugins?.find(\n    (plugin: any) => plugin?.constructor?.name === 'MiniCssExtractPlugin'\n  ) as any;\n\n  if (miniCssPlugin && 'options' in miniCssPlugin) {\n    miniCssPlugin.options.filename = '[name].[contenthash].css';\n    miniCssPlugin.options.chunkFilename = '[name].iframe.[contenthash].css';\n  }\n\n  webpackConfig.plugins.push(\n    new WebpackDefinePlugin({\n      STORYBOOK_ANGULAR_OPTIONS: JSON.stringify({\n        experimentalZoneless: builderOptions.experimentalZoneless,\n      }),\n    })\n  );\n\n  try {\n    resolvePackageDir('@angular/animations');\n  } catch (e) {\n    webpackConfig.plugins.push(\n      new WebpackIgnorePlugin({\n        resourceRegExp: /@angular\\/platform-browser\\/animations$/,\n      })\n    );\n    webpackConfig.plugins.push(\n      new WebpackIgnorePlugin({\n        resourceRegExp: /@angular\\/animations\\/browser$/,\n      })\n    );\n  }\n\n  return webpackConfig;\n}\n\n/** Get Builder Context If storybook is not start by angular builder create dumb BuilderContext */\nfunction getBuilderContext(options: PresetOptions): BuilderContext {\n  return (\n    options.angularBuilderContext ??\n    ({\n      target: { project: 'noop-project', builder: '', options: {} },\n      workspaceRoot: process.cwd(),\n      getProjectMetadata: () => ({}),\n      getTargetOptions: () => ({}),\n      logger: new logging.Logger('Storybook'),\n    } as unknown as BuilderContext)\n  );\n}\n\n/**\n * Deep merge function that properly handles nested objects. Preserves arrays and objects from\n * source when they exist in target\n *\n * @internal - exported for testing purposes\n */\nexport function deepMerge(target: JsonObject, source: JsonObject): JsonObject {\n  const result = { ...target };\n\n  for (const key in source) {\n    if (source[key] !== undefined && source[key] !== null) {\n      if (\n        typeof source[key] === 'object' &&\n        !Array.isArray(source[key]) &&\n        typeof target[key] === 'object' &&\n        !Array.isArray(target[key]) &&\n        target[key] !== null\n      ) {\n        // Deep merge nested objects\n        result[key] = deepMerge(target[key] as JsonObject, source[key] as JsonObject);\n      } else {\n        // Override with source value\n        result[key] = source[key];\n      }\n    }\n  }\n\n  return result;\n}\n\n/** Get builder options Merge target options from browser target and from storybook options */\nexport async function getBuilderOptions(options: PresetOptions, builderContext: BuilderContext) {\n  /** Get Browser Target options */\n  let browserTargetOptions: JsonObject = {};\n  if (options.angularBrowserTarget) {\n    const browserTarget = targetFromTargetString(options.angularBrowserTarget);\n\n    logger.info(\n      `Using angular browser target options from \"${browserTarget.project}:${\n        browserTarget.target\n      }${browserTarget.configuration ? `:${browserTarget.configuration}` : ''}\"`\n    );\n    browserTargetOptions = await builderContext.getTargetOptions(browserTarget);\n  }\n\n  // `options.angularBuilderOptions` implicitly adds all options a target can have\n  // To figure out what user-land actually has explicitly defined in their target options, we\n  // manually need to read them\n  const explicitAngularBuilderOptions = await builderContext.getTargetOptions(\n    builderContext.target\n  );\n\n  /**\n   * Merge target options from browser target options and from storybook options Use deep merge to\n   * preserve nested properties like stylePreprocessorOptions.includePaths when they exist in\n   * browserTarget but not in storybook options\n   */\n  const builderOptions = deepMerge(browserTargetOptions, explicitAngularBuilderOptions || {});\n\n  // Handle tsConfig separately to maintain existing logic\n  builderOptions.tsConfig =\n    options.tsConfig ??\n    find.up('tsconfig.json', { cwd: options.configDir, last: getProjectRoot() }) ??\n    browserTargetOptions.tsConfig;\n  logger.info(\n    `Using angular project with \"tsConfig:${relative(getProjectRoot(), builderOptions.tsConfig as string)}\"`\n  );\n\n  builderOptions.experimentalZoneless = options.angularBuilderOptions?.experimentalZoneless;\n\n  return builderOptions;\n}\n\n/**\n * Checks if using legacy configuration that doesn't use builder and logs message referring to\n * migration docs.\n */\nfunction checkForLegacyBuildOptions(options: PresetOptions) {\n  if (options.angularBrowserTarget !== undefined) {\n    // Not use legacy way with builder (`angularBrowserTarget` is defined or null with builder and undefined without)\n    return;\n  }\n\n  throw new AngularLegacyBuildOptionsError();\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/framework-preset-angular-ivy.ts",
    "content": "import { join } from 'node:path';\n\nimport type { Preset } from 'storybook/internal/types';\n\nimport type { Configuration } from 'webpack';\n\nimport type { AngularOptions } from '../types.ts';\nimport type { PresetOptions } from './preset-options.ts';\nimport { createRequire } from 'node:module';\n\nconst require = createRequire(import.meta.url);\n\n/**\n * Source :\n * https://github.com/angular/angular-cli/blob/ebccb5de4a455af813c5e82483db6af20666bdbd/packages/angular_devkit/build_angular/src/utils/load-esm.ts#L23\n * This uses a dynamic import to load a module which may be ESM. CommonJS code can load ESM code via\n * a dynamic import. Unfortunately, TypeScript will currently, unconditionally downlevel dynamic\n * import into a require call. require calls cannot load ESM code and will result in a runtime\n * error. To workaround this, a Function constructor is used to prevent TypeScript from changing the\n * dynamic import. Once TypeScript provides support for keeping the dynamic import this workaround\n * can be dropped.\n *\n * @param modulePath The path of the module to load.\n * @returns A Promise that resolves to the dynamically imported module.\n */\nfunction loadEsmModule<T>(modulePath: string): Promise<T> {\n  // eslint-disable-next-line @typescript-eslint/no-implied-eval\n  return new Function('modulePath', `return import(modulePath);`)(modulePath) as Promise<T>;\n}\n\n/**\n * Run ngcc for converting modules to ivy format before starting storybook This step is needed in\n * order to support Ivy in storybook\n *\n * Information about Ivy can be found here https://angular.io/guide/ivy\n */\nexport const runNgcc = async () => {\n  let ngcc: any;\n  try {\n    ngcc = require('@angular/compiler-cli/ngcc');\n  } catch (error) {\n    ngcc = await loadEsmModule('@angular/compiler-cli/ngcc');\n  }\n\n  ngcc.process({\n    // should be async: true but does not work due to\n    // https://github.com/storybookjs/storybook/pull/11157/files#r615413803\n    async: false,\n    basePath: join(process.cwd(), 'node_modules'), // absolute path to node_modules\n    createNewEntryPointFormats: true, // --create-ivy-entry-points\n    compileAllFormats: false, // --first-only\n  });\n};\n\nexport const webpack = async (webpackConfig: Configuration, options: PresetOptions) => {\n  const framework = await options.presets.apply<Preset>('framework');\n  const angularOptions = (typeof framework === 'object' ? framework.options : {}) as AngularOptions;\n\n  // Default to true, if undefined\n  if (angularOptions.enableIvy === false) {\n    return webpackConfig;\n  }\n\n  return {\n    ...webpackConfig,\n    resolve: {\n      ...webpackConfig.resolve,\n      mainFields: ['browser', 'module', 'main'],\n    },\n  };\n};\n"
  },
  {
    "path": "code/frameworks/angular/src/server/plugins/storybook-normalize-angular-entry-plugin.js",
    "content": "const PLUGIN_NAME = 'storybook-normalize-angular-entry-plugin';\n/**\n * This plugin is designed to modify the Webpack configuration for Storybook projects that use\n * Angular, specifically to prevent multiple runtime bundle issues by merging 'main' and 'styles'\n * entry points. It ensures that only one runtime bundle is generated to avoid\n * '**webpack_require**.nmd is not a function' errors.\n */\n\nexport default class StorybookNormalizeAngularEntryPlugin {\n  constructor(options) {\n    this.options = options; // Store options if future configuration is needed\n  }\n\n  apply(compiler) {\n    compiler.hooks.environment.tap(PLUGIN_NAME, () => {\n      // Store the original entry configuration\n      const originalEntry = compiler.options.entry;\n\n      // Overwrite the entry configuration to normalize it\n      compiler.options.entry = async () => {\n        let entryResult;\n\n        // Handle the case where the original entry is a function, which could be async\n        if (typeof originalEntry === 'function') {\n          try {\n            // Execute the function and await its result, in case it returns a promise\n            entryResult = await originalEntry();\n          } catch (error) {\n            // Log the error and re-throw it to ensure it's visible and doesn't silently fail\n            console.error('Failed to execute the entry function:', error);\n            throw error;\n          }\n        } else {\n          // If the original entry is not a function, use it as is\n          entryResult = originalEntry;\n        }\n\n        // Merge 'main' and 'styles' entries if both exist\n        if (entryResult && entryResult.main && entryResult.styles) {\n          // Combine and deduplicate imports from 'main' and 'styles'\n          return {\n            main: {\n              import: Array.from(\n                new Set([...entryResult.main.import, ...entryResult.styles.import])\n              ),\n            },\n          };\n        }\n\n        // If not both 'main' and 'styles' are present, return the original or resolved entry result\n        return entryResult;\n      };\n    });\n\n    compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {\n      this.compilation = compilation;\n    });\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/server/preset-options.ts",
    "content": "import type { Options as CoreOptions } from 'storybook/internal/types';\n\nimport type { BuilderContext } from '@angular-devkit/architect';\nimport type { StandaloneOptions } from '../builders/utils/standalone-options.ts';\n\nexport type PresetOptions = CoreOptions & {\n  /* Allow to get the options of a targeted \"browser builder\"  */\n  angularBrowserTarget?: string | null;\n  /* Defined set of options. These will take over priority from angularBrowserTarget options  */\n  angularBuilderOptions?: StandaloneOptions['angularBuilderOptions'];\n  /* Angular context from builder */\n  angularBuilderContext?: BuilderContext | null;\n  tsConfig?: string;\n};\n"
  },
  {
    "path": "code/frameworks/angular/src/server/utils/filter-out-styling-rules.ts",
    "content": "import type { Configuration, RuleSetRule } from 'webpack';\n\nconst isStylingRule = (rule: RuleSetRule) => {\n  const { test } = rule;\n\n  if (!test) {\n    return false;\n  }\n\n  if (!(test instanceof RegExp)) {\n    return false;\n  }\n\n  return test.test('.css') || test.test('.scss') || test.test('.sass');\n};\n\nexport const filterOutStylingRules = (config: Configuration) => {\n  return (config.module.rules as RuleSetRule[]).filter((rule) => !isStylingRule(rule));\n};\n"
  },
  {
    "path": "code/frameworks/angular/src/test-setup.ts",
    "content": "import '@analogjs/vite-plugin-angular/setup-vitest';\nimport { getTestBed } from '@angular/core/testing';\nimport {\n  BrowserDynamicTestingModule,\n  platformBrowserDynamicTesting,\n} from '@angular/platform-browser-dynamic/testing';\n\ngetTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());\n"
  },
  {
    "path": "code/frameworks/angular/src/types.ts",
    "content": "import type { CompatibleString } from 'storybook/internal/types';\n\nimport type {\n  BuilderOptions,\n  StorybookConfigWebpack,\n  TypescriptOptions as TypescriptOptionsBuilder,\n} from '@storybook/builder-webpack5';\nimport type {\n  StorybookConfig as StorybookConfigBase,\n  TypescriptOptions as TypescriptOptionsReact,\n} from '@storybook/core-webpack';\n\ntype FrameworkName = CompatibleString<'@storybook/angular'>;\ntype BuilderName = CompatibleString<'@storybook/builder-webpack5'>;\n\nexport type FrameworkOptions = AngularOptions & {\n  builder?: BuilderOptions;\n};\n\ntype StorybookConfigFramework = {\n  framework:\n    | FrameworkName\n    | {\n        name: FrameworkName;\n        options: FrameworkOptions;\n      };\n  core?: StorybookConfigBase['core'] & {\n    builder?:\n      | BuilderName\n      | {\n          name: BuilderName;\n          options: BuilderOptions;\n        };\n  };\n  typescript?: Partial<TypescriptOptionsBuilder & TypescriptOptionsReact> &\n    StorybookConfigBase['typescript'];\n};\n\n/** The interface for Storybook configuration in `main.ts` files. */\nexport type StorybookConfig = Omit<\n  StorybookConfigBase,\n  keyof StorybookConfigWebpack | keyof StorybookConfigFramework\n> &\n  StorybookConfigWebpack &\n  StorybookConfigFramework;\n\nexport interface AngularOptions {\n  enableIvy?: boolean;\n}\n"
  },
  {
    "path": "code/frameworks/angular/src/typings.d.ts",
    "content": "// will be provided by the webpack define plugin\ndeclare var NODE_ENV: string | undefined;\n\ndeclare var __STORYBOOK_ADDONS_CHANNEL__: any;\ndeclare var __STORYBOOK_ADDONS_PREVIEW: any;\ndeclare var __STORYBOOK_COMPODOC_JSON__: any;\ndeclare var __STORYBOOK_PREVIEW__: any;\ndeclare var __STORYBOOK_STORY_STORE__: any;\ndeclare var CHANNEL_OPTIONS: any;\ndeclare var DOCS_OPTIONS: any;\n\ndeclare var FEATURES: import('storybook/internal/types').StorybookConfigRaw['features'];\n\ndeclare var IS_STORYBOOK: any;\ndeclare var LOGLEVEL: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent' | undefined;\ndeclare var STORIES: any;\ndeclare var STORYBOOK_ENV: 'angular';\ndeclare var STORYBOOK_HOOKS_CONTEXT: any;\n"
  },
  {
    "path": "code/frameworks/angular/start-schema.json",
    "content": "{\n  \"$schema\": \"http://json-schema.org/schema\",\n  \"title\": \"Start Storybook\",\n  \"description\": \"Serve up storybook in development mode.\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"browserTarget\": {\n      \"type\": \"string\",\n      \"description\": \"Build target to be served in project-name:builder:config format. Should generally target on the builder: '@angular-devkit/build-angular:browser'. Useful for Storybook to use options (styles, assets, ...).\",\n      \"pattern\": \"^[^:\\\\s]+:[^:\\\\s]+(:[^\\\\s]+)?$\"\n    },\n    \"debugWebpack\": {\n      \"type\": \"boolean\",\n      \"description\": \"Debug the Webpack configuration\",\n      \"default\": false\n    },\n    \"tsConfig\": {\n      \"type\": \"string\",\n      \"description\": \"The full path for the TypeScript configuration file, relative to the current workspace.\"\n    },\n    \"preserveSymlinks\": {\n      \"type\": \"boolean\",\n      \"description\": \"Do not use the real path when resolving modules. If true, symlinks are resolved to their real path, if false, symlinks are resolved to their symlinked path.\",\n      \"default\": false\n    },\n    \"port\": {\n      \"type\": \"number\",\n      \"description\": \"Port to listen on.\",\n      \"default\": 9009\n    },\n    \"host\": {\n      \"type\": \"string\",\n      \"description\": \"Host to listen on.\",\n      \"default\": \"localhost\"\n    },\n    \"configDir\": {\n      \"type\": \"string\",\n      \"description\": \"Directory where to load Storybook configurations from.\",\n      \"default\": \".storybook\"\n    },\n    \"https\": {\n      \"type\": \"boolean\",\n      \"description\": \"Serve Storybook over HTTPS. Note: You must provide your own certificate information.\",\n      \"default\": false\n    },\n    \"sslCa\": {\n      \"type\": \"string\",\n      \"description\": \"Provide an SSL certificate authority. (Optional with --https, required if using a self-signed certificate).\"\n    },\n    \"sslCert\": {\n      \"type\": \"string\",\n      \"description\": \"Provide an SSL certificate. (Required with --https).\"\n    },\n    \"sslKey\": {\n      \"type\": \"string\",\n      \"description\": \"SSL key to use for serving HTTPS.\"\n    },\n    \"smokeTest\": {\n      \"type\": \"boolean\",\n      \"description\": \"Exit after successful start.\",\n      \"default\": false\n    },\n    \"ci\": {\n      \"type\": \"boolean\",\n      \"description\": \"CI mode (skip interactive prompts, don't open browser).\",\n      \"default\": false\n    },\n    \"open\": {\n      \"type\": \"boolean\",\n      \"description\": \"Whether to open Storybook automatically in the browser.\",\n      \"default\": true\n    },\n    \"quiet\": {\n      \"type\": \"boolean\",\n      \"description\": \"Suppress verbose build output.\",\n      \"default\": false\n    },\n    \"enableProdMode\": {\n      \"type\": \"boolean\",\n      \"description\": \"Disable Angular's development mode, which turns off assertions and other checks within the framework.\",\n      \"default\": false\n    },\n    \"docs\": {\n      \"type\": \"boolean\",\n      \"description\": \"Starts Storybook in documentation mode. Learn more about it : https://storybook.js.org/docs/writing-docs/build-documentation#preview-storybooks-documentation.\",\n      \"default\": false\n    },\n    \"compodoc\": {\n      \"type\": \"boolean\",\n      \"description\": \"Execute compodoc before.\",\n      \"default\": true\n    },\n    \"compodocArgs\": {\n      \"type\": \"array\",\n      \"description\": \"Compodoc options : https://compodoc.app/guides/options.html. Options `-p` with tsconfig path and `-d` with workspace root is always given.\",\n      \"default\": [\"-e\", \"json\"],\n      \"items\": {\n        \"type\": \"string\"\n      }\n    },\n    \"styles\": {\n      \"type\": \"array\",\n      \"description\": \"Global styles to be included in the build.\",\n      \"items\": {\n        \"$ref\": \"#/definitions/styleElement\"\n      }\n    },\n    \"stylePreprocessorOptions\": {\n      \"description\": \"Options to pass to style preprocessors.\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"includePaths\": {\n          \"description\": \"Paths to include. Paths will be resolved to workspace root.\",\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        }\n      },\n      \"additionalProperties\": false\n    },\n    \"assets\": {\n      \"type\": \"array\",\n      \"description\": \"List of static application assets.\",\n      \"default\": [],\n      \"items\": {\n        \"$ref\": \"#/definitions/assetPattern\"\n      }\n    },\n    \"initialPath\": {\n      \"type\": \"string\",\n      \"description\": \"URL path to be appended when visiting Storybook for the first time\"\n    },\n    \"webpackStatsJson\": {\n      \"type\": [\"boolean\", \"string\"],\n      \"description\": \"Write Webpack Stats JSON to disk\",\n      \"default\": false\n    },\n    \"statsJson\": {\n      \"type\": [\"boolean\", \"string\"],\n      \"description\": \"Write stats JSON to disk\",\n      \"default\": false\n    },\n    \"previewUrl\": {\n      \"type\": \"string\",\n      \"description\": \"Disables the default storybook preview and lets you use your own\"\n    },\n    \"loglevel\": {\n      \"type\": \"string\",\n      \"description\": \"Controls level of logging during build. Can be one of: [trace, debug, info (default), warn, error, silent].\",\n      \"pattern\": \"(trace|debug|info|warn|error|silent)\"\n    },\n    \"logfile\": {\n      \"type\": \"string\",\n      \"description\": \"If provided, the log output will be written to the specified file path.\"\n    },\n    \"sourceMap\": {\n      \"type\": [\"boolean\", \"object\"],\n      \"description\": \"Configure sourcemaps. See: https://angular.io/guide/workspace-config#source-map-configuration\",\n      \"default\": false\n    },\n    \"experimentalZoneless\": {\n      \"type\": \"boolean\",\n      \"description\": \"Experimental: Use zoneless change detection.\"\n    }\n  },\n  \"additionalProperties\": false,\n  \"definitions\": {\n    \"assetPattern\": {\n      \"oneOf\": [\n        {\n          \"type\": \"object\",\n          \"properties\": {\n            \"followSymlinks\": {\n              \"type\": \"boolean\",\n              \"default\": false,\n              \"description\": \"Allow glob patterns to follow symlink directories. This allows subdirectories of the symlink to be searched.\"\n            },\n            \"glob\": {\n              \"type\": \"string\",\n              \"description\": \"The pattern to match.\"\n            },\n            \"input\": {\n              \"type\": \"string\",\n              \"description\": \"The input directory path in which to apply 'glob'. Defaults to the project root.\"\n            },\n            \"ignore\": {\n              \"description\": \"An array of globs to ignore.\",\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            },\n            \"output\": {\n              \"type\": \"string\",\n              \"description\": \"Absolute path within the output.\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"required\": [\"glob\", \"input\", \"output\"]\n        },\n        {\n          \"type\": \"string\"\n        }\n      ]\n    },\n    \"styleElement\": {\n      \"oneOf\": [\n        {\n          \"type\": \"object\",\n          \"properties\": {\n            \"input\": {\n              \"type\": \"string\",\n              \"description\": \"The file to include.\"\n            },\n            \"bundleName\": {\n              \"type\": \"string\",\n              \"pattern\": \"^[\\\\w\\\\-.]*$\",\n              \"description\": \"The bundle name for this extra entry point.\"\n            },\n            \"inject\": {\n              \"type\": \"boolean\",\n              \"description\": \"If the bundle will be referenced in the HTML file.\",\n              \"default\": true\n            }\n          },\n          \"additionalProperties\": false,\n          \"required\": [\"input\"]\n        },\n        {\n          \"type\": \"string\",\n          \"description\": \"The file to include.\"\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/cli/button.component.ts",
    "content": "import { CommonModule } from '@angular/common';\nimport { Component, Input, Output, EventEmitter } from '@angular/core';\n\n@Component({\n  selector: 'storybook-button',\n  standalone: true,\n  imports: [CommonModule],\n  template: ` <button\n  type=\"button\"\n  (click)=\"onClick.emit($event)\"\n  [ngClass]=\"classes\"\n  [ngStyle]=\"{ 'background-color': backgroundColor }\"\n>\n  {{ label }}\n</button>`,\n  styleUrls: ['./button.css'],\n})\nexport class ButtonComponent {\n  /** Is this the principal call to action on the page? */\n  @Input()\n  primary = false;\n\n  /** What background color to use */\n  @Input()\n  backgroundColor?: string;\n\n  /** How large should the button be? */\n  @Input()\n  size: 'small' | 'medium' | 'large' = 'medium';\n\n  /**\n   * Button contents\n   *\n   * @required\n   */\n  @Input()\n  label = 'Button';\n\n  /** Optional click handler */\n  @Output()\n  onClick = new EventEmitter<Event>();\n\n  public get classes(): string[] {\n    const mode = this.primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n\n    return ['storybook-button', `storybook-button--${this.size}`, mode];\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/cli/button.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\nimport { fn } from 'storybook/test';\n\nimport { ButtonComponent } from './button.component';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories\nconst meta: Meta<ButtonComponent> = {\n  title: 'Example/Button',\n  component: ButtonComponent,\n  tags: ['autodocs'],\n  argTypes: {\n    backgroundColor: {\n      control: 'color',\n    },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onClick: fn() },\n};\n\nexport default meta;\ntype Story = StoryObj<ButtonComponent>;\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large: Story = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small: Story = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/cli/header.component.ts",
    "content": "import { Component, Input, Output, EventEmitter } from '@angular/core';\nimport { CommonModule } from '@angular/common';\n\nimport { ButtonComponent } from './button.component';\nimport type { User } from './user';\n\n@Component({\n  selector: 'storybook-header',\n  standalone: true,\n  imports: [CommonModule, ButtonComponent],\n  template: `<header>\n  <div class=\"storybook-header\">\n    <div>\n      <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n        <g fill=\"none\" fillRule=\"evenodd\">\n          <path\n            d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n            fill=\"#FFF\"\n          />\n          <path\n            d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n            fill=\"#555AB9\"\n          />\n          <path d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\" fill=\"#91BAF8\" />\n        </g>\n      </svg>\n      <h1>Acme</h1>\n    </div>\n    <div>\n      <div *ngIf=\"user\">\n        <span class=\"welcome\">\n          Welcome, <b>{{ user.name }}</b\n          >!\n        </span>\n        <storybook-button\n          *ngIf=\"user\"\n          size=\"small\"\n          (onClick)=\"onLogout.emit($event)\"\n          label=\"Log out\"\n        ></storybook-button>\n      </div>\n      <div *ngIf=\"!user\">\n        <storybook-button\n          *ngIf=\"!user\"\n          size=\"small\"\n          class=\"margin-left\"\n          (onClick)=\"onLogin.emit($event)\"\n          label=\"Log in\"\n        ></storybook-button>\n        <storybook-button\n          *ngIf=\"!user\"\n          size=\"small\"\n          [primary]=\"true\"\n          class=\"margin-left\"\n          (onClick)=\"onCreateAccount.emit($event)\"\n          label=\"Sign up\"\n        ></storybook-button>\n      </div>\n    </div>\n  </div>\n</header>`,\n  styleUrls: ['./header.css'],\n})\nexport class HeaderComponent {\n  @Input()\n  user: User | null = null;\n\n  @Output()\n  onLogin = new EventEmitter<Event>();\n\n  @Output()\n  onLogout = new EventEmitter<Event>();\n\n  @Output()\n  onCreateAccount = new EventEmitter<Event>();\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/cli/header.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\nimport { fn } from 'storybook/test';\n\nimport { HeaderComponent } from './header.component';\n\nconst meta: Meta<HeaderComponent> = {\n  title: 'Example/Header',\n  component: HeaderComponent,\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<HeaderComponent>;\n\nexport const LoggedIn: Story = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut: Story = {};\n"
  },
  {
    "path": "code/frameworks/angular/template/cli/page.component.ts",
    "content": "import { Component } from '@angular/core';\nimport { CommonModule } from '@angular/common';\n\nimport { HeaderComponent } from './header.component';\nimport type { User } from './user';\n\n@Component({\n  selector: 'storybook-page',\n  standalone: true,\n  imports: [CommonModule, HeaderComponent],\n  template: `<article>\n  <storybook-header\n    [user]=\"user\"\n    (onLogout)=\"doLogout()\"\n    (onLogin)=\"doLogin()\"\n    (onCreateAccount)=\"doCreateAccount()\"\n  ></storybook-header>\n  <section class=\"storybook-page\">\n    <h2>Pages in Storybook</h2>\n    <p>\n      We recommend building UIs with a\n      <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n        <strong>component-driven</strong>\n      </a>\n      process starting with atomic components and ending with pages.\n    </p>\n    <p>\n      Render pages with mock data. This makes it easy to build and review page states without\n      needing to navigate to them in your app. Here are some handy patterns for managing page data\n      in Storybook:\n    </p>\n    <ul>\n      <li>\n        Use a higher-level connected component. Storybook helps you compose such data from the\n        \"args\" of child component stories\n      </li>\n      <li>\n        Assemble data in the page component from your services. You can mock these services out\n        using Storybook.\n      </li>\n    </ul>\n    <p>\n      Get a guided tutorial on component-driven development at\n      <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n        Storybook tutorials\n      </a>\n      . Read more in the\n      <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\"> docs </a>\n      .\n    </p>\n    <div class=\"tip-wrapper\">\n      <span class=\"tip\">Tip</span> Adjust the width of the canvas with the\n      <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n        <g fill=\"none\" fillRule=\"evenodd\">\n          <path\n            d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n            id=\"a\"\n            fill=\"#999\"\n          />\n        </g>\n      </svg>\n      Viewports addon in the toolbar\n    </div>\n  </section>\n</article>`,\n  styleUrls: ['./page.css'],\n})\nexport class PageComponent {\n  user: User | null = null;\n\n  doLogout() {\n    this.user = null;\n  }\n\n  doLogin() {\n    this.user = { name: 'Jane Doe' };\n  }\n\n  doCreateAccount() {\n    this.user = { name: 'Jane Doe' };\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/cli/page.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\nimport { expect, userEvent, within } from 'storybook/test';\n\nimport { PageComponent } from './page.component';\n\nconst meta: Meta<PageComponent> = {\n  title: 'Example/Page',\n  component: PageComponent,\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<PageComponent>;\n\nexport const LoggedOut: Story = {};\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn: Story = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await expect(loginButton).not.toBeInTheDocument();\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/cli/user.ts",
    "content": "export interface User {\n  name: string;\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/components/button.component.ts",
    "content": "import { Component, Input, Output, EventEmitter } from '@angular/core';\n\n@Component({\n  standalone: false,\n  // Needs to be a different name to the CLI template button\n  selector: 'storybook-framework-button',\n  template: ` <button\n  type=\"button\"\n  (click)=\"onClick.emit($event)\"\n  [ngClass]=\"classes\"\n  [ngStyle]=\"{ 'background-color': backgroundColor }\"\n>\n  {{ label }}\n</button>`,\n  styleUrls: ['./button.css'],\n})\nexport default class FrameworkButtonComponent {\n  /** Is this the principal call to action on the page? */\n  @Input()\n  primary = false;\n\n  /** What background color to use */\n  @Input()\n  backgroundColor?: string;\n\n  /** How large should the button be? */\n  @Input()\n  size: 'small' | 'medium' | 'large' = 'medium';\n\n  /**\n   * Button contents\n   *\n   * @required\n   */\n  @Input()\n  label = 'Button';\n\n  /** Optional click handler */\n  @Output()\n  onClick = new EventEmitter<Event>();\n\n  public get classes(): string[] {\n    const mode = this.primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n\n    return ['storybook-button', `storybook-button--${this.size}`, mode];\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/components/button.css",
    "content": ".storybook-button {\n  display: inline-block;\n  cursor: pointer;\n  border: 0;\n  border-radius: 3em;\n  font-weight: 700;\n  line-height: 1;\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n.storybook-button--primary {\n  background-color: #555ab9;\n  color: white;\n}\n.storybook-button--secondary {\n  box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;\n  background-color: transparent;\n  color: #333;\n}\n.storybook-button--small {\n  padding: 10px 16px;\n  font-size: 12px;\n}\n.storybook-button--medium {\n  padding: 11px 20px;\n  font-size: 14px;\n}\n.storybook-button--large {\n  padding: 12px 24px;\n  font-size: 16px;\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/components/form.component.ts",
    "content": "import { Component, output, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\n@Component({\n  standalone: true,\n  imports: [FormsModule],\n  selector: 'storybook-form',\n  template: `\n    <form id=\"interaction-test-form\" ngNativeValidate (submit)=\"handleSubmit($event)\">\n  <label>\n    Enter Value\n    <input type=\"text\" data-testid=\"value\" name=\"value\" [(ngModel)]=\"value\" required />\n  </label>\n  <button type=\"submit\">Submit</button>\n  @if (complete()) {\n    <p>Completed!!</p>\n  }\n</form>\n  `,\n})\nexport default class FormComponent {\n  /** Optional success handler */\n  onSuccess = output<string>();\n\n  value = '';\n\n  complete = signal(false);\n\n  handleSubmit(event: SubmitEvent) {\n    event.preventDefault();\n    this.onSuccess.emit(this.value);\n    setTimeout(() => {\n      this.complete.set(true);\n    }, 500);\n    setTimeout(() => {\n      this.complete.set(false);\n    }, 1500);\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/components/html.component.ts",
    "content": "import { Component, Input } from '@angular/core';\n// DomSanitizer must be a regular import, not a type-only import, because it's used in dependency injection.\n// Type-only imports are stripped during compilation, causing runtime errors like \"DomSanitizer is not defined\".\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\nimport { DomSanitizer } from '@angular/platform-browser';\n@Component({\n  standalone: false,\n  selector: 'storybook-html',\n  template: `<div [innerHTML]=\"safeContent\"></div>`,\n})\nexport default class HtmlComponent {\n  /**\n   * The HTML to render\n   *\n   * @required\n   */\n  @Input()\n  content = '';\n\n  constructor(private sanitizer: DomSanitizer) {}\n\n  get safeContent() {\n    return this.sanitizer.bypassSecurityTrustHtml(this.content);\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/components/index.js",
    "content": "import Button from './button.component';\nimport Form from './form.component';\nimport Html from './html.component';\nimport Pre from './pre.component';\n\nglobalThis.__TEMPLATE_COMPONENTS__ = { Button, Html, Pre, Form };\n"
  },
  {
    "path": "code/frameworks/angular/template/components/pre.component.ts",
    "content": "import { Component, Input } from '@angular/core';\n\n@Component({\n  standalone: false,\n  selector: 'storybook-pre',\n  template: `<pre data-testid=\"pre\" [ngStyle]=\"style\">{{ finalText }}</pre>`,\n})\nexport default class PreComponent {\n  /** Styles to apply to the component */\n  @Input()\n  style?: object;\n\n  /** An object to render */\n  @Input()\n  object?: object;\n\n  /** The code to render */\n  @Input()\n  text?: string;\n\n  get finalText() {\n    return this.object ? JSON.stringify(this.object, null, 2) : this.text;\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/argTypes/doc-button/doc-button.component.html",
    "content": "<button [disabled]=\"isDisabled\" [ngClass]=\"classes\" #buttonRef>\n  <img\n    width=\"100\"\n    src=\"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxOS4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAyNTAgMjUwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyNTAgMjUwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDojREQwMDMxO30NCgkuc3Qxe2ZpbGw6I0MzMDAyRjt9DQoJLnN0MntmaWxsOiNGRkZGRkY7fQ0KPC9zdHlsZT4NCjxnPg0KCTxwb2x5Z29uIGNsYXNzPSJzdDAiIHBvaW50cz0iMTI1LDMwIDEyNSwzMCAxMjUsMzAgMzEuOSw2My4yIDQ2LjEsMTg2LjMgMTI1LDIzMCAxMjUsMjMwIDEyNSwyMzAgMjAzLjksMTg2LjMgMjE4LjEsNjMuMiAJIi8+DQoJPHBvbHlnb24gY2xhc3M9InN0MSIgcG9pbnRzPSIxMjUsMzAgMTI1LDUyLjIgMTI1LDUyLjEgMTI1LDE1My40IDEyNSwxNTMuNCAxMjUsMjMwIDEyNSwyMzAgMjAzLjksMTg2LjMgMjE4LjEsNjMuMiAxMjUsMzAgCSIvPg0KCTxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik0xMjUsNTIuMUw2Ni44LDE4Mi42aDBoMjEuN2gwbDExLjctMjkuMmg0OS40bDExLjcsMjkuMmgwaDIxLjdoMEwxMjUsNTIuMUwxMjUsNTIuMUwxMjUsNTIuMUwxMjUsNTIuMQ0KCQlMMTI1LDUyLjF6IE0xNDIsMTM1LjRIMTA4bDE3LTQwLjlMMTQyLDEzNS40eiIvPg0KPC9nPg0KPC9zdmc+DQo=\"\n  />\n  {{ label }}\n</button>\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/argTypes/doc-button/doc-button.component.scss",
    "content": ".btn-primary {\n  background-color: #ff9899;\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/argTypes/doc-button/doc-button.component.ts",
    "content": "import type { ElementRef } from '@angular/core';\nimport {\n  Component,\n  EventEmitter,\n  HostBinding,\n  HostListener,\n  Input,\n  Output,\n  ViewChild,\n} from '@angular/core';\n\nexport const exportedConstant = 'An exported constant';\n\nexport type ButtonSize = 'small' | 'medium' | 'large' | 'xlarge';\n\nexport interface ISomeInterface {\n  one: string;\n  two: boolean;\n  three: any[];\n}\n\nexport enum ButtonAccent {\n  'Normal' = 'Normal',\n  'High' = 'High',\n}\n\n/**\n * This is a simple button that demonstrates various JSDoc handling in Storybook Docs for Angular.\n *\n * It supports [markdown](https://en.wikipedia.org/wiki/Markdown), so you can embed formatted text,\n * like **bold**, _italic_, and `inline code`.> How you like dem apples?! It's never been easier to\n * document all your components.\n *\n * @string Hello world\n * @link [Example](http://example.com)\n * @code `ThingThing`\n * @html <span class=\"badge\">aaa</span>\n */\n@Component({\n  standalone: false,\n  selector: 'my-button',\n  templateUrl: './doc-button.component.html',\n  styleUrls: ['./doc-button.component.scss'],\n})\nexport class DocButtonComponent<T> {\n  @ViewChild('buttonRef', { static: false }) buttonRef!: ElementRef;\n\n  /** Test default value. */\n  @Input()\n  public theDefaultValue = 'Default value in component';\n\n  /**\n   * Setting default value here because compodoc won't get the default value for accessors\n   *\n   * @default Another default value\n   */\n  @Input()\n  get anotherDefaultValue() {\n    return this._anotherDefaultValue;\n  }\n\n  set anotherDefaultValue(v: string) {\n    this._anotherDefaultValue = v;\n  }\n\n  _anotherDefaultValue = 'Another default value';\n\n  /** Test null default value. */\n  @Input()\n  public aNullValue: string | null = null;\n\n  /** Test null default value. */\n  @Input()\n  public anUndefinedValue: undefined;\n\n  /** Test numeric default value. */\n  @Input()\n  public aNumericValue = 123;\n\n  /** Appearance style of the button. */\n  @Input()\n  public appearance: 'primary' | 'secondary' = 'secondary';\n\n  /** Sets the button to a disabled state. */\n  @Input()\n  public isDisabled = false;\n\n  /** Specify the accent-type of the button */\n  @Input()\n  public accent: ButtonAccent = ButtonAccent.Normal;\n\n  /**\n   * Specifies some arbitrary object. This comment is to test certain chars like apostrophes - it's\n   * working\n   */\n  @Input() public someDataObject!: ISomeInterface;\n\n  /**\n   * The inner text of the button.\n   *\n   * @required\n   */\n  @Input()\n  public label!: string;\n\n  /** Size of the button. */\n  @Input()\n  public size?: ButtonSize = 'medium';\n\n  /**\n   * Some input you shouldn't use.\n   *\n   * @deprecated\n   */\n  @Input()\n  public somethingYouShouldNotUse = false;\n\n  /**\n   * Handler to be called when the button is clicked by a user.\n   *\n   * Will also block the emission of the event if `isDisabled` is true.\n   */\n  @Output()\n  public onClick = new EventEmitter<Event>();\n\n  /**\n   * This is an internal method that we don't want to document and have added the `ignore`\n   * annotation to.\n   *\n   * @ignore\n   */\n  public handleClick(event: Event) {\n    event.stopPropagation();\n\n    if (!this.isDisabled) {\n      this.onClick.emit(event);\n    }\n  }\n\n  private _inputValue = 'some value';\n\n  /** Setter for `inputValue` that is also an `@Input`. */\n  @Input()\n  public set inputValue(value: string) {\n    this._inputValue = value;\n  }\n\n  /** Getter for `inputValue`. */\n  public get inputValue() {\n    return this._inputValue;\n  }\n\n  @HostListener('click', ['$event'])\n  onClickListener(event: Event) {\n    console.log('button', event.target);\n    this.handleClick(event);\n  }\n\n  @HostBinding('class.focused') focus = false;\n\n  /**\n   * Returns all the CSS classes for the button.\n   *\n   * @ignore\n   */\n  public get classes(): string[] {\n    return [this.appearance, this.size]\n      .filter((_class) => !!_class)\n      .map((_class) => `btn-${_class}`);\n  }\n\n  /** @ignore */\n  public ignoredProperty = 'Ignore me';\n\n  /** Public value. */\n  public internalProperty = 'Public hello';\n\n  /** Private value. */\n  private _value = 'Private hello';\n\n  /** Set the private value. */\n  public set value(value: string | number) {\n    this._value = `${value}`;\n  }\n\n  /** Get the private value. */\n  public get value(): string | number {\n    return this._value;\n  }\n\n  /**\n   * An internal calculation method which adds `x` and `y` together.\n   *\n   * @param x Some number you'd like to use.\n   * @param y Some other number or string you'd like to use, will have `parseInt()` applied before\n   *   calculation.\n   */\n  public calc(x: number, y: string | number): number {\n    return x + parseInt(`${y}`, 10);\n  }\n\n  /** A public method using an interface. */\n  public publicMethod(things: ISomeInterface) {\n    console.log(things);\n  }\n\n  /**\n   * A protected method.\n   *\n   * @param id Some `id`.\n   */\n  protected protectedMethod(id?: number) {\n    console.log(id);\n  }\n\n  /**\n   * A private method.\n   *\n   * @param password Some `password`.\n   */\n  private privateMethod(password: string) {\n    console.log(password);\n  }\n\n  @Input('showKeyAlias')\n  public showKey!: keyof T;\n\n  @Input()\n  public set item(item: T[]) {\n    this.processedItem = item;\n  }\n\n  public processedItem!: T[];\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/argTypes/doc-button/doc-button.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\nimport { argsToTemplate } from '@storybook/angular';\n\nimport { DocButtonComponent } from './doc-button.component';\n\nconst meta: Meta<DocButtonComponent<any>> = {\n  component: DocButtonComponent,\n};\n\nexport default meta;\n\ntype Story = StoryObj<DocButtonComponent<any>>;\n\nexport const Basic: Story = {\n  args: { label: 'Args test', isDisabled: false },\n  argTypes: {\n    theDefaultValue: {\n      table: {\n        defaultValue: { summary: 'Basic default value' },\n      },\n    },\n  },\n};\n\nexport const WithTemplate: Story = {\n  args: { label: 'Template test', appearance: 'primary' },\n  render: (args) => ({\n    props: args,\n    template: `<my-button ${argsToTemplate(args)}></my-button>`,\n  }),\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/argTypes/doc-directive/doc-directive.directive.ts",
    "content": "// ElementRef must be a regular import, not a type-only import, because it's used in dependency injection.\n// Type-only imports are stripped during compilation, causing runtime errors like \"ElementRef is not defined\".\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\nimport { ElementRef, AfterViewInit, Directive, Input } from '@angular/core';\n\n/** This is an Angular Directive example that has a Prop Table. */\n@Directive({\n  standalone: false,\n  selector: '[docDirective]',\n})\nexport class DocDirective implements AfterViewInit {\n  constructor(private ref: ElementRef) {}\n\n  /** Will apply gray background color if set to true. */\n  @Input() hasGrayBackground = false;\n\n  ngAfterViewInit(): void {\n    if (this.hasGrayBackground) {\n      this.ref.nativeElement.style = 'background-color: lightgray';\n    }\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/argTypes/doc-directive/doc-directive.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\n\nimport { DocDirective } from './doc-directive.directive';\n\nconst meta: Meta<DocDirective> = {\n  component: DocDirective,\n};\n\nexport default meta;\n\ntype Story = StoryObj<DocDirective>;\n\nexport const Basic: Story = {\n  render: () => ({\n    moduleMetadata: {\n      declarations: [DocDirective],\n    },\n    template: '<div docDirective [hasGrayBackground]=\"true\"><h1>DocDirective</h1></div>',\n  }),\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/argTypes/doc-injectable/doc-injectable.service.ts",
    "content": "import { Injectable } from '@angular/core';\nimport { HttpHeaders } from '@angular/common/http';\n\n/** This is an Angular Injectable example that has a Prop Table. */\n@Injectable({\n  providedIn: 'root',\n})\nexport class DocInjectableService {\n  /** Auth headers to use. */\n  auth: any;\n\n  constructor() {\n    this.auth = new HttpHeaders({ 'Content-Type': 'application/json' });\n  }\n\n  /** Get posts from Backend. */\n  getPosts(): unknown[] {\n    return [];\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/argTypes/doc-injectable/doc-injectable.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\n\nimport { DocInjectableService } from './doc-injectable.service';\n\nconst meta: Meta<DocInjectableService> = {\n  component: DocInjectableService,\n};\n\nexport default meta;\n\ntype Story = StoryObj<DocInjectableService>;\n\nexport const Basic: Story = {\n  render: () => ({\n    moduleMetadata: {\n      providers: [DocInjectableService],\n    },\n    template: '<div><h1>DocInjectable</h1></div>',\n  }),\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/argTypes/doc-pipe/doc-pipe.pipe.ts",
    "content": "import type { PipeTransform } from '@angular/core';\nimport { Pipe } from '@angular/core';\n\n/** This is an Angular Pipe example that has a Prop Table. */\n@Pipe({\n  standalone: false,\n  name: 'docPipe',\n})\nexport class DocPipe implements PipeTransform {\n  /**\n   * Transforms a string into uppercase.\n   *\n   * @param value String\n   */\n  transform(value: string): string {\n    return value?.toUpperCase();\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/argTypes/doc-pipe/doc-pipe.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\n\nimport { DocPipe } from './doc-pipe.pipe';\n\nconst meta: Meta<DocPipe> = {\n  component: DocPipe,\n};\n\nexport default meta;\n\ntype Story = StoryObj<DocPipe>;\n\nexport const Basic: Story = {\n  render: () => ({\n    moduleMetadata: {\n      declarations: [DocPipe],\n    },\n    template: `<div><h1>{{ 'DocPipe' | docPipe }}</h1></div>`,\n  }),\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/README.mdx",
    "content": "import { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"stories / frameworks / angular / basics / README\" />\n\n# Examples for Angular features\n\nThese examples serve to highlight the right Storybook operation for basics Angular features\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/angular-forms/customControlValueAccessor/custom-cva-component.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\nimport { StoryFn, moduleMetadata } from '@storybook/angular';\n\nimport { FormsModule } from '@angular/forms';\n\nimport { CustomCvaComponent } from './custom-cva.component';\n\nconst meta: Meta<CustomCvaComponent> = {\n  // title: 'Basics / Angular forms / ControlValueAccessor',\n  component: CustomCvaComponent,\n  decorators: [\n    moduleMetadata({\n      imports: [FormsModule],\n    }),\n    (storyFn) => {\n      const story = storyFn();\n      console.log(story);\n      return story;\n    },\n  ],\n} as Meta;\n\nexport default meta;\n\ntype Story = StoryObj<CustomCvaComponent>;\n\nexport const SimpleInput: Story = {\n  name: 'Simple input',\n  render: () => ({\n    props: {\n      ngModel: 'Type anything',\n      ngModelChange: () => {},\n    },\n  }),\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/angular-forms/customControlValueAccessor/custom-cva.component.ts",
    "content": "import { Component, forwardRef } from '@angular/core';\nimport type { ControlValueAccessor } from '@angular/forms';\nimport { NG_VALUE_ACCESSOR } from '@angular/forms';\n\nconst NOOP = () => {};\n\n@Component({\n  standalone: false,\n  selector: 'storybook-custom-cva-component',\n  template: ` <div>{{ value }}</div>\n<input type=\"text\" [(ngModel)]=\"value\" /> `,\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => CustomCvaComponent),\n      multi: true,\n    },\n  ],\n})\nexport class CustomCvaComponent implements ControlValueAccessor {\n  disabled?: boolean;\n\n  protected onChange: (value: any) => void = NOOP;\n\n  protected onTouch: () => void = NOOP;\n\n  protected internalValue: any;\n\n  get value(): any {\n    return this.internalValue;\n  }\n\n  set value(value: any) {\n    if (value !== this.internalValue) {\n      this.internalValue = value;\n      this.onChange(value);\n    }\n  }\n\n  writeValue(value: any): void {\n    if (value !== this.internalValue) {\n      this.internalValue = value;\n    }\n  }\n\n  registerOnChange(fn: any): void {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: any): void {\n    this.onTouch = fn;\n  }\n\n  setDisabledState(isDisabled: boolean): void {\n    this.disabled = isDisabled;\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-complex-selectors/attribute-selector.component.ts",
    "content": "// ElementRef must be a regular import, not a type-only import, because it's used in dependency injection.\n// Type-only imports are stripped during compilation, causing runtime errors like \"ElementRef is not defined\".\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\nimport { ComponentFactoryResolver, ElementRef, Component } from '@angular/core';\n\n@Component({\n  standalone: false,\n  selector: 'storybook-attribute-selector[foo=bar]',\n  template: `<h3>Attribute selector</h3>\nSelector: {{ selectors }} <br />\nGenerated template: {{ generatedTemplate }}`,\n})\nexport class AttributeSelectorComponent {\n  generatedTemplate!: string;\n\n  selectors!: string;\n\n  constructor(\n    public el: ElementRef,\n    private resolver: ComponentFactoryResolver\n  ) {\n    const factory = this.resolver.resolveComponentFactory(AttributeSelectorComponent);\n    this.selectors = factory.selector;\n    this.generatedTemplate = el.nativeElement.outerHTML;\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-complex-selectors/attribute-selectors.component.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\n\nimport { AttributeSelectorComponent } from './attribute-selector.component';\n\nconst meta: Meta<AttributeSelectorComponent> = {\n  // title: 'Basics / Component / With Complex Selectors',\n  component: AttributeSelectorComponent,\n};\n\nexport default meta;\n\ntype Story = StoryObj<AttributeSelectorComponent>;\n\nexport const AttributeSelectors: Story = {};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-complex-selectors/class-selector.component.stories.ts",
    "content": "import { ClassSelectorComponent } from './class-selector.component';\n\nexport default {\n  // title: 'Basics / Component / With Complex Selectors',\n  component: ClassSelectorComponent,\n};\n\nexport const ClassSelectors = {};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-complex-selectors/class-selector.component.ts",
    "content": "// ElementRef must be a regular import, not a type-only import, because it's used in dependency injection.\n// Type-only imports are stripped during compilation, causing runtime errors like \"ElementRef is not defined\".\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\nimport { ComponentFactoryResolver, ElementRef, Component } from '@angular/core';\n\n@Component({\n  standalone: false,\n  selector: 'storybook-class-selector.foo, storybook-class-selector.bar',\n  template: `<h3>Class selector</h3>\nSelector: {{ selectors }} <br />\nGenerated template: {{ generatedTemplate }}`,\n})\nexport class ClassSelectorComponent {\n  generatedTemplate!: string;\n\n  selectors!: string;\n\n  constructor(\n    public el: ElementRef,\n    private resolver: ComponentFactoryResolver\n  ) {\n    const factory = this.resolver.resolveComponentFactory(ClassSelectorComponent);\n    this.selectors = factory.selector;\n    this.generatedTemplate = el.nativeElement.outerHTML;\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-complex-selectors/multiple-class-selector.component.stories.ts",
    "content": "import { MultipleClassSelectorComponent } from './multiple-selector.component';\n\nexport default {\n  // title: 'Basics / Component / With Complex Selectors',\n  component: MultipleClassSelectorComponent,\n};\n\nexport const MultipleClassSelectors = {};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-complex-selectors/multiple-selector.component.stories.ts",
    "content": "import { MultipleSelectorComponent } from './multiple-selector.component';\n\nexport default {\n  // title: 'Basics / Component / With Complex Selectors',\n  component: MultipleSelectorComponent,\n};\n\nexport const MultipleSelectors = {};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-complex-selectors/multiple-selector.component.ts",
    "content": "// ElementRef must be a regular import, not a type-only import, because it's used in dependency injection.\n// Type-only imports are stripped during compilation, causing runtime errors like \"ElementRef is not defined\".\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\nimport { ComponentFactoryResolver, ElementRef, Component } from '@angular/core';\n\n@Component({\n  standalone: false,\n  selector: 'storybook-multiple-selector, storybook-multiple-selector2',\n  template: `<h3>Multiple selector</h3>\nSelector: {{ selectors }} <br />\nGenerated template: {{ generatedTemplate }}`,\n})\nexport class MultipleSelectorComponent {\n  generatedTemplate!: string;\n\n  selectors!: string;\n\n  constructor(\n    public el: ElementRef,\n    private resolver: ComponentFactoryResolver\n  ) {\n    const factory = this.resolver.resolveComponentFactory(MultipleClassSelectorComponent);\n    this.selectors = factory.selector;\n    this.generatedTemplate = el.nativeElement.outerHTML;\n  }\n}\n\n@Component({\n  standalone: false,\n  selector: 'storybook-button, button[foo], .button[foo], button[baz]',\n  template: `<h3>Multiple selector</h3>\nSelector: {{ selectors }} <br />\nGenerated template: {{ generatedTemplate }}`,\n})\nexport class MultipleClassSelectorComponent {\n  generatedTemplate!: string;\n\n  selectors!: string;\n\n  constructor(\n    public el: ElementRef,\n    private resolver: ComponentFactoryResolver\n  ) {\n    const factory = this.resolver.resolveComponentFactory(MultipleClassSelectorComponent);\n    this.selectors = factory.selector;\n    this.generatedTemplate = el.nativeElement.outerHTML;\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-enums/enums.component.html",
    "content": "<div>\n  <div>unionType: {{ unionType }}</div>\n  <div>aliasedUnionType: {{ aliasedUnionType }}</div>\n  <div>enumNumeric: {{ enumNumeric }}</div>\n  <div>enumNumericInitial: {{ enumNumericInitial }}</div>\n  <div>enumStrings: {{ enumStrings }}</div>\n  <div>enumAlias: {{ enumAlias }}</div>\n</div>\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-enums/enums.component.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\n\nimport {\n  EnumNumeric,\n  EnumNumericInitial,\n  EnumStringValues,\n  EnumsComponent,\n} from './enums.component';\n\nconst meta: Meta<EnumsComponent> = {\n  // title: 'Basics / Component / With Enum Types',\n  component: EnumsComponent,\n};\n\nexport default meta;\n\ntype Story = StoryObj<EnumsComponent>;\n\nexport const Basic: Story = {\n  args: {\n    unionType: 'Union A',\n    aliasedUnionType: 'Type Alias 1',\n    enumNumeric: EnumNumeric.FIRST,\n    enumNumericInitial: EnumNumericInitial.UNO,\n    enumStrings: EnumStringValues.PRIMARY,\n    enumAlias: EnumNumeric.FIRST,\n  },\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-enums/enums.component.ts",
    "content": "import { Component, Input } from '@angular/core';\n\n/** This component is used for testing the various forms of enum types */\n@Component({\n  standalone: false,\n  selector: 'app-enums',\n  templateUrl: './enums.component.html',\n})\nexport class EnumsComponent {\n  /** Union Type of string literals */\n  @Input() unionType?: 'Union A' | 'Union B' | 'Union C';\n\n  /** Union Type assigned as a Type Alias */\n  @Input() aliasedUnionType?: TypeAlias;\n\n  /** Base Enum Type with no assigned values */\n  @Input() enumNumeric?: EnumNumeric;\n\n  /** Enum with initial numeric value and auto-incrementing subsequent values */\n  @Input() enumNumericInitial?: EnumNumericInitial;\n\n  /** Enum with string values */\n  @Input() enumStrings?: EnumStringValues;\n\n  /** Type Aliased Enum Type */\n  @Input() enumAlias?: EnumAlias;\n}\n\n/** Button Priority */\nexport enum EnumNumeric {\n  FIRST,\n  SECOND,\n  THIRD,\n}\n\nexport enum EnumNumericInitial {\n  UNO = 1,\n  DOS,\n  TRES,\n}\n\nexport enum EnumStringValues {\n  PRIMARY = 'PRIMARY',\n  SECONDARY = 'SECONDARY',\n  TERTIARY = 'TERTIARY',\n}\n\nexport type EnumAlias = EnumNumeric;\n\ntype TypeAlias = 'Type Alias 1' | 'Type Alias 2' | 'Type Alias 3';\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-inheritance/base-button.component.ts",
    "content": "import { Component, Input } from '@angular/core';\n\n@Component({\n  standalone: false,\n  selector: `storybook-base-button`,\n  template: ` <button>{{ label }}</button> `,\n})\nexport class BaseButtonComponent {\n  @Input()\n  label?: string;\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-inheritance/base-button.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\n\nimport { BaseButtonComponent } from './base-button.component';\n\nconst meta: Meta<BaseButtonComponent> = {\n  // title: 'Basics / Component / With Inheritance',\n  component: BaseButtonComponent,\n};\n\nexport default meta;\n\nexport const BaseButton: StoryObj<BaseButtonComponent> = {\n  args: {\n    label: 'this is label',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-inheritance/icon-button.component.ts",
    "content": "import { Component, Input } from '@angular/core';\nimport { BaseButtonComponent } from './base-button.component';\n\n@Component({\n  standalone: false,\n  selector: `storybook-icon-button`,\n  template: ` <button>{{ label }} - {{ icon }}</button> `,\n})\nexport class IconButtonComponent extends BaseButtonComponent {\n  @Input()\n  icon?: string;\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-inheritance/icon-button.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\n\nimport { IconButtonComponent } from './icon-button.component';\n\nconst meta: Meta<IconButtonComponent> = {\n  // title: 'Basics / Component / With Inheritance',\n  component: IconButtonComponent,\n};\n\nexport default meta;\n\ntype Story = StoryObj<IconButtonComponent>;\n\nexport const IconButton: Story = {\n  args: {\n    icon: 'this is icon',\n    label: 'this is label',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-ng-content/ng-content-about-parent.stories.ts",
    "content": "import { Component, Input } from '@angular/core';\nimport type { Meta, StoryObj } from '@storybook/angular';\nimport { componentWrapperDecorator } from '@storybook/angular';\n\n@Component({\n  standalone: false,\n  selector: 'sb-button',\n  template: `<button [style.background-color]=\"color\"><ng-content></ng-content></button>`,\n  styles: [\n    `\n      button {\n        padding: 4px;\n      }\n    `,\n  ],\n})\nclass SbButtonComponent {\n  @Input()\n  color = '#5eadf5';\n}\n\nconst meta: Meta<SbButtonComponent> = {\n  // title: 'Basics / Component / With ng-content / Button with different contents',\n  // Implicitly declares the component to Angular\n  // This will be the component described by the addon docs\n  component: SbButtonComponent,\n  decorators: [\n    // Wrap all stories with this template\n    componentWrapperDecorator(\n      (story) => `<sb-button [color]=\"propsColor\">${story}</sb-button>`,\n\n      ({ args }) => ({ propsColor: args['color'] })\n    ),\n  ],\n  argTypes: {\n    color: { control: 'color' },\n  },\n} as Meta;\n\nexport default meta;\n\ntype Story = StoryObj<SbButtonComponent>;\n\n// By default storybook uses the default export component if no template or component is defined in the story\n// So Storybook nests the component twice because it is first added by the componentWrapperDecorator.\nexport const AlwaysDefineTemplateOrComponent: Story = {};\n\nexport const EmptyButton: Story = {\n  render: () => ({\n    template: '',\n  }),\n};\n\nexport const InH1: Story = {\n  render: () => ({\n    template: 'My button in h1',\n  }),\n  decorators: [componentWrapperDecorator((story) => `<h1>${story}</h1>`)],\n  name: 'In <h1>',\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-ng-content/ng-content-simple.stories.ts",
    "content": "import { Component } from '@angular/core';\n\nimport type { Meta, StoryObj } from '@storybook/angular';\n\n@Component({\n  standalone: false,\n  selector: 'storybook-with-ng-content',\n  template: `Content value:\n<div style=\"color: #1e88e5\"><ng-content></ng-content></div>`,\n})\nclass WithNgContentComponent {}\n\nconst meta: Meta<WithNgContentComponent> = {\n  // title: 'Basics / Component / With ng-content / Simple',\n  component: WithNgContentComponent,\n} as Meta;\n\nexport default meta;\n\ntype Story = StoryObj<WithNgContentComponent & { content: string }>;\n\nexport const OnlyComponent: Story = {};\n\nexport const Default: Story = {\n  render: () => ({\n    template: `<storybook-with-ng-content><h1>This is rendered in ng-content</h1></storybook-with-ng-content>`,\n  }),\n};\n\nexport const WithDynamicContentAndArgs: Story = {\n  render: (args) => ({\n    template: `<storybook-with-ng-content><h1>${args['content']}</h1></storybook-with-ng-content>`,\n  }),\n  args: { content: 'Default content' },\n  argTypes: {\n    content: { control: 'text' },\n  },\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-ng-on-destroy/component-with-on-destroy.stories.ts",
    "content": "import type { OnDestroy, OnInit } from '@angular/core';\nimport { Component } from '@angular/core';\nimport type { Meta, StoryObj } from '@storybook/angular';\n\n@Component({\n  standalone: false,\n  selector: 'on-destroy',\n  template: `Current time: {{ time }} <br />\n📝 The current time in console should no longer display after a change of story`,\n})\nclass OnDestroyComponent implements OnInit, OnDestroy {\n  time?: string;\n\n  interval: any;\n\n  ngOnInit(): void {\n    const myTimer = () => {\n      const d = new Date();\n      this.time = d.toLocaleTimeString();\n      console.info(`Current time: ${this.time}`);\n    };\n\n    myTimer();\n    this.interval = setInterval(myTimer, 3000);\n  }\n\n  ngOnDestroy(): void {\n    clearInterval(this.interval);\n  }\n}\n\nconst meta: Meta<OnDestroyComponent> = {\n  // title: 'Basics / Component / with ngOnDestroy',\n  component: OnDestroyComponent,\n  parameters: {\n    // disabled due to new Date()\n    chromatic: { disableSnapshot: true },\n  },\n} as Meta;\n\nexport default meta;\n\ntype Story = StoryObj<OnDestroyComponent>;\n\nexport const SimpleComponent: Story = {};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-on-push/on-push-box.component.ts",
    "content": "import { Component, Input, ChangeDetectionStrategy, HostBinding } from '@angular/core';\n\n@Component({\n  standalone: false,\n  selector: 'storybook-on-push-box',\n  template: ` Word of the day: {{ word }} `,\n  styles: [\n    `\n      :host {\n        display: block;\n        padding: 1rem;\n        width: fit-content;\n      }\n    `,\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class OnPushBoxComponent {\n  @Input() word?: string;\n\n  @Input() @HostBinding('style.background-color') bgColor?: string;\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-on-push/on-push.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\n\nimport { OnPushBoxComponent } from './on-push-box.component';\n\nconst meta: Meta<OnPushBoxComponent> = {\n  // title: 'Basics / Component / With OnPush strategy',\n  component: OnPushBoxComponent,\n  argTypes: {\n    word: { control: 'text' },\n    bgColor: { control: 'color' },\n  },\n  args: {\n    word: 'The text',\n    bgColor: '#FFF000',\n  },\n};\n\nexport default meta;\n\ntype Story = StoryObj<OnPushBoxComponent>;\n\nexport const ClassSpecifiedComponentWithOnPushAndArgs: Story = {\n  name: 'Class-specified component with OnPush and Args',\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-pipe/custom-pipes.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\nimport { moduleMetadata } from '@storybook/angular';\n\nimport { CustomPipePipe } from './custom.pipe';\nimport { WithPipeComponent } from './with-pipe.component';\n\nconst meta: Meta<WithPipeComponent> = {\n  // title: 'Basics / Component / With Pipes',\n  component: WithPipeComponent,\n  decorators: [\n    moduleMetadata({\n      declarations: [CustomPipePipe],\n    }),\n  ],\n};\n\nexport default meta;\n\ntype Story = StoryObj<WithPipeComponent>;\n\nexport const Simple: Story = {\n  render: () => ({\n    props: {\n      field: 'foobar',\n    },\n  }),\n};\n\nexport const WithArgsStory: Story = {\n  name: 'With args',\n  argTypes: {\n    field: { control: 'text' },\n  },\n  args: {\n    field: 'Foo Bar',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-pipe/custom.pipe.ts",
    "content": "import type { PipeTransform } from '@angular/core';\nimport { Pipe } from '@angular/core';\n\n@Pipe({\n  standalone: false,\n  name: 'customPipe',\n})\nexport class CustomPipePipe implements PipeTransform {\n  transform(value: any, args?: any): any {\n    return `CustomPipe: ${value}`;\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-pipe/with-pipe.component.ts",
    "content": "import { Component, Input } from '@angular/core';\n\n@Component({\n  standalone: false,\n  selector: 'storybook-with-pipe',\n  template: ` <h1>{{ field | customPipe }}</h1> `,\n})\nexport class WithPipeComponent {\n  @Input()\n  field: any;\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-provider/di.component.html",
    "content": "<div>\n  <div>All dependencies are defined: {{ isAllDeps() }}</div>\n  <div>Title: {{ title }}</div>\n  <div data-chromatic=\"ignore\">Injector: {{ injector.constructor.toString() }}</div>\n  <div>ElementRef: {{ elRefStr() }}</div>\n  <div>TestToken: {{ testToken }}</div>\n</div>\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-provider/di.component.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\n\nimport { DiComponent } from './di.component';\n\nconst meta: Meta<DiComponent> = {\n  // title: 'Basics / Component / With Provider',\n  component: DiComponent,\n};\n\nexport default meta;\n\ntype Story = StoryObj<DiComponent>;\n\nexport const InputsAndInjectDependencies: Story = {\n  render: () => ({\n    props: {\n      title: 'Component dependencies',\n    },\n  }),\n  name: 'inputs and inject dependencies',\n};\n\nexport const InputsAndInjectDependenciesWithArgs: Story = {\n  name: 'inputs and inject dependencies with args',\n  argTypes: {\n    title: { control: 'text' },\n  },\n  args: {\n    title: 'Component dependencies',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-provider/di.component.ts",
    "content": "// ElementRef must be a regular import, not a type-only import, because it's used in dependency injection.\n// Type-only imports are stripped during compilation, causing runtime errors like \"ElementRef is not defined\".\n// Do not remove `Inject` even though it seems unused, it is used in the constructor.\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\nimport { Injector, ElementRef, Component, Input, InjectionToken, Inject } from '@angular/core';\nimport { stringify } from 'telejson';\n\nexport const TEST_TOKEN = new InjectionToken<string>('test');\n\n@Component({\n  standalone: false,\n  selector: 'storybook-di-component',\n  templateUrl: './di.component.html',\n  providers: [{ provide: TEST_TOKEN, useValue: 123 }],\n})\nexport class DiComponent {\n  @Input()\n  title?: string;\n\n  constructor(\n    protected injector: Injector,\n    protected elRef: ElementRef,\n    @Inject(TEST_TOKEN) protected testToken: number\n  ) {}\n\n  isAllDeps(): boolean {\n    return Boolean(this.testToken && this.elRef && this.injector && this.title);\n  }\n\n  elRefStr(): string {\n    return stringify(this.elRef, { maxDepth: 1 });\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-style/styled.component.css",
    "content": ".red-color {\n  color: red;\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-style/styled.component.html",
    "content": "<div>\n  <p class=\"red-color\">Styled with scoped CSS</p>\n  <p class=\"blue-color\">Styled with scoped SCSS</p>\n  <p class=\"green-color\">Styled with global CSS</p>\n</div>\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-style/styled.component.scss",
    "content": "div {\n  p.blue-color {\n    color: blue;\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-style/styled.component.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\n\nimport { StyledComponent } from './styled.component';\n\nconst meta: Meta = {\n  // title: 'Basics / Component / With StyleUrls',\n  component: StyledComponent,\n};\n\nexport default meta;\n\ntype Story = StoryObj<StyledComponent>;\n\nexport const ComponentWithStyles: Story = {\n  name: 'Component with styles',\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-style/styled.component.ts",
    "content": "import { Component } from '@angular/core';\n\n@Component({\n  standalone: false,\n  selector: 'storybook-styled-component',\n  templateUrl: './styled.component.html',\n  styleUrls: ['./styled.component.css', './styled.component.scss'],\n})\nexport class StyledComponent {}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-template/template.component.ts",
    "content": "import { CommonModule } from '@angular/common';\nimport { Component, EventEmitter, Input, Output } from '@angular/core';\n\n@Component({\n  selector: 'app-template',\n  imports: [CommonModule],\n  template: `<div (click)=\"event($event)\">\n  Label: {{ label }}\n  <br />\n  Label2: {{ label2 }}\n  <br />\n  <button (click)=\"inc()\">+</button>\n</div>`,\n  styles: [],\n  standalone: true,\n})\nexport class Template {\n  @Input() label = 'default label';\n\n  @Input() label2 = 'default label2';\n\n  @Output() changed = new EventEmitter<string>();\n\n  inc() {\n    this.changed.emit('Increase');\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-with-template/template.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\nimport { argsToTemplate } from '@storybook/angular';\n\nimport { Template } from './template.component';\n\nconst meta: Meta<Template> = {\n  component: Template,\n};\n\nexport default meta;\n\ntype Story = StoryObj<Template>;\n\nexport const Default: Story = {\n  render: (args) => ({\n    props: args,\n    template: `<app-template ${argsToTemplate(args)}></app-template>`,\n  }),\n};\n\nexport const SetOneInput: Story = {\n  ...Default,\n  args: {\n    label: 'Label Example 1',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-without-selector/without-selector-ng-component-outlet.stories.ts",
    "content": "import type { OnInit, Type } from '@angular/core';\nimport { Component, Injector, Input } from '@angular/core';\nimport type { Meta, StoryObj } from '@storybook/angular';\nimport { componentWrapperDecorator, moduleMetadata } from '@storybook/angular';\nimport { WithoutSelectorComponent, WITHOUT_SELECTOR_DATA } from './without-selector.component';\n\nconst meta: Meta<WithoutSelectorComponent> = {\n  // title: 'Basics / Component / without selector / Custom wrapper *NgComponentOutlet',\n  component: WithoutSelectorComponent,\n  decorators: [\n    moduleMetadata({\n      entryComponents: [WithoutSelectorComponent],\n    }),\n  ],\n} as Meta;\n\nexport default meta;\n\ntype Story = StoryObj<WithoutSelectorComponent>;\n\n// Advanced example with custom *ngComponentOutlet\n\n@Component({\n  standalone: false,\n  selector: 'ng-component-outlet-wrapper',\n  template: `<ng-container\n  *ngComponentOutlet=\"componentOutlet; injector: componentInjector; content: componentContent\"\n></ng-container>`,\n})\nclass NgComponentOutletWrapperComponent implements OnInit {\n  @Input()\n  componentOutlet?: Type<unknown>;\n\n  @Input()\n  name?: string;\n\n  @Input()\n  color?: string;\n\n  componentInjector?: Injector;\n\n  componentContent = [\n    [document.createTextNode('Ng-content : Inspired by ')],\n    [document.createTextNode('https://angular.io/api/common/NgComponentOutlet')],\n  ];\n\n  constructor(private readonly injector: Injector) {}\n\n  ngOnInit(): void {\n    this.componentInjector = Injector.create({\n      providers: [\n        { provide: WITHOUT_SELECTOR_DATA, useValue: { color: this.color, name: this.name } },\n      ],\n      parent: this.injector,\n    });\n  }\n}\n\n// Live changing of args by controls does not work at the moment. When changing args storybook does not fully\n// reload and therefore does not take into account the change of provider.\nexport const WithCustomNgComponentOutletWrapper: Story = {\n  name: 'Custom wrapper *NgComponentOutlet',\n  argTypes: {\n    name: { control: 'text' },\n    color: { control: 'color' },\n  },\n  args: { name: 'Color', color: 'green' },\n  decorators: [\n    moduleMetadata({\n      declarations: [NgComponentOutletWrapperComponent],\n    }),\n    componentWrapperDecorator(NgComponentOutletWrapperComponent, (args) => ({\n      name: args.name,\n\n      color: args['color'],\n      componentOutlet: WithoutSelectorComponent,\n    })),\n  ],\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-without-selector/without-selector.component.ts",
    "content": "import { Component, Inject, InjectionToken, Optional } from '@angular/core';\n\nexport const WITHOUT_SELECTOR_DATA = new InjectionToken<{ color: string; name: string }>(\n  'WITHOUT_SELECTOR_DATA'\n);\n\n@Component({\n  standalone: false,\n  template: `My name in color :\n<div [style.color]=\"color\">{{ name }}</div>\n<ng-content></ng-content> <ng-content></ng-content>`,\n})\nexport class WithoutSelectorComponent {\n  color = '#1e88e5';\n\n  name = 'Joe Bar';\n\n  constructor(\n    @Inject(WITHOUT_SELECTOR_DATA)\n    @Optional()\n    data: {\n      color: string;\n      name: string;\n    } | null\n  ) {\n    if (data) {\n      this.color = data.color;\n      this.name = data.name;\n    }\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/component-without-selector/without-selector.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\nimport { moduleMetadata } from '@storybook/angular';\n\nimport { WITHOUT_SELECTOR_DATA, WithoutSelectorComponent } from './without-selector.component';\n\nconst meta: Meta<WithoutSelectorComponent> = {\n  // title: 'Basics / Component / without selector',\n  component: WithoutSelectorComponent,\n  decorators: [\n    moduleMetadata({\n      entryComponents: [WithoutSelectorComponent],\n    }),\n  ],\n} as Meta;\n\nexport default meta;\n\ntype Story = StoryObj<WithoutSelectorComponent>;\n\nexport const SimpleComponent: Story = {};\n\n// Live changing of args by controls does not work for now. When changing args storybook does not fully\n// reload and therefore does not take into account the change of provider.\nexport const WithInjectionTokenAndArgs: StoryObj = {\n  render: (args) => ({\n    props: args,\n    moduleMetadata: {\n      providers: [\n        { provide: WITHOUT_SELECTOR_DATA, useValue: { color: args['color'], name: args['name'] } },\n      ],\n    },\n  }),\n  argTypes: {\n    name: { control: 'text' },\n    color: { control: 'color' },\n  },\n  args: { name: 'Color', color: 'red' },\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/ng-module/angular-src/chip-color.token.ts",
    "content": "import { InjectionToken } from '@angular/core';\n\nexport const CHIP_COLOR = new InjectionToken<string>('chip-color');\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/ng-module/angular-src/chip-text.pipe.ts",
    "content": "import type { PipeTransform } from '@angular/core';\nimport { Pipe } from '@angular/core';\n\n@Pipe({\n  standalone: false,\n  name: 'chipText',\n})\nexport class ChipTextPipe implements PipeTransform {\n  transform(value: string): string {\n    return Array.from(value)\n      .map((char) => this.accentVowel(char))\n      .join('');\n  }\n\n  accentVowel(char: string): string {\n    switch (char) {\n      case 'a':\n        return 'á';\n      case 'e':\n        return 'é';\n      case 'i':\n        return 'í';\n      case 'o':\n        return 'ó';\n      case 'u':\n        return 'ú';\n      default:\n        return char;\n    }\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/ng-module/angular-src/chip.component.ts",
    "content": "import { Component, Input, Output, EventEmitter, Inject, HostBinding } from '@angular/core';\nimport { CHIP_COLOR } from './chip-color.token';\n\n@Component({\n  standalone: false,\n  selector: 'storybook-chip',\n  template: `\n    <span class=\"text\">{{ displayText | chipText }}</span>\n<div class=\"remove\" (click)=\"removeClicked.emit()\">\n  <span class=\"x\">✕</span>\n</div>\n  `,\n  styles: [\n    `\n      :host {\n        display: inline-flex;\n        justify-content: center;\n        align-items: center;\n        cursor: default;\n        border: solid 0.1rem transparent;\n        border-radius: 1rem;\n        padding: 0.2rem 0.5rem;\n      }\n      :host:hover {\n        border-color: black;\n      }\n      .text {\n        font-family: inherit;\n      }\n      .remove {\n        margin-left: 1rem;\n        border-radius: 50%;\n        background-color: lightgrey;\n        width: 1rem;\n        height: 1rem;\n        text-align: center;\n      }\n      .remove:hover {\n        background-color: palevioletred;\n      }\n      .x {\n        display: inline-block;\n        vertical-align: baseline;\n        color: #eeeeee;\n        line-height: 1rem;\n        text-align: center;\n      }\n    `,\n  ],\n})\nexport class ChipComponent {\n  @Input() displayText?: string;\n\n  @Output() removeClicked = new EventEmitter();\n\n  @HostBinding('style.background-color') backgroundColor: string;\n\n  constructor(@Inject(CHIP_COLOR) chipColor: string) {\n    this.backgroundColor = chipColor;\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/ng-module/angular-src/chips-group.component.ts",
    "content": "import { Component, Input, Output, EventEmitter } from '@angular/core';\n\n@Component({\n  standalone: false,\n  selector: 'storybook-chips-group',\n  template: `\n    <storybook-chip\n  *ngFor=\"let chip of chips\"\n  class=\"chip\"\n  [displayText]=\"chip.text\"\n  (removeClicked)=\"removeChipClick.emit(chip.id)\"\n></storybook-chip>\n<div *ngIf=\"chips.length > 1\" class=\"remove-all\" (click)=\"removeAllChipsClick.emit()\">\n  Remove All\n</div>\n  `,\n  styles: [\n    `\n      :host {\n        display: flex;\n        align-content: center;\n        border-radius: 0.5rem;\n        background-color: lightgrey;\n        padding: 0.5rem;\n        width: fit-content;\n      }\n      .chip:not(:first-of-type) {\n        margin-left: 0.5rem;\n      }\n      .remove-all {\n        margin-left: 0.5rem;\n        border: solid 0.1rem #eeeeee;\n        padding: 0.2rem 0.5rem;\n      }\n      .remove-all:hover {\n        background-color: palevioletred;\n      }\n    `,\n  ],\n})\nexport class ChipsGroupComponent {\n  @Input() chips?: {\n    id: number;\n    text: string;\n  }[];\n\n  @Output() removeChipClick = new EventEmitter<number>();\n\n  @Output() removeAllChipsClick = new EventEmitter();\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/ng-module/angular-src/chips.module.ts",
    "content": "import type { ModuleWithProviders } from '@angular/core';\nimport { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { ChipComponent } from './chip.component';\nimport { ChipsGroupComponent } from './chips-group.component';\nimport { ChipTextPipe } from './chip-text.pipe';\nimport { CHIP_COLOR } from './chip-color.token';\n\n@NgModule({\n  imports: [CommonModule],\n  exports: [ChipsGroupComponent, ChipComponent],\n  declarations: [ChipsGroupComponent, ChipComponent, ChipTextPipe],\n  providers: [\n    {\n      provide: CHIP_COLOR,\n      useValue: '#eeeeee',\n    },\n  ],\n})\nexport class ChipsModule {\n  public static forRoot(): ModuleWithProviders<ChipsModule> {\n    return {\n      ngModule: ChipsModule,\n      providers: [\n        {\n          provide: CHIP_COLOR,\n          useValue: '#ff5454',\n        },\n      ],\n    };\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/ng-module/import-module-chip.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\nimport { StoryFn, moduleMetadata } from '@storybook/angular';\n\nimport { ChipComponent } from './angular-src/chip.component';\nimport { ChipsModule } from './angular-src/chips.module';\n\nconst meta: Meta<ChipComponent> = {\n  component: ChipComponent,\n  decorators: [\n    moduleMetadata({\n      imports: [ChipsModule],\n    }),\n  ],\n};\n\nexport default meta;\n\ntype Story = StoryObj<ChipComponent>;\n\nexport const Chip: Story = {\n  args: {\n    displayText: 'Chip',\n  },\n  argTypes: {\n    removeClicked: { action: 'Remove icon clicked' },\n  },\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/ng-module/import-module-for-root.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\nimport { StoryFn, moduleMetadata } from '@storybook/angular';\n\nimport { CHIP_COLOR } from './angular-src/chip-color.token';\nimport { ChipsGroupComponent } from './angular-src/chips-group.component';\nimport { ChipsModule } from './angular-src/chips.module';\n\nconst meta: Meta<ChipsGroupComponent> = {\n  // title: 'Basics / NgModule / forRoot() pattern',\n  component: ChipsGroupComponent,\n  decorators: [\n    moduleMetadata({\n      imports: [ChipsModule.forRoot()],\n    }),\n  ],\n  args: {\n    chips: [\n      {\n        id: 1,\n        text: 'Chip 1',\n      },\n      {\n        id: 2,\n        text: 'Chip 2',\n      },\n    ],\n  },\n  argTypes: {\n    removeChipClick: { action: 'Remove chip' },\n    removeAllChipsClick: { action: 'Remove all chips clicked' },\n  },\n};\n\nexport default meta;\n\ntype Story = StoryObj<ChipsGroupComponent>;\n\nexport const Base: Story = {\n  name: 'Chips group',\n};\n\nexport const WithCustomProvider: Story = {\n  decorators: [\n    moduleMetadata({\n      providers: [\n        {\n          provide: CHIP_COLOR,\n          useValue: 'yellow',\n        },\n      ],\n    }),\n  ],\n  name: 'Chips group with overridden provider',\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/basics/ng-module/import-module.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\nimport { StoryFn, moduleMetadata } from '@storybook/angular';\n\nimport { ChipsGroupComponent } from './angular-src/chips-group.component';\nimport { ChipsModule } from './angular-src/chips.module';\n\nconst meta: Meta<ChipsGroupComponent> = {\n  // title: 'Basics / NgModule / Module with multiple component',\n  component: ChipsGroupComponent,\n  decorators: [\n    moduleMetadata({\n      imports: [ChipsModule],\n    }),\n  ],\n};\n\nexport default meta;\n\ntype Story = StoryObj<ChipsGroupComponent>;\n\nexport const ChipsGroup: Story = {\n  args: {\n    chips: [\n      {\n        id: 1,\n        text: 'Chip 1',\n      },\n      {\n        id: 2,\n        text: 'Chip 2',\n      },\n    ],\n  },\n  argTypes: {\n    removeChipClick: { action: 'Remove chip' },\n    removeAllChipsClick: { action: 'Remove all chips clicked' },\n  },\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/button.component.ts",
    "content": "import { Component, Input, Output, EventEmitter } from '@angular/core';\n\n@Component({\n  standalone: false,\n  selector: 'storybook-button-component',\n  template: ` <button (click)=\"onClick.emit($event)\">{{ text }}</button> `,\n  styles: [\n    `\n      button {\n        cursor: pointer;\n        margin: 10px;\n        border: 1px solid #eee;\n        border-radius: 3px;\n        background-color: #ffffff;\n        padding: 3px 10px;\n        font-size: 15px;\n      }\n    `,\n  ],\n})\nexport default class ButtonComponent {\n  @Input()\n  text = '';\n\n  @Output()\n  onClick = new EventEmitter<any>();\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/core/README.mdx",
    "content": "import { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"stories / frameworks / angular / core / README\" />\n\n# Examples for Storybook native features\n\nThese examples highlight Storybook's native functionality. It does not require any special addon\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/core/decorators/componentWrapperDecorator/child.component.ts",
    "content": "import { Component, Input, Output, EventEmitter } from '@angular/core';\n\n@Component({\n  standalone: false,\n  selector: 'child-component',\n  template: `\n    Child<br />\nInput text: {{ childText }} <br />\nOutput : <button (click)=\"onClickChild.emit($event)\">Click here !</button> <br />\nPrivate text: {{ childPrivateText }} <br />\n  `,\n})\nexport default class ChildComponent {\n  @Input()\n  childText = '';\n\n  childPrivateText = '';\n\n  @Output()\n  onClickChild = new EventEmitter<any>();\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/core/decorators/componentWrapperDecorator/decorators.stories.ts",
    "content": "// your-component.stories.ts\nimport type { Args, Meta, StoryObj } from '@storybook/angular';\nimport { componentWrapperDecorator, moduleMetadata } from '@storybook/angular';\n\nimport ChildComponent from './child.component';\nimport ParentComponent from './parent.component';\n\nconst meta: Meta<ChildComponent> = {\n  // title: 'Core / Decorators / ComponentWrapperDecorator',\n  component: ChildComponent,\n  decorators: [\n    componentWrapperDecorator(\n      (story) => `Grandparent<br><div style=\"margin: 3em; border:solid;\">${story}</div>`\n    ),\n  ],\n  args: { childText: 'Child text', childPrivateText: 'Child private text' },\n  argTypes: { onClickChild: { action: 'onClickChild' } },\n};\n\nexport default meta;\n\ntype Story = StoryObj<ChildComponent>;\n\nexport const WithTemplate: Story = {\n  render: (args: Args) => ({\n    template: `Child Template`,\n    props: args,\n  }),\n};\n\nexport const WithComponent: Story = {};\n\nexport const WithLegacyComponent: Story = {\n  render: (args: Args) => ({\n    component: ChildComponent,\n    props: args,\n  }),\n};\n\nexport const WithComponentWrapperDecorator: Story = {\n  render: (args: Args) => ({\n    component: ChildComponent,\n    props: args,\n  }),\n  decorators: [\n    moduleMetadata({ declarations: [ParentComponent] }),\n    componentWrapperDecorator(ParentComponent),\n  ],\n};\n\nexport const WithComponentWrapperDecoratorAndProps: Story = {\n  render: (args: Args) => ({\n    component: ChildComponent,\n    props: {\n      ...args,\n    },\n  }),\n  decorators: [\n    moduleMetadata({ declarations: [ParentComponent] }),\n    componentWrapperDecorator(ParentComponent, {\n      parentText: 'Parent text',\n      onClickParent: () => {\n        console.log('onClickParent');\n      },\n    }),\n  ],\n};\n\nexport const WithComponentWrapperDecoratorAndArgs: StoryObj<{\n  parentText: string;\n  onClickParent: () => void;\n}> = {\n  render: (args: Args) => ({\n    component: ChildComponent,\n    props: {\n      ...args,\n    },\n  }),\n  argTypes: {\n    parentText: { control: { type: 'text' } },\n    onClickParent: { action: 'onClickParent' },\n  },\n  decorators: [\n    moduleMetadata({ declarations: [ParentComponent] }),\n    componentWrapperDecorator(ParentComponent, ({ args }) => ({\n      parentText: args.parentText,\n      onClickParent: args.onClickParent,\n    })),\n  ],\n};\n\nexport const WithCustomDecorator = (args: Args) => ({\n  template: `Child Template`,\n  props: {\n    ...args,\n  },\n});\nWithCustomDecorator.decorators = [\n  (storyFunc) => {\n    const story = storyFunc();\n\n    return {\n      ...story,\n      template: `Custom Decorator <div style=\"margin: 3em\">${story.template}</div>`,\n    };\n  },\n] as Story['decorators'];\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/core/decorators/componentWrapperDecorator/parent.component.ts",
    "content": "import { Component, Input, Output, EventEmitter } from '@angular/core';\n\n@Component({\n  standalone: false,\n  selector: 'parent-component',\n  template: `\n    Parent<br />\nInput text: {{ parentText }} <br />\nOutput : <button (click)=\"onClickParent.emit($event)\">Click here !</button> <br />\n<div style=\"margin: 3em; border: solid\"><ng-content></ng-content></div>\n  `,\n})\nexport default class ParentComponent {\n  @Input()\n  parentText = '';\n\n  @Output()\n  onClickParent = new EventEmitter<any>();\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/core/decorators/theme-decorator/decorators.stories.ts",
    "content": "import type { Args, Meta } from '@storybook/angular';\nimport { componentWrapperDecorator } from '@storybook/angular';\n\nexport const Base = (args: Args) => ({\n  template: 'Change sb_theme with the brush in toolbar',\n  props: {\n    ...args,\n  },\n});\n\nexport default {\n  // title: 'Core / Decorators / Theme Decorators',\n  component: Base,\n  decorators: [\n    componentWrapperDecorator(\n      (story) => `<div [class]=\"myTheme\">${story}</div>`,\n\n      ({ globals }) => ({ myTheme: `${globals['sb_theme']}-theme` })\n    ),\n  ],\n} as Meta;\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/core/moduleMetadata/angular-src/custom.pipe.ts",
    "content": "import type { PipeTransform } from '@angular/core';\nimport { Pipe } from '@angular/core';\n\n@Pipe({\n  standalone: false,\n  name: 'customPipe',\n})\nexport class CustomPipePipe implements PipeTransform {\n  transform(value: any, args?: any): any {\n    return `CustomPipe: ${value}`;\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/core/moduleMetadata/angular-src/dummy.service.ts",
    "content": "import { Injectable } from '@angular/core';\n\n@Injectable({ providedIn: 'root' })\nexport class DummyService {\n  constructor() {}\n\n  getItems() {\n    return new Promise((resolve) => {\n      setTimeout(() => {\n        resolve(['Joe', 'Jane']);\n      }, 2000);\n    });\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/core/moduleMetadata/angular-src/service.component.ts",
    "content": "import type { OnInit } from '@angular/core';\nimport { Component, Input } from '@angular/core';\nimport type { DummyService } from './dummy.service';\n\n@Component({\n  standalone: false,\n  selector: 'storybook-simple-service-component',\n  template: `<p>{{ name }}:</p>\n<ul>\n  <li *ngFor=\"let item of items\">{{ item }}</li>\n</ul>`,\n})\nexport class ServiceComponent implements OnInit {\n  items?: {};\n\n  @Input()\n  name?: any;\n\n  constructor(private dummy: DummyService) {}\n\n  async ngOnInit() {\n    this.items = (await this.dummy.getItems()) as any;\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/core/moduleMetadata/angular-src/token.component.ts",
    "content": "import { Component, Input, InjectionToken, Inject, Optional } from '@angular/core';\n\nexport const ITEMS = new InjectionToken<string[]>('TokenComponent.Items');\nexport const DEFAULT_NAME = new InjectionToken<string>('TokenComponent.DefaultName');\n\n@Component({\n  standalone: false,\n  selector: 'storybook-simple-token-component',\n  template: `\n    <h3>{{ name }}</h3>\n<p>Items:</p>\n<ul>\n  <li *ngFor=\"let item of items\">{{ item }}</li>\n</ul>\n  `,\n})\nexport class TokenComponent {\n  items;\n\n  @Input()\n  name;\n\n  constructor(\n    @Optional()\n    @Inject(DEFAULT_NAME)\n    defaultName: string,\n    @Inject(ITEMS) items: string[]\n  ) {\n    this.name = defaultName;\n    this.items = items;\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/core/moduleMetadata/in-export-default.stories.ts",
    "content": "import type { Meta, StoryFn } from '@storybook/angular';\nimport { moduleMetadata } from '@storybook/angular';\n\nimport { DEFAULT_NAME, ITEMS, TokenComponent } from './angular-src/token.component';\n\nexport const Story1: StoryFn = () => ({\n  template: `<storybook-simple-token-component [name]=\"name\"></storybook-simple-token-component>`,\n  props: {\n    name: 'Prop Name',\n  },\n});\n\nStory1.storyName = 'Story 1';\n\nexport const Story2: StoryFn = () => ({\n  template: `<storybook-simple-token-component></storybook-simple-token-component>`,\n});\n\nStory2.storyName = 'Story 2';\n\nexport default {\n  // title: 'Core / ModuleMetadata / In export default with decorator',\n  component: Story1,\n  decorators: [\n    moduleMetadata({\n      imports: [],\n      declarations: [TokenComponent],\n      providers: [\n        {\n          provide: ITEMS,\n          useValue: ['Joe', 'Jane'],\n        },\n        {\n          provide: DEFAULT_NAME,\n          useValue: 'Provider Name',\n        },\n      ],\n    }),\n  ],\n} as Meta;\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/core/moduleMetadata/in-stories.stories.ts",
    "content": "import type { Meta, StoryFn } from '@storybook/angular';\n\nimport { DEFAULT_NAME, ITEMS, TokenComponent } from './angular-src/token.component';\n\nexport const Individual1: StoryFn = () => ({\n  template: `<storybook-simple-token-component [name]=\"name\"></storybook-simple-token-component>`,\n  props: {\n    name: 'Prop Name',\n  },\n  moduleMetadata: {\n    imports: [],\n    declarations: [TokenComponent],\n    providers: [\n      {\n        provide: ITEMS,\n        useValue: ['Joe', 'Jane'],\n      },\n    ],\n  },\n});\n\nIndividual1.storyName = 'Individual 1';\n\nexport const Individual2: StoryFn = () => ({\n  template: `<storybook-simple-token-component></storybook-simple-token-component>`,\n  moduleMetadata: {\n    imports: [],\n    declarations: [TokenComponent],\n    providers: [\n      {\n        provide: ITEMS,\n        useValue: ['Jim', 'Jill'],\n      },\n      {\n        provide: DEFAULT_NAME,\n        useValue: 'Provider Name',\n      },\n    ],\n  },\n});\n\nIndividual2.storyName = 'Individual 2';\n\nexport default {\n  // title: 'Core / ModuleMetadata / In stories',\n  component: Individual1,\n} as Meta;\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/core/moduleMetadata/merge-default-and-story.stories.ts",
    "content": "import type { Meta, StoryFn } from '@storybook/angular';\nimport { moduleMetadata } from '@storybook/angular';\n\nimport { CustomPipePipe } from './angular-src/custom.pipe';\nimport { DEFAULT_NAME, ITEMS, TokenComponent } from './angular-src/token.component';\n\nexport const MergeWithDefaultModuleMetadata: StoryFn = () => ({\n  template: `<storybook-simple-token-component [name]=\"name | customPipe\"></storybook-simple-token-component>`,\n  props: {\n    name: 'Prop Name',\n  },\n  moduleMetadata: {\n    declarations: [CustomPipePipe],\n    providers: [],\n  },\n});\nMergeWithDefaultModuleMetadata.storyName = 'Merge with default ModuleMetadata';\n\nexport default {\n  // title: 'Core / ModuleMetadata / Merge default and story',\n  component: MergeWithDefaultModuleMetadata,\n  decorators: [\n    moduleMetadata({\n      declarations: [TokenComponent],\n      providers: [\n        {\n          provide: ITEMS,\n          useValue: ['Joe', 'Jane'],\n        },\n        {\n          provide: DEFAULT_NAME,\n          useValue: 'Provider Name',\n        },\n      ],\n    }),\n  ],\n} as Meta;\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/core/parameters/bootstrap-options.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\nimport { Component } from '@angular/core';\n\n@Component({\n  standalone: false,\n  selector: 'component-with-whitespace',\n  preserveWhitespaces: true,\n  template: ` <div>\n  <p>Some content</p>\n</div>`,\n})\nclass ComponentWithWhitespace {}\n\nconst meta: Meta<ComponentWithWhitespace> = {\n  // title: 'Core / Parameters / With Bootstrap Options',\n  component: ComponentWithWhitespace,\n};\n\nexport default meta;\n\ntype Story = StoryObj<ComponentWithWhitespace>;\n\nexport const WithPreserveWhitespaces: Story = {};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/core/styles/story-styles.stories.ts",
    "content": "import type { Meta, StoryFn } from '@storybook/angular';\nimport { moduleMetadata } from '@storybook/angular';\n\nimport Button from '../../button.component';\n\nexport const TemplateStory: StoryFn = () => ({\n  template: `<storybook-button-component [text]=\"text\" (onClick)=\"onClick($event)\"></storybook-button-component>`,\n  props: {\n    text: 'Button with custom styles',\n    onClick: () => {},\n  },\n  styles: [\n    `\n      storybook-button-component {\n        background-color: yellow;\n        padding: 25px;\n      }\n    `,\n  ],\n});\nTemplateStory.storyName = 'With story template';\n\nexport const WithArgsStory: StoryFn = (args) => ({\n  template: `<storybook-button-component [text]=\"text\" (onClick)=\"onClick($event)\"></storybook-button-component>`,\n  props: args,\n  styles: [\n    `\n  storybook-button-component {\n    background-color: red;\n    padding: 25px;\n  }\n`,\n  ],\n});\nWithArgsStory.storyName = 'With Args';\nWithArgsStory.argTypes = {\n  text: { control: 'text' },\n  onClick: { action: 'On click' },\n};\nWithArgsStory.args = {\n  text: 'Button with custom styles',\n};\n\nexport default {\n  // title: 'Core / Story host styles',\n  component: TemplateStory,\n  decorators: [\n    moduleMetadata({\n      declarations: [Button],\n    }),\n  ],\n} as Meta;\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/others/app-initializer-use-factory/app-initializer-use-factory.stories.ts",
    "content": "import { action } from 'storybook/actions';\nimport type { Meta, StoryObj } from '@storybook/angular';\nimport { moduleMetadata } from '@storybook/angular';\n\nimport { APP_INITIALIZER } from '@angular/core';\n\nimport Button from '../../button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  render: (args) => ({\n    props: {\n      ...args,\n    },\n  }),\n  decorators: [\n    moduleMetadata({\n      providers: [\n        {\n          provide: APP_INITIALIZER,\n          useFactory: () => {\n            return action('APP_INITIALIZER useFactory called successfully');\n          },\n          multi: true,\n        },\n      ],\n    }),\n  ],\n};\n\nexport default meta;\n\ntype Story = StoryObj<Button>;\n\nexport const Default: Story = {\n  args: {\n    text: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/others/issues/12009-unknown-component.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\n\nimport Button from '../../button.component';\n\nconst meta: Meta<Button> = {\n  // title: 'Others / Issues / 12009 unknown component',\n  component: Button,\n};\n\nexport default meta;\n\ntype Story = StoryObj<Button>;\n\nexport const Basic: Story = {\n  args: { text: 'Unknown component' },\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories/others/ngx-translate/README.mdx",
    "content": "import { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"stories / frameworks / angular / others / ngx-translate\" />\n\n# [ngx-translate](https://github.com/ngx-translate/core)\n\n> No real example here to avoid adding more dependency to storybook mono repository\n\nThere are several ways to configure ngx-translate in storybook which will depend on your context.\n\nHere is a simple example with a storybook decorator that you can place in the `preview.ts` or locally on the stories.\n[See the doc on decorators](https://storybook.js.org/docs/writing-stories/decorators?renderer=angular)\n\n```ts\nimport { HttpClient, HttpClientModule } from '@angular/common/http';\nimport { TranslateLoader, TranslateModule } from '@ngx-translate/core';\nimport { TranslateHttpLoader } from '@ngx-translate/http-loader';\nimport { moduleMetadata, applicationConfig } from '@storybook/angular';\n\nfunction createTranslateLoader(http: HttpClient) {\n  return new TranslateHttpLoader(http, '/assets/i18n/', '.json');\n}\n\nconst TranslateModuleDecorator = (storyFunc, context) => {\n  const { locale } = context.globals;\n\n  return applicationConfig({\n    providers: [\n      importProvidersFrom(\n        HttpClientModule, \n        TranslateModule.forRoot({\n          defaultLanguage: locale,\n          loader: {\n            provide: TranslateLoader,\n            useFactory: createTranslateLoader,\n            deps: [HttpClient],\n          },\n        })\n      )\n    ]\n  })(storyFunc, context);\n};\n\n// for `preview.ts`\nexport const decorators = [\n  moduleMetadata({\n    imports: [TranslateModule],\n  }),\n  TranslateModuleDecorator,\n];\n```\n\nIf the `TranslateModule.forRoot` is made by another module you can try to set this provider `DEFAULT_LANGUAGE`\n\n```ts\nimport { DEFAULT_LANGUAGE } from '@ngx-translate/core';\n\nconst TranslateModuleDecorator = (storyFunc, context) => {\n  const { locale } = context.globals;\n\n  return applicationConfig({\n    providers: [{ provide: DEFAULT_LANGUAGE, useValue: locale }],\n  })(storyFunc, context);\n};\n```\n"
  },
  {
    "path": "code/frameworks/angular/template/stories_angular-cli-default-ts/signal/button.component.ts",
    "content": "import { Component, Input, input, output } from '@angular/core';\n\n@Component({\n  standalone: false,\n  // Needs to be a different name to the CLI template button\n  selector: 'storybook-signal-button',\n  template: ` <button\n  type=\"button\"\n  (click)=\"onClick.emit($event)\"\n  [ngClass]=\"classes\"\n  [ngStyle]=\"{ 'background-color': backgroundColor }\"\n>\n  {{ label() }}\n</button>`,\n  styleUrls: ['./button.css'],\n})\nexport default class SignalButtonComponent {\n  /** Is this the principal call to action on the page? */\n  primary = input(false);\n\n  /** What background color to use */\n  @Input()\n  backgroundColor?: string;\n\n  /** How large should the button be? */\n  size = input('medium', {\n    transform: (val: 'small' | 'medium') => val,\n  });\n\n  /** Button contents */\n  label = input.required({ transform: (val: string) => val.trim() });\n\n  /** Optional click handler */\n  onClick = output<Event>();\n\n  public get classes(): string[] {\n    const mode = this.primary() ? 'storybook-button--primary' : 'storybook-button--secondary';\n\n    return ['storybook-button', `storybook-button--${this.size()}`, mode];\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories_angular-cli-default-ts/signal/button.css",
    "content": ".storybook-button {\n  display: inline-block;\n  cursor: pointer;\n  border: 0;\n  border-radius: 3em;\n  font-weight: 700;\n  line-height: 1;\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n.storybook-button--primary {\n  background-color: #555ab9;\n  color: white;\n}\n.storybook-button--secondary {\n  box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;\n  background-color: transparent;\n  color: #333;\n}\n.storybook-button--small {\n  padding: 10px 16px;\n  font-size: 12px;\n}\n.storybook-button--medium {\n  padding: 11px 20px;\n  font-size: 14px;\n}\n.storybook-button--large {\n  padding: 12px 24px;\n  font-size: 16px;\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories_angular-cli-default-ts/signal/button.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\nimport { fn } from 'storybook/test';\n\nimport SignalButtonComponent from './button.component';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories\nconst meta: Meta<SignalButtonComponent> = {\n  component: SignalButtonComponent,\n  tags: ['autodocs'],\n  argTypes: {\n    backgroundColor: {\n      control: 'color',\n    },\n    // The following argTypes are necessary,\n    // because Compodoc does not support Angular's new input and output signals yet\n    primary: {\n      type: 'boolean',\n    },\n    size: {\n      control: {\n        type: 'radio',\n      },\n      options: ['small', 'medium'],\n    },\n    label: {\n      type: 'string',\n    },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: {\n    onClick: fn(),\n    primary: false,\n    size: 'medium',\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<SignalButtonComponent>;\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Medium: Story = {\n  args: {\n    size: 'medium',\n    label: 'Button',\n  },\n};\n\nexport const Small: Story = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/angular/template/stories_angular-cli-prerelease/signal/button.component.ts",
    "content": "import { Component, Input, input, output } from '@angular/core';\n\n@Component({\n  standalone: false,\n  // Needs to be a different name to the CLI template button\n  selector: 'storybook-signal-button',\n  template: ` <button\n  type=\"button\"\n  (click)=\"onClick.emit($event)\"\n  [ngClass]=\"classes\"\n  [ngStyle]=\"{ 'background-color': backgroundColor }\"\n>\n  {{ label() }}\n</button>`,\n  styleUrls: ['./button.css'],\n})\nexport default class SignalButtonComponent {\n  /** Is this the principal call to action on the page? */\n  primary = input(false);\n\n  /** What background color to use */\n  @Input()\n  backgroundColor?: string;\n\n  /** How large should the button be? */\n  size = input('medium', {\n    transform: (val: 'small' | 'medium') => val,\n  });\n\n  /** Button contents */\n  label = input.required({ transform: (val: string) => val.trim() });\n\n  /** Optional click handler */\n  onClick = output<Event>();\n\n  public get classes(): string[] {\n    const mode = this.primary() ? 'storybook-button--primary' : 'storybook-button--secondary';\n\n    return ['storybook-button', `storybook-button--${this.size()}`, mode];\n  }\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories_angular-cli-prerelease/signal/button.css",
    "content": ".storybook-button {\n  display: inline-block;\n  cursor: pointer;\n  border: 0;\n  border-radius: 3em;\n  font-weight: 700;\n  line-height: 1;\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n.storybook-button--primary {\n  background-color: #555ab9;\n  color: white;\n}\n.storybook-button--secondary {\n  box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;\n  background-color: transparent;\n  color: #333;\n}\n.storybook-button--small {\n  padding: 10px 16px;\n  font-size: 12px;\n}\n.storybook-button--medium {\n  padding: 11px 20px;\n  font-size: 14px;\n}\n.storybook-button--large {\n  padding: 12px 24px;\n  font-size: 16px;\n}\n"
  },
  {
    "path": "code/frameworks/angular/template/stories_angular-cli-prerelease/signal/button.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/angular';\nimport { fn } from 'storybook/test';\n\nimport SignalButtonComponent from './button.component';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories\nconst meta: Meta<SignalButtonComponent> = {\n  component: SignalButtonComponent,\n  tags: ['autodocs'],\n  argTypes: {\n    backgroundColor: {\n      control: 'color',\n    },\n    // The following argTypes are necessary,\n    // because Compodoc does not support Angular's new input and output signals yet\n    primary: {\n      type: 'boolean',\n    },\n    size: {\n      control: {\n        type: 'radio',\n      },\n      options: ['small', 'medium'],\n    },\n    label: {\n      type: 'string',\n    },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: {\n    onClick: fn(),\n    primary: false,\n    size: 'medium',\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<SignalButtonComponent>;\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Medium: Story = {\n  args: {\n    size: 'medium',\n    label: 'Button',\n  },\n};\n\nexport const Small: Story = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/angular/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"moduleResolution\": \"bundler\",\n    \"module\": \"ES2022\",\n    \"experimentalDecorators\": true,\n    \"emitDecoratorMetadata\": true,\n    \"strict\": false\n  },\n  \"include\": [\"src/**/*\", \"./src/typings.d.ts\"]\n}\n"
  },
  {
    "path": "code/frameworks/angular/tsconfig.spec.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"types\": [\"node\"],\n    \"typeRoots\": [\"../../node_modules/@types\", \"node_modules/@types\"],\n    \"allowJs\": true\n  },\n  \"include\": [\"**/*.test.ts\", \"**/*.d.ts\"]\n}\n"
  },
  {
    "path": "code/frameworks/angular/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n    test: {\n      globals: true,\n      setupFiles: ['src/test-setup.ts'],\n    },\n  })\n);\n"
  },
  {
    "path": "code/frameworks/ember/README.md",
    "content": "# Storybook for Ember\n\nStorybook for Ember is a UI development environment for your Ember components.\nWith it, you can visualize different states of your UI components and develop them interactively.\n\n![Storybook Screenshot](https://github.com/storybookjs/storybook/blob/main/media/storybook-intro.gif)\n\nStorybook runs outside of your app.\nSo you can develop UI components in isolation without worrying about app specific dependencies and requirements.\n\n## Getting Started\n\n```sh\ncd my-ember-app\nnpx storybook@latest init\n```\n\nFor more information visit: [storybook.js.org](https://storybook.js.org?ref=readme)\n\n---\n\nStorybook also comes with a lot of [addons](https://storybook.js.org/addons?ref=readme) and a great API to customize as you wish.\nYou can also build a [static version](https://storybook.js.org/docs/sharing/publish-storybook?renderer=ember&ref=readme) of your Storybook and deploy it anywhere you want.\n\n## Docs\n\n- [Basics](https://storybook.js.org/docs/get-started/install?renderer=ember&ref=readme)\n- [Configurations](https://storybook.js.org/docs/configure?renderer=ember&ref=readme)\n- [Addons](https://storybook.js.org/docs/configure/user-interface/storybook-addons?renderer=ember&ref=readme)\n\n## Working with polyfills\n\nIf you need to use a polyfill that is already in use in our Ember application,\nyou will need to add some options to have Storybook working with them.\n\nIn this example we'll use the [named-block-polyfill](https://github.com/ember-polyfills/ember-named-blocks-polyfill).\nThis example also assume that you already have the package in your `package.json`.\n\nIn your `.storybook/main.js` you can add the following lines:\n\n```javascript\nimport namedBlockPolyfill from 'ember-named-blocks-polyfill/lib/named-blocks-polyfill-plugin';\n\nexport default {\n  framework: {\n    name: '@storybook/ember',\n    options: {\n      polyfills: [namedBlockPolyfill],\n    }\n  },\n  [...]\n};\n```\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/frameworks/ember/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./node'],\n        entryPoint: './src/node/index.ts',\n      },\n      {\n        exportEntries: ['./server/framework-preset-babel-ember'],\n        entryPoint: './src/server/framework-preset-babel-ember.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/frameworks/ember/package.json",
    "content": "{\n  \"name\": \"@storybook/ember\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook for Ember: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-framework\",\n    \"ember\",\n    \"component\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/frameworks/ember\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/frameworks/ember\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./node\": {\n      \"types\": \"./dist/node/index.d.ts\",\n      \"code\": \"./src/node/index.ts\",\n      \"default\": \"./dist/node/index.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\",\n    \"./server/framework-preset-babel-ember\": \"./dist/server/framework-preset-babel-ember.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"template/cli/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/builder-webpack5\": \"workspace:*\",\n    \"@storybook/global\": \"^5.0.0\",\n    \"babel-loader\": \"9.1.3\",\n    \"empathic\": \"2.0.0\"\n  },\n  \"devDependencies\": {\n    \"ember-source\": \"~3.28.1\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"@babel/core\": \"*\",\n    \"babel-plugin-ember-modules-api-polyfill\": \"^3.5.0\",\n    \"babel-plugin-htmlbars-inline-precompile\": \"^5.3.1\",\n    \"ember-source\": \"~3.28.1 || >=4.0.0\",\n    \"react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"storybook\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/frameworks/ember/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/frameworks/ember/project.json",
    "content": "{\n  \"name\": \"ember\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/frameworks/ember/src/client/preview/config.ts",
    "content": "import { enhanceArgTypes } from 'storybook/internal/docs-tools';\nimport type { ArgTypesEnhancer } from 'storybook/internal/types';\n\nimport './globals.ts';\nimport { extractArgTypes, extractComponentDescription } from './jsondoc.ts';\n\nexport { renderToCanvas } from './render.ts';\n\nexport const parameters = {\n  renderer: 'ember',\n  docs: {\n    story: { iframeHeight: '80px' },\n    extractArgTypes,\n    extractComponentDescription,\n  },\n};\n\nexport const argTypesEnhancers: ArgTypesEnhancer[] = [enhanceArgTypes];\n"
  },
  {
    "path": "code/frameworks/ember/src/client/preview/globals.ts",
    "content": "import { global } from '@storybook/global';\n\nglobal.STORYBOOK_NAME = process.env.STORYBOOK_NAME;\nglobal.STORYBOOK_ENV = 'ember';\n"
  },
  {
    "path": "code/frameworks/ember/src/client/preview/jsondoc.ts",
    "content": "import { global } from '@storybook/global';\n\nexport const getJSONDoc = () => {\n  return global.__EMBER_GENERATED_DOC_JSON__;\n};\n\nexport const extractArgTypes = (componentName: string) => {\n  const json = getJSONDoc();\n  if (!(json && json.included)) {\n    return null;\n  }\n  const componentDoc = json.included.find((doc: any) => doc.attributes.name === componentName);\n\n  if (!componentDoc) {\n    return null;\n  }\n  return componentDoc.attributes.arguments.reduce((acc: any, prop: any) => {\n    acc[prop.name] = {\n      name: prop.name,\n      defaultValue: prop.defaultValue,\n      description: prop.description,\n      table: {\n        defaultValue: { summary: prop.defaultValue },\n        type: {\n          summary: prop.type,\n          required: prop.tags.length\n            ? prop.tags.some((tag: any) => tag.name === 'required')\n            : false,\n        },\n      },\n    };\n    return acc;\n  }, {});\n};\n\nexport const extractComponentDescription = (componentName: string) => {\n  const json = getJSONDoc();\n  if (!(json && json.included)) {\n    return null;\n  }\n  const componentDoc = json.included.find((doc: any) => doc.attributes.name === componentName);\n\n  if (!componentDoc) {\n    return null;\n  }\n\n  return componentDoc.attributes.description;\n};\n"
  },
  {
    "path": "code/frameworks/ember/src/client/preview/render.ts",
    "content": "import type { RenderContext } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { dedent } from 'ts-dedent';\n\nimport type { EmberRenderer, OptionsArgs } from './types.ts';\n\nconst { document } = global;\n\ndeclare let Ember: any;\n\nconst rootEl = document.getElementById('storybook-root');\n\nfunction loadEmberApp() {\n  const config = global.require(`${global.STORYBOOK_NAME}/config/environment`);\n  return global.require(`${global.STORYBOOK_NAME}/app`).default.create({\n    autoboot: false,\n    rootElement: rootEl,\n    ...config.APP,\n  });\n}\n\nconst app = loadEmberApp();\nlet lastPromise = app.boot();\nlet hasRendered = false;\nlet isRendering = false;\n\nfunction render(options: OptionsArgs, el: EmberRenderer['canvasElement']) {\n  if (isRendering) {\n    return;\n  }\n  isRendering = true;\n\n  const { template, context = {}, element } = options;\n\n  if (hasRendered) {\n    lastPromise = lastPromise.then((instance: any) => instance.destroy());\n  }\n\n  lastPromise = lastPromise\n    .then(() => {\n      const appInstancePrivate = app.buildInstance();\n      return appInstancePrivate.boot().then(() => appInstancePrivate);\n    })\n    .then((instance: any) => {\n      instance.register(\n        'component:story-mode',\n        Ember.Component.extend({\n          layout: template || options,\n          ...context,\n        })\n      );\n\n      const component = instance.lookup('component:story-mode');\n\n      if (element) {\n        component.appendTo(element);\n\n        element.appendTo(el);\n      } else {\n        component.appendTo(el);\n      }\n      hasRendered = true;\n      isRendering = false;\n\n      return instance;\n    });\n}\n\nexport function renderToCanvas(\n  { storyFn, kind, name, showMain, showError }: RenderContext<EmberRenderer>,\n  canvasElement: EmberRenderer['canvasElement']\n) {\n  const element = storyFn();\n\n  if (!element) {\n    showError({\n      title: `Expecting a Ember element from the story: \"${name}\" of \"${kind}\".`,\n      description: dedent`\n        Did you forget to return the Ember element from the story?\n        Use \"() => hbs('{{component}}')\" or \"() => { return {\n          template: hbs\\`{{component}}\\`\n        } }\" when defining the story.\n      `,\n    });\n    return;\n  }\n\n  showMain();\n  render(element, canvasElement);\n}\n"
  },
  {
    "path": "code/frameworks/ember/src/client/preview/types.ts",
    "content": "import type { WebRenderer } from 'storybook/internal/types';\n\nexport type { RenderContext } from 'storybook/internal/types';\n\nexport interface ShowErrorArgs {\n  title: string;\n  description: string;\n}\n\nexport interface OptionsArgs {\n  template: any;\n  context: any;\n  element: any;\n}\n\nexport interface EmberRenderer extends WebRenderer {\n  component: any;\n  storyResult: OptionsArgs;\n}\n"
  },
  {
    "path": "code/frameworks/ember/src/index.ts",
    "content": "export * from './types.ts';\n"
  },
  {
    "path": "code/frameworks/ember/src/node/index.ts",
    "content": "import type { StorybookConfig } from '../types.ts';\n\nexport function defineMain(config: StorybookConfig) {\n  return config;\n}\n\nexport type { StorybookConfig };\n"
  },
  {
    "path": "code/frameworks/ember/src/preset.ts",
    "content": "import { getProjectRoot, resolvePathInStorybookCache } from 'storybook/internal/common';\nimport type { PresetProperty } from 'storybook/internal/types';\n\nimport { getVirtualModules } from '@storybook/builder-webpack5';\n\nimport type { StorybookConfig } from './types.ts';\n\nexport const addons: PresetProperty<'addons'> = [\n  import.meta.resolve('@storybook/ember/server/framework-preset-babel-ember'),\n];\n\nexport const webpackFinal: StorybookConfig['webpackFinal'] = async (baseConfig, options) => {\n  const { virtualModules } = await getVirtualModules(options);\n\n  const babelOptions = await options.presets.apply('babel', {}, options);\n  const typescriptOptions = await options.presets.apply('typescript', {}, options);\n\n  return {\n    ...baseConfig,\n    module: {\n      ...baseConfig.module,\n      rules: [\n        ...(baseConfig.module?.rules ?? []),\n        {\n          test: typescriptOptions.skipCompiler ? /\\.((c|m)?jsx?)$/ : /\\.((c|m)?(j|t)sx?)$/,\n          use: [\n            {\n              loader: import.meta.resolve('babel-loader'),\n              options: {\n                cacheDirectory: resolvePathInStorybookCache('babel'),\n                ...babelOptions,\n              },\n            },\n          ],\n          include: [getProjectRoot()],\n          exclude: [/node_modules/, ...Object.keys(virtualModules)],\n        },\n      ],\n    },\n  };\n};\n\nexport const core: PresetProperty<'core'> = {\n  builder: import.meta.resolve('@storybook/builder-webpack5'),\n};\n"
  },
  {
    "path": "code/frameworks/ember/src/server/framework-preset-babel-ember.ts",
    "content": "import type { PresetProperty, PresetPropertyFn } from 'storybook/internal/types';\n\nimport type { TransformOptions } from '@babel/core';\nimport { precompile } from 'ember-source/dist/ember-template-compiler.js';\n\nimport { findDistFile } from '../util.ts';\n\nlet emberOptions: any;\n\nfunction precompileWithPlugins(string: string, options: any) {\n  const precompileOptions: any = options;\n  if (emberOptions && emberOptions.polyfills) {\n    precompileOptions.plugins = { ast: emberOptions.polyfills };\n  }\n\n  return precompile(string, precompileOptions);\n}\n\nexport const babel: PresetPropertyFn<'babel'> = (config: TransformOptions, options) => {\n  if (options && options.presetsList) {\n    options.presetsList.forEach((e: any, index: number) => {\n      if (e.preset && e.preset.emberOptions) {\n        emberOptions = e.preset.emberOptions;\n        if (options.presetsList) {\n          delete options.presetsList[index].preset.emberOptions;\n        }\n      }\n    });\n  }\n\n  const babelConfigPlugins = config?.plugins || [];\n\n  const extraPlugins = [\n    [\n      import.meta.resolve('babel-plugin-htmlbars-inline-precompile'),\n      {\n        precompile: precompileWithPlugins,\n        modules: {\n          'ember-cli-htmlbars': 'hbs',\n          'ember-cli-htmlbars-inline-precompile': 'default',\n          'htmlbars-inline-precompile': 'default',\n        },\n      },\n    ],\n    [import.meta.resolve('babel-plugin-ember-modules-api-polyfill')],\n  ];\n\n  return {\n    ...config,\n    plugins: [...babelConfigPlugins, ...extraPlugins],\n  };\n};\n\nexport const previewAnnotations: PresetProperty<'previewAnnotations'> = (entry = []) => {\n  return [...entry, findDistFile(__dirname, 'client/preview/config')];\n};\n"
  },
  {
    "path": "code/frameworks/ember/src/types.ts",
    "content": "import type { CompatibleString } from 'storybook/internal/types';\n\nimport type {\n  BuilderOptions,\n  StorybookConfigWebpack,\n  TypescriptOptions as TypescriptOptionsBuilder,\n} from '@storybook/builder-webpack5';\nimport type {\n  StorybookConfig as StorybookConfigBase,\n  TypescriptOptions as TypescriptOptionsReact,\n} from '@storybook/core-webpack';\n\ntype FrameworkName = CompatibleString<'@storybook/ember-webpack5'>;\ntype BuilderName = CompatibleString<'@storybook/builder-webpack5'>;\n\nexport type FrameworkOptions = {\n  builder?: BuilderOptions;\n};\n\ntype StorybookConfigFramework = {\n  framework:\n    | FrameworkName\n    | {\n        name: FrameworkName;\n        options: FrameworkOptions;\n      };\n  core?: StorybookConfigBase['core'] & {\n    builder?:\n      | BuilderName\n      | {\n          name: BuilderName;\n          options: BuilderOptions;\n        };\n  };\n  typescript?: Partial<TypescriptOptionsBuilder & TypescriptOptionsReact> &\n    StorybookConfigBase['typescript'];\n};\n\n/** The interface for Storybook configuration in `main.ts` files. */\nexport type StorybookConfig = Omit<\n  StorybookConfigBase,\n  keyof StorybookConfigWebpack | keyof StorybookConfigFramework\n> &\n  StorybookConfigWebpack &\n  StorybookConfigFramework;\n\ndeclare global {\n  // eslint-disable-next-line no-var\n  var __EMBER_GENERATED_DOC_JSON__: any;\n}\n"
  },
  {
    "path": "code/frameworks/ember/src/typings.d.ts",
    "content": "declare module 'ember-source/dist/ember-template-compiler.js';\n\ndeclare var STORYBOOK_ENV: 'ember';\ndeclare var STORYBOOK_NAME: any;\n"
  },
  {
    "path": "code/frameworks/ember/src/util.ts",
    "content": "import { dirname, join } from 'node:path';\n\nimport { getProjectRoot } from 'storybook/internal/common';\n\nimport * as pkg from 'empathic/package';\n\nexport const findDistFile = (cwd: string, relativePath: string) => {\n  const nearestPackageJson = pkg.up({ cwd, last: getProjectRoot() });\n  if (!nearestPackageJson) {\n    throw new Error(`Could not find package.json in: ${cwd}`);\n  }\n  const packageDir = dirname(nearestPackageJson);\n\n  return join(packageDir, 'dist', relativePath);\n};\n"
  },
  {
    "path": "code/frameworks/ember/template/cli/Button.stories.js",
    "content": "import { linkTo } from '@storybook/addon-links';\n\nimport { hbs } from 'ember-cli-htmlbars';\nimport { action } from 'storybook/actions';\nimport { fn } from 'storybook/test';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories\nexport default {\n  title: 'Example/Button',\n  render: (args) => ({\n    template: hbs`<button {{on \"click\" this.onClick}}>{{this.label}}</button>`,\n    context: args,\n  }),\n  argTypes: {\n    label: { control: 'text' },\n  },\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/ember/writing-docs/autodocs\n  tags: ['autodocs'],\n  args: { onClick: fn() },\n};\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Text = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Emoji = {\n  args: {\n    label: '😀 😎 👍 💯',\n  },\n};\n\nexport const TextWithAction = {\n  render: () => ({\n    template: hbs`\n    <button {{on \"click\" this.onClick}}>\n      Trigger Action\n    </button>\n  `,\n    context: {\n      onClick: () => action('This was clicked')(),\n    },\n  }),\n  name: 'With an action',\n  parameters: {\n    notes: 'My notes on a button with emojis',\n  },\n};\n\nexport const ButtonWithLinkToAnotherStory = {\n  render: () => ({\n    template: hbs`\n    <button {{on \"click\" this.onClick}}>\n      Go to Welcome Story\n    </button>\n  `,\n    context: {\n      onClick: linkTo('example-button--docs'),\n    },\n  }),\n  name: 'button with link to another story',\n};\n"
  },
  {
    "path": "code/frameworks/ember/template/components/index.js",
    "content": ""
  },
  {
    "path": "code/frameworks/ember/template/stories/.gitkeep",
    "content": ""
  },
  {
    "path": "code/frameworks/ember/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/frameworks/ember/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/frameworks/html-vite/README.md",
    "content": "# Storybook for HTML\n\nSee [documentation](https://storybook.js.org/docs?ref=readme) for installation instructions, usage examples, APIs, and more.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/frameworks/html-vite/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./node'],\n        entryPoint: './src/node/index.ts',\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/frameworks/html-vite/package.json",
    "content": "{\n  \"name\": \"@storybook/html-vite\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook for HTML and Vite: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-framework\",\n    \"html\",\n    \"vite\",\n    \"component\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/frameworks/html-vite\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/frameworks/html-vite\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./node\": {\n      \"types\": \"./dist/node/index.d.ts\",\n      \"code\": \"./src/node/index.ts\",\n      \"default\": \"./dist/node/index.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"template/cli/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/builder-vite\": \"workspace:*\",\n    \"@storybook/html\": \"workspace:*\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.19.1\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"storybook\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/frameworks/html-vite/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/frameworks/html-vite/project.json",
    "content": "{\n  \"name\": \"html-vite\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/frameworks/html-vite/src/index.ts",
    "content": "export * from '@storybook/html';\nexport * from './types.ts';\n"
  },
  {
    "path": "code/frameworks/html-vite/src/node/index.ts",
    "content": "import type { StorybookConfig } from '../types.ts';\n\nexport function defineMain(config: StorybookConfig) {\n  return config;\n}\n\nexport type { StorybookConfig };\n"
  },
  {
    "path": "code/frameworks/html-vite/src/preset.ts",
    "content": "import type { PresetProperty } from 'storybook/internal/types';\n\nexport const core: PresetProperty<'core'> = {\n  builder: import.meta.resolve('@storybook/builder-vite'),\n  renderer: import.meta.resolve('@storybook/html/preset'),\n};\n"
  },
  {
    "path": "code/frameworks/html-vite/src/types.ts",
    "content": "import type {\n  CompatibleString,\n  StorybookConfig as StorybookConfigBase,\n} from 'storybook/internal/types';\n\nimport type { BuilderOptions, StorybookConfigVite } from '@storybook/builder-vite';\n\ntype FrameworkName = CompatibleString<'@storybook/html-vite'>;\ntype BuilderName = CompatibleString<'@storybook/builder-vite'>;\n\nexport type FrameworkOptions = {\n  builder?: BuilderOptions;\n};\n\ntype StorybookConfigFramework = {\n  framework:\n    | FrameworkName\n    | {\n        name: FrameworkName;\n        options: FrameworkOptions;\n      };\n  core?: StorybookConfigBase['core'] & {\n    builder?:\n      | BuilderName\n      | {\n          name: BuilderName;\n          options: BuilderOptions;\n        };\n  };\n};\n\n/** The interface for Storybook configuration in `main.ts` files. */\nexport type StorybookConfig = Omit<\n  StorybookConfigBase,\n  keyof StorybookConfigVite | keyof StorybookConfigFramework\n> &\n  StorybookConfigVite &\n  StorybookConfigFramework;\n"
  },
  {
    "path": "code/frameworks/html-vite/template/cli/.eslintrc.json",
    "content": "{\n  \"rules\": {\n    \"no-undef\": \"off\",\n    \"import/extensions\": \"off\"\n  }\n}\n"
  },
  {
    "path": "code/frameworks/html-vite/template/cli/js/Button.js",
    "content": "import './button.css';\n\nexport const createButton = ({\n  primary = false,\n  size = 'medium',\n  backgroundColor,\n  label,\n  onClick,\n}) => {\n  const btn = document.createElement('button');\n  btn.type = 'button';\n  btn.innerText = label;\n  btn.addEventListener('click', onClick);\n\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n  btn.className = ['storybook-button', `storybook-button--${size}`, mode].join(' ');\n\n  btn.style.backgroundColor = backgroundColor;\n\n  return btn;\n};\n"
  },
  {
    "path": "code/frameworks/html-vite/template/cli/js/Button.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport { createButton } from './Button';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories\nexport default {\n  title: 'Example/Button',\n  tags: ['autodocs'],\n  render: ({ label, ...args }) => {\n    // You can either use a function to create DOM elements or use a plain html string!\n    // return `<div>${label}</div>`;\n    return createButton({ label, ...args });\n  },\n  argTypes: {\n    backgroundColor: { control: 'color' },\n    label: { control: 'text' },\n    onClick: { action: 'onClick' },\n    primary: { control: 'boolean' },\n    size: {\n      control: { type: 'select' },\n      options: ['small', 'medium', 'large'],\n    },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onClick: fn() },\n};\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/html-vite/template/cli/js/Header.js",
    "content": "import { createButton } from './Button';\nimport './header.css';\n\nexport const createHeader = ({ user, onLogout, onLogin, onCreateAccount }) => {\n  const header = document.createElement('header');\n\n  const wrapper = document.createElement('div');\n  wrapper.className = 'storybook-header';\n\n  const logo = `<div>\n    <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n      <g fill=\"none\" fillRule=\"evenodd\">\n        <path\n          d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n          fill=\"#FFF\" />\n        <path\n          d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n          fill=\"#555AB9\" />\n        <path d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\" fill=\"#91BAF8\" />\n      </g>\n    </svg>\n    <h1>Acme</h1>\n  </div>`;\n\n  wrapper.insertAdjacentHTML('afterbegin', logo);\n\n  const account = document.createElement('div');\n  if (user) {\n    const welcomeMessage = `<span class=\"welcome\">Welcome, <b>${user.name}</b>!</span>`;\n    account.innerHTML = welcomeMessage;\n    account.appendChild(createButton({ size: 'small', label: 'Log out', onClick: onLogout }));\n  } else {\n    account.appendChild(createButton({ size: 'small', label: 'Log in', onClick: onLogin }));\n    account.appendChild(\n      createButton({\n        size: 'small',\n        label: 'Sign up',\n        onClick: onCreateAccount,\n        primary: true,\n      })\n    );\n  }\n  wrapper.appendChild(account);\n  header.appendChild(wrapper);\n\n  return header;\n};\n"
  },
  {
    "path": "code/frameworks/html-vite/template/cli/js/Header.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport { createHeader } from './Header';\n\nexport default {\n  title: 'Example/Header',\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  render: (args) => createHeader(args),\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n};\n\nexport const LoggedIn = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut = {};\n"
  },
  {
    "path": "code/frameworks/html-vite/template/cli/js/Page.js",
    "content": "import { createHeader } from './Header';\nimport './page.css';\n\nexport const createPage = () => {\n  const article = document.createElement('article');\n  let user = null;\n  let header = null;\n\n  const rerenderHeader = () => {\n    const wrapper = document.getElementsByTagName('article')[0];\n    wrapper.replaceChild(createHeaderElement(), wrapper.firstChild);\n  };\n\n  const onLogin = () => {\n    user = { name: 'Jane Doe' };\n    rerenderHeader();\n  };\n\n  const onLogout = () => {\n    user = null;\n    rerenderHeader();\n  };\n\n  const onCreateAccount = () => {\n    user = { name: 'Jane Doe' };\n    rerenderHeader();\n  };\n\n  const createHeaderElement = () => {\n    return createHeader({ onLogin, onLogout, onCreateAccount, user });\n  };\n\n  header = createHeaderElement();\n  article.appendChild(header);\n\n  const section = `\n  <section class=\"storybook-page\">\n    <h2>Pages in Storybook</h2>\n    <p>\n      We recommend building UIs with a\n      <a\n        href=\"https://blog.hichroma.com/component-driven-development-ce1109d56c8e\"\n        target=\"_blank\"\n        rel=\"noopener noreferrer\">\n        <strong>component-driven</strong>\n      </a>\n      process starting with atomic components and ending with pages.\n    </p>\n    <p>\n      Render pages with mock data. This makes it easy to build and review page states without\n      needing to navigate to them in your app. Here are some handy patterns for managing page data\n      in Storybook:\n    </p>\n    <ul>\n      <li>\n        Use a higher-level connected component. Storybook helps you compose such data from the\n        \"args\" of child component stories\n      </li>\n      <li>\n        Assemble data in the page component from your services. You can mock these services out\n        using Storybook.\n      </li>\n    </ul>\n    <p>\n      Get a guided tutorial on component-driven development at\n      <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n        Storybook tutorials\n      </a>\n      . Read more in the\n      <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">docs</a>\n      .\n    </p>\n    <div class=\"tip-wrapper\">\n      <span class=\"tip\">Tip</span>\n      Adjust the width of the canvas with the\n      <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n        <g fill=\"none\" fillRule=\"evenodd\">\n          <path\n            d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0\n            01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0\n            010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n            id=\"a\"\n            fill=\"#999\" />\n        </g>\n      </svg>\n      Viewports addon in the toolbar\n    </div>\n  </section>\n`;\n\n  article.insertAdjacentHTML('beforeend', section);\n\n  return article;\n};\n"
  },
  {
    "path": "code/frameworks/html-vite/template/cli/js/Page.stories.js",
    "content": "import { expect, userEvent, within } from 'storybook/test';\n\nimport { createPage } from './Page';\n\nexport default {\n  title: 'Example/Page',\n  render: () => createPage(),\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n};\n\nexport const LoggedOut = {};\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await expect(loginButton).not.toBeInTheDocument();\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n"
  },
  {
    "path": "code/frameworks/html-vite/template/cli/ts/Button.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/html-vite';\n\nimport { fn } from 'storybook/test';\n\nimport type { ButtonProps } from './Button';\nimport { createButton } from './Button';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export\nconst meta = {\n  title: 'Example/Button',\n  tags: ['autodocs'],\n  render: (args) => {\n    // You can either use a function to create DOM elements or use a plain html string!\n    // return `<div>${label}</div>`;\n    return createButton(args);\n  },\n  argTypes: {\n    backgroundColor: { control: 'color' },\n    label: { control: 'text' },\n    onClick: { action: 'onClick' },\n    primary: { control: 'boolean' },\n    size: {\n      control: { type: 'select' },\n      options: ['small', 'medium', 'large'],\n    },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onClick: fn() },\n} satisfies Meta<ButtonProps>;\n\nexport default meta;\ntype Story = StoryObj<ButtonProps>;\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large: Story = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small: Story = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/html-vite/template/cli/ts/Button.ts",
    "content": "import './button.css';\n\nexport interface ButtonProps {\n  /** Is this the principal call to action on the page? */\n  primary?: boolean;\n  /** What background color to use */\n  backgroundColor?: string;\n  /** How large should the button be? */\n  size?: 'small' | 'medium' | 'large';\n  /** Button contents */\n  label: string;\n  /** Optional click handler */\n  onClick?: () => void;\n}\n\n/** Primary UI component for user interaction */\nexport const createButton = ({\n  primary = false,\n  size = 'medium',\n  backgroundColor,\n  label,\n  onClick,\n}: ButtonProps) => {\n  const btn = document.createElement('button');\n  btn.type = 'button';\n  btn.innerText = label;\n  if (onClick) {\n    btn.addEventListener('click', onClick);\n  }\n\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n  btn.className = ['storybook-button', `storybook-button--${size}`, mode].join(' ');\n\n  if (backgroundColor) {\n    btn.style.backgroundColor = backgroundColor;\n  }\n\n  return btn;\n};\n"
  },
  {
    "path": "code/frameworks/html-vite/template/cli/ts/Header.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/html-vite';\n\nimport { fn } from 'storybook/test';\n\nimport type { HeaderProps } from './Header';\nimport { createHeader } from './Header';\n\nconst meta = {\n  title: 'Example/Header',\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  render: (args) => createHeader(args),\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n} satisfies Meta<HeaderProps>;\n\nexport default meta;\ntype Story = StoryObj<HeaderProps>;\n\nexport const LoggedIn: Story = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut: Story = {};\n"
  },
  {
    "path": "code/frameworks/html-vite/template/cli/ts/Header.ts",
    "content": "import { createButton } from './Button';\nimport './header.css';\n\nexport interface HeaderProps {\n  user?: { name: string };\n  onLogin?: () => void;\n  onLogout?: () => void;\n  onCreateAccount?: () => void;\n}\n\nexport const createHeader = ({ user, onLogout, onLogin, onCreateAccount }: HeaderProps) => {\n  const header = document.createElement('header');\n\n  const wrapper = document.createElement('div');\n  wrapper.className = 'storybook-header';\n\n  const logo = `<div>\n    <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n      <g fill=\"none\" fillRule=\"evenodd\">\n        <path\n          d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n          fill=\"#FFF\" />\n        <path\n          d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n          fill=\"#555AB9\" />\n        <path d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\" fill=\"#91BAF8\" />\n      </g>\n    </svg>\n    <h1>Acme</h1>\n  </div>`;\n\n  wrapper.insertAdjacentHTML('afterbegin', logo);\n\n  const account = document.createElement('div');\n  if (user) {\n    const welcomeMessage = `<span class=\"welcome\">Welcome, <b>${user.name}</b>!</span>`;\n    account.innerHTML = welcomeMessage;\n    account.appendChild(createButton({ size: 'small', label: 'Log out', onClick: onLogout }));\n  } else {\n    account.appendChild(createButton({ size: 'small', label: 'Log in', onClick: onLogin }));\n    account.appendChild(\n      createButton({\n        size: 'small',\n        label: 'Sign up',\n        onClick: onCreateAccount,\n        primary: true,\n      })\n    );\n  }\n  wrapper.appendChild(account);\n  header.appendChild(wrapper);\n\n  return header;\n};\n"
  },
  {
    "path": "code/frameworks/html-vite/template/cli/ts/Page.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/html-vite';\n\nimport { expect, userEvent, within } from 'storybook/test';\n\nimport { createPage } from './Page';\n\nconst meta = {\n  title: 'Example/Page',\n  render: () => createPage(),\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n} satisfies Meta;\n\nexport default meta;\n\nexport const LoggedOut: StoryObj = {};\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn: StoryObj = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await expect(loginButton).not.toBeInTheDocument();\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n"
  },
  {
    "path": "code/frameworks/html-vite/template/cli/ts/Page.ts",
    "content": "import { createHeader } from './Header';\nimport './page.css';\n\ntype User = {\n  name: string;\n};\n\nexport const createPage = () => {\n  const article = document.createElement('article');\n  let user: User | undefined;\n  let header: HTMLElement | null = null;\n\n  const rerenderHeader = () => {\n    const wrapper = document.getElementsByTagName('article')[0];\n    wrapper.replaceChild(createHeaderElement(), wrapper.firstChild as HTMLElement);\n  };\n\n  const onLogin = () => {\n    user = { name: 'Jane Doe' };\n    rerenderHeader();\n  };\n\n  const onLogout = () => {\n    user = undefined;\n    rerenderHeader();\n  };\n\n  const onCreateAccount = () => {\n    user = { name: 'Jane Doe' };\n    rerenderHeader();\n  };\n\n  const createHeaderElement = () => {\n    return createHeader({ onLogin, onLogout, onCreateAccount, user });\n  };\n\n  header = createHeaderElement();\n  article.appendChild(header);\n\n  const section = `\n  <section class=\"storybook-page\">\n    <h2>Pages in Storybook</h2>\n    <p>\n      We recommend building UIs with a\n      <a\n        href=\"https://blog.hichroma.com/component-driven-development-ce1109d56c8e\"\n        target=\"_blank\"\n        rel=\"noopener noreferrer\">\n        <strong>component-driven</strong>\n      </a>\n      process starting with atomic components and ending with pages.\n    </p>\n    <p>\n      Render pages with mock data. This makes it easy to build and review page states without\n      needing to navigate to them in your app. Here are some handy patterns for managing page data\n      in Storybook:\n    </p>\n    <ul>\n      <li>\n        Use a higher-level connected component. Storybook helps you compose such data from the\n        \"args\" of child component stories\n      </li>\n      <li>\n        Assemble data in the page component from your services. You can mock these services out\n        using Storybook.\n      </li>\n    </ul>\n    <p>\n      Get a guided tutorial on component-driven development at\n      <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n        Storybook tutorials\n      </a>\n      . Read more in the\n      <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">docs</a>\n      .\n    </p>\n    <div class=\"tip-wrapper\">\n      <span class=\"tip\">Tip</span>\n      Adjust the width of the canvas with the\n      <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n        <g fill=\"none\" fillRule=\"evenodd\">\n          <path\n            d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0\n            01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0\n            010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n            id=\"a\"\n            fill=\"#999\" />\n        </g>\n      </svg>\n      Viewports addon in the toolbar\n    </div>\n  </section>\n`;\n\n  article.insertAdjacentHTML('beforeend', section);\n\n  return article;\n};\n"
  },
  {
    "path": "code/frameworks/html-vite/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"storybook/internal/*\": [\"../../lib/cli/core/*\"]\n    },\n    \"rootDir\": \"./src\"\n  },\n  \"exclude\": [\"src/**/*.test.*\", \"src/**/__testfixtures__/**\"],\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/.eslintrc.json",
    "content": "{\n  \"rules\": {\n    \"global-require\": \"off\",\n    \"no-param-reassign\": \"off\",\n    \"import/no-dynamic-require\": \"off\"\n  },\n  \"overrides\": [\n    {\n      \"files\": [\"**/*.stories.@(jsx|tsx)\"],\n      \"rules\": {\n        \"react/no-unknown-property\": \"off\",\n        \"jsx-a11y/anchor-is-valid\": \"off\"\n      }\n    },\n    {\n      \"files\": [\"**/*.compat.@(tsx|ts)\"],\n      \"rules\": {\n        \"local-rules/no-uncategorized-errors\": \"off\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/README.md",
    "content": "# Storybook for Next.js\n\nSee [documentation](https://storybook.js.org/docs/get-started/frameworks/nextjs?renderer=react&ref=readme) for installation instructions, usage examples, APIs, and more.\n\n## Acknowledgements\n\nThis framework borrows heavily from these Storybook addons:\n\n- [storybook-addon-next](https://github.com/RyanClementsHax/storybook-addon-next) by [RyanClementsHax](https://github.com/RyanClementsHax/)\n- [storybook-addon-next-router](https://github.com/lifeiscontent/storybook-addon-next-router) by [lifeiscontent](https://github.com/lifeiscontent)\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/frameworks/nextjs/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./preview'],\n        entryPoint: './src/preview.tsx',\n      },\n      {\n        exportEntries: ['./config/preview'],\n        entryPoint: './src/config/preview.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./cache.mock'],\n        entryPoint: './src/export-mocks/cache/index.ts',\n      },\n      {\n        exportEntries: ['./headers.mock'],\n        entryPoint: './src/export-mocks/headers/index.ts',\n      },\n      {\n        exportEntries: ['./navigation.mock'],\n        entryPoint: './src/export-mocks/navigation/index.ts',\n      },\n      {\n        exportEntries: ['./link.mock'],\n        entryPoint: './src/export-mocks/link/index.tsx',\n      },\n      {\n        exportEntries: ['./router.mock'],\n        entryPoint: './src/export-mocks/router/index.ts',\n      },\n      {\n        exportEntries: ['./compatibility/draft-mode.compat'],\n        entryPoint: './src/compatibility/draft-mode.compat.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./next-image-loader-stub'],\n        entryPoint: './src/next-image-loader-stub.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./image-context'],\n        entryPoint: './src/image-context.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./images/next-image'],\n        entryPoint: './src/images/next-image.tsx',\n        dts: false,\n      },\n      {\n        exportEntries: ['./images/next-legacy-image'],\n        entryPoint: './src/images/next-legacy-image.tsx',\n        dts: false,\n      },\n      {\n        exportEntries: ['./rsc/server-only'],\n        entryPoint: './src/rsc/server-only.ts',\n        dts: false,\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./node'],\n        entryPoint: './src/node/index.ts',\n      },\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./export-mocks'],\n        entryPoint: './src/export-mocks/index.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./next-swc-loader-patch'],\n        entryPoint: './src/swc/next-swc-loader-patch.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./storybook-nextjs-font-loader'],\n        entryPoint: './src/font/webpack/loader/storybook-nextjs-font-loader.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/frameworks/nextjs/package.json",
    "content": "{\n  \"name\": \"@storybook/nextjs\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook for Next.js: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"next\",\n    \"next.js\",\n    \"webpack\",\n    \"component\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/frameworks/nextjs\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/frameworks/nextjs\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./cache.mock\": {\n      \"types\": \"./dist/export-mocks/cache/index.d.ts\",\n      \"code\": \"./src/export-mocks/cache/index.ts\",\n      \"default\": \"./dist/export-mocks/cache/index.js\"\n    },\n    \"./compatibility/draft-mode.compat\": \"./dist/compatibility/draft-mode.compat.js\",\n    \"./config/preview\": \"./dist/config/preview.js\",\n    \"./export-mocks\": \"./dist/export-mocks/index.js\",\n    \"./headers.mock\": {\n      \"types\": \"./dist/export-mocks/headers/index.d.ts\",\n      \"code\": \"./src/export-mocks/headers/index.ts\",\n      \"default\": \"./dist/export-mocks/headers/index.js\"\n    },\n    \"./image-context\": \"./dist/image-context.js\",\n    \"./images/next-image\": \"./dist/images/next-image.js\",\n    \"./images/next-legacy-image\": \"./dist/images/next-legacy-image.js\",\n    \"./link.mock\": {\n      \"types\": \"./dist/export-mocks/link/index.d.ts\",\n      \"code\": \"./src/export-mocks/link/index.tsx\",\n      \"default\": \"./dist/export-mocks/link/index.js\"\n    },\n    \"./navigation.mock\": {\n      \"types\": \"./dist/export-mocks/navigation/index.d.ts\",\n      \"code\": \"./src/export-mocks/navigation/index.ts\",\n      \"default\": \"./dist/export-mocks/navigation/index.js\"\n    },\n    \"./next-image-loader-stub\": \"./dist/next-image-loader-stub.js\",\n    \"./next-swc-loader-patch\": \"./dist/swc/next-swc-loader-patch.js\",\n    \"./node\": {\n      \"types\": \"./dist/node/index.d.ts\",\n      \"code\": \"./src/node/index.ts\",\n      \"default\": \"./dist/node/index.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\",\n    \"./preview\": {\n      \"types\": \"./dist/preview.d.ts\",\n      \"code\": \"./src/preview.tsx\",\n      \"default\": \"./dist/preview.js\"\n    },\n    \"./router.mock\": {\n      \"types\": \"./dist/export-mocks/router/index.d.ts\",\n      \"code\": \"./src/export-mocks/router/index.ts\",\n      \"default\": \"./dist/export-mocks/router/index.js\"\n    },\n    \"./rsc/server-only\": \"./dist/rsc/server-only.js\",\n    \"./storybook-nextjs-font-loader\": \"./dist/font/webpack/loader/storybook-nextjs-font-loader.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"template/cli/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@babel/core\": \"^7.28.5\",\n    \"@babel/plugin-syntax-bigint\": \"^7.8.3\",\n    \"@babel/plugin-syntax-dynamic-import\": \"^7.8.3\",\n    \"@babel/plugin-syntax-import-assertions\": \"^7.27.1\",\n    \"@babel/plugin-transform-class-properties\": \"^7.27.1\",\n    \"@babel/plugin-transform-export-namespace-from\": \"^7.27.1\",\n    \"@babel/plugin-transform-numeric-separator\": \"^7.27.1\",\n    \"@babel/plugin-transform-object-rest-spread\": \"^7.28.4\",\n    \"@babel/plugin-transform-runtime\": \"^7.28.5\",\n    \"@babel/preset-env\": \"^7.28.5\",\n    \"@babel/preset-react\": \"^7.28.5\",\n    \"@babel/preset-typescript\": \"^7.28.5\",\n    \"@babel/runtime\": \"^7.28.4\",\n    \"@pmmmwh/react-refresh-webpack-plugin\": \"^0.5.11\",\n    \"@storybook/builder-webpack5\": \"workspace:*\",\n    \"@storybook/preset-react-webpack\": \"workspace:*\",\n    \"@storybook/react\": \"workspace:*\",\n    \"@types/semver\": \"^7.7.1\",\n    \"babel-loader\": \"^9.1.3\",\n    \"css-loader\": \"^6.7.3\",\n    \"image-size\": \"^2.0.2\",\n    \"loader-utils\": \"^3.2.1\",\n    \"node-polyfill-webpack-plugin\": \"^2.0.1\",\n    \"postcss\": \"^8.4.38\",\n    \"postcss-loader\": \"^8.1.1\",\n    \"react-refresh\": \"^0.14.0\",\n    \"resolve-url-loader\": \"^5.0.0\",\n    \"sass-loader\": \"^16.0.5\",\n    \"semver\": \"^7.7.3\",\n    \"style-loader\": \"^3.3.1\",\n    \"styled-jsx\": \"^5.1.6\",\n    \"tsconfig-paths\": \"^4.0.0\",\n    \"tsconfig-paths-webpack-plugin\": \"^4.0.1\"\n  },\n  \"devDependencies\": {\n    \"@babel/types\": \"^7.28.5\",\n    \"@types/babel__core\": \"^7\",\n    \"@types/babel__plugin-transform-runtime\": \"^7\",\n    \"@types/babel__preset-env\": \"^7\",\n    \"@types/loader-utils\": \"^2.0.5\",\n    \"@types/node\": \"^22.19.1\",\n    \"@types/react-refresh\": \"^0\",\n    \"next\": \"^15.2.3\",\n    \"typescript\": \"^5.9.3\",\n    \"webpack\": \"^5.65.0\"\n  },\n  \"peerDependencies\": {\n    \"next\": \"^14.1.0 || ^15.0.0 || ^16.0.0\",\n    \"react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"storybook\": \"workspace:^\",\n    \"webpack\": \"^5.0.0\"\n  },\n  \"peerDependenciesMeta\": {\n    \"typescript\": {\n      \"optional\": true\n    },\n    \"webpack\": {\n      \"optional\": true\n    }\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/frameworks/nextjs/project.json",
    "content": "{\n  \"name\": \"nextjs\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/src/aliases/webpack.ts",
    "content": "import type { Configuration as WebpackConfig } from 'webpack';\n\nimport { resolvePackageDir } from '../../../../core/src/shared/utils/module.ts';\nimport { configureCompatibilityAliases } from '../compatibility/compatibility-map.ts';\nimport { configureNextExportMocks } from '../export-mocks/webpack.ts';\n\nexport const configureAliases = (baseConfig: WebpackConfig): void => {\n  configureNextExportMocks(baseConfig);\n  configureCompatibilityAliases(baseConfig);\n\n  baseConfig.resolve = {\n    ...(baseConfig.resolve ?? {}),\n    alias: {\n      ...(baseConfig.resolve?.alias ?? {}),\n      '@opentelemetry/api': 'next/dist/compiled/@opentelemetry/api',\n      next: resolvePackageDir('next'),\n      'next/dist/shared/lib/app-router-context.shared-runtime':\n        'next/dist/shared/lib/app-router-context.shared-runtime',\n      'next/dist/shared/lib/app-router-context':\n        'next/dist/shared/lib/app-router-context.shared-runtime',\n    },\n  };\n\n  // remove warnings regarding compatibility paths\n  baseConfig.ignoreWarnings = [\n    ...(baseConfig.ignoreWarnings ?? []),\n    (warning) =>\n      warning.message.includes(\"export 'draftMode'\") &&\n      warning.message.includes('next/dist/server/request/headers'),\n  ];\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/babel/loader.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport { getProjectRoot, resolvePathInStorybookCache } from 'storybook/internal/common';\nimport type { Options } from 'storybook/internal/types';\n\nimport { getVirtualModules } from '@storybook/builder-webpack5';\n\nimport type { NextConfig } from 'next';\n\nimport { getNodeModulesExcludeRegex } from '../utils.ts';\n\nexport const configureBabelLoader = async (\n  baseConfig: any,\n  options: Options,\n  nextConfig: NextConfig\n) => {\n  const { virtualModules } = await getVirtualModules(options);\n\n  const babelOptions = await options.presets.apply('babel', {}, options);\n  const typescriptOptions = await options.presets.apply('typescript', {}, options);\n\n  baseConfig.module.rules = [\n    ...baseConfig.module.rules,\n    {\n      test: typescriptOptions.skipCompiler ? /\\.((c|m)?jsx?)$/ : /\\.((c|m)?(j|t)sx?)$/,\n      use: [\n        {\n          loader: fileURLToPath(import.meta.resolve('babel-loader')),\n          options: {\n            cacheDirectory: resolvePathInStorybookCache('babel'),\n            ...babelOptions,\n          },\n        },\n      ],\n      include: [getProjectRoot()],\n      exclude: [\n        getNodeModulesExcludeRegex(nextConfig.transpilePackages ?? []),\n        ...Object.keys(virtualModules),\n      ],\n    },\n  ];\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/babel/plugins/amp-attributes.ts",
    "content": "import type { NodePath, PluginObj, types } from '@babel/core';\n\n/**\n * Source:\n * https://github.com/vercel/next.js/blob/canary/packages/next/src/build/babel/plugins/amp-attributes.ts\n */\nexport default function AmpAttributePatcher(): PluginObj {\n  return {\n    visitor: {\n      JSXOpeningElement(path: NodePath<types.JSXOpeningElement>) {\n        const openingElement = path.node;\n\n        const { name, attributes } = openingElement;\n        if (!(name && name.type === 'JSXIdentifier')) {\n          return;\n        }\n\n        if (!name.name.startsWith('amp-')) {\n          return;\n        }\n\n        for (const attribute of attributes) {\n          if (attribute.type !== 'JSXAttribute') {\n            continue;\n          }\n\n          if (attribute.name.name === 'className') {\n            attribute.name.name = 'class';\n          }\n        }\n      },\n    },\n  };\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/src/babel/plugins/jsx-pragma.ts",
    "content": "/**\n * Source:\n * https://github.com/vercel/next.js/blob/canary/packages/next/src/build/babel/plugins/jsx-pragma.ts\n */\nimport type { types as BabelTypes, NodePath, PluginObj } from '@babel/core';\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-expect-error\nimport jsx from 'next/dist/compiled/babel/plugin-syntax-jsx.js';\n\nexport default function jsxPragma({ types: t }: { types: typeof BabelTypes }): PluginObj<any> {\n  return {\n    inherits: jsx,\n    visitor: {\n      JSXElement(_path, state) {\n        state.set('jsx', true);\n      },\n\n      // Fragment syntax is still JSX since it compiles to createElement(),\n      // but JSXFragment is not a JSXElement\n      JSXFragment(_path, state) {\n        state.set('jsx', true);\n      },\n\n      Program: {\n        exit(path: NodePath<BabelTypes.Program>, state) {\n          if (state.get('jsx')) {\n            const pragma = t.identifier(state.opts.pragma);\n            let importAs = pragma;\n\n            // if there's already a React in scope, use that instead of adding an import\n            const existingBinding =\n              state.opts.reuseImport !== false &&\n              state.opts.importAs &&\n              path.scope.getBinding(state.opts.importAs);\n\n            // var _jsx = _pragma.createElement;\n            if (state.opts.property) {\n              if (state.opts.importAs) {\n                importAs = t.identifier(state.opts.importAs);\n              } else {\n                importAs = path.scope.generateUidIdentifier('pragma');\n              }\n\n              const mapping = t.variableDeclaration('var', [\n                t.variableDeclarator(\n                  pragma,\n                  t.memberExpression(importAs, t.identifier(state.opts.property))\n                ),\n              ]);\n\n              // if the React binding came from a require('react'),\n              // make sure that our usage comes after it.\n              let newPath: NodePath<BabelTypes.VariableDeclaration>;\n\n              if (\n                existingBinding &&\n                t.isVariableDeclarator(existingBinding.path.node) &&\n                t.isCallExpression(existingBinding.path.node.init) &&\n                t.isIdentifier(existingBinding.path.node.init.callee) &&\n                existingBinding.path.node.init.callee.name === 'require'\n              ) {\n                [newPath] = existingBinding.path.parentPath.insertAfter(mapping);\n              } else {\n                [newPath] = path.unshiftContainer('body', mapping);\n              }\n\n              for (const declar of newPath.get('declarations')) {\n                const kind = (['var', 'let', 'const'].find((k) => newPath.node.kind === k) ||\n                  'const') as 'var' | 'let' | 'const';\n                path.scope.registerBinding(kind, declar as NodePath<BabelTypes.Node>);\n              }\n            }\n\n            if (!existingBinding) {\n              const importSpecifier = t.importDeclaration(\n                [\n                  state.opts.import\n                    ? // import { $import as _pragma } from '$module'\n                      t.importSpecifier(importAs, t.identifier(state.opts.import))\n                    : state.opts.importNamespace\n                      ? t.importNamespaceSpecifier(importAs)\n                      : // import _pragma from '$module'\n                        t.importDefaultSpecifier(importAs),\n                ],\n                t.stringLiteral(state.opts.module || 'react')\n              );\n\n              const [newPath] = path.unshiftContainer('body', importSpecifier);\n              for (const specifier of newPath.get('specifiers')) {\n                path.scope.registerBinding('module', specifier as NodePath<BabelTypes.Node>);\n              }\n            }\n          }\n        },\n      },\n    },\n  };\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/src/babel/plugins/optimize-hook-destructuring.ts",
    "content": "/**\n * Source:\n * https://github.com/vercel/next.js/blob/canary/packages/next/src/build/babel/plugins/optimize-hook-destructuring.ts\n */\nimport type { types as BabelTypes, NodePath, PluginObj } from '@babel/core';\n\n// matches any hook-like (the default)\nconst isHook = /^use[A-Z]/;\n\n// matches only built-in hooks provided by React et al\nconst isBuiltInHook =\n  /^use(Callback|Context|DebugValue|Effect|ImperativeHandle|LayoutEffect|Memo|Reducer|Ref|State)$/;\n\nexport default function optimizeHookDestructuring({\n  types: t,\n}: {\n  types: typeof BabelTypes;\n}): PluginObj<any> {\n  const visitor = {\n    CallExpression(path: NodePath<BabelTypes.CallExpression>, state: any) {\n      const { onlyBuiltIns } = state.opts;\n\n      // if specified, options.lib is a list of libraries that provide hook functions\n      const libs =\n        state.opts.lib &&\n        (state.opts.lib === true ? ['react', 'preact/hooks'] : [].concat(state.opts.lib));\n\n      // skip function calls that are not the init of a variable declaration:\n\n      // skip function calls that are not the init of a variable declaration:\n      if (!t.isVariableDeclarator(path.parent)) {\n        return;\n      }\n\n      // skip function calls where the return value is not Array-destructured:\n\n      // skip function calls where the return value is not Array-destructured:\n\n      // skip function calls where the return value is not Array-destructured:\n      if (!t.isArrayPattern(path.parent.id)) {\n        return;\n      }\n\n      // name of the (hook) function being called:\n\n      // name of the (hook) function being called:\n      const hookName = (path.node.callee as BabelTypes.Identifier).name;\n\n      if (libs) {\n        const binding = path.scope.getBinding(hookName);\n        // not an import\n\n        // not an import\n        if (!binding || binding.kind !== 'module') {\n          return;\n        }\n\n        const specifier = (binding.path.parent as BabelTypes.ImportDeclaration).source.value;\n        // not a match\n\n        // not a match\n        if (!libs.some((lib: any) => lib === specifier)) {\n          return;\n        }\n      }\n\n      // only match function calls with names that look like a hook\n\n      // only match function calls with names that look like a hook\n      if (!(onlyBuiltIns ? isBuiltInHook : isHook).test(hookName)) {\n        return;\n      }\n\n      path.parent.id = t.objectPattern(\n        path.parent.id.elements.reduce<Array<BabelTypes.ObjectProperty>>((patterns, element, i) => {\n          if (element === null) {\n            return patterns;\n          }\n\n          return patterns.concat(t.objectProperty(t.numericLiteral(i), element as any));\n        }, [])\n      );\n    },\n  };\n\n  return {\n    name: 'optimize-hook-destructuring',\n    visitor: {\n      // this is a workaround to run before preset-env destroys destructured assignments\n      Program(path, state) {\n        path.traverse(visitor, state);\n      },\n    },\n  };\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/src/babel/plugins/react-loadable-plugin.ts",
    "content": "/**\n * Source:\n * https://github.com/vercel/next.js/blob/canary/packages/next/src/build/babel/plugins/react-loadable-plugin.ts\n */\nimport { relative as relativePath } from 'node:path';\n\nimport type { types as BabelTypes, NodePath, PluginObj } from '@babel/core';\n\nexport default function ({ types: t }: { types: typeof BabelTypes }): PluginObj {\n  return {\n    visitor: {\n      ImportDeclaration(path: NodePath<BabelTypes.ImportDeclaration>, state: any) {\n        const source = path.node.source.value;\n\n        if (source !== 'next/dynamic') {\n          return;\n        }\n\n        const defaultSpecifier = path.get('specifiers').find((specifier: any) => {\n          return specifier.isImportDefaultSpecifier();\n        });\n\n        if (!defaultSpecifier) {\n          return;\n        }\n\n        const bindingName = defaultSpecifier.node.local.name;\n        const binding = path.scope.getBinding(bindingName);\n\n        if (!binding) {\n          return;\n        }\n\n        binding.referencePaths.forEach((refPath: any) => {\n          let callExpression = refPath.parentPath;\n\n          if (callExpression.isMemberExpression() && callExpression.node.computed === false) {\n            const property = callExpression.get('property');\n            if (!Array.isArray(property) && property.isIdentifier({ name: 'Map' })) {\n              callExpression = callExpression.parentPath;\n            }\n          }\n\n          if (!callExpression.isCallExpression()) {\n            return;\n          }\n\n          const callExpression_ = callExpression as NodePath<BabelTypes.CallExpression>;\n\n          let args = callExpression_.get('arguments');\n          if (args.length > 2) {\n            throw callExpression_.buildCodeFrameError('next/dynamic only accepts 2 arguments');\n          }\n\n          if (!args[0]) {\n            return;\n          }\n\n          let loader;\n          let options;\n\n          if (args[0].isObjectExpression()) {\n            options = args[0];\n          } else {\n            if (!args[1]) {\n              callExpression_.node.arguments.push(t.objectExpression([]));\n            }\n            // This is needed as the code is modified above\n            args = callExpression_.get('arguments');\n            loader = args[0];\n            options = args[1];\n          }\n\n          if (!options.isObjectExpression()) {\n            return;\n          }\n          const options_ = options as NodePath<BabelTypes.ObjectExpression>;\n\n          const properties = options_.get('properties');\n          const propertiesMap: {\n            [key: string]: NodePath<\n              | BabelTypes.ObjectProperty\n              | BabelTypes.ObjectMethod\n              | BabelTypes.SpreadElement\n              | BabelTypes.BooleanLiteral\n            >;\n          } = {};\n\n          properties.forEach((property) => {\n            const key: any = property.get('key');\n            propertiesMap[key.node.name] = property;\n          });\n\n          if (propertiesMap.loadableGenerated) {\n            return;\n          }\n\n          if (propertiesMap.loader) {\n            loader = propertiesMap.loader.get('value');\n          }\n\n          if (propertiesMap.modules) {\n            loader = propertiesMap.modules.get('value');\n          }\n\n          if (!loader || Array.isArray(loader)) {\n            return;\n          }\n          const dynamicImports: BabelTypes.Expression[] = [];\n          const dynamicKeys: BabelTypes.Expression[] = [];\n\n          if (propertiesMap.ssr) {\n            const ssr = propertiesMap.ssr.get('value');\n            const nodePath = Array.isArray(ssr) ? undefined : ssr;\n\n            if (nodePath) {\n              const nonSSR =\n                nodePath.node.type === 'BooleanLiteral' && nodePath.node.value === false;\n              // If `ssr` is set to `false`, erase the loader for server side\n              if (nonSSR && loader && state.file.opts.caller?.isServer) {\n                loader.replaceWith(t.arrowFunctionExpression([], t.nullLiteral(), true));\n              }\n            }\n          }\n\n          loader.traverse({\n            Import(importPath) {\n              const importArguments = importPath.parentPath.get('arguments');\n\n              if (!Array.isArray(importArguments)) {\n                return;\n              }\n              const { node } = importArguments[0];\n              dynamicImports.push(node as any);\n              dynamicKeys.push(\n                t.binaryExpression(\n                  '+',\n                  t.stringLiteral(\n                    `${\n                      state.file.opts.caller?.pagesDir\n                        ? relativePath(state.file.opts.caller.pagesDir, state.file.opts.filename)\n                        : state.file.opts.filename\n                    } -> `\n                  ),\n                  node as any\n                )\n              );\n            },\n          });\n\n          if (!dynamicImports.length) {\n            return;\n          }\n\n          options.node.properties.push(\n            t.objectProperty(\n              t.identifier('loadableGenerated'),\n              t.objectExpression(\n                state.file.opts.caller?.isDev || state.file.opts.caller?.isServer\n                  ? [t.objectProperty(t.identifier('modules'), t.arrayExpression(dynamicKeys))]\n                  : [\n                      t.objectProperty(\n                        t.identifier('webpack'),\n                        t.arrowFunctionExpression(\n                          [],\n                          t.arrayExpression(\n                            dynamicImports.map((dynamicImport) => {\n                              return t.callExpression(\n                                t.memberExpression(\n                                  t.identifier('require'),\n                                  t.identifier('resolveWeak')\n                                ),\n                                [dynamicImport]\n                              );\n                            })\n                          )\n                        )\n                      ),\n                    ]\n              )\n            )\n          );\n\n          // Turns `dynamic(import('something'))` into `dynamic(() => import('something'))` for backwards compat.\n          // This is the replicate the behavior in versions below Next.js 7 where we magically handled not executing the `import()` too.\n          // We'll deprecate this behavior and provide a codemod for it in 7.1.\n          if (loader.isCallExpression()) {\n            const arrowFunction = t.arrowFunctionExpression([], loader.node);\n            loader.replaceWith(arrowFunction);\n          }\n        });\n      },\n    },\n  };\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/src/babel/preset.ts",
    "content": "import { createRequire } from 'node:module';\nimport { dirname } from 'node:path';\n\nimport type { PluginItem } from '@babel/core';\n\nimport ampAttributesPlugin from './plugins/amp-attributes.ts';\n// Static imports for relative requires\nimport jsxPragmaPlugin from './plugins/jsx-pragma.ts';\nimport optimizeHookDestructuringPlugin from './plugins/optimize-hook-destructuring.ts';\nimport reactLoadablePlugin from './plugins/react-loadable-plugin.ts';\n\nconst isLoadIntentTest = process.env.NODE_ENV === 'test';\nconst isLoadIntentDevelopment = process.env.NODE_ENV === 'development';\n\nconst require = createRequire(import.meta.url);\n\ntype StyledJsxPlugin = [string, any] | string;\ntype StyledJsxBabelOptions =\n  | {\n      plugins?: StyledJsxPlugin[];\n      styleModule?: string;\n      'babel-test'?: boolean;\n    }\n  | undefined;\n\n// Resolve styled-jsx plugins\nfunction styledJsxOptions(options: StyledJsxBabelOptions) {\n  options = options || {};\n  options.styleModule = 'styled-jsx/style';\n\n  if (!Array.isArray(options.plugins)) {\n    return options;\n  }\n\n  options.plugins = options.plugins.map((plugin: StyledJsxPlugin): StyledJsxPlugin => {\n    if (Array.isArray(plugin)) {\n      const [name, pluginOptions] = plugin;\n      return [require.resolve(name), pluginOptions];\n    }\n\n    return require.resolve(plugin);\n  });\n\n  return options;\n}\n\ntype NextBabelPresetOptions = {\n  'preset-env'?: any;\n  'preset-react'?: any;\n  'class-properties'?: any;\n  'transform-runtime'?: any;\n  'styled-jsx'?: StyledJsxBabelOptions;\n  'preset-typescript'?: any;\n};\n\ntype BabelPreset = {\n  presets?: PluginItem[] | null;\n  plugins?: PluginItem[] | null;\n  sourceType?: 'script' | 'module' | 'unambiguous';\n  overrides?: Array<{ test: RegExp } & Omit<BabelPreset, 'overrides'>>;\n};\n\n// Taken from https://github.com/babel/babel/commit/d60c5e1736543a6eac4b549553e107a9ba967051#diff-b4beead8ad9195361b4537601cc22532R158\nfunction supportsStaticESM(caller: any): boolean {\n  return !!caller?.supportsStaticESM;\n}\n\nexport default (api: any, options: NextBabelPresetOptions = {}): BabelPreset => {\n  const supportsESM = api.caller(supportsStaticESM);\n  const isServer = api.caller((caller: any) => !!caller && caller.isServer);\n  const isCallerDevelopment = api.caller((caller: any) => caller?.isDev);\n\n  // Look at external intent if used without a caller (e.g. via Jest):\n  const isTest = isCallerDevelopment == null && isLoadIntentTest;\n\n  // Look at external intent if used without a caller (e.g. Storybook):\n  const isDevelopment =\n    isCallerDevelopment === true || (isCallerDevelopment == null && isLoadIntentDevelopment);\n\n  const isBabelLoader = api.caller(\n    (caller: any) =>\n      !!caller && (caller.name === 'babel-loader' || caller.name === 'next-babel-turbo-loader')\n  );\n\n  const useJsxRuntime =\n    options['preset-react']?.runtime === 'automatic' ||\n    (Boolean(api.caller((caller: any) => !!caller && caller.hasJsxRuntime)) &&\n      options['preset-react']?.runtime !== 'classic');\n\n  const presetEnvConfig = {\n    // In the test environment `modules` is often needed to be set to true, babel figures that out by itself using the `'auto'` option\n    // In production/development this option is set to `false` so that webpack can handle import/export with tree-shaking\n    modules: 'auto',\n    exclude: ['transform-typeof-symbol'],\n    bugfixes: true,\n    targets: {\n      chrome: 100,\n      safari: 15,\n      firefox: 91,\n    },\n    ...options['preset-env'],\n  };\n\n  // When transpiling for the server or tests, target the current Node version\n  // if not explicitly specified:\n  if (\n    (isServer || isTest) &&\n    (!presetEnvConfig.targets ||\n      !(typeof presetEnvConfig.targets === 'object' && 'node' in presetEnvConfig.targets))\n  ) {\n    presetEnvConfig.targets = {\n      // Targets the current process' version of Node. This requires apps be\n      // built and deployed on the same version of Node.\n      // This is the same as using \"current\" but explicit\n      node: process.versions.node,\n    };\n  }\n\n  return {\n    sourceType: 'unambiguous',\n    presets: [\n      [require('@babel/preset-env'), presetEnvConfig],\n      [\n        require('@babel/preset-react'),\n        {\n          // This adds @babel/plugin-transform-react-jsx-source and\n          // @babel/plugin-transform-react-jsx-self automatically in development\n          development: isDevelopment || isTest,\n          ...(useJsxRuntime ? { runtime: 'automatic' } : { pragma: '__jsx' }),\n          ...options['preset-react'],\n        },\n      ],\n      [\n        require('@babel/preset-typescript'),\n        { allowNamespaces: true, ...options['preset-typescript'] },\n      ],\n    ],\n    plugins: [\n      isDevelopment && require.resolve('react-refresh/babel'),\n      !useJsxRuntime && [\n        jsxPragmaPlugin,\n        {\n          // This produces the following injected import for modules containing JSX:\n          //   import React from 'react';\n          //   var __jsx = React.createElement;\n          module: 'react',\n          importAs: 'React',\n          pragma: '__jsx',\n          property: 'createElement',\n        },\n      ],\n      [\n        optimizeHookDestructuringPlugin,\n        {\n          // only optimize hook functions imported from React/Preact\n          lib: true,\n        },\n      ],\n      require('@babel/plugin-syntax-dynamic-import'),\n      require('@babel/plugin-syntax-import-assertions'),\n      reactLoadablePlugin,\n      [require('@babel/plugin-transform-class-properties'), options['class-properties'] || {}],\n      [\n        require('@babel/plugin-transform-object-rest-spread'),\n        {\n          useBuiltIns: true,\n        },\n      ],\n      !isServer && [\n        require('@babel/plugin-transform-runtime'),\n        {\n          corejs: false,\n          helpers: true,\n          regenerator: true,\n          useESModules: supportsESM && presetEnvConfig.modules !== 'commonjs',\n          absoluteRuntime: isBabelLoader\n            ? dirname(require.resolve('@babel/runtime/package.json'))\n            : undefined,\n          ...options['transform-runtime'],\n        },\n      ],\n      [\n        isTest && options['styled-jsx'] && options['styled-jsx']['babel-test']\n          ? require('styled-jsx/babel-test')\n          : require('styled-jsx/babel'),\n        styledJsxOptions(options['styled-jsx']),\n      ],\n      ampAttributesPlugin,\n      isServer && require('@babel/plugin-syntax-bigint'),\n      // Always compile numeric separator because the resulting number is\n      // smaller.\n      require('@babel/plugin-transform-numeric-separator'),\n      require('@babel/plugin-transform-export-namespace-from'),\n    ].filter(Boolean),\n  };\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/compatibility/compatibility-map.ts",
    "content": "import semver from 'semver';\nimport type { Configuration as WebpackConfig } from 'webpack';\n\nimport { addScopedAlias, getNextjsVersion, setAlias } from '../utils.ts';\n\nconst mapping: Record<string, Record<string, string | boolean>> = {\n  '<15.0.0': {\n    'next/dist/server/request/headers': 'next/dist/client/components/headers',\n    // this path only exists from Next 15 onwards\n    'next/dist/server/request/draft-mode': '@storybook/nextjs/compatibility/draft-mode.compat',\n  },\n};\n\nexport const getCompatibilityAliases = () => {\n  const version = getNextjsVersion();\n  const result: Record<string, string> = {};\n\n  Object.keys(mapping).forEach((key) => {\n    if (semver.intersects(version, key)) {\n      Object.assign(result, mapping[key]);\n    }\n  });\n\n  return result;\n};\n\nexport const configureCompatibilityAliases = (baseConfig: WebpackConfig): void => {\n  const aliases = getCompatibilityAliases();\n\n  Object.entries(aliases).forEach(([name, alias]) => {\n    if (typeof alias === 'string') {\n      addScopedAlias(baseConfig, name, alias);\n    } else {\n      setAlias(baseConfig, name, alias);\n    }\n  });\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/compatibility/draft-mode.compat.ts",
    "content": "// @ts-expect-error Compatibility for Next 14\nexport { draftMode } from 'next/dist/client/components/headers.js';\n"
  },
  {
    "path": "code/frameworks/nextjs/src/config/preview.ts",
    "content": "import { setConfig } from 'next/config';\n\nsetConfig(process.env.__NEXT_RUNTIME_CONFIG);\n"
  },
  {
    "path": "code/frameworks/nextjs/src/config/webpack.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport type { NextConfig } from 'next';\nimport type { Configuration as WebpackConfig } from 'webpack';\n\nimport { addScopedAlias, isNextVersionGte, resolveNextConfig } from '../utils.ts';\n\nconst isNext16orNewer = isNextVersionGte('16.0.0');\n\nconst tryResolve = (path: string) => {\n  try {\n    return fileURLToPath(import.meta.resolve(path)) || false;\n  } catch (err) {\n    return false;\n  }\n};\n\nexport const configureConfig = async ({\n  baseConfig,\n  nextConfigPath,\n}: {\n  baseConfig: WebpackConfig;\n  nextConfigPath?: string;\n}): Promise<NextConfig> => {\n  const nextConfig = await resolveNextConfig({ nextConfigPath });\n\n  // TODO: Remove this once we only support Next.js 16 and above\n  if (!isNext16orNewer) {\n    addScopedAlias(baseConfig, 'next/config');\n  }\n\n  // @ts-expect-error We know that alias is an object\n  if (baseConfig.resolve?.alias?.['react-dom']) {\n    // Removing the alias to react-dom to avoid conflicts with the alias we are setting\n    // because the react-dom alias is an exact match and we need to alias separate parts of react-dom\n    // in different places\n    // @ts-expect-error We know that alias is an object\n    delete baseConfig.resolve.alias?.['react-dom'];\n  }\n\n  if (tryResolve('next/dist/compiled/react')) {\n    addScopedAlias(baseConfig, 'react', 'next/dist/compiled/react');\n  }\n  if (tryResolve('next/dist/compiled/react-dom/cjs/react-dom-test-utils.production.js')) {\n    addScopedAlias(\n      baseConfig,\n      'react-dom/test-utils',\n      'next/dist/compiled/react-dom/cjs/react-dom-test-utils.production.js'\n    );\n  }\n  if (tryResolve('next/dist/compiled/react-dom')) {\n    addScopedAlias(baseConfig, 'react-dom$', 'next/dist/compiled/react-dom');\n    addScopedAlias(baseConfig, 'react-dom/client', 'next/dist/compiled/react-dom/client');\n    addScopedAlias(baseConfig, 'react-dom/server', 'next/dist/compiled/react-dom/server');\n  }\n\n  await setupRuntimeConfig(baseConfig, nextConfig);\n\n  return nextConfig;\n};\n\nconst setupRuntimeConfig = async (\n  baseConfig: WebpackConfig,\n  nextConfig: NextConfig\n): Promise<void> => {\n  const definePluginConfig: Record<string, any> = {};\n\n  // TODO: Remove this once we only support Next.js 16 and above\n  if (!isNext16orNewer) {\n    // this mimics what nextjs does client side\n    // https://github.com/vercel/next.js/blob/57702cb2a9a9dba4b552e0007c16449cf36cfb44/packages/next/client/index.tsx#L101\n    definePluginConfig['process.env.__NEXT_RUNTIME_CONFIG'] = JSON.stringify({\n      serverRuntimeConfig: {},\n      publicRuntimeConfig: nextConfig.publicRuntimeConfig,\n    });\n  }\n\n  const newNextLinkBehavior = (nextConfig.experimental as any)?.newNextLinkBehavior;\n\n  definePluginConfig['process.env.__NEXT_NEW_LINK_BEHAVIOR'] = newNextLinkBehavior;\n\n  // Load DefinePlugin with a dynamic import to ensure that Next.js can first\n  // replace webpack with its own internal instance, and we get that here.\n  baseConfig.plugins?.push(new (await import('webpack')).default.DefinePlugin(definePluginConfig));\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/css/webpack.ts",
    "content": "import { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { NextConfig } from 'next';\nimport { cssFileResolve } from 'next/dist/build/webpack/config/blocks/css/loaders/file-resolve.js';\nimport { getCssModuleLocalIdent } from 'next/dist/build/webpack/config/blocks/css/loaders/getCssModuleLocalIdent.js';\nimport semver from 'semver';\nimport type { Configuration as WebpackConfig } from 'webpack';\n\nimport { resolvePackageDir } from '../../../../core/src/shared/utils/module.ts';\n\n// This tries to follow nextjs's css config, please refer to this file for more info:\n// https://github.com/vercel/next.js/blob/canary/packages/next/build/webpack-config.ts\n\nexport const configureCss = (baseConfig: WebpackConfig, nextConfig: NextConfig): void => {\n  const rules = baseConfig.module?.rules;\n  rules?.forEach((rule, i) => {\n    if (\n      rule &&\n      typeof rule !== 'string' &&\n      rule.test instanceof RegExp &&\n      rule.test.test('test.css')\n    ) {\n      rules[i] = {\n        test: /\\.css$/,\n        use: [\n          fileURLToPath(import.meta.resolve('style-loader')),\n          {\n            loader: fileURLToPath(import.meta.resolve('css-loader')),\n            options: {\n              importLoaders: 1,\n              ...getImportAndUrlCssLoaderOptions(nextConfig),\n              modules: {\n                auto: true,\n                getLocalIdent: getCssModuleLocalIdent,\n              },\n            },\n          },\n          fileURLToPath(import.meta.resolve('postcss-loader')),\n        ],\n        // We transform the \"target.css\" files from next.js into Javascript\n        // for Next.js to support fonts, so it should be ignored by the css-loader.\n        exclude: /next(\\\\|\\/|\\\\\\\\).*(\\\\|\\/|\\\\\\\\)target\\.css$/,\n      };\n    }\n  });\n  rules?.push({\n    test: /\\.(scss|sass)$/,\n    use: [\n      fileURLToPath(import.meta.resolve('style-loader')),\n      {\n        loader: fileURLToPath(import.meta.resolve('css-loader')),\n        options: {\n          importLoaders: 3,\n          ...getImportAndUrlCssLoaderOptions(nextConfig),\n          modules: { auto: true, getLocalIdent: getCssModuleLocalIdent },\n        },\n      },\n      fileURLToPath(import.meta.resolve('postcss-loader')),\n      fileURLToPath(import.meta.resolve('resolve-url-loader')),\n      {\n        loader: fileURLToPath(import.meta.resolve('sass-loader')),\n        options: {\n          sourceMap: true,\n          sassOptions: nextConfig.sassOptions,\n          additionalData:\n            nextConfig.sassOptions?.prependData || nextConfig.sassOptions?.additionalData,\n        },\n      },\n    ],\n  });\n};\n\n/**\n * Webpack v4-v6 api https://webpack.js.org/loaders/css-loader/#url\n * https://webpack.js.org/loaders/css-loader/#import\n *\n * Webpack v3 api https://webpack-3.cdn.bcebos.com/loaders/css-loader/#url\n * https://webpack-3.cdn.bcebos.com/loaders/css-loader/#import\n */\nconst getImportAndUrlCssLoaderOptions = (nextConfig: NextConfig) =>\n  isCssLoaderV6()\n    ? {\n        url: {\n          filter: getUrlResolver(nextConfig),\n        },\n        import: {\n          filter: getImportResolver(nextConfig),\n        },\n      }\n    : {\n        url: getUrlResolver(nextConfig),\n        import: getImportResolver(nextConfig),\n      };\n\nconst getUrlResolver = (nextConfig: NextConfig) => (url: string, resourcePath: string) =>\n  cssFileResolve(url, resourcePath, nextConfig.experimental?.urlImports);\n\nconst getImportResolver =\n  (nextConfig: NextConfig) =>\n  (url: string | { url: string; media: string }, _: string, resourcePath: string) =>\n    cssFileResolve(\n      typeof url === 'string' ? url : url.url,\n      resourcePath,\n      nextConfig.experimental?.urlImports\n    );\n\nconst isCssLoaderV6 = () => {\n  try {\n    const cssLoaderVersion = JSON.parse(\n      readFileSync(join(resolvePackageDir('css-loader'), 'package.json'), 'utf8')\n    ).version;\n    return semver.gte(cssLoaderVersion, '6.0.0');\n  } catch {\n    /**\n     * Css-loader isn't a resolvable dependency thus storybook webpack 5 manager will resolve to use\n     * its version which is v5\n     */\n    return false;\n  }\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/export-mocks/cache/index.ts",
    "content": "import { unstable_cache } from 'next/dist/server/web/spec-extension/unstable-cache.js';\nimport { unstable_noStore } from 'next/dist/server/web/spec-extension/unstable-no-store.js';\nimport { fn } from 'storybook/test';\n\n// mock utilities/overrides (as of Next v14.2.0)\nconst revalidatePath = fn().mockName('next/cache::revalidatePath');\nconst revalidateTag = fn().mockName('next/cache::revalidateTag');\n\nconst cacheExports = {\n  unstable_cache,\n  revalidateTag,\n  revalidatePath,\n  unstable_noStore,\n};\n\nexport default cacheExports;\nexport { unstable_cache, revalidateTag, revalidatePath, unstable_noStore };\n"
  },
  {
    "path": "code/frameworks/nextjs/src/export-mocks/headers/cookies.ts",
    "content": "// We need this import to be a singleton, and because it's used in multiple entrypoints\n// both in ESM and CJS, importing it via the package name instead of having a local import\n// is the only way to achieve it actually being a singleton\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore we must ignore types here as during compilation they are not generated yet\nimport { headers } from '@storybook/nextjs/headers.mock';\n\nimport { RequestCookies } from 'next/dist/compiled/@edge-runtime/cookies/index.js';\nimport { fn } from 'storybook/test';\n\nclass RequestCookiesMock extends RequestCookies {\n  get = fn(super.get.bind(this)).mockName('next/headers::cookies().get');\n\n  getAll = fn(super.getAll.bind(this)).mockName('next/headers::cookies().getAll');\n\n  has = fn(super.has.bind(this)).mockName('next/headers::cookies().has');\n\n  set = fn(super.set.bind(this)).mockName('next/headers::cookies().set');\n\n  delete = fn(super.delete.bind(this)).mockName('next/headers::cookies().delete');\n}\n\nlet requestCookiesMock: RequestCookiesMock;\n\nexport const cookies = fn(() => {\n  if (!requestCookiesMock) {\n    requestCookiesMock = new RequestCookiesMock(headers());\n  }\n  return requestCookiesMock;\n}).mockName('next/headers::cookies()');\n\nconst originalRestore = cookies.mockRestore.bind(null);\n\n// will be called automatically by the test loader\ncookies.mockRestore = () => {\n  originalRestore();\n  headers.mockRestore();\n  requestCookiesMock = new RequestCookiesMock(headers());\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/export-mocks/headers/headers.ts",
    "content": "import { HeadersAdapter } from 'next/dist/server/web/spec-extension/adapters/headers.js';\nimport { fn } from 'storybook/test';\n\nclass HeadersAdapterMock extends HeadersAdapter {\n  constructor() {\n    super({});\n  }\n\n  append = fn(super.append.bind(this)).mockName('next/headers::headers().append');\n\n  delete = fn(super.delete.bind(this)).mockName('next/headers::headers().delete');\n\n  get = fn(super.get.bind(this)).mockName('next/headers::headers().get');\n\n  has = fn(super.has.bind(this)).mockName('next/headers::headers().has');\n\n  set = fn(super.set.bind(this)).mockName('next/headers::headers().set');\n\n  forEach = fn(super.forEach.bind(this)).mockName('next/headers::headers().forEach');\n\n  entries = fn(super.entries.bind(this)).mockName('next/headers::headers().entries');\n\n  keys = fn(super.keys.bind(this)).mockName('next/headers::headers().keys');\n\n  values = fn(super.values.bind(this)).mockName('next/headers::headers().values');\n}\n\nlet headersAdapterMock: HeadersAdapterMock;\n\nexport const headers = () => {\n  if (!headersAdapterMock) {\n    headersAdapterMock = new HeadersAdapterMock();\n  }\n  return headersAdapterMock;\n};\n\n// This fn is called by ./cookies to restore the headers in the right order\nheaders.mockRestore = () => {\n  headersAdapterMock = new HeadersAdapterMock();\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/export-mocks/headers/index.ts",
    "content": "import * as headers from 'next/dist/server/request/headers.js';\nimport { fn } from 'storybook/test';\n\n// re-exports of the actual module\nexport * from 'next/dist/server/request/headers.js';\n\n// mock utilities/overrides (as of Next v14.2.0)\nexport { headers } from './headers.ts';\nexport { cookies } from './cookies.ts';\n\n// passthrough mocks - keep original implementation but allow for spying\n// In Next.js 14, draftMode is exported from 'next/dist/client/components/headers'\n// In Next.js 15+, draftMode is exported from 'next/dist/server/request/draft-mode'\n// The webpack alias handles this, but we need to avoid the top-level import\n// to prevent build errors when the module doesn't exist\nlet originalDraftMode: any;\ntry {\n  // This will be resolved by webpack alias to the correct location based on Next.js version\n  originalDraftMode = require('next/dist/server/request/draft-mode').draftMode;\n} catch {\n  // Fallback to the location in the headers module (Next.js 14)\n  originalDraftMode = (headers as any).draftMode;\n}\n\nconst draftMode = fn(originalDraftMode).mockName('draftMode');\nexport { draftMode };\n"
  },
  {
    "path": "code/frameworks/nextjs/src/export-mocks/index.ts",
    "content": "export { getPackageAliases } from './webpack.ts';\n"
  },
  {
    "path": "code/frameworks/nextjs/src/export-mocks/link/index.tsx",
    "content": "import React from 'react';\n\nimport { fn } from 'storybook/test';\n\nconst linkAction = fn().mockName('next/link::Link');\n\nconst MockLink = React.forwardRef<HTMLAnchorElement, any>(function MockLink(\n  {\n    href,\n    as: _as,\n    replace,\n    scroll,\n    shallow,\n    prefetch,\n    passHref,\n    legacyBehavior,\n    locale,\n    onClick,\n    children,\n    ...rest\n  },\n  ref\n) {\n  const hrefString =\n    typeof href === 'object'\n      ? `${href.pathname || ''}${href.query ? '?' + new URLSearchParams(href.query).toString() : ''}${href.hash || ''}`\n      : href;\n\n  const handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {\n    e.preventDefault();\n    onClick?.(e);\n    linkAction(hrefString, { replace, scroll, shallow, prefetch, locale });\n  };\n\n  if (legacyBehavior) {\n    const child = React.Children.only(children) as React.ReactElement<any>;\n    const childProps: Record<string, any> = {\n      ref,\n      onClick: (e: React.MouseEvent<HTMLAnchorElement>) => {\n        e.preventDefault();\n        if (child.props && typeof child.props.onClick === 'function') {\n          child.props.onClick(e);\n        }\n        linkAction(hrefString, { replace, scroll, shallow, prefetch, locale });\n      },\n      ...rest,\n    };\n\n    if (passHref || (child.type === 'a' && !('href' in (child.props || {})))) {\n      childProps.href = hrefString;\n    }\n\n    return React.cloneElement(child, childProps);\n  }\n\n  return (\n    <a ref={ref} href={hrefString} onClick={handleClick} {...rest}>\n      {children}\n    </a>\n  );\n});\n\nMockLink.displayName = 'NextLink';\n\nexport default MockLink;\nexport { MockLink as Link };\n"
  },
  {
    "path": "code/frameworks/nextjs/src/export-mocks/navigation/index.ts",
    "content": "import { NextjsRouterMocksNotAvailable } from 'storybook/internal/preview-errors';\n\nimport * as actual from 'next/dist/client/components/navigation.js';\nimport { RedirectStatusCode } from 'next/dist/client/components/redirect-status-code.js';\nimport { getRedirectError } from 'next/dist/client/components/redirect.js';\nimport type { Mock } from 'storybook/test';\nimport { fn } from 'storybook/test';\n\nlet navigationAPI: {\n  push: Mock;\n  replace: Mock;\n  forward: Mock;\n  back: Mock;\n  prefetch: Mock;\n  refresh: Mock;\n};\n\n/**\n * Creates a next/navigation router API mock. Used internally.\n *\n * @ignore\n * @internal\n */\nexport const createNavigation = (overrides: any) => {\n  const navigationActions = {\n    push: fn().mockName('next/navigation::useRouter().push'),\n    replace: fn().mockName('next/navigation::useRouter().replace'),\n    forward: fn().mockName('next/navigation::useRouter().forward'),\n    back: fn().mockName('next/navigation::useRouter().back'),\n    prefetch: fn().mockName('next/navigation::useRouter().prefetch'),\n    refresh: fn().mockName('next/navigation::useRouter().refresh'),\n  };\n\n  if (overrides) {\n    Object.keys(navigationActions).forEach((key) => {\n      if (key in overrides) {\n        (navigationActions as any)[key] = fn((...args: any[]) => {\n          return (overrides as any)[key](...args);\n        }).mockName(`useRouter().${key}`);\n      }\n    });\n  }\n\n  navigationAPI = navigationActions;\n\n  return navigationAPI;\n};\n\nexport const getRouter = () => {\n  if (!navigationAPI) {\n    throw new NextjsRouterMocksNotAvailable({\n      importType: 'next/navigation',\n    });\n  }\n\n  return navigationAPI;\n};\n\n// re-exports of the actual module\nexport * from 'next/dist/client/components/navigation.js';\n\n// mock utilities/overrides (as of Next v14.2.0)\nexport const redirect = fn(\n  (url: string, type: actual.RedirectType = actual.RedirectType.push): never => {\n    throw getRedirectError(url, type, RedirectStatusCode.SeeOther);\n  }\n).mockName('next/navigation::redirect');\n\nexport const permanentRedirect = fn(\n  (url: string, type: actual.RedirectType = actual.RedirectType.push): never => {\n    throw getRedirectError(url, type, RedirectStatusCode.SeeOther);\n  }\n).mockName('next/navigation::permanentRedirect');\n\n// passthrough mocks - keep original implementation but allow for spying\nexport const useSearchParams = fn(actual.useSearchParams).mockName(\n  'next/navigation::useSearchParams'\n);\nexport const usePathname = fn(actual.usePathname).mockName('next/navigation::usePathname');\nexport const useSelectedLayoutSegment = fn(actual.useSelectedLayoutSegment).mockName(\n  'next/navigation::useSelectedLayoutSegment'\n);\nexport const useSelectedLayoutSegments = fn(actual.useSelectedLayoutSegments).mockName(\n  'next/navigation::useSelectedLayoutSegments'\n);\nexport const useRouter = fn(() => {\n  if (!navigationAPI) {\n    throw new NextjsRouterMocksNotAvailable({\n      importType: 'next/navigation',\n    });\n  }\n  return navigationAPI;\n}).mockName('next/navigation::useRouter');\nexport const useServerInsertedHTML = fn(actual.useServerInsertedHTML).mockName(\n  'next/navigation::useServerInsertedHTML'\n);\nexport const notFound = fn(actual.notFound).mockName('next/navigation::notFound');\n\n// Params, not exported by Next.js, is manually declared to avoid inference issues.\ninterface Params {\n  [key: string]: string | string[];\n}\nexport const useParams = fn<() => Params>(actual.useParams).mockName('next/navigation::useParams');\n"
  },
  {
    "path": "code/frameworks/nextjs/src/export-mocks/router/index.ts",
    "content": "import { NextjsRouterMocksNotAvailable } from 'storybook/internal/preview-errors';\n\nimport singletonRouter, * as originalRouter from 'next/dist/client/router.js';\nimport type { NextRouter, SingletonRouter } from 'next/router';\nimport type { Mock } from 'storybook/test';\nimport { fn } from 'storybook/test';\n\nconst defaultRouterState = {\n  route: '/',\n  asPath: '/',\n  basePath: '/',\n  pathname: '/',\n  query: {},\n  isFallback: false,\n  isLocaleDomain: false,\n  isReady: true,\n  isPreview: false,\n};\n\nlet routerAPI: {\n  push: Mock;\n  replace: Mock;\n  reload: Mock;\n  back: Mock;\n  forward: Mock;\n  prefetch: Mock;\n  beforePopState: Mock;\n  events: {\n    on: Mock;\n    off: Mock;\n    emit: Mock;\n  };\n} & typeof defaultRouterState;\n\n/**\n * Creates a next/router router API mock. Used internally.\n *\n * @ignore\n * @internal\n */\nexport const createRouter = (overrides: Partial<NextRouter>) => {\n  const routerActions: Partial<NextRouter> = {\n    push: fn((..._args: any[]) => {\n      return Promise.resolve(true);\n    }).mockName('next/router::useRouter().push'),\n    replace: fn((..._args: any[]) => {\n      return Promise.resolve(true);\n    }).mockName('next/router::useRouter().replace'),\n    reload: fn((..._args: any[]) => {}).mockName('next/router::useRouter().reload'),\n    back: fn((..._args: any[]) => {}).mockName('next/router::useRouter().back'),\n    forward: fn(() => {}).mockName('next/router::useRouter().forward'),\n    prefetch: fn((..._args: any[]) => {\n      return Promise.resolve();\n    }).mockName('next/router::useRouter().prefetch'),\n    beforePopState: fn((..._args: any[]) => {}).mockName('next/router::useRouter().beforePopState'),\n  };\n\n  const routerEvents: NextRouter['events'] = {\n    on: fn((..._args: any[]) => {}).mockName('next/router::useRouter().events.on'),\n    off: fn((..._args: any[]) => {}).mockName('next/router::useRouter().events.off'),\n    emit: fn((..._args: any[]) => {}).mockName('next/router::useRouter().events.emit'),\n  };\n\n  if (overrides) {\n    Object.keys(routerActions).forEach((key) => {\n      if (key in overrides) {\n        (routerActions as any)[key] = fn((...args: any[]) => {\n          return (overrides as any)[key](...args);\n        }).mockName(`useRouter().${key}`);\n      }\n    });\n  }\n\n  if (overrides?.events) {\n    Object.keys(routerEvents).forEach((key) => {\n      if (key in routerEvents) {\n        (routerEvents as any)[key] = fn((...args: any[]) => {\n          return (overrides.events as any)[key](...args);\n        }).mockName(`useRouter().events.${key}`);\n      }\n    });\n  }\n\n  routerAPI = {\n    ...defaultRouterState,\n    ...overrides,\n    ...routerActions,\n    // @ts-expect-error TODO improve typings\n    events: routerEvents,\n  };\n\n  // overwrite the singleton router from next/router\n  (singletonRouter as unknown as SingletonRouter).router = routerAPI as any;\n  (singletonRouter as unknown as SingletonRouter).readyCallbacks.forEach((cb) => cb());\n  (singletonRouter as unknown as SingletonRouter).readyCallbacks = [];\n\n  return routerAPI as unknown as NextRouter;\n};\n\nexport const getRouter = () => {\n  if (!routerAPI) {\n    throw new NextjsRouterMocksNotAvailable({\n      importType: 'next/router',\n    });\n  }\n\n  return routerAPI;\n};\n\n// re-exports of the actual module\nexport * from 'next/dist/client/router.js';\nexport default singletonRouter;\n\n// mock utilities/overrides (as of Next v14.2.0)\n// passthrough mocks - keep original implementation but allow for spying\nexport const useRouter = fn(originalRouter.useRouter).mockName('next/router::useRouter');\nexport const withRouter = fn(originalRouter.withRouter).mockName('next/router::withRouter');\n"
  },
  {
    "path": "code/frameworks/nextjs/src/export-mocks/webpack.ts",
    "content": "import type { Configuration as WebpackConfig } from 'webpack';\n\nimport { getCompatibilityAliases } from '../compatibility/compatibility-map.ts';\n\nconst mapping = {\n  'next/headers': '@storybook/nextjs/headers.mock',\n  'next/navigation': '@storybook/nextjs/navigation.mock',\n  'next/router': '@storybook/nextjs/router.mock',\n  'next/cache': '@storybook/nextjs/cache.mock',\n  'next/link': '@storybook/nextjs/link.mock',\n  ...getCompatibilityAliases(),\n};\n\n// Utility that assists in adding aliases to the Webpack configuration\n// and also doubles as alias solution for portable stories in Jest/Vitest/etc.\nexport const getPackageAliases = () => {\n  return mapping;\n};\n\nexport const configureNextExportMocks = (baseConfig: WebpackConfig): void => {\n  const resolve = baseConfig.resolve ?? {};\n\n  resolve.alias = {\n    ...resolve.alias,\n    ...mapping,\n  };\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/fastRefresh/webpack.ts",
    "content": "import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';\nimport type { Configuration as WebpackConfig } from 'webpack';\n\nexport const configureFastRefresh = (baseConfig: WebpackConfig): void => {\n  baseConfig.plugins = [\n    ...(baseConfig.plugins ?? []),\n    // overlay is disabled as it is shown with caught errors in error boundaries\n    // and the next app router is using error boundaries to redirect\n    // TODO use the Next error overlay\n    new ReactRefreshWebpackPlugin({ overlay: false }),\n  ];\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/font/babel/helpers.ts",
    "content": "import type * as BabelCoreNamespace from '@babel/core';\nimport type * as BabelTypesNamespace from '@babel/types';\n\ntype BabelTypes = typeof BabelTypesNamespace;\ntype PrimaryTypes = Record<string, any> | string | number | boolean | undefined | null;\n\nexport type JSReturnValue = PrimaryTypes | Array<PrimaryTypes>;\n\nexport type VariableMeta = {\n  /**\n   * Variable Declaration name of the assigned function call\n   *\n   * @example\n   *\n   * ```ts\n   * import { Roboto } from 'next/font/google';\n   * const robotoName = Roboto({\n   *   weight: '400',\n   * });\n   *\n   * // identifierName = 'robotName'\n   * ```\n   */\n  identifierName: string;\n  /**\n   * Properties of the assigned function call\n   *\n   * @example\n   *\n   * ```ts\n   * import { Roboto } from 'next/font/google';\n   * const robotoName = Roboto({\n   *   weight: '400',\n   * });\n   *\n   * // properties = { weight: '400' }\n   * ```\n   */\n  properties: JSReturnValue;\n  /**\n   * Function name of the imported next/font/google function\n   *\n   * @example\n   *\n   * ```ts\n   * import { Roboto } from 'next/font/google';\n   * const robotoName = Roboto({\n   *   weight: '400',\n   * });\n   *\n   * // functionName = Roboto\n   * ```\n   */\n  functionName: string;\n};\n\nfunction convertNodeToJSON(types: BabelTypes, node: any): JSReturnValue {\n  if (types.isBooleanLiteral(node) || types.isStringLiteral(node) || types.isNumericLiteral(node)) {\n    return node.value;\n  }\n\n  if (node.name === 'undefined' && !node.value) {\n    return undefined;\n  }\n\n  if (types.isNullLiteral(node)) {\n    return null;\n  }\n\n  if (types.isObjectExpression(node)) {\n    return computeProps(types, node.properties);\n  }\n\n  if (types.isArrayExpression(node)) {\n    return node.elements.reduce(\n      (acc, element) => [\n        ...acc,\n        ...(element?.type === 'SpreadElement'\n          ? (convertNodeToJSON(types, element.argument) as PrimaryTypes[])\n          : [convertNodeToJSON(types, element)]),\n      ],\n      [] as PrimaryTypes[]\n    );\n  }\n\n  return {};\n}\n\nfunction computeProps(\n  types: BabelTypes,\n  props: (\n    | BabelTypesNamespace.ObjectMethod\n    | BabelTypesNamespace.ObjectProperty\n    | BabelTypesNamespace.SpreadElement\n  )[]\n) {\n  return props.reduce((acc, prop) => {\n    if (prop.type === 'SpreadElement') {\n      return {\n        ...acc,\n        ...(convertNodeToJSON(types, prop.argument) as Record<string, any>),\n      };\n    }\n    if (prop.type !== 'ObjectMethod') {\n      const val = convertNodeToJSON(types, prop.value);\n      if (val !== undefined && types.isIdentifier(prop.key)) {\n        return {\n          ...acc,\n          [prop.key.name]: val,\n        };\n      }\n    }\n    return acc;\n  }, {});\n}\n\nexport function isDefined<T>(value: T): value is Exclude<T, undefined> {\n  return value !== undefined;\n}\n\n/**\n * Removes transformed variable declarations, which were already replaced with parameterized imports\n *\n * @example\n *\n * ```ts\n * // AST\n * import { Roboto, Inter } from 'next/font/google';\n * const interName = Inter({\n *   subsets: ['latin'],\n * });\n * const robotoName = Roboto({\n *   weight: '400',\n * });\n *\n * // Result\n * import { Roboto, Inter } from 'next/font/google';\n *\n * // Variable declarations are removed\n * ```\n */\nexport function removeTransformedVariableDeclarations(\n  path: BabelCoreNamespace.NodePath<BabelCoreNamespace.types.ImportDeclaration>,\n  types: BabelTypes,\n  metas: VariableMeta[]\n) {\n  path.parentPath.traverse({\n    ExportNamedDeclaration(declaratorPath) {\n      if (!declaratorPath.parentPath?.isProgram()) {\n        return;\n      }\n\n      metas.forEach((meta) => {\n        if (\n          types.isVariableDeclaration(declaratorPath.node.declaration) &&\n          declaratorPath.node.declaration.declarations.length === 1 &&\n          types.isVariableDeclarator(declaratorPath.node.declaration.declarations[0]) &&\n          types.isIdentifier(declaratorPath.node.declaration.declarations[0].id) &&\n          meta.identifierName === declaratorPath.node.declaration.declarations[0].id.name\n        ) {\n          declaratorPath.replaceWith(\n            types.exportNamedDeclaration(null, [\n              types.exportSpecifier(\n                types.identifier(meta.identifierName),\n                types.identifier(meta.identifierName)\n              ),\n            ])\n          );\n        }\n      });\n    },\n    VariableDeclarator(declaratorPath) {\n      if (!declaratorPath.parentPath.parentPath?.isProgram()) {\n        return;\n      }\n\n      if (\n        metas.some(\n          (meta) =>\n            types.isIdentifier(declaratorPath.node.id) &&\n            meta.identifierName === declaratorPath.node.id.name\n        )\n      ) {\n        declaratorPath.remove();\n      }\n    },\n  });\n}\n\n/**\n * Replaces `next/font` import with a parameterized import\n *\n * @example\n *\n * ```ts\n * // AST of src/example.js\n * import { Roboto, Inter } from 'next/font/google';\n * const interName = Inter({\n *   subsets: ['latin'],\n * });\n * const robotoName = Roboto({\n *   weight: '400',\n * });\n *\n * // Result\n * import interName from 'storybook-nextjs-font-loader?{filename: \"src/example.js\", source: \"next/font/google\", fontFamily: \"Inter\", props: {\"subsets\":[\"latin\"]}}!next/font/google';\n * import robotoName from 'storybook-nextjs-font-loader?{filename: \"src/example.js\", source: \"next/font/google\", fontFamily: \"Roboto\", props: {\"weight\": \"400\"}}!next/font/google';\n *\n * // Following code will be removed from removeUnusedVariableDeclarations function\n * const interName = Inter({\n *   subsets: ['latin'],\n * });\n *\n * const robotoName = Roboto({\n *   weight: '400',\n * });\n * ```\n */\nexport function replaceImportWithParameterImport(\n  path: BabelCoreNamespace.NodePath<BabelCoreNamespace.types.ImportDeclaration>,\n  types: BabelTypes,\n  source: BabelCoreNamespace.types.StringLiteral,\n  metas: Array<VariableMeta>,\n  filename: string\n) {\n  // Add an import for each specifier with parameters\n  path.replaceWithMultiple([\n    ...metas.map((meta) => {\n      return types.importDeclaration(\n        [types.importDefaultSpecifier(types.identifier(meta.identifierName))],\n        types.stringLiteral(\n          `storybook-nextjs-font-loader?${JSON.stringify({\n            source: source.value,\n            props: meta.properties,\n            fontFamily: meta.functionName,\n            filename,\n          })}!${source.value}`\n        )\n      );\n    }),\n  ]);\n}\n\n/**\n * Get meta information for the provided import specifier\n *\n * @example\n *\n * ```ts\n * // AST\n * import { Roboto, Inter } from 'next/font/google';\n * const interName = Inter({\n *   subsets: ['latin'],\n * });\n * const robotoName = Roboto({\n *   weight: '400',\n * });\n *\n * // Return value\n * const variableMetas = [\n *   {\n *     identifierName: 'interName',\n *     properties: { subsets: ['latin'] },\n *     functionName: 'Inter',\n *   },\n *   {\n *     identifierName: 'robotoName',\n *     properties: { weight: '400' },\n *     functionName: 'Roboto',\n *   },\n * ];\n * ```\n */\nexport function getVariableMetasBySpecifier(\n  program: BabelCoreNamespace.NodePath<BabelCoreNamespace.types.Program>,\n  types: BabelTypes,\n  specifier:\n    | BabelCoreNamespace.types.ImportDefaultSpecifier\n    | BabelCoreNamespace.types.ImportNamespaceSpecifier\n    | BabelCoreNamespace.types.ImportSpecifier\n) {\n  return program.node.body\n    .map((statement) => {\n      if (!types.isVariableDeclaration(statement) && !types.isExportNamedDeclaration(statement)) {\n        return undefined;\n      }\n\n      const exportedNamedDeclaration =\n        !types.isVariableDeclaration(statement) &&\n        types.isVariableDeclaration(statement.declaration) &&\n        statement.declaration.declarations.length === 1\n          ? statement.declaration.declarations[0]\n          : null;\n\n      const declaration = types.isVariableDeclaration(statement)\n        ? statement.declarations[0]\n        : exportedNamedDeclaration;\n\n      if (!declaration) {\n        return undefined;\n      }\n\n      if (!types.isIdentifier(declaration.id)) {\n        return undefined;\n      }\n\n      if (!types.isCallExpression(declaration.init)) {\n        return undefined;\n      }\n\n      if (!types.isIdentifier(declaration.init.callee)) {\n        return undefined;\n      }\n\n      if (\n        (specifier.type !== 'ImportSpecifier' ||\n          specifier.imported.type !== 'Identifier' ||\n          (declaration.init.callee.name !== specifier.imported.name &&\n            declaration.init.callee.name !== specifier.local.name)) &&\n        (specifier.type !== 'ImportDefaultSpecifier' ||\n          declaration.init.callee.name !== specifier.local.name)\n      ) {\n        return undefined;\n      }\n\n      const options = declaration.init.arguments[0];\n\n      if (!types.isObjectExpression(options)) {\n        throw program.buildCodeFrameError(\n          'Please pass an options object to the call expression of next/font functions'\n        );\n      }\n\n      options.properties.forEach((property) => {\n        if (types.isSpreadElement(property)) {\n          throw program.buildCodeFrameError(\n            'Please do not use spread elements in the options object in next/font function calls'\n          );\n        }\n      });\n\n      const identifierName = declaration.id.name;\n      const properties = convertNodeToJSON(types, options);\n      let functionName = declaration.init.callee.name;\n      if (\n        specifier.type === 'ImportSpecifier' &&\n        specifier.imported &&\n        specifier.imported.type === 'Identifier' &&\n        declaration.init.callee.name !== specifier.imported.name\n      ) {\n        functionName = specifier.imported.name;\n      }\n      return { identifierName, properties, functionName };\n    })\n    .filter(isDefined);\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/src/font/babel/index.test.ts",
    "content": "import { expect, it } from 'vitest';\n\nimport { transform } from '@babel/core';\n\nimport TransformFontImports from './index.ts';\n\nconst example = `\nimport { Inter, Lora as FontLora, Roboto } from 'next/font/google'\nimport localFont from 'next/font/local'\n\nconst myFont = localFont({ src: './my-font.woff2' })\n\nconst roboto = Roboto({\n  weight: '400',\n})\n\nconst lora = FontLora({\n  weight: '400',\n})\n\nconst inter = Inter({\n  subsets: ['latin'],\n});\n\nconst randomObj = {}\n`;\n\nconst exampleLegacy = `\nimport { Inter, Lora as FontLora, Roboto } from '@next/font/google'\nimport localFont from '@next/font/local'\n\nconst myFont = localFont({ src: './my-font.woff2' })\n\nconst roboto = Roboto({\n  weight: '400',\n})\n\nconst lora = FontLora({\n  weight: '400',\n})\n\nconst inter = Inter({\n  subsets: ['latin'],\n});\n\nconst randomObj = {}\n`;\n\nit('should transform next/font AST properly', () => {\n  const { code } = transform(example, { plugins: [TransformFontImports] })!;\n  expect(code).toMatchInlineSnapshot(`\n    \"import inter from \"storybook-nextjs-font-loader?{\\\\\"source\\\\\":\\\\\"next/font/google\\\\\",\\\\\"props\\\\\":{\\\\\"subsets\\\\\":[\\\\\"latin\\\\\"]},\\\\\"fontFamily\\\\\":\\\\\"Inter\\\\\",\\\\\"filename\\\\\":\\\\\"\\\\\"}!next/font/google\";\n    import lora from \"storybook-nextjs-font-loader?{\\\\\"source\\\\\":\\\\\"next/font/google\\\\\",\\\\\"props\\\\\":{\\\\\"weight\\\\\":\\\\\"400\\\\\"},\\\\\"fontFamily\\\\\":\\\\\"Lora\\\\\",\\\\\"filename\\\\\":\\\\\"\\\\\"}!next/font/google\";\n    import roboto from \"storybook-nextjs-font-loader?{\\\\\"source\\\\\":\\\\\"next/font/google\\\\\",\\\\\"props\\\\\":{\\\\\"weight\\\\\":\\\\\"400\\\\\"},\\\\\"fontFamily\\\\\":\\\\\"Roboto\\\\\",\\\\\"filename\\\\\":\\\\\"\\\\\"}!next/font/google\";\n    import myFont from \"storybook-nextjs-font-loader?{\\\\\"source\\\\\":\\\\\"next/font/local\\\\\",\\\\\"props\\\\\":{\\\\\"src\\\\\":\\\\\"./my-font.woff2\\\\\"},\\\\\"fontFamily\\\\\":\\\\\"localFont\\\\\",\\\\\"filename\\\\\":\\\\\"\\\\\"}!next/font/local\";\n    const randomObj = {};\"\n  `);\n});\n\nit('should transform @next/font AST properly', () => {\n  const { code } = transform(exampleLegacy, { plugins: [TransformFontImports] })!;\n  expect(code).toMatchInlineSnapshot(`\n    \"import inter from \"storybook-nextjs-font-loader?{\\\\\"source\\\\\":\\\\\"@next/font/google\\\\\",\\\\\"props\\\\\":{\\\\\"subsets\\\\\":[\\\\\"latin\\\\\"]},\\\\\"fontFamily\\\\\":\\\\\"Inter\\\\\",\\\\\"filename\\\\\":\\\\\"\\\\\"}!@next/font/google\";\n    import lora from \"storybook-nextjs-font-loader?{\\\\\"source\\\\\":\\\\\"@next/font/google\\\\\",\\\\\"props\\\\\":{\\\\\"weight\\\\\":\\\\\"400\\\\\"},\\\\\"fontFamily\\\\\":\\\\\"Lora\\\\\",\\\\\"filename\\\\\":\\\\\"\\\\\"}!@next/font/google\";\n    import roboto from \"storybook-nextjs-font-loader?{\\\\\"source\\\\\":\\\\\"@next/font/google\\\\\",\\\\\"props\\\\\":{\\\\\"weight\\\\\":\\\\\"400\\\\\"},\\\\\"fontFamily\\\\\":\\\\\"Roboto\\\\\",\\\\\"filename\\\\\":\\\\\"\\\\\"}!@next/font/google\";\n    import myFont from \"storybook-nextjs-font-loader?{\\\\\"source\\\\\":\\\\\"@next/font/local\\\\\",\\\\\"props\\\\\":{\\\\\"src\\\\\":\\\\\"./my-font.woff2\\\\\"},\\\\\"fontFamily\\\\\":\\\\\"localFont\\\\\",\\\\\"filename\\\\\":\\\\\"\\\\\"}!@next/font/local\";\n    const randomObj = {};\"\n  `);\n});\n"
  },
  {
    "path": "code/frameworks/nextjs/src/font/babel/index.ts",
    "content": "import type * as BabelCoreNamespace from '@babel/core';\n\nimport {\n  getVariableMetasBySpecifier,\n  isDefined,\n  removeTransformedVariableDeclarations,\n  replaceImportWithParameterImport,\n} from './helpers.ts';\n\ntype Babel = typeof BabelCoreNamespace;\n\n/**\n * Transforms \"next/font\" imports and usages to a webpack loader friendly format with parameters\n *\n * @example // src/example.js // Turns this code: import { Inter, Roboto } from 'next/font/google'\n * import localFont from 'next/font/local'\n *\n * Const myFont = localFont({ src: './my-font.woff2' }) const roboto = Roboto({ weight: '400', })\n *\n * Const inter = Inter({ subsets: ['latin'], });\n *\n * // Into this code: import inter from 'storybook-nextjs-font-loader?{filename: \"src/example.js\",\n * source: \"next/font/google\", fontFamily: \"Inter\", props: {\"subsets\":[\"latin\"]}}!next/font/google'\n * import roboto from 'storybook-nextjs-font-loader?{filename: \"src/example.js\", source:\n * \"next/font/google\", fontFamily: \"Roboto\", props: {\"weight\": \"400\"}}!next/font/google' import\n * myFont from 'storybook-nextjs-font-loader?{filename: \"src/example.js\", source: \"next/font/local\",\n * props: {\"src\": \"./my-font.woff2\"}}!next/font/local'\n *\n * This Plugin tries to adopt the functionality which is provided by the nextjs swc plugin\n * https://github.com/vercel/next.js/pull/40221\n */\nexport default function TransformFontImports({ types }: Babel): BabelCoreNamespace.PluginObj {\n  return {\n    name: 'storybook-nextjs-font-imports',\n    visitor: {\n      ImportDeclaration(path, state) {\n        const { node } = path;\n        const { source } = node;\n        const { filename = '' } = state;\n\n        if (source.value === 'next/font/local' || source.value === '@next/font/local') {\n          const { specifiers } = node;\n\n          // next/font/local only provides a default export\n          const specifier = specifiers[0];\n\n          if (!path.parentPath.isProgram()) {\n            return;\n          }\n\n          const program = path.parentPath;\n\n          const variableMetas = getVariableMetasBySpecifier(program, types, specifier);\n\n          removeTransformedVariableDeclarations(path, types, variableMetas);\n          replaceImportWithParameterImport(path, types, source, variableMetas, filename);\n        }\n\n        if (source.value === 'next/font/google' || source.value === '@next/font/google') {\n          const { specifiers } = node;\n\n          const variableMetas = specifiers\n            .flatMap((specifier) => {\n              if (!path.parentPath.isProgram()) {\n                return [];\n              }\n\n              const program = path.parentPath;\n\n              return getVariableMetasBySpecifier(program, types, specifier);\n            })\n            .filter(isDefined);\n\n          removeTransformedVariableDeclarations(path, types, variableMetas);\n          replaceImportWithParameterImport(path, types, source, variableMetas, filename);\n        }\n      },\n    },\n  };\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/src/font/webpack/configureNextFont.ts",
    "content": "import type { Configuration } from 'webpack';\n\nexport function configureNextFont(baseConfig: Configuration, isSWC?: boolean) {\n  if (isSWC) {\n    baseConfig.module?.rules?.push({\n      test: /next(\\\\|\\/|\\\\\\\\).*(\\\\|\\/|\\\\\\\\)target\\.css$/,\n      loader: '@storybook/nextjs/storybook-nextjs-font-loader',\n    });\n  } else {\n    baseConfig.resolveLoader = {\n      ...baseConfig.resolveLoader,\n      alias: {\n        ...baseConfig.resolveLoader?.alias,\n        'storybook-nextjs-font-loader': '@storybook/nextjs/storybook-nextjs-font-loader',\n      },\n    };\n  }\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/src/font/webpack/loader/google/get-font-face-declarations.ts",
    "content": "import {\n  GoogleFontsDownloadError,\n  GoogleFontsLoadingError,\n} from 'storybook/internal/server-errors';\n\nimport { fetchCSSFromGoogleFonts } from 'next/dist/compiled/@next/font/dist/google/fetch-css-from-google-fonts.js';\nimport { getFontAxes } from 'next/dist/compiled/@next/font/dist/google/get-font-axes.js';\nimport { getGoogleFontsUrl } from 'next/dist/compiled/@next/font/dist/google/get-google-fonts-url.js';\nimport { validateGoogleFontFunctionCall } from 'next/dist/compiled/@next/font/dist/google/validate-google-font-function-call.js';\nimport loaderUtils from 'next/dist/compiled/loader-utils3/index.js';\n\nimport type { LoaderOptions } from '../types.ts';\n\nconst cssCache = new Map<string, string>();\n\nexport async function getFontFaceDeclarations(options: LoaderOptions) {\n  const { fontFamily, weights, styles, selectedVariableAxes, display, variable } =\n    validateGoogleFontFunctionCall(options.fontFamily, options.props);\n\n  const fontAxes = getFontAxes(fontFamily, weights, styles, selectedVariableAxes);\n  const url = getGoogleFontsUrl(fontFamily, fontAxes, display);\n\n  try {\n    const hasCachedCSS = cssCache.has(url);\n    const fontFaceCSS = hasCachedCSS\n      ? cssCache.get(url)\n      : await fetchCSSFromGoogleFonts(url, fontFamily, true).catch(() => null);\n    if (!hasCachedCSS) {\n      cssCache.set(url, fontFaceCSS as string);\n    } else {\n      cssCache.delete(url);\n    }\n    if (fontFaceCSS === null) {\n      throw new GoogleFontsDownloadError({\n        fontFamily,\n        url,\n      });\n    }\n\n    return {\n      id: loaderUtils.getHashDigest(url, 'md5', 'hex', 6),\n      fontFamily,\n      fontFaceCSS,\n      weights,\n      styles,\n      variable,\n    };\n  } catch (error) {\n    throw new GoogleFontsLoadingError({ error, url });\n  }\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/src/font/webpack/loader/local/get-font-face-declarations.ts",
    "content": "import { dirname, join } from 'node:path';\n\nimport { getProjectRoot } from 'storybook/internal/common';\n\nimport { validateLocalFontFunctionCall } from 'next/dist/compiled/@next/font/dist/local/validate-local-font-function-call.js';\nimport loaderUtils from 'next/dist/compiled/loader-utils3/index.js';\n\nimport type { LoaderOptions } from '../types.ts';\n\ntype LocalFontSrc = string | Array<{ path: string; weight?: string; style?: string }>;\n\nexport async function getFontFaceDeclarations(\n  options: LoaderOptions,\n  rootContext: string,\n  swcMode: boolean\n) {\n  const localFontSrc = options.props.src as LocalFontSrc;\n\n  // Parent folder relative to the root context\n  const parentFolder = swcMode\n    ? dirname(join(getProjectRoot(), options.filename)).replace(rootContext, '')\n    : dirname(options.filename).replace(rootContext, '');\n\n  const {\n    weight,\n    style,\n    variable,\n    declarations = [],\n  } = validateLocalFontFunctionCall('', options.props);\n\n  const id = `font-${loaderUtils.getHashDigest(\n    Buffer.from(JSON.stringify(localFontSrc)),\n    'md5',\n    'hex',\n    6\n  )}`;\n\n  const fontDeclarations = declarations\n    .map(({ prop, value }: { prop: string; value: string }) => `${prop}: ${value};`)\n    .join('\\n');\n\n  const getFontFaceCSS = () => {\n    if (typeof localFontSrc === 'string') {\n      const localFontPath = join(parentFolder, localFontSrc).replaceAll('\\\\', '/');\n\n      return `@font-face {\n          font-family: ${id};\n          src: url(.${localFontPath});\n          ${weight ? `font-weight: ${weight};` : ''}\n          ${style ? `font-style: ${style};` : ''}\n          ${fontDeclarations}\n      }`;\n    }\n    return localFontSrc\n      .map((font) => {\n        const localFontPath = join(parentFolder, font.path).replaceAll('\\\\', '/');\n\n        return `@font-face {\n          font-family: ${id};\n          src: url(.${localFontPath});\n          ${font.weight ? `font-weight: ${font.weight};` : ''}\n          ${font.style ? `font-style: ${font.style};` : ''}\n          ${fontDeclarations}\n        }`;\n      })\n      .join('');\n  };\n\n  return {\n    id,\n    fontFamily: id,\n    fontFaceCSS: getFontFaceCSS(),\n    weights: weight ? [weight] : [],\n    styles: style ? [style] : [],\n    variable,\n  };\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/src/font/webpack/loader/storybook-nextjs-font-loader.ts",
    "content": "import { sep } from 'node:path';\n\nimport { getFontFaceDeclarations as getGoogleFontFaceDeclarations } from './google/get-font-face-declarations.ts';\nimport { getFontFaceDeclarations as getLocalFontFaceDeclarations } from './local/get-font-face-declarations.ts';\nimport type { LoaderOptions } from './types.ts';\nimport { getCSSMeta } from './utils/get-css-meta.ts';\nimport { setFontDeclarationsInHead } from './utils/set-font-declarations-in-head.ts';\n\ntype FontFaceDeclaration = {\n  id: string;\n  fontFamily: string;\n  fontFaceCSS: any;\n  weights: string[];\n  styles: string[];\n  variable?: string;\n};\n\nexport default async function storybookNextjsFontLoader(this: any) {\n  const loaderOptions = this.getOptions() as LoaderOptions;\n  let swcMode = false;\n  let options;\n\n  if (Object.keys(loaderOptions).length > 0) {\n    // handles Babel mode\n    options = loaderOptions;\n  } else {\n    // handles SWC mode\n    const importQuery = JSON.parse(this.resourceQuery.slice(1));\n    swcMode = true;\n\n    options = {\n      filename: importQuery.path,\n      fontFamily: importQuery.import,\n      props: importQuery.arguments[0],\n      source: this.context.replace(this.rootContext, ''),\n    };\n  }\n\n  // get execution context\n  const rootCtx = this.rootContext;\n\n  let fontFaceDeclaration: FontFaceDeclaration | undefined;\n\n  const pathSep = sep;\n\n  if (\n    options.source.endsWith(`next${pathSep}font${pathSep}google`) ||\n    options.source.endsWith(`@next${pathSep}font${pathSep}google`)\n  ) {\n    fontFaceDeclaration = await getGoogleFontFaceDeclarations(options);\n  }\n\n  if (\n    options.source.endsWith(`next${pathSep}font${pathSep}local`) ||\n    options.source.endsWith(`@next${pathSep}font${pathSep}local`)\n  ) {\n    fontFaceDeclaration = await getLocalFontFaceDeclarations(options, rootCtx, swcMode);\n  }\n\n  if (typeof fontFaceDeclaration !== 'undefined') {\n    const cssMeta = getCSSMeta(fontFaceDeclaration);\n\n    return `\n    ${setFontDeclarationsInHead({\n      fontFaceCSS: cssMeta.fontFaceCSS,\n      id: fontFaceDeclaration.id,\n      classNamesCSS: cssMeta.classNamesCSS,\n    })}\n\n    module.exports = {\n      className: \"${cssMeta.className}\", \n      style: ${JSON.stringify(cssMeta.style)}\n      ${cssMeta.variableClassName ? `, variable: \"${cssMeta.variableClassName}\"` : ''}\n    }\n    `;\n  }\n\n  return `module.exports = {}`;\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/src/font/webpack/loader/types.ts",
    "content": "export type LoaderOptions = {\n  /** Initial import name. Can be `next/font/google` or `next/font/local` */\n  source: string;\n  /** Props passed to the `next/font` function call */\n  props: Record<string, any>;\n  /** Font Family name */\n  fontFamily: string;\n  /** Filename of the issuer file, which imports `next/font/google` or `next/font/local */\n  filename: string;\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/font/webpack/loader/utils/get-css-meta.ts",
    "content": "type Options = {\n  fontFamily: string;\n  styles: string[];\n  weights: string[];\n  fontFaceCSS: string;\n  variable?: string;\n};\n\nexport function getCSSMeta(options: Options) {\n  const className = getClassName(options);\n  const style = getStylesObj(options);\n  const variableClassName = `__variable_${className}`;\n\n  const classNamesCSS = `\n    .${className} {\n      font-family: ${options.fontFamily};\n      ${isNextCSSPropertyValid(options.styles) ? `font-style: ${options.styles[0]};` : ''}\n      ${\n        isNextCSSPropertyValid(options.weights) && !options.weights[0]?.includes(' ')\n          ? `font-weight: ${options.weights[0]};`\n          : ''\n      }\n    }\n\n    ${\n      options.variable\n        ? `.${variableClassName} { ${options.variable}: '${options.fontFamily}'; }`\n        : ''\n    }\n  `;\n\n  const fontFaceCSS = `${changeFontDisplayToSwap(options.fontFaceCSS)}`;\n\n  return {\n    className,\n    fontFaceCSS,\n    classNamesCSS,\n    style,\n    ...(options.variable ? { variableClassName } : {}),\n  };\n}\n\nfunction getClassName({ styles, weights, fontFamily }: Options) {\n  const font = fontFamily.replaceAll(' ', '-').toLowerCase();\n  const style = isNextCSSPropertyValid(styles) ? styles[0] : null;\n  const weight = isNextCSSPropertyValid(weights) ? weights[0]?.replaceAll(' ', '-') : null;\n  return `${font}${style ? `-${style}` : ''}${weight ? `-${weight}` : ''}`;\n}\n\nfunction getStylesObj({ styles, weights, fontFamily }: Options) {\n  return {\n    fontFamily,\n    ...(isNextCSSPropertyValid(styles) ? { fontStyle: styles[0] } : {}),\n    ...(isNextCSSPropertyValid(weights) ? { fontWeight: weights[0] } : {}),\n  };\n}\n\nfunction isNextCSSPropertyValid(prop: string[]) {\n  return prop.length === 1 && prop[0] !== 'variable';\n}\n\n/**\n * This step is necessary, because otherwise the font-display: optional; property blocks Storybook\n * from rendering the font, because the @font-face declaration is not loaded in time.\n */\nfunction changeFontDisplayToSwap(css: string) {\n  return css.replaceAll('font-display: optional;', 'font-display: block;');\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/src/font/webpack/loader/utils/set-font-declarations-in-head.ts",
    "content": "type Props = {\n  id: string;\n  fontFaceCSS: string;\n  classNamesCSS: string;\n};\n\nexport function setFontDeclarationsInHead({ id, fontFaceCSS, classNamesCSS }: Props) {\n  return `\n    if (!document.getElementById('id-${id}')) {\n      const fontDeclarations = \\`${fontFaceCSS}\\`;\n      const style = document.createElement('style');\n      style.setAttribute('id', 'font-face-${id}');\n      style.innerHTML = fontDeclarations;\n      document.head.appendChild(style);\n\n      const classNamesCSS = \\`${classNamesCSS}\\`;\n      const classNamesStyle = document.createElement('style');\n      classNamesStyle.setAttribute('id', 'classnames-${id}');\n      classNamesStyle.innerHTML = classNamesCSS;\n      document.head.appendChild(classNamesStyle);\n\n    }\n  `;\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/src/globals.d.ts",
    "content": "declare module 'next/dist/compiled';\ndeclare module 'next/dist/compiled/babel/plugin-transform-modules-commonjs';\ndeclare module 'next/dist/compiled/babel/plugin-syntax-jsx';\ndeclare module 'next/dist/compiled/loader-utils3/index.js';\n"
  },
  {
    "path": "code/frameworks/nextjs/src/head-manager/decorator.tsx",
    "content": "import * as React from 'react';\n\nimport HeadManagerProvider from './head-manager-provider.tsx';\n\nexport const HeadManagerDecorator = (Story: React.FC): React.ReactNode => {\n  return (\n    <HeadManagerProvider>\n      <Story />\n    </HeadManagerProvider>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/head-manager/head-manager-provider.tsx",
    "content": "import type { PropsWithChildren } from 'react';\nimport React, { useMemo } from 'react';\n\nimport initHeadManager from 'next/dist/client/head-manager.js';\nimport { HeadManagerContext } from 'next/dist/shared/lib/head-manager-context.shared-runtime.js';\n\ntype HeadManagerValue = {\n  updateHead?: ((state: JSX.Element[]) => void) | undefined;\n  mountedInstances?: Set<unknown>;\n  updateScripts?: ((state: any) => void) | undefined;\n  scripts?: any;\n  getIsSsr?: () => boolean;\n  appDir?: boolean | undefined;\n  nonce?: string | undefined;\n};\n\nconst HeadManagerProvider: React.FC<PropsWithChildren> = ({ children }) => {\n  const headManager: HeadManagerValue = useMemo(initHeadManager, []);\n  headManager.getIsSsr = () => false;\n\n  return <HeadManagerContext.Provider value={headManager}>{children}</HeadManagerContext.Provider>;\n};\n\nexport default HeadManagerProvider;\n"
  },
  {
    "path": "code/frameworks/nextjs/src/image-context.ts",
    "content": "import { createContext } from 'react';\n\nimport type { ImageProps, StaticImageData } from 'next/image';\nimport type { ImageProps as LegacyImageProps } from 'next/legacy/image';\n\n// StaticRequire needs to be in scope for the TypeScript compiler to work.\n// See: https://github.com/microsoft/TypeScript/issues/5711\n// Since next/image doesn't export StaticRequire we need to re-define it here and set src's type to it.\ninterface StaticRequire {\n  default: StaticImageData;\n}\n\ndeclare type StaticImport = StaticRequire | StaticImageData;\n\nexport const ImageContext = createContext<\n  Partial<Omit<ImageProps, 'src'> & { src: string | StaticImport }> & Omit<LegacyImageProps, 'src'>\n>({});\n"
  },
  {
    "path": "code/frameworks/nextjs/src/images/decorator.tsx",
    "content": "import * as React from 'react';\n\nimport type { Addon_StoryContext } from 'storybook/internal/types';\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore-error (this only errors during compilation for production)\nimport { ImageContext as ImageContextValue } from '@storybook/nextjs/image-context';\n\nimport { type ImageContext as ImageContextType } from '../image-context.ts';\n\nconst ImageContext = ImageContextValue as typeof ImageContextType;\n\nexport const ImageDecorator = (\n  Story: React.FC,\n  { parameters }: Addon_StoryContext\n): React.ReactNode => {\n  if (!parameters.nextjs?.image) {\n    return <Story />;\n  }\n\n  return (\n    <ImageContext.Provider value={parameters.nextjs.image}>\n      <Story />\n    </ImageContext.Provider>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/images/next-image-default-loader.tsx",
    "content": "import type * as _NextImage from 'next/image';\n\nexport const defaultLoader = ({ src, width, quality = 75 }: _NextImage.ImageLoaderProps) => {\n  const missingValues = [];\n  if (!src) {\n    missingValues.push('src');\n  }\n\n  if (!width) {\n    missingValues.push('width');\n  }\n\n  if (missingValues.length > 0) {\n    throw new Error(\n      `Next Image Optimization requires ${missingValues.join(\n        ', '\n      )} to be provided. Make sure you pass them as props to the \\`next/image\\` component. Received: ${JSON.stringify(\n        {\n          src,\n          width,\n          quality,\n        }\n      )}`\n    );\n  }\n\n  const url = new URL(src, window.location.href);\n\n  if (!url.searchParams.has('w') && !url.searchParams.has('q')) {\n    url.searchParams.set('w', width.toString());\n    url.searchParams.set('q', quality.toString());\n  }\n\n  if (!src.startsWith('http://') && !src.startsWith('https://')) {\n    return url.toString().slice(url.origin.length);\n  }\n\n  return url.toString();\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/images/next-image.tsx",
    "content": "/* eslint-disable @typescript-eslint/ban-ts-comment */\nimport React from 'react';\n\n// @ts-ignore-error (this only errors during compilation for production)\nimport { ImageContext as ImageContextValue } from '@storybook/nextjs/image-context';\n\nimport type * as _NextImage from 'next/image';\n// @ts-ignore import is aliased in webpack config\nimport * as NextImageNamespace from 'sb-original/next/image';\n\nimport { type ImageContext as ImageContextType } from '../image-context.ts';\nimport { defaultLoader } from './next-image-default-loader.tsx';\n\nconst OriginalNextImage = NextImageNamespace.default;\nconst { getImageProps: originalGetImageProps } = NextImageNamespace;\nconst ImageContext = ImageContextValue as typeof ImageContextType;\n\nconst MockedNextImage = React.forwardRef<HTMLImageElement, _NextImage.ImageProps>(\n  ({ loader, ...props }, ref) => {\n    const imageParameters = React.useContext(ImageContext);\n\n    return (\n      <OriginalNextImage\n        ref={ref}\n        {...imageParameters}\n        {...props}\n        loader={loader ?? defaultLoader}\n      />\n    );\n  }\n);\n\nMockedNextImage.displayName = 'NextImage';\n\nexport const getImageProps = (props: _NextImage.ImageProps) =>\n  originalGetImageProps?.({ loader: defaultLoader, ...props });\n\nexport default MockedNextImage;\n"
  },
  {
    "path": "code/frameworks/nextjs/src/images/next-legacy-image.tsx",
    "content": "/* eslint-disable @typescript-eslint/ban-ts-comment */\nimport React from 'react';\n\n// @ts-ignore-error (this only errors during compilation for production)\nimport { ImageContext as ImageContextValue } from '@storybook/nextjs/image-context';\n\nimport type * as _NextLegacyImage from 'next/legacy/image';\n// @ts-ignore import is aliased in webpack config\nimport OriginalNextLegacyImage from 'sb-original/next/legacy/image';\n\nimport { type ImageContext as ImageContextType } from '../image-context.ts';\nimport { defaultLoader } from './next-image-default-loader.tsx';\n\nconst ImageContext = ImageContextValue as typeof ImageContextType;\n\nfunction NextLegacyImage({ loader, ...props }: _NextLegacyImage.ImageProps) {\n  const imageParameters = React.useContext(ImageContext);\n\n  return (\n    <OriginalNextLegacyImage {...imageParameters} {...props} loader={loader ?? defaultLoader} />\n  );\n}\n\nexport default NextLegacyImage;\n"
  },
  {
    "path": "code/frameworks/nextjs/src/images/webpack.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport type { NextConfig } from 'next';\nimport semver from 'semver';\nimport type { RuleSetRule, Configuration as WebpackConfig } from 'webpack';\n\nimport { getNextjsVersion } from '../utils.ts';\n\nexport const configureImages = (baseConfig: WebpackConfig, nextConfig: NextConfig): void => {\n  configureStaticImageImport(baseConfig, nextConfig);\n  configureImageDefaults(baseConfig);\n};\n\nconst fallbackFilename = 'static/media/[path][name][ext]';\n\nconst configureImageDefaults = (baseConfig: WebpackConfig): void => {\n  const version = getNextjsVersion();\n  const resolve = baseConfig.resolve ?? {};\n  resolve.alias = {\n    ...resolve.alias,\n    'sb-original/next/image': fileURLToPath(import.meta.resolve('next/image')),\n    'next/image': fileURLToPath(import.meta.resolve('@storybook/nextjs/images/next-image')),\n  };\n\n  if (semver.satisfies(version, '>=13.0.0')) {\n    resolve.alias = {\n      ...resolve.alias,\n      'sb-original/next/legacy/image': fileURLToPath(import.meta.resolve('next/legacy/image')),\n      'next/legacy/image': fileURLToPath(\n        import.meta.resolve('@storybook/nextjs/images/next-legacy-image')\n      ),\n    };\n  }\n};\n\nconst configureStaticImageImport = (baseConfig: WebpackConfig, nextConfig: NextConfig): void => {\n  const rules = baseConfig.module?.rules;\n\n  const assetRule = rules?.find(\n    (rule) =>\n      rule && typeof rule !== 'string' && rule.test instanceof RegExp && rule.test.test('test.jpg')\n  ) as RuleSetRule;\n\n  if (!assetRule) {\n    return;\n  }\n\n  assetRule.test = /\\.(apng|eot|otf|ttf|woff|woff2|cur|ani|pdf)(\\?.*)?$/;\n\n  rules?.push({\n    test: /\\.(png|jpg|jpeg|gif|webp|avif|ico|bmp|svg)$/i,\n    issuer: { not: /\\.(css|scss|sass)$/ },\n    use: [\n      {\n        loader: fileURLToPath(import.meta.resolve('@storybook/nextjs/next-image-loader-stub')),\n        options: {\n          filename: assetRule.generator?.filename ?? fallbackFilename,\n          nextConfig,\n        },\n      },\n    ],\n  });\n  rules?.push({\n    test: /\\.(png|jpg|jpeg|gif|webp|avif|ico|bmp|svg)$/i,\n    issuer: /\\.(css|scss|sass)$/,\n    type: 'asset/resource',\n    generator: {\n      filename: assetRule.generator?.filename ?? fallbackFilename,\n    },\n  });\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/imports/webpack.ts",
    "content": "import { loadConfig } from 'tsconfig-paths';\nimport TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin';\nimport type { Configuration as WebpackConfig } from 'webpack';\n\nexport const configureImports = ({\n  baseConfig,\n  configDir,\n}: {\n  baseConfig: WebpackConfig;\n  configDir: string;\n}): void => {\n  const configLoadResult = loadConfig(configDir);\n\n  if (configLoadResult.resultType === 'failed') {\n    // either not a typescript project or tsconfig is not found - we bail\n    return;\n  }\n\n  baseConfig.resolve ??= {};\n  baseConfig.resolve.plugins ??= [];\n\n  baseConfig.resolve.plugins.push(\n    new TsconfigPathsPlugin({\n      configFile: configLoadResult.configFileAbsolutePath,\n      extensions: ['.js', '.jsx', '.ts', '.tsx'],\n    }) as any\n  );\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/index.ts",
    "content": "import type { AddonTypes, InferTypes, PreviewAddon } from 'storybook/internal/csf';\nimport type { ProjectAnnotations } from 'storybook/internal/types';\n\nimport type { ReactPreview } from '@storybook/react';\nimport { __definePreview } from '@storybook/react';\nimport type { ReactTypes } from '@storybook/react';\n\nimport * as nextPreview from './preview.tsx';\nimport type { NextJsTypes } from './types.ts';\n\nexport * from '@storybook/react';\nexport * from './types.ts';\n// @ts-expect-error (double exports)\nexport * from './portable-stories.ts';\n\nexport function definePreview<Addons extends PreviewAddon<never>[]>(\n  preview: { addons?: Addons } & ProjectAnnotations<ReactTypes & NextJsTypes & InferTypes<Addons>>\n): NextPreview<InferTypes<Addons>> {\n  // @ts-expect-error hard\n  return __definePreview({\n    ...preview,\n    addons: [nextPreview, ...(preview.addons ?? [])],\n  });\n}\n\nexport interface NextPreview<T extends AddonTypes> extends ReactPreview<NextJsTypes & T> {}\n"
  },
  {
    "path": "code/frameworks/nextjs/src/next-image-loader-stub.ts",
    "content": "import { imageSize } from 'image-size';\nimport { interpolateName } from 'loader-utils';\nimport type { NextConfig } from 'next';\nimport type { RawLoaderDefinition } from 'webpack';\n\ninterface LoaderOptions {\n  filename: string;\n  nextConfig: NextConfig;\n}\n\nconst nextImageLoaderStub: RawLoaderDefinition<LoaderOptions> = async function NextImageLoader(\n  content\n) {\n  const { filename, nextConfig } = this.getOptions();\n  const opts = {\n    context: this.rootContext,\n    content,\n  };\n  const outputPath = interpolateName(this, filename.replace('[ext]', '.[ext]'), opts);\n\n  this.emitFile(outputPath, content);\n\n  if (nextConfig.images?.disableStaticImages) {\n    return `const src = '${outputPath}'; export default src;`;\n  }\n\n  const { width, height } = imageSize(content as Uint8Array);\n\n  return `export default ${JSON.stringify({\n    src: outputPath,\n    height,\n    width,\n    blurDataURL: outputPath,\n  })};`;\n};\n\nnextImageLoaderStub.raw = true;\n\nexport default nextImageLoaderStub;\nexport const raw = true;\n"
  },
  {
    "path": "code/frameworks/nextjs/src/node/index.ts",
    "content": "import type { StorybookConfig } from '../types.ts';\n\nexport function defineMain(config: StorybookConfig) {\n  return config;\n}\n\nexport type { StorybookConfig };\n"
  },
  {
    "path": "code/frameworks/nextjs/src/nodePolyfills/webpack.ts",
    "content": "import NodePolyfillPlugin from 'node-polyfill-webpack-plugin';\nimport type { Configuration } from 'webpack';\n\nexport const configureNodePolyfills = (baseConfig: Configuration) => {\n  // This is added as a way to avoid issues caused by Next.js 13.4.3\n  // introduced by gzip-size\n  baseConfig.plugins = [...(baseConfig.plugins || []), new NodePolyfillPlugin()];\n\n  baseConfig.resolve = {\n    ...baseConfig.resolve,\n    fallback: {\n      fs: false,\n    },\n  };\n\n  return baseConfig;\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/portable-stories.ts",
    "content": "import type {\n  Args,\n  ComposedStoryFn,\n  NamedOrDefaultProjectAnnotations,\n  NormalizedProjectAnnotations,\n  ProjectAnnotations,\n  Store_CSFExports,\n  StoriesWithPartialProps,\n  StoryAnnotationsOrFn,\n} from 'storybook/internal/types';\n\nimport type { Meta, ReactRenderer } from '@storybook/react';\n\nimport {\n  composeConfigs,\n  composeStories as originalComposeStories,\n  composeStory as originalComposeStory,\n  setProjectAnnotations as originalSetProjectAnnotations,\n  setDefaultProjectAnnotations,\n} from 'storybook/preview-api';\n\n// ! ATTENTION: This needs to be a relative import so it gets prebundled. This is to avoid ESM issues in Nextjs + Jest setups\nimport { INTERNAL_DEFAULT_PROJECT_ANNOTATIONS as reactAnnotations } from '../../../renderers/react/src/portable-stories.tsx';\nimport * as nextJsAnnotations from './preview.tsx';\n\n/**\n * Function that sets the globalConfig of your storybook. The global config is the preview module of\n * your .storybook folder.\n *\n * It should be run a single time, so that your global config (e.g. decorators) is applied to your\n * stories when using `composeStories` or `composeStory`.\n *\n * Example:\n *\n * ```jsx\n * // setup-file.js\n * import { setProjectAnnotations } from '@storybook/nextjs';\n * import projectAnnotations from './.storybook/preview';\n *\n * setProjectAnnotations(projectAnnotations);\n * ```\n *\n * @param projectAnnotations - E.g. (import projectAnnotations from '../.storybook/preview')\n */\nexport function setProjectAnnotations(\n  projectAnnotations:\n    | NamedOrDefaultProjectAnnotations<any>\n    | NamedOrDefaultProjectAnnotations<any>[]\n): NormalizedProjectAnnotations<ReactRenderer> {\n  setDefaultProjectAnnotations(INTERNAL_DEFAULT_PROJECT_ANNOTATIONS);\n  return originalSetProjectAnnotations(\n    projectAnnotations\n  ) as NormalizedProjectAnnotations<ReactRenderer>;\n}\n\n// This will not be necessary once we have auto preset loading\nconst INTERNAL_DEFAULT_PROJECT_ANNOTATIONS: ProjectAnnotations<ReactRenderer> = composeConfigs([\n  reactAnnotations,\n  nextJsAnnotations,\n]);\n\n/**\n * Function that will receive a story along with meta (e.g. a default export from a .stories file)\n * and optionally projectAnnotations e.g. (import * from '../.storybook/preview) and will return a\n * composed component that has all args/parameters/decorators/etc combined and applied to it.\n *\n * It's very useful for reusing a story in scenarios outside of Storybook like unit testing.\n *\n * Example:\n *\n * ```jsx\n * import { render } from '@testing-library/react';\n * import { composeStory } from '@storybook/nextjs';\n * import Meta, { Primary as PrimaryStory } from './Button.stories';\n *\n * const Primary = composeStory(PrimaryStory, Meta);\n *\n * test('renders primary button with Hello World', () => {\n *   const { getByText } = render(<Primary>Hello world</Primary>);\n *   expect(getByText(/Hello world/i)).not.toBeNull();\n * });\n * ```\n *\n * @param story\n * @param componentAnnotations - E.g. (import Meta from './Button.stories')\n * @param [projectAnnotations] - E.g. (import * as projectAnnotations from '../.storybook/preview')\n *   this can be applied automatically if you use `setProjectAnnotations` in your setup files.\n * @param [exportsName] - In case your story does not contain a name and you want it to have a name.\n */\nexport function composeStory<TArgs extends Args = Args>(\n  story: StoryAnnotationsOrFn<ReactRenderer, TArgs>,\n  componentAnnotations: Meta<TArgs | any>,\n  projectAnnotations?: ProjectAnnotations<ReactRenderer>,\n  exportsName?: string\n): ComposedStoryFn<ReactRenderer, Partial<TArgs>> {\n  return originalComposeStory<ReactRenderer, TArgs>(\n    story as StoryAnnotationsOrFn<ReactRenderer, Args>,\n    componentAnnotations,\n    projectAnnotations,\n    globalThis.globalProjectAnnotations ?? INTERNAL_DEFAULT_PROJECT_ANNOTATIONS,\n    exportsName\n  );\n}\n\n/**\n * Function that will receive a stories import (e.g. `import * as stories from './Button.stories'`)\n * and optionally projectAnnotations (e.g. `import * from '../.storybook/preview`) and will return\n * an object containing all the stories passed, but now as a composed component that has all\n * args/parameters/decorators/etc combined and applied to it.\n *\n * It's very useful for reusing stories in scenarios outside of Storybook like unit testing.\n *\n * Example:\n *\n * ```jsx\n * import { render } from '@testing-library/react';\n * import { composeStories } from '@storybook/nextjs';\n * import * as stories from './Button.stories';\n *\n * const { Primary, Secondary } = composeStories(stories);\n *\n * test('renders primary button with Hello World', () => {\n *   const { getByText } = render(<Primary>Hello world</Primary>);\n *   expect(getByText(/Hello world/i)).not.toBeNull();\n * });\n * ```\n *\n * @param csfExports - E.g. (import * as stories from './Button.stories')\n * @param [projectAnnotations] - E.g. (import * as projectAnnotations from '../.storybook/preview')\n *   this can be applied automatically if you use `setProjectAnnotations` in your setup files.\n */\nexport function composeStories<TModule extends Store_CSFExports<ReactRenderer, any>>(\n  csfExports: TModule,\n  projectAnnotations?: ProjectAnnotations<ReactRenderer>\n) {\n  // @ts-expect-error (Converted from ts-ignore)\n  const composedStories = originalComposeStories(csfExports, projectAnnotations, composeStory);\n\n  return composedStories as unknown as Omit<\n    StoriesWithPartialProps<ReactRenderer, TModule>,\n    keyof Store_CSFExports\n  >;\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/src/preset.ts",
    "content": "// https://storybook.js.org/docs/react/addons/writing-presets\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { getProjectRoot } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\nimport type { PresetProperty } from 'storybook/internal/types';\n\nimport type { ConfigItem, PluginItem, TransformOptions } from '@babel/core';\nimport { loadPartialConfig } from '@babel/core';\nimport semver from 'semver';\n\nimport nextBabelPreset from './babel/preset.ts';\nimport { configureConfig } from './config/webpack.ts';\nimport TransformFontImports from './font/babel/index.ts';\nimport type { FrameworkOptions, StorybookConfig } from './types.ts';\nimport { isNextVersionGte } from './utils.ts';\n\nexport const addons: PresetProperty<'addons'> = [\n  fileURLToPath(import.meta.resolve('@storybook/preset-react-webpack')),\n];\n\nexport const core: PresetProperty<'core'> = async (config, options) => {\n  const framework = await options.presets.apply<StorybookConfig['framework']>('framework');\n\n  // Load the Next.js configuration before we need it in webpackFinal (below).\n  // This gives Next.js an opportunity to override some of webpack's internals\n  // (see next/dist/server/config-utils.js) before @storybook/builder-webpack5\n  // starts to use it. Without this, webpack's file system cache (fsCache: true)\n  // does not work.\n  await configureConfig({\n    // Pass in a dummy webpack config object for now, since we don't want to\n    // modify the real one yet. We pass in the real one in webpackFinal.\n    baseConfig: {},\n    nextConfigPath: typeof framework === 'string' ? undefined : framework.options.nextConfigPath,\n  });\n\n  return {\n    ...config,\n    builder: {\n      name: fileURLToPath(import.meta.resolve('@storybook/builder-webpack5')),\n      options: {\n        ...(typeof framework === 'string' ? {} : framework.options.builder || {}),\n      },\n    },\n    renderer: fileURLToPath(import.meta.resolve('@storybook/react/preset')),\n  };\n};\n\nexport const previewAnnotations: PresetProperty<'previewAnnotations'> = (entry = []) => {\n  const annotations = [...entry, fileURLToPath(import.meta.resolve('@storybook/nextjs/preview'))];\n\n  const isNext16orNewer = isNextVersionGte('16.0.0');\n\n  // TODO: Remove this once we only support Next.js v16 and above\n  if (!isNext16orNewer) {\n    annotations.push(fileURLToPath(import.meta.resolve('@storybook/nextjs/config/preview')));\n  }\n\n  return annotations;\n};\n\nexport const babel: PresetProperty<'babel'> = async (baseConfig: TransformOptions) => {\n  const configPartial = loadPartialConfig({\n    ...baseConfig,\n    filename: `${getProjectRoot()}/__fake__.js`,\n  });\n\n  const options = configPartial?.options;\n\n  const isPresetConfigItem = (preset: any): preset is ConfigItem => {\n    return typeof preset === 'object' && preset !== null && 'file' in preset;\n  };\n\n  const isNextBabelConfig = (preset: PluginItem) =>\n    (Array.isArray(preset) && preset[0] === 'next/babel') ||\n    preset === 'next/babel' ||\n    (isPresetConfigItem(preset) && preset.file?.request === 'next/babel');\n\n  const hasNextBabelConfig = options?.presets?.find(isNextBabelConfig);\n\n  const presets =\n    options?.presets?.filter(\n      (preset) =>\n        !(\n          (isPresetConfigItem(preset) &&\n            (preset as ConfigItem).file?.request ===\n              fileURLToPath(import.meta.resolve('@babel/preset-react'))) ||\n          isNextBabelConfig(preset)\n        )\n    ) ?? [];\n\n  if (hasNextBabelConfig) {\n    if (Array.isArray(hasNextBabelConfig) && hasNextBabelConfig[1]) {\n      presets.push([nextBabelPreset, hasNextBabelConfig[1]]);\n    } else if (\n      isPresetConfigItem(hasNextBabelConfig) &&\n      hasNextBabelConfig.file?.request === 'next/babel'\n    ) {\n      presets.push([nextBabelPreset, hasNextBabelConfig.options]);\n    } else {\n      presets.push(nextBabelPreset);\n    }\n  } else {\n    presets.push(nextBabelPreset);\n  }\n\n  const plugins = [...(options?.plugins ?? []), TransformFontImports];\n\n  return {\n    ...options,\n    plugins,\n    presets,\n    babelrc: false,\n    configFile: false,\n    overrides: [\n      ...(options?.overrides ?? []),\n      // We need to re-apply the default storybook babel override from:\n      // https://github.com/storybookjs/storybook/blob/next/code/core/src/core-server/presets/common-preset.ts\n      // Because it get lost in the loadPartialConfig call above.\n      // See https://github.com/storybookjs/storybook/issues/28467\n      {\n        include: /(story|stories)\\.[cm]?[jt]sx?$/,\n        presets: [\n          [\n            'next/dist/compiled/babel/preset-env',\n            {\n              bugfixes: true,\n              targets: {\n                chrome: 100,\n                safari: 15,\n                firefox: 91,\n              },\n            },\n          ],\n        ],\n      },\n    ],\n  };\n};\n\nexport const webpackFinal: StorybookConfig['webpackFinal'] = async (baseConfig, options) => {\n  const { nextConfigPath } = await options.presets.apply<FrameworkOptions>('frameworkOptions');\n  const nextConfig = await configureConfig({\n    baseConfig,\n    nextConfigPath,\n  });\n\n  // Use dynamic imports to ensure these modules that use webpack load after\n  // Next.js has been configured (above), and has replaced webpack with its precompiled\n  // version.\n  const { configureNextFont } = await import('./font/webpack/configureNextFont.ts');\n  const { configureRuntimeNextjsVersionResolution, getNextjsVersion } = await import('./utils.ts');\n  const { configureImports } = await import('./imports/webpack.ts');\n  const { configureCss } = await import('./css/webpack.ts');\n  const { configureImages } = await import('./images/webpack.ts');\n  const { configureStyledJsx } = await import('./styledJsx/webpack.ts');\n  const { configureNodePolyfills } = await import('./nodePolyfills/webpack.ts');\n  const { configureAliases } = await import('./aliases/webpack.ts');\n  const { configureFastRefresh } = await import('./fastRefresh/webpack.ts');\n  const { configureRSC } = await import('./rsc/webpack.ts');\n  const { configureSWCLoader } = await import('./swc/loader.ts');\n  const { configureBabelLoader } = await import('./babel/loader.ts');\n\n  const babelRCPath = join(getProjectRoot(), '.babelrc');\n  const babelConfigPath = join(getProjectRoot(), 'babel.config.js');\n  const hasBabelConfig = existsSync(babelRCPath) || existsSync(babelConfigPath);\n  const nextjsVersion = getNextjsVersion();\n  const isDevelopment = options.configType !== 'PRODUCTION';\n\n  const isNext14orNewer = semver.gte(nextjsVersion, '14.0.0');\n  const useSWC =\n    isNext14orNewer && (nextConfig.experimental?.forceSwcTransforms || !hasBabelConfig);\n\n  configureNextFont(baseConfig, useSWC);\n  configureRuntimeNextjsVersionResolution(baseConfig);\n  configureImports({ baseConfig, configDir: options.configDir });\n  configureCss(baseConfig, nextConfig);\n  configureImages(baseConfig, nextConfig);\n  configureStyledJsx(baseConfig);\n  configureNodePolyfills(baseConfig);\n  configureAliases(baseConfig);\n\n  if (isDevelopment) {\n    configureFastRefresh(baseConfig);\n  }\n\n  if (options.features?.experimentalRSC) {\n    configureRSC(baseConfig);\n  }\n\n  if (useSWC) {\n    logger.info('Using SWC as compiler');\n    await configureSWCLoader(baseConfig, options, nextConfig);\n  } else {\n    logger.info('Using Babel as compiler');\n    await configureBabelLoader(baseConfig, options, nextConfig);\n  }\n\n  return baseConfig;\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/preview.tsx",
    "content": "import type { Addon_DecoratorFunction, Addon_LoaderFunction } from 'storybook/internal/types';\n\n// We need this import to be a singleton, and because it's used in multiple entrypoints\n// both in ESM and CJS, importing it via the package name instead of having a local import\n// is the only way to achieve it actually being a singleton\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore we must ignore types here as during compilation they are not generated yet\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore we must ignore types here as during compilation they are not generated yet\nimport { createNavigation } from '@storybook/nextjs/navigation.mock';\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore we must ignore types here as during compilation they are not generated yet\nimport { createRouter } from '@storybook/nextjs/router.mock';\n\nimport { isNextRouterError } from 'next/dist/client/components/is-next-router-error.js';\n\nimport { HeadManagerDecorator } from './head-manager/decorator.tsx';\nimport { ImageDecorator } from './images/decorator.tsx';\nimport { RouterDecorator } from './routing/decorator.tsx';\nimport { StyledJsxDecorator } from './styledJsx/decorator.tsx';\n\nfunction addNextHeadCount() {\n  const meta = document.createElement('meta');\n  meta.name = 'next-head-count';\n  meta.content = '0';\n  document.head.appendChild(meta);\n}\n\nfunction isAsyncClientComponentError(error: unknown) {\n  return (\n    typeof error === 'string' &&\n    (error.includes('Only Server Components can be async at the moment.') ||\n      error.includes('A component was suspended by an uncached promise.') ||\n      error.includes('async/await is not yet supported in Client Components'))\n  );\n}\naddNextHeadCount();\n\n// Copying Next patch of console.error:\n// https://github.com/vercel/next.js/blob/a74deb63e310df473583ab6f7c1783bc609ca236/packages/next/src/client/app-index.tsx#L15\nconst origConsoleError = globalThis.console.error;\nglobalThis.console.error = (...args: unknown[]) => {\n  const error = args[0];\n  if (isNextRouterError(error) || isAsyncClientComponentError(error)) {\n    return;\n  }\n  origConsoleError.apply(globalThis.console, args);\n};\n\nglobalThis.addEventListener('error', (ev: WindowEventMap['error']): void => {\n  if (isNextRouterError(ev.error) || isAsyncClientComponentError(ev.error)) {\n    ev.preventDefault();\n    return;\n  }\n});\n\nexport const decorators: Addon_DecoratorFunction<any>[] = [\n  StyledJsxDecorator,\n  ImageDecorator,\n  RouterDecorator,\n  HeadManagerDecorator,\n];\n\nexport const loaders: Addon_LoaderFunction = async ({ globals, parameters }) => {\n  const { router, appDirectory } = parameters.nextjs ?? {};\n  if (appDirectory) {\n    createNavigation(router);\n  } else {\n    createRouter({\n      locale: globals.locale,\n      ...router,\n    });\n  }\n};\n\nexport const parameters = {\n  docs: {\n    source: {\n      excludeDecorators: true,\n    },\n  },\n  react: {\n    rootOptions: {\n      onCaughtError(error: unknown) {\n        if (isNextRouterError(error)) {\n          return;\n        }\n        console.error(error);\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/routing/app-router-provider.tsx",
    "content": "// We need this import to be a singleton, and because it's used in multiple entrypoints\n// both in ESM and CJS, importing it via the package name instead of having a local import\n// is the only way to achieve it actually being a singleton\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore we must ignore types here as during compilation they are not generated yet\nimport React, { useMemo } from 'react';\n\nimport { getRouter } from '@storybook/nextjs/navigation.mock';\n\nimport type { FlightRouterState } from 'next/dist/server/app-render/types';\nimport {\n  AppRouterContext,\n  GlobalLayoutRouterContext,\n  LayoutRouterContext,\n} from 'next/dist/shared/lib/app-router-context.shared-runtime.js';\nimport {\n  PathParamsContext,\n  PathnameContext,\n  SearchParamsContext,\n} from 'next/dist/shared/lib/hooks-client-context.shared-runtime.js';\nimport { PAGE_SEGMENT_KEY } from 'next/dist/shared/lib/segment.js';\n\nimport type { RouteParams } from './types.tsx';\n\n// Using an inline type so we can support Next 14 and lower\n// from https://github.com/vercel/next.js/blob/v15.0.3/packages/next/src/server/request/params.ts#L25\ntype Params = Record<string, string | Array<string> | undefined>;\n\ntype AppRouterProviderProps = {\n  routeParams: RouteParams;\n};\n\n// Since Next 14.2.x\n// https://github.com/vercel/next.js/pull/60708/files#diff-7b6239af735eba0c401e1a0db1a04dd4575c19a031934f02d128cf3ac813757bR106\nfunction getSelectedParams(currentTree: FlightRouterState, params: Params = {}): Params {\n  const parallelRoutes = currentTree[1];\n\n  for (const parallelRoute of Object.values(parallelRoutes)) {\n    const segment = parallelRoute[0];\n    const isDynamicParameter = Array.isArray(segment);\n    const segmentValue = isDynamicParameter ? segment[1] : segment;\n\n    if (!segmentValue || segmentValue.startsWith(PAGE_SEGMENT_KEY)) {\n      continue;\n    }\n\n    // Ensure catchAll and optional catchall are turned into an array\n    const isCatchAll = isDynamicParameter && (segment[2] === 'c' || segment[2] === 'oc');\n\n    if (isCatchAll) {\n      params[segment[0]] = Array.isArray(segment[1]) ? segment[1] : segment[1].split('/');\n    } else if (isDynamicParameter) {\n      params[segment[0]] = segment[1];\n    }\n\n    params = getSelectedParams(parallelRoute, params);\n  }\n\n  return params;\n}\n\nconst getParallelRoutes = (segmentsList: Array<string>): FlightRouterState => {\n  const segment = segmentsList.shift();\n\n  if (segment) {\n    return [segment, { children: getParallelRoutes(segmentsList) }];\n  }\n\n  return [] as any;\n};\n\nexport const AppRouterProvider: React.FC<React.PropsWithChildren<AppRouterProviderProps>> = ({\n  children,\n  routeParams,\n}) => {\n  const { pathname, query, segments = [] } = routeParams;\n\n  const tree: FlightRouterState = [pathname, { children: getParallelRoutes([...segments]) }];\n  const pathParams = useMemo(() => {\n    const params: Params = {};\n    const currentSegments = routeParams.segments;\n\n    if (currentSegments) {\n      if (Array.isArray(currentSegments)) {\n        for (const segmentEntry of currentSegments) {\n          if (\n            Array.isArray(segmentEntry) &&\n            segmentEntry.length === 2 &&\n            typeof segmentEntry[0] === 'string'\n          ) {\n            const key: string = segmentEntry[0];\n            const value = segmentEntry[1] as string | string[] | undefined;\n            params[key] = value;\n          }\n        }\n      } else if (typeof currentSegments === 'object' && !Array.isArray(currentSegments)) {\n        const segmentObject = currentSegments as Record<string, string | string[] | undefined>;\n        for (const key in segmentObject) {\n          if (Object.prototype.hasOwnProperty.call(segmentObject, key)) {\n            params[key] = segmentObject[key];\n          }\n        }\n      }\n    }\n    return params;\n  }, [routeParams.segments]);\n\n  const newLazyCacheNode = {\n    lazyData: null,\n    rsc: null,\n    prefetchRsc: null,\n    head: null,\n    prefetchHead: null,\n    parallelRoutes: new Map(),\n    loading: null,\n  };\n\n  // https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/app-router.tsx#L436\n  return (\n    <PathParamsContext.Provider value={pathParams}>\n      <PathnameContext.Provider value={pathname}>\n        <SearchParamsContext.Provider value={new URLSearchParams(query)}>\n          <GlobalLayoutRouterContext.Provider\n            value={{\n              // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n              // @ts-ignore (Only available in Next.js >= v15.1.1)\n              changeByServerResponse() {\n                // NOOP\n              },\n              buildId: 'storybook',\n              tree,\n              focusAndScrollRef: {\n                apply: false,\n                hashFragment: null,\n                segmentPaths: [tree],\n                onlyHashChange: false,\n              },\n              nextUrl: pathname,\n            }}\n          >\n            <AppRouterContext.Provider value={getRouter()}>\n              <LayoutRouterContext.Provider\n                value={{\n                  // TODO Remove when dropping Next.js < v15.1.1\n                  childNodes: new Map(),\n                  tree,\n                  // TODO END\n\n                  // START Next.js v15.2 support\n                  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n                  // @ts-ignore Only available in Next.js >= v15.1.1\n                  parentTree: tree,\n                  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n                  // @ts-ignore Only available in Next.js >= v15.1.1\n                  parentCacheNode: newLazyCacheNode,\n                  // END\n                  url: pathname,\n                  loading: null,\n                }}\n              >\n                {children}\n              </LayoutRouterContext.Provider>\n            </AppRouterContext.Provider>\n          </GlobalLayoutRouterContext.Provider>\n        </SearchParamsContext.Provider>\n      </PathnameContext.Provider>\n    </PathParamsContext.Provider>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/routing/decorator.tsx",
    "content": "import * as React from 'react';\n\nimport type { Addon_StoryContext } from 'storybook/internal/types';\n\nimport { RedirectBoundary } from 'next/dist/client/components/redirect-boundary.js';\n\nimport { AppRouterProvider } from './app-router-provider.tsx';\nimport { PageRouterProvider } from './page-router-provider.tsx';\nimport type { NextAppDirectory, RouteParams } from './types.tsx';\n\nconst defaultRouterParams: RouteParams = {\n  pathname: '/',\n  query: {},\n};\n\nexport const RouterDecorator = (\n  Story: React.FC,\n  { parameters }: Addon_StoryContext\n): React.ReactNode => {\n  const nextAppDirectory =\n    (parameters.nextjs?.appDirectory as NextAppDirectory | undefined) ?? false;\n\n  if (nextAppDirectory) {\n    if (!AppRouterProvider) {\n      return null;\n    }\n    return (\n      <AppRouterProvider\n        routeParams={{\n          ...defaultRouterParams,\n          ...parameters.nextjs?.navigation,\n        }}\n      >\n        {/*\n        The next.js RedirectBoundary causes flashing UI when used client side.\n        Possible use the implementation of the PR: https://github.com/vercel/next.js/pull/49439\n        Or wait for next to solve this on their side.\n        */}\n        <RedirectBoundary>\n          <Story />\n        </RedirectBoundary>\n      </AppRouterProvider>\n    );\n  }\n\n  return (\n    <PageRouterProvider>\n      <Story />\n    </PageRouterProvider>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/routing/page-router-provider.tsx",
    "content": "// We need this import to be a singleton, and because it's used in multiple entrypoints\n// both in ESM and CJS, importing it via the package name instead of having a local import\n// is the only way to achieve it actually being a singleton\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore we must ignore types here as during compilation they are not generated yet\nimport type { PropsWithChildren } from 'react';\nimport React from 'react';\n\nimport { getRouter } from '@storybook/nextjs/router.mock';\n\nimport { RouterContext } from 'next/dist/shared/lib/router-context.shared-runtime.js';\n\nexport const PageRouterProvider: React.FC<PropsWithChildren> = ({ children }) => (\n  <RouterContext.Provider value={getRouter()}>{children}</RouterContext.Provider>\n);\n"
  },
  {
    "path": "code/frameworks/nextjs/src/routing/types.tsx",
    "content": "export type RouteParams = {\n  pathname: string;\n  query: Record<string, string>;\n  [key: string]: any;\n};\n\nexport type NextAppDirectory = boolean;\n"
  },
  {
    "path": "code/frameworks/nextjs/src/rsc/server-only.ts",
    "content": "// dummy export to make this a module\nexport default {};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/rsc/webpack.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport type { Configuration as WebpackConfig } from 'webpack';\n\nexport const configureRSC = (baseConfig: WebpackConfig): void => {\n  const resolve = baseConfig.resolve ?? {};\n  resolve.alias = {\n    ...resolve.alias,\n    'server-only$': fileURLToPath(import.meta.resolve('@storybook/nextjs/rsc/server-only')),\n  };\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/styledJsx/decorator.tsx",
    "content": "import * as React from 'react';\n\nimport { StyleRegistry } from 'styled-jsx';\n\nexport const StyledJsxDecorator = (Story: React.FC): React.ReactNode => (\n  <StyleRegistry>\n    <Story />\n  </StyleRegistry>\n);\n"
  },
  {
    "path": "code/frameworks/nextjs/src/styledJsx/webpack.ts",
    "content": "import type { Configuration as WebpackConfig } from 'webpack';\n\nimport { addScopedAlias } from '../utils.ts';\n\nexport const configureStyledJsx = (baseConfig: WebpackConfig): void => {\n  addScopedAlias(baseConfig, 'styled-jsx');\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/src/swc/loader.ts",
    "content": "import { join } from 'node:path';\n\nimport { getProjectRoot } from 'storybook/internal/common';\nimport type { Options } from 'storybook/internal/types';\n\nimport { getVirtualModules } from '@storybook/builder-webpack5';\n\nimport type { NextConfig } from 'next';\nimport nextJSLoadConfigModule from 'next/dist/build/load-jsconfig.js';\nimport type { Configuration as WebpackConfig } from 'webpack';\n\nimport { getNodeModulesExcludeRegex } from '../utils.ts';\n\nexport const configureSWCLoader = async (\n  baseConfig: WebpackConfig,\n  options: Options,\n  nextConfig: NextConfig\n) => {\n  const isDevelopment = options.configType !== 'PRODUCTION';\n\n  const { virtualModules } = await getVirtualModules(options);\n  const projectRoot = getProjectRoot();\n  const loadJsConfig = (nextJSLoadConfigModule as any).default ?? nextJSLoadConfigModule;\n\n  const { jsConfig } = await loadJsConfig(projectRoot, nextConfig as any);\n\n  const rawRule = baseConfig.module?.rules?.find(\n    (rule) => typeof rule === 'object' && rule?.resourceQuery?.toString() === '/raw/'\n  );\n\n  if (rawRule && typeof rawRule === 'object') {\n    rawRule.exclude = /^__barrel_optimize__/;\n  }\n\n  const transpilePackages = nextConfig.transpilePackages ?? [];\n\n  baseConfig.module?.rules?.push({\n    test: /\\.((c|m)?(j|t)sx?)$/,\n    include: [projectRoot],\n    exclude: [getNodeModulesExcludeRegex(transpilePackages), ...Object.keys(virtualModules)],\n    use: {\n      // we use our own patch because we need to remove tracing from the original code\n      // which is not possible otherwise\n      loader: '@storybook/nextjs/next-swc-loader-patch',\n      options: {\n        isServer: false,\n        rootDir: projectRoot,\n        pagesDir: `${projectRoot}/pages`,\n        appDir: `${projectRoot}/apps`,\n        hasReactRefresh: isDevelopment,\n        jsConfig,\n        nextConfig,\n        supportedBrowsers: await getSupportedBrowsers(projectRoot, isDevelopment),\n        swcCacheDir: join(projectRoot, nextConfig?.distDir ?? '.next', 'cache', 'swc'),\n        bundleTarget: 'default',\n      },\n    },\n  });\n};\n\nasync function getSupportedBrowsers(projectRoot: string, isDevelopment: boolean) {\n  try {\n    // @ts-expect-error - Correct import since Next.js v16.2\n    return (await import('next/dist/build/get-supported-browsers.js')).getSupportedBrowsers(\n      projectRoot,\n      isDevelopment\n    );\n  } catch (e) {\n    // TODO: Remove as soon as we don't have to support Next.js < 16.2 anymore\n    return (await import('next/dist/build/utils.js')).getSupportedBrowsers(\n      projectRoot,\n      isDevelopment\n    );\n  }\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/src/swc/next-swc-loader-patch.ts",
    "content": "// THIS IS A PATCH over the original code from Next 14.0.0\n// we use our own patch because we need to remove tracing from the original code\n// which is not possible otherwise\n/*\nCopyright (c) 2017 The swc Project Developers\nPermission is hereby granted, free of charge, to any\nperson obtaining a copy of this software and associated\ndocumentation files (the \"Software\"), to deal in the\nSoftware without restriction, including without\nlimitation the rights to use, copy, modify, merge,\npublish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software\nis furnished to do so, subject to the following\nconditions:\nThe above copyright notice and this permission notice\nshall be included in all copies or substantial portions\nof the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF\nANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED\nTO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\nPARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT\nSHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\nIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n*/\nimport { isAbsolute, relative } from 'node:path';\n\nimport type { NextConfig } from 'next';\nimport * as nextSwcUtils from 'next/dist/build/swc/index.js';\nimport { getLoaderSWCOptions } from 'next/dist/build/swc/options.js';\n\nexport interface SWCLoaderOptions {\n  rootDir: string;\n  isServer: boolean;\n  pagesDir?: string;\n  appDir?: string;\n  hasReactRefresh: boolean;\n  optimizeServerReact?: boolean;\n  nextConfig: NextConfig;\n  jsConfig: any;\n  supportedBrowsers: string[] | undefined;\n  swcCacheDir: string;\n  serverComponents?: boolean;\n  isReactServerLayer?: boolean;\n}\n\nconst mockCurrentTraceSpan = {\n  traceChild: (name: string) => mockCurrentTraceSpan,\n  traceAsyncFn: async (fn: any) => fn(),\n};\n\nasync function loaderTransform(this: any, parentTrace: any, source?: string, inputSourceMap?: any) {\n  // Make the loader async\n  const filename = this.resourcePath;\n\n  const loaderOptions: SWCLoaderOptions = this.getOptions() || {};\n\n  const {\n    isServer,\n    rootDir,\n    pagesDir,\n    appDir,\n    hasReactRefresh,\n    nextConfig,\n    jsConfig,\n    supportedBrowsers,\n    swcCacheDir,\n    serverComponents,\n    isReactServerLayer,\n  } = loaderOptions;\n  const isPageFile = filename.startsWith(pagesDir);\n  const relativeFilePathFromRoot = relative(rootDir, filename);\n\n  const swcOptions = getLoaderSWCOptions({\n    pagesDir,\n    appDir,\n    filename,\n    isServer,\n    isPageFile,\n    development: this.mode === 'development',\n    hasReactRefresh,\n    modularizeImports: nextConfig?.modularizeImports,\n    optimizePackageImports: nextConfig?.experimental?.optimizePackageImports,\n    swcPlugins: nextConfig?.experimental?.swcPlugins,\n    compilerOptions: nextConfig?.compiler,\n    optimizeServerReact: nextConfig?.experimental?.optimizeServerReact,\n    jsConfig,\n    supportedBrowsers,\n    swcCacheDir,\n    relativeFilePathFromRoot,\n    serverComponents,\n    // @ts-expect-error Relevant for Next.js < 14.1\n    // TODO: Remove this when Next.js < 14.1 is no longer supported\n    isReactServerLayer,\n  });\n\n  const programmaticOptions = {\n    ...swcOptions,\n    filename,\n    inputSourceMap:\n      inputSourceMap && typeof inputSourceMap === 'object'\n        ? JSON.stringify(inputSourceMap)\n        : undefined,\n\n    // Set the default sourcemap behavior based on Webpack's mapping flag,\n    sourceMaps: this.sourceMap,\n    inlineSourcesContent: this.sourceMap,\n\n    // Ensure that Webpack will get a full absolute path in the sourcemap\n    // so that it can properly map the module back to its internal cached\n    // modules.\n    sourceFileName: filename,\n  };\n  // Transpiles the broken syntax to the closest non-broken modern syntax.\n  // E.g. it won't transpile parameter destructuring in Safari\n  // which would break how we detect if the mount context property is used in the play function.\n  programmaticOptions.env.bugfixes = true;\n\n  if (!programmaticOptions.inputSourceMap) {\n    delete programmaticOptions.inputSourceMap;\n  }\n\n  // auto detect development mode\n  if (\n    this.mode &&\n    programmaticOptions.jsc &&\n    programmaticOptions.jsc.transform &&\n    programmaticOptions.jsc.transform.react &&\n    !Object.prototype.hasOwnProperty.call(programmaticOptions.jsc.transform.react, 'development')\n  ) {\n    programmaticOptions.jsc.transform.react.development = this.mode === 'development';\n  }\n\n  const swcSpan = parentTrace.traceChild('next-swc-transform');\n  return swcSpan.traceAsyncFn(() =>\n    nextSwcUtils.transform(source as any, programmaticOptions).then((output) => {\n      if (output.eliminatedPackages && this.eliminatedPackages) {\n        for (const pkg of JSON.parse(output.eliminatedPackages)) {\n          this.eliminatedPackages.add(pkg);\n        }\n      }\n      return [output.code, output.map ? JSON.parse(output.map) : undefined];\n    })\n  );\n}\n\nconst EXCLUDED_PATHS = /[\\\\/](cache[\\\\/][^\\\\/]+\\.zip[\\\\/]node_modules|__virtual__)[\\\\/]/g;\n\nexport function pitch(this: any) {\n  const callback = this.async();\n  (async () => {\n    let isWasm: boolean = false;\n\n    if (!!nextSwcUtils.isWasm) {\n      isWasm = await nextSwcUtils.isWasm();\n      // @ts-expect-error Relevant from Next.js >= 16.0.2-canary.12\n    } else if (!!nextSwcUtils.getBindingsSync) {\n      await nextSwcUtils.loadBindings();\n      // @ts-expect-error Relevant from Next.js >= 16.0.2-canary.12\n      isWasm = nextSwcUtils.getBindingsSync().isWasm;\n    }\n\n    if (\n      // TODO: Evaluate if this is correct after removing pnp compatibility code in SB11\n      // TODO: investigate swc file reading in PnP mode?\n      !process.versions.pnp &&\n      !EXCLUDED_PATHS.test(this.resourcePath) &&\n      this.loaders.length - 1 === this.loaderIndex &&\n      isAbsolute(this.resourcePath) &&\n      !isWasm\n    ) {\n      const loaderSpan = mockCurrentTraceSpan.traceChild('next-swc-loader');\n      this.addDependency(this.resourcePath);\n      return loaderSpan.traceAsyncFn(() => loaderTransform.call(this, loaderSpan));\n    }\n\n    return null;\n  })().then((r) => {\n    if (r) {\n      return callback(null, ...r);\n    }\n    callback();\n    return null;\n  }, callback);\n}\n\nexport default function swcLoader(this: any, inputSource: string, inputSourceMap: any) {\n  const loaderSpan = mockCurrentTraceSpan.traceChild('next-swc-loader');\n  const callback = this.async();\n  loaderSpan\n    .traceAsyncFn(() => loaderTransform.call(this, loaderSpan, inputSource, inputSourceMap))\n    .then(\n      ([transformedSource, outputSourceMap]: any) => {\n        callback(null, transformedSource, outputSourceMap || inputSourceMap);\n      },\n      (err: Error) => {\n        callback(err);\n      }\n    );\n}\n\n// accept Buffers instead of strings\nexport const raw = true;\n"
  },
  {
    "path": "code/frameworks/nextjs/src/types.ts",
    "content": "import type { CompatibleString } from 'storybook/internal/types';\n\nimport type {\n  BuilderOptions,\n  StorybookConfigWebpack,\n  TypescriptOptions as TypescriptOptionsBuilder,\n} from '@storybook/builder-webpack5';\nimport type {\n  ReactOptions,\n  StorybookConfig as StorybookConfigBase,\n  TypescriptOptions as TypescriptOptionsReact,\n} from '@storybook/preset-react-webpack';\n\nimport type * as NextImage from 'next/image';\nimport type { NextRouter } from 'next/router';\n\ntype FrameworkName = CompatibleString<'@storybook/nextjs'>;\ntype BuilderName = CompatibleString<'@storybook/builder-webpack5'>;\n\nexport type FrameworkOptions = ReactOptions & {\n  nextConfigPath?: string;\n  builder?: BuilderOptions;\n};\n\ntype StorybookConfigFramework = {\n  framework:\n    | FrameworkName\n    | {\n        name: FrameworkName;\n        options: FrameworkOptions;\n      };\n  core?: StorybookConfigBase['core'] & {\n    builder?:\n      | BuilderName\n      | {\n          name: BuilderName;\n          options: BuilderOptions;\n        };\n  };\n  typescript?: Partial<TypescriptOptionsBuilder & TypescriptOptionsReact> &\n    StorybookConfigBase['typescript'];\n};\n\n/** The interface for Storybook configuration in `main.ts` files. */\nexport type StorybookConfig = Omit<\n  StorybookConfigBase,\n  keyof StorybookConfigWebpack | keyof StorybookConfigFramework\n> &\n  StorybookConfigWebpack &\n  StorybookConfigFramework;\n\nexport interface NextJsParameters {\n  /**\n   * Next.js framework configuration\n   *\n   * @see https://storybook.js.org/docs/get-started/frameworks/nextjs\n   */\n  nextjs?: {\n    /**\n     * Enable App Directory features If your story imports components that use next/navigation, you\n     * need to set this parameter to true\n     */\n    appDirectory?: boolean;\n\n    /**\n     * Next.js navigation configuration when using `next/navigation`. Please note that it can only\n     * be used in components/pages in the app directory.\n     */\n    navigation?: Partial<NextRouter>;\n\n    /** Next.js router configuration */\n    router?: Partial<NextRouter>;\n\n    /** Next.js image props */\n    image?: Partial<NextImage.ImageProps>;\n  };\n}\n\nexport interface NextJsTypes {\n  parameters: NextJsParameters;\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/src/utils.ts",
    "content": "import { readFileSync } from 'node:fs';\nimport { dirname, join, sep } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { getProjectRoot } from 'storybook/internal/common';\n\nimport { WebpackDefinePlugin } from '@storybook/builder-webpack5';\n\nimport type { NextConfig } from 'next';\nimport { PHASE_DEVELOPMENT_SERVER } from 'next/constants.js';\nimport nextJsLoadConfigModule from 'next/dist/server/config.js';\nimport semver from 'semver';\nimport type { Configuration as WebpackConfig } from 'webpack';\n\nimport { resolvePackageDir } from '../../../core/src/shared/utils/module.ts';\n\nexport const configureRuntimeNextjsVersionResolution = (baseConfig: WebpackConfig): void => {\n  baseConfig.plugins?.push(\n    new WebpackDefinePlugin({\n      'process.env.__NEXT_VERSION': JSON.stringify(getNextjsVersion()),\n    })\n  );\n};\n\nexport const getNextjsVersion = (): string =>\n  JSON.parse(readFileSync(join(resolvePackageDir('next'), 'package.json'), 'utf8')).version;\n\nexport const isNextVersionGte = (version: string): boolean => {\n  const currentVersion = getNextjsVersion();\n  const coercedVersion = semver.coerce(currentVersion);\n  return coercedVersion ? semver.gte(coercedVersion, version) : false;\n};\n\nexport const resolveNextConfig = async ({\n  nextConfigPath,\n}: {\n  nextConfigPath?: string;\n}): Promise<NextConfig> => {\n  const dir = nextConfigPath ? dirname(nextConfigPath) : getProjectRoot();\n  const loadConfig = (nextJsLoadConfigModule as any).default ?? nextJsLoadConfigModule;\n\n  // This hack is necessary to prevent Next.js override Node.js' module resolution\n  // Next.js attempts to set aliases for webpack imports on the module resolution level\n  // which leads to two webpack versions used at the same time. It seems that Next.js doesn't\n  // forward/alias all possible webpack imports.\n  const nextPrivateRenderWorker = process.env.__NEXT_PRIVATE_RENDER_WORKER;\n\n  process.env.__NEXT_PRIVATE_RENDER_WORKER = 'defined';\n\n  const config = loadConfig(PHASE_DEVELOPMENT_SERVER, dir, undefined);\n\n  if (typeof nextPrivateRenderWorker === 'undefined') {\n    delete process.env.__NEXT_PRIVATE_RENDER_WORKER;\n  } else {\n    process.env.__NEXT_PRIVATE_RENDER_WORKER = nextPrivateRenderWorker;\n  }\n\n  return config;\n};\n\nexport function setAlias(baseConfig: WebpackConfig, name: string, alias: string) {\n  baseConfig.resolve ??= {};\n  baseConfig.resolve.alias ??= {};\n  const aliasConfig = baseConfig.resolve.alias;\n\n  if (Array.isArray(aliasConfig)) {\n    aliasConfig.push({\n      name,\n      alias,\n    });\n  } else {\n    aliasConfig[name] = alias;\n  }\n}\n\n// This is to help the addon in development\n// Without it, webpack resolves packages in its node_modules instead of the example's node_modules\nexport const addScopedAlias = (baseConfig: WebpackConfig, name: string, alias?: string): void => {\n  const scopedAlias = scopedResolve(`${alias ?? name}`);\n\n  setAlias(baseConfig, name, scopedAlias);\n};\n\n/**\n * @example\n *\n * ```\n * // before main script path truncation\n * require.resolve('styled-jsx') === '/some/path/node_modules/styled-jsx/index.js\n * // after main script path truncation\n * scopedResolve('styled-jsx') === '/some/path/node_modules/styled-jsx'\n * ```\n *\n * @example\n *\n * ```\n * // referencing a named export of a package\n * scopedResolve('next/dist/compiled/react-dom/client') ===\n *   // returns the path to the package export without the script filename\n *   '/some/path/node_modules/next/dist/compiled/react-dom/client';\n *\n * // referencing a specific file within a CJS package\n * scopedResolve('next/dist/compiled/react-dom/cjs/react-dom-test-utils.production.js') ===\n *   // returns the path to the physical file, including the script filename\n *   '/some/path/node_modules/next/dist/compiled/react-dom/cjs/react-dom-test-utils.production.js';\n * ```\n *\n * @param id The module id or script file to resolve\n * @returns An absolute path to the specified module id or script file scoped to the project folder\n * @summary\n * This is to help the addon in development.\n * Without it, the addon resolves packages in its node_modules instead of the example's node_modules.\n * Because require.resolve will also include the main script as part of the path, this function strips\n * that to just include the path to the module folder when the id provided is a package or named export.\n */\nexport const scopedResolve = (id: string): string => {\n  const scopedModulePath = fileURLToPath(import.meta.resolve(id));\n  const idWithNativePathSep = id.replace(/\\//g /* all '/' occurrences */, sep);\n\n  // If the id referenced the file specifically, return the full module path & filename\n  if (scopedModulePath.endsWith(idWithNativePathSep)) {\n    return scopedModulePath;\n  }\n\n  // Otherwise, return just the path to the module folder or named export\n  const moduleFolderStrPosition = scopedModulePath.lastIndexOf(idWithNativePathSep);\n  const beginningOfMainScriptPath = moduleFolderStrPosition + id.length;\n  return scopedModulePath.substring(0, beginningOfMainScriptPath);\n};\n\n/**\n * Returns a RegExp that matches node_modules except for the given transpilePackages.\n *\n * @param transpilePackages Array of package names to NOT exclude (i.e., to include for\n *   transpilation)\n * @returns RegExp for use in Webpack's exclude\n */\nexport function getNodeModulesExcludeRegex(transpilePackages: string[]): RegExp {\n  if (!transpilePackages || transpilePackages.length === 0) {\n    return /node_modules/;\n  }\n  const escaped = transpilePackages\n    .map((pkg) => pkg.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'))\n    .join('|');\n  return new RegExp(`node_modules/(?!(${escaped})/)`);\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/template/cli/.eslintrc.json",
    "content": "{\n  \"rules\": {\n    \"import/extensions\": \"off\",\n    \"react/no-unknown-property\": \"off\"\n  }\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/template/cli/js/Button.jsx",
    "content": "import PropTypes from 'prop-types';\n\nimport './button.css';\n\n/** Primary UI component for user interaction */\nexport const Button = ({ primary, backgroundColor, size, label, ...props }) => {\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n  return (\n    <button\n      type=\"button\"\n      className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n      {...props}\n    >\n      {label}\n      <style jsx>{`\n        button {\n          background-color: ${backgroundColor};\n        }\n      `}</style>\n    </button>\n  );\n};\n\nButton.propTypes = {\n  /** Is this the principal call to action on the page? */\n  primary: PropTypes.bool,\n  /** What background color to use */\n  backgroundColor: PropTypes.string,\n  /** How large should the button be? */\n  size: PropTypes.oneOf(['small', 'medium', 'large']),\n  /** Button contents */\n  label: PropTypes.string.isRequired,\n  /** Optional click handler */\n  onClick: PropTypes.func,\n};\n\nButton.defaultProps = {\n  backgroundColor: null,\n  primary: false,\n  size: 'medium',\n  onClick: undefined,\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/cli/js/Button.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport { Button } from './Button';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export\nexport default {\n  title: 'Example/Button',\n  component: Button,\n  parameters: {\n    // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout\n    layout: 'centered',\n  },\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  // More on argTypes: https://storybook.js.org/docs/api/argtypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onClick: fn() },\n};\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/cli/js/Configure.mdx",
    "content": "import { Meta } from \"@storybook/addon-docs/blocks\";\nimport Image from \"next/image\";\n\nimport Github from \"./assets/github.svg\";\nimport Discord from \"./assets/discord.svg\";\nimport Youtube from \"./assets/youtube.svg\";\nimport Tutorials from \"./assets/tutorials.svg\";\nimport Styling from \"./assets/styling.png\";\nimport Context from \"./assets/context.png\";\nimport Assets from \"./assets/assets.png\";\nimport Docs from \"./assets/docs.png\";\nimport Share from \"./assets/share.png\";\nimport FigmaPlugin from \"./assets/figma-plugin.png\";\nimport Testing from \"./assets/testing.png\";\nimport Accessibility from \"./assets/accessibility.png\";\nimport Theming from \"./assets/theming.png\";\nimport AddonLibrary from \"./assets/addon-library.png\";\n\nexport const RightArrow = () => <svg \n    viewBox=\"0 0 14 14\" \n    width=\"8px\" \n    height=\"14px\" \n    style={{ \n      marginLeft: '4px',\n      display: 'inline-block',\n      shapeRendering: 'inherit',\n      verticalAlign: 'middle',\n      fill: 'currentColor',\n      'path fill': 'currentColor'\n    }}\n>\n  <path d=\"m11.1 7.35-5.5 5.5a.5.5 0 0 1-.7-.7L10.04 7 4.9 1.85a.5.5 0 1 1 .7-.7l5.5 5.5c.2.2.2.5 0 .7Z\" />\n</svg>\n\n<Meta title=\"Configure your project\" />\n\n<div className=\"sb-container\">\n  <div className='sb-section-title'>\n    # Configure your project\n\n    Because Storybook works separately from your app, you'll need to configure it for your specific stack and setup. Below, explore guides for configuring Storybook with popular frameworks and tools. If you get stuck, learn how you can ask for help from our community.\n  </div>\n  <div className=\"sb-section\">\n    <div className=\"sb-section-item\">\n      <Image\n        src={Styling}\n        alt=\"A wall of logos representing different styling technologies\"\n        width={0}\n        height={0}\n        style={{ width: '100%', height: 'auto' }}\n      />\n      <h4 className=\"sb-section-item-heading\">Add styling and CSS</h4>\n      <p className=\"sb-section-item-paragraph\">Like with web applications, there are many ways to include CSS within Storybook. Learn more about setting up styling within Storybook.</p>\n      <a\n        className=\"sb-action-link\"\n        href=\"https://storybook.js.org/docs/configure/styling-and-css/?renderer=react&ref=configure\"\n        target=\"_blank\"\n      >Learn more<RightArrow /></a>\n    </div>\n    <div className=\"sb-section-item\">\n      <Image \n        width={0}\n        height={0}\n        style={{ width: '100%', height: 'auto' }}\n        src={Context}\n        alt=\"An abstraction representing the composition of data for a component\"\n      />\n      <h4 className=\"sb-section-item-heading\">Provide context and mocking</h4>\n      <p className=\"sb-section-item-paragraph\">Often when a story doesn't render, it's because your component is expecting a specific environment or context (like a theme provider) to be available.</p>\n      <a\n        className=\"sb-action-link\"\n        href=\"https://storybook.js.org/docs/writing-stories/decorators/?renderer=react&ref=configure#context-for-mocking\"\n        target=\"_blank\"\n      >Learn more<RightArrow /></a>\n    </div>\n    <div className=\"sb-section-item\">\n      <Image \n        width={0}\n        height={0}\n        style={{ width: '100%', height: 'auto' }} \n        src={Assets} \n        alt=\"A representation of typography and image assets\" \n      />\n      <div>\n        <h4 className=\"sb-section-item-heading\">Load assets and resources</h4>\n        <p className=\"sb-section-item-paragraph\">To link static files (like fonts) to your projects and stories, use the\n        `staticDirs` configuration option to specify folders to load when\n        starting Storybook.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/configure/images-and-assets/?renderer=react&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n    </div>\n  </div>\n</div>\n<div className=\"sb-container\">\n  <div className='sb-section-title'>\n    # Do more with Storybook\n\n    Now that you know the basics, let's explore other parts of Storybook that will improve your experience. This list is just to get you started. You can customise Storybook in many ways to fit your needs.\n  </div>\n\n  <div className=\"sb-section\">\n    <div className=\"sb-features-grid\">\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={Docs} \n          alt=\"A screenshot showing the autodocs tag being set, pointing a docs page being generated\" \n        />\n        <h4 className=\"sb-section-item-heading\">Autodocs</h4>\n        <p className=\"sb-section-item-paragraph\">Auto-generate living,\n          interactive reference documentation from your components and stories.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/writing-docs/autodocs/?renderer=react&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={Share} \n          alt=\"A browser window showing a Storybook being published to a chromatic.com URL\" \n        />\n        <h4 className=\"sb-section-item-heading\">Publish to Chromatic</h4>\n        <p className=\"sb-section-item-paragraph\">Publish your Storybook to review and collaborate with your entire team.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/sharing/publish-storybook/?renderer=react&ref=configure#publish-storybook-with-chromatic\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={FigmaPlugin} \n          alt=\"Windows showing the Storybook plugin in Figma\" \n        />\n        <h4 className=\"sb-section-item-heading\">Figma Plugin</h4>\n        <p className=\"sb-section-item-paragraph\">Embed your stories into Figma to cross-reference the design and live\n          implementation in one place.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/sharing/design-integrations/?renderer=react&ref=configure#embed-storybook-in-figma-with-the-plugin\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={Testing} \n          alt=\"Screenshot of tests passing and failing\" \n        />\n        <h4 className=\"sb-section-item-heading\">Testing</h4>\n        <p className=\"sb-section-item-paragraph\">Use stories to test a component in all its variations, no matter how\n          complex.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/writing-tests/?renderer=react&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={Accessibility} \n          alt=\"Screenshot of accessibility tests passing and failing\" \n        />\n        <h4 className=\"sb-section-item-heading\">Accessibility</h4>\n        <p className=\"sb-section-item-paragraph\">Automatically test your components for a11y issues as you develop.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/writing-tests/accessibility-testing/?renderer=react&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={Theming} \n          alt=\"Screenshot of Storybook in light and dark mode\" \n        />\n        <h4 className=\"sb-section-item-heading\">Theming</h4>\n        <p className=\"sb-section-item-paragraph\">Theme Storybook's UI to personalize it to your project.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/configure/theming/?renderer=react&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n    </div>\n  </div>\n</div>\n<div className='sb-addon'>\n  <div className='sb-addon-text'>\n    <h4>Addons</h4>\n    <p className=\"sb-section-item-paragraph\">Integrate your tools with Storybook to connect workflows.</p>\n    <a\n        className=\"sb-action-link\"\n        href=\"https://storybook.js.org/addons/?ref=configure\"\n        target=\"_blank\"\n      >Discover all addons<RightArrow /></a>\n  </div>\n  <div className='sb-addon-img'>\n    <Image \n      width={650}\n      height={347}\n      src={AddonLibrary} \n      alt=\"Integrate your tools with Storybook to connect workflows.\" \n    />\n  </div>\n</div>\n\n<div className=\"sb-section sb-socials\">\n    <div className=\"sb-section-item\">\n      <Image \n        width={32}\n        height={32}\n        layout=\"fixed\"\n        src={Github} \n        alt=\"Github logo\" \n        className=\"sb-explore-image\"\n      />\n      Join our contributors building the future of UI development.\n\n      <a\n        className=\"sb-action-link\"\n        href=\"https://github.com/storybookjs/storybook\"\n        target=\"_blank\"\n      >Star on GitHub<RightArrow /></a>\n    </div>\n    <div className=\"sb-section-item\">\n      <Image \n        width={33}\n        height={32}\n        layout=\"fixed\"\n        src={Discord} \n        alt=\"Discord logo\" \n        className=\"sb-explore-image\"\n      />\n      <div>\n        Get support and chat with frontend developers.\n\n        <a\n          className=\"sb-action-link\"\n          href=\"https://discord.gg/storybook\"\n          target=\"_blank\"\n        >Join Discord server<RightArrow /></a>\n      </div>\n    </div>\n    <div className=\"sb-section-item\">\n      <Image \n        width={32}\n        height={32}\n        layout=\"fixed\"\n        src={Youtube} \n        alt=\"Youtube logo\" \n        className=\"sb-explore-image\"\n      />\n      <div>\n        Watch tutorials, feature previews and interviews.\n\n        <a\n          className=\"sb-action-link\"\n          href=\"https://www.youtube.com/@chromaticui\"\n          target=\"_blank\"\n        >Watch on YouTube<RightArrow /></a>\n      </div>\n    </div>\n    <div className=\"sb-section-item\">\n      <Image \n        width={33}\n        height={32}\n        layout=\"fixed\"\n        src={Tutorials} \n        alt=\"A book\" \n        className=\"sb-explore-image\"\n      />\n      <p>Follow guided walkthroughs on for key workflows.</p>\n\n      <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/tutorials/?ref=configure\"\n          target=\"_blank\"\n        >Discover tutorials<RightArrow /></a>\n    </div>\n</div>\n\n<style>\n  {`\n  .sb-container {\n    margin-bottom: 48px;\n  }\n\n  .sb-section {\n    width: 100%;\n    display: flex;\n    flex-direction: row;\n    gap: 20px;\n  }\n\n  img {\n    object-fit: cover;\n  }\n\n  .sb-section-title {\n    margin-bottom: 32px;\n  }\n\n  .sb-section a:not(h1 a, h2 a, h3 a) {\n    font-size: 14px;\n  }\n\n  .sb-section-item, .sb-grid-item {\n    flex: 1;\n    display: flex;\n    flex-direction: column;\n  }\n\n  .sb-section-item-heading {\n    padding-top: 20px !important;\n    padding-bottom: 5px !important;\n    margin: 0 !important;\n  }\n  .sb-section-item-paragraph {\n    margin: 0;\n    padding-bottom: 10px;\n  }\n\n  .sb-action-link {\n    text-decoration: none;\n  }\n\n  .sb-action-link:hover, .sb-action-link:focus {\n    text-decoration: underline;\n    text-decoration-thickness: 0.03125rem;\n    text-underline-offset: 0.11em;\n  }\n\n  .sb-chevron {\n    margin-left: 5px;\n  }\n\n  .sb-features-grid {\n    display: grid;\n    grid-template-columns: repeat(2, 1fr);\n    grid-gap: 32px 20px;\n  }\n\n  .sb-socials {\n    display: grid;\n    grid-template-columns: repeat(4, 1fr);\n  }\n\n  .sb-socials p {\n    margin-bottom: 10px;\n  }\n\n  .sb-explore-image {\n    max-height: 32px;\n    align-self: flex-start;\n  }\n\n  .sb-addon {\n    width: 100%;\n    display: flex;\n    align-items: center;\n    position: relative;\n    background-color: #EEF3F8;\n    border-radius: 5px;\n    border: 1px solid rgba(0, 0, 0, 0.05);\n    background: #EEF3F8;\n    height: 180px;\n    margin-bottom: 48px;\n    overflow: hidden;\n  }\n\n  .sb-addon-text {\n    padding-left: 48px;\n    max-width: 240px;\n  }\n\n  .sb-addon-text h4 {\n    padding-top: 0px;\n  }\n\n  .sb-addon-img {\n    position: absolute;\n    left: 345px;\n    top: 0;\n    height: 100%;\n    width: 200%;\n    overflow: hidden;\n  }\n\n  .sb-addon-img img {\n    width: 650px;\n    transform: rotate(-15deg);\n    margin-left: 40px;\n    margin-top: -72px;\n    box-shadow: 0 0 1px rgba(255, 255, 255, 0);\n    backface-visibility: hidden;\n  }\n\n  @media screen and (max-width: 800px) {\n    .sb-addon-img {\n      left: 300px;\n    }\n  }\n\n  @media screen and (max-width: 600px) {\n    .sb-section {\n      flex-direction: column;\n    }\n\n    .sb-features-grid {\n      grid-template-columns: repeat(1, 1fr);\n    }\n\n    .sb-socials {\n      grid-template-columns: repeat(2, 1fr);\n    }\n\n    .sb-addon {\n      height: 280px;\n      align-items: flex-start;\n      padding-top: 32px;\n      overflow: hidden;\n    }\n\n    .sb-addon-text {\n      padding-left: 24px;\n    }\n\n    .sb-addon-img {\n      right: 0;\n      left: 0;\n      top: 130px;\n      bottom: 0;\n      overflow: hidden;\n      height: auto;\n      width: 124%;\n    }\n\n    .sb-addon-img img {\n      width: 1200px;\n      transform: rotate(-12deg);\n      margin-left: 0;\n      margin-top: 48px;\n      margin-bottom: -40px;\n      margin-left: -24px;\n    }\n  }\n  `}\n</style>\n"
  },
  {
    "path": "code/frameworks/nextjs/template/cli/js/Header.jsx",
    "content": "import PropTypes from 'prop-types';\n\nimport { Button } from './Button';\nimport './header.css';\n\nexport const Header = ({ user, onLogin, onLogout, onCreateAccount }) => (\n  <header>\n    <div className=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        {user ? (\n          <>\n            <span className=\"welcome\">\n              Welcome, <b>{user.name}</b>!\n            </span>\n            <Button size=\"small\" onClick={onLogout} label=\"Log out\" />\n          </>\n        ) : (\n          <>\n            <Button size=\"small\" onClick={onLogin} label=\"Log in\" />\n            <Button primary size=\"small\" onClick={onCreateAccount} label=\"Sign up\" />\n          </>\n        )}\n      </div>\n    </div>\n  </header>\n);\n\nHeader.propTypes = {\n  user: PropTypes.shape({\n    name: PropTypes.string.isRequired,\n  }),\n  onLogin: PropTypes.func.isRequired,\n  onLogout: PropTypes.func.isRequired,\n  onCreateAccount: PropTypes.func.isRequired,\n};\n\nHeader.defaultProps = {\n  user: null,\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/cli/js/Header.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport { Header } from './Header';\n\nexport default {\n  title: 'Example/Header',\n  component: Header,\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n};\nexport const LoggedIn = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut = {\n  args: {},\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/cli/js/Page.jsx",
    "content": "import React from 'react';\n\nimport { Header } from './Header';\nimport './page.css';\n\nexport const Page = () => {\n  const [user, setUser] = React.useState();\n\n  return (\n    <article>\n      <Header\n        user={user}\n        onLogin={() => setUser({ name: 'Jane Doe' })}\n        onLogout={() => setUser(undefined)}\n        onCreateAccount={() => setUser({ name: 'Jane Doe' })}\n      />\n      <section className=\"storybook-page\">\n        <h2>Pages in Storybook</h2>\n        <p>\n          We recommend building UIs with a{' '}\n          <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n            <strong>component-driven</strong>\n          </a>{' '}\n          process starting with atomic components and ending with pages.\n        </p>\n        <p>\n          Render pages with mock data. This makes it easy to build and review page states without\n          needing to navigate to them in your app. Here are some handy patterns for managing page\n          data in Storybook:\n        </p>\n        <ul>\n          <li>\n            Use a higher-level connected component. Storybook helps you compose such data from the\n            \"args\" of child component stories\n          </li>\n          <li>\n            Assemble data in the page component from your services. You can mock these services out\n            using Storybook.\n          </li>\n        </ul>\n        <p>\n          Get a guided tutorial on component-driven development at{' '}\n          <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n            Storybook tutorials\n          </a>\n          . Read more in the{' '}\n          <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">\n            docs\n          </a>\n          .\n        </p>\n        <div className=\"tip-wrapper\">\n          <span className=\"tip\">Tip</span> Adjust the width of the canvas with the{' '}\n          <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n            <g fill=\"none\" fillRule=\"evenodd\">\n              <path\n                d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n                id=\"a\"\n                fill=\"#999\"\n              />\n            </g>\n          </svg>\n          Viewports addon in the toolbar\n        </div>\n      </section>\n    </article>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/cli/js/Page.stories.js",
    "content": "import { expect, userEvent, within } from 'storybook/test';\n\nimport { Page } from './Page';\n\nexport default {\n  title: 'Example/Page',\n  component: Page,\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n};\n\nexport const LoggedOut = {};\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await expect(loginButton).not.toBeInTheDocument();\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/cli/ts/Button.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/nextjs';\n\nimport { fn } from 'storybook/test';\n\nimport { Button } from './Button';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export\nconst meta = {\n  title: 'Example/Button',\n  component: Button,\n  parameters: {\n    // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout\n    layout: 'centered',\n  },\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  // More on argTypes: https://storybook.js.org/docs/api/argtypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onClick: fn() },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large: Story = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small: Story = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/cli/ts/Button.tsx",
    "content": "import './button.css';\n\nexport interface ButtonProps {\n  /** Is this the principal call to action on the page? */\n  primary?: boolean;\n  /** What background color to use */\n  backgroundColor?: string;\n  /** How large should the button be? */\n  size?: 'small' | 'medium' | 'large';\n  /** Button contents */\n  label: string;\n  /** Optional click handler */\n  onClick?: () => void;\n}\n\n/** Primary UI component for user interaction */\nexport const Button = ({\n  primary = false,\n  size = 'medium',\n  backgroundColor,\n  label,\n  ...props\n}: ButtonProps) => {\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n  return (\n    <button\n      type=\"button\"\n      className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n      {...props}\n    >\n      {label}\n      <style jsx>{`\n        button {\n          background-color: ${backgroundColor};\n        }\n      `}</style>\n    </button>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/cli/ts/Configure.mdx",
    "content": "import { Meta } from \"@storybook/addon-docs/blocks\";\nimport Image from \"next/image\";\n\nimport Github from \"./assets/github.svg\";\nimport Discord from \"./assets/discord.svg\";\nimport Youtube from \"./assets/youtube.svg\";\nimport Tutorials from \"./assets/tutorials.svg\";\nimport Styling from \"./assets/styling.png\";\nimport Context from \"./assets/context.png\";\nimport Assets from \"./assets/assets.png\";\nimport Docs from \"./assets/docs.png\";\nimport Share from \"./assets/share.png\";\nimport FigmaPlugin from \"./assets/figma-plugin.png\";\nimport Testing from \"./assets/testing.png\";\nimport Accessibility from \"./assets/accessibility.png\";\nimport Theming from \"./assets/theming.png\";\nimport AddonLibrary from \"./assets/addon-library.png\";\n\nexport const RightArrow = () => <svg \n    viewBox=\"0 0 14 14\" \n    width=\"8px\" \n    height=\"14px\" \n    style={{ \n      marginLeft: '4px',\n      display: 'inline-block',\n      shapeRendering: 'inherit',\n      verticalAlign: 'middle',\n      fill: 'currentColor',\n      'path fill': 'currentColor'\n    }}\n>\n  <path d=\"m11.1 7.35-5.5 5.5a.5.5 0 0 1-.7-.7L10.04 7 4.9 1.85a.5.5 0 1 1 .7-.7l5.5 5.5c.2.2.2.5 0 .7Z\" />\n</svg>\n\n<Meta title=\"Configure your project\" />\n\n<div className=\"sb-container\">\n  <div className='sb-section-title'>\n    # Configure your project\n\n    Because Storybook works separately from your app, you'll need to configure it for your specific stack and setup. Below, explore guides for configuring Storybook with popular frameworks and tools. If you get stuck, learn how you can ask for help from our community.\n  </div>\n  <div className=\"sb-section\">\n    <div className=\"sb-section-item\">\n      <Image\n        src={Styling}\n        alt=\"A wall of logos representing different styling technologies\"\n        width={0}\n        height={0}\n        style={{ width: '100%', height: 'auto' }}\n      />\n      <h4 className=\"sb-section-item-heading\">Add styling and CSS</h4>\n      <p className=\"sb-section-item-paragraph\">Like with web applications, there are many ways to include CSS within Storybook. Learn more about setting up styling within Storybook.</p>\n      <a\n        className=\"sb-action-link\"\n        href=\"https://storybook.js.org/docs/configure/styling-and-css/?renderer=react&ref=configure\"\n        target=\"_blank\"\n      >Learn more<RightArrow /></a>\n    </div>\n    <div className=\"sb-section-item\">\n      <Image \n        width={0}\n        height={0}\n        style={{ width: '100%', height: 'auto' }}\n        src={Context}\n        alt=\"An abstraction representing the composition of data for a component\"\n      />\n      <h4 className=\"sb-section-item-heading\">Provide context and mocking</h4>\n      <p className=\"sb-section-item-paragraph\">Often when a story doesn't render, it's because your component is expecting a specific environment or context (like a theme provider) to be available.</p>\n      <a\n        className=\"sb-action-link\"\n        href=\"https://storybook.js.org/docs/writing-stories/decorators/?renderer=react&ref=configure#context-for-mocking\"\n        target=\"_blank\"\n      >Learn more<RightArrow /></a>\n    </div>\n    <div className=\"sb-section-item\">\n      <Image \n        width={0}\n        height={0}\n        style={{ width: '100%', height: 'auto' }} \n        src={Assets} \n        alt=\"A representation of typography and image assets\" \n      />\n      <div>\n        <h4 className=\"sb-section-item-heading\">Load assets and resources</h4>\n        <p className=\"sb-section-item-paragraph\">To link static files (like fonts) to your projects and stories, use the\n        `staticDirs` configuration option to specify folders to load when\n        starting Storybook.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/configure/images-and-assets/?renderer=react&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n    </div>\n  </div>\n</div>\n<div className=\"sb-container\">\n  <div className='sb-section-title'>\n    # Do more with Storybook\n\n    Now that you know the basics, let's explore other parts of Storybook that will improve your experience. This list is just to get you started. You can customise Storybook in many ways to fit your needs.\n  </div>\n\n  <div className=\"sb-section\">\n    <div className=\"sb-features-grid\">\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={Docs} \n          alt=\"A screenshot showing the autodocs tag being set, pointing a docs page being generated\" \n        />\n        <h4 className=\"sb-section-item-heading\">Autodocs</h4>\n        <p className=\"sb-section-item-paragraph\">Auto-generate living,\n          interactive reference documentation from your components and stories.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/writing-docs/autodocs/?renderer=react&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={Share} \n          alt=\"A browser window showing a Storybook being published to a chromatic.com URL\" \n        />\n        <h4 className=\"sb-section-item-heading\">Publish to Chromatic</h4>\n        <p className=\"sb-section-item-paragraph\">Publish your Storybook to review and collaborate with your entire team.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/sharing/publish-storybook/?renderer=react&ref=configure#publish-storybook-with-chromatic\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={FigmaPlugin} \n          alt=\"Windows showing the Storybook plugin in Figma\" \n        />\n        <h4 className=\"sb-section-item-heading\">Figma Plugin</h4>\n        <p className=\"sb-section-item-paragraph\">Embed your stories into Figma to cross-reference the design and live\n          implementation in one place.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/sharing/design-integrations/?renderer=react&ref=configure#embed-storybook-in-figma-with-the-plugin\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={Testing} \n          alt=\"Screenshot of tests passing and failing\" \n        />\n        <h4 className=\"sb-section-item-heading\">Testing</h4>\n        <p className=\"sb-section-item-paragraph\">Use stories to test a component in all its variations, no matter how\n          complex.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/writing-tests/?renderer=react&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={Accessibility} \n          alt=\"Screenshot of accessibility tests passing and failing\" \n        />\n        <h4 className=\"sb-section-item-heading\">Accessibility</h4>\n        <p className=\"sb-section-item-paragraph\">Automatically test your components for a11y issues as you develop.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/writing-tests/accessibility-testing/?renderer=react&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={Theming} \n          alt=\"Screenshot of Storybook in light and dark mode\" \n        />\n        <h4 className=\"sb-section-item-heading\">Theming</h4>\n        <p className=\"sb-section-item-paragraph\">Theme Storybook's UI to personalize it to your project.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/configure/theming/?renderer=react&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n    </div>\n  </div>\n</div>\n<div className='sb-addon'>\n  <div className='sb-addon-text'>\n    <h4>Addons</h4>\n    <p className=\"sb-section-item-paragraph\">Integrate your tools with Storybook to connect workflows.</p>\n    <a\n        className=\"sb-action-link\"\n        href=\"https://storybook.js.org/addons/?ref=configure\"\n        target=\"_blank\"\n      >Discover all addons<RightArrow /></a>\n  </div>\n  <div className='sb-addon-img'>\n    <Image \n      width={650}\n      height={347}\n      src={AddonLibrary} \n      alt=\"Integrate your tools with Storybook to connect workflows.\" \n    />\n  </div>\n</div>\n\n<div className=\"sb-section sb-socials\">\n    <div className=\"sb-section-item\">\n      <Image \n        width={32}\n        height={32}\n        layout=\"fixed\"\n        src={Github} \n        alt=\"Github logo\" \n        className=\"sb-explore-image\"\n      />\n      Join our contributors building the future of UI development.\n\n      <a\n        className=\"sb-action-link\"\n        href=\"https://github.com/storybookjs/storybook\"\n        target=\"_blank\"\n      >Star on GitHub<RightArrow /></a>\n    </div>\n    <div className=\"sb-section-item\">\n      <Image \n        width={33}\n        height={32}\n        layout=\"fixed\"\n        src={Discord} \n        alt=\"Discord logo\" \n        className=\"sb-explore-image\"\n      />\n      <div>\n        Get support and chat with frontend developers.\n\n        <a\n          className=\"sb-action-link\"\n          href=\"https://discord.gg/storybook\"\n          target=\"_blank\"\n        >Join Discord server<RightArrow /></a>\n      </div>\n    </div>\n    <div className=\"sb-section-item\">\n      <Image \n        width={32}\n        height={32}\n        layout=\"fixed\"\n        src={Youtube} \n        alt=\"Youtube logo\" \n        className=\"sb-explore-image\"\n      />\n      <div>\n        Watch tutorials, feature previews and interviews.\n\n        <a\n          className=\"sb-action-link\"\n          href=\"https://www.youtube.com/@chromaticui\"\n          target=\"_blank\"\n        >Watch on YouTube<RightArrow /></a>\n      </div>\n    </div>\n    <div className=\"sb-section-item\">\n      <Image \n        width={33}\n        height={32}\n        layout=\"fixed\"\n        src={Tutorials} \n        alt=\"A book\" \n        className=\"sb-explore-image\"\n      />\n      <p>Follow guided walkthroughs on for key workflows.</p>\n\n      <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/tutorials/?ref=configure\"\n          target=\"_blank\"\n        >Discover tutorials<RightArrow /></a>\n    </div>\n</div>\n\n<style>\n  {`\n  .sb-container {\n    margin-bottom: 48px;\n  }\n\n  .sb-section {\n    width: 100%;\n    display: flex;\n    flex-direction: row;\n    gap: 20px;\n  }\n\n  img {\n    object-fit: cover;\n  }\n\n  .sb-section-title {\n    margin-bottom: 32px;\n  }\n\n  .sb-section a:not(h1 a, h2 a, h3 a) {\n    font-size: 14px;\n  }\n\n  .sb-section-item, .sb-grid-item {\n    flex: 1;\n    display: flex;\n    flex-direction: column;\n  }\n\n  .sb-section-item-heading {\n    padding-top: 20px !important;\n    padding-bottom: 5px !important;\n    margin: 0 !important;\n  }\n  .sb-section-item-paragraph {\n    margin: 0;\n    padding-bottom: 10px;\n  }\n\n  .sb-action-link {\n    text-decoration: none;\n  }\n\n  .sb-action-link:hover, .sb-action-link:focus {\n    text-decoration: underline;\n    text-decoration-thickness: 0.03125rem;\n    text-underline-offset: 0.11em;\n  }\n\n  .sb-chevron {\n    margin-left: 5px;\n  }\n\n  .sb-features-grid {\n    display: grid;\n    grid-template-columns: repeat(2, 1fr);\n    grid-gap: 32px 20px;\n  }\n\n  .sb-socials {\n    display: grid;\n    grid-template-columns: repeat(4, 1fr);\n  }\n\n  .sb-socials p {\n    margin-bottom: 10px;\n  }\n\n  .sb-explore-image {\n    max-height: 32px;\n    align-self: flex-start;\n  }\n\n  .sb-addon {\n    width: 100%;\n    display: flex;\n    align-items: center;\n    position: relative;\n    background-color: #EEF3F8;\n    border-radius: 5px;\n    border: 1px solid rgba(0, 0, 0, 0.05);\n    background: #EEF3F8;\n    height: 180px;\n    margin-bottom: 48px;\n    overflow: hidden;\n  }\n\n  .sb-addon-text {\n    padding-left: 48px;\n    max-width: 240px;\n  }\n\n  .sb-addon-text h4 {\n    padding-top: 0px;\n  }\n\n  .sb-addon-img {\n    position: absolute;\n    left: 345px;\n    top: 0;\n    height: 100%;\n    width: 200%;\n    overflow: hidden;\n  }\n\n  .sb-addon-img img {\n    width: 650px;\n    transform: rotate(-15deg);\n    margin-left: 40px;\n    margin-top: -72px;\n    box-shadow: 0 0 1px rgba(255, 255, 255, 0);\n    backface-visibility: hidden;\n  }\n\n  @media screen and (max-width: 800px) {\n    .sb-addon-img {\n      left: 300px;\n    }\n  }\n\n  @media screen and (max-width: 600px) {\n    .sb-section {\n      flex-direction: column;\n    }\n\n    .sb-features-grid {\n      grid-template-columns: repeat(1, 1fr);\n    }\n\n    .sb-socials {\n      grid-template-columns: repeat(2, 1fr);\n    }\n\n    .sb-addon {\n      height: 280px;\n      align-items: flex-start;\n      padding-top: 32px;\n      overflow: hidden;\n    }\n\n    .sb-addon-text {\n      padding-left: 24px;\n    }\n\n    .sb-addon-img {\n      right: 0;\n      left: 0;\n      top: 130px;\n      bottom: 0;\n      overflow: hidden;\n      height: auto;\n      width: 124%;\n    }\n\n    .sb-addon-img img {\n      width: 1200px;\n      transform: rotate(-12deg);\n      margin-left: 0;\n      margin-top: 48px;\n      margin-bottom: -40px;\n      margin-left: -24px;\n    }\n  }\n  `}\n</style>\n"
  },
  {
    "path": "code/frameworks/nextjs/template/cli/ts/Header.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/nextjs';\n\nimport { fn } from 'storybook/test';\n\nimport { Header } from './Header';\n\nconst meta = {\n  title: 'Example/Header',\n  component: Header,\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n} satisfies Meta<typeof Header>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const LoggedIn: Story = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut: Story = {};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/cli/ts/Header.tsx",
    "content": "import { Button } from './Button';\nimport './header.css';\n\ntype User = {\n  name: string;\n};\n\nexport interface HeaderProps {\n  user?: User;\n  onLogin?: () => void;\n  onLogout?: () => void;\n  onCreateAccount?: () => void;\n}\n\nexport const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => (\n  <header>\n    <div className=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        {user ? (\n          <>\n            <span className=\"welcome\">\n              Welcome, <b>{user.name}</b>!\n            </span>\n            <Button size=\"small\" onClick={onLogout} label=\"Log out\" />\n          </>\n        ) : (\n          <>\n            <Button size=\"small\" onClick={onLogin} label=\"Log in\" />\n            <Button primary size=\"small\" onClick={onCreateAccount} label=\"Sign up\" />\n          </>\n        )}\n      </div>\n    </div>\n  </header>\n);\n"
  },
  {
    "path": "code/frameworks/nextjs/template/cli/ts/Page.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/nextjs';\n\nimport { expect, userEvent, within } from 'storybook/test';\n\nimport { Page } from './Page';\n\nconst meta = {\n  title: 'Example/Page',\n  component: Page,\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n} satisfies Meta<typeof Page>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const LoggedOut: Story = {};\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn: Story = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await expect(loginButton).not.toBeInTheDocument();\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/cli/ts/Page.tsx",
    "content": "import React from 'react';\n\nimport { Header } from './Header';\nimport './page.css';\n\ntype User = {\n  name: string;\n};\n\nexport const Page: React.FC = () => {\n  const [user, setUser] = React.useState<User>();\n\n  return (\n    <article>\n      <Header\n        user={user}\n        onLogin={() => setUser({ name: 'Jane Doe' })}\n        onLogout={() => setUser(undefined)}\n        onCreateAccount={() => setUser({ name: 'Jane Doe' })}\n      />\n\n      <section className=\"storybook-page\">\n        <h2>Pages in Storybook</h2>\n        <p>\n          We recommend building UIs with a{' '}\n          <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n            <strong>component-driven</strong>\n          </a>{' '}\n          process starting with atomic components and ending with pages.\n        </p>\n        <p>\n          Render pages with mock data. This makes it easy to build and review page states without\n          needing to navigate to them in your app. Here are some handy patterns for managing page\n          data in Storybook:\n        </p>\n        <ul>\n          <li>\n            Use a higher-level connected component. Storybook helps you compose such data from the\n            \"args\" of child component stories\n          </li>\n          <li>\n            Assemble data in the page component from your services. You can mock these services out\n            using Storybook.\n          </li>\n        </ul>\n        <p>\n          Get a guided tutorial on component-driven development at{' '}\n          <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n            Storybook tutorials\n          </a>\n          . Read more in the{' '}\n          <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">\n            docs\n          </a>\n          .\n        </p>\n        <div className=\"tip-wrapper\">\n          <span className=\"tip\">Tip</span> Adjust the width of the canvas with the{' '}\n          <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n            <g fill=\"none\" fillRule=\"evenodd\">\n              <path\n                d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n                id=\"a\"\n                fill=\"#999\"\n              />\n            </g>\n          </svg>\n          Viewports addon in the toolbar\n        </div>\n      </section>\n    </article>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/next-env.d.ts",
    "content": "// Reference necessary since Next.js 13.2.0, because types in `next/navigation` are not exported per default, but\n// type references are dynamically created during Next.js start up.\n// See https://github.com/vercel/next.js/commit/cdf1d52d9aed42d01a46539886a4bda14cb77a99\n// for more insights.\n\n/// <reference types=\"next\" />\n/// <reference types=\"next/navigation-types/navigation\" />\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories/DynamicImport.stories.tsx",
    "content": "import React, { Suspense } from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs';\n\nimport dynamic from 'next/dynamic';\n\nconst DynamicComponent = dynamic(() => import('./dynamic-component'), {\n  ssr: false,\n});\n\nfunction Component() {\n  return (\n    <Suspense fallback=\"Loading...\">\n      <DynamicComponent />\n    </Suspense>\n  );\n}\n\nexport default {\n  component: Component,\n} as Meta<typeof Component>;\n\nexport const Default: StoryObj<typeof Component> = {};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories/Font.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/nextjs';\n\nimport Font from './Font';\n\nexport default {\n  component: Font,\n} as Meta<typeof Font>;\n\ntype Story = StoryObj<typeof Font>;\n\nexport const WithClassName: Story = {\n  args: {\n    variant: 'className',\n  },\n};\n\nexport const WithStyle: Story = {\n  args: {\n    variant: 'style',\n  },\n};\n\nexport const WithVariable: Story = {\n  args: {\n    variant: 'variable',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories/Font.tsx",
    "content": "import React from 'react';\n\nimport { Rubik_Puddles } from 'next/font/google';\nimport localFont from 'next/font/local';\n\nconst rubik = Rubik_Puddles({\n  subsets: ['latin'],\n  variable: '--font-latin-rubik',\n  weight: '400',\n});\n\nexport const localRubikStorm = localFont({\n  src: '/fonts/RubikStorm-Regular.ttf',\n  variable: '--font-rubik-storm',\n});\n\nexport default function Font({ variant }: { variant: 'className' | 'style' | 'variable' }) {\n  switch (variant) {\n    case 'className':\n      return (\n        <div>\n          <h1 className={rubik.className}>Google Rubik Puddles</h1>\n          <h1 className={localRubikStorm.className}>Google Local Rubik Storm</h1>\n        </div>\n      );\n    case 'style':\n      return (\n        <div>\n          <h1 style={rubik.style}>Google Rubik Puddles</h1>\n          <h1 style={localRubikStorm.style}>Google Local Rubik Storm</h1>\n        </div>\n      );\n    case 'variable':\n      return (\n        <div>\n          <div className={rubik.variable}>\n            <h1\n              style={{\n                fontFamily: 'var(--font-latin-rubik)',\n                fontStyle: rubik.style.fontStyle,\n                fontWeight: rubik.style.fontWeight,\n              }}\n            >\n              Google Rubik Puddles\n            </h1>\n          </div>\n          <div className={localRubikStorm.variable}>\n            <h1\n              style={{\n                fontFamily: 'var(--font-rubik-storm)',\n                fontStyle: localRubikStorm.style.fontStyle,\n                fontWeight: localRubikStorm.style.fontWeight,\n              }}\n            >\n              Google Local Rubik Storm\n            </h1>\n          </div>\n        </div>\n      );\n    default:\n      return null;\n  }\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories/Head.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs';\n\nimport Head from 'next/head';\nimport { expect, waitFor } from 'storybook/test';\n\nfunction Component() {\n  return (\n    <div>\n      <Head>\n        <title>Next.js Head Title</title>\n        <meta property=\"og:title\" content=\"My page title\" key=\"title\" />\n      </Head>\n      <Head>\n        <meta property=\"og:title\" content=\"My new title\" key=\"title\" />\n      </Head>\n      <p>Hello world!</p>\n    </div>\n  );\n}\n\nexport default {\n  component: Component,\n} as Meta<typeof Component>;\n\nexport const Default: StoryObj<typeof Component> = {\n  play: async () => {\n    await waitFor(() => expect(document.title).toEqual('Next.js Head Title'));\n    await expect(document.querySelectorAll('meta[property=\"og:title\"]')).toHaveLength(1);\n    await expect(\n      (document.querySelector('meta[property=\"og:title\"]') as HTMLMetaElement)?.content\n    ).toEqual('My new title');\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories/Image.stories.tsx",
    "content": "import React, { useState } from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs';\n\nimport Image from 'next/image';\n\nimport Accessibility from '../../assets/accessibility.svg';\nimport AvifImage from '../../assets/avif-test-image.avif';\n\nexport default {\n  component: Image,\n  args: {\n    src: Accessibility,\n    alt: 'Accessibility',\n  },\n} as Meta<typeof Image>;\n\ntype Story = StoryObj<typeof Image>;\n\nexport const Default: Story = {};\n\nexport const Avif: Story = {\n  args: {\n    src: AvifImage,\n    alt: 'Avif Test Image',\n  },\n};\n\nexport const BlurredPlaceholder: Story = {\n  args: {\n    placeholder: 'blur',\n  },\n};\n\nexport const BlurredAbsolutePlaceholder: Story = {\n  args: {\n    src: 'https://storybook.js.org/images/placeholders/50x50.png',\n    width: 50,\n    height: 50,\n    blurDataURL:\n      'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAABP5JREFUWEeNlwtz2zgMhEGKsv/k9XFp82xe11763yOJVGcXC4m2czM3GYa0E2s/LACSTi+vv1czM/7CvPpqxY/ejPeS3khmFiPHOiVLHKaZi4ux4j18GpMlS6cALupEQBCKQM4BdnGzjIcJgs//QBxAPQAem55f3yL4PWJIdyCyhlMfPdYZot0cwj3Ayg/5JwHA13paen7pADphxr/n5VI8JQsHCCGQ3gVGLLsxQ3h/LYSn5383B05rwNOws3Z576LOTOduvwfrOd5FtVat4akx0uPTrw8BNuUz23vLsY7hmg7i4ipqM2saiAdruNuirh4ff0bNdb3Qy3vkvfAQwrkHoDxTTZtDCOKrC1bMEkdnsQh/PLyetOGHkXeRAgQAQ84efQcBdUhvFofoulpdm9WGGTA+AJEe7l+i37a2c371tCFKs5zzJjxQNBMi1im7OCudP2aNghJuzZaGdSMEZjpwf/t0UgNdg9DOyLGLnY0BUHlzwVtNDkgEQhBeKkb1tUDgQrq7frwAiIJi5BKAeIFgHk5mOpPzvgltOfcoK0Rrs7lWHwsgqtXarK3N0u23h5Ne8+3Cqxn5RYSMfHCAMgDAx4CBWlA9RAGw0GA/ol0gvFB4WjAvBAFUa83SzdUdAbYMqp28uHpxCRefxwAYhksAFBlthxCiXig+zT4TYqkC+Hq7OdAfJv8lPpZiZShWBBIuRP+jspDb2lwcDkzz7OLzbO/zvAHAoXTz5eYMQL0t2yHAiCFcfPY1QDwNFylA5bPoFpsV9fsEiMl8dhcc4PP1CYD3drYcBYdIKQrx0cbRxd2JHSDcQ297/vvoZ5smRC+AyV2AQ+nm03evge08Tyy4jGqXzWWEoIvTgXHU38pWiNgH4ixB/ukAcy/xycXfp4kwdAAAt399W+OCgMjxILQacxvRQ3gEwHgKUIr/rz53CuDFNyP/Eob4+/vEWkBq6AAA/HIi62n/Lk67Q7wDYQ0UpQB7hc54T4E6gACLTYxeAwB0YKZL6U4ATEGIBwCs7qPfQJCCHkCnoK50noJKcXcAojsEAJZZKXhgCoziGKxqWV8IMNp4kP2aC+oB0TMFvhGxDQHQfIPhDrilwKOm/YCZASAHfgBABQjr3f7CyAkA0cPB03AQULRhKd4xAIjzHymo2Gp7gN0FAMAVOoA2fPz03a9ssh/RM7Iz8QKIzYF9HyB0XEZ1xJ4DzNoDOAfAslhDDTyjDfv8A2AcBeCiu/jBHQEgxnYW6Kp6BlCVAkQM8VnieF2Xyr0ivXy+XvsCzKOihwNHCCryw8HrQXVB8dgFeRfAVQiXjMbIIgXINQYB2H7Kf5wF/2Ar7h0AgKKGuAP4zOjhzlkLbpcRXKRZhNUjxG6HIQDOjN47gCn4+fWW3xVS9urPESEEwwHMo9IhAGxS2ISiA1iEnQOoA4hXRAwItp7WzL9Ow18ESJaw/ar4NgeOR49cAHCAnaH8swBhv+6CBGjeBSxEOUAI7HyKHkD4O9xKb3/feQouAI4uLBciHRRHmgbfA7h/xFc9AngNBADthvii1sMOiPwDAFeyt6s7FSFS4PmnA1v0vQvqDqQKAAPE/weAUuEgsj8c+H11Twdw/AKANXA82EDr5cJBEEzB3oI4Mb0AdR3nNw8vQnegWuvqAABwJFJEBwDgNdA7IOs3gL0LhuJdwBY8c4BfNnDdVgooHiOqn/b7JoSW/QODjTHXhU7hMQAAAABJRU5ErkJggg==',\n    placeholder: 'blur',\n  },\n  parameters: {\n    // ignoring in Chromatic to avoid inconsistent snapshots\n    // given that the switch from blur to image is quite fast\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const FilledParent: Story = {\n  args: {\n    fill: true,\n  },\n  decorators: [\n    (Story) => (\n      <div style={{ width: 500, height: 500, position: 'relative' }}>\n        <Story />\n      </div>\n    ),\n  ],\n};\n\nexport const Sized: Story = {\n  args: {\n    fill: true,\n    sizes: '(max-width: 600px) 100vw, 600px',\n  },\n  decorators: [\n    (Story) => (\n      <div style={{ width: 800, height: 800, position: 'relative' }}>\n        <Story />\n      </div>\n    ),\n  ],\n};\n\nexport const Lazy: Story = {\n  args: {\n    src: 'https://storybook.js.org/images/placeholders/50x50.png',\n    width: 50,\n    height: 50,\n  },\n  decorators: [\n    (Story) => (\n      <>\n        <div style={{ height: '200vh' }} />\n        <Story />\n      </>\n    ),\n  ],\n};\n\nexport const Eager: Story = {\n  ...Lazy,\n  parameters: {\n    nextjs: {\n      image: {\n        loading: 'eager',\n      },\n    },\n  },\n};\n\nexport const WithRef: Story = {\n  render() {\n    const [ref, setRef] = useState<HTMLImageElement | null>(null);\n\n    return (\n      <div>\n        <Image src={Accessibility} alt=\"Accessibility\" ref={setRef} />\n        <p>Alt attribute of image: {ref?.alt}</p>\n      </div>\n    );\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories/ImageLegacy.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/nextjs';\n\nimport Image from 'next/legacy/image';\n\nimport Accessibility from '../../assets/accessibility.svg';\n\nexport default {\n  component: Image,\n  args: {\n    src: Accessibility,\n    alt: 'Accessibility',\n  },\n} as Meta<typeof Image>;\n\ntype Story = StoryObj<typeof Image>;\n\nexport const Default: Story = {};\n\nexport const BlurredPlaceholder: Story = {\n  args: {\n    placeholder: 'blur',\n  },\n};\n\nexport const BlurredAbsolutePlaceholder: Story = {\n  args: {\n    src: 'https://storybook.js.org/images/placeholders/50x50.png',\n    width: 50,\n    height: 50,\n    blurDataURL:\n      'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAABP5JREFUWEeNlwtz2zgMhEGKsv/k9XFp82xe11763yOJVGcXC4m2czM3GYa0E2s/LACSTi+vv1czM/7CvPpqxY/ejPeS3khmFiPHOiVLHKaZi4ux4j18GpMlS6cALupEQBCKQM4BdnGzjIcJgs//QBxAPQAem55f3yL4PWJIdyCyhlMfPdYZot0cwj3Ayg/5JwHA13paen7pADphxr/n5VI8JQsHCCGQ3gVGLLsxQ3h/LYSn5383B05rwNOws3Z576LOTOduvwfrOd5FtVat4akx0uPTrw8BNuUz23vLsY7hmg7i4ipqM2saiAdruNuirh4ff0bNdb3Qy3vkvfAQwrkHoDxTTZtDCOKrC1bMEkdnsQh/PLyetOGHkXeRAgQAQ84efQcBdUhvFofoulpdm9WGGTA+AJEe7l+i37a2c371tCFKs5zzJjxQNBMi1im7OCudP2aNghJuzZaGdSMEZjpwf/t0UgNdg9DOyLGLnY0BUHlzwVtNDkgEQhBeKkb1tUDgQrq7frwAiIJi5BKAeIFgHk5mOpPzvgltOfcoK0Rrs7lWHwsgqtXarK3N0u23h5Ne8+3Cqxn5RYSMfHCAMgDAx4CBWlA9RAGw0GA/ol0gvFB4WjAvBAFUa83SzdUdAbYMqp28uHpxCRefxwAYhksAFBlthxCiXig+zT4TYqkC+Hq7OdAfJv8lPpZiZShWBBIuRP+jspDb2lwcDkzz7OLzbO/zvAHAoXTz5eYMQL0t2yHAiCFcfPY1QDwNFylA5bPoFpsV9fsEiMl8dhcc4PP1CYD3drYcBYdIKQrx0cbRxd2JHSDcQ297/vvoZ5smRC+AyV2AQ+nm03evge08Tyy4jGqXzWWEoIvTgXHU38pWiNgH4ixB/ukAcy/xycXfp4kwdAAAt399W+OCgMjxILQacxvRQ3gEwHgKUIr/rz53CuDFNyP/Eob4+/vEWkBq6AAA/HIi62n/Lk67Q7wDYQ0UpQB7hc54T4E6gACLTYxeAwB0YKZL6U4ATEGIBwCs7qPfQJCCHkCnoK50noJKcXcAojsEAJZZKXhgCoziGKxqWV8IMNp4kP2aC+oB0TMFvhGxDQHQfIPhDrilwKOm/YCZASAHfgBABQjr3f7CyAkA0cPB03AQULRhKd4xAIjzHymo2Gp7gN0FAMAVOoA2fPz03a9ssh/RM7Iz8QKIzYF9HyB0XEZ1xJ4DzNoDOAfAslhDDTyjDfv8A2AcBeCiu/jBHQEgxnYW6Kp6BlCVAkQM8VnieF2Xyr0ivXy+XvsCzKOihwNHCCryw8HrQXVB8dgFeRfAVQiXjMbIIgXINQYB2H7Kf5wF/2Ar7h0AgKKGuAP4zOjhzlkLbpcRXKRZhNUjxG6HIQDOjN47gCn4+fWW3xVS9urPESEEwwHMo9IhAGxS2ISiA1iEnQOoA4hXRAwItp7WzL9Ow18ESJaw/ar4NgeOR49cAHCAnaH8swBhv+6CBGjeBSxEOUAI7HyKHkD4O9xKb3/feQouAI4uLBciHRRHmgbfA7h/xFc9AngNBADthvii1sMOiPwDAFeyt6s7FSFS4PmnA1v0vQvqDqQKAAPE/weAUuEgsj8c+H11Twdw/AKANXA82EDr5cJBEEzB3oI4Mb0AdR3nNw8vQnegWuvqAABwJFJEBwDgNdA7IOs3gL0LhuJdwBY8c4BfNnDdVgooHiOqn/b7JoSW/QODjTHXhU7hMQAAAABJRU5ErkJggg==',\n    placeholder: 'blur',\n  },\n  parameters: {\n    // ignoring in Chromatic to avoid inconsistent snapshots\n    // given that the switch from blur to image is quite fast\n    chromatic: { disableSnapshot: true },\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories/Link.stories.module.css",
    "content": ".link {\n  color: green;\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories/Link.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs';\n\nimport Link from 'next/link';\n\nimport style from './Link.stories.module.css';\n\n// `onClick`, `href`, and `ref` need to be passed to the DOM element\n// for proper handling\nconst MyButton = React.forwardRef<\n  HTMLAnchorElement,\n  React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>\n>(function Button({ onClick, href, children }, ref) {\n  return (\n    <a href={href} onClick={onClick} ref={ref}>\n      {children}\n    </a>\n  );\n});\n\nconst Component = () => (\n  <ul>\n    <li>\n      <Link href=\"/\">Normal Link</Link>\n    </li>\n    <li>\n      <Link\n        href={{\n          pathname: '/with-url-object',\n          query: { name: 'test' },\n        }}\n      >\n        With URL Object\n      </Link>\n    </li>\n    <li>\n      <Link href=\"/replace-url\" replace>\n        Replace the URL instead of push\n      </Link>\n    </li>\n    <li>\n      <Link href=\"/#hashid\" scroll={false}>\n        Disables scrolling to the top\n      </Link>\n    </li>\n    <li>\n      <Link href=\"/no-prefetch\" prefetch={false}>\n        No Prefetching\n      </Link>\n    </li>\n    <li>\n      <Link style={{ color: 'red' }} href=\"/with-style\">\n        With style\n      </Link>\n    </li>\n    <li>\n      <Link className={style.link} href=\"/with-classname\">\n        With className\n      </Link>\n    </li>\n  </ul>\n);\n\nexport default {\n  component: Component,\n} as Meta<typeof Component>;\n\ntype Story = StoryObj<typeof Component>;\n\nexport const Default: Story = {};\n\nexport const InAppDir: Story = {\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n    },\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories/Navigation.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs';\nimport { getRouter } from '@storybook/nextjs/navigation.mock';\n\nimport {\n  useParams,\n  usePathname,\n  useRouter,\n  useSearchParams,\n  useSelectedLayoutSegment,\n  useSelectedLayoutSegments,\n} from 'next/navigation';\nimport { expect, userEvent, within } from 'storybook/test';\n\nfunction Component() {\n  const router = useRouter();\n  const pathname = usePathname();\n  const searchParams = useSearchParams();\n  const params = useParams();\n  const segment = useSelectedLayoutSegment();\n  const segments = useSelectedLayoutSegments();\n\n  const searchParamsList = searchParams ? Array.from(searchParams.entries()) : [];\n\n  const routerActions = [\n    {\n      cb: () => router.back(),\n      name: 'Go back',\n    },\n    {\n      cb: () => router.forward(),\n      name: 'Go forward',\n    },\n    {\n      cb: () => router.prefetch('/prefetched-html'),\n      name: 'Prefetch',\n    },\n    {\n      // @ts-expect-error (old API)\n      cb: () => router.push('/push-html', { forceOptimisticNavigation: true }),\n      name: 'Push HTML',\n    },\n    {\n      cb: () => router.refresh(),\n      name: 'Refresh',\n    },\n    {\n      // @ts-expect-error (old API)\n      cb: () => router.replace('/replaced-html', { forceOptimisticNavigation: true }),\n      name: 'Replace',\n    },\n  ];\n\n  return (\n    <div>\n      <div>pathname: {pathname}</div>\n      <div>segment: {segment}</div>\n      <div>segments: {segments.join(',')}</div>\n      <div>\n        searchparams:{' '}\n        <ul>\n          {searchParamsList.map(([key, value]) => (\n            <li key={key}>\n              {key}: {value}\n            </li>\n          ))}\n        </ul>\n      </div>\n      <div>\n        params:{' '}\n        <ul>\n          {Object.entries(params).map(([key, value]) => (\n            <li key={key}>\n              {key}: {value}\n            </li>\n          ))}\n        </ul>\n      </div>\n      {routerActions.map(({ cb, name }) => (\n        <div key={name} style={{ marginBottom: '1em' }}>\n          <button type=\"button\" onClick={cb}>\n            {name}\n          </button>\n        </div>\n      ))}\n    </div>\n  );\n}\n\ntype Story = StoryObj<typeof Component>;\n\nexport default {\n  component: Component,\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        pathname: '/hello',\n        query: {\n          foo: 'bar',\n        },\n        prefetch: () => {\n          console.log('custom prefetch');\n        },\n      },\n    },\n  },\n} as Meta<typeof Component>;\n\nexport const Default: Story = {\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const routerMock = getRouter();\n\n    await step('Asserts whether forward hook is called', async () => {\n      const forwardBtn = await canvas.findByText('Go forward');\n      await userEvent.click(forwardBtn);\n      await expect(routerMock.forward).toHaveBeenCalled();\n    });\n\n    await step('Asserts whether custom prefetch hook is called', async () => {\n      const prefetchBtn = await canvas.findByText('Prefetch');\n      await userEvent.click(prefetchBtn);\n      await expect(routerMock.prefetch).toHaveBeenCalledWith('/prefetched-html');\n    });\n  },\n};\n\nexport const WithSegmentDefined: Story = {\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        segments: ['dashboard', 'settings'],\n      },\n    },\n  },\n};\n\nexport const WithSegmentDefinedForParams: Story = {\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        segments: [\n          ['slug', 'hello'],\n          ['framework', 'nextjs'],\n        ],\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories/RSC.stories.tsx",
    "content": "/* eslint-disable local-rules/no-uncategorized-errors */\nimport React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs';\n\nimport { Nested, RSC } from './RSC';\n\nexport default {\n  component: RSC,\n  args: { label: 'label' },\n  parameters: {\n    react: {\n      rsc: true,\n    },\n  },\n} as Meta<typeof RSC>;\n\ntype Story = StoryObj<typeof RSC>;\n\nexport const Default: Story = {};\n\nexport const DisableRSC: Story = {\n  tags: ['!test'],\n  parameters: {\n    chromatic: { disableSnapshot: true },\n    nextjs: { rsc: false },\n  },\n};\n\nexport const Errored: Story = {\n  tags: ['!test', '!vitest'],\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n  render: () => {\n    throw new Error('RSC Error');\n  },\n};\n\nexport const NestedRSC: Story = {\n  render: (args) => (\n    <Nested>\n      <RSC {...args} />\n    </Nested>\n  ),\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories/RSC.tsx",
    "content": "import React from 'react';\n\nimport 'server-only';\n\nexport const RSC = async ({ label }: { label: string }) => <>RSC {label}</>;\n\nexport const Nested = async ({ children }: any) => <>Nested {children}</>;\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories/Router.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs';\nimport { getRouter } from '@storybook/nextjs/router.mock';\n\nimport Router, { useRouter } from 'next/router';\nimport { expect, userEvent, within } from 'storybook/test';\n\nfunction Component() {\n  const router = useRouter();\n  const searchParams = router.query;\n\n  const routerActions = [\n    {\n      cb: () => router.back(),\n      name: 'Go back',\n    },\n    {\n      cb: () => router.forward(),\n      name: 'Go forward',\n    },\n    {\n      cb: () => router.prefetch('/prefetched-html'),\n      name: 'Prefetch',\n    },\n    {\n      // @ts-expect-error (old API)\n      cb: () => router.push('/push-html', { forceOptimisticNavigation: true }),\n      name: 'Push HTML',\n    },\n    {\n      // @ts-expect-error (old API)\n      cb: () => router.replace('/replaced-html', { forceOptimisticNavigation: true }),\n      name: 'Replace',\n    },\n  ];\n\n  return (\n    <div>\n      <div>Router pathname: {Router.pathname}</div>\n      <div>pathname: {router.pathname}</div>\n      <div>\n        searchparams:{' '}\n        <ul>\n          {Object.entries(searchParams).map(([key, value]) => (\n            <li key={key}>\n              {key}: {value}\n            </li>\n          ))}\n        </ul>\n      </div>\n      {routerActions.map(({ cb, name }) => (\n        <div key={name} style={{ marginBottom: '1em' }}>\n          <button type=\"button\" onClick={cb}>\n            {name}\n          </button>\n        </div>\n      ))}\n    </div>\n  );\n}\n\nexport default {\n  component: Component,\n  parameters: {\n    nextjs: {\n      router: {\n        pathname: '/hello',\n        query: {\n          foo: 'bar',\n        },\n        prefetch: () => {\n          console.log('custom prefetch');\n        },\n      },\n    },\n  },\n} as Meta<typeof Component>;\n\nexport const Default: StoryObj<typeof Component> = {\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const routerMock = getRouter();\n\n    await step('Router property overrides should be available in useRouter fn', async () => {\n      await expect(Router.pathname).toBe('/hello');\n      await expect(Router.query).toEqual({ foo: 'bar' });\n    });\n\n    await step(\n      'Router property overrides should be available in default export from next/router',\n      async () => {\n        await expect(Router.pathname).toBe('/hello');\n        await expect(Router.query).toEqual({ foo: 'bar' });\n      }\n    );\n\n    await step('Asserts whether forward hook is called', async () => {\n      const forwardBtn = await canvas.findByText('Go forward');\n      await userEvent.click(forwardBtn);\n      await expect(routerMock.forward).toHaveBeenCalled();\n    });\n\n    await step('Asserts whether custom prefetch hook is called', async () => {\n      const prefetchBtn = await canvas.findByText('Prefetch');\n      await userEvent.click(prefetchBtn);\n      await expect(routerMock.prefetch).toHaveBeenCalledWith('/prefetched-html');\n    });\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories/StyledJsx.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs';\n\nconst Component = () => (\n  <div>\n    <style jsx>{`\n      .main p {\n        color: #ff4785;\n      }\n    `}</style>\n    <main className=\"main\">\n      <p>This is styled using Styled JSX</p>\n    </main>\n  </div>\n);\n\nexport default {\n  component: Component,\n} as Meta<typeof Component>;\n\nexport const Default: StoryObj<typeof Component> = {};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories/dynamic-component.tsx",
    "content": "import React from 'react';\n\nexport default function DynamicComponent() {\n  return <div>I am a dynamically loaded component</div>;\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories/fonts/OFL.txt",
    "content": "Copyright 2020 The Rubik Filtered Project Authors (https://https://github.com/NaN-xyz/Rubik-Filtered)\r\n\r\nThis Font Software is licensed under the SIL Open Font License, Version 1.1.\r\nThis license is copied below, and is also available with a FAQ at:\r\nhttp://scripts.sil.org/OFL\r\n\r\n\r\n-----------------------------------------------------------\r\nSIL OPEN FONT LICENSE Version 1.1 - 26 February 2007\r\n-----------------------------------------------------------\r\n\r\nPREAMBLE\r\nThe goals of the Open Font License (OFL) are to stimulate worldwide\r\ndevelopment of collaborative font projects, to support the font creation\r\nefforts of academic and linguistic communities, and to provide a free and\r\nopen framework in which fonts may be shared and improved in partnership\r\nwith others.\r\n\r\nThe OFL allows the licensed fonts to be used, studied, modified and\r\nredistributed freely as long as they are not sold by themselves. The\r\nfonts, including any derivative works, can be bundled, embedded, \r\nredistributed and/or sold with any software provided that any reserved\r\nnames are not used by derivative works. The fonts and derivatives,\r\nhowever, cannot be released under any other type of license. The\r\nrequirement for fonts to remain under this license does not apply\r\nto any document created using the fonts or their derivatives.\r\n\r\nDEFINITIONS\r\n\"Font Software\" refers to the set of files released by the Copyright\r\nHolder(s) under this license and clearly marked as such. This may\r\ninclude source files, build scripts and documentation.\r\n\r\n\"Reserved Font Name\" refers to any names specified as such after the\r\ncopyright statement(s).\r\n\r\n\"Original Version\" refers to the collection of Font Software components as\r\ndistributed by the Copyright Holder(s).\r\n\r\n\"Modified Version\" refers to any derivative made by adding to, deleting,\r\nor substituting -- in part or in whole -- any of the components of the\r\nOriginal Version, by changing formats or by porting the Font Software to a\r\nnew environment.\r\n\r\n\"Author\" refers to any designer, engineer, programmer, technical\r\nwriter or other person who contributed to the Font Software.\r\n\r\nPERMISSION & CONDITIONS\r\nPermission is hereby granted, free of charge, to any person obtaining\r\na copy of the Font Software, to use, study, copy, merge, embed, modify,\r\nredistribute, and sell modified and unmodified copies of the Font\r\nSoftware, subject to the following conditions:\r\n\r\n1) Neither the Font Software nor any of its individual components,\r\nin Original or Modified Versions, may be sold by itself.\r\n\r\n2) Original or Modified Versions of the Font Software may be bundled,\r\nredistributed and/or sold with any software, provided that each copy\r\ncontains the above copyright notice and this license. These can be\r\nincluded either as stand-alone text files, human-readable headers or\r\nin the appropriate machine-readable metadata fields within text or\r\nbinary files as long as those fields can be easily viewed by the user.\r\n\r\n3) No Modified Version of the Font Software may use the Reserved Font\r\nName(s) unless explicit written permission is granted by the corresponding\r\nCopyright Holder. This restriction only applies to the primary font name as\r\npresented to the users.\r\n\r\n4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font\r\nSoftware shall not be used to promote, endorse or advertise any\r\nModified Version, except to acknowledge the contribution(s) of the\r\nCopyright Holder(s) and the Author(s) or with their explicit written\r\npermission.\r\n\r\n5) The Font Software, modified or unmodified, in part or in whole,\r\nmust be distributed entirely under this license, and must not be\r\ndistributed under any other license. The requirement for fonts to\r\nremain under this license does not apply to any document created\r\nusing the Font Software.\r\n\r\nTERMINATION\r\nThis license becomes null and void if any of the above conditions are\r\nnot met.\r\n\r\nDISCLAIMER\r\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\r\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\r\nOF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE\r\nCOPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\r\nINCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\r\nDAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r\nFROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM\r\nOTHER DEALINGS IN THE FONT SOFTWARE.\r\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories_nextjs-default-ts/GetImageProps.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs';\n\nimport { getImageProps } from 'next/image';\n\nimport Accessibility from '../../assets/accessibility.svg';\nimport Testing from '../../assets/testing.png';\n\n// referenced from https://nextjs.org/docs/pages/api-reference/components/image#theme-detection-picture\nconst Component = (props: any) => {\n  const {\n    props: { srcSet: dark },\n  } = getImageProps({ src: Accessibility, ...props });\n  const {\n    // capture rest on one to spread to img as default; it doesn't matter which barring art direction\n    props: { srcSet: light, ...rest },\n  } = getImageProps({ src: Testing, ...props });\n\n  return (\n    <picture>\n      <source media=\"(prefers-color-scheme: dark)\" srcSet={dark} />\n      <source media=\"(prefers-color-scheme: light)\" srcSet={light} />\n      <img {...rest} />\n    </picture>\n  );\n};\n\nexport default {\n  component: Component,\n  args: {\n    alt: 'getImageProps Example',\n  },\n} as Meta<typeof Component>;\n\nexport const Default: StoryObj<typeof Component> = {};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories_nextjs-default-ts/NextHeader.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/nextjs';\nimport { cookies, headers } from '@storybook/nextjs/headers.mock';\n\nimport { expect, userEvent, within } from 'storybook/test';\n\nimport NextHeader from './NextHeader';\n\nexport default {\n  component: NextHeader,\n  parameters: {\n    react: {\n      rsc: true,\n    },\n  },\n} as Meta<typeof NextHeader>;\n\ntype Story = StoryObj<typeof NextHeader>;\n\nexport const Default: Story = {\n  loaders: async () => {\n    cookies().set('firstName', 'Jane');\n    cookies().set({\n      name: 'lastName',\n      value: 'Doe',\n    });\n    headers().set('timezone', 'Central European Summer Time');\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const headersMock = headers();\n    const cookiesMock = cookies();\n    await step('Cookie and header store apis are called upon rendering', async () => {\n      await expect(cookiesMock.getAll).toHaveBeenCalled();\n      await expect(headersMock.entries).toHaveBeenCalled();\n    });\n\n    await step('Upon clicking on submit, the user-id cookie is set', async () => {\n      const submitButton = await canvas.findByRole('button');\n      await userEvent.click(submitButton);\n\n      await expect(cookiesMock.set).toHaveBeenCalledWith('user-id', 'encrypted-id');\n    });\n\n    await step('The user-id cookie is available in cookie and header stores', async () => {\n      await expect(headersMock.get('cookie')).toContain('user-id=encrypted-id');\n      await expect(cookiesMock.get('user-id')).toEqual({\n        name: 'user-id',\n        value: 'encrypted-id',\n      });\n    });\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories_nextjs-default-ts/NextHeader.tsx",
    "content": "import React from 'react';\n\nimport { cookies, headers } from 'next/headers';\n\nexport default async function Component() {\n  async function handleClick() {\n    'use server';\n    (await cookies()).set('user-id', 'encrypted-id');\n  }\n\n  return (\n    <>\n      <h3>Cookies:</h3>\n      {(await cookies()).getAll().map(({ name, value }) => {\n        return (\n          <p key={name} style={{ display: 'flex', flexDirection: 'row', gap: 8 }}>\n            <strong>Name:</strong> <span>{name}</span>\n            <strong>Value:</strong> <span>{value}</span>\n          </p>\n        );\n      })}\n\n      <h3>Headers:</h3>\n      {Array.from((await headers()).entries()).map(([name, value]: [string, string]) => {\n        return (\n          <p key={name} style={{ display: 'flex', flexDirection: 'row', gap: 8 }}>\n            <strong>Name:</strong> <span>{name}</span>\n            <strong>Value:</strong> <span>{value}</span>\n          </p>\n        );\n      })}\n\n      <form action={handleClick}>\n        <button>add user-id cookie</button>\n      </form>\n    </>\n  );\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories_nextjs-default-ts/Redirect.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs';\n\nimport { redirect } from 'next/navigation';\nimport { userEvent, within } from 'storybook/test';\n\nlet state = 'Bug! Not invalidated';\n\nexport default {\n  render() {\n    return (\n      <div>\n        <div>{state}</div>\n        <form\n          action={() => {\n            state = 'State is invalidated successfully.';\n            redirect('/');\n          }}\n        >\n          <button>Submit</button>\n        </form>\n      </div>\n    );\n  },\n  parameters: {\n    test: {\n      // This is needed until Next will update to the React 19 beta: https://github.com/vercel/next.js/pull/65058\n      // In the React 19 beta ErrorBoundary errors (such as redirect) are only logged, and not thrown.\n      // We will also suspress console.error logs for re the console.error logs for redirect in the next framework.\n      // Using the onCaughtError react root option:\n      //   react: {\n      //     rootOptions: {\n      //       onCaughtError(error: unknown) {\n      //         if (isNextRouterError(error)) return;\n      //         console.error(error);\n      //       },\n      //     },\n      // See: code/frameworks/nextjs/src/preview.tsx\n      dangerouslyIgnoreUnhandledErrors: true,\n    },\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        pathname: '/',\n      },\n    },\n  },\n  tags: ['!test'],\n} as Meta;\n\nexport const SingletonStateGetsInvalidatedAfterRedirecting: StoryObj = {\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    await userEvent.click(canvas.getByRole('button'));\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories_nextjs-default-ts/ServerActions.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs';\nimport { revalidatePath } from '@storybook/nextjs/cache.mock';\nimport { cookies } from '@storybook/nextjs/headers.mock';\nimport { getRouter, redirect } from '@storybook/nextjs/navigation.mock';\n\nimport { expect, userEvent, waitFor, within } from 'storybook/test';\n\nimport { accessRoute, login, logout } from './server-actions';\n\nfunction Component() {\n  return (\n    <div style={{ display: 'flex', gap: 8 }}>\n      <form>\n        <button type=\"submit\" formAction={login}>\n          Login\n        </button>\n      </form>\n      <form>\n        <button type=\"submit\" formAction={logout}>\n          Logout\n        </button>\n      </form>\n      <form>\n        <button type=\"submit\" formAction={accessRoute}>\n          Access protected route\n        </button>\n      </form>\n    </div>\n  );\n}\n\nexport default {\n  component: Component,\n  tags: ['!test'],\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        pathname: '/',\n      },\n    },\n    test: {\n      // This is needed until Next will update to the React 19 beta: https://github.com/vercel/next.js/pull/65058\n      // In the React 19 beta ErrorBoundary errors (such as redirect) are only logged, and not thrown.\n      // We will also suspress console.error logs for re the console.error logs for redirect in the next framework.\n      // Using the onCaughtError react root option:\n      //   react: {\n      //     rootOptions: {\n      //       onCaughtError(error: unknown) {\n      //         if (isNextRouterError(error)) return;\n      //         console.error(error);\n      //       },\n      //     },\n      // See: code/frameworks/nextjs/src/preview.tsx\n      dangerouslyIgnoreUnhandledErrors: true,\n    },\n  },\n} as Meta<typeof Component>;\n\ntype Story = StoryObj<typeof Component>;\n\nexport const ProtectedWhileLoggedOut: Story = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    await userEvent.click(canvas.getByText('Access protected route'));\n\n    await expect(cookies().get).toHaveBeenCalledWith('user');\n    await expect(redirect).toHaveBeenCalledWith('/');\n\n    await waitFor(() => expect(getRouter().push).toHaveBeenCalled());\n  },\n};\n\nexport const ProtectedWhileLoggedIn: Story = {\n  beforeEach() {\n    cookies().set('user', 'storybookjs');\n  },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    await userEvent.click(canvas.getByText('Access protected route'));\n\n    await expect(cookies().get).toHaveBeenLastCalledWith('user');\n    await expect(revalidatePath).toHaveBeenLastCalledWith('/');\n    await expect(redirect).toHaveBeenLastCalledWith('/protected');\n\n    await waitFor(() => expect(getRouter().push).toHaveBeenCalled());\n  },\n};\n\nexport const Logout: Story = {\n  beforeEach() {\n    cookies().set('user', 'storybookjs');\n  },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n\n    await userEvent.click(canvas.getByText('Logout'));\n    await expect(cookies().delete).toHaveBeenCalled();\n    await expect(revalidatePath).toHaveBeenCalledWith('/');\n    await expect(redirect).toHaveBeenCalledWith('/');\n\n    await waitFor(() => expect(getRouter().push).toHaveBeenCalled());\n  },\n};\n\nexport const Login: Story = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    await userEvent.click(canvas.getByText('Login'));\n\n    await expect(cookies().set).toHaveBeenCalledWith('user', 'storybookjs');\n    await expect(revalidatePath).toHaveBeenCalledWith('/');\n    await expect(redirect).toHaveBeenCalledWith('/');\n\n    await waitFor(() => expect(getRouter().push).toHaveBeenCalled());\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories_nextjs-default-ts/server-actions.tsx",
    "content": "'use server';\n\nimport { revalidatePath } from 'next/cache';\nimport { cookies } from 'next/headers';\nimport { redirect } from 'next/navigation';\n\nexport async function accessRoute() {\n  const user = (await cookies()).get('user');\n\n  if (!user) {\n    redirect('/');\n  }\n\n  revalidatePath('/');\n  redirect(`/protected`);\n}\n\nexport async function logout() {\n  (await cookies()).delete('user');\n  revalidatePath('/');\n  redirect('/');\n}\n\nexport async function login() {\n  (await cookies()).set('user', 'storybookjs');\n  revalidatePath('/');\n  redirect('/');\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories_nextjs-prerelease/GetImageProps.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs';\n\nimport { getImageProps } from 'next/image';\n\nimport Accessibility from '../../assets/accessibility.svg';\nimport Testing from '../../assets/testing.png';\n\n// referenced from https://nextjs.org/docs/pages/api-reference/components/image#theme-detection-picture\nconst Component = (props: any) => {\n  const {\n    props: { srcSet: dark },\n  } = getImageProps({ src: Accessibility, ...props });\n  const {\n    // capture rest on one to spread to img as default; it doesn't matter which barring art direction\n    props: { srcSet: light, ...rest },\n  } = getImageProps({ src: Testing, ...props });\n\n  return (\n    <picture>\n      <source media=\"(prefers-color-scheme: dark)\" srcSet={dark} />\n      <source media=\"(prefers-color-scheme: light)\" srcSet={light} />\n      <img {...rest} />\n    </picture>\n  );\n};\n\nexport default {\n  component: Component,\n  args: {\n    alt: 'getImageProps Example',\n  },\n} as Meta<typeof Component>;\n\nexport const Default: StoryObj<typeof Component> = {};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories_nextjs-prerelease/NextHeader.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/nextjs';\nimport { cookies, headers } from '@storybook/nextjs/headers.mock';\n\nimport { expect, userEvent, within } from 'storybook/test';\n\nimport NextHeader from './NextHeader';\n\nexport default {\n  component: NextHeader,\n  parameters: {\n    react: {\n      rsc: true,\n    },\n  },\n} as Meta<typeof NextHeader>;\n\ntype Story = StoryObj<typeof NextHeader>;\n\nexport const Default: Story = {\n  loaders: async () => {\n    cookies().set('firstName', 'Jane');\n    cookies().set({\n      name: 'lastName',\n      value: 'Doe',\n    });\n    headers().set('timezone', 'Central European Summer Time');\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const headersMock = headers();\n    const cookiesMock = cookies();\n    await step('Cookie and header store apis are called upon rendering', async () => {\n      await expect(cookiesMock.getAll).toHaveBeenCalled();\n      await expect(headersMock.entries).toHaveBeenCalled();\n    });\n\n    await step('Upon clicking on submit, the user-id cookie is set', async () => {\n      const submitButton = await canvas.findByRole('button');\n      await userEvent.click(submitButton);\n\n      await expect(cookiesMock.set).toHaveBeenCalledWith('user-id', 'encrypted-id');\n    });\n\n    await step('The user-id cookie is available in cookie and header stores', async () => {\n      await expect(headersMock.get('cookie')).toContain('user-id=encrypted-id');\n      await expect(cookiesMock.get('user-id')).toEqual({\n        name: 'user-id',\n        value: 'encrypted-id',\n      });\n    });\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories_nextjs-prerelease/NextHeader.tsx",
    "content": "import React from 'react';\n\nimport { cookies, headers } from 'next/headers';\n\nexport default async function Component() {\n  async function handleClick() {\n    'use server';\n    (await cookies()).set('user-id', 'encrypted-id');\n  }\n\n  return (\n    <>\n      <h3>Cookies:</h3>\n      {(await cookies()).getAll().map(({ name, value }) => {\n        return (\n          <p key={name} style={{ display: 'flex', flexDirection: 'row', gap: 8 }}>\n            <strong>Name:</strong> <span>{name}</span>\n            <strong>Value:</strong> <span>{value}</span>\n          </p>\n        );\n      })}\n\n      <h3>Headers:</h3>\n      {Array.from((await headers()).entries()).map(([name, value]: [string, string]) => {\n        return (\n          <p key={name} style={{ display: 'flex', flexDirection: 'row', gap: 8 }}>\n            <strong>Name:</strong> <span>{name}</span>\n            <strong>Value:</strong> <span>{value}</span>\n          </p>\n        );\n      })}\n\n      <form action={handleClick}>\n        <button>add user-id cookie</button>\n      </form>\n    </>\n  );\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories_nextjs-prerelease/Redirect.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs';\n\nimport { redirect } from 'next/navigation';\nimport { userEvent, within } from 'storybook/test';\n\nlet state = 'Bug! Not invalidated';\n\nexport default {\n  render() {\n    return (\n      <div>\n        <div>{state}</div>\n        <form\n          action={() => {\n            state = 'State is invalidated successfully.';\n            redirect('/');\n          }}\n        >\n          <button>Submit</button>\n        </form>\n      </div>\n    );\n  },\n  parameters: {\n    test: {\n      // This is needed until Next will update to the React 19 beta: https://github.com/vercel/next.js/pull/65058\n      // In the React 19 beta ErrorBoundary errors (such as redirect) are only logged, and not thrown.\n      // We will also suspress console.error logs for re the console.error logs for redirect in the next framework.\n      // Using the onCaughtError react root option:\n      //   react: {\n      //     rootOptions: {\n      //       onCaughtError(error: unknown) {\n      //         if (isNextRouterError(error)) return;\n      //         console.error(error);\n      //       },\n      //     },\n      // See: code/frameworks/nextjs/src/preview.tsx\n      dangerouslyIgnoreUnhandledErrors: true,\n    },\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        pathname: '/',\n      },\n    },\n  },\n  tags: ['!test'],\n} as Meta;\n\nexport const SingletonStateGetsInvalidatedAfterRedirecting: StoryObj = {\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    await userEvent.click(canvas.getByRole('button'));\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories_nextjs-prerelease/ServerActions.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs';\nimport { revalidatePath } from '@storybook/nextjs/cache.mock';\nimport { cookies } from '@storybook/nextjs/headers.mock';\nimport { getRouter, redirect } from '@storybook/nextjs/navigation.mock';\n\nimport { expect, userEvent, waitFor, within } from 'storybook/test';\n\nimport { accessRoute, login, logout } from './server-actions';\n\nfunction Component() {\n  return (\n    <div style={{ display: 'flex', gap: 8 }}>\n      <form>\n        <button type=\"submit\" formAction={login}>\n          Login\n        </button>\n      </form>\n      <form>\n        <button type=\"submit\" formAction={logout}>\n          Logout\n        </button>\n      </form>\n      <form>\n        <button type=\"submit\" formAction={accessRoute}>\n          Access protected route\n        </button>\n      </form>\n    </div>\n  );\n}\n\nexport default {\n  component: Component,\n  tags: ['!test'],\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        pathname: '/',\n      },\n    },\n    test: {\n      // This is needed until Next will update to the React 19 beta: https://github.com/vercel/next.js/pull/65058\n      // In the React 19 beta ErrorBoundary errors (such as redirect) are only logged, and not thrown.\n      // We will also suspress console.error logs for re the console.error logs for redirect in the next framework.\n      // Using the onCaughtError react root option:\n      //   react: {\n      //     rootOptions: {\n      //       onCaughtError(error: unknown) {\n      //         if (isNextRouterError(error)) return;\n      //         console.error(error);\n      //       },\n      //     },\n      // See: code/frameworks/nextjs/src/preview.tsx\n      dangerouslyIgnoreUnhandledErrors: true,\n    },\n  },\n} as Meta<typeof Component>;\n\ntype Story = StoryObj<typeof Component>;\n\nexport const ProtectedWhileLoggedOut: Story = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    await userEvent.click(canvas.getByText('Access protected route'));\n\n    await expect(cookies().get).toHaveBeenCalledWith('user');\n    await expect(redirect).toHaveBeenCalledWith('/');\n\n    await waitFor(() => expect(getRouter().push).toHaveBeenCalled());\n  },\n};\n\nexport const ProtectedWhileLoggedIn: Story = {\n  beforeEach() {\n    cookies().set('user', 'storybookjs');\n  },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    await userEvent.click(canvas.getByText('Access protected route'));\n\n    await expect(cookies().get).toHaveBeenLastCalledWith('user');\n    await expect(revalidatePath).toHaveBeenLastCalledWith('/');\n    await expect(redirect).toHaveBeenLastCalledWith('/protected');\n\n    await waitFor(() => expect(getRouter().push).toHaveBeenCalled());\n  },\n};\n\nexport const Logout: Story = {\n  beforeEach() {\n    cookies().set('user', 'storybookjs');\n  },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n\n    await userEvent.click(canvas.getByText('Logout'));\n    await expect(cookies().delete).toHaveBeenCalled();\n    await expect(revalidatePath).toHaveBeenCalledWith('/');\n    await expect(redirect).toHaveBeenCalledWith('/');\n\n    await waitFor(() => expect(getRouter().push).toHaveBeenCalled());\n  },\n};\n\nexport const Login: Story = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    await userEvent.click(canvas.getByText('Login'));\n\n    await expect(cookies().set).toHaveBeenCalledWith('user', 'storybookjs');\n    await expect(revalidatePath).toHaveBeenCalledWith('/');\n    await expect(redirect).toHaveBeenCalledWith('/');\n\n    await waitFor(() => expect(getRouter().push).toHaveBeenCalled());\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs/template/stories_nextjs-prerelease/server-actions.tsx",
    "content": "'use server';\n\nimport { revalidatePath } from 'next/cache';\nimport { cookies } from 'next/headers';\nimport { redirect } from 'next/navigation';\n\nexport async function accessRoute() {\n  const user = (await cookies()).get('user');\n\n  if (!user) {\n    redirect('/');\n  }\n\n  revalidatePath('/');\n  redirect(`/protected`);\n}\n\nexport async function logout() {\n  (await cookies()).delete('user');\n  revalidatePath('/');\n  redirect('/');\n}\n\nexport async function login() {\n  (await cookies()).set('user', 'storybookjs');\n  revalidatePath('/');\n  redirect('/');\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/template/typings.d.ts",
    "content": "declare module '*.svg' {\n  const content: string;\n  export default content;\n}\n\ndeclare module '*.avif' {\n  const content: string;\n  export default content;\n}\n\ndeclare module '*.png' {\n  const content: string;\n  export default content;\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\", \"template/**/*\"]\n}\n"
  },
  {
    "path": "code/frameworks/nextjs/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/.eslintrc.json",
    "content": "{\n  \"rules\": {\n    \"global-require\": \"off\",\n    \"no-param-reassign\": \"off\",\n    \"import/no-dynamic-require\": \"off\"\n  },\n  \"overrides\": [\n    {\n      \"files\": [\"**/*.stories.@(jsx|tsx)\"],\n      \"rules\": {\n        \"react/no-unknown-property\": \"off\",\n        \"jsx-a11y/anchor-is-valid\": \"off\"\n      }\n    },\n    {\n      \"files\": [\"**/*.compat.@(tsx|ts)\"],\n      \"rules\": {\n        \"local-rules/no-uncategorized-errors\": \"off\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/README.md",
    "content": "# Storybook for Next.js with Vite Builder\n\nSee [documentation](https://storybook.js.org/docs/get-started/frameworks/nextjs-vite?renderer=react&ref=readme) for installation instructions, usage examples, APIs, and more.\n\n## Acknowledgements\n\nThis framework borrows heavily from these Storybook addons:\n\n- [storybook-addon-next](https://github.com/RyanClementsHax/storybook-addon-next) by [RyanClementsHax](https://github.com/RyanClementsHax/)\n- [storybook-addon-next-router](https://github.com/lifeiscontent/storybook-addon-next-router) by [lifeiscontent](https://github.com/lifeiscontent)\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./preview'],\n        entryPoint: './src/preview.tsx',\n      },\n      {\n        exportEntries: ['./config/preview'],\n        entryPoint: './src/config/preview.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./cache.mock'],\n        entryPoint: './src/export-mocks/cache/index.ts',\n      },\n      {\n        exportEntries: ['./headers.mock'],\n        entryPoint: './src/export-mocks/headers/index.ts',\n      },\n      {\n        exportEntries: ['./navigation.mock'],\n        entryPoint: './src/export-mocks/navigation/index.ts',\n      },\n      {\n        exportEntries: ['./router.mock'],\n        entryPoint: './src/export-mocks/router/index.ts',\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./node'],\n        entryPoint: './src/node/index.ts',\n      },\n      {\n        exportEntries: ['./vite-plugin'],\n        entryPoint: './src/vite-plugin/index.ts',\n      },\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/package.json",
    "content": "{\n  \"name\": \"@storybook/nextjs-vite\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook for Next.js and Vite: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-framework\",\n    \"next\",\n    \"next.js\",\n    \"vite\",\n    \"component\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/frameworks/nextjs-vite\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/frameworks/nextjs\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./cache.mock\": {\n      \"types\": \"./dist/export-mocks/cache/index.d.ts\",\n      \"code\": \"./src/export-mocks/cache/index.ts\",\n      \"default\": \"./dist/export-mocks/cache/index.js\"\n    },\n    \"./config/preview\": \"./dist/config/preview.js\",\n    \"./headers.mock\": {\n      \"types\": \"./dist/export-mocks/headers/index.d.ts\",\n      \"code\": \"./src/export-mocks/headers/index.ts\",\n      \"default\": \"./dist/export-mocks/headers/index.js\"\n    },\n    \"./navigation.mock\": {\n      \"types\": \"./dist/export-mocks/navigation/index.d.ts\",\n      \"code\": \"./src/export-mocks/navigation/index.ts\",\n      \"default\": \"./dist/export-mocks/navigation/index.js\"\n    },\n    \"./node\": {\n      \"types\": \"./dist/node/index.d.ts\",\n      \"code\": \"./src/node/index.ts\",\n      \"default\": \"./dist/node/index.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\",\n    \"./preview\": {\n      \"types\": \"./dist/preview.d.ts\",\n      \"code\": \"./src/preview.tsx\",\n      \"default\": \"./dist/preview.js\"\n    },\n    \"./router.mock\": {\n      \"types\": \"./dist/export-mocks/router/index.d.ts\",\n      \"code\": \"./src/export-mocks/router/index.ts\",\n      \"default\": \"./dist/export-mocks/router/index.js\"\n    },\n    \"./vite-plugin\": {\n      \"types\": \"./dist/vite-plugin/index.d.ts\",\n      \"code\": \"./src/vite-plugin/index.ts\",\n      \"default\": \"./dist/vite-plugin/index.js\"\n    }\n  },\n  \"main\": \"dist/index.js\",\n  \"module\": \"dist/index.mjs\",\n  \"types\": \"dist/index.d.ts\",\n  \"files\": [\n    \"dist/**/*\",\n    \"template/cli/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/builder-vite\": \"workspace:*\",\n    \"@storybook/react\": \"workspace:*\",\n    \"@storybook/react-vite\": \"workspace:*\",\n    \"styled-jsx\": \"5.1.6\",\n    \"vite-plugin-storybook-nextjs\": \"^3.2.4\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.19.1\",\n    \"lilconfig\": \"^3.0.0\",\n    \"next\": \"^15.2.3\",\n    \"postcss-load-config\": \"^6.0.1\",\n    \"semver\": \"^7.7.3\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"next\": \"^14.1.0 || ^15.0.0 || ^16.0.0\",\n    \"react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"storybook\": \"workspace:^\",\n    \"vite\": \"^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0\"\n  },\n  \"peerDependenciesMeta\": {\n    \"typescript\": {\n      \"optional\": true\n    }\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/project.json",
    "content": "{\n  \"name\": \"nextjs-vite\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/config/preview.ts",
    "content": "import { setConfig } from 'next/config';\n\nsetConfig(process.env.__NEXT_RUNTIME_CONFIG);\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/export-mocks/cache/index.ts",
    "content": "import { fn } from 'storybook/test';\n\n// biome-ignore lint/suspicious/noExplicitAny: <explanation>\ntype Callback = (...args: any[]) => Promise<any>;\n\n// mock utilities/overrides (as of Next v14.2.0)\nconst revalidatePath = fn().mockName('next/cache::revalidatePath');\nconst revalidateTag = fn().mockName('next/cache::revalidateTag');\nconst unstable_cache = fn()\n  .mockName('next/cache::unstable_cache')\n  .mockImplementation((cb: Callback) => cb);\nconst unstable_noStore = fn().mockName('next/cache::unstable_noStore');\n\nconst cacheExports = {\n  unstable_cache,\n  revalidateTag,\n  revalidatePath,\n  unstable_noStore,\n};\n\nexport default cacheExports;\nexport { unstable_cache, revalidateTag, revalidatePath, unstable_noStore };\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/export-mocks/headers/cookies.ts",
    "content": "// We need this import to be a singleton, and because it's used in multiple entrypoints\n// both in ESM and CJS, importing it via the package name instead of having a local import\n// is the only way to achieve it actually being a singleton\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore we must ignore types here as during compilation they are not generated yet\nimport { headers } from '@storybook/nextjs-vite/headers.mock';\n\nimport { RequestCookies } from 'next/dist/compiled/@edge-runtime/cookies/index.js';\nimport { fn } from 'storybook/test';\n\nclass RequestCookiesMock extends RequestCookies {\n  get = fn(super.get.bind(this)).mockName('next/headers::cookies().get');\n\n  getAll = fn(super.getAll.bind(this)).mockName('next/headers::cookies().getAll');\n\n  has = fn(super.has.bind(this)).mockName('next/headers::cookies().has');\n\n  set = fn(super.set.bind(this)).mockName('next/headers::cookies().set');\n\n  delete = fn(super.delete.bind(this)).mockName('next/headers::cookies().delete');\n}\n\nlet requestCookiesMock: RequestCookiesMock;\n\nexport const cookies = fn(() => {\n  if (!requestCookiesMock) {\n    requestCookiesMock = new RequestCookiesMock(headers());\n  }\n  return requestCookiesMock;\n}).mockName('next/headers::cookies()');\n\nconst originalRestore = cookies.mockRestore.bind(null);\n\n// will be called automatically by the test loader\ncookies.mockRestore = () => {\n  originalRestore();\n  headers.mockRestore();\n  requestCookiesMock = new RequestCookiesMock(headers());\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/export-mocks/headers/headers.ts",
    "content": "import { HeadersAdapter } from 'next/dist/server/web/spec-extension/adapters/headers.js';\nimport { fn } from 'storybook/test';\n\nclass HeadersAdapterMock extends HeadersAdapter {\n  constructor() {\n    super({});\n  }\n\n  append = fn(super.append.bind(this)).mockName('next/headers::headers().append');\n\n  delete = fn(super.delete.bind(this)).mockName('next/headers::headers().delete');\n\n  get = fn(super.get.bind(this)).mockName('next/headers::headers().get');\n\n  has = fn(super.has.bind(this)).mockName('next/headers::headers().has');\n\n  set = fn(super.set.bind(this)).mockName('next/headers::headers().set');\n\n  forEach = fn(super.forEach.bind(this)).mockName('next/headers::headers().forEach');\n\n  entries = fn(super.entries.bind(this)).mockName('next/headers::headers().entries');\n\n  keys = fn(super.keys.bind(this)).mockName('next/headers::headers().keys');\n\n  values = fn(super.values.bind(this)).mockName('next/headers::headers().values');\n}\n\nlet headersAdapterMock: HeadersAdapterMock;\n\nexport const headers = () => {\n  if (!headersAdapterMock) {\n    headersAdapterMock = new HeadersAdapterMock();\n  }\n  return headersAdapterMock;\n};\n\n// This fn is called by ./cookies to restore the headers in the right order\nheaders.mockRestore = () => {\n  headersAdapterMock = new HeadersAdapterMock();\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/export-mocks/headers/index.ts",
    "content": "import { draftMode as originalDraftMode } from 'next/dist/server/request/draft-mode.js';\nimport * as headers from 'next/dist/server/request/headers.js';\nimport { fn } from 'storybook/test';\n\n// re-exports of the actual module\nexport * from 'next/dist/server/request/headers.js';\n\n// mock utilities/overrides (as of Next v14.2.0)\nexport { headers } from './headers.ts';\nexport { cookies } from './cookies.ts';\n\n// passthrough mocks - keep original implementation but allow for spying\nconst draftMode = fn(originalDraftMode ?? (headers as any).draftMode).mockName('draftMode');\nexport { draftMode };\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/export-mocks/navigation/index.ts",
    "content": "import { NextjsRouterMocksNotAvailable } from 'storybook/internal/preview-errors';\n\nimport * as actual from 'next/dist/client/components/navigation.js';\nimport { RedirectStatusCode } from 'next/dist/client/components/redirect-status-code.js';\nimport { getRedirectError } from 'next/dist/client/components/redirect.js';\nimport type { Mock } from 'storybook/test';\nimport { fn } from 'storybook/test';\n\nlet navigationAPI: {\n  push: Mock;\n  replace: Mock;\n  forward: Mock;\n  back: Mock;\n  prefetch: Mock;\n  refresh: Mock;\n};\n\n/**\n * Creates a next/navigation router API mock. Used internally.\n *\n * @ignore\n * @internal\n */\nexport const createNavigation = (overrides: any) => {\n  const navigationActions = {\n    push: fn().mockName('next/navigation::useRouter().push'),\n    replace: fn().mockName('next/navigation::useRouter().replace'),\n    forward: fn().mockName('next/navigation::useRouter().forward'),\n    back: fn().mockName('next/navigation::useRouter().back'),\n    prefetch: fn().mockName('next/navigation::useRouter().prefetch'),\n    refresh: fn().mockName('next/navigation::useRouter().refresh'),\n  };\n\n  if (overrides) {\n    Object.keys(navigationActions).forEach((key) => {\n      if (key in overrides) {\n        (navigationActions as any)[key] = fn((...args: any[]) => {\n          return (overrides as any)[key](...args);\n        }).mockName(`useRouter().${key}`);\n      }\n    });\n  }\n\n  navigationAPI = navigationActions;\n\n  return navigationAPI;\n};\n\nexport const getRouter = () => {\n  if (!navigationAPI) {\n    throw new NextjsRouterMocksNotAvailable({\n      importType: 'next/navigation',\n    });\n  }\n\n  return navigationAPI;\n};\n\n// re-exports of the actual module\nexport * from 'next/dist/client/components/navigation.js';\n\n// mock utilities/overrides (as of Next v14.2.0)\nexport const redirect = fn(\n  (url: string, type: actual.RedirectType = actual.RedirectType.push): never => {\n    throw getRedirectError(url, type, RedirectStatusCode.SeeOther);\n  }\n).mockName('next/navigation::redirect');\n\nexport const permanentRedirect = fn(\n  (url: string, type: actual.RedirectType = actual.RedirectType.push): never => {\n    throw getRedirectError(url, type, RedirectStatusCode.SeeOther);\n  }\n).mockName('next/navigation::permanentRedirect');\n\n// passthrough mocks - keep original implementation but allow for spying\nexport const useSearchParams = fn(actual.useSearchParams).mockName(\n  'next/navigation::useSearchParams'\n);\nexport const usePathname = fn(actual.usePathname).mockName('next/navigation::usePathname');\nexport const useSelectedLayoutSegment = fn(actual.useSelectedLayoutSegment).mockName(\n  'next/navigation::useSelectedLayoutSegment'\n);\nexport const useSelectedLayoutSegments = fn(actual.useSelectedLayoutSegments).mockName(\n  'next/navigation::useSelectedLayoutSegments'\n);\nexport const useRouter = fn(actual.useRouter).mockName('next/navigation::useRouter');\nexport const useServerInsertedHTML = fn(actual.useServerInsertedHTML).mockName(\n  'next/navigation::useServerInsertedHTML'\n);\nexport const notFound = fn(actual.notFound).mockName('next/navigation::notFound');\n\n// Params, not exported by Next.js, is manually declared to avoid inference issues.\ninterface Params {\n  [key: string]: string | string[];\n}\nexport const useParams = fn<() => Params>(actual.useParams).mockName('next/navigation::useParams');\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/export-mocks/router/index.ts",
    "content": "import { NextjsRouterMocksNotAvailable } from 'storybook/internal/preview-errors';\n\nimport singletonRouter, * as originalRouter from 'next/dist/client/router.js';\nimport type { NextRouter, SingletonRouter } from 'next/router';\nimport type { Mock } from 'storybook/test';\nimport { fn } from 'storybook/test';\n\nconst defaultRouterState = {\n  route: '/',\n  asPath: '/',\n  basePath: '/',\n  pathname: '/',\n  query: {},\n  isFallback: false,\n  isLocaleDomain: false,\n  isReady: true,\n  isPreview: false,\n};\n\nlet routerAPI: {\n  push: Mock;\n  replace: Mock;\n  reload: Mock;\n  back: Mock;\n  forward: Mock;\n  prefetch: Mock;\n  beforePopState: Mock;\n  events: {\n    on: Mock;\n    off: Mock;\n    emit: Mock;\n  };\n} & typeof defaultRouterState;\n\n/**\n * Creates a next/router router API mock. Used internally.\n *\n * @ignore\n * @internal\n */\nexport const createRouter = (overrides: Partial<NextRouter>) => {\n  const routerActions: Partial<NextRouter> = {\n    push: fn((..._args: any[]) => {\n      return Promise.resolve(true);\n    }).mockName('next/router::useRouter().push'),\n    replace: fn((..._args: any[]) => {\n      return Promise.resolve(true);\n    }).mockName('next/router::useRouter().replace'),\n    reload: fn((..._args: any[]) => {}).mockName('next/router::useRouter().reload'),\n    back: fn((..._args: any[]) => {}).mockName('next/router::useRouter().back'),\n    forward: fn(() => {}).mockName('next/router::useRouter().forward'),\n    prefetch: fn((..._args: any[]) => {\n      return Promise.resolve();\n    }).mockName('next/router::useRouter().prefetch'),\n    beforePopState: fn((..._args: any[]) => {}).mockName('next/router::useRouter().beforePopState'),\n  };\n\n  const routerEvents: NextRouter['events'] = {\n    on: fn((..._args: any[]) => {}).mockName('next/router::useRouter().events.on'),\n    off: fn((..._args: any[]) => {}).mockName('next/router::useRouter().events.off'),\n    emit: fn((..._args: any[]) => {}).mockName('next/router::useRouter().events.emit'),\n  };\n\n  if (overrides) {\n    Object.keys(routerActions).forEach((key) => {\n      if (key in overrides) {\n        (routerActions as any)[key] = fn((...args: any[]) => {\n          return (overrides as any)[key](...args);\n        }).mockName(`useRouter().${key}`);\n      }\n    });\n  }\n\n  if (overrides?.events) {\n    Object.keys(routerEvents).forEach((key) => {\n      if (key in routerEvents) {\n        (routerEvents as any)[key] = fn((...args: any[]) => {\n          return (overrides.events as any)[key](...args);\n        }).mockName(`useRouter().events.${key}`);\n      }\n    });\n  }\n\n  routerAPI = {\n    ...defaultRouterState,\n    ...overrides,\n    ...routerActions,\n    // @ts-expect-error TODO improve typings\n    events: routerEvents,\n  };\n\n  // overwrite the singleton router from next/router\n  (singletonRouter as unknown as SingletonRouter).router = routerAPI as any;\n  (singletonRouter as unknown as SingletonRouter).readyCallbacks.forEach((cb) => cb());\n  (singletonRouter as unknown as SingletonRouter).readyCallbacks = [];\n\n  return routerAPI as unknown as NextRouter;\n};\n\nexport const getRouter = () => {\n  if (!routerAPI) {\n    throw new NextjsRouterMocksNotAvailable({\n      importType: 'next/router',\n    });\n  }\n\n  return routerAPI;\n};\n\n// re-exports of the actual module\nexport * from 'next/dist/client/router.js';\nexport default singletonRouter;\n\n// mock utilities/overrides (as of Next v14.2.0)\n// passthrough mocks - keep original implementation but allow for spying\nexport const useRouter = fn(originalRouter.useRouter).mockName('next/router::useRouter');\nexport const withRouter = fn(originalRouter.withRouter).mockName('next/router::withRouter');\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/find-postcss-config.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\nimport { createRequire } from 'node:module';\n\nimport { getProjectRoot } from 'storybook/internal/common';\nimport { IncompatiblePostCssConfigError } from 'storybook/internal/server-errors';\n\nimport config from 'lilconfig';\nimport postCssLoadConfig from 'postcss-load-config';\n\ntype Options = import('lilconfig').Options;\n\nconst require = createRequire(import.meta.url);\n\nasync function loader(filepath: string) {\n  return require(filepath);\n}\n\nconst withLoaders = (options: Options = {}) => {\n  const moduleName = 'postcss';\n\n  return {\n    ...options,\n    loaders: {\n      ...options.loaders,\n      '.cjs': loader,\n      '.cts': loader,\n      '.js': loader,\n      '.mjs': loader,\n      '.mts': loader,\n      '.ts': loader,\n    },\n    searchPlaces: [\n      ...(options.searchPlaces ?? []),\n      'package.json',\n      `.${moduleName}rc`,\n      `.${moduleName}rc.json`,\n      `.${moduleName}rc.ts`,\n      `.${moduleName}rc.cts`,\n      `.${moduleName}rc.mts`,\n      `.${moduleName}rc.js`,\n      `.${moduleName}rc.cjs`,\n      `.${moduleName}rc.mjs`,\n      `${moduleName}.config.ts`,\n      `${moduleName}.config.cts`,\n      `${moduleName}.config.mts`,\n      `${moduleName}.config.js`,\n      `${moduleName}.config.cjs`,\n      `${moduleName}.config.mjs`,\n    ],\n  } satisfies Options;\n};\n\n/**\n * Find PostCSS config file path (without loading the config)\n *\n * @param {String} path Config Path\n * @param {Object} options Config Options\n * @returns {Promise<string | null>} Config file path or null if not found\n */\nasync function postCssFindConfig(path: string, options: Options = {}) {\n  const result = await config.lilconfig('postcss', withLoaders(options)).search(path);\n\n  return result ? result.filepath : null;\n}\n\nexport { postCssLoadConfig };\n\n/**\n * Normalizes PostCSS configuration for NextJS compatibility.\n *\n * This function handles the incompatibility between NextJS's PostCSS plugin format and Storybook's\n * requirements. NextJS uses array format for plugins while Storybook expects object format.\n *\n * Process:\n *\n * 1. First attempts to load the config as-is\n * 2. If that fails due to \"Invalid PostCSS Plugin found\" error, modifies the config file to convert\n *    array format to object format (e.g., [\"@tailwindcss/postcss\"] becomes {\n *    \"@tailwindcss/postcss\": {} })\n * 3. Retries loading with the modified config\n *\n * @param searchPath - Directory path to search for PostCSS config\n * @returns Promise<boolean> - true if config loads successfully (or no config found), false if\n *   config exists but cannot be loaded\n * @throws {IncompatiblePostCssConfigError} - When config cannot be fixed automatically\n * @sideEffect Modifies the PostCSS config file on disk when fixing plugin format\n */ export const normalizePostCssConfig = async (searchPath: string): Promise<boolean> => {\n  const configPath = await postCssFindConfig(searchPath);\n  if (!configPath) {\n    return true;\n  }\n\n  let error: Error | undefined;\n\n  // First attempt: try loading config as-is\n  try {\n    await postCssLoadConfig({}, searchPath, { stopDir: getProjectRoot() });\n    return true; // Success!\n  } catch (e: unknown) {\n    if (e instanceof Error) {\n      error = e;\n    }\n  }\n\n  if (!error) {\n    return true;\n  }\n\n  // No config found is not an error we need to handle\n  if (error.message.includes('No PostCSS Config found')) {\n    return true;\n  }\n\n  // NextJS uses an incompatible format for PostCSS plugins, we make an attempt to fix it\n  if (error.message.includes('Invalid PostCSS Plugin found')) {\n    // Second attempt: try with modified config\n    const originalContent = await readFile(configPath, 'utf8');\n    try {\n      const modifiedContent = originalContent.replace(\n        'plugins: [\"@tailwindcss/postcss\"]',\n        'plugins: { \"@tailwindcss/postcss\": {} }'\n      );\n\n      // Write the modified content\n      await writeFile(configPath, modifiedContent, 'utf8');\n\n      // Retry loading the config\n      await postCssLoadConfig({}, searchPath, { stopDir: getProjectRoot() });\n      return true; // Success with modified config!\n    } catch (e: any) {\n      // We were unable to fix the config, so we change the file back to the original content\n      await writeFile(configPath, originalContent, 'utf8');\n      // and throw an error\n      throw new IncompatiblePostCssConfigError({ error });\n    }\n  }\n\n  return false;\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/head-manager/decorator.tsx",
    "content": "import * as React from 'react';\n\nimport HeadManagerProvider from './head-manager-provider.tsx';\n\nexport const HeadManagerDecorator = (Story: React.FC): React.ReactNode => {\n  return (\n    <HeadManagerProvider>\n      <Story />\n    </HeadManagerProvider>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/head-manager/head-manager-provider.tsx",
    "content": "import type { PropsWithChildren } from 'react';\nimport React, { useMemo } from 'react';\n\nimport initHeadManager from 'next/dist/client/head-manager.js';\nimport { HeadManagerContext } from 'next/dist/shared/lib/head-manager-context.shared-runtime.js';\n\ntype HeadManagerValue = {\n  updateHead?: ((state: JSX.Element[]) => void) | undefined;\n  mountedInstances?: Set<unknown>;\n  updateScripts?: ((state: any) => void) | undefined;\n  scripts?: any;\n  getIsSsr?: () => boolean;\n  appDir?: boolean | undefined;\n  nonce?: string | undefined;\n};\n\nconst HeadManagerProvider: React.FC<PropsWithChildren> = ({ children }) => {\n  const headManager: HeadManagerValue = useMemo(initHeadManager, []);\n  headManager.getIsSsr = () => false;\n\n  return <HeadManagerContext.Provider value={headManager}>{children}</HeadManagerContext.Provider>;\n};\n\nexport default HeadManagerProvider;\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/images/decorator.tsx",
    "content": "import * as React from 'react';\n\nimport type { Addon_StoryContext } from 'storybook/internal/types';\n\nimport { ImageContext } from 'sb-original/image-context';\n\nexport const ImageDecorator = (\n  Story: React.FC,\n  { parameters }: Addon_StoryContext\n): React.ReactNode => {\n  if (!parameters.nextjs?.image) {\n    return <Story />;\n  }\n\n  return (\n    <ImageContext.Provider value={parameters.nextjs.image}>\n      <Story />\n    </ImageContext.Provider>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/index.ts",
    "content": "import type { AddonTypes, InferTypes, PreviewAddon } from 'storybook/internal/csf';\nimport type { ProjectAnnotations } from 'storybook/internal/types';\n\nimport type { ReactPreview } from '@storybook/react';\nimport { __definePreview } from '@storybook/react';\nimport type { ReactTypes } from '@storybook/react';\n\nimport type vitePluginStorybookNextJs from 'vite-plugin-storybook-nextjs';\n\nimport * as nextPreview from './preview.tsx';\nimport type { NextJsTypes } from './types.ts';\n\nexport * from '@storybook/react';\n// @ts-expect-error (double exports)\nexport * from './portable-stories.ts';\nexport * from './types.ts';\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\ndeclare module '@storybook/nextjs-vite/vite-plugin' {\n  export const storybookNextJsPlugin: typeof vitePluginStorybookNextJs;\n}\n\nexport function definePreview<Addons extends PreviewAddon<never>[]>(\n  preview: { addons?: Addons } & ProjectAnnotations<ReactTypes & NextJsTypes & InferTypes<Addons>>\n): NextPreview<InferTypes<Addons>> {\n  // @ts-expect-error hard\n  return __definePreview({\n    ...preview,\n    addons: [nextPreview, ...(preview.addons ?? [])],\n  });\n}\n\nexport interface NextPreview<T extends AddonTypes> extends ReactPreview<NextJsTypes & T> {}\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/node/index.ts",
    "content": "import type { StorybookConfig } from '../types.ts';\n\nexport function defineMain(config: StorybookConfig) {\n  return config;\n}\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/portable-stories.ts",
    "content": "import type {\n  Args,\n  ComposedStoryFn,\n  NamedOrDefaultProjectAnnotations,\n  NormalizedProjectAnnotations,\n  ProjectAnnotations,\n  Store_CSFExports,\n  StoriesWithPartialProps,\n  StoryAnnotationsOrFn,\n} from 'storybook/internal/types';\n\nimport type { Meta, ReactRenderer } from '@storybook/react';\n\nimport {\n  composeConfigs,\n  composeStories as originalComposeStories,\n  composeStory as originalComposeStory,\n  setProjectAnnotations as originalSetProjectAnnotations,\n  setDefaultProjectAnnotations,\n} from 'storybook/preview-api';\n\n// ! ATTENTION: This needs to be a relative import so it gets prebundled. This is to avoid ESM issues in Nextjs + Jest setups\nimport { INTERNAL_DEFAULT_PROJECT_ANNOTATIONS as reactAnnotations } from '../../../renderers/react/src/portable-stories.tsx';\nimport * as nextJsAnnotations from './preview.tsx';\n\n/**\n * Function that sets the globalConfig of your storybook. The global config is the preview module of\n * your .storybook folder.\n *\n * It should be run a single time, so that your global config (e.g. decorators) is applied to your\n * stories when using `composeStories` or `composeStory`.\n *\n * Example:\n *\n * ```jsx\n * // setup-file.js\n * import { setProjectAnnotations } from '@storybook/nextjs-vite';\n * import projectAnnotations from './.storybook/preview';\n *\n * setProjectAnnotations(projectAnnotations);\n * ```\n *\n * @param projectAnnotations - E.g. (import projectAnnotations from '../.storybook/preview')\n */\nexport function setProjectAnnotations(\n  projectAnnotations:\n    | NamedOrDefaultProjectAnnotations<any>\n    | NamedOrDefaultProjectAnnotations<any>[]\n): NormalizedProjectAnnotations<ReactRenderer> {\n  setDefaultProjectAnnotations(INTERNAL_DEFAULT_PROJECT_ANNOTATIONS);\n  return originalSetProjectAnnotations(\n    projectAnnotations\n  ) as NormalizedProjectAnnotations<ReactRenderer>;\n}\n\n// This will not be necessary once we have auto preset loading\nconst INTERNAL_DEFAULT_PROJECT_ANNOTATIONS: ProjectAnnotations<ReactRenderer> = composeConfigs([\n  reactAnnotations,\n  nextJsAnnotations,\n]);\n\n/**\n * Function that will receive a story along with meta (e.g. a default export from a .stories file)\n * and optionally projectAnnotations e.g. (import * from '../.storybook/preview) and will return a\n * composed component that has all args/parameters/decorators/etc combined and applied to it.\n *\n * It's very useful for reusing a story in scenarios outside of Storybook like unit testing.\n *\n * Example:\n *\n * ```jsx\n * import { render } from '@testing-library/react';\n * import { composeStory } from '@storybook/nextjs-vite';\n * import Meta, { Primary as PrimaryStory } from './Button.stories';\n *\n * const Primary = composeStory(PrimaryStory, Meta);\n *\n * test('renders primary button with Hello World', () => {\n *   const { getByText } = render(<Primary>Hello world</Primary>);\n *   expect(getByText(/Hello world/i)).not.toBeNull();\n * });\n * ```\n *\n * @param story\n * @param componentAnnotations - E.g. (import Meta from './Button.stories')\n * @param [projectAnnotations] - E.g. (import * as projectAnnotations from '../.storybook/preview')\n *   this can be applied automatically if you use `setProjectAnnotations` in your setup files.\n * @param [exportsName] - In case your story does not contain a name and you want it to have a name.\n */\nexport function composeStory<TArgs extends Args = Args>(\n  story: StoryAnnotationsOrFn<ReactRenderer, TArgs>,\n  componentAnnotations: Meta<TArgs | any>,\n  projectAnnotations?: ProjectAnnotations<ReactRenderer>,\n  exportsName?: string\n): ComposedStoryFn<ReactRenderer, Partial<TArgs>> {\n  return originalComposeStory<ReactRenderer, TArgs>(\n    story as StoryAnnotationsOrFn<ReactRenderer, Args>,\n    componentAnnotations,\n    projectAnnotations,\n    globalThis.globalProjectAnnotations ?? INTERNAL_DEFAULT_PROJECT_ANNOTATIONS,\n    exportsName\n  );\n}\n\n/**\n * Function that will receive a stories import (e.g. `import * as stories from './Button.stories'`)\n * and optionally projectAnnotations (e.g. `import * from '../.storybook/preview`) and will return\n * an object containing all the stories passed, but now as a composed component that has all\n * args/parameters/decorators/etc combined and applied to it.\n *\n * It's very useful for reusing stories in scenarios outside of Storybook like unit testing.\n *\n * Example:\n *\n * ```jsx\n * import { render } from '@testing-library/react';\n * import { composeStories } from '@storybook/nextjs-vite';\n * import * as stories from './Button.stories';\n *\n * const { Primary, Secondary } = composeStories(stories);\n *\n * test('renders primary button with Hello World', () => {\n *   const { getByText } = render(<Primary>Hello world</Primary>);\n *   expect(getByText(/Hello world/i)).not.toBeNull();\n * });\n * ```\n *\n * @param csfExports - E.g. (import * as stories from './Button.stories')\n * @param [projectAnnotations] - E.g. (import * as projectAnnotations from '../.storybook/preview')\n *   this can be applied automatically if you use `setProjectAnnotations` in your setup files.\n */\nexport function composeStories<TModule extends Store_CSFExports<ReactRenderer, any>>(\n  csfExports: TModule,\n  projectAnnotations?: ProjectAnnotations<ReactRenderer>\n) {\n  // @ts-expect-error (Converted from ts-ignore)\n  const composedStories = originalComposeStories(csfExports, projectAnnotations, composeStory);\n\n  return composedStories as unknown as Omit<\n    StoriesWithPartialProps<ReactRenderer, TModule>,\n    keyof Store_CSFExports\n  >;\n}\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/preset.ts",
    "content": "// https://storybook.js.org/docs/react/addons/writing-presets\nimport { createRequire } from 'node:module';\nimport { dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { PresetProperty } from 'storybook/internal/types';\n\nimport type { StorybookConfigVite } from '@storybook/builder-vite';\nimport { viteFinal as reactViteFinal } from '@storybook/react-vite/preset';\n\nimport semver from 'semver';\n\nimport { normalizePostCssConfig } from './find-postcss-config.ts';\nimport type { FrameworkOptions } from './types.ts';\nimport { getNextjsVersion } from './utils.ts';\n\nconst require = createRequire(import.meta.url);\n\n// the ESM output of this package is broken, so I had to force it to use the CJS version it's shipping.\nconst vitePluginStorybookNextjs = require('vite-plugin-storybook-nextjs');\n\nexport const core: PresetProperty<'core'> = {\n  builder: import.meta.resolve('@storybook/builder-vite'),\n  renderer: import.meta.resolve('@storybook/react/preset'),\n};\n\nexport const previewAnnotations: PresetProperty<'previewAnnotations'> = (entry = []) => {\n  const annotations = [\n    ...entry,\n    fileURLToPath(import.meta.resolve('@storybook/nextjs-vite/preview')),\n  ];\n\n  const nextjsVersion = getNextjsVersion();\n  const isNext16orNewer = semver.gte(nextjsVersion, '16.0.0');\n\n  // TODO: Remove this once we only support Next.js v16 and above\n  if (!isNext16orNewer) {\n    annotations.push(fileURLToPath(import.meta.resolve('@storybook/nextjs-vite/config/preview')));\n  }\n\n  return annotations;\n};\n\nexport const optimizeViteDeps = [\n  '@storybook/nextjs-vite/navigation.mock',\n  '@storybook/nextjs-vite/router.mock',\n  '@storybook/nextjs-vite > styled-jsx',\n  '@storybook/nextjs-vite > styled-jsx/style',\n  '@opentelemetry/api',\n];\n\nexport const viteFinal: StorybookConfigVite['viteFinal'] = async (config, options) => {\n  const reactConfig = await reactViteFinal(config, options);\n\n  const inlineOptions = config.css?.postcss;\n  const searchPath = typeof inlineOptions === 'string' ? inlineOptions : config.root;\n\n  if (searchPath) {\n    await normalizePostCssConfig(searchPath);\n  }\n\n  const { nextConfigPath, image = {} } =\n    await options.presets.apply<FrameworkOptions>('frameworkOptions');\n\n  const nextDir = nextConfigPath ? dirname(nextConfigPath) : undefined;\n\n  const vitePluginOptions = {\n    image,\n    dir: nextDir,\n  };\n\n  return {\n    ...reactConfig,\n    resolve: {\n      ...(reactConfig?.resolve ?? {}),\n      alias: {\n        ...(reactConfig?.resolve?.alias ?? {}),\n        'styled-jsx': dirname(fileURLToPath(import.meta.resolve('styled-jsx/package.json'))),\n        'styled-jsx/style': fileURLToPath(import.meta.resolve('styled-jsx/style')),\n        'styled-jsx/style.js': fileURLToPath(import.meta.resolve('styled-jsx/style')),\n      },\n    },\n    plugins: [...(reactConfig?.plugins ?? []), vitePluginStorybookNextjs(vitePluginOptions)],\n  };\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/preview.tsx",
    "content": "import type * as React from 'react';\n\nimport type { Addon_DecoratorFunction, LoaderFunction } from 'storybook/internal/types';\n\nimport type { ReactRenderer } from '@storybook/react';\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore we must ignore types here as during compilation they are not generated yet\nimport { createNavigation } from '@storybook/nextjs-vite/navigation.mock';\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore we must ignore types here as during compilation they are not generated yet\nimport { createRouter } from '@storybook/nextjs-vite/router.mock';\n\nimport { isNextRouterError } from 'next/dist/client/components/is-next-router-error.js';\n\nimport { HeadManagerDecorator } from './head-manager/decorator.tsx';\nimport { ImageDecorator } from './images/decorator.tsx';\nimport { RouterDecorator } from './routing/decorator.tsx';\nimport { StyledJsxDecorator } from './styledJsx/decorator.tsx';\n\nfunction addNextHeadCount() {\n  const meta = document.createElement('meta');\n  meta.name = 'next-head-count';\n  meta.content = '0';\n  document.head.appendChild(meta);\n}\n\nfunction isAsyncClientComponentError(error: unknown) {\n  return (\n    typeof error === 'string' &&\n    (error.includes('Only Server Components can be async at the moment.') ||\n      error.includes('A component was suspended by an uncached promise.') ||\n      error.includes('async/await is not yet supported in Client Components'))\n  );\n}\naddNextHeadCount();\n\n// Copying Next patch of console.error:\n// https://github.com/vercel/next.js/blob/a74deb63e310df473583ab6f7c1783bc609ca236/packages/next/src/client/app-index.tsx#L15\nconst origConsoleError = globalThis.console.error;\nglobalThis.console.error = (...args: unknown[]) => {\n  const error = args[0];\n  if (isNextRouterError(error) || isAsyncClientComponentError(error)) {\n    return;\n  }\n  origConsoleError.apply(globalThis.console, args);\n};\n\nglobalThis.addEventListener('error', (ev: WindowEventMap['error']): void => {\n  if (isNextRouterError(ev.error) || isAsyncClientComponentError(ev.error)) {\n    ev.preventDefault();\n    return;\n  }\n});\n\n// Type assertion to handle the decorator type mismatch\nconst asDecorator = (decorator: (Story: React.FC, context?: any) => React.ReactNode) =>\n  decorator as unknown as Addon_DecoratorFunction<ReactRenderer>;\n\nexport const decorators: Addon_DecoratorFunction<ReactRenderer>[] = [\n  asDecorator(StyledJsxDecorator),\n  asDecorator(ImageDecorator),\n  asDecorator(RouterDecorator),\n  asDecorator(HeadManagerDecorator),\n];\n\nexport const loaders: LoaderFunction<ReactRenderer> = async ({ globals, parameters }) => {\n  const { router, appDirectory } = parameters.nextjs ?? {};\n  if (appDirectory) {\n    createNavigation(router);\n  } else {\n    createRouter({\n      locale: globals.locale,\n      ...(router as Record<string, unknown>),\n    });\n  }\n};\n\nexport const parameters = {\n  docs: {\n    source: {\n      excludeDecorators: true,\n    },\n  },\n  react: {\n    rootOptions: {\n      onCaughtError(error: unknown) {\n        if (isNextRouterError(error)) {\n          return;\n        }\n        console.error(error);\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/routing/app-router-provider.tsx",
    "content": "import React, { useMemo } from 'react';\n\n// We need this import to be a singleton, and because it's used in multiple entrypoints\n// both in ESM and CJS, importing it via the package name instead of having a local import\n// is the only way to achieve it actually being a singleton\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore we must ignore types here as during compilation they are not generated yet\nimport { getRouter } from '@storybook/nextjs-vite/navigation.mock';\n\nimport type { FlightRouterState } from 'next/dist/server/app-render/types';\nimport {\n  AppRouterContext,\n  GlobalLayoutRouterContext,\n  LayoutRouterContext,\n} from 'next/dist/shared/lib/app-router-context.shared-runtime.js';\nimport {\n  PathParamsContext,\n  PathnameContext,\n  SearchParamsContext,\n} from 'next/dist/shared/lib/hooks-client-context.shared-runtime.js';\nimport { PAGE_SEGMENT_KEY } from 'next/dist/shared/lib/segment.js';\n\nimport type { RouteParams } from './types.tsx';\n\n// Using an inline type so we can support Next 14 and lower\n// from https://github.com/vercel/next.js/blob/v15.0.3/packages/next/src/server/request/params.ts#L25\ntype Params = Record<string, string | Array<string> | undefined>;\n\ntype AppRouterProviderProps = {\n  routeParams: RouteParams;\n};\n\n// Since Next 14.2.x\n// https://github.com/vercel/next.js/pull/60708/files#diff-7b6239af735eba0c401e1a0db1a04dd4575c19a031934f02d128cf3ac813757bR106\nfunction getSelectedParams(currentTree: FlightRouterState, params: Params = {}): Params {\n  const parallelRoutes = currentTree[1];\n\n  for (const parallelRoute of Object.values(parallelRoutes)) {\n    const segment = parallelRoute[0];\n    const isDynamicParameter = Array.isArray(segment);\n    const segmentValue = isDynamicParameter ? segment[1] : segment;\n\n    if (!segmentValue || segmentValue.startsWith(PAGE_SEGMENT_KEY)) {\n      continue;\n    }\n\n    // Ensure catchAll and optional catchall are turned into an array\n    const isCatchAll = isDynamicParameter && (segment[2] === 'c' || segment[2] === 'oc');\n\n    if (isCatchAll) {\n      params[segment[0]] = Array.isArray(segment[1]) ? segment[1] : segment[1].split('/');\n    } else if (isDynamicParameter) {\n      params[segment[0]] = segment[1];\n    }\n\n    params = getSelectedParams(parallelRoute, params);\n  }\n\n  return params;\n}\n\nconst getParallelRoutes = (segmentsList: Array<string>): FlightRouterState => {\n  const segment = segmentsList.shift();\n\n  if (segment) {\n    return [segment, { children: getParallelRoutes(segmentsList) }];\n  }\n\n  return [] as any;\n};\n\nexport const AppRouterProvider: React.FC<React.PropsWithChildren<AppRouterProviderProps>> = ({\n  children,\n  routeParams,\n}) => {\n  const { pathname, query, segments = [] } = routeParams;\n\n  const tree: FlightRouterState = [pathname, { children: getParallelRoutes([...segments]) }];\n  const pathParams = useMemo(() => {\n    const params: Params = {};\n    const currentSegments = routeParams.segments;\n\n    if (currentSegments) {\n      if (Array.isArray(currentSegments)) {\n        for (const segmentEntry of currentSegments) {\n          if (\n            Array.isArray(segmentEntry) &&\n            segmentEntry.length === 2 &&\n            typeof segmentEntry[0] === 'string'\n          ) {\n            const key: string = segmentEntry[0];\n            const value = segmentEntry[1] as string | string[] | undefined;\n            params[key] = value;\n          }\n        }\n      } else if (typeof currentSegments === 'object' && !Array.isArray(currentSegments)) {\n        const segmentObject = currentSegments as Record<string, string | string[] | undefined>;\n        for (const key in segmentObject) {\n          if (Object.prototype.hasOwnProperty.call(segmentObject, key)) {\n            params[key] = segmentObject[key];\n          }\n        }\n      }\n    }\n    return params;\n  }, [routeParams.segments]);\n\n  const newLazyCacheNode = {\n    lazyData: null,\n    rsc: null,\n    prefetchRsc: null,\n    head: null,\n    prefetchHead: null,\n    parallelRoutes: new Map(),\n    loading: null,\n  };\n\n  // https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/app-router.tsx#L436\n  return (\n    <PathParamsContext.Provider value={pathParams}>\n      <PathnameContext.Provider value={pathname}>\n        <SearchParamsContext.Provider value={new URLSearchParams(query)}>\n          <GlobalLayoutRouterContext.Provider\n            value={{\n              // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n              // @ts-ignore (Only available in Next.js >= v15.1.1)\n              changeByServerResponse() {\n                // NOOP\n              },\n              buildId: 'storybook',\n              tree,\n              focusAndScrollRef: {\n                apply: false,\n                hashFragment: null,\n                segmentPaths: [tree],\n                onlyHashChange: false,\n              },\n              nextUrl: pathname,\n            }}\n          >\n            <AppRouterContext.Provider value={getRouter()}>\n              <LayoutRouterContext.Provider\n                value={{\n                  // TODO Remove when dropping Next.js < v15.1.1\n                  childNodes: new Map(),\n                  tree,\n                  // TODO END\n\n                  // START Next.js v15.2 support\n                  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n                  // @ts-ignore Only available in Next.js >= v15.1.1\n                  parentTree: tree,\n                  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n                  // @ts-ignore Only available in Next.js >= v15.1.1\n                  parentCacheNode: newLazyCacheNode,\n                  // END\n                  url: pathname,\n                  loading: null,\n                }}\n              >\n                {children}\n              </LayoutRouterContext.Provider>\n            </AppRouterContext.Provider>\n          </GlobalLayoutRouterContext.Provider>\n        </SearchParamsContext.Provider>\n      </PathnameContext.Provider>\n    </PathParamsContext.Provider>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/routing/decorator.tsx",
    "content": "import * as React from 'react';\n\nimport type { Addon_StoryContext } from 'storybook/internal/types';\n\nimport { RedirectBoundary } from 'next/dist/client/components/redirect-boundary.js';\n\nimport { AppRouterProvider } from './app-router-provider.tsx';\nimport { PageRouterProvider } from './page-router-provider.tsx';\nimport type { NextAppDirectory, RouteParams } from './types.tsx';\n\nconst defaultRouterParams: RouteParams = {\n  pathname: '/',\n  query: {},\n};\n\nexport const RouterDecorator = (\n  Story: React.FC,\n  { parameters }: Addon_StoryContext\n): React.ReactNode => {\n  const nextAppDirectory =\n    (parameters.nextjs?.appDirectory as NextAppDirectory | undefined) ?? false;\n\n  if (nextAppDirectory) {\n    if (!AppRouterProvider) {\n      return null;\n    }\n    return (\n      <AppRouterProvider\n        routeParams={{\n          ...defaultRouterParams,\n          ...parameters.nextjs?.navigation,\n        }}\n      >\n        {/*\n        The next.js RedirectBoundary causes flashing UI when used client side.\n        Possible use the implementation of the PR: https://github.com/vercel/next.js/pull/49439\n        Or wait for next to solve this on their side.\n        */}\n        <RedirectBoundary>\n          <Story />\n        </RedirectBoundary>\n      </AppRouterProvider>\n    );\n  }\n\n  return (\n    <PageRouterProvider>\n      <Story />\n    </PageRouterProvider>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/routing/page-router-provider.tsx",
    "content": "import type { PropsWithChildren } from 'react';\nimport React from 'react';\n\n// We need this import to be a singleton, and because it's used in multiple entrypoints\n// both in ESM and CJS, importing it via the package name instead of having a local import\n// is the only way to achieve it actually being a singleton\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore we must ignore types here as during compilation they are not generated yet\nimport { getRouter } from '@storybook/nextjs-vite/router.mock';\n\nimport { RouterContext } from 'next/dist/shared/lib/router-context.shared-runtime.js';\n\nexport const PageRouterProvider: React.FC<PropsWithChildren> = ({ children }) => (\n  <RouterContext.Provider value={getRouter()}>{children}</RouterContext.Provider>\n);\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/routing/types.tsx",
    "content": "export type RouteParams = {\n  pathname: string;\n  query: Record<string, string>;\n  [key: string]: any;\n};\n\nexport type NextAppDirectory = boolean;\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/styledJsx/decorator.tsx",
    "content": "import * as React from 'react';\n\nimport { StyleRegistry } from 'styled-jsx';\n\nexport const StyledJsxDecorator = (Story: React.FC): React.ReactNode => (\n  <StyleRegistry>\n    <Story />\n  </StyleRegistry>\n);\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/types.ts",
    "content": "import type { CompatibleString } from 'storybook/internal/types';\n\nimport type { BuilderOptions } from '@storybook/builder-vite';\nimport type { StorybookConfig as StorybookConfigReactVite } from '@storybook/react-vite';\n\nimport type { NextRouter } from 'next/router';\n\ntype FrameworkName = CompatibleString<'@storybook/nextjs-vite'>;\ntype BuilderName = CompatibleString<'@storybook/builder-vite'>;\n\nexport type FrameworkOptions = {\n  /** The path to the Next.js configuration file. */\n  nextConfigPath?: string;\n  image?: {\n    includeFiles?: string[];\n    excludeFiles?: string[];\n  };\n  builder?: BuilderOptions;\n};\n\ntype StorybookConfigFramework = {\n  framework:\n    | FrameworkName\n    | {\n        name: FrameworkName;\n        options: FrameworkOptions;\n      };\n  core?: StorybookConfigReactVite['core'] & {\n    builder?:\n      | BuilderName\n      | {\n          name: BuilderName;\n          options: BuilderOptions;\n        };\n  };\n};\n\n/** The interface for Storybook configuration in `main.ts` files. */\nexport type StorybookConfig = Omit<StorybookConfigReactVite, keyof StorybookConfigFramework> &\n  StorybookConfigFramework;\n\nexport interface NextJsParameters {\n  /**\n   * Next.js framework configuration\n   *\n   * @see https://storybook.js.org/docs/get-started/frameworks/nextjs-vite\n   */\n  nextjs?: {\n    /**\n     * Enable App Directory features If your story imports components that use next/navigation, you\n     * need to set this parameter to true\n     */\n    appDirectory?: boolean;\n\n    /**\n     * Next.js navigation configuration when using `next/navigation`. Please note that it can only\n     * be used in components/pages in the app directory.\n     */\n    navigation?: Partial<NextRouter>;\n\n    /** Next.js router configuration */\n    router?: Partial<NextRouter>;\n  };\n}\n\nexport interface NextJsTypes {\n  parameters: NextJsParameters;\n}\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/typings.d.ts",
    "content": "declare module 'sb-original/image-context' {\n  import type { StaticImport } from 'next/dist/shared/lib/get-img-props';\n  import type { Context } from 'next/dist/compiled/react';\n  import type { ImageProps } from 'next/image';\n  import type { ImageProps as LegacyImageProps } from 'next/legacy/image';\n\n  export const ImageContext: Context<\n    Partial<\n      Omit<ImageProps, 'src'> & {\n        src: string | StaticImport;\n      }\n    > &\n      Omit<LegacyImageProps, 'src'>\n  >;\n}\n\ndeclare module 'sb-original/default-loader' {\n  import type { ImageLoaderProps } from 'next/image';\n\n  export const defaultLoader: (props: ImageLoaderProps) => string;\n}\n\ndeclare module 'next/dist/compiled/react' {\n  import * as React from 'react';\n  export default React;\n  export type Context<T> = React.Context<T>;\n  export function createContext<T>(\n    // If you thought this should be optional, see\n    // https://github.com/DefinitelyTyped/DefinitelyTyped/pull/24509#issuecomment-382213106\n    defaultValue: T\n  ): Context<T>;\n}\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/utils.ts",
    "content": "import { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { resolvePackageDir } from '../../../core/src/shared/utils/module.ts';\n\nexport const getNextjsVersion = (): string =>\n  JSON.parse(readFileSync(join(resolvePackageDir('next'), 'package.json'), 'utf8')).version;\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/src/vite-plugin/index.ts",
    "content": "import { createRequire } from 'node:module';\n\nconst require = createRequire(import.meta.url);\n\nconst vitePluginStorybookNextjs = require('vite-plugin-storybook-nextjs');\n\nexport const storybookNextJsPlugin = vitePluginStorybookNextjs;\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/cli/.eslintrc.json",
    "content": "{\n  \"rules\": {\n    \"import/extensions\": \"off\",\n    \"react/no-unknown-property\": \"off\"\n  }\n}\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/cli/js/Button.jsx",
    "content": "import PropTypes from 'prop-types';\n\nimport './button.css';\n\n/** Primary UI component for user interaction */\nexport const Button = ({ primary, backgroundColor, size, label, ...props }) => {\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n  return (\n    <button\n      type=\"button\"\n      className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n      {...props}\n    >\n      {label}\n      <style jsx>{`\n        button {\n          background-color: ${backgroundColor};\n        }\n      `}</style>\n    </button>\n  );\n};\n\nButton.propTypes = {\n  /** Is this the principal call to action on the page? */\n  primary: PropTypes.bool,\n  /** What background color to use */\n  backgroundColor: PropTypes.string,\n  /** How large should the button be? */\n  size: PropTypes.oneOf(['small', 'medium', 'large']),\n  /** Button contents */\n  label: PropTypes.string.isRequired,\n  /** Optional click handler */\n  onClick: PropTypes.func,\n};\n\nButton.defaultProps = {\n  backgroundColor: null,\n  primary: false,\n  size: 'medium',\n  onClick: undefined,\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/cli/js/Button.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport { Button } from './Button';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export\nexport default {\n  title: 'Example/Button',\n  component: Button,\n  parameters: {\n    // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout\n    layout: 'centered',\n  },\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  // More on argTypes: https://storybook.js.org/docs/api/argtypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onClick: fn() },\n};\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/cli/js/Configure.mdx",
    "content": "import { Meta } from \"@storybook/addon-docs/blocks\";\nimport Image from \"next/image\";\n\nimport Github from \"./assets/github.svg\";\nimport Discord from \"./assets/discord.svg\";\nimport Youtube from \"./assets/youtube.svg\";\nimport Tutorials from \"./assets/tutorials.svg\";\nimport Styling from \"./assets/styling.png\";\nimport Context from \"./assets/context.png\";\nimport Assets from \"./assets/assets.png\";\nimport Docs from \"./assets/docs.png\";\nimport Share from \"./assets/share.png\";\nimport FigmaPlugin from \"./assets/figma-plugin.png\";\nimport Testing from \"./assets/testing.png\";\nimport Accessibility from \"./assets/accessibility.png\";\nimport Theming from \"./assets/theming.png\";\nimport AddonLibrary from \"./assets/addon-library.png\";\n\nexport const RightArrow = () => <svg \n    viewBox=\"0 0 14 14\" \n    width=\"8px\" \n    height=\"14px\" \n    style={{ \n      marginLeft: '4px',\n      display: 'inline-block',\n      shapeRendering: 'inherit',\n      verticalAlign: 'middle',\n      fill: 'currentColor',\n      'path fill': 'currentColor'\n    }}\n>\n  <path d=\"m11.1 7.35-5.5 5.5a.5.5 0 0 1-.7-.7L10.04 7 4.9 1.85a.5.5 0 1 1 .7-.7l5.5 5.5c.2.2.2.5 0 .7Z\" />\n</svg>\n\n<Meta title=\"Configure your project\" />\n\n<div className=\"sb-container\">\n  <div className='sb-section-title'>\n    # Configure your project\n\n    Because Storybook works separately from your app, you'll need to configure it for your specific stack and setup. Below, explore guides for configuring Storybook with popular frameworks and tools. If you get stuck, learn how you can ask for help from our community.\n  </div>\n  <div className=\"sb-section\">\n    <div className=\"sb-section-item\">\n      <Image\n        src={Styling}\n        alt=\"A wall of logos representing different styling technologies\"\n        width={0}\n        height={0}\n        style={{ width: '100%', height: 'auto' }}\n      />\n      <h4 className=\"sb-section-item-heading\">Add styling and CSS</h4>\n      <p className=\"sb-section-item-paragraph\">Like with web applications, there are many ways to include CSS within Storybook. Learn more about setting up styling within Storybook.</p>\n      <a\n        className=\"sb-action-link\"\n        href=\"https://storybook.js.org/docs/configure/styling-and-css/?renderer=react&ref=configure\"\n        target=\"_blank\"\n      >Learn more<RightArrow /></a>\n    </div>\n    <div className=\"sb-section-item\">\n      <Image \n        width={0}\n        height={0}\n        style={{ width: '100%', height: 'auto' }}\n        src={Context}\n        alt=\"An abstraction representing the composition of data for a component\"\n      />\n      <h4 className=\"sb-section-item-heading\">Provide context and mocking</h4>\n      <p className=\"sb-section-item-paragraph\">Often when a story doesn't render, it's because your component is expecting a specific environment or context (like a theme provider) to be available.</p>\n      <a\n        className=\"sb-action-link\"\n        href=\"https://storybook.js.org/docs/writing-stories/decorators/?renderer=react&ref=configure#context-for-mocking\"\n        target=\"_blank\"\n      >Learn more<RightArrow /></a>\n    </div>\n    <div className=\"sb-section-item\">\n      <Image \n        width={0}\n        height={0}\n        style={{ width: '100%', height: 'auto' }} \n        src={Assets} \n        alt=\"A representation of typography and image assets\" \n      />\n      <div>\n        <h4 className=\"sb-section-item-heading\">Load assets and resources</h4>\n        <p className=\"sb-section-item-paragraph\">To link static files (like fonts) to your projects and stories, use the\n        `staticDirs` configuration option to specify folders to load when\n        starting Storybook.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/configure/images-and-assets/?renderer=react&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n    </div>\n  </div>\n</div>\n<div className=\"sb-container\">\n  <div className='sb-section-title'>\n    # Do more with Storybook\n\n    Now that you know the basics, let's explore other parts of Storybook that will improve your experience. This list is just to get you started. You can customise Storybook in many ways to fit your needs.\n  </div>\n\n  <div className=\"sb-section\">\n    <div className=\"sb-features-grid\">\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={Docs} \n          alt=\"A screenshot showing the autodocs tag being set, pointing a docs page being generated\" \n        />\n        <h4 className=\"sb-section-item-heading\">Autodocs</h4>\n        <p className=\"sb-section-item-paragraph\">Auto-generate living,\n          interactive reference documentation from your components and stories.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/writing-docs/autodocs/?renderer=react&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={Share} \n          alt=\"A browser window showing a Storybook being published to a chromatic.com URL\" \n        />\n        <h4 className=\"sb-section-item-heading\">Publish to Chromatic</h4>\n        <p className=\"sb-section-item-paragraph\">Publish your Storybook to review and collaborate with your entire team.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/sharing/publish-storybook/?renderer=react&ref=configure#publish-storybook-with-chromatic\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={FigmaPlugin} \n          alt=\"Windows showing the Storybook plugin in Figma\" \n        />\n        <h4 className=\"sb-section-item-heading\">Figma Plugin</h4>\n        <p className=\"sb-section-item-paragraph\">Embed your stories into Figma to cross-reference the design and live\n          implementation in one place.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/sharing/design-integrations/?renderer=react&ref=configure#embed-storybook-in-figma-with-the-plugin\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={Testing} \n          alt=\"Screenshot of tests passing and failing\" \n        />\n        <h4 className=\"sb-section-item-heading\">Testing</h4>\n        <p className=\"sb-section-item-paragraph\">Use stories to test a component in all its variations, no matter how\n          complex.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/writing-tests/?renderer=react&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={Accessibility} \n          alt=\"Screenshot of accessibility tests passing and failing\" \n        />\n        <h4 className=\"sb-section-item-heading\">Accessibility</h4>\n        <p className=\"sb-section-item-paragraph\">Automatically test your components for a11y issues as you develop.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/writing-tests/accessibility-testing/?renderer=react&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={Theming} \n          alt=\"Screenshot of Storybook in light and dark mode\" \n        />\n        <h4 className=\"sb-section-item-heading\">Theming</h4>\n        <p className=\"sb-section-item-paragraph\">Theme Storybook's UI to personalize it to your project.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/configure/theming/?renderer=react&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n    </div>\n  </div>\n</div>\n<div className='sb-addon'>\n  <div className='sb-addon-text'>\n    <h4>Addons</h4>\n    <p className=\"sb-section-item-paragraph\">Integrate your tools with Storybook to connect workflows.</p>\n    <a\n        className=\"sb-action-link\"\n        href=\"https://storybook.js.org/addons/?ref=configure\"\n        target=\"_blank\"\n      >Discover all addons<RightArrow /></a>\n  </div>\n  <div className='sb-addon-img'>\n    <Image \n      width={650}\n      height={347}\n      src={AddonLibrary} \n      alt=\"Integrate your tools with Storybook to connect workflows.\" \n    />\n  </div>\n</div>\n\n<div className=\"sb-section sb-socials\">\n    <div className=\"sb-section-item\">\n      <Image \n        width={32}\n        height={32}\n        layout=\"fixed\"\n        src={Github} \n        alt=\"Github logo\" \n        className=\"sb-explore-image\"\n      />\n      Join our contributors building the future of UI development.\n\n      <a\n        className=\"sb-action-link\"\n        href=\"https://github.com/storybookjs/storybook\"\n        target=\"_blank\"\n      >Star on GitHub<RightArrow /></a>\n    </div>\n    <div className=\"sb-section-item\">\n      <Image \n        width={33}\n        height={32}\n        layout=\"fixed\"\n        src={Discord} \n        alt=\"Discord logo\" \n        className=\"sb-explore-image\"\n      />\n      <div>\n        Get support and chat with frontend developers.\n\n        <a\n          className=\"sb-action-link\"\n          href=\"https://discord.gg/storybook\"\n          target=\"_blank\"\n        >Join Discord server<RightArrow /></a>\n      </div>\n    </div>\n    <div className=\"sb-section-item\">\n      <Image \n        width={32}\n        height={32}\n        layout=\"fixed\"\n        src={Youtube} \n        alt=\"Youtube logo\" \n        className=\"sb-explore-image\"\n      />\n      <div>\n        Watch tutorials, feature previews and interviews.\n\n        <a\n          className=\"sb-action-link\"\n          href=\"https://www.youtube.com/@chromaticui\"\n          target=\"_blank\"\n        >Watch on YouTube<RightArrow /></a>\n      </div>\n    </div>\n    <div className=\"sb-section-item\">\n      <Image \n        width={33}\n        height={32}\n        layout=\"fixed\"\n        src={Tutorials} \n        alt=\"A book\" \n        className=\"sb-explore-image\"\n      />\n      <p>Follow guided walkthroughs on for key workflows.</p>\n\n      <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/tutorials/?ref=configure\"\n          target=\"_blank\"\n        >Discover tutorials<RightArrow /></a>\n    </div>\n</div>\n\n<style>\n  {`\n  .sb-container {\n    margin-bottom: 48px;\n  }\n\n  .sb-section {\n    width: 100%;\n    display: flex;\n    flex-direction: row;\n    gap: 20px;\n  }\n\n  img {\n    object-fit: cover;\n  }\n\n  .sb-section-title {\n    margin-bottom: 32px;\n  }\n\n  .sb-section a:not(h1 a, h2 a, h3 a) {\n    font-size: 14px;\n  }\n\n  .sb-section-item, .sb-grid-item {\n    flex: 1;\n    display: flex;\n    flex-direction: column;\n  }\n\n  .sb-section-item-heading {\n    padding-top: 20px !important;\n    padding-bottom: 5px !important;\n    margin: 0 !important;\n  }\n  .sb-section-item-paragraph {\n    margin: 0;\n    padding-bottom: 10px;\n  }\n\n  .sb-action-link {\n    text-decoration: none;\n  }\n\n  .sb-action-link:hover, .sb-action-link:focus {\n    text-decoration: underline;\n    text-decoration-thickness: 0.03125rem;\n    text-underline-offset: 0.11em;\n  }\n\n  .sb-chevron {\n    margin-left: 5px;\n  }\n\n  .sb-features-grid {\n    display: grid;\n    grid-template-columns: repeat(2, 1fr);\n    grid-gap: 32px 20px;\n  }\n\n  .sb-socials {\n    display: grid;\n    grid-template-columns: repeat(4, 1fr);\n  }\n\n  .sb-socials p {\n    margin-bottom: 10px;\n  }\n\n  .sb-explore-image {\n    max-height: 32px;\n    align-self: flex-start;\n  }\n\n  .sb-addon {\n    width: 100%;\n    display: flex;\n    align-items: center;\n    position: relative;\n    background-color: #EEF3F8;\n    border-radius: 5px;\n    border: 1px solid rgba(0, 0, 0, 0.05);\n    background: #EEF3F8;\n    height: 180px;\n    margin-bottom: 48px;\n    overflow: hidden;\n  }\n\n  .sb-addon-text {\n    padding-left: 48px;\n    max-width: 240px;\n  }\n\n  .sb-addon-text h4 {\n    padding-top: 0px;\n  }\n\n  .sb-addon-img {\n    position: absolute;\n    left: 345px;\n    top: 0;\n    height: 100%;\n    width: 200%;\n    overflow: hidden;\n  }\n\n  .sb-addon-img img {\n    width: 650px;\n    transform: rotate(-15deg);\n    margin-left: 40px;\n    margin-top: -72px;\n    box-shadow: 0 0 1px rgba(255, 255, 255, 0);\n    backface-visibility: hidden;\n  }\n\n  @media screen and (max-width: 800px) {\n    .sb-addon-img {\n      left: 300px;\n    }\n  }\n\n  @media screen and (max-width: 600px) {\n    .sb-section {\n      flex-direction: column;\n    }\n\n    .sb-features-grid {\n      grid-template-columns: repeat(1, 1fr);\n    }\n\n    .sb-socials {\n      grid-template-columns: repeat(2, 1fr);\n    }\n\n    .sb-addon {\n      height: 280px;\n      align-items: flex-start;\n      padding-top: 32px;\n      overflow: hidden;\n    }\n\n    .sb-addon-text {\n      padding-left: 24px;\n    }\n\n    .sb-addon-img {\n      right: 0;\n      left: 0;\n      top: 130px;\n      bottom: 0;\n      overflow: hidden;\n      height: auto;\n      width: 124%;\n    }\n\n    .sb-addon-img img {\n      width: 1200px;\n      transform: rotate(-12deg);\n      margin-left: 0;\n      margin-top: 48px;\n      margin-bottom: -40px;\n      margin-left: -24px;\n    }\n  }\n  `}\n</style>\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/cli/js/Header.jsx",
    "content": "import PropTypes from 'prop-types';\n\nimport { Button } from './Button';\nimport './header.css';\n\nexport const Header = ({ user, onLogin, onLogout, onCreateAccount }) => (\n  <header>\n    <div className=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        {user ? (\n          <>\n            <span className=\"welcome\">\n              Welcome, <b>{user.name}</b>!\n            </span>\n            <Button size=\"small\" onClick={onLogout} label=\"Log out\" />\n          </>\n        ) : (\n          <>\n            <Button size=\"small\" onClick={onLogin} label=\"Log in\" />\n            <Button primary size=\"small\" onClick={onCreateAccount} label=\"Sign up\" />\n          </>\n        )}\n      </div>\n    </div>\n  </header>\n);\n\nHeader.propTypes = {\n  user: PropTypes.shape({\n    name: PropTypes.string.isRequired,\n  }),\n  onLogin: PropTypes.func.isRequired,\n  onLogout: PropTypes.func.isRequired,\n  onCreateAccount: PropTypes.func.isRequired,\n};\n\nHeader.defaultProps = {\n  user: null,\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/cli/js/Header.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport { Header } from './Header';\n\nexport default {\n  title: 'Example/Header',\n  component: Header,\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n};\nexport const LoggedIn = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut = {\n  args: {},\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/cli/js/Page.jsx",
    "content": "import React from 'react';\n\nimport { Header } from './Header';\nimport './page.css';\n\nexport const Page = () => {\n  const [user, setUser] = React.useState();\n\n  return (\n    <article>\n      <Header\n        user={user}\n        onLogin={() => setUser({ name: 'Jane Doe' })}\n        onLogout={() => setUser(undefined)}\n        onCreateAccount={() => setUser({ name: 'Jane Doe' })}\n      />\n      <section className=\"storybook-page\">\n        <h2>Pages in Storybook</h2>\n        <p>\n          We recommend building UIs with a{' '}\n          <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n            <strong>component-driven</strong>\n          </a>{' '}\n          process starting with atomic components and ending with pages.\n        </p>\n        <p>\n          Render pages with mock data. This makes it easy to build and review page states without\n          needing to navigate to them in your app. Here are some handy patterns for managing page\n          data in Storybook:\n        </p>\n        <ul>\n          <li>\n            Use a higher-level connected component. Storybook helps you compose such data from the\n            \"args\" of child component stories\n          </li>\n          <li>\n            Assemble data in the page component from your services. You can mock these services out\n            using Storybook.\n          </li>\n        </ul>\n        <p>\n          Get a guided tutorial on component-driven development at{' '}\n          <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n            Storybook tutorials\n          </a>\n          . Read more in the{' '}\n          <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">\n            docs\n          </a>\n          .\n        </p>\n        <div className=\"tip-wrapper\">\n          <span className=\"tip\">Tip</span> Adjust the width of the canvas with the{' '}\n          <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n            <g fill=\"none\" fillRule=\"evenodd\">\n              <path\n                d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n                id=\"a\"\n                fill=\"#999\"\n              />\n            </g>\n          </svg>\n          Viewports addon in the toolbar\n        </div>\n      </section>\n    </article>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/cli/js/Page.stories.js",
    "content": "import { expect, userEvent, within } from 'storybook/test';\n\nimport { Page } from './Page';\n\nexport default {\n  title: 'Example/Page',\n  component: Page,\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n};\n\nexport const LoggedOut = {};\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await expect(loginButton).not.toBeInTheDocument();\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/cli/ts/Button.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/nextjs-vite';\n\nimport { fn } from 'storybook/test';\n\nimport { Button } from './Button';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export\nconst meta = {\n  title: 'Example/Button',\n  component: Button,\n  parameters: {\n    // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout\n    layout: 'centered',\n  },\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  // More on argTypes: https://storybook.js.org/docs/api/argtypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onClick: fn() },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large: Story = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small: Story = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/cli/ts/Button.tsx",
    "content": "import './button.css';\n\nexport interface ButtonProps {\n  /** Is this the principal call to action on the page? */\n  primary?: boolean;\n  /** What background color to use */\n  backgroundColor?: string;\n  /** How large should the button be? */\n  size?: 'small' | 'medium' | 'large';\n  /** Button contents */\n  label: string;\n  /** Optional click handler */\n  onClick?: () => void;\n}\n\n/** Primary UI component for user interaction */\nexport const Button = ({\n  primary = false,\n  size = 'medium',\n  backgroundColor,\n  label,\n  ...props\n}: ButtonProps) => {\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n  return (\n    <button\n      type=\"button\"\n      className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n      {...props}\n    >\n      {label}\n      <style jsx>{`\n        button {\n          background-color: ${backgroundColor};\n        }\n      `}</style>\n    </button>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/cli/ts/Configure.mdx",
    "content": "import { Meta } from \"@storybook/addon-docs/blocks\";\nimport Image from \"next/image\";\n\nimport Github from \"./assets/github.svg\";\nimport Discord from \"./assets/discord.svg\";\nimport Youtube from \"./assets/youtube.svg\";\nimport Tutorials from \"./assets/tutorials.svg\";\nimport Styling from \"./assets/styling.png\";\nimport Context from \"./assets/context.png\";\nimport Assets from \"./assets/assets.png\";\nimport Docs from \"./assets/docs.png\";\nimport Share from \"./assets/share.png\";\nimport FigmaPlugin from \"./assets/figma-plugin.png\";\nimport Testing from \"./assets/testing.png\";\nimport Accessibility from \"./assets/accessibility.png\";\nimport Theming from \"./assets/theming.png\";\nimport AddonLibrary from \"./assets/addon-library.png\";\n\nexport const RightArrow = () => <svg \n    viewBox=\"0 0 14 14\" \n    width=\"8px\" \n    height=\"14px\" \n    style={{ \n      marginLeft: '4px',\n      display: 'inline-block',\n      shapeRendering: 'inherit',\n      verticalAlign: 'middle',\n      fill: 'currentColor',\n      'path fill': 'currentColor'\n    }}\n>\n  <path d=\"m11.1 7.35-5.5 5.5a.5.5 0 0 1-.7-.7L10.04 7 4.9 1.85a.5.5 0 1 1 .7-.7l5.5 5.5c.2.2.2.5 0 .7Z\" />\n</svg>\n\n<Meta title=\"Configure your project\" />\n\n<div className=\"sb-container\">\n  <div className='sb-section-title'>\n    # Configure your project\n\n    Because Storybook works separately from your app, you'll need to configure it for your specific stack and setup. Below, explore guides for configuring Storybook with popular frameworks and tools. If you get stuck, learn how you can ask for help from our community.\n  </div>\n  <div className=\"sb-section\">\n    <div className=\"sb-section-item\">\n      <Image\n        src={Styling}\n        alt=\"A wall of logos representing different styling technologies\"\n        width={0}\n        height={0}\n        style={{ width: '100%', height: 'auto' }}\n      />\n      <h4 className=\"sb-section-item-heading\">Add styling and CSS</h4>\n      <p className=\"sb-section-item-paragraph\">Like with web applications, there are many ways to include CSS within Storybook. Learn more about setting up styling within Storybook.</p>\n      <a\n        href=\"https://storybook.js.org/docs/configure/styling-and-css/?renderer=react&ref=configure\"\n        target=\"_blank\"\n      >Learn more<RightArrow /></a>\n    </div>\n    <div className=\"sb-section-item\">\n      <Image \n        width={0}\n        height={0}\n        style={{ width: '100%', height: 'auto' }}\n        src={Context}\n        alt=\"An abstraction representing the composition of data for a component\"\n      />\n      <h4 className=\"sb-section-item-heading\">Provide context and mocking</h4>\n      <p className=\"sb-section-item-paragraph\">Often when a story doesn't render, it's because your component is expecting a specific environment or context (like a theme provider) to be available.</p>\n      <a\n        href=\"https://storybook.js.org/docs/writing-stories/decorators/?renderer=react&ref=configure#context-for-mocking\"\n        target=\"_blank\"\n      >Learn more<RightArrow /></a>\n    </div>\n    <div className=\"sb-section-item\">\n      <Image \n        width={0}\n        height={0}\n        style={{ width: '100%', height: 'auto' }} \n        src={Assets} \n        alt=\"A representation of typography and image assets\" \n      />\n      <div>\n        <h4 className=\"sb-section-item-heading\">Load assets and resources</h4>\n        <p className=\"sb-section-item-paragraph\">To link static files (like fonts) to your projects and stories, use the\n        `staticDirs` configuration option to specify folders to load when\n        starting Storybook.</p>\n        <a\n          href=\"https://storybook.js.org/docs/configure/images-and-assets/?renderer=react&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n    </div>\n  </div>\n</div>\n<div className=\"sb-container\">\n  <div className='sb-section-title'>\n    # Do more with Storybook\n\n    Now that you know the basics, let's explore other parts of Storybook that will improve your experience. This list is just to get you started. You can customise Storybook in many ways to fit your needs.\n  </div>\n\n  <div className=\"sb-section\">\n    <div className=\"sb-features-grid\">\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={Docs} \n          alt=\"A screenshot showing the autodocs tag being set, pointing a docs page being generated\" \n        />\n        <h4 className=\"sb-section-item-heading\">Autodocs</h4>\n        <p className=\"sb-section-item-paragraph\">Auto-generate living,\n          interactive reference documentation from your components and stories.</p>\n        <a\n          href=\"https://storybook.js.org/docs/writing-docs/autodocs/?renderer=react&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={Share} \n          alt=\"A browser window showing a Storybook being published to a chromatic.com URL\" \n        />\n        <h4 className=\"sb-section-item-heading\">Publish to Chromatic</h4>\n        <p className=\"sb-section-item-paragraph\">Publish your Storybook to review and collaborate with your entire team.</p>\n        <a\n          href=\"https://storybook.js.org/docs/sharing/publish-storybook/?renderer=react&ref=configure#publish-storybook-with-chromatic\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={FigmaPlugin} \n          alt=\"Windows showing the Storybook plugin in Figma\" \n        />\n        <h4 className=\"sb-section-item-heading\">Figma Plugin</h4>\n        <p className=\"sb-section-item-paragraph\">Embed your stories into Figma to cross-reference the design and live\n          implementation in one place.</p>\n        <a\n          href=\"https://storybook.js.org/docs/sharing/design-integrations/?renderer=react&ref=configure#embed-storybook-in-figma-with-the-plugin\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={Testing} \n          alt=\"Screenshot of tests passing and failing\" \n        />\n        <h4 className=\"sb-section-item-heading\">Testing</h4>\n        <p className=\"sb-section-item-paragraph\">Use stories to test a component in all its variations, no matter how\n          complex.</p>\n        <a\n          href=\"https://storybook.js.org/docs/writing-tests/?renderer=react&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={Accessibility} \n          alt=\"Screenshot of accessibility tests passing and failing\" \n        />\n        <h4 className=\"sb-section-item-heading\">Accessibility</h4>\n        <p className=\"sb-section-item-paragraph\">Automatically test your components for a11y issues as you develop.</p>\n        <a\n          href=\"https://storybook.js.org/docs/writing-tests/accessibility-testing/?renderer=react&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <Image \n          width={0}\n          height={0}\n          style={{ width: '100%', height: 'auto' }} \n          src={Theming} \n          alt=\"Screenshot of Storybook in light and dark mode\" \n        />\n        <h4 className=\"sb-section-item-heading\">Theming</h4>\n        <p className=\"sb-section-item-paragraph\">Theme Storybook's UI to personalize it to your project.</p>\n        <a\n          href=\"https://storybook.js.org/docs/configure/theming/?renderer=react&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n    </div>\n  </div>\n</div>\n<div className='sb-addon'>\n  <div className='sb-addon-text'>\n    <h4>Addons</h4>\n    <p className=\"sb-section-item-paragraph\">Integrate your tools with Storybook to connect workflows.</p>\n    <a\n        href=\"https://storybook.js.org/addons/?ref=configure\"\n        target=\"_blank\"\n      >Discover all addons<RightArrow /></a>\n  </div>\n  <div className='sb-addon-img'>\n    <Image \n      width={650}\n      height={347}\n      src={AddonLibrary} \n      alt=\"Integrate your tools with Storybook to connect workflows.\" \n    />\n  </div>\n</div>\n\n<div className=\"sb-section sb-socials\">\n    <div className=\"sb-section-item\">\n      <Image \n        width={32}\n        height={32}\n        layout=\"fixed\"\n        src={Github} \n        alt=\"Github logo\" \n        className=\"sb-explore-image\"\n      />\n      Join our contributors building the future of UI development.\n\n      <a\n        href=\"https://github.com/storybookjs/storybook\"\n        target=\"_blank\"\n      >Star on GitHub<RightArrow /></a>\n    </div>\n    <div className=\"sb-section-item\">\n      <Image \n        width={33}\n        height={32}\n        layout=\"fixed\"\n        src={Discord} \n        alt=\"Discord logo\" \n        className=\"sb-explore-image\"\n      />\n      <div>\n        Get support and chat with frontend developers.\n\n        <a\n          href=\"https://discord.gg/storybook\"\n          target=\"_blank\"\n        >Join Discord server<RightArrow /></a>\n      </div>\n    </div>\n    <div className=\"sb-section-item\">\n      <Image \n        width={32}\n        height={32}\n        layout=\"fixed\"\n        src={Youtube} \n        alt=\"Youtube logo\" \n        className=\"sb-explore-image\"\n      />\n      <div>\n        Watch tutorials, feature previews and interviews.\n\n        <a\n          href=\"https://www.youtube.com/@chromaticui\"\n          target=\"_blank\"\n        >Watch on YouTube<RightArrow /></a>\n      </div>\n    </div>\n    <div className=\"sb-section-item\">\n      <Image \n        width={33}\n        height={32}\n        layout=\"fixed\"\n        src={Tutorials} \n        alt=\"A book\" \n        className=\"sb-explore-image\"\n      />\n      <p>Follow guided walkthroughs on for key workflows.</p>\n\n      <a\n          href=\"https://storybook.js.org/tutorials/?ref=configure\"\n          target=\"_blank\"\n        >Discover tutorials<RightArrow /></a>\n    </div>\n</div>\n\n<style>\n  {`\n  .sb-container {\n    margin-bottom: 48px;\n  }\n\n  .sb-section {\n    width: 100%;\n    display: flex;\n    flex-direction: row;\n    gap: 20px;\n  }\n\n  img {\n    object-fit: cover;\n  }\n\n  .sb-section-title {\n    margin-bottom: 32px;\n  }\n\n  .sb-section a:not(h1 a, h2 a, h3 a) {\n    font-size: 14px;\n  }\n\n  .sb-section-item, .sb-grid-item {\n    flex: 1;\n    display: flex;\n    flex-direction: column;\n  }\n\n  .sb-section-item-heading {\n    padding-top: 20px !important;\n    padding-bottom: 5px !important;\n    margin: 0 !important;\n  }\n  .sb-section-item-paragraph {\n    margin: 0;\n    padding-bottom: 10px;\n  }\n\n  .sb-chevron {\n    margin-left: 5px;\n  }\n\n  .sb-features-grid {\n    display: grid;\n    grid-template-columns: repeat(2, 1fr);\n    grid-gap: 32px 20px;\n  }\n\n  .sb-socials {\n    display: grid;\n    grid-template-columns: repeat(4, 1fr);\n  }\n\n  .sb-socials p {\n    margin-bottom: 10px;\n  }\n\n  .sb-explore-image {\n    max-height: 32px;\n    align-self: flex-start;\n  }\n\n  .sb-addon {\n    width: 100%;\n    display: flex;\n    align-items: center;\n    position: relative;\n    background-color: #EEF3F8;\n    border-radius: 5px;\n    border: 1px solid rgba(0, 0, 0, 0.05);\n    background: #EEF3F8;\n    height: 180px;\n    margin-bottom: 48px;\n    overflow: hidden;\n  }\n\n  .sb-addon-text {\n    padding-left: 48px;\n    max-width: 240px;\n  }\n\n  .sb-addon-text h4 {\n    padding-top: 0px;\n  }\n\n  .sb-addon-img {\n    position: absolute;\n    left: 345px;\n    top: 0;\n    height: 100%;\n    width: 200%;\n    overflow: hidden;\n  }\n\n  .sb-addon-img img {\n    width: 650px;\n    transform: rotate(-15deg);\n    margin-left: 40px;\n    margin-top: -72px;\n    box-shadow: 0 0 1px rgba(255, 255, 255, 0);\n    backface-visibility: hidden;\n  }\n\n  @media screen and (max-width: 800px) {\n    .sb-addon-img {\n      left: 300px;\n    }\n  }\n\n  @media screen and (max-width: 600px) {\n    .sb-section {\n      flex-direction: column;\n    }\n\n    .sb-features-grid {\n      grid-template-columns: repeat(1, 1fr);\n    }\n\n    .sb-socials {\n      grid-template-columns: repeat(2, 1fr);\n    }\n\n    .sb-addon {\n      height: 280px;\n      align-items: flex-start;\n      padding-top: 32px;\n      overflow: hidden;\n    }\n\n    .sb-addon-text {\n      padding-left: 24px;\n    }\n\n    .sb-addon-img {\n      right: 0;\n      left: 0;\n      top: 130px;\n      bottom: 0;\n      overflow: hidden;\n      height: auto;\n      width: 124%;\n    }\n\n    .sb-addon-img img {\n      width: 1200px;\n      transform: rotate(-12deg);\n      margin-left: 0;\n      margin-top: 48px;\n      margin-bottom: -40px;\n      margin-left: -24px;\n    }\n  }\n  `}\n</style>\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/cli/ts/Header.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/nextjs-vite';\n\nimport { fn } from 'storybook/test';\n\nimport { Header } from './Header';\n\nconst meta = {\n  title: 'Example/Header',\n  component: Header,\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n} satisfies Meta<typeof Header>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const LoggedIn: Story = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut: Story = {};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/cli/ts/Header.tsx",
    "content": "import { Button } from './Button';\nimport './header.css';\n\ntype User = {\n  name: string;\n};\n\nexport interface HeaderProps {\n  user?: User;\n  onLogin?: () => void;\n  onLogout?: () => void;\n  onCreateAccount?: () => void;\n}\n\nexport const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => (\n  <header>\n    <div className=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        {user ? (\n          <>\n            <span className=\"welcome\">\n              Welcome, <b>{user.name}</b>!\n            </span>\n            <Button size=\"small\" onClick={onLogout} label=\"Log out\" />\n          </>\n        ) : (\n          <>\n            <Button size=\"small\" onClick={onLogin} label=\"Log in\" />\n            <Button primary size=\"small\" onClick={onCreateAccount} label=\"Sign up\" />\n          </>\n        )}\n      </div>\n    </div>\n  </header>\n);\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/cli/ts/Page.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/nextjs-vite';\n\nimport { expect, userEvent, within } from 'storybook/test';\n\nimport { Page } from './Page';\n\nconst meta = {\n  title: 'Example/Page',\n  component: Page,\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n} satisfies Meta<typeof Page>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const LoggedOut: Story = {};\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn: Story = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await expect(loginButton).not.toBeInTheDocument();\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/cli/ts/Page.tsx",
    "content": "import React from 'react';\n\nimport { Header } from './Header';\nimport './page.css';\n\ntype User = {\n  name: string;\n};\n\nexport const Page: React.FC = () => {\n  const [user, setUser] = React.useState<User>();\n\n  return (\n    <article>\n      <Header\n        user={user}\n        onLogin={() => setUser({ name: 'Jane Doe' })}\n        onLogout={() => setUser(undefined)}\n        onCreateAccount={() => setUser({ name: 'Jane Doe' })}\n      />\n\n      <section className=\"storybook-page\">\n        <h2>Pages in Storybook</h2>\n        <p>\n          We recommend building UIs with a{' '}\n          <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n            <strong>component-driven</strong>\n          </a>{' '}\n          process starting with atomic components and ending with pages.\n        </p>\n        <p>\n          Render pages with mock data. This makes it easy to build and review page states without\n          needing to navigate to them in your app. Here are some handy patterns for managing page\n          data in Storybook:\n        </p>\n        <ul>\n          <li>\n            Use a higher-level connected component. Storybook helps you compose such data from the\n            \"args\" of child component stories\n          </li>\n          <li>\n            Assemble data in the page component from your services. You can mock these services out\n            using Storybook.\n          </li>\n        </ul>\n        <p>\n          Get a guided tutorial on component-driven development at{' '}\n          <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n            Storybook tutorials\n          </a>\n          . Read more in the{' '}\n          <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">\n            docs\n          </a>\n          .\n        </p>\n        <div className=\"tip-wrapper\">\n          <span className=\"tip\">Tip</span> Adjust the width of the canvas with the{' '}\n          <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n            <g fill=\"none\" fillRule=\"evenodd\">\n              <path\n                d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n                id=\"a\"\n                fill=\"#999\"\n              />\n            </g>\n          </svg>\n          Viewports addon in the toolbar\n        </div>\n      </section>\n    </article>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/next-env.d.ts",
    "content": "// Reference necessary since Next.js 13.2.0, because types in `next/navigation` are not exported per default, but\n// type references are dynamically created during Next.js start up.\n// See https://github.com/vercel/next.js/commit/cdf1d52d9aed42d01a46539886a4bda14cb77a99\n// for more insights.\n\n/// <reference types=\"next\" />\n/// <reference types=\"next/navigation-types/navigation\" />\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/DynamicImport.stories.tsx",
    "content": "import React, { Suspense } from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs-vite';\n\nimport dynamic from 'next/dynamic';\n\nconst DynamicComponent = dynamic(() => import('./DynamicImport'), {\n  ssr: false,\n});\n\nfunction Component() {\n  return (\n    <Suspense fallback=\"Loading...\">\n      <DynamicComponent />\n    </Suspense>\n  );\n}\n\nconst meta = {\n  component: Component,\n} satisfies Meta<typeof DynamicComponent>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/DynamicImport.tsx",
    "content": "import React from 'react';\n\nexport default function DynamicComponent() {\n  return <div>I am a dynamically loaded component</div>;\n}\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/Font.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/nextjs-vite';\n\nimport Font from './Font';\n\nconst meta = {\n  component: Font,\n} satisfies Meta<typeof Font>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const WithClassName: Story = {\n  args: {\n    variant: 'className',\n  },\n};\n\nexport const WithStyle: Story = {\n  args: {\n    variant: 'style',\n  },\n};\n\nexport const WithVariable: Story = {\n  args: {\n    variant: 'variable',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/Font.tsx",
    "content": "import React from 'react';\n\nimport { Rubik_Puddles } from 'next/font/google';\nimport localFont from 'next/font/local';\n\nconst rubik = Rubik_Puddles({\n  subsets: ['latin'],\n  variable: '--font-latin-rubik',\n  weight: '400',\n});\n\nexport const localRubikStorm = localFont({\n  src: '/fonts/RubikStorm-Regular.ttf',\n  variable: '--font-rubik-storm',\n});\n\ntype FontProps = {\n  variant: 'className' | 'style' | 'variable';\n};\n\nexport default function Font({ variant }: FontProps) {\n  switch (variant) {\n    case 'className':\n      return (\n        <div>\n          <h1 className={rubik.className}>Google Rubik Puddles</h1>\n          <h1 className={localRubikStorm.className}>Google Local Rubik Storm</h1>\n        </div>\n      );\n    case 'style':\n      return (\n        <div>\n          <h1 style={rubik.style}>Google Rubik Puddles</h1>\n          <h1 style={localRubikStorm.style}>Google Local Rubik Storm</h1>\n        </div>\n      );\n    case 'variable':\n      return (\n        <div>\n          <div className={rubik.variable}>\n            <h1\n              style={{\n                fontFamily: 'var(--font-latin-rubik)',\n                fontStyle: rubik.style.fontStyle,\n                fontWeight: rubik.style.fontWeight,\n              }}\n            >\n              Google Rubik Puddles\n            </h1>\n          </div>\n          <div className={localRubikStorm.variable}>\n            <h1\n              style={{\n                fontFamily: 'var(--font-rubik-storm)',\n                fontStyle: localRubikStorm.style.fontStyle,\n                fontWeight: localRubikStorm.style.fontWeight,\n              }}\n            >\n              Google Local Rubik Storm\n            </h1>\n          </div>\n        </div>\n      );\n    default:\n      return null;\n  }\n}\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/GetImageProps.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs-vite';\n\nimport { type ImageProps, getImageProps } from 'next/image';\n\nimport Accessibility from '../../assets/accessibility.svg';\nimport Testing from '../../assets/testing.png';\n\n// referenced from https://nextjs.org/docs/pages/api-reference/components/image#theme-detection-picture\nconst Component = (props: Omit<ImageProps, 'src'>) => {\n  const {\n    props: { srcSet: dark },\n  } = getImageProps({ src: Accessibility, ...props });\n  const {\n    // capture rest on one to spread to img as default; it doesn't matter which barring art direction\n    props: { srcSet: light, ...rest },\n  } = getImageProps({ src: Testing, ...props });\n\n  return (\n    <picture>\n      <source media=\"(prefers-color-scheme: dark)\" srcSet={dark} />\n      <source media=\"(prefers-color-scheme: light)\" srcSet={light} />\n      <img {...rest} />\n    </picture>\n  );\n};\n\nconst meta = {\n  component: Component,\n  args: {\n    alt: 'getImageProps Example',\n  },\n} satisfies Meta<typeof Component>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/Head.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta } from '@storybook/nextjs-vite';\nimport type { StoryObj } from '@storybook/nextjs-vite';\n\nimport Head from 'next/head';\nimport { expect, waitFor } from 'storybook/test';\n\nfunction Component() {\n  return (\n    <div>\n      <Head>\n        <title>Next.js Head Title</title>\n        <meta property=\"og:title\" content=\"My page title\" key=\"title\" />\n      </Head>\n      <Head>\n        <meta property=\"og:title\" content=\"My new title\" key=\"title\" />\n      </Head>\n      <p>Hello world!</p>\n    </div>\n  );\n}\n\nconst meta = {\n  component: Component,\n} satisfies Meta<typeof Component>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {\n  play: async () => {\n    await waitFor(() => expect(document.title).toEqual('Next.js Head Title'));\n    await expect(document.querySelectorAll('meta[property=\"og:title\"]')).toHaveLength(1);\n    await expect(\n      (document.querySelector('meta[property=\"og:title\"]') as HTMLMetaElement)?.content\n    ).toEqual('My new title');\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/Image.stories.tsx",
    "content": "import React, { useRef, useState } from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs-vite';\n\nimport Image from 'next/image';\n\nimport Accessibility from '../../assets/accessibility.svg';\nimport AvifImage from '../../assets/avif-test-image.avif';\n\nconst meta = {\n  component: Image,\n  args: {\n    src: Accessibility,\n    alt: 'Accessibility',\n  },\n} satisfies Meta<typeof Image>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Default: Story = {};\n\nexport const Avif: Story = {\n  args: {\n    src: AvifImage,\n    alt: 'Avif Test Image',\n  },\n};\n\nexport const BlurredPlaceholder: Story = {\n  args: {\n    placeholder: 'blur',\n  },\n};\n\nexport const BlurredAbsolutePlaceholder: Story = {\n  args: {\n    src: 'https://storybook.js.org/images/placeholders/50x50.png',\n    width: 50,\n    height: 50,\n    blurDataURL:\n      'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAABP5JREFUWEeNlwtz2zgMhEGKsv/k9XFp82xe11763yOJVGcXC4m2czM3GYa0E2s/LACSTi+vv1czM/7CvPpqxY/ejPeS3khmFiPHOiVLHKaZi4ux4j18GpMlS6cALupEQBCKQM4BdnGzjIcJgs//QBxAPQAem55f3yL4PWJIdyCyhlMfPdYZot0cwj3Ayg/5JwHA13paen7pADphxr/n5VI8JQsHCCGQ3gVGLLsxQ3h/LYSn5383B05rwNOws3Z576LOTOduvwfrOd5FtVat4akx0uPTrw8BNuUz23vLsY7hmg7i4ipqM2saiAdruNuirh4ff0bNdb3Qy3vkvfAQwrkHoDxTTZtDCOKrC1bMEkdnsQh/PLyetOGHkXeRAgQAQ84efQcBdUhvFofoulpdm9WGGTA+AJEe7l+i37a2c371tCFKs5zzJjxQNBMi1im7OCudP2aNghJuzZaGdSMEZjpwf/t0UgNdg9DOyLGLnY0BUHlzwVtNDkgEQhBeKkb1tUDgQrq7frwAiIJi5BKAeIFgHk5mOpPzvgltOfcoK0Rrs7lWHwsgqtXarK3N0u23h5Ne8+3Cqxn5RYSMfHCAMgDAx4CBWlA9RAGw0GA/ol0gvFB4WjAvBAFUa83SzdUdAbYMqp28uHpxCRefxwAYhksAFBlthxCiXig+zT4TYqkC+Hq7OdAfJv8lPpZiZShWBBIuRP+jspDb2lwcDkzz7OLzbO/zvAHAoXTz5eYMQL0t2yHAiCFcfPY1QDwNFylA5bPoFpsV9fsEiMl8dhcc4PP1CYD3drYcBYdIKQrx0cbRxd2JHSDcQ297/vvoZ5smRC+AyV2AQ+nm03evge08Tyy4jGqXzWWEoIvTgXHU38pWiNgH4ixB/ukAcy/xycXfp4kwdAAAt399W+OCgMjxILQacxvRQ3gEwHgKUIr/rz53CuDFNyP/Eob4+/vEWkBq6AAA/HIi62n/Lk67Q7wDYQ0UpQB7hc54T4E6gACLTYxeAwB0YKZL6U4ATEGIBwCs7qPfQJCCHkCnoK50noJKcXcAojsEAJZZKXhgCoziGKxqWV8IMNp4kP2aC+oB0TMFvhGxDQHQfIPhDrilwKOm/YCZASAHfgBABQjr3f7CyAkA0cPB03AQULRhKd4xAIjzHymo2Gp7gN0FAMAVOoA2fPz03a9ssh/RM7Iz8QKIzYF9HyB0XEZ1xJ4DzNoDOAfAslhDDTyjDfv8A2AcBeCiu/jBHQEgxnYW6Kp6BlCVAkQM8VnieF2Xyr0ivXy+XvsCzKOihwNHCCryw8HrQXVB8dgFeRfAVQiXjMbIIgXINQYB2H7Kf5wF/2Ar7h0AgKKGuAP4zOjhzlkLbpcRXKRZhNUjxG6HIQDOjN47gCn4+fWW3xVS9urPESEEwwHMo9IhAGxS2ISiA1iEnQOoA4hXRAwItp7WzL9Ow18ESJaw/ar4NgeOR49cAHCAnaH8swBhv+6CBGjeBSxEOUAI7HyKHkD4O9xKb3/feQouAI4uLBciHRRHmgbfA7h/xFc9AngNBADthvii1sMOiPwDAFeyt6s7FSFS4PmnA1v0vQvqDqQKAAPE/weAUuEgsj8c+H11Twdw/AKANXA82EDr5cJBEEzB3oI4Mb0AdR3nNw8vQnegWuvqAABwJFJEBwDgNdA7IOs3gL0LhuJdwBY8c4BfNnDdVgooHiOqn/b7JoSW/QODjTHXhU7hMQAAAABJRU5ErkJggg==',\n    placeholder: 'blur',\n  },\n  parameters: {\n    // ignoring in Chromatic to avoid inconsistent snapshots\n    // given that the switch from blur to image is quite fast\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const FilledParent: Story = {\n  args: {\n    fill: true,\n  },\n  decorators: [\n    (Story) => (\n      <div style={{ width: 500, height: 500, position: 'relative' }}>\n        <Story />\n      </div>\n    ),\n  ],\n};\n\nexport const Sized: Story = {\n  args: {\n    fill: true,\n    sizes: '(max-width: 600px) 100vw, 600px',\n  },\n  decorators: [\n    (Story) => (\n      <div style={{ width: 800, height: 800, position: 'relative' }}>\n        <Story />\n      </div>\n    ),\n  ],\n};\n\nexport const Lazy: Story = {\n  args: {\n    src: 'https://storybook.js.org/images/placeholders/50x50.png',\n    width: 50,\n    height: 50,\n  },\n  decorators: [\n    (Story) => (\n      <>\n        <div style={{ height: '200vh' }} />\n        <Story />\n      </>\n    ),\n  ],\n};\n\nexport const Eager: Story = {\n  ...Lazy,\n  parameters: {\n    nextjs: {\n      image: {\n        loading: 'eager',\n      },\n    },\n  },\n};\n\nexport const WithRef: Story = {\n  render() {\n    const [ref, setRef] = useState<HTMLImageElement | null>(null);\n\n    return (\n      <div>\n        <Image src={Accessibility} alt=\"Accessibility\" ref={setRef} />\n        <p>Alt attribute of image: {ref?.alt}</p>\n      </div>\n    );\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/ImageLegacy.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs-vite';\n\nimport Image from 'next/legacy/image';\n\nimport Accessibility from '../../assets/accessibility.svg';\n\nexport default {\n  component: Image,\n  args: {\n    src: Accessibility,\n    alt: 'Accessibility',\n  },\n} as Meta<typeof Image>;\n\ntype Story = StoryObj<typeof Image>;\n\nexport const Default: Story = {};\n\nexport const BlurredPlaceholder: Story = {\n  args: {\n    placeholder: 'blur',\n  },\n};\n\nexport const BlurredAbsolutePlaceholder: Story = {\n  args: {\n    src: 'https://storybook.js.org/images/placeholders/50x50.png',\n    width: 50,\n    height: 50,\n    blurDataURL:\n      'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAABP5JREFUWEeNlwtz2zgMhEGKsv/k9XFp82xe11763yOJVGcXC4m2czM3GYa0E2s/LACSTi+vv1czM/7CvPpqxY/ejPeS3khmFiPHOiVLHKaZi4ux4j18GpMlS6cALupEQBCKQM4BdnGzjIcJgs//QBxAPQAem55f3yL4PWJIdyCyhlMfPdYZot0cwj3Ayg/5JwHA13paen7pADphxr/n5VI8JQsHCCGQ3gVGLLsxQ3h/LYSn5383B05rwNOws3Z576LOTOduvwfrOd5FtVat4akx0uPTrw8BNuUz23vLsY7hmg7i4ipqM2saiAdruNuirh4ff0bNdb3Qy3vkvfAQwrkHoDxTTZtDCOKrC1bMEkdnsQh/PLyetOGHkXeRAgQAQ84efQcBdUhvFofoulpdm9WGGTA+AJEe7l+i37a2c371tCFKs5zzJjxQNBMi1im7OCudP2aNghJuzZaGdSMEZjpwf/t0UgNdg9DOyLGLnY0BUHlzwVtNDkgEQhBeKkb1tUDgQrq7frwAiIJi5BKAeIFgHk5mOpPzvgltOfcoK0Rrs7lWHwsgqtXarK3N0u23h5Ne8+3Cqxn5RYSMfHCAMgDAx4CBWlA9RAGw0GA/ol0gvFB4WjAvBAFUa83SzdUdAbYMqp28uHpxCRefxwAYhksAFBlthxCiXig+zT4TYqkC+Hq7OdAfJv8lPpZiZShWBBIuRP+jspDb2lwcDkzz7OLzbO/zvAHAoXTz5eYMQL0t2yHAiCFcfPY1QDwNFylA5bPoFpsV9fsEiMl8dhcc4PP1CYD3drYcBYdIKQrx0cbRxd2JHSDcQ297/vvoZ5smRC+AyV2AQ+nm03evge08Tyy4jGqXzWWEoIvTgXHU38pWiNgH4ixB/ukAcy/xycXfp4kwdAAAt399W+OCgMjxILQacxvRQ3gEwHgKUIr/rz53CuDFNyP/Eob4+/vEWkBq6AAA/HIi62n/Lk67Q7wDYQ0UpQB7hc54T4E6gACLTYxeAwB0YKZL6U4ATEGIBwCs7qPfQJCCHkCnoK50noJKcXcAojsEAJZZKXhgCoziGKxqWV8IMNp4kP2aC+oB0TMFvhGxDQHQfIPhDrilwKOm/YCZASAHfgBABQjr3f7CyAkA0cPB03AQULRhKd4xAIjzHymo2Gp7gN0FAMAVOoA2fPz03a9ssh/RM7Iz8QKIzYF9HyB0XEZ1xJ4DzNoDOAfAslhDDTyjDfv8A2AcBeCiu/jBHQEgxnYW6Kp6BlCVAkQM8VnieF2Xyr0ivXy+XvsCzKOihwNHCCryw8HrQXVB8dgFeRfAVQiXjMbIIgXINQYB2H7Kf5wF/2Ar7h0AgKKGuAP4zOjhzlkLbpcRXKRZhNUjxG6HIQDOjN47gCn4+fWW3xVS9urPESEEwwHMo9IhAGxS2ISiA1iEnQOoA4hXRAwItp7WzL9Ow18ESJaw/ar4NgeOR49cAHCAnaH8swBhv+6CBGjeBSxEOUAI7HyKHkD4O9xKb3/feQouAI4uLBciHRRHmgbfA7h/xFc9AngNBADthvii1sMOiPwDAFeyt6s7FSFS4PmnA1v0vQvqDqQKAAPE/weAUuEgsj8c+H11Twdw/AKANXA82EDr5cJBEEzB3oI4Mb0AdR3nNw8vQnegWuvqAABwJFJEBwDgNdA7IOs3gL0LhuJdwBY8c4BfNnDdVgooHiOqn/b7JoSW/QODjTHXhU7hMQAAAABJRU5ErkJggg==',\n    placeholder: 'blur',\n  },\n  parameters: {\n    // ignoring in Chromatic to avoid inconsistent snapshots\n    // given that the switch from blur to image is quite fast\n    chromatic: { disableSnapshot: true },\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/Link.stories.module.css",
    "content": ".link {\n  color: green;\n}\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/Link.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs-vite';\n\nimport Link from 'next/link';\n\nimport style from './Link.stories.module.css';\n\n// `onClick`, `href`, and `ref` need to be passed to the DOM element\n// for proper handling\nconst MyButton = React.forwardRef<\n  HTMLAnchorElement,\n  React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>\n>(function Button({ onClick, href, children }, ref) {\n  return (\n    <a href={href} onClick={onClick} ref={ref}>\n      {children}\n    </a>\n  );\n});\n\nconst Component = () => (\n  <ul>\n    <li>\n      <Link href=\"/\">Normal Link</Link>\n    </li>\n    <li>\n      <Link\n        href={{\n          pathname: '/with-url-object',\n          query: { name: 'test' },\n        }}\n      >\n        With URL Object\n      </Link>\n    </li>\n    <li>\n      <Link href=\"/replace-url\" replace>\n        Replace the URL instead of push\n      </Link>\n    </li>\n    <li>\n      <Link href=\"/#hashid\" scroll={false}>\n        Disables scrolling to the top\n      </Link>\n    </li>\n    <li>\n      <Link href=\"/no-prefetch\" prefetch={false}>\n        No Prefetching\n      </Link>\n    </li>\n    <li>\n      <Link style={{ color: 'red' }} href=\"/with-style\">\n        With style\n      </Link>\n    </li>\n    <li>\n      <Link className={style.link} href=\"/with-classname\">\n        With className\n      </Link>\n    </li>\n  </ul>\n);\n\nexport default {\n  component: Component,\n} as Meta<typeof Component>;\n\ntype Story = StoryObj<typeof Component>;\n\nexport const Default: Story = {};\n\nexport const InAppDir: Story = {\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n    },\n  },\n};\n\nexport const LegacyLink: Story = {\n  render: () => (\n    <Link href=\"/legacy-behaviour\" legacyBehavior>\n      <a>Legacy behavior</a>\n    </Link>\n  ),\n  tags: ['!test'],\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/Navigation.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs-vite';\nimport { getRouter } from '@storybook/nextjs-vite/navigation.mock';\n\nimport {\n  useParams,\n  usePathname,\n  useRouter,\n  useSearchParams,\n  useSelectedLayoutSegment,\n  useSelectedLayoutSegments,\n} from 'next/navigation';\nimport { expect, userEvent, within } from 'storybook/test';\n\nfunction Component() {\n  const router = useRouter();\n  const pathname = usePathname();\n  const searchParams = useSearchParams();\n  const params = useParams();\n  const segment = useSelectedLayoutSegment();\n  const segments = useSelectedLayoutSegments();\n\n  const searchParamsList = searchParams ? Array.from(searchParams.entries()) : [];\n\n  const routerActions = [\n    {\n      cb: () => router.back(),\n      name: 'Go back',\n    },\n    {\n      cb: () => router.forward(),\n      name: 'Go forward',\n    },\n    {\n      cb: () => router.prefetch('/prefetched-html'),\n      name: 'Prefetch',\n    },\n    {\n      // @ts-expect-error (old API)\n      cb: () => router.push('/push-html', { forceOptimisticNavigation: true }),\n      name: 'Push HTML',\n    },\n    {\n      cb: () => router.refresh(),\n      name: 'Refresh',\n    },\n    {\n      // @ts-expect-error (old API)\n      cb: () => router.replace('/replaced-html', { forceOptimisticNavigation: true }),\n      name: 'Replace',\n    },\n  ];\n\n  return (\n    <div>\n      <div>pathname: {pathname}</div>\n      <div>segment: {segment}</div>\n      <div>segments: {segments.join(',')}</div>\n      <div>\n        searchparams:{' '}\n        <ul>\n          {searchParamsList.map(([key, value]) => (\n            <li key={key}>\n              {key}: {value}\n            </li>\n          ))}\n        </ul>\n      </div>\n      <div>\n        params:{' '}\n        <ul>\n          {Object.entries(params).map(([key, value]) => (\n            <li key={key}>\n              {key}: {value}\n            </li>\n          ))}\n        </ul>\n      </div>\n      {routerActions.map(({ cb, name }) => (\n        <div key={name} style={{ marginBottom: '1em' }}>\n          <button type=\"button\" onClick={cb}>\n            {name}\n          </button>\n        </div>\n      ))}\n    </div>\n  );\n}\n\ntype Story = StoryObj<typeof Component>;\n\nexport default {\n  component: Component,\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        pathname: '/hello',\n        query: {\n          foo: 'bar',\n        },\n        prefetch: () => {\n          console.log('custom prefetch');\n        },\n      },\n    },\n  },\n} as Meta<typeof Component>;\n\nexport const Default: Story = {\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const routerMock = getRouter();\n\n    await step('Asserts whether forward hook is called', async () => {\n      const forwardBtn = await canvas.findByText('Go forward');\n      await userEvent.click(forwardBtn);\n      await expect(routerMock.forward).toHaveBeenCalled();\n    });\n\n    await step('Asserts whether custom prefetch hook is called', async () => {\n      const prefetchBtn = await canvas.findByText('Prefetch');\n      await userEvent.click(prefetchBtn);\n      await expect(routerMock.prefetch).toHaveBeenCalledWith('/prefetched-html');\n    });\n  },\n};\n\nexport const WithSegmentDefined: Story = {\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        segments: ['dashboard', 'settings'],\n      },\n    },\n  },\n};\n\nexport const WithSegmentDefinedForParams: Story = {\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        segments: [\n          ['slug', 'hello'],\n          ['framework', 'nextjs'],\n        ],\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/NextHeader.stories.tsx",
    "content": "import type { Meta } from '@storybook/nextjs-vite';\nimport type { StoryObj } from '@storybook/nextjs-vite';\nimport { cookies, headers } from '@storybook/nextjs-vite/headers.mock';\n\nimport { expect, userEvent, within } from 'storybook/test';\n\nimport NextHeader from './NextHeader';\n\nexport default {\n  component: NextHeader,\n  parameters: {\n    react: {\n      rsc: true,\n    },\n  },\n} as Meta<typeof NextHeader>;\n\ntype Story = StoryObj<typeof NextHeader>;\n\nexport const Default: Story = {\n  loaders: async () => {\n    cookies().set('firstName', 'Jane');\n    cookies().set({\n      name: 'lastName',\n      value: 'Doe',\n    });\n    headers().set('timezone', 'Central European Summer Time');\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const headersMock = headers();\n    const cookiesMock = cookies();\n    await step('Cookie and header store apis are called upon rendering', async () => {\n      await expect(cookiesMock.getAll).toHaveBeenCalled();\n      await expect(headersMock.entries).toHaveBeenCalled();\n    });\n\n    await step('Upon clicking on submit, the user-id cookie is set', async () => {\n      const submitButton = await canvas.findByRole('button');\n      await userEvent.click(submitButton);\n\n      await expect(cookiesMock.set).toHaveBeenCalledWith('user-id', 'encrypted-id');\n    });\n\n    await step('The user-id cookie is available in cookie and header stores', async () => {\n      await expect(headersMock.get('cookie')).toContain('user-id=encrypted-id');\n      await expect(cookiesMock.get('user-id')).toEqual({\n        name: 'user-id',\n        value: 'encrypted-id',\n      });\n    });\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/NextHeader.tsx",
    "content": "import React from 'react';\n\nimport { cookies, headers } from 'next/headers';\n\nexport default async function Component() {\n  async function handleClick() {\n    'use server';\n    (await cookies()).set('user-id', 'encrypted-id');\n  }\n\n  return (\n    <>\n      <h3>Cookies:</h3>\n      {(await cookies()).getAll().map(({ name, value }) => {\n        return (\n          <p key={name} style={{ display: 'flex', flexDirection: 'row', gap: 8 }}>\n            <strong>Name:</strong> <span>{name}</span>\n            <strong>Value:</strong> <span>{value}</span>\n          </p>\n        );\n      })}\n\n      <h3>Headers:</h3>\n      {Array.from((await headers()).entries()).map(([name, value]: [string, string]) => {\n        return (\n          <p key={name} style={{ display: 'flex', flexDirection: 'row', gap: 8 }}>\n            <strong>Name:</strong> <span>{name}</span>\n            <strong>Value:</strong> <span>{value}</span>\n          </p>\n        );\n      })}\n\n      <form action={handleClick}>\n        <button>add user-id cookie</button>\n      </form>\n    </>\n  );\n}\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/RSC.stories.tsx",
    "content": "/* eslint-disable local-rules/no-uncategorized-errors */\nimport React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs-vite';\n\nimport { Nested, RSC } from './RSC';\n\nexport default {\n  component: RSC,\n  args: { label: 'label' },\n  parameters: {\n    react: {\n      rsc: true,\n    },\n  },\n} as Meta<typeof RSC>;\n\ntype Story = StoryObj<typeof RSC>;\n\nexport const Default: Story = {};\n\nexport const DisableRSC: Story = {\n  tags: ['!test'],\n  parameters: {\n    chromatic: { disableSnapshot: true },\n    nextjs: { rsc: false },\n  },\n};\n\nexport const Errored: Story = {\n  tags: ['!test', '!vitest'],\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n  render: () => {\n    throw new Error('RSC Error');\n  },\n};\n\nexport const NestedRSC: Story = {\n  render: (args) => (\n    <Nested>\n      <RSC {...args} />\n    </Nested>\n  ),\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/RSC.tsx",
    "content": "import React from 'react';\n\nimport 'server-only';\n\nexport const RSC = async ({ label }: { label: string }) => <>RSC {label}</>;\n\nexport const Nested = async ({ children }: any) => <>Nested {children}</>;\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/Redirect.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs-vite';\n\nimport { redirect } from 'next/navigation';\nimport { userEvent, within } from 'storybook/test';\n\nlet state = 'Bug! Not invalidated';\n\nexport default {\n  render() {\n    return (\n      <div>\n        <div>{state}</div>\n        <form\n          action={() => {\n            state = 'State is invalidated successfully.';\n            redirect('/');\n          }}\n        >\n          <button>Submit</button>\n        </form>\n      </div>\n    );\n  },\n  parameters: {\n    test: {\n      // This is needed until Next will update to the React 19 beta: https://github.com/vercel/next.js/pull/65058\n      // In the React 19 beta ErrorBoundary errors (such as redirect) are only logged, and not thrown.\n      // We will also suspress console.error logs for re the console.error logs for redirect in the next framework.\n      // Using the onCaughtError react root option:\n      //   react: {\n      //     rootOptions: {\n      //       onCaughtError(error: unknown) {\n      //         if (isNextRouterError(error)) return;\n      //         console.error(error);\n      //       },\n      //     },\n      // See: code/frameworks/nextjs/src/preview.tsx\n      dangerouslyIgnoreUnhandledErrors: true,\n    },\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        pathname: '/',\n      },\n    },\n  },\n  tags: ['!test', '!vitest'],\n} as Meta;\n\nexport const SingletonStateGetsInvalidatedAfterRedirecting: StoryObj = {\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    await userEvent.click(canvas.getByRole('button'));\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/Router.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs-vite';\nimport { getRouter } from '@storybook/nextjs-vite/router.mock';\n\nimport Router, { useRouter } from 'next/router';\nimport { expect, userEvent, within } from 'storybook/test';\n\nfunction Component() {\n  const router = useRouter();\n  const searchParams = router.query;\n\n  const routerActions = [\n    {\n      cb: () => router.back(),\n      name: 'Go back',\n    },\n    {\n      cb: () => router.forward(),\n      name: 'Go forward',\n    },\n    {\n      cb: () => router.prefetch('/prefetched-html'),\n      name: 'Prefetch',\n    },\n    {\n      // @ts-expect-error (old API)\n      cb: () => router.push('/push-html', { forceOptimisticNavigation: true }),\n      name: 'Push HTML',\n    },\n    {\n      // @ts-expect-error (old API)\n      cb: () => router.replace('/replaced-html', { forceOptimisticNavigation: true }),\n      name: 'Replace',\n    },\n  ];\n\n  return (\n    <div>\n      <div>Router pathname: {Router.pathname}</div>\n      <div>pathname: {router.pathname}</div>\n      <div>\n        searchparams:{' '}\n        <ul>\n          {Object.entries(searchParams).map(([key, value]) => (\n            <li key={key}>\n              {key}: {value}\n            </li>\n          ))}\n        </ul>\n      </div>\n      {routerActions.map(({ cb, name }) => (\n        <div key={name} style={{ marginBottom: '1em' }}>\n          <button type=\"button\" onClick={cb}>\n            {name}\n          </button>\n        </div>\n      ))}\n    </div>\n  );\n}\n\nexport default {\n  component: Component,\n  parameters: {\n    nextjs: {\n      router: {\n        pathname: '/hello',\n        query: {\n          foo: 'bar',\n        },\n        prefetch: () => {\n          console.log('custom prefetch');\n        },\n      },\n    },\n  },\n} as Meta<typeof Component>;\n\nexport const Default: StoryObj<typeof Component> = {\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const routerMock = getRouter();\n\n    await step('Router property overrides should be available in useRouter fn', async () => {\n      await expect(Router.pathname).toBe('/hello');\n      await expect(Router.query).toEqual({ foo: 'bar' });\n    });\n\n    await step(\n      'Router property overrides should be available in default export from next/router',\n      async () => {\n        await expect(Router.pathname).toBe('/hello');\n        await expect(Router.query).toEqual({ foo: 'bar' });\n      }\n    );\n\n    await step('Asserts whether forward hook is called', async () => {\n      const forwardBtn = await canvas.findByText('Go forward');\n      await userEvent.click(forwardBtn);\n      await expect(routerMock.forward).toHaveBeenCalled();\n    });\n\n    await step('Asserts whether custom prefetch hook is called', async () => {\n      const prefetchBtn = await canvas.findByText('Prefetch');\n      await userEvent.click(prefetchBtn);\n      await expect(routerMock.prefetch).toHaveBeenCalledWith('/prefetched-html');\n    });\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/ServerActions.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs-vite';\nimport { revalidatePath } from '@storybook/nextjs-vite/cache.mock';\nimport { cookies } from '@storybook/nextjs-vite/headers.mock';\nimport { getRouter, redirect } from '@storybook/nextjs-vite/navigation.mock';\n\nimport { expect, userEvent, waitFor, within } from 'storybook/test';\n\nimport { accessRoute, login, logout } from './ServerActions';\n\nfunction Component() {\n  return (\n    <div style={{ display: 'flex', gap: 8 }}>\n      <form>\n        <button type=\"submit\" formAction={login}>\n          Login\n        </button>\n      </form>\n      <form>\n        <button type=\"submit\" formAction={logout}>\n          Logout\n        </button>\n      </form>\n      <form>\n        <button type=\"submit\" formAction={accessRoute}>\n          Access protected route\n        </button>\n      </form>\n    </div>\n  );\n}\n\nexport default {\n  component: Component,\n  tags: ['!test'],\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        pathname: '/',\n      },\n    },\n    test: {\n      // This is needed until Next will update to the React 19 beta: https://github.com/vercel/next.js/pull/65058\n      // In the React 19 beta ErrorBoundary errors (such as redirect) are only logged, and not thrown.\n      // We will also suspress console.error logs for re the console.error logs for redirect in the next framework.\n      // Using the onCaughtError react root option:\n      //   react: {\n      //     rootOptions: {\n      //       onCaughtError(error: unknown) {\n      //         if (isNextRouterError(error)) return;\n      //         console.error(error);\n      //       },\n      //     },\n      // See: code/frameworks/nextjs/src/preview.tsx\n      dangerouslyIgnoreUnhandledErrors: true,\n    },\n  },\n} as Meta<typeof Component>;\n\ntype Story = StoryObj<typeof Component>;\n\nexport const ProtectedWhileLoggedOut: Story = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    await userEvent.click(canvas.getByText('Access protected route'));\n\n    await expect(cookies().get).toHaveBeenCalledWith('user');\n    await expect(redirect).toHaveBeenCalledWith('/');\n\n    await waitFor(() => expect(getRouter().push).toHaveBeenCalled());\n  },\n};\n\nexport const ProtectedWhileLoggedIn: Story = {\n  beforeEach() {\n    cookies().set('user', 'storybookjs');\n  },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    await userEvent.click(canvas.getByText('Access protected route'));\n\n    await expect(cookies().get).toHaveBeenLastCalledWith('user');\n    await expect(revalidatePath).toHaveBeenLastCalledWith('/');\n    await expect(redirect).toHaveBeenLastCalledWith('/protected');\n\n    await waitFor(() => expect(getRouter().push).toHaveBeenCalled());\n  },\n};\n\nexport const Logout: Story = {\n  beforeEach() {\n    cookies().set('user', 'storybookjs');\n  },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n\n    await userEvent.click(canvas.getByText('Logout'));\n    await expect(cookies().delete).toHaveBeenCalled();\n    await expect(revalidatePath).toHaveBeenCalledWith('/');\n    await expect(redirect).toHaveBeenCalledWith('/');\n\n    await waitFor(() => expect(getRouter().push).toHaveBeenCalled());\n  },\n};\n\nexport const Login: Story = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    await userEvent.click(canvas.getByText('Login'));\n\n    await expect(cookies().set).toHaveBeenCalledWith('user', 'storybookjs');\n    await expect(revalidatePath).toHaveBeenCalledWith('/');\n    await expect(redirect).toHaveBeenCalledWith('/');\n\n    await waitFor(() => expect(getRouter().push).toHaveBeenCalled());\n  },\n};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/ServerActions.tsx",
    "content": "'use server';\n\nimport { revalidatePath } from 'next/cache';\nimport { cookies } from 'next/headers';\nimport { redirect } from 'next/navigation';\n\nexport async function accessRoute() {\n  const user = (await cookies()).get('user');\n\n  if (!user) {\n    redirect('/');\n  }\n\n  revalidatePath('/');\n  redirect(`/protected`);\n}\n\nexport async function logout() {\n  (await cookies()).delete('user');\n  revalidatePath('/');\n  redirect('/');\n}\n\nexport async function login() {\n  (await cookies()).set('user', 'storybookjs');\n  revalidatePath('/');\n  redirect('/');\n}\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/StyledJsx.stories.tsx",
    "content": "import React from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/nextjs-vite';\n\nconst Component = () => (\n  <div>\n    <style jsx>{`\n      .main p {\n        color: #ff4785;\n      }\n    `}</style>\n    <main className=\"main\">\n      <p>This is styled using Styled JSX</p>\n    </main>\n  </div>\n);\n\nexport default {\n  component: Component,\n} as Meta<typeof Component>;\n\nexport const Default: StoryObj<typeof Component> = {};\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/stories/fonts/OFL.txt",
    "content": "Copyright 2020 The Rubik Filtered Project Authors (https://https://github.com/NaN-xyz/Rubik-Filtered)\r\n\r\nThis Font Software is licensed under the SIL Open Font License, Version 1.1.\r\nThis license is copied below, and is also available with a FAQ at:\r\nhttp://scripts.sil.org/OFL\r\n\r\n\r\n-----------------------------------------------------------\r\nSIL OPEN FONT LICENSE Version 1.1 - 26 February 2007\r\n-----------------------------------------------------------\r\n\r\nPREAMBLE\r\nThe goals of the Open Font License (OFL) are to stimulate worldwide\r\ndevelopment of collaborative font projects, to support the font creation\r\nefforts of academic and linguistic communities, and to provide a free and\r\nopen framework in which fonts may be shared and improved in partnership\r\nwith others.\r\n\r\nThe OFL allows the licensed fonts to be used, studied, modified and\r\nredistributed freely as long as they are not sold by themselves. The\r\nfonts, including any derivative works, can be bundled, embedded, \r\nredistributed and/or sold with any software provided that any reserved\r\nnames are not used by derivative works. The fonts and derivatives,\r\nhowever, cannot be released under any other type of license. The\r\nrequirement for fonts to remain under this license does not apply\r\nto any document created using the fonts or their derivatives.\r\n\r\nDEFINITIONS\r\n\"Font Software\" refers to the set of files released by the Copyright\r\nHolder(s) under this license and clearly marked as such. This may\r\ninclude source files, build scripts and documentation.\r\n\r\n\"Reserved Font Name\" refers to any names specified as such after the\r\ncopyright statement(s).\r\n\r\n\"Original Version\" refers to the collection of Font Software components as\r\ndistributed by the Copyright Holder(s).\r\n\r\n\"Modified Version\" refers to any derivative made by adding to, deleting,\r\nor substituting -- in part or in whole -- any of the components of the\r\nOriginal Version, by changing formats or by porting the Font Software to a\r\nnew environment.\r\n\r\n\"Author\" refers to any designer, engineer, programmer, technical\r\nwriter or other person who contributed to the Font Software.\r\n\r\nPERMISSION & CONDITIONS\r\nPermission is hereby granted, free of charge, to any person obtaining\r\na copy of the Font Software, to use, study, copy, merge, embed, modify,\r\nredistribute, and sell modified and unmodified copies of the Font\r\nSoftware, subject to the following conditions:\r\n\r\n1) Neither the Font Software nor any of its individual components,\r\nin Original or Modified Versions, may be sold by itself.\r\n\r\n2) Original or Modified Versions of the Font Software may be bundled,\r\nredistributed and/or sold with any software, provided that each copy\r\ncontains the above copyright notice and this license. These can be\r\nincluded either as stand-alone text files, human-readable headers or\r\nin the appropriate machine-readable metadata fields within text or\r\nbinary files as long as those fields can be easily viewed by the user.\r\n\r\n3) No Modified Version of the Font Software may use the Reserved Font\r\nName(s) unless explicit written permission is granted by the corresponding\r\nCopyright Holder. This restriction only applies to the primary font name as\r\npresented to the users.\r\n\r\n4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font\r\nSoftware shall not be used to promote, endorse or advertise any\r\nModified Version, except to acknowledge the contribution(s) of the\r\nCopyright Holder(s) and the Author(s) or with their explicit written\r\npermission.\r\n\r\n5) The Font Software, modified or unmodified, in part or in whole,\r\nmust be distributed entirely under this license, and must not be\r\ndistributed under any other license. The requirement for fonts to\r\nremain under this license does not apply to any document created\r\nusing the Font Software.\r\n\r\nTERMINATION\r\nThis license becomes null and void if any of the above conditions are\r\nnot met.\r\n\r\nDISCLAIMER\r\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\r\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\r\nOF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE\r\nCOPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\r\nINCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\r\nDAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r\nFROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM\r\nOTHER DEALINGS IN THE FONT SOFTWARE.\r\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/template/typings.d.ts",
    "content": "declare module '*.svg' {\n  const content: string;\n  export default content;\n}\n\ndeclare module '*.avif' {\n  const content: string;\n  export default content;\n}\n\ndeclare module '*.png' {\n  const content: string;\n  export default content;\n}\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\", \"template/**/*\"]\n}\n"
  },
  {
    "path": "code/frameworks/nextjs-vite/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/frameworks/preact-vite/README.md",
    "content": "# Storybook for Preact & Vite\n\nDevelop, document, and test UI components in isolation.\n\nSee [documentation](https://storybook.js.org/docs/get-started/frameworks/preact-vite?renderer=preact&ref=readme) for installation instructions, usage examples, APIs, and more.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/frameworks/preact-vite/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./node'],\n        entryPoint: './src/node/index.ts',\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/frameworks/preact-vite/package.json",
    "content": "{\n  \"name\": \"@storybook/preact-vite\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook for Preact and Vite: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-framework\",\n    \"preact\",\n    \"vite\",\n    \"component\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/frameworks/preact-vite\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/frameworks/preact-vite\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./node\": {\n      \"types\": \"./dist/node/index.d.ts\",\n      \"code\": \"./src/node/index.ts\",\n      \"default\": \"./dist/node/index.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"template/cli/**/*\",\n    \"types/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/builder-vite\": \"workspace:*\",\n    \"@storybook/preact\": \"workspace:*\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.19.1\",\n    \"typescript\": \"^5.9.3\",\n    \"vite\": \"^7.0.4\"\n  },\n  \"peerDependencies\": {\n    \"preact\": \">=10\",\n    \"storybook\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/frameworks/preact-vite/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/frameworks/preact-vite/project.json",
    "content": "{\n  \"name\": \"preact-vite\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/frameworks/preact-vite/src/index.ts",
    "content": "export * from '@storybook/preact';\nexport * from './types.ts';\n"
  },
  {
    "path": "code/frameworks/preact-vite/src/node/index.ts",
    "content": "import type { StorybookConfig } from '../types.ts';\n\nexport function defineMain(config: StorybookConfig) {\n  return config;\n}\n\nexport type { StorybookConfig };\n"
  },
  {
    "path": "code/frameworks/preact-vite/src/preset.ts",
    "content": "import type { StorybookConfig } from './types.ts';\n\nexport const core: StorybookConfig['core'] = {\n  builder: import.meta.resolve('@storybook/builder-vite'),\n  renderer: import.meta.resolve('@storybook/preact/preset'),\n};\n\nexport const viteFinal: StorybookConfig['viteFinal'] = async (config) => {\n  // TODO: Add docgen plugin per issue https://github.com/storybookjs/storybook/issues/19739\n  return config;\n};\n"
  },
  {
    "path": "code/frameworks/preact-vite/src/types.ts",
    "content": "import type {\n  CompatibleString,\n  StorybookConfig as StorybookConfigBase,\n} from 'storybook/internal/types';\n\nimport type { BuilderOptions, StorybookConfigVite } from '@storybook/builder-vite';\n\ntype FrameworkName = CompatibleString<'@storybook/preact-vite'>;\ntype BuilderName = CompatibleString<'@storybook/builder-vite'>;\n\nexport type FrameworkOptions = {\n  builder?: BuilderOptions;\n};\n\ntype StorybookConfigFramework = {\n  framework:\n    | FrameworkName\n    | {\n        name: FrameworkName;\n        options: FrameworkOptions;\n      };\n  core?: StorybookConfigBase['core'] & {\n    builder?:\n      | BuilderName\n      | {\n          name: BuilderName;\n          options: BuilderOptions;\n        };\n  };\n};\n\n/** The interface for Storybook configuration in `main.ts` files. */\nexport type StorybookConfig = Omit<\n  StorybookConfigBase,\n  keyof StorybookConfigVite | keyof StorybookConfigFramework\n> &\n  StorybookConfigVite &\n  StorybookConfigFramework;\n"
  },
  {
    "path": "code/frameworks/preact-vite/template/cli/.eslintrc.json",
    "content": "{\n  \"rules\": {\n    \"import/extensions\": \"off\",\n    \"react/react-in-jsx-scope\": \"off\",\n    \"react/prop-types\": \"off\"\n  }\n}\n"
  },
  {
    "path": "code/frameworks/preact-vite/template/cli/Button.jsx",
    "content": "import './button.css';\n\n/**\n * Primary UI component for user interaction\n *\n * @param {object} props\n * @param {string} [props.primary=false] Default is `false`\n * @param {string} [props.backgroundColor]\n * @param {'small' | 'medium' | 'large'} [props.size='medium'] Default is `'medium'`\n * @param {string} props.label\n * @param {function} props.onClick\n */\nexport const Button = ({\n  primary = false,\n  backgroundColor = null,\n  size = 'medium',\n  label,\n  ...props\n}) => {\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n  return (\n    <button\n      type=\"button\"\n      className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n      style={backgroundColor && { backgroundColor }}\n      {...props}\n    >\n      {label}\n    </button>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/preact-vite/template/cli/Button.stories.jsx",
    "content": "import { fn } from 'storybook/test';\n\nimport { Button } from './Button';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories\nexport default {\n  title: 'Example/Button',\n  component: Button,\n  tags: ['autodocs'],\n  argTypes: {\n    backgroundColor: { control: 'color' },\n    onClick: { action: 'onClick' },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onClick: fn() },\n};\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/preact-vite/template/cli/Header.jsx",
    "content": "import { Button } from './Button';\nimport './header.css';\n\n/**\n * Header component\n *\n * @param {object} props\n * @param {object} [props.user]\n * @param {string} props.user.name\n * @param {function} props.onLogin\n * @param {function} props.onLogout\n * @param {function} props.onCreateAccount\n */\nexport const Header = ({ user = null, onLogin, onLogout, onCreateAccount }) => (\n  <header>\n    <div className=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        {user ? (\n          <>\n            <span className=\"welcome\">\n              Welcome, <b>{user.name}</b>!\n            </span>\n            <Button size=\"small\" onClick={onLogout} label=\"Log out\" />\n          </>\n        ) : (\n          <>\n            <Button size=\"small\" onClick={onLogin} label=\"Log in\" />\n            <Button primary size=\"small\" onClick={onCreateAccount} label=\"Sign up\" />\n          </>\n        )}\n      </div>\n    </div>\n  </header>\n);\n"
  },
  {
    "path": "code/frameworks/preact-vite/template/cli/Header.stories.jsx",
    "content": "import { fn } from 'storybook/test';\n\nimport { Header } from './Header';\n\nexport default {\n  title: 'Example/Header',\n  component: Header,\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n};\n\nexport const LoggedIn = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut = {};\n"
  },
  {
    "path": "code/frameworks/preact-vite/template/cli/Page.jsx",
    "content": "import { useState } from 'preact/hooks';\n\nimport { Header } from './Header';\nimport './page.css';\n\n/** Simple page component */\nexport const Page = () => {\n  const [user, setUser] = useState();\n\n  return (\n    <article>\n      <Header\n        user={user}\n        onLogin={() => setUser({ name: 'Jane Doe' })}\n        onLogout={() => setUser(undefined)}\n        onCreateAccount={() => setUser({ name: 'Jane Doe' })}\n      />\n\n      <section className=\"storybook-page\">\n        <h2>Pages in Storybook</h2>\n        <p>\n          We recommend building UIs with a{' '}\n          <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n            <strong>component-driven</strong>\n          </a>{' '}\n          process starting with atomic components and ending with pages.\n        </p>\n        <p>\n          Render pages with mock data. This makes it easy to build and review page states without\n          needing to navigate to them in your app. Here are some handy patterns for managing page\n          data in Storybook:\n        </p>\n        <ul>\n          <li>\n            Use a higher-level connected component. Storybook helps you compose such data from the\n            \"args\" of child component stories\n          </li>\n          <li>\n            Assemble data in the page component from your services. You can mock these services out\n            using Storybook.\n          </li>\n        </ul>\n        <p>\n          Get a guided tutorial on component-driven development at{' '}\n          <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n            Storybook tutorials\n          </a>\n          . Read more in the{' '}\n          <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">\n            docs\n          </a>\n          .\n        </p>\n        <div className=\"tip-wrapper\">\n          <span className=\"tip\">Tip</span> Adjust the width of the canvas with the{' '}\n          <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n            <g fill=\"none\" fillRule=\"evenodd\">\n              <path\n                d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n                id=\"a\"\n                fill=\"#999\"\n              />\n            </g>\n          </svg>\n          Viewports addon in the toolbar\n        </div>\n      </section>\n    </article>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/preact-vite/template/cli/Page.stories.jsx",
    "content": "import { userEvent, within } from 'storybook/test';\n\nimport { Page } from './Page';\n\nexport default {\n  title: 'Example/Page',\n  component: Page,\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n};\n\nexport const LoggedOut = {};\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = await canvas.getByRole('button', {\n      name: /Log in/i,\n    });\n    await userEvent.click(loginButton);\n  },\n};\n"
  },
  {
    "path": "code/frameworks/preact-vite/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"storybook/internal/*\": [\"../../lib/cli/core/*\"]\n    },\n    \"rootDir\": \"./src\"\n  },\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/frameworks/preact-vite/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/README.md",
    "content": "# Storybook for React Native Web & Vite\n\nSee [documentation](https://storybook.js.org/docs/get-started/frameworks/react-native-web-vite?renderer=react-native-web&ref=readme) for installation instructions, usage examples, APIs, and more.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./node'],\n        entryPoint: './src/node/index.ts',\n      },\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./vite-plugin'],\n        entryPoint: './src/vite-plugin.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/package.json",
    "content": "{\n  \"name\": \"@storybook/react-native-web-vite\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook for React Native Web and Vite: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"react-native\",\n    \"react-native-web\",\n    \"expo\",\n    \"expo-web\",\n    \"vite\",\n    \"component\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/frameworks/react-native-web-vite\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/frameworks/react-native-web-vite\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./node\": {\n      \"types\": \"./dist/node/index.d.ts\",\n      \"code\": \"./src/node/index.ts\",\n      \"default\": \"./dist/node/index.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\",\n    \"./vite-plugin\": \"./dist/vite-plugin.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"template/cli/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/builder-vite\": \"workspace:*\",\n    \"@storybook/react\": \"workspace:*\",\n    \"@storybook/react-vite\": \"workspace:*\",\n    \"vite-plugin-rnw\": \"^0.0.11\",\n    \"vite-tsconfig-paths\": \"^6.1.1\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.19.1\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-native\": \">=0.74.5\",\n    \"react-native-web\": \"^0.19.12 || ^0.20.0 || ^0.21.0\",\n    \"storybook\": \"workspace:^\",\n    \"vite\": \"^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/project.json",
    "content": "{\n  \"name\": \"react-native-web-vite\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/src/index.ts",
    "content": "export type { FrameworkOptions, StorybookConfig } from './types.ts';\n\nexport { __definePreview as definePreview } from '@storybook/react';\nexport * from '@storybook/react';\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/src/node/index.ts",
    "content": "import type { StorybookConfig } from '../types.ts';\n\nexport function defineMain(config: StorybookConfig) {\n  return config;\n}\n\nexport type { StorybookConfig };\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/src/preset.ts",
    "content": "import { viteFinal as reactViteFinal } from '@storybook/react-vite/preset';\n\nimport type { InlineConfig } from 'vite';\nimport { rnw } from 'vite-plugin-rnw';\nimport tsconfigPaths from 'vite-tsconfig-paths';\n\nimport type { FrameworkOptions, StorybookConfig } from './types.ts';\n\nconst getExcludeOptions = (modulesToTranspile: string[]) => {\n  const defaultModulesToTranspile = ['react-native', '@react-native', 'expo', '@expo'];\n  const uniqueModulesToTranspile = Array.from(\n    new Set([...modulesToTranspile, ...defaultModulesToTranspile])\n  );\n\n  if (modulesToTranspile.length) {\n    // produce a regex of `/\\/node_modules\\/(?!react-native|@react-native|expo|@expo|[others])/`\n    return { exclude: new RegExp(`/node_modules/(?!${uniqueModulesToTranspile.join('|')})`) };\n  }\n\n  return {};\n};\n\nexport const viteFinal: StorybookConfig['viteFinal'] = async (config, options) => {\n  const { mergeConfig } = await import('vite');\n\n  const { pluginReactOptions = {}, modulesToTranspile = [] } =\n    await options.presets.apply<FrameworkOptions>('frameworkOptions');\n\n  const { plugins = [], ...reactConfigWithoutPlugins } = await reactViteFinal(config, options);\n\n  return mergeConfig(reactConfigWithoutPlugins, {\n    plugins: [\n      tsconfigPaths(),\n\n      rnw({\n        ...getExcludeOptions(modulesToTranspile),\n        ...pluginReactOptions,\n        jsxRuntime: pluginReactOptions.jsxRuntime || 'automatic',\n        babel: {\n          babelrc: false,\n          configFile: false,\n          ...pluginReactOptions.babel,\n        },\n      }),\n\n      ...plugins,\n    ],\n  } satisfies InlineConfig);\n};\n\nexport const core = {\n  builder: import.meta.resolve('@storybook/builder-vite'),\n  renderer: import.meta.resolve('@storybook/react/preset'),\n};\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/src/types.ts",
    "content": "import type { CompatibleString } from 'storybook/internal/types';\n\nimport type {\n  FrameworkOptions as FrameworkOptionsBase,\n  StorybookConfig as StorybookConfigBase,\n} from '@storybook/react-vite';\n\nimport type { RnwOptions } from 'vite-plugin-rnw';\n\nexport type FrameworkOptions = FrameworkOptionsBase & {\n  /**\n   * Many react native libraries aren't transpiled for the web, add them to this list to make sure\n   * they get transpiled before attempting to load them on the web. We will automatically add\n   * `react-native`, `@react-native`, `expo`, and `@expo` to this list.\n   *\n   * @example {modulesToTranspile: ['my-library']}\n   */\n  modulesToTranspile?: string[];\n  pluginReactOptions?: RnwOptions;\n  /**\n   * @deprecated These options will be ignored. Use `pluginReactOptions` now for everything and\n   *   override includes in order to transpile node_modules pluginBabelOptions will be removed in\n   *   the next major version. To configure babel, use `pluginReactOptions.babel`.\n   */\n  pluginBabelOptions?: Record<string, unknown>;\n};\n\ntype FrameworkName = CompatibleString<'@storybook/react-native-web-vite'>;\n\n/** The interface for Storybook configuration in `main.ts` files. */\nexport type StorybookConfig = Omit<StorybookConfigBase, 'framework'> & {\n  framework:\n    | FrameworkName\n    | {\n        name: FrameworkName;\n        options: FrameworkOptions;\n      };\n};\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/src/vite-plugin.ts",
    "content": "import { rnw } from 'vite-plugin-rnw';\nimport tsconfigPaths from 'vite-tsconfig-paths';\n\nexport const storybookReactNativeWeb = () => {\n  return [\n    tsconfigPaths(),\n    rnw({\n      jsxRuntime: 'automatic',\n    }),\n  ];\n};\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/template/cli/.eslintrc.json",
    "content": "{\n  \"rules\": {\n    \"import/extensions\": \"off\",\n    \"react/no-unknown-property\": \"off\",\n    \"react/react-in-jsx-scope\": \"off\"\n  }\n}\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/template/cli/js/Button.jsx",
    "content": "import PropTypes from 'prop-types';\nimport { StyleSheet, Text, TouchableOpacity, View } from 'react-native';\n\n/** Primary UI component for user interaction */\nexport const Button = ({\n  primary = false,\n  size = 'medium',\n  backgroundColor,\n  label,\n  style,\n  onPress,\n}) => {\n  const modeStyle = primary ? styles.primary : styles.secondary;\n  const textModeStyle = primary ? styles.primaryText : styles.secondaryText;\n\n  const sizeStyle = styles[size];\n  const textSizeStyle = textSizeStyles[size];\n\n  return (\n    <TouchableOpacity accessibilityRole=\"button\" activeOpacity={0.6} onPress={onPress}>\n      <View\n        style={[\n          styles.button,\n          modeStyle,\n          sizeStyle,\n          style,\n          !!backgroundColor && { backgroundColor },\n          { borderColor: 'black' },\n        ]}\n      >\n        <Text style={[textModeStyle, textSizeStyle]}>{label}</Text>\n      </View>\n    </TouchableOpacity>\n  );\n};\n\nconst styles = StyleSheet.create({\n  button: {\n    borderWidth: 0,\n    borderRadius: 48,\n  },\n  buttonText: {\n    fontWeight: '700',\n    lineHeight: 1,\n  },\n  primary: {\n    backgroundColor: '#555ab9',\n  },\n  primaryText: {\n    color: 'white',\n  },\n  secondary: {\n    backgroundColor: 'transparent',\n    borderColor: 'rgba(0, 0, 0, 0.15)',\n    color: '#333',\n    borderWidth: 1,\n  },\n  secondaryText: {\n    color: '#333',\n  },\n  small: {\n    paddingVertical: 10,\n    paddingHorizontal: 16,\n  },\n  smallText: {\n    fontSize: 12,\n  },\n  medium: {\n    paddingVertical: 11,\n    paddingHorizontal: 20,\n  },\n  mediumText: {\n    fontSize: 14,\n  },\n  large: {\n    paddingVertical: 12,\n    paddingHorizontal: 24,\n  },\n  largeText: {\n    fontSize: 16,\n  },\n});\n\nconst textSizeStyles = {\n  small: styles.smallText,\n  medium: styles.mediumText,\n  large: styles.largeText,\n};\n\nButton.propTypes = {\n  /** Is this the principal call to action on the page? */\n  primary: PropTypes.bool,\n  /** What background color to use */\n  backgroundColor: PropTypes.string,\n  /** How large should the button be? */\n  size: PropTypes.oneOf(['small', 'medium', 'large']),\n  /** Button contents */\n  label: PropTypes.string.isRequired,\n  /** Optional click handler */\n  onPress: PropTypes.func,\n  /** Optional extra styles */\n  style: PropTypes.object,\n};\n\nButton.defaultProps = {\n  backgroundColor: null,\n  primary: false,\n  size: 'medium',\n  onClick: undefined,\n};\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/template/cli/js/Button.stories.jsx",
    "content": "import { View } from 'react-native';\nimport { fn } from 'storybook/test';\n\nimport { Button } from './Button';\n\nconst meta = {\n  title: 'Example/Button',\n  component: Button,\n  decorators: [\n    (Story) => (\n      <View style={{ flex: 1, alignItems: 'flex-start' }}>\n        <Story />\n      </View>\n    ),\n  ],\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  // Use `fn` to spy on the onPress arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onPress: fn() },\n};\n\nexport default meta;\n\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/template/cli/js/Header.jsx",
    "content": "import PropTypes from 'prop-types';\nimport { StyleSheet, Text, View } from 'react-native';\n\nimport { Button } from './Button';\n\nexport const Header = ({ user, onLogin, onLogout, onCreateAccount }) => (\n  <View>\n    <View style={styles.wrapper}>\n      <View style={styles.logoContainer}>\n        <Text style={styles.h1}>Acme</Text>\n      </View>\n\n      <View style={styles.buttonContainer}>\n        {user ? (\n          <>\n            <Text>Welcome, </Text>\n            <Text style={styles.userName}>{user.name}!</Text>\n\n            <Button style={styles.button} size=\"small\" onPress={onLogout} label=\"Log out\" />\n          </>\n        ) : (\n          <>\n            <Button style={styles.button} size=\"small\" onPress={onLogin} label=\"Log in\" />\n            <Button\n              style={styles.button}\n              primary\n              size=\"small\"\n              onPress={onCreateAccount}\n              label=\"Sign up\"\n            />\n          </>\n        )}\n      </View>\n    </View>\n  </View>\n);\n\nconst styles = StyleSheet.create({\n  wrapper: {\n    borderBottomWidth: 1,\n    borderBottomColor: 'rgba(0, 0, 0, 0.1)',\n    paddingVertical: 15,\n    paddingHorizontal: 20,\n    flexDirection: 'row',\n    justifyContent: 'space-between',\n  },\n  h1: {\n    fontWeight: '900',\n    fontSize: 20,\n    marginTop: 6,\n    marginBottom: 6,\n    marginLeft: 10,\n    color: 'black',\n    alignSelf: 'flex-start',\n  },\n  logoContainer: {\n    flexDirection: 'row',\n    alignItems: 'center',\n  },\n  button: {\n    marginLeft: 10,\n  },\n  buttonContainer: {\n    flexDirection: 'row',\n    alignItems: 'center',\n  },\n  userName: {\n    fontWeight: '700',\n  },\n});\n\nHeader.propTypes = {\n  user: PropTypes.shape({\n    name: PropTypes.string.isRequired,\n  }),\n  onLogin: PropTypes.func.isRequired,\n  onLogout: PropTypes.func.isRequired,\n  onCreateAccount: PropTypes.func.isRequired,\n};\n\nHeader.defaultProps = {\n  user: null,\n};\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/template/cli/js/Header.stories.jsx",
    "content": "import { Header } from './Header';\n\nconst meta = {\n  title: 'Example/Header',\n  component: Header,\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n};\n\nexport default meta;\n\nexport const LoggedIn = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n    onLogin: () => {},\n    onLogout: () => {},\n    onCreateAccount: () => {},\n  },\n};\n\nexport const LoggedOut = {\n  args: {\n    onLogin: () => {},\n    onLogout: () => {},\n    onCreateAccount: () => {},\n  },\n};\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/template/cli/js/Page.jsx",
    "content": "import { useState } from 'react';\n\nimport { Linking, StyleSheet, Text, View } from 'react-native';\n\nimport { Header } from './Header';\n\nexport const Page = () => {\n  const [user, setUser] = useState();\n\n  return (\n    <View>\n      <Header\n        user={user}\n        onLogin={() => setUser({ name: 'Jane Doe' })}\n        onLogout={() => setUser(undefined)}\n        onCreateAccount={() => setUser({ name: 'Jane Doe' })}\n      />\n\n      <View style={styles.section}>\n        <Text role=\"heading\" style={styles.h2}>\n          Pages in Storybook\n        </Text>\n\n        <Text style={styles.p}>\n          We recommend building UIs with a{' '}\n          <Text\n            style={[styles.a, { fontWeight: 'bold' }]}\n            role=\"link\"\n            onPress={() => {\n              Linking.openURL('https://componentdriven.org');\n            }}\n          >\n            <Text>component-driven</Text>\n          </Text>{' '}\n          process starting with atomic components and ending with pages.\n        </Text>\n\n        <Text style={styles.p}>\n          Render pages with mock data. This makes it easy to build and review page states without\n          needing to navigate to them in your app. Here are some handy patterns for managing page\n          data in Storybook:\n        </Text>\n\n        <View>\n          <Text>\n            Use a higher-level connected component. Storybook helps you compose such data from the\n            \"args\" of child component stories\n          </Text>\n\n          <Text>\n            Assemble data in the page component from your services. You can mock these services out\n            using Storybook.\n          </Text>\n        </View>\n\n        <Text style={styles.p}>\n          Get a guided tutorial on component-driven development at{' '}\n          <Text\n            style={styles.a}\n            role=\"link\"\n            onPress={() => {\n              Linking.openURL('https://storybook.js.org/tutorials/');\n            }}\n          >\n            Storybook tutorials\n          </Text>\n          . Read more in the{' '}\n          <Text\n            style={styles.a}\n            role=\"link\"\n            onPress={() => {\n              Linking.openURL('https://storybook.js.org/docs');\n            }}\n          >\n            docs\n          </Text>\n          .\n        </Text>\n\n        <View style={styles.tipWrapper}>\n          <View style={styles.tip}>\n            <Text style={styles.tipText}>Tip </Text>\n          </View>\n\n          <Text>Adjust the width of the canvas with the </Text>\n\n          <Text>Viewports addon in the toolbar</Text>\n        </View>\n      </View>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  section: {\n    fontFamily: \"'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif\",\n    fontSize: 14,\n    lineHeight: 24,\n    paddingVertical: 48,\n    paddingHorizontal: 20,\n    marginHorizontal: 'auto',\n    maxWidth: 600,\n    color: '#333',\n  },\n\n  h2: {\n    fontWeight: '900',\n    fontSize: 32,\n    lineHeight: 1,\n    marginBottom: 4,\n  },\n\n  p: {\n    marginVertical: 16,\n    marginHorizontal: 0,\n  },\n\n  a: {\n    color: '#1a237e',\n    textDecorationLine: 'underline',\n  },\n\n  ul: {\n    paddingLeft: 30,\n    marginVertical: 16,\n  },\n\n  li: {\n    marginBottom: 8,\n  },\n\n  tip: {\n    alignSelf: 'flex-start',\n    borderRadius: 16,\n    backgroundColor: '#e7fdd8',\n    paddingVertical: 4,\n    paddingHorizontal: 12,\n    marginRight: 10,\n    marginBottom: 4,\n  },\n  tipText: {\n    fontSize: 11,\n    lineHeight: 12,\n    fontWeight: '700',\n    color: '#1a237e',\n  },\n\n  tipWrapper: {\n    fontSize: 13,\n    lineHeight: 20,\n    marginTop: 40,\n    marginBottom: 40,\n    flexDirection: 'row',\n    flexWrap: 'wrap',\n  },\n\n  tipWrapperSvg: {\n    height: 12,\n    width: 12,\n    marginRight: 4,\n    marginTop: 3,\n  },\n});\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/template/cli/js/Page.stories.jsx",
    "content": "import { expect, userEvent, within } from 'storybook/test';\n\nimport { Page } from './Page';\n\nconst meta = {\n  title: 'Example/Page',\n  component: Page,\n};\n\nexport default meta;\n\nexport const LoggedIn = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n\nexport const LoggedOut = {};\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/template/cli/ts/Button.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-native-web-vite';\n\nimport { View } from 'react-native';\nimport { fn } from 'storybook/test';\n\nimport { Button } from './Button';\n\nconst meta = {\n  title: 'Example/Button',\n  component: Button,\n  decorators: [\n    (Story) => (\n      <View style={{ flex: 1, alignItems: 'flex-start' }}>\n        <Story />\n      </View>\n    ),\n  ],\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  // Use `fn` to spy on the onPress arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onPress: fn() },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large: Story = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small: Story = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/template/cli/ts/Button.tsx",
    "content": "import type { StyleProp, ViewStyle } from 'react-native';\nimport { StyleSheet, Text, TouchableOpacity, View } from 'react-native';\n\nexport interface ButtonProps {\n  /** Is this the principal call to action on the page? */\n  primary?: boolean;\n  /** What background color to use */\n  backgroundColor?: string;\n  /** How large should the button be? */\n  size?: 'small' | 'medium' | 'large';\n  /** Button contents */\n  label: string;\n  /** Optional click handler */\n  onPress?: () => void;\n  style?: StyleProp<ViewStyle>;\n}\n\n/** Primary UI component for user interaction */\nexport const Button = ({\n  primary = false,\n  size = 'medium',\n  backgroundColor,\n  label,\n  style,\n  onPress,\n}: ButtonProps) => {\n  const modeStyle = primary ? styles.primary : styles.secondary;\n  const textModeStyle = primary ? styles.primaryText : styles.secondaryText;\n\n  const sizeStyle = styles[size];\n  const textSizeStyle = textSizeStyles[size];\n\n  return (\n    <TouchableOpacity accessibilityRole=\"button\" activeOpacity={0.6} onPress={onPress}>\n      <View\n        style={[\n          styles.button,\n          modeStyle,\n          sizeStyle,\n          style,\n          !!backgroundColor && { backgroundColor },\n          { borderColor: 'black' },\n        ]}\n      >\n        <Text style={[textModeStyle, textSizeStyle]}>{label}</Text>\n      </View>\n    </TouchableOpacity>\n  );\n};\n\nconst styles = StyleSheet.create({\n  button: {\n    borderWidth: 0,\n    borderRadius: 48,\n  },\n  buttonText: {\n    fontWeight: '700',\n    lineHeight: 1,\n  },\n  primary: {\n    backgroundColor: '#555ab9',\n  },\n  primaryText: {\n    color: 'white',\n  },\n  secondary: {\n    backgroundColor: 'transparent',\n    borderColor: 'rgba(0, 0, 0, 0.15)',\n    color: '#333',\n    borderWidth: 1,\n  },\n  secondaryText: {\n    color: '#333',\n  },\n  small: {\n    paddingVertical: 10,\n    paddingHorizontal: 16,\n  },\n  smallText: {\n    fontSize: 12,\n  },\n  medium: {\n    paddingVertical: 11,\n    paddingHorizontal: 20,\n  },\n  mediumText: {\n    fontSize: 14,\n  },\n  large: {\n    paddingVertical: 12,\n    paddingHorizontal: 24,\n  },\n  largeText: {\n    fontSize: 16,\n  },\n});\n\nconst textSizeStyles = {\n  small: styles.smallText,\n  medium: styles.mediumText,\n  large: styles.largeText,\n};\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/template/cli/ts/Header.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-native-web-vite';\n\nimport { Header } from './Header';\n\nconst meta = {\n  title: 'Example/Header',\n  component: Header,\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n} satisfies Meta<typeof Header>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const LoggedIn: Story = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n    onLogin: () => {},\n    onLogout: () => {},\n    onCreateAccount: () => {},\n  },\n};\n\nexport const LoggedOut: Story = {\n  args: {\n    onLogin: () => {},\n    onLogout: () => {},\n    onCreateAccount: () => {},\n  },\n};\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/template/cli/ts/Header.tsx",
    "content": "import { StyleSheet, Text, View } from 'react-native';\n\nimport { Button } from './Button';\n\nexport type HeaderProps = {\n  user?: { name: string };\n  onLogin: () => void;\n  onLogout: () => void;\n  onCreateAccount: () => void;\n};\n\nexport const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => (\n  <View>\n    <View style={styles.wrapper}>\n      <View style={styles.logoContainer}>\n        <Text style={styles.h1}>Acme</Text>\n      </View>\n      <View style={styles.buttonContainer}>\n        {user ? (\n          <>\n            <Text>Welcome, </Text>\n            <Text style={styles.userName}>{user.name}!</Text>\n\n            <Button style={styles.button} size=\"small\" onPress={onLogout} label=\"Log out\" />\n          </>\n        ) : (\n          <>\n            <Button style={styles.button} size=\"small\" onPress={onLogin} label=\"Log in\" />\n            <Button\n              style={styles.button}\n              primary\n              size=\"small\"\n              onPress={onCreateAccount}\n              label=\"Sign up\"\n            />\n          </>\n        )}\n      </View>\n    </View>\n  </View>\n);\n\nconst styles = StyleSheet.create({\n  wrapper: {\n    borderBottomWidth: 1,\n    borderBottomColor: 'rgba(0, 0, 0, 0.1)',\n    paddingVertical: 15,\n    paddingHorizontal: 20,\n    flexDirection: 'row',\n    justifyContent: 'space-between',\n  },\n  h1: {\n    fontWeight: '900',\n    fontSize: 20,\n    marginTop: 6,\n    marginBottom: 6,\n    marginLeft: 10,\n    color: 'black',\n    alignSelf: 'flex-start',\n  },\n  logoContainer: {\n    flexDirection: 'row',\n    alignItems: 'center',\n  },\n  button: {\n    marginLeft: 10,\n  },\n  buttonContainer: {\n    flexDirection: 'row',\n    alignItems: 'center',\n  },\n  userName: {\n    fontWeight: '700',\n  },\n});\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/template/cli/ts/Page.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-native-web-vite';\n\nimport { expect, userEvent, within } from 'storybook/test';\n\nimport { Page } from './Page';\n\nconst meta = {\n  title: 'Example/Page',\n  component: Page,\n} satisfies Meta<typeof Page>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const LoggedIn: Story = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n\nexport const LoggedOut: Story = {};\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/template/cli/ts/Page.tsx",
    "content": "import { useState } from 'react';\n\nimport { Linking, StyleSheet, Text, View } from 'react-native';\n\nimport { Header } from './Header';\n\nexport const Page = () => {\n  const [user, setUser] = useState<{ name: string } | undefined>();\n\n  return (\n    <View>\n      <Header\n        user={user}\n        onLogin={() => setUser({ name: 'Jane Doe' })}\n        onLogout={() => setUser(undefined)}\n        onCreateAccount={() => setUser({ name: 'Jane Doe' })}\n      />\n\n      <View style={styles.section}>\n        <Text role=\"heading\" style={styles.h2}>\n          Pages in Storybook\n        </Text>\n        <Text style={styles.p}>\n          We recommend building UIs with a{' '}\n          <Text\n            style={[styles.a, { fontWeight: 'bold' }]}\n            role=\"link\"\n            onPress={() => {\n              Linking.openURL('https://componentdriven.org');\n            }}\n          >\n            <Text>component-driven</Text>\n          </Text>{' '}\n          process starting with atomic components and ending with pages.\n        </Text>\n        <Text style={styles.p}>\n          Render pages with mock data. This makes it easy to build and review page states without\n          needing to navigate to them in your app. Here are some handy patterns for managing page\n          data in Storybook:\n        </Text>\n        <View>\n          <Text>\n            Use a higher-level connected component. Storybook helps you compose such data from the\n            \"args\" of child component stories\n          </Text>\n          <Text>\n            Assemble data in the page component from your services. You can mock these services out\n            using Storybook.\n          </Text>\n        </View>\n        <Text style={styles.p}>\n          Get a guided tutorial on component-driven development at{' '}\n          <Text\n            style={styles.a}\n            role=\"link\"\n            onPress={() => {\n              Linking.openURL('https://storybook.js.org/tutorials/');\n            }}\n          >\n            Storybook tutorials\n          </Text>\n          . Read more in the{' '}\n          <Text\n            style={styles.a}\n            role=\"link\"\n            onPress={() => {\n              Linking.openURL('https://storybook.js.org/docs');\n            }}\n          >\n            docs\n          </Text>\n          .\n        </Text>\n        <View style={styles.tipWrapper}>\n          <View style={styles.tip}>\n            <Text style={styles.tipText}>Tip </Text>\n          </View>\n          <Text>Adjust the width of the canvas with the </Text>\n          <Text>Viewports addon in the toolbar</Text>\n        </View>\n      </View>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  section: {\n    fontFamily: \"'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif\",\n    fontSize: 14,\n    lineHeight: 24,\n    paddingVertical: 48,\n    paddingHorizontal: 20,\n    marginHorizontal: 'auto',\n    maxWidth: 600,\n    color: '#333',\n  },\n\n  h2: {\n    fontWeight: '900',\n    fontSize: 32,\n    lineHeight: 1,\n    marginBottom: 4,\n  },\n\n  p: {\n    marginVertical: 16,\n    marginHorizontal: 0,\n  },\n\n  a: {\n    color: '#1a237e',\n    textDecorationLine: 'underline',\n  },\n\n  ul: {\n    paddingLeft: 30,\n    marginVertical: 16,\n  },\n\n  li: {\n    marginBottom: 8,\n  },\n\n  tip: {\n    alignSelf: 'flex-start',\n    borderRadius: 16,\n    backgroundColor: '#e7fdd8',\n    paddingVertical: 4,\n    paddingHorizontal: 12,\n    marginRight: 10,\n    marginBottom: 4,\n  },\n  tipText: {\n    fontSize: 11,\n    lineHeight: 12,\n    fontWeight: '700',\n    color: '#1a237e',\n  },\n\n  tipWrapper: {\n    fontSize: 13,\n    lineHeight: 20,\n    marginTop: 40,\n    marginBottom: 40,\n    flexDirection: 'row',\n    flexWrap: 'wrap',\n  },\n\n  tipWrapperSvg: {\n    height: 12,\n    width: 12,\n    marginRight: 4,\n    marginTop: 3,\n  },\n});\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"storybook/internal/*\": [\"../../lib/cli/core/*\"]\n    },\n    \"rootDir\": \"./src\"\n  },\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/frameworks/react-native-web-vite/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/frameworks/react-vite/README.md",
    "content": "# Storybook for React & Vite\n\nDevelop, document, and test UI components in isolation.\n\nSee [documentation](https://storybook.js.org/docs/get-started/frameworks/react-vite?renderer=react&ref=readme) for installation instructions, usage examples, APIs, and more.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/frameworks/react-vite/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n      },\n      {\n        exportEntries: ['./node'],\n        entryPoint: './src/node/index.ts',\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/frameworks/react-vite/package.json",
    "content": "{\n  \"name\": \"@storybook/react-vite\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook for React and Vite: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-framework\",\n    \"react\",\n    \"vite\",\n    \"component\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/frameworks/react-vite\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/frameworks/react-vite\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./node\": {\n      \"types\": \"./dist/node/index.d.ts\",\n      \"code\": \"./src/node/index.ts\",\n      \"default\": \"./dist/node/index.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./preset\": {\n      \"types\": \"./dist/preset.d.ts\",\n      \"code\": \"./src/preset.ts\",\n      \"default\": \"./dist/preset.js\"\n    }\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"template/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@joshwooding/vite-plugin-react-docgen-typescript\": \"^0.7.0\",\n    \"@rollup/pluginutils\": \"^5.0.2\",\n    \"@storybook/builder-vite\": \"workspace:*\",\n    \"@storybook/react\": \"workspace:*\",\n    \"empathic\": \"^2.0.0\",\n    \"magic-string\": \"^0.30.0\",\n    \"react-docgen\": \"^8.0.0\",\n    \"resolve\": \"^1.22.8\",\n    \"tsconfig-paths\": \"^4.2.0\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.19.1\",\n    \"typescript\": \"^5.9.3\",\n    \"vite\": \"^7.0.4\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"storybook\": \"workspace:^\",\n    \"vite\": \"^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/frameworks/react-vite/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/frameworks/react-vite/project.json",
    "content": "{\n  \"name\": \"react-vite\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/frameworks/react-vite/src/index.ts",
    "content": "export * from '@storybook/react';\nexport { __definePreview as definePreview } from '@storybook/react';\n\nexport * from './types.ts';\n"
  },
  {
    "path": "code/frameworks/react-vite/src/node/index.ts",
    "content": "import type { StorybookConfig } from '../types.ts';\n\nexport function defineMain(config: StorybookConfig) {\n  return config;\n}\n\nexport type { StorybookConfig };\n"
  },
  {
    "path": "code/frameworks/react-vite/src/plugins/docgen-handlers/actualNameHandler.ts",
    "content": "/**\n * This is heavily based on the react-docgen `displayNameHandler`\n * (https://github.com/reactjs/react-docgen/blob/26c90c0dd105bf83499a83826f2a6ff7a724620d/src/handlers/displayNameHandler.ts)\n * but instead defines an `actualName` property on the generated docs that is taken first from the\n * component's actual name. This addresses an issue where the name that the generated docs are\n * stored under is incorrectly named with the `displayName` and not the component's actual name.\n *\n * This is inspired by `actualNameHandler` from\n * https://github.com/storybookjs/babel-plugin-react-docgen, but is modified directly from\n * displayNameHandler, using the same approach as babel-plugin-react-docgen.\n */\nimport type { Handler, NodePath, babelTypes as t } from 'react-docgen';\nimport { utils } from 'react-docgen';\n\nconst { getNameOrValue, isReactForwardRefCall } = utils;\n\nconst actualNameHandler: Handler = function actualNameHandler(documentation, componentDefinition) {\n  documentation.set('definedInFile', componentDefinition.hub.file.opts.filename);\n\n  if (\n    (componentDefinition.isClassDeclaration() || componentDefinition.isFunctionDeclaration()) &&\n    componentDefinition.has('id')\n  ) {\n    documentation.set(\n      'actualName',\n      getNameOrValue(componentDefinition.get('id') as NodePath<t.Identifier>)\n    );\n  } else if (\n    componentDefinition.isArrowFunctionExpression() ||\n    componentDefinition.isFunctionExpression() ||\n    isReactForwardRefCall(componentDefinition)\n  ) {\n    let currentPath: NodePath = componentDefinition;\n\n    while (currentPath.parentPath) {\n      if (currentPath.parentPath.isVariableDeclarator()) {\n        documentation.set('actualName', getNameOrValue(currentPath.parentPath.get('id')));\n        return;\n      }\n      if (currentPath.parentPath.isAssignmentExpression()) {\n        const leftPath = currentPath.parentPath.get('left');\n\n        if (leftPath.isIdentifier() || leftPath.isLiteral()) {\n          documentation.set('actualName', getNameOrValue(leftPath));\n          return;\n        }\n      }\n\n      currentPath = currentPath.parentPath;\n    }\n    // Could not find an actual name\n    documentation.set('actualName', '');\n  }\n};\n\nexport default actualNameHandler;\n"
  },
  {
    "path": "code/frameworks/react-vite/src/plugins/docgen-resolver.ts",
    "content": "import { extname } from 'node:path';\n\nimport resolve from 'resolve';\n\nexport class ReactDocgenResolveError extends Error {\n  // the magic string that react-docgen uses to check if a module is ignored\n  readonly code = 'MODULE_NOT_FOUND';\n\n  constructor(filename: string) {\n    super(`'${filename}' was ignored by react-docgen.`);\n  }\n}\n\n/* The below code was copied from:\n * https://github.com/reactjs/react-docgen/blob/df2daa8b6f0af693ecc3c4dc49f2246f60552bcb/packages/react-docgen/src/importer/makeFsImporter.ts#L14-L63\n * because it wasn't exported from the react-docgen package.\n * watch out: when updating this code, also update the code in code/presets/react-webpack/src/loaders/docgen-resolver.ts\n */\n\n// These extensions are sorted by priority\n// resolve() will check for files in the order these extensions are sorted\nexport const RESOLVE_EXTENSIONS = [\n  '.js',\n  '.cts', // These were originally not in the code, I added them\n  '.mts', // These were originally not in the code, I added them\n  '.ctsx', // These were originally not in the code, I added them\n  '.mtsx', // These were originally not in the code, I added them\n  '.ts',\n  '.tsx',\n  '.mjs',\n  '.cjs',\n  '.mts',\n  '.cts',\n  '.jsx',\n];\n\nexport function defaultLookupModule(filename: string, basedir: string): string {\n  const resolveOptions = {\n    basedir,\n    extensions: RESOLVE_EXTENSIONS,\n    // we do not need to check core modules as we cannot import them anyway\n    includeCoreModules: false,\n  };\n\n  try {\n    return resolve.sync(filename, resolveOptions);\n  } catch (error) {\n    const ext = extname(filename);\n    let newFilename: string;\n\n    // if we try to import a JavaScript file it might be that we are actually pointing to\n    // a TypeScript file. This can happen in ES modules as TypeScript requires to import other\n    // TypeScript files with .js extensions\n    // https://www.typescriptlang.org/docs/handbook/esm-node.html#type-in-packagejson-and-new-extensions\n    switch (ext) {\n      case '.js':\n      case '.mjs':\n      case '.cjs': {\n        // Try .ts first, then fall back to .tsx (for React components using ESM-style .js imports)\n        const base = filename.slice(0, -2);\n        try {\n          return resolve.sync(`${base}ts`, { ...resolveOptions, extensions: [] });\n        } catch {\n          newFilename = `${base}tsx`;\n        }\n        break;\n      }\n\n      case '.jsx':\n        newFilename = `${filename.slice(0, -3)}tsx`;\n        break;\n      default:\n        throw error;\n    }\n\n    return resolve.sync(newFilename, {\n      ...resolveOptions,\n      // we already know that there is an extension at this point, so no need to check other extensions\n      extensions: [],\n    });\n  }\n}\n"
  },
  {
    "path": "code/frameworks/react-vite/src/plugins/react-docgen.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { getReactDocgenImporter } from './react-docgen.ts';\n\nconst reactDocgenMock = vi.hoisted(() => {\n  return {\n    makeFsImporter: vi.fn().mockImplementation((fn) => fn),\n  };\n});\n\nconst reactDocgenResolverMock = vi.hoisted(() => {\n  return {\n    defaultLookupModule: vi.fn(),\n  };\n});\n\nvi.mock('./docgen-resolver', async (importOriginal) => {\n  const actual = await importOriginal<typeof import('path')>();\n  return {\n    ...actual,\n    defaultLookupModule: reactDocgenResolverMock.defaultLookupModule,\n  };\n});\n\nvi.mock('react-docgen', async (importOriginal) => {\n  const actual = await importOriginal<typeof import('path')>();\n  return {\n    ...actual,\n    makeFsImporter: reactDocgenMock.makeFsImporter,\n  };\n});\n\ndescribe('getReactDocgenImporter function', () => {\n  it('should not map the request if a tsconfig path mapping is not available', () => {\n    const filename = './src/components/Button.tsx';\n    const basedir = '/src';\n    const imported = getReactDocgenImporter(undefined);\n    reactDocgenResolverMock.defaultLookupModule.mockImplementation((filen: string) => filen);\n    const result = (imported as any)(filename, basedir);\n    expect(result).toBe(filename);\n  });\n\n  it('should map the request', () => {\n    const mappedFile = './mapped-file.tsx';\n    const matchPath = vi.fn().mockReturnValue(mappedFile);\n    const filename = './src/components/Button.tsx';\n    const basedir = '/src';\n    const imported = getReactDocgenImporter(matchPath);\n    reactDocgenResolverMock.defaultLookupModule.mockImplementation((filen: string) => filen);\n    const result = (imported as any)(filename, basedir);\n    expect(result).toBe(mappedFile);\n  });\n});\n"
  },
  {
    "path": "code/frameworks/react-vite/src/plugins/react-docgen.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { relative, sep } from 'node:path';\n\nimport { getProjectRoot } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { createFilter } from '@rollup/pluginutils';\nimport * as find from 'empathic/find';\nimport MagicString from 'magic-string';\nimport type { Documentation } from 'react-docgen';\nimport {\n  ERROR_CODES,\n  builtinHandlers as docgenHandlers,\n  builtinResolvers as docgenResolver,\n  makeFsImporter,\n  parse,\n} from 'react-docgen';\nimport * as TsconfigPaths from 'tsconfig-paths';\nimport type { PluginOption } from 'vite';\n\nimport actualNameHandler from './docgen-handlers/actualNameHandler.ts';\nimport {\n  RESOLVE_EXTENSIONS,\n  ReactDocgenResolveError,\n  defaultLookupModule,\n} from './docgen-resolver.ts';\n\ntype DocObj = Documentation & { actualName: string; definedInFile: string };\n\n// TODO: None of these are able to be overridden, so `default` is aspirational here.\nconst defaultHandlers = Object.values(docgenHandlers).map((handler) => handler);\nconst defaultResolver = new docgenResolver.FindExportedDefinitionsResolver();\nconst handlers = [...defaultHandlers, actualNameHandler];\n\ntype Options = {\n  include?: string | RegExp | (string | RegExp)[];\n  exclude?: string | RegExp | (string | RegExp)[];\n};\n\nexport async function reactDocgen({\n  include = /\\.(mjs|tsx?|jsx?)$/,\n  exclude = [/node_modules\\/.*/],\n}: Options = {}): Promise<PluginOption> {\n  const cwd = process.cwd();\n  const filter = createFilter(include, exclude);\n\n  const projectRoot = getProjectRoot();\n  const tsconfigPath =\n    find.up('tsconfig.json', { cwd, last: projectRoot }) ??\n    find.up('tsconfig.base.json', { cwd, last: projectRoot }) ??\n    find.up('tsconfig.app.json', { cwd, last: projectRoot });\n  const tsconfig = TsconfigPaths.loadConfig(tsconfigPath);\n\n  let matchPath: TsconfigPaths.MatchPath | undefined;\n\n  if (tsconfig.resultType === 'success') {\n    logger.debug('Using tsconfig paths for react-docgen');\n    matchPath = TsconfigPaths.createMatchPath(tsconfig.absoluteBaseUrl, tsconfig.paths, [\n      'browser',\n      'module',\n      'main',\n    ]);\n  }\n\n  return {\n    name: 'storybook:react-docgen-plugin',\n    enforce: 'pre',\n    async transform(src: string, id: string) {\n      if (!filter(relative(cwd, id))) {\n        return;\n      }\n\n      try {\n        const docgenResults = parse(src, {\n          resolver: defaultResolver,\n          handlers,\n          importer: getReactDocgenImporter(matchPath),\n          filename: id,\n        }) as DocObj[];\n        const s = new MagicString(src);\n\n        docgenResults.forEach((info) => {\n          const { actualName, definedInFile, ...docgenInfo } = info;\n          if (actualName && definedInFile == id) {\n            const docNode = JSON.stringify(docgenInfo);\n            s.append(`;${actualName}.__docgenInfo=${docNode}`);\n          }\n        });\n\n        return {\n          code: s.toString(),\n          map: s.generateMap({ hires: true, source: id }),\n        };\n      } catch (e: any) {\n        // Ignore the error when react-docgen cannot find a react component\n        if (e.code === ERROR_CODES.MISSING_DEFINITION) {\n          return;\n        }\n        throw e;\n      }\n    },\n  };\n}\n\nexport function getReactDocgenImporter(matchPath: TsconfigPaths.MatchPath | undefined) {\n  return makeFsImporter((filename, basedir) => {\n    const mappedFilenameByPaths = (() => {\n      if (matchPath) {\n        const match = matchPath(filename);\n        return match || filename;\n      } else {\n        return filename;\n      }\n    })();\n\n    const result = defaultLookupModule(mappedFilenameByPaths, basedir);\n\n    if (result.includes(`${sep}react-native${sep}index.js`)) {\n      const replaced = result.replace(\n        `${sep}react-native${sep}index.js`,\n        `${sep}react-native-web${sep}dist${sep}index.js`\n      );\n      if (existsSync(replaced)) {\n        if (RESOLVE_EXTENSIONS.find((ext) => result.endsWith(ext))) {\n          return replaced;\n        }\n      }\n    }\n    if (RESOLVE_EXTENSIONS.find((ext) => result.endsWith(ext))) {\n      return result;\n    }\n\n    throw new ReactDocgenResolveError(filename);\n  });\n}\n"
  },
  {
    "path": "code/frameworks/react-vite/src/preset.ts",
    "content": "import type { PresetProperty } from 'storybook/internal/types';\n\nimport type { StorybookConfig } from './types.ts';\n\nexport const core: PresetProperty<'core'> = {\n  builder: import.meta.resolve('@storybook/builder-vite'),\n  renderer: import.meta.resolve('@storybook/react/preset'),\n};\n\nexport const viteFinal: NonNullable<StorybookConfig['viteFinal']> = async (config, { presets }) => {\n  const plugins = [...(config?.plugins ?? [])];\n\n  // Add docgen plugin\n  const { reactDocgen: reactDocgenOption, reactDocgenTypescriptOptions } = await presets.apply<any>(\n    'typescript',\n    {}\n  );\n  let typescriptPresent;\n\n  try {\n    import.meta.resolve('typescript');\n    typescriptPresent = true;\n  } catch (e) {\n    typescriptPresent = false;\n  }\n\n  if (reactDocgenOption === 'react-docgen-typescript' && typescriptPresent) {\n    plugins.push(\n      (await import('@joshwooding/vite-plugin-react-docgen-typescript')).default({\n        ...reactDocgenTypescriptOptions,\n        // We *need* this set so that RDT returns default values in the same format as react-docgen\n        savePropValueAsString: true,\n      })\n    );\n  }\n\n  // Add react-docgen so long as the option is not false\n  if (typeof reactDocgenOption === 'string') {\n    const { reactDocgen } = await import('./plugins/react-docgen.ts');\n    // Needs to run before the react plugin, so add to the front\n    plugins.unshift(\n      // If react-docgen is specified, use it for everything, otherwise only use it for non-typescript files\n      await reactDocgen({\n        include: reactDocgenOption === 'react-docgen' ? /\\.(mjs|tsx?|jsx?)$/ : /\\.(mjs|jsx?)$/,\n      })\n    );\n  }\n\n  return { ...config, plugins };\n};\n"
  },
  {
    "path": "code/frameworks/react-vite/src/types.ts",
    "content": "import type {\n  CompatibleString,\n  StorybookConfig as StorybookConfigBase,\n  TypescriptOptions as TypescriptOptionsBase,\n} from 'storybook/internal/types';\n\nimport type { BuilderOptions, StorybookConfigVite } from '@storybook/builder-vite';\n\nimport type docgenTypescript from '@joshwooding/vite-plugin-react-docgen-typescript';\n\ntype FrameworkName = CompatibleString<'@storybook/react-vite'>;\ntype BuilderName = CompatibleString<'@storybook/builder-vite'>;\n\nexport type FrameworkOptions = {\n  builder?: BuilderOptions;\n  strictMode?: boolean;\n  /**\n   * Use React's legacy root API to mount components\n   *\n   * React has introduced a new root API with React 18.x to enable a whole set of new features (e.g.\n   * concurrent features) If this flag is true, the legacy Root API is used to mount components to\n   * make it easier to migrate step by step to React 18.\n   *\n   * @default false\n   */\n  legacyRootApi?: boolean;\n};\n\ntype StorybookConfigFramework = {\n  framework:\n    | FrameworkName\n    | {\n        name: FrameworkName;\n        options: FrameworkOptions;\n      };\n  core?: StorybookConfigBase['core'] & {\n    builder?:\n      | BuilderName\n      | {\n          name: BuilderName;\n          options: BuilderOptions;\n        };\n  };\n  features?: StorybookConfigBase['features'] & {\n    /**\n     * Enable the experimental `.test` function in CSF Next\n     *\n     * @see https://storybook.js.org/docs/api/main-config/main-config-features#experimentaltestsyntax\n     */\n    experimentalTestSyntax?: boolean;\n  };\n};\n\ntype TypescriptOptions = TypescriptOptionsBase & {\n  /**\n   * Sets the type of Docgen when working with React and TypeScript\n   *\n   * @default `'react-docgen'`\n   */\n  reactDocgen: 'react-docgen-typescript' | 'react-docgen' | false;\n  /** Configures `@joshwooding/vite-plugin-react-docgen-typescript` */\n  reactDocgenTypescriptOptions: Parameters<typeof docgenTypescript>[0];\n};\n\n/** The interface for Storybook configuration in `main.ts` files. */\nexport type StorybookConfig = Omit<\n  StorybookConfigBase,\n  keyof StorybookConfigVite | keyof StorybookConfigFramework | 'typescript'\n> &\n  StorybookConfigVite &\n  StorybookConfigFramework & {\n    typescript?: Partial<TypescriptOptions>;\n  };\n"
  },
  {
    "path": "code/frameworks/react-vite/template/cli/.eslintrc.json",
    "content": "{\n  \"rules\": {\n    \"import/extensions\": \"off\"\n  }\n}\n"
  },
  {
    "path": "code/frameworks/react-vite/template/cli/js/Button.jsx",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nimport './button.css';\n\n/** Primary UI component for user interaction */\nexport const Button = ({\n  primary = false,\n  backgroundColor = null,\n  size = 'medium',\n  label,\n  ...props\n}) => {\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n  return (\n    <button\n      type=\"button\"\n      className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n      style={backgroundColor && { backgroundColor }}\n      {...props}\n    >\n      {label}\n    </button>\n  );\n};\n\nButton.propTypes = {\n  /** Is this the principal call to action on the page? */\n  primary: PropTypes.bool,\n  /** What background color to use */\n  backgroundColor: PropTypes.string,\n  /** How large should the button be? */\n  size: PropTypes.oneOf(['small', 'medium', 'large']),\n  /** Button contents */\n  label: PropTypes.string.isRequired,\n  /** Optional click handler */\n  onClick: PropTypes.func,\n};\n"
  },
  {
    "path": "code/frameworks/react-vite/template/cli/js/Button.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport { Button } from './Button';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export\nexport default {\n  title: 'Example/Button',\n  component: Button,\n  parameters: {\n    // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout\n    layout: 'centered',\n  },\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  // More on argTypes: https://storybook.js.org/docs/api/argtypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onClick: fn() },\n};\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/react-vite/template/cli/js/Header.jsx",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nimport { Button } from './Button';\nimport './header.css';\n\nexport const Header = ({ user = null, onLogin, onLogout, onCreateAccount }) => (\n  <header>\n    <div className=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        {user ? (\n          <>\n            <span className=\"welcome\">\n              Welcome, <b>{user.name}</b>!\n            </span>\n            <Button size=\"small\" onClick={onLogout} label=\"Log out\" />\n          </>\n        ) : (\n          <>\n            <Button size=\"small\" onClick={onLogin} label=\"Log in\" />\n            <Button primary size=\"small\" onClick={onCreateAccount} label=\"Sign up\" />\n          </>\n        )}\n      </div>\n    </div>\n  </header>\n);\n\nHeader.propTypes = {\n  user: PropTypes.shape({\n    name: PropTypes.string.isRequired,\n  }),\n  onLogin: PropTypes.func.isRequired,\n  onLogout: PropTypes.func.isRequired,\n  onCreateAccount: PropTypes.func.isRequired,\n};\n"
  },
  {
    "path": "code/frameworks/react-vite/template/cli/js/Header.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport { Header } from './Header';\n\nexport default {\n  title: 'Example/Header',\n  component: Header,\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n};\n\nexport const LoggedIn = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut = {};\n"
  },
  {
    "path": "code/frameworks/react-vite/template/cli/js/Page.jsx",
    "content": "import React from 'react';\n\nimport { Header } from './Header';\nimport './page.css';\n\nexport const Page = () => {\n  const [user, setUser] = React.useState();\n\n  return (\n    <article>\n      <Header\n        user={user}\n        onLogin={() => setUser({ name: 'Jane Doe' })}\n        onLogout={() => setUser(undefined)}\n        onCreateAccount={() => setUser({ name: 'Jane Doe' })}\n      />\n\n      <section className=\"storybook-page\">\n        <h2>Pages in Storybook</h2>\n        <p>\n          We recommend building UIs with a{' '}\n          <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n            <strong>component-driven</strong>\n          </a>{' '}\n          process starting with atomic components and ending with pages.\n        </p>\n        <p>\n          Render pages with mock data. This makes it easy to build and review page states without\n          needing to navigate to them in your app. Here are some handy patterns for managing page\n          data in Storybook:\n        </p>\n        <ul>\n          <li>\n            Use a higher-level connected component. Storybook helps you compose such data from the\n            \"args\" of child component stories\n          </li>\n          <li>\n            Assemble data in the page component from your services. You can mock these services out\n            using Storybook.\n          </li>\n        </ul>\n        <p>\n          Get a guided tutorial on component-driven development at{' '}\n          <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n            Storybook tutorials\n          </a>\n          . Read more in the{' '}\n          <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">\n            docs\n          </a>\n          .\n        </p>\n        <div className=\"tip-wrapper\">\n          <span className=\"tip\">Tip</span> Adjust the width of the canvas with the{' '}\n          <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n            <g fill=\"none\" fillRule=\"evenodd\">\n              <path\n                d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n                id=\"a\"\n                fill=\"#999\"\n              />\n            </g>\n          </svg>\n          Viewports addon in the toolbar\n        </div>\n      </section>\n    </article>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/react-vite/template/cli/js/Page.stories.js",
    "content": "import { expect, userEvent, within } from 'storybook/test';\n\nimport { Page } from './Page';\n\nexport default {\n  title: 'Example/Page',\n  component: Page,\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n};\n\nexport const LoggedOut = {};\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await expect(loginButton).not.toBeInTheDocument();\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n"
  },
  {
    "path": "code/frameworks/react-vite/template/cli/ts/Button.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { fn } from 'storybook/test';\n\nimport { Button } from './Button';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export\nconst meta = {\n  title: 'Example/Button',\n  component: Button,\n  parameters: {\n    // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout\n    layout: 'centered',\n  },\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  // More on argTypes: https://storybook.js.org/docs/api/argtypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onClick: fn() },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large: Story = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small: Story = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/react-vite/template/cli/ts/Button.tsx",
    "content": "import React from 'react';\n\nimport './button.css';\n\nexport interface ButtonProps {\n  /** Is this the principal call to action on the page? */\n  primary?: boolean;\n  /** What background color to use */\n  backgroundColor?: string;\n  /** How large should the button be? */\n  size?: 'small' | 'medium' | 'large';\n  /** Button contents */\n  label: string;\n  /** Optional click handler */\n  onClick?: () => void;\n}\n\n/** Primary UI component for user interaction */\nexport const Button = ({\n  primary = false,\n  size = 'medium',\n  backgroundColor,\n  label,\n  ...props\n}: ButtonProps) => {\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n  return (\n    <button\n      type=\"button\"\n      className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n      style={{ backgroundColor }}\n      {...props}\n    >\n      {label}\n    </button>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/react-vite/template/cli/ts/Header.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { fn } from 'storybook/test';\n\nimport { Header } from './Header';\n\nconst meta = {\n  title: 'Example/Header',\n  component: Header,\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n} satisfies Meta<typeof Header>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const LoggedIn: Story = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut: Story = {};\n"
  },
  {
    "path": "code/frameworks/react-vite/template/cli/ts/Header.tsx",
    "content": "import React from 'react';\n\nimport { Button } from './Button';\nimport './header.css';\n\ntype User = {\n  name: string;\n};\n\nexport interface HeaderProps {\n  user?: User;\n  onLogin?: () => void;\n  onLogout?: () => void;\n  onCreateAccount?: () => void;\n}\n\nexport const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => (\n  <header>\n    <div className=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        {user ? (\n          <>\n            <span className=\"welcome\">\n              Welcome, <b>{user.name}</b>!\n            </span>\n            <Button size=\"small\" onClick={onLogout} label=\"Log out\" />\n          </>\n        ) : (\n          <>\n            <Button size=\"small\" onClick={onLogin} label=\"Log in\" />\n            <Button primary size=\"small\" onClick={onCreateAccount} label=\"Sign up\" />\n          </>\n        )}\n      </div>\n    </div>\n  </header>\n);\n"
  },
  {
    "path": "code/frameworks/react-vite/template/cli/ts/Page.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { expect, userEvent, within } from 'storybook/test';\n\nimport { Page } from './Page';\n\nconst meta = {\n  title: 'Example/Page',\n  component: Page,\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n} satisfies Meta<typeof Page>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const LoggedOut: Story = {};\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn: Story = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await expect(loginButton).not.toBeInTheDocument();\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n"
  },
  {
    "path": "code/frameworks/react-vite/template/cli/ts/Page.tsx",
    "content": "import React from 'react';\n\nimport { Header } from './Header';\nimport './page.css';\n\ntype User = {\n  name: string;\n};\n\nexport const Page: React.FC = () => {\n  const [user, setUser] = React.useState<User>();\n\n  return (\n    <article>\n      <Header\n        user={user}\n        onLogin={() => setUser({ name: 'Jane Doe' })}\n        onLogout={() => setUser(undefined)}\n        onCreateAccount={() => setUser({ name: 'Jane Doe' })}\n      />\n\n      <section className=\"storybook-page\">\n        <h2>Pages in Storybook</h2>\n        <p>\n          We recommend building UIs with a{' '}\n          <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n            <strong>component-driven</strong>\n          </a>{' '}\n          process starting with atomic components and ending with pages.\n        </p>\n        <p>\n          Render pages with mock data. This makes it easy to build and review page states without\n          needing to navigate to them in your app. Here are some handy patterns for managing page\n          data in Storybook:\n        </p>\n        <ul>\n          <li>\n            Use a higher-level connected component. Storybook helps you compose such data from the\n            \"args\" of child component stories\n          </li>\n          <li>\n            Assemble data in the page component from your services. You can mock these services out\n            using Storybook.\n          </li>\n        </ul>\n        <p>\n          Get a guided tutorial on component-driven development at{' '}\n          <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n            Storybook tutorials\n          </a>\n          . Read more in the{' '}\n          <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">\n            docs\n          </a>\n          .\n        </p>\n        <div className=\"tip-wrapper\">\n          <span className=\"tip\">Tip</span> Adjust the width of the canvas with the{' '}\n          <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n            <g fill=\"none\" fillRule=\"evenodd\">\n              <path\n                d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n                id=\"a\"\n                fill=\"#999\"\n              />\n            </g>\n          </svg>\n          Viewports addon in the toolbar\n        </div>\n      </section>\n    </article>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/react-vite/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"storybook/internal/*\": [\"../../lib/cli/core/*\"]\n    },\n    \"rootDir\": \"./src\"\n  },\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/frameworks/react-vite/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/frameworks/react-webpack5/README.md",
    "content": "# Storybook for React & Webpack\n\nDevelop, document, and test UI components in isolation.\n\nSee [documentation](https://storybook.js.org/docs/get-started/frameworks/react-webpack5?renderer=react&ref=readme) for installation instructions, usage examples, APIs, and more.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/frameworks/react-webpack5/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./node'],\n        entryPoint: './src/node/index.ts',\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/frameworks/react-webpack5/package.json",
    "content": "{\n  \"name\": \"@storybook/react-webpack5\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook for React and Webpack: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-framework\",\n    \"react\",\n    \"webpack\",\n    \"component\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/frameworks/react-webpack5\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/frameworks/react-webpack5\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./node\": {\n      \"types\": \"./dist/node/index.d.ts\",\n      \"code\": \"./src/node/index.ts\",\n      \"default\": \"./dist/node/index.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"template/cli/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/builder-webpack5\": \"workspace:*\",\n    \"@storybook/preset-react-webpack\": \"workspace:*\",\n    \"@storybook/react\": \"workspace:*\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.19.1\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"storybook\": \"workspace:^\",\n    \"typescript\": \">= 4.9.x\"\n  },\n  \"peerDependenciesMeta\": {\n    \"typescript\": {\n      \"optional\": true\n    }\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/frameworks/react-webpack5/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/frameworks/react-webpack5/project.json",
    "content": "{\n  \"name\": \"react-webpack5\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/frameworks/react-webpack5/src/index.ts",
    "content": "export * from '@storybook/react';\nexport * from './types.ts';\nexport { __definePreview as definePreview } from '@storybook/react';\n"
  },
  {
    "path": "code/frameworks/react-webpack5/src/node/index.ts",
    "content": "import type { StorybookConfig } from '../types.ts';\n\nexport function defineMain(config: StorybookConfig) {\n  return config;\n}\n\nexport type { StorybookConfig };\n"
  },
  {
    "path": "code/frameworks/react-webpack5/src/preset.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport type { PresetProperty } from 'storybook/internal/types';\n\nimport { WebpackDefinePlugin } from '@storybook/builder-webpack5';\n\nimport type { StorybookConfig } from './types.ts';\n\nexport const addons: PresetProperty<'addons'> = [\n  fileURLToPath(import.meta.resolve('@storybook/preset-react-webpack')),\n];\n\nexport const core: PresetProperty<'core'> = {\n  builder: import.meta.resolve('@storybook/builder-webpack5'),\n  renderer: import.meta.resolve('@storybook/react/preset'),\n};\n\nexport const webpack: StorybookConfig['webpack'] = async (config, options) => {\n  config.resolve = config.resolve || {};\n\n  config.resolve.alias = {\n    ...config.resolve?.alias,\n    '@storybook/react': fileURLToPath(import.meta.resolve('@storybook/react')),\n  };\n\n  if (options.features?.developmentModeForBuild) {\n    config.plugins = [\n      // @ts-expect-error Ignore this error, because in the `webpack` preset the user actually hasn't defined a config yet.\n      ...config.plugins,\n      new WebpackDefinePlugin({\n        NODE_ENV: JSON.stringify('development'),\n      }),\n    ];\n  }\n\n  return config;\n};\n"
  },
  {
    "path": "code/frameworks/react-webpack5/src/types.ts",
    "content": "import type { CompatibleString } from 'storybook/internal/types';\n\nimport type {\n  BuilderOptions,\n  StorybookConfigWebpack,\n  TypescriptOptions as TypescriptOptionsBuilder,\n} from '@storybook/builder-webpack5';\nimport type {\n  ReactOptions,\n  StorybookConfig as StorybookConfigBase,\n  TypescriptOptions as TypescriptOptionsReact,\n} from '@storybook/preset-react-webpack';\n\ntype FrameworkName = CompatibleString<'@storybook/react-webpack5'>;\ntype BuilderName = CompatibleString<'@storybook/builder-webpack5'>;\n\nexport type FrameworkOptions = ReactOptions & {\n  builder?: BuilderOptions;\n};\n\ntype StorybookConfigFramework = {\n  framework:\n    | FrameworkName\n    | {\n        name: FrameworkName;\n        options: FrameworkOptions;\n      };\n  core?: StorybookConfigBase['core'] & {\n    builder?:\n      | BuilderName\n      | {\n          name: BuilderName;\n          options: BuilderOptions;\n        };\n  };\n  typescript?: Partial<TypescriptOptionsBuilder & TypescriptOptionsReact> &\n    StorybookConfigBase['typescript'];\n};\n\n/** The interface for Storybook configuration in `main.ts` files. */\nexport type StorybookConfig = Omit<\n  StorybookConfigBase,\n  keyof StorybookConfigWebpack | keyof StorybookConfigFramework\n> &\n  StorybookConfigWebpack &\n  StorybookConfigFramework;\n"
  },
  {
    "path": "code/frameworks/react-webpack5/template/cli/.eslintrc.json",
    "content": "{\n  \"rules\": {\n    \"import/extensions\": \"off\"\n  }\n}\n"
  },
  {
    "path": "code/frameworks/react-webpack5/template/cli/js/Button.jsx",
    "content": "import PropTypes from 'prop-types';\n\nimport './button.css';\n\n/** Primary UI component for user interaction */\nexport const Button = ({\n  primary = false,\n  backgroundColor = null,\n  size = 'medium',\n  label,\n  ...props\n}) => {\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n  return (\n    <button\n      type=\"button\"\n      className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n      style={backgroundColor && { backgroundColor }}\n      {...props}\n    >\n      {label}\n    </button>\n  );\n};\n\nButton.propTypes = {\n  /** Is this the principal call to action on the page? */\n  primary: PropTypes.bool,\n  /** What background color to use */\n  backgroundColor: PropTypes.string,\n  /** How large should the button be? */\n  size: PropTypes.oneOf(['small', 'medium', 'large']),\n  /** Button contents */\n  label: PropTypes.string.isRequired,\n  /** Optional click handler */\n  onClick: PropTypes.func,\n};\n"
  },
  {
    "path": "code/frameworks/react-webpack5/template/cli/js/Button.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport { Button } from './Button';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export\nexport default {\n  title: 'Example/Button',\n  component: Button,\n  parameters: {\n    // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout\n    layout: 'centered',\n  },\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  // More on argTypes: https://storybook.js.org/docs/api/argtypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onClick: fn() },\n};\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/react-webpack5/template/cli/js/Header.jsx",
    "content": "import PropTypes from 'prop-types';\n\nimport { Button } from './Button';\nimport './header.css';\n\nexport const Header = ({ user = null, onLogin, onLogout, onCreateAccount }) => (\n  <header>\n    <div className=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        {user ? (\n          <>\n            <span className=\"welcome\">\n              Welcome, <b>{user.name}</b>!\n            </span>\n            <Button size=\"small\" onClick={onLogout} label=\"Log out\" />\n          </>\n        ) : (\n          <>\n            <Button size=\"small\" onClick={onLogin} label=\"Log in\" />\n            <Button primary size=\"small\" onClick={onCreateAccount} label=\"Sign up\" />\n          </>\n        )}\n      </div>\n    </div>\n  </header>\n);\n\nHeader.propTypes = {\n  user: PropTypes.shape({\n    name: PropTypes.string.isRequired,\n  }),\n  onLogin: PropTypes.func.isRequired,\n  onLogout: PropTypes.func.isRequired,\n  onCreateAccount: PropTypes.func.isRequired,\n};\n"
  },
  {
    "path": "code/frameworks/react-webpack5/template/cli/js/Header.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport { Header } from './Header';\n\nexport default {\n  title: 'Example/Header',\n  component: Header,\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n};\n\nexport const LoggedIn = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut = {};\n"
  },
  {
    "path": "code/frameworks/react-webpack5/template/cli/js/Page.jsx",
    "content": "import React from 'react';\n\nimport { Header } from './Header';\nimport './page.css';\n\nexport const Page = () => {\n  const [user, setUser] = React.useState();\n\n  return (\n    <article>\n      <Header\n        user={user}\n        onLogin={() => setUser({ name: 'Jane Doe' })}\n        onLogout={() => setUser(undefined)}\n        onCreateAccount={() => setUser({ name: 'Jane Doe' })}\n      />\n\n      <section className=\"storybook-page\">\n        <h2>Pages in Storybook</h2>\n        <p>\n          We recommend building UIs with a{' '}\n          <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n            <strong>component-driven</strong>\n          </a>{' '}\n          process starting with atomic components and ending with pages.\n        </p>\n        <p>\n          Render pages with mock data. This makes it easy to build and review page states without\n          needing to navigate to them in your app. Here are some handy patterns for managing page\n          data in Storybook:\n        </p>\n        <ul>\n          <li>\n            Use a higher-level connected component. Storybook helps you compose such data from the\n            \"args\" of child component stories\n          </li>\n          <li>\n            Assemble data in the page component from your services. You can mock these services out\n            using Storybook.\n          </li>\n        </ul>\n        <p>\n          Get a guided tutorial on component-driven development at{' '}\n          <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n            Storybook tutorials\n          </a>\n          . Read more in the{' '}\n          <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">\n            docs\n          </a>\n          .\n        </p>\n        <div className=\"tip-wrapper\">\n          <span className=\"tip\">Tip</span> Adjust the width of the canvas with the{' '}\n          <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n            <g fill=\"none\" fillRule=\"evenodd\">\n              <path\n                d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n                id=\"a\"\n                fill=\"#999\"\n              />\n            </g>\n          </svg>\n          Viewports addon in the toolbar\n        </div>\n      </section>\n    </article>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/react-webpack5/template/cli/js/Page.stories.js",
    "content": "import { expect, userEvent, within } from 'storybook/test';\n\nimport { Page } from './Page';\n\nexport default {\n  title: 'Example/Page',\n  component: Page,\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n};\n\nexport const LoggedOut = {};\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await expect(loginButton).not.toBeInTheDocument();\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n"
  },
  {
    "path": "code/frameworks/react-webpack5/template/cli/ts/Button.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/react-webpack5';\n\nimport { fn } from 'storybook/test';\n\nimport { Button } from './Button';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export\nconst meta = {\n  title: 'Example/Button',\n  component: Button,\n  parameters: {\n    // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout\n    layout: 'centered',\n  },\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  // More on argTypes: https://storybook.js.org/docs/api/argtypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onClick: fn() },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large: Story = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small: Story = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/react-webpack5/template/cli/ts/Button.tsx",
    "content": "import './button.css';\n\nexport interface ButtonProps {\n  /** Is this the principal call to action on the page? */\n  primary?: boolean;\n  /** What background color to use */\n  backgroundColor?: string;\n  /** How large should the button be? */\n  size?: 'small' | 'medium' | 'large';\n  /** Button contents */\n  label: string;\n  /** Optional click handler */\n  onClick?: () => void;\n}\n\n/** Primary UI component for user interaction */\nexport const Button = ({\n  primary = false,\n  size = 'medium',\n  backgroundColor,\n  label,\n  ...props\n}: ButtonProps) => {\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n  return (\n    <button\n      type=\"button\"\n      className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n      style={{ backgroundColor }}\n      {...props}\n    >\n      {label}\n    </button>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/react-webpack5/template/cli/ts/Header.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/react-webpack5';\n\nimport { fn } from 'storybook/test';\n\nimport { Header } from './Header';\n\nconst meta = {\n  title: 'Example/Header',\n  component: Header,\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n} satisfies Meta<typeof Header>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const LoggedIn: Story = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut: Story = {};\n"
  },
  {
    "path": "code/frameworks/react-webpack5/template/cli/ts/Header.tsx",
    "content": "import { Button } from './Button';\nimport './header.css';\n\ntype User = {\n  name: string;\n};\n\nexport interface HeaderProps {\n  user?: User;\n  onLogin?: () => void;\n  onLogout?: () => void;\n  onCreateAccount?: () => void;\n}\n\nexport const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => (\n  <header>\n    <div className=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        {user ? (\n          <>\n            <span className=\"welcome\">\n              Welcome, <b>{user.name}</b>!\n            </span>\n            <Button size=\"small\" onClick={onLogout} label=\"Log out\" />\n          </>\n        ) : (\n          <>\n            <Button size=\"small\" onClick={onLogin} label=\"Log in\" />\n            <Button primary size=\"small\" onClick={onCreateAccount} label=\"Sign up\" />\n          </>\n        )}\n      </div>\n    </div>\n  </header>\n);\n"
  },
  {
    "path": "code/frameworks/react-webpack5/template/cli/ts/Page.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/react-webpack5';\n\nimport { expect, userEvent, within } from 'storybook/test';\n\nimport { Page } from './Page';\n\nconst meta = {\n  title: 'Example/Page',\n  component: Page,\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n} satisfies Meta<typeof Page>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const LoggedOut: Story = {};\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn: Story = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await expect(loginButton).not.toBeInTheDocument();\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n"
  },
  {
    "path": "code/frameworks/react-webpack5/template/cli/ts/Page.tsx",
    "content": "import React from 'react';\n\nimport { Header } from './Header';\nimport './page.css';\n\ntype User = {\n  name: string;\n};\n\nexport const Page: React.FC = () => {\n  const [user, setUser] = React.useState<User>();\n\n  return (\n    <article>\n      <Header\n        user={user}\n        onLogin={() => setUser({ name: 'Jane Doe' })}\n        onLogout={() => setUser(undefined)}\n        onCreateAccount={() => setUser({ name: 'Jane Doe' })}\n      />\n\n      <section className=\"storybook-page\">\n        <h2>Pages in Storybook</h2>\n        <p>\n          We recommend building UIs with a{' '}\n          <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n            <strong>component-driven</strong>\n          </a>{' '}\n          process starting with atomic components and ending with pages.\n        </p>\n        <p>\n          Render pages with mock data. This makes it easy to build and review page states without\n          needing to navigate to them in your app. Here are some handy patterns for managing page\n          data in Storybook:\n        </p>\n        <ul>\n          <li>\n            Use a higher-level connected component. Storybook helps you compose such data from the\n            \"args\" of child component stories\n          </li>\n          <li>\n            Assemble data in the page component from your services. You can mock these services out\n            using Storybook.\n          </li>\n        </ul>\n        <p>\n          Get a guided tutorial on component-driven development at{' '}\n          <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n            Storybook tutorials\n          </a>\n          . Read more in the{' '}\n          <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">\n            docs\n          </a>\n          .\n        </p>\n        <div className=\"tip-wrapper\">\n          <span className=\"tip\">Tip</span> Adjust the width of the canvas with the{' '}\n          <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n            <g fill=\"none\" fillRule=\"evenodd\">\n              <path\n                d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n                id=\"a\"\n                fill=\"#999\"\n              />\n            </g>\n          </svg>\n          Viewports addon in the toolbar\n        </div>\n      </section>\n    </article>\n  );\n};\n"
  },
  {
    "path": "code/frameworks/react-webpack5/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/frameworks/react-webpack5/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/frameworks/server-webpack5/README.md",
    "content": "# Storybook for Server\n\n---\n\nStorybook for Server is a UI development environment for your plain HTML snippets rendered by your server backend.\nWith it, you can visualize different states of your UI components and develop them interactively.\n\n![Storybook Screenshot](https://github.com/storybookjs/storybook/blob/main/media/storybook-intro.gif)\n\nStorybook runs outside of your app.\nSo you can develop UI components in isolation without worrying about app specific dependencies and requirements.\n\n## Getting Started\n\n```sh\ncd my-app\nnpx storybook@latest init -t server\n```\n\nTo configure the server that Storybook will connect to, export a global parameter `parameters.server.url` in `.storybook/preview.js`:\n\n```js\nexport const parameters = {\n  server: {\n    url: `http://localhost:${port}/storybook_preview`,\n  },\n};\n```\n\nThe URL you connect to should have the ability to render a story, see [server rendering](#server-rendering) below.\n\nFor more information visit: [storybook.js.org](https://storybook.js.org?ref=readme)\n\n## Writing Stories\n\nTo write a story, use whatever API is natural for your server-side rendering framework to generate set of JSON or YAML files of stories analogous to CSF files (see the [`server-kitchen-sink`](../../../test-storybooks/server-kitchen-sink/stories) example for ideas).\n\n```json\n{\n  \"title\": \"Component\",\n  \"parameters\": {\n    \"options\": { \"component\": \"my_widget\" }\n  },\n  \"stories\": [\n    {\n      \"name\": \"Default\",\n      \"parameters\": {\n        \"server\": { \"id\": \"path/of/your/story\" }\n      }\n    }\n  ]\n}\n```\n\nIn your `.storybook/main.js` you simply provide a glob specifying the location of those JSON files, e.g.\n\n```js\nexport default {\n  stories: ['../stories/**/*.stories.json'],\n};\n```\n\nNotice that the JSON does not specify a rendering function -- `@storybook/server` will instead call your `parameters.server.url` with the story's server id appended.\n\nFor example the JSON story above is requivalent to the CSF3 definition:\n\n```javascript\nexport default {\n  title: 'Component',\n  parameters: {\n    options: {\n      component: 'my_widget',\n    },\n  },\n};\n\nexport const Default = {\n  name: 'Default',\n  parameters: {\n    server: {\n      id: 'path/of/your/story\"',\n    },\n  },\n};\n```\n\nWith the story HTML will be fetched from the server by making a GET request to http://localhost/storybook_preview/path/of/your/story`\n\n### Ruby/Rails support\n\nIn particular the [View Component::Storybook](https://github.com/jonspalmer/view_component_storybook) gem provides a Ruby API for easily creating the above with a Ruby/Rails DSL (as well as providing a server rendering endpoint).\n\n## Server rendering\n\nThe server rendering side of things is relatively straightforward. When you browse to a story in the sidebar, Storybook will make a `fetch` request to `${parameters.server.url}/{parameters.server.id}` and display the HTML that is returned.\n\nYou need to ensure the route in your server app renders the appropriate HTML when called in that fashion.\n\n### Passing parameters to the server\n\nMany components are likely to be dynamic - responding to parameters that change their content or appearance. `@storybook\\server` has two mechanisms for passing those parameters to the server - `params` and `args`. Parameters defined in this way are appended to the fetch url as query string parameters. The server endpoint is responsible for interpreting those parameters and vary the returned html appropriately\n\n#### Constant parameters with `params`\n\nStatic parameters can be defined using the `params` story parameter. For example suppose you have a Button component that has a label and color options:\n\n```json\n{\n  \"title\": \"Buttons\",\n  \"stories\": [\n    {\n      \"name\": \"Red\",\n      \"parameters\": {\n        \"server\": {\n          \"id\": \"button\",\n          \"params\": { \"color\": \"red\", \"label\": \"Stop\" }\n        }\n      }\n    },\n    {\n      \"name\": \"Green\",\n      \"parameters\": {\n        \"server\": {\n          \"id\": \"button\",\n          \"params\": { \"color\": \"green\", \"label\": \"OK\" }\n        }\n      }\n    }\n  ]\n}\n```\n\nThe Red and Green story HTML will be fetched from the urls `server.url/controls/button?color=red&label=Stop` and `server.url/controls/button?color=green&label=OK`\n\nLike all story parameters server params can be defined in the default export and overridden in stories.\n\n```json\n{\n  \"title\": \"Buttons\",\n  \"parameters\": {\n    \"server\": {\n      \"params\": { \"color\": \"red\" }\n    }\n  },\n  \"stories\": [\n    {\n      \"name\": \"Default\",\n      \"parameters\": {\n        \"server\": {\n          \"id\": \"button\",\n          \"params\": { \"label\": \"Stop\" }\n        }\n      }\n    },\n    {\n      \"name\": \"Green\",\n      \"parameters\": {\n        \"server\": {\n          \"id\": \"button\",\n          \"params\": { \"color\": \"green\", \"label\": \"OK\" }\n        }\n      }\n    }\n  ]\n}\n```\n\n#### Dynamic parameters with `args` and Controls\n\nDynamic parameters can be defined using args and the Controls addon\n\n```json\n{\n  \"title\": \"Buttons\",\n  \"stories\": [\n    {\n      \"name\": \"Red\",\n      \"parameters\": {\n        \"server\": {\n          \"id\": \"button\"\n        }\n      },\n      \"args\": { \"color\": \"red\", \"label\": \"Stop\" }\n    },\n    {\n      \"name\": \"Green\",\n      \"parameters\": {\n        \"server\": {\n          \"id\": \"button\"\n        }\n      },\n      \"args\": { \"color\": \"green\", \"label\": \"Go\" }\n    }\n  ]\n}\n```\n\nStory args are passed to the server as url query parameters just like `params` except now they can be varied on the Controls addon panel.\n\nJust like CSF stories we can define `argTypes` to specify the controls used in the controls panel. `argTypes` can be defined at the default or story level.\n\n```json\n{\n  \"title\": \"Buttons\",\n  \"argTypes\": {\n    \"color\": { \"control\": { \"type\": \"color\" } }\n  },\n  \"stories\": [\n    {\n      \"name\": \"Red\",\n      \"parameters\": {\n        \"server\": {\n          \"id\": \"button\"\n        }\n      },\n      \"args\": { \"color\": \"red\", \"label\": \"Stop\" }\n    },\n    {\n      \"name\": \"Green\",\n      \"parameters\": {\n        \"server\": {\n          \"id\": \"button\"\n        }\n      },\n      \"args\": { \"color\": \"green\", \"label\": \"Go\" }\n    }\n  ]\n}\n```\n\n## Addon compatibility\n\nStorybook also comes with a lot of [addons](https://storybook.js.org/addons?ref=readme) and a great API to customize as you wish. As some addons assume the story is rendered in JS, they may not work with `@storybook/server` (yet!).\n\nMany addons that act on the manager side (such as `backgrounds` and `viewport`) will work out of the box with `@storybook/server` -- you can configure them with parameters written on the server as usual.\n\n### Controls\n\nTo configure controls, simple add `args` and `argTypes` keys to the story JSON much like you would CSF:\n\n```json\n{\n  \"title\": \"Controls\",\n  \"stories\": [\n    {\n      \"name\": \"Button\",\n      \"parameters\": {\n        \"server\": { \"id\": \"controls/button\" }\n      },\n      \"args\": { \"button_text\": \"Push Me\", \"color\": \"red\" },\n      \"argTypes\": { \"button_text\": { \"control\": { \"type\": \"color\" } } }\n    }\n  ]\n}\n```\n\nThe controls values will be added to your story URL as query parameters.\n\n### Actions\n\nTo use actions, use the `parameters.actions.handles` parameter:\n\n```json\n{\n  \"title\": \"Actions\",\n  \"stories\": [\n    {\n      \"name\": \"Button\",\n      \"parameters\": {\n        \"server\": { \"id\": \"actions/button\" },\n        \"actions\": {\n          \"handles\": [\"mouseover\", \"click .btn\"]\n        }\n      }\n    }\n  ]\n}\n```\n\n## Advanced Configuration\n\n### fetchStoryHtml\n\nFor control over how `@storybook/server` fetches Html from the server you can provide a `fetchStoryHtml` function as a parameter. You would typically set this in `.storybook/preview.js` but it's just a regular Storybook parameter so could be overridden at the stories or story level.\n\n```javascript\n// .storybook/preview.js\n\nconst fetchStoryHtml = async (url, path, params, context) => {\n  // Custom fetch implementation\n  // ....\n  return html;\n};\n\nexport const parameters = {\n  server: {\n    url: `http://localhost:${port}/storybook_preview`,\n    fetchStoryHtml,\n  },\n};\n```\n\n`fetchStoryHtml` should be an async function with the following signature\n\n```javascript\ntype FetchStoryHtmlType = (\n  url: string,\n  id: string,\n  params: any,\n  context: StoryContext\n) => Promise<string | Node>;\n```\n\n- url: Server url configured by the `parameters.server.url`\n- id: Id of the story being rendered given by `parameters.server.id`\n- params: Merged story params `parameters.server.params`and story args\n- context: The context of the story\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/frameworks/server-webpack5/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./node'],\n        entryPoint: './src/node/index.ts',\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/frameworks/server-webpack5/package.json",
    "content": "{\n  \"name\": \"@storybook/server-webpack5\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook for Server: View HTML snippets from a server in isolation with Hot Reloading.\",\n  \"keywords\": [\n    \"storybook\",\n    \"server\",\n    \"component\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/frameworks/server-webpack5\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/frameworks/server-webpack5\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./node\": {\n      \"types\": \"./dist/node/index.d.ts\",\n      \"code\": \"./src/node/index.ts\",\n      \"default\": \"./dist/node/index.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"template/cli/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/builder-webpack5\": \"workspace:*\",\n    \"@storybook/preset-server-webpack\": \"workspace:*\",\n    \"@storybook/server\": \"workspace:*\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.19.1\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"storybook\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/frameworks/server-webpack5/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/frameworks/server-webpack5/project.json",
    "content": "{\n  \"name\": \"server-webpack5\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/frameworks/server-webpack5/src/index.ts",
    "content": "export * from '@storybook/server';\nexport * from './types.ts';\n"
  },
  {
    "path": "code/frameworks/server-webpack5/src/node/index.ts",
    "content": "import type { StorybookConfig } from '../types.ts';\n\nexport function defineMain(config: StorybookConfig) {\n  return config;\n}\n\nexport type { StorybookConfig };\n"
  },
  {
    "path": "code/frameworks/server-webpack5/src/preset.ts",
    "content": "import type { PresetProperty } from 'storybook/internal/types';\n\nexport const addons: PresetProperty<'addons'> = [\n  import.meta.resolve('@storybook/preset-server-webpack'),\n];\n\nexport const core: PresetProperty<'core'> = {\n  builder: import.meta.resolve('@storybook/builder-webpack5'),\n  renderer: import.meta.resolve('@storybook/server/preset'),\n};\n"
  },
  {
    "path": "code/frameworks/server-webpack5/src/types.ts",
    "content": "import type { CompatibleString } from 'storybook/internal/types';\n\nimport type {\n  BuilderOptions,\n  StorybookConfigWebpack,\n  TypescriptOptions as TypescriptOptionsBuilder,\n} from '@storybook/builder-webpack5';\nimport type {\n  StorybookConfig as StorybookConfigBase,\n  TypescriptOptions as TypescriptOptionsReact,\n} from '@storybook/preset-server-webpack';\n\ntype FrameworkName = CompatibleString<'@storybook/server-webpack5'>;\ntype BuilderName = CompatibleString<'@storybook/builder-webpack5'>;\n\nexport type FrameworkOptions = {\n  builder?: BuilderOptions;\n};\n\ntype StorybookConfigFramework = {\n  framework:\n    | FrameworkName\n    | {\n        name: FrameworkName;\n        options: FrameworkOptions;\n      };\n  core?: StorybookConfigBase['core'] & {\n    builder?:\n      | BuilderName\n      | {\n          name: BuilderName;\n          options: BuilderOptions;\n        };\n  };\n  typescript?: Partial<TypescriptOptionsBuilder & TypescriptOptionsReact> &\n    StorybookConfigBase['typescript'];\n};\n\n/** The interface for Storybook configuration in `main.ts` files. */\nexport type StorybookConfig = Omit<\n  StorybookConfigBase,\n  keyof StorybookConfigWebpack | keyof StorybookConfigFramework\n> &\n  StorybookConfigWebpack &\n  StorybookConfigFramework;\n"
  },
  {
    "path": "code/frameworks/server-webpack5/template/cli/button.stories.json",
    "content": "{\n  \"title\": \"Example/Button\",\n  \"parameters\": {\n    \"server\": {\n      \"url\": \"https://storybook-server-demo.netlify.app/api\",\n      \"id\": \"button\"\n    }\n  },\n  \"args\": { \"label\": \"Button\" },\n  \"argTypes\": {\n    \"label\": { \"control\": \"text\" },\n    \"primary\": { \"control\": \"boolean\" },\n    \"backgroundColor\": { \"control\": \"color\" },\n    \"size\": {\n      \"control\": { \"type\": \"select\", \"options\": [\"small\", \"medium\", \"large\"] }\n    }\n  },\n  \"tags\": [\"autodocs\"],\n  \"stories\": [\n    {\n      \"name\": \"Primary\",\n      \"args\": { \"primary\": true }\n    },\n    {\n      \"name\": \"Secondary\"\n    },\n    {\n      \"name\": \"Large\",\n      \"args\": { \"size\": \"large\" }\n    },\n    {\n      \"name\": \"Small\",\n      \"args\": { \"size\": \"small\" }\n    }\n  ]\n}\n"
  },
  {
    "path": "code/frameworks/server-webpack5/template/cli/header.stories.json",
    "content": "{\n  \"title\": \"Example/Header\",\n  \"parameters\": {\n    \"server\": {\n      \"url\": \"https://storybook-server-demo.netlify.app/api\",\n      \"id\": \"header\"\n    }\n  },\n  \"stories\": [\n    {\n      \"name\": \"LoggedIn\",\n      \"args\": { \"user\": {} }\n    },\n    {\n      \"name\": \"LoggedOut\"\n    }\n  ]\n}\n"
  },
  {
    "path": "code/frameworks/server-webpack5/template/cli/page.stories.yaml",
    "content": "title: 'Example/Page'\nparameters:\n  server:\n    url: 'https://storybook-server-demo.netlify.app/api'\n    id: 'page'\nstories:\n  - name: 'LoggedIn'\n    args:\n      user: {}\n  - name: 'LoggedOut'\n"
  },
  {
    "path": "code/frameworks/server-webpack5/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/frameworks/server-webpack5/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/frameworks/svelte-vite/README.md",
    "content": "# Storybook for Svelte & Vite\n\nSee [documentation](https://storybook.js.org/docs/get-started/frameworks/svelte-vite?renderer=svelte&ref=readme) for installation instructions, usage examples, APIs, and more.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/frameworks/svelte-vite/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n      },\n      {\n        exportEntries: ['./node'],\n        entryPoint: './src/node/index.ts',\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/frameworks/svelte-vite/package.json",
    "content": "{\n  \"name\": \"@storybook/svelte-vite\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook for Svelte and Vite: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-framework\",\n    \"svelte\",\n    \"vite\",\n    \"component\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/frameworks/svelte-vite\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/frameworks/svelte-vite\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./node\": {\n      \"types\": \"./dist/node/index.d.ts\",\n      \"code\": \"./src/node/index.ts\",\n      \"default\": \"./dist/node/index.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./preset\": {\n      \"types\": \"./dist/preset.d.ts\",\n      \"code\": \"./src/preset.ts\",\n      \"default\": \"./dist/preset.js\"\n    }\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"template/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/builder-vite\": \"workspace:*\",\n    \"@storybook/svelte\": \"workspace:*\",\n    \"magic-string\": \"^0.30.0\",\n    \"svelte2tsx\": \"^0.7.44\",\n    \"typescript\": \"^4.9.4 || ^5.0.0\"\n  },\n  \"devDependencies\": {\n    \"@sveltejs/vite-plugin-svelte\": \"^6.2.0\",\n    \"@types/node\": \"^22.19.1\",\n    \"svelte\": \"^5.39.5\",\n    \"sveltedoc-parser\": \"^4.2.1\",\n    \"typescript\": \"^5.9.3\",\n    \"vite\": \"^7.0.4\"\n  },\n  \"peerDependencies\": {\n    \"@sveltejs/vite-plugin-svelte\": \"^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0\",\n    \"storybook\": \"workspace:^\",\n    \"svelte\": \"^5.0.0\",\n    \"vite\": \"^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/frameworks/svelte-vite/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/frameworks/svelte-vite/project.json",
    "content": "{\n  \"name\": \"svelte-vite\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/frameworks/svelte-vite/src/index.ts",
    "content": "export * from '@storybook/svelte';\nexport * from './types.ts';\n"
  },
  {
    "path": "code/frameworks/svelte-vite/src/node/index.ts",
    "content": "import type { StorybookConfig } from '../types.ts';\n\nexport function defineMain(config: StorybookConfig) {\n  return config;\n}\n\nexport type { StorybookConfig };\n"
  },
  {
    "path": "code/frameworks/svelte-vite/src/plugins/generateDocgen.ts",
    "content": "import path from 'node:path';\n\nimport svelte2tsx, { internalHelpers } from 'svelte2tsx';\nimport { VERSION } from 'svelte/compiler';\nimport ts from 'typescript';\n\nexport type Docgen = {\n  name?: string;\n  props: PropInfo[];\n};\n\nexport type PropInfo = {\n  name: string;\n  type?: Type;\n  optional?: boolean;\n  defaultValue?: DefaultValue;\n  description?: string;\n};\n\ntype BaseType = object;\n\ntype ScalarType = BaseType & {\n  type: 'number' | 'string' | 'boolean' | 'symbol' | 'any' | 'null' | 'undefined' | 'void';\n};\ntype FunctionType = BaseType & {\n  type: 'function';\n  text: string;\n};\ntype LiteralType = BaseType & {\n  type: 'literal';\n  value: string | number | boolean;\n  text: string;\n};\ntype ArrayType = BaseType & {\n  type: 'array';\n  text: string;\n};\ntype ObjectType = BaseType & {\n  type: 'object';\n  text: string;\n};\ntype UnionType = BaseType & {\n  type: 'union';\n  types: Type[];\n};\ntype IntersectionType = BaseType & {\n  type: 'intersection';\n  types: Type[];\n};\n\nexport type Type =\n  | ScalarType\n  | LiteralType\n  | FunctionType\n  | ArrayType\n  | ObjectType\n  | UnionType\n  | IntersectionType;\n\ntype DefaultValue = {\n  text: string;\n};\n\nfunction convertType(type: ts.Type, checker: ts.TypeChecker): Type | undefined {\n  // TypeScript compiler uses bit flags to represent type information.\n  // Note the use of the bitwise AND (&) operator here.\n  // See examples at: https://github.com/search?q=repo%3Amicrosoft%2FTypeScript+TypeFlags.&type=code\n  if (type.flags & ts.TypeFlags.Any) {\n    return { type: 'any' };\n  }\n  if (type.flags & ts.TypeFlags.Number) {\n    return { type: 'number' };\n  }\n  if (type.flags & ts.TypeFlags.String) {\n    return { type: 'string' };\n  }\n  if (type.flags & ts.TypeFlags.Boolean) {\n    return { type: 'boolean' };\n  }\n  if (type.flags & ts.TypeFlags.ESSymbol) {\n    return { type: 'symbol' };\n  }\n  if (type.flags & ts.TypeFlags.Null) {\n    return { type: 'null' };\n  }\n  if (type.flags & ts.TypeFlags.Undefined) {\n    return { type: 'undefined' };\n  }\n  if (type.flags & ts.TypeFlags.Void) {\n    return { type: 'void' };\n  }\n  if (type.getCallSignatures().length > 0) {\n    return { type: 'function', text: checker.typeToString(type) };\n  }\n  if (type.flags & ts.TypeFlags.Object) {\n    const indexType = checker.getIndexTypeOfType(type, ts.IndexKind.Number);\n    if (indexType) {\n      return { type: 'array', text: checker.typeToString(type) };\n    }\n    return { type: 'object', text: checker.typeToString(type) };\n  }\n  if (type.isNumberLiteral() || type.isStringLiteral()) {\n    return {\n      type: 'literal',\n      value: type.value,\n      text:\n        type.flags & ts.TypeFlags.EnumLiteral\n          ? checker.typeToString(type)\n          : JSON.stringify(type.value),\n    };\n  }\n  if (type.flags & ts.TypeFlags.BooleanLiteral) {\n    const text = checker.typeToString(type);\n    return { type: 'literal', value: text === 'true', text: text };\n  }\n  if (type.isUnion()) {\n    // TypeA | TypeB\n    const types = type.types\n      .map((t) => convertType(t, checker))\n      .filter((t) => {\n        return t !== undefined && t.type !== 'undefined';\n      }) as Type[];\n\n    // Boolean is represented as 'true' | 'false' in TypeScript's type checker,\n    // so we need to merge them into a single 'boolean' type.\n    const idxTrue = types.findIndex((t) => t.type === 'literal' && t.value === true);\n    const idxFalse = types.findIndex((t) => t.type === 'literal' && t.value === false);\n    if (idxTrue !== -1 && idxFalse !== -1) {\n      types.splice(Math.max(idxTrue, idxFalse), 1);\n      types.splice(Math.min(idxTrue, idxFalse), 1, { type: 'boolean' });\n    }\n\n    return types.length > 1 ? { type: 'union', types: types } : types[0];\n  }\n  if (type.isIntersection()) {\n    // TypeA & TypeB\n    const types = type.types\n      .map((t) => convertType(t, checker))\n      .filter((t) => t !== undefined) as Type[];\n    return { type: 'intersection', types };\n  }\n\n  return undefined;\n}\n\nfunction initializerToDefaultValue(\n  expr: ts.Expression,\n  checker: ts.TypeChecker\n): DefaultValue | undefined {\n  if (ts.isNumericLiteral(expr)) {\n    return { text: expr.text };\n  } else if (ts.isStringLiteral(expr)) {\n    return { text: JSON.stringify(expr.text) };\n  } else if (ts.isIdentifier(expr) || ts.isPropertyAccessExpression(expr)) {\n    const symbol = checker.getSymbolAtLocation(expr);\n    if (symbol && checker.isUndefinedSymbol(symbol)) {\n      return undefined;\n    }\n    const type = checker.getTypeAtLocation(expr);\n    if (type.flags & ts.TypeFlags.EnumLiteral) {\n      return { text: checker.typeToString(type) };\n    } else if (type.isLiteral()) {\n      // string or number\n      return { text: JSON.stringify(type.value) };\n    } else if (type.flags & ts.TypeFlags.Null) {\n      return { text: 'null' };\n    } else if (type.flags & ts.TypeFlags.BooleanLiteral) {\n      return { text: checker.typeToString(type) };\n    } else if (type.getCallSignatures().length > 0) {\n      return { text: 'function' };\n    }\n  } else if (\n    ts.isArrayLiteralExpression(expr) ||\n    ts.isObjectLiteralExpression(expr) ||\n    ts.isNewExpression(expr)\n  ) {\n    return { text: expr.getText() };\n  } else if (ts.isArrowFunction(expr)) {\n    return { text: 'function' };\n  }\n  switch (expr.kind) {\n    case ts.SyntaxKind.TrueKeyword:\n      return { text: 'true' };\n    case ts.SyntaxKind.FalseKeyword:\n      return { text: 'false' };\n    case ts.SyntaxKind.NullKeyword:\n      return { text: 'null' };\n  }\n  return { text: '...' };\n}\n\nfunction loadConfig(basepath: string): [ts.CompilerOptions, Set<string>] {\n  const configPath =\n    ts.findConfigFile(basepath, ts.sys.fileExists) ||\n    ts.findConfigFile(basepath, ts.sys.fileExists, 'jsconfig.json');\n\n  const forcedOptions = {\n    sourceMap: false,\n    noEmit: true,\n    strict: true,\n    allowJs: true,\n    checkJs: true,\n    skipLibCheck: true,\n    skipDefaultLibCheck: true,\n  };\n  if (!configPath) {\n    return [forcedOptions, new Set()];\n  }\n\n  const configFile = ts.readConfigFile(configPath, ts.sys.readFile);\n  const config = ts.parseJsonConfigFileContent(\n    configFile.config,\n    ts.sys,\n    path.dirname(configPath),\n    undefined,\n    configPath,\n    undefined,\n    [\n      {\n        extension: 'svelte',\n        isMixedContent: true,\n        scriptKind: ts.ScriptKind.Deferred,\n      },\n    ]\n  );\n\n  const fileNames = new Set(\n    config.fileNames\n      .filter((fileName) => fileName.endsWith('.svelte'))\n      .map((fileName) => fileName + '.tsx')\n  );\n\n  return [\n    {\n      ...config.options,\n      ...forcedOptions,\n    },\n    fileNames,\n  ];\n}\n\nexport interface DocgenCache {\n  filenameToModifiedTime: Record<string, Date | undefined>;\n  filenameToSourceFile: Record<string, ts.SourceFile>;\n  fileCache: Record<string, string>;\n  oldProgram?: ts.Program;\n  options?: ts.CompilerOptions;\n  rootNames?: Set<string>;\n}\n\nexport function createDocgenCache(): DocgenCache {\n  return {\n    filenameToModifiedTime: {},\n    filenameToSourceFile: {},\n    fileCache: {},\n  };\n}\n\nexport function generateDocgen(targetFileName: string, cache: DocgenCache): Docgen {\n  if (targetFileName.endsWith('.svelte')) {\n    targetFileName = targetFileName + '.tsx';\n  }\n\n  if (cache.options === undefined || !cache.rootNames?.has(targetFileName)) {\n    [cache.options, cache.rootNames] = loadConfig(targetFileName);\n\n    const shimFilename = import.meta.resolve('svelte2tsx/svelte-shims-v4.d.ts');\n    cache.rootNames.add(shimFilename);\n    cache.rootNames.add(targetFileName);\n  }\n\n  // Create a custom host\n  const originalHost = ts.createCompilerHost(cache.options);\n  const host: ts.CompilerHost = {\n    ...originalHost,\n    readFile(fileName) {\n      // Cache package.json\n      const isCacheTarget = fileName.endsWith(path.sep + 'package.json');\n      if (isCacheTarget && cache.fileCache[fileName]) {\n        return cache.fileCache[fileName];\n      }\n      const content = originalHost.readFile(fileName);\n      if (content && isCacheTarget) {\n        cache.fileCache[fileName] = content;\n      }\n      return content;\n    },\n    fileExists(fileName) {\n      const isCacheTarget = fileName.endsWith(path.sep + 'package.json');\n      if (isCacheTarget && cache.fileCache[fileName]) {\n        return true;\n      }\n\n      let exists = originalHost.fileExists(fileName);\n      if (exists) {\n        return exists;\n      }\n\n      // Virtual .svelte.tsx file\n      if (fileName.endsWith('.svelte.tsx') || fileName.endsWith('.svelte.jsx')) {\n        fileName = fileName.slice(0, -4); // remove .tsx or .jsx\n        exists = originalHost.fileExists(fileName);\n        return exists;\n      }\n\n      return false;\n    },\n    getSourceFile(fileName, languageVersion, onError) {\n      if (fileName.endsWith('.svelte.tsx') || fileName.endsWith('.svelte.jsx')) {\n        // .svelte file (`import ... from './path/to/file.svelte'`)\n\n        const realFileName = fileName.slice(0, -4); // remove .tsx or .jsx\n\n        const modifiedTime: Date | undefined = ts.sys.getModifiedTime\n          ? ts.sys.getModifiedTime(realFileName)\n          : undefined;\n        if (modifiedTime) {\n          const cachedModifiedTime = cache.filenameToModifiedTime[fileName];\n          if (cachedModifiedTime?.getTime() === modifiedTime.getTime()) {\n            return cache.filenameToSourceFile[fileName];\n          }\n        }\n\n        const content = originalHost.readFile(realFileName);\n        if (content === undefined) {\n          return;\n        }\n\n        const isTsFile = /<script\\s+[^>]*?lang=('|\")(ts|typescript)('|\")/.test(content);\n\n        const tsx = svelte2tsx.svelte2tsx(content, {\n          version: VERSION,\n          isTsFile,\n          mode: 'dts',\n        });\n\n        const sourceFile = ts.createSourceFile(\n          fileName,\n          tsx.code,\n          languageVersion,\n          true,\n          isTsFile ? ts.ScriptKind.TS : ts.ScriptKind.JS // Set to 'JS' to enable TypeScript to parse JSDoc.\n        );\n\n        // update cache\n        cache.filenameToSourceFile[fileName] = sourceFile;\n        cache.filenameToModifiedTime[fileName] = modifiedTime;\n\n        return sourceFile;\n      } else {\n        // non-svelte file\n\n        let staticCaching = false;\n        staticCaching ||= fileName\n          .split(path.sep)\n          .some((part) => part.toLowerCase() === 'node_modules');\n\n        // We can significantly speed up the docgen process by caching source files.\n        const cachedSourceFile = cache.filenameToSourceFile[fileName];\n        if (cachedSourceFile && staticCaching) {\n          return cachedSourceFile;\n        }\n        const modifiedTime: Date | undefined = ts.sys.getModifiedTime\n          ? ts.sys.getModifiedTime(fileName)\n          : undefined;\n        if (modifiedTime) {\n          const cachedModifiedTime = cache.filenameToModifiedTime[fileName];\n          if (cachedModifiedTime?.getTime() === modifiedTime.getTime()) {\n            return cache.filenameToSourceFile[fileName];\n          }\n        }\n\n        const content = originalHost.readFile(fileName);\n        if (content === undefined) {\n          return;\n        }\n\n        const sourceFile = ts.createSourceFile(fileName, content, languageVersion, true);\n\n        // update cache\n        cache.filenameToSourceFile[fileName] = sourceFile;\n        cache.filenameToModifiedTime[fileName] = modifiedTime;\n\n        return sourceFile;\n      }\n    },\n    writeFile() {\n      // Write nothing\n    },\n  };\n\n  const program = ts.createProgram({\n    rootNames: Array.from(cache.rootNames),\n    options: cache.options,\n    host,\n    oldProgram: cache.oldProgram,\n  });\n  cache.oldProgram = program;\n\n  const checker = program.getTypeChecker();\n  const sourceFile = program.getSourceFile(targetFileName);\n  if (sourceFile === undefined) {\n    return {\n      props: [],\n    };\n  }\n\n  const propMap: Map<string, PropInfo> = new Map();\n\n  // Get render function generated by svelte2tsx\n  const renderFunction = sourceFile.statements.find((statement) => {\n    return (\n      ts.isFunctionDeclaration(statement) && statement.name?.text === internalHelpers.renderName\n    );\n  }) as ts.FunctionDeclaration | undefined;\n  if (renderFunction === undefined) {\n    return {\n      props: [],\n    };\n  }\n\n  let propsType: ts.Type | undefined;\n\n  const signature = checker.getSignatureFromDeclaration(renderFunction);\n\n  if (signature && signature.declaration) {\n    // Get props type from ReturnType<render>\n    const type = checker.getReturnTypeOfSignature(signature);\n\n    type.getProperties().forEach((retObjProp) => {\n      if (retObjProp.name === 'props') {\n        const decl = signature.getDeclaration();\n        propsType = checker.getTypeOfSymbolAtLocation(retObjProp, decl);\n        propsType.getProperties().forEach((prop) => {\n          const name = prop.getName();\n          let description =\n            ts.displayPartsToString(prop.getDocumentationComment(checker)) || undefined;\n\n          // Infer prop type\n          const propType = checker.getTypeOfSymbolAtLocation(prop, decl);\n\n          if (prop.valueDeclaration) {\n            // Comment from JSDoc '@type {type} comment'\n            const typeTag = ts.getJSDocTypeTag(prop.valueDeclaration);\n            if (typeTag?.comment) {\n              description = ((description || '') + '\\n' + typeTag.comment).trim();\n            }\n          }\n\n          // Ignore props from svelte/elements.d.ts (HTMLAttributes, AriaAttributes and DOMAttributes).\n          // Some libraries use these for {...$$restProps}\n          if (\n            (prop.valueDeclaration ?? (prop as any)?.links?.syntheticOrigin?.valueDeclaration)\n              ?.getSourceFile()\n              .fileName.includes('node_modules/svelte/elements.d.ts')\n          ) {\n            return;\n          }\n\n          // Check if this prop is optional\n          const optional = (prop.flags & ts.SymbolFlags.Optional) !== 0;\n          propMap.set(name, {\n            name,\n            optional,\n            description,\n            type: convertType(propType, checker),\n          });\n        });\n      }\n    });\n  }\n\n  renderFunction.body?.forEachChild((node) => {\n    if (ts.isVariableStatement(node)) {\n      node.declarationList.declarations.forEach((declaration) => {\n        // Extract default values from:\n        //     let { <name> = <defaultValue>, ... }: <propsType> = $props();\n\n        if (ts.isObjectBindingPattern(declaration.name)) {\n          const isPropsRune =\n            declaration.initializer &&\n            ts.isCallExpression(declaration.initializer) &&\n            ts.isIdentifier(declaration.initializer.expression) &&\n            declaration.initializer.expression.text === '$props';\n\n          const isPropsType =\n            declaration.type && propsType === checker.getTypeFromTypeNode(declaration.type);\n\n          if (isPropsRune || isPropsType) {\n            declaration.name.elements.forEach((element) => {\n              const name = element.name.getText();\n              const prop = propMap.get(name);\n              if (prop && element.initializer) {\n                const defaultValue = initializerToDefaultValue(element.initializer, checker);\n                if (defaultValue) {\n                  prop.defaultValue = defaultValue;\n                }\n              }\n            });\n          }\n        }\n\n        // Extract default values from:\n        //    export let <name> = <defaultValue>\n        if (\n          ts.isVariableDeclaration(declaration) &&\n          ts.isIdentifier(declaration.name) &&\n          propMap.has(declaration.name.text)\n        ) {\n          const prop = propMap.get(declaration.name.text);\n          if (prop && declaration.initializer) {\n            prop.optional = true;\n            const defaultValue = initializerToDefaultValue(declaration.initializer, checker);\n            if (defaultValue) {\n              prop.defaultValue = defaultValue;\n            }\n          }\n        }\n      });\n    }\n  });\n\n  return {\n    props: Array.from(propMap.values()),\n  };\n}\n"
  },
  {
    "path": "code/frameworks/svelte-vite/src/plugins/svelte-docgen.ts",
    "content": "import { basename, relative } from 'node:path';\n\nimport type AST from 'estree';\nimport MagicString from 'magic-string';\nimport type { JSDocType, SvelteComponentDoc, SvelteDataItem } from 'sveltedoc-parser';\nimport type { PluginOption } from 'vite';\n\nimport { type Docgen, type Type, createDocgenCache, generateDocgen } from './generateDocgen.ts';\n\n/**\n * It access the AST output of _compiled_ Svelte component file. To read the name of the default\n * export - which is source of truth.\n *\n * In Svelte prior to `v4` component is a class. From `v5` is a function.\n */\nfunction getComponentName(ast: AST.Program): string {\n  // NOTE: Assertion, because rollup returns a type `AcornNode` for some reason, which doesn't overlap with `Program` from estree\n  const exportDefaultDeclaration = ast.body.find((n) => n.type === 'ExportDefaultDeclaration') as\n    | AST.ExportDefaultDeclaration\n    | undefined;\n\n  if (!exportDefaultDeclaration) {\n    throw new Error('Unreachable - no default export found');\n  }\n\n  // NOTE: Output differs based on svelte version and dev/prod mode\n\n  if (exportDefaultDeclaration.declaration.type === 'Identifier') {\n    return exportDefaultDeclaration.declaration.name;\n  }\n\n  if (\n    exportDefaultDeclaration.declaration.type !== 'ClassDeclaration' &&\n    exportDefaultDeclaration.declaration.type !== 'FunctionDeclaration'\n  ) {\n    throw new Error('Unreachable - not a class or a function');\n  }\n\n  if (!exportDefaultDeclaration.declaration.id) {\n    throw new Error('Unreachable - unnamed class/function');\n  }\n\n  return exportDefaultDeclaration.declaration.id.name;\n}\n\nfunction transformToSvelteDocParserType(type: Type): JSDocType {\n  switch (type.type) {\n    case 'string':\n      return { kind: 'type', type: 'string', text: 'string' };\n    case 'number':\n      return { kind: 'type', type: 'number', text: 'number' };\n    case 'boolean':\n      return { kind: 'type', type: 'boolean', text: 'boolean' };\n    case 'symbol':\n      return { kind: 'type', type: 'other', text: 'symbol' };\n    case 'null':\n      return { kind: 'type', type: 'other', text: 'null' };\n    case 'undefined':\n      return { kind: 'type', type: 'other', text: 'undefined' };\n    case 'void':\n      return { kind: 'type', type: 'other', text: 'void' };\n    case 'any':\n      return { kind: 'type', type: 'any', text: 'any' };\n    case 'object':\n      return { kind: 'type', type: 'object', text: type.text };\n    case 'array':\n      return { kind: 'type', type: 'array', text: type.text };\n    case 'function':\n      return { kind: 'function', text: type.text };\n    case 'literal':\n      return { kind: 'const', type: typeof type.value, value: type.value, text: type.text };\n    case 'union': {\n      const nonNull = type.types.filter((t) => t.type !== 'null'); // ignore null\n      const text = nonNull.map((t): string => transformToSvelteDocParserType(t).text).join(' | ');\n      const types = nonNull.map((t) => transformToSvelteDocParserType(t));\n      return types.length === 1 ? types[0] : { kind: 'union', type: types, text };\n    }\n    case 'intersection': {\n      const text = type.types\n        .map((t): string => transformToSvelteDocParserType(t).text)\n        .join(' & ');\n      return { kind: 'type', type: 'intersection', text };\n    }\n  }\n}\n\n/** Mimic sveltedoc-parser's props data structure */\nfunction transformToSvelteDocParserDataItems(docgen: Docgen): SvelteDataItem[] {\n  return docgen.props.map((p) => {\n    const required = p.optional === false && p.defaultValue === undefined;\n    return {\n      name: p.name,\n      visibility: 'public',\n      description: p.description,\n      keywords: required ? [{ name: 'required', description: '' }] : [],\n      kind: 'let',\n      type: p.type ? transformToSvelteDocParserType(p.type) : undefined,\n      static: false,\n      readonly: false,\n      importPath: undefined,\n      originalName: undefined,\n      localName: undefined,\n      defaultValue: p.defaultValue ? p.defaultValue.text : undefined,\n    } satisfies SvelteDataItem;\n  });\n}\n\nexport async function svelteDocgen(): Promise<PluginOption> {\n  const cwd = process.cwd();\n  const include = /\\.svelte$/;\n  const exclude = /node_modules\\/.*/;\n  const { createFilter } = await import('vite');\n\n  const filter = createFilter(include, exclude);\n  const sourceFileCache = createDocgenCache();\n\n  return {\n    name: 'storybook:svelte-docgen-plugin',\n    transform: {\n      filter: { id: { include, exclude } },\n      async handler(src: string, id: string) {\n        if (id.startsWith('\\0') || !filter(id)) {\n          return undefined;\n        }\n\n        const resource = relative(cwd, id);\n\n        // Get props information\n        const docgen = generateDocgen(resource, sourceFileCache);\n        const data = transformToSvelteDocParserDataItems(docgen);\n\n        const componentDoc: SvelteComponentDoc & { keywords?: string[] } = {\n          data: data,\n          name: basename(resource),\n        };\n\n        const s = new MagicString(src);\n        const outputAst = this.parse(src);\n        const componentName = getComponentName(outputAst as unknown as AST.Program);\n        s.append(`\\n;${componentName}.__docgen = ${JSON.stringify(componentDoc)}`);\n\n        return {\n          code: s.toString(),\n          map: s.generateMap({ hires: true, source: id }),\n        };\n      },\n    },\n  };\n}\n"
  },
  {
    "path": "code/frameworks/svelte-vite/src/preset.ts",
    "content": "import type { PresetProperty } from 'storybook/internal/types';\n\nimport { svelteDocgen } from './plugins/svelte-docgen.ts';\nimport type { FrameworkOptions, StorybookConfig } from './types.ts';\nimport { handleSvelteKit } from './utils.ts';\n\nexport const core: PresetProperty<'core'> = {\n  builder: import.meta.resolve('@storybook/builder-vite'),\n  renderer: import.meta.resolve('@storybook/svelte/preset'),\n};\n\nexport const viteFinal: NonNullable<StorybookConfig['viteFinal']> = async (config, options) => {\n  const { plugins = [] } = config;\n\n  // Get framework options to check if docgen is disabled\n  const framework = await options.presets.apply('framework');\n  const frameworkOptions: FrameworkOptions =\n    typeof framework === 'string' ? {} : (framework.options ?? {});\n\n  // Check if docgen is disabled in framework options (default is true/enabled)\n  if (frameworkOptions.docgen !== false) {\n    plugins.push(await svelteDocgen());\n  }\n\n  await handleSvelteKit(plugins, options);\n\n  return {\n    ...config,\n    plugins,\n  };\n};\n"
  },
  {
    "path": "code/frameworks/svelte-vite/src/types.ts",
    "content": "import type {\n  CompatibleString,\n  StorybookConfig as StorybookConfigBase,\n} from 'storybook/internal/types';\n\nimport type { BuilderOptions, StorybookConfigVite } from '@storybook/builder-vite';\n\ntype FrameworkName = CompatibleString<'@storybook/svelte-vite'>;\ntype BuilderName = CompatibleString<'@storybook/builder-vite'>;\n\nexport type FrameworkOptions = {\n  builder?: BuilderOptions;\n  /**\n   * Enable or disable automatic documentation generation for component properties, events, and\n   * slots. When disabled, Storybook will skip the docgen processing step during build, which can\n   * improve build performance.\n   *\n   * @default true\n   */\n  docgen?: boolean;\n};\n\ntype StorybookConfigFramework = {\n  framework:\n    | FrameworkName\n    | {\n        name: FrameworkName;\n        options: FrameworkOptions;\n      };\n  core?: StorybookConfigBase['core'] & {\n    builder?:\n      | BuilderName\n      | {\n          name: BuilderName;\n          options: BuilderOptions;\n        };\n  };\n};\n\n/** The interface for Storybook configuration in `main.ts` files. */\nexport type StorybookConfig = Omit<\n  StorybookConfigBase,\n  keyof StorybookConfigVite | keyof StorybookConfigFramework\n> &\n  StorybookConfigVite &\n  StorybookConfigFramework;\n"
  },
  {
    "path": "code/frameworks/svelte-vite/src/utils.ts",
    "content": "import { SvelteViteWithSvelteKitError } from 'storybook/internal/server-errors';\nimport type { Options } from 'storybook/internal/types';\n\nimport { hasVitePlugins } from '@storybook/builder-vite';\n\nimport type { PluginOption } from 'vite';\n\n/**\n * A migration step that ensures the svelte-vite framework still supports SvelteKit, but warns the\n * user that they should use the sveltekit framework instead. Should be removed when we decide to\n * remove support completely for SvelteKit in svelte-vite\n */\nexport async function handleSvelteKit(plugins: PluginOption[], options: Options) {\n  /*\n  the sveltekit framework uses this svelte-vite framework under the hood\n  so we have to take extra care of only throwing when the user is actually using\n  svelte-vite directly and not just through sveltekit\n  */\n  const frameworkPreset = await options.presets.apply('framework', {}, options);\n  const framework = typeof frameworkPreset === 'string' ? frameworkPreset : frameworkPreset.name;\n\n  const hasSvelteKitPlugins = await hasVitePlugins(plugins, [\n    'vite-plugin-svelte-kit',\n    'vite-plugin-sveltekit-setup',\n    'vite-plugin-sveltekit-compile',\n  ]);\n\n  if (hasSvelteKitPlugins && !framework.includes('@storybook/sveltekit')) {\n    throw new SvelteViteWithSvelteKitError();\n  }\n}\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/cli/js/Button.stories.svelte",
    "content": "<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import Button from './Button.svelte';\n  import { fn } from 'storybook/test';\n\n  // More on how to set up stories at: https://storybook.js.org/docs/writing-stories\n  const { Story } = defineMeta({\n    title: 'Example/Button',\n    component: Button,\n    tags: ['autodocs'],\n    argTypes: {\n      backgroundColor: { control: 'color' },\n      size: {\n        control: { type: 'select' },\n        options: ['small', 'medium', 'large'],\n      },\n    },\n    args: {\n      onclick: fn(),\n    }\n  });\n</script>\n\n<!-- More on writing stories with args: https://storybook.js.org/docs/writing-stories/args -->\n<Story name=\"Primary\" args={{ primary: true, label: 'Button' }} />\n\n<Story name=\"Secondary\" args={{ label: 'Button' }} />\n\n<Story name=\"Large\" args={{ size: 'large', label: 'Button' }} />\n\n<Story name=\"Small\" args={{ size: 'small', label: 'Button' }} />\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/cli/js/Button.svelte",
    "content": "<script>\n  import './button.css';\n\n  /**\n   * @typedef {Object} Props\n   * @property {boolean} [primary] Is this the principal call to action on the page?\n   * @property {string} [backgroundColor] What background color to use\n   * @property {'small' | 'medium' | 'large'} [size] How large should the button be?\n   * @property {string} label Button contents\n   * @property {() => void} [onclick] The onclick event handler\n   */\n\n  /** @type {Props} */\n  const { primary = false, backgroundColor, size = 'medium', label, ...props } = $props();\n\n  let mode = $derived(primary ? 'storybook-button--primary' : 'storybook-button--secondary');\n  let style = $derived(backgroundColor ? `background-color: ${backgroundColor}` : '');\n</script>\n\n<button\n  type=\"button\"\n  class={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n  {style}\n  {...props}\n>\n  {label}\n</button>\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/cli/js/Header.stories.svelte",
    "content": "<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import Header from './Header.svelte';\n  import { fn } from 'storybook/test';\n\n  // More on how to set up stories at: https://storybook.js.org/docs/writing-stories\n  const { Story } = defineMeta({\n    title: 'Example/Header',\n    component: Header,\n    // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n    tags: ['autodocs'],\n    parameters: {\n      // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n      layout: 'fullscreen',\n    },\n    args: {\n      onLogin: fn(),\n      onLogout: fn(),\n      onCreateAccount: fn(),\n    }\n  });\n</script>\n\n<Story name=\"Logged In\" args={{ user: { name: 'Jane Doe' } }} />\n\n<Story name=\"Logged Out\" />\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/cli/js/Header.svelte",
    "content": "<script>\n  import './header.css';\n  import Button from './Button.svelte';\n\n  /**\n   * @typedef {Object} Props\n   * @property {{name: string}} [user] The user object\n   * @property {() => void} [onLogin] The login event handler\n   * @property {() => void} [onLogout] The logout event handler\n   * @property {() => void} [onCreateAccount] The account creation event handler\n   */\n\n  /** @type {Props} */\n  const { user, onLogin, onLogout, onCreateAccount } = $props();\n</script>\n\n<header>\n  <div class=\"storybook-header\">\n    <div>\n      <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n        <g fill=\"none\" fill-rule=\"evenodd\">\n          <path\n            d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n            fill=\"#FFF\"\n          />\n          <path\n            d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n            fill=\"#555AB9\"\n          />\n          <path d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\" fill=\"#91BAF8\" />\n        </g>\n      </svg>\n      <h1>Acme</h1>\n    </div>\n    <div>\n      {#if user}\n        <span class=\"welcome\">\n          Welcome, <b>{user.name}</b>!\n        </span>\n        <Button size=\"small\" onclick={onLogout} label=\"Log out\" />\n      {:else}\n        <Button size=\"small\" onclick={onLogin} label=\"Log in\" />\n        <Button primary size=\"small\" onclick={onCreateAccount} label=\"Sign up\" />\n      {/if}\n    </div>\n  </div>\n</header>\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/cli/js/Page.stories.svelte",
    "content": "<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import { expect, userEvent, waitFor, within } from 'storybook/test';\n  import Page from './Page.svelte';\n  import { fn } from 'storybook/test';\n\n  // More on how to set up stories at: https://storybook.js.org/docs/writing-stories\n  const { Story } = defineMeta({\n    title: 'Example/Page',\n    component: Page,\n    parameters: {\n      // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n      layout: 'fullscreen',\n    },\n  });\n</script>\n\n<Story name=\"Logged In\" play={async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await waitFor(() => expect(loginButton).not.toBeInTheDocument());\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  }}\n  />\n\n<Story name=\"Logged Out\" />\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/cli/js/Page.svelte",
    "content": "<script>\n  import './page.css';\n  import Header from './Header.svelte';\n\n  let user = $state(null);\n</script>\n\n<article>\n  <Header\n    {user}\n    onLogin={() => (user = { name: 'Jane Doe' })}\n    onLogout={() => (user = null)}\n    onCreateAccount={() => (user = { name: 'Jane Doe' })}\n  />\n\n  <section class=\"storybook-page\">\n    <h2>Pages in Storybook</h2>\n    <p>\n      We recommend building UIs with a\n      <a\n        href=\"https://blog.hichroma.com/component-driven-development-ce1109d56c8e\"\n        target=\"_blank\"\n        rel=\"noopener noreferrer\"\n      >\n        <strong>component-driven</strong>\n      </a>\n      process starting with atomic components and ending with pages.\n    </p>\n    <p>\n      Render pages with mock data. This makes it easy to build and review page states without\n      needing to navigate to them in your app. Here are some handy patterns for managing page data\n      in Storybook:\n    </p>\n    <ul>\n      <li>\n        Use a higher-level connected component. Storybook helps you compose such data from the\n        \"args\" of child component stories\n      </li>\n      <li>\n        Assemble data in the page component from your services. You can mock these services out\n        using Storybook.\n      </li>\n    </ul>\n    <p>\n      Get a guided tutorial on component-driven development at\n      <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n        Storybook tutorials\n      </a>\n      . Read more in the\n      <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">docs</a>\n      .\n    </p>\n    <div class=\"tip-wrapper\">\n      <span class=\"tip\">Tip</span>\n      Adjust the width of the canvas with the\n      <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n        <g fill=\"none\" fill-rule=\"evenodd\">\n          <path\n            d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0\n            01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0\n            010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n            id=\"a\"\n            fill=\"#999\"\n          />\n        </g>\n      </svg>\n      Viewports addon in the toolbar\n    </div>\n  </section>\n</article>\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/cli/ts/Button.stories.svelte",
    "content": "<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import Button from './Button.svelte';\n  import { fn } from 'storybook/test';\n\n  // More on how to set up stories at: https://storybook.js.org/docs/writing-stories\n  const { Story } = defineMeta({\n    title: 'Example/Button',\n    component: Button,\n    tags: ['autodocs'],\n    argTypes: {\n      backgroundColor: { control: 'color' },\n      size: {\n        control: { type: 'select' },\n        options: ['small', 'medium', 'large'],\n      },\n    },\n    args: {\n      onclick: fn(),\n    }\n  });\n</script>\n\n<!-- More on writing stories with args: https://storybook.js.org/docs/writing-stories/args -->\n<Story name=\"Primary\" args={{ primary: true, label: 'Button' }} />\n\n<Story name=\"Secondary\" args={{ label: 'Button' }} />\n\n<Story name=\"Large\" args={{ size: 'large', label: 'Button' }} />\n\n<Story name=\"Small\" args={{ size: 'small', label: 'Button' }} />\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/cli/ts/Button.svelte",
    "content": "<script lang=\"ts\">\n  import './button.css';\n\n  interface Props {\n    /** Is this the principal call to action on the page? */\n    primary?: boolean;\n    /** What background color to use */\n    backgroundColor?: string;\n    /** How large should the button be? */\n    size?: 'small' | 'medium' | 'large';\n    /** Button contents */\n    label: string;\n    /** The onclick event handler */\n    onclick?: () => void;\n  }\n\n  const { primary = false, backgroundColor, size = 'medium', label, ...props }: Props = $props();\n  \n  let mode = $derived(primary ? 'storybook-button--primary' : 'storybook-button--secondary');\n  let style = $derived(backgroundColor ? `background-color: ${backgroundColor}` : '');\n</script>\n\n<button\n  type=\"button\"\n  class={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n  {style}\n  {...props}\n>\n  {label}\n</button>\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/cli/ts/Header.stories.svelte",
    "content": "<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import Header from './Header.svelte';\n  import { fn } from 'storybook/test';\n\n  // More on how to set up stories at: https://storybook.js.org/docs/writing-stories\n  const { Story } = defineMeta({\n    title: 'Example/Header',\n    component: Header,\n    // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n    tags: ['autodocs'],\n    parameters: {\n      // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n      layout: 'fullscreen',\n    },\n    args: {\n      onLogin: fn(),\n      onLogout: fn(),\n      onCreateAccount: fn(),\n    }\n  });\n</script>\n\n<Story name=\"Logged In\" args={{ user: { name: 'Jane Doe' } }} />\n\n<Story name=\"Logged Out\" />\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/cli/ts/Header.svelte",
    "content": "<script lang=\"ts\">\n  import './header.css';\n  import Button from './Button.svelte';\n\n  interface Props {\n    user?: { name: string };\n    onLogin?: () => void;\n    onLogout?: () => void;\n    onCreateAccount?: () => void;\n  }\n\n  const { user, onLogin, onLogout, onCreateAccount }: Props = $props();\n</script>\n\n<header>\n  <div class=\"storybook-header\">\n    <div>\n      <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n        <g fill=\"none\" fill-rule=\"evenodd\">\n          <path\n            d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n            fill=\"#FFF\"\n          />\n          <path\n            d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n            fill=\"#555AB9\"\n          />\n          <path d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\" fill=\"#91BAF8\" />\n        </g>\n      </svg>\n      <h1>Acme</h1>\n    </div>\n    <div>\n      {#if user}\n        <span class=\"welcome\">\n          Welcome, <b>{user.name}</b>!\n        </span>\n        <Button size=\"small\" onclick={onLogout} label=\"Log out\" />\n      {:else}\n        <Button size=\"small\" onclick={onLogin} label=\"Log in\" />\n        <Button primary size=\"small\" onclick={onCreateAccount} label=\"Sign up\" />\n      {/if}\n    </div>\n  </div>\n</header>\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/cli/ts/Page.stories.svelte",
    "content": "<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import { expect, userEvent, waitFor, within } from 'storybook/test';\n  import Page from './Page.svelte';\n  import { fn } from 'storybook/test';\n\n  // More on how to set up stories at: https://storybook.js.org/docs/writing-stories\n  const { Story } = defineMeta({\n    title: 'Example/Page',\n    component: Page,\n    parameters: {\n      // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n      layout: 'fullscreen',\n    },\n  });\n</script>\n\n<Story name=\"Logged In\" play={async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await waitFor(() => expect(loginButton).not.toBeInTheDocument());\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  }}\n/>\n\n<Story name=\"Logged Out\" />\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/cli/ts/Page.svelte",
    "content": "<script lang=\"ts\">\n  import './page.css';\n  import Header from './Header.svelte';\n\n  let user = $state<{ name: string }>();\n</script>\n\n<article>\n  <Header\n    {user}\n    onLogin={() => (user = { name: 'Jane Doe' })}\n    onLogout={() => (user = undefined)}\n    onCreateAccount={() => (user = { name: 'Jane Doe' })}\n  />\n\n  <section class=\"storybook-page\">\n    <h2>Pages in Storybook</h2>\n    <p>\n      We recommend building UIs with a\n      <a\n        href=\"https://blog.hichroma.com/component-driven-development-ce1109d56c8e\"\n        target=\"_blank\"\n        rel=\"noopener noreferrer\"\n      >\n        <strong>component-driven</strong>\n      </a>\n      process starting with atomic components and ending with pages.\n    </p>\n    <p>\n      Render pages with mock data. This makes it easy to build and review page states without\n      needing to navigate to them in your app. Here are some handy patterns for managing page data\n      in Storybook:\n    </p>\n    <ul>\n      <li>\n        Use a higher-level connected component. Storybook helps you compose such data from the\n        \"args\" of child component stories\n      </li>\n      <li>\n        Assemble data in the page component from your services. You can mock these services out\n        using Storybook.\n      </li>\n    </ul>\n    <p>\n      Get a guided tutorial on component-driven development at\n      <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n        Storybook tutorials\n      </a>\n      . Read more in the\n      <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">docs</a>\n      .\n    </p>\n    <div class=\"tip-wrapper\">\n      <span class=\"tip\">Tip</span>\n      Adjust the width of the canvas with the\n      <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n        <g fill=\"none\" fill-rule=\"evenodd\">\n          <path\n            d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0\n            01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0\n            010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n            id=\"a\"\n            fill=\"#999\"\n          />\n        </g>\n      </svg>\n      Viewports addon in the toolbar\n    </div>\n  </section>\n</article>\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/stories_svelte-vite-default-js/docgen/jsdoc.stories.js",
    "content": "import JSDoc from './jsdoc.svelte';\n\n/** @typedef {import('@storybook/svelte-vite').StoryObj} StoryObj */\n\n/** @type {Meta<typeof JSDoc>} */\nconst meta = {\n  component: JSDoc,\n  tags: ['autodocs'],\n  render: (args, { argTypes }) => ({\n    Component: JSDoc,\n    props: { ...args, argTypes },\n  }),\n};\n\nexport default meta;\n\nexport const Default = {};\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/stories_svelte-vite-default-js/docgen/jsdoc.svelte",
    "content": "<script>\n  /**\n   * @typedef {Object} MyObject\n   * @property {string} foo\n   * @property {number} bar\n   */\n\n  /**\n   * @typedef {Object} MyProps\n   * @property {boolean} [boolean] Boolean\n   * @property {string} [string] String\n   * @property {string} stringRequired String (required)\n   * @property {number} [number] Number\n   * @property {true} [trueLiteral] True literal\n   * @property {symbol} [symbol] Symbol\n   * @property {null} [nullValue] Null\n   * @property {undefined} [undefinedValue] Undefined\n   * @property {any} [any] Any\n   * @property {Date} [date] Date\n   * @property {import('./types').LiteralStrings} [unionLiteralStrings] Union of literal strings\n   * @property {import('./types').LiteralNumbers} [unionLiteralNumbers] Union of literal numbers\n   * @property {MyObject} [object] Object\n   * @property {{ foo: string; bar: number }} [inlineObject] Inline object\n   * @property {Record<string, number>} [record] Record\n   * @property {number | string} [unionTypes] Union of types\n   * @property {{ a: number } & { b: string }} [intersection] Intersection of types\n   * @property {(event: MouseEvent) => number} [func] Event callback function\n   * @property {import('svelte').Snippet} children Snippet contents\n   * @property {Record<string, any>} [argTypes] Actual arg types inferred from the component\n   */\n\n  /** @type {MyProps} */\n  let {\n    boolean = true,\n    string = 'default',\n    stringRequired,\n    number = 123,\n    trueLiteral = undefined,\n    symbol = undefined,\n    nullValue = null,\n    undefinedValue = undefined,\n    any = undefined,\n    date = new Date('20 Jan 1983'),\n    unionLiteralStrings = 'apple',\n    unionLiteralNumbers = 1000,\n    object = undefined,\n    inlineObject = undefined,\n    record = { a: 1, b: 2 },\n    unionTypes = 123,\n    intersection = undefined,\n    func = () => 10,\n    children,\n    argTypes,\n  } = $props();\n</script>\n\n<h1>Docgen: JS - JSDoc</h1>\n\n<h2>Args</h2>\n<pre>{JSON.stringify(\n    {\n      boolean,\n      string,\n      stringRequired,\n      number,\n      trueLiteral,\n      symbol,\n      nullValue,\n      undefinedValue,\n      any,\n      date,\n      unionLiteralStrings,\n      unionLiteralNumbers,\n      object,\n      inlineObject,\n      record,\n      unionTypes,\n      intersection,\n      func,\n      argTypes,\n    },\n    null,\n    2\n  )}</pre>\n\n<h2>Children</h2>\n{#if children}\n  {@render children()}\n{/if}\n\n<h2>Arg Types</h2>\n<pre>{JSON.stringify(argTypes, null, 2)}</pre>\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/stories_svelte-vite-default-ts/docgen/jsdoc.stories.js",
    "content": "import JSDoc from './jsdoc.svelte';\n\n/** @typedef {import('@storybook/svelte-vite').StoryObj} StoryObj */\n\n/** @type {Meta<typeof JSDoc>} */\nconst meta = {\n  component: JSDoc,\n  tags: ['autodocs'],\n  render: (args, { argTypes }) => ({\n    Component: JSDoc,\n    props: { ...args, argTypes },\n  }),\n};\n\nexport default meta;\n\nexport const Default = {};\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/stories_svelte-vite-default-ts/docgen/jsdoc.svelte",
    "content": "<script>\n  /**\n   * @typedef {Object} MyObject\n   * @property {string} foo\n   * @property {number} bar\n   */\n\n  /**\n   * @typedef {Object} MyProps\n   * @property {boolean} [boolean] Boolean\n   * @property {string} [string] String\n   * @property {string} stringRequired String (required)\n   * @property {number} [number] Number\n   * @property {true} [trueLiteral] True literal\n   * @property {symbol} [symbol] Symbol\n   * @property {null} [nullValue] Null\n   * @property {undefined} [undefinedValue] Undefined\n   * @property {any} [any] Any\n   * @property {import('./types').LiteralStrings} [unionLiteralStrings] Union of literal strings\n   * @property {import('./types').LiteralNumbers} [unionLiteralNumbers] Union of literal numbers\n   * @property {MyObject} [object] Object\n   * @property {{ foo: string; bar: number }} [inlineObject] Inline object\n   * @property {Record<string, number>} [record] Record\n   * @property {Date} [date] Date\n   * @property {number | string} [unionTypes] Union of types\n   * @property {{ a: number } & { b: string }} [intersection] Intersection of types\n   * @property {import('svelte').Snippet} children Snippet contents\n   * @property {(event: MouseEvent) => number} [func] Event callback function\n   * @property {Record<string, any>} [argTypes] Actual arg types inferred from the component\n   */\n\n  /** @type {MyProps} */\n  let {\n    boolean = true,\n    string = 'default',\n    stringRequired,\n    number = 123,\n    trueLiteral = undefined,\n    symbol = undefined,\n    nullValue = null,\n    undefinedValue = undefined,\n    any = undefined,\n    unionLiteralStrings = 'apple',\n    unionLiteralNumbers = 1000,\n    object = undefined,\n    inlineObject = undefined,\n    record = { a: 1, b: 2 },\n    date = new Date('20 Jan 1983'),\n    unionTypes = 123,\n    intersection = undefined,\n    children,\n    func = () => 10,\n    argTypes,\n  } = $props();\n</script>\n\n<h1>Docgen: JS - JSDoc</h1>\n\n<h2>Args</h2>\n<pre>{JSON.stringify(\n    {\n      boolean,\n      string,\n      stringRequired,\n      number,\n      trueLiteral,\n      symbol,\n      nullValue,\n      undefinedValue,\n      any,\n      date,\n      unionLiteralStrings,\n      unionLiteralNumbers,\n      object,\n      inlineObject,\n      record,\n      unionTypes,\n      intersection,\n      func,\n    },\n    null,\n    2\n  )}</pre>\n\n<h2>Children</h2>\n{#if children}\n  {@render children()}\n{/if}\n\n<h2>Arg Types</h2>\n<pre>{JSON.stringify(argTypes, null, 2)}</pre>\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/stories_svelte-vite-default-ts/docgen/ts-inline-prop-types.stories.ts",
    "content": "import type { Meta } from '@storybook/svelte-vite';\n\nimport TSInlinePropTypes from './ts-inline-prop-types.svelte';\n\nconst meta = {\n  component: TSInlinePropTypes,\n  tags: ['autodocs'],\n  render: (args, { argTypes }) => ({\n    Component: TSInlinePropTypes,\n    props: { ...args, argTypes },\n  }),\n} satisfies Meta<typeof TSInlinePropTypes>;\n\nexport default meta;\n\nexport const Default = {};\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/stories_svelte-vite-default-ts/docgen/ts-inline-prop-types.svelte",
    "content": "<script lang=\"ts\">\n  import type { Snippet } from 'svelte';\n  import type { LiteralNumbers, LiteralStrings } from './types';\n  import { MyEnum } from './types';\n\n  type MyObject = {\n    foo: string;\n    bar: number;\n  };\n\n  let {\n    boolean = true,\n    string = 'default',\n    stringRequired,\n    number = 123,\n    nullValue = null,\n    arrayOfNumbers = [1, 20, 300],\n    enumValue = MyEnum.FOO,\n    record = { a: 1, b: 2 },\n    date = new Date('20 Jan 1983'),\n    unionTypes = 123,\n    func = () => 10,\n    children,\n    argTypes,\n  }: {\n    /** Boolean */\n    boolean?: boolean;\n    /** String */\n    string?: string;\n    /** String (required) */\n    stringRequired: string;\n    /** Number */\n    number?: number;\n    /** True literal */\n    trueLiteral?: true;\n    /** Symbol */\n    symbol?: symbol;\n    /** Null */\n    nullValue?: null;\n    /** Undefined */\n    undefinedValue?: undefined;\n    /** Any */\n    any?: any;\n    /** Date */\n    date?: Date;\n    /** Array of numbers */\n    arrayOfNumbers?: number[];\n    /** Enum */\n    enumValue?: MyEnum;\n    /** Union of literal strings */\n    unionLiteralStrings?: LiteralStrings;\n    /** Union of literal numbers */\n    unionLiteralNumbers?: LiteralNumbers;\n    /** Object */\n    object?: MyObject;\n    /** Inline object */\n    inlineObject?: {\n      foo: string;\n      bar: number;\n    };\n    /** Record */\n    record?: Record<string, number>;\n    /** Union of types */\n    unionTypes?: number | string;\n    /** Intersection of types */\n    intersection?: { a: number } & { b: string };\n    /** Event callback function */\n    func?: (event: MouseEvent) => number;\n    /** Snippet contents */\n    children: Snippet;\n    /** Actual arg types inferred from the component */\n    argTypes: Record<string, any>;\n  } = $props();\n</script>\n\n<h1>Docgen: TS - inline prop types</h1>\n\n<h2>Args</h2>\n<pre>{JSON.stringify(\n    {\n      boolean,\n      string,\n      stringRequired,\n      number,\n      nullValue,\n      date,\n      arrayOfNumbers,\n      enumValue,\n      record,\n      unionTypes,\n      func,\n    },\n    null,\n    2\n  )}</pre>\n\n<h2>Children</h2>\n{#if children}\n  {@render children()}\n{/if}\n\n<h2>Arg Types</h2>\n<pre>{JSON.stringify(argTypes, null, 2)}</pre>\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/stories_svelte-vite-default-ts/docgen/ts-legacy.stories.ts",
    "content": "import type { Meta } from '@storybook/svelte-vite';\n\nimport TSLegacy from './ts-legacy.svelte';\n\nconst meta = {\n  component: TSLegacy,\n  tags: ['autodocs'],\n  render: (args, { argTypes }) => ({\n    Component: TSLegacy,\n    props: { ...args, argTypes } as any,\n  }),\n} satisfies Meta<typeof TSLegacy>;\n\nexport default meta;\n\nexport const Default = {};\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/stories_svelte-vite-default-ts/docgen/ts-legacy.svelte",
    "content": "<script lang=\"ts\">\n  import type { Snippet } from 'svelte';\n  import type { LiteralNumbers, LiteralStrings } from './types';\n  import { MyEnum } from './types';\n\n  type MyObject = {\n    foo: string;\n    bar: number;\n  };\n\n  /** Boolean */\n  export let boolean: boolean = true;\n  /** String */\n  export let string: string = 'default';\n  /** String (required) */\n  export let stringRequired: string;\n  /** Number */\n  export let number: number = 123;\n  /** True literal */\n  export let trueLiteral: true | undefined = undefined;\n  /** Symbol */\n  export let symbol: symbol | undefined = undefined;\n  /** Null */\n  export let nullValue: null = null;\n  /** Undefined */\n  export let undefinedValue: undefined = undefined;\n  /** Any */\n  export let any: any = null;\n  /** Date */\n  export let date: Date = new Date('20 Jan 1983');\n  /** Array of numbers */\n  export let arrayOfNumbers: number[] = [1, 20, 300];\n  /** Enum */\n  export let enumValue: MyEnum = MyEnum.FOO;\n  /** Union of literal strings */\n  export let unionLiteralStrings: LiteralStrings = 'apple';\n  /** Union of literal numbers */\n  export let unionLiteralNumbers: LiteralNumbers = 1000;\n  /** Object */\n  export let object: MyObject | undefined = undefined;\n  /** Inline object */\n  export let inlineObject:\n    | {\n        foo: string;\n        bar: number;\n      }\n    | undefined = undefined;\n  /** Record */\n  export let record: Record<string, number> = { a: 1, b: 2 };\n  /** Union of types */\n  export let unionTypes: number | string = 123;\n  /** Intersection of types */\n  export let intersection: ({ a: number } & { b: string }) | undefined = undefined;\n  /** Event callback function */\n  export let func: (event: MouseEvent) => number = () => 10;\n  /** Snippet contents */\n  export let children: Snippet;\n  /** Actual arg types inferred from the component */\n  export let argTypes: Record<string, any> = {};\n</script>\n\n<h1>Docgen: TS - legacy</h1>\n\n<h2>Args</h2>\n<pre>{JSON.stringify(\n    {\n      boolean,\n      string,\n      stringRequired,\n      number,\n      trueLiteral,\n      symbol,\n      nullValue,\n      undefinedValue,\n      any,\n      date,\n      arrayOfNumbers,\n      enumValue,\n      unionLiteralStrings,\n      unionLiteralNumbers,\n      object,\n      inlineObject,\n      record,\n      unionTypes,\n      intersection,\n      func,\n    },\n    null,\n    2\n  )}</pre>\n\n<h2>Children</h2>\n{#if children}\n  {@render children()}\n{/if}\n\n<h2>Arg Types</h2>\n<pre>{JSON.stringify(argTypes, null, 2)}</pre>\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/stories_svelte-vite-default-ts/docgen/ts-referenced-prop-types.stories.ts",
    "content": "import type { Meta } from '@storybook/svelte-vite';\n\nimport TSReferencedPropTypes from './ts-referenced-prop-types.svelte';\n\nconst meta = {\n  component: TSReferencedPropTypes,\n  tags: ['autodocs'],\n  render: (args, { argTypes }) => ({\n    Component: TSReferencedPropTypes,\n    props: { ...args, argTypes },\n  }),\n} satisfies Meta<typeof TSReferencedPropTypes>;\n\nexport default meta;\n\nexport const Default = {};\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/stories_svelte-vite-default-ts/docgen/ts-referenced-prop-types.svelte",
    "content": "<script lang=\"ts\">\n  import type { Snippet } from 'svelte';\n  import type { LiteralNumbers, LiteralStrings } from './types';\n  import { MyEnum } from './types';\n\n  type MyObject = {\n    foo: string;\n    bar: number;\n  };\n\n  type PropsA = {\n    /** Boolean */\n    boolean?: boolean;\n    /** String */\n    string?: string;\n    /** String (required) */\n    stringRequired: string;\n    /** Number */\n    number?: number;\n  };\n  type PropsB = {\n    /** True literal */\n    trueLiteral?: true;\n    /** Symbol */\n    symbol?: symbol;\n    /** Null */\n    nullValue?: null;\n    /** Undefined */\n    undefinedValue?: undefined;\n    /** Any */\n    any?: any;\n    /** Date */\n    date?: Date;\n    /** Array of numbers */\n    arrayOfNumbers?: number[];\n    /** Enum */\n    enumValue?: MyEnum;\n    /** Union of literal strings */\n    unionLiteralStrings?: LiteralStrings;\n    /** Union of literal numbers */\n    unionLiteralNumbers?: LiteralNumbers;\n    /** Object */\n    object?: MyObject;\n    /** Inline object */\n    inlineObject?: {\n      foo: string;\n      bar: number;\n    };\n    /** Record */\n    record?: Record<string, number>;\n    /** Union of types */\n    unionTypes?: number | string;\n    /** Intersection of types */\n    intersection?: { a: number } & { b: string };\n    /** Event callback function */\n    func?: (event: MouseEvent) => number;\n    /** Snippet contents */\n    children: Snippet;\n    /** Actual arg types inferred from the component */\n    argTypes: Record<string, any>;\n  };\n\n  let {\n    boolean = true,\n    string = 'default',\n    stringRequired,\n    number = 123,\n    nullValue = null,\n    arrayOfNumbers = [1, 20, 300],\n    enumValue = MyEnum.FOO,\n    record = { a: 1, b: 2 },\n    date = new Date('20 Jan 1983'),\n    unionTypes = 123,\n    children,\n    func = () => 10,\n    argTypes,\n  }: PropsA & PropsB = $props();\n</script>\n\n<h1>Docgen: TS - referenced prop types</h1>\n\n<h2>Args</h2>\n<pre>{JSON.stringify(\n    {\n      boolean,\n      string,\n      stringRequired,\n      number,\n      nullValue,\n      arrayOfNumbers,\n      enumValue,\n      record,\n      date,\n      unionTypes,\n      func,\n    },\n    null,\n    2\n  )}</pre>\n\n<h2>Children</h2>\n{#if children}\n  {@render children()}\n{/if}\n\n<h2>Arg Types</h2>\n<pre>{JSON.stringify(argTypes, null, 2)}</pre>\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/stories_svelte-vite-default-ts/docgen/ts.stories.ts",
    "content": "import type { Meta } from '@storybook/svelte-vite';\n\nimport TS from './ts.svelte';\n\nconst meta = {\n  component: TS,\n  tags: ['autodocs'],\n  render: (args, { argTypes }) => ({\n    Component: TS,\n    props: { ...args, argTypes },\n  }),\n} satisfies Meta<typeof TS>;\n\nexport default meta;\n\nexport const Default = {};\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/stories_svelte-vite-default-ts/docgen/ts.svelte",
    "content": "<script lang=\"ts\">\n  import type { Snippet } from 'svelte';\n  import type { LiteralNumbers, LiteralStrings } from './types';\n  import { MyEnum } from './types';\n\n  type MyObject = {\n    foo: string;\n    bar: number;\n  };\n\n  type Props = {\n    /** Boolean */\n    boolean?: boolean;\n    /** String */\n    string?: string;\n    /** String (required) */\n    stringRequired: string;\n    /** Number */\n    number?: number;\n    /** True literal */\n    trueLiteral?: true | undefined;\n    /** Symbol */\n    symbol?: symbol | undefined;\n    /** Null */\n    nullValue?: null;\n    /** Undefined */\n    undefinedValue?: undefined;\n    /** Any */\n    any?: any;\n    /** Date */\n    date?: Date;\n    /** Array of numbers */\n    arrayOfNumbers?: number[];\n    /** Enum */\n    enumValue?: MyEnum;\n    /** Union of literal strings */\n    unionLiteralStrings?: LiteralStrings;\n    /** Union of literal numbers */\n    unionLiteralNumbers?: LiteralNumbers;\n    /** Object */\n    object?: MyObject | undefined;\n    /** Inline object */\n    inlineObject?:\n      | {\n          foo: string;\n          bar: number;\n        }\n      | undefined;\n    /** Record */\n    record?: Record<string, number>;\n    /** Union of types */\n    unionTypes?: number | string;\n    /** Intersection of types */\n    intersection?: ({ a: number } & { b: string }) | undefined;\n    /** Event callback function */\n    func?: (event: MouseEvent) => number;\n    /** Children */\n    children: Snippet;\n    /** Actual arg types inferred from the component */\n    argTypes: Record<string, any>;\n  };\n\n  const {\n    boolean = true,\n    string = 'default',\n    stringRequired,\n    number = 123,\n    trueLiteral = undefined,\n    symbol = undefined,\n    nullValue = null,\n    undefinedValue = undefined,\n    any = null,\n    date = new Date('20 Jan 1983'),\n    arrayOfNumbers = [1, 20, 300],\n    enumValue = MyEnum.FOO,\n    unionLiteralStrings = 'apple',\n    unionLiteralNumbers = 100,\n    object = undefined,\n    inlineObject = undefined,\n    record = { a: 1, b: 2 },\n    unionTypes = 123,\n    intersection = undefined,\n    func = () => 10,\n    children,\n    argTypes,\n  }: Props = $props();\n</script>\n\n<h1>Docgen: TS</h1>\n\n<h2>Args</h2>\n<pre>{JSON.stringify(\n    {\n      boolean,\n      string,\n      stringRequired,\n      number,\n      trueLiteral,\n      symbol,\n      nullValue,\n      undefinedValue,\n      any,\n      date,\n      arrayOfNumbers,\n      enumValue,\n      unionLiteralStrings,\n      unionLiteralNumbers,\n      object,\n      inlineObject,\n      record,\n      unionTypes,\n      intersection,\n      func,\n    },\n    null,\n    2\n  )}</pre>\n\n<h2>Children</h2>\n{#if children}\n  {@render children()}\n{/if}\n\n<h2>Arg Types</h2>\n<pre>{JSON.stringify(argTypes, null, 2)}</pre>\n"
  },
  {
    "path": "code/frameworks/svelte-vite/template/stories_svelte-vite-default-ts/docgen/types.ts",
    "content": "export type LiteralNumbers = 100 | 1000 | 10000;\nexport type LiteralStrings = 'apple' | 'grape' | 'orange';\n\nexport enum MyEnum {\n  FOO = 'foo',\n  BAR = 'bar',\n}\n"
  },
  {
    "path": "code/frameworks/svelte-vite/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"storybook/internal/*\": [\"../../lib/cli/core/*\"]\n    },\n    \"rootDir\": \"./src\"\n  },\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/frameworks/svelte-vite/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/frameworks/sveltekit/README.md",
    "content": "# Storybook for SvelteKit\n\nSee [documentation](https://storybook.js.org/docs/get-started/frameworks/sveltekit?renderer=svelte&ref=readme) for installation instructions, usage examples, APIs, and more.\n\n## Acknowledgements\n\nIntegrating with SvelteKit would not have been possible if it weren't for the fantastic efforts by the Svelte core team - especially [Ben McCann](https://twitter.com/benjaminmccann) - to make integrations with the wider ecosystem possible.\nA big thank you also goes out to [Paolo Ricciuti](https://twitter.com/PaoloRicciuti) for improving the mocking capabilities.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/frameworks/sveltekit/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./preview'],\n        entryPoint: './src/preview.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./internal/mocks/app/forms'],\n        entryPoint: './src/mocks/app/forms.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./internal/mocks/app/navigation'],\n        entryPoint: './src/mocks/app/navigation.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./internal/mocks/app/stores'],\n        entryPoint: './src/mocks/app/stores.ts',\n        dts: false,\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./node'],\n        entryPoint: './src/node/index.ts',\n      },\n      {\n        exportEntries: ['./vite-plugin'],\n        entryPoint: './src/vite-plugin.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n    ],\n  },\n  extraOutputs: {\n    './internal/mocks/app/state.svelte.js': './static/app-state-mock.svelte.js',\n    './internal/MockProvider.svelte': './static/MockProvider.svelte',\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/frameworks/sveltekit/package.json",
    "content": "{\n  \"name\": \"@storybook/sveltekit\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook for SvelteKit: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-framework\",\n    \"svelte\",\n    \"sveltekit\",\n    \"svelte-kit\",\n    \"vite\",\n    \"component\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/frameworks/sveltekit\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/frameworks/sveltekit\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./internal/MockProvider.svelte\": \"./static/MockProvider.svelte\",\n    \"./internal/mocks/app/forms\": \"./dist/mocks/app/forms.js\",\n    \"./internal/mocks/app/navigation\": \"./dist/mocks/app/navigation.js\",\n    \"./internal/mocks/app/state.svelte.js\": \"./static/app-state-mock.svelte.js\",\n    \"./internal/mocks/app/stores\": \"./dist/mocks/app/stores.js\",\n    \"./node\": {\n      \"types\": \"./dist/node/index.d.ts\",\n      \"code\": \"./src/node/index.ts\",\n      \"default\": \"./dist/node/index.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\",\n    \"./preview\": \"./dist/preview.js\",\n    \"./vite-plugin\": \"./dist/vite-plugin.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"static/**/*\",\n    \"template/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\"\n  ],\n  \"dependencies\": {\n    \"@storybook/builder-vite\": \"workspace:*\",\n    \"@storybook/svelte\": \"workspace:*\",\n    \"@storybook/svelte-vite\": \"workspace:*\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.19.1\",\n    \"typescript\": \"^5.9.3\",\n    \"vite\": \"^7.0.4\"\n  },\n  \"peerDependencies\": {\n    \"storybook\": \"workspace:^\",\n    \"svelte\": \"^5.0.0\",\n    \"vite\": \"^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/frameworks/sveltekit/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/frameworks/sveltekit/preview.js",
    "content": "export * from './dist/preview.js';\n"
  },
  {
    "path": "code/frameworks/sveltekit/project.json",
    "content": "{\n  \"name\": \"sveltekit\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/frameworks/sveltekit/src/index.ts",
    "content": "export * from '@storybook/svelte';\nexport * from './types.ts';\n// @ts-expect-error (double exports)\nexport * from './portable-stories.ts';\n"
  },
  {
    "path": "code/frameworks/sveltekit/src/mocks/app/forms.ts",
    "content": "export function enhance(form: HTMLFormElement) {\n  const listener = (...args: any[]) => {\n    const e = args[0];\n    e.preventDefault();\n    const event = new CustomEvent('storybook:enhance', {\n      detail: args,\n    });\n    window.dispatchEvent(event);\n  };\n  form.addEventListener('submit', listener);\n  return {\n    destroy() {\n      form.removeEventListener('submit', listener);\n    },\n  };\n}\n\nexport function applyAction() {}\n\nexport function deserialize() {}\n"
  },
  {
    "path": "code/frameworks/sveltekit/src/mocks/app/navigation.ts",
    "content": "import { getContext, onMount, setContext } from 'svelte';\n\nexport async function goto(...args: any[]) {\n  const event = new CustomEvent('storybook:goto', {\n    detail: args,\n  });\n  window.dispatchEvent(event);\n}\n\nexport function setAfterNavigateArgument(afterNavigateArgs: any) {\n  setContext('after-navigate-args', afterNavigateArgs);\n}\n\nexport function afterNavigate(cb: any) {\n  const argument = getContext('after-navigate-args');\n  onMount(() => {\n    if (cb && cb instanceof Function) {\n      cb(argument);\n    }\n  });\n}\n\nexport function onNavigate() {}\n\nexport function beforeNavigate() {}\n\nexport function disableScrollHandling() {}\n\nexport async function invalidate(...args: any[]) {\n  const event = new CustomEvent('storybook:invalidate', {\n    detail: args,\n  });\n  window.dispatchEvent(event);\n}\n\nexport async function invalidateAll() {\n  const event = new CustomEvent('storybook:invalidateAll');\n  window.dispatchEvent(event);\n}\n\nexport function preloadCode() {}\n\nexport function preloadData() {}\n\nexport async function pushState(...args: any[]) {\n  const event = new CustomEvent('storybook:pushState', {\n    detail: args,\n  });\n  window.dispatchEvent(event);\n}\n\nexport async function replaceState(...args: any[]) {\n  const event = new CustomEvent('storybook:replaceState', {\n    detail: args,\n  });\n  window.dispatchEvent(event);\n}\n"
  },
  {
    "path": "code/frameworks/sveltekit/src/mocks/app/stores.ts",
    "content": "import { getContext, setContext } from 'svelte';\n\nfunction createMockedStore(contextName: string) {\n  return [\n    {\n      subscribe(runner: any) {\n        const page = getContext(contextName);\n        runner(page);\n        return () => {};\n      },\n    },\n    (value: unknown) => {\n      setContext(contextName, value);\n    },\n  ] as const;\n}\n\nexport const [page, setAppStoresPage] = createMockedStore('page-ctx');\nexport const [navigating, setAppStoresNavigating] = createMockedStore('navigating-ctx');\nconst [updated, setAppStoresUpdated] = createMockedStore('updated-ctx');\n\n(updated as any).check = () => {};\n\nexport { updated, setAppStoresUpdated };\n\nexport function getStores() {\n  return {\n    page,\n    navigating,\n    updated,\n  };\n}\n"
  },
  {
    "path": "code/frameworks/sveltekit/src/node/index.ts",
    "content": "import type { StorybookConfig } from '../types.ts';\n\nexport function defineMain(config: StorybookConfig) {\n  return config;\n}\n\nexport type { StorybookConfig };\n"
  },
  {
    "path": "code/frameworks/sveltekit/src/plugins/config-overrides.ts",
    "content": "import type { Plugin } from 'vite';\n\nexport function configOverrides() {\n  return {\n    // SvelteKit sets SSR, we need it to be false when building\n    name: 'storybook:sveltekit-overrides',\n    apply: 'build',\n    config: () => {\n      return { build: { ssr: false } };\n    },\n  } satisfies Plugin;\n}\n"
  },
  {
    "path": "code/frameworks/sveltekit/src/plugins/mock-sveltekit-stores.ts",
    "content": "import type { Plugin } from 'vite';\n\nexport function mockSveltekitStores() {\n  return {\n    name: 'storybook:sveltekit-mock-stores',\n    config: () => ({\n      resolve: {\n        alias: {\n          '$app/forms': '@storybook/sveltekit/internal/mocks/app/forms',\n          '$app/navigation': '@storybook/sveltekit/internal/mocks/app/navigation',\n          '$app/state': '@storybook/sveltekit/internal/mocks/app/state.svelte.js',\n          '$app/stores': '@storybook/sveltekit/internal/mocks/app/stores',\n        },\n      },\n    }),\n  } satisfies Plugin;\n}\n"
  },
  {
    "path": "code/frameworks/sveltekit/src/portable-stories.ts",
    "content": "import type {\n  NamedOrDefaultProjectAnnotations,\n  NormalizedProjectAnnotations,\n  ProjectAnnotations,\n} from 'storybook/internal/types';\n\nimport type { SvelteRenderer } from '@storybook/svelte';\nimport { INTERNAL_DEFAULT_PROJECT_ANNOTATIONS as svelteAnnotations } from '@storybook/svelte';\n\nimport {\n  composeConfigs,\n  setProjectAnnotations as originalSetProjectAnnotations,\n  setDefaultProjectAnnotations,\n} from 'storybook/preview-api';\n\nimport * as svelteKitAnnotations from './preview.ts';\n\n/**\n * Function that sets the globalConfig of your storybook. The global config is the preview module of\n * your .storybook folder.\n *\n * It should be run a single time, so that your global config (e.g. decorators) is applied to your\n * stories when using `composeStories` or `composeStory`.\n *\n * Example:\n *\n * ```jsx\n * // setup-file.js\n * import { setProjectAnnotations } from '@storybook/sveltekit';\n * import projectAnnotations from './.storybook/preview';\n *\n * setProjectAnnotations(projectAnnotations);\n * ```\n *\n * @param projectAnnotations - E.g. (import projectAnnotations from '../.storybook/preview')\n */\nexport function setProjectAnnotations(\n  projectAnnotations:\n    | NamedOrDefaultProjectAnnotations<any>\n    | NamedOrDefaultProjectAnnotations<any>[]\n): NormalizedProjectAnnotations<SvelteRenderer> {\n  setDefaultProjectAnnotations(INTERNAL_DEFAULT_PROJECT_ANNOTATIONS);\n  return originalSetProjectAnnotations(\n    projectAnnotations\n  ) as NormalizedProjectAnnotations<SvelteRenderer>;\n}\n\n// This will not be necessary once we have auto preset loading\nconst INTERNAL_DEFAULT_PROJECT_ANNOTATIONS: ProjectAnnotations<SvelteRenderer> = composeConfigs([\n  svelteAnnotations,\n  svelteKitAnnotations,\n]);\n"
  },
  {
    "path": "code/frameworks/sveltekit/src/preset.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport type { PresetProperty } from 'storybook/internal/types';\n\nimport { withoutVitePlugins } from '@storybook/builder-vite';\nimport { viteFinal as svelteViteFinal } from '@storybook/svelte-vite/preset';\n\nimport { configOverrides } from './plugins/config-overrides.ts';\nimport { mockSveltekitStores } from './plugins/mock-sveltekit-stores.ts';\nimport { type StorybookConfig } from './types.ts';\n\nexport const core: PresetProperty<'core'> = {\n  builder: import.meta.resolve('@storybook/builder-vite'),\n  renderer: import.meta.resolve('@storybook/svelte/preset'),\n};\nexport const previewAnnotations: PresetProperty<'previewAnnotations'> = (entry = []) => [\n  ...entry,\n  fileURLToPath(import.meta.resolve('@storybook/sveltekit/preview')),\n];\n\nexport const viteFinal: NonNullable<StorybookConfig['viteFinal']> = async (config, options) => {\n  const baseConfig = await svelteViteFinal(config, options);\n\n  return {\n    ...baseConfig,\n    plugins: [\n      // disable specific plugins that are not compatible with Storybook\n      ...(await withoutVitePlugins(baseConfig.plugins ?? [], [\n        'vite-plugin-sveltekit-compile',\n        'vite-plugin-sveltekit-guard',\n      ])),\n      configOverrides(),\n      mockSveltekitStores(),\n    ],\n  };\n};\n\nexport const optimizeViteDeps = [\n  '@storybook/sveltekit/internal/mocks/app/forms',\n  '@storybook/sveltekit/internal/mocks/app/navigation',\n  '@storybook/sveltekit/internal/mocks/app/stores',\n  '@storybook/sveltekit/internal/mocks/app/state.svelte.js',\n];\n"
  },
  {
    "path": "code/frameworks/sveltekit/src/preview.ts",
    "content": "import type { Decorator, Preview } from '@storybook/svelte';\nimport MockProvider from '@storybook/sveltekit/internal/MockProvider.svelte';\nimport {\n  setAppStateNavigating,\n  setAppStatePage,\n  setAppStateUpdated, // @ts-expect-error no declaration file for this JS module\n} from '@storybook/sveltekit/internal/mocks/app/state.svelte.js';\n\nimport type { SvelteKitParameters } from './types.ts';\n\nconst svelteKitMocksDecorator: Decorator = (Story, ctx) => {\n  const svelteKitParameters: SvelteKitParameters = ctx.parameters?.sveltekit_experimental ?? {};\n\n  return {\n    Component: MockProvider,\n    props: {\n      svelteKitParameters,\n    },\n  };\n};\n\nexport const decorators: Decorator[] = [svelteKitMocksDecorator];\n\nexport const beforeEach: Preview['beforeEach'] = async (ctx) => {\n  const svelteKitParameters: SvelteKitParameters = ctx.parameters?.sveltekit_experimental ?? {};\n\n  setAppStatePage(svelteKitParameters?.state?.page);\n  setAppStateNavigating(svelteKitParameters?.state?.navigating);\n  setAppStateUpdated(svelteKitParameters?.state?.updated);\n};\n"
  },
  {
    "path": "code/frameworks/sveltekit/src/types.ts",
    "content": "import type {\n  CompatibleString,\n  StorybookConfig as StorybookConfigBase,\n} from 'storybook/internal/types';\n\nimport type { BuilderOptions, StorybookConfigVite } from '@storybook/builder-vite';\n\nimport type { enhance } from './mocks/app/forms.ts';\nimport type { goto, invalidate, invalidateAll } from './mocks/app/navigation.ts';\n\ntype FrameworkName = CompatibleString<'@storybook/sveltekit'>;\ntype BuilderName = CompatibleString<'@storybook/builder-vite'>;\n\nexport type FrameworkOptions = {\n  builder?: BuilderOptions;\n  /**\n   * Enable or disable automatic documentation generation for component properties, events, and\n   * slots. When disabled, Storybook will skip the docgen processing step during build, which can\n   * improve build performance.\n   *\n   * @default true\n   */\n  docgen?: boolean;\n};\n\ntype StorybookConfigFramework = {\n  framework:\n    | FrameworkName\n    | {\n        name: FrameworkName;\n        options: FrameworkOptions;\n      };\n  core?: StorybookConfigBase['core'] & {\n    builder?:\n      | BuilderName\n      | {\n          name: BuilderName;\n          options: BuilderOptions;\n        };\n  };\n};\n\nexport type StorybookConfig = Omit<\n  StorybookConfigBase,\n  keyof StorybookConfigVite | keyof StorybookConfigFramework\n> &\n  StorybookConfigVite &\n  StorybookConfigFramework;\n\nexport type NormalizedHrefConfig = {\n  callback: (to: string, event: Event) => void;\n  asRegex?: boolean;\n};\n\nexport type HrefConfig = NormalizedHrefConfig | NormalizedHrefConfig['callback'];\n\n/**\n * Copied from:\n * {@link https://github.com/sveltejs/kit/blob/7bb41aa4263b057a8912f4cdd35db03755d37342/packages/kit/types/index.d.ts#L1102-L1143}\n */\ninterface Page<\n  Params extends Record<string, string> = Record<string, string>,\n  RouteId extends string | null = string | null,\n> {\n  url: URL;\n  params: Params;\n  route: {\n    id: RouteId;\n  };\n  status: number;\n  error: Error | null;\n  data: Record<string, any>;\n  state: Record<string, any>;\n  form: any;\n}\n\n/**\n * Copied from:\n * {@link https://github.com/sveltejs/kit/blob/7bb41aa4263b057a8912f4cdd35db03755d37342/packages/kit/types/index.d.ts#L988}\n */\ninterface NavigationTarget {\n  params: Record<string, string> | null;\n  route: {\n    id: string | null;\n  };\n  url: URL;\n}\n\n/**\n * Copied from:\n * {@link https://github.com/sveltejs/kit/blob/7bb41aa4263b057a8912f4cdd35db03755d37342/packages/kit/types/index.d.ts#L1017C9-L1017C89}\n */\ntype NavigationType = 'enter' | 'form' | 'leave' | 'link' | 'goto' | 'popstate';\n\n/**\n * Copied from:\n * {@link https://github.com/sveltejs/kit/blob/7bb41aa4263b057a8912f4cdd35db03755d37342/packages/kit/types/index.d.ts#L1017C9-L1017C89}\n */\ninterface Navigation {\n  from: NavigationTarget | null;\n  to: NavigationTarget | null;\n  type: Exclude<NavigationType, 'enter'>;\n  willUnload: boolean;\n  delta?: number;\n  complete: Promise<void>;\n}\n\nexport type SvelteKitParameters = Partial<{\n  hrefs: Record<string, HrefConfig>;\n  state: {\n    page: Partial<Page>;\n    navigating: Partial<Navigation>;\n    updated: { current: boolean };\n  };\n  /**\n   * @deprecated\n   * @see {@link https://svelte.dev/docs/kit/$app-stores}\n   */\n  stores: {\n    page: Record<string, any>;\n    navigating: Record<string, any>;\n    updated: boolean;\n  };\n  navigation: {\n    goto: typeof goto;\n    invalidate: typeof invalidate;\n    invalidateAll: typeof invalidateAll;\n    afterNavigate: Record<string, any>;\n  };\n  forms: {\n    enhance: typeof enhance;\n  };\n}>;\n"
  },
  {
    "path": "code/frameworks/sveltekit/src/vite-plugin.ts",
    "content": "import { mockSveltekitStores } from './plugins/mock-sveltekit-stores.ts';\n\nexport const storybookSveltekitPlugin = () => {\n  return [mockSveltekitStores()];\n};\n"
  },
  {
    "path": "code/frameworks/sveltekit/static/MockProvider.svelte",
    "content": "<script>\n  import { onMount } from 'svelte';\n  import { action } from 'storybook/actions';\n  \n  import { setAfterNavigateArgument } from '@storybook/sveltekit/internal/mocks/app/navigation';\n  import { setAppStoresNavigating, setAppStoresPage, setAppStoresUpdated } from '@storybook/sveltekit/internal/mocks/app/stores';\n\n  const { svelteKitParameters = {}, children } = $props();\n\n  // Set context during component initialization - this happens before any child components\n  setAppStoresPage(svelteKitParameters?.stores?.page);\n  setAppStoresNavigating(svelteKitParameters?.stores?.navigating);\n  setAppStoresUpdated(svelteKitParameters?.stores?.updated);\n  setAfterNavigateArgument(svelteKitParameters?.navigation?.afterNavigate);\n\n  const normalizeHrefConfig = (hrefConfig) => {\n    if (typeof hrefConfig === 'function') {\n      return { callback: hrefConfig, asRegex: false };\n    }\n    return hrefConfig;\n  };\n\n  onMount(() => {\n    const globalClickListener = (e) => {\n      // we add a global click event listener and we check if there's a link in the composedPath\n      const path = e.composedPath();\n      const element = path.findLast((el) => el instanceof HTMLElement && el.tagName === 'A');\n      if (element && element instanceof HTMLAnchorElement) {\n        // if the element is an a-tag we get the href of the element\n        // and compare it to the hrefs-parameter set by the user\n        const to = element.getAttribute('href');\n        if (!to) {\n          return;\n        }\n        e.preventDefault();\n        const defaultActionCallback = () => action('navigate')(to, e);\n        if (!svelteKitParameters.hrefs) {\n          defaultActionCallback();\n          return;\n        }\n\n        let callDefaultCallback = true;\n        // we loop over every href set by the user and check if the href matches\n        // if it does we call the callback provided by the user and disable the default callback\n        Object.entries(svelteKitParameters.hrefs).forEach(([href, hrefConfig]) => {\n          const { callback, asRegex } = normalizeHrefConfig(hrefConfig);\n          const isMatch = asRegex ? new RegExp(href).test(to) : to === href;\n          if (isMatch) {\n            callDefaultCallback = false;\n            callback?.(to, e);\n          }\n        });\n        if (callDefaultCallback) {\n          defaultActionCallback();\n        }\n      }\n    };\n\n    /**\n     * Function that create and add listeners for the event that are emitted by the mocked\n     * functions. The event name is based on the function name\n     *\n     * Eg. storybook:goto, storybook:invalidateAll\n     *\n     * @param baseModule The base module where the function lives (navigation|forms)\n     * @param functions The list of functions in that module that emit events\n     * @param {boolean} [defaultToAction] The list of functions in that module that emit events\n     * @returns A function to remove all the listener added\n     */\n    function createListeners(baseModule, functions, defaultToAction) {\n      // the array of every added listener, we can use this in the return function\n      // to clean them\n      const toRemove = [];\n      functions.forEach((func) => {\n        // we loop over every function and check if the user actually passed\n        // a function in sveltekit_experimental[baseModule][func] eg. sveltekit_experimental.navigation.goto\n        const hasFunction =\n          svelteKitParameters[baseModule]?.[func] &&\n          svelteKitParameters[baseModule][func] instanceof Function;\n        // if we default to an action we still add the listener (this will be the case for goto, invalidate, invalidateAll)\n        if (hasFunction || defaultToAction) {\n          // we create the listener that will just get the detail array from the custom element\n          // and call the user provided function spreading this args in...this will basically call\n          // the function that the user provide with the same arguments the function is invoked to\n\n          // eg. if it calls goto(\"/my-route\") inside the component the function sveltekit_experimental.navigation.goto\n          // it provided to storybook will be called with \"/my-route\"\n          const listener = ({ detail = [] }) => {\n            const args = Array.isArray(detail) ? detail : [];\n            // if it has a function in the parameters we call that function\n            // otherwise we invoke the action\n            const fnToCall = hasFunction\n              ? svelteKitParameters[baseModule][func]\n              : action(func);\n            fnToCall(...args);\n          };\n          const eventType = `storybook:${func}`;\n          toRemove.push({ eventType, listener });\n          // add the listener to window\n          window.addEventListener(eventType, listener);\n        }\n      });\n      return () => {\n        // loop over every listener added and remove them\n        toRemove.forEach(({ eventType, listener }) => {\n          window.removeEventListener(eventType, listener);\n        });\n      };\n    }\n\n    const removeNavigationListeners = createListeners(\n      'navigation',\n      ['goto', 'invalidate', 'invalidateAll', 'pushState', 'replaceState'],\n      true\n    );\n    const removeFormsListeners = createListeners('forms', ['enhance']);\n    window.addEventListener('click', globalClickListener);\n\n    return () => {\n      window.removeEventListener('click', globalClickListener);\n      removeNavigationListeners();\n      removeFormsListeners();\n    };\n  });\n</script>\n\n{@render children()}\n"
  },
  {
    "path": "code/frameworks/sveltekit/static/app-state-mock.svelte.js",
    "content": "/**\n * Inspired by the the code:\n * {@link https://github.com/sveltejs/kit/blob/main/packages/kit/src/runtime/client/state.svelte.js}\n *\n * The differences:\n *\n * - Legacy Svelte support is not included\n * - Not using classes (internal coding style preference)\n *\n * @module\n */\nimport { fn } from 'storybook/test';\n\n/**\n * @typedef {Object} App\n * @property {Object} Error\n * @property {string} Error.message\n * @property {Object} Locals\n * @property {Object} PageData\n * @property {Object} PageState\n * @property {Object} Platform\n */\n\n/**\n * @typedef {Object} Page\n * @property {URL} url\n * @property {Record<string, string>} params\n * @property {Object} route\n * @property {string | null} route.id\n * @property {number} status\n * @property {App.Error | null} error\n * @property {App.PageData & Record<string, any>} data\n * @property {App.PageState} state\n * @property {any} form\n */\n\nconst defaultStatePageValues = {\n  data: {},\n  form: null,\n  error: null,\n  params: {},\n  route: { id: null },\n  state: {},\n  status: -1,\n  url: new URL(location.origin),\n};\n\n/** @type {Page['data']} */\nlet pageData = $state.raw(defaultStatePageValues.data);\n/** @type {Page['form']} */\nlet pageForm = $state.raw(defaultStatePageValues.form);\n/** @type {Page['error']} */\nlet pageError = $state.raw(defaultStatePageValues.error);\n/** @type {Page['params']} */\nlet pageParams = $state.raw(defaultStatePageValues.params);\n/** @type {Page['route']} */\nlet pageRoute = $state.raw(defaultStatePageValues.route);\n/** @type {Page['state']} */\nlet pageState = $state.raw(defaultStatePageValues.state);\n/** @type {Page['status']} */\nlet pageStatus = $state.raw(defaultStatePageValues.status);\n/** @type {Page['url']} */\nlet pageUrl = $state.raw(defaultStatePageValues.url);\n\n/** @type {Page} */\nexport let page = {\n  get data() {\n    return pageData;\n  },\n  set data(newPageData) {\n    pageData = newPageData;\n  },\n  get form() {\n    return pageForm;\n  },\n  set form(newPageForm) {\n    pageForm = newPageForm;\n  },\n  get error() {\n    return pageError;\n  },\n  set error(newPageError) {\n    pageError = newPageError;\n  },\n  get params() {\n    return pageParams;\n  },\n  set params(newPageParams) {\n    pageParams = newPageParams;\n  },\n  get route() {\n    return pageRoute;\n  },\n  set route(newPageRoute) {\n    pageRoute = newPageRoute;\n  },\n  get state() {\n    return pageState;\n  },\n  set state(newPageState) {\n    pageState = newPageState;\n  },\n  get status() {\n    return pageStatus;\n  },\n  set status(newPageStatus) {\n    pageStatus = newPageStatus;\n  },\n  get url() {\n    return pageUrl;\n  },\n  set url(newPageUrl) {\n    pageUrl = newPageUrl;\n  },\n};\n\nexport function setAppStatePage(params = {}) {\n  page.data = params.data ?? defaultStatePageValues.data;\n  page.form = params.form ?? defaultStatePageValues.form;\n  page.error = params.error ?? defaultStatePageValues.error;\n  page.params = params.params ?? defaultStatePageValues.params;\n  page.route = params.route ?? defaultStatePageValues.route;\n  page.state = params.state ?? defaultStatePageValues.state;\n  page.status = params.status ?? defaultStatePageValues.status;\n  page.url = params.url ?? defaultStatePageValues.url;\n}\n\n/**\n * @typedef {Object} NavigationTarget\n * @property {Record<string, string> | null} params\n * @property {Object} route\n * @property {string | null} route.id\n * @property {URL} url\n */\n\n/** @typedef {'enter' | 'form' | 'leave' | 'link' | 'goto' | 'popstate'} NavigationType */\n\n/**\n * @typedef {Object} Navigation\n * @property {NavigationTarget | null} from\n * @property {NavigationTarget | null} to\n * @property {Exclude<NavigationType, 'enter'>} type\n * @property {boolean} willUnload\n * @property {number} [delta]\n * @property {Promise<void>} complete\n */\n\nconst defaultStateNavigatingValues = {\n  from: null,\n  to: null,\n  type: null,\n  willUnload: null,\n  delta: null,\n  complete: null,\n};\n\n/** @type {Navigation['from'] | null} */\nlet navigatingFrom = $state.raw(defaultStateNavigatingValues.from);\n/** @type {Navigation['to'] | null} */\nlet navigatingTo = $state.raw(defaultStateNavigatingValues.to);\n/** @type {Navigation['type'] | null} */\nlet navigatingType = $state.raw(defaultStateNavigatingValues.type);\n/** @type {Navigation['willUnload'] | null} */\nlet navigatingWillUnload = $state.raw(defaultStateNavigatingValues.willUnload);\n/** @type {Navigation['delta'] | null} */\nlet navigatingDelta = $state.raw(defaultStateNavigatingValues.delta);\n/** @type {Navigation['complete'] | null} */\nlet navigatingComplete = $state.raw(defaultStateNavigatingValues.complete);\n\n/** @type {Navigation} */\nexport let navigating = {\n  get from() {\n    return navigatingFrom;\n  },\n  set from(newNavigatingFrom) {\n    navigatingFrom = newNavigatingFrom;\n  },\n  get to() {\n    return navigatingTo;\n  },\n  set to(newNavigatingTo) {\n    navigatingTo = newNavigatingTo;\n  },\n  get type() {\n    return navigatingType;\n  },\n  set type(newNavigatingType) {\n    navigatingType = newNavigatingType;\n  },\n  get willUnload() {\n    return navigatingWillUnload;\n  },\n  set willUnload(newNavigatingWillUnload) {\n    navigatingWillUnload = newNavigatingWillUnload;\n  },\n  get delta() {\n    return navigatingDelta;\n  },\n  set delta(newNavigatingDelta) {\n    navigatingDelta = newNavigatingDelta;\n  },\n  get complete() {\n    return navigatingComplete;\n  },\n  set complete(newNavigatingComplete) {\n    navigatingComplete = newNavigatingComplete;\n  },\n};\n\nexport function setAppStateNavigating(params = {}) {\n  navigating.from = params.from ?? defaultStateNavigatingValues.from;\n  navigating.to = params.to ?? defaultStateNavigatingValues.to;\n  navigating.type = params.type ?? defaultStateNavigatingValues.type;\n  navigating.willUnload = params.willUnload ?? defaultStateNavigatingValues.willUnload;\n  navigating.delta = params.delta ?? defaultStateNavigatingValues.delta;\n  navigating.complete = params.complete ?? defaultStateNavigatingValues.complete;\n}\n\n/** @type {boolean} */\nlet updatedCurrent = $state.raw(false);\n\nexport let updated = {\n  get current() {\n    return updatedCurrent;\n  },\n  set current(newCurrent) {\n    updatedCurrent = newCurrent;\n  },\n  check: fn(() => Promise.resolve(updatedCurrent)),\n};\n\nexport function setAppStateUpdated(params = {}) {\n  updated.current = params.current ?? false;\n}\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/cli/js/Button.stories.svelte",
    "content": "<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import Button from './Button.svelte';\n  import { fn } from 'storybook/test';\n\n  // More on how to set up stories at: https://storybook.js.org/docs/writing-stories\n  const { Story } = defineMeta({\n    title: 'Example/Button',\n    component: Button,\n    tags: ['autodocs'],\n    argTypes: {\n      backgroundColor: { control: 'color' },\n      size: {\n        control: { type: 'select' },\n        options: ['small', 'medium', 'large'],\n      },\n    },\n    args: {\n      onclick: fn(),\n    }\n  });\n</script>\n\n<!-- More on writing stories with args: https://storybook.js.org/docs/writing-stories/args -->\n<Story name=\"Primary\" args={{ primary: true, label: 'Button' }} />\n\n<Story name=\"Secondary\" args={{ label: 'Button' }} />\n\n<Story name=\"Large\" args={{ size: 'large', label: 'Button' }} />\n\n<Story name=\"Small\" args={{ size: 'small', label: 'Button' }} />\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/cli/js/Button.svelte",
    "content": "<script>\n  import './button.css';\n\n  /**\n   * @typedef {Object} Props\n   * @property {boolean} [primary] Is this the principal call to action on the page?\n   * @property {string} [backgroundColor] What background color to use\n   * @property {'small' | 'medium' | 'large'} [size] How large should the button be?\n   * @property {string} label Button contents\n   * @property {() => void} [onclick] The onclick event handler\n   */\n\n  /** @type {Props} */\n  const { primary = false, backgroundColor, size = 'medium', label, ...props } = $props();\n\n  let mode = $derived(primary ? 'storybook-button--primary' : 'storybook-button--secondary');\n  let style = $derived(backgroundColor ? `background-color: ${backgroundColor}` : '');\n</script>\n\n<button\n  type=\"button\"\n  class={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n  {style}\n  {...props}\n>\n  {label}\n</button>\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/cli/js/Header.stories.svelte",
    "content": "<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import Header from './Header.svelte';\n  import { fn } from 'storybook/test';\n\n  // More on how to set up stories at: https://storybook.js.org/docs/writing-stories\n  const { Story } = defineMeta({\n    title: 'Example/Header',\n    component: Header,\n    // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n    tags: ['autodocs'],\n    parameters: {\n      // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n      layout: 'fullscreen',\n    },\n    args: {\n      onLogin: fn(),\n      onLogout: fn(),\n      onCreateAccount: fn(),\n    }\n  });\n</script>\n\n<Story name=\"Logged In\" args={{ user: { name: 'Jane Doe' } }} />\n\n<Story name=\"Logged Out\" />\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/cli/js/Header.svelte",
    "content": "<script>\n  import './header.css';\n  import Button from './Button.svelte';\n\n  /**\n   * @typedef {Object} Props\n   * @property {{name: string}} [user] The user object\n   * @property {() => void} [onLogin] The login event handler\n   * @property {() => void} [onLogout] The logout event handler\n   * @property {() => void} [onCreateAccount] The account creation event handler\n   */\n\n  /** @type {Props} */\n  const { user, onLogin, onLogout, onCreateAccount } = $props();\n</script>\n\n<header>\n  <div class=\"storybook-header\">\n    <div>\n      <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n        <g fill=\"none\" fill-rule=\"evenodd\">\n          <path\n            d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n            fill=\"#FFF\"\n          />\n          <path\n            d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n            fill=\"#555AB9\"\n          />\n          <path d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\" fill=\"#91BAF8\" />\n        </g>\n      </svg>\n      <h1>Acme</h1>\n    </div>\n    <div>\n      {#if user}\n        <span class=\"welcome\">\n          Welcome, <b>{user.name}</b>!\n        </span>\n        <Button size=\"small\" onclick={onLogout} label=\"Log out\" />\n      {:else}\n        <Button size=\"small\" onclick={onLogin} label=\"Log in\" />\n        <Button primary size=\"small\" onclick={onCreateAccount} label=\"Sign up\" />\n      {/if}\n    </div>\n  </div>\n</header>\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/cli/js/Page.stories.svelte",
    "content": "<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import { expect, userEvent, waitFor, within } from 'storybook/test';\n  import Page from './Page.svelte';\n  import { fn } from 'storybook/test';\n\n  // More on how to set up stories at: https://storybook.js.org/docs/writing-stories\n  const { Story } = defineMeta({\n    title: 'Example/Page',\n    component: Page,\n    parameters: {\n      // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n      layout: 'fullscreen',\n    },\n  });\n</script>\n\n<Story name=\"Logged In\" play={async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await waitFor(() => expect(loginButton).not.toBeInTheDocument());\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  }}\n  />\n\n<Story name=\"Logged Out\" />\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/cli/js/Page.svelte",
    "content": "<script>\n  import './page.css';\n  import Header from './Header.svelte';\n\n  let user = $state();\n</script>\n\n<article>\n  <Header\n    {user}\n    onLogin={() => (user = { name: 'Jane Doe' })}\n    onLogout={() => (user = undefined)}\n    onCreateAccount={() => (user = { name: 'Jane Doe' })}\n  />\n\n  <section class=\"storybook-page\">\n    <h2>Pages in Storybook</h2>\n    <p>\n      We recommend building UIs with a\n      <a\n        href=\"https://blog.hichroma.com/component-driven-development-ce1109d56c8e\"\n        target=\"_blank\"\n        rel=\"noopener noreferrer\"\n      >\n        <strong>component-driven</strong>\n      </a>\n      process starting with atomic components and ending with pages.\n    </p>\n    <p>\n      Render pages with mock data. This makes it easy to build and review page states without\n      needing to navigate to them in your app. Here are some handy patterns for managing page data\n      in Storybook:\n    </p>\n    <ul>\n      <li>\n        Use a higher-level connected component. Storybook helps you compose such data from the\n        \"args\" of child component stories\n      </li>\n      <li>\n        Assemble data in the page component from your services. You can mock these services out\n        using Storybook.\n      </li>\n    </ul>\n    <p>\n      Get a guided tutorial on component-driven development at\n      <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n        Storybook tutorials\n      </a>\n      . Read more in the\n      <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">docs</a>\n      .\n    </p>\n    <div class=\"tip-wrapper\">\n      <span class=\"tip\">Tip</span>\n      Adjust the width of the canvas with the\n      <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n        <g fill=\"none\" fill-rule=\"evenodd\">\n          <path\n            d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0\n            01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0\n            010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n            id=\"a\"\n            fill=\"#999\"\n          />\n        </g>\n      </svg>\n      Viewports addon in the toolbar\n    </div>\n  </section>\n</article>\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/cli/ts/Button.stories.svelte",
    "content": "<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import Button from './Button.svelte';\n  import { fn } from 'storybook/test';\n\n  // More on how to set up stories at: https://storybook.js.org/docs/writing-stories\n  const { Story } = defineMeta({\n    title: 'Example/Button',\n    component: Button,\n    tags: ['autodocs'],\n    argTypes: {\n      backgroundColor: { control: 'color' },\n      size: {\n        control: { type: 'select' },\n        options: ['small', 'medium', 'large'],\n      },\n    },\n    args: {\n      onclick: fn(),\n    }\n  });\n</script>\n\n<!-- More on writing stories with args: https://storybook.js.org/docs/writing-stories/args -->\n<Story name=\"Primary\" args={{ primary: true, label: 'Button' }} />\n\n<Story name=\"Secondary\" args={{ label: 'Button' }} />\n\n<Story name=\"Large\" args={{ size: 'large', label: 'Button' }} />\n\n<Story name=\"Small\" args={{ size: 'small', label: 'Button' }} />\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/cli/ts/Button.svelte",
    "content": "<script lang=\"ts\">\n  import './button.css';\n\n  interface Props {\n    /** Is this the principal call to action on the page? */\n    primary?: boolean;\n    /** What background color to use */\n    backgroundColor?: string;\n    /** How large should the button be? */\n    size?: 'small' | 'medium' | 'large';\n    /** Button contents */\n    label: string;\n    /** The onclick event handler */\n    onclick?: () => void;\n  }\n\n  const { primary = false, backgroundColor, size = 'medium', label, ...props }: Props = $props();\n  \n  let mode = $derived(primary ? 'storybook-button--primary' : 'storybook-button--secondary');\n  let style = $derived(backgroundColor ? `background-color: ${backgroundColor}` : '');\n</script>\n\n<button\n  type=\"button\"\n  class={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n  {style}\n  {...props}\n>\n  {label}\n</button>\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/cli/ts/Header.stories.svelte",
    "content": "<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import Header from './Header.svelte';\n  import { fn } from 'storybook/test';\n\n  // More on how to set up stories at: https://storybook.js.org/docs/writing-stories\n  const { Story } = defineMeta({\n    title: 'Example/Header',\n    component: Header,\n    // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n    tags: ['autodocs'],\n    parameters: {\n      // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n      layout: 'fullscreen',\n    },\n    args: {\n      onLogin: fn(),\n      onLogout: fn(),\n      onCreateAccount: fn(),\n    }\n  });\n</script>\n\n<Story name=\"Logged In\" args={{ user: { name: 'Jane Doe' } }} />\n\n<Story name=\"Logged Out\" />\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/cli/ts/Header.svelte",
    "content": "<script lang=\"ts\">\n  import './header.css';\n  import Button from './Button.svelte';\n\n  interface Props {\n    user?: { name: string };\n    onLogin?: () => void;\n    onLogout?: () => void;\n    onCreateAccount?: () => void;\n  }\n\n  const { user, onLogin, onLogout, onCreateAccount }: Props = $props();\n</script>\n\n<header>\n  <div class=\"storybook-header\">\n    <div>\n      <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n        <g fill=\"none\" fill-rule=\"evenodd\">\n          <path\n            d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n            fill=\"#FFF\"\n          />\n          <path\n            d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n            fill=\"#555AB9\"\n          />\n          <path d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\" fill=\"#91BAF8\" />\n        </g>\n      </svg>\n      <h1>Acme</h1>\n    </div>\n    <div>\n      {#if user}\n        <span class=\"welcome\">\n          Welcome, <b>{user.name}</b>!\n        </span>\n        <Button size=\"small\" onclick={onLogout} label=\"Log out\" />\n      {:else}\n        <Button size=\"small\" onclick={onLogin} label=\"Log in\" />\n        <Button primary size=\"small\" onclick={onCreateAccount} label=\"Sign up\" />\n      {/if}\n    </div>\n  </div>\n</header>\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/cli/ts/Page.stories.svelte",
    "content": "<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import { expect, userEvent, waitFor, within } from 'storybook/test';\n  import Page from './Page.svelte';\n  import { fn } from 'storybook/test';\n\n  // More on how to set up stories at: https://storybook.js.org/docs/writing-stories\n  const { Story } = defineMeta({\n    title: 'Example/Page',\n    component: Page,\n    parameters: {\n      // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n      layout: 'fullscreen',\n    },\n  });\n</script>\n\n<Story name=\"Logged In\" play={async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await waitFor(() => expect(loginButton).not.toBeInTheDocument());\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  }}\n/>\n\n<Story name=\"Logged Out\" />\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/cli/ts/Page.svelte",
    "content": "<script lang=\"ts\">\n  import './page.css';\n  import Header from './Header.svelte';\n\n  let user = $state<{ name: string }>();\n</script>\n\n<article>\n  <Header\n    {user}\n    onLogin={() => (user = { name: 'Jane Doe' })}\n    onLogout={() => (user = undefined)}\n    onCreateAccount={() => (user = { name: 'Jane Doe' })}\n  />\n\n  <section class=\"storybook-page\">\n    <h2>Pages in Storybook</h2>\n    <p>\n      We recommend building UIs with a\n      <a\n        href=\"https://blog.hichroma.com/component-driven-development-ce1109d56c8e\"\n        target=\"_blank\"\n        rel=\"noopener noreferrer\"\n      >\n        <strong>component-driven</strong>\n      </a>\n      process starting with atomic components and ending with pages.\n    </p>\n    <p>\n      Render pages with mock data. This makes it easy to build and review page states without\n      needing to navigate to them in your app. Here are some handy patterns for managing page data\n      in Storybook:\n    </p>\n    <ul>\n      <li>\n        Use a higher-level connected component. Storybook helps you compose such data from the\n        \"args\" of child component stories\n      </li>\n      <li>\n        Assemble data in the page component from your services. You can mock these services out\n        using Storybook.\n      </li>\n    </ul>\n    <p>\n      Get a guided tutorial on component-driven development at\n      <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n        Storybook tutorials\n      </a>\n      . Read more in the\n      <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">docs</a>\n      .\n    </p>\n    <div class=\"tip-wrapper\">\n      <span class=\"tip\">Tip</span>\n      Adjust the width of the canvas with the\n      <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n        <g fill=\"none\" fill-rule=\"evenodd\">\n          <path\n            d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0\n            01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0\n            010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n            id=\"a\"\n            fill=\"#999\"\n          />\n        </g>\n      </svg>\n      Viewports addon in the toolbar\n    </div>\n  </section>\n</article>\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/modules/Environment.svelte",
    "content": "<script>\n  import { browser, dev, building, version } from '$app/environment';\n</script>\n\n<div data-testid=\"browser\">{browser}</div>\n<div data-testid=\"dev\">{dev}</div>\n<div data-testid=\"building\">{building}</div>\n<div data-testid=\"version\" data-chromatic=\"ignore\">{version}</div>\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/modules/Forms.svelte",
    "content": "<script>\n\timport { enhance } from '$app/forms';\n</script>\n\n<form use:enhance method=\"post\">\n\t<button>enhance</button>\n</form>"
  },
  {
    "path": "code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/modules/Hrefs.svelte",
    "content": "<ul>\n  <li><a href=\"/basic-href\">Link to <code>/basic-href</code></a></li>\n  <li>\n    <a href=\"/deep/nested/link?with=true&multiple-params=200#and-an-id\"\n      >Link to <code>/deep/nested/link?with=true&multiple-params=200#and-an-id</code></a\n    >\n  </li>\n</ul>\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/modules/Navigation.svelte",
    "content": "<script>\n  import {\n    goto,\n    invalidate,\n    invalidateAll,\n    afterNavigate,\n    replaceState,\n    pushState,\n  } from '$app/navigation';\n\n  const { afterNavigateFn } = $props();\n\n  afterNavigate(afterNavigateFn);\n</script>\n\n<button\n  on:click={() => {\n    goto('/storybook-goto');\n  }}>goto</button\n>\n\n<button\n  on:click={() => {\n    invalidate('/storybook-invalidate');\n  }}>invalidate</button\n>\n\n<button\n  on:click={() => {\n    invalidateAll();\n  }}>invalidateAll</button\n>\n\n<button\n  on:click={() => {\n    pushState('/storybook-push-state', {});\n  }}>pushState</button\n>\n\n<button\n  on:click={() => {\n    replaceState('/storybook-replace-state', {});\n  }}>replaceState</button\n>\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/modules/Paths.svelte",
    "content": "<script>\n\timport { assets, base } from \"$app/paths\";\n</script>\n\n<div data-testid=\"assets\">{assets}</div>\n<div data-testid=\"base\">{base}</div>\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/modules/State.svelte",
    "content": "<script>\n\timport { page, navigating, updated } from '$app/state';\n\n\tupdated.check();\n</script>\n\n<h1>$app/state</h1>\n\n<h2>page</h2>\n<pre>{JSON.stringify(page, null, 2)}</pre>\n\n<h2>navigating</h2>\n<pre>{JSON.stringify(navigating, null, 2)}</pre>\n\n<h2>updated</h2>\n<pre>{JSON.stringify(updated, null, 2)}</pre>\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/modules/Stores.svelte",
    "content": "<script>\n\timport { page, navigating, updated, getStores } from '$app/stores';\n\n\tlet { navigating: navigatingStore, page: pageStore, updated: updatedStore } = getStores();\n\n\tupdated.check();\n</script>\n\n<p>Directly importing</p>\n<pre>{JSON.stringify($page, null, 2)}</pre>\n<pre>{JSON.stringify($navigating, null, 2)}</pre>\n<pre>{JSON.stringify($updated, null, 2)}</pre>\n\n<p>With getStores</p>\n<pre>{JSON.stringify($pageStore, null, 2)}</pre>\n<pre>{JSON.stringify($navigatingStore, null, 2)}</pre>\n<pre>{JSON.stringify($updatedStore, null, 2)}</pre>\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/modules/environment.stories.js",
    "content": "import Environment from './Environment.svelte';\n\nexport default {\n  title: 'stories/frameworks/sveltekit/modules/environment',\n  component: Environment,\n};\n\nexport const Default = {};\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/modules/forms.stories.js",
    "content": "import { expect, fn, within } from 'storybook/test';\n\nimport Forms from './Forms.svelte';\n\nexport default {\n  title: 'stories/frameworks/sveltekit/modules/forms',\n  component: Forms,\n};\n\nconst enhance = fn();\n\nexport const Enhance = {\n  async play({ canvasElement }) {\n    const canvas = within(canvasElement);\n    const button = canvas.getByText('enhance');\n    button.click();\n    expect(enhance).toHaveBeenCalled();\n  },\n  parameters: {\n    sveltekit_experimental: {\n      forms: {\n        enhance,\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/modules/hrefs.stories.js",
    "content": "import { expect, fn, within } from 'storybook/test';\n\nimport Hrefs from './Hrefs.svelte';\n\nexport default {\n  title: 'stories/frameworks/sveltekit/modules/hrefs',\n  component: Hrefs,\n};\n\nexport const DefaultActions = {\n  async play({ canvasElement }) {\n    const canvas = within(canvasElement);\n\n    const initialUrl = window.location.toString();\n\n    const basicHref = canvas.getByText('/basic-href');\n    basicHref.click();\n\n    const complexHref = canvas.getByText(\n      '/deep/nested/link?with=true&multiple-params=200#and-an-id'\n    );\n    complexHref.click();\n\n    const finalUrl = window.location.toString();\n    expect(finalUrl).toBe(initialUrl);\n  },\n};\n\nconst basicStringMatch = fn();\nconst noMatch = fn();\nconst exactStringMatch = fn();\nconst regexMatch = fn();\n\nexport const Callbacks = {\n  parameters: {\n    sveltekit_experimental: {\n      hrefs: {\n        '/basic-href': basicStringMatch,\n        '/basic': noMatch,\n        '/deep/nested/link?with=true&multiple-params=200#and-an-id': exactStringMatch,\n        'nested/link\\\\?with': { callback: regexMatch, asRegex: true },\n      },\n    },\n  },\n  play: async (ctx) => {\n    await DefaultActions.play(ctx);\n    expect(basicStringMatch).toHaveBeenCalledTimes(1);\n    expect(noMatch).not.toHaveBeenCalled();\n    expect(exactStringMatch).toHaveBeenCalledTimes(1);\n    expect(regexMatch).toHaveBeenCalledTimes(1);\n  },\n};\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/modules/navigation.stories.js",
    "content": "import { expect, fn, within } from 'storybook/test';\n\nimport Navigation from './Navigation.svelte';\n\nexport default {\n  title: 'stories/frameworks/sveltekit/modules/navigation',\n  component: Navigation,\n};\n\nconst goto = fn();\n\nexport const Goto = {\n  async play({ canvasElement }) {\n    const canvas = within(canvasElement);\n    const button = canvas.getByText('goto');\n    button.click();\n    expect(goto).toHaveBeenCalledWith('/storybook-goto');\n  },\n  parameters: {\n    sveltekit_experimental: {\n      navigation: {\n        goto,\n      },\n    },\n  },\n};\n\nconst replaceState = fn();\n\nexport const ReplaceState = {\n  async play({ canvasElement }) {\n    const canvas = within(canvasElement);\n    const button = canvas.getByText('replaceState');\n    button.click();\n    expect(replaceState).toHaveBeenCalledWith('/storybook-replace-state', {});\n  },\n  parameters: {\n    sveltekit_experimental: {\n      navigation: {\n        replaceState,\n      },\n    },\n  },\n};\n\nconst pushState = fn();\n\nexport const PushState = {\n  async play({ canvasElement }) {\n    const canvas = within(canvasElement);\n    const button = canvas.getByText('pushState');\n    button.click();\n    expect(pushState).toHaveBeenCalledWith('/storybook-push-state', {});\n  },\n  parameters: {\n    sveltekit_experimental: {\n      navigation: {\n        pushState,\n      },\n    },\n  },\n};\n\nexport const DefaultActions = {};\n\nconst invalidate = fn();\n\nexport const Invalidate = {\n  async play({ canvasElement }) {\n    const canvas = within(canvasElement);\n    const button = canvas.getByText('invalidate', { exact: true });\n    button.click();\n    expect(invalidate).toHaveBeenCalledWith('/storybook-invalidate');\n  },\n  parameters: {\n    sveltekit_experimental: {\n      navigation: {\n        invalidate,\n      },\n    },\n  },\n};\n\nconst invalidateAll = fn();\n\nexport const InvalidateAll = {\n  async play({ canvasElement }) {\n    const canvas = within(canvasElement);\n    const button = canvas.getByText('invalidateAll');\n    button.click();\n    expect(invalidateAll).toHaveBeenCalledWith();\n  },\n  parameters: {\n    sveltekit_experimental: {\n      navigation: {\n        invalidateAll,\n      },\n    },\n  },\n};\n\nconst afterNavigateFn = fn();\n\nexport const AfterNavigate = {\n  async play() {\n    expect(afterNavigateFn).toHaveBeenCalledWith({ test: 'passed' });\n  },\n  args: {\n    afterNavigateFn,\n  },\n  parameters: {\n    sveltekit_experimental: {\n      navigation: {\n        afterNavigate: {\n          test: 'passed',\n        },\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/modules/paths.stories.js",
    "content": "import Paths from './Paths.svelte';\n\nexport default {\n  title: 'stories/frameworks/sveltekit/modules/paths',\n  component: Paths,\n};\n\nexport const Default = {};\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/modules/state.stories.js",
    "content": "import State from './State.svelte';\n\nexport default {\n  title: 'stories/frameworks/sveltekit/modules/state',\n  component: State,\n  parameters: {\n    sveltekit_experimental: {\n      state: {\n        page: {\n          url: new URL('https://storybook.js.org'), // necessary to make the rendered output deterministic in CH snapshots\n        },\n      },\n    },\n  },\n};\n\nexport const Default = {};\n\nexport const Page = {\n  parameters: {\n    sveltekit_experimental: {\n      state: {\n        page: {\n          data: {\n            test: 'passed',\n          },\n          form: {\n            framework: 'SvelteKit',\n            rating: 5,\n          },\n          params: {\n            referrer: 'storybook',\n          },\n          route: {\n            id: '/framework/sveltekit',\n          },\n          status: 200,\n          url: new URL('https://svelte.dev/docs/kit/'),\n        },\n      },\n    },\n  },\n};\n\nexport const Navigating = {\n  parameters: {\n    sveltekit_experimental: {\n      state: {\n        navigating: {\n          from: {\n            params: {\n              framework: 'SvelteKit',\n            },\n            route: {\n              id: '/framework/sveltekit',\n            },\n            url: new URL('https://svelte.dev'),\n          },\n          to: {\n            route: { id: '/storybook' },\n            params: {},\n            url: new URL('https://storybook.js.org'),\n          },\n          type: 'link',\n          willUnload: true,\n          delta: 3,\n          complete: Promise.resolve(),\n        },\n      },\n    },\n  },\n};\n\nexport const Updated = {\n  parameters: {\n    sveltekit_experimental: {\n      state: {\n        updated: {\n          current: true,\n        },\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "code/frameworks/sveltekit/template/stories_svelte-kit-skeleton-ts/modules/stores.stories.js",
    "content": "import Stores from './Stores.svelte';\n\nexport default {\n  title: 'stories/frameworks/sveltekit/modules/stores',\n  component: Stores,\n};\n\nexport const AllUndefined = {};\n\nexport const PageStore = {\n  parameters: {\n    sveltekit_experimental: {\n      stores: {\n        page: {\n          data: {\n            test: 'passed',\n          },\n        },\n      },\n    },\n  },\n};\n\nexport const NavigatingStore = {\n  parameters: {\n    sveltekit_experimental: {\n      stores: {\n        navigating: {\n          route: {\n            id: '/storybook',\n          },\n        },\n      },\n    },\n  },\n};\n\nexport const UpdatedStore = {\n  parameters: {\n    sveltekit_experimental: {\n      stores: {\n        updated: true,\n      },\n    },\n  },\n};\n\nexport const PageAndNavigatingStore = {\n  parameters: {\n    sveltekit_experimental: {\n      stores: {\n        page: {\n          data: {\n            test: 'passed',\n          },\n        },\n        navigating: {\n          route: {\n            id: '/storybook',\n          },\n        },\n      },\n    },\n  },\n};\n\nexport const PageAndUpdatedStore = {\n  parameters: {\n    sveltekit_experimental: {\n      stores: {\n        page: {\n          data: {\n            test: 'passed',\n          },\n        },\n        updated: true,\n      },\n    },\n  },\n};\n\nexport const NavigatingAndUpdatedStore = {\n  parameters: {\n    sveltekit_experimental: {\n      stores: {\n        navigating: {\n          route: {\n            id: '/storybook',\n          },\n        },\n        updated: true,\n      },\n    },\n  },\n};\n\nexport const AllThreeStores = {\n  parameters: {\n    sveltekit_experimental: {\n      stores: {\n        page: {\n          data: {\n            test: 'passed',\n          },\n        },\n        navigating: {\n          route: {\n            id: '/storybook',\n          },\n        },\n        updated: true,\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "code/frameworks/sveltekit/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"storybook/internal/*\": [\"../../lib/cli/core/*\"]\n    }\n  },\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/frameworks/sveltekit/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/frameworks/vue3-vite/README.md",
    "content": "# Storybook for Vue and Vite\n\nSee [documentation](https://storybook.js.org/docs/get-started/frameworks/vue3-vite?renderer=vue&ref=readme) for installation instructions, usage examples, APIs, and more.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/frameworks/vue3-vite/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./node'],\n        entryPoint: './src/node/index.ts',\n      },\n      {\n        exportEntries: ['./vite-plugin'],\n        entryPoint: './src/vite-plugin.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/frameworks/vue3-vite/package.json",
    "content": "{\n  \"name\": \"@storybook/vue3-vite\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook for Vue3 and Vite: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-framework\",\n    \"vue3\",\n    \"vite\",\n    \"component\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/frameworks/vue3-vite\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/frameworks/vue3-vite\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./node\": {\n      \"types\": \"./dist/node/index.d.ts\",\n      \"code\": \"./src/node/index.ts\",\n      \"default\": \"./dist/node/index.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\",\n    \"./vite-plugin\": \"./dist/vite-plugin.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"template/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/builder-vite\": \"workspace:*\",\n    \"@storybook/vue3\": \"workspace:*\",\n    \"magic-string\": \"^0.30.0\",\n    \"typescript\": \"^5.9.3\",\n    \"vue-component-meta\": \"^2.0.0\",\n    \"vue-docgen-api\": \"^4.75.1\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.19.1\",\n    \"typescript\": \"^5.9.3\",\n    \"vite\": \"^7.0.4\"\n  },\n  \"peerDependencies\": {\n    \"storybook\": \"workspace:^\",\n    \"vite\": \"^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/frameworks/vue3-vite/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/frameworks/vue3-vite/project.json",
    "content": "{\n  \"name\": \"vue3-vite\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/frameworks/vue3-vite/src/index.ts",
    "content": "export * from '@storybook/vue3';\nexport * from './types.ts';\n\nexport { __definePreview as definePreview } from '@storybook/vue3';\n"
  },
  {
    "path": "code/frameworks/vue3-vite/src/node/index.ts",
    "content": "import type { StorybookConfig } from '../types.ts';\n\nexport function defineMain(config: StorybookConfig) {\n  return config;\n}\n\nexport type { StorybookConfig };\n"
  },
  {
    "path": "code/frameworks/vue3-vite/src/plugins/vue-component-meta.ts",
    "content": "import { readFile, stat } from 'node:fs/promises';\nimport { join, parse } from 'node:path';\n\nimport { getProjectRoot } from 'storybook/internal/common';\n\nimport MagicString from 'magic-string';\nimport type { ModuleNode, Plugin } from 'vite';\nimport {\n  type ComponentMeta,\n  type MetaCheckerOptions,\n  type PropertyMetaSchema,\n  TypeMeta,\n  createChecker,\n  createCheckerByJson,\n} from 'vue-component-meta';\nimport { parseMulti } from 'vue-docgen-api';\n\ntype MetaSource = {\n  exportName: string;\n  displayName: string;\n  sourceFiles: string;\n} & ComponentMeta &\n  MetaCheckerOptions['schema'];\n\nexport async function vueComponentMeta(tsconfigPath = 'tsconfig.json'): Promise<Plugin> {\n  const { createFilter } = await import('vite');\n\n  // exclude stories, virtual modules and storybook internals\n  const exclude = /\\.stories\\.(ts|tsx|js|jsx)$|^\\0\\/virtual:|^\\/virtual:|\\.storybook\\/.*\\.(ts|js)$/;\n  const include = /\\.(vue|ts|js|tsx|jsx)$/;\n  const filter = createFilter(include, exclude);\n\n  const checker = await createVueComponentMetaChecker(tsconfigPath);\n\n  return {\n    name: 'storybook:vue-component-meta-plugin',\n    transform: {\n      filter: { id: { include, exclude } },\n      async handler(src, id) {\n        if (!filter(id)) {\n          return undefined;\n        }\n\n        try {\n          const exportNames = checker.getExportNames(id);\n          let componentsMeta = exportNames.map((name) => checker.getComponentMeta(id, name));\n          componentsMeta = await applyTempFixForEventDescriptions(id, componentsMeta);\n\n          const metaSources: MetaSource[] = [];\n\n          componentsMeta.forEach((meta, index) => {\n            // filter out empty meta\n            const isEmpty =\n              !meta.props.length &&\n              !meta.events.length &&\n              !meta.slots.length &&\n              !meta.exposed.length;\n\n            if (isEmpty || meta.type === TypeMeta.Unknown) {\n              return;\n            }\n\n            const exportName = exportNames[index];\n\n            // we remove nested object schemas here since they are not used inside Storybook (we don't generate controls for object properties)\n            // and they can cause \"out of memory\" issues for large/complex schemas (e.g. HTMLElement)\n            // it also reduced the bundle size when running \"storybook build\" when such schemas are used\n            (['props', 'events', 'slots', 'exposed'] as const).forEach((key) => {\n              meta[key].forEach((value) => {\n                if (Array.isArray(value.schema)) {\n                  value.schema.forEach((eventSchema) => removeNestedSchemas(eventSchema));\n                } else {\n                  removeNestedSchemas(value.schema);\n                }\n              });\n            });\n\n            const exposed =\n              // the meta also includes duplicated entries in the \"exposed\" array with \"on\"\n              // prefix (e.g. onClick instead of click), so we need to filter them out here\n              meta.exposed\n                .filter((expose) => {\n                  let nameWithoutOnPrefix = expose.name;\n\n                  if (nameWithoutOnPrefix.startsWith('on')) {\n                    nameWithoutOnPrefix = lowercaseFirstLetter(expose.name.replace('on', ''));\n                  }\n\n                  const hasEvent = meta.events.find((event) => event.name === nameWithoutOnPrefix);\n                  return !hasEvent;\n                })\n                // remove unwanted duplicated \"$slots\" expose\n                .filter((expose) => {\n                  if (expose.name === '$slots') {\n                    const slotNames = meta.slots.map((slot) => slot.name);\n                    return !slotNames.every((slotName) => expose.type.includes(slotName));\n                  }\n                  return true;\n                });\n\n            metaSources.push({\n              exportName,\n              displayName: exportName === 'default' ? getFilenameWithoutExtension(id) : exportName,\n              ...meta,\n              exposed,\n              sourceFiles: id,\n            });\n          });\n\n          // if there is no component meta, return undefined\n          if (metaSources.length === 0) {\n            return undefined;\n          }\n\n          const s = new MagicString(src);\n\n          metaSources.forEach((meta) => {\n            const isDefaultExport = meta.exportName === 'default';\n            const name = isDefaultExport ? '_sfc_main' : meta.exportName;\n\n            // we can only add the \"__docgenInfo\" to variables that are actually defined in the current file\n            // so e.g. re-exports like \"export { default as MyComponent } from './MyComponent.vue'\" must be ignored\n            // to prevent runtime errors\n            if (\n              new RegExp(`export {.*${name}.*}`).test(src) ||\n              new RegExp(`export \\\\* from ['\"]\\\\S*${name}['\"]`).test(src) ||\n              // when using re-exports, some exports might be resolved via checker.getExportNames\n              // but are not directly exported inside the current file so we need to ignore them too\n              !src.includes(name)\n            ) {\n              return;\n            }\n\n            if (!id.endsWith('.vue') && isDefaultExport) {\n              // we can not add the __docgenInfo if the component is default exported directly\n              // so we need to safe it to a variable instead and export default it instead\n              s.replace('export default ', 'const _sfc_main = ');\n              s.append('\\nexport default _sfc_main;');\n            }\n\n            s.append(`\\n;${name}.__docgenInfo = Object.assign({\n            displayName: ${name}.name ?? ${name}.__name\n          }, ${JSON.stringify(meta)})`);\n          });\n\n          return {\n            code: s.toString(),\n            map: s.generateMap({ hires: true, source: id }),\n          };\n        } catch (e) {\n          return undefined;\n        }\n      },\n    },\n    // handle hot updates to update the component meta on file changes\n    async handleHotUpdate({ file, read, server, modules, timestamp }) {\n      const content = await read();\n      checker.updateFile(file, content);\n      // Invalidate modules manually\n      const invalidatedModules = new Set<ModuleNode>();\n\n      for (const mod of modules) {\n        server.moduleGraph.invalidateModule(mod, invalidatedModules, timestamp, true);\n      }\n\n      server.ws.send({ type: 'full-reload' });\n      return [];\n    },\n  };\n}\n\n/**\n * Creates the `vue-component-meta` checker to use for extracting component meta/docs. Considers the\n * given tsconfig file (will use a fallback checker if it does not exist or is not supported).\n */\nasync function createVueComponentMetaChecker(tsconfigPath = 'tsconfig.json') {\n  const checkerOptions: MetaCheckerOptions = {\n    forceUseTs: true,\n    noDeclarations: true,\n    printer: { newLine: 1 },\n  };\n\n  const projectRoot = getProjectRoot();\n\n  const projectTsConfigPath = join(projectRoot, tsconfigPath);\n\n  const defaultChecker = createCheckerByJson(projectRoot, { include: ['**/*'] }, checkerOptions);\n\n  // prefer the tsconfig.json file of the project to support alias resolution etc.\n  if (await fileExists(projectTsConfigPath)) {\n    // vue-component-meta does currently not resolve tsconfig references (see https://github.com/vuejs/language-tools/issues/3896)\n    // so we will return the defaultChecker if references are used.\n    // Otherwise vue-component-meta might not work at all for the Storybook docgen.\n    const references = await getTsConfigReferences(projectTsConfigPath);\n\n    if (references.length > 0) {\n      return defaultChecker;\n    }\n    return createChecker(projectTsConfigPath, checkerOptions);\n  }\n\n  return defaultChecker;\n}\n\n/** Gets the filename without file extension. */\nfunction getFilenameWithoutExtension(filename: string) {\n  return parse(filename).name;\n}\n\n/** Lowercases the first letter. */\nfunction lowercaseFirstLetter(string: string) {\n  return string.charAt(0).toLowerCase() + string.slice(1);\n}\n\n/** Checks whether the given file path exists. */\nasync function fileExists(fullPath: string) {\n  try {\n    await stat(fullPath);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Applies a temporary workaround/fix for missing event descriptions because Volar is currently not\n * able to extract them. Will modify the events of the passed meta. Performance note: Based on some\n * quick tests, calling \"parseMulti\" only takes a few milliseconds (8-20ms) so it should not\n * decrease performance that much. Especially because it is only execute if the component actually\n * has events.\n *\n * Check status of this Volar issue: https://github.com/vuejs/language-tools/issues/3893 and\n * update/remove this workaround once Volar supports it:\n *\n * - Delete this function\n * - Uninstall vue-docgen-api dependency\n */\nasync function applyTempFixForEventDescriptions(filename: string, componentMeta: ComponentMeta[]) {\n  // do not apply temp fix if no events exist for performance reasons\n  const hasEvents = componentMeta.some((meta) => meta.events.length);\n\n  if (!hasEvents) {\n    return componentMeta;\n  }\n\n  try {\n    const parsedComponentDocs = await parseMulti(filename);\n\n    // add event descriptions to the existing Volar meta if available\n    componentMeta.map((meta, index) => {\n      const eventsWithDescription = parsedComponentDocs[index].events;\n\n      if (!meta.events.length || !eventsWithDescription?.length) {\n        return meta;\n      }\n\n      meta.events = meta.events.map((event) => {\n        const description = eventsWithDescription.find((i) => i.name === event.name)?.description;\n        if (description) {\n          (event as typeof event & { description: string }).description = description;\n        }\n        return event;\n      });\n\n      return meta;\n    });\n  } catch {\n    // noop\n  }\n\n  return componentMeta;\n}\n\n/**\n * Gets a list of tsconfig references for the given tsconfig This is only needed for the temporary\n * workaround/fix for: https://github.com/vuejs/language-tools/issues/3896\n */\nasync function getTsConfigReferences(tsConfigPath: string) {\n  try {\n    const content = JSON.parse(await readFile(tsConfigPath, 'utf-8'));\n\n    if (!('references' in content) || !Array.isArray(content.references)) {\n      return [];\n    }\n    return content.references as unknown[];\n  } catch {\n    // invalid project tsconfig\n    return [];\n  }\n}\n\n/**\n * Removes any nested schemas from the given main schema (e.g. from a prop, event, slot or exposed).\n * Useful to drastically reduce build size and prevent out of memory issues when large schemas (e.g.\n * HTMLElement, MouseEvent) are used.\n */\nfunction removeNestedSchemas(schema: PropertyMetaSchema) {\n  if (typeof schema !== 'object') {\n    return;\n  }\n  if (schema.kind === 'enum') {\n    // for enum types, we do not want to remove the schemas because otherwise the controls will be missing\n    // instead we remove the nested schemas for the enum entries to prevent out of memory errors for types like \"HTMLElement | MouseEvent\"\n    schema.schema?.forEach((enumSchema) => removeNestedSchemas(enumSchema));\n    return;\n  }\n  delete schema.schema;\n}\n"
  },
  {
    "path": "code/frameworks/vue3-vite/src/plugins/vue-docgen.ts",
    "content": "import MagicString from 'magic-string';\nimport type { Plugin } from 'vite';\nimport { parse } from 'vue-docgen-api';\n\nexport async function vueDocgen(): Promise<Plugin> {\n  const { createFilter } = await import('vite');\n\n  const include = /\\.(vue)$/;\n  const filter = createFilter(include);\n\n  return {\n    name: 'storybook:vue-docgen-plugin',\n    transform: {\n      filter: { id: include },\n      async handler(src, id) {\n        if (!filter(id)) {\n          return undefined;\n        }\n\n        const metaData = await parse(id);\n\n        const s = new MagicString(src);\n\n        s.append(`;_sfc_main.__docgenInfo = Object.assign({\n        displayName: _sfc_main.name ?? _sfc_main.__name\n      }, ${JSON.stringify(metaData)});`);\n\n        return {\n          code: s.toString(),\n          map: s.generateMap({ hires: true, source: id }),\n        };\n      },\n    },\n  };\n}\n"
  },
  {
    "path": "code/frameworks/vue3-vite/src/plugins/vue-template.ts",
    "content": "import type { Plugin } from 'vite';\n\nexport async function templateCompilation(): Promise<Plugin> {\n  return {\n    name: 'storybook:vue-template-compilation',\n    config: () => ({\n      resolve: {\n        alias: {\n          vue: 'vue/dist/vue.esm-bundler.js',\n        },\n      },\n    }),\n  } satisfies Plugin;\n}\n"
  },
  {
    "path": "code/frameworks/vue3-vite/src/preset.ts",
    "content": "import type { PresetProperty } from 'storybook/internal/types';\n\nimport type { Plugin } from 'vite';\n\nimport { vueComponentMeta } from './plugins/vue-component-meta.ts';\nimport { vueDocgen } from './plugins/vue-docgen.ts';\nimport { templateCompilation } from './plugins/vue-template.ts';\nimport type { FrameworkOptions, StorybookConfig, VueDocgenPlugin } from './types.ts';\n\nexport const core: PresetProperty<'core'> = {\n  builder: import.meta.resolve('@storybook/builder-vite'),\n  renderer: import.meta.resolve('@storybook/vue3/preset'),\n};\n\nexport const viteFinal: StorybookConfig['viteFinal'] = async (config, options) => {\n  const plugins: Plugin[] = [await templateCompilation()];\n\n  const framework = await options.presets.apply('framework');\n  const frameworkOptions: FrameworkOptions =\n    typeof framework === 'string' ? {} : (framework.options ?? {});\n\n  const docgen = resolveDocgenOptions(frameworkOptions.docgen);\n\n  // add docgen plugin depending on framework option\n  if (docgen !== false) {\n    if (docgen.plugin === 'vue-component-meta') {\n      plugins.push(await vueComponentMeta(docgen.tsconfig));\n    } else {\n      plugins.push(await vueDocgen());\n    }\n  }\n\n  const { mergeConfig } = await import('vite');\n  return mergeConfig(config, {\n    plugins,\n  });\n};\n\n/** Resolves the docgen framework option. */\nconst resolveDocgenOptions = (\n  docgen?: FrameworkOptions['docgen']\n): false | { plugin: VueDocgenPlugin; tsconfig?: string } => {\n  if (docgen === false) {\n    return false;\n  }\n\n  if (docgen === undefined || docgen === true) {\n    return { plugin: 'vue-docgen-api' };\n  }\n\n  if (typeof docgen === 'string') {\n    return { plugin: docgen };\n  }\n\n  return docgen;\n};\n"
  },
  {
    "path": "code/frameworks/vue3-vite/src/types.ts",
    "content": "import type {\n  CompatibleString,\n  StorybookConfig as StorybookConfigBase,\n} from 'storybook/internal/types';\n\nimport type { BuilderOptions, StorybookConfigVite } from '@storybook/builder-vite';\n\nimport type { ComponentMeta } from 'vue-component-meta';\nimport type { ComponentDoc } from 'vue-docgen-api';\n\ntype FrameworkName = CompatibleString<'@storybook/vue3-vite'>;\ntype BuilderName = CompatibleString<'@storybook/builder-vite'>;\n\n/** Available docgen plugins for vue. */\nexport type VueDocgenPlugin = 'vue-docgen-api' | 'vue-component-meta';\n\nexport type FrameworkOptions = {\n  builder?: BuilderOptions;\n  /**\n   * Plugin to use for generation docs for component props, events, slots and exposes. Since\n   * Storybook 8, the official vue plugin \"vue-component-meta\" (Volar) can be used which supports\n   * more complex types, better type docs, support for js(x)/ts(x) components and more.\n   *\n   * \"vue-component-meta\" will become the new default in the future and \"vue-docgen-api\" will be\n   * removed.\n   *\n   * Set to `false` to disable docgen processing entirely for improved build performance.\n   *\n   * @default 'vue-docgen-api'\n   */\n  docgen?:\n    | boolean\n    | VueDocgenPlugin\n    | {\n        plugin: 'vue-component-meta';\n        /**\n         * Tsconfig path to use. Should be set if your main `tsconfig.json` includes references to\n         * other tsconfig files like `tsconfig.app.json`. Otherwise docgen might not be generated\n         * correctly (e.g. import aliases are not resolved). The path is resolved relative to\n         * project root.\n         *\n         * For further information, see our\n         * [docs](https://storybook.js.org/docs/get-started/vue3-vite#override-the-default-configuration).\n         *\n         * @default 'tsconfig.json'\n         */\n        tsconfig: `${string}/tsconfig${string}.json` | `tsconfig${string}.json`;\n      };\n};\n\ntype StorybookConfigFramework = {\n  framework:\n    | FrameworkName\n    | {\n        name: FrameworkName;\n        options: FrameworkOptions;\n      };\n  core?: StorybookConfigBase['core'] & {\n    builder?:\n      | BuilderName\n      | {\n          name: BuilderName;\n          options: BuilderOptions;\n        };\n  };\n};\n\n/** The interface for Storybook configuration in `main.ts` files. */\nexport type StorybookConfig = Omit<\n  StorybookConfigBase,\n  keyof StorybookConfigVite | keyof StorybookConfigFramework\n> &\n  StorybookConfigVite &\n  StorybookConfigFramework;\n\n/** Gets the type of a single array element. */\ntype ArrayElement<T> = T extends readonly (infer A)[] ? A : never;\n\n/** Type of \"__docgenInfo\" depending on the used docgenPlugin. */\nexport type VueDocgenInfo<T extends VueDocgenPlugin> = T extends 'vue-component-meta'\n  ? ComponentMeta\n  : ComponentDoc;\n\n/**\n * Single prop/event/slot/exposed entry of \"__docgenInfo\" depending on the used docgenPlugin.\n *\n * @example\n *\n * ```ts\n * type PropInfo = VueDocgenInfoEntry<'vue-component-meta', 'props'>;\n * ```\n */\nexport type VueDocgenInfoEntry<\n  T extends VueDocgenPlugin,\n  TKey extends 'props' | 'events' | 'slots' | 'exposed' | 'expose' =\n    | 'props'\n    | 'events'\n    | 'slots'\n    | 'exposed'\n    | 'expose',\n> = ArrayElement<\n  T extends 'vue-component-meta'\n    ? VueDocgenInfo<'vue-component-meta'>[Exclude<TKey, 'expose'>]\n    : VueDocgenInfo<'vue-docgen-api'>[Exclude<TKey, 'exposed'>]\n>;\n"
  },
  {
    "path": "code/frameworks/vue3-vite/src/vite-plugin.ts",
    "content": "import type { Plugin } from 'vite';\n\nimport { templateCompilation } from './plugins/vue-template.ts';\n\nexport const storybookVuePlugin = (): Promise<Plugin>[] => {\n  return [templateCompilation()];\n};\n"
  },
  {
    "path": "code/frameworks/vue3-vite/template/cli/js/Button.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport MyButton from './Button.vue';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories\nexport default {\n  title: 'Example/Button',\n  component: MyButton,\n  tags: ['autodocs'],\n  argTypes: {\n    size: { control: { type: 'select' }, options: ['small', 'medium', 'large'] },\n    backgroundColor: { control: 'color' },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onClick: fn() },\n};\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/vue3-vite/template/cli/js/Button.vue",
    "content": "<template>\n  <button type=\"button\" :class=\"classes\" @click=\"onClick\" :style=\"style\">{{ label }}</button>\n</template>\n\n<script>\nimport { computed, reactive } from 'vue';\n\nimport './button.css';\n\nexport default {\n  name: 'my-button',\n\n  props: {\n    label: {\n      type: String,\n      required: true,\n    },\n    primary: {\n      type: Boolean,\n      default: false,\n    },\n    size: {\n      type: String,\n      validator: function (value) {\n        return ['small', 'medium', 'large'].indexOf(value) !== -1;\n      },\n    },\n    backgroundColor: {\n      type: String,\n    },\n  },\n\n  emits: ['click'],\n\n  setup(props, { emit }) {\n    props = reactive(props);\n    return {\n      classes: computed(() => ({\n        'storybook-button': true,\n        'storybook-button--primary': props.primary,\n        'storybook-button--secondary': !props.primary,\n        [`storybook-button--${props.size || 'medium'}`]: true,\n      })),\n      style: computed(() => ({\n        backgroundColor: props.backgroundColor,\n      })),\n      onClick() {\n        emit('click');\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "code/frameworks/vue3-vite/template/cli/js/Header.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport MyHeader from './Header.vue';\n\nexport default {\n  title: 'Example/Header',\n  component: MyHeader,\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  render: (args) => ({\n    // Components used in your story `template` are defined in the `components` object\n    components: {\n      MyHeader,\n    },\n    // The story's `args` need to be mapped into the template through the `setup()` method\n    setup() {\n      // Story args can be spread into the returned object\n      return {\n        ...args,\n      };\n    },\n    // Then, the spread values can be accessed directly in the template\n    template: '<my-header :user=\"user\" />',\n  }),\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n};\n\nexport const LoggedIn = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut = {\n  args: {\n    user: null,\n  },\n};\n"
  },
  {
    "path": "code/frameworks/vue3-vite/template/cli/js/Header.vue",
    "content": "<template>\n  <header>\n    <div class=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fill-rule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        <span class=\"welcome\" v-if=\"user\"\n          >Welcome, <b>{{ user.name }}</b\n          >!</span\n        >\n        <my-button size=\"small\" @click=\"$emit('logout')\" label=\"Log out\" v-if=\"user\" />\n        <my-button size=\"small\" @click=\"$emit('login')\" label=\"Log in\" v-if=\"!user\" />\n        <my-button\n          primary\n          size=\"small\"\n          @click=\"$emit('createAccount')\"\n          label=\"Sign up\"\n          v-if=\"!user\"\n        />\n      </div>\n    </div>\n  </header>\n</template>\n\n<script>\nimport MyButton from './Button.vue';\nimport './header.css';\n\nexport default {\n  name: 'my-header',\n\n  components: { MyButton },\n\n  props: {\n    user: {\n      type: Object,\n    },\n  },\n\n  emits: ['login', 'logout', 'createAccount'],\n};\n</script>\n"
  },
  {
    "path": "code/frameworks/vue3-vite/template/cli/js/Page.stories.js",
    "content": "import { expect, userEvent, within } from 'storybook/test';\n\nimport MyPage from './Page.vue';\n\nexport default {\n  title: 'Example/Page',\n  component: MyPage,\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n};\n\nexport const LoggedOut = {};\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn = {\n  render: () => ({\n    components: {\n      MyPage,\n    },\n    template: '<my-page />',\n  }),\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await expect(loginButton).not.toBeInTheDocument();\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n"
  },
  {
    "path": "code/frameworks/vue3-vite/template/cli/js/Page.vue",
    "content": "<template>\n  <article>\n    <my-header :user=\"user\" @login=\"onLogin\" @logout=\"onLogout\" @createAccount=\"onCreateAccount\" />\n\n    <section class=\"storybook-page\">\n      <h2>Pages in Storybook</h2>\n      <p>\n        We recommend building UIs with a\n        <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n          <strong>component-driven</strong>\n        </a>\n        process starting with atomic components and ending with pages.\n      </p>\n      <p>\n        Render pages with mock data. This makes it easy to build and review page states without\n        needing to navigate to them in your app. Here are some handy patterns for managing page data\n        in Storybook:\n      </p>\n      <ul>\n        <li>\n          Use a higher-level connected component. Storybook helps you compose such data from the\n          \"args\" of child component stories\n        </li>\n        <li>\n          Assemble data in the page component from your services. You can mock these services out\n          using Storybook.\n        </li>\n      </ul>\n      <p>\n        Get a guided tutorial on component-driven development at\n        <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\"\n          >Storybook tutorials</a\n        >\n        . Read more in the\n        <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">docs</a>\n        .\n      </p>\n      <div class=\"tip-wrapper\">\n        <span class=\"tip\">Tip</span>\n        Adjust the width of the canvas with the\n        <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fill-rule=\"evenodd\">\n            <path\n              d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n              id=\"a\"\n              fill=\"#999\"\n            />\n          </g>\n        </svg>\n        Viewports addon in the toolbar\n      </div>\n    </section>\n  </article>\n</template>\n\n<script>\nimport MyHeader from './Header.vue';\nimport './page.css';\n\nexport default {\n  name: 'my-page',\n\n  components: { MyHeader },\n\n  data() {\n    return {\n      user: null,\n    };\n  },\n\n  methods: {\n    onLogin() {\n      this.user = { name: 'Jane Doe' };\n    },\n    onLogout() {\n      this.user = null;\n    },\n    onCreateAccount() {\n      this.user = { name: 'Jane Doe' };\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "code/frameworks/vue3-vite/template/cli/ts/Button.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport { fn } from 'storybook/test';\n\nimport Button from './Button.vue';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories\nconst meta = {\n  title: 'Example/Button',\n  component: Button,\n  // This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  argTypes: {\n    size: { control: 'select', options: ['small', 'medium', 'large'] },\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    primary: false,\n    // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n    onClick: fn(),\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    primary: false,\n    label: 'Button',\n  },\n};\n\nexport const Large: Story = {\n  args: {\n    label: 'Button',\n    size: 'large',\n  },\n};\n\nexport const Small: Story = {\n  args: {\n    label: 'Button',\n    size: 'small',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/vue3-vite/template/cli/ts/Button.vue",
    "content": "<template>\n  <button type=\"button\" :class=\"classes\" @click=\"onClick\" :style=\"style\">{{ label }}</button>\n</template>\n\n<script lang=\"ts\" setup>\nimport { computed } from 'vue';\n\nimport './button.css';\n\nconst props = withDefaults(\n  defineProps<{\n    /**\n     * The label of the button\n     */\n    label: string;\n    /**\n     * primary or secondary button\n     */\n    primary?: boolean;\n    /**\n     * size of the button\n     */\n    size?: 'small' | 'medium' | 'large';\n    /**\n     * background color of the button\n     */\n    backgroundColor?: string;\n  }>(),\n  { primary: false }\n);\n\nconst emit = defineEmits<{\n  (e: 'click', id: number): void;\n}>();\n\nconst classes = computed(() => ({\n  'storybook-button': true,\n  'storybook-button--primary': props.primary,\n  'storybook-button--secondary': !props.primary,\n  [`storybook-button--${props.size || 'medium'}`]: true,\n}));\n\nconst style = computed(() => ({\n  backgroundColor: props.backgroundColor,\n}));\n\nconst onClick = () => {\n  emit('click', 1);\n};\n</script>\n"
  },
  {
    "path": "code/frameworks/vue3-vite/template/cli/ts/Header.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport { fn } from 'storybook/test';\n\nimport MyHeader from './Header.vue';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Example/Header',\n  component: MyHeader,\n  render: (args: any) => ({\n    components: { MyHeader },\n    setup() {\n      return { args };\n    },\n    template: '<my-header :user=\"args.user\" />',\n  }),\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n  // This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n} satisfies Meta<typeof MyHeader>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const LoggedIn: Story = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut: Story = {\n  args: {\n    user: null,\n  },\n};\n"
  },
  {
    "path": "code/frameworks/vue3-vite/template/cli/ts/Header.vue",
    "content": "<template>\n  <header>\n    <div class=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fill-rule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        <span class=\"welcome\" v-if=\"user\"\n          >Welcome, <b>{{ user.name }}</b\n          >!</span\n        >\n        <my-button size=\"small\" @click=\"$emit('logout')\" label=\"Log out\" v-if=\"user\" />\n        <my-button size=\"small\" @click=\"$emit('login')\" label=\"Log in\" v-if=\"!user\" />\n        <my-button\n          primary\n          size=\"small\"\n          @click=\"$emit('createAccount')\"\n          label=\"Sign up\"\n          v-if=\"!user\"\n        />\n      </div>\n    </div>\n  </header>\n</template>\n\n<script lang=\"ts\" setup>\nimport MyButton from './Button.vue';\nimport './header.css';\n\ndefineProps<{ user: { name: string } | null }>();\n\ndefineEmits<{\n  (event: 'createAccount'): void;\n  (event: 'login'): void;\n  (event: 'logout'): void;\n}>();\n</script>\n"
  },
  {
    "path": "code/frameworks/vue3-vite/template/cli/ts/Page.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport { expect, userEvent, within } from 'storybook/test';\n\nimport MyPage from './Page.vue';\n\nconst meta = {\n  title: 'Example/Page',\n  component: MyPage,\n  render: () => ({\n    components: { MyPage },\n    template: '<my-page />',\n  }),\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  // This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n} satisfies Meta<typeof MyPage>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn: Story = {\n  play: async ({ canvasElement }: any) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await expect(loginButton).not.toBeInTheDocument();\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n\nexport const LoggedOut: Story = {};\n"
  },
  {
    "path": "code/frameworks/vue3-vite/template/cli/ts/Page.vue",
    "content": "<template>\n  <article>\n    <my-header :user=\"user\" @login=\"onLogin\" @logout=\"onLogout\" @create-account=\"onCreateAccount\" />\n\n    <section class=\"storybook-page\">\n      <h2>Pages in Storybook</h2>\n      <p>\n        We recommend building UIs with a\n        <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n          <strong>component-driven</strong>\n        </a>\n        process starting with atomic components and ending with pages.\n      </p>\n      <p>\n        Render pages with mock data. This makes it easy to build and review page states without\n        needing to navigate to them in your app. Here are some handy patterns for managing page data\n        in Storybook:\n      </p>\n      <ul>\n        <li>\n          Use a higher-level connected component. Storybook helps you compose such data from the\n          \"args\" of child component stories\n        </li>\n        <li>\n          Assemble data in the page component from your services. You can mock these services out\n          using Storybook.\n        </li>\n      </ul>\n      <p>\n        Get a guided tutorial on component-driven development at\n        <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\"\n          >Storybook tutorials</a\n        >\n        . Read more in the\n        <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">docs</a>\n        .\n      </p>\n      <div class=\"tip-wrapper\">\n        <span class=\"tip\">Tip</span>\n        Adjust the width of the canvas with the\n        <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fill-rule=\"evenodd\">\n            <path\n              d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n              id=\"a\"\n              fill=\"#999\"\n            />\n          </g>\n        </svg>\n        Viewports addon in the toolbar\n      </div>\n    </section>\n  </article>\n</template>\n\n<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport MyHeader from './Header.vue';\nimport './page.css';\n\nconst user = ref<{ name: string } | null>(null);\n\nconst onLogin = () => {\n  user.value = { name: 'Jane Doe' };\n};\nconst onLogout = () => {\n  user.value = null;\n};\nconst onCreateAccount = () => {\n  user.value = { name: 'Jane Doe' };\n};\n</script>\n"
  },
  {
    "path": "code/frameworks/vue3-vite/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"storybook/internal/*\": [\"../../lib/cli/core/*\"]\n    },\n    \"rootDir\": \"./src\"\n  },\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/frameworks/vue3-vite/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/frameworks/web-components-vite/README.md",
    "content": "# Storybook for Web components & Vite\n\nSee [documentation](https://storybook.js.org/docs/get-started/frameworks/web-components-vite?renderer=web-components&ref=readme) for installation instructions, usage examples, APIs, and more.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/frameworks/web-components-vite/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./node'],\n        entryPoint: './src/node/index.ts',\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/frameworks/web-components-vite/package.json",
    "content": "{\n  \"name\": \"@storybook/web-components-vite\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook for Web Components and Vite: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-framework\",\n    \"lit\",\n    \"lit-html\",\n    \"web-components\",\n    \"vite\",\n    \"component\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/frameworks/web-components-vite\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/frameworks/web-components-vite\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./node\": {\n      \"types\": \"./dist/node/index.d.ts\",\n      \"code\": \"./src/node/index.ts\",\n      \"default\": \"./dist/node/index.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"template/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/builder-vite\": \"workspace:*\",\n    \"@storybook/web-components\": \"workspace:*\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.19.1\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"storybook\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/frameworks/web-components-vite/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/frameworks/web-components-vite/project.json",
    "content": "{\n  \"name\": \"web-components-vite\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/frameworks/web-components-vite/src/index.ts",
    "content": "export * from '@storybook/web-components';\nexport * from './types.ts';\n\nexport { __definePreview as definePreview } from '@storybook/web-components';\n"
  },
  {
    "path": "code/frameworks/web-components-vite/src/node/index.ts",
    "content": "import type { StorybookConfig } from '../types.ts';\n\nexport function defineMain(config: StorybookConfig) {\n  return config;\n}\n\nexport type { StorybookConfig };\n"
  },
  {
    "path": "code/frameworks/web-components-vite/src/preset.ts",
    "content": "import type { PresetProperty } from 'storybook/internal/types';\n\nexport const core: PresetProperty<'core'> = {\n  builder: import.meta.resolve('@storybook/builder-vite'),\n  renderer: import.meta.resolve('@storybook/web-components/preset'),\n};\n"
  },
  {
    "path": "code/frameworks/web-components-vite/src/types.ts",
    "content": "import type {\n  CompatibleString,\n  StorybookConfig as StorybookConfigBase,\n} from 'storybook/internal/types';\n\nimport type { BuilderOptions, StorybookConfigVite } from '@storybook/builder-vite';\n\ntype FrameworkName = CompatibleString<'@storybook/web-components-vite'>;\ntype BuilderName = CompatibleString<'@storybook/builder-vite'>;\n\nexport type FrameworkOptions = {\n  builder?: BuilderOptions;\n};\n\ntype StorybookConfigFramework = {\n  framework:\n    | FrameworkName\n    | {\n        name: FrameworkName;\n        options: FrameworkOptions;\n      };\n  core?: StorybookConfigBase['core'] & {\n    builder?:\n      | BuilderName\n      | {\n          name: BuilderName;\n          options: BuilderOptions;\n        };\n  };\n};\n\n/** The interface for Storybook configuration in `main.ts` files. */\nexport type StorybookConfig = Omit<\n  StorybookConfigBase,\n  keyof StorybookConfigVite | keyof StorybookConfigFramework\n> &\n  StorybookConfigVite &\n  StorybookConfigFramework;\n"
  },
  {
    "path": "code/frameworks/web-components-vite/template/cli/.eslintrc.json",
    "content": "{\n  \"rules\": {\n    \"import/extensions\": \"off\"\n  }\n}\n"
  },
  {
    "path": "code/frameworks/web-components-vite/template/cli/js/Button.js",
    "content": "import { html } from 'lit';\nimport { styleMap } from 'lit/directives/style-map.js';\n\nimport './button.css';\n\n/** Primary UI component for user interaction */\nexport const Button = ({ primary, backgroundColor = null, size, label, onClick }) => {\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n\n  return html`\n    <button\n      type=\"button\"\n      class=${['storybook-button', `storybook-button--${size || 'medium'}`, mode].join(' ')}\n      style=${styleMap({ backgroundColor })}\n      @click=${onClick}\n    >\n      ${label}\n    </button>\n  `;\n};\n"
  },
  {
    "path": "code/frameworks/web-components-vite/template/cli/js/Button.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport { Button } from './Button';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories\nexport default {\n  title: 'Example/Button',\n  tags: ['autodocs'],\n  render: (args) => Button(args),\n  argTypes: {\n    backgroundColor: { control: 'color' },\n    size: {\n      control: { type: 'select' },\n      options: ['small', 'medium', 'large'],\n    },\n  },\n  args: { onClick: fn() },\n};\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/web-components-vite/template/cli/js/Header.js",
    "content": "import { html } from 'lit';\n\nimport { Button } from './Button';\nimport './header.css';\n\nexport const Header = ({ user, onLogin, onLogout, onCreateAccount }) => html`\n  <header>\n    <div class=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        ${\n          user\n            ? Button({ size: 'small', onClick: onLogout, label: 'Log out' })\n            : html`${Button({\n                size: 'small',\n                onClick: onLogin,\n                label: 'Log in',\n              })}\n            ${Button({\n              primary: true,\n              size: 'small',\n              onClick: onCreateAccount,\n              label: 'Sign up',\n            })}`\n        }\n      </div>\n    </div>\n  </header>\n`;\n"
  },
  {
    "path": "code/frameworks/web-components-vite/template/cli/js/Header.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport { Header } from './Header';\n\nexport default {\n  title: 'Example/Header',\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/web-components/vue/writing-docs/autodocs\n  tags: ['autodocs'],\n  render: (args) => Header(args),\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n};\nexport const LoggedIn = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut = {};\n"
  },
  {
    "path": "code/frameworks/web-components-vite/template/cli/js/Page.js",
    "content": "import { html } from 'lit';\n\nimport { Header } from './Header';\nimport './page.css';\n\nexport const Page = ({ user, onLogin, onLogout, onCreateAccount }) => html`\n  <article>\n    ${Header({\n      user,\n      onLogin,\n      onLogout,\n      onCreateAccount,\n    })}\n\n    <section class=\"storybook-page\">\n      <h2>Pages in Storybook</h2>\n      <p>\n        We recommend building UIs with a\n        <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n          <strong>component-driven</strong> </a\n        >process starting with atomic components and ending with pages.\n      </p>\n      <p>\n        Render pages with mock data. This makes it easy to build and review page states without\n        needing to navigate to them in your app. Here are some handy patterns for managing page data\n        in Storybook:\n      </p>\n      <ul>\n        <li>\n          Use a higher-level connected component. Storybook helps you compose such data from the\n          \"args\" of child component stories\n        </li>\n        <li>\n          Assemble data in the page component from your services. You can mock these services out\n          using Storybook.\n        </li>\n      </ul>\n      <p>\n        Get a guided tutorial on component-driven development at\n        <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n          Storybook tutorials\n        </a>\n        . Read more in the\n        <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\"> docs </a>\n        .\n      </p>\n      <div class=\"tip-wrapper\">\n        <span class=\"tip\">Tip</span> Adjust the width of the canvas with the\n        <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n              id=\"a\"\n              fill=\"#999\"\n            />\n          </g>\n        </svg>\n        Viewports addon in the toolbar\n      </div>\n    </section>\n  </article>\n`;\n"
  },
  {
    "path": "code/frameworks/web-components-vite/template/cli/js/Page.stories.js",
    "content": "import * as HeaderStories from './Header.stories';\nimport { Page } from './Page';\n\nexport default {\n  title: 'Example/Page',\n  render: (args) => Page(args),\n};\n\nexport const LoggedIn = {\n  args: {\n    // More on composing args: https://storybook.js.org/docs/writing-stories/args#args-composition\n    ...HeaderStories.LoggedIn.args,\n  },\n};\n\nexport const LoggedOut = {\n  args: {\n    ...HeaderStories.LoggedOut.args,\n  },\n};\n"
  },
  {
    "path": "code/frameworks/web-components-vite/template/cli/ts/Button.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { fn } from 'storybook/test';\n\nimport type { ButtonProps } from './Button';\nimport { Button } from './Button';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories\nconst meta = {\n  title: 'Example/Button',\n  tags: ['autodocs'],\n  render: (args) => Button(args),\n  argTypes: {\n    backgroundColor: { control: 'color' },\n    size: {\n      control: { type: 'select' },\n      options: ['small', 'medium', 'large'],\n    },\n  },\n  args: { onClick: fn() },\n} satisfies Meta<ButtonProps>;\n\nexport default meta;\ntype Story = StoryObj<ButtonProps>;\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large: Story = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small: Story = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/frameworks/web-components-vite/template/cli/ts/Button.ts",
    "content": "import { html } from 'lit';\nimport { styleMap } from 'lit/directives/style-map.js';\n\nimport './button.css';\n\nexport interface ButtonProps {\n  /** Is this the principal call to action on the page? */\n  primary?: boolean;\n  /** What background color to use */\n  backgroundColor?: string;\n  /** How large should the button be? */\n  size?: 'small' | 'medium' | 'large';\n  /** Button contents */\n  label: string;\n  /** Optional click handler */\n  onClick?: () => void;\n}\n/** Primary UI component for user interaction */\nexport const Button = ({ primary, backgroundColor, size, label, onClick }: ButtonProps) => {\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n\n  return html`\n    <button\n      type=\"button\"\n      class=${['storybook-button', `storybook-button--${size || 'medium'}`, mode].join(' ')}\n      style=${styleMap({ backgroundColor })}\n      @click=${onClick}\n    >\n      ${label}\n    </button>\n  `;\n};\n"
  },
  {
    "path": "code/frameworks/web-components-vite/template/cli/ts/Header.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { fn } from 'storybook/test';\n\nimport type { HeaderProps } from './Header';\nimport { Header } from './Header';\n\nconst meta = {\n  title: 'Example/Header',\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  render: (args: HeaderProps) => Header(args),\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n} satisfies Meta<HeaderProps>;\n\nexport default meta;\ntype Story = StoryObj<HeaderProps>;\n\nexport const LoggedIn: Story = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut: Story = {};\n"
  },
  {
    "path": "code/frameworks/web-components-vite/template/cli/ts/Header.ts",
    "content": "import { html } from 'lit';\n\nimport { Button } from './Button';\nimport './header.css';\n\ntype User = {\n  name: string;\n};\n\nexport interface HeaderProps {\n  user?: User;\n  onLogin?: () => void;\n  onLogout?: () => void;\n  onCreateAccount?: () => void;\n}\n\nexport const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => html`\n  <header>\n    <div class=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        ${\n          user\n            ? Button({ size: 'small', onClick: onLogout, label: 'Log out' })\n            : html`${Button({\n                size: 'small',\n                onClick: onLogin,\n                label: 'Log in',\n              })}\n            ${Button({\n              primary: true,\n              size: 'small',\n              onClick: onCreateAccount,\n              label: 'Sign up',\n            })}`\n        }\n      </div>\n    </div>\n  </header>\n`;\n"
  },
  {
    "path": "code/frameworks/web-components-vite/template/cli/ts/Page.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport * as HeaderStories from './Header.stories';\nimport type { PageProps } from './Page';\nimport { Page } from './Page';\n\nconst meta = {\n  title: 'Example/Page',\n  render: (args: PageProps) => Page(args),\n} satisfies Meta<PageProps>;\n\nexport default meta;\ntype Story = StoryObj<PageProps>;\n\nexport const LoggedIn: Story = {\n  args: {\n    // More on composing args: https://storybook.js.org/docs/writing-stories/args#args-composition\n    ...HeaderStories.LoggedIn.args,\n  },\n};\n\nexport const LoggedOut: Story = {\n  args: {\n    ...HeaderStories.LoggedOut.args,\n  },\n};\n"
  },
  {
    "path": "code/frameworks/web-components-vite/template/cli/ts/Page.ts",
    "content": "import { html } from 'lit';\n\nimport { Header } from './Header';\nimport './page.css';\n\ntype User = {\n  name: string;\n};\n\nexport interface PageProps {\n  user?: User;\n  onLogin?: () => void;\n  onLogout?: () => void;\n  onCreateAccount?: () => void;\n}\n\nexport const Page = ({ user, onLogin, onLogout, onCreateAccount }: PageProps) => html`\n  <article>\n    ${Header({\n      user,\n      onLogin,\n      onLogout,\n      onCreateAccount,\n    })}\n\n    <section class=\"storybook-page\">\n      <h2>Pages in Storybook</h2>\n      <p>\n        We recommend building UIs with a\n        <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n          <strong>component-driven</strong> </a\n        >process starting with atomic components and ending with pages.\n      </p>\n      <p>\n        Render pages with mock data. This makes it easy to build and review page states without\n        needing to navigate to them in your app. Here are some handy patterns for managing page data\n        in Storybook:\n      </p>\n      <ul>\n        <li>\n          Use a higher-level connected component. Storybook helps you compose such data from the\n          \"args\" of child component stories\n        </li>\n        <li>\n          Assemble data in the page component from your services. You can mock these services out\n          using Storybook.\n        </li>\n      </ul>\n      <p>\n        Get a guided tutorial on component-driven development at\n        <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n          Storybook tutorials\n        </a>\n        . Read more in the\n        <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\"> docs </a>\n        .\n      </p>\n      <div class=\"tip-wrapper\">\n        <span class=\"tip\">Tip</span> Adjust the width of the canvas with the\n        <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n              id=\"a\"\n              fill=\"#999\"\n            />\n          </g>\n        </svg>\n        Viewports addon in the toolbar\n      </div>\n    </section>\n  </article>\n`;\n"
  },
  {
    "path": "code/frameworks/web-components-vite/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"storybook/internal/*\": [\"../../lib/cli/core/*\"]\n    },\n    \"rootDir\": \"./src\"\n  },\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/frameworks/web-components-vite/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/lib/cli-sb/README.md",
    "content": "# Storybook CLI\n\nThis is a wrapper for <https://www.npmjs.com/package/@storybook/cli>\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/lib/cli-sb/index.js",
    "content": "#!/usr/bin/env node\n\nimport('storybook/internal/bin/dispatcher');\n"
  },
  {
    "path": "code/lib/cli-sb/package.json",
    "content": "{\n  \"name\": \"sb\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook CLI: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"cli\",\n    \"dev\",\n    \"build\",\n    \"upgrade\",\n    \"init\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/lib/cli-sb\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/lib/cli-sb\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"bin\": \"./index.js\",\n  \"dependencies\": {\n    \"storybook\": \"workspace:*\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/lib/cli-sb/project.json",
    "content": "{\n  \"name\": \"sb\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {}\n}\n"
  },
  {
    "path": "code/lib/cli-sb/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/lib/cli-storybook/.eslintrc.cjs",
    "content": "module.exports = {\n  overrides: [\n    {\n      files: 'templates/**/*',\n      env: {\n        browser: true,\n      },\n      rules: {\n        'react/no-this-in-sfc': 'off',\n        'react/react-in-jsx-scope': 'off',\n        'global-require': 'off',\n        'no-redeclare': 'off',\n        'react/prop-types': 'off',\n      },\n    },\n    {\n      files: 'rendererAssets/**/*',\n      env: {\n        browser: true,\n      },\n      rules: {\n        'jsx-a11y/anchor-is-valid': 'off',\n        'react/prop-types': 'off',\n        'react/react-in-jsx-scope': 'off',\n        'import/extensions': 'off',\n        'import/named': 'off',\n      },\n    },\n  ],\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/README.md",
    "content": "# Storybook\n\n## CLI\n\nStorybook CLI (_Command Line Interface_) is the easiest way to add [Storybook](https://github.com/storybookjs/storybook) to your project.\n\n![Screenshot](docs/getstorybook.png)\n\nGo to your project and run:\n\n```sh\ncd my-app\nnpx storybook@latest init\n```\n\nIn addition to `init`, the CLI also has other commands:\n\n- `add` - add an addon and register it\n- `info` - print out system information for bug reports\n- `upgrade` - upgrade to the latest version of Storybook (or a specific version)\n- `migrate` - run codemods to migrate your code\n\nSee the command-line help with `-h` (including other useful commands) for details.\n\n## Core APIs\n\nThis package has multiple sub-exports to can be used to gain access to storybook's APIs.\n\n### `storybook/components`\n\nThis export contains a list of components very useful for building out addons.\nWe recommend addon-authors to use these components to ensure a consistent look and feel, and to reduce the amount of code they need to write.\n\n### `storybook/theming`\n\nThis export exposes a few utility functions to help writing components that automatically adapt to the current theme.\nUseful for addon authors who want to make their addons theme-aware.\n\n### `storybook/preview-api`\n\nThis export contains the API that is available in the preview iframe.\n\n### `storybook/manager-api`\n\nThis export contains the API that is available in the manager iframe.\n\n### `storybook/types`\n\nThis export exposes a lot of TypeScript interfaces used throughout storybook, including for storybook configuration, addons etc.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/lib/cli-storybook/build-config.ts",
    "content": "import { join } from 'node:path';\n\nimport type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    node: [\n      {\n        entryPoint: './src/bin/index.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/lib/cli-storybook/package.json",
    "content": "{\n  \"name\": \"@storybook/cli\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook CLI: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"cli\",\n    \"dev\",\n    \"build\",\n    \"upgrade\",\n    \"init\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/lib/cli-storybook\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/lib/cli-storybook\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Storybook Team\",\n  \"type\": \"module\",\n  \"exports\": {\n    \"./package.json\": \"./package.json\"\n  },\n  \"bin\": \"./dist/bin/index.js\",\n  \"files\": [\n    \"bin/**/*\",\n    \"dist/**/*\",\n    \"README.md\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/codemod\": \"workspace:*\",\n    \"@types/semver\": \"^7.7.1\",\n    \"commander\": \"^14.0.2\",\n    \"create-storybook\": \"workspace:*\",\n    \"jscodeshift\": \"^0.15.1\",\n    \"storybook\": \"workspace:*\",\n    \"ts-dedent\": \"^2.0.0\"\n  },\n  \"devDependencies\": {\n    \"@types/cross-spawn\": \"^6.0.6\",\n    \"@types/prompts\": \"^2.0.9\",\n    \"comment-json\": \"^4.2.5\",\n    \"cross-spawn\": \"^7.0.6\",\n    \"empathic\": \"^2.0.0\",\n    \"envinfo\": \"^7.14.0\",\n    \"globby\": \"^14.1.0\",\n    \"leven\": \"^4.0.0\",\n    \"p-limit\": \"^7.2.0\",\n    \"picocolors\": \"^1.1.0\",\n    \"semver\": \"^7.7.3\",\n    \"slash\": \"^5.0.0\",\n    \"tiny-invariant\": \"^1.3.3\",\n    \"typescript\": \"^5.8.3\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/project.json",
    "content": "{\n  \"name\": \"cli\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/add.test.ts",
    "content": "import { beforeEach, describe, expect, test, vi } from 'vitest';\n\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { PackageManagerName } from '../../../core/src/common/index.ts';\nimport { add, getVersionSpecifier } from './add.ts';\n\nconst MockedConfig = vi.hoisted(() => {\n  return {\n    appendValueToArray: vi.fn(),\n    getFieldNode: vi.fn(),\n    valueToNode: vi.fn(),\n    appendNodeToArray: vi.fn(),\n  };\n});\nconst MockedPackageManager = vi.hoisted(() => {\n  return {\n    getPrimaryPackageJson: vi.fn(() => ({\n      packageJson: {\n        devDependencies: {},\n        dependencies: {},\n      },\n      packageJsonPath: 'some/path',\n      operationDir: 'some/path',\n    })),\n    getDependencyVersion: vi.fn(() => '^8.0.0'),\n    latestVersion: vi.fn(() => '1.0.0'),\n    addDependencies: vi.fn(() => {}),\n    type: 'npm',\n  };\n});\nconst MockedPostInstall = vi.hoisted(() => {\n  return {\n    postinstallAddon: vi.fn(),\n  };\n});\nconst MockWrapGetAbsolutePathUtils = vi.hoisted(() => {\n  return {\n    getAbsolutePathWrapperName: vi.fn(),\n    wrapValueWithGetAbsolutePathWrapper: vi.fn(),\n  };\n});\nconst MockedConsole = {\n  log: vi.fn(),\n  warn: vi.fn(),\n  error: vi.fn(),\n} as any as Console;\n\nconst MockedMainConfigFileHelper = vi.hoisted(() => {\n  return {\n    getStorybookData: vi.fn(() => ({\n      mainConfig: {},\n      mainConfigPath: '.storybook/main.ts',\n      configDir: '.storybook',\n      previewConfigPath: '.storybook/preview.ts',\n      storybookVersion: '8.0.0',\n      storybookVersionSpecifier: '^8.0.0',\n      packageManager: MockedPackageManager,\n    })),\n  };\n});\n\nvi.mock('storybook/internal/csf-tools', () => {\n  return {\n    readConfig: vi.fn(() => MockedConfig),\n    writeConfig: vi.fn(),\n  };\n});\nvi.mock('./postinstallAddon', () => {\n  return MockedPostInstall;\n});\nvi.mock('./automigrate/helpers/mainConfigFile', () => {\n  return MockedMainConfigFileHelper;\n});\nvi.mock('./codemod/helpers/csf-factories-utils');\nvi.mock('storybook/internal/common', () => {\n  return {\n    getStorybookInfo: vi.fn(() => ({ mainConfig: {}, configDir: '' })),\n    serverRequire: vi.fn(() => ({})),\n    loadMainConfig: vi.fn(() => ({})),\n    JsPackageManagerFactory: {\n      getPackageManager: vi.fn(() => MockedPackageManager),\n    },\n    setupAddonInConfig: vi.fn(),\n    getAbsolutePathWrapperName: MockWrapGetAbsolutePathUtils.getAbsolutePathWrapperName,\n    wrapValueWithGetAbsolutePathWrapper:\n      MockWrapGetAbsolutePathUtils.wrapValueWithGetAbsolutePathWrapper,\n    versions: {\n      storybook: '8.0.0',\n      '@storybook/addon-docs': '8.0.0',\n    },\n    frameworkToRenderer: vi.fn(),\n  };\n});\n\ndescribe('getVersionSpecifier', (it) => {\n  test.each([\n    ['@storybook/addon-docs', ['@storybook/addon-docs', undefined]],\n    ['@storybook/addon-docs@7.0.1', ['@storybook/addon-docs', '7.0.1']],\n    ['@storybook/addon-docs@7.0.1-beta.1', ['@storybook/addon-docs', '7.0.1-beta.1']],\n    ['@storybook/addon-docs@~7.0.1-beta.1', ['@storybook/addon-docs', '~7.0.1-beta.1']],\n    ['@storybook/addon-docs@^7.0.1-beta.1', ['@storybook/addon-docs', '^7.0.1-beta.1']],\n    ['@storybook/addon-docs@next', ['@storybook/addon-docs', 'next']],\n  ])('%s => %s', (input, expected) => {\n    const result = getVersionSpecifier(input);\n    expect(result[0]).toEqual(expected[0]);\n    expect(result[1]).toEqual(expected[1]);\n  });\n});\n\ndescribe('add', () => {\n  const testData = [\n    { input: 'aa', expected: 'aa@^1.0.0' }, // resolves to the latest version\n    { input: 'aa@4', expected: 'aa@^4' },\n    { input: 'aa@4.1.0', expected: 'aa@^4.1.0' },\n    { input: 'aa@^4', expected: 'aa@^4' },\n    { input: 'aa@~4', expected: 'aa@~4' },\n    { input: 'aa@4.1.0-alpha.1', expected: 'aa@^4.1.0-alpha.1' },\n    { input: 'aa@next', expected: 'aa@next' },\n\n    { input: '@org/aa', expected: '@org/aa@^1.0.0' },\n    { input: '@org/aa@4', expected: '@org/aa@^4' },\n    { input: '@org/aa@4.1.0', expected: '@org/aa@^4.1.0' },\n    { input: '@org/aa@4.1.0-alpha.1', expected: '@org/aa@^4.1.0-alpha.1' },\n    { input: '@org/aa@next', expected: '@org/aa@next' },\n\n    { input: '@storybook/addon-docs@~4', expected: '@storybook/addon-docs@~4' },\n    { input: '@storybook/addon-docs@next', expected: '@storybook/addon-docs@next' },\n    { input: '@storybook/addon-docs', expected: '@storybook/addon-docs@^8.0.0' }, // takes it from the versions file\n  ];\n\n  test.each(testData)('$input', async ({ input, expected }) => {\n    await add(input, { packageManager: PackageManagerName.NPM, skipPostinstall: true });\n\n    expect(MockedPackageManager.addDependencies).toHaveBeenCalledWith(\n      { type: 'devDependencies', writeOutputToFile: false },\n      [expected]\n    );\n  });\n});\n\ndescribe('add (extra)', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n  });\n  test('not warning when installing the correct version of storybook', async () => {\n    await add('@storybook/addon-docs', {\n      packageManager: PackageManagerName.NPM,\n      skipPostinstall: true,\n    });\n\n    expect(logger.warn).not.toHaveBeenCalledWith(\n      expect.stringContaining(`is not the same as the version of Storybook you are using.`)\n    );\n  });\n  test('not warning when installing unrelated package', async () => {\n    await add('aa', { packageManager: PackageManagerName.NPM, skipPostinstall: true });\n\n    expect(logger.warn).not.toHaveBeenCalledWith(\n      expect.stringContaining(`is not the same as the version of Storybook you are using.`)\n    );\n  });\n  test('warning when installing a core addon mismatching version of storybook', async () => {\n    await add('@storybook/addon-docs@2.0.0', {\n      packageManager: PackageManagerName.NPM,\n      skipPostinstall: true,\n    });\n\n    expect(logger.warn).toHaveBeenCalledWith(\n      expect.stringContaining(\n        `The version of @storybook/addon-docs (2.0.0) you are installing is not the same as the version of Storybook you are using (8.0.0). This may lead to unexpected behavior.`\n      )\n    );\n  });\n\n  test('postInstall', async () => {\n    await add('@storybook/addon-docs', {\n      packageManager: PackageManagerName.NPM,\n      skipPostinstall: false,\n    });\n\n    expect(MockedPostInstall.postinstallAddon).toHaveBeenCalledWith('@storybook/addon-docs', {\n      packageManager: 'npm',\n      configDir: '.storybook',\n      logger: expect.any(Object),\n      prompt: expect.any(Object),\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/add.ts",
    "content": "import { type PackageManagerName, setupAddonInConfig, versions } from 'storybook/internal/common';\nimport { readConfig } from 'storybook/internal/csf-tools';\nimport { logger as nodeLogger } from 'storybook/internal/node-logger';\nimport { prompt } from 'storybook/internal/node-logger';\nimport type { StorybookConfigRaw } from 'storybook/internal/types';\n\nimport SemVer from 'semver';\nimport { dedent } from 'ts-dedent';\n\nimport { getStorybookData } from './automigrate/helpers/mainConfigFile.ts';\nimport { postinstallAddon } from './postinstallAddon.ts';\n\nexport interface PostinstallOptions {\n  packageManager: PackageManagerName;\n  configDir: string;\n  logger: typeof nodeLogger;\n  prompt: typeof prompt;\n  yes?: boolean;\n  skipInstall?: boolean;\n  /**\n   * Skip all dependency management (collecting, adding to package.json, installing). Used when the\n   * caller (e.g., init command) has already handled dependencies.\n   */\n  skipDependencyManagement?: boolean;\n}\n\n/**\n * Extract the addon name and version specifier from the input string\n *\n * @example\n *\n * ```ts\n * getVersionSpecifier('@storybook/addon-docs@7.0.1') => ['@storybook/addon-docs', '7.0.1']\n * ```\n *\n * @param addon - The input string\n * @returns {undefined} AddonName, versionSpecifier\n */\nexport const getVersionSpecifier = (addon: string) => {\n  const groups = /^(@{0,1}[^@]+)(?:@(.+))?$/.exec(addon);\n  if (groups) {\n    return [groups[1], groups[2]] as const;\n  }\n  return [addon, undefined] as const;\n};\n\nconst checkInstalled = (addonName: string, main: StorybookConfigRaw) => {\n  const existingAddon = main.addons?.find((entry: string | { name: string }) => {\n    const name = typeof entry === 'string' ? entry : entry.name;\n    return name?.endsWith(addonName);\n  });\n  return !!existingAddon;\n};\n\nconst isCoreAddon = (addonName: string) => Object.hasOwn(versions, addonName);\n\ntype CLIOptions = {\n  packageManager?: PackageManagerName;\n  configDir?: string;\n  skipInstall?: boolean;\n  skipPostinstall: boolean;\n  yes?: boolean;\n};\n\n/**\n * Install the given addon package and add it to main.js\n *\n * @example\n *\n * ```sh\n * sb add \"@storybook/addon-docs\"\n * sb add \"@storybook/addon-vitest@9.0.1\"\n * ```\n *\n * If there is no version specifier and it's a Storybook addon, it will try to use the version\n * specifier matching your current Storybook install version.\n */\nexport async function add(\n  addon: string,\n  {\n    packageManager: pkgMgr,\n    skipPostinstall,\n    configDir: userSpecifiedConfigDir,\n    yes,\n    skipInstall,\n  }: CLIOptions,\n  logger = nodeLogger\n) {\n  const [addonName, inputVersion] = getVersionSpecifier(addon);\n\n  const { mainConfig, mainConfigPath, configDir, previewConfigPath, packageManager } =\n    await getStorybookData({\n      configDir: userSpecifiedConfigDir,\n      packageManagerName: pkgMgr,\n    });\n\n  if (typeof configDir === 'undefined') {\n    throw new Error(dedent`\n      Unable to find storybook config directory. Please specify your Storybook config directory with the --config-dir flag.\n    `);\n  }\n\n  if (!mainConfigPath) {\n    logger.error('Unable to find Storybook main.js config');\n    return;\n  }\n\n  let shouldAddToMain = true;\n  if (checkInstalled(addonName, mainConfig)) {\n    shouldAddToMain = false;\n    if (!yes) {\n      logger.log(`The Storybook addon \"${addonName}\" is already present in ${mainConfigPath}.`);\n      const shouldForceInstall = await prompt.confirm({\n        message: `Do you wish to install it again?`,\n      });\n\n      if (!shouldForceInstall) {\n        return;\n      }\n    }\n  }\n\n  const main = await readConfig(mainConfigPath);\n  logger.log(`Verifying ${addonName}`);\n\n  let version = inputVersion;\n\n  if (!version && isCoreAddon(addonName)) {\n    version = versions.storybook;\n  }\n\n  if (!version) {\n    const latestVersion = await packageManager.latestVersion(addonName);\n    if (!latestVersion) {\n      throw new Error(`No version found for ${addonName}`);\n    }\n    version = latestVersion;\n  }\n\n  const storybookVersion = versions.storybook;\n  const versionIsStorybook = version === versions.storybook;\n\n  if (isCoreAddon(addonName) && !versionIsStorybook) {\n    logger.warn(\n      `The version of ${addonName} (${version}) you are installing is not the same as the version of Storybook you are using (${storybookVersion}). This may lead to unexpected behavior.`\n    );\n  }\n\n  const storybookVersionSpecifier = packageManager.getDependencyVersion('storybook');\n  const versionRange = storybookVersionSpecifier?.match(/^[~^]/)?.[0] ?? '';\n\n  const addonWithVersion = versionIsStorybook\n    ? `${addonName}@${versionRange}${storybookVersion}`\n    : isValidVersion(version) && !version.includes('-pr-')\n      ? `${addonName}@^${version}`\n      : `${addonName}@${version}`;\n\n  logger.log(`Installing ${addonWithVersion}`);\n\n  await packageManager.addDependencies(\n    { type: 'devDependencies', writeOutputToFile: false, skipInstall },\n    [addonWithVersion]\n  );\n\n  if (shouldAddToMain) {\n    logger.log(`Adding '${addon}' to the \"addons\" field in ${mainConfigPath}`);\n\n    await setupAddonInConfig({\n      addonName,\n      mainConfigCSFFile: main,\n      previewConfigPath,\n      configDir,\n    });\n  }\n\n  if (!skipPostinstall && isCoreAddon(addonName)) {\n    await postinstallAddon(addonName, {\n      packageManager: packageManager.type,\n      configDir,\n      yes,\n      logger,\n      prompt,\n      skipInstall,\n    });\n  }\n}\nfunction isValidVersion(version: string) {\n  return SemVer.valid(version) || version.match(/^\\d+$/);\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/autoblock/block-dependencies-versions.ts",
    "content": "import { dedent } from 'ts-dedent';\n\nimport { createBlocker } from './types.ts';\nimport { findOutdatedPackage } from './utils.ts';\n\nconst minimalVersionsMap = {\n  '@angular/core': '18.0.0',\n  'react-scripts': '5.0.0',\n  next: '14.1.0',\n  preact: '10.0.0',\n  svelte: '5.0.0',\n  vue: '3.0.0',\n  vite: '5.0.0',\n} as const;\n\nexport const blocker = createBlocker({\n  id: 'dependenciesVersions',\n  async check({ packageManager }) {\n    return findOutdatedPackage<typeof minimalVersionsMap>(minimalVersionsMap, { packageManager });\n  },\n  log(data) {\n    switch (data.packageName) {\n      case '@angular/core':\n        return {\n          title: 'Angular 18 support removed',\n          message: dedent`\n            Support for Angular < 18 has been removed.\n            Please see the migration guide for more information:\n          `,\n          link: 'https://angular.dev/update-guide',\n        };\n      case 'next':\n        return {\n          title: 'Next.js 14.1 support removed',\n          message: dedent`\n            Support for Next.js < 14.1 has been removed.\n            Please see the migration guide for more information:\n          `,\n          link: 'https://nextjs.org/docs/pages/building-your-application/upgrading/version-13',\n        };\n      default:\n        return {\n          title: `${data.packageName} version < ${data.minimumVersion} support removed`,\n          message: dedent`\n            Support for ${data.packageName} version < ${data.minimumVersion} has been removed.\n            Storybook needs a minimum version of ${data.minimumVersion}, but you have version ${data.installedVersion}.\n          `,\n        };\n    }\n  },\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/autoblock/block-experimental-addon-test.test.ts",
    "content": "import { beforeEach, describe, expect, test, vi } from 'vitest';\n\nimport semver from 'semver';\nimport { dedent } from 'ts-dedent';\n\nimport { blocker } from './block-experimental-addon-test.ts';\n\nvi.mock('semver');\n\nvi.mock('picocolors', async (importOriginal) => {\n  const mod = (await importOriginal()) as any;\n  return {\n    ...mod,\n    default: {\n      bold: (s: string) => s,\n      magenta: (s: string) => s,\n    },\n  };\n});\n\ndescribe('experimentalAddonTestVitest blocker', () => {\n  const mockPackageManager = {\n    getInstalledVersion: vi.fn(),\n  };\n\n  beforeEach(() => {\n    vi.clearAllMocks();\n    vi.mocked(semver.lt).mockReturnValue(false);\n    mockPackageManager.getInstalledVersion.mockResolvedValue('3.0.0');\n  });\n\n  test('should return false if experimental addon is not installed', async () => {\n    mockPackageManager.getInstalledVersion.mockImplementation(async (pkg: string) => {\n      if (pkg === '@storybook/experimental-addon-test') {\n        return null;\n      }\n      return '3.0.0';\n    });\n\n    const result = await blocker.check({\n      packageJson: {\n        dependencies: {},\n        devDependencies: {},\n      },\n      packageManager: mockPackageManager as any,\n    } as any);\n\n    expect(result).toBe(false);\n  });\n\n  test('should return false if vitest is not installed', async () => {\n    mockPackageManager.getInstalledVersion.mockImplementation(async (pkg: string) => {\n      if (pkg === '@storybook/experimental-addon-test') {\n        return '1.0.0';\n      }\n      if (pkg === 'vitest') {\n        return null;\n      }\n      return '3.0.0';\n    });\n\n    const result = await blocker.check({\n      packageJson: {\n        dependencies: {\n          '@storybook/experimental-addon-test': '^1.0.0',\n        },\n        devDependencies: {},\n      },\n      packageManager: mockPackageManager as any,\n    } as any);\n\n    expect(result).toBe(false);\n    expect(mockPackageManager.getInstalledVersion).toHaveBeenCalledWith('vitest');\n  });\n\n  test('should return true if vitest version is less than 3.0.0', async () => {\n    mockPackageManager.getInstalledVersion.mockImplementation(async (pkg: string) => {\n      if (pkg === '@storybook/experimental-addon-test') {\n        return '1.0.0';\n      }\n      if (pkg === 'vitest') {\n        return '2.9.0';\n      }\n      return '3.0.0';\n    });\n    vi.mocked(semver.lt).mockReturnValue(true);\n\n    const result = await blocker.check({\n      packageJson: {\n        dependencies: {\n          '@storybook/experimental-addon-test': '^1.0.0',\n        },\n        devDependencies: {},\n      },\n      packageManager: mockPackageManager as any,\n    } as any);\n\n    expect(result).toBe(true);\n    expect(mockPackageManager.getInstalledVersion).toHaveBeenCalledWith('vitest');\n    expect(semver.lt).toHaveBeenCalledWith('2.9.0', '3.0.0');\n  });\n\n  test('should return false if vitest version is 3.0.0 or greater', async () => {\n    mockPackageManager.getInstalledVersion.mockImplementation(async (pkg: string) => {\n      if (pkg === '@storybook/experimental-addon-test') {\n        return '1.0.0';\n      }\n      if (pkg === 'vitest') {\n        return '3.0.0';\n      }\n      return '3.0.0';\n    });\n    vi.mocked(semver.lt).mockReturnValue(false);\n\n    const result = await blocker.check({\n      packageJson: {\n        dependencies: {\n          '@storybook/experimental-addon-test': '^1.0.0',\n        },\n        devDependencies: {},\n      },\n      packageManager: mockPackageManager as any,\n    } as any);\n\n    expect(result).toBe(false);\n    expect(mockPackageManager.getInstalledVersion).toHaveBeenCalledWith('vitest');\n    expect(semver.lt).toHaveBeenCalledWith('3.0.0', '3.0.0');\n  });\n\n  test('should check both dependencies and devDependencies for experimental addon', async () => {\n    mockPackageManager.getInstalledVersion.mockImplementation(async (pkg: string) => {\n      if (pkg === '@storybook/experimental-addon-test') {\n        return '1.0.0';\n      }\n      if (pkg === 'vitest') {\n        return '3.0.0';\n      }\n      return '3.0.0';\n    });\n\n    await blocker.check({\n      packageJson: {\n        dependencies: {},\n        devDependencies: {\n          '@storybook/experimental-addon-test': '^1.0.0',\n        },\n      },\n      packageManager: mockPackageManager as any,\n    } as any);\n\n    expect(mockPackageManager.getInstalledVersion).toHaveBeenCalledWith('vitest');\n  });\n\n  test('log should return correct message', () => {\n    const result = blocker.log(true);\n    expect(result.message).toMatchInlineSnapshot(dedent`\n      \"@storybook/experimental-addon-test is being stabilized in Storybook 9.\n\n      The addon will be renamed to @storybook/addon-vitest and as part of this stabilization, we have dropped support for Vitest 2.\n\n      You have two options to proceed:\n      1. Remove @storybook/experimental-addon-test if you don't need it\n      2. Upgrade to Vitest 3 to continue using the addon\"\n    `);\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/autoblock/block-experimental-addon-test.ts",
    "content": "import semver from 'semver';\nimport { dedent } from 'ts-dedent';\n\nimport { createBlocker } from './types.ts';\n\nexport const blocker = createBlocker({\n  id: 'experimentalAddonTestVitest',\n  async check({ packageManager }) {\n    const experimentalAddonTestVersion = await packageManager.getInstalledVersion(\n      '@storybook/experimental-addon-test'\n    );\n\n    if (!experimentalAddonTestVersion) {\n      return false;\n    }\n\n    const vitestVersion = await packageManager.getInstalledVersion('vitest');\n\n    if (!vitestVersion) {\n      return false;\n    }\n\n    return semver.lt(vitestVersion, '3.0.0');\n  },\n  log() {\n    return {\n      title: 'Experimental Addon Test Vitest',\n      message: dedent`\n      @storybook/experimental-addon-test is being stabilized in Storybook 9.\n      \n      The addon will be renamed to @storybook/addon-vitest and as part of this stabilization, we have dropped support for Vitest 2.\n      \n      You have two options to proceed:\n      1. Remove @storybook/experimental-addon-test if you don't need it\n      2. Upgrade to Vitest 3 to continue using the addon\n    `,\n      link: 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#experimental-addon-test-vitest',\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/autoblock/block-major-version.test.ts",
    "content": "import { beforeEach, describe, expect, test, vi } from 'vitest';\n\n// Import mocked modules\nimport * as semver from 'semver';\n\nimport { blocker, validateVersionTransition } from './block-major-version.ts';\n\n// Mock all dependencies at the top level\nvi.mock('storybook/internal/common', () => ({\n  versions: {\n    storybook: '9.0.0',\n  },\n}));\n\nvi.mock('picocolors', () => ({\n  default: {\n    red: (s: string) => s,\n    cyan: (s: string) => s,\n  },\n}));\n\nvi.mock('semver', () => ({\n  coerce: vi.fn(),\n  gt: vi.fn(),\n  major: vi.fn(),\n  parse: vi.fn(),\n  prerelease: vi.fn(),\n}));\n\nvi.mock('ts-dedent', () => ({\n  dedent: vi.fn((strings: TemplateStringsArray, ...values: any[]) => {\n    // Simple dedent mock that just joins the template\n    let result = strings[0];\n    for (let i = 0; i < values.length; i++) {\n      result += values[i] + strings[i + 1];\n    }\n    return result.trim();\n  }),\n}));\n\nvi.mock('./types', () => ({\n  createBlocker: vi.fn((blocker) => blocker),\n}));\n\nconst mockedSemver = vi.mocked(semver);\n\ndescribe('validateVersionTransition', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n  });\n\n  test('should return \"ok\" for missing currentVersion', () => {\n    const result = validateVersionTransition('', '9.0.0');\n    expect(result).toBe('ok');\n  });\n\n  test('should return \"ok\" for missing targetVersion', () => {\n    const result = validateVersionTransition('8.0.0', '');\n    expect(result).toBe('ok');\n  });\n\n  test('should return \"ok\" for invalid currentVersion', () => {\n    mockedSemver.parse\n      .mockReturnValueOnce(null)\n      .mockReturnValueOnce({ major: 9, minor: 0, patch: 0 } as any);\n\n    const result = validateVersionTransition('invalid', '9.0.0');\n    expect(result).toBe('ok');\n  });\n\n  test('should return \"ok\" for invalid targetVersion', () => {\n    mockedSemver.parse\n      .mockReturnValueOnce({ major: 8, minor: 0, patch: 0 } as any)\n      .mockReturnValueOnce(null);\n\n    const result = validateVersionTransition('8.0.0', 'invalid');\n    expect(result).toBe('ok');\n  });\n\n  test('should return \"ok\" for prerelease currentVersion', () => {\n    mockedSemver.parse\n      .mockReturnValueOnce({ major: 8, minor: 0, patch: 0 } as any)\n      .mockReturnValueOnce({ major: 9, minor: 0, patch: 0 } as any);\n    mockedSemver.prerelease.mockReturnValueOnce(['alpha', 1]).mockReturnValueOnce(null);\n\n    const result = validateVersionTransition('8.0.0-alpha.1', '9.0.0');\n    expect(result).toBe('ok');\n  });\n\n  test('should return \"ok\" for prerelease targetVersion', () => {\n    mockedSemver.parse\n      .mockReturnValueOnce({ major: 8, minor: 0, patch: 0 } as any)\n      .mockReturnValueOnce({ major: 9, minor: 0, patch: 0 } as any);\n    mockedSemver.prerelease.mockReturnValueOnce(null).mockReturnValueOnce(['alpha', 1]);\n\n    const result = validateVersionTransition('8.0.0', '9.0.0-alpha.1');\n    expect(result).toBe('ok');\n  });\n\n  test('should return \"ok\" for version zero currentVersion', () => {\n    mockedSemver.parse\n      .mockReturnValueOnce({ major: 0, minor: 1, patch: 0 } as any)\n      .mockReturnValueOnce({ major: 9, minor: 0, patch: 0 } as any);\n    mockedSemver.prerelease.mockReturnValue(null);\n\n    const result = validateVersionTransition('0.1.0', '9.0.0');\n    expect(result).toBe('ok');\n  });\n\n  test('should return \"ok\" for version zero targetVersion', () => {\n    mockedSemver.parse\n      .mockReturnValueOnce({ major: 8, minor: 0, patch: 0 } as any)\n      .mockReturnValueOnce({ major: 0, minor: 1, patch: 0 } as any);\n    mockedSemver.prerelease.mockReturnValue(null);\n\n    const result = validateVersionTransition('8.0.0', '0.1.0');\n    expect(result).toBe('ok');\n  });\n\n  test('should return \"downgrade\" when current version is greater than target', () => {\n    mockedSemver.parse\n      .mockReturnValueOnce({ major: 9, minor: 0, patch: 0 } as any)\n      .mockReturnValueOnce({ major: 8, minor: 0, patch: 0 } as any);\n    mockedSemver.prerelease.mockReturnValue(null);\n    mockedSemver.gt.mockReturnValue(true);\n\n    const result = validateVersionTransition('9.0.0', '8.0.0');\n    expect(result).toBe('downgrade');\n  });\n\n  test('should return \"gap-too-large\" when version gap is greater than 1', () => {\n    mockedSemver.parse\n      .mockReturnValueOnce({ major: 7, minor: 0, patch: 0 } as any)\n      .mockReturnValueOnce({ major: 9, minor: 0, patch: 0 } as any);\n    mockedSemver.prerelease.mockReturnValue(null);\n    mockedSemver.gt.mockReturnValue(false);\n\n    const result = validateVersionTransition('7.0.0', '9.0.0');\n    expect(result).toBe('gap-too-large');\n  });\n\n  test('should return \"ok\" for valid single major version upgrade', () => {\n    mockedSemver.parse\n      .mockReturnValueOnce({ major: 8, minor: 0, patch: 0 } as any)\n      .mockReturnValueOnce({ major: 9, minor: 0, patch: 0 } as any);\n    mockedSemver.prerelease.mockReturnValue(null);\n    mockedSemver.gt.mockReturnValue(false);\n\n    const result = validateVersionTransition('8.0.0', '9.0.0');\n    expect(result).toBe('ok');\n  });\n\n  test('should return \"ok\" for same version', () => {\n    mockedSemver.parse\n      .mockReturnValueOnce({ major: 9, minor: 0, patch: 0 } as any)\n      .mockReturnValueOnce({ major: 9, minor: 0, patch: 0 } as any);\n    mockedSemver.prerelease.mockReturnValue(null);\n    mockedSemver.gt.mockReturnValue(false);\n\n    const result = validateVersionTransition('9.0.0', '9.0.0');\n    expect(result).toBe('ok');\n  });\n});\n\ndescribe('blocker', () => {\n  const mockPackageManager = {\n    getAllDependencies: vi.fn(),\n  };\n\n  const baseOptions = {\n    packageManager: mockPackageManager,\n    mainConfig: { stories: [] },\n    mainConfigPath: '.storybook/main.ts',\n    configDir: '.storybook',\n  } as any;\n\n  beforeEach(() => {\n    vi.clearAllMocks();\n    mockPackageManager.getAllDependencies.mockReturnValue({});\n  });\n\n  describe('check method', () => {\n    test('should return false when storybook dependency is not found', async () => {\n      mockPackageManager.getAllDependencies.mockReturnValue({});\n\n      const result = await blocker.check(baseOptions);\n      expect(result).toBe(false);\n    });\n\n    test('should return false when version transition is ok', async () => {\n      mockPackageManager.getAllDependencies.mockReturnValue({\n        storybook: '8.0.0',\n      });\n      mockedSemver.parse\n        .mockReturnValueOnce({ major: 8, minor: 0, patch: 0 } as any)\n        .mockReturnValueOnce({ major: 9, minor: 0, patch: 0 } as any);\n      mockedSemver.prerelease.mockReturnValue(null);\n      mockedSemver.gt.mockReturnValue(false);\n\n      const result = await blocker.check(baseOptions);\n      expect(result).toBe(false);\n    });\n\n    test('should return data when downgrade is detected', async () => {\n      mockPackageManager.getAllDependencies.mockReturnValue({\n        storybook: '10.0.0',\n      });\n      mockedSemver.parse\n        .mockReturnValueOnce({ major: 10, minor: 0, patch: 0 } as any)\n        .mockReturnValueOnce({ major: 9, minor: 0, patch: 0 } as any);\n      mockedSemver.prerelease.mockReturnValue(null);\n      mockedSemver.gt.mockReturnValue(true);\n\n      const result = await blocker.check(baseOptions);\n      expect(result).toEqual({\n        currentVersion: '10.0.0',\n        reason: 'downgrade',\n      });\n    });\n\n    test('should return data when version gap is too large', async () => {\n      mockPackageManager.getAllDependencies.mockReturnValue({\n        storybook: '7.0.0',\n      });\n      mockedSemver.parse\n        .mockReturnValueOnce({ major: 7, minor: 0, patch: 0 } as any)\n        .mockReturnValueOnce({ major: 9, minor: 0, patch: 0 } as any);\n      mockedSemver.prerelease.mockReturnValue(null);\n      mockedSemver.gt.mockReturnValue(false);\n\n      const result = await blocker.check(baseOptions);\n      expect(result).toEqual({\n        currentVersion: '7.0.0',\n        reason: 'gap-too-large',\n      });\n    });\n\n    test('should return false when an error occurs', async () => {\n      mockPackageManager.getAllDependencies.mockImplementation(() => {\n        throw new Error('Test error');\n      });\n\n      const result = await blocker.check(baseOptions);\n      expect(result).toBe(false);\n    });\n  });\n\n  describe('log method', () => {\n    test('should return downgrade message when reason is downgrade', () => {\n      const data = {\n        currentVersion: '10.0.0',\n        reason: 'downgrade' as const,\n      };\n\n      const result = blocker.log(data);\n      expect(result.title).toContain('Downgrade Not Supported');\n      expect(result.message).toContain('v10.0.0');\n      expect(result.message).toContain('v9.0.0');\n      expect(result.message).toContain('Downgrading is not supported');\n    });\n\n    test('should return version gap message with upgrade command when version can be coerced', () => {\n      const data = {\n        currentVersion: '7.0.0',\n        reason: 'gap-too-large' as const,\n      };\n\n      mockedSemver.coerce.mockReturnValue({ version: '7.0.0' } as any);\n      mockedSemver.major.mockReturnValue(7);\n\n      const result = blocker.log(data);\n      expect(result.title).toContain('Major Version Gap Detected');\n      expect(result.message).toContain('v7.0.0');\n      expect(result.message).toContain('v9.0.0');\n      expect(result.message).toContain('upgrade one major version at a time');\n      expect(result.message).toContain('npx storybook@8 upgrade');\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/autoblock/block-major-version.ts",
    "content": "import { versions } from 'storybook/internal/common';\nimport { CLI_COLORS } from 'storybook/internal/node-logger';\n\nimport { coerce, gt, major, parse } from 'semver';\nimport { dedent } from 'ts-dedent';\n\nimport { createBlocker } from './types.ts';\n\ntype UpgradeCheckResult = 'downgrade' | 'gap-too-large' | 'ok';\n\ninterface MajorVersionData {\n  currentVersion: string;\n  reason: Exclude<UpgradeCheckResult, 'ok'>;\n}\n\n/** Returns the status of the upgrade check */\nexport function validateVersionTransition(\n  currentVersion: string,\n  targetVersion: string\n): UpgradeCheckResult {\n  // Skip check for missing versions\n  if (!currentVersion || !targetVersion) {\n    return 'ok';\n  }\n\n  const current = parse(currentVersion);\n  const target = parse(targetVersion);\n  if (!current || !target) {\n    return 'ok';\n  }\n\n  // Never block if upgrading from or to version zero\n  if (current.major === 0 || target.major === 0) {\n    return 'ok';\n  }\n\n  // Check for downgrade (when current version is greater than target)\n  if (gt(currentVersion, targetVersion)) {\n    return 'downgrade';\n  }\n\n  // Check for version gap\n  const gap = target.major - current.major;\n  return gap > 1 ? 'gap-too-large' : 'ok';\n}\n\nexport const blocker = createBlocker<MajorVersionData>({\n  id: 'major-version-gap',\n  async check(options) {\n    const { packageManager } = options;\n    try {\n      const currentStorybookVersion = packageManager.getAllDependencies().storybook;\n      if (!currentStorybookVersion) {\n        return false;\n      }\n\n      const target = versions.storybook;\n      const result = validateVersionTransition(currentStorybookVersion, target);\n      if (result === 'ok') {\n        return false;\n      }\n\n      return {\n        currentVersion: currentStorybookVersion,\n        reason: result,\n      };\n    } catch (e) {\n      // If we can't determine the version, don't block\n      return false;\n    }\n  },\n  log(data) {\n    const coercedVersion = coerce(data.currentVersion);\n\n    if (data.reason === 'downgrade') {\n      return {\n        title: 'Downgrade Not Supported',\n        message: dedent`\n          Your Storybook version (v${data.currentVersion}) is newer than the target release (v${versions.storybook}). Downgrading is not supported.\n          `,\n        link: 'https://storybook.js.org/docs/releases/migration-guide?ref=upgrade',\n      };\n    }\n\n    if (coercedVersion) {\n      const currentMajor = major(coercedVersion);\n      const nextMajor = currentMajor + 1;\n      return {\n        title: 'Major Version Gap Detected',\n        message: dedent`\n          Your Storybook version (v${data.currentVersion}) is more than one major version behind the target release (v${versions.storybook}). Please upgrade one major version at a time.\n          \n          You can upgrade to version ${nextMajor} by running:\n          ${CLI_COLORS.info(`npx storybook@${nextMajor} upgrade`)}\n        `,\n        link: `https://storybook.js.org/docs/${nextMajor}/migration-guide?ref=upgrade`,\n      };\n    }\n\n    throw new Error('No message found');\n  },\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/autoblock/block-node-version.ts",
    "content": "import { lt } from 'semver';\n\nimport { createBlocker } from './types.ts';\n\nexport const blocker = createBlocker({\n  id: 'minimumNode20',\n  async check() {\n    const nodeVersion = process.versions.node;\n    if (nodeVersion && lt(nodeVersion, '20.0.0')) {\n      return { nodeVersion };\n    }\n    return false;\n  },\n  log(data) {\n    return {\n      title: 'Node.js 20 support removed',\n      message: `We've detected you're using Node.js v${data.nodeVersion}. Storybook needs Node.js 20 or higher.`,\n      link: 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#nodejs--20',\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/autoblock/block-webpack5-frameworks.ts",
    "content": "import { createBlocker } from './types.ts';\nimport { findOutdatedPackage } from './utils.ts';\n\nconst minimalVersionsMap = {\n  '@storybook/preact-webpack5': '9.0.0',\n  '@storybook/preset-preact-webpack': '9.0.0',\n  '@storybook/vue3-webpack5': '9.0.0',\n  '@storybook/preset-vue3-webpack': '9.0.0',\n  '@storybook/html-webpack5': '9.0.0',\n  '@storybook/preset-html-webpack': '9.0.0',\n  '@storybook/web-components-webpack5': '9.0.0',\n  '@storybook/svelte-webpack5': '9.0.0',\n} as const;\n\nexport const blocker = createBlocker({\n  id: 'dependenciesVersions',\n  async check({ packageManager }) {\n    return findOutdatedPackage<typeof minimalVersionsMap>(minimalVersionsMap, { packageManager });\n  },\n  log(data) {\n    const additionalInfo =\n      'Please migrate your Webpack5-based frameworks to their Vite equivalents.';\n    const link =\n      'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#dropped-webpack5-builder-support-in-favor-of-vite';\n\n    let title: string;\n\n    switch (data.packageName) {\n      case '@storybook/preact-webpack5':\n      case '@storybook/preset-preact-webpack':\n        title = 'Preact Webpack5 support removed';\n        break;\n      case '@storybook/vue3-webpack5':\n      case '@storybook/preset-vue3-webpack':\n        title = 'Vue3 Webpack5 support removed';\n        break;\n      case '@storybook/html-webpack5':\n      case '@storybook/preset-html-webpack':\n        title = 'HTML Webpack5 support removed';\n        break;\n      case '@storybook/web-components-webpack5':\n        title = 'Web Components Webpack5 support removed';\n        break;\n      case '@storybook/svelte-webpack5':\n        title = 'Svelte Webpack5 support removed';\n        break;\n    }\n\n    return {\n      title,\n      message: additionalInfo,\n      link,\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/autoblock/index.test.ts",
    "content": "import { beforeEach, expect, test, vi } from 'vitest';\n\nimport { autoblock } from './index.ts';\nimport { type BlockerModule, createBlocker } from './types.ts';\n\nvi.mock('node:fs/promises', async (importOriginal) => ({\n  ...(await importOriginal<any>()),\n  writeFile: vi.fn(),\n}));\nvi.mock('storybook/internal/node-logger', () => ({\n  logger: {\n    info: vi.fn(),\n    line: vi.fn(),\n    plain: vi.fn(),\n  },\n  prompt: {\n    logBox: vi.fn((x) => x),\n  },\n}));\n\nconst blockers = {\n  alwaysPass: createBlocker({\n    id: 'alwaysPass',\n    check: async () => false,\n    log: () => ({ title: 'Always pass', message: 'Always pass' }),\n  }),\n  alwaysFail: createBlocker({\n    id: 'alwaysFail',\n    check: async () => ({ bad: true }),\n    log: () => ({ title: 'Always fail', message: 'Always fail' }),\n  }),\n  alwaysFail2: createBlocker({\n    id: 'alwaysFail2',\n    check: async () => ({ disaster: true }),\n    log: () => ({ title: 'Always fail 2', message: 'Always fail 2' }),\n  }),\n} as const;\n\nconst mockPackageManager = {\n  getInstalledVersion: vi.fn(),\n  isPackageInstalled: vi.fn(),\n} as any;\n\nconst baseOptions: Parameters<typeof autoblock>[0] = {\n  configDir: '.storybook',\n  mainConfig: {\n    stories: [],\n  },\n  mainConfigPath: '.storybook/main.ts',\n  packageManager: mockPackageManager,\n};\n\nbeforeEach(() => {\n  vi.clearAllMocks();\n  // Default mock behavior: package not installed\n  mockPackageManager.getInstalledVersion.mockResolvedValue(null);\n  mockPackageManager.isPackageInstalled.mockResolvedValue(false);\n});\n\ntest('with empty list', async () => {\n  const result = await autoblock({ ...baseOptions }, []);\n  expect(result).toBe(null);\n});\n\ntest('all passing', async () => {\n  const result = await autoblock({ ...baseOptions }, [\n    Promise.resolve({ blocker: blockers.alwaysPass }),\n    Promise.resolve({ blocker: blockers.alwaysPass }),\n  ] as BlockerModule<any>[]);\n  expect(result?.[0].result).toEqual(false);\n  expect(result?.[1].result).toEqual(false);\n});\n\ntest('1 fail', async () => {\n  const result = await autoblock({ ...baseOptions }, [\n    Promise.resolve({ blocker: blockers.alwaysPass }),\n    Promise.resolve({ blocker: blockers.alwaysFail }),\n  ] as BlockerModule<any>[]);\n\n  expect(result?.[0].result).toEqual(false);\n  expect(result?.[1].result).toEqual({ bad: true });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/autoblock/index.ts",
    "content": "import type {\n  AutoblockOptions,\n  AutoblockerResult,\n  Blocker,\n  BlockerCheckResult,\n  BlockerModule,\n} from './types.ts';\n\nconst blockers: () => BlockerModule<any>[] = () => [\n  // add/remove blockers here\n  import('./block-dependencies-versions.ts'),\n  import('./block-node-version.ts'),\n  import('./block-webpack5-frameworks.ts'),\n  import('./block-major-version.ts'),\n  import('./block-experimental-addon-test.ts'),\n];\n\n/**\n * Runs autoblockers for a given project\n *\n * @param options - The options for the autoblockers.\n * @param list - The list of autoblockers to run.\n * @returns The results of the autoblockers.\n */\nexport const autoblock = async <R = unknown>(\n  options: AutoblockOptions,\n  list: BlockerModule<unknown>[] = blockers()\n): Promise<AutoblockerResult<R>[] | null> => {\n  if (list.length === 0) {\n    return null;\n  }\n\n  return await Promise.all(\n    list.map(async (i) => {\n      const blocker = (await i).blocker as Blocker<R>;\n      const result = (await blocker.check(options)) as BlockerCheckResult<R>;\n      return { result, blocker };\n    })\n  );\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/autoblock/types.ts",
    "content": "import type { JsPackageManager } from 'storybook/internal/common';\nimport type { StorybookConfig } from 'storybook/internal/types';\n\nexport interface AutoblockOptions {\n  packageManager: JsPackageManager;\n  mainConfig: StorybookConfig;\n  mainConfigPath: string;\n  configDir: string;\n}\n\nexport type BlockerCheckResult<T> = T | false;\n\nexport type BlockerModule<T> = Promise<{ blocker: Blocker<T> }>;\n\nexport type AutoblockerResult<T> = {\n  result: BlockerCheckResult<T>;\n  blocker: Blocker<T>;\n};\n\nexport interface Blocker<T> {\n  /** A unique string to identify the blocker with. */\n  id: string;\n  /**\n   * Check if the blocker should block.\n   *\n   * @param context\n   * @returns A truthy value to activate the block, return false to proceed.\n   */\n  check: (options: AutoblockOptions) => Promise<BlockerCheckResult<T>>;\n  /**\n   * Format a message to be printed to the log-file.\n   *\n   * @param context\n   * @param data Returned from the check method.\n   * @returns The string to print to the log-file.\n   */\n  log: (data: T) => {\n    /** The title of the blocker. */\n    title: string;\n    /** The message of the blocker. */\n    message: string;\n    /** A link to the documentation for the blocker. */\n    link?: string;\n  };\n}\n\nexport function createBlocker<T>(block: Blocker<T>) {\n  return block;\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/autoblock/utils.ts",
    "content": "import type { JsPackageManager } from 'storybook/internal/common';\nimport { CLI_COLORS } from 'storybook/internal/node-logger';\n\nimport picocolors from 'picocolors';\nimport { lt } from 'semver';\n\nimport { shortenPath } from '../util.ts';\nimport type { AutoblockerResult } from './types.ts';\n\ntype Result<M extends Record<string, string>> = {\n  installedVersion: string | undefined;\n  packageName: keyof M;\n  minimumVersion: string;\n};\n\nconst typedKeys = <TKey extends string>(obj: Record<TKey, any>) => Object.keys(obj) as TKey[];\n\n/**\n * Finds the outdated package in the list of packages.\n *\n * @param minimalVersionsMap - The map of minimal versions for the packages.\n * @param options - The options for the function.\n * @returns The outdated package or false if no outdated package is found.\n */\nexport async function findOutdatedPackage<M extends Record<string, string>>(\n  minimalVersionsMap: M,\n  options: {\n    packageManager: JsPackageManager;\n  }\n): Promise<false | Result<M>> {\n  const list = await Promise.all(\n    typedKeys(minimalVersionsMap).map(async (packageName) => ({\n      packageName,\n      installedVersion:\n        (await options.packageManager.getModulePackageJSON(packageName))?.version ?? null,\n      minimumVersion: minimalVersionsMap[packageName],\n    }))\n  );\n\n  return list.reduce<false | Result<M>>(\n    (acc, { installedVersion, minimumVersion, packageName }) => {\n      if (acc) {\n        return acc;\n      }\n      if (packageName && installedVersion && lt(installedVersion, minimumVersion)) {\n        return {\n          installedVersion,\n          packageName,\n          minimumVersion,\n        };\n      }\n      return acc;\n    },\n    false\n  );\n}\n\n/**\n * Processes autoblocker results and formats them for display. Returns true if there are blocking\n * issues that should prevent the upgrade.\n *\n * @param projects - Array of project results with autoblocker check results\n * @param onError - Callback function to handle error display\n * @returns True if there are blockers that should prevent upgrade, false otherwise\n */\nexport function processAutoblockerResults<\n  T extends { configDir: string; autoblockerCheckResults?: AutoblockerResult<unknown>[] | null },\n>(projects: T[], onError: (message: string) => void): boolean {\n  const autoblockerMessagesMap = new Map<\n    string,\n    { title: string; message: string; link?: string; configDirs: string[] }\n  >();\n\n  projects.forEach((result) => {\n    result.autoblockerCheckResults?.forEach((blocker) => {\n      if (blocker.result === null || blocker.result === false) {\n        return;\n      }\n      const blockerResult = blocker.blocker.log(blocker.result);\n      const message = blockerResult.message;\n      const link = blockerResult.link;\n\n      if (autoblockerMessagesMap.has(message)) {\n        autoblockerMessagesMap.get(message)!.configDirs.push(result.configDir);\n      } else {\n        autoblockerMessagesMap.set(message, {\n          title: blockerResult.title,\n          message,\n          link,\n          configDirs: [result.configDir],\n        });\n      }\n    });\n  });\n\n  const autoblockerMessages = Array.from(autoblockerMessagesMap.values());\n\n  if (autoblockerMessages.length > 0) {\n    const formatConfigDirs = (configDirs: string[]) => {\n      const baseMessage = 'Affected projects:';\n      const relativeDirs = configDirs.map((dir) => shortenPath(dir) || '.');\n      if (relativeDirs.length <= 3) {\n        return `${baseMessage} ${relativeDirs.join(', ')}`;\n      }\n      const remaining = relativeDirs.length - 3;\n      return `${baseMessage} ${relativeDirs.slice(0, 3).join(', ')}${remaining > 0 ? ` and ${remaining} more...` : ''}`;\n    };\n\n    const formattedMessages = autoblockerMessages.map((item) => {\n      let message = `${CLI_COLORS.warning(item.title)}\\n\\n${item.message}\\n\\n${formatConfigDirs(item.configDirs)}`;\n\n      if (item.link) {\n        message += `\\n\\nMore information: ${item.link}`;\n      }\n\n      return message;\n    });\n\n    onError(\n      `Storybook has found potential blockers that need to be resolved before upgrading:\\n\\n${[...formattedMessages].join(`\\n\\n`)}\\n\\n---\\n\\nAfter addressing this, you can try running the upgrade command again. You can also rerun the upgrade command with the ${CLI_COLORS.info('--force')} flag to skip the blocker check and to proceed with the upgrade.`\n    );\n\n    return true;\n  }\n\n  return false;\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/codemod.ts",
    "content": "import os from 'node:os';\n\nimport { formatFileContent } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { promises as fs } from 'fs';\nimport picocolors from 'picocolors';\n// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\n\nexport const maxConcurrentTasks = Math.max(1, os.cpus().length - 1);\n\nexport interface FileInfo {\n  path: string;\n  source: string;\n  [key: string]: any;\n}\n\n/**\n * Runs a codemod transformation on files matching the specified glob pattern.\n *\n * The function processes each file matching the glob pattern, applies the transform function, and\n * writes the transformed source back to the file if it has changed.\n *\n * @example\n *\n * ```\n * await runCodemod('*.stories.tsx', async (fileInfo) => {\n *   // Transform the file source return\n *   return fileInfo.source.replace(/foo/g, 'bar');\n * });\n * ```\n */\nexport async function runCodemod(\n  globPattern = '**/*.{stories,story}.{js,jsx,ts,tsx,mjs,mjsx,mts,mtsx}',\n  transform: (source: FileInfo, ...rest: any) => Promise<string>,\n  { dryRun = false, skipFormatting = false }: { dryRun?: boolean; skipFormatting?: boolean } = {}\n) {\n  let modifiedCount = 0;\n  let unmodifiedCount = 0;\n  let errorCount = 0;\n\n  // Dynamically import these packages because they are pure ESM modules\n  // eslint-disable-next-line depend/ban-dependencies\n  const { globby } = await import('globby');\n\n  // glob only supports forward slashes\n  const files = await globby(slash(globPattern), {\n    followSymbolicLinks: true,\n    ignore: ['**/node_modules/**', '**/dist/**', '**/storybook-static/**', '**/build/**'],\n  });\n\n  if (!files.length) {\n    logger.error(\n      `No files found for glob pattern \"${globPattern}\".\\nPlease try a different pattern.\\n`\n    );\n    // eslint-disable-next-line local-rules/no-uncategorized-errors\n    throw new Error('No files matched');\n  }\n\n  try {\n    const pLimit = (await import('p-limit')).default;\n\n    const limit = pLimit(maxConcurrentTasks);\n\n    await Promise.all(\n      files.map((file: string) =>\n        limit(async () => {\n          try {\n            let filePath = file;\n            try {\n              filePath = await fs.realpath(file);\n            } catch (err) {\n              // if anything goes wrong when resolving the file, fallback to original path as is set above\n            }\n\n            const source = await fs.readFile(filePath, 'utf-8');\n            const fileInfo: FileInfo = { path: filePath, source };\n            const transformedSource = await transform(fileInfo);\n\n            if (transformedSource !== source) {\n              if (!dryRun) {\n                const fileContent = skipFormatting\n                  ? transformedSource\n                  : await formatFileContent(file, transformedSource);\n                await fs.writeFile(file, fileContent, 'utf-8');\n              }\n              modifiedCount++;\n            } else {\n              unmodifiedCount++;\n            }\n          } catch (fileError) {\n            logger.error(`Error processing file ${file}: ${String(fileError)}`);\n            errorCount++;\n          }\n        })\n      )\n    );\n  } catch (error) {\n    logger.error(`Error applying transform: ${String(error)}`);\n    errorCount++;\n  }\n\n  logger.log(\n    `Summary: ${picocolors.green(`${modifiedCount} transformed`)}, ${picocolors.yellow(`${unmodifiedCount} unmodified`)}, ${picocolors.red(`${errorCount} errors`)}`\n  );\n\n  if (dryRun) {\n    logger.log(\n      picocolors.bold(\n        `This was a dry run. Run without --dry-run to apply the transformation to ${modifiedCount} files.`\n      )\n    );\n  }\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/__test__/main-config-with-essential-options.js",
    "content": "const config = {\n  stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    {\n      name: '@storybook/addon-essentials',\n      options: {\n        docs: false,\n        backgrounds: false,\n        measure: false,\n        outline: false,\n        grid: false,\n      },\n    },\n  ],\n  framework: {\n    name: '@storybook/angular',\n    options: {},\n  },\n};\nexport default config;\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/__test__/main-config-with-wrappers.js",
    "content": "import { dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst wrapForPnp = (packageName) =>\n  dirname(fileURLToPath(import.meta.resolve(`${packageName}/package.json`)));\n\nconst config = {\n  stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [wrapForPnp('@storybook/addon-links'), wrapForPnp('@storybook/addon-essentials')],\n  framework: {\n    name: wrapForPnp('@storybook/angular'),\n    options: {},\n  },\n  docs: {\n    autodocs: 'tag',\n  },\n};\nexport default config;\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/__test__/main-config-without-wrappers.js",
    "content": "const config = {\n  stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    {\n      name: '@chromatic-com/storybook',\n      options: {},\n    },\n    '@storybook/addon-vitest',\n  ],\n  framework: {\n    name: '@storybook/angular',\n    options: {},\n  },\n  docs: {\n    autodocs: 'tag',\n  },\n};\nexport default config;\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/addon-a11y-addon-test.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { getAddonNames } from 'storybook/internal/common';\n\nimport { existsSync, readFileSync, writeFileSync } from 'fs';\nimport path from 'path';\nimport { dedent } from 'ts-dedent';\n\nimport {\n  addonA11yAddonTest,\n  transformPreviewFile,\n  transformSetupFile,\n} from './addon-a11y-addon-test.ts';\n\nvi.mock('storybook/internal/common', async (importOriginal) => {\n  const mod = (await importOriginal()) as any;\n  return {\n    ...mod,\n    getAddonNames: vi.fn(),\n  };\n});\n\n// mock fs.existsSync\nvi.mock('fs', async (importOriginal) => {\n  const mod = (await importOriginal()) as any;\n  return {\n    ...mod,\n    existsSync: vi.fn(),\n    readFileSync: vi.fn(),\n    writeFileSync: vi.fn(),\n  };\n});\n\nvi.mock('picocolors', async (importOriginal) => {\n  const mod = (await importOriginal()) as any;\n  return {\n    ...mod,\n    default: {\n      gray: (s: string) => s,\n      green: (s: string) => s,\n      cyan: (s: string) => s,\n      magenta: (s: string) => s,\n      yellow: (s: string) => s,\n    },\n  };\n});\n\ndescribe('addonA11yAddonTest', () => {\n  const configDir = '/path/to/config';\n  const mainConfig = {} as any;\n\n  beforeEach(() => {\n    vi.clearAllMocks();\n  });\n\n  describe('check', () => {\n    it('should return null if a11y addon is not present', async () => {\n      vi.mocked(getAddonNames).mockReturnValue([]);\n      const result = await addonA11yAddonTest.check({ mainConfig, configDir } as any);\n      expect(result).toBeNull();\n    });\n\n    it('should return null if test addon is not present', async () => {\n      vi.mocked(getAddonNames).mockReturnValue(['@storybook/addon-a11y']);\n      const result = await addonA11yAddonTest.check({ mainConfig, configDir } as any);\n      expect(result).toBeNull();\n    });\n\n    it('should return null if configDir is not provided', async () => {\n      const result = await addonA11yAddonTest.check({ mainConfig, configDir: '' } as any);\n      expect(result).toBeNull();\n    });\n\n    it('should return null if provided framework is not supported', async () => {\n      vi.mocked(getAddonNames).mockReturnValue([\n        '@storybook/addon-a11y',\n        '@storybook/addon-vitest',\n      ]);\n      const result = await addonA11yAddonTest.check({\n        mainConfig: {\n          framework: '@storybook/angular',\n        },\n        configDir: '',\n      } as any);\n      expect(result).toBeNull();\n    });\n\n    it('should return null if vitest.setup file and preview file have the necessary transformations', async () => {\n      vi.mocked(getAddonNames).mockReturnValue([\n        '@storybook/addon-a11y',\n        '@storybook/addon-vitest',\n      ]);\n      vi.mocked(existsSync).mockReturnValue(true);\n      vi.mocked(readFileSync).mockImplementation((p) => {\n        if (p.toString().includes('vitest.setup')) {\n          return `\n            import * as a11yAddonAnnotations from \"@storybook/addon-a11y/preview\";\n            import { setProjectAnnotations } from 'storybook';\n            import * as projectAnnotations from './preview';\n\n            setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]);\n          `;\n        } else {\n          return `\n            export default {\n              parameters: {\n                a11y: {\n                  test: 'todo'\n                }\n              }\n            }\n          `;\n        }\n      });\n\n      const result = await addonA11yAddonTest.check({\n        mainConfig: {\n          framework: '@storybook/react-vite',\n        },\n        configDir,\n      } as any);\n      expect(result).toBeNull();\n    });\n\n    it('should return setupFile and transformedSetupCode if vitest.setup file exists', async () => {\n      vi.mocked(getAddonNames).mockReturnValue([\n        '@storybook/addon-a11y',\n        '@storybook/addon-vitest',\n      ]);\n      vi.mocked(existsSync).mockImplementation((p) => {\n        if (p.toString().includes('vitest.setup')) {\n          return true;\n        } else {\n          return false;\n        }\n      });\n      vi.mocked(readFileSync).mockImplementation((p) => {\n        if (p.toString().includes('vitest.setup')) {\n          return 'const annotations = setProjectAnnotations([]);';\n        } else {\n          return '';\n        }\n      });\n\n      const result = await addonA11yAddonTest.check({\n        mainConfig: {\n          framework: '@storybook/react-vite',\n        },\n        configDir,\n        hasCsfFactoryPreview: false,\n      } as any);\n      expect(result).toEqual({\n        setupFile: path.join(configDir, 'vitest.setup.js'),\n        previewFile: null,\n        transformedPreviewCode: null,\n        transformedSetupCode: expect.any(String),\n        skipPreviewTransformation: false,\n        skipVitestSetupTransformation: false,\n      });\n    });\n\n    it.skip('should return previewFile and transformedPreviewCode if preview file exists', async () => {\n      vi.mocked(getAddonNames).mockReturnValue([\n        '@storybook/addon-a11y',\n        '@storybook/addon-vitest',\n      ]);\n      vi.mocked(existsSync).mockImplementation((p) => {\n        if (p.toString().includes('preview')) {\n          return true;\n        } else {\n          return false;\n        }\n      });\n      vi.mocked(readFileSync).mockImplementation((p) => {\n        if (p.toString().includes('preview')) {\n          return 'export default {}';\n        } else {\n          return '';\n        }\n      });\n\n      const result = await addonA11yAddonTest.check({\n        mainConfig: {\n          framework: '@storybook/react-vite',\n        },\n        configDir,\n      } as any);\n      expect(result).toEqual({\n        setupFile: null,\n        previewFile: path.join(configDir, 'preview.js'),\n        transformedPreviewCode: expect.any(String),\n        transformedSetupCode: null,\n        skipPreviewTransformation: false,\n        skipVitestSetupTransformation: false,\n      });\n    });\n\n    it('should return setupFile and null transformedSetupCode if transformation fails', async () => {\n      vi.mocked(getAddonNames).mockReturnValue([\n        '@storybook/addon-a11y',\n        '@storybook/addon-vitest',\n      ]);\n      vi.mocked(existsSync).mockImplementation((p) => {\n        if (p.toString().includes('vitest.setup')) {\n          return true;\n        } else {\n          return false;\n        }\n      });\n      vi.mocked(readFileSync).mockImplementation((p) => {\n        if (p.toString().includes('vitest.setup')) {\n          throw new Error('Test error');\n        } else {\n          return '';\n        }\n      });\n\n      const result = await addonA11yAddonTest.check({\n        mainConfig: {\n          framework: '@storybook/sveltekit',\n        },\n        configDir,\n        hasCsfFactoryPreview: false,\n      } as any);\n      expect(result).toEqual({\n        setupFile: path.join(configDir, 'vitest.setup.js'),\n        previewFile: null,\n        transformedPreviewCode: null,\n        transformedSetupCode: null,\n        skipPreviewTransformation: false,\n        skipVitestSetupTransformation: false,\n      });\n    });\n\n    it('should return previewFile and null transformedPreviewCode if transformation fails', async () => {\n      vi.mocked(getAddonNames).mockReturnValue([\n        '@storybook/addon-a11y',\n        '@storybook/addon-vitest',\n      ]);\n      vi.mocked(existsSync).mockImplementation((p) => {\n        if (p.toString().includes('preview')) {\n          return true;\n        } else {\n          return false;\n        }\n      });\n      vi.mocked(readFileSync).mockImplementation((p) => {\n        if (p.toString().includes('preview')) {\n          throw new Error('Test error');\n        } else {\n          return '';\n        }\n      });\n\n      const result = await addonA11yAddonTest.check({\n        mainConfig: {\n          framework: '@storybook/sveltekit',\n        },\n        configDir,\n        hasCsfFactoryPreview: false,\n      } as any);\n      expect(result).toEqual({\n        setupFile: null,\n        previewFile: path.join(configDir, 'preview.js'),\n        transformedPreviewCode: null,\n        transformedSetupCode: null,\n        skipPreviewTransformation: false,\n        skipVitestSetupTransformation: false,\n      });\n    });\n\n    it('should return skipPreviewTransformation=true if preview file has the necessary change', async () => {\n      vi.mocked(getAddonNames).mockReturnValue([\n        '@storybook/addon-a11y',\n        '@storybook/addon-vitest',\n      ]);\n      vi.mocked(existsSync).mockReturnValue(true);\n      vi.mocked(readFileSync).mockImplementation((p) => {\n        if (p.toString().includes('vitest.setup')) {\n          return `\n            import { setProjectAnnotations } from 'storybook';\n            import * as projectAnnotations from './preview';\n\n            setProjectAnnotations([projectAnnotations]);\n          `;\n        } else {\n          return `\n            export default {\n              parameters: {\n                a11y: {\n                  test: 'todo'\n                }\n              }\n            }\n          `;\n        }\n      });\n\n      const result = await addonA11yAddonTest.check({\n        mainConfig: {\n          framework: '@storybook/sveltekit',\n        },\n        configDir,\n      } as any);\n      expect(result).toEqual({\n        setupFile: path.join(configDir, 'vitest.setup.js'),\n        previewFile: path.join(configDir, 'preview.js'),\n        transformedPreviewCode: null,\n        transformedSetupCode: expect.any(String),\n        skipPreviewTransformation: true,\n        skipVitestSetupTransformation: false,\n      });\n    });\n\n    it('should return skipVitestSetupTransformation=true if setup file has the necessary change', async () => {\n      vi.mocked(getAddonNames).mockReturnValue([\n        '@storybook/addon-a11y',\n        '@storybook/addon-vitest',\n      ]);\n      vi.mocked(existsSync).mockReturnValue(true);\n      vi.mocked(readFileSync).mockImplementation((p) => {\n        if (p.toString().includes('vitest.setup')) {\n          return `\n            import * as a11yAddonAnnotations from \"@storybook/addon-a11y/preview\";\n            import { setProjectAnnotations } from 'storybook';\n            import * as projectAnnotations from './preview';\n\n            setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]);\n          `;\n        } else {\n          return `\n            export default {\n              tags: [],\n            }\n          `;\n        }\n      });\n\n      const result = await addonA11yAddonTest.check({\n        mainConfig: {\n          framework: '@storybook/sveltekit',\n        },\n        configDir,\n      } as any);\n      expect(result).toEqual({\n        setupFile: path.join(configDir, 'vitest.setup.js'),\n        previewFile: path.join(configDir, 'preview.js'),\n        transformedPreviewCode: expect.any(String),\n        transformedSetupCode: null,\n        skipPreviewTransformation: false,\n        skipVitestSetupTransformation: true,\n      });\n    });\n\n    it('should return skipVitestSetupTransformation=true if hasCsfFactoryPreview is true', async () => {\n      vi.mocked(getAddonNames).mockReturnValue([\n        '@storybook/addon-a11y',\n        '@storybook/addon-vitest',\n      ]);\n      vi.mocked(existsSync).mockImplementation((p) => {\n        if (p.toString().includes('vitest.setup') || p.toString().includes('preview.js')) {\n          return true;\n        } else {\n          return false;\n        }\n      });\n      vi.mocked(readFileSync).mockImplementation((p) => {\n        if (p.toString().includes('vitest.setup')) {\n          return 'const annotations = setProjectAnnotations([]);';\n        } else {\n          return '';\n        }\n      });\n\n      const result = await addonA11yAddonTest.check({\n        mainConfig: {\n          framework: '@storybook/react-vite',\n        },\n        configDir,\n        hasCsfFactoryPreview: true,\n      } as any);\n      expect(result).toEqual({\n        setupFile: path.join(configDir, 'vitest.setup.js'),\n        previewFile: path.join(configDir, 'preview.js'),\n        transformedPreviewCode: expect.any(String),\n        transformedSetupCode: null,\n        skipPreviewTransformation: false,\n        skipVitestSetupTransformation: true,\n      });\n    });\n  });\n\n  describe('run', () => {\n    it('should write transformed setup code to file', async () => {\n      const setupFile = '/path/to/vitest.setup.ts';\n      const transformedSetupCode = 'transformed code';\n\n      await addonA11yAddonTest.run?.({\n        result: {\n          setupFile,\n          transformedSetupCode,\n          previewFile: null,\n          transformedPreviewCode: null,\n          skipVitestSetupTransformation: false,\n          skipPreviewTransformation: true,\n        },\n      } as any);\n\n      expect(writeFileSync).toHaveBeenCalledWith(setupFile, transformedSetupCode, 'utf8');\n    });\n\n    it('should write transformed preview code to file', async () => {\n      const previewFile = '/path/to/preview.ts';\n      const transformedPreviewCode = 'transformed code';\n\n      await addonA11yAddonTest.run?.({\n        result: {\n          setupFile: null,\n          transformedSetupCode: null,\n          previewFile: previewFile,\n          transformedPreviewCode: transformedPreviewCode,\n          skipVitestSetupTransformation: true,\n          skipPreviewTransformation: false,\n        },\n      } as any);\n\n      expect(writeFileSync).toHaveBeenCalledWith(previewFile, transformedPreviewCode, 'utf8');\n    });\n\n    it('should not write to file if setupFile or transformedSetupCode is null', async () => {\n      await addonA11yAddonTest.run?.({\n        result: {\n          setupFile: null,\n          transformedSetupCode: null,\n          previewFile: null,\n          transformedPreviewCode: null,\n          skipVitestSetupTransformation: true,\n          skipPreviewTransformation: true,\n        },\n      } as any);\n\n      expect(writeFileSync).not.toHaveBeenCalled();\n    });\n\n    it('should throw with instructions when skipVitestSetupTransformation is false and transformedSetupCode is null', async () => {\n      await expect(\n        addonA11yAddonTest.run?.({\n          result: {\n            setupFile: 'vitest.setup.ts',\n            transformedSetupCode: null,\n            previewFile: null,\n            transformedPreviewCode: null,\n            skipPreviewTransformation: true,\n            skipVitestSetupTransformation: false,\n          },\n        } as any)\n      ).rejects.toMatchInlineSnapshot(\n        `[Error: The addon-a11y-addon-test automigration couldn't make the changes but here are instructions for doing them yourself:\n1) We couldn't find or automatically update .storybook/vitest.setup.<ts|js> in your project to smoothly set up project annotations from @storybook/addon-a11y. \nPlease manually update your vitest.setup.ts file to include the following:\n\n...   \n+ import * as a11yAddonAnnotations from \"@storybook/addon-a11y/preview\";\n\nsetProjectAnnotations([\n  ...\n+ a11yAddonAnnotations,\n]);]`\n      );\n    });\n\n    it('should throw with instructions when skipPreviewTransformation is false and transformedPreviewCode is null', async () => {\n      await expect(\n        addonA11yAddonTest.run?.({\n          result: {\n            setupFile: null,\n            transformedSetupCode: null,\n            previewFile: 'preview.js',\n            transformedPreviewCode: null,\n            skipPreviewTransformation: false,\n            skipVitestSetupTransformation: true,\n          },\n        } as any)\n      ).rejects\n        .toMatchInlineSnapshot(`[Error: The addon-a11y-addon-test automigration couldn't make the changes but here are instructions for doing them yourself:\n1) We couldn't find or automatically update your .storybook/preview.<ts|js> in your project to smoothly set up parameters.a11y.test from @storybook/addon-a11y. Please manually update your .storybook/preview.<ts|js> file to include the following:\n\nexport default {\n  ...\n  parameters: {\n+   a11y: {\n+      test: \"todo\"\n+   }\n  }\n}]`);\n    });\n\n    it('should throw with full instructions when skipPreviewTransformation is false and both transformedSetupCode and transformedPreviewCode are null', async () => {\n      await expect(\n        addonA11yAddonTest.run?.({\n          result: {\n            setupFile: 'vitest.setup.ts',\n            transformedSetupCode: null,\n            previewFile: 'preview.js',\n            transformedPreviewCode: null,\n            skipPreviewTransformation: false,\n            skipVitestSetupTransformation: false,\n          },\n        } as any)\n      ).rejects\n        .toMatchInlineSnapshot(`[Error: The addon-a11y-addon-test automigration couldn't make the changes but here are instructions for doing them yourself:\n1) We couldn't find or automatically update .storybook/vitest.setup.<ts|js> in your project to smoothly set up project annotations from @storybook/addon-a11y. \nPlease manually update your vitest.setup.ts file to include the following:\n\n...   \n+ import * as a11yAddonAnnotations from \"@storybook/addon-a11y/preview\";\n\nsetProjectAnnotations([\n  ...\n+ a11yAddonAnnotations,\n]);\n2) We couldn't find or automatically update your .storybook/preview.<ts|js> in your project to smoothly set up parameters.a11y.test from @storybook/addon-a11y. Please manually update your .storybook/preview.<ts|js> file to include the following:\n\nexport default {\n  ...\n  parameters: {\n+   a11y: {\n+      test: \"todo\"\n+   }\n  }\n}]`);\n    });\n  });\n\n  describe('transformSetupFile', async () => {\n    it('should throw', async () => {\n      const setupFile = '/path/to/vitest.setup.ts';\n      const source = dedent`\n        import { setProjectAnnotations } from 'storybook';\n      `;\n\n      vi.mocked(readFileSync).mockReturnValue(source);\n\n      expect(() => transformSetupFile(setupFile)).toThrow();\n    });\n\n    it('should transform setup file correctly - 1', () => {\n      const setupFile = '/path/to/vitest.setup.ts';\n      const source = dedent`\n        import { setProjectAnnotations } from 'storybook';\n        import * as projectAnnotations from './preview';\n\n        setProjectAnnotations([projectAnnotations]);\n      `;\n      vi.mocked(readFileSync).mockReturnValue(source);\n\n      const s = readFileSync(setupFile, 'utf8');\n      const transformedCode = transformSetupFile(s);\n      expect(transformedCode).toMatchInlineSnapshot(`\n        \"import * as a11yAddonAnnotations from \"@storybook/addon-a11y/preview\";\n        import { setProjectAnnotations } from 'storybook';\n        import * as projectAnnotations from './preview';\n\n        setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]);\"\n      `);\n    });\n\n    it('should transform setup file correctly - 2 (different format)', () => {\n      const setupFile = '/path/to/vitest.setup.ts';\n      const source = dedent`\n        import { setProjectAnnotations } from 'storybook';\n        import * as projectAnnotations from './preview';\n\n        setProjectAnnotations([\n          projectAnnotations\n        ]);\n      `;\n      vi.mocked(readFileSync).mockReturnValue(source);\n\n      const s = readFileSync(setupFile, 'utf8');\n      const transformedCode = transformSetupFile(s);\n      expect(transformedCode).toMatchInlineSnapshot(`\n        \"import * as a11yAddonAnnotations from \"@storybook/addon-a11y/preview\";\n        import { setProjectAnnotations } from 'storybook';\n        import * as projectAnnotations from './preview';\n\n        setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]);\"\n      `);\n    });\n\n    it('should transform setup file correctly - project annotation is not an array', () => {\n      const setupFile = '/path/to/vitest.setup.ts';\n      const source = dedent`\n        import { setProjectAnnotations } from 'storybook';\n        import * as projectAnnotations from './preview';\n\n        setProjectAnnotations(projectAnnotations);\n      `;\n      vi.mocked(readFileSync).mockReturnValue(source);\n\n      const s = readFileSync(setupFile, 'utf8');\n      const transformedCode = transformSetupFile(s);\n      expect(transformedCode).toMatchInlineSnapshot(dedent`\n        \"import * as a11yAddonAnnotations from \"@storybook/addon-a11y/preview\";\n        import { setProjectAnnotations } from 'storybook';\n        import * as projectAnnotations from './preview';\n\n        setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]);\"\n      `);\n    });\n  });\n\n  describe('transformPreviewFile', () => {\n    it('should add a new parameter property if it does not exist', async () => {\n      const source = dedent`\n        import type { Preview } from '@storybook/react';\n\n        const preview: Preview = {};\n\n        export default preview;\n      `;\n\n      const transformed = await transformPreviewFile(source, process.cwd());\n\n      expect(transformed).toMatchInlineSnapshot(`\n        \"import type { Preview } from '@storybook/react';\n\n        const preview: Preview = {\n          parameters: {\n            a11y: {\n              // 'todo' - show a11y violations in the test UI only\n              // 'error' - fail CI on a11y violations\n              // 'off' - skip a11y checks entirely\n              test: 'todo'\n            }\n          }\n        };\n\n        export default preview;\"\n      `);\n    });\n\n    it('should add a new parameter property if it does not exist and a default export does not exist', async () => {\n      const source = dedent``;\n\n      const transformed = await transformPreviewFile(source, process.cwd());\n\n      expect(transformed).toMatchInlineSnapshot(`\n        \"export const parameters = {\n          a11y: {\n            // 'todo' - show a11y violations in the test UI only\n            // 'error' - fail CI on a11y violations\n            // 'off' - skip a11y checks entirely\n            test: \"todo\"\n          }\n        };\"\n        `);\n    });\n\n    it('should extend the existing parameters property', async () => {\n      const source = dedent`\n        export const parameters = {\n          controls: {\n            matchers: {\n              color: /(background|color)$/i,\n              date: /Date$/i,\n            },\n          },\n        }\n      `;\n\n      const transformed = await transformPreviewFile(source, process.cwd());\n\n      expect(transformed).toMatchInlineSnapshot(`\n        \"export const parameters = {\n          controls: {\n            matchers: {\n              color: /(background|color)$/i,\n              date: /Date$/i,\n            },\n          },\n\n          a11y: {\n            // 'todo' - show a11y violations in the test UI only\n            // 'error' - fail CI on a11y violations\n            // 'off' - skip a11y checks entirely\n            test: \"todo\"\n          }\n        }\"\n        `);\n    });\n\n    it('should not add the test parameter if it already exists', async () => {\n      const source = dedent`\n        import type { Preview } from \"@storybook/react\";\n\n        const preview: Preview = {\n          parameters: {\n            a11y: {\n              test: \"off\"\n            }\n          },\n        };\n\n        export default preview;\n      `;\n\n      const transformed = await transformPreviewFile(source, process.cwd());\n\n      expect(transformed).toMatchInlineSnapshot(`\n        \"import type { Preview } from \"@storybook/react\";\n\n        const preview: Preview = {\n          parameters: {\n            a11y: {\n              test: \"off\"\n            }\n          },\n        };\n\n        export default preview;\"\n      `);\n    });\n\n    it('should handle the default export without type annotations', async () => {\n      const source = dedent`\n        export default {};\n      `;\n\n      const transformed = await transformPreviewFile(source, process.cwd());\n\n      expect(transformed).toMatchInlineSnapshot(`\n        \"export default {\n          parameters: {\n            a11y: {\n              // 'todo' - show a11y violations in the test UI only\n              // 'error' - fail CI on a11y violations\n              // 'off' - skip a11y checks entirely\n              test: \"todo\"\n            }\n          }\n        };\"\n      `);\n    });\n\n    it('should handle const parameters with preview object', async () => {\n      const source = dedent`\n        const parameters = {};\n        const preview = {\n          parameters,\n        };\n        export default preview;\n      `;\n\n      const transformed = await transformPreviewFile(source, process.cwd());\n\n      expect(transformed).toMatchInlineSnapshot(`\n        \"const parameters = {\n          a11y: {\n            // 'todo' - show a11y violations in the test UI only\n            // 'error' - fail CI on a11y violations\n            // 'off' - skip a11y checks entirely\n            test: \"todo\"\n          }\n        };\n        const preview = {\n          parameters,\n        };\n        export default preview;\"\n      `);\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/addon-a11y-addon-test.ts",
    "content": "import { formatFileContent, frameworkPackages, getAddonNames } from 'storybook/internal/common';\nimport { formatConfig, loadConfig } from 'storybook/internal/csf-tools';\n\nimport { existsSync, readFileSync, writeFileSync } from 'fs';\nimport jscodeshift from 'jscodeshift';\nimport path from 'path';\nimport picocolors from 'picocolors';\nimport { dedent } from 'ts-dedent';\n\n// Relative path import to avoid dependency to storybook/test\nimport { getFrameworkPackageName } from '../helpers/mainConfigFile.ts';\nimport type { Fix } from '../types.ts';\n\nexport const fileExtensions = [\n  '.js',\n  '.ts',\n  '.cts',\n  '.mts',\n  '.cjs',\n  '.mjs',\n  '.jsx',\n  '.tsx',\n] as const;\n\ninterface AddonA11yAddonTestOptions {\n  setupFile: string | null;\n  previewFile: string | null;\n  transformedSetupCode: string | null;\n  transformedPreviewCode: string | null;\n  skipVitestSetupTransformation: boolean;\n  skipPreviewTransformation: boolean;\n}\n\n/**\n * If addon-a11y and addon-vitest are already installed, we need to update\n *\n * - `.storybook/vitest.setup.<ts|js>` to set up project annotations from addon-a11y.\n * - `.storybook/preview.<ts|js>` to set up tags.\n * - If we can't transform the files automatically, we'll prompt the user to do it manually.\n */\nexport const addonA11yAddonTest: Fix<AddonA11yAddonTestOptions> = {\n  id: 'addon-a11y-addon-test',\n  link: 'https://storybook.js.org/docs/writing-tests/accessibility-testing#with-the-vitest-addon',\n\n  promptType: 'auto',\n\n  async check({ mainConfig, configDir, hasCsfFactoryPreview }) {\n    const addons = getAddonNames(mainConfig);\n\n    const frameworkPackageName = getFrameworkPackageName(mainConfig);\n\n    const hasA11yAddon = !!addons.find((addon) => addon.includes('@storybook/addon-a11y'));\n    const hasTestAddon = !!addons.find((addon) => addon.includes('@storybook/addon-vitest'));\n\n    if (\n      !Object.keys(frameworkPackages).find((framework) => frameworkPackageName?.includes(framework))\n    ) {\n      return null;\n    }\n\n    if (!hasA11yAddon || !hasTestAddon || !configDir) {\n      return null;\n    }\n\n    const vitestSetupFile =\n      fileExtensions\n        .map((ext) => path.join(configDir, `vitest.setup${ext}`))\n        .find((filePath) => existsSync(filePath)) ?? null;\n\n    const previewFile =\n      fileExtensions\n        .map((ext) => path.join(configDir, `preview${ext}`))\n        .find((filePath) => existsSync(filePath)) ?? null;\n\n    let skipVitestSetupTransformation = hasCsfFactoryPreview;\n    let skipPreviewTransformation = false;\n\n    if (vitestSetupFile && previewFile) {\n      const vitestSetupSource = readFileSync(vitestSetupFile, 'utf8');\n      const previewSetupSource = readFileSync(previewFile, 'utf8');\n\n      skipVitestSetupTransformation ||= vitestSetupSource.includes('@storybook/addon-a11y');\n      skipPreviewTransformation ||= !shouldPreviewFileBeTransformed(previewSetupSource);\n\n      if (skipVitestSetupTransformation && skipPreviewTransformation) {\n        return null;\n      }\n    }\n\n    const getTransformedSetupCode = () => {\n      if (!vitestSetupFile || skipVitestSetupTransformation) {\n        return null;\n      }\n\n      try {\n        const vitestSetupSource = readFileSync(vitestSetupFile, 'utf8');\n        return transformSetupFile(vitestSetupSource);\n      } catch (e) {\n        return null;\n      }\n    };\n\n    const getTransformedPreviewCode = () => {\n      if (!previewFile || skipPreviewTransformation) {\n        return null;\n      }\n\n      try {\n        const previewSetupSource = readFileSync(previewFile, 'utf8');\n        return transformPreviewFile(previewSetupSource, previewFile);\n      } catch (e) {\n        return null;\n      }\n    };\n\n    return {\n      setupFile: vitestSetupFile,\n      previewFile: previewFile,\n      transformedSetupCode: getTransformedSetupCode(),\n      transformedPreviewCode: await getTransformedPreviewCode(),\n      skipVitestSetupTransformation,\n      skipPreviewTransformation,\n    };\n  },\n\n  prompt() {\n    return 'We have detected that you have @storybook/addon-a11y and @storybook/addon-vitest installed. The automigration will configure both for the new testing experience';\n  },\n\n  async run({ result }) {\n    let counter = 1;\n\n    const {\n      transformedSetupCode,\n      skipPreviewTransformation,\n      skipVitestSetupTransformation,\n      setupFile,\n      previewFile,\n      transformedPreviewCode,\n    } = result;\n\n    const errorMessage: string[] = [];\n    if (!skipVitestSetupTransformation) {\n      if (transformedSetupCode === null && setupFile) {\n        errorMessage.push(dedent`\n          ${counter++}) We couldn't find or automatically update ${picocolors.cyan(`.storybook/vitest.setup.<ts|js>`)} in your project to smoothly set up project annotations from ${picocolors.magenta(`@storybook/addon-a11y`)}. \n          Please manually update your ${picocolors.cyan(`vitest.setup.ts`)} file to include the following:\n\n          ${picocolors.gray('...')}   \n          ${picocolors.green('+ import * as a11yAddonAnnotations from \"@storybook/addon-a11y/preview\";')}\n\n          ${picocolors.gray('setProjectAnnotations([')}\n          ${picocolors.gray('  ...')}\n          ${picocolors.green('+ a11yAddonAnnotations,')}\n          ${picocolors.gray(']);')}\n        `);\n      }\n    }\n\n    if (!skipPreviewTransformation) {\n      if (transformedPreviewCode === null) {\n        errorMessage.push(dedent`\n          ${counter++}) We couldn't find or automatically update your .storybook/preview.<ts|js> in your project to smoothly set up ${picocolors.cyan('parameters.a11y.test')} from @storybook/addon-a11y. Please manually update your .storybook/preview.<ts|js> file to include the following:\n\n          ${picocolors.gray('export default {')}\n          ${picocolors.gray('  ...')}\n          ${picocolors.gray('  parameters: {')}\n          ${picocolors.green('+   a11y: {')}\n          ${picocolors.gray('+      test: \"todo\"')}\n          ${picocolors.green('+   }')}\n          ${picocolors.gray('  }')}\n          ${picocolors.gray('}')}\n        `);\n      }\n    }\n\n    if (errorMessage.length > 0) {\n      // eslint-disable-next-line local-rules/no-uncategorized-errors\n      throw new Error(\n        dedent`The ${this.id} automigration couldn't make the changes but here are instructions for doing them yourself:\\n${errorMessage.join('\\n')}`\n      );\n    }\n\n    if (transformedSetupCode && setupFile) {\n      writeFileSync(setupFile, transformedSetupCode, 'utf8');\n    }\n\n    if (transformedPreviewCode && previewFile) {\n      writeFileSync(previewFile, transformedPreviewCode, 'utf8');\n    }\n  },\n};\n\nexport function transformSetupFile(source: string) {\n  const j = jscodeshift.withParser('ts');\n\n  const root = j(source);\n\n  // Import a11yAddonAnnotations\n  const importDeclaration = j.importDeclaration(\n    [j.importNamespaceSpecifier(j.identifier('a11yAddonAnnotations'))],\n    j.literal('@storybook/addon-a11y/preview')\n  );\n\n  // Find the setProjectAnnotations call\n  const setProjectAnnotationsCall = root.find(j.CallExpression, {\n    callee: {\n      type: 'Identifier',\n      name: 'setProjectAnnotations',\n    },\n  });\n\n  if (setProjectAnnotationsCall.length === 0) {\n    throw new Error('Could not find setProjectAnnotations call in vitest.setup file');\n  }\n\n  // Add a11yAddonAnnotations to the annotations array or create a new array if argument is a string\n  setProjectAnnotationsCall.forEach((p) => {\n    if (p.value.arguments.length === 1 && p.value.arguments[0].type === 'ArrayExpression') {\n      p.value.arguments[0].elements.unshift(j.identifier('a11yAddonAnnotations'));\n    } else if (p.value.arguments.length === 1 && p.value.arguments[0].type === 'Identifier') {\n      const arg = p.value.arguments[0];\n      p.value.arguments[0] = j.arrayExpression([j.identifier('a11yAddonAnnotations'), arg]);\n    }\n  });\n\n  // Add the import declaration at the top\n  root.get().node.program.body.unshift(importDeclaration);\n\n  return root.toSource();\n}\n\nexport function transformPreviewFile(source: string, filePath: string) {\n  if (!shouldPreviewFileBeTransformed(source)) {\n    return source;\n  }\n\n  const previewConfig = loadConfig(source).parse();\n\n  previewConfig.setFieldValue(['parameters', 'a11y', 'test'], 'todo');\n\n  const formattedPreviewConfig = formatConfig(previewConfig);\n  const lines = formattedPreviewConfig.split('\\n');\n\n  // Find the line with the \"parameters.a11y.test\" property\n  const parametersLineIndex = lines.findIndex(\n    (line) => line.includes('test: \"todo\"') || line.includes(\"test: 'todo'\")\n  );\n  if (parametersLineIndex === -1) {\n    return formattedPreviewConfig;\n  }\n\n  // Determine the indentation level of the \"tags\" property\n  const parametersLine = lines[parametersLineIndex];\n  const indentation = parametersLine?.match(/^\\s*/)?.[0];\n\n  // Add the comment with the same indentation level\n  const comment = `${indentation}// 'todo' - show a11y violations in the test UI only\\n${indentation}// 'error' - fail CI on a11y violations\\n${indentation}// 'off' - skip a11y checks entirely`;\n  lines.splice(parametersLineIndex, 0, comment);\n\n  return formatFileContent(filePath, lines.join('\\n'));\n}\n\nexport function shouldPreviewFileBeTransformed(source: string) {\n  const previewConfig = loadConfig(source).parse();\n  const parametersA11yTest = previewConfig.getFieldNode(['parameters', 'a11y', 'test']);\n\n  if (parametersA11yTest) {\n    return false;\n  }\n\n  return true;\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/addon-a11y-parameters.test.ts",
    "content": "/* eslint-disable depend/ban-dependencies */\nimport { afterEach, describe, expect, it, vi } from 'vitest';\n\nimport { addonA11yParameters } from './addon-a11y-parameters.ts';\n\n// Mock dependencies\nvi.mock('node:fs/promises', () => ({\n  readFile: vi.fn(),\n}));\n\nvi.mock('globby', () => ({\n  globby: vi.fn(),\n}));\n\nvi.mock('storybook/internal/common', () => ({\n  commonGlobOptions: vi.fn(),\n  getProjectRoot: () => '/mock/project/root',\n}));\n\nvi.mock('storybook/internal/csf-tools', () => ({\n  writeConfig: vi.fn(),\n  writeCsf: vi.fn(),\n}));\n\ndescribe('addon-a11y-parameters', () => {\n  const mockPreviewFile = '/mock/project/root/.storybook/preview.ts';\n  const mockStoryFiles = [\n    '/mock/project/root/src/components/Button.stories.ts',\n    '/mock/project/root/src/components/Input.stories.ts',\n  ];\n\n  afterEach(() => {\n    vi.clearAllMocks();\n  });\n\n  describe('check', () => {\n    it('should return null if a11y addon is not installed', async () => {\n      const result = await addonA11yParameters.check({\n        mainConfig: { addons: [] },\n        previewConfigPath: mockPreviewFile,\n        storiesPaths: [],\n      } as any);\n\n      expect(result).toBeNull();\n    });\n\n    it('should return null if no relevant files are found', async () => {\n      const { globby } = await import('globby');\n      (globby as unknown as ReturnType<typeof vi.fn>).mockResolvedValue([]);\n      const { readFile } = await import('node:fs/promises');\n      (readFile as unknown as ReturnType<typeof vi.fn>).mockResolvedValue('');\n\n      const result = await addonA11yParameters.check({\n        mainConfig: { addons: ['@storybook/addon-a11y'] },\n        previewConfigPath: mockPreviewFile,\n        storiesPaths: mockStoryFiles,\n      } as any);\n\n      expect(result).toBeNull();\n    });\n\n    it('should return files that need to be updated', async () => {\n      const { globby } = await import('globby');\n      (globby as unknown as ReturnType<typeof vi.fn>).mockResolvedValue(mockStoryFiles);\n      const { readFile } = await import('node:fs/promises');\n      (readFile as unknown as ReturnType<typeof vi.fn>)\n        .mockResolvedValueOnce('parameters: { a11y: { element: \"#root\" } }')\n        .mockResolvedValueOnce('parameters: { a11y: { element: \"#app\" } }')\n        .mockResolvedValueOnce('parameters: { a11y: { element: \"#main\" } }');\n\n      const result = await addonA11yParameters.check({\n        mainConfig: { addons: ['@storybook/addon-a11y'] },\n        previewConfigPath: mockPreviewFile,\n        storiesPaths: mockStoryFiles,\n      } as any);\n\n      expect(result).toEqual({\n        storyFilesToUpdate: [mockStoryFiles[0], mockStoryFiles[1]],\n        previewFileToUpdate: mockPreviewFile,\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/addon-a11y-parameters.ts",
    "content": "import { readFile } from 'node:fs/promises';\n\nimport { writeConfig, writeCsf } from 'storybook/internal/csf-tools';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport picocolors from 'picocolors';\nimport { dedent } from 'ts-dedent';\n\nimport {\n  transformPreviewA11yParameters,\n  transformStoryA11yParameters,\n} from '../helpers/addon-a11y-parameters.ts';\nimport type { Fix, RunOptions } from '../types.ts';\n\ninterface A11yOptions {\n  storyFilesToUpdate: string[];\n  previewFileToUpdate: string | undefined;\n}\n\nexport const addonA11yParameters: Fix<A11yOptions> = {\n  id: 'addon-a11y-parameters',\n  link: 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#a11y-addon-replace-element-parameter-with-context-parameter',\n\n  check: async ({ mainConfig, previewConfigPath, storiesPaths }) => {\n    // Check if the a11y addon is installed\n    const hasA11yAddon = mainConfig.addons?.some((addon) =>\n      typeof addon === 'string'\n        ? addon === '@storybook/addon-a11y'\n        : addon.name === '@storybook/addon-a11y'\n    );\n\n    if (!hasA11yAddon) {\n      return null;\n    }\n\n    const maybeHasA11yParameter = (content: string) =>\n      content.includes('a11y:') && content.includes('element:');\n\n    // Filter files that contain both 'a11y' and 'element' in their content\n    const storyFilesWithA11y = (\n      await Promise.all(\n        storiesPaths.map(async (file) => {\n          const content = await readFile(file, 'utf-8');\n          return maybeHasA11yParameter(content) ? file : null;\n        })\n      )\n    ).filter((file): file is string => file !== null);\n\n    let hasA11yConfigInPreview = false;\n\n    if (previewConfigPath) {\n      const content = await readFile(previewConfigPath, 'utf-8');\n      hasA11yConfigInPreview = maybeHasA11yParameter(content);\n    }\n\n    if (storyFilesWithA11y.length === 0 && !hasA11yConfigInPreview) {\n      return null;\n    }\n\n    return {\n      storyFilesToUpdate: storyFilesWithA11y,\n      previewFileToUpdate: hasA11yConfigInPreview ? previewConfigPath : undefined,\n    };\n  },\n\n  prompt: () => {\n    return dedent`\n      The a11y addon has replaced ${picocolors.yellow('parameters.a11y.element')} with ${picocolors.yellow('parameters.a11y.context')} for more flexible accessibility check scoping.\n    `;\n  },\n\n  run: async (options: RunOptions<A11yOptions>) => {\n    const { result, dryRun = false } = options;\n    const { storyFilesToUpdate, previewFileToUpdate } = result;\n    const errors: Array<{ file: string; error: Error }> = [];\n\n    if (previewFileToUpdate) {\n      const content = await readFile(previewFileToUpdate, 'utf-8');\n      const code = transformPreviewA11yParameters(content);\n\n      if (code) {\n        if (!dryRun) {\n          try {\n            await writeConfig(code, previewFileToUpdate);\n          } catch (error) {\n            errors.push({ file: previewFileToUpdate, error: error as Error });\n          }\n        } else {\n          logger.log(`Would have updated ${code.fileName}`);\n        }\n      }\n    }\n\n    const { default: pLimit } = await import('p-limit');\n    const limit = pLimit(10);\n\n    await Promise.all(\n      storyFilesToUpdate.map((file) =>\n        limit(async () => {\n          try {\n            const content = await readFile(file, 'utf-8');\n            const code = transformStoryA11yParameters(content);\n\n            if (code) {\n              if (!dryRun) {\n                await writeCsf(code, file);\n              } else {\n                logger.log(`Would have updated ${file}`);\n              }\n            }\n          } catch (error) {\n            errors.push({ file, error: error as Error });\n          }\n        })\n      )\n    );\n\n    if (errors.length > 0) {\n      // eslint-disable-next-line local-rules/no-uncategorized-errors\n      throw new Error(\n        `Failed to process ${errors.length} files:\\n${errors\n          .map(({ file, error }) => `- ${file}: ${error.message}`)\n          .join('\\n')}`\n      );\n    }\n  },\n} as const;\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/addon-experimental-test.test.ts",
    "content": "import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { JsPackageManager } from 'storybook/internal/common';\nimport type { PackageJson, StorybookConfig } from 'storybook/internal/types';\n\nimport { readFileSync, writeFileSync } from 'fs';\n\nimport { addonExperimentalTest } from './addon-experimental-test.ts';\n\n// Mock filesystem and globby\nvi.mock('fs', async (importOriginal) => {\n  const mod = (await importOriginal()) as any;\n  return {\n    ...mod,\n    readFileSync: vi.fn(),\n    writeFileSync: vi.fn(),\n  };\n});\n\n// mock picocolors yellow and cyan\nvi.mock('picocolors', () => {\n  return {\n    default: {\n      cyan: (str: string) => str,\n    },\n  };\n});\n\n// Mock the dynamic import of globby\nvi.mock('globby', () => ({\n  globbySync: vi.fn(),\n}));\n\nvi.mock('../../util', () => ({\n  findFilesUp: vi.fn(),\n}));\n\nconst mockFiles: Record<string, string> = {\n  '.storybook/test-setup.ts': `\n    import { setup } from '@storybook/experimental-addon-test';\n    // Setup code here\n  `,\n  '.storybook/main.ts': `\n    import type { StorybookConfig } from '@storybook/react-vite';\n\n    const config: StorybookConfig = {\n      addons: ['@storybook/experimental-addon-test'],\n    };\n\n    export default config;\n  `,\n  'vitest.setup.ts': `\n    import { setup } from '@storybook/experimental-addon-test';\n    import * as a11yAddonAnnotations from \"@storybook/addon-a11y/preview\";\n    import { beforeAll } from 'vitest'\n    import { setProjectAnnotations } from '@storybook/nextjs-vite'\n    import * as projectAnnotations from './preview'\n    \n    const project = setProjectAnnotations([a11yAddonAnnotations, projectAnnotations])\n    \n    beforeAll(project.beforeAll)\n  `,\n  'vite.config.ts': `\n    import { defineConfig } from 'vite';\n    import { test } from '@storybook/experimental-addon-test';\n\n    export default defineConfig({\n      // Some config\n    });\n  `,\n};\n\nconst checkAddonExperimentalTest = async ({\n  packageManager = {},\n  mainConfig = {},\n  storybookVersion = '8.0.0',\n  files = Object.keys(mockFiles),\n}: {\n  packageManager?: Partial<JsPackageManager>;\n  mainConfig?: Partial<StorybookConfig>;\n  storybookVersion?: string;\n  files?: string[];\n}) => {\n  // Mock the findFilesUp function\n  const { findFilesUp } = await import('../../util.ts');\n  (findFilesUp as any).mockReturnValue(files);\n\n  return addonExperimentalTest.check({\n    packageManager: packageManager as any,\n    storybookVersion,\n    mainConfig: mainConfig as any,\n    storiesPaths: [],\n    hasCsfFactoryPreview: false,\n  });\n};\n\nconst packageManager = vi.mocked(JsPackageManager.prototype);\n\ndescribe('addon-experimental-test fix', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n    packageManager.getModulePackageJSON = vi.fn();\n    // @ts-expect-error Ignore readonly property\n    packageManager.primaryPackageJson = {\n      packageJson: { devDependencies: {}, dependencies: {} },\n      packageJsonPath: 'some/path',\n      operationDir: 'some/path',\n    };\n    packageManager.runPackageCommand = vi.fn();\n    packageManager.getAllDependencies = vi.fn();\n    packageManager.addDependencies = vi.fn();\n    packageManager.removeDependencies = vi.fn();\n\n    // @ts-expect-error Ignore\n    vi.mocked(readFileSync).mockImplementation((file: string) => {\n      if (mockFiles[file]) {\n        return mockFiles[file];\n      }\n      throw new Error(`File not found: ${file}`);\n    });\n  });\n\n  afterEach(() => {\n    vi.restoreAllMocks();\n  });\n\n  describe('check function', () => {\n    it('should return null if @storybook/experimental-addon-test is not installed', async () => {\n      const packageManager = {\n        isPackageInstalled: async () => false,\n      };\n      await expect(checkAddonExperimentalTest({ packageManager })).resolves.toBeNull();\n    });\n\n    it('should find files containing @storybook/experimental-addon-test', async () => {\n      const packageManager = {\n        isPackageInstalled: async (packageName: string) => {\n          return packageName === '@storybook/experimental-addon-test';\n        },\n      };\n\n      const result = await checkAddonExperimentalTest({ packageManager });\n      expect(result).toEqual({\n        matchingFiles: [\n          '.storybook/test-setup.ts',\n          '.storybook/main.ts',\n          'vitest.setup.ts',\n          'vite.config.ts',\n        ],\n      });\n    });\n  });\n\n  describe('run function', () => {\n    it('should replace @storybook/experimental-addon-test in files', async () => {\n      packageManager.getModulePackageJSON.mockImplementation(async (packageName: string) => {\n        if (packageName === '@storybook/experimental-addon-test') {\n          return {\n            version: '8.6.0',\n          };\n        }\n        if (packageName === 'storybook') {\n          return {\n            version: '9.0.0',\n          };\n        }\n        return null;\n      });\n\n      // @ts-expect-error Ignore readonly property\n      packageManager.primaryPackageJson = {\n        packageJson: {\n          dependencies: {},\n          devDependencies: {\n            '@storybook/experimental-addon-test': '8.6.0',\n          },\n        },\n        packageJsonPath: '/some/path',\n        operationDir: '/some/path',\n      };\n\n      const matchingFiles = ['.storybook/test-setup.ts', '.storybook/main.ts', 'vitest.setup.ts'];\n\n      await addonExperimentalTest.run?.({\n        result: {\n          matchingFiles,\n          hasPackageJsonDependency: true,\n        },\n        packageManager: packageManager as JsPackageManager,\n        dryRun: false,\n        storybookVersion: '9.0.0',\n      } as any);\n\n      // Check that each file was read and written with the replacement\n      expect(readFileSync).toHaveBeenCalledTimes(3);\n      expect(writeFileSync).toHaveBeenCalledTimes(3);\n\n      // Verify writeFileSync was called with replaced content\n      matchingFiles.forEach((file) => {\n        expect(writeFileSync).toHaveBeenCalledWith(\n          file,\n          expect.stringContaining('@storybook/addon-vitest'),\n          'utf-8'\n        );\n      });\n\n      expect(writeFileSync).toHaveBeenCalledWith(\n        'vitest.setup.ts',\n        `\n    import { setup } from '@storybook/addon-vitest';\n    import * as a11yAddonAnnotations from \"@storybook/addon-a11y/preview\";\n    import { beforeAll } from 'vitest'\n    import { setProjectAnnotations } from '@storybook/nextjs-vite'\n    import * as projectAnnotations from './preview'\n    \n    const project = setProjectAnnotations([a11yAddonAnnotations, projectAnnotations])\n  `,\n        'utf-8'\n      );\n\n      // Verify package dependencies were updated\n      expect(packageManager.removeDependencies).toHaveBeenCalledWith([\n        '@storybook/experimental-addon-test',\n      ]);\n\n      expect(packageManager.addDependencies).toHaveBeenCalledWith(\n        { type: 'devDependencies', skipInstall: true },\n        ['@storybook/addon-vitest@9.0.0']\n      );\n    });\n\n    it('should replace @storybook/experimental-addon-test in files (dependency)', async () => {\n      packageManager.getModulePackageJSON.mockImplementation(async (packageName: string) => {\n        if (packageName === '@storybook/experimental-addon-test') {\n          return {\n            version: '8.6.0',\n          };\n        }\n        if (packageName === 'storybook') {\n          return {\n            version: '9.0.0',\n          };\n        }\n        return null;\n      });\n\n      // @ts-expect-error Ignore readonly property\n      packageManager.primaryPackageJson = {\n        packageJson: {\n          dependencies: {\n            '@storybook/experimental-addon-test': '8.6.0',\n          },\n          devDependencies: {},\n        },\n        packageJsonPath: '/some/path',\n        operationDir: '/some/path',\n      };\n\n      const matchingFiles = ['.storybook/test-setup.ts', '.storybook/main.ts', 'vitest.setup.ts'];\n\n      await addonExperimentalTest.run?.({\n        result: {\n          matchingFiles,\n          hasPackageJsonDependency: true,\n        },\n        packageManager: packageManager as any,\n        dryRun: false,\n        storybookVersion: '9.0.0',\n      } as any);\n\n      expect(packageManager.addDependencies).toHaveBeenCalledWith(\n        { type: 'devDependencies', skipInstall: true },\n        ['@storybook/addon-vitest@9.0.0']\n      );\n    });\n\n    it('should not modify files or dependencies in dry run mode', async () => {\n      const packageManager = {\n        getModulePackageJSON: () =>\n          ({\n            version: '0.2.0',\n          }) as PackageJson,\n        removeDependencies: vi.fn(),\n        addDependencies: vi.fn(),\n      };\n\n      const matchingFiles = ['.storybook/test-setup.ts'];\n\n      await addonExperimentalTest.run?.({\n        result: {\n          matchingFiles,\n          hasPackageJsonDependency: true,\n        },\n        packageManager: packageManager as any,\n        dryRun: true,\n        storybookVersion: '9.0.0',\n      } as any);\n\n      // Files should be read but not written in dry run mode\n      expect(readFileSync).toHaveBeenCalledTimes(1);\n      expect(writeFileSync).not.toHaveBeenCalled();\n\n      // Package dependencies should not be modified in dry run mode\n      expect(packageManager.removeDependencies).not.toHaveBeenCalled();\n      expect(packageManager.addDependencies).not.toHaveBeenCalled();\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/addon-experimental-test.ts",
    "content": "import { readFileSync, writeFileSync } from 'fs';\n\nimport { findFilesUp } from '../../util.ts';\nimport type { Fix } from '../types.ts';\n\ninterface AddonExperimentalTestOptions {\n  matchingFiles: string[];\n}\n\n/**\n * This fix migrates users from @storybook/experimental-addon-test to @storybook/addon-vitest\n *\n * It will:\n *\n * - Replace all instances of @storybook/experimental-addon-test with @storybook/addon-vitest in all\n *   project files\n * - Update package.json dependencies if needed\n */\nexport const addonExperimentalTest: Fix<AddonExperimentalTestOptions> = {\n  id: 'addon-experimental-test',\n  link: 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#experimental-test-addon-stabilized-and-renamed',\n\n  promptType: 'auto',\n\n  async check({ packageManager }) {\n    const isExperimentalAddonTestInstalled = await packageManager.isPackageInstalled(\n      '@storybook/experimental-addon-test'\n    );\n\n    if (!isExperimentalAddonTestInstalled) {\n      return null;\n    }\n\n    const matchingFiles = findFilesUp(\n      ['.storybook/**/*.*', 'vitest.*.{js,ts,mjs,cjs}', 'vite.config.{js,ts,mjs,cjs}'],\n      packageManager.instanceDir\n    );\n\n    const filesWithExperimentalAddon = [];\n\n    for (const file of matchingFiles) {\n      try {\n        const content = readFileSync(file, 'utf-8');\n        if (content.includes('@storybook/experimental-addon-test')) {\n          filesWithExperimentalAddon.push(file);\n        }\n      } catch (e) {\n        // Skip files that can't be read\n      }\n    }\n\n    return {\n      matchingFiles: filesWithExperimentalAddon,\n    };\n  },\n\n  prompt() {\n    return \"We'll migrate @storybook/experimental-addon-test to @storybook/addon-vitest\";\n  },\n\n  async run({ result: { matchingFiles }, packageManager, dryRun, storybookVersion }) {\n    // Update all files that contain @storybook/experimental-addon-test\n    for (const file of matchingFiles) {\n      const content = readFileSync(file, 'utf-8');\n      let updatedContent = content.replace(\n        /@storybook\\/experimental-addon-test/g,\n        '@storybook/addon-vitest'\n      );\n\n      if (file.includes('vitest.setup')) {\n        updatedContent = updatedContent.replace(/^\\s*beforeAll.*\\n?/gm, '');\n      }\n\n      if (!dryRun) {\n        writeFileSync(file, updatedContent, 'utf-8');\n      }\n    }\n\n    // Update package.json if needed\n    if (!dryRun) {\n      await packageManager.removeDependencies(['@storybook/experimental-addon-test']);\n      await packageManager.addDependencies({ type: 'devDependencies', skipInstall: true }, [\n        `@storybook/addon-vitest@${storybookVersion}`,\n      ]);\n    }\n  },\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.test.ts",
    "content": "import * as fsp from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { afterEach, describe, expect, it, vi } from 'vitest';\n\nimport { printCsf } from 'storybook/internal/csf-tools';\n\n// Import common to mock\nimport { dedent } from 'ts-dedent';\n\n// Import FixResult type\nimport { addonGlobalsApi, transformStoryFile } from './addon-globals-api.ts';\n\n// Mock fs/promises\nvi.mock('node:fs/promises', async () => import('../../../../../__mocks__/fs/promises.ts'));\n\nvi.mock(import('storybook/internal/babel'), async (actualImport) => {\n  const actual = await actualImport();\n  return {\n    ...actual,\n    recast: {\n      ...actual.recast,\n      print: (ast, options) => actual.recast.print(ast, { ...options, quote: 'single' }),\n    },\n  };\n});\n\nconst previewConfigPath = join('.storybook', 'preview.js');\n\nconst check = async (previewContents: string) => {\n  vi.mocked<typeof import('../../../../../__mocks__/fs/promises')>(fsp as any).__setMockFiles({\n    [previewConfigPath]: previewContents,\n  });\n  return addonGlobalsApi.check({\n    packageManager: {} as any,\n    configDir: '',\n    mainConfig: {} as any,\n    storybookVersion: '9.0.0', // Assume v9 for testing migrations\n    previewConfigPath,\n    storiesPaths: [],\n    hasCsfFactoryPreview: false,\n  });\n};\n\n// Helper to run the migration for preview file and capture transform function\nconst runMigrationAndGetTransformFn = async (previewContents: string) => {\n  const result = await check(previewContents);\n  const mockWriteFile = vi.mocked(fsp.writeFile);\n\n  let transformFn: (filePath: string, content: string) => string | null = () => null;\n\n  let transformOptions: any;\n\n  if (result) {\n    await addonGlobalsApi.run?.({\n      result,\n      dryRun: false,\n      storiesPaths: ['**/*.stories.{js,jsx,ts,tsx,mdx}'], // Mock stories paths\n      packageManager: {} as any, // Add necessary mock properties\n    } as any);\n\n    if (result) {\n      // Create a transform function that uses transformStoryFile + printCsf\n      transformFn = (filePath: string, content: string) => {\n        const transformed = transformStoryFile(content, {\n          needsViewportMigration: result.needsViewportMigration,\n          needsBackgroundsMigration: result.needsBackgroundsMigration,\n          viewportsOptions: result.viewportsOptions,\n          backgroundsOptions: result.backgroundsOptions,\n        });\n        return transformed ? printCsf(transformed, {}).code : null;\n      };\n      // Extract options passed to transformStoryFile from the closure\n      // This is a bit indirect, relying on the implementation detail\n      transformOptions = {\n        needsViewportMigration: result.needsViewportMigration,\n        needsBackgroundsMigration: result.needsBackgroundsMigration,\n        backgroundValues: result.backgroundsOptions?.values,\n      };\n    }\n  }\n\n  return {\n    previewFileContent: mockWriteFile.mock.calls[0]?.[1] as string | undefined,\n    transformFn,\n    transformOptions,\n    migrationResult: result,\n  };\n};\n\ndescribe('addon-globals-api', () => {\n  afterEach(() => {\n    vi.clearAllMocks();\n  });\n\n  describe('check', () => {\n    it('should return null for empty config', async () => {\n      await expect(check(`export default { parameters: {} }`)).resolves.toBeFalsy();\n    });\n\n    it('should detect viewport configuration', async () => {\n      const result = await check(`\n        export default {\n          parameters: {\n            viewport: {\n              viewports: {\n                mobile: { name: 'Mobile', width: '320px', height: '568px' },\n                tablet: { name: 'Tablet', width: '768px', height: '1024px' }\n              },\n              defaultViewport: 'mobile'\n            }\n          }\n        }\n      `);\n\n      expect(result).toBeTruthy();\n      expect(result?.needsViewportMigration).toBe(true);\n      expect(result?.needsBackgroundsMigration).toBe(false);\n      expect(result?.viewportsOptions?.defaultViewport).toBe('mobile');\n    });\n\n    it('should detect backgrounds configuration', async () => {\n      const result = await check(`\n        export default {\n          parameters: {\n            backgrounds: {\n              values: [\n                { name: 'Light', value: '#F8F8F8' },\n                { name: 'Dark', value: '#333333' }\n              ],\n              default: 'Light',\n              disable: false\n            }\n          }\n        }\n      `);\n\n      expect(result).toBeTruthy();\n      expect(result?.needsViewportMigration).toBe(false);\n      expect(result?.needsBackgroundsMigration).toBe(true);\n      expect(result?.backgroundsOptions?.default).toBe('Light');\n    });\n\n    it('should detect both viewport and backgrounds configuration', async () => {\n      const result = await check(`\n        export default {\n          parameters: {\n            viewport: {\n              viewports: {\n                mobile: { name: 'Mobile', width: '320px', height: '568px' },\n                tablet: { name: 'Tablet', width: '768px', height: '1024px' }\n              },\n              defaultViewport: 'tablet'\n            },\n            backgrounds: {\n              values: [\n                { name: 'Light', value: '#F8F8F8' },\n                { name: 'Dark', value: '#333333' }\n              ],\n              default: 'Dark'\n            }\n          }\n        }\n      `);\n\n      expect(result).toBeTruthy();\n      expect(result?.needsViewportMigration).toBe(true);\n      expect(result?.needsBackgroundsMigration).toBe(true);\n      expect(result?.viewportsOptions?.defaultViewport).toBe('tablet');\n      expect(result?.backgroundsOptions?.default).toBe('Dark');\n    });\n\n    it('should detect both viewport and backgrounds configuration with dynamic values', async () => {\n      const result = await check(`\n        import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport';\n\n        const backgroundValues = [\n          { name: 'Light', value: '#F8F8F8' },\n          { name: 'Dark', value: '#333333' }\n        ];\n\n        export default {\n          parameters: {\n            viewport: {\n              viewports: INITIAL_VIEWPORTS,\n              defaultViewport: 'tablet'\n            },\n            backgrounds: {\n              values: backgroundValues,\n              default: 'Dark'\n            }\n          }\n        }\n      `);\n\n      expect(result).toBeTruthy();\n      expect(result?.needsViewportMigration).toBe(true);\n      expect(result?.needsBackgroundsMigration).toBe(true);\n      expect(result?.viewportsOptions?.defaultViewport).toBe('tablet');\n      expect(result?.backgroundsOptions?.default).toBe('Dark');\n    });\n\n    it('should not detect configurations already using globals API', async () => {\n      const result = await check(`\n        export default {\n          parameters: {\n            viewport: {\n              options: {\n                mobile: { name: 'Mobile', width: '320px', height: '568px' },\n                tablet: { name: 'Tablet', width: '768px', height: '1024px' }\n              }\n            },\n            backgrounds: {\n              options: {\n                light: { name: 'Light', value: '#F8F8F8' },\n                dark: { name: 'Dark', value: '#333333' }\n              }\n            }\n          },\n          initialGlobals: {\n            viewport: { value: 'mobile', isRotated: false },\n            backgrounds: { value: 'dark' }\n          }\n        }\n      `);\n\n      // Since there's no defaultViewport or default properties, it should return null (nothing to migrate)\n      expect(result?.needsViewportMigration).toBeFalsy();\n      expect(result?.needsBackgroundsMigration).toBeFalsy();\n    });\n  });\n\n  describe('run - preview file', () => {\n    it('should migrate viewport configuration correctly', async () => {\n      const { previewFileContent } = await runMigrationAndGetTransformFn(dedent`\n        export default {\n          parameters: {\n            viewport: {\n              viewports: {\n                mobile: { name: 'Mobile', width: '320px', height: '568px' },\n                tablet: { name: 'Tablet', width: '768px', height: '1024px' }\n              },\n              defaultViewport: 'mobile'\n            }\n          }\n        }\n      `);\n\n      expect(previewFileContent).toMatchInlineSnapshot(`\n        \"export default {\n          parameters: {\n            viewport: {\n              options: {\n                mobile: { name: 'Mobile', width: '320px', height: '568px' },\n                tablet: { name: 'Tablet', width: '768px', height: '1024px' }\n              }\n            }\n          },\n\n          initialGlobals: {\n            viewport: {\n              value: 'mobile',\n              isRotated: false\n            }\n          }\n        };\"\n      `);\n    });\n\n    it('should migrate backgrounds configuration correctly', async () => {\n      const { previewFileContent } = await runMigrationAndGetTransformFn(dedent`\n        export default {\n          parameters: {\n            backgrounds: {\n              values: [\n                { name: 'Light', value: '#F8F8F8' },\n                { name: 'Dark', value: '#333333' }\n              ],\n              default: 'Light'\n            }\n          }\n        }\n      `);\n\n      expect(previewFileContent).toMatchInlineSnapshot(`\n        \"export default {\n          parameters: {\n            backgrounds: {\n              options: {\n                light: { name: 'Light', value: '#F8F8F8' },\n                dark: { name: 'Dark', value: '#333333' }\n              }\n            }\n          },\n\n          initialGlobals: {\n            backgrounds: {\n              value: 'light'\n            }\n          }\n        };\"\n      `);\n    });\n\n    it('should rename backgrounds disable property to disabled', async () => {\n      const { previewFileContent } = await runMigrationAndGetTransformFn(dedent`\n        export default {\n          parameters: {\n            backgrounds: {\n              values: [\n                { name: 'Light', value: '#F8F8F8' }\n              ],\n              disable: true\n            }\n          }\n        }\n      `);\n\n      // Verify the transformation results\n      expect(previewFileContent).toMatchInlineSnapshot(`\n        \"export default {\n          parameters: {\n            backgrounds: {\n              options: {\n                light: { name: 'Light', value: '#F8F8F8' }\n              },\n              disabled: true\n            }\n          }\n        }\"\n      `);\n    });\n\n    it('should migrate both viewport and backgrounds configurations', async () => {\n      const { previewFileContent } = await runMigrationAndGetTransformFn(dedent`\n        export default {\n          parameters: {\n            viewport: {\n              viewports: {\n                mobile: { name: 'Mobile', width: '320px', height: '568px' }\n              },\n              defaultViewport: 'mobile'\n            },\n            backgrounds: {\n              values: [\n                { name: 'Light', value: '#F8F8F8' },\n                { name: 'Dark', value: '#333333' }\n              ],\n              default: 'Light'\n            }\n          }\n        }\n      `);\n\n      expect(previewFileContent).toMatchInlineSnapshot(`\n  \"export default {\n    parameters: {\n      viewport: {\n        options: {\n          mobile: { name: 'Mobile', width: '320px', height: '568px' }\n        }\n      },\n      backgrounds: {\n        options: {\n          light: { name: 'Light', value: '#F8F8F8' },\n          dark: { name: 'Dark', value: '#333333' }\n        }\n      }\n    },\n\n    initialGlobals: {\n      viewport: {\n        value: 'mobile',\n        isRotated: false\n      },\n\n      backgrounds: {\n        value: 'light'\n      }\n    }\n  };\"\n`);\n    });\n\n    it('should correctly handle partial configurations', async () => {\n      const { previewFileContent } = await runMigrationAndGetTransformFn(dedent`\n        export default {\n          parameters: {\n            viewport: {\n              viewports: {\n                mobile: { name: 'Mobile', width: '320px', height: '568px' }\n              }\n            },\n            backgrounds: {\n              values: [\n                { name: 'Light', value: '#F8F8F8' }\n              ]\n            }\n          }\n        }\n      `);\n\n      // Verify the transformation results\n      expect(previewFileContent).toMatchInlineSnapshot(`\n        \"export default {\n          parameters: {\n            viewport: {\n              options: {\n                mobile: { name: 'Mobile', width: '320px', height: '568px' }\n              }\n            },\n            backgrounds: {\n              options: {\n                light: { name: 'Light', value: '#F8F8F8' }\n              }\n            }\n          }\n        }\"\n      `);\n    });\n\n    it('should migrate dynamic values correctly', async () => {\n      const { previewFileContent } = await runMigrationAndGetTransformFn(dedent`\n        import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport';\n\n        export default {\n          parameters: {\n            viewport: {\n              viewports: INITIAL_VIEWPORTS,\n              defaultViewport: 'tablet'\n            },\n            backgrounds: {\n              values: [\n                { name: 'Light', value: '#F8F8F8' },\n                { name: 'Dark', value: '#333333' }\n              ],\n              default: 'Light'\n            }\n          }\n        }\n      `);\n\n      expect(previewFileContent).toMatchInlineSnapshot(`\n        \"import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport';\n\n        export default {\n          parameters: {\n            viewport: {\n              options: INITIAL_VIEWPORTS\n            },\n            backgrounds: {\n              options: {\n                light: { name: 'Light', value: '#F8F8F8' },\n                dark: { name: 'Dark', value: '#333333' }\n              }\n            }\n          },\n\n          initialGlobals: {\n            viewport: {\n              value: 'tablet',\n              isRotated: false\n            },\n\n            backgrounds: {\n              value: 'light'\n            }\n          }\n        };\"\n      `);\n    });\n\n    it('should migrate complex backgrounds configuration with dots and brackets in names', async () => {\n      const { previewFileContent } = await runMigrationAndGetTransformFn(dedent`\n        export default {\n          parameters: {\n            backgrounds: {\n              default: 'palette.neutral[100]',\n              values: [\n                {\n                  name: 'palette.neutral[100]',\n                  value: palette.neutral[100],\n                },\n              ],\n            }\n          }\n        }\n      `);\n\n      expect(previewFileContent).toMatchInlineSnapshot(`\n  \"export default {\n    parameters: {\n      backgrounds: {\n        options: {\n          'palette.neutral[100]': {\n            name: 'palette.neutral[100]',\n            value: palette.neutral[100],\n          }\n        }\n      }\n    },\n\n    initialGlobals: {\n      backgrounds: {\n        value: 'palette.neutral[100]'\n      }\n    }\n  };\"\n`);\n    });\n  });\n\n  describe('run - story files', () => {\n    const defaultPreview = dedent`\n      export default {\n        parameters: {\n          viewport: {\n            viewports: { mobile: {}, tablet: {} },\n            defaultViewport: 'mobile'\n          },\n          backgrounds: {\n            values: [\n              { name: 'Light', value: '#F8F8F8' },\n              { name: 'Dark', value: '#333333' },\n              { name: 'Tweet', value: '#00aced' }\n            ],\n            default: 'Light',\n            disable: false\n          }\n        }\n      }\n    `;\n\n    it('should migrate parameters.backgrounds.default to globals.backgrounds', async () => {\n      const { transformFn } = await runMigrationAndGetTransformFn(defaultPreview);\n      const storyContent = dedent`\n          import Button from './Button';\n          export default { component: Button };\n          export const Default = {\n            parameters: {\n              backgrounds: { default: 'Dark' }\n            }\n          };\n        `;\n\n      expect(transformFn).toBeDefined();\n      expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(`\n        \"import Button from './Button';\n        export default { component: Button };\n        export const Default = {\n          globals: {\n            backgrounds: {\n              value: 'dark'\n            }\n          }\n        };\"\n      `);\n    });\n\n    it('should migrate parameters.backgrounds.disable: true to disabled: true', async () => {\n      const { transformFn } = await runMigrationAndGetTransformFn(defaultPreview);\n      const storyContent = dedent`\n          import Button from './Button';\n          export default { component: Button };\n          export const Disabled = {\n            parameters: {\n              backgrounds: { disable: true }\n            }\n          };\n        `;\n      expect(transformFn).toBeDefined();\n      expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(`\n        \"import Button from './Button';\n        export default { component: Button };\n        export const Disabled = {\n          parameters: {\n            backgrounds: { disabled: true }\n          }\n        };\"\n      `);\n    });\n\n    it('should rename parameters.backgrounds.disable: false to disabled: false', async () => {\n      const { transformFn } = await runMigrationAndGetTransformFn(defaultPreview);\n      const storyContent = dedent`\n          import Button from './Button';\n          export default { component: Button };\n          export const Disabled = {\n            parameters: {\n              backgrounds: { disable: false }\n            }\n          };\n        `;\n      expect(transformFn).toBeDefined();\n      expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(`\n        \"import Button from './Button';\n        export default { component: Button };\n        export const Disabled = {\n          parameters: {\n            backgrounds: { disabled: false }\n          }\n        };\"\n      `);\n    });\n\n    it('should migrate parameters.viewport.defaultViewport to globals.viewport', async () => {\n      const { transformFn } = await runMigrationAndGetTransformFn(defaultPreview);\n      const storyContent = dedent`\n          import Button from './Button';\n          export default { component: Button };\n          export const MobileOnly = {\n            parameters: {\n              viewport: { defaultViewport: 'mobile' }\n            }\n          };\n        `;\n      expect(transformFn).toBeDefined();\n      expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(`\n        \"import Button from './Button';\n        export default { component: Button };\n        export const MobileOnly = {\n          globals: {\n            viewport: {\n              value: 'mobile',\n              isRotated: false\n            }\n          }\n        };\"\n      `);\n    });\n\n    it('should migrate both viewport and backgrounds in the same story', async () => {\n      const { transformFn } = await runMigrationAndGetTransformFn(defaultPreview);\n      const storyContent = dedent`\n          import Button from './Button';\n          export default { component: Button };\n          export const DarkMobile = {\n            parameters: {\n              viewport: { defaultViewport: 'mobile' },\n              backgrounds: { default: 'Dark' }\n            }\n          };\n        `;\n      expect(transformFn).toBeDefined();\n      expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(`\n        \"import Button from './Button';\n        export default { component: Button };\n        export const DarkMobile = {\n          globals: {\n            viewport: {\n              value: 'mobile',\n              isRotated: false\n            },\n\n            backgrounds: {\n              value: 'dark'\n            }\n          }\n        };\"\n      `);\n    });\n\n    it('should handle migration in meta (export default)', async () => {\n      const { transformFn } = await runMigrationAndGetTransformFn(defaultPreview);\n      const storyContent = dedent`\n          import Button from './Button';\n          export default {\n            component: Button,\n            parameters: {\n              backgrounds: { default: 'Tweet' }\n            }\n          };\n          export const Default = {};\n        `;\n\n      expect(transformFn).toBeDefined();\n      expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(`\n        \"import Button from './Button';\n        export default {\n          component: Button,\n          globals: {\n            backgrounds: {\n              value: 'tweet'\n            }\n          }\n        };\n        export const Default = {};\"\n      `);\n    });\n\n    it('should return null if no changes are needed', async () => {\n      const { transformFn } = await runMigrationAndGetTransformFn(defaultPreview);\n      const storyContent = dedent`\n        import Button from './Button';\n        export default { component: Button };\n        export const NoParams = {};\n        export const ExistingGlobals = { globals: { backgrounds: { value: 'dark' } } };\n        export const ExistingDisabled = { parameters: { backgrounds: { disabled: true } } };\n      `;\n      expect(transformFn).toBeDefined();\n      expect(transformFn!('story.js', storyContent)).toBeNull();\n    });\n\n    it('should migrate parameters even when other stories have existing globals', async () => {\n      const { transformFn } = await runMigrationAndGetTransformFn(defaultPreview);\n      const storyContent = dedent`\n        import Button from './Button';\n\n        export default { \n          component: Button \n        };\n\n        export const ExistingGlobals = { \n          globals: { \n            backgrounds: { \n              value: 'dark' \n            } \n          } \n        };\n\n        export const NeedsMigration = { \n          parameters: { \n            backgrounds: { \n              default: 'Dark' \n            } \n          } \n        };\n      `;\n      expect(transformFn).toBeDefined();\n      expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(`\n        \"import Button from './Button';\n\n        export default { \n          component: Button \n        };\n\n        export const ExistingGlobals = { \n          globals: { \n            backgrounds: { \n              value: 'dark' \n            } \n          } \n        };\n\n        export const NeedsMigration = { \n          globals: {\n            backgrounds: {\n              value: 'dark'\n            }\n          } \n        };\"\n      `);\n    });\n\n    it('should merge new globals with existing globals in the same story', async () => {\n      const { transformFn } = await runMigrationAndGetTransformFn(defaultPreview);\n      const storyContent = dedent`\n        import Button from './Button';\n\n        export default { component: Button };\n        \n        export const ExistingAndNeedsMigration = { \n          globals: { \n            backgrounds: { \n              value: 'light' \n            } \n          },\n          parameters: {\n            backgrounds: {\n              default: 'Dark'\n            }\n          } \n        };\n      `;\n      expect(transformFn).toBeDefined();\n      expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(`\n        \"import Button from './Button';\n\n        export default { component: Button };\n\n        export const ExistingAndNeedsMigration = {\n          globals: { \n            backgrounds: { \n              value: 'light' \n            } \n          }\n        };\"\n      `);\n    });\n\n    it('should remove empty parameters/backgrounds/viewport objects after migration', async () => {\n      const { transformFn } = await runMigrationAndGetTransformFn(defaultPreview);\n      const storyContent = dedent`\n          import Button from './Button';\n\n          export default { component: Button };\n\n          export const TestStory = {\n            parameters: {\n              otherParam: true,\n              backgrounds: { \n                default: 'Dark' \n              },\n              viewport: { \n                defaultViewport: 'tablet'\n              }\n            }\n          };\n        `;\n      expect(transformFn).toBeDefined();\n      expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(`\n        \"import Button from './Button';\n\n        export default { component: Button };\n\n        export const TestStory = {\n          parameters: {\n            otherParam: true\n          },\n\n          globals: {\n            viewport: {\n              value: 'tablet',\n              isRotated: false\n            },\n\n            backgrounds: {\n              value: 'dark'\n            }\n          }\n        };\"\n      `);\n    });\n\n    it('should transform defaultOrientation and disabled properties in viewport stories', async () => {\n      const { transformFn } = await runMigrationAndGetTransformFn(defaultPreview);\n      const storyContent = dedent`\n          import Button from './Button';\n          export default { component: Button };\n          export const Mobile = {\n            parameters: {\n              viewport: {\n                defaultOrientation: 'portrait',\n                defaultViewport: 'iphonex',\n                disable: true,\n              },\n            },\n          };\n        `;\n      expect(transformFn).toBeDefined();\n      expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(`\n        \"import Button from './Button';\n        export default { component: Button };\n        export const Mobile = {\n          parameters: {\n            viewport: {\n              disabled: true\n            },\n          },\n\n          globals: {\n            viewport: {\n              value: 'iphonex',\n              isRotated: true\n            }\n          }\n        };\"\n      `);\n    });\n\n    it('should transform member expression references in viewport stories', async () => {\n      const { transformFn } = await runMigrationAndGetTransformFn(defaultPreview);\n      const storyContent = dedent`\n          import { MINIMAL_VIEWPORTS } from 'storybook/viewport';\n          import Button from './Button';\n          export default { component: Button };\n          export const Mobile = {\n            parameters: {\n              viewport: {\n                defaultViewport: MINIMAL_VIEWPORTS.mobile2\n              },\n            },\n          };\n        `;\n      expect(transformFn).toBeDefined();\n      expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(`\n        \"import { MINIMAL_VIEWPORTS } from 'storybook/viewport';\n        import Button from './Button';\n        export default { component: Button };\n        export const Mobile = {\n          globals: {\n            viewport: {\n              value: MINIMAL_VIEWPORTS.mobile2,\n              isRotated: false\n            }\n          },\n        };\"\n      `);\n    });\n\n    it('should transform backgrounds values to options and migrate default in story files', async () => {\n      const { transformFn } = await runMigrationAndGetTransformFn(defaultPreview);\n      const storyContent = dedent`\n          import Button from './Button';\n          export default { component: Button };\n          export const Mobile = {\n            parameters: {\n              backgrounds: {\n                default: 'Light',\n                values: [\n                  { name: 'Gray', value: '#CCC' },\n                ],\n              },\n            },\n          };\n        `;\n      expect(transformFn).toBeDefined();\n      expect(transformFn!('story.js', storyContent)).toMatchInlineSnapshot(`\n        \"import Button from './Button';\n        export default { component: Button };\n        export const Mobile = {\n          parameters: {\n            backgrounds: {\n              options: {\n                gray: { name: 'Gray', value: '#CCC' }\n              }\n            },\n          },\n\n          globals: {\n            backgrounds: {\n              value: 'light'\n            }\n          }\n        };\"\n      `);\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/addon-globals-api.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\n\nimport { types as t } from 'storybook/internal/babel';\nimport type { ConfigFile, CsfFile } from 'storybook/internal/csf-tools';\nimport { formatConfig, loadConfig, loadCsf, writeCsf } from 'storybook/internal/csf-tools';\n\nimport type { ArrayExpression, Expression, ObjectExpression } from '@babel/types';\n\nimport {\n  addProperty,\n  getKeyFromName,\n  getObjectProperty,\n  removeProperty,\n  transformStoryParameters,\n  transformValuesToOptions,\n} from '../helpers/ast-utils.ts';\nimport type { Fix } from '../types.ts';\n\ninterface AddonGlobalsApiOptions {\n  previewConfig: ConfigFile;\n  previewConfigPath: string;\n  needsViewportMigration: boolean;\n  needsBackgroundsMigration: boolean;\n  viewportsOptions:\n    | {\n        defaultViewport?: string;\n        viewports?: Expression;\n      }\n    | undefined;\n  backgroundsOptions:\n    | {\n        default?: string;\n        values?: Expression;\n        disable?: boolean;\n      }\n    | undefined;\n}\n\n/**\n * Migrate viewport and backgrounds addons to use the new globals API in Storybook 9\n *\n * - Migrate viewports to use options and initialGlobals\n * - Migrate backgrounds to use options and initialGlobals\n */\nexport const addonGlobalsApi: Fix<AddonGlobalsApiOptions> = {\n  id: 'addon-globals-api',\n  link: 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#viewportbackgrounds-addon-synchronized-configuration-and-globals-usage',\n\n  async check({ previewConfigPath }) {\n    if (!previewConfigPath) {\n      return null;\n    }\n\n    const previewConfig = loadConfig((await readFile(previewConfigPath)).toString()).parse();\n\n    const getFieldNode = previewConfig.getFieldNode.bind(previewConfig);\n    const getFieldValue = previewConfig.getFieldValue.bind(previewConfig);\n\n    // Reusable function to check addon migration status\n    const checkAddonMigration = (addonName: 'viewport' | 'backgrounds') => {\n      const paramPath = ['parameters', addonName];\n      const addonParams = getFieldNode(paramPath) as ObjectExpression | undefined;\n\n      if (!addonParams) {\n        return { needsMigration: false };\n      }\n\n      const hasOptions = getFieldNode([...paramPath, 'options']) !== undefined;\n\n      // Define fields to check based on addon type\n      const fieldsToCheck =\n        addonName === 'viewport'\n          ? ['viewports', 'defaultViewport']\n          : ['values', 'default', 'disable'];\n\n      // Check if any old format fields exist\n      const hasOldFormat = fieldsToCheck.some(\n        (field) => getFieldNode([...paramPath, field]) !== undefined\n      );\n\n      // Only migrate if using old format and not already migrated\n      const needsMigration = hasOldFormat && !hasOptions;\n\n      // Collect relevant options from old format\n      const options: Record<string, any> = {};\n\n      if (needsMigration) {\n        fieldsToCheck.forEach((field) => {\n          const value =\n            (addonName === 'viewport' && field === 'viewports') ||\n            (addonName === 'backgrounds' && field === 'values')\n              ? getFieldNode([...paramPath, field])\n              : getFieldValue([...paramPath, field]);\n\n          if (value !== undefined) {\n            // Convert field names if necessary (maintaining the expected output structure)\n            const optionKey = addonName === 'viewport' ? field : field;\n            options[optionKey] = value;\n          }\n        });\n      }\n\n      return { needsMigration, options };\n    };\n\n    // Check migration status for both addons\n    const viewportMigration = checkAddonMigration('viewport');\n    const backgroundsMigration = checkAddonMigration('backgrounds');\n\n    // Return null if there's nothing to migrate\n    if (!viewportMigration.needsMigration && !backgroundsMigration.needsMigration) {\n      return null;\n    }\n\n    return {\n      previewConfig,\n      previewConfigPath,\n      needsViewportMigration: viewportMigration.needsMigration,\n      needsBackgroundsMigration: backgroundsMigration.needsMigration,\n      viewportsOptions: viewportMigration.options,\n      backgroundsOptions: backgroundsMigration.options,\n    };\n  },\n\n  prompt() {\n    return \"You're using a deprecated config API for viewport/backgrounds. The globals API will be used instead.\";\n  },\n\n  async run({ dryRun = false, result, storiesPaths }) {\n    const {\n      previewConfig,\n      needsViewportMigration,\n      needsBackgroundsMigration,\n      viewportsOptions,\n      backgroundsOptions,\n    } = result;\n\n    const getFieldNode = previewConfig.getFieldNode.bind(previewConfig);\n\n    if (needsViewportMigration) {\n      // Get the viewport parameter object\n      const viewports = getFieldNode(['parameters', 'viewport', 'viewports']) as ObjectExpression;\n\n      if (viewportsOptions?.viewports) {\n        // Remove the old viewports property\n        previewConfig.removeField(['parameters', 'viewport', 'viewports']);\n        addProperty(\n          getFieldNode(['parameters', 'viewport']) as ObjectExpression,\n          'options',\n          viewports\n        );\n      }\n\n      // If defaultViewport exists, create initialGlobals.viewport\n      if (viewportsOptions?.defaultViewport) {\n        // Remove the old defaultViewport property\n        const viewportNode = getFieldNode(['parameters', 'viewport']);\n        removeProperty(viewportNode as ObjectExpression, 'defaultViewport');\n\n        previewConfig.setFieldValue(\n          ['initialGlobals', 'viewport', 'value'],\n          viewportsOptions.defaultViewport\n        );\n        previewConfig.setFieldValue(['initialGlobals', 'viewport', 'isRotated'], false);\n      }\n    }\n\n    if (needsBackgroundsMigration) {\n      if (backgroundsOptions?.values) {\n        // Transform values array to options object\n        const optionsObject = transformValuesToOptions(\n          backgroundsOptions.values as ArrayExpression\n        );\n\n        // Remove the old values property\n        previewConfig.removeField(['parameters', 'backgrounds', 'values']);\n        addProperty(\n          getFieldNode(['parameters', 'backgrounds']) as ObjectExpression,\n          'options',\n          optionsObject\n        );\n      }\n\n      // If default exists, create initialGlobals.backgrounds\n      if (backgroundsOptions?.default) {\n        // Remove the old default property\n        removeProperty(getFieldNode(['parameters', 'backgrounds']) as ObjectExpression, 'default');\n\n        previewConfig.setFieldValue(\n          ['initialGlobals', 'backgrounds', 'value'],\n          getKeyFromName(backgroundsOptions.values as ArrayExpression, backgroundsOptions.default)\n        );\n      }\n\n      // If disable exists, rename to disabled\n      if (backgroundsOptions?.disable === true) {\n        // Remove the old disable property\n        removeProperty(getFieldNode(['parameters', 'backgrounds']) as ObjectExpression, 'disable');\n\n        addProperty(\n          getFieldNode(['parameters', 'backgrounds']) as ObjectExpression,\n          'disabled',\n          t.booleanLiteral(true)\n        );\n      }\n    }\n\n    // Write the updated config back to the file\n    if (!dryRun) {\n      await writeFile(result.previewConfigPath, formatConfig(previewConfig));\n    }\n\n    // Update stories\n    if (needsViewportMigration || needsBackgroundsMigration) {\n      await transformStoryFiles(\n        storiesPaths,\n        {\n          needsViewportMigration,\n          needsBackgroundsMigration,\n          viewportsOptions,\n          backgroundsOptions,\n        },\n        dryRun\n      );\n    }\n  },\n};\n\n// Story transformation function\nasync function transformStoryFiles(\n  files: string[],\n  options: {\n    needsViewportMigration: boolean;\n    needsBackgroundsMigration: boolean;\n    viewportsOptions: any;\n    backgroundsOptions: any;\n  },\n  dryRun: boolean\n): Promise<Array<{ file: string; error: Error }>> {\n  const errors: Array<{ file: string; error: Error }> = [];\n  const { default: pLimit } = await import('p-limit');\n  const limit = pLimit(10);\n\n  await Promise.all(\n    files.map((file) =>\n      limit(async () => {\n        try {\n          const content = await readFile(file, 'utf-8');\n          const transformed = transformStoryFile(content, options);\n\n          if (transformed && !dryRun) {\n            await writeCsf(transformed, file);\n          }\n        } catch (error) {\n          errors.push({ file, error: error as Error });\n        }\n      })\n    )\n  );\n\n  return errors;\n}\n\n// Transform a single story file\nexport function transformStoryFile(\n  source: string,\n  options: {\n    needsViewportMigration: boolean;\n    needsBackgroundsMigration: boolean;\n    viewportsOptions: any;\n    backgroundsOptions: any;\n  }\n): CsfFile | null {\n  const { needsViewportMigration, needsBackgroundsMigration, backgroundsOptions } = options;\n\n  // Load the story file using CSF tools\n  const storyConfig = loadCsf(source, {\n    makeTitle: (title?: string) => title || 'default',\n  }).parse();\n\n  // Use the story transformer utility to handle all story iteration\n  const hasChanges = transformStoryParameters(storyConfig, (parameters, storyObject) => {\n    let newGlobals: ObjectExpression | undefined;\n    let viewportParams: ObjectExpression | undefined;\n    let backgroundsParams: ObjectExpression | undefined;\n    let storyHasChanges = false;\n\n    // Handle viewport migration\n    if (needsViewportMigration) {\n      viewportParams = getObjectProperty(parameters, 'viewport') as ObjectExpression;\n      if (viewportParams) {\n        const defaultViewport = getObjectProperty(viewportParams, 'defaultViewport');\n        const defaultOrientation = getObjectProperty(viewportParams, 'defaultOrientation');\n        const disableViewport = getObjectProperty(viewportParams, 'disable');\n\n        // Handle both string literals and member expressions for defaultViewport\n        let viewportValue: t.StringLiteral | t.MemberExpression | null = null;\n        if (defaultViewport) {\n          if (t.isStringLiteral(defaultViewport)) {\n            viewportValue = defaultViewport;\n          } else if (t.isMemberExpression(defaultViewport)) {\n            // Preserve the member expression as-is\n            viewportValue = defaultViewport;\n          }\n        }\n\n        if (viewportValue) {\n          // Create globals.viewport\n          if (!newGlobals) {\n            newGlobals = t.objectExpression([]);\n          }\n\n          // Determine isRotated based on defaultOrientation\n          let isRotated = false;\n          if (defaultOrientation && t.isStringLiteral(defaultOrientation)) {\n            isRotated = defaultOrientation.value === 'portrait';\n          }\n\n          newGlobals.properties.push(\n            t.objectProperty(\n              t.identifier('viewport'),\n              t.objectExpression([\n                t.objectProperty(t.identifier('value'), viewportValue),\n                t.objectProperty(t.identifier('isRotated'), t.booleanLiteral(isRotated)),\n              ])\n            )\n          );\n\n          // Remove defaultViewport from parameters\n          removeProperty(viewportParams, 'defaultViewport');\n          storyHasChanges = true;\n        }\n\n        // Handle defaultOrientation removal\n        if (defaultOrientation) {\n          removeProperty(viewportParams, 'defaultOrientation');\n          storyHasChanges = true;\n        }\n\n        // Handle disable -> disabled rename\n        if (disableViewport && t.isBooleanLiteral(disableViewport)) {\n          removeProperty(viewportParams, 'disable');\n          // Rename disable to disabled (preserve both true and false values)\n          addProperty(viewportParams, 'disabled', disableViewport);\n          storyHasChanges = true;\n        }\n      }\n    }\n\n    // Handle backgrounds migration\n    if (needsBackgroundsMigration) {\n      backgroundsParams = getObjectProperty(parameters, 'backgrounds') as ObjectExpression;\n      if (backgroundsParams) {\n        const defaultBackground = getObjectProperty(backgroundsParams, 'default');\n        const disableBackground = getObjectProperty(backgroundsParams, 'disable');\n        const valuesBackground = getObjectProperty(backgroundsParams, 'values');\n\n        // Handle values -> options transformation\n        if (valuesBackground && t.isArrayExpression(valuesBackground)) {\n          // Transform values array to options object\n          const optionsObject = transformValuesToOptions(valuesBackground);\n\n          // Remove the old values property\n          removeProperty(backgroundsParams, 'values');\n          addProperty(backgroundsParams, 'options', optionsObject);\n          storyHasChanges = true;\n        }\n\n        if (defaultBackground && t.isStringLiteral(defaultBackground)) {\n          // Create globals.backgrounds\n          if (!newGlobals) {\n            newGlobals = t.objectExpression([]);\n          }\n\n          const backgroundKey = getKeyFromName(\n            backgroundsOptions?.values as ArrayExpression,\n            defaultBackground.value\n          );\n\n          newGlobals.properties.push(\n            t.objectProperty(\n              t.identifier('backgrounds'),\n              t.objectExpression([\n                t.objectProperty(t.identifier('value'), t.stringLiteral(backgroundKey)),\n              ])\n            )\n          );\n\n          // Remove default from parameters\n          removeProperty(backgroundsParams, 'default');\n          storyHasChanges = true;\n        }\n\n        // Handle disable -> disabled rename\n        if (disableBackground && t.isBooleanLiteral(disableBackground)) {\n          removeProperty(backgroundsParams, 'disable');\n          // Rename disable to disabled (preserve both true and false values)\n          addProperty(backgroundsParams, 'disabled', disableBackground);\n          storyHasChanges = true;\n        }\n      }\n    }\n\n    // Add globals to story if we created any\n    if (newGlobals && newGlobals.properties.length > 0) {\n      const existingGlobals = getObjectProperty(storyObject, 'globals') as\n        | ObjectExpression\n        | undefined;\n\n      if (existingGlobals) {\n        // Merge new globals with existing globals\n        newGlobals.properties.forEach((newGlobal) => {\n          if (t.isObjectProperty(newGlobal) && t.isIdentifier(newGlobal.key)) {\n            const globalName = newGlobal.key.name;\n            const existingGlobal = getObjectProperty(existingGlobals, globalName) as\n              | ObjectExpression\n              | undefined;\n\n            if (existingGlobal) {\n              // Merge properties if both are object expressions\n              if (t.isObjectExpression(newGlobal.value) && t.isObjectExpression(existingGlobal)) {\n                newGlobal.value.properties.forEach((newProp) => {\n                  if (t.isObjectProperty(newProp) && t.isIdentifier(newProp.key)) {\n                    const propName = newProp.key.name;\n                    const existingProp = getObjectProperty(existingGlobal, propName);\n\n                    if (!existingProp) {\n                      existingGlobal.properties.push(newProp);\n                    }\n                  }\n                });\n              }\n            } else {\n              // Add new global to existing globals\n              existingGlobals.properties.push(newGlobal);\n            }\n          }\n        });\n      } else {\n        // No existing globals, add new ones\n        storyObject.properties.push(t.objectProperty(t.identifier('globals'), newGlobals));\n      }\n      storyHasChanges = true;\n    }\n\n    // Clean up empty parameter objects\n    if (viewportParams && viewportParams.properties.length === 0) {\n      removeProperty(parameters, 'viewport');\n      storyHasChanges = true;\n    }\n\n    if (backgroundsParams && backgroundsParams.properties.length === 0) {\n      removeProperty(parameters, 'backgrounds');\n      storyHasChanges = true;\n    }\n\n    // Remove parameters if it's now empty\n    if (parameters.properties.length === 0) {\n      removeProperty(storyObject, 'parameters');\n      storyHasChanges = true;\n    }\n\n    return storyHasChanges;\n  });\n\n  return hasChanges ? storyConfig : null;\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/addon-mdx-gfm-remove.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { JsPackageManager } from 'storybook/internal/common';\nimport type { StorybookConfigRaw } from 'storybook/internal/types';\n\nimport type { CheckOptions, RunOptions } from '../types.ts';\nimport { addonMdxGfmRemove } from './addon-mdx-gfm-remove.ts';\n\n// Mock modules before any other imports or declarations\nvi.mock('node:fs/promises', async () => {\n  return {\n    readFile: vi.fn(),\n    lstat: vi.fn(),\n    readdir: vi.fn(),\n    readlink: vi.fn(),\n    realpath: vi.fn(),\n  };\n});\n\nvi.mock('../helpers/mainConfigFile', () => {\n  const updateMainConfig = vi.fn().mockImplementation(({ mainConfigPath }, callback) => {\n    return callback(mockConfigs.get(mainConfigPath));\n  });\n  return { updateMainConfig };\n});\n\nvi.mock('storybook/internal/common', async (importOriginal) => {\n  const actual = (await importOriginal()) as any;\n  return {\n    ...actual,\n    removeAddon: vi.fn(),\n  };\n});\n\n// Mock ConfigFile type\ninterface MockConfigFile {\n  getFieldValue: (path: string[]) => any;\n  setFieldValue: (path: string[], value: any) => void;\n  appendValueToArray: (path: string[], value: any) => void;\n  removeField: (path: string[]) => void;\n  _ast: Record<string, unknown>;\n  _code: string;\n  _exports: Record<string, unknown>;\n  _exportDecls: unknown[];\n}\n\n// Store mock configs by path\nconst mockConfigs = new Map<string, MockConfigFile>();\n\n// Get reference to mocked readFile\nconst readFileMock = vi.mocked(await import('node:fs/promises')).readFile;\n\nconst mockPackageManager = vi.mocked(JsPackageManager.prototype);\n\nconst baseCheckOptions: CheckOptions = {\n  packageManager: mockPackageManager,\n  mainConfig: {\n    stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n    addons: ['@storybook/addon-links'],\n  } as StorybookConfigRaw,\n  storybookVersion: '7.0.0',\n  configDir: '.storybook',\n  storiesPaths: [],\n  hasCsfFactoryPreview: false,\n};\n\ninterface AddonMdxGfmOptions {\n  hasMdxGfm: boolean;\n}\n\n// Add type for migration object\ninterface Migration {\n  check: (options: CheckOptions) => Promise<true | null>;\n  run: (options: RunOptions<any>) => Promise<void>;\n}\n\nconst typedAddonMdxGfmRemove = addonMdxGfmRemove as Migration;\n\ndescribe('addon-mdx-gfm-remove migration', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n    mockPackageManager.runPackageCommand = vi.fn();\n    Object.defineProperty(mockPackageManager, 'packageJsonPaths', {\n      value: [],\n      writable: true,\n      configurable: true,\n    });\n    mockPackageManager.removeDependencies = vi.fn();\n    mockConfigs.clear();\n  });\n\n  describe('check phase', () => {\n    it('returns null if no mainConfigPath provided', async () => {\n      const result = await typedAddonMdxGfmRemove.check(baseCheckOptions);\n      expect(result).toBeNull();\n    });\n\n    it('returns null if mdx-gfm not found in config', async () => {\n      const mainConfig = `\n        export default {\n          stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n          addons: ['@storybook/addon-links'],\n        };\n      `;\n      readFileMock.mockResolvedValueOnce(mainConfig);\n\n      const result = await typedAddonMdxGfmRemove.check({\n        ...baseCheckOptions,\n        mainConfigPath: 'main.ts',\n        mainConfig: {\n          stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n          addons: ['@storybook/addon-links'],\n        } as StorybookConfigRaw,\n      });\n      expect(result).toBeNull();\n    });\n\n    it('detects mdx-gfm addon when present as string', async () => {\n      const mockMain: MockConfigFile = {\n        getFieldValue: vi.fn().mockReturnValue(['@storybook/addon-mdx-gfm']),\n        setFieldValue: vi.fn(),\n        appendValueToArray: vi.fn(),\n        removeField: vi.fn(),\n        _ast: {},\n        _code: '',\n        _exports: {},\n        _exportDecls: [],\n      };\n\n      mockConfigs.set('main.ts', mockMain);\n\n      const result = await typedAddonMdxGfmRemove.check({\n        ...baseCheckOptions,\n        mainConfigPath: 'main.ts',\n        mainConfig: {\n          stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n          addons: ['@storybook/addon-mdx-gfm'],\n        } as StorybookConfigRaw,\n      });\n      expect(result).toEqual(true);\n    });\n\n    it('detects mdx-gfm addon when present as object', async () => {\n      const mockMain: MockConfigFile = {\n        getFieldValue: vi.fn().mockReturnValue([{ name: '@storybook/addon-mdx-gfm' }]),\n        setFieldValue: vi.fn(),\n        appendValueToArray: vi.fn(),\n        removeField: vi.fn(),\n        _ast: {},\n        _code: '',\n        _exports: {},\n        _exportDecls: [],\n      };\n\n      mockConfigs.set('main.ts', mockMain);\n\n      const result = await typedAddonMdxGfmRemove.check({\n        ...baseCheckOptions,\n        mainConfigPath: 'main.ts',\n        mainConfig: {\n          stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n          addons: [{ name: '@storybook/addon-mdx-gfm' }],\n        } as StorybookConfigRaw,\n      });\n      expect(result).toEqual(true);\n    });\n  });\n\n  describe('run phase', () => {\n    it('removes mdx-gfm addon using storybook remove command', async () => {\n      const { removeAddon } = await import('storybook/internal/common');\n\n      await typedAddonMdxGfmRemove.run({\n        result: true,\n        packageManager: mockPackageManager as JsPackageManager,\n        configDir: '.storybook',\n      } as RunOptions<true>);\n\n      expect(removeAddon).toHaveBeenCalledWith('@storybook/addon-mdx-gfm', {\n        configDir: '.storybook',\n        skipInstall: true,\n        packageManager: mockPackageManager,\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/addon-mdx-gfm-remove.ts",
    "content": "import { getAddonNames, removeAddon } from 'storybook/internal/common';\n\nimport type { Fix } from '../types.ts';\n\ntype AddonMdxGfmOptions = true;\n\n/**\n * Migration to handle @storybook/addon-mdx-gfm being removed\n *\n * - Remove @storybook/addon-mdx-gfm from main.ts and package.json\n */\nexport const addonMdxGfmRemove: Fix<AddonMdxGfmOptions> = {\n  id: 'addon-mdx-gfm-remove',\n  link: 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#mdx-gfm-addon-removed',\n\n  async check({ mainConfigPath, mainConfig, packageManager }) {\n    if (!mainConfigPath) {\n      return null;\n    }\n\n    try {\n      const addonName = '@storybook/addon-mdx-gfm';\n      const addonNames = getAddonNames(mainConfig);\n      const hasMdxGfm = addonNames.includes(addonName);\n      const hasMdxGfmInDeps = packageManager.isDependencyInstalled(addonName);\n\n      if (!hasMdxGfm && !hasMdxGfmInDeps) {\n        return null;\n      }\n\n      return true;\n    } catch (err) {\n      return null;\n    }\n  },\n\n  prompt() {\n    return `We'll remove @storybook/addon-mdx-gfm as it's no longer needed in Storybook 9.0.`;\n  },\n\n  async run({ packageManager, configDir }) {\n    await removeAddon('@storybook/addon-mdx-gfm', {\n      configDir,\n      skipInstall: true,\n      packageManager,\n    });\n  },\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/addon-storysource-code-panel.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { JsPackageManager } from 'storybook/internal/common';\nimport type { StorybookConfigRaw } from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\n\nimport { add } from '../../add.ts';\nimport type { CheckOptions, RunOptions } from '../types.ts';\nimport {\n  type StorysourceOptions,\n  addonStorysourceCodePanel,\n} from './addon-storysource-code-panel.ts';\n\nvi.mock('../../add');\n\nvi.mock('storybook/internal/common', async (importOriginal) => {\n  const actual = (await importOriginal()) as any;\n  return {\n    ...actual,\n    removeAddon: vi.fn(),\n  };\n});\n\n// Mock modules before any other imports or declarations\nvi.mock('node:fs/promises', async (importOriginal) => {\n  const mod = (await importOriginal()) as any;\n  return {\n    ...mod,\n    readFile: vi.fn().mockResolvedValue(\n      Buffer.from(dedent`\n        import React from 'react';\n        import { ThemeProvider, convert, themes } from 'storybook/theming';\n\n        export const parameters = {\n          storySort: {\n            order: ['Examples', 'Docs', 'Demo'],\n          }\n        };\n\n        export const decorators = [\n          (StoryFn) => (\n            <ThemeProvider theme={convert(themes.light)}>\n              <StoryFn />\n            </ThemeProvider>\n          )\n        ];\n      `)\n    ),\n    writeFile: vi.fn(),\n  };\n});\n\nvi.mock('picocolors', () => {\n  return {\n    default: {\n      cyan: (str: string) => str,\n      yellow: (str: string) => str,\n      blue: (str: string) => str,\n    },\n  };\n});\n\n// Create mock package manager\nconst mockPackageManager = {} as JsPackageManager;\n\n// Set up test data\nconst baseCheckOptions: CheckOptions = {\n  packageManager: mockPackageManager,\n  mainConfig: {\n    stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n    addons: ['@storybook/addon-links'],\n  } as StorybookConfigRaw,\n  storybookVersion: '8.0.0',\n  configDir: '.storybook',\n  storiesPaths: [],\n  hasCsfFactoryPreview: false,\n};\n\ndescribe('addon-storysource-remove', () => {\n  beforeEach(() => {\n    mockPackageManager.runPackageCommand = vi.fn();\n    mockPackageManager.removeDependencies = vi.fn();\n    vi.clearAllMocks();\n  });\n\n  describe('check phase', () => {\n    it('returns null if storysource addon not found', async () => {\n      const result = await addonStorysourceCodePanel.check({\n        ...baseCheckOptions,\n      });\n      expect(result).toBeNull();\n    });\n\n    it('detects storysource addon when present', async () => {\n      const result = await addonStorysourceCodePanel.check({\n        ...baseCheckOptions,\n        mainConfig: {\n          stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n          addons: ['@storybook/addon-links', '@storybook/addon-storysource'],\n        } as StorybookConfigRaw,\n        mainConfigPath: '.storybook/main.js',\n        previewConfigPath: '.storybook/preview.js',\n      });\n\n      expect(result).toEqual({\n        hasStorysource: true,\n        hasDocs: false,\n      });\n    });\n\n    it('detects storysource addon when present as object', async () => {\n      const result = await addonStorysourceCodePanel.check({\n        ...baseCheckOptions,\n        mainConfig: {\n          stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n          addons: ['@storybook/addon-links', { name: '@storybook/addon-storysource' }],\n        } as StorybookConfigRaw,\n        mainConfigPath: '.storybook/main.js',\n        previewConfigPath: '.storybook/preview.js',\n      });\n\n      expect(result).toEqual({\n        hasStorysource: true,\n        hasDocs: false,\n      });\n    });\n\n    it('detects docs addon when present', async () => {\n      const result = await addonStorysourceCodePanel.check({\n        ...baseCheckOptions,\n        mainConfig: {\n          stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n          addons: ['@storybook/addon-storysource', '@storybook/addon-docs'],\n        } as StorybookConfigRaw,\n        mainConfigPath: '.storybook/main.js',\n        previewConfigPath: '.storybook/preview.js',\n      });\n\n      expect(result).toEqual({\n        hasStorysource: true,\n        hasDocs: true,\n      });\n    });\n  });\n\n  describe('run phase', () => {\n    it('does nothing if storysource addon not found', async () => {\n      await addonStorysourceCodePanel.run?.({\n        result: {\n          hasStorysource: false,\n          hasDocs: false,\n        },\n        packageManager: mockPackageManager as JsPackageManager,\n        configDir: '.storybook',\n      } as RunOptions<StorysourceOptions>);\n\n      expect(mockPackageManager.runPackageCommand).not.toHaveBeenCalled();\n    });\n\n    it('removes storysource addon and updates preview config', async () => {\n      const { removeAddon } = await import('storybook/internal/common');\n\n      await addonStorysourceCodePanel.run?.({\n        result: {\n          hasStorysource: true,\n          hasDocs: true,\n        },\n        packageManager: mockPackageManager as JsPackageManager,\n        previewConfigPath: '.storybook/preview.js',\n        configDir: '.storybook',\n      } as RunOptions<StorysourceOptions>);\n\n      // Verify removeAddon was called with correct arguments\n      expect(removeAddon).toHaveBeenCalledWith('@storybook/addon-storysource', {\n        configDir: '.storybook',\n        skipInstall: true,\n        packageManager: mockPackageManager,\n      });\n\n      expect(vi.mocked(add)).not.toHaveBeenCalled();\n\n      const writeFile = vi.mocked((await import('node:fs/promises')).writeFile);\n\n      const newConfig = writeFile.mock.calls[0][1];\n\n      expect(newConfig).toMatchInlineSnapshot(dedent`\n        \"import React from 'react';\n        import { ThemeProvider, convert, themes } from 'storybook/theming';\n\n        export const parameters = {\n          storySort: {\n            order: ['Examples', 'Docs', 'Demo'],\n          },\n\n          docs: {\n            codePanel: true\n          }\n        };\n\n        export const decorators = [\n          (StoryFn) => (\n            <ThemeProvider theme={convert(themes.light)}>\n              <StoryFn />\n            </ThemeProvider>\n          )\n        ];\"\n      `);\n    });\n\n    it('should add docs addon if it is not present', async () => {\n      await addonStorysourceCodePanel.run?.({\n        result: {\n          hasStorysource: true,\n          hasDocs: false,\n        },\n        packageManager: mockPackageManager as JsPackageManager,\n        previewConfigPath: '.storybook/preview.js',\n        configDir: '.storybook',\n        storybookVersion: '9.0.0',\n      } as RunOptions<StorysourceOptions>);\n\n      expect(vi.mocked(add)).toHaveBeenCalledWith('@storybook/addon-docs', {\n        configDir: '.storybook',\n        skipInstall: true,\n        skipPostinstall: true,\n        yes: true,\n      });\n    });\n\n    it('does nothing in dry run mode', async () => {\n      await addonStorysourceCodePanel.run?.({\n        result: {\n          hasStorysource: true,\n          hasDocs: true,\n        },\n        previewConfigPath: '.storybook/preview.js',\n        packageManager: mockPackageManager as JsPackageManager,\n        configDir: '.storybook',\n        dryRun: true,\n      } as RunOptions<StorysourceOptions>);\n\n      // Verify no actual changes were made\n      expect(mockPackageManager.runPackageCommand).not.toHaveBeenCalled();\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/addon-storysource-code-panel.ts",
    "content": "import { getAddonNames, removeAddon } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport picocolors from 'picocolors';\nimport { dedent } from 'ts-dedent';\n\nimport { add } from '../../add.ts';\nimport { updateMainConfig } from '../helpers/mainConfigFile.ts';\nimport type { Fix, RunOptions } from '../types.ts';\n\nexport interface StorysourceOptions {\n  hasStorysource: boolean;\n  hasDocs: boolean;\n}\n\nexport const addonStorysourceCodePanel: Fix<StorysourceOptions> = {\n  id: 'addon-storysource-code-panel',\n  link: 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#storysource-addon-removed',\n\n  async check({ mainConfigPath, mainConfig }) {\n    if (!mainConfigPath) {\n      return null;\n    }\n\n    const addonNames = getAddonNames(mainConfig);\n    const hasStorysource = addonNames.includes('@storybook/addon-storysource');\n    const hasDocs = addonNames.includes('@storybook/addon-docs');\n\n    if (!hasStorysource) {\n      return null;\n    }\n\n    return {\n      hasStorysource,\n      hasDocs,\n    };\n  },\n\n  prompt: () => {\n    return dedent`\n      We'll remove @storybook/addon-storysource and enable the Code Panel instead.\n    `;\n  },\n\n  run: async (options: RunOptions<StorysourceOptions>) => {\n    const { result, dryRun = false, packageManager, configDir, previewConfigPath } = options;\n    const { hasStorysource, hasDocs } = result;\n    const errors: Array<{ file: string; error: Error }> = [];\n\n    if (!hasStorysource) {\n      return;\n    }\n\n    // Remove the addon\n    if (!dryRun) {\n      logger.debug('Removing @storybook/addon-storysource...');\n\n      await removeAddon('@storybook/addon-storysource', {\n        configDir,\n        skipInstall: true,\n        packageManager,\n      });\n\n      if (!hasDocs) {\n        logger.log('Installing @storybook/addon-docs...');\n\n        await add(`@storybook/addon-docs`, {\n          configDir,\n          packageManager: packageManager.type,\n          skipInstall: true,\n          skipPostinstall: true,\n          yes: true,\n        });\n      }\n\n      // Update preview config to enable code panel\n      if (previewConfigPath) {\n        try {\n          await updateMainConfig({ mainConfigPath: previewConfigPath, dryRun }, (previewConfig) => {\n            previewConfig.setFieldValue(['parameters', 'docs', 'codePanel'], true);\n          });\n        } catch (error) {\n          console.log(error);\n          errors.push({ file: previewConfigPath, error: error as Error });\n        }\n      } else {\n        logger.log('No preview config file found. Please manually add code panel parameters.');\n        logger.log(dedent`\n          Add this to your .storybook/preview.js:\n          export const parameters = {\n            docs: {\n              codePanel: true,\n            },\n          };`);\n      }\n    }\n\n    if (errors.length > 0) {\n      // eslint-disable-next-line local-rules/no-uncategorized-errors\n      throw new Error(\n        `Failed to process ${errors.length} files:\\n${errors\n          .map(({ file, error }) => `- ${file}: ${error.message}`)\n          .join('\\n')}`\n      );\n    }\n  },\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/consolidated-imports.test.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\n\nimport { describe, expect, it, vi } from 'vitest';\n\nimport { JsPackageManager, versions } from 'storybook/internal/common';\n\nimport { consolidatedImports, transformPackageJsonFiles } from './consolidated-imports.ts';\n\n// mock picocolors yellow and cyan\nvi.mock('picocolors', () => {\n  return {\n    default: {\n      cyan: (str: string) => str,\n      red: (str: string) => str,\n    },\n  };\n});\n\nvi.mock('node:fs/promises');\nvi.mock('globby', () => ({\n  globby: vi.fn(),\n}));\n\nconst mockPackageJson = {\n  dependencies: {\n    '@storybook/react': '^7.0.0',\n    '@storybook/core-common': '^7.0.0',\n    react: '^18.0.0',\n  },\n  devDependencies: {\n    '@storybook/addon-essentials': '^7.0.0',\n    '@storybook/manager-api': '^7.0.0',\n    typescript: '^5.0.0',\n  },\n};\n\nconst mockPackageManager = vi.mocked(JsPackageManager.prototype);\n\nconst mockRunOptions = {\n  packageManager: mockPackageManager,\n  mainConfig: {} as any,\n  mainConfigPath: 'main.ts',\n  packageJson: mockPackageJson,\n  storiesPaths: [],\n  hasCsfFactoryPreview: false,\n};\n\nconst setupGlobby = async (files: string[]) => {\n  // eslint-disable-next-line depend/ban-dependencies\n  const { globby } = await import('globby');\n  vi.mocked(globby).mockResolvedValueOnce(files);\n};\n\nconst setupCheck = async (packageJsonContents: string, packageJsonFiles: string[]) => {\n  vi.mocked(readFile).mockImplementation(async (path: any) => {\n    const filePath = path.toString();\n    if (filePath.endsWith('package.json')) {\n      return packageJsonContents;\n    }\n    return '';\n  });\n  await setupGlobby(packageJsonFiles);\n\n  // Mock packageJsonPaths\n  Object.defineProperty(mockPackageManager, 'packageJsonPaths', {\n    value: packageJsonFiles,\n    writable: true,\n    configurable: true,\n  });\n\n  return consolidatedImports.check({\n    ...mockRunOptions,\n    storybookVersion: '8.0.0',\n  });\n};\n\ndescribe('check', () => {\n  it('should call globby with correct patterns for package.json files', async () => {\n    const filePath = 'test/package.json';\n    const contents = JSON.stringify(mockPackageJson);\n\n    await setupCheck(contents, [filePath]);\n\n    // The implementation doesn't call globby directly, it uses packageJsonPaths\n    // So we shouldn't expect globby to be called\n    expect(mockPackageManager.packageJsonPaths).toEqual([filePath]);\n  });\n\n  it('should detect consolidated packages in package.json', async () => {\n    const contents = JSON.stringify(mockPackageJson);\n    const filePath = 'test/package.json';\n\n    const result = await setupCheck(contents, [filePath]);\n    expect(result).toMatchObject({\n      consolidatedDeps: expect.any(Set),\n    });\n    expect(result?.consolidatedDeps).toContain('@storybook/core-common');\n    expect(result?.consolidatedDeps).toContain('@storybook/manager-api');\n  });\n\n  it('should not detect non-consolidated packages in package.json', async () => {\n    const packageJsonWithoutConsolidated = {\n      dependencies: {\n        react: '^18.0.0',\n      },\n      devDependencies: {\n        typescript: '^5.0.0',\n      },\n    };\n    const contents = JSON.stringify(packageJsonWithoutConsolidated);\n    const filePath = 'test/package.json';\n\n    const result = await setupCheck(contents, [filePath]);\n    expect(result).toBeNull();\n  });\n});\n\ndescribe('transformPackageJsonFiles', () => {\n  it('should transform package.json files', async () => {\n    const contents = JSON.stringify(mockPackageJson);\n    const filePath = 'test/package.json';\n\n    vi.mocked(readFile).mockResolvedValueOnce(contents);\n\n    const errors = await transformPackageJsonFiles([filePath], false);\n\n    expect(errors).toHaveLength(0);\n    expect(writeFile).toHaveBeenCalledWith(\n      filePath,\n      expect.not.stringContaining('\"@storybook/core-common\": \"^8.0.0\"')\n    );\n  });\n\n  it('should add renamed packages to devDependencies when storybook is in devDependencies', async () => {\n    const pkgJson = {\n      dependencies: {\n        '@storybook/experimental-nextjs-vite': '^8.0.0',\n      },\n      devDependencies: {\n        storybook: '^9.0.0',\n      },\n    };\n    const contents = JSON.stringify(pkgJson);\n    const filePath = 'test/package.json';\n\n    vi.mocked(readFile).mockResolvedValueOnce(contents);\n\n    const errors = await transformPackageJsonFiles([filePath], false);\n\n    expect(errors).toHaveLength(0);\n    const written = JSON.parse(vi.mocked(writeFile).mock.calls[0][1] as string);\n    expect(written.devDependencies['@storybook/nextjs-vite']).toBe('^9.0.0');\n    expect(written.dependencies['@storybook/experimental-nextjs-vite']).toBeUndefined();\n  });\n\n  it('should add renamed packages to dependencies when storybook is in dependencies', async () => {\n    const pkgJson = {\n      dependencies: {\n        storybook: '^9.0.0',\n        '@storybook/experimental-nextjs-vite': '^8.0.0',\n      },\n    };\n    const contents = JSON.stringify(pkgJson);\n    const filePath = 'test/package.json';\n\n    vi.mocked(readFile).mockResolvedValueOnce(contents);\n\n    const errors = await transformPackageJsonFiles([filePath], false);\n\n    expect(errors).toHaveLength(0);\n    const written = JSON.parse(vi.mocked(writeFile).mock.calls[0][1] as string);\n    expect(written.dependencies['@storybook/nextjs-vite']).toBe('^9.0.0');\n    expect(written.dependencies['@storybook/experimental-nextjs-vite']).toBeUndefined();\n  });\n\n  it('should add renamed packages if storybook is not found', async () => {\n    const pkgJson = {\n      dependencies: {\n        '@storybook/experimental-nextjs-vite': '^7.0.0',\n      },\n    };\n    const contents = JSON.stringify(pkgJson);\n    const filePath = 'test/package.json';\n\n    vi.mocked(readFile).mockResolvedValueOnce(contents);\n\n    const errors = await transformPackageJsonFiles([filePath], false);\n\n    expect(errors).toHaveLength(0);\n    const written = JSON.parse(vi.mocked(writeFile).mock.calls[0][1] as string);\n    expect(written.devDependencies['@storybook/nextjs-vite']).toEqual(\n      versions['@storybook/nextjs-vite']\n    );\n    expect(written.dependencies?.['@storybook/nextjs-vite']).toBeUndefined();\n  });\n\n  it('should not write files in dry run mode', async () => {\n    const contents = JSON.stringify(mockPackageJson);\n    const filePath = 'test/package.json';\n\n    vi.mocked(readFile).mockResolvedValueOnce(contents);\n\n    const errors = await transformPackageJsonFiles([filePath], true);\n\n    expect(errors).toHaveLength(0);\n    expect(writeFile).not.toHaveBeenCalled();\n  });\n\n  it('should handle file read errors', async () => {\n    const filePath = 'test/package.json';\n    vi.mocked(readFile).mockRejectedValueOnce(new Error('Failed to read file'));\n\n    const errors = await transformPackageJsonFiles([filePath], false);\n\n    expect(errors).toHaveLength(1);\n    expect(errors[0]).toMatchObject({\n      file: filePath,\n      error: expect.any(Error),\n    });\n  });\n\n  it('should handle file write errors', async () => {\n    const contents = JSON.stringify(mockPackageJson);\n    const filePath = 'test/package.json';\n    vi.mocked(readFile).mockResolvedValueOnce(contents);\n    vi.mocked(writeFile).mockRejectedValueOnce(new Error('Failed to write file'));\n\n    const errors = await transformPackageJsonFiles([filePath], false);\n\n    expect(errors).toHaveLength(1);\n    expect(errors[0]).toMatchObject({\n      file: filePath,\n      error: expect.any(Error),\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/consolidated-imports.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\n\nimport { transformImportFiles, versions } from 'storybook/internal/common';\n\nimport { consolidatedPackages } from '../helpers/consolidated-packages.ts';\nimport type { Fix } from '../types.ts';\n\nexport interface ConsolidatedOptions {\n  consolidatedDeps: Set<keyof typeof consolidatedPackages>;\n}\n\nfunction transformPackageJson(content: string): string | null {\n  const packageJson = JSON.parse(content);\n  let hasChanges = false;\n\n  // Track new packages to add\n  const packagesToAdd = new Set<string>();\n\n  // Check both dependencies and devDependencies\n  const depTypes = ['dependencies', 'devDependencies', 'peerDependencies'] as const;\n\n  // Determine where storybook is installed and get its version\n  let storybookVersion: string | null = null;\n  let storybookDepType: (typeof depTypes)[number] | null = null;\n\n  for (const depType of depTypes) {\n    if (packageJson[depType]?.storybook) {\n      storybookVersion = packageJson[depType].storybook;\n      storybookDepType = depType;\n      break;\n    }\n  }\n\n  for (const depType of depTypes) {\n    if (packageJson[depType]) {\n      for (const [dep] of Object.entries(packageJson[depType])) {\n        if (dep in consolidatedPackages) {\n          const newPackage = consolidatedPackages[dep as keyof typeof consolidatedPackages];\n          // Only add to packagesToAdd if it's not being consolidated into storybook/* or if it's a sub-path of a consolidated package\n          if (!newPackage.startsWith('storybook/') && !newPackage.match(/(?:.*\\/){2,}/)) {\n            packagesToAdd.add(newPackage);\n          }\n          delete packageJson[depType][dep];\n          hasChanges = true;\n        }\n      }\n    }\n  }\n\n  // Add new packages to the same dependency type as storybook\n  if (packagesToAdd.size > 0) {\n    const version = storybookVersion ?? versions['@storybook/nextjs-vite'];\n    const depType = storybookDepType ?? 'devDependencies';\n    packageJson[depType] = packageJson[depType] || {};\n    for (const pkg of packagesToAdd) {\n      packageJson[depType][pkg] = version;\n    }\n    hasChanges = true;\n  }\n\n  return hasChanges ? JSON.stringify(packageJson, null, 2) : null;\n}\n\nexport const transformPackageJsonFiles = async (files: string[], dryRun: boolean) => {\n  const errors: Array<{ file: string; error: Error }> = [];\n\n  const { default: pLimit } = await import('p-limit');\n\n  const limit = pLimit(10);\n\n  await Promise.all(\n    files.map((file) =>\n      limit(async () => {\n        try {\n          const contents = await readFile(file, 'utf-8');\n          const transformed = transformPackageJson(contents);\n          if (!dryRun && transformed) {\n            await writeFile(file, transformed);\n          }\n        } catch (error) {\n          errors.push({ file, error: error as Error });\n        }\n      })\n    )\n  );\n\n  return errors;\n};\n\nexport const consolidatedImports: Fix<ConsolidatedOptions> = {\n  id: 'consolidated-imports',\n  link: 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#dropped-support-for-legacy-packages',\n  check: async ({ packageManager }) => {\n    const consolidatedDeps = new Set<keyof typeof consolidatedPackages>();\n    const affectedPackageJSONFiles = new Set<string>();\n\n    // Check all package.json files for consolidated packages\n    await Promise.all(\n      packageManager.packageJsonPaths.map(async (packageJsonPath) => {\n        const contents = await readFile(packageJsonPath, 'utf-8');\n        const packageJson = JSON.parse(contents);\n\n        // Check both dependencies and devDependencies\n        const allDeps = {\n          ...(packageJson.dependencies || {}),\n          ...(packageJson.devDependencies || {}),\n        };\n\n        // Add any consolidated packages to the set\n        let hasConsolidatedDeps = false;\n        Object.keys(allDeps).forEach((dep) => {\n          if (dep in consolidatedPackages) {\n            consolidatedDeps.add(dep as keyof typeof consolidatedPackages);\n            hasConsolidatedDeps = true;\n          }\n        });\n\n        if (hasConsolidatedDeps) {\n          affectedPackageJSONFiles.add(packageJsonPath);\n        }\n      })\n    );\n\n    if (consolidatedDeps.size === 0) {\n      return null;\n    }\n\n    return {\n      consolidatedDeps,\n    };\n  },\n  prompt: () => {\n    return \"We've detected Storybook packages that have been renamed or consolidated. We'll update these packages by scanning your codebase and updating any imports from these packages.\";\n  },\n  run: async ({ dryRun = false, packageManager, storiesPaths, configDir }) => {\n    const errors: Array<{ file: string; error: Error }> = [];\n\n    const packageJsonErrors = await transformPackageJsonFiles(\n      packageManager.packageJsonPaths,\n      dryRun\n    );\n    errors.push(...packageJsonErrors);\n\n    // eslint-disable-next-line depend/ban-dependencies\n    const { globby } = await import('globby');\n    const configFiles = await globby([`${configDir}/**/*`]);\n\n    const importErrors = await transformImportFiles(\n      [...storiesPaths, ...configFiles].filter(Boolean) as string[],\n      {\n        ...consolidatedPackages,\n        'storybook/internal/manager-api': 'storybook/manager-api',\n        'storybook/internal/preview-api': 'storybook/preview-api',\n        'storybook/internal/theming': 'storybook/theming',\n        'storybook/internal/theming/create': 'storybook/theming/create',\n        'storybook/internal/test': 'storybook/test',\n        'storybook/internal/actions': 'storybook/internal/actions',\n        'storybook/internal/actions/decorator': 'storybook/internal/actions/decorator',\n        'storybook/internal/highlight': 'storybook/internal/highlight',\n        'storybook/internal/viewport': 'storybook/internal/viewport',\n      },\n      !!dryRun\n    );\n\n    errors.push(...importErrors);\n\n    if (errors.length > 0) {\n      // eslint-disable-next-line local-rules/no-uncategorized-errors\n      throw new Error(\n        `Failed to process ${errors.length} files:\\n${errors\n          .map(({ file, error }) => `- ${file}: ${error.message}`)\n          .join('\\n')}`\n      );\n    }\n  },\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/eslint-plugin.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport * as cliImports from 'storybook/internal/cli';\nimport type { PackageJson } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { makePackageManager } from '../helpers/testing-helpers.ts';\nimport { eslintPlugin } from './eslint-plugin.ts';\n\nconst defaultHasEslintValues = {\n  hasEslint: false,\n  eslintConfigFile: undefined,\n  isStorybookPluginInstalled: false,\n  isFlatConfig: false,\n  unsupportedExtension: undefined,\n};\n\nconst checkEslint = async ({ packageJson }: { packageJson: PackageJson }) => {\n  return eslintPlugin.check({\n    packageManager: makePackageManager(packageJson),\n    mainConfig: {} as any,\n    storybookVersion: '7.0.0',\n    storiesPaths: [],\n    hasCsfFactoryPreview: false,\n  });\n};\n\ndescribe('eslint-plugin fix', () => {\n  beforeEach(() => {\n    vi.spyOn(cliImports, 'extractEslintInfo').mockClear();\n  });\n\n  describe('should skip migration when', () => {\n    it('project does not have eslint installed', async () => {\n      const packageJson = { dependencies: {} };\n      vi.spyOn(cliImports, 'extractEslintInfo').mockImplementation(async () => {\n        return { ...defaultHasEslintValues, hasEslint: false };\n      });\n\n      await expect(\n        checkEslint({\n          packageJson,\n        })\n      ).resolves.toBeFalsy();\n    });\n\n    it('project already contains eslint-plugin-storybook dependency', async () => {\n      const packageJson = { dependencies: { 'eslint-plugin-storybook': '^0.0.0' } };\n\n      vi.spyOn(cliImports, 'extractEslintInfo').mockImplementation(async () => {\n        return { ...defaultHasEslintValues, hasEslint: true, isStorybookPluginInstalled: true };\n      });\n\n      await expect(\n        checkEslint({\n          packageJson,\n        })\n      ).resolves.toBeFalsy();\n    });\n  });\n\n  describe('when project does not contain eslint-plugin-storybook but has eslint installed', () => {\n    const packageJson = { dependencies: { '@storybook/react': '^6.2.0', eslint: '^7.0.0' } };\n\n    describe('should no-op and warn when', () => {\n      it('.eslintrc is not found', async () => {\n        const loggerSpy = vi.spyOn(logger, 'warn').mockImplementation(() => {});\n\n        vi.spyOn(cliImports, 'extractEslintInfo').mockImplementation(async () => {\n          return { ...defaultHasEslintValues, hasEslint: true, eslintConfigFile: undefined };\n        });\n\n        const result = await checkEslint({\n          packageJson,\n        });\n\n        expect(loggerSpy).toHaveBeenCalledWith('Unable to find eslint config file, skipping');\n\n        expect(result).toBeFalsy();\n        loggerSpy.mockRestore();\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/eslint-plugin.ts",
    "content": "import {\n  SUPPORTED_ESLINT_EXTENSIONS,\n  configureEslintPlugin,\n  extractEslintInfo,\n} from 'storybook/internal/cli';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { dedent } from 'ts-dedent';\n\nimport type { Fix } from '../types.ts';\n\ninterface EslintPluginRunOptions {\n  eslintConfigFile: string;\n  unsupportedExtension?: string;\n  isFlatConfig: boolean;\n}\n\n/**\n * Does the user not have eslint-plugin-storybook installed?\n *\n * If so:\n *\n * - Install it, and if possible configure it\n */\nexport const eslintPlugin: Fix<EslintPluginRunOptions> = {\n  id: 'eslintPlugin',\n  link: 'https://storybook.js.org/docs/configure/integration/eslint-plugin',\n\n  async check({ packageManager }) {\n    const {\n      hasEslint,\n      eslintConfigFile,\n      isStorybookPluginInstalled,\n      unsupportedExtension,\n      isFlatConfig,\n    } = await extractEslintInfo(packageManager);\n\n    if (isStorybookPluginInstalled || !hasEslint) {\n      return null;\n    }\n\n    if (!eslintConfigFile) {\n      logger.warn('Unable to find eslint config file, skipping');\n      return null;\n    }\n    return { eslintConfigFile, unsupportedExtension, isFlatConfig };\n  },\n\n  prompt() {\n    return `We'll install and configure the Storybook ESLint plugin for you.`;\n  },\n\n  async run({\n    result: { eslintConfigFile, unsupportedExtension, isFlatConfig },\n    packageManager,\n    dryRun,\n    storybookVersion,\n  }) {\n    const deps = [`eslint-plugin-storybook@${storybookVersion}`];\n\n    logger.debug(`Adding dependencies: ${deps}`);\n    if (!dryRun) {\n      await packageManager.addDependencies({ type: 'devDependencies', skipInstall: true }, deps);\n    }\n\n    if (!dryRun && unsupportedExtension) {\n      logger.warn(dedent`\n          The plugin was successfully installed but failed to be configured.\n          \n          Found an eslint config file with an unsupported automigration format: .eslintrc.${unsupportedExtension}.\n          The supported formats for this automigration are: ${SUPPORTED_ESLINT_EXTENSIONS.join(\n            ', '\n          )}.\n\n          Please refer to https://storybook.js.org/docs/configure/integration/eslint-plugin#configuration-eslintrc to finish setting up the plugin manually.\n      `);\n      return;\n    }\n\n    if (!dryRun) {\n      await configureEslintPlugin({ eslintConfigFile, packageManager, isFlatConfig });\n    }\n  },\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { bannerComment, containsDirnameUsage } from '../helpers/mainConfigFile.ts';\nimport { fixFauxEsmRequire } from './fix-faux-esm-require.ts';\n\nvi.mock('node:fs/promises', async (importOriginal) => ({\n  ...(await importOriginal<typeof import('node:fs/promises')>()),\n  readFile: vi.fn(),\n  writeFile: vi.fn(),\n}));\n\ndescribe('fix-faux-esm-require', () => {\n  const mockReadFile = vi.mocked(readFile);\n  const mockWriteFile = vi.mocked(writeFile);\n\n  beforeEach(() => {\n    vi.clearAllMocks();\n  });\n\n  describe('check', () => {\n    it('should return null if no mainConfigPath', async () => {\n      const result = await fixFauxEsmRequire.check({\n        mainConfigPath: undefined,\n      } as any);\n\n      expect(result).toBeNull();\n    });\n\n    it('should return null if file is not ESM', async () => {\n      const contentWithoutESM = `\n        const config = require('./config');\n        module.exports = config;\n      `;\n\n      mockReadFile.mockResolvedValue(contentWithoutESM);\n\n      const result = await fixFauxEsmRequire.check({\n        mainConfigPath: 'main.js',\n      } as any);\n\n      expect(result).toBeNull();\n    });\n\n    it('should return null if file already has require banner', async () => {\n      const contentWithBanner = `\n        import { createRequire } from \"node:module\";\n        ${bannerComment}\n        const config = require('./some-config');\n      `;\n\n      mockReadFile.mockResolvedValue(contentWithBanner);\n\n      const result = await fixFauxEsmRequire.check({\n        mainConfigPath: 'main.js',\n      } as any);\n\n      expect(result).toBeNull();\n    });\n\n    it('should return null if file does not contain require usage', async () => {\n      const contentWithoutRequire = `\n        import { addons } from '@storybook/addon-essentials';\n        export default {\n          addons: ['@storybook/addon-essentials'],\n        };\n      `;\n\n      mockReadFile.mockResolvedValue(contentWithoutRequire);\n\n      const result = await fixFauxEsmRequire.check({\n        mainConfigPath: 'main.js',\n      } as any);\n\n      expect(result).toBeNull();\n    });\n\n    it('should return BannerConfig if file is ESM with require usage', async () => {\n      const contentWithRequire = `\n        import { addons } from '@storybook/addon-essentials';\n        const config = require('./some-config');\n        export default {\n          addons: ['@storybook/addon-essentials'],\n        };\n      `;\n\n      mockReadFile.mockResolvedValue(contentWithRequire);\n\n      const result = await fixFauxEsmRequire.check({\n        mainConfigPath: 'main.js',\n      } as any);\n\n      expect(result).toEqual({\n        hasRequireUsage: true,\n        hasUnderscoreDirname: false,\n        hasUnderscoreFilename: false,\n      });\n    });\n\n    it('should return BannerConfig if file is ESM with __dirname usage but no definition', async () => {\n      const contentWithDirname = `\n        import { addons } from '@storybook/addon-essentials';\n        const configPath = path.join(__dirname, 'config.js');\n        export default {\n          addons: ['@storybook/addon-essentials'],\n        };\n      `;\n\n      mockReadFile.mockResolvedValue(contentWithDirname);\n\n      const result = await fixFauxEsmRequire.check({\n        mainConfigPath: 'main.js',\n      } as any);\n\n      expect(result).toEqual({\n        hasRequireUsage: false,\n        hasUnderscoreDirname: true,\n        hasUnderscoreFilename: false,\n      });\n    });\n\n    it('should detect TypeScript config files', async () => {\n      const contentWithRequire = `\n        import { addons } from '@storybook/addon-essentials';\n        const config = require('./some-config');\n        export default {\n          addons: ['@storybook/addon-essentials'],\n        };\n      `;\n\n      mockReadFile.mockResolvedValue(contentWithRequire);\n\n      const result = await fixFauxEsmRequire.check({\n        mainConfigPath: 'main.ts',\n      } as any);\n\n      expect(result).toEqual({\n        hasRequireUsage: true,\n        hasUnderscoreDirname: false,\n        hasUnderscoreFilename: false,\n      });\n    });\n  });\n\n  describe('containsDirnameUsage', () => {\n    it('should detect __dirname in actual code', () => {\n      const content = `\n        const path = require('path');\n        const configPath = path.join(__dirname, 'config.js');\n      `;\n      expect(containsDirnameUsage(content)).toBe(true);\n    });\n\n    it('should not detect __dirname in double-quoted strings', () => {\n      const content = `\n        const message = \"This is __dirname in a string\";\n        const another = \"path/to/__dirname/file.js\";\n      `;\n      expect(containsDirnameUsage(content)).toBe(false);\n    });\n\n    it('should not detect __dirname in single-quoted strings', () => {\n      const content = `\n        const message = 'This is __dirname in a string';\n        const another = 'path/to/__dirname/file.js';\n      `;\n      expect(containsDirnameUsage(content)).toBe(false);\n    });\n\n    it('should not detect __dirname in backtick strings', () => {\n      const content = `\n        const message = \\`This is __dirname in a string\\`;\n        const another = \\`path/to/__dirname/file.js\\`;\n      `;\n      expect(containsDirnameUsage(content)).toBe(false);\n    });\n\n    it('should not detect __dirname in single-line comments', () => {\n      const content = `\n        // This is __dirname in a comment\n        const config = { addons: [] };\n      `;\n      expect(containsDirnameUsage(content)).toBe(false);\n    });\n\n    it('should not detect __dirname in multi-line comments', () => {\n      const content = `\n        /* This is __dirname in a \n           multi-line comment */\n        const config = { addons: [] };\n      `;\n      expect(containsDirnameUsage(content)).toBe(false);\n    });\n\n    it('should handle // inside strings correctly', () => {\n      const content = `\n        const url = \"https://example.com//path\";\n        const config = { addons: [] };\n      `;\n      expect(containsDirnameUsage(content)).toBe(false);\n    });\n\n    it('should detect __dirname when it appears after string with //', () => {\n      const content = `\n        const url = \"https://example.com//path\";\n        const configPath = path.join(__dirname, 'config.js');\n      `;\n      expect(containsDirnameUsage(content)).toBe(true);\n    });\n\n    it('should handle escaped quotes in strings', () => {\n      const content = `\n        const message = \"This is \\\\\"__dirname\\\\\" in a string\";\n        const config = { addons: [] };\n      `;\n      expect(containsDirnameUsage(content)).toBe(false);\n    });\n\n    it('should handle mixed quote types', () => {\n      const content = `\n        const double = \"This is __dirname in double quotes\";\n        const single = 'This is __dirname in single quotes';\n        const backtick = \\`This is __dirname in backticks\\`;\n        const actual = path.join(__dirname, 'config.js');\n      `;\n      expect(containsDirnameUsage(content)).toBe(true);\n    });\n  });\n\n  describe('run', () => {\n    it('should add require banner to file', async () => {\n      const originalContent = `\n        import { addons } from '@storybook/addon-essentials';\n        const config = require('./some-config');\n        export default {\n          addons: ['@storybook/addon-essentials'],\n        };\n      `;\n\n      mockReadFile.mockResolvedValue(originalContent);\n\n      await fixFauxEsmRequire.run({\n        dryRun: false,\n        mainConfigPath: 'main.js',\n        result: {\n          hasRequireUsage: true,\n          hasUnderscoreDirname: false,\n          hasUnderscoreFilename: false,\n        },\n      } as any);\n\n      expect(mockWriteFile).toHaveBeenCalledWith(\n        'main.js',\n        expect.stringContaining('import { createRequire } from \"node:module\"')\n      );\n    });\n\n    it('should add __dirname support when needed', async () => {\n      const originalContent = `\n        import { addons } from '@storybook/addon-essentials';\n        const config = require('./some-config');\n        const configPath = path.join(__dirname, 'config.js');\n        export default {\n          addons: ['@storybook/addon-essentials'],\n        };\n      `;\n\n      mockReadFile.mockResolvedValue(originalContent);\n\n      await fixFauxEsmRequire.run({\n        dryRun: false,\n        mainConfigPath: 'main.js',\n        result: {\n          hasRequireUsage: true,\n          hasUnderscoreDirname: true,\n          hasUnderscoreFilename: false,\n        },\n      } as any);\n\n      const writtenContent = mockWriteFile.mock.calls[0][1];\n      expect(writtenContent).toMatchInlineSnapshot(`\n        \"\n                import { fileURLToPath } from \"node:url\";\n                import { dirname } from \"node:path\";\n                import { createRequire } from \"node:module\";\n                import { addons } from '@storybook/addon-essentials';\n                const __filename = fileURLToPath(import.meta.url);\n                const __dirname = dirname(__filename);\n                const require = createRequire(import.meta.url);\n                const config = require('./some-config');\n                const configPath = path.join(__dirname, 'config.js');\n                export default {\n                  addons: ['@storybook/addon-essentials'],\n                };\n              \"\n      `);\n    });\n\n    it('should not add duplicate imports when they already exist', async () => {\n      const originalContent = `\n        import { dirname } from \"node:path\";\n        import { addons } from '@storybook/addon-essentials';\n        const config = require('./some-config');\n        const configPath = path.join(__dirname, 'config.js');\n        export default {\n          addons: ['@storybook/addon-essentials'],\n        };\n      `;\n\n      mockReadFile.mockResolvedValue(originalContent);\n\n      await fixFauxEsmRequire.run({\n        dryRun: false,\n        mainConfigPath: 'main.js',\n        result: {\n          hasRequireUsage: true,\n          hasUnderscoreDirname: true,\n          hasUnderscoreFilename: false,\n        },\n      } as any);\n\n      const writtenContent = mockWriteFile.mock.calls[0][1];\n\n      expect(writtenContent).toMatchInlineSnapshot(`\n        \"\n                import { fileURLToPath } from \"node:url\";\n                import { createRequire } from \"node:module\";\n                import { dirname } from \"node:path\";\n                import { addons } from '@storybook/addon-essentials';\n                const __filename = fileURLToPath(import.meta.url);\n                const __dirname = dirname(__filename);\n                const require = createRequire(import.meta.url);\n                const config = require('./some-config');\n                const configPath = path.join(__dirname, 'config.js');\n                export default {\n                  addons: ['@storybook/addon-essentials'],\n                };\n              \"\n      `);\n    });\n\n    it('should not write file in dry run mode', async () => {\n      await fixFauxEsmRequire.run({\n        dryRun: true,\n        mainConfigPath: 'main.js',\n        result: {\n          hasRequireUsage: true,\n          hasUnderscoreDirname: false,\n          hasUnderscoreFilename: false,\n        },\n      } as any);\n\n      expect(mockWriteFile).not.toHaveBeenCalled();\n    });\n\n    it('should not add duplicate __filename/__dirname declarations when they already exist', async () => {\n      const originalContent = `\n        import { addons } from '@storybook/addon-essentials';\n        const __filename = 'existing-filename';\n        const __dirname = 'existing-dirname';\n        const config = require('./some-config');\n        const configPath = path.join(__dirname, 'config.js');\n        export default {\n          addons: ['@storybook/addon-essentials'],\n        };\n      `;\n\n      mockReadFile.mockResolvedValue(originalContent);\n\n      await fixFauxEsmRequire.run({\n        dryRun: false,\n        mainConfigPath: 'main.js',\n        result: {\n          hasRequireUsage: true,\n          hasUnderscoreDirname: true,\n          hasUnderscoreFilename: true,\n        },\n      } as any);\n\n      const writtenContent = mockWriteFile.mock.calls[0][1];\n      expect(writtenContent).toMatchInlineSnapshot(`\n        \"\n                import { fileURLToPath } from \"node:url\";\n                import { dirname } from \"node:path\";\n                import { createRequire } from \"node:module\";\n                import { addons } from '@storybook/addon-essentials';\n                const require = createRequire(import.meta.url);\n                const __filename = 'existing-filename';\n                const __dirname = 'existing-dirname';\n                const config = require('./some-config');\n                const configPath = path.join(__dirname, 'config.js');\n                export default {\n                  addons: ['@storybook/addon-essentials'],\n                };\n              \"\n      `);\n    });\n\n    it('should not add duplicate require declaration when it already exists', async () => {\n      const originalContent = `\n        import { addons } from '@storybook/addon-essentials';\n        const require = createRequire(import.meta.url);\n        const config = require('./some-config');\n        export default {\n          addons: ['@storybook/addon-essentials'],\n        };\n      `;\n\n      mockReadFile.mockResolvedValue(originalContent);\n\n      await fixFauxEsmRequire.run({\n        dryRun: false,\n        mainConfigPath: 'main.js',\n        result: {\n          hasRequireUsage: true,\n          hasUnderscoreDirname: false,\n          hasUnderscoreFilename: false,\n        },\n      } as any);\n\n      const writtenContent = mockWriteFile.mock.calls[0][1];\n      expect(writtenContent).toMatchInlineSnapshot(`\n        \"\n                import { createRequire } from \"node:module\";\n                import { addons } from '@storybook/addon-essentials';\n                const require = createRequire(import.meta.url);\n                const config = require('./some-config');\n                export default {\n                  addons: ['@storybook/addon-essentials'],\n                };\n              \"\n      `);\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\n\nimport { types as t } from 'storybook/internal/babel';\n\nimport { dedent } from 'ts-dedent';\n\nimport {\n  type BannerConfig,\n  bannerComment,\n  containsDirnameUsage,\n  containsESMUsage,\n  containsFilenameUsage,\n  containsRequireUsage,\n  hasRequireBanner,\n  updateMainConfig,\n} from '../helpers/mainConfigFile.ts';\nimport type { Fix } from '../types.ts';\n\n/**\n * Checks if a variable declaration with the given identifier name exists in the program body.\n * Covers var/let/const declarations and assignment patterns.\n */\nfunction hasExistingDeclaration(program: t.Program, identifierName: string): boolean {\n  return program.body.some((node) => {\n    // Check variable declarations (const, let, var)\n    if (t.isVariableDeclaration(node)) {\n      return node.declarations.some((decl) => {\n        if (t.isVariableDeclarator(decl) && t.isIdentifier(decl.id)) {\n          return decl.id.name === identifierName;\n        }\n        return false;\n      });\n    }\n\n    // Check export named declarations with variable declarations\n    if (\n      t.isExportNamedDeclaration(node) &&\n      node.declaration &&\n      t.isVariableDeclaration(node.declaration)\n    ) {\n      return node.declaration.declarations.some((decl) => {\n        if (t.isVariableDeclarator(decl) && t.isIdentifier(decl.id)) {\n          return decl.id.name === identifierName;\n        }\n        return false;\n      });\n    }\n\n    // Check function declarations\n    if (t.isFunctionDeclaration(node) && t.isIdentifier(node.id)) {\n      return node.id.name === identifierName;\n    }\n\n    // Check export named declarations with function declarations\n    if (\n      t.isExportNamedDeclaration(node) &&\n      node.declaration &&\n      t.isFunctionDeclaration(node.declaration)\n    ) {\n      return t.isIdentifier(node.declaration.id) && node.declaration.id.name === identifierName;\n    }\n\n    return false;\n  });\n}\n\nexport const fixFauxEsmRequire = {\n  id: 'fix-faux-esm-require',\n  link: 'https://storybook.js.org/docs/faq#how-do-i-fix-module-resolution-in-special-environments',\n\n  async check({ mainConfigPath }) {\n    if (!mainConfigPath) {\n      return null;\n    }\n\n    // Read the raw file content to check for ESM syntax and require usage\n    const content = await readFile(mainConfigPath, 'utf-8');\n\n    const isESM = containsESMUsage(content);\n    const isWithBanner = hasRequireBanner(content);\n\n    // Check if the file is ESM format based on content\n    if (!isESM) {\n      return null;\n    }\n\n    // Check if the file already has the require banner\n    if (isWithBanner) {\n      return null;\n    }\n\n    // Analyze what compatibility features are needed\n    const hasRequireUsage = containsRequireUsage(content);\n    const hasUnderscoreFilename = containsFilenameUsage(content);\n    const hasUnderscoreDirname = containsDirnameUsage(content);\n\n    // Check if any compatibility features are needed\n    if (hasRequireUsage || hasUnderscoreFilename || hasUnderscoreDirname) {\n      return {\n        hasRequireUsage,\n        hasUnderscoreDirname,\n        hasUnderscoreFilename,\n      };\n    }\n\n    return null;\n  },\n\n  prompt() {\n    return dedent`Main config is ESM but uses 'require' or '__dirname'. This will break in Storybook 10; Adding compatibility banner`;\n  },\n\n  async run({ dryRun, mainConfigPath, result }) {\n    if (dryRun) {\n      return;\n    }\n\n    const { hasRequireUsage, hasUnderscoreDirname, hasUnderscoreFilename } = result;\n\n    await updateMainConfig({ mainConfigPath, dryRun: !!dryRun }, (mainConfig) => {\n      // Only add imports for symbols that are actually used\n      if (hasRequireUsage) {\n        mainConfig.setImport(['createRequire'], 'node:module');\n      }\n      if (hasUnderscoreDirname) {\n        mainConfig.setImport(['dirname'], 'node:path');\n      }\n      if (hasUnderscoreFilename || hasUnderscoreDirname) {\n        mainConfig.setImport(['fileURLToPath'], 'node:url');\n      }\n\n      // Find the index after the last import declaration\n      const body = mainConfig._ast.program.body;\n      let lastImportIndex = -1;\n      for (let i = 0; i < body.length; i++) {\n        if (t.isImportDeclaration(body[i])) {\n          lastImportIndex = i;\n        }\n      }\n      const insertIndex = lastImportIndex + 1;\n\n      // Check for existing declarations before inserting\n      const hasExistingFilename = hasExistingDeclaration(mainConfig._ast.program, '__filename');\n      const hasExistingDirname = hasExistingDeclaration(mainConfig._ast.program, '__dirname');\n      const hasExistingRequire = hasExistingDeclaration(mainConfig._ast.program, 'require');\n\n      // Add __filename and __dirname if used and not already declared\n      if (hasUnderscoreFilename || hasUnderscoreDirname) {\n        const declarationsToInsert: t.Statement[] = [];\n        let insertOffset = 0;\n\n        // Add __filename declaration if needed and not already exists\n        // Note: __filename is always needed if __dirname is used, since __dirname depends on __filename\n        if ((hasUnderscoreFilename || hasUnderscoreDirname) && !hasExistingFilename) {\n          const filenameDeclaration = t.variableDeclaration('const', [\n            t.variableDeclarator(\n              t.identifier('__filename'),\n              t.callExpression(t.identifier('fileURLToPath'), [\n                t.memberExpression(\n                  t.metaProperty(t.identifier('import'), t.identifier('meta')),\n                  t.identifier('url')\n                ),\n              ])\n            ),\n          ]);\n          declarationsToInsert.push(filenameDeclaration);\n          insertOffset++;\n        }\n\n        // Add __dirname declaration if needed and not already exists\n        if (hasUnderscoreDirname && !hasExistingDirname) {\n          const dirnameDeclaration = t.variableDeclaration('const', [\n            t.variableDeclarator(\n              t.identifier('__dirname'),\n              t.callExpression(t.identifier('dirname'), [t.identifier('__filename')])\n            ),\n          ]);\n          declarationsToInsert.push(dirnameDeclaration);\n          insertOffset++;\n        }\n\n        // Insert declarations after imports\n        declarationsToInsert.forEach((declaration, index) => {\n          body.splice(insertIndex + index, 0, declaration);\n        });\n      }\n\n      // add require if used and not already declared\n      if (hasRequireUsage && !hasExistingRequire) {\n        const requireDeclaration = t.variableDeclaration('const', [\n          t.variableDeclarator(\n            t.identifier('require'),\n            t.callExpression(t.identifier('createRequire'), [\n              t.memberExpression(\n                t.metaProperty(t.identifier('import'), t.identifier('meta')),\n                t.identifier('url')\n              ),\n            ])\n          ),\n        ]);\n\n        // Calculate insert position: after imports and after any __filename/__dirname declarations that were added\n        const filenameAdded =\n          (hasUnderscoreFilename || hasUnderscoreDirname) && !hasExistingFilename;\n        const dirnameAdded = hasUnderscoreDirname && !hasExistingDirname;\n        const declarationsAdded = (filenameAdded ? 1 : 0) + (dirnameAdded ? 1 : 0);\n        const currentInsertIndex = insertIndex + declarationsAdded;\n        body.splice(currentInsertIndex, 0, requireDeclaration);\n      }\n    });\n\n    const content = await readFile(mainConfigPath, 'utf-8');\n    const newContent = [bannerComment, content].join('\\n');\n    await writeFile(mainConfigPath, newContent);\n  },\n} satisfies Fix<BannerConfig>;\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/index.ts",
    "content": "import { csfFactories } from '../../codemod/csf-factories.ts';\nimport type { CommandFix, Fix } from '../types.ts';\nimport { addonA11yAddonTest } from './addon-a11y-addon-test.ts';\nimport { addonA11yParameters } from './addon-a11y-parameters.ts';\nimport { addonExperimentalTest } from './addon-experimental-test.ts';\nimport { addonGlobalsApi } from './addon-globals-api.ts';\nimport { addonMdxGfmRemove } from './addon-mdx-gfm-remove.ts';\nimport { addonStorysourceCodePanel } from './addon-storysource-code-panel.ts';\nimport { consolidatedImports } from './consolidated-imports.ts';\nimport { eslintPlugin } from './eslint-plugin.ts';\nimport { fixFauxEsmRequire } from './fix-faux-esm-require.ts';\nimport { initialGlobals } from './initial-globals.ts';\nimport { migrateAddonConsole } from './migrate-addon-console.ts';\nimport { nextjsToNextjsVite } from './nextjs-to-nextjs-vite.ts';\nimport { removeAddonInteractions } from './remove-addon-interactions.ts';\nimport { removeDocsAutodocs } from './remove-docs-autodocs.ts';\nimport { removeEssentials } from './remove-essentials.ts';\nimport { rendererToFramework } from './renderer-to-framework.ts';\nimport { rnstorybookConfig } from './rnstorybook-config.ts';\nimport { storybookPackageNameConflict } from './storybook-package-name-conflict.ts';\nimport { upgradeStorybookRelatedDependencies } from './upgrade-storybook-related-dependencies.ts';\nimport { wrapGetAbsolutePath } from './wrap-getAbsolutePath.ts';\n\nexport * from '../types.ts';\n\nexport const allFixes: Fix[] = [\n  eslintPlugin,\n  addonMdxGfmRemove,\n  addonStorysourceCodePanel,\n  upgradeStorybookRelatedDependencies,\n  initialGlobals,\n  addonGlobalsApi,\n  addonA11yAddonTest,\n  consolidatedImports,\n  addonExperimentalTest,\n  rnstorybookConfig,\n  migrateAddonConsole,\n  nextjsToNextjsVite,\n  removeAddonInteractions,\n  rendererToFramework,\n  removeEssentials,\n  addonA11yParameters,\n  removeDocsAutodocs,\n  wrapGetAbsolutePath,\n  fixFauxEsmRequire,\n  storybookPackageNameConflict,\n];\n\nexport const initFixes: Fix[] = [eslintPlugin];\n\n// These are specific fixes that only occur when triggered on command, and are hidden otherwise.\n// e.g. npx storybook automigrate csf-factories\nexport const commandFixes: CommandFix[] = [csfFactories];\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/initial-globals.test.ts",
    "content": "import * as fsp from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { expect, it, vi } from 'vitest';\n\nimport { initialGlobals } from './initial-globals.ts';\n\nvi.mock('node:fs/promises', async () => import('../../../../../__mocks__/fs/promises.ts'));\n\nconst previewConfigPath = join('.storybook', 'preview.js');\nconst check = async (previewContents: string) => {\n  vi.mocked<typeof import('../../../../../__mocks__/fs/promises')>(fsp as any).__setMockFiles({\n    [previewConfigPath]: previewContents,\n  });\n  return initialGlobals.check({\n    packageManager: {} as any,\n    configDir: '',\n    mainConfig: {} as any,\n    storybookVersion: '8.0',\n    previewConfigPath,\n    storiesPaths: [],\n    hasCsfFactoryPreview: false,\n  });\n};\n\nit('no globals setting', async () => {\n  await expect(check(`export default { tags: ['a', 'b']}`)).resolves.toBeFalsy();\n});\n\nit('initialGlobals setting', async () => {\n  await expect(check(`export default { initialGlobals: { a:  1 } }`)).resolves.toBeFalsy();\n});\n\nit('globals setting', async () => {\n  await expect(check(`export default { globals: { a:  1 } }`)).resolves.toBeTruthy();\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/initial-globals.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\n\nimport type { types } from 'storybook/internal/babel';\nimport type { ConfigFile } from 'storybook/internal/csf-tools';\nimport { formatConfig, loadConfig } from 'storybook/internal/csf-tools';\n\nimport picocolors from 'picocolors';\n\nimport type { Fix } from '../types.ts';\n\ninterface Options {\n  previewConfig: ConfigFile;\n  previewConfigPath: string;\n  globals: types.Expression;\n}\n\n/** Rename preview.js globals to initialGlobals */\nexport const initialGlobals: Fix<Options> = {\n  id: 'initial-globals',\n  link: 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#previewjs-globals-renamed-to-initialglobals',\n\n  async check({ previewConfigPath }) {\n    if (!previewConfigPath) {\n      return null;\n    }\n\n    const previewConfig = loadConfig((await readFile(previewConfigPath)).toString()).parse();\n    const globals = previewConfig.getFieldNode(['globals']) as types.Expression;\n\n    if (!globals) {\n      return null;\n    }\n\n    return { globals, previewConfig, previewConfigPath };\n  },\n\n  prompt() {\n    return `Rename ${picocolors.cyan('globals')} to ${picocolors.cyan('initialGlobals')} in preview.js?`;\n  },\n\n  async run({ dryRun, result }) {\n    result.previewConfig.removeField(['globals']);\n    result.previewConfig.setFieldNode(['initialGlobals'], result.globals);\n    if (!dryRun) {\n      await writeFile(result.previewConfigPath, formatConfig(result.previewConfig));\n    }\n  },\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/migrate-addon-console.test.ts",
    "content": "import { readFileSync, writeFileSync } from 'node:fs';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { getAddonNames, removeAddon } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { dedent } from 'ts-dedent';\n\nimport type { CheckOptions, RunOptions } from '../types.ts';\nimport {\n  type MigrateAddonConsoleOptions,\n  migrateAddonConsole,\n  transformPreviewFile,\n} from './migrate-addon-console.ts';\n\n// Mock external dependencies\nvi.mock('storybook/internal/common', async (importOriginal) => {\n  const mod = (await importOriginal()) as any;\n  return {\n    ...mod,\n    getAddonNames: vi.fn(),\n    removeAddon: vi.fn(),\n    formatFileContent: vi.fn((_path: string, content: string) => content),\n  };\n});\n\nvi.mock('storybook/internal/node-logger', async (importOriginal) => {\n  const mod = (await importOriginal()) as any;\n  return {\n    ...mod,\n    logger: {\n      debug: vi.fn(),\n    },\n  };\n});\n\nvi.mock('node:fs', async (importOriginal) => {\n  const mod = (await importOriginal()) as any;\n  return {\n    ...mod,\n    readFileSync: vi.fn(),\n    writeFileSync: vi.fn(),\n  };\n});\n\nconst loggerMock = vi.mocked(logger);\n\ndescribe('migrateAddonConsole', () => {\n  const configDir = '.storybook';\n  const mainConfig = {} as any;\n  const previewConfigPath = '.storybook/preview.ts';\n\n  beforeEach(() => {\n    vi.clearAllMocks();\n  });\n\n  describe('check', () => {\n    it('should return null if console addon is not present in config or dependencies', async () => {\n      vi.mocked(getAddonNames).mockReturnValue([]);\n      const packageManager = {\n        isDependencyInstalled: vi.fn().mockReturnValue(false),\n      } as any;\n\n      const result = await migrateAddonConsole.check({\n        mainConfig,\n        packageManager,\n        previewConfigPath,\n      } as CheckOptions);\n\n      expect(result).toBeNull();\n      expect(packageManager.isDependencyInstalled).toHaveBeenCalledWith('@storybook/addon-console');\n    });\n\n    it('should return result if console addon is present in config', async () => {\n      vi.mocked(getAddonNames).mockReturnValue(['@storybook/addon-console']);\n      const packageManager = {\n        isDependencyInstalled: vi.fn().mockReturnValue(false),\n      } as any;\n      vi.mocked(readFileSync).mockReturnValue('export default {};');\n\n      const result = await migrateAddonConsole.check({\n        mainConfig,\n        packageManager,\n        previewConfigPath,\n      } as CheckOptions);\n\n      expect(result).toEqual({\n        transformedPreviewCode: expect.any(String),\n      });\n    });\n\n    it('should return result if console addon is present in dependencies', async () => {\n      vi.mocked(getAddonNames).mockReturnValue([]);\n      const packageManager = {\n        isDependencyInstalled: vi.fn().mockReturnValue(true),\n      } as any;\n      vi.mocked(readFileSync).mockReturnValue('export default {};');\n\n      const result = await migrateAddonConsole.check({\n        mainConfig,\n        packageManager,\n        previewConfigPath,\n      } as CheckOptions);\n\n      expect(result).toEqual({\n        transformedPreviewCode: expect.any(String),\n      });\n    });\n\n    it('should return result with undefined transformedPreviewCode if no preview config path', async () => {\n      vi.mocked(getAddonNames).mockReturnValue(['@storybook/addon-console']);\n      const packageManager = {\n        isDependencyInstalled: vi.fn().mockReturnValue(false),\n      } as any;\n\n      const result = await migrateAddonConsole.check({\n        mainConfig,\n        packageManager,\n        previewConfigPath: undefined,\n      } as CheckOptions);\n\n      expect(result).toEqual({\n        previewConfigPath: undefined,\n        transformedPreviewCode: undefined,\n      });\n    });\n  });\n\n  describe('prompt', () => {\n    it('should return the correct prompt message', () => {\n      const message = migrateAddonConsole.prompt();\n      expect(message).toBe(\n        '@storybook/addon-console can now be implemented with spies on the console object.'\n      );\n    });\n  });\n\n  describe('run', () => {\n    const packageManager = {} as any;\n\n    it('should not write files when in dry run mode', async () => {\n      await migrateAddonConsole.run?.({\n        packageManager,\n        dryRun: true,\n        configDir,\n        result: {\n          transformedPreviewCode: 'transformed code',\n        },\n      } as RunOptions<MigrateAddonConsoleOptions>);\n\n      expect(writeFileSync).not.toHaveBeenCalled();\n      expect(removeAddon).not.toHaveBeenCalled();\n    });\n\n    it('should remove addon and update preview file when not in dry run mode', async () => {\n      const transformedPreviewCode = 'transformed code';\n\n      await migrateAddonConsole.run?.({\n        packageManager,\n        dryRun: false,\n        configDir,\n        result: {\n          transformedPreviewCode,\n        },\n      } as RunOptions<MigrateAddonConsoleOptions>);\n\n      expect(writeFileSync).toHaveBeenCalledWith(previewConfigPath, transformedPreviewCode, 'utf8');\n      expect(removeAddon).toHaveBeenCalledWith('@storybook/addon-console', {\n        configDir,\n        skipInstall: true,\n        packageManager,\n      });\n      expect(loggerMock.debug).toHaveBeenCalledWith(\n        'Updating preview file to replace addon-console logic with spies.'\n      );\n      expect(loggerMock.debug).toHaveBeenCalledWith('Removing @storybook/addon-console addon.');\n    });\n\n    it(\"should remove addon and create a preview file when it didn't previously exist\", async () => {\n      await migrateAddonConsole.run?.({\n        packageManager,\n        dryRun: false,\n        configDir,\n        previewConfigPath: undefined,\n        result: {\n          transformedPreviewCode: undefined,\n        },\n      } as RunOptions<MigrateAddonConsoleOptions>);\n\n      expect(removeAddon).toHaveBeenCalledWith('@storybook/addon-console', {\n        configDir,\n        skipInstall: true,\n        packageManager,\n      });\n      expect(writeFileSync).toHaveBeenCalledWith(expect.any(String), expect.any(String), 'utf8');\n      expect(loggerMock.debug).toHaveBeenCalledWith(\n        'addon-console was installed but no preview file was found. Creating a preview file.'\n      );\n      expect(loggerMock.debug).toHaveBeenCalledWith('Removing @storybook/addon-console addon.');\n    });\n  });\n});\n\ndescribe('transformPreviewFile', () => {\n  it('should add spyOn import and remove addon-console import', async () => {\n    const source = dedent`\n      import \"@storybook/addon-console\";\n\n      export default {};\n    `;\n\n    const result = await transformPreviewFile(source, '.storybook/preview.ts');\n    expect(result).toMatchInlineSnapshot(`\n      \"import { spyOn } from \"storybook/test\";\n\n      export default {\n        beforeEach: function beforeEach() {\n          spyOn(console, \"log\").mockName(\"console.log\");\n          spyOn(console, \"warn\").mockName(\"console.warn\");\n          spyOn(console, \"error\").mockName(\"console.error\");\n          spyOn(console, \"info\").mockName(\"console.info\");\n          spyOn(console, \"debug\").mockName(\"console.debug\");\n          spyOn(console, \"trace\").mockName(\"console.trace\");\n          spyOn(console, \"count\").mockName(\"console.count\");\n          spyOn(console, \"dir\").mockName(\"console.dir\");\n          spyOn(console, \"assert\").mockName(\"console.assert\");\n        }\n      };\"\n    `);\n  });\n\n  it('should add console spies to beforeEach function', async () => {\n    const source = dedent`\n      import \"@storybook/addon-console\";\n\n      export default {\n        beforeEach: () => {\n          // existing code\n        }\n      };\n    `;\n\n    const result = await transformPreviewFile(source, '.storybook/preview.ts');\n    expect(result).toMatchInlineSnapshot(`\n      \"import { spyOn } from \"storybook/test\";\n\n      export default {\n        beforeEach: () => {\n          spyOn(console, \"log\").mockName(\"console.log\");\n          spyOn(console, \"warn\").mockName(\"console.warn\");\n          spyOn(console, \"error\").mockName(\"console.error\");\n          spyOn(console, \"info\").mockName(\"console.info\");\n          spyOn(console, \"debug\").mockName(\"console.debug\");\n          spyOn(console, \"trace\").mockName(\"console.trace\");\n          spyOn(console, \"count\").mockName(\"console.count\");\n          spyOn(console, \"dir\").mockName(\"console.dir\");\n          spyOn(console, \"assert\").mockName(\"console.assert\");\n        }\n      };\"\n    `);\n  });\n\n  it('should create beforeEach function if it does not exist', async () => {\n    const source = dedent`\n      import \"@storybook/addon-console\";\n\n      export default {};\n    `;\n\n    const result = await transformPreviewFile(source, '.storybook/preview.ts');\n    expect(result).toMatchInlineSnapshot(`\n      \"import { spyOn } from \"storybook/test\";\n\n      export default {\n        beforeEach: function beforeEach() {\n          spyOn(console, \"log\").mockName(\"console.log\");\n          spyOn(console, \"warn\").mockName(\"console.warn\");\n          spyOn(console, \"error\").mockName(\"console.error\");\n          spyOn(console, \"info\").mockName(\"console.info\");\n          spyOn(console, \"debug\").mockName(\"console.debug\");\n          spyOn(console, \"trace\").mockName(\"console.trace\");\n          spyOn(console, \"count\").mockName(\"console.count\");\n          spyOn(console, \"dir\").mockName(\"console.dir\");\n          spyOn(console, \"assert\").mockName(\"console.assert\");\n        }\n      };\"\n    `);\n  });\n\n  it('should handle arrow function beforeEach with expression body', async () => {\n    const source = dedent`\n      import \"@storybook/addon-console\";\n\n      export default {\n        beforeEach: () => someFunction()\n      };\n    `;\n\n    const result = await transformPreviewFile(source, '.storybook/preview.ts');\n    expect(result).toMatchInlineSnapshot(`\n      \"import { spyOn } from \"storybook/test\";\n\n      export default {\n        beforeEach: () => {\n          spyOn(console, \"log\").mockName(\"console.log\");\n          spyOn(console, \"warn\").mockName(\"console.warn\");\n          spyOn(console, \"error\").mockName(\"console.error\");\n          spyOn(console, \"info\").mockName(\"console.info\");\n          spyOn(console, \"debug\").mockName(\"console.debug\");\n          spyOn(console, \"trace\").mockName(\"console.trace\");\n          spyOn(console, \"count\").mockName(\"console.count\");\n          spyOn(console, \"dir\").mockName(\"console.dir\");\n          spyOn(console, \"assert\").mockName(\"console.assert\");\n          return someFunction();\n        }\n      };\"\n    `);\n  });\n\n  it('should handle arrow function beforeEach with block body', async () => {\n    const source = dedent`\n      import \"@storybook/addon-console\";\n\n      export default {\n        beforeEach: () => {\n          // existing setup\n          setupTest();\n        }\n      };\n    `;\n\n    const result = await transformPreviewFile(source, '.storybook/preview.ts');\n    expect(result).toMatchInlineSnapshot(`\n      \"import { spyOn } from \"storybook/test\";\n\n      export default {\n        beforeEach: () => {\n          // existing setup\n          setupTest();\n          spyOn(console, \"log\").mockName(\"console.log\");\n          spyOn(console, \"warn\").mockName(\"console.warn\");\n          spyOn(console, \"error\").mockName(\"console.error\");\n          spyOn(console, \"info\").mockName(\"console.info\");\n          spyOn(console, \"debug\").mockName(\"console.debug\");\n          spyOn(console, \"trace\").mockName(\"console.trace\");\n          spyOn(console, \"count\").mockName(\"console.count\");\n          spyOn(console, \"dir\").mockName(\"console.dir\");\n          spyOn(console, \"assert\").mockName(\"console.assert\");\n        }\n      };\"\n    `);\n  });\n\n  it('should handle beforeEach function', async () => {\n    const source = dedent`\n      import \"@storybook/addon-console\";\n\n      export default {\n        beforeEach: function() {\n          // existing code\n          setupSomething();\n        }\n      };\n    `;\n\n    const result = await transformPreviewFile(source, '.storybook/preview.ts');\n    expect(result).toMatchInlineSnapshot(`\n      \"import { spyOn } from \"storybook/test\";\n\n      export default {\n        beforeEach: function() {\n          // existing code\n          setupSomething();\n          spyOn(console, \"log\").mockName(\"console.log\");\n          spyOn(console, \"warn\").mockName(\"console.warn\");\n          spyOn(console, \"error\").mockName(\"console.error\");\n          spyOn(console, \"info\").mockName(\"console.info\");\n          spyOn(console, \"debug\").mockName(\"console.debug\");\n          spyOn(console, \"trace\").mockName(\"console.trace\");\n          spyOn(console, \"count\").mockName(\"console.count\");\n          spyOn(console, \"dir\").mockName(\"console.dir\");\n          spyOn(console, \"assert\").mockName(\"console.assert\");\n        }\n      };\"\n    `);\n  });\n\n  it('should handle existing beforeEach function declaration', async () => {\n    const source = dedent`\n      import \"@storybook/addon-console\";\n\n      export default {\n        beforeEach: function beforeEach() {\n          // existing setup\n          initializeTest();\n        }\n      };\n    `;\n\n    const result = await transformPreviewFile(source, '.storybook/preview.ts');\n    expect(result).toMatchInlineSnapshot(`\n      \"import { spyOn } from \"storybook/test\";\n\n      export default {\n        beforeEach: function beforeEach() {\n          // existing setup\n          initializeTest();\n          spyOn(console, \"log\").mockName(\"console.log\");\n          spyOn(console, \"warn\").mockName(\"console.warn\");\n          spyOn(console, \"error\").mockName(\"console.error\");\n          spyOn(console, \"info\").mockName(\"console.info\");\n          spyOn(console, \"debug\").mockName(\"console.debug\");\n          spyOn(console, \"trace\").mockName(\"console.trace\");\n          spyOn(console, \"count\").mockName(\"console.count\");\n          spyOn(console, \"dir\").mockName(\"console.dir\");\n          spyOn(console, \"assert\").mockName(\"console.assert\");\n        }\n      };\"\n    `);\n  });\n\n  it('should preserve existing spyOn import if present', async () => {\n    const source = dedent`\n      import { spyOn } from \"storybook/test\";\n      import \"@storybook/addon-console\";\n\n      export default {};\n    `;\n\n    const result = await transformPreviewFile(source, '.storybook/preview.ts');\n    expect(result).toMatchInlineSnapshot(`\n      \"import { spyOn } from \"storybook/test\";\n\n      export default {\n        beforeEach: function beforeEach() {\n          spyOn(console, \"log\").mockName(\"console.log\");\n          spyOn(console, \"warn\").mockName(\"console.warn\");\n          spyOn(console, \"error\").mockName(\"console.error\");\n          spyOn(console, \"info\").mockName(\"console.info\");\n          spyOn(console, \"debug\").mockName(\"console.debug\");\n          spyOn(console, \"trace\").mockName(\"console.trace\");\n          spyOn(console, \"count\").mockName(\"console.count\");\n          spyOn(console, \"dir\").mockName(\"console.dir\");\n          spyOn(console, \"assert\").mockName(\"console.assert\");\n        }\n      };\"\n    `);\n  });\n\n  it('should create named export for beforeEach when no default export exists', async () => {\n    const source = dedent`\n      import \"@storybook/addon-console\";\n\n      export const parameters = {};\n    `;\n\n    const result = await transformPreviewFile(source, '.storybook/preview.ts');\n    expect(result).toMatchInlineSnapshot(`\n      \"import { spyOn } from \"storybook/test\";\n\n      export const parameters = {};\n\n      export const beforeEach = function beforeEach() {\n        spyOn(console, \"log\").mockName(\"console.log\");\n        spyOn(console, \"warn\").mockName(\"console.warn\");\n        spyOn(console, \"error\").mockName(\"console.error\");\n        spyOn(console, \"info\").mockName(\"console.info\");\n        spyOn(console, \"debug\").mockName(\"console.debug\");\n        spyOn(console, \"trace\").mockName(\"console.trace\");\n        spyOn(console, \"count\").mockName(\"console.count\");\n        spyOn(console, \"dir\").mockName(\"console.dir\");\n        spyOn(console, \"assert\").mockName(\"console.assert\");\n      };\"\n    `);\n  });\n\n  it('should add beforeEach to default export object when no beforeEach exists', async () => {\n    const source = dedent`\n      import \"@storybook/addon-console\";\n\n      export default {\n        parameters: {\n          layout: 'centered'\n        }\n      };\n    `;\n\n    const result = await transformPreviewFile(source, '.storybook/preview.ts');\n    expect(result).toMatchInlineSnapshot(`\n      \"import { spyOn } from \"storybook/test\";\n\n      export default {\n        parameters: {\n          layout: 'centered'\n        },\n\n        beforeEach: function beforeEach() {\n          spyOn(console, \"log\").mockName(\"console.log\");\n          spyOn(console, \"warn\").mockName(\"console.warn\");\n          spyOn(console, \"error\").mockName(\"console.error\");\n          spyOn(console, \"info\").mockName(\"console.info\");\n          spyOn(console, \"debug\").mockName(\"console.debug\");\n          spyOn(console, \"trace\").mockName(\"console.trace\");\n          spyOn(console, \"count\").mockName(\"console.count\");\n          spyOn(console, \"dir\").mockName(\"console.dir\");\n          spyOn(console, \"assert\").mockName(\"console.assert\");\n        }\n      };\"\n    `);\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/migrate-addon-console.ts",
    "content": "import { readFileSync, writeFileSync } from 'node:fs';\n\nimport { types as t } from 'storybook/internal/babel';\nimport { formatFileContent, getAddonNames, removeAddon } from 'storybook/internal/common';\nimport { formatConfig, loadConfig } from 'storybook/internal/csf-tools';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport type { Fix } from '../types.ts';\n\nexport interface MigrateAddonConsoleOptions {\n  transformedPreviewCode: string | undefined;\n}\n\n/** Remove @storybook/addon-console since it's now part of Storybook core. */\nexport const migrateAddonConsole: Fix<MigrateAddonConsoleOptions> = {\n  id: 'migrate-addon-console',\n  link: 'https://github.com/storybookjs/storybook/discussions/31657',\n\n  async check({ mainConfig, packageManager, previewConfigPath }) {\n    const addons = getAddonNames(mainConfig);\n    const consoleAddon = '@storybook/addon-console';\n\n    const hasConsoleAddon = addons.some((addon) => addon.includes(consoleAddon));\n    const hasConsoleAddonInDeps = packageManager.isDependencyInstalled(consoleAddon);\n\n    if (!hasConsoleAddon && !hasConsoleAddonInDeps) {\n      return null;\n    }\n\n    const transformedPreviewCode = previewConfigPath\n      ? await transformPreviewFile(readFileSync(previewConfigPath, 'utf8'), previewConfigPath)\n      : undefined;\n\n    return {\n      transformedPreviewCode,\n    };\n  },\n\n  prompt() {\n    return '@storybook/addon-console can now be implemented with spies on the console object.';\n  },\n\n  async run({ packageManager, dryRun, configDir, previewConfigPath, result }) {\n    const { transformedPreviewCode } = result;\n    if (!dryRun) {\n      if (!previewConfigPath) {\n        logger.debug(\n          'addon-console was installed but no preview file was found. Creating a preview file.'\n        );\n      }\n\n      const finalPreviewPath = previewConfigPath || `${configDir}/preview.ts`;\n      const finalTransformedCode =\n        transformedPreviewCode || (await transformPreviewFile('', finalPreviewPath));\n\n      logger.debug('Updating preview file to replace addon-console logic with spies.');\n      writeFileSync(finalPreviewPath, finalTransformedCode, 'utf8');\n\n      logger.debug('Removing @storybook/addon-console addon.');\n      await removeAddon('@storybook/addon-console', {\n        configDir,\n        skipInstall: true,\n        packageManager,\n      });\n    }\n  },\n};\n\nexport async function transformPreviewFile(source: string, filePath: string): Promise<string> {\n  const previewConfig = loadConfig(source).parse();\n\n  // We import spyOn so we can use it.\n  previewConfig.setImport(['spyOn'], 'storybook/test');\n\n  // addon-console required its users to import it in preview instead of\n  // the usual addon loading mechanism.\n  previewConfig.removeImport(null, '@storybook/addon-console');\n\n  // Construct spies for all relevant console methods, to provide named mocks for the actions addon.\n  const callsToInject = [];\n  for (const method of [\n    'log',\n    'warn',\n    'error',\n    'info',\n    'debug',\n    'trace',\n    'count',\n    'dir',\n    'assert',\n  ]) {\n    callsToInject.push(\n      t.callExpression(\n        t.memberExpression(\n          t.callExpression(t.identifier('spyOn'), [\n            t.identifier('console'),\n            t.stringLiteral(method),\n          ]),\n          t.identifier('mockName')\n        ),\n        [t.stringLiteral(`console.${method}`)]\n      )\n    );\n  }\n\n  // Fetch default export, as we'll need it to decide where to inject beforeEach if\n  // it doesn't already exist.\n  const defaultExport = previewConfig.hasDefaultExport\n    ? previewConfig._ast.program.body.find((node) => t.isExportDefaultDeclaration(node))\n    : undefined;\n\n  // We now add spies to beforeEach, accounting for various edge cases.\n  // Find beforeEach export.\n  let beforeEach = previewConfig.getFieldNode(['beforeEach']);\n\n  // Find a `beforeEach` export because `function beforeEach() {}` is missed by getFieldNode.\n  if (!beforeEach) {\n    const beforeEachExport = previewConfig._ast.program.body.find(\n      (\n        node\n      ): node is t.ExportNamedDeclaration & {\n        declaration: t.FunctionDeclaration;\n      } =>\n        t.isExportNamedDeclaration(node) &&\n        t.isFunctionDeclaration(node.declaration) &&\n        node.declaration.id?.name === 'beforeEach'\n    );\n    if (beforeEachExport) {\n      beforeEach = beforeEachExport.declaration;\n    }\n  }\n\n  // Find `beforeEach` in default export properties.\n  if (!beforeEach && defaultExport) {\n    if (t.isIdentifier(defaultExport.declaration)) {\n      const identifierName = defaultExport.declaration.name;\n      const variableDeclarations = previewConfig._ast.program.body.filter((node) =>\n        t.isVariableDeclaration(node)\n      );\n      for (const declaration of variableDeclarations) {\n        for (const declarator of declaration.declarations) {\n          if (\n            t.isVariableDeclarator(declarator) &&\n            t.isIdentifier(declarator.id, { name: identifierName })\n          ) {\n            if (t.isObjectExpression(declarator.init)) {\n              beforeEach = declarator.init.properties.find(\n                (prop): prop is t.ObjectMethod =>\n                  t.isObjectMethod(prop) && t.isIdentifier(prop.key, { name: 'beforeEach' })\n              );\n\n              if (!beforeEach) {\n                const beforeEachProperty = declarator.init.properties.find(\n                  (prop): prop is t.ObjectProperty =>\n                    t.isObjectProperty(prop) && t.isIdentifier(prop.key, { name: 'beforeEach' })\n                );\n                if (beforeEachProperty && t.isFunctionExpression(beforeEachProperty.value)) {\n                  beforeEach = beforeEachProperty.value;\n                }\n                if (beforeEachProperty && t.isIdentifier(beforeEachProperty.value)) {\n                  const identifierName = beforeEachProperty.value.name;\n                  beforeEach = previewConfig._ast.program.body.find(\n                    (node): node is t.FunctionDeclaration | t.VariableDeclaration =>\n                      (t.isFunctionDeclaration(node) && node.id?.name === identifierName) ||\n                      (t.isVariableDeclaration(node) &&\n                        node.declarations.some(\n                          (decl) =>\n                            t.isVariableDeclarator(decl) &&\n                            t.isIdentifier(decl.id, { name: identifierName }) &&\n                            (t.isFunctionExpression(decl.init) ||\n                              t.isArrowFunctionExpression(decl.init))\n                        ))\n                  );\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n\n    if (t.isObjectExpression(defaultExport.declaration)) {\n      beforeEach = previewConfig.getFieldNode(['default', 'beforeEach']);\n    }\n  }\n\n  // If no beforeEach is found, we create a new one.\n  if (!beforeEach) {\n    beforeEach = t.functionExpression(t.identifier('beforeEach'), [], t.blockStatement([]));\n\n    // If we have a default export and it's an object, we add beforeEach to it,\n    // else we export beforeEach as a named export.\n    if (defaultExport && t.isObjectExpression(defaultExport.declaration)) {\n      defaultExport.declaration.properties.push(\n        t.objectProperty(t.identifier('beforeEach'), beforeEach)\n      );\n    } else {\n      previewConfig._ast.program.body.push(\n        t.exportNamedDeclaration(\n          t.variableDeclaration('const', [\n            t.variableDeclarator(t.identifier('beforeEach'), beforeEach),\n          ])\n        )\n      );\n    }\n  }\n\n  if (\n    t.isFunctionDeclaration(beforeEach) ||\n    t.isFunctionExpression(beforeEach) ||\n    t.isArrowFunctionExpression(beforeEach) ||\n    t.isObjectMethod(beforeEach)\n  ) {\n    const functionBody = beforeEach.body;\n    if (t.isBlockStatement(functionBody)) {\n      functionBody.body.push(...callsToInject.map((call) => t.expressionStatement(call)));\n    } else {\n      beforeEach.body = t.blockStatement([\n        ...callsToInject.map((call) => t.expressionStatement(call)),\n        t.returnStatement(functionBody),\n      ]);\n    }\n  }\n\n  return formatFileContent(filePath, formatConfig(previewConfig));\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/nextjs-to-nextjs-vite.test.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { JsPackageManager } from 'storybook/internal/common';\n\nimport type { CheckOptions } from './index.ts';\nimport { VITE_DEFAULT_VERSION, nextjsToNextjsVite } from './nextjs-to-nextjs-vite.ts';\n\n// Mock dependencies\nvi.mock('node:fs/promises', () => ({\n  readFile: vi.fn(),\n  writeFile: vi.fn(),\n}));\n\nvi.mock('storybook/internal/node-logger', () => ({\n  logger: {\n    step: vi.fn(),\n    debug: vi.fn(),\n    warn: vi.fn(),\n    log: vi.fn(),\n    error: vi.fn(),\n  },\n}));\n\nvi.mock('storybook/internal/common', () => ({\n  transformImportFiles: vi.fn().mockResolvedValue([]),\n}));\n\nvi.mock('globby', () => ({\n  globby: vi.fn().mockResolvedValue([]),\n}));\n\nconst mockReadFile = vi.mocked(readFile);\nconst mockWriteFile = vi.mocked(writeFile);\n\ndescribe('nextjs-to-nextjs-vite', () => {\n  const mockPackageManager = {\n    getAllDependencies: vi.fn(),\n    packageJsonPaths: ['/project/package.json'],\n    removeDependencies: vi.fn().mockResolvedValue(undefined),\n    addDependencies: vi.fn().mockResolvedValue(undefined),\n    getDependencyVersion: vi.fn(),\n  } as unknown as JsPackageManager;\n\n  beforeEach(() => {\n    vi.clearAllMocks();\n    vi.mocked(mockPackageManager.removeDependencies).mockResolvedValue(undefined);\n    vi.mocked(mockPackageManager.addDependencies).mockResolvedValue(undefined);\n    vi.mocked(mockPackageManager.getDependencyVersion).mockReturnValue(null);\n  });\n\n  describe('check function', () => {\n    it('should return null if @storybook/nextjs is not installed', async () => {\n      mockPackageManager.getAllDependencies = vi.fn().mockReturnValue({\n        '@storybook/react': '^9.0.0',\n      });\n\n      const result = await nextjsToNextjsVite.check({\n        packageManager: mockPackageManager,\n      } as CheckOptions);\n      expect(result).toBeNull();\n    });\n\n    it('should return migration options if @storybook/nextjs is installed', async () => {\n      mockPackageManager.getAllDependencies = vi.fn().mockReturnValue({\n        '@storybook/nextjs': '^9.0.0',\n        '@storybook/react': '^9.0.0',\n      });\n\n      mockReadFile.mockResolvedValue(\n        JSON.stringify({\n          dependencies: {\n            '@storybook/nextjs': '^9.0.0',\n          },\n        })\n      );\n\n      const result = await nextjsToNextjsVite.check({\n        packageManager: mockPackageManager,\n      } as CheckOptions);\n\n      expect(result).toEqual({\n        hasNextjsPackage: true,\n        packageJsonFiles: ['/project/package.json'],\n      });\n    });\n\n    it('should handle invalid package.json files gracefully', async () => {\n      mockPackageManager.getAllDependencies = vi.fn().mockReturnValue({\n        '@storybook/nextjs': '^9.0.0',\n      });\n\n      mockReadFile.mockRejectedValue(new Error('Invalid JSON'));\n\n      const result = await nextjsToNextjsVite.check({\n        packageManager: mockPackageManager,\n      } as CheckOptions);\n\n      expect(result).toEqual({\n        hasNextjsPackage: true,\n        packageJsonFiles: [],\n      });\n    });\n  });\n\n  describe('prompt function', () => {\n    it('should return a descriptive prompt message', () => {\n      const prompt = nextjsToNextjsVite.prompt();\n\n      expect(prompt).toContain('@storybook/nextjs');\n      expect(prompt).toContain('@storybook/nextjs-vite');\n    });\n  });\n\n  describe('run function', () => {\n    it('should handle null result gracefully', async () => {\n      await expect(\n        nextjsToNextjsVite.run!({\n          result: null,\n          dryRun: false,\n          packageManager: mockPackageManager,\n          mainConfigPath: '/project/.storybook/main.js',\n          storiesPaths: ['**/*.stories.*'],\n          configDir: '.storybook',\n        } as any)\n      ).resolves.toBeUndefined();\n    });\n\n    it('should transform package.json files and add vite if not installed', async () => {\n      const result = {\n        hasNextjsPackage: true,\n        packageJsonFiles: ['/project/package.json'],\n      };\n\n      mockReadFile.mockResolvedValue(\n        JSON.stringify({\n          dependencies: {\n            '@storybook/nextjs': '^9.0.0',\n            '@storybook/react': '^9.0.0',\n          },\n        })\n      );\n\n      await nextjsToNextjsVite.run!({\n        result,\n        dryRun: false,\n        packageManager: mockPackageManager,\n        mainConfigPath: '/project/.storybook/main.js',\n        storiesPaths: ['**/*.stories.*'],\n        configDir: '.storybook',\n        storybookVersion: '9.0.0',\n      } as any);\n\n      expect(mockPackageManager.removeDependencies).toHaveBeenCalledWith(['@storybook/nextjs']);\n      expect(mockPackageManager.addDependencies).toHaveBeenCalledWith(\n        { type: 'devDependencies', skipInstall: true },\n        [`@storybook/nextjs-vite@9.0.0`, `vite@${VITE_DEFAULT_VERSION}`]\n      );\n    });\n\n    it('should transform package.json files without adding vite if already installed', async () => {\n      const result = {\n        hasNextjsPackage: true,\n        packageJsonFiles: ['/project/package.json'],\n      };\n\n      mockReadFile.mockResolvedValue(\n        JSON.stringify({\n          dependencies: {\n            '@storybook/nextjs': '^9.0.0',\n            '@storybook/react': '^9.0.0',\n          },\n        })\n      );\n\n      // Mock getDependencyVersion to return a version (vite is installed)\n      vi.mocked(mockPackageManager.getDependencyVersion).mockReturnValue('6.0.0');\n\n      await nextjsToNextjsVite.run!({\n        result,\n        dryRun: false,\n        packageManager: mockPackageManager,\n        mainConfigPath: '/project/.storybook/main.js',\n        storiesPaths: ['**/*.stories.*'],\n        configDir: '.storybook',\n        storybookVersion: '9.0.0',\n      } as any);\n\n      expect(mockPackageManager.removeDependencies).toHaveBeenCalledWith(['@storybook/nextjs']);\n      expect(mockPackageManager.addDependencies).toHaveBeenCalledWith(\n        { type: 'devDependencies', skipInstall: true },\n        ['@storybook/nextjs-vite@9.0.0']\n      );\n    });\n\n    it('should transform main config file', async () => {\n      const result = {\n        hasNextjsPackage: true,\n        packageJsonFiles: [],\n      };\n\n      mockReadFile.mockResolvedValue(`\n        export default {\n          framework: '@storybook/nextjs',\n          addons: ['@storybook/addon-essentials'],\n        };\n      `);\n\n      // Mock getDependencyVersion to return a version (vite is installed)\n      vi.mocked(mockPackageManager.getDependencyVersion).mockReturnValue('6.0.0');\n\n      await nextjsToNextjsVite.run!({\n        result,\n        dryRun: false,\n        packageManager: mockPackageManager,\n        mainConfigPath: '/project/.storybook/main.js',\n        storiesPaths: ['**/*.stories.*'],\n        configDir: '.storybook',\n        storybookVersion: '9.0.0',\n      } as any);\n\n      expect(mockPackageManager.removeDependencies).toHaveBeenCalledWith(['@storybook/nextjs']);\n      expect(mockPackageManager.addDependencies).toHaveBeenCalledWith(\n        { type: 'devDependencies', skipInstall: true },\n        ['@storybook/nextjs-vite@9.0.0']\n      );\n      expect(mockWriteFile).toHaveBeenCalledWith(\n        '/project/.storybook/main.js',\n        expect.stringContaining('@storybook/nextjs-vite')\n      );\n    });\n\n    it('should not corrupt main config that already references @storybook/nextjs-vite', async () => {\n      // Regression: projects with both @storybook/nextjs and @storybook/nextjs-vite installed\n      // (valid in SB9) already use nextjs-vite in main.ts. Without the fix, the regex would\n      // rewrite @storybook/nextjs-vite to @storybook/nextjs-vite-vite.\n      const result = {\n        hasNextjsPackage: true,\n        packageJsonFiles: [],\n      };\n\n      mockReadFile.mockResolvedValue(`\n        import type { StorybookConfig } from '@storybook/nextjs-vite';\n        export default {\n          framework: { name: '@storybook/nextjs-vite', options: {} },\n        };\n      `);\n\n      vi.mocked(mockPackageManager.getDependencyVersion).mockReturnValue('7.0.0');\n\n      await nextjsToNextjsVite.run!({\n        result,\n        dryRun: false,\n        packageManager: mockPackageManager,\n        mainConfigPath: '/project/.storybook/main.ts',\n        storiesPaths: [],\n        configDir: '.storybook',\n        storybookVersion: '10.0.0',\n      } as any);\n\n      expect(mockWriteFile).not.toHaveBeenCalled();\n    });\n\n    it('should handle dry run mode', async () => {\n      const result = {\n        hasNextjsPackage: true,\n        packageJsonFiles: ['/project/package.json'],\n      };\n\n      mockReadFile.mockResolvedValue(\n        JSON.stringify({\n          dependencies: {\n            '@storybook/nextjs': '^9.0.0',\n          },\n        })\n      );\n\n      await nextjsToNextjsVite.run!({\n        result,\n        dryRun: true,\n        packageManager: mockPackageManager,\n        mainConfigPath: '/project/.storybook/main.js',\n        storiesPaths: ['**/*.stories.*'],\n        configDir: '.storybook',\n        storybookVersion: '9.0.0',\n      } as any);\n\n      // In dry run mode, package.json updates should be skipped\n      expect(mockPackageManager.removeDependencies).not.toHaveBeenCalled();\n      expect(mockPackageManager.addDependencies).not.toHaveBeenCalled();\n      expect(mockWriteFile).not.toHaveBeenCalled();\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/nextjs-to-nextjs-vite.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\n\nimport { transformImportFiles } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport type { Fix } from '../types.ts';\n\nexport const VITE_DEFAULT_VERSION = '^7.0.0';\n\ninterface NextjsToNextjsViteOptions {\n  hasNextjsPackage: boolean;\n  packageJsonFiles: string[];\n}\n\nconst transformMainConfig = async (mainConfigPath: string, dryRun: boolean): Promise<boolean> => {\n  try {\n    const content = await readFile(mainConfigPath, 'utf-8');\n\n    // Check if the file contains @storybook/nextjs references\n    if (!content.includes('@storybook/nextjs')) {\n      return false;\n    }\n\n    // Replace @storybook/nextjs with @storybook/nextjs-vite, using a negative lookahead\n    // to avoid corrupting references that are already @storybook/nextjs-vite\n    const transformedContent = content.replace(\n      /@storybook\\/nextjs(?!-vite)/g,\n      '@storybook/nextjs-vite'\n    );\n\n    if (transformedContent !== content && !dryRun) {\n      await writeFile(mainConfigPath, transformedContent);\n    }\n\n    return transformedContent !== content;\n  } catch (error) {\n    logger.error(`Failed to update main config at ${mainConfigPath}: ${error}`);\n    return false;\n  }\n};\n\nexport const nextjsToNextjsVite: Fix<NextjsToNextjsViteOptions> = {\n  id: 'nextjs-to-nextjs-vite',\n  link: 'https://storybook.js.org/docs/get-started/frameworks/nextjs-vite',\n  defaultSelected: false,\n\n  async check({ packageManager }): Promise<NextjsToNextjsViteOptions | null> {\n    const allDeps = packageManager.getAllDependencies();\n\n    // Check if @storybook/nextjs is present\n    if (!allDeps['@storybook/nextjs']) {\n      return null;\n    }\n\n    // Find package.json files that contain @storybook/nextjs\n    const packageJsonFiles: string[] = [];\n\n    for (const packageJsonPath of packageManager.packageJsonPaths) {\n      try {\n        const content = await readFile(packageJsonPath, 'utf-8');\n        const packageJson = JSON.parse(content);\n\n        const hasNextjs = Object.keys({\n          ...(packageJson.dependencies || {}),\n          ...(packageJson.devDependencies || {}),\n        }).includes('@storybook/nextjs');\n\n        if (hasNextjs) {\n          packageJsonFiles.push(packageJsonPath);\n        }\n      } catch {\n        // Skip invalid package.json files\n        continue;\n      }\n    }\n\n    return {\n      hasNextjsPackage: true,\n      packageJsonFiles,\n    };\n  },\n\n  prompt() {\n    return 'Migrate from @storybook/nextjs to @storybook/nextjs-vite (Vite framework)';\n  },\n\n  async run({\n    result,\n    dryRun = false,\n    mainConfigPath,\n    storiesPaths,\n    configDir,\n    packageManager,\n    storybookVersion,\n  }) {\n    if (!result) {\n      return;\n    }\n\n    logger.step('Migrating from @storybook/nextjs to @storybook/nextjs-vite...');\n\n    // Update package.json files\n    if (dryRun) {\n      logger.debug('Dry run: Skipping package.json updates.');\n    } else {\n      logger.debug('Updating package.json files...');\n      const viteVersion = packageManager.getDependencyVersion('vite');\n      await packageManager.removeDependencies(['@storybook/nextjs']);\n      await packageManager.addDependencies({ type: 'devDependencies', skipInstall: true }, [\n        `@storybook/nextjs-vite@${storybookVersion}`,\n        ...(viteVersion ? [] : [`vite@${VITE_DEFAULT_VERSION}`]), // Add vite if it's not installed yet\n      ]);\n    }\n\n    // Update main config file\n    if (mainConfigPath) {\n      logger.debug('Updating main config file...');\n      await transformMainConfig(mainConfigPath, dryRun);\n    }\n\n    // Scan and transform import statements in source files\n    logger.debug('Scanning and updating import statements...');\n\n    // eslint-disable-next-line depend/ban-dependencies\n    const { globby } = await import('globby');\n    const configFiles = await globby([`${configDir}/**/*`]);\n    const allFiles = [...storiesPaths, ...configFiles].filter(Boolean) as string[];\n\n    const transformErrors = await transformImportFiles(\n      allFiles,\n      {\n        '@storybook/nextjs': '@storybook/nextjs-vite',\n      },\n      !!dryRun\n    );\n\n    if (transformErrors.length > 0) {\n      logger.warn(`Encountered ${transformErrors.length} errors during file transformation:`);\n      transformErrors.forEach(({ file, error }) => {\n        logger.warn(`  - ${file}: ${error.message}`);\n      });\n    }\n\n    logger.step('Migration completed successfully!');\n    logger.log(\n      `For more information, see: https://storybook.js.org/docs/get-started/frameworks/nextjs-vite`\n    );\n  },\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/remove-addon-interactions.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { getAddonNames } from 'storybook/internal/common';\n\nimport { removeAddonInteractions } from './remove-addon-interactions.ts';\n\nvi.mock('storybook/internal/common', async (importOriginal) => {\n  const mod = (await importOriginal()) as any;\n  return {\n    ...mod,\n    getAddonNames: vi.fn(),\n    removeAddon: vi.fn(),\n  };\n});\n\nvi.mock('picocolors', async (importOriginal) => {\n  const mod = (await importOriginal()) as any;\n  return {\n    ...mod,\n    default: {\n      magenta: (s: string) => s,\n    },\n  };\n});\n\ndescribe('removeAddonInteractions', () => {\n  const mockPackageManager = {\n    isDependencyInstalled: vi.fn(),\n  };\n\n  beforeEach(() => {\n    vi.clearAllMocks();\n    vi.mocked(mockPackageManager.isDependencyInstalled).mockReturnValue(false);\n  });\n\n  describe('check', () => {\n    it('should return null if addon-interactions is not present', async () => {\n      vi.mocked(getAddonNames).mockReturnValue(['@storybook/addon-essentials']);\n      const result = await removeAddonInteractions.check({\n        mainConfig: {},\n        packageManager: mockPackageManager,\n      } as any);\n      expect(result).toBeNull();\n    });\n\n    it('should return true if addon-interactions is present', async () => {\n      vi.mocked(getAddonNames).mockReturnValue(['@storybook/addon-interactions']);\n      const result = await removeAddonInteractions.check({\n        mainConfig: {},\n        packageManager: mockPackageManager,\n      } as any);\n      expect(result).toEqual(true);\n    });\n  });\n\n  describe('run', () => {\n    it('should run storybook remove command', async () => {\n      const { removeAddon } = await import('storybook/internal/common');\n\n      await removeAddonInteractions?.run?.({\n        packageManager: {} as any,\n        configDir: './storybook',\n        dryRun: false,\n      } as any);\n\n      expect(removeAddon).toHaveBeenCalledWith('@storybook/addon-interactions', {\n        configDir: './storybook',\n        skipInstall: true,\n        packageManager: {},\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/remove-addon-interactions.ts",
    "content": "import { getAddonNames, removeAddon } from 'storybook/internal/common';\n\nimport type { Fix } from '../types.ts';\n\n/** Remove @storybook/addon-interactions since it's now part of Storybook core. */\nexport const removeAddonInteractions: Fix<true> = {\n  id: 'remove-addon-interactions',\n  link: 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#essentials-addon-viewport-controls-interactions-and-actions-moved-to-core',\n\n  async check({ mainConfig, packageManager }) {\n    const addons = getAddonNames(mainConfig);\n    const interactionsAddon = '@storybook/addon-interactions';\n\n    const hasInteractionsAddon = addons.some((addon) => addon.includes(interactionsAddon));\n    const hasInteractionsAddonInDeps = packageManager.isDependencyInstalled(interactionsAddon);\n\n    if (!hasInteractionsAddon && !hasInteractionsAddonInDeps) {\n      return null;\n    }\n\n    return true;\n  },\n\n  prompt() {\n    return '@storybook/addon-interactions has been moved to Storybook core and will be removed from your configuration.';\n  },\n\n  async run({ packageManager, dryRun, configDir }) {\n    if (!dryRun) {\n      await removeAddon('@storybook/addon-interactions', {\n        configDir,\n        skipInstall: true,\n        packageManager,\n      });\n    }\n  },\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/remove-docs-autodocs.test.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\nimport type * as fs from 'node:fs/promises';\n\nimport { describe, expect, it, vi } from 'vitest';\n\nimport { JsPackageManager } from 'storybook/internal/common';\nimport type { StorybookConfigRaw } from 'storybook/internal/types';\n\nimport type { CheckOptions, Fix } from '../types.ts';\nimport { removeDocsAutodocs } from './remove-docs-autodocs.ts';\n\nvi.mock('node:fs/promises', async (importOriginal) => {\n  const actual = (await importOriginal()) as typeof fs;\n  return {\n    ...actual,\n    readFile: vi.fn(),\n    writeFile: vi.fn(),\n    // Add other fs functions that might be used internally\n    lstat: vi.fn().mockResolvedValue({ isFile: () => true }),\n    readdir: vi.fn(),\n    readlink: vi.fn(),\n  };\n});\n\nconst mockPackageManager = vi.mocked(JsPackageManager.prototype);\n\nconst baseCheckOptions: CheckOptions = {\n  packageManager: mockPackageManager,\n  mainConfig: {\n    stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n  } as StorybookConfigRaw,\n  storybookVersion: '9.0.0',\n  configDir: '.storybook',\n  storiesPaths: [],\n  hasCsfFactoryPreview: false,\n};\n\nconst typedRemoveDocsAutodocs = removeDocsAutodocs as Required<\n  Fix<{ autodocs: boolean | 'tag' | undefined }>\n>;\n\ndescribe('check phase', () => {\n  it('returns null if no mainConfigPath provided', async () => {\n    const result = await typedRemoveDocsAutodocs.check(baseCheckOptions);\n    expect(result).toBeNull();\n  });\n\n  it('returns null if docs.autodocs not found in config', async () => {\n    vi.mocked(readFile).mockResolvedValue(\n      Buffer.from(`\n          export default {\n            stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n            docs: {}\n          };\n        `)\n    );\n\n    const result = await typedRemoveDocsAutodocs.check({\n      ...baseCheckOptions,\n      mainConfigPath: 'main.ts',\n    });\n    expect(result).toBeNull();\n  });\n\n  it('detects docs.autodocs when present with tag value', async () => {\n    vi.mocked(readFile).mockResolvedValue(\n      Buffer.from(`\n          export default {\n            stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n            docs: { autodocs: 'tag' }\n          };\n        `)\n    );\n\n    const result = await typedRemoveDocsAutodocs.check({\n      ...baseCheckOptions,\n      mainConfigPath: 'main.ts',\n    });\n    expect(result).toEqual({\n      autodocs: 'tag',\n    });\n  });\n\n  it('detects docs.autodocs when present with true value', async () => {\n    vi.mocked(readFile).mockResolvedValue(\n      Buffer.from(`\n          export default {\n            stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n            docs: { autodocs: true }\n          };\n        `)\n    );\n\n    const result = await typedRemoveDocsAutodocs.check({\n      ...baseCheckOptions,\n      mainConfigPath: 'main.ts',\n    });\n    expect(result).toEqual({\n      autodocs: true,\n    });\n  });\n});\n\ndescribe('run phase', () => {\n  it('removes docs.autodocs field when present with tag value', async () => {\n    vi.mocked(readFile).mockImplementation(async (path) => {\n      if (path === '.storybook/main.ts') {\n        return Buffer.from(`\n            export default {\n              stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n              docs: { \n                autodocs: 'tag',\n                defaultName: 'Docs'\n              }\n            };\n          `);\n      }\n      return Buffer.from('');\n    });\n\n    await typedRemoveDocsAutodocs.run({\n      result: { autodocs: 'tag' },\n      packageManager: mockPackageManager,\n      configDir: '.storybook',\n      mainConfigPath: '.storybook/main.ts',\n      storybookVersion: '9.0.0',\n      mainConfig: {} as StorybookConfigRaw,\n      storiesPaths: [],\n    });\n\n    expect(writeFile).toHaveBeenCalledTimes(1);\n    expect(writeFile).toHaveBeenCalledWith('.storybook/main.ts', expect.any(String));\n    expect(vi.mocked(writeFile).mock.calls[0][1]).toMatchInlineSnapshot(`\n        \"\n                    export default {\n                      stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n                      docs: {\n                        defaultName: 'Docs'\n                      }\n                    };\n                  \"\n      `);\n  });\n\n  it('removes docs.autodocs field and updates preview.js when autodocs is true', async () => {\n    vi.mocked(readFile).mockImplementation(async (path) => {\n      if (path === '.storybook/main.ts') {\n        return Buffer.from(`\n            export default {\n              stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n              docs: { autodocs: true }\n            };\n          `);\n      }\n      if (path === '.storybook/preview.ts') {\n        return Buffer.from(`\n            export default {\n              tags: ['existing-tag']\n            };\n          `);\n      }\n      return Buffer.from('');\n    });\n\n    await typedRemoveDocsAutodocs.run({\n      result: { autodocs: true },\n      packageManager: mockPackageManager,\n      configDir: '.storybook',\n      mainConfigPath: '.storybook/main.ts',\n      previewConfigPath: '.storybook/preview.ts',\n      storybookVersion: '9.0.0',\n      mainConfig: {} as StorybookConfigRaw,\n      storiesPaths: [],\n    });\n\n    expect(writeFile).toHaveBeenCalledTimes(2);\n    expect(writeFile).toHaveBeenCalledWith('.storybook/main.ts', expect.any(String));\n    expect(writeFile).toHaveBeenCalledWith('.storybook/preview.ts', expect.any(String));\n    expect(vi.mocked(writeFile).mock.calls[0][1]).toMatchInlineSnapshot(`\n        \"\n                    export default {\n                      stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)']\n                    };\n                  \"\n      `);\n    expect(String(vi.mocked(writeFile).mock.calls[1][1]).replaceAll(`\"`, `'`))\n      .toMatchInlineSnapshot(`\n        \"\n                    export default {\n                      tags: ['existing-tag', 'autodocs']\n                    };\n                  \"\n      `);\n  });\n\n  it('adds autodocs tag to empty tags array in preview.js when autodocs is true', async () => {\n    vi.mocked(readFile).mockImplementation(async (path) => {\n      if (path === '.storybook/main.ts') {\n        return Buffer.from(`\n            export default {\n              stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n              docs: { autodocs: true }\n            };\n          `);\n      }\n      if (path === '.storybook/preview.ts') {\n        return Buffer.from(`\n            export default {\n              tags: []\n            };\n          `);\n      }\n      return Buffer.from('');\n    });\n\n    await typedRemoveDocsAutodocs.run({\n      result: { autodocs: true },\n      packageManager: mockPackageManager,\n      configDir: '.storybook',\n      mainConfigPath: '.storybook/main.ts',\n      previewConfigPath: '.storybook/preview.ts',\n      storybookVersion: '9.0.0',\n      mainConfig: {} as StorybookConfigRaw,\n      storiesPaths: [],\n    });\n\n    expect(writeFile).toHaveBeenCalledTimes(2);\n    expect(writeFile).toHaveBeenCalledWith('.storybook/main.ts', expect.any(String));\n    expect(writeFile).toHaveBeenCalledWith('.storybook/preview.ts', expect.any(String));\n    expect(vi.mocked(writeFile).mock.calls[0][1]).toMatchInlineSnapshot(`\n        \"\n                    export default {\n                      stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)']\n                    };\n                  \"\n      `);\n    expect(vi.mocked(writeFile).mock.calls[1][1]).toMatchInlineSnapshot(`\n        \"\n                    export default {\n                      tags: [\"autodocs\"]\n                    };\n                  \"\n      `);\n  });\n\n  it('does nothing in dry run mode', async () => {\n    vi.mocked(readFile).mockImplementation(async (path) => {\n      if (path === 'main.ts') {\n        return Buffer.from(`\n            export default {\n              stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n              docs: { autodocs: true }\n            };\n          `);\n      }\n      if (path === 'preview.ts') {\n        return Buffer.from(`\n            export default {\n              tags: ['existing-tag']\n            };\n          `);\n      }\n      return Buffer.from('');\n    });\n\n    await typedRemoveDocsAutodocs.run({\n      result: { autodocs: true },\n      packageManager: mockPackageManager,\n      mainConfigPath: '.storybook/main.ts',\n      configDir: '.storybook',\n      previewConfigPath: '.storybook/preview.ts',\n      storybookVersion: '9.0.0',\n      mainConfig: {} as StorybookConfigRaw,\n      dryRun: true,\n      storiesPaths: [],\n    });\n\n    expect(writeFile).not.toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/remove-docs-autodocs.ts",
    "content": "import { Tag } from 'storybook/internal/core-server';\nimport { readConfig } from 'storybook/internal/csf-tools';\n\nimport picocolors from 'picocolors';\n\nimport { updateMainConfig } from '../helpers/mainConfigFile.ts';\nimport type { Fix } from '../types.ts';\n\nconst logger = {\n  log: (message: string) => {\n    if (process.env.NODE_ENV !== 'test') {\n      console.log(message);\n    }\n  },\n};\n\ninterface RemoveDocsAutodocsOptions {\n  autodocs: boolean | 'tag' | undefined;\n}\n\n/**\n * Migration to remove the docs.autodocs field from main.ts config This field was deprecated in\n * Storybook 7-8 and removed in Storybook 9\n */\nexport const removeDocsAutodocs: Fix<RemoveDocsAutodocsOptions> = {\n  id: 'remove-docs-autodocs',\n  link: 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#mainjs-docsautodocs-is-deprecated',\n\n  async check({ mainConfigPath }) {\n    if (!mainConfigPath) {\n      return null;\n    }\n\n    try {\n      const config = await readConfig(mainConfigPath);\n      const autodocs = config.getSafeFieldValue(['docs', 'autodocs']);\n\n      if (autodocs === undefined) {\n        return null;\n      }\n\n      return {\n        autodocs,\n      };\n    } catch (err) {\n      return null;\n    }\n  },\n\n  prompt: () => {\n    return `${picocolors.cyan('docs.autodocs')} has been removed in Storybook 9 and will be removed from your configuration.`;\n  },\n\n  async run({ result, dryRun, mainConfigPath, previewConfigPath }) {\n    const { autodocs } = result;\n\n    // Remove autodocs from main config\n    logger.log(`🔄 Updating ${picocolors.cyan('docs')} parameter in main config file...`);\n    await updateMainConfig({ mainConfigPath, dryRun: !!dryRun }, async (main) => {\n      const docs = main.getFieldValue(['docs']) || {};\n\n      if (!dryRun) {\n        delete docs.autodocs;\n\n        // If docs object is now empty, remove it entirely\n        if (Object.keys(docs).length === 0) {\n          main.removeField(['docs']);\n        } else {\n          main.setFieldValue(['docs'], docs);\n        }\n      }\n    });\n\n    // If autodocs was true, update preview config to use tags\n    if (autodocs === true && previewConfigPath) {\n      logger.log(`🔄 Updating ${picocolors.cyan('tags')} parameter in preview config file...`);\n      await updateMainConfig(\n        { mainConfigPath: previewConfigPath, dryRun: !!dryRun },\n        async (preview) => {\n          const tags = preview.getFieldValue(['tags']) || [];\n\n          if (!tags.includes(Tag.AUTODOCS) && !dryRun) {\n            preview.setFieldValue(['tags'], [...tags, Tag.AUTODOCS]);\n          }\n        }\n      );\n    }\n  },\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/remove-essentials.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { JsPackageManager, removeAddon } from 'storybook/internal/common';\nimport { formatConfig, readConfig } from 'storybook/internal/csf-tools';\nimport type { StorybookConfigRaw } from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\n\nimport { add } from '../../add.ts';\nimport type { CheckOptions, RunOptions } from '../types.ts';\nimport { removeEssentials } from './remove-essentials.ts';\nimport { moveEssentialOptions } from './remove-essentials.utils.ts';\n\n// Mock modules before any other imports or declarations\nvi.mock('node:fs/promises', async () => {\n  return {\n    readFile: vi.fn(),\n    lstat: vi.fn(),\n    readdir: vi.fn(),\n    readlink: vi.fn(),\n    realpath: vi.fn(),\n  };\n});\n\nvi.mock('../helpers/mainConfigFile', () => {\n  const updateMainConfig = vi.fn().mockImplementation(({ mainConfigPath }, callback) => {\n    return callback(mockConfigs.get(mainConfigPath));\n  });\n  return { updateMainConfig };\n});\n\nvi.mock('storybook/internal/common', async (importOriginal) => {\n  return {\n    ...(await importOriginal<typeof import('storybook/internal/common')>()),\n    getAddonNames: vi.fn(),\n    getProjectRoot: () => '/fake/project/root',\n    commonGlobOptions: vi.fn().mockReturnValue({}),\n    removeAddon: vi.fn().mockResolvedValue(undefined),\n    transformImportFiles: vi.fn().mockResolvedValue([]),\n  };\n});\n\nvi.mock('../../add', () => ({\n  add: vi.fn(),\n}));\n\nvi.mock('globby', () => ({\n  globby: vi.fn().mockResolvedValue(['/fake/project/root/src/stories/Button.stories.tsx']),\n}));\n\n// Mock ConfigFile type\ninterface MockConfigFile {\n  getFieldValue: (path: string[]) => any;\n  setFieldValue: (path: string[], value: any) => void;\n  appendValueToArray: (path: string[], value: any) => void;\n  removeField: (path: string[]) => void;\n  _ast: Record<string, unknown>;\n  _code: string;\n  _exports: Record<string, unknown>;\n  _exportDecls: unknown[];\n}\n\n// Store mock configs by path\nconst mockConfigs = new Map<string, MockConfigFile>();\n\n// Get reference to mocked readFile\nconst readFileMock = vi.mocked(await import('node:fs/promises')).readFile;\n\nconst mockPackageManager = vi.mocked(JsPackageManager.prototype);\nconst mockRemoveAddon = vi.mocked(removeAddon);\nconst mockTransformImportFiles = vi.mocked(\n  await import('storybook/internal/common')\n).transformImportFiles;\n\nconst mockedAdd = vi.mocked(add);\n\nconst baseCheckOptions: CheckOptions = {\n  packageManager: mockPackageManager,\n  mainConfig: {\n    stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n    addons: ['@storybook/addon-links'],\n  } as StorybookConfigRaw,\n  storybookVersion: '7.0.0',\n  configDir: '.storybook',\n  storiesPaths: [],\n  hasCsfFactoryPreview: false,\n};\n\ninterface AddonDocsOptions {\n  hasEssentials: boolean;\n  hasDocsDisabled: boolean;\n  hasDocsAddon: boolean;\n  additionalAddonsToRemove: string[];\n}\n\n// Add type for migration object\ninterface Migration {\n  check: (options: CheckOptions) => Promise<AddonDocsOptions | null>;\n  run: (options: RunOptions<any>) => Promise<void>;\n}\n\nconst typedAddonDocsEssentials = removeEssentials as Migration;\n\ndescribe('remove-essentials migration', () => {\n  beforeEach(() => {\n    // @ts-expect-error Ignore readonly property\n    mockPackageManager.primaryPackageJson = {\n      packageJson: { devDependencies: {}, dependencies: {} },\n      packageJsonPath: 'some/path',\n      operationDir: 'some/path',\n    };\n    mockPackageManager.packageJsonPaths = ['some/path'];\n    mockPackageManager.runPackageCommand = vi.fn();\n    mockPackageManager.getAllDependencies = vi.fn(() => ({}));\n    mockPackageManager.addDependencies = vi.fn();\n    mockPackageManager.getInstalledVersion = vi.fn().mockResolvedValue(null);\n    mockPackageManager.isPackageInstalled = vi.fn().mockResolvedValue(false);\n\n    vi.clearAllMocks();\n    mockConfigs.clear();\n  });\n\n  describe('check phase', () => {\n    it('returns null if no mainConfigPath provided', async () => {\n      const result = await typedAddonDocsEssentials.check(baseCheckOptions);\n      expect(result).toBeNull();\n    });\n\n    it('returns null if essentials and no core addons found in config', async () => {\n      const mainConfig = `\n        export default {\n          stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n          addons: ['@storybook/addon-links'],\n        };\n      `;\n      readFileMock.mockResolvedValueOnce(mainConfig);\n\n      const result = await typedAddonDocsEssentials.check({\n        ...baseCheckOptions,\n        mainConfigPath: 'main.ts',\n        mainConfig: {\n          stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n          addons: ['@storybook/addon-links'],\n        } as StorybookConfigRaw,\n      });\n      expect(result).toBeNull();\n    });\n\n    it('detects essentials with docs disabled and core addons', async () => {\n      const mockMain: MockConfigFile = {\n        getFieldValue: vi.fn().mockReturnValue([\n          {\n            name: '@storybook/addon-essentials',\n            options: { docs: false },\n          },\n          '@storybook/addon-actions',\n        ]),\n        setFieldValue: vi.fn(),\n        appendValueToArray: vi.fn(),\n        removeField: vi.fn(),\n        _ast: {},\n        _code: '',\n        _exports: {},\n        _exportDecls: [],\n      };\n\n      mockConfigs.set('main.ts', mockMain);\n      vi.mocked(await import('storybook/internal/common')).getAddonNames.mockReturnValue([\n        '@storybook/addon-essentials',\n        '@storybook/addon-actions',\n      ]);\n\n      const mockPackageJsonWithAddons = {\n        dependencies: {\n          '@storybook/addon-controls': '^7.0.0',\n        },\n        devDependencies: {\n          '@storybook/addon-toolbars': '^7.0.0',\n        },\n      };\n\n      // @ts-expect-error Ignore readonly property\n      mockPackageManager.primaryPackageJson = {\n        packageJson: mockPackageJsonWithAddons,\n        packageJsonPath: 'some/path',\n        operationDir: 'some/path',\n      };\n\n      mockPackageManager.getAllDependencies.mockReturnValue({\n        ...mockPackageJsonWithAddons.dependencies,\n        ...mockPackageJsonWithAddons.devDependencies,\n      });\n\n      const result = await typedAddonDocsEssentials.check({\n        ...baseCheckOptions,\n        mainConfigPath: 'main.ts',\n        mainConfig: {\n          stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n          addons: [\n            {\n              name: '@storybook/addon-essentials',\n              options: { docs: false },\n            },\n            '@storybook/addon-actions',\n          ],\n        } as StorybookConfigRaw,\n      });\n      expect(result).toEqual({\n        hasEssentials: true,\n        hasDocsDisabled: true,\n        hasDocsAddon: false,\n        additionalAddonsToRemove: [\n          '@storybook/addon-actions',\n          '@storybook/addon-controls',\n          '@storybook/addon-toolbars',\n        ],\n        allDeps: {\n          '@storybook/addon-controls': '^7.0.0',\n          '@storybook/addon-toolbars': '^7.0.0',\n        },\n      });\n    });\n\n    it('detects only core addons without essentials', async () => {\n      const mockMain: MockConfigFile = {\n        getFieldValue: vi.fn().mockReturnValue(['@storybook/addon-actions']),\n        setFieldValue: vi.fn(),\n        appendValueToArray: vi.fn(),\n        removeField: vi.fn(),\n        _ast: {},\n        _code: '',\n        _exports: {},\n        _exportDecls: [],\n      };\n\n      mockConfigs.set('main.ts', mockMain);\n      vi.mocked(await import('storybook/internal/common')).getAddonNames.mockReturnValue([\n        '@storybook/addon-actions',\n      ]);\n\n      const mockPackageJsonWithViewport = {\n        dependencies: {},\n        devDependencies: {\n          '@storybook/addon-viewport': '^7.0.0',\n        },\n      };\n\n      // @ts-expect-error Ignore readonly property\n      mockPackageManager.primaryPackageJson = {\n        packageJson: mockPackageJsonWithViewport,\n        packageJsonPath: 'some/path',\n        operationDir: 'some/path',\n      };\n\n      mockPackageManager.getAllDependencies.mockReturnValue({\n        ...mockPackageJsonWithViewport.dependencies,\n        ...mockPackageJsonWithViewport.devDependencies,\n      });\n\n      const result = await typedAddonDocsEssentials.check({\n        ...baseCheckOptions,\n        mainConfigPath: 'main.ts',\n        mainConfig: {\n          stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n          addons: ['@storybook/addon-actions'],\n        } as StorybookConfigRaw,\n      });\n      expect(result).toEqual({\n        hasEssentials: false,\n        hasDocsDisabled: false,\n        hasDocsAddon: false,\n        additionalAddonsToRemove: ['@storybook/addon-actions', '@storybook/addon-viewport'],\n        allDeps: {\n          '@storybook/addon-viewport': '^7.0.0',\n        },\n      });\n    });\n  });\n\n  describe('run phase', () => {\n    it('removes essentials addon and core addons when docs is disabled', async () => {\n      await typedAddonDocsEssentials.run({\n        result: {\n          hasEssentials: true,\n          hasDocsDisabled: true,\n          hasDocsAddon: false,\n          additionalAddonsToRemove: ['@storybook/addon-actions', '@storybook/addon-controls'],\n        },\n        configDir: '.storybook',\n        packageManager: mockPackageManager,\n        storiesPaths: [],\n        mainConfigPath: '.storybook/main.ts',\n        storybookVersion: '8.0.0',\n        mainConfig: {} as StorybookConfigRaw,\n      });\n\n      expect(mockRemoveAddon).toHaveBeenCalledWith(\n        '@storybook/addon-essentials',\n        expect.any(Object)\n      );\n      expect(mockRemoveAddon).toHaveBeenCalledWith('@storybook/addon-actions', expect.any(Object));\n      expect(mockRemoveAddon).toHaveBeenCalledWith('@storybook/addon-controls', expect.any(Object));\n      expect(mockRemoveAddon).toHaveBeenCalledTimes(3);\n    });\n\n    it('does not add docs addon if essentials is not present', async () => {\n      await typedAddonDocsEssentials.run({\n        result: {\n          hasEssentials: false,\n          hasDocsDisabled: false,\n          hasDocsAddon: false,\n          additionalAddonsToRemove: [],\n        },\n        packageManager: mockPackageManager,\n        storiesPaths: [],\n        mainConfigPath: '.storybook/main.ts',\n        configDir: '.storybook',\n        storybookVersion: '8.0.0',\n        mainConfig: {} as StorybookConfigRaw,\n      });\n\n      expect(mockRemoveAddon).not.toHaveBeenCalledWith('@storybook/addon-docs', expect.any(Object));\n    });\n\n    it('removes core addons without essentials', async () => {\n      await typedAddonDocsEssentials.run({\n        result: {\n          hasEssentials: false,\n          hasDocsDisabled: false,\n          hasDocsAddon: false,\n          additionalAddonsToRemove: ['@storybook/addon-actions', '@storybook/addon-controls'],\n        },\n        packageManager: mockPackageManager,\n        storiesPaths: [],\n        mainConfigPath: '.storybook/main.ts',\n        configDir: '.storybook',\n        storybookVersion: '8.0.0',\n        mainConfig: {} as StorybookConfigRaw,\n      });\n\n      expect(mockRemoveAddon).toHaveBeenCalledWith('@storybook/addon-actions', expect.any(Object));\n      expect(mockRemoveAddon).toHaveBeenCalledWith('@storybook/addon-controls', expect.any(Object));\n      expect(mockRemoveAddon).toHaveBeenCalledTimes(2);\n    });\n\n    it('does not add docs addon if essentials is not present', async () => {\n      await typedAddonDocsEssentials.run({\n        result: {\n          hasEssentials: false,\n          hasDocsDisabled: false,\n          hasDocsAddon: false,\n          additionalAddonsToRemove: [],\n        },\n        packageManager: mockPackageManager,\n        storiesPaths: [],\n        mainConfigPath: '.storybook/main.ts',\n        configDir: '.storybook',\n        storybookVersion: '8.0.0',\n        mainConfig: {} as StorybookConfigRaw,\n      });\n\n      expect(mockPackageManager.runPackageCommand).not.toHaveBeenCalledWith('storybook', [\n        'add',\n        '@storybook/addon-docs',\n        '--config-dir',\n        '.storybook',\n      ]);\n    });\n\n    it('does add docs addon if essentials is present', async () => {\n      await typedAddonDocsEssentials.run({\n        result: {\n          hasEssentials: true,\n          hasDocsDisabled: false,\n          hasDocsAddon: false,\n          additionalAddonsToRemove: [],\n        },\n        packageManager: mockPackageManager,\n        storiesPaths: [],\n        mainConfigPath: '.storybook/main.ts',\n        configDir: '.storybook',\n        storybookVersion: '8.0.0',\n        mainConfig: {} as StorybookConfigRaw,\n      });\n\n      expect(mockedAdd).toHaveBeenCalledWith('@storybook/addon-docs', {\n        configDir: '.storybook',\n        packageManager: mockPackageManager.type,\n        skipInstall: true,\n        skipPostinstall: true,\n        yes: true,\n      });\n    });\n\n    it('handles import transformations', async () => {\n      await typedAddonDocsEssentials.run({\n        result: {\n          hasEssentials: false,\n          hasDocsDisabled: false,\n          hasDocsAddon: false,\n          additionalAddonsToRemove: ['@storybook/addon-actions', '@storybook/addon-controls'],\n        },\n        packageManager: mockPackageManager,\n        storiesPaths: [],\n        configDir: '.storybook',\n        storybookVersion: '8.0.0',\n        mainConfigPath: '.storybook/main.ts',\n        mainConfig: {} as StorybookConfigRaw,\n      });\n\n      expect(mockTransformImportFiles).toHaveBeenCalledWith(\n        ['.storybook/main.ts'],\n        {\n          '@storybook/addon-actions': 'storybook/actions',\n          '@storybook/addon-backgrounds': 'storybook/backgrounds',\n          '@storybook/addon-controls': 'storybook/internal/controls',\n          '@storybook/addon-highlight': 'storybook/highlight',\n          '@storybook/addon-measure': 'storybook/measure',\n          '@storybook/addon-outline': 'storybook/outline',\n          '@storybook/addon-toolbars': 'storybook/internal/toolbars',\n          '@storybook/addon-viewport': 'storybook/viewport',\n        },\n        undefined\n      );\n    });\n\n    it('does nothing in dry run mode', async () => {\n      await typedAddonDocsEssentials.run({\n        result: {\n          hasEssentials: true,\n          hasDocsDisabled: false,\n          hasDocsAddon: false,\n          additionalAddonsToRemove: ['@storybook/addon-actions', '@storybook/addon-controls'],\n        },\n        packageManager: mockPackageManager,\n        storiesPaths: [],\n        configDir: '.storybook',\n        storybookVersion: '8.0.0',\n        mainConfigPath: '.storybook/main.ts',\n        mainConfig: {} as StorybookConfigRaw,\n        dryRun: true,\n      });\n\n      expect(mockPackageManager.runPackageCommand).not.toHaveBeenCalled();\n    });\n\n    it('handles missing essentials addon and no core addons gracefully', async () => {\n      await typedAddonDocsEssentials.run({\n        result: {\n          hasEssentials: false,\n          hasDocsDisabled: false,\n          hasDocsAddon: false,\n          additionalAddonsToRemove: [],\n        },\n        packageManager: mockPackageManager,\n        configDir: '.storybook',\n        storiesPaths: [],\n        storybookVersion: '8.0.0',\n        mainConfigPath: 'main.ts',\n        mainConfig: {} as StorybookConfigRaw,\n      });\n\n      expect(mockPackageManager.runPackageCommand).not.toHaveBeenCalled();\n    });\n  });\n});\n\ndescribe('moveEssentialOptions', () => {\n  it('should move essential options to features', async () => {\n    const main = await readConfig('main.ts');\n    await moveEssentialOptions(false, {\n      docs: false,\n      backgrounds: false,\n      measure: false,\n      outline: false,\n      grid: false,\n    })(main);\n\n    expect(dedent(formatConfig(main))).toMatchInlineSnapshot(`\n      \"export default {\n        stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n        addons: ['@storybook/addon-links'],\n\n        features: {\n          docs: false,\n          backgrounds: false,\n          measure: false,\n          outline: false,\n          grid: false\n        }\n      };\"\n    `);\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/remove-essentials.ts",
    "content": "import { getAddonNames, removeAddon, transformImportFiles } from 'storybook/internal/common';\n\nimport { add } from '../../add.ts';\nimport { updateMainConfig } from '../helpers/mainConfigFile.ts';\nimport type { Fix } from '../types.ts';\nimport { moveEssentialOptions } from './remove-essentials.utils.ts';\n\ninterface AddonDocsOptions {\n  hasEssentials: boolean;\n  essentialsOptions?: Record<string, any>;\n  hasDocsDisabled: boolean;\n  hasDocsAddon: boolean;\n  additionalAddonsToRemove: string[];\n  allDeps: Record<string, string>;\n}\n\nconst consolidatedAddons = {\n  '@storybook/addon-actions': 'storybook/actions',\n  '@storybook/addon-controls': 'storybook/internal/controls',\n  '@storybook/addon-toolbars': 'storybook/internal/toolbars',\n  '@storybook/addon-highlight': 'storybook/highlight',\n  '@storybook/addon-measure': 'storybook/measure',\n  '@storybook/addon-outline': 'storybook/outline',\n  '@storybook/addon-backgrounds': 'storybook/backgrounds',\n  '@storybook/addon-viewport': 'storybook/viewport',\n};\n\n/**\n * Migration to handle @storybook/addon-essentials being removed and its features moving to core\n *\n * - Remove @storybook/addon-essentials from main.ts and package.json\n * - If user had docs enabled (default): Install @storybook/addon-docs and add to main.ts\n * - If user had docs disabled: Skip addon-docs installation\n */\nexport const removeEssentials: Fix<AddonDocsOptions> = {\n  id: 'remove-essential-addons',\n  link: 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#essentials-addon-viewport-controls-interactions-and-actions-moved-to-core',\n\n  async check({ mainConfigPath, mainConfig, packageManager }) {\n    if (!mainConfigPath) {\n      return null;\n    }\n\n    try {\n      let hasEssentialsAddon = false;\n      let hasDocsAddon = false;\n      let hasDocsDisabled = false;\n      let essentialsOptions: Record<string, any> | undefined = undefined;\n      const additionalAddonsToRemove: string[] = [];\n\n      const CORE_ADDONS = [\n        '@storybook/addon-actions',\n        '@storybook/addon-backgrounds',\n        '@storybook/addon-controls',\n        '@storybook/addon-highlight',\n        '@storybook/addon-measure',\n        '@storybook/addon-outline',\n        '@storybook/addon-toolbars',\n        '@storybook/addon-viewport',\n      ];\n\n      const addonNames = getAddonNames(mainConfig);\n\n      // Check if essentials is present\n      hasEssentialsAddon = addonNames.includes('@storybook/addon-essentials');\n      hasDocsAddon = addonNames.includes('@storybook/addon-docs');\n\n      const allDeps = packageManager.getAllDependencies();\n\n      const installedAddons = Object.keys(allDeps);\n\n      // Check for additional addons that need to be removed\n      for (const addon of CORE_ADDONS) {\n        if (addonNames.includes(addon) || installedAddons.includes(addon)) {\n          additionalAddonsToRemove.push(addon);\n        }\n      }\n\n      if (hasEssentialsAddon) {\n        // Find the essentials entry to check its configuration\n        const essentialsEntry = mainConfig.addons?.find((addon) => {\n          if (typeof addon === 'string') {\n            return addon.includes('@storybook/addon-essentials');\n          }\n          return addon.name.includes('@storybook/addon-essentials');\n        });\n\n        // Check if docs is explicitly disabled in the options\n        if (typeof essentialsEntry === 'object') {\n          const options = essentialsEntry.options || {};\n          hasDocsDisabled = options.docs === false;\n\n          const optionsExceptDocs = Object.fromEntries(\n            Object.entries(options).filter(([key]) => key !== 'docs')\n          );\n\n          if (Object.keys(optionsExceptDocs).length > 0) {\n            essentialsOptions = optionsExceptDocs;\n          }\n        }\n      }\n\n      if (!hasEssentialsAddon && additionalAddonsToRemove.length === 0) {\n        return null;\n      }\n\n      const result: AddonDocsOptions = {\n        hasEssentials: hasEssentialsAddon,\n        hasDocsDisabled,\n        hasDocsAddon,\n        additionalAddonsToRemove,\n        allDeps,\n      };\n\n      if (essentialsOptions) {\n        result.essentialsOptions = essentialsOptions;\n      }\n\n      return result;\n    } catch (err) {\n      return null;\n    }\n  },\n\n  prompt() {\n    return \"In Storybook 9.0, several addons have been moved into Storybook's core and are no longer needed as separate packages. We'll remove the unnecessary addons from your configuration and dependencies, and update your code to use the new core features.\";\n  },\n\n  async run({\n    result,\n    dryRun,\n    packageManager,\n    configDir,\n    storiesPaths,\n    mainConfigPath,\n    previewConfigPath,\n  }) {\n    const { hasEssentials, hasDocsDisabled, additionalAddonsToRemove, essentialsOptions } = result;\n\n    if (!hasEssentials && additionalAddonsToRemove.length === 0) {\n      return;\n    }\n\n    if (!dryRun) {\n      // Remove addon-essentials package if present\n      if (hasEssentials) {\n        await removeAddon('@storybook/addon-essentials', {\n          configDir,\n          packageManager,\n          skipInstall: true,\n        });\n      }\n\n      // Remove additional core addons\n      for (const addon of additionalAddonsToRemove) {\n        await removeAddon(addon, {\n          configDir,\n          packageManager,\n          skipInstall: true,\n        });\n      }\n\n      const errors = await transformImportFiles(\n        [...storiesPaths, mainConfigPath, previewConfigPath].filter(Boolean) as string[],\n        consolidatedAddons,\n        dryRun\n      );\n\n      if (errors.length > 0) {\n        // eslint-disable-next-line local-rules/no-uncategorized-errors\n        throw new Error(\n          `Failed to process ${errors.length} files:\\n${errors\n            .map(({ file, error }) => `- ${file}: ${error.message}`)\n            .join('\\n')}`\n        );\n      }\n\n      if (essentialsOptions) {\n        await updateMainConfig(\n          { mainConfigPath, dryRun: !!dryRun },\n          moveEssentialOptions(dryRun, essentialsOptions)\n        );\n      }\n\n      // If docs was enabled (not disabled) and not already installed, add it\n      if (!hasDocsDisabled && hasEssentials) {\n        await add('@storybook/addon-docs', {\n          configDir,\n          packageManager: packageManager.type,\n          skipInstall: true,\n          skipPostinstall: true,\n          yes: true,\n        });\n      }\n    }\n  },\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/remove-essentials.utils.ts",
    "content": "import type { ConfigFile } from 'storybook/internal/csf-tools';\n\nexport function moveEssentialOptions(\n  dryRun: boolean | undefined,\n  essentialsOptions: Record<string, any>\n): (main: ConfigFile) => Promise<void> | void {\n  return async (main) => {\n    const features = main.getFieldValue(['features']) || {};\n\n    if (!dryRun) {\n      main.setFieldValue(['features'], {\n        ...features,\n        ...essentialsOptions,\n      });\n    }\n  };\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/renderer-to-framework.test.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { dedent } from 'ts-dedent';\n\nimport { removeRendererInPackageJson, transformSourceFiles } from './renderer-to-framework.ts';\nimport { rendererToFramework } from './renderer-to-framework.ts';\n\nvi.mock('node:fs/promises');\nvi.mock('globby', () => ({\n  globby: vi.fn(),\n}));\nvi.mock('p-limit', () => ({\n  default: vi.fn(() => vi.fn((fn) => fn())),\n}));\nvi.mock('storybook/internal/common', async (importOriginal) => ({\n  ...(await importOriginal()),\n  commonGlobOptions: () => ({}),\n  getProjectRoot: () => '/project/root',\n}));\n\nconst mockPackageJson = {\n  dependencies: {\n    '@storybook/react': '^9.0.0',\n    '@storybook/react-vite': '^9.0.0',\n    react: '^18.0.0',\n  },\n  devDependencies: {\n    '@storybook/addon-essentials': '^9.0.0',\n    '@storybook/manager-api': '^9.0.0',\n    typescript: '^5.0.0',\n  },\n};\n\ndescribe('transformSourceFiles', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n    vi.mocked(readFile).mockImplementation(() => Promise.resolve(''));\n    vi.mocked(writeFile).mockImplementation(() => Promise.resolve());\n  });\n\n  it('should transform multiple files', async () => {\n    const sourceContents = dedent`\n      import { something } from '@storybook/react';\n      import { other } from '@storybook/react-vite';\n    `;\n    const sourceFiles = [join('src', 'test1.ts'), join('src', 'test2.ts')];\n\n    vi.mocked(readFile).mockResolvedValue(sourceContents);\n\n    const errors = await transformSourceFiles(\n      sourceFiles,\n      '@storybook/react',\n      '@storybook/react-vite',\n      false\n    );\n\n    expect(errors).toHaveLength(0);\n    expect(writeFile).toHaveBeenCalledTimes(2);\n\n    const firstFile = vi.mocked(writeFile).mock.calls[0][1];\n    expect(firstFile).toMatchInlineSnapshot(dedent`\n      \"import { something } from '@storybook/react-vite';\n      import { other } from '@storybook/react-vite';\"\n    `);\n\n    const secondFile = vi.mocked(writeFile).mock.calls[1][1];\n    expect(secondFile).toMatchInlineSnapshot(dedent`\n      \"import { something } from '@storybook/react-vite';\n      import { other } from '@storybook/react-vite';\"\n    `);\n  });\n  it('should not write files in dry run mode', async () => {\n    const sourceContents = dedent`\n      import { something } from '@storybook/react';\n    `;\n    const sourceFiles = [join('src', 'test.ts')];\n\n    vi.mocked(readFile).mockResolvedValue(sourceContents);\n\n    const errors = await transformSourceFiles(\n      sourceFiles,\n      '@storybook/react',\n      '@storybook/react-vite',\n      true\n    );\n\n    expect(errors).toHaveLength(0);\n    expect(writeFile).not.toHaveBeenCalled();\n  });\n\n  it('should handle file read errors', async () => {\n    const sourceFiles = [join('src', 'test.ts')];\n    vi.mocked(readFile).mockRejectedValueOnce(new Error('Failed to read file'));\n\n    const errors = await transformSourceFiles(\n      sourceFiles,\n      '@storybook/react',\n      '@storybook/react-vite',\n      false\n    );\n\n    expect(errors).toHaveLength(1);\n    expect(errors[0]).toMatchObject({\n      file: sourceFiles[0],\n      error: expect.any(Error),\n    });\n  });\n});\n\ndescribe('removeRendererInPackageJson', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n    vi.mocked(readFile).mockImplementation(() => Promise.resolve('{}'));\n    vi.mocked(writeFile).mockImplementation(() => Promise.resolve());\n  });\n\n  it('should remove renderer packages from dependencies', async () => {\n    const contents = JSON.stringify(mockPackageJson);\n    const filePath = 'test/package.json';\n\n    vi.mocked(readFile).mockResolvedValueOnce(contents);\n\n    const hasChanges = await removeRendererInPackageJson(filePath, '@storybook/react', false);\n\n    expect(hasChanges).toBe(true);\n    const file = vi.mocked(writeFile).mock.calls[0][1];\n    expect(file).toMatchInlineSnapshot(dedent`\n      \"{\n        \"dependencies\": {\n          \"@storybook/react-vite\": \"^9.0.0\",\n          \"react\": \"^18.0.0\"\n        },\n        \"devDependencies\": {\n          \"@storybook/addon-essentials\": \"^9.0.0\",\n          \"@storybook/manager-api\": \"^9.0.0\",\n          \"typescript\": \"^5.0.0\"\n        }\n      }\"\n    `);\n  });\n\n  it('should remove renderer packages from devDependencies', async () => {\n    const contents = JSON.stringify({\n      ...mockPackageJson,\n      dependencies: {},\n      devDependencies: {\n        '@storybook/react-vite': '^9.0.0',\n        '@storybook/react': '^9.0.0',\n      },\n    });\n    const filePath = 'test/package.json';\n\n    vi.mocked(readFile).mockResolvedValueOnce(contents);\n\n    const hasChanges = await removeRendererInPackageJson(filePath, '@storybook/react', false);\n\n    expect(hasChanges).toBe(true);\n    const file = vi.mocked(writeFile).mock.calls[0][1];\n    expect(file).toMatchInlineSnapshot(dedent`\n      \"{\n        \"dependencies\": {},\n        \"devDependencies\": {\n          \"@storybook/react-vite\": \"^9.0.0\"\n        }\n      }\"\n    `);\n  });\n\n  it('should not write files in dry run mode', async () => {\n    const contents = JSON.stringify(mockPackageJson);\n    const filePath = 'test/package.json';\n\n    vi.mocked(readFile).mockResolvedValueOnce(contents);\n\n    const hasChanges = await removeRendererInPackageJson(filePath, '@storybook/react', true);\n\n    expect(hasChanges).toBe(true);\n    expect(writeFile).not.toHaveBeenCalled();\n  });\n\n  it('should handle file read errors', async () => {\n    const filePath = 'test/package.json';\n    vi.mocked(readFile).mockRejectedValueOnce(new Error('Failed to read file'));\n\n    await expect(removeRendererInPackageJson(filePath, '@storybook/react', false)).rejects.toThrow(\n      'Failed to update package.json'\n    );\n  });\n});\n\ndescribe('check', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n    vi.mocked(readFile).mockImplementation(() => Promise.resolve('{}'));\n  });\n\n  it('should detect frameworks and renderers in package.json', async () => {\n    const packageJsonFiles = ['package.json'];\n    const contents = JSON.stringify(mockPackageJson);\n    const mockPackageManager = {\n      packageJsonPaths: packageJsonFiles,\n    };\n\n    vi.mocked(readFile).mockResolvedValue(contents);\n\n    const result = await rendererToFramework.check({ packageManager: mockPackageManager } as any);\n\n    expect(result).toEqual({\n      frameworks: ['@storybook/react-vite'],\n      renderers: ['@storybook/react'],\n      packageJsonFiles: ['package.json'],\n    });\n  });\n\n  it('should handle multiple package.json files', async () => {\n    const packageJsonFiles = ['package.json', 'packages/app/package.json'];\n    const contents1 = JSON.stringify(mockPackageJson);\n    const contents2 = JSON.stringify({\n      dependencies: {\n        '@storybook/vue3': '^9.0.0',\n        '@storybook/vue3-vite': '^9.0.0',\n      },\n    });\n    const mockPackageManager = {\n      packageJsonPaths: packageJsonFiles,\n    };\n\n    vi.mocked(readFile).mockResolvedValueOnce(contents1).mockResolvedValueOnce(contents2);\n\n    const result = await rendererToFramework.check({ packageManager: mockPackageManager } as any);\n\n    expect(result).toEqual({\n      frameworks: ['@storybook/react-vite', '@storybook/vue3-vite'],\n      renderers: ['@storybook/react', '@storybook/vue3'],\n      packageJsonFiles: ['package.json', 'packages/app/package.json'],\n    });\n  });\n\n  it('should return null when no frameworks found', async () => {\n    const packageJsonFiles = ['package.json'];\n    const contents = JSON.stringify({\n      dependencies: {\n        '@storybook/react': '^9.0.0',\n        react: '^18.0.0',\n      },\n    });\n    const mockPackageManager = {\n      packageJsonPaths: packageJsonFiles,\n    };\n\n    vi.mocked(readFile).mockResolvedValue(contents);\n\n    const result = await rendererToFramework.check({ packageManager: mockPackageManager } as any);\n\n    expect(result).toBeNull();\n  });\n\n  it('should return null when no renderers found', async () => {\n    const packageJsonFiles = ['package.json'];\n    const contents = JSON.stringify({\n      dependencies: {\n        '@storybook/react-vite': '^9.0.0',\n        react: '^18.0.0',\n      },\n    });\n    const mockPackageManager = {\n      packageJsonPaths: packageJsonFiles,\n    };\n\n    vi.mocked(readFile).mockResolvedValue(contents);\n\n    const result = await rendererToFramework.check({ packageManager: mockPackageManager } as any);\n\n    expect(result).toBeNull();\n  });\n\n  it('should return null when a renderer was found which is also a framework', async () => {\n    const packageJsonFiles = ['package.json'];\n    const contents = JSON.stringify({\n      dependencies: {\n        '@storybook/angular': '^9.0.0',\n        angular: '^18.0.0',\n      },\n    });\n    const mockPackageManager = {\n      packageJsonPaths: packageJsonFiles,\n    };\n\n    vi.mocked(readFile).mockResolvedValue(contents);\n\n    const result = await rendererToFramework.check({ packageManager: mockPackageManager } as any);\n\n    expect(result).toBeNull();\n  });\n\n  it('should handle file read errors gracefully', async () => {\n    const packageJsonFiles = ['package.json'];\n    const mockPackageManager = {\n      packageJsonPaths: packageJsonFiles,\n    };\n\n    vi.mocked(readFile).mockRejectedValue(new Error('Failed to read file'));\n\n    const result = await rendererToFramework.check({ packageManager: mockPackageManager } as any);\n\n    expect(result).toBeNull();\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/renderer-to-framework.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\n\nimport {\n  frameworkPackages,\n  frameworkToRenderer,\n  rendererPackages,\n} from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\nimport type { PackageJson } from 'storybook/internal/types';\n\nimport type { Fix, RunOptions } from '../types.ts';\n\ninterface MigrationResult {\n  frameworks: string[];\n  renderers: string[];\n  packageJsonFiles: string[];\n}\n\nconst getAllDependencies = (packageJson: PackageJson): string[] =>\n  Object.keys({\n    ...(packageJson.dependencies || {}),\n    ...(packageJson.devDependencies || {}),\n  });\n\nconst detectFrameworks = (dependencies: string[]): string[] => {\n  return Object.keys(frameworkPackages).filter((pkg) => dependencies.includes(pkg));\n};\n\nconst detectRenderers = (dependencies: string[]): string[] => {\n  return Object.keys(rendererPackages)\n    .filter((pkg) => dependencies.includes(pkg))\n    .filter((pkg) => !Object.keys(frameworkPackages).includes(pkg));\n};\n\nconst replaceImports = (source: string, renderer: string, framework: string) => {\n  const regex = new RegExp(`(['\"])${renderer}(['\"])`, 'g');\n  return regex.test(source) ? source.replace(regex, `$1${framework}$2`) : null;\n};\n\nexport const transformSourceFiles = async (\n  files: string[],\n  renderer: string,\n  framework: string,\n  dryRun: boolean\n) => {\n  const errors: Array<{ file: string; error: Error }> = [];\n  const { default: pLimit } = await import('p-limit');\n  const limit = pLimit(10);\n\n  await Promise.all(\n    files.map((file) =>\n      limit(async () => {\n        try {\n          const contents = await readFile(file, 'utf-8');\n          const transformed = replaceImports(contents, renderer, framework);\n          if (!dryRun && transformed) {\n            await writeFile(file, transformed);\n          }\n        } catch (error) {\n          errors.push({ file, error: error as Error });\n        }\n      })\n    )\n  );\n\n  return errors;\n};\n\nexport const removeRendererInPackageJson = async (\n  packageJsonPath: string,\n  renderer: string,\n  dryRun: boolean\n) => {\n  try {\n    const content = await readFile(packageJsonPath, 'utf-8');\n    const packageJson = JSON.parse(content);\n    let hasChanges = false;\n\n    if (packageJson.dependencies?.[renderer]) {\n      delete packageJson.dependencies[renderer];\n      hasChanges = true;\n    }\n    if (packageJson.devDependencies?.[renderer]) {\n      delete packageJson.devDependencies[renderer];\n      hasChanges = true;\n    }\n\n    if (!dryRun && hasChanges) {\n      await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));\n    }\n\n    return hasChanges;\n  } catch (error) {\n    // eslint-disable-next-line local-rules/no-uncategorized-errors\n    throw new Error(`Failed to update package.json: ${error}`);\n  }\n};\n\n// Helper to check if a package.json needs migration\nconst checkPackageJson = async (\n  packageJsonPath: string\n): Promise<{ frameworks: string[]; renderers: string[] } | null> => {\n  const content = await readFile(packageJsonPath, 'utf-8');\n  const packageJson = JSON.parse(content);\n  const dependencies = getAllDependencies(packageJson);\n\n  const frameworks = detectFrameworks(dependencies);\n  if (frameworks.length === 0) {\n    return null;\n  }\n\n  const renderers = detectRenderers(dependencies);\n  if (renderers.length === 0) {\n    return null;\n  }\n\n  return { frameworks, renderers };\n};\n\nexport const rendererToFramework: Fix<MigrationResult> = {\n  id: 'renderer-to-framework',\n  promptType: 'auto',\n  link: 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#moving-from-renderer-based-to-framework-based-configuration',\n\n  async check({ packageManager }): Promise<MigrationResult | null> {\n    // Check each package.json for migration needs\n    const results = await Promise.all(\n      packageManager.packageJsonPaths.map(async (file) => {\n        try {\n          return await checkPackageJson(file);\n        } catch (error) {\n          return null;\n        }\n      })\n    );\n    const validResults = results.filter(\n      (r): r is { frameworks: string[]; renderers: string[] } =>\n        r !== null && r.renderers.length > 0\n    );\n\n    if (validResults.length === 0) {\n      return null;\n    }\n\n    return {\n      frameworks: [...new Set(validResults.flatMap((r) => r.frameworks))],\n      renderers: [...new Set(validResults.flatMap((r) => r.renderers))],\n      packageJsonFiles: packageManager.packageJsonPaths.filter((_, i) => validResults[i] !== null),\n    };\n  },\n\n  prompt(): string {\n    return `We're moving from renderer-based to framework-based configuration and update your imports and dependencies accordingly.`;\n  },\n\n  async run(options: RunOptions<MigrationResult>) {\n    const { result, dryRun = false, storiesPaths, configDir } = options;\n\n    for (const selectedFramework of result.frameworks) {\n      const frameworkName = frameworkPackages[selectedFramework];\n      if (!frameworkName) {\n        logger.warn(`Framework name not found for ${selectedFramework}, skipping.`);\n        continue;\n      }\n      const rendererName = frameworkToRenderer[frameworkPackages[selectedFramework]];\n      const [rendererPackage] =\n        Object.entries(rendererPackages).find(([, renderer]) => renderer === rendererName) ?? [];\n\n      if (!rendererPackage) {\n        logger.warn(`Renderer package not found for ${selectedFramework}, skipping.`);\n        continue;\n      }\n\n      if (rendererPackage === selectedFramework) {\n        continue;\n      }\n\n      logger.debug(`\\nMigrating ${rendererPackage} to ${selectedFramework}`);\n\n      // eslint-disable-next-line depend/ban-dependencies\n      const { globby } = await import('globby');\n      const configFiles = await globby([`${configDir}/**/*`]);\n\n      await transformSourceFiles(\n        [...storiesPaths, ...configFiles].filter(Boolean) as string[],\n        rendererPackage,\n        selectedFramework,\n        dryRun\n      );\n\n      logger.debug('Updating package.json files...');\n\n      // Update all package.json files to remove renderers\n      await Promise.all(\n        result.packageJsonFiles.map((file: string) =>\n          removeRendererInPackageJson(file, rendererPackage, dryRun)\n        )\n      );\n    }\n  },\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/rnstorybook-config.test.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { readFile, rename, writeFile } from 'node:fs/promises';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { StorybookConfigRaw } from 'storybook/internal/types';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport { globby } from 'globby';\n\nimport { makePackageManager } from '../helpers/testing-helpers.ts';\nimport { rnstorybookConfig } from './rnstorybook-config.ts';\n\nconst mockMainConfig: StorybookConfigRaw = {\n  stories: ['../stories/**/*.stories.@(js|jsx|ts|tsx)'],\n};\n\nvi.mock('node:fs', { spy: true });\nvi.mock('node:fs/promises', { spy: true });\nvi.mock('globby', { spy: true });\n\ndescribe('react-native-config fix', () => {\n  beforeEach(() => {\n    vi.mocked(globby).mockResolvedValue(['storybook.requires.ts']);\n    vi.mocked(readFile).mockResolvedValue('');\n    vi.mocked(writeFile).mockResolvedValue();\n    vi.mocked(rename).mockResolvedValue();\n  });\n\n  describe('no-ops', () => {\n    it('when @storybook/react-native is not installed', async () => {\n      const packageManager = makePackageManager({\n        devDependencies: {},\n      });\n\n      await expect(\n        rnstorybookConfig.check({\n          packageManager,\n          mainConfigPath: '.storybook/main.js',\n          mainConfig: mockMainConfig,\n          storybookVersion: '8.0.0',\n          storiesPaths: [],\n          hasCsfFactoryPreview: false,\n        })\n      ).resolves.toBeNull();\n    });\n\n    it('when .storybook directory does not exist', async () => {\n      const packageManager = makePackageManager({\n        devDependencies: {\n          '@storybook/react-native': '^8.0.0',\n        },\n      });\n\n      vi.mocked(existsSync).mockReturnValue(false);\n\n      await expect(\n        rnstorybookConfig.check({\n          packageManager,\n          mainConfigPath: '.storybook/main.js',\n          mainConfig: mockMainConfig,\n          storybookVersion: '8.0.0',\n          storiesPaths: [],\n          hasCsfFactoryPreview: false,\n        })\n      ).resolves.toBeNull();\n    });\n\n    it('when .rnstorybook directory already exists', async () => {\n      const packageManager = makePackageManager({\n        devDependencies: {\n          '@storybook/react-native': '^8.0.0',\n        },\n      });\n      vi.mocked(existsSync).mockReturnValue(true);\n\n      await expect(\n        rnstorybookConfig.check({\n          packageManager,\n          mainConfigPath: '.storybook/main.js',\n          mainConfig: mockMainConfig,\n          storybookVersion: '8.0.0',\n          storiesPaths: [],\n          hasCsfFactoryPreview: false,\n        })\n      ).resolves.toBeNull();\n    });\n\n    it('when @storybook/react-native is installed and .storybook exists but no requires file', async () => {\n      const packageManager = makePackageManager({\n        devDependencies: {\n          '@storybook/react-native': '^8.0.0',\n        },\n      });\n\n      // Mock existsSync to return true for .storybook and false for .rnstorybook\n      vi.mocked(existsSync).mockImplementation((path) => path.toString().includes('.storybook'));\n      vi.mocked(globby).mockResolvedValue([]);\n      const result = await rnstorybookConfig.check({\n        packageManager,\n        mainConfigPath: '.storybook/main.js',\n        mainConfig: mockMainConfig,\n        storybookVersion: '8.0.0',\n        storiesPaths: [],\n        hasCsfFactoryPreview: false,\n      });\n\n      expect(result).toBeNull();\n    });\n  });\n\n  describe('continue', () => {\n    it('when @storybook/react-native is installed and .storybook exists', async () => {\n      const packageManager = makePackageManager({\n        devDependencies: {\n          '@storybook/react-native': '^8.0.0',\n        },\n      });\n\n      // Mock existsSync to return true for .storybook and false for .rnstorybook\n      vi.mocked(existsSync).mockImplementation((path) => path.toString().includes('.storybook'));\n\n      const result = await rnstorybookConfig.check({\n        packageManager,\n        mainConfigPath: '.storybook/main.js',\n        mainConfig: mockMainConfig,\n        storybookVersion: '8.0.0',\n        storiesPaths: [],\n        hasCsfFactoryPreview: false,\n      });\n\n      expect(result).toEqual({\n        storybookDir: expect.stringContaining('.storybook'),\n        rnStorybookDir: expect.stringContaining('.rnstorybook'),\n      });\n    });\n  });\n\n  describe('run', () => {\n    const createMockPackageManagerWithInstanceDir = (instanceDir: string) => {\n      const packageManager = makePackageManager({\n        devDependencies: {\n          '@storybook/react-native': '^8.0.0',\n        },\n      });\n      // Mock the instanceDir as a readonly property\n      Object.defineProperty(packageManager, 'instanceDir', {\n        value: instanceDir,\n        writable: false,\n        configurable: true,\n      });\n      return packageManager;\n    };\n\n    it('should rename files and update references when not in dry run mode', async () => {\n      const packageManager = createMockPackageManagerWithInstanceDir('/test/project');\n\n      // Mock globby to return files with .storybook references\n      vi.mocked(globby).mockResolvedValue(['/test/project/src/component.tsx']);\n      vi.mocked(readFile).mockImplementation((path) => {\n        if (path === '/test/project/src/component.tsx') {\n          return Promise.resolve('import \".storybook/config\"');\n        }\n        return Promise.resolve('no references here');\n      });\n\n      // Type assertion since we know rnstorybookConfig has a run method\n      await (rnstorybookConfig as any).run({\n        result: {\n          storybookDir: '/test/project/.storybook',\n          rnStorybookDir: '/test/project/.rnstorybook',\n        },\n        dryRun: false,\n        packageManager,\n        mainConfigPath: '/test/project/.storybook/main.js',\n        mainConfig: mockMainConfig,\n        configDir: '/test/project/.storybook',\n        storybookVersion: '8.0.0',\n        storiesPaths: [],\n        skipInstall: false,\n      });\n\n      // Verify the file content was updated\n      expect(vi.mocked(writeFile)).toHaveBeenCalledWith(\n        '/test/project/src/component.tsx',\n        'import \".rnstorybook/config\"',\n        'utf8'\n      );\n\n      // Verify the directory was renamed\n      expect(vi.mocked(rename)).toHaveBeenCalledWith(\n        '/test/project/.storybook',\n        '/test/project/.rnstorybook'\n      );\n    });\n\n    it('should handle errors gracefully when searching for references', async () => {\n      const packageManager = createMockPackageManagerWithInstanceDir('/test/project');\n\n      // Mock globby to throw an error\n      vi.mocked(globby).mockRejectedValue(new Error('File system error'));\n\n      const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});\n\n      // Type assertion since we know rnstorybookConfig has a run method\n      await (rnstorybookConfig as any).run({\n        result: {\n          storybookDir: '/test/project/.storybook',\n          rnStorybookDir: '/test/project/.rnstorybook',\n        },\n        dryRun: false,\n        packageManager,\n        mainConfigPath: '/test/project/.storybook/main.js',\n        mainConfig: mockMainConfig,\n        configDir: '/test/project/.storybook',\n        storybookVersion: '8.0.0',\n        storiesPaths: [],\n        skipInstall: false,\n      });\n\n      // Verify error was logged\n      expect(consoleSpy).toHaveBeenCalledWith(\n        'Unable to search for .storybook references:',\n        expect.any(Error)\n      );\n\n      // Directory should still be renamed even if reference search fails\n      expect(vi.mocked(rename)).toHaveBeenCalledWith(\n        '/test/project/.storybook',\n        '/test/project/.rnstorybook'\n      );\n\n      consoleSpy.mockRestore();\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/rnstorybook-config.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { readFile, rename, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { dedent } from 'ts-dedent';\n\nimport type { Fix } from '../types.ts';\n\ninterface Options {\n  storybookDir: string;\n  rnStorybookDir: string;\n}\n\n/** Replaces all occurrences of a string in a file with another string */\nasync function renameInFile(filePath: string, oldText: string, newText: string): Promise<void> {\n  try {\n    const content = await readFile(filePath, 'utf8');\n    const updatedContent = content.replaceAll(oldText, newText);\n    await writeFile(filePath, updatedContent, 'utf8');\n  } catch (error) {\n    console.error(`Error updating references in ${filePath}:`, error);\n  }\n}\n\nconst getDotStorybookReferences = async (searchDir: string) => {\n  try {\n    // eslint-disable-next-line depend/ban-dependencies\n    const { globby } = await import('globby');\n    const { readFile } = await import('node:fs/promises');\n\n    // Find all relevant files (excluding common directories that shouldn't be searched)\n    const files = await globby(`${searchDir}/**/*`, {\n      onlyFiles: true,\n      gitignore: true,\n    });\n\n    const referencedFiles: string[] = [];\n\n    // Check each file for .storybook references\n    await Promise.all(\n      files.map(async (file) => {\n        try {\n          const content = await readFile(file, 'utf8');\n          if (content.includes('.storybook')) {\n            referencedFiles.push(file);\n          }\n        } catch (readError) {\n          // Skip files that can't be read (e.g., binary files)\n        }\n      })\n    );\n\n    return referencedFiles;\n  } catch (fsError) {\n    console.warn('Unable to search for .storybook references:', fsError);\n    return [];\n  }\n};\n\nexport const rnstorybookConfig: Fix<Options> = {\n  id: 'rnstorybook-config',\n  link: 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#react-native-config-dir-renamed',\n\n  async check({ packageManager, mainConfigPath }) {\n    const allDependencies = packageManager.getAllDependencies();\n\n    if (!allDependencies['@storybook/react-native']) {\n      return null;\n    }\n\n    // Check if .storybook directory exists\n    const projectDir = mainConfigPath ? join(mainConfigPath, '..', '..') : process.cwd();\n    const storybookDir = join(projectDir, '.storybook');\n    const rnStorybookDir = join(projectDir, '.rnstorybook');\n    // eslint-disable-next-line depend/ban-dependencies\n    const { globby } = await import('globby');\n\n    const requiresFiles = await globby(join(storybookDir, 'storybook.requires.*'));\n\n    if (existsSync(storybookDir) && requiresFiles.length > 0 && !existsSync(rnStorybookDir)) {\n      return { storybookDir, rnStorybookDir };\n    }\n\n    return null;\n  },\n\n  prompt() {\n    return dedent`We'll rename your .storybook directory to .rnstorybook and update all references to it.`;\n  },\n\n  async run({ result: { storybookDir, rnStorybookDir }, dryRun, packageManager }) {\n    const instanceDir = packageManager.instanceDir;\n    const dotStorybookReferences = await getDotStorybookReferences(instanceDir);\n\n    if (!dryRun) {\n      await Promise.all(\n        dotStorybookReferences.map(async (ref) => {\n          await renameInFile(ref, '.storybook', '.rnstorybook');\n        })\n      );\n      await rename(storybookDir, rnStorybookDir);\n    }\n  },\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/storybook-package-name-conflict.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport type { StorybookConfigRaw } from 'storybook/internal/types';\n\nimport { makePackageManager } from '../helpers/testing-helpers.ts';\nimport { storybookPackageNameConflict } from './storybook-package-name-conflict.ts';\n\nconst mockMainConfig: StorybookConfigRaw = {\n  stories: [],\n};\n\nconst check = async (packageName: string) => {\n  return storybookPackageNameConflict.check({\n    packageManager: makePackageManager({ name: packageName }),\n    mainConfig: mockMainConfig,\n    storybookVersion: '8.0.0',\n    storiesPaths: [],\n    hasCsfFactoryPreview: false,\n  });\n};\n\ndescribe('storybookPackageNameConflict', () => {\n  describe('check', () => {\n    it('detects when package name is \"storybook\"', async () => {\n      await expect(check('storybook')).resolves.toEqual({\n        packageName: 'storybook',\n      });\n    });\n\n    it('returns null when package name is something else', async () => {\n      await expect(check('my-cool-app')).resolves.toBeNull();\n    });\n\n    it('returns null when package name is undefined', async () => {\n      const result = await storybookPackageNameConflict.check({\n        packageManager: makePackageManager({}),\n        mainConfig: mockMainConfig,\n        storybookVersion: '8.0.0',\n        storiesPaths: [],\n        hasCsfFactoryPreview: false,\n      });\n      expect(result).toBeNull();\n    });\n  });\n\n  describe('prompt', () => {\n    it('includes relevant information about the conflict', () => {\n      const message = storybookPackageNameConflict.prompt();\n      expect(message).toContain('storybook');\n      expect(message).toContain('node_modules/storybook');\n      expect(message).toContain('rename');\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/storybook-package-name-conflict.ts",
    "content": "import picocolors from 'picocolors';\nimport { dedent } from 'ts-dedent';\n\nimport type { Fix } from '../types.ts';\n\ninterface StorybookPackageNameOptions {\n  packageName: string;\n}\n\n/**\n * Detects when a project's package.json \"name\" field is \"storybook\",\n * which conflicts with the actual storybook package in node_modules\n * when using npm/pnpm/yarn workspaces.\n *\n * See: https://github.com/storybookjs/storybook/issues/28725\n */\nexport const storybookPackageNameConflict: Fix<StorybookPackageNameOptions> = {\n  id: 'storybookPackageNameConflict',\n  promptType: 'notification',\n  link: 'https://github.com/storybookjs/storybook/issues/28725',\n\n  async check({ packageManager }) {\n    const packageName = packageManager.primaryPackageJson.packageJson.name;\n\n    if (packageName === 'storybook') {\n      return { packageName };\n    }\n\n    return null;\n  },\n\n  prompt() {\n    return dedent`\n      Your package.json ${picocolors.cyan('\"name\"')} field is set to ${picocolors.cyan('\"storybook\"')}.\n\n      In npm, pnpm, or yarn workspaces this creates a symlink at\n      ${picocolors.yellow('node_modules/storybook')} that shadows the real Storybook\n      package, causing ${picocolors.red('\"Cannot find module storybook/internal/...\"')} errors.\n\n      To fix this, rename the ${picocolors.cyan('\"name\"')} field in your package.json\n      to something other than ${picocolors.cyan('\"storybook\"')} (e.g. \"my-storybook\", \"docs\", \"@myorg/storybook\").\n    `;\n  },\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/upgrade-storybook-related-dependencies.test.ts",
    "content": "import { readFileSync } from 'node:fs';\n\nimport { afterEach, describe, expect, it, vi } from 'vitest';\n\nimport type { JsPackageManager } from 'storybook/internal/common';\nimport type { StorybookConfig } from 'storybook/internal/types';\n\nimport * as docsUtils from '../../doctor/getIncompatibleStorybookPackages.ts';\nimport { upgradeStorybookRelatedDependencies } from './upgrade-storybook-related-dependencies.ts';\n\nvi.mock('../../doctor/getIncompatibleStorybookPackages');\nvi.mock('node:fs', async (importOriginal) => {\n  const actual = (await importOriginal()) as any;\n  return {\n    ...actual,\n    readFileSync: vi.fn(),\n  };\n});\n\nconst check = async ({\n  packageManager,\n  main: mainConfig = {},\n  storybookVersion = '9.0.0',\n}: {\n  packageManager: Partial<JsPackageManager>;\n  main?: Partial<StorybookConfig> & Record<string, unknown>;\n  storybookVersion?: string;\n}) => {\n  return upgradeStorybookRelatedDependencies.check({\n    packageManager: packageManager as any,\n    configDir: '',\n    mainConfig: mainConfig as any,\n    storybookVersion,\n    storiesPaths: [],\n    hasCsfFactoryPreview: false,\n  });\n};\n\ndescribe('upgrade-storybook-related-dependencies fix', () => {\n  afterEach(() => {\n    vi.restoreAllMocks();\n  });\n\n  it('should detect storyshots registered in main.js', async () => {\n    const analyzedPackages = [\n      {\n        packageName: '@chromatic-com/storybook',\n        packageVersion: '1.2.9',\n        availableUpgrade: '2.0.0',\n        hasIncompatibleDependencies: false,\n      },\n      {\n        packageName: '@storybook/jest',\n        packageVersion: '0.2.3',\n        availableUpgrade: '1.0.0',\n        hasIncompatibleDependencies: false,\n      },\n      {\n        packageName: '@storybook/preset-create-react-app',\n        packageVersion: '3.2.0',\n        availableUpgrade: '8.0.0',\n        hasIncompatibleDependencies: true,\n      },\n      {\n        packageName: 'storybook',\n        packageVersion: '8.0.0',\n        availableUpgrade: '8.0.0',\n        hasIncompatibleDependencies: true,\n      },\n    ];\n    vi.mocked(docsUtils.getIncompatibleStorybookPackages).mockResolvedValue(analyzedPackages);\n\n    // Mock the package.json content\n    const mockPackageJson = {\n      dependencies: {\n        '@storybook/jest': '0.2.3',\n        '@storybook/preset-create-react-app': '3.2.0',\n      },\n      devDependencies: {\n        '@chromatic-com/storybook': '1.2.9',\n        storybook: '8.0.0',\n      },\n    };\n\n    vi.mocked(readFileSync).mockReturnValue(JSON.stringify(mockPackageJson));\n\n    const mockPackageManager = {\n      getAllDependencies: () =>\n        analyzedPackages.reduce(\n          (acc, { packageName, packageVersion }) => {\n            acc[packageName] = packageVersion;\n            return acc;\n          },\n          {} as Record<string, string>\n        ),\n      latestVersion: async (pkgName: string) =>\n        analyzedPackages.find((pkg) => pkg.packageName === pkgName)?.availableUpgrade || '',\n      getInstalledVersion: async (pkgName: string) =>\n        analyzedPackages.find((pkg) => pkg.packageName === pkgName)?.packageVersion || null,\n      packageJsonPaths: ['package.json'],\n    };\n\n    await expect(\n      check({\n        packageManager: mockPackageManager,\n      })\n    ).resolves.toMatchInlineSnapshot(`\n      {\n        \"upgradable\": [\n          {\n            \"afterVersion\": \"1.0.0\",\n            \"beforeVersion\": \"0.2.3\",\n            \"packageName\": \"@storybook/jest\",\n          },\n          {\n            \"afterVersion\": \"8.0.0\",\n            \"beforeVersion\": \"3.2.0\",\n            \"packageName\": \"@storybook/preset-create-react-app\",\n          },\n        ],\n      }\n    `);\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/upgrade-storybook-related-dependencies.ts",
    "content": "import { readFileSync } from 'node:fs';\nimport { dirname } from 'node:path';\n\nimport type { PackageJson } from 'storybook/internal/common';\nimport type { JsPackageManager } from 'storybook/internal/common';\nimport { isCorePackage, isSatelliteAddon } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { gt } from 'semver';\nimport { dedent } from 'ts-dedent';\n\nimport { getIncompatibleStorybookPackages } from '../../doctor/getIncompatibleStorybookPackages.ts';\nimport type { Fix } from '../types.ts';\n\ntype PackageMetadata = {\n  packageName: string;\n  beforeVersion: string | null;\n  afterVersion: string | null;\n};\n\ninterface Options {\n  upgradable: PackageMetadata[];\n}\n\nasync function getLatestVersions(\n  packageManager: JsPackageManager,\n  packages: [string, string][]\n): Promise<PackageMetadata[]> {\n  return Promise.all(\n    packages.map(async ([packageName]) => ({\n      packageName,\n      beforeVersion: await packageManager.getInstalledVersion(packageName),\n      afterVersion: await packageManager.latestVersion(packageName),\n    }))\n  );\n}\n\n/** Filter out dependencies that are not valid e.g. yarn patches, git urls and other protocols */\nfunction isValidVersionType(packageName: string, specifier: string) {\n  if (\n    specifier.startsWith('patch:') ||\n    specifier.startsWith('file:') ||\n    specifier.startsWith('link:') ||\n    specifier.startsWith('portal:') ||\n    specifier.startsWith('git:') ||\n    specifier.startsWith('git+') ||\n    specifier.startsWith('http:') ||\n    specifier.startsWith('https:') ||\n    specifier.startsWith('workspace:')\n  ) {\n    logger.debug(`Skipping ${packageName} as it does not have a valid version type: ${specifier}`);\n    return false;\n  }\n\n  return true;\n}\n\n/**\n * Is the user upgrading to the `latest` version of Storybook? Let's try to pull along some of the\n * storybook related dependencies to `latest` as well!\n *\n * We communicate clearly that this migration is a helping hand, but not a complete solution. The\n * user should still manually check for other dependencies that might be incompatible.\n *\n * See: https://github.com/storybookjs/storybook/issues/25731#issuecomment-1977346398\n */\nexport const upgradeStorybookRelatedDependencies = {\n  id: 'upgrade-storybook-related-dependencies',\n  promptType: 'auto',\n  defaultSelected: false,\n\n  async check({ packageManager, storybookVersion }) {\n    logger.debug('Checking for incompatible storybook packages...');\n    const analyzedPackages = await getIncompatibleStorybookPackages({\n      currentStorybookVersion: storybookVersion,\n      packageManager,\n      skipErrors: true,\n    });\n\n    const allDependencies = packageManager.getAllDependencies();\n\n    const storybookDependencies = Object.keys(allDependencies)\n      .filter((dep) => dep.includes('storybook'))\n      .filter((dep) => !isCorePackage(dep) && !isSatelliteAddon(dep));\n\n    const incompatibleDependencies = analyzedPackages\n      .filter((pkg) => pkg.hasIncompatibleDependencies)\n      .map((pkg) => pkg.packageName);\n\n    const uniquePackages = Array.from(\n      new Set(\n        [...storybookDependencies, ...incompatibleDependencies].filter((dep) =>\n          isValidVersionType(dep, allDependencies[dep])\n        )\n      )\n    ).map((packageName) => [packageName, allDependencies[packageName]]) as [string, string][];\n\n    const packageVersions = await getLatestVersions(packageManager, uniquePackages);\n    const upgradablePackages = packageVersions.filter(\n      ({ afterVersion, beforeVersion, packageName }) => {\n        if (\n          beforeVersion === null ||\n          afterVersion === null ||\n          allDependencies[packageName] === null\n        ) {\n          return false;\n        }\n\n        return gt(afterVersion, beforeVersion);\n      }\n    );\n\n    return upgradablePackages.length > 0 ? { upgradable: upgradablePackages } : null;\n  },\n\n  prompt() {\n    return \"We'll upgrade the community packages that are compatible.\";\n  },\n\n  async run({ result: { upgradable }, packageManager, dryRun }) {\n    if (dryRun) {\n      logger.log(dedent`\n        The following would have been upgraded:\n        ${upgradable\n          .map(\n            ({ packageName, afterVersion, beforeVersion }) =>\n              `${packageName}: ${beforeVersion} => ${afterVersion}`\n          )\n          .join('\\n')}\n      `);\n      return;\n    }\n\n    if (upgradable.length > 0) {\n      packageManager.packageJsonPaths.forEach((packageJsonPath) => {\n        const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8')) as PackageJson;\n        upgradable.forEach((item) => {\n          if (!item) {\n            return;\n          }\n\n          const { packageName, afterVersion: version } = item;\n          const prefixed = `^${version}`;\n\n          if (packageJson.dependencies?.[packageName]) {\n            packageJson.dependencies[packageName] = prefixed;\n          }\n          if (packageJson.devDependencies?.[packageName]) {\n            packageJson.devDependencies[packageName] = prefixed;\n          }\n          if (packageJson.peerDependencies?.[packageName]) {\n            packageJson.peerDependencies[packageName] = prefixed;\n          }\n        });\n\n        packageManager.writePackageJson(packageJson, dirname(packageJsonPath));\n      });\n    }\n  },\n} satisfies Fix<Options>;\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/wrap-getAbsolutePath.test.ts",
    "content": "import type { MockInstance } from 'vitest';\nimport { describe, expect, it, vi } from 'vitest';\n\nimport * as detect from 'storybook/internal/cli';\n\nimport type { CheckOptions, RunOptions } from '../types.ts';\nimport { type WrapGetAbsolutePathRunOptions, wrapGetAbsolutePath } from './wrap-getAbsolutePath.ts';\n\nvi.mock('storybook/internal/cli', async (importOriginal) => ({\n  ...(await importOriginal<typeof import('storybook/internal/cli')>()),\n  detectPnp: vi.fn(),\n}));\n\nvi.mock('node:fs/promises', async (importOriginal) => ({\n  ...(await importOriginal<typeof import('node:fs/promises')>()),\n  writeFile: vi.fn(),\n}));\n\ndescribe('wrapGetAbsolutePath', () => {\n  describe('check', () => {\n    it('should return null if not in a monorepo and pnp is not enabled', async () => {\n      (detect.detectPnp as any as MockInstance).mockResolvedValue(false);\n\n      const check = wrapGetAbsolutePath.check({\n        packageManager: {\n          isStorybookInMonorepo: () => false,\n        },\n        storybookVersion: '7.0.0',\n        mainConfigPath: require.resolve('./__test__/main-config-without-wrappers.js'),\n      } as CheckOptions);\n\n      await expect(check).resolves.toBeNull();\n    });\n\n    it('should return the configuration object if in a pnp environment', async () => {\n      (detect.detectPnp as any as MockInstance).mockResolvedValue(true);\n\n      const check = wrapGetAbsolutePath.check({\n        packageManager: {\n          isStorybookInMonorepo: () => false,\n        },\n        storybookVersion: '7.0.0',\n        mainConfigPath: require.resolve('./__test__/main-config-without-wrappers.js'),\n      } as CheckOptions);\n\n      await expect(check).resolves.toEqual({\n        isConfigTypescript: false,\n        isPnp: true,\n        isStorybookInMonorepo: false,\n        storybookVersion: '7.0.0',\n      });\n    });\n\n    it('should return the configuration object if in a monorepo environment', async () => {\n      (detect.detectPnp as any as MockInstance).mockResolvedValue(false);\n\n      const check = wrapGetAbsolutePath.check({\n        packageManager: {\n          isStorybookInMonorepo: () => true,\n        },\n        storybookVersion: '7.0.0',\n        mainConfigPath: require.resolve('./__test__/main-config-without-wrappers.js'),\n      } as CheckOptions);\n\n      await expect(check).resolves.toEqual({\n        isConfigTypescript: false,\n        isPnp: false,\n        isStorybookInMonorepo: true,\n        storybookVersion: '7.0.0',\n      });\n    });\n\n    it('should return null, if all fields have the require wrapper', async () => {\n      (detect.detectPnp as any as MockInstance).mockResolvedValue(true);\n\n      const check = wrapGetAbsolutePath.check({\n        packageManager: {\n          isStorybookInMonorepo: () => true,\n        },\n        storybookVersion: '7.0.0',\n        mainConfigPath: require.resolve('./__test__/main-config-with-wrappers.js'),\n      } as CheckOptions);\n\n      await expect(check).resolves.toBeNull();\n    });\n  });\n\n  describe('run', () => {\n    it('should wrap the require wrapper', async () => {\n      await wrapGetAbsolutePath.run?.({\n        mainConfigPath: require.resolve('./__test__/main-config-without-wrappers.js'),\n        result: {\n          isConfigTypescript: false,\n        },\n      } as RunOptions<WrapGetAbsolutePathRunOptions>);\n\n      const writeFile = vi.mocked((await import('node:fs/promises')).writeFile);\n\n      const call = writeFile.mock.calls[0];\n\n      expect(call[1]).toMatchInlineSnapshot(`\n        \"import { fileURLToPath } from \"node:url\";\n        import { dirname } from \"node:path\";\n        const config = {\n          stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n          addons: [\n            {\n              name: getAbsolutePath(\"@chromatic-com/storybook\"),\n              options: {},\n            },\n            getAbsolutePath(\"@storybook/addon-vitest\"),\n          ],\n          framework: {\n            name: getAbsolutePath(\"@storybook/angular\"),\n            options: {},\n          },\n          docs: {\n            autodocs: 'tag',\n          },\n        };\n        export default config;\n\n        function getAbsolutePath(value) {\n          return dirname(fileURLToPath(import.meta.resolve(\\`\\${value}/package.json\\`)));\n        }\n        \"\n      `);\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/fixes/wrap-getAbsolutePath.ts",
    "content": "import { detectPnp } from 'storybook/internal/cli';\nimport {\n  getAbsolutePathWrapperAsCallExpression,\n  getAbsolutePathWrapperName,\n  getFieldsForGetAbsolutePathWrapper,\n  isGetAbsolutePathWrapperNecessary,\n  wrapValueWithGetAbsolutePathWrapper,\n} from 'storybook/internal/common';\nimport { readConfig } from 'storybook/internal/csf-tools';\nimport { CommonJsConfigNotSupportedError } from 'storybook/internal/server-errors';\n\nimport { dedent } from 'ts-dedent';\n\nimport { updateMainConfig } from '../helpers/mainConfigFile.ts';\nimport type { Fix } from '../types.ts';\n\nexport interface WrapGetAbsolutePathRunOptions {\n  storybookVersion: string;\n  isStorybookInMonorepo: boolean;\n  isPnp: boolean;\n  isConfigTypescript: boolean;\n}\n\nexport const wrapGetAbsolutePath: Fix<WrapGetAbsolutePathRunOptions> = {\n  id: 'wrap-getAbsolutePath',\n  link: 'https://storybook.js.org/docs/faq#how-do-i-fix-module-resolution-in-special-environments',\n\n  async check({ packageManager, storybookVersion, mainConfigPath }) {\n    const isStorybookInMonorepo = packageManager.isStorybookInMonorepo();\n    const isPnp = await detectPnp();\n\n    if (!mainConfigPath) {\n      return null;\n    }\n\n    const config = await readConfig(mainConfigPath);\n\n    if (!isStorybookInMonorepo && !isPnp) {\n      return null;\n    }\n\n    if (\n      !getFieldsForGetAbsolutePathWrapper(config).some((node) =>\n        isGetAbsolutePathWrapperNecessary(node)\n      )\n    ) {\n      return null;\n    }\n\n    const isConfigTypescript = mainConfigPath.endsWith('.ts') || mainConfigPath.endsWith('.tsx');\n\n    return { storybookVersion, isStorybookInMonorepo, isPnp, isConfigTypescript };\n  },\n\n  prompt() {\n    return dedent`We have detected that you're using Storybook in a monorepo or PnP project. Some fields in your main config must be updated.`;\n  },\n\n  async run({ dryRun, mainConfigPath, result }) {\n    await updateMainConfig({ dryRun: !!dryRun, mainConfigPath }, (mainConfig) => {\n      getFieldsForGetAbsolutePathWrapper(mainConfig).forEach((node) => {\n        wrapValueWithGetAbsolutePathWrapper(mainConfig, node);\n      });\n\n      if (getAbsolutePathWrapperName(mainConfig) === null) {\n        if (\n          mainConfig?.fileName?.endsWith('.cjs') ||\n          mainConfig?.fileName?.endsWith('.cts') ||\n          mainConfig?.fileName?.endsWith('.cjsx') ||\n          mainConfig?.fileName?.endsWith('.ctsx') ||\n          mainConfig._code.includes('module.exports')\n        ) {\n          throw new CommonJsConfigNotSupportedError();\n        } else {\n          mainConfig.setImport(['dirname'], 'node:path');\n          mainConfig.setImport(['fileURLToPath'], 'node:url');\n        }\n        mainConfig.setBodyDeclaration(\n          getAbsolutePathWrapperAsCallExpression(result.isConfigTypescript)\n        );\n      }\n    });\n  },\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/helpers/addon-a11y-parameters.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { printConfig, printCsf } from 'storybook/internal/csf-tools';\n\nimport { dedent } from 'ts-dedent';\n\nimport {\n  transformPreviewA11yParameters,\n  transformStoryA11yParameters,\n} from './addon-a11y-parameters.ts';\n\nexpect.addSnapshotSerializer({\n  serialize: (val: any) => (typeof val === 'string' ? val : val.toString()),\n  test: () => true,\n});\n\nconst transformStories = (code: string) => {\n  const transformed = transformStoryA11yParameters(code);\n  return transformed ? printCsf(transformed).code : null;\n};\n\nconst transformPreview = (code: string) => {\n  const transformed = transformPreviewA11yParameters(code);\n  return transformed ? printConfig(transformed).code : null;\n};\n\ndescribe('a11yParameters', () => {\n  describe('transformA11yParameters', () => {\n    it('should transform a11y element to context in story parameters', () => {\n      const code = dedent`\n        import { StoryObj } from '@storybook/react-vite';\n        export default {\n          title: 'Button',\n          parameters: {\n            a11y: {\n              element: '#root',\n            },\n          },\n        };\n        export const TypeAssign: StoryObj = {\n          parameters: {\n            a11y: {\n              element: '#root',\n            },\n          },\n        };\n        export const TypeAlias = {\n          parameters: {\n            a11y: {\n              element: '#root',\n            },\n          },\n        } as StoryObj;\n        export const TypeSatisfies = {\n          parameters: {\n            a11y: {\n              element: '#root',\n            },\n          },\n        } satisfies StoryObj;\n        export const WithNestedProperties = {\n          parameters: {\n            a11y: {\n              element: '#app',\n              config: {\n                rules: [{ id: 'xyz', options: {} }],\n              },\n              options: {},\n            },\n          },\n        };\n      `;\n\n      const transformedCode = transformStories(code);\n\n      expect(transformedCode).toMatchInlineSnapshot(`\n        import { StoryObj } from '@storybook/react-vite';\n        export default {\n          title: 'Button',\n          parameters: {\n            a11y: {\n              context: '#root',\n            },\n          },\n        };\n        export const TypeAssign: StoryObj = {\n          parameters: {\n            a11y: {\n              context: '#root',\n            },\n          },\n        };\n        export const TypeAlias = {\n          parameters: {\n            a11y: {\n              context: '#root',\n            },\n          },\n        } as StoryObj;\n        export const TypeSatisfies = {\n          parameters: {\n            a11y: {\n              context: '#root',\n            },\n          },\n        } satisfies StoryObj;\n        export const WithNestedProperties = {\n          parameters: {\n            a11y: {\n              context: '#app',\n              config: {\n                rules: [{ id: 'xyz', options: {} }],\n              },\n              options: {},\n            },\n          },\n        };\n      `);\n      expect(transformedCode).toContain(\"context: '#root'\");\n    });\n\n    it('should not transform if a11y element is not present', () => {\n      const code = dedent`\n        export default {\n          title: 'Button'\n        };\n        export const Primary = {\n          parameters: {\n            a11y: {\n              other: 'value',\n            },\n          },\n        };\n      `;\n\n      expect(transformStories(code)).toBeNull();\n    });\n\n    it('should handle stories with CSF v2 parameter style', () => {\n      const code = dedent`\n        export default {\n          title: 'Button'\n        };\n        export const Primary = (args) => <Button {...args} />;\n        Primary.parameters = {\n          a11y: {\n            element: '#root',\n          }\n        }\n      `;\n\n      expect(transformStories(code)).toMatchInlineSnapshot(`\n        export default {\n          title: 'Button'\n        };\n        export const Primary = (args) => <Button {...args} />;\n        Primary.parameters = {\n          a11y: {\n            context: '#root',\n          }\n        }\n      `);\n    });\n  });\n\n  describe('transformPreviewA11yParameters', () => {\n    it('should transform a11y element to context in preview parameters', () => {\n      const code = dedent`\n        const preview = {\n          parameters: {\n            a11y: {\n              element: '#root',\n            },\n          },\n        };\n        export default preview;\n      `;\n\n      expect(transformPreview(code)).toMatchInlineSnapshot(`\n        const preview = {\n          parameters: {\n            a11y: {\n              context: '#root',\n            },\n          },\n        };\n        export default preview;\n      `);\n    });\n\n    it('should not transform if a11y element is not present', () => {\n      const code = dedent`\n        const preview = {\n          parameters: {},\n        };\n        export default preview;\n      `;\n\n      expect(transformPreview(code)).toBeNull();\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/helpers/addon-a11y-parameters.ts",
    "content": "import { types as t } from 'storybook/internal/babel';\nimport { type ConfigFile, type CsfFile, loadConfig, loadCsf } from 'storybook/internal/csf-tools';\n\nimport { getObjectProperty, transformStories } from './ast-utils.ts';\n\n// TODO: this is copied from the codemod, we should move both utilities to the csf-tools package at some point\nconst isStoryAnnotation = (stmt: t.Statement, objectExports: Record<string, any>) =>\n  t.isExpressionStatement(stmt) &&\n  t.isAssignmentExpression(stmt.expression) &&\n  t.isMemberExpression(stmt.expression.left) &&\n  t.isIdentifier(stmt.expression.left.object) &&\n  objectExports[stmt.expression.left.object.name];\n\nfunction migrateA11yParameters(obj: t.ObjectExpression): boolean {\n  const parametersValue = getObjectProperty(obj, 'parameters') as t.ObjectExpression | undefined;\n\n  if (parametersValue) {\n    const a11yValue = getObjectProperty(parametersValue, 'a11y') as t.ObjectExpression | undefined;\n\n    if (a11yValue) {\n      const elementProp = a11yValue.properties.find(\n        (prop) =>\n          t.isObjectProperty(prop) && t.isIdentifier(prop.key) && prop.key.name === 'element'\n      );\n      if (elementProp && t.isObjectProperty(elementProp)) {\n        elementProp.key = t.identifier('context');\n        return true;\n      }\n    }\n  }\n\n  return false;\n}\n\nexport function transformStoryA11yParameters(code: string): CsfFile | null {\n  const parsed = loadCsf(code, { makeTitle: (title?: string) => title || 'default' }).parse();\n\n  // Use the story transformer utility to handle all story iteration\n  let hasChanges = transformStories(parsed, (storyObject, storyName, csf) => {\n    return migrateA11yParameters(storyObject);\n  });\n\n  // Also handle CSF2-style story annotations\n  parsed._ast.program.body.forEach((stmt: t.Statement) => {\n    const statement = stmt;\n    if (\n      isStoryAnnotation(statement, parsed._storyExports) &&\n      t.isExpressionStatement(statement) &&\n      t.isAssignmentExpression(statement.expression) &&\n      t.isObjectExpression(statement.expression.right)\n    ) {\n      const parameters = statement.expression.right.properties;\n      parameters.forEach((param) => {\n        if (t.isObjectProperty(param) && t.isIdentifier(param.key) && param.key.name === 'a11y') {\n          const a11yValue = param.value as t.ObjectExpression;\n          const elementProp = a11yValue.properties.find(\n            (prop) =>\n              t.isObjectProperty(prop) && t.isIdentifier(prop.key) && prop.key.name === 'element'\n          );\n          if (elementProp && t.isObjectProperty(elementProp)) {\n            elementProp.key = t.identifier('context');\n            hasChanges = true;\n          }\n        }\n      });\n    }\n  });\n\n  return hasChanges ? parsed : null;\n}\n\nexport function transformPreviewA11yParameters(code: string): ConfigFile | null {\n  const parsed = loadConfig(code).parse();\n\n  if (parsed._exportsObject && t.isObjectExpression(parsed._exportsObject)) {\n    if (migrateA11yParameters(parsed._exportsObject)) {\n      return parsed;\n    }\n  }\n\n  return null;\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/helpers/ast-utils.ts",
    "content": "import { types as t } from 'storybook/internal/babel';\nimport type { CsfFile } from 'storybook/internal/csf-tools';\n\nimport type { Expression, ObjectExpression } from '@babel/types';\n\n/** Get a property from an object expression by name */\nexport function getObjectProperty(\n  obj: ObjectExpression,\n  propertyName: string\n): Expression | undefined {\n  if (!obj || !obj.properties) {\n    return undefined;\n  }\n\n  const property = obj.properties.find(\n    (prop) =>\n      t.isObjectProperty(prop) &&\n      ((t.isIdentifier(prop.key) && prop.key.name === propertyName) ||\n        (t.isStringLiteral(prop.key) && prop.key.value === propertyName))\n  ) as t.ObjectProperty;\n\n  return property?.value as Expression;\n}\n\n/** Remove a property from an object expression by name */\nexport function removeProperty(obj: ObjectExpression, propertyName: string): void {\n  if (!obj || !obj.properties) {\n    return;\n  }\n\n  const index = obj.properties.findIndex(\n    (prop) =>\n      t.isObjectProperty(prop) &&\n      ((t.isIdentifier(prop.key) && prop.key.name === propertyName) ||\n        (t.isStringLiteral(prop.key) && prop.key.value === propertyName))\n  );\n\n  if (index !== -1) {\n    obj.properties.splice(index, 1);\n  }\n}\n\n/** Add a property to an object expression */\nexport function addProperty(obj: ObjectExpression, propertyName: string, value: Expression): void {\n  if (!obj || !obj.properties) {\n    return;\n  }\n\n  obj.properties.push(t.objectProperty(t.identifier(propertyName), value));\n}\n\n/** Get the story object from a declaration (handles both story exports and meta exports) */\nexport function getStoryObject(declaration: t.Node): t.ObjectExpression | undefined {\n  if (t.isVariableDeclarator(declaration)) {\n    // Handle story exports: `export const Story = { ... }`\n    let init = declaration.init;\n    if (t.isTSSatisfiesExpression(init) || t.isTSAsExpression(init)) {\n      init = init.expression;\n    }\n    if (t.isObjectExpression(init)) {\n      return init;\n    }\n  } else if (t.isExportDefaultDeclaration(declaration)) {\n    // Handle meta export: `export default { ... }`\n    let init = declaration.declaration;\n    if (t.isTSSatisfiesExpression(init) || t.isTSAsExpression(init)) {\n      init = init.expression;\n    }\n    if (t.isObjectExpression(init)) {\n      return init;\n    }\n  }\n\n  return undefined;\n}\n\n/** Transform values array to options object for background keys */\nexport function transformValuesToOptions(valuesArray: t.ArrayExpression): t.Expression {\n  // Transform [{ name: 'Light', value: '#FFF' }] to { light: { name: 'Light', value: '#FFF' } }\n  const optionsObject = t.objectExpression([]);\n\n  if (valuesArray && t.isArrayExpression(valuesArray) && valuesArray.elements) {\n    valuesArray.elements.forEach((element) => {\n      if (t.isObjectExpression(element)) {\n        const nameProperty = getObjectProperty(element, 'name');\n\n        if (t.isStringLiteral(nameProperty)) {\n          const key = nameProperty.value.toLowerCase().replace(/\\s+/g, '_');\n\n          // For complex names with dots, brackets, or other special characters, use string literal\n          // For simple names, use identifier\n          const keyNode = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key)\n            ? t.identifier(key)\n            : t.stringLiteral(nameProperty.value);\n\n          optionsObject.properties.push(t.objectProperty(keyNode, element));\n        }\n      }\n    });\n  }\n\n  return optionsObject;\n}\n\n/** Get key from name using the options mapping */\nexport function getKeyFromName(valuesArray: t.ArrayExpression, name: string): string {\n  // Generate a key from a name in the values array\n  if (valuesArray && t.isArrayExpression(valuesArray) && valuesArray.elements) {\n    for (const element of valuesArray.elements) {\n      if (t.isObjectExpression(element)) {\n        const nameProperty = getObjectProperty(element, 'name');\n\n        if (t.isStringLiteral(nameProperty) && nameProperty.value === name) {\n          return name.toLowerCase().replace(/\\s+/g, '_');\n        }\n      }\n    }\n  }\n\n  // If not found, generate a key from the name\n  return name.toLowerCase().replace(/\\s+/g, '_');\n}\n\n/** Options for story transformation */\nexport interface StoryTransformOptions {\n  /** Whether to transform the meta export (export default) */\n  includeMeta?: boolean;\n  /** Whether to transform story exports */\n  includeStories?: boolean;\n}\n\n/** Callback function for transforming a story object */\nexport type StoryTransformCallback = (\n  storyObject: t.ObjectExpression,\n  storyName: string,\n  csf: CsfFile\n) => boolean;\n\n/** Callback function for transforming story parameters */\nexport type StoryParametersTransformCallback = (\n  parameters: t.ObjectExpression,\n  storyObject: t.ObjectExpression,\n  storyName: string,\n  csf: CsfFile\n) => boolean;\n\n/** Callback function for transforming story globals */\nexport type StoryGlobalsTransformCallback = (\n  globals: t.ObjectExpression,\n  storyObject: t.ObjectExpression,\n  storyName: string,\n  csf: CsfFile\n) => boolean;\n\n/** Transform all stories in a CSF file using a callback function */\nexport function transformStories(\n  csf: CsfFile,\n  transformCallback: StoryTransformCallback,\n  options: StoryTransformOptions = { includeMeta: true, includeStories: true }\n): boolean {\n  let hasChanges = false;\n\n  // Transform story exports\n  if (options.includeStories) {\n    Object.entries(csf._storyExports).forEach(([storyName, declaration]) => {\n      const storyObject = getStoryObject(declaration);\n      if (storyObject) {\n        if (transformCallback(storyObject, storyName, csf)) {\n          hasChanges = true;\n        }\n      }\n    });\n  }\n\n  // Transform meta export\n  if (options.includeMeta && csf._metaPath) {\n    const storyObject = getStoryObject(csf._metaPath.node);\n    if (storyObject) {\n      if (transformCallback(storyObject, 'meta', csf)) {\n        hasChanges = true;\n      }\n    }\n  }\n\n  return hasChanges;\n}\n\n/** Transform stories with parameters-specific logic */\nexport function transformStoryParameters(\n  csf: CsfFile,\n  transformParameters: StoryParametersTransformCallback,\n  options: StoryTransformOptions = { includeMeta: true, includeStories: true }\n): boolean {\n  return transformStories(\n    csf,\n    (storyObject, storyName, csf) => {\n      const parameters = getObjectProperty(storyObject, 'parameters') as t.ObjectExpression;\n      if (parameters) {\n        return transformParameters(parameters, storyObject, storyName, csf);\n      }\n      return false;\n    },\n    options\n  );\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/helpers/consolidated-packages.ts",
    "content": "/**\n * Consolidated packages are packages that have been merged into the main storybook package. This\n * object maps the old package name to the new package name.\n */\nexport const consolidatedPackages = {\n  '@storybook/channels': 'storybook/internal/channels',\n  '@storybook/client-logger': 'storybook/internal/client-logger',\n  '@storybook/core-common': 'storybook/internal/common',\n  '@storybook/core-events': 'storybook/internal/core-events',\n  '@storybook/csf': 'storybook/internal/csf',\n  '@storybook/csf-tools': 'storybook/internal/csf-tools',\n  '@storybook/docs-tools': 'storybook/internal/docs-tools',\n  '@storybook/node-logger': 'storybook/internal/node-logger',\n  '@storybook/preview-api': 'storybook/preview-api',\n  '@storybook/router': 'storybook/internal/router',\n  '@storybook/telemetry': 'storybook/internal/telemetry',\n  '@storybook/theming': 'storybook/theming',\n  '@storybook/types': 'storybook/internal/types',\n  '@storybook/manager-api': 'storybook/manager-api',\n  '@storybook/manager': 'storybook/internal/manager',\n  '@storybook/preview': 'storybook/internal/preview',\n  '@storybook/core-server': 'storybook/internal/core-server',\n  '@storybook/builder-manager': 'storybook/internal/builder-manager',\n  '@storybook/components': 'storybook/internal/components',\n  '@storybook/test': 'storybook/test',\n  '@storybook/experimental-nextjs-vite': '@storybook/nextjs-vite',\n  '@storybook/instrumenter': 'storybook/internal/instrumenter',\n  '@storybook/blocks': '@storybook/addon-docs/blocks',\n} as const;\n\nexport type ConsolidatedPackage = keyof typeof consolidatedPackages;\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/helpers/logMigrationSummary.ts",
    "content": "import { CLI_COLORS, logger } from 'storybook/internal/node-logger';\n\nimport picocolors from 'picocolors';\nimport { dedent } from 'ts-dedent';\n\nimport type { FixSummary } from '../types.ts';\nimport { FixStatus } from '../types.ts';\n\nexport const messageDivider = '\\n\\n';\nconst segmentDivider = '\\n\\n─────────────────────────────────────────────────\\n\\n';\n\nfunction getGlossaryMessages(fixSummary: FixSummary, fixResults: Record<string, FixStatus>) {\n  const messages = [];\n  if (fixSummary.succeeded.length > 0) {\n    messages.push(picocolors.bold('Successful migrations:'));\n    messages.push(fixSummary.succeeded.map((m) => picocolors.green(m)).join(', '));\n  }\n\n  if (Object.keys(fixSummary.failed).length > 0) {\n    messages.push(picocolors.bold('Failed migrations:'));\n    messages.push(\n      Object.entries(fixSummary.failed)\n        .map(([id, error]) => {\n          return `${picocolors.bold(picocolors.red(id))}:\\n${error}`;\n        })\n        .join('\\n')\n    );\n  }\n\n  if (fixSummary.manual.length > 0) {\n    messages.push(picocolors.bold('Manual migrations:'));\n    messages.push(\n      fixSummary.manual\n        .map((m) =>\n          fixResults[m] === FixStatus.MANUAL_SUCCEEDED ? picocolors.green(m) : picocolors.blue(m)\n        )\n        .join(', ')\n    );\n  }\n\n  if (fixSummary.skipped.length > 0) {\n    messages.push(picocolors.bold('Skipped migrations:'));\n    messages.push(fixSummary.skipped.map((m) => picocolors.cyan(m)).join(', '));\n  }\n\n  return messages;\n}\n\nexport function logMigrationSummary({\n  fixResults,\n  fixSummary,\n}: {\n  fixResults: Record<string, FixStatus>;\n  fixSummary: FixSummary;\n}) {\n  const messages = [];\n  messages.push(getGlossaryMessages(fixSummary, fixResults).join(messageDivider));\n\n  messages.push(dedent`If you'd like to run the migrations again, you can do so by running \n    ${picocolors.cyan('npx storybook automigrate')}\n    \n    The automigrations try to migrate common patterns in your project, but might not contain everything needed to migrate to the latest version of Storybook.\n    \n    Please check the changelog and migration guide for manual migrations and more information: \n    https://storybook.js.org/docs/releases/migration-guide?ref=upgrade\n    And reach out on Discord if you need help: https://discord.gg/storybook\n  `);\n\n  const hasNoFixes = Object.values(fixResults).every((r) => r === FixStatus.UNNECESSARY);\n  const hasFailures = Object.values(fixResults).some(\n    (r) => r === FixStatus.FAILED || r === FixStatus.CHECK_FAILED\n  );\n\n  if (hasNoFixes) {\n    logger.warn('No migrations were applicable to your project');\n  } else if (hasFailures) {\n    logger.error('Migration check ran with failures');\n  } else {\n    logger.step(CLI_COLORS.success('Migration check ran successfully'));\n  }\n\n  logger.log(messages.filter(Boolean).join(segmentDivider));\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport {\n  getBuilderPackageName,\n  getFrameworkPackageName,\n  getRendererName,\n} from './mainConfigFile.ts';\n\ndescribe('getBuilderPackageName', () => {\n  it('should return null when mainConfig is undefined or null', () => {\n    const packageName = getBuilderPackageName(undefined);\n    expect(packageName).toBeNull();\n\n    // @ts-expect-error (Argument of type 'null' is not assignable)\n    const packageName2 = getBuilderPackageName(null);\n    expect(packageName2).toBeNull();\n  });\n\n  it('should return null when builder package name or path is not found', () => {\n    const mainConfig = {};\n\n    const packageName = getBuilderPackageName(mainConfig as any);\n    expect(packageName).toBeNull();\n  });\n\n  it('should return builder package name when core.builder is a string', () => {\n    const builderPackage = '@storybook/builder-webpack5';\n    const mainConfig = {\n      core: {\n        builder: builderPackage,\n      },\n    };\n\n    const packageName = getBuilderPackageName(mainConfig as any);\n    expect(packageName).toBe(builderPackage);\n  });\n\n  it('should return builder package name when core.builder.name contains valid builder package name', () => {\n    const builderPackage = '@storybook/builder-webpack5';\n    const packageNameOrPath = `/path/to/${builderPackage}`;\n    const mainConfig = {\n      core: {\n        builder: { name: packageNameOrPath },\n      },\n    };\n\n    const packageName = getBuilderPackageName(mainConfig as any);\n    expect(packageName).toBe(builderPackage);\n  });\n\n  it('should return builder package name when core.builder.name contains windows backslash paths', () => {\n    const builderPackage = '@storybook/builder-webpack5';\n    const packageNameOrPath = 'c:\\\\path\\\\to\\\\@storybook\\\\builder-webpack5';\n    const mainConfig = {\n      core: {\n        builder: { name: packageNameOrPath },\n      },\n    };\n\n    const packageName = getBuilderPackageName(mainConfig as any);\n    expect(packageName).toBe(builderPackage);\n  });\n\n  it(`should return package name or path when core.builder doesn't contain the name of a valid builder package`, () => {\n    const packageNameOrPath = '@my-org/storybook-builder';\n    const mainConfig = {\n      core: {\n        builder: packageNameOrPath,\n      },\n    };\n\n    const packageName = getBuilderPackageName(mainConfig as any);\n    expect(packageName).toBe(packageNameOrPath);\n  });\n});\n\ndescribe('getFrameworkPackageName', () => {\n  it('should return null when mainConfig is undefined or null', () => {\n    const packageName = getFrameworkPackageName(undefined);\n    expect(packageName).toBeNull();\n\n    // @ts-expect-error (Argument of type 'null' is not assignable)\n    const packageName2 = getFrameworkPackageName(null);\n    expect(packageName2).toBeNull();\n  });\n\n  it('should return null when framework package name or path is not found', () => {\n    const mainConfig = {};\n\n    const packageName = getFrameworkPackageName(mainConfig as any);\n    expect(packageName).toBeNull();\n  });\n\n  it('should return framework package name when framework is a string', () => {\n    const frameworkPackage = '@storybook/react';\n    const mainConfig = {\n      framework: frameworkPackage,\n    };\n\n    const packageName = getFrameworkPackageName(mainConfig as any);\n    expect(packageName).toBe(frameworkPackage);\n  });\n\n  it('should return framework package name when framework.name contains valid framework package name', () => {\n    const frameworkPackage = '@storybook/react-vite';\n    const packageNameOrPath = `/path/to/${frameworkPackage}`;\n    const mainConfig = {\n      framework: { name: packageNameOrPath },\n    };\n\n    const packageName = getFrameworkPackageName(mainConfig as any);\n    expect(packageName).toBe(frameworkPackage);\n  });\n\n  it('should return builder package name when framework.name contains windows backslash paths', () => {\n    const builderPackage = '@storybook/react-vite';\n    const packageNameOrPath = 'c:\\\\path\\\\to\\\\@storybook\\\\react-vite';\n    const mainConfig = {\n      framework: { name: packageNameOrPath },\n    };\n\n    const packageName = getFrameworkPackageName(mainConfig as any);\n    expect(packageName).toBe(builderPackage);\n  });\n\n  it(`should return package name or path when framework does not contain the name of a valid framework package`, () => {\n    const packageNameOrPath = '@my-org/storybook-framework';\n    const mainConfig = {\n      framework: packageNameOrPath,\n    };\n\n    const packageName = getFrameworkPackageName(mainConfig as any);\n    expect(packageName).toBe(packageNameOrPath);\n  });\n});\n\ndescribe('getRendererName', () => {\n  it('should return null when mainConfig is undefined', () => {\n    const rendererName = getRendererName(undefined);\n    expect(rendererName).toBeNull();\n  });\n\n  it('should return null when framework package name or path is not found', () => {\n    const mainConfig = {};\n\n    const rendererName = getRendererName(mainConfig as any);\n    expect(rendererName).toBeNull();\n  });\n\n  it('should return renderer name when framework is a string', () => {\n    const frameworkPackage = '@storybook/react-webpack5';\n    const mainConfig = {\n      framework: frameworkPackage,\n    };\n\n    const rendererName = getRendererName(mainConfig as any);\n    expect(rendererName).toBe('react');\n  });\n\n  it('should return renderer name when framework.name contains valid framework package name', () => {\n    const frameworkPackage = '@storybook/react-vite';\n    const packageNameOrPath = `/path/to/${frameworkPackage}`;\n    const mainConfig = {\n      framework: { name: packageNameOrPath },\n    };\n\n    const rendererName = getRendererName(mainConfig as any);\n    expect(rendererName).toBe('react');\n  });\n\n  it('should return renderer name when framework.name contains windows backslash paths', () => {\n    const packageNameOrPath = 'c:\\\\path\\\\to\\\\@storybook\\\\sveltekit';\n    const mainConfig = {\n      framework: { name: packageNameOrPath },\n    };\n\n    const rendererName = getRendererName(mainConfig as any);\n    expect(rendererName).toBe('svelte');\n  });\n\n  it(`should return undefined when framework does not contain the name of a valid framework package`, () => {\n    const packageNameOrPath = '@my-org/storybook-framework';\n    const mainConfig = {\n      framework: packageNameOrPath,\n    };\n\n    const rendererName = getRendererName(mainConfig as any);\n    expect(rendererName).toBeUndefined();\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts",
    "content": "import { dirname, isAbsolute, join, normalize } from 'node:path';\n\nimport {\n  JsPackageManagerFactory,\n  builderPackages,\n  extractFrameworkPackageName,\n  frameworkPackages,\n  getStorybookInfo,\n} from 'storybook/internal/common';\nimport type { PackageManagerName } from 'storybook/internal/common';\nimport { frameworkToRenderer } from 'storybook/internal/common';\nimport type { ConfigFile } from 'storybook/internal/csf-tools';\nimport {\n  isCsfFactoryPreview,\n  readConfig,\n  writeConfig as writeConfigFile,\n} from 'storybook/internal/csf-tools';\nimport { logger } from 'storybook/internal/node-logger';\nimport type { StorybookConfigRaw } from 'storybook/internal/types';\n\nimport picocolors from 'picocolors';\n\nimport { getStoriesPathsFromConfig } from '../../util.ts';\n\n/**\n * Given a Storybook configuration object, retrieves the package name or file path of the framework.\n *\n * @param mainConfig - The main Storybook configuration object to lookup.\n * @returns - The package name of the framework. If not found, returns null.\n */\nexport const getFrameworkPackageName = (mainConfig?: StorybookConfigRaw) => {\n  const packageNameOrPath =\n    typeof mainConfig?.framework === 'string' ? mainConfig.framework : mainConfig?.framework?.name;\n\n  if (!packageNameOrPath) {\n    return null;\n  }\n\n  return extractFrameworkPackageName(packageNameOrPath);\n};\n\n/**\n * Given a Storybook configuration object, retrieves the inferred renderer name from the framework.\n *\n * @param mainConfig - The main Storybook configuration object to lookup.\n * @returns - The renderer name. If not found, returns null.\n */\nexport const getRendererName = (mainConfig?: StorybookConfigRaw) => {\n  const frameworkPackageName = getFrameworkPackageName(mainConfig);\n\n  if (!frameworkPackageName) {\n    return null;\n  }\n\n  const frameworkName = frameworkPackages[frameworkPackageName];\n\n  return frameworkToRenderer[frameworkName as keyof typeof frameworkToRenderer];\n};\n\n/**\n * Given a Storybook configuration object, retrieves the package name or file path of the builder.\n *\n * @param mainConfig - The main Storybook configuration object to lookup.\n * @returns - The package name of the builder. If not found, returns null.\n */\nexport const getBuilderPackageName = (mainConfig?: StorybookConfigRaw) => {\n  const frameworkOptions = getFrameworkOptions(mainConfig);\n\n  const frameworkBuilder = frameworkOptions?.builder;\n\n  const frameworkBuilderName =\n    typeof frameworkBuilder === 'string' ? frameworkBuilder : frameworkBuilder?.options?.name;\n\n  const coreBuilderName =\n    typeof mainConfig?.core?.builder === 'string'\n      ? mainConfig.core.builder\n      : mainConfig?.core?.builder?.name;\n\n  const packageNameOrPath = coreBuilderName ?? frameworkBuilderName;\n\n  if (!packageNameOrPath) {\n    return null;\n  }\n\n  const normalizedPath = normalize(packageNameOrPath).replace(new RegExp(/\\\\/, 'g'), '/');\n\n  return (\n    Object.keys(builderPackages).find((pkg) => normalizedPath.endsWith(pkg)) || packageNameOrPath\n  );\n};\n\n/**\n * Given a Storybook configuration object, retrieves the configuration for the framework.\n *\n * @param mainConfig - The main Storybook configuration object to lookup.\n * @returns - The configuration for the framework. If not found, returns null.\n */\nexport const getFrameworkOptions = (\n  mainConfig?: StorybookConfigRaw\n): Record<string, any> | null => {\n  return typeof mainConfig?.framework === 'string'\n    ? null\n    : (mainConfig?.framework?.options ?? null);\n};\n\nexport const getStorybookData = async ({\n  configDir: userDefinedConfigDir,\n  packageManagerName,\n}: {\n  configDir?: string;\n  packageManagerName?: PackageManagerName;\n  cache?: boolean;\n}) => {\n  logger.debug('Getting Storybook info...');\n  const {\n    mainConfig,\n    mainConfigPath: mainConfigPath,\n    configDir: configDirFromScript,\n    previewConfigPath,\n    versionSpecifier,\n  } = await getStorybookInfo(\n    userDefinedConfigDir,\n    userDefinedConfigDir ? dirname(userDefinedConfigDir) : undefined\n  );\n\n  const configDir = userDefinedConfigDir || configDirFromScript || '.storybook';\n\n  logger.debug('Loading main config...');\n\n  const workingDir = isAbsolute(configDir)\n    ? dirname(configDir)\n    : dirname(join(process.cwd(), configDir));\n\n  logger.debug('Getting stories paths...');\n  const storiesPaths = await getStoriesPathsFromConfig({\n    stories: mainConfig.stories,\n    configDir,\n    workingDir,\n  });\n\n  logger.debug('Getting package manager...');\n  const packageManager = JsPackageManagerFactory.getPackageManager({\n    force: packageManagerName,\n    configDir,\n    storiesPaths,\n  });\n\n  logger.debug('Getting Storybook version...');\n  const versionInstalled = (await packageManager.getModulePackageJSON('storybook'))?.version;\n\n  logger.debug('Detecting CSF factory usage...');\n  const hasCsfFactoryPreview = previewConfigPath\n    ? isCsfFactoryPreview(await readConfig(previewConfigPath))\n    : false;\n\n  return {\n    configDir,\n    mainConfig,\n    /** The version specifier of Storybook from the user's package.json */\n    versionSpecifier,\n    /** The version of Storybook installed in the user's project */\n    versionInstalled,\n    mainConfigPath,\n    previewConfigPath,\n    packageManager,\n    storiesPaths,\n    hasCsfFactoryPreview,\n  };\n};\nexport type GetStorybookData = typeof getStorybookData;\n\n/**\n * A helper function to safely read and write the main config file. At the end of the callback,\n * main.js will be overwritten. If it fails, it will handle the error and log a message to the user\n * explaining what to do.\n *\n * It receives a mainConfigPath and a callback which will have access to utilities to manipulate\n * main.js.\n *\n * @example\n *\n * ```ts\n * await safeWriteMain({ mainConfigPath, dryRun }, async ({ main }) => {\n *   // manipulate main.js here\n * });\n * ```\n */\nexport const updateMainConfig = async (\n  { mainConfigPath, dryRun }: { mainConfigPath: string; dryRun: boolean },\n  callback: (main: ConfigFile) => Promise<void> | void\n) => {\n  try {\n    const main = await readConfig(mainConfigPath);\n    await callback(main);\n    if (!dryRun) {\n      await writeConfigFile(main);\n    }\n  } catch (e) {\n    logger.log(\n      `❌ The migration failed to update your ${picocolors.blue(\n        mainConfigPath\n      )} on your behalf because of the following error:\n        ${e}\\n`\n    );\n    logger.log(\n      `⚠️ Storybook automigrations are based on AST parsing and it's possible that your ${picocolors.blue(\n        mainConfigPath\n      )} file contains a non-standard format (e.g. your export is not an object) or that there was an error when parsing dynamic values (e.g. \"require\" calls, or usage of environment variables). When your main config is non-standard, automigrations are unfortunately not possible. Please follow the instructions given previously and follow the documentation to make the updates manually.`\n    );\n  }\n};\n\n/** Check if a file is in ESM format based on its content */\nexport function containsESMUsage(content: string): boolean {\n  // For .js/.ts files, check the content for ESM syntax\n  // Check for ESM syntax indicators (multiline aware)\n  const hasImportStatement =\n    /^\\s*import\\s+/m.test(content) ||\n    /^\\s*import\\s*{/m.test(content) ||\n    /^\\s*import\\s*\\(/m.test(content);\n  const hasExportStatement =\n    /^\\s*export\\s+/m.test(content) ||\n    /^\\s*export\\s*{/m.test(content) ||\n    /^\\s*export\\s*default/m.test(content);\n  const hasImportMeta = /import\\.meta/.test(content);\n\n  // If any ESM syntax is found, it's likely an ESM file\n  return hasImportStatement || hasExportStatement || hasImportMeta;\n}\n\n/** Check if the file content contains require usage */\nexport function containsRequireUsage(content: string): boolean {\n  // Check for require() calls\n  const requireCallRegex = /\\brequire\\(/;\n  const requireDotRegex = /\\brequire\\./;\n  return requireCallRegex.test(content) || requireDotRegex.test(content);\n}\n\n/** Check if the file content contains a pattern matching the given regex */\nexport function containsPatternUsage(content: string, pattern: RegExp): boolean {\n  // Remove strings first, then comments\n  const stripStrings = (s: string) => s.replace(/(['\"`])(?:\\\\.|(?!\\1)[\\s\\S])*?\\1/g, '\"\"');\n  const withoutStrings = stripStrings(content);\n  const withoutBlock = withoutStrings.replace(/\\/\\*[\\s\\S]*?\\*\\//g, '');\n  const cleanContent = withoutBlock\n    .split('\\n')\n    .map((line) => line.split('//')[0])\n    .join('\\n');\n\n  // Check for pattern usage in the cleaned content\n  return pattern.test(cleanContent);\n}\n\n/** Check if the file content contains __dirname usage */\nexport function containsDirnameUsage(content: string): boolean {\n  return containsPatternUsage(content, /\\b__dirname\\b/);\n}\n\nexport function containsFilenameUsage(content: string): boolean {\n  return containsPatternUsage(content, /\\b__filename\\b/);\n}\n\n/** Check if __dirname is already defined in the file */\nexport function hasDirnameDefined(content: string): boolean {\n  // Check if __dirname is already defined as a const/let/var\n  const dirnameDefinedRegex = /(?:const|let|var)\\s+__dirname\\s*=/;\n  return dirnameDefinedRegex.test(content);\n}\n\n/** Check if a specific import already exists in the file */\n\n/** Configuration for what should be included in the compatibility banner */\nexport interface BannerConfig {\n  hasRequireUsage: boolean;\n  hasUnderscoreDirname: boolean;\n  hasUnderscoreFilename: boolean;\n}\n\nexport const bannerComment =\n  '// This file has been automatically migrated to valid ESM format by Storybook.';\n\nexport const hasRequireBanner = (content: string): boolean => {\n  return content.includes(bannerComment);\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/helpers/testing-helpers.ts",
    "content": "import { vi } from 'vitest';\n\nimport type {\n  JsPackageManager,\n  PackageJson,\n  PackageJsonWithDepsAndDevDeps,\n} from 'storybook/internal/common';\n\nvi.mock('./mainConfigFile', async (importOriginal) => ({\n  ...(await importOriginal<typeof import('./mainConfigFile')>()),\n  getStorybookData: vi.fn(),\n}));\n\nvi.mock('storybook/internal/common', async (importOriginal) => ({\n  ...(await importOriginal<typeof import('storybook/internal/common')>()),\n  loadMainConfig: vi.fn(),\n}));\n\nexport const makePackageManager = (packageJson: PackageJson) => {\n  const { dependencies = {}, devDependencies = {}, peerDependencies = {} } = packageJson;\n  return {\n    primaryPackageJson: {\n      packageJson: {\n        dependencies: {},\n        devDependencies: {},\n        ...packageJson,\n      } as PackageJsonWithDepsAndDevDeps,\n      packageJsonPath: '/some/path',\n      operationDir: '/some/path',\n    },\n    getAllDependencies: () => ({\n      ...dependencies,\n      ...devDependencies,\n      ...peerDependencies,\n    }),\n  } as JsPackageManager;\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/index.test.ts",
    "content": "import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { JsPackageManager, PackageJson } from 'storybook/internal/common';\nimport { prompt } from 'storybook/internal/node-logger';\n\nimport * as mainConfigFile from './helpers/mainConfigFile.ts';\nimport { doAutomigrate, runFixes } from './index.ts';\nimport type { Fix } from './types.ts';\n\nconst check1 = vi.fn();\nconst run1 = vi.fn();\nconst getModulePackageJSON = vi.fn();\nconst getStorybookData = vi.fn();\nconst prompt1Message = 'prompt1Message';\n\nvi.spyOn(console, 'error').mockImplementation(console.log);\nvi.spyOn(mainConfigFile, 'getStorybookData').mockImplementation(getStorybookData);\n\nvi.mock('storybook/internal/node-logger', () => ({\n  logger: {\n    logBox: vi.fn(),\n    log: vi.fn(),\n    warn: vi.fn(),\n    error: vi.fn(),\n    info: vi.fn(),\n    debug: vi.fn(),\n    step: vi.fn(),\n  },\n  prompt: {\n    confirm: vi.fn(),\n    taskLog: vi.fn(() => ({\n      success: vi.fn(),\n      error: vi.fn(),\n      message: vi.fn(),\n    })),\n  },\n  logTracker: {\n    enableLogWriting: vi.fn(),\n  },\n  CLI_COLORS: {\n    success: vi.fn((text: string) => text),\n    error: vi.fn((text: string) => text),\n    warning: vi.fn((text: string) => text),\n    info: vi.fn((text: string) => text),\n    debug: vi.fn((text: string) => text),\n    cta: vi.fn((text: string) => text),\n    dimmed: vi.fn((text: string) => text),\n  },\n}));\n\nconst fixes: Fix[] = [\n  {\n    id: 'fix-1',\n\n    async check(config) {\n      return check1(config);\n    },\n\n    prompt() {\n      return prompt1Message;\n    },\n\n    async run(result) {\n      run1(result);\n    },\n  },\n];\n\nconst coreCommonMock = vi.hoisted(() => {\n  return {\n    loadMainConfig: vi.fn(),\n  };\n});\n\nvi.mock('storybook/internal/common', async (importOriginal) => ({\n  ...(await importOriginal<typeof import('storybook/internal/common')>()),\n  loadMainConfig: coreCommonMock.loadMainConfig,\n}));\n\n// Remove the old prompt mock - now handled in the node-logger mock\n\nclass PackageManager implements Partial<JsPackageManager> {\n  async getModulePackageJSON(\n    packageName: string,\n    basePath?: string | undefined\n  ): Promise<PackageJson | null> {\n    return getModulePackageJSON(packageName, basePath);\n  }\n}\n\nconst packageManager = new PackageManager() as unknown as JsPackageManager;\n\nconst dryRun = false;\nconst yes = true;\nconst rendererPackage = 'storybook';\nconst skipInstall = false;\nconst configDir = '/path/to/config';\nconst mainConfigPath = '/path/to/mainConfig';\nconst beforeVersion = '6.5.15';\nconst isUpgrade = true;\n\nconst common = {\n  fixes,\n  dryRun,\n  yes,\n  mainConfig: { stories: [] },\n  rendererPackage,\n  skipInstall,\n  configDir,\n  packageManager: packageManager,\n  mainConfigPath,\n  isUpgrade,\n  storiesPaths: [],\n  hasCsfFactoryPreview: false,\n};\n\nconst runFixWrapper = async ({ storybookVersion }: { storybookVersion: string }) => {\n  return runFixes({\n    ...common,\n    storybookVersion,\n  });\n};\n\nconst runAutomigrateWrapper = async ({\n  beforeVersion,\n  storybookVersion,\n}: {\n  beforeVersion: string;\n  storybookVersion: string;\n}) => {\n  getStorybookData.mockResolvedValue({\n    ...common,\n    beforeVersion,\n    versionInstalled: storybookVersion,\n    isLatest: true,\n  });\n  return doAutomigrate({ configDir, fixes });\n};\n\ndescribe('runFixes', () => {\n  beforeEach(() => {\n    getModulePackageJSON.mockImplementation(() => {\n      return {\n        version: beforeVersion,\n      };\n    });\n    check1.mockResolvedValue({ some: 'result' });\n    vi.mocked(prompt.confirm).mockResolvedValue(true);\n  });\n\n  afterEach(() => {\n    vi.clearAllMocks();\n  });\n\n  it('should be necessary to run fix-1 from SB 6.5.15 to 7.0.0', async () => {\n    const { fixResults } = await runFixWrapper({ storybookVersion: '7.0.0' });\n\n    expect(fixResults).toEqual({\n      'fix-1': 'succeeded',\n    });\n    expect(run1).toHaveBeenCalledWith(\n      expect.objectContaining({\n        dryRun,\n        mainConfigPath,\n        packageManager,\n        result: {\n          some: 'result',\n        },\n        skipInstall,\n      })\n    );\n  });\n\n  it('should fail if an error is thrown by migration', async () => {\n    check1.mockRejectedValue(new Error('check1 error'));\n\n    const { fixResults } = await runFixWrapper({ storybookVersion: '7.0.0' });\n\n    expect(fixResults).toEqual({\n      'fix-1': 'check_failed',\n    });\n    expect(run1).not.toHaveBeenCalled();\n  });\n\n  it('should throw error if an error is thrown by migration', async () => {\n    check1.mockRejectedValue(new Error('check1 error'));\n\n    const result = runAutomigrateWrapper({ beforeVersion, storybookVersion: '7.0.0' });\n\n    await expect(result).rejects.toThrow(\n      'An error occurred while running the automigrate command.'\n    );\n    expect(run1).not.toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/index.ts",
    "content": "import { type JsPackageManager } from 'storybook/internal/common';\nimport { versions } from 'storybook/internal/common';\nimport { logTracker, logger, prompt } from 'storybook/internal/node-logger';\nimport { AutomigrateError } from 'storybook/internal/server-errors';\nimport type { StorybookConfigRaw } from 'storybook/internal/types';\n\nimport picocolors from 'picocolors';\nimport invariant from 'tiny-invariant';\nimport { dedent } from 'ts-dedent';\n\nimport { doctor } from '../doctor/index.ts';\nimport type {\n  AutofixOptions,\n  AutofixOptionsFromCLI,\n  Fix,\n  FixId,\n  FixSummary,\n  PreCheckFailure,\n  Prompt,\n} from './fixes/index.ts';\nimport { FixStatus, allFixes, commandFixes } from './fixes/index.ts';\nimport { upgradeStorybookRelatedDependencies } from './fixes/upgrade-storybook-related-dependencies.ts';\nimport { logMigrationSummary } from './helpers/logMigrationSummary.ts';\nimport { getStorybookData } from './helpers/mainConfigFile.ts';\n\nconst logAvailableMigrations = () => {\n  const availableFixes = [...allFixes, ...commandFixes]\n    .map((f) => picocolors.yellow(f.id))\n    .map((x) => `- ${x}`)\n    .join('\\n');\n\n  logger.log(dedent`\n    The following migrations are available:\n    ${availableFixes}\n  `);\n};\n\nconst hasFailures = (fixResults: Record<string, FixStatus> | undefined): boolean => {\n  return Object.values(fixResults || {}).some(\n    (r) => r === FixStatus.FAILED || r === FixStatus.CHECK_FAILED\n  );\n};\n\nexport const doAutomigrate = async (options: AutofixOptionsFromCLI) => {\n  logger.debug('Extracting storybook data...');\n  const {\n    mainConfig,\n    mainConfigPath,\n    previewConfigPath,\n    versionInstalled,\n    configDir,\n    packageManager,\n    storiesPaths,\n    hasCsfFactoryPreview,\n  } = await getStorybookData({\n    configDir: options.configDir,\n    packageManagerName: options.packageManager,\n  });\n\n  if (!mainConfigPath) {\n    throw new Error('Could not determine main config path');\n  }\n\n  const outcome = await automigrate({\n    ...options,\n    packageManager,\n    storybookVersion: versionInstalled || versions.storybook,\n    mainConfigPath,\n    mainConfig,\n    previewConfigPath,\n    configDir,\n    isUpgrade: false,\n    isLatest: false,\n    storiesPaths,\n    hasCsfFactoryPreview,\n  });\n\n  // only install dependencies if the outcome contains any fixes that were not failed or skipped\n  const hasAppliedFixes = Object.values(outcome?.fixResults ?? {}).some(\n    (r) => r === FixStatus.SUCCEEDED || r === FixStatus.MANUAL_SUCCEEDED\n  );\n\n  if (hasAppliedFixes && !options.skipInstall) {\n    await packageManager.installDependencies();\n  }\n\n  if (outcome && !options.skipDoctor) {\n    await doctor({ configDir, packageManager: options.packageManager });\n  }\n\n  if (hasFailures(outcome?.fixResults)) {\n    const failedMigrations = Object.entries(outcome?.fixResults ?? {})\n      .filter(([, status]) => status === FixStatus.FAILED || status === FixStatus.CHECK_FAILED)\n      .map(([id, status]) => {\n        const statusLabel = status === FixStatus.CHECK_FAILED ? 'check failed' : 'failed';\n        return `${picocolors.cyan(id)} (${statusLabel})`;\n      });\n\n    throw new AutomigrateError({ errors: failedMigrations });\n  }\n};\n\nexport const automigrate = async ({\n  fixId,\n  fixes: inputFixes,\n  dryRun,\n  yes,\n  packageManager,\n  list,\n  configDir,\n  mainConfig,\n  mainConfigPath,\n  previewConfigPath,\n  storybookVersion,\n  renderer: rendererPackage,\n  skipInstall,\n  hideMigrationSummary = false,\n  isUpgrade,\n  isLatest,\n  storiesPaths,\n  hasCsfFactoryPreview,\n  glob,\n}: AutofixOptions): Promise<{\n  fixResults: Record<string, FixStatus>;\n  preCheckFailure?: PreCheckFailure;\n} | null> => {\n  if (list) {\n    logAvailableMigrations();\n    return null;\n  }\n\n  // if an on-command migration is triggered, run it and bail\n  const commandFix = commandFixes.find((f) => f.id === fixId);\n  if (commandFix) {\n    logger.step(`Running migration ${picocolors.magenta(fixId)}..`);\n\n    await commandFix.run({\n      mainConfigPath,\n      previewConfigPath,\n      packageManager,\n      configDir,\n      dryRun,\n      mainConfig,\n      result: null,\n      storybookVersion,\n      storiesPaths,\n      yes,\n      glob,\n    });\n\n    return null;\n  }\n\n  const selectedFixes: Fix[] =\n    inputFixes ||\n    allFixes.filter((fix) => {\n      // we only allow this automigration when the user explicitly asks for it, or they are upgrading to the latest version of storybook\n      if (\n        fix.id === upgradeStorybookRelatedDependencies.id &&\n        isLatest === false &&\n        fixId !== upgradeStorybookRelatedDependencies.id\n      ) {\n        return false;\n      }\n\n      return true;\n    });\n  const fixes: Fix[] = fixId ? selectedFixes.filter((f) => f.id === fixId) : selectedFixes;\n\n  if (fixId && fixes.length === 0) {\n    logger.log(`📭 No migrations found for ${picocolors.magenta(fixId)}.`);\n    logAvailableMigrations();\n    return null;\n  }\n\n  logger.step('Checking possible migrations..');\n\n  const { fixResults, fixSummary, preCheckFailure } = await runFixes({\n    fixes,\n    packageManager,\n    rendererPackage,\n    skipInstall,\n    configDir,\n    previewConfigPath,\n    mainConfig,\n    mainConfigPath,\n    storybookVersion,\n    isUpgrade: !!isUpgrade,\n    dryRun,\n    yes,\n    storiesPaths,\n    hasCsfFactoryPreview,\n  });\n\n  // if migration failed, display a log file in the users cwd\n  if (hasFailures(fixResults)) {\n    logTracker.enableLogWriting();\n  }\n\n  if (!hideMigrationSummary) {\n    logMigrationSummary({\n      fixResults,\n      fixSummary,\n    });\n  }\n\n  return { fixResults, preCheckFailure };\n};\n\ntype RunFixesOptions = {\n  fixes: Fix[];\n  yes?: boolean;\n  storiesPaths: string[];\n  dryRun?: boolean;\n  rendererPackage?: string;\n  skipInstall?: boolean;\n  configDir: string;\n  packageManager: JsPackageManager;\n  mainConfigPath: string;\n  previewConfigPath?: string;\n  mainConfig: StorybookConfigRaw;\n  storybookVersion: string;\n  isUpgrade?: boolean;\n  hasCsfFactoryPreview: boolean;\n};\n\nexport async function runFixes({\n  fixes,\n  dryRun,\n  yes,\n  rendererPackage,\n  skipInstall,\n  configDir,\n  packageManager,\n  mainConfig,\n  mainConfigPath,\n  previewConfigPath,\n  storybookVersion,\n  storiesPaths,\n  hasCsfFactoryPreview,\n}: RunFixesOptions): Promise<{\n  preCheckFailure?: PreCheckFailure;\n  fixResults: Record<FixId, FixStatus>;\n  fixSummary: FixSummary;\n}> {\n  const fixResults = {} as Record<FixId, FixStatus>;\n  const fixSummary: FixSummary = { succeeded: [], failed: {}, manual: [], skipped: [] };\n\n  for (let i = 0; i < fixes.length; i += 1) {\n    const f = fixes[i] as Fix;\n    let result;\n\n    try {\n      logger.debug(`Running ${picocolors.cyan(f.id)} migration checks`);\n      result = await f.check({\n        packageManager,\n        configDir,\n        rendererPackage,\n        mainConfig,\n        storybookVersion,\n        previewConfigPath,\n        mainConfigPath,\n        storiesPaths,\n        hasCsfFactoryPreview,\n      });\n      logger.debug(`End of ${picocolors.cyan(f.id)} migration checks`);\n    } catch (error) {\n      logger.warn(`⚠️  failed to check fix ${picocolors.bold(f.id)}`);\n      if (error instanceof Error) {\n        logger.error(`\\n${error.stack}`);\n        fixSummary.failed[f.id] = error.message;\n      }\n      fixResults[f.id] = FixStatus.CHECK_FAILED;\n    }\n\n    if (result) {\n      const promptType: Prompt =\n        typeof f.promptType === 'function' ? await f.promptType(result) : (f.promptType ?? 'auto');\n\n      logger.log(`🔎 found a '${picocolors.cyan(f.id)}' migration:`);\n\n      const getTitle = () => {\n        switch (promptType) {\n          case 'auto':\n            return 'Automigration detected';\n          case 'manual':\n            return 'Manual migration detected';\n          case 'notification':\n            return 'Migration notification';\n        }\n      };\n\n      const currentTaskLogger = prompt.taskLog({\n        id: `automigrate-task-${f.id}`,\n        title: `${getTitle()}: ${picocolors.cyan(f.id)}`,\n      });\n\n      logger.logBox(f.prompt());\n\n      let runAnswer: { fix: boolean } | undefined;\n\n      try {\n        if (dryRun) {\n          runAnswer = { fix: false };\n        } else if (yes) {\n          runAnswer = { fix: true };\n          if (promptType === 'manual') {\n            fixResults[f.id] = FixStatus.MANUAL_SUCCEEDED;\n            fixSummary.manual.push(f.id);\n          }\n        } else if (promptType === 'manual') {\n          fixResults[f.id] = FixStatus.MANUAL_SUCCEEDED;\n          fixSummary.manual.push(f.id);\n\n          const shouldContinue = await prompt.confirm(\n            {\n              message:\n                'Select continue once you have made the required changes, or quit to exit the migration process',\n              initialValue: true,\n              active: 'continue',\n              inactive: 'quit',\n            },\n            {\n              onCancel: () => {\n                throw new Error();\n              },\n            }\n          );\n\n          if (!shouldContinue) {\n            fixResults[f.id] = FixStatus.MANUAL_SKIPPED;\n            break;\n          }\n        } else if (promptType === 'auto') {\n          const shouldRun = yes\n            ? true\n            : await prompt.confirm(\n                {\n                  message: `Do you want to run the '${picocolors.cyan(f.id)}' migration on your project?`,\n                  initialValue: f.defaultSelected ?? true,\n                },\n                {\n                  onCancel: () => {\n                    throw new Error();\n                  },\n                }\n              );\n          runAnswer = { fix: shouldRun };\n        } else if (promptType === 'notification') {\n          const shouldContinue = await prompt.confirm(\n            {\n              message: `Do you want to continue?`,\n            },\n            {\n              onCancel: () => {\n                throw new Error();\n              },\n            }\n          );\n          runAnswer = { fix: shouldContinue };\n        }\n      } catch (err) {\n        break;\n      }\n\n      if (promptType === 'auto') {\n        invariant(runAnswer, 'runAnswer must be defined if not promptOnly');\n        if (runAnswer.fix) {\n          try {\n            invariant(typeof f.run === 'function', 'run method should be available in fix.');\n            invariant(mainConfigPath, 'Main config path should be defined to run migration.');\n            await f.run({\n              result,\n              packageManager,\n              dryRun,\n              mainConfigPath,\n              configDir,\n              previewConfigPath,\n              mainConfig,\n              skipInstall,\n              storybookVersion,\n              storiesPaths,\n              yes,\n            });\n            logger.log(`✅ ran ${picocolors.cyan(f.id)} migration`);\n\n            fixResults[f.id] = FixStatus.SUCCEEDED;\n            fixSummary.succeeded.push(f.id);\n            currentTaskLogger.success(`Ran ${picocolors.cyan(f.id)} migration`);\n          } catch (error) {\n            fixResults[f.id] = FixStatus.FAILED;\n            const errorMessage = error instanceof Error ? error.message : 'Failed to run migration';\n            fixSummary.failed[f.id] = errorMessage;\n\n            currentTaskLogger.error(`Error when running ${picocolors.cyan(f.id)} migration`);\n          }\n        } else {\n          fixResults[f.id] = FixStatus.SKIPPED;\n          fixSummary.skipped.push(f.id);\n          currentTaskLogger.success(`Skipped ${picocolors.cyan(f.id)} migration`);\n        }\n      }\n    } else {\n      fixResults[f.id] = fixResults[f.id] || FixStatus.UNNECESSARY;\n    }\n  }\n\n  return { fixResults, fixSummary };\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/multi-project.test.ts",
    "content": "import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport {\n  type ProjectAutomigrationData,\n  collectAutomigrationsAcrossProjects,\n  promptForAutomigrations,\n} from './multi-project.ts';\nimport type { Fix } from './types.ts';\n\nvi.mock('storybook/internal/node-logger', async (importOriginal) => {\n  return {\n    ...(await importOriginal<typeof import('storybook/internal/node-logger')>()),\n    prompt: {\n      multiselect: vi.fn(),\n      error: vi.fn(),\n    },\n    logger: {\n      log: vi.fn(),\n      error: vi.fn(),\n      debug: vi.fn(),\n      SYMBOLS: {\n        success: '✔',\n        error: '✕',\n      },\n    },\n  };\n});\n\nconst taskLogMock = {\n  message: vi.fn(),\n  success: vi.fn(),\n  error: vi.fn(),\n  group: vi.fn().mockReturnValue({\n    message: vi.fn(),\n    success: vi.fn(),\n    error: vi.fn(),\n  }),\n};\n\ndescribe('multi-project automigrations', () => {\n  let consoleErrorSpy: any;\n\n  beforeEach(() => {\n    consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});\n  });\n\n  afterEach(() => {\n    consoleErrorSpy.mockRestore();\n  });\n\n  const createMockFix = (id: string, checkResult: any = {}): Fix => ({\n    id,\n    check: vi.fn().mockResolvedValue(checkResult),\n    prompt: vi.fn().mockReturnValue(`Prompt for ${id}`),\n    promptType: 'auto',\n    run: vi.fn(),\n  });\n\n  const createMockProject = (configDir: string): ProjectAutomigrationData => ({\n    configDir,\n    packageManager: {} as any,\n    mainConfig: {} as any,\n    mainConfigPath: `${configDir}/main.js`,\n    storybookVersion: '8.0.0',\n    beforeVersion: '7.0.0',\n    storiesPaths: [],\n    hasCsfFactoryPreview: false,\n  });\n\n  describe('collectAutomigrationsAcrossProjects', () => {\n    it('should collect automigrations across multiple projects', async () => {\n      const fix1 = createMockFix('fix1', { needsFix: true });\n      const fix2 = createMockFix('fix2', { needsFix: true });\n      const fix3 = createMockFix('fix3', null); // This fix doesn't apply\n\n      const project1 = createMockProject('/project1/.storybook');\n      const project2 = createMockProject('/project2/.storybook');\n\n      const results = await collectAutomigrationsAcrossProjects({\n        fixes: [fix1, fix2, fix3],\n        projects: [project1, project2],\n        taskLog: taskLogMock,\n      });\n\n      expect(results).toHaveLength(3);\n      expect(results[0].fix.id).toBe('fix1');\n      expect(results[0].reports.every((report) => report.status === 'check_succeeded')).toBe(true);\n      expect(results[1].fix.id).toBe('fix2');\n      expect(results[1].reports.every((report) => report.status === 'check_succeeded')).toBe(true);\n      expect(results[2].fix.id).toBe('fix3');\n      expect(results[2].reports.every((report) => report.status === 'not_applicable')).toBe(true);\n    });\n\n    it('should deduplicate automigrations across projects', async () => {\n      const fix1 = createMockFix('fix1', { needsFix: true });\n\n      const project1 = createMockProject('/project1/.storybook');\n      const project2 = createMockProject('/project2/.storybook');\n      const project3 = createMockProject('/project3/.storybook');\n\n      const results = await collectAutomigrationsAcrossProjects({\n        fixes: [fix1],\n        projects: [project1, project2, project3],\n        taskLog: taskLogMock,\n      });\n\n      expect(results).toHaveLength(1);\n      expect(results[0].fix.id).toBe('fix1');\n      expect(results[0].reports).toHaveLength(3);\n    });\n\n    it('should handle check errors gracefully', async () => {\n      const fix1 = createMockFix('fix1', { needsFix: true });\n      const fix2 = createMockFix('fix2', { needsFix: true });\n      fix1.check = vi.fn().mockRejectedValue(new Error('Check failed'));\n\n      const project1 = createMockProject('/project1/.storybook');\n\n      const results = await collectAutomigrationsAcrossProjects({\n        fixes: [fix1, fix2],\n        projects: [project1],\n        taskLog: taskLogMock,\n      });\n\n      expect(results).toHaveLength(2);\n      expect(results[0].fix.id).toBe('fix1');\n      expect(results[0].reports.every((report) => report.status === 'check_failed')).toBe(true);\n    });\n  });\n\n  describe('promptForAutomigrations', () => {\n    it('should call multiselect with required: false', async () => {\n      const { prompt } = await import('storybook/internal/node-logger');\n      const multiselectMock = vi.mocked(prompt.multiselect);\n      multiselectMock.mockResolvedValue(['fix1']);\n\n      const fix1 = createMockFix('fix1', { needsFix: true });\n      const project1 = createMockProject('/project1/.storybook');\n\n      const automigrations = [\n        {\n          fix: fix1,\n          reports: [\n            {\n              result: { needsFix: true },\n              status: 'check_succeeded' as const,\n              project: project1,\n            },\n          ],\n        },\n      ];\n\n      await promptForAutomigrations(automigrations, { dryRun: false, yes: false });\n\n      expect(multiselectMock).toHaveBeenCalledWith(\n        expect.objectContaining({\n          message: 'Select automigrations to run',\n          required: false,\n        })\n      );\n    });\n\n    it('should return empty array when user selects nothing', async () => {\n      const { prompt } = await import('storybook/internal/node-logger');\n      const multiselectMock = vi.mocked(prompt.multiselect);\n      multiselectMock.mockResolvedValue([]);\n\n      const fix1 = createMockFix('fix1', { needsFix: true });\n      const project1 = createMockProject('/project1/.storybook');\n\n      const automigrations = [\n        {\n          fix: fix1,\n          reports: [\n            {\n              result: { needsFix: true },\n              status: 'check_succeeded' as const,\n              project: project1,\n            },\n          ],\n        },\n      ];\n\n      const result = await promptForAutomigrations(automigrations, {\n        dryRun: false,\n        yes: false,\n      });\n\n      expect(result).toEqual([]);\n    });\n\n    it('should return all automigrations when yes option is true', async () => {\n      const { logger } = await import('storybook/internal/node-logger');\n      const logSpy = vi.spyOn(logger, 'log');\n\n      const fix1 = createMockFix('fix1', { needsFix: true });\n      const fix2 = createMockFix('fix2', { needsFix: true });\n      const project1 = createMockProject('/project1/.storybook');\n\n      const automigrations = [\n        {\n          fix: fix1,\n          reports: [\n            {\n              result: { needsFix: true },\n              status: 'check_succeeded' as const,\n              project: project1,\n            },\n          ],\n        },\n        {\n          fix: fix2,\n          reports: [\n            {\n              result: { needsFix: true },\n              status: 'check_succeeded' as const,\n              project: project1,\n            },\n          ],\n        },\n      ];\n\n      const result = await promptForAutomigrations(automigrations, { dryRun: false, yes: true });\n\n      expect(result).toEqual(automigrations);\n      expect(logSpy).toHaveBeenCalledWith('Running all detected automigrations:');\n    });\n\n    it('should return empty array when dryRun is true', async () => {\n      const { logger } = await import('storybook/internal/node-logger');\n      const logSpy = vi.spyOn(logger, 'log');\n\n      const fix1 = createMockFix('fix1', { needsFix: true });\n      const project1 = createMockProject('/project1/.storybook');\n\n      const automigrations = [\n        {\n          fix: fix1,\n          reports: [\n            {\n              result: { needsFix: true },\n              status: 'check_succeeded' as const,\n              project: project1,\n            },\n          ],\n        },\n      ];\n\n      const result = await promptForAutomigrations(automigrations, { dryRun: true, yes: false });\n\n      expect(result).toEqual([]);\n      expect(logSpy).toHaveBeenCalledWith(\n        'Detected automigrations (dry run - no changes will be made):'\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/multi-project.ts",
    "content": "import type { JsPackageManager } from 'storybook/internal/common';\nimport { CLI_COLORS, type TaskLogInstance, logger, prompt } from 'storybook/internal/node-logger';\nimport { ErrorCollector, sanitizeError } from 'storybook/internal/telemetry';\nimport type { StorybookConfigRaw } from 'storybook/internal/types';\n\nimport type { UpgradeOptions } from '../upgrade.ts';\nimport { shortenPath } from '../util.ts';\nimport type { CollectProjectsSuccessResult } from '../util.ts';\nimport { allFixes } from './fixes/index.ts';\nimport { rnstorybookConfig } from './fixes/rnstorybook-config.ts';\nimport type { CheckOptions, Fix, FixId, RunOptions } from './types.ts';\nimport { FixStatus } from './types.ts';\n\nexport interface ProjectAutomigrationData {\n  configDir: string;\n  packageManager: JsPackageManager;\n  mainConfig: StorybookConfigRaw;\n  mainConfigPath: string;\n  previewConfigPath?: string;\n  storybookVersion: string;\n  beforeVersion: string;\n  storiesPaths: string[];\n  hasCsfFactoryPreview: boolean;\n}\n\nexport interface AutomigrationCheckResultReport {\n  result: any;\n  status: 'check_succeeded' | 'check_failed' | 'not_applicable';\n  project: ProjectAutomigrationData;\n}\n\nexport interface AutomigrationCheckResult<T = any> {\n  fix: Fix<T>;\n  reports: AutomigrationCheckResultReport[];\n}\n\nexport interface MultiProjectAutomigrationOptions {\n  fixes: Fix[];\n  projects: ProjectAutomigrationData[];\n  dryRun?: boolean;\n  yes?: boolean;\n  skipInstall?: boolean;\n  taskLog: TaskLogInstance;\n}\n\nexport interface MultiProjectRunAutomigrationOptions {\n  automigrations: AutomigrationCheckResult[];\n  dryRun?: boolean;\n  yes?: boolean;\n  skipInstall?: boolean;\n}\n\n/** Collects all applicable automigrations across multiple projects */\nexport async function collectAutomigrationsAcrossProjects(\n  options: MultiProjectAutomigrationOptions\n): Promise<AutomigrationCheckResult[]> {\n  const { fixes, projects, taskLog } = options;\n  const automigrationMap = new Map<FixId, AutomigrationCheckResult>();\n\n  logger.debug(\n    `Starting automigration collection across ${projects.length} projects and ${fixes.length} fixes...`\n  );\n\n  /** Utility to collect results and account for existing entries in the map. */\n  function collectResult(\n    fix: Fix,\n    project: ProjectAutomigrationData,\n    status: 'check_succeeded' | 'check_failed' | 'not_applicable',\n    result?: any\n  ) {\n    const existing = automigrationMap.get(fix.id);\n    if (existing) {\n      // Add project to existing automigration\n      existing.reports.push({\n        project,\n        result,\n        status,\n      });\n    } else {\n      // Create new automigration entry\n      automigrationMap.set(fix.id, {\n        fix,\n        reports: [\n          {\n            result,\n            status,\n            project,\n          },\n        ],\n      });\n    }\n  }\n\n  // Run check for each fix on each project\n  for (const project of projects) {\n    const projectName = shortenPath(project.configDir);\n\n    taskLog.message(`Checking automigrations for ${projectName}...`);\n    logger.debug(`Processing project: ${projectName}`);\n\n    for (const fix of fixes) {\n      try {\n        logger.debug(`Checking fix ${fix.id} for project ${projectName}...`);\n\n        const checkOptions: CheckOptions = {\n          packageManager: project.packageManager,\n          configDir: project.configDir,\n          mainConfig: project.mainConfig,\n          storybookVersion: project.storybookVersion,\n          previewConfigPath: project.previewConfigPath,\n          mainConfigPath: project.mainConfigPath,\n          storiesPaths: project.storiesPaths,\n          hasCsfFactoryPreview: project.hasCsfFactoryPreview,\n        };\n        const result = await fix.check(checkOptions);\n\n        if (result !== null) {\n          collectResult(fix, project, 'check_succeeded', result);\n        } else {\n          collectResult(fix, project, 'not_applicable');\n        }\n      } catch (error) {\n        collectResult(fix, project, 'check_failed');\n\n        logger.debug(\n          `Failed to check fix ${fix.id} for project ${shortenPath(project.configDir)}.`\n        );\n        logger.debug(`${error instanceof Error ? error.stack : String(error)}`);\n        ErrorCollector.addError(error);\n      }\n    }\n  }\n\n  const allAutomigrations = Array.from(automigrationMap.values());\n\n  const applicableAutomigrations = allAutomigrations.filter((am) =>\n    am.reports.every((rep) => rep.status !== 'not_applicable')\n  );\n  // Single pass through detectedAutomigrations to build both arrays\n  const { successAutomigrations, failedAutomigrations } = applicableAutomigrations.reduce(\n    (acc, { fix, reports }) => {\n      const successReports = reports.filter((report) => report.status === 'check_succeeded');\n      const failedReports = reports.filter((report) => report.status === 'check_failed');\n\n      if (successReports.length > 0) {\n        acc.successAutomigrations.push(fix.id);\n      }\n\n      if (failedReports.length > 0) {\n        acc.failedAutomigrations.push(fix.id);\n      }\n\n      return acc;\n    },\n    { successAutomigrations: [], failedAutomigrations: [] } as {\n      successAutomigrations: Array<string>;\n      failedAutomigrations: Array<string>;\n    }\n  );\n\n  taskLog.message('\\nAutomigrations detected:');\n\n  successAutomigrations.forEach((fixId) => {\n    taskLog.message(`${CLI_COLORS.success(`${logger.SYMBOLS.success} ${fixId}`)}`);\n  });\n\n  failedAutomigrations.forEach((fixId) => {\n    taskLog.message(`${CLI_COLORS.error(`${logger.SYMBOLS.error} ${fixId}`)}`);\n  });\n\n  if (failedAutomigrations.length > 0) {\n    taskLog.error(\n      `${failedAutomigrations.length} automigration ${\n        failedAutomigrations.length > 1 ? 'checks' : 'check'\n      } failed`\n    );\n  } else {\n    taskLog.success(\n      `${applicableAutomigrations.length === 0 ? 'No automigrations detected' : `${applicableAutomigrations.length} automigration(s) detected`}`\n    );\n  }\n\n  return allAutomigrations;\n}\n\n// Format project directories relative to git root\nconst formatProjectDirs = (list: AutomigrationCheckResult['reports']) => {\n  const amountOfProjectsShown = 1;\n  const relativeDirs = list\n    .filter((p) => p.status === 'check_succeeded')\n    .map((p) => shortenPath(p.project.configDir) || '.');\n  if (relativeDirs.length <= amountOfProjectsShown) {\n    return relativeDirs.join(', ');\n  }\n  const remaining = relativeDirs.length - amountOfProjectsShown;\n  return `${relativeDirs.slice(0, amountOfProjectsShown).join(', ')}${remaining > 0 ? ` and ${remaining} more...` : ''}`;\n};\n\n/** Prompts user to select which automigrations to run */\nexport async function promptForAutomigrations(\n  automigrations: AutomigrationCheckResult[],\n  options: { dryRun?: boolean; yes?: boolean }\n): Promise<AutomigrationCheckResult[]> {\n  if (automigrations.length === 0) {\n    return [];\n  }\n\n  if (options.dryRun) {\n    logger.log('Detected automigrations (dry run - no changes will be made):');\n    automigrations.forEach(({ fix, reports: list }) => {\n      logger.log(`  - ${fix.id} (${formatProjectDirs(list)})`);\n    });\n    return [];\n  }\n\n  if (options.yes) {\n    logger.log('Running all detected automigrations:');\n    automigrations.forEach(({ fix, reports: list }) => {\n      logger.log(`  - ${fix.id} (${formatProjectDirs(list)})`);\n    });\n    return automigrations;\n  }\n\n  // Create choices for multiselect prompt\n  const choices = automigrations.map((am) => {\n    const hint = [];\n\n    hint.push(`${am.fix.prompt()}`);\n\n    if (am.fix.link) {\n      hint.push(`More info: ${am.fix.link}`);\n    }\n\n    const label =\n      am.reports.length > 1 ? `${am.fix.id} (${formatProjectDirs(am.reports)})` : am.fix.id;\n\n    return {\n      value: am.fix.id,\n      label,\n      hint: hint.join('\\n'),\n      defaultSelected: am.fix.defaultSelected ?? true,\n    };\n  });\n\n  const selectedIds = await prompt.multiselect({\n    message: 'Select automigrations to run',\n    options: choices,\n    initialValues: choices.filter((c) => c.defaultSelected).map((c) => c.value),\n    required: false,\n  });\n\n  return automigrations.filter((am) => selectedIds.includes(am.fix.id));\n}\n\n// Group automigrations by project\ntype ConfigDir = string;\ntype ErrorMessage = string;\nexport type AutomigrationResult = {\n  automigrationStatuses: Record<FixId, FixStatus>;\n  automigrationErrors: Record<FixId, ErrorMessage>;\n};\n/** Runs selected automigrations for each project */\nexport async function runAutomigrationsForProjects(\n  selectedAutomigrations: AutomigrationCheckResult[],\n  options: MultiProjectRunAutomigrationOptions\n): Promise<Record<ConfigDir, AutomigrationResult>> {\n  const { dryRun, skipInstall, automigrations, yes } = options;\n  const projectResults: Record<ConfigDir, AutomigrationResult> = {};\n\n  const applicableAutomigrations = selectedAutomigrations.filter((am) =>\n    am.reports.every((rep) => rep.status !== 'not_applicable')\n  );\n  const projectAutomigrationResults = new Map<\n    ConfigDir,\n    {\n      fix: Fix;\n      project: ProjectAutomigrationData;\n      result: any;\n      status: AutomigrationCheckResultReport['status'];\n    }[]\n  >();\n\n  // selectedAutomigrations -> { fix, reports } -> reports (status passed or failed or skipped) -> project\n  for (const automigration of automigrations) {\n    for (const report of automigration.reports) {\n      const { project, result, status } = report;\n      const existing = projectAutomigrationResults.get(project.configDir) || [];\n\n      if (existing.length > 0) {\n        existing.push({\n          fix: automigration.fix,\n          project,\n          result,\n          status,\n        });\n      } else {\n        projectAutomigrationResults.set(project.configDir, [\n          {\n            fix: automigration.fix,\n            project,\n            result,\n            status,\n          },\n        ]);\n      }\n    }\n  }\n\n  // Run automigrations for each project\n  let projectIndex = 0;\n  for (const [configDir, projectAutomigration] of projectAutomigrationResults) {\n    const countPrefix =\n      projectAutomigrationResults.size > 1\n        ? `(${++projectIndex}/${projectAutomigrationResults.size}) `\n        : '';\n\n    const { project } = projectAutomigration[0];\n\n    const projectName = shortenPath(project.configDir);\n\n    // If there isn't any applicable automigrations, we don't need to use the task log\n    const taskLog =\n      applicableAutomigrations.length > 0\n        ? prompt.taskLog({\n            id: `automigrate-${projectName}`,\n            title: `${countPrefix}Running automigrations for ${projectName}`,\n          })\n        : {\n            message: (message: string) => {\n              logger.debug(`${message}`);\n            },\n            error: (message: string) => {\n              logger.debug(`${message}`);\n            },\n            success: (message: string) => {\n              logger.debug(`${message}`);\n            },\n          };\n    const fixResults: Record<FixId, FixStatus> = {};\n    const fixFailures: Record<FixId, ErrorMessage> = {};\n\n    for (const automigration of projectAutomigration) {\n      const { fix, result, project, status } = automigration;\n\n      if (status === 'not_applicable') {\n        fixResults[fix.id] = FixStatus.UNNECESSARY;\n        continue;\n      }\n\n      if (status === 'check_failed') {\n        fixResults[fix.id] = FixStatus.CHECK_FAILED;\n        continue;\n      }\n\n      // it is only skipped when the current automigration\n      // is either not selected by the user (for a particular proejct)\n      // therefore we need to check for configDir as well as fix id matches\n      const hasBeenSelected = selectedAutomigrations.some(\n        (am) =>\n          am.fix.id === fix.id &&\n          am.reports.some((report) => report.project.configDir === project.configDir)\n      );\n      if (!hasBeenSelected) {\n        fixResults[fix.id] = FixStatus.SKIPPED;\n        continue;\n      }\n\n      try {\n        if (typeof fix.run === 'function') {\n          const runOptions: RunOptions<typeof result> = {\n            packageManager: project.packageManager,\n            result,\n            dryRun,\n            mainConfigPath: project.mainConfigPath,\n            previewConfigPath: project.previewConfigPath,\n            mainConfig: project.mainConfig,\n            configDir: project.configDir,\n            skipInstall,\n            storybookVersion: project.storybookVersion,\n            storiesPaths: project.storiesPaths,\n            yes,\n          };\n\n          await fix.run(runOptions);\n          fixResults[fix.id] = FixStatus.SUCCEEDED;\n          taskLog.message(CLI_COLORS.success(`${logger.SYMBOLS.success} ${fix.id}`));\n        }\n      } catch (error) {\n        const errorMessage =\n          (error instanceof Error ? error.stack : String(error)) ?? 'Unknown error';\n        fixResults[fix.id] = FixStatus.FAILED;\n        fixFailures[fix.id] = sanitizeError(error as Error);\n        taskLog.message(CLI_COLORS.error(`${logger.SYMBOLS.error} ${automigration.fix.id}`));\n        logger.debug(errorMessage);\n        ErrorCollector.addError(error);\n      }\n    }\n\n    const automigrationsWithErrors = Object.values(fixResults).filter(\n      (status) => status === FixStatus.FAILED\n    );\n\n    if (automigrationsWithErrors.length > 0) {\n      const count = automigrationsWithErrors.length;\n      taskLog.error(`${countPrefix}${count} automigrations failed for ${projectName}`);\n    } else {\n      taskLog.success(`${countPrefix}Completed automigrations for ${projectName}`);\n    }\n\n    projectResults[configDir] = {\n      automigrationStatuses: fixResults,\n      automigrationErrors: fixFailures,\n    };\n  }\n\n  return projectResults;\n}\n\nexport async function runAutomigrations(\n  projects: CollectProjectsSuccessResult[],\n  options: UpgradeOptions\n): Promise<{\n  detectedAutomigrations: AutomigrationCheckResult[];\n  automigrationResults: Record<string, AutomigrationResult>;\n}> {\n  // Prepare project data for automigrations\n  const projectAutomigrationData: ProjectAutomigrationData[] = projects.map((project) => ({\n    configDir: project.configDir,\n    packageManager: project.packageManager,\n    mainConfig: project.mainConfig,\n    mainConfigPath: project.mainConfigPath!,\n    previewConfigPath: project.previewConfigPath,\n    storybookVersion: project.currentCLIVersion,\n    beforeVersion: project.beforeVersion,\n    storiesPaths: project.storiesPaths,\n    hasCsfFactoryPreview: project.hasCsfFactoryPreview,\n  }));\n\n  const detectingAutomigrationTask = prompt.taskLog({\n    id: 'detect-automigrations',\n    title:\n      projectAutomigrationData.length > 1\n        ? `Detecting automigrations for ${projectAutomigrationData.length} projects...`\n        : `Detecting automigrations...`,\n  });\n  // Collect all applicable automigrations across all projects\n  const detectedAutomigrations = await collectAutomigrationsAcrossProjects({\n    fixes: allFixes,\n    projects: projectAutomigrationData,\n    dryRun: options.dryRun,\n    yes: options.yes,\n    skipInstall: options.skipInstall,\n    taskLog: detectingAutomigrationTask,\n  });\n\n  // Filter out automigrations that should run\n  const successfulAutomigrations = detectedAutomigrations.filter((am) =>\n    am.reports.some((report) => report.status === 'check_succeeded')\n  );\n\n  // Prompt user to select which automigrations to run\n  const selectedAutomigrations = await promptForAutomigrations(successfulAutomigrations, {\n    dryRun: options.dryRun,\n    yes: options.yes,\n  });\n  // Run selected automigrations for each project\n  const automigrationResults = await runAutomigrationsForProjects(selectedAutomigrations, {\n    automigrations: detectedAutomigrations,\n    dryRun: options.dryRun,\n    yes: options.yes,\n    skipInstall: options.skipInstall,\n  });\n\n  // Special case handling for rnstorybook-config which renames the config dir\n  // TODO: Remove this as soon as the rn-storybook-config automigration is removed\n  Object.entries(automigrationResults).forEach(([configDir, resultData]) => {\n    if (resultData.automigrationStatuses[rnstorybookConfig.id] === FixStatus.SUCCEEDED) {\n      const project = projects.find((p) => p.configDir === configDir);\n      if (project) {\n        const oldConfigDir = project.configDir;\n        project.configDir = project.configDir.replace('.storybook', '.rnstorybook');\n        automigrationResults[project.configDir] = resultData;\n        delete automigrationResults[oldConfigDir];\n      }\n    }\n  });\n\n  return {\n    detectedAutomigrations,\n    automigrationResults,\n  };\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/automigrate/types.ts",
    "content": "import type { JsPackageManager, PackageManagerName } from 'storybook/internal/common';\nimport type { StorybookConfigRaw } from 'storybook/internal/types';\n\nexport interface CheckOptions {\n  packageManager: JsPackageManager;\n  rendererPackage?: string;\n  configDir?: string;\n  mainConfig: StorybookConfigRaw;\n  storybookVersion: string;\n  previewConfigPath?: string;\n  mainConfigPath?: string;\n  storiesPaths: string[];\n  hasCsfFactoryPreview: boolean;\n}\n\nexport interface RunOptions<ResultType> {\n  packageManager: JsPackageManager;\n  result: ResultType;\n  dryRun?: boolean;\n  mainConfigPath: string;\n  previewConfigPath?: string;\n  mainConfig: StorybookConfigRaw;\n  configDir: string;\n  skipInstall?: boolean;\n  storybookVersion: string;\n  storiesPaths: string[];\n  /** Skip prompts and use defaults (from --yes flag) */\n  yes?: boolean;\n  /** Glob pattern for story files (for csf-factories codemod) */\n  glob?: string;\n}\n\n/**\n * PromptType defines how the user will be prompted to apply an automigration fix\n *\n * - Auto: the fix will be applied automatically\n * - Manual: the user will be prompted to apply the fix\n * - Notification: the user will be notified about some changes. A fix isn't required, though\n * - Command: the fix will only be applied when specified directly by its id\n */\nexport type Prompt = 'auto' | 'manual' | 'notification' | 'command';\n\ntype BaseFix<ResultType = any> = {\n  id: string;\n  check: (options: CheckOptions) => Promise<ResultType | null>;\n  /** Keep the prompt message short and concise. */\n  prompt: () => string;\n  /** Whether the automigration is selected by default when the user is prompted. */\n  defaultSelected?: boolean;\n  link?: string;\n};\n\ntype PromptType<ResultType = any, T = Prompt> =\n  | T\n  | ((result: ResultType) => Promise<Prompt> | Prompt);\n\nexport type Fix<ResultType = any> =\n  | ({\n      promptType?: PromptType<ResultType, 'auto'>;\n      run: (options: RunOptions<ResultType>) => Promise<void>;\n    } & BaseFix<ResultType>)\n  | ({\n      promptType: PromptType<ResultType, 'manual' | 'notification'>;\n      run?: never;\n    } & BaseFix<ResultType>);\n\nexport type CommandFix<ResultType = any> = {\n  promptType: PromptType<ResultType, 'command'>;\n  run: (options: RunOptions<ResultType>) => Promise<void>;\n} & Omit<BaseFix<ResultType>, 'versionRange' | 'check' | 'prompt'>;\n\nexport type FixId = string;\n\nexport enum PreCheckFailure {\n  UNDETECTED_SB_VERSION = 'undetected_sb_version',\n  MAINJS_NOT_FOUND = 'mainjs_not_found',\n  MAINJS_EVALUATION = 'mainjs_evaluation_error',\n}\n\nexport interface AutofixOptions extends Omit<AutofixOptionsFromCLI, 'packageManager'> {\n  packageManager: JsPackageManager;\n  mainConfigPath: string;\n  previewConfigPath?: string;\n  mainConfig: StorybookConfigRaw;\n  storybookVersion: string;\n  /** Whether the migration is part of an upgrade. */\n  isUpgrade: boolean;\n  isLatest: boolean;\n  storiesPaths: string[];\n  hasCsfFactoryPreview: boolean;\n}\nexport interface AutofixOptionsFromCLI {\n  fixId?: FixId;\n  list?: boolean;\n  fixes?: Fix[];\n  yes?: boolean;\n  packageManager?: PackageManagerName;\n  dryRun?: boolean;\n  configDir: string;\n  renderer?: string;\n  skipInstall?: boolean;\n  hideMigrationSummary?: boolean;\n  skipDoctor?: boolean;\n  /** Glob pattern for story files (for csf-factories codemod) */\n  glob?: string;\n}\n\nexport enum FixStatus {\n  CHECK_FAILED = 'check_failed',\n  UNNECESSARY = 'unnecessary',\n  MANUAL_SUCCEEDED = 'manual_succeeded',\n  MANUAL_SKIPPED = 'manual_skipped',\n  SKIPPED = 'skipped',\n  SUCCEEDED = 'succeeded',\n  FAILED = 'failed',\n}\n\nexport type FixSummary = {\n  skipped: FixId[];\n  manual: FixId[];\n  succeeded: FixId[];\n  failed: Record<FixId, string>;\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/bin/index.ts",
    "content": "#!/usr/bin/env node\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { dedent } from 'ts-dedent';\n\nconst [majorNodeVersion, minorNodeVersion] = process.versions.node.split('.').map(Number);\n\nif (\n  majorNodeVersion < 20 ||\n  (majorNodeVersion === 20 && minorNodeVersion < 19) ||\n  (majorNodeVersion === 22 && minorNodeVersion < 12)\n) {\n  logger.error(\n    dedent`To run Storybook, you need Node.js version 20.19+ or 22.12+.\n      You are currently running Node.js ${process.version}. Please upgrade your Node.js installation.`\n  );\n  process.exit(1);\n}\n\nimport('./run.ts');\n"
  },
  {
    "path": "code/lib/cli-storybook/src/bin/run.ts",
    "content": "import { globalSettings } from 'storybook/internal/cli';\nimport {\n  HandledError,\n  JsPackageManagerFactory,\n  PackageManagerName,\n  isCI,\n  optionalEnvToBoolean,\n  removeAddon as remove,\n  versions,\n} from 'storybook/internal/common';\nimport { withTelemetry } from 'storybook/internal/core-server';\nimport { CLI_COLORS, logTracker, logger } from 'storybook/internal/node-logger';\nimport { addToGlobalContext, telemetry } from 'storybook/internal/telemetry';\n\nimport { Option, program } from 'commander';\nimport envinfo from 'envinfo';\nimport leven from 'leven';\nimport picocolors from 'picocolors';\n\nimport { version } from '../../package.json';\nimport { add } from '../add.ts';\nimport { doAutomigrate } from '../automigrate/index.ts';\nimport { doctor } from '../doctor/index.ts';\nimport { link } from '../link.ts';\nimport { migrate } from '../migrate.ts';\nimport { sandbox } from '../sandbox.ts';\nimport { type UpgradeOptions, upgrade } from '../upgrade.ts';\n\naddToGlobalContext('cliVersion', versions.storybook);\n\n// Return a failed exit code but write the logs to a file first\nconst handleCommandFailure =\n  (logFilePath: string | boolean | undefined) =>\n  async (error: unknown): Promise<never> => {\n    if (!(error instanceof HandledError)) {\n      logger.error(String(error));\n    }\n\n    try {\n      const logFile = await logTracker.writeToFile(logFilePath);\n      logger.log(`Debug logs are written to: ${logFile}`);\n    } catch {}\n    logger.outro('');\n    process.exit(1);\n  };\n\nconst command = (name: string) =>\n  program\n    .command(name)\n    .option(\n      '--disable-telemetry',\n      'Disable sending telemetry data',\n      optionalEnvToBoolean(process.env.STORYBOOK_DISABLE_TELEMETRY)\n    )\n    .option('--debug', 'Get more logs in debug mode', false)\n    .option('--enable-crash-reports', 'Enable sending crash reports to telemetry data')\n    .option(\n      '--logfile [path]',\n      'Write all debug logs to the specified file at the end of the run. Defaults to debug-storybook.log when [path] is not provided'\n    )\n    .option('--loglevel <trace | debug | info | warn | error | silent>', 'Define log level', 'info')\n    .hook('preAction', async (self) => {\n      const options = self.opts();\n      if (options.debug) {\n        logger.setLogLevel('debug');\n      }\n\n      if (options.loglevel) {\n        logger.setLogLevel(options.loglevel);\n      }\n\n      if (options.logfile) {\n        logTracker.enableLogWriting();\n      }\n\n      try {\n        await globalSettings();\n      } catch (e) {\n        logger.error('Error loading global settings:\\n' + String(e));\n      }\n    })\n    .hook('postAction', async (command) => {\n      if (logTracker.shouldWriteLogsToFile) {\n        try {\n          const logFile = await logTracker.writeToFile(command.getOptionValue('logfile'));\n          logger.log(`Debug logs are written to: ${logFile}`);\n        } catch {}\n        logger.outro(CLI_COLORS.success('Done!'));\n      }\n    });\n\ncommand('init')\n  .description('Initialize Storybook into your project')\n  .option('-f --force', 'Force add Storybook')\n  .option('-s --skip-install', 'Skip installing deps')\n  .addOption(\n    new Option('--package-manager <type>', 'Force package manager for installing deps').choices(\n      Object.values(PackageManagerName)\n    )\n  )\n  // TODO: Remove in SB11\n  .option('--use-pnp', 'Enable PnP mode for Yarn 2+')\n  .option('-p --parser <babel | babylon | flow | ts | tsx>', 'jscodeshift parser')\n  .option('-t --type <type>', 'Add Storybook for a specific project type')\n  .option('-y --yes', 'Answer yes to all prompts')\n  .option('-b --builder <webpack5 | vite>', 'Builder library')\n  .option('-l --linkable', 'Prepare installation for link (contributor helper)')\n  .option(\n    '--dev',\n    'Launch the development server after completing initialization. Enabled by default (default: true)',\n    !isCI() && !optionalEnvToBoolean(process.env.IN_STORYBOOK_SANDBOX)\n  )\n  .option(\n    '--no-dev',\n    'Complete the initialization of Storybook without launching the Storybook development server'\n  );\n\ncommand('add <addon>')\n  .description('Add an addon to your Storybook')\n  .addOption(\n    new Option('--package-manager <type>', 'Force package manager for installing deps').choices(\n      Object.values(PackageManagerName)\n    )\n  )\n  .option('-c, --config-dir <dir-name>', 'Directory where to load Storybook configurations from')\n  .option('--skip-install', 'Skip installing deps')\n  .option('-s --skip-postinstall', 'Skip package specific postinstall config modifications')\n  .option('-y --yes', 'Skip prompting the user')\n  .option('--skip-doctor', 'Skip doctor check')\n  .action((addonName: string, options: any) => {\n    withTelemetry('add', { cliOptions: options }, async () => {\n      logger.intro(`Setting up your project for ${addonName}`);\n\n      await add(addonName, options);\n\n      if (!options.disableTelemetry) {\n        await telemetry('add', { addon: addonName, source: 'cli' });\n      }\n      logger.outro('Done!');\n    }).catch(handleCommandFailure);\n  });\n\ncommand('remove <addon>')\n  .description('Remove an addon from your Storybook')\n  .addOption(\n    new Option('--package-manager <type>', 'Force package manager for installing deps').choices(\n      Object.values(PackageManagerName)\n    )\n  )\n  .option('-c, --config-dir <dir-name>', 'Directory where to load Storybook configurations from')\n  .option('-s --skip-install', 'Skip installing deps')\n  .action((addonName: string, options: any) =>\n    withTelemetry('remove', { cliOptions: options }, async () => {\n      logger.intro(`Removing ${addonName} from your Storybook`);\n      const packageManager = JsPackageManagerFactory.getPackageManager({\n        configDir: options.configDir,\n        force: options.packageManager,\n      });\n      await remove(addonName, {\n        configDir: options.configDir,\n        packageManager,\n        skipInstall: options.skipInstall,\n      });\n      if (!options.disableTelemetry) {\n        await telemetry('remove', { addon: addonName, source: 'cli' });\n      }\n      logger.outro('Done!');\n    }).catch(handleCommandFailure(options.logfile))\n  );\n\ncommand('upgrade')\n  .description(`Upgrade your Storybook packages to v${versions.storybook}`)\n  .addOption(\n    new Option('--package-manager <type>', 'Force package manager for installing deps').choices(\n      Object.values(PackageManagerName)\n    )\n  )\n  .option('-y --yes', 'Skip prompting the user')\n  .option('-f --force', 'force the upgrade, skipping autoblockers')\n  .option('-n --dry-run', 'Only check for upgrades, do not install')\n  .option('-s --skip-check', 'Skip postinstall version and automigration checks')\n  .option(\n    '-c, --config-dir <dir-name...>',\n    'Directory(ies) where to load Storybook configurations from'\n  )\n  .action(async (options: UpgradeOptions) => {\n    await withTelemetry(\n      'upgrade',\n      { cliOptions: { ...options, configDir: options.configDir?.[0] } },\n      async () => {\n        logger.intro(`Storybook upgrade - v${versions.storybook}`);\n        await upgrade(options);\n        logger.outro('Storybook upgrade completed!');\n      }\n    ).catch(handleCommandFailure(options.logfile));\n  });\n\ncommand('info')\n  .description('Prints debugging information about the local environment')\n  .action(async () => {\n    logger.log(picocolors.bold('\\nStorybook Environment Info:'));\n    const pkgManager = JsPackageManagerFactory.getPackageManager();\n    const activePackageManager = pkgManager.type.replace(/\\d/, ''); // 'yarn1' -> 'yarn'\n    const output = await envinfo.run({\n      System: ['OS', 'CPU', 'Shell'],\n      Binaries: ['Node', 'Yarn', 'npm', 'pnpm'],\n      Browsers: ['Chrome', 'Edge', 'Firefox', 'Safari'],\n      npmPackages: '{@storybook/*,*storybook*,sb,chromatic}',\n      npmGlobalPackages: '{@storybook/*,*storybook*,sb,chromatic}',\n    });\n    const activePackageManagerLine = output.match(new RegExp(`${activePackageManager}:.*`, 'i'));\n    logger.log(\n      output.replace(\n        activePackageManagerLine,\n        picocolors.bold(`${activePackageManagerLine} <----- active`)\n      )\n    );\n  });\n\ncommand('migrate [migration]')\n  .description('Run a Storybook codemod migration on your source files')\n  .option('-l --list', 'List available migrations')\n  .option('-g --glob <glob>', 'Glob for files upon which to apply the migration', '**/*.js')\n  .option('-p --parser <babel | babylon | flow | ts | tsx>', 'jscodeshift parser')\n  .option('-c, --config-dir <dir-name>', 'Directory where to load Storybook configurations from')\n  .option(\n    '-n --dry-run',\n    'Dry run: verify the migration exists and show the files to which it will be applied'\n  )\n  .option(\n    '-r --rename <from-to>',\n    'Rename suffix of matching files after codemod has been applied, e.g. \".js:.ts\"'\n  )\n  .action((migration, options) => {\n    withTelemetry('migrate', { cliOptions: options }, async () => {\n      logger.intro(`Running ${migration} migration`);\n      await migrate(migration, options);\n      logger.outro('Migration completed');\n    }).catch(handleCommandFailure(options.logfile));\n  });\n\ncommand('sandbox [filterValue]')\n  .alias('repro') // for backwards compatibility\n  .description('Create a sandbox from a set of possible templates')\n  .option('-o --output <outDir>', 'Define an output directory')\n  .option('--no-init', 'Whether to download a template without an initialized Storybook', false)\n  .action((filterValue, options) => {\n    logger.intro(`Creating a Storybook sandbox...`);\n    sandbox({ filterValue, ...options })\n      .catch(handleCommandFailure)\n      .finally(() => {\n        logger.outro('Done!');\n      });\n  });\n\ncommand('link <repo-url-or-directory>')\n  .description('Pull down a repro from a URL (or a local directory), link it, and run storybook')\n  .option('--local', 'Link a local directory already in your file system')\n  .option('--no-start', 'Start the storybook', true)\n  .action((target, { local, start, logfile }) =>\n    link({ target, local, start }).catch(handleCommandFailure(logfile))\n  );\n\ncommand('automigrate [fixId]')\n  .description('Check storybook for incompatibilities or migrations and apply fixes')\n  .option('-y --yes', 'Skip prompting the user')\n  .option('-n --dry-run', 'Only check for fixes, do not actually run them')\n  .addOption(\n    new Option('--package-manager <type>', 'Force package manager for installing deps').choices(\n      Object.values(PackageManagerName)\n    )\n  )\n  .option('-l --list', 'List available migrations')\n  .option('-c, --config-dir <dir-name>', 'Directory of Storybook configurations to migrate')\n  .option('-s --skip-install', 'Skip installing deps')\n  .option(\n    '--renderer <renderer-pkg-name>',\n    'The renderer package for the framework Storybook is using.'\n  )\n  .option('--skip-doctor', 'Skip doctor check')\n  .option('--glob <pattern>', 'Glob pattern for story files (for csf-factories codemod)')\n  .action(async (fixId, options) => {\n    withTelemetry('automigrate', { cliOptions: options }, async () => {\n      logger.intro(fixId ? `Running ${fixId} automigration` : 'Running automigrations');\n      await doAutomigrate({ fixId, ...options });\n      logger.outro('Done');\n    }).catch(handleCommandFailure(options.logfile));\n  });\n\ncommand('doctor')\n  .description('Check Storybook for known problems and provide suggestions or fixes')\n  .addOption(\n    new Option('--package-manager <type>', 'Force package manager for installing deps').choices(\n      Object.values(PackageManagerName)\n    )\n  )\n  .option('-c, --config-dir <dir-name>', 'Directory of Storybook configuration')\n  .action(async (options) => {\n    withTelemetry('doctor', { cliOptions: options }, async () => {\n      logger.intro('Doctoring Storybook');\n      await doctor(options);\n      logger.outro('Done');\n    }).catch(handleCommandFailure(options.logfile));\n  });\n\nprogram.on('command:*', ([invalidCmd]) => {\n  let errorMessage = ` Invalid command: ${picocolors.bold(invalidCmd)}.\\n See --help for a list of available commands.`;\n  const availableCommands = program.commands.map((cmd) => cmd.name());\n  const suggestion = availableCommands.find((cmd) => leven(cmd, invalidCmd) < 3);\n  if (suggestion) {\n    errorMessage += `\\n Did you mean ${picocolors.yellow(suggestion)}?`;\n  }\n  logger.error(errorMessage);\n  process.exit(1);\n});\n\nprogram.usage('<command> [options]').version(String(version)).parse(process.argv);\n"
  },
  {
    "path": "code/lib/cli-storybook/src/codemod/csf-factories.ts",
    "content": "import {\n  type JsPackageManager,\n  optionalEnvToBoolean,\n  syncStorybookAddons,\n} from 'storybook/internal/common';\nimport { logger, prompt } from 'storybook/internal/node-logger';\n\nimport picocolors from 'picocolors';\nimport { dedent } from 'ts-dedent';\n\nimport { runCodemod } from '../automigrate/codemod.ts';\nimport { getFrameworkPackageName } from '../automigrate/helpers/mainConfigFile.ts';\nimport type { CommandFix } from '../automigrate/types.ts';\nimport { configToCsfFactory } from './helpers/config-to-csf-factory.ts';\nimport { storyToCsfFactory } from './helpers/story-to-csf-factory.ts';\n\nasync function runStoriesCodemod(options: {\n  dryRun: boolean | undefined;\n  packageManager: JsPackageManager;\n  useSubPathImports: boolean;\n  previewConfigPath: string;\n  yes: boolean | undefined;\n  glob: string | undefined;\n}) {\n  const { dryRun, packageManager, yes, glob, ...codemodOptions } = options;\n  try {\n    const inSandbox = optionalEnvToBoolean(process.env.IN_STORYBOOK_SANDBOX) ?? false;\n    let globString = glob ?? '**/*.{stories,story}.{js,jsx,ts,tsx,mjs,mjsx,mts,mtsx}';\n\n    if (!glob && inSandbox) {\n      // Sandbox uses limited glob for faster testing (unless glob explicitly provided)\n      globString = '{stories,src}/**/{Button,Header,Page,button,header,page}.stories.*';\n    } else if (!glob && !yes) {\n      logger.log('Please enter the glob for your stories to migrate');\n      globString = await prompt.text({\n        message: 'glob',\n        initialValue: globString,\n      });\n    }\n\n    logger.step('Applying codemod on your stories, this might take some time...');\n\n    await packageManager.runPackageCommand({\n      args: ['storybook', 'migrate', 'csf-2-to-3', `--glob=\"${globString}\"`],\n    });\n\n    await runCodemod(globString, (info) => storyToCsfFactory(info, codemodOptions), {\n      dryRun,\n    });\n  } catch (err: any) {\n    if (err.message === 'No files matched') {\n      await runStoriesCodemod(options);\n    } else {\n      throw err;\n    }\n  }\n}\n\nexport const csfFactories: CommandFix = {\n  id: 'csf-factories',\n  promptType: 'command',\n  async run({\n    dryRun,\n    mainConfig,\n    mainConfigPath,\n    previewConfigPath,\n    packageManager,\n    configDir,\n    yes,\n    glob,\n  }) {\n    const inSandbox = optionalEnvToBoolean(process.env.IN_STORYBOOK_SANDBOX) ?? false;\n    // Defaults to false for users and true in sandbox\n    let useSubPathImports = inSandbox;\n\n    if (!yes && !inSandbox) {\n      // prompt whether the user wants to use imports map\n      logger.logBox(dedent`\n        The CSF Factories format can benefit from using absolute imports of your ${picocolors.cyan(previewConfigPath)} file. We can configure that for you, using subpath imports (a node standard), by adjusting the imports property of your package.json.\n        \n        However, we cannot broadly recommend it for all projects, because it might not work in some monorepo setups or if you have an outdated tsconfig, use custom paths, or have type alias plugins configured in your project. You can always rerun this codemod and select another option to update your code later.\n        \n        More info: ${picocolors.yellow('https://storybook.js.org/docs/api/csf/csf-next?ref=upgrade#previewmeta')}\n      `);\n\n      useSubPathImports = await prompt.select<boolean>({\n        message: 'Which import type would you like to use for your story files?',\n        options: [\n          {\n            label: \"Relative imports (import preview from '../../.storybook/preview')\",\n            value: false,\n          },\n          { label: \"Subpath imports (import preview from '#.storybook/preview')\", value: true },\n        ],\n      });\n    }\n\n    const { packageJson } = packageManager.primaryPackageJson;\n\n    if (useSubPathImports && !packageJson.imports?.['#*']) {\n      logger.step(\n        `Adding imports map in ${picocolors.cyan(packageManager.primaryPackageJson.packageJsonPath)}`\n      );\n      packageJson.imports = {\n        ...packageJson.imports,\n        // @ts-expect-error we need to upgrade type-fest\n        '#*': ['./*', './*.ts', './*.tsx', './*.js', './*.jsx'],\n      };\n      packageManager.writePackageJson(packageJson);\n    }\n\n    await runStoriesCodemod({\n      dryRun,\n      packageManager,\n      useSubPathImports,\n      previewConfigPath: previewConfigPath!,\n      yes,\n      glob,\n    });\n\n    logger.step('Applying codemod on your main config...');\n    const frameworkPackage =\n      getFrameworkPackageName(mainConfig) || '@storybook/your-framework-here';\n    await runCodemod(mainConfigPath, (fileInfo) =>\n      configToCsfFactory(fileInfo, { configType: 'main', frameworkPackage }, { dryRun })\n    );\n\n    logger.step('Applying codemod on your preview config...');\n    await runCodemod(previewConfigPath, (fileInfo) =>\n      configToCsfFactory(fileInfo, { configType: 'preview', frameworkPackage }, { dryRun })\n    );\n\n    await syncStorybookAddons(mainConfig, previewConfigPath!, configDir);\n\n    logger.logBox(\n      dedent`\n          You can now run Storybook with the new CSF factories format.\n          \n          For more info, check out the docs:\n          ${picocolors.yellow('https://storybook.js.org/docs/api/csf/csf-next?ref=upgrade')}\n        `\n    );\n  },\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.test.ts",
    "content": "import { describe, expect, it, vi, beforeEach } from 'vitest';\nimport { dedent } from 'ts-dedent';\nimport { formatFileContent } from 'storybook/internal/common';\nimport { configToCsfFactory } from './config-to-csf-factory.ts';\n\nvi.mock('storybook/internal/common', { spy: true });\n\nbeforeEach(() => {\n  vi.mocked(formatFileContent).mockImplementation(async (_path, content) => content);\n});\nexpect.addSnapshotSerializer({\n  serialize: (val: any) => (typeof val === 'string' ? val : val.toString()),\n  test: () => true,\n});\n\ndescribe('main/preview codemod: general parsing functionality', () => {\n  const transform = async (source: string) =>\n    (\n      await configToCsfFactory(\n        { source, path: 'main.ts' },\n        { configType: 'main', frameworkPackage: '@storybook/react-vite' }\n      )\n    ).trim();\n\n  it('should wrap defineMain call from inline default export', async () => {\n    await expect(\n      transform(dedent`\n        export default {\n          stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n          addons: ['@storybook/addon-essentials'],\n          framework: '@storybook/react-vite',\n        };\n      `)\n    ).resolves.toMatchInlineSnapshot(`\n      import { defineMain } from \"@storybook/react-vite/node\";\n      export default defineMain({\n        stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n        addons: ['@storybook/addon-essentials'],\n        framework: '@storybook/react-vite'\n      });\n    `);\n  });\n  it('should wrap defineMain call from const declared default export', async () => {\n    await expect(\n      transform(dedent`\n        const config = {\n          stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n          addons: ['@storybook/addon-essentials'],\n          framework: '@storybook/react-vite',\n        };\n\n        export default config;\n      `)\n    ).resolves.toMatchInlineSnapshot(`\n      import { defineMain } from \"@storybook/react-vite/node\";\n\n      export default defineMain({\n        stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n        addons: ['@storybook/addon-essentials'],\n        framework: '@storybook/react-vite',\n      });\n    `);\n  });\n\n  it('should preserve leading comments when adding import', async () => {\n    await expect(\n      transform(dedent`\n        // @ts-check\n        /** @license MIT */\n        export default {\n          stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n          framework: '@storybook/react-vite',\n        };\n      `)\n    ).resolves.toMatchInlineSnapshot(`\n      // @ts-check\n      /** @license MIT */\n      import { defineMain } from \"@storybook/react-vite/node\";\n\n      export default defineMain({\n        stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n        framework: '@storybook/react-vite'\n      });\n    `);\n  });\n  it('should wrap defineMain call from const declared default export with different type annotations', async () => {\n    const typedVariants = [\n      'export default config;',\n      'export default config satisfies StorybookConfig;',\n      'export default config as StorybookConfig;',\n      'export default config as unknown as StorybookConfig;',\n    ];\n\n    for (const variant of typedVariants) {\n      await expect(\n        transform(dedent`\n          const config = {\n            stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n            addons: ['@storybook/addon-essentials'],\n            framework: '@storybook/react-vite',\n          };\n\n          ${variant}\n        `)\n      ).resolves.toMatchInlineSnapshot(`\n        import { defineMain } from \"@storybook/react-vite/node\";\n\n        export default defineMain({\n          stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],\n          addons: ['@storybook/addon-essentials'],\n          framework: '@storybook/react-vite',\n        });\n      `);\n    }\n  });\n\n  it('should wrap defineMain call from const declared default export and default export mix', async () => {\n    await expect(\n      transform(dedent`\n        export const tags = [];\n        export async function viteFinal(config) { return config };\n        const config = {\n          framework: '@storybook/react-vite',\n        };\n\n        export default config;\n      `)\n    ).resolves.toMatchInlineSnapshot(`\n      import { defineMain } from \"@storybook/react-vite/node\";\n\n      export default defineMain({\n        tags: [],\n        viteFinal: () => { return config },\n        framework: '@storybook/react-vite'\n      });\n    `);\n  });\n  it('should wrap defineMain call from named exports format', async () => {\n    await expect(\n      transform(dedent`\n        export function stories() { return ['../src/**/*.stories.@(js|jsx|ts|tsx)'] };\n        export const addons = ['@storybook/addon-essentials'];\n        export async function viteFinal(config) { return config };\n        export const framework = '@storybook/react-vite';\n      `)\n    ).resolves.toMatchInlineSnapshot(`\n      import { defineMain } from \"@storybook/react-vite/node\";\n\n      export default defineMain({\n        stories: () => { return ['../src/**/*.stories.@(js|jsx|ts|tsx)'] },\n        addons: ['@storybook/addon-essentials'],\n        viteFinal: () => { return config },\n        framework: '@storybook/react-vite'\n      });\n    `);\n  });\n  it('should not add additional imports if there is already one', async () => {\n    const transformed = await transform(dedent`\n        import { defineMain } from \"@storybook/react-vite/node\";\n        const config = {};\n\n        export default config;\n    `);\n    expect(\n      transformed.match(/import { defineMain } from \"@storybook\\/react-vite\\/node\"/g)\n    ).toHaveLength(1);\n  });\n\n  it('should leave already transformed code as is', async () => {\n    const original = dedent`\n      import { defineMain } from '@storybook/react-vite/node';\n\n      export default defineMain({});\n    `;\n    const transformed = await transform(original);\n    expect(transformed).toEqual(original);\n  });\n\n  it('should add missing import when already transformed but import is absent', async () => {\n    await expect(\n      transform(dedent`\n        export default defineMain({});\n      `)\n    ).resolves.toMatchInlineSnapshot(`\n      import { defineMain } from \"@storybook/react-vite/node\";\n      export default defineMain({});\n    `);\n  });\n\n  it('should add missing specifier when already transformed but defineMain is not in existing import', async () => {\n    await expect(\n      transform(dedent`\n        import { someHelper } from '@storybook/react-vite/node';\n\n        export default defineMain({});\n      `)\n    ).resolves.toMatchInlineSnapshot(`\n      import { someHelper, defineMain } from '@storybook/react-vite/node';\n\n      export default defineMain({});\n    `);\n  });\n\n  it('should remove legacy main config type imports if unused', async () => {\n    await expect(\n      transform(dedent`\n        import { type StorybookConfig } from '@storybook/react-vite'\n\n        const config: StorybookConfig = {\n          stories: []\n        };\n        export default config;\n      `)\n    ).resolves.toMatchInlineSnapshot(`\n      import { defineMain } from \"@storybook/react-vite/node\";\n      export default defineMain({\n        stories: []\n      });\n    `);\n  });\n\n  it('should not remove legacy main config type imports if used', async () => {\n    await expect(\n      transform(dedent`\n        import { type StorybookConfig } from '@storybook/react-vite'\n\n        const config: StorybookConfig = {\n          stories: []\n        };\n\n        const features: StorybookConfig['features'] = {\n          foo: true,\n        };\n\n        export default config;\n      `)\n    ).resolves.toMatchInlineSnapshot(`\n      import { defineMain } from \"@storybook/react-vite/node\";\n      import { type StorybookConfig } from '@storybook/react-vite'\n\n      const features: StorybookConfig['features'] = {\n        foo: true,\n      };\n\n      export default defineMain({\n        stories: []\n      });\n    `);\n  });\n});\n\ndescribe('preview specific functionality', () => {\n  const transform = async (source: string) =>\n    (\n      await configToCsfFactory(\n        { source, path: 'preview.ts' },\n        { configType: 'preview', frameworkPackage: '@storybook/react-vite' }\n      )\n    ).trim();\n\n  it('should contain a named config export', async () => {\n    await expect(\n      transform(dedent`\n        export default {\n          tags: ['test'],\n        };\n      `)\n    ).resolves.toMatchInlineSnapshot(`\n      import { definePreview } from \"@storybook/react-vite\";\n      export default definePreview({\n        tags: ['test']\n      });\n    `);\n  });\n\n  it('should remove legacy preview type imports', async () => {\n    await expect(\n      transform(dedent`\n        import type { Preview } from '@storybook/react-vite'\n\n        const preview: Preview = {\n          tags: []\n        };\n        export default preview;\n      `)\n    ).resolves.toMatchInlineSnapshot(`\n      import { definePreview } from \"@storybook/react-vite\";\n      export default definePreview({\n        tags: []\n      });\n    `);\n  });\n\n  it('should not change non story exports', async () => {\n    await expect(\n      transform(dedent`\n        import type { Preview } from '@storybook/react-vite'\n        \n        export const withStore: Decorator = () => {}\n\n        const preview: Preview = {\n          tags: []\n        };\n        export default preview;\n      `)\n    ).resolves.toMatchInlineSnapshot(`\n      import { definePreview } from \"@storybook/react-vite\";\n\n      export const withStore: Decorator = () => {}\n\n      export default definePreview({\n        tags: []\n      });\n    `);\n  });\n  it('should wrap definePreview for mixed annotations and default export', async () => {\n    await expect(\n      transform(dedent`\n        export const decorators = [1]\n        export default {\n          parameters: {},\n        }\n      `)\n    ).resolves.toMatchInlineSnapshot(`\n      import { definePreview } from \"@storybook/react-vite\";\n      export default definePreview({\n        decorators: [1],\n        parameters: {}\n      });\n    `);\n  });\n\n  it('should wrap definePreview for const defined preview with type annotations', async () => {\n    await expect(\n      transform(dedent`\n        import { type Preview } from '@storybook/react-vite';\n\n        const preview = {\n          decorators: [],\n          \n          parameters: {\n            options: {}\n          }\n        } satisfies Preview;\n\n        export default preview;\n\n      `)\n    ).resolves.toMatchInlineSnapshot(`\n      import { definePreview } from '@storybook/react-vite';\n\n      export default definePreview({\n        decorators: [],\n        \n        parameters: {\n          options: {}\n        }\n      });\n    `);\n  });\n\n  it('should wrap definePreview for mixed annotations and default const export', async () => {\n    await expect(\n      transform(dedent`\n        import { type Preview } from '@storybook/react-vite';\n        export const decorators = []\n        const preview = {\n\n          parameters: {\n            options: {}\n          }\n        } satisfies Preview;\n\n        export default preview;\n\n      `)\n    ).resolves.toMatchInlineSnapshot(`\n      import { definePreview } from '@storybook/react-vite';\n\n      export default definePreview({\n        decorators: [],\n\n        parameters: {\n          options: {}\n        }\n      });\n    `);\n  });\n\n  it('should add default export when preview only has side-effect imports', async () => {\n    await expect(\n      transform(dedent`\n        import './preview.scss'\n      `)\n    ).resolves.toMatchInlineSnapshot(`\n      import { definePreview } from \"@storybook/react-vite\";\n      import './preview.scss'\n      export default definePreview({});\n    `);\n  });\n\n  it('should add default export when preview file is empty', async () => {\n    await expect(transform('')).resolves.toMatchInlineSnapshot(`\n      import { definePreview } from \"@storybook/react-vite\";\n      export default definePreview({});\n    `);\n  });\n\n  it('should add default export when preview only has multiple side-effect imports', async () => {\n    await expect(\n      transform(dedent`\n        import './preview.scss'\n        import './global.css'\n      `)\n    ).resolves.toMatchInlineSnapshot(`\n      import { definePreview } from \"@storybook/react-vite\";\n      import './preview.scss'\n      import './global.css'\n      export default definePreview({});\n    `);\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.ts",
    "content": "import { types as t } from 'storybook/internal/babel';\nimport { formatFileContent } from 'storybook/internal/common';\nimport { loadConfig, printConfig } from 'storybook/internal/csf-tools';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport picocolors from 'picocolors';\n\nimport type { FileInfo } from '../../automigrate/codemod.ts';\nimport {\n  addImportToTop,\n  cleanupTypeImports,\n  getConfigProperties,\n  removeExportDeclarations,\n} from './csf-factories-utils.ts';\n\nexport async function configToCsfFactory(\n  info: FileInfo,\n  { configType, frameworkPackage }: { configType: 'main' | 'preview'; frameworkPackage: string },\n  { dryRun = false, skipFormatting = false }: { dryRun?: boolean; skipFormatting?: boolean } = {}\n) {\n  const config = loadConfig(info.source);\n  try {\n    config.parse();\n  } catch (err) {\n    logger.log(`Error when parsing ${info.path}, skipping:\\n${err}`);\n    return info.source;\n  }\n\n  const methodName = configType === 'main' ? 'defineMain' : 'definePreview';\n  const programNode = config._ast.program;\n  const exportDecls = config._exportDecls;\n\n  const defineConfigProps = getConfigProperties(exportDecls, { configType });\n  const hasNamedExports = defineConfigProps.length > 0;\n\n  // Early return if the code is already transformed (default export is already defineMain/definePreview)\n  const isAlreadyTransformed = programNode.body.some((node) => {\n    if (!t.isExportDefaultDeclaration(node)) return false;\n\n    // Unwrap TS syntax (e.g. `as`, `satisfies`) around the default export expression\n    const declaration =\n      typeof (config as any)._unwrap === 'function'\n        ? (config as any)._unwrap(node.declaration)\n        : node.declaration;\n\n    return (\n      t.isCallExpression(declaration) &&\n      t.isIdentifier(declaration.callee) &&\n      declaration.callee.name === methodName\n    );\n  });\n\n  // Check whether the required framework import (e.g. defineMain from '@storybook/react-vite/node') is already present\n  const expectedImportSource = frameworkPackage + (configType === 'main' ? '/node' : '');\n  const hasCorrectImport = programNode.body.some(\n    (node) =>\n      t.isImportDeclaration(node) &&\n      node.importKind !== 'type' &&\n      node.source.value === expectedImportSource &&\n      node.specifiers.some(\n        (spec) =>\n          t.isImportSpecifier(spec) &&\n          t.isIdentifier(spec.imported) &&\n          spec.imported.name === methodName\n      )\n  );\n\n  // For main configs, always return early when already transformed and imports are valid.\n  // For preview configs, only return early when there are no named exports to merge.\n  const shouldSkipTransform =\n    configType === 'main' ? isAlreadyTransformed : isAlreadyTransformed && !hasNamedExports;\n\n  if (shouldSkipTransform && hasCorrectImport) {\n    return info.source;\n  }\n\n  function findDeclarationNodeIndex(declarationName: string): number {\n    return programNode.body.findIndex(\n      (n) =>\n        t.isVariableDeclaration(n) &&\n        n.declarations.some((d) => {\n          let declaration = d.init;\n          // unwrap TS type annotations\n          if (t.isTSAsExpression(declaration) || t.isTSSatisfiesExpression(declaration)) {\n            declaration = declaration.expression;\n          }\n          return (\n            t.isIdentifier(d.id) &&\n            d.id.name === declarationName &&\n            t.isObjectExpression(declaration)\n          );\n        })\n    );\n  }\n\n  if (shouldSkipTransform) {\n    // already transformed — skip transformation but still run import fixup below\n  } else if (config._exportsObject && hasNamedExports) {\n    /**\n     * Scenario 1: Mixed exports\n     *\n     * ```\n     * export const tags = [];\n     * export default {\n     *   parameters: {},\n     * };\n     * ```\n     *\n     * Transform into: `export default defineMain({ tags: [], parameters: {} })`\n     */\n    // when merging named exports with default exports, add the named exports first in the list\n    config._exportsObject.properties = [...defineConfigProps, ...config._exportsObject.properties];\n    programNode.body = removeExportDeclarations(programNode, exportDecls);\n\n    // After merging, ensure the default export is wrapped with defineMain/definePreview\n    const defineConfigCall = t.callExpression(t.identifier(methodName), [config._exportsObject]);\n\n    let exportDefaultNode = null as unknown as t.ExportDefaultDeclaration;\n    let declarationNodeIndex = -1;\n\n    programNode.body.forEach((node) => {\n      // Detect Syntax 1: export default <identifier>\n      if (t.isExportDefaultDeclaration(node) && t.isIdentifier(node.declaration)) {\n        const declarationName = node.declaration.name;\n\n        declarationNodeIndex = findDeclarationNodeIndex(declarationName);\n\n        if (declarationNodeIndex !== -1) {\n          exportDefaultNode = node;\n          // remove the original declaration as it will become a default export\n          const declarationNode = programNode.body[declarationNodeIndex];\n          if (t.isVariableDeclaration(declarationNode)) {\n            const id = declarationNode.declarations[0].id;\n            const variableName = t.isIdentifier(id) && id.name;\n\n            if (variableName) {\n              programNode.body.splice(declarationNodeIndex, 1);\n            }\n          }\n        }\n      } else if (t.isExportDefaultDeclaration(node) && t.isObjectExpression(node.declaration)) {\n        // Detect Syntax 2: export default { ... }\n        exportDefaultNode = node;\n      }\n    });\n\n    if (exportDefaultNode !== null) {\n      exportDefaultNode.declaration = defineConfigCall;\n    }\n  } else if (config._exportsObject) {\n    /**\n     * Scenario 2: Default exports\n     *\n     * - Syntax 1: `const config = {}; export default config;`\n     * - Syntax 2: `export default {};`\n     *\n     * Transform into: `export default defineMain({})`\n     */\n    const defineConfigCall = t.callExpression(t.identifier(methodName), [config._exportsObject]);\n\n    let exportDefaultNode = null as any as t.ExportDefaultDeclaration;\n    let declarationNodeIndex = -1;\n\n    programNode.body.forEach((node) => {\n      // Detect Syntax 1\n      const declaration =\n        t.isExportDefaultDeclaration(node) && config._unwrap(node.declaration as t.Node);\n\n      if (t.isExportDefaultDeclaration(node) && t.isIdentifier(declaration)) {\n        const declarationName = declaration.name;\n\n        declarationNodeIndex = findDeclarationNodeIndex(declarationName);\n\n        if (declarationNodeIndex !== -1) {\n          exportDefaultNode = node;\n          // remove the original declaration as it will become a default export\n          const declarationNode = programNode.body[declarationNodeIndex];\n          if (t.isVariableDeclaration(declarationNode)) {\n            const id = declarationNode.declarations[0].id;\n            const variableName = t.isIdentifier(id) && id.name;\n\n            if (variableName) {\n              programNode.body.splice(declarationNodeIndex, 1);\n            }\n          }\n        }\n      } else if (t.isExportDefaultDeclaration(node) && t.isObjectExpression(node.declaration)) {\n        // Detect Syntax 2\n        exportDefaultNode = node;\n      }\n    });\n\n    if (exportDefaultNode !== null) {\n      exportDefaultNode.declaration = defineConfigCall;\n    }\n  } else if (hasNamedExports) {\n    /**\n     * Scenario 3: Named exports export const foo = {}; export bar = '';\n     *\n     * Transform into: export default defineMain({ foo: {}, bar: '' });\n     */\n    // Construct the `define` call\n    const defineConfigCall = t.callExpression(t.identifier(methodName), [\n      t.objectExpression(defineConfigProps),\n    ]);\n\n    // Remove all related named exports\n    programNode.body = removeExportDeclarations(programNode, exportDecls);\n\n    // Add the new export default declaration\n    programNode.body.push(t.exportDefaultDeclaration(defineConfigCall));\n  } else if (configType === 'preview') {\n    /**\n     * Scenario 4: No exports (empty file or only side-effect imports)\n     *\n     * ```\n     * import './preview.scss';\n     * ```\n     *\n     * Transform into: `import './preview.scss'; export default definePreview({})`\n     *\n     * This is needed because story files using CSF factories import from preview, so the preview\n     * file must have a default export.\n     */\n    const defineConfigCall = t.callExpression(t.identifier(methodName), [t.objectExpression([])]);\n    programNode.body.push(t.exportDefaultDeclaration(defineConfigCall));\n  }\n\n  const configImport = t.importDeclaration(\n    [t.importSpecifier(t.identifier(methodName), t.identifier(methodName))],\n    t.stringLiteral(frameworkPackage + `${configType === 'main' ? '/node' : ''}`)\n  );\n\n  // Check whether @storybook/framework import already exists\n  const existingImport = programNode.body.find(\n    (node) =>\n      t.isImportDeclaration(node) &&\n      node.importKind !== 'type' &&\n      node.source.value === configImport.source.value\n  );\n\n  if (existingImport && t.isImportDeclaration(existingImport)) {\n    // If it does, check whether defineMain/definePreview is already imported\n    // and only add it if it's not\n    const hasMethodName = existingImport.specifiers.some(\n      (specifier) =>\n        t.isImportSpecifier(specifier) &&\n        t.isIdentifier(specifier.imported) &&\n        specifier.imported.name === methodName\n    );\n\n    if (!hasMethodName) {\n      existingImport.specifiers.push(\n        t.importSpecifier(t.identifier(methodName), t.identifier(methodName))\n      );\n    }\n  } else {\n    // if not, add import { defineMain } from '@storybook/framework'\n    addImportToTop(programNode, configImport);\n  }\n\n  // Remove type imports – now inferred – from @storybook/* packages\n  const disallowList = ['StorybookConfig', 'Preview'];\n  programNode.body = cleanupTypeImports(programNode, disallowList);\n\n  const output = printConfig(config).code;\n\n  if (dryRun) {\n    logger.log(`Would write to ${picocolors.yellow(info.path)}:\\n${picocolors.green(output)}`);\n    return info.source;\n  }\n\n  return skipFormatting ? output : formatFileContent(info.path, output);\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { types as t } from 'storybook/internal/babel';\nimport { generate, parser } from 'storybook/internal/babel';\n\nimport {\n  cleanupTypeImports,\n  getConfigProperties,\n  removeExportDeclarations,\n} from './csf-factories-utils.ts';\n\nexpect.addSnapshotSerializer({\n  serialize: (val: any) => {\n    if (typeof val === 'string') {\n      return val;\n    }\n    if (typeof val === 'object' && val !== null) {\n      return JSON.stringify(val, null, 2);\n    }\n    return String(val);\n  },\n  test: (_val) => true,\n});\n\nfunction parseCodeToProgramNode(code: string): t.Program {\n  return parser.parse(code, { sourceType: 'unambiguous', plugins: ['typescript'] }).program;\n}\n\nfunction generateCodeFromAST(node: t.Program) {\n  return generate(node).code;\n}\n\ndescribe('cleanupTypeImports', () => {\n  it('removes disallowed imports from @storybook/*', () => {\n    const code = `\n      import { Story, SomethingElse } from '@storybook/react';\n      import { Other } from 'some-other-package';\n    `;\n\n    const programNode = parseCodeToProgramNode(code);\n    const cleanedNodes = cleanupTypeImports(programNode, ['Story']);\n\n    expect(generateCodeFromAST({ ...programNode, body: cleanedNodes })).toMatchInlineSnapshot(`\n      import { SomethingElse } from '@storybook/react';\n      import { Other } from 'some-other-package';\n    `);\n  });\n\n  it('removes entire import if all specifiers are removed', () => {\n    const code = `\n      import { Story, Meta } from '@storybook/react';\n    `;\n\n    const programNode = parseCodeToProgramNode(code);\n    const cleanedNodes = cleanupTypeImports(programNode, ['Story', 'Meta']);\n\n    expect(generateCodeFromAST({ ...programNode, body: cleanedNodes })).toMatchInlineSnapshot(``);\n  });\n\n  it('retains non storybook imports', () => {\n    const code = `\n      import { Preview } from 'internal-types';\n    `;\n\n    const programNode = parseCodeToProgramNode(code);\n    const cleanedNodes = cleanupTypeImports(programNode, ['Preview']);\n\n    expect(generateCodeFromAST({ ...programNode, body: cleanedNodes })).toMatchInlineSnapshot(\n      `import { Preview } from 'internal-types';`\n    );\n  });\n\n  it('retains namespace imports', () => {\n    const code = `\n      import * as Storybook from '@storybook/react';\n    `;\n\n    const programNode = parseCodeToProgramNode(code);\n    const cleanedNodes = cleanupTypeImports(programNode, ['Preview']);\n\n    expect(generateCodeFromAST({ ...programNode, body: cleanedNodes })).toMatchInlineSnapshot(\n      `import * as Storybook from '@storybook/react';`\n    );\n  });\n\n  it('retains imports if they are used', () => {\n    const code = `\n      import { Type1, type Type2 } from '@storybook/react';\n      import type { Type3, ShouldBeRemoved, Type4 } from '@storybook/react';\n\n      const example: Type1 = {};\n      const example2 = {} as Type2;\n      const example3 = {} satisfies Type3;\n      const example4 = {\n        render: (args: Type4['args']) => {}\n      };\n    `;\n\n    const programNode = parseCodeToProgramNode(code);\n    const cleanedNodes = cleanupTypeImports(programNode, [\n      'Type1',\n      'Type2',\n      'Type3',\n      'Type4',\n      'ShouldBeRemoved',\n    ]);\n\n    const result = generateCodeFromAST({ ...programNode, body: cleanedNodes });\n\n    expect(result).toMatchInlineSnapshot(`\n      import { Type1, type Type2 } from '@storybook/react';\n      import type { Type3, Type4 } from '@storybook/react';\n      const example: Type1 = {};\n      const example2 = {} as Type2;\n      const example3 = {} satisfies Type3;\n      const example4 = {\n        render: (args: Type4['args']) => {}\n      };\n    `);\n\n    expect(result).not.toContain('ShouldBeRemoved');\n  });\n});\n\ndescribe('removeExportDeclarations', () => {\n  it('removes specified variable export declarations', () => {\n    const code = `\n      export const foo = 'foo';\n      export const bar = 'bar';\n      export const baz = 'baz';\n    `;\n\n    const programNode = parseCodeToProgramNode(code);\n    const exportDecls = {\n      foo: t.variableDeclarator(t.identifier('foo')),\n      baz: t.variableDeclarator(t.identifier('baz')),\n    };\n\n    const cleanedNodes = removeExportDeclarations(programNode, exportDecls);\n    const cleanedCode = generateCodeFromAST({ ...programNode, body: cleanedNodes });\n\n    expect(cleanedCode).toMatchInlineSnapshot(`export const bar = 'bar';`);\n  });\n\n  it('removes specified function export declarations', () => {\n    const code = `\n      export function foo() { return 'foo'; }\n      export function bar() { return 'bar'; }\n    `;\n\n    const programNode = parseCodeToProgramNode(code);\n    const exportDecls = {\n      foo: t.functionDeclaration(t.identifier('foo'), [], t.blockStatement([])),\n    };\n\n    const cleanedNodes = removeExportDeclarations(programNode, exportDecls);\n    const cleanedCode = generateCodeFromAST({ ...programNode, body: cleanedNodes });\n\n    expect(cleanedCode).toMatchInlineSnapshot(`\n      export function bar() {\n        return 'bar';\n      }\n    `);\n  });\n\n  it('retains exports not in the disallow list', () => {\n    const code = `\n      export const foo = 'foo';\n      export const bar = 'bar';\n    `;\n\n    const programNode = parseCodeToProgramNode(code);\n    const exportDecls = {\n      nonExistent: t.variableDeclarator(t.identifier('nonExistent')),\n    };\n\n    const cleanedNodes = removeExportDeclarations(programNode, exportDecls);\n    const cleanedCode = generateCodeFromAST({ ...programNode, body: cleanedNodes });\n\n    expect(cleanedCode).toMatchInlineSnapshot(`\n      export const foo = 'foo';\n      export const bar = 'bar';\n    `);\n  });\n});\n\ndescribe('getConfigProperties', () => {\n  it('returns object properties from variable declarations', () => {\n    const exportDecls = {\n      foo: t.variableDeclarator(t.identifier('foo'), t.stringLiteral('fooValue')),\n      bar: t.variableDeclarator(t.identifier('bar'), t.numericLiteral(42)),\n    };\n\n    const properties = getConfigProperties(exportDecls, { configType: 'main' });\n\n    expect(properties).toHaveLength(2);\n    expect(properties[0].key.name).toBe('foo');\n    expect(properties[0].value.value).toBe('fooValue');\n    expect(properties[1].key.name).toBe('bar');\n    expect(properties[1].value.value).toBe(42);\n  });\n\n  it('returns object properties from function declarations', () => {\n    const exportDecls = {\n      foo: t.functionDeclaration(t.identifier('foo'), [], t.blockStatement([])),\n    };\n\n    const properties = getConfigProperties(exportDecls, { configType: 'main' });\n\n    expect(properties).toHaveLength(1);\n    expect(properties[0].key.name).toBe('foo');\n    expect(properties[0].value.type).toBe('ArrowFunctionExpression');\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/codemod/helpers/csf-factories-utils.ts",
    "content": "import { types as t, traverse } from 'storybook/internal/babel';\n\nconst projectAnnotationNames = [\n  'decorators',\n  'parameters',\n  'args',\n  'argTypes',\n  'loaders',\n  'beforeEach',\n  'afterEach',\n  'render',\n  'tags',\n  'mount',\n  'argsEnhancers',\n  'argTypesEnhancers',\n  'beforeAll',\n  'initialGlobals',\n  'globalTypes',\n  'applyDecorators',\n  'runStep',\n];\n\nexport function cleanupTypeImports(programNode: t.Program, disallowList: string[]) {\n  const usedIdentifiers = new Set<string>();\n\n  try {\n    // Collect all identifiers used in the program\n    traverse(programNode, {\n      Identifier(path) {\n        // Ensure we're not counting identifiers within import declarations\n        if (!path.findParent((p) => p.isImportDeclaration())) {\n          usedIdentifiers.add(path.node.name);\n        }\n      },\n      noScope: true,\n    });\n  } catch (err) {\n    // traversing could fail if the code isn't supported by\n    // our babel parse plugins, so we ignore\n  }\n\n  return programNode.body.filter((node) => {\n    if (t.isImportDeclaration(node)) {\n      const { source, specifiers } = node;\n\n      if (source.value.startsWith('@storybook/')) {\n        const allowedSpecifiers = specifiers.filter((specifier) => {\n          if (t.isImportSpecifier(specifier) && t.isIdentifier(specifier.imported)) {\n            const name = specifier.imported.name;\n            // Only remove if disallowed AND unused\n            return !disallowList.includes(name) || usedIdentifiers.has(name);\n          }\n          // Retain namespace imports and non-specifiers\n          return true;\n        });\n\n        // Remove the entire import if no valid specifiers remain\n        if (allowedSpecifiers.length > 0) {\n          node.specifiers = allowedSpecifiers;\n          return true;\n        }\n        return false;\n      }\n    }\n\n    // Retain all other nodes\n    return true;\n    // @TODO adding any for now, unsure how to fix the following error:\n    // error TS4058: Return type of exported function has or is using name 'BlockStatement' from external module \"/code/core/dist/babel/index\" but cannot be named\n  }) as any;\n}\n\nexport function removeExportDeclarations(\n  programNode: t.Program,\n  exportDecls: Record<string, t.VariableDeclarator | t.FunctionDeclaration>\n) {\n  return programNode.body.filter((node) => {\n    if (t.isExportNamedDeclaration(node) && node.declaration) {\n      if (t.isVariableDeclaration(node.declaration)) {\n        // Handle variable declarations\n        node.declaration.declarations = node.declaration.declarations.filter(\n          (decl) => t.isIdentifier(decl.id) && !exportDecls[decl.id.name]\n        );\n        return node.declaration.declarations.length > 0;\n      } else if (t.isFunctionDeclaration(node.declaration)) {\n        // Handle function declarations\n        const funcDecl = node.declaration;\n        return t.isIdentifier(funcDecl.id) && !exportDecls[funcDecl.id.name];\n      }\n    }\n    return true;\n    // @TODO adding any for now, unsure how to fix the following error:\n    // error TS4058: Return type of exported function has or is using name 'ObjectProperty' from external module \"/tmp/storybook/code/core/dist/babel/index\" but cannot be named.\n  }) as any;\n}\n\nexport function getConfigProperties(\n  exportDecls: Record<string, t.VariableDeclarator | t.FunctionDeclaration>,\n  options: { configType: 'main' | 'preview' }\n) {\n  const properties = [];\n\n  // Collect properties from named exports\n  for (const [name, decl] of Object.entries(exportDecls)) {\n    // only include real preview exports to definePreview factory\n    if (options.configType === 'preview' && !projectAnnotationNames.includes(name)) {\n      continue;\n    }\n    if (t.isVariableDeclarator(decl) && decl.init) {\n      properties.push(t.objectProperty(t.identifier(name), decl.init));\n    } else if (t.isFunctionDeclaration(decl)) {\n      properties.push(\n        t.objectProperty(t.identifier(name), t.arrowFunctionExpression([], decl.body))\n      );\n    }\n  }\n\n  // @TODO adding any for now, unsure how to fix the following error:\n  // error TS4058: Return type of exported function has or is using name 'ObjectProperty' from external module \"/tmp/storybook/code/core/dist/babel/index\" but cannot be named.\n  return properties as any;\n}\n\n/**\n * Adds an import declaration to the beginning of the program while preserving any leading comments\n * (like license headers or @ts-check directives).\n *\n * When using `programNode.body.unshift()`, the import would be placed before any leading comments\n * attached to the first node. This function transfers those comments to the new import so they\n * remain at the top of the file.\n *\n * Note: We use the `comments` property (used by recast for printing) rather than `leadingComments`\n * (used by babel internally) to ensure proper output formatting.\n */\nexport function addImportToTop(programNode: t.Program, importDecl: t.ImportDeclaration): void {\n  const firstNode = programNode.body[0] as t.Node & { comments?: t.Comment[] };\n\n  if (firstNode && firstNode.leadingComments && firstNode.leadingComments.length > 0) {\n    // Transfer leading comments from the first node to the import using 'comments' property\n    // which is what recast uses for printing (not 'leadingComments')\n    (importDecl as t.Node & { comments?: t.Comment[] }).comments = firstNode.leadingComments;\n    // Clear comments from the original first node to avoid duplication\n    firstNode.leadingComments = [];\n    firstNode.comments = [];\n  }\n\n  programNode.body.unshift(importDecl);\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/codemod/helpers/remove-unused-types.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { loadCsf, printCsf } from 'storybook/internal/csf-tools';\n\nimport { dedent } from 'ts-dedent';\n\nimport { getDiff } from '../../../../../core/src/core-server/utils/save-story/getDiff.ts';\nimport { removeUnusedTypes } from './remove-unused-types.ts';\n\nexpect.addSnapshotSerializer({\n  serialize: (val: any) => (typeof val === 'string' ? val : val.toString()),\n  test: () => true,\n});\n\nconst unescape = (str: string) => str.replace(/\\r\\n/g, '\\n');\n\ndescribe('removeUnusedTypes', () => {\n  const getTransformed = (source: string) => {\n    const csf = loadCsf(source, { makeTitle: () => 'FIXME' }).parse();\n    removeUnusedTypes(csf._ast.program, csf._ast);\n    return printCsf(csf).code;\n  };\n\n  it('should remove unused Storybook types', async () => {\n    const source = dedent`\n      import { Button } from './Button';\n      import { StoryFn, StoryObj } from '@storybook/react';\n      import type { Meta, MetaObj } from '@storybook/react';\n      import { type ComponentStory, type ComponentMeta } from '@storybook/react';\n\n      // unused types that should be removed\n      type UnusedAlias = Meta<typeof Button>;\n      type UnusedAlias2 = StoryObj<typeof Button>;\n      type UnusedAlias3 = ComponentStory<typeof Button>;\n      type UnusedAlias4 = ComponentMeta<typeof Button>;\n      type UnusedDeepType = {\n        foo: {\n          bar: {\n            story: StoryObj<typeof Button>;\n          }\n        }\n      };\n      interface UnusedInterface extends Meta {}\n      interface UnusedDeepInterface {\n        baz: {\n          qux: {\n            meta: Meta<typeof Button>;\n          }\n        }\n      };\n\n      export default { component: Button };\n    `;\n\n    const transformed = getTransformed(source);\n    expect(getDiff(unescape(source), unescape(transformed))).toMatchInlineSnapshot(`\n      import { Button } from './Button';\n        \n      - import { StoryFn, StoryObj } from '@storybook/react';\n      - import type { Meta, MetaObj } from '@storybook/react';\n      - import { type ComponentStory, type ComponentMeta } from '@storybook/react';\n      - \n        \n        \n      - // unused types that should be removed\n      - type UnusedAlias = Meta<typeof Button>;\n      - type UnusedAlias2 = StoryObj<typeof Button>;\n      - type UnusedAlias3 = ComponentStory<typeof Button>;\n      - type UnusedAlias4 = ComponentMeta<typeof Button>;\n      - type UnusedDeepType = {\n      -   foo: {\n      -     bar: {\n      -       story: StoryObj<typeof Button>;\n      -     }\n      -   }\n      - };\n      - interface UnusedInterface extends Meta {}\n      - interface UnusedDeepInterface {\n      -   baz: {\n      -     qux: {\n      -       meta: Meta<typeof Button>;\n      -     }\n      -   }\n      - };\n      - \n      - \n        export default { component: Button };\n    `);\n  });\n\n  it('should not remove used Storybook types', async () => {\n    const source = dedent`\n      // Nothing in this file should be removed or modified\n      import { StoryFn, StoryObj, ComponentStory, Meta, MetaObj, ComponentMeta } from '@storybook/react';\n      import { Button } from './Button';\n\n      type Alias = StoryFn<typeof Button>;\n      type Alias2 = Alias & { b: string };\n      type Story = StoryObj & { a: string };\n      type DeepType = {\n        foo: {\n          bar: {\n            story: ComponentStory<typeof Button>;\n          }\n        }\n      };\n      interface Interface extends Meta {}\n      interface DeepInterface {\n        baz: {\n          qux: {\n            meta: MetaObj<typeof Button>;\n          }\n        }\n      };\n      const X: ComponentMeta = {}\n\n      function foo(a: Story, c: DeepType, d: Interface, e: DeepInterface){}\n\n      export default {};\n    `;\n\n    const transformed = getTransformed(source);\n\n    expect(unescape(transformed)).toEqual(unescape(source));\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/codemod/helpers/remove-unused-types.ts",
    "content": "import { types as t, traverse } from 'storybook/internal/babel';\n\nimport { cleanupTypeImports } from './csf-factories-utils.ts';\n\n// Name of types that should be removed from the import list\nconst typesDisallowList = [\n  'Story',\n  'StoryFn',\n  'StoryObj',\n  'Meta',\n  'MetaObj',\n  'ComponentStory',\n  'ComponentMeta',\n];\n\nconst disallowedTypesSet = new Set(typesDisallowList);\n\n/**\n * Remove unused Storybook-specific type aliases from the program.\n *\n * Conditions to remove a declared type/interface:\n *\n * - It is declared in the file,\n * - It is not referenced anywhere in the file,\n * - AND it (the declaration) references at least one Storybook type from typesDisallowList.\n *\n * This implementation performs a single traversal of `ast`. During traversal we:\n *\n * - Collect declared type names,\n * - Record references to declared types (including handling references that appear before\n *   declarations),\n * - Detect per-declaration whether it references any disallowed Storybook type, and then perform a\n *   single filter pass on program.body.\n */\nexport function removeUnusedTypes(programNode: t.Program, ast: t.File): void {\n  // Declared type/interface names seen in this file\n  const declaredTypes = new Set<string>();\n\n  // Names of declared types that are referenced somewhere in the file\n  const referencedTypes = new Set<string>();\n\n  // Temporary: identifier names seen before we encountered their declaration\n  // This lets us count forward references (identifier appears before type is declared).\n  const pendingIdentifierNames = new Set<string>();\n\n  // Names of type declarations that (somewhere in their AST) reference a disallowed Storybook type\n  const typeDeclReferencesDisallowed = new Set<string>();\n\n  traverse(ast, {\n    enter(path) {\n      const node = path.node;\n\n      // 1) When we encounter a type/interface declaration, register it.\n      if (path.isTSTypeAliasDeclaration() || path.isTSInterfaceDeclaration()) {\n        // These always have an `id` property that's an Identifier\n        const idNode = (node as t.TSTypeAliasDeclaration | t.TSInterfaceDeclaration).id;\n        const name = idNode && t.isIdentifier(idNode) ? idNode.name : undefined;\n        if (name) {\n          declaredTypes.add(name);\n\n          // If we previously saw identifiers with this name before the declaration,\n          // count them now as references (handles reference-before-declaration).\n          if (pendingIdentifierNames.has(name)) {\n            referencedTypes.add(name);\n          }\n        }\n\n        // No need to traverse into the id itself here; we still want to traverse the\n        // declaration body so that disallowed-type references inside are detected\n        // by the TSTypeReference/TSExpressionWithTypeArguments handlers below.\n        return;\n      }\n\n      // 2) Track identifier references to declared types.\n      if (path.isIdentifier()) {\n        const identifierNode = node as t.Identifier;\n        const name = identifierNode.name;\n\n        // Skip the identifier that *is* the declaration id itself:\n        // parent is TSTypeAliasDeclaration or TSInterfaceDeclaration and its id is this node\n        const parentPath = path.parentPath;\n        if (\n          parentPath &&\n          (parentPath.isTSTypeAliasDeclaration() || parentPath.isTSInterfaceDeclaration())\n        ) {\n          const parentIdNode = (\n            parentPath.node as t.TSTypeAliasDeclaration | t.TSInterfaceDeclaration\n          ).id;\n          if (parentIdNode === node) {\n            return;\n          }\n        }\n\n        // If we've already seen the declaration, mark as referenced.\n        if (declaredTypes.has(name)) {\n          referencedTypes.add(name);\n        } else {\n          // Otherwise record as pending — if the declaration appears later, we'll promote it.\n          pendingIdentifierNames.add(name);\n        }\n\n        return;\n      }\n\n      // 3) Detect references to disallowed Storybook types inside type declarations.\n      // If we find one, record which type declaration (owner) contains it.\n      if (path.isTSTypeReference()) {\n        const typeRefNode = node as t.TSTypeReference;\n        const typeNameNode = typeRefNode.typeName;\n\n        if (t.isIdentifier(typeNameNode) && disallowedTypesSet.has(typeNameNode.name)) {\n          // Find the nearest enclosing type declaration (alias or interface)\n          const owner = path.findParent(\n            (p) => p.isTSTypeAliasDeclaration() || p.isTSInterfaceDeclaration()\n          );\n          if (owner && (owner.isTSTypeAliasDeclaration() || owner.isTSInterfaceDeclaration())) {\n            const ownerId = (owner.node as t.TSTypeAliasDeclaration | t.TSInterfaceDeclaration).id;\n            const ownerName = t.isIdentifier(ownerId) ? ownerId.name : undefined;\n            if (ownerName) {\n              typeDeclReferencesDisallowed.add(ownerName);\n            }\n          }\n        }\n\n        return;\n      }\n\n      if (path.isTSExpressionWithTypeArguments()) {\n        const tsExprNode = node as t.TSExpressionWithTypeArguments;\n        const expr = tsExprNode.expression;\n        if (t.isIdentifier(expr) && disallowedTypesSet.has(expr.name)) {\n          const owner = path.findParent(\n            (p) => p.isTSTypeAliasDeclaration() || p.isTSInterfaceDeclaration()\n          );\n          if (owner && (owner.isTSTypeAliasDeclaration() || owner.isTSInterfaceDeclaration())) {\n            const ownerId = (owner.node as t.TSTypeAliasDeclaration | t.TSInterfaceDeclaration).id;\n            const ownerName = t.isIdentifier(ownerId) ? ownerId.name : undefined;\n            if (ownerName) {\n              typeDeclReferencesDisallowed.add(ownerName);\n            }\n          }\n        }\n        return;\n      }\n    },\n  });\n\n  // Final pass: remove unused declared types that reference disallowed types\n  programNode.body = programNode.body.filter((node) => {\n    if (t.isTSTypeAliasDeclaration(node) || t.isTSInterfaceDeclaration(node)) {\n      const name = node.id.name;\n\n      // If it's a declared type, unused, and references a disallowed Storybook type — remove it.\n      if (\n        declaredTypes.has(name) &&\n        !referencedTypes.has(name) &&\n        typeDeclReferencesDisallowed.has(name)\n      ) {\n        return false; // filter out (remove)\n      }\n    }\n\n    return true; // keep everything else\n  });\n\n  // Cleanup any now-unused Storybook type imports (keeps original API: pass array)\n  programNode.body = cleanupTypeImports(programNode, typesDisallowList);\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { formatFileContent } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport path from 'path';\nimport { dedent } from 'ts-dedent';\n\nimport { storyToCsfFactory } from './story-to-csf-factory.ts';\n\nvi.mock('storybook/internal/node-logger', () => ({\n  logger: {\n    log: vi.fn(),\n    warn: vi.fn(),\n  },\n}));\n\nexpect.addSnapshotSerializer({\n  serialize: (val: any) => (typeof val === 'string' ? val : val.toString()),\n  test: () => true,\n});\n\ndescribe('stories codemod', () => {\n  const transform = async (source: string) =>\n    formatFileContent(\n      'Component.stories.tsx',\n      await storyToCsfFactory(\n        { source, path: 'Component.stories.tsx' },\n        { previewConfigPath: '#.storybook/preview', useSubPathImports: true }\n      )\n    );\n  describe('javascript', () => {\n    it('should wrap const declared meta', async () => {\n      await expect(\n        transform(dedent`\n            const meta = { title: 'Component' };\n            export default meta;\n            export const A = {};\n          `)\n      ).resolves.toMatchInlineSnapshot(`\n        import preview from \"#.storybook/preview\";\n        const meta = preview.meta({ title: \"Component\" });\n        export const A = meta.story();\n      `);\n    });\n\n    it('should preserve leading comments when adding import', async () => {\n      await expect(\n        transform(dedent`\n            // @ts-check\n            /**\n             * @license MIT\n             * Copyright 2024\n             */\n            const meta = { title: 'Component' };\n            export default meta;\n            export const A = {};\n          `)\n      ).resolves.toMatchInlineSnapshot(`\n        // @ts-check\n        /**\n         * @license MIT\n         * Copyright 2024\n         */\n        import preview from \"#.storybook/preview\";\n\n        const meta = preview.meta({ title: \"Component\" });\n        export const A = meta.story();\n      `);\n    });\n\n    it('should transform and wrap inline default exported meta', async () => {\n      await expect(\n        transform(dedent`\n            export default { title: 'Component' };\n            export const A = {};\n          `)\n      ).resolves.toMatchInlineSnapshot(`\n        import preview from \"#.storybook/preview\";\n\n        const meta = preview.meta({\n          title: \"Component\",\n        });\n\n        export const A = meta.story();\n      `);\n    });\n\n    it('should keep the original meta variable name', async () => {\n      await expect(\n        transform(dedent`\n            const componentMeta = { title: 'Component' };\n            export default componentMeta;\n            export const A = {};\n          `)\n      ).resolves.toMatchInlineSnapshot(`\n        import preview from \"#.storybook/preview\";\n        const componentMeta = preview.meta({ title: \"Component\" });\n        export const A = componentMeta.story();\n      `);\n    });\n\n    it('should wrap stories in a meta.story method', async () => {\n      await expect(\n        transform(dedent`\n            const componentMeta = { title: 'Component' };\n            export default componentMeta;\n            export const A = {\n              args: { primary: true },\n              render: (args) => <Component {...args} />\n            };\n          `)\n      ).resolves.toMatchInlineSnapshot(`\n        import preview from \"#.storybook/preview\";\n        const componentMeta = preview.meta({ title: \"Component\" });\n        export const A = componentMeta.story({\n          args: { primary: true },\n          render: (args) => <Component {...args} />,\n        });\n      `);\n    });\n\n    it('should respect existing config imports', async () => {\n      await expect(\n        transform(dedent`\n            import { decorators } from \"#.storybook/preview\";\n            const componentMeta = { title: 'Component' };\n            export default componentMeta;\n            export const A = {\n              args: { primary: true },\n              render: (args) => <Component {...args} />\n            };\n          `)\n      ).resolves.toMatchInlineSnapshot(`\n        import preview, { decorators } from \"#.storybook/preview\";\n        const componentMeta = preview.meta({ title: \"Component\" });\n        export const A = componentMeta.story({\n          args: { primary: true },\n          render: (args) => <Component {...args} />,\n        });\n      `);\n    });\n\n    it('should reuse existing default config import name', async () => {\n      await expect(\n        transform(dedent`\n            import previewConfig from \"#.storybook/preview\";\n            const componentMeta = { title: 'Component' };\n            export default componentMeta;\n            export const A = {\n              args: { primary: true },\n              render: (args) => <Component {...args} />\n            };\n          `)\n      ).resolves.toMatchInlineSnapshot(`\n        import previewConfig from \"#.storybook/preview\";\n        const componentMeta = previewConfig.meta({ title: \"Component\" });\n        export const A = componentMeta.story({\n          args: { primary: true },\n          render: (args) => <Component {...args} />,\n        });\n      `);\n    });\n\n    it('if there is an existing local constant called preview, rename storybook preview import', async () => {\n      await expect(\n        transform(dedent`\n            const componentMeta = { title: 'Component' };\n            export default componentMeta;\n            const preview = {};\n            export const A = {\n              args: { primary: true },\n              render: (args) => <Component {...args} />\n            };\n          `)\n      ).resolves.toMatchInlineSnapshot(`\n        import storybookPreview from \"#.storybook/preview\";\n        const componentMeta = storybookPreview.meta({ title: \"Component\" });\n        const preview = {};\n        export const A = componentMeta.story({\n          args: { primary: true },\n          render: (args) => <Component {...args} />,\n        });\n      `);\n    });\n\n    it('migrate reused properties of other stories from `Story.xyz` to `Story.input.xyz`', async () => {\n      await expect(\n        transform(dedent`\n            export default { title: 'Component' };\n            const someData = {};\n\n            export const A = {};\n            \n            export const B = {\n              ...A,\n              args: {\n                ...A.args,\n                ...someData,\n              },\n            };\n            export const C = {\n              render: async () => {\n                return JSON.stringify({\n                  ...A.argTypes,\n                  ...B,\n                })\n              }\n            };\n          `)\n      ).resolves.toMatchInlineSnapshot(`\n        import preview from \"#.storybook/preview\";\n\n        const meta = preview.meta({\n          title: \"Component\",\n        });\n\n        const someData = {};\n\n        export const A = meta.story();\n\n        export const B = meta.story({\n          ...A.input,\n          args: {\n            ...A.input.args,\n            ...someData,\n          },\n        });\n        export const C = meta.story({\n          render: async () => {\n            return JSON.stringify({\n              ...A.input.argTypes,\n              ...B.input,\n            });\n          },\n        });\n      `);\n    });\n\n    it('migrate reused properties of meta from `meta.xyz` to `meta.input.xyz`', async () => {\n      await expect(\n        transform(dedent`\n            const myMeta = { title: 'Component', args: {} };\n            export default myMeta;\n\n            const metaProperties = {\n              ...myMeta,\n            }\n\n            export const A = {\n              args: myMeta.args,\n            };\n            \n            export const B = {\n              args: {\n                ...myMeta.args,\n                ...metaProperties.args,\n              },\n            };\n            export const C = {\n              render: async () => {\n                return JSON.stringify({\n                  ...myMeta.argTypes,\n                })\n              }\n            };\n          `)\n      ).resolves.toMatchInlineSnapshot(`\n        import preview from \"#.storybook/preview\";\n        const myMeta = preview.meta({ title: \"Component\", args: {} });\n\n        const metaProperties = {\n          ...myMeta.input,\n        };\n\n        export const A = myMeta.story({\n          args: myMeta.input.args,\n        });\n\n        export const B = myMeta.story({\n          args: {\n            ...myMeta.input.args,\n            ...metaProperties.args,\n          },\n        });\n        export const C = myMeta.story({\n          render: async () => {\n            return JSON.stringify({\n              ...myMeta.input.argTypes,\n            });\n          },\n        });\n      `);\n    });\n\n    it('migrate cross-file story imports from `ImportedStories.Story.xyz` to `ImportedStories.Story.input.xyz`', async () => {\n      await expect(\n        transform(dedent`\n            import * as BaseStories from './Button.stories';\n            import { Primary as ImportedPrimary } from './Card.stories';\n\n            export default { title: 'Component' };\n\n            export const A = {\n              args: BaseStories.Primary.args,\n            };\n\n            export const B = {\n              ...BaseStories.Secondary,\n              args: {\n                ...BaseStories.Secondary.args,\n                label: 'Custom',\n              },\n            };\n\n            export const C = {\n              args: {\n                ...ImportedPrimary.args,\n              },\n            };\n          `)\n      ).resolves.toMatchInlineSnapshot(`\n        import preview from \"#.storybook/preview\";\n        import * as BaseStories from \"./Button.stories\";\n        import { Primary as ImportedPrimary } from \"./Card.stories\";\n\n        const meta = preview.meta({\n          title: \"Component\",\n        });\n\n        export const A = meta.story({\n          args: BaseStories.Primary.input.args,\n        });\n\n        export const B = meta.story({\n          ...BaseStories.Secondary.input,\n          args: {\n            ...BaseStories.Secondary.input.args,\n            label: \"Custom\",\n          },\n        });\n\n        export const C = meta.story({\n          args: {\n            ...ImportedPrimary.input.args,\n          },\n        });\n      `);\n    });\n\n    it('does not migrate reused properties from disallowed list', async () => {\n      await expect(\n        transform(dedent`\n            export default { title: 'Component' };\n            export const A = {};\n            export const B = {\n              play: async () => {\n                await A.play();\n              }\n            };\n            export const C = A.run;\n            export const D = A.extends({});\n          `)\n      ).resolves.toMatchInlineSnapshot(`\n        export default { title: \"Component\" };\n        export const A = {};\n        export const B = {\n          play: async () => {\n            await A.play();\n          },\n        };\n        export const C = A.run;\n        export const D = A.extends({});\n      `);\n    });\n\n    it.todo('should support non-conventional formats', async () => {\n      const transformed = await transform(dedent`\n        import { A as Component } from './Button';\n        import * as Stories from './Other.stories';\n        import someData from './fixtures'\n        export default { \n          component: Component, \n          // not supported yet (story coming from another file)\n          args: Stories.A.args\n        };\n        const data = {};\n        export const A = () => {};\n        export function B() { };\n        // not supported yet (story redeclared)\n        const C = { ...A, args: data, };\n        const D = { args: data };\n        export { C, D as E };\n        `);\n\n      expect(transformed).toMatchInlineSnapshot(`\n        import { A as Component } from './Button';\n        import * as Stories from './Other.stories';\n        import someData from './fixtures';\n\n        export default {\n          component: Component,\n          // not supported yet (story coming from another file)\n          args: Stories.A.args,\n        };\n        const data = {};\n        export const A = () => {};\n        export function B() {}\n        // not supported yet (story redeclared)\n        const C = { ...A, args: data };\n        const D = { args: data };\n        export { C, D as E };\n      `);\n\n      expect(transformed).toContain('A = meta.story');\n      expect(transformed).toContain('B = meta.story');\n      // @TODO: when we support these, uncomment this line\n      // expect(transformed).toContain('C = meta.story');\n    });\n\n    it('converts the preview import path based on useSubPathImports flag', async () => {\n      const relativeMock = vi.spyOn(path, 'relative').mockReturnValue('../../preview.ts');\n\n      try {\n        await expect(\n          formatFileContent(\n            'Component.stories.tsx',\n            await storyToCsfFactory(\n              {\n                source: dedent`\n                  import preview, { extra } from '../../../.storybook/preview';\n                  export default {};\n                  export const A = {};\n                `,\n                path: 'Component.stories.tsx',\n              },\n              { previewConfigPath: '#.storybook/preview', useSubPathImports: true }\n            )\n          )\n        ).resolves.toMatchInlineSnapshot(`\n          import preview, { extra } from \"#.storybook/preview\";\n          const meta = preview.meta({});\n          export const A = meta.story();\n        `);\n\n        await expect(\n          formatFileContent(\n            'Component.stories.tsx',\n            await storyToCsfFactory(\n              {\n                source: dedent`\n                  import preview, { extra } from '#.storybook/preview';\n                  export default {};\n                  export const A = {};\n                `,\n                path: 'Component.stories.tsx',\n              },\n              { previewConfigPath: '#.storybook/preview', useSubPathImports: false }\n            )\n          )\n        ).resolves.toMatchInlineSnapshot(`\n          import preview, { extra } from \"../../preview\";\n          const meta = preview.meta({});\n          export const A = meta.story();\n        `);\n      } finally {\n        relativeMock.mockRestore();\n      }\n    });\n\n    it('converts CSF1 into CSF4 with render', async () => {\n      await expect(\n        transform(dedent`\n            const meta = { title: 'Component' };\n            export default meta;\n            export const CSF1Story = () => <div>Hello</div>;\n          `)\n      ).resolves.toMatchInlineSnapshot(`\n        import preview from \"#.storybook/preview\";\n        const meta = preview.meta({ title: \"Component\" });\n        export const CSF1Story = meta.story(() => <div>Hello</div>);\n      `);\n    });\n  });\n\n  describe('typescript', () => {\n    const inlineMetaSatisfies = dedent`\n        import { Meta, StoryObj as CSF3 } from '@storybook/react';\n        import { ComponentProps } from './Component';\n  \n        export default { title: 'Component', component: Component } satisfies Meta<ComponentProps>;\n  \n        export const A: CSF3<ComponentProps> = {\n          args: { primary: true }\n        };\n      `;\n    it('meta satisfies syntax', async () => {\n      await expect(transform(inlineMetaSatisfies)).resolves.toMatchInlineSnapshot(`\n        import preview from \"#.storybook/preview\";\n        import { ComponentProps } from \"./Component\";\n\n        const meta = preview.meta({ title: \"Component\", component: Component });\n\n        export const A = meta.story({\n          args: { primary: true },\n        });\n      `);\n    });\n\n    const inlineMetaAs = dedent`\n        import { Meta, StoryObj as CSF3 } from '@storybook/react';\n        import { ComponentProps } from './Component';\n  \n        export default { title: 'Component', component: Component } as Meta<ComponentProps>;\n  \n        export const A: CSF3<ComponentProps> = {\n          args: { primary: true }\n        };\n      `;\n    it('meta as syntax', async () => {\n      await expect(transform(inlineMetaAs)).resolves.toMatchInlineSnapshot(`\n        import preview from \"#.storybook/preview\";\n        import { ComponentProps } from \"./Component\";\n\n        const meta = preview.meta({ title: \"Component\", component: Component });\n\n        export const A = meta.story({\n          args: { primary: true },\n        });\n      `);\n    });\n    const metaSatisfies = dedent`\n        import { Meta, StoryObj as CSF3 } from '@storybook/react';\n        import { ComponentProps } from './Component';\n  \n        const meta = { title: 'Component', component: Component } satisfies Meta<ComponentProps>\n        export default meta;\n  \n        export const A: CSF3<ComponentProps> = {\n          args: { primary: true }\n        };\n      `;\n    it('meta satisfies syntax', async () => {\n      await expect(transform(metaSatisfies)).resolves.toMatchInlineSnapshot(`\n        import preview from \"#.storybook/preview\";\n        import { ComponentProps } from \"./Component\";\n\n        const meta = preview.meta({ title: \"Component\", component: Component });\n\n        export const A = meta.story({\n          args: { primary: true },\n        });\n      `);\n    });\n\n    const metaTypeDef = dedent`\n        import { Meta, StoryObj as CSF3 } from '@storybook/react';\n        import { ComponentProps } from './Component';\n  \n        const meta: Meta<ComponentProps> = { title: 'Component', component: Component }\n        export default meta;\n  \n        export const A: CSF3<ComponentProps> = {\n          args: { primary: true }\n        };\n      `;\n    it('meta type syntax', async () => {\n      await expect(transform(metaTypeDef)).resolves.toMatchInlineSnapshot(`\n        import preview from \"#.storybook/preview\";\n        import { ComponentProps } from \"./Component\";\n\n        const meta = preview.meta({ title: \"Component\", component: Component });\n\n        export const A = meta.story({\n          args: { primary: true },\n        });\n      `);\n    });\n\n    const metaAs = dedent`\n        import { Meta, StoryObj as CSF3 } from '@storybook/react';\n        import { ComponentProps } from './Component';\n  \n        const meta = { title: 'Component', component: Component } as Meta<ComponentProps>\n        export default meta;\n  \n        export const A: CSF3<ComponentProps> = {\n          args: { primary: true }\n        };\n      `;\n    it('meta as syntax', async () => {\n      await expect(transform(metaAs)).resolves.toMatchInlineSnapshot(`\n        import preview from \"#.storybook/preview\";\n        import { ComponentProps } from \"./Component\";\n\n        const meta = preview.meta({ title: \"Component\", component: Component });\n\n        export const A = meta.story({\n          args: { primary: true },\n        });\n      `);\n    });\n\n    const storySatisfies = dedent`\n        import { Meta, StoryObj as CSF3 } from '@storybook/react';\n        import { ComponentProps } from './Component';\n  \n        const meta = { title: 'Component', component: Component } as Meta<ComponentProps>\n        export default meta;\n  \n        export const A = {\n          args: { primary: true }\n        } satisfies CSF3<ComponentProps>;\n      `;\n    it('story satisfies syntax', async () => {\n      await expect(transform(storySatisfies)).resolves.toMatchInlineSnapshot(`\n        import preview from \"#.storybook/preview\";\n        import { ComponentProps } from \"./Component\";\n\n        const meta = preview.meta({ title: \"Component\", component: Component });\n\n        export const A = meta.story({\n          args: { primary: true },\n        });\n      `);\n    });\n\n    const storyAs = dedent`\n        import { Meta, StoryObj as CSF3 } from '@storybook/react';\n        import { ComponentProps } from './Component';\n  \n        const meta = { title: 'Component', component: Component } as Meta<ComponentProps>\n        export default meta;\n  \n        export const A = {\n          args: { primary: true }\n        } as CSF3<ComponentProps>;\n      `;\n    it('story as syntax', async () => {\n      await expect(transform(storyAs)).resolves.toMatchInlineSnapshot(`\n        import preview from \"#.storybook/preview\";\n        import { ComponentProps } from \"./Component\";\n\n        const meta = preview.meta({ title: \"Component\", component: Component });\n\n        export const A = meta.story({\n          args: { primary: true },\n        });\n      `);\n    });\n\n    it('should yield the same result to all syntaxes', async () => {\n      const allSnippets = await Promise.all([\n        transform(inlineMetaSatisfies),\n        transform(inlineMetaAs),\n        transform(metaSatisfies),\n        transform(metaAs),\n        transform(storySatisfies),\n        transform(storyAs),\n      ]);\n\n      allSnippets.forEach((result) => {\n        expect(result).toEqual(allSnippets[0]);\n      });\n    });\n\n    it('should remove unused Story types', async () => {\n      await expect(\n        transform(\n          `import { Meta, StoryObj as CSF3 } from '@storybook/react';\n        import { ComponentProps } from './Component';\n  \n        export default {};\n        type Story = StoryObj<typeof ComponentProps>;\n\n        export const A: Story = {};`\n        )\n      ).resolves.toMatchInlineSnapshot(`\n        import preview from \"#.storybook/preview\";\n        import { ComponentProps } from \"./Component\";\n\n        const meta = preview.meta({});\n\n        export const A = meta.story();\n      `);\n    });\n\n    it('should preserve user-defined generic types', async () => {\n      const result = await transform(dedent`\n        import { Meta, StoryObj } from '@storybook/react';\n        \n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        type Data = Record<string, any>;\n        interface UnusedButShouldNotBeRemoved { name: string };\n        type UnusedAndShouldBeRemoved = Meta;\n\n        export default { title: 'Table' };\n\n        export const A = {\n          render: () => {\n            const data: Data[] = [];\n            return <Table data={data} />;\n          }\n        };\n      `);\n\n      expect(result).toContain('UnusedButShouldNotBeRemoved');\n      expect(result).not.toContain('UnusedAndShouldBeRemoved');\n\n      expect(result).toMatchInlineSnapshot(`\n        import preview from \"#.storybook/preview\";\n\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        type Data = Record<string, any>;\n        interface UnusedButShouldNotBeRemoved {\n          name: string;\n        }\n\n        const meta = preview.meta({\n          title: \"Table\",\n        });\n\n        export const A = meta.story({\n          render: () => {\n            const data: Data[] = [];\n            return <Table data={data} />;\n          },\n        });\n      `);\n    });\n\n    it('should remove Storybook-specific type aliases but leave the ones that are actually used', async () => {\n      await expect(\n        transform(dedent`\n          import { Meta, StoryObj, ComponentStory, ComponentMeta } from '@storybook/react';\n          import { Button } from './Button';\n\n          type CustomMeta = Meta<typeof Button>;\n          type CustomStory = StoryObj<typeof Button>;\n          type LegacyStory = ComponentStory<typeof Button>;\n          type LegacyMeta = ComponentMeta<typeof Button>;\n          type ThisShouldNotBeRemoved = Meta<typeof Button>;\n          const something: ThisShouldNotBeRemoved = {};\n\n          export default { title: 'Button' };\n          export const A = {};\n        `)\n      ).resolves.toMatchInlineSnapshot(`\n        import preview from \"#.storybook/preview\";\n        import { Meta } from \"@storybook/react\";\n        import { Button } from \"./Button\";\n\n        type ThisShouldNotBeRemoved = Meta<typeof Button>;\n        const something: ThisShouldNotBeRemoved = {};\n\n        const meta = preview.meta({\n          title: \"Button\",\n        });\n\n        export const A = meta.story();\n      `);\n    });\n\n    it.todo('should support non-conventional formats', async () => {\n      const transformed = await transform(dedent`\n        import { Meta, StoryObj as CSF3 } from '@storybook/react';\n        import { ComponentProps } from './Component';\n        import { A as Component } from './Button';\n        import * as Stories from './Other.stories';\n        import someData from './fixtures'\n        export default {\n          title: 'Component',\n          component: Component, \n          // not supported yet (story coming from another file)\n          args: Stories.A.args\n        };\n        const data = {};\n        export const A: StoryObj = () => {};\n        export function B() { };\n        export const C = () => <Component />;\n        export const D = C;\n        // not supported yet (story redeclared)\n        const E = { ...A, args: data, } satisfies CSF3<ComponentProps>;\n        const F = { args: data };\n        export { E, F as G };\n        `);\n\n      expect(transformed).toMatchInlineSnapshot(`\n        import { StoryObj as CSF3, Meta } from '@storybook/react';\n\n        import { A as Component } from './Button';\n        import { ComponentProps } from './Component';\n        import * as Stories from './Other.stories';\n        import someData from './fixtures';\n\n        export default {\n          title: 'Component',\n          component: Component,\n          // not supported yet (story coming from another file)\n          args: Stories.A.args,\n        };\n        const data = {};\n        export const A: StoryObj = () => {};\n        export function B() {}\n        export const C = () => <Component />;\n        export const D = C;\n        // not supported yet (story redeclared)\n        const E = { ...A, args: data } satisfies CSF3<ComponentProps>;\n        const F = { args: data };\n        export { E, F as G };\n      `);\n\n      expect(transformed).toContain('A = meta.story');\n      expect(transformed).toContain('B = meta.story');\n      // @TODO: when we support these, uncomment this line\n      // expect(transformed).toContain('C = meta.story');\n    });\n\n    it('should bail transformation when no stories can be transformed', async () => {\n      const source = dedent`\n        export default {\n          title: 'Component',\n        };\n      `;\n      const transformed = await transform(source);\n      const formattedSource = await formatFileContent('Component.stories.tsx', source);\n      expect(transformed).toEqual(formattedSource);\n\n      expect(transformed).not.toContain('preview.meta');\n      expect(transformed).not.toContain('meta.story');\n\n      expect(vi.mocked(logger.warn).mock.calls[0][0]).toMatchInlineSnapshot(\n        `Skipping codemod for Component.stories.tsx: no stories were transformed. Either there are no stories, file has been already transformed or some stories are written in an unsupported format.`\n      );\n    });\n\n    it('should bail transformation and warn if some stories are not transformed to avoid mixed CSF formats', async () => {\n      const source = dedent`\n        export default {\n          title: 'Component',\n        };\n        export const A = {};\n        // not supported yet (story redeclared)\n        const B = { args: data };\n        const C = { args: data };\n        export { B, C as D };`;\n      const transformed = await transform(source);\n      const formattedSource = await formatFileContent('Component.stories.tsx', source);\n      expect(transformed).toEqual(formattedSource);\n\n      expect(transformed).not.toContain('preview.meta');\n      expect(transformed).not.toContain('meta.story');\n\n      expect(vi.mocked(logger.warn).mock.calls[0][0]).toMatchInlineSnapshot(`\n        Skipping codemod for Component.stories.tsx:\n        Some of the detected stories [\"A\", \"B\", \"D\"] would not be transformed because they are written in an unsupported format.\n      `);\n    });\n\n    it('should bail transformation and not warn when file is already transformed', async () => {\n      const source = dedent`\n        import preview from '#.storybook/preview';\n\n        const meta = preview.meta({ title: 'Component' });\n        export const A = meta.story();\n      `;\n      const transformed = await transform(source);\n      const formattedSource = await formatFileContent('Component.stories.tsx', source);\n      expect(transformed).toEqual(formattedSource);\n\n      expect(logger.log).not.toHaveBeenCalled();\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.ts",
    "content": "import { types as t, traverse } from 'storybook/internal/babel';\nimport { isValidPreviewPath, loadCsf, printCsf } from 'storybook/internal/csf-tools';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport path from 'path';\n\nimport type { FileInfo } from '../../automigrate/codemod.ts';\nimport { addImportToTop, cleanupTypeImports } from './csf-factories-utils.ts';\nimport { removeUnusedTypes } from './remove-unused-types.ts';\n\nconst typesDisallowList = [\n  'Story',\n  'StoryFn',\n  'StoryObj',\n  'Meta',\n  'MetaObj',\n  'ComponentStory',\n  'ComponentMeta',\n];\n\n// Name of properties that should not be renamed to `Story.input.xyz`\nconst reuseDisallowList = ['play', 'run', 'extends', 'story'];\n\ntype Options = { previewConfigPath: string; useSubPathImports: boolean };\n\nexport async function storyToCsfFactory(\n  info: FileInfo,\n  { previewConfigPath, useSubPathImports }: Options\n) {\n  const csf = loadCsf(info.source, { makeTitle: () => 'FIXME' });\n  try {\n    csf.parse();\n  } catch (err) {\n    logger.log(`Error when parsing ${info.path}, skipping:\\n${err}`);\n    return info.source;\n  }\n\n  // Track detected stories and which ones we actually transform\n  const detectedStories = csf.stories;\n  const detectedStoryNames = detectedStories.map((story) => story.name);\n  const transformedStoryExports = new Set<string>();\n\n  const metaVariableName = csf._metaVariableName ?? 'meta';\n\n  /**\n   * Add the preview import if it doesn't exist yet:\n   *\n   * `import preview from '#.storybook/preview'`;\n   */\n  const programNode = csf._ast.program;\n  let previewImport: t.ImportDeclaration | undefined;\n\n  // Check if a root-level constant named 'preview' exists\n  const hasRootLevelConfig = programNode.body.some(\n    (n) =>\n      t.isVariableDeclaration(n) &&\n      n.declarations.some((declaration) => t.isIdentifier(declaration.id, { name: 'preview' }))\n  );\n\n  let previewPath = '#.storybook/preview';\n  if (!useSubPathImports) {\n    // calculate relative path from story file to preview file\n    const relativePath = path.relative(path.dirname(info.path), previewConfigPath);\n    const { dir, name } = path.parse(relativePath);\n\n    // Construct the path manually and replace Windows backslashes\n    previewPath = `${dir ? `${dir}/` : ''}${name}`;\n\n    // account for stories in the same path as preview file\n    if (!previewPath.startsWith('.')) {\n      previewPath = `./${previewPath}`;\n    }\n\n    // Convert Windows backslashes to forward slashes\n    previewPath = previewPath.replace(/\\\\/g, '/');\n  }\n\n  let sbConfigImportName = hasRootLevelConfig ? 'storybookPreview' : 'preview';\n\n  const sbConfigImportSpecifier = t.importDefaultSpecifier(t.identifier(sbConfigImportName));\n\n  /**\n   * Collect imports from other .stories files.\n   *\n   * When we see: import * as BaseStories from './Button.stories'; import { Primary } from\n   * './Card.stories';\n   *\n   * We store the local names (\"BaseStories\", \"Primary\") so we can later transform references like\n   * `BaseStories.Primary.args` → `BaseStories.Primary.input.args`\n   *\n   * Why? Because those imported stories will ALSO be transformed to CSF4, so their properties will\n   * be under `.input` instead of directly on the object.\n   *\n   * We track TWO types of imports:\n   *\n   * - Namespace imports (import * as X): X.Story.args → X.Story.input.args\n   * - Named imports (import { Story }): Story.args → Story.input.args\n   */\n  const namespaceStoryImports = new Set<string>(); // import * as X\n  const namedStoryImports = new Set<string>(); // import { X } or import X\n\n  programNode.body.forEach((node) => {\n    if (t.isImportDeclaration(node)) {\n      const importPath = node.source.value;\n\n      // Check if this import is from a .stories file\n      // Matches: ./Button.stories, ../components/Card.stories.tsx, etc.\n      const isStoryFileImport = /\\.stories(\\.(ts|tsx|js|jsx|mjs|mts))?$/.test(importPath);\n\n      if (isStoryFileImport) {\n        // Collect all imported names from this story file\n        node.specifiers.forEach((specifier) => {\n          if (t.isImportNamespaceSpecifier(specifier)) {\n            // import * as BaseStories from './Button.stories'\n            // BaseStories.Primary is a story, so we need: BaseStories.Primary.input\n            namespaceStoryImports.add(specifier.local.name);\n          } else if (t.isImportSpecifier(specifier)) {\n            // import { Primary } from './Button.stories'\n            // Primary itself is a story, so we need: Primary.input\n            namedStoryImports.add(specifier.local.name);\n          } else if (t.isImportDefaultSpecifier(specifier)) {\n            // import ButtonStories from './Button.stories'\n            // This typically imports the meta, not stories, so we treat it like namespace\n            namespaceStoryImports.add(specifier.local.name);\n          }\n        });\n      }\n    }\n\n    if (t.isImportDeclaration(node) && isValidPreviewPath(node.source.value)) {\n      const defaultImportSpecifier = node.specifiers.find((specifier) =>\n        t.isImportDefaultSpecifier(specifier)\n      );\n\n      if (!defaultImportSpecifier) {\n        node.specifiers.push(sbConfigImportSpecifier);\n      } else if (defaultImportSpecifier.local.name !== sbConfigImportName) {\n        sbConfigImportName = defaultImportSpecifier.local.name;\n      }\n\n      previewImport = node;\n    }\n  });\n\n  const hasMeta = !!csf._meta;\n\n  // Combined set for quick lookup\n  const storyFileImports = new Set([...namespaceStoryImports, ...namedStoryImports]);\n\n  // @TODO: Support unconventional formats:\n  // `export function Story() { };` and `export { Story };\n  // These are not part of csf._storyExports but rather csf._storyStatements and are tricky to support.\n  Object.entries(csf._storyExports).forEach(([exportName, decl]) => {\n    const id = decl.id;\n    const declarator = decl as t.VariableDeclarator;\n    let init = t.isVariableDeclarator(declarator) ? declarator.init : undefined;\n\n    if (t.isIdentifier(id) && init) {\n      // Remove type annotations e.g. A<B> in `const Story: A<B> = {};`\n      if (id.typeAnnotation) {\n        id.typeAnnotation = null;\n      }\n\n      // Remove type annotations e.g. A<B> in `const Story = {} satisfies A<B>;`\n      if (t.isTSSatisfiesExpression(init) || t.isTSAsExpression(init)) {\n        init = init.expression;\n      }\n\n      if (t.isObjectExpression(init)) {\n        // Wrap the object in `meta.story()`\n\n        declarator.init = t.callExpression(\n          t.memberExpression(t.identifier(metaVariableName), t.identifier('story')),\n          init.properties.length === 0 ? [] : [init]\n        );\n        if (t.isIdentifier(id)) {\n          transformedStoryExports.add(exportName);\n        }\n      } else if (t.isArrowFunctionExpression(init)) {\n        // Transform CSF1 to meta.story({ render: <originalFn> })\n        declarator.init = t.callExpression(\n          t.memberExpression(t.identifier(metaVariableName), t.identifier('story')),\n          [init]\n        );\n        if (t.isIdentifier(id)) {\n          transformedStoryExports.add(exportName);\n        }\n      }\n    }\n  });\n\n  // Support function-declared stories\n  Object.entries(csf._storyExports).forEach(([exportName, decl]) => {\n    if (t.isFunctionDeclaration(decl) && decl.id) {\n      const arrowFn = t.arrowFunctionExpression(decl.params, decl.body);\n      arrowFn.async = !!decl.async;\n\n      const wrappedCall = t.callExpression(\n        t.memberExpression(t.identifier(metaVariableName), t.identifier('story')),\n        [arrowFn]\n      );\n\n      const replacement = t.exportNamedDeclaration(\n        t.variableDeclaration('const', [\n          t.variableDeclarator(t.identifier(exportName), wrappedCall),\n        ])\n      );\n\n      const pathForExport = (\n        csf as unknown as {\n          _storyPaths?: Record<string, { replaceWith?: (node: t.Node) => void }>;\n        }\n      )._storyPaths?.[exportName];\n      if (pathForExport && pathForExport.replaceWith) {\n        pathForExport.replaceWith(replacement);\n        transformedStoryExports.add(exportName);\n      }\n    }\n  });\n\n  const storyExportDecls = new Map(\n    Object.entries(csf._storyExports).filter(\n      (\n        entry\n      ): entry is [string, Exclude<(typeof csf._storyExports)[string], t.FunctionDeclaration>] =>\n        !t.isFunctionDeclaration(entry[1])\n    )\n  );\n\n  // For each story, replace any reference of story reuse e.g.\n  // Story.args -> Story.input.args\n  // meta.args -> meta.input.args\n  // BaseStories.Primary.args -> BaseStories.Primary.input.args (cross-file)\n  traverse(csf._ast, {\n    /**\n     * Handle SAME-FILE story references.\n     *\n     * Examples: Primary.args → Primary.input.args meta.args → meta.input.args\n     */\n    Identifier(nodePath) {\n      const identifierName = nodePath.node.name;\n      const binding = nodePath.scope.getBinding(identifierName);\n\n      // Check if the identifier corresponds to a story export or the meta variable\n      const isStoryExport = binding && storyExportDecls.has(binding.identifier.name);\n      const isMetaVariable = identifierName === metaVariableName;\n\n      if (isStoryExport || isMetaVariable) {\n        const parent = nodePath.parent;\n\n        // Skip declarations (e.g., `const Story = {};`)\n        if (t.isVariableDeclarator(parent) && parent.id === nodePath.node) {\n          return;\n        }\n\n        // Skip import statements e.g.`import { X as Story }`\n        if (t.isImportSpecifier(parent)) {\n          return;\n        }\n\n        // Skip export statements e.g.`export const Story` or `export { Story }`\n        if (t.isExportSpecifier(parent) || t.isExportDefaultDeclaration(parent)) {\n          return;\n        }\n\n        // Skip if it's already `Story.input` or `meta.input`\n        if (t.isMemberExpression(parent) && t.isIdentifier(parent.property, { name: 'input' })) {\n          return;\n        }\n\n        // Check if the property name is in the disallow list\n        if (\n          t.isMemberExpression(parent) &&\n          t.isIdentifier(parent.property) &&\n          reuseDisallowList.includes(parent.property.name)\n        ) {\n          return;\n        }\n\n        try {\n          // Replace the identifier with `Story.input` or `meta.input`\n          nodePath.replaceWith(\n            t.memberExpression(t.identifier(identifierName), t.identifier('input'))\n          );\n        } catch (err: any) {\n          // This error occurs for cross-file references like `Stories.Story.args`\n          // which are handled by the MemberExpression visitor below.\n          if (err.message.includes(`instead got \"MemberExpression\"`)) {\n            return;\n          } else {\n            throw err;\n          }\n        }\n      }\n    },\n\n    /**\n     * Handle CROSS-FILE story references.\n     *\n     * When we import stories from another file: import * as BaseStories from './Button.stories';\n     *\n     * And use them like: BaseStories.Primary.args\n     *\n     * We need to transform to: BaseStories.Primary.input.args\n     *\n     * Why? Because the imported file will ALSO be transformed to CSF4, where story properties are\n     * accessed via `.input`.\n     */\n    MemberExpression(nodePath) {\n      const node = nodePath.node;\n\n      // We're looking for patterns like: BaseStories.Primary.args\n      // Which is: MemberExpression { object: MemberExpression { object: Identifier, property }, property }\n      //\n      // We want to find the inner MemberExpression (BaseStories.Primary)\n      // and check if its object (BaseStories) is from a story file import.\n\n      // Check if this is a nested member expression (e.g., BaseStories.Primary.args)\n      // We want to transform BaseStories.Primary → BaseStories.Primary.input\n      // So we look for MemberExpression where object is also a MemberExpression\n\n      const innerObject = node.object;\n\n      // Check if the object is a MemberExpression like BaseStories.Primary\n      if (t.isMemberExpression(innerObject)) {\n        const importName = innerObject.object; // BaseStories\n        const storyName = innerObject.property; // Primary\n        const accessedProperty = node.property; // args\n\n        // Verify: importName is an Identifier that's in our storyFileImports set\n        if (\n          t.isIdentifier(importName) &&\n          storyFileImports.has(importName.name) &&\n          t.isIdentifier(storyName)\n        ) {\n          // Skip if already transformed: BaseStories.Primary.input.args\n          // This check prevents infinite loops when the traverser revisits modified nodes\n          if (t.isIdentifier(storyName, { name: 'input' })) {\n            return;\n          }\n\n          // Only process if the accessed property is an Identifier\n          if (!t.isIdentifier(accessedProperty)) {\n            return;\n          }\n\n          // Skip if the current property being accessed is 'input'\n          // This means we're looking at something like: BaseStories.Primary.input\n          // which was already transformed in a previous iteration\n          if (accessedProperty.name === 'input') {\n            return;\n          }\n\n          // Skip if accessing a property in the disallow list\n          if (reuseDisallowList.includes(accessedProperty.name)) {\n            return;\n          }\n\n          // Transform: BaseStories.Primary.args → BaseStories.Primary.input.args\n          // We do this by replacing the inner object (BaseStories.Primary)\n          // with (BaseStories.Primary.input)\n          nodePath.node.object = t.memberExpression(innerObject, t.identifier('input'));\n\n          // Skip traversing into the newly created node to prevent infinite loops\n          nodePath.skip();\n        }\n      }\n\n      // Handle NAMED IMPORTS: import { Primary } from './Button.stories'\n      // Usage: Primary.args → Primary.input.args\n      //\n      // Pattern: MemberExpression { object: Identifier(\"Primary\"), property: Identifier(\"args\") }\n      // Where \"Primary\" is in our namedStoryImports set (NOT namespace imports)\n      if (t.isIdentifier(innerObject) && namedStoryImports.has(innerObject.name)) {\n        const accessedProperty = node.property;\n\n        // Only process if the property is an Identifier\n        if (!t.isIdentifier(accessedProperty)) {\n          return;\n        }\n\n        // Skip if this is already accessing .input\n        if (accessedProperty.name === 'input') {\n          return;\n        }\n\n        // Skip if accessing a property in the disallow list\n        if (reuseDisallowList.includes(accessedProperty.name)) {\n          return;\n        }\n\n        // Transform: Primary.args → Primary.input.args\n        nodePath.replaceWith(\n          t.memberExpression(\n            t.memberExpression(innerObject, t.identifier('input')),\n            accessedProperty\n          )\n        );\n        nodePath.skip();\n        return;\n      }\n\n      // Handle NAMESPACE IMPORTS spread: import * as BaseStories from './Button.stories'\n      // Usage: ...BaseStories.Secondary → ...BaseStories.Secondary.input\n      //\n      // Pattern: SpreadElement containing MemberExpression { object: Identifier(\"BaseStories\"), property: Identifier(\"Secondary\") }\n      if (t.isIdentifier(innerObject) && namespaceStoryImports.has(innerObject.name)) {\n        const storyName = node.property;\n\n        // Skip if this is already .input\n        if (t.isIdentifier(storyName, { name: 'input' })) {\n          return;\n        }\n\n        // Check if parent is a SpreadElement (...BaseStories.Secondary)\n        const parent = nodePath.parent;\n        if (t.isSpreadElement(parent)) {\n          // Transform: ...BaseStories.Secondary → ...BaseStories.Secondary.input\n          nodePath.replaceWith(t.memberExpression(node, t.identifier('input')));\n          nodePath.skip();\n        }\n        // Note: For non-spread namespace access like BaseStories.Primary.args,\n        // it's handled by the nested MemberExpression case above\n      }\n    },\n  });\n\n  // If no stories were transformed, bail early to avoid having a mixed CSF syntax and therefore a broken indexer.\n  if (transformedStoryExports.size === 0) {\n    logger.warn(\n      `Skipping codemod for ${info.path}: no stories were transformed. Either there are no stories, file has been already transformed or some stories are written in an unsupported format.`\n    );\n    return info.source;\n  }\n\n  // If some stories were detected but not all could be transformed, we skip the codemod to avoid mixed csf syntax and therefore a broken indexer.\n  if (detectedStoryNames.length > 0 && transformedStoryExports.size !== detectedStoryNames.length) {\n    logger.warn(\n      `Skipping codemod for ${info.path}:\\nSome of the detected stories [${detectedStoryNames\n        .map((name) => `\"${name}\"`)\n        .join(', ')}] would not be transformed because they are written in an unsupported format.`\n    );\n    return info.source;\n  }\n\n  // modify meta\n  if (csf._metaPath) {\n    let declaration = csf._metaPath.node.declaration;\n    if (t.isTSSatisfiesExpression(declaration) || t.isTSAsExpression(declaration)) {\n      declaration = declaration.expression;\n    }\n\n    if (t.isObjectExpression(declaration)) {\n      const metaVariable = t.variableDeclaration('const', [\n        t.variableDeclarator(\n          t.identifier(metaVariableName),\n          t.callExpression(\n            t.memberExpression(t.identifier(sbConfigImportName), t.identifier('meta')),\n            [declaration]\n          )\n        ),\n      ]);\n      csf._metaPath.replaceWith(metaVariable);\n    } else if (t.isIdentifier(declaration)) {\n      /**\n       * Transform const declared metas:\n       *\n       * `const meta = {}; export default meta;`\n       *\n       * Into a meta call:\n       *\n       * `const meta = preview.meta({ title: 'A' });`\n       */\n      const binding = csf._metaPath.scope.getBinding(declaration.name);\n      if (binding && binding.path.isVariableDeclarator()) {\n        const originalName = declaration.name;\n\n        // Always rename the meta variable to 'meta'\n        binding.path.node.id = t.identifier(metaVariableName);\n\n        let init = binding.path.node.init;\n        if (t.isTSSatisfiesExpression(init) || t.isTSAsExpression(init)) {\n          init = init.expression;\n        }\n        if (t.isObjectExpression(init)) {\n          binding.path.node.init = t.callExpression(\n            t.memberExpression(t.identifier(sbConfigImportName), t.identifier('meta')),\n            [init]\n          );\n        }\n\n        // Update all references to the original name\n        csf._metaPath.scope.rename(originalName, metaVariableName);\n      }\n\n      // Remove the default export, it's not needed anymore\n      csf._metaPath.remove();\n    }\n  }\n\n  if (previewImport) {\n    // If there is alerady an import, just update the path. This is useful for users\n    // who rerun the codemod to change the preview import to use (or not) subpaths\n    if (previewImport.source.value !== previewPath) {\n      previewImport.source = t.stringLiteral(previewPath);\n    }\n  } else if (hasMeta) {\n    // If the import doesn't exist, create a new one\n    const configImport = t.importDeclaration(\n      [t.importDefaultSpecifier(t.identifier(sbConfigImportName))],\n      t.stringLiteral(previewPath)\n    );\n    addImportToTop(programNode, configImport);\n  }\n\n  removeUnusedTypes(programNode, csf._ast);\n\n  return printCsf(csf).code;\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/doctor/getDuplicatedDepsWarnings.ts",
    "content": "import { frameworkPackages, rendererPackages } from 'storybook/internal/common';\nimport type { InstallationMetadata } from 'storybook/internal/common';\n\nimport picocolors from 'picocolors';\n\nimport { hasMultipleVersions } from './hasMultipleVersions.ts';\n\nexport const messageDivider = '\\n\\n';\n\n// These packages are aliased by Storybook, so it doesn't matter if they're duplicated\nexport const allowList = [\n  '@storybook/csf',\n  // see this file for more info: code/lib/preview/src/globals/types.ts\n  '@storybook/addons',\n  '@storybook/channel-postmessage',\n  '@storybook/channel-websocket',\n  '@storybook/client-api',\n  '@storybook/core-client',\n  '@storybook/preview-web',\n  '@storybook/store',\n\n  // see this file for more info: code/ui/manager/src/globals/types.ts\n  '@storybook/components',\n  '@storybook/router',\n  '@storybook/theming',\n  '@storybook/api',\n  '@storybook/manager-api',\n];\n\n// These packages definitely will cause issues if they're duplicated\nexport const disallowList = [\n  Object.keys(rendererPackages),\n  Object.keys(frameworkPackages),\n  'storybook',\n  '@storybook/instrumenter',\n  '@storybook/core-server',\n  '@storybook/manager',\n  '@storybook/preview',\n];\n\nexport function getDuplicatedDepsWarnings(\n  installationMetadata?: InstallationMetadata\n): string[] | undefined {\n  try {\n    if (\n      !installationMetadata ||\n      !installationMetadata?.duplicatedDependencies ||\n      Object.keys(installationMetadata.duplicatedDependencies).length === 0\n    ) {\n      return undefined;\n    }\n\n    const messages: string[] = [];\n\n    const { critical, trivial } = Object.entries(\n      installationMetadata?.duplicatedDependencies\n    ).reduce<{\n      critical: string[];\n      trivial: string[];\n    }>(\n      (acc, [dep, packageVersions]) => {\n        if (allowList.includes(dep)) {\n          return acc;\n        }\n\n        const hasMultipleMajorVersions = hasMultipleVersions(packageVersions);\n\n        if (disallowList.includes(dep) && hasMultipleMajorVersions) {\n          acc.critical.push(\n            `${picocolors.bold(picocolors.red(dep))}:\\n${packageVersions.join(', ')}`\n          );\n        } else {\n          acc.trivial.push(`${picocolors.yellow(dep)}:\\n${packageVersions.join(', ')}`);\n        }\n\n        return acc;\n      },\n      { critical: [], trivial: [] }\n    );\n\n    if (critical.length === 0 && trivial.length === 0) {\n      return messages;\n    }\n\n    if (critical.length > 0) {\n      messages.push(\n        `${picocolors.bold(\n          'Critical:'\n        )} The following dependencies are duplicated and WILL cause unexpected behavior:`\n      );\n      messages.push(critical.join(messageDivider), '\\n');\n    }\n\n    if (trivial.length > 0) {\n      messages.push(\n        `${picocolors.bold(\n          'Attention:'\n        )} The following dependencies are duplicated which might cause unexpected behavior:`\n      );\n      messages.push(trivial.join(messageDivider));\n    }\n\n    messages.push(\n      '\\n',\n      `Please try de-duplicating these dependencies by running ${picocolors.cyan(\n        `${installationMetadata.dedupeCommand}`\n      )}`\n    );\n\n    messages.push(\n      '\\n',\n      `You can find more information for a given dependency by running ${picocolors.cyan(\n        `${installationMetadata.infoCommand} <package-name>`\n      )}`\n    );\n\n    return messages;\n  } catch (err) {\n    return undefined;\n  }\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/doctor/getIncompatibleStorybookPackages.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { JsPackageManager } from 'storybook/internal/common';\n\nimport type { AnalysedPackage } from './getIncompatibleStorybookPackages.ts';\nimport {\n  checkPackageCompatibility,\n  getIncompatiblePackagesSummary,\n  getIncompatibleStorybookPackages,\n} from './getIncompatibleStorybookPackages.ts';\n\nvi.mock('picocolors', () => {\n  return {\n    default: {\n      yellow: (str: string) => str,\n      cyan: (str: string) => str,\n      bold: (str: string) => str,\n    },\n  };\n});\n\nconst packageManagerMock = {\n  getAllDependencies: vi.fn(),\n  latestVersion: vi.fn(),\n  getModulePackageJSON: vi.fn(),\n} as Partial<JsPackageManager> as JsPackageManager;\n\ndescribe('checkPackageCompatibility', () => {\n  beforeEach(() => {\n    vi.mocked(packageManagerMock.getAllDependencies).mockReturnValue({});\n    vi.mocked(packageManagerMock.latestVersion).mockResolvedValue('9.0.0');\n    vi.mocked(packageManagerMock.getModulePackageJSON).mockResolvedValue({ version: '9.0.0' });\n  });\n\n  it('returns that a package is incompatible', async () => {\n    const packageName = 'my-storybook-package';\n    vi.mocked(packageManagerMock.getModulePackageJSON).mockResolvedValueOnce({\n      name: packageName,\n      version: '1.0.0',\n      dependencies: {\n        storybook: '8.0.0',\n      },\n    });\n    const result = await checkPackageCompatibility(packageName, {\n      currentStorybookVersion: '9.0.0',\n      packageManager: packageManagerMock as JsPackageManager,\n    });\n    expect(result).toEqual(\n      expect.objectContaining({\n        packageName: 'my-storybook-package',\n        packageVersion: '1.0.0',\n        hasIncompatibleDependencies: true,\n      })\n    );\n  });\n\n  it('returns that a package is compatible', async () => {\n    const packageName = 'my-storybook-package';\n    vi.mocked(packageManagerMock.getModulePackageJSON).mockResolvedValueOnce({\n      name: packageName,\n      version: '1.0.0',\n      dependencies: {\n        'storybook/internal/common': '9.0.0',\n      },\n    });\n    const result = await checkPackageCompatibility(packageName, {\n      currentStorybookVersion: '9.0.0',\n      packageManager: packageManagerMock as JsPackageManager,\n    });\n    expect(result).toEqual(\n      expect.objectContaining({\n        packageName: 'my-storybook-package',\n        packageVersion: '1.0.0',\n        hasIncompatibleDependencies: false,\n      })\n    );\n  });\n\n  it('returns that a package is incompatible and because it is core, can be upgraded', async () => {\n    const packageName = '@storybook/addon-docs';\n\n    vi.mocked(packageManagerMock.getModulePackageJSON).mockResolvedValueOnce({\n      name: packageName,\n      version: '8.0.0',\n      dependencies: {\n        storybook: '8.0.0',\n      },\n    });\n\n    const result = await checkPackageCompatibility(packageName, {\n      currentStorybookVersion: '9.0.0',\n      packageManager: packageManagerMock,\n    });\n\n    expect(result).toEqual(\n      expect.objectContaining({\n        packageName: '@storybook/addon-docs',\n        packageVersion: '8.0.0',\n        hasIncompatibleDependencies: true,\n        availableUpdate: '9.0.0',\n      })\n    );\n  });\n\n  it('returns that an addon is incompatible because it uses legacy consolidated packages', async () => {\n    const packageName = '@storybook/addon-designs';\n\n    vi.mocked(packageManagerMock.getModulePackageJSON).mockResolvedValueOnce({\n      name: packageName,\n      version: '8.0.0',\n      dependencies: {\n        '@storybook/core-common': '8.0.0',\n      },\n    });\n\n    const result = await checkPackageCompatibility(packageName, {\n      currentStorybookVersion: '9.0.0',\n      packageManager: packageManagerMock,\n    });\n\n    expect(result).toEqual(\n      expect.objectContaining({\n        packageName: '@storybook/addon-designs',\n        packageVersion: '8.0.0',\n        hasIncompatibleDependencies: true,\n      })\n    );\n  });\n});\n\ndescribe('getIncompatibleStorybookPackages', () => {\n  beforeEach(() => {\n    vi.mocked(packageManagerMock.getAllDependencies).mockReturnValue({});\n    vi.mocked(packageManagerMock.latestVersion).mockResolvedValue('9.0.0');\n    vi.mocked(packageManagerMock.getModulePackageJSON).mockResolvedValue({ version: '9.0.0' });\n  });\n\n  it('succeeds if only core storybook packages used', async () => {\n    vi.mocked(packageManagerMock.getAllDependencies).mockReturnValueOnce({\n      storybook: '9.0.0',\n    });\n\n    const result = await getIncompatibleStorybookPackages({\n      currentStorybookVersion: '9.0.0',\n      packageManager: packageManagerMock as JsPackageManager,\n    });\n\n    expect(result).toHaveLength(0);\n  });\n\n  it('returns an array of incompatible packages', async () => {\n    // Mock a non-core storybook package that would be found\n    vi.mocked(packageManagerMock.getAllDependencies).mockReturnValueOnce({\n      'react-storybook-addon': '1.0.0',\n    });\n\n    vi.mocked(packageManagerMock.getModulePackageJSON).mockResolvedValueOnce({\n      name: 'react-storybook-addon',\n      version: '1.0.0',\n      dependencies: {\n        storybook: '8.0.0',\n      },\n    });\n\n    const result = await getIncompatibleStorybookPackages({\n      currentStorybookVersion: '9.0.0',\n      packageManager: packageManagerMock as JsPackageManager,\n    });\n\n    expect(result).toEqual([\n      expect.objectContaining({\n        packageName: 'react-storybook-addon',\n        hasIncompatibleDependencies: true,\n      }),\n    ]);\n  });\n});\n\ndescribe('getIncompatiblePackagesSummary', () => {\n  // necessary for windows and unix output to match in the assertions\n  const normalizeLineBreaks = (str: string) => str.replace(/\\r\\n|\\r|\\n/g, '\\n').trim();\n\n  it('generates a summary message for incompatible packages', () => {\n    const analysedPackages: AnalysedPackage[] = [\n      {\n        packageName: 'storybook-react',\n        packageVersion: '1.0.0',\n        hasIncompatibleDependencies: true,\n      },\n      {\n        packageName: '@storybook/addon-docs',\n        packageVersion: '8.0.0',\n        hasIncompatibleDependencies: true,\n        availableUpdate: '9.0.0',\n      },\n    ];\n    const summary = getIncompatiblePackagesSummary(analysedPackages, '9.0.0');\n\n    expect(normalizeLineBreaks(summary)).toMatchInlineSnapshot(`\n      \"You are currently using Storybook 9.0.0 but you have packages which are incompatible with it:\n\n      - storybook-react@1.0.0\n      - @storybook/addon-docs@8.0.0 (9.0.0 available!)\n      \n      Please consider updating your packages or contacting the maintainers for compatibility details.\n\n      For more details on compatibility guidance, see:\n      https://github.com/storybookjs/storybook/issues/32836\"\n    `);\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/doctor/getIncompatibleStorybookPackages.ts",
    "content": "/* eslint-disable local-rules/no-uncategorized-errors */\nimport type { JsPackageManager } from 'storybook/internal/common';\nimport { versions as storybookCorePackages } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport picocolors from 'picocolors';\nimport semver from 'semver';\n\nimport { consolidatedPackages } from '../automigrate/helpers/consolidated-packages.ts';\n\nexport type AnalysedPackage = {\n  packageName: string;\n  packageVersion?: string;\n  homepage?: string;\n  hasIncompatibleDependencies?: boolean;\n  availableUpdate?: string;\n  availableCoreUpdate?: string;\n  packageStorybookVersion?: string;\n};\n\ntype Context = {\n  currentStorybookVersion: string;\n  packageManager: JsPackageManager;\n  skipUpgradeCheck?: boolean;\n  skipErrors?: boolean;\n};\n\nexport const checkPackageCompatibility = async (\n  dependency: string,\n  context: Context\n): Promise<AnalysedPackage> => {\n  const { currentStorybookVersion, skipErrors, packageManager } = context;\n  try {\n    const dependencyPackageJson = await packageManager.getModulePackageJSON(dependency);\n    if (dependencyPackageJson === null) {\n      return { packageName: dependency };\n    }\n\n    const {\n      version: packageVersion,\n      name = dependency,\n      dependencies,\n      peerDependencies,\n      homepage,\n    } = dependencyPackageJson;\n\n    const packageStorybookVersion = Object.entries({\n      ...dependencies,\n      ...peerDependencies,\n    })\n      .filter(\n        ([dep]) =>\n          storybookCorePackages[dep as keyof typeof storybookCorePackages] ||\n          consolidatedPackages[dep as keyof typeof consolidatedPackages]\n      )\n      .map(([_, versionRange]) => versionRange)\n      .find((versionRange) => {\n        // prevent issues with \"tag\" based versions e.g. \"latest\" or \"next\" instead of actual numbers\n        return (\n          versionRange &&\n          // We can't check compatibility for 0.x packages, so we skip them\n          !/^[~^]?0\\./.test(versionRange) &&\n          semver.validRange(versionRange) &&\n          !semver.satisfies(currentStorybookVersion, versionRange)\n        );\n      });\n\n    const isCorePackage = storybookCorePackages[name as keyof typeof storybookCorePackages];\n\n    let availableUpdate;\n    let availableCoreUpdate;\n\n    // For now, we notify about updates only for core packages (which will match the currently installed storybook version)\n    // In the future, we can use packageManager.latestVersion(name, constraint) for all packages\n    if (isCorePackage && packageVersion && semver.gt(currentStorybookVersion, packageVersion)) {\n      availableUpdate = currentStorybookVersion;\n    }\n\n    // If the package is greater than the current version, this means a core update is available.\n    if (isCorePackage && packageVersion && semver.gt(packageVersion, currentStorybookVersion)) {\n      availableCoreUpdate = packageVersion;\n    }\n\n    return {\n      packageName: name,\n      packageVersion,\n      homepage,\n      hasIncompatibleDependencies: packageStorybookVersion != null,\n      packageStorybookVersion,\n      availableUpdate,\n      availableCoreUpdate,\n    };\n  } catch (err) {\n    if (!skipErrors) {\n      logger.log(\n        `Error checking compatibility for ${dependency}, please report an issue:\\n` + String(err)\n      );\n    }\n    return { packageName: dependency };\n  }\n};\n\nexport const getIncompatibleStorybookPackages = async (\n  context: Context\n): Promise<AnalysedPackage[]> => {\n  if (context.currentStorybookVersion.includes('0.0.0')) {\n    // We can't know if a Storybook canary version is compatible with other packages, so we skip it\n    return [];\n  }\n\n  const allDeps = context.packageManager.getAllDependencies();\n  const storybookLikeDeps = Object.keys(allDeps).filter((dep) => dep.includes('storybook'));\n  if (storybookLikeDeps.length === 0 && !context.skipErrors) {\n    throw new Error('No Storybook dependencies found in the package.json');\n  }\n  return Promise.all(\n    storybookLikeDeps\n      .filter((dep) => !storybookCorePackages[dep as keyof typeof storybookCorePackages])\n      .map((dep) => checkPackageCompatibility(dep, context))\n  );\n};\n\nexport const getIncompatiblePackagesSummary = (\n  dependencyAnalysis: AnalysedPackage[],\n  currentStorybookVersion: string\n) => {\n  const summaryMessage: string[] = [];\n\n  const incompatiblePackages = dependencyAnalysis.filter(\n    (dep) => dep.hasIncompatibleDependencies\n  ) as AnalysedPackage[];\n\n  if (incompatiblePackages.length > 0) {\n    summaryMessage.push(\n      `You are currently using Storybook ${picocolors.bold(\n        currentStorybookVersion\n      )} but you have packages which are incompatible with it:\\n`\n    );\n    incompatiblePackages.forEach(\n      ({\n        packageName: addonName,\n        packageVersion: addonVersion,\n        homepage,\n        availableUpdate,\n        packageStorybookVersion,\n      }) => {\n        const packageDescription = `${addonName}@${addonVersion}`;\n        const updateMessage = availableUpdate ? ` (${availableUpdate} available!)` : '';\n        const dependsOnStorybook =\n          packageStorybookVersion != null ? ` which depends on ${packageStorybookVersion}` : '';\n        const packageRepo = homepage ? `\\n Repo: ${homepage}` : '';\n\n        summaryMessage.push(\n          `- ${packageDescription}${updateMessage}${dependsOnStorybook}${packageRepo}`\n        );\n      }\n    );\n\n    summaryMessage.push(\n      '\\nPlease consider updating your packages or contacting the maintainers for compatibility details.',\n      '\\nFor more details on compatibility guidance, see:',\n      'https://github.com/storybookjs/storybook/issues/32836'\n    );\n\n    if (incompatiblePackages.some((dep) => dep.availableCoreUpdate)) {\n      summaryMessage.push(\n        '\\n',\n        `The version of ${picocolors.blue(`storybook@${currentStorybookVersion}`)} is behind the following core packages:`,\n        `${incompatiblePackages\n          .filter((dep) => dep.availableCoreUpdate)\n          .map(\n            ({ packageName, packageVersion }) =>\n              `- ${picocolors.blue(`${packageName}@${packageVersion}`)}`\n          )\n          .join('\\n')}`,\n        '\\n',\n        `Upgrade Storybook with:`,\n        picocolors.blue('npx storybook@latest upgrade')\n      );\n    }\n  }\n\n  return summaryMessage.join('\\n');\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/doctor/getMismatchingVersionsWarning.ts",
    "content": "import { frameworkPackages, versions as storybookCorePackages } from 'storybook/internal/common';\nimport type { InstallationMetadata } from 'storybook/internal/common';\n\nimport picocolors from 'picocolors';\nimport semver from 'semver';\n\nfunction getPrimaryVersion(name: string | undefined, installationMetadata?: InstallationMetadata) {\n  if (!name) {\n    return undefined;\n  }\n  const packageMetadata = installationMetadata?.dependencies[name];\n  if (!packageMetadata) {\n    return undefined;\n  }\n\n  return packageMetadata[0]?.version;\n}\n\nexport function getMismatchingVersionsWarnings(\n  installationMetadata?: InstallationMetadata\n): string | undefined {\n  if (!installationMetadata) {\n    return undefined;\n  }\n\n  const messages: string[] = [];\n  try {\n    const frameworkPackageName = Object.keys(installationMetadata?.dependencies || []).find(\n      (packageName) => {\n        return Object.keys(frameworkPackages).includes(packageName);\n      }\n    );\n    const cliVersion = getPrimaryVersion('storybook', installationMetadata);\n    const frameworkVersion = getPrimaryVersion(frameworkPackageName, installationMetadata);\n\n    if (!cliVersion || !frameworkVersion || semver.eq(cliVersion, frameworkVersion)) {\n      return undefined;\n    }\n\n    messages.push(\n      `${picocolors.bold(\n        'Attention:'\n      )} There seems to be a mismatch between your Storybook package versions. This can result in a broken Storybook installation.`\n    );\n\n    let versionToCompare: string;\n    let packageToDisplay: string;\n    if (semver.lt(cliVersion, frameworkVersion)) {\n      versionToCompare = frameworkVersion;\n      packageToDisplay = frameworkPackageName as string;\n    } else {\n      versionToCompare = cliVersion;\n      packageToDisplay = 'storybook';\n    }\n\n    messages.push(\n      `The version of your storybook core packages should align with ${picocolors.yellow(\n        versionToCompare\n      )} (from the ${picocolors.cyan(packageToDisplay)} package) or higher.`\n    );\n\n    const filteredDependencies = Object.entries(installationMetadata?.dependencies || []).filter(\n      ([name, packages]) => {\n        if (Object.keys(storybookCorePackages).includes(name)) {\n          const packageVersion = packages[0].version;\n          return packageVersion !== versionToCompare;\n        }\n\n        return false;\n      }\n    );\n\n    if (filteredDependencies.length > 0) {\n      messages.push(\n        `Based on your lockfile, these dependencies should be aligned:`,\n        filteredDependencies\n          .map(([name, dep]) => `${picocolors.yellow(name)}: ${dep[0].version}`)\n          .join('\\n')\n      );\n    }\n\n    messages.push(\n      `You can run ${picocolors.cyan('npx storybook@latest upgrade')} to upgrade all of your Storybook packages to the latest version.\\n\\nAlternatively you can try manually changing the versions to match in your package.json. We also recommend regenerating your lockfile, or running the following command to possibly deduplicate your Storybook package versions: ${picocolors.cyan(installationMetadata?.dedupeCommand)}`\n    );\n\n    return messages.join('\\n\\n');\n  } catch (err) {\n    return undefined;\n  }\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/doctor/hasMultipleVersions.ts",
    "content": "import semver from 'semver';\n\nexport function hasMultipleVersions(versions: string[]) {\n  return versions.find((v) => {\n    const major = semver.major(v);\n    // If major version === 0, treat minor or patch as major\n    if (major === 0) {\n      const minor = semver.minor(v);\n      if (minor === 0) {\n        const patch = semver.patch(v);\n        return versions.some((v2) => {\n          return semver.patch(v2) !== patch;\n        });\n      }\n\n      return versions.some((v2) => {\n        return semver.minor(v2) !== minor;\n      });\n    }\n\n    return versions.some((v2) => {\n      return semver.major(v2) !== major;\n    });\n  });\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/doctor/index.ts",
    "content": "import { JsPackageManager } from 'storybook/internal/common';\nimport { CLI_COLORS, logTracker, logger } from 'storybook/internal/node-logger';\nimport type { StorybookConfigRaw } from 'storybook/internal/types';\n\nimport picocolors from 'picocolors';\nimport { dedent } from 'ts-dedent';\n\nimport { getStorybookData } from '../automigrate/helpers/mainConfigFile.ts';\nimport { shortenPath } from '../util.ts';\nimport { getDuplicatedDepsWarnings } from './getDuplicatedDepsWarnings.ts';\nimport {\n  getIncompatiblePackagesSummary,\n  getIncompatibleStorybookPackages,\n} from './getIncompatibleStorybookPackages.ts';\nimport { getMismatchingVersionsWarnings } from './getMismatchingVersionsWarning.ts';\nimport { DiagnosticType as DiagType, DiagnosticStatus } from './types.ts';\nimport type {\n  DiagnosticResult,\n  DiagnosticType,\n  DoctorCheckResult,\n  DoctorOptions,\n  ProjectDoctorData,\n  ProjectDoctorResults,\n} from './types.ts';\n\n/** Collects deduplicated diagnostic results across multiple projects */\nexport function collectDeduplicatedDiagnostics(\n  projectResults: Record<string, ProjectDoctorResults>\n): DiagnosticResult[] {\n  const diagnosticMap = new Map<DiagnosticType, DiagnosticResult>();\n\n  Object.entries(projectResults).forEach(([configDir, result]) => {\n    Object.entries(result.diagnostics).forEach(([type, status]) => {\n      if (status !== DiagnosticStatus.PASSED) {\n        const diagnosticType = type as DiagnosticType;\n        const message = result.messages[diagnosticType];\n\n        if (message) {\n          const existing = diagnosticMap.get(diagnosticType);\n          if (existing) {\n            // Add project to existing diagnostic\n            existing.projects.push({ configDir });\n          } else {\n            // Create new diagnostic entry\n            diagnosticMap.set(diagnosticType, {\n              type: diagnosticType,\n              title: type.replace(/_/g, ' ').replace(/\\b\\w/g, (l) => l.toUpperCase()),\n              message,\n              projects: [{ configDir }],\n            });\n          }\n        }\n      }\n    });\n  });\n\n  return Array.from(diagnosticMap.values());\n}\n\n/** Displays project-based doctor results (similar to automigration pattern) */\nexport function displayDoctorResults(\n  projectResults: Record<string, ProjectDoctorResults>\n): boolean {\n  const projectCount = Object.keys(projectResults).length;\n\n  if (projectCount === 0) {\n    return false;\n  }\n\n  const hasAnyIssues = Object.values(projectResults).some((result) => result.status !== 'healthy');\n\n  if (!hasAnyIssues) {\n    if (projectCount === 1) {\n      logger.log(`Your Storybook project looks good!`);\n    } else {\n      logger.log(`All ${projectCount} Storybook projects look good!`);\n    }\n    return false;\n  }\n\n  // For single project, display per-project results\n  if (projectCount === 1) {\n    const [configDir, result] = Object.entries(projectResults)[0];\n    const projectName = shortenPath(configDir) || '.';\n\n    if (result.status === 'healthy') {\n      logger.log(`✅ ${projectName}: No issues found`);\n    } else {\n      const issueCount = Object.values(result.diagnostics).filter(\n        (status) => status !== DiagnosticStatus.PASSED\n      ).length;\n      if (result.status === 'check_error') {\n        logger.error(\n          `${projectName}: ${issueCount} ${issueCount === 1 ? 'problem' : 'problems'} found`\n        );\n      } else {\n        logger.warn(`${projectName}: ${issueCount} ${issueCount === 1 ? 'issue' : 'issues'} found`);\n      }\n\n      // Display each diagnostic issue\n      Object.entries(result.diagnostics).forEach(([type, status]) => {\n        if (status !== DiagnosticStatus.PASSED) {\n          const message = result.messages[type as DiagnosticType];\n          if (message) {\n            const title = type.replace(/_/g, ' ').replace(/\\b\\w/g, (l) => l.toUpperCase());\n            logger.logBox(message, {\n              title:\n                status === DiagnosticStatus.CHECK_ERROR\n                  ? CLI_COLORS.error(title)\n                  : CLI_COLORS.warning(title),\n            });\n          }\n        }\n      });\n    }\n  } else {\n    // For multiple projects, use deduplicated approach\n    const deduplicatedDiagnostics = collectDeduplicatedDiagnostics(projectResults);\n\n    const totalIssues = deduplicatedDiagnostics.length;\n    const errorCount = Object.values(projectResults).filter(\n      (result) => result.status === 'check_error'\n    ).length;\n\n    if (errorCount > 0) {\n      logger.error(\n        `Found ${totalIssues} ${totalIssues === 1 ? 'issue' : 'issues'} across ${projectCount} projects`\n      );\n    } else {\n      logger.warn(\n        `Found ${totalIssues} ${totalIssues === 1 ? 'issue' : 'issues'} across ${projectCount} projects`\n      );\n    }\n\n    // Display deduplicated diagnostics\n    deduplicatedDiagnostics.forEach((diagnostic) => {\n      let messageWithProjects = diagnostic.message;\n\n      if (diagnostic.projects.length > 1) {\n        const projectNames = diagnostic.projects\n          .map((p) => shortenPath(p.configDir) || '.')\n          .join(', ');\n        messageWithProjects += `\\n\\nAffected projects: ${projectNames}`;\n      } else {\n        const projectName = shortenPath(diagnostic.projects[0].configDir) || '.';\n        messageWithProjects += `\\n\\nAffected project: ${projectName}`;\n      }\n\n      logger.logBox(messageWithProjects, {\n        title: CLI_COLORS.warning(diagnostic.title),\n      });\n    });\n  }\n\n  logger.step('Storybook doctor is complete!');\n\n  const commandMessage = `You can always recheck the health of your project(s) by running:\\n${picocolors.cyan(\n    'npx storybook doctor'\n  )}`;\n\n  logger.log(commandMessage);\n\n  return true;\n}\n\n/** Runs doctor checks across multiple projects */\nexport async function runMultiProjectDoctor(\n  projects: ProjectDoctorData[]\n): Promise<Record<string, ProjectDoctorResults>> {\n  if (projects.length === 0) {\n    return {};\n  }\n\n  const projectOptions: ProjectDoctorData[] = projects.map((project) => ({\n    configDir: project.configDir,\n    packageManager: project.packageManager,\n    storybookVersion: project.storybookVersion,\n    mainConfig: project.mainConfig,\n  }));\n\n  // Always return the project-based results structure\n  return await collectDoctorResultsByProject(projectOptions);\n}\n\n/** Doctor function that can handle both single and multiple projects */\nexport const doctor = async ({\n  configDir: userSpecifiedConfigDir,\n  packageManager: packageManagerName,\n}: DoctorOptions) => {\n  logger.step('Checking the health of your Storybook..');\n\n  const diagnosticResults: DiagnosticResult[] = [];\n\n  let packageManager!: JsPackageManager;\n  let configDir!: string;\n  let versionInstalled: string | undefined;\n  let mainConfig!: StorybookConfigRaw;\n\n  try {\n    ({ packageManager, configDir, versionInstalled, mainConfig } = await getStorybookData({\n      configDir: userSpecifiedConfigDir,\n      packageManagerName,\n    }));\n  } catch (err: any) {\n    const title = 'Configuration Error';\n    let message: string;\n\n    if (err.message.includes('No configuration files have been found')) {\n      message = dedent`\n          Could not find or evaluate your Storybook main.js config directory at ${picocolors.blue(\n            configDir || '.storybook'\n          )} so the doctor command cannot proceed. You might be running this command in a monorepo or a non-standard project structure. If that is the case, please rerun this command by specifying the path to your Storybook config directory via the --config-dir option.\n        `;\n    } else {\n      message = `❌ ${err.message}`;\n    }\n\n    diagnosticResults.push({\n      type: DiagType.CONFIGURATION_ERROR,\n      title,\n      message,\n      projects: [{ configDir }],\n    });\n  }\n\n  const doctorResults = await collectDoctorResultsByProject([\n    {\n      configDir,\n      packageManager,\n      storybookVersion: versionInstalled,\n      mainConfig,\n    },\n  ]);\n\n  const foundIssues = displayDoctorResults(doctorResults);\n\n  if (foundIssues) {\n    logTracker.enableLogWriting();\n  }\n};\n\n/** Gets doctor diagnostic results for a single project */\nexport async function getDoctorDiagnostics({\n  configDir,\n  packageManager,\n  storybookVersion,\n  mainConfig,\n}: {\n  configDir: string;\n  packageManager: JsPackageManager;\n  storybookVersion?: string;\n  mainConfig: StorybookConfigRaw;\n}): Promise<DoctorCheckResult[]> {\n  const results: DoctorCheckResult[] = [];\n\n  if (!storybookVersion) {\n    results.push({\n      type: DiagType.CONFIGURATION_ERROR,\n      title: 'Version Detection Failed',\n      message: dedent`\n        ❌ Unable to determine Storybook version so the command will not proceed.\n        🤔 Are you running storybook doctor from your project directory? Please specify your Storybook config directory with the --config-dir flag.\n      `,\n      project: { configDir },\n    });\n    return results;\n  }\n\n  if (!mainConfig) {\n    results.push({\n      type: DiagType.CONFIGURATION_ERROR,\n      title: 'Main Config Error',\n      message: 'mainConfig is undefined',\n      project: { configDir },\n    });\n    return results;\n  }\n\n  // Check for missing storybook dependency\n  const hasStorybookDependency = packageManager.packageJsonPaths.some(\n    JsPackageManager.hasStorybookDependency\n  );\n\n  if (!hasStorybookDependency) {\n    results.push({\n      type: DiagType.MISSING_STORYBOOK_DEPENDENCY,\n      title: `Package \"storybook\" not found`,\n      message: dedent`\n        The \"storybook\" package was not found in your package.json.\n        Installing \"storybook\" as a direct dev dependency in your package.json is required.\n      `,\n      project: { configDir },\n    });\n  }\n\n  // Check for incompatible packages\n  const incompatibleStorybookPackagesList = await getIncompatibleStorybookPackages({\n    currentStorybookVersion: storybookVersion,\n    packageManager,\n  });\n  const incompatiblePackagesMessage = getIncompatiblePackagesSummary(\n    incompatibleStorybookPackagesList,\n    storybookVersion\n  );\n\n  if (incompatiblePackagesMessage) {\n    results.push({\n      type: DiagType.INCOMPATIBLE_PACKAGES,\n      title: 'Incompatible packages found',\n      message: incompatiblePackagesMessage,\n      project: { configDir },\n    });\n  }\n\n  const installationMetadata = await packageManager.findInstallations([\n    '@storybook/*',\n    'storybook',\n  ]);\n\n  // If we found incompatible packages, we let the users fix that first\n  // If they run doctor again and there are still issues, we show the other warnings\n  if (!incompatiblePackagesMessage) {\n    const mismatchingVersionMessage = getMismatchingVersionsWarnings(installationMetadata);\n\n    if (mismatchingVersionMessage) {\n      results.push({\n        type: DiagType.MISMATCHING_VERSIONS,\n        title: 'Diagnostics',\n        message: mismatchingVersionMessage,\n        project: { configDir },\n      });\n    } else {\n      const list = installationMetadata\n        ? getDuplicatedDepsWarnings(installationMetadata)\n        : getDuplicatedDepsWarnings();\n\n      if (Array.isArray(list) && list.length > 0) {\n        results.push({\n          type: DiagType.DUPLICATED_DEPENDENCIES,\n          title: 'Duplicated dependencies found',\n          message: list.join('\\n'),\n          project: { configDir },\n        });\n      }\n    }\n  }\n\n  return results;\n}\n\nexport async function collectDoctorResultsByProject(\n  projectOptions: ProjectDoctorData[]\n): Promise<Record<string, ProjectDoctorResults>> {\n  const projectResults: Record<string, ProjectDoctorResults> = {};\n\n  for (const options of projectOptions) {\n    const { configDir } = options;\n\n    try {\n      const checkResults = await getDoctorDiagnostics(options);\n\n      const diagnostics: Record<DiagnosticType, DiagnosticStatus> = {} as Record<\n        DiagnosticType,\n        DiagnosticStatus\n      >;\n      const messages: Record<DiagnosticType, string> = {} as Record<DiagnosticType, string>;\n\n      // Initialize all diagnostic types as passed\n      Object.values(DiagType).forEach((type) => {\n        diagnostics[type] = DiagnosticStatus.PASSED;\n      });\n\n      let hasIssues = false;\n      let hasErrors = false;\n\n      // Process each check result\n      for (const checkResult of checkResults) {\n        if (checkResult.type === DiagType.CONFIGURATION_ERROR) {\n          diagnostics[checkResult.type] = DiagnosticStatus.CHECK_ERROR;\n          hasErrors = true;\n        } else {\n          diagnostics[checkResult.type] = DiagnosticStatus.HAS_ISSUES;\n          hasIssues = true;\n        }\n        messages[checkResult.type] = checkResult.message;\n      }\n\n      const status = hasErrors ? 'check_error' : hasIssues ? 'has_issues' : 'healthy';\n\n      projectResults[configDir] = {\n        configDir,\n        status,\n        diagnostics,\n        messages,\n      };\n    } catch (error) {\n      logger.error(`Failed to run doctor checks for project ${configDir}:\\n${error}`);\n\n      // Mark as error state\n      const diagnostics: Record<DiagnosticType, DiagnosticStatus> = {} as Record<\n        DiagnosticType,\n        DiagnosticStatus\n      >;\n      const messages: Record<DiagnosticType, string> = {} as Record<DiagnosticType, string>;\n\n      Object.values(DiagType).forEach((type) => {\n        diagnostics[type] = DiagnosticStatus.PASSED;\n      });\n\n      diagnostics[DiagType.CONFIGURATION_ERROR] = DiagnosticStatus.CHECK_ERROR;\n      messages[DiagType.CONFIGURATION_ERROR] =\n        `Failed to run doctor checks: ${error instanceof Error ? error.message : String(error)}`;\n\n      projectResults[configDir] = {\n        configDir,\n        status: 'check_error',\n        diagnostics,\n        messages,\n      };\n    }\n  }\n\n  return projectResults;\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/doctor/types.ts",
    "content": "import type { JsPackageManager, PackageManagerName } from 'storybook/internal/common';\nimport type { StorybookConfigRaw } from 'storybook/internal/types';\n\nexport interface DoctorOptions {\n  configDir: string;\n  packageManager?: PackageManagerName;\n}\n\nexport interface ProjectDoctorData {\n  configDir: string;\n  packageManager: JsPackageManager;\n  storybookVersion?: string;\n  mainConfig: StorybookConfigRaw;\n}\n\nexport enum DiagnosticType {\n  MISSING_STORYBOOK_DEPENDENCY = 'missing_storybook_dependency',\n  INCOMPATIBLE_PACKAGES = 'incompatible_packages',\n  MISMATCHING_VERSIONS = 'mismatching_versions',\n  DUPLICATED_DEPENDENCIES = 'duplicated_dependencies',\n  CONFIGURATION_ERROR = 'configuration_error',\n}\n\nexport enum DiagnosticStatus {\n  PASSED = 'passed',\n  HAS_ISSUES = 'has_issues',\n  CHECK_ERROR = 'check_error',\n}\n\nexport type DiagnosticDoctorData = {\n  configDir: string;\n};\n\nexport interface DiagnosticResult {\n  type: DiagnosticType;\n  title: string;\n  message: string;\n  projects: DiagnosticDoctorData[];\n}\n\nexport interface DoctorCheckResult {\n  type: DiagnosticType;\n  title: string;\n  message: string;\n  project: DiagnosticDoctorData;\n}\n\nexport interface ProjectDoctorResults {\n  configDir: string;\n  status: 'healthy' | 'has_issues' | 'check_error';\n  diagnostics: Record<DiagnosticType, DiagnosticStatus>;\n  messages: Record<DiagnosticType, string>;\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/index.ts",
    "content": ""
  },
  {
    "path": "code/lib/cli-storybook/src/link.ts",
    "content": "import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { basename, extname, join } from 'node:path';\n\nimport { executeCommand } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { sync as spawnSync } from 'cross-spawn';\n\ninterface LinkOptions {\n  target: string;\n  local?: boolean;\n  start: boolean;\n}\n\nexport const link = async ({ target, local, start }: LinkOptions) => {\n  const storybookDir = process.cwd();\n  try {\n    const packageJson = JSON.parse(await readFile('package.json', { encoding: 'utf8' }));\n    if (packageJson.name !== '@storybook/code') {\n      throw new Error();\n    }\n  } catch {\n    throw new Error('Expected to run link from the root of the storybook monorepo');\n  }\n\n  let reproDir = target;\n  let reproName = basename(target);\n\n  if (!local) {\n    const reprosDir = join(storybookDir, '../storybook-repros');\n    logger.info(`Ensuring directory ${reprosDir}`);\n    // Passing `recursive: true` ensures that the method doesn't throw when\n    // the directory already exists.\n    await mkdir(reprosDir, { recursive: true });\n\n    logger.info(`Cloning ${target}`);\n    await executeCommand({\n      command: 'git',\n      args: ['clone', target],\n      cwd: reprosDir,\n    });\n    // Extract a repro name from url given as input (take the last part of the path and remove the extension)\n    reproName = basename(target, extname(target));\n    reproDir = join(reprosDir, reproName);\n  }\n\n  const version = spawnSync('yarn', ['--version'], {\n    cwd: reproDir,\n    stdio: 'pipe',\n    shell: true,\n  }).stdout.toString();\n\n  if (!/^[2-4]\\./.test(version)) {\n    logger.warn(`🚨 Expected yarn 2 or higher in ${reproDir}!`);\n    logger.warn('');\n    logger.warn('Please set it up with `yarn set version berry`,');\n    logger.warn(`then link '${reproDir}' with the '--local' flag.`);\n    return;\n  }\n\n  logger.info(`Linking ${reproDir}`);\n  await executeCommand({\n    command: 'yarn',\n    args: ['link', '--all', '--relative', storybookDir],\n    cwd: reproDir,\n  });\n\n  logger.info(`Installing ${reproName}`);\n\n  const reproPackageJson = JSON.parse(\n    await readFile(join(reproDir, 'package.json'), { encoding: 'utf8' })\n  );\n\n  if (!reproPackageJson.devDependencies?.vite) {\n    reproPackageJson.devDependencies = {\n      ...reproPackageJson.devDependencies,\n      'webpack-hot-middleware': '*',\n    };\n  }\n\n  // ensure that linking is possible\n  reproPackageJson.devDependencies = {\n    ...reproPackageJson.devDependencies,\n    '@types/node': '^22',\n  };\n\n  await writeFile(join(reproDir, 'package.json'), JSON.stringify(reproPackageJson, null, 2));\n\n  await executeCommand({\n    command: 'yarn',\n    args: ['install'],\n    cwd: reproDir,\n  });\n\n  if (start) {\n    logger.info(`Running ${reproName} storybook`);\n    await executeCommand({\n      command: 'yarn',\n      args: ['run', 'storybook'],\n      cwd: reproDir,\n    });\n  }\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/migrate.ts",
    "content": "import { logger } from 'storybook/internal/node-logger';\n\nimport { listCodemods, runCodemod } from '@storybook/codemod';\n\ntype CLIOptions = {\n  glob: string;\n  configDir?: string;\n  dryRun?: boolean;\n  list?: string[];\n  /** Rename suffix of matching files after codemod has been applied, e.g. `\".js:.ts\"` */\n  rename?: string;\n  /** `jscodeshift` parser */\n  parser?: 'babel' | 'babylon' | 'flow' | 'ts' | 'tsx';\n};\n\nexport async function migrate(migration: any, { glob, dryRun, list, rename, parser }: CLIOptions) {\n  if (list) {\n    listCodemods().forEach((key: any) => logger.log(key));\n  } else if (migration) {\n    await runCodemod(migration, { glob, dryRun, logger, rename, parser });\n  } else {\n    throw new Error('Migrate: please specify a migration name or --list');\n  }\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/postinstallAddon.ts",
    "content": "import { createRequire } from 'node:module';\nimport { fileURLToPath } from 'node:url';\n\nimport { importModule } from '../../../core/src/shared/utils/module.ts';\nimport type { PostinstallOptions } from './add.ts';\n\nconst DIR_CWD = process.cwd();\nconst require = createRequire(DIR_CWD);\n\nexport const postinstallAddon = async (addonName: string, options: PostinstallOptions) => {\n  const hookPath = `${addonName}/postinstall`;\n  let modulePath: string;\n  try {\n    modulePath = import.meta.resolve(hookPath, DIR_CWD);\n  } catch (e) {\n    try {\n      modulePath = require.resolve(hookPath, { paths: [DIR_CWD] });\n    } catch (e) {\n      return;\n    }\n  }\n\n  let moduledLoaded: any;\n  try {\n    moduledLoaded = await import(hookPath)\n      .catch(() => importModule(hookPath))\n      .catch(() => importModule(modulePath))\n      .catch(() => importModule(fileURLToPath(modulePath)))\n      .catch(() => require(hookPath))\n      .catch(() => require(modulePath))\n      .catch(() => require(fileURLToPath(modulePath)));\n  } catch (e) {\n    return;\n  }\n\n  const postinstall = moduledLoaded?.default || moduledLoaded?.postinstall || moduledLoaded;\n  const logger = options.logger;\n\n  if (!postinstall || typeof postinstall !== 'function') {\n    logger.error(`Error finding postinstall function for ${addonName}`);\n    return;\n  }\n\n  try {\n    await postinstall(options);\n  } catch (e) {\n    throw e;\n  }\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/sandbox-templates.ts",
    "content": "import type { ConfigFile } from 'storybook/internal/csf-tools';\nimport { type StoriesEntry, type StorybookConfigRaw } from 'storybook/internal/types';\n\nimport { ProjectType } from '../../../core/src/cli/projectTypes.ts';\nimport { SupportedBuilder } from '../../../core/src/types/modules/builders.ts';\n\nexport type TemplateType = Pick<Template, 'inDevelopment' | 'skipTasks' | 'typeCheck'>;\nexport type AllTemplatesKey = keyof typeof allTemplates;\nexport type AllTemplatesType = Record<AllTemplatesKey, TemplateType>;\n\nexport type SkippableTask =\n  | 'smoke-test'\n  | 'test-runner'\n  | 'test-runner-dev'\n  | 'vitest-integration'\n  | 'chromatic'\n  | 'e2e-tests'\n  | 'e2e-tests-dev'\n  | 'bench';\n\nexport type TemplateKey =\n  | keyof typeof baseTemplates\n  | keyof typeof internalTemplates\n  | keyof typeof benchTemplates;\n\nexport type Cadence = keyof typeof templatesByCadence;\n\n// Some properties e.g. experimentalTestSyntax are only available in framework specific types for StorybookConfig, therefore we loosen the type here otherwise it would always fail\ntype LoosenedStorybookConfig = Omit<Partial<StorybookConfigRaw>, 'features'> & {\n  features?:\n    | (Partial<NonNullable<StorybookConfigRaw['features']>> & Record<string, unknown>)\n    | undefined;\n};\n\nexport type Template = {\n  /**\n   * Readable name for the template, which will be used for feedback and the status page Follows the\n   * naming scheme when it makes sense: <framework> <\"v\"version|\"Latest\"|\"Prerelease\">\n   * (<\"Webpack\"|\"Vite\"> | <\"JavaScript\"|\"TypeScript\">) React Latest - Webpack (TS) Next.js v12 (JS)\n   * Angular CLI Prerelease\n   */\n  name: string;\n  /**\n   * Script used to generate the base project of a template. The Storybook CLI will then initialize\n   * Storybook on top of that template. This is used to generate projects which are pushed to\n   * https://github.com/storybookjs/sandboxes\n   */\n  script: string;\n  /** Environment variables to set when running the script. */\n  env?: Record<string, unknown>;\n  /**\n   * Used to assert various things about the generated template. If the template is generated with a\n   * different expected framework, it will fail, detecting a possible regression.\n   */\n  expected: {\n    framework: string;\n    renderer: string;\n    builder: string;\n  };\n\n  expectedFailures?: Array<{\n    feature: string;\n    issues: string[];\n  }>;\n\n  unsupportedFeatures?: Array<{\n    feature: string;\n    issues: string[];\n  }>;\n  /**\n   * Some sandboxes might not work properly in specific tasks temporarily, but we might still want\n   * to run the other tasks. Set the ones to skip in this property.\n   */\n  skipTasks?: SkippableTask[];\n  /**\n   * Should the sandbox be type checked after build. Not part of skipTasks as the default answer\n   * will be 'no', at least initially\n   */\n  typeCheck?: boolean;\n  /**\n   * Set this only while developing a newly created framework, to avoid using it in CI. NOTE: Make\n   * sure to always add a TODO comment to remove this flag in a subsequent PR.\n   */\n  inDevelopment?: boolean;\n  /**\n   * Some sandboxes might need extra modifications in the initialized Storybook, such as extend\n   * main.js, for setting specific feature flags.\n   */\n  modifications?: {\n    skipTemplateStories?: boolean;\n    skipMocking?: boolean;\n    mainConfig?: LoosenedStorybookConfig | ((config: ConfigFile) => LoosenedStorybookConfig);\n    testBuild?: boolean;\n    disableDocs?: boolean;\n    extraDependencies?: string[];\n    editAddons?: (addons: string[]) => string[];\n    useCsfFactory?: boolean;\n  };\n  /** Additional CI steps in case this template has special needs during CI. */\n  extraCiSteps?: {\n    // Some sandboxes (e.g. Angular) rely on Node 22.22.1 as minimum supported version and threfore it needs enforcing, even if the CI image comes with a different node version.\n    ensureMinNodeVersion?: boolean;\n  };\n  /** Additional options to pass to the initiate command when initializing Storybook. */\n  initOptions?: {\n    builder?: SupportedBuilder;\n    type?: ProjectType;\n    [key: string]: unknown;\n  };\n  /**\n   * Flag to indicate that this template is a secondary template, which is used mainly to test\n   * rather specific features. This means the template might be hidden from the Storybook status\n   * page or the repro CLI command.\n   */\n  isInternal?: boolean;\n};\n\ntype BaseTemplates = Template & {\n  name: `${string} ${`v${number}` | 'Latest' | 'Prerelease'} (${'Webpack' | 'Vite' | 'RsBuild'} | ${\n    | 'JavaScript'\n    | 'TypeScript'})`;\n};\n\nexport const baseTemplates = {\n  'cra/default-js': {\n    name: 'Create React App Latest (Webpack | JavaScript)',\n    script: `\n      npx create-react-app {{beforeDir}} && cd {{beforeDir}} && \\\n      jq '.browserslist.production[0] = \">0.9%\"' package.json > tmp.json && mv tmp.json package.json\n    `,\n    expected: {\n      // TODO: change this to @storybook/cra once that package is created\n      framework: '@storybook/react-webpack5',\n      renderer: '@storybook/react',\n      builder: '@storybook/builder-webpack5',\n    },\n\n    skipTasks: ['e2e-tests', 'bench', 'vitest-integration'],\n    modifications: {\n      useCsfFactory: true,\n      extraDependencies: ['prop-types'],\n      mainConfig: (config) => {\n        const stories = config.getFieldValue<Array<StoriesEntry>>(['stories']);\n        return {\n          features: {\n            experimentalTestSyntax: true,\n          },\n          stories: stories?.map((s) => {\n            if (typeof s === 'string') {\n              return s.replace(/\\|(tsx?|ts)\\b|\\b(tsx?|ts)\\|/g, '');\n            } else {\n              return s;\n            }\n          }),\n        };\n      },\n    },\n  },\n  'cra/default-ts': {\n    name: 'Create React App Latest (Webpack | TypeScript)',\n    script: `\n      npx create-react-app {{beforeDir}} --template typescript && cd {{beforeDir}} && \\\n      jq '.browserslist.production[0] = \">0.9%\"' package.json > tmp.json && mv tmp.json package.json\n    `,\n    // Re-enable once https://github.com/storybookjs/storybook/issues/19351 is fixed.\n    skipTasks: ['smoke-test', 'bench', 'vitest-integration'],\n    expected: {\n      // TODO: change this to @storybook/cra once that package is created\n      framework: '@storybook/react-webpack5',\n      renderer: '@storybook/react',\n      builder: '@storybook/builder-webpack5',\n    },\n    modifications: {\n      useCsfFactory: true,\n      extraDependencies: ['prop-types'],\n      mainConfig: {\n        features: {\n          experimentalTestSyntax: true,\n        },\n      },\n    },\n  },\n  'nextjs/14-ts': {\n    name: 'Next.js v14.2 (Webpack | TypeScript)',\n    script:\n      'yarn create next-app {{beforeDir}} -e https://github.com/vercel/next.js/tree/v14.2.17/examples/hello-world && cd {{beforeDir}} && npm pkg set \"dependencies.next\"=\"^14.2.17\" && yarn && git add . && git commit --amend --no-edit && cd ..',\n    expected: {\n      framework: '@storybook/nextjs',\n      renderer: '@storybook/react',\n      builder: '@storybook/builder-webpack5',\n    },\n    modifications: {\n      useCsfFactory: true,\n      mainConfig: {\n        features: {\n          experimentalRSC: true,\n          developmentModeForBuild: true,\n          experimentalTestSyntax: true,\n        },\n      },\n      extraDependencies: ['server-only', 'prop-types'],\n    },\n    initOptions: {\n      builder: SupportedBuilder.WEBPACK5,\n    },\n    skipTasks: ['e2e-tests-dev', 'e2e-tests', 'bench', 'vitest-integration'],\n  },\n  'nextjs/15-ts': {\n    name: 'Next.js v15 (Webpack | TypeScript)',\n    script:\n      'npx create-next-app@^15.5 {{beforeDir}} --eslint --tailwind --app --import-alias=\"@/*\" --src-dir',\n    expected: {\n      framework: '@storybook/nextjs',\n      renderer: '@storybook/react',\n      builder: '@storybook/builder-webpack5',\n    },\n    modifications: {\n      useCsfFactory: true,\n      mainConfig: {\n        features: {\n          experimentalRSC: true,\n          developmentModeForBuild: true,\n          experimentalTestSyntax: true,\n        },\n      },\n      extraDependencies: ['server-only', 'prop-types'],\n    },\n    initOptions: {\n      builder: SupportedBuilder.WEBPACK5,\n    },\n    skipTasks: ['e2e-tests', 'bench', 'vitest-integration'],\n  },\n  'nextjs/default-ts': {\n    name: 'Next.js Latest (Webpack | TypeScript)',\n    script:\n      'npx create-next-app {{beforeDir}} --eslint --tailwind --app --import-alias=\"@/*\" --src-dir',\n    expected: {\n      framework: '@storybook/nextjs',\n      renderer: '@storybook/react',\n      builder: '@storybook/builder-webpack5',\n    },\n    modifications: {\n      useCsfFactory: true,\n      mainConfig: {\n        features: {\n          experimentalRSC: true,\n          developmentModeForBuild: true,\n          experimentalTestSyntax: true,\n        },\n      },\n      extraDependencies: ['server-only', 'prop-types'],\n    },\n    initOptions: {\n      builder: SupportedBuilder.WEBPACK5,\n    },\n    skipTasks: ['bench', 'vitest-integration'],\n  },\n  'nextjs/prerelease': {\n    name: 'Next.js Prerelease (Webpack | TypeScript)',\n    script:\n      'npx create-next-app@canary {{beforeDir}} --eslint --tailwind --app --import-alias=\"@/*\" --src-dir',\n    expected: {\n      framework: '@storybook/nextjs',\n      renderer: '@storybook/react',\n      builder: '@storybook/builder-webpack5',\n    },\n    modifications: {\n      useCsfFactory: true,\n      mainConfig: {\n        features: {\n          experimentalRSC: true,\n          developmentModeForBuild: true,\n          experimentalTestSyntax: true,\n        },\n      },\n      extraDependencies: ['server-only', 'prop-types'],\n    },\n    initOptions: {\n      builder: SupportedBuilder.WEBPACK5,\n    },\n    skipTasks: ['e2e-tests', 'bench', 'vitest-integration'],\n  },\n  'nextjs-vite/14-ts': {\n    name: 'Next.js v14 (Vite | TypeScript)',\n    script:\n      'npx create-next-app@^14 {{beforeDir}} --eslint --tailwind --app --import-alias=\"@/*\" --src-dir',\n    expected: {\n      framework: '@storybook/nextjs-vite',\n      renderer: '@storybook/react',\n      builder: '@storybook/builder-vite',\n    },\n    modifications: {\n      useCsfFactory: true,\n      mainConfig: {\n        framework: '@storybook/nextjs-vite',\n        features: {\n          experimentalRSC: true,\n          developmentModeForBuild: true,\n          experimentalTestSyntax: true,\n        },\n      },\n      extraDependencies: ['server-only', 'vite', 'prop-types'],\n    },\n    skipTasks: ['e2e-tests', 'bench'],\n  },\n  'nextjs-vite/15-ts': {\n    name: 'Next.js v15 (Vite | TypeScript)',\n    script:\n      'npx create-next-app@^15 {{beforeDir}} --eslint --tailwind --app --import-alias=\"@/*\" --src-dir',\n    expected: {\n      framework: '@storybook/nextjs-vite',\n      renderer: '@storybook/react',\n      builder: '@storybook/builder-vite',\n    },\n    modifications: {\n      useCsfFactory: true,\n      mainConfig: {\n        framework: '@storybook/nextjs-vite',\n        features: {\n          experimentalRSC: true,\n          developmentModeForBuild: true,\n          experimentalTestSyntax: true,\n        },\n      },\n      extraDependencies: ['server-only', 'vite', 'prop-types'],\n    },\n    skipTasks: ['e2e-tests', 'bench'],\n  },\n  'nextjs-vite/default-ts': {\n    name: 'Next.js Latest (Vite | TypeScript)',\n    script:\n      'npx create-next-app {{beforeDir}} --eslint --no-tailwind --app --import-alias=\"@/*\" --src-dir',\n    expected: {\n      framework: '@storybook/nextjs-vite',\n      renderer: '@storybook/react',\n      builder: '@storybook/builder-vite',\n    },\n    modifications: {\n      useCsfFactory: true,\n      mainConfig: {\n        framework: '@storybook/nextjs-vite',\n        features: {\n          experimentalRSC: true,\n          developmentModeForBuild: true,\n          experimentalTestSyntax: true,\n        },\n      },\n      extraDependencies: ['server-only', 'vite', 'prop-types'],\n    },\n    skipTasks: ['bench'],\n  },\n  'react-vite/default-js': {\n    name: 'React Latest (Vite | JavaScript)',\n    script: 'npm create vite --yes {{beforeDir}} -- --template react',\n    expected: {\n      framework: '@storybook/react-vite',\n      renderer: '@storybook/react',\n      builder: '@storybook/builder-vite',\n    },\n    modifications: {\n      useCsfFactory: true,\n      extraDependencies: ['prop-types'],\n      mainConfig: {\n        features: {\n          developmentModeForBuild: true,\n          experimentalTestSyntax: true,\n        },\n      },\n    },\n    skipTasks: ['e2e-tests', 'bench'],\n  },\n  'react-vite/default-ts': {\n    name: 'React Latest (Vite | TypeScript)',\n    script: 'npm create vite --yes {{beforeDir}} -- --template react-ts',\n    expected: {\n      framework: '@storybook/react-vite',\n      renderer: '@storybook/react',\n      builder: '@storybook/builder-vite',\n    },\n    modifications: {\n      useCsfFactory: true,\n      extraDependencies: ['prop-types', '@types/prop-types', '@storybook/addon-mcp'],\n      editAddons: (addons) => [...addons, '@storybook/addon-mcp'],\n      mainConfig: {\n        features: {\n          developmentModeForBuild: true,\n          experimentalTestSyntax: true,\n        },\n      },\n    },\n    skipTasks: ['bench'],\n    typeCheck: true,\n  },\n  'react-vite/prerelease-ts': {\n    name: 'React Prerelease (Vite | TypeScript)',\n    /**\n     * 1. Create a Vite project with the React template\n     * 2. Add React beta versions\n     * 3. Add resolutions for react, react-dom,@types/react and @types/react-dom, see\n     *    https://react.dev/blog/2024/04/25/react-19-upgrade-guide#installing\n     * 4. Add @types/react and @types/react-dom pointing to the beta packages\n     */\n    script: `\n      npm create vite --yes {{beforeDir}} -- --template react-ts && \\\n      cd {{beforeDir}} && \\\n      jq '.resolutions += {\"@types/react\": \"npm:types-react@beta\", \"@types/react-dom\": \"npm:types-react-dom@beta\", \"react\": \"npm:react@beta\", \"react-dom\": \"npm:react-dom@beta\"}' package.json > tmp.json && mv tmp.json package.json && \\\n      yarn add react@beta react-dom@beta && \\\n      yarn add --dev @types/react@npm:types-react@beta @types/react-dom@npm:types-react-dom@beta\n      `,\n    expected: {\n      framework: '@storybook/react-vite',\n      renderer: '@storybook/react',\n      builder: '@storybook/builder-vite',\n    },\n    modifications: {\n      useCsfFactory: true,\n      extraDependencies: ['prop-types'],\n      mainConfig: {\n        features: {\n          developmentModeForBuild: true,\n          experimentalTestSyntax: true,\n        },\n      },\n    },\n    skipTasks: ['e2e-tests', 'bench'],\n  },\n  'react-webpack/18-ts': {\n    name: 'React Latest (Webpack | TypeScript)',\n    script: 'yarn create webpack5-react {{beforeDir}}',\n    expected: {\n      framework: '@storybook/react-webpack5',\n      renderer: '@storybook/react',\n      builder: '@storybook/builder-webpack5',\n    },\n    modifications: {\n      useCsfFactory: true,\n      extraDependencies: ['prop-types'],\n      mainConfig: {\n        features: {\n          experimentalTestSyntax: true,\n        },\n      },\n    },\n    skipTasks: ['e2e-tests', 'bench', 'vitest-integration'],\n  },\n  'react-webpack/17-ts': {\n    name: 'React v17 (Webpack | TypeScript)',\n    script:\n      'yarn create webpack5-react {{beforeDir}} --version-react=\"17\" --version-react-dom=\"17\"',\n    expected: {\n      framework: '@storybook/react-webpack5',\n      renderer: '@storybook/react',\n      builder: '@storybook/builder-webpack5',\n    },\n    modifications: {\n      useCsfFactory: true,\n      extraDependencies: ['prop-types'],\n      mainConfig: {\n        features: {\n          experimentalTestSyntax: true,\n        },\n      },\n    },\n    skipTasks: ['e2e-tests', 'bench', 'vitest-integration'],\n  },\n  'react-webpack/prerelease-ts': {\n    name: 'React Prerelease (Webpack | TypeScript)',\n    /**\n     * 1. Create a Webpack project with React beta versions\n     * 2. Add resolutions for @types/react and @types/react-dom, see\n     *    https://react.dev/blog/2024/04/25/react-19-upgrade-guide#installing\n     * 3. Add @types/react and @types/react-dom pointing to the beta packages\n     */\n    script: `\n      yarn create webpack5-react {{beforeDir}} --version-react=\"beta\" --version-react-dom=\"beta\" && \\\n      cd {{beforeDir}} && \\\n      jq '.resolutions += {\"@types/react\": \"npm:types-react@beta\", \"@types/react-dom\": \"npm:types-react-dom@beta\"}' package.json > tmp.json && mv tmp.json package.json && \\\n      yarn add --dev @types/react@npm:types-react@beta @types/react-dom@npm:types-react-dom@beta\n      `,\n    expected: {\n      framework: '@storybook/react-webpack5',\n      renderer: '@storybook/react',\n      builder: '@storybook/builder-webpack5',\n    },\n    modifications: {\n      useCsfFactory: true,\n      extraDependencies: ['prop-types'],\n      mainConfig: {\n        features: {\n          experimentalTestSyntax: true,\n        },\n      },\n    },\n    skipTasks: ['e2e-tests', 'bench', 'vitest-integration'],\n  },\n  'react-rsbuild/default-ts': {\n    name: 'React Latest (RsBuild | TypeScript)',\n    script: 'yarn create rsbuild -d {{beforeDir}} -t react-ts --tools eslint',\n    expected: {\n      framework: 'storybook-react-rsbuild',\n      renderer: '@storybook/react',\n      builder: 'storybook-builder-rsbuild',\n    },\n    modifications: {\n      extraDependencies: ['prop-types'],\n      useCsfFactory: true,\n      mainConfig: {\n        features: {\n          experimentalTestSyntax: true,\n        },\n      },\n      skipMocking: true,\n    },\n    skipTasks: ['e2e-tests', 'e2e-tests-dev', 'bench', 'vitest-integration'],\n  },\n  'solid-vite/default-ts': {\n    name: 'SolidJS Latest (Vite | TypeScript)',\n    script: 'yarn create solid {{beforeDir}} --vanilla --ts --template=with-vitest',\n    expected: {\n      framework: 'storybook-solidjs-vite',\n      renderer: 'storybook-solidjs-vite',\n      builder: '@storybook/builder-vite',\n    },\n    skipTasks: ['e2e-tests', 'e2e-tests-dev', 'bench', 'vitest-integration'],\n  },\n  'vue3-vite/default-js': {\n    name: 'Vue v3 (Vite | JavaScript)',\n    script: 'npm create vite --yes {{beforeDir}} -- --template vue',\n    expected: {\n      framework: '@storybook/vue3-vite',\n      renderer: '@storybook/vue3',\n      builder: '@storybook/builder-vite',\n    },\n    modifications: {\n      useCsfFactory: true,\n    },\n    skipTasks: ['e2e-tests', 'bench'],\n  },\n  'vue3-vite/default-ts': {\n    name: 'Vue v3 (Vite | TypeScript)',\n    script: 'npm create vite --yes {{beforeDir}} -- --template vue-ts',\n    expected: {\n      framework: '@storybook/vue3-vite',\n      renderer: '@storybook/vue3',\n      builder: '@storybook/builder-vite',\n    },\n    modifications: {\n      useCsfFactory: true,\n    },\n    skipTasks: ['bench'],\n  },\n  'vue3-rsbuild/default-ts': {\n    name: 'Vue Latest (RsBuild | TypeScript)',\n    script: 'yarn create rsbuild -d {{beforeDir}} -t vue-ts --tools eslint',\n    expected: {\n      framework: 'storybook-vue3-rsbuild',\n      renderer: '@storybook/vue3',\n      builder: 'storybook-builder-rsbuild',\n    },\n    modifications: {\n      extraDependencies: ['storybook-vue3-rsbuild@^3.0.0-beta.1'],\n      mainConfig: {\n        features: {\n          experimentalTestSyntax: true,\n        },\n      },\n      skipMocking: true,\n    },\n    skipTasks: ['e2e-tests', 'e2e-tests-dev', 'bench', 'vitest-integration'],\n  },\n  // 'nuxt-vite/default-ts': {\n  //   name: 'Nuxt v3 (Vite | TypeScript)',\n  //   script: 'npx nuxi init --packageManager yarn --gitInit false -M @nuxt/ui {{beforeDir}}',\n  //   expected: {\n  //     framework: '@storybook-vue/nuxt',\n  //     renderer: '@storybook/vue3',\n  //     builder: '@storybook/builder-vite',\n  //   },\n  //   skipTasks: ['e2e-tests', 'bench', 'vitest-integration'],\n  // },\n  'html-vite/default-js': {\n    name: 'HTML Latest (Vite | JavaScript)',\n    script:\n      'npm create vite --yes {{beforeDir}} -- --template vanilla && cd {{beforeDir}} && echo \"export default {}\" > vite.config.js',\n    expected: {\n      framework: '@storybook/html-vite',\n      renderer: '@storybook/html',\n      builder: '@storybook/builder-vite',\n    },\n    skipTasks: ['e2e-tests', 'bench'],\n    initOptions: {\n      type: ProjectType.HTML,\n    },\n  },\n  'html-vite/default-ts': {\n    name: 'HTML Latest (Vite | TypeScript)',\n    script:\n      'npm create vite --yes {{beforeDir}} -- --template vanilla-ts && cd {{beforeDir}} && echo \"export default {}\" > vite.config.js',\n    expected: {\n      framework: '@storybook/html-vite',\n      renderer: '@storybook/html',\n      builder: '@storybook/builder-vite',\n    },\n    skipTasks: ['e2e-tests', 'bench'],\n    initOptions: {\n      type: ProjectType.HTML,\n    },\n  },\n  'html-rsbuild/default-ts': {\n    name: 'HTML Latest (RsBuild | TypeScript)',\n    script: 'yarn create rsbuild -d {{beforeDir}} -t vanilla-ts --tools eslint',\n    expected: {\n      framework: 'storybook-html-rsbuild',\n      renderer: '@storybook/html',\n      builder: 'storybook-builder-rsbuild',\n    },\n    modifications: {\n      skipMocking: true,\n    },\n    skipTasks: ['e2e-tests', 'e2e-tests-dev', 'bench', 'vitest-integration'],\n    initOptions: {\n      type: ProjectType.HTML,\n    },\n  },\n  'svelte-vite/default-js': {\n    name: 'Svelte Latest (Vite | JavaScript)',\n    script: 'npm create vite --yes {{beforeDir}} -- --template svelte',\n    expected: {\n      framework: '@storybook/svelte-vite',\n      renderer: '@storybook/svelte',\n      builder: '@storybook/builder-vite',\n    },\n    skipTasks: ['e2e-tests', 'bench'],\n  },\n  'svelte-vite/default-ts': {\n    name: 'Svelte Latest (Vite | TypeScript)',\n    script: 'npm create vite --yes {{beforeDir}} -- --template svelte-ts',\n    expected: {\n      framework: '@storybook/svelte-vite',\n      renderer: '@storybook/svelte',\n      builder: '@storybook/builder-vite',\n    },\n    // Remove smoke-test from the list once https://github.com/storybookjs/storybook/issues/19351 is fixed.\n    skipTasks: ['smoke-test', 'bench'],\n  },\n  'svelte-kit/skeleton-ts': {\n    name: 'SvelteKit Latest (Vite | TypeScript)',\n    script:\n      'npx sv@latest create --template minimal --types ts --no-add-ons --no-install {{beforeDir}}',\n    expected: {\n      framework: '@storybook/sveltekit',\n      renderer: '@storybook/svelte',\n      builder: '@storybook/builder-vite',\n    },\n    skipTasks: ['e2e-tests', 'bench'],\n  },\n  'angular-cli/prerelease': {\n    name: 'Angular CLI Prerelease (Webpack | TypeScript)',\n    script:\n      'npx -p @angular/cli@next ng new angular-v16 --directory {{beforeDir}} --routing=true --minimal=true --style=scss --strict --skip-git --skip-install --package-manager=yarn --ssr',\n    modifications: {\n      // extraDependencies: ['@standard-schema/spec@^1', '@angular/forms@next'],\n      useCsfFactory: true,\n    },\n    extraCiSteps: {\n      ensureMinNodeVersion: true,\n    },\n    expected: {\n      framework: '@storybook/angular',\n      renderer: '@storybook/angular',\n      builder: '@storybook/builder-webpack5',\n    },\n    skipTasks: ['e2e-tests', 'bench', 'vitest-integration'],\n  },\n  'angular-cli/default-ts': {\n    name: 'Angular CLI Latest (Webpack | TypeScript)',\n    script:\n      'npx -p @angular/cli ng new angular-latest --directory {{beforeDir}} --routing=true --minimal=true --style=scss --strict --skip-git --skip-install --package-manager=yarn --ssr',\n    modifications: {\n      extraDependencies: ['@angular/forms@latest'],\n      useCsfFactory: true,\n    },\n    extraCiSteps: {\n      ensureMinNodeVersion: true,\n    },\n    expected: {\n      framework: '@storybook/angular',\n      renderer: '@storybook/angular',\n      builder: '@storybook/builder-webpack5',\n    },\n    skipTasks: ['bench', 'vitest-integration'],\n  },\n  'lit-vite/default-js': {\n    name: 'Lit Latest (Vite | JavaScript)',\n    script:\n      'npm create vite --yes {{beforeDir}} -- --template lit && cd {{beforeDir}} && echo \"export default {}\" > vite.config.js',\n    expected: {\n      framework: '@storybook/web-components-vite',\n      renderer: '@storybook/web-components',\n      builder: '@storybook/builder-vite',\n    },\n    modifications: {\n      useCsfFactory: true,\n    },\n    // Remove smoke-test from the list once https://github.com/storybookjs/storybook/issues/19351 is fixed.\n    skipTasks: ['smoke-test', 'e2e-tests', 'bench'],\n  },\n  'lit-vite/default-ts': {\n    name: 'Lit Latest (Vite | TypeScript)',\n    script:\n      'npm create vite --yes {{beforeDir}} -- --template lit-ts && cd {{beforeDir}} && echo \"export default {}\" > vite.config.js',\n    expected: {\n      framework: '@storybook/web-components-vite',\n      renderer: '@storybook/web-components',\n      builder: '@storybook/builder-vite',\n    },\n    modifications: {\n      useCsfFactory: true,\n    },\n    // Remove smoke-test from the list once https://github.com/storybookjs/storybook/issues/19351 is fixed.\n    skipTasks: ['smoke-test', 'e2e-tests', 'bench'],\n  },\n  'lit-rsbuild/default-ts': {\n    name: 'Web Components Latest (RsBuild | TypeScript)',\n    script: 'yarn create rsbuild -d {{beforeDir}} -t lit-ts --tools eslint',\n    expected: {\n      framework: 'storybook-web-components-rsbuild',\n      renderer: '@storybook/web-components',\n      builder: 'storybook-builder-rsbuild',\n    },\n    modifications: {\n      skipMocking: true,\n    },\n    skipTasks: ['e2e-tests', 'e2e-tests-dev', 'bench', 'vitest-integration'],\n  },\n  'preact-vite/default-js': {\n    name: 'Preact Latest (Vite | JavaScript)',\n    script: 'npm create vite --yes {{beforeDir}} -- --template preact',\n    expected: {\n      framework: '@storybook/preact-vite',\n      renderer: '@storybook/preact',\n      builder: '@storybook/builder-vite',\n    },\n    modifications: {\n      extraDependencies: ['preact-render-to-string'],\n    },\n    skipTasks: ['e2e-tests', 'bench'],\n  },\n  'preact-vite/default-ts': {\n    name: 'Preact Latest (Vite | TypeScript)',\n    script: 'npm create vite --yes {{beforeDir}} -- --template preact-ts',\n    expected: {\n      framework: '@storybook/preact-vite',\n      renderer: '@storybook/preact',\n      builder: '@storybook/builder-vite',\n    },\n    modifications: {\n      extraDependencies: ['preact-render-to-string'],\n    },\n    skipTasks: ['e2e-tests', 'bench'],\n  },\n  /** This is currently broken, we generate components and stories that do not work */\n  // 'qwik-vite/default-ts': {\n  //   name: 'Qwik CLI Latest (Vite | TypeScript)',\n  //   script: 'npm create qwik playground {{beforeDir}}',\n  //   // TODO: The community template does not provide standard stories, which is required for e2e tests. Reenable once it does.\n  //   inDevelopment: true,\n  //   expected: {\n  //     framework: 'storybook-framework-qwik',\n  //     renderer: 'storybook-framework-qwik',\n  //     builder: 'storybook-framework-qwik',\n  //   },\n  //   // TODO: The community template does not provide standard stories, which is required for e2e tests.\n  //   skipTasks: ['e2e-tests-dev', 'e2e-tests', 'bench', 'vitest-integration', 'chromatic'],\n  // },\n  'ember/3-js': {\n    name: 'Ember v3 (Webpack | JavaScript)',\n    script: 'npx --package ember-cli@3.28.1 ember new {{beforeDir}}',\n    inDevelopment: true,\n    expected: {\n      framework: '@storybook/ember',\n      renderer: '@storybook/ember',\n      builder: '@storybook/builder-webpack5',\n    },\n  },\n  'ember/default-js': {\n    name: 'Ember v4 (Webpack | JavaScript)',\n    script:\n      'npx --package ember-cli@4.12.1 ember new {{beforeDir}} --yarn && cd {{beforeDir}} && yarn add --dev @storybook/ember-cli-storybook && yarn build',\n    inDevelopment: true,\n    expected: {\n      framework: '@storybook/ember',\n      renderer: '@storybook/ember',\n      builder: '@storybook/builder-webpack5',\n    },\n  },\n  'react-native-web-vite/expo-ts': {\n    // NOTE: create-expo-app installs React 18.2.0. But yarn portal\n    // expects 18.3.1 (dunno why). Therefore to run this in dev you\n    // must either:\n    //  - edit the sandbox package.json to depend on react 18.3.1, OR\n    //  - build/run the sandbox in --no-link mode, which is fine\n    //\n    // Users & CI won't see this limitation because they are not using\n    // yarn portals.\n    name: 'React Native Expo Latest (Vite | TypeScript)',\n    script: 'npx create-expo-app -y {{beforeDir}}',\n    expected: {\n      framework: '@storybook/react-native-web-vite',\n      renderer: '@storybook/react',\n      builder: '@storybook/builder-vite',\n    },\n    modifications: {\n      useCsfFactory: true,\n      mainConfig: {\n        features: {\n          experimentalTestSyntax: true,\n        },\n      },\n    },\n    skipTasks: ['bench', 'vitest-integration'],\n    initOptions: {\n      type: ProjectType.REACT_NATIVE_WEB,\n    },\n  },\n  'react-native-web-vite/rn-cli-ts': {\n    // NOTE: create-expo-app installs React 18.2.0. But yarn portal\n    // expects 18.3.1 (dunno why). Therefore to run this in dev you\n    // must either:\n    //  - edit the sandbox package.json to depend on react 18.3.1, OR\n    //  - build/run the sandbox in --no-link mode, which is fine\n    //\n    // Users & CI won't see this limitation because they are not using\n    // yarn portals.\n    name: 'React Native CLI Latest (Vite | TypeScript)',\n    script:\n      'npx @react-native-community/cli@latest init --install-pods=false --directory={{beforeDir}} rnapp',\n    expected: {\n      framework: '@storybook/react-native-web-vite',\n      renderer: '@storybook/react',\n      builder: '@storybook/builder-vite',\n    },\n    skipTasks: ['e2e-tests', 'bench', 'vitest-integration'],\n    initOptions: {\n      type: ProjectType.REACT_NATIVE_WEB,\n    },\n  },\n} satisfies Record<string, BaseTemplates>;\n\n/**\n * Internal templates reuse config from other templates and add extra config on top. They must\n * contain an id that starts with 'internal/' and contain \"isInternal: true\". They will be hidden by\n * default in the Storybook status page.\n */\nconst internalTemplates = {\n  'internal/react18-webpack-babel': {\n    name: 'React with Babel Latest (Webpack | TypeScript)',\n    script: 'yarn create webpack5-react {{beforeDir}}',\n    expected: {\n      framework: '@storybook/react-webpack5',\n      renderer: '@storybook/react',\n      builder: '@storybook/builder-webpack5',\n    },\n    modifications: {\n      useCsfFactory: true,\n      extraDependencies: ['@storybook/addon-webpack5-compiler-babel', 'prop-types'],\n      editAddons: (addons) =>\n        [...addons, '@storybook/addon-webpack5-compiler-babel'].filter(\n          (a) => a !== '@storybook/addon-webpack5-compiler-swc'\n        ),\n      mainConfig: {\n        features: {\n          experimentalTestSyntax: true,\n        },\n      },\n    },\n    isInternal: true,\n    skipTasks: ['e2e-tests', 'bench', 'vitest-integration'],\n  },\n  'internal/react16-webpack': {\n    name: 'React 16 (Webpack | TypeScript)',\n    script:\n      'yarn create webpack5-react {{beforeDir}} --version-react=16 --version-react-dom=16 --version-@types/react=16 --version-@types/react-dom=16',\n    expected: {\n      framework: '@storybook/react-webpack5',\n      renderer: '@storybook/react',\n      builder: '@storybook/builder-webpack5',\n    },\n    modifications: {\n      useCsfFactory: true,\n      extraDependencies: ['prop-types'],\n      mainConfig: {\n        features: {\n          experimentalTestSyntax: true,\n        },\n      },\n    },\n    skipTasks: ['e2e-tests', 'bench', 'vitest-integration'],\n    isInternal: true,\n  },\n  'internal/server-webpack5': {\n    name: 'Server Webpack5',\n    script: 'yarn init -y && echo \"module.exports = {}\" > webpack.config.js',\n    expected: {\n      framework: '@storybook/server-webpack5',\n      renderer: '@storybook/server',\n      builder: '@storybook/builder-webpack5',\n    },\n    isInternal: true,\n    skipTasks: ['bench', 'vitest-integration'],\n    initOptions: {\n      type: ProjectType.SERVER,\n    },\n  },\n} satisfies Record<`internal/${string}`, Template & { isInternal: true }>;\n\nconst benchTemplates = {\n  'bench/react-vite-default-ts': {\n    ...baseTemplates['react-vite/default-ts'],\n    name: 'Bench (react-vite/default-ts)',\n    isInternal: true,\n    modifications: {\n      skipTemplateStories: true,\n      skipMocking: true,\n    },\n    skipTasks: [\n      'e2e-tests',\n      'test-runner',\n      'test-runner-dev',\n      'e2e-tests-dev',\n      'chromatic',\n      'vitest-integration',\n    ],\n    typeCheck: false,\n  },\n  'bench/react-webpack-18-ts': {\n    ...baseTemplates['react-webpack/18-ts'],\n    name: 'Bench (react-webpack/18-ts)',\n    isInternal: true,\n    modifications: {\n      skipTemplateStories: true,\n      skipMocking: true,\n    },\n    skipTasks: [\n      'e2e-tests',\n      'test-runner',\n      'test-runner-dev',\n      'e2e-tests-dev',\n      'chromatic',\n      'vitest-integration',\n    ],\n  },\n  'bench/react-vite-default-ts-nodocs': {\n    ...baseTemplates['react-vite/default-ts'],\n    name: 'Bench (react-vite/default-ts, no docs)',\n    isInternal: true,\n    modifications: {\n      skipTemplateStories: true,\n      disableDocs: true,\n      skipMocking: true,\n    },\n    skipTasks: [\n      'e2e-tests',\n      'test-runner',\n      'test-runner-dev',\n      'e2e-tests-dev',\n      'chromatic',\n      'vitest-integration',\n    ],\n    typeCheck: false,\n  },\n  'bench/react-vite-default-ts-test-build': {\n    ...baseTemplates['react-vite/default-ts'],\n    name: 'Bench (react-vite/default-ts, test-build)',\n    isInternal: true,\n    modifications: {\n      skipTemplateStories: true,\n      testBuild: true,\n      skipMocking: true,\n    },\n    skipTasks: [\n      'e2e-tests',\n      'test-runner',\n      'test-runner-dev',\n      'e2e-tests-dev',\n      'vitest-integration',\n    ],\n    typeCheck: false,\n  },\n  'bench/react-webpack-18-ts-test-build': {\n    ...baseTemplates['react-webpack/18-ts'],\n    name: 'Bench (react-webpack/18-ts, test-build)',\n    isInternal: true,\n    modifications: {\n      skipTemplateStories: true,\n      testBuild: true,\n      skipMocking: true,\n    },\n    skipTasks: [\n      'e2e-tests',\n      'test-runner',\n      'test-runner-dev',\n      'e2e-tests-dev',\n      'vitest-integration',\n    ],\n  },\n} satisfies Record<string, Template & { isInternal: true }>;\n\nexport const allTemplates: Record<TemplateKey, Template> = {\n  ...baseTemplates,\n  ...internalTemplates,\n  ...benchTemplates,\n};\n\nexport const normal: TemplateKey[] = [\n  // TODO: Add this back once we resolve the React 19 issues\n  // 'cra/default-ts',\n  'react-vite/default-ts',\n  'angular-cli/default-ts',\n  'vue3-vite/default-ts',\n  // 'nuxt-vite/default-ts', // temporarily disabled because it's broken\n  'lit-vite/default-ts',\n  'svelte-vite/default-ts',\n  'svelte-kit/skeleton-ts',\n  'nextjs/default-ts',\n  'nextjs-vite/default-ts',\n  'bench/react-vite-default-ts',\n  'bench/react-webpack-18-ts',\n  'bench/react-vite-default-ts-nodocs',\n  'bench/react-vite-default-ts-test-build',\n  'bench/react-webpack-18-ts-test-build',\n  // 'ember/default-js',\n  'react-rsbuild/default-ts',\n];\n\nexport const merged: TemplateKey[] = [\n  ...normal,\n  'react-webpack/18-ts',\n  'react-webpack/17-ts',\n  'nextjs/15-ts',\n  'nextjs-vite/15-ts',\n  'preact-vite/default-ts',\n  'html-vite/default-ts',\n  'solid-vite/default-ts',\n  'vue3-rsbuild/default-ts',\n];\n\nexport const daily: TemplateKey[] = [\n  ...merged,\n  'angular-cli/prerelease',\n  // TODO: Add this back once we resolve the React 19 issues\n  // 'cra/default-js',\n  'react-vite/default-js',\n  'react-vite/prerelease-ts',\n  'react-webpack/prerelease-ts',\n  'nextjs-vite/14-ts',\n  'nextjs/14-ts',\n  'vue3-vite/default-js',\n  'lit-vite/default-js',\n  'svelte-vite/default-js',\n  'nextjs/prerelease',\n  // 'qwik-vite/default-ts',\n  'preact-vite/default-js',\n  'html-vite/default-js',\n  'internal/react16-webpack',\n  'internal/react18-webpack-babel',\n  'react-native-web-vite/expo-ts',\n  'lit-rsbuild/default-ts',\n  'html-rsbuild/default-ts',\n  // 'react-native-web-vite/rn-cli-ts',\n];\n\nexport const templatesByCadence = { normal, merged, daily };\n"
  },
  {
    "path": "code/lib/cli-storybook/src/sandbox.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { mkdir, readdir, rm } from 'node:fs/promises';\nimport { isAbsolute } from 'node:path';\n\nimport { PackageManagerName } from 'storybook/internal/common';\nimport {\n  JsPackageManagerFactory,\n  isCI,\n  optionalEnvToBoolean,\n  versions,\n} from 'storybook/internal/common';\nimport { logger, prompt } from 'storybook/internal/node-logger';\n\nimport { sync as spawnSync } from 'cross-spawn';\nimport { join } from 'pathe';\nimport picocolors from 'picocolors';\nimport { lt, prerelease } from 'semver';\nimport invariant from 'tiny-invariant';\nimport { dedent } from 'ts-dedent';\n\nimport type { Template, TemplateKey } from './sandbox-templates.ts';\nimport { allTemplates as TEMPLATES } from './sandbox-templates.ts';\n\ninterface SandboxOptions {\n  filterValue?: string;\n  output?: string;\n  branch?: string;\n  init?: boolean;\n  packageManager: PackageManagerName;\n}\ntype Choice = keyof typeof TEMPLATES;\n\nconst toChoices = (c: Choice) => ({ label: TEMPLATES[c].name, value: c });\n\nexport const sandbox = async ({\n  output: outputDirectory,\n  filterValue,\n  init,\n  ...options\n}: SandboxOptions) => {\n  // Either get a direct match when users pass a template id, or filter through all templates\n  let selectedConfig: Template | undefined = TEMPLATES[filterValue as TemplateKey];\n  let templateId: Choice | null = selectedConfig ? (filterValue as TemplateKey) : null;\n\n  // Always use npm to fetch versions, as other package manager commands may fail when running in\n  // non-project directories (e.g. parent sandbox directory). We just need to use npm info for this use case.\n  const packageManager = JsPackageManagerFactory.getPackageManager({\n    force: PackageManagerName.NPM,\n  });\n  const latestVersion = (await packageManager.latestVersion('storybook'))!;\n  const nextVersion = (await packageManager.latestVersion('storybook@next')) ?? '0.0.0';\n  const currentVersion = versions.storybook;\n  const isPrerelease = prerelease(currentVersion);\n  const isOutdated = lt(currentVersion, isPrerelease ? nextVersion : latestVersion);\n\n  const downloadType = !isOutdated && init ? 'after-storybook' : 'before-storybook';\n  const branch = isPrerelease ? 'next' : 'main';\n\n  const messages = {\n    welcome: `Creating a Storybook ${picocolors.bold(currentVersion)} sandbox..`,\n    notLatest: picocolors.red(dedent`\n      This version is behind the latest release, which is: ${picocolors.bold(latestVersion)}!\n      You likely ran the init command through npx, which can use a locally cached version, to get the latest please run:\n      ${picocolors.bold('npx storybook@latest sandbox')}\n      \n      You may want to CTRL+C to stop, and run with the latest version instead.\n    `),\n    longInitTime: picocolors.yellow(\n      'The creation of the sandbox will take longer, because we will need to run init.'\n    ),\n    prerelease: picocolors.yellow('This is a pre-release version.'),\n  };\n\n  logger.logBox(\n    [messages.welcome]\n      .concat(isOutdated && !isPrerelease ? [messages.notLatest] : [])\n      .concat(init && (isOutdated || isPrerelease) ? [messages.longInitTime] : [])\n      .concat(isPrerelease ? [messages.prerelease] : [])\n      .join('\\n'),\n    {\n      rounded: true,\n    }\n  );\n\n  if (!selectedConfig) {\n    const filterRegex = new RegExp(`^${filterValue || ''}`, 'i');\n\n    const keys = Object.keys(TEMPLATES) as Choice[];\n    // get value from template and reduce through TEMPLATES to filter out the correct template\n    const choices = keys.reduce<Choice[]>((acc, group) => {\n      const current = TEMPLATES[group];\n\n      if (!filterValue) {\n        acc.push(group);\n        return acc;\n      }\n\n      if (\n        current.name.match(filterRegex) ||\n        group.match(filterRegex) ||\n        current.expected.builder.match(filterRegex) ||\n        current.expected.framework.match(filterRegex) ||\n        current.expected.renderer.match(filterRegex)\n      ) {\n        acc.push(group);\n        return acc;\n      }\n\n      return acc;\n    }, []);\n\n    if (choices.length === 0) {\n      logger.logBox(\n        dedent`\n            🔎 You filtered out all templates. 🔍\n\n            After filtering all the templates with \"${picocolors.yellow(\n              filterValue\n            )}\", we found no results. Please try again with a different filter.\n\n            Available templates:\n            ${keys.map((key) => picocolors.blue(`- ${key}`)).join('\\n')}\n            `.trim(),\n        { borderStyle: 'round', padding: 1, borderColor: '#F1618C' } as any\n      );\n      process.exit(1);\n    }\n\n    if (choices.length === 1) {\n      [templateId] = choices;\n    } else {\n      logger.logBox(\n        dedent`\n            🤗 Welcome to ${picocolors.yellow('sb sandbox')}! 🤗\n\n            Create a ${picocolors.green('new project')} to minimally reproduce Storybook issues.\n\n            1. select an environment that most closely matches your project setup.\n            2. select a location for the reproduction, outside of your project.\n\n            After the reproduction is ready, we'll guide you through the next steps.\n            `.trim(),\n        { borderStyle: 'round', padding: 1, borderColor: '#F1618C' } as any\n      );\n\n      templateId = await promptSelectedTemplate(choices);\n    }\n\n    const hasSelectedTemplate = !!(templateId ?? null);\n    if (!hasSelectedTemplate) {\n      logger.error('Somehow we got no templates. Please rerun this command!');\n      return;\n    }\n\n    selectedConfig = templateId ? TEMPLATES[templateId] : undefined;\n\n    if (!selectedConfig) {\n      // eslint-disable-next-line local-rules/no-uncategorized-errors\n      throw new Error('🚨 Sandbox: please specify a valid template type');\n    }\n  }\n\n  let selectedDirectory = outputDirectory;\n  const outputDirectoryName = outputDirectory || templateId;\n  if (selectedDirectory && existsSync(`${selectedDirectory}`)) {\n    logger.log(`⚠️  ${selectedDirectory} already exists! Overwriting...`);\n    await rm(selectedDirectory, { recursive: true, force: true });\n  }\n\n  if (!selectedDirectory) {\n    const directory = await prompt.text(\n      {\n        message: 'Enter the output directory',\n        initialValue: outputDirectoryName ?? undefined,\n        validate: (directoryName) =>\n          directoryName && existsSync(directoryName)\n            ? `${directoryName} already exists. Please choose another name.`\n            : undefined,\n      },\n      {\n        onCancel: () => {\n          logger.log('Command cancelled by the user. Exiting...');\n          process.exit(1);\n        },\n      }\n    );\n    selectedDirectory = directory;\n  }\n  invariant(selectedDirectory);\n\n  try {\n    const templateDestination = isAbsolute(selectedDirectory)\n      ? selectedDirectory\n      : join(process.cwd(), selectedDirectory);\n\n    logger.log(`🏃 Adding ${selectedConfig.name} into ${templateDestination}`);\n\n    logger.log(`📦 Downloading sandbox template (${picocolors.bold(downloadType)})...`);\n    try {\n      // Download the sandbox based on subfolder \"after-storybook\" and selected branch\n      const gitPath = `storybookjs/sandboxes/tree/${branch}/${templateId}/${downloadType}`;\n      // create `templateDestination` first\n      await mkdir(templateDestination, { recursive: true });\n      spawnSync('npx', ['gitpick@4.12.4', gitPath, templateDestination, '-o'], {\n        stdio: 'inherit',\n      });\n      // throw an error if templateDestination is an empty directory\n      if ((await readdir(templateDestination)).length === 0) {\n        const selected = picocolors.yellow(templateId);\n        throw new Error(dedent`\n          Template downloaded from ${picocolors.blue(gitPath)} is empty.\n          Are you use it exists? Or did you want to set ${selected} to inDevelopment first?\n        `);\n      }\n\n      // when user wanted an sandbox that has been initiated, but force-downloaded the before-storybook directory\n      // then we need to initiate the sandbox\n      // this is to ensure we DO get the latest version of the template (output of the generator), but we initialize using the version of storybook that the CLI is.\n      // we warned the user about the fact they are running an old version of storybook\n      // we warned the user the sandbox step would take longer\n      if (downloadType === 'before-storybook' && init) {\n        const before = process.cwd();\n        process.chdir(templateDestination);\n        // we run doInitiate, instead of initiate, to avoid sending this init event to telemetry, because it's not a real world project\n        // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n        // @ts-ignore-error (no types for this)\n        const { initiate } = await import('create-storybook');\n        await initiate({\n          dev: isCI() && !optionalEnvToBoolean(process.env.IN_STORYBOOK_SANDBOX),\n          ...options,\n          ...(selectedConfig.initOptions || {}),\n          features: ['docs', 'test'],\n        });\n        process.chdir(before);\n      }\n    } catch (err) {\n      logger.error(`🚨 Failed to download sandbox template: ${String(err)}`);\n      throw err;\n    }\n\n    const initMessage = init\n      ? picocolors.yellow(dedent`\n          yarn install\n          yarn storybook\n        `)\n      : `Recreate your setup, then ${picocolors.yellow(`npx storybook@latest init`)}`;\n\n    logger.logBox(\n      dedent`\n        🎉 Your Storybook reproduction project is ready to use! 🎉\n\n        ${picocolors.yellow(`cd ${selectedDirectory}`)}\n        ${initMessage}\n\n        Once you've recreated the problem you're experiencing, please:\n\n        1. Document any additional steps in ${picocolors.cyan('README.md')}\n        2. Publish the repository to github\n        3. Link to the repro repository in your issue\n\n        Having a clean repro helps us solve your issue faster! 🙏\n      `.trim(),\n      { rounded: true }\n    );\n  } catch (error) {\n    logger.error('🚨 Failed to create sandbox');\n    throw error;\n  }\n};\n\nasync function promptSelectedTemplate(choices: Choice[]): Promise<Choice | null> {\n  // using any here as the types are too strict\n  const selected = await prompt.select<any>({\n    message: 'Select a template',\n    options: choices.map(toChoices),\n  });\n  return selected as Choice;\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/typings.d.ts",
    "content": "declare module 'envinfo';\ndeclare var LOGLEVEL: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent' | undefined;\n"
  },
  {
    "path": "code/lib/cli-storybook/src/upgrade.test.ts",
    "content": "import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type * as sbcc from 'storybook/internal/common';\nimport type { JsPackageManager } from 'storybook/internal/common';\n\nimport { getStorybookVersion } from './upgrade.ts';\nimport { generateUpgradeSpecs } from './util.ts';\n\nconst findInstallationsMock =\n  vi.fn<(arg: string[]) => Promise<sbcc.InstallationMetadata | undefined>>();\nconst getInstalledVersionMock = vi.fn<(arg: string) => Promise<string | undefined>>();\n\nvi.mock('storybook/internal/telemetry');\nvi.mock('storybook/internal/common', async (importOriginal) => {\n  const originalModule = (await importOriginal()) as typeof sbcc;\n  return {\n    ...originalModule,\n    JsPackageManagerFactory: {\n      getPackageManager: () => ({\n        findInstallations: findInstallationsMock,\n        getInstalledVersion: getInstalledVersionMock,\n        latestVersion: async () => '8.0.0',\n        getAllDependencies: () => ({ storybook: '8.0.0' }),\n        getModulePackageJSON: vi.fn(),\n      }),\n    },\n    versions: Object.keys(originalModule.versions).reduce(\n      (acc, key) => {\n        acc[key] = '9.0.0';\n        return acc;\n      },\n      {} as Record<string, string>\n    ),\n  };\n});\n\ndescribe.each([\n  ['│ │ │ ├── @babel/code-frame@7.10.3 deduped', null],\n  [\n    '├─┬ @storybook/preset-create-react-app@3.1.2',\n    { package: '@storybook/preset-create-react-app', version: '3.1.2' },\n  ],\n  ['│ ├─┬ @storybook/node-logger@5.3.19', { package: '@storybook/node-logger', version: '5.3.19' }],\n  [\n    'npm ERR! peer dep missing: @storybook/react@>=5.2, required by @storybook/preset-create-react-app@3.1.2',\n    null,\n  ],\n])('getStorybookVersion', (input, output) => {\n  it(`${input}`, () => {\n    expect(getStorybookVersion(input)).toEqual(output);\n  });\n});\n\ndescribe('toUpgradedDependencies', () => {\n  let mockPackageManager: JsPackageManager;\n\n  beforeEach(() => {\n    mockPackageManager = {\n      latestVersion: vi.fn(),\n    } as unknown as JsPackageManager;\n\n    vi.mocked(mockPackageManager.latestVersion).mockImplementation(async (packageName: string) => {\n      if (packageName === '@storybook/addon-designs@next') {\n        return '9.0.0-beta.1';\n      }\n      if (packageName === '@storybook/addon-designs') {\n        return '8.0.0';\n      }\n      if (packageName === '@chromatic-com/storybook@next') {\n        return '4.0.0';\n      }\n      if (packageName === '@chromatic-com/storybook') {\n        return '3.0.0';\n      }\n\n      return '9.0.0';\n    });\n  });\n\n  afterEach(() => {\n    vi.restoreAllMocks();\n  });\n\n  describe('core storybook packages', () => {\n    it('should upgrade Storybook core dependencies respecting the version modifier of the dependency to upgrade', async () => {\n      const deps = {\n        '@storybook/react': '8.0.0',\n        '@storybook/vue3': '~8.0.0',\n        '@storybook/svelte': '^8.0.0',\n        '@storybook/angular': '>=8.0.0',\n        // in this case, it uses the first modifier of the first version defined\n        '@storybook/html': '>8.0.0 || ^0.0.0-pr.0',\n        // invalid cases become fixed version\n        '@storybook/web-components': '*',\n        '@storybook/react-vite': 'workspace:*',\n        react: '18.0.0',\n      };\n\n      const result = await generateUpgradeSpecs(deps, {\n        packageManager: mockPackageManager,\n        isCanary: false,\n        isCLIOutdated: false,\n        isCLIPrerelease: false,\n        isCLIExactPrerelease: false,\n        isCLIExactLatest: false,\n      });\n\n      expect(result).toEqual([\n        '@storybook/react@9.0.0',\n        '@storybook/vue3@~9.0.0',\n        '@storybook/svelte@^9.0.0',\n        '@storybook/angular@>=9.0.0',\n        '@storybook/html@>9.0.0',\n        '@storybook/web-components@9.0.0',\n        '@storybook/react-vite@9.0.0',\n      ]);\n    });\n\n    it('should not add ^ for outdated CLI versions', async () => {\n      const deps = {\n        '@storybook/react': '^8.0.0',\n      };\n\n      const result = await generateUpgradeSpecs(deps, {\n        packageManager: mockPackageManager,\n        isCanary: false,\n        isCLIOutdated: true,\n        isCLIPrerelease: false,\n        isCLIExactPrerelease: false,\n        isCLIExactLatest: false,\n      });\n\n      expect(result).toEqual(['@storybook/react@9.0.0']);\n    });\n\n    it('should not add ^ for canary versions', async () => {\n      const deps = {\n        '@storybook/react': '^8.0.0',\n      };\n\n      const result = await generateUpgradeSpecs(deps, {\n        packageManager: mockPackageManager,\n        isCanary: true,\n        isCLIOutdated: false,\n        isCLIPrerelease: false,\n        isCLIExactPrerelease: false,\n        isCLIExactLatest: false,\n      });\n\n      expect(result).toEqual(['@storybook/react@9.0.0']);\n    });\n  });\n\n  describe('satellite packages', () => {\n    it('should include satellite dependencies for latest stable version', async () => {\n      const deps = {\n        '@storybook/react': '8.0.0',\n        '@storybook/addon-designs': '8.0.0',\n        '@storybook/test-runner': '^8.0.0',\n        '@chromatic-com/storybook': '~3.0.0',\n      };\n\n      const result = await generateUpgradeSpecs(deps, {\n        packageManager: mockPackageManager,\n        isCanary: false,\n        isCLIOutdated: false,\n        isCLIPrerelease: false,\n        isCLIExactPrerelease: false,\n        isCLIExactLatest: true,\n      });\n\n      expect(result).toEqual([\n        '@storybook/react@9.0.0',\n        '@storybook/addon-designs@8.0.0',\n        '@storybook/test-runner@^9.0.0',\n        '@chromatic-com/storybook@~3.0.0',\n      ]);\n      expect(mockPackageManager.latestVersion).toHaveBeenCalledWith('@storybook/addon-designs');\n    });\n\n    it('should include satellite dependencies with @next for prerelease version', async () => {\n      const deps = {\n        '@storybook/react': '^8.0.0',\n        '@storybook/addon-designs': '8.0.0',\n      };\n\n      const result = await generateUpgradeSpecs(deps, {\n        packageManager: mockPackageManager,\n        isCanary: false,\n        isCLIOutdated: false,\n        isCLIExactLatest: false,\n        isCLIExactPrerelease: true,\n        isCLIPrerelease: true,\n      });\n\n      expect(result).toContainEqual('@storybook/react@^9.0.0');\n      expect(result).toContainEqual('@storybook/addon-designs@9.0.0-beta.1');\n      expect(mockPackageManager.latestVersion).toHaveBeenCalledWith(\n        '@storybook/addon-designs@next'\n      );\n    });\n\n    it('should handle errors when fetching satellite dependencies', async () => {\n      const deps = {\n        '@storybook/react': '^8.0.0',\n        '@storybook/addon-designs': '8.0.0',\n      };\n\n      vi.mocked(mockPackageManager.latestVersion).mockRejectedValueOnce(\n        new Error('MOCKED Network error')\n      );\n\n      const result = await generateUpgradeSpecs(deps, {\n        packageManager: mockPackageManager,\n        isCanary: false,\n        isCLIOutdated: false,\n        isCLIExactLatest: true,\n        isCLIPrerelease: false,\n        isCLIExactPrerelease: false,\n      });\n\n      // Should still have the core dependencies\n      expect(result).toContainEqual('@storybook/react@^9.0.0');\n\n      // Satellite dependencies should be omitted due to the error\n      expect(result).not.toContainEqual(expect.stringContaining('@storybook/addon-designs'));\n    });\n  });\n\n  it('should handle empty dependencies', async () => {\n    const result = await generateUpgradeSpecs(\n      {},\n      {\n        packageManager: mockPackageManager,\n        isCanary: false,\n        isCLIOutdated: false,\n        isCLIPrerelease: false,\n        isCLIExactPrerelease: false,\n        isCLIExactLatest: false,\n      }\n    );\n    expect(result).toEqual([]);\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/upgrade.ts",
    "content": "import { PackageManagerName } from 'storybook/internal/common';\nimport { HandledError, JsPackageManagerFactory, isCorePackage } from 'storybook/internal/common';\nimport {\n  CLI_COLORS,\n  createHyperlink,\n  logTracker,\n  logger,\n  prompt,\n} from 'storybook/internal/node-logger';\nimport type { LogLevel } from 'storybook/internal/node-logger';\nimport {\n  UpgradeStorybookToLowerVersionError,\n  UpgradeStorybookUnknownCurrentVersionError,\n} from 'storybook/internal/server-errors';\nimport { telemetry } from 'storybook/internal/telemetry';\n\nimport { sync as spawnSync } from 'cross-spawn';\nimport picocolors from 'picocolors';\nimport semver, { clean, lt } from 'semver';\nimport { dedent } from 'ts-dedent';\n\nimport { processAutoblockerResults } from './autoblock/utils.ts';\nimport {\n  type AutomigrationCheckResult,\n  type AutomigrationResult,\n  runAutomigrations,\n} from './automigrate/multi-project.ts';\nimport { FixStatus } from './automigrate/types.ts';\nimport { displayDoctorResults, runMultiProjectDoctor } from './doctor/index.ts';\nimport type { ProjectDoctorData, ProjectDoctorResults } from './doctor/types.ts';\nimport {\n  type CollectProjectsSuccessResult,\n  getProjects,\n  shortenPath,\n  upgradeStorybookDependencies,\n} from './util.ts';\n\ntype Package = {\n  package: string;\n  version: string;\n};\n\nconst versionRegex = /(@storybook\\/[^@]+)@(\\S+)/;\nexport const getStorybookVersion = (line: string) => {\n  if (line.startsWith('npm ')) {\n    return null;\n  }\n  const match = versionRegex.exec(line);\n\n  if (!match || !clean(match[2])) {\n    return null;\n  }\n  return {\n    package: match[1],\n    version: match[2],\n  };\n};\n\nconst deprecatedPackages = [\n  {\n    minVersion: '6.0.0-alpha.0',\n    url: 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#60-deprecations',\n    deprecations: [\n      '@storybook/addon-notes',\n      '@storybook/addon-info',\n      '@storybook/addon-contexts',\n      '@storybook/addon-options',\n      '@storybook/addon-centered',\n    ],\n  },\n];\n\nconst formatPackage = (pkg: Package) => `${pkg.package}@${pkg.version}`;\n\nconst warnPackages = (pkgs: Package[]) => pkgs.map((pkg) => `- ${formatPackage(pkg)}`).join('\\n');\n\nexport const checkVersionConsistency = () => {\n  const lines = spawnSync('npm', ['ls'], { stdio: 'pipe' }).output.toString().split('\\n');\n  const storybookPackages = lines\n    .map(getStorybookVersion)\n    .filter((item): item is NonNullable<typeof item> => !!item)\n    .filter((pkg) => isCorePackage(pkg.package));\n  if (!storybookPackages.length) {\n    logger.warn('No storybook core packages found.');\n    logger.warn(`'npm ls | grep storybook' can show if multiple versions are installed.`);\n    return;\n  }\n  storybookPackages.sort((a, b) => semver.rcompare(a.version, b.version));\n  const latestVersion = storybookPackages[0].version;\n  const outdated = storybookPackages.filter((pkg) => pkg.version !== latestVersion);\n  if (outdated.length > 0) {\n    logger.warn(\n      dedent`Found ${outdated.length} outdated packages (relative to '${formatPackage(\n        storybookPackages[0]\n      )}')\n      Please make sure your packages are updated to ensure a consistent experience:\n\n      ${warnPackages(outdated)}`\n    );\n  }\n\n  deprecatedPackages.forEach(({ minVersion, url, deprecations }) => {\n    if (semver.gte(latestVersion, minVersion)) {\n      const deprecated = storybookPackages.filter((pkg) => deprecations.includes(pkg.package));\n      if (deprecated.length > 0) {\n        logger.warn(\n          dedent`Found ${deprecated.length} deprecated packages since ${minVersion}\n          See ${url}\n          ${warnPackages(deprecated)}`\n        );\n      }\n    }\n  });\n  logger.debug('End of version consistency check');\n};\n\nexport type UpgradeOptions = {\n  skipCheck: boolean;\n  packageManager?: PackageManagerName;\n  dryRun: boolean;\n  yes: boolean;\n  force: boolean;\n  disableTelemetry: boolean;\n  configDir?: string[];\n  fixId?: string;\n  skipInstall?: boolean;\n  loglevel?: LogLevel;\n  logfile?: string | boolean;\n};\n\nfunction getUpgradeResults(\n  projectResults: Record<string, AutomigrationResult>,\n  doctorResults: Record<string, ProjectDoctorResults>\n) {\n  const successfulProjects: string[] = [];\n  const failedProjects: string[] = [];\n  const projectsWithNoFixes: string[] = [];\n\n  const allProjects = Object.entries(projectResults).map(([configDir, resultData]) => {\n    const automigrationResults = Object.entries(resultData.automigrationStatuses).map(\n      ([fixId, status]) => {\n        const succeeded = status === FixStatus.SUCCEEDED || status === FixStatus.MANUAL_SUCCEEDED;\n        return {\n          fixId,\n          status,\n          succeeded,\n        };\n      }\n    );\n\n    const hasFailures = automigrationResults.some(\n      (fix) => fix.status === FixStatus.FAILED || fix.status === FixStatus.CHECK_FAILED\n    );\n    const hasSuccessfulFixes = automigrationResults.some(\n      (fix) => fix.status === FixStatus.SUCCEEDED || fix.status === FixStatus.MANUAL_SUCCEEDED\n    );\n    const noFixesNeeded = Object.keys(resultData.automigrationStatuses).length === 0;\n\n    // Determine if migration was successful (has successful fixes and no failures)\n    const migratedSuccessfully = hasSuccessfulFixes && !hasFailures;\n\n    // Check if doctor report exists\n    const hasDoctorReport = !!doctorResults[configDir];\n\n    // Categorize this project\n    if (hasFailures) {\n      failedProjects.push(configDir);\n    } else if (migratedSuccessfully) {\n      successfulProjects.push(configDir);\n    } else if (noFixesNeeded) {\n      projectsWithNoFixes.push(configDir);\n    }\n\n    return {\n      configDir,\n      migratedSuccessfully,\n      hasDoctorReport,\n      automigrations: {\n        fixes: automigrationResults,\n        noFixesNeeded,\n        hasFailures,\n        hasSuccessfulFixes,\n      },\n      doctor: doctorResults[configDir]\n        ? {\n            status: doctorResults[configDir].status,\n            isHealthy: doctorResults[configDir].status === 'healthy',\n          }\n        : null,\n    };\n  });\n\n  return {\n    allProjects,\n    successfulProjects,\n    failedProjects,\n    projectsWithNoFixes,\n  };\n}\n\n/** Logs the results of the upgrade process, including project categorization and diagnostic messages */\nfunction logUpgradeResults(\n  projectResults: Record<string, AutomigrationResult>,\n  detectedAutomigrations: AutomigrationCheckResult[],\n  doctorResults: Record<string, ProjectDoctorResults>\n) {\n  const { successfulProjects, failedProjects, projectsWithNoFixes } = getUpgradeResults(\n    projectResults,\n    doctorResults\n  );\n\n  // If there are any failures, show detailed summary\n  if (failedProjects.length > 0) {\n    logTracker.enableLogWriting();\n    logger.step(\n      'The upgrade is complete, but some projects failed to upgrade or migrate completely. Please see the debug logs for more details.'\n    );\n    // Display appropriate messages based on results\n    if (successfulProjects.length > 0) {\n      const successfulProjectsList = successfulProjects\n        .map((dir) => `  • ${shortenPath(dir)}`)\n        .join('\\n');\n      logger.log(`${CLI_COLORS.success('Successfully upgraded:')}\\n${successfulProjectsList}`);\n    }\n\n    const failedProjectsList = failedProjects.map((dir) => `  • ${shortenPath(dir)}`).join('\\n');\n    logger.log(\n      `${CLI_COLORS.error('Failed to upgrade:')}\\nSome automigrations failed, please check the logs in the log file for more details.\\n${failedProjectsList}`\n    );\n\n    if (projectsWithNoFixes.length > 0) {\n      const projectList = projectsWithNoFixes.map((dir) => `  • ${shortenPath(dir)}`).join('\\n');\n      logger.log(`${CLI_COLORS.info('No applicable migrations:')}\\n${projectList}`);\n    }\n  } else {\n    if (Object.values(doctorResults).every((result) => result.status === 'healthy')) {\n      logger.step(`${CLI_COLORS.success('Your project(s) have been upgraded successfully! 🎉')}`);\n    } else {\n      logger.step(\n        `${picocolors.yellow('Your project(s) have been upgraded successfully, but some issues were found which need your attention, please check Storybook doctor logs above.')}`\n      );\n    }\n  }\n\n  const automigrationLinks = detectedAutomigrations\n    .filter((am) =>\n      Object.entries(projectResults).some(\n        ([_, resultData]) =>\n          resultData.automigrationStatuses[am.fix.id] === FixStatus.FAILED ||\n          resultData.automigrationStatuses[am.fix.id] === FixStatus.SUCCEEDED ||\n          resultData.automigrationStatuses[am.fix.id] === FixStatus.CHECK_FAILED\n      )\n    )\n    .map((am) => `• ${createHyperlink(am.fix.id, am.fix.link!)}`);\n\n  if (automigrationLinks.length > 0) {\n    const automigrationLinksMessage = [\n      'If you want to learn more about the automigrations that executed in your project(s), please check the following links:',\n      ...automigrationLinks,\n    ].join('\\n');\n\n    logger.log(automigrationLinksMessage);\n  }\n\n  logger.log(\n    `For a full list of changes, please check our migration guide: ${CLI_COLORS.cta('https://storybook.js.org/docs/releases/migration-guide?ref=upgrade')}`\n  );\n}\n\ninterface MultiUpgradeTelemetryOptions {\n  allProjects: CollectProjectsSuccessResult[];\n  selectedProjects: CollectProjectsSuccessResult[];\n  projectResults: Record<string, AutomigrationResult>;\n  doctorResults: Record<string, ProjectDoctorResults>;\n  hasUserInterrupted?: boolean;\n}\n\nasync function sendMultiUpgradeTelemetry(options: MultiUpgradeTelemetryOptions) {\n  const {\n    allProjects,\n    selectedProjects,\n    projectResults,\n    doctorResults,\n    hasUserInterrupted = false,\n  } = options;\n\n  const { successfulProjects, failedProjects, projectsWithNoFixes } = getUpgradeResults(\n    projectResults,\n    doctorResults\n  );\n\n  // Calculate incomplete projects (projects that were supposed to be processed but have no results)\n  const processedProjects = new Set([\n    ...Object.keys(projectResults),\n    ...Object.keys(doctorResults),\n  ]);\n  const incompleteProjects = selectedProjects\n    .map((p) => p.configDir)\n    .filter((configDir) => !processedProjects.has(configDir));\n  const projectsWithDoctorReports = Object.values(doctorResults).filter(\n    (result) => result.status !== 'healthy'\n  ).length;\n\n  try {\n    await telemetry('multi-upgrade', {\n      totalDetectedProjects: allProjects.length,\n      totalSelectedProjects: selectedProjects.length,\n      projectsWithSuccessfulAutomigrations: successfulProjects.length,\n      projectsWithFailedAutomigrations: failedProjects.length,\n      projectsWithNoAutomigrations: projectsWithNoFixes.length,\n      projectsWithDoctorReports,\n      incompleteProjects: incompleteProjects.length,\n      hasUserInterrupted,\n    });\n  } catch (error) {\n    // Silently handle telemetry errors to avoid disrupting the upgrade process\n    logger.debug(`Failed to send multi-upgrade telemetry: ${String(error)}`);\n  }\n}\n\nexport async function upgrade(options: UpgradeOptions): Promise<void> {\n  const projectsResult = await getProjects(options);\n\n  if (projectsResult === undefined || projectsResult.selectedProjects.length === 0) {\n    // nothing to upgrade\n    return;\n  }\n\n  const { allProjects, selectedProjects: storybookProjects } = projectsResult;\n\n  if (storybookProjects.length > 1) {\n    logger.info(`Upgrading the following projects:\n          ${storybookProjects.map((p) => `${picocolors.cyan(shortenPath(p.configDir))}: ${picocolors.bold(p.beforeVersion)} -> ${picocolors.bold(p.currentCLIVersion)}`).join('\\n')}`);\n  } else {\n    logger.info(\n      `Upgrading from ${picocolors.bold(storybookProjects[0].beforeVersion)} to ${picocolors.bold(storybookProjects[0].currentCLIVersion)}`\n    );\n  }\n\n  const automigrationResults: Record<string, AutomigrationResult> = {};\n  let doctorResults: Record<string, ProjectDoctorResults> = {};\n\n  // Set up signal handling for interruptions\n  const handleInterruption = async () => {\n    logger.log('\\n\\nUpgrade interrupted by user.');\n    if (allProjects.length > 1) {\n      await sendMultiUpgradeTelemetry({\n        allProjects,\n        selectedProjects: storybookProjects,\n        projectResults: automigrationResults,\n        doctorResults,\n        hasUserInterrupted: true,\n      });\n    }\n    throw new HandledError('Upgrade cancelled by user');\n  };\n\n  process.on('SIGINT', handleInterruption);\n  process.on('SIGTERM', handleInterruption);\n\n  try {\n    // Handle autoblockers\n    const hasBlockers = processAutoblockerResults(storybookProjects, (message) => {\n      logger.error(dedent`Blockers detected\\n\\n${message}`);\n    });\n\n    if (hasBlockers) {\n      throw new HandledError('Blockers detected');\n    }\n\n    // Checks whether we can upgrade\n    storybookProjects.some((project) => {\n      if (!project.isCanary && lt(project.currentCLIVersion, project.beforeVersion)) {\n        throw new UpgradeStorybookToLowerVersionError({\n          beforeVersion: project.beforeVersion,\n          currentVersion: project.currentCLIVersion,\n        });\n      }\n\n      if (!project.beforeVersion) {\n        throw new UpgradeStorybookUnknownCurrentVersionError();\n      }\n    });\n\n    // Update dependencies in package.jsons for all projects\n    if (!options.dryRun) {\n      const task = prompt.taskLog({\n        id: 'upgrade-dependencies',\n        title: `Fetching versions to update package.json files..`,\n      });\n      try {\n        const loggedPaths: string[] = [];\n        for (const project of storybookProjects) {\n          logger.debug(`Updating dependencies in ${shortenPath(project.configDir)}...`);\n          const packageJsonPaths = project.packageManager.packageJsonPaths.map(shortenPath);\n          const newPaths = packageJsonPaths.filter((path) => !loggedPaths.includes(path));\n          if (newPaths.length > 0) {\n            task.message(newPaths.join('\\n'));\n            loggedPaths.push(...newPaths);\n          }\n          await upgradeStorybookDependencies({\n            packageManager: project.packageManager,\n            isCanary: project.isCanary,\n            isCLIOutdated: project.isCLIOutdated,\n            isCLIPrerelease: project.isCLIPrerelease,\n            isCLIExactLatest: project.isCLIExactLatest,\n            isCLIExactPrerelease: project.isCLIExactPrerelease,\n          });\n        }\n        task.success(`Updated package versions in package.json files`);\n      } catch (err) {\n        task.error(`Failed to upgrade dependencies: ${String(err)}`);\n      }\n    }\n\n    // Run automigrations for all projects\n    const { automigrationResults, detectedAutomigrations } = await runAutomigrations(\n      storybookProjects,\n      options\n    );\n\n    // Install dependencies\n    const rootPackageManager =\n      storybookProjects.length > 1\n        ? JsPackageManagerFactory.getPackageManager({ force: options.packageManager })\n        : storybookProjects[0].packageManager;\n\n    if (rootPackageManager.type === 'npm') {\n      // see https://github.com/npm/cli/issues/8059 for more details\n      await rootPackageManager.installDependencies({ force: true });\n    } else {\n      await rootPackageManager.installDependencies();\n    }\n\n    if (\n      rootPackageManager.type !== PackageManagerName.YARN1 &&\n      rootPackageManager.isStorybookInMonorepo()\n    ) {\n      logger.warn(\n        `Since you are in a monorepo, we advise you to deduplicate your dependencies. We can do this for you but it might take some time.`\n      );\n\n      const dedupe =\n        options.yes ||\n        (await prompt.confirm({\n          message: `Execute ${rootPackageManager.getRunCommand('dedupe')}?`,\n          initialValue: true,\n        }));\n\n      if (dedupe) {\n        if (rootPackageManager.type === 'npm') {\n          // see https://github.com/npm/cli/issues/8059 for more details\n          await rootPackageManager.dedupeDependencies({ force: true });\n        } else {\n          await rootPackageManager.dedupeDependencies();\n        }\n      } else {\n        logger.log(\n          `If you find any issues running Storybook, you can run ${rootPackageManager.getRunCommand('dedupe')} manually to deduplicate your dependencies and try again.`\n        );\n      }\n    }\n\n    // Run doctor for each project\n    const doctorProjects: ProjectDoctorData[] = storybookProjects.map((project) => ({\n      configDir: project.configDir,\n      packageManager: project.packageManager,\n      storybookVersion: project.currentCLIVersion,\n      mainConfig: project.mainConfig,\n    }));\n\n    logger.step('Checking the health of your project(s)..');\n    doctorResults = await runMultiProjectDoctor(doctorProjects);\n    const hasIssues = displayDoctorResults(doctorResults);\n    if (hasIssues) {\n      logTracker.enableLogWriting();\n    }\n\n    // Display upgrade results summary\n    logUpgradeResults(automigrationResults, detectedAutomigrations, doctorResults);\n\n    // TELEMETRY\n    if (!options.disableTelemetry) {\n      for (const project of storybookProjects) {\n        const resultData = automigrationResults[project.configDir] || {\n          automigrationStatuses: {},\n          automigrationErrors: {},\n        };\n        let doctorFailureCount = 0;\n        let doctorErrorCount = 0;\n        Object.values(doctorResults[project.configDir]?.diagnostics || {}).forEach((status) => {\n          if (status === 'has_issues') {\n            doctorFailureCount++;\n          }\n\n          if (status === 'check_error') {\n            doctorErrorCount++;\n          }\n        });\n        const automigrationFailureCount = Object.keys(resultData.automigrationErrors).length;\n        const automigrationPreCheckFailure =\n          project.autoblockerCheckResults && project.autoblockerCheckResults.length > 0\n            ? project.autoblockerCheckResults\n                ?.map((result) => {\n                  if (result.result !== null) {\n                    return result.blocker.id;\n                  }\n                  return null;\n                })\n                .filter(Boolean)\n            : null;\n        await telemetry('upgrade', {\n          beforeVersion: project.beforeVersion,\n          afterVersion: project.currentCLIVersion,\n          automigrationResults: resultData.automigrationStatuses,\n          automigrationErrors: resultData.automigrationErrors,\n          automigrationFailureCount,\n          automigrationPreCheckFailure,\n          doctorResults: doctorResults[project.configDir]?.diagnostics || {},\n          doctorFailureCount,\n          doctorErrorCount,\n        });\n      }\n\n      await sendMultiUpgradeTelemetry({\n        allProjects,\n        selectedProjects: storybookProjects,\n        projectResults: automigrationResults,\n        doctorResults,\n      });\n    }\n  } finally {\n    // Clean up signal handlers\n    process.removeListener('SIGINT', handleInterruption);\n    process.removeListener('SIGTERM', handleInterruption);\n  }\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/src/util.ts",
    "content": "import type { PackageJsonWithDepsAndDevDeps } from 'storybook/internal/common';\nimport { HandledError, JsPackageManager, normalizeStories } from 'storybook/internal/common';\nimport { getProjectRoot, isSatelliteAddon, versions } from 'storybook/internal/common';\nimport { StoryIndexGenerator, experimental_loadStorybook } from 'storybook/internal/core-server';\nimport { logTracker, logger, prompt } from 'storybook/internal/node-logger';\nimport {\n  UpgradeStorybookToLowerVersionError,\n  UpgradeStorybookUnknownCurrentVersionError,\n} from 'storybook/internal/server-errors';\nimport type { StorybookConfigRaw } from 'storybook/internal/types';\n\nimport * as walk from 'empathic/walk';\n// eslint-disable-next-line depend/ban-dependencies\nimport { globby, globbySync } from 'globby';\nimport picocolors from 'picocolors';\nimport { lt, prerelease } from 'semver';\n\nimport { autoblock } from './autoblock/index.ts';\nimport type { AutoblockerResult } from './autoblock/types.ts';\nimport { getStorybookData } from './automigrate/helpers/mainConfigFile.ts';\nimport { type UpgradeOptions } from './upgrade.ts';\n\n// ============================================================================\n// TYPES AND INTERFACES\n// ============================================================================\n\n/** Configuration for upgrading Storybook dependencies */\ninterface UpgradeConfig {\n  readonly packageManager: JsPackageManager;\n  readonly isCanary: boolean;\n  readonly isCLIOutdated: boolean;\n  readonly isCLIPrerelease: boolean;\n  readonly isCLIExactPrerelease: boolean;\n  readonly isCLIExactLatest: boolean;\n}\n\n/** Result of successfully collecting project data */\nexport interface CollectProjectsSuccessResult extends UpgradeConfig {\n  configDir: string;\n  readonly mainConfig: StorybookConfigRaw;\n  readonly mainConfigPath: string | undefined;\n  readonly previewConfigPath: string | undefined;\n  readonly isUpgrade: boolean;\n  readonly beforeVersion: string;\n  readonly currentCLIVersion: string;\n  readonly latestCLIVersionOnNPM: string;\n  readonly autoblockerCheckResults: AutoblockerResult<unknown>[] | null;\n  readonly storiesPaths: string[];\n  readonly hasCsfFactoryPreview: boolean;\n}\n\n/** Result when project collection fails */\ninterface CollectProjectsErrorResult {\n  /** Path to the configuration directory that failed */\n  readonly configDir: string;\n  /** Error that occurred during collection */\n  readonly error: Error;\n}\n\n/** Union type representing either success or error result from project collection */\nexport type CollectProjectsResult = CollectProjectsSuccessResult | CollectProjectsErrorResult;\n\n/** Version modifier configuration */\ninterface VersionModifier {\n  /** The modifier character(s) (^, ~, >=, etc.) */\n  readonly modifier: string;\n  /** Whether to use a fixed version (no modifier) */\n  readonly useFixed: boolean;\n}\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\n/** Glob pattern for finding Storybook directories */\nconst STORYBOOK_DIR_PATTERN = ['**/.storybook', '**/.rnstorybook'];\n\n// ============================================================================\n// UTILITY FUNCTIONS\n// ============================================================================\n\n/**\n * Type guard to check if a result is a success result\n *\n * @param result - The result to check\n * @returns True if the result is a success result\n */\nexport const isSuccessResult = (\n  result: CollectProjectsResult\n): result is CollectProjectsSuccessResult => !('error' in result);\n\n/**\n * Type guard to check if a result is an error result\n *\n * @param result - The result to check\n * @returns True if the result is an error result\n */\nexport const isErrorResult = (\n  result: CollectProjectsResult\n): result is CollectProjectsErrorResult => 'error' in result;\n\n/**\n * Extracts version modifier from a version specifier string\n *\n * @example\n *\n * ```typescript\n * const modifier = getVersionModifier('^1.0.0');\n * // Returns: { modifier: '^', useFixed: false }\n * ```\n *\n * @param versionSpecifier - Version string like \"^1.0.0\" or \"~2.1.0\"\n * @returns Version modifier configuration\n */\nconst getVersionModifier = (versionSpecifier: string): VersionModifier => {\n  if (!versionSpecifier || typeof versionSpecifier !== 'string') {\n    return { modifier: '', useFixed: true };\n  }\n\n  // Split in case of complex version strings like \"9.0.0 || >= 0.0.0-pr.0\"\n  const firstPart = versionSpecifier.split(/\\s*\\|\\|\\s*/)[0]?.trim();\n  if (!firstPart) {\n    return { modifier: '', useFixed: true };\n  }\n\n  // Match common modifiers\n  const match = firstPart.match(/^([~^><=]+)/);\n  const modifier = match?.[1] ?? '';\n\n  return {\n    modifier,\n    useFixed: !modifier,\n  };\n};\n\n/**\n * Checks if a version represents a canary release\n *\n * @param version - Version string to check\n * @returns True if the version is a canary release\n */\nconst isCanaryVersion = (version: string): boolean =>\n  version.startsWith('0.0.0') || version.startsWith('portal:') || version.startsWith('workspace:');\n\n/**\n * Validates that a version string is not empty or undefined\n *\n * @param version - Version string to validate\n * @throws {UpgradeStorybookUnknownCurrentVersionError} When version is invalid\n */\nfunction validateVersion(version: string | undefined): asserts version is string {\n  if (!version) {\n    throw new UpgradeStorybookUnknownCurrentVersionError();\n  }\n}\n\n/**\n * Validates upgrade compatibility between versions\n *\n * @param currentVersion - Current CLI version\n * @param beforeVersion - Version before upgrade\n * @param isCanary - Whether this is a canary version\n * @throws {UpgradeStorybookToLowerVersionError} When trying to downgrade\n */\nconst validateUpgradeCompatibility = (\n  currentVersion: string,\n  beforeVersion: string,\n  isCanary: boolean\n): void => {\n  if (!isCanary && lt(currentVersion, beforeVersion)) {\n    throw new UpgradeStorybookToLowerVersionError({\n      beforeVersion,\n      currentVersion: currentVersion,\n    });\n  }\n};\n\n// ============================================================================\n// CORE FUNCTIONS\n// ============================================================================\n\n/**\n * Finds all Storybook projects in the specified directory\n *\n * @example\n *\n * ```typescript\n * const projects = await findStorybookProjects('/path/to/workspace');\n * console.log(projects); // ['/path/to/workspace/app1/.storybook', ...]\n * ```\n *\n * @param cwd - Current working directory to search from\n * @returns Promise resolving to array of Storybook project paths\n */\nexport const findStorybookProjects = async (cwd: string = process.cwd()): Promise<string[]> => {\n  try {\n    logger.debug(`Finding Storybook projects...`);\n    // Find all .storybook directories, accounting for custom config dirs later\n    const storybookDirs = await globby(STORYBOOK_DIR_PATTERN, {\n      cwd,\n      dot: true,\n      gitignore: true,\n      absolute: true,\n      onlyDirectories: true,\n      followSymbolicLinks: false,\n    });\n\n    logger.debug(`Found ${storybookDirs.length} Storybook projects`);\n\n    if (storybookDirs.length === 0) {\n      const answer = await prompt.text({\n        message:\n          'No Storybook projects were found. Please enter the path to the .storybook directory for the project you want to upgrade.',\n      });\n      return [answer];\n    }\n\n    return storybookDirs;\n  } catch (error) {\n    logger.error('Failed to find Storybook projects');\n    throw error;\n  }\n};\n\n/**\n * Retrieves the installed version of Storybook from package manager\n *\n * @example\n *\n * ```typescript\n * const version = await getInstalledStorybookVersion(packageManager);\n * console.log(version); // \"7.0.0\" or undefined\n * ```\n *\n * @param packageManager - Package manager instance\n * @returns Promise resolving to installed version string or undefined\n */\nexport const getInstalledStorybookVersion = async (\n  packageManager: JsPackageManager\n): Promise<string | undefined> => {\n  try {\n    // First try to get the storybook CLI version directly\n    const storybookCliVersion = await packageManager.getInstalledVersion('storybook');\n    if (storybookCliVersion) {\n      return storybookCliVersion;\n    }\n\n    // Fallback to checking all Storybook packages\n    const installations = await packageManager.findInstallations(Object.keys(versions));\n    if (!installations?.dependencies) {\n      return undefined;\n    }\n\n    // Get the first available version from dependencies\n    const firstDependency = Object.entries(installations.dependencies)[0];\n    return firstDependency?.[1]?.[0]?.version;\n  } catch (error) {\n    logger.warn('Failed to get installed Storybook version');\n    return undefined;\n  }\n};\n\n/**\n * Processes a single Storybook project and collects its data\n *\n * @param configDir - Path to the Storybook configuration directory\n * @param options - Upgrade options\n * @param currentCLIVersion - Current CLI version\n * @returns Promise resolving to project collection result\n */\nconst processProject = async ({\n  configDir,\n  options,\n  currentCLIVersion,\n  onScanStart,\n}: {\n  configDir: string;\n  options: UpgradeOptions;\n  currentCLIVersion: string;\n  onScanStart: () => void;\n}): Promise<CollectProjectsResult> => {\n  try {\n    onScanStart();\n    const name = configDir.replace(getProjectRoot(), '');\n\n    logger.debug(`Getting Storybook data...`);\n    const {\n      configDir: resolvedConfigDir,\n      mainConfig,\n      mainConfigPath,\n      packageManager,\n      previewConfigPath,\n      storiesPaths,\n      versionInstalled,\n      hasCsfFactoryPreview,\n    } = await getStorybookData({ configDir });\n\n    // Validate version and upgrade compatibility\n    logger.debug(`${name} - Validating before version... ${versionInstalled}`);\n    validateVersion(versionInstalled);\n    const isCanary = isCanaryVersion(currentCLIVersion) || isCanaryVersion(versionInstalled);\n    logger.debug(`${name} - Validating upgrade compatibility...`);\n    validateUpgradeCompatibility(currentCLIVersion, versionInstalled, isCanary);\n\n    // Get version information from NPM\n    logger.debug(`${name} - Fetching NPM version information...`);\n    const [latestCLIVersionOnNPM, latestPrereleaseCLIVersionOnNPM] = await Promise.all([\n      packageManager.latestVersion('storybook'),\n      packageManager.latestVersion('storybook@next'),\n    ]);\n\n    // Calculate version flags\n    const isCLIOutdated = lt(currentCLIVersion, latestCLIVersionOnNPM!);\n    const isCLIExactLatest = currentCLIVersion === latestCLIVersionOnNPM;\n    const isCLIPrerelease = prerelease(currentCLIVersion) !== null;\n    const isCLIExactPrerelease = currentCLIVersion === latestPrereleaseCLIVersionOnNPM;\n    const isUpgrade = lt(versionInstalled, currentCLIVersion);\n\n    // Check for blockers\n    let autoblockerCheckResults: AutoblockerResult<unknown>[] | null = null;\n\n    if (\n      typeof mainConfig !== 'boolean' &&\n      typeof mainConfigPath !== 'undefined' &&\n      !options.force\n    ) {\n      logger.debug(`${name} - Evaluating blockers...`);\n      autoblockerCheckResults = await autoblock({\n        packageManager,\n        configDir: resolvedConfigDir,\n        mainConfig,\n        mainConfigPath,\n      });\n    }\n\n    return {\n      configDir: resolvedConfigDir,\n      mainConfig,\n      mainConfigPath,\n      packageManager,\n      isCanary,\n      isCLIOutdated,\n      isCLIPrerelease,\n      isCLIExactLatest,\n      isUpgrade,\n      beforeVersion: versionInstalled,\n      currentCLIVersion,\n      latestCLIVersionOnNPM: latestCLIVersionOnNPM!,\n      isCLIExactPrerelease,\n      autoblockerCheckResults,\n      previewConfigPath,\n      storiesPaths,\n      hasCsfFactoryPreview,\n    } satisfies CollectProjectsSuccessResult;\n  } catch (error) {\n    logger.debug(String(error));\n    return {\n      configDir,\n      error: error as Error,\n    } satisfies CollectProjectsErrorResult;\n  }\n};\n\n/**\n * Collects data from multiple Storybook projects\n *\n * @example\n *\n * ```typescript\n * const results = await collectProjects(options, ['/path/to/.storybook']);\n * const successResults = results.filter(isSuccessResult);\n * ```\n *\n * @param options - Upgrade options\n * @param configDirs - Array of configuration directory paths\n * @returns Promise resolving to array of collection results\n */\nexport const collectProjects = async (\n  options: UpgradeOptions,\n  configDirs: readonly string[],\n  onProjectScanStart: () => void\n): Promise<CollectProjectsResult[]> => {\n  const { default: pLimit } = await import('p-limit');\n\n  const currentCLIVersion = versions.storybook;\n  const limit = pLimit(5); // Process 5 projects concurrently\n\n  const projectPromises = configDirs.map((configDir) =>\n    limit(() =>\n      processProject({\n        configDir,\n        options,\n        currentCLIVersion,\n        onScanStart: () => onProjectScanStart(),\n      })\n    )\n  );\n\n  const result = await Promise.all(projectPromises);\n\n  return result;\n};\n\n/**\n * Generates upgrade specifications for dependencies\n *\n * @param dependencies - Dependencies object from package.json\n * @param config - Upgrade configuration\n * @returns Promise resolving to array of upgrade specifications\n */\nexport const generateUpgradeSpecs = async (\n  dependencies: PackageJsonWithDepsAndDevDeps['dependencies'] = {},\n  config: UpgradeConfig\n): Promise<string[]> => {\n  const {\n    packageManager,\n    isCanary,\n    isCLIOutdated,\n    isCLIPrerelease,\n    isCLIExactPrerelease,\n    isCLIExactLatest,\n  } = config;\n\n  // Filter for monorepo dependencies\n  const monorepoDependencies = Object.keys(dependencies).filter(\n    (dependency): dependency is keyof typeof versions => dependency in versions\n  );\n\n  // Generate core Storybook upgrades\n  const storybookCoreUpgrades = monorepoDependencies.map((dependency) => {\n    const versionSpec = dependencies[dependency];\n\n    if (!versionSpec) {\n      return `${dependency}@${versions[dependency]}`;\n    }\n\n    const { modifier } = getVersionModifier(versionSpec);\n\n    // Use fixed version for outdated CLI or canary versions\n    const shouldUseFixed = isCLIOutdated || isCanary;\n    const finalModifier = shouldUseFixed ? '' : modifier;\n\n    return `${dependency}@${finalModifier}${versions[dependency]}`;\n  });\n\n  // Generate satellite addon upgrades if applicable\n  let storybookSatelliteUpgrades: string[] = [];\n  if (isCLIExactPrerelease || isCLIExactLatest) {\n    const satelliteDependencies = Object.keys(dependencies).filter(isSatelliteAddon);\n\n    if (satelliteDependencies.length > 0) {\n      try {\n        const upgradePromises = satelliteDependencies.map(async (dependency) => {\n          try {\n            const packageName = isCLIPrerelease ? `${dependency}@next` : dependency;\n            const mostRecentVersion = (await packageManager.latestVersion(packageName))!;\n            if (!mostRecentVersion) {\n              return null;\n            }\n            const { modifier } = getVersionModifier(dependencies[dependency] ?? '');\n            return `${dependency}@${modifier}${mostRecentVersion}`;\n          } catch {\n            return null;\n          }\n        });\n\n        const results = await Promise.all(upgradePromises);\n        storybookSatelliteUpgrades = results.filter((result): result is string => result !== null);\n      } catch (error) {\n        logger.warn('Failed to fetch satellite dependencies');\n        // Continue without satellite upgrades\n      }\n    }\n  }\n\n  return [...storybookCoreUpgrades, ...storybookSatelliteUpgrades];\n};\n\n/**\n * Upgrades Storybook dependencies across all package.json files\n *\n * @example\n *\n * ```typescript\n * await upgradeStorybookDependencies({\n *   packageManager,\n *   isCanary: false,\n *   isCLIOutdated: false,\n *   isCLIPrerelease: false,\n *   isCLIExactPrerelease: false,\n *   isCLIExactLatest: true,\n * });\n * ```\n *\n * @param config - Upgrade configuration\n */\nexport const upgradeStorybookDependencies = async (config: UpgradeConfig): Promise<void> => {\n  const { packageManager } = config;\n\n  for (const packageJsonPath of packageManager.packageJsonPaths) {\n    const packageJson = JsPackageManager.getPackageJson(packageJsonPath);\n\n    const [upgradedDependencies, upgradedDevDependencies, upgradedPeerDependencies] =\n      await Promise.all([\n        generateUpgradeSpecs(packageJson.dependencies, config),\n        generateUpgradeSpecs(packageJson.devDependencies, config),\n        generateUpgradeSpecs(packageJson.peerDependencies, config),\n      ]);\n\n    logger.debug(JSON.stringify({ upgradedDependencies }, null, 2));\n    logger.debug(JSON.stringify({ upgradedDevDependencies }, null, 2));\n    logger.debug(JSON.stringify({ upgradedPeerDependencies }, null, 2));\n\n    await packageManager.addDependencies(\n      {\n        type: 'dependencies',\n        skipInstall: true,\n        packageJsonInfo: JsPackageManager.getPackageJsonInfo(packageJsonPath),\n      },\n      upgradedDependencies\n    );\n\n    await packageManager.addDependencies(\n      {\n        type: 'devDependencies',\n        skipInstall: true,\n        packageJsonInfo: JsPackageManager.getPackageJsonInfo(packageJsonPath),\n      },\n      upgradedDevDependencies\n    );\n\n    await packageManager.addDependencies(\n      {\n        type: 'peerDependencies',\n        skipInstall: true,\n        packageJsonInfo: JsPackageManager.getPackageJsonInfo(packageJsonPath),\n      },\n      upgradedPeerDependencies\n    );\n  }\n};\n\n/**\n * Formats project directories for display\n *\n * @param projectData - Array of project results\n * @param modifier - Symbol to prefix each directory\n * @returns Formatted string of project directories\n */\nconst formatProjectDirectories = (\n  projectData: readonly CollectProjectsResult[],\n  modifier: string\n): string => {\n  if (projectData.length === 0) {\n    return '';\n  }\n\n  return projectData\n    .map((project) => project.configDir)\n    .map((dir) => `${modifier} ${picocolors.cyan(shortenPath(dir))}`)\n    .join('\\n');\n};\n\n/**\n * Shortens a path to the relative path from the project root\n *\n * @param path - The path to shorten\n * @returns The shortened path\n */\nexport const shortenPath = (path: string) => {\n  const gitRoot = getProjectRoot();\n  return path.replace(gitRoot, '');\n};\n\n/**\n * Handles multiple project selection and validation\n *\n * @param validProjects - Array of valid project results\n * @param errorProjects - Array of error project results\n * @param detectedConfigDirs - Array of detected configuration directories\n * @returns Promise resolving to selected projects or undefined\n */\nconst handleMultipleProjects = async (\n  validProjects: readonly CollectProjectsSuccessResult[],\n  errorProjects: readonly CollectProjectsErrorResult[],\n  detectedConfigDirs: readonly string[],\n  yes: boolean\n): Promise<CollectProjectsSuccessResult[] | undefined> => {\n  // Check for overlapping Storybooks\n  const allPackageJsonPaths = validProjects\n    .flatMap((data) => data.packageManager.packageJsonPaths)\n    .filter(JsPackageManager.hasAnyStorybookDependency);\n\n  const uniquePackageJsonPaths = new Set(allPackageJsonPaths);\n  const hasOverlappingStorybooks = uniquePackageJsonPaths.size !== allPackageJsonPaths.length;\n\n  if (hasOverlappingStorybooks) {\n    const projectsFoundMessage = [\n      'Multiple Storybook projects found. Storybook can only upgrade all projects at once:',\n    ];\n    if (validProjects.length > 0) {\n      projectsFoundMessage.push(formatProjectDirectories(validProjects, logger.SYMBOLS.success));\n    }\n    if (errorProjects.length > 0) {\n      logTracker.enableLogWriting();\n      projectsFoundMessage.push(\n        `There were some errors while collecting data for the following projects:\\n${formatProjectDirectories(errorProjects, logger.SYMBOLS.error)}`,\n        '',\n        'Full logs will be available in the Storybook debug logs at the end of the run.'\n      );\n    }\n    logger.log(projectsFoundMessage.join('\\n'));\n\n    const continueUpgrade =\n      yes ||\n      (await prompt.confirm({\n        message: 'Continue with the upgrade?',\n        initialValue: true,\n      }));\n\n    if (!continueUpgrade) {\n      throw new HandledError('Upgrade cancelled by user');\n    }\n\n    return [...validProjects];\n  }\n\n  if (detectedConfigDirs.length > 1) {\n    const selectedConfigDirs = await prompt.multiselect({\n      message: 'Select which projects to upgrade',\n      options: detectedConfigDirs.map((configDir) => ({\n        label: shortenPath(configDir),\n        value: configDir,\n      })),\n    });\n\n    return validProjects.filter((data) => selectedConfigDirs.includes(data.configDir));\n  }\n\n  return undefined;\n};\n\n/**\n * Gets and validates Storybook projects for upgrade\n *\n * @example\n *\n * ```typescript\n * const result = await getProjects({ configDir: ['/path/to/.storybook'] });\n * if (result) {\n *   console.log(\n *     `Found ${result.selectedProjects.length} of ${result.allProjects.length} projects to upgrade`\n *   );\n * }\n * ```\n *\n * @param options - Upgrade options\n * @returns Promise resolving to object with all detected projects and selected projects, or\n *   undefined\n */\nexport const getProjects = async (\n  options: UpgradeOptions\n): Promise<\n  | {\n      allProjects: CollectProjectsSuccessResult[];\n      selectedProjects: CollectProjectsSuccessResult[];\n    }\n  | undefined\n> => {\n  try {\n    const task = prompt.spinner({ id: 'detect-projects' });\n    task.start('Detecting projects...');\n\n    // Determine configuration directories\n    let detectedConfigDirs: string[] = options.configDir ?? [];\n    if (!options.configDir || options.configDir.length === 0) {\n      detectedConfigDirs = await findStorybookProjects();\n    }\n\n    let count = 0;\n    const projects = await collectProjects(options, detectedConfigDirs, () =>\n      task.message(`Detecting projects: ${++count} projects`)\n    );\n    task.stop(`${projects.length} ${projects.length > 1 ? 'projects' : 'project'} detected`);\n\n    // Separate valid and error projects\n    const validProjects = projects.filter(isSuccessResult);\n    const errorProjects = projects.filter(isErrorResult);\n    logger.debug(\n      `Found ${validProjects.length} valid projects and ${errorProjects.length} error projects`\n    );\n\n    // Handle single project case\n    if (validProjects.length === 1) {\n      return { allProjects: validProjects, selectedProjects: validProjects };\n    }\n\n    // Handle case with only errors\n    if (validProjects.length === 0 && errorProjects.length > 0) {\n      const errorMessage = errorProjects\n        .map((project) => {\n          const relativePath = shortenPath(project.configDir);\n          return `${relativePath}:\\n${project.error.stack || project.error.message}`;\n        })\n        .join('\\n');\n\n      throw new Error(\n        `❌ Storybook found errors while collecting data for the following projects:\\n${errorMessage}\\nPlease fix the errors and run the upgrade command again.`\n      );\n    }\n\n    // Handle multiple projects\n    const selectedProjects = await handleMultipleProjects(\n      validProjects,\n      errorProjects,\n      detectedConfigDirs,\n      options.yes\n    );\n\n    return selectedProjects ? { allProjects: validProjects, selectedProjects } : undefined;\n  } catch (error) {\n    if (!(error instanceof HandledError)) {\n      logger.error('Failed to get projects');\n    }\n\n    throw error;\n  }\n};\n\n/** Finds files in the directory tree up to the project root */\nexport const findFilesUp = (matchers: string[], cwd: string) => {\n  const matchingFiles: string[] = [];\n  for (const directory of walk.up(cwd, { last: getProjectRoot() })) {\n    matchingFiles.push(\n      ...globbySync(matchers, {\n        gitignore: true,\n        absolute: true,\n        cwd: directory,\n      })\n    );\n  }\n\n  return matchingFiles;\n};\n\n/**\n * Gets story file paths from a Storybook configuration directory\n *\n * @example\n *\n * ```typescript\n * const storiesPaths = await getStoriesPathsFromConfig(\n *   '/path/to/.storybook',\n *   '/path/to/project'\n * );\n * ```\n *\n * @param configDir - Path to the Storybook configuration directory\n * @param workingDir - Working directory for resolving relative paths\n * @returns Promise resolving to array of story file paths\n */\nexport const getEvaluatedStoryPaths = async (\n  configDir: string,\n  workingDir: string\n): Promise<string[]> => {\n  const { presets } = await experimental_loadStorybook({\n    configDir,\n    packageJson: {},\n  });\n\n  const stories = await presets.apply('stories', []);\n\n  return getStoriesPathsFromConfig({\n    stories,\n    configDir,\n    workingDir,\n  });\n};\n\n/**\n * Gets story file paths from a Storybook configuration directory\n *\n * @example\n *\n * ```typescript\n * const storiesPaths = await getStoriesPathsFromConfigWithoutEvaluating({\n *   stories: ['src\\/**\\/*.stories.tsx'],\n *   configDir: '/path/to/.storybook',\n *   workingDir: '/path/to/project',\n * });\n * ```\n */\nexport const getStoriesPathsFromConfig = async ({\n  stories,\n  configDir,\n  workingDir,\n}: {\n  stories: StorybookConfigRaw['stories'];\n  configDir: string;\n  workingDir: string;\n}) => {\n  if (stories.length === 0) {\n    return [];\n  }\n\n  const normalizedStories = normalizeStories(stories, {\n    configDir,\n    workingDir,\n  });\n\n  const matchingStoryFiles = await StoryIndexGenerator.findMatchingFilesForSpecifiers(\n    normalizedStories,\n    workingDir,\n    true\n  );\n\n  const storiesPaths = matchingStoryFiles.flatMap(([specifier, cache]) => {\n    return StoryIndexGenerator.storyFileNames(new Map([[specifier, cache]]));\n  });\n\n  return storiesPaths;\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/warn.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { warn } from './warn.ts';\n\nvi.mock('storybook/internal/node-logger');\n\nconst mocks = vi.hoisted(() => {\n  return {\n    globby: vi.fn(),\n  };\n});\n\nvi.mock('globby', async (importOriginal) => {\n  return {\n    ...(await importOriginal<typeof import('globby')>()),\n    globby: mocks.globby,\n  };\n});\n\ndescribe('warn', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n  });\n\n  describe('when TypeScript is installed as a dependency', () => {\n    it('should not warn', () => {\n      warn({\n        hasTSDependency: true,\n      });\n      expect(logger.warn).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('when TypeScript is not installed as a dependency', () => {\n    it('should not warn if `.tsx?` files are not found', async () => {\n      mocks.globby.mockResolvedValue([]);\n      await warn({\n        hasTSDependency: false,\n      });\n      expect(logger.warn).toHaveBeenCalledTimes(0);\n    });\n\n    it('should warn if `.tsx?` files are found', async () => {\n      mocks.globby.mockResolvedValue(['a.ts']);\n      await warn({\n        hasTSDependency: false,\n      });\n      expect(logger.warn).toHaveBeenCalledTimes(2);\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/src/warn.ts",
    "content": "import { logger } from 'storybook/internal/node-logger';\n\ninterface Options {\n  hasTSDependency: boolean;\n}\n\nexport const warn = async ({ hasTSDependency }: Options) => {\n  if (!hasTSDependency) {\n    // Dynamically import globby because it is a pure ESM module\n    // eslint-disable-next-line depend/ban-dependencies\n    const { globby } = await import('globby');\n\n    const files = await globby(['**/*.@(ts|tsx)', '!**/node_modules', '!**/*.d.ts']);\n\n    const hasTSFiles = !!files.length;\n\n    if (hasTSFiles) {\n      logger.warn(\n        'We have detected TypeScript files in your project directory, however TypeScript is not listed as a project dependency.'\n      );\n      logger.warn('Storybook will continue as though this is a JavaScript project.');\n      logger.info(\n        'For more information, see: https://storybook.js.org/docs/configure/integration/typescript'\n      );\n    }\n  }\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/src/window.d.ts",
    "content": "import type { Renderer } from 'storybook/internal/types';\n\nimport type { StoryStore } from 'storybook/preview-api';\n\ndeclare global {\n  interface Window {\n    __STORYBOOK_STORY_STORE__: StoryStore<Renderer>;\n  }\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/test/default/cli.test.cjs",
    "content": "import { expect, test } from 'vitest';\n\nconst { run, cleanLog } = require('../helpers.cjs');\n\ntest('suggests the closest match to an unknown command', () => {\n  const { status, stdout } = run(['upgraed']);\n\n  // Assertions\n  expect(status).toBe(1);\n  const stdoutString = cleanLog(stdout.toString());\n\n  // Error messages are now written to stdout\n  expect(stdoutString).toContain('Invalid command: upgraed.');\n  expect(stdoutString).toContain('Did you mean upgrade?');\n});\n\ntest('help command', () => {\n  const { status, stdout, stderr } = run(['help']);\n\n  const stderrString = cleanLog(stderr.toString());\n  const stdoutString = cleanLog(stdout.toString());\n\n  expect(stderrString).toBe('');\n  expect(stdoutString).toContain('init');\n  expect(stdoutString).toContain('Initialize Storybook into your project');\n\n  expect(stdoutString).toContain('add');\n  expect(stdoutString).toContain('Add an addon to your Storybook');\n\n  expect(stdoutString).toContain('remove');\n  expect(stdoutString).toContain('Remove an addon from your Storybook');\n\n  expect(stdoutString).toContain('upgrade');\n  expect(stdoutString).toContain('Upgrade your Storybook packages to');\n\n  expect(stdoutString).toContain('migrate');\n  expect(stdoutString).toContain('Run a Storybook codemod migration on your source files');\n\n  expect(stdoutString).toContain('sandbox');\n  expect(stdoutString).toContain('Create a sandbox from a set of possible templates');\n\n  expect(stdoutString).toContain('link');\n  expect(stdoutString).toContain(\n    'Pull down a repro from a URL (or a local directory), link it, and run storybook'\n  );\n\n  expect(stdoutString).toContain('automigrate');\n  expect(stdoutString).toContain(\n    'Check storybook for incompatibilities or migrations and apply fixes'\n  );\n\n  expect(stdoutString).toContain('doctor');\n  expect(stdoutString).toContain(\n    'Check Storybook for known problems and provide suggestions or fixes'\n  );\n\n  expect(status).toBe(0);\n});\n"
  },
  {
    "path": "code/lib/cli-storybook/test/helpers.cjs",
    "content": "const { sync: spawnSync } = require('cross-spawn');\nconst path = require('path');\n\nconst CORE_CLI_PATH = path.join(\n  __dirname,\n  '..',\n  '..',\n  '..',\n  'core',\n  'dist',\n  'bin',\n  'dispatcher.js'\n);\n\n/**\n * Execute command\n *\n * @param {String[]} args - Args to be passed in\n * @param {Object} options - Customize the behavior\n * @returns {Object}\n */\nconst run = (args, options = {}) => spawnSync('node', [CORE_CLI_PATH].concat(args), options);\n\nconst cleanLog = (str) => {\n  const pattern = [\n    '[\\\\u001B\\\\u009B][[\\\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]+)*|[a-zA-Z\\\\d]+(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]*)*)?\\\\u0007)',\n    '(?:(?:\\\\d{1,4}(?:;\\\\d{0,4})*)?[\\\\dA-PR-TZcf-ntqry=><~]))',\n  ].join('|');\n\n  return str.replace(new RegExp(pattern, 'g'), '');\n};\n\nmodule.exports = {\n  run,\n  cleanLog,\n};\n"
  },
  {
    "path": "code/lib/cli-storybook/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"resolveJsonModule\": true\n  },\n  \"include\": [\n    \"src/**/*\",\n    \"../../core/src/common/utils/get-addon-annotations.test.ts\",\n    \"../../core/src/common/utils/get-addon-annotations.ts\"\n  ]\n}\n"
  },
  {
    "path": "code/lib/cli-storybook/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/lib/codemod/README.md",
    "content": "# Storybook Codemods\n\nStorybook Codemods is a collection of codemod scripts written with JSCodeshift.\nIt will help you migrate breaking changes & deprecations.\n\n## CLI Integration\n\nThe preferred way to run these codemods is via the CLI's `migrate` command.\n\nTo get a list of available codemods:\n\n```\nnpx sb migrate --list\n```\n\nTo run a codemod `<name-of-codemod>`:\n\n```\nnpx sb migrate <name-of-codemod> --glob=\"**/*.stories.js\"\n```\n\n## Installation\n\nIf you want to run these codemods by hand:\n\n```sh\nyarn add jscodeshift @storybook/codemod --dev\n```\n\n- `@storybook/codemod` is our collection of codemod scripts.\n- `jscodeshift` is a tool we use to apply our codemods.\n\nAfter running the migration commands, you can remove them from your `package.json`, if you added them.\n\n## How to run a codemod script\n\nFrom the directory where you installed both `jscodeshift` and `@storybook/codemod` run:\n\nExample:\n\n```sh\n./node_modules/.bin/jscodeshift -t ./node_modules/@storybook/codemod/dist/transforms/upgrade-hierarchy-separators.js . --ignore-pattern \"node_modules|dist\"\n```\n\nExplanation:\n\n    <jscodeShiftCommand> -t <transformFileLocation> <pathToSource> --ignore-pattern \"<globPatternToIgnore>\"\n\n## Transforms\n\n### upgrade-hierarchy-separators\n\nStarting in 5.3, Storybook is moving to using a single path separator, `/`, to specify the story hierarchy. It previously defaulted to `|` for story \"roots\" (optional) and either `/` or `.` for denoting paths. This codemod updates the old default to the new default.\n\n```sh\n./node_modules/.bin/jscodeshift -t ./node_modules/@storybook/codemod/dist/transforms/upgrade-hierarchy-separators.js . --ignore-pattern \"node_modules|dist\"\n```\n\nFor example:\n\n```js\nstoriesOf('Foo|Bar/baz');\nstoriesOf('Foo.Bar.baz');\n\nexport default {\n  title: 'Foo|Bar/baz.whatever',\n};\n```\n\nBecomes:\n\n```js\nstoriesOf('Foo/Bar/baz');\nstoriesOf('Foo/Bar/baz');\n\nexport default {\n  title: 'Foo/Bar/baz/whatever',\n};\n```\n\n### csf-hoist-story-annotations\n\nStarting in 6.0, Storybook has deprecated the `.story` annotation in CSF and is using hoisted annotations.\n\n```sh\n./node_modules/.bin/jscodeshift -t ./node_modules/@storybook/codemod/dist/transforms/csf-hoist-story-annotations.js . --ignore-pattern \"node_modules|dist\" --extensions=js\n```\n\nFor example:\n\n```js\nexport const Basic = () => <Button />\nBasic.story = {\n  name: 'foo',\n  parameters: { ... },\n  decorators: [ ... ],\n};\n```\n\nBecomes:\n\n```js\nexport const Basic = () => <Button />\nBasic.storyName = 'foo';\nBasic.parameters = { ... };\nBasic.decorators = [ ... ];\n```\n\nThe new syntax is slightly more compact, is more ergonomic, and resembles React's `displayName`/`propTypes`/`defaultProps` annotations.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/lib/codemod/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    node: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./transforms/csf-2-to-3'],\n        entryPoint: './src/transforms/csf-2-to-3.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./transforms/find-implicit-spies'],\n        entryPoint: './src/transforms/find-implicit-spies.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./transforms/upgrade-deprecated-types'],\n        entryPoint: './src/transforms/upgrade-deprecated-types.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./transforms/upgrade-hierarchy-separators'],\n        entryPoint: './src/transforms/upgrade-hierarchy-separators.js',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/lib/codemod/package.json",
    "content": "{\n  \"name\": \"@storybook/codemod\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"A collection of codemod scripts written with JSCodeshift\",\n  \"keywords\": [\n    \"storybook\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/lib/codemod\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/lib/codemod\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"sideEffects\": false,\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./transforms/csf-2-to-3\": \"./dist/transforms/csf-2-to-3.js\",\n    \"./transforms/find-implicit-spies\": \"./dist/transforms/find-implicit-spies.js\",\n    \"./transforms/upgrade-deprecated-types\": \"./dist/transforms/upgrade-deprecated-types.js\",\n    \"./transforms/upgrade-hierarchy-separators\": \"./dist/transforms/upgrade-hierarchy-separators.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@types/cross-spawn\": \"^6.0.6\",\n    \"cross-spawn\": \"^7.0.6\",\n    \"es-toolkit\": \"^1.43.0\",\n    \"jscodeshift\": \"^0.15.1\",\n    \"prettier\": \"^3.7.1\",\n    \"storybook\": \"workspace:*\",\n    \"tiny-invariant\": \"^1.3.1\",\n    \"tinyglobby\": \"^0.2.13\"\n  },\n  \"devDependencies\": {\n    \"@types/jscodeshift\": \"^0.11.10\",\n    \"ansi-regex\": \"^6.0.1\",\n    \"ts-dedent\": \"^2.2.0\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/lib/codemod/project.json",
    "content": "{\n  \"name\": \"codemod\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/lib/codemod/src/index.test.ts",
    "content": "import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\n\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { runCodemod } from './index.ts';\n\nconst logger = {\n  step: vi.fn(),\n  log: vi.fn(),\n};\n\nconst csf2Source = `import { Meta, Story } from '@storybook/react-vite'\n\nimport { Chart, ChartProps } from './chart'\n\nexport default {\n  component: Chart,\n  title: 'Chart',\n} as Meta\n\nconst Template: Story<ChartProps> = (args) => <Chart {...args} />\n\nexport const SimpleBar = Template.bind({})\nSimpleBar.args = { name: 'test' }\n`;\n\ndescribe('runCodemod', () => {\n  const tempDir = join(tmpdir(), 'storybook-codemod-test');\n\n  beforeEach(() => {\n    mkdirSync(tempDir, { recursive: true });\n    vi.clearAllMocks();\n  });\n\n  afterEach(() => {\n    rmSync(tempDir, { recursive: true, force: true });\n  });\n\n  /**\n   * https://github.com/storybookjs/storybook/issues/33639\n   *\n   * Reproduces the bug where csf-2-to-3 silently fails because filenames are incorrectly quoted\n   * when passed to spawnSync.\n   *\n   * Test file from:\n   * https://github.com/seb-oss/green/blob/b634df24d2dae157300f73b711e569d1755eb138/libs/react-charts/src/lib/chart.stories.tsx\n   */\n  it('should transform CSF2 Template.bind({}) files with csf-2-to-3', async () => {\n    const storyFile = join(tempDir, 'chart.stories.tsx');\n    writeFileSync(storyFile, csf2Source);\n\n    await runCodemod('csf-2-to-3', {\n      glob: storyFile,\n      logger,\n    });\n\n    const result = readFileSync(storyFile, 'utf-8');\n\n    // csf-2-to-3 should transform Template.bind({}) to CSF3 object\n    expect(result).not.toContain('Template.bind({})');\n    expect(result).toContain('export const SimpleBar = {');\n  });\n\n  it('should handle filenames with spaces', async () => {\n    const storyFile = join(tempDir, 'my component.stories.tsx');\n    writeFileSync(storyFile, csf2Source);\n\n    await runCodemod('csf-2-to-3', {\n      glob: storyFile,\n      logger,\n    });\n\n    const result = readFileSync(storyFile, 'utf-8');\n\n    expect(result).not.toContain('Template.bind({})');\n    expect(result).toContain('export const SimpleBar = {');\n  });\n\n  it('should handle glob patterns', async () => {\n    const storyFile1 = join(tempDir, 'chart.stories.tsx');\n    const storyFile2 = join(tempDir, 'button.stories.tsx');\n    writeFileSync(storyFile1, csf2Source);\n    writeFileSync(storyFile2, csf2Source);\n\n    await runCodemod('csf-2-to-3', {\n      glob: join(tempDir, '*.stories.tsx'),\n      logger,\n    });\n\n    const result1 = readFileSync(storyFile1, 'utf-8');\n    const result2 = readFileSync(storyFile2, 'utf-8');\n\n    expect(result1).not.toContain('Template.bind({})');\n    expect(result2).not.toContain('Template.bind({})');\n  });\n\n  it('should handle recursive glob patterns', async () => {\n    const nestedDir = join(tempDir, 'components', 'charts');\n    mkdirSync(nestedDir, { recursive: true });\n\n    const storyFile1 = join(tempDir, 'root.stories.tsx');\n    const storyFile2 = join(nestedDir, 'nested.stories.tsx');\n    writeFileSync(storyFile1, csf2Source);\n    writeFileSync(storyFile2, csf2Source);\n\n    await runCodemod('csf-2-to-3', {\n      glob: join(tempDir, '**/*.stories.tsx'),\n      logger,\n    });\n\n    const result1 = readFileSync(storyFile1, 'utf-8');\n    const result2 = readFileSync(storyFile2, 'utf-8');\n\n    expect(result1).not.toContain('Template.bind({})');\n    expect(result2).not.toContain('Template.bind({})');\n  });\n});\n"
  },
  {
    "path": "code/lib/codemod/src/index.ts",
    "content": "/* eslint import-x/prefer-default-export: \"off\" */\nimport { readdirSync } from 'node:fs';\nimport { rename as renameAsync } from 'node:fs/promises';\nimport { extname, join } from 'node:path';\n\nimport { resolvePackageDir } from 'storybook/internal/common';\n\nimport { sync as spawnSync } from 'cross-spawn';\nimport { normalize } from 'pathe';\nimport { glob as tinyglobby } from 'tinyglobby';\n\nimport { jscodeshiftToPrettierParser } from './lib/utils.ts';\n\nconst TRANSFORM_DIR = join(resolvePackageDir('@storybook/codemod'), 'dist', 'transforms');\n\nexport function listCodemods() {\n  return readdirSync(TRANSFORM_DIR)\n    .filter((fname) => fname.endsWith('.js'))\n    .map((fname) => fname.slice(0, -3));\n}\n\nasync function renameFile(file: any, from: any, to: any, { logger }: any) {\n  const newFile = file.replace(from, to);\n  logger.log(`Rename: ${file} ${newFile}`);\n  return renameAsync(file, newFile);\n}\n\nexport async function runCodemod(\n  codemod: any,\n  {\n    glob,\n    logger,\n    dryRun,\n    rename,\n    parser,\n  }: { glob: any; logger: any; dryRun?: any; rename?: any; parser?: any }\n) {\n  const codemods = listCodemods();\n  if (!codemods.includes(codemod)) {\n    throw new Error(`Unknown codemod ${codemod}. Run --list for options.`);\n  }\n\n  let renameParts = null;\n  if (rename) {\n    renameParts = rename.split(':');\n    if (renameParts.length !== 2) {\n      throw new Error(`Codemod rename: expected format \"from:to\", got \"${rename}\"`);\n    }\n  }\n\n  // jscodeshift/prettier know how to handle .ts/.tsx extensions,\n  // so if the user uses one of those globs, we can auto-infer\n  let inferredParser = parser;\n\n  if (!parser) {\n    const extension = extname(glob).slice(1);\n    const knownParser = jscodeshiftToPrettierParser(extension);\n\n    if (knownParser !== 'babel') {\n      inferredParser = extension;\n    }\n  }\n\n  // Normalize the glob pattern to use forward slashes (required for glob patterns on Windows)\n  const files = await tinyglobby([normalize(glob), '!**/node_modules', '!**/dist']);\n  const extensions = new Set(files.map((file) => extname(file).slice(1)));\n  const commaSeparatedExtensions = Array.from(extensions).join(',');\n\n  logger.step(`Applying ${codemod}: ${files.length} files`);\n\n  if (files.length === 0) {\n    logger.step(`No matching files for glob: ${glob}`);\n    return;\n  }\n\n  if (!dryRun && files.length > 0) {\n    const parserArgs = inferredParser ? ['--parser', inferredParser] : [];\n    const result = spawnSync(\n      'node',\n      [\n        join(resolvePackageDir('jscodeshift'), 'bin', 'jscodeshift'),\n        // this makes sure codeshift doesn't transform our own source code with babel\n        // which is faster, and also makes sure the user won't see babel messages such as:\n        // [BABEL] Note: The code generator has deoptimised the styling of repo/node_modules/prettier/index.js as it exceeds the max of 500KB.\n        '--no-babel',\n        `--extensions=${commaSeparatedExtensions}`,\n        '--fail-on-error',\n        '-t',\n        `${TRANSFORM_DIR}/${codemod}.js`,\n        ...parserArgs,\n        ...files,\n      ],\n      {\n        stdio: 'inherit',\n      }\n    );\n\n    if (codemod === 'mdx-to-csf' && result.status === 1) {\n      logger.log(\n        'The codemod was not able to transform the files mentioned above. We have renamed the files to .mdx.broken. Please check the files and rename them back to .mdx after you have either manually transformed them to mdx + csf or fixed the issues so that the codemod can transform them.'\n      );\n    } else if (result.status === 1) {\n      logger.log('Skipped renaming because of errors.');\n      return;\n    }\n  }\n\n  if (renameParts) {\n    const [from, to] = renameParts;\n    logger.step(`Renaming ${rename}: ${files.length} files`);\n    await Promise.all(\n      files.map((file) => renameFile(file, new RegExp(`${from}$`), to, { logger }))\n    );\n  }\n}\n"
  },
  {
    "path": "code/lib/codemod/src/lib/utils.test.js",
    "content": "import { expect, it } from 'vitest';\n\nimport { sanitizeName } from './utils';\n\nit('should sanitize names', () => {\n  expect(sanitizeName('basic')).toMatchInlineSnapshot(`\"Basic\"`);\n  expect(sanitizeName('with space')).toMatchInlineSnapshot(`\"WithSpace\"`);\n  expect(sanitizeName('default')).toMatchInlineSnapshot(`\"Default\"`);\n  expect(sanitizeName('w/punctuation')).toMatchInlineSnapshot(`\"WPunctuation\"`);\n  expect(sanitizeName('5')).toMatchInlineSnapshot(`\"_5\"`);\n});\n"
  },
  {
    "path": "code/lib/codemod/src/lib/utils.ts",
    "content": "import { camelCase, upperFirst } from 'es-toolkit/string';\n\nexport const sanitizeName = (name: string) => {\n  let key = upperFirst(camelCase(name)) as string;\n  // prepend _ if name starts with a digit\n  if (/^\\d/.test(key)) {\n    key = `_${key}`;\n  }\n  // prepend _ if name starts with a digit\n  if (/^\\d/.test(key)) {\n    key = `_${key}`;\n  }\n  return key;\n};\n\nexport function jscodeshiftToPrettierParser(parser?: string) {\n  const parserMap: Record<string, string> = {\n    babylon: 'babel',\n    flow: 'flow',\n    ts: 'typescript',\n    tsx: 'typescript',\n  };\n\n  if (!parser) {\n    return 'babel';\n  }\n  return parserMap[parser] || 'babel';\n}\n"
  },
  {
    "path": "code/lib/codemod/src/transforms/__testfixtures__/upgrade-hierarchy-separators/csf.input.js",
    "content": "export default {\n  title: 'Foo|Bar/baz.whatever',\n};\n"
  },
  {
    "path": "code/lib/codemod/src/transforms/__testfixtures__/upgrade-hierarchy-separators/csf.output.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`upgrade-hierarchy-separators transforms correctly using \"csf.input.js\" data 1`] = `\n\"export default {\n  title: 'Foo/Bar/baz/whatever',\n};\"\n`;\n"
  },
  {
    "path": "code/lib/codemod/src/transforms/__testfixtures__/upgrade-hierarchy-separators/dynamic-storiesof.input.js",
    "content": "import { storiesOf } from '@storybook/react';\n\nconst foo = 'some|generated/path';\n\nstoriesOf(foo, module).add('foobar', () => <>hmm</>);\n"
  },
  {
    "path": "code/lib/codemod/src/transforms/__testfixtures__/upgrade-hierarchy-separators/dynamic-storiesof.output.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`upgrade-hierarchy-separators transforms correctly using \"dynamic-storiesof.input.js\" data 1`] = `\n\"import { storiesOf } from '@storybook/react';\n\nconst foo = 'some|generated/path';\n\nstoriesOf(foo, module).add('foobar', () => <>hmm</>);\"\n`;\n"
  },
  {
    "path": "code/lib/codemod/src/transforms/__testfixtures__/upgrade-hierarchy-separators/storiesof.input.js",
    "content": "import { storiesOf } from '@storybook/react';\n\nstoriesOf('A/B/C', module).add('abc', () => <div>hello</div>);\nstoriesOf('D|E/f', module).add('def', () => <div>hello</div>);\n\nstoriesOf('G|h/i.jkl', module)\n  .add('hijkl', () => <div>hello</div>)\n  .add('whatever', () => <div>goodbye!</div>);\n"
  },
  {
    "path": "code/lib/codemod/src/transforms/__testfixtures__/upgrade-hierarchy-separators/storiesof.output.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`upgrade-hierarchy-separators transforms correctly using \"storiesof.input.js\" data 1`] = `\n\"import { storiesOf } from '@storybook/react';\n\nstoriesOf('A/B/C', module).add('abc', () => <div>hello</div>);\nstoriesOf('D/E/f', module).add('def', () => <div>hello</div>);\n\nstoriesOf('G/h/i/jkl', module)\n  .add('hijkl', () => <div>hello</div>)\n  .add('whatever', () => <div>goodbye!</div>);\"\n`;\n"
  },
  {
    "path": "code/lib/codemod/src/transforms/__tests__/__snapshots__/upgrade-deprecated-types.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`upgrade-deprecated-types > typescript > upgrade imports with conflicting local names 1`] = `\nSyntaxError: This codemod does not support local imports that are called the same as a storybook import.\nRename this local import and try again.\n> 1 |  import { ComponentMeta as Meta, ComponentStory as StoryFn } from '@storybook/react';\n    |           ^^^^^^^^^^^^^^^^^^^^^\n  2 |  import { Cat } from './Cat';\n  3 |    \n  4 |  const meta = { title: 'Cat', component: Cat } satisfies Meta<typeof Cat>\n`;\n\nexports[`upgrade-deprecated-types > typescript > upgrade imports with local names 1`] = `\nimport {\n  StoryFn as Story_,\n  Meta as ComponentMeta_,\n  StoryObj as ComponentStoryObj_,\n} from \"@storybook/react\";\nimport { Cat } from \"./Cat\";\n\nconst meta = { title: \"Cat\", component: Cat } satisfies ComponentMeta_<\n  typeof Cat\n>;\nconst meta2: ComponentMeta_<typeof Cat> = { title: \"Cat\", component: Cat };\nexport default meta;\n\nexport const A: Story__<typeof Cat> = (args) => <Cat {...args} />;\nexport const B: any = (args) => <Button {...args} />;\nexport const C: StoryFn_<typeof Cat> = (args) => <Cat {...args} />;\nexport const D: ComponentStoryObj_<typeof Cat> = {\n  args: {\n    name: \"Fluffy\",\n  },\n};\nexport const E: Story_<CatProps> = (args) => <Cat {...args} />;\n`;\n\nexports[`upgrade-deprecated-types > typescript > upgrade namespaces 1`] = `\nimport * as SB from \"@storybook/react\";\nimport { Cat, CatProps } from \"./Cat\";\n\nconst meta = { title: \"Cat\", component: Cat } satisfies SB.Meta<typeof Cat>;\nconst meta2: SB.Meta<typeof Cat> = { title: \"Cat\", component: Cat };\nexport default meta;\n\nexport const A: SB.StoryFn<typeof Cat> = (args) => <Cat {...args} />;\nexport const B: any = (args) => <Button {...args} />;\nexport const C: SB.StoryFn<typeof Cat> = (args) => <Cat {...args} />;\nexport const D: SB.StoryObj<typeof Cat> = {\n  args: {\n    name: \"Fluffy\",\n  },\n};\nexport const E: SB.StoryFn<CatProps> = (args) => <Cat {...args} />;\n`;\n\nexports[`upgrade-deprecated-types > typescript > upgrade regular imports 1`] = `\nimport { StoryFn, Meta, StoryObj } from \"@storybook/react\";\nimport { Cat, CatProps } from \"./Cat\";\n\nconst meta = { title: \"Cat\", component: Cat } satisfies Meta<typeof Cat>;\nconst meta2: Meta<CatProps> = { title: \"Cat\", component: Cat };\nexport default meta;\n\nexport const A: StoryFn<typeof Cat> = (args) => <Cat {...args} />;\nexport const B: any = (args) => <Button {...args} />;\nexport const C: StoryFn<typeof Cat> = (args) => <Cat {...args} />;\nexport const D: StoryObj<typeof Cat> = {\n  args: {\n    name: \"Fluffy\",\n  },\n};\nexport const E: StoryFn<CatProps> = (args) => <Cat {...args} />;\n`;\n"
  },
  {
    "path": "code/lib/codemod/src/transforms/__tests__/csf-2-to-3.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport ansiRegex from 'ansi-regex';\nimport type { API } from 'jscodeshift';\nimport { dedent } from 'ts-dedent';\n\nimport _transform from '../csf-2-to-3.ts';\n\nexpect.addSnapshotSerializer({\n  serialize: (val: any) => (typeof val === 'string' ? val : val.toString()),\n  test: () => true,\n});\n\nconst jsTransform = async (source: string) =>\n  (await _transform({ source, path: 'Component.stories.jsx' }, {} as API, {})).trim();\nconst tsTransform = async (source: string) =>\n  (\n    await _transform({ source, path: 'Component.stories.tsx' }, {} as API, {\n      parser: 'tsx',\n    })\n  ).trim();\n\ndescribe('csf-2-to-3', () => {\n  describe('javascript', () => {\n    it('should replace non-simple function exports with objects', async () => {\n      await expect(\n        jsTransform(dedent`\n          export default { title: 'Cat' };\n          export const A = () => <Cat />;\n          export const B = (args) => <Button {...args} />;\n        `)\n      ).resolves.toMatchInlineSnapshot(`\n        export default { title: \"Cat\" };\n        export const A = () => <Cat />;\n        export const B = {\n          render: (args) => <Button {...args} />,\n        };\n      `);\n    });\n\n    it('should move annotations into story objects', async () => {\n      await expect(\n        jsTransform(dedent`\n          export default { title: 'Cat' };\n\n          export const A = () => <Cat />;\n          A.storyName = 'foo';\n          A.parameters = { bar: 2 };\n          A.play = () => {};\n        `)\n      ).resolves.toMatchInlineSnapshot(`\n        export default { title: \"Cat\" };\n\n        export const A = {\n          render: () => <Cat />,\n          name: \"foo\",\n          parameters: { bar: 2 },\n          play: () => {},\n        };\n      `);\n    });\n\n    it('should ignore non-story exports, statements', async () => {\n      await expect(\n        jsTransform(dedent`\n          export default { title: 'components/Fruit', includeStories: ['A'] };\n\n          export const A = (args) => <Apple {...args} />;\n\n          export const B = (args) => <Banana {...args} />;\n\n          const C = (args) => <Cherry {...args} />;\n        `)\n      ).resolves.toMatchInlineSnapshot(`\n        export default { title: \"components/Fruit\", includeStories: [\"A\"] };\n\n        export const A = {\n          render: (args) => <Apple {...args} />,\n        };\n\n        export const B = (args) => <Banana {...args} />;\n\n        const C = (args) => <Cherry {...args} />;\n      `);\n    });\n\n    it('should do nothing when there is no meta', async () => {\n      await expect(\n        jsTransform(dedent`\n          export const A = () => <Apple />;\n\n          export const B = (args) => <Banana {...args} />;\n        `)\n      ).resolves.toMatchInlineSnapshot(`\n        export const A = () => <Apple />;\n\n        export const B = (args) => <Banana {...args} />;\n      `);\n    });\n\n    it('should remove implicit global render function (react)', async () => {\n      await expect(\n        jsTransform(dedent`\n          export default { title: 'Cat', component: Cat };\n          export const A = (args) => <Cat {...args} />;\n          export const B = (args) => <Banana {...args} />;\n        `)\n      ).resolves.toMatchInlineSnapshot(`\n        export default { title: \"Cat\", component: Cat };\n        export const A = {};\n        export const B = {\n          render: (args) => <Banana {...args} />,\n        };\n      `);\n    });\n\n    it('should ignore object exports', async () => {\n      await expect(\n        jsTransform(dedent`\n          export default { title: 'Cat', component: Cat };\n\n          export const A = {\n            render: (args) => <Cat {...args} />\n          };\n        `)\n      ).resolves.toMatchInlineSnapshot(`\n        export default { title: \"Cat\", component: Cat };\n\n        export const A = {\n          render: (args) => <Cat {...args} />,\n        };\n      `);\n    });\n\n    it('should hoist template.bind (if there is only one)', async () => {\n      await expect(\n        jsTransform(dedent`\n          export default { title: 'Cat' };\n          const Template = (args) => <Cat {...args} />;\n          export const A = Template.bind({});\n          A.args = { isPrimary: false };\n        `)\n      ).resolves.toMatchInlineSnapshot(`\n        export default { title: \"Cat\" };\n        const Template = (args) => <Cat {...args} />;\n\n        export const A = {\n          render: Template,\n          args: { isPrimary: false },\n        };\n      `);\n    });\n\n    it('should reuse the template when there are multiple Template.bind references but no component defined', async () => {\n      await expect(\n        jsTransform(dedent`\n          export default { title: 'Cat' };\n          const Template = (args) => <Cat {...args} />;\n\n          export const A = Template.bind({});\n          A.args = { isPrimary: false };\n          \n          export const B = Template.bind({});\n          B.args = { isPrimary: true };\n          \n                    \n          export const C = Template.bind({});\n          C.args = { bla: true };\n          \n          export const D = Template.bind({});\n          D.args = { bla: false };\n        `)\n      ).resolves.toMatchInlineSnapshot(`\n        export default { title: \"Cat\" };\n        const Template = (args) => <Cat {...args} />;\n\n        export const A = {\n          render: Template,\n          args: { isPrimary: false },\n        };\n\n        export const B = {\n          render: Template,\n          args: { isPrimary: true },\n        };\n\n        export const C = {\n          render: Template,\n          args: { bla: true },\n        };\n\n        export const D = {\n          render: Template,\n          args: { bla: false },\n        };\n      `);\n    });\n\n    it('should remove implicit global render for template.bind', async () => {\n      await expect(\n        jsTransform(dedent`\n          export default { title: 'Cat', component: Cat };\n\n          const Template = (args) => <Cat {...args} />;\n\n          export const A = Template.bind({});\n          A.args = { isPrimary: false };\n\n          const Template2 = (args) => <Banana {...args} />;\n\n          export const B = Template2.bind({});\n          B.args = { isPrimary: true };\n        `)\n      ).resolves.toMatchInlineSnapshot(`\n        export default { title: \"Cat\", component: Cat };\n\n        export const A = {\n          args: { isPrimary: false },\n        };\n\n        const Template2 = (args) => <Banana {...args} />;\n\n        export const B = {\n          render: Template2,\n          args: { isPrimary: true },\n        };\n      `);\n    });\n\n    it('should ignore no-arg stories without annotations', async () => {\n      await expect(\n        jsTransform(dedent`\n          export default { title: 'Cat', component: Cat };\n\n          export const A = (args) => <Cat {...args} />;\n          export const B = () => <Cat name=\"frisky\" />;\n          export const C = () => <Cat name=\"fluffy\" />;\n          C.parameters = { foo: 2 };\n        `)\n      ).resolves.toMatchInlineSnapshot(`\n        export default { title: \"Cat\", component: Cat };\n\n        export const A = {};\n        export const B = () => <Cat name=\"frisky\" />;\n\n        export const C = {\n          render: () => <Cat name=\"fluffy\" />,\n          parameters: { foo: 2 },\n        };\n      `);\n    });\n\n    it('should work for v1-style annotations', async () => {\n      await expect(\n        jsTransform(dedent`\n          export default { title: 'Cat' };\n          export const A = (args) => <Cat {...args} />;\n          A.story = {\n            parameters: { foo: 2 }\n          };\n        `)\n      ).resolves.toMatchInlineSnapshot(`\n        export default { title: \"Cat\" };\n\n        export const A = {\n          render: (args) => <Cat {...args} />,\n          parameters: { foo: 2 },\n        };\n      `);\n    });\n  });\n\n  describe('typescript', () => {\n    it('should error with namespace imports', async () => {\n      await expect.addSnapshotSerializer({\n        serialize: (value) => {\n          const stringVal = typeof value === 'string' ? value : value.toString();\n          return stringVal.replace(ansiRegex(), '');\n        },\n        test: () => true,\n      });\n      await expect(() =>\n        tsTransform(dedent`\n          import * as SB from '@storybook/react';\n          import { CatProps } from './Cat';\n\n          const meta = { title: 'Cat', component: Cat } as Meta<CatProps>\n          export default meta;\n\n          export const A: SB.StoryFn<CatProps> = () => <Cat />;\n        `)\n      ).rejects.toThrowErrorMatchingInlineSnapshot(dedent`\n        Error: This codemod does not support namespace imports for a @storybook/react package.\n        Replace the namespace import with named imports and try again.\n      `);\n    });\n    it('should keep local names', async () => {\n      await expect(\n        tsTransform(dedent`\n          import { Meta, StoryObj as CSF3, StoryFn as CSF2 } from '@storybook/react';\n          import { CatProps } from './Cat';\n\n          const meta = { title: 'Cat', component: Cat } satisfies Meta<CatProps>\n          export default meta;\n\n          export const A: CSF2<CatProps> = () => <Cat />;\n          \n          export const B: CSF3<CatProps> = {\n            args: { name: \"already csf3\" }\n          };\n\n          export const C: CSF2<CatProps> = (args) => <Cat {...args} />;\n          C.args = { \n            name: \"Fluffy\"\n          };\n        `)\n      ).resolves.toMatchInlineSnapshot(`\n        import { Meta, StoryObj as CSF3, StoryFn as CSF2 } from \"@storybook/react\";\n        import { CatProps } from \"./Cat\";\n\n        const meta = { title: \"Cat\", component: Cat } satisfies Meta<CatProps>;\n        export default meta;\n\n        export const A: CSF2<CatProps> = () => <Cat />;\n\n        export const B: CSF3<CatProps> = {\n          args: { name: \"already csf3\" },\n        };\n\n        export const C: CSF3<CatProps> = {\n          args: {\n            name: \"Fluffy\",\n          },\n        };\n      `);\n    });\n\n    it('should replace function exports with objects and update type', async () => {\n      await expect(\n        tsTransform(dedent`\n          import { Story, StoryFn, ComponentStory, ComponentStoryObj } from '@storybook/react';\n\n          // some extra whitespace to test\n\n          export default { \n            title: 'Cat', \n            component: Cat,\n          } as Meta<CatProps>;\n\n          export const A: Story<CatProps> = (args) => <Cat {...args} />;\n          A.args = { name: \"Fluffy\" };\n\n          export const B: any = (args) => <Button {...args} />;\n\n          export const C: Story<CatProps> = () => <Cat />;\n\n          export const D: StoryFn<CatProps> = (args) => <Cat {...args} />;\n          D.args = { \n            name: \"Fluffy\"\n          };\n          \n          export const E: ComponentStory<Cat> = (args) => <Cat {...args} />;\n          E.args = { name: \"Fluffy\" };\n          \n          export const F: Story = (args) => <Cat {...args} />;\n          F.args = { \n            name: \"Fluffy\"\n          };\n          \n          export const G: ComponentStoryObj<typeof Cat> = {\n            args: {\n              name: 'Fluffy',\n            },\n          };\n        `)\n      ).resolves.toMatchInlineSnapshot(`\n        import { StoryObj, StoryFn } from \"@storybook/react\";\n\n        // some extra whitespace to test\n\n        export default {\n          title: \"Cat\",\n          component: Cat,\n        } as Meta<CatProps>;\n\n        export const A: StoryObj<CatProps> = {\n          args: { name: \"Fluffy\" },\n        };\n\n        export const B: any = {\n          render: (args) => <Button {...args} />,\n        };\n\n        export const C: StoryFn<CatProps> = () => <Cat />;\n\n        export const D: StoryObj<CatProps> = {\n          args: {\n            name: \"Fluffy\",\n          },\n        };\n\n        export const E: StoryObj<Cat> = {\n          args: { name: \"Fluffy\" },\n        };\n\n        export const F: StoryObj = {\n          args: {\n            name: \"Fluffy\",\n          },\n        };\n\n        export const G: StoryObj<typeof Cat> = {\n          args: {\n            name: \"Fluffy\",\n          },\n        };\n      `);\n    });\n\n    it('migrate Story type to StoryFn when used in an not exported Template function', async () => {\n      await expect(\n        tsTransform(dedent`\n          import { Story, Meta } from '@storybook/react'\n          \n          export default {\n            component: Cat,\n          } satisfies Meta\n          \n          const Template: Story = () => <div>Hello World</div>;\n          \n          export const Default = Template.bind({})\n        `)\n      ).resolves.toMatchInlineSnapshot(`\n        import { StoryFn, Meta } from \"@storybook/react\";\n\n        export default {\n          component: Cat,\n        } satisfies Meta;\n\n        const Template: StoryFn = () => <div>Hello World</div>;\n\n        export const Default = {\n          render: Template,\n        };\n      `);\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/codemod/src/transforms/__tests__/find-implicit-spies.test.ts",
    "content": "import { beforeEach, expect, test, vi } from 'vitest';\n\nimport ansiRegex from 'ansi-regex';\nimport { dedent } from 'ts-dedent';\n\nimport transform from '../find-implicit-spies.ts';\n\nexpect.addSnapshotSerializer({\n  print: (val, print) => print((val as string).replace(ansiRegex(), '')),\n  test: (value) => typeof value === 'string' && ansiRegex().test(value),\n});\n\nconst tsTransform = async (source: string) => transform({ source, path: 'Component.stories.tsx' });\n\nconst warn = vi.spyOn(console, 'warn');\n\nbeforeEach(() => {\n  warn.mockImplementation(() => {});\n});\n\ntest('Warn for possible implicit actions', async () => {\n  const input = dedent`\n    export default { title: 'foo/bar', args: {onClick: fn() }, argTypes: { onHover: {action: true} } };\n    const Template = (args) => { };\n    export const A = Template.bind({});\n    A.args = { onBla: fn() };\n    A.play = async ({ args }) => {\n      await userEvent.click(screen.getByRole(\"button\"));\n      await expect(args.onImplicit).toHaveBeenCalled();\n      await expect(args.onClick).toHaveBeenCalled();\n      await expect(args.onHover).toHaveBeenCalled();\n      await expect(args.onBla).toHaveBeenCalled();\n    };\n    \n    export const B = { \n      args: {onBla: fn() },\n      play: async ({ args }) => {\n        await userEvent.click(screen.getByRole(\"button\"));\n        await expect(args.onImplicit).toHaveBeenCalled();\n        await expect(args.onClick).toHaveBeenCalled();\n        await expect(args.onHover).toHaveBeenCalled();\n        await expect(args.onBla).toHaveBeenCalled();\n      }\n    };\n  `;\n\n  await tsTransform(input);\n\n  expect(warn.mock.calls).toMatchInlineSnapshot(`\n    [\n      [\n        \"Component.stories.tsx Possible implicit spy found\n       5 | A.play = async ({ args }) => {\n       6 |   await userEvent.click(screen.getByRole(\"button\"));\n    >  7 |   await expect(args.onImplicit).toHaveBeenCalled();\n         |                     ^^^^^^^^^^\n       8 |   await expect(args.onClick).toHaveBeenCalled();\n       9 |   await expect(args.onHover).toHaveBeenCalled();\n      10 |   await expect(args.onBla).toHaveBeenCalled();\",\n      ],\n      [\n        \"Component.stories.tsx Possible implicit spy found\n      15 |   play: async ({ args }) => {\n      16 |     await userEvent.click(screen.getByRole(\"button\"));\n    > 17 |     await expect(args.onImplicit).toHaveBeenCalled();\n         |                       ^^^^^^^^^^\n      18 |     await expect(args.onClick).toHaveBeenCalled();\n      19 |     await expect(args.onHover).toHaveBeenCalled();\n      20 |     await expect(args.onBla).toHaveBeenCalled();\",\n      ],\n    ]\n  `);\n});\n"
  },
  {
    "path": "code/lib/codemod/src/transforms/__tests__/upgrade-deprecated-types.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport ansiRegex from 'ansi-regex';\nimport type { API } from 'jscodeshift';\nimport { dedent } from 'ts-dedent';\n\nimport _transform from '../upgrade-deprecated-types.ts';\n\nexpect.addSnapshotSerializer({\n  serialize: (val: any) => (typeof val === 'string' ? val : val.toString()),\n  test: () => true,\n});\n\nconst tsTransform = async (source: string) =>\n  (\n    await _transform({ source, path: 'Component.stories.tsx' }, {} as API, {\n      parser: 'tsx',\n    })\n  ).trim();\n\ndescribe('upgrade-deprecated-types', () => {\n  describe('typescript', () => {\n    it('upgrade regular imports', async () => {\n      await expect(\n        tsTransform(dedent`\n          import { Story, ComponentMeta, Meta, ComponentStory, ComponentStoryObj, ComponentStoryFn } from '@storybook/react';\n          import { Cat, CatProps } from './Cat';\n            \n          const meta = { title: 'Cat', component: Cat } satisfies ComponentMeta<typeof Cat>\n          const meta2: Meta<CatProps> = { title: 'Cat', component: Cat };\n          export default meta;\n          \n          export const A: ComponentStory<typeof Cat> = (args) => <Cat {...args} />;\n          export const B: any = (args) => <Button {...args} />;\n          export const C: ComponentStoryFn<typeof Cat> = (args) => <Cat {...args} />;\n          export const D: ComponentStoryObj<typeof Cat> = {\n            args: {\n              name: 'Fluffy',\n            },\n          };\n          export const E: Story<CatProps> = (args) => <Cat {...args} />;\n        `)\n      ).resolves.toMatchSnapshot();\n    });\n\n    it('upgrade imports with local names', async () => {\n      await expect(\n        tsTransform(dedent`\n          import { Story as Story_, ComponentMeta as ComponentMeta_, ComponentStory as Story__, ComponentStoryObj as ComponentStoryObj_, ComponentStoryFn as StoryFn_ } from '@storybook/react';\n          import { Cat } from './Cat';\n            \n          const meta = { title: 'Cat', component: Cat } satisfies ComponentMeta_<typeof Cat>\n          const meta2: ComponentMeta_<typeof Cat> = { title: 'Cat', component: Cat };\n          export default meta;\n          \n          export const A: Story__<typeof Cat> = (args) => <Cat {...args} />;\n          export const B: any = (args) => <Button {...args} />;\n          export const C: StoryFn_<typeof Cat> = (args) => <Cat {...args} />;\n          export const D: ComponentStoryObj_<typeof Cat> = {\n            args: {\n              name: 'Fluffy',\n            },\n          };\n          export const E: Story_<CatProps> = (args) => <Cat {...args} />;\n        `)\n      ).resolves.toMatchSnapshot();\n    });\n\n    it('upgrade imports with conflicting local names', async () => {\n      await expect.addSnapshotSerializer({\n        serialize: (value) => {\n          const stringVal = typeof value === 'string' ? value : value.toString();\n          return stringVal.replace(ansiRegex(), '');\n        },\n        test: () => true,\n      });\n\n      await expect(() =>\n        tsTransform(dedent`\n          import { ComponentMeta as Meta, ComponentStory as StoryFn } from '@storybook/react';\n          import { Cat } from './Cat';\n            \n          const meta = { title: 'Cat', component: Cat } satisfies Meta<typeof Cat>\n          export default meta;\n          \n          export const A: StoryFn<typeof Cat> = (args) => <Cat {...args} />;\n         \n        `)\n      ).rejects.toThrowErrorMatchingSnapshot();\n    });\n\n    it('upgrade namespaces', async () => {\n      await expect(\n        tsTransform(dedent`\n          import * as SB from '@storybook/react';\n          import { Cat, CatProps } from './Cat';\n  \n          const meta = { title: 'Cat', component: Cat } satisfies SB.ComponentMeta<typeof Cat>;\n          const meta2: SB.ComponentMeta<typeof Cat> = { title: 'Cat', component: Cat };\n          export default meta;\n  \n          export const A: SB.ComponentStory<typeof Cat> = (args) => <Cat {...args} />;\n          export const B: any = (args) => <Button {...args} />;\n          export const C: SB.ComponentStoryFn<typeof Cat> = (args) => <Cat {...args} />;\n          export const D: SB.ComponentStoryObj<typeof Cat> = {\n            args: {\n              name: 'Fluffy',\n            },\n          };\n          export const E: SB.Story<CatProps> = (args) => <Cat {...args} />;\n          \n        `)\n      ).resolves.toMatchSnapshot();\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/codemod/src/transforms/csf-2-to-3.ts",
    "content": "import type { BabelFile, NodePath } from 'storybook/internal/babel';\nimport { core as babel, types as t } from 'storybook/internal/babel';\nimport type { CsfFile } from 'storybook/internal/csf-tools';\nimport { loadCsf, printCsf } from 'storybook/internal/csf-tools';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport type { API, FileInfo } from 'jscodeshift';\nimport prettier from 'prettier';\nimport invariant from 'tiny-invariant';\n\nimport { upgradeDeprecatedTypes } from './upgrade-deprecated-types.ts';\n\nconst { isIdentifier, isTSTypeAnnotation, isTSTypeReference } = t;\n\nconst renameAnnotation = (annotation: string) => {\n  return annotation === 'storyName' ? 'name' : annotation;\n};\n\nconst getTemplateBindVariable = (init: t.Expression | undefined) =>\n  t.isCallExpression(init) &&\n  t.isMemberExpression(init.callee) &&\n  t.isIdentifier(init.callee.object) &&\n  t.isIdentifier(init.callee.property) &&\n  init.callee.property.name === 'bind' &&\n  (init.arguments.length === 0 ||\n    (init.arguments.length === 1 &&\n      t.isObjectExpression(init.arguments[0]) &&\n      init.arguments[0].properties.length === 0))\n    ? init.callee.object.name\n    : null;\n\n// export const A = ...\n// A.parameters = { ... }; <===\nconst isStoryAnnotation = (stmt: t.Statement, objectExports: Record<string, any>) =>\n  t.isExpressionStatement(stmt) &&\n  t.isAssignmentExpression(stmt.expression) &&\n  t.isMemberExpression(stmt.expression.left) &&\n  t.isIdentifier(stmt.expression.left.object) &&\n  objectExports[stmt.expression.left.object.name];\n\nconst getNewExport = (stmt: t.Statement, objectExports: Record<string, any>) => {\n  if (\n    t.isExportNamedDeclaration(stmt) &&\n    t.isVariableDeclaration(stmt.declaration) &&\n    stmt.declaration.declarations.length === 1\n  ) {\n    const decl = stmt.declaration.declarations[0];\n    if (t.isVariableDeclarator(decl) && t.isIdentifier(decl.id)) {\n      return objectExports[decl.id.name];\n    }\n  }\n  return null;\n};\n\n// Remove render function when it matches the global render function in react\n// export default { component: Cat };\n// export const A = (args) => <Cat {...args} />;\nconst isReactGlobalRenderFn = (csf: CsfFile, storyFn: t.Expression) => {\n  if (\n    csf._meta?.component &&\n    t.isArrowFunctionExpression(storyFn) &&\n    storyFn.params.length === 1 &&\n    t.isJSXElement(storyFn.body)\n  ) {\n    const { openingElement } = storyFn.body;\n    if (\n      openingElement.selfClosing &&\n      t.isJSXIdentifier(openingElement.name) &&\n      openingElement.attributes.length === 1\n    ) {\n      const attr = openingElement.attributes[0];\n      const param = storyFn.params[0];\n      if (\n        t.isJSXSpreadAttribute(attr) &&\n        t.isIdentifier(attr.argument) &&\n        t.isIdentifier(param) &&\n        param.name === attr.argument.name &&\n        csf._meta.component === openingElement.name.name\n      ) {\n        return true;\n      }\n    }\n  }\n  return false;\n};\n\n// A simple CSF story is a no-arg story without any extra annotations (params, args, etc.)\nconst isSimpleCSFStory = (init: t.Expression, annotations: t.ObjectProperty[]) =>\n  annotations.length === 0 && t.isArrowFunctionExpression(init) && init.params.length === 0;\n\nfunction removeUnusedTemplates(csf: CsfFile) {\n  Object.entries(csf._templates).forEach(([template, templateExpression]) => {\n    const references: NodePath[] = [];\n    babel.traverse(csf._ast, {\n      Identifier: (path) => {\n        if (path.node.name === template) {\n          references.push(path as NodePath);\n        }\n      },\n    });\n    // if there is only one reference and this reference is the variable declaration initializing the template\n    // then we are sure the template is unused\n    if (references.length === 1) {\n      const reference = references[0];\n      if (\n        reference.parentPath?.isVariableDeclarator() &&\n        reference.parentPath.node.init === templateExpression\n      ) {\n        reference.parentPath.remove();\n      }\n    }\n  });\n}\n\nexport default async function transform(info: FileInfo, api: API, options: { parser?: string }) {\n  const makeTitle = (userTitle?: string) => {\n    return userTitle || 'FIXME';\n  };\n  const csf = loadCsf(info.source, { makeTitle });\n\n  try {\n    csf.parse();\n  } catch (err) {\n    logger.log(`Error ${err}, skipping`);\n    return info.source;\n  }\n\n  // This allows for showing buildCodeFrameError messages\n  // @ts-expect-error File is not yet exposed, see https://github.com/babel/babel/issues/11350#issuecomment-644118606\n\n  const file: BabelFile = new babel.File(\n    { filename: info.path },\n    { code: info.source, ast: csf._ast }\n  );\n\n  const importHelper = new StorybookImportHelper(file, info);\n\n  const objectExports: Record<string, t.Statement> = {};\n  Object.entries(csf._storyExports).forEach(([key, decl]) => {\n    const annotations = Object.entries(csf._storyAnnotations[key]).map(([annotation, val]) => {\n      return t.objectProperty(t.identifier(renameAnnotation(annotation)), val as t.Expression);\n    });\n\n    if (t.isVariableDeclarator(decl as t.Node)) {\n      const { init, id } = decl as any;\n      invariant(init, 'Inital value should be declared');\n      // only replace arrow function expressions && template\n      const template = getTemplateBindVariable(init);\n\n      if (!t.isArrowFunctionExpression(init) && !template) {\n        return;\n      }\n      // Do change the type of no-arg stories without annotations to StoryFn when applicable\n      // Do change the type of no-arg stories without annotations to StoryFn when applicable\n      if (isSimpleCSFStory(init, annotations)) {\n        objectExports[key] = t.exportNamedDeclaration(\n          t.variableDeclaration('const', [\n            t.variableDeclarator(importHelper.updateTypeTo(id, 'StoryFn'), init),\n          ])\n        );\n        return;\n      }\n\n      const storyFn: t.Expression = template ? t.identifier(template) : init;\n\n      // Remove the render function when we can hoist the template\n      // const Template = (args) => <Cat {...args} />;\n      // export const A = Template.bind({});\n      const renderAnnotation = isReactGlobalRenderFn(\n        csf,\n        template ? csf._templates[template] : storyFn\n      )\n        ? []\n        : [t.objectProperty(t.identifier('render'), storyFn)];\n\n      objectExports[key] = t.exportNamedDeclaration(\n        t.variableDeclaration('const', [\n          t.variableDeclarator(\n            importHelper.updateTypeTo(id, 'StoryObj'),\n            t.objectExpression([...renderAnnotation, ...annotations])\n          ),\n        ])\n      );\n    }\n  });\n\n  csf._ast.program.body = csf._ast.program.body.reduce((acc: t.Statement[], stmt: t.Statement) => {\n    const statement = stmt;\n    // remove story annotations & template declarations\n    if (isStoryAnnotation(statement, objectExports)) {\n      return acc;\n    }\n\n    // replace story exports with new object exports\n    const newExport = getNewExport(statement, objectExports);\n    if (newExport) {\n      acc.push(newExport);\n      return acc;\n    }\n\n    // include unknown statements\n    acc.push(statement);\n    return acc;\n  }, []);\n\n  upgradeDeprecatedTypes(file);\n  importHelper.removeDeprecatedStoryImport();\n  removeUnusedTemplates(csf);\n\n  let output = printCsf(csf).code;\n\n  try {\n    output = await prettier.format(output, {\n      ...(await prettier.resolveConfig(info.path)),\n      filepath: info.path,\n    });\n  } catch (e) {\n    logger.log(`Failed applying prettier to ${info.path}.`);\n  }\n\n  return output;\n}\n\nclass StorybookImportHelper {\n  constructor(file: BabelFile, info: FileInfo) {\n    this.sbImportDeclarations = this.getAllSbImportDeclarations(file);\n  }\n\n  private sbImportDeclarations: NodePath<t.ImportDeclaration>[];\n\n  private getAllSbImportDeclarations = (file: BabelFile) => {\n    const found: NodePath<t.ImportDeclaration>[] = [];\n\n    file.path.traverse({\n      ImportDeclaration: (path) => {\n        const source = path.node.source.value;\n\n        if (source.startsWith('@storybook/csf') || !source.startsWith('@storybook')) {\n          return;\n        }\n        const isRendererImport = path.get('specifiers').some((specifier) => {\n          if (specifier.isImportNamespaceSpecifier()) {\n            // throw path.buildCodeFrameError(\n            //   `This codemod does not support namespace imports for a ${path.node.source.value} package.\\n` +\n            //     'Replace the namespace import with named imports and try again.'\n            // );\n            throw new Error(\n              `This codemod does not support namespace imports for a ${path.node.source.value} package.\\n` +\n                'Replace the namespace import with named imports and try again.'\n            );\n          }\n\n          if (!specifier.isImportSpecifier()) {\n            return false;\n          }\n          const imported = specifier.get('imported');\n\n          if (Array.isArray(imported)) {\n            return imported.some((importedSpecifier) => {\n              if (!importedSpecifier.isIdentifier()) {\n                return false;\n              }\n              return [\n                'Story',\n                'StoryFn',\n                'StoryObj',\n                'Meta',\n                'ComponentStory',\n                'ComponentStoryFn',\n                'ComponentStoryObj',\n                'ComponentMeta',\n              ].includes(importedSpecifier.node.name);\n            });\n          }\n\n          if (!imported.isIdentifier()) {\n            return false;\n          }\n          return [\n            'Story',\n            'StoryFn',\n            'StoryObj',\n            'Meta',\n            'ComponentStory',\n            'ComponentStoryFn',\n            'ComponentStoryObj',\n            'ComponentMeta',\n          ].includes(imported.node.name);\n        });\n\n        if (isRendererImport) {\n          found.push(path);\n        }\n      },\n    });\n    return found;\n  };\n\n  getOrAddImport = (type: string): string | undefined => {\n    // prefer type import\n    const sbImport =\n      this.sbImportDeclarations.find((path) => path.node.importKind === 'type') ??\n      this.sbImportDeclarations[0];\n\n    if (sbImport == null) {\n      return undefined;\n    }\n\n    const specifiers = sbImport.get('specifiers');\n    const importSpecifier = specifiers.find((specifier) => {\n      if (!specifier.isImportSpecifier()) {\n        return false;\n      }\n      const imported = specifier.get('imported');\n\n      if (!imported.isIdentifier()) {\n        return false;\n      }\n      return imported.node.name === type;\n    });\n\n    if (importSpecifier) {\n      return importSpecifier.node.local.name;\n    }\n    specifiers[0].insertBefore(t.importSpecifier(t.identifier(type), t.identifier(type)));\n    return type;\n  };\n\n  removeDeprecatedStoryImport = () => {\n    const specifiers = this.sbImportDeclarations.flatMap((it) => it.get('specifiers'));\n    const storyImports = specifiers.filter((specifier) => {\n      if (!specifier.isImportSpecifier()) {\n        return false;\n      }\n      const imported = specifier.get('imported');\n\n      if (!imported.isIdentifier()) {\n        return false;\n      }\n      return imported.node.name === 'Story';\n    });\n    storyImports.forEach((path) => path.remove());\n  };\n\n  getAllLocalImports = () => {\n    return this.sbImportDeclarations\n      .flatMap((it) => it.get('specifiers'))\n      .map((it) => it.node.local.name);\n  };\n\n  updateTypeTo = (id: t.LVal, type: string): t.LVal => {\n    if (\n      isIdentifier(id) &&\n      isTSTypeAnnotation(id.typeAnnotation) &&\n      isTSTypeReference(id.typeAnnotation.typeAnnotation) &&\n      isIdentifier(id.typeAnnotation.typeAnnotation.typeName)\n    ) {\n      const { name } = id.typeAnnotation.typeAnnotation.typeName;\n      if (this.getAllLocalImports().includes(name)) {\n        const localTypeImport = this.getOrAddImport(type);\n        return {\n          ...id,\n          typeAnnotation: t.tsTypeAnnotation(\n            t.tsTypeReference(\n              t.identifier(localTypeImport ?? ''),\n              id.typeAnnotation.typeAnnotation.typeParameters\n            )\n          ),\n        };\n      }\n    }\n    return id;\n  };\n}\n\nexport const parser = 'tsx';\n"
  },
  {
    "path": "code/lib/codemod/src/transforms/find-implicit-spies.ts",
    "content": "import type { BabelFile } from 'storybook/internal/babel';\nimport { core as babel, types as t } from 'storybook/internal/babel';\nimport { loadCsf } from 'storybook/internal/csf-tools';\n\nimport type { FileInfo } from 'jscodeshift';\n\nfunction findImplicitSpies(path: babel.NodePath, file: string, keys: string[]) {\n  path.traverse({\n    Identifier: (identifier) => {\n      if (!keys.includes(identifier.node.name) && /^on[A-Z].*/.test(identifier.node.name)) {\n        console.warn(identifier.buildCodeFrameError(`${file} Possible implicit spy found`).message);\n      }\n    },\n  });\n}\n\nfunction getAnnotationKeys(file: BabelFile, storyName: string, annotationName: string) {\n  const argKeys: string[] = [];\n\n  file.path.traverse({\n    // CSF2 play function Story.args =\n    AssignmentExpression: (path) => {\n      const left = path.get('left');\n\n      if (!left.isMemberExpression()) {\n        return;\n      }\n      const object = left.get('object');\n\n      if (!(object.isIdentifier() && object.node.name === storyName)) {\n        return;\n      }\n\n      const property = left.get('property');\n      const right = path.get('right');\n      if (\n        property.isIdentifier() &&\n        property.node.name === annotationName &&\n        right.isObjectExpression()\n      ) {\n        argKeys.push(\n          ...right.node.properties.flatMap((value) =>\n            t.isObjectProperty(value) && t.isIdentifier(value.key) ? [value.key.name] : []\n          )\n        );\n      }\n    },\n    // CSF3 const Story = {args: () => {} };\n    VariableDeclarator: (path) => {\n      const id = path.get('id');\n      const init = path.get('init');\n\n      if (!(id.isIdentifier() && id.node.name === storyName) || !init.isObjectExpression()) {\n        return;\n      }\n\n      const args = init\n        .get('properties')\n        .flatMap((it) => (it.isObjectProperty() ? [it] : []))\n        .find((it) => {\n          const argKey = it.get('key');\n          return argKey.isIdentifier() && argKey.node.name === annotationName;\n        });\n\n      if (!args) {\n        return;\n      }\n      const argsValue = args.get('value');\n\n      if (!argsValue || !argsValue.isObjectExpression()) {\n        return;\n      }\n      argKeys.push(\n        ...argsValue.node.properties.flatMap((value) =>\n          t.isObjectProperty(value) && t.isIdentifier(value.key) ? [value.key.name] : []\n        )\n      );\n    },\n  });\n\n  return argKeys;\n}\n\nconst getObjectExpressionKeys = (node: babel.Node | undefined) => {\n  return t.isObjectExpression(node)\n    ? node.properties.flatMap((value) =>\n        t.isObjectProperty(value) && t.isIdentifier(value.key) ? [value.key.name] : []\n      )\n    : [];\n};\n\nexport default async function transform(info: FileInfo) {\n  const csf = loadCsf(info.source, { makeTitle: (title) => title });\n  const fileNode = csf._ast;\n  // @ts-expect-error File is not yet exposed, see https://github.com/babel/babel/issues/11350#issuecomment-644118606\n  const file: BabelFile = new babel.File(\n    { filename: info.path },\n    { code: info.source, ast: fileNode }\n  );\n\n  csf.parse();\n\n  const metaKeys = [\n    ...getObjectExpressionKeys(csf._metaAnnotations.args),\n    ...getObjectExpressionKeys(csf._metaAnnotations.argTypes),\n  ];\n\n  Object.values(csf.stories).forEach(({ name }) => {\n    if (!name) {\n      return;\n    }\n    const allKeys = [\n      ...metaKeys,\n      ...getAnnotationKeys(file, name, 'args'),\n      ...getAnnotationKeys(file, name, 'argTypes'),\n    ];\n\n    file.path.traverse({\n      // CSF2 play function Story.play =\n      AssignmentExpression: (path) => {\n        const left = path.get('left');\n\n        if (!left.isMemberExpression()) {\n          return;\n        }\n        const object = left.get('object');\n\n        if (!(object.isIdentifier() && object.node.name === name)) {\n          return;\n        }\n\n        const property = left.get('property');\n        if (property.isIdentifier() && property.node.name === 'play') {\n          findImplicitSpies(path, info.path, allKeys);\n        }\n      },\n\n      // CSF3 play function: const Story = {play: () => {} };\n      VariableDeclarator: (path) => {\n        const id = path.get('id');\n        const init = path.get('init');\n\n        if (!(id.isIdentifier() && id.node.name === name) || !init.isObjectExpression()) {\n          return;\n        }\n\n        const play = init\n          .get('properties')\n          .flatMap((it) => (it.isObjectProperty() ? [it] : []))\n          .find((it) => {\n            const argKey = it.get('key');\n            return argKey.isIdentifier() && argKey.node.name === 'play';\n          });\n\n        if (play) {\n          findImplicitSpies(play, info.path, allKeys);\n        }\n      },\n    });\n  });\n\n  return;\n}\n\nexport const parser = 'tsx';\n"
  },
  {
    "path": "code/lib/codemod/src/transforms/upgrade-deprecated-types.ts",
    "content": "import { type BabelFile, type NodePath, core as babel, types as t } from 'storybook/internal/babel';\nimport { loadCsf, printCsf } from 'storybook/internal/csf-tools';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport type { API, FileInfo } from 'jscodeshift';\nimport prettier from 'prettier';\n\nconst deprecatedTypes = [\n  'ComponentStory',\n  'ComponentStoryFn',\n  'ComponentStoryObj',\n  'ComponentMeta',\n  'Story',\n];\n\nfunction migrateType(oldType: string) {\n  if (oldType === 'Story' || oldType === 'ComponentStory') {\n    return 'StoryFn';\n  }\n  return oldType.replace('Component', '');\n}\n\nexport default async function transform(info: FileInfo, api: API, options: { parser?: string }) {\n  // TODO what do I need to with the title?\n  const csf = loadCsf(info.source, { makeTitle: (title) => title });\n  const fileNode = csf._ast;\n  // @ts-expect-error File is not yet exposed, see https://github.com/babel/babel/issues/11350#issuecomment-644118606\n  const file: BabelFile = new babel.File(\n    { filename: info.path },\n    { code: info.source, ast: fileNode }\n  );\n\n  upgradeDeprecatedTypes(file);\n\n  let output = printCsf(csf).code;\n\n  try {\n    output = await prettier.format(output, {\n      ...(await prettier.resolveConfig(info.path)),\n      filepath: info.path,\n    });\n  } catch (e) {\n    logger.log(`Failed applying prettier to ${info.path}.`);\n  }\n\n  return output;\n}\n\nexport const parser = 'tsx';\n\nexport function upgradeDeprecatedTypes(file: BabelFile) {\n  const importedNamespaces: Set<string> = new Set();\n  const typeReferencesToUpdate: Set<string> = new Set();\n  const existingImports: { name: string; isAlias: boolean; path: NodePath }[] = [];\n\n  file.path.traverse({\n    ImportDeclaration: (path) => {\n      existingImports.push(\n        ...path.get('specifiers').map((specifier) => ({\n          name: specifier.node.local.name,\n          isAlias: !(\n            specifier.isImportSpecifier() &&\n            t.isIdentifier(specifier.node.imported) &&\n            specifier.node.local.name === specifier.node.imported.name\n          ),\n          path: specifier,\n        }))\n      );\n\n      const source = path.node.source.value;\n\n      if (!source.startsWith('@storybook')) {\n        return;\n      }\n\n      path.get('specifiers').forEach((specifier) => {\n        if (specifier.isImportNamespaceSpecifier()) {\n          importedNamespaces.add(specifier.node.local.name);\n        }\n\n        if (!specifier.isImportSpecifier()) {\n          return;\n        }\n        const imported = specifier.get('imported');\n\n        if (!imported.isIdentifier()) {\n          return;\n        }\n\n        // if we find a deprecated import\n\n        // if we find a deprecated import\n        if (deprecatedTypes.includes(imported.node.name)) {\n          // we don't have to rewrite type references for aliased imports\n          if (imported.node.name === specifier.node.local.name) {\n            typeReferencesToUpdate.add(specifier.node.local.name);\n          }\n\n          const newType = migrateType(imported.node.name);\n\n          // replace the deprecated import type when the new type isn't yet imported\n          // note that we don't replace the local name of the specifier\n          if (!existingImports.some((it) => it.name === newType)) {\n            imported.replaceWith(t.identifier(newType));\n            existingImports.push({ name: newType, isAlias: false, path: specifier });\n          } else {\n            // if the existing import has the same local name but is an alias we throw\n            // we could have imported the type with an alias, but seems to much effort\n            const existingImport = existingImports.find((it) => it.name === newType && it.isAlias);\n            if (existingImport) {\n              throw existingImport.path.buildCodeFrameError(\n                'This codemod does not support local imports that are called the same as a storybook import.\\n' +\n                  'Rename this local import and try again.'\n              );\n            } else {\n              // if the type already exists, without being aliased\n              // we can safely remove the deprecated import now\n              specifier.remove();\n            }\n          }\n        }\n      });\n    },\n  });\n\n  file.path.traverse({\n    TSTypeReference: (path) => {\n      const typeName = path.get('typeName');\n      if (typeName.isIdentifier()) {\n        if (typeReferencesToUpdate.has(typeName.node.name)) {\n          typeName.replaceWith(t.identifier(migrateType(typeName.node.name)));\n        }\n      } else if (typeName.isTSQualifiedName()) {\n        // For example SB.StoryObj\n        const namespace = typeName.get('left');\n        if (namespace.isIdentifier()) {\n          if (importedNamespaces.has(namespace.node.name)) {\n            const right = typeName.get('right');\n            if (deprecatedTypes.includes(right.node.name)) {\n              right.replaceWith(t.identifier(migrateType(right.node.name)));\n            }\n          }\n        }\n      }\n    },\n  });\n}\n"
  },
  {
    "path": "code/lib/codemod/src/transforms/upgrade-hierarchy-separators.js",
    "content": "function upgradeSeparator(path) {\n  return path.replace(/[|.]/g, '/');\n}\n\nexport default function transformer(file, api, options) {\n  const j = api.jscodeshift;\n  const root = j(file.source);\n\n  // storiesOf(...)\n  root\n    .find(j.CallExpression)\n    .filter((call) => call.node.callee.name === 'storiesOf')\n    .filter(\n      (call) =>\n        call.node.arguments.length > 0 &&\n        ['Literal', 'StringLiteral'].includes(call.node.arguments[0].type)\n    )\n    .forEach((call) => {\n      const arg0 = call.node.arguments[0];\n      arg0.value = upgradeSeparator(arg0.value);\n    });\n\n  // export default { title: ... }\n  root\n    .find(j.ExportDefaultDeclaration)\n    .filter((def) => def.node.declaration.properties.map((p) => p.key.name).includes('title'))\n    .forEach((def) => {\n      if (def.node.declaration && def.node.declaration.properties) {\n        def.node.declaration.properties.forEach((p) => {\n          if (p.key.name === 'title') {\n            p.value.value = upgradeSeparator(p.value.value);\n          }\n        });\n      }\n    });\n\n  return root.toSource({ quote: 'single' });\n}\n"
  },
  {
    "path": "code/lib/codemod/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"allowJs\": true,\n    \"strict\": false\n  },\n  \"exclude\": [\"node_modules\", \"__testfixtures__\", \"__tests__\"],\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/lib/codemod/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/lib/core-webpack/README.md",
    "content": "# Storybook Core-Common\n\nCommon utilities used across `@storybook/core-server` (manager UI configuration) and `@storybook/builder-webpack{4,5}` (preview configuration).\n\nThis is a lot of code extracted for convenience, not because it made sense.\n\nSupporting multiple version of webpack and this duplicating a large portion of code that was never meant to be generic caused this.\n\nAt some point we'll refactor this, it's likely a lot of this code is dead or barely used.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/lib/core-webpack/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    node: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/lib/core-webpack/package.json",
    "content": "{\n  \"name\": \"@storybook/core-webpack\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook framework-agnostic API\",\n  \"keywords\": [\n    \"storybook\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/lib/core-webpack\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/lib/core-webpack\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"templates/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"ts-dedent\": \"^2.0.0\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.19.1\",\n    \"typescript\": \"^5.8.3\",\n    \"webpack\": \"5\"\n  },\n  \"peerDependencies\": {\n    \"storybook\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/lib/core-webpack/project.json",
    "content": "{\n  \"name\": \"core-webpack\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/lib/core-webpack/src/__snapshots__/merge-webpack-config.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`mergeConfigs > merges partial custom config 1`] = `\n{\n  \"devtool\": \"source-map\",\n  \"entry\": {\n    \"bundle\": \"index.js\",\n  },\n  \"module\": {\n    \"rules\": [\n      {\n        \"use\": \"r1\",\n      },\n      {\n        \"use\": \"r2\",\n      },\n    ],\n  },\n  \"optimization\": {\n    \"runtimeChunk\": true,\n    \"splitChunks\": {\n      \"chunks\": \"all\",\n    },\n  },\n  \"output\": {\n    \"filename\": \"[name].js\",\n  },\n  \"plugins\": [\n    \"p1\",\n    \"p2\",\n    \"p3\",\n  ],\n  \"resolve\": {\n    \"alias\": {\n      \"A1\": \"src/B1\",\n      \"A2\": \"src/B2\",\n    },\n    \"enforceExtension\": true,\n    \"extensions\": [\n      \".js\",\n      \".json\",\n      \".ts\",\n      \".tsx\",\n    ],\n  },\n}\n`;\n\nexports[`mergeConfigs > merges successfully if custom config is empty 1`] = `\n{\n  \"devtool\": \"source-map\",\n  \"entry\": {\n    \"bundle\": \"index.js\",\n  },\n  \"module\": {\n    \"rules\": [\n      {\n        \"use\": \"r1\",\n      },\n      {\n        \"use\": \"r2\",\n      },\n    ],\n  },\n  \"optimization\": {\n    \"runtimeChunk\": true,\n    \"splitChunks\": {\n      \"chunks\": \"all\",\n    },\n  },\n  \"output\": {\n    \"filename\": \"[name].js\",\n  },\n  \"plugins\": [\n    \"p1\",\n    \"p2\",\n  ],\n  \"resolve\": {\n    \"alias\": {\n      \"A1\": \"src/B1\",\n      \"A2\": \"src/B2\",\n    },\n    \"enforceExtension\": true,\n    \"extensions\": [\n      \".js\",\n      \".json\",\n    ],\n  },\n}\n`;\n\nexports[`mergeConfigs > merges two full configs in one 1`] = `\n{\n  \"devtool\": \"source-map\",\n  \"entry\": {\n    \"bundle\": \"index.js\",\n  },\n  \"module\": {\n    \"noParse\": /jquery\\\\|lodash/,\n    \"rules\": [\n      {\n        \"use\": \"r1\",\n      },\n      {\n        \"use\": \"r2\",\n      },\n      {\n        \"use\": \"r3\",\n      },\n      {\n        \"use\": \"r4\",\n      },\n    ],\n  },\n  \"optimization\": {\n    \"minimizer\": [\n      \"banana\",\n    ],\n    \"runtimeChunk\": true,\n    \"splitChunks\": {\n      \"chunks\": \"all\",\n    },\n  },\n  \"output\": {\n    \"filename\": \"[name].js\",\n  },\n  \"plugins\": [\n    \"p1\",\n    \"p2\",\n    \"p3\",\n    \"p4\",\n  ],\n  \"profile\": true,\n  \"resolve\": {\n    \"alias\": {\n      \"A1\": \"src/B1\",\n      \"A2\": \"src/B2\",\n      \"A3\": \"src/B3\",\n      \"A4\": \"src/B4\",\n    },\n    \"enforceExtension\": false,\n    \"extensions\": [\n      \".js\",\n      \".json\",\n      \".ts\",\n      \".tsx\",\n    ],\n  },\n}\n`;\n"
  },
  {
    "path": "code/lib/core-webpack/src/check-webpack-version.ts",
    "content": "import { logger } from 'storybook/internal/node-logger';\n\nimport { dedent } from 'ts-dedent';\n\nexport const checkWebpackVersion = (\n  webpack: { version?: string },\n  specifier: string,\n  caption: string\n) => {\n  if (!webpack.version) {\n    logger.info('Skipping webpack version check, no version available');\n    return;\n  }\n  if (webpack.version !== specifier) {\n    logger.warn(dedent`\n      Unexpected webpack version in ${caption}:\n      - Received '${webpack.version}'\n      - Expected '${specifier}'\n\n      If you're using Webpack 5 in SB6.2 and upgrading, consider: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#webpack-5-manager-build\n\n      For more info about Webpack 5 support: https://gist.github.com/shilman/8856ea1786dcd247139b47b270912324#troubleshooting\n    `);\n  }\n};\n"
  },
  {
    "path": "code/lib/core-webpack/src/importPipeline.test.ts",
    "content": "import { expect, it, vi } from 'vitest';\n\nimport { importPipeline } from './importPipeline.ts';\n\nconst createGate = (): [Promise<any | undefined>, (_?: any) => void] => {\n  let openGate = (_?: any) => {};\n  const gate = new Promise<any | undefined>((resolve) => {\n    openGate = resolve;\n  });\n  return [gate, openGate];\n};\n\nit('passes through to passed importFn on serial calls', async () => {\n  const pipeline = importPipeline();\n  const importFn = vi.fn();\n\n  importFn.mockResolvedValueOnce('r1');\n  expect(await pipeline(() => importFn('i1'))).toEqual('r1');\n  expect(importFn).toHaveBeenCalledTimes(1);\n  expect(importFn).toHaveBeenCalledWith('i1');\n\n  importFn.mockResolvedValueOnce('r2');\n  expect(await pipeline(() => importFn('i2'))).toEqual('r2');\n  expect(importFn).toHaveBeenCalledTimes(2);\n  expect(importFn).toHaveBeenCalledWith('i2');\n});\n\nit('blocks on parallel calls', async () => {\n  const pipeline = importPipeline();\n  const [firstGate, openFirstGate] = createGate();\n  const importFn = vi\n    .fn()\n    .mockImplementationOnce(() => firstGate)\n    .mockResolvedValueOnce('r2');\n\n  const firstPromise = pipeline(() => importFn('i1'));\n\n  // We need to await promise resolution to get the block setup\n  await new Promise((r) => r(null));\n\n  const secondPromise = pipeline(() => importFn('i2'));\n\n  expect(importFn).toHaveBeenCalledTimes(1);\n  expect(importFn).toHaveBeenCalledWith('i1');\n  openFirstGate('r1');\n  expect(await firstPromise).toEqual('r1');\n\n  // We need to await promise resolution to get past the block\n  await new Promise((r) => r(null));\n\n  expect(importFn).toHaveBeenCalledTimes(2);\n  expect(importFn).toHaveBeenCalledWith('i2');\n  expect(await secondPromise).toEqual('r2');\n});\n\nit('dispatches all queued calls on opening', async () => {\n  const pipeline = importPipeline();\n  const [firstGate, openFirstGate] = createGate();\n  const importFn = vi\n    .fn()\n    .mockImplementationOnce(() => firstGate)\n    .mockResolvedValueOnce('r2')\n    .mockResolvedValueOnce('r3');\n\n  const firstPromise = pipeline(() => importFn('i1'));\n\n  // We need to await promise resolution to get the block setup\n  await new Promise((r) => r(null));\n  const secondPromise = pipeline(() => importFn('i2'));\n\n  // We need to await promise resolution to get the block setup\n  await new Promise((r) => r(null));\n  const thirdPromise = pipeline(() => importFn('i3'));\n\n  expect(importFn).toHaveBeenCalledTimes(1);\n  expect(importFn).toHaveBeenCalledWith('i1');\n  openFirstGate('r1');\n  expect(await firstPromise).toEqual('r1');\n\n  // We need to await promise resolution to get past the block\n  await new Promise((r) => r(null));\n\n  expect(importFn).toHaveBeenCalledTimes(3);\n  expect(importFn).toHaveBeenCalledWith('i2');\n  expect(importFn).toHaveBeenCalledWith('i3');\n  expect(await secondPromise).toEqual('r2');\n  expect(await thirdPromise).toEqual('r3');\n});\n\nit('blocks sequentially on parallel calls', async () => {\n  const pipeline = importPipeline();\n  const [firstGate, openFirstGate] = createGate();\n  const [secondGate, openSecondGate] = createGate();\n  const importFn = vi\n    .fn()\n    .mockImplementationOnce(() => firstGate)\n    .mockImplementationOnce(() => secondGate)\n    .mockResolvedValueOnce('r3');\n\n  const firstPromise = pipeline(() => importFn('i1'));\n\n  // We need to await promise resolution to get the block setup\n  await new Promise((r) => r(null));\n  const secondPromise = pipeline(() => importFn('i2'));\n\n  expect(importFn).toHaveBeenCalledTimes(1);\n  expect(importFn).toHaveBeenCalledWith('i1');\n  openFirstGate('r1');\n  expect(await firstPromise).toEqual('r1');\n\n  // We need to await promise resolution to get past the block, and set up the new one\n  await new Promise((r) => r(null));\n  const thirdPromise = pipeline(() => importFn('i3'));\n\n  expect(importFn).toHaveBeenCalledTimes(2);\n  expect(importFn).toHaveBeenCalledWith('i2');\n  openSecondGate('r2');\n  expect(await secondPromise).toEqual('r2');\n\n  // We need to await promise resolution to get past the block\n  await new Promise((r) => r(null));\n  expect(await thirdPromise).toEqual('r3');\n});\n"
  },
  {
    "path": "code/lib/core-webpack/src/importPipeline.ts",
    "content": "type ModuleExports = Record<string, any>;\n\n// If an import is in flight when another import arrives, block it until the first completes.\n// This is to avoid a situation where webpack kicks off a second compilation whilst the\n// first is still completing, cf: https://github.com/webpack/webpack/issues/15541#issuecomment-1143138832\n// Note the way this code works if N further `import()`s occur while the first is in flight,\n// they will all be kicked off in the same tick and not block each other. This is by design,\n// Webpack can handle multiple invalidations simultaneously, just not in quick succession.\n\nexport function importPipeline() {\n  let importGate: Promise<void> = Promise.resolve();\n\n  return async (importFn: () => Promise<ModuleExports>) => {\n    await importGate;\n\n    const moduleExportsPromise = importFn();\n    importGate = importGate.then(async () => {\n      await moduleExportsPromise;\n    });\n    return moduleExportsPromise;\n  };\n}\n"
  },
  {
    "path": "code/lib/core-webpack/src/index.ts",
    "content": "export * from './types.ts';\nexport * from './load-custom-webpack-config.ts';\nexport * from './check-webpack-version.ts';\nexport * from './merge-webpack-config.ts';\nexport * from './to-importFn.ts';\nexport * from './to-require-context.ts';\n"
  },
  {
    "path": "code/lib/core-webpack/src/load-custom-webpack-config.ts",
    "content": "import { resolve } from 'node:path';\n\nimport { serverRequire } from 'storybook/internal/common';\n\nconst webpackConfigs = ['webpack.config', 'webpackfile'];\n\nexport const loadCustomWebpackConfig = async (configDir: string) =>\n  serverRequire(webpackConfigs.map((configName) => resolve(configDir, configName)));\n"
  },
  {
    "path": "code/lib/core-webpack/src/merge-webpack-config.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport type { Configuration } from 'webpack';\n\nimport { mergeConfigs } from './merge-webpack-config.ts';\n\nconst config: Configuration = {\n  devtool: 'source-map',\n  entry: {\n    bundle: 'index.js',\n  },\n  output: {\n    filename: '[name].js',\n  },\n  module: {\n    rules: [{ use: 'r1' }, { use: 'r2' }],\n  },\n  // @ts-expect-errors For snapshot readability purposes `plugins` attribute doesn't match the correct type\n  plugins: ['p1', 'p2'],\n  resolve: {\n    enforceExtension: true,\n    extensions: ['.js', '.json'],\n    alias: {\n      A1: 'src/B1',\n      A2: 'src/B2',\n    },\n  },\n  optimization: {\n    splitChunks: {\n      chunks: 'all',\n    },\n    runtimeChunk: true,\n  },\n};\n\ndescribe('mergeConfigs', () => {\n  it('merges two full configs in one', () => {\n    const customConfig: Configuration = {\n      profile: true,\n      entry: {\n        bundle: 'should_not_be_merged.js',\n      },\n      output: {\n        filename: 'should_not_be_merged.js',\n      },\n      module: {\n        noParse: /jquery|lodash/,\n        rules: [{ use: 'r3' }, { use: 'r4' }],\n      },\n      // @ts-expect-errors For snapshot readability purposes `plugins` attribute doesn't match the correct type\n      plugins: ['p3', 'p4'],\n      resolve: {\n        enforceExtension: false,\n        extensions: ['.ts', '.tsx'],\n        alias: {\n          A3: 'src/B3',\n          A4: 'src/B4',\n        },\n      },\n      optimization: {\n        // @ts-expect-errors For snapshot readability purposes `minimizer` attribute doesn't match the correct type\n        minimizer: ['banana'],\n      },\n    };\n\n    const result = mergeConfigs(config, customConfig);\n\n    expect(result).toMatchSnapshot();\n  });\n\n  it('merges partial custom config', () => {\n    const customConfig: Configuration = {\n      // @ts-expect-errors For snapshot readability purposes `plugins` attribute doesn't match the correct type\n      plugins: ['p3'],\n      resolve: {\n        extensions: ['.ts', '.tsx'],\n      },\n    };\n\n    const result = mergeConfigs(config, customConfig);\n\n    expect(result).toMatchSnapshot();\n  });\n\n  it('merges successfully if custom config is empty', () => {\n    const customConfig = {};\n\n    const result = mergeConfigs(config, customConfig);\n\n    expect(result).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "code/lib/core-webpack/src/merge-webpack-config.ts",
    "content": "import type {\n  WebpackConfiguration as Configuration,\n  ModuleConfig,\n  ResolveConfig,\n  RulesConfig,\n} from './types.ts';\n\nfunction mergePluginsField(\n  defaultPlugins: Required<Configuration>['plugins'] = [],\n  customPlugins: Required<Configuration>['plugins'] = []\n): Required<Configuration>['plugins'] {\n  return [...defaultPlugins, ...customPlugins];\n}\n\nfunction mergeRulesField(\n  defaultRules: RulesConfig[] = [],\n  customRules: RulesConfig[] = []\n): ModuleConfig['rules'] {\n  return [...defaultRules, ...customRules];\n}\n\nfunction mergeExtensionsField(\n  { extensions: defaultExtensions = [] }: ResolveConfig,\n  { extensions: customExtensions = [] }: ResolveConfig\n): ResolveConfig['extensions'] {\n  return [...defaultExtensions, ...customExtensions];\n}\n\nfunction mergeAliasField(\n  { alias: defaultAlias = {} }: ResolveConfig,\n  { alias: customAlias = {} }: ResolveConfig\n): ResolveConfig['alias'] {\n  return {\n    ...defaultAlias,\n    ...customAlias,\n  };\n}\n\nfunction mergeModuleField(a: ModuleConfig, b: ModuleConfig): ModuleConfig {\n  return {\n    ...a,\n    ...b,\n    rules: mergeRulesField(a.rules || [], b.rules || []),\n  };\n}\n\nfunction mergeResolveField(\n  { resolve: defaultResolve = {} }: Configuration,\n  { resolve: customResolve = {} }: Configuration\n): ResolveConfig {\n  return {\n    ...defaultResolve,\n    ...customResolve,\n    alias: mergeAliasField(defaultResolve, customResolve),\n    extensions: mergeExtensionsField(defaultResolve, customResolve),\n  };\n}\n\nfunction mergeOptimizationField(\n  { optimization: defaultOptimization = {} }: Configuration,\n  { optimization: customOptimization = {} }: Configuration\n): Configuration['optimization'] {\n  return {\n    ...defaultOptimization,\n    ...customOptimization,\n  };\n}\n\nexport function mergeConfigs(config: Configuration, customConfig: Configuration): Configuration {\n  return {\n    // We'll always load our configurations after the custom config.\n    // So, we'll always load the stuff we need.\n    ...customConfig,\n    ...config,\n    devtool: customConfig.devtool || config.devtool,\n    plugins: mergePluginsField(config.plugins, customConfig.plugins),\n    module: mergeModuleField(config.module || {}, customConfig.module || {}),\n    resolve: mergeResolveField(config, customConfig),\n    optimization: mergeOptimizationField(config, customConfig),\n  };\n}\n"
  },
  {
    "path": "code/lib/core-webpack/src/to-importFn.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { normalizeStoriesEntry } from 'storybook/internal/common';\n\nimport { webpackIncludeRegexp } from './to-importFn.ts';\n\nconst testCases: [string, string[], string[]][] = [\n  [\n    '**/*.stories.tsx',\n    [\n      '/Users/user/code/.storybook/Icon.stories.tsx',\n      '/Users/user/code/.storybook/stories/Icon.stories.tsx',\n      '/Users/user/code/.storybook/stories/components/Icon.stories.tsx',\n    ],\n    [\n      '/Users/user/code/.storybook/stories.tsx',\n      '/Users/user/code/.storybook/Icon.stories.ts',\n      '/Users/user/code/.storybook/Icon.stories.js',\n      '/Users/user/code/.storybook/src/components/stories.tsx',\n      '/Users/user/code/.storybook/src/components/Icon.stories/stories.tsx',\n      '/Users/user/code/.storybook/src/components/Icon.stories.ts',\n      '/Users/user/code/.storybook/src/components/Icon.stories.js',\n      '/Users/user/code/src/components/Icon.stories.tsx',\n    ],\n  ],\n  [\n    './**/*.stories.tsx',\n    [\n      '/Users/user/code/.storybook/Icon.stories.tsx',\n      '/Users/user/code/.storybook/stories/Icon.stories.tsx',\n      '/Users/user/code/.storybook/stories/components/Icon.stories.tsx',\n    ],\n    [\n      '/Users/user/code/.storybook/stories.tsx',\n      '/Users/user/code/.storybook/Icon.stories.ts',\n      '/Users/user/code/.storybook/Icon.stories.js',\n      '/Users/user/code/.storybook/src/components/stories.tsx',\n      '/Users/user/code/.storybook/src/components/Icon.stories/stories.tsx',\n      '/Users/user/code/.storybook/src/components/Icon.stories.ts',\n      '/Users/user/code/.storybook/src/components/Icon.stories.js',\n      '/Users/user/code/src/components/Icon.stories.tsx',\n    ],\n  ],\n  [\n    '../**/*.stories.tsx',\n    [\n      '/Users/user/code/.storybook/Icon.stories.tsx',\n      '/Users/user/code/Icon.stories.tsx',\n      '/Users/user/code/src/Icon.stories.tsx',\n      '/Users/user/code/src/components/Icon.stories.tsx',\n      '/Users/user/code/src/components/Icon.stories/Icon.stories.tsx',\n    ],\n    [\n      '/Users/user/code/.storybook/stories.tsx',\n      '/Users/user/code/stories.tsx',\n      '/Users/user/code/Icon.stories.ts',\n      '/Users/user/code/Icon.stories.js',\n      '/Users/user/code/src/components/stories.tsx',\n      '/Users/user/code/src/components/Icon.stories/stories.tsx',\n      '/Users/user/code/src/components/Icon.stories.ts',\n      '/Users/user/code/src/components/Icon.stories.js',\n    ],\n  ],\n  [\n    '../src',\n    [],\n    [\n      '/Users/user/code/Icon.stories.tsx',\n      '/Users/user/code/src/Icon.stories.tsx',\n      '/Users/user/code/src/components/Icon.stories.tsx',\n      '/Users/user/code/src/components/Icon.stories/Icon.stories.tsx',\n      '/Users/user/code/stories.tsx',\n      '/Users/user/code/Icon.stories.ts',\n      '/Users/user/code/Icon.stories.js',\n      '/Users/user/code/src/components/stories.tsx',\n      '/Users/user/code/src/components/Icon.stories/stories.tsx',\n      '/Users/user/code/src/components/Icon.stories.ts',\n      '/Users/user/code/src/components/Icon.stories.js',\n    ],\n  ],\n  [\n    '../src/*',\n    ['/Users/user/code/src/Icon.stories.tsx'],\n    [\n      '/Users/user/code/Icon.stories.tsx',\n      '/Users/user/code/src/components/Icon.stories.tsx',\n      '/Users/user/code/src/components/Icon.stories/Icon.stories.tsx',\n      '/Users/user/code/stories.tsx',\n      '/Users/user/code/Icon.stories.ts',\n      '/Users/user/code/Icon.stories.js',\n      '/Users/user/code/src/components/stories.tsx',\n      '/Users/user/code/src/components/Icon.stories/stories.tsx',\n      '/Users/user/code/src/components/Icon.stories.ts',\n      '/Users/user/code/src/components/Icon.stories.js',\n    ],\n  ],\n  [\n    './stories/**/*.stories.tsx',\n    [\n      '/Users/user/code/.storybook/stories/Icon.stories.tsx',\n      '/Users/user/code/.storybook/stories/components/Icon.stories.tsx',\n      '/Users/user/code/.storybook/stories/components/Icon.stories/Icon.stories.tsx',\n    ],\n    [\n      '/Users/user/code/Icon.stories.tsx',\n      '/Users/user/code/stories.tsx',\n      '/Users/user/code/Icon.stories.ts',\n      '/Users/user/code/Icon.stories.js',\n      '/Users/user/code/stories/components/stories.tsx',\n      '/Users/user/code/stories/components/Icon.stories/stories.tsx',\n      '/Users/user/code/stories/components/Icon.stories.ts',\n      '/Users/user/code/stories/components/Icon.stories.js',\n    ],\n  ],\n  [\n    '../src/**/*.stories.tsx',\n    [\n      '/Users/user/code/src/Icon.stories.tsx',\n      '/Users/user/code/src/components/Icon.stories.tsx',\n      '/Users/user/code/src/components/Icon.stories/Icon.stories.tsx',\n    ],\n    [\n      '/Users/user/code/.storybook/Icon.stories.tsx',\n      // Although it would make sense for these three files to fail to match the `importFn()`,\n      // because we are limited to matching on the RHS of the path (from 'src' onwards, basically)\n      // we cannot avoid matching things inside the config dir in such situations.\n      // '/Users/user/code/.storybook/src/Icon.stories.tsx',\n      // '/Users/user/code/.storybook/src/components/Icon.stories.tsx',\n      // '/Users/user/code/.storybook/src/components/Icon.stories/Icon.stories.tsx',\n      '/Users/user/code/Icon.stories.tsx',\n      '/Users/user/code/stories.tsx',\n      '/Users/user/code/Icon.stories.ts',\n      '/Users/user/code/Icon.stories.js',\n      '/Users/user/code/src/components/stories.tsx',\n      '/Users/user/code/src/components/Icon.stories/stories.tsx',\n      '/Users/user/code/src/components/Icon.stories.ts',\n      '/Users/user/code/src/components/Icon.stories.js',\n    ],\n  ],\n  [\n    '../../src/**/*.stories.tsx',\n    [\n      '/Users/user/code/src/Icon.stories.tsx',\n      '/Users/user/code/src/components/Icon.stories.tsx',\n      '/Users/user/code/src/components/Icon.stories/Icon.stories.tsx',\n    ],\n    [\n      '/Users/user/code/Icon.stories.tsx',\n      '/Users/user/code/stories.tsx',\n      '/Users/user/code/Icon.stories.ts',\n      '/Users/user/code/Icon.stories.js',\n      '/Users/user/code/src/components/stories.tsx',\n      '/Users/user/code/src/components/Icon.stories/stories.tsx',\n      '/Users/user/code/src/components/Icon.stories.ts',\n      '/Users/user/code/src/components/Icon.stories.js',\n    ],\n  ],\n  [\n    './../../src/**/*.stories.tsx',\n    [\n      '/Users/user/code/src/Icon.stories.tsx',\n      '/Users/user/code/src/components/Icon.stories.tsx',\n      '/Users/user/code/src/components/Icon.stories/Icon.stories.tsx',\n    ],\n    [\n      '/Users/user/code/Icon.stories.tsx',\n      '/Users/user/code/stories.tsx',\n      '/Users/user/code/Icon.stories.ts',\n      '/Users/user/code/Icon.stories.js',\n      '/Users/user/code/src/components/stories.tsx',\n      '/Users/user/code/src/components/Icon.stories/stories.tsx',\n      '/Users/user/code/src/components/Icon.stories.ts',\n      '/Users/user/code/src/components/Icon.stories.js',\n    ],\n  ],\n  [\n    './Introduction.stories.tsx',\n    ['/Users/user/code/.storybook/Introduction.stories.tsx'],\n    [\n      '/Users/user/code/Introduction.stories.tsx',\n      '/Users/user/code/src/Introduction.stories.tsx',\n      '/Users/user/code/src/Introduction.tsx',\n    ],\n  ],\n  [\n    'Introduction.stories.tsx',\n    ['/Users/user/code/.storybook/Introduction.stories.tsx'],\n    [\n      '/Users/user/code/Introduction.stories.tsx',\n      '/Users/user/code/src/Introduction.stories.tsx',\n      '/Users/user/code/src/Introduction.tsx',\n    ],\n  ],\n];\n\ndescribe('toImportFn - webpackIncludeRegexp', () => {\n  it.each(testCases)('matches only suitable paths - %s', (glob, validPaths, invalidPaths) => {\n    const regex = webpackIncludeRegexp(\n      normalizeStoriesEntry(glob, {\n        configDir: '/Users/user/code/.storybook',\n        workingDir: '/Users/user/code/',\n      })\n    );\n\n    const isNotMatchedForValidPaths = validPaths.filter(\n      (absolutePath) => !regex.test(absolutePath)\n    );\n    const isMatchedForInvalidPaths = invalidPaths.filter(\n      (absolutePath) => !!regex.test(absolutePath)\n    );\n\n    expect(isNotMatchedForValidPaths).toEqual([]);\n    expect(isMatchedForInvalidPaths).toEqual([]);\n  });\n});\n"
  },
  {
    "path": "code/lib/core-webpack/src/to-importFn.ts",
    "content": "import { globToRegexp } from 'storybook/internal/common';\nimport type { NormalizedStoriesSpecifier } from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\n\nimport { importPipeline } from './importPipeline.ts';\n\nfunction adjustRegexToExcludeNodeModules(originalRegex: RegExp) {\n  const originalRegexString = originalRegex.source;\n  const startsWithCaret = originalRegexString.startsWith('^');\n  const excludeNodeModulesPattern = startsWithCaret ? '(?!.*node_modules)' : '^(?!.*node_modules)';\n\n  // Combine the new exclusion pattern with the original regex\n  const adjustedRegexString = startsWithCaret\n    ? `^${excludeNodeModulesPattern}${originalRegexString.substring(1)}`\n    : excludeNodeModulesPattern + originalRegexString;\n\n  // Create and return the new regex\n  return new RegExp(adjustedRegexString);\n}\n\nexport function webpackIncludeRegexp(specifier: NormalizedStoriesSpecifier) {\n  const { directory, files } = specifier;\n\n  // It appears webpack passes *something* similar to the absolute path to the file\n  // on disk (prefixed with something unknown) to the matcher.\n  // We don't want to include the absolute path in our bundle, so we will just pull any leading\n  // `./` or `../` off our directory and match on that.\n  // It's imperfect as it could match extra things in extremely unusual cases, but it'll do for now.\n  // NOTE: directory is \"slashed\" so will contain only `/` (no `\\`), even on windows\n  const directoryWithoutLeadingDots = directory.replace(/^(\\.+\\/)+/, '/');\n  const webpackIncludeGlob = ['.', '..'].includes(directory)\n    ? files\n    : `${directoryWithoutLeadingDots}/${files}`;\n  const webpackIncludeRegexpWithCaret = webpackIncludeGlob.includes('node_modules')\n    ? globToRegexp(webpackIncludeGlob)\n    : adjustRegexToExcludeNodeModules(globToRegexp(webpackIncludeGlob));\n  // picomatch is creating an exact match, but we are only matching the end of the filename\n  return new RegExp(webpackIncludeRegexpWithCaret.source.replace(/^\\^/, ''));\n}\n\nexport function toImportFnPart(specifier: NormalizedStoriesSpecifier) {\n  const { directory, importPathMatcher } = specifier;\n\n  return dedent`\n      async (path) => {\n        if (!${importPathMatcher}.exec(path)) {\n          return;\n        }\n\n        const pathRemainder = path.substring(${directory.length + 1});\n        return import(\n          /* webpackChunkName: \"[request]\" */\n          /* webpackInclude: ${webpackIncludeRegexp(specifier)} */\n          '${directory}/' + pathRemainder\n        );\n      }\n\n  `;\n}\n\nexport function toImportFn(\n  stories: NormalizedStoriesSpecifier[],\n  { needPipelinedImport }: { needPipelinedImport?: boolean } = {}\n) {\n  let pipelinedImport = `const pipeline = (x) => x();`;\n  if (needPipelinedImport) {\n    pipelinedImport = `\n      const importPipeline = ${importPipeline};\n      const pipeline = importPipeline();\n    `;\n  }\n\n  return dedent`\n    ${pipelinedImport}\n\n    const importers = [\n      ${stories.map(toImportFnPart).join(',\\n')}\n    ];\n\n    export async function importFn(path) {\n      for (let i = 0; i < importers.length; i++) {\n        const moduleExports = await pipeline(() => importers[i](path));\n        if (moduleExports) {\n          return moduleExports;\n        }\n      }\n    }\n  `;\n}\n"
  },
  {
    "path": "code/lib/core-webpack/src/to-require-context.test.ts",
    "content": "import { relative } from 'node:path';\n\nimport { describe, expect, it } from 'vitest';\n\nimport { normalizeStoriesEntry } from 'storybook/internal/common';\n\nimport { toRequireContext } from './to-require-context.ts';\n\nconst testCases = [\n  {\n    glob: '**/*.stories.tsx',\n    recursive: true,\n    validPaths: [\n      './Icon.stories.tsx',\n      './src/Icon.stories.tsx',\n      './src/components/Icon.stories.tsx',\n      './src/components/Icon.stories/Icon.stories.tsx',\n    ],\n    invalidPaths: [\n      './stories.tsx',\n      './Icon.stories.ts',\n      './Icon.stories.js',\n      './src/components/stories.tsx',\n      './src/components/Icon.stories/stories.tsx',\n      './src/components/Icon.stories.ts',\n      './src/components/Icon.stories.js',\n    ],\n  },\n  {\n    glob: 'src',\n    recursive: false,\n    validPaths: [],\n    invalidPaths: [\n      './Icon.stories.tsx',\n      './src/Icon.stories.tsx',\n      './src/components/Icon.stories.tsx',\n      './src/components/Icon.stories/Icon.stories.tsx',\n      './stories.tsx',\n      './Icon.stories.ts',\n      './Icon.stories.js',\n      './src/components/stories.tsx',\n      './src/components/Icon.stories/stories.tsx',\n      './src/components/Icon.stories.ts',\n      './src/components/Icon.stories.js',\n    ],\n  },\n  {\n    glob: 'src/*',\n    recursive: false,\n    validPaths: ['./src/Icon.stories.tsx'],\n    invalidPaths: [\n      './Icon.stories.tsx',\n      './src/components/Icon.stories.tsx',\n      './src/components/Icon.stories/Icon.stories.tsx',\n      './stories.tsx',\n      './Icon.stories.ts',\n      './Icon.stories.js',\n      './src/components/stories.tsx',\n      './src/components/Icon.stories/stories.tsx',\n      './src/components/Icon.stories.ts',\n      './src/components/Icon.stories.js',\n    ],\n  },\n  // INVALID GLOB\n  {\n    glob: '../src/stories/**/*.stories.(js|ts)',\n    recursive: true,\n    validPaths: [\n      '../src/stories/components/Icon.stories.js',\n      '../src/stories/Icon.stories.js',\n      '../src/stories/Icon.stories.ts',\n      '../src/stories/components/Icon/Icon.stories.js',\n      '../src/stories/components/Icon.stories/Icon.stories.ts',\n    ],\n    invalidPaths: [\n      './stories.js',\n      './src/stories/Icon.stories.js',\n      './Icon.stories.js',\n      '../src/Icon.stories.ts',\n      '../src/stories/components/Icon/Icon.stories.tsx',\n      '../src/stories/components/Icon/Icon.mdx',\n    ],\n  },\n  {\n    glob: 'dirname/../stories/*.stories.*',\n    recursive: false,\n    validPaths: [\n      './dirname/../stories/App.stories.js',\n      './dirname/../stories/addon-centered.stories.js',\n    ],\n    invalidPaths: ['./dirname/../stories.js', './dirname/../App.stories.js'],\n  },\n  {\n    glob: '../src/stories/**/@(*.stories.js|*.stories.ts)',\n    recursive: true,\n    validPaths: [\n      '../src/stories/components/Icon.stories.js',\n      '../src/stories/Icon.stories.js',\n      '../src/stories/Icon.stories.ts',\n      '../src/stories/components/Icon/Icon.stories.js',\n      '../src/stories/components/Icon.stories/Icon.stories.ts',\n    ],\n    invalidPaths: [\n      './stories.js',\n      './src/stories/Icon.stories.js',\n      './Icon.stories.js',\n      '../src/Icon.stories.ts',\n      '../src/stories/components/Icon/Icon.stories.tsx',\n      '../src/stories/components/Icon/Icon.mdx',\n    ],\n  },\n  {\n    glob: '../src/stories/**/*.stories.+(js|ts)',\n    recursive: true,\n    validPaths: [\n      '../src/stories/components/Icon.stories.js',\n      '../src/stories/Icon.stories.js',\n      '../src/stories/Icon.stories.ts',\n      '../src/stories/components/Icon/Icon.stories.js',\n      '../src/stories/components/Icon.stories/Icon.stories.ts',\n    ],\n    invalidPaths: [\n      './stories.js',\n      './src/stories/Icon.stories.js',\n      './Icon.stories.js',\n      '../src/Icon.stories.tsx',\n      '../src/stories/components/Icon/Icon.stories.tsx',\n      '../src/stories/components/Icon/Icon.mdx',\n    ],\n  },\n  {\n    glob: '../src/stories/**/*.stories.*(js|ts)',\n    recursive: true,\n    validPaths: [\n      '../src/stories/components/Icon.stories.js',\n      '../src/stories/Icon.stories.js',\n      '../src/stories/Icon.stories.ts',\n      '../src/stories/components/Icon/Icon.stories.js',\n      '../src/stories/components/Icon.stories/Icon.stories.ts',\n    ],\n    invalidPaths: [\n      './stories.js',\n      './src/stories/Icon.stories.js',\n      './Icon.stories.js',\n      '../src/Icon.stories.ts',\n      '../src/stories/components/Icon/Icon.stories.tsx',\n      '../src/stories/components/Icon/Icon.mdx',\n    ],\n  },\n  {\n    glob: '../src/stories/components/Icon.stories.js',\n    recursive: false,\n    validPaths: ['../src/stories/components/Icon.stories.js'],\n    invalidPaths: [\n      '../src/Icon.stories.tsx',\n      '../src/stories/components/Icon.stories/Icon.stories.tsx',\n      '../src/stories/components/Icon/Icon.mdx',\n      '../src/stories/components/Icon/Icon.stories.js',\n      '../src/stories/components/Icon/Icon.stories.ts',\n      '../src/stories/Icon.stories.js',\n      '../src/stories/Icon.stories.tsx',\n      './Icon.stories.js',\n      './src/stories/Icon.stories.js',\n      './stories.js',\n    ],\n  },\n  // DUMB GLOB\n  {\n    glob: '../src/stories/**/*.stories.[tj]sx',\n    recursive: true,\n    validPaths: [\n      '../src/stories/components/Icon.stories.jsx',\n      '../src/stories/Icon.stories.jsx',\n      '../src/stories/Icon.stories.tsx',\n      '../src/stories/components/Icon/Icon.stories.jsx',\n      '../src/stories/components/Icon.stories/Icon.stories.tsx',\n    ],\n    invalidPaths: [\n      './stories.jsx',\n      './src/stories/Icon.stories.jsx',\n      './Icon.stories.jsx',\n      '../src/Icon.stories.tsx',\n      '../src/stories/components/Icon/Icon.stories.ts',\n      '../src/stories/components/Icon/Icon.tsx',\n    ],\n  },\n  {\n    glob: '../components/*.stories.js',\n    recursive: false,\n    validPaths: ['../components/Icon.stories.js'],\n    invalidPaths: [\n      '../components/icon/node_modules/icon/Icon.stories.js',\n      './stories.js',\n      './src/stories/Icon.stories.js',\n      './Icon.stories.js',\n      '../src/Icon.stories.tsx',\n      '../src/stories/components/Icon/Icon.stories.ts',\n      '../src/stories/components/Icon/Icon.mdx',\n    ],\n  },\n  {\n    glob: '../components/*/*.stories.js',\n    recursive: true,\n    validPaths: ['../components/icon/Icon.stories.js'],\n    invalidPaths: [\n      '../components/icon/node_modules/icon/Icon.stories.js',\n      './stories.js',\n      './src/stories/Icon.stories.js',\n      './Icon.stories.js',\n      '../src/Icon.stories.tsx',\n      '../src/stories/components/Icon/Icon.stories.ts',\n      '../src/stories/components/Icon/Icon.mdx',\n    ],\n  },\n  {\n    glob: '../components/*/*/*.stories.js',\n    recursive: true,\n    validPaths: ['../components/basics/icon/Icon.stories.js'],\n    invalidPaths: [\n      '../components/icon/node_modules/icon/Icon.stories.js',\n      './stories.js',\n      './src/stories/Icon.stories.js',\n      './Icon.stories.js',\n      '../src/Icon.stories.tsx',\n      '../components/icon/Icon.stories.js',\n      '../components/basics/simple/icon/Icon.stories.js',\n      '../src/stories/components/Icon/Icon.stories.ts',\n      '../src/stories/components/Icon/Icon.mdx',\n    ],\n  },\n  {\n    glob: '../components/*/stories/*.js',\n    recursive: true,\n    validPaths: ['../components/icon/stories/Icon.js'],\n    invalidPaths: [\n      '../components/icon/node_modules/icon/stories/Icon.js',\n      './stories.js',\n      './src/stories/Icon.stories.js',\n      './Icon.stories.js',\n      '../src/Icon.stories.tsx',\n      '../src/stories/components/Icon/Icon.stories.ts',\n      '../src/stories/components/Icon/Icon.mdx',\n    ],\n  },\n  // Patterns before the **, see:\n  //   - https://github.com/storybookjs/storybook/issues/17038\n  //   - https://github.com/storybookjs/storybook/issues/16964\n  //   - https://github.com/storybookjs/storybook/issues/16924\n  {\n    glob: '../{dir1,dir2}/**/*.stories.js',\n    recursive: true,\n    validPaths: [\n      '../dir1/Icon.stories.js',\n      '../dir1/nested/Icon.stories.js',\n      '../dir2/Icon.stories.js',\n      '../dir2/nested/Icon.stories.js',\n    ],\n    invalidPaths: ['../dir3/Icon.stories.js', '../dir3/nested/Icon.stories.js'],\n  },\n];\n\ndescribe('toRequireContext', () => {\n  testCases.forEach(({ glob, recursive, validPaths, invalidPaths }) => {\n    it(`matches only suitable paths - ${glob}`, () => {\n      const {\n        path: base,\n        recursive: willRecurse,\n        match,\n      } = toRequireContext(\n        normalizeStoriesEntry(glob, { configDir: '/path', workingDir: '/path' })\n      );\n\n      const regex = new RegExp(match);\n\n      function isMatched(filePath: string) {\n        const relativePath = `./${relative(base, filePath)}`;\n\n        const baseIncluded = filePath.includes(base);\n        const matched = regex.test(relativePath);\n\n        // console.log(filePath, relativePath, regex, matched);\n\n        return baseIncluded && matched;\n      }\n\n      const isNotMatchedForValidPaths = validPaths.filter((filePath) => !isMatched(filePath));\n      const isMatchedForInvalidPaths = invalidPaths.filter((filePath) => !!isMatched(filePath));\n\n      expect(isNotMatchedForValidPaths).toEqual([]);\n      expect(isMatchedForInvalidPaths).toEqual([]);\n      expect(willRecurse).toEqual(recursive);\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/core-webpack/src/to-require-context.ts",
    "content": "import { globToRegexp } from 'storybook/internal/common';\nimport type { NormalizedStoriesSpecifier } from 'storybook/internal/types';\n\nexport const toRequireContext = (specifier: NormalizedStoriesSpecifier) => {\n  const { directory, files } = specifier;\n\n  // The importPathMatcher is a `./`-prefixed matcher that includes the directory\n  // For `require.context()` we want the same thing, relative to directory\n  const match = globToRegexp(`./${files}`);\n\n  return {\n    path: directory,\n    recursive: files.includes('**') || files.split('/').length > 1,\n    match,\n  };\n};\n\nexport const toRequireContextString = (specifier: NormalizedStoriesSpecifier) => {\n  const { path: p, recursive: r, match: m } = toRequireContext(specifier);\n\n  const result = `require.context('${p}', ${r}, ${m})`;\n  return result;\n};\n"
  },
  {
    "path": "code/lib/core-webpack/src/types.ts",
    "content": "import type { Options, StorybookConfig as StorybookConfigBase } from 'storybook/internal/types';\n\nexport type { Options, Preset, BuilderResult, TypescriptOptions } from 'storybook/internal/types';\n\nexport type RulesConfig = any;\n\nexport type ModuleConfig = {\n  rules?: RulesConfig[];\n};\n\nexport type ResolveConfig = {\n  extensions?: string[];\n  mainFields?: (string | string[])[] | undefined;\n  alias?: any;\n};\n\nexport interface WebpackConfiguration {\n  plugins?: any[];\n  module?: ModuleConfig;\n  resolve?: ResolveConfig;\n  optimization?: any;\n  devtool?: false | string;\n}\n\nexport type BuilderOptions = {\n  fsCache?: boolean;\n  lazyCompilation?: boolean;\n};\n\nexport type StorybookConfig<TWebpackConfiguration = WebpackConfiguration> = StorybookConfigBase & {\n  /**\n   * Modify or return a custom Webpack config after the Storybook's default configuration has run\n   * (mostly used by addons).\n   */\n  webpack?: (\n    config: TWebpackConfiguration,\n    options: Options\n  ) => TWebpackConfiguration | Promise<TWebpackConfiguration>;\n\n  /** Modify or return a custom Webpack config after every addon has run. */\n  webpackFinal?: (\n    config: TWebpackConfiguration,\n    options: Options\n  ) => TWebpackConfiguration | Promise<TWebpackConfiguration>;\n};\n"
  },
  {
    "path": "code/lib/core-webpack/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/lib/core-webpack/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/lib/create-storybook/.eslintrc.cjs",
    "content": "module.exports = {\n  overrides: [\n    {\n      files: 'templates/**/*',\n      env: {\n        browser: true,\n      },\n      rules: {\n        'react/no-this-in-sfc': 'off',\n        'react/react-in-jsx-scope': 'off',\n        'global-require': 'off',\n        'no-redeclare': 'off',\n        'react/prop-types': 'off',\n      },\n    },\n    {\n      files: 'rendererAssets/**/*',\n      env: {\n        browser: true,\n      },\n      rules: {\n        'jsx-a11y/anchor-is-valid': 'off',\n        'react/prop-types': 'off',\n        'react/react-in-jsx-scope': 'off',\n        'import/extensions': 'off',\n        'import/named': 'off',\n      },\n    },\n  ],\n};\n"
  },
  {
    "path": "code/lib/create-storybook/README.md",
    "content": "## Install Storybook in your project\n\n```sh\nnpm create storybook@latest\n```\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/lib/create-storybook/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    node: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n        dts: false,\n      },\n      {\n        entryPoint: './src/bin/index.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/lib/create-storybook/package.json",
    "content": "{\n  \"name\": \"create-storybook\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook installer: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"cli\",\n    \"create\",\n    \"init\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/lib/create-storybook\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/lib/cli\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"Storybook Team\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": \"./dist/index.js\",\n    \"./package.json\": \"./package.json\"\n  },\n  \"bin\": \"./dist/bin/index.js\",\n  \"files\": [\n    \"bin/**/*\",\n    \"dist/**/*\",\n    \"rendererAssets/**/*\",\n    \"templates/**/*\",\n    \"README.md\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"semver\": \"^7.7.3\",\n    \"storybook\": \"workspace:*\"\n  },\n  \"devDependencies\": {\n    \"@types/prompts\": \"^2.0.9\",\n    \"@types/semver\": \"^7.7.1\",\n    \"commander\": \"^14.0.2\",\n    \"empathic\": \"^2.0.0\",\n    \"picocolors\": \"^1.1.0\",\n    \"process-ancestry\": \"^0.0.2\",\n    \"react\": \"^18.2.0\",\n    \"tiny-invariant\": \"^1.3.1\",\n    \"ts-dedent\": \"^2.0.0\",\n    \"typescript\": \"^5.8.3\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/lib/create-storybook/project.json",
    "content": "{\n  \"name\": \"create-storybook\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/lib/create-storybook/rendererAssets/.eslintrc.json",
    "content": "{\n  \"rules\": {\n    \"no-undef\": \"off\",\n    \"react/prop-types\": \"off\",\n    \"react/react-in-jsx-scope\": \"off\",\n    \"import/extensions\": \"off\"\n  },\n  \"overrides\": [\n    {\n      \"files\": [\"nextjs/**/*.@(jsx|tsx)\"],\n      \"rules\": {\n        \"react/no-unknown-property\": \"off\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "code/lib/create-storybook/rendererAssets/common/Configure.mdx",
    "content": "import { Meta } from \"@storybook/addon-docs/blocks\";\n\nimport Github from \"./assets/github.svg\";\nimport Discord from \"./assets/discord.svg\";\nimport Youtube from \"./assets/youtube.svg\";\nimport Tutorials from \"./assets/tutorials.svg\";\nimport Styling from \"./assets/styling.png\";\nimport Context from \"./assets/context.png\";\nimport Assets from \"./assets/assets.png\";\nimport Docs from \"./assets/docs.png\";\nimport Share from \"./assets/share.png\";\nimport FigmaPlugin from \"./assets/figma-plugin.png\";\nimport Testing from \"./assets/testing.png\";\nimport Accessibility from \"./assets/accessibility.png\";\nimport Theming from \"./assets/theming.png\";\nimport AddonLibrary from \"./assets/addon-library.png\";\n\nexport const RightArrow = () => <svg \n    viewBox=\"0 0 14 14\" \n    width=\"8px\" \n    height=\"14px\" \n    style={{ \n      marginLeft: '4px',\n      display: 'inline-block',\n      shapeRendering: 'inherit',\n      verticalAlign: 'middle',\n      fill: 'currentColor',\n      'path fill': 'currentColor'\n    }}\n>\n  <path d=\"m11.1 7.35-5.5 5.5a.5.5 0 0 1-.7-.7L10.04 7 4.9 1.85a.5.5 0 1 1 .7-.7l5.5 5.5c.2.2.2.5 0 .7Z\" />\n</svg>\n\n<Meta title=\"Configure your project\" />\n\n<div className=\"sb-container\">\n  <div className='sb-section-title'>\n    # Configure your project\n\n    Because Storybook works separately from your app, you'll need to configure it for your specific stack and setup. Below, explore guides for configuring Storybook with popular frameworks and tools. If you get stuck, learn how you can ask for help from our community.\n  </div>\n  <div className=\"sb-section\">\n    <div className=\"sb-section-item\">\n      <img\n        src={Styling}\n        alt=\"A wall of logos representing different styling technologies\"\n      />\n      <h4 className=\"sb-section-item-heading\">Add styling and CSS</h4>\n      <p className=\"sb-section-item-paragraph\">Like with web applications, there are many ways to include CSS within Storybook. Learn more about setting up styling within Storybook.</p>\n      <a\n        className=\"sb-action-link\"\n        href=\"https://storybook.js.org/docs/configure/styling-and-css/?renderer={{renderer}}&ref=configure\"\n        target=\"_blank\"\n      >Learn more<RightArrow /></a>\n    </div>\n    <div className=\"sb-section-item\">\n      <img\n        src={Context}\n        alt=\"An abstraction representing the composition of data for a component\"\n      />\n      <h4 className=\"sb-section-item-heading\">Provide context and mocking</h4>\n      <p className=\"sb-section-item-paragraph\">Often when a story doesn't render, it's because your component is expecting a specific environment or context (like a theme provider) to be available.</p>\n      <a\n        className=\"sb-action-link\"\n        href=\"https://storybook.js.org/docs/writing-stories/decorators/?renderer={{renderer}}&ref=configure#context-for-mocking\"\n        target=\"_blank\"\n      >Learn more<RightArrow /></a>\n    </div>\n    <div className=\"sb-section-item\">\n      <img src={Assets} alt=\"A representation of typography and image assets\" />\n      <div>\n        <h4 className=\"sb-section-item-heading\">Load assets and resources</h4>\n        <p className=\"sb-section-item-paragraph\">To link static files (like fonts) to your projects and stories, use the\n        `staticDirs` configuration option to specify folders to load when\n        starting Storybook.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/configure/images-and-assets/?renderer={{renderer}}&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n    </div>\n  </div>\n</div>\n<div className=\"sb-container\">\n  <div className='sb-section-title'>\n    # Do more with Storybook\n\n    Now that you know the basics, let's explore other parts of Storybook that will improve your experience. This list is just to get you started. You can customise Storybook in many ways to fit your needs.\n  </div>\n\n  <div className=\"sb-section\">\n    <div className=\"sb-features-grid\">\n      <div className=\"sb-grid-item\">\n        <img src={Docs} alt=\"A screenshot showing the autodocs tag being set, pointing a docs page being generated\" />\n        <h4 className=\"sb-section-item-heading\">Autodocs</h4>\n        <p className=\"sb-section-item-paragraph\">Auto-generate living,\n          interactive reference documentation from your components and stories.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/writing-docs/autodocs/?renderer={{renderer}}&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <img src={Share} alt=\"A browser window showing a Storybook being published to a chromatic.com URL\" />\n        <h4 className=\"sb-section-item-heading\">Publish to Chromatic</h4>\n        <p className=\"sb-section-item-paragraph\">Publish your Storybook to review and collaborate with your entire team.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/sharing/publish-storybook/?renderer={{renderer}}&ref=configure#publish-storybook-with-chromatic\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <img src={FigmaPlugin} alt=\"Windows showing the Storybook plugin in Figma\" />\n        <h4 className=\"sb-section-item-heading\">Figma Plugin</h4>\n        <p className=\"sb-section-item-paragraph\">Embed your stories into Figma to cross-reference the design and live\n          implementation in one place.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/sharing/design-integrations/?renderer={{renderer}}&ref=configure#embed-storybook-in-figma-with-the-plugin\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <img src={Testing} alt=\"Screenshot of tests passing and failing\" />\n        <h4 className=\"sb-section-item-heading\">Testing</h4>\n        <p className=\"sb-section-item-paragraph\">Use stories to test a component in all its variations, no matter how\n          complex.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/writing-tests/?renderer={{renderer}}&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <img src={Accessibility} alt=\"Screenshot of accessibility tests passing and failing\" />\n        <h4 className=\"sb-section-item-heading\">Accessibility</h4>\n        <p className=\"sb-section-item-paragraph\">Automatically test your components for a11y issues as you develop.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/writing-tests/accessibility-testing/?renderer={{renderer}}&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <img src={Theming} alt=\"Screenshot of Storybook in light and dark mode\" />\n        <h4 className=\"sb-section-item-heading\">Theming</h4>\n        <p className=\"sb-section-item-paragraph\">Theme Storybook's UI to personalize it to your project.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/configure/theming/?renderer={{renderer}}&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n    </div>\n  </div>\n</div>\n<div className='sb-addon'>\n  <div className='sb-addon-text'>\n    <h4>Addons</h4>\n    <p className=\"sb-section-item-paragraph\">Integrate your tools with Storybook to connect workflows.</p>\n    <a\n        className=\"sb-action-link\"\n        href=\"https://storybook.js.org/addons/?ref=configure\"\n        target=\"_blank\"\n      >Discover all addons<RightArrow /></a>\n  </div>\n  <div className='sb-addon-img'>\n    <img src={AddonLibrary} alt=\"Integrate your tools with Storybook to connect workflows.\" />\n  </div>\n</div>\n\n<div className=\"sb-section sb-socials\">\n    <div className=\"sb-section-item\">\n      <img src={Github} alt=\"Github logo\" className=\"sb-explore-image\"/>\n      Join our contributors building the future of UI development.\n\n      <a\n        className=\"sb-action-link\"\n        href=\"https://github.com/storybookjs/storybook\"\n        target=\"_blank\"\n      >Star on GitHub<RightArrow /></a>\n    </div>\n    <div className=\"sb-section-item\">\n      <img src={Discord} alt=\"Discord logo\" className=\"sb-explore-image\"/>\n      <div>\n        Get support and chat with frontend developers.\n\n        <a\n          className=\"sb-action-link\"\n          href=\"https://discord.gg/storybook\"\n          target=\"_blank\"\n        >Join Discord server<RightArrow /></a>\n      </div>\n    </div>\n    <div className=\"sb-section-item\">\n      <img src={Youtube} alt=\"Youtube logo\" className=\"sb-explore-image\"/>\n      <div>\n        Watch tutorials, feature previews and interviews.\n\n        <a\n          className=\"sb-action-link\"\n          href=\"https://www.youtube.com/@chromaticui\"\n          target=\"_blank\"\n        >Watch on YouTube<RightArrow /></a>\n      </div>\n    </div>\n    <div className=\"sb-section-item\">\n      <img src={Tutorials} alt=\"A book\" className=\"sb-explore-image\"/>\n      <p>Follow guided walkthroughs on for key workflows.</p>\n\n      <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/tutorials/?ref=configure\"\n          target=\"_blank\"\n        >Discover tutorials<RightArrow /></a>\n    </div>\n</div>\n\n<style>\n  {`\n  .sb-container {\n    margin-bottom: 48px;\n  }\n\n  .sb-section {\n    width: 100%;\n    display: flex;\n    flex-direction: row;\n    gap: 20px;\n  }\n\n  img {\n    object-fit: cover;\n  }\n\n  .sb-section-title {\n    margin-bottom: 32px;\n  }\n\n  .sb-section a:not(h1 a, h2 a, h3 a) {\n    font-size: 14px;\n  }\n\n  .sb-section-item, .sb-grid-item {\n    flex: 1;\n    display: flex;\n    flex-direction: column;\n  }\n\n  .sb-section-item-heading {\n    padding-top: 20px !important;\n    padding-bottom: 5px !important;\n    margin: 0 !important;\n  }\n  .sb-section-item-paragraph {\n    margin: 0;\n    padding-bottom: 10px;\n  }\n\n  .sb-action-link {\n    text-decoration: none;\n  }\n\n  .sb-action-link:hover, .sb-action-link:focus {\n    text-decoration: underline;\n    text-decoration-thickness: 0.03125rem;\n    text-underline-offset: 0.11em;\n  }\n\n  .sb-chevron {\n    margin-left: 5px;\n  }\n\n  .sb-features-grid {\n    display: grid;\n    grid-template-columns: repeat(2, 1fr);\n    grid-gap: 32px 20px;\n  }\n\n  .sb-socials {\n    display: grid;\n    grid-template-columns: repeat(4, 1fr);\n  }\n\n  .sb-socials p {\n    margin-bottom: 10px;\n  }\n\n  .sb-explore-image {\n    max-height: 32px;\n    align-self: flex-start;\n  }\n\n  .sb-addon {\n    width: 100%;\n    display: flex;\n    align-items: center;\n    position: relative;\n    background-color: #EEF3F8;\n    border-radius: 5px;\n    border: 1px solid rgba(0, 0, 0, 0.05);\n    background: #EEF3F8;\n    height: 180px;\n    margin-bottom: 48px;\n    overflow: hidden;\n  }\n\n  .sb-addon-text {\n    padding-left: 48px;\n    max-width: 240px;\n  }\n\n  .sb-addon-text h4 {\n    padding-top: 0px;\n  }\n\n  .sb-addon-img {\n    position: absolute;\n    left: 345px;\n    top: 0;\n    height: 100%;\n    width: 200%;\n    overflow: hidden;\n  }\n\n  .sb-addon-img img {\n    width: 650px;\n    transform: rotate(-15deg);\n    margin-left: 40px;\n    margin-top: -72px;\n    box-shadow: 0 0 1px rgba(255, 255, 255, 0);\n    backface-visibility: hidden;\n  }\n\n  @media screen and (max-width: 800px) {\n    .sb-addon-img {\n      left: 300px;\n    }\n  }\n\n  @media screen and (max-width: 600px) {\n    .sb-section {\n      flex-direction: column;\n    }\n\n    .sb-features-grid {\n      grid-template-columns: repeat(1, 1fr);\n    }\n\n    .sb-socials {\n      grid-template-columns: repeat(2, 1fr);\n    }\n\n    .sb-addon {\n      height: 280px;\n      align-items: flex-start;\n      padding-top: 32px;\n      overflow: hidden;\n    }\n\n    .sb-addon-text {\n      padding-left: 24px;\n    }\n\n    .sb-addon-img {\n      right: 0;\n      left: 0;\n      top: 130px;\n      bottom: 0;\n      overflow: hidden;\n      height: auto;\n      width: 124%;\n    }\n\n    .sb-addon-img img {\n      width: 1200px;\n      transform: rotate(-12deg);\n      margin-left: 0;\n      margin-top: 48px;\n      margin-bottom: -40px;\n      margin-left: -24px;\n    }\n  }\n  `}\n</style>\n"
  },
  {
    "path": "code/lib/create-storybook/rendererAssets/common/button.css",
    "content": ".storybook-button {\n  display: inline-block;\n  cursor: pointer;\n  border: 0;\n  border-radius: 3em;\n  font-weight: 700;\n  line-height: 1;\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n.storybook-button--primary {\n  background-color: #555ab9;\n  color: white;\n}\n.storybook-button--secondary {\n  box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;\n  background-color: transparent;\n  color: #333;\n}\n.storybook-button--small {\n  padding: 10px 16px;\n  font-size: 12px;\n}\n.storybook-button--medium {\n  padding: 11px 20px;\n  font-size: 14px;\n}\n.storybook-button--large {\n  padding: 12px 24px;\n  font-size: 16px;\n}\n"
  },
  {
    "path": "code/lib/create-storybook/rendererAssets/common/header.css",
    "content": ".storybook-header {\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n  padding: 15px 20px;\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n\n.storybook-header svg {\n  display: inline-block;\n  vertical-align: top;\n}\n\n.storybook-header h1 {\n  display: inline-block;\n  vertical-align: top;\n  margin: 6px 0 6px 10px;\n  font-weight: 700;\n  font-size: 20px;\n  line-height: 1;\n}\n\n.storybook-header button + button {\n  margin-left: 10px;\n}\n\n.storybook-header .welcome {\n  margin-right: 10px;\n  color: #333;\n  font-size: 14px;\n}\n"
  },
  {
    "path": "code/lib/create-storybook/rendererAssets/common/page.css",
    "content": ".storybook-page {\n  margin: 0 auto;\n  padding: 48px 20px;\n  max-width: 600px;\n  color: #333;\n  font-size: 14px;\n  line-height: 24px;\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n\n.storybook-page h2 {\n  display: inline-block;\n  vertical-align: top;\n  margin: 0 0 4px;\n  font-weight: 700;\n  font-size: 32px;\n  line-height: 1;\n}\n\n.storybook-page p {\n  margin: 1em 0;\n}\n\n.storybook-page a {\n  color: inherit;\n}\n\n.storybook-page ul {\n  margin: 1em 0;\n  padding-left: 30px;\n}\n\n.storybook-page li {\n  margin-bottom: 8px;\n}\n\n.storybook-page .tip {\n  display: inline-block;\n  vertical-align: top;\n  margin-right: 10px;\n  border-radius: 1em;\n  background: #e7fdd8;\n  padding: 4px 12px;\n  color: #357a14;\n  font-weight: 700;\n  font-size: 11px;\n  line-height: 12px;\n}\n\n.storybook-page .tip-wrapper {\n  margin-top: 40px;\n  margin-bottom: 40px;\n  font-size: 13px;\n  line-height: 20px;\n}\n\n.storybook-page .tip-wrapper svg {\n  display: inline-block;\n  vertical-align: top;\n  margin-top: 3px;\n  margin-right: 4px;\n  width: 12px;\n  height: 12px;\n}\n\n.storybook-page .tip-wrapper svg path {\n  fill: #1ea7fd;\n}\n"
  },
  {
    "path": "code/lib/create-storybook/src/bin/index.ts",
    "content": "#!/usr/bin/env node\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { dedent } from 'ts-dedent';\n\nconst [majorNodeVersion, minorNodeVersion] = process.versions.node.split('.').map(Number);\n\nif (\n  majorNodeVersion < 20 ||\n  (majorNodeVersion === 20 && minorNodeVersion < 19) ||\n  (majorNodeVersion === 22 && minorNodeVersion < 12)\n) {\n  logger.error(\n    dedent`To run Storybook, you need Node.js version 20.19+ or 22.12+.\n      You are currently running Node.js ${process.version}. Please upgrade your Node.js installation.`\n  );\n  process.exit(1);\n}\n\nimport('./run.ts');\n"
  },
  {
    "path": "code/lib/create-storybook/src/bin/modernInputs.ts",
    "content": "export type Framework = (typeof supportedFrameworks)[number];\n\n// TODO: sync this/pull this from core\nexport const supportedFrameworks = [\n  'angular',\n  'ember',\n  'html-vite',\n  'nextjs',\n  'nextjs-vite',\n  'nuxt',\n  'preact-vite',\n  'qwik',\n  'react-native-web-vite',\n  'react-rsbuild',\n  'react-vite',\n  'react-webpack5',\n  'server-webpack5',\n  'solid',\n  'svelte-vite',\n  'sveltekit',\n  'vue3-rsbuild',\n  'vue3-vite',\n  'react-native',\n  'web-components-vite',\n] as const;\n\nexport const supportedFrameworksPackages = {\n  'html-vite': '@storybook/html-vite',\n  'preact-vite': '@storybook/preact-vite',\n  'react-native-web-vite': '@storybook/react-native-web-vite',\n  'react-rsbuild': 'storybook-react-rsbuild',\n  'react-vite': '@storybook/react-vite',\n  'react-webpack5': '@storybook/react-webpack5',\n  'server-webpack5': '@storybook/server-webpack5',\n  'svelte-vite': '@storybook/svelte-vite',\n  'vue3-rsbuild': 'storybook-vue3-rsbuild',\n  'vue3-vite': '@storybook/vue3-vite',\n  'web-components-vite': '@storybook/web-components-vite',\n\n  angular: '@storybook/angular',\n  ember: '@storybook/ember',\n  nextjs: '@storybook/nextjs',\n  'nextjs-vite': '@storybook/nextjs-vite',\n\n  nuxt: '@storybook/vue3-vite',\n  qwik: 'storybook-framework-qwik',\n  solid: 'storybook-solidjs-vite',\n  sveltekit: '@storybook/sveltekit',\n  'react-native': '@storybook/react-native',\n} satisfies Record<Framework, string>;\n\nexport const supportedFrameworksNames = {\n  'html-vite': 'HTML with Vite',\n  'preact-vite': 'Preact with Vite',\n  'react-native-web-vite': 'React Native Web with Vite',\n  'react-rsbuild': 'React with Rsbuild',\n  'react-vite': 'React with Vite',\n  'react-webpack5': 'React with Webpack 5',\n  'server-webpack5': 'Server with Webpack 5',\n  'svelte-vite': 'Svelte with Vite',\n  'vue3-rsbuild': 'Vue 3 with Rsbuild',\n  'vue3-vite': 'Vue 3 with Vite',\n  'web-components-vite': 'Web Components with Vite',\n  angular: 'Angular',\n  ember: 'Ember',\n  nextjs: 'NextJS',\n  'nextjs-vite': 'NextJS with Vite',\n  nuxt: 'Nuxt',\n  qwik: 'Qwik',\n  solid: 'Solid',\n  sveltekit: 'SvelteKit',\n  'react-native': 'React Native',\n} satisfies Record<Framework, string>;\n"
  },
  {
    "path": "code/lib/create-storybook/src/bin/run.ts",
    "content": "import { ProjectType } from 'storybook/internal/cli';\nimport { PackageManagerName, isCI, optionalEnvToBoolean } from 'storybook/internal/common';\nimport { logTracker, logger } from 'storybook/internal/node-logger';\nimport { addToGlobalContext } from 'storybook/internal/telemetry';\nimport { Feature, SupportedBuilder } from 'storybook/internal/types';\n\nimport { Option, program } from 'commander';\n\nimport { version } from '../../package.json';\nimport type { CommandOptions } from '../generators/types.ts';\nimport { initiate } from '../initiate.ts';\n\naddToGlobalContext('cliVersion', version);\n\n/**\n * Create a commander application with flags for both legacy and modern. We then check the options\n * given by commander with zod. If zod validates the options, we run the modern version of the app.\n * If zod fails to validate the options, we check why, and if it's because of a legacy flag, we run\n * the legacy version of the app.\n */\nconst createStorybookProgram = program\n  .name('Initialize Storybook into your project.')\n  .option(\n    '--disable-telemetry',\n    'Disable sending telemetry data',\n    optionalEnvToBoolean(process.env.STORYBOOK_DISABLE_TELEMETRY)\n  )\n  .addOption(\n    new Option('--features <list...>', 'Storybook features')\n      .choices(Object.values(Feature))\n      .default(undefined)\n  )\n  .option('--no-features', 'Disable all features (overrides --features)')\n  .option('--debug', 'Get more logs in debug mode')\n  .option('--enable-crash-reports', 'Enable sending crash reports to telemetry data')\n  .option('-f --force', 'Force add Storybook')\n  .option('-s --skip-install', 'Skip installing deps')\n  .addOption(\n    new Option('--package-manager <type>', 'Force package manager for installing deps').choices(\n      Object.values(PackageManagerName)\n    )\n  )\n  // TODO: Remove in SB11\n  .option('--use-pnp', 'Enable pnp mode for Yarn 2+')\n  .addOption(\n    new Option('--parser <type>', 'jscodeshift parser').choices([\n      'babel',\n      'babylon',\n      'flow',\n      'ts',\n      'tsx',\n    ])\n  )\n  .addOption(\n    new Option('--type <type>', 'Add Storybook for a specific project type').choices(\n      Object.values(ProjectType).filter(\n        (type) => ![ProjectType.UNDETECTED, ProjectType.UNSUPPORTED, ProjectType.NX].includes(type)\n      )\n    )\n  )\n  .option('-y --yes', 'Answer yes to all prompts')\n  .addOption(\n    new Option('--builder <type>', 'Builder library').choices(Object.values(SupportedBuilder))\n  )\n  .option('-l --linkable', 'Prepare installation for link (contributor helper)')\n  // due to how Commander handles default values and negated options, we have to elevate the default into Commander, and we have to specify `--dev`\n  // alongside `--no-dev` even if we are unlikely to directly use `--dev`. https://github.com/tj/commander.js/issues/2068#issuecomment-1804524585\n  .option(\n    '--dev',\n    'Launch the development server after completing initialization. Enabled by default'\n  )\n  .option(\n    '--no-dev',\n    'Complete the initialization of Storybook without launching the Storybook development server'\n  )\n  .option(\n    '--logfile [path]',\n    'Write all debug logs to the specified file at the end of the run. Defaults to debug-storybook.log when [path] is not provided'\n  )\n  .addOption(\n    new Option('--loglevel <level>', 'Define log level').choices([\n      'trace',\n      'debug',\n      'info',\n      'warn',\n      'error',\n      'silent',\n    ])\n  )\n  .hook('preAction', async (self) => {\n    const options = self.opts();\n\n    if (options.debug) {\n      logger.setLogLevel('debug');\n    }\n\n    if (options.loglevel) {\n      logger.setLogLevel(options.loglevel);\n    }\n\n    if (options.logfile) {\n      logTracker.enableLogWriting();\n    }\n  })\n  .hook('postAction', async (command) => {\n    if (logTracker.shouldWriteLogsToFile) {\n      try {\n        await logTracker.writeToFile(command.getOptionValue('logfile'));\n      } catch {}\n    }\n  });\n\ncreateStorybookProgram\n  .action(async (options) => {\n    const isNeitherCiNorSandbox =\n      !isCI() && !optionalEnvToBoolean(process.env.IN_STORYBOOK_SANDBOX);\n    options.debug = options.debug ?? false;\n    options.dev = options.dev ?? isNeitherCiNorSandbox;\n\n    if (options.features === false) {\n      // Ensure features are treated as empty when --no-features is set\n      options.features = [];\n    }\n\n    await initiate(options as CommandOptions).catch(() => process.exit(1));\n  })\n  .version(String(version))\n  .parse(process.argv);\n"
  },
  {
    "path": "code/lib/create-storybook/src/commands/AddonConfigurationCommand.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { AddonVitestService } from 'storybook/internal/cli';\nimport { type JsPackageManager, PackageManagerName } from 'storybook/internal/common';\nimport { logger, prompt } from 'storybook/internal/node-logger';\nimport { ErrorCollector } from 'storybook/internal/telemetry';\n\nimport addonA11yPostinstall from '../../../../addons/a11y/src/postinstall.ts';\nimport addonVitestPostinstall from '../../../../addons/vitest/src/postinstall.ts';\nimport type { TelemetryService } from '../services/index.ts';\nimport {\n  AddonConfigurationCommand,\n  executeAddonConfiguration,\n} from './AddonConfigurationCommand.ts';\n\nvi.mock('storybook/internal/node-logger', { spy: true });\nvi.mock('storybook/internal/telemetry', { spy: true });\nvi.mock('../../../../addons/a11y/src/postinstall', { spy: true });\nvi.mock('../../../../addons/vitest/src/postinstall', { spy: true });\nvi.mock('../../../cli-storybook/src/postinstallAddon', () => ({\n  postinstallAddon: vi.fn().mockResolvedValue(undefined),\n}));\n\ndescribe('AddonConfigurationCommand', () => {\n  let command: AddonConfigurationCommand;\n  let mockPackageManager: JsPackageManager;\n  let mockAddonVitestService: AddonVitestService;\n  let mockTelemetryService: TelemetryService;\n  let mockTaskLog: ReturnType<typeof prompt.taskLog>;\n\n  beforeEach(() => {\n    mockPackageManager = {\n      type: 'npm',\n    } as Partial<JsPackageManager> as JsPackageManager;\n\n    mockAddonVitestService = {\n      installPlaywright: vi.fn().mockResolvedValue({ errors: [], result: 'installed' }),\n    } as Partial<AddonVitestService> as AddonVitestService;\n\n    mockTelemetryService = {\n      trackPlaywrightPromptDecision: vi.fn().mockResolvedValue(undefined),\n    } as Partial<TelemetryService> as TelemetryService;\n\n    mockTaskLog = {\n      message: vi.fn(),\n      success: vi.fn(),\n      error: vi.fn(),\n    } as unknown as ReturnType<typeof prompt.taskLog>;\n\n    vi.mocked(prompt.taskLog).mockReturnValue(mockTaskLog);\n    vi.mocked(logger.warn).mockImplementation(() => {});\n    vi.mocked(logger.error).mockImplementation(() => {});\n    vi.mocked(logger.debug).mockImplementation(() => {});\n    vi.mocked(logger.log).mockImplementation(() => {});\n    vi.mocked(ErrorCollector.addError).mockImplementation(() => {});\n    vi.mocked(addonA11yPostinstall).mockResolvedValue(undefined);\n    vi.mocked(addonVitestPostinstall).mockResolvedValue(undefined);\n\n    command = new AddonConfigurationCommand(\n      mockPackageManager,\n      { packageManager: PackageManagerName.NPM, yes: false, disableTelemetry: false },\n      mockAddonVitestService,\n      mockTelemetryService\n    );\n\n    vi.clearAllMocks();\n  });\n\n  describe('execute', () => {\n    it('should return success when no configDir is provided', async () => {\n      const result = await command.execute({\n        addons: ['@storybook/addon-vitest'],\n        configDir: undefined,\n      });\n\n      expect(result).toEqual({ status: 'success' });\n      expect(prompt.taskLog).not.toHaveBeenCalled();\n    });\n\n    it('should return success when addons array is empty', async () => {\n      const result = await command.execute({\n        addons: [],\n        configDir: '.storybook',\n      });\n\n      expect(result).toEqual({ status: 'success' });\n      expect(prompt.taskLog).not.toHaveBeenCalled();\n    });\n\n    it('should configure vitest addon successfully', async () => {\n      vi.mocked(prompt.taskLog).mockReturnValue(mockTaskLog);\n\n      const result = await command.execute({\n        addons: ['@storybook/addon-vitest'],\n        configDir: '.storybook',\n      });\n\n      expect(result).toEqual({ status: 'success' });\n      expect(addonVitestPostinstall).toHaveBeenCalledWith({\n        packageManager: 'npm',\n        configDir: '.storybook',\n        yes: true,\n        skipInstall: true,\n        skipDependencyManagement: true,\n        logger,\n        prompt,\n      });\n      expect(mockAddonVitestService.installPlaywright).toHaveBeenCalledWith({\n        yes: false,\n        useRemotePkg: false,\n      });\n      expect(mockTelemetryService.trackPlaywrightPromptDecision).toHaveBeenCalledWith('installed');\n      expect(mockTaskLog.success).toHaveBeenCalledWith('Addons configured successfully');\n    });\n\n    it('should configure a11y addon successfully', async () => {\n      vi.mocked(prompt.taskLog).mockReturnValue(mockTaskLog);\n\n      const result = await command.execute({\n        addons: ['@storybook/addon-a11y'],\n        configDir: '.storybook',\n      });\n\n      expect(result).toEqual({ status: 'success' });\n      expect(addonA11yPostinstall).toHaveBeenCalledWith({\n        packageManager: 'npm',\n        configDir: '.storybook',\n        yes: true,\n        skipInstall: true,\n        skipDependencyManagement: true,\n        logger,\n        prompt,\n      });\n      expect(mockTaskLog.success).toHaveBeenCalledWith('Addons configured successfully');\n    });\n\n    it('should configure generic addon via postinstallAddon', async () => {\n      const { postinstallAddon } = await import('../../../cli-storybook/src/postinstallAddon.ts');\n      vi.mocked(prompt.taskLog).mockReturnValue(mockTaskLog);\n\n      const result = await command.execute({\n        addons: ['@storybook/addon-docs'],\n        configDir: '.storybook',\n      });\n\n      expect(result).toEqual({ status: 'success' });\n      expect(postinstallAddon).toHaveBeenCalledWith('@storybook/addon-docs', {\n        packageManager: 'npm',\n        configDir: '.storybook',\n        yes: true,\n        skipInstall: true,\n        skipDependencyManagement: true,\n        logger,\n        prompt,\n      });\n      expect(mockTaskLog.success).toHaveBeenCalledWith('Addons configured successfully');\n    });\n\n    it('should configure multiple addons', async () => {\n      vi.mocked(prompt.taskLog).mockReturnValue(mockTaskLog);\n\n      const result = await command.execute({\n        addons: ['@storybook/addon-vitest', '@storybook/addon-a11y'],\n        configDir: '.storybook',\n      });\n\n      expect(result).toEqual({ status: 'success' });\n      expect(addonVitestPostinstall).toHaveBeenCalled();\n      expect(addonA11yPostinstall).toHaveBeenCalled();\n      expect(mockTaskLog.message).toHaveBeenCalledWith('Configuring @storybook/addon-vitest...');\n      expect(mockTaskLog.message).toHaveBeenCalledWith('Configuring @storybook/addon-a11y...');\n    });\n\n    it('should handle addon configuration failure gracefully', async () => {\n      const error = new Error('Configuration failed');\n      vi.mocked(addonVitestPostinstall).mockRejectedValue(error);\n      vi.mocked(prompt.taskLog).mockReturnValue(mockTaskLog);\n\n      const result = await command.execute({\n        addons: ['@storybook/addon-vitest'],\n        configDir: '.storybook',\n      });\n\n      expect(result).toEqual({ status: 'failed' });\n      expect(logger.debug).toHaveBeenCalledWith(error);\n      expect(ErrorCollector.addError).toHaveBeenCalledWith(error);\n      expect(mockTaskLog.error).toHaveBeenCalledWith('Failed to configure addons');\n    });\n\n    it('should handle partial addon failures', async () => {\n      const error = new Error('Vitest configuration failed');\n      vi.mocked(addonVitestPostinstall).mockRejectedValue(error);\n      vi.mocked(prompt.taskLog).mockReturnValue(mockTaskLog);\n\n      const result = await command.execute({\n        addons: ['@storybook/addon-vitest', '@storybook/addon-a11y'],\n        configDir: '.storybook',\n      });\n\n      expect(result).toEqual({ status: 'failed' });\n      expect(addonA11yPostinstall).toHaveBeenCalled();\n      expect(mockTaskLog.error).toHaveBeenCalledWith('Failed to configure addons');\n    });\n\n    it('should handle unexpected errors during execution', async () => {\n      const unexpectedError = new Error('Unexpected error');\n      vi.mocked(prompt.taskLog).mockImplementation(() => {\n        throw unexpectedError;\n      });\n\n      const result = await command.execute({\n        addons: ['@storybook/addon-vitest'],\n        configDir: '.storybook',\n      });\n\n      expect(result).toEqual({ status: 'failed' });\n      expect(logger.error).toHaveBeenCalledWith('Unexpected error during addon configuration:');\n      expect(logger.error).toHaveBeenCalledWith(unexpectedError);\n    });\n\n    it('should not install Playwright when vitest addon is not configured', async () => {\n      vi.mocked(prompt.taskLog).mockReturnValue(mockTaskLog);\n\n      await command.execute({\n        addons: ['@storybook/addon-a11y'],\n        configDir: '.storybook',\n      });\n\n      expect(mockAddonVitestService.installPlaywright).not.toHaveBeenCalled();\n      expect(mockTelemetryService.trackPlaywrightPromptDecision).not.toHaveBeenCalled();\n    });\n\n    it('should track skipped Playwright installation', async () => {\n      vi.mocked(mockAddonVitestService.installPlaywright).mockResolvedValue({\n        errors: [],\n        result: 'skipped',\n      });\n      vi.mocked(prompt.taskLog).mockReturnValue(mockTaskLog);\n\n      await command.execute({\n        addons: ['@storybook/addon-vitest'],\n        configDir: '.storybook',\n      });\n\n      expect(mockTelemetryService.trackPlaywrightPromptDecision).toHaveBeenCalledWith('skipped');\n    });\n\n    it('should track aborted Playwright installation', async () => {\n      vi.mocked(mockAddonVitestService.installPlaywright).mockResolvedValue({\n        errors: [],\n        result: 'aborted',\n      });\n      vi.mocked(prompt.taskLog).mockReturnValue(mockTaskLog);\n\n      await command.execute({\n        addons: ['@storybook/addon-vitest'],\n        configDir: '.storybook',\n      });\n\n      expect(mockTelemetryService.trackPlaywrightPromptDecision).toHaveBeenCalledWith('aborted');\n    });\n\n    it('should track failed Playwright installation', async () => {\n      vi.mocked(mockAddonVitestService.installPlaywright).mockResolvedValue({\n        errors: ['Installation error'],\n        result: 'failed',\n      });\n      vi.mocked(prompt.taskLog).mockReturnValue(mockTaskLog);\n\n      await command.execute({\n        addons: ['@storybook/addon-vitest'],\n        configDir: '.storybook',\n      });\n\n      expect(mockTelemetryService.trackPlaywrightPromptDecision).toHaveBeenCalledWith('failed');\n    });\n\n    it('should pass yes option to addon postinstall functions', async () => {\n      const commandWithYes = new AddonConfigurationCommand(\n        mockPackageManager,\n        { packageManager: PackageManagerName.NPM, yes: true, disableTelemetry: false },\n        mockAddonVitestService,\n        mockTelemetryService\n      );\n      vi.mocked(prompt.taskLog).mockReturnValue(mockTaskLog);\n\n      await commandWithYes.execute({\n        addons: ['@storybook/addon-vitest'],\n        configDir: '.storybook',\n      });\n\n      expect(addonVitestPostinstall).toHaveBeenCalledWith(expect.objectContaining({ yes: true }));\n      expect(mockAddonVitestService.installPlaywright).toHaveBeenCalledWith({\n        yes: true,\n        useRemotePkg: false,\n      });\n    });\n  });\n});\n\ndescribe('executeAddonConfiguration', () => {\n  let mockPackageManager: JsPackageManager;\n  let mockTaskLog: ReturnType<typeof prompt.taskLog>;\n\n  beforeEach(() => {\n    mockPackageManager = {\n      type: 'npm',\n    } as Partial<JsPackageManager> as JsPackageManager;\n\n    mockTaskLog = {\n      message: vi.fn(),\n      success: vi.fn(),\n      error: vi.fn(),\n    } as unknown as ReturnType<typeof prompt.taskLog>;\n\n    vi.mocked(prompt.taskLog).mockReturnValue(mockTaskLog);\n    vi.mocked(logger.warn).mockImplementation(() => {});\n    vi.mocked(logger.error).mockImplementation(() => {});\n    vi.mocked(logger.debug).mockImplementation(() => {});\n    vi.mocked(logger.log).mockImplementation(() => {});\n    vi.mocked(addonA11yPostinstall).mockResolvedValue(undefined);\n    vi.mocked(addonVitestPostinstall).mockResolvedValue(undefined);\n\n    vi.clearAllMocks();\n  });\n\n  it('should create command and execute with provided parameters', async () => {\n    const result = await executeAddonConfiguration({\n      packageManager: mockPackageManager,\n      options: { packageManager: PackageManagerName.NPM, disableTelemetry: true },\n      addons: [],\n      configDir: '.storybook',\n    });\n\n    expect(result).toEqual({ status: 'success' });\n  });\n\n  it('should execute addon configuration through helper function', async () => {\n    const result = await executeAddonConfiguration({\n      packageManager: mockPackageManager,\n      options: { packageManager: PackageManagerName.NPM, disableTelemetry: false },\n      addons: ['@storybook/addon-a11y'],\n      configDir: '.storybook',\n    });\n\n    expect(result).toEqual({ status: 'success' });\n    expect(addonA11yPostinstall).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/commands/AddonConfigurationCommand.ts",
    "content": "import { AddonVitestService } from 'storybook/internal/cli';\nimport { type JsPackageManager } from 'storybook/internal/common';\nimport { CLI_COLORS, logger, prompt } from 'storybook/internal/node-logger';\nimport { ErrorCollector } from 'storybook/internal/telemetry';\n\nimport { dedent } from 'ts-dedent';\n\nimport addonA11yPostinstall from '../../../../addons/a11y/src/postinstall.ts';\nimport addonVitestPostinstall from '../../../../addons/vitest/src/postinstall.ts';\nimport type { CommandOptions } from '../generators/types.ts';\nimport { TelemetryService } from '../services/index.ts';\n\nconst ADDON_INSTALLATION_INSTRUCTIONS = {\n  '@storybook/addon-vitest':\n    'https://storybook.js.org/docs/writing-tests/integrations/vitest-addon#manual-setup-advanced',\n} as { [key: string]: string };\n\ntype ExecuteAddonConfigurationParams = {\n  addons: string[];\n  configDir?: string;\n};\n\nexport type ExecuteAddonConfigurationResult = {\n  status: 'failed' | 'success';\n};\n\n/**\n * Command for configuring Storybook addons\n *\n * Responsibilities:\n *\n * - Run postinstall scripts for test addons (a11y, vitest)\n * - Configure addons without triggering installations\n * - Handle configuration errors gracefully\n */\nexport class AddonConfigurationCommand {\n  constructor(\n    readonly packageManager: JsPackageManager,\n    private readonly commandOptions: CommandOptions,\n    private readonly addonVitestService = new AddonVitestService(packageManager),\n    private readonly telemetryService = new TelemetryService(commandOptions.disableTelemetry)\n  ) {}\n\n  /** Execute addon configuration */\n  async execute({\n    addons,\n    configDir,\n  }: ExecuteAddonConfigurationParams): Promise<ExecuteAddonConfigurationResult> {\n    if (!configDir || addons.length === 0) {\n      return { status: 'success' };\n    }\n\n    try {\n      const { hasFailures, addonResults } = await this.configureAddons(configDir, addons);\n\n      if (addonResults.has('@storybook/addon-vitest')) {\n        const { result } = await this.addonVitestService.installPlaywright({\n          yes: this.commandOptions.yes,\n          useRemotePkg: !!this.commandOptions.skipInstall,\n        });\n        // Map outcome to telemetry decision\n        await this.telemetryService.trackPlaywrightPromptDecision(result);\n      }\n\n      // some addons failed\n      if (hasFailures) {\n        this.logManualAddonInstructions(\n          addons.filter((addon) => addonResults.get(addon)?.result === 'failed')\n        );\n      }\n\n      return { status: hasFailures ? 'failed' : 'success' };\n    } catch (e) {\n      logger.error('Unexpected error during addon configuration:');\n      logger.error(e);\n      return { status: 'failed' };\n    }\n  }\n\n  private getAddonsWithInstructions(addons: string[]): string[] {\n    return addons.filter((addon) => ADDON_INSTALLATION_INSTRUCTIONS[addon]);\n  }\n\n  private logManualAddonInstructions(addons: string[]): void {\n    const addonsWithInstructions = this.getAddonsWithInstructions(addons);\n\n    if (addonsWithInstructions.length > 0) {\n      logger.warn(dedent`\n      The following addons couldn't be configured:\n\n      ${addonsWithInstructions\n        .map((addon) => {\n          const manualInstructionLink = ADDON_INSTALLATION_INSTRUCTIONS[addon];\n\n          return `- ${addon}: ${manualInstructionLink}`;\n        })\n        .join('\\n')}\n\n      ${\n        addonsWithInstructions.length > 0\n          ? `Please follow each addon's configuration instructions manually.`\n          : ''\n      }\n      `);\n    }\n  }\n\n  /** Configure test addons (a11y and vitest) */\n  private async configureAddons(configDir: string, addons: string[]) {\n    // Import postinstallAddon from cli-storybook package\n    const { postinstallAddon } = await import('../../../cli-storybook/src/postinstallAddon.ts');\n\n    const task = prompt.taskLog({\n      id: 'configure-addons',\n      title: 'Configuring addons...',\n    });\n\n    // Track failures for each addon\n    const addonResults = new Map<string, null | any>();\n\n    // Configure each addon\n    for (const addon of addons) {\n      try {\n        task.message(`Configuring ${addon}...`);\n\n        const options = {\n          packageManager: this.packageManager.type,\n          configDir,\n          yes: true,\n          skipInstall: true,\n          skipDependencyManagement: true,\n          logger,\n          prompt,\n        };\n\n        if (addon === '@storybook/addon-vitest') {\n          await addonVitestPostinstall(options);\n        } else if (addon === '@storybook/addon-a11y') {\n          await addonA11yPostinstall(options);\n        } else {\n          await postinstallAddon(addon, options);\n        }\n\n        task.message(`${addon} configured\\n`);\n        addonResults.set(addon, null);\n      } catch (e) {\n        logger.debug(e);\n        ErrorCollector.addError(e);\n        addonResults.set(addon, e);\n      }\n    }\n\n    const hasFailures = [...addonResults.values()].some((result) => result !== null);\n\n    // Set final task status\n    if (hasFailures) {\n      task.error('Failed to configure addons');\n    } else {\n      task.success('Addons configured successfully');\n    }\n\n    // Log results for each addon, each as a separate log entry\n    addons.forEach((addon, index) => {\n      const error = addonResults.get(addon);\n      logger.log(CLI_COLORS.muted(error ? `❌ ${addon}` : `✅ ${addon}`), {\n        spacing: index === 0 ? 1 : 0,\n      });\n    });\n\n    return { hasFailures, addonResults };\n  }\n}\n\nexport const executeAddonConfiguration = ({\n  packageManager,\n  options,\n  ...rest\n}: ExecuteAddonConfigurationParams & {\n  packageManager: JsPackageManager;\n  options: CommandOptions;\n}) => {\n  return new AddonConfigurationCommand(packageManager, options).execute(rest);\n};\n"
  },
  {
    "path": "code/lib/create-storybook/src/commands/DependencyInstallationCommand.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { JsPackageManager } from 'storybook/internal/common';\nimport { Feature } from 'storybook/internal/types';\n\nimport { DependencyCollector } from '../dependency-collector.ts';\nimport { DependencyInstallationCommand } from './DependencyInstallationCommand.ts';\n\ndescribe('DependencyInstallationCommand', () => {\n  let command: DependencyInstallationCommand;\n  const mockPackageManager = {\n    addDependencies: vi.fn().mockResolvedValue(undefined),\n    installDependencies: vi.fn().mockResolvedValue(undefined),\n  } as Partial<JsPackageManager> as JsPackageManager;\n  let dependencyCollector: DependencyCollector;\n\n  beforeEach(async () => {\n    dependencyCollector = new DependencyCollector();\n    command = new DependencyInstallationCommand(dependencyCollector, mockPackageManager);\n\n    vi.clearAllMocks();\n  });\n\n  describe('execute', () => {\n    it('should install dependencies when collector has packages', async () => {\n      dependencyCollector.addDevDependencies(['storybook@8.0.0']);\n\n      await command.execute({\n        skipInstall: false,\n        selectedFeatures: new Set([Feature.TEST]),\n      });\n\n      expect(mockPackageManager.addDependencies).toHaveBeenCalledWith(\n        { type: 'devDependencies', skipInstall: true },\n        ['storybook@8.0.0']\n      );\n      expect(mockPackageManager.installDependencies).toHaveBeenCalled();\n    });\n\n    it('should skip installation when skipInstall is true and no packages', async () => {\n      await command.execute({\n        skipInstall: true,\n        selectedFeatures: new Set([Feature.TEST]),\n      });\n\n      expect(mockPackageManager.addDependencies).not.toHaveBeenCalled();\n      expect(mockPackageManager.installDependencies).not.toHaveBeenCalled();\n    });\n\n    it('should install packages even when skipInstall is true if packages exist', async () => {\n      dependencyCollector.addDevDependencies(['storybook@8.0.0']);\n\n      await command.execute({\n        skipInstall: true,\n        selectedFeatures: new Set([Feature.TEST]),\n      });\n\n      expect(mockPackageManager.addDependencies).toHaveBeenCalledWith(\n        { type: 'devDependencies', skipInstall: true },\n        ['storybook@8.0.0']\n      );\n      expect(mockPackageManager.installDependencies).not.toHaveBeenCalled();\n    });\n\n    it('should pass skipInstall flag to package manager service', async () => {\n      dependencyCollector.addDependencies(['react@18.0.0']);\n\n      await command.execute({\n        skipInstall: true,\n        selectedFeatures: new Set([Feature.TEST]),\n      });\n\n      expect(mockPackageManager.addDependencies).toHaveBeenCalledWith(\n        { type: 'dependencies', skipInstall: true },\n        ['react@18.0.0']\n      );\n      expect(mockPackageManager.installDependencies).not.toHaveBeenCalled();\n    });\n\n    it('should throw error if installation fails', async () => {\n      dependencyCollector.addDevDependencies(['storybook@8.0.0']);\n      const error = new Error('Installation failed');\n      vi.mocked(mockPackageManager.addDependencies).mockRejectedValue(error);\n\n      await expect(\n        command.execute({\n          skipInstall: false,\n          selectedFeatures: new Set([Feature.TEST]),\n        })\n      ).rejects.toThrow('Installation failed');\n    });\n\n    it('should handle empty dependency collector', async () => {\n      await command.execute({\n        skipInstall: false,\n        selectedFeatures: new Set([Feature.TEST]),\n      });\n\n      expect(mockPackageManager.addDependencies).not.toHaveBeenCalled();\n      expect(mockPackageManager.installDependencies).not.toHaveBeenCalled();\n    });\n\n    it('should not collect test dependencies if test feature is not selected', async () => {\n      await command.execute({\n        skipInstall: false,\n        selectedFeatures: new Set([Feature.DOCS]),\n      });\n\n      expect(dependencyCollector.getAllPackages()).not.toContain('vitest');\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/commands/DependencyInstallationCommand.ts",
    "content": "import { AddonVitestService } from 'storybook/internal/cli';\nimport type { JsPackageManager } from 'storybook/internal/common';\nimport { logger, prompt } from 'storybook/internal/node-logger';\nimport { ErrorCollector } from 'storybook/internal/telemetry';\nimport { Feature } from 'storybook/internal/types';\n\nimport type { DependencyCollector } from '../dependency-collector.ts';\n\ntype DependencyInstallationCommandParams = {\n  skipInstall: boolean;\n  selectedFeatures: Set<Feature>;\n};\n\n/**\n * Command for installing all collected dependencies\n *\n * Responsibilities:\n *\n * - Update package.json with all dependencies\n * - Run single installation operation\n * - Handle skipInstall option\n */\nexport class DependencyInstallationCommand {\n  constructor(\n    private readonly dependencyCollector: DependencyCollector,\n    private readonly packageManager: JsPackageManager,\n    private readonly addonVitestService = new AddonVitestService(packageManager)\n  ) {}\n  /** Execute dependency installation */\n  async execute({\n    skipInstall = false,\n    selectedFeatures,\n  }: DependencyInstallationCommandParams): Promise<{ status: 'success' | 'failed' }> {\n    await this.collectAddonDependencies(selectedFeatures);\n\n    if (!this.dependencyCollector.hasPackages() && skipInstall) {\n      return { status: 'success' };\n    }\n\n    const { dependencies, devDependencies } = this.dependencyCollector.getAllPackages();\n\n    const task = prompt.taskLog({\n      id: 'adding-dependencies',\n      title: 'Adding dependencies to package.json',\n    });\n\n    if (dependencies.length > 0) {\n      task.message('Adding dependencies:\\n' + dependencies.map((dep) => `- ${dep}`).join('\\n'));\n\n      await this.packageManager.addDependencies(\n        { type: 'dependencies', skipInstall: true },\n        dependencies\n      );\n    }\n\n    if (devDependencies.length > 0) {\n      task.message(\n        'Adding devDependencies:\\n' + devDependencies.map((dep) => `- ${dep}`).join('\\n')\n      );\n\n      await this.packageManager.addDependencies(\n        { type: 'devDependencies', skipInstall: true },\n        devDependencies\n      );\n    }\n\n    task.success('Dependencies added to package.json', { showLog: true });\n\n    if (!skipInstall && this.dependencyCollector.hasPackages()) {\n      try {\n        await this.packageManager.installDependencies();\n      } catch (err) {\n        ErrorCollector.addError(err);\n        return { status: 'failed' };\n      }\n    }\n\n    return { status: 'success' };\n  }\n\n  /** Collect addon dependencies without installing them */\n  private async collectAddonDependencies(selectedFeatures: Set<Feature>): Promise<void> {\n    try {\n      if (selectedFeatures.has(Feature.TEST)) {\n        const vitestDeps = await this.addonVitestService.collectDependencies();\n        this.dependencyCollector.addDevDependencies(vitestDeps);\n      }\n    } catch (err) {\n      logger.warn(`Failed to collect addon dependencies: ${err}`);\n    }\n  }\n}\n\nexport const executeDependencyInstallation = ({\n  dependencyCollector,\n  packageManager,\n  ...props\n}: DependencyInstallationCommandParams & {\n  dependencyCollector: DependencyCollector;\n  packageManager: JsPackageManager;\n}) => new DependencyInstallationCommand(dependencyCollector, packageManager).execute(props);\n"
  },
  {
    "path": "code/lib/create-storybook/src/commands/FinalizationCommand.test.ts",
    "content": "import fs from 'node:fs/promises';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { getProjectRoot } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport * as find from 'empathic/find';\n\nimport { FinalizationCommand } from './FinalizationCommand.ts';\n\nvi.mock('node:fs/promises', { spy: true });\nvi.mock('storybook/internal/common', { spy: true });\nvi.mock('storybook/internal/node-logger', { spy: true });\nvi.mock('empathic/find', { spy: true });\n\ndescribe('FinalizationCommand', () => {\n  let command: FinalizationCommand;\n\n  beforeEach(() => {\n    command = new FinalizationCommand(undefined);\n\n    vi.mocked(getProjectRoot).mockReturnValue('/test/project');\n    vi.mocked(logger.step).mockImplementation(() => {});\n    vi.mocked(logger.log).mockImplementation(() => {});\n    vi.mocked(logger.outro).mockImplementation(() => {});\n\n    vi.clearAllMocks();\n  });\n\n  describe('execute', () => {\n    it('should update gitignore and print success message', async () => {\n      vi.mocked(find.up).mockReturnValue('/test/project/.gitignore');\n      vi.mocked(fs.readFile).mockResolvedValue('node_modules/\\n');\n      vi.mocked(fs.appendFile).mockResolvedValue(undefined);\n\n      await command.execute({\n        storybookCommand: 'npm run storybook',\n      });\n\n      expect(fs.appendFile).toHaveBeenCalledWith(\n        '/test/project/.gitignore',\n        '\\n*storybook.log\\nstorybook-static\\n'\n      );\n      expect(logger.step).toHaveBeenCalledWith(expect.stringContaining('successfully installed'));\n      expect(logger.log).toHaveBeenCalledWith(expect.stringContaining('npm run storybook'));\n      expect(logger.log).toHaveBeenCalledWith(expect.stringContaining('storybook.js.org'));\n    });\n\n    it('should not update gitignore if file not found', async () => {\n      vi.mocked(find.up).mockReturnValue(undefined);\n\n      await command.execute({\n        storybookCommand: 'yarn storybook',\n      });\n\n      expect(fs.readFile).not.toHaveBeenCalled();\n      expect(fs.appendFile).not.toHaveBeenCalled();\n      expect(logger.step).toHaveBeenCalled();\n    });\n\n    it('should not update gitignore if file is outside project root', async () => {\n      vi.mocked(find.up).mockReturnValue('/other/path/.gitignore');\n      vi.mocked(getProjectRoot).mockReturnValue('/test/project');\n\n      await command.execute({\n        storybookCommand: 'npm run storybook',\n      });\n\n      expect(fs.readFile).not.toHaveBeenCalled();\n      expect(fs.appendFile).not.toHaveBeenCalled();\n    });\n\n    it('should not add entries that already exist in gitignore', async () => {\n      vi.mocked(find.up).mockReturnValue('/test/project/.gitignore');\n      vi.mocked(fs.readFile).mockResolvedValue('node_modules/\\n*storybook.log\\nstorybook-static\\n');\n\n      await command.execute({\n        storybookCommand: 'npm run storybook',\n      });\n\n      expect(fs.appendFile).not.toHaveBeenCalled();\n    });\n\n    it('should add only missing entries to gitignore', async () => {\n      vi.mocked(find.up).mockReturnValue('/test/project/.gitignore');\n      vi.mocked(fs.readFile).mockResolvedValue('node_modules/\\n*storybook.log\\n');\n      vi.mocked(fs.appendFile).mockResolvedValue(undefined);\n\n      await command.execute({\n        storybookCommand: 'npm run storybook',\n      });\n\n      expect(fs.appendFile).toHaveBeenCalledWith(\n        '/test/project/.gitignore',\n        '\\nstorybook-static\\n'\n      );\n    });\n\n    it('should include storybook command in output', async () => {\n      vi.mocked(find.up).mockReturnValue(undefined);\n\n      await command.execute({\n        storybookCommand: 'ng run my-app:storybook',\n      });\n\n      expect(logger.log).toHaveBeenCalledWith(expect.stringContaining('ng run my-app:storybook'));\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/commands/FinalizationCommand.ts",
    "content": "import fs from 'node:fs/promises';\n\nimport { getProjectRoot } from 'storybook/internal/common';\nimport { CLI_COLORS, logTracker, logger } from 'storybook/internal/node-logger';\nimport { ErrorCollector } from 'storybook/internal/telemetry';\n\nimport * as find from 'empathic/find';\nimport { dedent } from 'ts-dedent';\n\ntype ExecuteFinalizationParams = {\n  storybookCommand?: string | null;\n};\n\n/**\n * Command for finalizing Storybook installation\n *\n * Responsibilities:\n *\n * - Update .gitignore with Storybook entries\n * - Print success message\n * - Display feature summary\n * - Show next steps\n */\nexport class FinalizationCommand {\n  constructor(private logfile: string | boolean | undefined) {}\n  /** Execute finalization steps */\n  async execute({ storybookCommand }: ExecuteFinalizationParams): Promise<void> {\n    // Update .gitignore\n    await this.updateGitignore();\n\n    const errors = ErrorCollector.getErrors();\n\n    if (errors.length > 0) {\n      await this.printFailureMessage(storybookCommand);\n    } else {\n      this.printSuccessMessage(storybookCommand);\n    }\n  }\n\n  /** Update .gitignore with Storybook-specific entries */\n  private async updateGitignore(): Promise<void> {\n    const foundGitIgnoreFile = find.up('.gitignore');\n    const rootDirectory = getProjectRoot();\n\n    if (!foundGitIgnoreFile || !foundGitIgnoreFile.includes(rootDirectory)) {\n      return;\n    }\n\n    const contents = await fs.readFile(foundGitIgnoreFile, 'utf-8');\n    const hasStorybookLog = contents.includes('*storybook.log');\n    const hasStorybookStatic = contents.includes('storybook-static');\n\n    const linesToAdd = [\n      !hasStorybookLog ? '*storybook.log' : '',\n      !hasStorybookStatic ? 'storybook-static' : '',\n    ]\n      .filter(Boolean)\n      .join('\\n');\n\n    if (linesToAdd) {\n      await fs.appendFile(foundGitIgnoreFile, `\\n${linesToAdd}\\n`);\n    }\n  }\n\n  private async printFailureMessage(storybookCommand?: string | null): Promise<void> {\n    logger.warn(\n      'Storybook setup completed, but some non-blocking errors occurred. Please check the log file below for details.'\n    );\n    this.printNextSteps(storybookCommand);\n\n    try {\n      const logFile = await logTracker.writeToFile(this.logfile);\n      logger.warn(`Debug logs are written to: ${logFile}`);\n    } catch {}\n  }\n\n  /** Print success message with feature summary */\n  private printSuccessMessage(storybookCommand?: string | null): void {\n    logger.step(CLI_COLORS.success('Storybook was successfully installed in your project!'));\n    this.printNextSteps(storybookCommand);\n  }\n\n  private printNextSteps(storybookCommand?: string | null): void {\n    if (storybookCommand) {\n      logger.log(\n        `To run Storybook manually, run ${CLI_COLORS.cta(storybookCommand)}. CTRL+C to stop.`\n      );\n    }\n\n    logger.log(dedent`\n      Want to learn more about Storybook? ${CLI_COLORS.cta('https://storybook.js.org/')}\n      Having trouble or want to chat? ${CLI_COLORS.cta('https://discord.gg/storybook/')}\n    `);\n  }\n}\nexport const executeFinalization = ({\n  logfile,\n  ...params\n}: ExecuteFinalizationParams & { logfile: string | boolean | undefined }) => {\n  return new FinalizationCommand(logfile).execute(params);\n};\n"
  },
  {
    "path": "code/lib/create-storybook/src/commands/FrameworkDetectionCommand.ts",
    "content": "import { type ProjectType } from 'storybook/internal/cli';\nimport { type JsPackageManager } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\nimport type { SupportedBuilder } from 'storybook/internal/types';\nimport { type SupportedRenderer } from 'storybook/internal/types';\nimport type { SupportedFramework } from 'storybook/internal/types';\n\nimport { generatorRegistry } from '../generators/GeneratorRegistry.ts';\nimport type { CommandOptions } from '../generators/types.ts';\nimport { FrameworkDetectionService } from '../services/FrameworkDetectionService.ts';\n\nexport interface FrameworkDetectionResult {\n  renderer: SupportedRenderer;\n  builder: SupportedBuilder;\n  framework: SupportedFramework | null;\n}\n\n/**\n * Command for detecting framework, renderer, and builder from ProjectType\n *\n * Uses generator metadata to determine the correct framework and renderer, and detects or uses\n * overridden builder configuration.\n */\nexport class FrameworkDetectionCommand {\n  constructor(\n    packageManager: JsPackageManager,\n    private frameworkDetectionService = new FrameworkDetectionService(packageManager)\n  ) {}\n  async execute(\n    projectType: ProjectType,\n    options: CommandOptions\n  ): Promise<FrameworkDetectionResult> {\n    // Get generator for the project type\n    const generatorModule = generatorRegistry.get(projectType);\n\n    if (!generatorModule) {\n      throw new Error(`No generator found for project type: ${projectType}`);\n    }\n\n    const { metadata } = generatorModule;\n\n    // Determine builder - use override if specified, otherwise detect\n    let builder: SupportedBuilder;\n    if (options.builder) {\n      // CLI option takes precedence\n      builder = options.builder as SupportedBuilder;\n    } else if (metadata.builderOverride) {\n      if (typeof metadata.builderOverride === 'function') {\n        builder = await metadata.builderOverride();\n      } else {\n        builder = metadata.builderOverride;\n      }\n    } else {\n      // Detect builder from project configuration\n      builder = await this.frameworkDetectionService.detectBuilder();\n    }\n\n    // Get framework and renderer from metadata\n    const renderer = metadata.renderer;\n\n    // Handle dynamic framework selection based on builder\n    let framework: SupportedFramework | null;\n    if (metadata.framework !== undefined) {\n      if (typeof metadata.framework === 'function') {\n        framework = metadata.framework(builder);\n      } else {\n        framework = metadata.framework;\n      }\n    } else {\n      framework = this.frameworkDetectionService.detectFramework(renderer, builder);\n    }\n\n    if (framework) {\n      logger.step(`Framework detected: ${framework}`);\n    }\n\n    return {\n      framework,\n      renderer,\n      builder,\n    };\n  }\n}\n\nexport const executeFrameworkDetection = (\n  projectType: ProjectType,\n  packageManager: JsPackageManager,\n  options: CommandOptions\n) => {\n  return new FrameworkDetectionCommand(packageManager).execute(projectType, options);\n};\n"
  },
  {
    "path": "code/lib/create-storybook/src/commands/GeneratorExecutionCommand.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { ProjectType } from 'storybook/internal/cli';\nimport { type JsPackageManager, PackageManagerName } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\nimport {\n  Feature,\n  SupportedBuilder,\n  SupportedFramework,\n  SupportedLanguage,\n  SupportedRenderer,\n} from 'storybook/internal/types';\n\nimport { DependencyCollector } from '../dependency-collector.ts';\nimport { generatorRegistry } from '../generators/GeneratorRegistry.ts';\nimport { baseGenerator } from '../generators/baseGenerator.ts';\nimport { AddonService } from '../services/index.ts';\nimport type { FrameworkDetectionResult } from './FrameworkDetectionCommand.ts';\nimport { GeneratorExecutionCommand } from './GeneratorExecutionCommand.ts';\n\nvi.mock('storybook/internal/node-logger', { spy: true });\nvi.mock('../generators/GeneratorRegistry', { spy: true });\nvi.mock('../generators/baseGenerator', { spy: true });\nvi.mock('../services', { spy: true });\n\ndescribe('GeneratorExecutionCommand', () => {\n  let command: GeneratorExecutionCommand;\n  let mockPackageManager: JsPackageManager;\n  let dependencyCollector: DependencyCollector;\n  let mockGenerator: {\n    metadata: {\n      projectType: ProjectType;\n      renderer: SupportedRenderer;\n      framework?: SupportedFramework;\n    };\n    configure: ReturnType<typeof vi.fn>;\n  };\n  let mockFrameworkInfo: FrameworkDetectionResult;\n  let mockAddonService: { getAddonsForFeatures: ReturnType<typeof vi.fn> };\n\n  beforeEach(() => {\n    dependencyCollector = new DependencyCollector();\n    mockAddonService = {\n      getAddonsForFeatures: vi.fn().mockReturnValue([]),\n    };\n    vi.mocked(AddonService).mockImplementation(function () {\n      return mockAddonService;\n    });\n    mockPackageManager = {\n      getRunCommand: vi.fn().mockReturnValue('npm run storybook'),\n    } as unknown as JsPackageManager;\n\n    command = new GeneratorExecutionCommand(dependencyCollector, mockPackageManager);\n\n    mockFrameworkInfo = {\n      renderer: SupportedRenderer.REACT,\n      builder: SupportedBuilder.VITE,\n      framework: SupportedFramework.REACT_VITE,\n    };\n\n    // Mock new-style generator module\n    mockGenerator = {\n      metadata: {\n        projectType: ProjectType.REACT,\n        renderer: SupportedRenderer.REACT,\n        framework: undefined,\n      },\n      configure: vi.fn().mockResolvedValue({\n        extraPackages: [],\n        extraAddons: [],\n      }),\n    };\n\n    vi.mocked(generatorRegistry.get).mockReturnValue(mockGenerator as any);\n    vi.mocked(logger.warn).mockImplementation(() => {});\n    vi.mocked(baseGenerator).mockResolvedValue({\n      configDir: '.storybook',\n      storybookCommand: undefined,\n      shouldRunDev: undefined,\n    });\n\n    vi.clearAllMocks();\n  });\n\n  describe('execute', () => {\n    it('should execute generator with all features', async () => {\n      const selectedFeatures = new Set([Feature.DOCS, Feature.TEST, Feature.ONBOARDING]);\n      mockAddonService.getAddonsForFeatures.mockReturnValue([\n        '@chromatic-com/storybook',\n        '@storybook/addon-vitest',\n        '@storybook/addon-docs',\n        '@storybook/addon-onboarding',\n      ]);\n      const options = {\n        skipInstall: false,\n        packageManager: PackageManagerName.NPM,\n      };\n\n      await command.execute({\n        projectType: ProjectType.REACT,\n        frameworkInfo: mockFrameworkInfo,\n        language: SupportedLanguage.TYPESCRIPT,\n        options,\n        selectedFeatures,\n      });\n\n      expect(generatorRegistry.get).toHaveBeenCalledWith(ProjectType.REACT);\n      expect(mockGenerator.configure).toHaveBeenCalled();\n      expect(baseGenerator).toHaveBeenCalled();\n      expect(mockAddonService.getAddonsForFeatures).toHaveBeenCalledWith(selectedFeatures);\n    });\n\n    it('should throw error if generator not found', async () => {\n      vi.mocked(generatorRegistry.get).mockReturnValue(undefined);\n      const selectedFeatures = new Set([]);\n      const options = {\n        packageManager: PackageManagerName.NPM,\n      };\n\n      await expect(\n        command.execute({\n          projectType: ProjectType.UNSUPPORTED,\n          frameworkInfo: mockFrameworkInfo,\n          language: SupportedLanguage.TYPESCRIPT,\n          options,\n          selectedFeatures,\n        })\n      ).rejects.toThrow('No generator found for project type');\n    });\n\n    it('should pass correct options to generator', async () => {\n      const selectedFeatures = new Set([Feature.DOCS, Feature.TEST, Feature.A11Y]);\n      mockAddonService.getAddonsForFeatures.mockReturnValue([\n        '@chromatic-com/storybook',\n        '@storybook/addon-vitest',\n        '@storybook/addon-a11y',\n        '@storybook/addon-docs',\n      ]);\n      const options = {\n        skipInstall: true,\n        builder: SupportedBuilder.VITE,\n        linkable: true,\n        usePnp: true,\n        yes: true,\n        packageManager: PackageManagerName.NPM,\n      };\n\n      await command.execute({\n        projectType: ProjectType.VUE3,\n        frameworkInfo: mockFrameworkInfo,\n        language: SupportedLanguage.TYPESCRIPT,\n        options,\n        selectedFeatures,\n      });\n\n      expect(mockGenerator.configure).toHaveBeenCalledWith(\n        mockPackageManager,\n        expect.objectContaining({\n          framework: mockFrameworkInfo.framework,\n          renderer: mockFrameworkInfo.renderer,\n          builder: mockFrameworkInfo.builder,\n          features: selectedFeatures,\n        })\n      );\n\n      expect(baseGenerator).toHaveBeenCalledWith(\n        mockPackageManager,\n        { type: 'devDependencies', skipInstall: true },\n        expect.objectContaining({\n          builder: SupportedBuilder.VITE,\n          linkable: true,\n          pnp: true,\n          yes: true,\n          projectType: ProjectType.VUE3,\n          features: expect.any(Set),\n          dependencyCollector: expect.any(Object),\n        }),\n        expect.objectContaining({\n          extraAddons: expect.arrayContaining([\n            '@chromatic-com/storybook',\n            '@storybook/addon-vitest',\n            '@storybook/addon-a11y',\n            '@storybook/addon-docs',\n          ]),\n          extraPackages: [],\n        })\n      );\n      expect(mockAddonService.getAddonsForFeatures).toHaveBeenCalledWith(selectedFeatures);\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/commands/GeneratorExecutionCommand.ts",
    "content": "import type { ProjectType } from 'storybook/internal/cli';\nimport { type JsPackageManager } from 'storybook/internal/common';\nimport { type Feature, type SupportedLanguage } from 'storybook/internal/types';\n\nimport type { DependencyCollector } from '../dependency-collector.ts';\nimport { generatorRegistry } from '../generators/GeneratorRegistry.ts';\nimport { baseGenerator } from '../generators/baseGenerator.ts';\nimport type { CommandOptions, GeneratorModule, GeneratorOptions } from '../generators/types.ts';\nimport { AddonService } from '../services/index.ts';\nimport type { FrameworkDetectionResult } from './FrameworkDetectionCommand.ts';\n\ntype ExecuteProjectGeneratorOptions = {\n  projectType: ProjectType;\n  language: SupportedLanguage;\n  frameworkInfo: FrameworkDetectionResult;\n  options: CommandOptions;\n  selectedFeatures: Set<Feature>;\n};\n\n/**\n * Command for executing the project-specific generator\n *\n * Responsibilities:\n *\n * - Get generator module from registry\n * - Call generator's configure() to get framework-specific options\n * - Execute baseGenerator with complete configuration\n * - Determine Storybook command\n */\nexport class GeneratorExecutionCommand {\n  /** Execute generator for the detected project type */\n  constructor(\n    private readonly dependencyCollector: DependencyCollector,\n    private readonly jsPackageManager: JsPackageManager,\n    private readonly addonService = new AddonService()\n  ) {}\n\n  async execute({\n    projectType,\n    options,\n    frameworkInfo,\n    selectedFeatures,\n    language,\n  }: ExecuteProjectGeneratorOptions) {\n    // Get and execute generator (supports both old and new style)\n    const generatorResult = await this.executeProjectGenerator({\n      projectType,\n      frameworkInfo,\n      options,\n      selectedFeatures,\n      language,\n    });\n\n    // Determine Storybook command\n\n    return {\n      ...generatorResult,\n      configDir: 'configDir' in generatorResult ? generatorResult.configDir : undefined,\n      storybookCommand:\n        generatorResult.storybookCommand !== undefined\n          ? generatorResult.storybookCommand\n          : this.jsPackageManager.getRunCommand('storybook'),\n    };\n  }\n\n  /** Execute the project-specific generator */\n  private readonly executeProjectGenerator = async ({\n    projectType,\n    frameworkInfo,\n    options,\n    selectedFeatures,\n    language,\n  }: ExecuteProjectGeneratorOptions) => {\n    const generator = generatorRegistry.get(projectType);\n\n    if (!generator) {\n      throw new Error(`No generator found for project type: ${projectType}`);\n    }\n\n    const npmOptions = {\n      type: 'devDependencies' as const,\n      skipInstall: options.skipInstall,\n    };\n\n    // All generators must be new-style modules with metadata + configure\n    const generatorModule = generator as GeneratorModule;\n\n    // Call configure function to get framework-specific options\n    const frameworkOptions = await generatorModule.configure(this.jsPackageManager, {\n      framework: frameworkInfo.framework,\n      renderer: frameworkInfo.renderer,\n      builder: frameworkInfo.builder,\n      language,\n      linkable: !!options.linkable,\n      features: selectedFeatures,\n      dependencyCollector: this.dependencyCollector,\n      yes: options.yes,\n    });\n\n    const generatorOptions = {\n      language,\n      builder: frameworkInfo.builder,\n      framework: frameworkInfo.framework,\n      renderer: frameworkInfo.renderer,\n      linkable: !!options.linkable,\n      pnp: !!options.usePnp,\n      yes: !!options.yes,\n      projectType,\n      features: selectedFeatures,\n      dependencyCollector: this.dependencyCollector,\n    } as GeneratorOptions;\n\n    if (frameworkOptions.skipGenerator) {\n      if (generatorModule.postConfigure) {\n        await generatorModule.postConfigure({ packageManager: this.jsPackageManager });\n      }\n\n      return {\n        shouldRunDev: frameworkOptions.shouldRunDev,\n        storybookCommand: frameworkOptions.storybookCommand,\n        extraAddons: [],\n      };\n    }\n\n    const extraAddons = this.addonService.getAddonsForFeatures(selectedFeatures);\n\n    // Call baseGenerator with complete configuration\n    const generatorResult = await baseGenerator(\n      this.jsPackageManager,\n      npmOptions,\n      generatorOptions,\n      {\n        ...frameworkOptions,\n        extraAddons: [...(frameworkOptions.extraAddons ?? []), ...extraAddons],\n      }\n    );\n\n    if (generatorModule.postConfigure) {\n      await generatorModule.postConfigure({ packageManager: this.jsPackageManager });\n    }\n\n    return {\n      ...generatorResult,\n      extraAddons,\n    };\n  };\n}\n\nexport const executeGeneratorExecution = ({\n  dependencyCollector,\n  packageManager,\n  ...options\n}: ExecuteProjectGeneratorOptions & {\n  dependencyCollector: DependencyCollector;\n  packageManager: JsPackageManager;\n}) => {\n  return new GeneratorExecutionCommand(dependencyCollector, packageManager).execute(options);\n};\n"
  },
  {
    "path": "code/lib/create-storybook/src/commands/PreflightCheckCommand.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport {\n  JsPackageManagerFactory,\n  PackageManagerName,\n  invalidateProjectRootCache,\n} from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport * as scaffoldModule from '../scaffold-new-project.ts';\nimport { PreflightCheckCommand } from './PreflightCheckCommand.ts';\n\nvi.mock('storybook/internal/common', { spy: true });\nvi.mock('../scaffold-new-project', { spy: true });\nvi.mock('storybook/internal/node-logger', { spy: true });\n\ndescribe('PreflightCheckCommand', () => {\n  let command: PreflightCheckCommand;\n  let mockPackageManager: any;\n\n  beforeEach(() => {\n    command = new PreflightCheckCommand();\n    mockPackageManager = {\n      installDependencies: vi.fn(),\n      latestVersion: vi.fn().mockResolvedValue('8.0.0'),\n      type: PackageManagerName.NPM,\n      primaryPackageJson: { packageJson: { name: 'my-app' } },\n    };\n\n    vi.mocked(JsPackageManagerFactory.getPackageManager).mockReturnValue(mockPackageManager);\n    vi.mocked(JsPackageManagerFactory.getPackageManagerType).mockReturnValue(\n      PackageManagerName.NPM\n    );\n    vi.mocked(scaffoldModule.scaffoldNewProject).mockResolvedValue(undefined);\n    vi.mocked(invalidateProjectRootCache).mockImplementation(() => {});\n    vi.clearAllMocks();\n  });\n\n  describe('execute', () => {\n    it('should return package manager for non-empty directory', async () => {\n      vi.mocked(scaffoldModule.currentDirectoryIsEmpty).mockReturnValue(false);\n\n      const result = await command.execute({ force: false } as any);\n\n      expect(result.packageManager).toBe(mockPackageManager);\n      expect(result.isEmptyProject).toBe(false);\n      expect(scaffoldModule.scaffoldNewProject).not.toHaveBeenCalled();\n      expect(mockPackageManager.installDependencies).not.toHaveBeenCalled();\n    });\n\n    it('should scaffold new project when directory is empty', async () => {\n      vi.mocked(scaffoldModule.currentDirectoryIsEmpty).mockReturnValue(true);\n\n      const result = await command.execute({ force: false, skipInstall: true } as any);\n\n      expect(scaffoldModule.scaffoldNewProject).toHaveBeenCalledWith('npm', {\n        force: false,\n        skipInstall: true,\n      });\n      expect(invalidateProjectRootCache).toHaveBeenCalled();\n      expect(result.isEmptyProject).toBe(true);\n    });\n\n    it('should install dependencies for empty project when not skipping install', async () => {\n      vi.mocked(scaffoldModule.currentDirectoryIsEmpty).mockReturnValue(true);\n\n      await command.execute({ force: false, skipInstall: false } as any);\n\n      expect(mockPackageManager.installDependencies).toHaveBeenCalled();\n    });\n\n    it('should not install dependencies when skipInstall is true', async () => {\n      vi.mocked(scaffoldModule.currentDirectoryIsEmpty).mockReturnValue(true);\n\n      await command.execute({ force: false, skipInstall: true } as any);\n\n      expect(mockPackageManager.installDependencies).not.toHaveBeenCalled();\n    });\n\n    it('should use npm instead of yarn1 for empty directory', async () => {\n      vi.mocked(scaffoldModule.currentDirectoryIsEmpty).mockReturnValue(true);\n      vi.mocked(JsPackageManagerFactory.getPackageManagerType).mockReturnValue(\n        PackageManagerName.YARN1\n      );\n\n      await command.execute({ force: false, skipInstall: true } as any);\n\n      expect(scaffoldModule.scaffoldNewProject).toHaveBeenCalledWith('npm', expect.any(Object));\n    });\n\n    it('should skip scaffolding when force is true', async () => {\n      vi.mocked(scaffoldModule.currentDirectoryIsEmpty).mockReturnValue(true);\n\n      const result = await command.execute({ force: true } as any);\n\n      expect(scaffoldModule.scaffoldNewProject).not.toHaveBeenCalled();\n      expect(result.isEmptyProject).toBe(false);\n    });\n\n    it('should use provided package manager', async () => {\n      vi.mocked(scaffoldModule.currentDirectoryIsEmpty).mockReturnValue(false);\n\n      await command.execute({ packageManager: 'yarn' } as any);\n\n      expect(JsPackageManagerFactory.getPackageManager).toHaveBeenCalledWith({\n        force: 'yarn',\n      });\n    });\n\n    it('should warn when package.json name is \"storybook\"', async () => {\n      vi.mocked(scaffoldModule.currentDirectoryIsEmpty).mockReturnValue(false);\n      mockPackageManager.primaryPackageJson = { packageJson: { name: 'storybook' } };\n\n      await command.execute({ force: false } as any);\n\n      expect(vi.mocked(logger.warn)).toHaveBeenCalledWith(\n        expect.stringContaining('Your package.json \"name\" field is set to \"storybook\"')\n      );\n    });\n\n    it('should not warn when package.json name is not \"storybook\"', async () => {\n      vi.mocked(scaffoldModule.currentDirectoryIsEmpty).mockReturnValue(false);\n      mockPackageManager.primaryPackageJson = { packageJson: { name: 'my-project' } };\n\n      await command.execute({ force: false } as any);\n\n      expect(vi.mocked(logger.warn)).not.toHaveBeenCalledWith(\n        expect.stringContaining('Your package.json \"name\" field is set to \"storybook\"')\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/commands/PreflightCheckCommand.ts",
    "content": "import { detectPnp } from 'storybook/internal/cli';\nimport {\n  type JsPackageManager,\n  JsPackageManagerFactory,\n  PackageManagerName,\n  invalidateProjectRootCache,\n} from 'storybook/internal/common';\nimport { CLI_COLORS, deprecate, logger } from 'storybook/internal/node-logger';\n\nimport { dedent } from 'ts-dedent';\n\nimport type { CommandOptions } from '../generators/types.ts';\nimport { currentDirectoryIsEmpty, scaffoldNewProject } from '../scaffold-new-project.ts';\nimport { VersionService } from '../services/index.ts';\n\nexport interface PreflightCheckResult {\n  packageManager: JsPackageManager;\n  isEmptyProject: boolean;\n}\n\n/**\n * Command for running preflight checks before Storybook initialization\n *\n * Responsibilities:\n *\n * - Handle empty directory detection and scaffolding\n * - Initialize package manager\n * - Install base dependencies if needed\n */\nexport class PreflightCheckCommand {\n  /** Execute preflight checks */\n  constructor(private readonly versionService = new VersionService()) {}\n  async execute(options: CommandOptions): Promise<PreflightCheckResult> {\n    const isEmptyDirProject = options.force !== true && currentDirectoryIsEmpty();\n    let packageManagerType = JsPackageManagerFactory.getPackageManagerType();\n\n    // Check if the current directory is empty\n    if (isEmptyDirProject) {\n      // Initializing Storybook in an empty directory with yarn1\n      // will very likely fail due to different kinds of hoisting issues\n      // which doesn't get fixed anymore in yarn1.\n      // We will fallback to npm in this case.\n      if (\n        options.packageManager\n          ? options.packageManager === PackageManagerName.YARN1\n          : packageManagerType === PackageManagerName.YARN1\n      ) {\n        logger.warn('Empty directory with yarn1 is unsupported. Falling back to npm.');\n        packageManagerType = PackageManagerName.NPM;\n        options.packageManager = packageManagerType;\n      }\n\n      // Prompt the user to create a new project from our list\n      logger.intro(CLI_COLORS.info(`Initializing a new project`));\n      await scaffoldNewProject(packageManagerType, options);\n      logger.outro(CLI_COLORS.info(`Project created successfully`));\n      invalidateProjectRootCache();\n    }\n\n    logger.intro(CLI_COLORS.info(`Initializing Storybook`));\n\n    const packageManager = JsPackageManagerFactory.getPackageManager({\n      force: options.packageManager,\n    });\n\n    // Install base project dependencies if we scaffolded a new project\n    if (isEmptyDirProject && !options.skipInstall) {\n      await packageManager.installDependencies();\n    }\n\n    const pnp = await detectPnp();\n    if (pnp) {\n      deprecate(dedent`\n        As of Storybook 10.0, PnP is deprecated. \n        If you are using PnP, you can continue to use Storybook 10.0, but we recommend migrating to a different package manager or linker-mode. In future versions, PnP compatibility will be removed.\n    `);\n    }\n\n    this.checkPackageNameConflict(packageManager);\n\n    await this.displayVersionInfo(packageManager);\n\n    return { packageManager, isEmptyProject: isEmptyDirProject };\n  }\n\n  /**\n   * Warn when the project's package.json \"name\" is \"storybook\", which shadows\n   * the real storybook package in workspaces.\n   *\n   * See: https://github.com/storybookjs/storybook/issues/28725\n   */\n  private checkPackageNameConflict(packageManager: JsPackageManager): void {\n    const packageName = packageManager.primaryPackageJson.packageJson.name;\n\n    if (packageName === 'storybook') {\n      logger.warn(dedent`\n        Your package.json \"name\" field is set to \"storybook\".\n\n        In npm, pnpm, or yarn workspaces this creates a symlink at\n        node_modules/storybook that shadows the real Storybook package,\n        causing \"Cannot find module storybook/internal/...\" errors.\n\n        Please rename the \"name\" field in your package.json to something\n        other than \"storybook\" (e.g. \"my-storybook\", \"docs\", \"@myorg/storybook\").\n      `);\n    }\n  }\n\n  /** Display version information and warnings */\n  private async displayVersionInfo(packageManager: JsPackageManager): Promise<void> {\n    const { currentVersion, latestVersion, isPrerelease, isOutdated } =\n      await this.versionService.getVersionInfo(packageManager);\n\n    if (isOutdated && !isPrerelease) {\n      logger.warn(dedent`\n          This version is behind the latest release, which is: ${latestVersion}!\n          You likely ran the init command through npx, which can use a locally cached version.\n          \n          To get the latest, please run: ${CLI_COLORS.cta('npx storybook@latest init')}\n          You may want to ${CLI_COLORS.cta('CTRL+C')} to stop, and run with the latest version instead.\n        `);\n    } else if (isPrerelease) {\n      logger.warn(`This is a pre-release version: ${currentVersion}`);\n    } else {\n      logger.info(`Adding Storybook version ${currentVersion} to your project`);\n    }\n  }\n}\n\nexport const executePreflightCheck = async (\n  options: CommandOptions\n): Promise<PreflightCheckResult> => {\n  const command = new PreflightCheckCommand();\n  return command.execute(options);\n};\n"
  },
  {
    "path": "code/lib/create-storybook/src/commands/ProjectDetectionCommand.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { ProjectType } from 'storybook/internal/cli';\nimport type { JsPackageManager } from 'storybook/internal/common';\nimport { HandledError, PackageManagerName } from 'storybook/internal/common';\nimport { logger, prompt } from 'storybook/internal/node-logger';\nimport type { Feature } from 'storybook/internal/types';\nimport { SupportedLanguage } from 'storybook/internal/types';\n\nimport type { CommandOptions } from '../generators/types.ts';\nimport { ProjectTypeService } from '../services/ProjectTypeService.ts';\nimport { ProjectDetectionCommand } from './ProjectDetectionCommand.ts';\n\nvi.mock('storybook/internal/common', { spy: true });\nvi.mock('storybook/internal/node-logger', { spy: true });\nvi.mock('../services/ProjectTypeService', { spy: true });\n\ndescribe('ProjectDetectionCommand', () => {\n  let command: ProjectDetectionCommand;\n  let mockPackageManager: JsPackageManager;\n  let mockProjectTypeService: {\n    validateProvidedType: ReturnType<typeof vi.fn>;\n    autoDetectProjectType: ReturnType<typeof vi.fn>;\n    isStorybookInstantiated: ReturnType<typeof vi.fn>;\n    detectLanguage: ReturnType<typeof vi.fn>;\n  };\n  let options: CommandOptions;\n\n  beforeEach(() => {\n    mockPackageManager = {\n      primaryPackageJson: { packageJson: {} },\n    } as unknown as JsPackageManager;\n\n    mockProjectTypeService = {\n      validateProvidedType: vi.fn(),\n      autoDetectProjectType: vi.fn(),\n      isStorybookInstantiated: vi.fn().mockReturnValue(false),\n      detectLanguage: vi.fn().mockResolvedValue(SupportedLanguage.JAVASCRIPT),\n    };\n\n    vi.mocked(ProjectTypeService).mockImplementation(function () {\n      return mockProjectTypeService;\n    });\n\n    options = {\n      packageManager: PackageManagerName.NPM,\n      features: undefined as unknown as Array<Feature>,\n    };\n\n    command = new ProjectDetectionCommand(options, mockPackageManager);\n\n    // Mock HandledError constructor\n    vi.mocked(HandledError).mockImplementation(\n      class MockHandledError extends Error {\n        constructor(message: string) {\n          super(message);\n          this.name = 'HandledError';\n        }\n      } as any\n    );\n\n    vi.mocked(logger.step).mockImplementation(() => {});\n    vi.mocked(logger.error).mockImplementation(() => {});\n    vi.mocked(logger.debug).mockImplementation(() => {});\n    vi.mocked(logger.warn).mockImplementation(() => {});\n\n    vi.clearAllMocks();\n  });\n\n  describe('execute', () => {\n    it('should use provided project type when valid', async () => {\n      options.type = ProjectType.REACT;\n      vi.mocked(mockProjectTypeService.validateProvidedType).mockResolvedValue(ProjectType.REACT);\n\n      const result = await command.execute();\n\n      expect(result.projectType).toBe(ProjectType.REACT);\n      expect(mockProjectTypeService.validateProvidedType).toHaveBeenCalledWith(ProjectType.REACT);\n      expect(logger.step).toHaveBeenCalledWith(\n        'Installing Storybook for user specified project type: react'\n      );\n      expect(mockProjectTypeService.autoDetectProjectType).not.toHaveBeenCalled();\n    });\n\n    it('should auto-detect project type when not provided', async () => {\n      options.type = undefined;\n      vi.mocked(mockProjectTypeService.autoDetectProjectType).mockResolvedValue(ProjectType.VUE3);\n\n      const result = await command.execute();\n\n      expect(result.projectType).toBe(ProjectType.VUE3);\n      expect(mockProjectTypeService.autoDetectProjectType).toHaveBeenCalledWith(options);\n      expect(logger.debug).toHaveBeenCalledWith('Project type detected: vue3');\n    });\n\n    it('should throw error for invalid provided type', async () => {\n      options.type = ProjectType.UNSUPPORTED;\n      const error = new HandledError('Unknown project type supplied: unsupported');\n      vi.mocked(mockProjectTypeService.validateProvidedType).mockImplementation(async () => {\n        logger.error(\n          `The provided project type ${ProjectType.UNSUPPORTED} was not recognized by Storybook`\n        );\n        throw error;\n      });\n\n      await expect(command.execute()).rejects.toThrow(HandledError);\n\n      expect(logger.error).toHaveBeenCalledWith(\n        'The provided project type unsupported was not recognized by Storybook'\n      );\n    });\n\n    it('should prompt for React Native variant when detected', async () => {\n      options.type = undefined;\n      options.yes = false;\n      vi.mocked(mockProjectTypeService.autoDetectProjectType).mockResolvedValue(\n        ProjectType.REACT_NATIVE\n      );\n      vi.mocked(prompt.select).mockResolvedValue(ProjectType.REACT_NATIVE_WEB);\n\n      const result = await command.execute();\n\n      expect(result.projectType).toBe(ProjectType.REACT_NATIVE_WEB);\n      expect(prompt.select).toHaveBeenCalledWith(\n        expect.objectContaining({\n          message: \"We've detected a React Native project. Install:\",\n        })\n      );\n    });\n\n    it('should not prompt for React Native variant when yes flag is set', async () => {\n      options.type = undefined;\n      options.yes = true;\n      vi.mocked(mockProjectTypeService.autoDetectProjectType).mockResolvedValue(\n        ProjectType.REACT_NATIVE\n      );\n\n      const result = await command.execute();\n\n      expect(result.projectType).toBe(ProjectType.REACT_NATIVE);\n      expect(prompt.select).not.toHaveBeenCalled();\n    });\n\n    it('should handle all React Native variants', async () => {\n      options.type = undefined;\n      vi.mocked(mockProjectTypeService.autoDetectProjectType).mockResolvedValue(\n        ProjectType.REACT_NATIVE\n      );\n      vi.mocked(prompt.select).mockResolvedValue(ProjectType.REACT_NATIVE_AND_RNW);\n\n      const result = await command.execute();\n\n      expect(result.projectType).toBe(ProjectType.REACT_NATIVE_AND_RNW);\n    });\n\n    it('should check for existing Storybook installation', async () => {\n      options.type = undefined;\n      options.force = false;\n      vi.mocked(mockProjectTypeService.autoDetectProjectType).mockResolvedValue(ProjectType.REACT);\n      vi.mocked(mockProjectTypeService.isStorybookInstantiated).mockReturnValue(true);\n      vi.mocked(prompt.confirm).mockResolvedValue(true);\n\n      await command.execute();\n\n      expect(mockProjectTypeService.isStorybookInstantiated).toHaveBeenCalled();\n      expect(prompt.confirm).toHaveBeenCalledWith(\n        expect.objectContaining({\n          message: expect.stringContaining('already instantiated'),\n        })\n      );\n      expect(options.force).toBe(true);\n    });\n\n    it('should exit if user declines to force install', async () => {\n      options.type = undefined;\n      options.force = false;\n      vi.mocked(mockProjectTypeService.autoDetectProjectType).mockResolvedValue(ProjectType.REACT);\n      vi.mocked(mockProjectTypeService.isStorybookInstantiated).mockReturnValue(true);\n      vi.mocked(prompt.confirm).mockResolvedValue(false);\n\n      const exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => undefined as never);\n\n      await command.execute();\n\n      expect(exitSpy).toHaveBeenCalledWith(0);\n      exitSpy.mockRestore();\n    });\n\n    it('should not check existing installation for Angular projects', async () => {\n      options.type = undefined;\n      options.force = false;\n      vi.mocked(mockProjectTypeService.autoDetectProjectType).mockResolvedValue(\n        ProjectType.ANGULAR\n      );\n      vi.mocked(mockProjectTypeService.isStorybookInstantiated).mockReturnValue(true);\n\n      await command.execute();\n\n      expect(prompt.confirm).not.toHaveBeenCalled();\n    });\n\n    it('should handle detection errors', async () => {\n      options.type = undefined;\n      const error = new Error('Detection failed');\n      vi.mocked(mockProjectTypeService.autoDetectProjectType).mockImplementation(async () => {\n        logger.error(String(error));\n        throw new HandledError(error.message);\n      });\n\n      await expect(command.execute()).rejects.toThrow(HandledError);\n\n      expect(logger.error).toHaveBeenCalledWith('Error: Detection failed');\n    });\n\n    it('should detect language from options or service', async () => {\n      options.type = undefined;\n      options.language = SupportedLanguage.TYPESCRIPT;\n      vi.mocked(mockProjectTypeService.autoDetectProjectType).mockResolvedValue(ProjectType.REACT);\n\n      const result = await command.execute();\n\n      expect(result.language).toBe(SupportedLanguage.TYPESCRIPT);\n      expect(mockProjectTypeService.detectLanguage).not.toHaveBeenCalled();\n    });\n\n    it('should use service to detect language when not provided', async () => {\n      options.type = undefined;\n      options.language = undefined;\n      vi.mocked(mockProjectTypeService.autoDetectProjectType).mockResolvedValue(ProjectType.REACT);\n      vi.mocked(mockProjectTypeService.detectLanguage).mockResolvedValue(\n        SupportedLanguage.TYPESCRIPT\n      );\n\n      const result = await command.execute();\n\n      expect(result.language).toBe(SupportedLanguage.TYPESCRIPT);\n      expect(mockProjectTypeService.detectLanguage).toHaveBeenCalled();\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/commands/ProjectDetectionCommand.ts",
    "content": "import { ProjectType } from 'storybook/internal/cli';\nimport type { JsPackageManager } from 'storybook/internal/common';\nimport { logger, prompt } from 'storybook/internal/node-logger';\nimport { telemetry } from 'storybook/internal/telemetry';\nimport type { SupportedLanguage } from 'storybook/internal/types';\n\nimport picocolors from 'picocolors';\nimport { dedent } from 'ts-dedent';\n\nimport type { CommandOptions } from '../generators/types.ts';\nimport { ProjectTypeService } from '../services/ProjectTypeService.ts';\n\n/**\n * Command for detecting the project type during Storybook initialization\n *\n * Responsibilities:\n *\n * - Auto-detect project type or use user-provided type\n * - Handle React Native variant selection\n * - Check for existing Storybook installation\n * - Prompt for force install if needed\n */\nexport class ProjectDetectionCommand {\n  constructor(\n    private options: CommandOptions,\n    jsPackageManager: JsPackageManager,\n    private projectTypeService: ProjectTypeService = new ProjectTypeService(jsPackageManager)\n  ) {}\n\n  /** Execute project type detection */\n  async execute(): Promise<{ projectType: ProjectType; language: SupportedLanguage }> {\n    let projectType: ProjectType;\n    const projectTypeProvided = this.options.type;\n\n    // Use provided type or auto-detect\n    if (projectTypeProvided) {\n      projectType = await this.projectTypeService.validateProvidedType(projectTypeProvided);\n      logger.step(`Installing Storybook for user specified project type: ${projectTypeProvided}`);\n    } else {\n      const detected = await this.projectTypeService.autoDetectProjectType(this.options);\n      projectType = detected;\n      if (detected === ProjectType.REACT_NATIVE && !this.options.yes) {\n        projectType = await this.promptReactNativeVariant();\n      }\n      logger.debug(`Project type detected: ${projectType}`);\n    }\n\n    // Check for existing installation\n    await this.checkExistingInstallation(projectType);\n\n    const language = this.options.language || (await this.projectTypeService.detectLanguage());\n\n    return { projectType, language };\n  }\n\n  /** Prompt user to select React Native variant */\n  private async promptReactNativeVariant(): Promise<ProjectType> {\n    const manualType = await prompt.select({\n      message: \"We've detected a React Native project. Install:\",\n      options: [\n        {\n          label: `${picocolors.bold('React Native')}: Storybook on your device/simulator`,\n          value: ProjectType.REACT_NATIVE,\n        },\n        {\n          label: `${picocolors.bold('React Native Web')}: Storybook on web for docs, test, and sharing`,\n          value: ProjectType.REACT_NATIVE_WEB,\n        },\n        {\n          label: `${picocolors.bold('Both')}: Add both native and web Storybooks`,\n          value: ProjectType.REACT_NATIVE_AND_RNW,\n        },\n      ],\n    });\n    return manualType as ProjectType;\n  }\n\n  /** Check if Storybook is already installed and handle force option */\n  private async checkExistingInstallation(projectType: ProjectType): Promise<void> {\n    const storybookInstantiated = this.projectTypeService.isStorybookInstantiated();\n    const options = this.options;\n    if (\n      options.force !== true &&\n      options.yes !== true &&\n      storybookInstantiated &&\n      projectType !== ProjectType.ANGULAR\n    ) {\n      const force = await prompt.confirm({\n        message: dedent`We found a .storybook config directory in your project.\nWe assume that Storybook is already instantiated for your project. Do you still want to continue and force the initialization?`,\n      });\n      if (force || options.yes) {\n        options.force = true;\n      } else {\n        if (!options.disableTelemetry) {\n          await telemetry(\n            'exit',\n            { eventType: 'init', reason: 'existing-installation' },\n            { stripMetadata: true, immediate: true }\n          );\n        }\n        process.exit(0);\n      }\n    }\n  }\n}\n\nexport const executeProjectDetection = (\n  packageManager: JsPackageManager,\n  options: CommandOptions\n) => {\n  return new ProjectDetectionCommand(options, packageManager).execute();\n};\n"
  },
  {
    "path": "code/lib/create-storybook/src/commands/UserPreferencesCommand.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { AddonVitestService, ProjectType, globalSettings } from 'storybook/internal/cli';\nimport type { JsPackageManager } from 'storybook/internal/common';\nimport { PackageManagerName, isCI } from 'storybook/internal/common';\nimport { logger, prompt } from 'storybook/internal/node-logger';\nimport type { SupportedBuilder } from 'storybook/internal/types';\nimport { Feature } from 'storybook/internal/types';\n\nimport type { CommandOptions } from '../generators/types.ts';\nimport { FeatureCompatibilityService } from '../services/FeatureCompatibilityService.ts';\nimport { TelemetryService } from '../services/TelemetryService.ts';\nimport { UserPreferencesCommand } from './UserPreferencesCommand.ts';\n\nvi.mock('storybook/internal/cli', { spy: true });\nvi.mock('storybook/internal/common', { spy: true });\nvi.mock('storybook/internal/node-logger', { spy: true });\nvi.mock('../services/FeatureCompatibilityService', { spy: true });\nvi.mock('../services/TelemetryService', { spy: true });\n\ninterface CommandWithPrivates {\n  telemetryService: {\n    trackNewUserCheck: ReturnType<typeof vi.fn>;\n    trackInstallType: ReturnType<typeof vi.fn>;\n  };\n  featureService: { validateTestFeatureCompatibility: ReturnType<typeof vi.fn> };\n}\n\ndescribe('UserPreferencesCommand', () => {\n  let command: UserPreferencesCommand;\n  const mockPackageManager = {} as Partial<JsPackageManager> as JsPackageManager;\n\n  beforeEach(() => {\n    // Provide required CommandOptions to avoid undefined access\n    const commandOptions: CommandOptions = {\n      packageManager: PackageManagerName.NPM,\n      disableTelemetry: true,\n    };\n\n    command = new UserPreferencesCommand(commandOptions, mockPackageManager);\n\n    // Mock AddonVitestService\n    const mockAddonVitestService = vi.fn().mockImplementation(() => ({\n      validateCompatibility: vi.fn().mockResolvedValue({ compatible: true }),\n    }));\n    vi.mocked(AddonVitestService).mockImplementation(mockAddonVitestService);\n\n    // Mock FeatureCompatibilityService\n    vi.mocked(FeatureCompatibilityService).mockImplementation(function () {\n      return {\n        validateTestFeatureCompatibility: vi.fn().mockResolvedValue({ compatible: true }),\n      };\n    });\n\n    // Mock TelemetryService\n    vi.mocked(TelemetryService).mockImplementation(function () {\n      return {\n        trackNewUserCheck: vi.fn(),\n        trackInstallType: vi.fn(),\n      };\n    });\n\n    // Mock globalSettings\n    const mockSettings = {\n      value: { init: {} },\n      save: vi.fn().mockResolvedValue(undefined),\n      filePath: 'test-config.json',\n    };\n    vi.mocked(globalSettings).mockResolvedValue(\n      mockSettings as unknown as Awaited<ReturnType<typeof globalSettings>>\n    );\n\n    // Create mock services\n    const mockTelemetryService = {\n      trackNewUserCheck: vi.fn(),\n      trackInstallType: vi.fn(),\n    };\n\n    const mockFeatureService = {\n      validateTestFeatureCompatibility: vi.fn().mockResolvedValue({ compatible: true }),\n    };\n\n    // Inject mocked services\n    (command as unknown as CommandWithPrivates).telemetryService = mockTelemetryService;\n    (command as unknown as CommandWithPrivates).featureService = mockFeatureService;\n\n    // Mock logger and prompt\n    vi.mocked(logger.intro).mockImplementation(() => {});\n    vi.mocked(logger.info).mockImplementation(() => {});\n    vi.mocked(logger.warn).mockImplementation(() => {});\n    vi.mocked(logger.log).mockImplementation(() => {});\n    vi.mocked(isCI).mockReturnValue(false);\n\n    vi.clearAllMocks();\n  });\n\n  describe('execute', () => {\n    it('should return recommended config for new users in non-interactive mode', async () => {\n      const result = await command.execute({\n        framework: null,\n        builder: 'vite' as SupportedBuilder,\n        projectType: ProjectType.REACT,\n      });\n\n      expect(result.newUser).toBe(true);\n      expect(result.selectedFeatures).toContain('docs');\n      expect(result.selectedFeatures).toContain('test');\n      expect(result.selectedFeatures).toContain('onboarding');\n    });\n\n    it('should prompt for new user in interactive mode', async () => {\n      // Mock TTY\n      Object.defineProperty(process.stdout, 'isTTY', { value: true, configurable: true });\n\n      vi.mocked(prompt.select).mockResolvedValueOnce(true); // new user\n\n      const result = await command.execute({\n        framework: null,\n        builder: 'vite' as SupportedBuilder,\n        projectType: ProjectType.REACT,\n      });\n\n      expect(prompt.select).toHaveBeenCalledWith(\n        expect.objectContaining({\n          message: 'New to Storybook?',\n        })\n      );\n      expect(result.newUser).toBe(true);\n      const telemetryService = (command as unknown as CommandWithPrivates).telemetryService;\n      expect(telemetryService.trackNewUserCheck).toHaveBeenCalledWith(true);\n    });\n\n    it('should prompt for install type when not a new user', async () => {\n      Object.defineProperty(process.stdout, 'isTTY', { value: true, configurable: true });\n\n      vi.mocked(prompt.select)\n        .mockResolvedValueOnce(false) // not new user\n        .mockResolvedValueOnce('light'); // minimal install\n\n      const result = await command.execute({\n        framework: null,\n        builder: 'vite' as SupportedBuilder,\n        projectType: ProjectType.REACT,\n      });\n\n      expect(prompt.select).toHaveBeenCalledTimes(2);\n      expect(result.newUser).toBe(false);\n      const telemetryService = (command as unknown as CommandWithPrivates).telemetryService;\n      expect(telemetryService.trackInstallType).toHaveBeenCalledWith('light');\n    });\n\n    it('should not include test feature in minimal install', async () => {\n      Object.defineProperty(process.stdout, 'isTTY', { value: true, configurable: true });\n\n      vi.mocked(prompt.select)\n        .mockResolvedValueOnce(false) // not new user\n        .mockResolvedValueOnce('light'); // minimal install\n\n      const result = await command.execute({\n        framework: null,\n        builder: 'vite' as SupportedBuilder,\n        projectType: ProjectType.REACT,\n      });\n\n      expect(result.selectedFeatures.has(Feature.TEST)).toBe(false);\n      expect(result.selectedFeatures.has(Feature.DOCS)).toBe(false);\n      expect(result.selectedFeatures.has(Feature.ONBOARDING)).toBe(false);\n    });\n\n    it('should validate test feature compatibility in interactive mode', async () => {\n      Object.defineProperty(process.stdout, 'isTTY', { value: true, configurable: true });\n\n      vi.mocked(prompt.select).mockResolvedValueOnce(true); // new user\n      const featureService = (command as unknown as CommandWithPrivates).featureService;\n      vi.mocked(featureService.validateTestFeatureCompatibility).mockResolvedValue({\n        compatible: true,\n      });\n\n      await command.execute({\n        framework: null,\n        builder: 'vite' as SupportedBuilder,\n        projectType: ProjectType.REACT,\n      });\n\n      expect(featureService.validateTestFeatureCompatibility).toHaveBeenCalledWith(\n        null,\n        'vite',\n        process.cwd()\n      );\n    });\n\n    it('should remove test feature if user chooses to continue without it', async () => {\n      Object.defineProperty(process.stdout, 'isTTY', { value: true, configurable: true });\n\n      vi.mocked(prompt.select).mockResolvedValueOnce(true); // new user\n      const featureService = (command as unknown as CommandWithPrivates).featureService;\n      vi.mocked(featureService.validateTestFeatureCompatibility).mockResolvedValue({\n        compatible: false,\n        reasons: ['React version is too old'],\n      });\n      vi.mocked(prompt.confirm).mockResolvedValueOnce(true); // continue without test\n\n      const result = await command.execute({\n        framework: null,\n        builder: 'vite' as SupportedBuilder,\n        projectType: ProjectType.REACT,\n      });\n\n      expect(result.selectedFeatures.has(Feature.TEST)).toBe(false);\n      expect(result.selectedFeatures.has(Feature.DOCS)).toBe(true);\n      expect(result.selectedFeatures.has(Feature.ONBOARDING)).toBe(true);\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/commands/UserPreferencesCommand.ts",
    "content": "import type { ProjectType } from 'storybook/internal/cli';\nimport { globalSettings } from 'storybook/internal/cli';\nimport { type JsPackageManager, isCI } from 'storybook/internal/common';\nimport { logger, prompt } from 'storybook/internal/node-logger';\nimport type { SupportedBuilder, SupportedFramework } from 'storybook/internal/types';\nimport { Feature } from 'storybook/internal/types';\n\nimport picocolors from 'picocolors';\nimport { dedent } from 'ts-dedent';\n\nimport type { CommandOptions } from '../generators/types.ts';\nimport { FeatureCompatibilityService } from '../services/FeatureCompatibilityService.ts';\nimport { TelemetryService } from '../services/TelemetryService.ts';\n\nexport type InstallType = 'recommended' | 'light';\n\nexport interface UserPreferencesResult {\n  /** Whether the user is a new user */\n  newUser: boolean;\n  /**\n   * The features that the user has selected explicitly or implicitly and which can actually be\n   * installed based on the project type or other constraints.\n   */\n  selectedFeatures: Set<Feature>;\n}\n\nexport interface UserPreferencesOptions {\n  skipPrompt?: boolean;\n  framework: SupportedFramework | null;\n  builder: SupportedBuilder;\n  projectType: ProjectType;\n}\n\n/**\n * Command for gathering user preferences during Storybook initialization\n *\n * Responsibilities:\n *\n * - Display version information\n * - Prompt for new user / onboarding preference\n * - Prompt for install type (recommended vs minimal)\n * - Run feature compatibility checks\n * - Track telemetry events\n */\nexport class UserPreferencesCommand {\n  constructor(\n    private readonly commandOptions: CommandOptions,\n    packageManager: JsPackageManager,\n    private readonly featureService = new FeatureCompatibilityService(packageManager),\n    private readonly telemetryService = new TelemetryService(commandOptions.disableTelemetry)\n  ) {}\n\n  /** Execute user preferences gathering */\n  async execute(options: UserPreferencesOptions): Promise<UserPreferencesResult> {\n    // Display version information\n    const isInteractive = process.stdout.isTTY && !isCI();\n    const skipPrompt = !isInteractive || !!this.commandOptions.yes;\n\n    const isTestFeatureAvailable = await this.isTestFeatureAvailable(\n      options.framework,\n      options.builder\n    );\n\n    // Get new user preference\n    const newUser = await this.promptNewUser(skipPrompt);\n\n    const commandOptionsFeatures = this.handleCommandOptionsFeatureFlag();\n\n    if (commandOptionsFeatures) {\n      return {\n        newUser,\n        selectedFeatures: commandOptionsFeatures,\n      };\n    }\n\n    // Get install type\n    const installType: InstallType =\n      !newUser && !this.commandOptions.features\n        ? await this.promptInstallType(skipPrompt, isTestFeatureAvailable)\n        : 'recommended';\n\n    const selectedFeatures = this.determineFeatures(\n      installType,\n      newUser,\n      isTestFeatureAvailable,\n      options.projectType\n    );\n\n    return { newUser, selectedFeatures };\n  }\n\n  private handleCommandOptionsFeatureFlag(): Set<Feature> | null {\n    if (this.commandOptions.features && this.commandOptions.features?.length > 0) {\n      logger.warn(dedent`\n        Skipping feature validation as these features were explicitly selected:\n        ${Array.from(this.commandOptions.features).join(', ')}\n      `);\n      return new Set(this.commandOptions.features);\n    } else if (this.commandOptions.features?.length === 0) {\n      logger.warn(dedent`\n        All features have been disabled via --no-features flag.\n      `);\n      return new Set();\n    }\n\n    return null;\n  }\n\n  /** Prompt user about onboarding */\n  private async promptNewUser(skipPrompt: boolean): Promise<boolean> {\n    const settings = await globalSettings();\n    const { skipOnboarding } = settings.value.init || {};\n    let isNewUser = skipOnboarding !== undefined ? !skipOnboarding : true;\n\n    if (skipPrompt || skipOnboarding) {\n      settings.value.init ||= {};\n      settings.value.init.skipOnboarding = !!skipOnboarding;\n    } else {\n      isNewUser = await prompt.select({\n        message: 'New to Storybook?',\n        options: [\n          {\n            label: `${picocolors.bold('Yes:')} Help me with onboarding`,\n            value: true,\n          },\n          {\n            label: `${picocolors.bold('No:')} Skip onboarding & don't ask again`,\n            value: false,\n          },\n        ],\n      });\n\n      settings.value.init ||= {};\n      settings.value.init.skipOnboarding = !isNewUser;\n\n      if (typeof isNewUser !== 'undefined') {\n        await this.telemetryService.trackNewUserCheck(isNewUser);\n      }\n    }\n\n    try {\n      await settings.save();\n    } catch (err) {\n      logger.warn(`Failed to save user settings: ${err}`);\n    }\n\n    return isNewUser;\n  }\n\n  /** Prompt user for install type */\n  private async promptInstallType(\n    skipPrompt: boolean,\n    isTestFeatureAvailable: boolean\n  ): Promise<InstallType> {\n    let installType: InstallType = 'recommended';\n\n    const recommendedLabel = isTestFeatureAvailable\n      ? `Recommended: Component development, docs, and testing features.`\n      : `Recommended: Component development and docs`;\n\n    if (!skipPrompt) {\n      installType = await prompt.select({\n        message: 'What configuration should we install?',\n        options: [\n          {\n            label: recommendedLabel,\n            value: 'recommended',\n          },\n          {\n            label: `Minimal: Just the essentials for component development.`,\n            value: 'light',\n          },\n        ],\n      });\n    }\n\n    await this.telemetryService.trackInstallType(installType);\n\n    return installType;\n  }\n\n  /** Determine features based on install type and user status */\n  private determineFeatures(\n    installType: InstallType,\n    newUser: boolean,\n    isTestFeatureAvailable: boolean,\n    projectType: ProjectType\n  ): Set<Feature> {\n    const features = new Set<Feature>();\n\n    if (installType === 'recommended') {\n      features.add(Feature.DOCS);\n      features.add(Feature.A11Y);\n\n      if (isTestFeatureAvailable) {\n        features.add(Feature.TEST);\n      }\n      if (newUser && FeatureCompatibilityService.supportsOnboarding(projectType)) {\n        features.add(Feature.ONBOARDING);\n      }\n    }\n\n    return features;\n  }\n\n  /** Validate test feature compatibility and prompt user if issues found */\n  private async isTestFeatureAvailable(\n    framework: SupportedFramework | null,\n    builder: SupportedBuilder\n  ): Promise<boolean> {\n    const result = await this.featureService.validateTestFeatureCompatibility(\n      framework,\n      builder,\n      process.cwd()\n    );\n\n    return result.compatible;\n  }\n}\n\nexport const executeUserPreferences = ({\n  options,\n  packageManager,\n  ...restOptions\n}: UserPreferencesOptions & { options: CommandOptions; packageManager: JsPackageManager }) => {\n  return new UserPreferencesCommand(options, packageManager).execute(restOptions);\n};\n"
  },
  {
    "path": "code/lib/create-storybook/src/commands/index.ts",
    "content": "/**\n * Command classes for Storybook initialization workflow\n *\n * Each command represents a discrete step in the init process with clear responsibilities\n */\n\nexport { executePreflightCheck } from './PreflightCheckCommand.ts';\nexport type { PreflightCheckResult } from './PreflightCheckCommand.ts';\n\nexport { executeProjectDetection } from './ProjectDetectionCommand.ts';\n\nexport { executeFrameworkDetection } from './FrameworkDetectionCommand.ts';\nexport type { FrameworkDetectionResult } from './FrameworkDetectionCommand.ts';\n\nexport { executeUserPreferences } from './UserPreferencesCommand.ts';\nexport type {\n  InstallType,\n  UserPreferencesOptions,\n  UserPreferencesResult,\n} from './UserPreferencesCommand.ts';\n\nexport { executeGeneratorExecution } from './GeneratorExecutionCommand.ts';\n\nexport { executeAddonConfiguration } from './AddonConfigurationCommand.ts';\n\nexport { executeDependencyInstallation } from './DependencyInstallationCommand.ts';\n\nexport { executeFinalization } from './FinalizationCommand.ts';\n"
  },
  {
    "path": "code/lib/create-storybook/src/dependency-collector.test.ts",
    "content": "import { beforeEach, describe, expect, it } from 'vitest';\n\nimport { DependencyCollector } from './dependency-collector.ts';\n\ndescribe('DependencyCollector', () => {\n  let collector: DependencyCollector;\n\n  beforeEach(() => {\n    collector = new DependencyCollector();\n  });\n\n  describe('addDependencies', () => {\n    it('should add dependencies', () => {\n      collector.addDependencies(['react@18.0.0', 'react-dom@18.0.0']);\n\n      const { dependencies } = collector.getAllPackages();\n\n      expect(dependencies).toContain('react@18.0.0');\n      expect(dependencies).toContain('react-dom@18.0.0');\n    });\n\n    it('should add dependencies without version', () => {\n      collector.addDependencies(['react', 'react-dom']);\n\n      const { dependencies } = collector.getAllPackages();\n\n      expect(dependencies).toContain('react');\n      expect(dependencies).toContain('react-dom');\n    });\n  });\n\n  describe('addDevDependencies', () => {\n    it('should add dev dependencies', () => {\n      collector.addDevDependencies(['typescript@5.0.0', 'vitest@1.0.0']);\n\n      const { devDependencies } = collector.getAllPackages();\n\n      expect(devDependencies).toContain('typescript@5.0.0');\n      expect(devDependencies).toContain('vitest@1.0.0');\n    });\n  });\n\n  describe('getAllPackages', () => {\n    it('should return all packages by type', () => {\n      collector.addDependencies(['react@18.0.0']);\n      collector.addDevDependencies(['typescript@5.0.0']);\n\n      const result = collector.getAllPackages();\n\n      expect(result.dependencies).toEqual(['react@18.0.0']);\n      expect(result.devDependencies).toEqual(['typescript@5.0.0']);\n    });\n\n    it('should return empty arrays when no packages', () => {\n      const result = collector.getAllPackages();\n\n      expect(result.dependencies).toEqual([]);\n      expect(result.devDependencies).toEqual([]);\n    });\n  });\n\n  describe('hasPackages', () => {\n    it('should return false when no packages added', () => {\n      expect(collector.hasPackages()).toBe(false);\n    });\n\n    it('should return true when dependencies added', () => {\n      collector.addDependencies(['react']);\n      expect(collector.hasPackages()).toBe(true);\n    });\n\n    it('should return true when devDependencies added', () => {\n      collector.addDevDependencies(['typescript']);\n      expect(collector.hasPackages()).toBe(true);\n    });\n  });\n\n  describe('getVersionConflicts', () => {\n    it('should return empty array when no conflicts', () => {\n      collector.addDependencies(['react@18.0.0', 'vue@3.0.0']);\n\n      const conflicts = collector.getVersionConflicts();\n\n      expect(conflicts).toEqual([]);\n    });\n\n    it('should detect no conflicts when package is updated', () => {\n      // When adding same package twice, it updates (doesn't create conflict)\n      collector.addDependencies(['react@18.0.0']);\n      collector.addDependencies(['react@17.0.0']);\n\n      const conflicts = collector.getVersionConflicts();\n\n      // No conflict because the second add updated the first\n      expect(conflicts).toEqual([]);\n\n      // Version should be updated to latest\n      const { dependencies } = collector.getAllPackages();\n      expect(dependencies).toContain('react@17.0.0');\n    });\n\n    it('should not report conflict for same version', () => {\n      collector.addDevDependencies(['typescript@5.0.0']);\n      collector.addDevDependencies(['typescript@5.0.0']);\n\n      const conflicts = collector.getVersionConflicts();\n\n      expect(conflicts).toEqual([]);\n    });\n\n    it('should handle scoped packages without conflicts', () => {\n      // When adding same package twice, it updates (doesn't create conflict)\n      collector.addDependencies(['@storybook/react@8.0.0']);\n      collector.addDependencies(['@storybook/react@7.0.0']);\n\n      const conflicts = collector.getVersionConflicts();\n\n      // No conflict - version was updated\n      expect(conflicts).toEqual([]);\n\n      const { dependencies } = collector.getAllPackages();\n      expect(dependencies).toContain('@storybook/react@7.0.0');\n    });\n  });\n\n  describe('merge', () => {\n    it('should merge dependencies from another collector', () => {\n      collector.addDependencies(['react@18.0.0']);\n      collector.addDevDependencies(['typescript@5.0.0']);\n\n      const other = new DependencyCollector();\n      other.addDependencies(['vue@3.0.0']);\n      other.addDevDependencies(['vitest@1.0.0']);\n\n      collector.merge(other);\n\n      const { dependencies, devDependencies } = collector.getAllPackages();\n\n      expect(dependencies).toContain('react@18.0.0');\n      expect(dependencies).toContain('vue@3.0.0');\n      expect(devDependencies).toContain('typescript@5.0.0');\n      expect(devDependencies).toContain('vitest@1.0.0');\n    });\n\n    it('should handle empty collector merge', () => {\n      collector.addDependencies(['react@18.0.0']);\n\n      const other = new DependencyCollector();\n\n      collector.merge(other);\n\n      const { dependencies } = collector.getAllPackages();\n      expect(dependencies).toEqual(['react@18.0.0']);\n    });\n  });\n\n  describe('validate', () => {\n    it('should return valid for valid packages', () => {\n      collector.addDependencies(['react@18.0.0']);\n      collector.addDevDependencies(['typescript@5.0.0']);\n\n      const result = collector.validate();\n\n      expect(result.valid).toBe(true);\n      expect(result.errors).toEqual([]);\n    });\n\n    it('should detect empty package names', () => {\n      const typeMap = (collector as any).packages.get('dependencies');\n      typeMap.set('', '1.0.0');\n\n      const result = collector.validate();\n\n      expect(result.valid).toBe(false);\n      expect(result.errors.length).toBeGreaterThan(0);\n      expect(result.errors.some((e) => e.includes('Invalid package name'))).toBe(true);\n    });\n\n    it('should detect empty versions', () => {\n      const typeMap = (collector as any).packages.get('dependencies');\n      typeMap.set('react', '');\n\n      const result = collector.validate();\n\n      expect(result.valid).toBe(false);\n      expect(result.errors).toContain('Package react in dependencies has empty version');\n    });\n\n    it('should return multiple errors', () => {\n      const typeMap = (collector as any).packages.get('dependencies');\n      typeMap.set('', '1.0.0');\n      typeMap.set('react', '');\n\n      const result = collector.validate();\n\n      expect(result.valid).toBe(false);\n      expect(result.errors).toHaveLength(2);\n    });\n  });\n\n  describe('getPackageCount', () => {\n    it('should return 0 for empty collector', () => {\n      expect(collector.getPackageCount()).toBe(0);\n    });\n\n    it('should return total count', () => {\n      collector.addDependencies(['react', 'vue']);\n      collector.addDevDependencies(['typescript', 'vitest']);\n\n      expect(collector.getPackageCount()).toBe(4);\n    });\n\n    it('should return count for specific type', () => {\n      collector.addDependencies(['react', 'vue']);\n      collector.addDevDependencies(['typescript']);\n\n      expect(collector.getPackageCount('dependencies')).toBe(2);\n      expect(collector.getPackageCount('devDependencies')).toBe(1);\n    });\n  });\n\n  describe('version handling', () => {\n    it('should update version when adding same package with different version', () => {\n      collector.addDependencies(['react@18.0.0']);\n      collector.addDependencies(['react@18.1.0']);\n\n      const { dependencies } = collector.getAllPackages();\n\n      expect(dependencies).toContain('react@18.1.0');\n      expect(dependencies).not.toContain('react@18.0.0');\n      expect(dependencies).toHaveLength(1);\n    });\n\n    it('should keep version when adding same package without version', () => {\n      collector.addDependencies(['react@18.0.0']);\n      collector.addDependencies(['react']);\n\n      const { dependencies } = collector.getAllPackages();\n\n      expect(dependencies).toContain('react@18.0.0');\n      expect(dependencies).toHaveLength(1);\n    });\n\n    it('should handle scoped packages', () => {\n      collector.addDependencies(['@storybook/react@8.0.0']);\n\n      const { dependencies } = collector.getAllPackages();\n\n      expect(dependencies).toContain('@storybook/react@8.0.0');\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/dependency-collector.ts",
    "content": "export type DependencyType = 'dependencies' | 'devDependencies';\n\ninterface PackageInfo {\n  name: string;\n  version?: string;\n}\n\nexport interface VersionConflict {\n  packageName: string;\n  existingVersion: string;\n  newVersion: string;\n  type: DependencyType;\n}\n\n/**\n * Collects all dependencies that need to be installed during the init process. This allows us to\n * gather all packages first and then install them in a single operation.\n */\nexport class DependencyCollector {\n  private packages: Map<DependencyType, Map<string, string>> = new Map([\n    ['dependencies', new Map()],\n    ['devDependencies', new Map()],\n  ]);\n\n  /** Add development dependencies */\n  addDevDependencies(packageNames: string[]): void {\n    this.add('devDependencies', packageNames);\n  }\n\n  /** Add regular dependencies */\n  addDependencies(packageNames: string[]): void {\n    this.add('dependencies', packageNames);\n  }\n\n  /** Get all packages across all types */\n  getAllPackages(): { dependencies: string[]; devDependencies: string[] } {\n    return {\n      dependencies: this.getDependencies(),\n      devDependencies: this.getDevDependencies(),\n    };\n  }\n\n  /** Check if collector has any packages */\n  hasPackages(): boolean {\n    return (\n      this.packages.get('dependencies')!.size > 0 || this.packages.get('devDependencies')!.size > 0\n    );\n  }\n\n  /** Get all version conflicts across all dependency types */\n  getVersionConflicts(): VersionConflict[] {\n    const conflicts: VersionConflict[] = [];\n\n    for (const [type, typeMap] of this.packages.entries()) {\n      const packageNames = new Map<string, string[]>();\n\n      // Group packages by name to find conflicts\n      typeMap.forEach((version, name) => {\n        const versions = packageNames.get(name) || [];\n        versions.push(version);\n        packageNames.set(name, versions);\n      });\n\n      // Find packages with multiple versions\n      packageNames.forEach((versions, name) => {\n        if (versions.length > 1 && new Set(versions).size > 1) {\n          conflicts.push({\n            packageName: name,\n            existingVersion: versions[0],\n            newVersion: versions[versions.length - 1],\n            type,\n          });\n        }\n      });\n    }\n\n    return conflicts;\n  }\n\n  /** Merge dependencies from another collector */\n  merge(other: DependencyCollector): void {\n    const { dependencies, devDependencies } = other.getAllPackages();\n    this.addDependencies(dependencies);\n    this.addDevDependencies(devDependencies);\n  }\n\n  /** Validate that all packages have valid version specifiers */\n  validate(): { valid: boolean; errors: string[] } {\n    const errors: string[] = [];\n\n    for (const [type, typeMap] of this.packages.entries()) {\n      typeMap.forEach((version, name) => {\n        if (!name || name.trim() === '') {\n          errors.push(`Invalid package name in ${type}: empty or whitespace`);\n        }\n\n        if (version === '') {\n          errors.push(`Package ${name} in ${type} has empty version`);\n        }\n      });\n    }\n\n    return {\n      valid: errors.length === 0,\n      errors,\n    };\n  }\n\n  /** Get count of packages by type */\n  getPackageCount(type?: DependencyType): number {\n    if (type) {\n      return this.packages.get(type)!.size;\n    }\n    return this.packages.get('dependencies')!.size + this.packages.get('devDependencies')!.size;\n  }\n\n  /**\n   * Add packages to the collector\n   *\n   * @param type - The dependency type (dependencies or devDependencies)\n   * @param packageNames - Array of package names, optionally with version specifiers (e.g.,\n   *   'react@18.0.0')\n   */\n  private add(type: DependencyType, packageNames: string[]): void {\n    const typeMap = this.packages.get(type)!;\n\n    for (const pkg of packageNames) {\n      const { name, version } = this.parsePackage(pkg);\n\n      // If package already exists, only update if new version is specified\n      if (typeMap.has(name)) {\n        if (version) {\n          typeMap.set(name, version);\n        }\n      } else {\n        typeMap.set(name, version || 'latest');\n      }\n    }\n  }\n\n  /** Get all packages with their versions for a specific type */\n  private getPackages(type: DependencyType): string[] {\n    const typeMap = this.packages.get(type)!;\n    return Array.from(typeMap.entries()).map(([name, version]) =>\n      version === 'latest' ? name : `${name}@${version}`\n    );\n  }\n\n  /** Get all development dependencies */\n  private getDevDependencies(): string[] {\n    return this.getPackages('devDependencies');\n  }\n\n  /** Get all regular dependencies */\n  private getDependencies(): string[] {\n    return this.getPackages('dependencies');\n  }\n\n  /**\n   * Parse a package string into name and version\n   *\n   * @param pkg - Package string (e.g., 'react@18.0.0' or 'react')\n   */\n  private parsePackage(pkg: string): PackageInfo {\n    // Handle scoped packages like @storybook/react@1.0.0\n    const scopedMatch = pkg.match(/^(@[^@]+\\/[^@]+)(?:@(.+))?$/);\n    if (scopedMatch) {\n      return {\n        name: scopedMatch[1],\n        version: scopedMatch[2],\n      };\n    }\n\n    // Handle regular packages like react@18.0.0\n    const regularMatch = pkg.match(/^([^@]+)(?:@(.+))?$/);\n    if (regularMatch) {\n      return {\n        name: regularMatch[1],\n        version: regularMatch[2],\n      };\n    }\n\n    return { name: pkg };\n  }\n}\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/ANGULAR/index.ts",
    "content": "import { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { AngularJSON, ProjectType, copyTemplate } from 'storybook/internal/cli';\nimport { logger, prompt } from 'storybook/internal/node-logger';\nimport { SupportedBuilder, SupportedFramework, SupportedRenderer } from 'storybook/internal/types';\n\nimport semver from 'semver';\nimport { dedent } from 'ts-dedent';\n\nimport { defineGeneratorModule } from '../modules/GeneratorModule.ts';\n\nexport default defineGeneratorModule({\n  metadata: {\n    projectType: ProjectType.ANGULAR,\n    renderer: SupportedRenderer.ANGULAR,\n    framework: SupportedFramework.ANGULAR,\n    builderOverride: SupportedBuilder.WEBPACK5,\n  },\n  configure: async (packageManager, context) => {\n    const angularJSON = new AngularJSON();\n\n    if (\n      !angularJSON.projects ||\n      (angularJSON.projects && Object.keys(angularJSON.projects).length === 0)\n    ) {\n      throw new Error(\n        'Storybook was not able to find any projects in your angular.json file. Are you sure this is an Angular CLI project?'\n      );\n    }\n\n    if (angularJSON.projectsWithoutStorybook.length === 0) {\n      throw new Error(\n        'Every project in your workspace is already set up with Storybook. There is nothing to do!'\n      );\n    }\n\n    const angularProjectName = await angularJSON.getProjectName();\n    logger.log(`Adding Storybook support to your \"${angularProjectName}\" project`);\n\n    const angularProject = angularJSON.getProjectSettingsByName(angularProjectName);\n\n    if (!angularProject) {\n      throw new Error(\n        `Somehow we were not able to retrieve the \"${angularProjectName}\" project in your angular.json file. This is likely a bug in Storybook, please file an issue.`\n      );\n    }\n\n    const { root, projectType } = angularProject;\n    const { projects } = angularJSON;\n    const useCompodoc = context.yes ? true : await promptForCompoDocs();\n    const storybookFolder = root ? `${root}/.storybook` : '.storybook';\n\n    angularJSON.addStorybookEntries({\n      angularProjectName,\n      storybookFolder,\n      useCompodoc,\n      root,\n    });\n    angularJSON.write();\n\n    const angularVersion = packageManager.getDependencyVersion('@angular/core');\n\n    // Handle script addition for single-project workspaces\n    if (Object.keys(projects).length === 1) {\n      packageManager.addScripts({\n        storybook: `ng run ${angularProjectName}:storybook`,\n        'build-storybook': `ng run ${angularProjectName}:build-storybook`,\n      });\n    }\n\n    // Copy Angular templates\n    let projectTypeValue = projectType || 'application';\n    if (projectTypeValue !== 'application' && projectTypeValue !== 'library') {\n      projectTypeValue = 'application';\n    }\n\n    const templateDir = join(\n      dirname(fileURLToPath(import.meta.resolve('create-storybook/package.json'))),\n      'templates',\n      'angular',\n      projectTypeValue\n    );\n\n    if (templateDir) {\n      copyTemplate(templateDir, root || undefined);\n    }\n\n    const toDevkitVersion = (ngRange?: string | null) => {\n      if (!ngRange) {\n        return undefined;\n      }\n      const min = semver.minVersion(ngRange);\n\n      if (!min) {\n        return undefined;\n      }\n      const pre = min.prerelease && min.prerelease.length > 0 ? `-${min.prerelease.join('.')}` : '';\n      // devkit follows 0.<major*100 + minor>.<patch>\n      const devkitMinor = min.major * 100 + min.minor;\n      const versionCore = `0.${devkitMinor}.${min.patch}${pre}`;\n      const hasCaret = ngRange.trim().startsWith('^');\n      return hasCaret ? `^${versionCore}` : versionCore;\n    };\n\n    const devkitVersion = toDevkitVersion(angularVersion);\n\n    const extraAngularDeps = [\n      angularVersion\n        ? `@angular-devkit/build-angular@${angularVersion}`\n        : '@angular-devkit/build-angular',\n      devkitVersion ? `@angular-devkit/architect@${devkitVersion}` : '@angular-devkit/architect',\n      angularVersion ? `@angular-devkit/core@${angularVersion}` : '@angular-devkit/core',\n      angularVersion\n        ? `@angular/platform-browser-dynamic@${angularVersion}`\n        : '@angular/platform-browser-dynamic',\n    ];\n\n    return {\n      extraPackages: [\n        ...extraAngularDeps,\n        ...(useCompodoc ? ['@compodoc/compodoc', '@storybook/addon-docs'] : []),\n      ],\n      addScripts: false, // Handled above based on project count\n      componentsDestinationPath: root ? `${root}/src/stories` : undefined,\n      storybookConfigFolder: storybookFolder,\n      storybookCommand: `ng run ${angularProjectName}:storybook`,\n      ...(useCompodoc && {\n        frameworkPreviewParts: {\n          prefix: dedent`\n          import { setCompodocJson } from \"@storybook/addon-docs/angular\";\n          import docJson from \"../documentation.json\";\n          setCompodocJson(docJson);\n        `.trimStart(),\n        },\n      }),\n    };\n  },\n});\n\nfunction promptForCompoDocs(): Promise<boolean> {\n  logger.log(\n    `Compodoc is a great tool to generate documentation for your Angular projects. Storybook can use the documentation generated by Compodoc to extract argument definitions and JSDOC comments to display them in the Storybook UI. We highly recommend using Compodoc for your Angular projects to get the best experience out of Storybook.`\n  );\n\n  return prompt.confirm({\n    message: 'Do you want to use Compodoc for documentation?',\n    initialValue: true,\n  });\n}\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/EMBER/index.ts",
    "content": "import { ProjectType } from 'storybook/internal/cli';\nimport { SupportedBuilder, SupportedFramework, SupportedRenderer } from 'storybook/internal/types';\n\nimport { defineGeneratorModule } from '../modules/GeneratorModule.ts';\n\nexport default defineGeneratorModule({\n  metadata: {\n    projectType: ProjectType.EMBER,\n    renderer: SupportedRenderer.EMBER,\n    framework: SupportedFramework.EMBER,\n    builderOverride: SupportedBuilder.WEBPACK5,\n  },\n  configure: async () => {\n    return {\n      staticDir: 'dist',\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/GeneratorRegistry.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { ProjectType } from 'storybook/internal/cli';\nimport { logger } from 'storybook/internal/node-logger';\nimport { SupportedRenderer } from 'storybook/internal/types';\n\nimport { GeneratorRegistry } from './GeneratorRegistry.ts';\nimport type { GeneratorModule } from './types.ts';\n\nvi.mock('storybook/internal/node-logger', { spy: true });\n\ndescribe('GeneratorRegistry', () => {\n  let registry: GeneratorRegistry;\n  let mockGeneratorModule: GeneratorModule;\n\n  beforeEach(() => {\n    registry = new GeneratorRegistry();\n    mockGeneratorModule = {\n      metadata: {\n        projectType: ProjectType.REACT,\n        renderer: SupportedRenderer.REACT,\n      },\n      configure: vi.fn(),\n    };\n    vi.clearAllMocks();\n  });\n\n  describe('register', () => {\n    it('should register a generator for a project type', () => {\n      registry.register(mockGeneratorModule);\n\n      expect(registry.get(ProjectType.REACT)).toBe(mockGeneratorModule);\n    });\n\n    it('should warn when overwriting an existing generator', () => {\n      const newGeneratorModule: GeneratorModule = {\n        metadata: {\n          projectType: ProjectType.REACT,\n          renderer: SupportedRenderer.REACT,\n        },\n        configure: vi.fn(),\n      };\n\n      // Mock logger.warn to prevent throwing in vitest-setup\n      vi.mocked(logger.warn).mockImplementation(() => {});\n\n      registry.register(mockGeneratorModule);\n      registry.register(newGeneratorModule);\n\n      expect(logger.warn).toHaveBeenCalledWith(\n        expect.stringContaining('already registered. Overwriting')\n      );\n      expect(registry.get(ProjectType.REACT)).toBe(newGeneratorModule);\n    });\n  });\n\n  describe('get', () => {\n    it('should return generator for registered project type', () => {\n      registry.register(mockGeneratorModule);\n\n      expect(registry.get(ProjectType.REACT)).toBe(mockGeneratorModule);\n    });\n\n    it('should return undefined for unregistered project type', () => {\n      expect(registry.get(ProjectType.VUE3)).toBeUndefined();\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/GeneratorRegistry.ts",
    "content": "import type { ProjectType } from 'storybook/internal/cli';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport type { GeneratorModule } from './types.ts';\n\n/**\n * Registry for managing Storybook project generators\n *\n * All new generators should use the GeneratorModule format with metadata + configure. Legacy\n * generators (not yet refactored) can still be registered with LegacyGeneratorMetadata.\n */\nexport class GeneratorRegistry {\n  private generators: Map<ProjectType, GeneratorModule> = new Map();\n\n  /** Register a generator for a specific project type */\n  register(generator: GeneratorModule): void {\n    const { metadata } = generator;\n    if (this.generators.has(metadata.projectType)) {\n      logger.warn(\n        `Generator for project type ${metadata.projectType} is already registered. Overwriting.`\n      );\n    }\n\n    this.generators.set(metadata.projectType, generator);\n  }\n\n  /** Get a generator for a specific project type */\n  get(projectType: ProjectType): GeneratorModule | undefined {\n    return this.generators.get(projectType);\n  }\n}\n\n// Create and export a singleton instance\nexport const generatorRegistry = new GeneratorRegistry();\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/HTML/index.ts",
    "content": "import { ProjectType } from 'storybook/internal/cli';\nimport { SupportedBuilder, SupportedRenderer } from 'storybook/internal/types';\n\nimport { defineGeneratorModule } from '../modules/GeneratorModule.ts';\n\nexport default defineGeneratorModule({\n  metadata: {\n    projectType: ProjectType.HTML,\n    renderer: SupportedRenderer.HTML,\n  },\n  configure: async () => {\n    return {\n      webpackCompiler: ({ builder }) => (builder === SupportedBuilder.WEBPACK5 ? 'swc' : undefined),\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/NEXTJS/index.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { ProjectType } from 'storybook/internal/cli';\nimport { findFilesUp } from 'storybook/internal/common';\nimport { logger, prompt } from 'storybook/internal/node-logger';\nimport { SupportedBuilder, SupportedFramework, SupportedRenderer } from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\n\nimport { defineGeneratorModule } from '../modules/GeneratorModule.ts';\n\nconst NEXT_CONFIG_FILES = [\n  'next.config.mjs',\n  'next.config.js',\n  'next.config.ts',\n  'next.config.mts',\n];\n\nconst BABEL_CONFIG_FILES = [\n  '.babelrc',\n  '.babelrc.json',\n  '.babelrc.js',\n  '.babelrc.mjs',\n  '.babelrc.cjs',\n  'babel.config.js',\n  'babel.config.json',\n  'babel.config.mjs',\n  'babel.config.cjs',\n];\n\nexport default defineGeneratorModule({\n  metadata: {\n    projectType: ProjectType.NEXTJS,\n    renderer: SupportedRenderer.REACT,\n    framework: (builder: SupportedBuilder) => {\n      return builder === SupportedBuilder.VITE\n        ? SupportedFramework.NEXTJS_VITE\n        : SupportedFramework.NEXTJS;\n    },\n    builderOverride: async () => {\n      const nextConfigFile = findFilesUp(NEXT_CONFIG_FILES, process.cwd())[0];\n      if (!nextConfigFile) {\n        return SupportedBuilder.VITE;\n      }\n\n      const nextConfig = await readFile(nextConfigFile, 'utf-8');\n      const hasCustomWebpackConfig = nextConfig.includes('webpack');\n      const babelConfigFile = findFilesUp(BABEL_CONFIG_FILES, process.cwd())[0];\n\n      if (!hasCustomWebpackConfig && !babelConfigFile) {\n        return SupportedBuilder.VITE;\n      } else {\n        // prompt to ask the user which framework to select\n        // based on the framework, either webpack5 or vite will be selected\n        // We want to tell users in this special case, that due to their custom webpack config or babel config\n        // they should select wisely, because the nextjs-vite framework may not be compatible with their setup\n        const reason =\n          hasCustomWebpackConfig && babelConfigFile\n            ? 'custom webpack config and babel config'\n            : hasCustomWebpackConfig\n              ? 'custom webpack config'\n              : 'custom babel config';\n        logger.info(dedent`\n          Storybook has two Next.js builder options: Webpack 5 and Vite.\n          \n          We generally recommend nextjs-vite, which is much faster, more modern, and supports our latest testing features.\n\n          However, your project has a ${reason}, which is not supported by nextjs-vite, so please be aware of that if you choose that option.\n        `);\n\n        return prompt.select({\n          message: 'Which framework would you like to use?',\n          options: [\n            { label: '@storybook/nextjs-vite', value: SupportedBuilder.VITE },\n            { label: '@storybook/nextjs (Webpack)', value: SupportedBuilder.WEBPACK5 },\n          ],\n        });\n      }\n    },\n  },\n  configure: async (packageManager, context) => {\n    let staticDir;\n\n    if (existsSync(join(process.cwd(), 'public'))) {\n      staticDir = 'public';\n    }\n\n    const extraPackages: string[] = [];\n\n    if (context.builder === SupportedBuilder.VITE) {\n      extraPackages.push('vite');\n      // Add any Vite-specific configuration here\n    }\n\n    return {\n      staticDir,\n      extraPackages,\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/NUXT/index.ts",
    "content": "import { ProjectType } from 'storybook/internal/cli';\nimport { logger } from 'storybook/internal/node-logger';\nimport {\n  Feature,\n  SupportedBuilder,\n  SupportedFramework,\n  SupportedRenderer,\n} from 'storybook/internal/types';\n\nimport { defineGeneratorModule } from '../modules/GeneratorModule.ts';\n\nexport default defineGeneratorModule({\n  metadata: {\n    projectType: ProjectType.NUXT,\n    renderer: SupportedRenderer.VUE3,\n    framework: SupportedFramework.NUXT,\n    builderOverride: SupportedBuilder.VITE,\n  },\n  configure: async (packageManager, context) => {\n    const extraStories = context.features.has(Feature.DOCS) ? ['../components/**/*.mdx'] : [];\n    extraStories.push('../components/**/*.stories.@(js|jsx|ts|tsx|mdx)');\n\n    // Nuxt requires special handling - always install dependencies even with skipInstall\n    // This is handled here to ensure Nuxt modules work correctly\n    logger.info(\n      'Note: Nuxt requires dependency installation to configure modules. Dependencies will be installed even if --skip-install is specified.'\n    );\n\n    // Add nuxtjs/storybook to nuxt.config.js\n    await packageManager.runPackageCommand({\n      args: ['nuxi', 'module', 'add', '@nuxtjs/storybook', '--skipInstall'],\n    });\n\n    return {\n      extraPackages: ['@nuxtjs/storybook'],\n      installFrameworkPackages: false,\n      componentsDestinationPath: './components',\n      extraMain: {\n        stories: extraStories,\n      },\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/PREACT/index.ts",
    "content": "import { ProjectType } from 'storybook/internal/cli';\nimport { SupportedBuilder, SupportedRenderer } from 'storybook/internal/types';\n\nimport { defineGeneratorModule } from '../modules/GeneratorModule.ts';\n\nexport default defineGeneratorModule({\n  metadata: {\n    projectType: ProjectType.PREACT,\n    renderer: SupportedRenderer.PREACT,\n  },\n  configure: async () => {\n    return {\n      webpackCompiler: ({ builder }) => (builder === SupportedBuilder.WEBPACK5 ? 'swc' : undefined),\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/QWIK/index.ts",
    "content": "import { ProjectType } from 'storybook/internal/cli';\nimport { SupportedFramework, SupportedRenderer } from 'storybook/internal/types';\n\nimport { defineGeneratorModule } from '../modules/GeneratorModule.ts';\n\nexport default defineGeneratorModule({\n  metadata: {\n    projectType: ProjectType.QWIK,\n    renderer: SupportedRenderer.QWIK,\n    framework: SupportedFramework.QWIK,\n  },\n  configure: async () => {\n    return {};\n  },\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/REACT/index.ts",
    "content": "import { ProjectType } from 'storybook/internal/cli';\nimport { SupportedBuilder, SupportedLanguage, SupportedRenderer } from 'storybook/internal/types';\n\nimport { defineGeneratorModule } from '../modules/GeneratorModule.ts';\n\n// Export as module\nexport default defineGeneratorModule({\n  metadata: {\n    projectType: ProjectType.REACT,\n    renderer: SupportedRenderer.REACT,\n  },\n  configure: async (packageManager, { language }) => {\n    const extraPackages = language === SupportedLanguage.JAVASCRIPT ? ['prop-types'] : [];\n\n    return {\n      extraPackages,\n      webpackCompiler: ({ builder }) => (builder === SupportedBuilder.WEBPACK5 ? 'swc' : undefined),\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts",
    "content": "import { ProjectType, copyTemplateFiles, getBabelDependencies } from 'storybook/internal/cli';\nimport { CLI_COLORS, logger } from 'storybook/internal/node-logger';\nimport { SupportedBuilder, SupportedLanguage, SupportedRenderer } from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\n\nimport { defineGeneratorModule } from '../modules/GeneratorModule.ts';\n\nexport default defineGeneratorModule({\n  metadata: {\n    projectType: ProjectType.REACT_NATIVE,\n    renderer: SupportedRenderer.REACT,\n    builderOverride: SupportedBuilder.WEBPACK5,\n    framework: null,\n  },\n  configure: async (packageManager, context) => {\n    const missingReactDom = !packageManager.getDependencyVersion('react-dom');\n    const reactVersion = packageManager.getDependencyVersion('react');\n    const dependencyCollector = context.dependencyCollector;\n\n    const peerDependencies = [\n      'react-native-safe-area-context',\n      '@react-native-async-storage/async-storage',\n      '@react-native-community/datetimepicker',\n      '@react-native-community/slider',\n      'react-native-reanimated',\n      'react-native-gesture-handler',\n      '@gorhom/bottom-sheet',\n      'react-native-svg',\n    ].filter((dep) => !packageManager.getDependencyVersion(dep));\n\n    const packagesToResolve = [\n      ...peerDependencies,\n      '@storybook/addon-ondevice-controls',\n      '@storybook/addon-ondevice-actions',\n      '@storybook/react-native',\n      'storybook',\n    ];\n\n    const versionedPackages = await packageManager.getVersionedPackages(packagesToResolve);\n    const babelDependencies = await getBabelDependencies(packageManager as any);\n\n    const packages: string[] = [\n      ...babelDependencies,\n      ...versionedPackages,\n      ...(missingReactDom && reactVersion ? [`react-dom@${reactVersion}`] : []),\n    ];\n\n    dependencyCollector.addDependencies(packages);\n\n    // Add React Native specific scripts\n    packageManager.addScripts({\n      'storybook-generate': 'sb-rn-get-stories',\n    });\n\n    const storybookConfigFolder = '.rnstorybook';\n\n    // Copy React Native templates\n    await copyTemplateFiles({\n      packageManager: packageManager as any,\n      templateLocation: SupportedRenderer.REACT_NATIVE,\n      language: SupportedLanguage.TYPESCRIPT,\n      destination: storybookConfigFolder,\n      features: context.features,\n    });\n\n    // React Native doesn't use baseGenerator - return special config\n    return {\n      // Signal to skip baseGenerator by returning minimal config\n      storybookConfigFolder,\n      skipGenerator: true,\n      storybookCommand: null,\n      shouldRunDev: false, // React Native needs additional manual steps to configure the project\n    };\n  },\n  postConfigure: ({ packageManager }) => {\n    logger.log(dedent`\n      ${CLI_COLORS.warning('The Storybook for React Native installation is not 100% automated.')}\n  \n      To run Storybook for React Native, you will need to:\n  \n      1. Replace the contents of your app entry with the following\n  \n      ${CLI_COLORS.info(' ' + \"export {default} from './.rnstorybook';\" + ' ')}\n  \n      2. Wrap your metro config with the withStorybook enhancer function like this:\n  \n      ${CLI_COLORS.info(' ' + \"const { withStorybook } = require('@storybook/react-native/metro/withStorybook');\" + ' ')}\n      ${CLI_COLORS.info(' ' + 'module.exports = withStorybook(defaultConfig);' + ' ')}\n  \n      For more details go to:\n      https://github.com/storybookjs/react-native#getting-started\n  \n      Then to start Storybook for React Native, run:\n  \n      ${CLI_COLORS.cta(' ' + packageManager.getRunCommand('start') + ' ')}\n    `);\n  },\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/REACT_NATIVE_AND_RNW/index.ts",
    "content": "import { ProjectType } from 'storybook/internal/cli';\nimport { SupportedBuilder, SupportedFramework, SupportedRenderer } from 'storybook/internal/types';\n\nimport reactNativeGeneratorModule from '../REACT_NATIVE/index.ts';\nimport reactNativeWebGeneratorModule from '../REACT_NATIVE_WEB/index.ts';\nimport { defineGeneratorModule } from '../modules/GeneratorModule.ts';\n\nexport default defineGeneratorModule({\n  metadata: {\n    projectType: ProjectType.REACT_NATIVE_AND_RNW,\n    renderer: SupportedRenderer.REACT,\n    framework: SupportedFramework.REACT_NATIVE_WEB_VITE,\n    builderOverride: SupportedBuilder.VITE,\n  },\n  configure: async (packageManager, context) => {\n    await reactNativeGeneratorModule.configure(packageManager, context);\n    const configurationResult = await reactNativeWebGeneratorModule.configure(\n      packageManager,\n      context\n    );\n\n    return {\n      ...configurationResult,\n      shouldRunDev: false, // React Native needs additional manual steps to configure the project\n    };\n  },\n  postConfigure: async ({ packageManager }) => {\n    await reactNativeWebGeneratorModule.postConfigure();\n    reactNativeGeneratorModule.postConfigure({ packageManager });\n  },\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/REACT_NATIVE_WEB/index.ts",
    "content": "import { readdir, rm } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { ProjectType, cliStoriesTargetPath } from 'storybook/internal/cli';\nimport {\n  SupportedBuilder,\n  SupportedFramework,\n  SupportedLanguage,\n  SupportedRenderer,\n} from 'storybook/internal/types';\n\nimport { defineGeneratorModule } from '../modules/GeneratorModule.ts';\n\n// Export as module\nexport default defineGeneratorModule({\n  metadata: {\n    projectType: ProjectType.REACT_NATIVE_WEB,\n    renderer: SupportedRenderer.REACT,\n    framework: SupportedFramework.REACT_NATIVE_WEB_VITE,\n    builderOverride: SupportedBuilder.VITE,\n  },\n  configure: async (packageManager, { language }) => {\n    // Add prop-types dependency if not using TypeScript\n    const extraPackages = ['vite', 'react-native-web'];\n    if (language === SupportedLanguage.JAVASCRIPT) {\n      extraPackages.push('prop-types');\n    }\n\n    return {\n      extraPackages,\n    };\n  },\n  postConfigure: async () => {\n    try {\n      const targetPath = await cliStoriesTargetPath();\n      const cssFiles = (await readdir(targetPath)).filter((f) => f.endsWith('.css'));\n      await Promise.all(cssFiles.map((f) => rm(join(targetPath, f))));\n    } catch {\n      // Silent fail if CSS cleanup fails - not critical\n    }\n  },\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/REACT_SCRIPTS/index.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { ProjectType } from 'storybook/internal/cli';\nimport { SupportedBuilder, SupportedRenderer } from 'storybook/internal/types';\n\nimport semver from 'semver';\nimport { dedent } from 'ts-dedent';\n\nimport { defineGeneratorModule } from '../modules/GeneratorModule.ts';\n\nexport default defineGeneratorModule({\n  metadata: {\n    projectType: ProjectType.REACT_SCRIPTS,\n    renderer: SupportedRenderer.REACT,\n    builderOverride: SupportedBuilder.WEBPACK5,\n  },\n  configure: async (packageManager, context) => {\n    const monorepoRootPath = fileURLToPath(new URL('../../../../../../..', import.meta.url));\n    const extraMain = context.linkable\n      ? {\n          webpackFinal: `%%(config) => {\n        // add monorepo root as a valid directory to import modules from\n        config.resolve.plugins.forEach((p) => {\n          if (Array.isArray(p.appSrcs)) {\n            p.appSrcs.push('${monorepoRootPath}');\n                }\n              });\n            return config;\n            }\n      %%`,\n        }\n      : {};\n\n    const craVersion =\n      (await packageManager.getModulePackageJSON('react-scripts'))?.version ?? null;\n\n    if (craVersion === null) {\n      throw new Error(dedent`\n        It looks like you're trying to initialize Storybook in a CRA project that does not have react-scripts installed.\n        Please install it and make sure it's of version 5 or higher, which are the versions supported by Storybook 7.0+.\n      `);\n    }\n\n    if (craVersion && semver.lt(craVersion, '5.0.0')) {\n      throw new Error(dedent`\n        Storybook 7.0+ doesn't support react-scripts@<5.0.0.\n  \n        https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#create-react-app-dropped-cra4-support\n      `);\n    }\n\n    // TODO: Evaluate if adding prop-types is correct after removing pnp compatibility code in SB11\n    // Miscellaneous dependency to add to be sure Storybook + CRA is working fine with Yarn PnP mode\n    const extraPackages = ['webpack', 'prop-types'];\n    const extraAddons = ['@storybook/preset-create-react-app'];\n\n    return {\n      webpackCompiler: () => undefined,\n      extraAddons,\n      extraPackages,\n      staticDir: existsSync(resolve('./public')) ? 'public' : undefined,\n      extraMain,\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/SERVER/index.ts",
    "content": "import { ProjectType } from 'storybook/internal/cli';\nimport { SupportedBuilder, SupportedRenderer } from 'storybook/internal/types';\n\nimport { defineGeneratorModule } from '../modules/GeneratorModule.ts';\n\n// Export as module\nexport default defineGeneratorModule({\n  metadata: {\n    projectType: ProjectType.SERVER,\n    renderer: SupportedRenderer.SERVER,\n    builderOverride: SupportedBuilder.WEBPACK5,\n  },\n  configure: async () => {\n    return {\n      webpackCompiler: () => 'swc',\n      extensions: ['json', 'yaml', 'yml'],\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/SOLID/index.ts",
    "content": "import { ProjectType } from 'storybook/internal/cli';\nimport { SupportedBuilder, SupportedFramework, SupportedRenderer } from 'storybook/internal/types';\n\nimport { defineGeneratorModule } from '../modules/GeneratorModule.ts';\n\nexport default defineGeneratorModule({\n  metadata: {\n    projectType: ProjectType.SOLID,\n    renderer: SupportedRenderer.SOLID,\n    framework: SupportedFramework.SOLID,\n    builderOverride: SupportedBuilder.VITE,\n  },\n  configure: async () => {\n    return {\n      addComponents: true,\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/SVELTE/index.ts",
    "content": "import { ProjectType } from 'storybook/internal/cli';\nimport { SupportedRenderer } from 'storybook/internal/types';\n\nimport { defineGeneratorModule } from '../modules/GeneratorModule.ts';\n\nexport default defineGeneratorModule({\n  metadata: {\n    projectType: ProjectType.SVELTE,\n    renderer: SupportedRenderer.SVELTE,\n  },\n  configure: async () => {\n    return {\n      extensions: ['js', 'ts', 'svelte'],\n      extraAddons: ['@storybook/addon-svelte-csf'],\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/SVELTEKIT/index.ts",
    "content": "import { ProjectType } from 'storybook/internal/cli';\nimport { SupportedBuilder, SupportedFramework, SupportedRenderer } from 'storybook/internal/types';\n\nimport { defineGeneratorModule } from '../modules/GeneratorModule.ts';\n\nexport default defineGeneratorModule({\n  metadata: {\n    projectType: ProjectType.SVELTEKIT,\n    renderer: SupportedRenderer.SVELTE,\n    framework: SupportedFramework.SVELTEKIT,\n    builderOverride: SupportedBuilder.VITE,\n  },\n  configure: async () => {\n    return {\n      extensions: ['js', 'ts', 'svelte'],\n      extraAddons: ['@storybook/addon-svelte-csf'],\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/VUE3/index.ts",
    "content": "import { ProjectType } from 'storybook/internal/cli';\nimport { SupportedBuilder, SupportedRenderer } from 'storybook/internal/types';\n\nimport { defineGeneratorModule } from '../modules/GeneratorModule.ts';\n\nexport default defineGeneratorModule({\n  metadata: {\n    projectType: ProjectType.VUE3,\n    renderer: SupportedRenderer.VUE3,\n  },\n  configure: async () => {\n    return {\n      extraPackages: async ({ builder }) => {\n        return builder === SupportedBuilder.WEBPACK5\n          ? ['vue-loader@^17.0.0', '@vue/compiler-sfc@^3.2.0']\n          : [];\n      },\n      webpackCompiler: ({ builder }) => (builder === SupportedBuilder.WEBPACK5 ? 'swc' : undefined),\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/WEB-COMPONENTS/index.ts",
    "content": "import { ProjectType } from 'storybook/internal/cli';\nimport { SupportedBuilder, SupportedRenderer } from 'storybook/internal/types';\n\nimport { defineGeneratorModule } from '../modules/GeneratorModule.ts';\n\nexport default defineGeneratorModule({\n  metadata: {\n    projectType: ProjectType.WEB_COMPONENTS,\n    renderer: SupportedRenderer.WEB_COMPONENTS,\n  },\n  configure: async () => {\n    return {\n      extraPackages: ['lit'],\n      webpackCompiler: ({ builder }) => (builder === SupportedBuilder.WEBPACK5 ? 'swc' : undefined),\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/baseGenerator.ts",
    "content": "import { mkdir } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport {\n  type NpmOptions,\n  configureEslintPlugin,\n  copyTemplateFiles,\n  extractEslintInfo,\n} from 'storybook/internal/cli';\nimport {\n  type JsPackageManager,\n  frameworkPackages,\n  getPackageDetails,\n  isCI,\n  optionalEnvToBoolean,\n} from 'storybook/internal/common';\nimport { prompt } from 'storybook/internal/node-logger';\nimport { SupportedFramework, SupportedLanguage } from 'storybook/internal/types';\n\nimport invariant from 'tiny-invariant';\nimport { dedent } from 'ts-dedent';\n\nimport { AddonService } from '../services/index.ts';\nimport { configureMain, configurePreview } from './configure.ts';\nimport type { FrameworkOptions, GeneratorOptions } from './types.ts';\n\nconst defaultOptions = {\n  extraPackages: [],\n  extraAddons: [],\n  staticDir: undefined,\n  addScripts: true,\n  addComponents: true,\n  webpackCompiler: () => undefined,\n  extraMain: undefined,\n  extensions: undefined,\n  componentsDestinationPath: undefined,\n  storybookConfigFolder: '.storybook',\n  installFrameworkPackages: true,\n} satisfies FrameworkOptions;\n\nconst getPackageByValue = (\n  type: 'framework' | 'renderer' | 'builder',\n  value: string,\n  packages: Record<string, string>\n) => {\n  const foundPackage = value\n    ? Object.entries(packages).find(([key, pkgValue]) => pkgValue === value)?.[0]\n    : undefined;\n\n  if (foundPackage) {\n    return foundPackage;\n  }\n\n  throw new Error(\n    dedent`\n      Could not find ${type} package for ${value}.\n      Make sure this package exists, and if it does, please file an issue as this might be a bug in Storybook.\n    `\n  );\n};\n\nconst applyGetAbsolutePathWrapper = (packageName: string) =>\n  `%%getAbsolutePath('${packageName}')%%`;\n\nconst applyAddonGetAbsolutePathWrapper = (pkg: string | { name: string }) => {\n  if (typeof pkg === 'string') {\n    return applyGetAbsolutePathWrapper(pkg);\n  }\n  const obj = { ...pkg } as { name: string };\n  obj.name = applyGetAbsolutePathWrapper(pkg.name);\n  return obj;\n};\n\nconst getFrameworkDetails = ({\n  framework,\n  shouldApplyRequireWrapperOnPackageNames,\n}: {\n  framework: SupportedFramework;\n  shouldApplyRequireWrapperOnPackageNames?: boolean;\n}): {\n  frameworkPackage: string;\n  frameworkPackagePath: string;\n} => {\n  const frameworkPackage = getPackageByValue('framework', framework, frameworkPackages);\n\n  const frameworkPackagePath = shouldApplyRequireWrapperOnPackageNames\n    ? applyGetAbsolutePathWrapper(frameworkPackage)\n    : frameworkPackage;\n\n  return {\n    frameworkPackage,\n    frameworkPackagePath,\n  };\n};\n\nconst hasFrameworkTemplates = (framework?: string) => {\n  if (!framework) {\n    return false;\n  }\n  // Nuxt has framework templates, but for sandboxes we create them from the Vue3 renderer\n  // As the Nuxt framework templates are not compatible with the stories we need for CI.\n  // See: https://github.com/storybookjs/storybook/pull/28607#issuecomment-2467903327\n  if (framework === 'nuxt') {\n    return !optionalEnvToBoolean(process.env.IN_STORYBOOK_SANDBOX);\n  }\n\n  const frameworksWithTemplates: SupportedFramework[] = [\n    SupportedFramework.ANGULAR,\n    SupportedFramework.EMBER,\n    SupportedFramework.HTML_VITE,\n    SupportedFramework.NEXTJS,\n    SupportedFramework.NEXTJS_VITE,\n    SupportedFramework.PREACT_VITE,\n    SupportedFramework.REACT_NATIVE_WEB_VITE,\n    SupportedFramework.REACT_VITE,\n    SupportedFramework.REACT_WEBPACK5,\n    SupportedFramework.SERVER_WEBPACK5,\n    SupportedFramework.SOLID,\n    SupportedFramework.SVELTE_VITE,\n    SupportedFramework.SVELTEKIT,\n    SupportedFramework.VUE3_VITE,\n    SupportedFramework.WEB_COMPONENTS_VITE,\n  ];\n\n  return frameworksWithTemplates.includes(framework as SupportedFramework);\n};\n\nexport async function baseGenerator(\n  packageManager: JsPackageManager,\n  npmOptions: NpmOptions,\n  { language, builder, framework, renderer, pnp, features, dependencyCollector }: GeneratorOptions,\n  _options: FrameworkOptions\n) {\n  const options = { ...defaultOptions, ..._options };\n  const isStorybookInMonorepository = packageManager.isStorybookInMonorepo();\n  const shouldApplyRequireWrapperOnPackageNames = isStorybookInMonorepository || pnp;\n\n  const taskLog = prompt.taskLog({\n    id: 'base-generator',\n    title: 'Generating Storybook configuration',\n  });\n\n  const { frameworkPackagePath, frameworkPackage } = getFrameworkDetails({\n    framework,\n    shouldApplyRequireWrapperOnPackageNames,\n  });\n\n  const {\n    extraAddons = [],\n    extraPackages,\n    staticDir,\n    addScripts,\n    addComponents,\n    extraMain,\n    extensions,\n    storybookConfigFolder,\n    componentsDestinationPath,\n    webpackCompiler,\n    installFrameworkPackages,\n  } = {\n    ...defaultOptions,\n    ...options,\n  };\n\n  // Configure addons using AddonManager\n  const addonManager = new AddonService();\n  const { addonsForMain: addons, addonPackages } = addonManager.configureAddons(\n    features,\n    extraAddons,\n    builder,\n    webpackCompiler\n  );\n\n  const { packageJson } = packageManager.primaryPackageJson;\n\n  const installedDependencies = new Set(\n    Object.keys({ ...packageJson.dependencies, ...packageJson.devDependencies })\n  );\n\n  const extraPackagesToInstall =\n    typeof extraPackages === 'function'\n      ? await extraPackages({\n          builder,\n        })\n      : extraPackages;\n\n  const allPackages = [\n    'storybook',\n    ...(installFrameworkPackages ? [frameworkPackage] : []),\n    ...addonPackages,\n    ...(extraPackagesToInstall || []),\n  ].filter(Boolean);\n\n  const packagesToInstall = [...new Set(allPackages)].filter(\n    (packageToInstall) =>\n      !installedDependencies.has(getPackageDetails(packageToInstall as string)[0])\n  );\n\n  let eslintPluginPackage: string | null = null;\n  try {\n    if (!isCI()) {\n      const { hasEslint, isStorybookPluginInstalled, isFlatConfig, eslintConfigFile } =\n        // TODO: Investigate why packageManager type does not match on CI\n        await extractEslintInfo(packageManager as any);\n\n      if (hasEslint && !isStorybookPluginInstalled) {\n        eslintPluginPackage = 'eslint-plugin-storybook';\n        packagesToInstall.push(eslintPluginPackage);\n        taskLog.message(`- Configuring ESLint plugin`);\n        await configureEslintPlugin({\n          eslintConfigFile,\n          // TODO: Investigate why packageManager type does not match on CI\n          packageManager: packageManager as any,\n          isFlatConfig,\n        });\n      }\n    }\n  } catch (err) {\n    // any failure regarding configuring the eslint plugin should not fail the whole generator\n  }\n\n  const versionedPackages = await packageManager.getVersionedPackages(\n    packagesToInstall as string[]\n  );\n\n  if (versionedPackages.length > 0) {\n    // When using the dependency collector, just collect the packages\n    if (npmOptions.type === 'devDependencies') {\n      dependencyCollector.addDevDependencies(versionedPackages);\n    } else {\n      dependencyCollector.addDependencies(versionedPackages);\n    }\n  }\n\n  await mkdir(`./${storybookConfigFolder}`, { recursive: true });\n\n  // TODO: Evaluate if this is correct after removing pnp compatibility code in SB11\n  const prefixes = shouldApplyRequireWrapperOnPackageNames\n    ? [\n        'import { dirname } from \"path\"',\n        'import { fileURLToPath } from \"url\"',\n        language === SupportedLanguage.JAVASCRIPT\n          ? dedent`/**\n            * This function is used to resolve the absolute path of a package.\n            * It is needed in projects that use Yarn PnP or are set up within a monorepo.\n            */\n            function getAbsolutePath(value) {\n              return dirname(fileURLToPath(import.meta.resolve(\\`\\${value}/package.json\\`)))\n            }`\n          : dedent`/**\n          * This function is used to resolve the absolute path of a package.\n          * It is needed in projects that use Yarn PnP or are set up within a monorepo.\n          */\n          function getAbsolutePath(value: string) {\n            return dirname(fileURLToPath(import.meta.resolve(\\`\\${value}/package.json\\`)))\n          }`,\n      ]\n    : [];\n\n  const configurationFileExtension = language === SupportedLanguage.TYPESCRIPT ? 'ts' : 'js';\n\n  taskLog.message(`- Configuring main.${configurationFileExtension}`);\n  await configureMain({\n    framework: frameworkPackagePath,\n    features,\n    frameworkPackage,\n    prefixes,\n    storybookConfigFolder,\n    addons: shouldApplyRequireWrapperOnPackageNames\n      ? addons.map((addon) => applyAddonGetAbsolutePathWrapper(addon))\n      : addons,\n    extensions,\n    language,\n    ...(staticDir ? { staticDirs: [join('..', staticDir)] } : null),\n    ...extraMain,\n  });\n\n  taskLog.message(`- Configuring preview.${configurationFileExtension}`);\n\n  await configurePreview({\n    frameworkPreviewParts: _options.frameworkPreviewParts,\n    storybookConfigFolder: storybookConfigFolder as string,\n    language,\n    frameworkPackage,\n  });\n\n  if (addScripts) {\n    taskLog.message(`- Adding Storybook command to package.json`);\n    packageManager.addStorybookCommandInScripts({\n      port: 6006,\n    });\n  }\n\n  if (addComponents) {\n    const templateLocation = hasFrameworkTemplates(framework) ? framework : renderer;\n    invariant(templateLocation, `Could not find template location for ${framework} or ${renderer}`);\n\n    taskLog.message(`- Copying framework templates`);\n\n    await copyTemplateFiles({\n      templateLocation,\n      packageManager: packageManager as any,\n      language,\n      destination: componentsDestinationPath,\n      commonAssetsDir: join(\n        dirname(fileURLToPath(import.meta.resolve('create-storybook/package.json'))),\n        'rendererAssets',\n        'common'\n      ),\n      features,\n    });\n  }\n\n  taskLog.success('Storybook configuration generated', { showLog: true });\n\n  return {\n    configDir: storybookConfigFolder,\n    storybookCommand: _options.storybookCommand,\n    shouldRunDev: _options.shouldRunDev,\n  };\n}\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/configure.test.ts",
    "content": "import type { Stats } from 'node:fs';\nimport * as fsp from 'node:fs/promises';\n\nimport { beforeAll, describe, expect, it, vi } from 'vitest';\n\nimport { Feature, SupportedLanguage } from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\n\nimport { configureMain, configurePreview } from './configure.ts';\n\nvi.mock('node:fs/promises');\n\ndescribe('configureMain', () => {\n  beforeAll(() => {\n    vi.clearAllMocks();\n    vi.mocked(fsp.stat).mockRejectedValue({});\n  });\n\n  it('should generate main.js', async () => {\n    await configureMain({\n      language: SupportedLanguage.JAVASCRIPT,\n      addons: [],\n      prefixes: [],\n      storybookConfigFolder: '.storybook',\n      framework: '@storybook/react-vite',\n      frameworkPackage: '@storybook/react-vite',\n      features: new Set([]),\n    });\n\n    const { calls } = vi.mocked(fsp.writeFile).mock;\n    const [mainConfigPath, mainConfigContent] = calls[0];\n\n    expect(mainConfigPath).toEqual('./.storybook/main.js');\n    expect(mainConfigContent).toMatchInlineSnapshot(`\n      \"\n\n      /** @type { import('@storybook/react-vite').StorybookConfig } */\n      const config = {\n        \"stories\": [\n          \"../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)\"\n        ],\n        \"addons\": [],\n        \"framework\": \"@storybook/react-vite\"\n      };\n      export default config;\"\n    `);\n  });\n\n  it('should generate main.ts with docs feature', async () => {\n    await configureMain({\n      language: SupportedLanguage.TYPESCRIPT,\n      addons: [],\n      prefixes: [],\n      storybookConfigFolder: '.storybook',\n      framework: '@storybook/react-vite',\n      frameworkPackage: '@storybook/react-vite',\n      features: new Set([Feature.DOCS]),\n    });\n\n    const { calls } = vi.mocked(fsp.writeFile).mock;\n    const [mainConfigPath, mainConfigContent] = calls[0];\n\n    expect(mainConfigPath).toEqual('./.storybook/main.ts');\n    expect(mainConfigContent).toMatchInlineSnapshot(`\n      \"import type { StorybookConfig } from '@storybook/react-vite';\n\n      const config: StorybookConfig = {\n        \"stories\": [\n          \"../stories/**/*.mdx\",\n          \"../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)\"\n        ],\n        \"addons\": [],\n        \"framework\": \"@storybook/react-vite\"\n      };\n      export default config;\"\n    `);\n  });\n\n  it('should generate main.ts without docs feature', async () => {\n    await configureMain({\n      language: SupportedLanguage.TYPESCRIPT,\n      addons: [],\n      prefixes: [],\n      storybookConfigFolder: '.storybook',\n      framework: '@storybook/react-vite',\n      frameworkPackage: '@storybook/react-vite',\n      features: new Set([]),\n    });\n\n    const { calls } = vi.mocked(fsp.writeFile).mock;\n    const [mainConfigPath, mainConfigContent] = calls[0];\n\n    expect(mainConfigPath).toEqual('./.storybook/main.ts');\n    expect(mainConfigContent).toMatchInlineSnapshot(`\n      \"import type { StorybookConfig } from '@storybook/react-vite';\n\n      const config: StorybookConfig = {\n        \"stories\": [\n          \"../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)\"\n        ],\n        \"addons\": [],\n        \"framework\": \"@storybook/react-vite\"\n      };\n      export default config;\"\n    `);\n  });\n\n  it('should handle resolved paths in pnp', async () => {\n    await configureMain({\n      language: SupportedLanguage.JAVASCRIPT,\n      prefixes: [],\n      addons: [\n        \"%%path.dirname(require.resolve(path.join('@storybook/addon-essentials', 'package.json')))%%\",\n        \"%%path.dirname(require.resolve(path.join('@storybook/preset-create-react-app', 'package.json')))%%\",\n      ],\n      storybookConfigFolder: '.storybook',\n      framework:\n        \"%%path.dirname(require.resolve(path.join('@storybook/react-webpack5', 'package.json')))%%\",\n      frameworkPackage: '@storybook/react-webpack5',\n      features: new Set([Feature.DOCS]),\n    });\n\n    const { calls } = vi.mocked(fsp.writeFile).mock;\n    const [mainConfigPath, mainConfigContent] = calls[0];\n\n    expect(mainConfigPath).toEqual('./.storybook/main.js');\n    expect(mainConfigContent).toMatchInlineSnapshot(`\n      \"import path from 'node:path';\n\n      /** @type { import('@storybook/react-webpack5').StorybookConfig } */\n      const config = {\n        \"stories\": [\n          \"../stories/**/*.mdx\",\n          \"../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)\"\n        ],\n        \"addons\": [\n          path.dirname(require.resolve(path.join('@storybook/addon-essentials', 'package.json'))),\n          path.dirname(require.resolve(path.join('@storybook/preset-create-react-app', 'package.json')))\n        ],\n        \"framework\": path.dirname(require.resolve(path.join('@storybook/react-webpack5', 'package.json')))\n      };\n      export default config;\"\n    `);\n  });\n});\n\ndescribe('configurePreview', () => {\n  it('should generate preview.js', async () => {\n    await configurePreview({\n      language: SupportedLanguage.JAVASCRIPT,\n      storybookConfigFolder: '.storybook',\n      frameworkPackage: '@storybook/react-vite',\n    });\n\n    const { calls } = vi.mocked(fsp.writeFile).mock;\n    const [previewConfigPath, previewConfigContent] = calls[0];\n\n    expect(previewConfigPath).toEqual('./.storybook/preview.js');\n    expect(previewConfigContent).toMatchInlineSnapshot(`\n      \"/** @type { import('@storybook/react-vite').Preview } */\n      const preview = {\n        parameters: {\n          controls: {\n            matchers: {\n             color: /(background|color)$/i,\n             date: /Date$/i,\n            },\n          },\n        },\n      };\n\n      export default preview;\"\n    `);\n  });\n\n  it('should generate preview.ts', async () => {\n    await configurePreview({\n      language: SupportedLanguage.TYPESCRIPT,\n      storybookConfigFolder: '.storybook',\n      frameworkPackage: '@storybook/react-vite',\n    });\n\n    const { calls } = vi.mocked(fsp.writeFile).mock;\n    const [previewConfigPath, previewConfigContent] = calls[0];\n\n    expect(previewConfigPath).toEqual('./.storybook/preview.ts');\n    expect(previewConfigContent).toMatchInlineSnapshot(`\n      \"import type { Preview } from '@storybook/react-vite'\n\n      const preview: Preview = {\n        parameters: {\n          controls: {\n            matchers: {\n             color: /(background|color)$/i,\n             date: /Date$/i,\n            },\n          },\n        },\n      };\n\n      export default preview;\"\n    `);\n  });\n\n  it('should not do anything if the framework template already included a preview', async () => {\n    vi.mocked(fsp.stat).mockResolvedValueOnce({} as Stats);\n    await configurePreview({\n      language: SupportedLanguage.TYPESCRIPT,\n      storybookConfigFolder: '.storybook',\n      frameworkPackage: '@storybook/react-vite',\n    });\n    expect(fsp.writeFile).not.toHaveBeenCalled();\n  });\n\n  it('should add prefix if frameworkParts are passed', async () => {\n    await configurePreview({\n      language: SupportedLanguage.TYPESCRIPT,\n      storybookConfigFolder: '.storybook',\n      frameworkPackage: '@storybook/angular',\n      frameworkPreviewParts: {\n        prefix: dedent`\n        import { setCompodocJson } from \"@storybook/addon-docs/angular\";\n        import docJson from \"../documentation.json\";\n        setCompodocJson(docJson);\n      `,\n      },\n    });\n\n    const { calls } = vi.mocked(fsp.writeFile).mock;\n    const [previewConfigPath, previewConfigContent] = calls[0];\n\n    expect(previewConfigPath).toEqual('./.storybook/preview.ts');\n    expect(previewConfigContent).toMatchInlineSnapshot(`\n      \"import type { Preview } from '@storybook/angular'\n      import { setCompodocJson } from \"@storybook/addon-docs/angular\";\n      import docJson from \"../documentation.json\";\n      setCompodocJson(docJson);\n\n      const preview: Preview = {\n        parameters: {\n          controls: {\n            matchers: {\n             color: /(background|color)$/i,\n             date: /Date$/i,\n            },\n          },\n        },\n      };\n\n      export default preview;\"\n    `);\n  });\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/configure.ts",
    "content": "import { stat, writeFile } from 'node:fs/promises';\nimport { resolve } from 'node:path';\n\nimport { logger } from 'storybook/internal/node-logger';\nimport { Feature, SupportedLanguage } from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\n\ninterface ConfigureMainOptions {\n  addons: string[];\n  extensions?: string[];\n  staticDirs?: string[];\n  storybookConfigFolder: string;\n  language: SupportedLanguage;\n  prefixes: string[];\n  frameworkPackage: string;\n  features: Set<Feature>;\n  /**\n   * Extra values for main.js\n   *\n   * In order to provide non-serializable data like functions, you can use `{ value:\n   * '%%yourFunctionCall()%%' }`\n   *\n   * `%%` and `%%` will be replaced.\n   */\n  [key: string]: any;\n}\n\nexport interface FrameworkPreviewParts {\n  prefix: string;\n}\n\ninterface ConfigurePreviewOptions {\n  frameworkPreviewParts?: FrameworkPreviewParts;\n  storybookConfigFolder: string;\n  language: SupportedLanguage;\n  frameworkPackage?: string;\n}\n\nconst pathExists = async (path: string) => {\n  return stat(path)\n    .then(() => true)\n    .catch(() => false);\n};\n\nexport async function configureMain({\n  addons,\n  extensions = ['js', 'jsx', 'mjs', 'ts', 'tsx'],\n  storybookConfigFolder,\n  language,\n  frameworkPackage,\n  prefixes = [],\n  features,\n  ...custom\n}: ConfigureMainOptions) {\n  const srcPath = resolve(storybookConfigFolder, '../src');\n  const prefix = (await pathExists(srcPath)) ? '../src' : '../stories';\n  const stories = features.has(Feature.DOCS) ? [`${prefix}/**/*.mdx`] : [];\n\n  stories.push(`${prefix}/**/*.stories.@(${extensions.join('|')})`);\n\n  const config = {\n    stories,\n    addons,\n    ...custom,\n  };\n\n  const isTypescript = language === SupportedLanguage.TYPESCRIPT;\n\n  let mainConfigTemplate = dedent`<<import>><<prefix>>const config<<type>> = <<mainContents>>;\n    export default config;`;\n\n  if (!frameworkPackage) {\n    mainConfigTemplate = mainConfigTemplate.replace('<<import>>', '').replace('<<type>>', '');\n    logger.warn('Could not find framework package name');\n  }\n\n  const mainContents = JSON.stringify(config, null, 2)\n    .replace(/['\"]%%/g, '')\n    .replace(/%%['\"]/g, '');\n\n  const imports = [];\n  const finalPrefixes = [...prefixes];\n\n  if (custom.framework.includes('path.dirname(')) {\n    imports.push(`import path from 'node:path';`);\n  }\n\n  if (isTypescript) {\n    imports.push(`import type { StorybookConfig } from '${frameworkPackage}';`);\n  } else {\n    finalPrefixes.push(`/** @type { import('${frameworkPackage}').StorybookConfig } */`);\n  }\n\n  let mainJsContents = '';\n  mainJsContents = mainConfigTemplate\n    .replace('<<import>>', `${imports.join('\\n\\n')}\\n\\n`)\n    .replace('<<prefix>>', finalPrefixes.length > 0 ? `${finalPrefixes.join('\\n\\n')}\\n` : '')\n    .replace('<<type>>', isTypescript ? ': StorybookConfig' : '')\n    .replace('<<mainContents>>', mainContents);\n\n  const mainPath = `./${storybookConfigFolder}/main.${isTypescript ? 'ts' : 'js'}`;\n\n  await writeFile(mainPath, mainJsContents, { encoding: 'utf8' });\n\n  return { mainPath };\n}\n\nexport async function configurePreview(options: ConfigurePreviewOptions) {\n  const { prefix: frameworkPrefix = '' } = options.frameworkPreviewParts || {};\n  const isTypescript = options.language === SupportedLanguage.TYPESCRIPT;\n\n  const previewConfigPath = `./${options.storybookConfigFolder}/preview.${isTypescript ? 'ts' : 'js'}`;\n\n  // If the framework template included a preview then we have nothing to do\n  if (await pathExists(previewConfigPath)) {\n    return { previewConfigPath };\n  }\n\n  const frameworkPackage = options.frameworkPackage;\n\n  const prefix = [\n    isTypescript && frameworkPackage ? `import type { Preview } from '${frameworkPackage}'` : '',\n    frameworkPrefix,\n  ]\n    .filter(Boolean)\n    .join('\\n');\n\n  let preview = '';\n  preview = dedent`\n    ${prefix}${prefix.length > 0 ? '\\n' : ''}\n    ${\n      !isTypescript && frameworkPackage\n        ? `/** @type { import('${frameworkPackage}').Preview } */\\n`\n        : ''\n    }const preview${isTypescript ? ': Preview' : ''} = {\n      parameters: {\n        controls: {\n          matchers: {\n           color: /(background|color)$/i,\n           date: /Date$/i,\n          },\n        },\n      },\n    };\n    \n    export default preview;\n    `\n    .replace('  \\n', '')\n    .trim();\n\n  await writeFile(previewConfigPath, preview, { encoding: 'utf8' });\n\n  return { previewConfigPath };\n}\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/index.ts",
    "content": "/**\n * Generator registry and utilities\n *\n * Provides a centralized way to manage and access Storybook generators\n */\n\nexport { GeneratorRegistry, generatorRegistry } from './GeneratorRegistry.ts';\n\nexport { registerAllGenerators } from './registerGenerators.ts';\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/modules/GeneratorModule.ts",
    "content": "import type { GeneratorModule } from '../types.ts';\n\nexport function defineGeneratorModule<T extends GeneratorModule>(generatorModule: T) {\n  return generatorModule;\n}\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/registerGenerators.ts",
    "content": "import angularGenerator from './ANGULAR/index.ts';\nimport emberGenerator from './EMBER/index.ts';\nimport { generatorRegistry } from './GeneratorRegistry.ts';\nimport htmlGenerator from './HTML/index.ts';\nimport nextjsGenerator from './NEXTJS/index.ts';\nimport nuxtGenerator from './NUXT/index.ts';\nimport preactGenerator from './PREACT/index.ts';\nimport qwikGenerator from './QWIK/index.ts';\nimport reactGenerator from './REACT/index.ts';\nimport reactNativeGenerator from './REACT_NATIVE/index.ts';\nimport reactNativeAndRNWGenerator from './REACT_NATIVE_AND_RNW/index.ts';\nimport reactNativeWebGenerator from './REACT_NATIVE_WEB/index.ts';\nimport reactScriptsGenerator from './REACT_SCRIPTS/index.ts';\nimport serverGenerator from './SERVER/index.ts';\nimport solidGenerator from './SOLID/index.ts';\nimport svelteGenerator from './SVELTE/index.ts';\nimport svelteKitGenerator from './SVELTEKIT/index.ts';\nimport vue3Generator from './VUE3/index.ts';\nimport webComponentsGenerator from './WEB-COMPONENTS/index.ts';\nimport type { GeneratorModule } from './types.ts';\n\nconst setOfGenerators = new Set<GeneratorModule>([\n  reactGenerator,\n  reactScriptsGenerator,\n  reactNativeGenerator,\n  reactNativeWebGenerator,\n  reactNativeAndRNWGenerator,\n  vue3Generator,\n  nuxtGenerator,\n  angularGenerator,\n  nextjsGenerator,\n  svelteGenerator,\n  svelteKitGenerator,\n  emberGenerator,\n  htmlGenerator,\n  webComponentsGenerator,\n  preactGenerator,\n  solidGenerator,\n  serverGenerator,\n  qwikGenerator,\n]);\n\n/** Register all framework generators with the central registry */\nexport function registerAllGenerators(): void {\n  setOfGenerators.forEach((generator) => {\n    generatorRegistry.register(generator);\n  });\n}\n"
  },
  {
    "path": "code/lib/create-storybook/src/generators/types.ts",
    "content": "import type { NpmOptions, ProjectType } from 'storybook/internal/cli';\nimport type { JsPackageManager, PackageManagerName } from 'storybook/internal/common';\nimport type { ConfigFile } from 'storybook/internal/csf-tools';\nimport type {\n  Feature,\n  StorybookConfig,\n  SupportedBuilder,\n  SupportedFramework,\n  SupportedLanguage,\n  SupportedRenderer,\n} from 'storybook/internal/types';\n\nimport type { DependencyCollector } from '../dependency-collector.ts';\nimport type { FrameworkPreviewParts } from './configure.ts';\n\nexport type GeneratorOptions = {\n  language: SupportedLanguage;\n  builder: SupportedBuilder;\n  framework: SupportedFramework;\n  renderer: SupportedRenderer;\n  linkable: boolean;\n  // TODO: Remove in SB11\n  pnp: boolean;\n  frameworkPreviewParts?: FrameworkPreviewParts;\n  // skip prompting the user\n  yes: boolean;\n  features: Set<Feature>;\n  dependencyCollector: DependencyCollector;\n};\n\nexport interface FrameworkOptions {\n  extraPackages?: string[] | ((details: { builder: SupportedBuilder }) => Promise<string[]>);\n  extraAddons?: string[];\n  staticDir?: string;\n  addScripts?: boolean;\n  addComponents?: boolean;\n  webpackCompiler?: ({ builder }: { builder: SupportedBuilder }) => 'babel' | 'swc' | undefined;\n  extraMain?: any;\n  extensions?: string[];\n  storybookConfigFolder?: string;\n  componentsDestinationPath?: string;\n  installFrameworkPackages?: boolean;\n  skipGenerator?: boolean;\n  storybookCommand?: string | null;\n  shouldRunDev?: boolean;\n  frameworkPreviewParts?: FrameworkPreviewParts;\n}\n\nexport type Generator<T = Record<string, any>> = (\n  packageManagerInstance: JsPackageManager,\n  npmOptions: NpmOptions,\n  generatorOptions: GeneratorOptions,\n  commandOptions?: CommandOptions\n) => Promise<\n  {\n    rendererPackage: string;\n    builderPackage: string;\n    frameworkPackage: string;\n    configDir: string;\n    mainConfig?: StorybookConfig;\n    mainConfigCSFFile?: ConfigFile;\n    previewConfigPath?: string;\n  } & T\n>;\n\n// New generator interface for configuration-based generators\n\nexport interface GeneratorMetadata {\n  projectType: ProjectType;\n  renderer: SupportedRenderer;\n  /**\n   * If the framework is a function, it will be called with the detected builder to determine the\n   * framework. This is useful for project types that support multiple frameworks based on the\n   * builder (e.g., Next.js with Vite vs Webpack).\n   */\n  framework?: SupportedFramework | null | ((builder: SupportedBuilder) => SupportedFramework);\n  /**\n   * If the builder is a function, it will be called to determine the builder. This is useful for\n   * generators that need to determine the builder based on the project type in cases where the\n   * builder cannot be detected (Webpack and Vite are both non-existent dependencies).\n   */\n  builderOverride?: SupportedBuilder | (() => SupportedBuilder | Promise<SupportedBuilder>);\n}\n\nexport interface GeneratorContext {\n  framework: SupportedFramework | null | undefined;\n  renderer: SupportedRenderer;\n  builder: SupportedBuilder;\n  language: SupportedLanguage;\n  features: Set<Feature>;\n  dependencyCollector: DependencyCollector;\n  linkable?: boolean;\n  yes?: boolean;\n}\n\nexport interface GeneratorModule {\n  /** Metadata about the generator This is used to register the generator with the generator registry */\n  metadata: GeneratorMetadata;\n  /**\n   * The function that configures the generator This is used to configure the generator It returns a\n   * promise that resolves to the framework options\n   */\n  configure: (\n    packageManager: JsPackageManager,\n    context: GeneratorContext\n  ) => Promise<FrameworkOptions>;\n  /**\n   * The function that runs after the generator is configured. This is used to run any\n   * post-configuration tasks\n   */\n  postConfigure?: ({\n    packageManager,\n  }: {\n    packageManager: JsPackageManager;\n  }) => Promise<void> | void;\n}\n\nexport type CommandOptions = {\n  packageManager: PackageManagerName;\n  usePnp?: boolean;\n  features?: Array<Feature>;\n  type?: ProjectType;\n  force?: any;\n  html?: boolean;\n  skipInstall?: boolean;\n  language?: SupportedLanguage;\n  parser?: string;\n  // Automatically answer yes to prompts\n  yes?: boolean;\n  builder?: SupportedBuilder;\n  linkable?: boolean;\n  disableTelemetry?: boolean;\n  enableCrashReports?: boolean;\n  debug?: boolean;\n  dev?: boolean;\n  logfile?: string | boolean;\n};\n"
  },
  {
    "path": "code/lib/create-storybook/src/index.ts",
    "content": "export { doInitiate as initiate } from './initiate.ts';\n"
  },
  {
    "path": "code/lib/create-storybook/src/initiate.test.ts",
    "content": "/**\n * NOTE: These tests use the VersionService from the refactored implementation. The promptNewUser\n * and promptInstallType functions are tested in:\n *\n * - Services/VersionService.test.ts (for version detection)\n * - Commands/UserPreferencesCommand.test.ts (for user prompts)\n */\nimport { describe, expect, it, vi } from 'vitest';\n\nimport { VersionService } from './services/VersionService.ts';\n\n// Create a version service instance for testing\nconst versionService = new VersionService();\nconst getStorybookVersionFromAncestry =\n  versionService.getStorybookVersionFromAncestry.bind(versionService);\nconst getCliIntegrationFromAncestry =\n  versionService.getCliIntegrationFromAncestry.bind(versionService);\n\nvi.mock('storybook/internal/telemetry');\n\nvi.mock('storybook/internal/core-server', () => ({\n  getServerPort: vi.fn().mockResolvedValue(6006),\n}));\n\ndescribe('getStorybookVersionFromAncestry', () => {\n  it('possible storybook path', () => {\n    const ancestry = [{ command: 'node' }, { command: 'storybook@7.0.0' }, { command: 'npm' }];\n    expect(getStorybookVersionFromAncestry(ancestry as any)).toBeUndefined();\n  });\n\n  it('create storybook', () => {\n    const ancestry = [\n      { command: 'node' },\n      { command: 'npm create storybook@7.0.0-alpha.3' },\n      { command: 'npm' },\n    ];\n    expect(getStorybookVersionFromAncestry(ancestry as any)).toBe('7.0.0-alpha.3');\n  });\n\n  it('storybook init', () => {\n    const ancestry = [\n      { command: 'node' },\n      { command: 'npx storybook@7.0.0 init' },\n      { command: 'npm' },\n    ];\n    expect(getStorybookVersionFromAncestry(ancestry as any)).toBe('7.0.0');\n  });\n\n  it('storybook init no version', () => {\n    const ancestry = [{ command: 'node' }, { command: 'npx storybook init' }, { command: 'npm' }];\n    expect(getStorybookVersionFromAncestry(ancestry as any)).toBeUndefined();\n  });\n\n  it('create-storybook with latest', () => {\n    const ancestry = [\n      { command: 'node' },\n      { command: 'npx create-storybook@latest' },\n      { command: 'npm' },\n    ];\n    expect(getStorybookVersionFromAncestry(ancestry as any)).toBe('latest');\n  });\n\n  it('foo-storybook with latest', () => {\n    const ancestry = [\n      { command: 'node' },\n      { command: 'npx foo-storybook@latest' },\n      { command: 'npm' },\n    ];\n    expect(getStorybookVersionFromAncestry(ancestry as any)).toBeUndefined();\n  });\n\n  it('multiple matches', () => {\n    const ancestry = [\n      { command: 'node' },\n      { command: 'npx create-storybook@foo' },\n      { command: 'npm' },\n      { command: 'npx create-storybook@bar' },\n    ];\n    expect(getStorybookVersionFromAncestry(ancestry as any)).toBe('bar');\n  });\n\n  it('returns undefined if no storybook version found', () => {\n    const ancestry = [{ command: 'node' }, { command: 'npm' }];\n    expect(getStorybookVersionFromAncestry(ancestry as any)).toBeUndefined();\n  });\n});\n\ndescribe('getCliIntegrationFromAncestry', () => {\n  it('returns the CLI integration if nested calls', () => {\n    const ancestry = [{ command: 'node' }, { command: 'npx sv add' }, { command: 'npx sv create' }];\n    expect(getCliIntegrationFromAncestry(ancestry as any)).toBe('sv create');\n  });\n\n  it('returns the CLI integration if found', () => {\n    const ancestry = [{ command: 'node' }, { command: 'npx sv add' }];\n    expect(getCliIntegrationFromAncestry(ancestry as any)).toBe('sv add');\n  });\n\n  it('returns the CLI integration if found', () => {\n    const ancestry = [{ command: 'node' }, { command: 'npx sv@latest add' }];\n    expect(getCliIntegrationFromAncestry(ancestry as any)).toBe('sv add');\n  });\n\n  it('returns undefined if no CLI integration found', () => {\n    const ancestry = [{ command: 'node' }, { command: 'npm' }];\n    expect(getCliIntegrationFromAncestry(ancestry as any)).toBeUndefined();\n  });\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/initiate.ts",
    "content": "import { ProjectType } from 'storybook/internal/cli';\nimport {\n  type JsPackageManager,\n  PackageManagerName,\n  executeCommand,\n} from 'storybook/internal/common';\nimport { getServerPort, withTelemetry } from 'storybook/internal/core-server';\nimport { logTracker, logger } from 'storybook/internal/node-logger';\n\nimport {\n  executeAddonConfiguration,\n  executeDependencyInstallation,\n  executeFinalization,\n  executeFrameworkDetection,\n  executeGeneratorExecution,\n  executePreflightCheck,\n  executeProjectDetection,\n  executeUserPreferences,\n} from './commands/index.ts';\nimport { DependencyCollector } from './dependency-collector.ts';\nimport { registerAllGenerators } from './generators/index.ts';\nimport type { CommandOptions } from './generators/types.ts';\nimport { FeatureCompatibilityService } from './services/FeatureCompatibilityService.ts';\nimport { TelemetryService } from './services/TelemetryService.ts';\n\n/**\n * Main entry point for Storybook initialization\n *\n * This is a clean, command-based orchestration that replaces the monolithic 986-line implementation\n * with a modular, testable approach.\n */\nexport async function doInitiate(options: CommandOptions): Promise<\n  | {\n      shouldRunDev: true;\n      shouldOnboard: boolean;\n      projectType: ProjectType;\n      packageManager: JsPackageManager;\n      storybookCommand?: string | null;\n    }\n  | { shouldRunDev: false }\n> {\n  // Initialize services\n  const telemetryService = new TelemetryService(options.disableTelemetry);\n\n  // Register all framework generators\n  registerAllGenerators();\n\n  let dependencyCollector: DependencyCollector | null = new DependencyCollector();\n\n  // Step 1: Run preflight checks\n  const { packageManager } = await executePreflightCheck(options);\n\n  // Step 2: Detect project type\n  const { projectType, language } = await executeProjectDetection(packageManager, options);\n\n  // Step 3: Detect framework, renderer, and builder\n  const { framework, builder, renderer } = await executeFrameworkDetection(\n    projectType,\n    packageManager,\n    options\n  );\n\n  // Step 4: Get user preferences and feature selections (with framework/builder for validation)\n  const { newUser, selectedFeatures } = await executeUserPreferences({\n    packageManager,\n    options,\n    framework,\n    builder,\n    projectType,\n  });\n\n  // Step 5: Execute generator with dependency collector (now with frameworkInfo)\n\n  const { configDir, storybookCommand, shouldRunDev, extraAddons } =\n    await executeGeneratorExecution({\n      projectType,\n      packageManager,\n      frameworkInfo: { builder, framework, renderer },\n      options,\n      dependencyCollector,\n      selectedFeatures,\n      language,\n    });\n\n  // Step 6: Install all dependencies in a single operation\n  const dependencyInstallationResult = await executeDependencyInstallation({\n    packageManager,\n    dependencyCollector,\n    skipInstall: !!options.skipInstall,\n    selectedFeatures,\n  });\n\n  // After dependencies are installed, we must not use the dependency collector anymore\n  dependencyCollector = null;\n\n  // Step 7: Configure addons (run postinstall scripts for configuration only)\n  await executeAddonConfiguration({\n    packageManager,\n    addons: extraAddons,\n    configDir,\n    options,\n  });\n\n  // Step 8: Print final summary\n  await executeFinalization({\n    logfile: options.logfile,\n    storybookCommand,\n  });\n\n  // Step 9: Track telemetry\n  await telemetryService.trackInitWithContext(projectType, selectedFeatures, newUser);\n\n  return {\n    shouldRunDev:\n      !!options.dev &&\n      !options.skipInstall &&\n      shouldRunDev !== false &&\n      dependencyInstallationResult.status === 'success',\n    shouldOnboard: newUser,\n    projectType,\n    packageManager,\n    storybookCommand,\n  };\n}\n\nconst handleCommandFailure = async (logFilePath: string | boolean | undefined): Promise<never> => {\n  const logFile = await logTracker.writeToFile(logFilePath);\n  logger.error('Storybook encountered an error during initialization');\n  logger.log(`Debug logs are written to: ${logFile}`);\n  logger.outro('Storybook exited with an error');\n  process.exit(1);\n};\n\n// cli command -> ctrl c -> exit 0\n// process.on('SIGINT', () => {\n// })\n\n/** Main initiate function with telemetry wrapper */\nexport async function initiate(options: CommandOptions): Promise<void> {\n  const initiateResult = await withTelemetry(\n    'init',\n    {\n      cliOptions: options,\n      printError: (err) => !err.handled && logger.error(err),\n    },\n    async () => {\n      const result = await doInitiate(options);\n\n      logger.outro('');\n\n      return result;\n    }\n  ).catch(() => {\n    handleCommandFailure(options.logfile);\n  });\n\n  if (initiateResult?.shouldRunDev) {\n    await runStorybookDev(initiateResult);\n  }\n}\n\n/** Run Storybook dev server after installation */\nasync function runStorybookDev(result: {\n  projectType: ProjectType;\n  packageManager: JsPackageManager;\n  storybookCommand?: string | null;\n  shouldOnboard: boolean;\n}): Promise<void> {\n  const { projectType, packageManager, storybookCommand, shouldOnboard } = result;\n\n  if (!storybookCommand) {\n    return;\n  }\n\n  try {\n    const supportsOnboarding = FeatureCompatibilityService.supportsOnboarding(projectType);\n\n    const parts = storybookCommand.split(' ');\n\n    // Angular CLI throws \"Unknown argument: silent\"\n    if (packageManager.type === 'npm' && projectType !== ProjectType.ANGULAR) {\n      parts.push('--silent');\n    }\n\n    // in the case of Angular, we are calling `ng run` which doesn't allow passing flags to the command\n    const supportSbFlags = projectType !== ProjectType.ANGULAR;\n\n    if (supportSbFlags) {\n      // npm needs extra -- to pass flags to the command\n      const doesNeedExtraDash =\n        packageManager.type === PackageManagerName.NPM ||\n        packageManager.type === PackageManagerName.BUN;\n\n      if (doesNeedExtraDash) {\n        parts.push('--');\n      }\n\n      const defaultPort = 6006;\n      const availablePort = await getServerPort(defaultPort);\n      const useAlternativePort = availablePort !== defaultPort;\n\n      if (useAlternativePort) {\n        parts.push(`-p`, `${availablePort}`);\n      }\n\n      if (supportsOnboarding && shouldOnboard) {\n        parts.push('--initial-path=/onboarding');\n      }\n\n      parts.push('--quiet');\n    }\n\n    // instead of calling 'dev' automatically, we spawn a subprocess so that it gets\n    // executed directly in the user's project directory. This avoid potential issues\n    // with packages running in npxs' node_modules\n    const [command, ...args] = [...parts];\n\n    await executeCommand({\n      command: command,\n      args,\n      stdio: 'inherit',\n    });\n  } catch {\n    // Do nothing here, as the command above will spawn a `storybook dev` process which does the error handling already\n  }\n}\n"
  },
  {
    "path": "code/lib/create-storybook/src/scaffold-new-project.ts",
    "content": "import { readdirSync } from 'node:fs';\nimport { rm } from 'node:fs/promises';\n\nimport { type PackageManagerName, executeCommand } from 'storybook/internal/common';\nimport { logger, prompt } from 'storybook/internal/node-logger';\nimport { GenerateNewProjectOnInitError } from 'storybook/internal/server-errors';\nimport { telemetry } from 'storybook/internal/telemetry';\n\nimport type { CommandOptions } from './generators/types.ts';\n\ntype CoercedPackageManagerName = 'npm' | 'yarn' | 'pnpm';\n\ninterface SupportedProject {\n  displayName: {\n    type: string;\n    builder?: string;\n    language: string;\n  };\n  createScript: Record<CoercedPackageManagerName, string>;\n}\n\n/** The supported projects. */\nconst SUPPORTED_PROJECTS: Record<string, SupportedProject> = {\n  'react-vite-ts': {\n    displayName: {\n      type: 'React',\n      builder: 'Vite',\n      language: 'TS',\n    },\n    createScript: {\n      npm: 'npm create vite@latest . -- --template react-ts',\n      yarn: 'yarn create vite . --template react-ts',\n      pnpm: 'pnpm create vite@latest . --template react-ts',\n    },\n  },\n  'nextjs-ts': {\n    displayName: {\n      type: 'Next.js',\n      language: 'TS',\n    },\n    createScript: {\n      npm: 'npm create next-app . -- --turbopack --typescript --use-npm --eslint --tailwind --no-app --import-alias=\"@/*\" --src-dir --no-react-compiler',\n      // yarn doesn't support version ranges, so we have to use npx\n      yarn: 'npx create-next-app . --turbopack --typescript --use-yarn --eslint --tailwind --no-app --import-alias=\"@/*\" --src-dir --no-react-compiler',\n      pnpm: 'pnpm create next-app . --turbopack --typescript --use-pnpm --eslint --tailwind --no-app --import-alias=\"@/*\" --src-dir --no-react-compiler',\n    },\n  },\n  'vue-vite-ts': {\n    displayName: {\n      type: 'Vue 3',\n      builder: 'Vite',\n      language: 'TS',\n    },\n    createScript: {\n      npm: 'npm create vite@latest . -- --template vue-ts',\n      yarn: 'yarn create vite . --template vue-ts',\n      pnpm: 'pnpm create vite@latest . --template vue-ts',\n    },\n  },\n  'angular-cli': {\n    displayName: {\n      type: 'Angular',\n      language: 'TS',\n    },\n    createScript: {\n      npm: 'npx -p @angular/cli@latest ng new angular-latest --directory . --routing=true --minimal=true --style=scss --strict --skip-git --skip-install',\n      yarn: 'yarn dlx -p @angular/cli ng new angular-latest --directory . --routing=true --minimal=true --style=scss --strict --skip-git --package-manager=yarn --skip-install && touch yarn.lock && yarn set version berry && yarn config set nodeLinker node-modules',\n      pnpm: 'pnpm --package @angular/cli dlx ng new angular-latest --directory . --routing=true --minimal=true --style=scss --strict --skip-git --package-manager=pnpm --skip-install',\n    },\n  },\n  'lit-vite-ts': {\n    displayName: {\n      type: 'Lit',\n      builder: 'Vite',\n      language: 'TS',\n    },\n    createScript: {\n      npm: 'npm create vite@latest . -- --template lit-ts',\n      yarn: 'yarn create vite . --template lit-ts && touch yarn.lock && yarn set version berry && yarn config set nodeLinker pnp',\n      pnpm: 'pnpm create vite@latest . --template lit-ts',\n    },\n  },\n};\n\nconst packageManagerToCoercedName = (\n  packageManager: PackageManagerName\n): CoercedPackageManagerName => {\n  switch (packageManager) {\n    case 'npm':\n      return 'npm';\n    case 'pnpm':\n      return 'pnpm';\n    default:\n      return 'yarn';\n  }\n};\n\nconst buildProjectDisplayNameForPrint = ({ displayName }: SupportedProject) => {\n  const { type, builder, language } = displayName;\n  return `${type} ${builder ? `+ ${builder} ` : ''}(${language})`;\n};\n\n/**\n * Scaffold a new project.\n *\n * @param packageManager The package manager to use.\n */\nexport const scaffoldNewProject = async (\n  packageManager: PackageManagerName,\n  { disableTelemetry }: CommandOptions\n) => {\n  const packageManagerName = packageManagerToCoercedName(packageManager);\n\n  let projectStrategy;\n\n  if (process.env.STORYBOOK_INIT_EMPTY_TYPE) {\n    projectStrategy = process.env.STORYBOOK_INIT_EMPTY_TYPE;\n  }\n\n  if (!projectStrategy) {\n    projectStrategy = await prompt.select({\n      message: 'Empty directory detected:',\n      options: [\n        ...Object.entries(SUPPORTED_PROJECTS).map(([key, value]) => ({\n          label: buildProjectDisplayNameForPrint(value),\n          value: key,\n        })),\n        {\n          label: 'Other',\n          value: 'other',\n          hint: 'To install Storybook on another framework, first generate a project with that framework and then rerun this command.',\n        },\n      ],\n    });\n  }\n\n  if (projectStrategy === 'other') {\n    if (!disableTelemetry) {\n      await telemetry(\n        'exit',\n        { eventType: 'init', reason: 'scaffold-other' },\n        { stripMetadata: true, immediate: true }\n      );\n    }\n    logger.warn(\n      'To install Storybook on another framework, first generate a project with that framework and then rerun this command.'\n    );\n    logger.outro('Exiting...');\n    process.exit(1);\n  }\n\n  const projectStrategyConfig = SUPPORTED_PROJECTS[projectStrategy];\n  const projectDisplayName = buildProjectDisplayNameForPrint(projectStrategyConfig);\n  const createScript = projectStrategyConfig.createScript[packageManagerName];\n\n  const spinner = prompt.spinner({\n    id: 'create-new-project',\n  });\n\n  spinner.start(`Creating a new \"${projectDisplayName}\" project with ${packageManagerName}...`);\n\n  const targetDir = process.cwd();\n\n  try {\n    // If target directory has a .cache folder, remove it\n    // so that it does not block the creation of the new project\n    await rm(`${targetDir}/.cache`, { recursive: true, force: true });\n  } catch (e) {\n    //\n  }\n  try {\n    // If target directory has a node_modules folder, remove it\n    // so that it does not block the creation of the new project\n    await rm(`${targetDir}/node_modules`, { recursive: true, force: true });\n  } catch (e) {\n    //\n  }\n\n  try {\n    // Create new project in temp directory\n    spinner.message(`Executing ${createScript}`);\n    await executeCommand({\n      command: createScript,\n      shell: true,\n      stdio: 'pipe',\n      cwd: targetDir,\n    });\n  } catch (e) {\n    spinner.error(\n      `Failed to create a new \"${projectDisplayName}\" project with ${packageManagerName}`\n    );\n    throw new GenerateNewProjectOnInitError({\n      error: e,\n      packageManager: packageManagerName,\n      projectType: projectStrategy,\n    });\n  }\n\n  spinner.stop(`${projectDisplayName} project with ${packageManagerName} created successfully!`);\n\n  if (!disableTelemetry) {\n    await telemetry('scaffolded-empty', {\n      packageManager: packageManagerName,\n      projectType: projectStrategy,\n    });\n  }\n};\n\nconst FILES_TO_IGNORE = [\n  '.git',\n  '.gitignore',\n  '.DS_Store',\n  '.cache',\n  'node_modules',\n  '.yarnrc.yml',\n  '.yarn',\n];\n\nexport const currentDirectoryIsEmpty = () => {\n  const cwdFolderEntries = readdirSync(process.cwd());\n\n  return (\n    cwdFolderEntries.length === 0 ||\n    cwdFolderEntries.every((entry) => FILES_TO_IGNORE.includes(entry))\n  );\n};\n"
  },
  {
    "path": "code/lib/create-storybook/src/services/AddonService.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { Feature, SupportedBuilder } from 'storybook/internal/types';\n\nimport { AddonService } from './AddonService.ts';\n\nvi.mock('storybook/internal/common', async () => {\n  const actual = await vi.importActual('storybook/internal/common');\n  return {\n    ...actual,\n    getPackageDetails: vi.fn().mockImplementation((pkg: string) => {\n      const match = pkg.match(/^(@?[^@]+)(?:@(.+))?$/);\n      return match ? [match[1], match[2]] : [pkg, undefined];\n    }),\n  };\n});\n\ndescribe('AddonService', () => {\n  let manager: AddonService;\n\n  beforeEach(() => {\n    manager = new AddonService();\n  });\n\n  describe('getWebpackCompilerAddon', () => {\n    it('should return undefined when no compiler function provided', () => {\n      const result = manager.getWebpackCompilerAddon(SupportedBuilder.WEBPACK5, undefined);\n      expect(result).toBeUndefined();\n    });\n\n    it('should return undefined when compiler function returns undefined', () => {\n      const webpackCompiler = vi.fn().mockReturnValue(undefined);\n      const result = manager.getWebpackCompilerAddon(SupportedBuilder.WEBPACK5, webpackCompiler);\n      expect(result).toBeUndefined();\n    });\n\n    it('should return swc compiler addon', () => {\n      const webpackCompiler = vi.fn().mockReturnValue('swc');\n      const result = manager.getWebpackCompilerAddon(SupportedBuilder.WEBPACK5, webpackCompiler);\n      expect(result).toBe('@storybook/addon-webpack5-compiler-swc');\n    });\n\n    it('should return babel compiler addon', () => {\n      const webpackCompiler = vi.fn().mockReturnValue('babel');\n      const result = manager.getWebpackCompilerAddon(SupportedBuilder.WEBPACK5, webpackCompiler);\n      expect(result).toBe('@storybook/addon-webpack5-compiler-babel');\n    });\n  });\n\n  describe('getAddonsForFeatures', () => {\n    it('should return empty array for no features', () => {\n      const addons = manager.getAddonsForFeatures(new Set([]));\n      expect(addons).toEqual([]);\n    });\n\n    it('should add chromatic and vitest addons for test feature', () => {\n      const addons = manager.getAddonsForFeatures(new Set([Feature.TEST]));\n      expect(addons).toContain('@chromatic-com/storybook');\n      expect(addons).toContain('@storybook/addon-vitest');\n    });\n\n    it('should add docs addon for docs feature', () => {\n      const addons = manager.getAddonsForFeatures(new Set([Feature.DOCS]));\n      expect(addons).toContain('@storybook/addon-docs');\n    });\n\n    it('should add onboarding addon for onboarding feature', () => {\n      const addons = manager.getAddonsForFeatures(new Set([Feature.ONBOARDING]));\n      expect(addons).toContain('@storybook/addon-onboarding');\n    });\n\n    it('should add a11y addon for a11y feature', () => {\n      const addons = manager.getAddonsForFeatures(new Set([Feature.A11Y]));\n      expect(addons).toContain('@storybook/addon-a11y');\n    });\n\n    it('should add all addons for all features', () => {\n      const addons = manager.getAddonsForFeatures(\n        new Set([Feature.DOCS, Feature.TEST, Feature.ONBOARDING, Feature.A11Y])\n      );\n      expect(addons).toContain('@storybook/addon-docs');\n      expect(addons).toContain('@chromatic-com/storybook');\n      expect(addons).toContain('@storybook/addon-vitest');\n      expect(addons).toContain('@storybook/addon-onboarding');\n      expect(addons).toContain('@storybook/addon-a11y');\n    });\n  });\n\n  describe('stripVersions', () => {\n    it('should strip version from addon names', () => {\n      const addons = ['@storybook/addon-essentials@8.0.0', '@storybook/addon-links@8.0.0'];\n      const stripped = manager.stripVersions(addons);\n\n      expect(stripped).toEqual(['@storybook/addon-essentials', '@storybook/addon-links']);\n    });\n\n    it('should handle addons without versions', () => {\n      const addons = ['@storybook/addon-essentials', '@storybook/addon-links'];\n      const stripped = manager.stripVersions(addons);\n\n      expect(stripped).toEqual(['@storybook/addon-essentials', '@storybook/addon-links']);\n    });\n  });\n\n  describe('configureAddons', () => {\n    it('should include compiler addon when specified', () => {\n      const webpackCompiler = vi.fn().mockReturnValue('swc');\n      const config = manager.configureAddons(\n        new Set([Feature.DOCS]),\n        [],\n        SupportedBuilder.WEBPACK5,\n        webpackCompiler\n      );\n\n      expect(config.addonsForMain).toContain('@storybook/addon-webpack5-compiler-swc');\n      expect(config.addonPackages).toContain('@storybook/addon-webpack5-compiler-swc');\n    });\n\n    it('should strip versions from addons in main config', () => {\n      const config = manager.configureAddons(\n        new Set([Feature.DOCS]),\n        ['@storybook/addon-links@8.0.0'],\n        SupportedBuilder.VITE,\n        undefined\n      );\n\n      expect(config.addonsForMain).toContain('@storybook/addon-links');\n      expect(config.addonsForMain).not.toContain('@storybook/addon-links@8.0.0');\n    });\n\n    it('should keep versions in addon packages', () => {\n      const config = manager.configureAddons(\n        new Set([Feature.TEST]),\n        ['@storybook/addon-links@8.0.0'],\n        SupportedBuilder.VITE,\n        undefined\n      );\n\n      expect(config.addonPackages).toContain('@storybook/addon-links@8.0.0');\n    });\n\n    it('should handle all features together', () => {\n      const webpackCompiler = vi.fn().mockReturnValue('swc');\n      const config = manager.configureAddons(\n        new Set([Feature.DOCS, Feature.TEST, Feature.ONBOARDING, Feature.A11Y]),\n        ['@storybook/addon-links'],\n        SupportedBuilder.WEBPACK5,\n        webpackCompiler\n      );\n\n      expect(config.addonsForMain).toHaveLength(2); // compiler + links\n      expect(config.addonPackages).toHaveLength(2); // compiler + links\n      expect(config.addonsForMain).toContain('@storybook/addon-webpack5-compiler-swc');\n      expect(config.addonsForMain).toContain('@storybook/addon-links');\n    });\n\n    it('should filter out falsy values', () => {\n      const config = manager.configureAddons(new Set([]), [], SupportedBuilder.VITE, undefined);\n\n      expect(config.addonsForMain).not.toContain(undefined);\n      expect(config.addonsForMain).not.toContain(null);\n      expect(config.addonPackages).not.toContain(undefined);\n      expect(config.addonPackages).not.toContain(null);\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/services/AddonService.ts",
    "content": "import { getPackageDetails } from 'storybook/internal/common';\nimport type { SupportedBuilder } from 'storybook/internal/types';\nimport { Feature } from 'storybook/internal/types';\n\nexport interface AddonConfiguration {\n  addonsForMain: Array<string | { name: string; [key: string]: any }>;\n  addonPackages: string[];\n}\n\n/** Module for managing Storybook addons */\nexport class AddonService {\n  /** Determine webpack compiler addon if needed */\n  getWebpackCompilerAddon(\n    builder: SupportedBuilder,\n    webpackCompiler?: ({ builder }: { builder: SupportedBuilder }) => 'babel' | 'swc' | undefined\n  ): string | undefined {\n    if (!webpackCompiler) {\n      return undefined;\n    }\n\n    const compiler = webpackCompiler({ builder });\n    return compiler ? `@storybook/addon-webpack5-compiler-${compiler}` : undefined;\n  }\n\n  /** Get addons based on selected features */\n  getAddonsForFeatures(features: Set<Feature>): string[] {\n    const addons: string[] = [];\n\n    if (features.has(Feature.TEST)) {\n      addons.push('@chromatic-com/storybook');\n      addons.push('@storybook/addon-vitest');\n    }\n\n    if (features.has(Feature.A11Y)) {\n      addons.push('@storybook/addon-a11y');\n    }\n\n    if (features.has(Feature.DOCS)) {\n      addons.push('@storybook/addon-docs');\n    }\n\n    if (features.has(Feature.ONBOARDING)) {\n      addons.push('@storybook/addon-onboarding');\n    }\n\n    return addons;\n  }\n\n  /** Strip version numbers from addon names */\n  stripVersions(addons: string[]): string[] {\n    return addons.map((addon) => getPackageDetails(addon)[0]);\n  }\n\n  /** Configure addons for the project */\n  configureAddons(\n    features: Set<Feature>,\n    extraAddons: string[] = [],\n    builder: SupportedBuilder,\n    webpackCompiler?: ({ builder }: { builder: SupportedBuilder }) => 'babel' | 'swc' | undefined\n  ): AddonConfiguration {\n    const compiler = this.getWebpackCompilerAddon(builder, webpackCompiler);\n\n    // Addons added to main.js\n    const addonsForMain = [\n      ...(compiler ? [compiler] : []),\n      ...this.stripVersions(extraAddons),\n    ].filter(Boolean);\n\n    // Packages added to package.json\n    const addonPackages = [...(compiler ? [compiler] : []), ...extraAddons].filter(Boolean);\n\n    return {\n      addonsForMain,\n      addonPackages,\n    };\n  }\n}\n"
  },
  {
    "path": "code/lib/create-storybook/src/services/FeatureCompatibilityService.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { AddonVitestService, ProjectType } from 'storybook/internal/cli';\nimport type { JsPackageManager } from 'storybook/internal/common';\nimport { SupportedBuilder, SupportedFramework } from 'storybook/internal/types';\n\nimport { FeatureCompatibilityService } from './FeatureCompatibilityService.ts';\n\nvi.mock('storybook/internal/cli', { spy: true });\n\ndescribe('FeatureCompatibilityService', () => {\n  let service: FeatureCompatibilityService;\n  const mockPackageManager = {\n    getInstalledVersion: vi.fn(),\n  } as Partial<JsPackageManager> as JsPackageManager;\n  let mockAddonVitestService: AddonVitestService;\n\n  beforeEach(() => {\n    // Mock AddonVitestService constructor and methods\n    const mockValidateCompatibility = vi.fn().mockResolvedValue({ compatible: true });\n    vi.mocked(AddonVitestService).mockImplementation(function (this: any) {\n      return {\n        validateCompatibility: mockValidateCompatibility,\n      };\n    });\n\n    mockAddonVitestService = new AddonVitestService(mockPackageManager);\n    service = new FeatureCompatibilityService(mockPackageManager, mockAddonVitestService);\n  });\n\n  describe('supportsOnboarding', () => {\n    it('should return true for supported project types', () => {\n      expect(FeatureCompatibilityService.supportsOnboarding(ProjectType.REACT)).toBe(true);\n      expect(FeatureCompatibilityService.supportsOnboarding(ProjectType.REACT_SCRIPTS)).toBe(true);\n      expect(FeatureCompatibilityService.supportsOnboarding(ProjectType.NEXTJS)).toBe(true);\n      expect(FeatureCompatibilityService.supportsOnboarding(ProjectType.VUE3)).toBe(true);\n      expect(FeatureCompatibilityService.supportsOnboarding(ProjectType.ANGULAR)).toBe(true);\n    });\n\n    it('should return false for unsupported project types', () => {\n      expect(FeatureCompatibilityService.supportsOnboarding(ProjectType.SVELTE)).toBe(false);\n      expect(FeatureCompatibilityService.supportsOnboarding(ProjectType.EMBER)).toBe(false);\n      expect(FeatureCompatibilityService.supportsOnboarding(ProjectType.HTML)).toBe(false);\n    });\n  });\n\n  describe('validateTestFeatureCompatibility', () => {\n    let mockValidateCompatibility: ReturnType<typeof vi.fn>;\n\n    beforeEach(() => {\n      // Get the mocked validateCompatibility method\n      mockValidateCompatibility = vi.mocked(mockAddonVitestService.validateCompatibility);\n    });\n\n    it('should return compatible when all checks pass', async () => {\n      mockValidateCompatibility.mockResolvedValue({ compatible: true });\n\n      const result = await service.validateTestFeatureCompatibility(\n        SupportedFramework.REACT_VITE,\n        SupportedBuilder.VITE,\n        '/test'\n      );\n\n      expect(result.compatible).toBe(true);\n      expect(mockValidateCompatibility).toHaveBeenCalledWith({\n        framework: 'react-vite',\n        builder: SupportedBuilder.VITE,\n        projectRoot: '/test',\n      });\n    });\n\n    it('should return incompatible if package versions check fails', async () => {\n      mockValidateCompatibility.mockResolvedValue({\n        compatible: false,\n        reasons: ['Vitest version is too old'],\n      });\n\n      const result = await service.validateTestFeatureCompatibility(\n        SupportedFramework.REACT_VITE,\n        SupportedBuilder.VITE,\n        '/test'\n      );\n\n      expect(result.compatible).toBe(false);\n      expect(result.reasons).toBeDefined();\n      expect(result.reasons).toContain('Vitest version is too old');\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/services/FeatureCompatibilityService.ts",
    "content": "import { AddonVitestService, ProjectType } from 'storybook/internal/cli';\nimport type { JsPackageManager } from 'storybook/internal/common';\nimport type { SupportedBuilder, SupportedFramework } from 'storybook/internal/types';\n\n/** Project types that support the onboarding feature */\nconst ONBOARDING_PROJECT_TYPES: ProjectType[] = [\n  ProjectType.REACT,\n  ProjectType.REACT_SCRIPTS,\n  ProjectType.REACT_NATIVE_WEB,\n  ProjectType.NEXTJS,\n  ProjectType.VUE3,\n  ProjectType.ANGULAR,\n];\n\nexport interface FeatureCompatibilityResult {\n  compatible: boolean;\n  reasons?: string[];\n}\n\n/** Service for validating feature compatibility with project configurations */\nexport class FeatureCompatibilityService {\n  constructor(\n    readonly packageManager: JsPackageManager,\n    private readonly addonVitestService = new AddonVitestService(packageManager)\n  ) {}\n\n  /** Check if a project type supports onboarding */\n\n  static supportsOnboarding(projectType: ProjectType): boolean {\n    return ONBOARDING_PROJECT_TYPES.includes(\n      projectType as (typeof ONBOARDING_PROJECT_TYPES)[number]\n    );\n  }\n\n  /**\n   * Validate all compatibility checks for test feature\n   *\n   * @param packageManager - Package manager instance\n   * @param framework - Detected framework (e.g., 'nextjs', 'react-vite')\n   * @param builder - Detected builder (e.g. SupportedBuilder.Vite)\n   * @param directory - Project root directory\n   * @returns Compatibility result with reasons if incompatible\n   */\n  async validateTestFeatureCompatibility(\n    framework: SupportedFramework | null | undefined,\n    builder: SupportedBuilder,\n    directory: string\n  ): Promise<FeatureCompatibilityResult> {\n    const compatibilityResult = await this.addonVitestService.validateCompatibility({\n      framework,\n      builder,\n      projectRoot: directory,\n    });\n\n    if (!compatibilityResult.compatible) {\n      return compatibilityResult;\n    }\n\n    return { compatible: true };\n  }\n}\n"
  },
  {
    "path": "code/lib/create-storybook/src/services/FrameworkDetectionService.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { JsPackageManager } from 'storybook/internal/common';\nimport { prompt } from 'storybook/internal/node-logger';\nimport { SupportedBuilder, SupportedFramework, SupportedRenderer } from 'storybook/internal/types';\n\nimport * as find from 'empathic/find';\n\nimport { FrameworkDetectionService } from './FrameworkDetectionService.ts';\n\nvi.mock('empathic/find', () => ({\n  any: vi.fn(),\n}));\n\nvi.mock('storybook/internal/common', async (importOriginal) => {\n  const actual = await importOriginal<typeof import('storybook/internal/common')>();\n  return {\n    ...actual,\n    getProjectRoot: vi.fn(() => '/project/root'),\n  };\n});\n\nvi.mock('storybook/internal/node-logger', () => ({\n  prompt: {\n    select: vi.fn(),\n  },\n}));\n\ndescribe('FrameworkDetectionService', () => {\n  let service: FrameworkDetectionService;\n  let mockPackageManager: JsPackageManager;\n\n  beforeEach(() => {\n    vi.clearAllMocks();\n    mockPackageManager = {\n      getAllDependencies: vi.fn(() => ({})),\n    } as unknown as JsPackageManager;\n    service = new FrameworkDetectionService(mockPackageManager);\n  });\n\n  describe('detectFramework', () => {\n    it('should return renderer directly if it is a valid framework', () => {\n      const result = service.detectFramework(\n        SupportedRenderer.REACT as SupportedRenderer,\n        SupportedBuilder.VITE\n      );\n      expect(result).toBe(SupportedFramework.REACT_VITE);\n    });\n\n    it('should combine renderer and builder when renderer is not a framework', () => {\n      const result = service.detectFramework(\n        SupportedRenderer.REACT as SupportedRenderer,\n        SupportedBuilder.VITE\n      );\n      expect(result).toBe(SupportedFramework.REACT_VITE);\n    });\n\n    it('should return react-webpack5 framework for react renderer with webpack5 builder', () => {\n      const result = service.detectFramework(\n        SupportedRenderer.REACT as SupportedRenderer,\n        SupportedBuilder.WEBPACK5\n      );\n      expect(result).toBe(SupportedFramework.REACT_WEBPACK5);\n    });\n\n    it('should return react-vite framework for react renderer with vite builder', () => {\n      const result = service.detectFramework(\n        SupportedRenderer.REACT as SupportedRenderer,\n        SupportedBuilder.VITE\n      );\n      expect(result).toBe(SupportedFramework.REACT_VITE);\n    });\n\n    it('should return vue3-vite framework for vue3 renderer with vite builder', () => {\n      const result = service.detectFramework(\n        SupportedRenderer.VUE3 as SupportedRenderer,\n        SupportedBuilder.VITE\n      );\n      expect(result).toBe(SupportedFramework.VUE3_VITE);\n    });\n\n    it('should return react-rsbuild framework for react renderer with rsbuild builder', () => {\n      const result = service.detectFramework(\n        SupportedRenderer.REACT as SupportedRenderer,\n        SupportedBuilder.RSBUILD\n      );\n      expect(result).toBe(SupportedFramework.REACT_RSBUILD);\n    });\n\n    it('should throw error for invalid renderer and builder combination', () => {\n      const invalidRenderer = 'invalid-renderer' as SupportedRenderer;\n      const invalidBuilder = SupportedBuilder.VITE;\n\n      expect(() => {\n        service.detectFramework(invalidRenderer, invalidBuilder);\n      }).toThrow('Could not find framework for renderer: invalid-renderer and builder: vite');\n    });\n  });\n\n  describe('detectBuilder', () => {\n    it('should detect vite builder from config file', async () => {\n      vi.mocked(find.any).mockImplementation((files: string[]) => {\n        if (files.includes('vite.config.ts')) {\n          return 'vite.config.ts';\n        }\n        return undefined;\n      });\n      vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({});\n\n      const result = await service.detectBuilder();\n\n      expect(result).toBe(SupportedBuilder.VITE);\n      expect(prompt.select).not.toHaveBeenCalled();\n    });\n\n    it('should detect vite builder from dependencies', async () => {\n      vi.mocked(find.any).mockReturnValue(undefined);\n      vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({\n        vite: '^5.0.0',\n      });\n\n      const result = await service.detectBuilder();\n\n      expect(result).toBe(SupportedBuilder.VITE);\n      expect(prompt.select).not.toHaveBeenCalled();\n    });\n\n    it('should detect webpack5 builder from config file', async () => {\n      vi.mocked(find.any).mockImplementation((files: string[]) => {\n        if (files.includes('webpack.config.js')) {\n          return 'webpack.config.js';\n        }\n        return undefined;\n      });\n      vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({});\n\n      const result = await service.detectBuilder();\n\n      expect(result).toBe(SupportedBuilder.WEBPACK5);\n      expect(prompt.select).not.toHaveBeenCalled();\n    });\n\n    it('should detect webpack5 builder from dependencies', async () => {\n      vi.mocked(find.any).mockReturnValue(undefined);\n      vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({\n        webpack: '^5.0.0',\n      });\n\n      const result = await service.detectBuilder();\n\n      expect(result).toBe(SupportedBuilder.WEBPACK5);\n      expect(prompt.select).not.toHaveBeenCalled();\n    });\n\n    it('should detect rsbuild builder from config file', async () => {\n      vi.mocked(find.any).mockImplementation((files: string[]) => {\n        if (files.includes('rsbuild.config.ts')) {\n          return 'rsbuild.config.ts';\n        }\n        return undefined;\n      });\n      vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({});\n\n      const result = await service.detectBuilder();\n\n      expect(result).toBe(SupportedBuilder.RSBUILD);\n      expect(prompt.select).not.toHaveBeenCalled();\n    });\n\n    it('should detect rsbuild builder from dependencies', async () => {\n      vi.mocked(find.any).mockReturnValue(undefined);\n      vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({\n        '@rsbuild/core': '^1.0.0',\n      });\n\n      const result = await service.detectBuilder();\n\n      expect(result).toBe(SupportedBuilder.RSBUILD);\n      expect(prompt.select).not.toHaveBeenCalled();\n    });\n\n    it('should detect both config file and dependency, then prompt user', async () => {\n      vi.mocked(find.any).mockImplementation((files: string[]) => {\n        // Check if this is the vite config files array (has vite.config.ts)\n        if (files.includes('vite.config.ts')) {\n          return 'vite.config.ts';\n        }\n        // For webpack and rsbuild config files, return undefined\n        return undefined;\n      });\n      vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({\n        webpack: '^5.0.0',\n      });\n      vi.mocked(prompt.select).mockResolvedValue(SupportedBuilder.VITE);\n\n      const result = await service.detectBuilder();\n\n      expect(result).toBe(SupportedBuilder.VITE);\n      expect(prompt.select).toHaveBeenCalledWith({\n        message: expect.stringContaining('Multiple builders were detected'),\n        options: [\n          { label: 'Vite', value: SupportedBuilder.VITE },\n          { label: 'Webpack 5', value: SupportedBuilder.WEBPACK5 },\n          { label: 'Rsbuild', value: SupportedBuilder.RSBUILD },\n        ],\n      });\n    });\n\n    it('should prompt user when multiple builders are detected', async () => {\n      vi.mocked(find.any).mockImplementation((files: string[]) => {\n        if (files.includes('vite.config.ts')) {\n          return 'vite.config.ts';\n        }\n        if (files.includes('webpack.config.js')) {\n          return 'webpack.config.js';\n        }\n        return undefined;\n      });\n      vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({});\n      vi.mocked(prompt.select).mockResolvedValue(SupportedBuilder.VITE);\n\n      const result = await service.detectBuilder();\n\n      expect(result).toBe(SupportedBuilder.VITE);\n      expect(prompt.select).toHaveBeenCalledWith({\n        message: expect.stringContaining('Multiple builders were detected'),\n        options: [\n          { label: 'Vite', value: SupportedBuilder.VITE },\n          { label: 'Webpack 5', value: SupportedBuilder.WEBPACK5 },\n          { label: 'Rsbuild', value: SupportedBuilder.RSBUILD },\n        ],\n      });\n    });\n\n    it('should prompt user when no builders are detected', async () => {\n      vi.mocked(find.any).mockReturnValue(undefined);\n      vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({});\n      vi.mocked(prompt.select).mockResolvedValue(SupportedBuilder.VITE);\n\n      const result = await service.detectBuilder();\n\n      expect(result).toBe(SupportedBuilder.VITE);\n      expect(prompt.select).toHaveBeenCalledWith({\n        message: expect.stringContaining('We were not able to detect the right builder'),\n        options: [\n          { label: 'Vite', value: SupportedBuilder.VITE },\n          { label: 'Webpack 5', value: SupportedBuilder.WEBPACK5 },\n          { label: 'Rsbuild', value: SupportedBuilder.RSBUILD },\n        ],\n      });\n    });\n\n    it('should detect multiple builders from dependencies', async () => {\n      vi.mocked(find.any).mockReturnValue(undefined);\n      vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({\n        vite: '^5.0.0',\n        webpack: '^5.0.0',\n      });\n      vi.mocked(prompt.select).mockResolvedValue(SupportedBuilder.WEBPACK5);\n\n      const result = await service.detectBuilder();\n\n      expect(result).toBe(SupportedBuilder.WEBPACK5);\n      expect(prompt.select).toHaveBeenCalled();\n    });\n\n    it('should detect all three builders when all are present', async () => {\n      vi.mocked(find.any).mockImplementation((files: string[]) => {\n        if (files.includes('vite.config.ts')) {\n          return 'vite.config.ts';\n        }\n        if (files.includes('webpack.config.js')) {\n          return 'webpack.config.js';\n        }\n        if (files.includes('rsbuild.config.ts')) {\n          return 'rsbuild.config.ts';\n        }\n        return undefined;\n      });\n      vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({});\n      vi.mocked(prompt.select).mockResolvedValue(SupportedBuilder.RSBUILD);\n\n      const result = await service.detectBuilder();\n\n      expect(result).toBe(SupportedBuilder.RSBUILD);\n      expect(prompt.select).toHaveBeenCalled();\n    });\n\n    it('should check all vite config file variants', async () => {\n      const viteConfigs = ['vite.config.ts', 'vite.config.js', 'vite.config.mjs'];\n      for (const config of viteConfigs) {\n        vi.mocked(find.any).mockImplementation((files: string[]) => {\n          if (files.includes(config)) {\n            return config;\n          }\n          return undefined;\n        });\n        vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({});\n\n        const result = await service.detectBuilder();\n\n        expect(result).toBe(SupportedBuilder.VITE);\n        vi.clearAllMocks();\n      }\n    });\n\n    it('should check all rsbuild config file variants', async () => {\n      const rsbuildConfigs = ['rsbuild.config.ts', 'rsbuild.config.js', 'rsbuild.config.mjs'];\n      for (const config of rsbuildConfigs) {\n        vi.mocked(find.any).mockImplementation((files: string[]) => {\n          if (files.includes(config)) {\n            return config;\n          }\n          return undefined;\n        });\n        vi.mocked(mockPackageManager.getAllDependencies).mockReturnValue({});\n\n        const result = await service.detectBuilder();\n\n        expect(result).toBe(SupportedBuilder.RSBUILD);\n        vi.clearAllMocks();\n      }\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/services/FrameworkDetectionService.ts",
    "content": "import { type JsPackageManager, getProjectRoot } from 'storybook/internal/common';\nimport { prompt } from 'storybook/internal/node-logger';\nimport type { SupportedRenderer } from 'storybook/internal/types';\nimport { SupportedBuilder, SupportedFramework } from 'storybook/internal/types';\n\nimport * as find from 'empathic/find';\nimport { dedent } from 'ts-dedent';\n\nconst viteConfigFiles = ['vite.config.ts', 'vite.config.js', 'vite.config.mjs'];\nconst webpackConfigFiles = ['webpack.config.js'];\nconst rsbuildConfigFiles = ['rsbuild.config.ts', 'rsbuild.config.js', 'rsbuild.config.mjs'];\n\nexport class FrameworkDetectionService {\n  constructor(private jsPackageManager: JsPackageManager) {}\n\n  detectFramework(renderer: SupportedRenderer, builder: SupportedBuilder): SupportedFramework {\n    if (Object.values(SupportedFramework).includes(renderer as any)) {\n      return renderer as any as SupportedFramework;\n    }\n\n    const maybeFramework = `${renderer}-${builder}`;\n\n    if (Object.values(SupportedFramework).includes(maybeFramework as SupportedFramework)) {\n      return maybeFramework as SupportedFramework;\n    }\n\n    throw new Error(`Could not find framework for renderer: ${renderer} and builder: ${builder}`);\n  }\n\n  async detectBuilder() {\n    const viteConfig = find.any(viteConfigFiles, { last: getProjectRoot() });\n    const webpackConfig = find.any(webpackConfigFiles, { last: getProjectRoot() });\n    const rsbuildConfig = find.any(rsbuildConfigFiles, { last: getProjectRoot() });\n    const dependencies = this.jsPackageManager.getAllDependencies();\n\n    // Detect which builders are present\n    const hasVite = viteConfig || !!dependencies.vite;\n    const hasWebpack = webpackConfig || !!dependencies.webpack;\n    const hasRsbuild = rsbuildConfig || !!dependencies['@rsbuild/core'];\n\n    const detectedBuilders: SupportedBuilder[] = [];\n\n    if (hasVite) {\n      detectedBuilders.push(SupportedBuilder.VITE);\n    }\n\n    if (hasWebpack) {\n      detectedBuilders.push(SupportedBuilder.WEBPACK5);\n    }\n\n    if (hasRsbuild) {\n      detectedBuilders.push(SupportedBuilder.RSBUILD);\n    }\n\n    // If exactly one builder is detected, return it\n    if (detectedBuilders.length === 1) {\n      return detectedBuilders[0];\n    }\n\n    // If multiple builders are detected or none are detected, prompt the user\n    const options = [\n      { label: 'Vite', value: SupportedBuilder.VITE },\n      { label: 'Webpack 5', value: SupportedBuilder.WEBPACK5 },\n      { label: 'Rsbuild', value: SupportedBuilder.RSBUILD },\n    ];\n\n    return prompt.select({\n      message: dedent`\n      ${\n        detectedBuilders.length > 1\n          ? 'Multiple builders were detected in your project. Please select one:'\n          : 'We were not able to detect the right builder for your project. Please select one:'\n      }\n      `,\n      options,\n    });\n  }\n}\n"
  },
  {
    "path": "code/lib/create-storybook/src/services/ProjectTypeService.test.ts",
    "content": "import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { ProjectType } from 'storybook/internal/cli';\nimport type { JsPackageManager } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\nimport { NxProjectDetectedError } from 'storybook/internal/server-errors';\n\nimport type { CommandOptions } from '../generators/types.ts';\nimport { ProjectTypeService } from './ProjectTypeService.ts';\n\ndescribe('ProjectTypeService', () => {\n  let pm: JsPackageManager;\n\n  beforeEach(() => {\n    pm = {\n      getAllDependencies: vi.fn(() => ({}) as any),\n      getModulePackageJSON: vi.fn(async () => ({ version: '0.0.0' })) as any,\n      primaryPackageJson: { packageJson: {} as any },\n    } as unknown as JsPackageManager;\n    vi.spyOn(logger, 'error').mockImplementation(() => undefined as any);\n    vi.spyOn(logger, 'warn').mockImplementation(() => undefined as any);\n  });\n\n  afterEach(() => {\n    vi.restoreAllMocks();\n  });\n\n  describe('autoDetectProjectType', () => {\n    it('logs a helpful message when framework cannot be detected', async () => {\n      const service = new ProjectTypeService(pm);\n      const options = { html: false } as unknown as CommandOptions;\n      // @ts-expect-error accessing private for test\n      vi.spyOn(service, 'detectProjectType').mockResolvedValue(ProjectType.UNDETECTED);\n\n      await expect(service.autoDetectProjectType(options)).rejects.toThrowError(\n        'Storybook failed to detect your project type'\n      );\n      expect(logger.error).toHaveBeenCalledWith(\n        expect.stringContaining('Unable to initialize Storybook in this directory.')\n      );\n    });\n\n    it('throws NxProjectDetectedError when NX project is detected', async () => {\n      const service = new ProjectTypeService(pm);\n      // @ts-expect-error private method spy\n      vi.spyOn(service, 'isNxProject').mockReturnValue(true);\n      await expect(service.autoDetectProjectType({} as CommandOptions)).rejects.toBeInstanceOf(\n        NxProjectDetectedError\n      );\n    });\n\n    it('returns HTML when options.html is true', async () => {\n      const service = new ProjectTypeService(pm);\n      // @ts-expect-error private method spy\n      vi.spyOn(service, 'isNxProject').mockReturnValue(false);\n      const result = await service.autoDetectProjectType({ html: true } as CommandOptions);\n      expect(result).toBe(ProjectType.HTML);\n    });\n\n    it('detects framework from package.json (nextjs)', async () => {\n      (pm as any).primaryPackageJson.packageJson = {\n        dependencies: { next: '^13.0.0' },\n      };\n      const service = new ProjectTypeService(pm);\n      // @ts-expect-error private method spy\n      vi.spyOn(service, 'isNxProject').mockReturnValue(false);\n      const result = await service.autoDetectProjectType({ html: false } as CommandOptions);\n      expect(result).toBe(ProjectType.NEXTJS);\n    });\n\n    it('detects VUE3 when vue major is 3', async () => {\n      (pm as any).primaryPackageJson.packageJson = {\n        dependencies: { vue: '^3.2.0' },\n      };\n      const service = new ProjectTypeService(pm);\n      // @ts-expect-error private method spy\n      vi.spyOn(service, 'isNxProject').mockReturnValue(false);\n      const result = await service.autoDetectProjectType({ html: false } as CommandOptions);\n      expect(result).toBe(ProjectType.VUE3);\n    });\n\n    it('detects SVELTEKIT via @sveltejs/kit', async () => {\n      (pm as any).primaryPackageJson.packageJson = {\n        dependencies: { '@sveltejs/kit': '^2.0.0' },\n      };\n      const service = new ProjectTypeService(pm);\n      // @ts-expect-error private method spy\n      vi.spyOn(service, 'isNxProject').mockReturnValue(false);\n      const result = await service.autoDetectProjectType({ html: false } as CommandOptions);\n      expect(result).toBe(ProjectType.SVELTEKIT);\n    });\n\n    it('detects WEB_COMPONENTS via lit', async () => {\n      (pm as any).primaryPackageJson.packageJson = {\n        dependencies: { lit: '^3.0.0' },\n      };\n      const service = new ProjectTypeService(pm);\n      // @ts-expect-error private method spy\n      vi.spyOn(service, 'isNxProject').mockReturnValue(false);\n      const result = await service.autoDetectProjectType({ html: false } as CommandOptions);\n      expect(result).toBe(ProjectType.WEB_COMPONENTS);\n    });\n\n    it('detects SOLID via solid-js', async () => {\n      (pm as any).primaryPackageJson.packageJson = {\n        dependencies: { 'solid-js': '^1.8.0' },\n      };\n      const service = new ProjectTypeService(pm);\n      // @ts-expect-error private method spy\n      vi.spyOn(service, 'isNxProject').mockReturnValue(false);\n      const result = await service.autoDetectProjectType({ html: false } as CommandOptions);\n      expect(result).toBe(ProjectType.SOLID);\n    });\n\n    it('detects REACT_SCRIPTS via dependency', async () => {\n      (pm as any).primaryPackageJson.packageJson = {\n        dependencies: { 'react-scripts': '^5.0.0' },\n      };\n      const service = new ProjectTypeService(pm);\n      // @ts-expect-error private method spy\n      vi.spyOn(service, 'isNxProject').mockReturnValue(false);\n      const result = await service.autoDetectProjectType({ html: false } as CommandOptions);\n      expect(result).toBe(ProjectType.REACT_SCRIPTS);\n    });\n\n    it('detects ANGULAR via @angular/core', async () => {\n      (pm as any).primaryPackageJson.packageJson = {\n        dependencies: { '@angular/core': '^17.0.0' },\n      };\n      const service = new ProjectTypeService(pm);\n      // @ts-expect-error private method spy\n      vi.spyOn(service, 'isNxProject').mockReturnValue(false);\n      const result = await service.autoDetectProjectType({ html: false } as CommandOptions);\n      expect(result).toBe(ProjectType.ANGULAR);\n    });\n\n    it('detects PREACT via preact', async () => {\n      (pm as any).primaryPackageJson.packageJson = {\n        dependencies: { preact: '^10.0.0' },\n      };\n      const service = new ProjectTypeService(pm);\n      // @ts-expect-error private method spy\n      vi.spyOn(service, 'isNxProject').mockReturnValue(false);\n      const result = await service.autoDetectProjectType({ html: false } as CommandOptions);\n      expect(result).toBe(ProjectType.PREACT);\n    });\n\n    it('detects EMBER via ember-cli', async () => {\n      (pm as any).primaryPackageJson.packageJson = {\n        dependencies: { 'ember-cli': '^5.0.0' },\n      };\n      const service = new ProjectTypeService(pm);\n      // @ts-expect-error private method spy\n      vi.spyOn(service, 'isNxProject').mockReturnValue(false);\n      const result = await service.autoDetectProjectType({ html: false } as CommandOptions);\n      expect(result).toBe(ProjectType.EMBER);\n    });\n\n    it('detects QWIK via @builder.io/qwik', async () => {\n      (pm as any).primaryPackageJson.packageJson = {\n        dependencies: { '@builder.io/qwik': '^1.4.0' },\n      };\n      const service = new ProjectTypeService(pm);\n      // @ts-expect-error private method spy\n      vi.spyOn(service, 'isNxProject').mockReturnValue(false);\n      const result = await service.autoDetectProjectType({ html: false } as CommandOptions);\n      expect(result).toBe(ProjectType.QWIK);\n    });\n\n    it('detects SVELTE via svelte', async () => {\n      (pm as any).primaryPackageJson.packageJson = {\n        dependencies: { svelte: '^4.0.0' },\n      };\n      const service = new ProjectTypeService(pm);\n      // @ts-expect-error private method spy\n      vi.spyOn(service, 'isNxProject').mockReturnValue(false);\n      const result = await service.autoDetectProjectType({ html: false } as CommandOptions);\n      expect(result).toBe(ProjectType.SVELTE);\n    });\n\n    it('detects REACT_NATIVE via react-native-scripts', async () => {\n      (pm as any).primaryPackageJson.packageJson = {\n        dependencies: { 'react-native-scripts': '^5.0.0' },\n      };\n      const service = new ProjectTypeService(pm);\n      // @ts-expect-error private method spy\n      vi.spyOn(service, 'isNxProject').mockReturnValue(false);\n      const result = await service.autoDetectProjectType({ html: false } as CommandOptions);\n      expect(result).toBe(ProjectType.REACT_NATIVE);\n    });\n\n    it('detects NUXT via nuxt', async () => {\n      (pm as any).primaryPackageJson.packageJson = {\n        dependencies: { nuxt: '^3.0.0' },\n      };\n      const service = new ProjectTypeService(pm);\n      // @ts-expect-error private method spy\n      vi.spyOn(service, 'isNxProject').mockReturnValue(false);\n      const result = await service.autoDetectProjectType({ html: false } as CommandOptions);\n      expect(result).toBe(ProjectType.NUXT);\n    });\n  });\n\n  describe('validateProvidedType', () => {\n    it('accepts installable types and rejects invalid ones', async () => {\n      const service = new ProjectTypeService(pm);\n      await expect(service.validateProvidedType(ProjectType.REACT)).resolves.toBe(\n        ProjectType.REACT\n      );\n      await expect(service.validateProvidedType(ProjectType.UNSUPPORTED)).rejects.toThrow(\n        /Unknown project type supplied/\n      );\n    });\n  });\n\n  describe('detectLanguage', () => {\n    // Note: FS-based language detection (jsconfig/tsconfig) is not tested here to avoid\n    // mutating the real filesystem or mocking ESM builtin modules. Covered by TS tooling path.\n    it('returns typescript when TS and compatible tooling are present', async () => {\n      (pm.getAllDependencies as any) = vi.fn(() => ({ typescript: '^5.0.0' }));\n      (pm.getModulePackageJSON as any) = vi.fn(async (name: string) => {\n        const versions: Record<string, string> = {\n          typescript: '5.2.0',\n          prettier: '3.3.0',\n          '@babel/plugin-transform-typescript': '7.23.0',\n          '@typescript-eslint/parser': '6.7.0',\n          'eslint-plugin-storybook': '0.7.0',\n        };\n        return { version: versions[name] } as any;\n      });\n      const service = new ProjectTypeService(pm);\n      await expect(service.detectLanguage()).resolves.toBe('typescript');\n    });\n\n    it('warns and returns javascript when TS/tooling versions incompatible', async () => {\n      (pm.getAllDependencies as any) = vi.fn(() => ({ typescript: '^4.8.0' }));\n      (pm.getModulePackageJSON as any) = vi.fn(async (name: string) => {\n        const versions: Record<string, string> = {\n          typescript: '4.8.4',\n          prettier: '2.7.1', // below 2.8.0\n          '@babel/plugin-transform-typescript': '7.19.0',\n          '@typescript-eslint/parser': '5.43.0',\n          'eslint-plugin-storybook': '0.6.7',\n        };\n        return { version: versions[name] } as any;\n      });\n      const warnSpy = vi.spyOn(logger, 'warn');\n      const service = new ProjectTypeService(pm);\n      await expect(service.detectLanguage()).resolves.toBe('javascript');\n      expect(warnSpy).toHaveBeenCalled();\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/services/ProjectTypeService.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport { ProjectType } from 'storybook/internal/cli';\nimport { HandledError, getProjectRoot } from 'storybook/internal/common';\nimport type { JsPackageManager, PackageJsonWithMaybeDeps } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\nimport { NxProjectDetectedError } from 'storybook/internal/server-errors';\nimport { SupportedLanguage } from 'storybook/internal/types';\n\nimport * as find from 'empathic/find';\nimport semver from 'semver';\nimport { dedent } from 'ts-dedent';\n\nimport type { CommandOptions } from '../generators/types.ts';\n\ntype TemplateMatcher = {\n  files?: boolean[];\n  dependencies?: boolean[];\n  peerDependencies?: boolean[];\n};\n\ntype TemplateConfiguration = {\n  preset: ProjectType;\n  /** Will be checked both against dependencies and devDependencies */\n  dependencies?: string[] | { [dependency: string]: (version: string) => boolean };\n  peerDependencies?: string[] | { [dependency: string]: (version: string) => boolean };\n  files?: string[];\n  matcherFunction: (matcher: TemplateMatcher) => boolean;\n};\n\n/** Service encapsulating helpers for ProjectType usage */\nexport class ProjectTypeService {\n  constructor(private readonly jsPackageManager: JsPackageManager) {}\n\n  /** Sorted configuration to match a Storybook preset template */\n  getSupportedTemplates(): TemplateConfiguration[] {\n    return [\n      {\n        preset: ProjectType.NUXT,\n        dependencies: ['nuxt'],\n        matcherFunction: ({ dependencies }) => {\n          return dependencies?.every(Boolean) ?? true;\n        },\n      },\n      {\n        preset: ProjectType.VUE3,\n        dependencies: {\n          // This Vue template works with Vue 3\n          vue: (versionRange) => versionRange === 'next' || this.eqMajor(versionRange, 3),\n        },\n        matcherFunction: ({ dependencies }) => {\n          return dependencies?.some(Boolean) ?? false;\n        },\n      },\n      {\n        preset: ProjectType.EMBER,\n        dependencies: ['ember-cli'],\n        matcherFunction: ({ dependencies }) => {\n          return dependencies?.every(Boolean) ?? true;\n        },\n      },\n      {\n        preset: ProjectType.NEXTJS,\n        dependencies: ['next'],\n        matcherFunction: ({ dependencies }) => {\n          return dependencies?.every(Boolean) ?? true;\n        },\n      },\n      {\n        preset: ProjectType.QWIK,\n        dependencies: ['@builder.io/qwik'],\n        matcherFunction: ({ dependencies }) => {\n          return dependencies?.every(Boolean) ?? true;\n        },\n      },\n      {\n        preset: ProjectType.REACT_NATIVE,\n        dependencies: ['react-native', 'react-native-scripts'],\n        matcherFunction: ({ dependencies }) => {\n          return dependencies?.some(Boolean) ?? false;\n        },\n      },\n      {\n        preset: ProjectType.REACT_SCRIPTS,\n        // For projects using a custom/forked `react-scripts` package.\n        files: ['/node_modules/.bin/react-scripts'],\n        // For standard CRA projects\n        dependencies: ['react-scripts'],\n        matcherFunction: ({ dependencies, files }) => {\n          return (dependencies?.every(Boolean) || files?.every(Boolean)) ?? false;\n        },\n      },\n      {\n        preset: ProjectType.ANGULAR,\n        dependencies: ['@angular/core'],\n        matcherFunction: ({ dependencies }) => {\n          return dependencies?.every(Boolean) ?? true;\n        },\n      },\n      {\n        preset: ProjectType.WEB_COMPONENTS,\n        dependencies: ['lit-element', 'lit-html', 'lit'],\n        matcherFunction: ({ dependencies }) => {\n          return dependencies?.some(Boolean) ?? false;\n        },\n      },\n      {\n        preset: ProjectType.PREACT,\n        dependencies: ['preact'],\n        matcherFunction: ({ dependencies }) => {\n          return dependencies?.every(Boolean) ?? true;\n        },\n      },\n      {\n        // TODO: This only works because it is before the SVELTE template. could be more explicit\n        preset: ProjectType.SVELTEKIT,\n        dependencies: ['@sveltejs/kit'],\n        matcherFunction: ({ dependencies }) => {\n          return dependencies?.every(Boolean) ?? true;\n        },\n      },\n      {\n        preset: ProjectType.SVELTE,\n        dependencies: ['svelte'],\n        matcherFunction: ({ dependencies }) => {\n          return dependencies?.every(Boolean) ?? true;\n        },\n      },\n      {\n        preset: ProjectType.SOLID,\n        dependencies: ['solid-js'],\n        matcherFunction: ({ dependencies }) => {\n          return dependencies?.every(Boolean) ?? true;\n        },\n      },\n      // DO NOT MOVE ANY TEMPLATES BELOW THIS LINE\n      // React is part of every Template, after Storybook is initialized once\n      {\n        preset: ProjectType.REACT,\n        dependencies: ['react'],\n        matcherFunction: ({ dependencies }) => {\n          return dependencies?.every(Boolean) ?? true;\n        },\n      },\n    ];\n  }\n\n  isStorybookInstantiated(configDir = resolve(process.cwd(), '.storybook')) {\n    return existsSync(configDir);\n  }\n\n  async validateProvidedType(projectTypeProvided: ProjectType): Promise<ProjectType> {\n    // Allow only installable types according to core list\n    const installable = Object.values(ProjectType).filter(\n      (t) => !['undetected', 'unsupported', 'nx'].includes(String(t))\n    );\n    if (installable.includes(projectTypeProvided)) {\n      return projectTypeProvided;\n    }\n    logger.error(\n      `The provided project type ${projectTypeProvided} was not recognized by Storybook`\n    );\n    throw new HandledError(`Unknown project type supplied: ${projectTypeProvided}`);\n  }\n\n  async autoDetectProjectType(options: CommandOptions): Promise<ProjectType> {\n    try {\n      const detectedType = await this.detectProjectType(options);\n\n      // prompting handled by command layer\n\n      if (detectedType === ProjectType.UNDETECTED || detectedType === null) {\n        logger.error(dedent`\n          Unable to initialize Storybook in this directory.\n\n          Storybook couldn't detect a supported framework or configuration for your project. Make sure you're inside a framework project (e.g., React, Vue, Svelte, Angular, Next.js) and that its dependencies are installed.\n\n          Tips:\n          - Run init in an empty directory or create a new framework app first.\n          - If this directory contains unrelated files, try a new directory for Storybook.\n        `);\n        throw new HandledError('Storybook failed to detect your project type');\n      }\n\n      if (detectedType === ProjectType.NX) {\n        throw new NxProjectDetectedError();\n      }\n\n      return detectedType;\n    } catch (err) {\n      if (err instanceof HandledError || err instanceof NxProjectDetectedError) {\n        throw err;\n      }\n      logger.error(String(err));\n      throw new HandledError(err instanceof Error ? err.message : String(err));\n    }\n  }\n\n  async detectLanguage(): Promise<SupportedLanguage> {\n    let language = SupportedLanguage.JAVASCRIPT;\n\n    if (existsSync('jsconfig.json')) {\n      return language;\n    }\n\n    const isTypescriptDirectDependency = !!this.jsPackageManager.getAllDependencies().typescript;\n\n    const getModulePackageJSONVersion = async (pkg: string) => {\n      return (await this.jsPackageManager.getModulePackageJSON(pkg))?.version ?? null;\n    };\n\n    const [\n      typescriptVersion,\n      prettierVersion,\n      babelPluginTransformTypescriptVersion,\n      typescriptEslintParserVersion,\n      eslintPluginStorybookVersion,\n    ] = await Promise.all([\n      getModulePackageJSONVersion('typescript'),\n      getModulePackageJSONVersion('prettier'),\n      getModulePackageJSONVersion('@babel/plugin-transform-typescript'),\n      getModulePackageJSONVersion('@typescript-eslint/parser'),\n      getModulePackageJSONVersion('eslint-plugin-storybook'),\n    ]);\n\n    const satisfies = (version: string | null, range: string) => {\n      if (!version) {\n        return false;\n      }\n      return semver.satisfies(version, range, { includePrerelease: true });\n    };\n\n    if (isTypescriptDirectDependency && typescriptVersion) {\n      if (\n        satisfies(typescriptVersion, '>=4.9.0') &&\n        (!prettierVersion || semver.gte(prettierVersion, '2.8.0')) &&\n        (!babelPluginTransformTypescriptVersion ||\n          satisfies(babelPluginTransformTypescriptVersion, '>=7.20.0')) &&\n        (!typescriptEslintParserVersion || satisfies(typescriptEslintParserVersion, '>=5.44.0')) &&\n        (!eslintPluginStorybookVersion || satisfies(eslintPluginStorybookVersion, '>=0.6.8'))\n      ) {\n        language = SupportedLanguage.TYPESCRIPT;\n      } else {\n        logger.warn(\n          'Detected TypeScript < 4.9 or incompatible tooling, populating with JavaScript examples'\n        );\n      }\n    } else {\n      // No direct dependency on TypeScript, but could be a transitive dependency\n      // This is eg the case for Nuxt projects, which support a recent version of TypeScript\n      // Check for tsconfig.json (https://www.typescriptlang.org/docs/handbook/tsconfig-json.html)\n      if (existsSync('tsconfig.json')) {\n        language = SupportedLanguage.TYPESCRIPT;\n      }\n    }\n\n    return language;\n  }\n\n  private eqMajor(versionRange: string, major: number) {\n    // Uses validRange to avoid a throw from minVersion if an invalid range gets passed\n    if (semver.validRange(versionRange)) {\n      return semver.minVersion(versionRange)?.major === major;\n    }\n    return false;\n  }\n\n  private async detectProjectType(options: CommandOptions): Promise<ProjectType | null> {\n    try {\n      if (this.isNxProject()) {\n        return ProjectType.NX;\n      }\n      if (options.html) {\n        return ProjectType.HTML;\n      }\n      const { packageJson } = this.jsPackageManager.primaryPackageJson;\n      return this.detectFrameworkPreset(packageJson);\n    } catch {\n      return ProjectType.UNDETECTED;\n    }\n  }\n\n  private detectFrameworkPreset(packageJson: PackageJsonWithMaybeDeps): ProjectType | null {\n    const result = [...this.getSupportedTemplates(), this.getUnsupportedTemplate()].find(\n      (framework) => {\n        return this.getProjectType(packageJson, framework) !== null;\n      }\n    );\n    return result ? result.preset : ProjectType.UNDETECTED;\n  }\n\n  /** Template that matches unsupported frameworks */\n  private getUnsupportedTemplate(): TemplateConfiguration {\n    return {\n      preset: ProjectType.UNSUPPORTED,\n      dependencies: {},\n      matcherFunction: ({ dependencies }) => {\n        return dependencies?.some(Boolean) ?? false;\n      },\n    };\n  }\n\n  private getProjectType(\n    packageJson: PackageJsonWithMaybeDeps,\n    framework: TemplateConfiguration\n  ): ProjectType | null {\n    const matcher: TemplateMatcher = {\n      dependencies: [false],\n      peerDependencies: [false],\n      files: [false],\n    };\n    const { preset, files, dependencies, peerDependencies, matcherFunction } = framework;\n\n    let dependencySearches: [string, ((version: string) => boolean) | undefined][] = [];\n\n    if (Array.isArray(dependencies)) {\n      dependencySearches = dependencies.map((name) => [name, undefined]);\n    } else if (typeof dependencies === 'object') {\n      dependencySearches = Object.entries(dependencies);\n    }\n\n    if (dependencySearches.length > 0) {\n      matcher.dependencies = dependencySearches.map(([name, matchFn]) =>\n        this.hasDependency(packageJson, name, matchFn)\n      );\n    }\n\n    let peerDependencySearches: [string, ((version: string) => boolean) | undefined][] = [];\n\n    if (Array.isArray(peerDependencies)) {\n      peerDependencySearches = peerDependencies.map((name) => [name, undefined]);\n    } else if (typeof peerDependencies === 'object') {\n      peerDependencySearches = Object.entries(peerDependencies);\n    }\n\n    if (peerDependencySearches.length > 0) {\n      matcher.peerDependencies = peerDependencySearches.map(([name, matchFn]) =>\n        this.hasPeerDependency(packageJson, name, matchFn)\n      );\n    }\n\n    if (Array.isArray(files) && files.length > 0) {\n      matcher.files = files.map((name) => existsSync(name));\n    }\n\n    return matcherFunction(matcher) ? preset : null;\n  }\n\n  private hasDependency(\n    packageJson: PackageJsonWithMaybeDeps,\n    name: string,\n    matcher?: (version: string) => boolean\n  ) {\n    const version = packageJson.dependencies?.[name] || packageJson.devDependencies?.[name];\n    if (version && typeof matcher === 'function') {\n      return matcher(version);\n    }\n    return !!version;\n  }\n\n  private hasPeerDependency(\n    packageJson: PackageJsonWithMaybeDeps,\n    name: string,\n    matcher?: (version: string) => boolean\n  ) {\n    const version = packageJson.peerDependencies?.[name];\n    if (version && typeof matcher === 'function') {\n      return matcher(version);\n    }\n    return !!version;\n  }\n\n  private isNxProject() {\n    return find.up('nx.json', { last: getProjectRoot() });\n  }\n}\n"
  },
  {
    "path": "code/lib/create-storybook/src/services/TelemetryService.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { ProjectType } from 'storybook/internal/cli';\nimport { telemetry } from 'storybook/internal/telemetry';\nimport { Feature } from 'storybook/internal/types';\n\nimport { getProcessAncestry } from 'process-ancestry';\n\nimport { TelemetryService } from './TelemetryService.ts';\n\nvi.mock('storybook/internal/telemetry', { spy: true });\nvi.mock('process-ancestry', { spy: true });\n\ndescribe('TelemetryService', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n    vi.mocked(telemetry).mockResolvedValue(undefined);\n  });\n\n  describe('when telemetry is enabled', () => {\n    let telemetryService: TelemetryService;\n\n    beforeEach(() => {\n      telemetryService = new TelemetryService(false);\n    });\n\n    it('should track new user check', async () => {\n      await telemetryService.trackNewUserCheck(true);\n\n      expect(telemetry).toHaveBeenCalledWith('init-step', {\n        step: 'new-user-check',\n        newUser: true,\n      });\n    });\n\n    it('should track install type', async () => {\n      await telemetryService.trackInstallType('recommended');\n\n      expect(telemetry).toHaveBeenCalledWith('init-step', {\n        step: 'install-type',\n        installType: 'recommended',\n      });\n    });\n\n    it('should track init event', async () => {\n      const data = {\n        projectType: ProjectType.REACT,\n        features: {\n          dev: true,\n          docs: true,\n          test: false,\n          onboarding: true,\n        },\n        newUser: true,\n        versionSpecifier: '8.0.0',\n        cliIntegration: 'sv create',\n      };\n\n      await telemetryService.trackInit(data);\n\n      expect(telemetry).toHaveBeenCalledWith('init', data);\n    });\n\n    it('should track scaffolded event', async () => {\n      const data = {\n        packageManager: 'npm',\n        projectType: 'react-vite-ts',\n      };\n\n      await telemetryService.trackScaffolded(data);\n\n      expect(telemetry).toHaveBeenCalledWith('scaffolded-empty', data);\n    });\n  });\n\n  describe('when telemetry is disabled', () => {\n    let telemetryService: TelemetryService;\n\n    beforeEach(() => {\n      telemetryService = new TelemetryService(true);\n    });\n\n    it('should not track new user check', async () => {\n      await telemetryService.trackNewUserCheck(true);\n\n      expect(telemetry).not.toHaveBeenCalled();\n    });\n\n    it('should not track install type', async () => {\n      await telemetryService.trackInstallType('light');\n\n      expect(telemetry).not.toHaveBeenCalled();\n    });\n\n    it('should not track init event', async () => {\n      await telemetryService.trackInit({\n        projectType: ProjectType.VUE3,\n        features: {\n          dev: true,\n          docs: false,\n          test: false,\n          onboarding: false,\n        },\n        newUser: false,\n      });\n\n      expect(telemetry).not.toHaveBeenCalled();\n    });\n\n    it('should not track scaffolded event', async () => {\n      await telemetryService.trackScaffolded({\n        packageManager: 'yarn',\n        projectType: 'vue-vite-ts',\n      });\n\n      expect(telemetry).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('trackInitWithContext', () => {\n    it('should track init with version and CLI integration from ancestry', async () => {\n      const telemetryService = new TelemetryService(false);\n      const selectedFeatures = new Set([Feature.DOCS, Feature.TEST]);\n\n      vi.mocked(getProcessAncestry).mockReturnValue([\n        { command: 'npx storybook@8.0.5 init' },\n      ] as any);\n\n      await telemetryService.trackInitWithContext(ProjectType.REACT, selectedFeatures, true);\n\n      expect(getProcessAncestry).toHaveBeenCalled();\n      expect(telemetry).toHaveBeenCalledWith('init', {\n        projectType: ProjectType.REACT,\n        features: {\n          dev: true,\n          docs: true,\n          test: true,\n          onboarding: false,\n        },\n        newUser: true,\n        versionSpecifier: '8.0.5',\n        cliIntegration: undefined,\n      });\n    });\n\n    it('should handle ancestry errors gracefully', async () => {\n      const telemetryService = new TelemetryService(false);\n      const selectedFeatures = new Set([]);\n\n      vi.mocked(getProcessAncestry).mockImplementation(() => {\n        throw new Error('Ancestry error');\n      });\n\n      await telemetryService.trackInitWithContext(ProjectType.VUE3, selectedFeatures, false);\n\n      expect(telemetry).toHaveBeenCalledWith('init', {\n        projectType: ProjectType.VUE3,\n        features: {\n          dev: true,\n          docs: false,\n          test: false,\n          onboarding: false,\n        },\n        newUser: false,\n        versionSpecifier: undefined,\n        cliIntegration: undefined,\n      });\n    });\n\n    it('should not track when telemetry is disabled', async () => {\n      const telemetryService = new TelemetryService(true);\n      const selectedFeatures = new Set([Feature.DOCS]);\n\n      await telemetryService.trackInitWithContext(ProjectType.ANGULAR, selectedFeatures, true);\n\n      expect(getProcessAncestry).not.toHaveBeenCalled();\n      expect(telemetry).not.toHaveBeenCalled();\n    });\n\n    it('should detect CLI integration from ancestry', async () => {\n      const telemetryService = new TelemetryService(false);\n      const selectedFeatures = new Set([]);\n\n      vi.mocked(getProcessAncestry).mockReturnValue([{ command: 'sv create my-app' }] as any);\n\n      await telemetryService.trackInitWithContext(ProjectType.NEXTJS, selectedFeatures, false);\n\n      expect(telemetry).toHaveBeenCalledWith(\n        'init',\n        expect.objectContaining({\n          cliIntegration: 'sv create',\n        })\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/services/TelemetryService.ts",
    "content": "import type { ProjectType } from 'storybook/internal/cli';\nimport { telemetry } from 'storybook/internal/telemetry';\nimport { Feature } from 'storybook/internal/types';\n\nimport { getProcessAncestry } from 'process-ancestry';\n\nimport { VersionService } from './VersionService.ts';\n\n/** Service for tracking telemetry events during Storybook initialization */\nexport class TelemetryService {\n  private disableTelemetry: boolean;\n  private versionService: VersionService;\n\n  constructor(disableTelemetry: boolean = false) {\n    this.disableTelemetry = disableTelemetry;\n    this.versionService = new VersionService();\n  }\n\n  /** Track a new user check step */\n  async trackNewUserCheck(newUser: boolean): Promise<void> {\n    await this.runTelemetryIfEnabled('init-step', {\n      step: 'new-user-check',\n      newUser,\n    });\n  }\n\n  /** Track install type selection */\n  async trackInstallType(installType: 'recommended' | 'light'): Promise<void> {\n    await this.runTelemetryIfEnabled('init-step', {\n      step: 'install-type',\n      installType,\n    });\n  }\n\n  /** Track Playwright prompt decision (install | skip | aborted) */\n  async trackPlaywrightPromptDecision(\n    result: 'installed' | 'skipped' | 'aborted' | 'failed'\n  ): Promise<void> {\n    await this.runTelemetryIfEnabled('init-step', {\n      step: 'playwright-install',\n      result,\n    });\n  }\n\n  /** Track the main init event with all metadata */\n  async trackInit(data: {\n    projectType: ProjectType;\n    features: {\n      dev: boolean;\n      docs: boolean;\n      test: boolean;\n      onboarding: boolean;\n    };\n    newUser: boolean;\n    versionSpecifier?: string;\n    cliIntegration?: string;\n  }): Promise<void> {\n    await this.runTelemetryIfEnabled('init', data);\n  }\n\n  /** Track empty directory scaffolding event */\n  async trackScaffolded(data: { packageManager: string; projectType: string }): Promise<void> {\n    await this.runTelemetryIfEnabled('scaffolded-empty', data);\n  }\n\n  /**\n   * Track init with complete context including version and CLI integration from ancestry This\n   * method encapsulates all telemetry gathering and tracking logic\n   */\n  async trackInitWithContext(\n    projectType: ProjectType,\n    selectedFeatures: Set<Feature>,\n    newUser: boolean\n  ): Promise<void> {\n    if (this.disableTelemetry) {\n      return;\n    }\n\n    // Get telemetry info from process ancestry\n    let versionSpecifier: string | undefined;\n    let cliIntegration: string | undefined;\n\n    try {\n      const ancestry = getProcessAncestry();\n      versionSpecifier = this.versionService.getStorybookVersionFromAncestry(ancestry);\n      cliIntegration = this.versionService.getCliIntegrationFromAncestry(ancestry);\n    } catch {\n      // Ignore errors getting ancestry\n    }\n\n    // Create features object and track\n    const telemetryFeatures = {\n      dev: true, // Always true during init\n      docs: selectedFeatures.has(Feature.DOCS),\n      test: selectedFeatures.has(Feature.TEST),\n      onboarding: selectedFeatures.has(Feature.ONBOARDING),\n    };\n\n    await telemetry('init', {\n      projectType,\n      features: telemetryFeatures,\n      newUser,\n      versionSpecifier,\n      cliIntegration,\n    });\n  }\n\n  private runTelemetryIfEnabled(...args: Parameters<typeof telemetry>): Promise<void> {\n    if (this.disableTelemetry) {\n      return Promise.resolve();\n    }\n\n    return telemetry(...args);\n  }\n}\n"
  },
  {
    "path": "code/lib/create-storybook/src/services/VersionService.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { JsPackageManager } from 'storybook/internal/common';\n\nimport { VersionService } from './VersionService.ts';\n\nvi.mock('storybook/internal/common', async () => {\n  const actual = await vi.importActual('storybook/internal/common');\n  return {\n    ...actual,\n    versions: {\n      storybook: '8.0.0',\n    },\n  };\n});\n\ndescribe('VersionService', () => {\n  let versionService: VersionService;\n  let mockPackageManager: JsPackageManager;\n\n  beforeEach(() => {\n    versionService = new VersionService();\n    mockPackageManager = {\n      latestVersion: vi.fn(),\n    } as any;\n  });\n\n  describe('getCurrentVersion', () => {\n    it('should return the current Storybook version', () => {\n      expect(versionService.getCurrentVersion()).toBe('8.0.0');\n    });\n  });\n\n  describe('getLatestVersion', () => {\n    it('should fetch the latest version from package manager', async () => {\n      vi.mocked(mockPackageManager.latestVersion).mockResolvedValue('8.1.0');\n\n      const latestVersion = await versionService.getLatestVersion(mockPackageManager);\n\n      expect(latestVersion).toBe('8.1.0');\n      expect(mockPackageManager.latestVersion).toHaveBeenCalledWith('storybook');\n    });\n  });\n\n  describe('isPrerelease', () => {\n    it('should return true for prerelease versions', () => {\n      expect(versionService.isPrerelease('8.0.0-alpha.1')).toBe(true);\n      expect(versionService.isPrerelease('8.0.0-beta.2')).toBe(true);\n      expect(versionService.isPrerelease('8.0.0-rc.3')).toBe(true);\n    });\n\n    it('should return false for stable versions', () => {\n      expect(versionService.isPrerelease('8.0.0')).toBe(false);\n      expect(versionService.isPrerelease('8.1.2')).toBe(false);\n    });\n  });\n\n  describe('isOutdated', () => {\n    it('should return true when current version is older than latest', () => {\n      expect(versionService.isOutdated('8.0.0', '8.1.0')).toBe(true);\n      expect(versionService.isOutdated('7.6.0', '8.0.0')).toBe(true);\n    });\n\n    it('should return false when current version is same or newer', () => {\n      expect(versionService.isOutdated('8.1.0', '8.1.0')).toBe(false);\n      expect(versionService.isOutdated('8.2.0', '8.1.0')).toBe(false);\n    });\n  });\n\n  describe('getStorybookVersionFromAncestry', () => {\n    it('should extract version from create-storybook command', () => {\n      const ancestry = [\n        { command: 'npx create-storybook@8.0.5' },\n        { command: 'node /usr/local/bin/npm' },\n      ];\n\n      const version = versionService.getStorybookVersionFromAncestry(ancestry as any);\n\n      expect(version).toBe('8.0.5');\n    });\n\n    it('should extract version from storybook command', () => {\n      const ancestry = [\n        { command: 'npx storybook@latest init' },\n        { command: 'node /usr/local/bin/npm' },\n      ];\n\n      const version = versionService.getStorybookVersionFromAncestry(ancestry as any);\n\n      expect(version).toBe('latest');\n    });\n\n    it('should return undefined if no version found', () => {\n      const ancestry = [{ command: 'npm install' }, { command: 'node /usr/local/bin/npm' }];\n\n      const version = versionService.getStorybookVersionFromAncestry(ancestry as any);\n\n      expect(version).toBeUndefined();\n    });\n  });\n\n  describe('getCliIntegrationFromAncestry', () => {\n    it('should detect sv create command', () => {\n      const ancestry = [{ command: 'sv create my-app' }, { command: 'node /usr/local/bin/npm' }];\n\n      const integration = versionService.getCliIntegrationFromAncestry(ancestry as any);\n\n      expect(integration).toBe('sv create');\n    });\n\n    it('should detect sv add command', () => {\n      const ancestry = [{ command: 'sv add storybook' }, { command: 'node /usr/local/bin/npm' }];\n\n      const integration = versionService.getCliIntegrationFromAncestry(ancestry as any);\n\n      expect(integration).toBe('sv add');\n    });\n\n    it('should detect sv with version specifier', () => {\n      const ancestry = [{ command: 'sv@1.0.0 create my-app' }];\n\n      const integration = versionService.getCliIntegrationFromAncestry(ancestry as any);\n\n      expect(integration).toBe('sv create');\n    });\n\n    it('should return undefined if no sv command found', () => {\n      const ancestry = [{ command: 'npm init' }, { command: 'node /usr/local/bin/npm' }];\n\n      const integration = versionService.getCliIntegrationFromAncestry(ancestry as any);\n\n      expect(integration).toBeUndefined();\n    });\n\n    it('should detect create-rsbuild command', () => {\n      const ancestry = [{ command: 'npx create-rsbuild' }, { command: 'node /usr/local/bin/npm' }];\n\n      const integration = versionService.getCliIntegrationFromAncestry(ancestry as any);\n\n      expect(integration).toBe('create-rsbuild');\n    });\n\n    it('should detect create rsbuild with version specifier', () => {\n      const ancestry = [{ command: 'npx create-rsbuild@1.0.0 init' }];\n\n      const integration = versionService.getCliIntegrationFromAncestry(ancestry as any);\n\n      expect(integration).toBe('create-rsbuild');\n    });\n\n    it('should detect \"create rsbuild\" with space instead of dash', () => {\n      const ancestry = [{ command: 'npm create rsbuild -- my-app' }];\n\n      const integration = versionService.getCliIntegrationFromAncestry(ancestry as any);\n\n      expect(integration).toBe('create-rsbuild');\n    });\n\n    it('should NOT detect creatersbuild without separator', () => {\n      const ancestry = [{ command: 'npx creatersbuild' }];\n\n      const integration = versionService.getCliIntegrationFromAncestry(ancestry as any);\n\n      expect(integration).toBeUndefined();\n    });\n\n    it('should detect @tanstack/start command', () => {\n      const ancestry = [{ command: 'npx @tanstack/start@latest create my-app' }];\n\n      const integration = versionService.getCliIntegrationFromAncestry(ancestry as any);\n\n      expect(integration).toBe('@tanstack/start');\n    });\n\n    it('should detect @tanstack/start in middle of command chain', () => {\n      const ancestry = [\n        { command: 'pnpm @tanstack/start init' },\n        { command: 'node /usr/local/bin/pnpm' },\n      ];\n\n      const integration = versionService.getCliIntegrationFromAncestry(ancestry as any);\n\n      expect(integration).toBe('@tanstack/start');\n    });\n\n    it('should detect vike new command', () => {\n      const ancestry = [{ command: 'pnpm create vike@latest --- --react --storybook' }];\n\n      const integration = versionService.getCliIntegrationFromAncestry(ancestry as any);\n\n      expect(integration).toBe('vike');\n    });\n  });\n\n  describe('getVersionInfo', () => {\n    it('should return complete version info for stable version', async () => {\n      vi.mocked(mockPackageManager.latestVersion).mockResolvedValue('8.1.0');\n\n      const versionInfo = await versionService.getVersionInfo(mockPackageManager);\n\n      expect(versionInfo).toEqual({\n        currentVersion: '8.0.0',\n        latestVersion: '8.1.0',\n        isPrerelease: false,\n        isOutdated: true,\n      });\n    });\n\n    it('should not mark prerelease as outdated', async () => {\n      const prereleaseService = new VersionService();\n      vi.mocked(mockPackageManager.latestVersion).mockResolvedValue('8.1.0');\n\n      // Mock getCurrentVersion to return prerelease\n      vi.spyOn(prereleaseService, 'getCurrentVersion').mockReturnValue('8.0.0-alpha.1');\n\n      const versionInfo = await prereleaseService.getVersionInfo(mockPackageManager);\n\n      expect(versionInfo).toEqual({\n        currentVersion: '8.0.0-alpha.1',\n        latestVersion: '8.1.0',\n        isPrerelease: true,\n        isOutdated: false,\n      });\n    });\n\n    it('should handle null latest version', async () => {\n      vi.mocked(mockPackageManager.latestVersion).mockResolvedValue(null);\n\n      const versionInfo = await versionService.getVersionInfo(mockPackageManager);\n\n      expect(versionInfo).toEqual({\n        currentVersion: '8.0.0',\n        latestVersion: null,\n        isPrerelease: false,\n        isOutdated: false,\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/lib/create-storybook/src/services/VersionService.ts",
    "content": "import type { JsPackageManager } from 'storybook/internal/common';\nimport { versions } from 'storybook/internal/common';\n\nimport type { getProcessAncestry } from 'process-ancestry';\nimport { lt, prerelease } from 'semver';\n\n/** Service for handling version-related operations during Storybook initialization */\nexport class VersionService {\n  /** Get the current Storybook version */\n  getCurrentVersion(): string {\n    return versions.storybook;\n  }\n\n  /** Get the latest Storybook version from the package manager */\n  async getLatestVersion(packageManager: JsPackageManager): Promise<string | null> {\n    return packageManager.latestVersion('storybook');\n  }\n\n  /** Check if the current version is a prerelease version */\n  isPrerelease(version: string): boolean {\n    return !!prerelease(version);\n  }\n\n  /** Check if the current version is outdated compared to the latest version */\n  isOutdated(currentVersion: string, latestVersion: string): boolean {\n    return lt(currentVersion, latestVersion);\n  }\n\n  /**\n   * Extract Storybook version from process ancestry Looks for version specifiers in command history\n   * like: create-storybook@1.0.0 or storybook@1.0.0\n   */\n  getStorybookVersionFromAncestry(\n    ancestry: ReturnType<typeof getProcessAncestry>\n  ): string | undefined {\n    for (const ancestor of ancestry.toReversed()) {\n      const match = ancestor.command?.match(/\\s(?:create-storybook|storybook)@([^\\s]+)/);\n      if (match) {\n        return match[1];\n      }\n    }\n    return undefined;\n  }\n\n  /**\n   * Extract CLI integration from process ancestry Detects if Storybook was invoked via sv create,\n   * sv add, create-rsbuild, or @tanstack/start commands\n   */\n  getCliIntegrationFromAncestry(\n    ancestry: ReturnType<typeof getProcessAncestry>\n  ): string | undefined {\n    for (const ancestor of ancestry.toReversed()) {\n      // Check for sv create/add\n      const svMatch = ancestor.command?.match(/(?:^|\\s)(sv(?:@[^ ]+)? (?:create|add))/i);\n      if (svMatch) {\n        return svMatch[1].toLowerCase().includes('add') ? 'sv add' : 'sv create';\n      }\n      // Check for create-rsbuild or create rsbuild\n      const rsbuildMatch = ancestor.command?.match(/(?:^|\\s)create[\\s\\-]rsbuild/i);\n      if (rsbuildMatch) {\n        return 'create-rsbuild';\n      }\n      // Check for @tanstack/start\n      if (ancestor.command?.includes('@tanstack/start')) {\n        return '@tanstack/start';\n      }\n      // Check for vike\n      if (ancestor.command?.includes('vike')) {\n        return 'vike';\n      }\n    }\n    return undefined;\n  }\n\n  /** Get version info including current, latest, and prerelease status */\n  async getVersionInfo(packageManager: JsPackageManager): Promise<{\n    currentVersion: string;\n    latestVersion: string | null;\n    isPrerelease: boolean;\n    isOutdated: boolean;\n  }> {\n    const currentVersion = this.getCurrentVersion();\n    const latestVersion = await this.getLatestVersion(packageManager);\n    const isPrereleaseVersion = this.isPrerelease(currentVersion);\n    const isOutdatedVersion =\n      latestVersion && !isPrereleaseVersion\n        ? this.isOutdated(currentVersion, latestVersion)\n        : false;\n\n    return {\n      currentVersion,\n      latestVersion,\n      isPrerelease: isPrereleaseVersion,\n      isOutdated: isOutdatedVersion,\n    };\n  }\n}\n"
  },
  {
    "path": "code/lib/create-storybook/src/services/index.ts",
    "content": "/**\n * Core services for Storybook initialization\n *\n * These services provide centralized, testable functionality for the init process\n */\n\nexport { FeatureCompatibilityService } from './FeatureCompatibilityService.ts';\nexport type { FeatureCompatibilityResult } from './FeatureCompatibilityService.ts';\n\nexport { TelemetryService } from './TelemetryService.ts';\nexport { AddonService } from './AddonService.ts';\nexport { VersionService } from './VersionService.ts';\n"
  },
  {
    "path": "code/lib/create-storybook/src/typings.d.ts",
    "content": "declare var CLI_APP_INSTANCE: ReturnType<typeof render> | undefined;\n"
  },
  {
    "path": "code/lib/create-storybook/templates/angular/application/template-csf/.storybook/tsconfig.doc.json",
    "content": "// This tsconfig is used by Compodoc to generate the documentation for the project.\n// If Compodoc is not used, this file can be deleted.\n{\n  \"extends\": \"./tsconfig.json\",\n  // Exclude all files that are not needed for documentation generation.\n  \"exclude\": [\"../src/test.ts\", \"../src/**/*.spec.ts\", \"../src/**/*.stories.ts\"],\n  // Please make sure to include all files from which Compodoc should generate documentation.\n  \"include\": [\"../src/**/*\"],\n  \"files\": [\"./typings.d.ts\"]\n}\n"
  },
  {
    "path": "code/lib/create-storybook/templates/angular/application/template-csf/.storybook/tsconfig.json",
    "content": "{\n  \"extends\": \"../tsconfig.app.json\",\n  \"compilerOptions\": {\n    \"types\": [\"node\"],\n    \"allowSyntheticDefaultImports\": true,\n    \"resolveJsonModule\": true,\n    \"moduleResolution\": \"bundler\"\n  },\n  \"exclude\": [\"../src/test.ts\", \"../src/**/*.spec.ts\"],\n  \"include\": [\"../src/**/*.stories.*\", \"./preview.ts\"],\n  \"files\": [\"./typings.d.ts\"]\n}\n"
  },
  {
    "path": "code/lib/create-storybook/templates/angular/application/template-csf/.storybook/typings.d.ts",
    "content": "declare module '*.md' {\n  const content: string;\n  export default content;\n}\n"
  },
  {
    "path": "code/lib/create-storybook/templates/angular/library/template-csf/.storybook/tsconfig.json",
    "content": "{\n  \"extends\": \"../tsconfig.lib.json\",\n  \"compilerOptions\": {\n    \"types\": [\"node\"],\n    \"allowSyntheticDefaultImports\": true,\n    \"resolveJsonModule\": true\n  },\n  \"exclude\": [\"../src/test.ts\", \"../src/**/*.spec.ts\"],\n  \"include\": [\"../src/**/*.stories.*\", \"./preview.ts\"],\n  \"files\": [\"./typings.d.ts\"]\n}\n"
  },
  {
    "path": "code/lib/create-storybook/templates/angular/library/template-csf/.storybook/typings.d.ts",
    "content": "declare module '*.md' {\n  const content: string;\n  export default content;\n}\n"
  },
  {
    "path": "code/lib/create-storybook/templates/aurelia/template-csf/.storybook/tsconfig.json",
    "content": "{\n  \"extends\": \"%SET_DURING_SB_INIT%\",\n  \"compilerOptions\": {\n    \"types\": [\"node\"]\n  },\n  \"exclude\": [\"../src/test.ts\", \"../src/**/*.spec.ts\", \"../projects/**/*.spec.ts\"],\n  \"include\": [\"../src/**/*\", \"../projects/**/*\"],\n  \"files\": [\"./typings.d.ts\"]\n}\n"
  },
  {
    "path": "code/lib/create-storybook/templates/aurelia/template-csf/.storybook/typings.d.ts",
    "content": "declare module '*.md' {\n  const content: string;\n  export default content;\n}\n"
  },
  {
    "path": "code/lib/create-storybook/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"moduleResolution\": \"bundler\",\n    \"module\": \"ES2022\"\n  },\n  \"include\": [\"src/**/*\", \"./src/typings.d.ts\"]\n}\n"
  },
  {
    "path": "code/lib/create-storybook/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/lib/csf-plugin/README.md",
    "content": "# CSF Plugin\n\nThe CSF plugin reads CSF files and enriches their content via static analysis.\nIt supports Webpack, Vite, and other bundlers using [unplugin](https://github.com/unjs/unplugin).\n\n## Source snippets\n\nCSF plugin can add static source snippets to each story. For example:\n\n```js\nexport const Basic = () => <Button />;\n```\n\nWould be transformed to:\n\n```js\nexport const Basic = () => <Button />;\nBasic.parameters = {\n  storySource: {\n    source: '() => <Button />',\n  },\n  ...Basic.parameters,\n};\n```\n\nThis allows `@storybook/addon-docs` to display the static source snippet.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/lib/csf-plugin/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    node: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./webpack-loader'],\n        entryPoint: './src/webpack-loader.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/lib/csf-plugin/package.json",
    "content": "{\n  \"name\": \"@storybook/csf-plugin\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Enrich CSF files via static analysis\",\n  \"keywords\": [\n    \"storybook\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/lib/csf-plugin\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/lib/csf-plugin\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"sideEffects\": false,\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./webpack-loader\": \"./dist/webpack-loader.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"unplugin\": \"^2.3.5\"\n  },\n  \"devDependencies\": {\n    \"typescript\": \"^5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"esbuild\": \"*\",\n    \"rollup\": \"*\",\n    \"storybook\": \"workspace:^\",\n    \"vite\": \"*\",\n    \"webpack\": \"*\"\n  },\n  \"peerDependenciesMeta\": {\n    \"esbuild\": {\n      \"optional\": true\n    },\n    \"rollup\": {\n      \"optional\": true\n    },\n    \"vite\": {\n      \"optional\": true\n    },\n    \"webpack\": {\n      \"optional\": true\n    }\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/lib/csf-plugin/project.json",
    "content": "{\n  \"name\": \"csf-plugin\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/lib/csf-plugin/src/constants.ts",
    "content": "export const STORIES_REGEX = /(?<!node_modules.*)\\.(story|stories)\\.[tj]sx?$/;\n"
  },
  {
    "path": "code/lib/csf-plugin/src/index.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport type { EnrichCsfOptions } from 'storybook/internal/csf-tools';\n\nimport type { UnpluginFactory } from 'unplugin';\nimport { createUnplugin } from 'unplugin';\n\nimport { STORIES_REGEX } from './constants.ts';\nimport { rollupBasedPlugin } from './rollup-based-plugin.ts';\n\nexport type CsfPluginOptions = EnrichCsfOptions;\n\nexport const unpluginFactory: UnpluginFactory<EnrichCsfOptions> = (options) => {\n  return {\n    name: 'unplugin-csf',\n    rollup: {\n      ...rollupBasedPlugin(options),\n    },\n    vite: {\n      enforce: 'pre',\n      ...(rollupBasedPlugin(options) as any),\n    },\n    webpack(compiler) {\n      compiler.options.module.rules.unshift({\n        test: STORIES_REGEX,\n        enforce: 'post',\n        use: {\n          options,\n          loader: fileURLToPath(import.meta.resolve('@storybook/csf-plugin/webpack-loader')),\n        },\n      });\n    },\n    rspack(compiler) {\n      compiler.options.module.rules.unshift({\n        test: STORIES_REGEX,\n        enforce: 'post',\n        use: {\n          options,\n          loader: fileURLToPath(import.meta.resolve('@storybook/csf-plugin/webpack-loader')),\n        },\n      });\n    },\n  };\n};\n\nexport const unplugin = /* #__PURE__ */ createUnplugin(unpluginFactory);\n\nexport const { esbuild } = unplugin;\nexport const { webpack } = unplugin;\nexport const { rollup } = unplugin;\nexport const { vite } = unplugin;\n"
  },
  {
    "path": "code/lib/csf-plugin/src/rollup-based-plugin.ts",
    "content": "import { readFile } from 'node:fs/promises';\n\nimport type { EnrichCsfOptions } from 'storybook/internal/csf-tools';\nimport { enrichCsf, formatCsf, loadCsf } from 'storybook/internal/csf-tools';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport type { RollupPlugin } from 'unplugin';\n\nimport { STORIES_REGEX } from './constants.ts';\n\nexport function rollupBasedPlugin(options: EnrichCsfOptions): Partial<RollupPlugin<any>> {\n  return {\n    name: 'plugin-csf',\n    async transform(code, id) {\n      if (!STORIES_REGEX.test(id)) {\n        return;\n      }\n\n      const sourceCode = await readFile(id, 'utf-8');\n      try {\n        const makeTitle = (userTitle: string) => userTitle || 'default';\n        const csf = loadCsf(code, { makeTitle }).parse();\n        const csfSource = loadCsf(sourceCode, {\n          makeTitle,\n        }).parse();\n        await enrichCsf(csf, csfSource, options);\n        const inputSourceMap = this.getCombinedSourcemap();\n        return formatCsf(csf, { sourceMaps: true, inputSourceMap }, code);\n      } catch (err: any) {\n        // This can be called on legacy storiesOf files, so just ignore\n        // those errors. But warn about other errors.\n        if (!err.message?.startsWith('CSF:')) {\n          logger.warn(err.message);\n        }\n        return code;\n      }\n    },\n  };\n}\n"
  },
  {
    "path": "code/lib/csf-plugin/src/webpack-loader.ts",
    "content": "import { readFile } from 'node:fs/promises';\n\nimport type { EnrichCsfOptions } from 'storybook/internal/csf-tools';\nimport { enrichCsf, formatCsf, loadCsf } from 'storybook/internal/csf-tools';\n\ninterface LoaderContext {\n  async: () => (err: Error | null, result?: string, map?: any) => void;\n  getOptions: () => EnrichCsfOptions;\n  resourcePath: string;\n}\n\nasync function loader(this: LoaderContext, content: string, map: any) {\n  const callback = this.async();\n  const options = this.getOptions();\n  const id = this.resourcePath;\n\n  const sourceCode = await readFile(id, 'utf-8');\n\n  try {\n    const makeTitle = (userTitle: string) => userTitle || 'default';\n    const csf = loadCsf(content, { makeTitle }).parse();\n    const csfSource = loadCsf(sourceCode, { makeTitle }).parse();\n    await enrichCsf(csf, csfSource, options);\n    const formattedCsf = formatCsf(\n      csf,\n      { sourceMaps: true, inputSourceMap: map, sourceFileName: id },\n      content\n    );\n\n    if (typeof formattedCsf === 'string') {\n      return callback(null, formattedCsf, map);\n    }\n\n    callback(null, formattedCsf.code, formattedCsf.map);\n  } catch (err: any) {\n    // This can be called on legacy storiesOf files, so just ignore\n    // those errors. But warn about other errors.\n    if (!err.message?.startsWith('CSF:')) {\n      console.warn(err.message);\n    }\n    callback(null, content, map);\n  }\n}\n\nexport default loader;\n"
  },
  {
    "path": "code/lib/csf-plugin/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/lib/csf-plugin/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/lib/eslint-plugin/CONTRIBUTING.md",
    "content": "## Table of Contents\n\n- [About the project](#about-the-project)\n- [Getting started](#getting-started)\n  - [Creating a new rule](#creating-a-new-rule)\n    - [Important metadata for a rule](#important-metadata-for-a-rule)\n  - [Testing rules](#testing-rules)\n  - [Updating configs or documentation](#updating-configs-or-documentation)\n  - [Useful resources](#useful-resources)\n\n# About the project\n\nThe ESLint plugin for Storybook aims to help steer developers into using the best practices when writing their stories. The rules should be auto-fixable when possible, to improve the developer experience as much as we can.\n\n# Getting started\n\nFirst of all, thank you so much for taking the time to contribute to this project.\n\n### Creating a new rule\n\nRun the following command and answer the prompts:\n\n```sh\nyarn generate-rule\n```\n\nThis command will generate the rule file, tests as well as the documentation page.\nThe generated files will look like this:\n\n```\ndocs/rules/<rule-name>.md\nsrc/rules/<rule-name>.js\ntests/rules/<rule-name>.js\n```\n\nThis command will auto-generate the test file with an example for you. Please refer to existing tests if more reference is needed.\n\n#### Important metadata for a rule\n\n```js\nimport { CategoryId } from '../utils/constants';\n\nmodule.exports = {\n  meta: {\n    severity: 'error', // whether the rule should yield 'warn' or 'error'\n    docs: {\n      categories: [CategoryId.RECOMMENDED], // You should always use an existing category from the CategoryId enum], or create a new one there\n      excludeFromConfig: true, // If the rule is not ready to be shipped in any category, set this flag to true, otherwise remove it\n    },\n  },\n  ...otherProperties,\n};\n```\n\n### Testing rules\n\nRun the following command for testing the rules:\n\n```sh\nyarn test\n```\n\nIf you want to run tests for a particular rule and skip the rest, you can do so like this:\n\n```js\nruleTester.run('my-rule-name', rule, {\n  valid: [\n    'export default { component: Button }',\n  ],\n\n  invalid: [\n    {\n      only: true, // <-- Add this property, which is equivalent to it.only in jest\n      code: \"export default { title: 'Button', component: Button }\",\n      errors: [ ... ],\n    },\n  ]\n})\n```\n\n### Updating configs or documentation\n\nWhen you make changes to rules or create/delete rules, the configuration files and documentation have to be updated. For that, run the following command:\n\n```sh\nyarn update-rules\n```\n\nor rebuild the package:\n\n```sh\nnx build eslint-plugin\n```\n\n### Useful resources\n\n- The [ESLint official developer guide](https://eslint.org/docs/developer-guide/working-with-rules) can be useful to assist when writing rules\n- The [AST Explorer](https://astexplorer.net/) website is the perfect place to get reference to writing rules. Given that ESLint rules are based in AST (Abstract Syntax Tree), you can paste an example code there and visualize all properties of the resulting AST of that code.\n- Storybook has a discord community! And we need more people like you. Please [join us](https://discord.gg/storybook) and say hi in the [#contributing](https://discord.com/channels/486522875931656193/839297503446695956) channel! 👋\n"
  },
  {
    "path": "code/lib/eslint-plugin/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://storybook.js.org/?ref=readme\">\n    <img src=\"https://user-images.githubusercontent.com/321738/63501763-88dbf600-c4cc-11e9-96cd-94adadc2fd72.png\" alt=\"Storybook\" width=\"400\" />\n  </a>\n</p>\n\n<p align=\"center\">Build bulletproof UI components faster</p>\n\n<br/>\n\n<p align=\"center\">\n  <a href=\"https://discord.gg/storybook\">\n    <img src=\"https://img.shields.io/badge/discord-join-7289DA.svg?logo=discord&longCache=true&style=flat\" />\n  </a>\n  <a href=\"https://storybook.js.org/community/?ref=readme\">\n    <img src=\"https://img.shields.io/badge/community-join-4BC424.svg\" alt=\"Storybook Community\" />\n  </a>\n  <a href=\"#backers\">\n    <img src=\"https://opencollective.com/storybook/backers/badge.svg\" alt=\"Backers on Open Collective\" />\n  </a>\n  <a href=\"#sponsors\">\n    <img src=\"https://opencollective.com/storybook/sponsors/badge.svg\" alt=\"Sponsors on Open Collective\" />\n  </a>\n  <a href=\"https://twitter.com/intent/follow?screen_name=storybookjs\">\n    <img src=\"https://badgen.net/twitter/follow/storybookjs?icon=twitter&label=%40storybookjs\" alt=\"Official Twitter Handle\" />\n  </a>\n</p>\n\n# eslint-plugin-storybook\n\nBest practice rules for Storybook\n\n## Installation\n\nYou'll first need to install [ESLint](https://eslint.org/):\n\n```sh\nnpm install eslint --save-dev\n# or\nyarn add eslint --dev\n```\n\nNext, install `eslint-plugin-storybook`:\n\n```sh\nnpm install eslint-plugin-storybook --save-dev\n# or\nyarn add eslint-plugin-storybook --dev\n```\n\nAnd finally, add this to your `.eslintignore` file:\n\n```\n// Inside your .eslintignore file\n!.storybook\n```\n\nThis allows for this plugin to also lint your configuration files inside the .storybook folder, so that you always have a correct configuration and don't face any issues regarding mistyped addon names, for instance.\n\n> For more info on why this line is required in the .eslintignore file, check this [ESLint documentation](https://eslint.org/docs/latest/use/configure/ignore-deprecated#:~:text=In%20addition%20to,contents%20are%20ignored).\n\nIf you are using [flat config style](https://eslint.org/docs/latest/use/configure/configuration-files-new), add this to your configuration file:\n\n```js\nimport { defineConfig, globalIgnores } from 'eslint/config';\n\nexport default defineConfig([\n  globalIgnores(['!.storybook'], 'Include Storybook Directory'),\n  // ...\n]);\n```\n\n## ESLint compatibility\n\nUse the following table to use the correct version of this package, based on the version of ESLint you're using:\n\n| ESLint version | Storybook plugin version |\n| -------------- | ------------------------ |\n| ^9.0.0         | ^0.10.0                  |\n| ^8.57.0        | ^0.10.0                  |\n| ^7.0.0         | ~0.9.0                   |\n\n## Usage\n\n### Configuration (`.eslintrc`)\n\nUse `.eslintrc.*` file to configure rules in ESLint < v9. See also: https://eslint.org/docs/latest/use/configure/.\n\nAdd `plugin:storybook/recommended` to the extends section of your `.eslintrc` configuration file. Note that we can omit the `eslint-plugin-` prefix:\n\n```js\n{\n  // extend plugin:storybook/<configuration>, such as:\n  \"extends\": [\"plugin:storybook/recommended\"]\n}\n```\n\nThis plugin will only be applied to files following the `*.stories.*` (we recommend this) or `*.story.*` pattern. This is an automatic configuration, so you don't have to do anything.\n\n#### Overriding/disabling rules\n\nOptionally, you can override, add or disable rules settings. You likely don't want these settings to be applied in every file, so make sure that you add a `overrides` section in your `.eslintrc.*` file that applies the overrides only to your stories files.\n\n```js\n{\n  \"overrides\": [\n    {\n      // or whatever matches stories specified in .storybook/main.js\n      \"files\": ['**/*.stories.@(ts|tsx|js|jsx|mjs|cjs)'],\n      \"rules\": {\n        // example of overriding a rule\n        'storybook/hierarchy-separator': 'error',\n        // example of disabling a rule\n        'storybook/default-exports': 'off',\n      }\n    }\n  ]\n}\n```\n\n### Configuration (`eslint.config.[c|m]?js`)\n\nUse `eslint.config.[c|m]?js` file to configure rules using the [flat config style](https://eslint.org/docs/latest/use/configure/configuration-files-new). This is the default in ESLint v9, but can be used starting from ESLint v8.57.0. See also: https://eslint.org/docs/latest/use/configure/configuration-files-new.\n\n```js\nimport storybook from 'eslint-plugin-storybook';\n\nexport default [\n  // add more generic rulesets here, such as:\n  // js.configs.recommended,\n  ...storybook.configs['flat/recommended'],\n\n  // something ...\n];\n```\n\nIn case you are using utility functions from tools like `tseslint`, you might need to set the plugin a little differently:\n\n```ts\nimport storybook from 'eslint-plugin-storybook';\nimport somePlugin from 'some-plugin';\nimport tseslint from 'typescript-eslint';\n\nexport default tseslint.config(\n  somePlugin,\n  storybook.configs['flat/recommended'] // notice that it is not destructured\n);\n```\n\n#### Overriding/disabling rules\n\nOptionally, you can override, add or disable rules settings. You likely don't want these settings to be applied in every file, so make sure that you add a flat config section in your `eslint.config.[m|c]?js` file that applies the overrides only to your stories files.\n\n```js\nimport storybook from 'eslint-plugin-storybook';\n\nexport default [\n  // ...\n\n  ...storybook.configs['flat/recommended'],\n  {\n    files: ['**/*.stories.@(ts|tsx|js|jsx|mjs|cjs)'],\n    rules: {\n      // example of overriding a rule\n      'storybook/hierarchy-separator': 'error',\n      // example of disabling a rule\n      'storybook/default-exports': 'off',\n    },\n  },\n\n  // something ...\n];\n```\n\n### MDX Support\n\nThis plugin does not support MDX files.\n\n## Supported Rules and configurations\n\n<!-- RULES-LIST:START -->\n\n**Key**: 🔧 = fixable\n\n**Configurations**: csf, csf-strict, addon-interactions, recommended\n\n| Name                                                                                       | Description                                                                                                                   | 🔧  | Included in configurations                                                                                                     |\n| ------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | --- | ------------------------------------------------------------------------------------------------------------------------------ |\n| [`storybook/await-interactions`](./docs/rules/await-interactions.md)                       | Interactions should be awaited                                                                                                | 🔧  | <ul><li>addon-interactions</li><li>flat/addon-interactions</li><li>recommended</li><li>flat/recommended</li></ul>              |\n| [`storybook/context-in-play-function`](./docs/rules/context-in-play-function.md)           | Pass a context when invoking play function of another story                                                                   |     | <ul><li>recommended</li><li>flat/recommended</li><li>addon-interactions</li><li>flat/addon-interactions</li></ul>              |\n| [`storybook/csf-component`](./docs/rules/csf-component.md)                                 | The component property should be set                                                                                          |     | <ul><li>csf</li><li>flat/csf</li><li>csf-strict</li><li>flat/csf-strict</li></ul>                                              |\n| [`storybook/default-exports`](./docs/rules/default-exports.md)                             | Story files should have a default export                                                                                      | 🔧  | <ul><li>csf</li><li>flat/csf</li><li>recommended</li><li>flat/recommended</li><li>csf-strict</li><li>flat/csf-strict</li></ul> |\n| [`storybook/hierarchy-separator`](./docs/rules/hierarchy-separator.md)                     | Deprecated hierarchy separator in title property                                                                              | 🔧  | <ul><li>csf</li><li>flat/csf</li><li>recommended</li><li>flat/recommended</li><li>csf-strict</li><li>flat/csf-strict</li></ul> |\n| [`storybook/meta-inline-properties`](./docs/rules/meta-inline-properties.md)               | Meta should only have inline properties                                                                                       |     | N/A                                                                                                                            |\n| [`storybook/meta-satisfies-type`](./docs/rules/meta-satisfies-type.md)                     | Meta should use `satisfies Meta`                                                                                              | 🔧  | N/A                                                                                                                            |\n| [`storybook/no-redundant-story-name`](./docs/rules/no-redundant-story-name.md)             | A story should not have a redundant name property                                                                             | 🔧  | <ul><li>csf</li><li>flat/csf</li><li>recommended</li><li>flat/recommended</li><li>csf-strict</li><li>flat/csf-strict</li></ul> |\n| [`storybook/no-stories-of`](./docs/rules/no-stories-of.md)                                 | storiesOf is deprecated and should not be used                                                                                |     | <ul><li>csf-strict</li><li>flat/csf-strict</li></ul>                                                                           |\n| [`storybook/no-title-property-in-meta`](./docs/rules/no-title-property-in-meta.md)         | Do not define a title in meta                                                                                                 | 🔧  | <ul><li>csf-strict</li><li>flat/csf-strict</li></ul>                                                                           |\n| [`storybook/no-uninstalled-addons`](./docs/rules/no-uninstalled-addons.md)                 | This rule identifies storybook addons that are invalid because they are either not installed or contain a typo in their name. |     | <ul><li>recommended</li><li>flat/recommended</li></ul>                                                                         |\n| [`storybook/prefer-pascal-case`](./docs/rules/prefer-pascal-case.md)                       | Stories should use PascalCase                                                                                                 | 🔧  | <ul><li>recommended</li><li>flat/recommended</li></ul>                                                                         |\n| [`storybook/story-exports`](./docs/rules/story-exports.md)                                 | A story file must contain at least one story export                                                                           |     | <ul><li>recommended</li><li>flat/recommended</li><li>csf</li><li>flat/csf</li><li>csf-strict</li><li>flat/csf-strict</li></ul> |\n| [`storybook/use-storybook-expect`](./docs/rules/use-storybook-expect.md)                   | Use expect from `@storybook/test`, `storybook/test` or `@storybook/jest`                                                      | 🔧  | <ul><li>addon-interactions</li><li>flat/addon-interactions</li><li>recommended</li><li>flat/recommended</li></ul>              |\n| [`storybook/use-storybook-testing-library`](./docs/rules/use-storybook-testing-library.md) | Do not use testing-library directly on stories                                                                                | 🔧  | <ul><li>addon-interactions</li><li>flat/addon-interactions</li><li>recommended</li><li>flat/recommended</li></ul>              |\n\n<!-- RULES-LIST:END -->\n\n## Contributors\n\nLooking into improving this plugin? That would be awesome!\nPlease refer to [the contributing guidelines](./CONTRIBUTING.md) for steps to contributing.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/lib/eslint-plugin/build-config.ts",
    "content": "import path from 'node:path';\n\nimport { x as exec } from 'tinyexec';\n\nimport type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  prebuild: async (cwd) => {\n    await exec('jiti', [path.join(import.meta.dirname, 'scripts', 'update-all.ts')], {\n      nodeOptions: {\n        cwd,\n        env: {\n          ...process.env,\n          FORCE_COLOR: '1',\n        },\n        stdio: 'inherit',\n      },\n      throwOnError: true,\n    });\n  },\n  entries: {\n    node: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/lib/eslint-plugin/docs/rules/await-interactions.md",
    "content": "# await-interactions\n\n<!-- RULE-CATEGORIES:START -->\n\n**Included in these configurations**: <ul><li>addon-interactions</li><li>flat/addon-interactions</li><li>recommended</li><li>flat/recommended</li></ul>\n\n<!-- RULE-CATEGORIES:END -->\n\n## Rule Details\n\nStorybook provides an instrumented version of the testing library in the [storybook/test](https://github.com/storybookjs/storybook/tree/next/code/core/src/test) core package (formerly available in [@storybook/testing-library](https://github.com/storybookjs/testing-library/)). When [writing interactions](https://storybook.js.org/docs/writing-tests/interaction-testing#writing-interaction-tests), make sure to **await** them, so that addon-interactions can intercept these helper functions and allow you to step through them when debugging.\n\nExamples of **incorrect** code for this rule:\n\n```js\nimport { userEvent, within } from \"storybook/test\";\n\n// or from the legacy package \"@storybook/testing-library\";\n\nMyStory.play = (context) => {\n  const canvas = within(context.canvasElement);\n  // not awaited!\n  userEvent.click(canvas.getByRole(\"button\"));\n};\n```\n\nExamples of **correct** code for this rule:\n\n```js\nimport { userEvent, within } from \"storybook/test\";\n\n// or from the legacy package \"@storybook/testing-library\";\n\nMyStory.play = async (context) => {\n  const canvas = within(context.canvasElement);\n  // awaited 👍\n  await userEvent.click(canvas.getByRole(\"button\"));\n};\n```\n\n## When Not To Use It\n\nThis rule should not be applied in test files. Please ensure you are defining the Storybook rules only for story files. You can see more details [here](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin#overridingdisabling-rules).\n"
  },
  {
    "path": "code/lib/eslint-plugin/docs/rules/context-in-play-function.md",
    "content": "# context-in-play-function\n\n<!-- RULE-CATEGORIES:START -->\n\n**Included in these configurations**: <ul><li>recommended</li><li>flat/recommended</li><li>addon-interactions</li><li>flat/addon-interactions</li></ul>\n\n<!-- RULE-CATEGORIES:END -->\n\n## Rule Details\n\nWhen invoking the play function from another story, it's necessary to pass the full context as an argument to it. The context that Storybook provides to the play function has internal functionality that is necessary for the interactions to work correctly.\n\nExamples of **incorrect** code for this rule:\n\n```js\nimport { within, userEvent } from '@storybook/testing-library'\n\nMyStory.play = ({ canvasElement }) => {\n  const canvas = within(canvasElement)\n  // not passing any context\n  await MyOtherStory.play()\n\n  userEvent.click(canvas.getByRole('button'))\n}\n```\n\n```js\nimport { within, userEvent } from '@storybook/testing-library'\n\nMyStory.play = ({ canvasElement }) => {\n  const canvas = within(canvasElement)\n  // not passing the full context\n  await MyOtherStory.play({ canvasElement })\n\n  userEvent.click(canvas.getByRole('button'))\n}\n```\n\nExamples of **correct** code for this rule:\n\n```js\nimport { within, userEvent } from '@storybook/testing-library'\n\nMyStory.play = (context) => {\n  const canvas = within(context.canvasElement)\n  // passing full context 👍\n  await MyOtherStory.play(context)\n\n  await userEvent.click(canvas.getByRole('button'))\n}\n```\n\n```js\nimport { within, userEvent } from '@storybook/testing-library'\n\nMyStory.play = ({ context, canvasElement }) => {\n  const canvas = within(canvasElement)\n  // passing self referencing context property 👍\n  await MyOtherStory.play(context)\n\n  await userEvent.click(canvas.getByRole('button'))\n}\n```\n\n## When Not To Use It\n\nThis rule should not be applied in test files. Please ensure you are defining the Storybook rules only for story files. You can see more details [here](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin#overridingdisabling-rules).\n"
  },
  {
    "path": "code/lib/eslint-plugin/docs/rules/csf-component.md",
    "content": "# Component property must be set in meta (csf-component)\n\n<!-- RULE-CATEGORIES:START -->\n\n**Included in these configurations**: <ul><li>csf</li><li>flat/csf</li><li>csf-strict</li><li>flat/csf-strict</li></ul>\n\n<!-- RULE-CATEGORIES:END -->\n\n## Rule Details\n\nThis rule encourages you to set the `component` property of your CSF default export. The `component` property is optional, but configuring it unlocks a variety of features in Storybook, including automatic prop table documentation in most frameworks, auto-generated controls for dynamically editing your stories, and, in CSF3, a reasonable default for rendering your component without having to define a render function.\n\nExamples of **incorrect** code for this rule:\n\n```js\nexport default {\n  title: \"Button\",\n};\n```\n\nExamples of **correct** code for this rule:\n\n```js\nexport default {\n  title: \"Button\",\n  component: Button,\n};\n```\n\n## When Not To Use It\n\nWhile we encourage each CSF file to clearly correspond to a single component, it's possible to organize a Storybook in any way you choose. If you have a different organizational scheme, this rule may not apply to you.\n\n## Further Reading\n\n- [Automatic argType inference](https://storybook.js.org/docs/api/arg-types#automatic-argtype-inference)\n"
  },
  {
    "path": "code/lib/eslint-plugin/docs/rules/default-exports.md",
    "content": "# Stories file should have a default export (default-exports)\n\n<!-- RULE-CATEGORIES:START -->\n\n**Included in these configurations**: <ul><li>csf</li><li>flat/csf</li><li>recommended</li><li>flat/recommended</li><li>csf-strict</li><li>flat/csf-strict</li></ul>\n\n<!-- RULE-CATEGORIES:END -->\n\n## Rule Details\n\nIn [CSF](https://storybook.js.org/docs/writing-stories#component-story-format), a story file should contain a _default export_ that describes the component, and _named exports_ that describe the stories. This rule enforces the definition of a default export in story files.\n\nExamples of **incorrect** code for this rule:\n\n```js\n// no default export\nexport const Primary = {};\n```\n\nExamples of **correct** code for this rule:\n\n```js\nexport default {\n  title: \"Button\",\n  args: { primary: true },\n  component: Button,\n};\nexport const Primary = {};\n```\n\n## When Not To Use It\n\nThis rule should only be applied in your `.stories.*` files. Please ensure that you define the Storybook rules only for story files. You can see more details [here](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin#overridingdisabling-rules).\n\nIf you're using Storybook 6.5 and [CSF in MDX](https://github.com/storybookjs/storybook/blob/v6.5.0/addons/docs/docs/recipes.md#csf-stories-with-mdx-docs), you should disable this rule for the stories that use CSF in MDX. You can see how to override the rule [here](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin#overridingdisabling-rules).\n\n## Further Reading\n\nMore information about defining stories here: https://storybook.js.org/docs/writing-stories#defining-stories\n"
  },
  {
    "path": "code/lib/eslint-plugin/docs/rules/hierarchy-separator.md",
    "content": "# Deprecated hierarchy separator (hierarchy-separator)\n\n<!-- RULE-CATEGORIES:START -->\n\n**Included in these configurations**: <ul><li>csf</li><li>flat/csf</li><li>recommended</li><li>flat/recommended</li><li>csf-strict</li><li>flat/csf-strict</li></ul>\n\n<!-- RULE-CATEGORIES:END -->\n\n## Rule Details\n\nSince Storybook 6.0, the ability to specify the hierarchy separators (how you control the grouping of story kinds in the sidebar) has been removed. There is now a single separator `/`, which cannot be configured. If you are using `|` or `.` as a separator, you should change all of them to `/`.\n\nExamples of **incorrect** code for this rule:\n\n```js\nexport default {\n  title: \"Components|Forms/Input\",\n  component: Input,\n};\n```\n\nExamples of **correct** code for this rule:\n\n```js\nexport default {\n  title: \"Components/Forms/Input\",\n  component: Input,\n};\n```\n\n## Further Reading\n\nFor more details about this change: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#removed-hierarchy-separators\n\nTo automatically migrate all of your codebase and fix this issue, run this codemod in the root folder of your project:\n\n```sh\nnpx storybook@latest migrate upgrade-hierarchy-separators --glob=\"*/**/*.stories.@(tsx|jsx|ts|js)\"\n```\n"
  },
  {
    "path": "code/lib/eslint-plugin/docs/rules/meta-inline-properties.md",
    "content": "# Meta should only have inline properties (meta-inline-properties)\n\n<!-- RULE-CATEGORIES:START -->\n\n**Included in these configurations**: N/A\n\n<!-- RULE-CATEGORIES:END -->\n\n## Rule Details\n\nThis rule encourages you to use inline property definitions for the default export in your CSF file. The reason is that there are a bunch of tools in Storybook that rely on static analysis of your CSF code, and inline properties (rather than variables, functions, etc.) are much easier to process. Authoring your files this way may save you headaches in the future when, for example, you try to run an automated codemod to upgrade your stories to the latest version of CSF.\n\nExamples of **incorrect** code for this rule:\n\n```js\nconst title = \"Button\";\nconst args = { primary: true };\n\nexport default {\n  title,\n  args,\n  component: Button,\n};\n```\n\nExamples of **correct** code for this rule:\n\n```js\nexport default {\n  title: \"Button\",\n  args: { primary: true },\n  component: Button,\n};\n```\n"
  },
  {
    "path": "code/lib/eslint-plugin/docs/rules/meta-satisfies-type.md",
    "content": "# Meta should be followed by `satisfies Meta` (meta-satisfies-type)\n\n<!-- RULE-CATEGORIES:START -->\n\n**Included in these configurations**: N/A\n\n<!-- RULE-CATEGORIES:END -->\n\n## Rule Details\n\nThis rule enforces writing `satisfies Meta` after the definition of the meta object. This is useful to ensure that stories use the correct properties in the metadata.\n\nAdditionally, `satisfies` is preferred over type annotations (`const meta: Meta = {...}`) and type assertions (`const meta = {...} as Meta`). This is because other types like `StoryObj` will check to see which properties are defined in meta and use them for increased type safety. Using type annotations or assertions hides this information from the type-checker, so `satisfies` should be used instead.\n\nExamples of **incorrect** code for this rule:\n\n```ts\nexport default {\n  title: \"Button\",\n  args: { primary: true },\n  component: Button,\n};\n```\n\n```ts\nconst meta: Meta<typeof Button> = {\n  title: \"Button\",\n  args: { primary: true },\n  component: Button,\n};\nexport default meta;\n```\n\nExamples of **correct** code for this rule:\n\n```ts\nexport default {\n  title: \"Button\",\n  args: { primary: true },\n  component: Button,\n} satisfies Meta<typeof Button>;\n```\n\n```ts\nconst meta = {\n  title: \"Button\",\n  args: { primary: true },\n  component: Button,\n} satisfies Meta<typeof Button>;\nexport default meta;\n```\n\n## When Not To Use It\n\nIf you aren't using TypeScript or you're using a version older than TypeScript 4.9, `satisfies` is not supported and you can avoid this rule.\n\n## Further Reading\n\nMore information on writing stories with TypeScript: https://storybook.js.org/docs/writing-stories/typescript\n"
  },
  {
    "path": "code/lib/eslint-plugin/docs/rules/no-redundant-story-name.md",
    "content": "# Named exports should not use the name annotation if it is redundant to the name that would be generated by the export name (no-redundant-story-name)\n\n<!-- RULE-CATEGORIES:START -->\n\n**Included in these configurations**: <ul><li>csf</li><li>flat/csf</li><li>recommended</li><li>flat/recommended</li><li>csf-strict</li><li>flat/csf-strict</li></ul>\n\n<!-- RULE-CATEGORIES:END -->\n\n## Rule Details\n\nStorybook automatically resolves a story name based on its named export. You can rename any particular story you'd like, but if the name is redundant to what Storybook will resolve, you don't need to do that.\n\nExamples of **incorrect** code for this rule:\n\n```js\nexport const PrimaryButton = {\n  // no need for this, as Storybook will resolve to this name already\n  name: \"Primary Button\",\n};\n```\n\nExamples of **correct** code for this rule:\n\n```js\nexport const PrimaryButton = {\n  name: \"I am the primary\",\n};\n```\n\n## When Not To Use It\n\nWhen you set a custom name for a story, it will ensure that the resolved story name will always be that same name, regardless of whether you rename the export later on. If that is your reason for keeping story names set, even if they are redundant, you should turn this rule off.\n"
  },
  {
    "path": "code/lib/eslint-plugin/docs/rules/no-renderer-packages.md",
    "content": "# Do not import renderer packages directly in stories (no-renderer-packages)\n\n<!-- RULE-CATEGORIES:START -->\n\n**Included in these configurations**: <ul><li>recommended</li><li>flat/recommended</li></ul>\n\n<!-- RULE-CATEGORIES:END -->\n\n## Rule Details\n\nThis rule prevents importing Storybook renderer packages directly into stories. Instead, use framework-specific packages designed for your build tool (e.g., Vite, Webpack).\n\nThe rule will suggest appropriate framework packages based on which renderer you're trying to use:\n\n- For `@storybook/html`: Use `@storybook/html-vite`\n- For `@storybook/preact`: Use `@storybook/preact-vite`\n- For `@storybook/react`: Use `@storybook/nextjs`, `@storybook/nextjs-vite`, `@storybook/react-vite`, `@storybook/react-webpack5`, or `@storybook/react-native-web-vite`\n- For `@storybook/server`: Use `@storybook/server-webpack5`\n- For `@storybook/svelte`: Use `@storybook/svelte-vite`, or `@storybook/sveltekit`\n- For `@storybook/vue3`: Use `@storybook/vue3-vite`\n- For `@storybook/web-components`: Use `@storybook/web-components-vite`\n\nExamples of **incorrect** code for this rule:\n\n```js\n// Don't import renderer packages directly\nimport { something } from \"@storybook/react\";\nimport { something } from \"@storybook/vue3\";\nimport { something } from \"@storybook/web-components\";\n```\n\nExamples of **correct** code for this rule:\n\n```js\n// Do use the appropriate framework package for your build tool\nimport { something } from \"@storybook/react-vite\"; // For Vite\nimport { something } from \"@storybook/vue3-vite\"; // For Vite\nimport { something } from \"@storybook/web-components-vite\"; // For Vite\nimport { something } from \"@storybook/nextjs\"; // For Next.js\n```\n\n## When Not To Use It\n\nIf you have a specific need to use renderer packages directly in your stories, you can turn off this rule. However, it's recommended to use the framework-specific packages as they are optimized for your build tool and provide better integration with your development environment.\n\n## Further Reading\n\nFor more information about Storybook's framework-specific packages and build tools, see:\n\n- [Storybook for React](https://storybook.js.org/docs/get-started/frameworks/react-vite)\n- [Storybook for Vue](https://storybook.js.org/docs/get-started/frameworks/vue3-vite)\n- [Storybook for Web Components](https://storybook.js.org/docs/get-started/frameworks/web-components-vite)\n- [Storybook for Svelte](https://storybook.js.org/docs/get-started/frameworks/svelte-vite)\n- [Storybook for HTML](https://storybook.js.org/docs/get-started/install?renderer=html)\n- [Storybook for Preact](https://storybook.js.org/docs/get-started/frameworks/preact-vite)\n"
  },
  {
    "path": "code/lib/eslint-plugin/docs/rules/no-stories-of.md",
    "content": "# storiesOf is deprecated and should not be used (no-stories-of)\n\n<!-- RULE-CATEGORIES:START -->\n\n**Included in these configurations**: <ul><li>csf-strict</li><li>flat/csf-strict</li></ul>\n\n<!-- RULE-CATEGORIES:END -->\n\n## Rule Details\n\nStarting with Storybook 5.2, the Component Story Format ([CSF](https://storybook.js.org/docs/api/csf)) was introduced as the preferred way to write stories. The `storiesOf` API is now removed and should be avoided in favor of CSF.\n\nExamples of **incorrect** code for this rule:\n\n```js\nimport { storiesOf } from \"@storybook/react\";\n\nimport Button from \"../components/Button\";\n\nstoriesOf(\"Button\", module).add(\"primary\", () => <Button primary />);\n```\n\nExamples of **correct** code for this rule:\n\n```js\nimport Button from \"../components/Button\";\n\nexport default = {\n  component: Button\n}\n\nexport const Primary = () => <Button primary />\n```\n\n```js\nimport Button from \"../components/Button\";\n\nexport default = {\n  component: Button\n}\n\nexport const Primary = {\n  args: {\n    primary: true\n  }\n}\n```\n\n## Further Reading\n\nFor more information about the change from `storiesOf` to `CSF`, read here: https://github.com/storybookjs/storybook/blob/master/lib/core/docs/storiesOf.md\n\nTo automatically migrate all of your codebase, run this codemod in the root folder of your project:\n\n```sh\nnpx storybook@latest migrate storiesof-to-csf --glob=\"*/**/*.stories.@(tsx|jsx|ts|js)\"\n```\n"
  },
  {
    "path": "code/lib/eslint-plugin/docs/rules/no-title-property-in-meta.md",
    "content": "# Meta should not have a title property (no-title-property-in-meta)\n\n<!-- RULE-CATEGORIES:START -->\n\n**Included in these configurations**: <ul><li>csf-strict</li><li>flat/csf-strict</li></ul>\n\n<!-- RULE-CATEGORIES:END -->\n\n## Rule Details\n\nStarting in [CSF 3.0](https://storybook.js.org/blog/storybook-csf3-is-here/), story titles can be generated automatically. You can still specify a title like in CSF 2.0, but if you don't define it, it can be inferred from the story's path on disk.\nThis rule aims to enforce not setting a title, making the codebase consistent.\n\nExamples of **incorrect** code for this rule:\n\n```js\nexport default {\n  title: \"Components/Forms/Input\",\n  component: Input,\n};\n```\n\nExamples of **correct** code for this rule:\n\n```js\nexport default {\n  component: Input, // no title necessary, it will be inferred from path on disk!\n};\n```\n\n## When Not To Use It\n\nIf you're not strictly enforcing this rule in your codebase (thus allowing custom titles), you should turn off this rule.\n\n## Further Reading\n\nYou can find more information about CSF3 and story titles here: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#optional-titles\n"
  },
  {
    "path": "code/lib/eslint-plugin/docs/rules/no-uninstalled-addons.md",
    "content": "# no-uninstalled-addons\n\n<!-- RULE-CATEGORIES:START -->\n\n**Included in these configurations**: <ul><li>recommended</li><li>flat/recommended</li></ul>\n\n<!-- RULE-CATEGORIES:END -->\n\n## Rule Details\n\nThis rule checks if all addons registered in `.storybook/main.js|ts` are properly listed in the root `package.json` of your project.\n\nFor instance, if the `@storybook/addon-links` is in the `.storybook/main.js|ts` file but is not listed in the project's `package.json`, this rule will notify the user to install it.\n\nAs an important side note, this rule checks for the `package.json` file at the **root level** of your project. You can customize the location of the `package.json` by [setting the `packageJsonLocation` option](#configure).\n\nAnother very important side note: your ESLint config must allow linting the `.storybook` folder. By default, ESLint ignores all dot-files, so this folder will be ignored. To allow this rule to lint the `.storybook/main.js` file, it's essential to configure ESLint to lint this file. This can be achieved by writing something like:\n\n```\n// Inside your .eslintignore file\n!.storybook\n```\n\nFor more info, check this [ESLint documentation](https://eslint.org/docs/latest/use/configure/ignore-deprecated#:~:text=In%20addition%20to,contents%20are%20ignored).\n\nExamples of **incorrect** code for this rule:\n\n```js\n// in .storybook/main.js\nmodule.exports = {\n  addons: [\n    '@storybook/addon-links',\n    '@storybook/addon-a11y', // <-- this addon is not listed in the package.json\n  ],\n}\n\n// package.json\n{\n  \"devDependencies\": {\n    \"@storybook/addon-links\": \"0.0.1\",\n    \"@storybook/addon-a11y\": \"0.0.1\",\n  }\n}\n```\n\nExamples of **correct** code for this rule:\n\n```js\n// in .storybook/main.js\nmodule.exports = {\n  addons: [\n    '@storybook/addon-links',\n    '@storybook/addon-a11y',\n  ],\n}\n\n// package.json\n{\n  \"devDependencies\": {\n    \"@storybook/addon-links\": \"0.0.1\",\n    \"@storybook/addon-a11y\": \"0.0.1\"\n  }\n}\n```\n\n### Configure\n\n#### `packageJsonLocation`\n\nThis rule assumes that the `package.json` is located in the root of your project. You can customize this by setting the `packageJsonLocation` option of the rule:\n\n```js\nmodule.exports = {\n  rules: {\n    \"storybook/no-uninstalled-addons\": [\n      \"error\",\n      { packageJsonLocation: \"./folder/package.json\" },\n    ],\n  },\n};\n```\n\nNote that the path must be relative to the location from which ESLint runs, which is typically the root of the project.\n\n#### `ignore`\n\nYou can also ignore specific addons by providing an ignore array in the options:\n\n```js\nmodule.exports = {\n  rules: {\n    \"storybook/no-uninstalled-addons\": [\n      \"error\",\n      {\n        packageJsonLocation: \"./folder/package.json\",\n        ignore: [\"custom-addon\"],\n      },\n    ],\n  },\n};\n```\n\n### What if I use a different Storybook config directory?\n\nSome Storybook folders use a different name for their config directory other than `.storybook`. This rule will not be applied there by default. If you have a custom location for your Storybook config directory, then you must add an override in your `.eslintrc.js` file, defining your config directory:\n\n```js\n{\n  overrides: [\n      {\n        files: ['your-config-dir/main.@(js|cjs|mjs|ts)'],\n        rules: {\n          'storybook/no-uninstalled-addons': 'error'\n        },\n      },\n    ],\n}\n```\n\n## When Not To Use It\n\nThis rule is convenient to use because if the user tries to start Storybook but has forgotten to install the plugin, Storybook will throw very unusual errors that provide no clue to the user about what's going wrong. To prevent that, this rule should always be on.\n\n## Further Reading\n\nCheck the issue in GitHub: [https://github.com/storybookjs/eslint-plugin-storybook/issues/95](https://github.com/storybookjs/eslint-plugin-storybook/issues/95)\n"
  },
  {
    "path": "code/lib/eslint-plugin/docs/rules/prefer-pascal-case.md",
    "content": "# Prefer pascal case for story names (prefer-pascal-case)\n\n<!-- RULE-CATEGORIES:START -->\n\n**Included in these configurations**: <ul><li>recommended</li><li>flat/recommended</li></ul>\n\n<!-- RULE-CATEGORIES:END -->\n\n## Rule Details\n\nAs a best practice, stories should be defined in [_PascalCase_](https://en.wiktionary.org/wiki/Pascal_case). This makes it easier to differentiate stories from other code visually. Plus, it makes it simpler to define regexes for [non-story exports](https://storybook.js.org/docs/api/csf#non-story-exports).\n\nExamples of **incorrect** code for this rule:\n\n```js\nexport const primaryButton = {};\n```\n\nExamples of **correct** code for this rule:\n\n```js\nexport const PrimaryButton = {};\n```\n\n## Further Reading\n\nMore information about naming stories can be found here: https://storybook.js.org/docs/writing-stories#defining-stories\n"
  },
  {
    "path": "code/lib/eslint-plugin/docs/rules/story-exports.md",
    "content": "# story-exports\n\n<!-- RULE-CATEGORIES:START -->\n\n**Included in these configurations**: <ul><li>recommended</li><li>flat/recommended</li><li>csf</li><li>flat/csf</li><li>csf-strict</li><li>flat/csf-strict</li></ul>\n\n<!-- RULE-CATEGORIES:END -->\n\n## Rule Details\n\nIn [CSF](https://storybook.js.org/docs/writing-stories#component-story-format), a story file should contain a _default export_ that describes the component, and _named exports_ that represent the stories. This rule enforces the definition of at least one named export in story files.\n\nExamples of **incorrect** code for this rule:\n\n```js\nexport default {\n  title: \"Button\",\n  args: { primary: true },\n  component: Button,\n};\n// no named export\n```\n\nExamples of **correct** code for this rule:\n\n```js\nexport default {\n  title: \"Button\",\n  args: { primary: true },\n  component: Button,\n};\nexport const Primary = {}; // at least one named export!\n```\n\n## When Not To Use It\n\nThis rule should only be applied in your `.stories.*` files. Please ensure that you define the Storybook rules only for story files. You can see more details [here](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin#overridingdisabling-rules).\n\n## Further Reading\n\nMore information about defining stories here: https://storybook.js.org/docs/writing-stories#defining-stories\n"
  },
  {
    "path": "code/lib/eslint-plugin/docs/rules/use-storybook-expect.md",
    "content": "# Use expect from &#39;@storybook/jest&#39; (use-storybook-expect)\n\n<!-- RULE-CATEGORIES:START -->\n\n**Included in these configurations**: <ul><li>addon-interactions</li><li>flat/addon-interactions</li><li>recommended</li><li>flat/recommended</li></ul>\n\n<!-- RULE-CATEGORIES:END -->\n\n## Rule Details\n\nStorybook provides a browser-compatible version of `expect` via the [storybook/test](https://github.com/storybookjs/storybook/tree/next/code/core/src/test) core package (formerly available in the legacy [@storybook/jest](https://github.com/storybookjs/jest) library).\nWhen [writing interactions](https://storybook.js.org/docs/essentials/interactions) and asserting values, you should always use `expect` from the `storybook/test` library.\n\nExamples of **incorrect** code for this rule:\n\n```js\nDefault.play = async () => {\n  // Using global expect from Jest. Will break on the browser\n  await expect(123).toEqual(123);\n};\n```\n\nExamples of **correct** code for this rule:\n\n```js\n// Correct import.\nimport { expect } from \"storybook/test\";\n// or this, which is now considered legacy\nimport { expect } from \"@storybook/jest\";\n\nDefault.play = async () => {\n  // Using imported expect from storybook package\n  await expect(123).toEqual(123);\n};\n```\n\n## When Not To Use It\n\nThis rule should not be applied in test files. Please ensure that you define the Storybook rules only for story files. You can see more details [here](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin#overridingdisabling-rules).\n"
  },
  {
    "path": "code/lib/eslint-plugin/docs/rules/use-storybook-testing-library.md",
    "content": "# Use storybook testing library package (use-storybook-testing-library)\n\n<!-- RULE-CATEGORIES:START -->\n\n**Included in these configurations**: <ul><li>addon-interactions</li><li>flat/addon-interactions</li><li>recommended</li><li>flat/recommended</li></ul>\n\n<!-- RULE-CATEGORIES:END -->\n\n## Rule Details\n\nStorybook provides an instrumented version of the testing library in the [storybook/test](https://github.com/storybookjs/storybook/tree/next/code/core/src/test) core package (formerly available in [@storybook/testing-library](https://github.com/storybookjs/testing-library/) library).\nWhen [writing interactions](https://storybook.js.org/docs/essentials/interactions), make sure to use the helper functions from `storybook/test`, so that addon-interactions can intercept these helper functions and allow you to step through them when debugging.\n\nExamples of **incorrect** code for this rule:\n\n```js\n// wrong import!\nimport { within } from \"@testing-library/react\";\n\nDefault.play = async (context) => {\n  const canvas = within(context.canvasElement);\n};\n```\n\nExamples of **correct** code for this rule:\n\n```js\n// correct import.\nimport { within } from \"storybook/test\";\n// or this, which is now considered legacy\nimport { within } from \"@storybook/testing-library\";\n\nDefault.play = async (context) => {\n  const canvas = within(context.canvasElement);\n};\n```\n\n## When Not To Use It\n\nThis rule should not be applied in test files. Please ensure that you define the Storybook rules only for story files. You can see more details [here](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin#overridingdisabling-rules).\n"
  },
  {
    "path": "code/lib/eslint-plugin/package.json",
    "content": "{\n  \"name\": \"eslint-plugin-storybook\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook ESLint Plugin: Best practice rules for writing stories\",\n  \"keywords\": [\n    \"eslint\",\n    \"eslintplugin\",\n    \"eslint-plugin\",\n    \"storybook\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/lib/eslint-plugin#readme\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook\",\n    \"directory\": \"code/lib/eslint-plugin\"\n  },\n  \"license\": \"MIT\",\n  \"author\": \"yannbf@gmail.com\",\n  \"contributors\": [\n    {\n      \"name\": \"Rafael Rozon\",\n      \"email\": \"rafaelrozon.developer@gmail.com\"\n    }\n  ],\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"README.md\"\n  ],\n  \"scripts\": {\n    \"generate-rule\": \"jiti ./scripts/generate-rule\",\n    \"prep\": \"jiti ../../../scripts/build/build-package.ts\"\n  },\n  \"dependencies\": {\n    \"@typescript-eslint/utils\": \"^8.48.0\"\n  },\n  \"devDependencies\": {\n    \"@types/eslint\": \"^8.56.2\",\n    \"@types/node\": \"^22.19.1\",\n    \"@types/prompts\": \"^2.0.9\",\n    \"@typescript-eslint/eslint-plugin\": \"^8.48.0\",\n    \"@typescript-eslint/parser\": \"^8.48.0\",\n    \"@typescript-eslint/rule-tester\": \"^8.48.0\",\n    \"@vitest/coverage-v8\": \"^3.2.4\",\n    \"eslint\": \"^8.57.1\",\n    \"eslint-plugin-eslint-plugin\": \"^6.5.0\",\n    \"eslint-plugin-node\": \"^11.1.0\",\n    \"prettier\": \"^3.7.1\",\n    \"prompts\": \"^2.4.0\",\n    \"ts-dedent\": \"^2.0.0\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"eslint\": \">=8\",\n    \"storybook\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/lib/eslint-plugin/project.json",
    "content": "{\n  \"name\": \"eslint-plugin\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/lib/eslint-plugin/scripts/generate-rule.ts",
    "content": "import cp from 'node:child_process';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport type { PromptObject } from 'prompts';\nimport prompts from 'prompts';\nimport { dedent } from 'ts-dedent';\n\nconst logger = console;\n\ntype Answers = {\n  authorName: string;\n  ruleId: string;\n  ruleDescription: string;\n  isAutoFixable: boolean;\n};\n\n// CLI questions\nconst questions: PromptObject<keyof Answers>[] = [\n  {\n    type: 'text',\n    name: 'authorName',\n    initial: '',\n    message: 'What is your name? (to be given credit for the rule)',\n    validate: (name: string) => (name === '' ? \"Name can't be empty\" : true),\n  },\n  {\n    type: 'text',\n    name: 'ruleId',\n    message: dedent(`Time to name your rule! Follow the ESLint rule naming conventions:\n\n      - If your rule is disallowing something, prefix it with no- such as no-eval for disallowing eval() and no-debugger for disallowing debugger.\n      - If your rule is enforcing the inclusion of something, use a short name without a special prefix.\n      - Use dashes between words.\n      What is the ID of this new rule?\n    `),\n    validate: (rule: string) => (rule === '' ? \"Rule can't be empty\" : true),\n  },\n  {\n    type: 'text',\n    name: 'ruleDescription',\n    message: 'Type a short description of this rule',\n    validate: (rule: string) => (rule === '' ? \"Description can't be empty\" : true),\n  },\n  {\n    type: 'confirm',\n    name: 'isAutoFixable',\n    message: 'Will this rule contain an autofix?',\n    initial: true,\n  },\n];\n\nconst generateRule = async () => {\n  logger.log(\n    '👋 Welcome to the Storybook ESLint rule generator! Please answer a few questions so I can provide everything you need for your new rule.'\n  );\n  logger.log('');\n  const { authorName, ruleId, ruleDescription, isAutoFixable } = await prompts(questions, {\n    onCancel: () => {\n      logger.log('Process canceled by the user.');\n      process.exit(0);\n    },\n  });\n\n  const ruleFile = path.resolve(__dirname, `../src/rules/${ruleId}.ts`);\n  const testFile = path.resolve(__dirname, `../tests/rules/${ruleId}.test.ts`);\n  const docFile = path.resolve(__dirname, `../docs/rules/${ruleId}.md`);\n\n  logger.log(`creating src/rules/${ruleId}.ts`);\n  await fs.writeFile(\n    ruleFile,\n    dedent(`/**\n       * @fileoverview ${ruleDescription}\n       * @author ${authorName}\n       */\n\n      import { TSESTree } from '@typescript-eslint/utils'\n      import { createStorybookRule } from '../utils/create-storybook-rule'\n      import { CategoryId } from '../utils/constants'\n      import { isIdentifier, isVariableDeclaration } from '../utils/ast'\n\n      //------------------------------------------------------------------------------\n      // Rule Definition\n      //------------------------------------------------------------------------------\n\n      export default createStorybookRule({\n        name: '${ruleId}',\n        defaultOptions: [],\n        meta: {\n          type: 'problem', // \\`problem\\`, \\`suggestion\\`, or \\`layout\\`\n          severity: 'error', // or 'warn'\n          docs: {\n            description: '${ruleDescription}',\n            // Add the categories that suit this rule.\n            categories: [CategoryId.RECOMMENDED],\n          },\n          messages: {\n            anyMessageIdHere: 'Fill me in',\n          },\n          ${isAutoFixable ? \"fixable: 'code',\" : ''}\n          ${isAutoFixable ? 'hasSuggestions: true,' : ''}\n          schema: [], // Add a schema if the rule has options. Otherwise remove this\n        },\n\n        create(context) {\n          // variables should be defined here\n\n          //----------------------------------------------------------------------\n          // Helpers\n          //----------------------------------------------------------------------\n\n          // any helper functions should go here or else delete this section\n\n          //----------------------------------------------------------------------\n          // Public\n          //----------------------------------------------------------------------\n\n          return {\n            /**\n             * 👉 Please read this and then delete this entire comment block.\n             * This is an example rule that reports an error in case a named export is called 'wrong'.\n             * Hopefully this will guide you to write your own rules. Make sure to always use the AST utilities and account for all possible cases.\n             *\n             * Keep in mind that sometimes AST nodes change when in javascript or typescript format. For example, the type of \"declaration\" from \"export default {}\" is ObjectExpression but in \"export default {} as SomeType\" is TSAsExpression.\n             *\n             * Use https://eslint.org/docs/developer-guide/working-with-rules for Eslint API reference\n             * And check https://astexplorer.net/ to help write rules\n             * Working with AST is fun. Good luck!\n             */\n            ExportNamedDeclaration: function (node: TSESTree.ExportNamedDeclaration) {\n              const declaration = node.declaration\n              if (!declaration) return\n              // use AST helpers to make sure the nodes are of the right type\n              if (isVariableDeclaration(declaration)) {\n                const identifier = declaration.declarations[0]?.id\n                if (isIdentifier(identifier)) {\n                  const { name } = identifier\n                  if (name === 'wrong') {\n                    context.report({\n                      node,\n                      messageId: 'anyMessageIdHere',\n                    })\n                  }\n                }\n              }\n            },\n          }\n        },\n      })\n\n`)\n  );\n\n  logger.log(`creating tests/rules/${ruleId}.test.ts`);\n  await fs.writeFile(\n    testFile,\n    dedent(`/**\n         * @fileoverview ${ruleDescription}\n         * @author ${authorName}\n         */\n\n        //------------------------------------------------------------------------------\n        // Requirements\n        //------------------------------------------------------------------------------\n\n        import rule from '../../src/rules/${ruleId}'\n        import ruleTester from '../utils/rule-tester'\n\n        //------------------------------------------------------------------------------\n        // Tests\n        //------------------------------------------------------------------------------\n\n        ruleTester.run('${ruleId}', rule, {\n          /**\n           * 👉 Please read this and delete this entire comment block.\n           * This is an example test for a rule that reports an error in case a named export is called 'wrong'\n           * Use https://eslint.org/docs/developer-guide/working-with-rules for Eslint API reference\n           */\n          valid: ['export const correct = {}'],\n          invalid: [\n            {\n              code: 'export const wrong = {}',\n              errors: [\n                {\n                  messageId: 'anyMessageIdHere', // comes from the rule file\n                },\n              ],\n            },\n          ],\n        })\n\n`)\n  );\n\n  logger.log(`creating docs/rules/${ruleId}.md`);\n  await fs.writeFile(\n    docFile,\n    dedent(`\n      # ${ruleId}\n\n      <!-- RULE-CATEGORIES:START -->\n      <!-- RULE-CATEGORIES:END -->\n\n      ## Rule Details\n\n      ${ruleDescription}.\n\n      Examples of **incorrect** code for this rule:\n\n      \\`\\`\\`js\n      // fill me in\n      \\`\\`\\`\n\n      Examples of **correct** code for this rule:\n\n      \\`\\`\\`js\n      // fill me in\n      \\`\\`\\`\n\n      ### Options\n\n      If there are any options, describe them here. Otherwise, delete this section.\n\n      ## When Not To Use It\n\n      Give a short description of when it would be appropriate to turn off this rule. If not applicable, delete this section.\n\n      ## Further Reading\n\n      If there are other links that describe the issue this rule addresses, please include them here in a bulleted list. Otherwise, delete this section.\n\n`)\n  );\n\n  const { shouldOpenInVSCode } = await prompts({\n    type: 'confirm',\n    name: 'shouldOpenInVSCode',\n    message: 'Do you want to open the newly generated files in VS Code?',\n    initial: false,\n  });\n\n  if (shouldOpenInVSCode) {\n    cp.execSync(`code \"${ruleFile}\"`);\n    cp.execSync(`code \"${testFile}\"`);\n    cp.execSync(`code \"${docFile}\"`);\n  }\n\n  logger.log(\n    '\\n🚀 All done! Make sure to run `yarn test` as you write the rule and `yarn update-rules` when you are done. This script will update the necessary config and docs files to reflect your changes.'\n  );\n  logger.log(`❤️  Thanks for helping this plugin get better, ${authorName.split(' ')[0]}!`);\n};\n\ngenerateRule().catch((error) => {\n  logger.error('An error occurred while generating the rule:', error);\n  process.exit(1);\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/scripts/update-all.ts",
    "content": "async function run() {\n  await import('./update-configs.ts');\n  await import('./update-rules-list.ts');\n}\n\nrun().catch((error) => {\n  console.error(error);\n  process.exit(1);\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/scripts/update-configs.ts",
    "content": "/*\nThis script updates `lib/*.js` files from rule's meta data.\n*/\nimport fs from 'fs/promises';\nimport path from 'path';\n\nimport { update as updateLegacyConfigs } from './update-lib-configs.ts';\nimport { update as updateFlatConfigs } from './update-lib-flat-configs.ts';\nimport { update as updateIndex } from './update-lib-index.ts';\n\nconst ROOT_CONFIG_DIR = path.resolve(__dirname, '../src/configs/');\n\nasync function run() {\n  // cleanup\n  await fs.rm(ROOT_CONFIG_DIR, { recursive: true });\n\n  // updates\n  await updateLegacyConfigs();\n  await updateFlatConfigs();\n  await updateIndex();\n}\n\nrun().catch((error) => {\n  console.error(error);\n  process.exit(1);\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/scripts/update-lib-configs.ts",
    "content": "/*\nThis script updates `lib/configs/*.js` files from rule's meta data.\n*/\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport { format } from 'oxfmt';\nimport type { TCategory } from './utils/categories.ts';\nimport { categories } from './utils/categories.ts';\nimport {\n  MAIN_JS_FILE,\n  STORIES_GLOBS,\n  extendsCategories,\n  formatRules,\n  formatSingleRule,\n} from './utils/updates.ts';\n\nfunction formatCategory(category: TCategory) {\n  const extendsCategoryId = extendsCategories[category.categoryId];\n  if (extendsCategoryId == null) {\n    return `/*\n      * IMPORTANT!\n      * This file has been automatically generated,\n      * in order to update its content, execute \"yarn update-rules\" or rebuild this package.\n      */\n      export default {\n        plugins: [\n          'storybook'\n        ],\n        overrides: [{\n          files: [${STORIES_GLOBS.join(', ')}],\n          rules: ${formatRules(category.rules, ['storybook/no-uninstalled-addons'])}\n        }, {\n          files: [${MAIN_JS_FILE.join(', ')}],\n          rules: ${formatSingleRule(category.rules, 'storybook/no-uninstalled-addons')}\n        }]\n      }\n    `;\n  }\n  return `/*\n    * IMPORTANT!\n    * This file has been automatically generated,\n    * in order to update its content, execute \"yarn update-rules\" or rebuild this package.\n    */\n    export default {\n      // This file is bundled in an index.js file at the root\n      // so the reference is relative to the src directory\n      extends: './configs/${extendsCategoryId}',\n      overrides: [{\n        files: [${STORIES_GLOBS.join(', ')}],\n        rules: ${formatRules(category.rules)}\n      },]\n    }\n  `;\n}\n\nconst CONFIG_DIR = path.resolve(__dirname, '../src/configs/');\n\nexport async function update() {\n  // setup config directory\n  await fs.mkdir(CONFIG_DIR);\n\n  // Update/add rule files\n  await Promise.all(\n    categories.map(async (category) => {\n      const filePath = path.join(CONFIG_DIR, `${category.categoryId}.ts`);\n      const { code: content } = await format(\n        `${category.categoryId}.ts`,\n        formatCategory(category),\n        { singleQuote: true }\n      );\n\n      await fs.writeFile(filePath, content);\n    })\n  );\n}\n"
  },
  {
    "path": "code/lib/eslint-plugin/scripts/update-lib-flat-configs.ts",
    "content": "/*\nThis script updates `lib/configs/flat/*.js` files from rule's meta data.\n*/\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport { format } from 'oxfmt';\nimport type { TCategory } from './utils/categories.ts';\nimport { categories } from './utils/categories.ts';\nimport {\n  MAIN_JS_FILE,\n  STORIES_GLOBS,\n  extendsCategories,\n  formatRules,\n  formatSingleRule,\n} from './utils/updates.ts';\n\nfunction formatCategory(category: TCategory) {\n  const extendsCategoryId = extendsCategories[category.categoryId];\n  if (extendsCategoryId == null) {\n    return `\n      import storybookPlugin from '../../index.ts';\n\n      /*\n      * IMPORTANT!\n      * This file has been automatically generated,\n      * in order to update its content, execute \"yarn update-rules\" or rebuild this package.\n      */\n      export default [\n        {\n          name: 'storybook:${category.categoryId}:setup',\n          plugins: {\n            get storybook() {\n              // this getter could just be a direct import, but we need to use a getter to avoid circular references in the types\n              return storybookPlugin;\n            },\n          }\n        },\n        {\n          name: 'storybook:${category.categoryId}:stories-rules',\n          files: [${STORIES_GLOBS.join(', ')}],\n          rules: ${formatRules(category.rules, ['storybook/no-uninstalled-addons'])}\n        },\n        {\n          name: 'storybook:${category.categoryId}:main-rules',\n          files: [${MAIN_JS_FILE.join(', ')}],\n          rules: ${formatSingleRule(category.rules, 'storybook/no-uninstalled-addons')}\n        }\n      ]\n    `;\n  }\n  return `/*\n    * IMPORTANT!\n    * This file has been automatically generated,\n    * in order to update its content, execute \"yarn update-rules\" or rebuild this package.\n    */\n    import config from './${extendsCategoryId}.ts'\n\n    export default [\n      ...config,\n      {\n        name: 'storybook:${category.categoryId}:rules',\n        files: [${STORIES_GLOBS.join(', ')}],\n        rules: ${formatRules(category.rules)}\n      }\n    ]\n  `;\n}\n\nconst FLAT_CONFIG_DIR = path.resolve(import.meta.dirname, '../src/configs/flat');\n\nexport async function update() {\n  // setup config directory\n  await fs.mkdir(FLAT_CONFIG_DIR, { recursive: true }).catch(() => {});\n\n  // Update/add rule files\n  await Promise.all(\n    categories.map(async (category) => {\n      const filePath = path.join(FLAT_CONFIG_DIR, `${category.categoryId}.ts`);\n      const { code: content } = await format(\n        `${category.categoryId}.ts`,\n        formatCategory(category),\n        { singleQuote: true }\n      );\n\n      await fs.writeFile(filePath, content);\n    })\n  );\n}\n"
  },
  {
    "path": "code/lib/eslint-plugin/scripts/update-lib-index.ts",
    "content": "'use strict';\n\n/*\nThis script updates `src/index.js` file from rule's meta data.\n*/\nimport fs from 'fs/promises';\nimport path from 'path';\nimport { format } from 'oxfmt';\n\nimport { categoryIds } from './utils/categories.ts';\nimport rules from './utils/rules.ts';\n\nfunction camelize(text: string) {\n  const a = text.toLowerCase().replace(/[-_\\s.]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''));\n  return a.substring(0, 1).toLowerCase() + a.substring(1);\n}\n\nexport async function update() {\n  const rawContent = `/*\n * IMPORTANT!\n * This file has been automatically generated,\n * in order to update its content execute \"yarn update\"\n */\n// configs\n${categoryIds\n  .map((categoryId) => `import ${camelize(categoryId)} from './configs/${categoryId}.ts'`)\n  .join('\\n')}\n${categoryIds\n  .map(\n    (categoryId) =>\n      `import ${camelize(`flat-${categoryId}`)} from './configs/flat/${categoryId}.ts'`\n  )\n  .join('\\n')}\n\n// rules\n${rules.map((rule) => `import ${camelize(rule.name)} from './rules/${rule.name}.ts'`).join('\\n')}\n\nexport const configs = {\n    // eslintrc configs\n    ${categoryIds.map((categoryId) => `'${categoryId}': ${camelize(categoryId)}`).join(',\\n')},\n\n    // flat configs\n    ${categoryIds\n      .map((categoryId) => `'flat/${categoryId}': ${camelize(`flat-${categoryId}`)}`)\n      .join(',\\n')},\n};\n\nexport const rules = {\n    ${rules.map((rule) => `'${rule.name}': ${camelize(rule.name)}`).join(',\\n')}\n};\n\nexport default {\n  configs,\n  rules,\n}\n`;\n  const { code: content } = await format('index.ts', rawContent, { singleQuote: true });\n  await fs.writeFile(path.resolve(__dirname, '../src/index.ts'), content);\n}\n"
  },
  {
    "path": "code/lib/eslint-plugin/scripts/update-rules-list.ts",
    "content": "import { emojiKey, updateRulesDocs, writeRulesListInReadme } from './utils/docs.ts';\nimport rules from './utils/rules.ts';\nimport { extendsCategories } from './utils/updates.ts';\n\n/*\nThis script updates the rules table in `README.md`from rule's meta data.\n*/\n\nexport type TRulesList = readonly [\n  ruleName: string,\n  ruleLink: string,\n  docsDescription: string,\n  fixable: string,\n  categories: string,\n];\nexport type TRuleListWithoutName = TRulesList extends readonly [string, ...infer TRulesWithoutName]\n  ? TRulesWithoutName\n  : never;\n\nconst ruleDocsPath =\n  'https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin/docs/rules/';\nconst createRuleLink = (ruleName: string) =>\n  `[\\`storybook/${ruleName}\\`](${ruleDocsPath}${ruleName}.md)`;\n\nconst rulesList: TRulesList[] = Object.entries(rules)\n  .sort(([_, { name: ruleNameA }], [__, { name: ruleNameB }]) => {\n    return ruleNameA.localeCompare(ruleNameB);\n  })\n  .map(([_, rule]) => {\n    const ruleCategories: string[] = rule.meta.docs?.categories ?? [];\n\n    Object.entries(extendsCategories).map(([category, extendedCategory]) => {\n      if (\n        extendedCategory &&\n        !ruleCategories.includes(category) &&\n        ruleCategories.includes(extendedCategory)\n      ) {\n        ruleCategories.push(category);\n      }\n    });\n\n    return [\n      rule.name,\n      createRuleLink(rule.name),\n      rule.meta.docs?.description || '',\n      rule.meta.fixable ? emojiKey.fixable : '',\n      rule.meta.docs?.excludeFromConfig\n        ? 'N/A'\n        : ruleCategories\n          ? `<ul>${ruleCategories.map((c) => `<li>${c}</li><li>flat/${c}</li>`).join('')}</ul>`\n          : '',\n    ];\n  });\n\nasync function run() {\n  await writeRulesListInReadme(rulesList);\n\n  await updateRulesDocs(rulesList);\n}\n\nrun().catch((error) => {\n  console.error(error);\n  process.exit(1);\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/scripts/utils/categories.ts",
    "content": "import { CategoryId } from '../../src/utils/constants.ts';\nimport type { TRules } from './rules.ts';\nimport rules from './rules.ts';\n\ntype TCategoriesConfig = Record<string, { text: string; rules: TRules }>;\n\nconst categoriesConfig: TCategoriesConfig = {\n  [CategoryId.CSF]: {\n    text: 'CSF Rules',\n    rules: [],\n  },\n  [CategoryId.CSF_STRICT]: {\n    text: 'Strict CSF Rules',\n    rules: [],\n  },\n  [CategoryId.ADDON_INTERACTIONS]: {\n    text: 'Rules for writing interactions in Storybook',\n    rules: [],\n  },\n  [CategoryId.RECOMMENDED]: {\n    text: 'Base rules recommended by Storybook',\n    rules: [],\n  },\n};\n\nexport const categoryIds = Object.keys(categoriesConfig) as CategoryId[];\n\nfor (const categoryId of categoryIds) {\n  const category = categoriesConfig[categoryId] as (typeof categoriesConfig)[CategoryId];\n  category.rules = [];\n\n  for (const rule of rules) {\n    const ruleCategories = rule.meta.docs?.categories;\n\n    if (\n      categoriesConfig[categoryId] &&\n      ruleCategories?.includes(categoryId) &&\n      rule.meta.docs?.excludeFromConfig !== true\n    ) {\n      categoriesConfig[categoryId].rules?.push(rule);\n    }\n  }\n}\n\nexport const categories = categoryIds\n  .map((categoryId) => {\n    const category = categoriesConfig[categoryId] as (typeof categoriesConfig)[CategoryId];\n    if (!category.rules.length) {\n      throw new Error(\n        `Category \"${categoryId}\" has no rules. Make sure that at least one rule is linked to this category.`\n      );\n    }\n\n    return {\n      categoryId,\n      title: category,\n      rules: category.rules.filter((rule) => !rule.meta.deprecated),\n    };\n  })\n  .filter((category) => category.rules.length >= 1);\n\nexport type TCategory = typeof categories extends (infer TCat)[] ? TCat : never;\n"
  },
  {
    "path": "code/lib/eslint-plugin/scripts/utils/docs.ts",
    "content": "import { readFile, writeFile } from 'fs/promises';\nimport { resolve } from 'path';\nimport { format, resolveConfig } from 'prettier';\n\nimport type { TRuleListWithoutName, TRulesList } from '../update-rules-list.ts';\nimport { categoryIds } from './categories.ts';\n\nconst prettierConfig = resolveConfig(__dirname);\nconst readmePath = resolve(\n  __dirname,\n  `../../../../../docs/configure/integration/eslint-plugin.mdx`\n);\nconst ruleDocsPath = resolve(__dirname, `../../docs/rules`);\n\nexport const configBadges = categoryIds.reduce(\n  (badges, category) => ({\n    ...badges,\n    // in case we ever want to add nice looking badges. Not in use at the moment\n    [category]: `![${category}-badge][]`,\n  }),\n  {}\n);\n\nexport const emojiKey = {\n  fixable: '✅',\n};\n\nconst staticElements = {\n  listHeaderRow: ['Name', 'Description', 'Automatically fixable', 'Included in configurations'],\n  listSpacerRow: Array(4).fill('-'),\n  rulesListKey: [\n    '',\n    '',\n    [\n      `**Configurations**:`,\n      Object.entries(configBadges)\n        .map(([template]) => template)\n        .join(', '),\n    ].join(' '),\n  ].join('\\n'),\n};\n\nconst generateRulesListTable = (rulesList: TRuleListWithoutName[]) =>\n  [staticElements.listHeaderRow, staticElements.listSpacerRow, ...rulesList]\n    .map((column) => `|${column.join('|')}|`)\n    .join('\\n');\n\nconst generateRulesListMarkdown = (rulesList: TRuleListWithoutName[]) =>\n  ['', staticElements.rulesListKey, '', generateRulesListTable(rulesList), ''].join('\\n');\n\nconst listBeginMarker = '{/* RULES-LIST:START */}';\nconst listEndMarker = '{/* RULES-LIST:END */}';\n\nconst overWriteRulesList = (rulesList: TRuleListWithoutName[], readme: string) => {\n  const listStartIndex = readme.indexOf(listBeginMarker);\n  const listEndIndex = readme.indexOf(listEndMarker);\n\n  if ([listStartIndex, listEndIndex].includes(-1)) {\n    throw new Error(`cannot find start or end rules-list`);\n  }\n\n  return [\n    readme.substring(0, listStartIndex - 1),\n    listBeginMarker,\n    '',\n    generateRulesListMarkdown(rulesList),\n    readme.substring(listEndIndex),\n  ].join('\\n');\n};\n\nconst ruleCategoriesBeginMarker = '<!-- RULE-CATEGORIES:START -->';\nconst ruleCategoriesEndMarker = '<!-- RULE-CATEGORIES:END -->';\n\nconst overWriteRuleDocs = (rule: TRulesList, ruleDocFile: string) => {\n  const ruleCategoriesStartIndex = ruleDocFile.indexOf(ruleCategoriesBeginMarker);\n  const ruleCategoriesEndIndex = ruleDocFile.indexOf(ruleCategoriesEndMarker);\n\n  if ([ruleCategoriesStartIndex, ruleCategoriesEndIndex].includes(-1)) {\n    throw new Error(`cannot find start or end rules-categories`);\n  }\n\n  return [\n    ruleDocFile.substring(0, ruleCategoriesStartIndex - 1),\n    ruleCategoriesBeginMarker,\n    '',\n    `**Included in these configurations**: ${rule[4]}`,\n    ruleDocFile.substring(ruleCategoriesEndIndex),\n  ].join('\\n');\n};\n\nexport const writeRulesListInReadme = async (rulesList: TRulesList[]) => {\n  const readme = await readFile(readmePath, 'utf8');\n  const rulesListWithoutName = rulesList.map((rule) => rule.slice(1)) as TRuleListWithoutName[];\n  const newReadme = await format(overWriteRulesList(rulesListWithoutName, readme), {\n    parser: 'markdown',\n    ...(await prettierConfig),\n  });\n  // Workaround for prettier that keeps replacing {/* xyz */} with {_ xyz _} and that breaks the docs\n  const contentToWrite = newReadme.replaceAll('{/_', '{/*').replaceAll('_/}', '*/}');\n  await writeFile(readmePath, contentToWrite);\n};\n\nexport const updateRulesDocs = async (rulesList: TRulesList[]) => {\n  await Promise.all(\n    rulesList.map(async (rule) => {\n      const ruleName = rule[0];\n      const ruleDocFilePath = resolve(ruleDocsPath, `${ruleName}.md`);\n      const ruleDocFile = await readFile(ruleDocFilePath, 'utf8');\n\n      const updatedDocFile = await format(overWriteRuleDocs(rule, ruleDocFile), {\n        parser: 'markdown',\n        ...(await prettierConfig),\n      });\n\n      await writeFile(ruleDocFilePath, updatedDocFile);\n    })\n  );\n};\n"
  },
  {
    "path": "code/lib/eslint-plugin/scripts/utils/rules.ts",
    "content": "import fs from 'fs';\nimport path from 'path';\n\nimport type { StorybookRuleMeta } from '../../src/types/index.ts';\nimport type { createStorybookRule } from '../../src/utils/create-storybook-rule.ts';\n\nconst ROOT = path.resolve(__dirname, '../../src/rules');\n\nexport type TRule = ReturnType<typeof createStorybookRule> & {\n  meta: StorybookRuleMeta;\n};\n\nconst rules = fs\n  .readdirSync(ROOT)\n  .filter((file) => path.extname(file) === '.ts' && !file.endsWith('.test.ts'))\n  .map((file) => path.basename(file, '.ts'))\n  .map((name) => {\n    const rule = require(path.join(ROOT, name)) as TRule;\n    const meta: StorybookRuleMeta = { ...rule.meta };\n    if (meta.docs && !meta.docs.categories) {\n      meta.docs = { ...meta.docs };\n      meta.docs.categories = [];\n    }\n\n    return {\n      ruleId: `storybook/${name}`,\n      name,\n      meta,\n    };\n  });\n\nexport type TRules = typeof rules;\n\nexport default rules;\n"
  },
  {
    "path": "code/lib/eslint-plugin/scripts/utils/updates.ts",
    "content": "import type { CategoryId } from '../../src/utils/constants.ts';\nimport type { TCategory } from './categories.ts';\n\nexport const extendsCategories: Partial<Record<CategoryId, string | null>> = {\n  csf: null,\n  recommended: null,\n  'csf-strict': 'csf',\n};\n\nconst externalRuleOverrides: { [key: string]: string } = {\n  'react-hooks/rules-of-hooks': 'off',\n  'import-x/no-anonymous-default-export': 'off',\n};\n\nexport function formatRules(rules: TCategory['rules'], exclude?: string[]) {\n  const obj = rules.reduce(\n    (setting, rule) => {\n      if (!exclude?.includes(rule.ruleId)) {\n        setting[rule.ruleId] = rule.meta.severity || 'error';\n      }\n      return setting;\n    },\n    { ...externalRuleOverrides }\n  );\n\n  return JSON.stringify(obj, null, 2) + ' as const';\n}\n\nexport function formatSingleRule(rules: TCategory['rules'], ruleId: string) {\n  const ruleOpt = rules.find((rule) => rule.ruleId === ruleId)?.meta.severity || 'error';\n\n  return JSON.stringify({ [ruleId]: ruleOpt }, null, 2) + ' as const';\n}\n\nexport const SUPPORTED_EXTENSIONS = ['ts', 'tsx', 'js', 'jsx', 'mjs', 'cjs'];\nexport const STORIES_GLOBS = [\n  `'**/*.stories.@(${SUPPORTED_EXTENSIONS.join('|')})'`,\n  `'**/*.story.@(${SUPPORTED_EXTENSIONS.join('|')})'`,\n];\n\n// Other files that will be linted\nexport const MAIN_JS_FILE = [`'.storybook/main.@(js|cjs|mjs|ts)'`];\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/configs/addon-interactions.ts",
    "content": "/*\n * IMPORTANT!\n * This file has been automatically generated,\n * in order to update its content, execute \"yarn update-rules\" or rebuild this package.\n */\nexport default {\n  plugins: ['storybook'],\n  overrides: [\n    {\n      files: ['**/*.stories.@(ts|tsx|js|jsx|mjs|cjs)', '**/*.story.@(ts|tsx|js|jsx|mjs|cjs)'],\n      rules: {\n        'react-hooks/rules-of-hooks': 'off',\n        'import-x/no-anonymous-default-export': 'off',\n        'storybook/await-interactions': 'error',\n        'storybook/context-in-play-function': 'error',\n        'storybook/use-storybook-expect': 'error',\n        'storybook/use-storybook-testing-library': 'error',\n      } as const,\n    },\n    {\n      files: ['.storybook/main.@(js|cjs|mjs|ts)'],\n      rules: {\n        'storybook/no-uninstalled-addons': 'error',\n      } as const,\n    },\n  ],\n};\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/configs/csf-strict.ts",
    "content": "/*\n * IMPORTANT!\n * This file has been automatically generated,\n * in order to update its content, execute \"yarn update-rules\" or rebuild this package.\n */\nexport default {\n  // This file is bundled in an index.js file at the root\n  // so the reference is relative to the src directory\n  extends: './configs/csf',\n  overrides: [\n    {\n      files: ['**/*.stories.@(ts|tsx|js|jsx|mjs|cjs)', '**/*.story.@(ts|tsx|js|jsx|mjs|cjs)'],\n      rules: {\n        'react-hooks/rules-of-hooks': 'off',\n        'import-x/no-anonymous-default-export': 'off',\n        'storybook/no-stories-of': 'error',\n        'storybook/no-title-property-in-meta': 'error',\n      } as const,\n    },\n  ],\n};\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/configs/csf.ts",
    "content": "/*\n * IMPORTANT!\n * This file has been automatically generated,\n * in order to update its content, execute \"yarn update-rules\" or rebuild this package.\n */\nexport default {\n  plugins: ['storybook'],\n  overrides: [\n    {\n      files: ['**/*.stories.@(ts|tsx|js|jsx|mjs|cjs)', '**/*.story.@(ts|tsx|js|jsx|mjs|cjs)'],\n      rules: {\n        'react-hooks/rules-of-hooks': 'off',\n        'import-x/no-anonymous-default-export': 'off',\n        'storybook/csf-component': 'warn',\n        'storybook/default-exports': 'error',\n        'storybook/hierarchy-separator': 'warn',\n        'storybook/no-redundant-story-name': 'warn',\n        'storybook/story-exports': 'error',\n      } as const,\n    },\n    {\n      files: ['.storybook/main.@(js|cjs|mjs|ts)'],\n      rules: {\n        'storybook/no-uninstalled-addons': 'error',\n      } as const,\n    },\n  ],\n};\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/configs/flat/addon-interactions.ts",
    "content": "import storybookPlugin from '../../index.ts';\n\n/*\n * IMPORTANT!\n * This file has been automatically generated,\n * in order to update its content, execute \"yarn update-rules\" or rebuild this package.\n */\nexport default [\n  {\n    name: 'storybook:addon-interactions:setup',\n    plugins: {\n      get storybook() {\n        // this getter could just be a direct import, but we need to use a getter to avoid circular references in the types\n        return storybookPlugin;\n      },\n    },\n  },\n  {\n    name: 'storybook:addon-interactions:stories-rules',\n    files: ['**/*.stories.@(ts|tsx|js|jsx|mjs|cjs)', '**/*.story.@(ts|tsx|js|jsx|mjs|cjs)'],\n    rules: {\n      'react-hooks/rules-of-hooks': 'off',\n      'import-x/no-anonymous-default-export': 'off',\n      'storybook/await-interactions': 'error',\n      'storybook/context-in-play-function': 'error',\n      'storybook/use-storybook-expect': 'error',\n      'storybook/use-storybook-testing-library': 'error',\n    } as const,\n  },\n  {\n    name: 'storybook:addon-interactions:main-rules',\n    files: ['.storybook/main.@(js|cjs|mjs|ts)'],\n    rules: {\n      'storybook/no-uninstalled-addons': 'error',\n    } as const,\n  },\n];\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/configs/flat/csf-strict.ts",
    "content": "/*\n * IMPORTANT!\n * This file has been automatically generated,\n * in order to update its content, execute \"yarn update-rules\" or rebuild this package.\n */\nimport config from './csf.ts';\n\nexport default [\n  ...config,\n  {\n    name: 'storybook:csf-strict:rules',\n    files: ['**/*.stories.@(ts|tsx|js|jsx|mjs|cjs)', '**/*.story.@(ts|tsx|js|jsx|mjs|cjs)'],\n    rules: {\n      'react-hooks/rules-of-hooks': 'off',\n      'import-x/no-anonymous-default-export': 'off',\n      'storybook/no-stories-of': 'error',\n      'storybook/no-title-property-in-meta': 'error',\n    } as const,\n  },\n];\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/configs/flat/csf.ts",
    "content": "import storybookPlugin from '../../index.ts';\n\n/*\n * IMPORTANT!\n * This file has been automatically generated,\n * in order to update its content, execute \"yarn update-rules\" or rebuild this package.\n */\nexport default [\n  {\n    name: 'storybook:csf:setup',\n    plugins: {\n      get storybook() {\n        // this getter could just be a direct import, but we need to use a getter to avoid circular references in the types\n        return storybookPlugin;\n      },\n    },\n  },\n  {\n    name: 'storybook:csf:stories-rules',\n    files: ['**/*.stories.@(ts|tsx|js|jsx|mjs|cjs)', '**/*.story.@(ts|tsx|js|jsx|mjs|cjs)'],\n    rules: {\n      'react-hooks/rules-of-hooks': 'off',\n      'import-x/no-anonymous-default-export': 'off',\n      'storybook/csf-component': 'warn',\n      'storybook/default-exports': 'error',\n      'storybook/hierarchy-separator': 'warn',\n      'storybook/no-redundant-story-name': 'warn',\n      'storybook/story-exports': 'error',\n    } as const,\n  },\n  {\n    name: 'storybook:csf:main-rules',\n    files: ['.storybook/main.@(js|cjs|mjs|ts)'],\n    rules: {\n      'storybook/no-uninstalled-addons': 'error',\n    } as const,\n  },\n];\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/configs/flat/recommended.ts",
    "content": "import storybookPlugin from '../../index.ts';\n\n/*\n * IMPORTANT!\n * This file has been automatically generated,\n * in order to update its content, execute \"yarn update-rules\" or rebuild this package.\n */\nexport default [\n  {\n    name: 'storybook:recommended:setup',\n    plugins: {\n      get storybook() {\n        // this getter could just be a direct import, but we need to use a getter to avoid circular references in the types\n        return storybookPlugin;\n      },\n    },\n  },\n  {\n    name: 'storybook:recommended:stories-rules',\n    files: ['**/*.stories.@(ts|tsx|js|jsx|mjs|cjs)', '**/*.story.@(ts|tsx|js|jsx|mjs|cjs)'],\n    rules: {\n      'react-hooks/rules-of-hooks': 'off',\n      'import-x/no-anonymous-default-export': 'off',\n      'storybook/await-interactions': 'error',\n      'storybook/context-in-play-function': 'error',\n      'storybook/default-exports': 'error',\n      'storybook/hierarchy-separator': 'warn',\n      'storybook/no-redundant-story-name': 'warn',\n      'storybook/no-renderer-packages': 'error',\n      'storybook/prefer-pascal-case': 'warn',\n      'storybook/story-exports': 'error',\n      'storybook/use-storybook-expect': 'error',\n      'storybook/use-storybook-testing-library': 'error',\n    } as const,\n  },\n  {\n    name: 'storybook:recommended:main-rules',\n    files: ['.storybook/main.@(js|cjs|mjs|ts)'],\n    rules: {\n      'storybook/no-uninstalled-addons': 'error',\n    } as const,\n  },\n];\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/configs/recommended.ts",
    "content": "/*\n * IMPORTANT!\n * This file has been automatically generated,\n * in order to update its content, execute \"yarn update-rules\" or rebuild this package.\n */\nexport default {\n  plugins: ['storybook'],\n  overrides: [\n    {\n      files: ['**/*.stories.@(ts|tsx|js|jsx|mjs|cjs)', '**/*.story.@(ts|tsx|js|jsx|mjs|cjs)'],\n      rules: {\n        'react-hooks/rules-of-hooks': 'off',\n        'import-x/no-anonymous-default-export': 'off',\n        'storybook/await-interactions': 'error',\n        'storybook/context-in-play-function': 'error',\n        'storybook/default-exports': 'error',\n        'storybook/hierarchy-separator': 'warn',\n        'storybook/no-redundant-story-name': 'warn',\n        'storybook/no-renderer-packages': 'error',\n        'storybook/prefer-pascal-case': 'warn',\n        'storybook/story-exports': 'error',\n        'storybook/use-storybook-expect': 'error',\n        'storybook/use-storybook-testing-library': 'error',\n      } as const,\n    },\n    {\n      files: ['.storybook/main.@(js|cjs|mjs|ts)'],\n      rules: {\n        'storybook/no-uninstalled-addons': 'error',\n      } as const,\n    },\n  ],\n};\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/index.ts",
    "content": "/*\n * IMPORTANT!\n * This file has been automatically generated,\n * in order to update its content execute \"yarn update\"\n */\n// configs\nimport csf from './configs/csf.ts';\nimport csfStrict from './configs/csf-strict.ts';\nimport addonInteractions from './configs/addon-interactions.ts';\nimport recommended from './configs/recommended.ts';\nimport flatCsf from './configs/flat/csf.ts';\nimport flatCsfStrict from './configs/flat/csf-strict.ts';\nimport flatAddonInteractions from './configs/flat/addon-interactions.ts';\nimport flatRecommended from './configs/flat/recommended.ts';\n\n// rules\nimport awaitInteractions from './rules/await-interactions.ts';\nimport contextInPlayFunction from './rules/context-in-play-function.ts';\nimport csfComponent from './rules/csf-component.ts';\nimport defaultExports from './rules/default-exports.ts';\nimport hierarchySeparator from './rules/hierarchy-separator.ts';\nimport metaInlineProperties from './rules/meta-inline-properties.ts';\nimport metaSatisfiesType from './rules/meta-satisfies-type.ts';\nimport noRedundantStoryName from './rules/no-redundant-story-name.ts';\nimport noRendererPackages from './rules/no-renderer-packages.ts';\nimport noStoriesOf from './rules/no-stories-of.ts';\nimport noTitlePropertyInMeta from './rules/no-title-property-in-meta.ts';\nimport noUninstalledAddons from './rules/no-uninstalled-addons.ts';\nimport preferPascalCase from './rules/prefer-pascal-case.ts';\nimport storyExports from './rules/story-exports.ts';\nimport useStorybookExpect from './rules/use-storybook-expect.ts';\nimport useStorybookTestingLibrary from './rules/use-storybook-testing-library.ts';\n\nexport const configs = {\n  // eslintrc configs\n  csf: csf,\n  'csf-strict': csfStrict,\n  'addon-interactions': addonInteractions,\n  recommended: recommended,\n\n  // flat configs\n  'flat/csf': flatCsf,\n  'flat/csf-strict': flatCsfStrict,\n  'flat/addon-interactions': flatAddonInteractions,\n  'flat/recommended': flatRecommended,\n};\n\nexport const rules = {\n  'await-interactions': awaitInteractions,\n  'context-in-play-function': contextInPlayFunction,\n  'csf-component': csfComponent,\n  'default-exports': defaultExports,\n  'hierarchy-separator': hierarchySeparator,\n  'meta-inline-properties': metaInlineProperties,\n  'meta-satisfies-type': metaSatisfiesType,\n  'no-redundant-story-name': noRedundantStoryName,\n  'no-renderer-packages': noRendererPackages,\n  'no-stories-of': noStoriesOf,\n  'no-title-property-in-meta': noTitlePropertyInMeta,\n  'no-uninstalled-addons': noUninstalledAddons,\n  'prefer-pascal-case': preferPascalCase,\n  'story-exports': storyExports,\n  'use-storybook-expect': useStorybookExpect,\n  'use-storybook-testing-library': useStorybookTestingLibrary,\n};\n\nexport default {\n  configs,\n  rules,\n};\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/await-interactions.test.ts",
    "content": "/**\n * @file Interactions should be awaited\n * @author Yann Braga\n */\n//------------------------------------------------------------------------------\n// Requirements\n//------------------------------------------------------------------------------\nimport { dedent } from 'ts-dedent';\n\nimport rule from '../rules/await-interactions.ts';\nimport ruleTester from '../test-utils.ts';\n\n//------------------------------------------------------------------------------\n// Tests\n//------------------------------------------------------------------------------\nruleTester.run('await-interactions', rule, {\n  valid: [\n    dedent`\n      Basic.play = async () => {\n        await userEvent.click(button)\n      }\n    `,\n    dedent`\n      WithModalOpen.play = ({ canvasElement }) => {\n        const MyButton = canvas.getByRole('button')\n      }\n    `,\n    dedent`\n      WithModalOpen.play = async ({ canvasElement }) => {\n        const MyButton = await canvas.findByRole('button')\n      }\n    `,\n    dedent`\n      WithModalOpen.play = async ({ canvasElement }) => {\n        const element: HTMLButtonElement = await within(canvasElement).findByText(/Hello/i)\n        await userEvent.click(element, undefined, { clickCount: 2 })\n        await userEvent.click(await within(canvasElement).findByText(/Hello/i), undefined, {\n          clickCount: 2,\n        })\n      }\n    `,\n    dedent`\n      export const WithModalOpen = {\n        play: async ({ canvasElement }) => {\n          const element: HTMLButtonElement = await within(canvasElement).findByText(/Hello/i)\n          await userEvent.click(element, undefined, { clickCount: 2 })\n          await userEvent.click(await within(canvasElement).findByText(/Hello/i), undefined, {\n            clickCount: 2,\n          })\n        }\n      }\n    `,\n    'await expect(foo).toBe(bar)',\n    dedent`\n      Basic.play = async () => {\n        await waitForElementToBeRemoved(() => canvas.findByText('Loading...'))\n        await waitForElementToBeRemoved(() => userEvent.hover(canvas.getByTestId('password-error-info')))\n      }\n    `,\n    dedent`\n      import { userEvent } from '../utils'\n      import { within } from '@storybook/testing-library'\n\n      Basic.play = async (context) => {\n        const canvas = within(context)\n        userEvent.click(canvas.getByRole('button'))\n      }\n    `,\n    dedent`\n      Basic.play = async () => {\n        const userEvent = { test: () => {} }\n        // should not complain\n        userEvent.test()\n      }\n    `,\n    // // @TODO: https://github.com/storybookjs/eslint-plugin-storybook/issues/28\n    // dedent`\n    //   Block.parameters = {\n    //     async puppeteerTest(page) {\n    //       const element = await page.$('[data-test-block]');\n    //       await element.hover();\n    //       const textContent = await element.getProperty('textContent');\n    //       const text = await textContent.jsonValue();\n    //       expect(text).toBe('I am hovered');\n    //     },\n    //   };\n    // `,\n    'Basic.play = async () => userEvent.click(button)',\n    'Basic.play = async () => { return userEvent.click(button) }',\n    dedent`\n      export const SecondStory = {\n        play: async (context) => {\n          await FirstStory.play(context)\n        }\n      }\n    `,\n    dedent`\n      export const SecondStory = {\n        play: async (context) => {\n          await FirstStory.play?.(context)\n        }\n      }\n    `,\n    dedent`\n      export const SecondStory = {\n        play: async (context) => {\n          await FirstStory.play!(context)\n        }\n      }\n    `,\n  ],\n  invalid: [\n    {\n      code: dedent`\n        import { expect } from '@storybook/jest'\n        WithModalOpen.play = async ({ args }) => {\n          // should complain\n          expect(args.onClick).toHaveBeenCalled()\n        }\n      `,\n      output: dedent`\n        import { expect } from '@storybook/jest'\n        WithModalOpen.play = async ({ args }) => {\n          // should complain\n          await expect(args.onClick).toHaveBeenCalled()\n        }\n      `,\n      errors: [\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'toHaveBeenCalled' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n                import { expect } from '@storybook/jest'\n                WithModalOpen.play = async ({ args }) => {\n                  // should complain\n                  await expect(args.onClick).toHaveBeenCalled()\n                }\n              `,\n            },\n          ],\n        },\n      ],\n    },\n    {\n      code: dedent`\n        import { expect, findByText } from '@storybook/test'\n        WithModalOpen.play = async ({ args }) => {\n          // should complain\n          expect(args.onClick).toHaveBeenCalled()\n          const element = findByText(canvasElement, 'asdf')\n        }\n      `,\n      output: dedent`\n        import { expect, findByText } from '@storybook/test'\n        WithModalOpen.play = async ({ args }) => {\n          // should complain\n          await expect(args.onClick).toHaveBeenCalled()\n          const element = await findByText(canvasElement, 'asdf')\n        }\n      `,\n      errors: [\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'toHaveBeenCalled' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n                import { expect, findByText } from '@storybook/test'\n                WithModalOpen.play = async ({ args }) => {\n                  // should complain\n                  await expect(args.onClick).toHaveBeenCalled()\n                  const element = findByText(canvasElement, 'asdf')\n                }\n              `,\n            },\n          ],\n        },\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'findByText' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n                import { expect, findByText } from '@storybook/test'\n                WithModalOpen.play = async ({ args }) => {\n                  // should complain\n                  expect(args.onClick).toHaveBeenCalled()\n                  const element = await findByText(canvasElement, 'asdf')\n                }\n              `,\n            },\n          ],\n        },\n      ],\n    },\n    {\n      code: dedent`\n        WithModalOpen.play = ({ canvasElement }) => {\n          const canvas = within(canvasElement)\n\n          const foodItem = canvas.findByText(/Cheeseburger/i)\n        }\n      `,\n      output: dedent`\n        WithModalOpen.play = async ({ canvasElement }) => {\n          const canvas = within(canvasElement)\n\n          const foodItem = await canvas.findByText(/Cheeseburger/i)\n        }\n      `,\n      errors: [\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'findByText' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n                WithModalOpen.play = async ({ canvasElement }) => {\n                  const canvas = within(canvasElement)\n\n                  const foodItem = await canvas.findByText(/Cheeseburger/i)\n                }\n              `,\n            },\n          ],\n        },\n      ],\n    },\n    {\n      code: dedent`\n        WithModalOpen.play = async ({ canvasElement }) => {\n          const canvas = within(canvasElement)\n          const foodItem = canvas.findByText(/Cheeseburger/i)\n          userEvent.click(foodItem)\n          const modalButton = canvas.findByLabelText('increase quantity by one')\n          userEvent.click(modalButton)\n        }\n      `,\n      output: dedent`\n        WithModalOpen.play = async ({ canvasElement }) => {\n          const canvas = within(canvasElement)\n          const foodItem = await canvas.findByText(/Cheeseburger/i)\n          await userEvent.click(foodItem)\n          const modalButton = await canvas.findByLabelText('increase quantity by one')\n          await userEvent.click(modalButton)\n        }\n      `,\n      errors: [\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'findByText' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n                WithModalOpen.play = async ({ canvasElement }) => {\n                  const canvas = within(canvasElement)\n                  const foodItem = await canvas.findByText(/Cheeseburger/i)\n                  userEvent.click(foodItem)\n                  const modalButton = canvas.findByLabelText('increase quantity by one')\n                  userEvent.click(modalButton)\n                }\n            `,\n            },\n          ],\n        },\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'userEvent' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n                WithModalOpen.play = async ({ canvasElement }) => {\n                  const canvas = within(canvasElement)\n                  const foodItem = canvas.findByText(/Cheeseburger/i)\n                  await userEvent.click(foodItem)\n                  const modalButton = canvas.findByLabelText('increase quantity by one')\n                  userEvent.click(modalButton)\n                }\n               `,\n            },\n          ],\n        },\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'findByLabelText' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n                WithModalOpen.play = async ({ canvasElement }) => {\n                  const canvas = within(canvasElement)\n                  const foodItem = canvas.findByText(/Cheeseburger/i)\n                  userEvent.click(foodItem)\n                  const modalButton = await canvas.findByLabelText('increase quantity by one')\n                  userEvent.click(modalButton)\n                }\n               `,\n            },\n          ],\n        },\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'userEvent' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n                WithModalOpen.play = async ({ canvasElement }) => {\n                  const canvas = within(canvasElement)\n                  const foodItem = canvas.findByText(/Cheeseburger/i)\n                  userEvent.click(foodItem)\n                  const modalButton = canvas.findByLabelText('increase quantity by one')\n                  await userEvent.click(modalButton)\n                }\n               `,\n            },\n          ],\n        },\n      ],\n    },\n    {\n      code: dedent`\n          WithModalOpen.play = async ({ canvasElement }) => {\n            const element: HTMLButtonElement = within(canvasElement).findByText(/Hello/i)\n            userEvent.click(element, undefined, { clickCount: 2 })\n            userEvent.click(within(canvasElement).findByText(/Hello/i), undefined, {\n              clickCount: 2,\n            })\n          }\n        `,\n      output: dedent`\n        WithModalOpen.play = async ({ canvasElement }) => {\n          const element: HTMLButtonElement = await within(canvasElement).findByText(/Hello/i)\n          await userEvent.click(element, undefined, { clickCount: 2 })\n          await userEvent.click(await within(canvasElement).findByText(/Hello/i), undefined, {\n            clickCount: 2,\n          })\n        }\n      `,\n      errors: [\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'findByText' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n                WithModalOpen.play = async ({ canvasElement }) => {\n                  const element: HTMLButtonElement = await within(canvasElement).findByText(/Hello/i)\n                  userEvent.click(element, undefined, { clickCount: 2 })\n                  userEvent.click(within(canvasElement).findByText(/Hello/i), undefined, {\n                    clickCount: 2,\n                  })\n                }\n              `,\n            },\n          ],\n        },\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'userEvent' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n                WithModalOpen.play = async ({ canvasElement }) => {\n                  const element: HTMLButtonElement = within(canvasElement).findByText(/Hello/i)\n                  await userEvent.click(element, undefined, { clickCount: 2 })\n                  userEvent.click(within(canvasElement).findByText(/Hello/i), undefined, {\n                    clickCount: 2,\n                  })\n                }\n              `,\n            },\n          ],\n        },\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'userEvent' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n                WithModalOpen.play = async ({ canvasElement }) => {\n                  const element: HTMLButtonElement = within(canvasElement).findByText(/Hello/i)\n                  userEvent.click(element, undefined, { clickCount: 2 })\n                  await userEvent.click(within(canvasElement).findByText(/Hello/i), undefined, {\n                    clickCount: 2,\n                  })\n                }\n              `,\n            },\n          ],\n        },\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'findByText' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n                WithModalOpen.play = async ({ canvasElement }) => {\n                  const element: HTMLButtonElement = within(canvasElement).findByText(/Hello/i)\n                  userEvent.click(element, undefined, { clickCount: 2 })\n                  userEvent.click(await within(canvasElement).findByText(/Hello/i), undefined, {\n                    clickCount: 2,\n                  })\n                }\n              `,\n            },\n          ],\n        },\n      ],\n    },\n    {\n      code: dedent`\n        export const WithModalOpen = {\n          play: async ({ canvasElement, args }) => {\n            const element: HTMLButtonElement = within(canvasElement).findByText(/Hello/i)\n            userEvent.click(element, undefined, { clickCount: 2 })\n            userEvent.click(within(canvasElement).findByText(/Hello/i), undefined, {\n              clickCount: 2,\n            })\n            expect(args.onSubmit).toHaveBeenCalled()\n          }\n        }\n      `,\n      output: dedent`\n        export const WithModalOpen = {\n          play: async ({ canvasElement, args }) => {\n            const element: HTMLButtonElement = await within(canvasElement).findByText(/Hello/i)\n            await userEvent.click(element, undefined, { clickCount: 2 })\n            await userEvent.click(await within(canvasElement).findByText(/Hello/i), undefined, {\n              clickCount: 2,\n            })\n            await expect(args.onSubmit).toHaveBeenCalled()\n          }\n        }\n      `,\n      errors: [\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'findByText' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n              export const WithModalOpen = {\n                play: async ({ canvasElement, args }) => {\n                  const element: HTMLButtonElement = await within(canvasElement).findByText(/Hello/i)\n                  userEvent.click(element, undefined, { clickCount: 2 })\n                  userEvent.click(within(canvasElement).findByText(/Hello/i), undefined, {\n                    clickCount: 2,\n                  })\n                  expect(args.onSubmit).toHaveBeenCalled()\n                }\n              }\n            `,\n            },\n          ],\n        },\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'userEvent' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n              export const WithModalOpen = {\n                play: async ({ canvasElement, args }) => {\n                  const element: HTMLButtonElement = within(canvasElement).findByText(/Hello/i)\n                  await userEvent.click(element, undefined, { clickCount: 2 })\n                  userEvent.click(within(canvasElement).findByText(/Hello/i), undefined, {\n                    clickCount: 2,\n                  })\n                  expect(args.onSubmit).toHaveBeenCalled()\n                }\n              }\n            `,\n            },\n          ],\n        },\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'userEvent' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n              export const WithModalOpen = {\n                play: async ({ canvasElement, args }) => {\n                  const element: HTMLButtonElement = within(canvasElement).findByText(/Hello/i)\n                  userEvent.click(element, undefined, { clickCount: 2 })\n                  await userEvent.click(within(canvasElement).findByText(/Hello/i), undefined, {\n                    clickCount: 2,\n                  })\n                  expect(args.onSubmit).toHaveBeenCalled()\n                }\n              }\n            `,\n            },\n          ],\n        },\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'findByText' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n              export const WithModalOpen = {\n                play: async ({ canvasElement, args }) => {\n                  const element: HTMLButtonElement = within(canvasElement).findByText(/Hello/i)\n                  userEvent.click(element, undefined, { clickCount: 2 })\n                  userEvent.click(await within(canvasElement).findByText(/Hello/i), undefined, {\n                    clickCount: 2,\n                  })\n                  expect(args.onSubmit).toHaveBeenCalled()\n                }\n              }\n            `,\n            },\n          ],\n        },\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'toHaveBeenCalled' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n              export const WithModalOpen = {\n                play: async ({ canvasElement, args }) => {\n                  const element: HTMLButtonElement = within(canvasElement).findByText(/Hello/i)\n                  userEvent.click(element, undefined, { clickCount: 2 })\n                  userEvent.click(within(canvasElement).findByText(/Hello/i), undefined, {\n                    clickCount: 2,\n                  })\n                  await expect(args.onSubmit).toHaveBeenCalled()\n                }\n              }\n            `,\n            },\n          ],\n        },\n      ],\n    },\n    {\n      code: dedent`\n        export const AfterLoadingState = {\n          play: async ({ canvasElement, args }) => {\n            const canvas = within(canvasElement)\n            waitForElementToBeRemoved(async () => {\n              canvas.findByText('Loading...')\n            }, { timeout: 2000 })\n            const button = canvas.findByText('Loaded!')\n            userEvent.click(button)\n            waitFor(async () => {\n              expect(args.onSubmit).toHaveBeenCalled()\n            })\n          }\n        }\n      `,\n      output: dedent`\n        export const AfterLoadingState = {\n          play: async ({ canvasElement, args }) => {\n            const canvas = within(canvasElement)\n            await waitForElementToBeRemoved(async () => {\n              await canvas.findByText('Loading...')\n            }, { timeout: 2000 })\n            const button = await canvas.findByText('Loaded!')\n            await userEvent.click(button)\n            await waitFor(async () => {\n              await expect(args.onSubmit).toHaveBeenCalled()\n            })\n          }\n        }\n      `,\n      errors: [\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'waitForElementToBeRemoved' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n              export const AfterLoadingState = {\n                play: async ({ canvasElement, args }) => {\n                  const canvas = within(canvasElement)\n                  await waitForElementToBeRemoved(async () => {\n                    canvas.findByText('Loading...')\n                  }, { timeout: 2000 })\n                  const button = canvas.findByText('Loaded!')\n                  userEvent.click(button)\n                  waitFor(async () => {\n                    expect(args.onSubmit).toHaveBeenCalled()\n                  })\n                }\n              }\n            `,\n            },\n          ],\n        },\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'findByText' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n              export const AfterLoadingState = {\n                play: async ({ canvasElement, args }) => {\n                  const canvas = within(canvasElement)\n                  waitForElementToBeRemoved(async () => {\n                    await canvas.findByText('Loading...')\n                  }, { timeout: 2000 })\n                  const button = canvas.findByText('Loaded!')\n                  userEvent.click(button)\n                  waitFor(async () => {\n                    expect(args.onSubmit).toHaveBeenCalled()\n                  })\n                }\n              }\n            `,\n            },\n          ],\n        },\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'findByText' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n              export const AfterLoadingState = {\n                play: async ({ canvasElement, args }) => {\n                  const canvas = within(canvasElement)\n                  waitForElementToBeRemoved(async () => {\n                    canvas.findByText('Loading...')\n                  }, { timeout: 2000 })\n                  const button = await canvas.findByText('Loaded!')\n                  userEvent.click(button)\n                  waitFor(async () => {\n                    expect(args.onSubmit).toHaveBeenCalled()\n                  })\n                }\n              }\n            `,\n            },\n          ],\n        },\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'userEvent' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n              export const AfterLoadingState = {\n                play: async ({ canvasElement, args }) => {\n                  const canvas = within(canvasElement)\n                  waitForElementToBeRemoved(async () => {\n                    canvas.findByText('Loading...')\n                  }, { timeout: 2000 })\n                  const button = canvas.findByText('Loaded!')\n                  await userEvent.click(button)\n                  waitFor(async () => {\n                    expect(args.onSubmit).toHaveBeenCalled()\n                  })\n                }\n              }\n            `,\n            },\n          ],\n        },\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'waitFor' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n              export const AfterLoadingState = {\n                play: async ({ canvasElement, args }) => {\n                  const canvas = within(canvasElement)\n                  waitForElementToBeRemoved(async () => {\n                    canvas.findByText('Loading...')\n                  }, { timeout: 2000 })\n                  const button = canvas.findByText('Loaded!')\n                  userEvent.click(button)\n                  await waitFor(async () => {\n                    expect(args.onSubmit).toHaveBeenCalled()\n                  })\n                }\n              }\n            `,\n            },\n          ],\n        },\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'toHaveBeenCalled' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n              export const AfterLoadingState = {\n                play: async ({ canvasElement, args }) => {\n                  const canvas = within(canvasElement)\n                  waitForElementToBeRemoved(async () => {\n                    canvas.findByText('Loading...')\n                  }, { timeout: 2000 })\n                  const button = canvas.findByText('Loaded!')\n                  userEvent.click(button)\n                  waitFor(async () => {\n                    await expect(args.onSubmit).toHaveBeenCalled()\n                  })\n                }\n              }\n            `,\n            },\n          ],\n        },\n      ],\n    },\n    {\n      code: dedent`\n        export const FourthStory = {\n          play: async (context) => {\n            FirstStory.play(context)\n            SecondStory.play!(context)\n            ThirdStory.play?.(context)\n          }\n        }\n      `,\n      output: dedent`\n        export const FourthStory = {\n          play: async (context) => {\n            await FirstStory.play(context)\n            await SecondStory.play!(context)\n            await ThirdStory.play?.(context)\n          }\n        }\n      `,\n      errors: [\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'play' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n                export const FourthStory = {\n                  play: async (context) => {\n                    await FirstStory.play(context)\n                    SecondStory.play!(context)\n                    ThirdStory.play?.(context)\n                  }\n                }\n              `,\n            },\n          ],\n        },\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'play' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n                export const FourthStory = {\n                  play: async (context) => {\n                    FirstStory.play(context)\n                    await SecondStory.play!(context)\n                    ThirdStory.play?.(context)\n                  }\n                }\n              `,\n            },\n          ],\n        },\n        {\n          messageId: 'interactionShouldBeAwaited',\n          data: { method: 'play' },\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: dedent`\n                export const FourthStory = {\n                  play: async (context) => {\n                    FirstStory.play(context)\n                    SecondStory.play!(context)\n                    await ThirdStory.play?.(context)\n                  }\n                }\n              `,\n            },\n          ],\n        },\n      ],\n    },\n  ],\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/await-interactions.ts",
    "content": "/**\n * @file Interactions should be awaited\n * @author Yann Braga\n */\nimport type { TSESLint, TSESTree } from '@typescript-eslint/utils';\n\nimport {\n  isArrowFunctionExpression,\n  isAwaitExpression,\n  isCallExpression,\n  isFunctionDeclaration,\n  isFunctionExpression,\n  isIdentifier,\n  isImportSpecifier,\n  isMemberExpression,\n  isProgram,\n  isReturnStatement,\n  isTSNonNullExpression,\n} from '../utils/ast.ts';\nimport { CategoryId } from '../utils/constants.ts';\nimport { createStorybookRule } from '../utils/create-storybook-rule.ts';\n\n//------------------------------------------------------------------------------\n// Rule Definition\n//------------------------------------------------------------------------------\n\nexport default createStorybookRule({\n  name: 'await-interactions',\n  defaultOptions: [],\n  meta: {\n    severity: 'error',\n    docs: {\n      description: 'Interactions should be awaited',\n      categories: [CategoryId.ADDON_INTERACTIONS, CategoryId.RECOMMENDED],\n    },\n    messages: {\n      interactionShouldBeAwaited: 'Interaction should be awaited: {{method}}',\n      fixSuggestion: 'Add `await` to method',\n    },\n    type: 'problem',\n    fixable: 'code',\n    hasSuggestions: true,\n    schema: [],\n  },\n\n  create(context) {\n    // variables should be defined here\n\n    //----------------------------------------------------------------------\n    // Helpers\n    //----------------------------------------------------------------------\n\n    // any helper functions should go here or else delete this section\n\n    const FUNCTIONS_TO_BE_AWAITED = [\n      'waitFor',\n      'waitForElementToBeRemoved',\n      'wait',\n      'waitForElement',\n      'waitForDomChange',\n      'userEvent',\n      'play',\n    ];\n\n    const getMethodThatShouldBeAwaited = (expr: TSESTree.CallExpression) => {\n      const shouldAwait = (name: string) => {\n        return FUNCTIONS_TO_BE_AWAITED.includes(name) || name.startsWith('findBy');\n      };\n\n      // When an expression is a return value it doesn't need to be awaited\n      if (isArrowFunctionExpression(expr.parent) || isReturnStatement(expr.parent)) {\n        return null;\n      }\n\n      if (\n        isMemberExpression(expr.callee) &&\n        isIdentifier(expr.callee.object) &&\n        shouldAwait(expr.callee.object.name)\n      ) {\n        return expr.callee.object;\n      }\n\n      if (\n        isTSNonNullExpression(expr.callee) &&\n        isMemberExpression(expr.callee.expression) &&\n        isIdentifier(expr.callee.expression.property) &&\n        shouldAwait(expr.callee.expression.property.name)\n      ) {\n        return expr.callee.expression.property;\n      }\n\n      if (\n        isMemberExpression(expr.callee) &&\n        isIdentifier(expr.callee.property) &&\n        shouldAwait(expr.callee.property.name)\n      ) {\n        return expr.callee.property;\n      }\n\n      if (\n        isMemberExpression(expr.callee) &&\n        isCallExpression(expr.callee.object) &&\n        isIdentifier(expr.callee.object.callee) &&\n        isIdentifier(expr.callee.property) &&\n        expr.callee.object.callee.name === 'expect'\n      ) {\n        return expr.callee.property;\n      }\n\n      if (isIdentifier(expr.callee) && shouldAwait(expr.callee.name)) {\n        return expr.callee;\n      }\n\n      return null;\n    };\n\n    const getClosestFunctionAncestor = (node: TSESTree.Node): TSESTree.Node | undefined => {\n      const parent = node.parent;\n\n      if (!parent || isProgram(parent)) {\n        return undefined;\n      }\n      if (\n        isArrowFunctionExpression(parent) ||\n        isFunctionExpression(parent) ||\n        isFunctionDeclaration(parent)\n      ) {\n        return node.parent;\n      }\n\n      return getClosestFunctionAncestor(parent);\n    };\n\n    const isUserEventFromStorybookImported = (node: TSESTree.ImportDeclaration) => {\n      return (\n        (node.source.value === '@storybook/testing-library' ||\n          node.source.value === '@storybook/test') &&\n        node.specifiers.find(\n          (spec) =>\n            isImportSpecifier(spec) &&\n            'name' in spec.imported &&\n            spec.imported.name === 'userEvent' &&\n            spec.local.name === 'userEvent'\n        ) !== undefined\n      );\n    };\n\n    const isExpectFromStorybookImported = (node: TSESTree.ImportDeclaration) => {\n      return (\n        (node.source.value === '@storybook/jest' || node.source.value === '@storybook/test') &&\n        node.specifiers.find(\n          (spec) =>\n            isImportSpecifier(spec) && 'name' in spec.imported && spec.imported.name === 'expect'\n        ) !== undefined\n      );\n    };\n\n    //----------------------------------------------------------------------\n    // Public\n    //----------------------------------------------------------------------\n    /** @param {import('eslint').Rule.Node} node */\n\n    let isImportedFromStorybook = true;\n    const invocationsThatShouldBeAwaited = [] as Array<{\n      node: TSESTree.Node;\n      method: TSESTree.Identifier;\n    }>;\n\n    return {\n      ImportDeclaration(node: TSESTree.ImportDeclaration) {\n        isImportedFromStorybook =\n          isUserEventFromStorybookImported(node) || isExpectFromStorybookImported(node);\n      },\n      VariableDeclarator(node: TSESTree.VariableDeclarator) {\n        isImportedFromStorybook =\n          isImportedFromStorybook && isIdentifier(node.id) && node.id.name !== 'userEvent';\n      },\n      CallExpression(node: TSESTree.CallExpression) {\n        const method = getMethodThatShouldBeAwaited(node);\n        if (method && !isAwaitExpression(node.parent) && !isAwaitExpression(node.parent?.parent)) {\n          invocationsThatShouldBeAwaited.push({ node, method });\n        }\n      },\n      'Program:exit': function () {\n        if (isImportedFromStorybook && invocationsThatShouldBeAwaited.length) {\n          invocationsThatShouldBeAwaited.forEach(({ node, method }) => {\n            const parentFnNode = getClosestFunctionAncestor(node);\n            const parentFnNeedsAsync =\n              parentFnNode && !('async' in parentFnNode && parentFnNode.async);\n\n            const fixFn: TSESLint.ReportFixFunction = (fixer) => {\n              const fixerResult = [fixer.insertTextBefore(node, 'await ')];\n\n              if (parentFnNeedsAsync) {\n                fixerResult.push(fixer.insertTextBefore(parentFnNode, 'async '));\n              }\n              return fixerResult;\n            };\n\n            context.report({\n              node,\n              messageId: 'interactionShouldBeAwaited',\n              data: {\n                method: method.name,\n              },\n              fix: fixFn,\n              suggest: [\n                {\n                  messageId: 'fixSuggestion',\n                  fix: fixFn,\n                },\n              ],\n            });\n          });\n        }\n      },\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/context-in-play-function.test.ts",
    "content": "/**\n * @file Pass a context object when invoking a play function\n * @author Yann Braga\n */\n//------------------------------------------------------------------------------\n// Requirements\n//------------------------------------------------------------------------------\nimport { dedent } from 'ts-dedent';\n\nimport ruleTester from '../test-utils.ts';\nimport rule from './context-in-play-function.ts';\n\n//------------------------------------------------------------------------------\n// Tests\n//------------------------------------------------------------------------------\n\nruleTester.run('context-in-play-function', rule, {\n  valid: [\n    dedent`\n      export const SecondStory = {\n        play: async (context) => {\n          await FirstStory.play(context)\n        }\n      }\n    `,\n    dedent`\n      export const SecondStory = {\n        play: async ({ ...context }) => {\n          await FirstStory.play({ ...context })\n        }\n      }\n    `,\n    dedent`\n      export const SecondStory = {\n        play: async ({ canvasElement, ...context }) => {\n          await FirstStory.play({ canvasElement, ...context })\n        }\n      }\n    `,\n    dedent`\n      export const SecondStory = Template.bind({})\n      SecondStory.play = async (ctx) => {\n        await FirstStory.play(ctx)\n      }\n    `,\n    dedent`\n      export const SecondStory = Template.bind({})\n      SecondStory.play = async ({ canvasElement, ...ctx }) => {\n        await FirstStory.play({ canvasElement, ...ctx })\n      }\n    `,\n    dedent`\n      export const SecondStory = {\n        play: async (ctx) => {\n          await FirstStory.play(ctx)\n        }\n      }\n    `,\n    dedent`\n      export const SecondStory = {\n        play: async ({ ...ctx }) => {\n          await FirstStory.play({ ...ctx })\n        }\n      }\n    `,\n    dedent`\n      export const SecondStory = {\n        play: async ({ canvasElement, ...ctx }) => {\n          await FirstStory.play({ canvasElement, ...ctx })\n        }\n      }\n    `,\n    dedent`\n      export const SecondStory = {\n        play: async ({ context, canvasElement }) => {\n          await FirstStory.play(context)\n        }\n      }\n    `,\n  ],\n  invalid: [\n    {\n      code: dedent`\n        export const SecondStory = {\n          play: async ({ canvasElement }) => {\n            await FirstStory.play({ canvasElement })\n          }\n        }\n      `,\n      errors: [\n        {\n          messageId: 'passContextToPlayFunction',\n        },\n      ],\n    },\n    {\n      code: dedent`\n        export const SecondStory = {\n          play: async () => {\n            await FirstStory.play()\n          }\n        }\n      `,\n      errors: [\n        {\n          messageId: 'passContextToPlayFunction',\n        },\n      ],\n    },\n    {\n      code: dedent`\n        export const SecondStory = Template.bind({})\n        SecondStory.play = async ({ canvasElement }) => {\n          await FirstStory.play({ canvasElement })\n        }\n      `,\n      errors: [\n        {\n          messageId: 'passContextToPlayFunction',\n        },\n      ],\n    },\n    {\n      code: dedent`\n        export const SecondStory = Template.bind({})\n        SecondStory.play = async () => {\n          await FirstStory.play()\n        }\n      `,\n      errors: [\n        {\n          messageId: 'passContextToPlayFunction',\n        },\n      ],\n    },\n  ],\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/context-in-play-function.ts",
    "content": "/**\n * @file Pass a context object when invoking a play function\n * @author Yann Braga\n */\nimport type { TSESTree } from '@typescript-eslint/utils';\n\nimport {\n  isArrowFunctionExpression,\n  isIdentifier,\n  isMemberExpression,\n  isObjectExpression,\n  isObjectPattern,\n  isRestElement,\n  isSpreadElement,\n  isTSNonNullExpression,\n} from '../utils/ast.ts';\nimport { CategoryId } from '../utils/constants.ts';\nimport { createStorybookRule } from '../utils/create-storybook-rule.ts';\n\n//------------------------------------------------------------------------------\n// Rule Definition\n//------------------------------------------------------------------------------\n\nexport default createStorybookRule({\n  name: 'context-in-play-function',\n  defaultOptions: [],\n  meta: {\n    type: 'problem',\n    severity: 'error',\n    docs: {\n      description: 'Pass a context when invoking play function of another story',\n      categories: [CategoryId.RECOMMENDED, CategoryId.ADDON_INTERACTIONS],\n    },\n    messages: {\n      passContextToPlayFunction: 'Pass a context when invoking play function of another story',\n    },\n    fixable: undefined,\n    schema: [],\n  },\n\n  create(context) {\n    // variables should be defined here\n\n    //----------------------------------------------------------------------\n    // Helpers\n    //----------------------------------------------------------------------\n\n    // any helper functions should go here or else delete this section\n\n    const isPlayFunctionFromAnotherStory = (expr: TSESTree.CallExpression) => {\n      if (\n        isTSNonNullExpression(expr.callee) &&\n        isMemberExpression(expr.callee.expression) &&\n        isIdentifier(expr.callee.expression.property) &&\n        expr.callee.expression.property.name === 'play'\n      ) {\n        return true;\n      }\n\n      if (\n        isMemberExpression(expr.callee) &&\n        isIdentifier(expr.callee.property) &&\n        expr.callee.property.name === 'play'\n      ) {\n        return true;\n      }\n\n      return false;\n    };\n\n    const getParentParameterName = (node: TSESTree.Node): string | undefined => {\n      if (!isArrowFunctionExpression(node)) {\n        if (!node.parent) {\n          return undefined;\n        }\n        return getParentParameterName(node.parent);\n      }\n      // No parameter found\n      if (node.params.length === 0) {\n        return undefined;\n      }\n\n      if (node.params.length >= 1) {\n        const param = node.params[0];\n        if (isIdentifier(param)) {\n          return param.name;\n        }\n        if (isObjectPattern(param)) {\n          if (\n            param.properties.find((prop) => {\n              return (\n                prop.type === 'Property' &&\n                prop.key.type === 'Identifier' &&\n                prop.key.name === 'context'\n              );\n            })\n          ) {\n            return 'context';\n          }\n\n          const restElement = param.properties.find(isRestElement);\n          if (!restElement || !isIdentifier(restElement.argument)) {\n            // No rest element found\n            return undefined;\n          }\n          return restElement.argument.name;\n        }\n      }\n      return undefined;\n    };\n\n    // Expression passing an argument called context OR spreading a variable called context\n    const isNotPassingContextCorrectly = (expr: TSESTree.CallExpression) => {\n      const firstExpressionArgument = expr.arguments[0];\n\n      if (!firstExpressionArgument) {\n        return true;\n      }\n\n      const contextVariableName = getParentParameterName(expr);\n\n      if (!contextVariableName) {\n        return true;\n      }\n\n      if (\n        expr.arguments.length === 1 &&\n        isIdentifier(firstExpressionArgument) &&\n        firstExpressionArgument.name === contextVariableName\n      ) {\n        return false;\n      }\n\n      if (\n        isObjectExpression(firstExpressionArgument) &&\n        firstExpressionArgument.properties.some((prop) => {\n          return (\n            isSpreadElement(prop) &&\n            isIdentifier(prop.argument) &&\n            prop.argument.name === contextVariableName\n          );\n        })\n      ) {\n        return false;\n      }\n\n      return true;\n    };\n\n    //----------------------------------------------------------------------\n    // Public\n    //----------------------------------------------------------------------\n\n    const invocationsWithoutProperContext: TSESTree.Node[] = [];\n\n    return {\n      CallExpression(node: TSESTree.CallExpression) {\n        if (isPlayFunctionFromAnotherStory(node) && isNotPassingContextCorrectly(node)) {\n          invocationsWithoutProperContext.push(node);\n        }\n      },\n      'Program:exit': function () {\n        invocationsWithoutProperContext.forEach((node) => {\n          context.report({\n            node,\n            messageId: 'passContextToPlayFunction',\n          });\n        });\n      },\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/csf-component.test.ts",
    "content": "/**\n * @file Component property should be set\n * @author Yann Braga\n */\n//------------------------------------------------------------------------------\n// Requirements\n//------------------------------------------------------------------------------\nimport { AST_NODE_TYPES } from '@typescript-eslint/utils';\n\nimport ruleTester from '../test-utils.ts';\nimport rule from './csf-component.ts';\n\n//------------------------------------------------------------------------------\n// Tests\n//------------------------------------------------------------------------------\n\nruleTester.run('csf-component', rule, {\n  valid: [\n    \"export default { title: 'Button', component: Button }\",\n    \"export default { title: 'Button', component: Button } as ComponentMeta<typeof Button>\",\n  ],\n\n  invalid: [\n    {\n      code: \"export default { title: 'Button' }\",\n      errors: [\n        {\n          messageId: 'missingComponentProperty',\n          type: AST_NODE_TYPES.ExportDefaultDeclaration,\n        },\n      ],\n    },\n    {\n      code: \"export default { title: 'Button' } as ComponentMeta<typeof Button>\",\n      errors: [\n        {\n          messageId: 'missingComponentProperty',\n          type: AST_NODE_TYPES.ExportDefaultDeclaration,\n        },\n      ],\n    },\n    {\n      code: `\n        const meta = { title: 'Button' } as Meta<typeof Button>\n        export default meta\n      `,\n      errors: [\n        {\n          messageId: 'missingComponentProperty',\n          type: AST_NODE_TYPES.ExportDefaultDeclaration,\n        },\n      ],\n    },\n  ],\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/csf-component.ts",
    "content": "/**\n * @file Component property should be set\n * @author Yann Braga\n */\nimport type { TSESTree } from '@typescript-eslint/utils';\n\nimport { getMetaObjectExpression } from '../utils/index.ts';\nimport { isSpreadElement } from '../utils/ast.ts';\nimport { CategoryId } from '../utils/constants.ts';\nimport { createStorybookRule } from '../utils/create-storybook-rule.ts';\n\n//------------------------------------------------------------------------------\n// Rule Definition\n//------------------------------------------------------------------------------\n\nexport default createStorybookRule({\n  name: 'csf-component',\n  defaultOptions: [],\n  meta: {\n    type: 'suggestion',\n    severity: 'warn',\n    docs: {\n      description: 'The component property should be set',\n      categories: [CategoryId.CSF],\n    },\n    messages: {\n      missingComponentProperty: 'Missing component property.',\n    },\n    schema: [],\n  },\n\n  create(context) {\n    // variables should be defined here\n\n    //----------------------------------------------------------------------\n    // Helpers\n    //----------------------------------------------------------------------\n\n    // any helper functions should go here or else delete this section\n\n    //----------------------------------------------------------------------\n    // Public\n    //----------------------------------------------------------------------\n\n    return {\n      ExportDefaultDeclaration(node: TSESTree.ExportDefaultDeclaration) {\n        const meta = getMetaObjectExpression(node, context);\n\n        if (!meta) {\n          return null;\n        }\n\n        const componentProperty = meta.properties.find(\n          (property) =>\n            !isSpreadElement(property) &&\n            'name' in property.key &&\n            property.key.name === 'component'\n        );\n\n        if (!componentProperty) {\n          context.report({\n            node,\n            messageId: 'missingComponentProperty',\n          });\n        }\n      },\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/default-exports.test.ts",
    "content": "/**\n * @file Story files should have a default export\n * @author Yann Braga\n */\n//------------------------------------------------------------------------------\n// Requirements\n//------------------------------------------------------------------------------\nimport { dedent } from 'ts-dedent';\n\nimport ruleTester from '../test-utils.ts';\nimport rule from './default-exports.ts';\n\n//------------------------------------------------------------------------------\n// Tests\n//------------------------------------------------------------------------------\n\nruleTester.run('default-exports', rule, {\n  valid: [\n    'export default { }',\n    \"export default { title: 'Button', component: Button }\",\n    \"export default { title: 'Button', component: Button } as ComponentMeta<typeof Button>\",\n    `\n      const meta = { title: 'Button', component: Button }\n      export default meta\n    `,\n    `\n    const meta: ComponentMeta<typeof Button> = { title: 'Button', component: Button }\n    export default meta\n    `,\n    `\n      import { config } from '#.storybook/preview'\n      const meta = config.meta({})\n    `,\n    `\n      import { storiesOf } from '@storybook/react'\n      storiesOf('Component', module)\n    `,\n  ],\n\n  invalid: [\n    {\n      code: 'export const Primary = () => <button>hello</button>',\n      output: dedent`\n        export default {}\n        export const Primary = () => <button>hello</button>\n      `,\n      errors: [\n        {\n          messageId: 'shouldHaveDefaultExport',\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output: 'export default {}\\nexport const Primary = () => <button>hello</button>',\n            },\n          ],\n        },\n      ],\n    },\n    {\n      code: dedent`\n        import { MyComponent, Foo } from './MyComponent'\n        export const Primary = () => <button>hello</button>\n      `,\n      output: dedent`\n        import { MyComponent, Foo } from './MyComponent'\n        export default { component: MyComponent }\n        export const Primary = () => <button>hello</button>\n      `,\n      errors: [\n        {\n          messageId: 'shouldHaveDefaultExport',\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output:\n                \"import { MyComponent, Foo } from './MyComponent'\\nexport default { component: MyComponent }\\nexport const Primary = () => <button>hello</button>\",\n            },\n          ],\n        },\n      ],\n    },\n    {\n      code: dedent`\n        import MyComponent from './MyComponent'\n        export const Primary = () => <button>hello</button>\n      `,\n      output: dedent`\n        import MyComponent from './MyComponent'\n        export default { component: MyComponent }\n        export const Primary = () => <button>hello</button>\n      `,\n      errors: [\n        {\n          messageId: 'shouldHaveDefaultExport',\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output:\n                \"import MyComponent from './MyComponent'\\nexport default { component: MyComponent }\\nexport const Primary = () => <button>hello</button>\",\n            },\n          ],\n        },\n      ],\n    },\n    {\n      code: dedent`\n        import { MyComponentProps } from './MyComponent'\n        export const Primary = () => <button>hello</button>\n      `,\n      output: dedent`\n        import { MyComponentProps } from './MyComponent'\n        export default {}\n        export const Primary = () => <button>hello</button>\n      `,\n      errors: [\n        {\n          messageId: 'shouldHaveDefaultExport',\n          suggestions: [\n            {\n              messageId: 'fixSuggestion',\n              output:\n                \"import { MyComponentProps } from './MyComponent'\\nexport default {}\\nexport const Primary = () => <button>hello</button>\",\n            },\n          ],\n        },\n      ],\n    },\n  ],\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/default-exports.ts",
    "content": "/**\n * @file Story files should have a default export\n * @author Yann Braga\n */\nimport type { TSESLint, TSESTree } from '@typescript-eslint/utils';\nimport path from 'path';\n\nimport { isIdentifier, isImportDeclaration, isLiteral } from '../utils/ast.ts';\nimport { CategoryId } from '../utils/constants.ts';\nimport { createStorybookRule } from '../utils/create-storybook-rule.ts';\n\n//------------------------------------------------------------------------------\n// Rule Definition\n//------------------------------------------------------------------------------\n\nexport default createStorybookRule({\n  name: 'default-exports',\n  defaultOptions: [],\n  meta: {\n    type: 'problem',\n    severity: 'error',\n    docs: {\n      description: 'Story files should have a default export',\n      categories: [CategoryId.CSF, CategoryId.RECOMMENDED],\n    },\n    messages: {\n      shouldHaveDefaultExport: 'The file should have a default export.',\n      fixSuggestion: 'Add default export',\n    },\n    fixable: 'code',\n    hasSuggestions: true,\n    schema: [],\n  },\n\n  create(context) {\n    // variables should be defined here\n\n    //----------------------------------------------------------------------\n    // Helpers\n    //----------------------------------------------------------------------\n\n    // any helper functions should go here or else delete this section\n    const getComponentName = (node: TSESTree.Program, filePath: string) => {\n      const name = path.basename(filePath).split('.')[0];\n      const imported = node.body.find((stmt: TSESTree.Node) => {\n        if (\n          isImportDeclaration(stmt) &&\n          isLiteral(stmt.source) &&\n          stmt.source.value.startsWith(`./${name}`)\n        ) {\n          return !!stmt.specifiers.find(\n            (spec) => isIdentifier(spec.local) && spec.local.name === name\n          );\n        }\n      });\n      return imported ? name : null;\n    };\n\n    //----------------------------------------------------------------------\n    // Public\n    //----------------------------------------------------------------------\n\n    let hasDefaultExport = false;\n    let isCsf4Style = false;\n    let hasStoriesOfImport = false;\n\n    return {\n      ImportSpecifier(node) {\n        if ('name' in node.imported && node.imported.name === 'storiesOf') {\n          hasStoriesOfImport = true;\n        }\n      },\n      VariableDeclaration(node) {\n        // we check for variables declared at the root in a CSF4 style\n        // e.g. const meta = config.meta({})\n        if (node.parent.type === 'Program') {\n          node.declarations.forEach((declaration) => {\n            const init = declaration.init;\n\n            if (init && init.type === 'CallExpression') {\n              const callee = init.callee;\n\n              if (\n                callee.type === 'MemberExpression' &&\n                callee.property.type === 'Identifier' &&\n                callee.property.name === 'meta'\n              ) {\n                isCsf4Style = true;\n              }\n            }\n          });\n        }\n      },\n      ExportDefaultSpecifier: function () {\n        hasDefaultExport = true;\n      },\n      ExportDefaultDeclaration: function () {\n        hasDefaultExport = true;\n      },\n      'Program:exit': function (program: TSESTree.Program) {\n        if (!isCsf4Style && !hasDefaultExport && !hasStoriesOfImport) {\n          const componentName = getComponentName(program, context.filename);\n          const firstNonImportStatement = program.body.find((n) => !isImportDeclaration(n));\n          const node = firstNonImportStatement || program.body[0] || program;\n\n          const report = {\n            node,\n            messageId: 'shouldHaveDefaultExport',\n          } as const;\n\n          const fix: TSESLint.ReportFixFunction = (fixer) => {\n            const metaDeclaration = componentName\n              ? `export default { component: ${componentName} }\\n`\n              : 'export default {}\\n';\n            return fixer.insertTextBefore(node, metaDeclaration);\n          };\n\n          context.report({\n            ...report,\n            fix,\n            suggest: [\n              {\n                messageId: 'fixSuggestion',\n                fix,\n              },\n            ],\n          });\n        }\n      },\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/hierarchy-separator.test.ts",
    "content": "/**\n * @file Deprecated hierarchy separator\n * @author Yann Braga\n */\n//------------------------------------------------------------------------------\n// Requirements\n//------------------------------------------------------------------------------\nimport { AST_NODE_TYPES } from '@typescript-eslint/utils';\nimport { dedent } from 'ts-dedent';\n\nimport ruleTester from '../test-utils.ts';\nimport rule from './hierarchy-separator.ts';\n\n//------------------------------------------------------------------------------\n// Tests\n//------------------------------------------------------------------------------\n\nruleTester.run('hierarchy-separator', rule, {\n  valid: [\n    'export default {  }',\n    \"export default { title: 'Examples.Components' }\",\n    \"export default { title: 'Examples/Components/Button' }\",\n    \"export default { title: 'Examples/Components/Button' } as ComponentMeta<typeof Button>\",\n    \"export default { title: 'Examples.Components' } satisfies Meta<typeof Button>\",\n    'export default { ...props } as ComponentMeta<typeof Button>',\n  ],\n\n  invalid: [\n    {\n      code: \"export default { title: 'Examples|Components/Button' }\",\n      output: \"export default { title: 'Examples/Components/Button' }\",\n      errors: [\n        {\n          type: AST_NODE_TYPES.Property,\n          messageId: 'deprecatedHierarchySeparator',\n          suggestions: [\n            {\n              messageId: 'useCorrectSeparators',\n              output: \"export default { title: 'Examples/Components/Button' }\",\n            },\n          ],\n        },\n      ],\n    },\n    {\n      code: dedent`\n        const meta = { title: 'Examples|Components/Button' }\n        export default meta\n      `,\n      output: dedent`\n        const meta = { title: 'Examples/Components/Button' }\n        export default meta\n      `,\n      errors: [\n        {\n          type: AST_NODE_TYPES.Property,\n          messageId: 'deprecatedHierarchySeparator',\n          suggestions: [\n            {\n              messageId: 'useCorrectSeparators',\n              output: dedent`\n                const meta = { title: 'Examples/Components/Button' }\n                export default meta\n              `,\n            },\n          ],\n        },\n      ],\n    },\n  ],\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/hierarchy-separator.ts",
    "content": "/**\n * @file Deprecated hierarchy separator\n * @author Yann Braga\n */\nimport type { TSESTree } from '@typescript-eslint/utils';\n\nimport { getMetaObjectExpression } from '../utils/index.ts';\nimport { isLiteral, isSpreadElement } from '../utils/ast.ts';\nimport { CategoryId } from '../utils/constants.ts';\nimport { createStorybookRule } from '../utils/create-storybook-rule.ts';\n\n//------------------------------------------------------------------------------\n// Rule Definition\n//------------------------------------------------------------------------------\n\nexport default createStorybookRule({\n  name: 'hierarchy-separator',\n  defaultOptions: [],\n  meta: {\n    type: 'problem',\n    fixable: 'code',\n    hasSuggestions: true,\n    severity: 'warn',\n    docs: {\n      description: 'Deprecated hierarchy separator in title property',\n      categories: [CategoryId.CSF, CategoryId.RECOMMENDED],\n    },\n    messages: {\n      useCorrectSeparators: 'Use correct separators',\n      deprecatedHierarchySeparator:\n        'Deprecated hierarchy separator in title property: {{metaTitle}}.',\n    },\n    schema: [],\n  },\n  create: function (context) {\n    return {\n      ExportDefaultDeclaration: function (node) {\n        const meta = getMetaObjectExpression(node, context);\n        if (!meta) {\n          return null;\n        }\n\n        const titleNode = meta.properties.find(\n          (prop) => !isSpreadElement(prop) && 'name' in prop.key && prop.key?.name === 'title'\n        ) as TSESTree.MethodDefinition | TSESTree.Property | undefined;\n\n        if (!titleNode || !isLiteral(titleNode.value)) {\n          return;\n        }\n\n        const metaTitle = titleNode.value.raw || '';\n\n        if (metaTitle.includes('|')) {\n          context.report({\n            node: titleNode,\n            messageId: 'deprecatedHierarchySeparator',\n            data: { metaTitle },\n            // In case we want this to be auto fixed by --fix\n            fix: function (fixer) {\n              return fixer.replaceTextRange(titleNode.value.range, metaTitle.replace(/\\|/g, '/'));\n            },\n            suggest: [\n              {\n                messageId: 'useCorrectSeparators',\n                fix: function (fixer) {\n                  return fixer.replaceTextRange(\n                    titleNode.value.range,\n                    metaTitle.replace(/\\|/g, '/')\n                  );\n                },\n              },\n            ],\n          });\n        }\n      },\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/meta-inline-properties.test.ts",
    "content": "/**\n * @file Meta should have inline properties\n * @author Yann Braga\n */\n//------------------------------------------------------------------------------\n// Requirements\n//------------------------------------------------------------------------------\nimport { AST_NODE_TYPES } from '@typescript-eslint/utils';\nimport { dedent } from 'ts-dedent';\n\nimport ruleTester from '../test-utils.ts';\nimport rule from './meta-inline-properties.ts';\n\n//------------------------------------------------------------------------------\n// Tests\n//------------------------------------------------------------------------------\n\nruleTester.run('meta-inline-properties', rule, {\n  valid: [\n    \"export default { title: 'Button', args: { primary: true } }\",\n    \"export default { title: 'Button', args: { primary: true } } as ComponentMeta<typeof Button>\",\n  ],\n\n  invalid: [\n    {\n      code: `\n      const title = 'foo';\n      const args = { a: 1 };\n      export default { title, args };\n    `,\n      errors: [\n        {\n          messageId: 'metaShouldHaveInlineProperties',\n          data: {\n            property: 'title',\n          },\n          type: AST_NODE_TYPES.Property,\n        },\n        {\n          messageId: 'metaShouldHaveInlineProperties',\n          data: {\n            property: 'args',\n          },\n          type: AST_NODE_TYPES.Property,\n        },\n      ],\n    },\n    {\n      code: `\n        export default { title: 'a' + 123 };\n      `,\n      errors: [\n        {\n          messageId: 'metaShouldHaveInlineProperties',\n          data: {\n            property: 'title',\n          },\n          type: AST_NODE_TYPES.Property,\n        },\n      ],\n    },\n    {\n      code: `\n        export default { title: \\`a \\${123}\\` };\n      `,\n      errors: [\n        {\n          messageId: 'metaShouldHaveInlineProperties',\n          data: {\n            property: 'title',\n          },\n          type: AST_NODE_TYPES.Property,\n        },\n      ],\n    },\n    {\n      code: `\n        const title = 'a'\n\n        export default {\n          title,\n          component: Badge,\n        } as ComponentMeta<typeof Badge>\n      `,\n      errors: [\n        {\n          messageId: 'metaShouldHaveInlineProperties',\n          data: {\n            property: 'title',\n          },\n          type: AST_NODE_TYPES.Property,\n        },\n      ],\n    },\n    {\n      code: `\n        export default {\n          title: someFunction(),\n        }\n      `,\n      errors: [\n        {\n          messageId: 'metaShouldHaveInlineProperties',\n          data: {\n            property: 'title',\n          },\n          type: AST_NODE_TYPES.Property,\n        },\n      ],\n    },\n    {\n      code: dedent`\n        const title = 'a'\n\n        const meta: ComponentMeta<typeof Badge> = {\n          title,\n          component: Badge,\n        }\n\n        export default meta\n      `,\n      errors: [\n        {\n          messageId: 'metaShouldHaveInlineProperties',\n          data: {\n            property: 'title',\n          },\n          type: AST_NODE_TYPES.Property,\n        },\n      ],\n    },\n  ],\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/meta-inline-properties.ts",
    "content": "/**\n * @file Meta should have inline properties\n * @author Yann Braga\n */\nimport type { TSESTree } from '@typescript-eslint/utils';\n\nimport { getMetaObjectExpression } from '../utils/index.ts';\nimport { CategoryId } from '../utils/constants.ts';\nimport { createStorybookRule } from '../utils/create-storybook-rule.ts';\n\ntype TDynamicProperty = (TSESTree.MethodDefinition | TSESTree.Property) & {\n  key: TSESTree.Identifier | TSESTree.PrivateIdentifier;\n};\n\n//------------------------------------------------------------------------------\n// Rule Definition\n//------------------------------------------------------------------------------\n\nexport default createStorybookRule({\n  name: 'meta-inline-properties',\n  defaultOptions: [{ csfVersion: 3 }],\n  meta: {\n    type: 'problem',\n    severity: 'error',\n    docs: {\n      description: 'Meta should only have inline properties',\n      categories: [CategoryId.CSF, CategoryId.RECOMMENDED],\n      excludeFromConfig: true,\n    },\n    messages: {\n      metaShouldHaveInlineProperties: 'Meta should only have inline properties: {{property}}',\n    },\n    schema: [\n      {\n        type: 'object',\n        properties: {\n          csfVersion: {\n            type: 'number',\n          },\n        },\n        additionalProperties: false,\n      },\n    ],\n  },\n\n  create(context) {\n    // variables should be defined here\n\n    // In case we need to get options defined in the rule schema\n    // const options = context.options[0] || {}\n    // const csfVersion = options.csfVersion\n\n    //----------------------------------------------------------------------\n    // Helpers\n    //----------------------------------------------------------------------\n    const isInline = <T>(node: T | TDynamicProperty): node is T => {\n      if (!(node && typeof node === 'object' && 'value' in node)) {\n        return false;\n      }\n\n      return (\n        node.value.type === 'ObjectExpression' ||\n        node.value.type === 'Literal' ||\n        node.value.type === 'ArrayExpression'\n      );\n    };\n    // any helper functions should go here or else delete this section\n\n    //----------------------------------------------------------------------\n    // Public\n    //----------------------------------------------------------------------\n\n    return {\n      ExportDefaultDeclaration(node) {\n        const meta = getMetaObjectExpression(node, context);\n        if (!meta) {\n          return null;\n        }\n\n        const ruleProperties = ['title', 'args'];\n        const dynamicProperties: TDynamicProperty[] = [];\n\n        const metaNodes = meta.properties.filter(\n          (prop) => 'key' in prop && 'name' in prop.key && ruleProperties.includes(prop.key.name)\n        );\n\n        metaNodes.forEach((metaNode) => {\n          if (!isInline(metaNode)) {\n            dynamicProperties.push(metaNode);\n          }\n        });\n\n        if (dynamicProperties.length > 0) {\n          dynamicProperties.forEach((propertyNode) => {\n            context.report({\n              node: propertyNode,\n              messageId: 'metaShouldHaveInlineProperties',\n              data: {\n                property: propertyNode.key?.name,\n              },\n            });\n          });\n        }\n      },\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/meta-satisfies-type.test.ts",
    "content": "/**\n * @file Meta should use `satisfies Meta`\n * @author Tiger Oakes\n */\n//------------------------------------------------------------------------------\n// Requirements\n//------------------------------------------------------------------------------\nimport ruleTester from '../test-utils.ts';\nimport rule from './meta-satisfies-type.ts';\n\n//------------------------------------------------------------------------------\n// Tests\n//------------------------------------------------------------------------------\n\nruleTester.run('meta-satisfies-type', rule, {\n  valid: [\n    \"export default { title: 'Button', args: { primary: true } } satisfies Meta<typeof Button>\",\n    `const meta = {\n      component: AccountForm,\n    } satisfies Meta<typeof AccountForm>;\n    export default meta;`,\n  ],\n\n  invalid: [\n    {\n      code: `export default { title: 'Button', args: { primary: true } }`,\n      errors: [{ messageId: 'metaShouldSatisfyType' }],\n    },\n    {\n      code: `\n      const meta = {\n        component: AccountForm,\n      }\n      export default meta;\n    `,\n      errors: [{ messageId: 'metaShouldSatisfyType' }],\n    },\n    {\n      code: `\n      const meta: Meta<typeof AccountForm> = {\n        component: AccountForm,\n      }\n      export default meta;`,\n      output: `\n      const meta = {\n        component: AccountForm,\n      } satisfies Meta<typeof AccountForm>\n      export default meta;`,\n      errors: [{ messageId: 'metaShouldSatisfyType' }],\n    },\n    {\n      code: `export default { title: 'Button', args: { primary: true } } as Meta<typeof Button>`,\n      output: `export default { title: 'Button', args: { primary: true } } satisfies Meta<typeof Button>`,\n      errors: [{ messageId: 'metaShouldSatisfyType' }],\n    },\n    {\n      code: `\n      const meta = ( {\n        component: AccountForm,\n      }) as (Meta<typeof AccountForm> )\n      export default ( meta );`,\n      output: `\n      const meta = ( {\n        component: AccountForm,\n      }) satisfies (Meta<typeof AccountForm> )\n      export default ( meta );`,\n      errors: [{ messageId: 'metaShouldSatisfyType' }],\n    },\n  ],\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/meta-satisfies-type.ts",
    "content": "/**\n * @file Meta should be followed by `satisfies Meta`\n * @author Tiger Oakes\n */\nimport type { TSESLint, TSESTree } from '@typescript-eslint/utils';\nimport { ASTUtils, AST_NODE_TYPES } from '@typescript-eslint/utils';\n\nimport { getMetaObjectExpression } from '../utils/index.ts';\nimport { isTSSatisfiesExpression } from '../utils/ast.ts';\nimport { createStorybookRule } from '../utils/create-storybook-rule.ts';\n\n//------------------------------------------------------------------------------\n// Rule Definition\n//------------------------------------------------------------------------------\n\nexport default createStorybookRule({\n  name: 'meta-satisfies-type',\n  defaultOptions: [],\n  meta: {\n    type: 'problem',\n    fixable: 'code',\n    severity: 'error',\n    docs: {\n      description: 'Meta should use `satisfies Meta`',\n      categories: [],\n      excludeFromConfig: true,\n    },\n    messages: {\n      metaShouldSatisfyType: 'CSF Meta should use `satisfies` for type safety',\n    },\n    schema: [],\n  },\n\n  create(context) {\n    // variables should be defined here\n    const sourceCode = context.sourceCode;\n\n    //----------------------------------------------------------------------\n    // Helpers\n    //----------------------------------------------------------------------\n    const getTextWithParentheses = (node: TSESTree.Node): string => {\n      // Capture parentheses before and after the node\n      let beforeCount = 0;\n      let afterCount = 0;\n\n      if (ASTUtils.isParenthesized(node, sourceCode)) {\n        const bodyOpeningParen = sourceCode.getTokenBefore(node, ASTUtils.isOpeningParenToken);\n        const bodyClosingParen = sourceCode.getTokenAfter(node, ASTUtils.isClosingParenToken);\n\n        if (bodyOpeningParen && bodyClosingParen) {\n          beforeCount = node.range[0] - bodyOpeningParen.range[0];\n          afterCount = bodyClosingParen.range[1] - node.range[1];\n        }\n      }\n\n      return sourceCode.getText(node, beforeCount, afterCount);\n    };\n\n    const getFixer = (meta: TSESTree.ObjectExpression): TSESLint.ReportFixFunction | undefined => {\n      const { parent } = meta;\n      if (!parent) {\n        return undefined;\n      }\n\n      switch (parent.type) {\n        // {} as Meta\n        case AST_NODE_TYPES.TSAsExpression:\n          return (fixer) => [\n            fixer.replaceText(parent, getTextWithParentheses(meta)),\n            fixer.insertTextAfter(\n              parent,\n              ` satisfies ${getTextWithParentheses(parent.typeAnnotation)}`\n            ),\n          ];\n        // const meta: Meta = {}\n        case AST_NODE_TYPES.VariableDeclarator: {\n          const { typeAnnotation } = parent.id;\n          if (typeAnnotation) {\n            return (fixer) => [\n              fixer.remove(typeAnnotation),\n              fixer.insertTextAfter(\n                meta,\n                ` satisfies ${getTextWithParentheses(typeAnnotation.typeAnnotation)}`\n              ),\n            ];\n          }\n          return undefined;\n        }\n        default:\n          return undefined;\n      }\n    };\n    // any helper functions should go here or else delete this section\n\n    //----------------------------------------------------------------------\n    // Public\n    //----------------------------------------------------------------------\n\n    return {\n      ExportDefaultDeclaration(node) {\n        const meta = getMetaObjectExpression(node, context);\n        if (!meta) {\n          return null;\n        }\n\n        if (!meta.parent || !isTSSatisfiesExpression(meta.parent)) {\n          context.report({\n            node: meta,\n            messageId: 'metaShouldSatisfyType',\n            fix: getFixer(meta),\n          });\n        }\n      },\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/no-redundant-story-name.test.ts",
    "content": "/**\n * @file Named exports should not use the name annotation if it is redundant to the name that would\n *   be generated by the export name\n * @author Yann Braga\n */\n//------------------------------------------------------------------------------\n// Requirements\n//------------------------------------------------------------------------------\nimport { AST_NODE_TYPES } from '@typescript-eslint/utils';\nimport { dedent } from 'ts-dedent';\n\nimport ruleTester from '../test-utils.ts';\nimport rule from './no-redundant-story-name.ts';\n\n//------------------------------------------------------------------------------\n// Tests\n//------------------------------------------------------------------------------\n\nruleTester.run('no-redundant-story-name', rule, {\n  valid: [\n    \"export const PrimaryButton = { name: 'The Primary Button' }\",\n    \"export const PrimaryButton: Story = { name: 'The Primary Button' }\",\n    `\n      const Default = {}\n      export const PrimaryButton = { ...Default, name: 'The Primary Button' }\n    `,\n    `\n      export const PrimaryButton = Template.bind({})\n      PrimaryButton.storyName = 'The Primary Button'\n    `,\n    `\n      export function PrimaryButton () {\n        return <div>Hello</div>\n      }\n      PrimaryButton.storyName = 'The Primary Button'\n    `,\n    `\n      export function H1 () {\n        return <h1>Hello</h1>\n      }\n      H1.storyName = 'H1'\n    `,\n  ],\n\n  invalid: [\n    {\n      code: \"export const PrimaryButton = { name: 'Primary Button' }\",\n      errors: [\n        {\n          messageId: 'storyNameIsRedundant',\n          type: AST_NODE_TYPES.Property,\n          suggestions: [\n            {\n              messageId: 'removeRedundantName',\n              output: 'export const PrimaryButton = {  }',\n            },\n          ],\n        },\n      ],\n    },\n    {\n      code: \"export const PrimaryButton: Story = { name: 'Primary Button' }\",\n      errors: [\n        {\n          messageId: 'storyNameIsRedundant',\n          type: AST_NODE_TYPES.Property,\n          suggestions: [\n            {\n              messageId: 'removeRedundantName',\n              output: 'export const PrimaryButton: Story = {  }',\n            },\n          ],\n        },\n      ],\n    },\n    {\n      code: dedent`\n        export const PrimaryButton = Template.bind({})\n        PrimaryButton.storyName = 'Primary Button'\n      `,\n      errors: [\n        {\n          messageId: 'storyNameIsRedundant',\n          type: AST_NODE_TYPES.AssignmentExpression,\n          suggestions: [\n            {\n              messageId: 'removeRedundantName',\n              output: dedent`\n                export const PrimaryButton = Template.bind({})\n\n              `,\n            },\n          ],\n        },\n      ],\n    },\n  ],\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/no-redundant-story-name.ts",
    "content": "/**\n * @file Named exports should not use the name annotation if it is redundant to the name that would\n *   be generated by the export name\n * @author Yann Braga\n */\nimport { storyNameFromExport } from 'storybook/internal/csf';\n\nimport {\n  isExpressionStatement,\n  isIdentifier,\n  isLiteral,\n  isMetaProperty,\n  isObjectExpression,\n  isProperty,\n  isSpreadElement,\n  isVariableDeclaration,\n} from '../utils/ast.ts';\nimport { CategoryId } from '../utils/constants.ts';\nimport { createStorybookRule } from '../utils/create-storybook-rule.ts';\n\n//------------------------------------------------------------------------------\n// Rule Definition\n//------------------------------------------------------------------------------\n\nexport default createStorybookRule({\n  name: 'no-redundant-story-name',\n  defaultOptions: [],\n  meta: {\n    type: 'suggestion',\n    fixable: 'code',\n    hasSuggestions: true,\n    severity: 'warn',\n    docs: {\n      description: 'A story should not have a redundant name property',\n      categories: [CategoryId.CSF, CategoryId.RECOMMENDED],\n    },\n    messages: {\n      removeRedundantName: 'Remove redundant name',\n      storyNameIsRedundant:\n        'Named exports should not use the name annotation if it is redundant to the name that would be generated by the export name',\n    },\n    schema: [],\n  },\n\n  create(context) {\n    //----------------------------------------------------------------------\n    // Public\n    //----------------------------------------------------------------------\n\n    return {\n      // CSF3\n      ExportNamedDeclaration: function (node) {\n        // if there are specifiers, node.declaration should be null\n\n        // if there are specifiers, node.declaration should be null\n        if (!node.declaration) {\n          return;\n        }\n\n        const decl = node.declaration;\n        if (isVariableDeclaration(decl)) {\n          const declaration = decl.declarations[0];\n\n          if (declaration == null) {\n            return;\n          }\n          const { id, init } = declaration;\n          if (isIdentifier(id) && isObjectExpression(init)) {\n            const storyNameNode = init.properties.find(\n              (prop) =>\n                isProperty(prop) &&\n                isIdentifier(prop.key) &&\n                (prop.key?.name === 'name' || prop.key?.name === 'storyName')\n            );\n\n            if (!storyNameNode) {\n              return;\n            }\n\n            const { name } = id;\n            const resolvedStoryName = storyNameFromExport(name);\n\n            if (\n              !isSpreadElement(storyNameNode) &&\n              isLiteral(storyNameNode.value) &&\n              storyNameNode.value.value === resolvedStoryName\n            ) {\n              context.report({\n                node: storyNameNode,\n                messageId: 'storyNameIsRedundant',\n                suggest: [\n                  {\n                    messageId: 'removeRedundantName',\n                    fix: function (fixer) {\n                      return fixer.remove(storyNameNode);\n                    },\n                  },\n                ],\n              });\n            }\n          }\n        }\n      },\n      // CSF2\n      AssignmentExpression: function (node) {\n        if (!isExpressionStatement(node.parent)) {\n          return;\n        }\n\n        const { left, right } = node;\n\n        if (\n          'property' in left &&\n          isIdentifier(left.property) &&\n          !isMetaProperty(left) &&\n          left.property.name === 'storyName'\n        ) {\n          if (!('name' in left.object && 'value' in right)) {\n            return;\n          }\n\n          const propertyName = left.object.name;\n          const propertyValue = right.value;\n          const resolvedStoryName = storyNameFromExport(propertyName);\n\n          if (propertyValue === resolvedStoryName) {\n            context.report({\n              node: node,\n              messageId: 'storyNameIsRedundant',\n              suggest: [\n                {\n                  messageId: 'removeRedundantName',\n                  fix: function (fixer) {\n                    return fixer.remove(node);\n                  },\n                },\n              ],\n            });\n          }\n        }\n      },\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/no-renderer-packages.test.ts",
    "content": "/**\n * @file Do not import renderer packages directly in stories\n * @author Norbert De Langen\n */\n//------------------------------------------------------------------------------\n// Requirements\n//------------------------------------------------------------------------------\nimport { AST_NODE_TYPES } from '@typescript-eslint/utils';\nimport { dedent } from 'ts-dedent';\n\nimport ruleTester from '../test-utils.ts';\nimport rule from './no-renderer-packages.ts';\n\n//------------------------------------------------------------------------------\n// Tests\n//------------------------------------------------------------------------------\n\nruleTester.run('no-renderer-packages', rule, {\n  valid: [\n    // Valid framework package imports\n    dedent`\n      import { something } from '@storybook/react-vite';\n      \n      export const MyStory = {\n        // ...\n      };\n    `,\n    dedent`\n      import { something } from '@storybook/vue3-webpack5';\n      \n      export const MyStory = {\n        // ...\n      };\n    `,\n    dedent`\n      import { something } from '@storybook/web-components-vite';\n      \n      export const MyStory = {\n        // ...\n      };\n    `,\n    // Non-storybook imports should be valid\n    dedent`\n      import React from 'react';\n      import { something } from 'some-other-package';\n      \n      export const MyStory = {\n        // ...\n      };\n    `,\n  ],\n\n  invalid: [\n    {\n      code: dedent`\n        import { something } from '@storybook/react';\n        \n        export const MyStory = {\n          // ...\n        };\n      `,\n      errors: [\n        {\n          messageId: 'noRendererPackages',\n          data: {\n            rendererPackage: '@storybook/react',\n            suggestions:\n              '@storybook/nextjs, @storybook/react-vite, @storybook/nextjs-vite, @storybook/react-webpack5, @storybook/react-native-web-vite',\n          },\n          type: AST_NODE_TYPES.ImportDeclaration,\n        },\n      ],\n    },\n    {\n      code: dedent`\n        import { something } from '@storybook/vue3';\n        \n        export const MyStory = {\n          // ...\n        };\n      `,\n      errors: [\n        {\n          messageId: 'noRendererPackages',\n          type: AST_NODE_TYPES.ImportDeclaration,\n          data: {\n            rendererPackage: '@storybook/vue3',\n            suggestions: '@storybook/vue3-vite, @storybook/vue3-webpack5',\n          },\n        },\n      ],\n    },\n    {\n      code: dedent`\n        import { something } from '@storybook/web-components';\n        \n        export const MyStory = {\n          // ...\n        };\n      `,\n      errors: [\n        {\n          messageId: 'noRendererPackages',\n          type: AST_NODE_TYPES.ImportDeclaration,\n          data: {\n            rendererPackage: '@storybook/web-components',\n            suggestions: '@storybook/web-components-vite, @storybook/web-components-webpack5',\n          },\n        },\n      ],\n    },\n  ],\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/no-renderer-packages.ts",
    "content": "/**\n * @file Do not import renderer packages directly in stories\n * @author Norbert De Langen\n */\nimport type { TSESTree } from '@typescript-eslint/utils';\n\nimport { CategoryId } from '../utils/constants.ts';\nimport { createStorybookRule } from '../utils/create-storybook-rule.ts';\n\ntype RendererPackage =\n  | '@storybook/html'\n  | '@storybook/preact'\n  | '@storybook/react'\n  | '@storybook/server'\n  | '@storybook/svelte'\n  | '@storybook/vue3'\n  | '@storybook/web-components';\n\nconst rendererToFrameworks: Record<RendererPackage, string[]> = {\n  '@storybook/html': ['@storybook/html-vite', '@storybook/html-webpack5'],\n  '@storybook/preact': ['@storybook/preact-vite', '@storybook/preact-webpack5'],\n  '@storybook/react': [\n    '@storybook/nextjs',\n    '@storybook/react-vite',\n    '@storybook/nextjs-vite',\n    '@storybook/react-webpack5',\n    '@storybook/react-native-web-vite',\n  ],\n  '@storybook/server': ['@storybook/server-webpack5'],\n  '@storybook/svelte': [\n    '@storybook/svelte-vite',\n    '@storybook/svelte-webpack5',\n    '@storybook/sveltekit',\n  ],\n  '@storybook/vue3': ['@storybook/vue3-vite', '@storybook/vue3-webpack5'],\n  '@storybook/web-components': [\n    '@storybook/web-components-vite',\n    '@storybook/web-components-webpack5',\n  ],\n};\n\n//------------------------------------------------------------------------------\n// Rule Definition\n//------------------------------------------------------------------------------\n\ntype MessageIds = 'noRendererPackages';\ntype Options = readonly [];\n\nexport default createStorybookRule<Options, MessageIds>({\n  name: 'no-renderer-packages',\n  defaultOptions: [] as const,\n  meta: {\n    type: 'problem',\n    severity: 'error',\n    docs: {\n      description: 'Do not import renderer packages directly in stories',\n      categories: [CategoryId.RECOMMENDED],\n    },\n    schema: [],\n    messages: {\n      noRendererPackages:\n        'Do not import renderer package \"{{rendererPackage}}\" directly. Use a framework package instead (e.g. {{suggestions}}).',\n    },\n  },\n\n  create(context) {\n    return {\n      ImportDeclaration(node: TSESTree.ImportDeclaration) {\n        const packageName = node.source.value;\n\n        if (typeof packageName === 'string' && packageName in rendererToFrameworks) {\n          const suggestions = rendererToFrameworks[packageName as RendererPackage];\n\n          context.report({\n            node,\n            messageId: 'noRendererPackages',\n            data: {\n              rendererPackage: packageName,\n              suggestions: suggestions.join(', '),\n            },\n          });\n        }\n      },\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/no-stories-of.test.ts",
    "content": "/**\n * @file StoriesOf is deprecated and should not be used\n * @author Yann Braga\n */\n//------------------------------------------------------------------------------\n// Requirements\n//------------------------------------------------------------------------------\nimport { AST_NODE_TYPES } from '@typescript-eslint/utils';\n\nimport ruleTester from '../test-utils.ts';\nimport rule from './no-stories-of.ts';\n\n//------------------------------------------------------------------------------\n// Tests\n//------------------------------------------------------------------------------\n\nruleTester.run('no-stories-of', rule, {\n  valid: [\n    `\n      import Button from '../components/Button';\n      export default {\n        title: 'Button',\n        component: Button\n      }\n\n      export const Primary = () => <Button primary />\n    `,\n    `\n      import Button from '../components/Button';\n      export default {\n        title: 'Button',\n        component: Button\n      } as ComponentMeta<typeof Button>\n\n      export const Primary: Story = () => <Button primary />\n    `,\n  ],\n\n  invalid: [\n    {\n      code: `\n        import { storiesOf } from '@storybook/react';\n        import Button from '../components/Button';\n\n        storiesOf('Button', module)\n          .add('primary', () => <Button primary />)\n      `,\n      errors: [\n        {\n          messageId: 'doNotUseStoriesOf',\n          type: AST_NODE_TYPES.ImportSpecifier,\n        },\n      ],\n    },\n  ],\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/no-stories-of.ts",
    "content": "/**\n * @file StoriesOf is deprecated and should not be used\n * @author Yann Braga\n */\nimport { CategoryId } from '../utils/constants.ts';\nimport { createStorybookRule } from '../utils/create-storybook-rule.ts';\n\n//------------------------------------------------------------------------------\n// Rule Definition\n//------------------------------------------------------------------------------\n\nexport default createStorybookRule({\n  name: 'no-stories-of',\n  defaultOptions: [],\n  meta: {\n    type: 'problem',\n    severity: 'error',\n    docs: {\n      description: 'storiesOf is deprecated and should not be used',\n      categories: [CategoryId.CSF_STRICT],\n    },\n    messages: {\n      doNotUseStoriesOf: 'storiesOf is deprecated and should not be used',\n    },\n    schema: [],\n  },\n\n  create(context) {\n    // variables should be defined here\n\n    //----------------------------------------------------------------------\n    // Helpers\n    //----------------------------------------------------------------------\n\n    // any helper functions should go here or else delete this section\n\n    //----------------------------------------------------------------------\n    // Public\n    //----------------------------------------------------------------------\n\n    return {\n      ImportSpecifier(node) {\n        if ('name' in node.imported && node.imported.name === 'storiesOf') {\n          context.report({\n            node,\n            messageId: 'doNotUseStoriesOf',\n          });\n        }\n      },\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/no-title-property-in-meta.test.ts",
    "content": "/**\n * @file No title property in meta\n * @author Yann Braga\n */\n//------------------------------------------------------------------------------\n// Requirements\n//------------------------------------------------------------------------------\nimport { AST_NODE_TYPES } from '@typescript-eslint/utils';\nimport { dedent } from 'ts-dedent';\n\nimport ruleTester from '../test-utils.ts';\nimport rule from './no-title-property-in-meta.ts';\n\n//------------------------------------------------------------------------------\n// Tests\n//------------------------------------------------------------------------------\n\nruleTester.run('no-title-property-in-meta', rule, {\n  valid: [\n    'export default {  }',\n    'export default { component: Button }',\n    'export default { component: Button } as ComponentMeta<typeof Button>',\n    'export default { component: Button } as Meta<typeof Button>',\n    'export default { component: Button } satisfies Meta<typeof Button>',\n    'export default { ...props }',\n    // CSF4 factory pattern: meta is a function call result, not an object literal\n    // getMetaObjectExpression() returns null for CallExpressions, so the rule skips it\n    dedent`\n      const meta = preview.meta({ component: Button, title: 'Button' })\n      export default meta\n    `,\n    {\n      code: dedent`\n        const meta = preview.type<{ args: { theme: string } }>().meta({ component: Button, title: 'Button' })\n        export default meta\n      `,\n      filename: 'MyComponent.stories.ts',\n    },\n  ],\n\n  invalid: [\n    {\n      code: \"export default { title: 'Button', component: Button }\",\n      errors: [\n        {\n          messageId: 'noTitleInMeta',\n          type: AST_NODE_TYPES.Property,\n          suggestions: [\n            {\n              messageId: 'removeTitleInMeta',\n              output: 'export default {  component: Button }',\n            },\n          ],\n        },\n      ],\n    },\n    {\n      code: dedent`\n        const meta = { component: Button, title: 'Button' }\n        export default meta\n      `,\n      errors: [\n        {\n          messageId: 'noTitleInMeta',\n          type: AST_NODE_TYPES.Property,\n          suggestions: [\n            {\n              messageId: 'removeTitleInMeta',\n              output: dedent`\n                const meta = { component: Button,  }\n                export default meta\n              `,\n            },\n          ],\n        },\n      ],\n    },\n    {\n      code: dedent`\n        const meta = { component: Button, title: 'Button' } as Meta<typeof Button>\n        export default meta\n      `,\n      errors: [\n        {\n          messageId: 'noTitleInMeta',\n          type: AST_NODE_TYPES.Property,\n          suggestions: [\n            {\n              messageId: 'removeTitleInMeta',\n              output: dedent`\n                const meta = { component: Button,  } as Meta<typeof Button>\n                export default meta\n              `,\n            },\n          ],\n        },\n      ],\n    },\n    {\n      code: dedent`\n        const meta = { component: Button, title: 'Button' } satisfies Meta<typeof Button>\n        export default meta\n      `,\n      errors: [\n        {\n          messageId: 'noTitleInMeta',\n          type: AST_NODE_TYPES.Property,\n          suggestions: [\n            {\n              messageId: 'removeTitleInMeta',\n              output: dedent`\n                const meta = { component: Button,  } satisfies Meta<typeof Button>\n                export default meta\n              `,\n            },\n          ],\n        },\n      ],\n    },\n  ],\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/no-title-property-in-meta.ts",
    "content": "/**\n * @file No title property in meta\n * @author Yann Braga\n */\nimport type { TSESTree } from '@typescript-eslint/utils';\n\nimport { getMetaObjectExpression } from '../utils/index.ts';\nimport { isSpreadElement } from '../utils/ast.ts';\nimport { CategoryId } from '../utils/constants.ts';\nimport { createStorybookRule } from '../utils/create-storybook-rule.ts';\n\n//------------------------------------------------------------------------------\n// Rule Definition\n//------------------------------------------------------------------------------\n\nexport default createStorybookRule({\n  name: 'no-title-property-in-meta',\n  defaultOptions: [],\n  meta: {\n    type: 'problem',\n    fixable: 'code',\n    hasSuggestions: true,\n    severity: 'error',\n    docs: {\n      description: 'Do not define a title in meta',\n      categories: [CategoryId.CSF_STRICT],\n    },\n    messages: {\n      removeTitleInMeta: 'Remove title property from meta',\n      noTitleInMeta: `CSF3 does not need a title in meta`,\n    },\n    schema: [],\n  },\n  create: function (context) {\n    return {\n      ExportDefaultDeclaration: function (node) {\n        const meta = getMetaObjectExpression(node, context);\n        if (!meta) {\n          return null;\n        }\n\n        const titleNode = meta.properties.find(\n          (prop) => !isSpreadElement(prop) && 'name' in prop.key && prop.key?.name === 'title'\n        );\n\n        if (titleNode) {\n          context.report({\n            node: titleNode,\n            messageId: 'noTitleInMeta',\n            suggest: [\n              {\n                messageId: 'removeTitleInMeta',\n                fix(fixer) {\n                  const fullText = context.sourceCode.text;\n                  const propertyTextWithExtraCharacter = fullText.slice(\n                    titleNode.range[0],\n                    titleNode.range[1] + 1\n                  );\n                  const hasComma = propertyTextWithExtraCharacter.slice(-1) === ',';\n                  const propertyRange: TSESTree.Range = [\n                    titleNode.range[0],\n                    hasComma ? titleNode.range[1] + 1 : titleNode.range[1],\n                  ];\n                  return fixer.removeRange(propertyRange);\n                },\n              },\n            ],\n          });\n        }\n      },\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/no-uninstalled-addons.test.ts",
    "content": "/**\n * @file This rule identifies storybook addons that are invalid because they are either not\n *   installed or contain a typo in their name.\n * @author Andre \"andrelas1\" Santos\n */\n//------------------------------------------------------------------------------\n// Requirements\n//------------------------------------------------------------------------------\nimport { vi } from 'vitest';\n\nimport { AST_NODE_TYPES } from '@typescript-eslint/utils';\nimport { sep } from 'path';\n\nimport ruleTester from '../test-utils.ts';\nimport rule from './no-uninstalled-addons.ts';\n\nconst rootDir = process.cwd().split(sep).pop();\n\nvi.mock('fs', () => ({\n  ...vi.importActual('fs'),\n  readFileSync: () => `\n    {\n      \"devDependencies\": {\n        \"@storybook/addon-essentials\": \"^6.5.9\",\n        \"@storybook/addon-interactions\": \"^6.5.9\",\n        \"@storybook/preset-create-react-app\": \"^6.5.9\",\n        \"@storybook/addon-links\": \"^6.5.9\",\n        \"storybook-addon-valid-addon\": \"0.0.1\",\n        \"addon-without-the-prefix\": \"^0.0.1\"\n      }\n    }\n  `,\n}));\n\n//------------------------------------------------------------------------------\n// Tests\n//------------------------------------------------------------------------------\n\nruleTester.run('no-uninstalled-addons', rule, {\n  valid: [\n    `\n    export default {\n      addons: [\n        \"@storybook/addon-links\",\n        \"@storybook/addon-essentials\",\n        \"@storybook/addon-interactions\",\n        \"@storybook/preset-create-react-app\"\n      ]\n    }\n  `,\n    `\n    export default {\n      addons: [\n        \"@storybook/addon-links\",\n        \"@storybook/addon-essentials\",\n        \"@storybook/addon-interactions\",\n        \"@storybook/preset-create-react-app\"\n      ]\n    } satisfies StorybookConfig\n  `,\n    `\n     const config: StorybookConfig = {\n        addons: [\n        \"@storybook/addon-links\",\n        \"@storybook/addon-essentials\",\n        \"@storybook/addon-interactions\",\n        \"@storybook/preset-create-react-app\"\n        ]\n      }\n      export default config\n  `,\n    `\n    export const addons = [\n      \"@storybook/addon-links\",\n      \"@storybook/addon-essentials\",\n      \"@storybook/addon-interactions\",\n    ]\n  `,\n    `\n    module.exports = {\n        addons: [\n          \"@storybook/addon-links\",\n          \"@storybook/addon-essentials\",\n          \"@storybook/addon-interactions\",\n        ]\n      }\n  `,\n    `\n    module.exports = {\n        addons: [\n          \"storybook-addon-valid-addon/register\",\n          \"addon-without-the-prefix/preset\",\n        ]\n      }\n  `,\n    `\n    module.exports = {\n        addons: [\n          \"@storybook/addon-links\",\n          \"@storybook/addon-essentials\",\n          \"@storybook/addon-interactions\",\n          \"storybook-addon-valid-addon\",\n        ]\n      }\n  `,\n    `\n    module.exports = {\n        addons: [\n          \"@storybook/addon-links\",\n          \"@storybook/addon-essentials\",\n          \"@storybook/addon-interactions\",\n          \"addon-without-the-prefix\",\n        ]\n      }\n  `,\n    `\n      module.exports = {\n          addons: [\n            \"../my-local-addon\",\n            \"../my-local-addon/index.cjs\",\n            \"/Users/foo/my-local-addon/index.js\",\n            \"/mount/foo/my-local-addon/index.js\",\n            \"C:\\\\Users\\\\foo\\\\my-local-addon/index.js\",\n            \"D:\\\\Users\\\\foo\\\\my-local-addon/index.js\",\n          ]\n        }\n    `,\n    `\n    module.exports = {\n        addons: [\n          {\n            name: \"@storybook/addon-links\",\n          },\n          \"@storybook/addon-essentials\",\n          \"@storybook/addon-interactions\",\n          {\n            name: \"addon-without-the-prefix\",\n          },\n          {\n            name: \"storybook-addon-valid-addon/register.js\",\n          },\n        ]\n      }\n  `,\n    {\n      code: `\n      module.exports = {\n          addons: [\n            \"@storybook/addon-links\",\n            \"@storybook/addon-essentials\",\n            \"@storybook/addon-interactions\",\n            \"@storybook/not-installed-addon\",\n          ]\n        }\n    `,\n      options: [\n        {\n          packageJsonLocation: '',\n          ignore: ['@storybook/not-installed-addon'],\n        },\n      ],\n    },\n  ],\n  invalid: [\n    {\n      code: `\n      module.exports = {\n        addons: [\n          \"@storybook/addon-links\",\n          \"@storybook/addon-essentials\",\n          \"@storybook/addon-interactions\",\n          '@storybook/not-installed-addon'\n        ]\n      }\n      `,\n      errors: [\n        {\n          messageId: 'addonIsNotInstalled',\n          type: AST_NODE_TYPES.Literal,\n          data: {\n            addonName: '@storybook/not-installed-addon',\n            packageJsonPath: `${rootDir}${sep}`,\n          },\n        },\n      ],\n    },\n    {\n      code: `\n      module.exports = {\n        addons: [\n          \"@storybook/addon-links\",\n          \"@storybook/addon-essentials\",\n          \"@storybook/addon-interactions\",\n          {\n            name: '@storybook/not-installed-addon'\n          }\n        ]\n      }\n      `,\n      errors: [\n        {\n          messageId: 'addonIsNotInstalled',\n          type: AST_NODE_TYPES.Literal,\n          data: {\n            addonName: '@storybook/not-installed-addon',\n            packageJsonPath: `${rootDir}${sep}`,\n          },\n        },\n      ],\n    },\n    {\n      code: `\n      module.exports = {\n        addons: [\n          \"@storybook/addon-links\",\n          {\n            name: \"@storybook/addon-esentials\",\n          },\n          \"@storybook/addon-interactions\",\n        ]\n      }\n      `,\n      errors: [\n        {\n          messageId: 'addonIsNotInstalled',\n          type: AST_NODE_TYPES.Literal,\n          data: {\n            addonName: '@storybook/addon-esentials',\n            packageJsonPath: `${rootDir}${sep}`,\n          },\n        },\n      ],\n    },\n    {\n      code: `\n      module.exports = {\n        addons: [\n          \"@storybook/addon-links\",\n          \"@storybook/adon-essentials\",\n          \"@storybook/addon-interactions\",\n        ]\n      }\n      `,\n      errors: [\n        {\n          messageId: 'addonIsNotInstalled',\n          type: AST_NODE_TYPES.Literal,\n          data: {\n            addonName: '@storybook/adon-essentials',\n            packageJsonPath: `${rootDir}${sep}`,\n          },\n        },\n      ],\n    },\n    {\n      code: `\n      module.exports = {\n        addons: [\n          \"@storybook/addon-links\",\n          \"@storybook/addon-essentials\",\n          \"@storybook/addon-interactions\",\n          \"addon-withut-the-prefix\",\n          \"@storybook/addon-esentials\",\n        ]\n      }\n      `,\n      errors: [\n        {\n          messageId: 'addonIsNotInstalled',\n          type: AST_NODE_TYPES.Literal,\n          data: {\n            addonName: 'addon-withut-the-prefix',\n            packageJsonPath: `${rootDir}${sep}`,\n          },\n        },\n        {\n          messageId: 'addonIsNotInstalled',\n          type: AST_NODE_TYPES.Literal,\n          data: {\n            addonName: '@storybook/addon-esentials',\n            packageJsonPath: `${rootDir}${sep}`,\n          },\n        },\n      ],\n    },\n    {\n      code: `\n      export default {\n        addons: [\n          \"@storybook/addon-links\",\n          \"@storybook/addon-essentials\",\n          \"@storybook/addon-interactions\",\n          \"addon-withut-the-prefix\",\n          \"@storybook/addon-esentials\",\n        ]\n      }\n      `,\n      errors: [\n        {\n          messageId: 'addonIsNotInstalled',\n          type: AST_NODE_TYPES.Literal,\n          data: {\n            addonName: 'addon-withut-the-prefix',\n            packageJsonPath: `${rootDir}${sep}`,\n          },\n        },\n        {\n          messageId: 'addonIsNotInstalled',\n          type: AST_NODE_TYPES.Literal,\n          data: {\n            addonName: '@storybook/addon-esentials',\n            packageJsonPath: `${rootDir}${sep}`,\n          },\n        },\n      ],\n    },\n    {\n      code: `\n      export default {\n        addons: [\n          \"@storybook/addon-links\",\n          \"@storybook/addon-essentials\",\n          \"@storybook/addon-interactions\",\n          \"addon-withut-the-prefix\",\n          \"@storybook/addon-esentials\",\n        ]\n      } satisfies StorybookConfig\n      `,\n      errors: [\n        {\n          messageId: 'addonIsNotInstalled',\n          type: AST_NODE_TYPES.Literal,\n          data: {\n            addonName: 'addon-withut-the-prefix',\n            packageJsonPath: `${rootDir}${sep}`,\n          },\n        },\n        {\n          messageId: 'addonIsNotInstalled',\n          type: AST_NODE_TYPES.Literal,\n          data: {\n            addonName: '@storybook/addon-esentials',\n            packageJsonPath: `${rootDir}${sep}`,\n          },\n        },\n      ],\n    },\n    {\n      code: `\n      const config: StorybookConfig = {\n        addons: [\n          \"@storybook/addon-links\",\n          \"@storybook/addon-essentials\",\n          \"@storybook/addon-interactions\",\n          \"addon-withut-the-prefix\",\n          \"@storybook/addon-esentials\",\n        ]\n      }\n      export default config\n      `,\n      errors: [\n        {\n          messageId: 'addonIsNotInstalled',\n          type: AST_NODE_TYPES.Literal,\n          data: {\n            addonName: 'addon-withut-the-prefix',\n            packageJsonPath: `${rootDir}${sep}`,\n          },\n        },\n        {\n          messageId: 'addonIsNotInstalled',\n          type: AST_NODE_TYPES.Literal,\n          data: {\n            addonName: '@storybook/addon-esentials',\n            packageJsonPath: `${rootDir}${sep}`,\n          },\n        },\n      ],\n    },\n    {\n      code: `\n        export const addons = [\n          \"../my-local-addon\",\n          \"@storybook/addon-links\",\n          \"@storybook/addon-essentials\",\n          \"@storybook/addon-interactions\",\n          \"addon-withut-the-prefix\",\n          \"@storybook/addon-esentials\",\n        ]\n      `,\n      errors: [\n        {\n          messageId: 'addonIsNotInstalled',\n          type: AST_NODE_TYPES.Literal,\n          data: {\n            addonName: 'addon-withut-the-prefix',\n            packageJsonPath: `${rootDir}${sep}`,\n          },\n        },\n        {\n          messageId: 'addonIsNotInstalled',\n          type: AST_NODE_TYPES.Literal,\n          data: {\n            addonName: '@storybook/addon-esentials',\n            packageJsonPath: `${rootDir}${sep}`,\n          },\n        },\n      ],\n    },\n  ],\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/no-uninstalled-addons.ts",
    "content": "/**\n * @file This rule identifies storybook addons that are invalid because they are either not\n *   installed or contain a typo in their name.\n * @author Andre \"andrelas1\" Santos\n */\nimport type { TSESTree } from '@typescript-eslint/utils';\nimport { readFileSync } from 'fs';\nimport { relative, resolve, sep } from 'path';\nimport { dedent } from 'ts-dedent';\n\nimport { getMetaObjectExpression } from '../utils/index.ts';\nimport {\n  isArrayExpression,\n  isIdentifier,\n  isLiteral,\n  isObjectExpression,\n  isProperty,\n  isVariableDeclaration,\n  isVariableDeclarator,\n} from '../utils/ast.ts';\nimport { CategoryId } from '../utils/constants.ts';\nimport { createStorybookRule } from '../utils/create-storybook-rule.ts';\n\n//------------------------------------------------------------------------------\n// Rule Definition\n//------------------------------------------------------------------------------\n\nexport default createStorybookRule({\n  name: 'no-uninstalled-addons',\n  defaultOptions: [\n    {\n      packageJsonLocation: '' as string,\n      ignore: [] as string[],\n    },\n  ],\n  meta: {\n    type: 'problem',\n    severity: 'error',\n    docs: {\n      description:\n        'This rule identifies storybook addons that are invalid because they are either not installed or contain a typo in their name.',\n      categories: [CategoryId.RECOMMENDED],\n    },\n    messages: {\n      addonIsNotInstalled: `The {{ addonName }} is not installed in {{packageJsonPath}}. Did you forget to install it or is your package.json in a different location?`,\n    },\n\n    schema: [\n      {\n        type: 'object',\n        properties: {\n          packageJsonLocation: {\n            type: 'string',\n          },\n          ignore: {\n            type: 'array',\n            items: {\n              type: 'string',\n            },\n          },\n        },\n        additionalProperties: false,\n      },\n    ],\n  },\n\n  create(context) {\n    // variables should be defined here\n    const { packageJsonLocation, ignore } = context.options.reduce<{\n      packageJsonLocation: string;\n      ignore: string[];\n    }>(\n      (acc, val) => {\n        return {\n          packageJsonLocation: val.packageJsonLocation || acc.packageJsonLocation,\n          ignore: val.ignore || acc.ignore,\n        };\n      },\n      { packageJsonLocation: '', ignore: [] }\n    );\n\n    //----------------------------------------------------------------------\n    // Helpers\n    //----------------------------------------------------------------------\n\n    // this will not only exclude the nullables but it will also exclude the type undefined from them, so that TS does not complain\n    function excludeNullable<T>(item: T | undefined): item is T {\n      return !!item;\n    }\n\n    type MergeDepsWithDevDeps = (packageJson: PackageJsonDependencies) => string[];\n    const mergeDepsWithDevDeps: MergeDepsWithDevDeps = (packageJson) => {\n      const deps = Object.keys(packageJson.dependencies || {});\n      const devDeps = Object.keys(packageJson.devDependencies || {});\n      return [...deps, ...devDeps];\n    };\n\n    type IsAddonInstalled = (addon: string, installedAddons: string[]) => boolean;\n    const isAddonInstalled: IsAddonInstalled = (addon, installedAddons) => {\n      // cleanup /register or /preset + file extension from registered addon\n      const addonName = addon\n        .replace(/\\.[mc]?js$/, '')\n        .replace(/\\/register$/, '')\n        .replace(/\\/preset$/, '');\n\n      return installedAddons.includes(addonName);\n    };\n\n    const filterLocalAddons = (addon: string) => {\n      const isLocalAddon = (addonName: string) =>\n        addonName.startsWith('.') ||\n        addonName.startsWith('/') ||\n        // for local Windows files e.g. (C: F: D:)\n        /\\w:.*/.test(addonName) ||\n        addonName.startsWith('\\\\');\n\n      return !isLocalAddon(addon);\n    };\n\n    type AreThereAddonsNotInstalled = (\n      addons: string[],\n      installedSbAddons: string[]\n    ) => false | { name: string }[];\n    const areThereAddonsNotInstalled: AreThereAddonsNotInstalled = (addons, installedSbAddons) => {\n      const result = addons\n        // remove local addons (e.g. ./my-addon/register.js)\n        .filter(filterLocalAddons)\n        .filter((addon) => !isAddonInstalled(addon, installedSbAddons) && !ignore.includes(addon))\n        .map((addon) => ({ name: addon }));\n      return result.length ? result : false;\n    };\n\n    type PackageJsonDependencies = {\n      devDependencies: Record<string, string>;\n      dependencies: Record<string, string>;\n    };\n\n    type GetPackageJson = (path: string) => PackageJsonDependencies;\n\n    const getPackageJson: GetPackageJson = (path) => {\n      const packageJson = {\n        devDependencies: {},\n        dependencies: {},\n      };\n      try {\n        const file = readFileSync(path, 'utf8');\n        const parsedFile = JSON.parse(file);\n        packageJson.dependencies = parsedFile.dependencies || {};\n        packageJson.devDependencies = parsedFile.devDependencies || {};\n      } catch (err) {\n        // eslint-disable-next-line local-rules/no-uncategorized-errors\n        throw new Error(\n          dedent`The provided path in your eslintrc.json - ${path} is not a valid path to a package.json file or your package.json file is not in the same folder as ESLint is running from.\n\n          Read more at: https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin/docs/rules/no-uninstalled-addons.md\n          `\n        );\n      }\n\n      return packageJson;\n    };\n\n    const extractAllAddonsFromTheStorybookConfig = (\n      addonsExpression: TSESTree.ArrayExpression | undefined\n    ) => {\n      if (addonsExpression?.elements) {\n        // extract all nodes that are a string inside the addons array\n        const nodesWithAddons = addonsExpression.elements\n          .map((elem) => (isLiteral(elem) ? { value: elem.value, node: elem } : undefined))\n          .filter(excludeNullable);\n\n        const listOfAddonsInString = nodesWithAddons.map((elem) => elem.value) as string[];\n\n        // extract all nodes that are an object inside the addons array\n        const nodesWithAddonsInObj = addonsExpression.elements\n          .map((elem) => (isObjectExpression(elem) ? elem : { properties: [] }))\n          .map((elem) => {\n            const property: TSESTree.Property = elem.properties.find(\n              (prop) => isProperty(prop) && isIdentifier(prop.key) && prop.key.name === 'name'\n            ) as TSESTree.Property;\n            return isLiteral(property?.value)\n              ? { value: property.value.value, node: property.value }\n              : undefined;\n          })\n          .filter(excludeNullable);\n\n        const listOfAddonsInObj = nodesWithAddonsInObj.map((elem) => elem.value) as string[];\n\n        const listOfAddons = [...listOfAddonsInString, ...listOfAddonsInObj];\n        const listOfAddonElements = [...nodesWithAddons, ...nodesWithAddonsInObj];\n        return { listOfAddons, listOfAddonElements };\n      }\n\n      return { listOfAddons: [], listOfAddonElements: [] };\n    };\n\n    function reportUninstalledAddons(addonsProp: TSESTree.ArrayExpression) {\n      const packageJsonPath = resolve(packageJsonLocation || `./package.json`);\n      let packageJsonObject: PackageJsonDependencies;\n      try {\n        packageJsonObject = getPackageJson(packageJsonPath);\n      } catch (e) {\n        // if we cannot find the package.json, we cannot check if the addons are installed\n        throw new Error(e as string);\n      }\n\n      const depsAndDevDeps = mergeDepsWithDevDeps(packageJsonObject);\n\n      const { listOfAddons, listOfAddonElements } =\n        extractAllAddonsFromTheStorybookConfig(addonsProp);\n      const result = areThereAddonsNotInstalled(listOfAddons, depsAndDevDeps);\n\n      if (result) {\n        const elemsWithErrors = listOfAddonElements.filter(\n          (elem) => !!result.find((addon) => addon.name === elem.value)\n        );\n\n        const rootDir = process.cwd().split(sep).pop();\n        const currentPackageJsonPath = `${rootDir}${sep}${relative(process.cwd(), packageJsonLocation)}`;\n\n        elemsWithErrors.forEach((elem) => {\n          context.report({\n            node: elem.node,\n            messageId: 'addonIsNotInstalled',\n            data: {\n              addonName: elem.value,\n              packageJsonPath: currentPackageJsonPath,\n            },\n          });\n        });\n      }\n    }\n\n    function findAddonsPropAndReport(node: TSESTree.ObjectExpression) {\n      const addonsProp = node.properties.find(\n        (prop): prop is TSESTree.Property =>\n          isProperty(prop) && isIdentifier(prop.key) && prop.key.name === 'addons'\n      );\n\n      if (addonsProp?.value && isArrayExpression(addonsProp.value)) {\n        reportUninstalledAddons(addonsProp.value);\n      }\n    }\n\n    //----------------------------------------------------------------------\n    // Public\n    //----------------------------------------------------------------------\n\n    return {\n      AssignmentExpression: function (node) {\n        if (isObjectExpression(node.right)) {\n          findAddonsPropAndReport(node.right);\n        }\n      },\n      ExportDefaultDeclaration: function (node) {\n        const meta = getMetaObjectExpression(node, context);\n\n        if (!meta) {\n          return null;\n        }\n\n        findAddonsPropAndReport(meta);\n      },\n      ExportNamedDeclaration: function (node) {\n        const addonsProp =\n          isVariableDeclaration(node.declaration) &&\n          node.declaration.declarations.find(\n            (decl) =>\n              isVariableDeclarator(decl) && isIdentifier(decl.id) && decl.id.name === 'addons'\n          );\n\n        if (addonsProp && isArrayExpression(addonsProp.init)) {\n          reportUninstalledAddons(addonsProp.init);\n        }\n      },\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/prefer-pascal-case.test.ts",
    "content": "/**\n * @file Prefer pascal case\n * @author Yann Braga\n */\n//------------------------------------------------------------------------------\n// Requirements\n//------------------------------------------------------------------------------\nimport { AST_NODE_TYPES } from '@typescript-eslint/utils';\nimport { dedent } from 'ts-dedent';\n\nimport ruleTester from '../test-utils.ts';\nimport rule from './prefer-pascal-case.ts';\n\n//------------------------------------------------------------------------------\n// Tests\n//------------------------------------------------------------------------------\n\nruleTester.run('prefer-pascal-case', rule, {\n  valid: [\n    'export const Primary = {}',\n    `export const __namedExportsOrder = ['Secondary', 'Primary']`,\n    `export const _primary = {}`,\n    'export const Primary: Story = {}',\n    `\n      import { storiesOf } from '@storybook/react'\n      export const links = []\n      storiesOf('Component', module)\n    `,\n    `\n      export default {\n        title: 'MyComponent',\n        component: MyComponent,\n        includeStories: ['SimpleStory', 'ComplexStory'],\n        excludeStories: /.*Data$/,\n      };\n\n      export const simpleData = { foo: 1, bar: 'baz' };\n      export const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n\n      export const SimpleStory = () => <MyComponent data={simpleData} />;\n      export const ComplexStory = () => <MyComponent data={complexData} />;\n    `,\n    `\n      export default {\n        title: 'MyComponent',\n        component: MyComponent,\n        includeStories: [MyComponent.name],\n      };\n\n      export const SimpleStory = () => <MyComponent />;\n    `,\n  ],\n\n  invalid: [\n    {\n      code: dedent`\n        export const primary = {}\n        primary.foo = 'bar'\n      `,\n      errors: [\n        {\n          messageId: 'usePascalCase',\n          data: {\n            name: 'primary',\n          },\n          type: AST_NODE_TYPES.Identifier,\n          suggestions: [\n            {\n              messageId: 'convertToPascalCase',\n              output: dedent`\n                export const Primary = {}\n                Primary.foo = 'bar'\n              `,\n            },\n          ],\n        },\n      ],\n    },\n    {\n      code: dedent`\n        export const primary: Story = {}\n        primary.foo = 'bar'\n      `,\n      errors: [\n        {\n          messageId: 'usePascalCase',\n          data: {\n            name: 'primary',\n          },\n          type: AST_NODE_TYPES.Identifier,\n          suggestions: [\n            {\n              messageId: 'convertToPascalCase',\n              output: dedent`\n                export const Primary: Story = {}\n                Primary.foo = 'bar'\n              `,\n            },\n          ],\n        },\n      ],\n    },\n    {\n      code: dedent`\n        export default {\n          title: 'MyComponent',\n          component: MyComponent,\n          includeStories: /.*Story$/,\n          excludeStories: /.*Data$/,\n        };\n        export const simpleData = { foo: 1, bar: 'baz' };\n        export const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n        export const simpleStory = () => <MyComponent data={simpleData} />;\n        simpleStory.args = {};\n      `,\n      errors: [\n        {\n          messageId: 'usePascalCase',\n          data: {\n            name: 'simpleStory',\n          },\n          type: AST_NODE_TYPES.Identifier,\n          suggestions: [\n            {\n              messageId: 'convertToPascalCase',\n              output: dedent`\n                export default {\n                  title: 'MyComponent',\n                  component: MyComponent,\n                  includeStories: /.*Story$/,\n                  excludeStories: /.*Data$/,\n                };\n                export const simpleData = { foo: 1, bar: 'baz' };\n                export const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n                export const SimpleStory = () => <MyComponent data={simpleData} />;\n                SimpleStory.args = {};\n              `,\n            },\n          ],\n        },\n      ],\n    },\n  ],\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/prefer-pascal-case.ts",
    "content": "/**\n * @file Prefer pascal case\n * @author Yann Braga\n */\nimport type { IncludeExcludeOptions } from 'storybook/internal/csf';\nimport { isExportStory } from 'storybook/internal/csf';\n\nimport type { TSESLint, TSESTree } from '@typescript-eslint/utils';\nimport { ASTUtils } from '@typescript-eslint/utils';\n\nimport { getDescriptor, getMetaObjectExpression } from '../utils/index.ts';\nimport { isIdentifier, isVariableDeclaration } from '../utils/ast.ts';\nimport { CategoryId } from '../utils/constants.ts';\nimport { createStorybookRule } from '../utils/create-storybook-rule.ts';\n\n//------------------------------------------------------------------------------\n// Rule Definition\n//------------------------------------------------------------------------------\n\nexport default createStorybookRule({\n  name: 'prefer-pascal-case',\n  defaultOptions: [],\n  meta: {\n    type: 'suggestion',\n    fixable: 'code',\n    hasSuggestions: true,\n    severity: 'warn',\n    docs: {\n      description: 'Stories should use PascalCase',\n      categories: [CategoryId.RECOMMENDED],\n    },\n    messages: {\n      convertToPascalCase: 'Use pascal case',\n      usePascalCase: 'The story should use PascalCase notation: {{name}}',\n    },\n    schema: [],\n  },\n\n  create(context) {\n    // variables should be defined here\n\n    //----------------------------------------------------------------------\n    // Helpers\n    //----------------------------------------------------------------------\n\n    const isPascalCase = (str: string) => /^[A-Z]+([a-z0-9]?)+/.test(str);\n    const toPascalCase = (str: string) => {\n      return str\n        .replace(new RegExp(/[-_]+/, 'g'), ' ')\n        .replace(new RegExp(/[^\\w\\s]/, 'g'), '')\n        .replace(\n          new RegExp(/\\s+(.)(\\w+)/, 'g'),\n          (_, $2, $3) => `${$2.toUpperCase() + $3.toLowerCase()}`\n        )\n        .replace(new RegExp(/\\s/, 'g'), '')\n        .replace(new RegExp(/\\w/), (s) => s.toUpperCase());\n    };\n    const getModuleScope = (): TSESLint.Scope.Scope | undefined => {\n      const { sourceCode } = context;\n\n      // Compatibility implementation for eslint v8.x and v9.x or later\n      // see https://eslint.org/blog/2023/09/preparing-custom-rules-eslint-v9/#context.getscope()\n      // @ts-expect-error keep it for compatibility with eslint v8.x\n      if (sourceCode.getScope) {\n        // for eslint v9.x or later\n        return sourceCode.scopeManager?.scopes?.find(\n          (scope: TSESLint.Scope.Scope) => scope.type === 'module'\n        );\n      } else {\n        // for eslint v8.x\n        return context\n          .getScope()\n          .childScopes.find((scope) => scope.type === 'module') as unknown as TSESLint.Scope.Scope;\n      }\n    };\n\n    const checkAndReportError = (id: TSESTree.Identifier, nonStoryExportsConfig = {}) => {\n      const { name } = id;\n      if (!isExportStory(name, nonStoryExportsConfig) || name === '__namedExportsOrder') {\n        return null;\n      }\n\n      if (!name.startsWith('_') && !isPascalCase(name)) {\n        context.report({\n          node: id,\n          messageId: 'usePascalCase',\n          data: {\n            name,\n          },\n          suggest: [\n            {\n              messageId: 'convertToPascalCase',\n              *fix(fixer) {\n                const fullText = context.sourceCode.text;\n                const fullName = fullText.slice(id.range[0], id.range[1]);\n                const suffix = fullName.substring(name.length);\n                const pascal = toPascalCase(name);\n                yield fixer.replaceTextRange(id.range, pascal + suffix);\n\n                const scope = getModuleScope();\n                if (scope) {\n                  const variable = ASTUtils.findVariable(scope, name);\n                  const referenceCount = variable?.references?.length || 0;\n\n                  for (let i = 0; i < referenceCount; i++) {\n                    const ref = variable?.references[i];\n                    if (ref && !ref.init) {\n                      yield fixer.replaceTextRange(ref.identifier.range, pascal);\n                    }\n                  }\n                }\n              },\n            },\n          ],\n        });\n      }\n    };\n\n    //----------------------------------------------------------------------\n    // Public\n    //----------------------------------------------------------------------\n\n    let meta;\n    let nonStoryExportsConfig: IncludeExcludeOptions;\n    const namedExports: TSESTree.Identifier[] = [];\n    let hasStoriesOfImport = false;\n\n    return {\n      ImportSpecifier(node) {\n        if ('name' in node.imported && node.imported.name === 'storiesOf') {\n          hasStoriesOfImport = true;\n        }\n      },\n      ExportDefaultDeclaration: function (node) {\n        meta = getMetaObjectExpression(node, context);\n        if (meta) {\n          try {\n            nonStoryExportsConfig = {\n              excludeStories: getDescriptor(meta, 'excludeStories'),\n              includeStories: getDescriptor(meta, 'includeStories'),\n            };\n          } catch (err) {\n            //\n          }\n        }\n      },\n      ExportNamedDeclaration: function (node: TSESTree.ExportNamedDeclaration) {\n        // if there are specifiers, node.declaration should be null\n\n        // if there are specifiers, node.declaration should be null\n        if (!node.declaration) {\n          return;\n        }\n\n        const decl = node.declaration;\n        if (isVariableDeclaration(decl)) {\n          const declaration = decl.declarations[0];\n\n          if (declaration == null) {\n            return;\n          }\n          const { id } = declaration;\n          if (isIdentifier(id)) {\n            namedExports.push(id);\n          }\n        }\n      },\n      'Program:exit': function () {\n        if (namedExports.length && !hasStoriesOfImport) {\n          namedExports.forEach((n) => checkAndReportError(n, nonStoryExportsConfig));\n        }\n      },\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/story-exports.test.ts",
    "content": "/**\n * @file A story file must contain at least one story export\n * @author Yann Braga\n */\n//------------------------------------------------------------------------------\n// Requirements\n//------------------------------------------------------------------------------\nimport { dedent } from 'ts-dedent';\n\nimport ruleTester from '../test-utils.ts';\nimport rule from './story-exports.ts';\n\n//------------------------------------------------------------------------------\n// Tests\n//------------------------------------------------------------------------------\n\nruleTester.run('story-exports', rule, {\n  valid: [\n    'export const Primary = {}',\n    dedent`\n      export default {}\n      export const Primary = {}\n    `,\n    dedent`\n      export default {} as ComponentMeta<typeof RestaurantDetailPage>\n      export const Primary = {}\n    `,\n    dedent`\n      import { storiesOf } from '@storybook/react'\n      storiesOf('MyComponent', module)\n    `,\n    dedent`\n      const Primary = {}\n      const Secondary = {}\n      export default {}\n      export { Primary, Secondary }\n    `,\n    `\n      export default {\n        title: 'MyComponent',\n        component: MyComponent,\n        includeStories: [MyComponent.name],\n      };\n\n      export const SimpleStory = () => <MyComponent />;\n    `,\n    dedent`\n      export default {\n        excludeStories: /.*Data$/,\n      }\n\n      const mockData = {}\n      const Primary = {}\n\n      export { mockData, Primary }\n    `,\n    'export function Primary() {}',\n    dedent`\n      export default {}\n      export function Primary() {}\n    `,\n    dedent`\n      export default {} as ComponentMeta<typeof RestaurantDetailPage>\n      export function Primary() {}\n    `,\n  ],\n  invalid: [\n    {\n      code: dedent`\n        export default {\n          component: Button\n        } as ComponentMeta<typeof RestaurantDetailPage>`,\n      // output: dedent`\n      //   export default {\n      //     component: Button\n      //   } as ComponentMeta<typeof RestaurantDetailPage>\n\n      //   export const Default = {}\n      // `,\n      errors: [\n        {\n          messageId: 'shouldHaveStoryExport',\n        },\n      ],\n    },\n    {\n      code: dedent`\n        export default {\n          excludeStories: /.*Data$/,\n        }\n\n        export const mockData = {}\n      `,\n      // output: dedent`\n      //   export default {\n      //     excludeStories: /.*Data$/,\n      //   }\n\n      //   export const mockData = {}\n\n      //   export const Default = {}\n      // `,\n      errors: [\n        {\n          messageId: 'shouldHaveStoryExportWithFilters',\n        },\n      ],\n    },\n    {\n      code: dedent`\n        export default {\n          excludeStories: /.*Data$/,\n        }\n\n        const mockData = {}\n        const Primary = {}\n\n        export { mockData }\n      `,\n      // output: dedent`\n      //   export default {\n      //     excludeStories: /.*Data$/,\n      //   }\n\n      //   const mockData = {}\n      //   const Primary = {}\n\n      //   export { mockData }\n\n      //   export const Default = {}\n      // `,\n      errors: [\n        {\n          messageId: 'shouldHaveStoryExportWithFilters',\n        },\n      ],\n    },\n    {\n      code: dedent`\n        export default {\n          excludeStories: /.*Data$/,\n        }\n\n        export function generateMockData() {}\n      `,\n      // output: dedent`\n      //   export default {\n      //     excludeStories: /.*Data$/,\n      //   }\n\n      //   export function generateMockData() {}\n\n      //   export const Default = {}\n      // `,\n      errors: [\n        {\n          messageId: 'shouldHaveStoryExportWithFilters',\n        },\n      ],\n    },\n  ],\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/story-exports.ts",
    "content": "/**\n * @file A story file must contain at least one story export\n * @author Yann Braga\n */\nimport type { IncludeExcludeOptions } from 'storybook/internal/csf';\n\nimport type { TSESTree } from '@typescript-eslint/utils';\n\nimport {\n  getAllNamedExports,\n  getDescriptor,\n  getMetaObjectExpression,\n  isValidStoryExport,\n} from '../utils/index.ts';\nimport { isImportDeclaration } from '../utils/ast.ts';\nimport { CategoryId } from '../utils/constants.ts';\nimport { createStorybookRule } from '../utils/create-storybook-rule.ts';\n\n//------------------------------------------------------------------------------\n// Rule Definition\n//------------------------------------------------------------------------------\n\nexport default createStorybookRule({\n  name: 'story-exports',\n  defaultOptions: [],\n  meta: {\n    type: 'problem',\n    severity: 'error',\n    docs: {\n      description: 'A story file must contain at least one story export',\n      categories: [CategoryId.RECOMMENDED, CategoryId.CSF],\n    },\n    messages: {\n      shouldHaveStoryExport: 'The file should have at least one story export',\n      shouldHaveStoryExportWithFilters:\n        'The file should have at least one story export. Make sure the includeStories/excludeStories you defined are correct, otherwise Storybook will not use any stories for this file.',\n      addStoryExport: 'Add a story export',\n    },\n    fixable: undefined, // change to 'code' once we have autofixes\n    schema: [],\n  },\n\n  create(context) {\n    // variables should be defined here\n\n    //----------------------------------------------------------------------\n    // Helpers\n    //----------------------------------------------------------------------\n\n    //----------------------------------------------------------------------\n    // Public\n    //----------------------------------------------------------------------\n\n    let hasStoriesOfImport = false;\n    let nonStoryExportsConfig: IncludeExcludeOptions = {};\n    let meta: TSESTree.ObjectExpression | null;\n    const namedExports: TSESTree.Identifier[] = [];\n\n    return {\n      ImportSpecifier(node) {\n        if ('name' in node.imported && node.imported.name === 'storiesOf') {\n          hasStoriesOfImport = true;\n        }\n      },\n      ExportDefaultDeclaration: function (node) {\n        meta = getMetaObjectExpression(node, context);\n        if (meta) {\n          try {\n            nonStoryExportsConfig = {\n              excludeStories: getDescriptor(meta, 'excludeStories'),\n              includeStories: getDescriptor(meta, 'includeStories'),\n            };\n          } catch (err) {\n            //\n          }\n        }\n      },\n      ExportNamedDeclaration: function (node) {\n        namedExports.push(...getAllNamedExports(node));\n      },\n      'Program:exit': function (program: TSESTree.Program) {\n        if (hasStoriesOfImport || !meta) {\n          return;\n        }\n\n        const storyExports = namedExports.filter((exp) =>\n          isValidStoryExport(exp, nonStoryExportsConfig)\n        );\n\n        if (storyExports.length) {\n          return;\n        }\n\n        const firstNonImportStatement = program.body.find((n) => !isImportDeclaration(n));\n        const node = firstNonImportStatement || program.body[0] || program;\n\n        // @TODO: bring apply this autofix with CSF3 release\n        // const fix = (fixer) => fixer.insertTextAfter(node, `\\n\\nexport const Default = {}`)\n\n        const hasFilter =\n          nonStoryExportsConfig.includeStories || nonStoryExportsConfig.excludeStories;\n        const report = {\n          node,\n          messageId: hasFilter ? 'shouldHaveStoryExportWithFilters' : 'shouldHaveStoryExport',\n          // fix,\n        } as const;\n\n        context.report(report);\n      },\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/use-storybook-expect.test.ts",
    "content": "/**\n * @file Use expect from '@storybook/jest'\n * @author Yann Braga\n */\n//------------------------------------------------------------------------------\n// Requirements\n//------------------------------------------------------------------------------\nimport { AST_NODE_TYPES } from '@typescript-eslint/utils';\nimport { dedent } from 'ts-dedent';\n\nimport ruleTester from '../test-utils.ts';\nimport rule from './use-storybook-expect.ts';\n\n//------------------------------------------------------------------------------\n// Tests\n//------------------------------------------------------------------------------\n\nruleTester.run('use-storybook-expect', rule, {\n  valid: [\n    dedent`\n      import { expect } from '@storybook/jest';\n\n      Default.play = () => {\n        expect(123).toEqual(123);\n      }\n    `,\n    dedent`\n      import { expect } from '@storybook/jest';\n\n      export const Basic = {\n        ...Default,\n        play: async (context) => {\n          expect(123).toEqual(123);\n        },\n      };\n    `,\n    dedent`\n      import { expect } from '@storybook/test';\n\n      Default.play = () => {\n        expect(123).toEqual(123);\n      }\n    `,\n    dedent`\n      import { expect } from '@storybook/test';\n\n      export const Basic = {\n        ...Default,\n        play: async (context) => {\n          expect(123).toEqual(123);\n        },\n      };\n    `,\n    dedent`\n      import { expect } from 'storybook/test';\n\n      Default.play = () => {\n        expect(123).toEqual(123);\n      }\n    `,\n  ],\n\n  invalid: [\n    {\n      code: dedent`\n        Default.play = () => {\n          expect(123).toEqual(123);\n        }\n      `,\n      errors: [\n        {\n          messageId: 'useExpectFromStorybook',\n          type: AST_NODE_TYPES.Identifier,\n        },\n      ],\n    },\n    {\n      code: dedent`\n        const someInteraction = () => {\n          expect(123).toEqual(123);\n        }\n        Default.play = someInteraction\n      `,\n      errors: [\n        {\n          messageId: 'useExpectFromStorybook',\n          type: AST_NODE_TYPES.Identifier,\n        },\n      ],\n    },\n    {\n      code: dedent`\n        export const Basic = {\n          ...Default,\n          play: async (context) => {\n            expect(123).toEqual(123);\n          },\n        };\n      `,\n      errors: [\n        {\n          messageId: 'useExpectFromStorybook',\n          type: AST_NODE_TYPES.Identifier,\n        },\n      ],\n    },\n  ],\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/use-storybook-expect.ts",
    "content": "/**\n * @file Use expect from '@storybook/jest'\n * @author Yann Braga\n */\nimport type { TSESTree } from '@typescript-eslint/utils';\n\nimport { isIdentifier, isImportSpecifier } from '../utils/ast.ts';\nimport { CategoryId } from '../utils/constants.ts';\nimport { createStorybookRule } from '../utils/create-storybook-rule.ts';\n\n//------------------------------------------------------------------------------\n// Rule Definition\n//------------------------------------------------------------------------------\n\ntype TDefaultOptions = {\n  storybookJestPath?: string;\n}[];\n\nexport default createStorybookRule<TDefaultOptions, string>({\n  name: 'use-storybook-expect',\n  defaultOptions: [],\n  meta: {\n    type: 'suggestion',\n    fixable: 'code',\n    schema: [],\n    severity: 'error',\n    docs: {\n      description: 'Use expect from `@storybook/test`, `storybook/test` or `@storybook/jest`',\n      categories: [CategoryId.ADDON_INTERACTIONS, CategoryId.RECOMMENDED],\n    },\n    messages: {\n      useExpectFromStorybook:\n        'Do not use global expect directly in the story. You should import it from `@storybook/test` (preferrably) or `@storybook/jest` instead.',\n    },\n  },\n\n  create(context) {\n    // variables should be defined here\n\n    //----------------------------------------------------------------------\n    // Helpers\n    //----------------------------------------------------------------------\n\n    const isExpectFromStorybookImported = (node: TSESTree.ImportDeclaration) => {\n      const { value: packageName } = node.source;\n      const usesExpectFromStorybook =\n        packageName === '@storybook/jest' ||\n        packageName === '@storybook/test' ||\n        packageName === 'storybook/test';\n      return (\n        usesExpectFromStorybook &&\n        node.specifiers.find(\n          (spec) =>\n            isImportSpecifier(spec) && 'name' in spec.imported && spec.imported.name === 'expect'\n        )\n      );\n    };\n\n    //----------------------------------------------------------------------\n    // Public\n    //----------------------------------------------------------------------\n\n    let isImportingFromStorybookExpect = false;\n    const expectInvocations: TSESTree.Identifier[] = [];\n\n    return {\n      ImportDeclaration(node) {\n        if (isExpectFromStorybookImported(node)) {\n          isImportingFromStorybookExpect = true;\n        }\n      },\n      CallExpression(node) {\n        if (!isIdentifier(node.callee)) {\n          return null;\n        }\n\n        if (node.callee.name === 'expect') {\n          expectInvocations.push(node.callee);\n        }\n      },\n      'Program:exit': function () {\n        if (!isImportingFromStorybookExpect && expectInvocations.length) {\n          expectInvocations.forEach((node) => {\n            context.report({\n              node,\n              messageId: 'useExpectFromStorybook',\n            });\n          });\n        }\n      },\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/use-storybook-testing-library.test.ts",
    "content": "/**\n * @file Do not testing library directly on stories\n * @author Yann Braga\n */\n//------------------------------------------------------------------------------\n// Requirements\n//------------------------------------------------------------------------------\nimport { AST_NODE_TYPES } from '@typescript-eslint/utils';\n\nimport ruleTester from '../test-utils.ts';\nimport rule from './use-storybook-testing-library.ts';\n\n//------------------------------------------------------------------------------\n// Tests\n//------------------------------------------------------------------------------\n\nruleTester.run('use-storybook-testing-library', rule, {\n  valid: [\"import { within } from '@storybook/testing-library'\"],\n\n  invalid: [\n    {\n      code: \"import { within } from '@testing-library/dom'\",\n      output: \"import { within } from '@storybook/testing-library'\",\n      errors: [\n        {\n          messageId: 'dontUseTestingLibraryDirectly',\n          data: {\n            library: '@testing-library/dom',\n          },\n          type: AST_NODE_TYPES.ImportDeclaration,\n          suggestions: [\n            {\n              messageId: 'updateImports',\n              output: \"import { within } from '@storybook/testing-library'\",\n            },\n          ],\n        },\n      ],\n    },\n    {\n      code: \"import userEvent from '@testing-library/user-event'\",\n      output: \"import { userEvent } from '@storybook/testing-library'\",\n      errors: [\n        {\n          messageId: 'dontUseTestingLibraryDirectly',\n          data: {\n            library: '@testing-library/user-event',\n          },\n          type: AST_NODE_TYPES.ImportDeclaration,\n          suggestions: [\n            {\n              messageId: 'updateImports',\n              output: \"import { userEvent } from '@storybook/testing-library'\",\n            },\n          ],\n        },\n      ],\n    },\n    {\n      code: \"import userEvent, { foo, bar as Bar } from '@testing-library/user-event'\",\n      output: \"import { userEvent, foo, bar as Bar } from '@storybook/testing-library'\",\n      errors: [\n        {\n          messageId: 'dontUseTestingLibraryDirectly',\n          data: {\n            library: '@testing-library/user-event',\n          },\n          type: AST_NODE_TYPES.ImportDeclaration,\n          suggestions: [\n            {\n              messageId: 'updateImports',\n              output: \"import { userEvent, foo, bar as Bar } from '@storybook/testing-library'\",\n            },\n          ],\n        },\n      ],\n    },\n  ],\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/rules/use-storybook-testing-library.ts",
    "content": "/**\n * @file Do not use testing library directly on stories\n * @author Yann Braga\n */\nimport type { TSESTree } from '@typescript-eslint/utils';\n\nimport { isImportDefaultSpecifier } from '../utils/ast.ts';\nimport { CategoryId } from '../utils/constants.ts';\nimport { createStorybookRule } from '../utils/create-storybook-rule.ts';\n\n//------------------------------------------------------------------------------\n// Rule Definition\n//------------------------------------------------------------------------------\nexport default createStorybookRule({\n  name: 'use-storybook-testing-library',\n  defaultOptions: [],\n  meta: {\n    type: 'suggestion',\n    fixable: 'code',\n    hasSuggestions: true,\n    severity: 'error',\n    docs: {\n      description: 'Do not use testing-library directly on stories',\n      categories: [CategoryId.ADDON_INTERACTIONS, CategoryId.RECOMMENDED],\n    },\n    schema: [],\n    messages: {\n      updateImports: 'Update imports',\n      dontUseTestingLibraryDirectly:\n        'Do not use `{{library}}` directly in the story. You should import the functions from `@storybook/test` (preferrably) or `@storybook/testing-library` instead.',\n    },\n  },\n\n  create(context) {\n    // variables should be defined here\n\n    //----------------------------------------------------------------------\n    // Helpers\n    //----------------------------------------------------------------------\n    const getRangeWithoutQuotes = (source: TSESTree.StringLiteral): TSESTree.Range => {\n      return [\n        // Not sure how to improve this. If I use node.source.range\n        // it will eat the quotes and we do not want to specify whether the quotes are single or double\n        source.range[0] + 1,\n        source.range[1] - 1,\n      ];\n    };\n\n    const hasDefaultImport = (specifiers: TSESTree.ImportClause[]) =>\n      specifiers.find((s) => isImportDefaultSpecifier(s));\n\n    const getSpecifiers = (node: TSESTree.ImportDeclaration) => {\n      const { specifiers } = node;\n      if (!specifiers[0]) {\n        return null;\n      }\n\n      const start = specifiers[0].range[0];\n      const previousSpecifier = specifiers[specifiers.length - 1];\n      if (!previousSpecifier) {\n        return null;\n      }\n\n      let end = previousSpecifier.range[1];\n\n      // this weird hack is necessary because the specifier range\n      // does not include the closing brace:\n      //\n      // import foo, { bar } from 'baz';\n      //        ^        ^ end\n      const fullText = context.sourceCode.text;\n      const importEnd = node.range[1];\n      const closingBrace = fullText.indexOf('}', end - 1);\n      if (closingBrace > -1 && closingBrace <= importEnd) {\n        end = closingBrace + 1;\n      }\n      const text = fullText.substring(start, end);\n\n      return { range: [start, end] as TSESTree.Range, text };\n    };\n\n    const fixSpecifiers = (specifiersText: string) => {\n      const flattened = specifiersText\n        .replace('{', '')\n        .replace('}', '')\n        .replace(/\\s\\s+/g, ' ')\n        .trim();\n      return `{ ${flattened} }`;\n    };\n\n    //----------------------------------------------------------------------\n    // Public\n    //----------------------------------------------------------------------\n\n    return {\n      ImportDeclaration(node) {\n        if (node.source.value.includes('@testing-library')) {\n          context.report({\n            node,\n            messageId: 'dontUseTestingLibraryDirectly',\n            data: {\n              library: node.source.value,\n            },\n            *fix(fixer) {\n              yield fixer.replaceTextRange(\n                getRangeWithoutQuotes(node.source),\n                '@storybook/testing-library'\n              );\n              if (hasDefaultImport(node.specifiers)) {\n                const specifiers = getSpecifiers(node);\n                if (specifiers) {\n                  const { range, text } = specifiers;\n                  yield fixer.replaceTextRange(range, fixSpecifiers(text));\n                }\n              }\n            },\n            suggest: [\n              {\n                messageId: 'updateImports',\n                *fix(fixer) {\n                  yield fixer.replaceTextRange(\n                    getRangeWithoutQuotes(node.source),\n                    '@storybook/testing-library'\n                  );\n                  if (hasDefaultImport(node.specifiers)) {\n                    const specifiers = getSpecifiers(node);\n                    if (specifiers) {\n                      const { range, text } = specifiers;\n                      yield fixer.replaceTextRange(range, fixSpecifiers(text));\n                    }\n                  }\n                },\n              },\n            ],\n          });\n        }\n      },\n    };\n  },\n});\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/test-utils.ts",
    "content": "import { RuleTester } from '@typescript-eslint/rule-tester';\nimport type { TSESLint } from '@typescript-eslint/utils';\n\nconst DEFAULT_TEST_CASE_CONFIG = {\n  filename: 'MyComponent.stories.js',\n};\n\nclass StorybookRuleTester extends RuleTester {\n  run<TMessageIds extends string, TOptions extends Readonly<unknown[]>>(\n    ruleName: string,\n    rule: TSESLint.RuleModule<TMessageIds, TOptions>,\n    tests: TSESLint.RunTests<TMessageIds, TOptions>\n  ): void {\n    const { valid, invalid } = tests;\n\n    const finalValid = valid.map((testCase) => {\n      if (typeof testCase === 'string') {\n        return {\n          ...DEFAULT_TEST_CASE_CONFIG,\n          code: testCase,\n        };\n      }\n\n      return { ...DEFAULT_TEST_CASE_CONFIG, ...testCase };\n    });\n    const finalInvalid = invalid.map((testCase) => ({\n      ...DEFAULT_TEST_CASE_CONFIG,\n      ...testCase,\n    }));\n\n    super.run(ruleName, rule, { valid: finalValid, invalid: finalInvalid });\n  }\n}\n\nexport const createRuleTester = (): RuleTester => {\n  return new StorybookRuleTester();\n};\n\nexport default createRuleTester();\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/types/index.ts",
    "content": "import type { TSESLint } from '@typescript-eslint/utils';\n\nimport type { CategoryId } from '../utils/constants.ts';\n\nexport type RuleModule = TSESLint.RuleModule<'', []> & {\n  meta: { hasSuggestions?: boolean };\n};\n\n// These 2 types are copied from @typescript-eslint/experimental-utils' CreateRuleMeta\n// and modified to our needs\nexport type StorybookRuleMetaDocs = TSESLint.RuleMetaDataDocs & {\n  /** Whether or not this rule should be excluded from linter config */\n  excludeFromConfig?: boolean;\n  /** Which configs the rule should be part of */\n  categories?: CategoryId[];\n};\n\nexport type StorybookRuleMeta<TMessageIds extends string = ''> = TSESLint.RuleMetaData<\n  TMessageIds,\n  StorybookRuleMetaDocs\n> & {\n  /** Severity of the rule to be defined in eslint config */\n  severity: 'off' | 'warn' | 'error';\n};\n\n// Comment out for testing purposes:\n// const docs: StorybookRuleMetaDocs = {\n//   description: 'bla',\n// }\n\n// const meta: StorybookRuleMeta<'someId'> = {\n//   messages: {\n//     someId: 'yea',\n//   },\n//   type: 'problem',\n//   schema: [],\n//   docs,\n//   severity: 'error',\n// }\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/utils/ast.ts",
    "content": "import type { TSESTree } from '@typescript-eslint/utils';\nimport { AST_NODE_TYPES } from '@typescript-eslint/utils';\n\nexport { ASTUtils } from '@typescript-eslint/utils';\n\nconst isNodeOfType =\n  <NodeType extends AST_NODE_TYPES>(nodeType: NodeType) =>\n  (node: TSESTree.Node | null | undefined): node is TSESTree.Node & { type: NodeType } =>\n    node?.type === nodeType;\n\nexport const isAwaitExpression = isNodeOfType(AST_NODE_TYPES.AwaitExpression);\nexport const isIdentifier = isNodeOfType(AST_NODE_TYPES.Identifier);\nexport const isVariableDeclarator = isNodeOfType(AST_NODE_TYPES.VariableDeclarator);\n\nexport const isArrayExpression = isNodeOfType(AST_NODE_TYPES.ArrayExpression);\nexport const isArrowFunctionExpression = isNodeOfType(AST_NODE_TYPES.ArrowFunctionExpression);\nexport const isBlockStatement = isNodeOfType(AST_NODE_TYPES.BlockStatement);\nexport const isCallExpression = isNodeOfType(AST_NODE_TYPES.CallExpression);\nexport const isExpressionStatement = isNodeOfType(AST_NODE_TYPES.ExpressionStatement);\nexport const isVariableDeclaration = isNodeOfType(AST_NODE_TYPES.VariableDeclaration);\nexport const isAssignmentExpression = isNodeOfType(AST_NODE_TYPES.AssignmentExpression);\nexport const isSequenceExpression = isNodeOfType(AST_NODE_TYPES.SequenceExpression);\nexport const isImportDeclaration = isNodeOfType(AST_NODE_TYPES.ImportDeclaration);\nexport const isImportDefaultSpecifier = isNodeOfType(AST_NODE_TYPES.ImportDefaultSpecifier);\nexport const isImportNamespaceSpecifier = isNodeOfType(AST_NODE_TYPES.ImportNamespaceSpecifier);\nexport const isImportSpecifier = isNodeOfType(AST_NODE_TYPES.ImportSpecifier);\nexport const isJSXAttribute = isNodeOfType(AST_NODE_TYPES.JSXAttribute);\nexport const isLiteral = isNodeOfType(AST_NODE_TYPES.Literal);\nexport const isMemberExpression = isNodeOfType(AST_NODE_TYPES.MemberExpression);\nexport const isNewExpression = isNodeOfType(AST_NODE_TYPES.NewExpression);\nexport const isObjectExpression = isNodeOfType(AST_NODE_TYPES.ObjectExpression);\nexport const isObjectPattern = isNodeOfType(AST_NODE_TYPES.ObjectPattern);\nexport const isProperty = isNodeOfType(AST_NODE_TYPES.Property);\nexport const isSpreadElement = isNodeOfType(AST_NODE_TYPES.SpreadElement);\nexport const isRestElement = isNodeOfType(AST_NODE_TYPES.RestElement);\nexport const isReturnStatement = isNodeOfType(AST_NODE_TYPES.ReturnStatement);\nexport const isFunctionDeclaration = isNodeOfType(AST_NODE_TYPES.FunctionDeclaration);\nexport const isFunctionExpression = isNodeOfType(AST_NODE_TYPES.FunctionExpression);\nexport const isProgram = isNodeOfType(AST_NODE_TYPES.Program);\nexport const isTSTypeAliasDeclaration = isNodeOfType(AST_NODE_TYPES.TSTypeAliasDeclaration);\nexport const isTSInterfaceDeclaration = isNodeOfType(AST_NODE_TYPES.TSInterfaceDeclaration);\nexport const isTSAsExpression = isNodeOfType(AST_NODE_TYPES.TSAsExpression);\nexport const isTSSatisfiesExpression = isNodeOfType(AST_NODE_TYPES.TSSatisfiesExpression);\nexport const isTSNonNullExpression = isNodeOfType(AST_NODE_TYPES.TSNonNullExpression);\nexport const isMetaProperty = isNodeOfType(AST_NODE_TYPES.MetaProperty);\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/utils/constants.ts",
    "content": "export enum CategoryId {\n  CSF = 'csf',\n  CSF_STRICT = 'csf-strict',\n  RECOMMENDED = 'recommended',\n  ADDON_INTERACTIONS = 'addon-interactions',\n}\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/utils/create-storybook-rule.ts",
    "content": "import type { TSESLint } from '@typescript-eslint/utils';\nimport { ESLintUtils } from '@typescript-eslint/utils';\n\nimport type { StorybookRuleMeta } from '../types/index.ts';\nimport { docsUrl } from './index.ts';\n\nexport function createStorybookRule<\n  TOptions extends readonly unknown[],\n  TMessageIds extends string,\n  TRuleListener extends TSESLint.RuleListener = TSESLint.RuleListener,\n>({\n  create,\n  meta,\n  ...remainingConfig\n}: Readonly<{\n  name: string;\n  meta: StorybookRuleMeta<TMessageIds>;\n  defaultOptions: TOptions;\n  create: (\n    context: Readonly<TSESLint.RuleContext<TMessageIds, TOptions>>,\n    optionsWithDefault: Readonly<TOptions>\n  ) => TRuleListener;\n}>) {\n  const ruleCreator = ESLintUtils.RuleCreator(docsUrl);\n  return ruleCreator({\n    ...remainingConfig,\n    create,\n    meta: {\n      ...meta,\n      docs: {\n        ...meta.docs!,\n      },\n      defaultOptions: remainingConfig.defaultOptions,\n    },\n  });\n}\n"
  },
  {
    "path": "code/lib/eslint-plugin/src/utils/index.ts",
    "content": "import type { IncludeExcludeOptions } from 'storybook/internal/csf';\nimport { isExportStory } from 'storybook/internal/csf';\n\nimport type { TSESLint, TSESTree } from '@typescript-eslint/utils';\nimport { ASTUtils } from '@typescript-eslint/utils';\n\nimport {\n  isFunctionDeclaration,\n  isIdentifier,\n  isObjectExpression,\n  isSpreadElement,\n  isTSAsExpression,\n  isTSSatisfiesExpression,\n  isVariableDeclaration,\n  isVariableDeclarator,\n} from './ast.ts';\n\nexport const docsUrl = (ruleName: string) =>\n  `https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin/docs/rules/${ruleName}.md`;\n\nexport const getMetaObjectExpression = (\n  node: TSESTree.ExportDefaultDeclaration,\n  context: Readonly<TSESLint.RuleContext<string, readonly unknown[]>>\n) => {\n  let meta: TSESTree.ExportDefaultDeclaration['declaration'] | null = node.declaration;\n  const { sourceCode } = context;\n  if (isIdentifier(meta)) {\n    // Compatibility implementation for eslint v8.x and v9.x or later\n    // see https://eslint.org/blog/2023/09/preparing-custom-rules-eslint-v9/#context.getscope()\n    const scope = sourceCode.getScope ? sourceCode.getScope(node) : context.getScope();\n    const variable = ASTUtils.findVariable(scope, meta.name);\n    const decl = variable && variable.defs.find((def) => isVariableDeclarator(def.node));\n    if (decl && isVariableDeclarator(decl.node)) {\n      meta = decl.node.init;\n    }\n  }\n  if (isTSAsExpression(meta) || isTSSatisfiesExpression(meta)) {\n    meta = meta.expression;\n  }\n\n  return isObjectExpression(meta) ? meta : null;\n};\n\nexport const getDescriptor = (\n  metaDeclaration: TSESTree.ObjectExpression,\n  propertyName: string\n): string[] | RegExp | undefined => {\n  const property =\n    metaDeclaration &&\n    metaDeclaration.properties.find(\n      (p) => 'key' in p && 'name' in p.key && p.key.name === propertyName\n    );\n\n  if (!property || isSpreadElement(property)) {\n    return undefined;\n  }\n\n  const { type } = property.value;\n\n  switch (type) {\n    case 'ArrayExpression':\n      return property.value.elements.map((t) => {\n        if (t === null) {\n          throw new Error(`Unexpected descriptor element: null`);\n        }\n        if (!['StringLiteral', 'Literal'].includes(t.type)) {\n          throw new Error(`Unexpected descriptor element: ${t.type}`);\n        }\n        // @ts-expect-error TODO: t should be only StringLiteral or Literal, and the type is not resolving correctly\n        return t.value;\n      });\n    case 'Literal':\n    // @ts-expect-error TODO: Investigation needed. Type systems says, that \"RegExpLiteral\" does not exist\n    case 'RegExpLiteral':\n      // @ts-expect-error TODO: investigation needed\n      return property.value.value;\n    default:\n      throw new Error(`Unexpected descriptor: ${type}`);\n  }\n};\n\nexport const isValidStoryExport = (\n  node: TSESTree.Identifier,\n  nonStoryExportsConfig: IncludeExcludeOptions\n) => isExportStory(node.name, nonStoryExportsConfig) && node.name !== '__namedExportsOrder';\n\nexport const getAllNamedExports = (node: TSESTree.ExportNamedDeclaration) => {\n  // e.g. `export { MyStory }`\n  if (!node.declaration && node.specifiers) {\n    return node.specifiers.reduce((acc, specifier) => {\n      if (isIdentifier(specifier.exported)) {\n        acc.push(specifier.exported);\n      }\n      return acc;\n    }, [] as TSESTree.Identifier[]);\n  }\n\n  const decl = node.declaration;\n  if (isVariableDeclaration(decl)) {\n    const declaration = decl.declarations[0];\n\n    if (declaration) {\n      const { id } = declaration;\n      // e.g. `export const MyStory`\n      if (isIdentifier(id)) {\n        return [id];\n      }\n    }\n  }\n\n  if (isFunctionDeclaration(decl)) {\n    // e.g. `export function MyStory() {}`\n    if (isIdentifier(decl.id)) {\n      return [decl.id];\n    }\n  }\n\n  return [];\n};\n"
  },
  {
    "path": "code/lib/eslint-plugin/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/lib/eslint-plugin/vitest-setup.ts",
    "content": "import * as vitest from 'vitest';\n\nimport { RuleTester } from '@typescript-eslint/rule-tester';\n\n// https://typescript-eslint.io/packages/rule-tester/#vitest\nRuleTester.afterAll = vitest.afterAll;\nRuleTester.it = vitest.it;\nRuleTester.itOnly = vitest.it.only;\nRuleTester.describe = vitest.describe;\n"
  },
  {
    "path": "code/lib/eslint-plugin/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    test: {\n      setupFiles: ['./vitest-setup.ts'],\n    },\n  })\n);\n"
  },
  {
    "path": "code/lib/eslint-plugin/vitest.integration.config.ts",
    "content": "import { defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n  test: {\n    include: ['**/tests/**/*.spec.ts'],\n    environment: 'node',\n    globals: true,\n    testTimeout: 60000,\n  },\n});\n"
  },
  {
    "path": "code/lib/react-dom-shim/README.md",
    "content": "# React Dom Shim\n\nA shim for `react-dom` that provides a single API that will work whether the user is on `react-dom@17` or `react-dom@18`, as well as webpack/vite config necessary to make that work.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/lib/react-dom-shim/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/react-18.tsx',\n      },\n      {\n        exportEntries: ['./react-16'],\n        entryPoint: './src/react-16.tsx',\n        dts: false,\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/lib/react-dom-shim/package.json",
    "content": "{\n  \"name\": \"@storybook/react-dom-shim\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"\",\n  \"keywords\": [\n    \"storybook\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/lib/react-dom-shim\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/lib/react-dom-shim\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"sideEffects\": false,\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/react-18.d.ts\",\n      \"code\": \"./src/react-18.tsx\",\n      \"default\": \"./dist/react-18.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\",\n    \"./react-16\": \"./dist/react-16.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"devDependencies\": {\n    \"typescript\": \"^5.8.3\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"storybook\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/lib/react-dom-shim/project.json",
    "content": "{\n  \"name\": \"react-dom-shim\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/lib/react-dom-shim/src/preset.ts",
    "content": "import { readFile } from 'node:fs/promises';\nimport { isAbsolute, join } from 'node:path';\n\nimport type { Options } from 'storybook/internal/types';\n\nimport { resolvePackageDir } from '../../../core/src/shared/utils/module.ts';\n\n/**\n * Get react-dom version from the resolvedReact preset, which points to either a root react-dom\n * dependency or the react-dom dependency shipped with addon-docs\n */\nconst getIsReactVersion18or19 = async (options: Options) => {\n  const { legacyRootApi } =\n    (await options.presets.apply<{ legacyRootApi?: boolean } | null>('frameworkOptions')) || {};\n\n  if (legacyRootApi) {\n    return false;\n  }\n\n  const resolvedReact = await options.presets.apply<{ reactDom?: string }>('resolvedReact', {});\n  const reactDom = resolvedReact.reactDom || resolvePackageDir('react-dom');\n\n  if (!isAbsolute(reactDom)) {\n    // if react-dom is not resolved to a file we can't be sure if the version in package.json is correct or even if package.json exists\n    // this happens when react-dom is resolved to 'preact/compat' for example\n    return false;\n  }\n\n  const { version } = JSON.parse(await readFile(join(reactDom, 'package.json'), 'utf-8'));\n  return version.startsWith('18') || version.startsWith('19') || version.startsWith('0.0.0');\n};\n\nexport const webpackFinal = async (config: any, options: Options) => {\n  const isReactVersion18 = await getIsReactVersion18or19(options);\n  if (isReactVersion18) {\n    return config;\n  }\n\n  return {\n    ...config,\n    resolve: {\n      ...config.resolve,\n      alias: {\n        ...config.resolve?.alias,\n        '@storybook/react-dom-shim': '@storybook/react-dom-shim/react-16',\n      },\n    },\n  };\n};\n\nexport const viteFinal = async (config: any, options: Options) => {\n  const isReactVersion18 = await getIsReactVersion18or19(options);\n\n  const optimizeDeps = {\n    ...(config?.optimizeDeps ?? {}),\n    include: [\n      ...(config.optimizeDeps?.include || []),\n      ...(isReactVersion18 ? ['react-dom/client'] : []),\n    ],\n  };\n\n  if (isReactVersion18) {\n    return {\n      ...config,\n      optimizeDeps,\n    };\n  }\n\n  const alias = Array.isArray(config.resolve?.alias)\n    ? config.resolve.alias.concat({\n        find: /^@storybook\\/react-dom-shim$/,\n        replacement: '@storybook/react-dom-shim/react-16',\n      })\n    : {\n        ...config.resolve?.alias,\n        '@storybook/react-dom-shim': '@storybook/react-dom-shim/react-16',\n      };\n\n  return {\n    ...config,\n    optimizeDeps,\n    resolve: {\n      ...config.resolve,\n      alias,\n    },\n  };\n};\n"
  },
  {
    "path": "code/lib/react-dom-shim/src/react-16.tsx",
    "content": "/* eslint-disable react/no-deprecated */\nimport type { ReactElement } from 'react';\nimport * as ReactDOM from 'react-dom';\n\nexport const renderElement = async (node: ReactElement, el: Element) => {\n  return new Promise<null>((resolve) => {\n    ReactDOM.render(node, el, () => resolve(null));\n  });\n};\n\nexport const unmountElement = (el: Element) => {\n  ReactDOM.unmountComponentAtNode(el);\n};\n"
  },
  {
    "path": "code/lib/react-dom-shim/src/react-18.tsx",
    "content": "/* eslint-disable @typescript-eslint/no-unnecessary-type-constraint */\nimport type { ReactElement } from 'react';\nimport * as React from 'react';\nimport type { Root as ReactRoot, RootOptions } from 'react-dom/client';\nimport * as ReactDOM from 'react-dom/client';\n\n// A map of all rendered React 18 nodes\nconst nodes = new Map<Element, ReactRoot>();\n\ndeclare const globalThis: {\n  IS_REACT_ACT_ENVIRONMENT: boolean;\n};\n\nfunction getIsReactActEnvironment() {\n  return globalThis.IS_REACT_ACT_ENVIRONMENT;\n}\n\nconst WithCallback: React.FC<{ callback: () => void; children: ReactElement }> = ({\n  callback,\n  children,\n}) => {\n  // See https://github.com/reactwg/react-18/discussions/5#discussioncomment-2276079\n  const once = React.useRef<() => void>();\n  React.useLayoutEffect(() => {\n    if (once.current === callback) {\n      return;\n    }\n    once.current = callback;\n    callback();\n  }, [callback]);\n\n  return children;\n};\n\n// pony-fill\nif (typeof Promise.withResolvers === 'undefined') {\n  Promise.withResolvers = <T extends unknown>() => {\n    let resolve: PromiseWithResolvers<T>['resolve'] = null!;\n    let reject: PromiseWithResolvers<T>['reject'] = null!;\n    const promise = new Promise<T>((res, rej) => {\n      resolve = res;\n      reject = rej;\n    });\n    return { promise, resolve, reject };\n  };\n}\n\nexport const renderElement = async (node: ReactElement, el: Element, rootOptions?: RootOptions) => {\n  // Create Root Element conditionally for new React 18 Root Api\n  const root = await getReactRoot(el, rootOptions);\n\n  if (getIsReactActEnvironment()) {\n    root.render(node);\n    return;\n  }\n\n  const { promise, resolve } = Promise.withResolvers<void>();\n  root.render(<WithCallback callback={resolve}>{node}</WithCallback>);\n  return promise;\n};\n\nexport const unmountElement = (el: Element, shouldUseNewRootApi?: boolean) => {\n  const root = nodes.get(el);\n\n  if (root) {\n    root.unmount();\n    nodes.delete(el);\n  }\n};\n\nconst getReactRoot = async (el: Element, rootOptions?: RootOptions): Promise<ReactRoot> => {\n  let root = nodes.get(el);\n\n  if (!root) {\n    root = ReactDOM.createRoot(el, rootOptions);\n    nodes.set(el, root);\n  }\n\n  return root;\n};\n"
  },
  {
    "path": "code/lib/react-dom-shim/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/package.json",
    "content": "{\n  \"name\": \"@storybook/code\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"private\": true,\n  \"description\": \"Storybook root\",\n  \"homepage\": \"https://storybook.js.org/\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"scripts\": {\n    \"await-serve-storybooks\": \"wait-on http://localhost:8001\",\n    \"build\": \"NODE_ENV=production yarn --cwd ../scripts build-package\",\n    \"changelog\": \"pr-log --sloppy --cherry-pick\",\n    \"changelog:next\": \"pr-log --sloppy --since-prerelease\",\n    \"check\": \"NODE_ENV=production yarn --cwd ../scripts check-package\",\n    \"ci-tests\": \"yarn task --task check --no-link --start-from=install && yarn lint && cd .. && yarn test\",\n    \"danger\": \"danger\",\n    \"generate-sandboxes\": \"yarn --cwd ../scripts generate-sandboxes\",\n    \"github-release\": \"github-release-from-changelog\",\n    \"i\": \"yarn --cwd .. i\",\n    \"knip\": \"knip --config ../scripts/knip.config.ts\",\n    \"lint\": \"yarn lint:js\",\n    \"lint:ejs\": \"ejslint **/*.ejs\",\n    \"lint:js\": \"yarn lint:js:cmd . --quiet\",\n    \"lint:js:cmd\": \"cross-env NODE_ENV=production eslint --cache --cache-location=../.cache/eslint --ext .js,.jsx,.json,.html,.ts,.tsx,.mjs --report-unused-disable-directives\",\n    \"lint:package\": \"yarn --cwd ../scripts lint:package\",\n    \"local-registry\": \"yarn --cwd ../scripts local-registry\",\n    \"publish-sandboxes\": \"yarn --cwd ../scripts publish\",\n    \"storybook:ui\": \"NODE_OPTIONS=\\\"--max_old_space_size=4096 --trace-deprecation\\\" core/dist/bin/dispatcher.js dev --port 6006 --config-dir ./.storybook\",\n    \"storybook:ui:build\": \"NODE_OPTIONS=\\\"--max_old_space_size=5120\\\" core/dist/bin/dispatcher.js build --config-dir ./.storybook --webpack-stats-json\",\n    \"storybook:ui:chromatic\": \"chromatic --storybook-build-dir storybook-static --exit-zero-on-changes --exit-once-uploaded\",\n    \"task\": \"yarn --cwd ../scripts task\"\n  },\n  \"browserslist\": [\n    \"chrome >= 131\",\n    \"android >= 131\",\n    \"and_chr >= 131\",\n    \"edge >= 134\",\n    \"firefox >= 136\",\n    \"safari >= 18.3\",\n    \"ios_saf >= 18.3\",\n    \"opera >= 117\",\n    \"node >= 20\"\n  ],\n  \"dependencies\": {\n    \"@chromatic-com/storybook\": \"^5.0.0\",\n    \"@playwright/test\": \"1.58.2\",\n    \"@storybook/addon-a11y\": \"workspace:*\",\n    \"@storybook/addon-designs\": \"^11.0.3\",\n    \"@storybook/addon-docs\": \"workspace:*\",\n    \"@storybook/addon-links\": \"workspace:*\",\n    \"@storybook/addon-onboarding\": \"workspace:*\",\n    \"@storybook/addon-themes\": \"workspace:*\",\n    \"@storybook/addon-vitest\": \"workspace:*\",\n    \"@storybook/angular\": \"workspace:*\",\n    \"@storybook/builder-vite\": \"workspace:*\",\n    \"@storybook/builder-webpack5\": \"workspace:*\",\n    \"@storybook/codemod\": \"workspace:*\",\n    \"@storybook/core-webpack\": \"workspace:*\",\n    \"@storybook/csf-plugin\": \"workspace:*\",\n    \"@storybook/ember\": \"workspace:*\",\n    \"@storybook/global\": \"^5.0.0\",\n    \"@storybook/html\": \"workspace:*\",\n    \"@storybook/html-vite\": \"workspace:*\",\n    \"@storybook/nextjs\": \"workspace:*\",\n    \"@storybook/preact\": \"workspace:*\",\n    \"@storybook/preact-vite\": \"workspace:*\",\n    \"@storybook/preset-create-react-app\": \"workspace:*\",\n    \"@storybook/preset-react-webpack\": \"workspace:*\",\n    \"@storybook/preset-server-webpack\": \"workspace:*\",\n    \"@storybook/react\": \"workspace:*\",\n    \"@storybook/react-vite\": \"workspace:*\",\n    \"@storybook/react-webpack5\": \"workspace:*\",\n    \"@storybook/server\": \"workspace:*\",\n    \"@storybook/server-webpack5\": \"workspace:*\",\n    \"@storybook/svelte\": \"workspace:*\",\n    \"@storybook/vue3\": \"workspace:*\",\n    \"@storybook/vue3-vite\": \"workspace:*\",\n    \"@storybook/web-components\": \"workspace:*\",\n    \"@storybook/web-components-vite\": \"workspace:*\",\n    \"@testing-library/dom\": \"^10.4.0\",\n    \"@testing-library/jest-dom\": \"^6.9.1\",\n    \"@testing-library/react\": \"^16.2.0\",\n    \"@testing-library/user-event\": \"patch:@testing-library/user-event@npm%3A14.6.1#~/.yarn/patches/@testing-library-user-event-npm-14.6.1-5da7e1d4e2.patch\",\n    \"@types/lodash-es\": \"^4.17.12\",\n    \"@types/mock-require\": \"^2.0.3\",\n    \"@types/node\": \"^22.19.1\",\n    \"@types/react\": \"^18.0.37\",\n    \"@types/react-dom\": \"^18.0.11\",\n    \"@vitejs/plugin-react\": \"^4.3.2\",\n    \"@vitejs/plugin-vue\": \"^4.4.0\",\n    \"@vitest/browser\": \"^4.1.0\",\n    \"@vitest/browser-playwright\": \"^4.1.0\",\n    \"@vitest/coverage-istanbul\": \"^4.1.0\",\n    \"@vitest/coverage-v8\": \"^4.1.0\",\n    \"chromatic\": \"^13.3.4\",\n    \"create-storybook\": \"workspace:*\",\n    \"cross-env\": \"^7.0.3\",\n    \"danger\": \"^13.0.4\",\n    \"es-toolkit\": \"^1.43.0\",\n    \"esbuild\": \"^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0\",\n    \"esbuild-loader\": \"^4.3.0\",\n    \"eslint\": \"^8.57.1\",\n    \"happy-dom\": \"^17.6.3\",\n    \"http-server\": \"^14.1.1\",\n    \"knip\": \"^5.70.2\",\n    \"mock-require\": \"^3.0.3\",\n    \"prettier\": \"^3.7.1\",\n    \"process\": \"^0.11.10\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-popper-tooltip\": \"^4.4.2\",\n    \"slash\": \"^5.0.0\",\n    \"sort-package-json\": \"^3.5.0\",\n    \"storybook\": \"workspace:^\",\n    \"storybook-addon-pseudo-states\": \"workspace:*\",\n    \"ts-dedent\": \"^2.0.0\",\n    \"typescript\": \"^5.9.3\",\n    \"uuid\": \"^11.1.0\",\n    \"vite\": \"^7.0.4\",\n    \"vite-plugin-inspect\": \"^11.0.0\",\n    \"vitest\": \"^4.1.0\",\n    \"wait-on\": \"^8.0.3\"\n  },\n  \"devDependencies\": {\n    \"oxfmt\": \"^0.41.0\"\n  },\n  \"dependenciesMeta\": {\n    \"ejs\": {\n      \"built\": false\n    },\n    \"level\": {\n      \"built\": false\n    },\n    \"node-uuid\": {\n      \"built\": false,\n      \"unplugged\": false\n    },\n    \"nodemon\": {\n      \"built\": false\n    },\n    \"parcel\": {\n      \"built\": false\n    },\n    \"preact\": {\n      \"built\": false\n    },\n    \"yorkie\": {\n      \"built\": false\n    }\n  },\n  \"collective\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"nx\": {\n    \"includedScripts\": []\n  },\n  \"pr-log\": {\n    \"skipLabels\": [\n      \"cleanup\"\n    ],\n    \"validLabels\": [\n      [\n        \"BREAKING CHANGE\",\n        \"Breaking Changes\"\n      ],\n      [\n        \"feature request\",\n        \"Features\"\n      ],\n      [\n        \"bug\",\n        \"Bug Fixes\"\n      ],\n      [\n        \"documentation\",\n        \"Documentation\"\n      ],\n      [\n        \"maintenance\",\n        \"Maintenance\"\n      ],\n      [\n        \"build\",\n        \"Build\"\n      ],\n      [\n        \"dependencies\",\n        \"Dependency Upgrades\"\n      ]\n    ]\n  }\n}\n"
  },
  {
    "path": "code/playwright.config.ts",
    "content": "import { defineConfig, devices } from '@playwright/test';\n\n/** Read environment variables from file. https://github.com/motdotla/dotenv */\n// require('dotenv').config();\n\n// Comment this out and fill in the values to run E2E tests locally using the Playwright extension easily\n// process.env.STORYBOOK_URL = 'http://localhost:6006';\n// process.env.STORYBOOK_TEMPLATE_NAME = 'react-vite/default-ts';\n\n/** See https://playwright.dev/docs/test-configuration. */\nexport default defineConfig({\n  testDir: './e2e-tests',\n  /* Maximum time one test can run for. */\n  timeout: 30 * 1000,\n  expect: {\n    /**\n     * Maximum time expect() should wait for the condition to be met. For example in `await\n     * expect(locator).toHaveText();`\n     */\n    timeout: 5000,\n  },\n  /* Run tests in files in parallel */\n  fullyParallel: true,\n  /* Fail the build on CI if you accidentally left test.only in the source code. */\n  forbidOnly: !!process.env.CI,\n  /* Retry on CI only */\n  retries: process.env.CI ? 2 : 0,\n  /* Opt out of parallel tests on CI. */\n  workers: process.env.CI ? 1 : undefined,\n  /* Reporter to use. See https://playwright.dev/docs/test-reporters */\n  reporter: process.env.PLAYWRIGHT_JUNIT_OUTPUT_NAME\n    ? [\n        [\n          'junit',\n          {\n            embedAnnotationsAsProperties: true,\n            outputFile: process.env.PLAYWRIGHT_JUNIT_OUTPUT_NAME,\n          },\n        ],\n      ]\n    : 'html',\n  /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */\n  use: {\n    /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */\n    actionTimeout: 0,\n    /* Base URL to use in actions like `await page.goto('/')`. */\n    // baseURL: 'http://localhost:3000',\n\n    /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */\n    trace: 'retain-on-failure',\n  },\n\n  /* Configure projects for major browsers */\n  projects: [\n    {\n      // Playwright recommends project dependencies over globalSetup when setup needs runner features\n      // like fixtures, traces, and retries:\n      // https://playwright.dev/docs/test-global-setup-teardown\n      name: 'setup',\n      testMatch: /.*\\.setup\\.ts/,\n    },\n    {\n      name: 'chromium',\n      dependencies: ['setup'],\n      use: {\n        ...devices['Desktop Chrome'],\n        permissions: ['clipboard-read', 'clipboard-write'],\n      },\n    },\n\n    // {\n    //   name: 'firefox',\n    //   use: {\n    //     ...devices['Desktop Firefox'],\n    //   },\n    // },\n\n    // {\n    //   name: 'webkit',\n    //   use: {\n    //     ...devices['Desktop Safari'],\n    //   },\n    // },\n\n    /* Test against mobile viewports. */\n    // {\n    //   name: 'Mobile Chrome',\n    //   use: {\n    //     ...devices['Pixel 5'],\n    //   },\n    // },\n    // {\n    //   name: 'Mobile Safari',\n    //   use: {\n    //     ...devices['iPhone 12'],\n    //   },\n    // },\n\n    /* Test against branded browsers. */\n    // {\n    //   name: 'Microsoft Edge',\n    //   use: {\n    //     channel: 'msedge',\n    //   },\n    // },\n    // {\n    //   name: 'Google Chrome',\n    //   use: {\n    //     channel: 'chrome',\n    //   },\n    // },\n  ],\n\n  /* Folder for test artifacts such as screenshots, videos, traces, etc. */\n  outputDir: 'playwright-results/',\n\n  /* Run your local dev server before starting the tests */\n  // webServer: {\n  //   command: 'npm run start',\n  //   port: 3000,\n  // },\n});\n"
  },
  {
    "path": "code/presets/create-react-app/CHANGELOG.md",
    "content": "## 4.1.2\n\n- Use overrides from SB rather than defining ourselves [#254](https://github.com/storybookjs/presets/pull/254)\n\n## 4.1.1\n\n- Update peer dependencies and add a note about versions [#252](https://github.com/storybookjs/presets/pull/252)\n\n## 4.1.0\n\n- Add support for builder.core options to CRA preset [#240](https://github.com/storybookjs/presets/pull/240)\n\n## 4.0.2\n\n- Fix bug merging core presets [#238](https://github.com/storybookjs/presets/pull/238) [#239](https://github.com/storybookjs/presets/pull/239)\n\n## 4.0.1\n\n- Support CJS files using Storybook's config [#229](https://github.com/storybookjs/presets/pull/229)\n\n## 4.0.0\n\n- CRA: Add compatibility for CRA v5 [#214](https://github.com/storybookjs/presets/pull/214)\n\n## 3.2.0\n\n- Add disableWebpackDefaults for forward-compatibility with SB core\n\n## 3.1.7\n\n- CRA: Fix fast refresh config [#193](https://github.com/storybookjs/presets/pull/193)\n\n## 3.1.6\n\n- Fix monorepos and PnP [#181](https://github.com/storybookjs/presets/pull/181)\n\n## 3.1.5\n\n- Fix duplicate ReactDocgenTypescriptPlugin [#173](https://github.com/storybookjs/presets/pull/173)\n- Bump react-docgen-typescript-plugin to 0.6.2 [#174](https://github.com/storybookjs/presets/pull/174)\n\n## 3.1.4\n\n- Upgrade react-docgen-typescript-plugin to 0.5.x [#158](https://github.com/storybookjs/presets/pull/158)\n\n## 3.1.3\n\n- Move node-logger to peer deps [#156](https://github.com/storybookjs/presets/pull/156)\n\n## 3.1.2\n\n- Restore node@10 compatibility [#154](https://github.com/storybookjs/presets/pull/154)\n\n## 3.1.1\n\n- Fix react-docgen-typescript-plugin deps [#151](https://github.com/storybookjs/presets/pull/151)\n\n## 3.1.0\n\n- Move to react-docgen-typescript-plugin [#149](https://github.com/storybookjs/presets/pull/149)\n\n## 3.0.1\n\n- Ignore default babel Config from Storybook [#147](https://github.com/storybookjs/presets/pull/147)\n\n## 3.0.0\n\nReverse course on typescript docgen handling [#142](https://github.com/storybookjs/presets/pull/142)\n\n- Add back `react-docgen-typescript-loader` to the preset\n- Add compatibility with SB6's main.js `typescript` setting\n\n## 2.1.2\n\n- Make `@storybook/node-logger` dependency less strict [#138](https://github.com/storybookjs/presets/pull/138)\n\n## 2.1.1\n\n- Set PUBLIC_URL if not set [#104](https://github.com/storybookjs/presets/pull/104)\n\n## 2.1.0\n\n- Yarn PNP compatibility [#104](https://github.com/storybookjs/presets/pull/104)\n\n## 2.0.0\n\n- Remove `react-docgen-typescript-loader` from the preset [#103](https://github.com/storybookjs/presets/pull/103)\n\nStarting in `v5.x`, `react-docgen` supports typescript natively, so we no longer recommend `react-docgen-typescript-loader` and have removed it from the preset. This is a breaking change and the migration is documented in [Storybook](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#react-prop-tables-with-typescript).\n"
  },
  {
    "path": "code/presets/create-react-app/README.md",
    "content": "# Create React App preset for Storybook\n\nOne-line [Create React App](https://github.com/facebook/create-react-app) configuration for Storybook.\n\nThis preset is designed to use alongside [`@storybook/react`](https://github.com/storybookjs/storybook/tree/master/app/react).\n\n## Compatibility\n\nFrom version 4.0.0 onwards, the `@storybook/preset-create-react-app` is compatible with Create React App version 5 and later. If you're using an earlier version of Create React App, you can still utilize the preset's previous versions.\n\n## Basic usage\n\n**Note: you don't need to do this manually** if you used `npx -p @storybook/cli sb init` on a create-react-app, everything should properly setup already ✅.\n\nFirst, install this preset to your project.\n\n```sh\n# Yarn\nyarn add -D @storybook/preset-create-react-app\n\n# npm\nnpm install -D @storybook/preset-create-react-app\n```\n\nOnce installed, add this preset to the appropriate file:\n\n- `./.storybook/main.js` (for Storybook 5.3.0 and newer)\n\n  ```js\n  module.exports = {\n    addons: ['@storybook/preset-create-react-app'],\n  };\n  ```\n\n- `./.storybook/presets.js` (for all Storybook versions)\n\n  ```js\n  module.exports = ['@storybook/preset-create-react-app'];\n  ```\n\n## Advanced usage\n\n### Usage with Docs\n\nWhen working with Storybook Docs, simply add the following config to your `main.js` file.\n\n```js\nmodule.exports = {\n  addons: [\n    '@storybook/preset-create-react-app',\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        configureJSX: true,\n      },\n    },\n  ],\n};\n```\n\n### CRA overrides\n\nThis preset uses CRA's Webpack/Babel configurations, so that Storybook's behavior matches your app's behavior.\n\nHowever, there may be some cases where you'd rather override CRA's default behavior. If that is something you need, you can use the `craOverrides` object.\n\n| Option               | Default          | Behaviour | Type       | Description                                                                                                        |\n| -------------------- | ---------------- | --------- | ---------- | ------------------------------------------------------------------------------------------------------------------ |\n| `fileLoaderExcludes` | `['ejs', 'mdx']` | Extends   | `string[]` | Excludes file types (by extension) from CRA's `file-loader` configuration. The defaults are required by Storybook. |\n\nHere's how you might configure this preset to ignore PDF files so they can be processed by another preset or loader:\n\n```js\nmodule.exports = {\n  addons: [\n    {\n      name: '@storybook/preset-create-react-app',\n      options: {\n        craOverrides: {\n          fileLoaderExcludes: ['pdf'],\n        },\n      },\n    },\n  ],\n};\n```\n\n### Custom `react-scripts` packages\n\nIn most cases, this preset will find your `react-scripts` package, even if it's a fork of the official `react-scripts`.\n\nIn the event that it doesn't, you can set the package's name with `scriptsPackageName`.\n\n```js\nmodule.exports = {\n  addons: [\n    {\n      name: '@storybook/preset-create-react-app',\n      options: {\n        scriptsPackageName: '@my/react-scripts',\n      },\n    },\n  ],\n};\n```\n\n### Warning for forks of 'react-scripts'\n\nOne of the tasks that this preset does is inject the storybook config directory (the default is `.storybook`)\ninto the `includes` key of the webpack babel-loader config that react-scripts (or your fork) provides. This is\nnice because then any components/code you've defined in your storybook config directory will be run through the\nbabel-loader as well.\n\nThe potential gotcha exists if you have tweaked the Conditions of the webpack babel-loader rule in your fork of\nreact-scripts. This preset will make the `include` condition an array (if not already), and inject the storybook\nconfig directory. If you have changed the conditions to utilize an `exclude`, then BOTH conditions will need to\nbe true (which isn't likely going to work as expected).\n\nThe steps to remedy this would be to follow the steps for customizing the webpack config within the storybook\nside of things. [Details for storybook custom webpack config](https://storybook.js.org/docs/configurations/custom-webpack-config/?ref=readme)\nYou'll have access to all of the rules in `config.module.rules`. You'll need to find the offending rule,\nand customize it how you need it to be to be compatible with your fork.\n\nSee [Webpack Rule Conditions](https://webpack.js.org/configuration/module/#rule-conditions) for more details\nconcerning the conditions.\n\n## Resources\n\n- [Walkthrough to set up Storybook Docs with CRA & typescript](https://gist.github.com/shilman/bc9cbedb2a7efb5ec6710337cbd20c0c)\n- [Example projects (used for testing this preset)](https://github.com/storybookjs/presets/tree/master/examples)\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/presets/create-react-app/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    node: [\n      {\n        exportEntries: ['./index', './preset'],\n        entryPoint: './src/index.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/presets/create-react-app/package.json",
    "content": "{\n  \"name\": \"@storybook/preset-create-react-app\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook for Create React App preset\",\n  \"keywords\": [\n    \"storybook\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/presets/create-react-app\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/presets/create-react-app\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \"./index\": \"./dist/index.js\",\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/index.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@pmmmwh/react-refresh-webpack-plugin\": \"^0.5.1\",\n    \"@storybook/react-docgen-typescript-plugin\": \"1.0.6--canary.9.0c3f3b7.0\",\n    \"@types/semver\": \"^7.7.1\",\n    \"pnp-webpack-plugin\": \"^1.7.0\",\n    \"semver\": \"^7.7.3\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.19.1\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"react-scripts\": \">=5.0.0\",\n    \"storybook\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/presets/create-react-app/preset.js",
    "content": "export * from './dist/index.js';\n"
  },
  {
    "path": "code/presets/create-react-app/project.json",
    "content": "{\n  \"name\": \"create-react-app\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/presets/create-react-app/src/helpers/checkPresets.ts",
    "content": "import { logger } from 'storybook/internal/node-logger';\n\nimport type { PluginOptions } from '../types.ts';\n\nconst incompatiblePresets = ['@storybook/preset-scss', '@storybook/preset-typescript'];\n\nexport const checkPresets = (options: PluginOptions): void => {\n  const { presetsList } = options;\n\n  presetsList?.forEach((preset: string | { name: string }) => {\n    const presetName = typeof preset === 'string' ? preset : preset.name;\n    if (incompatiblePresets.includes(presetName)) {\n      logger.warn(\n        `\\`${presetName}\\` may not be compatible with \\`@storybook/preset-create-react-app\\``\n      );\n    }\n  });\n};\n"
  },
  {
    "path": "code/presets/create-react-app/src/helpers/getModulePath.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\n\ninterface PartialTSConfig {\n  compilerOptions: {\n    baseUrl?: string;\n  };\n}\n\nconst JSCONFIG = 'jsconfig.json';\nconst TSCONFIG = 'tsconfig.json';\n\nexport const getModulePath = (appDirectory: string): string[] => {\n  // CRA only supports `jsconfig.json` if `tsconfig.json` doesn't exist.\n  let configName = '';\n  if (existsSync(join(appDirectory, TSCONFIG))) {\n    configName = TSCONFIG;\n  } else if (existsSync(join(appDirectory, JSCONFIG))) {\n    configName = JSCONFIG;\n  }\n\n  try {\n    const { baseUrl } = (require(join(appDirectory, configName)) as PartialTSConfig)\n      .compilerOptions;\n    return (baseUrl ? [baseUrl] : []) as string[];\n  } catch (e) {\n    return [];\n  }\n};\n"
  },
  {
    "path": "code/presets/create-react-app/src/helpers/getReactScriptsPath.ts",
    "content": "import { lstatSync, readFileSync, realpathSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { resolvePackageDir } from '../../../../core/src/shared/utils/module.ts';\n\nexport const getReactScriptsPath = (): string => {\n  const cwd = process.cwd();\n  const scriptsBinPath = join(cwd, '/node_modules/.bin/react-scripts');\n\n  if (process.platform === 'win32') {\n    /*\n     * Try to find the scripts package on Windows by following the `react-scripts` CMD file.\n     * https://github.com/storybookjs/storybook/issues/5801\n     */\n    try {\n      const content = readFileSync(scriptsBinPath, 'utf8');\n\n      const packagePathMatch = content.match(\n        /\"\\$basedir[\\\\/](\\S+?)[\\\\/]bin[\\\\/]react-scripts\\.js\"/i\n      );\n\n      if (packagePathMatch && packagePathMatch.length > 1) {\n        const scriptsPath = join(cwd, '/node_modules/.bin/', packagePathMatch[1]);\n        return scriptsPath;\n      }\n    } catch (e) {\n      // NOOP\n    }\n  } else {\n    /*\n     * Try to find the scripts package by following the `react-scripts` symlink.\n     * This won't work for Windows users, unless within WSL.\n     */\n    try {\n      const scriptsBinPathStat = lstatSync(scriptsBinPath);\n      if (scriptsBinPathStat.isSymbolicLink() === true) {\n        const resolvedBinPath = realpathSync(scriptsBinPath);\n        const scriptsPath = join(resolvedBinPath, '..', '..');\n        return scriptsPath;\n      }\n      if (scriptsBinPathStat.isFile() === true) {\n        const scriptsPath = join(cwd, '/node_modules/react-scripts');\n        return scriptsPath;\n      }\n    } catch (e) {\n      // NOOP\n    }\n  }\n\n  /*\n   * Try to find the `react-scripts` package by name (won't catch forked scripts packages).\n   */\n  try {\n    const scriptsPath = resolvePackageDir('react-scripts');\n    return scriptsPath;\n  } catch (e) {\n    // NOOP\n  }\n\n  return '';\n};\n"
  },
  {
    "path": "code/presets/create-react-app/src/helpers/mergePlugins.ts",
    "content": "import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';\nimport type { Configuration, WebpackPluginInstance } from 'webpack';\n\nexport const mergePlugins = (...args: WebpackPluginInstance[]): Configuration['plugins'] =>\n  args?.reduce((plugins, plugin) => {\n    if (\n      plugins?.some(\n        (includedPlugin: WebpackPluginInstance) =>\n          includedPlugin?.constructor.name === plugin?.constructor.name\n      ) ||\n      plugin?.constructor.name === 'WebpackManifestPlugin'\n    ) {\n      return plugins;\n    }\n    let updatedPlugin = plugin;\n    if (plugin?.constructor.name === 'ReactRefreshPlugin') {\n      // Storybook uses webpack-hot-middleware\n      // https://github.com/storybookjs/presets/issues/177\n\n      updatedPlugin = new ReactRefreshWebpackPlugin({\n        overlay: {\n          sockIntegration: 'whm',\n        },\n      });\n    }\n    return [...(plugins ?? []), updatedPlugin];\n  }, [] as WebpackPluginInstance[]);\n"
  },
  {
    "path": "code/presets/create-react-app/src/helpers/processCraConfig.ts",
    "content": "import { resolve } from 'node:path';\n\nimport type { PluginItem, TransformOptions } from '@babel/core';\nimport semver from 'semver';\nimport type { Configuration, RuleSetCondition, RuleSetRule } from 'webpack';\n\nimport type { PluginOptions } from '../types.ts';\n\ntype RuleSetConditions = RuleSetCondition[];\n\nconst isRegExp = (value: RegExp | unknown): value is RegExp => value instanceof RegExp;\n\nconst isString = (value: string | unknown): value is string => typeof value === 'string';\n\n// This handles arrays in Webpack rule tests.\nconst testMatch = (rule: RuleSetRule, string: string): boolean => {\n  if (!rule.test) {\n    return false;\n  }\n  return Array.isArray(rule.test)\n    ? rule.test.some((test) => isRegExp(test) && test.test(string))\n    : isRegExp(rule.test) && rule.test.test(string);\n};\n\nexport const processCraConfig = async (\n  craWebpackConfig: Configuration,\n  options: PluginOptions\n): Promise<RuleSetRule[]> => {\n  const configDir = resolve(options.configDir);\n\n  /*\n   * NOTE: As of version 5.3.0 of Storybook, Storybook's default loaders are no\n   * longer appended when using this preset, meaning less customisation is\n   * needed when used alongside that version.\n   *\n   * When loaders were appended in previous Storybook versions, some CRA loaders\n   * had to be disabled or modified to avoid conflicts.\n   *\n   * See: https://github.com/storybookjs/storybook/pull/9157\n   */\n  const storybookVersion = semver.coerce(options.packageJson?.version) || '';\n  const isStorybook530 = semver.gte(storybookVersion, '5.3.0');\n  const babelOptions = await options.presets.apply('babel');\n\n  if (!craWebpackConfig?.module?.rules) {\n    return [];\n  }\n\n  return craWebpackConfig.module.rules.reduce((rules, rule): RuleSetRule[] => {\n    const { oneOf, include } = rule as RuleSetRule;\n\n    // Add our `configDir` to support JSX and TypeScript in that folder.\n    if (testMatch(rule as RuleSetRule, '.jsx')) {\n      const newRule = {\n        ...(rule as RuleSetRule),\n        include: [include as string, configDir].filter(Boolean),\n      };\n      return [...rules, newRule];\n    }\n\n    /*\n     * CRA makes use of Webpack's `oneOf` feature.\n     * https://webpack.js.org/configuration/module/#ruleoneof\n     *\n     * Here, we map over those rules and add our `configDir` as above.\n     */\n    if (oneOf) {\n      return [\n        ...rules,\n        {\n          // @ts-expect-error (broken typings from webpack)\n          oneOf: oneOf.map((oneOfRule: RuleSetRule): RuleSetRule => {\n            if (oneOfRule.type === 'asset/resource') {\n              if (isStorybook530) {\n                const excludes = [\n                  'ejs', // Used within Storybook.\n                  'md', // Used with Storybook Notes.\n                  'mdx', // Used with Storybook Docs.\n                  'cjs', // Used for CommonJS modules.\n                  ...(options.craOverrides?.fileLoaderExcludes || []),\n                ];\n                const excludeRegex = new RegExp(`\\\\.(${excludes.join('|')})$`);\n                return {\n                  ...oneOfRule,\n\n                  exclude: [...(oneOfRule.exclude as RuleSetConditions), excludeRegex],\n                };\n              }\n              return {};\n            }\n\n            // This rule causes conflicts with Storybook addons like `addon-info`.\n            if (testMatch(oneOfRule, '.css')) {\n              return {\n                ...oneOfRule,\n                include: isStorybook530 ? undefined : [configDir],\n                exclude: [oneOfRule.exclude as RegExp, /@storybook/],\n              };\n            }\n\n            // Used for the next two rules modifications.\n            const isBabelLoader =\n              isString(oneOfRule.loader) && /[/\\\\]babel-loader[/\\\\]/.test(oneOfRule.loader);\n\n            // Target `babel-loader` and add user's Babel config.\n            if (isBabelLoader && isRegExp(oneOfRule.test) && oneOfRule.test.test('.jsx')) {\n              const { include: _include, options: ruleOptions } = oneOfRule;\n\n              const {\n                plugins: rulePlugins,\n                presets: rulePresets,\n                overrides: ruleOverrides,\n              } = (typeof ruleOptions === 'object' ? ruleOptions : {}) as {\n                plugins: PluginItem[] | null;\n                presets: PluginItem[] | null;\n                overrides: TransformOptions[] | null;\n              };\n\n              const { extends: _extends, plugins, presets, overrides } = babelOptions;\n\n              return {\n                ...oneOfRule,\n                include: [_include as string, configDir].filter(Boolean),\n                options: {\n                  ...(ruleOptions as Record<string, unknown>),\n                  extends: _extends,\n                  plugins: [...(plugins ?? []), ...(rulePlugins ?? [])],\n                  presets: [...(presets ?? []), ...(rulePresets ?? [])],\n                  overrides: [...(overrides ?? []), ...(ruleOverrides ?? [])],\n                },\n              };\n            }\n\n            // Target `babel-loader` that processes `node_modules`, and add Storybook config dir.\n            if (isBabelLoader && isRegExp(oneOfRule.test) && oneOfRule.test.test('.js')) {\n              return {\n                ...oneOfRule,\n                include: [configDir],\n              };\n            }\n\n            return oneOfRule;\n          }),\n        },\n      ];\n    }\n\n    return [...rules, rule as RuleSetRule];\n  }, [] as RuleSetRule[]);\n};\n"
  },
  {
    "path": "code/presets/create-react-app/src/index.ts",
    "content": "import module from 'node:module';\nimport { dirname, join, relative } from 'node:path';\n\nimport { logger } from 'storybook/internal/node-logger';\n\n// TODO: Remove in SB11\nimport PnpWebpackPlugin from 'pnp-webpack-plugin';\nimport type { Configuration, RuleSetRule, WebpackPluginInstance } from 'webpack';\n\nimport { checkPresets } from './helpers/checkPresets.ts';\nimport { getModulePath } from './helpers/getModulePath.ts';\nimport { getReactScriptsPath } from './helpers/getReactScriptsPath.ts';\nimport { mergePlugins } from './helpers/mergePlugins.ts';\nimport { processCraConfig } from './helpers/processCraConfig.ts';\nimport type { PluginOptions } from './types.ts';\n\nconst CWD = process.cwd();\n\nconst REACT_SCRIPTS_PATH = getReactScriptsPath();\nconst OPTION_SCRIPTS_PACKAGE = 'scriptsPackageName';\n\n// Ensures that assets are served from the correct path when Storybook is built.\n// Resolves: https://github.com/storybookjs/storybook/issues/4645\nif (!process.env.PUBLIC_URL) {\n  process.env.PUBLIC_URL = '.';\n}\n\ntype ResolveLoader = Configuration['resolveLoader'];\n\n// This loader is shared by both the `managerWebpack` and `webpack` functions.\nconst resolveLoader: ResolveLoader = {\n  modules: ['node_modules', join(REACT_SCRIPTS_PATH, 'node_modules')],\n  // TODO: Remove in SB11\n  plugins: [PnpWebpackPlugin.moduleLoader(module)],\n};\n\n// TODO: Replace with exported type from Storybook.\n\nconst core = (existing: { disableWebpackDefaults: boolean }) => ({\n  ...existing,\n  disableWebpackDefaults: true,\n});\n\n// Update the core Webpack config.\nconst webpack = async (\n  webpackConfig: Configuration = {},\n  options: PluginOptions\n): Promise<Configuration> => {\n  let scriptsPath = REACT_SCRIPTS_PATH;\n\n  // Flag any potentially conflicting presets.\n  checkPresets(options);\n\n  // If the user has provided a package by name, try to resolve it.\n  const scriptsPackageName = options[OPTION_SCRIPTS_PACKAGE];\n  if (typeof scriptsPackageName === 'string') {\n    try {\n      scriptsPath = dirname(\n        require.resolve(`${scriptsPackageName}/package.json`, {\n          paths: [options.configDir],\n        })\n      );\n    } catch (e) {\n      logger.warn(`A \\`${OPTION_SCRIPTS_PACKAGE}\\` was provided, but couldn't be resolved.`);\n    }\n  }\n\n  // If there isn't a scripts-path set, return the Webpack config unmodified.\n  if (!scriptsPath) {\n    logger.error('Failed to resolve a `react-scripts` package.');\n    return webpackConfig;\n  }\n\n  logger.step(`Loading Webpack configuration from \\`${relative(CWD, scriptsPath)}\\``);\n\n  // Remove existing rules related to JavaScript and TypeScript.\n  logger.step(`Removing existing JavaScript and TypeScript rules.`);\n  const filteredRules = (webpackConfig.module?.rules as RuleSetRule[])?.filter((rule) => {\n    if (typeof rule === 'string') {\n      return false;\n    }\n    const { test } = rule;\n    return !(test instanceof RegExp && (test?.test('.js') || test?.test('.ts')));\n  });\n\n  // Require the CRA config and set the appropriate mode.\n  const craWebpackConfigPath = join(scriptsPath, 'config', 'webpack.config');\n\n  const craWebpackConfig = require(craWebpackConfigPath)(webpackConfig.mode) as Configuration;\n\n  // Select the relevant CRA rules and add the Storybook config directory.\n  logger.step(`Modifying Create React App rules.`);\n  const craRules = await processCraConfig(craWebpackConfig, options);\n\n  // NOTE: This is code replicated from\n  //   https://github.com/storybookjs/storybook/blob/89830ad76384faeaeb0c19df3cb44232cdde261b/builders/builder-webpack5/src/preview/base-webpack.config.ts#L45-L53\n  // as we are not applying SB's default webpack config here.\n  // We need to figure out a better way to apply various layers of webpack config; perhaps\n  // these options need to be in a separate preset.\n  const isProd = webpackConfig.mode !== 'development';\n  const coreOptions = await options.presets.apply('core');\n  const builder = coreOptions?.builder;\n  const builderOptions = typeof builder === 'string' ? {} : builder?.options;\n  const cacheConfig = builderOptions?.fsCache ? { cache: { type: 'filesystem' } } : {};\n  const lazyCompilationConfig =\n    builderOptions?.lazyCompilation && !isProd\n      ? { experiments: { lazyCompilation: { entries: false } } }\n      : {};\n\n  // Return the new config.\n  return {\n    ...webpackConfig,\n    ...cacheConfig,\n    ...lazyCompilationConfig,\n    module: {\n      ...webpackConfig.module,\n      rules: [...(filteredRules || []), ...craRules],\n    },\n    // NOTE: this prioritizes the storybook version of a plugin\n    // when there are duplicates between SB and CRA\n    plugins: mergePlugins(\n      ...((webpackConfig.plugins ?? []) as WebpackPluginInstance[]),\n      ...((craWebpackConfig.plugins ?? []) as WebpackPluginInstance[])\n    ),\n    resolve: {\n      ...webpackConfig.resolve,\n      extensions: craWebpackConfig.resolve?.extensions,\n      modules: [\n        ...((webpackConfig.resolve && webpackConfig.resolve.modules) || []),\n        join(REACT_SCRIPTS_PATH, 'node_modules'),\n        ...getModulePath(CWD),\n      ],\n      // TODO: Remove in SB11\n      plugins: [PnpWebpackPlugin as any],\n      // manual copy from builder-webpack because defaults are disabled in this CRA preset\n      conditionNames: [\n        ...(webpackConfig.resolve?.conditionNames ?? []),\n        'storybook',\n        'stories',\n        'test',\n        '...',\n      ],\n    },\n    resolveLoader,\n  } as Configuration;\n};\n\n// we do not care of the typings exported from this package\nconst exportedCore = core as any;\nconst exportedWebpack = webpack as any;\n\nexport { exportedCore as core, exportedWebpack as webpack };\n"
  },
  {
    "path": "code/presets/create-react-app/src/types.ts",
    "content": "import type { Options } from 'storybook/internal/types';\n\nimport type { PluginOptions as RDTSPluginOptions } from '@storybook/react-docgen-typescript-plugin';\n\nexport interface PluginOptions extends Options {\n  /**\n   * Optionally set the package name of a react-scripts fork. In most cases, the package is located\n   * automatically by this preset.\n   */\n  scriptsPackageName?: string;\n\n  /** Overrides for Create React App's Webpack configuration. */\n  craOverrides?: {\n    fileLoaderExcludes?: string[];\n  };\n\n  typescriptOptions?: {\n    reactDocgen: 'react-docgen-typescript' | 'react-docgen' | false;\n    reactDocgenTypescriptOptions: RDTSPluginOptions;\n  };\n}\n\nexport interface CoreConfig {\n  builder: {\n    options?: {\n      fsCache?: boolean;\n      lazyCompilation?: boolean;\n    };\n  };\n}\n"
  },
  {
    "path": "code/presets/create-react-app/src/typings.d.ts",
    "content": "declare module 'pnp-webpack-plugin';\n"
  },
  {
    "path": "code/presets/create-react-app/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/presets/react-webpack/README.md",
    "content": "# Storybook Webpack preset for React\n\nThis package is a [preset](https://storybook.js.org/docs/addons/writing-presets?renderer=react&ref=readme) that configures Storybook's webpack settings for handling React.\nIt's an internal package that's not intended to be used directly by users.\n\n- More info on [Storybook for React](https://storybook.js.org/docs/get-started/install?renderer=react&ref=readme)\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/presets/react-webpack/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    node: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./preset-cra'],\n        entryPoint: './src/framework-preset-cra.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./preset-react-docs'],\n        entryPoint: './src/framework-preset-react-docs.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./react-docgen-loader'],\n        entryPoint: './src/loaders/react-docgen-loader.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/presets/react-webpack/package.json",
    "content": "{\n  \"name\": \"@storybook/preset-react-webpack\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook for React: Develop React Component in isolation with Hot Reloading\",\n  \"keywords\": [\n    \"storybook\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/presets/react-webpack\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/presets/react-webpack\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./preset-cra\": \"./dist/framework-preset-cra.js\",\n    \"./preset-react-docs\": \"./dist/framework-preset-react-docs.js\",\n    \"./react-docgen-loader\": \"./dist/loaders/react-docgen-loader.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/core-webpack\": \"workspace:*\",\n    \"@storybook/react-docgen-typescript-plugin\": \"1.0.6--canary.9.0c3f3b7.0\",\n    \"@types/semver\": \"^7.7.1\",\n    \"magic-string\": \"^0.30.5\",\n    \"react-docgen\": \"^7.1.1\",\n    \"resolve\": \"^1.22.8\",\n    \"semver\": \"^7.7.3\",\n    \"tsconfig-paths\": \"^4.2.0\",\n    \"webpack\": \"5\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.19.1\",\n    \"empathic\": \"^2.0.0\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"storybook\": \"workspace:^\"\n  },\n  \"peerDependenciesMeta\": {\n    \"typescript\": {\n      \"optional\": true\n    }\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/presets/react-webpack/preset.js",
    "content": "export * from './dist/index.js';\n"
  },
  {
    "path": "code/presets/react-webpack/project.json",
    "content": "{\n  \"name\": \"react-webpack\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/presets/react-webpack/src/cra-config.test.ts",
    "content": "import fs from 'node:fs';\nimport { join, sep } from 'node:path';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { getReactScriptsPath } from './cra-config.ts';\n\nvi.mock('fs', () => ({\n  realpathSync: vi.fn(() => '/test-project'),\n  readFileSync: vi.fn(),\n  existsSync: vi.fn(() => true),\n}));\n\nconst SCRIPT_PATH = join('.bin', 'react-scripts');\n\ndescribe('cra-config', () => {\n  describe('when used with the default react-scripts package', () => {\n    beforeEach(() => {\n      vi.mocked(fs.realpathSync).mockImplementationOnce((filePath) =>\n        filePath.toString().replace(SCRIPT_PATH, `react-scripts/${SCRIPT_PATH}`)\n      );\n    });\n\n    it('should locate the react-scripts package', () => {\n      expect(getReactScriptsPath({ noCache: true })).toEqual(\n        join(sep, 'test-project', 'node_modules', 'react-scripts')\n      );\n    });\n  });\n\n  describe('when used with a custom react-scripts package', () => {\n    beforeEach(() => {\n      vi.mocked(fs.realpathSync).mockImplementationOnce((filePath) =>\n        filePath.toString().replace(SCRIPT_PATH, `custom-react-scripts/${SCRIPT_PATH}`)\n      );\n    });\n\n    it('should locate the react-scripts package', () => {\n      expect(getReactScriptsPath({ noCache: true })).toEqual(\n        join(sep, 'test-project', 'node_modules', 'custom-react-scripts')\n      );\n    });\n  });\n\n  describe('when used with a custom react-scripts package without symlinks in .bin folder', () => {\n    beforeEach(() => {\n      // In case of .bin/react-scripts is not symlink (like it happens on Windows),\n      // realpathSync() method does not translate the path.\n      vi.mocked(fs.realpathSync).mockImplementationOnce((filePath) => filePath.toString());\n\n      vi.mocked(fs.readFileSync).mockImplementationOnce(\n        () => `#!/bin/sh\nbasedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\,/,g')\")\n\ncase \\`uname\\` in\n    *CYGWIN*) basedir=\\`cygpath -w \"$basedir\"\\`;;\nesac\n\nif [ -x \"$basedir/node\" ]; then\n  \"$basedir/node\"  \"$basedir/../custom-react-scripts/bin/react-scripts.js\" \"$@\"\n  ret=$?\nelse\n  node  \"$basedir/../custom-react-scripts/bin/react-scripts.js\" \"$@\"\n  ret=$?\nfi\nexit $ret`\n      );\n    });\n\n    it('should locate the react-scripts package', () => {\n      expect(getReactScriptsPath({ noCache: true })).toEqual(\n        join(sep, 'test-project', 'node_modules', 'custom-react-scripts')\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "code/presets/react-webpack/src/cra-config.ts",
    "content": "import { existsSync, readFileSync, realpathSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nimport { logger } from 'storybook/internal/node-logger';\n\nimport semver from 'semver';\n\nconst appDirectory = realpathSync(process.cwd());\n\nlet reactScriptsPath: string;\n\nexport function getReactScriptsPath({ noCache }: { noCache?: boolean } = {}) {\n  if (reactScriptsPath && !noCache) {\n    return reactScriptsPath;\n  }\n\n  let reactScriptsScriptPath = realpathSync(join(appDirectory, '/node_modules/.bin/react-scripts'));\n\n  try {\n    // Note: Since there is no symlink for .bin/react-scripts on Windows\n    // we'll parse react-scripts file to find actual package path.\n    // This is important if you use fork of CRA.\n\n    const pathIsNotResolved = /node_modules[\\\\/]\\.bin[\\\\/]react-scripts/i.test(\n      reactScriptsScriptPath\n    );\n\n    if (pathIsNotResolved) {\n      const content = readFileSync(reactScriptsScriptPath, 'utf8');\n      const packagePathMatch = content.match(\n        /\"\\$basedir[\\\\/]([^\\s]+?[\\\\/]bin[\\\\/]react-scripts\\.js\")/i\n      );\n\n      if (packagePathMatch && packagePathMatch.length > 1) {\n        reactScriptsScriptPath = join(appDirectory, '/node_modules/.bin/', packagePathMatch[1]);\n      }\n    }\n  } catch (e) {\n    logger.warn(`Error occurred during react-scripts package path resolving: ${e}`);\n  }\n\n  reactScriptsPath = join(reactScriptsScriptPath, '../..');\n  const scriptsPkgJson = join(reactScriptsPath, 'package.json');\n\n  if (!existsSync(scriptsPkgJson)) {\n    reactScriptsPath = 'react-scripts';\n  }\n\n  return reactScriptsPath;\n}\n\nexport async function isReactScriptsInstalled(minimumVersion = '2.0.0') {\n  try {\n    const { default: reactScriptsJson } = await import(\n      pathToFileURL(join(getReactScriptsPath(), 'package.json')).href,\n      {\n        with: { type: 'json' },\n      }\n    );\n    return !semver.gtr(minimumVersion, reactScriptsJson.version);\n  } catch (e) {\n    return false;\n  }\n}\n"
  },
  {
    "path": "code/presets/react-webpack/src/framework-preset-cra.ts",
    "content": "import { logger } from 'storybook/internal/node-logger';\n\nimport type { Preset, StorybookConfig } from '@storybook/core-webpack';\n\nimport { isReactScriptsInstalled } from './cra-config.ts';\n\nconst checkForNewPreset = (presetsList: Preset[]) => {\n  const hasNewPreset = presetsList.some((preset: Preset) => {\n    const presetName = typeof preset === 'string' ? preset : preset.name;\n    return /@storybook(\\/|\\\\)preset-create-react-app/.test(presetName);\n  });\n\n  if (!hasNewPreset) {\n    logger.warn('Storybook support for Create React App is now a separate preset.');\n    logger.warn(\n      'To use the new preset, install `@storybook/preset-create-react-app` and add it to the list of `addons` in your `.storybook/main.js` config file.'\n    );\n    logger.warn('The built-in preset has been disabled in Storybook 6.0.');\n  }\n};\n\nexport const webpackFinal: StorybookConfig['webpack'] = async (config, { presetsList }) => {\n  if (await isReactScriptsInstalled()) {\n    if (presetsList) {\n      checkForNewPreset(presetsList);\n    }\n  }\n  config.module?.rules?.push(\n    ...[\n      {\n        test: /\\.m?js$/,\n        type: 'javascript/auto',\n      },\n      {\n        test: /\\.m?js$/,\n        resolve: {\n          fullySpecified: false,\n        },\n      },\n    ]\n  );\n  return config;\n};\n"
  },
  {
    "path": "code/presets/react-webpack/src/framework-preset-react-docs.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport type { TypescriptOptions } from '@storybook/core-webpack';\nimport ReactDocgenTypescriptPlugin from '@storybook/react-docgen-typescript-plugin';\n\nimport type { Configuration } from 'webpack';\n\nimport * as preset from './framework-preset-react-docs.ts';\n\nvi.mock('./requirer', () => ({\n  requirer: (resolver: any, path: string) => path,\n}));\n\ndescribe('framework-preset-react-docgen', () => {\n  const presetsListWithDocs = [{ name: '@storybook/addon-docs', options: {}, preset: null }];\n\n  // mock requirer\n\n  describe('react-docgen', () => {\n    it('should return the webpack config with the extra webpack loader', async () => {\n      const webpackConfig: Configuration = {};\n\n      const config = await preset.webpackFinal?.(webpackConfig, {\n        presets: {\n          apply: async (name: string) => {\n            if (name === 'typescript') {\n              return {\n                check: false,\n                reactDocgen: 'react-docgen',\n              } as Partial<TypescriptOptions>;\n            }\n\n            if (name === 'babel') {\n              return {\n                plugins: [],\n                presets: [],\n              };\n            }\n\n            return undefined;\n          },\n        },\n        presetsList: presetsListWithDocs,\n      } as any);\n\n      expect(config).toEqual({\n        module: {\n          rules: [\n            {\n              exclude: /(\\.(stories|story)\\.(js|jsx|ts|tsx))|(node_modules)/,\n              loader: expect.stringContaining('@storybook/preset-react-webpack'),\n              options: { babelOptions: { plugins: [], presets: [] }, debug: false },\n              test: /\\.(cjs|mjs|tsx?|jsx?)$/,\n            },\n          ],\n        },\n      });\n    });\n  });\n\n  describe('react-docgen-typescript', () => {\n    it('should return the webpack config with the extra plugin', async () => {\n      const webpackConfig = {\n        plugins: [],\n      };\n\n      const config = await preset.webpackFinal?.(webpackConfig, {\n        presets: {\n          // @ts-expect-error (not strict)\n          apply: async (name: string) => {\n            if (name === 'typescript') {\n              return {\n                check: false,\n                reactDocgen: 'react-docgen-typescript',\n              } as Partial<TypescriptOptions>;\n            }\n\n            if (name === 'babel') {\n              return {\n                plugins: [],\n                presets: [],\n              };\n            }\n\n            return undefined;\n          },\n        },\n        presetsList: presetsListWithDocs,\n      });\n\n      expect(config).toEqual({\n        module: {\n          rules: [\n            {\n              exclude: /(\\.(stories|story)\\.(js|jsx|ts|tsx))|(node_modules)/,\n              loader: expect.stringContaining('@storybook/preset-react-webpack'),\n              options: { babelOptions: { plugins: [], presets: [] }, debug: false },\n              test: /\\.(cjs|mjs|jsx?)$/,\n            },\n          ],\n        },\n        plugins: [expect.any(ReactDocgenTypescriptPlugin)],\n      });\n    });\n  });\n\n  describe('no docgen', () => {\n    it('should not add any extra plugins', async () => {\n      const webpackConfig = {\n        plugins: [],\n      };\n\n      const outputWebpackconfig = await preset.webpackFinal?.(webpackConfig, {\n        presets: {\n          // @ts-expect-error (Converted from ts-ignore)\n          apply: async () =>\n            ({\n              check: false,\n              reactDocgen: false,\n            }) as Partial<TypescriptOptions>,\n        },\n        presetsList: presetsListWithDocs,\n      });\n\n      expect(outputWebpackconfig).toEqual({ plugins: [] });\n    });\n  });\n\n  describe('no docs or controls addon used', () => {\n    it('should not add any extra plugins', async () => {\n      const webpackConfig = {\n        plugins: [],\n      };\n\n      const outputWebpackconfig = await preset.webpackFinal?.(webpackConfig, {\n        presets: {\n          // @ts-expect-error (Converted from ts-ignore)\n          apply: async () =>\n            ({\n              check: false,\n              reactDocgen: 'react-docgen-typescript',\n            }) as Partial<TypescriptOptions>,\n        },\n        presetsList: [],\n      });\n\n      expect(outputWebpackconfig).toEqual({\n        plugins: [],\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/presets/react-webpack/src/framework-preset-react-docs.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport type { Configuration } from 'webpack';\n\nimport type { StorybookConfig } from './types.ts';\n\nexport const webpackFinal: StorybookConfig['webpackFinal'] = async (\n  config,\n  options\n): Promise<Configuration> => {\n  const typescriptOptions = await options.presets.apply('typescript', {} as any);\n  const debug = options.loglevel === 'debug';\n\n  const { reactDocgen, reactDocgenTypescriptOptions } = typescriptOptions || {};\n\n  if (typeof reactDocgen !== 'string') {\n    return config;\n  }\n\n  if (reactDocgen !== 'react-docgen-typescript') {\n    return {\n      ...config,\n      module: {\n        ...(config.module ?? {}),\n        rules: [\n          ...(config.module?.rules ?? []),\n          {\n            test: /\\.(cjs|mjs|tsx?|jsx?)$/,\n            enforce: 'pre',\n            loader: fileURLToPath(\n              import.meta.resolve('@storybook/preset-react-webpack/react-docgen-loader')\n            ),\n            options: {\n              debug,\n            },\n            exclude: /(\\.(stories|story)\\.(js|jsx|ts|tsx))|(node_modules)/,\n          },\n        ],\n      },\n    };\n  }\n\n  const { ReactDocgenTypeScriptPlugin } = await import('@storybook/react-docgen-typescript-plugin');\n\n  return {\n    ...config,\n    module: {\n      ...(config.module ?? {}),\n      rules: [\n        ...(config.module?.rules ?? []),\n        {\n          test: /\\.(cjs|mjs|jsx?)$/,\n          enforce: 'pre',\n          loader: fileURLToPath(\n            import.meta.resolve('@storybook/preset-react-webpack/react-docgen-loader')\n          ),\n          options: {\n            debug,\n          },\n          exclude: /(\\.(stories|story)\\.(js|jsx|ts|tsx))|(node_modules)/,\n        },\n      ],\n    },\n    plugins: [\n      ...(config.plugins || []),\n      new ReactDocgenTypeScriptPlugin({\n        ...reactDocgenTypescriptOptions,\n        // We *need* this set so that RDT returns default values in the same format as react-docgen\n        savePropValueAsString: true,\n      }),\n    ],\n  };\n};\n"
  },
  {
    "path": "code/presets/react-webpack/src/index.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport type { PresetProperty } from 'storybook/internal/types';\n\nexport * from './types.ts';\n\nexport const addons: PresetProperty<'addons'> = [\n  fileURLToPath(import.meta.resolve('@storybook/preset-react-webpack/preset-cra')),\n  fileURLToPath(import.meta.resolve('@storybook/preset-react-webpack/preset-react-docs')),\n];\n"
  },
  {
    "path": "code/presets/react-webpack/src/loaders/docgen-resolver.ts",
    "content": "import { extname } from 'node:path';\n\nimport resolve from 'resolve';\n\nexport class ReactDocgenResolveError extends Error {\n  // the magic string that react-docgen uses to check if a module is ignored\n  readonly code = 'MODULE_NOT_FOUND';\n\n  constructor(filename: string) {\n    super(`'${filename}' was ignored by react-docgen.`);\n  }\n}\n\n/* The below code was copied from:\n * https://github.com/reactjs/react-docgen/blob/df2daa8b6f0af693ecc3c4dc49f2246f60552bcb/packages/react-docgen/src/importer/makeFsImporter.ts#L14-L63\n * because it wasn't exported from the react-docgen package.\n * watch out: when updating this code, also update the code in code/frameworks/react-vite/src/plugins/docgen-resolver.ts\n */\n\n// These extensions are sorted by priority\n// resolve() will check for files in the order these extensions are sorted\nexport const RESOLVE_EXTENSIONS = [\n  '.js',\n  '.cts', // These were originally not in the code, I added them\n  '.mts', // These were originally not in the code, I added them\n  '.ctsx', // These were originally not in the code, I added them\n  '.mtsx', // These were originally not in the code, I added them\n  '.ts',\n  '.tsx',\n  '.mjs',\n  '.cjs',\n  '.mts',\n  '.cts',\n  '.jsx',\n];\n\nexport function defaultLookupModule(filename: string, basedir: string): string {\n  const resolveOptions = {\n    basedir,\n    extensions: RESOLVE_EXTENSIONS,\n    // we do not need to check core modules as we cannot import them anyway\n    includeCoreModules: false,\n  };\n\n  try {\n    return resolve.sync(filename, resolveOptions);\n  } catch (error) {\n    const ext = extname(filename);\n    let newFilename: string;\n\n    // if we try to import a JavaScript file it might be that we are actually pointing to\n    // a TypeScript file. This can happen in ES modules as TypeScript requires to import other\n    // TypeScript files with .js extensions\n    // https://www.typescriptlang.org/docs/handbook/esm-node.html#type-in-packagejson-and-new-extensions\n    switch (ext) {\n      case '.js':\n      case '.mjs':\n      case '.cjs': {\n        // Try .ts first, then fall back to .tsx (for React components using ESM-style .js imports)\n        const base = filename.slice(0, -2);\n        try {\n          return resolve.sync(`${base}ts`, { ...resolveOptions, extensions: [] });\n        } catch {\n          newFilename = `${base}tsx`;\n        }\n        break;\n      }\n\n      case '.jsx':\n        newFilename = `${filename.slice(0, -3)}tsx`;\n        break;\n      default:\n        throw error;\n    }\n\n    return resolve.sync(newFilename, {\n      ...resolveOptions,\n      // we already know that there is an extension at this point, so no need to check other extensions\n      extensions: [],\n    });\n  }\n}\n"
  },
  {
    "path": "code/presets/react-webpack/src/loaders/react-docgen-loader.test.ts",
    "content": "import { describe, expect, it, vi } from 'vitest';\n\nimport { getReactDocgenImporter } from './react-docgen-loader.ts';\n\nconst reactDocgenMock = vi.hoisted(() => {\n  return {\n    makeFsImporter: vi.fn().mockImplementation((fn) => fn),\n  };\n});\n\nconst reactDocgenResolverMock = vi.hoisted(() => {\n  return {\n    defaultLookupModule: vi.fn(),\n  };\n});\n\nvi.mock('./docgen-resolver', async (importOriginal) => {\n  const actual = await importOriginal<typeof import('path')>();\n  return {\n    ...actual,\n    defaultLookupModule: reactDocgenResolverMock.defaultLookupModule,\n  };\n});\n\nvi.mock('react-docgen', async (importOriginal) => {\n  const actual = await importOriginal<typeof import('path')>();\n  return {\n    ...actual,\n    makeFsImporter: reactDocgenMock.makeFsImporter,\n  };\n});\n\ndescribe('getReactDocgenImporter function', () => {\n  it('should not map the request if a tsconfig path mapping is not available', () => {\n    const filename = './src/components/Button.tsx';\n    const basedir = '/src';\n    const imported = getReactDocgenImporter(undefined);\n    reactDocgenResolverMock.defaultLookupModule.mockImplementation((filen: string) => filen);\n    const result = (imported as any)(filename, basedir);\n    expect(result).toBe(filename);\n  });\n\n  it('should map the request', () => {\n    const mappedFile = './mapped-file.tsx';\n    const matchPath = vi.fn().mockReturnValue(mappedFile);\n    const filename = './src/components/Button.tsx';\n    const basedir = '/src';\n    const imported = getReactDocgenImporter(matchPath);\n    reactDocgenResolverMock.defaultLookupModule.mockImplementation((filen: string) => filen);\n    const result = (imported as any)(filename, basedir);\n    expect(result).toBe(mappedFile);\n  });\n});\n"
  },
  {
    "path": "code/presets/react-webpack/src/loaders/react-docgen-loader.ts",
    "content": "import { getProjectRoot } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport * as find from 'empathic/find';\nimport MagicString from 'magic-string';\nimport {\n  ERROR_CODES,\n  builtinHandlers as docgenHandlers,\n  builtinResolvers as docgenResolver,\n  makeFsImporter,\n  parse,\n  utils,\n} from 'react-docgen';\nimport type { Documentation, Handler, NodePath, babelTypes as t } from 'react-docgen';\nimport * as TsconfigPaths from 'tsconfig-paths';\nimport type { LoaderContext } from 'webpack';\n\nimport {\n  RESOLVE_EXTENSIONS,\n  ReactDocgenResolveError,\n  defaultLookupModule,\n} from './docgen-resolver.ts';\n\nconst { getNameOrValue, isReactForwardRefCall } = utils;\n\nconst actualNameHandler: Handler = function actualNameHandler(documentation, componentDefinition) {\n  documentation.set('definedInFile', componentDefinition.hub.file.opts.filename);\n  if (\n    (componentDefinition.isClassDeclaration() || componentDefinition.isFunctionDeclaration()) &&\n    componentDefinition.has('id')\n  ) {\n    documentation.set(\n      'actualName',\n      getNameOrValue(componentDefinition.get('id') as NodePath<t.Identifier>)\n    );\n  } else if (\n    componentDefinition.isArrowFunctionExpression() ||\n    componentDefinition.isFunctionExpression() ||\n    isReactForwardRefCall(componentDefinition)\n  ) {\n    let currentPath: NodePath = componentDefinition;\n\n    while (currentPath.parentPath) {\n      if (currentPath.parentPath.isVariableDeclarator()) {\n        documentation.set('actualName', getNameOrValue(currentPath.parentPath.get('id')));\n        return;\n      }\n      if (currentPath.parentPath.isAssignmentExpression()) {\n        const leftPath = currentPath.parentPath.get('left');\n\n        if (leftPath.isIdentifier() || leftPath.isLiteral()) {\n          documentation.set('actualName', getNameOrValue(leftPath));\n          return;\n        }\n      }\n\n      currentPath = currentPath.parentPath;\n    }\n    // Could not find an actual name\n    documentation.set('actualName', '');\n  }\n};\n\ntype DocObj = Documentation & { actualName: string; definedInFile: string };\n\nconst defaultHandlers = Object.values(docgenHandlers).map((handler) => handler);\nconst defaultResolver = new docgenResolver.FindExportedDefinitionsResolver();\nconst handlers = [...defaultHandlers, actualNameHandler];\n\nlet tsconfigPathsInitialized = false;\nlet matchPath: TsconfigPaths.MatchPath | undefined;\n\nexport default async function reactDocgenLoader(\n  this: LoaderContext<{ debug: boolean }>,\n  source: string,\n  map: any\n) {\n  const callback = this.async();\n  // get options\n  const options = this.getOptions() || {};\n  const { debug = false } = options;\n\n  if (!tsconfigPathsInitialized) {\n    const projectRoot = getProjectRoot();\n    const cwd = process.cwd();\n    const tsconfigPath =\n      find.up('tsconfig.json', { cwd, last: projectRoot }) ??\n      find.up('tsconfig.base.json', { cwd, last: projectRoot }) ??\n      find.up('tsconfig.app.json', { cwd, last: projectRoot });\n    const tsconfig = TsconfigPaths.loadConfig(tsconfigPath);\n\n    if (tsconfig.resultType === 'success') {\n      logger.debug('Using tsconfig paths for react-docgen');\n      matchPath = TsconfigPaths.createMatchPath(tsconfig.absoluteBaseUrl, tsconfig.paths, [\n        'browser',\n        'module',\n        'main',\n      ]);\n    }\n\n    tsconfigPathsInitialized = true;\n  }\n\n  try {\n    const docgenResults = parse(source, {\n      filename: this.resourcePath,\n      resolver: defaultResolver,\n      handlers,\n      importer: getReactDocgenImporter(matchPath),\n      babelOptions: {\n        babelrc: false,\n        configFile: false,\n      },\n    }) as DocObj[];\n\n    const magicString = new MagicString(source);\n\n    docgenResults.forEach((info) => {\n      const { actualName, definedInFile, ...docgenInfo } = info;\n      if (actualName && definedInFile == this.resourcePath) {\n        const docNode = JSON.stringify(docgenInfo);\n        magicString.append(`;${actualName}.__docgenInfo=${docNode}`);\n      }\n    });\n\n    callback(\n      null,\n      magicString.toString(),\n      map ??\n        magicString.generateMap({\n          hires: true,\n          source: this.resourcePath,\n          includeContent: true,\n        })\n    );\n  } catch (error: any) {\n    if (error.code === ERROR_CODES.MISSING_DEFINITION) {\n      callback(null, source);\n    } else {\n      if (!debug) {\n        logger.warn(\n          `Failed to parse ${this.resourcePath} with react-docgen. Rerun Storybook with --loglevel=debug to get more info.`\n        );\n      } else {\n        logger.warn(\n          `Failed to parse ${this.resourcePath} with react-docgen. Please use the below error message and the content of the file which causes the error to report the issue to the maintainers of react-docgen. https://github.com/reactjs/react-docgen`\n        );\n        logger.error(error);\n      }\n\n      callback(null, source);\n    }\n  }\n}\n\nexport function getReactDocgenImporter(matchingPath: TsconfigPaths.MatchPath | undefined) {\n  return makeFsImporter((filename, basedir) => {\n    const mappedFilenameByPaths = (() => {\n      if (matchingPath) {\n        const match = matchingPath(filename);\n        return match || filename;\n      } else {\n        return filename;\n      }\n    })();\n\n    const result = defaultLookupModule(mappedFilenameByPaths, basedir);\n\n    if (RESOLVE_EXTENSIONS.find((ext) => result.endsWith(ext))) {\n      return result;\n    }\n\n    throw new ReactDocgenResolveError(filename);\n  });\n}\n"
  },
  {
    "path": "code/presets/react-webpack/src/types.ts",
    "content": "import type {\n  StorybookConfig as StorybookConfigBase,\n  TypescriptOptions as TypescriptOptionsBase,\n  WebpackConfiguration as WebpackConfigurationBase,\n} from '@storybook/core-webpack';\nimport type { PluginOptions as ReactDocgenTypescriptOptions } from '@storybook/react-docgen-typescript-plugin';\n\nexport type { BuilderResult } from '@storybook/core-webpack';\n\nexport interface ReactOptions {\n  strictMode?: boolean;\n  /**\n   * Use React's legacy root API to mount components\n   *\n   * React has introduced a new root API with React 18.x to enable a whole set of new features (e.g.\n   * concurrent features) If this flag is true, the legacy Root API is used to mount components to\n   * make it easier to migrate step by step to React 18.\n   *\n   * @default false\n   */\n  legacyRootApi?: boolean;\n}\n\nexport type TypescriptOptions = TypescriptOptionsBase & {\n  /**\n   * Sets the type of Docgen when working with React and TypeScript\n   *\n   * @default `'react-docgen'`\n   */\n  reactDocgen: 'react-docgen-typescript' | 'react-docgen' | false;\n  /**\n   * Configures `react-docgen-typescript-plugin`\n   *\n   * @default\n   * @see https://github.com/storybookjs/storybook/blob/next/code/builders/builder-webpack5/src/config/defaults.js#L4-L6\n   */\n  reactDocgenTypescriptOptions: ReactDocgenTypescriptOptions;\n};\n\nexport type StorybookConfig<TWebpackConfiguration = WebpackConfigurationBase> =\n  StorybookConfigBase<TWebpackConfiguration> & {\n    typescript?: Partial<TypescriptOptions>;\n  };\n"
  },
  {
    "path": "code/presets/react-webpack/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/presets/server-webpack/README.md",
    "content": "# Storybook Webpack preset for Server\n\nThis package is a [preset](https://storybook.js.org/docs/addons/writing-presets?ref=readme) that configures Storybook's webpack settings for handling React.\nIt's an internal package that's not intended to be used directly by users.\n\n- More info on [Storybook for Server](https://github.com/storybookjs/storybook/tree/next/code/frameworks/server-webpack5)\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/presets/server-webpack/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    node: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./loader'],\n        entryPoint: './src/loader.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/presets/server-webpack/package.json",
    "content": "{\n  \"name\": \"@storybook/preset-server-webpack\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook for Server: View HTML snippets from a server in isolation with Hot Reloading.\",\n  \"keywords\": [\n    \"storybook\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/presets/server-webpack\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/presets/server-webpack\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./loader\": \"./dist/loader.js\",\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/core-webpack\": \"workspace:*\",\n    \"safe-identifier\": \"^0.4.2\",\n    \"ts-dedent\": \"^2.0.0\",\n    \"yaml-loader\": \"^0.8.1\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.19.1\",\n    \"typescript\": \"^5.9.3\",\n    \"yaml\": \"^2.8.1\"\n  },\n  \"peerDependencies\": {\n    \"storybook\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/presets/server-webpack/preset.js",
    "content": "export * from './dist/index.js';\n"
  },
  {
    "path": "code/presets/server-webpack/project.json",
    "content": "{\n  \"name\": \"server-webpack\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/presets/server-webpack/src/index.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport type { StorybookConfig } from './types.ts';\n\nexport * from './types.ts';\n\nexport const webpack: StorybookConfig['webpack'] = (config) => {\n  const rules = [\n    ...(config.module?.rules || []),\n    {\n      type: 'javascript/auto',\n      test: /\\.stories\\.json$/,\n      use: fileURLToPath(import.meta.resolve('@storybook/preset-server-webpack/loader')),\n    },\n\n    {\n      type: 'javascript/auto',\n      test: /\\.stories\\.ya?ml/,\n      use: [\n        fileURLToPath(import.meta.resolve('@storybook/preset-server-webpack/loader')),\n        {\n          loader: fileURLToPath(import.meta.resolve('yaml-loader')),\n          options: { asJSON: true },\n        },\n      ],\n    },\n  ];\n\n  config.module = config.module || {};\n\n  config.module.rules = rules;\n\n  return config;\n};\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/a11y.json",
    "content": "{\n  \"title\": \"Addons/a11y\",\n  \"parameters\": {\n    \"options\": { \"selectedPanel\": \"storybook/a11y/panel\" }\n  },\n  \"stories\": [\n    {\n      \"name\": \"Label\",\n      \"parameters\": {\n        \"server\": { \"id\": \"addons/a11y/label\" }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/a11y.snapshot",
    "content": "\nexport default {\n  title: \"Addons/a11y\",\n  parameters: {\n    options: {\n      selectedPanel: \"storybook/a11y/panel\"\n    }\n  }\n};\n\nexport const Label = {\n  name: \"Label\",\n  parameters: {\n    server: {\n      id: \"addons/a11y/label\"\n    }\n  }\n};\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/actions.json",
    "content": "{\n  \"title\": \"Addons/Actions\",\n  \"parameters\": {\n    \"options\": { \"selectedPanel\": \"storybook/actions/panel\" }\n  },\n  \"stories\": [\n    {\n      \"name\": \"Multiple actions + config\",\n      \"parameters\": {\n        \"actions\": [\"click\", \"contextmenu\", { \"clearOnStoryChange\": false }],\n        \"server\": { \"id\": \"addons/actions/story3\" }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/actions.snapshot",
    "content": "\nexport default {\n  title: \"Addons/Actions\",\n  parameters: {\n    options: {\n      selectedPanel: \"storybook/actions/panel\"\n    }\n  }\n};\n\nexport const Multiple_actions_config = {\n  name: \"Multiple actions + config\",\n  parameters: {\n    actions: [\n      \"click\",\n      \"contextmenu\",\n      {\n        clearOnStoryChange: false\n      }\n    ],\n    server: {\n      id: \"addons/actions/story3\"\n    }\n  }\n};\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/backgrounds.json",
    "content": "{\n  \"title\": \"Addons/Backgrounds\",\n  \"parameters\": {\n    \"backgrounds\": [\n      { \"name\": \"light\", \"value\": \"#eeeeee\" },\n      { \"name\": \"dark\", \"value\": \"#222222\", \"default\": true }\n    ]\n  },\n  \"stories\": [\n    {\n      \"name\": \"Story 1\",\n      \"parameters\": {\n        \"server\": { \"id\": \"addons/backgrounds/story1\" }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/backgrounds.snapshot",
    "content": "\nexport default {\n  title: \"Addons/Backgrounds\",\n  parameters: {\n    backgrounds: [\n      {\n        name: \"light\",\n        value: \"#eeeeee\"\n      },\n      {\n        name: \"dark\",\n        value: \"#222222\",\n        default: true\n      }\n    ]\n  }\n};\n\nexport const Story_1 = {\n  name: \"Story 1\",\n  parameters: {\n    server: {\n      id: \"addons/backgrounds/story1\"\n    }\n  }\n};\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/controls.json",
    "content": "{\n  \"title\": \"Addons/Controls\",\n  \"parameters\": {\n    \"options\": { \"selectedPanel\": \"storybook/controls/panel\" }\n  },\n  \"stories\": [\n    {\n      \"name\": \"Simple\",\n      \"parameters\": {\n        \"server\": { \"id\": \"addons/controls/simple\" }\n      },\n      \"args\": {\n        \"name\": \"John Doe\",\n        \"birthday\": \"1960-12-25T00:42:03.600Z\",\n        \"favorite_color\": \"red\",\n        \"active\": true,\n        \"pets\": 2,\n        \"sports\": [\"football\", \"baseball\"],\n        \"favorite_food\": \"Ice Cream\",\n        \"other_things\": { \"hair\": \"Brown\", \"eyes\": \"Blue\" }\n      },\n      \"argTypes\": {\n        \"birthday\": { \"control\": { \"type\": \"date\" } },\n        \"favorite_color\": { \"control\": { \"type\": \"color\" } },\n        \"favorite_food\": {\n          \"control\": {\n            \"type\": \"select\",\n            \"options\": {\n              \"hot_dog\": \"Hot Dog\",\n              \"pizza\": \"Pizza\",\n              \"burgers\": \"Burgers\",\n              \"ice_cream\": \"Ice Cream\"\n            }\n          }\n        }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/controls.snapshot",
    "content": "\nexport default {\n  title: \"Addons/Controls\",\n  parameters: {\n    options: {\n      selectedPanel: \"storybook/controls/panel\"\n    }\n  }\n};\n\nexport const Simple = {\n  name: \"Simple\",\n  parameters: {\n    server: {\n      id: \"addons/controls/simple\"\n    }\n  },\n  args: {\n    name: \"John Doe\",\n    birthday: \"1960-12-25T00:42:03.600Z\",\n    favorite_color: \"red\",\n    active: true,\n    pets: 2,\n    sports: [\n      \"football\",\n      \"baseball\"\n    ],\n    favorite_food: \"Ice Cream\",\n    other_things: {\n      hair: \"Brown\",\n      eyes: \"Blue\"\n    }\n  },\n  argTypes: {\n    birthday: {\n      control: {\n        type: \"date\"\n      }\n    },\n    favorite_color: {\n      control: {\n        type: \"color\"\n      }\n    },\n    favorite_food: {\n      control: {\n        type: \"select\",\n        options: {\n          hot_dog: \"Hot Dog\",\n          pizza: \"Pizza\",\n          burgers: \"Burgers\",\n          ice_cream: \"Ice Cream\"\n        }\n      }\n    }\n  }\n};\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/kitchen_sink.json",
    "content": "{\n  \"title\": \"Kitchen Sink\",\n  \"parameters\": {\n    \"backgrounds\": [\n      { \"name\": \"light\", \"value\": \"#eeeeee\" },\n      { \"name\": \"dark\", \"value\": \"#222222\", \"default\": true }\n    ],\n    \"options\": { \"selectedPanel\": \"storybook/a11y/panel\" },\n    \"server\": {\n      \"params\": { \"color\": \"red\" }\n    }\n  },\n  \"stories\": [\n    {\n      \"name\": \"Heading\",\n      \"parameters\": {\n        \"actions\": [\"click\", \"contextmenu\", { \"clearOnStoryChange\": false }],\n        \"server\": {\n          \"id\": \"demo/heading\",\n          \"params\": {\n            \"color\": \"orange\"\n          }\n        }\n      },\n      \"args\": { \"name\": \"John Doe\", \"age\": 44 }\n    },\n    {\n      \"name\": \"Button\",\n      \"parameters\": {\n        \"server\": { \"id\": \"demo/button\" }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/kitchen_sink.snapshot",
    "content": "\nexport default {\n  title: \"Kitchen Sink\",\n  parameters: {\n    backgrounds: [\n      {\n        name: \"light\",\n        value: \"#eeeeee\"\n      },\n      {\n        name: \"dark\",\n        value: \"#222222\",\n        default: true\n      }\n    ],\n    options: {\n      selectedPanel: \"storybook/a11y/panel\"\n    },\n    server: {\n      params: {\n        color: \"red\"\n      }\n    }\n  }\n};\n\nexport const Heading = {\n  name: \"Heading\",\n  parameters: {\n    actions: [\n      \"click\",\n      \"contextmenu\",\n      {\n        clearOnStoryChange: false\n      }\n    ],\n    server: {\n      id: \"demo/heading\",\n      params: {\n        color: \"orange\"\n      }\n    }\n  },\n  args: {\n    name: \"John Doe\",\n    age: 44\n  }\n};\n\nexport const Button = {\n  name: \"Button\",\n  parameters: {\n    server: {\n      id: \"demo/button\"\n    }\n  }\n};\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/links.json",
    "content": "{\n  \"title\": \"Welcome\",\n  \"stories\": [\n    {\n      \"name\": \"Welcome\",\n      \"parameters\": {\n        \"server\": {\n          \"id\": \"welcome/welcome\"\n        }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/links.snapshot",
    "content": "\nexport default {\n  title: \"Welcome\",\n};\n\nexport const Welcome = {\n  name: \"Welcome\",\n  parameters: {\n    server: {\n      id: \"welcome/welcome\"\n    }\n  }\n};\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/multiple_stories.json",
    "content": "{\n  \"title\": \"Demo\",\n  \"stories\": [\n    {\n      \"name\": \"Heading\",\n      \"parameters\": {\n        \"server\": { \"id\": \"demo/heading\" }\n      }\n    },\n    {\n      \"name\": \"Headings\",\n      \"parameters\": {\n        \"server\": { \"id\": \"demo/headings\" }\n      }\n    },\n    {\n      \"name\": \"Button\",\n      \"parameters\": {\n        \"server\": { \"id\": \"demo/button\" }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/multiple_stories.snapshot",
    "content": "\nexport default {\n  title: \"Demo\",\n};\n\nexport const Heading = {\n  name: \"Heading\",\n  parameters: {\n    server: {\n      id: \"demo/heading\"\n    }\n  }\n};\n\nexport const Headings = {\n  name: \"Headings\",\n  parameters: {\n    server: {\n      id: \"demo/headings\"\n    }\n  }\n};\n\nexport const Button = {\n  name: \"Button\",\n  parameters: {\n    server: {\n      id: \"demo/button\"\n    }\n  }\n};\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/params.json",
    "content": "{\n  \"title\": \"Params\",\n  \"parameters\": {\n    \"server\": {\n      \"params\": { \"color\": \"red\" },\n      \"1200x600\": { \"viewport\": { \"width\": 1200, \"height\": 600 } }\n    }\n  },\n  \"stories\": [\n    {\n      \"name\": \"Story\",\n      \"parameters\": {\n        \"server\": {\n          \"id\": \"params/story\",\n          \"params\": { \"message\": \"Hello World\" }\n        }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/params.snapshot",
    "content": "\nexport default {\n  title: \"Params\",\n  parameters: {\n    server: {\n      params: {\n        color: \"red\"\n      },\n      1200x600: {\n        viewport: {\n          width: 1200,\n          height: 600\n        }\n      }\n    }\n  }\n};\n\nexport const Story = {\n  name: \"Story\",\n  parameters: {\n    server: {\n      id: \"params/story\",\n      params: {\n        message: \"Hello World\"\n      }\n    }\n  }\n};\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/params_override.json",
    "content": "{\n  \"title\": \"Params\",\n  \"parameters\": {\n    \"server\": {\n      \"params\": { \"color\": \"red\" }\n    }\n  },\n  \"stories\": [\n    {\n      \"name\": \"Override\",\n      \"parameters\": {\n        \"server\": {\n          \"id\": \"params/override\",\n          \"params\": { \"message\": \"Hello World\", \"color\": \"green\" }\n        }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/params_override.snapshot",
    "content": "\nexport default {\n  title: \"Params\",\n  parameters: {\n    server: {\n      params: {\n        color: \"red\"\n      }\n    }\n  }\n};\n\nexport const Override = {\n  name: \"Override\",\n  parameters: {\n    server: {\n      id: \"params/override\",\n      params: {\n        message: \"Hello World\",\n        color: \"green\"\n      }\n    }\n  }\n};\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/yaml.snapshot",
    "content": "\nexport default {\n  title: \"Demo YAML\",\n};\n\nexport const Heading = {\n  name: \"Heading\",\n  parameters: {\n    server: {\n      id: \"yaml/heading\"\n    }\n  }\n};\n\nexport const Headings = {\n  name: \"Headings\",\n  parameters: {\n    server: {\n      id: \"yaml/headings\"\n    }\n  }\n};\n\nexport const Button = {\n  name: \"Button\",\n  parameters: {\n    server: {\n      id: \"yaml/button\"\n    }\n  }\n};\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/yaml.yaml",
    "content": "title: Demo YAML\nstories:\n  - name: Heading\n    parameters:\n      server:\n        id: yaml/heading\n  - name: Headings\n    parameters:\n      server:\n        id: yaml/headings\n  - name: Button\n    parameters:\n      server:\n        id: yaml/button\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/yml.snapshot",
    "content": "\nexport default {\n  title: \"Demo YML\",\n};\n\nexport const Heading = {\n  name: \"Heading\",\n  parameters: {\n    server: {\n      id: \"yaml/heading\"\n    }\n  }\n};\n\nexport const Headings = {\n  name: \"Headings\",\n  parameters: {\n    server: {\n      id: \"yaml/headings\"\n    }\n  }\n};\n\nexport const Button = {\n  name: \"Button\",\n  parameters: {\n    server: {\n      id: \"yaml/button\"\n    }\n  }\n};\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/__testfixtures__/yml.yml",
    "content": "title: Demo YML\nstories:\n  - name: Heading\n    parameters:\n      server:\n        id: yaml/heading\n  - name: Headings\n    parameters:\n      server:\n        id: yaml/headings\n  - name: Button\n    parameters:\n      server:\n        id: yaml/button\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/index.ts",
    "content": "import { stringifySection } from './stringifier.ts';\nimport type {\n  CompileCsfModuleArgs,\n  CompileStorybookSectionArgs,\n  StorybookSection,\n} from './types.ts';\n\nfunction createSection(args: CompileStorybookSectionArgs): StorybookSection {\n  return {\n    imports: {},\n    decorators: [],\n    ...args,\n  };\n}\n\nexport function compileCsfModule(args: CompileCsfModuleArgs): string {\n  return stringifySection(createSection(args));\n}\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/json-to-csf-compiler.test.ts",
    "content": "import { readdirSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { describe, expect, it } from 'vitest';\n\nimport YAML from 'yaml';\n\nimport { compileCsfModule } from './index.ts';\n\nasync function generate(filePath: string) {\n  const content = await readFile(filePath, { encoding: 'utf8' });\n  const parsed = filePath.endsWith('.json') ? JSON.parse(content) : YAML.parse(content);\n  return compileCsfModule(parsed);\n}\n\n['json', 'ya?ml'].forEach((fileType) => {\n  const inputRegExp = new RegExp(`.${fileType}$`);\n\n  describe(`${fileType}-to-csf-compiler`, () => {\n    const transformFixturesDir = join(__dirname, '__testfixtures__');\n    readdirSync(transformFixturesDir)\n      .filter((fileName: string) => inputRegExp.test(fileName))\n      .forEach((fixtureFile: string) => {\n        it(`${fixtureFile}`, async () => {\n          const inputPath = join(transformFixturesDir, fixtureFile);\n          const code = await generate(inputPath);\n          await expect(code).toMatchFileSnapshot(inputPath.replace(inputRegExp, '.snapshot'));\n        });\n      });\n  });\n});\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/stringifier.ts",
    "content": "import { identifier } from 'safe-identifier';\nimport { dedent } from 'ts-dedent';\n\nimport type { StorybookSection, StorybookStory } from './types.ts';\n\nexport function stringifyObject(object: any, level = 0, excludeOuterParams = false): string {\n  if (typeof object === 'string') {\n    return JSON.stringify(object);\n  }\n  const indent = '  '.repeat(level);\n  if (Array.isArray(object)) {\n    const arrayStrings: string[] = object.map((item: any) => stringifyObject(item, level + 1));\n    const arrayString = arrayStrings.join(`,\\n${indent}  `);\n\n    if (excludeOuterParams) {\n      return arrayString;\n    }\n    return `[\\n${indent}  ${arrayString}\\n${indent}]`;\n  }\n  if (typeof object === 'object') {\n    let objectString = '';\n    if (Object.keys(object).length > 0) {\n      const objectStrings: string[] = Object.keys(object).map((key) => {\n        const value: string = stringifyObject(object[key], level + 1);\n        return `\\n${indent}  ${key}: ${value}`;\n      });\n      objectString = objectStrings.join(',');\n    }\n\n    if (excludeOuterParams) {\n      return objectString;\n    }\n\n    if (objectString.length === 0) {\n      return '{}';\n    }\n    return `{${objectString}\\n${indent}}`;\n  }\n\n  return object;\n}\n\nexport function stringifyImports(imports: Record<string, string[]>): string {\n  if (Object.keys(imports).length === 0) {\n    return '';\n  }\n  return Object.entries(imports)\n    .map(([module, names]) => `import { ${names.sort().join(', ')} } from '${module}';\\n`)\n    .join('');\n}\n\nexport function stringifyDecorators(decorators: string[] | undefined): string {\n  return decorators && decorators.length > 0\n    ? `\\n  decorators: [\\n    ${decorators.join(',\\n    ')}\\n  ],`\n    : '';\n}\n\nexport function stringifyDefault(section: StorybookSection): string {\n  const { title, imports, decorators, stories, ...options } = section;\n\n  const decoratorsString = stringifyDecorators(decorators);\n\n  const optionsString = stringifyObject(options, 0, true);\n\n  return dedent`\n  export default {\n    title: ${JSON.stringify(title)},${decoratorsString}${optionsString}\n  };\n  \n  `;\n}\n\nexport function stringifyStory(story: StorybookStory): string {\n  const { name, ...options } = story;\n  const storyId = identifier(name);\n\n  const exportedStory = { name, ...options };\n\n  const storyStrings = [`export const ${storyId} = ${stringifyObject(exportedStory)};`, ''];\n\n  return storyStrings.join('\\n');\n}\n\nexport function stringifySection(section: StorybookSection): string {\n  const sectionString = [\n    stringifyImports(section.imports),\n    stringifyDefault(section),\n    ...section.stories.map((story) => stringifyStory(story)),\n  ].join('\\n');\n\n  return sectionString;\n}\n"
  },
  {
    "path": "code/presets/server-webpack/src/lib/compiler/types.ts",
    "content": "export interface CompileStorybookStoryArgs {\n  name: string;\n  [x: string]: any;\n}\n\nexport interface CompileStorybookSectionArgs {\n  title: string;\n  stories: CompileStorybookStoryArgs[];\n  [x: string]: any;\n}\n\nexport interface CompileCsfModuleArgs extends CompileStorybookSectionArgs {\n  addons?: string[];\n}\n\nexport interface StorybookStory {\n  name: string;\n  decorators?: string[];\n  [x: string]: any;\n}\n\nexport interface StorybookSection {\n  imports: Record<string, string[]>;\n  decorators?: string[];\n  title: string;\n  stories: StorybookStory[];\n  [x: string]: any;\n}\n"
  },
  {
    "path": "code/presets/server-webpack/src/loader.ts",
    "content": "import { compileCsfModule } from './lib/compiler/index.ts';\n\nexport default (content: string) => {\n  try {\n    const after = compileCsfModule(JSON.parse(content));\n    return after;\n  } catch (e) {\n    // for debugging\n    console.log(content, e);\n  }\n  return content;\n};\n"
  },
  {
    "path": "code/presets/server-webpack/src/types.ts",
    "content": "export type { BuilderResult, TypescriptOptions, StorybookConfig } from '@storybook/core-webpack';\n"
  },
  {
    "path": "code/presets/server-webpack/src/typings.d.ts",
    "content": "// will be provided by the webpack define plugin\ndeclare var NODE_ENV: string | undefined;\n"
  },
  {
    "path": "code/presets/server-webpack/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\"]\n}\n"
  },
  {
    "path": "code/presets/server-webpack/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/project.json",
    "content": "{\n  \"name\": \"code\",\n  \"$schema\": \"../node_modules/nx/schemas/project-schema.json\",\n  \"tags\": [\"library\"],\n  \"targets\": {\n    \"fmt\": {\n      \"executor\": \"nx:run-commands\",\n      \"options\": { \"command\": \"yarn fmt:check\" },\n      \"cache\": true,\n      \"inputs\": [\"sharedGlobals\", \"{workspaceRoot}/**/*\"],\n      \"configurations\": { \"production\": {} }\n    },\n    \"lint\": {\n      \"dependsOn\": [{ \"projects\": [\"*\"], \"target\": \"compile\" }],\n      \"executor\": \"nx:run-commands\",\n      \"options\": { \"cwd\": \"{projectRoot}\", \"command\": \"yarn lint\" },\n      \"cache\": true,\n      \"inputs\": [\"default\"],\n      \"configurations\": { \"production\": {} }\n    },\n    \"test\": {\n      \"dependsOn\": [{ \"projects\": [\"*\"], \"target\": \"compile\" }],\n      \"executor\": \"nx:run-commands\",\n      \"options\": { \"command\": \"yarn test\" },\n      \"cache\": true,\n      \"inputs\": [\"default\", \"{workspaceRoot}/vitest.config.ts\"],\n      \"configurations\": { \"production\": {} }\n    },\n    \"knip\": {\n      \"dependsOn\": [{ \"projects\": [\"*\"], \"target\": \"compile\" }],\n      \"executor\": \"nx:run-commands\",\n      \"options\": { \"cwd\": \"{projectRoot}\", \"command\": \"yarn knip --no-exit-code\" },\n      \"cache\": true,\n      \"inputs\": [\"default\"],\n      \"configurations\": { \"production\": {} }\n    }\n  }\n}\n"
  },
  {
    "path": "code/renderers/html/README.md",
    "content": "# Storybook HTML Renderer\n\nDevelop, document, and test UI components in isolation.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/renderers/html/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./entry-preview'],\n        entryPoint: './src/entry-preview.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./entry-preview-docs'],\n        entryPoint: './src/entry-preview-docs.ts',\n        dts: false,\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/renderers/html/package.json",
    "content": "{\n  \"name\": \"@storybook/html\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook HTML renderer: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-renderer\",\n    \"html\",\n    \"component\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/renderers/html\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/renderers/html\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./entry-preview\": \"./dist/entry-preview.js\",\n    \"./entry-preview-docs\": \"./dist/entry-preview-docs.js\",\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"template/cli/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/global\": \"^5.0.0\",\n    \"ts-dedent\": \"^2.0.0\"\n  },\n  \"devDependencies\": {\n    \"typescript\": \"^5.8.3\"\n  },\n  \"peerDependencies\": {\n    \"storybook\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/renderers/html/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/renderers/html/project.json",
    "content": "{\n  \"name\": \"html\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/renderers/html/src/docs/sourceDecorator.test.ts",
    "content": "/** @vitest-environment happy-dom */\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { SNIPPET_RENDERED, SourceType } from 'storybook/internal/docs-tools';\n\nimport { addons, emitTransformCode, useEffect, useRef, useState } from 'storybook/preview-api';\n\nimport { sourceDecorator } from './sourceDecorator';\n\n// Mock the storybook preview-api\nvi.mock('storybook/preview-api', () => ({\n  addons: {\n    getChannel: vi.fn(),\n  },\n  useEffect: vi.fn((fn) => fn()),\n  useRef: vi.fn(),\n  emitTransformCode: vi.fn(),\n}));\n\ndescribe('sourceDecorator', () => {\n  const mockChannel = {\n    emit: vi.fn(),\n  };\n\n  beforeEach(() => {\n    vi.clearAllMocks();\n    vi.mocked(addons.getChannel).mockReturnValue(mockChannel as any);\n    vi.mocked(useRef).mockReturnValue({ current: undefined });\n  });\n\n  it('should not render source for non-args stories', () => {\n    const storyFn = () => '<div>Test Story</div>';\n    const context = {\n      id: 'test-story',\n      parameters: {\n        __isArgsStory: false,\n        docs: { source: {} },\n      },\n      args: {},\n      unmappedArgs: {},\n    };\n\n    sourceDecorator(storyFn, context as any);\n\n    expect(emitTransformCode).not.toHaveBeenCalled();\n  });\n\n  it('should render source for args stories', () => {\n    const storyContent = '<div>Test Story</div>';\n    const storyFn = () => storyContent;\n    const context = {\n      id: 'test-story',\n      parameters: {\n        __isArgsStory: true,\n        docs: { source: {} },\n      },\n      args: {},\n      unmappedArgs: {},\n    };\n\n    sourceDecorator(storyFn, context as any);\n\n    expect(emitTransformCode).toHaveBeenCalledWith(storyContent, context);\n  });\n\n  it('should handle Element type story returns', () => {\n    const element = document.createElement('div');\n    element.innerHTML = 'Test Story';\n    const storyFn = () => element;\n    const context = {\n      id: 'test-story',\n      parameters: {\n        __isArgsStory: true,\n        docs: { source: {} },\n      },\n      args: {},\n      unmappedArgs: {},\n    };\n\n    sourceDecorator(storyFn, context as any);\n\n    expect(emitTransformCode).toHaveBeenCalledWith(element.outerHTML, context);\n  });\n\n  it('should emit SNIPPET_RENDERED event when source is available', () => {\n    const source = '<div>Test Story</div>';\n\n    const storyFn = () => source;\n    const context = {\n      id: 'test-story',\n      parameters: {\n        __isArgsStory: true,\n        docs: { source: {} },\n      },\n      args: {},\n      unmappedArgs: {},\n    };\n\n    sourceDecorator(storyFn, context as any);\n\n    expect(emitTransformCode).toHaveBeenCalledWith(source, context);\n  });\n\n  it('should respect excludeDecorators parameter', () => {\n    const originalStoryContent = '<div>Original Story</div>';\n    const decoratedStoryContent = '<div>Decorated Story</div>';\n    const context = {\n      id: 'test-story',\n      parameters: {\n        __isArgsStory: true,\n        docs: {\n          source: {\n            excludeDecorators: true,\n          },\n        },\n      },\n      args: {},\n      unmappedArgs: {},\n      originalStoryFn: () => originalStoryContent,\n    };\n\n    const storyFn = () => decoratedStoryContent;\n\n    sourceDecorator(storyFn, context as any);\n\n    expect(emitTransformCode).toHaveBeenCalledWith(originalStoryContent, context);\n  });\n\n  it('should skip source render when type is CODE', () => {\n    const storyFn = () => '<div>Test Story</div>';\n    const context = {\n      id: 'test-story',\n      parameters: {\n        __isArgsStory: true,\n        docs: {\n          source: {\n            type: SourceType.CODE,\n            code: 'const x = 1;',\n          },\n        },\n      },\n      args: {},\n      unmappedArgs: {},\n    };\n\n    sourceDecorator(storyFn, context as any);\n\n    expect(emitTransformCode).not.toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "code/renderers/html/src/docs/sourceDecorator.ts",
    "content": "import { SourceType } from 'storybook/internal/docs-tools';\nimport type { DecoratorFunction } from 'storybook/internal/types';\n\nimport { emitTransformCode, useEffect, useRef } from 'storybook/preview-api';\n\nimport type { StoryFn } from '../public-types';\nimport type { HtmlRenderer } from '../types';\n\nfunction skipSourceRender(context: Parameters<DecoratorFunction<HtmlRenderer>>[1]) {\n  const sourceParams = context?.parameters.docs?.source;\n  const isArgsStory = context?.parameters.__isArgsStory;\n\n  // always render if the user forces it\n  if (sourceParams?.type === SourceType.DYNAMIC) {\n    return false;\n  }\n\n  // never render if the user is forcing the block to render code, or\n  // if the user provides code, or if it's not an args story.\n  return !isArgsStory || sourceParams?.code || sourceParams?.type === SourceType.CODE;\n}\n\nexport const sourceDecorator: DecoratorFunction<HtmlRenderer> = (storyFn, context) => {\n  const source = useRef<string | undefined>(undefined);\n  const story = storyFn();\n\n  useEffect(() => {\n    const renderedForSource = context?.parameters.docs?.source?.excludeDecorators\n      ? (context.originalStoryFn as StoryFn)(context.args, context)\n      : story;\n\n    if (!skipSourceRender(context)) {\n      if (typeof renderedForSource === 'string' && source.current !== renderedForSource) {\n        emitTransformCode(renderedForSource, context);\n        source.current = renderedForSource;\n      } else if (\n        renderedForSource instanceof Element &&\n        source.current !== renderedForSource.outerHTML\n      ) {\n        emitTransformCode(renderedForSource.outerHTML, context);\n        source.current = renderedForSource.outerHTML;\n      }\n    }\n  });\n\n  return story;\n};\n"
  },
  {
    "path": "code/renderers/html/src/entry-preview-docs.ts",
    "content": "import { SourceType } from 'storybook/internal/docs-tools';\nimport type { DecoratorFunction } from 'storybook/internal/types';\n\nimport { sourceDecorator } from './docs/sourceDecorator.ts';\nimport type { HtmlRenderer } from './types.ts';\n\nexport const decorators: DecoratorFunction<HtmlRenderer>[] = [sourceDecorator];\n\nexport const parameters = {\n  docs: {\n    story: { inline: true },\n    source: {\n      type: SourceType.DYNAMIC,\n      language: 'html',\n      code: undefined,\n      excludeDecorators: undefined,\n    },\n  },\n};\n"
  },
  {
    "path": "code/renderers/html/src/entry-preview.ts",
    "content": "import { enhanceArgTypes } from 'storybook/internal/docs-tools';\nimport type { ArgTypesEnhancer } from 'storybook/internal/types';\n\nimport type { Parameters } from './types.ts';\n\nexport const parameters: Parameters = { renderer: 'html' };\n\nexport { renderToCanvas, render } from './render.ts';\n\nexport const argTypesEnhancers: ArgTypesEnhancer[] = [enhanceArgTypes];\n"
  },
  {
    "path": "code/renderers/html/src/globals.ts",
    "content": "import { global } from '@storybook/global';\n\nconst { window: globalWindow } = global;\n\nglobalWindow.STORYBOOK_ENV = 'HTML';\n"
  },
  {
    "path": "code/renderers/html/src/index.ts",
    "content": "import './globals.ts';\n\nexport * from './public-types.ts';\nexport * from './portable-stories.ts';\n"
  },
  {
    "path": "code/renderers/html/src/portable-stories.ts",
    "content": "import type {\n  NamedOrDefaultProjectAnnotations,\n  NormalizedProjectAnnotations,\n} from 'storybook/internal/types';\n\nimport {\n  setProjectAnnotations as originalSetProjectAnnotations,\n  setDefaultProjectAnnotations,\n} from 'storybook/preview-api';\n\nimport * as INTERNAL_DEFAULT_PROJECT_ANNOTATIONS from './entry-preview.ts';\nimport type { HtmlRenderer } from './types.ts';\n\n/**\n * Function that sets the globalConfig of your storybook. The global config is the preview module of\n * your .storybook folder.\n *\n * It should be run a single time, so that your global config (e.g. decorators) is applied to your\n * stories when using `composeStories` or `composeStory`.\n *\n * Example:\n *\n * ```jsx\n * // setup-file.js\n * import { setProjectAnnotations } from '@storybook/preact';\n * import projectAnnotations from './.storybook/preview';\n *\n * setProjectAnnotations(projectAnnotations);\n * ```\n *\n * @param projectAnnotations - E.g. (import projectAnnotations from '../.storybook/preview')\n */\nexport function setProjectAnnotations(\n  projectAnnotations:\n    | NamedOrDefaultProjectAnnotations<any>\n    | NamedOrDefaultProjectAnnotations<any>[]\n): NormalizedProjectAnnotations<HtmlRenderer> {\n  setDefaultProjectAnnotations(INTERNAL_DEFAULT_PROJECT_ANNOTATIONS);\n  return originalSetProjectAnnotations(\n    projectAnnotations\n  ) as NormalizedProjectAnnotations<HtmlRenderer>;\n}\n"
  },
  {
    "path": "code/renderers/html/src/preset.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport type { PresetProperty } from 'storybook/internal/types';\n\nexport const previewAnnotations: PresetProperty<'previewAnnotations'> = async (\n  input = [],\n  options\n) => {\n  const docsEnabled = Object.keys(await options.presets.apply('docs', {}, options)).length > 0;\n  const result: string[] = [];\n\n  return result\n    .concat(input)\n    .concat([fileURLToPath(import.meta.resolve('@storybook/html/entry-preview'))])\n    .concat(\n      docsEnabled ? [fileURLToPath(import.meta.resolve('@storybook/html/entry-preview-docs'))] : []\n    );\n};\n"
  },
  {
    "path": "code/renderers/html/src/public-types.ts",
    "content": "import type {\n  AnnotatedStoryFn,\n  Args,\n  ComponentAnnotations,\n  DecoratorFunction,\n  StoryContext as GenericStoryContext,\n  LoaderFunction,\n  ProjectAnnotations,\n  StoryAnnotations,\n  StrictArgs,\n} from 'storybook/internal/types';\n\nimport type { HtmlRenderer } from './types.ts';\n\nexport type { Args, ArgTypes, Parameters, StrictArgs } from 'storybook/internal/types';\nexport type { HtmlRenderer };\n\n/**\n * Metadata to configure the stories for a component.\n *\n * @see [Default export](https://storybook.js.org/docs/api/csf#default-export)\n */\nexport type Meta<TArgs = Args> = ComponentAnnotations<HtmlRenderer, TArgs>;\n\n/**\n * Story function that represents a CSFv2 component example.\n *\n * @see [Named Story exports](https://storybook.js.org/docs/api/csf#named-story-exports)\n */\nexport type StoryFn<TArgs = Args> = AnnotatedStoryFn<HtmlRenderer, TArgs>;\n\n/**\n * Story object that represents a CSFv3 component example.\n *\n * @see [Named Story exports](https://storybook.js.org/docs/api/csf#named-story-exports)\n */\nexport type StoryObj<TArgs = Args> = StoryAnnotations<HtmlRenderer, TArgs>;\n\nexport type Decorator<TArgs = StrictArgs> = DecoratorFunction<HtmlRenderer, TArgs>;\nexport type Loader<TArgs = StrictArgs> = LoaderFunction<HtmlRenderer, TArgs>;\nexport type StoryContext<TArgs = StrictArgs> = GenericStoryContext<HtmlRenderer, TArgs>;\nexport type Preview = ProjectAnnotations<HtmlRenderer>;\n"
  },
  {
    "path": "code/renderers/html/src/render.ts",
    "content": "import type { ArgsStoryFn, RenderContext } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { simulateDOMContentLoaded, simulatePageLoad } from 'storybook/preview-api';\nimport { dedent } from 'ts-dedent';\n\nimport type { HtmlRenderer } from './types.ts';\n\nconst { Node } = global;\n\nexport const render: ArgsStoryFn<HtmlRenderer> = (args, context) => {\n  const { id, component: Component } = context;\n\n  if (typeof Component === 'string') {\n    let output = Component;\n    Object.keys(args).forEach((key) => {\n      output = output.replace(`{{${key}}}`, args[key]);\n    });\n    return output;\n  }\n  if (Component instanceof HTMLElement) {\n    const output = Component.cloneNode(true) as HTMLElement;\n    Object.keys(args).forEach((key) => {\n      output.setAttribute(\n        key,\n        typeof args[key] === 'string' ? args[key] : JSON.stringify(args[key])\n      );\n    });\n\n    return output;\n  }\n  if (typeof Component === 'function') {\n    return Component(args, context);\n  }\n\n  console.warn(dedent`\n    Storybook's HTML renderer only supports rendering DOM elements and strings.\n    Received: ${Component}\n  `);\n  throw new Error(`Unable to render story ${id}`);\n};\n\nexport function renderToCanvas(\n  { storyFn, kind, name, showMain, showError, forceRemount }: RenderContext<HtmlRenderer>,\n  canvasElement: HtmlRenderer['canvasElement']\n) {\n  const element = storyFn();\n  showMain();\n  if (typeof element === 'string') {\n    canvasElement.innerHTML = element;\n    simulatePageLoad(canvasElement);\n  } else if (element instanceof Node) {\n    if (canvasElement.firstChild === element && forceRemount === false) {\n      return;\n    }\n\n    canvasElement.innerHTML = '';\n    canvasElement.appendChild(element);\n    simulateDOMContentLoaded();\n  } else {\n    showError({\n      title: `Expecting an HTML snippet or DOM node from the story: \"${name}\" of \"${kind}\".`,\n      description: dedent`\n        Did you forget to return the HTML snippet from the story?\n        Use \"() => <your snippet or node>\" or when defining the story.\n      `,\n    });\n  }\n}\n"
  },
  {
    "path": "code/renderers/html/src/types.ts",
    "content": "import type { SourceType } from 'storybook/internal/docs-tools';\nimport type {\n  ArgsStoryFn,\n  StoryContext as DefaultStoryContext,\n  WebRenderer,\n} from 'storybook/internal/types';\n\nexport type { RenderContext } from 'storybook/internal/types';\n\nexport type StoryFnHtmlReturnType = string | Node;\n\nexport interface ShowErrorArgs {\n  title: string;\n  description: string;\n}\n\nexport interface HtmlRenderer extends WebRenderer {\n  component: string | HTMLElement | ArgsStoryFn<HtmlRenderer>;\n  storyResult: StoryFnHtmlReturnType;\n}\n\nexport interface Parameters {\n  renderer: 'html';\n  docs?: {\n    story: { inline: boolean };\n    source: {\n      type: SourceType.DYNAMIC;\n      language: 'html';\n      code: any;\n      excludeDecorators: any;\n    };\n  };\n}\n\nexport type StoryContext = DefaultStoryContext<HtmlRenderer> & {\n  parameters: DefaultStoryContext<HtmlRenderer>['parameters'] & Parameters;\n};\n"
  },
  {
    "path": "code/renderers/html/src/typings.d.ts",
    "content": "declare var STORYBOOK_ENV: 'HTML';\n"
  },
  {
    "path": "code/renderers/html/template/cli/.eslintrc.json",
    "content": "{\n  \"rules\": {\n    \"no-undef\": \"off\",\n    \"import/extensions\": \"off\"\n  }\n}\n"
  },
  {
    "path": "code/renderers/html/template/cli/js/Button.js",
    "content": "import './button.css';\n\nexport const createButton = ({\n  primary = false,\n  size = 'medium',\n  backgroundColor,\n  label,\n  onClick,\n}) => {\n  const btn = document.createElement('button');\n  btn.type = 'button';\n  btn.innerText = label;\n  btn.addEventListener('click', onClick);\n\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n  btn.className = ['storybook-button', `storybook-button--${size}`, mode].join(' ');\n\n  btn.style.backgroundColor = backgroundColor;\n\n  return btn;\n};\n"
  },
  {
    "path": "code/renderers/html/template/cli/js/Button.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport { createButton } from './Button';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories\nexport default {\n  title: 'Example/Button',\n  tags: ['autodocs'],\n  render: ({ label, ...args }) => {\n    // You can either use a function to create DOM elements or use a plain html string!\n    // return `<div>${label}</div>`;\n    return createButton({ label, ...args });\n  },\n  argTypes: {\n    backgroundColor: { control: 'color' },\n    label: { control: 'text' },\n    onClick: { action: 'onClick' },\n    primary: { control: 'boolean' },\n    size: {\n      control: { type: 'select' },\n      options: ['small', 'medium', 'large'],\n    },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onClick: fn() },\n};\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/renderers/html/template/cli/js/Header.js",
    "content": "import { createButton } from './Button';\nimport './header.css';\n\nexport const createHeader = ({ user, onLogout, onLogin, onCreateAccount }) => {\n  const header = document.createElement('header');\n\n  const wrapper = document.createElement('div');\n  wrapper.className = 'storybook-header';\n\n  const logo = `<div>\n    <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n      <g fill=\"none\" fillRule=\"evenodd\">\n        <path\n          d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n          fill=\"#FFF\" />\n        <path\n          d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n          fill=\"#555AB9\" />\n        <path d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\" fill=\"#91BAF8\" />\n      </g>\n    </svg>\n    <h1>Acme</h1>\n  </div>`;\n\n  wrapper.insertAdjacentHTML('afterbegin', logo);\n\n  const account = document.createElement('div');\n  if (user) {\n    const welcomeMessage = `<span class=\"welcome\">Welcome, <b>${user.name}</b>!</span>`;\n    account.innerHTML = welcomeMessage;\n    account.appendChild(createButton({ size: 'small', label: 'Log out', onClick: onLogout }));\n  } else {\n    account.appendChild(createButton({ size: 'small', label: 'Log in', onClick: onLogin }));\n    account.appendChild(\n      createButton({\n        size: 'small',\n        label: 'Sign up',\n        onClick: onCreateAccount,\n        primary: true,\n      })\n    );\n  }\n  wrapper.appendChild(account);\n  header.appendChild(wrapper);\n\n  return header;\n};\n"
  },
  {
    "path": "code/renderers/html/template/cli/js/Header.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport { createHeader } from './Header';\n\nexport default {\n  title: 'Example/Header',\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  render: (args) => createHeader(args),\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n};\n\nexport const LoggedIn = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut = {};\n"
  },
  {
    "path": "code/renderers/html/template/cli/js/Page.js",
    "content": "import { createHeader } from './Header';\nimport './page.css';\n\nexport const createPage = () => {\n  const article = document.createElement('article');\n  let user = null;\n  let header = null;\n\n  const rerenderHeader = () => {\n    const wrapper = document.getElementsByTagName('article')[0];\n    wrapper.replaceChild(createHeaderElement(), wrapper.firstChild);\n  };\n\n  const onLogin = () => {\n    user = { name: 'Jane Doe' };\n    rerenderHeader();\n  };\n\n  const onLogout = () => {\n    user = null;\n    rerenderHeader();\n  };\n\n  const onCreateAccount = () => {\n    user = { name: 'Jane Doe' };\n    rerenderHeader();\n  };\n\n  const createHeaderElement = () => {\n    return createHeader({ onLogin, onLogout, onCreateAccount, user });\n  };\n\n  header = createHeaderElement();\n  article.appendChild(header);\n\n  const section = `\n  <section class=\"storybook-page\">\n    <h2>Pages in Storybook</h2>\n    <p>\n      We recommend building UIs with a\n      <a\n        href=\"https://blog.hichroma.com/component-driven-development-ce1109d56c8e\"\n        target=\"_blank\"\n        rel=\"noopener noreferrer\">\n        <strong>component-driven</strong>\n      </a>\n      process starting with atomic components and ending with pages.\n    </p>\n    <p>\n      Render pages with mock data. This makes it easy to build and review page states without\n      needing to navigate to them in your app. Here are some handy patterns for managing page data\n      in Storybook:\n    </p>\n    <ul>\n      <li>\n        Use a higher-level connected component. Storybook helps you compose such data from the\n        \"args\" of child component stories\n      </li>\n      <li>\n        Assemble data in the page component from your services. You can mock these services out\n        using Storybook.\n      </li>\n    </ul>\n    <p>\n      Get a guided tutorial on component-driven development at\n      <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n        Storybook tutorials\n      </a>\n      . Read more in the\n      <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">docs</a>\n      .\n    </p>\n    <div class=\"tip-wrapper\">\n      <span class=\"tip\">Tip</span>\n      Adjust the width of the canvas with the\n      <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n        <g fill=\"none\" fillRule=\"evenodd\">\n          <path\n            d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0\n            01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0\n            010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n            id=\"a\"\n            fill=\"#999\" />\n        </g>\n      </svg>\n      Viewports addon in the toolbar\n    </div>\n  </section>\n`;\n\n  article.insertAdjacentHTML('beforeend', section);\n\n  return article;\n};\n"
  },
  {
    "path": "code/renderers/html/template/cli/js/Page.stories.js",
    "content": "import { expect, userEvent, within } from 'storybook/test';\n\nimport { createPage } from './Page';\n\nexport default {\n  title: 'Example/Page',\n  render: () => createPage(),\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n};\n\nexport const LoggedOut = {};\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await expect(loginButton).not.toBeInTheDocument();\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n"
  },
  {
    "path": "code/renderers/html/template/cli/ts/Button.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/html';\n\nimport { fn } from 'storybook/test';\n\nimport type { ButtonProps } from './Button';\nimport { createButton } from './Button';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export\nconst meta = {\n  title: 'Example/Button',\n  tags: ['autodocs'],\n  render: (args) => {\n    // You can either use a function to create DOM elements or use a plain html string!\n    // return `<div>${label}</div>`;\n    return createButton(args);\n  },\n  argTypes: {\n    backgroundColor: { control: 'color' },\n    label: { control: 'text' },\n    onClick: { action: 'onClick' },\n    primary: { control: 'boolean' },\n    size: {\n      control: { type: 'select' },\n      options: ['small', 'medium', 'large'],\n    },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onClick: fn() },\n} satisfies Meta<ButtonProps>;\n\nexport default meta;\ntype Story = StoryObj<ButtonProps>;\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large: Story = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small: Story = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/renderers/html/template/cli/ts/Button.ts",
    "content": "import './button.css';\n\nexport interface ButtonProps {\n  /** Is this the principal call to action on the page? */\n  primary?: boolean;\n  /** What background color to use */\n  backgroundColor?: string;\n  /** How large should the button be? */\n  size?: 'small' | 'medium' | 'large';\n  /** Button contents */\n  label: string;\n  /** Optional click handler */\n  onClick?: () => void;\n}\n\n/** Primary UI component for user interaction */\nexport const createButton = ({\n  primary = false,\n  size = 'medium',\n  backgroundColor,\n  label,\n  onClick,\n}: ButtonProps) => {\n  const btn = document.createElement('button');\n  btn.type = 'button';\n  btn.innerText = label;\n  if (onClick) {\n    btn.addEventListener('click', onClick);\n  }\n\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n  btn.className = ['storybook-button', `storybook-button--${size}`, mode].join(' ');\n\n  if (backgroundColor) {\n    btn.style.backgroundColor = backgroundColor;\n  }\n\n  return btn;\n};\n"
  },
  {
    "path": "code/renderers/html/template/cli/ts/Header.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/html';\n\nimport { fn } from 'storybook/test';\n\nimport type { HeaderProps } from './Header';\nimport { createHeader } from './Header';\n\nconst meta = {\n  title: 'Example/Header',\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  render: (args) => createHeader(args),\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  // More on argTypes: https://storybook.js.org/docs/api/argtypes\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n} satisfies Meta<HeaderProps>;\n\nexport default meta;\ntype Story = StoryObj<HeaderProps>;\n\nexport const LoggedIn: Story = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut: Story = {};\n"
  },
  {
    "path": "code/renderers/html/template/cli/ts/Header.ts",
    "content": "import { createButton } from './Button';\nimport './header.css';\n\nexport interface HeaderProps {\n  user?: { name: string };\n  onLogin?: () => void;\n  onLogout?: () => void;\n  onCreateAccount?: () => void;\n}\n\nexport const createHeader = ({ user, onLogout, onLogin, onCreateAccount }: HeaderProps) => {\n  const header = document.createElement('header');\n\n  const wrapper = document.createElement('div');\n  wrapper.className = 'storybook-header';\n\n  const logo = `<div>\n    <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n      <g fill=\"none\" fillRule=\"evenodd\">\n        <path\n          d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n          fill=\"#FFF\" />\n        <path\n          d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n          fill=\"#555AB9\" />\n        <path d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\" fill=\"#91BAF8\" />\n      </g>\n    </svg>\n    <h1>Acme</h1>\n  </div>`;\n\n  wrapper.insertAdjacentHTML('afterbegin', logo);\n\n  const account = document.createElement('div');\n  if (user) {\n    const welcomeMessage = `<span class=\"welcome\">Welcome, <b>${user.name}</b>!</span>`;\n    account.innerHTML = welcomeMessage;\n    account.appendChild(createButton({ size: 'small', label: 'Log out', onClick: onLogout }));\n  } else {\n    account.appendChild(createButton({ size: 'small', label: 'Log in', onClick: onLogin }));\n    account.appendChild(\n      createButton({\n        size: 'small',\n        label: 'Sign up',\n        onClick: onCreateAccount,\n        primary: true,\n      })\n    );\n  }\n  wrapper.appendChild(account);\n  header.appendChild(wrapper);\n\n  return header;\n};\n"
  },
  {
    "path": "code/renderers/html/template/cli/ts/Page.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/html';\n\nimport { expect, userEvent, within } from 'storybook/test';\n\nimport { createPage } from './Page';\n\nconst meta = {\n  title: 'Example/Page',\n  render: () => createPage(),\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n} satisfies Meta;\n\nexport default meta;\n\nexport const LoggedOut: StoryObj = {};\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn: StoryObj = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await expect(loginButton).not.toBeInTheDocument();\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n"
  },
  {
    "path": "code/renderers/html/template/cli/ts/Page.ts",
    "content": "import { createHeader } from './Header';\nimport './page.css';\n\ntype User = {\n  name: string;\n};\n\nexport const createPage = () => {\n  const article = document.createElement('article');\n  let user: User | undefined;\n  let header: HTMLElement | null = null;\n\n  const rerenderHeader = () => {\n    const wrapper = document.getElementsByTagName('article')[0];\n    wrapper.replaceChild(createHeaderElement(), wrapper.firstChild as HTMLElement);\n  };\n\n  const onLogin = () => {\n    user = { name: 'Jane Doe' };\n    rerenderHeader();\n  };\n\n  const onLogout = () => {\n    user = undefined;\n    rerenderHeader();\n  };\n\n  const onCreateAccount = () => {\n    user = { name: 'Jane Doe' };\n    rerenderHeader();\n  };\n\n  const createHeaderElement = () => {\n    return createHeader({ onLogin, onLogout, onCreateAccount, user });\n  };\n\n  header = createHeaderElement();\n  article.appendChild(header);\n\n  const section = `\n  <section class=\"storybook-page\">\n    <h2>Pages in Storybook</h2>\n    <p>\n      We recommend building UIs with a\n      <a\n        href=\"https://blog.hichroma.com/component-driven-development-ce1109d56c8e\"\n        target=\"_blank\"\n        rel=\"noopener noreferrer\">\n        <strong>component-driven</strong>\n      </a>\n      process starting with atomic components and ending with pages.\n    </p>\n    <p>\n      Render pages with mock data. This makes it easy to build and review page states without\n      needing to navigate to them in your app. Here are some handy patterns for managing page data\n      in Storybook:\n    </p>\n    <ul>\n      <li>\n        Use a higher-level connected component. Storybook helps you compose such data from the\n        \"args\" of child component stories\n      </li>\n      <li>\n        Assemble data in the page component from your services. You can mock these services out\n        using Storybook.\n      </li>\n    </ul>\n    <p>\n      Get a guided tutorial on component-driven development at\n      <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n        Storybook tutorials\n      </a>\n      . Read more in the\n      <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">docs</a>\n      .\n    </p>\n    <div class=\"tip-wrapper\">\n      <span class=\"tip\">Tip</span>\n      Adjust the width of the canvas with the\n      <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n        <g fill=\"none\" fillRule=\"evenodd\">\n          <path\n            d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0\n            01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0\n            010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n            id=\"a\"\n            fill=\"#999\" />\n        </g>\n      </svg>\n      Viewports addon in the toolbar\n    </div>\n  </section>\n`;\n\n  article.insertAdjacentHTML('beforeend', section);\n\n  return article;\n};\n"
  },
  {
    "path": "code/renderers/html/template/components/Button.js",
    "content": "export const Button = (args) => {\n  const button = document.createElement('button');\n\n  button.innerHTML = args.label;\n  button.addEventListener('click', args.onClick);\n\n  return button;\n};\n"
  },
  {
    "path": "code/renderers/html/template/components/Form.js",
    "content": "export const Form = ({ onSuccess }) => {\n  const container = document.createElement('div');\n\n  const getInnerHTML = ({ complete, value }) => `\n  <form id=\"interaction-test-form\">\n    <label>\n      Enter Value\n      <input type=\"text\" data-testid=\"value\" value=\"${value}\" required />\n    </label>\n    <button type=\"submit\">Submit</button>\n    ${complete ? '<p>Completed!!</p>' : ''}\n  </form>\n`;\n\n  container.innerHTML = getInnerHTML({ complete: false, value: '' });\n\n  const form = container.querySelector('form');\n  form.addEventListener('submit', (e) => {\n    e.preventDefault();\n\n    const { value } = form.querySelector('input'); // Store the current value\n\n    setTimeout(() => {\n      container.innerHTML = getInnerHTML({ complete: true, value });\n    }, 500);\n    setTimeout(() => {\n      container.innerHTML = getInnerHTML({ complete: false, value });\n    }, 1500);\n    onSuccess(value);\n  });\n\n  return container;\n};\n"
  },
  {
    "path": "code/renderers/html/template/components/Html.js",
    "content": "export const Html = `<div>{{content}}</div>`;\n"
  },
  {
    "path": "code/renderers/html/template/components/Pre.js",
    "content": "export const Pre = (args) => {\n  const pre = document.createElement('pre');\n\n  pre.setAttribute('data-testid', 'pre');\n  pre.style = args.style;\n\n  if (args.object) {\n    pre.textContent = JSON.stringify(args.object, null, 2);\n  } else {\n    pre.textContent = args.text;\n  }\n\n  return pre;\n};\n"
  },
  {
    "path": "code/renderers/html/template/components/index.js",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { Button } from './Button';\nimport { Form } from './Form';\nimport { Html } from './Html';\nimport { Pre } from './Pre';\n\nglobalThis.__TEMPLATE_COMPONENTS__ = { Button, Pre, Form, Html };\nglobalThis.storybookRenderer = 'html';\n"
  },
  {
    "path": "code/renderers/html/template/stories/README.md",
    "content": "Placeholder until we write some render-specific stories\n"
  },
  {
    "path": "code/renderers/html/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\", \"template/**/*\"]\n}\n"
  },
  {
    "path": "code/renderers/html/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/renderers/preact/README.md",
    "content": "# Storybook Preact renderer\n\nDevelop, document, and test UI components in isolation.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/renderers/preact/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./entry-preview'],\n        entryPoint: './src/entry-preview.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./entry-preview-docs'],\n        entryPoint: './src/entry-preview-docs.ts',\n        dts: false,\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/renderers/preact/package.json",
    "content": "{\n  \"name\": \"@storybook/preact\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook Preact renderer: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-renderer\",\n    \"preact\",\n    \"components\",\n    \"component\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/renderers/preact\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/renderers/preact\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./entry-preview\": \"./dist/entry-preview.js\",\n    \"./entry-preview-docs\": \"./dist/entry-preview-docs.js\",\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"template/cli/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/global\": \"^5.0.0\",\n    \"ts-dedent\": \"^2.0.0\"\n  },\n  \"devDependencies\": {\n    \"preact\": \"^10.5.13\",\n    \"typescript\": \"^5.8.3\"\n  },\n  \"peerDependencies\": {\n    \"preact\": \"^8.0.0||^10.0.0\",\n    \"storybook\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/renderers/preact/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/renderers/preact/project.json",
    "content": "{\n  \"name\": \"preact\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/renderers/preact/src/entry-preview-docs.ts",
    "content": "export const parameters = {\n  docs: {\n    story: { inline: true },\n  },\n};\n"
  },
  {
    "path": "code/renderers/preact/src/entry-preview.ts",
    "content": "export { renderToCanvas, render } from './render.tsx';\n\nexport const parameters = { renderer: 'preact' };\n"
  },
  {
    "path": "code/renderers/preact/src/globals.ts",
    "content": "import { global } from '@storybook/global';\n\nconst { window: globalWindow } = global;\n\nif (globalWindow) {\n  globalWindow.STORYBOOK_ENV = 'preact';\n}\n"
  },
  {
    "path": "code/renderers/preact/src/index.ts",
    "content": "import './globals.ts';\n\nexport * from './public-types.ts';\nexport * from './portable-stories.ts';\n"
  },
  {
    "path": "code/renderers/preact/src/portable-stories.ts",
    "content": "import type {\n  NamedOrDefaultProjectAnnotations,\n  NormalizedProjectAnnotations,\n} from 'storybook/internal/types';\n\nimport {\n  setProjectAnnotations as originalSetProjectAnnotations,\n  setDefaultProjectAnnotations,\n} from 'storybook/preview-api';\n\nimport * as INTERNAL_DEFAULT_PROJECT_ANNOTATIONS from './entry-preview.ts';\nimport type { PreactRenderer } from './types.ts';\n\n/**\n * Function that sets the globalConfig of your storybook. The global config is the preview module of\n * your .storybook folder.\n *\n * It should be run a single time, so that your global config (e.g. decorators) is applied to your\n * stories when using `composeStories` or `composeStory`.\n *\n * Example:\n *\n * ```jsx\n * // setup-file.js\n * import { setProjectAnnotations } from '@storybook/preact';\n * import projectAnnotations from './.storybook/preview';\n *\n * setProjectAnnotations(projectAnnotations);\n * ```\n *\n * @param projectAnnotations - E.g. (import projectAnnotations from '../.storybook/preview')\n */\nexport function setProjectAnnotations(\n  projectAnnotations:\n    | NamedOrDefaultProjectAnnotations<any>\n    | NamedOrDefaultProjectAnnotations<any>[]\n): NormalizedProjectAnnotations<PreactRenderer> {\n  setDefaultProjectAnnotations(INTERNAL_DEFAULT_PROJECT_ANNOTATIONS);\n  return originalSetProjectAnnotations(\n    projectAnnotations\n  ) as NormalizedProjectAnnotations<PreactRenderer>;\n}\n"
  },
  {
    "path": "code/renderers/preact/src/preset.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport type { PresetProperty } from 'storybook/internal/types';\n\nexport const previewAnnotations: PresetProperty<'previewAnnotations'> = async (\n  input = [],\n  options\n) => {\n  const docsEnabled = Object.keys(await options.presets.apply('docs', {}, options)).length > 0;\n  const result: string[] = [];\n\n  return result\n    .concat(input)\n    .concat([fileURLToPath(import.meta.resolve('@storybook/preact/entry-preview'))])\n    .concat(\n      docsEnabled\n        ? [fileURLToPath(import.meta.resolve('@storybook/preact/entry-preview-docs'))]\n        : []\n    );\n};\n\n/**\n * Alias react and react-dom to preact/compat similar to the preact vite preset\n * https://github.com/preactjs/preset-vite/blob/main/src/index.ts#L238-L239\n */\nexport const resolvedReact = async (existing: any) => {\n  try {\n    return {\n      ...existing,\n      react: 'preact/compat',\n      reactDom: 'preact/compat',\n    };\n  } catch (e) {\n    return existing;\n  }\n};\n\nexport const optimizeViteDeps = ['preact/compat/jsx-runtime', '@storybook/react-dom-shim'];\n"
  },
  {
    "path": "code/renderers/preact/src/public-types.test.tsx",
    "content": "// @vitest-environment happy-dom\n/** @jsxImportSource preact */\n// this file tests TypeScript types — that's why there are no runtime assertions\nimport { describe, it } from 'vitest';\n\nimport { satisfies } from 'storybook/internal/common';\nimport type { Args, StoryAnnotations, StrictArgs } from 'storybook/internal/types';\n\nimport { expectTypeOf } from 'expect-type';\nimport { h } from 'preact';\nimport type { FunctionComponent } from 'preact';\nimport { fn } from 'storybook/test';\nimport type { Mock } from 'storybook/test';\nimport type { SetOptional } from 'type-fest';\n\nimport type { Decorator, Meta, StoryObj } from './public-types.ts';\nimport type { PreactRenderer } from './types.ts';\n\ntype PreactStory<TArgs, TRequiredArgs> = StoryAnnotations<PreactRenderer, TArgs, TRequiredArgs>;\n\ntype ButtonProps = { label: string; disabled: boolean };\nconst Button: FunctionComponent<ButtonProps> = () => h('div', null);\n\ndescribe('Meta correctly extracts props from component types', () => {\n  it('✅ Meta<typeof Component> extracts component props', () => {\n    const meta = satisfies<Meta<typeof Button>>()({\n      component: Button,\n      args: { label: 'good', disabled: false },\n    });\n\n    expectTypeOf(meta.args).toMatchTypeOf<Partial<ButtonProps>>();\n  });\n\n  it('✅ Meta<Props> still works when passing props directly', () => {\n    const meta = satisfies<Meta<ButtonProps>>()({\n      component: Button,\n      args: { label: 'good', disabled: false },\n    });\n\n    expectTypeOf(meta.args).toMatchTypeOf<Partial<ButtonProps>>();\n  });\n\n  it('✅ Meta can be used without generic', () => {\n    expectTypeOf({ component: Button }).toMatchTypeOf<Meta>();\n  });\n});\n\ndescribe('Args can be provided in multiple ways', () => {\n  it('✅ All required args may be provided in meta', () => {\n    const meta = satisfies<Meta<typeof Button>>()({\n      component: Button,\n      args: { label: 'good', disabled: false },\n    });\n\n    type Story = StoryObj<typeof meta>;\n    const Basic: Story = {};\n\n    expectTypeOf(Basic).toEqualTypeOf<\n      PreactStory<ButtonProps, SetOptional<ButtonProps, 'label' | 'disabled'>>\n    >();\n  });\n\n  it('✅ Required args may be provided partial in meta and the story', () => {\n    const meta = satisfies<Meta<typeof Button>>()({\n      component: Button,\n      args: { label: 'good' },\n    });\n    const Basic: StoryObj<typeof meta> = {\n      args: { disabled: false },\n    };\n\n    type Expected = PreactStory<ButtonProps, SetOptional<ButtonProps, 'label'>>;\n    expectTypeOf(Basic).toEqualTypeOf<Expected>();\n  });\n\n  it('❌ The combined shape of meta args and story args must match the required args.', () => {\n    {\n      const meta = satisfies<Meta<typeof Button>>()({ component: Button });\n      const Basic: StoryObj<typeof meta> = {\n        // @ts-expect-error disabled not provided ❌\n        args: { label: 'good' },\n      };\n\n      type Expected = PreactStory<ButtonProps, ButtonProps>;\n      expectTypeOf(Basic).toEqualTypeOf<Expected>();\n    }\n    {\n      const meta = satisfies<Meta<typeof Button>>()({\n        component: Button,\n        args: { label: 'good' },\n      });\n      // @ts-expect-error disabled not provided ❌\n      const Basic: StoryObj<typeof meta> = {};\n\n      type Expected = PreactStory<ButtonProps, SetOptional<ButtonProps, 'label'>>;\n      expectTypeOf(Basic).toEqualTypeOf<Expected>();\n    }\n    {\n      const meta = satisfies<Meta<ButtonProps>>()({ component: Button });\n      const Basic: StoryObj<typeof meta> = {\n        // @ts-expect-error disabled not provided ❌\n        args: { label: 'good' },\n      };\n\n      type Expected = PreactStory<ButtonProps, ButtonProps>;\n      expectTypeOf(Basic).toEqualTypeOf<Expected>();\n    }\n  });\n\n  it('Component can be used as generic parameter for StoryObj', () => {\n    type Expected = PreactStory<ButtonProps, Partial<ButtonProps>>;\n    expectTypeOf<StoryObj<typeof Button>>().toEqualTypeOf<Expected>();\n  });\n});\n\nit('StoryObj<typeof meta> is allowed when meta is upcasted to Meta<Props>', () => {\n  expectTypeOf<StoryObj<Meta<ButtonProps>>>().toEqualTypeOf<\n    PreactStory<ButtonProps, Partial<ButtonProps>>\n  >();\n});\n\nit('StoryObj<typeof meta> is allowed when meta is upcasted to Meta<typeof Cmp>', () => {\n  expectTypeOf<StoryObj<Meta<typeof Button>>>().toEqualTypeOf<\n    PreactStory<ButtonProps, Partial<ButtonProps>>\n  >();\n});\n\nit('StoryObj<typeof meta> is allowed when all arguments are optional', () => {\n  expectTypeOf<StoryObj<Meta<{ label?: string }>>>().toEqualTypeOf<\n    PreactStory<{ label?: string }, { label?: string }>\n  >();\n});\n\nit('Props can be defined as interfaces, issue #21768', () => {\n  interface Props {\n    label: string;\n  }\n\n  const Component: FunctionComponent<Props> = ({ label }) => h('span', null, label);\n\n  const withDecorator: Decorator = (Story) => h(Story, null);\n\n  const meta = {\n    component: Component,\n    args: {\n      label: 'label',\n    },\n    decorators: [withDecorator],\n  } satisfies Meta<Props>;\n\n  const Basic: StoryObj<typeof meta> = {};\n\n  type Expected = PreactStory<Props, SetOptional<Props, 'label'>>;\n  expectTypeOf(Basic).toEqualTypeOf<Expected>();\n});\n\nit('Components without Props can be used, issue #21768', () => {\n  const Component: FunctionComponent = () => h('div', null);\n  const withDecorator: Decorator = (Story) => h(Story, null);\n\n  const meta = {\n    component: Component,\n    decorators: [withDecorator],\n  } satisfies Meta<typeof Component>;\n\n  const Basic: StoryObj<typeof meta> = {};\n\n  type Expected = PreactStory<{}, {}>;\n  expectTypeOf(Basic).toEqualTypeOf<Expected>();\n});\n\ndescribe('Story args can be inferred', () => {\n  it('Correct args are inferred when type is widened for render function', () => {\n    type ThemeData = 'light' | 'dark';\n    type Props = ButtonProps & { theme: ThemeData };\n\n    const meta = satisfies<Meta<Props>>()({\n      component: Button,\n      args: { disabled: false },\n      render: (args) => {\n        return h('div', null, args.label);\n      },\n    });\n\n    const Basic: StoryObj<typeof meta> = { args: { theme: 'light', label: 'good' } };\n\n    type Expected = PreactStory<Props, SetOptional<Props, 'disabled'>>;\n    expectTypeOf(Basic).toMatchTypeOf<Expected>();\n  });\n\n  const withDecorator: Decorator<{ decoratorArg: number }> = (Story, { args }) => h(Story, null);\n\n  it('Correct args are inferred when type is widened for decorators', () => {\n    type Props = ButtonProps & { decoratorArg: number };\n\n    const meta = satisfies<Meta<Props>>()({\n      component: Button,\n      args: { disabled: false },\n      decorators: [withDecorator],\n    });\n\n    const Basic: StoryObj<typeof meta> = { args: { decoratorArg: 0, label: 'good' } };\n\n    type Expected = PreactStory<Props, SetOptional<Props, 'disabled'>>;\n    expectTypeOf(Basic).toEqualTypeOf<Expected>();\n  });\n});\n\nit('Infer mock function given to args in meta.', () => {\n  type Props = { label: string; onClick: () => void; onRender: () => void };\n  const TestButton: FunctionComponent<Props> = () => h('div', null);\n\n  const meta = {\n    component: TestButton,\n    args: { label: 'label', onClick: fn(), onRender: () => {} },\n  } satisfies Meta<typeof TestButton>;\n\n  type Story = StoryObj<typeof meta>;\n\n  const Basic: Story = {\n    play: async ({ args }) => {\n      expectTypeOf(args.onClick).toEqualTypeOf<Mock>();\n      expectTypeOf(args.onRender).toEqualTypeOf<() => void>();\n    },\n  };\n  type Expected = StoryAnnotations<PreactRenderer, Props & { onClick: Mock }, Partial<Props>>;\n\n  expectTypeOf(Basic).toEqualTypeOf<Expected>();\n});\n"
  },
  {
    "path": "code/renderers/preact/src/public-types.ts",
    "content": "import type {\n  AnnotatedStoryFn,\n  Args,\n  ArgsFromMeta,\n  ArgsStoryFn,\n  ComponentAnnotations,\n  DecoratorFunction,\n  StoryContext as GenericStoryContext,\n  LoaderFunction,\n  ProjectAnnotations,\n  StoryAnnotations,\n  StrictArgs,\n} from 'storybook/internal/types';\n\nimport type { ComponentProps, ComponentType } from 'preact';\nimport type { SetOptional, Simplify } from 'type-fest';\n\nimport type { PreactRenderer } from './types.ts';\n\nexport type { Args, ArgTypes, Parameters, StrictArgs } from 'storybook/internal/types';\nexport type { PreactRenderer };\n\n/**\n * Metadata to configure the stories for a component.\n *\n * @see [Default export](https://storybook.js.org/docs/api/csf#default-export)\n */\nexport type Meta<TCmpOrArgs = Args> = [TCmpOrArgs] extends [ComponentType<any>]\n  ? ComponentAnnotations<PreactRenderer, ComponentProps<TCmpOrArgs>>\n  : ComponentAnnotations<PreactRenderer, TCmpOrArgs>;\n\n/**\n * Story function that represents a CSFv2 component example.\n *\n * @see [Named Story exports](https://storybook.js.org/docs/api/csf#named-story-exports)\n */\nexport type StoryFn<TCmpOrArgs = Args> = [TCmpOrArgs] extends [ComponentType<any>]\n  ? AnnotatedStoryFn<PreactRenderer, ComponentProps<TCmpOrArgs>>\n  : AnnotatedStoryFn<PreactRenderer, TCmpOrArgs>;\n\n/**\n * Story object that represents a CSFv3 component example.\n *\n * @see [Named Story exports](https://storybook.js.org/docs/api/csf#named-story-exports)\n */\nexport type StoryObj<TMetaOrCmpOrArgs = Args> = [TMetaOrCmpOrArgs] extends [\n  {\n    render?: ArgsStoryFn<PreactRenderer, any>;\n    component?: infer Component;\n    args?: infer DefaultArgs;\n  },\n]\n  ? Simplify<\n      (Component extends ComponentType<any> ? ComponentProps<Component> : unknown) &\n        ArgsFromMeta<PreactRenderer, TMetaOrCmpOrArgs>\n    > extends infer TArgs\n    ? StoryAnnotations<\n        PreactRenderer,\n        AddMocks<TArgs, DefaultArgs>,\n        SetOptional<TArgs, keyof TArgs & keyof DefaultArgs>\n      >\n    : never\n  : TMetaOrCmpOrArgs extends ComponentType<any>\n    ? StoryAnnotations<PreactRenderer, ComponentProps<TMetaOrCmpOrArgs>>\n    : StoryAnnotations<PreactRenderer, TMetaOrCmpOrArgs>;\n\n// This performs a downcast to function types that are mocks, when a mock fn is given to meta args.\nexport type AddMocks<TArgs, DefaultArgs> = Simplify<{\n  [T in keyof TArgs]: T extends keyof DefaultArgs\n    ? DefaultArgs[T] extends (...args: any) => any & { mock: {} } // allow any function with a mock object\n      ? DefaultArgs[T]\n      : TArgs[T]\n    : TArgs[T];\n}>;\n\nexport type Decorator<TArgs = StrictArgs> = DecoratorFunction<PreactRenderer, TArgs>;\nexport type Loader<TArgs = StrictArgs> = LoaderFunction<PreactRenderer, TArgs>;\nexport type StoryContext<TArgs = StrictArgs> = GenericStoryContext<PreactRenderer, TArgs>;\nexport type Preview = ProjectAnnotations<PreactRenderer>;\n"
  },
  {
    "path": "code/renderers/preact/src/render.tsx",
    "content": "/** @jsx h */\nimport type { ArgsStoryFn, RenderContext } from 'storybook/internal/types';\n\nimport * as preact from 'preact';\nimport { dedent } from 'ts-dedent';\n\nimport type { PreactRenderer, StoryFnPreactReturnType } from './types.ts';\n\nconst { h } = preact;\n\nexport const render: ArgsStoryFn<PreactRenderer> = (args, context) => {\n  const { id, component: Component } = context;\n  if (!Component) {\n    throw new Error(\n      `Unable to render story ${id} as the component annotation is missing from the default export`\n    );\n  }\n\n  return h(Component, args);\n};\n\nlet renderedStory: Element;\n\nfunction preactRender(story: StoryFnPreactReturnType | null, canvasElement: Element): void {\n  // @ts-expect-error (Converted from ts-ignore)\n  if (preact.Fragment) {\n    // Preact 10 only:\n    preact.render(story, canvasElement);\n  } else {\n    renderedStory = preact.render(story, canvasElement, renderedStory) as unknown as Element;\n  }\n}\n\nconst StoryHarness: preact.FunctionalComponent<{\n  name: string;\n  title: string;\n  showError: RenderContext<PreactRenderer>['showError'];\n  storyFn: () => any;\n  canvasElement: PreactRenderer['canvasElement'];\n}> = ({ showError, name, title, storyFn, canvasElement }) => {\n  const content = preact.h(storyFn as any, null);\n  if (!content) {\n    showError({\n      title: `Expecting a Preact element from the story: \"${name}\" of \"${title}\".`,\n      description: dedent`\n        Did you forget to return the Preact element from the story?\n        Use \"() => (<MyComp/>)\" or \"() => { return <MyComp/>; }\" when defining the story.\n      `,\n    });\n    return null;\n  }\n  return content;\n};\n\nexport function renderToCanvas(\n  { storyFn, title, name, showMain, showError, forceRemount }: RenderContext<PreactRenderer>,\n  canvasElement: PreactRenderer['canvasElement']\n) {\n  if (forceRemount) {\n    preactRender(null, canvasElement);\n  }\n\n  showMain();\n\n  preactRender(\n    preact.h(StoryHarness, { name, title, showError, storyFn, canvasElement }),\n    canvasElement\n  );\n}\n"
  },
  {
    "path": "code/renderers/preact/src/types.ts",
    "content": "import type { WebRenderer } from 'storybook/internal/types';\n\nimport type { AnyComponent } from 'preact';\n\nexport type { RenderContext } from 'storybook/internal/types';\n\nexport type StoryFnPreactReturnType = string | Node | preact.JSX.Element;\n\nexport interface ShowErrorArgs {\n  title: string;\n  description: string;\n}\n\nexport interface PreactRenderer extends WebRenderer {\n  component: AnyComponent<this['T'], any>;\n  storyResult: StoryFnPreactReturnType;\n}\n"
  },
  {
    "path": "code/renderers/preact/src/typings.d.ts",
    "content": "declare var STORYBOOK_ENV: 'preact';\n"
  },
  {
    "path": "code/renderers/preact/template/cli/.eslintrc.json",
    "content": "{\n  \"rules\": {\n    \"import/extensions\": \"off\",\n    \"react/react-in-jsx-scope\": \"off\"\n  }\n}\n"
  },
  {
    "path": "code/renderers/preact/template/cli/Button.jsx",
    "content": "import './button.css';\n\n/**\n * Primary UI component for user interaction\n *\n * @param {object} props\n * @param {string} [props.primary=false] Default is `false`\n * @param {string} [props.backgroundColor]\n * @param {'small' | 'medium' | 'large'} [props.size='medium'] Default is `'medium'`\n * @param {string} props.label\n * @param {function} props.onClick\n */\nexport const Button = ({\n  primary = false,\n  backgroundColor = null,\n  size = 'medium',\n  label,\n  ...props\n}) => {\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n  return (\n    <button\n      type=\"button\"\n      className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n      style={backgroundColor && { backgroundColor }}\n      {...props}\n    >\n      {label}\n    </button>\n  );\n};\n"
  },
  {
    "path": "code/renderers/preact/template/cli/Button.stories.jsx",
    "content": "import { fn } from 'storybook/test';\n\nimport { Button } from './Button';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories\nexport default {\n  title: 'Example/Button',\n  component: Button,\n  tags: ['autodocs'],\n  argTypes: {\n    backgroundColor: { control: 'color' },\n    onClick: { action: 'onClick' },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onClick: fn() },\n};\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/renderers/preact/template/cli/Header.jsx",
    "content": "import { Button } from './Button';\nimport './header.css';\n\n/**\n * Header component\n *\n * @param {object} props\n * @param {object} [props.user]\n * @param {string} props.user.name\n * @param {function} props.onLogin\n * @param {function} props.onLogout\n * @param {function} props.onCreateAccount\n */\nexport const Header = ({ user = null, onLogin, onLogout, onCreateAccount }) => (\n  <header>\n    <div className=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        {user ? (\n          <>\n            <span className=\"welcome\">\n              Welcome, <b>{user.name}</b>!\n            </span>\n            <Button size=\"small\" onClick={onLogout} label=\"Log out\" />\n          </>\n        ) : (\n          <>\n            <Button size=\"small\" onClick={onLogin} label=\"Log in\" />\n            <Button primary size=\"small\" onClick={onCreateAccount} label=\"Sign up\" />\n          </>\n        )}\n      </div>\n    </div>\n  </header>\n);\n"
  },
  {
    "path": "code/renderers/preact/template/cli/Header.stories.jsx",
    "content": "import { fn } from 'storybook/test';\n\nimport { Header } from './Header';\n\nexport default {\n  title: 'Example/Header',\n  component: Header,\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n};\n\nexport const LoggedIn = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut = {};\n"
  },
  {
    "path": "code/renderers/preact/template/cli/Page.jsx",
    "content": "import { useState } from 'preact/hooks';\n\nimport { Header } from './Header';\nimport './page.css';\n\n/** Simple page component */\nexport const Page = () => {\n  const [user, setUser] = useState();\n\n  return (\n    <article>\n      <Header\n        user={user}\n        onLogin={() => setUser({ name: 'Jane Doe' })}\n        onLogout={() => setUser(undefined)}\n        onCreateAccount={() => setUser({ name: 'Jane Doe' })}\n      />\n\n      <section className=\"storybook-page\">\n        <h2>Pages in Storybook</h2>\n        <p>\n          We recommend building UIs with a{' '}\n          <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n            <strong>component-driven</strong>\n          </a>{' '}\n          process starting with atomic components and ending with pages.\n        </p>\n        <p>\n          Render pages with mock data. This makes it easy to build and review page states without\n          needing to navigate to them in your app. Here are some handy patterns for managing page\n          data in Storybook:\n        </p>\n        <ul>\n          <li>\n            Use a higher-level connected component. Storybook helps you compose such data from the\n            \"args\" of child component stories\n          </li>\n          <li>\n            Assemble data in the page component from your services. You can mock these services out\n            using Storybook.\n          </li>\n        </ul>\n        <p>\n          Get a guided tutorial on component-driven development at{' '}\n          <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n            Storybook tutorials\n          </a>\n          . Read more in the{' '}\n          <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">\n            docs\n          </a>\n          .\n        </p>\n        <div className=\"tip-wrapper\">\n          <span className=\"tip\">Tip</span> Adjust the width of the canvas with the{' '}\n          <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n            <g fill=\"none\" fillRule=\"evenodd\">\n              <path\n                d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n                id=\"a\"\n                fill=\"#999\"\n              />\n            </g>\n          </svg>\n          Viewports addon in the toolbar\n        </div>\n      </section>\n    </article>\n  );\n};\n"
  },
  {
    "path": "code/renderers/preact/template/cli/Page.stories.jsx",
    "content": "import { userEvent, within } from 'storybook/test';\n\nimport { Page } from './Page';\n\nexport default {\n  title: 'Example/Page',\n  component: Page,\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n};\n\nexport const LoggedOut = {};\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = await canvas.getByRole('button', {\n      name: /Log in/i,\n    });\n    await userEvent.click(loginButton);\n  },\n};\n"
  },
  {
    "path": "code/renderers/preact/template/components/Button.jsx",
    "content": "/**\n * Button component\n *\n * @param {object} props\n * @param {string} props.label\n * @param {function} props.onClick\n */\nexport const Button = ({ onClick, label }) => (\n  <button type=\"button\" onClick={onClick}>\n    {label}\n  </button>\n);\n"
  },
  {
    "path": "code/renderers/preact/template/components/Form.jsx",
    "content": "import { useState } from 'preact/hooks';\n\n/**\n * Header component\n *\n * @param {object} props\n * @param {object} [props.user]\n * @param {string} props.user.name\n * @param {function} props.onLogin\n * @param {function} props.onLogout\n * @param {function} props.onCreateAccount\n */\nexport const Form = ({ onSuccess }) => {\n  const [value, setValue] = useState('');\n  const [complete, setComplete] = useState(false);\n\n  function onSubmit(event) {\n    event.preventDefault();\n    onSuccess(value);\n\n    setTimeout(() => setComplete(true), 500);\n    setTimeout(() => setComplete(false), 1500);\n  }\n\n  return (\n    <form id=\"interaction-test-form\" onSubmit={onSubmit}>\n      <label>\n        Enter Value\n        <input\n          type=\"text\"\n          data-testid=\"value\"\n          value={value}\n          required\n          onInput={(event) => setValue(event.target.value)}\n        />\n      </label>\n      <button type=\"submit\">Submit</button>\n      {complete && <p>Completed!!</p>}\n    </form>\n  );\n};\n"
  },
  {
    "path": "code/renderers/preact/template/components/Html.jsx",
    "content": "export const Html = ({ content }) => <div dangerouslySetInnerHTML={{ __html: content }} />;\n"
  },
  {
    "path": "code/renderers/preact/template/components/Pre.jsx",
    "content": "/**\n * Pre component\n *\n * @param {object} props\n * @param {object} [props.style]\n * @param {object} [props.object]\n * @param {string} [props.text]\n */\nexport const Pre = ({ style, object, text }) => (\n  <pre style={style} data-testid=\"pre\">\n    {object ? JSON.stringify(object, null, 2) : text}\n  </pre>\n);\n"
  },
  {
    "path": "code/renderers/preact/template/components/index.js",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { Button } from './Button.jsx';\nimport { Form } from './Form.jsx';\nimport { Html } from './Html.jsx';\nimport { Pre } from './Pre.jsx';\n\nglobalThis.__TEMPLATE_COMPONENTS__ = { Button, Pre, Form, Html };\nglobalThis.storybookRenderer = 'preact';\n"
  },
  {
    "path": "code/renderers/preact/template/stories/React.jsx",
    "content": "import React from 'react';\n\n/**\n * ReactFunctionalComponent component\n *\n * @param {object} props\n * @param {string} props.label\n */\nexport const ReactFunctionalComponent = ({ label }) => {\n  const [clicks, setValue] = React.useState(0);\n  return (\n    <div\n      tabIndex={0}\n      onClick={() => setValue(clicks + 1)}\n      style={{ cursor: 'pointer' }}\n      onKeyDown={() => undefined}\n      role=\"button\"\n    >\n      <div style={{ color: 'red' }}>{label}</div>\n      <div>Clicked {clicks} times.</div>\n    </div>\n  );\n};\n\n/**\n * ReactClassComponent component\n *\n * @param {object} props\n * @param {string} props.label\n */\nexport class ReactClassComponent extends React.Component {\n  state = {\n    clicks: 0,\n  };\n\n  render() {\n    const { label } = this.props;\n    const { clicks } = this.state;\n    return (\n      <div\n        tabIndex={0}\n        onClick={() => this.setState({ clicks: clicks + 1 })}\n        onKeyDown={() => undefined}\n        style={{ cursor: 'pointer' }}\n        role=\"button\"\n      >\n        <div style={{ color: 'green' }}>{label}</div>\n        <div>Clicked {clicks} times.</div>\n      </div>\n    );\n  }\n}\n"
  },
  {
    "path": "code/renderers/preact/template/stories/react-compat.stories.jsx",
    "content": "import { ReactClassComponent, ReactFunctionalComponent } from './React.jsx';\n\nexport default {\n  component: ReactFunctionalComponent,\n};\n\nexport const ReactComponentDemo = () => (\n  <div>\n    <h1>React component demo</h1>\n    <ReactFunctionalComponent label=\"This is a React functional component rendered by Preact\" />\n    <hr />\n    <ReactClassComponent label=\"This is a React class component rendered by Preact\" />\n  </div>\n);\n"
  },
  {
    "path": "code/renderers/preact/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\", \"template/**/*\"]\n}\n"
  },
  {
    "path": "code/renderers/preact/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/renderers/react/README.md",
    "content": "# Storybook React renderer\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/renderers/react/__mocks__/fs/promises.cjs",
    "content": "const { fs } = require('memfs');\nmodule.exports = fs.promises;\n"
  },
  {
    "path": "code/renderers/react/__mocks__/fs.cjs",
    "content": "const { fs } = require('memfs');\nmodule.exports = fs;\n"
  },
  {
    "path": "code/renderers/react/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./preview'],\n        entryPoint: './src/preview.tsx',\n      },\n      {\n        exportEntries: ['./entry-preview'],\n        entryPoint: './src/entry-preview.tsx',\n        dts: false,\n      },\n      {\n        exportEntries: ['./entry-preview-argtypes'],\n        entryPoint: './src/entry-preview-argtypes.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./entry-preview-docs'],\n        entryPoint: './src/entry-preview-docs.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./entry-preview-rsc'],\n        entryPoint: './src/entry-preview-rsc.tsx',\n        dts: false,\n      },\n      {\n        exportEntries: ['./experimental-playwright'],\n        entryPoint: './src/playwright.ts',\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/renderers/react/package.json",
    "content": "{\n  \"name\": \"@storybook/react\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook React renderer\",\n  \"keywords\": [\n    \"storybook\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/renderers/react\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/renderers/react\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./entry-preview\": \"./dist/entry-preview.js\",\n    \"./entry-preview-argtypes\": \"./dist/entry-preview-argtypes.js\",\n    \"./entry-preview-docs\": \"./dist/entry-preview-docs.js\",\n    \"./entry-preview-rsc\": \"./dist/entry-preview-rsc.js\",\n    \"./experimental-playwright\": {\n      \"types\": \"./dist/playwright.d.ts\",\n      \"code\": \"./src/playwright.ts\",\n      \"default\": \"./dist/playwright.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\",\n    \"./preview\": {\n      \"types\": \"./dist/preview.d.ts\",\n      \"code\": \"./src/preview.tsx\",\n      \"default\": \"./dist/preview.js\"\n    }\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"template/cli/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/global\": \"^5.0.0\",\n    \"@storybook/react-dom-shim\": \"workspace:*\",\n    \"react-docgen\": \"^8.0.2\",\n    \"react-docgen-typescript\": \"^2.2.2\"\n  },\n  \"devDependencies\": {\n    \"@types/babel-plugin-react-docgen\": \"^4.2.3\",\n    \"@types/escodegen\": \"^0.0.6\",\n    \"@types/estree\": \"^1.0.6\",\n    \"@types/node\": \"^22.19.1\",\n    \"@volar/language-core\": \"~2.4.28\",\n    \"@volar/typescript\": \"~2.4.28\",\n    \"acorn\": \"^7.4.1\",\n    \"acorn-jsx\": \"^5.3.1\",\n    \"acorn-walk\": \"^7.2.0\",\n    \"babel-plugin-react-docgen\": \"^4.2.1\",\n    \"comment-parser\": \"^1.4.1\",\n    \"empathic\": \"^2.0.0\",\n    \"es-toolkit\": \"^1.43.0\",\n    \"escodegen\": \"^2.1.0\",\n    \"expect-type\": \"^0.15.0\",\n    \"html-tags\": \"^3.1.0\",\n    \"prop-types\": \"^15.7.2\",\n    \"react-element-to-jsx-string\": \"npm:@7rulnik/react-element-to-jsx-string@15.0.1\",\n    \"require-from-string\": \"^2.0.2\",\n    \"ts-dedent\": \"^2.0.0\",\n    \"type-fest\": \"~2.19\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"react-dom\": \"^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0\",\n    \"storybook\": \"workspace:^\",\n    \"typescript\": \">= 4.9.x\"\n  },\n  \"peerDependenciesMeta\": {\n    \"typescript\": {\n      \"optional\": true\n    }\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/renderers/react/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/renderers/react/preview.js",
    "content": "export * from './dist/preview.js';\n"
  },
  {
    "path": "code/renderers/react/project.json",
    "content": "{\n  \"name\": \"react\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/renderers/react/src/__test__/Button.csf4.stories.tsx",
    "content": "import React, { useEffect, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { action } from 'storybook/actions';\nimport { expect, fn, mocked, userEvent, within } from 'storybook/test';\n\nimport { __definePreview } from '../preview.tsx';\nimport { Button } from './Button.tsx';\n\nconst preview = __definePreview({\n  addons: [],\n});\n\nconst meta = preview.meta({\n  id: 'button-component',\n  title: 'Example/CSF4/Button',\n  component: Button,\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    children: 'Children coming from meta args',\n  },\n});\n\nexport const CSF2Secondary = meta.story({\n  render: (args) => {\n    return <Button {...args} />;\n  },\n  args: {\n    children: 'Children coming from story args!',\n    primary: false,\n  },\n});\n\nconst getCaptionForLocale = (locale: string) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'pt':\n      return 'Olá!';\n    case 'en':\n      return 'Hello!';\n    default:\n      return undefined;\n  }\n};\n\nexport const CSF2StoryWithLocale = meta.story({\n  render: (_, { globals: { locale } }) => {\n    const caption = getCaptionForLocale(locale);\n    return (\n      <>\n        <p>locale: {locale}</p>\n        <Button>{caption}</Button>\n      </>\n    );\n  },\n  name: 'WithLocale',\n});\n\nexport const CSF2StoryWithParamsAndDecorator = meta.story({\n  render: (args) => {\n    return <Button {...args} />;\n  },\n  args: {\n    children: 'foo',\n  },\n  parameters: {\n    layout: 'centered',\n  },\n  decorators: (StoryFn) => <StoryFn />,\n});\n\nexport const CSF3Primary = meta.story({\n  args: {\n    children: 'foo',\n    size: 'large',\n    primary: true,\n  },\n});\n\nexport const CSF3Button = meta.story({\n  args: { children: 'foo' },\n});\n\nexport const CSF3ButtonWithRender = meta.story({\n  ...CSF3Button.input,\n  render: (args) => (\n    <div>\n      <p data-testid=\"custom-render\">I am a custom render function</p>\n      <Button {...args} />\n    </div>\n  ),\n});\n\nexport const HooksStory = meta.story({\n  render: function Component() {\n    const [isClicked, setClicked] = useState(false);\n    return (\n      <>\n        <input data-testid=\"input\" />\n        <br />\n        <button onClick={() => setClicked(!isClicked)}>\n          I am {isClicked ? 'clicked' : 'not clicked'}\n        </button>\n      </>\n    );\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    await step('Step label', async () => {\n      const inputEl = canvas.getByTestId('input');\n      const buttonEl = canvas.getByRole('button');\n      await userEvent.click(buttonEl);\n      await userEvent.type(inputEl, 'Hello world!');\n\n      await expect(inputEl).toHaveValue('Hello world!');\n      await expect(buttonEl).toHaveTextContent('I am clicked');\n    });\n  },\n});\n\nexport const CSF3InputFieldFilled = meta.story({\n  render: () => {\n    return <input data-testid=\"input\" />;\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    await step('Step label', async () => {\n      const inputEl = canvas.getByTestId('input');\n      await userEvent.type(inputEl, 'Hello world!');\n      await expect(inputEl).toHaveValue('Hello world!');\n    });\n  },\n});\n\nconst mockFn = fn();\nexport const LoaderStory = meta.story({\n  args: {\n    // @ts-expect-error TODO: add a way to provide custom args/argTypes\n    mockFn,\n  },\n  loaders: [\n    async () => {\n      mockFn.mockReturnValueOnce('mockFn return value');\n      return {\n        value: 'loaded data',\n      };\n    },\n  ],\n  render: (args: any & { mockFn: (val: string) => string }, { loaded }) => {\n    const data = args.mockFn('render');\n    return (\n      <div>\n        <div data-testid=\"loaded-data\">{loaded.value}</div>\n        <div data-testid=\"spy-data\">{String(data)}</div>\n      </div>\n    );\n  },\n  play: async () => {\n    expect(mockFn).toHaveBeenCalledWith('render');\n  },\n});\n\nexport const MountInPlayFunction = meta.story({\n  args: {\n    // @ts-expect-error TODO: add a way to provide custom args/argTypes\n    mockFn: fn(),\n  },\n  play: async ({ args, mount, context }) => {\n    // equivalent of loaders\n    const loadedData = await Promise.resolve('loaded data');\n    // @ts-expect-error TODO: add a way to provide custom args/argTypes\n    mocked(args.mockFn).mockReturnValueOnce('mockFn return value');\n    // equivalent of render\n    // @ts-expect-error TODO: add a way to provide custom args/argTypes\n    const data = args.mockFn('render');\n    // TODO refactor this in the mount args PR\n    context.originalStoryFn = () => (\n      <div>\n        <div data-testid=\"loaded-data\">{loadedData}</div>\n        <div data-testid=\"spy-data\">{String(data)}</div>\n      </div>\n    );\n    await mount();\n\n    // equivalent of play\n    // @ts-expect-error TODO: add a way to provide custom args/argTypes\n    expect(args.mockFn).toHaveBeenCalledWith('render');\n  },\n});\n\nexport const MountInPlayFunctionThrow = meta.story({\n  play: async () => {\n    throw new Error('Error thrown in play');\n  },\n});\n\nexport const WithActionArg = meta.story({\n  args: {\n    // @ts-expect-error TODO: add a way to provide custom args/argTypes\n    someActionArg: action('some-action-arg'),\n  },\n  render: (args) => {\n    // @ts-expect-error TODO: add a way to provide custom args/argTypes\n    args.someActionArg('in render');\n    return (\n      <button\n        onClick={() => {\n          // @ts-expect-error TODO: add a way to provide custom args/argTypes\n          args.someActionArg('on click');\n        }}\n      />\n    );\n  },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const buttonEl = canvas.getByRole('button');\n    buttonEl.click();\n  },\n});\n\nexport const WithActionArgType = meta.story({\n  argTypes: {\n    // @ts-expect-error TODO: add a way to provide custom args/argTypes\n    someActionArg: {\n      action: true,\n    },\n  },\n  render: () => {\n    return <div>nothing</div>;\n  },\n});\n\nexport const Modal = meta.story({\n  render: function Component() {\n    const [isModalOpen, setIsModalOpen] = useState(false);\n    const [modalContainer] = useState(() => {\n      const div = document.createElement('div');\n      div.id = 'modal-root';\n      return div;\n    });\n\n    useEffect(() => {\n      document.body.appendChild(modalContainer);\n      return () => {\n        document.body.removeChild(modalContainer);\n      };\n    }, [modalContainer]);\n\n    const handleOpenModal = () => setIsModalOpen(true);\n    const handleCloseModal = () => setIsModalOpen(false);\n\n    const modalContent = isModalOpen\n      ? createPortal(\n          <div\n            role=\"dialog\"\n            style={{\n              position: 'fixed',\n              top: '20%',\n              left: '50%',\n              transform: 'translate(-50%, -20%)',\n              backgroundColor: 'white',\n              padding: '20px',\n              zIndex: 1000,\n              border: '2px solid black',\n              borderRadius: '5px',\n            }}\n          >\n            <div style={{ marginBottom: '10px' }}>\n              <p>This is a modal!</p>\n            </div>\n            <button onClick={handleCloseModal}>Close</button>\n          </div>,\n          modalContainer\n        )\n      : null;\n\n    return (\n      <>\n        <button id=\"openModalButton\" onClick={handleOpenModal}>\n          Open Modal\n        </button>\n        {modalContent}\n      </>\n    );\n  },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const openModalButton = canvas.getByRole('button', { name: /open modal/i });\n    await userEvent.click(openModalButton);\n    await expect(within(document.body).getByRole('dialog')).toBeInTheDocument();\n  },\n});\n"
  },
  {
    "path": "code/renderers/react/src/__test__/Button.stories.tsx",
    "content": "import React, { useEffect, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { action } from 'storybook/actions';\nimport type { HandlerFunction } from 'storybook/actions';\nimport { expect, fn, mocked, userEvent, within } from 'storybook/test';\n\nimport type { StoryFn as CSF2Story, StoryObj as CSF3Story, Meta } from '../index.ts';\nimport type { ButtonProps } from './Button.tsx';\nimport { Button } from './Button.tsx';\n\nconst meta = {\n  title: 'Example/Button',\n  component: Button,\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n\nconst Template: CSF2Story<ButtonProps> = (args) => <Button {...args} />;\n\nexport const CSF2Secondary = Template.bind({});\nCSF2Secondary.args = {\n  children: 'Children coming from story args!',\n  primary: false,\n};\n\nconst getCaptionForLocale = (locale: string) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'pt':\n      return 'Olá!';\n    case 'en':\n      return 'Hello!';\n    default:\n      return undefined;\n  }\n};\n\nexport const CSF2StoryWithLocale: CSF2Story = (args, { globals: { locale } }) => {\n  const caption = getCaptionForLocale(locale);\n  return (\n    <>\n      <p>locale: {locale}</p>\n      <Button>{caption}</Button>\n    </>\n  );\n};\nCSF2StoryWithLocale.storyName = 'WithLocale';\n\nexport const CSF2StoryWithParamsAndDecorator: CSF2Story<ButtonProps> = (args) => {\n  return <Button {...args} />;\n};\nCSF2StoryWithParamsAndDecorator.args = {\n  children: 'foo',\n};\nCSF2StoryWithParamsAndDecorator.parameters = {\n  layout: 'centered',\n};\nCSF2StoryWithParamsAndDecorator.decorators = [(StoryFn) => <StoryFn />];\n\nexport const CSF3Primary: CSF3Story<ButtonProps> = {\n  args: {\n    children: 'foo',\n    size: 'large',\n    primary: true,\n  },\n};\n\nexport const CSF3Button: CSF3Story<ButtonProps> = {\n  args: { children: 'foo' },\n};\n\nexport const CSF3ButtonWithRender: CSF3Story<ButtonProps> = {\n  ...CSF3Button,\n  render: (args: any) => (\n    <div>\n      <p data-testid=\"custom-render\">I am a custom render function</p>\n      <Button {...args} />\n    </div>\n  ),\n};\n\nexport const HooksStory: CSF3Story = {\n  render: function Component() {\n    const [isClicked, setClicked] = useState(false);\n    return (\n      <>\n        <input data-testid=\"input\" />\n        <br />\n        <button onClick={() => setClicked(!isClicked)}>\n          I am {isClicked ? 'clicked' : 'not clicked'}\n        </button>\n      </>\n    );\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    await step('Step label', async () => {\n      const inputEl = canvas.getByTestId('input');\n      const buttonEl = canvas.getByRole('button');\n      await userEvent.click(buttonEl);\n      await userEvent.type(inputEl, 'Hello world!');\n\n      await expect(inputEl).toHaveValue('Hello world!');\n      await expect(buttonEl).toHaveTextContent('I am clicked');\n    });\n  },\n};\n\nexport const CSF3InputFieldFilled: CSF3Story = {\n  render: () => {\n    return <input data-testid=\"input\" />;\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    await step('Step label', async () => {\n      const inputEl = canvas.getByTestId('input');\n      await userEvent.type(inputEl, 'Hello world!');\n      await expect(inputEl).toHaveValue('Hello world!');\n    });\n  },\n};\n\nconst mockFn = fn();\nexport const LoaderStory: CSF3Story<{ mockFn: (val: string) => string }> = {\n  args: {\n    mockFn,\n  },\n  loaders: [\n    async () => {\n      mockFn.mockReturnValueOnce('mockFn return value');\n      return {\n        value: 'loaded data',\n      };\n    },\n  ],\n  render: (args, { loaded }) => {\n    const data = args.mockFn('render');\n    return (\n      <div>\n        <div data-testid=\"loaded-data\">{loaded.value}</div>\n        <div data-testid=\"spy-data\">{String(data)}</div>\n      </div>\n    );\n  },\n  play: async () => {\n    expect(mockFn).toHaveBeenCalledWith('render');\n  },\n};\n\nexport const MountInPlayFunction: CSF3Story<{ mockFn: (val: string) => string }> = {\n  args: {\n    mockFn: fn(),\n  },\n  play: async ({ args, mount, context }) => {\n    // equivalent of loaders\n    const loadedData = await Promise.resolve('loaded data');\n    mocked(args.mockFn).mockReturnValueOnce('mockFn return value');\n    // equivalent of render\n    const data = args.mockFn('render');\n    // TODO refactor this in the mount args PR\n    context.originalStoryFn = () => (\n      <div>\n        <div data-testid=\"loaded-data\">{loadedData}</div>\n        <div data-testid=\"spy-data\">{String(data)}</div>\n      </div>\n    );\n    await mount();\n\n    // equivalent of play\n    expect(args.mockFn).toHaveBeenCalledWith('render');\n  },\n};\n\nexport const MountInPlayFunctionThrow: CSF3Story<{ mockFn: (val: string) => string }> = {\n  play: async () => {\n    throw new Error('Error thrown in play');\n  },\n};\n\nexport const WithActionArg: CSF3Story<{ someActionArg: HandlerFunction }> = {\n  args: {\n    someActionArg: action('some-action-arg'),\n  },\n  render: (args) => {\n    args.someActionArg('in render');\n    return (\n      <button\n        onClick={() => {\n          args.someActionArg('on click');\n        }}\n      />\n    );\n  },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const buttonEl = await canvas.getByRole('button');\n    await buttonEl.click();\n  },\n};\n\nexport const WithActionArgType: CSF3Story<{ someActionArg: HandlerFunction }> = {\n  argTypes: {\n    someActionArg: {\n      action: true,\n    },\n  },\n  render: () => {\n    return <div>nothing</div>;\n  },\n};\n\nexport const Modal: CSF3Story = {\n  render: function Component() {\n    const [isModalOpen, setIsModalOpen] = useState(false);\n    const [modalContainer] = useState(() => {\n      const div = document.createElement('div');\n      div.id = 'modal-root';\n      return div;\n    });\n\n    useEffect(() => {\n      document.body.appendChild(modalContainer);\n      return () => {\n        document.body.removeChild(modalContainer);\n      };\n    }, [modalContainer]);\n\n    const handleOpenModal = () => setIsModalOpen(true);\n    const handleCloseModal = () => setIsModalOpen(false);\n\n    const modalContent = isModalOpen\n      ? createPortal(\n          <div\n            role=\"dialog\"\n            style={{\n              position: 'fixed',\n              top: '20%',\n              left: '50%',\n              transform: 'translate(-50%, -20%)',\n              backgroundColor: 'white',\n              padding: '20px',\n              zIndex: 1000,\n              border: '2px solid black',\n              borderRadius: '5px',\n            }}\n          >\n            <div style={{ marginBottom: '10px' }}>\n              <p>This is a modal!</p>\n            </div>\n            <button onClick={handleCloseModal}>Close</button>\n          </div>,\n          modalContainer\n        )\n      : null;\n\n    return (\n      <>\n        <button id=\"openModalButton\" onClick={handleOpenModal}>\n          Open Modal\n        </button>\n        {modalContent}\n      </>\n    );\n  },\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const openModalButton = await canvas.getByRole('button', { name: /open modal/i });\n    await userEvent.click(openModalButton);\n    await expect(within(document.body).getByRole('dialog')).toBeInTheDocument();\n  },\n};\n"
  },
  {
    "path": "code/renderers/react/src/__test__/Button.tsx",
    "content": "import React from 'react';\n\nimport './button.css';\n\nexport interface ButtonProps {\n  /** Is this the principal call to action on the page? */\n  primary?: boolean;\n  /** What background color to use */\n  backgroundColor?: string;\n  /** How large should the button be? */\n  size?: 'small' | 'medium' | 'large';\n  /** Button contents */\n  children: React.ReactNode;\n  /** Optional click handler */\n  onClick?: () => void;\n}\n\n/** Primary UI component for user interaction */\nexport const Button: React.FC<ButtonProps> = (props) => {\n  const { primary = false, size = 'medium', backgroundColor, children, onClick } = props;\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n  return (\n    <button\n      type=\"button\"\n      className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n      style={{ backgroundColor }}\n      onClick={onClick}\n    >\n      {children}\n    </button>\n  );\n};\n"
  },
  {
    "path": "code/renderers/react/src/__test__/ComponentWithError.stories.tsx",
    "content": "import type { Meta, StoryObj } from '../index.ts';\nimport { ComponentWithError } from './ComponentWithError.tsx';\n\nconst meta = {\n  title: 'Example/ComponentWithError',\n  component: ComponentWithError as any,\n} satisfies Meta<typeof ComponentWithError>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const ThrowsError: Story = {};\n"
  },
  {
    "path": "code/renderers/react/src/__test__/ComponentWithError.tsx",
    "content": "export function ComponentWithError() {\n  // eslint-disable-next-line local-rules/no-uncategorized-errors\n  throw new Error('Error in render');\n}\n"
  },
  {
    "path": "code/renderers/react/src/__test__/README.md",
    "content": "## Integration tests for @storybook/react.\n\nAs these tests are implemented as stories, we may consider moving them inside the `template/stories` folder.\n"
  },
  {
    "path": "code/renderers/react/src/__test__/__snapshots__/portable-stories-factory.test.tsx.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`Renders CSF2StoryWithLocale story 1`] = `\n<body>\n  <div>\n    <p>\n      locale: \n    </p>\n    <button\n      class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n      type=\"button\"\n    />\n  </div>\n</body>\n`;\n\nexports[`Renders CSF3Button story 1`] = `\n<body>\n  <div>\n    <button\n      class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n      type=\"button\"\n    >\n      foo\n    </button>\n  </div>\n</body>\n`;\n\nexports[`Renders CSF3ButtonWithRender story 1`] = `\n<body>\n  <div>\n    <div>\n      <p\n        data-testid=\"custom-render\"\n      >\n        I am a custom render function\n      </p>\n      <button\n        class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n        type=\"button\"\n      >\n        foo\n      </button>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`Renders CSF3InputFieldFilled story 1`] = `\n<body>\n  <div>\n    <input\n      data-testid=\"input\"\n    />\n  </div>\n</body>\n`;\n\nexports[`Renders CSF3Primary story 1`] = `\n<body>\n  <div>\n    <button\n      class=\"storybook-button storybook-button--large storybook-button--primary\"\n      type=\"button\"\n    >\n      foo\n    </button>\n  </div>\n</body>\n`;\n\nexports[`Renders MountInPlayFunction story 1`] = `\n<body>\n  <div>\n    <div>\n      <div\n        data-testid=\"loaded-data\"\n      >\n        loaded data\n      </div>\n      <div\n        data-testid=\"spy-data\"\n      >\n        mockFn return value\n      </div>\n    </div>\n  </div>\n</body>\n`;\n"
  },
  {
    "path": "code/renderers/react/src/__test__/__snapshots__/portable-stories-legacy.test.tsx.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`Legacy Portable Stories API > Renders CSF2Secondary story 1`] = `\n<body>\n  <div>\n    <button\n      class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n      type=\"button\"\n    >\n      Children coming from story args!\n    </button>\n  </div>\n</body>\n`;\n\nexports[`Legacy Portable Stories API > Renders CSF2StoryWithParamsAndDecorator story 1`] = `\n<body>\n  <div>\n    <button\n      class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n      type=\"button\"\n    >\n      foo\n    </button>\n  </div>\n</body>\n`;\n\nexports[`Legacy Portable Stories API > Renders CSF3Button story 1`] = `\n<body>\n  <div>\n    <button\n      class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n      type=\"button\"\n    >\n      foo\n    </button>\n  </div>\n</body>\n`;\n\nexports[`Legacy Portable Stories API > Renders CSF3ButtonWithRender story 1`] = `\n<body>\n  <div>\n    <div>\n      <p\n        data-testid=\"custom-render\"\n      >\n        I am a custom render function\n      </p>\n      <button\n        class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n        type=\"button\"\n      >\n        foo\n      </button>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`Legacy Portable Stories API > Renders CSF3InputFieldFilled story 1`] = `\n<body>\n  <div>\n    <input\n      data-testid=\"input\"\n    />\n  </div>\n</body>\n`;\n\nexports[`Legacy Portable Stories API > Renders CSF3Primary story 1`] = `\n<body>\n  <div>\n    <button\n      class=\"storybook-button storybook-button--large storybook-button--primary\"\n      type=\"button\"\n    >\n      foo\n    </button>\n  </div>\n</body>\n`;\n\nexports[`Legacy Portable Stories API > Renders HooksStory story 1`] = `\n<body>\n  <div>\n    <input\n      data-testid=\"input\"\n    />\n    <br />\n    <button>\n      I am \n      clicked\n    </button>\n  </div>\n</body>\n`;\n\nexports[`Legacy Portable Stories API > Renders LoaderStory story 1`] = `\n<body>\n  <div>\n    <div>\n      <div\n        data-testid=\"loaded-data\"\n      >\n        loaded data\n      </div>\n      <div\n        data-testid=\"spy-data\"\n      >\n        mockFn return value\n      </div>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`Legacy Portable Stories API > Renders Modal story 1`] = `\n<body>\n  <div>\n    <button\n      id=\"openModalButton\"\n    >\n      Open Modal\n    </button>\n  </div>\n  <div\n    id=\"modal-root\"\n  >\n    <div\n      role=\"dialog\"\n      style=\"position: fixed; top: 20%; left: 50%; transform: translate(-50%, -20%); background-color: white; padding: 20px; z-index: 1000; border: 2px solid black; border-radius: 5px;\"\n    >\n      <div\n        style=\"margin-bottom: 10px;\"\n      >\n        <p>\n          This is a modal!\n        </p>\n      </div>\n      <button>\n        Close\n      </button>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`Legacy Portable Stories API > Renders WithActionArg story 1`] = `\n<body>\n  <div>\n    <button />\n  </div>\n</body>\n`;\n\nexports[`Legacy Portable Stories API > Renders WithActionArgType story 1`] = `\n<body>\n  <div>\n    <div>\n      nothing\n    </div>\n  </div>\n</body>\n`;\n"
  },
  {
    "path": "code/renderers/react/src/__test__/__snapshots__/portable-stories.test.tsx.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`Renders CSF2Secondary story 1`] = `\n<body>\n  <div>\n    <button\n      class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n      type=\"button\"\n    >\n      Children coming from story args!\n    </button>\n  </div>\n</body>\n`;\n\nexports[`Renders CSF2StoryWithParamsAndDecorator story 1`] = `\n<body>\n  <div>\n    <button\n      class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n      type=\"button\"\n    >\n      foo\n    </button>\n  </div>\n</body>\n`;\n\nexports[`Renders CSF3Button story 1`] = `\n<body>\n  <div>\n    <button\n      class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n      type=\"button\"\n    >\n      foo\n    </button>\n  </div>\n</body>\n`;\n\nexports[`Renders CSF3ButtonWithRender story 1`] = `\n<body>\n  <div>\n    <div>\n      <p\n        data-testid=\"custom-render\"\n      >\n        I am a custom render function\n      </p>\n      <button\n        class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n        type=\"button\"\n      >\n        foo\n      </button>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`Renders CSF3InputFieldFilled story 1`] = `\n<body>\n  <div>\n    <input\n      data-testid=\"input\"\n    />\n  </div>\n</body>\n`;\n\nexports[`Renders CSF3Primary story 1`] = `\n<body>\n  <div>\n    <button\n      class=\"storybook-button storybook-button--large storybook-button--primary\"\n      type=\"button\"\n    >\n      foo\n    </button>\n  </div>\n</body>\n`;\n\nexports[`Renders HooksStory story 1`] = `\n<body>\n  <div>\n    <input\n      data-testid=\"input\"\n    />\n    <br />\n    <button>\n      I am \n      clicked\n    </button>\n  </div>\n</body>\n`;\n\nexports[`Renders LoaderStory story 1`] = `\n<body>\n  <div>\n    <div>\n      <div\n        data-testid=\"loaded-data\"\n      >\n        loaded data\n      </div>\n      <div\n        data-testid=\"spy-data\"\n      >\n        mockFn return value\n      </div>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`Renders Modal story 1`] = `\n<body>\n  <div>\n    <button\n      id=\"openModalButton\"\n    >\n      Open Modal\n    </button>\n  </div>\n  <div\n    id=\"modal-root\"\n  >\n    <div\n      role=\"dialog\"\n      style=\"position: fixed; top: 20%; left: 50%; transform: translate(-50%, -20%); background-color: white; padding: 20px; z-index: 1000; border: 2px solid black; border-radius: 5px;\"\n    >\n      <div\n        style=\"margin-bottom: 10px;\"\n      >\n        <p>\n          This is a modal!\n        </p>\n      </div>\n      <button>\n        Close\n      </button>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`Renders MountInPlayFunction story 1`] = `\n<body>\n  <div>\n    <div>\n      <div\n        data-testid=\"loaded-data\"\n      >\n        loaded data\n      </div>\n      <div\n        data-testid=\"spy-data\"\n      >\n        mockFn return value\n      </div>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`Renders WithActionArg story 1`] = `\n<body>\n  <div>\n    <button />\n  </div>\n</body>\n`;\n\nexports[`Renders WithActionArgType story 1`] = `\n<body>\n  <div>\n    <div>\n      nothing\n    </div>\n  </div>\n</body>\n`;\n"
  },
  {
    "path": "code/renderers/react/src/__test__/button.css",
    "content": ".storybook-button {\n  display: inline-block;\n  cursor: pointer;\n  border: 0;\n  border-radius: 3em;\n  font-weight: 700;\n  line-height: 1;\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n.storybook-button--primary {\n  background-color: #555ab9;\n  color: white;\n}\n.storybook-button--secondary {\n  box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;\n  background-color: transparent;\n  color: #333;\n}\n.storybook-button--small {\n  padding: 10px 16px;\n  font-size: 12px;\n}\n.storybook-button--medium {\n  padding: 11px 20px;\n  font-size: 14px;\n}\n.storybook-button--large {\n  padding: 12px 24px;\n  font-size: 16px;\n}\n"
  },
  {
    "path": "code/renderers/react/src/__test__/portable-stories-factory.test.tsx",
    "content": "// @vitest-environment happy-dom\nimport { cleanup, render, screen } from '@testing-library/react';\nimport { afterEach, describe, expect, it, vi } from 'vitest';\n\nimport React from 'react';\n\nimport {\n  CSF2StoryWithLocale,\n  CSF3Button,\n  CSF3ButtonWithRender,\n  CSF3InputFieldFilled,\n  CSF3Primary,\n  MountInPlayFunction,\n  MountInPlayFunctionThrow,\n} from './Button.csf4.stories.tsx';\nimport { CSF2Secondary, HooksStory } from './Button.csf4.stories.tsx';\n\nafterEach(() => {\n  cleanup();\n});\n\ndescribe('renders', () => {\n  it('renders primary button', () => {\n    render(<CSF2Secondary.Component primary={true}>Hello world</CSF2Secondary.Component>);\n    const buttonElement = screen.getByText(/Hello world/i);\n    expect(buttonElement).not.toBeNull();\n  });\n\n  it('reuses args from composed story', () => {\n    render(<CSF2Secondary.Component />);\n    const buttonElement = screen.getByRole('button');\n    expect(buttonElement.textContent).toEqual(CSF2Secondary.input.args.children);\n  });\n\n  it('onclick handler is called', async () => {\n    const onClickSpy = vi.fn();\n    render(<CSF2Secondary.Component onClick={onClickSpy} />);\n    const buttonElement = screen.getByRole('button');\n    buttonElement.click();\n    expect(onClickSpy).toHaveBeenCalled();\n  });\n\n  it('reuses args from composeStories', () => {\n    const { getByText } = render(<CSF3Primary.Component />);\n    const buttonElement = getByText(/foo/i);\n    expect(buttonElement).not.toBeNull();\n  });\n\n  it('should render component mounted in play function', async () => {\n    await MountInPlayFunction.run();\n\n    expect(screen.getByTestId('spy-data').textContent).toEqual('mockFn return value');\n    expect(screen.getByTestId('loaded-data').textContent).toEqual('loaded data');\n  });\n\n  it('should throw an error in play function', async () => {\n    await expect(() => MountInPlayFunctionThrow.run()).rejects.toThrowError('Error thrown in play');\n  });\n});\n\ndescribe('CSF3', () => {\n  it('renders with inferred globalRender', () => {\n    render(<CSF3Button.Component>Hello world</CSF3Button.Component>);\n    const buttonElement = screen.getByText(/Hello world/i);\n    expect(buttonElement).not.toBeNull();\n  });\n\n  it('renders with custom render function', () => {\n    render(<CSF3ButtonWithRender.Component />);\n    expect(screen.getByTestId('custom-render')).not.toBeNull();\n  });\n\n  it('renders with play function without canvas element', async () => {\n    await CSF3InputFieldFilled.run();\n\n    const input = screen.getByTestId('input') as HTMLInputElement;\n    expect(input.value).toEqual('Hello world!');\n  });\n\n  it('renders with play function with canvas element', async () => {\n    let divElement;\n    try {\n      divElement = document.createElement('div');\n      document.body.appendChild(divElement);\n\n      await CSF3InputFieldFilled.run({ canvasElement: divElement });\n\n      const input = screen.getByTestId('input') as HTMLInputElement;\n      expect(input.value).toEqual('Hello world!');\n    } finally {\n      if (divElement) {\n        document.body.removeChild(divElement);\n      }\n    }\n  });\n\n  it('renders with hooks', async () => {\n    await HooksStory.run();\n\n    const input = screen.getByTestId('input') as HTMLInputElement;\n    expect(input.value).toEqual('Hello world!');\n  });\n});\n\nconst testCases = Object.entries({\n  CSF2StoryWithLocale,\n  CSF3Button,\n  CSF3ButtonWithRender,\n  CSF3InputFieldFilled,\n  CSF3Primary,\n  MountInPlayFunction,\n}).map(([name, Story]) => [name, Story] as [string, typeof Story]);\nit.each(testCases)('Renders %s story', async (_storyName, Story) => {\n  await Story.run();\n  expect(document.body).toMatchSnapshot();\n});\n"
  },
  {
    "path": "code/renderers/react/src/__test__/portable-stories-legacy.test.tsx",
    "content": "// @vitest-environment happy-dom\nimport { cleanup, render, screen } from '@testing-library/react';\nimport { afterEach, describe, expect, it, vi } from 'vitest';\n\nimport React from 'react';\n\nimport type { Meta } from '@storybook/react';\n\nimport { expectTypeOf } from 'expect-type';\nimport { addons } from 'storybook/preview-api';\n\nimport { composeStories, composeStory, setProjectAnnotations } from '../index.ts';\nimport type { Button } from './Button.tsx';\nimport * as stories from './Button.stories.tsx';\n\n// TODO: Potentially remove this in Storybook 9.0 once we fully move users to the new portable stories API (with CSF4)\ndescribe('Legacy Portable Stories API', () => {\n  // example with composeStories, returns an object with all stories composed with args/decorators\n  const { CSF3Primary, LoaderStory } = composeStories(stories);\n\n  // example with composeStory, returns a single story composed with args/decorators\n  const Secondary = composeStory(stories.CSF2Secondary, stories.default);\n  describe('renders', () => {\n    afterEach(() => {\n      cleanup();\n    });\n\n    it('renders primary button', () => {\n      render(<CSF3Primary>Hello world</CSF3Primary>);\n      const buttonElement = screen.getByText(/Hello world/i);\n      expect(buttonElement).not.toBeNull();\n    });\n\n    it('reuses args from composed story', () => {\n      render(<Secondary />);\n      const buttonElement = screen.getByRole('button');\n      expect(buttonElement.textContent).toEqual(Secondary.args.children);\n    });\n\n    it('onclick handler is called', async () => {\n      const onClickSpy = vi.fn();\n      render(<Secondary onClick={onClickSpy} />);\n      const buttonElement = screen.getByRole('button');\n      buttonElement.click();\n      expect(onClickSpy).toHaveBeenCalled();\n    });\n\n    it('reuses args from composeStories', () => {\n      const { getByText } = render(<CSF3Primary />);\n      const buttonElement = getByText(/foo/i);\n      expect(buttonElement).not.toBeNull();\n    });\n\n    it('should call and compose loaders data', async () => {\n      await LoaderStory.load();\n      const { getByTestId } = render(<LoaderStory />);\n      expect(getByTestId('spy-data').textContent).toEqual('mockFn return value');\n      expect(getByTestId('loaded-data').textContent).toEqual('loaded data');\n      // spy assertions happen in the play function and should work\n      await LoaderStory.play!();\n    });\n  });\n\n  describe('projectAnnotations', () => {\n    afterEach(() => {\n      cleanup();\n    });\n\n    it('renders with default projectAnnotations', () => {\n      setProjectAnnotations([\n        {\n          parameters: { injected: true },\n          initialGlobals: { locale: 'en' },\n        },\n      ]);\n      const WithEnglishText = composeStory(stories.CSF2StoryWithLocale, stories.default);\n      const { getByText } = render(<WithEnglishText />);\n      const buttonElement = getByText('Hello!');\n      expect(buttonElement).not.toBeNull();\n      expect(WithEnglishText.parameters?.injected).toBe(true);\n    });\n\n    it('renders with custom projectAnnotations via composeStory params', () => {\n      const WithPortugueseText = composeStory(stories.CSF2StoryWithLocale, stories.default, {\n        initialGlobals: { locale: 'pt' },\n      });\n      const { getByText } = render(<WithPortugueseText />);\n      const buttonElement = getByText('Olá!');\n      expect(buttonElement).not.toBeNull();\n    });\n\n    it('explicit action are spies when the test loader is loaded', async () => {\n      const Story = composeStory(stories.WithActionArg, stories.default);\n      await Story.load();\n      expect(vi.mocked(Story.args.someActionArg!).mock).toBeDefined();\n\n      const { container } = render(<Story />);\n      expect(Story.args.someActionArg).toHaveBeenCalledOnce();\n      expect(Story.args.someActionArg).toHaveBeenCalledWith('in render');\n\n      await Story.play!({ canvasElement: container });\n      expect(Story.args.someActionArg).toHaveBeenCalledTimes(2);\n      expect(Story.args.someActionArg).toHaveBeenCalledWith('on click');\n    });\n\n    it('has action arg from argTypes when addon-actions annotations are added', () => {\n      const Story = composeStory(stories.WithActionArgType, stories.default);\n      expect(Story.args.someActionArg).toHaveProperty('isAction', true);\n    });\n  });\n\n  describe('CSF3', () => {\n    afterEach(() => {\n      cleanup();\n    });\n\n    it('renders with inferred globalRender', () => {\n      const Primary = composeStory(stories.CSF3Button, stories.default);\n\n      render(<Primary>Hello world</Primary>);\n      const buttonElement = screen.getByText(/Hello world/i);\n      expect(buttonElement).not.toBeNull();\n    });\n\n    it('renders with custom render function', () => {\n      const Primary = composeStory(stories.CSF3ButtonWithRender, stories.default);\n\n      render(<Primary />);\n      expect(screen.getByTestId('custom-render')).not.toBeNull();\n    });\n\n    it('renders with play function without canvas element', async () => {\n      const CSF3InputFieldFilled = composeStory(stories.CSF3InputFieldFilled, stories.default);\n\n      render(<CSF3InputFieldFilled />);\n\n      await CSF3InputFieldFilled.play!();\n\n      const input = screen.getByTestId('input') as HTMLInputElement;\n      expect(input.value).toEqual('Hello world!');\n    });\n\n    it('renders with play function with canvas element', async () => {\n      const CSF3InputFieldFilled = composeStory(stories.CSF3InputFieldFilled, stories.default);\n\n      const { container } = render(<CSF3InputFieldFilled />);\n\n      await CSF3InputFieldFilled.play!({ canvasElement: container });\n\n      const input = screen.getByTestId('input') as HTMLInputElement;\n      expect(input.value).toEqual('Hello world!');\n    });\n  });\n\n  // common in addons that need to communicate between manager and preview\n  it('should pass with decorators that need addons channel', () => {\n    const PrimaryWithChannels = composeStory(stories.CSF3Primary, stories.default, {\n      decorators: [\n        (StoryFn: any) => {\n          addons.getChannel();\n          return StoryFn();\n        },\n      ],\n    });\n    render(<PrimaryWithChannels>Hello world</PrimaryWithChannels>);\n    const buttonElement = screen.getByText(/Hello world/i);\n    expect(buttonElement).not.toBeNull();\n  });\n\n  describe('ComposeStories types', () => {\n    // this file tests Typescript types that's why there are no assertions\n    it('Should support typescript operators', () => {\n      type ComposeStoriesParam = Parameters<typeof composeStories>[0];\n\n      expectTypeOf({\n        ...stories,\n        default: stories.default as Meta<typeof Button>,\n      }).toMatchTypeOf<ComposeStoriesParam>();\n\n      expectTypeOf({\n        ...stories,\n        default: stories.default satisfies Meta<typeof Button>,\n      }).toMatchTypeOf<ComposeStoriesParam>();\n    });\n  });\n\n  // Batch snapshot testing\n  const testCases = Object.values(composeStories(stories)).map(\n    (Story) => [Story.storyName, Story] as [string, typeof Story]\n  );\n\n  it.each(testCases)('Renders %s story', async (_storyName, Story) => {\n    cleanup();\n\n    if (\n      _storyName === 'CSF2StoryWithLocale' ||\n      _storyName === 'MountInPlayFunction' ||\n      _storyName === 'MountInPlayFunctionThrow'\n    ) {\n      return;\n    }\n\n    await Story.load();\n\n    const { baseElement } = await render(<Story />);\n\n    globalThis.IS_REACT_ACT_ENVIRONMENT = false;\n    await Story.play?.();\n    globalThis.IS_REACT_ACT_ENVIRONMENT = true;\n\n    expect(baseElement).toMatchSnapshot();\n  });\n});\n\ndeclare const globalThis: {\n  IS_REACT_ACT_ENVIRONMENT?: boolean;\n};\n"
  },
  {
    "path": "code/renderers/react/src/__test__/portable-stories.test.tsx",
    "content": "// @vitest-environment happy-dom\nimport { cleanup, render, screen } from '@testing-library/react';\nimport { afterEach, beforeAll, describe, expect, it, vi } from 'vitest';\n\nimport React from 'react';\n\nimport type { Meta } from '@storybook/react';\n\nimport { expectTypeOf } from 'expect-type';\nimport { addons } from 'storybook/preview-api';\n\nimport { composeStories, composeStory, setProjectAnnotations } from '../index.ts';\nimport type { Button } from './Button.tsx';\nimport * as ButtonStories from './Button.stories.tsx';\nimport * as ComponentWithErrorStories from './ComponentWithError.stories.tsx';\n\nconst HooksStory = composeStory(ButtonStories.HooksStory, ButtonStories.default);\n\nconst projectAnnotations = setProjectAnnotations([]);\n\n// example with composeStories, returns an object with all stories composed with args/decorators\nconst { CSF3Primary, LoaderStory, MountInPlayFunction, MountInPlayFunctionThrow } =\n  composeStories(ButtonStories);\nconst { ThrowsError } = composeStories(ComponentWithErrorStories);\n\nbeforeAll(async () => {\n  await projectAnnotations.beforeAll?.();\n});\n\nafterEach(() => {\n  cleanup();\n});\n\n// example with composeStory, returns a single story composed with args/decorators\nconst Secondary = composeStory(ButtonStories.CSF2Secondary, ButtonStories.default);\ndescribe('renders', () => {\n  it('renders primary button', () => {\n    render(<CSF3Primary>Hello world</CSF3Primary>);\n    const buttonElement = screen.getByText(/Hello world/i);\n    expect(buttonElement).not.toBeNull();\n  });\n\n  it('reuses args from composed story', () => {\n    render(<Secondary />);\n    const buttonElement = screen.getByRole('button');\n    expect(buttonElement.textContent).toEqual(Secondary.args.children);\n  });\n\n  it('onclick handler is called', async () => {\n    const onClickSpy = vi.fn();\n    render(<Secondary onClick={onClickSpy} />);\n    const buttonElement = screen.getByRole('button');\n    buttonElement.click();\n    expect(onClickSpy).toHaveBeenCalled();\n  });\n\n  it('reuses args from composeStories', () => {\n    const { getByText } = render(<CSF3Primary />);\n    const buttonElement = getByText(/foo/i);\n    expect(buttonElement).not.toBeNull();\n  });\n\n  it('should throw error when rendering a component with a render error', async () => {\n    await expect(ThrowsError.run()).rejects.toThrowError('Error in render');\n  });\n\n  it('should render component mounted in play function', async () => {\n    await MountInPlayFunction.run();\n\n    expect(screen.getByTestId('spy-data').textContent).toEqual('mockFn return value');\n    expect(screen.getByTestId('loaded-data').textContent).toEqual('loaded data');\n  });\n\n  it('should throw an error in play function', async () => {\n    await expect(MountInPlayFunctionThrow.run()).rejects.toThrowError('Error thrown in play');\n  });\n\n  it('should call and compose loaders data', async () => {\n    await LoaderStory.load();\n    const { getByTestId } = render(<LoaderStory />);\n    expect(getByTestId('spy-data').textContent).toEqual('mockFn return value');\n    expect(getByTestId('loaded-data').textContent).toEqual('loaded data');\n    // spy assertions happen in the play function and should work\n    await LoaderStory.run!();\n  });\n});\n\ndescribe('projectAnnotations', () => {\n  it('renders with default projectAnnotations', () => {\n    setProjectAnnotations([\n      {\n        parameters: { injected: true },\n        initialGlobals: { locale: 'en' },\n      },\n    ]);\n    const WithEnglishText = composeStory(ButtonStories.CSF2StoryWithLocale, ButtonStories.default);\n    const { getByText } = render(<WithEnglishText />);\n    const buttonElement = getByText('Hello!');\n    expect(buttonElement).not.toBeNull();\n    expect(WithEnglishText.parameters?.injected).toBe(true);\n  });\n\n  it('renders with custom projectAnnotations via composeStory params', () => {\n    const WithPortugueseText = composeStory(\n      ButtonStories.CSF2StoryWithLocale,\n      ButtonStories.default,\n      {\n        initialGlobals: { locale: 'pt' },\n      }\n    );\n    const { getByText } = render(<WithPortugueseText />);\n    const buttonElement = getByText('Olá!');\n    expect(buttonElement).not.toBeNull();\n  });\n\n  it('has action arg from argTypes when addon-actions annotations are added', () => {\n    const Story = composeStory(ButtonStories.WithActionArgType, ButtonStories.default);\n    expect(Story.args.someActionArg).toHaveProperty('isAction', true);\n  });\n});\n\ndescribe('CSF3', () => {\n  it('renders with inferred globalRender', () => {\n    const Primary = composeStory(ButtonStories.CSF3Button, ButtonStories.default);\n\n    render(<Primary>Hello world</Primary>);\n    const buttonElement = screen.getByText(/Hello world/i);\n    expect(buttonElement).not.toBeNull();\n  });\n\n  it('renders with custom render function', () => {\n    const Primary = composeStory(ButtonStories.CSF3ButtonWithRender, ButtonStories.default);\n\n    render(<Primary />);\n    expect(screen.getByTestId('custom-render')).not.toBeNull();\n  });\n\n  it('renders with play function without canvas element', async () => {\n    const CSF3InputFieldFilled = composeStory(\n      ButtonStories.CSF3InputFieldFilled,\n      ButtonStories.default\n    );\n    await CSF3InputFieldFilled.run();\n\n    const input = screen.getByTestId('input') as HTMLInputElement;\n    expect(input.value).toEqual('Hello world!');\n  });\n\n  it('renders with play function with canvas element', async () => {\n    const CSF3InputFieldFilled = composeStory(\n      ButtonStories.CSF3InputFieldFilled,\n      ButtonStories.default\n    );\n\n    const div = document.createElement('div');\n    document.body.appendChild(div);\n\n    await CSF3InputFieldFilled.run({ canvasElement: div });\n\n    const input = screen.getByTestId('input') as HTMLInputElement;\n    expect(input.value).toEqual('Hello world!');\n\n    document.body.removeChild(div);\n  });\n\n  it('renders with hooks', async () => {\n    await HooksStory.run();\n\n    const input = screen.getByTestId('input') as HTMLInputElement;\n    expect(input.value).toEqual('Hello world!');\n  });\n});\n\n// common in addons that need to communicate between manager and preview\nit('should pass with decorators that need addons channel', () => {\n  const PrimaryWithChannels = composeStory(ButtonStories.CSF3Primary, ButtonStories.default, {\n    decorators: [\n      (StoryFn: any) => {\n        addons.getChannel();\n        return StoryFn();\n      },\n    ],\n  });\n  render(<PrimaryWithChannels>Hello world</PrimaryWithChannels>);\n  const buttonElement = screen.getByText(/Hello world/i);\n  expect(buttonElement).not.toBeNull();\n});\n\ndescribe('ComposeStories types', () => {\n  // this file tests Typescript types that's why there are no assertions\n  it('Should support typescript operators', () => {\n    type ComposeStoriesParam = Parameters<typeof composeStories>[0];\n\n    expectTypeOf({\n      ...ButtonStories,\n      default: ButtonStories.default as Meta<typeof Button>,\n    }).toMatchTypeOf<ComposeStoriesParam>();\n\n    expectTypeOf({\n      ...ButtonStories,\n      default: ButtonStories.default satisfies Meta<typeof Button>,\n    }).toMatchTypeOf<ComposeStoriesParam>();\n  });\n});\n\nconst testCases = Object.values(composeStories(ButtonStories)).map(\n  (Story) => [Story.storyName, Story] as [string, typeof Story]\n);\nit.each(testCases)('Renders %s story', async (_storyName, Story) => {\n  if (_storyName === 'CSF2StoryWithLocale' || _storyName === 'MountInPlayFunctionThrow') {\n    return;\n  }\n  await Story.run();\n  expect(document.body).toMatchSnapshot();\n});\n"
  },
  {
    "path": "code/renderers/react/src/act-compat.ts",
    "content": "// Copied from\n// https://github.com/testing-library/react-testing-library/blob/3dcd8a9649e25054c0e650d95fca2317b7008576/src/act-compat.js\nimport * as React from 'react';\n\ndeclare const globalThis: {\n  IS_REACT_ACT_ENVIRONMENT: boolean;\n};\n\n// We need to spread React to avoid\n// export 'act' (imported as 'React4') was not found in 'react' errors in webpack\n// We do check if act exists, but webpack will still throw an error on compile time\nconst clonedReact = { ...React };\n\nexport function setReactActEnvironment(isReactActEnvironment: boolean) {\n  globalThis.IS_REACT_ACT_ENVIRONMENT = isReactActEnvironment;\n}\n\nexport function getReactActEnvironment() {\n  return globalThis.IS_REACT_ACT_ENVIRONMENT;\n}\n\nfunction withGlobalActEnvironment(actImplementation: (callback: () => void) => Promise<any>) {\n  return (callback: () => any) => {\n    const previousActEnvironment = getReactActEnvironment();\n    setReactActEnvironment(true);\n    try {\n      // The return value of `act` is always a thenable.\n      let callbackNeedsToBeAwaited = false;\n      const actResult = actImplementation(() => {\n        const result = callback();\n        if (result !== null && typeof result === 'object' && typeof result.then === 'function') {\n          callbackNeedsToBeAwaited = true;\n        }\n        return result;\n      });\n      if (callbackNeedsToBeAwaited) {\n        const thenable = actResult;\n        return {\n          then: (resolve: (param: any) => void, reject: (param: any) => void) => {\n            thenable.then(\n              (returnValue: any) => {\n                setReactActEnvironment(previousActEnvironment);\n                resolve(returnValue);\n              },\n              (error: any) => {\n                setReactActEnvironment(previousActEnvironment);\n                reject(error);\n              }\n            );\n          },\n        };\n      } else {\n        setReactActEnvironment(previousActEnvironment);\n        return actResult;\n      }\n    } catch (error) {\n      // Can't be a `finally {}` block since we don't know if we have to immediately restore IS_REACT_ACT_ENVIRONMENT\n      // or if we have to await the callback first.\n      setReactActEnvironment(previousActEnvironment);\n      throw error;\n    }\n  };\n}\n\nexport const getAct = async ({ disableAct = false }: { disableAct?: boolean } = {}) => {\n  if (process.env.NODE_ENV === 'production' || disableAct) {\n    return (cb: (...args: any[]) => any) => cb();\n  }\n\n  let reactAct: typeof React.act;\n  if (typeof clonedReact.act === 'function') {\n    reactAct = clonedReact.act;\n  } else {\n    // Lazy loading this makes sure that @storybook/react can be loaded in SSR contexts\n    // For example when SSR'ing portable stories\n    const deprecatedTestUtils = await import('react-dom/test-utils');\n    reactAct = deprecatedTestUtils?.default?.act ?? deprecatedTestUtils.act;\n  }\n\n  return withGlobalActEnvironment(reactAct);\n};\n"
  },
  {
    "path": "code/renderers/react/src/applyDecorators.ts",
    "content": "import React from 'react';\n\nimport type { DecoratorFunction, LegacyStoryFn } from 'storybook/internal/types';\n\nimport { defaultDecorateStory } from 'storybook/preview-api';\n\nimport type { ReactRenderer } from './types.ts';\n\nexport const applyDecorators = (\n  storyFn: LegacyStoryFn<ReactRenderer>,\n  decorators: DecoratorFunction<ReactRenderer>[]\n): LegacyStoryFn<ReactRenderer> => {\n  return defaultDecorateStory((context) => React.createElement(storyFn, context), decorators);\n};\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/Arrow.ts",
    "content": "interface CardProps {\n  title: string;\n}\nexport const Card = (props: CardProps) => null;\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/Button.ts",
    "content": "interface ButtonProps {\n  label: string;\n  disabled?: boolean;\n}\nexport function Button(props: ButtonProps) {\n  return null;\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/DefaultExport.ts",
    "content": "interface IconProps {\n  name: string;\n  size?: number;\n}\nfunction Icon(props: IconProps) {\n  return null;\n}\nexport default Icon;\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/DefaultValues.ts",
    "content": "interface AlertProps {\n  message: string;\n  severity?: string;\n}\nexport function Alert({ message, severity = 'info' }: AlertProps) {\n  return null;\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/DisplayNameOverride.ts",
    "content": "import type { FC } from 'react';\n\ninterface ModalProps {\n  title: string;\n  open?: boolean;\n}\n\n// Component has an explicit displayName that differs from the variable name\nconst InternalModal: FC<ModalProps> = (props) => null as any;\nInternalModal.displayName = 'FancyModal';\n\nexport { InternalModal as Modal };\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/Documented.ts",
    "content": "interface TooltipProps {\n  /** The content to display */\n  content: string;\n}\n/** A tooltip component. */\nexport function Tooltip(props: TooltipProps) {\n  return null;\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/DtsComponent.tsx",
    "content": "import type { ButtonHTMLAttributes } from 'react';\n\ninterface HtmlButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n  /** The button variant */\n  variant?: 'solid' | 'outline';\n}\n\nexport function HtmlButton(props: HtmlButtonProps) {\n  return null;\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/ForwardRef.tsx",
    "content": "import { forwardRef } from 'react';\n\ninterface TextInputProps {\n  /** Input label */\n  label: string;\n  /** Placeholder text */\n  placeholder?: string;\n  /** Change handler */\n  onChange?: (value: string) => void;\n}\n\nexport const TextInput = forwardRef<HTMLInputElement, TextInputProps>(\n  function TextInput(props, ref) {\n    return null;\n  }\n);\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/FunctionProps.ts",
    "content": "interface CallbackProps {\n  onClick?: (id: string) => void;\n  onSubmit: () => boolean;\n}\nexport function Callback(props: CallbackProps) {\n  return null;\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/Generic.ts",
    "content": "interface ListProps<T> {\n  items: T[];\n  renderItem: (item: T) => string;\n  emptyMessage?: string;\n}\n\nexport function StringList(props: ListProps<string>) {\n  return null;\n}\n\nexport function NumberList(props: ListProps<number>) {\n  return null;\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/ImportedProps.ts",
    "content": "import type { ClickableProps, SharedProps, Variant } from './types';\n\ninterface BadgeProps extends SharedProps, ClickableProps {\n  /** The badge label */\n  label: string;\n  variant: Variant;\n  count?: number;\n}\n\nexport function Badge(props: BadgeProps) {\n  return null;\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/Intersection.ts",
    "content": "type Base = {\n  id: string;\n  createdAt: Date;\n};\n\ntype WithMeta = {\n  tags: string[];\n  archived?: boolean;\n};\n\ntype ItemProps = Base &\n  WithMeta & {\n    title: string;\n    onSave: () => Promise<void>;\n  };\n\nexport function Item(props: ItemProps) {\n  return null;\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/MultipleExports.ts",
    "content": "interface InputProps {\n  placeholder?: string;\n}\nexport function Input(props: InputProps) {\n  return null;\n}\n\ninterface LabelProps {\n  text: string;\n}\nexport default function Bla(props: LabelProps) {\n  return null;\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/NoComponents.ts",
    "content": "export function add(a: number, b: number) {\n  return a + b;\n}\nexport const PI = 3.14;\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/PickOmit.ts",
    "content": "import type { ClickableProps, SharedProps } from './types';\n\ntype CardProps = Pick<SharedProps, 'id'> &\n  Omit<ClickableProps, 'disabled'> & {\n    title: string;\n    subtitle?: string;\n  };\n\nexport function Card(props: CardProps) {\n  return null;\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/ReExport.ts",
    "content": "export { Badge } from './ImportedProps';\nexport { Card as RenamedCard } from './PickOmit';\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/RenamedExport.ts",
    "content": "import type { FC } from 'react';\n\ninterface AlertProps {\n  message: string;\n  severity?: 'info' | 'warning' | 'error';\n}\n\n// Internal name is \"Alert\" but consumers see \"NotificationBanner\"\nconst Alert: FC<AlertProps> = (props) => null as any;\n\nexport { Alert as NotificationBanner };\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/UnionProps.ts",
    "content": "interface TagProps {\n  variant: 'primary' | 'secondary' | 'danger';\n  size?: 'small' | 'large';\n}\nexport function Tag(props: TagProps) {\n  return null;\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/barrel/Button.ts",
    "content": "interface ButtonProps {\n  label: string;\n  size?: 'sm' | 'md' | 'lg';\n}\nexport function Button(props: ButtonProps) {\n  return null;\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/barrel/Input.ts",
    "content": "interface InputProps {\n  value: string;\n  onChange: (value: string) => void;\n}\nexport function Input(props: InputProps) {\n  return null;\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/barrel/index.ts",
    "content": "export * from './Button';\nexport * from './Input';\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/__testfixtures__/types.ts",
    "content": "export interface SharedProps {\n  /** Unique identifier */\n  id: string;\n  /** Optional CSS class name */\n  className?: string;\n}\n\nexport type Variant = 'primary' | 'secondary' | 'danger';\n\nexport interface ClickableProps {\n  /** Click handler */\n  onClick?: (event: { target: string }) => void;\n  disabled?: boolean;\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/componentMeta/ComponentMetaManager.test.ts",
    "content": "import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport { afterEach, describe, expect, it } from 'vitest';\n\nimport { dedent } from 'ts-dedent';\nimport ts from 'typescript';\n\nimport type { StoryRef } from '../getComponentImports.ts';\nimport { ComponentMetaManager, isFileInDir, sortTSConfigs } from './ComponentMetaManager.ts';\nimport { cleanup, createTempDir, tsconfigJSON, writeFiles } from './test-helpers.ts';\n\n// ---------------------------------------------------------------------------\n// Unit tests: sortTSConfigs and isFileInDir\n// ---------------------------------------------------------------------------\n\ndescribe('isFileInDir', () => {\n  it('returns true for a file inside the directory', () => {\n    expect(isFileInDir('/project/src/Button.tsx', '/project')).toBe(true);\n    expect(isFileInDir('/project/src/Button.tsx', '/project/src')).toBe(true);\n  });\n\n  it('returns false for a file outside the directory', () => {\n    expect(isFileInDir('/other/Button.tsx', '/project')).toBe(false);\n    expect(isFileInDir('/project/../other/Button.tsx', '/project')).toBe(false);\n  });\n\n  it('returns false for the directory itself', () => {\n    expect(isFileInDir('/project', '/project')).toBe(false);\n  });\n});\n\ndescribe('sortTSConfigs', () => {\n  it('prefers tsconfig whose directory contains the file', () => {\n    const result = sortTSConfigs(\n      '/project/src/Button.tsx',\n      '/project/tsconfig.json',\n      '/other/tsconfig.json'\n    );\n    // a contains file, b does not → a should come first (negative result)\n    expect(result).toBeLessThan(0);\n  });\n\n  it('prefers deeper tsconfig when both contain the file', () => {\n    const result = sortTSConfigs(\n      '/project/src/components/Button.tsx',\n      '/project/tsconfig.json',\n      '/project/src/tsconfig.json'\n    );\n    // b is deeper → b should come first (positive result)\n    expect(result).toBeGreaterThan(0);\n  });\n\n  it('prefers tsconfig.json over jsconfig.json at same depth', () => {\n    const result = sortTSConfigs(\n      '/project/src/Button.tsx',\n      '/project/tsconfig.json',\n      '/project/jsconfig.json'\n    );\n    // Same depth, a is tsconfig.json → a should come first (negative result)\n    expect(result).toBeLessThan(0);\n  });\n\n  it('returns 0 for identical configs', () => {\n    const result = sortTSConfigs(\n      '/project/src/Button.tsx',\n      '/project/tsconfig.json',\n      '/project/tsconfig.json'\n    );\n    expect(result).toBe(0);\n  });\n});\n\n// ---------------------------------------------------------------------------\n// ComponentMetaManager: multi-project scenarios\n// ---------------------------------------------------------------------------\n\ndescribe('multi-project management', () => {\n  let tempDir: string | undefined;\n  let manager: ComponentMetaManager;\n\n  afterEach(() => {\n    manager?.dispose();\n    if (tempDir) {\n      cleanup(tempDir);\n      tempDir = undefined;\n    }\n  });\n\n  it('creates separate projects for files under different tsconfigs', { timeout: 30_000 }, () => {\n    tempDir = createTempDir();\n\n    writeFiles(tempDir, {\n      'app/tsconfig.json': tsconfigJSON(),\n      'app/Button.tsx': dedent`\n        import React from 'react';\n        export const Button = (_props: { label: string }) => <button />;\n      `,\n      'lib/tsconfig.json': tsconfigJSON(),\n      'lib/Card.tsx': dedent`\n        import React from 'react';\n        export const Card = (_props: { title: string }) => <div />;\n      `,\n    });\n\n    manager = new ComponentMetaManager(ts);\n\n    const buttonProject = manager.getProjectForFile(path.join(tempDir, 'app/Button.tsx'));\n    const cardProject = manager.getProjectForFile(path.join(tempDir, 'lib/Card.tsx'));\n\n    // Different tsconfigs → different project instances\n    expect(buttonProject).not.toBe(cardProject);\n  });\n\n  it('falls back to inferred project when no tsconfig found', { timeout: 30_000 }, () => {\n    tempDir = createTempDir();\n\n    writeFiles(tempDir, {\n      'Button.tsx': dedent`\n        import React from 'react';\n        export const Button = (_props: { label: string }) => <button />;\n      `,\n    });\n\n    // Remove the tsconfig that createTempDir might have created\n    const possibleTsconfig = path.join(tempDir, 'tsconfig.json');\n    if (fs.existsSync(possibleTsconfig)) {\n      fs.unlinkSync(possibleTsconfig);\n    }\n\n    manager = new ComponentMetaManager(ts);\n\n    const project = manager.getProjectForFile(path.join(tempDir, 'Button.tsx'));\n    expect(project).toBeDefined();\n  });\n\n  it('broadcasts file changes to all projects', { timeout: 30_000 }, () => {\n    tempDir = createTempDir();\n\n    const files = writeFiles(tempDir, {\n      'tsconfig.json': tsconfigJSON(),\n      'Tag.tsx': dedent`\n        import React from 'react';\n        export const Tag = (_props: { text: string }) => <span />;\n      `,\n      'Tag.stories.tsx': dedent`\n        import { Tag } from './Tag';\n        export default { component: Tag };\n      `,\n    });\n\n    manager = new ComponentMetaManager(ts);\n    const tagPath = path.join(tempDir, 'Tag.tsx');\n    const project = manager.getProjectForFile(tagPath);\n\n    // Initial extraction\n    const entries1: StoryRef[] = [\n      {\n        storyPath: files['Tag.stories.tsx'],\n        component: {\n          componentName: 'Tag',\n          importName: 'Tag',\n          path: tagPath,\n          isPackage: false,\n        },\n      },\n    ];\n    project.extractPropsFromStories(entries1);\n    expect(entries1[0].component?.reactComponentMeta).toMatchObject({\n      props: { text: expect.anything() },\n    });\n    expect(entries1[0].component?.reactComponentMeta?.props?.color).toBeUndefined();\n\n    // Modify the file\n    fs.writeFileSync(\n      tagPath,\n      dedent`\n        import React from 'react';\n        export const Tag = (_props: { text: string; color?: string }) => <span />;\n      `\n    );\n\n    // Broadcast change via manager (not project directly)\n    manager.onFilesChanged([{ filePath: tagPath, type: 'changed' }]);\n\n    // Re-extract — should see the new prop\n    const entries2: StoryRef[] = [\n      {\n        storyPath: files['Tag.stories.tsx'],\n        component: {\n          componentName: 'Tag',\n          importName: 'Tag',\n          path: tagPath,\n          isPackage: false,\n        },\n      },\n    ];\n    project.extractPropsFromStories(entries2);\n    expect(entries2[0].component?.reactComponentMeta).toMatchObject({\n      props: { color: expect.anything() },\n    });\n  });\n\n  it('handles config change: deleted tsconfig disposes project', () => {\n    tempDir = createTempDir();\n\n    const files = writeFiles(tempDir, {\n      'tsconfig.json': tsconfigJSON(),\n      'Button.tsx': dedent`\n        import React from 'react';\n        export const Button = (_props: { label: string }) => <button />;\n      `,\n    });\n\n    manager = new ComponentMetaManager(ts);\n    const configPath = files['tsconfig.json'];\n\n    // Create project by looking up file\n    const project1 = manager.getProjectForFile(files['Button.tsx']);\n    expect(project1).toBeDefined();\n\n    // Delete the tsconfig\n    manager.onConfigChanged(configPath, 'deleted');\n\n    // Next lookup should create a new project (or inferred)\n    const project2 = manager.getProjectForFile(files['Button.tsx']);\n    // Should be a different instance (old one was disposed)\n    expect(project2).not.toBe(project1);\n  });\n\n  it('handles config change: created tsconfig is discovered', { timeout: 30_000 }, () => {\n    tempDir = createTempDir();\n\n    writeFiles(tempDir, {\n      'Button.tsx': dedent`\n        import React from 'react';\n        export const Button = (_props: { label: string }) => <button />;\n      `,\n    });\n\n    manager = new ComponentMetaManager(ts);\n    const configPath = path.join(tempDir, 'tsconfig.json');\n\n    // First lookup (no tsconfig yet — may use inferred or find monorepo root)\n    const project1 = manager.getProjectForFile(path.join(tempDir, 'Button.tsx'));\n    expect(project1).toBeDefined();\n\n    // Now write a tsconfig and notify the manager\n    fs.writeFileSync(configPath, tsconfigJSON());\n\n    manager.onConfigChanged(configPath, 'created');\n\n    // Next lookup should use the new tsconfig\n    const project2 = manager.getProjectForFile(path.join(tempDir, 'Button.tsx'));\n    expect(project2).toBeDefined();\n  });\n\n  it('shares fsFileSnapshots across projects', { timeout: 30_000 }, () => {\n    tempDir = createTempDir();\n\n    const files = writeFiles(tempDir, {\n      'app/tsconfig.json': tsconfigJSON(),\n      'app/Button.tsx': dedent`\n        import React from 'react';\n        export const Button = (_props: { label: string }) => <button />;\n      `,\n      'app/Button.stories.tsx': dedent`\n        import { Button } from './Button';\n        export default { component: Button };\n      `,\n      'lib/tsconfig.json': tsconfigJSON(),\n      'lib/Card.tsx': dedent`\n        import React from 'react';\n        export const Card = (_props: { title: string }) => <div />;\n      `,\n      'lib/Card.stories.tsx': dedent`\n        import { Card } from './Card';\n        export default { component: Card };\n      `,\n    });\n\n    manager = new ComponentMetaManager(ts);\n\n    // Access both projects and trigger extraction (populates fsFileSnapshots)\n    const p1 = manager.getProjectForFile(path.join(tempDir, 'app/Button.tsx'));\n    p1.extractPropsFromStories([\n      {\n        storyPath: files['app/Button.stories.tsx'],\n        component: {\n          componentName: 'Button',\n          importName: 'Button',\n          path: files['app/Button.tsx'],\n          isPackage: false,\n        },\n      },\n    ]);\n    const p2 = manager.getProjectForFile(path.join(tempDir, 'lib/Card.tsx'));\n    p2.extractPropsFromStories([\n      {\n        storyPath: files['lib/Card.stories.tsx'],\n        component: {\n          componentName: 'Card',\n          importName: 'Card',\n          path: files['lib/Card.tsx'],\n          isPackage: false,\n        },\n      },\n    ]);\n\n    // fsFileSnapshots is shared — entries from both projects exist in one map\n    expect(manager.fsFileSnapshots.size).toBeGreaterThan(0);\n  });\n\n  it('project references: finds file via referenced project', () => {\n    tempDir = createTempDir();\n\n    writeFiles(tempDir, {\n      'tsconfig.json': tsconfigJSON({ references: [{ path: './packages/ui' }], files: [] }),\n      'packages/ui/tsconfig.json': tsconfigJSON({\n        compilerOptions: {\n          target: 'ES2020',\n          module: 'ESNext',\n          jsx: 'react-jsx',\n          strict: true,\n          esModuleInterop: true,\n          moduleResolution: 'bundler',\n          composite: true,\n        },\n      }),\n      'packages/ui/Button.tsx': dedent`\n        import React from 'react';\n        export const Button = (_props: { label: string }) => <button />;\n      `,\n    });\n\n    manager = new ComponentMetaManager(ts);\n    const filePath = path.join(tempDir, 'packages/ui/Button.tsx');\n    const project = manager.getProjectForFile(filePath);\n\n    expect(project).toBeDefined();\n  });\n\n  it('extracts via Path 1 (importId + JSX in story file)', { timeout: 30_000 }, () => {\n    tempDir = createTempDir();\n\n    writeFiles(tempDir, {\n      'tsconfig.json': tsconfigJSON(),\n      'Button.tsx': dedent`\n        import React from 'react';\n        export const Button = (_props: { label: string; disabled?: boolean }) => <button />;\n      `,\n      'Button.stories.tsx': dedent`\n        import { Button } from './Button';\n        const _story = () => <Button label=\"click me\" />;\n      `,\n    });\n\n    manager = new ComponentMetaManager(ts);\n    const componentPath = path.join(tempDir, 'Button.tsx');\n    const storyPath = path.join(tempDir, 'Button.stories.tsx');\n    const project = manager.getProjectForFile(componentPath);\n\n    project.ensureFiles([storyPath]);\n\n    const entries: StoryRef[] = [\n      {\n        storyPath,\n        component: {\n          componentName: 'Button',\n          importId: './Button',\n          importName: 'Button',\n          path: componentPath,\n          isPackage: false,\n        },\n      },\n    ];\n    project.extractPropsFromStories(entries);\n\n    expect(entries[0].component?.reactComponentMeta).toMatchObject({\n      displayName: 'Button',\n      props: {\n        label: expect.anything(),\n        disabled: expect.anything(),\n      },\n    });\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/componentMeta/ComponentMetaManager.ts",
    "content": "/**\n * ComponentMetaManager — multi-project manager for component metadata extraction.\n *\n * Mirrors Volar-style project management patterns:\n *\n * - https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L18-L390\n * - https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProjectLs.ts#L262-L353\n * - ConfigProjects / inferredProject / rootTsConfigs / searchedDirs\n * - FindMatchTSConfig → prepareClosestRootCommandLine / findDirectIncludeTsconfig /\n *   findIndirectReferenceTsconfig / findTSConfig / getReferencesChains / getCommandLine\n * - GetOrCreateConfiguredProject / getOrCreateInferredProject\n * - SortTSConfigs / isFileInDir\n * - Config change handler (Created / Changed+Deleted dispose pattern)\n *\n * Plus our own file watching layer (fs.watch + debounce) since we're a standalone Node.js process,\n * not running inside an IDE.\n */\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { type FSWatcher, existsSync, watch } from 'fs';\nimport * as path from 'path';\nimport type ts from 'typescript';\n\nimport type { StoryRef } from '../getComponentImports.ts';\nimport { groupByToMap } from '../utils.ts';\nimport { ComponentMetaProject } from './ComponentMetaProject.ts';\n\n// Adapted from:\n// https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L18\nconst rootTsConfigNames = ['tsconfig.json', 'jsconfig.json'];\n\nconst DEFAULT_INFERRED_OPTIONS: ts.CompilerOptions = {\n  strict: true,\n  esModuleInterop: true,\n  allowJs: true,\n  skipLibCheck: true,\n};\n\nexport class ComponentMetaManager {\n  // Adapted from:\n  // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L34-L37\n  private configProjects = new Map<string, ComponentMetaProject>();\n  private inferredProject: ComponentMetaProject | undefined;\n  private rootTsConfigs = new Set<string>();\n  private searchedDirs = new Set<string>();\n\n  // Our own file watching layer\n  private watching = false;\n  private watchersByDir = new Map<string, FSWatcher>();\n  private pendingEvents = new Map<string, ReturnType<typeof setTimeout>>();\n\n  // Adapted from:\n  // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/kit/lib/createChecker.ts#L83\n  readonly fsFileSnapshots = new Map<\n    string,\n    [number | undefined, ts.IScriptSnapshot | undefined]\n  >();\n\n  constructor(private typescript: typeof ts) {}\n\n  // ---------------------------------------------------------------------------\n  // Adapted from:\n  // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L70-L79\n  // ---------------------------------------------------------------------------\n\n  getProjectForFile(fileName: string): ComponentMetaProject {\n    const tsconfig = this.findMatchTSConfig(fileName);\n    if (tsconfig) {\n      // Adapted from:\n      // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L71-L77\n      // Always go through getOrCreateConfiguredProject — never raw map lookup.\n      return (\n        this.getOrCreateConfiguredProject(tsconfig) ?? this.getOrCreateInferredProject(fileName)\n      );\n    }\n    return this.getOrCreateInferredProject(fileName);\n  }\n\n  /**\n   * Batch-extract component props across all entries, grouping by tsconfig project so each project\n   * builds its TS program only once.\n   */\n  batchExtract(entries: StoryRef[]): void {\n    const extractableEntries = entries.filter(\n      (storyRef) => storyRef.component?.path && storyRef.component.importName\n    );\n    const byProject = groupByToMap(extractableEntries, (storyRef) =>\n      this.getProjectForFile(storyRef.storyPath)\n    );\n\n    for (const [project, projectEntries] of byProject) {\n      try {\n        project.extractPropsFromStories(projectEntries);\n      } catch (err) {\n        logger.debug(`[reactComponentMeta] Batch extraction failed: ${err}`);\n      }\n    }\n  }\n\n  // ---------------------------------------------------------------------------\n  // Adapted from:\n  // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L101-L234\n  // ---------------------------------------------------------------------------\n\n  private findMatchTSConfig(filePath: string): string | null {\n    const fileName = filePath.replace(/\\\\/g, '/');\n\n    // Adapted from:\n    // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L104-L118\n    let dir = path.dirname(fileName);\n    while (true) {\n      if (this.searchedDirs.has(dir)) {\n        break;\n      }\n      this.searchedDirs.add(dir);\n      for (const tsConfigName of rootTsConfigNames) {\n        const tsconfigPath = path.join(dir, tsConfigName).replace(/\\\\/g, '/');\n        if (this.typescript.sys.fileExists(tsconfigPath)) {\n          this.rootTsConfigs.add(tsconfigPath);\n        }\n      }\n      const parent = path.dirname(dir);\n      if (parent === dir) {\n        break;\n      }\n      dir = parent;\n    }\n\n    if (this.rootTsConfigs.size === 0) {\n      return null;\n    }\n\n    // Adapted from:\n    // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L124-L138\n    // Side-effect only: pre-creates the closest project via getCommandLine() so that\n    // findIndirectReferenceTsconfig below can inspect its project references.\n    const prepareClosestRootCommandLine = () => {\n      let matches: string[] = [];\n      for (const rootTsConfig of this.rootTsConfigs) {\n        if (isFileInDir(fileName, path.dirname(rootTsConfig))) {\n          matches.push(rootTsConfig);\n        }\n      }\n      matches = matches.sort((a, b) => sortTSConfigs(fileName, a, b));\n      if (matches.length) {\n        getCommandLine(matches[0]);\n      }\n    };\n\n    // Adapted from:\n    // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L139-L147\n    const findIndirectReferenceTsconfig = () => {\n      return findTSConfig((tsconfig) => {\n        const project = this.configProjects.get(tsconfig);\n        return !!project?.hasSourceFile(fileName);\n      });\n    };\n\n    // Adapted from:\n    // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L149-L158\n    const findDirectIncludeTsconfig = () => {\n      return findTSConfig((tsconfig) => {\n        const commandLine = getCommandLine(tsconfig);\n        const fileNames = new Set(commandLine?.fileNames ?? []);\n        return fileNames.has(fileName);\n      });\n    };\n\n    // Adapted from:\n    // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L160-L188\n    const findTSConfig = (match: (tsconfig: string) => boolean): string | null => {\n      const checked = new Set<string>();\n\n      for (const rootTsConfig of [...this.rootTsConfigs].sort((a, b) =>\n        sortTSConfigs(fileName, a, b)\n      )) {\n        const project = this.configProjects.get(rootTsConfig);\n        if (project) {\n          let chains = getReferencesChains(project.getCommandLine(), rootTsConfig, []);\n\n          // This is to be consistent with tsserver behavior\n          chains = chains.reverse();\n\n          for (const chain of chains) {\n            for (let i = chain.length - 1; i >= 0; i--) {\n              const tsconfig = chain[i];\n\n              if (checked.has(tsconfig)) {\n                continue;\n              }\n              checked.add(tsconfig);\n\n              if (match(tsconfig)) {\n                return tsconfig;\n              }\n            }\n          }\n        }\n      }\n\n      return null;\n    };\n\n    // Adapted from:\n    // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L189-L229\n    const getReferencesChains = (\n      commandLine: ts.ParsedCommandLine,\n      tsConfig: string,\n      before: string[]\n    ): string[][] => {\n      if (commandLine.projectReferences?.length) {\n        const newChains: string[][] = [];\n\n        for (const projectReference of commandLine.projectReferences) {\n          let tsConfigPath = projectReference.path.replace(/\\\\/g, '/');\n\n          // fix https://github.com/johnsoncodehk/volar/issues/712\n          if (this.typescript.sys.directoryExists(tsConfigPath)) {\n            const newTsConfigPath = path.join(tsConfigPath, 'tsconfig.json');\n            const newJsConfigPath = path.join(tsConfigPath, 'jsconfig.json');\n            if (this.typescript.sys.fileExists(newTsConfigPath)) {\n              tsConfigPath = newTsConfigPath;\n            } else if (this.typescript.sys.fileExists(newJsConfigPath)) {\n              tsConfigPath = newJsConfigPath;\n            }\n          }\n\n          const beforeIndex = before.indexOf(tsConfigPath); // cycle\n          if (beforeIndex >= 0) {\n            newChains.push(before.slice(0, Math.max(beforeIndex, 1)));\n          } else {\n            const referenceCommandLine = getCommandLine(tsConfigPath);\n            if (referenceCommandLine) {\n              for (const chain of getReferencesChains(referenceCommandLine, tsConfigPath, [\n                ...before,\n                tsConfig,\n              ])) {\n                newChains.push(chain);\n              }\n            }\n          }\n        }\n\n        return newChains;\n      } else {\n        return [[...before, tsConfig]];\n      }\n    };\n\n    // Adapted from:\n    // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L230-L233\n    const getCommandLine = (tsConfig: string) => {\n      const project = this.getOrCreateConfiguredProject(tsConfig);\n      return project?.getCommandLine();\n    };\n\n    prepareClosestRootCommandLine();\n\n    return findDirectIncludeTsconfig() ?? findIndirectReferenceTsconfig();\n  }\n\n  // ---------------------------------------------------------------------------\n  // Adapted from:\n  // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L236-L256\n  // ---------------------------------------------------------------------------\n\n  private getOrCreateConfiguredProject(tsconfig: string): ComponentMetaProject | null {\n    tsconfig = tsconfig.replace(/\\\\/g, '/');\n    let project = this.configProjects.get(tsconfig);\n    if (!project) {\n      try {\n        const getCommandLine = () => this.parseConfigWorker(tsconfig);\n        project = new ComponentMetaProject(\n          this.typescript,\n          getCommandLine(),\n          tsconfig,\n          this.fsFileSnapshots,\n          getCommandLine\n        );\n        this.configProjects.set(tsconfig, project);\n\n        // Auto-watch the project's directories if watching is active.\n        // This covers projects discovered after initial startWatching().\n        if (this.watching) {\n          this.watchDirectory(path.dirname(tsconfig));\n          this.watchProgramSourceDirs(project);\n        }\n      } catch (err) {\n        logger.debug(`[reactComponentMeta] Failed to parse tsconfig ${tsconfig}: ${err}`);\n        return null;\n      }\n    }\n    return project;\n  }\n\n  // ---------------------------------------------------------------------------\n  // Adapted from:\n  // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L258-L284\n  // ---------------------------------------------------------------------------\n\n  private getOrCreateInferredProject(fileName: string): ComponentMetaProject {\n    if (!this.inferredProject) {\n      this.inferredProject = new ComponentMetaProject(\n        this.typescript,\n        {\n          options: {\n            ...DEFAULT_INFERRED_OPTIONS,\n            target: this.typescript.ScriptTarget.Latest,\n            module: this.typescript.ModuleKind.ESNext,\n            moduleResolution: this.typescript.ModuleResolutionKind.Bundler,\n            jsx: this.typescript.JsxEmit.ReactJSX,\n          },\n          fileNames: [],\n          errors: [],\n        },\n        undefined,\n        this.fsFileSnapshots\n      );\n    }\n\n    this.inferredProject.ensureFiles([fileName]);\n\n    return this.inferredProject;\n  }\n\n  // ---------------------------------------------------------------------------\n  // Adapted from:\n  // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProjectLs.ts#L262-L353\n  // ---------------------------------------------------------------------------\n\n  private parseConfigWorker(tsconfig: string): ts.ParsedCommandLine {\n    const config = this.typescript.readJsonConfigFile(tsconfig, this.typescript.sys.readFile);\n    const content = this.typescript.parseJsonSourceFileConfigFileContent(\n      config,\n      this.typescript.sys,\n      path.dirname(tsconfig),\n      {},\n      tsconfig\n    );\n    // fix https://github.com/johnsoncodehk/volar/issues/1786\n    // https://github.com/microsoft/TypeScript/issues/30457\n    content.options.outDir = undefined;\n    content.fileNames = content.fileNames.map((fileName) => fileName.replace(/\\\\/g, '/'));\n    return content;\n  }\n\n  // ---------------------------------------------------------------------------\n  // File events\n  // ---------------------------------------------------------------------------\n\n  /**\n   * Broadcast file changes to all projects. Each project selectively bumps projectVersion.\n   *\n   * Adapted from:\n   * https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/kit/lib/createChecker.ts#L409-L432\n   */\n  onFilesChanged(changes: Array<{ filePath: string; type: 'changed' | 'created' | 'deleted' }>) {\n    for (const project of this.configProjects.values()) {\n      project.onFilesChanged(changes);\n    }\n    this.inferredProject?.onFilesChanged(changes);\n  }\n\n  /**\n   * Adapted from:\n   * https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L43-L68\n   */\n  onConfigChanged(configPath: string, type: 'created' | 'changed' | 'deleted') {\n    configPath = configPath.replace(/\\\\/g, '/');\n    if (type === 'created') {\n      this.rootTsConfigs.add(configPath);\n    } else if ((type === 'changed' || type === 'deleted') && this.configProjects.has(configPath)) {\n      if (type === 'deleted') {\n        this.rootTsConfigs.delete(configPath);\n      }\n      const project = this.configProjects.get(configPath);\n      this.configProjects.delete(configPath);\n      project?.dispose();\n    }\n    // Clear searchedDirs so findMatchTSConfig re-scans directories.\n    // Without this, new tsconfigs in previously-scanned dirs would be invisible.\n    this.searchedDirs.clear();\n  }\n\n  // ---------------------------------------------------------------------------\n  // Our own file watching layer (no Volar equivalent — we're standalone)\n  // ---------------------------------------------------------------------------\n\n  startWatching(): void {\n    if (this.watching) {\n      return;\n    }\n    this.watching = true;\n\n    // Retroactively create watchers for projects that were created before\n    // watching was enabled (the first manifest request creates projects\n    // eagerly, but startWatching() is only called once the manager is ready).\n    for (const tsconfig of this.configProjects.keys()) {\n      this.watchDirectory(path.dirname(tsconfig));\n    }\n\n    // Also watch directories containing source files resolved by the TS program.\n    // This covers files reached via path aliases (e.g. monorepos where stories\n    // live in apps/storybook/ but components live in packages/ui/).\n    this.watchProgramSourceDirs();\n  }\n\n  /**\n   * Watch directories that contain source files from all TS programs. This covers monorepo setups\n   * where stories import components via path aliases (e.g. apps/storybook/ imports from\n   * packages/ui/ via tsconfig paths).\n   */\n  private watchProgramSourceDirs(singleProject?: ComponentMetaProject): void {\n    const dirs = new Set<string>();\n\n    if (singleProject) {\n      for (const filePath of singleProject.getSourceFilePaths()) {\n        dirs.add(path.dirname(filePath));\n      }\n    } else {\n      for (const project of this.configProjects.values()) {\n        for (const filePath of project.getSourceFilePaths()) {\n          dirs.add(path.dirname(filePath));\n        }\n      }\n      if (this.inferredProject) {\n        for (const filePath of this.inferredProject.getSourceFilePaths()) {\n          dirs.add(path.dirname(filePath));\n        }\n      }\n    }\n\n    // Walk up from each source file dir to find package roots (package.json or tsconfig.json).\n    // This avoids creating hundreds of individual watchers for each subdirectory.\n    const roots = new Set<string>();\n    for (const dir of dirs) {\n      let candidate = dir;\n      while (candidate !== path.dirname(candidate)) {\n        // If already covered by an existing watcher, skip\n        const normalized = candidate.replace(/\\\\/g, '/');\n        let alreadyWatched = false;\n        for (const watched of this.watchersByDir.keys()) {\n          if (normalized === watched || normalized.startsWith(watched + '/')) {\n            alreadyWatched = true;\n            break;\n          }\n        }\n        if (alreadyWatched) {\n          break;\n        }\n\n        // Use package root as watch boundary\n        if (\n          this.typescript.sys.fileExists(path.join(candidate, 'package.json')) ||\n          this.typescript.sys.fileExists(path.join(candidate, 'tsconfig.json'))\n        ) {\n          roots.add(candidate);\n          break;\n        }\n        candidate = path.dirname(candidate);\n      }\n    }\n\n    for (const root of roots) {\n      this.watchDirectory(root);\n    }\n  }\n\n  private watchDirectory(dir: string): void {\n    if (!this.watching) {\n      return;\n    }\n\n    const normalized = dir.replace(/\\\\/g, '/');\n\n    for (const watched of this.watchersByDir.keys()) {\n      // Already covered by an existing broader watcher\n      if (normalized === watched || normalized.startsWith(watched + '/')) {\n        return;\n      }\n    }\n\n    // Close and remove narrower watchers that this broader directory subsumes.\n    // The new recursive watcher covers them, so keeping both wastes file descriptors\n    // and produces duplicate events.\n    for (const [watched, watcher] of this.watchersByDir) {\n      if (watched.startsWith(normalized + '/')) {\n        watcher.close();\n        this.watchersByDir.delete(watched);\n      }\n    }\n\n    try {\n      const watcher = watch(dir, { recursive: true }, (eventType, filename) => {\n        if (!filename) {\n          return;\n        }\n        const filePath = path.resolve(dir, filename).replace(/\\\\/g, '/');\n\n        if (filePath.includes('/node_modules/') || filePath.includes('/.git/')) {\n          return;\n        }\n\n        const existing = this.pendingEvents.get(filePath);\n        if (existing) {\n          clearTimeout(existing);\n        }\n\n        this.pendingEvents.set(\n          filePath,\n          setTimeout(() => {\n            this.pendingEvents.delete(filePath);\n\n            if (eventType === 'rename') {\n              if (existsSync(filePath)) {\n                this.handleFileEvent(filePath, 'created');\n              } else {\n                this.handleFileEvent(filePath, 'deleted');\n              }\n            } else {\n              this.handleFileEvent(filePath, 'changed');\n            }\n          }, 50)\n        );\n      });\n      watcher.unref();\n      this.watchersByDir.set(normalized, watcher);\n    } catch (err) {\n      logger.debug(`[reactComponentMeta] Failed to watch directory ${normalized}: ${err}`);\n    }\n  }\n\n  stopWatching(): void {\n    for (const timeout of this.pendingEvents.values()) {\n      clearTimeout(timeout);\n    }\n    this.pendingEvents.clear();\n    for (const watcher of this.watchersByDir.values()) {\n      watcher.close();\n    }\n    this.watchersByDir.clear();\n    this.watching = false;\n  }\n\n  /**\n   * Map raw fs.watch events to LSP-style FileChangeType before broadcasting.\n   *\n   * Fs.watch reports atomic saves (sed -i, editors) as `rename` → we classify as `created` (file\n   * exists after rename). But an IDE/LSP would report an atomic save of an _existing_ file as\n   * `Changed`, not `Created`.\n   *\n   * We reclassify here so that onFilesChanged stays 1:1 with Volar Kit.\n   */\n  private handleFileEvent(filePath: string, type: 'created' | 'changed' | 'deleted') {\n    // Reclassify: atomic save of tracked file → 'changed' (LSP Changed)\n    if (type === 'created') {\n      for (const project of this.configProjects.values()) {\n        if (project.hasSourceFile(filePath)) {\n          type = 'changed';\n          break;\n        }\n      }\n      if (type === 'created' && this.inferredProject?.hasSourceFile(filePath)) {\n        type = 'changed';\n      }\n    }\n\n    const basename = path.basename(filePath);\n    if (rootTsConfigNames.includes(basename)) {\n      this.onConfigChanged(filePath, type);\n      return;\n    }\n\n    this.onFilesChanged([{ filePath, type }]);\n  }\n\n  dispose() {\n    this.stopWatching();\n    for (const project of this.configProjects.values()) {\n      project.dispose();\n    }\n    this.inferredProject?.dispose();\n    this.configProjects.clear();\n    this.inferredProject = undefined;\n    this.fsFileSnapshots.clear();\n    this.searchedDirs.clear();\n    this.rootTsConfigs.clear();\n  }\n}\n\n// Adapted from:\n// https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L365-L385\nexport function sortTSConfigs(file: string, a: string, b: string) {\n  const inA = isFileInDir(file, path.dirname(a));\n  const inB = isFileInDir(file, path.dirname(b));\n\n  if (inA !== inB) {\n    const aWeight = inA ? 1 : 0;\n    const bWeight = inB ? 1 : 0;\n    return bWeight - aWeight;\n  }\n\n  const aLength = a.split('/').length;\n  const bLength = b.split('/').length;\n\n  if (aLength === bLength) {\n    const aWeight = path.basename(a) === 'tsconfig.json' ? 1 : 0;\n    const bWeight = path.basename(b) === 'tsconfig.json' ? 1 : 0;\n    return bWeight - aWeight;\n  }\n\n  return bLength - aLength;\n}\n\n// Adapted from:\n// https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProject.ts#L387-L390\nexport function isFileInDir(fileName: string, dir: string) {\n  const relative = path.relative(dir, fileName);\n  return !!relative && !relative.startsWith('..') && !path.isAbsolute(relative);\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/componentMeta/ComponentMetaProject.storyExtraction.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { dedent } from 'ts-dedent';\n\nimport { extractFromStory } from './componentMetaExtractor.test-helpers.ts';\n\ndescribe('prop extraction via story JSX', () => {\n  it('simple named export', async () => {\n    const entry = await extractFromStory(\n      {\n        'path1/Button.tsx': dedent`\n          import React from 'react';\n          interface ButtonProps {\n            /** The button label */\n            label: string;\n            variant?: 'solid' | 'outline';\n            disabled?: boolean;\n          }\n          export const Button = (props: ButtonProps) => <button>{props.label}</button>;\n        `,\n        'path1/Button.stories.tsx': dedent`\n          import React from 'react';\n          import { Button } from './Button';\n          export default { component: Button };\n          export const Default = () => <Button label=\"Click me\" variant=\"solid\" />;\n        `,\n      },\n      'path1/Button.stories.tsx'\n    );\n\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      displayName: 'Button',\n      exportName: 'Button',\n      props: {\n        label: {\n          type: { name: 'string' },\n          required: true,\n          description: 'The button label',\n          parent: { name: 'ButtonProps' },\n        },\n        variant: {\n          type: { name: 'enum', value: [{ value: '\"solid\"' }, { value: '\"outline\"' }] },\n          required: false,\n          parent: { name: 'ButtonProps' },\n        },\n        disabled: {\n          type: { name: 'boolean | undefined' },\n          required: false,\n          parent: { name: 'ButtonProps' },\n        },\n      },\n    });\n  });\n\n  it('generic component (TypeScript resolves type parameters)', async () => {\n    const entry = await extractFromStory(\n      {\n        'path1/GenericList.tsx': dedent`\n          import React from 'react';\n          interface ListProps<T> {\n            /** The items to render */\n            items: T[];\n            /** Render function for each item */\n            renderItem: (item: T) => React.ReactNode;\n            /** Optional label above the list */\n            title?: string;\n          }\n          export function GenericList<T>(props: ListProps<T>) {\n            return <ul>{props.items.map(props.renderItem)}</ul>;\n          }\n        `,\n        'path1/GenericList.stories.tsx': dedent`\n          import React from 'react';\n          import { GenericList } from './GenericList';\n          export default { component: GenericList };\n          export const StringList = () => (\n            <GenericList items={['a', 'b']} renderItem={(s) => <li>{s}</li>} />\n          );\n        `,\n      },\n      'path1/GenericList.stories.tsx'\n    );\n\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      displayName: 'GenericList',\n      exportName: 'GenericList',\n      props: {\n        items: {\n          type: { name: 'string[]' },\n          required: true,\n          description: 'The items to render',\n          parent: { name: 'ListProps' },\n        },\n        renderItem: {\n          type: { name: '(item: string) => ReactNode' },\n          required: true,\n          description: 'Render function for each item',\n          parent: { name: 'ListProps' },\n        },\n        title: {\n          type: { name: 'string' },\n          required: false,\n          description: 'Optional label above the list',\n          parent: { name: 'ListProps' },\n        },\n      },\n    });\n  });\n\n  it('forwardRef component', async () => {\n    const entry = await extractFromStory(\n      {\n        'path1/ForwardRefButton.tsx': dedent`\n          import React from 'react';\n          interface FRButtonProps {\n            /** Button text */\n            text: string;\n            size?: 'sm' | 'md' | 'lg';\n          }\n          export const ForwardRefButton = React.forwardRef<HTMLButtonElement, FRButtonProps>(\n            (props, ref) => <button ref={ref}>{props.text}</button>\n          );\n        `,\n        'path1/ForwardRefButton.stories.tsx': dedent`\n          import React from 'react';\n          import { ForwardRefButton } from './ForwardRefButton';\n          export default { component: ForwardRefButton };\n          export const Default = () => <ForwardRefButton text=\"Hello\" size=\"md\" />;\n        `,\n      },\n      'path1/ForwardRefButton.stories.tsx'\n    );\n\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      displayName: 'ForwardRefButton',\n      exportName: 'ForwardRefButton',\n      props: {\n        text: {\n          type: { name: 'string' },\n          required: true,\n          description: 'Button text',\n          parent: { name: 'FRButtonProps' },\n        },\n        size: {\n          type: { name: 'enum', value: [{ value: '\"md\"' }, { value: '\"sm\"' }, { value: '\"lg\"' }] },\n          required: false,\n          parent: { name: 'FRButtonProps' },\n        },\n        key: {\n          type: { name: 'Key | null | undefined' },\n          required: false,\n          parent: { name: 'Attributes' },\n        },\n        ref: {\n          type: { name: 'LegacyRef<HTMLButtonElement> | undefined' },\n          required: false,\n          parent: { name: 'RefAttributes' },\n        },\n      },\n    });\n  });\n\n  it('memo component', async () => {\n    const entry = await extractFromStory(\n      {\n        'path1/MemoButton.tsx': dedent`\n          import React from 'react';\n          interface MemoButtonProps {\n            /** The label */\n            label: string;\n            color?: string;\n          }\n          const Inner = (props: MemoButtonProps) => <button>{props.label}</button>;\n          export const MemoButton = React.memo(Inner);\n        `,\n        'path1/MemoButton.stories.tsx': dedent`\n          import React from 'react';\n          import { MemoButton } from './MemoButton';\n          export default { component: MemoButton };\n          export const Default = () => <MemoButton label=\"Click\" color=\"blue\" />;\n        `,\n      },\n      'path1/MemoButton.stories.tsx'\n    );\n\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      displayName: 'MemoButton',\n      exportName: 'MemoButton',\n      props: {\n        label: {\n          type: { name: 'string' },\n          required: true,\n          description: 'The label',\n          parent: { name: 'MemoButtonProps' },\n        },\n        color: {\n          type: { name: 'string' },\n          required: false,\n          parent: { name: 'MemoButtonProps' },\n        },\n      },\n    });\n  });\n\n  it('compound component member (Accordion.Root)', async () => {\n    const entry = await extractFromStory(\n      {\n        'path1/Compound.tsx': dedent`\n          import React from 'react';\n          interface RootProps {\n            /** Whether multiple items can be open */\n            multiple?: boolean;\n          }\n          /**\n           * Compound root description\n           * @summary Compound root summary\n           */\n          const Root = ({ multiple = true }: RootProps) => <div data-multiple={multiple} />;\n          interface ItemProps {\n            value: string;\n            disabled?: boolean;\n          }\n          const Item = (props: ItemProps) => <div />;\n          export const Accordion = { Root, Item };\n        `,\n        'path1/Compound.stories.tsx': dedent`\n          import React from 'react';\n          import { Accordion } from './Compound';\n          export default {};\n          export const Default = () => (\n            <Accordion.Root multiple>\n              <Accordion.Item value=\"a\" />\n            </Accordion.Root>\n          );\n        `,\n      },\n      'path1/Compound.stories.tsx',\n      { componentName: 'Accordion.Root' }\n    );\n\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      displayName: 'Accordion.Root',\n      exportName: 'Accordion',\n      description: 'Compound root description',\n      jsDocTags: {\n        summary: ['Compound root summary'],\n      },\n      props: {\n        multiple: {\n          type: { name: 'boolean | undefined' },\n          required: false,\n          description: 'Whether multiple items can be open',\n          defaultValue: { value: 'true' },\n          parent: { name: 'RootProps' },\n        },\n      },\n    });\n  });\n\n  it('namespace import (Popover.Panel)', async () => {\n    const entry = await extractFromStory(\n      {\n        'path1/NamespaceCompound.tsx': dedent`\n          import React from 'react';\n          interface PanelProps {\n            /** Whether the panel is open */\n            open?: boolean;\n            label: string;\n          }\n          /**\n           * Panel description\n           * @summary Panel summary\n           */\n          export const Panel = ({ open = false, label }: PanelProps) => <div data-open={open}>{label}</div>;\n          interface TriggerProps {\n            onClick: () => void;\n          }\n          export const Trigger = (props: TriggerProps) => <button />;\n        `,\n        'path1/NamespaceCompound.stories.tsx': dedent`\n          import React from 'react';\n          import * as Popover from './NamespaceCompound';\n          export default {};\n          export const Default = () => <Popover.Panel open label=\"hello\" />;\n        `,\n      },\n      'path1/NamespaceCompound.stories.tsx',\n      { componentName: 'Popover.Panel' }\n    );\n\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      displayName: 'Popover.Panel',\n      exportName: 'Panel',\n      description: 'Panel description',\n      jsDocTags: {\n        summary: ['Panel summary'],\n      },\n      props: {\n        label: {\n          type: { name: 'string' },\n          required: true,\n          parent: { name: 'PanelProps' },\n        },\n        open: {\n          type: { name: 'boolean | undefined' },\n          required: false,\n          description: 'Whether the panel is open',\n          defaultValue: { value: 'false' },\n          parent: { name: 'PanelProps' },\n        },\n      },\n    });\n  });\n\n  it('default-export attached member (Button.Aligner)', async () => {\n    const entry = await extractFromStory(\n      {\n        'path1/AttachedMember.tsx': dedent`\n          import React from 'react';\n          interface ButtonProps {\n            variant?: 'solid' | 'outline';\n          }\n          const Button = (props: ButtonProps) => <button />;\n\n          interface AlignerProps {\n            /** Side to align */\n            side?: 'start' | 'end';\n          }\n\n          /**\n           * Aligner description\n           * @summary Aligner summary\n           */\n          const Aligner = ({ side = 'start' }: AlignerProps) => <div data-side={side} />;\n\n          const ButtonRoot = Button as typeof Button & {\n            Aligner: typeof Aligner;\n          };\n          ButtonRoot.Aligner = Aligner;\n\n          export default ButtonRoot;\n        `,\n        'path1/AttachedMember.stories.tsx': dedent`\n          import React from 'react';\n          import Button from './AttachedMember';\n          export default { component: Button };\n          export const Default = () => <Button.Aligner />;\n        `,\n      },\n      'path1/AttachedMember.stories.tsx',\n      { componentName: 'Button.Aligner' }\n    );\n\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      displayName: 'Button.Aligner',\n      exportName: 'default',\n      description: 'Aligner description',\n      jsDocTags: {\n        summary: ['Aligner summary'],\n      },\n      props: {\n        side: {\n          type: { name: 'enum', value: [{ value: '\"start\"' }, { value: '\"end\"' }] },\n          required: false,\n          description: 'Side to align',\n          defaultValue: { value: \"'start'\" },\n          parent: { name: 'AlignerProps' },\n        },\n      },\n    });\n  });\n\n  it('default export', async () => {\n    const entry = await extractFromStory(\n      {\n        'path1/DefaultExport.tsx': dedent`\n          import React from 'react';\n          interface HeaderProps {\n            /** The title text */\n            title: string;\n            subtitle?: string;\n          }\n          const Header = (props: HeaderProps) => <header>{props.title}</header>;\n          export default Header;\n        `,\n        'path1/DefaultExport.stories.tsx': dedent`\n          import React from 'react';\n          import Header from './DefaultExport';\n          export default { component: Header };\n          export const Default = () => <Header title=\"Welcome\" subtitle=\"Hi\" />;\n        `,\n      },\n      'path1/DefaultExport.stories.tsx'\n    );\n\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      displayName: 'Header',\n      exportName: 'default',\n      props: {\n        title: {\n          type: { name: 'string' },\n          required: true,\n          description: 'The title text',\n          parent: { name: 'HeaderProps' },\n        },\n        subtitle: {\n          type: { name: 'string' },\n          required: false,\n          parent: { name: 'HeaderProps' },\n        },\n      },\n    });\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/componentMeta/ComponentMetaProject.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { dedent } from 'ts-dedent';\n\nimport type { StoryRef } from '../getComponentImports.ts';\nimport { extractFromStory, withProject } from './componentMetaExtractor.test-helpers.ts';\n\ndescribe('compound component extraction', () => {\n  it('extracts props for Accordion.Root, not Item or Trigger', async () => {\n    const entry = await extractFromStory(\n      {\n        'accordion.tsx': dedent`\n          import React from 'react';\n\n          interface RootProps {\n            /** Allow multiple items open */\n            multiple?: boolean;\n            /** Default open items */\n            defaultValue?: string[];\n          }\n          const Root = (props: RootProps) => <div />;\n\n          interface ItemProps {\n            value: string;\n            disabled?: boolean;\n          }\n          const Item = (props: ItemProps) => <div />;\n\n          interface TriggerProps {\n            asChild?: boolean;\n          }\n          const Trigger = (props: TriggerProps) => <button />;\n\n          export const Accordion = { Root, Item, Trigger };\n        `,\n        'accordion.stories.tsx': dedent`\n          import React from 'react';\n          import { Accordion } from './accordion';\n          export default {};\n          export const Default = () => <Accordion.Root multiple><Accordion.Item value=\"a\"><Accordion.Trigger /></Accordion.Item></Accordion.Root>;\n        `,\n      },\n      'accordion.stories.tsx',\n      { componentName: 'Accordion.Root' }\n    );\n\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        multiple: { required: false, description: 'Allow multiple items open' },\n        defaultValue: expect.anything(),\n      },\n    });\n    // Should NOT have Item or Trigger props\n    expect(entry.component?.reactComponentMeta?.props?.value).toBeUndefined();\n    expect(entry.component?.reactComponentMeta?.props?.asChild).toBeUndefined();\n  });\n\n  it('uses Root description and jsDocTags, not wrapper Accordion', async () => {\n    const entry = await extractFromStory(\n      {\n        'accordion.tsx': dedent`\n          import React from 'react';\n\n          interface RootProps {\n            /** Root size */\n            size?: 'sm' | 'md';\n          }\n\n          /**\n           * Root-specific description\n           * @summary Root summary\n           */\n          const Root = ({ size = 'md' }: RootProps) => <div data-size={size} />;\n\n          interface ItemProps {\n            value: string;\n          }\n          const Item = (props: ItemProps) => <div />;\n\n          /**\n           * Wrapper description\n           * @summary Wrapper summary\n           */\n          export const Accordion = { Root, Item };\n        `,\n        'accordion.stories.tsx': dedent`\n          import React from 'react';\n          import { Accordion } from './accordion';\n          export default {};\n          export const Default = () => <Accordion.Root />;\n        `,\n      },\n      'accordion.stories.tsx',\n      { componentName: 'Accordion.Root' }\n    );\n\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      displayName: 'Accordion.Root',\n      description: 'Root-specific description',\n      jsDocTags: { summary: ['Root summary'] },\n      props: { size: { defaultValue: { value: \"'md'\" } } },\n    });\n    expect(entry.component?.importOverride).toBeUndefined();\n  });\n\n  it('extracts Aligner props when targeting Button.Aligner, Button props otherwise', async () => {\n    // Uses withProject directly because this test needs two extraction rounds on the same project.\n    await withProject(\n      {\n        'button.tsx': dedent`\n          import React from 'react';\n\n          interface ButtonProps {\n            /** Visual variant */\n            variant?: 'solid' | 'outline';\n            /** Color theme */\n            color?: 'neutral' | 'primary';\n            /** Disabled state */\n            disabled?: boolean;\n          }\n          const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n            (props, ref) => <button ref={ref} />\n          );\n\n          interface AlignerProps {\n            /** Side of the button to align */\n            side?: 'start' | 'end';\n            children?: React.ReactNode;\n          }\n          const Aligner = (props: AlignerProps) => <div />;\n\n          interface GroupProps {\n            /** Gap between buttons */\n            gap?: number;\n            children?: React.ReactNode;\n          }\n          const Group = (props: GroupProps) => <div />;\n\n          const ButtonRoot = Button as typeof Button & {\n            Aligner: typeof Aligner;\n            Group: typeof Group;\n          };\n          ButtonRoot.Aligner = Aligner;\n          ButtonRoot.Group = Group;\n\n          export default ButtonRoot;\n        `,\n        'button.stories.tsx': dedent`\n          import React from 'react';\n          import Button from './button';\n          export default { component: Button };\n          export const AlignerStory = () => <Button.Aligner side=\"start\"><Button /></Button.Aligner>;\n          export const ButtonStory = () => <Button variant=\"solid\" />;\n        `,\n      },\n      (project, filePaths) => {\n        // memberAccess='Aligner' → find <Button.Aligner />, get Aligner's props\n        const entries1: StoryRef[] = [\n          {\n            storyPath: filePaths['button.stories.tsx'],\n            component: {\n              componentName: 'Button',\n              importId: './button',\n              importName: 'default',\n              member: 'Aligner',\n              path: filePaths['button.tsx'],\n              isPackage: false,\n            },\n          },\n        ];\n        project.extractPropsFromStories(entries1);\n\n        expect(entries1[0]?.component?.reactComponentMeta).toMatchObject({\n          props: { side: expect.anything() },\n        });\n        expect(entries1[0]?.component?.reactComponentMeta?.props?.variant).toBeUndefined();\n\n        // Without memberAccess → find <Button />, get Button's own props\n        const entries2: StoryRef[] = [\n          {\n            storyPath: filePaths['button.stories.tsx'],\n            component: {\n              componentName: 'Button',\n              importId: './button',\n              importName: 'default',\n              path: filePaths['button.tsx'],\n              isPackage: false,\n            },\n          },\n        ];\n        project.extractPropsFromStories(entries2);\n\n        expect(entries2[0]?.component?.reactComponentMeta).toMatchObject({\n          props: { variant: expect.anything(), color: expect.anything() },\n        });\n        expect(entries2[0]?.component?.reactComponentMeta?.props?.side).toBeUndefined();\n      }\n    );\n  });\n\n  it('uses Aligner metadata for default-exported Button.Aligner', async () => {\n    const entry = await extractFromStory(\n      {\n        'button.tsx': dedent`\n          import React from 'react';\n\n          interface ButtonProps {\n            variant?: 'solid' | 'outline';\n          }\n          const Button = (props: ButtonProps) => <button />;\n\n          interface AlignerProps {\n            /** Aligner direction */\n            side?: 'start' | 'end';\n          }\n\n          /**\n           * Aligner-specific description\n           * @summary Aligner summary\n           */\n          const Aligner = ({ side = 'start' }: AlignerProps) => <div data-side={side} />;\n\n          /**\n           * Wrapper description\n           * @summary Wrapper summary\n           */\n          const ButtonRoot = Button as typeof Button & {\n            Aligner: typeof Aligner;\n          };\n\n          ButtonRoot.Aligner = Aligner;\n\n          export default ButtonRoot;\n        `,\n        'button.stories.tsx': dedent`\n          import React from 'react';\n          import Button from './button';\n          export default { component: Button };\n          export const AlignerStory = () => <Button.Aligner />;\n        `,\n      },\n      'button.stories.tsx',\n      { componentName: 'Button.Aligner' }\n    );\n\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      displayName: 'Button.Aligner',\n      description: 'Aligner-specific description',\n      jsDocTags: { summary: ['Aligner summary'] },\n      props: { side: { defaultValue: { value: \"'start'\" } } },\n    });\n    expect(entry.component?.importOverride).toBeUndefined();\n  });\n\n  it('inherits @import from wrapper for compound members', async () => {\n    const entry = await extractFromStory(\n      {\n        'accordion.tsx': dedent`\n          import React from 'react';\n\n          interface RootProps {\n            /** Root size */\n            size?: 'sm' | 'md';\n          }\n\n          /**\n           * Root-specific description\n           * @summary Root summary\n           */\n          const Root = ({ size = 'md' }: RootProps) => <div data-size={size} />;\n\n          interface ItemProps {\n            value: string;\n          }\n          const Item = (props: ItemProps) => <div />;\n\n          /**\n           * Wrapper description\n           * @import import { Accordion } from '@design-system/components/accordion';\n           */\n          export const Accordion = { Root, Item };\n        `,\n        'accordion.stories.tsx': dedent`\n          import React from 'react';\n          import { Accordion } from './accordion';\n          export default {};\n          export const Default = () => <Accordion.Root />;\n        `,\n      },\n      'accordion.stories.tsx',\n      { componentName: 'Accordion.Root' }\n    );\n\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      description: 'Root-specific description',\n      props: { size: { defaultValue: { value: \"'md'\" } } },\n    });\n    expect(entry.component?.importOverride).toBe(\n      \"import { Accordion } from '@design-system/components/accordion';\"\n    );\n  });\n\n  it('extracts Dialog.Root and Button in the same batch', async () => {\n    // Uses withProject directly because this test extracts two story files in one batch.\n    await withProject(\n      {\n        'dialog.tsx': dedent`\n          import React from 'react';\n\n          interface RootProps {\n            open?: boolean;\n            onOpenChange?: (open: boolean) => void;\n          }\n          const Root = (props: RootProps) => <div />;\n\n          interface ContentProps {\n            /** Trap focus inside dialog */\n            trapFocus?: boolean;\n          }\n          const Content = (props: ContentProps) => <div />;\n\n          export const Dialog = { Root, Content };\n        `,\n        'button.tsx': dedent`\n          import React from 'react';\n          export interface ButtonProps {\n            label: string;\n            variant?: 'primary' | 'secondary';\n          }\n          export const Button = (props: ButtonProps) => <button />;\n        `,\n        'dialog.stories.tsx': dedent`\n          import React from 'react';\n          import { Dialog } from './dialog';\n          export default {};\n          export const Default = () => <Dialog.Root open><Dialog.Content trapFocus /></Dialog.Root>;\n        `,\n        'button.stories.tsx': dedent`\n          import React from 'react';\n          import { Button } from './button';\n          export default { component: Button };\n          export const Default = () => <Button label=\"Click\" />;\n        `,\n      },\n      (project, filePaths) => {\n        const entries: StoryRef[] = [\n          {\n            storyPath: filePaths['dialog.stories.tsx'],\n            component: {\n              componentName: 'Dialog',\n              importId: './dialog',\n              importName: 'Dialog',\n              member: 'Root',\n              path: filePaths['dialog.tsx'],\n              isPackage: false,\n            },\n          },\n          {\n            storyPath: filePaths['button.stories.tsx'],\n            component: {\n              componentName: 'Button',\n              importId: './button',\n              importName: 'Button',\n              path: filePaths['button.tsx'],\n              isPackage: false,\n            },\n          },\n        ];\n        project.extractPropsFromStories(entries);\n\n        expect(entries[0]?.component?.reactComponentMeta).toMatchObject({\n          props: { open: expect.anything(), onOpenChange: expect.anything() },\n        });\n        expect(entries[1]?.component?.reactComponentMeta).toMatchObject({\n          props: { label: expect.anything(), variant: expect.anything() },\n        });\n      }\n    );\n  });\n\n  it('extracts description, @import, and @summary from component JSDoc', async () => {\n    const entry = await extractFromStory(\n      {\n        'button.tsx': dedent`\n          import React from 'react';\n\n          export interface ButtonProps {\n            label: string;\n          }\n\n          /**\n           * Primary UI component for user interaction\n           * @import import { Button } from '@design-system/components/override';\n           * @summary Fast summary\n           */\n          export const Button = ({ label }: ButtonProps) => <button>{label}</button>;\n        `,\n        'button.stories.tsx': dedent`\n          import React from 'react';\n          import { Button } from './button';\n          export default { component: Button };\n          export const Default = () => <Button label=\"Click\" />;\n        `,\n      },\n      'button.stories.tsx'\n    );\n\n    expect(entry.component).toMatchObject({\n      reactComponentMeta: {\n        description: 'Primary UI component for user interaction',\n      },\n      componentJsDocTags: {\n        import: [\"import { Button } from '@design-system/components/override';\"],\n        summary: ['Fast summary'],\n      },\n      importOverride: \"import { Button } from '@design-system/components/override';\",\n    });\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/componentMeta/ComponentMetaProject.ts",
    "content": "/**\n * ComponentMetaProject — one TS LanguageService per tsconfig.\n *\n * Mirrors Volar-style checker/project-host patterns:\n *\n * - https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/kit/lib/createChecker.ts#L83-L461\n * - https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/language-server/lib/project/typescriptProjectLs.ts#L44-L233\n * - https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/typescript/lib/protocol/createProject.ts#L30-L120\n * - CreateLanguage + createLanguageServiceHost from @volar/typescript\n * - FsFileSnapshots with mtime-based caching (shared across projects)\n * - TypeScriptProjectHost contract (projectVersion, shouldCheckRootFiles, checkRootFilesUpdate)\n * - Selective projectVersion bump on file events (Kit checker pattern)\n * - EnsureFiles for dynamic file inclusion (LS pattern)\n *\n * Props extraction works probe-free:\n *\n * - Path 1 (primary): Find JSX in story files → getResolvedSignature() → props type\n * - Path 2 (fallback): Direct type inspection for args-only stories (component-meta approach)\n * - SerializeComponentDoc() serializes the resolved props type into ComponentDoc format\n */\nimport { FileMap, createLanguage } from '@volar/language-core';\nimport {\n  type TypeScriptProjectHost,\n  createLanguageServiceHost,\n  resolveFileLanguageId,\n} from '@volar/typescript';\nimport * as path from 'path';\nimport type ts from 'typescript';\n\nimport type { StoryRef } from '../getComponentImports.ts';\nimport type { ComponentRef, ResolvedComponentTarget } from '../types.ts';\nimport {\n  resolvePropsFromComponentType,\n  resolvePropsFromStoryFile,\n  serializeComponentDoc,\n} from './componentMetaExtractor.ts';\n\nexport class ComponentMetaProject {\n  private ls: ts.LanguageService;\n  private projectVersion = 0;\n  private shouldCheckRootFiles = false;\n  private warmupTimer?: ReturnType<typeof setTimeout>;\n  /** Entries to extract — set by the generator, replayed during warmup for targeted type resolution. */\n  private entries: StoryRef[] = [];\n\n  constructor(\n    private typescript: typeof ts,\n    private commandLine: ts.ParsedCommandLine,\n    public readonly configFileName: string | undefined,\n    /**\n     * Shared snapshot cache owned by ComponentMetaManager.\n     *\n     * Adapted from:\n     * https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/kit/lib/createChecker.ts#L83\n     */\n    private fsFileSnapshots: Map<\n      string,\n      [number | undefined, ts.IScriptSnapshot | undefined]\n    > = new Map(),\n    private getCommandLineFn?: () => ts.ParsedCommandLine\n  ) {\n    // Adapted from:\n    // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/kit/lib/createChecker.ts#L110-L141\n    const language = createLanguage<string>(\n      [{ getLanguageId: (fileName: string) => resolveFileLanguageId(fileName) }],\n      new FileMap(typescript.sys.useCaseSensitiveFileNames),\n      (fileName, includeFsFiles) => {\n        if (!includeFsFiles) {\n          return;\n        }\n        const cache = fsFileSnapshots.get(fileName);\n        const modifiedTime = typescript.sys.getModifiedTime?.(fileName)?.valueOf();\n        if (!cache || cache[0] !== modifiedTime) {\n          if (typescript.sys.fileExists(fileName)) {\n            const text = typescript.sys.readFile(fileName);\n            const snapshot =\n              text !== undefined ? typescript.ScriptSnapshot.fromString(text) : undefined;\n            fsFileSnapshots.set(fileName, [modifiedTime, snapshot]);\n          } else {\n            fsFileSnapshots.set(fileName, [modifiedTime, undefined]);\n          }\n        }\n        const snapshot = fsFileSnapshots.get(fileName)?.[1];\n        if (snapshot) {\n          language.scripts.set(fileName, snapshot);\n        } else {\n          language.scripts.delete(fileName);\n        }\n      }\n    );\n\n    // Adapted from:\n    // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/kit/lib/createChecker.ts#L359-L383\n    const projectHost: TypeScriptProjectHost = {\n      getCurrentDirectory: () =>\n        configFileName\n          ? path.dirname(configFileName)\n          : (commandLine.options.rootDir ?? process.cwd()),\n      getCompilationSettings: () => {\n        return this.commandLine.options;\n      },\n      getProjectReferences: () => {\n        return this.commandLine.projectReferences;\n      },\n      getProjectVersion: () => {\n        this.checkRootFilesUpdate();\n        return this.projectVersion.toString();\n      },\n      getScriptFileNames: () => {\n        this.checkRootFilesUpdate();\n        return this.commandLine.fileNames;\n      },\n    };\n\n    // Adapted from:\n    // https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/typescript/lib/protocol/createProject.ts#L30-L120\n    const { languageServiceHost } = createLanguageServiceHost(\n      typescript,\n      typescript.sys,\n      language,\n      (s) => s, // asScriptId — identity for React (no URI mapping needed)\n      projectHost\n    );\n\n    this.ls = typescript.createLanguageService(languageServiceHost);\n  }\n\n  getCommandLine(): ts.ParsedCommandLine {\n    return this.commandLine;\n  }\n\n  dispose() {\n    clearTimeout(this.warmupTimer);\n    this.ls.dispose();\n  }\n\n  // ---------------------------------------------------------------------------\n  // Project management\n  // ---------------------------------------------------------------------------\n\n  /**\n   * Batch-add multiple files to the project in one go. Only bumps projectVersion once, avoiding\n   * repeated program rebuilds.\n   */\n  ensureFiles(fileNames: string[]): void {\n    let added = false;\n    for (const fileName of fileNames) {\n      if (!this.commandLine.fileNames.includes(fileName)) {\n        this.commandLine.fileNames.push(fileName);\n        added = true;\n      }\n    }\n    if (added) {\n      this.projectVersion++;\n    }\n  }\n\n  /**\n   * Adapted from:\n   * https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/kit/lib/createChecker.ts#L436-L447\n   */\n  private checkRootFilesUpdate(): void {\n    if (!this.shouldCheckRootFiles) {\n      return;\n    }\n    this.shouldCheckRootFiles = false;\n\n    if (!this.getCommandLineFn) {\n      return;\n    }\n    const newCommandLine = this.getCommandLineFn();\n    if (!arrayItemsEqual(newCommandLine.fileNames, this.commandLine.fileNames)) {\n      this.commandLine.fileNames = newCommandLine.fileNames;\n      this.projectVersion++;\n    }\n  }\n\n  hasSourceFile(fileName: string): boolean {\n    return !!this.ls.getProgram()?.getSourceFile(fileName);\n  }\n\n  /**\n   * Get all non-node_modules source file paths from the TS program. Used by ComponentMetaManager to\n   * watch directories for file changes.\n   */\n  getSourceFilePaths(): string[] {\n    const program = this.ls.getProgram();\n    if (!program) {\n      return [];\n    }\n    return program\n      .getSourceFiles()\n      .map((sf) => sf.fileName.replace(/\\\\/g, '/'))\n      .filter((f) => !f.includes('node_modules'));\n  }\n\n  /**\n   * Adapted from:\n   * https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/kit/lib/createChecker.ts#L409-L432\n   *\n   * Created events only set shouldCheckRootFiles (version bump happens in checkRootFilesUpdate if\n   * the file list actually changed). Deleted/created break early since they trigger a full config\n   * reparse — processing remaining changes is unnecessary.\n   */\n  onFilesChanged(\n    changes: Array<{ filePath: string; type: 'changed' | 'created' | 'deleted' }>\n  ): void {\n    // Eagerly invalidate snapshot cache for ALL changes before processing.\n    // Deleting from fsFileSnapshots ensures the sync callback re-reads the file.\n    for (const { filePath } of changes) {\n      this.fsFileSnapshots.delete(filePath);\n    }\n\n    const oldVersion = this.projectVersion;\n    const program = this.ls.getProgram();\n    for (const { filePath, type } of changes) {\n      if (type === 'changed') {\n        if (program?.getSourceFile(filePath)) {\n          this.projectVersion++;\n        }\n      } else if (type === 'deleted') {\n        if (program?.getSourceFile(filePath)) {\n          this.projectVersion++;\n        }\n        this.shouldCheckRootFiles = true;\n        break;\n      } else if (type === 'created') {\n        this.shouldCheckRootFiles = true;\n        break;\n      }\n    }\n\n    // Targeted warmup: re-extract in the background so the next request is instant.\n    // Only resolves the specific types we need (story JSX → getResolvedSignature),\n    // not the entire program. TypeScript caches resolved types on AST nodes —\n    // the real extraction then hits cached results.\n    if (this.projectVersion !== oldVersion && this.entries.length > 0) {\n      clearTimeout(this.warmupTimer);\n      this.warmupTimer = setTimeout(() => {\n        try {\n          this.extractPropsFromStories(this.entries);\n        } catch {\n          // Warmup failure is non-fatal — extraction will still work on demand.\n        }\n      }, 100);\n      this.warmupTimer?.unref?.();\n    }\n  }\n\n  // ---------------------------------------------------------------------------\n  // Primary extraction method — probe-free\n  // ---------------------------------------------------------------------------\n\n  extractPropsFromStories(entries: StoryRef[]): void {\n    this.entries = entries;\n\n    const allFiles = entries.flatMap((entry) =>\n      entry.component?.path ? [entry.storyPath, entry.component.path] : [entry.storyPath]\n    );\n    this.ensureFiles(allFiles);\n    this.ensureFresh(allFiles);\n\n    const program = this.ls.getProgram();\n    if (!program) {\n      return;\n    }\n    const checker = program.getTypeChecker();\n    const serializationContextByComponentPath = new Map<\n      string,\n      { sourceFile: ts.SourceFile; defaultsSourcePath?: string }\n    >();\n\n    for (const entry of entries) {\n      try {\n        const storySourceFile = program.getSourceFile(entry.storyPath);\n        const entryComponent = entry.component;\n        const componentPath = entryComponent?.path;\n        const exportName = entryComponent?.importName;\n        if (!storySourceFile || !componentPath || !exportName || !entryComponent) {\n          continue;\n        }\n\n        const importId = entryComponent.importId;\n        const isPackageImport = importId && !importId.startsWith('.');\n        let componentSourceFile: ts.SourceFile | undefined;\n\n        if (isPackageImport) {\n          const resolved = this.typescript.resolveModuleName(\n            importId!,\n            entry.storyPath,\n            this.commandLine.options,\n            this.typescript.sys\n          );\n          componentSourceFile = resolved.resolvedModule\n            ? program.getSourceFile(resolved.resolvedModule.resolvedFileName)\n            : program.getSourceFile(componentPath);\n        } else {\n          componentSourceFile = program.getSourceFile(componentPath);\n        }\n\n        if (!componentSourceFile) {\n          continue;\n        }\n\n        // Path 1: Find JSX in story file\n        let resolvedComponent: ResolvedComponentTarget | undefined;\n        if (importId) {\n          resolvedComponent = resolvePropsFromStoryFile(\n            this.typescript,\n            checker,\n            storySourceFile,\n            entryComponent\n          );\n        }\n\n        // Path 2: Fallback — resolve from meta.component in the story file.\n        // Only fires when the user explicitly set `component:` in the meta object.\n        if (!resolvedComponent) {\n          resolvedComponent = this.resolveFromMetaComponent(\n            checker,\n            storySourceFile,\n            entryComponent\n          );\n        }\n\n        if (!resolvedComponent) {\n          continue;\n        }\n\n        let serializationContext = serializationContextByComponentPath.get(componentPath);\n        if (serializationContext === undefined) {\n          const resolvedFileName = componentSourceFile.fileName;\n          serializationContext = {\n            sourceFile: componentSourceFile,\n            defaultsSourcePath:\n              resolvedFileName.endsWith('.d.ts') ||\n              resolvedFileName.endsWith('.d.mts') ||\n              resolvedFileName.endsWith('.d.cts')\n                ? componentPath\n                : undefined,\n          };\n          serializationContextByComponentPath.set(componentPath, serializationContext);\n        }\n\n        const doc = serializeComponentDoc(this.typescript, checker, {\n          sourceFile: serializationContext.sourceFile,\n          resolvedComponent,\n          defaultsSourcePath: serializationContext.defaultsSourcePath,\n        });\n\n        if (doc) {\n          entryComponent.reactComponentMeta = doc;\n          entryComponent.componentJsDocTags = doc.jsDocTags;\n          entryComponent.importOverride = entryComponent.componentJsDocTags?.import?.[0]?.trim();\n        }\n      } catch {\n        // One bad component should not kill the entire batch.\n        continue;\n      }\n    }\n  }\n\n  /**\n   * Check mtime for specific files and bump projectVersion if any changed.\n   *\n   * This bypasses the sync() gate in createLanguageServiceHost — sync() only runs when\n   * projectVersion changes, so mtime-based cache alone can't detect stale files. We do a targeted\n   * mtime check for the files we're about to extract from, ensuring freshness even when the\n   * fs.watch event hasn't arrived yet (race with HMR) or was missed entirely.\n   */\n  private ensureFresh(fileNames: string[]): void {\n    let stale = false;\n    for (const fileName of fileNames) {\n      const cache = this.fsFileSnapshots.get(fileName);\n      if (!cache) {\n        continue;\n      }\n      const currentMtime = this.typescript.sys.getModifiedTime?.(fileName)?.valueOf();\n      if (cache[0] !== currentMtime) {\n        this.fsFileSnapshots.delete(fileName);\n        stale = true;\n      }\n    }\n    if (stale) {\n      this.projectVersion++;\n    }\n  }\n\n  // ---------------------------------------------------------------------------\n  // Internal helpers\n  // ---------------------------------------------------------------------------\n\n  /**\n   * Path 2 fallback: resolve the component type from the story file's `meta.component` property.\n   * Only works when the user explicitly set `component:` in the meta — no node means no\n   * extraction.\n   */\n  private resolveFromMetaComponent(\n    checker: ts.TypeChecker,\n    storySourceFile: ts.SourceFile,\n    componentRef: ComponentRef\n  ): ResolvedComponentTarget | undefined {\n    const { member: memberAccess } = componentRef;\n    const moduleSymbol = checker.getSymbolAtLocation(storySourceFile);\n    if (!moduleSymbol) {\n      return undefined;\n    }\n\n    const defaultExport = checker\n      .getExportsOfModule(moduleSymbol)\n      .find((e) => e.getName() === 'default');\n    if (!defaultExport) {\n      return undefined;\n    }\n\n    const metaType = checker.getTypeOfSymbol(defaultExport);\n    const componentProp = metaType.getProperty('component');\n    if (!componentProp) {\n      return undefined;\n    }\n\n    let componentType = checker.getTypeOfSymbol(componentProp);\n    let selectedSymbol =\n      componentProp.valueDeclaration &&\n      this.typescript.isPropertyAssignment(componentProp.valueDeclaration)\n        ? checker.getSymbolAtLocation(componentProp.valueDeclaration.initializer)\n        : componentType.getSymbol?.();\n\n    if (memberAccess) {\n      const prop = componentType.getProperty(memberAccess);\n      if (prop) {\n        componentType = checker.getTypeOfSymbol(prop);\n        selectedSymbol = prop;\n      } else {\n        return undefined;\n      }\n    }\n\n    const propsType = resolvePropsFromComponentType(this.typescript, checker, componentType);\n    if (!propsType || !selectedSymbol) {\n      return undefined;\n    }\n\n    return {\n      componentRef,\n      propsType,\n      symbol: selectedSymbol,\n    };\n  }\n}\n\n// Adapted from:\n// https://github.com/volarjs/volar.js/blob/882cd56d46a13d272f34e451f495d3d62251969a/packages/kit/lib/createChecker.ts#L450-L461\nfunction arrayItemsEqual(a: string[], b: string[]) {\n  if (a.length !== b.length) {\n    return false;\n  }\n  const set = new Set(a);\n  for (const file of b) {\n    if (!set.has(file)) {\n      return false;\n    }\n  }\n  return true;\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/componentMeta/componentMetaExtractor.defaultValue.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { dedent } from 'ts-dedent';\n\nimport { extract } from './componentMetaExtractor.test-helpers.ts';\n\ndescribe('default value extraction', () => {\n  it('extracts destructuring defaults from arrow function', async () => {\n    const entry = await extract(\n      'Button',\n      dedent`\n        import React from 'react';\n        interface Props { size?: string; color?: string; label: string }\n        export const Button = ({ size = 'md', color = 'blue', label }: Props) => <button />;\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        size: { defaultValue: { value: \"'md'\" } },\n        color: { defaultValue: { value: \"'blue'\" } },\n        label: { defaultValue: null },\n      },\n    });\n  });\n\n  it('extracts defaults from forwardRef', async () => {\n    const entry = await extract(\n      'Button',\n      dedent`\n        import React from 'react';\n        interface Props { variant?: string; label: string }\n        export const Button = React.forwardRef<HTMLButtonElement, Props>(\n          ({ variant = 'primary', label }, ref) => <button ref={ref} />\n        );\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        variant: { defaultValue: { value: \"'primary'\" } },\n        label: { defaultValue: null },\n      },\n    });\n  });\n\n  it('extracts JSDoc @default tags', async () => {\n    const entry = await extract(\n      'Button',\n      dedent`\n        import React from 'react';\n        interface Props {\n          /** @default 'md' */\n          size?: string;\n          label: string;\n        }\n        export const Button = (props: Props) => <button />;\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        size: { defaultValue: { value: \"'md'\" } },\n        label: { defaultValue: null },\n      },\n    });\n  });\n\n  it('extracts defaults from body-level destructuring in forwardRef', async () => {\n    const entry = await extract(\n      'Alert',\n      dedent`\n        import React from 'react';\n        interface Props { color?: string; rounded?: boolean; label: string }\n        export const Alert = React.forwardRef<HTMLDivElement, Props>((props, ref) => {\n          const { color = 'info', rounded = true, label } = props;\n          return <div ref={ref} />;\n        });\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        color: { defaultValue: { value: \"'info'\" } },\n        rounded: { defaultValue: { value: 'true' } },\n        label: { defaultValue: null },\n      },\n    });\n  });\n\n  it('extracts defaults from helper calls that receive props directly', async () => {\n    const entry = await extract(\n      'Alert',\n      dedent`\n        import React from 'react';\n        interface Props { color?: string; rounded?: boolean; label: string }\n        const resolveProps = (props: Props) => props;\n        export const Alert = React.forwardRef<HTMLDivElement, Props>((props, ref) => {\n          const { color = 'info', rounded = true, label } = resolveProps(props);\n          return <div ref={ref} />;\n        });\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        color: { defaultValue: { value: \"'info'\" } },\n        rounded: { defaultValue: { value: 'true' } },\n        label: { defaultValue: null },\n      },\n    });\n  });\n\n  it('ignores body-level destructuring from unrelated local objects', async () => {\n    const entry = await extract(\n      'Alert',\n      dedent`\n        import React from 'react';\n        interface Props { color?: string; label: string }\n        const theme = { color: 'danger' };\n        export const Alert = (props: Props) => {\n          const { color = 'danger' } = theme;\n          return <div data-color={color}>{props.label}</div>;\n        };\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        color: { defaultValue: null },\n        label: { defaultValue: null },\n      },\n    });\n  });\n\n  it('resolves identifier references to literal values', async () => {\n    const entry = await extract(\n      'Button',\n      dedent`\n        import React from 'react';\n        const DEFAULT_SIZE = 'md';\n        const DEFAULT_COUNT = 42;\n        interface Props { size?: string; count?: number; label: string }\n        export const Button = ({ size = DEFAULT_SIZE, count = DEFAULT_COUNT, label }: Props) => <button />;\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        size: { defaultValue: { value: \"'md'\" } },\n        count: { defaultValue: { value: '42' } },\n        label: { defaultValue: null },\n      },\n    });\n  });\n\n  it('extracts Component.defaultProps expression pattern', async () => {\n    const entry = await extract(\n      'Button',\n      dedent`\n        import React from 'react';\n        interface Props { size?: string; color?: string; label: string }\n        export const Button = (props: Props) => <button />;\n        Button.defaultProps = { size: 'md', color: 'blue' };\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        size: { defaultValue: { value: \"'md'\" } },\n        color: { defaultValue: { value: \"'blue'\" } },\n        label: { defaultValue: null },\n      },\n    });\n  });\n\n  it('extracts static defaultProps from class components', async () => {\n    const entry = await extract(\n      'Button',\n      dedent`\n        import React from 'react';\n        interface Props { size?: string; label: string }\n        export class Button extends React.Component<Props> {\n          static defaultProps = { size: 'md' };\n          render() { return <button />; }\n        }\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        size: { defaultValue: { value: \"'md'\" } },\n        label: { defaultValue: null },\n      },\n    });\n  });\n\n  it('extracts @defaultValue tag (alias for @default)', async () => {\n    const entry = await extract(\n      'Button',\n      dedent`\n        import React from 'react';\n        interface Props {\n          /** @defaultValue 'primary' */\n          variant?: string;\n          label: string;\n        }\n        export const Button = (props: Props) => <button />;\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        variant: { defaultValue: { value: \"'primary'\" } },\n        label: { defaultValue: null },\n      },\n    });\n  });\n\n  it('extracts negative number defaults', async () => {\n    const entry = await extract(\n      'Slider',\n      dedent`\n        import React from 'react';\n        interface Props { min?: number; offset?: number }\n        export const Slider = ({ min = -100, offset = -1 }: Props) => <input />;\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        min: { defaultValue: { value: '-100' } },\n        offset: { defaultValue: { value: '-1' } },\n      },\n    });\n  });\n\n  it('extracts null defaults', async () => {\n    const entry = await extract(\n      'Select',\n      dedent`\n        import React from 'react';\n        interface Props { value?: string | null; label: string }\n        export const Select = ({ value = null, label }: Props) => <select />;\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        value: { defaultValue: { value: 'null' } },\n        label: { defaultValue: null },\n      },\n    });\n  });\n\n  it('extracts enum member as default value', async () => {\n    const entry = await extract(\n      'Badge',\n      dedent`\n        import React from 'react';\n        enum Status { Active = 'active', Inactive = 'inactive' }\n        interface Props { status?: Status }\n        export const Badge = ({ status = Status.Active }: Props) => <span />;\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        status: { defaultValue: { value: \"'active'\" } },\n      },\n    });\n  });\n\n  it('extracts shorthand property in defaultProps', async () => {\n    const entry = await extract(\n      'Button',\n      dedent`\n        import React from 'react';\n        const size = 'md';\n        interface Props { size?: string; label: string }\n        export const Button = (props: Props) => <button />;\n        Button.defaultProps = { size };\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        size: { defaultValue: { value: \"'md'\" } },\n        label: { defaultValue: null },\n      },\n    });\n  });\n\n  it('extracts body-level destructuring through ternary', async () => {\n    const entry = await extract(\n      'Alert',\n      dedent`\n        import React from 'react';\n        interface Props { color?: string; label: string }\n        export const Alert = (props: Props) => {\n          const isValid = true;\n          const { color = 'info', label } = isValid ? props : props;\n          return <div />;\n        };\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        color: { defaultValue: { value: \"'info'\" } },\n        label: { defaultValue: null },\n      },\n    });\n  });\n\n  it('extracts body-level destructuring through nullish coalescing', async () => {\n    const entry = await extract(\n      'Alert',\n      dedent`\n        import React from 'react';\n        interface Props { color?: string; label: string }\n        const fallback: Props = { color: 'red', label: '' };\n        export const Alert = (props: Props) => {\n          const { color = 'info', label } = props ?? fallback;\n          return <div />;\n        };\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        color: { defaultValue: { value: \"'info'\" } },\n        label: { defaultValue: null },\n      },\n    });\n  });\n\n  it('extracts body-level destructuring through nullish coalescing with empty object fallback', async () => {\n    const entry = await extract(\n      'Alert',\n      dedent`\n        import React from 'react';\n        interface Props { color?: string; label?: string }\n        export const Alert = (props: Props) => {\n          const { color = 'info', label } = props ?? {};\n          return <div />;\n        };\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        color: { defaultValue: { value: \"'info'\" } },\n        label: { defaultValue: null },\n      },\n    });\n  });\n\n  // Default precedence is intentional: destructuring > defaultProps > JSDoc.\n  it('prefers destructuring defaults over JSDoc @default', async () => {\n    const entry = await extract(\n      'Button',\n      dedent`\n        import React from 'react';\n        interface Props {\n          /** @default 'lg' */\n          size?: string;\n        }\n        export const Button = ({ size = 'md' }: Props) => <button />;\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        size: { defaultValue: { value: \"'md'\" } },\n      },\n    });\n  });\n\n  it('prefers destructuring defaults over defaultProps', async () => {\n    const entry = await extract(\n      'Button',\n      dedent`\n        import React from 'react';\n        interface Props { size?: string }\n        export const Button = ({ size = 'md' }: Props) => <button />;\n        Button.defaultProps = { size: 'lg' };\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        size: { defaultValue: { value: \"'md'\" } },\n      },\n    });\n  });\n\n  it('extracts defaults from overloaded function component', async () => {\n    const entry = await extract(\n      'Button',\n      dedent`\n        import React from 'react';\n        interface Props { size?: string; label: string }\n        export function Button(props: Props): React.ReactElement;\n        export function Button({ size = 'md', label }: Props) {\n          return <button />;\n        }\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        size: { defaultValue: { value: \"'md'\" } },\n        label: { defaultValue: null },\n      },\n    });\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/componentMeta/componentMetaExtractor.detection.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { dedent } from 'ts-dedent';\n\nimport { extract, extractFromStory } from './componentMetaExtractor.test-helpers.ts';\n\ndescribe('component detection', () => {\n  describe('function components', () => {\n    it('detects arrow function component', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          interface Props { label: string }\n          export const Button = (props: Props) => <button>{props.label}</button>;\n        `\n      );\n      expect(entry.component?.reactComponentMeta).toMatchObject({ displayName: 'Button' });\n    });\n\n    it('detects function declaration component', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          export function Button(props: { label: string }) { return <button /> }\n        `\n      );\n      expect(entry.component?.reactComponentMeta).toMatchObject({ displayName: 'Button' });\n    });\n\n    it('detects component returning null', async () => {\n      const entry = await extract(\n        'Empty',\n        dedent`\n          import React from 'react';\n          export const Empty = (props: { show: boolean }) => props.show ? <div /> : null;\n        `\n      );\n      expect(entry.component?.reactComponentMeta).toMatchObject({ displayName: 'Empty' });\n    });\n\n    it('detects component with no props', async () => {\n      const entry = await extract(\n        'Logo',\n        dedent`\n          import React from 'react';\n          export const Logo = () => <svg />;\n        `\n      );\n      expect(entry.component?.reactComponentMeta).toMatchObject({ displayName: 'Logo' });\n    });\n\n    it('detects function component with overloads', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          interface Props { label: string; size?: string }\n          export function Button(props: Props): React.ReactElement;\n          export function Button({ label, size = 'md' }: Props) {\n            return <button />;\n          }\n        `\n      );\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        displayName: 'Button',\n        props: { label: { required: true }, size: { required: false } },\n      });\n    });\n  });\n\n  describe('class components', () => {\n    it('detects class extending React.Component', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          export class Button extends React.Component<{ label: string }> {\n            render() { return <button /> }\n          }\n        `\n      );\n      expect(entry.component?.reactComponentMeta).toMatchObject({ displayName: 'Button' });\n    });\n\n    it('detects class extending React.PureComponent', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          export class Button extends React.PureComponent<{ label: string }> {\n            render() { return <button /> }\n          }\n        `\n      );\n      expect(entry.component?.reactComponentMeta).toMatchObject({ displayName: 'Button' });\n    });\n  });\n\n  describe('wrapped components', () => {\n    it('detects React.memo', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          const Inner = (props: { label: string }) => <button />;\n          export const Button = React.memo(Inner);\n        `\n      );\n      expect(entry.component?.reactComponentMeta).toMatchObject({ displayName: 'Button' });\n    });\n\n    it('detects React.forwardRef', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          export const Button = React.forwardRef<HTMLButtonElement, { label: string }>((props, ref) => (\n            <button ref={ref} />\n          ));\n        `\n      );\n      expect(entry.component?.reactComponentMeta).toMatchObject({ displayName: 'Button' });\n    });\n\n    it('detects React.memo(React.forwardRef(...))', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          export const Button = React.memo(\n            React.forwardRef<HTMLButtonElement, { label: string }>((props, ref) => <button ref={ref} />)\n          );\n        `\n      );\n      expect(entry.component?.reactComponentMeta).toMatchObject({ displayName: 'Button' });\n    });\n\n    it('detects React.lazy', async () => {\n      const entry = await extractFromStory(\n        {\n          'detect/lazy/Target.tsx': dedent`\n            import React from 'react';\n            export default (props: {}) => <button />;\n          `,\n          'detect/lazy/Lazy.tsx': dedent`\n            import React from 'react';\n            export const LazyButton = React.lazy(() => import('./Target'));\n          `,\n          'detect/lazy/Lazy.stories.tsx': dedent`\n            import { LazyButton } from './Lazy';\n            export default { component: LazyButton };\n          `,\n        },\n        'detect/lazy/Lazy.stories.tsx'\n      );\n      expect(entry.component?.reactComponentMeta).toBeDefined();\n    });\n\n    it('detects satisfies expression', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          interface Props { label: string }\n          export const Button = ((props: Props) => <button />) satisfies React.FC<Props>;\n        `\n      );\n      expect(entry.component?.reactComponentMeta).toMatchObject({ displayName: 'Button' });\n    });\n  });\n\n  describe('default exports', () => {\n    it('detects default exported component', async () => {\n      const entry = await extract(\n        'default',\n        dedent`\n          import React from 'react';\n          const Button = (props: { label: string }) => <button />;\n          export default Button;\n        `\n      );\n      expect(entry.component?.reactComponentMeta).toMatchObject({ exportName: 'default' });\n    });\n\n    it('detects inline default export', async () => {\n      const entry = await extract(\n        'default',\n        dedent`\n          import React from 'react';\n          export default (props: { label: string }) => <button />;\n        `\n      );\n      expect(entry.component?.reactComponentMeta).toMatchObject({ exportName: 'default' });\n    });\n\n    it('detects default export function declaration', async () => {\n      const entry = await extract(\n        'default',\n        dedent`\n          import React from 'react';\n          export default function Button(props: { label: string }) { return <button /> }\n        `\n      );\n      expect(entry.component?.reactComponentMeta).toMatchObject({ exportName: 'default' });\n    });\n  });\n\n  describe('non-components', () => {\n    it('rejects plain object', async () => {\n      const entry = await extract('Config', `export const Config = { key: 'value' };`);\n      expect(entry.component?.reactComponentMeta).toBeUndefined();\n    });\n\n    it('rejects string constant', async () => {\n      const entry = await extract('Title', `export const Title = 'Hello';`);\n      expect(entry.component?.reactComponentMeta).toBeUndefined();\n    });\n\n    it('rejects number constant', async () => {\n      const entry = await extract('Count', `export const Count = 42;`);\n      expect(entry.component?.reactComponentMeta).toBeUndefined();\n    });\n\n    it('rejects array', async () => {\n      const entry = await extract('Items', `export const Items = [1, 2, 3];`);\n      expect(entry.component?.reactComponentMeta).toBeUndefined();\n    });\n\n    it('rejects type-only exports', async () => {\n      const entry = await extract(\n        'ButtonProps',\n        dedent`\n          export interface ButtonProps { label: string }\n          export type Size = 'small' | 'large';\n        `\n      );\n      expect(entry.component?.reactComponentMeta).toBeUndefined();\n    });\n\n    it('rejects class not extending Component', async () => {\n      const entry = await extract(\n        'Store',\n        dedent`\n          export class Store {\n            data = {};\n            get(key: string) { return this.data; }\n          }\n        `\n      );\n      expect(entry.component?.reactComponentMeta).toBeUndefined();\n    });\n\n    it('rejects enum-like const object', async () => {\n      const entry = await extract(\n        'ButtonVariant',\n        dedent`\n          export const ButtonVariant = {\n            Primary: 'primary',\n            Secondary: 'secondary',\n          } as const;\n        `\n      );\n      expect(entry.component?.reactComponentMeta).toBeUndefined();\n    });\n  });\n\n  describe('ambiguous exports', () => {\n    it('accepts uppercase function returning ReactNode-assignable value', async () => {\n      const entry = await extract(\n        'FormatDate',\n        dedent`\n          export function FormatDate(timestamp: number) { return new Date(timestamp).toISOString(); }\n        `\n      );\n      expect(entry.component?.reactComponentMeta).toMatchObject({ displayName: 'FormatDate' });\n    });\n\n    it('accepts function with primitive props param', async () => {\n      const entry = await extract(\n        'ParseProps',\n        dedent`\n          export function ParseProps(props: string) { return JSON.parse(props); }\n        `\n      );\n      expect(entry.component?.reactComponentMeta).toMatchObject({ displayName: 'ParseProps' });\n    });\n  });\n\n  describe('multiple and mixed exports', () => {\n    it('detects multiple component exports from a single file', async () => {\n      const content = dedent`\n        import React from 'react';\n        interface ButtonProps { label: string }\n        export const Button = (props: ButtonProps) => <button />;\n        interface IconProps { name: string }\n        export const Icon = (props: IconProps) => <span />;\n      `;\n      const button = await extract('Button', content);\n      const icon = await extract('Icon', content);\n      expect(button.component?.reactComponentMeta).toMatchObject({ displayName: 'Button' });\n      expect(icon.component?.reactComponentMeta).toMatchObject({ displayName: 'Icon' });\n    });\n\n    it('only detects components among mixed exports', async () => {\n      const content = dedent`\n        import React from 'react';\n        export const Button = (props: { label: string }) => <button />;\n        export const Config = { key: 'value' };\n        export const Icon = (props: { name: string }) => <span />;\n        export const SIZES = ['small', 'large'] as const;\n      `;\n      const button = await extract('Button', content);\n      expect(button.component?.reactComponentMeta).toMatchObject({ displayName: 'Button' });\n      const config = await extract('Config', content);\n      expect(config.component?.reactComponentMeta).toBeUndefined();\n      const icon = await extract('Icon', content);\n      expect(icon.component?.reactComponentMeta).toMatchObject({ displayName: 'Icon' });\n      const sizes = await extract('SIZES', content);\n      expect(sizes.component?.reactComponentMeta).toBeUndefined();\n    });\n\n    it('detects components alongside type exports', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          export interface ButtonProps { label: string }\n          export const Button = (props: ButtonProps) => <button />;\n          export type Size = 'small' | 'large';\n        `\n      );\n      expect(entry.component?.reactComponentMeta).toMatchObject({ displayName: 'Button' });\n    });\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/componentMeta/componentMetaExtractor.displayName.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { dedent } from 'ts-dedent';\n\nimport { extractFromStory } from './componentMetaExtractor.test-helpers.ts';\n\ndescribe('display name resolution', () => {\n  it('uses export name for named exports', async () => {\n    const entry = await extractFromStory(\n      {\n        'dn/MyButton.tsx': dedent`\n          import React from 'react';\n          interface Props { label: string }\n          export const MyButton = (props: Props) => <button />;\n        `,\n        'dn/MyButton.stories.tsx': dedent`\n          import { MyButton } from './MyButton';\n          export default { component: MyButton };\n        `,\n      },\n      'dn/MyButton.stories.tsx'\n    );\n\n    expect(entry.component?.reactComponentMeta).toMatchObject({ displayName: 'MyButton' });\n  });\n\n  it('uses resolved symbol name for default exports', async () => {\n    const entry = await extractFromStory(\n      {\n        'dn/MyButton.tsx': dedent`\n          import React from 'react';\n          interface Props { label: string }\n          const MyButton = (props: Props) => <button />;\n          export default MyButton;\n        `,\n        'dn/MyButton.stories.tsx': dedent`\n          import MyButton from './MyButton';\n          export default { component: MyButton };\n        `,\n      },\n      'dn/MyButton.stories.tsx'\n    );\n\n    expect(entry.component?.reactComponentMeta).toMatchObject({ displayName: 'MyButton' });\n  });\n\n  it('uses the story-level component name for anonymous default exports', async () => {\n    const entry = await extractFromStory(\n      {\n        'dn/Widget.tsx': dedent`\n          import React from 'react';\n          export default (props: { label: string }) => <button />;\n        `,\n        'dn/Widget.stories.tsx': dedent`\n          import Widget from './Widget';\n          export default { component: Widget };\n        `,\n      },\n      'dn/Widget.stories.tsx'\n    );\n\n    expect(entry.component?.reactComponentMeta).toMatchObject({ displayName: 'Widget' });\n  });\n\n  it('uses a custom story alias for anonymous default exports', async () => {\n    const entry = await extractFromStory(\n      {\n        'dn/Widget.tsx': dedent`\n          import React from 'react';\n          export default (props: { label: string }) => <button />;\n        `,\n        'dn/Widget.stories.tsx': dedent`\n          import MarketingHeader from './Widget';\n          export default { component: MarketingHeader };\n        `,\n      },\n      'dn/Widget.stories.tsx'\n    );\n\n    expect(entry.component?.reactComponentMeta).toMatchObject({ displayName: 'MarketingHeader' });\n  });\n\n  it('uses the story-level component name for anonymous default exports from index.ts', async () => {\n    const entry = await extractFromStory(\n      {\n        'dn/TextInput/TextInput.tsx': dedent`\n          import React from 'react';\n          export default (props: { value: string }) => <input />;\n        `,\n        'dn/TextInput/index.ts': dedent`\n          export { default } from './TextInput';\n        `,\n        'dn/TextInput.stories.tsx': dedent`\n          import TextInput from './TextInput/index';\n          export default { component: TextInput };\n        `,\n      },\n      'dn/TextInput.stories.tsx'\n    );\n\n    expect(entry.component?.reactComponentMeta).toMatchObject({ displayName: 'TextInput' });\n  });\n\n  it('uses a custom story alias for anonymous default exports from index.ts', async () => {\n    const entry = await extractFromStory(\n      {\n        'dn/TextInput/TextInput.tsx': dedent`\n          import React from 'react';\n          export default (props: { value: string }) => <input />;\n        `,\n        'dn/TextInput/index.ts': dedent`\n          export { default } from './TextInput';\n        `,\n        'dn/TextInput.stories.tsx': dedent`\n          import SearchField from './TextInput/index';\n          export default { component: SearchField };\n        `,\n      },\n      'dn/TextInput.stories.tsx'\n    );\n\n    expect(entry.component?.reactComponentMeta).toMatchObject({ displayName: 'SearchField' });\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/componentMeta/componentMetaExtractor.parentTracking.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { dedent } from 'ts-dedent';\n\nimport { extract } from './componentMetaExtractor.test-helpers.ts';\n\ndescribe('parent and declaration tracking', () => {\n  it('attaches parent type info to props from named interfaces', async () => {\n    const entry = await extract(\n      'Button',\n      dedent`\n        import React from 'react';\n        interface ButtonProps {\n          label: string;\n        }\n        export const Button = (props: ButtonProps) => <button />;\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        label: {\n          parent: { name: 'ButtonProps' },\n          declarations: [{ name: 'ButtonProps' }],\n        },\n      },\n    });\n  });\n\n  it('attaches declarations with TypeLiteral for inline types', async () => {\n    const entry = await extract(\n      'Button',\n      dedent`\n        import React from 'react';\n        export const Button = (props: { label: string }) => <button />;\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        label: {\n          declarations: [{ name: 'TypeLiteral' }],\n        },\n      },\n    });\n  });\n\n  it('resolves parent through intersection type literals', async () => {\n    const entry = await extract(\n      'Button',\n      dedent`\n        import React from 'react';\n        type BaseProps = { loading?: boolean };\n        type ButtonProps = { variant?: string } & BaseProps;\n        export const Button = (props: ButtonProps) => <button />;\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        loading: { parent: { name: 'BaseProps' }, declarations: [{ name: 'TypeLiteral' }] },\n        variant: { parent: { name: 'ButtonProps' }, declarations: [{ name: 'TypeLiteral' }] },\n      },\n    });\n  });\n\n  it('resolves parent for forwardRef with polymorphic as-cast', async () => {\n    const entry = await extract(\n      'Button',\n      dedent`\n        import React from 'react';\n        type BaseProps = { loading?: boolean } & React.ButtonHTMLAttributes<HTMLButtonElement>;\n        type ButtonProps = { variant?: string } & BaseProps;\n        type PolymorphicFC<As extends React.ElementType, P> =\n          React.ForwardRefExoticComponent<P & { as?: As } & React.RefAttributes<any>>;\n        export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n          (props, ref) => <button ref={ref} />\n        ) as PolymorphicFC<'button', ButtonProps>;\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        as: { parent: { name: 'PolymorphicFC' }, declarations: [{ name: 'TypeLiteral' }] },\n        loading: { parent: { name: 'BaseProps' }, declarations: [{ name: 'TypeLiteral' }] },\n        variant: { parent: { name: 'ButtonProps' }, declarations: [{ name: 'TypeLiteral' }] },\n      },\n    });\n  });\n\n  it('tracks parent through intersection types', async () => {\n    const entry = await extract(\n      'Button',\n      dedent`\n        import React from 'react';\n        interface BaseProps {\n          /** Unique identifier */\n          id: string;\n        }\n        interface StyleProps {\n          /** Custom CSS class */\n          className?: string;\n        }\n        type ButtonProps = BaseProps & StyleProps & {\n          /** The label */\n          label: string;\n        };\n        export const Button = (props: ButtonProps) => <button />;\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        id: { parent: { name: 'BaseProps' }, declarations: [{ name: 'BaseProps' }] },\n        className: { parent: { name: 'StyleProps' }, declarations: [{ name: 'StyleProps' }] },\n        label: { parent: { name: 'ButtonProps' }, declarations: [{ name: 'TypeLiteral' }] },\n      },\n    });\n  });\n\n  it('tracks parent through extends', async () => {\n    const entry = await extract(\n      'Button',\n      dedent`\n        import React from 'react';\n        interface BaseProps {\n          /** Unique identifier */\n          id: string;\n        }\n        interface ButtonProps extends BaseProps {\n          label: string;\n        }\n        export const Button = (props: ButtonProps) => <button />;\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        id: { parent: { name: 'BaseProps' }, declarations: [{ name: 'BaseProps' }] },\n        label: { parent: { name: 'ButtonProps' }, declarations: [{ name: 'ButtonProps' }] },\n      },\n    });\n  });\n\n  it('tracks declarations from multiple sources', async () => {\n    const entry = await extract(\n      'Comp',\n      dedent`\n        import React from 'react';\n        interface A { shared: string }\n        interface B { shared: string }\n        type Props = A & B;\n        export const Comp = (props: Props) => <div />;\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        shared: {\n          parent: { name: 'A' },\n          declarations: [{ name: 'A' }, { name: 'B' }],\n        },\n      },\n    });\n  });\n\n  it('filters out HTML attributes when declaration file contributes >30 props', async () => {\n    const entry = await extract(\n      'Button',\n      dedent`\n        import React from 'react';\n        interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n          /** Custom variant */\n          variant: 'primary' | 'secondary';\n        }\n        export const Button = (props: ButtonProps) => <button />;\n      `\n    );\n    expect(entry.component?.reactComponentMeta).toMatchObject({\n      props: {\n        variant: {\n          parent: { name: 'ButtonProps', fileName: expect.any(String) },\n          declarations: [{ name: 'ButtonProps', fileName: expect.any(String) }],\n        },\n      },\n    });\n    // HTML attributes from ButtonHTMLAttributes are filtered out (>30 props)\n    const propNames = Object.keys(entry.component?.reactComponentMeta?.props ?? {});\n    expect(propNames).toContain('variant');\n    expect(propNames).not.toContain('onClick');\n    expect(propNames).not.toContain('className');\n    expect(propNames).not.toContain('disabled');\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/componentMeta/componentMetaExtractor.props.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { dedent } from 'ts-dedent';\n\nimport { extract, extractFromStory } from './componentMetaExtractor.test-helpers.ts';\n\ndescribe('prop extraction', () => {\n  describe('basic types', () => {\n    it('extracts string, number, and boolean props', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          interface ButtonProps {\n            label: string;\n            count: number;\n            disabled?: boolean;\n          }\n          export const Button = (props: ButtonProps) => <button />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: {\n          label: { type: { name: 'string' }, required: true },\n          count: { type: { name: 'number' }, required: true },\n          disabled: { required: false },\n        },\n      });\n    });\n\n    it('extracts function prop types', async () => {\n      const entry = await extract(\n        'Form',\n        dedent`\n          import React from 'react';\n          interface Props {\n            onClick: () => void;\n            onChange: (value: string) => void;\n            onSubmit: (event: React.FormEvent) => Promise<void>;\n          }\n          export const Form = (props: Props) => <form />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: {\n          onClick: { type: { name: '() => void' } },\n          onChange: { type: { name: '(value: string) => void' } },\n          onSubmit: { type: { name: '(event: FormEvent<Element>) => Promise<void>' } },\n        },\n      });\n    });\n\n    it('extracts array prop types', async () => {\n      const entry = await extract(\n        'List',\n        dedent`\n          import React from 'react';\n          interface Props {\n            items: string[];\n            matrix: number[][];\n            nodes: Array<React.ReactNode>;\n          }\n          export const List = (props: Props) => <ul />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: {\n          items: { type: { name: 'string[]' } },\n          matrix: { type: { name: 'number[][]' } },\n          nodes: { type: { name: 'ReactNode[]' } },\n        },\n      });\n    });\n\n    it('extracts nested object props', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          interface Theme {\n            colors: { primary: string; secondary: string };\n            spacing: number;\n          }\n          interface Props { theme: Theme; label: string }\n          export const Button = (props: Props) => <button />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: {\n          theme: { type: { name: 'Theme' } },\n          label: { type: { name: 'string' } },\n        },\n      });\n    });\n\n    it('extracts React.ReactNode and React.ReactElement', async () => {\n      const entry = await extract(\n        'Card',\n        dedent`\n          import React from 'react';\n          interface Props {\n            children: React.ReactNode;\n            icon: React.ReactElement;\n            header?: React.ReactNode;\n          }\n          export const Card = (props: Props) => <div />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: {\n          children: { type: { name: 'ReactNode' } },\n          icon: { type: { name: 'ReactElement<any, string | JSXElementConstructor<any>>' } },\n          header: { type: { name: 'ReactNode' } },\n        },\n      });\n    });\n\n    it('extracts tuple, Record, and indexed access types', async () => {\n      const entry = await extract(\n        'Comp',\n        dedent`\n          import React from 'react';\n          interface Config { theme: { color: string; size: number } }\n          interface Props {\n            point: [number, number];\n            cells: Record<string, number>;\n            theme: Config['theme'];\n          }\n          export const Comp = (props: Props) => <div />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: {\n          point: { type: { name: '[number, number]' } },\n          cells: { type: { name: 'Record<string, number>' } },\n          theme: { type: { name: '{ color: string; size: number; }' } },\n        },\n      });\n    });\n  });\n\n  describe('union types', () => {\n    it('extracts string literal union as enum', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          interface Props { size: 'small' | 'medium' | 'large' }\n          export const Button = (props: Props) => <button />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: {\n          size: {\n            type: {\n              name: 'enum',\n              value: [{ value: '\"small\"' }, { value: '\"medium\"' }, { value: '\"large\"' }],\n            },\n          },\n        },\n      });\n    });\n\n    it('extracts optional string literal union as enum', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          interface Props { size?: 'small' | 'medium' | 'large' }\n          export const Button = (props: Props) => <button />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: {\n          size: {\n            required: false,\n            type: {\n              name: 'enum',\n              value: [{ value: '\"small\"' }, { value: '\"medium\"' }, { value: '\"large\"' }],\n            },\n          },\n        },\n      });\n    });\n\n    it('extracts number literal union as enum', async () => {\n      const entry = await extract(\n        'Grid',\n        dedent`\n          import React from 'react';\n          interface Props { columns: 1 | 2 | 3 | 4 }\n          export const Grid = (props: Props) => <div />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: {\n          columns: {\n            type: {\n              name: 'enum',\n              value: [{ value: '1' }, { value: '2' }, { value: '3' }, { value: '4' }],\n            },\n          },\n        },\n      });\n    });\n\n    it('extracts TypeScript enum as enum', async () => {\n      const entry = await extract(\n        'Badge',\n        dedent`\n          import React from 'react';\n          enum Status { Active = 'active', Inactive = 'inactive', Pending = 'pending' }\n          interface Props { status: Status }\n          export const Badge = (props: Props) => <span />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: {\n          status: {\n            type: {\n              name: 'enum',\n              value: [{ value: '\"active\"' }, { value: '\"inactive\"' }, { value: '\"pending\"' }],\n            },\n          },\n        },\n      });\n    });\n\n    it('extracts template literal type as enum', async () => {\n      const entry = await extract(\n        'Token',\n        dedent`\n          import React from 'react';\n          type Color = 'red' | 'blue';\n          interface Props { token: \\`color-\\${Color}\\` }\n          export const Token = (props: Props) => <span />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: {\n          token: {\n            type: {\n              name: 'enum',\n              value: [{ value: '\"color-red\"' }, { value: '\"color-blue\"' }],\n            },\n          },\n        },\n      });\n    });\n\n    it('extracts mixed union as type string, not enum', async () => {\n      const entry = await extract(\n        'Input',\n        dedent`\n          import React from 'react';\n          interface Props { value: string | number }\n          export const Input = (props: Props) => <input />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: { value: { type: { name: 'string | number' } } },\n      });\n    });\n\n    it('collapses true | false to boolean', async () => {\n      const entry = await extract(\n        'Toggle',\n        dedent`\n          import React from 'react';\n          interface Props { on: true | false }\n          export const Toggle = (props: Props) => <button />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: { on: { type: { name: 'boolean' } } },\n      });\n    });\n\n    it('preserves nested | undefined in optional multi-member unions', async () => {\n      const entry = await extract(\n        'Widget',\n        dedent`\n          import React from 'react';\n          type A = { a: string };\n          type B = { b: number };\n          interface Props {\n            config?: Record<string, number | undefined>;\n            onChange?: (value: string | undefined) => void;\n            handler?: ((x: number) => void) | string;\n            combo?: (A & B) | string;\n          }\n          export const Widget = (props: Props) => <div />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: {\n          config: { type: { name: 'Record<string, number | undefined>' } },\n          onChange: { type: { name: '(value: string | undefined) => void' } },\n          handler: { type: { name: 'string | ((x: number) => void) | undefined' } },\n          combo: { type: { name: 'string | (A & B) | undefined' } },\n        },\n      });\n    });\n\n    it('collects all props from discriminated union', async () => {\n      const entry = await extract(\n        'Slider',\n        dedent`\n          import React from 'react';\n          type ControlledProps = { value: number; defaultValue?: never };\n          type UncontrolledProps = { value?: never; defaultValue?: number };\n          type BaseProps = { min?: number; max?: number; step?: number };\n          type Props = BaseProps & (ControlledProps | UncontrolledProps);\n          export const Slider: React.FC<Props> = (props) => <div />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: {\n          defaultValue: { required: false },\n          max: { required: false },\n          min: { required: false },\n          step: { required: false },\n          value: { required: false },\n        },\n      });\n    });\n\n    it('forces optional when union variant lacks a prop', async () => {\n      const entry = await extract(\n        'Alert',\n        dedent`\n          import React from 'react';\n          type SuccessProps = { kind: 'success'; message: string; retryable?: never };\n          type ErrorProps = { kind: 'error'; message: string; retryable: boolean };\n          type Props = SuccessProps | ErrorProps;\n          export const Alert: React.FC<Props> = (props) => <div />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: {\n          kind: { required: true },\n          message: { required: true },\n          retryable: { required: false },\n        },\n      });\n    });\n  });\n\n  describe('utility types', () => {\n    it('extracts Pick<>', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          interface FullProps { id: string; label: string; disabled: boolean; hidden: boolean }\n          type ButtonProps = Pick<FullProps, 'id' | 'label'>;\n          export const Button = (props: ButtonProps) => <button />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: { id: { type: { name: 'string' } }, label: { type: { name: 'string' } } },\n      });\n    });\n\n    it('extracts Omit<>', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          interface FullProps { id: string; label: string; internal: boolean }\n          type ButtonProps = Omit<FullProps, 'internal'>;\n          export const Button = (props: ButtonProps) => <button />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: { id: { type: { name: 'string' } }, label: { type: { name: 'string' } } },\n      });\n    });\n\n    it('extracts Partial<> as all optional', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          interface FullProps { label: string; count: number }\n          export const Button = (props: Partial<FullProps>) => <button />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: { label: { required: false }, count: { required: false } },\n      });\n    });\n\n    it('extracts Required<> as all required', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          interface OptionalProps { label?: string; count?: number }\n          export const Button = (props: Required<OptionalProps>) => <button />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: { label: { required: true }, count: { required: true } },\n      });\n    });\n\n    it('extracts Readonly<>', async () => {\n      const entry = await extract(\n        'Display',\n        dedent`\n          import React from 'react';\n          interface Props { value: string; count: number }\n          export const Display = (props: Readonly<Props>) => <div />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: { value: { required: true }, count: { required: true } },\n      });\n    });\n\n    it('extracts complex Pick & Omit & intersection', async () => {\n      const entry = await extract(\n        'Comp',\n        dedent`\n          import React from 'react';\n          interface Full { a: string; b: number; c: boolean; d: string }\n          type Props = Pick<Full, 'a' | 'b' | 'c'> & Omit<{ extra: string; d: number }, 'd'>;\n          export const Comp = (props: Props) => <div />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: { a: {}, b: {}, c: {}, extra: {} },\n      });\n      expect(entry.component?.reactComponentMeta?.props).not.toHaveProperty('d');\n    });\n\n    it('extracts mapped type', async () => {\n      const entry = await extract(\n        'Comp',\n        dedent`\n          import React from 'react';\n          type Flags<T extends string> = { [K in T]: boolean };\n          type Props = Flags<'a' | 'b'>;\n          export const Comp = (props: Props) => <div />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: { a: { type: { name: 'boolean' } }, b: { type: { name: 'boolean' } } },\n      });\n    });\n\n    it('extracts conditional type', async () => {\n      const entry = await extract(\n        'Comp',\n        dedent`\n          import React from 'react';\n          type IsString<T> = T extends string ? true : false;\n          interface Props { check: IsString<'hello'>; other: IsString<42> }\n          export const Comp = (props: Props) => <div />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: { check: { type: { name: 'true' } }, other: { type: { name: 'false' } } },\n      });\n    });\n\n    it('extracts type alias wrapping interface', async () => {\n      const entry = await extract(\n        'Comp',\n        dedent`\n          import React from 'react';\n          interface BaseProps { label: string; count: number }\n          type Props = BaseProps;\n          export const Comp = (props: Props) => <div />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: { label: { required: true }, count: { required: true } },\n      });\n    });\n  });\n\n  describe('forwardRef', () => {\n    it('extracts props', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          interface Props { label: string; variant?: 'a' | 'b' }\n          export const Button = React.forwardRef<HTMLButtonElement, Props>((props, ref) => (\n            <button ref={ref} />\n          ));\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: {\n          label: { type: { name: 'string' }, required: true },\n          variant: { type: { name: 'enum', value: [{ value: '\"a\"' }, { value: '\"b\"' }] } },\n        },\n      });\n    });\n\n    it('includes ref and key props', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          interface Props { label: string }\n          export const Button = React.forwardRef<HTMLButtonElement, Props>((props, ref) => (\n            <button ref={ref} />\n          ));\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: {\n          ref: { parent: { name: 'RefAttributes' } },\n          key: { parent: { name: 'Attributes' } },\n        },\n      });\n    });\n  });\n\n  describe('bulk source filtering', () => {\n    it('filters HTML attributes exceeding >30 props threshold', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n            variant: 'primary' | 'secondary';\n            label: string;\n          }\n          export const Button = (props: ButtonProps) => <button />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: { variant: { required: true }, label: { required: true } },\n      });\n      expect(entry.component?.reactComponentMeta?.props).not.toHaveProperty('onClick');\n      expect(entry.component?.reactComponentMeta?.props).not.toHaveProperty('className');\n    });\n\n    it('keeps HTML attributes when Pick narrows below threshold', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          type ButtonProps = Pick<React.ButtonHTMLAttributes<HTMLButtonElement>, 'disabled' | 'type'> & {\n            label: string;\n          };\n          export const Button = (props: ButtonProps) => <button />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: {\n          disabled: { required: false },\n          type: { required: false },\n          label: { required: true },\n        },\n      });\n    });\n  });\n\n  describe('without meta.component (JSX path)', () => {\n    it('extracts props via named import', async () => {\n      const entry = await extractFromStory(\n        {\n          'jsx/Button.stories.tsx': dedent`\n            import { Button } from './Button';\n            export default {};\n            export const Primary = () => <Button label=\"Click\" />;\n          `,\n          'jsx/Button.tsx': dedent`\n            import React from 'react';\n            interface ButtonProps {\n              /** The label */\n              label: string;\n              variant?: 'primary' | 'secondary';\n            }\n            export const Button = (props: ButtonProps) => <button />;\n          `,\n        },\n        'jsx/Button.stories.tsx'\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        displayName: 'Button',\n        props: {\n          label: { description: 'The label', type: { name: 'string' }, required: true },\n          variant: {\n            type: { name: 'enum', value: [{ value: '\"primary\"' }, { value: '\"secondary\"' }] },\n            required: false,\n          },\n        },\n      });\n    });\n\n    it('extracts props via default import', async () => {\n      const entry = await extractFromStory(\n        {\n          'jsx/Widget.stories.tsx': dedent`\n            import Widget from './Widget';\n            export default {};\n            export const Default = () => <Widget title=\"Hello\" />;\n          `,\n          'jsx/Widget.tsx': dedent`\n            import React from 'react';\n            interface Props { title: string; active?: boolean }\n            const Widget = (props: Props) => <div />;\n            export default Widget;\n          `,\n        },\n        'jsx/Widget.stories.tsx'\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        displayName: 'Widget',\n        props: { title: { required: true }, active: { required: false } },\n      });\n    });\n\n    it('extracts props via { default as X } import', async () => {\n      const entry = await extractFromStory(\n        {\n          'jsx/Panel.stories.tsx': dedent`\n            import { default as Panel } from './Panel';\n            export default {};\n            export const Open = () => <Panel title=\"Details\" open />;\n          `,\n          'jsx/Panel.tsx': dedent`\n            import React from 'react';\n            interface Props { title: string; open?: boolean }\n            export default (props: Props) => <div />;\n          `,\n        },\n        'jsx/Panel.stories.tsx'\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: { title: { required: true }, open: { required: false } },\n      });\n    });\n\n    it('extracts props via namespace import', async () => {\n      const entry = await extractFromStory(\n        {\n          'jsx/ns/Accordion.stories.tsx': dedent`\n            import * as Accordion from './Accordion';\n            export default {};\n            export const Basic = () => <Accordion.Root multiple />;\n          `,\n          'jsx/ns/Accordion.tsx': dedent`\n            import React from 'react';\n            interface RootProps { multiple?: boolean; defaultValue?: string }\n            export const Root = (props: RootProps) => <div />;\n          `,\n        },\n        'jsx/ns/Accordion.stories.tsx'\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: { multiple: { required: false }, defaultValue: { type: { name: 'string' } } },\n      });\n    });\n\n    it('extracts satisfies expression component', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          interface Props { label: string; size?: 'sm' | 'md' }\n          export const Button = ((props: Props) => <button />) satisfies React.FC<Props>;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: {\n          label: { required: true },\n          size: { type: { name: 'enum', value: [{ value: '\"sm\"' }, { value: '\"md\"' }] } },\n        },\n      });\n    });\n  });\n\n  describe('JSDoc', () => {\n    it('extracts prop-level descriptions', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          interface Props {\n            /** The button label text */\n            label: string;\n            /** Whether the button is in primary style */\n            primary?: boolean;\n          }\n          export const Button = (props: Props) => <button />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        props: {\n          label: { description: 'The button label text' },\n          primary: { description: 'Whether the button is in primary style' },\n        },\n      });\n    });\n\n    it('extracts component-level description', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          interface Props { label: string }\n          /** Primary UI component for user interaction */\n          export const Button = (props: Props) => <button />;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        description: 'Primary UI component for user interaction',\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/componentMeta/componentMetaExtractor.qa.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { dedent } from 'ts-dedent';\n\nimport { extract, extractFromStory } from './componentMetaExtractor.test-helpers.ts';\n\ndescribe('real-world component patterns', () => {\n  describe('ForwardRefExoticComponent from HOC factory (Park UI)', () => {\n    it('extracts withProvider HOC', async () => {\n      const entry = await extract(\n        'Root',\n        dedent`\n          import React from 'react';\n\n          function withProvider<T extends HTMLElement, P>(\n            Component: React.ComponentType<any>,\n            _slot: string\n          ): React.ForwardRefExoticComponent<React.PropsWithoutRef<P> & React.RefAttributes<T>> {\n            return React.forwardRef<T, P>((props, ref) => <Component {...props} ref={ref} />) as any;\n          }\n\n          interface RootProps {\n            /** The accordion items */\n            items: string[];\n            /** Whether multiple items can be open */\n            multiple?: boolean;\n          }\n\n          const InternalRoot = (props: RootProps) => <div />;\n\n          export const Root = withProvider<HTMLDivElement, RootProps>(InternalRoot, 'root');\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        displayName: 'Root',\n        props: {\n          items: { description: 'The accordion items', required: true, type: { name: 'string[]' } },\n          multiple: { description: 'Whether multiple items can be open', required: false },\n        },\n      });\n    });\n\n    it('extracts withContext HOC', async () => {\n      const entry = await extract(\n        'ItemTrigger',\n        dedent`\n          import React from 'react';\n\n          function withContext<T extends HTMLElement, P>(\n            Component: React.ComponentType<any>,\n            _slot: string\n          ): React.ForwardRefExoticComponent<React.PropsWithoutRef<P> & React.RefAttributes<T>> {\n            return React.forwardRef<T, P>((props, ref) => <Component {...props} ref={ref} />) as any;\n          }\n\n          interface ItemTriggerProps {\n            /** Click handler */\n            onClick?: () => void;\n          }\n\n          const BaseItemTrigger = (props: ItemTriggerProps) => <button />;\n\n          export const ItemTrigger = withContext<HTMLButtonElement, ItemTriggerProps>(\n            BaseItemTrigger, 'itemTrigger'\n          );\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        displayName: 'ItemTrigger',\n        props: {\n          onClick: { description: 'Click handler', required: false, type: { name: '() => void' } },\n        },\n      });\n    });\n\n    it('extracts multiple HOC-wrapped sub-components', async () => {\n      const componentSource = dedent`\n        import React from 'react';\n\n        function withProvider<T extends HTMLElement, P>(\n          Component: React.ComponentType<any>,\n          _slot: string\n        ): React.ForwardRefExoticComponent<React.PropsWithoutRef<P> & React.RefAttributes<T>> {\n          return React.forwardRef<T, P>((props, ref) => <Component {...props} ref={ref} />) as any;\n        }\n\n        function withContext<T extends HTMLElement, P>(\n          Component: React.ComponentType<any>,\n          _slot: string\n        ): React.ForwardRefExoticComponent<React.PropsWithoutRef<P> & React.RefAttributes<T>> {\n          return React.forwardRef<T, P>((props, ref) => <Component {...props} ref={ref} />) as any;\n        }\n\n        interface RootProps { multiple?: boolean }\n        interface ItemProps { value: string; disabled?: boolean }\n        interface ItemTriggerProps { onClick?: () => void }\n\n        const InternalRoot = (props: RootProps) => <div />;\n        const InternalItem = (props: ItemProps) => <div />;\n        const InternalTrigger = (props: ItemTriggerProps) => <button />;\n\n        export const Root = withProvider<HTMLDivElement, RootProps>(InternalRoot, 'root');\n        export const Item = withContext<HTMLDivElement, ItemProps>(InternalItem, 'item');\n        export const ItemTrigger = withContext<HTMLButtonElement, ItemTriggerProps>(\n          InternalTrigger, 'itemTrigger'\n        );\n      `;\n\n      const root = await extract('Root', componentSource);\n      expect(root.component?.reactComponentMeta).toMatchObject({\n        displayName: 'Root',\n        props: { multiple: { required: false } },\n      });\n\n      const item = await extract('Item', componentSource);\n      expect(item.component?.reactComponentMeta).toMatchObject({\n        displayName: 'Item',\n        props: { value: { required: true }, disabled: { required: false } },\n      });\n\n      const itemTrigger = await extract('ItemTrigger', componentSource);\n      expect(itemTrigger.component?.reactComponentMeta).toMatchObject({\n        displayName: 'ItemTrigger',\n        props: { onClick: { required: false } },\n      });\n    });\n  });\n\n  describe('as-cast patterns (Primer)', () => {\n    it('extracts component after as WithSlotMarker cast', async () => {\n      const entry = await extract(\n        'default',\n        dedent`\n          import React from 'react';\n\n          interface CheckboxProps {\n            /** Whether the checkbox is checked */\n            checked?: boolean;\n            /** Change handler */\n            onChange?: (checked: boolean) => void;\n            /** Disabled state */\n            disabled?: boolean;\n          }\n\n          interface SlotMarker { __SLOT__?: symbol }\n          type WithSlotMarker<T> = T & SlotMarker;\n\n          const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>((props, ref) => (\n            <input type=\"checkbox\" ref={ref} />\n          ));\n\n          (Checkbox as WithSlotMarker<typeof Checkbox>).__SLOT__ = Symbol('Checkbox');\n\n          export default Checkbox as WithSlotMarker<typeof Checkbox>;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        exportName: 'default',\n        props: {\n          checked: { description: 'Whether the checkbox is checked', required: false },\n          onChange: { description: 'Change handler', required: false },\n          disabled: { description: 'Disabled state', required: false },\n        },\n      });\n    });\n\n    it('extracts PolymorphicForwardRefComponent', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n\n          type Merge<A, B> = Omit<A, keyof B> & B;\n\n          interface PolymorphicForwardRefComponent<\n            DefaultElement extends React.ElementType,\n            OwnProps = {}\n          > extends React.ForwardRefExoticComponent<\n            Merge<React.ComponentPropsWithRef<DefaultElement>, OwnProps & { as?: DefaultElement }>\n          > {\n            <As extends React.ElementType = DefaultElement>(\n              props: Merge<React.ComponentPropsWithRef<As>, OwnProps & { as?: As }>\n            ): React.ReactElement | null;\n          }\n\n          interface ButtonProps {\n            /** Button variant style */\n            variant?: 'default' | 'primary' | 'danger';\n            /** Button size */\n            size?: 'small' | 'medium' | 'large';\n          }\n\n          const ButtonComponent = React.forwardRef<HTMLButtonElement, ButtonProps>(\n            (props, ref) => <button ref={ref} />\n          ) as PolymorphicForwardRefComponent<'button', ButtonProps>;\n\n          ButtonComponent.displayName = 'Button';\n\n          export { ButtonComponent as Button };\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        displayName: 'Button',\n        props: {\n          variant: {\n            description: 'Button variant style',\n            type: {\n              name: 'enum',\n              value: [{ value: '\"default\"' }, { value: '\"primary\"' }, { value: '\"danger\"' }],\n            },\n          },\n          size: {\n            description: 'Button size',\n            type: {\n              name: 'enum',\n              value: [{ value: '\"small\"' }, { value: '\"medium\"' }, { value: '\"large\"' }],\n            },\n          },\n        },\n      });\n    });\n\n    it('extracts destructuring defaults from PolymorphicForwardRefComponent', async () => {\n      const entry = await extract(\n        'Stack',\n        dedent`\n          import React, { forwardRef, type ElementType } from 'react';\n\n          type Merge<A, B> = Omit<A, keyof B> & B;\n\n          interface PolymorphicForwardRefComponent<\n            DefaultElement extends React.ElementType,\n            OwnProps = {}\n          > extends React.ForwardRefExoticComponent<\n            Merge<React.ComponentPropsWithRef<DefaultElement>, OwnProps & { as?: DefaultElement }>\n          > {\n            <As extends React.ElementType = DefaultElement>(\n              props: Merge<React.ComponentPropsWithRef<As>, OwnProps & { as?: As }>\n            ): React.ReactElement | null;\n          }\n\n          interface StackProps {\n            /** Specify the direction\n             * @default vertical\n             */\n            direction?: 'horizontal' | 'vertical';\n            /** Specify the alignment */\n            align?: 'stretch' | 'start' | 'center' | 'end';\n            /** Specify wrapping */\n            wrap?: 'wrap' | 'nowrap';\n          }\n\n          const Stack = forwardRef(\n            ({\n              direction = 'vertical',\n              align = 'stretch',\n              wrap = 'nowrap',\n              ...rest\n            }: StackProps, forwardedRef: React.Ref<HTMLDivElement>) => {\n              return <div ref={forwardedRef} {...rest} />;\n            },\n          ) as PolymorphicForwardRefComponent<ElementType, StackProps>;\n\n          export { Stack };\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        displayName: 'Stack',\n        props: {\n          direction: { defaultValue: { value: \"'vertical'\" } },\n          align: { defaultValue: { value: \"'stretch'\" } },\n          wrap: { defaultValue: { value: \"'nowrap'\" } },\n        },\n      });\n    });\n  });\n\n  describe('Object.assign compound component (Primer)', () => {\n    it('extracts component from Object.assign export', async () => {\n      const entry = await extract(\n        'default',\n        dedent`\n          import React from 'react';\n\n          interface FormControlProps {\n            /** Unique identifier */\n            id: string;\n            /** Whether the field is required */\n            required?: boolean;\n            /** Whether the field is disabled */\n            disabled?: boolean;\n          }\n\n          const FormControlBase = React.forwardRef<HTMLDivElement, FormControlProps>(\n            (props, ref) => <div ref={ref} />\n          );\n\n          const Caption = (props: { children: React.ReactNode }) => <span />;\n          const Label = (props: { children: React.ReactNode }) => <label />;\n\n          const FormControl = Object.assign(FormControlBase, { Caption, Label });\n\n          export default FormControl;\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        displayName: 'FormControl',\n        props: {\n          id: { description: 'Unique identifier', required: true },\n          required: { description: 'Whether the field is required', required: false },\n          disabled: { description: 'Whether the field is disabled', required: false },\n        },\n      });\n    });\n\n    it('extracts destructuring defaults through Object.assign', async () => {\n      const entry = await extract(\n        'Stack',\n        dedent`\n          import React, { forwardRef, type ElementType } from 'react';\n\n          interface StackProps {\n            direction?: 'horizontal' | 'vertical';\n            align?: 'stretch' | 'start' | 'center' | 'end';\n            wrap?: 'wrap' | 'nowrap';\n          }\n\n          const StackImpl = forwardRef(\n            ({\n              direction = 'vertical',\n              align = 'stretch',\n              wrap = 'nowrap',\n              ...rest\n            }: StackProps, forwardedRef: React.Ref<HTMLDivElement>) => {\n              return <div ref={forwardedRef} {...rest} />;\n            },\n          );\n\n          const StackItem = (props: { children: React.ReactNode }) => <div />;\n\n          export const Stack = Object.assign(StackImpl, { Item: StackItem });\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        displayName: 'Stack',\n        props: {\n          direction: { defaultValue: { value: \"'vertical'\" } },\n          align: { defaultValue: { value: \"'stretch'\" } },\n          wrap: { defaultValue: { value: \"'nowrap'\" } },\n        },\n      });\n    });\n  });\n\n  describe('aliased barrel re-export (Primer)', () => {\n    it('extracts component through aliased re-export', async () => {\n      const entry = await extractFromStory(\n        {\n          'qa/barrel/Button.tsx': dedent`\n            import React from 'react';\n            interface ButtonProps {\n              /** Button label */\n              label: string;\n              /** Visual variant */\n              variant?: 'solid' | 'outline' | 'ghost';\n            }\n            export const InternalButton = React.forwardRef<HTMLButtonElement, ButtonProps>(\n              (props, ref) => <button ref={ref}>{props.label}</button>\n            );\n            InternalButton.displayName = 'Button';\n          `,\n          'qa/barrel/index.ts': `export { InternalButton as Button } from './Button';`,\n          'qa/barrel/index.stories.tsx': dedent`\n            import { Button } from './index';\n            export default { component: Button };\n          `,\n        },\n        'qa/barrel/index.stories.tsx'\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        displayName: 'Button',\n        props: {\n          label: { description: 'Button label', required: true },\n          variant: {\n            description: 'Visual variant',\n            type: {\n              name: 'enum',\n              value: [{ value: '\"solid\"' }, { value: '\"outline\"' }, { value: '\"ghost\"' }],\n            },\n          },\n        },\n      });\n    });\n  });\n\n  describe('empty interface with deep extends (Mantine)', () => {\n    it('extracts props from empty interface extending multiple bases', async () => {\n      const entry = await extract(\n        'TextInput',\n        dedent`\n          import React from 'react';\n\n          interface StylesApiProps {\n            /** CSS class name */\n            className?: string;\n            /** Inline styles */\n            style?: React.CSSProperties;\n          }\n\n          interface BaseInputProps {\n            /** Input label */\n            label?: React.ReactNode;\n            /** Error message */\n            error?: React.ReactNode;\n            /** Description text */\n            description?: React.ReactNode;\n          }\n\n          interface BoxProps {\n            /** Custom component */\n            component?: React.ElementType;\n          }\n\n          type ElementProps<E extends React.ElementType, Excluded extends string = never> =\n            Omit<React.ComponentPropsWithoutRef<E>, Excluded>;\n\n          interface TextInputProps extends BoxProps, BaseInputProps,\n            StylesApiProps, ElementProps<'input', 'size'> {}\n\n          export const TextInput = React.forwardRef<HTMLInputElement, TextInputProps>(\n            (props, ref) => <input ref={ref} />\n          );\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        displayName: 'TextInput',\n        props: {\n          className: { description: 'CSS class name', parent: { name: 'StylesApiProps' } },\n          label: { description: 'Input label', parent: { name: 'BaseInputProps' } },\n          error: { description: 'Error message', parent: { name: 'BaseInputProps' } },\n          description: { description: 'Description text', parent: { name: 'BaseInputProps' } },\n          component: { description: 'Custom component', parent: { name: 'BoxProps' } },\n        },\n      });\n    });\n  });\n\n  describe('factory() wrapping forwardRef (Mantine)', () => {\n    it('extracts component from factory HOC', async () => {\n      const entry = await extract(\n        'Select',\n        dedent`\n          import React from 'react';\n\n          interface FactoryPayload {\n            props: Record<string, any>;\n            ref: HTMLElement;\n          }\n\n          type MantineComponent<Payload extends FactoryPayload> =\n            React.ForwardRefExoticComponent<\n              Payload['props'] & React.RefAttributes<Payload['ref']>\n            >;\n\n          function factory<Payload extends FactoryPayload>(\n            renderFn: (props: Payload['props'], ref: React.Ref<Payload['ref']>) => React.ReactNode\n          ): MantineComponent<Payload> {\n            const Component = React.forwardRef(renderFn as any) as any;\n            return Component;\n          }\n\n          interface SelectProps {\n            /** Currently selected value */\n            value?: string;\n            /** Change handler */\n            onChange?: (value: string | null) => void;\n            /** Dropdown options */\n            data: string[];\n            /** Whether the select is searchable */\n            searchable?: boolean;\n          }\n\n          interface SelectFactory extends FactoryPayload {\n            props: SelectProps;\n            ref: HTMLInputElement;\n          }\n\n          export const Select = factory<SelectFactory>((_props, ref) => {\n            return <input ref={ref} />;\n          });\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        displayName: 'Select',\n        props: {\n          value: { description: 'Currently selected value', required: false },\n          onChange: { description: 'Change handler', required: false },\n          data: { description: 'Dropdown options', required: true },\n          searchable: { description: 'Whether the select is searchable', required: false },\n        },\n      });\n    });\n  });\n\n  describe('standard Storybook fixtures', () => {\n    it('extracts the standard Button fixture', async () => {\n      const entry = await extract(\n        'Button',\n        dedent`\n          import React from 'react';\n          export interface ButtonProps {\n            /** Description of primary */\n            primary?: boolean;\n            backgroundColor?: string;\n            size?: 'small' | 'medium' | 'large';\n            label: string;\n            onClick?: () => void;\n          }\n\n          /**\n           * Primary UI component for user interaction\n           * @import import { Button } from '@design-system/components/override';\n           */\n          export const Button = ({\n            primary = false,\n            size = 'medium',\n            backgroundColor,\n            label,\n            ...props\n          }: ButtonProps) => {\n            const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n            return (\n              <button\n                type=\"button\"\n                className={['storybook-button', \\`storybook-button--\\${size}\\`, mode].join(' ')}\n                style={{ backgroundColor }}\n                {...props}\n              >\n                {label}\n              </button>\n            );\n          };\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        description: 'Primary UI component for user interaction',\n        displayName: 'Button',\n        jsDocTags: { import: [\"import { Button } from '@design-system/components/override';\"] },\n        props: {\n          primary: { description: 'Description of primary', defaultValue: { value: 'false' } },\n          size: { defaultValue: { value: \"'medium'\" } },\n          label: { required: true },\n          onClick: { required: false },\n        },\n      });\n    });\n\n    it('extracts default-exported Header fixture', async () => {\n      const entry = await extract(\n        'default',\n        dedent`\n          import React from 'react';\n\n          interface User { name: string }\n\n          export interface HeaderProps {\n            user?: User;\n            onLogin?: () => void;\n            onLogout?: () => void;\n            onCreateAccount?: () => void;\n          }\n\n          export default ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => (\n            <header>\n              <div>{user?.name}</div>\n            </header>\n          );\n        `\n      );\n\n      expect(entry.component?.reactComponentMeta).toMatchObject({\n        displayName: 'Component',\n        exportName: 'default',\n        props: {\n          user: { parent: { name: 'HeaderProps' }, type: { name: 'User' } },\n          onLogin: { required: false },\n          onLogout: { required: false },\n          onCreateAccount: { required: false },\n        },\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/componentMeta/componentMetaExtractor.test-helpers.ts",
    "content": "import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport { loadCsf } from 'storybook/internal/csf-tools';\n\nimport ts from 'typescript';\n\nimport { findMatchingComponent } from '../generator.ts';\nimport { type StoryRef, getComponents } from '../getComponentImports.ts';\nimport { ComponentMetaProject } from './ComponentMetaProject.ts';\nimport { createTempProject, writeFiles } from './test-helpers.ts';\n\n/**\n * Shared LanguageService across all tests — avoids re-parsing @types/react per test. First\n * getProgram() is ~300ms, subsequent incremental rebuilds are ~5ms.\n */\nconst { projectDir, configPath } = createTempProject({});\nconst fsFileSnapshots = new Map<string, [number | undefined, ts.IScriptSnapshot | undefined]>();\nconst sharedProject = new ComponentMetaProject(\n  ts,\n  ts.parseJsonSourceFileConfigFileContent(\n    ts.readJsonConfigFile(configPath, ts.sys.readFile),\n    ts.sys,\n    projectDir,\n    {},\n    configPath\n  ),\n  configPath,\n  fsFileSnapshots\n);\n\n/** Write files into the shared project, invalidate caches, and run a callback. */\nexport async function withProject<T>(\n  files: Record<string, string>,\n  fn: (project: ComponentMetaProject, filePaths: Record<string, string>) => T | Promise<T>\n): Promise<T> {\n  const filePaths = writeFiles(projectDir, files);\n  for (const fp of Object.values(filePaths)) {\n    fsFileSnapshots.delete(fp);\n  }\n  (sharedProject as any).projectVersion++;\n  return fn(sharedProject, filePaths);\n}\n\n/**\n * Full production flow: loadCsf → getComponents → extractPropsFromStories. Title is auto-derived\n * from the story file name for findMatchingComponent.\n */\nexport async function extractFromStory(\n  files: Record<string, string>,\n  storyFileName: string,\n  options?: { componentName?: string }\n): Promise<StoryRef> {\n  return withProject(files, async (project, filePaths) => {\n    const storyPath = filePaths[storyFileName];\n    const title = path.basename(storyFileName).replace(/\\.stories\\.\\w+$/, '');\n    const csf = loadCsf(fs.readFileSync(storyPath, 'utf-8'), {\n      makeTitle: () => title,\n    }).parse();\n\n    const components = await getComponents({\n      csf,\n      storyFilePath: storyPath,\n      docgenEngine: 'react-component-meta',\n    });\n\n    const componentName = options?.componentName ?? csf._meta?.component;\n    const component = findMatchingComponent(components, componentName, title);\n\n    const entry: StoryRef = { storyPath, component };\n    project.extractPropsFromStories([entry]);\n    return entry;\n  });\n}\n\n/**\n * Convenience wrapper: generates a story with meta.component and extracts props. Goes through the\n * fallback path (resolveFromMetaComponent, no JSX).\n */\nexport async function extract(exportName: string, content: string): Promise<StoryRef> {\n  const componentName = exportName === 'default' ? 'Component' : exportName;\n  const importLine =\n    exportName === 'default'\n      ? `import ${componentName} from './Component';`\n      : `import { ${exportName} as ${componentName} } from './Component';`;\n\n  return extractFromStory(\n    {\n      'test/Component.tsx': content,\n      'test/Component.stories.tsx': `${importLine}\\nexport default { component: ${componentName} };`,\n    },\n    'test/Component.stories.tsx'\n  );\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/componentMeta/componentMetaExtractor.ts",
    "content": "/**\n * Prop extractor — resolves React component props via TypeScript's type checker.\n *\n * Two extraction paths:\n *\n * **Path 1 (primary)**: `resolvePropsFromStoryFile()` — finds JSX elements in an existing story\n * file that match the target component, then calls `checker.getResolvedSignature()` to extract the\n * full props type. Works for ~95% of components (any story with JSX usage).\n *\n * **Path 2 (fallback)**: `resolvePropsFromComponentType()` — for args-only stories with no JSX,\n * inspects the component's type directly via `getCallSignatures()[0].parameters[0]` (similar to\n * Vue's component-meta approach). Does NOT work for polymorphic/generic components (TS #61133).\n *\n * The story path returns the selected component target together with its props type, and the\n * fallback path still resolves the props type directly. `serializeComponentDoc()` uses the selected\n * symbol and component ref from that target so member components keep their own metadata.\n *\n * TypeScript resolves props the same way as autocompletion — by calling\n * `checker.getResolvedSignature()` on the JSX element. For polymorphic components with generic call\n * signatures (e.g. Mantine's polymorphicFactory), TypeScript instantiates the generic with its\n * default type parameter, giving the correct concrete props. This avoids the `ComponentProps<T>` /\n * `infer P` limitation (TS #61133).\n */\nimport type ts from 'typescript';\n\nimport type { ComponentRef, ResolvedComponentTarget } from '../types.ts';\nimport { groupBy } from '../utils.ts';\n\n// ---------------------------------------------------------------------------\n// Output types — compatible with react-docgen-typescript's ComponentDoc shape\n// ---------------------------------------------------------------------------\n\nexport interface PropItemType {\n  name: string;\n  raw?: string;\n  value?: { value: string }[];\n}\n\nexport interface ParentType {\n  name: string;\n  fileName: string;\n}\n\nexport interface PropItem {\n  name: string;\n  required: boolean;\n  type: PropItemType;\n  description: string;\n  defaultValue: { value: string } | null;\n  parent?: ParentType;\n  declarations?: ParentType[];\n}\n\nexport interface ComponentDoc {\n  displayName?: string;\n  exportName: string;\n  filePath: string;\n  description: string;\n  jsDocTags?: Record<string, string[]>;\n  props: Record<string, PropItem>;\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/**\n * Props from a single `.d.ts` or `node_modules` declaration file exceeding this count are\n * bulk-excluded from the manifest. This filters out HTML attribute interfaces (100+ props) and\n * generated CSS-in-JS types (e.g. Panda CSS styled-system) while keeping user-defined props.\n *\n * The threshold is per source file — a user's own interface with 31 props in a `.tsx` file is NOT\n * affected (only `.d.ts` and `node_modules` paths are checked).\n */\nconst LARGE_SOURCE_THRESHOLD = 30;\n\n/** Max recursion depth for unwrapping React.memo/forwardRef/Object.assign chains. */\nconst MAX_UNWRAP_DEPTH = 5;\nconst MAX_SERIALIZATION_DEPTH = 5;\ntype WrappedExpression =\n  | ts.ParenthesizedExpression\n  | ts.AsExpression\n  | ts.NonNullExpression\n  | ts.SatisfiesExpression;\n\nfunction isLiteralType(type: ts.Type): type is ts.LiteralType {\n  return type.isStringLiteral() || type.isNumberLiteral();\n}\n\nfunction isUnionType(type: ts.Type): type is ts.UnionType {\n  return type.isUnion();\n}\n\nfunction isWrappedExpression(\n  typescript: typeof ts,\n  expression: ts.Expression\n): expression is WrappedExpression {\n  return (\n    typescript.isParenthesizedExpression(expression) ||\n    typescript.isAsExpression(expression) ||\n    typescript.isNonNullExpression(expression) ||\n    (typescript.isSatisfiesExpression?.(expression) ?? false)\n  );\n}\n\nfunction resolveAliasedSymbol(\n  typescript: typeof ts,\n  checker: ts.TypeChecker,\n  symbol: ts.Symbol\n): ts.Symbol {\n  return symbol.flags & typescript.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;\n}\n\nfunction getSymbolContextNode(symbol: ts.Symbol): ts.Node | undefined {\n  return symbol.valueDeclaration ?? symbol.getDeclarations()?.[0];\n}\n\nfunction resolveComponentSymbolFromNode(\n  typescript: typeof ts,\n  checker: ts.TypeChecker,\n  node: ts.Node | undefined\n): ts.Symbol | undefined {\n  if (!node) {\n    return undefined;\n  }\n\n  const symbol = checker.getSymbolAtLocation(node);\n  return symbol ? resolveComponentSymbol(typescript, checker, symbol, node) : undefined;\n}\n\n/**\n * Normalizes the symbol we get from JSX/member resolution to the declaration symbol that owns the\n * component metadata.\n *\n * For top-level components, TypeScript usually gives us the declaration symbol directly. For member\n * selections it often gives an intermediate symbol instead, for example:\n *\n * - A shorthand/property symbol from `export const Accordion = { Root }`\n * - An attached-member symbol from `ButtonRoot.Aligner = Aligner`\n * - A property signature from `Aligner: typeof Aligner`\n * - An anonymous function symbol (`__function`) for `const Aligner = () => ...`\n *\n * Those symbols do not reliably carry the selected member's JSDoc/defaults, so we follow them back\n * to the actual component declaration before serialization.\n */\nfunction resolveComponentSymbol(\n  typescript: typeof ts,\n  checker: ts.TypeChecker,\n  symbol: ts.Symbol,\n  contextNode: ts.Node,\n  depth = 0\n): ts.Symbol {\n  let resolved = resolveAliasedSymbol(typescript, checker, symbol);\n  if (depth > MAX_UNWRAP_DEPTH) {\n    return resolved;\n  }\n\n  const declarationForPromotion = getSymbolContextNode(resolved);\n  if (\n    declarationForPromotion &&\n    (typescript.isArrowFunction(declarationForPromotion) ||\n      typescript.isFunctionExpression(declarationForPromotion)) &&\n    declarationForPromotion.parent &&\n    typescript.isVariableDeclaration(declarationForPromotion.parent) &&\n    typescript.isIdentifier(declarationForPromotion.parent.name)\n  ) {\n    const variableSymbol = checker.getSymbolAtLocation(declarationForPromotion.parent.name);\n    if (variableSymbol) {\n      resolved = resolveAliasedSymbol(typescript, checker, variableSymbol);\n    }\n  }\n\n  const declaration = getSymbolContextNode(resolved);\n  if (declaration) {\n    if (typescript.isShorthandPropertyAssignment(declaration)) {\n      const valueSymbol = checker.getShorthandAssignmentValueSymbol(declaration);\n      if (valueSymbol) {\n        return resolveComponentSymbol(\n          typescript,\n          checker,\n          valueSymbol,\n          declaration.name,\n          depth + 1\n        );\n      }\n    }\n\n    if (typescript.isPropertyAssignment(declaration)) {\n      const next = resolveComponentSymbolFromNode(typescript, checker, declaration.initializer);\n      if (next) {\n        return next;\n      }\n    }\n\n    if (\n      typescript.isBinaryExpression(declaration) &&\n      declaration.operatorToken.kind === typescript.SyntaxKind.EqualsToken\n    ) {\n      const next = resolveComponentSymbolFromNode(typescript, checker, declaration.right);\n      if (next) {\n        return next;\n      }\n    }\n  }\n\n  const shouldUseTypeSymbolFallback =\n    Boolean(resolved.flags & typescript.SymbolFlags.Property) ||\n    (declaration !== undefined &&\n      (typescript.isPropertyAssignment(declaration) ||\n        typescript.isShorthandPropertyAssignment(declaration) ||\n        typescript.isPropertySignature(declaration) ||\n        typescript.isPropertyDeclaration(declaration) ||\n        (typescript.isBinaryExpression(declaration) &&\n          declaration.operatorToken.kind === typescript.SyntaxKind.EqualsToken)));\n\n  const typeSymbol =\n    shouldUseTypeSymbolFallback &&\n    checker.getTypeOfSymbolAtLocation(resolved, contextNode).getSymbol?.();\n  if (typeSymbol) {\n    const resolvedTypeSymbol = resolveAliasedSymbol(typescript, checker, typeSymbol);\n    const typeDeclaration = getSymbolContextNode(resolvedTypeSymbol);\n    if (resolvedTypeSymbol !== resolved && typeDeclaration) {\n      return resolveComponentSymbol(\n        typescript,\n        checker,\n        resolvedTypeSymbol,\n        typeDeclaration,\n        depth + 1\n      );\n    }\n  }\n\n  return resolved;\n}\n\n// ---------------------------------------------------------------------------\n// Story-based prop extraction (probe-free)\n// ---------------------------------------------------------------------------\n\n/**\n * Resolves the selected component symbol and props type by finding JSX usage of the target\n * component in a story file.\n *\n * Story files already contain JSX like `<Button />` that TypeScript has resolved. This function\n * walks the story AST to find a JSX element matching the target component and extracts the props\n * type via `getResolvedSignature()` — the same mechanism as autocomplete and the former probe\n * approach.\n *\n * @param importSpecifier - The import specifier as written in the story file (e.g., './Button',\n *   '@mantine/core')\n * @param importName - The export name of the component (e.g., 'Button', 'default')\n * @param memberAccess - For compound components (e.g., 'Root' in `<Accordion.Root />`)\n */\nexport function resolvePropsFromStoryFile(\n  typescript: typeof ts,\n  checker: ts.TypeChecker,\n  storySourceFile: ts.SourceFile,\n  componentRef: ComponentRef\n): ResolvedComponentTarget | undefined {\n  const importSpecifier = componentRef.importId;\n  const importName = componentRef.importName;\n  const memberAccess = componentRef.member;\n  if (!importSpecifier) {\n    return undefined;\n  }\n\n  // Step 1: Find the import binding symbol in the story file.\n  // This is the local symbol that the story uses in JSX (e.g., `Button` from `import { Button } from './Button'`).\n  let importSymbol: ts.Symbol | undefined;\n\n  for (const stmt of storySourceFile.statements) {\n    if (!typescript.isImportDeclaration(stmt)) {\n      continue;\n    }\n    const moduleSpec = stmt.moduleSpecifier;\n    if (!typescript.isStringLiteral(moduleSpec)) {\n      continue;\n    }\n    if (moduleSpec.text !== importSpecifier) {\n      continue;\n    }\n\n    const clause = stmt.importClause;\n    if (!clause) {\n      continue;\n    }\n\n    if (importName === 'default') {\n      // Default import: import Button from '...'\n      if (clause.name) {\n        importSymbol = checker.getSymbolAtLocation(clause.name);\n      }\n      // Also check named imports for `{ default as Button }` pattern\n      if (\n        !importSymbol &&\n        clause.namedBindings &&\n        typescript.isNamedImports(clause.namedBindings)\n      ) {\n        for (const spec of clause.namedBindings.elements) {\n          const originalName = (spec.propertyName ?? spec.name).text;\n          if (originalName === 'default') {\n            importSymbol = checker.getSymbolAtLocation(spec.name);\n            break;\n          }\n        }\n      }\n    } else {\n      // Named import: import { Button } from '...' or import { Button as Btn } from '...'\n      if (clause.namedBindings && typescript.isNamedImports(clause.namedBindings)) {\n        for (const spec of clause.namedBindings.elements) {\n          const originalName = (spec.propertyName ?? spec.name).text;\n          if (originalName === importName) {\n            importSymbol = checker.getSymbolAtLocation(spec.name);\n            break;\n          }\n        }\n      }\n    }\n    // Namespace import: import * as Ns from '...'\n    // Only applies when memberAccess is set (compound components accessed as <Ns.Member />).\n    // Without this guard, a namespace import from the same module could shadow a named\n    // import we're actually looking for (e.g. `import * as X from './m'; import { Y } from './m'`).\n    if (\n      !importSymbol &&\n      memberAccess &&\n      clause.namedBindings &&\n      typescript.isNamespaceImport(clause.namedBindings)\n    ) {\n      importSymbol = checker.getSymbolAtLocation(clause.namedBindings.name);\n    }\n\n    if (importSymbol) {\n      break;\n    }\n  }\n\n  if (!importSymbol) {\n    return undefined;\n  }\n\n  // Step 2: Walk story file to find JSX elements using this import\n  let result: ResolvedComponentTarget | undefined;\n\n  function extractPropsFromJsx(\n    node: ts.JsxSelfClosingElement | ts.JsxOpeningElement\n  ): ts.Type | undefined {\n    const sig = checker.getResolvedSignature(node);\n    if (!sig) {\n      return undefined;\n    }\n    const params = sig.getParameters();\n    if (params.length === 0) {\n      // Component with no props\n      return checker.getTypeFromTypeNode(typescript.factory.createTypeLiteralNode([]));\n    }\n    return checker.getTypeOfSymbolAtLocation(params[0], node);\n  }\n\n  function visit(node: ts.Node) {\n    if (result) {\n      return;\n    }\n\n    if (typescript.isJsxSelfClosingElement(node) || typescript.isJsxOpeningElement(node)) {\n      const tagName = node.tagName;\n\n      if (memberAccess) {\n        // Handle <Accordion.Root /> pattern\n        if (typescript.isPropertyAccessExpression(tagName) && tagName.name.text === memberAccess) {\n          const leftSym = checker.getSymbolAtLocation(tagName.expression);\n          if (leftSym && importSymbol && leftSym === importSymbol) {\n            const propsType = extractPropsFromJsx(node);\n            if (propsType) {\n              const memberSymbol =\n                checker.getSymbolAtLocation(tagName.name) ??\n                checker.getTypeAtLocation(tagName.expression).getProperty(tagName.name.text) ??\n                resolveComponentSymbolFromNode(typescript, checker, tagName);\n              result = {\n                componentRef,\n                propsType,\n                symbol: memberSymbol\n                  ? resolveComponentSymbol(typescript, checker, memberSymbol, tagName.name)\n                  : resolveAliasedSymbol(typescript, checker, importSymbol),\n              };\n              return;\n            }\n          }\n        }\n      } else {\n        // Handle <Button /> pattern\n        if (typescript.isIdentifier(tagName)) {\n          const sym = checker.getSymbolAtLocation(tagName);\n          if (sym && importSymbol && sym === importSymbol) {\n            const propsType = extractPropsFromJsx(node);\n            if (propsType) {\n              result = {\n                componentRef,\n                propsType,\n                symbol: resolveAliasedSymbol(typescript, checker, sym),\n              };\n              return;\n            }\n          }\n        }\n      }\n    }\n\n    typescript.forEachChild(node, visit);\n  }\n\n  visit(storySourceFile);\n  return result;\n}\n\n/**\n * Resolves props type directly from a component's type (Vue component-meta approach).\n *\n * For functional components: `getCallSignatures()[0].parameters[0]` For class components: construct\n * signature → return type → `props` property\n *\n * This is the fallback for args-only stories that have no JSX in the story file. Does NOT work for\n * polymorphic/generic components (TS #61133), which is acceptable since args-only stories for\n * polymorphic components don't exist in practice.\n */\nexport function resolvePropsFromComponentType(\n  typescript: typeof ts,\n  checker: ts.TypeChecker,\n  componentType: ts.Type\n): ts.Type | undefined {\n  // Try call signatures first (functional components — the common case)\n  const callSigs = componentType.getCallSignatures();\n  if (callSigs.length > 0) {\n    const sig = callSigs[0];\n    if (sig.parameters.length === 0) {\n      // No-props component (e.g., () => <div />)\n      // Return void as a sentinel — serializeComponentDocs will serialize as empty props {}\n      return checker.getVoidType();\n    }\n    const propsType = checker.getTypeOfSymbol(sig.parameters[0]);\n    if (!(propsType.flags & typescript.TypeFlags.Any)) {\n      return propsType;\n    }\n  }\n\n  // Try construct signatures (class components)\n  // For `class Button extends React.Component<Props>`, the constructor type has\n  // construct signatures whose return type (the instance) has a `props` property.\n  const ctorSigs = componentType.getConstructSignatures();\n  for (const sig of ctorSigs) {\n    const ret = sig.getReturnType();\n    const propsSym = ret.getProperty('props');\n    if (propsSym) {\n      const propsType = checker.getTypeOfSymbol(propsSym);\n      if (!(propsType.flags & typescript.TypeFlags.Any)) {\n        return propsType;\n      }\n    }\n  }\n\n  return undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Parent / source info per property\n// ---------------------------------------------------------------------------\n\n/**\n * Returns the source file for a property symbol, used by getBulkSourceExclusions to decide whether\n * a prop comes from a \"bulk\" source (node_modules/.d.ts).\n *\n * When a prop has multiple declarations (e.g. user re-declares `aria-label` in their own interface\n * AND it exists in React's HTMLAttributes), we check ALL declarations. If ANY declaration is in\n * user code (not node_modules, not .d.ts), we return that user-code path so the prop is NOT\n * bulk-excluded.\n */\nfunction getPropSourceFile(prop: ts.Symbol): string | undefined {\n  const declarations = prop.getDeclarations();\n  if (!declarations?.length) {\n    return undefined;\n  }\n\n  // If any declaration lives in user code (not node_modules, not .d.ts),\n  // return that source — the prop should not be bulk-excluded.\n  for (const decl of declarations) {\n    const fileName = decl.getSourceFile().fileName;\n    if (!fileName.includes('node_modules') && !fileName.endsWith('.d.ts')) {\n      return fileName;\n    }\n  }\n\n  // All declarations are in node_modules or .d.ts — return the first one.\n  return declarations[0].getSourceFile().fileName;\n}\n\nfunction getParentType(typescript: typeof ts, prop: ts.Symbol): ParentType | undefined {\n  const declarations = prop.getDeclarations();\n  if (!declarations?.length) {\n    return undefined;\n  }\n\n  // Walk up the AST from the property's parent to find the enclosing named type.\n  // Props declared in type literals inside intersections (e.g. `type T = { prop: X } & Base`)\n  // have the chain: PropertySignature → TypeLiteralNode → IntersectionTypeNode → TypeAliasDeclaration\n  let node: ts.Node | undefined = declarations[0].parent;\n  while (node) {\n    if (typescript.isInterfaceDeclaration(node) || typescript.isTypeAliasDeclaration(node)) {\n      return {\n        name: node.name.getText(),\n        fileName: node.getSourceFile().fileName,\n      };\n    }\n    node = node.parent;\n  }\n\n  return undefined;\n}\n\nfunction getAllDeclarationParents(\n  typescript: typeof ts,\n  prop: ts.Symbol\n): ParentType[] | undefined {\n  const declarations = prop.getDeclarations();\n  if (!declarations?.length) {\n    return undefined;\n  }\n\n  const parents: ParentType[] = [];\n\n  for (const declaration of declarations) {\n    const { parent } = declaration;\n    if (!parent) {\n      continue;\n    }\n\n    if (typescript.isInterfaceDeclaration(parent) || typescript.isTypeAliasDeclaration(parent)) {\n      parents.push({\n        name: parent.name.getText(),\n        fileName: parent.getSourceFile().fileName,\n      });\n    } else if (typescript.isTypeLiteralNode(parent)) {\n      parents.push({\n        name: 'TypeLiteral',\n        fileName: parent.getSourceFile().fileName,\n      });\n    }\n  }\n\n  return parents.length > 0 ? parents : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Type serialization\n// ---------------------------------------------------------------------------\n\nfunction serializeType(\n  typescript: typeof ts,\n  checker: ts.TypeChecker,\n  type: ts.Type,\n  isRequired: boolean,\n  depth = 0\n): PropItemType {\n  if (depth > MAX_SERIALIZATION_DEPTH) {\n    return { name: checker.typeToString(type) };\n  }\n\n  if (type.isUnion()) {\n    // Filter undefined from union members before any further processing.\n    // This replaces the fragile `typeString.replace(' | undefined', '')` pattern\n    // which broke for `undefined | string` or multiple `undefined` members.\n    const nonUndefinedTypes = type.types.filter(\n      (t) => !(t.getFlags() & typescript.TypeFlags.Undefined)\n    );\n\n    const literalMembers = nonUndefinedTypes.filter(isLiteralType);\n\n    if (literalMembers.length > 0 && literalMembers.length === nonUndefinedTypes.length) {\n      const rawParts = literalMembers.map((m) => checker.typeToString(m));\n      return {\n        name: 'enum',\n        raw: rawParts.join(' | '),\n        value: literalMembers.map((m) => ({\n          value: JSON.stringify(m.value),\n        })),\n      };\n    }\n\n    // For optional props with a single non-undefined type, serialize that type directly.\n    // This strips the implicit `| undefined` added by strictNullChecks without any string\n    // manipulation, so nested `| undefined` in generics (e.g. `Record<string, number |\n    // undefined>`) is preserved correctly.\n    //\n    // For multi-member unions we don't strip — reconstructing TypeScript's typeToString\n    // behavior (boolean collapsing, parenthesization, ordering) is fragile and error-prone.\n    // The `required: false` field already captures optionality; keeping `| undefined` in\n    // the type name for these rare cases is the safest choice.\n    if (\n      !isRequired &&\n      nonUndefinedTypes.length === 1 &&\n      nonUndefinedTypes.length < type.types.length\n    ) {\n      return { name: checker.typeToString(nonUndefinedTypes[0]) };\n    }\n  }\n\n  const constraint = type.getConstraint?.();\n  if (constraint && constraint !== type) {\n    return serializeType(typescript, checker, constraint, isRequired, depth + 1);\n  }\n\n  return { name: checker.typeToString(type) };\n}\n\n// ---------------------------------------------------------------------------\n// Default value extraction\n// ---------------------------------------------------------------------------\n\n/**\n * Unwraps wrapper calls (React.forwardRef, React.memo, etc.) to find the underlying function\n * expression or declaration.\n */\nfunction unwrapToFunction(\n  typescript: typeof ts,\n  node: ts.Node,\n  depth = 0,\n  checker?: ts.TypeChecker\n): ts.FunctionLikeDeclaration | undefined {\n  if (depth > MAX_UNWRAP_DEPTH) {\n    return undefined;\n  }\n\n  if (\n    typescript.isArrowFunction(node) ||\n    typescript.isFunctionExpression(node) ||\n    typescript.isFunctionDeclaration(node)\n  ) {\n    return node;\n  }\n\n  // Unwrap CallExpression: React.forwardRef(fn), React.memo(fn), etc.\n  if (typescript.isCallExpression(node)) {\n    for (const arg of node.arguments) {\n      const fn = unwrapToFunction(typescript, arg, depth + 1, checker);\n      if (fn) {\n        return fn;\n      }\n    }\n  }\n\n  // Unwrap parenthesized expressions: (fn)\n  if (typescript.isParenthesizedExpression(node)) {\n    return unwrapToFunction(typescript, node.expression, depth + 1, checker);\n  }\n\n  // Unwrap as-expression: fn as SomeType\n  if (typescript.isAsExpression(node)) {\n    return unwrapToFunction(typescript, node.expression, depth + 1, checker);\n  }\n\n  // Follow identifier references when a checker is available.\n  // Handles: Object.assign(StackImpl, ...) where StackImpl = forwardRef(...)\n  if (typescript.isIdentifier(node) && checker) {\n    const symbol = checker.getSymbolAtLocation(node);\n    if (symbol) {\n      const resolved =\n        symbol.flags & typescript.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;\n      const decl = resolved.valueDeclaration;\n      if (decl && typescript.isVariableDeclaration(decl) && decl.initializer) {\n        return unwrapToFunction(typescript, decl.initializer, depth + 1, checker);\n      }\n      if (decl && typescript.isFunctionDeclaration(decl)) {\n        return decl;\n      }\n    }\n  }\n\n  return undefined;\n}\n\n/**\n * Resolves an expression to its literal string representation.\n *\n * For identifiers like `DEFAULT_SIZE` pointing to `const DEFAULT_SIZE = 'md'`, follows the\n * reference chain and returns `'md'` (the literal value). Handles variable declarations, imports,\n * enum members, and property accesses. Falls back to `.getText()` for unresolvable expressions.\n */\nfunction resolveLiteralValue(\n  typescript: typeof ts,\n  checker: ts.TypeChecker,\n  node: ts.Expression,\n  depth = 0\n): string {\n  if (depth > MAX_UNWRAP_DEPTH) {\n    return node.getText();\n  }\n\n  // Direct literals — return source text as-is\n  if (\n    typescript.isStringLiteral(node) ||\n    typescript.isNumericLiteral(node) ||\n    typescript.isNoSubstitutionTemplateLiteral(node) ||\n    node.kind === typescript.SyntaxKind.TrueKeyword ||\n    node.kind === typescript.SyntaxKind.FalseKeyword ||\n    node.kind === typescript.SyntaxKind.NullKeyword\n  ) {\n    return node.getText();\n  }\n\n  // Identifier — follow to declaration\n  if (typescript.isIdentifier(node)) {\n    if (node.text === 'undefined') {\n      return 'undefined';\n    }\n\n    const symbol = checker.getSymbolAtLocation(node);\n    if (!symbol) {\n      return node.getText();\n    }\n\n    const resolved =\n      symbol.flags & typescript.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;\n\n    const decl = resolved.valueDeclaration;\n    if (decl && typescript.isVariableDeclaration(decl) && decl.initializer) {\n      return resolveLiteralValue(typescript, checker, decl.initializer, depth + 1);\n    }\n    if (decl && typescript.isEnumMember(decl) && decl.initializer) {\n      return resolveLiteralValue(typescript, checker, decl.initializer, depth + 1);\n    }\n\n    // BindingElement — sibling destructured parameter: inputLabel = placeholderText\n    // where placeholderText = 'Filter items' is in the same destructuring pattern\n    if (decl && typescript.isBindingElement(decl) && decl.initializer) {\n      return resolveLiteralValue(typescript, checker, decl.initializer, depth + 1);\n    }\n\n    return node.getText();\n  }\n\n  // PropertyAccessExpression — Enum.Value, obj.key\n  if (typescript.isPropertyAccessExpression(node)) {\n    const symbol = checker.getSymbolAtLocation(node);\n    if (symbol) {\n      const decl = symbol.valueDeclaration;\n      if (decl && typescript.isEnumMember(decl) && decl.initializer) {\n        return resolveLiteralValue(typescript, checker, decl.initializer, depth + 1);\n      }\n      if (decl && typescript.isPropertyAssignment(decl) && decl.initializer) {\n        return resolveLiteralValue(typescript, checker, decl.initializer, depth + 1);\n      }\n      if (decl && typescript.isVariableDeclaration(decl) && decl.initializer) {\n        return resolveLiteralValue(typescript, checker, decl.initializer, depth + 1);\n      }\n    }\n    return node.getText();\n  }\n\n  // Fallback — preserve source text for expressions we don't resolve explicitly.\n  return node.getText();\n}\n\n/**\n * Collects default values from an ObjectBindingPattern into the given map.\n *\n * For `{ size = 'md', icon: Icon = DefaultIcon }`, adds: 'size' → \"'md'\", 'icon' → 'DefaultIcon'\n *\n * When a checker is provided, identifiers like `DEFAULT_SIZE` are resolved to their literal values\n * (e.g. `'md'`).\n */\nfunction collectBindingDefaults(\n  typescript: typeof ts,\n  pattern: ts.ObjectBindingPattern,\n  defaults: Map<string, string>,\n  checker?: ts.TypeChecker\n): void {\n  for (const element of pattern.elements) {\n    if (element.initializer) {\n      // Use the property name if renamed (e.g. { icon: Icon = DefaultIcon }),\n      // otherwise use the binding name\n      const propName = element.propertyName\n        ? element.propertyName.getText()\n        : element.name.getText();\n      defaults.set(\n        propName,\n        checker\n          ? resolveLiteralValue(typescript, checker, element.initializer)\n          : element.initializer.getText()\n      );\n    }\n  }\n}\n\nfunction unwrapExpression(typescript: typeof ts, expression: ts.Expression): ts.Expression {\n  let current = expression;\n\n  while (isWrappedExpression(typescript, current)) {\n    current = current.expression;\n  }\n\n  return current;\n}\n\nfunction isPropsIdentifier(\n  typescript: typeof ts,\n  node: ts.Expression,\n  paramName: ts.Identifier,\n  checker?: ts.TypeChecker\n): boolean {\n  if (!typescript.isIdentifier(node)) {\n    return false;\n  }\n\n  if (!checker) {\n    return node.text === paramName.text;\n  }\n\n  const symbol = checker.getSymbolAtLocation(node);\n  const paramSymbol = checker.getSymbolAtLocation(paramName);\n\n  return symbol !== undefined && symbol === paramSymbol;\n}\n\nfunction isPropsDerivedInitializer(\n  typescript: typeof ts,\n  initializer: ts.Expression,\n  paramName: ts.Identifier,\n  checker?: ts.TypeChecker\n): boolean {\n  const expr = unwrapExpression(typescript, initializer);\n\n  if (isPropsIdentifier(typescript, expr, paramName, checker)) {\n    return true;\n  }\n\n  if (typescript.isAwaitExpression(expr)) {\n    return isPropsDerivedInitializer(typescript, expr.expression, paramName, checker);\n  }\n\n  if (\n    typescript.isBinaryExpression(expr) &&\n    [\n      typescript.SyntaxKind.BarBarToken,\n      typescript.SyntaxKind.QuestionQuestionToken,\n      typescript.SyntaxKind.AmpersandAmpersandToken,\n    ].includes(expr.operatorToken.kind)\n  ) {\n    return (\n      isPropsDerivedInitializer(typescript, expr.left, paramName, checker) ||\n      isPropsDerivedInitializer(typescript, expr.right, paramName, checker)\n    );\n  }\n\n  if (typescript.isConditionalExpression(expr)) {\n    return (\n      isPropsDerivedInitializer(typescript, expr.whenTrue, paramName, checker) ||\n      isPropsDerivedInitializer(typescript, expr.whenFalse, paramName, checker)\n    );\n  }\n\n  if (typescript.isCallExpression(expr) || typescript.isNewExpression(expr)) {\n    return (\n      expr.arguments?.some((arg) =>\n        isPropsDerivedInitializer(typescript, arg, paramName, checker)\n      ) ?? false\n    );\n  }\n\n  return false;\n}\n\n/**\n * Extracts destructuring default values from the component function.\n *\n * Handles two patterns:\n *\n * 1. **Parameter destructuring**: `({ size = 'md' }: Props) => ...`\n * 2. **Body destructuring**: `(props) => { const { size = 'md' } = props; ... }` Also handles `const {\n *    size = 'md' } = resolveProps(props, ...)` and similar.\n *\n * Returns Map { 'size' => \"'md'\" }. For class components or non-destructured params, returns an\n * empty map.\n */\nfunction extractDestructuringDefaults(\n  typescript: typeof ts,\n  resolved: ts.Symbol,\n  checker?: ts.TypeChecker\n): Map<string, string> {\n  const defaults = new Map<string, string>();\n  const decl = resolved.valueDeclaration;\n  if (!decl) {\n    return defaults;\n  }\n\n  // Find the function: may be directly a function, or wrapped in forwardRef/memo/etc.\n  let fn: ts.FunctionLikeDeclaration | undefined;\n\n  if (typescript.isFunctionDeclaration(decl)) {\n    fn = decl;\n    // For overloaded functions, valueDeclaration points to the first overload (no body).\n    // Find the implementation signature (the one with a body) to get destructuring defaults.\n    if (!fn.body) {\n      const allDecls = resolved.getDeclarations?.() ?? [];\n      for (const d of allDecls) {\n        if (typescript.isFunctionDeclaration(d) && d.body) {\n          fn = d;\n          break;\n        }\n      }\n    }\n  } else if (typescript.isVariableDeclaration(decl) && decl.initializer) {\n    fn = unwrapToFunction(typescript, decl.initializer, 0, checker);\n  } else if (typescript.isExportAssignment(decl) && decl.expression) {\n    // export default Object.assign(Component, { Sub }), export default forwardRef(...)\n    fn = unwrapToFunction(typescript, decl.expression, 0, checker);\n  }\n\n  if (!fn) {\n    return defaults;\n  }\n\n  // Get the first parameter (props)\n  const firstParam = fn.parameters[0];\n  if (!firstParam) {\n    return defaults;\n  }\n\n  // Case 1: Parameter-level destructuring — ({ size = 'md' }: Props) => ...\n  if (typescript.isObjectBindingPattern(firstParam.name)) {\n    collectBindingDefaults(typescript, firstParam.name, defaults, checker);\n    return defaults;\n  }\n\n  const propsParamName = typescript.isIdentifier(firstParam.name) ? firstParam.name : undefined;\n\n  // Case 2: Body-level destructuring — (props) => { const { size = 'md' } = props; }\n  // Also handles: const { size = 'md' } = resolveProps(props, ...)\n  if (fn.body && propsParamName) {\n    const body = typescript.isBlock(fn.body) ? fn.body : undefined;\n    if (body) {\n      for (const stmt of body.statements) {\n        if (!typescript.isVariableStatement(stmt)) {\n          continue;\n        }\n        for (const varDecl of stmt.declarationList.declarations) {\n          if (\n            typescript.isObjectBindingPattern(varDecl.name) &&\n            varDecl.initializer &&\n            isPropsDerivedInitializer(typescript, varDecl.initializer, propsParamName, checker)\n          ) {\n            collectBindingDefaults(typescript, varDecl.name, defaults, checker);\n          }\n        }\n      }\n    }\n  }\n\n  return defaults;\n}\n\n/**\n * Collects default values from an object literal expression.\n *\n * Used for `defaultProps = { size: 'md', disabled: false }` patterns. Handles PropertyAssignment\n * and ShorthandPropertyAssignment.\n */\nfunction collectObjectLiteralDefaults(\n  typescript: typeof ts,\n  checker: ts.TypeChecker,\n  obj: ts.ObjectLiteralExpression,\n  defaults: Map<string, string>\n): void {\n  for (const prop of obj.properties) {\n    if (typescript.isPropertyAssignment(prop) && prop.name) {\n      const name = prop.name.getText();\n      defaults.set(name, resolveLiteralValue(typescript, checker, prop.initializer));\n    } else if (typescript.isShorthandPropertyAssignment(prop)) {\n      const name = prop.name.getText();\n      const symbol = checker.getShorthandAssignmentValueSymbol(prop);\n      if (\n        symbol?.valueDeclaration &&\n        typescript.isVariableDeclaration(symbol.valueDeclaration) &&\n        symbol.valueDeclaration.initializer\n      ) {\n        defaults.set(\n          name,\n          resolveLiteralValue(typescript, checker, symbol.valueDeclaration.initializer)\n        );\n      } else {\n        defaults.set(name, name);\n      }\n    }\n  }\n}\n\n/**\n * Extracts default values from `Component.defaultProps = {...}` and `static defaultProps = {...}`\n * patterns.\n *\n * This is a legacy React pattern (deprecated in React 19) but still used in many codebases. Lower\n * priority than destructuring defaults.\n */\nfunction extractStaticDefaultProps(\n  typescript: typeof ts,\n  checker: ts.TypeChecker,\n  resolved: ts.Symbol\n): Map<string, string> {\n  const defaults = new Map<string, string>();\n\n  const decl = resolved.valueDeclaration ?? resolved.getDeclarations()?.[0];\n  if (!decl) {\n    return defaults;\n  }\n  const componentSourceFile = decl.getSourceFile();\n\n  for (const stmt of componentSourceFile.statements) {\n    // Pattern 1: Class with static defaultProps = { size: 'md' }\n    if (typescript.isClassDeclaration(stmt) && stmt.name) {\n      const classSymbol = checker.getSymbolAtLocation(stmt.name);\n      if (classSymbol !== resolved) {\n        continue;\n      }\n\n      for (const member of stmt.members) {\n        if (!typescript.isPropertyDeclaration(member)) {\n          continue;\n        }\n        if (!member.name || member.name.getText() !== 'defaultProps') {\n          continue;\n        }\n        if (!member.initializer) {\n          continue;\n        }\n\n        let initializer: ts.Expression = member.initializer;\n        // Follow identifier reference: static defaultProps = myDefaults\n        if (typescript.isIdentifier(initializer)) {\n          const sym = checker.getSymbolAtLocation(initializer);\n          const symDecl = sym?.valueDeclaration;\n          if (symDecl && typescript.isVariableDeclaration(symDecl) && symDecl.initializer) {\n            initializer = symDecl.initializer;\n          }\n        }\n\n        if (typescript.isObjectLiteralExpression(initializer)) {\n          collectObjectLiteralDefaults(typescript, checker, initializer, defaults);\n        }\n      }\n    }\n\n    // Pattern 2: Component.defaultProps = { size: 'md' }\n    if (\n      typescript.isExpressionStatement(stmt) &&\n      typescript.isBinaryExpression(stmt.expression) &&\n      stmt.expression.operatorToken.kind === typescript.SyntaxKind.EqualsToken\n    ) {\n      const left = stmt.expression.left;\n      if (!typescript.isPropertyAccessExpression(left)) {\n        continue;\n      }\n      if (left.name.text !== 'defaultProps') {\n        continue;\n      }\n\n      // Check if the expression target is our component\n      const targetSymbol = checker.getSymbolAtLocation(left.expression);\n      if (!targetSymbol) {\n        continue;\n      }\n\n      const targetResolved =\n        targetSymbol.flags & typescript.SymbolFlags.Alias\n          ? checker.getAliasedSymbol(targetSymbol)\n          : targetSymbol;\n\n      if (targetResolved !== resolved) {\n        continue;\n      }\n\n      let right: ts.Expression = stmt.expression.right;\n      // Follow identifier reference: Button.defaultProps = myDefaults\n      if (typescript.isIdentifier(right)) {\n        const sym = checker.getSymbolAtLocation(right);\n        const symDecl = sym?.valueDeclaration;\n        if (symDecl && typescript.isVariableDeclaration(symDecl) && symDecl.initializer) {\n          right = symDecl.initializer;\n        }\n      }\n\n      if (typescript.isObjectLiteralExpression(right)) {\n        collectObjectLiteralDefaults(typescript, checker, right, defaults);\n      }\n    }\n  }\n\n  return defaults;\n}\n\n/** Extracts a default value from JSDoc @default / @defaultValue tags on a prop's declaration. */\nfunction getJSDocDefault(\n  typescript: typeof ts,\n  prop: ts.Symbol,\n  checker: ts.TypeChecker\n): string | undefined {\n  const tags = prop.getJsDocTags(checker);\n  for (const tag of tags) {\n    if (tag.name === 'default' || tag.name === 'defaultValue') {\n      return typescript.displayPartsToString(tag.text) || undefined;\n    }\n  }\n  return undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Single prop extraction\n// ---------------------------------------------------------------------------\n\nfunction extractPropItem(\n  typescript: typeof ts,\n  checker: ts.TypeChecker,\n  prop: ts.Symbol,\n  contextNode: ts.Node,\n  defaultsMap?: Map<string, string>\n): PropItem {\n  const isOptional = !!(prop.flags & typescript.SymbolFlags.Optional);\n  const isRequired = !isOptional;\n\n  const propType = checker.getTypeOfSymbolAtLocation(prop, contextNode);\n  const type = serializeType(typescript, checker, propType, isRequired);\n\n  const description = typescript.displayPartsToString(prop.getDocumentationComment(checker));\n\n  const parent = getParentType(typescript, prop);\n  const declarations = getAllDeclarationParents(typescript, prop);\n\n  // Default value: prefer destructuring default, then JSDoc @default\n  const propName = prop.getName();\n  const destructuringDefault = defaultsMap?.get(propName);\n  const jsDocDefault = getJSDocDefault(typescript, prop, checker);\n  const defaultStr = destructuringDefault ?? jsDocDefault;\n\n  return {\n    name: propName,\n    required: isRequired,\n    type,\n    description,\n    defaultValue: defaultStr !== undefined ? { value: defaultStr } : null,\n    parent,\n    declarations,\n  };\n}\n\n// ---------------------------------------------------------------------------\n// >30 bulk source filter\n// ---------------------------------------------------------------------------\n\n/**\n * Identifies properties from declaration files or node_modules interfaces with more than\n * LARGE_SOURCE_THRESHOLD properties (e.g. HTMLAttributes, Panda CSS styled-system types). These are\n * filtered to keep the manifest focused on user-defined props.\n *\n * Checks both `node_modules` paths AND `.d.ts` files. The `.d.ts` check catches generated type\n * systems like Panda CSS's `styled-system/` that live outside node_modules but still inject\n * hundreds of CSS properties. Project-local `.d.ts` with fewer than 30 props per file are\n * unaffected.\n */\nfunction getBulkSourceExclusions(properties: ts.Symbol[]): Set<string> {\n  // Cache getPropSourceFile results — avoids walking declarations twice per prop.\n  const propSourceCache = new Map<ts.Symbol, string | undefined>();\n  const getSource = (prop: ts.Symbol) => {\n    let cached = propSourceCache.get(prop);\n    if (cached === undefined && !propSourceCache.has(prop)) {\n      cached = getPropSourceFile(prop);\n      propSourceCache.set(prop, cached);\n    }\n    return cached;\n  };\n\n  const sourceCount = new Map<string, number>();\n\n  for (const prop of properties) {\n    const source = getSource(prop);\n    if (source && (source.includes('node_modules') || source.endsWith('.d.ts'))) {\n      sourceCount.set(source, (sourceCount.get(source) ?? 0) + 1);\n    }\n  }\n\n  const bulkSources = new Set(\n    [...sourceCount.entries()]\n      .filter(([, count]) => count > LARGE_SOURCE_THRESHOLD)\n      .map(([source]) => source)\n  );\n\n  const excluded = new Set<string>();\n  for (const prop of properties) {\n    const source = getSource(prop);\n    if (source && bulkSources.has(source)) {\n      excluded.add(prop.getName());\n    }\n  }\n\n  return excluded;\n}\n\n// ---------------------------------------------------------------------------\n// Display name computation\n// ---------------------------------------------------------------------------\n\nfunction computeDisplayName({\n  exportSymbol,\n  resolvedSymbol,\n}: {\n  exportSymbol?: ts.Symbol;\n  resolvedSymbol: ts.Symbol;\n}): string | undefined {\n  const resolvedName = resolvedSymbol.getName();\n\n  if (!exportSymbol) {\n    if (resolvedName && resolvedName !== 'default' && resolvedName !== '__function') {\n      return resolvedName;\n    }\n    return undefined;\n  }\n\n  const exportName = exportSymbol.getName();\n\n  if (exportName === 'default') {\n    if (resolvedName && resolvedName !== 'default' && resolvedName !== '__function') {\n      return resolvedName;\n    }\n    return undefined;\n  }\n\n  return exportName;\n}\n\nfunction extractComponentJsDocTags(\n  typescript: typeof ts,\n  checker: ts.TypeChecker,\n  symbol: ts.Symbol\n): Record<string, string[]> | undefined {\n  const tags = symbol.getJsDocTags(checker);\n  if (tags.length === 0) {\n    return undefined;\n  }\n\n  const groupedTags = groupBy(tags, (tag) => tag.name);\n  return Object.fromEntries(\n    Object.entries(groupedTags).map(([name, grouped]) => [\n      name,\n      (grouped ?? []).map((tag) => typescript.displayPartsToString(tag.text ?? []).trim()),\n    ])\n  );\n}\n\n// ---------------------------------------------------------------------------\n// Props type → ComponentDoc serialization\n// ---------------------------------------------------------------------------\n\n/**\n * Serializes one resolved component target into ComponentDoc format.\n *\n * Used by `ComponentMetaProject` to convert the output of JSX/meta resolution into the final\n * serialized format for a single story/component pair.\n */\nexport function serializeComponentDoc(\n  typescript: typeof ts,\n  checker: ts.TypeChecker,\n  {\n    sourceFile,\n    resolvedComponent,\n    defaultsSourcePath,\n  }: {\n    sourceFile: ts.SourceFile;\n    resolvedComponent: ResolvedComponentTarget;\n    defaultsSourcePath?: string;\n  }\n): ComponentDoc | undefined {\n  const { componentRef, propsType, symbol } = resolvedComponent;\n  const exportName = componentRef.importName;\n  if (!exportName) {\n    return undefined;\n  }\n  const displayNameOverride = componentRef.componentName;\n  const isMemberSelection = Boolean(componentRef.member);\n  const filePath = componentRef.path ?? sourceFile.fileName;\n  const resolved = resolveAliasedSymbol(typescript, checker, symbol);\n\n  const contextNode = resolved.valueDeclaration ?? resolved.getDeclarations()?.[0];\n  if (!contextNode) {\n    return undefined;\n  }\n\n  const moduleSymbol = checker.getSymbolAtLocation(sourceFile);\n  const exportSymbol = moduleSymbol\n    ? checker\n        .getExportsOfModule(moduleSymbol)\n        .find((candidate) => candidate.getName() === exportName)\n    : undefined;\n\n  // getApparentProperties() on a union type only returns common members.\n  // For discriminated unions (e.g. Reshaped Slider: ControlledProps | UncontrolledProps),\n  // variant-specific props like `value`, `defaultValue` would be lost.\n  // Collect all properties across all union members, deduplicating by name.\n  // When deduplicating, prefer symbols with real types (e.g. `value: number` over\n  // `value?: never` which resolves to `undefined`). Props that are degraded or\n  // optional in any variant are force-optional since the caller doesn't always need them.\n  let allProperties: ts.Symbol[];\n  let unionForceOptional: Set<string> | undefined;\n  if (isUnionType(propsType)) {\n    const seen = new Map<string, ts.Symbol>();\n    const forceOptional = new Set<string>();\n    const unionMembers = propsType.types;\n\n    const allMemberPropSets: Set<string>[] = [];\n    for (const member of unionMembers) {\n      const memberPropNames = new Set<string>();\n      for (const prop of member.getApparentProperties()) {\n        const name = prop.getName();\n        memberPropNames.add(name);\n\n        const propType = checker.getTypeOfSymbolAtLocation(prop, contextNode);\n        const isOptional = !!(prop.flags & typescript.SymbolFlags.Optional);\n        // `value?: never` resolves to type `undefined` (Never + Optional → Undefined).\n        // Detect these \"degraded\" props so we can prefer the real variant.\n        const isDegraded =\n          !!(propType.getFlags() & typescript.TypeFlags.Never) ||\n          !!(propType.getFlags() & typescript.TypeFlags.Undefined);\n\n        // Props with degraded type or optional in any variant → force optional\n        if (isOptional || isDegraded) {\n          forceOptional.add(name);\n        }\n\n        const existing = seen.get(name);\n        if (!existing) {\n          seen.set(name, prop);\n        } else if (!isDegraded) {\n          // Replace if existing is degraded but this one isn't\n          const existingType = checker.getTypeOfSymbolAtLocation(existing, contextNode);\n          const existingIsDegraded =\n            !!(existingType.getFlags() & typescript.TypeFlags.Never) ||\n            !!(existingType.getFlags() & typescript.TypeFlags.Undefined);\n          if (existingIsDegraded) {\n            seen.set(name, prop);\n          }\n        }\n      }\n      allMemberPropSets.push(memberPropNames);\n    }\n\n    // Props not present in ALL union members → force optional.\n    // A prop that exists in variant B but not variant A must be optional\n    // since the caller may pass variant A which doesn't have it.\n    for (const name of seen.keys()) {\n      if (!allMemberPropSets.every((s) => s.has(name))) {\n        forceOptional.add(name);\n      }\n    }\n\n    allProperties = Array.from(seen.values());\n    unionForceOptional = forceOptional;\n  } else {\n    allProperties = propsType.getApparentProperties();\n  }\n  const excluded = getBulkSourceExclusions(allProperties);\n\n  // Collect defaults: destructuring > defaultProps > JSDoc (in extractPropItem)\n  const defaultsMap = extractDestructuringDefaults(typescript, resolved, checker);\n\n  // Fallback: when the symbol resolves to a .d.ts file (e.g. package imports in\n  // monorepos), .d.ts declarations have no function bodies so extractDestructuringDefaults\n  // returns empty. Use the original source file for AST-only defaults extraction.\n  if (defaultsMap.size === 0 && defaultsSourcePath) {\n    const fallbackDefaults = extractDefaultsFromSourceFile(typescript, defaultsSourcePath, {\n      exportName,\n      localName: resolved.getName(),\n      preferLocalName: isMemberSelection,\n    });\n    for (const [key, value] of fallbackDefaults) {\n      defaultsMap.set(key, value);\n    }\n  }\n\n  // Also check for defaultProps pattern (legacy, deprecated in React 19)\n  const staticDefaults = extractStaticDefaultProps(typescript, checker, resolved);\n  for (const [key, value] of staticDefaults) {\n    if (!defaultsMap.has(key)) {\n      defaultsMap.set(key, value);\n    }\n  }\n\n  const props: Record<string, PropItem> = {};\n  for (const prop of allProperties) {\n    if (excluded.has(prop.getName())) {\n      continue;\n    }\n    const item = extractPropItem(typescript, checker, prop, contextNode, defaultsMap);\n    if (unionForceOptional?.has(prop.getName())) {\n      item.required = false;\n    }\n    props[prop.getName()] = item;\n  }\n\n  const displayName =\n    (isMemberSelection ? displayNameOverride : undefined) ??\n    computeDisplayName({\n      exportSymbol,\n      resolvedSymbol: resolved,\n    }) ??\n    displayNameOverride;\n\n  const description = typescript.displayPartsToString(resolved.getDocumentationComment(checker));\n  const selectedJsDocTags = extractComponentJsDocTags(typescript, checker, resolved);\n  const exportResolved =\n    exportSymbol && exportSymbol !== resolved\n      ? resolveAliasedSymbol(typescript, checker, exportSymbol)\n      : undefined;\n  const exportJsDocTags = exportResolved\n    ? extractComponentJsDocTags(typescript, checker, exportResolved)\n    : undefined;\n  const jsDocTags =\n    selectedJsDocTags?.import || !exportJsDocTags?.import\n      ? selectedJsDocTags\n      : {\n          ...(selectedJsDocTags ?? {}),\n          import: exportJsDocTags.import,\n        };\n\n  return {\n    displayName,\n    exportName,\n    filePath,\n    description,\n    jsDocTags,\n    props,\n  };\n}\n\n// ---------------------------------------------------------------------------\n// AST-only defaults extraction from source files\n// ---------------------------------------------------------------------------\n\n/**\n * Extracts destructuring defaults from a source file using pure AST walking.\n *\n * Used as a fallback when the primary file is a `.d.ts` (e.g. package imports in monorepos) where\n * function bodies are stripped. Reads the original source file, finds the exported function\n * matching `exportName`, and collects defaults from its parameter destructuring.\n *\n * Works without a TypeChecker — only string literal, numeric, boolean, null, and undefined defaults\n * are extracted. Identifier references (e.g. `noop`, `DEFAULT_SIZE`) are included as-is.\n */\nfunction extractDefaultsFromSourceFile(\n  typescript: typeof ts,\n  filePath: string,\n  {\n    exportName,\n    localName,\n    preferLocalName = false,\n  }: {\n    exportName: string;\n    localName?: string;\n    preferLocalName?: boolean;\n  }\n): Map<string, string> {\n  const defaults = new Map<string, string>();\n\n  const content = typescript.sys.readFile(filePath);\n  if (!content) {\n    return defaults;\n  }\n\n  const sf = typescript.createSourceFile(\n    filePath,\n    content,\n    typescript.ScriptTarget.Latest,\n    /* setParentNodes */ true\n  );\n\n  // Build a map of top-level variable names → initializer nodes.\n  // This lets us follow references like: export const Stack = Object.assign(StackImpl, ...)\n  // where StackImpl is defined as: const StackImpl = forwardRef(...)\n  const varMap = new Map<string, ts.Expression | ts.FunctionDeclaration>();\n  for (const stmt of sf.statements) {\n    if (typescript.isVariableStatement(stmt)) {\n      for (const decl of stmt.declarationList.declarations) {\n        if (typescript.isIdentifier(decl.name) && decl.initializer) {\n          varMap.set(decl.name.text, decl.initializer);\n        }\n      }\n    }\n    if (typescript.isFunctionDeclaration(stmt) && stmt.name) {\n      varMap.set(stmt.name.text, stmt);\n    }\n  }\n\n  // Find the target: the function associated with the exported symbol.\n  // For \"default\" export, look at export default ... or export { X as default }.\n  // For named exports, look at export const X = ... or export { X }.\n  const fn = preferLocalName\n    ? (findLocalFunction(typescript, sf, localName, varMap) ??\n      findExportedFunction(typescript, sf, exportName, varMap))\n    : (findExportedFunction(typescript, sf, exportName, varMap) ??\n      findLocalFunction(typescript, sf, localName, varMap));\n  if (!fn) {\n    return defaults;\n  }\n\n  // Extract destructuring defaults from the first parameter\n  const firstParam = fn.parameters[0];\n  if (!firstParam) {\n    return defaults;\n  }\n\n  if (typescript.isObjectBindingPattern(firstParam.name)) {\n    collectBindingDefaults(typescript, firstParam.name, defaults);\n  } else if (fn.body) {\n    const propsParamName = typescript.isIdentifier(firstParam.name) ? firstParam.name : undefined;\n\n    // Body destructuring: (props) => { const { x = 1 } = props; }\n    const body = typescript.isBlock(fn.body) ? fn.body : undefined;\n    if (body && propsParamName) {\n      for (const stmt of body.statements) {\n        if (!typescript.isVariableStatement(stmt)) {\n          continue;\n        }\n        for (const varDecl of stmt.declarationList.declarations) {\n          if (\n            typescript.isObjectBindingPattern(varDecl.name) &&\n            varDecl.initializer &&\n            isPropsDerivedInitializer(typescript, varDecl.initializer, propsParamName)\n          ) {\n            collectBindingDefaults(typescript, varDecl.name, defaults);\n          }\n        }\n      }\n    }\n  }\n\n  return defaults;\n}\n\nfunction findLocalFunction(\n  typescript: typeof ts,\n  sf: ts.SourceFile,\n  localName: string | undefined,\n  varMap: Map<string, ts.Expression | ts.FunctionDeclaration>\n): ts.FunctionLikeDeclaration | undefined {\n  if (!localName) {\n    return undefined;\n  }\n\n  const targetExpr = varMap.get(localName);\n  if (!targetExpr) {\n    return undefined;\n  }\n\n  return unwrapToFunctionAST(typescript, targetExpr, varMap, 0);\n}\n\n/**\n * Finds the function-like declaration for a given export name in the source file. Pure AST —\n * follows Object.assign, forwardRef, memo, as-casts, and identifier refs.\n */\nfunction findExportedFunction(\n  typescript: typeof ts,\n  sf: ts.SourceFile,\n  exportName: string,\n  varMap: Map<string, ts.Expression | ts.FunctionDeclaration>\n): ts.FunctionLikeDeclaration | undefined {\n  let targetExpr: ts.Node | undefined;\n\n  for (const stmt of sf.statements) {\n    // export default X\n    if (exportName === 'default' && typescript.isExportAssignment(stmt) && !stmt.isExportEquals) {\n      targetExpr = stmt.expression;\n      break;\n    }\n\n    // export const X = ... or export function X\n    if (typescript.isVariableStatement(stmt) && hasExportModifier(typescript, stmt)) {\n      for (const decl of stmt.declarationList.declarations) {\n        if (\n          typescript.isIdentifier(decl.name) &&\n          decl.name.text === exportName &&\n          decl.initializer\n        ) {\n          targetExpr = decl.initializer;\n          break;\n        }\n      }\n      if (targetExpr) {\n        break;\n      }\n    }\n\n    if (\n      typescript.isFunctionDeclaration(stmt) &&\n      hasExportModifier(typescript, stmt) &&\n      stmt.name?.text === exportName\n    ) {\n      // Find implementation (not overload) for overloaded functions\n      return findFunctionImpl(typescript, sf, stmt.name.text) ?? stmt;\n    }\n\n    // export { StackImpl as Stack } or export { X }\n    if (\n      typescript.isExportDeclaration(stmt) &&\n      stmt.exportClause &&\n      typescript.isNamedExports(stmt.exportClause)\n    ) {\n      for (const spec of stmt.exportClause.elements) {\n        const exported = spec.name.text;\n        const local = spec.propertyName ? spec.propertyName.text : spec.name.text;\n        if (exported === exportName) {\n          targetExpr = varMap.get(local);\n          break;\n        }\n      }\n      if (targetExpr) {\n        break;\n      }\n    }\n  }\n\n  if (!targetExpr) {\n    // Not explicitly exported — might be via barrel: import { X } from './...'\n    // Try to find a top-level variable matching the export name\n    targetExpr = varMap.get(exportName);\n  }\n\n  if (!targetExpr) {\n    return undefined;\n  }\n\n  return unwrapToFunctionAST(typescript, targetExpr, varMap, 0);\n}\n\n/**\n * Pure AST version of unwrapToFunction. Follows forwardRef, memo, Object.assign, as-casts,\n * parenthesized expressions, and identifier references via varMap.\n */\nfunction unwrapToFunctionAST(\n  typescript: typeof ts,\n  node: ts.Node,\n  varMap: Map<string, ts.Expression | ts.FunctionDeclaration>,\n  depth: number\n): ts.FunctionLikeDeclaration | undefined {\n  if (depth > MAX_UNWRAP_DEPTH) {\n    return undefined;\n  }\n\n  // Already a function\n  if (typescript.isFunctionExpression(node) || typescript.isArrowFunction(node)) {\n    return node;\n  }\n  if (typescript.isFunctionDeclaration(node)) {\n    return node;\n  }\n\n  // Parenthesized: (expr)\n  if (typescript.isParenthesizedExpression(node)) {\n    return unwrapToFunctionAST(typescript, node.expression, varMap, depth + 1);\n  }\n\n  // As-expression: expr as Type\n  if (typescript.isAsExpression(node)) {\n    return unwrapToFunctionAST(typescript, node.expression, varMap, depth + 1);\n  }\n\n  // Type assertion: <Type>expr\n  if (typescript.isTypeAssertionExpression && typescript.isTypeAssertionExpression(node)) {\n    return unwrapToFunctionAST(typescript, node.expression, varMap, depth + 1);\n  }\n\n  // Call expression: forwardRef(...), memo(...), Object.assign(X, ...)\n  if (typescript.isCallExpression(node)) {\n    const callee = node.expression;\n    // Object.assign(Component, { Sub }) — first arg is the component\n    if (\n      typescript.isPropertyAccessExpression(callee) &&\n      typescript.isIdentifier(callee.expression) &&\n      callee.expression.text === 'Object' &&\n      callee.name.text === 'assign' &&\n      node.arguments.length >= 1\n    ) {\n      return unwrapToFunctionAST(typescript, node.arguments[0], varMap, depth + 1);\n    }\n\n    // forwardRef(...), memo(...) — first arg is the function\n    if (node.arguments.length >= 1) {\n      return unwrapToFunctionAST(typescript, node.arguments[0], varMap, depth + 1);\n    }\n  }\n\n  // Identifier: follow to its declaration via varMap\n  if (typescript.isIdentifier(node)) {\n    const init = varMap.get(node.text);\n    if (init) {\n      return unwrapToFunctionAST(typescript, init, varMap, depth + 1);\n    }\n  }\n\n  return undefined;\n}\n\n/** Finds the implementation body for an overloaded function declaration. */\nfunction findFunctionImpl(\n  typescript: typeof ts,\n  sf: ts.SourceFile,\n  name: string\n): ts.FunctionDeclaration | undefined {\n  for (const stmt of sf.statements) {\n    if (typescript.isFunctionDeclaration(stmt) && stmt.name?.text === name && stmt.body) {\n      return stmt;\n    }\n  }\n  return undefined;\n}\n\n/** Check if a statement has the `export` modifier. */\nfunction hasExportModifier(typescript: typeof ts, node: ts.Statement): boolean {\n  return (\n    typescript.canHaveModifiers(node) &&\n    typescript.getModifiers(node)?.some((m) => m.kind === typescript.SyntaxKind.ExportKeyword) ===\n      true\n  );\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/componentMeta/test-helpers.ts",
    "content": "import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\n\n/** Resolve the real node_modules directory (may be hoisted to the workspace root). */\nconst NODE_MODULES_DIR = path.resolve(require.resolve('react/package.json'), '../..');\n\n/** Copy the minimal node_modules packages TypeScript needs for React type resolution. */\nfunction copyNodeModules(projectDir: string): void {\n  const dest = path.join(projectDir, 'node_modules');\n  const typesSrc = path.join(NODE_MODULES_DIR, '@types');\n\n  fs.mkdirSync(path.join(dest, '@types'), { recursive: true });\n\n  for (const pkg of ['react', 'csstype']) {\n    fs.cpSync(path.join(NODE_MODULES_DIR, pkg), path.join(dest, pkg), {\n      recursive: true,\n      dereference: true,\n    });\n  }\n\n  for (const pkg of ['react', 'prop-types']) {\n    fs.cpSync(path.join(typesSrc, pkg), path.join(dest, '@types', pkg), {\n      recursive: true,\n      dereference: true,\n    });\n  }\n}\n\n/** Write files into `baseDir`, creating nested directories as needed. Returns absolute paths. */\nexport function writeFiles(baseDir: string, files: Record<string, string>): Record<string, string> {\n  const filePaths: Record<string, string> = {};\n  for (const [name, content] of Object.entries(files)) {\n    const filePath = path.join(baseDir, name);\n    fs.mkdirSync(path.dirname(filePath), { recursive: true });\n    fs.writeFileSync(filePath, content);\n    filePaths[name] = filePath;\n  }\n  return filePaths;\n}\n\n/** Create a temp directory in os.tmpdir() with node_modules copied in. */\nexport function createTempDir(prefix = 'meta-test'): string {\n  const dir = path.join(\n    os.tmpdir(),\n    `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}`\n  );\n  fs.mkdirSync(dir, { recursive: true });\n  copyNodeModules(dir);\n  return dir;\n}\n\nconst DEFAULT_TSCONFIG = {\n  compilerOptions: {\n    target: 'ES2020',\n    module: 'ESNext',\n    jsx: 'react-jsx',\n    strict: true,\n    esModuleInterop: true,\n    moduleResolution: 'bundler',\n  },\n  include: ['./**/*.ts', './**/*.tsx'],\n};\n\n/**\n * Creates a temp project directory with node_modules, a tsconfig.json, and the given source files\n * written to disk.\n */\nexport function createTempProject(\n  files: Record<string, string>,\n  tsconfig: object = DEFAULT_TSCONFIG\n): {\n  projectDir: string;\n  configPath: string;\n  filePaths: Record<string, string>;\n} {\n  const projectDir = createTempDir('prop-ls-test');\n  const configPath = path.join(projectDir, 'tsconfig.json');\n  fs.writeFileSync(configPath, JSON.stringify(tsconfig, null, 2));\n  const filePaths = writeFiles(projectDir, files);\n  return { projectDir, configPath, filePaths };\n}\n\n/** Serialize a tsconfig to JSON, optionally merging overrides into `DEFAULT_TSCONFIG`. */\nexport function tsconfigJSON(overrides: Record<string, unknown> = {}): string {\n  return JSON.stringify({ ...DEFAULT_TSCONFIG, ...overrides });\n}\n\n/** Best-effort cleanup of a temp directory. */\nexport function cleanup(dir: string): void {\n  try {\n    fs.rmSync(dir, { recursive: true, force: true });\n  } catch {\n    // best-effort cleanup\n  }\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/fixtures.ts",
    "content": "import { Tag } from 'storybook/internal/core-server';\nimport type { IndexEntry } from 'storybook/internal/types';\n\nimport { dedent } from 'ts-dedent';\n\nexport const fsMocks = {\n  ['./package.json']: JSON.stringify({ name: 'some-package' }),\n  ['./src/stories/Button.stories.ts']: dedent`\n        import type { Meta, StoryObj } from '@storybook/react';\n        import { fn } from 'storybook/test';\n        import { Button } from './Button';\n        \n        const meta = {\n          title: 'Example/Button',\n          component: Button,\n          args: { onClick: fn() },\n        } satisfies Meta<typeof Button>;\n        export default meta;\n        type Story = StoryObj<typeof meta>;\n        \n        export const Primary: Story = { args: { primary: true,  label: 'Button' } };\n        export const Secondary: Story = { args: { label: 'Button' } };\n        export const Large: Story = { args: { size: 'large', label: 'Button' } };\n        export const Small: Story = { args: { size: 'small', label: 'Button' } };`,\n  ['./src/stories/Button.tsx']: dedent`\n        import React from 'react';\n        export interface ButtonProps {\n          /** Description of primary */\n          primary?: boolean;\n          backgroundColor?: string;\n          size?: 'small' | 'medium' | 'large';\n          label: string;\n          onClick?: () => void;\n        }\n        \n        /** \n         * Primary UI component for user interaction\n         * @import import { Button } from '@design-system/components/override';\n         */\n        export const Button = ({\n          primary = false,\n          size = 'medium',\n          backgroundColor,\n          label,\n          ...props\n        }: ButtonProps) => {\n          const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n          return (\n            <button\n              type=\"button\"\n              className={['storybook-button', \\`storybook-button--\\${size}\\`, mode].join(' ')}\n              style={{ backgroundColor }}\n              {...props}\n            >\n              {label}\n            </button>\n          );\n        };`,\n  ['./src/stories/Header.stories.ts']: dedent`\n        import type { Meta, StoryObj } from '@storybook/react';\n        import { fn } from 'storybook/test';\n        import Header from './Header';\n        \n        /** \n          * Description from meta and very long.\n          * @summary Component summary\n          */\n        const meta = {\n          title: 'Example/Header',\n          component: Header,\n          args: {\n            onLogin: fn(),\n            onLogout: fn(),\n            onCreateAccount: fn(),\n          }\n        } satisfies Meta<typeof Header>;\n        export default meta;\n        type Story = StoryObj<typeof meta>;\n        export const LoggedIn: Story = { args: { user: { name: 'Jane Doe' } } };\n        export const LoggedOut: Story = {};\n        `,\n  ['./src/stories/Header.tsx']: dedent`\n        import { Button } from './Button';\n        \n        export interface HeaderProps {\n          user?: User;\n          onLogin?: () => void;\n          onLogout?: () => void;\n          onCreateAccount?: () => void;\n        }\n        \n        export default ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => (\n          <header>\n            <div className=\"storybook-header\">\n              <div>\n                {user ? (\n                  <>\n                    <span className=\"welcome\">\n                      Welcome, <b>{user.name}</b>!\n                    </span>\n                    <Button size=\"small\" onClick={onLogout} label=\"Log out\" />\n                  </>\n                ) : (\n                  <>\n                    <Button size=\"small\" onClick={onLogin} label=\"Log in\" />\n                    <Button primary size=\"small\" onClick={onCreateAccount} label=\"Sign up\" />\n                  </>\n                )}\n              </div>\n            </div>\n          </header>\n      );`,\n};\n\nexport const indexJson = {\n  v: 5,\n  entries: {\n    'example-button--primary': {\n      type: 'story',\n      subtype: 'story',\n      id: 'example-button--primary',\n      name: 'Primary',\n      title: 'Example/Button',\n      importPath: './src/stories/Button.stories.ts',\n      componentPath: './src/stories/Button.tsx',\n      tags: [Tag.DEV, Tag.TEST, 'vitest', Tag.AUTODOCS, Tag.MANIFEST],\n      exportName: 'Primary',\n    },\n    'example-button--secondary': {\n      type: 'story',\n      subtype: 'story',\n      id: 'example-button--secondary',\n      name: 'Secondary',\n      title: 'Example/Button',\n      importPath: './src/stories/Button.stories.ts',\n      componentPath: './src/stories/Button.tsx',\n      tags: [Tag.DEV, Tag.TEST, 'vitest', Tag.AUTODOCS, Tag.MANIFEST],\n      exportName: 'Secondary',\n    },\n    'example-button--large': {\n      type: 'story',\n      subtype: 'story',\n      id: 'example-button--large',\n      name: 'Large',\n      title: 'Example/Button',\n      importPath: './src/stories/Button.stories.ts',\n      componentPath: './src/stories/Button.tsx',\n      tags: [Tag.DEV, Tag.TEST, 'vitest', Tag.AUTODOCS, Tag.MANIFEST],\n      exportName: 'Large',\n    },\n    'example-button--small': {\n      type: 'story',\n      subtype: 'story',\n      id: 'example-button--small',\n      name: 'Small',\n      title: 'Example/Button',\n      importPath: './src/stories/Button.stories.ts',\n      componentPath: './src/stories/Button.tsx',\n      tags: [Tag.DEV, Tag.TEST, 'vitest', Tag.AUTODOCS, Tag.MANIFEST],\n      exportName: 'Small',\n    },\n    'example-header--docs': {\n      id: 'example-header--docs',\n      title: 'Example/Header',\n      name: 'Docs',\n      importPath: './src/stories/Header.stories.ts',\n      type: 'docs',\n      tags: [Tag.DEV, Tag.TEST, 'vitest', Tag.AUTODOCS],\n      storiesImports: [],\n    },\n    'example-header--logged-in': {\n      type: 'story',\n      subtype: 'story',\n      id: 'example-header--logged-in',\n      name: 'Logged In',\n      title: 'Example/Header',\n      importPath: './src/stories/Header.stories.ts',\n      componentPath: './src/stories/Header.tsx',\n      tags: [Tag.DEV, Tag.TEST, 'vitest', Tag.AUTODOCS, Tag.MANIFEST],\n      exportName: 'LoggedIn',\n    },\n    'example-header--logged-out': {\n      type: 'story',\n      subtype: 'story',\n      id: 'example-header--logged-out',\n      name: 'Logged Out',\n      title: 'Example/Header',\n      importPath: './src/stories/Header.stories.ts',\n      componentPath: './src/stories/Header.tsx',\n      tags: [Tag.DEV, Tag.TEST, 'vitest', Tag.AUTODOCS, Tag.MANIFEST],\n      exportName: 'LoggedOut',\n    },\n  },\n} satisfies { v: number; entries: Record<string, IndexEntry> };\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/generateCodeSnippet.test.tsx",
    "content": "import { expect, test } from 'vitest';\n\nimport { recast, types as t } from 'storybook/internal/babel';\nimport { loadCsf } from 'storybook/internal/csf-tools';\n\nimport { dedent } from 'ts-dedent';\n\nimport { getCodeSnippet } from './generateCodeSnippet.ts';\n\nfunction generateExample(code: string) {\n  const csf = loadCsf(code, { makeTitle: (userTitle?: string) => userTitle ?? 'title' }).parse();\n\n  const snippets = Object.keys(csf._storyExports)\n    .map((name) => getCodeSnippet(csf, name, csf._meta?.component ?? 'ComponentTitle'))\n    .filter(Boolean);\n\n  return recast.print(t.program(snippets)).code;\n}\n\nfunction withCSF3(body: string) {\n  return dedent`\n    import type { Meta } from '@storybook/react';\n    import { Button } from '@design-system/button';\n\n    const meta: Meta<typeof Button> = {\n      component: Button,\n      args: {\n        children: 'Click me'\n      }\n    };\n    export default meta;\n\n    ${body}\n  `;\n}\n\nfunction withCSF4(body: string) {\n  return dedent`\n    import preview from './preview';\n    import { Button } from '@design-system/button';\n    \n    const meta = preview.meta({\n      component: Button,\n      args: {\n        children: 'Click me'\n      }\n    });\n    \n    ${body}\n  `;\n}\n\ntest('Default', () => {\n  const input = withCSF3(`\n    export const Default: Story = {};\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const Default = () => <Button>Click me</Button>;\"`\n  );\n});\n\ntest('Synthesizes self-closing when no children', () => {\n  const input = dedent`\n    import type { Meta } from '@storybook/react';\n    import { Button } from '@design-system/button';\n\n    const meta: Meta<typeof Button> = {\n      component: Button,\n    };\n    export default meta;\n\n    export const NoChildren: Story = {};\n  `;\n  expect(generateExample(input)).toMatchInlineSnapshot(`\"const NoChildren = () => <Button />;\"`);\n});\n\ntest('Default satisfies or as', () => {\n  const input = withCSF3(`\n    export const Default = {} satisfies Story;\n    export const Other = {} as Story;\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\n    \"const Default = () => <Button>Click me</Button>;\n    const Other = () => <Button>Click me</Button>;\"\n  `\n  );\n});\n\ntest('Edge case identifier we can not find', () => {\n  const input = withCSF3(`\n    export const Default = someImportOrWhatever;\n  `);\n  expect(() => generateExample(input)).toThrowErrorMatchingInlineSnapshot(\n    `\n    [SyntaxError: Expected story to be csf factory, function or an object expression\n      11 |\n      12 |\n    > 13 |     export const Default = someImportOrWhatever;\n         |                            ^^^^^^^^^^^^^^^^^^^^\n      14 |   ]\n  `\n  );\n});\n\ntest('Default- CSF4', () => {\n  const input = withCSF4(`\n    export const Default = meta.story({});\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const Default = () => <Button>Click me</Button>;\"`\n  );\n});\n\ntest('StoryWithoutArguments - CSF4', () => {\n  const input = withCSF4(`\n    export const StoryWithoutArguments = meta.story();\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const StoryWithoutArguments = () => <Button>Click me</Button>;\"`\n  );\n});\n\ntest('Replace children', () => {\n  const input = withCSF3(dedent`\n    export const WithEmoji: Story = {\n      args: {\n        children: '🚀Launch'\n      }\n    };\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const WithEmoji = () => <Button>🚀Launch</Button>;\"`\n  );\n});\n\ntest('Boolean', () => {\n  const input = withCSF3(dedent`\n    export const Disabled: Story = {\n      args: {\n        disabled: true\n      }\n    };\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const Disabled = () => <Button disabled>Click me</Button>;\"`\n  );\n});\n\ntest('JSX Children', () => {\n  const input = withCSF3(dedent`\n    export const LinkButton: Story = {\n      args: {\n        children: <a href=\"/some-link\">This is a link</a>,\n      }\n    };\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const LinkButton = () => <Button><a href=\"/some-link\">This is a link</a></Button>;\"`\n  );\n});\n\ntest('Object', () => {\n  const input = withCSF3(dedent`\n    export const ObjectArgs: Story = {\n      args: {\n        string: 'string',\n        number: 1,\n        object: { an: 'object'},\n        complexObject: {...{a: 1}, an: 'object'},\n        array: [1,2,3]\n      }\n    };\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(`\n    \"const ObjectArgs = () => <Button\n        string=\"string\"\n        number={1}\n        object={{ an: 'object'}}\n        complexObject={{...{a: 1}, an: 'object'}}\n        array={[1,2,3]}>Click me</Button>;\"\n  `);\n});\n\ntest('CSF1', () => {\n  const input = withCSF3(dedent`\n    export const CSF1: StoryFn = () => <Button label=\"String\"></Button>;\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const CSF1 = () => <Button label=\"String\"></Button>;\"`\n  );\n});\n\ntest('CSF2', () => {\n  const input = withCSF3(dedent`\n    export const CSF2: StoryFn = (args) => <Button {...args} label=\"String\"></Button>;\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const CSF2 = () => <Button label=\"String\">Click me</Button>;\"`\n  );\n});\n\ntest('CSF2 - Template.bind', () => {\n  const input = withCSF3(dedent`\n    const Template = (args) => <Button {...args} label=\"String\"></Button>\n    export const CSF2: StoryFn = Template.bind({});\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const CSF2 = () => <Button label=\"String\">Click me</Button>;\"`\n  );\n});\n\ntest('CSF2 - with args', () => {\n  const input = withCSF3(dedent`\n    const Template = (args) => <Button {...args} override=\"overide\" />;\n    export const CSF2: StoryFn = Template.bind({});\n    CSF2.args = { foo: 'bar', override: 'value' }\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const CSF2 = () => <Button foo=\\\"bar\\\" override=\\\"overide\\\">Click me</Button>;\"`\n  );\n});\n\ntest('render: Template (identifier referencing local function)', () => {\n  const input = withCSF3(dedent`\n    const Template = (args) => <Button {...args} label=\"String\"></Button>\n    export const Interactive: Story = { render: Template }\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const Interactive = () => <Button label=\"String\">Click me</Button>;\"`\n  );\n});\n\ntest('render: Template (identifier referencing local function declaration)', () => {\n  const input = withCSF3(dedent`\n    function Template(args) { return <Button {...args} label=\"String\"></Button> }\n    export const Interactive: Story = { render: Template }\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(`\n    \"function Interactive() {\n        return <Button label=\"String\">Click me</Button>;\n    }\"\n  `);\n});\n\ntest('render: Template (identifier referencing unresolvable function)', () => {\n  // When Template can't be resolved (e.g. imported), fall back to no-function JSX synthesis\n  const input = withCSF3(dedent`\n    export const Interactive: Story = { render: Template }\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const Interactive = () => <Button>Click me</Button>;\"`\n  );\n});\n\ntest('Custom Render', () => {\n  const input = withCSF3(dedent`\n    export const CustomRender: Story = { render: () => <Button label=\"String\"></Button> }\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const CustomRender = () => <Button label=\"String\"></Button>;\"`\n  );\n});\n\ntest('CustomRenderWithOverideArgs only', async () => {\n  const input = withCSF3(\n    `export const CustomRenderWithOverideArgs = {\n      render: (args) => <Button {...args} override=\"overide\">Render</Button>,\n      args: { foo: 'bar', override: 'value' }\n    };`\n  );\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const CustomRenderWithOverideArgs = () => <Button foo=\"bar\" override=\"overide\">Render</Button>;\"`\n  );\n});\n\ntest('Meta level render: Template (identifier referencing local function)', async () => {\n  const input = dedent`\n    import type { Meta } from '@storybook/react';\n    import { Button } from '@design-system/button';\n\n    const Template = (args) => <Button {...args} override=\"overide\" />;\n\n    const meta: Meta<typeof Button> = {\n      render: Template,\n      args: {\n        children: 'Click me'\n      }\n    };\n    export default meta;\n\n    export const CustomRenderWithOverideArgs = {\n      args: { foo: 'bar', override: 'value' }\n    };\n  `;\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const CustomRenderWithOverideArgs = () => <Button foo=\"bar\" override=\"overide\">Click me</Button>;\"`\n  );\n});\n\ntest('Meta level render: Template (identifier referencing unresolvable function)', async () => {\n  const input = dedent`\n    import type { Meta } from '@storybook/react';\n    import { Button } from '@design-system/button';\n\n    const meta: Meta<typeof Button> = {\n      component: Button,\n      render: Template,\n      args: {\n        children: 'Click me'\n      }\n    };\n    export default meta;\n\n    export const Fallback = {\n      args: { foo: 'bar' }\n    };\n  `;\n  // Falls back to no-function JSX synthesis using component name\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const Fallback = () => <Button foo=\"bar\">Click me</Button>;\"`\n  );\n});\n\ntest('Story unresolvable render does not fall back to meta render', async () => {\n  // When a story has `render: ImportedTemplate` (unresolvable) and meta has an inline render,\n  // the story's render should take precedence — fall through to no-function JSX synthesis,\n  // NOT use meta's render function.\n  const input = dedent`\n    import type { Meta } from '@storybook/react';\n    import { Button } from '@design-system/button';\n\n    const meta: Meta<typeof Button> = {\n      component: Button,\n      render: (args) => <Button {...args} extra=\"from-meta\" />,\n      args: {\n        children: 'Click me'\n      }\n    };\n    export default meta;\n\n    export const StoryWithImportedRender = {\n      render: ImportedTemplate,\n      args: { label: 'hello' }\n    };\n  `;\n  // Should NOT contain extra=\"from-meta\" — that would mean meta's render leaked through\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const StoryWithImportedRender = () => <Button label=\"hello\">Click me</Button>;\"`\n  );\n});\n\ntest('Meta level render', async () => {\n  const input = dedent`\n    import type { Meta } from '@storybook/react';\n    import { Button } from '@design-system/button';\n\n    const meta: Meta<typeof Button> = {\n      render: (args) => <Button {...args} override=\"overide\" />,\n      args: {\n        children: 'Click me'\n      }\n    };\n    export default meta;\n\n    export const CustomRenderWithOverideArgs = {\n      args: { foo: 'bar', override: 'value' }\n    };\n  `;\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const CustomRenderWithOverideArgs = () => <Button foo=\"bar\" override=\"overide\">Click me</Button>;\"`\n  );\n});\n\ntest('CustomRenderWithNoArgs only', async () => {\n  const input = withCSF3(\n    `export const CustomRenderWithNoArgs = {\n      render: (args) => <Button {...args}>Render</Button>\n    };`\n  );\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const CustomRenderWithNoArgs = () => <Button>Render</Button>;\"`\n  );\n});\n\ntest('CustomRenderWithDuplicateOnly only', async () => {\n  const input = withCSF3(\n    `export const CustomRenderWithDuplicateOnly = {\n      render: (args) => <Button {...args} override=\"overide\">Render</Button>,\n      args: { override: 'value' }\n    };`\n  );\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const CustomRenderWithDuplicateOnly = () => <Button override=\"overide\">Render</Button>;\"`\n  );\n});\n\ntest('CustomRenderWithMultipleSpreads only', async () => {\n  const input = withCSF3(\n    `export const CustomRenderWithMultipleSpreads = {\n      render: (args) => <Button foo=\"a\" {...args} bar=\"b\" {...args} baz=\"c\">Render</Button>,\n      args: { qux: 'q' }\n    };`\n  );\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const CustomRenderWithMultipleSpreads = () => <Button foo=\"a\" qux=\"q\" bar=\"b\" baz=\"c\">Render</Button>;\"`\n  );\n});\n\ntest('CustomRenderBlockBody only', async () => {\n  const input = withCSF3(\n    `export const CustomRenderBlockBody = {\n      render: (args) => { return <Button {...args}>Render</Button> },\n      args: { foo: 'bar' }\n    };`\n  );\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\n    \"const CustomRenderBlockBody = () => {\n        return <Button foo=\"bar\">Render</Button>;\n    };\"\n  `\n  );\n});\n\ntest('ObjectFalsyArgs only', async () => {\n  const input = withCSF3(\n    `export const ObjectFalsyArgs = {\n      args: { disabled: false, count: 0, empty: '' }\n    };`\n  );\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const ObjectFalsyArgs = () => <Button disabled={false} count={0} empty=\"\">Click me</Button>;\"`\n  );\n});\n\ntest('ObjectUndefinedNull only', async () => {\n  const input = withCSF3(\n    `export const ObjectUndefinedNull = {\n      args: { thing: undefined, nada: null }\n    };`\n  );\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const ObjectUndefinedNull = () => <Button thing={undefined} nada={null}>Click me</Button>;\"`\n  );\n});\n\ntest('ObjectDataAttr only', async () => {\n  const input = withCSF3(\n    `export const ObjectDataAttr = {\n      args: { 'data-test-id': 'x' }\n    };`\n  );\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const ObjectDataAttr = () => <Button data-test-id=\"x\">Click me</Button>;\"`\n  );\n});\n\ntest('ObjectInvalidAttr only', async () => {\n  const input = withCSF3(\n    `export const ObjectInvalidAttr = {\n      args: { '1x': 'a', 'bad key': 'b', '@foo': 'c', '-dash': 'd' }\n    };`\n  );\n  expect(generateExample(input)).toMatchInlineSnapshot(`\n    \"const ObjectInvalidAttr = () => <Button\n        {...{\n            \"1x\": 'a',\n            \"bad key\": 'b',\n            \"@foo\": 'c',\n            \"-dash\": 'd'\n        }}>Click me</Button>;\"\n  `);\n});\n\ntest('Inline nested args in child element (string)', () => {\n  const input = withCSF3(dedent`\n    export const NestedInline: Story = {\n      render: (args) => <Button><OtherElement prop={args.foo} /></Button>,\n      args: { foo: 'bar' }\n    };\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const NestedInline = () => <Button><OtherElement prop=\"bar\" /></Button>;\"`\n  );\n});\n\ntest('Inline nested args in child element (boolean)', () => {\n  const input = withCSF3(dedent`\n    export const NestedBoolean: Story = {\n      render: (args) => <Button><OtherElement active={args.active} /></Button>,\n      args: { active: true }\n    };\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const NestedBoolean = () => <Button><OtherElement active /></Button>;\"`\n  );\n});\n\ntest('Remove nested attr when arg is null/undefined', () => {\n  const input = withCSF3(dedent`\n    export const NestedRemove: Story = {\n      render: (args) => <Button><OtherElement gone={args.gone} /></Button>,\n      args: { gone: null }\n    };\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const NestedRemove = () => <Button><OtherElement gone={null} /></Button>;\"`\n  );\n});\n\ntest('Inline args.children when used as child expression', () => {\n  const input = withCSF3(dedent`\n    export const ChildrenExpr: Story = {\n      render: (args) => <Button>{args.children}</Button>\n    };\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\"const ChildrenExpr = () => <Button>Click me</Button>;\"`\n  );\n});\n\n// Deeper tree examples\n\ntest('Deeply nested prop replacement (string)', () => {\n  const input = withCSF3(dedent`\n    export const DeepNestedProp: Story = {\n      render: (args) => (\n        <Button>\n          <Level1>\n            <Level2>\n              <Leaf val={args.foo} />\n            </Level2>\n          </Level1>\n        </Button>\n      ),\n      args: { foo: 'bar' }\n    };\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\n    \"const DeepNestedProp = () => <Button>\n        <Level1>\n            <Level2>\n                <Leaf val=\"bar\" />\n            </Level2>\n        </Level1>\n    </Button>;\"\n  `\n  );\n});\n\ntest('Deeply nested prop replacement (boolean)', () => {\n  const input = withCSF3(dedent`\n    export const DeepNestedBoolean: Story = {\n      render: (args) => (\n        <Button>\n          <Level1>\n            <Level2>\n              <Leaf active={args.active} />\n            </Level2>\n          </Level1>\n        </Button>\n      ),\n      args: { active: true }\n    };\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\n    \"const DeepNestedBoolean = () => <Button>\n        <Level1>\n            <Level2>\n                <Leaf active />\n            </Level2>\n        </Level1>\n    </Button>;\"\n  `\n  );\n});\n\ntest('Deeply nested children expression', () => {\n  const input = withCSF3(dedent`\n    export const DeepNestedChildren: Story = {\n      render: (args) => (\n        <Button>\n          <Level1>\n            <Level2>{args.children}</Level2>\n          </Level1>\n        </Button>\n      )\n    };\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\n    \"const DeepNestedChildren = () => <Button>\n        <Level1>\n            <Level2>Click me</Level2>\n        </Level1>\n    </Button>;\"\n  `\n  );\n});\n\ntest('Deeply nested multiple replacements', () => {\n  const input = withCSF3(dedent`\n    export const DeepNestedMultiple: Story = {\n      render: (args) => (\n        <Button>\n          <Level1>\n            <Leaf1 a={args.a} />\n            <Level2>\n              <Leaf2 b={args.b} />\n            </Level2>\n          </Level1>\n        </Button>\n      ),\n      args: { a: 'x', b: 'y' }\n    };\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\n    \"const DeepNestedMultiple = () => <Button>\n        <Level1>\n            <Leaf1 a=\"x\" />\n            <Level2>\n                <Leaf2 b=\"y\" />\n            </Level2>\n        </Level1>\n    </Button>;\"\n  `\n  );\n});\n\ntest('Deeply nested multiple replacements and using args spread', () => {\n  const input = withCSF3(dedent`\n    export const DeepNestedMultiple: Story = {\n      render: (args) => (\n        <Button {...args}>\n          <Level1>\n            <Leaf1 a={args.a} />\n            <Level2>\n              <Leaf2 b={args.b} />\n            </Level2>\n          </Level1>\n        </Button>\n      ),\n      args: { a: 'x', b: 'y' }\n    };\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(\n    `\n    \"const DeepNestedMultiple = () => <Button a=\"x\" b=\"y\">\n        <Level1>\n            <Leaf1 a=\"x\" />\n            <Level2>\n                <Leaf2 b=\"y\" />\n            </Level2>\n        </Level1>\n    </Button>;\"\n  `\n  );\n});\n\ntest('top level args injection and spreading in different places', async () => {\n  const input = withCSF3(dedent`\n    export const MultipleSpreads: Story = {\n      args: { disabled: false, count: 0, empty: '' },\n      render: (args) => (\n        <div count={args.count}>\n          <Button {...args} />\n          <Button {...args} />\n        </div>\n      ),\n    };\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(`\n    \"const MultipleSpreads = () => <div count={0}>\n        <Button disabled={false} count={0} empty=\"\">Click me</Button>\n        <Button disabled={false} count={0} empty=\"\">Click me</Button>\n    </div>;\"\n  `);\n});\n\ntest('allow top level export functions', async () => {\n  const input = withCSF3(dedent`\n    export function Usage(args) {\n      return (\n        <div style={{ padding: 40 }}>\n          <Button {...args}></Button>\n        </div>\n      );\n    }\n  `);\n  expect(generateExample(input)).toMatchInlineSnapshot(`\n    \"function Usage() {\n        return (\n            <div style={{ padding: 40 }}>\n                <Button>Click me</Button>\n            </div>\n        );\n    }\"\n  `);\n});\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/generateCodeSnippet.ts",
    "content": "import { type NodePath, types as t } from 'storybook/internal/babel';\nimport { type CsfFile } from 'storybook/internal/csf-tools';\n\nimport { invariant } from './utils.ts';\n\nexport function getCodeSnippet(\n  csf: CsfFile,\n  storyName: string,\n  componentName?: string\n): t.VariableDeclaration | t.FunctionDeclaration {\n  const storyDeclaration = csf._storyDeclarationPath[storyName];\n  const metaObj = csf._metaNode;\n\n  if (!storyDeclaration) {\n    const message = 'Expected story to be a function or variable declaration';\n    throw csf._storyPaths[storyName]?.buildCodeFrameError(message) ?? message;\n  }\n\n  // Normalize to NodePath<Function | Expression>\n  let storyPath: NodePath<t.FunctionDeclaration | t.Expression>;\n  if (storyDeclaration.isFunctionDeclaration()) {\n    storyPath = storyDeclaration;\n  } else if (storyDeclaration.isVariableDeclarator()) {\n    const init = storyDeclaration.get('init');\n    invariant(\n      init.isExpression(),\n      () =>\n        storyDeclaration.buildCodeFrameError('Expected story initializer to be an expression')\n          .message\n    );\n    storyPath = init;\n  } else {\n    throw storyDeclaration.buildCodeFrameError(\n      'Expected story to be a function or variable declaration'\n    );\n  }\n\n  let normalizedPath: NodePath<t.FunctionDeclaration | t.Expression> = storyPath;\n\n  // Handle Template.bind(...) or factory(story)\n  if (storyPath.isCallExpression()) {\n    const callee = storyPath.get('callee');\n    if (callee.isMemberExpression()) {\n      const obj = callee.get('object');\n      const prop = callee.get('property');\n      const isBind =\n        (prop.isIdentifier() && prop.node.name === 'bind') ||\n        (t.isStringLiteral(prop.node) && prop.node.value === 'bind');\n\n      if (obj.isIdentifier() && isBind) {\n        const resolved = resolveIdentifierInit(storyDeclaration, obj);\n\n        if (resolved) {\n          normalizedPath = resolved;\n        }\n      }\n    }\n\n    if (storyPath === normalizedPath) {\n      const args = storyPath.get('arguments');\n      // Allow meta.story() with zero args (CSF4)\n      if (args.length === 0) {\n        // Leave normalizedPath as the CallExpression; we'll treat it as an empty story config later\n      } else {\n        invariant(\n          args.length === 1,\n          () => storyPath.buildCodeFrameError('Could not evaluate story expression').message\n        );\n        const storyArg = args[0];\n        invariant(\n          storyArg.isExpression(),\n          () => storyPath.buildCodeFrameError('Could not evaluate story expression').message\n        );\n        normalizedPath = storyArg;\n      }\n    }\n  }\n\n  // Strip TS `satisfies` / `as`\n  normalizedPath = normalizedPath.isTSSatisfiesExpression()\n    ? normalizedPath.get('expression')\n    : normalizedPath.isTSAsExpression()\n      ? normalizedPath.get('expression')\n      : normalizedPath;\n\n  // Find a function (explicit story fn or render())\n  let storyFn:\n    | NodePath<t.ArrowFunctionExpression | t.FunctionExpression | t.FunctionDeclaration>\n    | undefined;\n\n  if (\n    normalizedPath.isArrowFunctionExpression() ||\n    normalizedPath.isFunctionExpression() ||\n    normalizedPath.isFunctionDeclaration()\n  ) {\n    storyFn = normalizedPath;\n  } else if (!normalizedPath.isObjectExpression()) {\n    // Allow CSF4 meta.story() without arguments, which is equivalent to an empty object story config\n    if (\n      normalizedPath.isCallExpression() &&\n      Array.isArray(normalizedPath.node.arguments) &&\n      normalizedPath.node.arguments.length === 0\n    ) {\n      // No-op: treat as an object story with no properties\n    } else {\n      throw normalizedPath.buildCodeFrameError(\n        'Expected story to be csf factory, function or an object expression'\n      );\n    }\n  }\n\n  const storyProps = normalizedPath.isObjectExpression()\n    ? normalizedPath.get('properties').filter((p) => p.isObjectProperty())\n    : [];\n\n  const metaPath = pathForNode(csf._file.path, metaObj);\n  const metaProps = metaPath?.isObjectExpression()\n    ? metaPath.get('properties').filter((p) => p.isObjectProperty())\n    : [];\n\n  // Tri-state render resolution: distinguishes \"no render property\" from\n  // \"render exists but couldn't be resolved\" so that an unresolvable story-level\n  // render (e.g. `render: ImportedTemplate`) doesn't incorrectly fall back to meta's render.\n  type RenderResolution =\n    | { kind: 'missing' }\n    | {\n        kind: 'resolved';\n        path: NodePath<t.ArrowFunctionExpression | t.FunctionExpression | t.FunctionDeclaration>;\n      }\n    | { kind: 'unresolved' };\n\n  const getRenderPath = (object: NodePath<t.ObjectProperty>[]): RenderResolution => {\n    const renderPath = object.find((p) => keyOf(p.node) === 'render')?.get('value');\n\n    if (!renderPath) {\n      return { kind: 'missing' };\n    }\n\n    // If render is an identifier (e.g. `render: Template`), try to resolve it\n    if (renderPath.isIdentifier()) {\n      const resolved = resolveIdentifierInit(storyDeclaration, renderPath);\n      if (\n        resolved &&\n        (resolved.isArrowFunctionExpression() ||\n          resolved.isFunctionExpression() ||\n          resolved.isFunctionDeclaration())\n      ) {\n        return { kind: 'resolved', path: resolved };\n      }\n      // Render property exists but couldn't be resolved — don't fall back to meta's render\n      return { kind: 'unresolved' };\n    }\n\n    if (!(renderPath.isArrowFunctionExpression() || renderPath.isFunctionExpression())) {\n      throw renderPath.buildCodeFrameError(\n        'Expected render to be an arrow function or function expression'\n      );\n    }\n\n    return { kind: 'resolved', path: renderPath };\n  };\n\n  const metaRender = getRenderPath(metaProps);\n  const storyRender = getRenderPath(storyProps);\n\n  // Story render takes precedence. Only fall back to meta render when the story\n  // has no render property at all — NOT when it has one that couldn't be resolved.\n  if (!storyFn) {\n    storyFn =\n      storyRender.kind === 'resolved'\n        ? storyRender.path\n        : storyRender.kind === 'missing' && metaRender.kind === 'resolved'\n          ? metaRender.path\n          : undefined;\n  }\n\n  // Collect args\n  const metaArgs = metaArgsRecord(metaObj ?? null);\n  const storyArgsPath = storyProps\n    .filter((p) => keyOf(p.node) === 'args')\n    .map((p) => p.get('value'))\n    .find((v) => v.isObjectExpression());\n  const storyArgs = argsRecordFromObjectPath(storyArgsPath);\n  const storyAssignedArgsPath = storyArgsAssignmentPath(csf._file.path, storyName);\n  const storyAssignedArgs = argsRecordFromObjectPath(storyAssignedArgsPath);\n  const merged: Record<string, t.Node> = { ...metaArgs, ...storyArgs, ...storyAssignedArgs };\n\n  // For no-function fallback\n  const entries = Object.entries(merged).filter(([k]) => k !== 'children');\n  const validEntries = entries.filter(([k, v]) => isValidJsxAttrName(k) && v != null);\n  const invalidEntries = entries.filter(([k, v]) => !isValidJsxAttrName(k) && v != null);\n  const injectedAttrs = validEntries.map(([k, v]) => toAttr(k, v)).filter((a) => a != null);\n\n  // If we have a function, transform returned JSX\n  if (storyFn) {\n    const fn = storyFn.node;\n\n    if (t.isArrowFunctionExpression(fn) && (t.isJSXElement(fn.body) || t.isJSXFragment(fn.body))) {\n      const spreadRes = transformArgsSpreadsInJsx(fn.body, merged);\n      const inlineRes = inlineArgsInJsx(spreadRes.node, merged);\n      if (spreadRes.changed || inlineRes.changed) {\n        const newFn = t.arrowFunctionExpression([], inlineRes.node, fn.async);\n        return t.variableDeclaration('const', [\n          t.variableDeclarator(t.identifier(storyName), newFn),\n        ]);\n      }\n    }\n\n    const stmts = t.isFunctionDeclaration(fn)\n      ? fn.body.body\n      : t.isArrowFunctionExpression(fn) && t.isBlockStatement(fn.body)\n        ? fn.body.body\n        : t.isFunctionExpression(fn) && t.isBlockStatement(fn.body)\n          ? fn.body.body\n          : undefined;\n\n    if (stmts) {\n      let changed = false;\n      const newBody = stmts.map((stmt) => {\n        if (\n          t.isReturnStatement(stmt) &&\n          stmt.argument &&\n          (t.isJSXElement(stmt.argument) || t.isJSXFragment(stmt.argument))\n        ) {\n          const spreadRes = transformArgsSpreadsInJsx(stmt.argument, merged);\n          const inlineRes = inlineArgsInJsx(spreadRes.node, merged);\n          if (spreadRes.changed || inlineRes.changed) {\n            changed = true;\n            return t.returnStatement(inlineRes.node);\n          }\n        }\n        return stmt;\n      });\n\n      if (changed) {\n        return t.isFunctionDeclaration(fn)\n          ? t.functionDeclaration(\n              t.identifier(storyName),\n              [],\n              t.blockStatement(newBody),\n              fn.generator,\n              fn.async\n            )\n          : t.variableDeclaration('const', [\n              t.variableDeclarator(\n                t.identifier(storyName),\n                t.arrowFunctionExpression([], t.blockStatement(newBody), fn.async)\n              ),\n            ]);\n      }\n    }\n\n    return t.isFunctionDeclaration(fn)\n      ? t.functionDeclaration(t.identifier(storyName), fn.params, fn.body, fn.generator, fn.async)\n      : t.variableDeclaration('const', [t.variableDeclarator(t.identifier(storyName), fn)]);\n  }\n\n  // No function: synthesize `<Component {...attrs}/>`\n  invariant(componentName, 'Could not generate snippet without component name.');\n  const invalidSpread = buildInvalidSpread(invalidEntries);\n  const name = t.jsxIdentifier(componentName);\n  const openingElAttrs = invalidSpread ? [...injectedAttrs, invalidSpread] : injectedAttrs;\n\n  const children = toJsxChildren(merged.children);\n  const selfClosing = children.length === 0;\n  const arrow = t.arrowFunctionExpression(\n    [],\n    t.jsxElement(\n      t.jsxOpeningElement(name, openingElAttrs, selfClosing),\n      selfClosing ? null : t.jsxClosingElement(name),\n      children,\n      selfClosing\n    )\n  );\n\n  return t.variableDeclaration('const', [t.variableDeclarator(t.identifier(storyName), arrow)]);\n}\n\n/** Build a spread `{...{k: v}}` for props that aren't valid JSX attributes. */\nfunction buildInvalidSpread(entries: ReadonlyArray<[string, t.Node]>): t.JSXSpreadAttribute | null {\n  if (entries.length === 0) {\n    return null;\n  }\n  const objectProps = entries.map(([k, v]) =>\n    t.objectProperty(t.stringLiteral(k), t.isExpression(v) ? v : t.identifier('undefined'))\n  );\n  return t.jsxSpreadAttribute(t.objectExpression(objectProps));\n}\n\nconst keyOf = (p: t.ObjectProperty): string | null =>\n  t.isIdentifier(p.key) ? p.key.name : t.isStringLiteral(p.key) ? p.key.value : null;\n\nconst isValidJsxAttrName = (n: string) => /^[A-Za-z_][A-Za-z0-9_:-]*$/.test(n);\n\nconst argsRecordFromObjectPath = (objPath?: NodePath<t.ObjectExpression> | null) =>\n  objPath\n    ? Object.fromEntries(\n        objPath\n          .get('properties')\n          .filter((p) => p.isObjectProperty())\n          .map((p) => [keyOf(p.node), p.get('value').node])\n          .filter((e) => Boolean(e[0]))\n      )\n    : {};\n\n/** Find `StoryName.args = { ... }` assignment and return the right-hand ObjectExpression if present. */\nfunction storyArgsAssignmentPath(\n  program: NodePath<t.Program>,\n  storyName: string\n): NodePath<t.ObjectExpression> | null {\n  let found: NodePath<t.ObjectExpression> | null = null;\n  program.traverse({\n    AssignmentExpression(p) {\n      const left = p.get('left');\n      const right = p.get('right');\n      if (left.isMemberExpression()) {\n        const obj = left.get('object');\n        const prop = left.get('property');\n        const isStoryIdent = obj.isIdentifier() && obj.node.name === storyName;\n        const isArgsProp =\n          (prop.isIdentifier() && prop.node.name === 'args' && !left.node.computed) ||\n          (t.isStringLiteral(prop.node) && left.node.computed && prop.node.value === 'args');\n        if (isStoryIdent && isArgsProp && right.isObjectExpression()) {\n          found = right as NodePath<t.ObjectExpression>;\n        }\n      }\n    },\n  });\n  return found;\n}\n\nconst argsRecordFromObjectNode = (obj?: t.ObjectExpression | null) =>\n  obj\n    ? Object.fromEntries(\n        obj.properties\n          .filter((p): p is t.ObjectProperty => t.isObjectProperty(p))\n          .map((p) => [keyOf(p), p.value])\n          .filter((e) => Boolean(e[0]))\n      )\n    : {};\n\nconst metaArgsRecord = (meta?: t.ObjectExpression | null) => {\n  if (!meta) {\n    return {};\n  }\n  const argsProp = meta.properties.find(\n    (p): p is t.ObjectProperty => t.isObjectProperty(p) && keyOf(p) === 'args'\n  );\n  return argsProp && t.isObjectExpression(argsProp.value)\n    ? argsRecordFromObjectNode(argsProp.value)\n    : {};\n};\n\nconst toAttr = (key: string, value: t.Node) => {\n  if (t.isBooleanLiteral(value)) {\n    return value.value\n      ? t.jsxAttribute(t.jsxIdentifier(key), null)\n      : t.jsxAttribute(t.jsxIdentifier(key), t.jsxExpressionContainer(value));\n  }\n\n  if (t.isStringLiteral(value)) {\n    return t.jsxAttribute(t.jsxIdentifier(key), t.stringLiteral(value.value));\n  }\n\n  if (t.isExpression(value)) {\n    return t.jsxAttribute(t.jsxIdentifier(key), t.jsxExpressionContainer(value));\n  }\n  return null;\n};\n\nconst toJsxChildren = (node: t.Node | null | undefined) =>\n  !node\n    ? []\n    : t.isStringLiteral(node)\n      ? [t.jsxText(node.value)]\n      : t.isJSXElement(node) || t.isJSXFragment(node)\n        ? [node]\n        : t.isExpression(node)\n          ? [t.jsxExpressionContainer(node)]\n          : [];\n\n/** Return `key` if expression is `args.key` (incl. optional chaining), else `null`. */\nfunction getArgsMemberKey(expr: t.Node) {\n  if (t.isMemberExpression(expr) && t.isIdentifier(expr.object) && expr.object.name === 'args') {\n    if (t.isIdentifier(expr.property) && !expr.computed) {\n      return expr.property.name;\n    }\n\n    if (t.isStringLiteral(expr.property) && expr.computed) {\n      return expr.property.value;\n    }\n  }\n  if (\n    t.isOptionalMemberExpression?.(expr) &&\n    t.isIdentifier(expr.object) &&\n    expr.object.name === 'args'\n  ) {\n    const prop = expr.property;\n\n    if (t.isIdentifier(prop) && !expr.computed) {\n      return prop.name;\n    }\n\n    if (t.isStringLiteral(prop) && expr.computed) {\n      return prop.value;\n    }\n  }\n  return null;\n}\n\n/** Inline `args.foo` -> actual literal/expression in attributes/children (recursively). */\nfunction inlineArgsInJsx(\n  node: t.JSXElement | t.JSXFragment,\n  merged: Record<string, t.Node>\n): { node: t.JSXElement | t.JSXFragment; changed: boolean } {\n  let changed = false;\n\n  if (t.isJSXElement(node)) {\n    const opening = node.openingElement;\n\n    const newAttrs = opening.attributes.flatMap<t.JSXAttribute | t.JSXSpreadAttribute>((a) => {\n      if (!t.isJSXAttribute(a)) {\n        return [a];\n      }\n      const name = t.isJSXIdentifier(a.name) ? a.name.name : null;\n\n      if (!(name && a.value && t.isJSXExpressionContainer(a.value))) {\n        return [a];\n      }\n\n      const key = getArgsMemberKey(a.value.expression);\n\n      if (!(key && key in merged)) {\n        return [a];\n      }\n\n      const repl = toAttr(name, merged[key]);\n      changed = true;\n      return repl ? [repl] : [];\n    });\n\n    const newChildren = node.children.flatMap<\n      t.JSXText | t.JSXExpressionContainer | t.JSXSpreadChild | t.JSXElement | t.JSXFragment\n    >((c) => {\n      if (t.isJSXElement(c) || t.isJSXFragment(c)) {\n        const res = inlineArgsInJsx(c, merged);\n        changed ||= res.changed;\n        return [res.node];\n      }\n      if (t.isJSXExpressionContainer(c)) {\n        const key = getArgsMemberKey(c.expression);\n        if (key === 'children' && merged.children) {\n          changed = true;\n          return toJsxChildren(merged.children);\n        }\n      }\n      return [c];\n    });\n\n    const selfClosing = opening.selfClosing && newChildren.length === 0;\n    return {\n      node: t.jsxElement(\n        t.jsxOpeningElement(opening.name, newAttrs, selfClosing),\n        selfClosing ? null : (node.closingElement ?? t.jsxClosingElement(opening.name)),\n        newChildren,\n        selfClosing\n      ),\n      changed,\n    };\n  }\n\n  const fragChildren = node.children.flatMap((c): (typeof c)[] => {\n    if (t.isJSXElement(c) || t.isJSXFragment(c)) {\n      const res = inlineArgsInJsx(c, merged);\n      changed ||= res.changed;\n      return [res.node];\n    }\n    if (t.isJSXExpressionContainer(c)) {\n      const key = getArgsMemberKey(c.expression);\n      if (key === 'children' && 'children' in merged) {\n        changed = true;\n        return toJsxChildren(merged.children);\n      }\n    }\n    return [c];\n  });\n\n  return { node: t.jsxFragment(node.openingFragment, node.closingFragment, fragChildren), changed };\n}\n\n/** Expand `{...args}` into concrete attributes/children (recursively). */\nfunction transformArgsSpreadsInJsx(\n  node: t.JSXElement | t.JSXFragment,\n  merged: Record<string, t.Node>\n): { node: t.JSXElement | t.JSXFragment; changed: boolean } {\n  let changed = false;\n\n  const makeInjectedPieces = (\n    existing: ReadonlySet<string>\n  ): Array<t.JSXAttribute | t.JSXSpreadAttribute> => {\n    const entries = Object.entries(merged).filter(([k, v]) => v != null && k !== 'children');\n    const validEntries = entries.filter(([k]) => isValidJsxAttrName(k));\n    const invalidEntries = entries.filter(([k]) => !isValidJsxAttrName(k));\n\n    const injectedAttrs = validEntries\n      .map(([k, v]) => toAttr(k, v))\n      .filter((a): a is t.JSXAttribute => Boolean(a))\n      .filter((a) => t.isJSXIdentifier(a.name) && !existing.has(a.name.name));\n\n    const invalidSpread = buildInvalidSpread(invalidEntries.filter(([k]) => !existing.has(k)));\n    return invalidSpread ? [...injectedAttrs, invalidSpread] : injectedAttrs;\n  };\n\n  if (t.isJSXElement(node)) {\n    const opening = node.openingElement;\n    const attrs = opening.attributes;\n\n    const isArgsSpread = (a: t.JSXAttribute | t.JSXSpreadAttribute) =>\n      t.isJSXSpreadAttribute(a) && t.isIdentifier(a.argument) && a.argument.name === 'args';\n\n    const sawArgsSpread = attrs.some(isArgsSpread);\n    const firstIdx = attrs.findIndex(isArgsSpread);\n    const nonArgsAttrs = attrs.filter((a) => !isArgsSpread(a));\n    const insertionIndex = sawArgsSpread\n      ? attrs.slice(0, firstIdx).filter((a) => !isArgsSpread(a)).length\n      : 0;\n\n    const newAttrs = sawArgsSpread\n      ? (() => {\n          const existing = new Set(\n            nonArgsAttrs\n              .filter((a): a is t.JSXAttribute => t.isJSXAttribute(a))\n              .flatMap((a) => (t.isJSXIdentifier(a.name) ? [a.name.name] : []))\n          );\n          const pieces = makeInjectedPieces(existing);\n          changed = true;\n          return [\n            ...nonArgsAttrs.slice(0, insertionIndex),\n            ...pieces,\n            ...nonArgsAttrs.slice(insertionIndex),\n          ];\n        })()\n      : nonArgsAttrs;\n\n    const newChildren = node.children.flatMap((c): (typeof c)[] => {\n      if (t.isJSXElement(c) || t.isJSXFragment(c)) {\n        const res = transformArgsSpreadsInJsx(c, merged);\n        changed ||= res.changed;\n        return [res.node];\n      }\n      return [c];\n    });\n\n    const children =\n      sawArgsSpread && newChildren.length === 0 && merged.children\n        ? ((changed = true), toJsxChildren(merged.children))\n        : newChildren;\n\n    const selfClosing = children.length === 0;\n    return {\n      node: t.jsxElement(\n        t.jsxOpeningElement(opening.name, newAttrs, selfClosing),\n        selfClosing ? null : (node.closingElement ?? t.jsxClosingElement(opening.name)),\n        children,\n        selfClosing\n      ),\n      changed,\n    };\n  }\n\n  const fragChildren = node.children.flatMap((c): (typeof c)[] => {\n    if (t.isJSXElement(c) || t.isJSXFragment(c)) {\n      const res = transformArgsSpreadsInJsx(c, merged);\n      changed ||= res.changed;\n      return [res.node];\n    }\n    return [c];\n  });\n\n  return { node: t.jsxFragment(node.openingFragment, node.closingFragment, fragChildren), changed };\n}\n\n/** Resolve the initializer for an identifier (e.g. `Template.bind({})` or `render: Template`). */\nfunction resolveIdentifierInit(storyPath: NodePath<t.Node>, identifier: NodePath<t.Identifier>) {\n  const programPath = storyPath.findParent((p) => p.isProgram()) as NodePath<t.Program> | null;\n\n  if (!programPath) {\n    return null;\n  }\n\n  // Check for function declarations: `function Template(args) { ... }` or `export function Template(args) { ... }`\n  for (const stmt of programPath.get('body')) {\n    if (stmt.isFunctionDeclaration() && stmt.node.id?.name === identifier.node.name) {\n      return stmt;\n    }\n    if (stmt.isExportNamedDeclaration()) {\n      const decl = stmt.get('declaration');\n      if (decl.isFunctionDeclaration() && decl.node.id?.name === identifier.node.name) {\n        return decl;\n      }\n    }\n  }\n\n  // Check for variable declarations: `const Template = (args) => ...`\n  const declarators = programPath.get('body').flatMap((stmt) => {\n    if (stmt.isVariableDeclaration()) {\n      return stmt.get('declarations');\n    }\n    if (stmt.isExportNamedDeclaration()) {\n      const decl = stmt.get('declaration');\n\n      if (decl && decl.isVariableDeclaration()) {\n        return decl.get('declarations');\n      }\n    }\n    return [];\n  });\n\n  const match = declarators.find((d) => {\n    const id = d.get('id');\n    return id.isIdentifier() && id.node.name === identifier.node.name;\n  });\n\n  if (!match) {\n    return null;\n  }\n  const init = match.get('init');\n  return init && init.isExpression() ? init : null;\n}\n\nexport function pathForNode<T extends t.Node>(\n  program: NodePath<t.Program>,\n  target: T | undefined\n): NodePath<T> | undefined {\n  if (!target) {\n    return undefined;\n  }\n  let found: NodePath<T> | undefined;\n\n  program.traverse({\n    enter(p) {\n      if (p.node && p.node === target) {\n        found = p as NodePath<T>;\n        p.stop(); // bail as soon as we have it\n      }\n    },\n  });\n\n  return found;\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/generator.test.ts",
    "content": "import { beforeEach, expect, test, vi } from 'vitest';\n\nimport { Tag } from 'storybook/internal/core-server';\n\nimport { vol } from 'memfs';\nimport { dedent } from 'ts-dedent';\n\nimport { ComponentMetaManager } from './componentMeta/ComponentMetaManager.ts';\nimport { indexJson } from './fixtures.ts';\nimport { manifests } from './generator.ts';\nimport { setupMemfsMocks } from './memfs-test-setup.ts';\n\n// Opt into memfs for this file (loads from __mocks__/fs.cjs)\nvi.mock('node:fs');\nvi.mock('node:fs/promises');\n\nvi.mock(import('./utils.ts'), { spy: true });\nvi.mock('storybook/internal/common', { spy: true });\nvi.mock('empathic/find', { spy: true });\nvi.mock('tsconfig-paths', { spy: true });\n\n/** Call manifests with only the fields tests need (presets/watch are optional-chained at runtime). */\ntype ManifestOptions = Parameters<typeof manifests>[1];\ntype ManifestEntries = ManifestOptions['manifestEntries'];\nconst createManifestOptions = (\n  manifestEntries: ManifestEntries,\n  options: Partial<ManifestOptions> = {}\n): ManifestOptions => ({ watch: false, manifestEntries, ...options }) as ManifestOptions;\n\nconst runManifests = (manifestEntries: ManifestEntries) =>\n  manifests(undefined, createManifestOptions(manifestEntries));\n\nconst runManifestsWithOptions = (\n  manifestEntries: ManifestEntries,\n  options: Partial<ManifestOptions> = {}\n) => manifests(undefined, createManifestOptions(manifestEntries, options));\n\nbeforeEach(() => {\n  setupMemfsMocks();\n});\n\ntest('manifests generates correct id, name, description and examples ', async () => {\n  const manifestEntries = Object.values(indexJson.entries).filter(\n    (entry) => entry.tags?.includes(Tag.MANIFEST) ?? false\n  );\n  const result = await runManifests(manifestEntries);\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars -- destructure to omit meta\n  const { meta: _meta, ...components } = result?.components ?? {};\n\n  expect(components).toMatchInlineSnapshot(`\n    {\n      \"components\": {\n        \"example-button\": {\n          \"description\": \"Primary UI component for user interaction\",\n          \"error\": undefined,\n          \"id\": \"example-button\",\n          \"import\": \"import { Button } from \"@design-system/components/override\";\",\n          \"jsDocTags\": {\n            \"import\": [\n              \"import { Button } from '@design-system/components/override';\",\n            ],\n          },\n          \"name\": \"Button\",\n          \"path\": \"./src/stories/Button.stories.ts\",\n          \"reactComponentMeta\": undefined,\n          \"reactDocgen\": {\n            \"actualName\": \"Button\",\n            \"definedInFile\": \"./src/stories/Button.tsx\",\n            \"description\": \"Primary UI component for user interaction\n    @import import { Button } from '@design-system/components/override';\",\n            \"displayName\": \"Button\",\n            \"exportName\": \"Button\",\n            \"methods\": [],\n            \"props\": {\n              \"backgroundColor\": {\n                \"description\": \"\",\n                \"required\": false,\n                \"tsType\": {\n                  \"name\": \"string\",\n                },\n              },\n              \"label\": {\n                \"description\": \"\",\n                \"required\": true,\n                \"tsType\": {\n                  \"name\": \"string\",\n                },\n              },\n              \"onClick\": {\n                \"description\": \"\",\n                \"required\": false,\n                \"tsType\": {\n                  \"name\": \"signature\",\n                  \"raw\": \"() => void\",\n                  \"signature\": {\n                    \"arguments\": [],\n                    \"return\": {\n                      \"name\": \"void\",\n                    },\n                  },\n                  \"type\": \"function\",\n                },\n              },\n              \"primary\": {\n                \"defaultValue\": {\n                  \"computed\": false,\n                  \"value\": \"false\",\n                },\n                \"description\": \"Description of primary\",\n                \"required\": false,\n                \"tsType\": {\n                  \"name\": \"boolean\",\n                },\n              },\n              \"size\": {\n                \"defaultValue\": {\n                  \"computed\": false,\n                  \"value\": \"'medium'\",\n                },\n                \"description\": \"\",\n                \"required\": false,\n                \"tsType\": {\n                  \"elements\": [\n                    {\n                      \"name\": \"literal\",\n                      \"value\": \"'small'\",\n                    },\n                    {\n                      \"name\": \"literal\",\n                      \"value\": \"'medium'\",\n                    },\n                    {\n                      \"name\": \"literal\",\n                      \"value\": \"'large'\",\n                    },\n                  ],\n                  \"name\": \"union\",\n                  \"raw\": \"'small' | 'medium' | 'large'\",\n                },\n              },\n            },\n          },\n          \"reactDocgenTypescript\": undefined,\n          \"stories\": [\n            {\n              \"description\": undefined,\n              \"id\": \"example-button--primary\",\n              \"name\": \"Primary\",\n              \"snippet\": \"const Primary = () => <Button onClick={fn()} primary label=\"Button\" />;\",\n              \"summary\": undefined,\n            },\n            {\n              \"description\": undefined,\n              \"id\": \"example-button--secondary\",\n              \"name\": \"Secondary\",\n              \"snippet\": \"const Secondary = () => <Button onClick={fn()} label=\"Button\" />;\",\n              \"summary\": undefined,\n            },\n            {\n              \"description\": undefined,\n              \"id\": \"example-button--large\",\n              \"name\": \"Large\",\n              \"snippet\": \"const Large = () => <Button onClick={fn()} size=\"large\" label=\"Button\" />;\",\n              \"summary\": undefined,\n            },\n            {\n              \"description\": undefined,\n              \"id\": \"example-button--small\",\n              \"name\": \"Small\",\n              \"snippet\": \"const Small = () => <Button onClick={fn()} size=\"small\" label=\"Button\" />;\",\n              \"summary\": undefined,\n            },\n          ],\n          \"summary\": undefined,\n        },\n        \"example-header\": {\n          \"description\": \"Description from meta and very long.\",\n          \"error\": undefined,\n          \"id\": \"example-header\",\n          \"import\": \"import { Header } from \"some-package\";\",\n          \"jsDocTags\": {\n            \"summary\": [\n              \"Component summary\",\n            ],\n          },\n          \"name\": \"Header\",\n          \"path\": \"./src/stories/Header.stories.ts\",\n          \"reactComponentMeta\": undefined,\n          \"reactDocgen\": {\n            \"actualName\": \"\",\n            \"definedInFile\": \"./src/stories/Header.tsx\",\n            \"description\": \"\",\n            \"exportName\": \"default\",\n            \"methods\": [],\n            \"props\": {\n              \"onCreateAccount\": {\n                \"description\": \"\",\n                \"required\": false,\n                \"tsType\": {\n                  \"name\": \"signature\",\n                  \"raw\": \"() => void\",\n                  \"signature\": {\n                    \"arguments\": [],\n                    \"return\": {\n                      \"name\": \"void\",\n                    },\n                  },\n                  \"type\": \"function\",\n                },\n              },\n              \"onLogin\": {\n                \"description\": \"\",\n                \"required\": false,\n                \"tsType\": {\n                  \"name\": \"signature\",\n                  \"raw\": \"() => void\",\n                  \"signature\": {\n                    \"arguments\": [],\n                    \"return\": {\n                      \"name\": \"void\",\n                    },\n                  },\n                  \"type\": \"function\",\n                },\n              },\n              \"onLogout\": {\n                \"description\": \"\",\n                \"required\": false,\n                \"tsType\": {\n                  \"name\": \"signature\",\n                  \"raw\": \"() => void\",\n                  \"signature\": {\n                    \"arguments\": [],\n                    \"return\": {\n                      \"name\": \"void\",\n                    },\n                  },\n                  \"type\": \"function\",\n                },\n              },\n              \"user\": {\n                \"description\": \"\",\n                \"required\": false,\n                \"tsType\": {\n                  \"name\": \"User\",\n                },\n              },\n            },\n          },\n          \"reactDocgenTypescript\": undefined,\n          \"stories\": [\n            {\n              \"description\": undefined,\n              \"id\": \"example-header--logged-in\",\n              \"name\": \"Logged In\",\n              \"snippet\": \"const LoggedIn = () => <Header\n        onLogin={fn()}\n        onLogout={fn()}\n        onCreateAccount={fn()}\n        user={{ name: 'Jane Doe' }} />;\",\n              \"summary\": undefined,\n            },\n            {\n              \"description\": undefined,\n              \"id\": \"example-header--logged-out\",\n              \"name\": \"Logged Out\",\n              \"snippet\": \"const LoggedOut = () => <Header onLogin={fn()} onLogout={fn()} onCreateAccount={fn()} />;\",\n              \"summary\": undefined,\n            },\n          ],\n          \"summary\": \"Component summary\",\n        },\n      },\n      \"v\": 0,\n    }\n  `);\n});\n\nasync function getManifestForStory(code: string) {\n  vol.fromJSON(\n    {\n      ['./package.json']: JSON.stringify({ name: 'some-package' }),\n      ['./src/stories/Button.stories.ts']: code,\n      ['./src/stories/Button.tsx']: dedent`\n        import React from 'react';\n        export interface ButtonProps {\n          /** Description of primary */\n          primary?: boolean;\n        }\n        \n        /** Primary UI component for user interaction */\n        export const Button = ({\n          primary = false,\n        }: ButtonProps) => {\n          const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n          return (\n            <button\n              type=\"button\"\n            ></button>\n          );\n        };`,\n    },\n    '/app'\n  );\n\n  const manifestEntries: ManifestEntries = [\n    {\n      type: 'story',\n      subtype: 'story',\n      id: 'example-button--primary',\n      name: 'Primary',\n      title: 'Example/Button',\n      importPath: './src/stories/Button.stories.ts',\n      componentPath: './src/stories/Button.tsx',\n      tags: [Tag.DEV, Tag.TEST, 'vitest', Tag.AUTODOCS, Tag.MANIFEST],\n      exportName: 'Primary',\n    },\n  ];\n\n  const result = await runManifests(manifestEntries);\n\n  return result?.components?.components?.['example-button'];\n}\n\nfunction withCSF3(body: string) {\n  return dedent`\n    import type { Meta } from '@storybook/react';\n    import { Button } from './Button';\n\n    const meta = {\n      title: 'Example/Button',\n      component: Button,\n      args: { onClick: fn() },\n    } satisfies Meta<typeof Button>;\n    export default meta;\n\n    ${body}\n  `;\n}\n\ntest('fall back to index title when no component name', async () => {\n  const code = dedent`\n    import type { Meta } from '@storybook/react';\n    import { Button } from './Button';\n\n    export default {\n      title: 'Example/Button',\n      args: { onClick: fn() },\n      tags: ['manifest'],\n    };\n    \n    export const Primary = () => <Button csf1=\"story\" />;\n  `;\n  expect(await getManifestForStory(code)).toMatchInlineSnapshot(`\n    {\n      \"description\": \"Primary UI component for user interaction\",\n      \"error\": undefined,\n      \"id\": \"example-button\",\n      \"import\": \"import { Button } from \"some-package\";\",\n      \"jsDocTags\": {},\n      \"name\": \"Button\",\n      \"path\": \"./src/stories/Button.stories.ts\",\n      \"reactComponentMeta\": undefined,\n      \"reactDocgen\": {\n        \"actualName\": \"Button\",\n        \"definedInFile\": \"./src/stories/Button.tsx\",\n        \"description\": \"Primary UI component for user interaction\",\n        \"displayName\": \"Button\",\n        \"exportName\": \"Button\",\n        \"methods\": [],\n        \"props\": {\n          \"primary\": {\n            \"defaultValue\": {\n              \"computed\": false,\n              \"value\": \"false\",\n            },\n            \"description\": \"Description of primary\",\n            \"required\": false,\n            \"tsType\": {\n              \"name\": \"boolean\",\n            },\n          },\n        },\n      },\n      \"reactDocgenTypescript\": undefined,\n      \"stories\": [\n        {\n          \"description\": undefined,\n          \"id\": \"example-button--primary\",\n          \"name\": \"Primary\",\n          \"snippet\": \"const Primary = () => <Button csf1=\"story\" />;\",\n          \"summary\": undefined,\n        },\n      ],\n      \"summary\": undefined,\n    }\n  `);\n});\n\ntest('component exported from other file', async () => {\n  const code = withCSF3(dedent`\n    export { Primary } from './other-file';\n  `);\n  expect(await getManifestForStory(code)).toMatchInlineSnapshot(`\n    {\n      \"description\": \"Primary UI component for user interaction\",\n      \"error\": undefined,\n      \"id\": \"example-button\",\n      \"import\": \"import { Button } from \"some-package\";\",\n      \"jsDocTags\": {},\n      \"name\": \"Button\",\n      \"path\": \"./src/stories/Button.stories.ts\",\n      \"reactComponentMeta\": undefined,\n      \"reactDocgen\": {\n        \"actualName\": \"Button\",\n        \"definedInFile\": \"./src/stories/Button.tsx\",\n        \"description\": \"Primary UI component for user interaction\",\n        \"displayName\": \"Button\",\n        \"exportName\": \"Button\",\n        \"methods\": [],\n        \"props\": {\n          \"primary\": {\n            \"defaultValue\": {\n              \"computed\": false,\n              \"value\": \"false\",\n            },\n            \"description\": \"Description of primary\",\n            \"required\": false,\n            \"tsType\": {\n              \"name\": \"boolean\",\n            },\n          },\n        },\n      },\n      \"reactDocgenTypescript\": undefined,\n      \"stories\": [\n        {\n          \"error\": {\n            \"message\": \"Expected story to be a function or variable declaration\n       9 | export default meta;\n      10 |\n    > 11 | export { Primary } from './other-file';\n         | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\",\n            \"name\": \"SyntaxError\",\n          },\n          \"id\": \"example-button--primary\",\n          \"name\": \"Primary\",\n        },\n      ],\n      \"summary\": undefined,\n    }\n  `);\n});\n\ntest('unknown expressions', async () => {\n  const code = withCSF3(dedent`\n    export const Primary = someWeirdExpression;\n  `);\n  expect(await getManifestForStory(code)).toMatchInlineSnapshot(`\n    {\n      \"description\": \"Primary UI component for user interaction\",\n      \"error\": undefined,\n      \"id\": \"example-button\",\n      \"import\": \"import { Button } from \"some-package\";\",\n      \"jsDocTags\": {},\n      \"name\": \"Button\",\n      \"path\": \"./src/stories/Button.stories.ts\",\n      \"reactComponentMeta\": undefined,\n      \"reactDocgen\": {\n        \"actualName\": \"Button\",\n        \"definedInFile\": \"./src/stories/Button.tsx\",\n        \"description\": \"Primary UI component for user interaction\",\n        \"displayName\": \"Button\",\n        \"exportName\": \"Button\",\n        \"methods\": [],\n        \"props\": {\n          \"primary\": {\n            \"defaultValue\": {\n              \"computed\": false,\n              \"value\": \"false\",\n            },\n            \"description\": \"Description of primary\",\n            \"required\": false,\n            \"tsType\": {\n              \"name\": \"boolean\",\n            },\n          },\n        },\n      },\n      \"reactDocgenTypescript\": undefined,\n      \"stories\": [\n        {\n          \"error\": {\n            \"message\": \"Expected story to be csf factory, function or an object expression\n       9 | export default meta;\n      10 |\n    > 11 | export const Primary = someWeirdExpression;\n         |                        ^^^^^^^^^^^^^^^^^^^\",\n            \"name\": \"SyntaxError\",\n          },\n          \"id\": \"example-button--primary\",\n          \"name\": \"Primary\",\n        },\n      ],\n      \"summary\": undefined,\n    }\n  `);\n});\n\ntest('generator uses reactComponentMeta displayName from batch extraction', async () => {\n  const batchExtract = vi\n    .spyOn(ComponentMetaManager.prototype, 'batchExtract')\n    .mockImplementation((entries) => {\n      for (const entry of entries) {\n        if (entry.component) {\n          entry.component.reactComponentMeta = {\n            displayName: 'Header',\n            exportName: 'default',\n            filePath: '/app/src/stories/Header.tsx',\n            description: '',\n            props: {},\n          };\n        }\n      }\n    });\n\n  const presets = {\n    apply: async (extension: string, config?: unknown) => {\n      if (extension === 'typescript') {\n        return {};\n      }\n      if (extension === 'features') {\n        return { experimentalReactComponentMeta: true };\n      }\n      return config;\n    },\n  } as NonNullable<ManifestOptions['presets']>;\n\n  const manifestEntries: ManifestEntries = [indexJson.entries['example-header--logged-in']];\n  const result = await runManifestsWithOptions(manifestEntries, { presets });\n  const header = result?.components?.components?.['example-header'];\n\n  expect(\n    header && 'reactComponentMeta' in header\n      ? (header as any).reactComponentMeta?.displayName\n      : undefined\n  ).toBe('Header');\n  expect(batchExtract).toHaveBeenCalled();\n});\n\ntest('generator preserves @import override when reactComponentMeta is enabled', async () => {\n  const batchExtract = vi\n    .spyOn(ComponentMetaManager.prototype, 'batchExtract')\n    .mockImplementation((entries) => {\n      for (const entry of entries) {\n        if (entry.component) {\n          entry.component.reactComponentMeta = {\n            displayName: 'Button',\n            exportName: 'Button',\n            filePath: '/app/src/stories/Button.tsx',\n            description: 'Primary UI component for user interaction',\n            props: {},\n          };\n          entry.component.componentJsDocTags = {\n            import: [\"import { Button } from '@design-system/components/override';\"],\n            summary: ['Fast summary'],\n          };\n          entry.component.importOverride =\n            \"import { Button } from '@design-system/components/override';\";\n        }\n      }\n    });\n\n  const presets = {\n    apply: async (extension: string, config?: unknown) => {\n      if (extension === 'typescript') {\n        return {};\n      }\n      if (extension === 'features') {\n        return { experimentalReactComponentMeta: true };\n      }\n      return config;\n    },\n  } as NonNullable<ManifestOptions['presets']>;\n\n  const manifestEntries: ManifestEntries = [indexJson.entries['example-button--primary']];\n  const result = await runManifestsWithOptions(manifestEntries, { presets });\n  const button = result?.components?.components?.['example-button'];\n\n  expect(button?.import).toBe('import { Button } from \"@design-system/components/override\";');\n  expect(button?.jsDocTags.import).toEqual([\n    \"import { Button } from '@design-system/components/override';\",\n  ]);\n  expect(button?.description).toBe('Primary UI component for user interaction');\n  expect(button?.summary).toBe('Fast summary');\n  expect(batchExtract).toHaveBeenCalled();\n});\n\ntest('generator falls back to title-based matching when meta.component aliases a compound member', async () => {\n  vol.fromJSON(\n    {\n      ['./package.json']: JSON.stringify({ name: 'some-package' }),\n      ['./src/stories/Accordion.stories.tsx']: dedent`\n        import type { Meta } from '@storybook/react';\n        import * as Accordion from './accordion';\n\n        const Root = Accordion.Root;\n\n        const meta = {\n          title: 'Example/Accordion',\n          component: Root,\n        } satisfies Meta<typeof Root>;\n        export default meta;\n\n        export const Default = () => <Accordion.Root multiple />;\n      `,\n      ['./src/stories/accordion.tsx']: dedent`\n        import React from 'react';\n\n        type RootProps = {\n          /** Allow multiple items open */\n          multiple?: boolean;\n        };\n\n        const Root = ({ multiple = false }: RootProps) => <div data-multiple={multiple} />;\n\n        export const Accordion = { Root };\n      `,\n    },\n    '/app'\n  );\n\n  const batchExtract = vi\n    .spyOn(ComponentMetaManager.prototype, 'batchExtract')\n    .mockImplementation((entries) => {\n      for (const entry of entries) {\n        if (entry.component?.componentName === 'Accordion.Root') {\n          entry.component.reactComponentMeta = {\n            displayName: 'Accordion.Root',\n            exportName: 'Root',\n            filePath: '/app/src/stories/accordion.tsx',\n            description: '',\n            props: {},\n          };\n        }\n      }\n    });\n\n  const presets = {\n    apply: async (extension: string, config?: unknown) => {\n      if (extension === 'typescript') {\n        return {};\n      }\n      if (extension === 'features') {\n        return { experimentalReactComponentMeta: true };\n      }\n      return config;\n    },\n  } as NonNullable<ManifestOptions['presets']>;\n\n  const manifestEntries = [\n    {\n      type: 'story' as const,\n      subtype: 'story' as const,\n      id: 'example-accordion--default',\n      name: 'Default',\n      title: 'Example/Accordion',\n      importPath: './src/stories/Accordion.stories.tsx',\n      componentPath: './src/stories/accordion.tsx',\n      tags: [Tag.DEV, Tag.TEST, Tag.MANIFEST],\n      exportName: 'Default',\n    },\n  ] satisfies ManifestEntries;\n\n  const result = await runManifestsWithOptions(manifestEntries, { presets });\n  const accordion = result?.components?.components?.['example-accordion'];\n\n  expect(accordion?.error).toBeUndefined();\n  expect(accordion?.name).toBe('Root');\n  expect(accordion?.import).toBe('import { Root } from \"some-package\";');\n  expect(batchExtract).toHaveBeenCalled();\n});\n\ntest('should create component manifest when only attached-mdx docs have manifest tag', async () => {\n  // This test verifies that the React renderer creates a component manifest entry\n  // when only an attached-mdx docs entry has the 'manifest' tag (and no story entries do).\n  // Note: The `docs` property of the component manifest is added by addon-docs, not by this generator,\n  // so it is not part of this test's snapshot.\n  vol.fromJSON(\n    {\n      ['./package.json']: JSON.stringify({ name: 'some-package' }),\n      ['./src/stories/Button.stories.ts']: dedent`\n        import type { Meta, StoryObj } from '@storybook/react';\n        import { fn } from 'storybook/test';\n        import { Button } from './Button';\n\n        const meta = {\n          title: 'Example/Button',\n          component: Button,\n          args: { onClick: fn() },\n        } satisfies Meta<typeof Button>;\n        export default meta;\n        type Story = StoryObj<typeof meta>;\n\n        export const Primary: Story = { args: { primary: true, label: 'Button', tags: ['!manifest'] } };\n      `,\n      ['./src/stories/Button.tsx']: dedent`\n        import React from 'react';\n        export interface ButtonProps {\n          /** Description of primary */\n          primary?: boolean;\n          label: string;\n        }\n\n        /** Primary UI component for user interaction */\n        export const Button = ({\n          primary = false,\n          label,\n        }: ButtonProps) => {\n          return <button type=\"button\">{label}</button>;\n        };\n      `,\n    },\n    '/app'\n  );\n\n  // Only docs entry has manifest tag, story does not\n  const manifestEntries = [\n    {\n      type: 'docs' as const,\n      id: 'example-button--docs',\n      name: 'Docs',\n      title: 'Example/Button',\n      importPath: './src/stories/Button.mdx',\n      tags: [Tag.DEV, Tag.TEST, Tag.MANIFEST, Tag.ATTACHED_MDX],\n      storiesImports: ['./src/stories/Button.stories.ts'],\n    },\n  ] satisfies ManifestEntries;\n\n  const result = await runManifests(manifestEntries);\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars -- destructure to omit meta\n  const { meta: _meta, ...components } = result?.components ?? {};\n  expect({ components }).toMatchInlineSnapshot(`\n    {\n      \"components\": {\n        \"components\": {\n          \"example-button\": {\n            \"description\": \"Primary UI component for user interaction\",\n            \"error\": undefined,\n            \"id\": \"example-button\",\n            \"import\": \"import { Button } from \"some-package\";\",\n            \"jsDocTags\": {},\n            \"name\": \"Button\",\n            \"path\": \"./src/stories/Button.stories.ts\",\n            \"reactComponentMeta\": undefined,\n            \"reactDocgen\": {\n              \"actualName\": \"Button\",\n              \"definedInFile\": \"./src/stories/Button.tsx\",\n              \"description\": \"Primary UI component for user interaction\",\n              \"displayName\": \"Button\",\n              \"exportName\": \"Button\",\n              \"methods\": [],\n              \"props\": {\n                \"label\": {\n                  \"description\": \"\",\n                  \"required\": true,\n                  \"tsType\": {\n                    \"name\": \"string\",\n                  },\n                },\n                \"primary\": {\n                  \"defaultValue\": {\n                    \"computed\": false,\n                    \"value\": \"false\",\n                  },\n                  \"description\": \"Description of primary\",\n                  \"required\": false,\n                  \"tsType\": {\n                    \"name\": \"boolean\",\n                  },\n                },\n              },\n            },\n            \"reactDocgenTypescript\": undefined,\n            \"stories\": [],\n            \"summary\": undefined,\n          },\n        },\n        \"v\": 0,\n      },\n    }\n  `);\n});\n\ntest('should prefer story entries over attached-mdx docs entries for the same component id', async () => {\n  vol.fromJSON(\n    {\n      ['./package.json']: JSON.stringify({ name: 'some-package' }),\n      ['./src/Primary/Primary.stories.tsx']: dedent`\n        import type { Meta } from '@storybook/react';\n        import { Primary } from './Primary';\n\n        const meta = {\n          title: 'Example/Primary',\n          component: Primary,\n        } satisfies Meta<typeof Primary>;\n        export default meta;\n\n        export const Default = () => <Primary title=\"Primary title\" />;\n      `,\n      ['./src/Primary/Primary.tsx']: dedent`\n        import React from 'react';\n\n        export interface PrimaryProps {\n          title: string;\n        }\n\n        /** Primary component description */\n        export const Primary = ({ title }: PrimaryProps) => <div>{title}</div>;\n      `,\n      ['./src/OtherFile/OtherFile.stories.tsx']: dedent`\n        import type { Meta } from '@storybook/react';\n        import { OtherFile } from './OtherFile';\n\n        const meta = {\n          title: 'Example/Other File',\n          component: OtherFile,\n        } satisfies Meta<typeof OtherFile>;\n        export default meta;\n\n        export const Default = () => <OtherFile label=\"Other file label\" />;\n      `,\n      ['./src/OtherFile/OtherFile.tsx']: dedent`\n        import React from 'react';\n\n        export interface OtherFileProps {\n          label: string;\n        }\n\n        /** Other file component description */\n        export const OtherFile = ({ label }: OtherFileProps) => (\n          <button type=\"button\">{label}</button>\n        );\n      `,\n    },\n    '/app'\n  );\n\n  const manifestEntries: ManifestEntries = [\n    {\n      type: 'docs' as const,\n      id: 'example-primary--docs',\n      name: 'Docs',\n      title: 'Example/Primary',\n      importPath: './src/Primary/Primary.mdx',\n      tags: [Tag.DEV, Tag.TEST, Tag.MANIFEST, Tag.ATTACHED_MDX],\n      storiesImports: [\n        './src/OtherFile/OtherFile.stories.tsx',\n        './src/Primary/Primary.stories.tsx',\n      ],\n    },\n    {\n      type: 'story' as const,\n      subtype: 'story' as const,\n      id: 'example-primary--default',\n      name: 'Default',\n      title: 'Example/Primary',\n      importPath: './src/Primary/Primary.stories.tsx',\n      componentPath: './src/Primary/Primary.tsx',\n      tags: [Tag.DEV, Tag.TEST, Tag.MANIFEST],\n      exportName: 'Default',\n    },\n  ];\n\n  const result = await runManifests(manifestEntries);\n\n  const component = result?.components?.components?.['example-primary'];\n\n  expect(component?.name).toBe('Primary');\n  expect(component?.path).toBe('./src/Primary/Primary.stories.tsx');\n  expect(component?.stories).toMatchObject([\n    {\n      id: 'example-primary--default',\n      name: 'Default',\n    },\n  ]);\n  expect(component?.stories[0]?.snippet).toContain('<Primary');\n});\n\ntest('stories are populated when meta has no explicit title', async () => {\n  vol.fromJSON(\n    {\n      ['./package.json']: JSON.stringify({ name: 'some-package' }),\n      ['./src/stories/Card.stories.ts']: dedent`\n        import type { Meta, StoryObj } from '@storybook/react';\n        import { Card } from './Card';\n\n        const meta: Meta<typeof Card> = {\n          component: Card,\n        };\n        export default meta;\n        type Story = StoryObj<typeof meta>;\n\n        export const Default: Story = { args: { label: 'Click me' } };\n        export const Large: Story = { args: { label: 'Big button', size: 'large' } };\n      `,\n      ['./src/stories/Card.tsx']: dedent`\n        import React from 'react';\n        /** A simple card component */\n        export const Card = ({ label, size }) => {\n          return <div className={size}>{label}</div>;\n        };\n      `,\n    },\n    '/app'\n  );\n\n  const manifestEntries: ManifestEntries = [\n    {\n      type: 'story',\n      subtype: 'story',\n      id: 'card--default',\n      name: 'Default',\n      title: 'Card',\n      importPath: './src/stories/Card.stories.ts',\n      componentPath: './src/stories/Card.tsx',\n      tags: [Tag.DEV, Tag.TEST, Tag.MANIFEST],\n      exportName: 'Default',\n    },\n    {\n      type: 'story',\n      subtype: 'story',\n      id: 'card--large',\n      name: 'Large',\n      title: 'Card',\n      importPath: './src/stories/Card.stories.ts',\n      componentPath: './src/stories/Card.tsx',\n      tags: [Tag.DEV, Tag.TEST, Tag.MANIFEST],\n      exportName: 'Large',\n    },\n  ];\n\n  const result = await runManifests(manifestEntries);\n  const component = result?.components?.components?.['card'];\n\n  // When no explicit title is in the meta, stories should still be populated\n  // because the generator should use the index entry's title as fallback\n  expect(component?.stories).toMatchInlineSnapshot(`\n    [\n      {\n        \"description\": undefined,\n        \"id\": \"card--default\",\n        \"name\": \"Default\",\n        \"snippet\": \"const Default = () => <Card label=\"Click me\" />;\",\n        \"summary\": undefined,\n      },\n      {\n        \"description\": undefined,\n        \"id\": \"card--large\",\n        \"name\": \"Large\",\n        \"snippet\": \"const Large = () => <Card label=\"Big button\" size=\"large\" />;\",\n        \"summary\": undefined,\n      },\n    ]\n  `);\n});\n\ntest('should extract story description and summary from JSDoc comments', async () => {\n  const code = withCSF3(dedent`\n    /**\n     * This is a longer description of the Primary story\n     * \n     * @summary This is a brief summary\n     */\n    export const Primary = () => <Button onClick={fn()} primary label=\"Button\" />;\n  `);\n  const manifest = await getManifestForStory(code);\n\n  expect(manifest?.stories).toMatchInlineSnapshot(`\n    [\n      {\n        \"description\": \"This is a longer description of the Primary story\",\n        \"id\": \"example-button--primary\",\n        \"name\": \"Primary\",\n        \"snippet\": \"const Primary = () => <Button onClick={fn()} primary label=\"Button\" />;\",\n        \"summary\": \"This is a brief summary\",\n      },\n    ]\n  `);\n});\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/generator.ts",
    "content": "import { recast } from 'storybook/internal/babel';\nimport { Tag } from 'storybook/internal/core-server';\nimport { storyNameFromExport } from 'storybook/internal/csf';\nimport { extractDescription, loadCsf } from 'storybook/internal/csf-tools';\nimport { logger } from 'storybook/internal/node-logger';\nimport type { DocsIndexEntry, IndexEntry } from 'storybook/internal/types';\nimport {\n  type ComponentManifest,\n  type PresetPropertyFn,\n  type StorybookConfigRaw,\n} from 'storybook/internal/types';\n\nimport path from 'pathe';\n\nimport { ComponentMetaManager } from './componentMeta/ComponentMetaManager.ts';\nimport type { ComponentDoc } from './componentMeta/componentMetaExtractor.ts';\nimport { getCodeSnippet } from './generateCodeSnippet.ts';\nimport {\n  type ComponentRef,\n  type TypescriptOptions,\n  getComponents,\n  getImports,\n} from './getComponentImports.ts';\nimport { extractJSDocInfo } from './jsdocTags.ts';\nimport { type DocObj } from './reactDocgen.ts';\nimport { type ComponentDocWithExportName, invalidateParser } from './reactDocgenTypescript.ts';\nimport { cachedFindUp, cachedReadTextFileSync, invalidateCache, invariant } from './utils.ts';\n\ninterface ReactComponentManifest extends ComponentManifest {\n  reactDocgen?: DocObj;\n  reactDocgenTypescript?: ComponentDocWithExportName;\n  reactComponentMeta?: ComponentDoc;\n}\n\nlet componentMetaManager: ComponentMetaManager | undefined;\n\nasync function createComponentMetaManager(\n  watch: boolean\n): Promise<ComponentMetaManager | undefined> {\n  if (componentMetaManager && watch) {\n    return componentMetaManager;\n  }\n  try {\n    const ts = await import('typescript');\n    const manager = new ComponentMetaManager(ts);\n    if (watch) {\n      componentMetaManager = manager;\n    }\n    return manager;\n  } catch {\n    logger.debug(\n      '[reactComponentMeta] TypeScript not available, skipping component meta extraction'\n    );\n  }\n}\n\nfunction isAttachedDocsEntry(\n  entry: IndexEntry\n): entry is DocsIndexEntry & { storiesImports: [string, ...string[]] } {\n  return (\n    entry.type === 'docs' &&\n    entry.tags?.includes(Tag.ATTACHED_MDX) === true &&\n    entry.storiesImports.length > 0\n  );\n}\n\nfunction selectComponentEntries(manifestEntries: IndexEntry[]) {\n  const entriesByComponentId = new Map<string, IndexEntry>();\n\n  manifestEntries\n    .filter(\n      (entry) =>\n        (entry.type === 'story' && entry.subtype === 'story') ||\n        // Attached docs entries are the only docs entries that can contribute to a\n        // component manifest, because they point back to a story file through storiesImports.\n        isAttachedDocsEntry(entry)\n    )\n    .forEach((entry) => {\n      const componentId = entry.id.split('--')[0];\n      const existingEntry = entriesByComponentId.get(componentId);\n\n      if (!existingEntry) {\n        // Keep the first eligible entry as a fallback so docs-only manifest coverage\n        // continues to work when no story entry for that component carries the manifest tag.\n        entriesByComponentId.set(componentId, entry);\n        return;\n      }\n\n      if (existingEntry.type === 'docs' && entry.type === 'story') {\n        // When both entries exist for the same component id, the story entry is authoritative.\n        // Attached docs may list unrelated stories first in storiesImports, so using the story\n        // entry avoids resolving the manifest from the wrong file.\n        entriesByComponentId.set(componentId, entry);\n      }\n    });\n\n  return [...entriesByComponentId.values()];\n}\n\nexport function findMatchingComponent(\n  components: ComponentRef[],\n  componentName: string | undefined,\n  title: string\n) {\n  // When meta.component is set, find the exact match.\n  // meta.component is the local variable name (e.g. \"Button\", \"Accordion\"),\n  // and getComponents adds it to the component set as-is when it maps cleanly to a component ref.\n  // If that strict lookup misses (for example `const Root = Accordion.Root`), continue into the\n  // regular title-based candidate selection below.\n  if (componentName) {\n    const match = components.find((it) => it.componentName === componentName);\n    if (match) {\n      return match;\n    }\n  }\n\n  // No meta.component — guess by title match.\n  const trimmedTitle = title.replace(/\\s+/g, '');\n  const matches = components.filter(\n    (it) =>\n      trimmedTitle.includes(it.componentName) ||\n      (it.localImportName && trimmedTitle.includes(it.localImportName)) ||\n      (it.importName && trimmedTitle.includes(it.importName))\n  );\n\n  if (matches.length <= 1) {\n    return matches[0];\n  }\n\n  // Prefer the outermost component (shallowest JSX nesting depth).\n  // jsxDepth 0 means top-level JSX — can't get shallower, so pick it immediately.\n  let best = matches[0];\n  for (const cur of matches) {\n    if (cur.jsxDepth === 0) {\n      return cur;\n    }\n    if ((cur.jsxDepth ?? Infinity) < (best.jsxDepth ?? Infinity)) {\n      best = cur;\n    }\n  }\n  return best;\n}\n\nfunction getPackageInfo(componentPath: string | undefined, fallbackPath: string) {\n  const nearestPkg = cachedFindUp('package.json', {\n    cwd: path.dirname(componentPath ?? fallbackPath),\n  });\n\n  try {\n    if (!nearestPkg) {\n      return undefined;\n    }\n\n    const parsed = JSON.parse(cachedReadTextFileSync(nearestPkg));\n    return typeof parsed === 'object' &&\n      parsed &&\n      'name' in parsed &&\n      typeof parsed.name === 'string'\n      ? parsed.name\n      : undefined;\n  } catch {\n    return undefined;\n  }\n}\n\nfunction extractStories(\n  csf: ReturnType<ReturnType<typeof loadCsf>['parse']>,\n  componentName: string | undefined,\n  manifestEntries: IndexEntry[]\n) {\n  const manifestEntryIds = new Set(manifestEntries.map((entry) => entry.id));\n  return Object.entries(csf._stories)\n    .filter(([, story]) =>\n      // Only include stories that are in the list of entries already filtered for the 'manifest' tag\n      manifestEntryIds.has(story.id)\n    )\n    .map(([storyExport, story]) => {\n      try {\n        const jsdocComment = extractDescription(csf._storyStatements[storyExport]);\n        const { tags = {}, description } = jsdocComment ? extractJSDocInfo(jsdocComment) : {};\n        const finalDescription = (tags?.describe?.[0] || tags?.desc?.[0]) ?? description;\n\n        return {\n          id: story.id,\n          name: story.name ?? storyNameFromExport(storyExport),\n          snippet: recast.print(getCodeSnippet(csf, storyExport, componentName)).code,\n          description: finalDescription?.trim(),\n          summary: tags.summary?.[0],\n        };\n      } catch (e) {\n        invariant(e instanceof Error);\n        return {\n          id: story.id,\n          name: story.name ?? storyNameFromExport(storyExport),\n          error: { name: e.name, message: e.message },\n        };\n      }\n    });\n}\n\nfunction extractComponentDescription(\n  metaJsDoc: string | undefined,\n  docgenDescription: string | undefined,\n  docgenJsDocTags?: Record<string, string[]>\n) {\n  const jsdocComment = metaJsDoc || docgenDescription;\n  const extracted = jsdocComment ? extractJSDocInfo(jsdocComment) : undefined;\n  const tags = docgenJsDocTags ?? extracted?.tags ?? {};\n  const description = extracted?.description;\n\n  return {\n    description: ((tags?.describe?.[0] || tags?.desc?.[0]) ?? description)?.trim(),\n    summary: tags.summary?.[0],\n    jsDocTags: tags,\n  };\n}\n\ntype DocgenEngine = 'react-docgen' | 'react-docgen-typescript' | 'react-component-meta';\n\nexport const manifests: PresetPropertyFn<\n  'experimental_manifests',\n  StorybookConfigRaw,\n  { manifestEntries: IndexEntry[]; watch: boolean }\n> = async (existingManifests = {}, options) => {\n  const { manifestEntries, presets, watch } = options;\n  const typescriptOptions =\n    (await presets?.apply<Partial<TypescriptOptions>>('typescript', {})) ?? {};\n  const features = await presets?.apply('features', {});\n\n  const docgenEngine: DocgenEngine = features?.experimentalReactComponentMeta\n    ? 'react-component-meta'\n    : typescriptOptions.reactDocgen || 'react-docgen';\n\n  invalidateCache();\n  invalidateParser();\n\n  const startTime = performance.now();\n  const manager =\n    docgenEngine === 'react-component-meta' ? await createComponentMetaManager(watch) : null;\n\n  try {\n    const entriesByUniqueComponent = selectComponentEntries(manifestEntries);\n\n    // Step 1: Resolve components for all entries\n    const resolvedEntries = await Promise.all(\n      entriesByUniqueComponent.map(async (entry) => {\n        const storyFilePath =\n          entry.type === 'story'\n            ? entry.importPath\n            : // For attached docs entries, storiesImports[0] points to the stories file being attached to\n              entry.storiesImports[0];\n        const storyPath = path.join(process.cwd(), storyFilePath);\n        const storyFile = cachedReadTextFileSync(storyPath);\n        const csf = loadCsf(storyFile, { makeTitle: () => entry.title }).parse();\n        const componentName = csf._meta?.component;\n        const allComponents = await getComponents({\n          csf,\n          storyFilePath: storyPath,\n          typescriptOptions,\n          docgenEngine,\n        });\n        const component = findMatchingComponent(allComponents, componentName, entry.title);\n        return {\n          storyPath,\n          component,\n          entry,\n          storyFilePath,\n          storyFile,\n          csf,\n          componentName,\n          allComponents,\n        };\n      })\n    );\n\n    // Step 2: Batch extract rcm props (one TS program build per tsconfig project)\n    if (docgenEngine === 'react-component-meta' && manager) {\n      manager.batchExtract(resolvedEntries);\n    }\n\n    // Step 3: Build manifests\n    const components = resolvedEntries\n      .map(\n        ({\n          storyPath,\n          component,\n          entry,\n          storyFilePath,\n          storyFile,\n          csf,\n          componentName,\n          allComponents,\n        }): ReactComponentManifest | undefined => {\n          const id = entry.id.split('--')[0];\n          const title = entry.title.split('/').at(-1)!.replace(/\\s+/g, '');\n\n          const packageName = getPackageInfo(component?.path, storyPath);\n          const fallbackImport =\n            packageName && componentName\n              ? `import { ${componentName} } from \"${packageName}\";`\n              : '';\n          const imports =\n            getImports({ components: allComponents, packageName }).join('\\n').trim() ||\n            fallbackImport;\n\n          const stories = extractStories(csf, component?.componentName, manifestEntries);\n\n          const base = {\n            id,\n            name: componentName ?? title,\n            path: storyFilePath,\n            stories,\n            import: imports,\n            jsDocTags: {},\n          } satisfies Partial<ComponentManifest>;\n\n          // --- Extract props via the active engine ---\n          let reactDocgen;\n          let reactDocgenTypescript;\n          let reactComponentMeta;\n          let docgenDescription;\n          let docgenJsDocTags;\n          let docgenError;\n\n          if (docgenEngine === 'react-docgen') {\n            const result = component?.reactDocgen;\n            reactDocgen = result?.type === 'success' ? result.data : undefined;\n            docgenDescription = reactDocgen?.description;\n            docgenError = result?.type === 'error' ? result.error : undefined;\n          } else if (docgenEngine === 'react-docgen-typescript') {\n            reactDocgenTypescript = component?.reactDocgenTypescript;\n            docgenDescription = reactDocgenTypescript?.description;\n            docgenError = component?.reactDocgenTypescriptError;\n          } else {\n            reactComponentMeta = component?.reactComponentMeta;\n            docgenDescription = reactComponentMeta?.description;\n            docgenJsDocTags = component?.componentJsDocTags;\n          }\n\n          if (!reactDocgen && !reactDocgenTypescript && !reactComponentMeta) {\n            const error = !csf._meta?.component\n              ? {\n                  name: 'No component found',\n                  message:\n                    'We could not detect the component from your story file. Specify meta.component.',\n                }\n              : {\n                  name: 'No component import found',\n                  message: `No component file found for the \"${csf.meta.component}\" component.`,\n                };\n\n            return {\n              ...base,\n              error: docgenError ?? {\n                name: error.name,\n                message:\n                  (csf._metaStatementPath?.buildCodeFrameError(error.message).message ??\n                    error.message) + `\\n\\n${entry.importPath}:\\n${storyFile}`,\n              },\n            };\n          }\n\n          const metaJsDoc = extractDescription(csf._metaStatement) || undefined;\n          const { description, summary, jsDocTags } = extractComponentDescription(\n            metaJsDoc,\n            docgenDescription,\n            docgenJsDocTags\n          );\n\n          return {\n            ...base,\n            description,\n            summary,\n            import: imports,\n            reactDocgen,\n            reactDocgenTypescript,\n            reactComponentMeta,\n            jsDocTags,\n            error: docgenError,\n          };\n        }\n      )\n      .filter((component) => component !== undefined);\n\n    // Start watching AFTER extraction — projects and TS programs are now populated,\n    // so watchProgramSourceDirs() can discover all source file directories.\n    if (manager && watch) {\n      manager.startWatching();\n    }\n\n    const durationMs = Math.round(performance.now() - startTime);\n\n    return {\n      ...existingManifests,\n      components: {\n        v: 0,\n        components: Object.fromEntries(components.map((component) => [component.id, component])),\n        meta: {\n          docgen: docgenEngine,\n          durationMs,\n        },\n      },\n    };\n  } finally {\n    if (manager && !watch) {\n      manager.dispose();\n    }\n  }\n};\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/getComponentImports.test.ts",
    "content": "import { beforeEach, expect, test, vi } from 'vitest';\n\nimport { loadCsf } from 'storybook/internal/csf-tools';\n\nimport { dedent } from 'ts-dedent';\n\nimport { getImports as buildImports, getComponentData } from './getComponentImports.ts';\nimport { setupMemfsMocks } from './memfs-test-setup.ts';\n\nvi.mock('node:fs');\nvi.mock('node:fs/promises');\nvi.mock(import('./utils.ts'), { spy: true });\nvi.mock('storybook/internal/common', { spy: true });\nvi.mock('empathic/find', { spy: true });\nvi.mock('tsconfig-paths', { spy: true });\n\nbeforeEach(() => {\n  setupMemfsMocks();\n});\n\nconst getImports = async (code: string, packageName?: string, storyFilePath?: string) => {\n  storyFilePath ??= '/app/src/stories/Button.stories.tsx';\n  const { components, imports } = await getComponentData({\n    csf: loadCsf(code, { makeTitle: (t?: string) => t ?? 'title' }).parse(),\n    packageName,\n    storyFilePath,\n    docgenEngine: 'react-docgen',\n  });\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  return { components: components.map(({ reactDocgen, ...rest }) => rest), imports };\n};\n\ntest('Get imports from multiple components', async () => {\n  const code = dedent`\n    import type { Meta } from '@storybook/react';\n    import { ButtonGroup } from './button-group';\n    import { Button } from '@design-system/button';\n\n    const meta: Meta<typeof Button> = {\n      component: Button,\n      args: {\n        children: 'Click me'\n      }\n    };\n    export default meta;\n    export const Default: Story = <ButtonGroup><Button>Click me</Button></ButtonGroup>;\n  `;\n  expect(await getImports(code)).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Button\",\n          \"importId\": \"@design-system/button\",\n          \"importName\": \"Button\",\n          \"importOverride\": \"import { Button } from '@design-system/components/override';\",\n          \"isPackage\": true,\n          \"jsxDepth\": 1,\n          \"localImportName\": \"Button\",\n          \"path\": \"./src/stories/Button.tsx\",\n        },\n        {\n          \"componentName\": \"ButtonGroup\",\n          \"importId\": \"./button-group\",\n          \"importName\": \"ButtonGroup\",\n          \"isPackage\": false,\n          \"jsxDepth\": 0,\n          \"localImportName\": \"ButtonGroup\",\n        },\n      ],\n      \"imports\": [\n        \"import { Button } from \"@design-system/components/override\";\",\n        \"import { ButtonGroup } from \"./button-group\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Namespace import with member usage', async () => {\n  const code = dedent`\n    import * as Accordion from './accordion';\n\n    const meta = {};\n    export default meta;\n    export const S = <Accordion.Root>Hi</Accordion.Root>;\n  `;\n  expect(await getImports(code)).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Accordion.Root\",\n          \"importId\": \"./accordion\",\n          \"importName\": \"Root\",\n          \"isPackage\": false,\n          \"jsxDepth\": 0,\n          \"localImportName\": \"Accordion\",\n          \"member\": \"Root\",\n          \"namespace\": \"Accordion\",\n        },\n      ],\n      \"imports\": [\n        \"import * as Accordion from \"./accordion\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Named import used as namespace object', async () => {\n  const code = dedent`\n    import { Accordion } from './accordion';\n\n    const meta = {};\n    export default meta;\n    export const S = <Accordion.Root>Hi</Accordion.Root>;\n  `;\n  expect(await getImports(code)).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Accordion.Root\",\n          \"importId\": \"./accordion\",\n          \"importName\": \"Accordion\",\n          \"isPackage\": false,\n          \"jsxDepth\": 0,\n          \"localImportName\": \"Accordion\",\n          \"member\": \"Root\",\n        },\n      ],\n      \"imports\": [\n        \"import { Accordion } from \"./accordion\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Default import', async () => {\n  const code = dedent`\n    import Button from '@ds/button';\n\n    const meta = {};\n    export default meta;\n    export const S = <Button/>;\n  `;\n  expect(await getImports(code)).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Button\",\n          \"importId\": \"@ds/button\",\n          \"importName\": \"default\",\n          \"importOverride\": \"import { Button } from '@design-system/components/override';\",\n          \"isPackage\": true,\n          \"jsxDepth\": 0,\n          \"localImportName\": \"Button\",\n          \"path\": \"./src/stories/Button.tsx\",\n        },\n      ],\n      \"imports\": [\n        \"import { Button } from \"@design-system/components/override\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Alias named import and meta.component inclusion', async () => {\n  const code = dedent`\n    import DefaultComponent, { Button as Btn } from '@ds/button';\n    import { Other } from './other';\n\n    const meta = { component: Btn };\n    export default meta;\n    export const S = <Other><Btn/></Other>;\n  `;\n  expect(await getImports(code)).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Btn\",\n          \"importId\": \"@ds/button\",\n          \"importName\": \"Button\",\n          \"importOverride\": \"import { Button } from '@design-system/components/override';\",\n          \"isPackage\": true,\n          \"jsxDepth\": 1,\n          \"localImportName\": \"Btn\",\n          \"path\": \"./src/stories/Button.tsx\",\n        },\n        {\n          \"componentName\": \"Other\",\n          \"importId\": \"./other\",\n          \"importName\": \"Other\",\n          \"isPackage\": false,\n          \"jsxDepth\": 0,\n          \"localImportName\": \"Other\",\n        },\n      ],\n      \"imports\": [\n        \"import { Button as Btn } from \"@design-system/components/override\";\",\n        \"import { Other } from \"./other\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Strip unused specifiers from the same import statement', async () => {\n  const code = dedent`\n    import { Button as Btn, useSomeHook } from '@ds/button';\n\n    const meta = {};\n    export default meta;\n    export const S = <Btn/>;\n  `;\n  expect(await getImports(code)).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Btn\",\n          \"importId\": \"@ds/button\",\n          \"importName\": \"Button\",\n          \"importOverride\": \"import { Button } from '@design-system/components/override';\",\n          \"isPackage\": true,\n          \"jsxDepth\": 0,\n          \"localImportName\": \"Btn\",\n          \"path\": \"./src/stories/Button.tsx\",\n        },\n      ],\n      \"imports\": [\n        \"import { Button as Btn } from \"@design-system/components/override\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Meta component with member and star import', async () => {\n  const code = dedent`\n    import * as Accordion from './accordion';\n\n    const meta = { component: Accordion.Root };\n    export default meta;\n  `;\n  expect(await getImports(code)).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Accordion.Root\",\n          \"importId\": \"./accordion\",\n          \"importName\": \"Root\",\n          \"isPackage\": false,\n          \"jsxDepth\": undefined,\n          \"localImportName\": \"Accordion\",\n          \"member\": \"Root\",\n          \"namespace\": \"Accordion\",\n        },\n      ],\n      \"imports\": [\n        \"import * as Accordion from \"./accordion\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Keeps multiple named specifiers and drops unused ones from same import', async () => {\n  const code = dedent`\n    import { Button, useHook } from '@ds/button';\n    import { ButtonGroup } from './button-group';\n\n    const meta = {};\n    export default meta;\n    export const S = <div><Button/><ButtonGroup/></div>;\n  `;\n  expect(await getImports(code)).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Button\",\n          \"importId\": \"@ds/button\",\n          \"importName\": \"Button\",\n          \"importOverride\": \"import { Button } from '@design-system/components/override';\",\n          \"isPackage\": true,\n          \"jsxDepth\": 1,\n          \"localImportName\": \"Button\",\n          \"path\": \"./src/stories/Button.tsx\",\n        },\n        {\n          \"componentName\": \"ButtonGroup\",\n          \"importId\": \"./button-group\",\n          \"importName\": \"ButtonGroup\",\n          \"isPackage\": false,\n          \"jsxDepth\": 1,\n          \"localImportName\": \"ButtonGroup\",\n        },\n      ],\n      \"imports\": [\n        \"import { Button } from \"@design-system/components/override\";\",\n        \"import { ButtonGroup } from \"./button-group\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Mixed default + named import: keep only default when only default used', async () => {\n  const code = dedent`\n    import Button, { useHook } from '@ds/button';\n\n    const meta = {};\n    export default meta;\n    export const S = <Button/>;\n  `;\n  expect(await getImports(code)).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Button\",\n          \"importId\": \"@ds/button\",\n          \"importName\": \"default\",\n          \"importOverride\": \"import { Button } from '@design-system/components/override';\",\n          \"isPackage\": true,\n          \"jsxDepth\": 0,\n          \"localImportName\": \"Button\",\n          \"path\": \"./src/stories/Button.tsx\",\n        },\n      ],\n      \"imports\": [\n        \"import { Button } from \"@design-system/components/override\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Mixed default + named import: keep only named when only named (alias) used', async () => {\n  const code = dedent`\n    import Button, { Button as Btn } from '@ds/button';\n\n    const meta = {};\n    export default meta;\n    export const S = <Btn/>;\n  `;\n  expect(await getImports(code)).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Btn\",\n          \"importId\": \"@ds/button\",\n          \"importName\": \"Button\",\n          \"importOverride\": \"import { Button } from '@design-system/components/override';\",\n          \"isPackage\": true,\n          \"jsxDepth\": 0,\n          \"localImportName\": \"Btn\",\n          \"path\": \"./src/stories/Button.tsx\",\n        },\n      ],\n      \"imports\": [\n        \"import { Button as Btn } from \"@design-system/components/override\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Per-specifier type import is dropped when mixing with value specifiers', async () => {\n  const code = dedent`\n    import type { Meta } from '@storybook/react';\n    import { type Meta as M, Button } from '@ds/button';\n\n    const meta = {};\n    export default meta;\n    export const S = <Button/>;\n  `;\n  expect(await getImports(code)).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Button\",\n          \"importId\": \"@ds/button\",\n          \"importName\": \"Button\",\n          \"importOverride\": \"import { Button } from '@design-system/components/override';\",\n          \"isPackage\": true,\n          \"jsxDepth\": 0,\n          \"localImportName\": \"Button\",\n          \"path\": \"./src/stories/Button.tsx\",\n        },\n      ],\n      \"imports\": [\n        \"import { Button } from \"@design-system/components/override\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Namespace import used for multiple members kept once', async () => {\n  const code = dedent`\n    import * as DS from './ds';\n\n    const meta = {};\n    export default meta;\n    export const S = <div><DS.A/><DS.B/></div>;\n  `;\n  expect(await getImports(code)).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"DS.A\",\n          \"importId\": \"./ds\",\n          \"importName\": \"A\",\n          \"isPackage\": false,\n          \"jsxDepth\": 1,\n          \"localImportName\": \"DS\",\n          \"member\": \"A\",\n          \"namespace\": \"DS\",\n        },\n        {\n          \"componentName\": \"DS.B\",\n          \"importId\": \"./ds\",\n          \"importName\": \"B\",\n          \"isPackage\": false,\n          \"jsxDepth\": 1,\n          \"localImportName\": \"DS\",\n          \"member\": \"B\",\n          \"namespace\": \"DS\",\n        },\n      ],\n      \"imports\": [\n        \"import * as DS from \"./ds\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Default import kept when referenced only via meta.component', async () => {\n  const code = dedent`\n    import Button from '@ds/button';\n\n    const meta = { component: Button };\n    export default meta;\n  `;\n  expect(await getImports(code)).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Button\",\n          \"importId\": \"@ds/button\",\n          \"importName\": \"default\",\n          \"importOverride\": \"import { Button } from '@design-system/components/override';\",\n          \"isPackage\": true,\n          \"jsxDepth\": undefined,\n          \"localImportName\": \"Button\",\n          \"path\": \"./src/stories/Button.tsx\",\n        },\n      ],\n      \"imports\": [\n        \"import { Button } from \"@design-system/components/override\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Side-effect-only import is ignored', async () => {\n  const code = dedent`\n    import '@ds/global.css';\n    import { Button } from '@ds/button';\n\n    const meta = {};\n    export default meta;\n    export const S = <Button/>;\n  `;\n  expect(await getImports(code)).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Button\",\n          \"importId\": \"@ds/button\",\n          \"importName\": \"Button\",\n          \"importOverride\": \"import { Button } from '@design-system/components/override';\",\n          \"isPackage\": true,\n          \"jsxDepth\": 0,\n          \"localImportName\": \"Button\",\n          \"path\": \"./src/stories/Button.tsx\",\n        },\n      ],\n      \"imports\": [\n        \"import { Button } from \"@design-system/components/override\";\",\n      ],\n    }\n  `\n  );\n});\n\n// New tests for packageName behavior\n\ntest('Converts default relative import to import override when provided', async () => {\n  const code = dedent`\n    import Button from './Button';\n\n    const meta = {};\n    export default meta;\n    export const S = <Button/>;\n  `;\n  expect(\n    await getImports(code, 'my-package', '/app/src/stories/Button.stories.tsx')\n  ).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Button\",\n          \"importId\": \"./Button\",\n          \"importName\": \"default\",\n          \"importOverride\": \"import { Button } from '@design-system/components/override';\",\n          \"isPackage\": false,\n          \"jsxDepth\": 0,\n          \"localImportName\": \"Button\",\n          \"path\": \"./src/stories/Button.tsx\",\n        },\n      ],\n      \"imports\": [\n        \"import { Button } from \"@design-system/components/override\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Keeps relative import when packageName is missing', async () => {\n  const code = dedent`\n    import { Button } from './components/Button';\n\n    const meta = {};\n    export default meta;\n    export const S = <Button/>;\n  `;\n  expect(await getImports(code)).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Button\",\n          \"importId\": \"./components/Button\",\n          \"importName\": \"Button\",\n          \"isPackage\": false,\n          \"jsxDepth\": 0,\n          \"localImportName\": \"Button\",\n        },\n      ],\n      \"imports\": [\n        \"import { Button } from \"./components/Button\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Non-relative import remains unchanged even if packageName provided', async () => {\n  const code = dedent`\n    import { Header } from '@ds/header';\n\n    const meta = {};\n    export default meta;\n    export const S = <Header/>;\n  `;\n  expect(await getImports(code, 'my-package')).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Header\",\n          \"importId\": \"@ds/header\",\n          \"importName\": \"Header\",\n          \"importOverride\": undefined,\n          \"isPackage\": true,\n          \"jsxDepth\": 0,\n          \"localImportName\": \"Header\",\n          \"path\": \"./src/stories/Header.tsx\",\n        },\n      ],\n      \"imports\": [\n        \"import { Header } from \"@ds/header\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Rewrites tilde-prefixed source to packageName', async () => {\n  const code = dedent`\n    import { Button } from '~/components/Button';\n\n    const meta = {};\n    export default meta;\n    export const S = <Button/>;\n  `;\n  expect(await getImports(code, 'pkg')).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Button\",\n          \"importId\": \"~/components/Button\",\n          \"importName\": \"Button\",\n          \"isPackage\": false,\n          \"jsxDepth\": 0,\n          \"localImportName\": \"Button\",\n        },\n      ],\n      \"imports\": [\n        \"import { Button } from \"pkg\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Rewrites hash-prefixed source to packageName', async () => {\n  const code = dedent`\n    import Btn from '#Button';\n\n    const meta = {};\n    export default meta;\n    export const S = <Btn/>;\n  `;\n  expect(await getImports(code, 'my-package')).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Btn\",\n          \"importId\": \"#Button\",\n          \"importName\": \"default\",\n          \"isPackage\": false,\n          \"jsxDepth\": 0,\n          \"localImportName\": \"Btn\",\n        },\n      ],\n      \"imports\": [\n        \"import { Btn } from \"my-package\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Does not rewrite scoped package subpath (valid bare specifier)', async () => {\n  const code = dedent`\n    import { Button } from '@scope/ui/components';\n\n    const meta = {};\n    export default meta;\n    export const S = <Button/>;\n  `;\n  expect(await getImports(code, 'pkg')).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Button\",\n          \"importId\": \"@scope/ui/components\",\n          \"importName\": \"Button\",\n          \"isPackage\": false,\n          \"jsxDepth\": 0,\n          \"localImportName\": \"Button\",\n        },\n      ],\n      \"imports\": [\n        \"import { Button } from \"pkg\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Does not rewrite unscoped package subpath (valid bare specifier)', async () => {\n  const code = dedent`\n    import { Button } from 'ui/components';\n\n    const meta = {};\n    export default meta;\n    export const S = <Button/>;\n  `;\n  expect(await getImports(code, 'pkg')).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Button\",\n          \"importId\": \"ui/components\",\n          \"importName\": \"Button\",\n          \"isPackage\": false,\n          \"jsxDepth\": 0,\n          \"localImportName\": \"Button\",\n        },\n      ],\n      \"imports\": [\n        \"import { Button } from \"pkg\";\",\n      ],\n    }\n  `\n  );\n});\n\n// Merging imports from same package\n\ntest('Merges multiple imports from the same package (defaults and named)', async () => {\n  const code = dedent`\n    import { CopilotIcon } from '@primer/octicons-react';\n    import { Banner } from \"@primer/react\";\n    import Link from \"@primer/react\";\n    import { Dialog } from \"@primer/react\";\n    import { Stack } from \"@primer/react\";\n    import { Heading } from \"@primer/react\";\n\n    const meta = {};\n    export default meta;\n    export const S = <div><Link/><Heading/><Banner/><Dialog/><Stack/><CopilotIcon/></div>;\n  `;\n  expect(await getImports(code)).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Banner\",\n          \"importId\": \"@primer/react\",\n          \"importName\": \"Banner\",\n          \"isPackage\": false,\n          \"jsxDepth\": 1,\n          \"localImportName\": \"Banner\",\n        },\n        {\n          \"componentName\": \"CopilotIcon\",\n          \"importId\": \"@primer/octicons-react\",\n          \"importName\": \"CopilotIcon\",\n          \"isPackage\": false,\n          \"jsxDepth\": 1,\n          \"localImportName\": \"CopilotIcon\",\n        },\n        {\n          \"componentName\": \"Dialog\",\n          \"importId\": \"@primer/react\",\n          \"importName\": \"Dialog\",\n          \"isPackage\": false,\n          \"jsxDepth\": 1,\n          \"localImportName\": \"Dialog\",\n        },\n        {\n          \"componentName\": \"Heading\",\n          \"importId\": \"@primer/react\",\n          \"importName\": \"Heading\",\n          \"isPackage\": false,\n          \"jsxDepth\": 1,\n          \"localImportName\": \"Heading\",\n        },\n        {\n          \"componentName\": \"Link\",\n          \"importId\": \"@primer/react\",\n          \"importName\": \"default\",\n          \"isPackage\": false,\n          \"jsxDepth\": 1,\n          \"localImportName\": \"Link\",\n        },\n        {\n          \"componentName\": \"Stack\",\n          \"importId\": \"@primer/react\",\n          \"importName\": \"Stack\",\n          \"isPackage\": false,\n          \"jsxDepth\": 1,\n          \"localImportName\": \"Stack\",\n        },\n      ],\n      \"imports\": [\n        \"import Link, { Banner, Dialog, Heading, Stack } from \"@primer/react\";\",\n        \"import { CopilotIcon } from \"@primer/octicons-react\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Handle namespace with default and separates named for same package', async () => {\n  const code = dedent`\n    import * as PR from '@primer/react';\n    import { Banner } from '@primer/react';\n    import Link from '.';\n\n    const meta = {};\n    export default meta;\n    export const S = <div><Link/><PR.Box/><Banner/></div>;\n  `;\n  expect(await getImports(code)).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Banner\",\n          \"importId\": \"@primer/react\",\n          \"importName\": \"Banner\",\n          \"isPackage\": false,\n          \"jsxDepth\": 1,\n          \"localImportName\": \"Banner\",\n        },\n        {\n          \"componentName\": \"Link\",\n          \"importId\": \".\",\n          \"importName\": \"default\",\n          \"isPackage\": false,\n          \"jsxDepth\": 1,\n          \"localImportName\": \"Link\",\n        },\n        {\n          \"componentName\": \"PR.Box\",\n          \"importId\": \"@primer/react\",\n          \"importName\": \"Box\",\n          \"isPackage\": false,\n          \"jsxDepth\": 1,\n          \"localImportName\": \"PR\",\n          \"member\": \"Box\",\n          \"namespace\": \"PR\",\n        },\n      ],\n      \"imports\": [\n        \"import * as PR from \"@primer/react\";\",\n        \"import { Banner } from \"@primer/react\";\",\n        \"import Link from \".\";\",\n      ],\n    }\n  `\n  );\n});\n\ntest('Component not imported returns undefined importId and importName', async () => {\n  const code = dedent`\n    const meta = {};\n    export default meta;\n    export const S = <Missing/>;\n  `;\n  expect(await getImports(code)).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"Missing\",\n          \"isPackage\": false,\n          \"jsxDepth\": 0,\n        },\n      ],\n      \"imports\": [],\n    }\n  `\n  );\n});\n\ntest('Namespace component not imported returns undefined importId and importName', async () => {\n  const code = dedent`\n    const meta = {};\n    export default meta;\n    export const S = <PR.Box/>;\n  `;\n  expect(await getImports(code)).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [\n        {\n          \"componentName\": \"PR.Box\",\n          \"isPackage\": false,\n          \"jsxDepth\": 0,\n          \"member\": \"Box\",\n        },\n      ],\n      \"imports\": [],\n    }\n  `\n  );\n});\n\ntest('Filters out locally defined components', async () => {\n  const code = dedent`\n    const Local = () => <div/>;\n\n    const meta = { component: Local };\n    export default meta;\n    export const S = <Local/>;\n  `;\n  expect(await getImports(code)).toMatchInlineSnapshot(\n    `\n    {\n      \"components\": [],\n      \"imports\": [],\n    }\n    `\n  );\n});\n\ntest('importOverride: default override forces default import (keeps local name)', async () => {\n  const code = dedent`\n    import { Button } from './Button';\n\n    const meta = {};\n    export default meta;\n    export const S = <Button/>;\n  `;\n  const csf = loadCsf(code, { makeTitle: (t) => t ?? 'No title' }).parse();\n  const base = await getComponentData({\n    csf,\n    packageName: 'my-package',\n    storyFilePath: '/app/src/stories/Button.stories.tsx',\n    docgenEngine: 'react-docgen',\n  });\n  const patched = base.components.map((c) =>\n    c.componentName === 'Button' ? { ...c, importOverride: \"import Button from '@pkg/button';\" } : c\n  );\n  const out = buildImports({ components: patched, packageName: 'my-package' });\n  expect(out).toMatchInlineSnapshot(`\n    [\n      \"import Button from \\\"@pkg/button\\\";\",\n    ]\n  `);\n});\n\ntest('importOverride: named override aliases imported to local name', async () => {\n  const code = dedent`\n    import Button from './Button';\n\n    const meta = {};\n    export default meta;\n    export const S = <Button/>;\n  `;\n  const csf = loadCsf(code, { makeTitle: (t) => t ?? 'No title' }).parse();\n  const base = await getComponentData({\n    csf,\n    packageName: 'pkg',\n    storyFilePath: '/app/src/stories/Button.stories.tsx',\n    docgenEngine: 'react-docgen',\n  });\n  const patched = base.components.map((c) =>\n    c.componentName === 'Button'\n      ? { ...c, importOverride: \"import { DSButton } from '@pkg/button';\" }\n      : c\n  );\n  const out = buildImports({ components: patched, packageName: 'pkg' });\n  expect(out).toMatchInlineSnapshot(`\n    [\n      \"import { DSButton as Button } from \\\"@pkg/button\\\";\",\n    ]\n  `);\n});\n\ntest('importOverride: uses namespace override as-is', async () => {\n  const code = dedent`\n    import * as UI from './ui';\n\n    const meta = {};\n    export default meta;\n    export const S = <UI.Button/>;\n  `;\n  const csf = loadCsf(code, { makeTitle: (t) => t ?? 'No title' }).parse();\n  const discovered = await getComponentData({\n    csf,\n    packageName: 'pkg',\n    storyFilePath: '/app/src/stories/ui.stories.tsx',\n    docgenEngine: 'react-docgen',\n  });\n  const patched = discovered.components.map((c) =>\n    c.componentName === 'UI.Button' ? { ...c, importOverride: \"import * as UI from '@pkg/ui';\" } : c\n  );\n  const out = buildImports({ components: patched, packageName: 'pkg' });\n  expect(out).toMatchInlineSnapshot(`\n    [\n      \"import * as UI from \\\"@pkg/ui\\\";\",\n    ]\n  `);\n});\n\ntest('importOverride: malformed string is ignored and behavior falls back', async () => {\n  const code = dedent`\n    import { Header } from './Header';\n\n    const meta = {};\n    export default meta;\n    export const S = <Header/>;\n  `;\n  const csf = loadCsf(code, { makeTitle: (t) => t ?? 'No title' }).parse();\n  const base = await getComponentData({\n    csf,\n    packageName: 'pkg',\n    storyFilePath: '/app/src/stories/Header.stories.tsx',\n    docgenEngine: 'react-docgen',\n  });\n  const patched = base.components.map((c) =>\n    c.componentName === 'Header' ? { ...c, importOverride: 'import oops not valid' } : c\n  );\n  const out = buildImports({ components: patched, packageName: 'pkg' });\n  expect(out).toMatchInlineSnapshot(`\n    [\n      \"import { Header } from \\\"pkg\\\";\",\n    ]\n  `);\n});\n\ntest('importOverride: merges multiple components into a single declaration per source', async () => {\n  const code = dedent`\n    import Button from './Button';\n    import { Header } from './Header';\n\n    const meta = {};\n    export default meta;\n    export const A = <Button/>;\n    export const B = <Header/>;\n  `;\n  const csf = loadCsf(code, { makeTitle: (t) => t ?? 'No title' }).parse();\n  const base = await getComponentData({\n    csf,\n    packageName: 'pkg',\n    storyFilePath: '/app/src/stories/multi.stories.tsx',\n    docgenEngine: 'react-docgen',\n  });\n  const patched = base.components.map((c) =>\n    c.componentName === 'Button'\n      ? { ...c, importOverride: \"import { DSButton } from '@ds/ui';\" }\n      : c.componentName === 'Header'\n        ? { ...c, importOverride: \"import { Header } from '@ds/ui';\" }\n        : c\n  );\n  const out = buildImports({ components: patched, packageName: 'pkg' });\n  expect(out).toMatchInlineSnapshot(`\n    [\n      \"import { DSButton as Button, Header } from \\\"@ds/ui\\\";\",\n    ]\n  `);\n});\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/getComponentImports.ts",
    "content": "import { dirname } from 'node:path';\n\nimport { type NodePath, babelParse, recast, types as t } from 'storybook/internal/babel';\nimport { type CsfFile } from 'storybook/internal/csf-tools';\nimport { logger } from 'storybook/internal/node-logger';\nimport type { TypescriptOptions as TypescriptOptionsBase } from 'storybook/internal/types';\n\nimport type { ParserOptions } from 'react-docgen-typescript';\n\nimport { getImportTag, getReactDocgen, matchPath } from './reactDocgen.ts';\nimport {\n  type ComponentDocWithExportName,\n  getReactDocgenTypescriptError,\n  matchComponentDoc,\n  parseWithReactDocgenTypescript,\n} from './reactDocgenTypescript.ts';\nimport type { ComponentRef } from './types.ts';\nimport { cachedResolveImport } from './utils.ts';\n\nexport type ReactDocgenConfig = 'react-docgen' | 'react-docgen-typescript' | false;\nexport type DocgenEngine = 'react-docgen' | 'react-docgen-typescript' | 'react-component-meta';\n\nexport interface TypescriptOptions extends TypescriptOptionsBase {\n  reactDocgen: ReactDocgenConfig;\n  reactDocgenTypescriptOptions: ParserOptions;\n}\n\nexport type { ComponentRef } from './types.ts';\n\n/** Selected component for a story file; `storyPath` is the absolute path on disk. */\nexport type StoryRef = {\n  storyPath: string;\n  component?: ComponentRef;\n};\n\nconst baseIdentifier = (component: string) => component.split('.')[0] ?? component;\n\nconst isTypeSpecifier = (\n  s: t.ImportSpecifier | t.ImportDefaultSpecifier | t.ImportNamespaceSpecifier\n) => t.isImportSpecifier(s) && s.importKind === 'type';\n\nconst importedName = (im: t.Identifier | t.StringLiteral) =>\n  t.isIdentifier(im) ? im.name : im.value;\n\nconst addUniqueBy = <T>(arr: T[], item: T, eq: (a: T) => boolean) => {\n  if (!arr.find(eq)) {\n    arr.push(item);\n  }\n};\n\n/**\n * Collects all React component references used by a CSF story file and resolves as much import and\n * docgen information as possible.\n *\n * Behavior:\n *\n * - Scans the AST for JSX opening elements and meta.component to discover component identifiers.\n * - Filters out components that are locally defined without an import (these are not public imports).\n * - Maps local identifiers back to their import source/specifier when available.\n * - Optionally resolves the absolute file path of each component import (using storyFilePath) and\n *   augments the result with react-docgen info and an import override tag when present.\n *\n * Notes:\n *\n * - Member expressions like Foo.Bar are supported; namespace imports are represented accordingly.\n * - Other docgen engines may populate `importOverride` eagerly; react-component-meta provides it\n *   later in ComponentMetaProject from TypeScript JSDoc tag data.\n */\nexport const getComponents = async ({\n  csf,\n  storyFilePath,\n  typescriptOptions = {},\n  docgenEngine,\n}: {\n  csf: CsfFile;\n  storyFilePath?: string;\n  typescriptOptions?: Partial<TypescriptOptions>;\n  docgenEngine: DocgenEngine;\n}): Promise<ComponentRef[]> => {\n  const { reactDocgenTypescriptOptions } = typescriptOptions;\n  const program: NodePath<t.Program> = csf._file.path;\n\n  const componentSet = new Set<string>();\n  /** Minimum JSX nesting depth per component name (1 = outermost JSX element). */\n  const componentDepth = new Map<string, number>();\n  const localToImport = new Map<string, { importId: string; importName: string }>();\n\n  // Gather components from all JSX opening elements, tracking nesting depth incrementally.\n  let jsxDepth = 0;\n  program.traverse({\n    JSXElement: {\n      enter() {\n        jsxDepth++;\n      },\n      exit() {\n        jsxDepth--;\n      },\n    },\n    JSXOpeningElement(p) {\n      const n = p.node.name;\n      let name: string | undefined;\n      if (t.isJSXIdentifier(n)) {\n        name = n.name;\n        if (name && /[A-Z]/.test(name.charAt(0))) {\n          componentSet.add(name);\n        }\n      } else if (t.isJSXMemberExpression(n)) {\n        const jsxNameToString = (nm: t.JSXIdentifier | t.JSXMemberExpression): string =>\n          t.isJSXIdentifier(nm)\n            ? nm.name\n            : `${jsxNameToString(nm.object)}.${jsxNameToString(nm.property)}`;\n        name = jsxNameToString(n);\n        componentSet.add(name);\n      }\n\n      if (name) {\n        // jsxDepth is already incremented by JSXElement.enter for the current element,\n        // so subtract 1 to get the number of *wrapping* JSX ancestors.\n        const depth = jsxDepth - 1;\n        const existing = componentDepth.get(name);\n        if (existing === undefined || depth < existing) {\n          componentDepth.set(name, depth);\n        }\n      }\n    },\n  });\n\n  // Add meta.component if present\n  const metaComp = csf._meta?.component;\n  if (metaComp) {\n    componentSet.add(metaComp);\n  }\n\n  const components = Array.from(componentSet).sort((a, b) => a.localeCompare(b));\n\n  const body = program.get('body');\n\n  // Collect import local bindings for component resolution (no package rewrite here)\n  for (const stmt of body) {\n    if (!stmt.isImportDeclaration()) {\n      continue;\n    }\n    const decl = stmt.node;\n\n    if (decl.importKind === 'type') {\n      continue;\n    }\n    const specifiers = decl.specifiers ?? [];\n\n    if (specifiers.length === 0) {\n      continue;\n    }\n\n    for (const s of specifiers) {\n      if (!('local' in s) || !s.local) {\n        continue;\n      }\n\n      if (isTypeSpecifier(s)) {\n        continue;\n      }\n\n      const importId = decl.source.value;\n      if (t.isImportDefaultSpecifier(s)) {\n        localToImport.set(s.local.name, { importId, importName: 'default' });\n      } else if (t.isImportNamespaceSpecifier(s)) {\n        localToImport.set(s.local.name, { importId, importName: '*' });\n      } else if (t.isImportSpecifier(s)) {\n        const imported = importedName(s.imported);\n        localToImport.set(s.local.name, { importId, importName: imported });\n      }\n    }\n  }\n\n  // Filter out locally defined components (those whose base identifier has a local, non-import binding)\n  const isLocallyDefinedWithoutImport = (base: string): boolean => {\n    const binding = program.scope.getBinding(base);\n\n    if (!binding) {\n      return false; // missing binding -> keep (will become null import)\n    }\n    const isImportBinding = Boolean(\n      binding.path.isImportSpecifier?.() ||\n      binding.path.isImportDefaultSpecifier?.() ||\n      binding.path.isImportNamespaceSpecifier?.()\n    );\n    return !isImportBinding;\n  };\n\n  const filteredComponents = components.filter(\n    (c) => !isLocallyDefinedWithoutImport(baseIdentifier(c))\n  );\n\n  const componentObjs = (\n    await Promise.all(\n      filteredComponents.map(async (c) => {\n        const depth = componentDepth.get(c);\n        // Split compound component names (e.g. \"Accordion.Root\") on the first dot to separate\n        // the namespace/import binding (\"Accordion\") from the accessed member (\"Root\").\n        //\n        // Three cases for compound names (dot !== -1):\n        //   1. No import found for the namespace  → keep componentName + member, no import metadata\n        //   2. Namespace import (`import * as Ns`) → importName = member (the actual export name)\n        //   3. Named import (`import { Accordion }`) → importName = original export, member carried separately\n        //\n        // Simple names (dot === -1) just look up the import binding directly.\n        const dot = c.indexOf('.');\n        const component =\n          dot !== -1\n            ? (() => {\n                const ns = c.slice(0, dot);\n                const mem = c.slice(dot + 1);\n                const direct = localToImport.get(ns);\n                return !direct\n                  ? { componentName: c, member: mem, jsxDepth: depth }\n                  : direct.importName === '*'\n                    ? {\n                        componentName: c,\n                        localImportName: ns,\n                        importId: direct.importId,\n                        importName: mem,\n                        namespace: ns,\n                        member: mem,\n                        jsxDepth: depth,\n                      }\n                    : {\n                        componentName: c,\n                        localImportName: ns,\n                        importId: direct.importId,\n                        importName: direct.importName,\n                        member: mem,\n                        jsxDepth: depth,\n                      };\n              })()\n            : (() => {\n                const direct = localToImport.get(c);\n                return direct\n                  ? {\n                      componentName: c,\n                      localImportName: c,\n                      importId: direct.importId,\n                      importName: direct.importName,\n                      jsxDepth: depth,\n                    }\n                  : { componentName: c, jsxDepth: depth };\n              })();\n\n        let path;\n        let isPackage = false;\n        try {\n          if (component.importId && storyFilePath) {\n            path = cachedResolveImport(matchPath(component.importId, dirname(storyFilePath)), {\n              basedir: dirname(storyFilePath),\n            });\n          }\n        } catch (e) {\n          logger.debug(e);\n        }\n\n        try {\n          if (component.importId && !component.importId.startsWith('.') && storyFilePath) {\n            // throws when it can not be resolved\n            cachedResolveImport(component.importId, { basedir: dirname(storyFilePath) });\n            isPackage = true;\n          }\n        } catch {}\n\n        const componentWithPackage = { ...component, isPackage };\n\n        if (path) {\n          if (docgenEngine === 'react-docgen-typescript') {\n            let reactDocgenTypescript: ComponentDocWithExportName | undefined;\n            let reactDocgenTypescriptError: { name: string; message: string } | undefined;\n            try {\n              const docs = await parseWithReactDocgenTypescript(path, reactDocgenTypescriptOptions);\n              reactDocgenTypescript = matchComponentDoc(docs, component);\n              if (!reactDocgenTypescript) {\n                reactDocgenTypescriptError = getReactDocgenTypescriptError(path, component, docs);\n              }\n            } catch (e) {\n              const message = e instanceof Error ? e.message : String(e);\n              logger.debug(`react-docgen-typescript failed for ${path}: ${message}`);\n              reactDocgenTypescriptError = {\n                name: 'react-docgen-typescript parse error',\n                message: `File: ${path}\\n${message}`,\n              };\n            }\n            const importOverride = reactDocgenTypescript\n              ? getImportTag(reactDocgenTypescript)\n              : undefined;\n\n            return {\n              ...componentWithPackage,\n              path,\n              ...(reactDocgenTypescript ? { reactDocgenTypescript } : {}),\n              ...(reactDocgenTypescriptError ? { reactDocgenTypescriptError } : {}),\n              importOverride,\n            };\n          }\n\n          if (docgenEngine === 'react-docgen') {\n            const reactDocgen = getReactDocgen(path, componentWithPackage);\n            return {\n              ...componentWithPackage,\n              path,\n              reactDocgen,\n              importOverride:\n                reactDocgen.type === 'success' ? getImportTag(reactDocgen.data) : undefined,\n            };\n          }\n\n          if (docgenEngine === 'react-component-meta') {\n            // RCM fills importOverride later in ComponentMetaProject, where the TypeScript checker\n            // is available and we can read the official JSDoc tag data from the resolved symbol.\n            // Step 2 in generator.ts mutates the selected component before Step 3 calls getImports().\n            return {\n              ...componentWithPackage,\n              path,\n            };\n          }\n        }\n        return componentWithPackage;\n      })\n    )\n  ).sort((a, b) => a.componentName.localeCompare(b.componentName));\n\n  return componentObjs;\n};\n\n/**\n * Builds a minimal, deduplicated list of import declarations required for the given components.\n *\n * Behavior:\n *\n * - Components are grouped by their (possibly rewritten) source package/path.\n * - If `packageName` is provided, relative imports are rewritten to that package name.\n * - If a component provides `importOverride`, its source and specifier are respected.\n * - Namespace imports are preserved unless a rewrite forces them to named members actually used.\n * - Default imports rewritten to a package become named imports using their local identifier.\n *\n * Output order:\n *\n * - Buckets preserve first-seen order of sources to keep declarations stable between runs.\n * - Within a bucket, namespace imports are emitted first (optionally coalesced with a default),\n *   followed by named-only, then any remaining defaults/namespaces one-per-declaration.\n *\n * @param components Component references to emit imports for. Only those with an importId are\n *   considered.\n * @param packageName Optional package name to rewrite relative imports to.\n * @returns An array of import declaration strings, formatted by recast.\n * @public\n */\nexport const getImports = ({\n  components,\n  packageName,\n}: {\n  components: ComponentRef[];\n  packageName?: string;\n}): string[] => {\n  // Group by source (after potential rewrite)\n  type Bucket = {\n    source: t.StringLiteral;\n    defaults: t.Identifier[];\n    namespaces: t.Identifier[];\n    named: t.ImportSpecifier[];\n    order: number;\n  };\n\n  const withSource = components\n    .filter((c) => Boolean(c.importId))\n    .map((c, idx) => {\n      const importId = c.importId!;\n      // If an importOverride is provided (and not a namespace import), override only the package/source\n      const overrideSource = (() => {\n        if (!c.importOverride) {\n          return undefined;\n        }\n        try {\n          const parsed = babelParse(c.importOverride);\n          const decl = parsed.program.body.find((n) => t.isImportDeclaration(n)) as\n            | t.ImportDeclaration\n            | undefined;\n          const src = decl?.source?.value;\n          return typeof src === 'string' ? src : undefined;\n        } catch {\n          return undefined;\n        }\n      })();\n      const rewritten =\n        overrideSource !== undefined\n          ? overrideSource\n          : // only rewrite to the package name it the import id is not already a valid package\n            // tsconfig paths such as ~/components/Button and components/Button are not seen as packages\n            packageName && !c.isPackage\n            ? packageName\n            : importId;\n      return { c, src: t.stringLiteral(rewritten), key: rewritten, ord: idx };\n    });\n\n  const orderOfSource: Record<string, number> = {};\n  for (const w of withSource) {\n    if (orderOfSource[w.key] === undefined) {\n      orderOfSource[w.key] = w.ord;\n    }\n  }\n\n  const buckets = new Map<string, Bucket>();\n\n  const ensureBucket = (key: string, src: t.StringLiteral): Bucket => {\n    const prev = buckets.get(key);\n\n    if (prev) {\n      return prev;\n    }\n    const b: Bucket = {\n      source: src,\n      defaults: [],\n      namespaces: [],\n      named: [],\n      order: orderOfSource[key] ?? 0,\n    };\n    buckets.set(key, b);\n    return b;\n  };\n\n  for (const { c, src, key } of withSource) {\n    const b = ensureBucket(key, src);\n\n    // Determine if this bucket was rewritten\n    const rewritten = src.value !== c.importId;\n\n    // If an importOverride provides a concrete specifier (default, named, or namespace), respect it.\n    // Do not try to match locals beyond using the bucketed structure. For namespace, just emit as-is.\n    const overrideSpec = (() => {\n      if (!c.importOverride) {\n        return undefined;\n      }\n      try {\n        const parsed = babelParse(c.importOverride);\n        const decl = parsed.program.body.find((n) => t.isImportDeclaration(n)) as\n          | t.ImportDeclaration\n          | undefined;\n        if (!decl) {\n          return undefined;\n        }\n        const spec = (decl.specifiers ?? []).find((s) => !isTypeSpecifier(s));\n        if (!spec) {\n          return undefined;\n        }\n        if (t.isImportNamespaceSpecifier(spec)) {\n          return { kind: 'namespace' as const, local: spec.local.name };\n        }\n        if (t.isImportDefaultSpecifier(spec)) {\n          return { kind: 'default' as const };\n        }\n        if (t.isImportSpecifier(spec)) {\n          const imported = t.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value;\n          return { kind: 'named' as const, imported };\n        }\n        return undefined;\n      } catch {\n        return undefined;\n      }\n    })();\n\n    if (overrideSpec) {\n      if (overrideSpec.kind === 'namespace') {\n        const ns = t.identifier(overrideSpec.local);\n        addUniqueBy(b.namespaces, ns, (n) => n.name === ns.name);\n        continue;\n      }\n      if (!c.localImportName) {\n        continue;\n      }\n      if (overrideSpec.kind === 'default') {\n        const id = t.identifier(c.localImportName);\n        addUniqueBy(b.defaults, id, (d) => d.name === id.name);\n        continue;\n      }\n      if (overrideSpec.kind === 'named') {\n        const local = t.identifier(c.localImportName);\n        const imported = t.identifier(overrideSpec.imported);\n        addUniqueBy(\n          b.named,\n          t.importSpecifier(local, imported),\n          (n) => n.local.name === local.name && importedName(n.imported) === imported.name\n        );\n        continue;\n      }\n    }\n\n    if (c.namespace) {\n      // Real namespace import usage (only present for `* as` imports)\n      if (rewritten) {\n        // Convert to named members actually used; require a concrete member name\n        if (!c.importName) {\n          continue;\n        }\n        const member = c.importName;\n        const id = t.identifier(member);\n        addUniqueBy(\n          b.named,\n          t.importSpecifier(id, id),\n          (n) => n.local.name === member && importedName(n.imported) === member\n        );\n      } else {\n        // Keep namespace import by base identifier once\n        const ns = t.identifier(c.namespace);\n        addUniqueBy(b.namespaces, ns, (n) => n.name === ns.name);\n      }\n      continue;\n    }\n\n    if (c.importName === 'default') {\n      // localImportName is only emitted for imported components; add a defensive guard for TS\n      if (!c.localImportName) {\n        continue;\n      }\n      if (rewritten) {\n        // default from relative becomes named using local identifier\n        const id = t.identifier(c.localImportName);\n        addUniqueBy(\n          b.named,\n          t.importSpecifier(id, id),\n          (n) => n.local.name === id.name && importedName(n.imported) === id.name\n        );\n      } else {\n        const id = t.identifier(c.localImportName);\n        addUniqueBy(b.defaults, id, (d) => d.name === id.name);\n      }\n      continue;\n    }\n\n    if (c.importName) {\n      // named import (including named used as namespace base)\n      if (!c.localImportName) {\n        continue;\n      }\n      const local = t.identifier(c.localImportName);\n      const imported = t.identifier(c.importName);\n      addUniqueBy(\n        b.named,\n        t.importSpecifier(local, imported),\n        (n) => n.local.name === local.name && importedName(n.imported) === imported.name\n      );\n      continue;\n    }\n  }\n\n  // Print merged declarations\n  const merged: string[] = [];\n  const printDecl = (\n    specs: (t.ImportDefaultSpecifier | t.ImportNamespaceSpecifier | t.ImportSpecifier)[],\n    src: t.StringLiteral\n  ) => {\n    const node = t.importDeclaration(specs, src);\n    const code = recast.print(node, {}).code;\n    merged.push(code);\n  };\n\n  const sortedBuckets = Array.from(buckets.values()).sort((a, b) => a.order - b.order);\n  for (const bucket of sortedBuckets) {\n    const { source, defaults, namespaces, named } = bucket;\n\n    if (defaults.length === 0 && namespaces.length === 0 && named.length === 0) {\n      continue;\n    }\n\n    if (namespaces.length > 0) {\n      const firstSpecs: (t.ImportDefaultSpecifier | t.ImportNamespaceSpecifier)[] = [];\n\n      if (defaults[0]) {\n        firstSpecs.push(t.importDefaultSpecifier(defaults[0]));\n      }\n      firstSpecs.push(t.importNamespaceSpecifier(namespaces[0]));\n      printDecl(firstSpecs, source);\n\n      if (named.length > 0) {\n        printDecl(named, source);\n      }\n\n      for (const d of defaults.slice(1)) {\n        printDecl([t.importDefaultSpecifier(d)], source);\n      }\n\n      for (const ns of namespaces.slice(1)) {\n        printDecl([t.importNamespaceSpecifier(ns)], source);\n      }\n    } else {\n      if (defaults.length > 0 || named.length > 0) {\n        const specs: (t.ImportDefaultSpecifier | t.ImportSpecifier)[] = [];\n\n        if (defaults[0]) {\n          specs.push(t.importDefaultSpecifier(defaults[0]));\n        }\n        specs.push(...named);\n        printDecl(specs, source);\n      }\n\n      for (const d of defaults.slice(1)) {\n        printDecl([t.importDefaultSpecifier(d)], source);\n      }\n    }\n  }\n\n  return merged;\n};\n\n/**\n * Convenience helper that combines `getComponents` and `getImports` in one call.\n *\n * It first discovers component references from the CSF file and then derives the minimal set of\n * import declarations for those components, applying the same rewrite/override rules as\n * `getImports`.\n *\n * @param csf The parsed CSF file instance.\n * @param packageName Optional package name used to rewrite relative imports.\n * @param storyFilePath Optional absolute path of the story file for resolving component import\n *   paths.\n * @returns An object containing the discovered components and the corresponding import statements.\n * @public\n */\nexport async function getComponentData({\n  csf,\n  packageName,\n  storyFilePath,\n  typescriptOptions,\n  docgenEngine,\n}: {\n  csf: CsfFile;\n  packageName?: string;\n  storyFilePath?: string;\n  typescriptOptions?: Partial<TypescriptOptions>;\n  docgenEngine: DocgenEngine;\n}): Promise<{\n  components: ComponentRef[];\n  imports: string[];\n}> {\n  const components = await getComponents({\n    csf,\n    storyFilePath,\n    typescriptOptions,\n    docgenEngine,\n  });\n  const imports = getImports({ components, packageName });\n  return { components, imports };\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/jsdocTags.test.ts",
    "content": "import { expect, it } from 'vitest';\n\nimport { dedent } from 'ts-dedent';\n\nimport { extractJSDocInfo } from './jsdocTags.ts';\n\nit('should extract @summary tag', () => {\n  const code = dedent`description\\n@summary\\n my summary`;\n  const tags = extractJSDocInfo(code);\n  expect(tags).toMatchInlineSnapshot(`\n    {\n      \"description\": \"description\",\n      \"tags\": {\n        \"summary\": [\n          \" my summary\",\n        ],\n      },\n    }\n  `);\n});\n\nit('should extract @param tag with type', () => {\n  const code = dedent`\n @param {Object} employee - The employee who is responsible for the project.\n @param {string} employee.name - The name of the employee.\n @param {string} employee.department - The employee's department.`;\n  const tags = extractJSDocInfo(code);\n  expect(tags).toMatchInlineSnapshot(`\n    {\n      \"description\": \"\",\n      \"tags\": {\n        \"param\": [\n          \"{Object} employee - The employee who is responsible for the project.\",\n          \"{string} employee.name - The name of the employee.\",\n          \"{string} employee.department - The employee's department.\",\n        ],\n      },\n    }\n  `);\n});\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/jsdocTags.ts",
    "content": "import { parse } from 'comment-parser';\n\nimport { groupBy } from './utils.ts';\n\nexport function extractJSDocInfo(jsdocComment: string) {\n  const lines = jsdocComment.split('\\n');\n  const jsDoc = ['/**', ...lines.map((line) => ` * ${line}`), ' */'].join('\\n');\n\n  const parsed = parse(jsDoc);\n\n  return {\n    description: parsed[0].description,\n    tags: Object.fromEntries(\n      Object.entries(groupBy(parsed[0].tags, (it) => it.tag)).map(([key, tags]) => [\n        key,\n        tags?.map((tag) => (tag.type ? `{${tag.type}} ` : '') + `${tag.name} ${tag.description}`) ??\n          [],\n      ])\n    ),\n  };\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/memfs-test-setup.ts",
    "content": "/**\n * Shared memfs mock setup for tests that use in-memory filesystem.\n *\n * Usage in test files: vi.mock('node:fs'); vi.mock('node:fs/promises'); vi.mock(import('./utils'),\n * { spy: true }); vi.mock('storybook/internal/common', { spy: true }); vi.mock('empathic/find', {\n * spy: true }); vi.mock('tsconfig-paths', { spy: true });\n *\n * BeforeEach(() => { setupMemfsMocks(); });\n */\nimport { vi } from 'vitest';\n\nimport { type JsPackageManager, JsPackageManagerFactory } from 'storybook/internal/common';\n\nimport { vol } from 'memfs';\nimport { loadConfig } from 'tsconfig-paths';\n\nimport { fsMocks } from './fixtures.ts';\nimport { cachedFindUp, cachedResolveImport, invalidateCache } from './utils.ts';\n\nexport function setupMemfsMocks() {\n  vol.reset();\n  vi.clearAllMocks();\n  invalidateCache();\n\n  vi.spyOn(process, 'cwd').mockReturnValue('/app');\n  vol.fromJSON(fsMocks, '/app');\n\n  vi.mocked(loadConfig).mockImplementation(() => ({ resultType: 'failed' as const, message: '' }));\n  vi.mocked(cachedFindUp).mockImplementation(() => '/app/package.json');\n  vi.mocked(JsPackageManagerFactory.getPackageManager).mockImplementation(\n    () =>\n      ({\n        primaryPackageJson: { packageJson: { name: 'some-package' } },\n      }) as unknown as JsPackageManager\n  );\n  vi.mocked(cachedResolveImport).mockImplementation((id) => {\n    const pkg: Record<string, string> = {\n      '@design-system/button': './src/stories/Button.tsx',\n      '@ds/button': './src/stories/Button.tsx',\n      '@ds/header': './src/stories/Header.tsx',\n      './Button': './src/stories/Button.tsx',\n      './Header': './src/stories/Header.tsx',\n    };\n    if (pkg[id]) {\n      return pkg[id];\n    }\n    throw new Error(`Unable to resolve ${id}`);\n  });\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/reactDocgen/actualNameHandler.ts",
    "content": "/**\n * This is heavily based on the react-docgen `displayNameHandler`\n * (https://github.com/reactjs/react-docgen/blob/26c90c0dd105bf83499a83826f2a6ff7a724620d/src/handlers/displayNameHandler.ts)\n * but instead defines an `actualName` property on the generated docs that is taken first from the\n * component's actual name. This addresses an issue where the name that the generated docs are\n * stored under is incorrectly named with the `displayName` and not the component's actual name.\n *\n * This is inspired by `actualNameHandler` from\n * https://github.com/storybookjs/babel-plugin-react-docgen, but is modified directly from\n * displayNameHandler, using the same approach as babel-plugin-react-docgen.\n */\nimport type { Handler, NodePath, babelTypes as t } from 'react-docgen';\nimport { utils } from 'react-docgen';\n\nconst { getNameOrValue, isReactForwardRefCall } = utils;\n\nconst actualNameHandler: Handler = function actualNameHandler(documentation, componentDefinition) {\n  documentation.set('definedInFile', componentDefinition.hub.file.opts.filename);\n\n  if (\n    (componentDefinition.isClassDeclaration() || componentDefinition.isFunctionDeclaration()) &&\n    componentDefinition.has('id')\n  ) {\n    documentation.set(\n      'actualName',\n      getNameOrValue(componentDefinition.get('id') as NodePath<t.Identifier>)\n    );\n  } else if (\n    componentDefinition.isArrowFunctionExpression() ||\n    componentDefinition.isFunctionExpression() ||\n    isReactForwardRefCall(componentDefinition)\n  ) {\n    let currentPath: NodePath = componentDefinition;\n\n    while (currentPath.parentPath) {\n      if (currentPath.parentPath.isVariableDeclarator()) {\n        documentation.set('actualName', getNameOrValue(currentPath.parentPath.get('id')));\n        return;\n      }\n      if (currentPath.parentPath.isAssignmentExpression()) {\n        const leftPath = currentPath.parentPath.get('left');\n\n        if (leftPath.isIdentifier() || leftPath.isLiteral()) {\n          documentation.set('actualName', getNameOrValue(leftPath));\n          return;\n        }\n      }\n\n      currentPath = currentPath.parentPath;\n    }\n    // Could not find an actual name\n    documentation.set('actualName', '');\n  }\n};\n\nexport default actualNameHandler;\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/reactDocgen/docgenResolver.ts",
    "content": "import { extname } from 'node:path';\n\nimport { supportedExtensions } from 'storybook/internal/common';\n\nimport resolve from 'resolve';\n\nexport class ReactDocgenResolveError extends Error {\n  // the magic string that react-docgen uses to check if a module is ignored\n  readonly code = 'MODULE_NOT_FOUND';\n\n  constructor(filename: string) {\n    super(`'${filename}' was ignored by react-docgen.`);\n  }\n}\n\n/* The below code was copied from:\n * https://github.com/reactjs/react-docgen/blob/df2daa8b6f0af693ecc3c4dc49f2246f60552bcb/packages/react-docgen/src/importer/makeFsImporter.ts#L14-L63\n * because it wasn't exported from the react-docgen package.\n */\nexport function defaultLookupModule(filename: string, basedir: string): string {\n  const resolveOptions = {\n    basedir,\n    extensions: supportedExtensions,\n    // we do not need to check core modules as we cannot import them anyway\n    includeCoreModules: false,\n  };\n\n  try {\n    return resolve.sync(filename, resolveOptions);\n  } catch (error) {\n    const ext = extname(filename);\n    let newFilename: string;\n\n    // if we try to import a JavaScript file it might be that we are actually pointing to\n    // a TypeScript file. This can happen in ES modules as TypeScript requires to import other\n    // TypeScript files with .js extensions\n    // https://www.typescriptlang.org/docs/handbook/esm-node.html#type-in-packagejson-and-new-extensions\n    switch (ext) {\n      case '.js':\n      case '.mjs':\n      case '.cjs': {\n        // Try .ts first, then fall back to .tsx (for React components using ESM-style .js imports)\n        const base = filename.slice(0, -2); // removes \"js\" keeping the dot, e.g. \"Chip.\" or \"Chip.m\"\n        try {\n          return resolve.sync(`${base}ts`, { ...resolveOptions, extensions: [] });\n        } catch {\n          newFilename = `${base}tsx`;\n        }\n        break;\n      }\n\n      case '.jsx':\n        newFilename = `${filename.slice(0, -3)}tsx`;\n        break;\n      default:\n        throw error;\n    }\n\n    return resolve.sync(newFilename, {\n      ...resolveOptions,\n      // we already know that there is an extension at this point, so no need to check other extensions\n      extensions: [],\n    });\n  }\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/reactDocgen/exportNameHandler.ts",
    "content": "/**\n * ExportNameHandler\n *\n * Sets `exportName` on the documentation:\n *\n * - 'default' for default exports\n * - The exported identifier for named exports (incl. aliases)\n * - Undefined when not exported / undetermined\n */\nimport type { Handler, NodePath, babelTypes as t } from 'react-docgen';\nimport { utils } from 'react-docgen';\n\nconst { isReactForwardRefCall } = utils;\n\n/** Extract a string name from Identifier or StringLiteral NodePath. */\nfunction nameFromId(path?: NodePath<t.Node> | null): string | undefined {\n  if (!path) {\n    return undefined;\n  }\n\n  if (path.isIdentifier()) {\n    return path.node.name;\n  }\n\n  if (path.isStringLiteral()) {\n    return path.node.value;\n  }\n  return undefined;\n}\n\n/** True if node is directly/indirectly inline default-exported. */\nfunction isInlineDefaultExport(path: NodePath<t.Node>): boolean {\n  let p: NodePath<t.Node> | null = path;\n  while (p && p.parentPath) {\n    if (p.parentPath.isExportDefaultDeclaration()) {\n      return true;\n    }\n    p = p.parentPath as NodePath<t.Node>;\n  }\n  return false;\n}\n\n/** Find the Program node that contains this path. */\nfunction findProgram(path: NodePath<t.Node>): NodePath<t.Program> | undefined {\n  const found = path.findParent((p) => p.isProgram()) as NodePath<t.Node> | null;\n  return found && found.isProgram() ? found : undefined;\n}\n\n/**\n * Determine the local identifier of the component in this file. Priority:\n *\n * 1. Provided fallback (documentation.actualName)\n * 2. Class/Function declaration `id`\n * 3. LHS of VariableDeclarator / AssignmentExpression for expressions\n */\nfunction getLocalName(\n  componentDefinition: NodePath<t.Node>,\n  fallback?: string\n): string | undefined {\n  if (fallback) {\n    return fallback;\n  }\n\n  // Named class/function declarations\n  if (\n    (componentDefinition.isClassDeclaration() || componentDefinition.isFunctionDeclaration()) &&\n    componentDefinition.has('id')\n  ) {\n    const idPath = componentDefinition.get('id') as NodePath<t.Identifier>;\n    return nameFromId(idPath);\n  }\n\n  // Expressions: arrow/function/forwardRef -> walk up to a declarator/assignment\n  if (\n    componentDefinition.isArrowFunctionExpression() ||\n    componentDefinition.isFunctionExpression() ||\n    isReactForwardRefCall(componentDefinition)\n  ) {\n    let p: NodePath<t.Node> | null = componentDefinition;\n    while (p && p.parentPath) {\n      if (p.parentPath.isVariableDeclarator()) {\n        const id = p.parentPath.get('id');\n        return nameFromId(id);\n      }\n      if (p.parentPath.isAssignmentExpression()) {\n        const left = p.parentPath.get('left');\n        const lhs = nameFromId(left);\n\n        if (lhs) {\n          return lhs;\n        }\n      }\n      p = p.parentPath as NodePath<t.Node>;\n    }\n  }\n\n  return undefined;\n}\n\nconst exportNameHandler: Handler = (documentation, componentDefinition) => {\n  // 1) Inline default export (e.g., `export default function Foo(){}`)\n  if (isInlineDefaultExport(componentDefinition)) {\n    documentation.set('exportName', 'default');\n    return;\n  }\n\n  // 2) Resolve local name we’ll match against exports\n  const actual = documentation.get('actualName');\n  const actualName = typeof actual === 'string' ? actual : undefined;\n  const localName = getLocalName(componentDefinition, actualName);\n\n  const programPath = findProgram(componentDefinition);\n  if (!programPath) {\n    documentation.set('exportName', undefined);\n    return;\n  }\n\n  const body = programPath.get('body');\n\n  // 3) Scan top-level export statements\n  for (const stmt of body) {\n    // A) `export const Foo = ...`, `export function Foo(){}`, `export class Foo {}`\n    if (stmt.isExportNamedDeclaration() && stmt.has('declaration')) {\n      const decl = stmt.get('declaration');\n\n      if (decl.isFunctionDeclaration() || decl.isClassDeclaration()) {\n        const name = nameFromId(decl.get('id') as NodePath<t.Identifier>);\n        if (name && name === localName) {\n          documentation.set('exportName', name);\n          return;\n        }\n      }\n\n      if (decl.isVariableDeclaration()) {\n        const decls = decl.get('declarations');\n        for (const d of decls) {\n          if (d.isVariableDeclarator()) {\n            const id = d.get('id');\n            if (id.isIdentifier() && id.node.name === localName) {\n              documentation.set('exportName', localName);\n              return;\n            }\n          }\n        }\n      }\n    }\n\n    // B) `export { Foo }`, `export { Foo as Bar }`, `export { Foo as default }`\n    if (stmt.isExportNamedDeclaration() && stmt.has('specifiers')) {\n      const specs = stmt.get('specifiers');\n      for (const s of specs) {\n        if (s.isExportSpecifier()) {\n          const local = nameFromId(s.get('local'));\n          const exported = nameFromId(s.get('exported'));\n          if (local && local === localName) {\n            documentation.set(\n              'exportName',\n              exported === 'default' ? 'default' : (exported ?? local)\n            );\n            return;\n          }\n        }\n      }\n    }\n\n    // C) `export default Foo`\n    if (stmt.isExportDefaultDeclaration()) {\n      const decl = stmt.get('declaration');\n      if (decl.isIdentifier() && decl.node.name === localName) {\n        documentation.set('exportName', 'default');\n        return;\n      }\n    }\n  }\n\n  // 4) Not exported / unknown\n  documentation.set('exportName', undefined);\n};\n\nexport default exportNameHandler;\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/reactDocgen/extractReactDocgenInfo.test.ts",
    "content": "import { beforeEach, describe, expect, test, vi } from 'vitest';\n\nimport { vol } from 'memfs';\nimport { dedent } from 'ts-dedent';\n\nimport { fsMocks } from '../fixtures.ts';\nimport { getComponentDocgen } from './extractReactDocgenInfo.ts';\n\nvi.mock('node:fs');\nvi.mock('node:fs/promises');\n\ndescribe('getComponentDocgen', () => {\n  beforeEach(() => {\n    vol.reset();\n    vi.spyOn(process, 'cwd').mockReturnValue('/app');\n    vol.fromJSON(fsMocks, '/app');\n  });\n\n  // Tests for getComponentDocgen function\n  test('extracts component name and docgen from a simple component file', () => {\n    const componentFilePath = '/app/src/components/Button.tsx';\n    const componentCode = dedent`\n    import React from 'react';\n\n    interface ButtonProps {\n      children: React.ReactNode;\n      variant?: 'primary' | 'secondary';\n    }\n\n    /**\n     * A simple button component\n     */\n    export const Button: React.FC<ButtonProps> = ({ children, variant = 'primary' }) => {\n      return <button className={variant}>{children}</button>;\n    };\n  `;\n\n    vol.fromJSON({\n      [componentFilePath]: componentCode,\n    });\n\n    const result = getComponentDocgen(componentFilePath);\n\n    expect(result).not.toBeNull();\n    expect(result?.componentName).toBe('Button');\n    expect(result?.reactDocgen.type).toBe('success');\n    // @ts-expect-error fix this later\n    expect(result?.reactDocgen.data.displayName).toBe('Button');\n  });\n\n  test('extracts default export component when no name specified', () => {\n    const componentFilePath = '/app/src/components/Icon.tsx';\n    const componentCode = dedent`\n    import React from 'react';\n\n    interface IconProps {\n      name: string;\n      size?: number;\n    }\n\n    /**\n     * An icon component\n     */\n    const Icon: React.FC<IconProps> = ({ name, size = 16 }) => {\n      return <span style={{ fontSize: size }}>{name}</span>;\n    };\n\n    export default Icon;\n  `;\n\n    vol.fromJSON({\n      [componentFilePath]: componentCode,\n    });\n\n    const result = getComponentDocgen(componentFilePath);\n\n    expect(result).not.toBeNull();\n    expect(result?.componentName).toBe('Icon');\n    expect(result?.reactDocgen.type).toBe('success');\n    // @ts-expect-error fix this later\n    expect(result?.reactDocgen.data.displayName).toBe('Icon');\n  });\n\n  test('finds specific component by name when multiple exports exist', () => {\n    const componentFilePath = '/app/src/components/Form.tsx';\n    const componentCode = dedent`\n    import React from 'react';\n\n    /**\n     * Input component\n     */\n    export const Input: React.FC<{ placeholder?: string }> = ({ placeholder }) => {\n      return <input placeholder={placeholder} />;\n    };\n\n    /**\n     * Label component\n     */\n    export const Label: React.FC<{ children: React.ReactNode }> = ({ children }) => {\n      return <label>{children}</label>;\n    };\n  `;\n\n    vol.fromJSON({\n      [componentFilePath]: componentCode,\n    });\n\n    const inputResult = getComponentDocgen(componentFilePath, 'Input');\n    const labelResult = getComponentDocgen(componentFilePath, 'Label');\n\n    expect(inputResult).not.toBeNull();\n    expect(inputResult?.componentName).toBe('Input');\n    // @ts-expect-error fix this later\n    expect(inputResult?.reactDocgen.data.displayName).toBe('Input');\n\n    expect(labelResult).not.toBeNull();\n    expect(labelResult?.componentName).toBe('Label');\n    // @ts-expect-error fix this later\n    expect(labelResult?.reactDocgen.data.displayName).toBe('Label');\n  });\n\n  test('returns null for non-existent component name', () => {\n    const componentFilePath = '/app/src/components/Button.tsx';\n    const componentCode = dedent`\n    import React from 'react';\n\n    export const Button: React.FC = () => {\n      return <button>Click me</button>;\n    };\n  `;\n\n    vol.fromJSON({\n      [componentFilePath]: componentCode,\n    });\n\n    const result = getComponentDocgen(componentFilePath, 'NonExistentComponent');\n\n    expect(result).toBeNull();\n  });\n\n  test('returns null for file with no components', () => {\n    const utilityFilePath = '/app/src/utils/helpers.ts';\n    const utilityCode = dedent`\n    export const formatDate = (date: Date): string => {\n      return date.toISOString();\n    };\n\n    export const capitalize = (str: string): string => {\n      return str.charAt(0).toUpperCase() + str.slice(1);\n    };\n  `;\n\n    vol.fromJSON({\n      [utilityFilePath]: utilityCode,\n    });\n\n    const result = getComponentDocgen(utilityFilePath);\n\n    expect(result).toBeNull();\n  });\n\n  test('handles file read errors gracefully', () => {\n    const nonExistentFilePath = '/app/src/components/NonExistent.tsx';\n\n    const result = getComponentDocgen(nonExistentFilePath);\n\n    expect(result).toBeNull();\n  });\n\n  test('works with TypeScript class components', () => {\n    const componentFilePath = '/app/src/components/LegacyButton.tsx';\n    const componentCode = dedent`\n    import React from 'react';\n\n    interface ButtonProps {\n      children: React.ReactNode;\n    }\n\n    /**\n     * A legacy class-based button component\n     */\n    export class LegacyButton extends React.Component<ButtonProps> {\n      render() {\n        return <button>{this.props.children}</button>;\n      }\n    }\n  `;\n\n    vol.fromJSON({\n      [componentFilePath]: componentCode,\n    });\n\n    const result = getComponentDocgen(componentFilePath);\n\n    expect(result).not.toBeNull();\n    expect(result?.componentName).toBe('LegacyButton');\n    expect(result?.reactDocgen.type).toBe('success');\n    // @ts-expect-error fix this later\n    expect(result?.reactDocgen.data.displayName).toBe('LegacyButton');\n  });\n\n  test('extracts JSDoc comments and component information', () => {\n    const componentFilePath = '/app/src/components/DetailedButton.tsx';\n    const componentCode = dedent`\n    import React from 'react';\n\n    interface DetailedButtonProps {\n      // React node\n      children: React.ReactNode;\n\n      // Literal union\n      variant?: 'primary' | 'secondary' | 'danger';\n\n      // Primitive booleans, numbers, strings\n      disabled?: boolean;\n      label?: string;\n      priority?: number;\n\n      // Date\n      createdAt?: Date;\n\n      // Array\n      tags?: string[];\n      steps?: Array<{ id: string; done: boolean }>;\n\n      // Tuple\n      coordinates?: [number, number];\n\n      // Object\n      metadata?: {\n        id: string;\n        description?: string;\n        flags?: Record<string, boolean>;\n      };\n\n      // Record/map-like object\n      styleOverrides?: Record<string, string | number>;\n\n      // Nullable/undefined union\n      note?: string | null;\n\n      // Function with parameters and return value\n      onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;\n      onClose?: () => Promise<void>;\n\n      // Discriminated union example\n      mode?:\n        | { type: 'static'; value: string }\n        | { type: 'dynamic'; compute: () => string };\n\n      // Enum-like field (numeric or string)\n      size?: 'small' | 'medium' | 'large';\n\n      // Arbitrary JSON-like struct\n      config?: unknown;\n\n      // Async data\n      fetchData?: () => Promise<{ result: string[] }>;\n\n      // Optional callback list\n      lifecycleHooks?: Array<() => void>;\n\n      // Optional custom renderer\n      renderPrefix?: () => React.ReactNode;\n    }\n\n    /**\n     * A detailed button component with comprehensive documentation\n     */\n    export const DetailedButton: React.FC<DetailedButtonProps> = ({\n      children,\n      variant = 'primary',\n      disabled = false,\n      onClick,\n    }) => {\n      return (\n        <button\n          className={variant}\n          disabled={disabled}\n          onClick={onClick}\n        >\n          {children}\n        </button>\n      );\n    };\n  `;\n\n    vol.fromJSON({\n      [componentFilePath]: componentCode,\n    });\n\n    const result = getComponentDocgen(componentFilePath);\n\n    expect(result).not.toBeNull();\n    expect(result?.componentName).toBe('DetailedButton');\n    expect(result?.reactDocgen.type).toBe('success');\n\n    // @ts-expect-error fix this later\n    const argTypesData = result?.reactDocgen.data;\n    expect(argTypesData?.displayName).toBe('DetailedButton');\n    expect(argTypesData?.description).toContain('detailed button component');\n    // Note: react-docgen may not always extract detailed prop types depending on configuration\n    expect(argTypesData?.props).toMatchInlineSnapshot(`\n    {\n      \"children\": {\n        \"description\": \"\",\n        \"required\": true,\n        \"tsType\": {\n          \"name\": \"ReactReactNode\",\n          \"raw\": \"React.ReactNode\",\n        },\n      },\n      \"config\": {\n        \"description\": \"\",\n        \"required\": false,\n        \"tsType\": {\n          \"name\": \"unknown\",\n        },\n      },\n      \"coordinates\": {\n        \"description\": \"\",\n        \"required\": false,\n        \"tsType\": {\n          \"elements\": [\n            {\n              \"name\": \"number\",\n            },\n            {\n              \"name\": \"number\",\n            },\n          ],\n          \"name\": \"tuple\",\n          \"raw\": \"[number, number]\",\n        },\n      },\n      \"createdAt\": {\n        \"description\": \"\",\n        \"required\": false,\n        \"tsType\": {\n          \"name\": \"Date\",\n        },\n      },\n      \"disabled\": {\n        \"defaultValue\": {\n          \"computed\": false,\n          \"value\": \"false\",\n        },\n        \"description\": \"\",\n        \"required\": false,\n        \"tsType\": {\n          \"name\": \"boolean\",\n        },\n      },\n      \"fetchData\": {\n        \"description\": \"\",\n        \"required\": false,\n        \"tsType\": {\n          \"name\": \"signature\",\n          \"raw\": \"() => Promise<{ result: string[] }>\",\n          \"signature\": {\n            \"arguments\": [],\n            \"return\": {\n              \"elements\": [\n                {\n                  \"name\": \"signature\",\n                  \"raw\": \"{ result: string[] }\",\n                  \"signature\": {\n                    \"properties\": [\n                      {\n                        \"key\": \"result\",\n                        \"value\": {\n                          \"elements\": [\n                            {\n                              \"name\": \"string\",\n                            },\n                          ],\n                          \"name\": \"Array\",\n                          \"raw\": \"string[]\",\n                          \"required\": true,\n                        },\n                      },\n                    ],\n                  },\n                  \"type\": \"object\",\n                },\n              ],\n              \"name\": \"Promise\",\n              \"raw\": \"Promise<{ result: string[] }>\",\n            },\n          },\n          \"type\": \"function\",\n        },\n      },\n      \"label\": {\n        \"description\": \"\",\n        \"required\": false,\n        \"tsType\": {\n          \"name\": \"string\",\n        },\n      },\n      \"lifecycleHooks\": {\n        \"description\": \"\",\n        \"required\": false,\n        \"tsType\": {\n          \"elements\": [\n            {\n              \"name\": \"signature\",\n              \"raw\": \"() => void\",\n              \"signature\": {\n                \"arguments\": [],\n                \"return\": {\n                  \"name\": \"void\",\n                },\n              },\n              \"type\": \"function\",\n            },\n          ],\n          \"name\": \"Array\",\n          \"raw\": \"Array<() => void>\",\n        },\n      },\n      \"metadata\": {\n        \"description\": \"\",\n        \"required\": false,\n        \"tsType\": {\n          \"name\": \"signature\",\n          \"raw\": \"{\n      id: string;\n      description?: string;\n      flags?: Record<string, boolean>;\n    }\",\n          \"signature\": {\n            \"properties\": [\n              {\n                \"key\": \"id\",\n                \"value\": {\n                  \"name\": \"string\",\n                  \"required\": true,\n                },\n              },\n              {\n                \"key\": \"description\",\n                \"value\": {\n                  \"name\": \"string\",\n                  \"required\": false,\n                },\n              },\n              {\n                \"key\": \"flags\",\n                \"value\": {\n                  \"elements\": [\n                    {\n                      \"name\": \"string\",\n                    },\n                    {\n                      \"name\": \"boolean\",\n                    },\n                  ],\n                  \"name\": \"Record\",\n                  \"raw\": \"Record<string, boolean>\",\n                  \"required\": false,\n                },\n              },\n            ],\n          },\n          \"type\": \"object\",\n        },\n      },\n      \"mode\": {\n        \"description\": \"\",\n        \"required\": false,\n        \"tsType\": {\n          \"elements\": [\n            {\n              \"name\": \"signature\",\n              \"raw\": \"{ type: 'static'; value: string }\",\n              \"signature\": {\n                \"properties\": [\n                  {\n                    \"key\": \"type\",\n                    \"value\": {\n                      \"name\": \"literal\",\n                      \"required\": true,\n                      \"value\": \"'static'\",\n                    },\n                  },\n                  {\n                    \"key\": \"value\",\n                    \"value\": {\n                      \"name\": \"string\",\n                      \"required\": true,\n                    },\n                  },\n                ],\n              },\n              \"type\": \"object\",\n            },\n            {\n              \"name\": \"signature\",\n              \"raw\": \"{ type: 'dynamic'; compute: () => string }\",\n              \"signature\": {\n                \"properties\": [\n                  {\n                    \"key\": \"type\",\n                    \"value\": {\n                      \"name\": \"literal\",\n                      \"required\": true,\n                      \"value\": \"'dynamic'\",\n                    },\n                  },\n                  {\n                    \"key\": \"compute\",\n                    \"value\": {\n                      \"name\": \"signature\",\n                      \"raw\": \"() => string\",\n                      \"required\": true,\n                      \"signature\": {\n                        \"arguments\": [],\n                        \"return\": {\n                          \"name\": \"string\",\n                        },\n                      },\n                      \"type\": \"function\",\n                    },\n                  },\n                ],\n              },\n              \"type\": \"object\",\n            },\n          ],\n          \"name\": \"union\",\n          \"raw\": \"| { type: 'static'; value: string }\n    | { type: 'dynamic'; compute: () => string }\",\n        },\n      },\n      \"note\": {\n        \"description\": \"\",\n        \"required\": false,\n        \"tsType\": {\n          \"elements\": [\n            {\n              \"name\": \"string\",\n            },\n            {\n              \"name\": \"null\",\n            },\n          ],\n          \"name\": \"union\",\n          \"raw\": \"string | null\",\n        },\n      },\n      \"onClick\": {\n        \"description\": \"\",\n        \"required\": false,\n        \"tsType\": {\n          \"name\": \"signature\",\n          \"raw\": \"(event: React.MouseEvent<HTMLButtonElement>) => void\",\n          \"signature\": {\n            \"arguments\": [\n              {\n                \"name\": \"event\",\n                \"type\": {\n                  \"elements\": [\n                    {\n                      \"name\": \"HTMLButtonElement\",\n                    },\n                  ],\n                  \"name\": \"ReactMouseEvent\",\n                  \"raw\": \"React.MouseEvent<HTMLButtonElement>\",\n                },\n              },\n            ],\n            \"return\": {\n              \"name\": \"void\",\n            },\n          },\n          \"type\": \"function\",\n        },\n      },\n      \"onClose\": {\n        \"description\": \"\",\n        \"required\": false,\n        \"tsType\": {\n          \"name\": \"signature\",\n          \"raw\": \"() => Promise<void>\",\n          \"signature\": {\n            \"arguments\": [],\n            \"return\": {\n              \"elements\": [\n                {\n                  \"name\": \"void\",\n                },\n              ],\n              \"name\": \"Promise\",\n              \"raw\": \"Promise<void>\",\n            },\n          },\n          \"type\": \"function\",\n        },\n      },\n      \"priority\": {\n        \"description\": \"\",\n        \"required\": false,\n        \"tsType\": {\n          \"name\": \"number\",\n        },\n      },\n      \"renderPrefix\": {\n        \"description\": \"\",\n        \"required\": false,\n        \"tsType\": {\n          \"name\": \"signature\",\n          \"raw\": \"() => React.ReactNode\",\n          \"signature\": {\n            \"arguments\": [],\n            \"return\": {\n              \"name\": \"ReactReactNode\",\n              \"raw\": \"React.ReactNode\",\n            },\n          },\n          \"type\": \"function\",\n        },\n      },\n      \"size\": {\n        \"description\": \"\",\n        \"required\": false,\n        \"tsType\": {\n          \"elements\": [\n            {\n              \"name\": \"literal\",\n              \"value\": \"'small'\",\n            },\n            {\n              \"name\": \"literal\",\n              \"value\": \"'medium'\",\n            },\n            {\n              \"name\": \"literal\",\n              \"value\": \"'large'\",\n            },\n          ],\n          \"name\": \"union\",\n          \"raw\": \"'small' | 'medium' | 'large'\",\n        },\n      },\n      \"steps\": {\n        \"description\": \"\",\n        \"required\": false,\n        \"tsType\": {\n          \"elements\": [\n            {\n              \"name\": \"signature\",\n              \"raw\": \"{ id: string; done: boolean }\",\n              \"signature\": {\n                \"properties\": [\n                  {\n                    \"key\": \"id\",\n                    \"value\": {\n                      \"name\": \"string\",\n                      \"required\": true,\n                    },\n                  },\n                  {\n                    \"key\": \"done\",\n                    \"value\": {\n                      \"name\": \"boolean\",\n                      \"required\": true,\n                    },\n                  },\n                ],\n              },\n              \"type\": \"object\",\n            },\n          ],\n          \"name\": \"Array\",\n          \"raw\": \"Array<{ id: string; done: boolean }>\",\n        },\n      },\n      \"styleOverrides\": {\n        \"description\": \"\",\n        \"required\": false,\n        \"tsType\": {\n          \"elements\": [\n            {\n              \"name\": \"string\",\n            },\n            {\n              \"elements\": [\n                {\n                  \"name\": \"string\",\n                },\n                {\n                  \"name\": \"number\",\n                },\n              ],\n              \"name\": \"union\",\n              \"raw\": \"string | number\",\n            },\n          ],\n          \"name\": \"Record\",\n          \"raw\": \"Record<string, string | number>\",\n        },\n      },\n      \"tags\": {\n        \"description\": \"\",\n        \"required\": false,\n        \"tsType\": {\n          \"elements\": [\n            {\n              \"name\": \"string\",\n            },\n          ],\n          \"name\": \"Array\",\n          \"raw\": \"string[]\",\n        },\n      },\n      \"variant\": {\n        \"defaultValue\": {\n          \"computed\": false,\n          \"value\": \"'primary'\",\n        },\n        \"description\": \"\",\n        \"required\": false,\n        \"tsType\": {\n          \"elements\": [\n            {\n              \"name\": \"literal\",\n              \"value\": \"'primary'\",\n            },\n            {\n              \"name\": \"literal\",\n              \"value\": \"'secondary'\",\n            },\n            {\n              \"name\": \"literal\",\n              \"value\": \"'danger'\",\n            },\n          ],\n          \"name\": \"union\",\n          \"raw\": \"'primary' | 'secondary' | 'danger'\",\n        },\n      },\n    }\n  `);\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/reactDocgen/extractReactDocgenInfo.ts",
    "content": "import { logger } from 'storybook/internal/node-logger';\n\nimport { extractArgTypes } from '../../extractArgTypes.ts';\nimport { type getReactDocgen, parseWithReactDocgen } from '../reactDocgen.ts';\nimport { cachedReadFileSync } from '../utils.ts';\nimport { type GetArgTypesDataOptions } from './utils.ts';\n\n/**\n * Extracts component name and React docgen data from a component file.\n *\n * This function reads a component file and uses react-docgen to parse its documentation and type\n * information. If a component name is provided, it will attempt to find that specific component's\n * documentation. If no name is provided, it will return the first component found or the default\n * export.\n *\n * @param filePath The absolute path to the component file.\n * @param componentName Optional name of the specific component to extract (if multiple components\n *   exist in the file).\n * @returns An object containing the component name and its react-docgen data, or null if no\n *   component is found.\n * @public\n */\nexport function getComponentDocgen(\n  filePath: string,\n  componentName?: string\n): { componentName: string; reactDocgen: ReturnType<typeof getReactDocgen> } | null {\n  try {\n    const code = cachedReadFileSync(filePath, 'utf-8') as string;\n    const docgens = parseWithReactDocgen(code, filePath);\n\n    if (docgens.length === 0) {\n      return null;\n    }\n\n    // If a specific component name is requested, find it\n    if (componentName) {\n      const matchingDocgen = docgens.find(\n        (docgen) =>\n          docgen.actualName === componentName ||\n          docgen.displayName === componentName ||\n          docgen.exportName === componentName\n      );\n\n      if (matchingDocgen) {\n        return {\n          componentName: matchingDocgen.actualName || matchingDocgen.displayName || componentName,\n          reactDocgen: { type: 'success', data: matchingDocgen },\n        };\n      }\n\n      // If a specific component name was requested but not found, return null\n      return null;\n    }\n\n    // Otherwise, return the first component found (typically the default export)\n    const firstDocgen = docgens[0];\n    return {\n      componentName: firstDocgen.actualName || firstDocgen.displayName || 'Unknown',\n      reactDocgen: { type: 'success', data: firstDocgen },\n    };\n  } catch (error) {\n    logger.debug(`Error parsing component file for docgen ${filePath}: ${error}`);\n    return null;\n  }\n}\n\nexport const extractArgTypesFromDocgen = ({\n  componentFilePath,\n  componentExportName,\n}: GetArgTypesDataOptions) => {\n  const docgen = getComponentDocgen(componentFilePath, componentExportName);\n\n  if (!docgen || docgen.reactDocgen.type !== 'success') {\n    return null;\n  }\n\n  return extractArgTypes({ __docgenInfo: docgen.reactDocgen.data }) ?? {};\n};\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/reactDocgen/extractReactTypescriptDocgenInfo.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { extractComponentProps } from 'storybook/internal/docs-tools';\n\nimport { extractProps } from '../../extractProps.ts';\n\n// TODO: Norbert figure this out thank you\ndescribe('extractArgTypesFromDocgenTypescript', () => {\n  it('should extract arg types from a simple component', async () => {\n    const tsDocgenData = {\n      name: {\n        defaultValue: null,\n        description: '',\n        name: 'name',\n        declarations: [],\n        required: false,\n        type: {\n          name: 'string',\n        },\n      },\n      strength: {\n        defaultValue: null,\n        description: '',\n        name: 'strength',\n        declarations: [],\n        required: false,\n        type: {\n          name: 'string | number',\n        },\n      },\n      image: {\n        defaultValue: null,\n        description: '',\n        name: 'image',\n        declarations: [],\n        required: true,\n        type: {\n          name: 'enum',\n          raw: '\"image/foo.png\" | \"image/bar.jpg\"',\n          value: [\n            {\n              value: '\"image/foo.png\"',\n            },\n            {\n              value: '\"image/bar.jpg\"',\n            },\n          ],\n        },\n      },\n      background: {\n        defaultValue: null,\n        description: '',\n        name: 'background',\n        declarations: [\n          {\n            fileName: 'dune-assets/src/card/traitor/Traitor.tsx',\n            name: 'TypeLiteral',\n          },\n        ],\n        required: true,\n        type: {\n          name: 'string',\n        },\n      },\n      owner: {\n        defaultValue: null,\n        description: '',\n        name: 'owner',\n        declarations: [\n          {\n            fileName: 'dune-assets/src/card/traitor/Traitor.tsx',\n            name: 'TypeLiteral',\n          },\n        ],\n        required: true,\n        type: {\n          name: 'string',\n        },\n      },\n    };\n\n    expect(extractProps({ __docgenInfo: tsDocgenData })).toMatchInlineSnapshot(`\n      {\n        \"rows\": [],\n      }\n    `);\n  });\n\n  it('original flow data', () => {\n    const data = {\n      description: '',\n      displayName: 'AllianceCard',\n      props: {\n        text: {\n          defaultValue: null,\n          description: '',\n          name: 'text',\n          required: true,\n          type: {\n            name: 'string',\n          },\n        },\n        background: {\n          defaultValue: null,\n          description: '',\n          name: 'background',\n          required: true,\n          type: {\n            name: 'string',\n          },\n        },\n        name: {\n          defaultValue: null,\n          description: '',\n          name: 'name',\n          required: true,\n          type: {\n            name: 'string',\n          },\n        },\n        troop: {\n          defaultValue: null,\n          description: '',\n          name: 'troop',\n          required: true,\n          type: {\n            name: 'enum',\n            value: [\n              {\n                value: '\"vector/troop/atreides.svg\"',\n              },\n              {\n                value: '\"vector/troop/smuggler.svg\"',\n              },\n            ],\n          },\n        },\n        logo: {\n          defaultValue: null,\n          description: '',\n          name: 'logo',\n          required: true,\n          type: {\n            name: 'enum',\n            value: [\n              {\n                value: '\"vector/troop/atreides.svg\"',\n              },\n              {\n                value: '\"vector/troop/smuggler.svg\"',\n              },\n              {\n                value: '\"vector/generic/x.svg\"',\n              },\n              {\n                value: '\"vector/generic/zap.svg\"',\n              },\n              {\n                value: '\"vector/logo/moritani.svg\"',\n              },\n              {\n                value: '\"vector/logo/richese.svg\"',\n              },\n              {\n                value: '\"vector/decal/weirding-way-multicolor.svg\"',\n              },\n              {\n                value: '\"vector/decal/weirding-way-plus.svg\"',\n              },\n              {\n                value: '\"vector/decal/weirding-way.svg\"',\n              },\n              {\n                value: '\"vector/decal/wire.svg\"',\n              },\n              {\n                value: '\"vector/decal/zenobia.svg\"',\n              },\n              {\n                value: '\"vector/icon/waves.svg\"',\n              },\n              {\n                value: '\"vector/icon/worthless.svg\"',\n              },\n              {\n                value: '\"vector/icon/wreath.svg\"',\n              },\n            ],\n          },\n        },\n        decals: {\n          defaultValue: null,\n          description: '',\n          name: 'decals',\n          required: true,\n          type: {\n            name: '{ id: \"vector/troop/atreides.svg\" | \"vector/troop/smuggler.svg\" | \"vector/generic/x.svg\" | \"vector/generic/zap.svg\" | \"vector/logo/moritani.svg\" | \"vector/logo/richese.svg\" | ... 7 more ... | \"vector/icon/wreath.svg\"; scale: number; offset: [...]; outline: boolean; muted: boolean; }[]',\n          },\n        },\n      },\n    };\n\n    expect(extractComponentProps({ __docgenInfo: data }, 'props')).toMatchInlineSnapshot(`\n      [\n        {\n          \"docgenInfo\": {\n            \"defaultValue\": null,\n            \"description\": \"\",\n            \"name\": \"text\",\n            \"required\": true,\n            \"type\": {\n              \"name\": \"string\",\n            },\n          },\n          \"jsDocTags\": undefined,\n          \"propDef\": {\n            \"defaultValue\": null,\n            \"description\": \"\",\n            \"name\": \"text\",\n            \"required\": true,\n            \"sbType\": {\n              \"name\": \"string\",\n            },\n            \"type\": {\n              \"detail\": undefined,\n              \"summary\": \"string\",\n            },\n          },\n          \"typeSystem\": \"JavaScript\",\n        },\n        {\n          \"docgenInfo\": {\n            \"defaultValue\": null,\n            \"description\": \"\",\n            \"name\": \"background\",\n            \"required\": true,\n            \"type\": {\n              \"name\": \"string\",\n            },\n          },\n          \"jsDocTags\": undefined,\n          \"propDef\": {\n            \"defaultValue\": null,\n            \"description\": \"\",\n            \"name\": \"background\",\n            \"required\": true,\n            \"sbType\": {\n              \"name\": \"string\",\n            },\n            \"type\": {\n              \"detail\": undefined,\n              \"summary\": \"string\",\n            },\n          },\n          \"typeSystem\": \"JavaScript\",\n        },\n        {\n          \"docgenInfo\": {\n            \"defaultValue\": null,\n            \"description\": \"\",\n            \"name\": \"name\",\n            \"required\": true,\n            \"type\": {\n              \"name\": \"string\",\n            },\n          },\n          \"jsDocTags\": undefined,\n          \"propDef\": {\n            \"defaultValue\": null,\n            \"description\": \"\",\n            \"name\": \"name\",\n            \"required\": true,\n            \"sbType\": {\n              \"name\": \"string\",\n            },\n            \"type\": {\n              \"detail\": undefined,\n              \"summary\": \"string\",\n            },\n          },\n          \"typeSystem\": \"JavaScript\",\n        },\n        {\n          \"docgenInfo\": {\n            \"defaultValue\": null,\n            \"description\": \"\",\n            \"name\": \"troop\",\n            \"required\": true,\n            \"type\": {\n              \"name\": \"enum\",\n              \"value\": [\n                {\n                  \"value\": \"\"vector/troop/atreides.svg\"\",\n                },\n                {\n                  \"value\": \"\"vector/troop/smuggler.svg\"\",\n                },\n              ],\n            },\n          },\n          \"jsDocTags\": undefined,\n          \"propDef\": {\n            \"defaultValue\": null,\n            \"description\": \"\",\n            \"name\": \"troop\",\n            \"required\": true,\n            \"sbType\": {\n              \"name\": \"enum\",\n              \"value\": [\n                \"vector/troop/atreides.svg\",\n                \"vector/troop/smuggler.svg\",\n              ],\n            },\n            \"type\": {\n              \"detail\": undefined,\n              \"summary\": \"enum\",\n            },\n          },\n          \"typeSystem\": \"JavaScript\",\n        },\n        {\n          \"docgenInfo\": {\n            \"defaultValue\": null,\n            \"description\": \"\",\n            \"name\": \"logo\",\n            \"required\": true,\n            \"type\": {\n              \"name\": \"enum\",\n              \"value\": [\n                {\n                  \"value\": \"\"vector/troop/atreides.svg\"\",\n                },\n                {\n                  \"value\": \"\"vector/troop/smuggler.svg\"\",\n                },\n                {\n                  \"value\": \"\"vector/generic/x.svg\"\",\n                },\n                {\n                  \"value\": \"\"vector/generic/zap.svg\"\",\n                },\n                {\n                  \"value\": \"\"vector/logo/moritani.svg\"\",\n                },\n                {\n                  \"value\": \"\"vector/logo/richese.svg\"\",\n                },\n                {\n                  \"value\": \"\"vector/decal/weirding-way-multicolor.svg\"\",\n                },\n                {\n                  \"value\": \"\"vector/decal/weirding-way-plus.svg\"\",\n                },\n                {\n                  \"value\": \"\"vector/decal/weirding-way.svg\"\",\n                },\n                {\n                  \"value\": \"\"vector/decal/wire.svg\"\",\n                },\n                {\n                  \"value\": \"\"vector/decal/zenobia.svg\"\",\n                },\n                {\n                  \"value\": \"\"vector/icon/waves.svg\"\",\n                },\n                {\n                  \"value\": \"\"vector/icon/worthless.svg\"\",\n                },\n                {\n                  \"value\": \"\"vector/icon/wreath.svg\"\",\n                },\n              ],\n            },\n          },\n          \"jsDocTags\": undefined,\n          \"propDef\": {\n            \"defaultValue\": null,\n            \"description\": \"\",\n            \"name\": \"logo\",\n            \"required\": true,\n            \"sbType\": {\n              \"name\": \"enum\",\n              \"value\": [\n                \"vector/troop/atreides.svg\",\n                \"vector/troop/smuggler.svg\",\n                \"vector/generic/x.svg\",\n                \"vector/generic/zap.svg\",\n                \"vector/logo/moritani.svg\",\n                \"vector/logo/richese.svg\",\n                \"vector/decal/weirding-way-multicolor.svg\",\n                \"vector/decal/weirding-way-plus.svg\",\n                \"vector/decal/weirding-way.svg\",\n                \"vector/decal/wire.svg\",\n                \"vector/decal/zenobia.svg\",\n                \"vector/icon/waves.svg\",\n                \"vector/icon/worthless.svg\",\n                \"vector/icon/wreath.svg\",\n              ],\n            },\n            \"type\": {\n              \"detail\": undefined,\n              \"summary\": \"enum\",\n            },\n          },\n          \"typeSystem\": \"JavaScript\",\n        },\n        {\n          \"docgenInfo\": {\n            \"defaultValue\": null,\n            \"description\": \"\",\n            \"name\": \"decals\",\n            \"required\": true,\n            \"type\": {\n              \"name\": \"{ id: \"vector/troop/atreides.svg\" | \"vector/troop/smuggler.svg\" | \"vector/generic/x.svg\" | \"vector/generic/zap.svg\" | \"vector/logo/moritani.svg\" | \"vector/logo/richese.svg\" | ... 7 more ... | \"vector/icon/wreath.svg\"; scale: number; offset: [...]; outline: boolean; muted: boolean; }[]\",\n            },\n          },\n          \"jsDocTags\": undefined,\n          \"propDef\": {\n            \"defaultValue\": null,\n            \"description\": \"\",\n            \"name\": \"decals\",\n            \"required\": true,\n            \"sbType\": {\n              \"name\": \"other\",\n              \"value\": \"{ id: \"vector/troop/atreides.svg\" | \"vector/troop/smuggler.svg\" | \"vector/generic/x.svg\" | \"vector/generic/zap.svg\" | \"vector/logo/moritani.svg\" | \"vector/logo/richese.svg\" | ... 7 more ... | \"vector/icon/wreath.svg\"; scale: number; offset: [...]; outline: boolean; muted: boolean; }[]\",\n            },\n            \"type\": {\n              \"detail\": undefined,\n              \"summary\": \"{ id: \"vector/troop/atreides.svg\" | \"vector/troop/smuggler.svg\" | \"vector/generic/x.svg\" | \"vector/generic/zap.svg\" | \"vector/logo/moritani.svg\" | \"vector/logo/richese.svg\" | ... 7 more ... | \"vector/icon/wreath.svg\"; scale: number; offset: [...]; outline: boolean; muted: boolean; }[]\",\n            },\n          },\n          \"typeSystem\": \"JavaScript\",\n        },\n      ]\n    `);\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/reactDocgen/extractReactTypescriptDocgenInfo.ts",
    "content": "import { logger } from 'storybook/internal/node-logger';\n\nimport type { ParserOptions as ReactDocgenTypescriptOptions } from 'react-docgen-typescript';\n\nimport { extractArgTypes } from '../../extractArgTypes.ts';\nimport { type GetArgTypesDataOptions, getTsConfig } from './utils.ts';\n\ninterface PropFilterProps {\n  parent?: { fileName: string };\n}\n\ninterface ComponentDocgenResult {\n  displayName?: string;\n  filePath?: string;\n  props?: Record<string, { type?: { name: string }; required?: boolean }>;\n}\n\n/**\n * Extracts component arg types from a file using react-docgen-typescript.\n *\n * This function uses the TypeScript compiler to parse component files and extract prop types with\n * more accurate type information, especially for complex TypeScript types.\n */\nexport const extractArgTypesFromDocgenTypescript = async ({\n  componentFilePath,\n  componentExportName,\n  reactDocgenTypescriptOptions,\n}: GetArgTypesDataOptions) => {\n  try {\n    // Using dynamic import for react-docgen-typescript\n    const { withCompilerOptions } = (await import('react-docgen-typescript')).default;\n\n    // Default options that match Storybook's expected behavior\n    const defaultOptions: ReactDocgenTypescriptOptions = {\n      shouldExtractLiteralValuesFromEnum: true,\n      shouldRemoveUndefinedFromOptional: true,\n      propFilter: (prop: PropFilterProps) =>\n        prop.parent ? !/node_modules/.test(prop.parent.fileName) : true,\n      // We *need* this set so that RDT returns default values in the same format as react-docgen\n      savePropValueAsString: true,\n    };\n\n    const tsConfig = await getTsConfig();\n\n    const mergedOptions = {\n      ...defaultOptions,\n      ...reactDocgenTypescriptOptions,\n      // Always ensure savePropValueAsString is true for consistency\n      savePropValueAsString: true,\n    };\n    const parser = withCompilerOptions(\n      { ...tsConfig, noErrorTruncation: true, strict: true },\n      mergedOptions\n    );\n    const docgens = parser.parse(componentFilePath) as ComponentDocgenResult[];\n\n    if (!docgens || docgens.length === 0) {\n      return null;\n    }\n\n    // Find the matching component if a name is specified\n    let targetDocgen = docgens[0];\n    if (componentExportName) {\n      const match = docgens.find(\n        (d) => d.displayName === componentExportName || d.filePath?.includes(componentExportName)\n      );\n      if (match) {\n        targetDocgen = match;\n      } else {\n        // If specific component requested but not found, return null\n        return null;\n      }\n    }\n    return extractArgTypes({ __docgenInfo: targetDocgen }) ?? {};\n  } catch (error) {\n    logger.debug(\n      `Error parsing component file with react-docgen-typescript ${componentFilePath}: ${error}`\n    );\n    return null;\n  }\n};\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/reactDocgen/utils.ts",
    "content": "import type { SBType } from 'storybook/internal/csf';\n\nimport { dirname } from 'path';\nimport type {\n  ElementsType,\n  LiteralType,\n  ObjectSignatureType,\n  TSFunctionSignatureType,\n  TypeDescriptor,\n} from 'react-docgen';\nimport type { ParserOptions as ReactDocgenTypescriptOptions } from 'react-docgen-typescript';\n\nexport type ReactDocgenConfig = 'react-docgen' | 'react-docgen-typescript' | false;\n\nexport type GetArgTypesDataOptions = {\n  componentFilePath: string;\n  componentExportName?: string;\n  reactDocgen?: ReactDocgenConfig;\n  reactDocgenTypescriptOptions?: ReactDocgenTypescriptOptions;\n};\n\nexport type ReactDocgenTsType = TypeDescriptor<TSFunctionSignatureType>;\nexport type ReactDocgenElementsType = ElementsType<TSFunctionSignatureType>;\nexport type ReactDocgenObjectSignatureType = ObjectSignatureType<TSFunctionSignatureType>;\nexport type ReactDocgenLiteralType = LiteralType;\n\nexport const REACT_NODE_TYPES = new Set<string>([\n  'JSX.Element',\n  'ComponentType',\n  'ReactComponentType',\n  'ReactElement',\n  'ReactReactElement',\n  'ElementType',\n  'ReactElementType',\n  'ReactNode',\n  'ReactReactNode',\n]);\n\n// Types that are considered \"known\" and should be mapped recursively in arrays\nexport const KNOWN_TYPE_NAMES = new Set([\n  'boolean',\n  'string',\n  'number',\n  'Date',\n  ...REACT_NODE_TYPES,\n  'signature',\n  'union',\n  'Array',\n  'tuple',\n  'literal',\n  'null',\n  'void',\n  'any',\n  'unknown',\n]);\n\n/** Check if a type name represents a React node type */\nexport function isReactNodeType(typeName: string): boolean {\n  if (REACT_NODE_TYPES.has(typeName)) {\n    return true;\n  }\n  // Handle React. prefixed versions and generics (for react-docgen-typescript)\n  if (\n    typeName === 'React.ReactNode' ||\n    typeName === 'React.ReactElement' ||\n    typeName.startsWith('ReactElement<') ||\n    typeName.startsWith('React.ReactElement<')\n  ) {\n    return true;\n  }\n  return false;\n}\n\nexport function isElementsType(value: ReactDocgenTsType): value is ReactDocgenElementsType {\n  return 'elements' in value;\n}\n\nexport function isObjectSignatureType(\n  value: ReactDocgenTsType\n): value is ReactDocgenObjectSignatureType {\n  return value.name === 'signature' && (value as ReactDocgenObjectSignatureType).type === 'object';\n}\n\nexport function isLiteralType(value: ReactDocgenTsType): value is ReactDocgenLiteralType {\n  return value.name === 'literal';\n}\n\n/**\n * Common mappings for primitive and React node types for both react-docgen and\n * react-docgen-typescript\n */\nexport function mapCommonTypes(typeName: string): SBType | null {\n  // Handle primitives\n  if (typeName === 'boolean') {\n    return { name: 'boolean' };\n  }\n  if (typeName === 'string') {\n    return { name: 'string' };\n  }\n  if (typeName === 'number') {\n    return { name: 'number' };\n  }\n  if (typeName === 'Date') {\n    return { name: 'date' };\n  }\n\n  // Handle React node types\n  if (isReactNodeType(typeName)) {\n    return { name: 'node', renderer: 'react' };\n  }\n\n  // Handle special types\n  if (typeName === 'null') {\n    return { name: 'other', value: 'null' };\n  }\n  if (typeName === 'void') {\n    return { name: 'other', value: 'void' };\n  }\n  if (typeName === 'any') {\n    return { name: 'other', value: 'any' };\n  }\n  if (typeName === 'unknown') {\n    return { name: 'other', value: 'unknown' };\n  }\n\n  return null;\n}\n\nexport const getTsConfig = async () => {\n  try {\n    const ts = await import('typescript');\n    const tsconfigPath = ts.findConfigFile(process.cwd(), ts.sys.fileExists);\n    console.log({ tsconfigPath });\n    if (tsconfigPath === undefined) {\n      return {};\n    }\n    const basePath = dirname(tsconfigPath);\n    const { config, error } = ts.readConfigFile(tsconfigPath, ts.sys.readFile);\n    if (error) {\n      return {};\n    }\n\n    return ts.parseJsonConfigFileContent(config, ts.sys, basePath, {}, tsconfigPath).options;\n  } catch {\n    return {};\n  }\n};\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/reactDocgen.test.ts",
    "content": "import { beforeEach, describe, expect, test } from 'vitest';\n\nimport { dedent } from 'ts-dedent';\n\nimport { parseWithReactDocgen } from './reactDocgen.ts';\nimport { invalidateCache } from './utils.ts';\n\nbeforeEach(() => {\n  invalidateCache();\n});\n\nasync function parse(code: string, name = 'Component.tsx') {\n  const filename = `/virtual/${name}`;\n  return parseWithReactDocgen(code, filename);\n}\n\ndescribe('parseWithReactDocgen exportName coverage', () => {\n  test('inline default export function declaration', async () => {\n    const code = dedent /* tsx */ `\n      import React from 'react';\n      export default function Foo() { return <></> }\n    `;\n    expect(await parse(code)).toMatchInlineSnapshot(`\n      [\n        {\n          \"actualName\": \"Foo\",\n          \"definedInFile\": \"/virtual/Component.tsx\",\n          \"description\": \"\",\n          \"displayName\": \"Foo\",\n          \"exportName\": \"default\",\n          \"methods\": [],\n        },\n      ]\n    `);\n  });\n\n  test('inline default export class declaration', async () => {\n    const code = dedent /* tsx */ `\n      import React from 'react';\n      export default class Foo extends React.Component { render(){ return null } }\n    `;\n    expect(await parse(code)).toMatchInlineSnapshot(`\n      [\n        {\n          \"actualName\": \"Foo\",\n          \"definedInFile\": \"/virtual/Component.tsx\",\n          \"description\": \"\",\n          \"displayName\": \"Foo\",\n          \"exportName\": \"default\",\n          \"methods\": [],\n        },\n      ]\n    `);\n  });\n\n  test('inline anonymous default export (arrow function)', async () => {\n    const code = dedent /* tsx */ `\n      export default () => <div/>;\n    `;\n    expect(await parse(code)).toMatchInlineSnapshot(`\n      [\n        {\n          \"actualName\": \"\",\n          \"definedInFile\": \"/virtual/Component.tsx\",\n          \"description\": \"\",\n          \"exportName\": \"default\",\n          \"methods\": [],\n        },\n      ]\n    `);\n  });\n\n  test('separate default export identifier', async () => {\n    const code = dedent /* tsx */ `\n      const Foo = () => <div/>;\n      export default Foo;\n    `;\n    expect(await parse(code)).toMatchInlineSnapshot(`\n      [\n        {\n          \"actualName\": \"Foo\",\n          \"definedInFile\": \"/virtual/Component.tsx\",\n          \"description\": \"\",\n          \"displayName\": \"Foo\",\n          \"exportName\": \"default\",\n          \"methods\": [],\n        },\n      ]\n    `);\n  });\n\n  test('named export: export const Foo = ...', async () => {\n    const code = dedent /* tsx */ `\n      export const Foo = () => <div/>;\n    `;\n    expect(await parse(code)).toMatchInlineSnapshot(`\n      [\n        {\n          \"actualName\": \"Foo\",\n          \"definedInFile\": \"/virtual/Component.tsx\",\n          \"description\": \"\",\n          \"displayName\": \"Foo\",\n          \"exportName\": \"Foo\",\n          \"methods\": [],\n        },\n      ]\n    `);\n  });\n\n  test('named export: export function Foo() {}', async () => {\n    const code = dedent /* tsx */ `\n      export function Foo() { return <div/> }\n    `;\n    expect(await parse(code)).toMatchInlineSnapshot(`\n      [\n        {\n          \"actualName\": \"Foo\",\n          \"definedInFile\": \"/virtual/Component.tsx\",\n          \"description\": \"\",\n          \"displayName\": \"Foo\",\n          \"exportName\": \"Foo\",\n          \"methods\": [],\n        },\n      ]\n    `);\n  });\n\n  test('export list: export { Foo }', async () => {\n    const code = dedent /* tsx */ `\n      const Foo = () => <div/>;\n      export { Foo };\n    `;\n    expect(await parse(code)).toMatchInlineSnapshot(`\n      [\n        {\n          \"actualName\": \"Foo\",\n          \"definedInFile\": \"/virtual/Component.tsx\",\n          \"description\": \"\",\n          \"displayName\": \"Foo\",\n          \"exportName\": \"Foo\",\n          \"methods\": [],\n        },\n      ]\n    `);\n  });\n\n  test('aliased named export: export { Foo as Bar }', async () => {\n    const code = dedent /* tsx */ `\n      const Foo = () => <div/>;\n      export { Foo as Bar };\n    `;\n    expect(await parse(code)).toMatchInlineSnapshot(`\n      [\n        {\n          \"actualName\": \"Foo\",\n          \"definedInFile\": \"/virtual/Component.tsx\",\n          \"description\": \"\",\n          \"displayName\": \"Foo\",\n          \"exportName\": \"Bar\",\n          \"methods\": [],\n        },\n      ]\n    `);\n  });\n\n  test('aliased to default: export { Foo as default }', async () => {\n    const code = dedent /* tsx */ `\n      const Foo = () => <div/>;\n      export { Foo as default };\n    `;\n    expect(await parse(code)).toMatchInlineSnapshot(`\n      [\n        {\n          \"actualName\": \"Foo\",\n          \"definedInFile\": \"/virtual/Component.tsx\",\n          \"description\": \"\",\n          \"displayName\": \"Foo\",\n          \"exportName\": \"default\",\n          \"methods\": [],\n        },\n      ]\n    `);\n  });\n\n  test('multiple components with different export styles', async () => {\n    const code = dedent /* tsx */ `\n      export function A(){ return null }\n      const B = () => <div/>;\n      export { B as Beta };\n      const C = () => <div/>;\n      export default C;\n    `;\n    expect(await parse(code)).toMatchInlineSnapshot(`\n      [\n        {\n          \"actualName\": \"B\",\n          \"definedInFile\": \"/virtual/Component.tsx\",\n          \"description\": \"\",\n          \"displayName\": \"B\",\n          \"exportName\": \"Beta\",\n          \"methods\": [],\n        },\n        {\n          \"actualName\": \"C\",\n          \"definedInFile\": \"/virtual/Component.tsx\",\n          \"description\": \"\",\n          \"displayName\": \"C\",\n          \"exportName\": \"default\",\n          \"methods\": [],\n        },\n      ]\n    `);\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/reactDocgen.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { dirname, sep } from 'node:path';\n\nimport { babelParse, types as t } from 'storybook/internal/babel';\nimport { supportedExtensions } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport {\n  type Documentation,\n  builtinHandlers as docgenHandlers,\n  builtinResolvers as docgenResolver,\n  makeFsImporter,\n  parse,\n} from 'react-docgen';\nimport { dedent } from 'ts-dedent';\nimport * as TsconfigPaths from 'tsconfig-paths';\n\nimport { type ComponentRef } from './getComponentImports.ts';\nimport { extractJSDocInfo } from './jsdocTags.ts';\nimport actualNameHandler from './reactDocgen/actualNameHandler.ts';\nimport { ReactDocgenResolveError } from './reactDocgen/docgenResolver.ts';\nimport exportNameHandler from './reactDocgen/exportNameHandler.ts';\nimport { cached, cachedReadFileSync, cachedResolveImport, findTsconfigPath } from './utils.ts';\n\nexport type DocObj = Documentation & {\n  actualName: string;\n  definedInFile: string;\n  exportName?: string;\n};\n\n// TODO: None of these are able to be overridden, so `default` is aspirational here.\nconst defaultHandlers = Object.values(docgenHandlers).map((handler) => handler);\nconst defaultResolver = new docgenResolver.FindExportedDefinitionsResolver();\nconst handlers = [...defaultHandlers, actualNameHandler, exportNameHandler];\n\nexport function getMatchingDocgen(docgens: DocObj[], component: ComponentRef) {\n  if (docgens.length === 0) {\n    return;\n  }\n  if (docgens.length === 1) {\n    return docgens[0];\n  }\n\n  const matchingDocgen =\n    docgens.find((docgen) =>\n      [component.importName, component.localImportName].includes(docgen.exportName)\n    ) ??\n    docgens.find(\n      (docgen) =>\n        [component.importName, component.localImportName, component.componentName].includes(\n          docgen.displayName\n        ) ||\n        [component.importName, component.localImportName, component.componentName].includes(\n          docgen.actualName\n        )\n    );\n\n  return matchingDocgen ?? docgens[0];\n}\n\nexport function matchPath(id: string, basedir?: string) {\n  basedir ??= process.cwd();\n  const tsconfig = getTsConfig(basedir);\n\n  if (tsconfig.resultType === 'success') {\n    const match = TsconfigPaths.createMatchPath(tsconfig.absoluteBaseUrl, tsconfig.paths, [\n      'browser',\n      'module',\n      'main',\n    ]);\n    return match(id, undefined, undefined, supportedExtensions) ?? id;\n  }\n  return id;\n}\n\nexport const getTsConfig = cached(\n  (cwd: string) => {\n    const tsconfigPath = findTsconfigPath(cwd);\n    return TsconfigPaths.loadConfig(tsconfigPath);\n  },\n  { name: 'getTsConfig' }\n);\n\nexport const parseWithReactDocgen = cached(\n  (code: string, path: string) => {\n    return parse(code, {\n      resolver: defaultResolver,\n      handlers,\n      importer: getReactDocgenImporter(),\n      filename: path,\n    }) as DocObj[];\n  },\n  { key: (code, path) => path, name: 'parseWithReactDocgen' }\n);\n\nconst getExportPaths = cached(\n  (code: string, filePath: string) => {\n    let ast;\n    try {\n      ast = babelParse(code);\n    } catch (_) {\n      return [];\n    }\n\n    const basedir = dirname(filePath);\n    const body = ast.program.body;\n    return body\n      .flatMap((statement) =>\n        t.isExportAllDeclaration(statement)\n          ? [statement.source.value]\n          : t.isExportNamedDeclaration(statement) && !!statement.source && !statement.declaration\n            ? [statement.source.value]\n            : []\n      )\n      .map((id) => matchPath(id, basedir))\n      .flatMap((id) => {\n        try {\n          return [cachedResolveImport(id, { basedir })];\n        } catch (e) {\n          logger.debug(e);\n          return [];\n        }\n      });\n  },\n  { name: 'getExportPaths' }\n);\n\nconst gatherDocgensForPath = cached(\n  (\n    path: string,\n    depth: number\n  ): {\n    docgens: DocObj[];\n    errors: { path: string; code: string; name: string; message: string }[];\n  } => {\n    if (path.includes('node_modules')) {\n      return {\n        docgens: [],\n        errors: [\n          {\n            path,\n            code: '/* File in node_modules */',\n            name: 'Component file in node_modules',\n            message: dedent`\n              Component files in node_modules are not supported.\n              The distributed files in node_modules usually don't contain the necessary comments or types needed to analyze component information.\n              Configure TypeScript path aliases to map your package name to the source file instead.\n\n              Example (tsconfig.json):\n              {\n                \"compilerOptions\": {\n                  \"baseUrl\": \".\",\n                  \"paths\": {\n                    \"@design-system/button\": [\"src/components/Button.tsx\"],\n                    \"@design-system/*\": [\"src/components/*\"]\n                  }\n                }\n              }\n\n              Then import using:\n              import { Button } from '@design-system/button'\n\n              Storybook resolves tsconfig paths automatically.\n            `,\n          },\n        ],\n      };\n    }\n\n    let code;\n    try {\n      code = cachedReadFileSync(path, 'utf-8') as string;\n    } catch {\n      return {\n        docgens: [],\n        errors: [\n          {\n            path,\n            code: '/* File not found or unreadable */',\n            name: 'Component file could not be read',\n            message: `Could not read the component file located at \"${path}\".\\nPrefer relative imports if possible.`,\n          },\n        ],\n      };\n    }\n\n    if (depth > 5) {\n      return {\n        docgens: [],\n        errors: [\n          {\n            path,\n            code,\n            name: 'Max re-export depth exceeded',\n            message: dedent`\n              Traversal stopped after 5 steps while following re-exports starting from this file.\n              This usually indicates a deep or circular re-export chain. Try one of the following:\n              - Import the component file directly (e.g., src/components/Button.tsx),\n              - Reduce the number of re-export hops.\n            `,\n          },\n        ],\n      };\n    }\n\n    const exportPaths = getExportPaths(code, path).map((p) => gatherDocgensForPath(p, depth + 1));\n    const docgens = exportPaths.flatMap((r) => r.docgens);\n    const errors = exportPaths.flatMap((r) => r.errors);\n\n    try {\n      return {\n        docgens: [...parseWithReactDocgen(code, path), ...docgens],\n        errors,\n      };\n    } catch (e) {\n      const message = e instanceof Error ? e.message : String(e);\n      return {\n        docgens,\n        errors: [\n          {\n            path,\n            code,\n            name: 'No component definition found',\n            message: dedent`\n              ${message}\n              You can debug your component file in this playground: https://react-docgen.dev/playground\n            `,\n          },\n          ...errors,\n        ],\n      };\n    }\n  },\n  { name: 'gatherDocgensWithTrace', key: (filePath) => filePath }\n);\n\nexport const getReactDocgen = cached(\n  (\n    path: string,\n    component: ComponentRef\n  ):\n    | { type: 'success'; data: DocObj }\n    | { type: 'error'; error: { name: string; message: string } } => {\n    const { docgens, errors } = gatherDocgensForPath(path, 0);\n\n    const docgen = getMatchingDocgen(docgens, component);\n\n    if (!docgen) {\n      const error = {\n        name: errors.at(-1)?.name ?? 'No component definition found',\n        message: errors\n          .map(\n            (e) => dedent`\n            File: ${e.path}\n            Error:\n            ${e.message}\n            Code:\n            ${e.code}`\n          )\n          .join('\\n\\n'),\n      };\n      return { type: 'error', error };\n    }\n    return { type: 'success', data: docgen };\n  },\n  { name: 'getReactDocgen', key: (path, component) => path + JSON.stringify(component) }\n);\n\nexport function getReactDocgenImporter() {\n  return makeFsImporter((filename, basedir) => {\n    const mappedFilenameByPaths = (() => {\n      return matchPath(filename, basedir);\n    })();\n\n    const result = cachedResolveImport(mappedFilenameByPaths, { basedir });\n\n    if (result.includes(`${sep}react-native${sep}index.js`)) {\n      const replaced = result.replace(\n        `${sep}react-native${sep}index.js`,\n        `${sep}react-native-web${sep}dist${sep}index.js`\n      );\n      if (existsSync(replaced)) {\n        if (supportedExtensions.find((ext) => result.endsWith(ext))) {\n          return replaced;\n        }\n      }\n    }\n    if (supportedExtensions.find((ext) => result.endsWith(ext))) {\n      return result;\n    }\n\n    throw new ReactDocgenResolveError(filename);\n  });\n}\n\nexport function getImportTag(docgen: { description?: string }) {\n  const jsdocComment = docgen?.description;\n  const tags = jsdocComment ? extractJSDocInfo(jsdocComment).tags : undefined;\n  return tags?.import?.[0];\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/reactDocgenTypescript.ts",
    "content": "import { dirname } from 'node:path';\n\nimport {\n  type ComponentDoc,\n  type FileParser,\n  type ParserOptions,\n  type PropItem,\n} from 'react-docgen-typescript';\nimport type ts from 'typescript';\n\nimport { logger } from 'storybook/internal/node-logger';\n\nimport { asyncCache, findTsconfigPath } from './utils.ts';\n\nexport type ComponentDocWithExportName = ComponentDoc & { exportName: string };\n\ntype TypeScriptRuntime = typeof import('typescript');\ntype ReactDocgenTypescriptRuntime = typeof import('react-docgen-typescript');\n\nlet typeScriptPromise: Promise<TypeScriptRuntime> | undefined;\nlet reactDocgenTypescriptPromise: Promise<ReactDocgenTypescriptRuntime> | undefined;\n\nconst loadTypeScript = () => (typeScriptPromise ??= import('typescript'));\n\nconst loadReactDocgenTypescript = () =>\n  (reactDocgenTypescriptPromise ??= import('react-docgen-typescript'));\n\n/**\n * Auto-detect bulk props contributed by a single non-user source file and filter them out.\n *\n * This catches:\n *\n * - React built-in props (HTMLAttributes, DOMAttributes, AriaAttributes from @types/react)\n * - DOM built-in props (HTMLElement, GlobalEventHandlers from lib.dom.d.ts)\n * - CSS-in-JS system props (Panda CSS, styled-system, Stitches style props)\n *\n * The heuristic: when a single source file in `node_modules` or ending in `.d.ts` contributes more\n * than {@link LARGE_NON_USER_SOURCE_THRESHOLD} props, all props from that source are filtered.\n * User-authored `.ts` files are never filtered.\n */\nconst LARGE_NON_USER_SOURCE_THRESHOLD = 30;\n\nconst getPropSource = (prop: PropItem): string | undefined =>\n  prop.parent?.fileName ?? prop.declarations?.[0]?.fileName;\n\nconst getLargeNonUserPropSources = (props: Record<string, PropItem>): Set<string> => {\n  const countBySource = new Map<string, number>();\n  for (const prop of Object.values(props)) {\n    const source = getPropSource(prop);\n    if (source?.includes('node_modules') || source?.endsWith('.d.ts')) {\n      countBySource.set(source, (countBySource.get(source) ?? 0) + 1);\n    }\n  }\n  const largeNonUserSources = new Set<string>();\n  for (const [source, count] of countBySource) {\n    if (count > LARGE_NON_USER_SOURCE_THRESHOLD) {\n      largeNonUserSources.add(source);\n    }\n  }\n  return largeNonUserSources;\n};\n\n/**\n * Find `Identifier.displayName = 'value'` assignments in a source file. Returns the string value if\n * the identifier matches the given name, otherwise undefined.\n */\nfunction findDisplayNameAssignment(\n  typescript: TypeScriptRuntime,\n  sourceFile: ts.SourceFile,\n  identifierName: string\n): string | undefined {\n  for (const statement of sourceFile.statements) {\n    if (!typescript.isExpressionStatement(statement)) {\n      continue;\n    }\n    const expr = statement.expression;\n    if (\n      typescript.isBinaryExpression(expr) &&\n      expr.operatorToken.kind === typescript.SyntaxKind.EqualsToken &&\n      typescript.isPropertyAccessExpression(expr.left) &&\n      expr.left.name.text === 'displayName' &&\n      typescript.isIdentifier(expr.left.expression) &&\n      expr.left.expression.text === identifierName &&\n      typescript.isStringLiteral(expr.right)\n    ) {\n      return expr.right.text;\n    }\n  }\n  return undefined;\n}\n\n/**\n * Build a map from possible displayName values to the public export name for component exports.\n * react-docgen-typescript computes displayName from:\n *\n * 1. An explicit `.displayName` static property\n * 2. The resolved symbol name (e.g. \"Card\" for `export { Card as RenamedCard }`)\n * 3. The filename (for default exports)\n *\n * We map all of these to the correct export name so we can match docs by displayName.\n *\n * @see https://github.com/styleguidist/react-docgen-typescript/blob/master/src/parser.ts\n */\nfunction getExportNameMap(\n  typescript: TypeScriptRuntime,\n  checker: ts.TypeChecker,\n  sourceFile: ts.SourceFile\n): Map<string, string> {\n  const moduleSymbol = checker.getSymbolAtLocation(sourceFile);\n  if (!moduleSymbol) {\n    return new Map();\n  }\n\n  const result = new Map<string, string>();\n  const fileName = sourceFile.fileName.replace(/.*\\//, '').replace(/\\.[^.]+$/, '');\n\n  for (const exportSymbol of checker.getExportsOfModule(moduleSymbol)) {\n    const resolved =\n      exportSymbol.flags & typescript.SymbolFlags.Alias\n        ? checker.getAliasedSymbol(exportSymbol)\n        : exportSymbol;\n\n    const declaration = resolved.valueDeclaration ?? resolved.getDeclarations()?.[0];\n    if (!declaration) {\n      continue;\n    }\n\n    const type = checker.getTypeOfSymbolAtLocation(resolved, declaration);\n\n    const callSigs = type.getCallSignatures();\n    const isStateless = callSigs.some((sig) => {\n      const params = sig.getParameters();\n      return params.length === 1 || (params.length > 0 && params[0].getName() === 'props');\n    });\n\n    const constructSigs = type.getConstructSignatures();\n    const isStateful = constructSigs.some(\n      (sig) => sig.getReturnType().getProperty('props') !== undefined\n    );\n\n    if (isStateless || isStateful) {\n      const exportName = exportSymbol.getName();\n      const resolvedName = resolved.getName();\n\n      // Map resolved symbol name → export name (handles aliased re-exports)\n      result.set(resolvedName, exportName);\n\n      // For default exports, RDT uses the filename as displayName\n      if (exportName === 'default') {\n        result.set(fileName, 'default');\n      }\n\n      // If the component has a static .displayName assignment (e.g. Foo.displayName = 'Bar'),\n      // RDT uses that value. Map it → export name so we can match it.\n      const displayNameValue = findDisplayNameAssignment(typescript, sourceFile, resolvedName);\n      if (displayNameValue) {\n        result.set(displayNameValue, exportName);\n      }\n    }\n  }\n\n  return result;\n}\n\n/**\n * Manages the TS program and react-docgen-typescript parser. On `invalidateParser()` the program is\n * rebuilt incrementally — TypeScript reuses source files that haven't changed on disk, so only\n * modified files are re-parsed. This keeps prop extraction correct across HMR cycles without the\n * cost of a full program rebuild.\n */\nlet cachedCompilerOptions: ts.CompilerOptions | undefined;\nlet cachedFileNames: string[] | undefined;\nlet previousProgram: ts.Program | undefined;\nlet parser: { program: ts.Program; fileParser: FileParser } | undefined;\nlet cachedParserOptionsKey: string | undefined;\n\n/** Rebuild the TS program incrementally so that file changes are picked up on the next parse. */\nexport function invalidateParser() {\n  parser = undefined;\n  cachedCompilerOptions = undefined;\n  cachedFileNames = undefined;\n  cachedParserOptionsKey = undefined;\n}\n\nasync function getParser(userOptions?: ParserOptions) {\n  const [typescript, reactDocgenTypescript] = await Promise.all([\n    loadTypeScript(),\n    loadReactDocgenTypescript(),\n  ]);\n  // Rebuild parser if options changed\n  const optionsKey = JSON.stringify(userOptions ?? {});\n  if (parser && cachedParserOptionsKey !== optionsKey) {\n    parser = undefined;\n  }\n\n  if (!parser) {\n    const configPath = findTsconfigPath(process.cwd());\n    cachedCompilerOptions = { noErrorTruncation: true, strict: true };\n\n    if (configPath) {\n      const { config } = typescript.readConfigFile(configPath, typescript.sys.readFile);\n      const parsed = typescript.parseJsonConfigFileContent(\n        config,\n        typescript.sys,\n        dirname(configPath)\n      );\n      cachedCompilerOptions = { ...parsed.options, noErrorTruncation: true };\n      cachedFileNames = parsed.fileNames;\n    } else {\n      logger.warn(\n        'No tsconfig.json (or tsconfig.base.json / tsconfig.app.json) found. ' +\n          'TypeScript component props will not be documented by react-docgen-typescript. ' +\n          'Create a tsconfig.json in your project root to enable automatic controls.'\n      );\n    }\n\n    const program = typescript.createProgram(\n      cachedFileNames ?? [],\n      cachedCompilerOptions,\n      undefined,\n      previousProgram\n    );\n    previousProgram = program;\n\n    const parserOptions: ParserOptions = {\n      shouldExtractLiteralValuesFromEnum: true,\n      shouldRemoveUndefinedFromOptional: true,\n      ...userOptions,\n      // Always force savePropValueAsString so default values are in a consistent format\n      savePropValueAsString: true,\n    };\n\n    parser = {\n      program,\n      fileParser: reactDocgenTypescript.withCompilerOptions(cachedCompilerOptions, parserOptions),\n    };\n    cachedParserOptionsKey = optionsKey;\n  }\n  return { ...parser, typescript };\n}\n\n/** Find the component doc that matches the given import/component name. */\nexport function matchComponentDoc(\n  docs: ComponentDocWithExportName[],\n  {\n    importName,\n    localImportName,\n    componentName,\n  }: { importName?: string; localImportName?: string; componentName?: string }\n): ComponentDocWithExportName | undefined {\n  if (docs.length === 0) {\n    return undefined;\n  }\n  if (docs.length === 1) {\n    return docs[0];\n  }\n  return docs.find(\n    (doc) =>\n      doc.exportName === importName ||\n      doc.exportName === localImportName ||\n      doc.displayName === importName ||\n      doc.displayName === localImportName ||\n      doc.displayName === componentName\n  );\n}\n\nexport function getReactDocgenTypescriptError(\n  path: string,\n  {\n    importName,\n    localImportName,\n    componentName,\n  }: { importName?: string; localImportName?: string; componentName?: string },\n  docs: ComponentDocWithExportName[]\n) {\n  if (docs.length === 0) {\n    return {\n      name: 'react-docgen-typescript found no component docs',\n      message: [\n        `File: ${path}`,\n        'react-docgen-typescript did not return any component docs for this file.',\n      ].join('\\n'),\n    };\n  }\n\n  return {\n    name: 'react-docgen-typescript could not match component docs',\n    message: [\n      `File: ${path}`,\n      \"react-docgen-typescript returned component docs for this file, but none matched the story's component import.\",\n      `Looked for: componentName=${componentName}, localImportName=${localImportName ?? '<none>'}, importName=${importName ?? '<none>'}.`,\n    ].join('\\n'),\n  };\n}\n\n/**\n * Parse a component file with react-docgen-typescript. Per-file results are cached via\n * `invalidateCache()`. The underlying TS program is a long-lived singleton.\n */\nexport const parseWithReactDocgenTypescript = asyncCache(\n  async (filePath: string, userOptions?: ParserOptions): Promise<ComponentDocWithExportName[]> => {\n    const { program, fileParser, typescript } = await getParser(userOptions);\n    const checker = program.getTypeChecker();\n    const sourceFile = program.getSourceFile(filePath);\n\n    const docs = fileParser.parseWithProgramProvider(filePath, () => program);\n    // Map from resolved (original) name → public export name.\n    // e.g. for `export { Card as RenamedCard }`: \"Card\" → \"RenamedCard\"\n    const exportNameMap = sourceFile\n      ? getExportNameMap(typescript, checker, sourceFile)\n      : new Map();\n\n    return docs.map((doc) => {\n      const largeNonUserSources = getLargeNonUserPropSources(doc.props);\n      return {\n        ...doc,\n        // Use name-based lookup: displayName is the resolved symbol name, so look it up in the\n        // export map to get the public export name. Falls back to displayName when not aliased.\n        exportName: exportNameMap.get(doc.displayName) ?? doc.displayName,\n        // Filter out bulk props from non-user sources (React built-ins, DOM, CSS-in-JS system props)\n        props: Object.fromEntries(\n          Object.entries(doc.props).filter(([, prop]) => {\n            const source = getPropSource(prop);\n            return !source || !largeNonUserSources.has(source);\n          })\n        ),\n      };\n    });\n  },\n  { name: 'parseWithReactDocgenTypescript' }\n);\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/types.ts",
    "content": "import type ts from 'typescript';\n\nexport type ComponentRef = {\n  componentName: string;\n  localImportName?: string;\n  importId?: string;\n  componentJsDocTags?: Record<string, string[]>;\n  importOverride?: string;\n  importName?: string;\n  namespace?: string;\n  /** For member expressions like `Accordion.Root`, the member part (`\"Root\"`). */\n  member?: string;\n  path?: string;\n  isPackage: boolean;\n  /** Minimum JSX nesting depth where this component first appears (1 = outermost JSX element). */\n  jsxDepth?: number;\n  reactDocgen?: ReturnType<typeof import('./reactDocgen').getReactDocgen>;\n  reactDocgenTypescript?: import('./reactDocgenTypescript').ComponentDocWithExportName;\n  reactComponentMeta?: import('./componentMeta/componentMetaExtractor').ComponentDoc;\n  reactDocgenTypescriptError?: { name: string; message: string };\n};\n\nexport interface ResolvedComponentTarget {\n  componentRef: ComponentRef;\n  propsType: ts.Type;\n  symbol: ts.Symbol;\n}\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/utils.test.ts",
    "content": "import { beforeEach, describe, expect, test, vi } from 'vitest';\n\nvi.mock('empathic/find', { spy: true });\nvi.mock('storybook/internal/common', { spy: true });\nvi.mock('storybook/internal/node-logger', { spy: true });\n\nimport { getProjectRoot } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport * as find from 'empathic/find';\n\nimport {\n  asyncCache,\n  cached,\n  findTsconfigPath,\n  groupBy,\n  invalidateCache,\n  invariant,\n} from './utils.ts';\n\n// Helpers\nconst calls = () => {\n  let n = 0;\n  return {\n    inc: () => ++n,\n    count: () => n,\n  };\n};\n\ntest('groupBy groups items by key function', () => {\n  const items = [\n    { k: 'a', v: 1 },\n    { k: 'b', v: 2 },\n    { k: 'a', v: 3 },\n  ];\n  const grouped = groupBy(items, (it) => it.k);\n  expect(grouped).toMatchInlineSnapshot(`\n    {\n      \"a\": [\n        {\n          \"k\": \"a\",\n          \"v\": 1,\n        },\n        {\n          \"k\": \"a\",\n          \"v\": 3,\n        },\n      ],\n      \"b\": [\n        {\n          \"k\": \"b\",\n          \"v\": 2,\n        },\n      ],\n    }\n  `);\n});\n\ntest('invariant throws only when condition is falsy and lazily evaluates message', () => {\n  const spy = vi.fn(() => 'Expensive message');\n\n  // True branch: does not throw and does not call message factory\n  expect(() => invariant(true, spy)).not.toThrow();\n  expect(spy).not.toHaveBeenCalled();\n\n  // False branch: throws and evaluates message lazily\n  expect(() => invariant(false, spy)).toThrowError('Expensive message');\n  expect(spy).toHaveBeenCalledTimes(1);\n});\n\ntest('cached memoizes by default on first argument value', () => {\n  const c = calls();\n  const fn = (x: number) => (c.inc(), x * 2);\n  const m = cached(fn);\n\n  expect(m(2)).toBe(4);\n  expect(m(2)).toBe(4);\n  expect(m(3)).toBe(6);\n  expect(m(3)).toBe(6);\n\n  // Underlying function should have been called only once per distinct key (2 keys => 2 calls)\n  expect(c.count()).toBe(2);\n});\n\ntest('cached supports custom key selector', () => {\n  const c = calls();\n  const fn = (x: number, y: number) => (c.inc(), x + y);\n  // Cache only by the first arg\n  const m = cached(fn, { key: (x) => `${x}` });\n\n  expect(m(1, 10)).toBe(11);\n  expect(m(1, 99)).toBe(11); // cached by key 1, result should be from first call\n  expect(m(2, 5)).toBe(7);\n  expect(m(2, 8)).toBe(7);\n\n  expect(c.count()).toBe(2);\n});\n\ntest('cached stores and returns undefined results without recomputing', () => {\n  const c = calls();\n  const fn = (x: string) => {\n    c.inc();\n    return x === 'hit' ? undefined : x.toUpperCase();\n  };\n  const m = cached(fn);\n\n  expect(m('hit')).toBeUndefined();\n  expect(m('hit')).toBeUndefined();\n  expect(m('miss')).toBe('MISS');\n  expect(m('miss')).toBe('MISS');\n\n  expect(c.count()).toBe(2);\n});\n\ntest('cached shares cache across wrappers of the same function', () => {\n  const c = calls();\n  const f = (x: string) => (c.inc(), x.length);\n\n  const m1 = cached(f, { key: (x) => x });\n  const m2 = cached(f, { key: (x) => x });\n\n  // First computes via m1 and caches the value 3 for key 'foo'\n  expect(m1('foo')).toBe(3);\n  // m2 should now return the cached value (from shared module store), not call f again\n  expect(m2('foo')).toBe(3);\n\n  // Verify call counts: underlying function called once\n  expect(c.count()).toBe(1);\n});\n\ntest('asyncCache memoizes in-flight work and resolved results', async () => {\n  const c = calls();\n  const f = async (x: number) => {\n    c.inc();\n    return x * 2;\n  };\n  const m = asyncCache(f);\n\n  const [first, second] = await Promise.all([m(2), m(2)]);\n\n  expect(first).toBe(4);\n  expect(second).toBe(4);\n  expect(c.count()).toBe(1);\n  expect(await m(2)).toBe(4);\n  expect(c.count()).toBe(1);\n});\n\ntest('asyncCache drops rejected promises so retries can recompute', async () => {\n  const c = calls();\n  const f = async (x: string) => {\n    if (c.inc() === 1) {\n      throw new Error('boom');\n    }\n    return x.toUpperCase();\n  };\n  const m = asyncCache(f);\n\n  await expect(m('hit')).rejects.toThrow('boom');\n  await expect(m('hit')).resolves.toBe('HIT');\n  expect(c.count()).toBe(2);\n});\n\ntest('invalidateCache clears the module-level memo store', () => {\n  const c = calls();\n  const f = (x: number) => (c.inc(), x * 2);\n  const m = cached(f);\n\n  expect(m(2)).toBe(4);\n  expect(c.count()).toBe(1);\n\n  // Cached result\n  expect(m(2)).toBe(4);\n  expect(c.count()).toBe(1);\n\n  // Invalidate and ensure it recomputes\n  invalidateCache();\n  expect(m(2)).toBe(4);\n  expect(c.count()).toBe(2);\n});\n\ntest('invalidateCache clears async module-level memo store', async () => {\n  const c = calls();\n  const f = async (x: number) => (c.inc(), x * 2);\n  const m = asyncCache(f);\n\n  expect(await m(2)).toBe(4);\n  expect(c.count()).toBe(1);\n\n  expect(await m(2)).toBe(4);\n  expect(c.count()).toBe(1);\n\n  invalidateCache();\n  expect(await m(2)).toBe(4);\n  expect(c.count()).toBe(2);\n});\n\ndescribe('findTsconfigPath', () => {\n  beforeEach(() => {\n    invalidateCache();\n    vi.mocked(getProjectRoot).mockReturnValue('/project-root');\n  });\n\n  test('returns tsconfig.json when found', () => {\n    vi.mocked(find.up).mockImplementation((name) => {\n      if (name === 'tsconfig.json') {\n        return '/project-root/tsconfig.json';\n      }\n      return undefined;\n    });\n\n    const result = findTsconfigPath('/project-root');\n\n    expect(result).toBe('/project-root/tsconfig.json');\n    expect(logger.warn).not.toHaveBeenCalled();\n  });\n\n  test('falls back to tsconfig.base.json when tsconfig.json is not found', () => {\n    vi.mocked(find.up).mockImplementation((name) => {\n      if (name === 'tsconfig.base.json') {\n        return '/project-root/tsconfig.base.json';\n      }\n      return undefined;\n    });\n\n    const result = findTsconfigPath('/project-root');\n\n    expect(result).toBe('/project-root/tsconfig.base.json');\n  });\n\n  test('falls back to tsconfig.app.json when neither tsconfig.json nor tsconfig.base.json is found', () => {\n    vi.mocked(find.up).mockImplementation((name) => {\n      if (name === 'tsconfig.app.json') {\n        return '/project-root/tsconfig.app.json';\n      }\n      return undefined;\n    });\n\n    const result = findTsconfigPath('/project-root');\n\n    expect(result).toBe('/project-root/tsconfig.app.json');\n  });\n\n  test('returns undefined when no tsconfig variant is found', () => {\n    vi.mocked(find.up).mockReturnValue(undefined);\n\n    const result = findTsconfigPath('/project-root');\n\n    expect(result).toBeUndefined();\n    expect(logger.warn).not.toHaveBeenCalled();\n  });\n\n  test('prefers tsconfig.json over fallback variants', () => {\n    vi.mocked(find.up).mockImplementation((name) => {\n      if (name === 'tsconfig.json') {\n        return '/project-root/tsconfig.json';\n      }\n      if (name === 'tsconfig.base.json') {\n        return '/project-root/tsconfig.base.json';\n      }\n      return undefined;\n    });\n\n    const result = findTsconfigPath('/project-root');\n\n    expect(result).toBe('/project-root/tsconfig.json');\n    expect(logger.warn).not.toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/componentManifest/utils.ts",
    "content": "// Object.groupBy polyfill\nimport { readFileSync } from 'node:fs';\n\nimport { getProjectRoot, resolveImport } from 'storybook/internal/common';\nimport { logger } from 'storybook/internal/node-logger';\n\nimport * as find from 'empathic/find';\n\nexport const groupBy = <K extends PropertyKey, T>(\n  items: T[],\n  keySelector: (item: T, index: number) => K\n) => {\n  return items.reduce<Partial<Record<K, T[]>>>((acc = {}, item, index) => {\n    const key = keySelector(item, index);\n    if (!Array.isArray(acc[key])) {\n      acc[key] = [];\n    }\n    acc[key].push(item);\n    return acc;\n  }, {});\n};\n\n/** Like {@link groupBy} but returns a `Map`, allowing non-PropertyKey keys. */\nexport function groupByToMap<T, K>(items: Iterable<T>, getKey: (item: T) => K): Map<K, T[]> {\n  const result = new Map<K, T[]>();\n  for (const item of items) {\n    const key = getKey(item);\n    const group = result.get(key);\n    if (group) {\n      group.push(item);\n    } else {\n      result.set(key, [item]);\n    }\n  }\n  return result;\n}\n\n// This invariant allows for lazy evaluation of the message, which we need to avoid excessive computation.\nexport function invariant(\n  condition: unknown,\n  message?: string | (() => string)\n): asserts condition {\n  if (condition) {\n    return;\n  }\n  throw new Error((typeof message === 'function' ? message() : message) ?? 'Invariant failed');\n}\n\n// Module-level cache stores: per-function caches keyed by derived string keys\nlet memoStore: WeakMap<object, Map<string, unknown>> = new WeakMap();\nlet asyncMemoStore: WeakMap<object, Map<string, Promise<unknown>>> = new WeakMap();\n\n// Generic cache/memoization helper (synchronous only)\n// - Caches by a derived key from the function arguments (must be a string)\n// - Supports caching of `undefined` results (uses Map.has to distinguish)\n// - Uses module-level store so multiple wrappers around the same function share cache\nexport const cached = <A extends unknown[], R>(\n  fn: (...args: A) => R,\n  opts: { key?: (...args: A) => string; name?: string } = {}\n): ((...args: A) => R) => {\n  const keyOf: (...args: A) => string =\n    opts.key ??\n    ((...args: A) => {\n      try {\n        // Prefer a stable string key based on the full arguments list\n        return JSON.stringify(args);\n      } catch {\n        // Fallback: use the first argument if it is not serializable\n        return String(args[0]);\n      }\n    });\n\n  return (...args: A) => {\n    const k = keyOf(...args);\n    const name = fn.name || opts.name || 'anonymous';\n\n    // Ensure store exists for this function\n    let store = memoStore.get(fn);\n    if (!store) {\n      store = new Map<string, unknown>();\n      memoStore.set(fn, store);\n    }\n\n    // Fast path: cached\n    if (store.has(k)) {\n      logger.verbose(`[cache] hit ${name} key=${k}`);\n      return store.get(k) as R;\n    }\n\n    // Compute result with benchmarking\n    const start = Date.now();\n    const result = fn(...args);\n    const duration = Date.now() - start;\n    store.set(k, result as unknown);\n    logger.verbose(`[cache] miss ${name} took ${duration}ms key=${k}`);\n    return result;\n  };\n};\n\n// Generic cache/memoization helper for async functions\n// - Caches the in-flight Promise so concurrent callers share work\n// - Drops rejected Promises from the cache so retries can succeed\n// - Uses a module-level store so multiple wrappers around the same function share cache\nexport const asyncCache = <A extends unknown[], R>(\n  fn: (...args: A) => Promise<R>,\n  opts: { key?: (...args: A) => string; name?: string } = {}\n): ((...args: A) => Promise<R>) => {\n  const keyOf: (...args: A) => string =\n    opts.key ??\n    ((...args: A) => {\n      try {\n        return JSON.stringify(args);\n      } catch {\n        return String(args[0]);\n      }\n    });\n\n  return (...args: A) => {\n    const k = keyOf(...args);\n    const name = fn.name || opts.name || 'anonymous';\n\n    let store = asyncMemoStore.get(fn);\n    if (!store) {\n      store = new Map<string, Promise<unknown>>();\n      asyncMemoStore.set(fn, store);\n    }\n\n    const existing = store.get(k);\n    if (existing) {\n      logger.verbose(`[cache] hit ${name} key=${k}`);\n      return existing as Promise<R>;\n    }\n\n    const start = Date.now();\n    const pending = fn(...args)\n      .then((result) => {\n        logger.verbose(`[cache] miss ${name} took ${Date.now() - start}ms key=${k}`);\n        return result;\n      })\n      .catch((error) => {\n        if (store.get(k) === pending) {\n          store.delete(k);\n        }\n        logger.verbose(`[cache] miss ${name} failed after ${Date.now() - start}ms key=${k}`);\n        throw error;\n      });\n\n    store.set(k, pending);\n    return pending;\n  };\n};\n\nexport const invalidateCache = () => {\n  // Reinitialize the module-level store\n  memoStore = new WeakMap();\n  asyncMemoStore = new WeakMap();\n};\n\nexport const cachedReadFileSync = cached(readFileSync, { name: 'cachedReadFile' });\nexport const cachedReadTextFileSync = cached(\n  (filePath: string) => readFileSync(filePath, 'utf-8'),\n  { name: 'cachedReadTextFile' }\n);\n\nexport const cachedFindUp = cached(find.up, { name: 'findUp' });\n\n/** Preserve `resolveImport` overloads at call sites after wrapping it in the generic cache helper. */\nexport const cachedResolveImport: typeof resolveImport = cached(resolveImport, {\n  name: 'resolveImport',\n}) as typeof resolveImport;\n\n/**\n * Tsconfig filenames to try, in order. Monorepo setups (e.g. Nx) often keep only\n * `tsconfig.base.json` at the repository root, so we fall back to common alternatives\n * when `tsconfig.json` is not found.\n */\nconst TSCONFIG_CANDIDATES = ['tsconfig.json', 'tsconfig.base.json', 'tsconfig.app.json'] as const;\n\nexport const findTsconfigPath = cached(\n  (cwd: string): string | undefined => {\n    const projectRoot = getProjectRoot();\n\n    for (const candidate of TSCONFIG_CANDIDATES) {\n      const found = find.up(candidate, { cwd, last: projectRoot });\n      if (found) {\n        return found;\n      }\n    }\n\n    return undefined;\n  },\n  { name: 'findTsconfigPath' }\n);\n"
  },
  {
    "path": "code/renderers/react/src/csf-factories.test.tsx",
    "content": "// @vitest-environment happy-dom\n// this file tests Typescript types that's why there are no assertions\nimport { describe, it } from 'vitest';\nimport { expect, test } from 'vitest';\n\nimport type { ComponentType, KeyboardEventHandler, ReactElement, ReactNode } from 'react';\nimport React from 'react';\n\nimport type { Canvas } from 'storybook/internal/csf';\nimport type { Args, StrictArgs } from 'storybook/internal/types';\n\nimport { expectTypeOf } from 'expect-type';\nimport { fn } from 'storybook/test';\nimport type { Mock } from 'storybook/test';\n\nimport { __definePreview } from './preview.tsx';\nimport type { Decorator } from './public-types.ts';\n\ntype ButtonProps = { label: string; disabled: boolean; onKeyDown?: () => void };\nconst Button: (props: ButtonProps) => ReactElement = () => <></>;\n\nconst preview = __definePreview({\n  addons: [],\n});\n\ntest('csf factories', () => {\n  const meta = preview.meta({ component: Button, args: { disabled: true } });\n\n  const MyStory = meta.story({\n    args: {\n      label: 'Hello world',\n    },\n  });\n\n  expect(MyStory.input.args?.label).toBe('Hello world');\n});\n\ndescribe('Args can be provided in multiple ways', () => {\n  it('✅ All required args may be provided in meta', () => {\n    const meta = preview.meta({\n      component: Button,\n      args: { label: 'good', disabled: false },\n    });\n\n    const Basic = meta.story({});\n  });\n\n  it('✅ Required args may be provided partial in meta and the story', () => {\n    const meta = preview.meta({\n      component: Button,\n      args: { label: 'good' },\n    });\n    const Basic = meta.story({\n      args: { disabled: false },\n    });\n  });\n\n  it('❌ The combined shape of meta args and story args must match the required args.', () => {\n    {\n      const meta = preview.meta({ component: Button });\n      // @ts-expect-error disabled not provided ❌\n      const Basic = meta.story({\n        args: { label: 'good' },\n      });\n    }\n    {\n      const meta = preview.meta({\n        component: Button,\n        args: { label: 'good' },\n      });\n      // @ts-expect-error disabled not provided ❌\n      const Basic = meta.story();\n    }\n    {\n      const meta = preview.meta({ component: Button });\n      // @ts-expect-error disabled not provided ❌\n      const Basic = meta.story({\n        args: { label: 'good' },\n      });\n    }\n  });\n\n  it(\"✅ Required args don't need to be provided when the user uses an empty render\", () => {\n    const meta = preview.meta({\n      component: Button,\n      args: { label: 'good' },\n    });\n    const Basic = meta.story({\n      render: () => <div>Hello world</div>,\n    });\n\n    const CSF1 = meta.story(() => <div>Hello world</div>);\n  });\n\n  it('❌ Required args need to be provided when the user uses a non-empty render', () => {\n    const meta = preview.meta({\n      component: Button,\n      args: { label: 'good' },\n    });\n    // @ts-expect-error disabled not provided ❌\n    const Basic = meta.story({\n      args: {\n        label: 'good',\n      },\n      render: (args) => <div>Hello world</div>,\n    });\n  });\n});\n\nit('✅ Void functions are not changed', () => {\n  interface CmpProps {\n    label: string;\n    disabled: boolean;\n    onClick(): void;\n    onKeyDown: KeyboardEventHandler;\n    onLoading: (s: string) => ReactElement;\n    submitAction(): void;\n  }\n\n  const Cmp: (props: CmpProps) => ReactElement = () => <></>;\n\n  const meta = preview.meta({\n    component: Cmp,\n    args: { label: 'good' },\n  });\n\n  const Basic = meta.story({\n    args: {\n      disabled: false,\n      onLoading: () => <div>Loading...</div>,\n      onKeyDown: fn(),\n      onClick: fn(),\n      submitAction: fn(),\n    },\n  });\n});\n\ntype ThemeData = 'light' | 'dark';\ndeclare const Theme: (props: { theme: ThemeData; children?: ReactNode }) => ReactElement;\n\ndescribe('Story args can be inferred', () => {\n  it('Correct args are inferred when type is widened for render function', () => {\n    const meta = preview.meta({\n      component: Button,\n      args: { disabled: false },\n      render: (args: ButtonProps & { theme: ThemeData }, { component }) => {\n        // component is not null as it is provided in meta\n\n        const Component = component!;\n        return (\n          <Theme theme={args.theme}>\n            <Component {...args} />\n          </Theme>\n        );\n      },\n    });\n\n    const Basic = meta.story({ args: { theme: 'light', label: 'good' } });\n  });\n\n  const withDecorator: Decorator<{ decoratorArg: number }> = (Story, { args }) => (\n    <>\n      Decorator: {args.decoratorArg}\n      <Story args={{ decoratorArg: 0 }} />\n    </>\n  );\n\n  it('Correct args are inferred when type is widened for decorators', () => {\n    const meta = preview.meta({\n      component: Button,\n      args: { disabled: false },\n      decorators: [withDecorator],\n    });\n\n    const Basic = meta.story({ args: { decoratorArg: 0, label: 'good' } });\n  });\n\n  it('Correct args are inferred when type is widened for multiple decorators', () => {\n    type Props = ButtonProps & { decoratorArg: number; decoratorArg2: string };\n\n    const secondDecorator: Decorator<{ decoratorArg2: string }> = (Story, { args }) => (\n      <>\n        Decorator: {args.decoratorArg2}\n        <Story />\n      </>\n    );\n\n    // decorator is not using args\n    const thirdDecorator: Decorator<Args> = (Story) => (\n      <>\n        <Story />\n      </>\n    );\n\n    // decorator is not using args\n    const fourthDecorator: Decorator<StrictArgs> = (Story) => (\n      <>\n        <Story />\n      </>\n    );\n\n    const meta = preview.meta({\n      component: Button,\n      args: { disabled: false },\n      decorators: [withDecorator, secondDecorator, thirdDecorator, fourthDecorator],\n    });\n\n    const Basic = meta.story({\n      args: { decoratorArg: 0, decoratorArg2: '', label: 'good' },\n    });\n  });\n\n  it('Component type can be overridden', () => {\n    const meta = preview.meta({\n      component: Button as unknown as ComponentType<\n        Omit<ButtonProps, 'onKeyDown'> & { onKeyDown?: boolean }\n      >,\n      render: ({ onKeyDown, ...args }) => {\n        return <Button {...args} onKeyDown={onKeyDown ? () => {} : undefined} />;\n      },\n      args: { label: 'hello', onKeyDown: false },\n    });\n\n    const Basic = meta.story({\n      args: {\n        disabled: false,\n      },\n    });\n    const WithKeyDown = meta.story({ args: { disabled: false, onKeyDown: true } });\n  });\n\n  it('Correct args are inferred when type is added in renderer', () => {\n    const meta = preview.meta({\n      component: Button,\n      args: { label: 'hello', onKeyDownToggle: false },\n      render: ({ onKeyDownToggle, ...args }: ButtonProps & { onKeyDownToggle?: boolean }) => {\n        return <Button {...args} onKeyDown={onKeyDownToggle ? () => {} : undefined} />;\n      },\n    });\n\n    const Basic = meta.story({ args: { disabled: false } });\n    const WithKeyDown = meta.story({ args: { disabled: false, onKeyDownToggle: true } });\n  });\n\n  it('args can be reused', () => {\n    const meta = preview.meta({\n      component: Button,\n    });\n\n    const Enabled = meta.story({ args: { label: 'hello', disabled: false } });\n    const Disabled = meta.story({ args: { ...Enabled.input.args, disabled: true } });\n  });\n\n  it('stories can be extended', () => {\n    const meta = preview.meta({\n      component: Button,\n    });\n\n    const Enabled = meta.story({ args: { label: 'hello', disabled: false } });\n    const Disabled = Enabled.extend({ args: { disabled: true } });\n  });\n});\n\nit('Components without Props can be used, issue #21768', () => {\n  const Component = () => <>Foo</>;\n  const withDecorator: Decorator = (Story) => (\n    <>\n      <Story />\n    </>\n  );\n\n  const meta = preview.meta({\n    component: Component,\n    decorators: [withDecorator],\n  });\n\n  const Basic = meta.story({});\n});\n\nit('Meta is broken when using discriminating types, issue #23629', () => {\n  type TestButtonProps = {\n    text: string;\n  } & (\n    | {\n        id?: string;\n        onClick?: (e: unknown, id: string | undefined) => void;\n      }\n    | {\n        id: string;\n        onClick: (e: unknown, id: string) => void;\n      }\n  );\n  const TestButton: React.FC<TestButtonProps> = ({ text }) => {\n    return <p>{text}</p>;\n  };\n\n  preview.meta({\n    title: 'Components/Button',\n    component: TestButton,\n    args: {\n      text: 'Button',\n    },\n  });\n});\n\nit('Infer mock function given to args in meta.', () => {\n  type Props = { label: string; onClick: () => void; onRender: () => JSX.Element };\n  const TestButton = (props: Props) => <></>;\n\n  const meta = preview.meta({\n    component: TestButton,\n    args: { label: 'label', onClick: fn(), onRender: () => <>some jsx</> },\n  });\n\n  const Basic = meta.story({\n    play: async ({ args, mount }) => {\n      const canvas = await mount(<TestButton {...args} />);\n      expectTypeOf(canvas).toEqualTypeOf<Canvas>();\n      expectTypeOf(args.onClick).toEqualTypeOf<Mock>();\n      expectTypeOf(args.onRender).toEqualTypeOf<() => JSX.Element>();\n    },\n  });\n});\n\ndescribe('Composed getters', () => {\n  type Props = {\n    label: string;\n    onClick: () => void;\n    onRender: () => JSX.Element;\n  };\n  const TestButton = (props: Props) => <></>;\n\n  const meta = preview.meta({\n    component: TestButton,\n    args: { label: 'label', onClick: fn(), onRender: () => <>some jsx</> },\n  });\n\n  it('Composes the play function', async () => {\n    const spy = fn();\n    const Basic = meta.story({\n      play: async ({ args }: { args: Props }) => {\n        spy(args);\n      },\n    });\n\n    await Basic.play({ args: meta.input.args });\n\n    expect(spy).toHaveBeenCalledWith({\n      label: 'label',\n      onClick: expect.any(Function),\n      onRender: expect.any(Function),\n    });\n  });\n\n  it('Composes the run function', async () => {\n    const playSpy = fn();\n    const renderSpy = fn();\n    const Basic = meta.story({\n      play: async ({ args }) => {\n        playSpy(args);\n      },\n      render: () => {\n        renderSpy();\n        return <></>;\n      },\n    });\n\n    await Basic.run();\n\n    expect(playSpy).toHaveBeenCalledWith({\n      label: 'label',\n      onClick: expect.any(Function),\n      onRender: expect.any(Function),\n    });\n\n    expect(renderSpy).toHaveBeenCalled();\n  });\n});\n\nit('meta.input also contains play', () => {\n  const meta = preview.meta({\n    /** Title, component, etc... */\n    play: async ({ canvas }) => {\n      /** Do some common interactions */\n    },\n  });\n\n  const ExtendedInteractionsStory = meta.story({\n    play: async ({ canvas, ...rest }) => {\n      await meta.input.play?.({ canvas, ...rest });\n\n      /** Do some extra interactions */\n    },\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/docs/applyDecorators.ts",
    "content": "import type { DecoratorFunction, LegacyStoryFn } from 'storybook/internal/types';\n\nimport { applyDecorators as defaultDecorateStory } from '../applyDecorators';\nimport type { ReactRenderer } from '../types';\nimport { jsxDecorator } from './jsxDecorator';\n\nexport const applyDecorators = (\n  storyFn: LegacyStoryFn<ReactRenderer>,\n  decorators: DecoratorFunction<ReactRenderer>[]\n): LegacyStoryFn<ReactRenderer> => {\n  // @ts-expect-error originalFn is not defined on the type for decorator. This is a temporary fix\n  // that we will remove soon (likely) in favour of a proper concept of \"inner\" decorators.\n  const jsxIndex = decorators.findIndex((d) => d.originalFn === jsxDecorator);\n\n  const reorderedDecorators =\n    jsxIndex === -1 ? decorators : [...decorators.splice(jsxIndex, 1), ...decorators];\n\n  return defaultDecorateStory(storyFn, reorderedDecorators);\n};\n"
  },
  {
    "path": "code/renderers/react/src/docs/jsxDecorator.test.tsx",
    "content": "/** @vitest-environment happy-dom */\nimport type { Mock } from 'vitest';\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport type { FC, PropsWithChildren } from 'react';\nimport React, { Profiler, StrictMode, createElement } from 'react';\n\nimport PropTypes from 'prop-types';\nimport { addons, emitTransformCode, useState } from 'storybook/preview-api';\n\nimport type { ReactRenderer, StoryContext } from '../types';\nimport { getReactSymbolName, jsxDecorator, renderJsx } from './jsxDecorator';\n\nvi.mock('storybook/preview-api', () => ({\n  addons: {\n    getChannel: vi.fn(),\n  },\n  useEffect: vi.fn((fn) => fn()),\n  useRef: vi.fn(() => ({ current: undefined })),\n  useState: vi.fn(),\n  emitTransformCode: vi.fn(),\n}));\n\nconst mockedGetChannel = vi.mocked(addons.getChannel);\nconst mockedEmitTransformCode = vi.mocked(emitTransformCode);\n\nexpect.addSnapshotSerializer({\n  print: (val: any) => val,\n  test: (val) => typeof val === 'string',\n});\n\ndescribe('converts React Symbol to displayName string', () => {\n  const symbolCases = [\n    ['react.suspense', 'React.Suspense'],\n    ['react.strict_mode', 'React.StrictMode'],\n    ['react.server_context.defaultValue', 'React.ServerContext.DefaultValue'],\n  ];\n\n  it.each(symbolCases)('\"%s\" to \"%s\"', (symbol, expectedValue) => {\n    expect(getReactSymbolName(Symbol(symbol))).toEqual(expectedValue);\n  });\n});\n\ndescribe('renderJsx', () => {\n  it('basic', () => {\n    expect(renderJsx(<div>hello</div>, {})).toMatchInlineSnapshot(`\n      <div>\n        hello\n      </div>\n    `);\n  });\n  it('functions', () => {\n    const onClick = () => console.log('onClick');\n    expect(renderJsx(<div onClick={onClick}>hello</div>, {})).toMatchInlineSnapshot(`\n      <div onClick={() => {}}>\n        hello\n      </div>\n    `);\n  });\n  it('undefined values', () => {\n    expect(renderJsx(<div className={undefined}>hello</div>, {})).toMatchInlineSnapshot(`\n      <div>\n        hello\n      </div>\n    `);\n  });\n  it('null values', () => {\n    expect(renderJsx(<div>hello</div>, {})).toMatchInlineSnapshot(`\n      <div>\n        hello\n      </div>\n    `);\n  });\n  it('large objects', () => {\n    const obj = Array.from({ length: 20 }).reduce((acc, _, i) => {\n      // @ts-expect-error (Converted from ts-ignore)\n      acc[`key_${i}`] = `val_${i}`;\n      return acc;\n    }, {});\n    expect(renderJsx(<div data-val={obj} />, {})).toMatchInlineSnapshot(`\n      <div\n        data-val={{\n          key_0: 'val_0',\n          key_1: 'val_1',\n          key_10: 'val_10',\n          key_11: 'val_11',\n          key_12: 'val_12',\n          key_13: 'val_13',\n          key_14: 'val_14',\n          key_15: 'val_15',\n          key_16: 'val_16',\n          key_17: 'val_17',\n          key_18: 'val_18',\n          key_19: 'val_19',\n          key_2: 'val_2',\n          key_3: 'val_3',\n          key_4: 'val_4',\n          key_5: 'val_5',\n          key_6: 'val_6',\n          key_7: 'val_7',\n          key_8: 'val_8',\n          key_9: 'val_9'\n        }}\n       />\n    `);\n  });\n\n  it('long arrays', () => {\n    const arr = Array.from({ length: 20 }, (_, i) => `item ${i}`);\n    expect(renderJsx(<div data-val={arr} />, {})).toMatchInlineSnapshot(`\n      <div\n        data-val={[\n          'item 0',\n          'item 1',\n          'item 2',\n          'item 3',\n          'item 4',\n          'item 5',\n          'item 6',\n          'item 7',\n          'item 8',\n          'item 9',\n          'item 10',\n          'item 11',\n          'item 12',\n          'item 13',\n          'item 14',\n          'item 15',\n          'item 16',\n          'item 17',\n          'item 18',\n          'item 19'\n        ]}\n       />\n    `);\n  });\n\n  describe('forwardRef component', () => {\n    it('with no displayName', () => {\n      const MyExoticComponentRef = React.forwardRef<FC, PropsWithChildren>(\n        function MyExoticComponent(props, _ref) {\n          return <div>{props.children}</div>;\n        }\n      );\n\n      expect(renderJsx(<MyExoticComponentRef>I am forwardRef!</MyExoticComponentRef>))\n        .toMatchInlineSnapshot(`\n          <React.ForwardRef>\n            I am forwardRef!\n          </React.ForwardRef>\n        `);\n    });\n\n    it('with displayName coming from docgen', () => {\n      const MyExoticComponentRef = React.forwardRef<FC, PropsWithChildren>(\n        function MyExoticComponent(props, _ref) {\n          return <div>{props.children}</div>;\n        }\n      );\n      (MyExoticComponentRef as any).__docgenInfo = {\n        displayName: 'ExoticComponent',\n      };\n      expect(renderJsx(<MyExoticComponentRef>I am forwardRef!</MyExoticComponentRef>))\n        .toMatchInlineSnapshot(`\n          <ExoticComponent>\n            I am forwardRef!\n          </ExoticComponent>\n        `);\n    });\n\n    it('with displayName coming from forwarded render function', () => {\n      const MyExoticComponentRef = React.forwardRef<FC, PropsWithChildren>(\n        Object.assign(\n          function MyExoticComponent(props: any, _ref: any) {\n            return <div>{props.children}</div>;\n          },\n          { displayName: 'ExoticComponent' }\n        )\n      );\n      expect(renderJsx(<MyExoticComponentRef>I am forwardRef!</MyExoticComponentRef>))\n        .toMatchInlineSnapshot(`\n        <ExoticComponent>\n          I am forwardRef!\n        </ExoticComponent>\n      `);\n    });\n  });\n\n  it('memo component', () => {\n    const MyMemoComponentRef: FC<PropsWithChildren> = React.memo(function MyMemoComponent(props) {\n      return <div>{props.children}</div>;\n    });\n\n    expect(renderJsx(<MyMemoComponentRef>I am memo!</MyMemoComponentRef>)).toMatchInlineSnapshot(`\n      <React.Memo>\n        I am memo!\n      </React.Memo>\n    `);\n\n    // if docgenInfo is present, it should use the displayName from there\n    (MyMemoComponentRef as any).__docgenInfo = {\n      displayName: 'MyMemoComponentRef',\n    };\n    expect(renderJsx(<MyMemoComponentRef>I am memo!</MyMemoComponentRef>)).toMatchInlineSnapshot(`\n      <MyMemoComponentRef>\n        I am memo!\n      </MyMemoComponentRef>\n    `);\n  });\n\n  it('Profiler', () => {\n    expect(\n      renderJsx(\n        <Profiler id=\"profiler-test\" onRender={() => {}}>\n          <div>I am in a Profiler</div>\n        </Profiler>,\n        {}\n      )\n    ).toMatchInlineSnapshot(`\n      <React.Profiler\n        id=\"profiler-test\"\n        onRender={() => {}}\n      >\n        <div>\n          I am in a Profiler\n        </div>\n      </React.Profiler>\n    `);\n  });\n\n  it('StrictMode', () => {\n    expect(renderJsx(<StrictMode>I am StrictMode</StrictMode>, {})).toMatchInlineSnapshot(`\n      <React.StrictMode>\n        I am StrictMode\n      </React.StrictMode>\n    `);\n  });\n\n  it('displayName coming from docgenInfo', () => {\n    function BasicComponent({ label }: any) {\n      return <button>{label}</button>;\n    }\n    BasicComponent.__docgenInfo = {\n      description: 'Some description',\n      methods: [],\n      displayName: 'Button',\n      props: {},\n    };\n\n    expect(\n      renderJsx(\n        createElement(\n          BasicComponent,\n          {\n            label: <p>Abcd</p>,\n          },\n          undefined\n        )\n      )\n    ).toMatchInlineSnapshot(`<Button label={<p>Abcd</p>} />`);\n  });\n\n  it('Suspense', () => {\n    expect(\n      renderJsx(\n        <React.Suspense fallback={null}>\n          <div>I am in Suspense</div>\n        </React.Suspense>,\n        {}\n      )\n    ).toMatchInlineSnapshot(`\n      <React.Suspense fallback={null}>\n        <div>\n          I am in Suspense\n        </div>\n      </React.Suspense>\n    `);\n  });\n\n  it('should not add default props to string if the prop value has not changed', () => {\n    const Container = ({ className, children }: { className: string; children: string }) => {\n      return <div className={className}>{children}</div>;\n    };\n\n    Container.propTypes = {\n      children: PropTypes.string.isRequired,\n      className: PropTypes.string,\n    };\n\n    Container.defaultProps = {\n      className: 'super-container',\n    };\n\n    expect(renderJsx(<Container>yo dude</Container>, {})).toMatchInlineSnapshot(`\n      <Container className=\"super-container\">\n        yo dude\n      </Container>\n    `);\n  });\n});\n\n// @ts-expect-error (Converted from ts-ignore)\nconst makeContext = (name: string, parameters: any, args: any, extra?: object): StoryContext => ({\n  id: `jsx-test--${name}`,\n  kind: 'js-text',\n  name,\n  parameters,\n  unmappedArgs: args,\n  args,\n  ...extra,\n});\n\ndescribe('jsxDecorator', () => {\n  const channel = { emit: vi.fn() };\n  let mockContext: StoryContext<ReactRenderer>;\n  let mockStoryFn: Mock;\n\n  const mockSetSource = vi.fn();\n\n  beforeEach(() => {\n    vi.clearAllMocks();\n    mockedGetChannel.mockReturnValue(channel as any);\n    vi.mocked(useState).mockReturnValue([undefined, mockSetSource]);\n\n    mockContext = makeContext('test', {}, { foo: 'bar' });\n    mockStoryFn = vi.fn().mockReturnValue(<div>Test Story</div>);\n  });\n\n  it('should skip JSX rendering when source type is CODE', () => {\n    const context = {\n      ...mockContext,\n      parameters: {\n        docs: { source: { type: 'code' } },\n      },\n      originalStoryFn: () => <div>Test Story</div>,\n    };\n\n    const result = jsxDecorator(mockStoryFn, context);\n    expect(channel.emit).not.toHaveBeenCalled();\n    expect(result).toEqual(<div>Test Story</div>);\n  });\n\n  it('should skip JSX rendering when source code is provided', () => {\n    const context = {\n      ...mockContext,\n      parameters: {\n        docs: { source: { code: 'const x = 1;' } },\n      },\n      originalStoryFn: () => <div>Test Story</div>,\n    };\n\n    const result = jsxDecorator(mockStoryFn, context);\n    expect(channel.emit).not.toHaveBeenCalled();\n    expect(result).toEqual(<div>Test Story</div>);\n  });\n\n  it('should handle MDX elements correctly', () => {\n    const mdxElement = {\n      type: { displayName: 'MDXCreateElement' },\n      props: {\n        mdxType: 'div',\n        originalType: 'div',\n        children: 'Hello MDX',\n      },\n    };\n\n    const context = {\n      ...mockContext,\n      parameters: {\n        __isArgsStory: true,\n      },\n      originalStoryFn: () => mdxElement,\n    };\n\n    jsxDecorator(mockStoryFn, context as any);\n\n    // First verify that useState was called with the correct JSX string\n    expect(mockedEmitTransformCode).toHaveBeenCalledWith(\n      expect.stringContaining('Hello MDX'),\n      context\n    );\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/docs/jsxDecorator.tsx",
    "content": "import type { ReactElement, ReactNode } from 'react';\nimport React, { createElement, isValidElement } from 'react';\n\nimport { logger } from 'storybook/internal/client-logger';\nimport { SourceType, getDocgenSection } from 'storybook/internal/docs-tools';\nimport type { PartialStoryFn, StoryContext } from 'storybook/internal/types';\n\nimport type { Options } from 'react-element-to-jsx-string';\nimport type reactElementToJSXStringType from 'react-element-to-jsx-string';\n// @ts-expect-error (this is needed, because our bundling prefers the `browser` field, but that yields CJS)\nimport reactElementToJSXStringRaw from 'react-element-to-jsx-string/dist/esm/index.js';\nimport { emitTransformCode, useEffect, useRef } from 'storybook/preview-api';\n\nimport type { ReactRenderer } from '../types';\nimport { isForwardRef, isMemo } from './lib/componentTypes';\n\nconst reactElementToJSXString = reactElementToJSXStringRaw as typeof reactElementToJSXStringType;\n\nconst toPascalCase = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);\n\n/**\n * Converts a React symbol to a React-like displayName\n *\n * Symbols come from here\n * https://github.com/facebook/react/blob/338dddc089d5865761219f02b5175db85c54c489/packages/react-devtools-shared/src/backend/ReactSymbols.js\n *\n * @example\n *\n * ```\n * Symbol(react.suspense) -> React.Suspense\n * Symbol(react.strict_mode) -> React.StrictMode\n * Symbol(react.server_context.defaultValue) -> React.ServerContext.DefaultValue\n * ```\n *\n * @param {Symbol} elementType - The symbol to convert\n * @returns {string | null} A displayName for the Symbol in case elementType is a Symbol; otherwise,\n *   null.\n */\nexport const getReactSymbolName = (elementType: any): string => {\n  const elementName = elementType.$$typeof || elementType;\n  const symbolDescription: string = elementName.toString().replace(/^Symbol\\((.*)\\)$/, '$1');\n\n  const reactComponentName = symbolDescription\n    .split('.')\n    .map((segment) => {\n      // Split segment by underscore to handle cases like 'strict_mode' separately, and PascalCase them\n      return segment.split('_').map(toPascalCase).join('');\n    })\n    .join('.');\n  return reactComponentName;\n};\n\n// Recursively remove \"_owner\" property from elements to avoid crash on docs page when passing components as an array prop (#17482)\n// Note: It may be better to use this function only in development environment.\nfunction simplifyNodeForStringify(node: ReactNode): ReactNode {\n  if (isValidElement(node)) {\n    const props = Object.keys(node.props).reduce<{ [key: string]: any }>((acc, cur) => {\n      acc[cur] = simplifyNodeForStringify(node.props[cur]);\n      return acc;\n    }, {});\n    return {\n      ...node,\n      props,\n      // @ts-expect-error (this is an internal or removed api)\n      _owner: null,\n    };\n  }\n  if (Array.isArray(node)) {\n    return node.map(simplifyNodeForStringify);\n  }\n  return node;\n}\n\ntype JSXOptions = Options & {\n  /** How many wrappers to skip when rendering the jsx */\n  skip?: number;\n  /** Whether to show the function in the jsx tab */\n  showFunctions?: boolean;\n  /** Whether to format HTML or Vue markup */\n  enableBeautify?: boolean;\n  /** Override the display name used for a component */\n  displayName?: string | Options['displayName'];\n};\n\n/** Apply the users parameters and render the jsx for a story */\nexport const renderJsx = (code: React.ReactElement, options?: JSXOptions) => {\n  if (typeof code === 'undefined') {\n    logger.warn('Too many skip or undefined component');\n    return null;\n  }\n\n  let renderedJSX = code;\n  const Type = renderedJSX.type;\n\n  // @ts-expect-error (Converted from ts-ignore)\n  for (let i = 0; i < options?.skip; i += 1) {\n    if (typeof renderedJSX === 'undefined') {\n      logger.warn('Cannot skip undefined element');\n      return null;\n    }\n\n    if (React.Children.count(renderedJSX) > 1) {\n      logger.warn('Trying to skip an array of elements');\n      return null;\n    }\n\n    if (typeof renderedJSX.props.children === 'undefined') {\n      logger.warn('Not enough children to skip elements.');\n\n      if (typeof renderedJSX.type === 'function' && renderedJSX.type.name === '') {\n        renderedJSX = <Type {...renderedJSX.props} />;\n      }\n    } else if (typeof renderedJSX.props.children === 'function') {\n      renderedJSX = renderedJSX.props.children();\n    } else {\n      renderedJSX = renderedJSX.props.children;\n    }\n  }\n\n  let displayNameDefaults;\n\n  if (typeof options?.displayName === 'string') {\n    displayNameDefaults = { showFunctions: true, displayName: () => options.displayName };\n    /**\n     * Add `renderedJSX?.type`to handle this case:\n     *\n     * https://github.com/zhyd1997/storybook/blob/20863a75ba4026d7eba6b288991a2cf091d4dfff/code/renderers/react/template/stories/errors.stories.tsx#L14\n     *\n     * Or it show the error message when run `yarn build-storybook --quiet`:\n     *\n     * Cannot read properties of undefined (reading '__docgenInfo').\n     */\n  } else {\n    displayNameDefaults = {\n      // To get exotic component names resolving properly\n      displayName: (el: any): string => {\n        if (el.type.displayName) {\n          return el.type.displayName;\n        } else if (getDocgenSection(el.type, 'displayName')) {\n          return getDocgenSection(el.type, 'displayName');\n        } else if (el.type.render?.displayName) {\n          return el.type.render.displayName;\n        } else if (\n          typeof el.type === 'symbol' ||\n          (el.type.$$typeof && typeof el.type.$$typeof === 'symbol')\n        ) {\n          return getReactSymbolName(el.type);\n        } else if (el.type.name && el.type.name !== '_default') {\n          return el.type.name;\n        } else if (typeof el.type === 'function') {\n          return 'No Display Name';\n        } else if (isForwardRef(el.type)) {\n          return el.type.render.name;\n        } else if (isMemo(el.type)) {\n          return el.type.type.name;\n        } else {\n          return el.type;\n        }\n      },\n    };\n  }\n\n  const filterDefaults = {\n    filterProps: (value: any, key: string): boolean => value !== undefined,\n  };\n\n  const opts = {\n    ...displayNameDefaults,\n    ...filterDefaults,\n    ...options,\n  };\n\n  const result = React.Children.map(code, (c) => {\n    // @ts-expect-error FIXME: workaround react-element-to-jsx-string\n    const child = typeof c === 'number' ? c.toString() : c;\n    const toJSXString =\n      typeof reactElementToJSXString === 'function'\n        ? reactElementToJSXString\n        : // @ts-expect-error (Converted from ts-ignore)\n          reactElementToJSXString.default;\n    let string: string = toJSXString(simplifyNodeForStringify(child), opts as Options);\n\n    if (string.indexOf('&quot;') > -1) {\n      const matches = string.match(/\\S+=\\\\\"([^\"]*)\\\\\"/g);\n      if (matches) {\n        matches.forEach((match) => {\n          string = string.replace(match, match.replace(/&quot;/g, \"'\"));\n        });\n      }\n    }\n\n    return string;\n  }).join('\\n');\n\n  return result.replace(/function\\s+noRefCheck\\(\\)\\s*\\{\\}/g, '() => {}');\n};\n\nconst defaultOpts = {\n  skip: 0,\n  showFunctions: false,\n  enableBeautify: true,\n  showDefaultProps: false,\n};\n\nexport const skipJsxRender = (context: StoryContext<ReactRenderer>) => {\n  const sourceParams = context?.parameters.docs?.source;\n  const isArgsStory = context?.parameters.__isArgsStory;\n\n  // always render if the user forces it\n  if (sourceParams?.type === SourceType.DYNAMIC) {\n    return false;\n  }\n\n  // never render if the user is forcing the block to render code, or\n  // if the user provides code, or if it's not an args story.\n  return !isArgsStory || sourceParams?.code || sourceParams?.type === SourceType.CODE;\n};\n\nconst isMdx = (node: any) => node.type?.displayName === 'MDXCreateElement' && !!node.props?.mdxType;\n\nconst mdxToJsx = (node: any) => {\n  if (!isMdx(node)) {\n    return node;\n  }\n  const { mdxType, originalType, children, ...rest } = node.props;\n  let jsxChildren = [] as ReactElement[];\n  if (children) {\n    const array = Array.isArray(children) ? children : [children];\n    jsxChildren = array.map(mdxToJsx);\n  }\n  return createElement(originalType, rest, ...jsxChildren);\n};\n\nexport const jsxDecorator = (\n  storyFn: PartialStoryFn<ReactRenderer>,\n  context: StoryContext<ReactRenderer>\n) => {\n  const jsx = useRef<undefined | string>(undefined);\n  const story = storyFn();\n\n  const skip = skipJsxRender(context);\n\n  const options = {\n    ...defaultOpts,\n    ...(context?.parameters.jsx || {}),\n  } as Required<JSXOptions>;\n\n  const storyJsx = context.originalStoryFn(context.args, context);\n\n  useEffect(() => {\n    if (skip) {\n      return;\n    }\n\n    const sourceJsx = mdxToJsx(storyJsx);\n\n    const rendered = renderJsx(sourceJsx, options);\n    if (rendered && jsx.current !== rendered) {\n      emitTransformCode(rendered, context);\n      jsx.current = rendered;\n    }\n  });\n\n  return story;\n};\n"
  },
  {
    "path": "code/renderers/react/src/docs/lib/captions.ts",
    "content": "export const CUSTOM_CAPTION = 'custom';\nexport const OBJECT_CAPTION = 'object';\nexport const ARRAY_CAPTION = 'array';\nexport const CLASS_CAPTION = 'class';\nexport const FUNCTION_CAPTION = 'func';\nexport const ELEMENT_CAPTION = 'element';\n"
  },
  {
    "path": "code/renderers/react/src/docs/lib/componentTypes.ts",
    "content": "export const isMemo = (component: any) => component.$$typeof === Symbol.for('react.memo');\nexport const isForwardRef = (component: any) =>\n  component.$$typeof === Symbol.for('react.forward_ref');\n"
  },
  {
    "path": "code/renderers/react/src/docs/lib/defaultValues/createDefaultValue.ts",
    "content": "import {\n  type PropDefaultValue,\n  createSummaryValue,\n  isTooLongForDefaultValueSummary,\n} from 'storybook/internal/docs-tools';\n\nimport { ELEMENT_CAPTION, FUNCTION_CAPTION } from '../captions';\nimport { generateCode } from '../generateCode';\nimport type {\n  InspectionElement,\n  InspectionFunction,\n  InspectionIdentifiableInferedType,\n  InspectionResult,\n} from '../inspection';\nimport { InspectionType, inspectValue } from '../inspection';\nimport { isHtmlTag } from '../isHtmlTag';\nimport { generateArray } from './generateArray';\nimport { generateObject } from './generateObject';\nimport { getPrettyIdentifier } from './prettyIdentifier';\n\nfunction generateFunc({ inferredType, ast }: InspectionResult): PropDefaultValue {\n  const { identifier } = inferredType as InspectionFunction;\n\n  if (identifier != null) {\n    return createSummaryValue(\n      getPrettyIdentifier(inferredType as InspectionIdentifiableInferedType),\n      generateCode(ast)\n    );\n  }\n\n  const prettyCaption = generateCode(ast, true);\n\n  return !isTooLongForDefaultValueSummary(prettyCaption)\n    ? createSummaryValue(prettyCaption)\n    : createSummaryValue(FUNCTION_CAPTION, generateCode(ast));\n}\n\n// All elements are JSX elements.\n// JSX elements are not supported by escodegen.\nfunction generateElement(\n  defaultValue: string,\n  inspectionResult: InspectionResult\n): PropDefaultValue {\n  const { inferredType } = inspectionResult;\n  const { identifier } = inferredType as InspectionElement;\n\n  if (identifier != null) {\n    if (!isHtmlTag(identifier)) {\n      const prettyIdentifier = getPrettyIdentifier(\n        inferredType as InspectionIdentifiableInferedType\n      );\n\n      return createSummaryValue(prettyIdentifier, defaultValue);\n    }\n  }\n\n  return !isTooLongForDefaultValueSummary(defaultValue)\n    ? createSummaryValue(defaultValue)\n    : createSummaryValue(ELEMENT_CAPTION, defaultValue);\n}\n\nexport function createDefaultValue(defaultValue: string): PropDefaultValue | null {\n  try {\n    const inspectionResult = inspectValue(defaultValue);\n\n    switch (inspectionResult.inferredType.type) {\n      case InspectionType.OBJECT:\n        return generateObject(inspectionResult);\n      case InspectionType.FUNCTION:\n        return generateFunc(inspectionResult);\n      case InspectionType.ELEMENT:\n        return generateElement(defaultValue, inspectionResult);\n      case InspectionType.ARRAY:\n        return generateArray(inspectionResult);\n      default:\n        return null;\n    }\n  } catch (e) {\n    console.error(e);\n  }\n\n  return null;\n}\n"
  },
  {
    "path": "code/renderers/react/src/docs/lib/defaultValues/createFromRawDefaultProp.ts",
    "content": "import {\n  type PropDef,\n  type PropDefaultValue,\n  createSummaryValue,\n  isTooLongForDefaultValueSummary,\n} from 'storybook/internal/docs-tools';\n\nimport { isFunction, isPlainObject, isString } from 'es-toolkit/predicate';\nimport type reactElementToJSXStringType from 'react-element-to-jsx-string';\n// @ts-expect-error (this is needed, because our bundling prefers the `browser` field, but that yields CJS)\nimport reactElementToJSXStringRaw from 'react-element-to-jsx-string/dist/esm/index.js';\n\nimport { ELEMENT_CAPTION, FUNCTION_CAPTION, OBJECT_CAPTION } from '../captions';\nimport type { InspectionFunction } from '../inspection';\nimport { inspectValue } from '../inspection';\nimport { isHtmlTag } from '../isHtmlTag';\nimport { generateArray } from './generateArray';\nimport { generateObject } from './generateObject';\nimport { getPrettyElementIdentifier, getPrettyFuncIdentifier } from './prettyIdentifier';\n\nconst reactElementToJSXString = reactElementToJSXStringRaw as typeof reactElementToJSXStringType;\n\nexport type TypeResolver = (rawDefaultProp: any, propDef: PropDef) => PropDefaultValue;\n\nexport interface TypeResolvers {\n  string: TypeResolver;\n  object: TypeResolver;\n  function: TypeResolver;\n  default: TypeResolver;\n}\n\nfunction isReactElement(element: any): boolean {\n  return element.$$typeof != null;\n}\n\nexport function extractFunctionName(func: Function, propName: string): string | null {\n  const { name } = func;\n\n  // Comparison with the prop name is to discard inferred function names.\n  if (name !== '' && name !== 'anonymous' && name !== propName) {\n    return name;\n  }\n\n  return null;\n}\n\nconst stringResolver: TypeResolver = (rawDefaultProp) => {\n  return createSummaryValue(JSON.stringify(rawDefaultProp));\n};\n\nfunction generateReactObject(rawDefaultProp: any) {\n  const { type } = rawDefaultProp;\n  const { displayName } = type;\n\n  const jsx = reactElementToJSXString(rawDefaultProp, {});\n\n  if (displayName != null) {\n    const prettyIdentifier = getPrettyElementIdentifier(displayName);\n\n    return createSummaryValue(prettyIdentifier, jsx);\n  }\n\n  if (isString(type)) {\n    // This is an HTML element.\n    if (isHtmlTag(type)) {\n      const jsxCompact = reactElementToJSXString(rawDefaultProp, { tabStop: 0 });\n      const jsxSummary = jsxCompact.replace(/\\r?\\n|\\r/g, '');\n\n      if (!isTooLongForDefaultValueSummary(jsxSummary)) {\n        return createSummaryValue(jsxSummary);\n      }\n    }\n  }\n\n  return createSummaryValue(ELEMENT_CAPTION, jsx);\n}\n\nconst objectResolver: TypeResolver = (rawDefaultProp) => {\n  if (isReactElement(rawDefaultProp) && rawDefaultProp.type != null) {\n    return generateReactObject(rawDefaultProp);\n  }\n\n  if (isPlainObject(rawDefaultProp)) {\n    const inspectionResult = inspectValue(JSON.stringify(rawDefaultProp));\n\n    return generateObject(inspectionResult);\n  }\n\n  if (Array.isArray(rawDefaultProp)) {\n    const inspectionResult = inspectValue(JSON.stringify(rawDefaultProp));\n\n    return generateArray(inspectionResult);\n  }\n\n  return createSummaryValue(OBJECT_CAPTION);\n};\n\nconst functionResolver: TypeResolver = (rawDefaultProp, propDef) => {\n  let isElement = false;\n  let inspectionResult;\n\n  // Try to display the name of the component. The body of the component is omitted since the code has been transpiled.\n  if (isFunction(rawDefaultProp.render)) {\n    isElement = true;\n  } else if (rawDefaultProp.prototype != null && isFunction(rawDefaultProp.prototype.render)) {\n    isElement = true;\n  } else {\n    let innerElement;\n\n    try {\n      inspectionResult = inspectValue(rawDefaultProp.toString());\n\n      const { hasParams, params } = inspectionResult.inferredType as InspectionFunction;\n      if (hasParams) {\n        // It might be a functional component accepting props.\n        if (params.length === 1 && params[0].type === 'ObjectPattern') {\n          innerElement = rawDefaultProp({});\n        }\n      } else {\n        innerElement = rawDefaultProp();\n      }\n\n      if (innerElement != null) {\n        if (isReactElement(innerElement)) {\n          isElement = true;\n        }\n      }\n    } catch (e) {\n      // do nothing.\n    }\n  }\n\n  const funcName = extractFunctionName(rawDefaultProp, propDef.name);\n  if (funcName != null) {\n    if (isElement) {\n      return createSummaryValue(getPrettyElementIdentifier(funcName));\n    }\n\n    if (inspectionResult != null) {\n      inspectionResult = inspectValue(rawDefaultProp.toString());\n    }\n\n    // @ts-expect-error (Converted from ts-ignore)\n    const { hasParams } = inspectionResult.inferredType as InspectionFunction;\n\n    return createSummaryValue(getPrettyFuncIdentifier(funcName, hasParams));\n  }\n\n  return createSummaryValue(isElement ? ELEMENT_CAPTION : FUNCTION_CAPTION);\n};\n\nconst defaultResolver: TypeResolver = (rawDefaultProp) => {\n  return createSummaryValue(rawDefaultProp.toString());\n};\n\nconst DEFAULT_TYPE_RESOLVERS: TypeResolvers = {\n  string: stringResolver,\n  object: objectResolver,\n  function: functionResolver,\n  default: defaultResolver,\n};\n\nexport function createTypeResolvers(customResolvers: Partial<TypeResolvers> = {}): TypeResolvers {\n  return {\n    ...DEFAULT_TYPE_RESOLVERS,\n    ...customResolvers,\n  };\n}\n\n// When react-docgen cannot provide a defaultValue we take it from the raw defaultProp.\n// It works fine for types that are not transpiled. For the types that are transpiled, we can only provide partial support.\n// This means that:\n//   - The detail might not be available.\n//   - Identifiers might not be \"prettified\" for all the types.\nexport function createDefaultValueFromRawDefaultProp(\n  rawDefaultProp: any,\n  propDef: PropDef,\n  typeResolvers: TypeResolvers = DEFAULT_TYPE_RESOLVERS\n): PropDefaultValue | null {\n  try {\n    // Keep the extra () otherwise it will fail for functions.\n    switch (typeof rawDefaultProp) {\n      case 'string':\n        return typeResolvers.string(rawDefaultProp, propDef);\n      case 'object':\n        return typeResolvers.object(rawDefaultProp, propDef);\n      case 'function': {\n        return typeResolvers.function(rawDefaultProp, propDef);\n      }\n      default:\n        return typeResolvers.default(rawDefaultProp, propDef);\n    }\n  } catch (e) {\n    console.error(e);\n  }\n\n  return null;\n}\n"
  },
  {
    "path": "code/renderers/react/src/docs/lib/defaultValues/generateArray.ts",
    "content": "import {\n  type PropDefaultValue,\n  createSummaryValue,\n  isTooLongForDefaultValueSummary,\n} from 'storybook/internal/docs-tools';\n\nimport { ARRAY_CAPTION } from '../captions';\nimport { generateArrayCode } from '../generateCode';\nimport type { InspectionArray, InspectionResult } from '../inspection';\n\nexport function generateArray({ inferredType, ast }: InspectionResult): PropDefaultValue {\n  const { depth } = inferredType as InspectionArray;\n\n  if (depth <= 2) {\n    const compactArray = generateArrayCode(ast, true);\n\n    if (!isTooLongForDefaultValueSummary(compactArray)) {\n      return createSummaryValue(compactArray);\n    }\n  }\n\n  return createSummaryValue(ARRAY_CAPTION, generateArrayCode(ast));\n}\n"
  },
  {
    "path": "code/renderers/react/src/docs/lib/defaultValues/generateObject.ts",
    "content": "import {\n  type PropDefaultValue,\n  createSummaryValue,\n  isTooLongForDefaultValueSummary,\n} from 'storybook/internal/docs-tools';\n\nimport { OBJECT_CAPTION } from '../captions';\nimport { generateObjectCode } from '../generateCode';\nimport type { InspectionArray, InspectionResult } from '../inspection';\n\nexport function generateObject({ inferredType, ast }: InspectionResult): PropDefaultValue {\n  const { depth } = inferredType as InspectionArray;\n\n  if (depth === 1) {\n    const compactObject = generateObjectCode(ast, true);\n\n    if (!isTooLongForDefaultValueSummary(compactObject)) {\n      return createSummaryValue(compactObject);\n    }\n  }\n\n  return createSummaryValue(OBJECT_CAPTION, generateObjectCode(ast));\n}\n"
  },
  {
    "path": "code/renderers/react/src/docs/lib/defaultValues/index.ts",
    "content": "export * from './createDefaultValue';\nexport * from './createFromRawDefaultProp';\n"
  },
  {
    "path": "code/renderers/react/src/docs/lib/defaultValues/prettyIdentifier.ts",
    "content": "import type { InspectionFunction, InspectionIdentifiableInferedType } from '../inspection';\nimport { InspectionType } from '../inspection';\n\nexport function getPrettyFuncIdentifier(identifier: string, hasArguments: boolean): string {\n  return hasArguments ? `${identifier}( ... )` : `${identifier}()`;\n}\n\nexport function getPrettyElementIdentifier(identifier: string) {\n  return `<${identifier} />`;\n}\n\nexport function getPrettyIdentifier(inferredType: InspectionIdentifiableInferedType): string {\n  const { type, identifier } = inferredType;\n\n  switch (type) {\n    case InspectionType.FUNCTION:\n      // @ts-expect-error (Converted from ts-ignore)\n      return getPrettyFuncIdentifier(identifier, (inferredType as InspectionFunction).hasParams);\n    case InspectionType.ELEMENT:\n      // @ts-expect-error (Converted from ts-ignore)\n      return getPrettyElementIdentifier(identifier);\n    default:\n      return identifier;\n  }\n}\n"
  },
  {
    "path": "code/renderers/react/src/docs/lib/generateCode.ts",
    "content": "import { generate } from 'escodegen';\nimport { dedent } from 'ts-dedent';\n\nconst BASIC_OPTIONS = {\n  format: {\n    indent: {\n      style: '  ',\n    },\n    semicolons: false,\n  },\n};\n\nconst COMPACT_OPTIONS = {\n  ...BASIC_OPTIONS,\n  format: {\n    newline: '',\n  },\n};\n\nconst PRETTY_OPTIONS = {\n  ...BASIC_OPTIONS,\n};\n\nexport function generateCode(ast: any, compact = false): string {\n  return generate(ast, compact ? COMPACT_OPTIONS : PRETTY_OPTIONS);\n}\n\nexport function generateObjectCode(ast: any, compact = false): string {\n  return !compact ? generateCode(ast) : generateCompactObjectCode(ast);\n}\n\nfunction generateCompactObjectCode(ast: any): string {\n  let result = generateCode(ast, true);\n\n  // Cannot get escodegen to add a space before the last } with the compact mode settings.\n  // Fix it until a better solution is found.\n  if (!result.endsWith(' }')) {\n    result = `${result.slice(0, -1)} }`;\n  }\n\n  return result;\n}\n\nexport function generateArrayCode(ast: any, compact = false): string {\n  return !compact ? generateMultilineArrayCode(ast) : generateCompactArrayCode(ast);\n}\n\nfunction generateMultilineArrayCode(ast: any): string {\n  let result = generateCode(ast);\n\n  // escodegen add extra spacing before the closing bracket of a multiple line array with a nested object.\n  // Fix it until a better solution is found.\n  if (result.endsWith('  }]')) {\n    result = dedent(result);\n  }\n\n  return result;\n}\n\nfunction generateCompactArrayCode(ast: any): string {\n  let result = generateCode(ast, true);\n\n  // escodegen add extra an extra before the opening bracket of a compact array that contains primitive values.\n  // Fix it until a better solution is found.\n  if (result.startsWith('[    ')) {\n    result = result.replace('[    ', '[');\n  }\n\n  return result;\n}\n"
  },
  {
    "path": "code/renderers/react/src/docs/lib/inspection/acornParser.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { parse } from './acornParser';\nimport type {\n  InspectionArray,\n  InspectionElement,\n  InspectionFunction,\n  InspectionIdentifier,\n  InspectionLiteral,\n  InspectionObject,\n  InspectionUnknown,\n} from './types';\nimport { InspectionType } from './types';\n\ndescribe('parse', () => {\n  describe('expression', () => {\n    it('support HTML element', () => {\n      const result = parse('<div>Hello!</div>');\n      const inferredType = result.inferredType as InspectionElement;\n\n      expect(inferredType.type).toBe(InspectionType.ELEMENT);\n      expect(inferredType.identifier).toBe('div');\n      expect(result.ast).toBeDefined();\n    });\n\n    it('support React declaration', () => {\n      const result = parse('<FunctionalComponent />');\n      const inferredType = result.inferredType as InspectionElement;\n\n      expect(inferredType.type).toBe(InspectionType.ELEMENT);\n      expect(inferredType.identifier).toBe('FunctionalComponent');\n      expect(result.ast).toBeDefined();\n    });\n\n    it('support anonymous functional React component', () => {\n      const result = parse('() => { return <div>Hey!</div>; }');\n      const inferredType = result.inferredType as InspectionElement;\n\n      expect(inferredType.type).toBe(InspectionType.ELEMENT);\n      expect(inferredType.identifier).toBeUndefined();\n      expect(result.ast).toBeDefined();\n    });\n\n    it('support named functional React component', () => {\n      const result = parse('function NamedFunctionalComponent() { return <div>Hey!</div>; }');\n      const inferredType = result.inferredType as InspectionElement;\n\n      expect(inferredType.type).toBe(InspectionType.ELEMENT);\n      expect(inferredType.identifier).toBe('NamedFunctionalComponent');\n      expect(result.ast).toBeDefined();\n    });\n\n    it('support class React component', () => {\n      const result = parse(`\n        class ClassComponent extends React.PureComponent {\n          render() {\n            return <div>Hey!</div>;\n          }\n      }`);\n      const inferredType = result.inferredType as InspectionElement;\n\n      expect(inferredType.type).toBe(InspectionType.ELEMENT);\n      expect(inferredType.identifier).toBe('ClassComponent');\n      expect(result.ast).toBeDefined();\n    });\n\n    it('support PropTypes.shape', () => {\n      const result = parse('PropTypes.shape({ foo: PropTypes.string })');\n      const inferredType = result.inferredType as InspectionObject;\n\n      expect(inferredType.type).toBe(InspectionType.OBJECT);\n      expect(inferredType.depth).toBe(1);\n      expect(result.ast).toBeDefined();\n    });\n\n    it('support deep PropTypes.shape', () => {\n      const result = parse('PropTypes.shape({ foo: PropTypes.shape({ bar: PropTypes.string }) })');\n      const inferredType = result.inferredType as InspectionObject;\n\n      expect(inferredType.type).toBe(InspectionType.OBJECT);\n      expect(inferredType.depth).toBe(2);\n      expect(result.ast).toBeDefined();\n    });\n\n    it('support shape', () => {\n      const result = parse('shape({ foo: string })');\n      const inferredType = result.inferredType as InspectionObject;\n\n      expect(inferredType.type).toBe(InspectionType.OBJECT);\n      expect(inferredType.depth).toBe(1);\n      expect(result.ast).toBeDefined();\n    });\n\n    it('support deep shape', () => {\n      const result = parse('shape({ foo: shape({ bar: string }) })');\n      const inferredType = result.inferredType as InspectionObject;\n\n      expect(inferredType.type).toBe(InspectionType.OBJECT);\n      expect(inferredType.depth).toBe(2);\n      expect(result.ast).toBeDefined();\n    });\n\n    it('support single prop object literal', () => {\n      const result = parse('{ foo: PropTypes.string }');\n      const inferredType = result.inferredType as InspectionObject;\n\n      expect(inferredType.type).toBe(InspectionType.OBJECT);\n      expect(inferredType.depth).toBe(1);\n      expect(result.ast).toBeDefined();\n    });\n\n    it('support multi prop object literal', () => {\n      const result = parse(`\n      {\n          foo: PropTypes.string,\n          bar: PropTypes.string\n      }`);\n      const inferredType = result.inferredType as InspectionObject;\n\n      expect(inferredType.type).toBe(InspectionType.OBJECT);\n      expect(inferredType.depth).toBe(1);\n      expect(result.ast).toBeDefined();\n    });\n\n    it('support deep object literal', () => {\n      const result = parse(`\n      {\n          foo: {\n            hey: PropTypes.string\n          },\n          bar: PropTypes.string,\n          hey: {\n            ho: PropTypes.string\n          }\n      }`);\n      const inferredType = result.inferredType as InspectionObject;\n\n      expect(inferredType.type).toBe(InspectionType.OBJECT);\n      expect(inferredType.depth).toBe(2);\n      expect(result.ast).toBeDefined();\n    });\n\n    it('support required prop', () => {\n      const result = parse('{ foo: PropTypes.string.isRequired }');\n      const inferredType = result.inferredType as InspectionObject;\n\n      expect(inferredType.type).toBe(InspectionType.OBJECT);\n      expect(inferredType.depth).toBe(1);\n      expect(result.ast).toBeDefined();\n    });\n\n    it('support array', () => {\n      const result = parse(\"['bottom-left', 'bottom-center', 'bottom-right']\");\n      const inferredType = result.inferredType as InspectionArray;\n\n      expect(inferredType.type).toBe(InspectionType.ARRAY);\n      expect(inferredType.depth).toBe(1);\n      expect(result.ast).toBeDefined();\n    });\n\n    it('support deep array', () => {\n      const result = parse(\"['bottom-left', { foo: string }, [['hey', 'ho']]]\");\n      const inferredType = result.inferredType as InspectionArray;\n\n      expect(inferredType.type).toBe(InspectionType.ARRAY);\n      expect(inferredType.depth).toBe(3);\n      expect(result.ast).toBeDefined();\n    });\n\n    it('support object identifier', () => {\n      const result = parse('NAMED_OBJECT');\n      const inferredType = result.inferredType as InspectionIdentifier;\n\n      expect(inferredType.type).toBe(InspectionType.IDENTIFIER);\n      expect(inferredType.identifier).toBe('NAMED_OBJECT');\n      expect(result.ast).toBeDefined();\n    });\n\n    it('support anonymous function', () => {\n      const result = parse('() => {}');\n      const inferredType = result.inferredType as InspectionFunction;\n\n      expect(inferredType.type).toBe(InspectionType.FUNCTION);\n      expect(inferredType.identifier).toBeUndefined();\n      expect(inferredType.hasParams).toBeFalsy();\n      expect(inferredType.params.length).toBe(0);\n      expect(result.ast).toBeDefined();\n    });\n\n    it('support anonymous function with arguments', () => {\n      const result = parse('(a, b) => {}');\n      const inferredType = result.inferredType as InspectionFunction;\n\n      expect(inferredType.type).toBe(InspectionType.FUNCTION);\n      expect(inferredType.identifier).toBeUndefined();\n      expect(inferredType.hasParams).toBeTruthy();\n      expect(inferredType.params.length).toBe(2);\n      expect(result.ast).toBeDefined();\n    });\n\n    it('support named function', () => {\n      const result = parse('function concat() {}');\n      const inferredType = result.inferredType as InspectionFunction;\n\n      expect(inferredType.type).toBe(InspectionType.FUNCTION);\n      expect(inferredType.identifier).toBe('concat');\n      expect(inferredType.hasParams).toBeFalsy();\n      expect(inferredType.params.length).toBe(0);\n      expect(result.ast).toBeDefined();\n    });\n\n    it('support named function with arguments', () => {\n      const result = parse('function concat(a, b) {}');\n      const inferredType = result.inferredType as InspectionFunction;\n\n      expect(inferredType.type).toBe(InspectionType.FUNCTION);\n      expect(inferredType.identifier).toBe('concat');\n      expect(inferredType.hasParams).toBeTruthy();\n      expect(inferredType.params.length).toBe(2);\n      expect(result.ast).toBeDefined();\n    });\n\n    it('support class', () => {\n      const result = parse('class Foo {}');\n      const inferredType = result.inferredType as InspectionFunction;\n\n      expect(inferredType.type).toBe(InspectionType.CLASS);\n      expect(inferredType.identifier).toBe('Foo');\n      expect(result.ast).toBeDefined();\n    });\n\n    [\n      { name: 'string', value: \"'string value'\" },\n      { name: 'numeric', value: '1' },\n      { name: 'boolean (true)', value: 'true' },\n      { name: 'boolean (false)', value: 'false' },\n      { name: 'null', value: 'null' },\n    ].forEach((x) => {\n      it(`support ${x.name}`, () => {\n        const result = parse(x.value);\n        const inferredType = result.inferredType as InspectionLiteral;\n\n        expect(inferredType.type).toBe(InspectionType.LITERAL);\n        expect(result.ast).toBeDefined();\n      });\n    });\n\n    it(\"returns Unknown when it's not supported\", () => {\n      const result = parse(\"Symbol('foo')\");\n      const inferredType = result.inferredType as InspectionUnknown;\n\n      expect(inferredType.type).toBe(InspectionType.UNKNOWN);\n      expect(result.ast).toBeDefined();\n    });\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/docs/lib/inspection/acornParser.ts",
    "content": "import { Parser } from 'acorn';\nimport jsx from 'acorn-jsx';\nimport * as acornWalk from 'acorn-walk';\nimport type estree from 'estree';\n\nimport type {\n  InspectionArray,\n  InspectionClass,\n  InspectionElement,\n  InspectionFunction,\n  InspectionIdentifier,\n  InspectionInferedType,\n  InspectionLiteral,\n  InspectionObject,\n  InspectionUnknown,\n} from './types';\nimport { InspectionType } from './types';\n\ninterface ParsingResult<T> {\n  inferredType: T;\n  ast: any;\n}\n\nconst ACORN_WALK_VISITORS = {\n  // @ts-expect-error (Converted from ts-ignore)\n  ...acornWalk.base,\n  JSXElement: () => {},\n};\n\nconst acornParser = Parser.extend(jsx());\n\n// Cannot use \"estree.Identifier\" type because this function also support \"JSXIdentifier\".\nfunction extractIdentifierName(identifierNode: any) {\n  return identifierNode != null ? identifierNode.name : null;\n}\n\nfunction filterAncestors(ancestors: estree.Node[]): estree.Node[] {\n  return ancestors.filter((x) => x.type === 'ObjectExpression' || x.type === 'ArrayExpression');\n}\n\nfunction calculateNodeDepth(node: estree.Expression): number {\n  const depths: number[] = [];\n\n  acornWalk.ancestor(\n    // @ts-expect-error (Converted from ts-ignore)\n    node,\n    {\n      ObjectExpression(_: any, ancestors: estree.Node[]) {\n        depths.push(filterAncestors(ancestors).length);\n      },\n      ArrayExpression(_: any, ancestors: estree.Node[]) {\n        depths.push(filterAncestors(ancestors).length);\n      },\n    },\n    ACORN_WALK_VISITORS\n  );\n\n  return Math.max(...depths);\n}\n\nfunction parseIdentifier(identifierNode: estree.Identifier): ParsingResult<InspectionIdentifier> {\n  return {\n    inferredType: {\n      type: InspectionType.IDENTIFIER,\n      identifier: extractIdentifierName(identifierNode),\n    },\n    ast: identifierNode,\n  };\n}\n\nfunction parseLiteral(literalNode: estree.Literal): ParsingResult<InspectionLiteral> {\n  return {\n    inferredType: { type: InspectionType.LITERAL },\n    ast: literalNode,\n  };\n}\n\nfunction parseFunction(\n  funcNode: estree.FunctionExpression | estree.ArrowFunctionExpression\n): ParsingResult<InspectionFunction | InspectionElement> {\n  let innerJsxElementNode;\n\n  // If there is at least a JSXElement in the body of the function, then it's a React component.\n  acornWalk.simple(\n    // @ts-expect-error (Converted from ts-ignore)\n    funcNode.body,\n    {\n      JSXElement(node: any) {\n        innerJsxElementNode = node;\n      },\n    },\n    ACORN_WALK_VISITORS\n  );\n\n  const isJsx = innerJsxElementNode != null;\n\n  const inferredType: InspectionFunction | InspectionElement = {\n    type: isJsx ? InspectionType.ELEMENT : InspectionType.FUNCTION,\n    params: funcNode.params,\n    hasParams: funcNode.params.length !== 0,\n  };\n\n  const identifierName = extractIdentifierName((funcNode as estree.FunctionExpression).id);\n  if (identifierName != null) {\n    inferredType.identifier = identifierName;\n  }\n\n  return {\n    inferredType,\n    ast: funcNode,\n  };\n}\n\nfunction parseClass(\n  classNode: estree.ClassExpression\n): ParsingResult<InspectionClass | InspectionElement> {\n  let innerJsxElementNode;\n\n  // If there is at least a JSXElement in the body of the class, then it's a React component.\n  acornWalk.simple(\n    // @ts-expect-error (Converted from ts-ignore)\n    classNode.body,\n    {\n      JSXElement(node: any) {\n        innerJsxElementNode = node;\n      },\n    },\n    ACORN_WALK_VISITORS\n  );\n\n  const inferredType: any = {\n    type: innerJsxElementNode != null ? InspectionType.ELEMENT : InspectionType.CLASS,\n    identifier: extractIdentifierName(classNode.id),\n  };\n\n  return {\n    inferredType,\n    ast: classNode,\n  };\n}\n\nfunction parseJsxElement(jsxElementNode: any): ParsingResult<InspectionElement> {\n  const inferredType: InspectionElement = {\n    type: InspectionType.ELEMENT,\n  };\n\n  const identifierName = extractIdentifierName(jsxElementNode.openingElement.name);\n  if (identifierName != null) {\n    inferredType.identifier = identifierName;\n  }\n\n  return {\n    inferredType,\n    ast: jsxElementNode,\n  };\n}\n\nfunction parseCall(callNode: estree.CallExpression): ParsingResult<InspectionObject> | null {\n  const identifierNode =\n    callNode.callee.type === 'MemberExpression' ? callNode.callee.property : callNode.callee;\n\n  const identifierName = extractIdentifierName(identifierNode);\n  if (identifierName === 'shape') {\n    return parseObject(callNode.arguments[0] as estree.ObjectExpression);\n  }\n\n  return null;\n}\n\nfunction parseObject(objectNode: estree.ObjectExpression): ParsingResult<InspectionObject> {\n  return {\n    inferredType: { type: InspectionType.OBJECT, depth: calculateNodeDepth(objectNode) },\n    ast: objectNode,\n  };\n}\n\nfunction parseArray(arrayNode: estree.ArrayExpression): ParsingResult<InspectionArray> {\n  return {\n    inferredType: { type: InspectionType.ARRAY, depth: calculateNodeDepth(arrayNode) },\n    ast: arrayNode,\n  };\n}\n\n// Cannot set \"expression\" type to \"estree.Expression\" because the type doesn't include JSX.\nfunction parseExpression(expression: any): ParsingResult<InspectionInferedType> | null {\n  switch (expression.type) {\n    case 'Identifier':\n      return parseIdentifier(expression);\n    case 'Literal':\n      return parseLiteral(expression);\n    case 'FunctionExpression':\n    case 'ArrowFunctionExpression':\n      return parseFunction(expression);\n    case 'ClassExpression':\n      return parseClass(expression);\n    case 'JSXElement':\n      return parseJsxElement(expression);\n    case 'CallExpression':\n      return parseCall(expression);\n    case 'ObjectExpression':\n      return parseObject(expression);\n    case 'ArrayExpression':\n      return parseArray(expression);\n    default:\n      return null;\n  }\n}\n\nexport function parse(value: string): ParsingResult<InspectionInferedType> {\n  const ast = acornParser.parse(`(${value})`, { ecmaVersion: 2020 }) as unknown as estree.Program;\n\n  let parsingResult: ParsingResult<InspectionUnknown> = {\n    inferredType: { type: InspectionType.UNKNOWN },\n    ast,\n  };\n\n  if (ast.body[0] != null) {\n    const rootNode = ast.body[0];\n\n    switch (rootNode.type) {\n      case 'ExpressionStatement': {\n        const expressionResult = parseExpression(rootNode.expression);\n        if (expressionResult != null) {\n          parsingResult = expressionResult as any;\n        }\n        break;\n      }\n      default:\n        break;\n    }\n  }\n\n  return parsingResult;\n}\n"
  },
  {
    "path": "code/renderers/react/src/docs/lib/inspection/index.ts",
    "content": "export * from './types';\nexport * from './inspectValue';\n"
  },
  {
    "path": "code/renderers/react/src/docs/lib/inspection/inspectValue.ts",
    "content": "import { parse } from './acornParser';\nimport type { InspectionResult } from './types';\nimport { InspectionType } from './types';\n\nexport function inspectValue(value: string): InspectionResult {\n  try {\n    const parsingResult = parse(value);\n\n    return { ...parsingResult };\n  } catch (e) {\n    // do nothing.\n  }\n\n  return { inferredType: { type: InspectionType.UNKNOWN } };\n}\n"
  },
  {
    "path": "code/renderers/react/src/docs/lib/inspection/types.ts",
    "content": "export enum InspectionType {\n  IDENTIFIER = 'Identifier',\n  LITERAL = 'Literal',\n  OBJECT = 'Object',\n  ARRAY = 'Array',\n  FUNCTION = 'Function',\n  CLASS = 'Class',\n  ELEMENT = 'Element',\n  UNKNOWN = 'Unknown',\n}\n\nexport interface InspectionInferedType {\n  type: InspectionType;\n}\n\nexport interface InspectionIdentifier extends InspectionInferedType {\n  type: InspectionType.IDENTIFIER;\n  identifier: string;\n}\n\nexport interface InspectionLiteral extends InspectionInferedType {\n  type: InspectionType.LITERAL;\n}\n\nexport interface InspectionObject extends InspectionInferedType {\n  type: InspectionType.OBJECT;\n  depth: number;\n}\n\nexport interface InspectionArray extends InspectionInferedType {\n  type: InspectionType.ARRAY;\n  depth: number;\n}\n\nexport interface InspectionClass extends InspectionInferedType {\n  type: InspectionType.CLASS;\n  identifier: string;\n}\n\nexport interface InspectionFunction extends InspectionInferedType {\n  type: InspectionType.FUNCTION;\n  identifier?: string;\n  params: any[];\n  hasParams: boolean;\n}\n\nexport interface InspectionElement extends InspectionInferedType {\n  type: InspectionType.ELEMENT;\n  identifier?: string;\n}\n\nexport interface InspectionUnknown extends InspectionInferedType {\n  type: InspectionType.UNKNOWN;\n}\n\nexport type InspectionIdentifiableInferedType =\n  | InspectionIdentifier\n  | InspectionClass\n  | InspectionFunction\n  | InspectionElement;\n\nexport interface InspectionResult {\n  inferredType: InspectionInferedType;\n  ast?: any;\n}\n"
  },
  {
    "path": "code/renderers/react/src/docs/lib/isHtmlTag.ts",
    "content": "import htmlTags from 'html-tags';\n\nexport function isHtmlTag(tagName: string): boolean {\n  return htmlTags.includes(tagName.toLowerCase() as Parameters<typeof htmlTags.includes>[0]);\n}\n"
  },
  {
    "path": "code/renderers/react/src/docs/propTypes/createType.ts",
    "content": "import type { DocgenPropType, ExtractedProp, PropType } from 'storybook/internal/docs-tools';\nimport { createSummaryValue, isTooLongForTypeSummary } from 'storybook/internal/docs-tools';\n\nimport {\n  ARRAY_CAPTION,\n  CLASS_CAPTION,\n  CUSTOM_CAPTION,\n  ELEMENT_CAPTION,\n  FUNCTION_CAPTION,\n  OBJECT_CAPTION,\n} from '../lib/captions';\nimport { generateCode, generateObjectCode } from '../lib/generateCode';\nimport type { InspectionArray, InspectionElement, InspectionObject } from '../lib/inspection';\nimport { InspectionType, inspectValue } from '../lib/inspection';\nimport { isHtmlTag } from '../lib/isHtmlTag';\nimport {\n  generateFuncSignature,\n  generateShortFuncSignature,\n  toMultilineSignature,\n} from './generateFuncSignature';\n\nconst MAX_FUNC_LENGTH = 150;\n\nenum PropTypesType {\n  CUSTOM = 'custom',\n  ANY = 'any',\n  FUNC = 'func',\n  SHAPE = 'shape',\n  OBJECT = 'object',\n  INSTANCEOF = 'instanceOf',\n  OBJECTOF = 'objectOf',\n  UNION = 'union',\n  ENUM = 'enum',\n  ARRAYOF = 'arrayOf',\n  ELEMENT = 'element',\n  ELEMENTTYPE = 'elementType',\n  NODE = 'node',\n}\n\ninterface EnumValue {\n  value: string;\n  computed: boolean;\n}\n\ninterface TypeDef {\n  name: string;\n  short: string;\n  compact: string | null;\n  full: string | null;\n  inferredType?: InspectionType | null;\n}\n\nfunction createTypeDef({\n  name,\n  short,\n  compact,\n  full,\n  inferredType,\n}: {\n  name: string;\n  short: string;\n  compact: string | null;\n  full?: string | null;\n  inferredType?: InspectionType | null;\n}): TypeDef {\n  return {\n    name,\n    short,\n    compact,\n    full: full != null ? full : short,\n    inferredType,\n  };\n}\n\nfunction cleanPropTypes(value: string): string {\n  return value.replace(/PropTypes./g, '').replace(/.isRequired/g, '');\n}\n\nfunction splitIntoLines(value: string): string[] {\n  return value.split(/\\r?\\n/);\n}\n\nfunction prettyObject(ast: any, compact = false): string {\n  return cleanPropTypes(generateObjectCode(ast, compact));\n}\n\nfunction prettyArray(ast: any, compact = false): string {\n  return cleanPropTypes(generateCode(ast, compact));\n}\n\nfunction getCaptionForInspectionType(type: InspectionType): string {\n  switch (type) {\n    case InspectionType.OBJECT:\n      return OBJECT_CAPTION;\n    case InspectionType.ARRAY:\n      return ARRAY_CAPTION;\n    case InspectionType.CLASS:\n      return CLASS_CAPTION;\n    case InspectionType.FUNCTION:\n      return FUNCTION_CAPTION;\n    case InspectionType.ELEMENT:\n      return ELEMENT_CAPTION;\n    default:\n      return CUSTOM_CAPTION;\n  }\n}\n\nfunction generateTypeFromString(value: string, originalTypeName: string): TypeDef {\n  const { inferredType, ast } = inspectValue(value);\n  const { type } = inferredType;\n\n  let short;\n  let compact;\n  let full;\n\n  switch (type) {\n    case InspectionType.IDENTIFIER:\n    case InspectionType.LITERAL:\n      short = value;\n      compact = value;\n      break;\n    case InspectionType.OBJECT: {\n      const { depth } = inferredType as InspectionObject;\n\n      short = OBJECT_CAPTION;\n      compact = depth === 1 ? prettyObject(ast, true) : null;\n      full = prettyObject(ast);\n      break;\n    }\n    case InspectionType.ELEMENT: {\n      const { identifier } = inferredType as InspectionElement;\n\n      short = identifier != null && !isHtmlTag(identifier) ? identifier : ELEMENT_CAPTION;\n      compact = splitIntoLines(value).length === 1 ? value : null;\n      full = value;\n      break;\n    }\n    case InspectionType.ARRAY: {\n      const { depth } = inferredType as InspectionArray;\n\n      short = ARRAY_CAPTION;\n      compact = depth <= 2 ? prettyArray(ast, true) : null;\n      full = prettyArray(ast);\n      break;\n    }\n    default:\n      short = getCaptionForInspectionType(type);\n      compact = splitIntoLines(value).length === 1 ? value : null;\n      full = value;\n      break;\n  }\n\n  return createTypeDef({\n    name: originalTypeName,\n    short,\n    compact,\n    full,\n    inferredType: type,\n  });\n}\n\nfunction generateCustom({ raw }: DocgenPropType): TypeDef {\n  if (raw != null) {\n    return generateTypeFromString(raw, PropTypesType.CUSTOM);\n  }\n\n  return createTypeDef({\n    name: PropTypesType.CUSTOM,\n    short: CUSTOM_CAPTION,\n    compact: CUSTOM_CAPTION,\n  });\n}\n\nfunction generateFunc(extractedProp: ExtractedProp): TypeDef {\n  const { jsDocTags } = extractedProp;\n\n  if (jsDocTags != null) {\n    if (jsDocTags.params != null || jsDocTags.returns != null) {\n      return createTypeDef({\n        name: PropTypesType.FUNC,\n        // @ts-expect-error (Converted from ts-ignore)\n        short: generateShortFuncSignature(jsDocTags.params, jsDocTags.returns),\n        compact: null,\n        // @ts-expect-error (Converted from ts-ignore)\n        full: generateFuncSignature(jsDocTags.params, jsDocTags.returns),\n      });\n    }\n  }\n\n  return createTypeDef({\n    name: PropTypesType.FUNC,\n    short: FUNCTION_CAPTION,\n    compact: FUNCTION_CAPTION,\n  });\n}\n\nfunction generateShape(type: DocgenPropType, extractedProp: ExtractedProp): TypeDef {\n  const fields = Object.keys(type.value)\n    .map((key: string) => `${key}: ${generateType(type.value[key], extractedProp).full}`)\n    .join(', ');\n\n  const { inferredType, ast } = inspectValue(`{ ${fields} }`);\n  const { depth } = inferredType as InspectionObject;\n\n  return createTypeDef({\n    name: PropTypesType.SHAPE,\n    short: OBJECT_CAPTION,\n    compact: depth === 1 && ast ? prettyObject(ast, true) : null,\n    full: ast ? prettyObject(ast) : null,\n  });\n}\n\nfunction objectOf(of: string): string {\n  return `objectOf(${of})`;\n}\n\nfunction generateObjectOf(type: DocgenPropType, extractedProp: ExtractedProp): TypeDef {\n  const { short, compact, full } = generateType(type.value, extractedProp);\n\n  return createTypeDef({\n    name: PropTypesType.OBJECTOF,\n    short: objectOf(short),\n    compact: compact != null ? objectOf(compact) : null,\n    full: full ? objectOf(full) : full,\n  });\n}\n\nfunction generateUnion(type: DocgenPropType, extractedProp: ExtractedProp): TypeDef {\n  if (Array.isArray(type.value)) {\n    const values = type.value.reduce(\n      (acc: any, v: any) => {\n        const { short, compact, full } = generateType(v, extractedProp);\n\n        acc.short.push(short);\n        acc.compact.push(compact);\n        acc.full.push(full);\n\n        return acc;\n      },\n      { short: [], compact: [], full: [] }\n    );\n\n    return createTypeDef({\n      name: PropTypesType.UNION,\n      short: values.short.join(' | '),\n      compact: values.compact.every((x: string) => x != null) ? values.compact.join(' | ') : null,\n      full: values.full.join(' | '),\n    });\n  }\n\n  return createTypeDef({ name: PropTypesType.UNION, short: type.value, compact: null });\n}\n\nfunction generateEnumValue({ value, computed }: EnumValue): TypeDef {\n  return computed\n    ? generateTypeFromString(value, 'enumvalue')\n    : createTypeDef({ name: 'enumvalue', short: value, compact: value });\n}\n\nfunction generateEnum(type: DocgenPropType): TypeDef {\n  if (Array.isArray(type.value)) {\n    const values = type.value.reduce(\n      (acc: any, v: EnumValue) => {\n        const { short, compact, full } = generateEnumValue(v);\n\n        acc.short.push(short);\n        acc.compact.push(compact);\n        acc.full.push(full);\n\n        return acc;\n      },\n      { short: [], compact: [], full: [] }\n    );\n\n    return createTypeDef({\n      name: PropTypesType.ENUM,\n      short: values.short.join(' | '),\n      compact: values.compact.every((x: string) => x != null) ? values.compact.join(' | ') : null,\n      full: values.full.join(' | '),\n    });\n  }\n\n  return createTypeDef({ name: PropTypesType.ENUM, short: type.value, compact: type.value });\n}\n\nfunction braceAfter(of: string): string {\n  return `${of}[]`;\n}\n\nfunction braceAround(of: string): string {\n  return `[${of}]`;\n}\n\nfunction createArrayOfObjectTypeDef(\n  short: string,\n  compact: string | null,\n  full: string | null\n): TypeDef {\n  return createTypeDef({\n    name: PropTypesType.ARRAYOF,\n    short: braceAfter(short),\n    compact: compact != null ? braceAround(compact) : null,\n    full: full ? braceAround(full) : full,\n  });\n}\n\nfunction generateArray(type: DocgenPropType, extractedProp: ExtractedProp): TypeDef {\n  const { name, short, compact, full, inferredType } = generateType(type.value, extractedProp);\n\n  if (name === PropTypesType.CUSTOM) {\n    if (inferredType === InspectionType.OBJECT) {\n      return createArrayOfObjectTypeDef(short, compact, full);\n    }\n  } else if (name === PropTypesType.SHAPE) {\n    return createArrayOfObjectTypeDef(short, compact, full);\n  }\n\n  return createTypeDef({\n    name: PropTypesType.ARRAYOF,\n    short: braceAfter(short),\n    compact: braceAfter(short),\n  });\n}\n\nfunction generateType(type: DocgenPropType, extractedProp: ExtractedProp): TypeDef {\n  try {\n    switch (type.name) {\n      case PropTypesType.CUSTOM:\n        return generateCustom(type);\n      case PropTypesType.FUNC:\n        return generateFunc(extractedProp);\n      case PropTypesType.SHAPE:\n        return generateShape(type, extractedProp);\n      case PropTypesType.INSTANCEOF:\n        return createTypeDef({\n          name: PropTypesType.INSTANCEOF,\n          short: type.value,\n          compact: type.value,\n        });\n      case PropTypesType.OBJECTOF:\n        return generateObjectOf(type, extractedProp);\n      case PropTypesType.UNION:\n        return generateUnion(type, extractedProp);\n      case PropTypesType.ENUM:\n        return generateEnum(type);\n      case PropTypesType.ARRAYOF:\n        return generateArray(type, extractedProp);\n      default:\n        return createTypeDef({ name: type.name, short: type.name, compact: type.name });\n    }\n  } catch (e) {\n    console.error(e);\n  }\n\n  return createTypeDef({ name: 'unknown', short: 'unknown', compact: 'unknown' });\n}\n\nexport function createType(extractedProp: ExtractedProp): PropType | null {\n  const { type } = extractedProp.docgenInfo;\n\n  // A type could be null if a defaultProp has been provided without a type definition.\n  if (type == null) {\n    return null;\n  }\n\n  try {\n    switch (type.name) {\n      case PropTypesType.CUSTOM:\n      case PropTypesType.SHAPE:\n      case PropTypesType.INSTANCEOF:\n      case PropTypesType.OBJECTOF:\n      case PropTypesType.UNION:\n      case PropTypesType.ENUM:\n      case PropTypesType.ARRAYOF: {\n        const { short, compact, full } = generateType(type, extractedProp);\n\n        if (compact != null) {\n          if (!isTooLongForTypeSummary(compact)) {\n            return createSummaryValue(compact);\n          }\n        }\n\n        return full ? createSummaryValue(short, full) : createSummaryValue(short);\n      }\n      case PropTypesType.FUNC: {\n        const { short, full } = generateType(type, extractedProp);\n\n        let summary = short;\n        let detail;\n\n        if (full && full.length < MAX_FUNC_LENGTH) {\n          summary = full;\n        } else if (full) {\n          detail = toMultilineSignature(full);\n        }\n\n        return createSummaryValue(summary, detail);\n      }\n      default:\n        return null;\n    }\n  } catch (e) {\n    console.error(e);\n  }\n\n  return null;\n}\n"
  },
  {
    "path": "code/renderers/react/src/docs/propTypes/generateFuncSignature.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { parseJsDoc } from 'storybook/internal/docs-tools';\n\nimport { generateFuncSignature, generateShortFuncSignature } from './generateFuncSignature';\n\ndescribe('generateFuncSignature', () => {\n  it('should return an empty string when there is no @params and @returns tags', () => {\n    // @ts-expect-error (invalid input)\n    const result = generateFuncSignature(null, null);\n\n    expect(result).toBe('');\n  });\n\n  it('should return a signature with a single arg when there is a @param tag with a name', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc('@param event').extractedTags;\n    const result = generateFuncSignature(params, returns);\n\n    expect(result).toBe('(event)');\n  });\n\n  it('should return a signature with a single arg when there is a @param tag with a name and a type', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc('@param {SyntheticEvent} event').extractedTags;\n    const result = generateFuncSignature(params, returns);\n\n    expect(result).toBe('(event: SyntheticEvent)');\n  });\n\n  it('should return a signature with a single arg when there is a @param tag with a name, a type and a desc', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc(\n      '@param {SyntheticEvent} event - React event'\n    ).extractedTags;\n    const result = generateFuncSignature(params, returns);\n\n    expect(result).toBe('(event: SyntheticEvent)');\n  });\n\n  it('should support @param of record type', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc('@param {{a: number}} event').extractedTags;\n    const result = generateFuncSignature(params, returns);\n\n    expect(result).toBe('(event: ({a: number}))');\n  });\n\n  it('should support @param of union type', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc('@param {(number|boolean)} event').extractedTags;\n    const result = generateFuncSignature(params, returns);\n\n    expect(result).toBe('(event: (number|boolean))');\n  });\n\n  it('should support @param of array type', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc('@param {number[]} event').extractedTags;\n    const result = generateFuncSignature(params, returns);\n\n    expect(result).toBe('(event: number[])');\n  });\n\n  it('should support @param with a nullable type', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc('@param {?number} event').extractedTags;\n    const result = generateFuncSignature(params, returns);\n\n    expect(result).toBe('(event: number)');\n  });\n\n  it('should support @param with a non nullable type', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc('@param {!number} event').extractedTags;\n    const result = generateFuncSignature(params, returns);\n\n    expect(result).toBe('(event: number)');\n  });\n\n  it('should support optional @param with []', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc('@param {number} [event]').extractedTags;\n    const result = generateFuncSignature(params, returns);\n\n    expect(result).toBe('(event: number)');\n  });\n\n  it('should support optional @param with =', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc('@param {number=} event').extractedTags;\n    const result = generateFuncSignature(params, returns);\n\n    expect(result).toBe('(event: number)');\n  });\n\n  it('should support @param of type any', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc('@param {*} event').extractedTags;\n    const result = generateFuncSignature(params, returns);\n\n    expect(result).toBe('(event: any)');\n  });\n\n  it('should support multiple @param tags', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc(\n      '@param {SyntheticEvent} event\\n@param {string} customData'\n    ).extractedTags;\n    const result = generateFuncSignature(params, returns);\n\n    expect(result).toBe('(event: SyntheticEvent, customData: string)');\n  });\n\n  it('should return a signature with a return type when there is a @returns with a type', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc('@returns {string}').extractedTags;\n    const result = generateFuncSignature(params, returns);\n\n    expect(result).toBe('() => string');\n  });\n\n  it('should support @returns of record type', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc('@returns {{a: number, b: string}}').extractedTags;\n    const result = generateFuncSignature(params, returns);\n\n    expect(result).toBe('() => ({a: number, b: string})');\n  });\n\n  it('should support @returns of array type', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc('@returns {integer[]}').extractedTags;\n    const result = generateFuncSignature(params, returns);\n\n    expect(result).toBe('() => integer[]');\n  });\n\n  it('should support @returns of union type', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc('@returns {(number|boolean)}').extractedTags;\n    const result = generateFuncSignature(params, returns);\n\n    expect(result).toBe('() => (number|boolean)');\n  });\n\n  it('should support @returns type any', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc('@returns {*}').extractedTags;\n    const result = generateFuncSignature(params, returns);\n\n    expect(result).toBe('() => any');\n  });\n\n  it('should support @returns of type void', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc('@returns {void}').extractedTags;\n    const result = generateFuncSignature(params, returns);\n\n    expect(result).toBe('() => void');\n  });\n\n  it('should return a full signature when there is a single @param tag and a @returns', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc(\n      '@param {SyntheticEvent} event - React event.\\n@returns {string}'\n    ).extractedTags;\n    const result = generateFuncSignature(params, returns);\n\n    expect(result).toBe('(event: SyntheticEvent) => string');\n  });\n\n  it('should return a full signature when there is a multiple @param tags and a @returns', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc(\n      '@param {SyntheticEvent} event - React event.\\n@param {string} data\\n@returns {string}'\n    ).extractedTags;\n    const result = generateFuncSignature(params, returns);\n\n    expect(result).toBe('(event: SyntheticEvent, data: string) => string');\n  });\n});\n\ndescribe('generateShortFuncSignature', () => {\n  it('should return an empty string when there is no @params and @returns tags', () => {\n    // @ts-expect-error (invalid input)\n    const result = generateShortFuncSignature(null, null);\n\n    expect(result).toBe('');\n  });\n\n  it('should return ( ... ) when there is @params', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc('@param event').extractedTags;\n    const result = generateShortFuncSignature(params, returns);\n\n    expect(result).toBe('( ... )');\n  });\n\n  it('should return ( ... ) => returnsType when there is @params and a @returns', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc('@param event\\n@returns {string}').extractedTags;\n    const result = generateShortFuncSignature(params, returns);\n\n    expect(result).toBe('( ... ) => string');\n  });\n\n  it('should return () => returnsType when there is only a @returns', () => {\n    // @ts-expect-error (unsafe)\n    const { params, returns } = parseJsDoc('@returns {string}').extractedTags;\n    const result = generateShortFuncSignature(params, returns);\n\n    expect(result).toBe('() => string');\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/docs/propTypes/generateFuncSignature.ts",
    "content": "import type { ExtractedJsDocParam, ExtractedJsDocReturns } from 'storybook/internal/docs-tools';\n\nexport function generateFuncSignature(\n  params: ExtractedJsDocParam[],\n  returns: ExtractedJsDocReturns\n): string {\n  const hasParams = params != null;\n  const hasReturns = returns != null;\n\n  if (!hasParams && !hasReturns) {\n    return '';\n  }\n\n  const funcParts = [];\n\n  if (hasParams) {\n    const funcParams = params.map((x: ExtractedJsDocParam) => {\n      const prettyName = x.getPrettyName();\n      const typeName = x.getTypeName();\n\n      if (typeName != null) {\n        return `${prettyName}: ${typeName}`;\n      }\n\n      return prettyName;\n    });\n\n    funcParts.push(`(${funcParams.join(', ')})`);\n  } else {\n    funcParts.push('()');\n  }\n\n  if (hasReturns) {\n    funcParts.push(`=> ${returns.getTypeName()}`);\n  }\n\n  return funcParts.join(' ');\n}\n\nexport function generateShortFuncSignature(\n  params: ExtractedJsDocParam[],\n  returns: ExtractedJsDocReturns\n): string {\n  const hasParams = params != null;\n  const hasReturns = returns != null;\n\n  if (!hasParams && !hasReturns) {\n    return '';\n  }\n\n  const funcParts = [];\n\n  if (hasParams) {\n    funcParts.push('( ... )');\n  } else {\n    funcParts.push('()');\n  }\n\n  if (hasReturns) {\n    funcParts.push(`=> ${returns.getTypeName()}`);\n  }\n\n  return funcParts.join(' ');\n}\n\nexport function toMultilineSignature(signature: string): string {\n  return signature.replace(/,/g, ',\\r\\n');\n}\n"
  },
  {
    "path": "code/renderers/react/src/docs/propTypes/handleProp.test.tsx",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport React from 'react';\n\nimport {\n  type DocgenInfo,\n  type DocgenPropDefaultValue,\n  type PropDef,\n  extractComponentProps,\n} from 'storybook/internal/docs-tools';\n\nimport PropTypes from 'prop-types';\n\nimport { enhancePropTypesProp, enhancePropTypesProps } from './handleProp';\n\ntype Component = any;\nconst DOCGEN_SECTION = 'props';\n\nfunction ReactComponent() {\n  return <div>React Component!</div>;\n}\n\nfunction createDocgenSection(docgenInfo: DocgenInfo): Record<string, any> {\n  return {\n    [DOCGEN_SECTION]: {\n      ...docgenInfo,\n    },\n  };\n}\n\nfunction createDocgenProp({\n  name,\n  type,\n  ...others\n}: Partial<DocgenInfo> & { name: string }): Record<string, any> {\n  return {\n    [name]: {\n      type,\n      required: false,\n      ...others,\n    },\n  };\n}\n\nfunction createComponent({ propTypes = {}, defaultProps = {}, docgenInfo = {} }): Component {\n  const component = () => {\n    return <div>Hey!</div>;\n  };\n  component.propTypes = propTypes;\n  component.defaultProps = defaultProps;\n\n  // @ts-expect-error (Converted from ts-ignore)\n  component.__docgenInfo = createDocgenSection(docgenInfo);\n\n  return component;\n}\n\nfunction createDefaultValue(defaultValue: string): DocgenPropDefaultValue {\n  return { value: defaultValue };\n}\n\nfunction extractPropDef(component: Component, rawDefaultProp?: any): PropDef {\n  return enhancePropTypesProp(extractComponentProps(component, DOCGEN_SECTION)[0], rawDefaultProp);\n}\n\ndescribe('enhancePropTypesProp', () => {\n  describe('type', () => {\n    function createTestComponent(docgenInfo: Partial<DocgenInfo>): Component {\n      return createComponent({\n        docgenInfo: {\n          ...createDocgenProp({ name: 'prop', ...docgenInfo }),\n        },\n      });\n    }\n\n    describe('custom', () => {\n      describe('when raw value is available', () => {\n        it('should support literal', () => {\n          const component = createTestComponent({\n            type: {\n              name: 'custom',\n              raw: 'MY_LITERAL',\n            },\n          });\n\n          const { type } = extractPropDef(component);\n\n          expect(type?.summary).toBe('MY_LITERAL');\n          expect(type?.detail).toBeUndefined();\n        });\n\n        it('should support short object', () => {\n          const component = createTestComponent({\n            type: {\n              name: 'custom',\n              raw: '{\\n  text: PropTypes.string.isRequired,\\n}',\n            },\n          });\n\n          const { type } = extractPropDef(component);\n\n          const expectedSummary = '{ text: string }';\n\n          expect(type?.summary?.replace(/\\s/g, '')).toBe(expectedSummary.replace(/\\s/g, ''));\n          expect(type?.detail).toBeUndefined();\n        });\n\n        it('should support long object', () => {\n          const component = createTestComponent({\n            type: {\n              name: 'custom',\n              raw: '{\\n  text: PropTypes.string.isRequired,\\n  value1: PropTypes.string.isRequired,\\n  value2: PropTypes.string.isRequired,\\n  value3: PropTypes.string.isRequired,\\n  value4: PropTypes.string.isRequired,\\n}',\n            },\n          });\n\n          const { type } = extractPropDef(component);\n\n          expect(type?.summary).toBe('object');\n\n          const expectedDetail = `{\n            text: string,\n            value1: string,\n            value2: string,\n            value3: string,\n            value4: string\n          }`;\n\n          expect(type?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n        });\n\n        it('should not have a deep object as summary', () => {\n          const component = createTestComponent({\n            type: {\n              name: 'custom',\n              raw: '{\\n  foo: { bar: PropTypes.string.isRequired,\\n  }}',\n            },\n          });\n\n          const { type } = extractPropDef(component);\n\n          expect(type?.summary).toBe('object');\n        });\n\n        it('should use identifier of a React element when available', () => {\n          const component = createTestComponent({\n            type: {\n              name: 'custom',\n              raw: 'function InlinedFunctionalComponent() {\\n  return <div>Inlined FunctionalComponent!</div>;\\n}',\n            },\n          });\n\n          const { type } = extractPropDef(component);\n\n          expect(type?.summary).toBe('InlinedFunctionalComponent');\n\n          const expectedDetail = `function InlinedFunctionalComponent() {\n            return <div>Inlined FunctionalComponent!</div>;\n          }`;\n\n          expect(type?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n        });\n\n        it('should not use identifier of a HTML element', () => {\n          const component = createTestComponent({\n            type: {\n              name: 'custom',\n              raw: '<div>Hello world from Montreal, Quebec, Canada!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!</div>',\n            },\n          });\n\n          const { type } = extractPropDef(component);\n\n          expect(type?.summary).toBe('element');\n\n          const expectedDetail =\n            '<div>Hello world from Montreal, Quebec, Canada!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!</div>';\n\n          expect(type?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n        });\n\n        it('should support element without identifier', () => {\n          const component = createTestComponent({\n            type: {\n              name: 'custom',\n              raw: '() => {\\n  return <div>Inlined FunctionalComponent!</div>;\\n}',\n            },\n          });\n\n          const { type } = extractPropDef(component);\n\n          expect(type?.summary).toBe('element');\n\n          const expectedDetail = `() => {\n              return <div>Inlined FunctionalComponent!</div>;\n            }`;\n\n          expect(type?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n        });\n\n        describe('when it is not a known type', () => {\n          it('should return \"custom\" when its a long type', () => {\n            const component = createTestComponent({\n              type: {\n                name: 'custom',\n                raw: 'Symbol(\"A very very very very very very lonnnngggggggggggggggggggggggggggggggggggg symbol\")',\n              },\n            });\n\n            const { type } = extractPropDef(component);\n\n            expect(type?.summary).toBe('custom');\n            expect(type?.detail).toBe(\n              'Symbol(\"A very very very very very very lonnnngggggggggggggggggggggggggggggggggggg symbol\")'\n            );\n          });\n\n          it('should return \"custom\" when its a short type', () => {\n            const component = createTestComponent({\n              type: {\n                name: 'custom',\n                raw: 'Symbol(\"Hey!\")',\n              },\n            });\n\n            const { type } = extractPropDef(component);\n\n            expect(type?.summary).toBe('Symbol(\"Hey!\")');\n            expect(type?.detail).toBeUndefined();\n          });\n        });\n      });\n\n      it(\"should return 'custom' when there is no raw value\", () => {\n        const component = createTestComponent({\n          type: {\n            name: 'custom',\n          },\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe('custom');\n      });\n    });\n\n    [\n      'any',\n      'bool',\n      'string',\n      'number',\n      'symbol',\n      'object',\n      'element',\n      'elementType',\n      'node',\n    ].forEach((x) => {\n      it(`should return '${x}' when type is ${x}`, () => {\n        const component = createTestComponent({\n          type: {\n            name: x,\n          },\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe(x);\n      });\n    });\n\n    it('should support short shape', () => {\n      const component = createTestComponent({\n        type: {\n          name: 'shape',\n          value: {\n            foo: {\n              name: 'string',\n              required: false,\n            },\n          },\n        },\n      });\n\n      const { type } = extractPropDef(component);\n\n      const expectedSummary = '{ foo: string }';\n\n      expect(type?.summary?.replace(/\\s/g, '')).toBe(expectedSummary.replace(/\\s/g, ''));\n      expect(type?.detail).toBeUndefined();\n    });\n\n    it('should support long shape', () => {\n      const component = createTestComponent({\n        type: {\n          name: 'shape',\n          value: {\n            foo: {\n              name: 'string',\n              required: false,\n            },\n            bar: {\n              name: 'string',\n              required: false,\n            },\n            another: {\n              name: 'string',\n              required: false,\n            },\n            another2: {\n              name: 'string',\n              required: false,\n            },\n            another3: {\n              name: 'string',\n              required: false,\n            },\n            another4: {\n              name: 'string',\n              required: false,\n            },\n          },\n        },\n      });\n\n      const { type } = extractPropDef(component);\n\n      expect(type?.summary).toBe('object');\n\n      const expectedDetail = `{\n        foo: string,\n        bar: string,\n        another: string,\n        another2: string,\n        another3: string,\n        another4: string\n      }`;\n\n      expect(type?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n    });\n\n    it('should not have a deep shape as summary', () => {\n      const component = createTestComponent({\n        type: {\n          name: 'shape',\n          value: {\n            bar: {\n              name: 'shape',\n              value: {\n                hey: {\n                  name: 'string',\n                  required: false,\n                },\n              },\n              required: false,\n            },\n          },\n        },\n      });\n\n      const { type } = extractPropDef(component);\n\n      expect(type?.summary).toBe('object');\n    });\n\n    it('should support enum of string', () => {\n      const component = createTestComponent({\n        type: {\n          name: 'enum',\n          value: [\n            {\n              value: \"'News'\",\n              computed: false,\n            },\n            {\n              value: \"'Photos'\",\n              computed: false,\n            },\n          ],\n        },\n      });\n\n      const { type } = extractPropDef(component);\n\n      expect(type?.summary).toBe(\"'News' | 'Photos'\");\n    });\n\n    it('should support enum of object', () => {\n      const component = createTestComponent({\n        type: {\n          name: 'enum',\n          value: [\n            {\n              value:\n                '{\\n  text: PropTypes.string.isRequired,\\n  value: PropTypes.string.isRequired,\\n}',\n              computed: true,\n            },\n            {\n              value:\n                '{\\n  foo: PropTypes.string,\\n  bar: PropTypes.string,\\n  hey: PropTypes.string,\\n  ho: PropTypes.string,\\n}',\n              computed: true,\n            },\n          ],\n        },\n      });\n\n      const { type } = extractPropDef(component);\n\n      expect(type?.summary).toBe('object | object');\n\n      const expectedDetail = `{\n          text: string,\n          value: string\n        } | {\n          foo: string,\n          bar: string,\n          hey: string,\n          ho: string\n        }`;\n\n      expect(type?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n    });\n\n    it('should support short object in enum summary', () => {\n      const component = createTestComponent({\n        type: {\n          name: 'enum',\n          value: [\n            {\n              value: '{\\n  text: PropTypes.string.isRequired,\\n}',\n              computed: true,\n            },\n            {\n              value: '{\\n  foo: PropTypes.string,\\n}',\n              computed: true,\n            },\n          ],\n        },\n      });\n\n      const { type } = extractPropDef(component);\n\n      expect(type?.summary).toBe('{ text: string } | { foo: string }');\n    });\n\n    it('should not have a deep object in an enum summary', () => {\n      const component = createTestComponent({\n        type: {\n          name: 'enum',\n          value: [\n            {\n              value: '{\\n  text: { foo: PropTypes.string.isRequired,\\n }\\n}',\n              computed: true,\n            },\n            {\n              value: '{\\n  foo: PropTypes.string,\\n}',\n              computed: true,\n            },\n          ],\n        },\n      });\n\n      const { type } = extractPropDef(component);\n\n      expect(type?.summary).toBe('object | object');\n    });\n\n    it('should support enum of element', () => {\n      const component = createTestComponent({\n        type: {\n          name: 'enum',\n          value: [\n            {\n              value: '() => {\\n  return <div>FunctionalComponent!</div>;\\n}',\n              computed: true,\n            },\n            {\n              value:\n                'class ClassComponent extends React.PureComponent {\\n  render() {\\n    return <div>ClassComponent!</div>;\\n  }\\n}',\n              computed: true,\n            },\n          ],\n        },\n      });\n\n      const { type } = extractPropDef(component);\n\n      expect(type?.summary).toBe('element | ClassComponent');\n\n      const expectedDetail = `() => {\n          return <div>FunctionalComponent!</div>;\n        } | class ClassComponent extends React.PureComponent {\n          render() {\n            return <div>ClassComponent!</div>;\n          }\n        }`;\n\n      expect(type?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n    });\n\n    describe('func', () => {\n      it('should return \"func\" when the prop dont have a description', () => {\n        const component = createTestComponent({\n          type: {\n            name: 'func',\n          },\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe('func');\n      });\n\n      it('should return \"func\" when the prop have a description without JSDoc tags', () => {\n        const component = createTestComponent({\n          type: {\n            name: 'func',\n          },\n          description: 'Hey! Hey!',\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe('func');\n      });\n\n      it('should return a func signature when there is JSDoc tags.', () => {\n        const component = createTestComponent({\n          type: {\n            name: 'func',\n          },\n          description: '@param event\\n@param data\\n@returns {string}',\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe('(event, data) => string');\n      });\n    });\n\n    it('should return the instance type when type is instanceOf', () => {\n      const component = createTestComponent({\n        type: {\n          name: 'instanceOf',\n          value: 'Set',\n        },\n      });\n\n      const { type } = extractPropDef(component);\n\n      expect(type?.summary).toBe('Set');\n    });\n\n    describe('objectOf', () => {\n      it('should support objectOf primitive', () => {\n        const component = createTestComponent({\n          type: {\n            name: 'objectOf',\n            value: {\n              name: 'number',\n            },\n          },\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe('objectOf(number)');\n        expect(type?.detail).toBeUndefined();\n      });\n\n      it('should support objectOf of identifier', () => {\n        const component = createTestComponent({\n          type: {\n            name: 'objectOf',\n            value: {\n              name: 'custom',\n              raw: 'NAMED_OBJECT',\n            },\n          },\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe('objectOf(NAMED_OBJECT)');\n        expect(type?.detail).toBeUndefined();\n      });\n\n      it('should support objectOf short object', () => {\n        const component = createTestComponent({\n          type: {\n            name: 'objectOf',\n            value: {\n              name: 'custom',\n              raw: '{\\n  foo: PropTypes.string,\\n}',\n            },\n          },\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe('objectOf({ foo: string })');\n        expect(type?.detail).toBeUndefined();\n      });\n\n      it('should support objectOf long object', () => {\n        const component = createTestComponent({\n          type: {\n            name: 'objectOf',\n            value: {\n              name: 'custom',\n              raw: '{\\n  foo: PropTypes.string,\\n  bar: PropTypes.string,\\n  another: PropTypes.string,\\n  anotherAnother: PropTypes.string,\\n}',\n            },\n          },\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe('objectOf(object)');\n\n        const expectedDetail = `objectOf({\n          foo: string,\n          bar: string,\n          another: string,\n          anotherAnother: string\n        })`;\n\n        expect(type?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n      });\n\n      it('should not have deep object in summary', () => {\n        const component = createTestComponent({\n          type: {\n            name: 'objectOf',\n            value: {\n              name: 'custom',\n              raw: '{\\n  foo: { bar: PropTypes.string,\\n }\\n}',\n            },\n          },\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe('objectOf(object)');\n      });\n\n      it('should support objectOf short shape', () => {\n        const component = createTestComponent({\n          type: {\n            name: 'objectOf',\n            value: {\n              name: 'shape',\n              value: {\n                foo: {\n                  name: 'string',\n                  required: false,\n                },\n              },\n            },\n          },\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe('objectOf({ foo: string })');\n        expect(type?.detail).toBeUndefined();\n      });\n\n      it('should support objectOf long shape', () => {\n        const component = createTestComponent({\n          type: {\n            name: 'objectOf',\n            value: {\n              name: 'shape',\n              value: {\n                foo: {\n                  name: 'string',\n                  required: false,\n                },\n                bar: {\n                  name: 'string',\n                  required: false,\n                },\n                another: {\n                  name: 'string',\n                  required: false,\n                },\n                anotherAnother: {\n                  name: 'string',\n                  required: false,\n                },\n              },\n            },\n          },\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe('objectOf(object)');\n\n        const expectedDetail = `objectOf({\n          foo: string,\n          bar: string,\n          another: string,\n          anotherAnother: string\n        })`;\n\n        expect(type?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n      });\n\n      it('should not have a deep shape in summary', () => {\n        const component = createTestComponent({\n          type: {\n            name: 'objectOf',\n            value: {\n              name: 'shape',\n              value: {\n                bar: {\n                  name: 'shape',\n                  value: {\n                    hey: {\n                      name: 'string',\n                      required: false,\n                    },\n                  },\n                  required: false,\n                },\n              },\n            },\n          },\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe('objectOf(object)');\n      });\n    });\n\n    it('should support union', () => {\n      const component = createTestComponent({\n        type: {\n          name: 'union',\n          value: [\n            {\n              name: 'string',\n            },\n            {\n              name: 'instanceOf',\n              value: 'Set',\n            },\n          ],\n        },\n      });\n\n      const { type } = extractPropDef(component);\n\n      expect(type?.summary).toBe('string | Set');\n      expect(type?.detail).toBeUndefined();\n    });\n\n    describe('array', () => {\n      it('should support array of primitive', () => {\n        const component = createTestComponent({\n          type: {\n            name: 'arrayOf',\n            value: {\n              name: 'number',\n            },\n          },\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe('number[]');\n        expect(type?.detail).toBeUndefined();\n      });\n\n      it('should support array of identifier', () => {\n        const component = createTestComponent({\n          type: {\n            name: 'arrayOf',\n            value: {\n              name: 'custom',\n              raw: 'NAMED_OBJECT',\n            },\n          },\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe('NAMED_OBJECT[]');\n        expect(type?.detail).toBeUndefined();\n      });\n\n      it('should support array of short object', () => {\n        const component = createTestComponent({\n          type: {\n            name: 'arrayOf',\n            value: {\n              name: 'custom',\n              raw: '{\\n  foo: PropTypes.string,\\n}',\n            },\n          },\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe('[{ foo: string }]');\n        expect(type?.detail).toBeUndefined();\n      });\n\n      it('should support array of long object', () => {\n        const component = createTestComponent({\n          type: {\n            name: 'arrayOf',\n            value: {\n              name: 'custom',\n              raw: '{\\n  text: PropTypes.string.isRequired,\\n  value: PropTypes.string.isRequired,\\n  another: PropTypes.string.isRequired,\\n  another2: PropTypes.string.isRequired,\\n  another3: PropTypes.string.isRequired,\\n  another4: PropTypes.string.isRequired,\\n}',\n            },\n          },\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe('object[]');\n\n        const expectedDetail = `[{\n          text: string,\n          value: string,\n          another: string,\n          another2: string,\n          another3: string,\n          another4: string\n        }]`;\n\n        expect(type?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n      });\n\n      it('should not have deep object in summary', () => {\n        const component = createTestComponent({\n          type: {\n            name: 'arrayOf',\n            value: {\n              name: 'custom',\n              raw: '{\\n  foo: { bar: PropTypes.string, }\\n}',\n            },\n          },\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe('object[]');\n      });\n\n      it('should support array of short shape', () => {\n        const component = createTestComponent({\n          type: {\n            name: 'arrayOf',\n            value: {\n              name: 'shape',\n              value: {\n                foo: {\n                  name: 'string',\n                  required: false,\n                },\n              },\n            },\n          },\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe('[{ foo: string }]');\n        expect(type?.detail).toBeUndefined();\n      });\n\n      it('should support array of long shape', () => {\n        const component = createTestComponent({\n          type: {\n            name: 'arrayOf',\n            value: {\n              name: 'shape',\n              value: {\n                foo: {\n                  name: 'string',\n                  required: false,\n                },\n                bar: {\n                  name: 'string',\n                  required: false,\n                },\n                another: {\n                  name: 'string',\n                  required: false,\n                },\n                another2: {\n                  name: 'string',\n                  required: false,\n                },\n                another3: {\n                  name: 'string',\n                  required: false,\n                },\n                another4: {\n                  name: 'string',\n                  required: false,\n                },\n              },\n            },\n          },\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe('object[]');\n\n        const expectedDetail = `[{\n          foo: string,\n          bar: string,\n          another: string,\n          another2: string,\n          another3: string,\n          another4: string\n        }]`;\n\n        expect(type?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n      });\n\n      it('should not have deep shape in summary', () => {\n        const component = createTestComponent({\n          type: {\n            name: 'arrayOf',\n            value: {\n              name: 'shape',\n              value: {\n                bar: {\n                  name: 'shape',\n                  value: {\n                    hey: {\n                      name: 'string',\n                      required: false,\n                    },\n                  },\n                  required: false,\n                },\n              },\n            },\n          },\n        });\n\n        const { type } = extractPropDef(component);\n\n        expect(type?.summary).toBe('object[]');\n      });\n    });\n  });\n\n  describe('defaultValue', () => {\n    function createTestComponent(\n      defaultValue: DocgenPropDefaultValue,\n      typeName = 'anything-is-fine'\n    ): Component {\n      return createComponent({\n        docgenInfo: {\n          ...createDocgenProp({\n            name: 'prop',\n            type: { name: typeName },\n            defaultValue,\n          }),\n        },\n      });\n    }\n\n    it('should support short object', () => {\n      const component = createTestComponent(createDefaultValue(\"{ foo: 'foo', bar: 'bar' }\"));\n\n      const { defaultValue } = extractPropDef(component);\n\n      const expectedSummary = \"{ foo: 'foo', bar: 'bar' }\";\n\n      expect(defaultValue?.summary?.replace(/\\s/g, '')).toBe(expectedSummary.replace(/\\s/g, ''));\n      expect(defaultValue?.detail).toBeUndefined();\n    });\n\n    it('should support long object', () => {\n      const component = createTestComponent(\n        createDefaultValue(\"{ foo: 'foo', bar: 'bar', another: 'another' }\")\n      );\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('object');\n\n      const expectedDetail = `{\n        foo: 'foo',\n        bar: 'bar',\n        another: 'another'\n      }`;\n\n      expect(defaultValue?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n    });\n\n    it('should not have deep object in summary', () => {\n      const component = createTestComponent(\n        createDefaultValue(\"{ foo: 'foo', bar: { hey: 'ho' } }\")\n      );\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('object');\n    });\n\n    it('should support short function', () => {\n      const component = createTestComponent(createDefaultValue('() => {}'));\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('() => {}');\n      expect(defaultValue?.detail).toBeUndefined();\n    });\n\n    it('should support long function', () => {\n      const component = createTestComponent(\n        createDefaultValue(\n          '(foo, bar) => {\\n  const concat = foo + bar;\\n  const append = concat + \" hey!\";\\n  \\n  return append;\\n}'\n        )\n      );\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('func');\n\n      const expectedDetail = `(foo, bar) => {\n        const concat = foo + bar;\n        const append = concat + ' hey!';\n        return append\n      }`;\n\n      expect(defaultValue?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n    });\n\n    it('should use the name of function when available and indicate that args are present', () => {\n      const component = createTestComponent(\n        createDefaultValue('function concat(a, b) {\\n  return a + b;\\n}')\n      );\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('concat( ... )');\n\n      const expectedDetail = `function concat(a, b) {\n        return a + b\n      }`;\n\n      expect(defaultValue?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n    });\n\n    it('should use the name of function when available', () => {\n      const component = createTestComponent(\n        createDefaultValue('function hello() {\\n  return \"hello\";\\n}')\n      );\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('hello()');\n\n      const expectedDetail = `function hello() {\n        return 'hello'\n      }`;\n\n      expect(defaultValue?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n    });\n\n    it('should support short element', () => {\n      const component = createTestComponent(createDefaultValue('<div>Hey!</div>'));\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('<div>Hey!</div>');\n      expect(defaultValue?.detail).toBeUndefined();\n    });\n\n    it('should support long element', () => {\n      const component = createTestComponent(\n        createDefaultValue(\n          '<div>Hey! Hey! Hey!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!</div>'\n        )\n      );\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('element');\n      expect(defaultValue?.detail).toBe(\n        '<div>Hey! Hey! Hey!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!</div>'\n      );\n    });\n\n    it('should support element with props', () => {\n      const component = createTestComponent(createDefaultValue('<Component className=\"toto\" />'));\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('<Component />');\n      expect(defaultValue?.detail).toBe('<Component className=\"toto\" />');\n    });\n\n    it(\"should use the name of the React component when it's available\", () => {\n      const component = createTestComponent(\n        createDefaultValue(\n          'function InlinedFunctionalComponent() {\\n  return <div>Inlined FunctionalComponent!</div>;\\n}'\n        )\n      );\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('<InlinedFunctionalComponent />');\n\n      const expectedDetail = `function InlinedFunctionalComponent() {\n        return <div>Inlined FunctionalComponent!</div>;\n      }`;\n\n      expect(defaultValue?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n    });\n\n    it('should not use the name of an HTML element', () => {\n      const component = createTestComponent(createDefaultValue('<div>Hey!</div>'));\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).not.toBe('<div />');\n    });\n\n    it('should support short array', () => {\n      const component = createTestComponent(createDefaultValue('[1]'));\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('[1]');\n      expect(defaultValue?.detail).toBeUndefined();\n    });\n\n    it('should support long array', () => {\n      const component = createTestComponent(\n        createDefaultValue(\n          '[\\n  {\\n    thing: {\\n      id: 2,\\n      func: () => {},\\n      arr: [],\\n    },\\n  },\\n]'\n        )\n      );\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('array');\n\n      const expectedDetail = `[{\n          thing: {\n            id: 2,\n            func: () => {\n            },\n            arr: []\n          }\n        }]`;\n\n      expect(defaultValue?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n    });\n\n    it('should not have deep array in summary', () => {\n      const component = createTestComponent(createDefaultValue('[[[1]]]'));\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('array');\n    });\n\n    describe('fromRawDefaultProp', () => {\n      [\n        { type: 'number', defaultProp: 1 },\n        { type: 'boolean', defaultProp: true },\n        { type: 'symbol', defaultProp: Symbol('hey!') },\n      ].forEach((x) => {\n        it(`should support ${x.type}`, () => {\n          // @ts-expect-error (invalid input)\n          const component = createTestComponent(null);\n\n          const { defaultValue } = extractPropDef(component, x.defaultProp);\n\n          expect(defaultValue?.summary).toBe(x.defaultProp.toString());\n          expect(defaultValue?.detail).toBeUndefined();\n        });\n      });\n\n      it('should support strings', () => {\n        // @ts-expect-error (invalid input)\n        const component = createTestComponent(null);\n\n        const { defaultValue } = extractPropDef(component, 'foo');\n\n        expect(defaultValue?.summary).toBe('\"foo\"');\n        expect(defaultValue?.detail).toBeUndefined();\n      });\n\n      it('should support array of primitives', () => {\n        // @ts-expect-error (invalid input)\n        const component = createTestComponent(null);\n\n        const { defaultValue } = extractPropDef(component, [1, 2, 3]);\n\n        expect(defaultValue?.summary).toBe('[1,    2,    3]');\n        expect(defaultValue?.detail).toBeUndefined();\n      });\n\n      it('should support array of short object', () => {\n        // @ts-expect-error (invalid input)\n        const component = createTestComponent(null);\n\n        const { defaultValue } = extractPropDef(component, [{ foo: 'bar' }]);\n\n        expect(defaultValue?.summary).toBe(\"[{ 'foo': 'bar' }]\");\n        expect(defaultValue?.detail).toBeUndefined();\n      });\n\n      it('should support array of long object', () => {\n        // @ts-expect-error (invalid input)\n        const component = createTestComponent(null);\n\n        const { defaultValue } = extractPropDef(component, [{ foo: 'bar', bar: 'foo', hey: 'ho' }]);\n\n        expect(defaultValue?.summary).toBe('array');\n\n        const expectedDetail = `[{\n          'foo': 'bar',\n          'bar': 'foo',\n          'hey': 'ho'\n        }]`;\n\n        expect(defaultValue?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n      });\n\n      it('should support short object', () => {\n        // @ts-expect-error (invalid input)\n        const component = createTestComponent(null);\n\n        const { defaultValue } = extractPropDef(component, { foo: 'bar' });\n\n        expect(defaultValue?.summary).toBe(\"{ 'foo': 'bar' }\");\n        expect(defaultValue?.detail).toBeUndefined();\n      });\n\n      it('should support long object', () => {\n        // @ts-expect-error (invalid input)\n        const component = createTestComponent(null);\n\n        const { defaultValue } = extractPropDef(component, { foo: 'bar', bar: 'foo', hey: 'ho' });\n\n        expect(defaultValue?.summary).toBe('object');\n\n        const expectedDetail = `{\n          'foo': 'bar',\n          'bar': 'foo',\n          'hey': 'ho'\n        }`;\n\n        expect(defaultValue?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n      });\n\n      it('should support anonymous function', () => {\n        // @ts-expect-error (invalid input)\n        const component = createTestComponent(null);\n\n        const { defaultValue } = extractPropDef(component, () => 'hey!');\n\n        expect(defaultValue?.summary).toBe('func');\n        expect(defaultValue?.detail).toBeUndefined();\n      });\n\n      it('should support named function', () => {\n        // @ts-expect-error (invalid input)\n        const component = createTestComponent(null);\n\n        const { defaultValue } = extractPropDef(component, function hello() {\n          return 'world!';\n        });\n\n        expect(defaultValue?.summary).toBe('hello()');\n        expect(defaultValue?.detail).toBeUndefined();\n      });\n\n      it('should support named function with params', () => {\n        // @ts-expect-error (invalid input)\n        const component = createTestComponent(null);\n\n        const { defaultValue } = extractPropDef(component, function add(a: number, b: number) {\n          return a + b;\n        });\n\n        expect(defaultValue?.summary).toBe('add( ... )');\n        expect(defaultValue?.detail).toBeUndefined();\n      });\n\n      it('should support React element', () => {\n        // @ts-expect-error (invalid input)\n        const component = createTestComponent(null);\n\n        const defaultProp = <ReactComponent />;\n        // Simulate babel-plugin-add-react-displayname.\n        defaultProp.type.displayName = 'ReactComponent';\n\n        const { defaultValue } = extractPropDef(component, defaultProp);\n\n        expect(defaultValue?.summary).toBe('<ReactComponent />');\n        expect(defaultValue?.detail).toBeUndefined();\n      });\n\n      it('should support React element with props', () => {\n        // @ts-expect-error (invalid input)\n        const component = createTestComponent(null);\n\n        // @ts-expect-error (Converted from ts-ignore)\n        const defaultProp = <ReactComponent className=\"toto\" />;\n        // Simulate babel-plugin-add-react-displayname.\n        defaultProp.type.displayName = 'ReactComponent';\n\n        const { defaultValue } = extractPropDef(component, defaultProp);\n\n        expect(defaultValue?.summary).toBe('<ReactComponent />');\n        expect(defaultValue?.detail).toBe('<ReactComponent className=\"toto\" />');\n      });\n\n      it('should support short HTML element', () => {\n        // @ts-expect-error (invalid input)\n        const component = createTestComponent(null);\n\n        const { defaultValue } = extractPropDef(component, <div>HTML element</div>);\n\n        expect(defaultValue?.summary).toBe('<div>HTML element</div>');\n        expect(defaultValue?.detail).toBeUndefined();\n      });\n\n      it('should support long HTML element', () => {\n        // @ts-expect-error (invalid input)\n        const component = createTestComponent(null);\n\n        const { defaultValue } = extractPropDef(\n          component,\n          <div>HTML element!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!</div>\n        );\n\n        expect(defaultValue?.summary).toBe('element');\n\n        const expectedDetail = `<div>\n          HTML element!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n        </div>`;\n\n        expect(defaultValue?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n      });\n\n      ['element', 'elementType'].forEach((x) => {\n        it(`should support inlined React class component for ${x}`, () => {\n          // @ts-expect-error (invalid input)\n          const component = createTestComponent(null, x);\n\n          const { defaultValue } = extractPropDef(\n            component,\n            class InlinedClassComponent extends React.PureComponent {\n              render() {\n                return <div>Inlined ClassComponent!</div>;\n              }\n            }\n          );\n\n          expect(defaultValue?.summary).toBe('<InlinedClassComponent />');\n          expect(defaultValue?.detail).toBeUndefined();\n        });\n\n        it(`should support inlined anonymous React functional component for ${x}`, () => {\n          // @ts-expect-error (invalid input)\n          const component = createTestComponent(null, x);\n\n          const { defaultValue } = extractPropDef(component, () => {\n            return <div>Inlined FunctionalComponent!</div>;\n          });\n\n          expect(defaultValue?.summary).toBe('element');\n          expect(defaultValue?.detail).toBeUndefined();\n        });\n\n        it(`should support inlined anonymous React functional component with props for ${x}`, () => {\n          // @ts-expect-error (invalid input)\n          const component = createTestComponent(null, x);\n\n          const { defaultValue } = extractPropDef(component, ({ foo }: { foo: string }) => {\n            return <div>{foo}</div>;\n          });\n\n          expect(defaultValue?.summary).toBe('element');\n          expect(defaultValue?.detail).toBeUndefined();\n        });\n\n        it(`should support inlined named React functional component for ${x}`, () => {\n          // @ts-expect-error (invalid input)\n          const component = createTestComponent(null, x);\n\n          const { defaultValue } = extractPropDef(component, function InlinedFunctionalComponent() {\n            return <div>Inlined FunctionalComponent!</div>;\n          });\n\n          expect(defaultValue?.summary).toBe('<InlinedFunctionalComponent />');\n          expect(defaultValue?.detail).toBeUndefined();\n        });\n\n        it(`should support inlined named React functional component with props for ${x}`, () => {\n          // @ts-expect-error (invalid input)\n          const component = createTestComponent(null, x);\n\n          const { defaultValue } = extractPropDef(\n            component,\n            function InlinedFunctionalComponent({ foo }: { foo: string }) {\n              return <div>{foo}</div>;\n            }\n          );\n\n          expect(defaultValue?.summary).toBe('<InlinedFunctionalComponent />');\n          expect(defaultValue?.detail).toBeUndefined();\n        });\n      });\n    });\n  });\n});\n\ndescribe('enhancePropTypesProps', () => {\n  it('should keep the original definition order', () => {\n    const component = createComponent({\n      propTypes: {\n        foo: PropTypes.string,\n        middleWithDefaultValue: PropTypes.string,\n        bar: PropTypes.string,\n        endWithDefaultValue: PropTypes.string,\n      },\n      docgenInfo: {\n        ...createDocgenProp({\n          name: 'middleWithDefaultValue',\n          type: { name: 'string' },\n          defaultValue: { value: 'Middle!' },\n        }),\n        ...createDocgenProp({\n          name: 'endWithDefaultValue',\n          type: { name: 'string' },\n          defaultValue: { value: 'End!' },\n        }),\n        ...createDocgenProp({\n          name: 'foo',\n          type: { name: 'string' },\n        }),\n        ...createDocgenProp({\n          name: 'bar',\n          type: { name: 'string' },\n        }),\n      },\n    });\n\n    const props = enhancePropTypesProps(\n      extractComponentProps(component, DOCGEN_SECTION),\n      component\n    );\n\n    expect(props.length).toBe(4);\n    expect(props[0].name).toBe('foo');\n    expect(props[1].name).toBe('middleWithDefaultValue');\n    expect(props[2].name).toBe('bar');\n    expect(props[3].name).toBe('endWithDefaultValue');\n  });\n\n  it('should not include @ignore props', () => {\n    const component = createComponent({\n      propTypes: {\n        foo: PropTypes.string,\n        bar: PropTypes.string,\n      },\n      docgenInfo: {\n        ...createDocgenProp({\n          name: 'foo',\n          type: { name: 'string' },\n        }),\n        ...createDocgenProp({\n          name: 'bar',\n          type: { name: 'string' },\n          description: '@ignore',\n        }),\n      },\n    });\n\n    const props = enhancePropTypesProps(\n      extractComponentProps(component, DOCGEN_SECTION),\n      component\n    );\n\n    expect(props.length).toBe(1);\n    expect(props[0].name).toBe('foo');\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/docs/propTypes/handleProp.ts",
    "content": "import type { ExtractedProp, PropDef } from 'storybook/internal/docs-tools';\n\nimport { createDefaultValue, createDefaultValueFromRawDefaultProp } from '../lib/defaultValues';\nimport { createType } from './createType';\nimport { rawDefaultPropTypeResolvers } from './rawDefaultPropResolvers';\nimport { keepOriginalDefinitionOrder } from './sortProps';\n\ntype Component = any;\n\nexport function enhancePropTypesProp(extractedProp: ExtractedProp, rawDefaultProp?: any): PropDef {\n  const { propDef } = extractedProp;\n\n  const newtype = createType(extractedProp);\n  if (newtype != null) {\n    propDef.type = newtype;\n  }\n\n  const { defaultValue } = extractedProp.docgenInfo;\n  if (defaultValue != null && defaultValue.value != null) {\n    const newDefaultValue = createDefaultValue(defaultValue.value);\n\n    if (newDefaultValue != null) {\n      propDef.defaultValue = newDefaultValue;\n    }\n  } else if (rawDefaultProp != null) {\n    const newDefaultValue = createDefaultValueFromRawDefaultProp(\n      rawDefaultProp,\n      propDef,\n      rawDefaultPropTypeResolvers\n    );\n\n    if (newDefaultValue != null) {\n      propDef.defaultValue = newDefaultValue;\n    }\n  }\n\n  return propDef;\n}\n\nexport function enhancePropTypesProps(\n  extractedProps: ExtractedProp[],\n  component: Component\n): PropDef[] {\n  const rawDefaultProps = component.defaultProps != null ? component.defaultProps : {};\n  const enhancedProps = extractedProps.map((x) =>\n    enhancePropTypesProp(x, rawDefaultProps[x.propDef.name])\n  );\n\n  return keepOriginalDefinitionOrder(enhancedProps, component);\n}\n"
  },
  {
    "path": "code/renderers/react/src/docs/propTypes/rawDefaultPropResolvers.ts",
    "content": "import { createSummaryValue } from 'storybook/internal/docs-tools';\n\nimport { ELEMENT_CAPTION, FUNCTION_CAPTION } from '../lib/captions';\nimport type { TypeResolver } from '../lib/defaultValues';\nimport { createTypeResolvers, extractFunctionName } from '../lib/defaultValues';\nimport {\n  getPrettyElementIdentifier,\n  getPrettyFuncIdentifier,\n} from '../lib/defaultValues/prettyIdentifier';\nimport type { InspectionFunction } from '../lib/inspection';\nimport { inspectValue } from '../lib/inspection';\n\nconst funcResolver: TypeResolver = (rawDefaultProp, { name, type }) => {\n  const isElement = type?.summary === 'element' || type?.summary === 'elementType';\n\n  const funcName = extractFunctionName(rawDefaultProp, name);\n  if (funcName != null) {\n    // Try to display the name of the component. The body of the component is omitted since the code has been transpiled.\n    if (isElement) {\n      return createSummaryValue(getPrettyElementIdentifier(funcName));\n    }\n\n    const { hasParams } = inspectValue(rawDefaultProp.toString())\n      .inferredType as InspectionFunction;\n\n    return createSummaryValue(getPrettyFuncIdentifier(funcName, hasParams));\n  }\n\n  return createSummaryValue(isElement ? ELEMENT_CAPTION : FUNCTION_CAPTION);\n};\n\nexport const rawDefaultPropTypeResolvers = createTypeResolvers({\n  function: funcResolver,\n});\n"
  },
  {
    "path": "code/renderers/react/src/docs/propTypes/sortProps.ts",
    "content": "import type { PropDef } from 'storybook/internal/docs-tools';\n\ntype Component = any;\n\n// react-docgen doesn't returned the props in the order they were defined in the \"propTypes\" object of the component.\n// This function re-order them by their original definition order.\nexport function keepOriginalDefinitionOrder(\n  extractedProps: PropDef[],\n  component: Component\n): PropDef[] {\n  const { propTypes } = component;\n\n  if (propTypes != null) {\n    return Object.keys(propTypes)\n      .map((x) => extractedProps.find((y) => y.name === x))\n      .filter(Boolean) as PropDef[];\n  }\n\n  return extractedProps;\n}\n"
  },
  {
    "path": "code/renderers/react/src/docs/typeScript/handleProp.test.tsx",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport React from 'react';\n\nimport {\n  type DocgenInfo,\n  type DocgenPropDefaultValue,\n  type PropDef,\n  extractComponentProps,\n} from 'storybook/internal/docs-tools';\n\nimport { enhanceTypeScriptProp } from './handleProp';\n\ntype Component = any;\n\nconst DOCGEN_SECTION = 'props';\n\nfunction ReactComponent() {\n  return <div>React Component!</div>;\n}\n\nfunction createDocgenSection(docgenInfo: DocgenInfo): Record<string, any> {\n  return {\n    [DOCGEN_SECTION]: {\n      ...docgenInfo,\n    },\n  };\n}\n\nfunction createDocgenProp({\n  name,\n  tsType,\n  ...others\n}: Partial<DocgenInfo> & { name: string }): Record<string, any> {\n  return {\n    [name]: {\n      tsType,\n      required: false,\n      ...others,\n    },\n  };\n}\n\nfunction createComponent({ propTypes = {}, defaultProps = {}, docgenInfo = {} }): Component {\n  const component = () => {\n    return <div>Hey!</div>;\n  };\n  component.propTypes = propTypes;\n  component.defaultProps = defaultProps;\n\n  // @ts-expect-error (Converted from ts-ignore)\n  component.__docgenInfo = createDocgenSection(docgenInfo);\n\n  return component;\n}\n\nfunction createDefaultValue(defaultValue: string): DocgenPropDefaultValue {\n  return { value: defaultValue };\n}\n\nfunction extractPropDef(component: Component, rawDefaultProp?: any): PropDef {\n  return enhanceTypeScriptProp(extractComponentProps(component, DOCGEN_SECTION)[0], rawDefaultProp);\n}\n\ndescribe('enhanceTypeScriptProp', () => {\n  describe('defaultValue', () => {\n    function createTestComponent(\n      defaultValue: DocgenPropDefaultValue | undefined,\n      typeName = 'anything-is-fine'\n    ): Component {\n      return createComponent({\n        docgenInfo: {\n          ...createDocgenProp({\n            name: 'prop',\n            tsType: { name: typeName },\n            defaultValue,\n          }),\n        },\n      });\n    }\n\n    it('should support short object', () => {\n      const component = createTestComponent(createDefaultValue(\"{ foo: 'foo', bar: 'bar' }\"));\n\n      const { defaultValue } = extractPropDef(component);\n\n      const expectedSummary = \"{ foo: 'foo', bar: 'bar' }\";\n\n      expect(defaultValue?.summary?.replace(/\\s/g, '')).toBe(expectedSummary.replace(/\\s/g, ''));\n      expect(defaultValue?.detail).toBeUndefined();\n    });\n\n    it('should support long object', () => {\n      const component = createTestComponent(\n        createDefaultValue(\"{ foo: 'foo', bar: 'bar', another: 'another' }\")\n      );\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('object');\n\n      const expectedDetail = `{\n        foo: 'foo',\n        bar: 'bar',\n        another: 'another'\n      }`;\n\n      expect(defaultValue?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n    });\n\n    it('should not have deep object in summary', () => {\n      const component = createTestComponent(\n        createDefaultValue(\"{ foo: 'foo', bar: { hey: 'ho' } }\")\n      );\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('object');\n    });\n\n    it('should support short function', () => {\n      const component = createTestComponent(createDefaultValue('() => {}'));\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('() => {}');\n      expect(defaultValue?.detail).toBeUndefined();\n    });\n\n    it('should support long function', () => {\n      const component = createTestComponent(\n        createDefaultValue(\n          '(foo, bar) => {\\n  const concat = foo + bar;\\n  const append = concat + \" hey!\";\\n  \\n  return append;\\n}'\n        )\n      );\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('func');\n\n      const expectedDetail = `(foo, bar) => {\n        const concat = foo + bar;\n        const append = concat + ' hey!';\n        return append\n      }`;\n\n      expect(defaultValue?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n    });\n\n    it('should use the name of function when available and indicate that args are present', () => {\n      const component = createTestComponent(\n        createDefaultValue('function concat(a, b) {\\n  return a + b;\\n}')\n      );\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('concat( ... )');\n\n      const expectedDetail = `function concat(a, b) {\n        return a + b\n      }`;\n\n      expect(defaultValue?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n    });\n\n    it('should use the name of function when available', () => {\n      const component = createTestComponent(\n        createDefaultValue('function hello() {\\n  return \"hello\";\\n}')\n      );\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('hello()');\n\n      const expectedDetail = `function hello() {\n        return 'hello'\n      }`;\n\n      expect(defaultValue?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n    });\n\n    it('should support short element', () => {\n      const component = createTestComponent(createDefaultValue('<div>Hey!</div>'));\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('<div>Hey!</div>');\n      expect(defaultValue?.detail).toBeUndefined();\n    });\n\n    it('should support long element', () => {\n      const component = createTestComponent(\n        createDefaultValue(\n          '<div>Hey! Hey! Hey!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!</div>'\n        )\n      );\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('element');\n      expect(defaultValue?.detail).toBe(\n        '<div>Hey! Hey! Hey!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!</div>'\n      );\n    });\n\n    it('should support element with props', () => {\n      const component = createTestComponent(createDefaultValue('<Component className=\"toto\" />'));\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('<Component />');\n      expect(defaultValue?.detail).toBe('<Component className=\"toto\" />');\n    });\n\n    it(\"should use the name of the React component when it's available\", () => {\n      const component = createTestComponent(\n        createDefaultValue(\n          'function InlinedFunctionalComponent() {\\n  return <div>Inlined FunctionalComponent!</div>;\\n}'\n        )\n      );\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('<InlinedFunctionalComponent />');\n\n      const expectedDetail = `function InlinedFunctionalComponent() {\n        return <div>Inlined FunctionalComponent!</div>;\n      }`;\n\n      expect(defaultValue?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n    });\n\n    it('should not use the name of an HTML element', () => {\n      const component = createTestComponent(createDefaultValue('<div>Hey!</div>'));\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).not.toBe('<div />');\n    });\n\n    it('should support short array', () => {\n      const component = createTestComponent(createDefaultValue('[1]'));\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('[1]');\n      expect(defaultValue?.detail).toBeUndefined();\n    });\n\n    it('should support long array', () => {\n      const component = createTestComponent(\n        createDefaultValue(\n          '[\\n  {\\n    thing: {\\n      id: 2,\\n      func: () => {},\\n      arr: [],\\n    },\\n  },\\n]'\n        )\n      );\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('array');\n\n      const expectedDetail = `[{\n          thing: {\n            id: 2,\n            func: () => {\n            },\n            arr: []\n          }\n        }]`;\n\n      expect(defaultValue?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n    });\n\n    it('should not have deep array in summary', () => {\n      const component = createTestComponent(createDefaultValue('[[[1]]]'));\n\n      const { defaultValue } = extractPropDef(component);\n\n      expect(defaultValue?.summary).toBe('array');\n    });\n\n    describe('fromRawDefaultProp', () => {\n      [\n        { type: 'number', defaultProp: 1 },\n        { type: 'boolean', defaultProp: true },\n        { type: 'symbol', defaultProp: Symbol('hey!') },\n      ].forEach((x) => {\n        it(`should support ${x.type}`, () => {\n          // @ts-expect-error (not strict)\n          const component = createTestComponent(null);\n\n          const { defaultValue } = extractPropDef(component, x.defaultProp);\n\n          expect(defaultValue?.summary).toBe(x.defaultProp.toString());\n          expect(defaultValue?.detail).toBeUndefined();\n        });\n      });\n\n      it('should support strings', () => {\n        const component = createTestComponent(undefined);\n\n        const { defaultValue } = extractPropDef(component, 'foo');\n\n        expect(defaultValue?.summary).toBe('\"foo\"');\n        expect(defaultValue?.detail).toBeUndefined();\n      });\n\n      it('should support array of primitives', () => {\n        const component = createTestComponent(undefined);\n\n        const { defaultValue } = extractPropDef(component, [1, 2, 3]);\n\n        expect(defaultValue?.summary).toBe('[1,    2,    3]');\n        expect(defaultValue?.detail).toBeUndefined();\n      });\n\n      it('should support array of short object', () => {\n        const component = createTestComponent(undefined);\n\n        const { defaultValue } = extractPropDef(component, [{ foo: 'bar' }]);\n\n        expect(defaultValue?.summary).toBe(\"[{ 'foo': 'bar' }]\");\n        expect(defaultValue?.detail).toBeUndefined();\n      });\n\n      it('should support array of long object', () => {\n        const component = createTestComponent(undefined);\n\n        const { defaultValue } = extractPropDef(component, [{ foo: 'bar', bar: 'foo', hey: 'ho' }]);\n\n        expect(defaultValue?.summary).toBe('array');\n\n        const expectedDetail = `[{\n          'foo': 'bar',\n          'bar': 'foo',\n          'hey': 'ho'\n        }]`;\n\n        expect(defaultValue?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n      });\n\n      it('should support short object', () => {\n        const component = createTestComponent(undefined);\n\n        const { defaultValue } = extractPropDef(component, { foo: 'bar' });\n\n        expect(defaultValue?.summary).toBe(\"{ 'foo': 'bar' }\");\n        expect(defaultValue?.detail).toBeUndefined();\n      });\n\n      it('should support long object', () => {\n        const component = createTestComponent(undefined);\n\n        const { defaultValue } = extractPropDef(component, { foo: 'bar', bar: 'foo', hey: 'ho' });\n\n        expect(defaultValue?.summary).toBe('object');\n\n        const expectedDetail = `{\n          'foo': 'bar',\n          'bar': 'foo',\n          'hey': 'ho'\n        }`;\n\n        expect(defaultValue?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n      });\n\n      it('should support anonymous function', () => {\n        const component = createTestComponent(undefined);\n\n        const { defaultValue } = extractPropDef(component, () => 'hey!');\n\n        expect(defaultValue?.summary).toBe('func');\n        expect(defaultValue?.detail).toBeUndefined();\n      });\n\n      it('should support named function', () => {\n        const component = createTestComponent(undefined);\n\n        const { defaultValue } = extractPropDef(component, function hello() {\n          return 'world!';\n        });\n\n        expect(defaultValue?.summary).toBe('hello()');\n        expect(defaultValue?.detail).toBeUndefined();\n      });\n\n      it('should support named function with params', () => {\n        const component = createTestComponent(undefined);\n\n        const { defaultValue } = extractPropDef(component, function add(a: number, b: number) {\n          return a + b;\n        });\n\n        expect(defaultValue?.summary).toBe('add( ... )');\n        expect(defaultValue?.detail).toBeUndefined();\n      });\n\n      it('should support React element', () => {\n        const component = createTestComponent(undefined);\n\n        const defaultProp = <ReactComponent />;\n        // Simulate babel-plugin-add-react-displayname.\n        defaultProp.type.displayName = 'ReactComponent';\n\n        const { defaultValue } = extractPropDef(component, defaultProp);\n\n        expect(defaultValue?.summary).toBe('<ReactComponent />');\n        expect(defaultValue?.detail).toBeUndefined();\n      });\n\n      it('should support React element with props', () => {\n        const component = createTestComponent(undefined);\n\n        // @ts-expect-error (Converted from ts-ignore)\n        const defaultProp = <ReactComponent className=\"toto\" />;\n        // Simulate babel-plugin-add-react-displayname.\n        defaultProp.type.displayName = 'ReactComponent';\n\n        const { defaultValue } = extractPropDef(component, defaultProp);\n\n        expect(defaultValue?.summary).toBe('<ReactComponent />');\n        expect(defaultValue?.detail).toBe('<ReactComponent className=\"toto\" />');\n      });\n\n      it('should support short HTML element', () => {\n        const component = createTestComponent(undefined);\n\n        const { defaultValue } = extractPropDef(component, <div>HTML element</div>);\n\n        expect(defaultValue?.summary).toBe('<div>HTML element</div>');\n        expect(defaultValue?.detail).toBeUndefined();\n      });\n\n      it('should support long HTML element', () => {\n        const component = createTestComponent(undefined);\n\n        const { defaultValue } = extractPropDef(\n          component,\n          <div>HTML element!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!</div>\n        );\n\n        expect(defaultValue?.summary).toBe('element');\n\n        const expectedDetail = `<div>\n          HTML element!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n        </div>`;\n\n        expect(defaultValue?.detail?.replace(/\\s/g, '')).toBe(expectedDetail.replace(/\\s/g, ''));\n      });\n\n      ['element', 'elementType'].forEach((x) => {\n        it(`should support inlined React class component for ${x}`, () => {\n          const component = createTestComponent(undefined, x);\n\n          const { defaultValue } = extractPropDef(\n            component,\n            class InlinedClassComponent extends React.PureComponent {\n              render() {\n                return <div>Inlined ClassComponent!</div>;\n              }\n            }\n          );\n\n          expect(defaultValue?.summary).toBe('<InlinedClassComponent />');\n          expect(defaultValue?.detail).toBeUndefined();\n        });\n\n        it(`should support inlined anonymous React functional component for ${x}`, () => {\n          const component = createTestComponent(undefined, x);\n\n          const { defaultValue } = extractPropDef(component, () => {\n            return <div>Inlined FunctionalComponent!</div>;\n          });\n\n          expect(defaultValue?.summary).toBe('element');\n          expect(defaultValue?.detail).toBeUndefined();\n        });\n\n        it(`should support inlined anonymous React functional component with props for ${x}`, () => {\n          const component = createTestComponent(undefined, x);\n\n          const { defaultValue } = extractPropDef(component, ({ foo }: { foo: string }) => {\n            return <div>{foo}</div>;\n          });\n\n          expect(defaultValue?.summary).toBe('element');\n          expect(defaultValue?.detail).toBeUndefined();\n        });\n\n        it(`should support inlined named React functional component for ${x}`, () => {\n          const component = createTestComponent(undefined, x);\n\n          const { defaultValue } = extractPropDef(component, function InlinedFunctionalComponent() {\n            return <div>Inlined FunctionalComponent!</div>;\n          });\n\n          expect(defaultValue?.summary).toBe('<InlinedFunctionalComponent />');\n          expect(defaultValue?.detail).toBeUndefined();\n        });\n\n        it(`should support inlined named React functional component with props for ${x}`, () => {\n          const component = createTestComponent(undefined, x);\n\n          const { defaultValue } = extractPropDef(\n            component,\n            function InlinedFunctionalComponent({ foo }: { foo: string }) {\n              return <div>{foo}</div>;\n            }\n          );\n\n          expect(defaultValue?.summary).toBe('<InlinedFunctionalComponent />');\n          expect(defaultValue?.detail).toBeUndefined();\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/docs/typeScript/handleProp.ts",
    "content": "import type { ExtractedProp, PropDef } from 'storybook/internal/docs-tools';\n\nimport { createDefaultValue, createDefaultValueFromRawDefaultProp } from '../lib/defaultValues';\n\nexport function enhanceTypeScriptProp(extractedProp: ExtractedProp, rawDefaultProp?: any): PropDef {\n  const { propDef } = extractedProp;\n\n  const { defaultValue } = extractedProp.docgenInfo;\n  if (defaultValue != null && defaultValue.value != null) {\n    const newDefaultValue = createDefaultValue(defaultValue.value);\n    if (newDefaultValue != null) {\n      propDef.defaultValue = newDefaultValue;\n    }\n  } else if (rawDefaultProp != null) {\n    const newDefaultValue = createDefaultValueFromRawDefaultProp(rawDefaultProp, propDef);\n\n    if (newDefaultValue != null) {\n      propDef.defaultValue = newDefaultValue;\n    }\n  }\n\n  return propDef;\n}\n\nexport function enhanceTypeScriptProps(extractedProps: ExtractedProp[]): PropDef[] {\n  return extractedProps.map((prop) => enhanceTypeScriptProp(prop));\n}\n"
  },
  {
    "path": "code/renderers/react/src/enrichCsf.test.ts",
    "content": "import { expect, test, vi } from 'vitest';\n\nimport { generate } from 'storybook/internal/babel';\nimport { type InterPresetOptions, getPresets } from 'storybook/internal/common';\nimport { loadCsf } from 'storybook/internal/csf-tools';\n\nimport { dedent } from 'ts-dedent';\n\nimport { enrichCsf } from './enrichCsf.ts';\n\nvi.mock('my-preset', () => ({\n  default: { experimental_enrichCsf: enrichCsf, features: { experimentalCodeExamples: true } },\n}));\n\ntest('should enrich csf with code parameters', async () => {\n  const presets = await getPresets(['my-preset'], { isCritical: true } as InterPresetOptions);\n  const enrichCsf = await presets.apply('experimental_enrichCsf');\n\n  const code = dedent`\n    import preview from '#.storybook/preview';\n    import { Button } from './Button';\n    \n    const meta = preview.meta({ component: Button })\n    \n    export const Primary = meta.story({ args: { primary: true,  label: 'Button' } });\n    export const Secondary = meta.story({ args: { label: 'Button' } });\n  `;\n  const csf = loadCsf(code, { makeTitle: (x) => x ?? 'title' });\n  csf.parse();\n  await enrichCsf?.(csf, csf);\n  expect(generate(csf._ast).code).toMatchInlineSnapshot(`\n    \"import preview from '#.storybook/preview';\n    import { Button } from './Button';\n    const meta = preview.meta({\n      component: Button\n    });\n    export const Primary = meta.story({\n      args: {\n        primary: true,\n        label: 'Button'\n      }\n    });\n    export const Secondary = meta.story({\n      args: {\n        label: 'Button'\n      }\n    });\n    Primary.input.parameters = {\n      ...Primary.input.parameters,\n      docs: {\n        ...Primary.input.parameters?.docs,\n        source: {\n          code: \"const Primary = () => <Button primary label=\\\\\"Button\\\\\" />;\\\\n\",\n          ...Primary.input.parameters?.docs?.source\n        }\n      }\n    };\n    Secondary.input.parameters = {\n      ...Secondary.input.parameters,\n      docs: {\n        ...Secondary.input.parameters?.docs,\n        source: {\n          code: \"const Secondary = () => <Button label=\\\\\"Button\\\\\" />;\\\\n\",\n          ...Secondary.input.parameters?.docs?.source\n        }\n      }\n    };\"\n  `);\n});\n\ntest('should not enrich when experimentalCodeExamples is disabled', async () => {\n  // @ts-expect-error module does not exist\n  vi.spyOn((await import('my-preset')).default, 'features', 'get').mockImplementation(() => ({\n    experimentalCodeExamples: false,\n  }));\n  const presets = await getPresets(['my-preset'], { isCritical: true } as InterPresetOptions);\n  const enrichCsf = await presets.apply('experimental_enrichCsf');\n\n  const code = dedent`\n    import preview from '#.storybook/preview';\n    import { Button } from './Button';\n    const meta = preview.meta({ component: Button })\n    export const Primary = meta.story({ args: { primary: true,  label: 'Button' } });\n  `;\n  const csf = loadCsf(code, { makeTitle: (x) => x ?? 'title' });\n  csf.parse();\n  await enrichCsf?.(csf, csf);\n  expect(generate(csf._ast).code).toMatchInlineSnapshot(`\n    \"import preview from '#.storybook/preview';\n    import { Button } from './Button';\n    const meta = preview.meta({\n      component: Button\n    });\n    export const Primary = meta.story({\n      args: {\n        primary: true,\n        label: 'Button'\n      }\n    });\"\n  `);\n});\n"
  },
  {
    "path": "code/renderers/react/src/enrichCsf.ts",
    "content": "import { type NodePath, recast, types as t } from 'storybook/internal/babel';\nimport { getPrettier } from 'storybook/internal/common';\nimport { type CsfFile } from 'storybook/internal/csf-tools';\nimport type { PresetPropertyFn } from 'storybook/internal/types';\n\nimport { join } from 'pathe';\n\nimport { getCodeSnippet } from './componentManifest/generateCodeSnippet.ts';\n\nexport const enrichCsf: PresetPropertyFn<'experimental_enrichCsf'> = async (input, options) => {\n  const features = await options.presets.apply('features');\n  if (!features.experimentalCodeExamples) {\n    return;\n  }\n  return async (csf: CsfFile, csfSource: CsfFile) => {\n    const promises = Object.keys(csf._stories).map(async (key) => {\n      if (!csfSource._meta?.component) {\n        return;\n      }\n      const { format } = await getPrettier();\n      let node;\n      let snippet;\n      try {\n        node = getCodeSnippet(csfSource, key, csfSource._meta?.component);\n      } catch (e) {\n        if (!(e instanceof Error)) {\n          return;\n        }\n        snippet = e.message;\n      }\n\n      try {\n        // TODO read the user config\n        if (!snippet && node) {\n          snippet = await format(recast.print(node).code, {\n            filepath: join(process.cwd(), 'component.tsx'),\n          });\n        }\n      } catch (e) {\n        if (!(e instanceof Error)) {\n          return;\n        }\n        snippet = e.message;\n      }\n\n      if (!snippet) {\n        return;\n      }\n\n      // e.g. Story.input.parameters\n      const originalParameters = t.memberExpression(\n        csf._metaIsFactory\n          ? t.memberExpression(t.identifier(key), t.identifier('input'))\n          : t.identifier(key),\n        t.identifier('parameters')\n      );\n\n      // e.g. Story.input.parameters?.docs\n      const docsParameter = t.optionalMemberExpression(\n        originalParameters,\n        t.identifier('docs'),\n        false,\n        true\n      );\n\n      // For example:\n      // Story.input.parameters = {\n      //   ...Story.input.parameters,\n      //   docs: {\n      //     ...Story.input.parameters?.docs,\n      //     source: {\n      //       code: \"snippet\",\n      //       ...Story.input.parameters?.docs?.source\n      //     }\n      //   }\n      // };\n\n      csf._ast.program.body.push(\n        t.expressionStatement(\n          t.assignmentExpression(\n            '=',\n            originalParameters,\n            t.objectExpression([\n              t.spreadElement(originalParameters),\n              t.objectProperty(\n                t.identifier('docs'),\n                t.objectExpression([\n                  t.spreadElement(docsParameter),\n                  t.objectProperty(\n                    t.identifier('source'),\n                    t.objectExpression([\n                      t.objectProperty(t.identifier('code'), t.stringLiteral(snippet)),\n                      t.spreadElement(\n                        t.optionalMemberExpression(\n                          docsParameter,\n                          t.identifier('source'),\n                          false,\n                          true\n                        )\n                      ),\n                    ])\n                  ),\n                ])\n              ),\n            ])\n          )\n        )\n      );\n    });\n    await Promise.all(promises);\n  };\n};\n"
  },
  {
    "path": "code/renderers/react/src/entry-preview-argtypes.ts",
    "content": "import { enhanceArgTypes, extractComponentDescription } from 'storybook/internal/docs-tools';\nimport type { ArgTypesEnhancer } from 'storybook/internal/types';\n\nimport { extractArgTypes } from './extractArgTypes.ts';\nimport type { ReactRenderer } from './types.ts';\n\nexport const parameters = {\n  docs: {\n    extractArgTypes,\n    extractComponentDescription,\n  },\n};\n\nexport const argTypesEnhancers: ArgTypesEnhancer<ReactRenderer>[] = [enhanceArgTypes];\n"
  },
  {
    "path": "code/renderers/react/src/entry-preview-docs.ts",
    "content": "import type { DecoratorFunction } from 'storybook/internal/types';\n\nimport { jsxDecorator } from './docs/jsxDecorator.tsx';\nimport type { ReactRenderer } from './types.ts';\n\nexport const decorators: DecoratorFunction<ReactRenderer>[] =\n  'FEATURES' in globalThis && globalThis?.FEATURES?.experimentalCodeExamples ? [] : [jsxDecorator];\n\nexport { applyDecorators } from './docs/applyDecorators.ts';\n\nexport const parameters = {\n  docs: {\n    story: { inline: true },\n  },\n};\n"
  },
  {
    "path": "code/renderers/react/src/entry-preview-rsc.tsx",
    "content": "export const parameters = {\n  react: {\n    rsc: true,\n  },\n};\n"
  },
  {
    "path": "code/renderers/react/src/entry-preview.tsx",
    "content": "import * as React from 'react';\n\nimport { Tag } from 'storybook/internal/preview-api';\n\nimport { global } from '@storybook/global';\n\nimport { configure } from 'storybook/test';\n\nimport { getAct, getReactActEnvironment, setReactActEnvironment } from './act-compat.ts';\nimport type { Decorator } from './public-types.ts';\n\nexport { render } from './render.tsx';\nexport { renderToCanvas } from './renderToCanvas.tsx';\nexport { mount } from './mount.ts';\nexport { applyDecorators } from './applyDecorators.ts';\n\nexport const decorators: Decorator[] = [\n  (story, context) => {\n    if (!context.parameters?.react?.rsc) {\n      return story();\n    }\n\n    const [major, minor] = React.version.split('.').map((part) => parseInt(part, 10));\n\n    if (!Number.isInteger(major) || !Number.isInteger(minor)) {\n      throw new Error('Unable to parse React version');\n    }\n    if (major < 18 || (major === 18 && minor < 3)) {\n      throw new Error('React Server Components require React >= 18.3');\n    }\n\n    return <React.Suspense>{story()}</React.Suspense>;\n  },\n  (story, context) => {\n    // @ts-expect-error this feature flag only exists in the react frameworks\n    if (context.tags?.includes(Tag.TEST_FN) && !global.FEATURES?.experimentalTestSyntax) {\n      throw new Error(\n        'To use the experimental test function, you must enable the experimentalTestSyntax feature flag. See https://storybook.js.org/docs/api/main-config/main-config-features#experimentaltestsyntax'\n      );\n    }\n    return story();\n  },\n];\n\nexport const parameters = {\n  renderer: 'react',\n};\n\nexport const beforeAll = async () => {\n  try {\n    // copied from\n    // https://github.com/testing-library/react-testing-library/blob/3dcd8a9649e25054c0e650d95fca2317b7008576/src/pure.js\n\n    const act = await getAct();\n\n    configure({\n      unstable_advanceTimersWrapper: (cb) => {\n        return act(cb);\n      },\n      // For more context about why we need disable act warnings in waitFor:\n      // https://github.com/reactwg/react-18/discussions/102\n      asyncWrapper: async (cb) => {\n        const previousActEnvironment = getReactActEnvironment();\n        setReactActEnvironment(false);\n        try {\n          const result = await cb();\n          // Drain microtask queue.\n          // Otherwise we'll restore the previous act() environment, before we resolve the `waitFor` call.\n          // The caller would have no chance to wrap the in-flight Promises in `act()`\n          await new Promise<void>((resolve) => {\n            setTimeout(() => {\n              resolve();\n            }, 0);\n\n            if (jestFakeTimersAreEnabled()) {\n              jest.advanceTimersByTime(0);\n            }\n          });\n\n          return result;\n        } finally {\n          setReactActEnvironment(previousActEnvironment);\n        }\n      },\n      eventWrapper: (cb) => {\n        let result;\n        act(() => {\n          result = cb();\n          return result;\n        });\n        return result;\n      },\n    });\n  } catch (e) {\n    // no-op\n    // storybook/test might not be available\n  }\n};\n\n/** The function is used to configure jest's fake timers in environments where React's act is enabled */\nfunction jestFakeTimersAreEnabled() {\n  if (typeof jest !== 'undefined' && jest !== null) {\n    return (\n      // legacy timers\n\n      (setTimeout as any)._isMockFunction === true || // modern timers\n      Object.prototype.hasOwnProperty.call(setTimeout, 'clock')\n    );\n  }\n\n  return false;\n}\n"
  },
  {
    "path": "code/renderers/react/src/extractArgTypes.test.ts",
    "content": "import { join, resolve } from 'node:path';\n\nimport { describe, expect, it, vi } from 'vitest';\n\nimport { normalizeNewlines } from 'storybook/internal/docs-tools';\nimport type { Renderer } from 'storybook/internal/types';\n\nimport { transformFileSync, transformSync } from '@babel/core';\n// @ts-expect-error (seems broken/missing)\nimport requireFromString from 'require-from-string';\nimport { inferControls } from 'storybook/preview-api';\n\nimport { extractArgTypes } from './extractArgTypes.ts';\nimport { extractProps } from './extractProps.ts';\nimport type { StoryContext } from './types.ts';\n\n// File hierarchy:\n// __testfixtures__ / some-test-case / input.*\nconst inputRegExp = /^input\\..*$/;\n\nconst transformToModule = (inputCode: string) => {\n  const options = {\n    presets: [\n      [\n        '@babel/preset-env',\n        {\n          targets: {\n            esmodules: true,\n          },\n        },\n      ],\n    ],\n  };\n  const { code } = transformSync(inputCode, options) || {};\n  return normalizeNewlines(code || '');\n};\n\nconst annotateWithDocgen = (inputPath: string) => {\n  const options = {\n    presets: ['@babel/typescript', '@babel/react'],\n    plugins: ['babel-plugin-react-docgen', '@babel/plugin-transform-class-properties'],\n    babelrc: false,\n  };\n  const { code } = transformFileSync(inputPath, options) || {};\n  return normalizeNewlines(code || '');\n};\n\n// We need to skip a set of test cases that use ESM code, as the `requireFromString`\n// code below does not support it. These stories will be tested via Chromatic in the\n// sandboxes. Hopefully we can figure out a better testing strategy in the future.\nconst skippedTests = [\n  'js-class-component',\n  'js-function-component',\n  'js-re-exported-component',\n  'js-function-component-inline-defaults',\n  'js-function-component-inline-defaults-no-propTypes',\n  'ts-function-component',\n  'ts-function-component-inline-defaults',\n  'js-proptypes',\n];\n\nconst fs = await vi.importActual<typeof import('node:fs')>('node:fs');\n\ndescribe('react component properties', async () => {\n  // Fixture files are in template/stories\n  const fixturesDir = resolve(__dirname, '../template/stories/docgen-components');\n\n  fs.readdirSync(fixturesDir, { withFileTypes: true }).forEach((testEntry) => {\n    if (testEntry.isDirectory()) {\n      const testDir = join(fixturesDir, testEntry.name);\n      const testFile = fs.readdirSync(testDir).find((fileName) => inputRegExp.test(fileName));\n      if (testFile) {\n        if (skippedTests.includes(testEntry.name)) {\n          it.skip(`${testEntry.name}`, () => {});\n        } else {\n          it(`${testEntry.name}`, async () => {\n            const inputPath = join(testDir, testFile);\n\n            // snapshot the output of babel-plugin-react-docgen\n            const docgenPretty = annotateWithDocgen(inputPath);\n            await expect(docgenPretty).toMatchFileSnapshot(join(testDir, 'docgen.snapshot'));\n\n            // transform into an uglier format that's works with require-from-string\n            const docgenModule = transformToModule(docgenPretty);\n\n            // snapshot the output of component-properties/react\n            const { component } = requireFromString(docgenModule, inputPath);\n            const properties = extractProps(component);\n            await expect(properties).toMatchFileSnapshot(join(testDir, 'properties.snapshot'));\n\n            // snapshot the output of `extractArgTypes`\n            const argTypes = extractArgTypes(component);\n            const parameters = { __isArgsStory: true };\n            const rows = inferControls({\n              argTypes,\n              parameters,\n            } as unknown as StoryContext<Renderer>);\n            await expect(rows).toMatchFileSnapshot(join(testDir, 'argTypes.snapshot'));\n          });\n        }\n      }\n    }\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/extractArgTypes.ts",
    "content": "import type { ArgTypesExtractor, PropDef } from 'storybook/internal/docs-tools';\nimport type { StrictArgTypes } from 'storybook/internal/types';\n\nimport { extractProps } from './extractProps.ts';\n\nexport const extractArgTypes: ArgTypesExtractor = (component): StrictArgTypes | null => {\n  if (component) {\n    const { rows } = extractProps(component);\n    if (rows) {\n      return rows.reduce((acc: StrictArgTypes, row: PropDef) => {\n        const {\n          name,\n          description,\n          type,\n          sbType,\n          defaultValue: defaultSummary,\n          jsDocTags,\n          required,\n        } = row;\n\n        acc[name] = {\n          name,\n          description,\n          type: { required, ...sbType },\n          table: {\n            type: type ?? undefined,\n            jsDocTags,\n            defaultValue: defaultSummary ?? undefined,\n          },\n        };\n        return acc;\n      }, {});\n    }\n  }\n\n  return null;\n};\n"
  },
  {
    "path": "code/renderers/react/src/extractProps.ts",
    "content": "import {\n  type PropDef,\n  TypeSystem,\n  extractComponentProps,\n  hasDocgen,\n} from 'storybook/internal/docs-tools';\n\nimport { isMemo } from './docs/lib/componentTypes.ts';\nimport { enhancePropTypesProps } from './docs/propTypes/handleProp.ts';\nimport { enhanceTypeScriptProps } from './docs/typeScript/handleProp.ts';\n\n// FIXME\ntype Component = any;\n\nexport interface PropDefMap {\n  [p: string]: PropDef;\n}\n\nfunction getPropDefs(component: Component, section: string): PropDef[] {\n  let processedComponent = component;\n\n  if (!hasDocgen(component) && !component.propTypes && isMemo(component)) {\n    processedComponent = component.type;\n  }\n\n  const extractedProps = extractComponentProps(processedComponent, section);\n  if (extractedProps.length === 0) {\n    return [];\n  }\n\n  switch (extractedProps[0].typeSystem) {\n    case TypeSystem.JAVASCRIPT:\n      return enhancePropTypesProps(extractedProps, component);\n    case TypeSystem.TYPESCRIPT:\n      return enhanceTypeScriptProps(extractedProps);\n    default:\n      return extractedProps.map((x) => x.propDef);\n  }\n}\n\nexport const extractProps = (component: Component) => ({\n  rows: getPropDefs(component, 'props'),\n});\n"
  },
  {
    "path": "code/renderers/react/src/globals.ts",
    "content": "import { global } from '@storybook/global';\n\nconst { window: globalWindow } = global;\n\nif (globalWindow) {\n  globalWindow.STORYBOOK_ENV = 'react';\n}\n"
  },
  {
    "path": "code/renderers/react/src/index.ts",
    "content": "import './globals.ts';\n\nexport * from './public-types.ts';\n\nexport * from './portable-stories.tsx';\n\nexport * from './preview.tsx';\n\nexport type { ReactTypes } from './types.ts';\n"
  },
  {
    "path": "code/renderers/react/src/mount.ts",
    "content": "import type { BaseAnnotations } from 'storybook/internal/types';\n\nimport { type ReactRenderer, type StoryContext } from './public-types.ts';\n\nexport const mount: BaseAnnotations<ReactRenderer>['mount'] =\n  (context: StoryContext) => async (ui) => {\n    if (ui != null) {\n      context.originalStoryFn = () => ui;\n    }\n    await context.renderToCanvas();\n    return context.canvas;\n  };\n"
  },
  {
    "path": "code/renderers/react/src/playwright.ts",
    "content": "export { createPlaywrightTest as createTest } from 'storybook/preview-api';\n"
  },
  {
    "path": "code/renderers/react/src/portable-stories.tsx",
    "content": "import * as React from 'react';\n\nimport type {\n  Args,\n  ComposedStoryFn,\n  NamedOrDefaultProjectAnnotations,\n  NormalizedProjectAnnotations,\n  ProjectAnnotations,\n  Store_CSFExports,\n  StoriesWithPartialProps,\n  StoryAnnotationsOrFn,\n} from 'storybook/internal/types';\n\nimport {\n  composeConfigs,\n  composeStories as originalComposeStories,\n  composeStory as originalComposeStory,\n  setProjectAnnotations as originalSetProjectAnnotations,\n  setDefaultProjectAnnotations,\n} from 'storybook/preview-api';\n\nimport * as reactProjectAnnotations from './entry-preview.tsx';\nimport * as reactArgTypesAnnotations from './entry-preview-argtypes.ts';\nimport type { Meta } from './public-types.ts';\nimport type { ReactRenderer } from './types.ts';\n\n/**\n * Function that sets the globalConfig of your storybook. The global config is the preview module of\n * your .storybook folder.\n *\n * It should be run a single time, so that your global config (e.g. decorators) is applied to your\n * stories when using `composeStories` or `composeStory`.\n *\n * Example:\n *\n * ```jsx\n * // setup-file.js\n * import { setProjectAnnotations } from '@storybook/react';\n * import projectAnnotations from './.storybook/preview';\n *\n * setProjectAnnotations(projectAnnotations);\n * ```\n *\n * @param projectAnnotations - E.g. (import * as projectAnnotations from '../.storybook/preview')\n */\nexport function setProjectAnnotations(\n  projectAnnotations:\n    | NamedOrDefaultProjectAnnotations<any>\n    | NamedOrDefaultProjectAnnotations<any>[]\n): NormalizedProjectAnnotations<ReactRenderer> {\n  setDefaultProjectAnnotations(INTERNAL_DEFAULT_PROJECT_ANNOTATIONS);\n  return originalSetProjectAnnotations(\n    projectAnnotations\n  ) as NormalizedProjectAnnotations<ReactRenderer>;\n}\n\n// This will not be necessary once we have auto preset loading\nexport const INTERNAL_DEFAULT_PROJECT_ANNOTATIONS: ProjectAnnotations<ReactRenderer> =\n  composeConfigs([\n    reactProjectAnnotations,\n    reactArgTypesAnnotations,\n    {\n      /** @deprecated */\n      renderToCanvas: async (renderContext, canvasElement) => {\n        if (renderContext.storyContext.testingLibraryRender == null) {\n          return reactProjectAnnotations.renderToCanvas(renderContext, canvasElement);\n        }\n        const {\n          storyContext: { context, unboundStoryFn: Story, testingLibraryRender: render },\n        } = renderContext;\n        const { unmount } = render(<Story {...context} />, { container: context.canvasElement });\n        return unmount;\n      },\n    } as ProjectAnnotations<ReactRenderer>,\n  ]);\n\n/**\n * Function that will receive a story along with meta (e.g. a default export from a .stories file)\n * and optionally projectAnnotations e.g. (import * as projectAnnotations from\n * '../.storybook/preview) and will return a composed component that has all\n * args/parameters/decorators/etc combined and applied to it.\n *\n * It's very useful for reusing a story in scenarios outside of Storybook like unit testing.\n *\n * Example:\n *\n * ```jsx\n * import { render } from '@testing-library/react';\n * import { composeStory } from '@storybook/react';\n * import Meta, { Primary as PrimaryStory } from './Button.stories';\n *\n * const Primary = composeStory(PrimaryStory, Meta);\n *\n * test('renders primary button with Hello World', () => {\n *   const { getByText } = render(<Primary>Hello world</Primary>);\n *   expect(getByText(/Hello world/i)).not.toBeNull();\n * });\n * ```\n *\n * @param story\n * @param componentAnnotations - E.g. (import Meta from './Button.stories')\n * @param [projectAnnotations] - E.g. (import * as projectAnnotations from '../.storybook/preview')\n *   this can be applied automatically if you use `setProjectAnnotations` in your setup files.\n * @param [exportsName] - In case your story does not contain a name and you want it to have a name.\n */\nexport function composeStory<TArgs extends Args = Args>(\n  story: StoryAnnotationsOrFn<ReactRenderer, TArgs>,\n  componentAnnotations: Meta<TArgs | any>,\n  projectAnnotations?: ProjectAnnotations<ReactRenderer>,\n  exportsName?: string\n): ComposedStoryFn<ReactRenderer, Partial<TArgs>> {\n  return originalComposeStory<ReactRenderer, TArgs>(\n    story as StoryAnnotationsOrFn<ReactRenderer, Args>,\n    componentAnnotations,\n    projectAnnotations,\n    globalThis.globalProjectAnnotations ?? INTERNAL_DEFAULT_PROJECT_ANNOTATIONS,\n    exportsName\n  );\n}\n\n/**\n * Function that will receive a stories import (e.g. `import * as stories from './Button.stories'`)\n * and optionally projectAnnotations (e.g. `import * as projectAnnotations from\n * '../.storybook/preview`) and will return an object containing all the stories passed, but now as\n * a composed component that has all args/parameters/decorators/etc combined and applied to it.\n *\n * It's very useful for reusing stories in scenarios outside of Storybook like unit testing.\n *\n * Example:\n *\n * ```jsx\n * import { render } from '@testing-library/react';\n * import { composeStories } from '@storybook/react';\n * import * as stories from './Button.stories';\n *\n * const { Primary, Secondary } = composeStories(stories);\n *\n * test('renders primary button with Hello World', () => {\n *   const { getByText } = render(<Primary>Hello world</Primary>);\n *   expect(getByText(/Hello world/i)).not.toBeNull();\n * });\n * ```\n *\n * @param csfExports - E.g. (import * as stories from './Button.stories')\n * @param [projectAnnotations] - E.g. (import * as projectAnnotations from '../.storybook/preview')\n *   this can be applied automatically if you use `setProjectAnnotations` in your setup files.\n */\nexport function composeStories<TModule extends Store_CSFExports<ReactRenderer, any>>(\n  csfExports: TModule,\n  projectAnnotations?: ProjectAnnotations<ReactRenderer>\n) {\n  // @ts-expect-error (Converted from ts-ignore)\n  const composedStories = originalComposeStories(csfExports, projectAnnotations, composeStory);\n\n  return composedStories as unknown as Omit<\n    StoriesWithPartialProps<ReactRenderer, TModule>,\n    keyof Store_CSFExports\n  >;\n}\n"
  },
  {
    "path": "code/renderers/react/src/preset.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { optimizeViteDeps } from './preset.ts';\n\ndescribe('optimizeViteDeps', () => {\n  it('includes react-dom/test-utils', () => {\n    // react-dom/test-utils is dynamically imported via `await import('react-dom/test-utils')`\n    // in act-compat.ts. Vite's static analyzer does not pre-bundle dynamic imports,\n    // so it must be listed explicitly in optimizeViteDeps.\n    // If this test fails, add 'react-dom/test-utils' back to the optimizeViteDeps array in preset.ts.\n    expect(optimizeViteDeps).toContain('react-dom/test-utils');\n  });\n});\n"
  },
  {
    "path": "code/renderers/react/src/preset.ts",
    "content": "import path, { join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { getProjectRoot } from 'storybook/internal/common';\nimport type { ArgTypes } from 'storybook/internal/csf';\nimport type { Options, PresetProperty } from 'storybook/internal/types';\n\nimport { resolvePackageDir } from '../../../core/src/shared/utils/module.ts';\nimport { extractArgTypesFromDocgen } from './componentManifest/reactDocgen/extractReactDocgenInfo.ts';\nimport { extractArgTypesFromDocgenTypescript } from './componentManifest/reactDocgen/extractReactTypescriptDocgenInfo.ts';\nimport type {\n  GetArgTypesDataOptions,\n  ReactDocgenConfig,\n} from './componentManifest/reactDocgen/utils.ts';\n\ntype TypescriptOptionsWithDocgen = {\n  reactDocgen?: ReactDocgenConfig;\n  reactDocgenTypescriptOptions?: Record<string, unknown>;\n};\n\ninterface InternalGetArgTypesDataOptions extends GetArgTypesDataOptions {\n  presets?: Options['presets'];\n}\n\nexport const addons: PresetProperty<'addons'> = [\n  import.meta.resolve('@storybook/react-dom-shim/preset'),\n];\n\nexport { manifests as experimental_manifests } from './componentManifest/generator.ts';\n\nexport { enrichCsf as experimental_enrichCsf } from './enrichCsf.ts';\n\nexport const previewAnnotations: PresetProperty<'previewAnnotations'> = async (\n  input = [],\n  options\n) => {\n  const [docsConfig, features] = await Promise.all([\n    options.presets.apply('docs', {}, options),\n    options.presets.apply('features', {}, options),\n  ]);\n  const docsEnabled = Object.keys(docsConfig).length > 0;\n  const experimentalRSC = features?.experimentalRSC;\n  const result: string[] = [];\n\n  return result\n    .concat(input)\n    .concat([\n      fileURLToPath(import.meta.resolve('@storybook/react/entry-preview')),\n      fileURLToPath(import.meta.resolve('@storybook/react/entry-preview-argtypes')),\n    ])\n    .concat(\n      docsEnabled ? [fileURLToPath(import.meta.resolve('@storybook/react/entry-preview-docs'))] : []\n    )\n    .concat(\n      experimentalRSC\n        ? [fileURLToPath(import.meta.resolve('@storybook/react/entry-preview-rsc'))]\n        : []\n    );\n};\n\n// TODO: Evaluate if this is correct after removing pnp compatibility code in SB11\n\n/**\n * Try to resolve react and react-dom from the root node_modules of the project addon-docs uses this\n * to alias react and react-dom to the project's version when possible If the user doesn't have an\n * explicit dependency on react this will return the existing values Which will be the versions\n * shipped with addon-docs\n *\n * We do the exact same thing in the common preset, but that will fail in Yarn PnP because\n *\n * Storybook/internal/core-server doesn't have a peer dependency on react This will make\n *\n * @storybook/react projects work in Yarn PnP\n */\nexport const resolvedReact = async (existing: any) => {\n  try {\n    return {\n      ...existing,\n      react: resolvePackageDir('react'),\n      reactDom: resolvePackageDir('react-dom'),\n    };\n  } catch {\n    return existing;\n  }\n};\n\nexport async function internal_getArgTypesData(\n  _input: unknown,\n  options: InternalGetArgTypesDataOptions\n): Promise<ArgTypes | null> {\n  const { componentFilePath, componentExportName, presets } = (options ??\n    {}) as InternalGetArgTypesDataOptions;\n\n  if (!componentFilePath) {\n    return null;\n  }\n\n  // Get typescript options from presets to determine which docgen to use\n  let typescriptOptions: TypescriptOptionsWithDocgen = {};\n  if (presets) {\n    try {\n      const appliedOptions = await presets.apply('typescript', {});\n      typescriptOptions = appliedOptions as TypescriptOptionsWithDocgen;\n    } catch {\n      // If typescript preset is not available, use defaults\n    }\n  }\n\n  const { reactDocgen = 'react-docgen', reactDocgenTypescriptOptions } = typescriptOptions;\n\n  // If docgen is disabled, return null\n  if (reactDocgen === false) {\n    return null;\n  }\n\n  const resolvedFilePath = path.isAbsolute(componentFilePath)\n    ? componentFilePath\n    : join(getProjectRoot(), componentFilePath);\n\n  // Choose the appropriate extractor based on the reactDocgen option\n  let argTypesData;\n  if (reactDocgen === 'react-docgen-typescript') {\n    argTypesData = await extractArgTypesFromDocgenTypescript({\n      componentFilePath: resolvedFilePath,\n      componentExportName,\n      reactDocgenTypescriptOptions,\n    });\n  } else {\n    // Default to 'react-docgen'\n    argTypesData = extractArgTypesFromDocgen({\n      componentFilePath: resolvedFilePath,\n      componentExportName,\n    });\n  }\n\n  return argTypesData;\n}\n\nexport const optimizeViteDeps: string[] = ['react-dom/test-utils'];\n"
  },
  {
    "path": "code/renderers/react/src/preview.tsx",
    "content": "import type { ComponentType } from 'react';\n\nimport { definePreview as definePreviewBase } from 'storybook/internal/csf';\nimport type { AddonTypes, InferTypes, Meta, Preview, Story } from 'storybook/internal/csf';\nimport type { PreviewAddon } from 'storybook/internal/csf';\nimport type {\n  Args,\n  ArgsStoryFn,\n  ComponentAnnotations,\n  DecoratorFunction,\n  ProjectAnnotations,\n  Renderer,\n  StoryAnnotations,\n} from 'storybook/internal/types';\n\nimport type { RemoveIndexSignature, SetOptional, Simplify, UnionToIntersection } from 'type-fest';\n\nimport * as reactAnnotations from './entry-preview.tsx';\nimport * as reactArgTypesAnnotations from './entry-preview-argtypes.ts';\nimport * as reactDocsAnnotations from './entry-preview-docs.ts';\nimport type { AddMocks } from './public-types.ts';\nimport type { ReactTypes } from './types.ts';\n\n/** Extracts and unions all args types from an array of decorators. */\ntype DecoratorsArgs<TRenderer extends Renderer, Decorators> = UnionToIntersection<\n  Decorators extends DecoratorFunction<TRenderer, infer TArgs> ? TArgs : unknown\n>;\n\ntype InferArgs<TArgs, T, Decorators> = Simplify<\n  TArgs & Simplify<RemoveIndexSignature<DecoratorsArgs<ReactTypes & T, Decorators>>>\n>;\n\ntype InferReactTypes<T, TArgs, Decorators> = ReactTypes &\n  T & { args: Simplify<InferArgs<TArgs, T, Decorators>> };\n\n/**\n * Creates a React-specific preview configuration with CSF factories support.\n *\n * This function wraps the base `definePreview` and adds React-specific annotations for rendering\n * and documentation. It returns a `ReactPreview` that provides type-safe `meta()` and `story()`\n * factory methods.\n *\n * @example\n *\n * ```ts\n * // .storybook/preview.ts\n * import { definePreview } from '@storybook/react';\n *\n * export const preview = definePreview({\n *   addons: [],\n *   parameters: { layout: 'centered' },\n * });\n * ```\n */\nexport function __definePreview<Addons extends PreviewAddon<never>[]>(\n  input: { addons: Addons } & ProjectAnnotations<ReactTypes & InferTypes<Addons>>\n): ReactPreview<ReactTypes & InferTypes<Addons>> {\n  const preview = definePreviewBase({\n    ...input,\n    addons: [\n      reactAnnotations,\n      reactArgTypesAnnotations,\n      reactDocsAnnotations,\n      ...(input.addons ?? []),\n    ],\n  }) as unknown as ReactPreview<ReactTypes & InferTypes<Addons>>;\n\n  const defineMeta = preview.meta.bind(preview);\n  preview.meta = (_input) => {\n    const meta = defineMeta(_input);\n    const defineStory = meta.story.bind(meta);\n    // @ts-expect-error internal code that is hard to type\n    meta.story = (__input: any) => {\n      const story = defineStory(__input);\n      // TODO: [test-syntax] Are we sure we want this? the Component construct was for\n      // compatibility with raw portable stories. We don't actually use this in vitest.\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore this is a private property used only here\n      story.Component = story.__compose();\n      return story;\n    };\n    return meta;\n  };\n  return preview;\n}\n\n/**\n * React-specific Preview interface that provides type-safe CSF factory methods.\n *\n * Use `preview.meta()` to create a meta configuration for a component, and then `meta.story()` to\n * create individual stories. The type system will infer args from the component props, decorators,\n * and any addon types.\n *\n * @example\n *\n * ```ts\n * const meta = preview.meta({ component: Button });\n * export const Primary = meta.story({ args: { label: 'Click me' } });\n * ```\n */\n/** @ts-expect-error We cannot implement the meta faithfully here, but that is okay. */\nexport interface ReactPreview<T extends AddonTypes> extends Preview<ReactTypes & T> {\n  /**\n   * Narrows the type of the preview to include additional type information. This is useful when you\n   * need to add args that aren't inferred from the component.\n   *\n   * @example\n   *\n   * ```ts\n   * const meta = preview.type<{ args: { theme: 'light' | 'dark' } }>().meta({\n   *   component: Button,\n   * });\n   * ```\n   */\n  type<R>(): ReactPreview<T & R>;\n\n  meta<\n    TArgs extends Args,\n    Decorators extends DecoratorFunction<ReactTypes & T, any>,\n    // Try to make Exact<Partial<TArgs>, TMetaArgs> work\n    TMetaArgs extends Partial<TArgs & T['args']>,\n  >(\n    meta: {\n      render?: ArgsStoryFn<ReactTypes & T, TArgs & T['args']>;\n      component?: ComponentType<TArgs>;\n      decorators?: Decorators | Decorators[];\n      args?: TMetaArgs;\n    } & Omit<\n      ComponentAnnotations<ReactTypes & T, TArgs>,\n      'decorators' | 'component' | 'args' | 'render'\n    >\n  ): ReactMeta<\n    InferReactTypes<T, TArgs, Decorators>,\n    Omit<ComponentAnnotations<InferReactTypes<T, TArgs, Decorators>>, 'args'> & {\n      args: Partial<TArgs> extends TMetaArgs ? {} : TMetaArgs;\n    }\n  >;\n}\n\n/**\n * React-specific Meta interface returned by `preview.meta()`.\n *\n * Provides the `story()` method to create individual stories with proper type inference. Args\n * provided in meta become optional in stories, while missing required args must be provided at the\n * story level.\n */\nexport interface ReactMeta<T extends ReactTypes, MetaInput extends ComponentAnnotations<T>>\n  /** @ts-expect-error ReactMeta requires two type parameters, but Meta's constraints differ */\n  extends Meta<T, MetaInput> {\n  /**\n   * Creates a story with a custom render function that takes no args.\n   *\n   * This overload allows you to define a story using just a render function or an object with a\n   * render function that doesn't depend on args. Since the render function doesn't use args, no\n   * args need to be provided regardless of what's required by the component.\n   *\n   * @example\n   *\n   * ```ts\n   * // Using just a render function\n   * export const CustomRender = meta.story(() => <div>Custom content</div>);\n   *\n   * // Using an object with render\n   * export const WithRender = meta.story({\n   *   render: () => <MyComponent prop=\"static\" />,\n   * });\n   * ```\n   */\n  story<\n    TInput extends\n      | (() => ReactTypes['storyResult'])\n      | (StoryAnnotations<T, T['args']> & {\n          render: () => ReactTypes['storyResult'];\n        }),\n  >(\n    story: TInput\n  ): ReactStory<T, TInput extends () => ReactTypes['storyResult'] ? { render: TInput } : TInput>;\n\n  /**\n   * Creates a story with custom configuration including args, decorators, or other annotations.\n   *\n   * This is the primary overload for defining stories. Args that were already provided in meta\n   * become optional, while any remaining required args must be specified here.\n   *\n   * @example\n   *\n   * ```ts\n   * // Provide required args not in meta\n   * export const Primary = meta.story({\n   *   args: { label: 'Click me', disabled: false },\n   * });\n   *\n   * // Override meta args and add story-specific configuration\n   * export const Disabled = meta.story({\n   *   args: { disabled: true },\n   *   decorators: [withCustomWrapper],\n   * });\n   * ```\n   */\n  story<\n    TInput extends Simplify<\n      StoryAnnotations<\n        T,\n        // TODO: infer mocks from story itself as well\n        AddMocks<T['args'], MetaInput['args']>,\n        SetOptional<T['args'], keyof T['args'] & keyof MetaInput['args']>\n      >\n    >,\n  >(\n    story: TInput\n    /** @ts-expect-error hard */\n  ): ReactStory<T, TInput>;\n\n  /**\n   * Creates a story with no additional configuration.\n   *\n   * This overload is only available when all required args have been provided in meta. The\n   * conditional type `Partial<T['args']> extends SetOptional<...>` checks if the remaining required\n   * args (after accounting for args provided in meta) are all optional. If so, the function accepts\n   * zero arguments `[]`. Otherwise, it requires `[never]` which makes this overload unmatchable,\n   * forcing the user to provide args.\n   *\n   * @example\n   *\n   * ```ts\n   * // When meta provides all required args, story() can be called with no arguments\n   * const meta = preview.meta({ component: Button, args: { label: 'Hi', disabled: false } });\n   * export const Default = meta.story(); // Valid - all args provided in meta\n   * ```\n   */\n  story(\n    ..._args: Partial<T['args']> extends SetOptional<\n      T['args'],\n      keyof T['args'] & keyof MetaInput['args']\n    >\n      ? []\n      : [never]\n  ): ReactStory<T, {}>;\n}\n\n/**\n * React-specific Story interface returned by `meta.story()`.\n *\n * Represents a single story with its configuration and provides access to the composed story for\n * testing via `story.run()`.\n *\n * Also includes a `Component` property for portable story compatibility.\n */\nexport interface ReactStory<\n  T extends ReactTypes,\n  TInput extends StoryAnnotations<T, T['args']>,\n> extends Story<T, TInput> {\n  Component: ComponentType<Partial<T['args']>>;\n}\n"
  },
  {
    "path": "code/renderers/react/src/public-types.test.tsx",
    "content": "// @vitest-environment happy-dom\n// this file tests Typescript types that's why there are no assertions\nimport { describe, it } from 'vitest';\n\nimport type { KeyboardEventHandler, ReactElement, ReactNode } from 'react';\nimport React from 'react';\n\nimport { satisfies } from 'storybook/internal/common';\nimport type { Canvas } from 'storybook/internal/csf';\nimport type { Args, StoryAnnotations, StrictArgs } from 'storybook/internal/types';\n\nimport { expectTypeOf } from 'expect-type';\nimport { fn } from 'storybook/test';\nimport type { Mock } from 'storybook/test';\nimport type { SetOptional } from 'type-fest';\n\nimport type { Decorator, Meta, StoryObj } from './public-types.ts';\nimport type { ReactRenderer } from './types.ts';\n\ntype ReactStory<TArgs, TRequiredArgs> = StoryAnnotations<ReactRenderer, TArgs, TRequiredArgs>;\n\ntype ButtonProps = { label: string; disabled: boolean };\nconst Button: (props: ButtonProps) => ReactElement = () => <></>;\n\ndescribe('Args can be provided in multiple ways', () => {\n  it('✅ All required args may be provided in meta', () => {\n    const meta = satisfies<Meta<typeof Button>>()({\n      component: Button,\n      args: { label: 'good', disabled: false },\n    });\n\n    type Story = StoryObj<typeof meta>;\n    const Basic: Story = {};\n\n    expectTypeOf(Basic).toEqualTypeOf<\n      ReactStory<ButtonProps, SetOptional<ButtonProps, 'label' | 'disabled'>>\n    >();\n  });\n\n  it('✅ Required args may be provided partial in meta and the story', () => {\n    const meta = satisfies<Meta<typeof Button>>()({\n      component: Button,\n      args: { label: 'good' },\n    });\n    const Basic: StoryObj<typeof meta> = {\n      args: { disabled: false },\n    };\n\n    type Expected = ReactStory<ButtonProps, SetOptional<ButtonProps, 'label'>>;\n    expectTypeOf(Basic).toEqualTypeOf<Expected>();\n  });\n\n  it('❌ The combined shape of meta args and story args must match the required args.', () => {\n    {\n      const meta = satisfies<Meta<typeof Button>>()({ component: Button });\n      const Basic: StoryObj<typeof meta> = {\n        // @ts-expect-error disabled not provided ❌\n        args: { label: 'good' },\n      };\n\n      type Expected = ReactStory<ButtonProps, ButtonProps>;\n      expectTypeOf(Basic).toEqualTypeOf<Expected>();\n    }\n    {\n      const meta = satisfies<Meta<typeof Button>>()({\n        component: Button,\n        args: { label: 'good' },\n      });\n      // @ts-expect-error disabled not provided ❌\n      const Basic: StoryObj<typeof meta> = {};\n\n      type Expected = ReactStory<ButtonProps, SetOptional<ButtonProps, 'label'>>;\n      expectTypeOf(Basic).toEqualTypeOf<Expected>();\n    }\n    {\n      const meta = satisfies<Meta<ButtonProps>>()({ component: Button });\n      const Basic: StoryObj<typeof meta> = {\n        // @ts-expect-error disabled not provided ❌\n        args: { label: 'good' },\n      };\n\n      type Expected = ReactStory<ButtonProps, ButtonProps>;\n      expectTypeOf(Basic).toEqualTypeOf<Expected>();\n    }\n  });\n\n  it('Component can be used as generic parameter for StoryObj', () => {\n    type Expected = ReactStory<ButtonProps, Partial<ButtonProps>>;\n    expectTypeOf<StoryObj<typeof Button>>().toEqualTypeOf<Expected>();\n  });\n});\n\nit('✅ Void functions are not changed', () => {\n  interface CmpProps {\n    label: string;\n    disabled: boolean;\n    onClick(): void;\n    onKeyDown: KeyboardEventHandler;\n    onLoading: (s: string) => ReactElement;\n    submitAction(): void;\n  }\n\n  const Cmp: (props: CmpProps) => ReactElement = () => <></>;\n\n  const meta = satisfies<Meta<CmpProps>>()({\n    component: Cmp,\n    args: { label: 'good' },\n  });\n\n  const Basic: StoryObj<typeof meta> = {\n    args: {\n      disabled: false,\n      onLoading: () => <div>Loading...</div>,\n      onKeyDown: fn(),\n      onClick: fn(),\n      submitAction: fn(),\n    },\n  };\n\n  type Expected = ReactStory<CmpProps, SetOptional<CmpProps, 'label'>>;\n  expectTypeOf(Basic).toEqualTypeOf<Expected>();\n});\n\ntype ThemeData = 'light' | 'dark';\ndeclare const Theme: (props: { theme: ThemeData; children?: ReactNode }) => ReactElement;\n\ndescribe('Story args can be inferred', () => {\n  it('Correct args are inferred when type is widened for render function', () => {\n    type Props = ButtonProps & { theme: ThemeData };\n\n    const meta = satisfies<Meta<Props>>()({\n      component: Button,\n      args: { disabled: false },\n      render: (args, { component }) => {\n        // component is not null as it is provided in meta\n\n        const Component = component!;\n        return (\n          <Theme theme={args.theme}>\n            <Component {...args} />\n          </Theme>\n        );\n      },\n    });\n\n    const Basic: StoryObj<typeof meta> = { args: { theme: 'light', label: 'good' } };\n\n    type Expected = ReactStory<Props, SetOptional<Props, 'disabled'>>;\n    expectTypeOf(Basic).toEqualTypeOf<Expected>();\n  });\n\n  const withDecorator: Decorator<{ decoratorArg: number }> = (Story, { args }) => (\n    <>\n      Decorator: {args.decoratorArg}\n      <Story args={{ decoratorArg: 0 }} />\n    </>\n  );\n\n  it('Correct args are inferred when type is widened for decorators', () => {\n    type Props = ButtonProps & { decoratorArg: number };\n\n    const meta = satisfies<Meta<Props>>()({\n      component: Button,\n      args: { disabled: false },\n      decorators: [withDecorator],\n    });\n\n    const Basic: StoryObj<typeof meta> = { args: { decoratorArg: 0, label: 'good' } };\n\n    type Expected = ReactStory<Props, SetOptional<Props, 'disabled'>>;\n    expectTypeOf(Basic).toEqualTypeOf<Expected>();\n  });\n\n  it('Correct args are inferred when type is widened for multiple decorators', () => {\n    type Props = ButtonProps & { decoratorArg: number; decoratorArg2: string };\n\n    const secondDecorator: Decorator<{ decoratorArg2: string }> = (Story, { args }) => (\n      <>\n        Decorator: {args.decoratorArg2}\n        <Story />\n      </>\n    );\n\n    // decorator is not using args\n    const thirdDecorator: Decorator<Args> = (Story) => (\n      <>\n        <Story />\n      </>\n    );\n\n    // decorator is not using args\n    const fourthDecorator: Decorator<StrictArgs> = (Story) => (\n      <>\n        <Story />\n      </>\n    );\n\n    const meta = satisfies<Meta<Props>>()({\n      component: Button,\n      args: { disabled: false },\n      decorators: [withDecorator, secondDecorator, thirdDecorator, fourthDecorator],\n    });\n\n    const Basic: StoryObj<typeof meta> = {\n      args: { decoratorArg: 0, decoratorArg2: '', label: 'good' },\n    };\n\n    type Expected = ReactStory<Props, SetOptional<Props, 'disabled'>>;\n    expectTypeOf(Basic).toEqualTypeOf<Expected>();\n  });\n});\n\nit('StoryObj<typeof meta> is allowed when meta is upcasted to Meta<Props>', () => {\n  expectTypeOf<StoryObj<Meta<ButtonProps>>>().toEqualTypeOf<\n    ReactStory<ButtonProps, Partial<ButtonProps>>\n  >();\n});\n\nit('StoryObj<typeof meta> is allowed when meta is upcasted to Meta<typeof Cmp>', () => {\n  expectTypeOf<StoryObj<Meta<typeof Button>>>().toEqualTypeOf<\n    ReactStory<ButtonProps, Partial<ButtonProps>>\n  >();\n});\n\nit('StoryObj<typeof meta> is allowed when all arguments are optional', () => {\n  expectTypeOf<StoryObj<Meta<{ label?: string }>>>().toEqualTypeOf<\n    ReactStory<{ label?: string }, { label?: string }>\n  >();\n});\n\nit('Meta can be used without generic', () => {\n  expectTypeOf({ component: Button }).toMatchTypeOf<Meta>();\n});\n\nit('Props can be defined as interfaces, issue #21768', () => {\n  interface Props {\n    label: string;\n  }\n\n  const Component = ({ label }: Props) => <>{label}</>;\n\n  const withDecorator: Decorator = (Story) => (\n    <>\n      <Story />\n    </>\n  );\n\n  const meta = {\n    component: Component,\n    args: {\n      label: 'label',\n    },\n    decorators: [withDecorator],\n  } satisfies Meta<Props>;\n\n  const Basic: StoryObj<typeof meta> = {};\n\n  type Expected = ReactStory<Props, SetOptional<Props, 'label'>>;\n  expectTypeOf(Basic).toEqualTypeOf<Expected>();\n});\n\nit('Components without Props can be used, issue #21768', () => {\n  const Component = () => <>Foo</>;\n  const withDecorator: Decorator = (Story) => (\n    <>\n      <Story />\n    </>\n  );\n\n  const meta = {\n    component: Component,\n    decorators: [withDecorator],\n  } satisfies Meta<typeof Component>;\n\n  const Basic: StoryObj<typeof meta> = {};\n\n  type Expected = ReactStory<{}, {}>;\n  expectTypeOf(Basic).toEqualTypeOf<Expected>();\n});\n\nit('Meta is broken when using discriminating types, issue #23629', () => {\n  type TestButtonProps = {\n    text: string;\n  } & (\n    | {\n        id?: string;\n        onClick?: (e: unknown, id: string | undefined) => void;\n      }\n    | {\n        id: string;\n        onClick: (e: unknown, id: string) => void;\n      }\n  );\n  const TestButton: React.FC<TestButtonProps> = ({ text }) => {\n    return <p>{text}</p>;\n  };\n\n  expectTypeOf({\n    title: 'Components/Button',\n    component: TestButton,\n    args: {\n      text: 'Button',\n    },\n  }).toMatchTypeOf<Meta<TestButtonProps>>();\n});\n\nit('Infer mock function given to args in meta.', () => {\n  type Props = { label: string; onClick: () => void; onRender: () => JSX.Element };\n  const TestButton = (props: Props) => <></>;\n\n  const meta = {\n    component: TestButton,\n    args: { label: 'label', onClick: fn(), onRender: () => <>some jsx</> },\n  } satisfies Meta<typeof TestButton>;\n\n  type Story = StoryObj<typeof meta>;\n\n  const Basic: Story = {\n    play: async ({ args, mount }) => {\n      const canvas = await mount(<TestButton {...args} />);\n      expectTypeOf(canvas).toEqualTypeOf<Canvas>();\n      expectTypeOf(args.onClick).toEqualTypeOf<Mock>();\n      expectTypeOf(args.onRender).toEqualTypeOf<() => JSX.Element>();\n    },\n  };\n  type Expected = StoryAnnotations<ReactRenderer, Props & { onClick: Mock }, Partial<Props>>;\n\n  expectTypeOf(Basic).toEqualTypeOf<Expected>();\n});\n"
  },
  {
    "path": "code/renderers/react/src/public-types.ts",
    "content": "import type { ComponentProps, ComponentType } from 'react';\n\nimport type {\n  AnnotatedStoryFn,\n  Args,\n  ArgsFromMeta,\n  ArgsStoryFn,\n  ComponentAnnotations,\n  DecoratorFunction,\n  StoryContext as GenericStoryContext,\n  LoaderFunction,\n  ProjectAnnotations,\n  StoryAnnotations,\n  StrictArgs,\n} from 'storybook/internal/types';\n\nimport type { SetOptional, Simplify } from 'type-fest';\n\nimport type { ReactRenderer } from './types.ts';\n\nexport type { Args, ArgTypes, Parameters, StrictArgs } from 'storybook/internal/types';\nexport type { ReactRenderer };\n\n/**\n * Metadata to configure the stories for a component.\n *\n * @see [Default export](https://storybook.js.org/docs/api/csf#default-export)\n */\nexport type Meta<TCmpOrArgs = Args> = [TCmpOrArgs] extends [ComponentType<any>]\n  ? ComponentAnnotations<ReactRenderer, ComponentProps<TCmpOrArgs>>\n  : ComponentAnnotations<ReactRenderer, TCmpOrArgs>;\n\n/**\n * Story function that represents a CSFv2 component example.\n *\n * @see [Named Story exports](https://storybook.js.org/docs/api/csf#named-story-exports)\n */\nexport type StoryFn<TCmpOrArgs = Args> = [TCmpOrArgs] extends [ComponentType<any>]\n  ? AnnotatedStoryFn<ReactRenderer, ComponentProps<TCmpOrArgs>>\n  : AnnotatedStoryFn<ReactRenderer, TCmpOrArgs>;\n\n/**\n * Story object that represents a CSFv3 component example.\n *\n * @see [Named Story exports](https://storybook.js.org/docs/api/csf#named-story-exports)\n */\nexport type StoryObj<TMetaOrCmpOrArgs = Args> = [TMetaOrCmpOrArgs] extends [\n  {\n    render?: ArgsStoryFn<ReactRenderer, any>;\n    component?: infer Component;\n    args?: infer DefaultArgs;\n  },\n]\n  ? Simplify<\n      (Component extends ComponentType<any> ? ComponentProps<Component> : unknown) &\n        ArgsFromMeta<ReactRenderer, TMetaOrCmpOrArgs>\n    > extends infer TArgs\n    ? StoryAnnotations<\n        ReactRenderer,\n        AddMocks<TArgs, DefaultArgs>,\n        SetOptional<TArgs, keyof TArgs & keyof DefaultArgs>\n      >\n    : never\n  : TMetaOrCmpOrArgs extends ComponentType<any>\n    ? StoryAnnotations<ReactRenderer, ComponentProps<TMetaOrCmpOrArgs>>\n    : StoryAnnotations<ReactRenderer, TMetaOrCmpOrArgs>;\n\n// This performs a downcast to function types that are mocks, when a mock fn is given to meta args.\nexport type AddMocks<TArgs, DefaultArgs> = Simplify<{\n  [T in keyof TArgs]: T extends keyof DefaultArgs\n    ? DefaultArgs[T] extends (...args: any) => any & { mock: {} } // allow any function with a mock object\n      ? DefaultArgs[T]\n      : TArgs[T]\n    : TArgs[T];\n}>;\n\nexport type Decorator<TArgs = StrictArgs> = DecoratorFunction<ReactRenderer, TArgs>;\nexport type Loader<TArgs = StrictArgs> = LoaderFunction<ReactRenderer, TArgs>;\nexport type StoryContext<TArgs = StrictArgs> = GenericStoryContext<ReactRenderer, TArgs>;\nexport type Preview = ProjectAnnotations<ReactRenderer>;\n"
  },
  {
    "path": "code/renderers/react/src/render.tsx",
    "content": "import React from 'react';\n\nimport type { ArgsStoryFn } from 'storybook/internal/types';\n\nimport type { ReactRenderer } from './types.ts';\n\nexport const render: ArgsStoryFn<ReactRenderer> = (args, context) => {\n  const { id, component: Component } = context;\n  if (!Component) {\n    throw new Error(\n      `Unable to render story ${id} as the component annotation is missing from the default export`\n    );\n  }\n\n  return <Component {...args} />;\n};\n"
  },
  {
    "path": "code/renderers/react/src/renderToCanvas.tsx",
    "content": "import type { FC } from 'react';\nimport React, { Fragment, Component as ReactComponent, StrictMode } from 'react';\n\nimport type { RenderContext } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { getAct } from './act-compat.ts';\nimport type { ReactRenderer, StoryContext } from './types.ts';\n\nconst { FRAMEWORK_OPTIONS } = global;\n\nclass ErrorBoundary extends ReactComponent<{\n  showException: (err: Error) => void;\n  showMain: () => void;\n  children?: React.ReactNode;\n}> {\n  state = { hasError: false };\n\n  static getDerivedStateFromError() {\n    return { hasError: true };\n  }\n\n  componentDidMount() {\n    const { hasError } = this.state;\n    const { showMain } = this.props;\n    if (!hasError) {\n      showMain();\n    }\n  }\n\n  componentDidCatch(err: Error) {\n    const { showException } = this.props;\n    // message partially duplicates stack, strip it\n    showException(err);\n  }\n\n  render() {\n    const { hasError } = this.state;\n    const { children } = this.props;\n\n    return hasError ? null : children;\n  }\n}\n\nconst Wrapper = FRAMEWORK_OPTIONS?.strictMode ? StrictMode : Fragment;\n\nconst actQueue: (() => Promise<void>)[] = [];\nlet isActing = false;\n\nconst processActQueue = async () => {\n  if (isActing || actQueue.length === 0) {\n    return;\n  }\n\n  isActing = true;\n  const actTask = actQueue.shift();\n  if (actTask) {\n    await actTask();\n  }\n  isActing = false;\n  processActQueue();\n};\n\nexport async function renderToCanvas(\n  {\n    storyContext,\n    unboundStoryFn,\n    showMain,\n    showException,\n    forceRemount,\n  }: RenderContext<ReactRenderer>,\n  canvasElement: ReactRenderer['canvasElement']\n) {\n  const { renderElement, unmountElement } = await import('@storybook/react-dom-shim');\n  const Story = unboundStoryFn as FC<StoryContext<ReactRenderer>>;\n\n  const isPortableStory = storyContext.parameters.__isPortableStory;\n\n  const content = isPortableStory ? (\n    <Story {...storyContext} />\n  ) : (\n    <ErrorBoundary key={storyContext.id} showMain={showMain} showException={showException}>\n      <Story {...storyContext} />\n    </ErrorBoundary>\n  );\n\n  // For React 15, StrictMode & Fragment doesn't exists.\n  const element = Wrapper ? <Wrapper>{content}</Wrapper> : content;\n\n  // In most cases, we need to unmount the existing set of components in the DOM node.\n  // Otherwise, React may not recreate instances for every story run.\n  // This could leads to issues like below:\n  // https://github.com/storybookjs/react-storybook/issues/81\n  // (This is not the case when we change args or globals to the story however)\n  if (forceRemount) {\n    unmountElement(canvasElement);\n  }\n\n  // Disable act in docs, see:\n  // https://github.com/storybookjs/storybook/issues/30356\n  const act = await getAct({ disableAct: storyContext.viewMode === 'docs' });\n  await new Promise<void>(async (resolve, reject) => {\n    actQueue.push(async () => {\n      try {\n        await act(async () => {\n          await renderElement(element, canvasElement, storyContext?.parameters?.react?.rootOptions);\n        });\n        resolve();\n      } catch (e) {\n        reject(e);\n      }\n    });\n    processActQueue();\n  });\n\n  return async () => {\n    await act(() => {\n      unmountElement(canvasElement);\n    });\n  };\n}\n"
  },
  {
    "path": "code/renderers/react/src/types.ts",
    "content": "import type { ComponentType, JSX } from 'react';\nimport type { RootOptions } from 'react-dom/client';\n\nimport type { Canvas, WebRenderer } from 'storybook/internal/types';\n\nexport type { RenderContext, StoryContext } from 'storybook/internal/types';\n\nexport interface ReactRenderer extends WebRenderer {\n  component: ComponentType<this['T']>;\n  storyResult: StoryFnReactReturnType;\n  mount: (ui?: JSX.Element) => Promise<Canvas>;\n}\n\nexport interface ShowErrorArgs {\n  title: string;\n  description: string;\n}\n\nexport interface ReactParameters {\n  /** React renderer configuration */\n  react?: {\n    /**\n     * Whether to enable React Server Components\n     *\n     * @see https://storybook.js.org/docs/get-started/frameworks/nextjs#react-server-components-rsc\n     */\n    rsc?: boolean;\n    /** Options passed to React root creation */\n    rootOptions?: RootOptions;\n  };\n}\n\nexport interface ReactTypes extends ReactRenderer {\n  parameters: ReactParameters;\n}\n\nexport type StoryFnReactReturnType = JSX.Element;\n"
  },
  {
    "path": "code/renderers/react/src/typings.d.ts",
    "content": "declare var STORYBOOK_ENV: 'react';\ndeclare var FRAMEWORK_OPTIONS: any;\ndeclare var LOGLEVEL: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent' | undefined;\ndeclare var FEATURES: import('storybook/internal/types').StorybookConfigRaw['features'];\n"
  },
  {
    "path": "code/renderers/react/template/cli/.eslintrc.json",
    "content": "{\n  \"rules\": {\n    \"import/extensions\": \"off\"\n  }\n}\n"
  },
  {
    "path": "code/renderers/react/template/cli/js/Button.jsx",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nimport './button.css';\n\n/** Primary UI component for user interaction */\nexport const Button = ({\n  primary = false,\n  backgroundColor = null,\n  size = 'medium',\n  label,\n  ...props\n}) => {\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n  return (\n    <button\n      type=\"button\"\n      className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n      style={backgroundColor && { backgroundColor }}\n      {...props}\n    >\n      {label}\n    </button>\n  );\n};\n\nButton.propTypes = {\n  /** Is this the principal call to action on the page? */\n  primary: PropTypes.bool,\n  /** What background color to use */\n  backgroundColor: PropTypes.string,\n  /** How large should the button be? */\n  size: PropTypes.oneOf(['small', 'medium', 'large']),\n  /** Button contents */\n  label: PropTypes.string.isRequired,\n  /** Optional click handler */\n  onClick: PropTypes.func,\n};\n"
  },
  {
    "path": "code/renderers/react/template/cli/js/Button.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport { Button } from './Button';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export\nexport default {\n  title: 'Example/Button',\n  component: Button,\n  parameters: {\n    // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout\n    layout: 'centered',\n  },\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  // More on argTypes: https://storybook.js.org/docs/api/argtypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onClick: fn() },\n};\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/renderers/react/template/cli/js/Header.jsx",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nimport { Button } from './Button';\nimport './header.css';\n\nexport const Header = ({ user = null, onLogin, onLogout, onCreateAccount }) => (\n  <header>\n    <div className=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        {user ? (\n          <>\n            <span className=\"welcome\">\n              Welcome, <b>{user.name}</b>!\n            </span>\n            <Button size=\"small\" onClick={onLogout} label=\"Log out\" />\n          </>\n        ) : (\n          <>\n            <Button size=\"small\" onClick={onLogin} label=\"Log in\" />\n            <Button primary size=\"small\" onClick={onCreateAccount} label=\"Sign up\" />\n          </>\n        )}\n      </div>\n    </div>\n  </header>\n);\n\nHeader.propTypes = {\n  user: PropTypes.shape({\n    name: PropTypes.string.isRequired,\n  }),\n  onLogin: PropTypes.func.isRequired,\n  onLogout: PropTypes.func.isRequired,\n  onCreateAccount: PropTypes.func.isRequired,\n};\n"
  },
  {
    "path": "code/renderers/react/template/cli/js/Header.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport { Header } from './Header';\n\nexport default {\n  title: 'Example/Header',\n  component: Header,\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n};\n\nexport const LoggedIn = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut = {};\n"
  },
  {
    "path": "code/renderers/react/template/cli/js/Page.jsx",
    "content": "import React from 'react';\n\nimport { Header } from './Header';\nimport './page.css';\n\nexport const Page = () => {\n  const [user, setUser] = React.useState();\n\n  return (\n    <article>\n      <Header\n        user={user}\n        onLogin={() => setUser({ name: 'Jane Doe' })}\n        onLogout={() => setUser(undefined)}\n        onCreateAccount={() => setUser({ name: 'Jane Doe' })}\n      />\n\n      <section className=\"storybook-page\">\n        <h2>Pages in Storybook</h2>\n        <p>\n          We recommend building UIs with a{' '}\n          <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n            <strong>component-driven</strong>\n          </a>{' '}\n          process starting with atomic components and ending with pages.\n        </p>\n        <p>\n          Render pages with mock data. This makes it easy to build and review page states without\n          needing to navigate to them in your app. Here are some handy patterns for managing page\n          data in Storybook:\n        </p>\n        <ul>\n          <li>\n            Use a higher-level connected component. Storybook helps you compose such data from the\n            \"args\" of child component stories\n          </li>\n          <li>\n            Assemble data in the page component from your services. You can mock these services out\n            using Storybook.\n          </li>\n        </ul>\n        <p>\n          Get a guided tutorial on component-driven development at{' '}\n          <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n            Storybook tutorials\n          </a>\n          . Read more in the{' '}\n          <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">\n            docs\n          </a>\n          .\n        </p>\n        <div className=\"tip-wrapper\">\n          <span className=\"tip\">Tip</span> Adjust the width of the canvas with the{' '}\n          <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n            <g fill=\"none\" fillRule=\"evenodd\">\n              <path\n                d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n                id=\"a\"\n                fill=\"#999\"\n              />\n            </g>\n          </svg>\n          Viewports addon in the toolbar\n        </div>\n      </section>\n    </article>\n  );\n};\n"
  },
  {
    "path": "code/renderers/react/template/cli/js/Page.stories.js",
    "content": "import { expect, userEvent, within } from 'storybook/test';\n\nimport { Page } from './Page';\n\nexport default {\n  title: 'Example/Page',\n  component: Page,\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n};\n\nexport const LoggedOut = {};\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await expect(loginButton).not.toBeInTheDocument();\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n"
  },
  {
    "path": "code/renderers/react/template/cli/ts/Button.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/react';\n\nimport { fn } from 'storybook/test';\n\nimport { Button } from './Button';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export\nconst meta = {\n  title: 'Example/Button',\n  component: Button,\n  parameters: {\n    // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout\n    layout: 'centered',\n  },\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  // More on argTypes: https://storybook.js.org/docs/api/argtypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onClick: fn() },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large: Story = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small: Story = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/renderers/react/template/cli/ts/Button.tsx",
    "content": "import React from 'react';\n\nimport './button.css';\n\nexport interface ButtonProps {\n  /** Is this the principal call to action on the page? */\n  primary?: boolean;\n  /** What background color to use */\n  backgroundColor?: string;\n  /** How large should the button be? */\n  size?: 'small' | 'medium' | 'large';\n  /** Button contents */\n  label: string;\n  /** Optional click handler */\n  onClick?: () => void;\n}\n\n/** Primary UI component for user interaction */\nexport const Button = ({\n  primary = false,\n  size = 'medium',\n  backgroundColor,\n  label,\n  ...props\n}: ButtonProps) => {\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n  return (\n    <button\n      type=\"button\"\n      className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n      style={{ backgroundColor }}\n      {...props}\n    >\n      {label}\n    </button>\n  );\n};\n"
  },
  {
    "path": "code/renderers/react/template/cli/ts/Header.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/react';\n\nimport { fn } from 'storybook/test';\n\nimport { Header } from './Header';\n\nconst meta = {\n  title: 'Example/Header',\n  component: Header,\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n} satisfies Meta<typeof Header>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const LoggedIn: Story = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut: Story = {};\n"
  },
  {
    "path": "code/renderers/react/template/cli/ts/Header.tsx",
    "content": "import React from 'react';\n\nimport { Button } from './Button';\nimport './header.css';\n\ntype User = {\n  name: string;\n};\n\nexport interface HeaderProps {\n  user?: User;\n  onLogin?: () => void;\n  onLogout?: () => void;\n  onCreateAccount?: () => void;\n}\n\nexport const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => (\n  <header>\n    <div className=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        {user ? (\n          <>\n            <span className=\"welcome\">\n              Welcome, <b>{user.name}</b>!\n            </span>\n            <Button size=\"small\" onClick={onLogout} label=\"Log out\" />\n          </>\n        ) : (\n          <>\n            <Button size=\"small\" onClick={onLogin} label=\"Log in\" />\n            <Button primary size=\"small\" onClick={onCreateAccount} label=\"Sign up\" />\n          </>\n        )}\n      </div>\n    </div>\n  </header>\n);\n"
  },
  {
    "path": "code/renderers/react/template/cli/ts/Page.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/react';\n\nimport { expect, userEvent, within } from 'storybook/test';\n\nimport { Page } from './Page';\n\nconst meta = {\n  title: 'Example/Page',\n  component: Page,\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n} satisfies Meta<typeof Page>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const LoggedOut: Story = {};\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn: Story = {\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await expect(loginButton).not.toBeInTheDocument();\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n"
  },
  {
    "path": "code/renderers/react/template/cli/ts/Page.tsx",
    "content": "import React from 'react';\n\nimport { Header } from './Header';\nimport './page.css';\n\ntype User = {\n  name: string;\n};\n\nexport const Page: React.FC = () => {\n  const [user, setUser] = React.useState<User>();\n\n  return (\n    <article>\n      <Header\n        user={user}\n        onLogin={() => setUser({ name: 'Jane Doe' })}\n        onLogout={() => setUser(undefined)}\n        onCreateAccount={() => setUser({ name: 'Jane Doe' })}\n      />\n\n      <section className=\"storybook-page\">\n        <h2>Pages in Storybook</h2>\n        <p>\n          We recommend building UIs with a{' '}\n          <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n            <strong>component-driven</strong>\n          </a>{' '}\n          process starting with atomic components and ending with pages.\n        </p>\n        <p>\n          Render pages with mock data. This makes it easy to build and review page states without\n          needing to navigate to them in your app. Here are some handy patterns for managing page\n          data in Storybook:\n        </p>\n        <ul>\n          <li>\n            Use a higher-level connected component. Storybook helps you compose such data from the\n            \"args\" of child component stories\n          </li>\n          <li>\n            Assemble data in the page component from your services. You can mock these services out\n            using Storybook.\n          </li>\n        </ul>\n        <p>\n          Get a guided tutorial on component-driven development at{' '}\n          <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n            Storybook tutorials\n          </a>\n          . Read more in the{' '}\n          <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">\n            docs\n          </a>\n          .\n        </p>\n        <div className=\"tip-wrapper\">\n          <span className=\"tip\">Tip</span> Adjust the width of the canvas with the{' '}\n          <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n            <g fill=\"none\" fillRule=\"evenodd\">\n              <path\n                d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n                id=\"a\"\n                fill=\"#999\"\n              />\n            </g>\n          </svg>\n          Viewports addon in the toolbar\n        </div>\n      </section>\n    </article>\n  );\n};\n"
  },
  {
    "path": "code/renderers/react/template/components/Button.jsx",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nexport const Button = ({ onClick = () => {}, label = '' }) => (\n  <button type=\"button\" onClick={onClick}>\n    {label}\n  </button>\n);\n\nButton.propTypes = {\n  onClick: PropTypes.func,\n  label: PropTypes.string,\n};\n"
  },
  {
    "path": "code/renderers/react/template/components/Form.jsx",
    "content": "import React, { useState } from 'react';\n\nimport PropTypes from 'prop-types';\n\nexport const Form = ({ onSuccess }) => {\n  const [value, setValue] = useState('');\n  const [complete, setComplete] = useState(false);\n\n  function onSubmit(event) {\n    event.preventDefault();\n    onSuccess(value);\n\n    setTimeout(() => setComplete(true), 500);\n    setTimeout(() => setComplete(false), 1500);\n  }\n\n  return (\n    <form id=\"interaction-test-form\" onSubmit={onSubmit}>\n      <label>\n        Enter Value\n        <input\n          type=\"text\"\n          data-testid=\"value\"\n          value={value}\n          required\n          onChange={(event) => setValue(event.target.value)}\n        />\n      </label>\n      <button type=\"submit\">Submit</button>\n      {complete && <p>Completed!!</p>}\n    </form>\n  );\n};\n\nForm.propTypes = {\n  onSuccess: PropTypes.func.isRequired,\n};\n"
  },
  {
    "path": "code/renderers/react/template/components/Html.jsx",
    "content": "import PropTypes from 'prop-types';\n\nexport const Html = ({ content }) => <div dangerouslySetInnerHTML={{ __html: content }} />;\n\nHtml.propTypes = {\n  content: PropTypes.string.isRequired,\n};\n"
  },
  {
    "path": "code/renderers/react/template/components/Pre.jsx",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nexport const Pre = ({ style = {}, object = null, text = '' }) => (\n  <pre style={style} data-testid=\"pre\">\n    {object ? JSON.stringify(object, null, 2) : text}\n  </pre>\n);\n\nPre.propTypes = {\n  style: PropTypes.shape({}),\n  object: PropTypes.shape({}),\n  text: PropTypes.string,\n};\n"
  },
  {
    "path": "code/renderers/react/template/components/index.js",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { Button } from './Button.jsx';\nimport { Form } from './Form.jsx';\nimport { Html } from './Html.jsx';\nimport { Pre } from './Pre.jsx';\n\nglobalThis.__TEMPLATE_COMPONENTS__ = { Button, Pre, Form, Html };\nglobalThis.storybookRenderer = 'react';\n"
  },
  {
    "path": "code/renderers/react/template/stories/csf1.stories.tsx",
    "content": "import React from 'react';\n\nexport default {\n  component: {},\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const Hello1 = () => <div>Hello1</div>;\nexport const Hello2 = () => <div>Hello2</div>;\n"
  },
  {
    "path": "code/renderers/react/template/stories/csf2.stories.tsx",
    "content": "import React from 'react';\n\nexport default {\n  component: {},\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nconst Template = ({ label }: { label: string }) => <div>{label}</div>;\nTemplate.args = { label: 'Hello' };\n\nexport const Hello1 = Template.bind({});\n\nexport const Hello2 = Template.bind({});\n\nexport const Hello3 = Template.bind({});\n"
  },
  {
    "path": "code/renderers/react/template/stories/csf4.mdx",
    "content": "import * as StoriesModule from './csf4.stories'\nimport { Meta, Stories } from '@storybook/addon-docs/blocks'\n\n<Meta of={StoriesModule} />\n\n# CSF4 in MDX\n\n<Stories />"
  },
  {
    "path": "code/renderers/react/template/stories/csf4.stories.tsx",
    "content": "// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- we can't expect error as it is an error in development but it isn't sandbox\n// @ts-ignore only present in sandbox\nimport preview from '#.storybook/preview';\n\nconst meta = preview.meta({\n  // @ts-expect-error fix globalThis.__TEMPLATE_COMPONENTS__ type not existing later\n  component: globalThis.__TEMPLATE_COMPONENTS__.Button,\n  args: {\n    label: 'Hello world!',\n  },\n});\n\nexport const Story = meta.story({});\n"
  },
  {
    "path": "code/renderers/react/template/stories/decorators.stories.tsx",
    "content": "import type { FC } from 'react';\nimport React, { createContext, useContext, useState } from 'react';\n\nimport type { Meta, StoryObj } from '@storybook/react';\n\nimport { useParameter } from 'storybook/preview-api';\n\nconst Component: FC = () => <p>Story</p>;\n\nexport default {\n  component: Component,\n  tags: ['autodocs'],\n  decorators: [\n    (Story) => (\n      <>\n        <p>Component Decorator</p>\n        <Story />\n      </>\n    ),\n  ],\n} as Meta<typeof Component>;\n\nexport const All: StoryObj<typeof Component> = {\n  decorators: [\n    (Story) => (\n      <>\n        <p>Local Decorator</p>\n        <Story />\n      </>\n    ),\n  ],\n};\n\n// This story should not error\n// See https://github.com/storybookjs/storybook/issues/21900\nconst TestContext = createContext<boolean>(false);\nexport const Context: StoryObj<typeof Component> = {\n  parameters: { docs: { source: { excludeDecorators: true } } },\n  decorators: [\n    (Story) => (\n      <TestContext.Provider value>\n        <Story />\n      </TestContext.Provider>\n    ),\n  ],\n  render: function Render() {\n    const value = useContext(TestContext);\n\n    if (!value) {\n      throw new Error('TestContext not set, decorator did not run!');\n    }\n    return <p>Story</p>;\n  },\n};\n\n/**\n * This story demonstrates is a regression test for this issue with React hooks in Storybook\n * (https://github.com/storybookjs/storybook/issues/29189)\n *\n * Which happened when a decorator was using storybook hooks, and the render react hooks.\n */\nexport const AllowUseStateInRender: StoryObj = {\n  render: () => {\n    const [count, setCount] = useState(0);\n    const Button = (globalThis as any).__TEMPLATE_COMPONENTS__.Button;\n    return <Button onClick={() => setCount(count + 1)} label={`Clicked ${count} times`} />;\n  },\n  decorators: [\n    (storyFn) => {\n      useParameter('docs', {});\n      return storyFn();\n    },\n  ],\n  play: async ({ canvas, userEvent }) => {\n    const button = await canvas.findByText('Clicked 0 times');\n    await userEvent.click(button);\n    await canvas.findByText('Clicked 1 times');\n  },\n  tags: ['!vitest'],\n};\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/10017-ts-union/argTypes.snapshot",
    "content": "{\n  \"icon\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": \"Specify icon=\"search\" or icon={IconComponent}\",\n    \"name\": \"icon\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"union\",\n      },\n    },\n    \"type\": {\n      \"name\": \"union\",\n      \"raw\": \"React.ReactNode | string\",\n      \"required\": true,\n      \"value\": [\n        {\n          \"name\": \"other\",\n          \"raw\": \"React.ReactNode\",\n          \"value\": \"ReactReactNode\",\n        },\n        {\n          \"name\": \"string\",\n        },\n      ],\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/10017-ts-union/docgen.snapshot",
    "content": "import React from 'react';\nconst Avatar = ({\n  icon\n}) => {\n  return /*#__PURE__*/React.createElement(\"div\", {\n    className: \"hello\"\n  }, \"Hello Component \", icon);\n};\nexport const component = Avatar;\nAvatar.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"Avatar\",\n  \"props\": {\n    \"icon\": {\n      \"required\": true,\n      \"tsType\": {\n        \"name\": \"union\",\n        \"raw\": \"React.ReactNode | string\",\n        \"elements\": [{\n          \"name\": \"ReactReactNode\",\n          \"raw\": \"React.ReactNode\"\n        }, {\n          \"name\": \"string\"\n        }]\n      },\n      \"description\": \"Specify icon=\\\"search\\\" or icon={IconComponent}\"\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/10017-ts-union/input.tsx",
    "content": "import React from 'react';\n\ninterface AvatarProps {\n  /** Specify icon=\"search\" or icon={IconComponent} */\n  icon: React.ReactNode | string;\n}\n\nconst Avatar = ({ icon }: AvatarProps) => {\n  return <div className=\"hello\">Hello Component {icon}</div>;\n};\n\nexport const component = Avatar;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/10017-ts-union/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": null,\n      \"description\": \"Specify icon=\"search\" or icon={IconComponent}\",\n      \"name\": \"icon\",\n      \"required\": true,\n      \"sbType\": {\n        \"name\": \"union\",\n        \"raw\": \"React.ReactNode | string\",\n        \"value\": [\n          {\n            \"name\": \"other\",\n            \"raw\": \"React.ReactNode\",\n            \"value\": \"ReactReactNode\",\n          },\n          {\n            \"name\": \"string\",\n          },\n        ],\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"union\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/10278-ts-multiple-components/argTypes.snapshot",
    "content": "{\n  \"aProperty\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"aProperty\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"any\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": true,\n      \"value\": \"any\",\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/10278-ts-multiple-components/docgen.snapshot",
    "content": "/* eslint-disable react/destructuring-assignment */\nimport React from 'react';\n/** A component */\nconst A = props => {\n  return /*#__PURE__*/React.createElement(React.Fragment, null, \"Hi \", props.aProperty);\n};\n\n/** B component */\nconst B = props => {\n  return /*#__PURE__*/React.createElement(React.Fragment, null, \"Hi \", props.bProperty);\n};\nA.__docgenInfo = {\n  \"description\": \"A component\",\n  \"methods\": [],\n  \"displayName\": \"A\",\n  \"props\": {\n    \"aProperty\": {\n      \"required\": true,\n      \"tsType\": {\n        \"name\": \"any\"\n      },\n      \"description\": \"\"\n    }\n  }\n};\nB.__docgenInfo = {\n  \"description\": \"B component\",\n  \"methods\": [],\n  \"displayName\": \"B\",\n  \"props\": {\n    \"bProperty\": {\n      \"required\": true,\n      \"tsType\": {\n        \"name\": \"any\"\n      },\n      \"description\": \"\"\n    }\n  }\n};\nexport { A, B };\nexport const component = A;"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/10278-ts-multiple-components/input.tsx",
    "content": "/* eslint-disable react/destructuring-assignment */\nimport React from 'react';\n\ninterface IAProps {\n  aProperty: any;\n}\n\ninterface IBProps {\n  bProperty: any;\n}\n\n/** A component */\nconst A = (props: IAProps): React.JSX.Element => {\n  return <>Hi {props.aProperty}</>;\n};\n\n/** B component */\nconst B = (props: IBProps): React.JSX.Element => {\n  return <>Hi {props.bProperty}</>;\n};\n\nexport { A, B };\nexport const component = A;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/10278-ts-multiple-components/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"aProperty\",\n      \"required\": true,\n      \"sbType\": {\n        \"name\": \"other\",\n        \"value\": \"any\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"any\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8140-js-prop-types-oneof/argTypes.snapshot",
    "content": "{\n  \"blank\": {\n    \"control\": {\n      \"type\": \"boolean\",\n    },\n    \"description\": \"No background or border if static alert\",\n    \"name\": \"blank\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"bool\",\n      },\n    },\n    \"type\": {\n      \"name\": \"boolean\",\n      \"required\": false,\n    },\n  },\n  \"icon\": {\n    \"control\": {\n      \"type\": \"text\",\n    },\n    \"description\": \"Allows icon override, accepts material icon name\",\n    \"name\": \"icon\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"message\": {\n    \"control\": {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"message\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"string\",\n      \"required\": true,\n    },\n  },\n  \"mode\": {\n    \"control\": {\n      \"type\": \"radio\",\n    },\n    \"description\": \"\",\n    \"name\": \"mode\",\n    \"options\": [\n      \"static\",\n      \"timed\",\n    ],\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'static'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"'static' | 'timed'\",\n      },\n    },\n    \"type\": {\n      \"name\": \"enum\",\n      \"required\": false,\n      \"value\": [\n        \"static\",\n        \"timed\",\n      ],\n    },\n  },\n  \"type\": {\n    \"control\": {\n      \"type\": \"radio\",\n    },\n    \"description\": \"\",\n    \"name\": \"type\",\n    \"options\": [\n      \"success\",\n      \"warning\",\n      \"error\",\n      \"primary\",\n    ],\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'warning'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"'success' | 'warning' | 'error' | 'primary'\",\n      },\n    },\n    \"type\": {\n      \"name\": \"enum\",\n      \"required\": false,\n      \"value\": [\n        \"success\",\n        \"warning\",\n        \"error\",\n        \"primary\",\n      ],\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8140-js-prop-types-oneof/docgen.snapshot",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nconst Alert = props => /*#__PURE__*/React.createElement(React.Fragment, null, JSON.stringify(props));\nAlert.defaultProps = {\n  mode: 'static',\n  type: 'warning'\n};\nAlert.propTypes = {\n  mode: PropTypes.oneOf(['static', 'timed']),\n  type: PropTypes.oneOf(['success', 'warning', 'error', 'primary']),\n  message: PropTypes.string.isRequired,\n  /** No background or border if static alert */\n  blank: PropTypes.bool,\n  /** Allows icon override, accepts material icon name */\n  icon: PropTypes.string\n};\nexport const component = Alert;\nAlert.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"Alert\",\n  \"props\": {\n    \"mode\": {\n      \"defaultValue\": {\n        \"value\": \"'static'\",\n        \"computed\": false\n      },\n      \"description\": \"\",\n      \"type\": {\n        \"name\": \"enum\",\n        \"value\": [{\n          \"value\": \"'static'\",\n          \"computed\": false\n        }, {\n          \"value\": \"'timed'\",\n          \"computed\": false\n        }]\n      },\n      \"required\": false\n    },\n    \"type\": {\n      \"defaultValue\": {\n        \"value\": \"'warning'\",\n        \"computed\": false\n      },\n      \"description\": \"\",\n      \"type\": {\n        \"name\": \"enum\",\n        \"value\": [{\n          \"value\": \"'success'\",\n          \"computed\": false\n        }, {\n          \"value\": \"'warning'\",\n          \"computed\": false\n        }, {\n          \"value\": \"'error'\",\n          \"computed\": false\n        }, {\n          \"value\": \"'primary'\",\n          \"computed\": false\n        }]\n      },\n      \"required\": false\n    },\n    \"message\": {\n      \"description\": \"\",\n      \"type\": {\n        \"name\": \"string\"\n      },\n      \"required\": true\n    },\n    \"blank\": {\n      \"description\": \"No background or border if static alert\",\n      \"type\": {\n        \"name\": \"bool\"\n      },\n      \"required\": false\n    },\n    \"icon\": {\n      \"description\": \"Allows icon override, accepts material icon name\",\n      \"type\": {\n        \"name\": \"string\"\n      },\n      \"required\": false\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8140-js-prop-types-oneof/input.jsx",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nconst Alert = (props) => <>{JSON.stringify(props)}</>;\n\nAlert.defaultProps = {\n  mode: 'static',\n  type: 'warning',\n};\n\nAlert.propTypes = {\n  mode: PropTypes.oneOf(['static', 'timed']),\n  type: PropTypes.oneOf(['success', 'warning', 'error', 'primary']),\n  message: PropTypes.string.isRequired,\n  /** No background or border if static alert */\n  blank: PropTypes.bool,\n  /** Allows icon override, accepts material icon name */\n  icon: PropTypes.string,\n};\n\nexport const component = Alert;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8140-js-prop-types-oneof/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'static'\",\n      },\n      \"description\": \"\",\n      \"name\": \"mode\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"enum\",\n        \"value\": [\n          \"static\",\n          \"timed\",\n        ],\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"'static' | 'timed'\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'warning'\",\n      },\n      \"description\": \"\",\n      \"name\": \"type\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"enum\",\n        \"value\": [\n          \"success\",\n          \"warning\",\n          \"error\",\n          \"primary\",\n        ],\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"'success' | 'warning' | 'error' | 'primary'\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"message\",\n      \"required\": true,\n      \"sbType\": {\n        \"name\": \"string\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"No background or border if static alert\",\n      \"name\": \"blank\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"boolean\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"bool\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Allows icon override, accepts material icon name\",\n      \"name\": \"icon\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"string\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8143-ts-imported-types/argTypes.snapshot",
    "content": "{\n  \"bar\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"bar\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"Foo['bar']\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"raw\": \"Foo['bar']\",\n      \"required\": true,\n      \"value\": \"Foo['bar']\",\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8143-ts-imported-types/docgen.snapshot",
    "content": "import React from 'react';\nexport const FooComponent = foo => /*#__PURE__*/React.createElement(React.Fragment, null, JSON.stringify(foo));\nexport const component = FooComponent;\nFooComponent.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"FooComponent\",\n  \"props\": {\n    \"bar\": {\n      \"required\": true,\n      \"tsType\": {\n        \"name\": \"Foo['bar']\",\n        \"raw\": \"Foo['bar']\"\n      },\n      \"description\": \"\"\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8143-ts-imported-types/input.tsx",
    "content": "import React from 'react';\n\nimport type { Foo } from './types';\n\ninterface FooProps {\n  bar: Foo['bar'];\n}\n\nexport const FooComponent = (foo: FooProps) => <>{JSON.stringify(foo)}</>;\n\nexport const component = FooComponent;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8143-ts-imported-types/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"bar\",\n      \"required\": true,\n      \"sbType\": {\n        \"name\": \"other\",\n        \"raw\": \"Foo['bar']\",\n        \"value\": \"Foo['bar']\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"Foo['bar']\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8143-ts-imported-types/types.ts",
    "content": "export interface Foo {\n  bar: number;\n}\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8143-ts-react-fc-generics/argTypes.snapshot",
    "content": "{\n  \"padding\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"padding\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'0'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8143-ts-react-fc-generics/docgen.snapshot",
    "content": "import React from 'react';\nexport const Text = ({\n  padding = '0',\n  margin\n}) => /*#__PURE__*/React.createElement(React.Fragment, null, \"Text\");\nexport const component = Text;\nText.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"Text\",\n  \"props\": {\n    \"padding\": {\n      \"defaultValue\": {\n        \"value\": \"'0'\",\n        \"computed\": false\n      },\n      \"required\": false\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8143-ts-react-fc-generics/input.tsx",
    "content": "import React from 'react';\n\ninterface Props {\n  padding: string;\n  margin: number;\n}\n\nexport const Text: React.FC<Props> = ({ padding = '0', margin }) => <>Text</>;\n\nexport const component = Text;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8143-ts-react-fc-generics/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'0'\",\n      },\n      \"description\": undefined,\n      \"name\": \"padding\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8428-js-static-prop-types/argTypes.snapshot",
    "content": "{\n  \"test\": {\n    \"control\": {\n      \"type\": \"text\",\n    },\n    \"description\": \"Please work...\",\n    \"name\": \"test\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8428-js-static-prop-types/docgen.snapshot",
    "content": "function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }\nfunction _toPropertyKey(t) { var i = _toPrimitive(t, \"string\"); return \"symbol\" == typeof i ? i : i + \"\"; }\nfunction _toPrimitive(t, r) { if (\"object\" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || \"default\"); if (\"object\" != typeof i) return i; throw new TypeError(\"@@toPrimitive must return a primitive value.\"); } return (\"string\" === r ? String : Number)(t); }\nimport React from 'react';\nimport PropTypes from 'prop-types';\nexport default class Test extends React.Component {\n  render() {\n    return /*#__PURE__*/React.createElement(\"div\", null, \"test\");\n  }\n}\n_defineProperty(Test, \"propTypes\", {\n  /** Please work... */\n  test: PropTypes.string\n});\nexport const component = Test;\nTest.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"Test\",\n  \"props\": {\n    \"test\": {\n      \"description\": \"Please work...\",\n      \"type\": {\n        \"name\": \"string\"\n      },\n      \"required\": false\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8428-js-static-prop-types/input.jsx",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nexport default class Test extends React.Component {\n  static propTypes = {\n    /** Please work... */\n    test: PropTypes.string,\n  };\n\n  render() {\n    return <div>test</div>;\n  }\n}\n\nexport const component = Test;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8428-js-static-prop-types/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": null,\n      \"description\": \"Please work...\",\n      \"name\": \"test\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"string\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8740-ts-multi-props/argTypes.snapshot",
    "content": "{\n  \"size\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"size\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'a'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8740-ts-multi-props/docgen.snapshot",
    "content": "import React from 'react';\nexport const Header = ({\n  size = 'a',\n  children\n}) => /*#__PURE__*/React.createElement(\"div\", {\n  className: size\n}, children);\nexport const Paragraph = ({\n  size,\n  children\n}) => /*#__PURE__*/React.createElement(\"div\", {\n  className: size\n}, children);\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- we can't expect error as it isn't an error in 18 (development) but it is in 19 (sandbox)\n// @ts-ignore not present on react 19\nParagraph.defaultProps = {\n  size: 'md'\n};\nexport const component = Header;\nHeader.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"Header\",\n  \"props\": {\n    \"size\": {\n      \"defaultValue\": {\n        \"value\": \"'a'\",\n        \"computed\": false\n      },\n      \"required\": false\n    }\n  }\n};\nParagraph.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"Paragraph\",\n  \"props\": {\n    \"size\": {\n      \"defaultValue\": {\n        \"value\": \"'md'\",\n        \"computed\": false\n      },\n      \"required\": false\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8740-ts-multi-props/input.tsx",
    "content": "import React from 'react';\n\nexport interface ElemAProps {\n  size?: 'a' | 'b' | 'c' | 'd';\n  children: React.ReactNode;\n}\n\nexport const Header: React.FC<ElemAProps> = ({ size = 'a', children }) => (\n  <div className={size}>{children}</div>\n);\n\nexport interface ElemBProps {\n  size?: 'sm' | 'md' | 'lg';\n  children: React.ReactNode;\n}\n\nexport const Paragraph: React.FC<ElemBProps> = ({ size, children }) => (\n  <div className={size}>{children}</div>\n);\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- we can't expect error as it isn't an error in 18 (development) but it is in 19 (sandbox)\n// @ts-ignore not present on react 19\nParagraph.defaultProps = { size: 'md' };\n\nexport const component = Header;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8740-ts-multi-props/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'a'\",\n      },\n      \"description\": undefined,\n      \"name\": \"size\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8894-9511-ts-forward-ref/argTypes.snapshot",
    "content": "{\n  \"disabled\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"disabled\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"false\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"variant\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"variant\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'small'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8894-9511-ts-forward-ref/docgen.snapshot",
    "content": "import React, { forwardRef } from 'react';\nconst Button = /*#__PURE__*/forwardRef(function Button({\n  disabled = false,\n  variant = 'small',\n  children\n}, ref) {\n  return /*#__PURE__*/React.createElement(\"button\", {\n    type: \"button\",\n    disabled: disabled,\n    ref: ref\n  }, children, \" \", variant);\n});\nButton.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"Button\",\n  \"props\": {\n    \"disabled\": {\n      \"defaultValue\": {\n        \"value\": \"false\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"variant\": {\n      \"defaultValue\": {\n        \"value\": \"'small'\",\n        \"computed\": false\n      },\n      \"required\": false\n    }\n  }\n};\nexport default Button;\nexport const component = Button;"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8894-9511-ts-forward-ref/input.tsx",
    "content": "import React, { forwardRef } from 'react';\n\ninterface ButtonProps {\n  /** Sets the button size. */\n  variant?: 'small' | 'large';\n  /** Disables the button. */\n  disabled?: boolean;\n  /** Content of the button. */\n  children: React.ReactNode;\n}\n\nconst Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(\n  { disabled = false, variant = 'small', children },\n  ref\n) {\n  return (\n    <button type=\"button\" disabled={disabled} ref={ref}>\n      {children} {variant}\n    </button>\n  );\n});\n\nexport default Button;\n\nexport const component = Button;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/8894-9511-ts-forward-ref/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"false\",\n      },\n      \"description\": undefined,\n      \"name\": \"disabled\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'small'\",\n      },\n      \"description\": undefined,\n      \"name\": \"variant\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9023-js-hoc/argTypes.snapshot",
    "content": "{\n  \"classes\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"classes\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"object\",\n      },\n    },\n    \"type\": {\n      \"name\": \"object\",\n      \"required\": true,\n    },\n  },\n  \"dismissible\": {\n    \"control\": {\n      \"type\": \"boolean\",\n    },\n    \"description\": \"\",\n    \"name\": \"dismissible\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"false\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"bool\",\n      },\n    },\n    \"type\": {\n      \"name\": \"boolean\",\n      \"required\": false,\n    },\n  },\n  \"icon\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"icon\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"elementType\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"elementType\",\n    },\n  },\n  \"variant\": {\n    \"control\": {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"variant\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'primary'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9023-js-hoc/docgen.snapshot",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\n\n// deepscan-disable-next-line\nconst withStyles = themeFn => Comp => Comp;\nclass Alert extends React.Component {\n  render() {\n    return /*#__PURE__*/React.createElement(React.Fragment, null, \"Alert\");\n  }\n}\nAlert.propTypes = {\n  variant: PropTypes.string,\n  dismissible: PropTypes.bool,\n  icon: PropTypes.elementType,\n  classes: PropTypes.object.isRequired\n};\nAlert.defaultProps = {\n  variant: 'primary',\n  dismissible: false\n};\nconst StyledAlert = withStyles(theme => ({\n  alert: props => ({\n    backgroundColor: theme.palette[props.variant].main\n  }),\n  message: {\n    display: 'flex',\n    alignItems: 'center'\n  },\n  icon: {\n    marginRight: theme.spacing(2)\n  }\n}))(Alert);\nexport const component = StyledAlert;\nAlert.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"Alert\",\n  \"props\": {\n    \"variant\": {\n      \"defaultValue\": {\n        \"value\": \"'primary'\",\n        \"computed\": false\n      },\n      \"description\": \"\",\n      \"type\": {\n        \"name\": \"string\"\n      },\n      \"required\": false\n    },\n    \"dismissible\": {\n      \"defaultValue\": {\n        \"value\": \"false\",\n        \"computed\": false\n      },\n      \"description\": \"\",\n      \"type\": {\n        \"name\": \"bool\"\n      },\n      \"required\": false\n    },\n    \"icon\": {\n      \"description\": \"\",\n      \"type\": {\n        \"name\": \"elementType\"\n      },\n      \"required\": false\n    },\n    \"classes\": {\n      \"description\": \"\",\n      \"type\": {\n        \"name\": \"object\"\n      },\n      \"required\": true\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9023-js-hoc/input.jsx",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\n// deepscan-disable-next-line\nconst withStyles = (themeFn) => (Comp) => Comp;\n\nclass Alert extends React.Component {\n  render() {\n    return <>Alert</>;\n  }\n}\nAlert.propTypes = {\n  variant: PropTypes.string,\n  dismissible: PropTypes.bool,\n  icon: PropTypes.elementType,\n  classes: PropTypes.object.isRequired,\n};\nAlert.defaultProps = {\n  variant: 'primary',\n  dismissible: false,\n};\n\nconst StyledAlert = withStyles((theme) => ({\n  alert: (props) => ({\n    backgroundColor: theme.palette[props.variant].main,\n  }),\n  message: {\n    display: 'flex',\n    alignItems: 'center',\n  },\n  icon: {\n    marginRight: theme.spacing(2),\n  },\n}))(Alert);\n\nexport const component = StyledAlert;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9023-js-hoc/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'primary'\",\n      },\n      \"description\": \"\",\n      \"name\": \"variant\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"string\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"false\",\n      },\n      \"description\": \"\",\n      \"name\": \"dismissible\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"boolean\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"bool\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"icon\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"other\",\n        \"value\": \"elementType\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"elementType\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"classes\",\n      \"required\": true,\n      \"sbType\": {\n        \"name\": \"object\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"object\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9399-js-proptypes-shape/argTypes.snapshot",
    "content": "{\n  \"areas\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"areas\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": \"[object]\",\n        \"summary\": \"object[]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"array\",\n      \"required\": true,\n      \"value\": {\n        \"name\": \"object\",\n        \"value\": {\n          \"names\": {\n            \"name\": \"array\",\n            \"value\": {\n              \"name\": \"string\",\n            },\n          },\n          \"position\": {\n            \"name\": \"string\",\n          },\n        },\n      },\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9399-js-proptypes-shape/docgen.snapshot",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nexport const Credits = ({\n  areas\n}) => /*#__PURE__*/React.createElement(React.Fragment, null, JSON.stringify(areas));\n\n// https://github.com/storybookjs/storybook/issues/9399\nCredits.propTypes = {\n  areas: PropTypes.arrayOf(PropTypes.shape({\n    position: PropTypes.string.isRequired,\n    names: PropTypes.arrayOf(PropTypes.string).isRequired\n  })).isRequired\n};\nexport const component = Credits;\nCredits.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"Credits\",\n  \"props\": {\n    \"areas\": {\n      \"description\": \"\",\n      \"type\": {\n        \"name\": \"arrayOf\",\n        \"value\": {\n          \"name\": \"shape\",\n          \"value\": {\n            \"position\": {\n              \"name\": \"string\",\n              \"required\": true\n            },\n            \"names\": {\n              \"name\": \"arrayOf\",\n              \"value\": {\n                \"name\": \"string\"\n              },\n              \"required\": true\n            }\n          }\n        }\n      },\n      \"required\": true\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9399-js-proptypes-shape/input.jsx",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nexport const Credits = ({ areas }) => <>{JSON.stringify(areas)}</>;\n\n// https://github.com/storybookjs/storybook/issues/9399\nCredits.propTypes = {\n  areas: PropTypes.arrayOf(\n    PropTypes.shape({\n      position: PropTypes.string.isRequired,\n      names: PropTypes.arrayOf(PropTypes.string).isRequired,\n    })\n  ).isRequired,\n};\n\nexport const component = Credits;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9399-js-proptypes-shape/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"areas\",\n      \"required\": true,\n      \"sbType\": {\n        \"name\": \"array\",\n        \"value\": {\n          \"name\": \"object\",\n          \"value\": {\n            \"names\": {\n              \"name\": \"array\",\n              \"value\": {\n                \"name\": \"string\",\n              },\n            },\n            \"position\": {\n              \"name\": \"string\",\n            },\n          },\n        },\n      },\n      \"type\": {\n        \"detail\": \"[object]\",\n        \"summary\": \"object[]\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9465-ts-type-props/argTypes.snapshot",
    "content": "{\n  \"disabled\": {\n    \"control\": {\n      \"type\": \"boolean\",\n    },\n    \"description\": \"\",\n    \"name\": \"disabled\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"false\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"boolean\",\n      },\n    },\n    \"type\": {\n      \"name\": \"boolean\",\n      \"required\": false,\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9465-ts-type-props/docgen.snapshot",
    "content": "import React from 'react';\nconst Component = ({\n  disabled = false,\n  children\n}) => /*#__PURE__*/React.createElement(\"button\", {\n  disabled: disabled\n}, children);\nexport const component = Component;\nComponent.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"Component\",\n  \"props\": {\n    \"disabled\": {\n      \"defaultValue\": {\n        \"value\": \"false\",\n        \"computed\": false\n      },\n      \"required\": false,\n      \"tsType\": {\n        \"name\": \"boolean\"\n      },\n      \"description\": \"\"\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9465-ts-type-props/input.tsx",
    "content": "import React from 'react';\n\ntype Props = React.ButtonHTMLAttributes<HTMLButtonElement> & {\n  disabled?: boolean;\n};\n\nconst Component = ({ disabled = false, children }: Props) => (\n  <button disabled={disabled}>{children}</button>\n);\n\nexport const component = Component;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9465-ts-type-props/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"false\",\n      },\n      \"description\": \"\",\n      \"name\": \"disabled\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"boolean\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"boolean\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9493-ts-display-name/argTypes.snapshot",
    "content": "{\n  \"message\": {\n    \"control\": {\n      \"type\": \"text\",\n    },\n    \"description\": \"A message alerting about Empire activities.\",\n    \"name\": \"message\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"string\",\n      \"required\": true,\n    },\n  },\n  \"title\": {\n    \"control\": {\n      \"type\": \"radio\",\n    },\n    \"description\": \"A title that brings attention to the alert.\",\n    \"name\": \"title\",\n    \"options\": [\n      \"Code Red\",\n      \"Code Yellow\",\n      \"Code Green\",\n    ],\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'Code Yellow'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"union\",\n      },\n    },\n    \"type\": {\n      \"name\": \"enum\",\n      \"raw\": \"'Code Red' | 'Code Yellow' | 'Code Green'\",\n      \"required\": false,\n      \"value\": [\n        \"Code Red\",\n        \"Code Yellow\",\n        \"Code Green\",\n      ],\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9493-ts-display-name/docgen.snapshot",
    "content": "import React from 'react';\n/** This message should show up in the Docs panel if everything works fine. */\nexport const EmpireAlert = ({\n  title = 'Code Yellow',\n  message\n}) => /*#__PURE__*/React.createElement(\"div\", null, /*#__PURE__*/React.createElement(\"h1\", null, title), /*#__PURE__*/React.createElement(\"p\", null, message));\nEmpireAlert.displayName = 'SomeOtherDisplayName';\nexport const component = EmpireAlert;\nEmpireAlert.__docgenInfo = {\n  \"description\": \"This message should show up in the Docs panel if everything works fine.\",\n  \"methods\": [],\n  \"displayName\": \"SomeOtherDisplayName\",\n  \"props\": {\n    \"title\": {\n      \"defaultValue\": {\n        \"value\": \"'Code Yellow'\",\n        \"computed\": false\n      },\n      \"required\": false,\n      \"tsType\": {\n        \"name\": \"union\",\n        \"raw\": \"'Code Red' | 'Code Yellow' | 'Code Green'\",\n        \"elements\": [{\n          \"name\": \"literal\",\n          \"value\": \"'Code Red'\"\n        }, {\n          \"name\": \"literal\",\n          \"value\": \"'Code Yellow'\"\n        }, {\n          \"name\": \"literal\",\n          \"value\": \"'Code Green'\"\n        }]\n      },\n      \"description\": \"A title that brings attention to the alert.\"\n    },\n    \"message\": {\n      \"required\": true,\n      \"tsType\": {\n        \"name\": \"string\"\n      },\n      \"description\": \"A message alerting about Empire activities.\"\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9493-ts-display-name/input.tsx",
    "content": "import React from 'react';\n\ntype AlertCode = 'Code Red' | 'Code Yellow' | 'Code Green';\n\nexport interface EmpireAlertProps {\n  /** A title that brings attention to the alert. */\n  title: AlertCode;\n  /** A message alerting about Empire activities. */\n  message: string;\n}\n\n/** This message should show up in the Docs panel if everything works fine. */\nexport const EmpireAlert: React.FC<EmpireAlertProps> = ({\n  title = 'Code Yellow',\n  message,\n}: EmpireAlertProps) => (\n  <div>\n    <h1>{title}</h1>\n    <p>{message}</p>\n  </div>\n);\nEmpireAlert.displayName = 'SomeOtherDisplayName';\n\nexport const component = EmpireAlert;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9493-ts-display-name/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'Code Yellow'\",\n      },\n      \"description\": \"A title that brings attention to the alert.\",\n      \"name\": \"title\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"enum\",\n        \"raw\": \"'Code Red' | 'Code Yellow' | 'Code Green'\",\n        \"value\": [\n          \"Code Red\",\n          \"Code Yellow\",\n          \"Code Green\",\n        ],\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"union\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"A message alerting about Empire activities.\",\n      \"name\": \"message\",\n      \"required\": true,\n      \"sbType\": {\n        \"name\": \"string\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9556-ts-react-default-exports/argTypes.snapshot",
    "content": "{\n  \"isDisabled\": {\n    \"control\": {\n      \"type\": \"boolean\",\n    },\n    \"description\": \"\",\n    \"name\": \"isDisabled\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"false\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"boolean\",\n      },\n    },\n    \"type\": {\n      \"name\": \"boolean\",\n      \"required\": false,\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9556-ts-react-default-exports/docgen.snapshot",
    "content": "function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }\nimport React from 'react';\nexport const Button = ({\n  isDisabled = false,\n  ...props\n}) => /*#__PURE__*/React.createElement(\"button\", _extends({\n  disabled: isDisabled\n}, props));\nexport const component = Button;\nButton.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"Button\",\n  \"props\": {\n    \"isDisabled\": {\n      \"defaultValue\": {\n        \"value\": \"false\",\n        \"computed\": false\n      },\n      \"required\": false,\n      \"tsType\": {\n        \"name\": \"boolean\"\n      },\n      \"description\": \"\"\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9556-ts-react-default-exports/input.tsx",
    "content": "import React from 'react';\n\nexport interface Props extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n  isDisabled?: boolean;\n}\n\nexport const Button: React.FC<Props> = ({ isDisabled = false, ...props }: Props) => (\n  <button disabled={isDisabled} {...props} />\n);\n\nexport const component = Button;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9556-ts-react-default-exports/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"false\",\n      },\n      \"description\": \"\",\n      \"name\": \"isDisabled\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"boolean\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"boolean\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9575-ts-camel-case/argTypes.snapshot",
    "content": "{\n  \"color\": {\n    \"control\": {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"color\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'primary'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9575-ts-camel-case/docgen.snapshot",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nconst iconButton = function IconButton() {\n  return /*#__PURE__*/React.createElement(\"div\", {\n    className: \"icon-button\"\n  }, \"icon-button\");\n};\niconButton.propTypes = {\n  // deepscan-disable-next-line\n  color: PropTypes.string\n};\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- we can't expect error as it isn't an error in 18 (development) but it is in 19 (sandbox)\n// @ts-ignore not present on react 19\niconButton.defaultProps = {\n  color: 'primary'\n};\niconButton.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"iconButton\",\n  \"props\": {\n    \"color\": {\n      \"defaultValue\": {\n        \"value\": \"'primary'\",\n        \"computed\": false\n      },\n      \"description\": \"\",\n      \"type\": {\n        \"name\": \"string\"\n      },\n      \"required\": false\n    }\n  }\n};\nexport default iconButton;\nexport const component = iconButton;"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9575-ts-camel-case/input.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport PropTypes from 'prop-types';\n\nexport interface IProps {\n  /** Button color */\n  color?: string;\n}\n\nconst iconButton: FC<IProps> = function IconButton() {\n  return <div className=\"icon-button\">icon-button</div>;\n};\n\niconButton.propTypes = {\n  // deepscan-disable-next-line\n  color: PropTypes.string,\n};\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- we can't expect error as it isn't an error in 18 (development) but it is in 19 (sandbox)\n// @ts-ignore not present on react 19\niconButton.defaultProps = {\n  color: 'primary',\n};\n\nexport default iconButton;\nexport const component = iconButton;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9575-ts-camel-case/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'primary'\",\n      },\n      \"description\": \"\",\n      \"name\": \"color\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"string\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9586-js-react-memo/argTypes.snapshot",
    "content": "{\n  \"label\": {\n    \"control\": {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"label\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"string\",\n      \"required\": true,\n    },\n  },\n  \"onClick\": {\n    \"description\": \"\",\n    \"name\": \"onClick\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": true,\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9586-js-react-memo/docgen.snapshot",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nfunction Button({\n  label,\n  onClick\n}) {\n  return /*#__PURE__*/React.createElement(\"button\", {\n    onClick: onClick\n  }, label);\n}\nButton.propTypes = {\n  label: PropTypes.string.isRequired,\n  onClick: PropTypes.func.isRequired\n};\nconst MemoButton = /*#__PURE__*/React.memo(Button);\nexport const component = MemoButton;\nButton.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"Button\",\n  \"props\": {\n    \"label\": {\n      \"description\": \"\",\n      \"type\": {\n        \"name\": \"string\"\n      },\n      \"required\": true\n    },\n    \"onClick\": {\n      \"description\": \"\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": true\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9586-js-react-memo/input.jsx",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nfunction Button({ label, onClick }) {\n  return <button onClick={onClick}>{label}</button>;\n}\n\nButton.propTypes = {\n  label: PropTypes.string.isRequired,\n  onClick: PropTypes.func.isRequired,\n};\n\nconst MemoButton = React.memo(Button);\nexport const component = MemoButton;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9586-js-react-memo/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"label\",\n      \"required\": true,\n      \"sbType\": {\n        \"name\": \"string\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"onClick\",\n      \"required\": true,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9591-ts-import-types/Bar.tsx",
    "content": "export interface BarProps {\n  foo?: string;\n}\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9591-ts-import-types/argTypes.snapshot",
    "content": "{\n  \"other\": {\n    \"control\": {\n      \"type\": \"number\",\n    },\n    \"description\": \"\",\n    \"name\": \"other\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"number\",\n      },\n    },\n    \"type\": {\n      \"name\": \"number\",\n      \"required\": false,\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9591-ts-import-types/docgen.snapshot",
    "content": "import React from 'react';\nconst Other = props => /*#__PURE__*/React.createElement(\"span\", props, \"Other\");\nexport const component = Other;\nOther.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"Other\",\n  \"props\": {\n    \"other\": {\n      \"required\": false,\n      \"tsType\": {\n        \"name\": \"number\"\n      },\n      \"description\": \"\"\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9591-ts-import-types/input.tsx",
    "content": "import React from 'react';\n\nimport type { BarProps } from './Bar';\n\ntype OtherProps = BarProps & {\n  other?: number;\n};\n\nconst Other = (props: OtherProps) => <span {...props}>Other</span>;\n\nexport const component = Other;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9591-ts-import-types/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"other\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"number\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"number\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9626-js-default-values/argTypes.snapshot",
    "content": "{\n  \"title\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"title\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'Beta'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9626-js-default-values/docgen.snapshot",
    "content": "import React from 'react';\n\n// eslint-disable-next-line react/prop-types\nexport const Tag = ({\n  title = 'Beta'\n}) => /*#__PURE__*/React.createElement(\"div\", null, title);\nexport const component = Tag;\nTag.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"Tag\",\n  \"props\": {\n    \"title\": {\n      \"defaultValue\": {\n        \"value\": \"'Beta'\",\n        \"computed\": false\n      },\n      \"required\": false\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9626-js-default-values/input.jsx",
    "content": "import React from 'react';\n\n// eslint-disable-next-line react/prop-types\nexport const Tag = ({ title = 'Beta' }) => <div>{title}</div>;\nexport const component = Tag;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9626-js-default-values/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'Beta'\",\n      },\n      \"description\": undefined,\n      \"name\": \"title\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9668-js-proptypes-no-jsdoc/argTypes.snapshot",
    "content": "{\n  \"heads\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"heads\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"array\",\n      },\n    },\n    \"type\": {\n      \"name\": \"array\",\n      \"required\": true,\n      \"value\": undefined,\n    },\n  },\n  \"onAddClick\": {\n    \"description\": \"\",\n    \"name\": \"onAddClick\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9668-js-proptypes-no-jsdoc/docgen.snapshot",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nconst CCTable = props => /*#__PURE__*/React.createElement(React.Fragment, null, JSON.stringify(props));\nCCTable.propTypes = {\n  heads: PropTypes.array.isRequired,\n  onAddClick: PropTypes.func\n};\nexport const component = CCTable;\nCCTable.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"CCTable\",\n  \"props\": {\n    \"heads\": {\n      \"description\": \"\",\n      \"type\": {\n        \"name\": \"array\"\n      },\n      \"required\": true\n    },\n    \"onAddClick\": {\n      \"description\": \"\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9668-js-proptypes-no-jsdoc/input.jsx",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nconst CCTable = (props) => <>{JSON.stringify(props)}</>;\nCCTable.propTypes = {\n  heads: PropTypes.array.isRequired,\n  onAddClick: PropTypes.func,\n};\n\nexport const component = CCTable;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9668-js-proptypes-no-jsdoc/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"heads\",\n      \"required\": true,\n      \"sbType\": {\n        \"name\": \"array\",\n        \"value\": undefined,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"array\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"onAddClick\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9721-ts-deprecated-jsdoc/argTypes.snapshot",
    "content": "{\n  \"size\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": \"The size (replaces width)\",\n    \"name\": \"size\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"{ width: number; height: number }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"object\",\n      \"raw\": \"{ width: number; height: number }\",\n      \"required\": true,\n      \"value\": {\n        \"height\": {\n          \"name\": \"number\",\n        },\n        \"width\": {\n          \"name\": \"number\",\n        },\n      },\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9721-ts-deprecated-jsdoc/docgen.snapshot",
    "content": "import React from 'react';\nconst Foo = props => /*#__PURE__*/React.createElement(React.Fragment, null, JSON.stringify(props));\nexport const component = Foo;\nFoo.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"Foo\",\n  \"props\": {\n    \"size\": {\n      \"required\": true,\n      \"tsType\": {\n        \"name\": \"signature\",\n        \"type\": \"object\",\n        \"raw\": \"{ width: number; height: number }\",\n        \"signature\": {\n          \"properties\": [{\n            \"key\": \"width\",\n            \"value\": {\n              \"name\": \"number\",\n              \"required\": true\n            }\n          }, {\n            \"key\": \"height\",\n            \"value\": {\n              \"name\": \"number\",\n              \"required\": true\n            }\n          }]\n        }\n      },\n      \"description\": \"The size (replaces width)\"\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9721-ts-deprecated-jsdoc/input.tsx",
    "content": "import React from 'react';\n\ninterface FooProps {\n  /** The size (replaces width) */\n  size: { width: number; height: number };\n}\n\nconst Foo: React.FC<FooProps> = (props: FooProps) => <>{JSON.stringify(props)}</>;\n\nexport const component = Foo;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9721-ts-deprecated-jsdoc/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": null,\n      \"description\": \"The size (replaces width)\",\n      \"name\": \"size\",\n      \"required\": true,\n      \"sbType\": {\n        \"name\": \"object\",\n        \"raw\": \"{ width: number; height: number }\",\n        \"value\": {\n          \"height\": {\n            \"name\": \"number\",\n          },\n          \"width\": {\n            \"name\": \"number\",\n          },\n        },\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"{ width: number; height: number }\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9764-ts-extend-props/argTypes.snapshot",
    "content": "{\n  \"checked\": {\n    \"control\": {\n      \"type\": \"boolean\",\n    },\n    \"description\": \"\",\n    \"name\": \"checked\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"boolean\",\n      },\n    },\n    \"type\": {\n      \"name\": \"boolean\",\n      \"required\": false,\n    },\n  },\n  \"defaultChecked\": {\n    \"control\": {\n      \"type\": \"boolean\",\n    },\n    \"description\": \"\",\n    \"name\": \"defaultChecked\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"boolean\",\n      },\n    },\n    \"type\": {\n      \"name\": \"boolean\",\n      \"required\": false,\n    },\n  },\n  \"value\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": \"The input content value\",\n    \"name\": \"value\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"union\",\n      },\n    },\n    \"type\": {\n      \"name\": \"union\",\n      \"raw\": \"string | number\",\n      \"required\": false,\n      \"value\": [\n        {\n          \"name\": \"string\",\n        },\n        {\n          \"name\": \"number\",\n        },\n      ],\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9764-ts-extend-props/docgen.snapshot",
    "content": "import React from 'react';\nconst Radio = props => /*#__PURE__*/React.createElement(React.Fragment, null, JSON.stringify(props));\nexport const component = Radio;\nRadio.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"Radio\",\n  \"props\": {\n    \"value\": {\n      \"required\": false,\n      \"tsType\": {\n        \"name\": \"union\",\n        \"raw\": \"string | number\",\n        \"elements\": [{\n          \"name\": \"string\"\n        }, {\n          \"name\": \"number\"\n        }]\n      },\n      \"description\": \"The input content value\"\n    },\n    \"defaultChecked\": {\n      \"required\": false,\n      \"tsType\": {\n        \"name\": \"boolean\"\n      },\n      \"description\": \"\"\n    },\n    \"checked\": {\n      \"required\": false,\n      \"tsType\": {\n        \"name\": \"boolean\"\n      },\n      \"description\": \"\"\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9764-ts-extend-props/input.tsx",
    "content": "import React from 'react';\n\ninterface InputProps {\n  /** The input content value */\n  value?: string | number;\n}\n\ninterface RadioProps extends InputProps {\n  defaultChecked?: boolean;\n  checked?: boolean;\n}\n\nconst Radio: React.FC<RadioProps> = (props: RadioProps) => <>{JSON.stringify(props)}</>;\n\nexport const component = Radio;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9764-ts-extend-props/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": null,\n      \"description\": \"The input content value\",\n      \"name\": \"value\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"union\",\n        \"raw\": \"string | number\",\n        \"value\": [\n          {\n            \"name\": \"string\",\n          },\n          {\n            \"name\": \"number\",\n          },\n        ],\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"union\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"defaultChecked\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"boolean\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"boolean\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"checked\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"boolean\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"boolean\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9827-ts-default-values/argTypes.snapshot",
    "content": "{\n  \"bar\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"bar\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string[]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"array\",\n      \"raw\": \"string[]\",\n      \"required\": false,\n      \"value\": [\n        {\n          \"name\": \"string\",\n        },\n      ],\n    },\n  },\n  \"foo\": {\n    \"control\": {\n      \"type\": \"boolean\",\n    },\n    \"description\": \"\",\n    \"name\": \"foo\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"boolean\",\n      },\n    },\n    \"type\": {\n      \"name\": \"boolean\",\n      \"required\": true,\n    },\n  },\n  \"title\": {\n    \"control\": {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"title\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'this is the default :)'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9827-ts-default-values/docgen.snapshot",
    "content": "import React from 'react';\nconst Hello = ({\n  title\n}) => {\n  return /*#__PURE__*/React.createElement(\"div\", {\n    className: \"hello\"\n  }, \"Hello Component \", title);\n};\nHello.defaultProps = {\n  title: 'this is the default :)'\n};\nexport const component = Hello;\nHello.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"Hello\",\n  \"props\": {\n    \"title\": {\n      \"defaultValue\": {\n        \"value\": \"'this is the default :)'\",\n        \"computed\": false\n      },\n      \"required\": false,\n      \"tsType\": {\n        \"name\": \"string\"\n      },\n      \"description\": \"\"\n    },\n    \"foo\": {\n      \"required\": true,\n      \"tsType\": {\n        \"name\": \"boolean\"\n      },\n      \"description\": \"\"\n    },\n    \"bar\": {\n      \"required\": false,\n      \"tsType\": {\n        \"name\": \"Array\",\n        \"elements\": [{\n          \"name\": \"string\"\n        }],\n        \"raw\": \"string[]\"\n      },\n      \"description\": \"\"\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9827-ts-default-values/input.tsx",
    "content": "import React from 'react';\n\nexport interface HelloProps {\n  title: string;\n  foo: boolean;\n  bar?: string[];\n}\n\nconst Hello = ({ title }: HelloProps) => {\n  return <div className=\"hello\">Hello Component {title}</div>;\n};\n\nHello.defaultProps = {\n  title: 'this is the default :)',\n};\n\nexport const component = Hello;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9827-ts-default-values/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'this is the default :)'\",\n      },\n      \"description\": \"\",\n      \"name\": \"title\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"string\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"foo\",\n      \"required\": true,\n      \"sbType\": {\n        \"name\": \"boolean\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"boolean\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"bar\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"array\",\n        \"raw\": \"string[]\",\n        \"value\": [\n          {\n            \"name\": \"string\",\n          },\n        ],\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string[]\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9832-ts-enum-export/argTypes.snapshot",
    "content": "{}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9832-ts-enum-export/docgen.snapshot",
    "content": "import React from 'react';\nexport let EnumWithExtraProps = /*#__PURE__*/function (EnumWithExtraProps) {\n  EnumWithExtraProps[\"key1\"] = \"key1\";\n  EnumWithExtraProps[\"key2\"] = \"key2\";\n  return EnumWithExtraProps;\n}({});\nexport const component = () => /*#__PURE__*/React.createElement(\"div\", null, \"hello\");\ncomponent.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"component\"\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9832-ts-enum-export/input.tsx",
    "content": "import React from 'react';\n\nexport enum EnumWithExtraProps {\n  key1 = 'key1',\n  key2 = 'key2',\n}\n\nexport const component = () => <div>hello</div>;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9832-ts-enum-export/properties.snapshot",
    "content": "{\n  \"rows\": [],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9922-ts-component-props/argTypes.snapshot",
    "content": "{\n  \"spacing\": {\n    \"control\": {\n      \"type\": \"number\",\n    },\n    \"description\": \"\",\n    \"name\": \"spacing\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"number\",\n      },\n    },\n    \"type\": {\n      \"name\": \"number\",\n      \"required\": true,\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9922-ts-component-props/docgen.snapshot",
    "content": "import React from 'react';\nconst Button = ({\n  children,\n  onClick\n}) => /*#__PURE__*/React.createElement(\"button\", {\n  onClick: onClick,\n  type: \"button\"\n}, children);\nconst WrappedButton = ({\n  spacing,\n  ...buttonProps\n}) => /*#__PURE__*/React.createElement(\"div\", {\n  style: {\n    padding: spacing\n  }\n}, /*#__PURE__*/React.createElement(Button, buttonProps));\nexport const component = WrappedButton;\nWrappedButton.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"WrappedButton\",\n  \"props\": {\n    \"spacing\": {\n      \"required\": true,\n      \"tsType\": {\n        \"name\": \"number\"\n      },\n      \"description\": \"\"\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9922-ts-component-props/input.tsx",
    "content": "import type { ComponentProps, FC, HTMLAttributes } from 'react';\nimport React from 'react';\n\ntype Props = Pick<HTMLAttributes<HTMLButtonElement>, 'onClick'> & {\n  children: React.ReactNode;\n};\n\nconst Button: FC<Props> = ({ children, onClick }) => (\n  <button onClick={onClick} type=\"button\">\n    {children}\n  </button>\n);\n\ntype WrappedProps = {\n  spacing: number;\n} & ComponentProps<typeof Button>;\n\nconst WrappedButton: FC<WrappedProps> = ({ spacing, ...buttonProps }: WrappedProps) => (\n  <div style={{ padding: spacing }}>\n    <Button {...buttonProps} />\n  </div>\n);\n\nexport const component = WrappedButton;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/9922-ts-component-props/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"spacing\",\n      \"required\": true,\n      \"sbType\": {\n        \"name\": \"number\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"number\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/imported.js",
    "content": "export const imported = 'imported-value';\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/imported.module.css",
    "content": ".foo {\n  color: red;\n}\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-class-component/argTypes.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`react component properties js-class-component 1`] = `\nObject {\n  \"arrayOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"arrayOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"['array',    'optional']\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string[]\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"array\",\n      \"required\": false,\n      \"value\": Object {\n        \"name\": \"string\",\n      },\n    },\n  },\n  \"arrayRequired\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"arrayRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string[]\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"array\",\n      \"required\": true,\n      \"value\": Object {\n        \"name\": \"string\",\n      },\n    },\n  },\n  \"booleanOptional\": Object {\n    \"control\": Object {\n      \"type\": \"boolean\",\n    },\n    \"description\": \"\",\n    \"name\": \"booleanOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"false\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"bool\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"boolean\",\n      \"required\": false,\n    },\n  },\n  \"booleanRequired\": Object {\n    \"control\": Object {\n      \"type\": \"boolean\",\n    },\n    \"description\": \"\",\n    \"name\": \"booleanRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"bool\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"boolean\",\n      \"required\": true,\n    },\n  },\n  \"dateOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"dateOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"new Date('20 Jan 1983')\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"instanceOf(Date)\",\n    },\n  },\n  \"dateRequired\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"dateRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"other\",\n      \"required\": true,\n      \"value\": \"instanceOf(Date)\",\n    },\n  },\n  \"functionOptional\": Object {\n    \"description\": \"\",\n    \"name\": \"functionOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"() => 'foo'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"functionRequired\": Object {\n    \"description\": \"\",\n    \"name\": \"functionRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"function\",\n      \"required\": true,\n    },\n  },\n  \"globalReference\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"globalReference\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"any\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"any\",\n    },\n  },\n  \"importedReference\": Object {\n    \"control\": Object {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"importedReference\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"imported\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"localReference\": Object {\n    \"control\": Object {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"localReference\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'local-value'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"numberOptional\": Object {\n    \"control\": Object {\n      \"type\": \"number\",\n    },\n    \"description\": \"\",\n    \"name\": \"numberOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"1\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"number\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"number\",\n      \"required\": false,\n    },\n  },\n  \"numberRequired\": Object {\n    \"control\": Object {\n      \"type\": \"number\",\n    },\n    \"description\": \"\",\n    \"name\": \"numberRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"number\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"number\",\n      \"required\": true,\n    },\n  },\n  \"objectOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"objectOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ object: 'optional' }\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ }\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"object\",\n      \"required\": false,\n      \"value\": Object {},\n    },\n  },\n  \"objectRequired\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"objectRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ }\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"object\",\n      \"required\": true,\n      \"value\": Object {},\n    },\n  },\n  \"stringGlobalName\": Object {\n    \"control\": Object {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"stringGlobalName\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'top'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"stringOptional\": Object {\n    \"control\": Object {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"stringOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'stringOptional'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"stringRequired\": Object {\n    \"control\": Object {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"stringRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n      \"required\": true,\n    },\n  },\n}\n`;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-class-component/docgen.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`react component properties js-class-component 1`] = `\n\"import React from 'react';\nimport PropTypes from 'prop-types';\nimport { imported } from '../imported';\nconst local = 'local-value';\n/**\n * A component that renders its props\n */\n// eslint-disable-next-line react/prefer-stateless-function\n\nclass PropsWriter extends React.Component {\n  render() {\n    return /*#__PURE__*/React.createElement(\\\\\"pre\\\\\", null, JSON.stringify(this.props));\n  }\n\n}\n\nPropsWriter.propTypes = {\n  numberRequired: PropTypes.number.isRequired,\n  numberOptional: PropTypes.number,\n  stringRequired: PropTypes.string.isRequired,\n  stringOptional: PropTypes.string,\n  booleanRequired: PropTypes.bool.isRequired,\n  booleanOptional: PropTypes.bool,\n  arrayRequired: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired,\n  arrayOptional: PropTypes.arrayOf(PropTypes.string.isRequired),\n  objectRequired: PropTypes.shape({}).isRequired,\n  objectOptional: PropTypes.shape({}),\n  functionRequired: PropTypes.func.isRequired,\n  functionOptional: PropTypes.func,\n  dateRequired: PropTypes.instanceOf(Date).isRequired,\n  dateOptional: PropTypes.instanceOf(Date),\n  localReference: PropTypes.string,\n  importedReference: PropTypes.string,\n  globalReference: PropTypes.any,\n  stringGlobalName: PropTypes.string\n};\nPropsWriter.defaultProps = {\n  numberOptional: 1,\n  stringOptional: 'stringOptional',\n  booleanOptional: false,\n  arrayOptional: ['array', 'optional'],\n  objectOptional: {\n    object: 'optional'\n  },\n  functionOptional: () => 'foo',\n  dateOptional: new Date('20 Jan 1983'),\n  localReference: local,\n  importedReference: imported,\n  globalReference: Date,\n  stringGlobalName: 'top',\n  // eslint-disable-next-line react/default-props-match-prop-types\n  stringNoPropType: 'stringNoPropType'\n};\nexport const component = PropsWriter;\nPropsWriter.__docgenInfo = {\n  \\\\\"description\\\\\": \\\\\"A component that renders its props\\\\\",\n  \\\\\"methods\\\\\": [],\n  \\\\\"displayName\\\\\": \\\\\"PropsWriter\\\\\",\n  \\\\\"props\\\\\": {\n    \\\\\"numberOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"1\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"number\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"stringOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'stringOptional'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"booleanOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"false\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"bool\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"arrayOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"['array', 'optional']\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"arrayOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"string\\\\\"\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"objectOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{ object: 'optional' }\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"shape\\\\\",\n        \\\\\"value\\\\\": {}\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"functionOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"() => 'foo'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"func\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"dateOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"new Date('20 Jan 1983')\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"instanceOf\\\\\",\n        \\\\\"value\\\\\": \\\\\"Date\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"localReference\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'local-value'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"importedReference\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"imported\\\\\",\n        \\\\\"computed\\\\\": true\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"globalReference\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"Date\\\\\",\n        \\\\\"computed\\\\\": true\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"any\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"stringGlobalName\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'top'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"stringNoPropType\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'stringNoPropType'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"numberRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"number\\\\\"\n      },\n      \\\\\"required\\\\\": true\n    },\n    \\\\\"stringRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": true\n    },\n    \\\\\"booleanRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"bool\\\\\"\n      },\n      \\\\\"required\\\\\": true\n    },\n    \\\\\"arrayRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"arrayOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"string\\\\\"\n        }\n      },\n      \\\\\"required\\\\\": true\n    },\n    \\\\\"objectRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"shape\\\\\",\n        \\\\\"value\\\\\": {}\n      },\n      \\\\\"required\\\\\": true\n    },\n    \\\\\"functionRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"func\\\\\"\n      },\n      \\\\\"required\\\\\": true\n    },\n    \\\\\"dateRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"instanceOf\\\\\",\n        \\\\\"value\\\\\": \\\\\"Date\\\\\"\n      },\n      \\\\\"required\\\\\": true\n    }\n  }\n};\"\n`;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-class-component/input.jsx",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nimport { imported } from '../imported';\n\nconst local = 'local-value';\n\n/** A component that renders its props */\n\nclass PropsWriter extends React.Component {\n  render() {\n    return <pre>{JSON.stringify(this.props)}</pre>;\n  }\n}\n\nPropsWriter.propTypes = {\n  numberRequired: PropTypes.number.isRequired,\n  numberOptional: PropTypes.number,\n  stringRequired: PropTypes.string.isRequired,\n  stringOptional: PropTypes.string,\n  booleanRequired: PropTypes.bool.isRequired,\n  booleanOptional: PropTypes.bool,\n  arrayRequired: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired,\n  arrayOptional: PropTypes.arrayOf(PropTypes.string.isRequired),\n  objectRequired: PropTypes.shape({}).isRequired,\n  objectOptional: PropTypes.shape({}),\n  functionRequired: PropTypes.func.isRequired,\n  functionOptional: PropTypes.func,\n  dateRequired: PropTypes.instanceOf(Date).isRequired,\n  dateOptional: PropTypes.instanceOf(Date),\n  localReference: PropTypes.string,\n  importedReference: PropTypes.string,\n  globalReference: PropTypes.any,\n  stringGlobalName: PropTypes.string,\n};\n\nPropsWriter.defaultProps = {\n  numberOptional: 1,\n  stringOptional: 'stringOptional',\n  booleanOptional: false,\n  arrayOptional: ['array', 'optional'],\n  objectOptional: { object: 'optional' },\n  functionOptional: () => 'foo',\n  dateOptional: new Date('20 Jan 1983'),\n  localReference: local,\n  importedReference: imported,\n  globalReference: Date,\n  stringGlobalName: 'top',\n\n  stringNoPropType: 'stringNoPropType',\n};\n\nexport const component = PropsWriter;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-class-component/properties.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`react component properties js-class-component 1`] = `\nObject {\n  \"rows\": Array [\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"numberRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"number\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"number\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"1\",\n      },\n      \"description\": \"\",\n      \"name\": \"numberOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"number\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"number\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"stringRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'stringOptional'\",\n      },\n      \"description\": \"\",\n      \"name\": \"stringOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"booleanRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"boolean\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"bool\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"false\",\n      },\n      \"description\": \"\",\n      \"name\": \"booleanOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"boolean\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"bool\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"arrayRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"array\",\n        \"value\": Object {\n          \"name\": \"string\",\n        },\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string[]\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"['array',    'optional']\",\n      },\n      \"description\": \"\",\n      \"name\": \"arrayOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"array\",\n        \"value\": Object {\n          \"name\": \"string\",\n        },\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string[]\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"objectRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"object\",\n        \"value\": Object {},\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ }\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ object: 'optional' }\",\n      },\n      \"description\": \"\",\n      \"name\": \"objectOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"object\",\n        \"value\": Object {},\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ }\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"functionRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"function\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"() => 'foo'\",\n      },\n      \"description\": \"\",\n      \"name\": \"functionOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"function\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"dateRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"other\",\n        \"value\": \"instanceOf(Date)\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"new Date('20 Jan 1983')\",\n      },\n      \"description\": \"\",\n      \"name\": \"dateOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"other\",\n        \"value\": \"instanceOf(Date)\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'local-value'\",\n      },\n      \"description\": \"\",\n      \"name\": \"localReference\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"imported\",\n      },\n      \"description\": \"\",\n      \"name\": \"importedReference\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n      \"description\": \"\",\n      \"name\": \"globalReference\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"other\",\n        \"value\": \"any\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"any\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'top'\",\n      },\n      \"description\": \"\",\n      \"name\": \"stringGlobalName\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n  ],\n}\n`;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-function-component/argTypes.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`react component properties js-function-component 1`] = `\nObject {\n  \"arrayOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"arrayOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"['array',    'optional']\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string[]\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"array\",\n      \"required\": false,\n      \"value\": Object {\n        \"name\": \"string\",\n      },\n    },\n  },\n  \"arrayRequired\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"arrayRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string[]\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"array\",\n      \"required\": true,\n      \"value\": Object {\n        \"name\": \"string\",\n      },\n    },\n  },\n  \"booleanOptional\": Object {\n    \"control\": Object {\n      \"type\": \"boolean\",\n    },\n    \"description\": \"\",\n    \"name\": \"booleanOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"false\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"bool\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"boolean\",\n      \"required\": false,\n    },\n  },\n  \"booleanRequired\": Object {\n    \"control\": Object {\n      \"type\": \"boolean\",\n    },\n    \"description\": \"\",\n    \"name\": \"booleanRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"bool\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"boolean\",\n      \"required\": true,\n    },\n  },\n  \"dateOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"dateOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"new Date('20 Jan 1983')\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"instanceOf(Date)\",\n    },\n  },\n  \"dateRequired\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"dateRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"other\",\n      \"required\": true,\n      \"value\": \"instanceOf(Date)\",\n    },\n  },\n  \"functionOptional\": Object {\n    \"description\": \"\",\n    \"name\": \"functionOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"() => 'foo'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"functionRequired\": Object {\n    \"description\": \"\",\n    \"name\": \"functionRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"function\",\n      \"required\": true,\n    },\n  },\n  \"globalReference\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"globalReference\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"any\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"any\",\n    },\n  },\n  \"importedReference\": Object {\n    \"control\": Object {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"importedReference\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"imported\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"localReference\": Object {\n    \"control\": Object {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"localReference\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'local-value'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"numberOptional\": Object {\n    \"control\": Object {\n      \"type\": \"number\",\n    },\n    \"description\": \"\",\n    \"name\": \"numberOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"1\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"number\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"number\",\n      \"required\": false,\n    },\n  },\n  \"numberRequired\": Object {\n    \"control\": Object {\n      \"type\": \"number\",\n    },\n    \"description\": \"\",\n    \"name\": \"numberRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"number\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"number\",\n      \"required\": true,\n    },\n  },\n  \"objectOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"objectOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ object: 'optional' }\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ }\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"object\",\n      \"required\": false,\n      \"value\": Object {},\n    },\n  },\n  \"objectRequired\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"objectRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ }\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"object\",\n      \"required\": true,\n      \"value\": Object {},\n    },\n  },\n  \"stringGlobalName\": Object {\n    \"control\": Object {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"stringGlobalName\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'top'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"stringOptional\": Object {\n    \"control\": Object {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"stringOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'stringOptional'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"stringRequired\": Object {\n    \"control\": Object {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"stringRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n      \"required\": true,\n    },\n  },\n}\n`;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-function-component/docgen.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`react component properties js-function-component 1`] = `\n\"import React from 'react';\nimport PropTypes from 'prop-types';\nimport { imported } from '../imported';\nconst local = 'local-value';\n/**\n * A component that renders its props\n */\n\nexport const PropsWriter = props => /*#__PURE__*/React.createElement(\\\\\"pre\\\\\", null, JSON.stringify(props));\nPropsWriter.propTypes = {\n  numberRequired: PropTypes.number.isRequired,\n  numberOptional: PropTypes.number,\n  stringRequired: PropTypes.string.isRequired,\n  stringOptional: PropTypes.string,\n  booleanRequired: PropTypes.bool.isRequired,\n  booleanOptional: PropTypes.bool,\n  arrayRequired: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired,\n  arrayOptional: PropTypes.arrayOf(PropTypes.string.isRequired),\n  objectRequired: PropTypes.shape({}).isRequired,\n  objectOptional: PropTypes.shape({}),\n  functionRequired: PropTypes.func.isRequired,\n  functionOptional: PropTypes.func,\n  dateRequired: PropTypes.instanceOf(Date).isRequired,\n  dateOptional: PropTypes.instanceOf(Date),\n  localReference: PropTypes.string,\n  importedReference: PropTypes.string,\n  globalReference: PropTypes.any,\n  stringGlobalName: PropTypes.string\n};\nPropsWriter.defaultProps = {\n  numberOptional: 1,\n  stringOptional: 'stringOptional',\n  booleanOptional: false,\n  arrayOptional: ['array', 'optional'],\n  objectOptional: {\n    object: 'optional'\n  },\n  functionOptional: () => 'foo',\n  dateOptional: new Date('20 Jan 1983'),\n  localReference: local,\n  importedReference: imported,\n  globalReference: Date,\n  stringGlobalName: 'top'\n};\nexport const component = PropsWriter;\nPropsWriter.__docgenInfo = {\n  \\\\\"description\\\\\": \\\\\"A component that renders its props\\\\\",\n  \\\\\"methods\\\\\": [],\n  \\\\\"displayName\\\\\": \\\\\"PropsWriter\\\\\",\n  \\\\\"props\\\\\": {\n    \\\\\"numberOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"1\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"number\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"stringOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'stringOptional'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"booleanOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"false\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"bool\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"arrayOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"['array', 'optional']\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"arrayOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"string\\\\\"\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"objectOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{ object: 'optional' }\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"shape\\\\\",\n        \\\\\"value\\\\\": {}\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"functionOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"() => 'foo'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"func\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"dateOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"new Date('20 Jan 1983')\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"instanceOf\\\\\",\n        \\\\\"value\\\\\": \\\\\"Date\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"localReference\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'local-value'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"importedReference\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"imported\\\\\",\n        \\\\\"computed\\\\\": true\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"globalReference\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"Date\\\\\",\n        \\\\\"computed\\\\\": true\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"any\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"stringGlobalName\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'top'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"numberRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"number\\\\\"\n      },\n      \\\\\"required\\\\\": true\n    },\n    \\\\\"stringRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": true\n    },\n    \\\\\"booleanRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"bool\\\\\"\n      },\n      \\\\\"required\\\\\": true\n    },\n    \\\\\"arrayRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"arrayOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"string\\\\\"\n        }\n      },\n      \\\\\"required\\\\\": true\n    },\n    \\\\\"objectRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"shape\\\\\",\n        \\\\\"value\\\\\": {}\n      },\n      \\\\\"required\\\\\": true\n    },\n    \\\\\"functionRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"func\\\\\"\n      },\n      \\\\\"required\\\\\": true\n    },\n    \\\\\"dateRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"instanceOf\\\\\",\n        \\\\\"value\\\\\": \\\\\"Date\\\\\"\n      },\n      \\\\\"required\\\\\": true\n    }\n  }\n};\"\n`;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-function-component/input.jsx",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nimport { imported } from '../imported';\n\nconst local = 'local-value';\n\n/** A component that renders its props */\nexport const PropsWriter = (props) => <pre>{JSON.stringify(props)}</pre>;\n\nPropsWriter.propTypes = {\n  numberRequired: PropTypes.number.isRequired,\n  numberOptional: PropTypes.number,\n  stringRequired: PropTypes.string.isRequired,\n  stringOptional: PropTypes.string,\n  booleanRequired: PropTypes.bool.isRequired,\n  booleanOptional: PropTypes.bool,\n  arrayRequired: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired,\n  arrayOptional: PropTypes.arrayOf(PropTypes.string.isRequired),\n  objectRequired: PropTypes.shape({}).isRequired,\n  objectOptional: PropTypes.shape({}),\n  functionRequired: PropTypes.func.isRequired,\n  functionOptional: PropTypes.func,\n  dateRequired: PropTypes.instanceOf(Date).isRequired,\n  dateOptional: PropTypes.instanceOf(Date),\n  localReference: PropTypes.string,\n  importedReference: PropTypes.string,\n  globalReference: PropTypes.any,\n  stringGlobalName: PropTypes.string,\n};\n\nPropsWriter.defaultProps = {\n  numberOptional: 1,\n  stringOptional: 'stringOptional',\n  booleanOptional: false,\n  arrayOptional: ['array', 'optional'],\n  objectOptional: { object: 'optional' },\n  functionOptional: () => 'foo',\n  dateOptional: new Date('20 Jan 1983'),\n  localReference: local,\n  importedReference: imported,\n  globalReference: Date,\n  stringGlobalName: 'top',\n};\n\nexport const component = PropsWriter;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-function-component/properties.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`react component properties js-function-component 1`] = `\nObject {\n  \"rows\": Array [\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"numberRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"number\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"number\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"1\",\n      },\n      \"description\": \"\",\n      \"name\": \"numberOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"number\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"number\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"stringRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'stringOptional'\",\n      },\n      \"description\": \"\",\n      \"name\": \"stringOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"booleanRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"boolean\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"bool\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"false\",\n      },\n      \"description\": \"\",\n      \"name\": \"booleanOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"boolean\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"bool\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"arrayRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"array\",\n        \"value\": Object {\n          \"name\": \"string\",\n        },\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string[]\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"['array',    'optional']\",\n      },\n      \"description\": \"\",\n      \"name\": \"arrayOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"array\",\n        \"value\": Object {\n          \"name\": \"string\",\n        },\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string[]\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"objectRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"object\",\n        \"value\": Object {},\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ }\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ object: 'optional' }\",\n      },\n      \"description\": \"\",\n      \"name\": \"objectOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"object\",\n        \"value\": Object {},\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ }\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"functionRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"function\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"() => 'foo'\",\n      },\n      \"description\": \"\",\n      \"name\": \"functionOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"function\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"dateRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"other\",\n        \"value\": \"instanceOf(Date)\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"new Date('20 Jan 1983')\",\n      },\n      \"description\": \"\",\n      \"name\": \"dateOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"other\",\n        \"value\": \"instanceOf(Date)\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'local-value'\",\n      },\n      \"description\": \"\",\n      \"name\": \"localReference\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"imported\",\n      },\n      \"description\": \"\",\n      \"name\": \"importedReference\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n      \"description\": \"\",\n      \"name\": \"globalReference\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"other\",\n        \"value\": \"any\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"any\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'top'\",\n      },\n      \"description\": \"\",\n      \"name\": \"stringGlobalName\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n  ],\n}\n`;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-function-component-inline-defaults/argTypes.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`react component properties js-function-component-inline-defaults 1`] = `\nObject {\n  \"arrayOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"arrayOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"['array',    'optional']\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string[]\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"array\",\n      \"required\": false,\n      \"value\": Object {\n        \"name\": \"string\",\n      },\n    },\n  },\n  \"arrayRequired\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"arrayRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string[]\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"array\",\n      \"required\": true,\n      \"value\": Object {\n        \"name\": \"string\",\n      },\n    },\n  },\n  \"booleanOptional\": Object {\n    \"control\": Object {\n      \"type\": \"boolean\",\n    },\n    \"description\": \"\",\n    \"name\": \"booleanOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"false\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"bool\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"boolean\",\n      \"required\": false,\n    },\n  },\n  \"booleanRequired\": Object {\n    \"control\": Object {\n      \"type\": \"boolean\",\n    },\n    \"description\": \"\",\n    \"name\": \"booleanRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"bool\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"boolean\",\n      \"required\": true,\n    },\n  },\n  \"dateOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"dateOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"new Date('20 Jan 1983')\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"instanceOf(Date)\",\n    },\n  },\n  \"dateRequired\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"dateRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"other\",\n      \"required\": true,\n      \"value\": \"instanceOf(Date)\",\n    },\n  },\n  \"functionOptional\": Object {\n    \"description\": \"\",\n    \"name\": \"functionOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"() => 'foo'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"functionRequired\": Object {\n    \"description\": \"\",\n    \"name\": \"functionRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"function\",\n      \"required\": true,\n    },\n  },\n  \"globalReference\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"globalReference\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"any\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"any\",\n    },\n  },\n  \"importedReference\": Object {\n    \"control\": Object {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"importedReference\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"imported\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"localReference\": Object {\n    \"control\": Object {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"localReference\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'local-value'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"numberOptional\": Object {\n    \"control\": Object {\n      \"type\": \"number\",\n    },\n    \"description\": \"\",\n    \"name\": \"numberOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"1\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"number\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"number\",\n      \"required\": false,\n    },\n  },\n  \"numberRequired\": Object {\n    \"control\": Object {\n      \"type\": \"number\",\n    },\n    \"description\": \"\",\n    \"name\": \"numberRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"number\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"number\",\n      \"required\": true,\n    },\n  },\n  \"objectOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"objectOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ object: 'optional' }\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ }\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"object\",\n      \"required\": false,\n      \"value\": Object {},\n    },\n  },\n  \"objectRequired\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"objectRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ }\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"object\",\n      \"required\": true,\n      \"value\": Object {},\n    },\n  },\n  \"stringGlobalName\": Object {\n    \"control\": Object {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"stringGlobalName\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'top'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"stringOptional\": Object {\n    \"control\": Object {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"stringOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'stringOptional'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"stringRequired\": Object {\n    \"control\": Object {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"stringRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n      \"required\": true,\n    },\n  },\n}\n`;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-function-component-inline-defaults/docgen.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`react component properties js-function-component-inline-defaults 1`] = `\n\"import React from 'react';\nimport PropTypes from 'prop-types';\nimport { imported } from '../imported';\nconst local = 'local-value';\n/**\n * A component that renders its props\n */\n\nexport const PropsWriter = ({\n  numberOptional = 1,\n  stringOptional = 'stringOptional',\n  booleanOptional = false,\n  arrayOptional = ['array', 'optional'],\n  objectOptional = {\n    object: 'optional'\n  },\n  functionOptional = () => 'foo',\n  dateOptional = new Date('20 Jan 1983'),\n  localReference = local,\n  importedReference = imported,\n  globalReference = Date,\n  stringGlobalName = 'top'\n}) => /*#__PURE__*/React.createElement(\\\\\"pre\\\\\", null, JSON.stringify({\n  numberOptional,\n  stringOptional,\n  booleanOptional,\n  arrayOptional,\n  objectOptional,\n  functionOptional,\n  dateOptional,\n  localReference,\n  importedReference,\n  globalReference,\n  stringGlobalName\n}));\nPropsWriter.propTypes = {\n  numberRequired: PropTypes.number.isRequired,\n  numberOptional: PropTypes.number,\n  stringRequired: PropTypes.string.isRequired,\n  stringOptional: PropTypes.string,\n  booleanRequired: PropTypes.bool.isRequired,\n  booleanOptional: PropTypes.bool,\n  arrayRequired: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired,\n  arrayOptional: PropTypes.arrayOf(PropTypes.string.isRequired),\n  objectRequired: PropTypes.shape({}).isRequired,\n  objectOptional: PropTypes.shape({}),\n  functionRequired: PropTypes.func.isRequired,\n  functionOptional: PropTypes.func,\n  dateRequired: PropTypes.instanceOf(Date).isRequired,\n  dateOptional: PropTypes.instanceOf(Date),\n  localReference: PropTypes.string,\n  importedReference: PropTypes.string,\n  globalReference: PropTypes.any,\n  stringGlobalName: PropTypes.string\n};\nexport const component = PropsWriter;\nPropsWriter.__docgenInfo = {\n  \\\\\"description\\\\\": \\\\\"A component that renders its props\\\\\",\n  \\\\\"methods\\\\\": [],\n  \\\\\"displayName\\\\\": \\\\\"PropsWriter\\\\\",\n  \\\\\"props\\\\\": {\n    \\\\\"numberOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"1\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"number\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"stringOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'stringOptional'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"booleanOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"false\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"bool\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"arrayOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"['array', 'optional']\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"arrayOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"string\\\\\"\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"objectOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{ object: 'optional' }\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"shape\\\\\",\n        \\\\\"value\\\\\": {}\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"functionOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"() => 'foo'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"func\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"dateOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"new Date('20 Jan 1983')\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"instanceOf\\\\\",\n        \\\\\"value\\\\\": \\\\\"Date\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"localReference\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'local-value'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"importedReference\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"imported\\\\\",\n        \\\\\"computed\\\\\": true\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"globalReference\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"Date\\\\\",\n        \\\\\"computed\\\\\": true\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"any\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"stringGlobalName\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'top'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"numberRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"number\\\\\"\n      },\n      \\\\\"required\\\\\": true\n    },\n    \\\\\"stringRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": true\n    },\n    \\\\\"booleanRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"bool\\\\\"\n      },\n      \\\\\"required\\\\\": true\n    },\n    \\\\\"arrayRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"arrayOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"string\\\\\"\n        }\n      },\n      \\\\\"required\\\\\": true\n    },\n    \\\\\"objectRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"shape\\\\\",\n        \\\\\"value\\\\\": {}\n      },\n      \\\\\"required\\\\\": true\n    },\n    \\\\\"functionRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"func\\\\\"\n      },\n      \\\\\"required\\\\\": true\n    },\n    \\\\\"dateRequired\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"instanceOf\\\\\",\n        \\\\\"value\\\\\": \\\\\"Date\\\\\"\n      },\n      \\\\\"required\\\\\": true\n    }\n  }\n};\"\n`;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-function-component-inline-defaults/input.jsx",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nimport { imported } from '../imported';\n\nconst local = 'local-value';\n\n/** A component that renders its props */\nexport const PropsWriter = ({\n  numberOptional = 1,\n  stringOptional = 'stringOptional',\n  booleanOptional = false,\n  arrayOptional = ['array', 'optional'],\n  objectOptional = { object: 'optional' },\n  functionOptional = () => 'foo',\n  dateOptional = new Date('20 Jan 1983'),\n  localReference = local,\n  importedReference = imported,\n  globalReference = Date,\n  stringGlobalName = 'top',\n}) => (\n  <pre>\n    {JSON.stringify({\n      numberOptional,\n      stringOptional,\n      booleanOptional,\n      arrayOptional,\n      objectOptional,\n      functionOptional,\n      dateOptional,\n      localReference,\n      importedReference,\n      globalReference,\n      stringGlobalName,\n    })}\n  </pre>\n);\n\nPropsWriter.propTypes = {\n  numberRequired: PropTypes.number.isRequired,\n  numberOptional: PropTypes.number,\n  stringRequired: PropTypes.string.isRequired,\n  stringOptional: PropTypes.string,\n  booleanRequired: PropTypes.bool.isRequired,\n  booleanOptional: PropTypes.bool,\n  arrayRequired: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired,\n  arrayOptional: PropTypes.arrayOf(PropTypes.string.isRequired),\n  objectRequired: PropTypes.shape({}).isRequired,\n  objectOptional: PropTypes.shape({}),\n  functionRequired: PropTypes.func.isRequired,\n  functionOptional: PropTypes.func,\n  dateRequired: PropTypes.instanceOf(Date).isRequired,\n  dateOptional: PropTypes.instanceOf(Date),\n  localReference: PropTypes.string,\n  importedReference: PropTypes.string,\n  globalReference: PropTypes.any,\n  stringGlobalName: PropTypes.string,\n};\n\nexport const component = PropsWriter;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-function-component-inline-defaults/properties.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`react component properties js-function-component-inline-defaults 1`] = `\nObject {\n  \"rows\": Array [\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"numberRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"number\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"number\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"1\",\n      },\n      \"description\": \"\",\n      \"name\": \"numberOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"number\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"number\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"stringRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'stringOptional'\",\n      },\n      \"description\": \"\",\n      \"name\": \"stringOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"booleanRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"boolean\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"bool\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"false\",\n      },\n      \"description\": \"\",\n      \"name\": \"booleanOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"boolean\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"bool\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"arrayRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"array\",\n        \"value\": Object {\n          \"name\": \"string\",\n        },\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string[]\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"['array',    'optional']\",\n      },\n      \"description\": \"\",\n      \"name\": \"arrayOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"array\",\n        \"value\": Object {\n          \"name\": \"string\",\n        },\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string[]\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"objectRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"object\",\n        \"value\": Object {},\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ }\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ object: 'optional' }\",\n      },\n      \"description\": \"\",\n      \"name\": \"objectOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"object\",\n        \"value\": Object {},\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ }\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"functionRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"function\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"() => 'foo'\",\n      },\n      \"description\": \"\",\n      \"name\": \"functionOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"function\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"dateRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"other\",\n        \"value\": \"instanceOf(Date)\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"new Date('20 Jan 1983')\",\n      },\n      \"description\": \"\",\n      \"name\": \"dateOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"other\",\n        \"value\": \"instanceOf(Date)\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'local-value'\",\n      },\n      \"description\": \"\",\n      \"name\": \"localReference\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"imported\",\n      },\n      \"description\": \"\",\n      \"name\": \"importedReference\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n      \"description\": \"\",\n      \"name\": \"globalReference\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"other\",\n        \"value\": \"any\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"any\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'top'\",\n      },\n      \"description\": \"\",\n      \"name\": \"stringGlobalName\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n  ],\n}\n`;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-function-component-inline-defaults-no-propTypes/argTypes.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`react component properties js-function-component-inline-defaults-no-propTypes 1`] = `\nObject {\n  \"arrayOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"arrayOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"['array', 'optional']\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"booleanOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"booleanOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"false\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"dateOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"dateOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"new Date('20 Jan 1983')\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"functionOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"functionOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"() => 'foo'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"globalReference\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"globalReference\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"importedReference\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"importedReference\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"imported\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"localReference\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"localReference\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'local-value'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"numberOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"numberOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"1\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"objectOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"objectOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ object: 'optional' }\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"stringGlobalName\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"stringGlobalName\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'top'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"stringOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"stringOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'stringOptional'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n}\n`;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-function-component-inline-defaults-no-propTypes/docgen.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`react component properties js-function-component-inline-defaults-no-propTypes 1`] = `\n\"/* eslint-disable react/prop-types */\nimport React from 'react';\nimport { imported } from '../imported';\nconst local = 'local-value';\n/**\n * A component that renders its props\n */\n\nexport const PropsWriter = ({\n  numberOptional = 1,\n  stringOptional = 'stringOptional',\n  booleanOptional = false,\n  arrayOptional = ['array', 'optional'],\n  objectOptional = {\n    object: 'optional'\n  },\n  functionOptional = () => 'foo',\n  dateOptional = new Date('20 Jan 1983'),\n  localReference = local,\n  importedReference = imported,\n  globalReference = Date,\n  stringGlobalName = 'top'\n}) => /*#__PURE__*/React.createElement(\\\\\"pre\\\\\", null, JSON.stringify({\n  numberOptional,\n  stringOptional,\n  booleanOptional,\n  arrayOptional,\n  objectOptional,\n  functionOptional,\n  dateOptional,\n  localReference,\n  importedReference,\n  globalReference,\n  stringGlobalName\n}));\nexport const component = PropsWriter;\nPropsWriter.__docgenInfo = {\n  \\\\\"description\\\\\": \\\\\"A component that renders its props\\\\\",\n  \\\\\"methods\\\\\": [],\n  \\\\\"displayName\\\\\": \\\\\"PropsWriter\\\\\",\n  \\\\\"props\\\\\": {\n    \\\\\"numberOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"1\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"stringOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'stringOptional'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"booleanOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"false\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"arrayOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"['array', 'optional']\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"objectOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{ object: 'optional' }\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"functionOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"() => 'foo'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"dateOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"new Date('20 Jan 1983')\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"localReference\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'local-value'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"importedReference\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"imported\\\\\",\n        \\\\\"computed\\\\\": true\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"globalReference\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"Date\\\\\",\n        \\\\\"computed\\\\\": true\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"stringGlobalName\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'top'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    }\n  }\n};\"\n`;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-function-component-inline-defaults-no-propTypes/input.jsx",
    "content": "/* eslint-disable react/prop-types */\nimport React from 'react';\n\nimport { imported } from '../imported';\n\nconst local = 'local-value';\n\n/** A component that renders its props */\nexport const PropsWriter = ({\n  numberOptional = 1,\n  stringOptional = 'stringOptional',\n  booleanOptional = false,\n  arrayOptional = ['array', 'optional'],\n  objectOptional = { object: 'optional' },\n  functionOptional = () => 'foo',\n  dateOptional = new Date('20 Jan 1983'),\n  localReference = local,\n  importedReference = imported,\n  globalReference = Date,\n  stringGlobalName = 'top',\n}) => (\n  <pre>\n    {JSON.stringify({\n      numberOptional,\n      stringOptional,\n      booleanOptional,\n      arrayOptional,\n      objectOptional,\n      functionOptional,\n      dateOptional,\n      localReference,\n      importedReference,\n      globalReference,\n      stringGlobalName,\n    })}\n  </pre>\n);\n\nexport const component = PropsWriter;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-function-component-inline-defaults-no-propTypes/properties.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`react component properties js-function-component-inline-defaults-no-propTypes 1`] = `\nObject {\n  \"rows\": Array [\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"1\",\n      },\n      \"description\": undefined,\n      \"name\": \"numberOptional\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'stringOptional'\",\n      },\n      \"description\": undefined,\n      \"name\": \"stringOptional\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"false\",\n      },\n      \"description\": undefined,\n      \"name\": \"booleanOptional\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"['array', 'optional']\",\n      },\n      \"description\": undefined,\n      \"name\": \"arrayOptional\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ object: 'optional' }\",\n      },\n      \"description\": undefined,\n      \"name\": \"objectOptional\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"() => 'foo'\",\n      },\n      \"description\": undefined,\n      \"name\": \"functionOptional\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"new Date('20 Jan 1983')\",\n      },\n      \"description\": undefined,\n      \"name\": \"dateOptional\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'local-value'\",\n      },\n      \"description\": undefined,\n      \"name\": \"localReference\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"imported\",\n      },\n      \"description\": undefined,\n      \"name\": \"importedReference\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n      \"description\": undefined,\n      \"name\": \"globalReference\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'top'\",\n      },\n      \"description\": undefined,\n      \"name\": \"stringGlobalName\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n  ],\n}\n`;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-proptypes/docgen.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`react component properties js-proptypes 1`] = `\n\"import React from 'react';\nimport PropTypes, { string, shape } from 'prop-types';\nimport { PRESET_SHAPE, SOME_PROP_TYPES } from './ext';\nconst NAMED_OBJECT = {\n  text: PropTypes.string.isRequired,\n  value: PropTypes.string.isRequired\n};\nconst ANOTHER_OBJECT = {\n  foo: PropTypes.string,\n  bar: PropTypes.string\n};\nconst NAMED_SHAPE = PropTypes.shape({\n  foo: PropTypes.string\n});\nexport const POSITIONS = ['top-left', 'top-right', 'top-center'];\n\nconst FunctionalComponent = () => {\n  return /*#__PURE__*/React.createElement(\\\\\"div\\\\\", null, \\\\\"FunctionalComponent!\\\\\");\n};\n\nclass ClassComponent extends React.PureComponent {\n  render() {\n    return /*#__PURE__*/React.createElement(\\\\\"div\\\\\", null, \\\\\"ClassComponent!\\\\\");\n  }\n\n}\n\nfunction concat(a, b) {\n  return a + b;\n}\n\nfunction customPropType() {\n  return null;\n}\n\nconst nestedCustomPropType = {\n  custom: customPropType\n};\nconst SOME_INLINE_PROP_TYPES = {\n  /**\n   * Hey Hey!\n   */\n  inlineString: PropTypes.string,\n  inlineBool: PropTypes.bool,\n  inlineNumber: PropTypes.number,\n  inlineObj: PropTypes.shape({\n    foo: PropTypes.string\n  }),\n  inlineArray: PropTypes.arrayOf(PropTypes.number),\n  inlineArrayOfObjects: PropTypes.arrayOf({\n    foo: PropTypes.string\n  }),\n  inlineFunctionalElement: PropTypes.element,\n  inlineFunctionalElementInline: PropTypes.element,\n  inlineFunctionalElementInlineReturningNull: PropTypes.element,\n  inlineHtmlElement: PropTypes.element,\n  inlineFunctionalElementInlineWithProps: PropTypes.element,\n  inlineFunctionalElementNamedInline: PropTypes.element,\n  inlineClassElement: PropTypes.element,\n  inlineClassElementWithProps: PropTypes.element,\n  inlineClassElementWithChildren: PropTypes.element,\n  inlineClassElementInline: PropTypes.element,\n  inlineFunc: PropTypes.func\n};\nconst SOME_INLINE_DEFAULT_PROPS = {\n  inlineString: 'Inline prop default value',\n  inlineBool: true,\n  inlineNumber: 10,\n  inlineObj: {\n    foo: 'bar'\n  },\n  inlineArray: [1, 2, 3],\n  inlineArrayOfObjects: [{\n    foo: 'bar'\n  }, {\n    foo: 'bar'\n  }, {\n    foo: 'bar'\n  }, {\n    foo: 'bar'\n  }, {\n    foo: 'bar'\n  }],\n  inlineFunctionalElement: /*#__PURE__*/React.createElement(FunctionalComponent, null),\n  inlineFunctionalElementInline: () => {\n    return /*#__PURE__*/React.createElement(\\\\\"div\\\\\", null, \\\\\"Inlined FunctionalComponent!\\\\\");\n  },\n  inlineFunctionalElementInlineReturningNull: () => {\n    return null;\n  },\n  inlineHtmlElement: /*#__PURE__*/React.createElement(\\\\\"div\\\\\", null, \\\\\"Hey!\\\\\"),\n  inlineFunctionalElementInlineWithProps: ({\n    foo\n  }) => {\n    return /*#__PURE__*/React.createElement(\\\\\"div\\\\\", null, foo);\n  },\n  inlineFunctionalElementNamedInline: function InlinedFunctionalComponent() {\n    return /*#__PURE__*/React.createElement(\\\\\"div\\\\\", null, \\\\\"Inlined FunctionalComponent!\\\\\");\n  },\n  inlineClassElement: /*#__PURE__*/React.createElement(ClassComponent, null),\n  inlineClassElementWithProps: /*#__PURE__*/React.createElement(ClassComponent, {\n    className: \\\\\"toto\\\\\"\n  }),\n  inlineClassElementWithChildren: /*#__PURE__*/React.createElement(ClassComponent, null, /*#__PURE__*/React.createElement(\\\\\"div\\\\\", null, \\\\\"hey!\\\\\")),\n  inlineClassElementInline: class InlinedClassComponent extends React.PureComponent {\n    render() {\n      return /*#__PURE__*/React.createElement(\\\\\"div\\\\\", null, \\\\\"Inlined ClassComponent!\\\\\");\n    }\n\n  },\n  inlineFunc: function add(a, b) {\n    return a + b;\n  }\n};\nexport const PropTypesProps = () => /*#__PURE__*/React.createElement(\\\\\"div\\\\\", null, \\\\\"PropTypes!\\\\\");\nPropTypesProps.propTypes = {\n  any: PropTypes.any,\n  bool: PropTypes.bool,\n  string: PropTypes.string,\n  func: PropTypes.func,\n\n  /**\n   * A function with JSDoc tags.\n   *\n   * @param {string} foo - A foo value.\n   * @param {number} bar - A bar value.\n   * @returns {ComplexObject} - Returns a complex object.\n   */\n  funcWithJsDoc: PropTypes.func,\n\n  /**\n   * @param {string} foo - A foo value.\n   * @param {number} bar - A bar value.\n   * @param {number} bar1 - A bar value.\n   * @param {number} bar2 - A bar value.\n   * @param {number} bar3 - A bar value.\n   * @param {number} bar4 - A bar value.\n   * @param {number} bar5 - A bar value.\n   * @returns {ComplexObject} - Returns a complex object.\n   */\n  semiLongFuncWithJsDoc: PropTypes.func,\n\n  /**\n   * @param {string} foo - A foo value.\n   * @param {number} bar - A bar value.\n   * @param {number} bar1 - A bar value.\n   * @param {number} bar2 - A bar value.\n   * @param {number} bar3 - A bar value.\n   * @param {number} bar4 - A bar value.\n   * @param {number} bar5 - A bar value.\n   * @param {number} bar6 - A bar value.\n   * @param {number} bar7 - A bar value.\n   * @param {number} bar8 - A bar value.\n   * @param {number} bar9 - A bar value.\n   * @param {number} bar10 - A bar value.\n   * @returns {ComplexObject} - Returns a complex object.\n   */\n  veryLongFuncWithJsDoc: PropTypes.func,\n  namedDefaultFunc: PropTypes.func,\n  number: PropTypes.number,\n\n  /**\n   * Plain object propType (use shape!!)\n   */\n  obj: PropTypes.object,\n  symbol: PropTypes.symbol,\n  node: PropTypes.node,\n  useCustomPropType: customPropType,\n  useNestedCustomPropType: nestedCustomPropType.custom,\n  functionalElement: PropTypes.element,\n  functionalElementInline: PropTypes.element,\n  functionalElementNamedInline: PropTypes.element,\n  classElement: PropTypes.element,\n  classElementInline: PropTypes.element,\n  functionalElementType: PropTypes.elementType,\n  classElementType: PropTypes.elementType,\n  elementWithProps: PropTypes.elementType,\n\n  /**\n   * \\`instanceOf\\` is also supported and the custom type will be shown instead of \\`instanceOf\\`\n   */\n  instanceOf: PropTypes.instanceOf(Set),\n\n  /**\n   * \\`oneOf\\` is basically an Enum which is also supported but can be pretty big.\n   */\n  oneOfString: PropTypes.oneOf(['News', 'Photos']),\n  oneOfNumeric: PropTypes.oneOf([0, 1, 2, 3]),\n  oneOfShapes: PropTypes.oneOf([PropTypes.shape({\n    foo: PropTypes.string\n  }), PropTypes.shape({\n    bar: PropTypes.number\n  })]),\n  oneOfComplexShapes: PropTypes.oneOf([PropTypes.shape({\n    /**\n     *  Just an internal propType for a shape.\n     *  It's also required, and as you can see it supports multi-line comments!\n     */\n    id: PropTypes.number.isRequired,\n\n    /**\n     *  A simple non-required function\n     */\n    func: PropTypes.func,\n\n    /**\n     * An \\`arrayOf\\` shape\n     */\n    arr: PropTypes.arrayOf(PropTypes.shape({\n      /**\n       * 5-level deep propType definition and still works.\n       */\n      index: PropTypes.number.isRequired\n    }))\n  }), shape({\n    bar: PropTypes.number\n  })]),\n  oneOfComplexType: PropTypes.oneOf([NAMED_OBJECT, ANOTHER_OBJECT]),\n  oneOfComponents: PropTypes.oneOf([FunctionalComponent, ClassComponent]),\n  oneOfEval: PropTypes.oneOf((() => ['News', 'Photos'])()),\n  oneOfVar: PropTypes.oneOf(POSITIONS),\n  oneOfNested: PropTypes.oneOf(['News', ['bottom-left', 'bottom-center', 'bottom-right']]),\n  oneOfNestedSimpleInlineObject: PropTypes.oneOf(['News', [{\n    foo: PropTypes.string\n  }]]),\n  oneOfNestedComplexInlineObject: PropTypes.oneOf(['News', [{\n    nested: {\n      foo: PropTypes.string\n    }\n  }]]),\n  oneOfNestedComplexShape: PropTypes.oneOf(['News', [{\n    nested: PropTypes.shape({\n      foo: PropTypes.string\n    })\n  }]]),\n\n  /**\n   *  A multi-type prop is also valid and is displayed as \\`Union<String|Message>\\`\n   */\n  oneOfType: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Set)]),\n\n  /**\n   * array of a primitive type\n   */\n  arrayOfPrimitive: PropTypes.arrayOf(PropTypes.number),\n  arrayOfNamedObject: PropTypes.arrayOf(NAMED_OBJECT),\n  arrayOfShortInlineObject: PropTypes.arrayOf({\n    foo: PropTypes.string\n  }),\n  arrayOfInlineObject: PropTypes.arrayOf({\n    text: PropTypes.string.isRequired,\n    value: PropTypes.string.isRequired\n  }),\n  arrayOfComplexInlineObject: PropTypes.arrayOf({\n    text: PropTypes.string.isRequired,\n    value: PropTypes.string.isRequired,\n    shape: {\n      id: PropTypes.string.isRequired,\n      age: PropTypes.number.isRequired\n    }\n  }),\n  arrayOfShortShape: PropTypes.arrayOf(PropTypes.shape({\n    bar: PropTypes.string\n  })),\n  arrayOfComplexShape: PropTypes.arrayOf(PropTypes.shape({\n    /**\n     *  Just an internal propType for a shape.\n     *  It's also required, and as you can see it supports multi-line comments!\n     */\n    id: PropTypes.number.isRequired,\n\n    /**\n     *  A simple non-required function\n     */\n    func: PropTypes.func,\n\n    /**\n     * An \\`arrayOf\\` shape\n     */\n    arr: PropTypes.arrayOf(PropTypes.shape({\n      /**\n       * 5-level deep propType definition and still works.\n       */\n      index: PropTypes.number.isRequired\n    }))\n  })),\n  arrayExternalShape: PropTypes.arrayOf(PropTypes.shape(PRESET_SHAPE)),\n\n  /**\n   *  A simple \\`objectOf\\` propType.\n   */\n  simpleObjectOf: PropTypes.objectOf(PropTypes.number),\n  objectOfShortInlineObject: PropTypes.objectOf({\n    foo: PropTypes.string\n  }),\n  objectOfInlineObject: PropTypes.objectOf({\n    foo: PropTypes.string,\n    bar: PropTypes.string,\n    barry: PropTypes.string\n  }),\n  objectOfShortShape: PropTypes.objectOf(PropTypes.shape({\n    foo: string\n  })),\n\n  /**\n   *  A very complex \\`objectOf\\` propType.\n   */\n  objectOfComplexShape: PropTypes.objectOf(PropTypes.shape({\n    /**\n     *  Just an internal propType for a shape.\n     *  It's also required, and as you can see it supports multi-line comments!\n     */\n    id: PropTypes.number.isRequired,\n\n    /**\n     *  A simple non-required function\n     */\n    func: PropTypes.func,\n\n    /**\n     * An \\`arrayOf\\` shape\n     */\n    arr: PropTypes.arrayOf(PropTypes.shape({\n      /**\n       * 5-level deep propType definition and still works.\n       */\n      index: PropTypes.number.isRequired\n    }))\n  })),\n  namedObjectOf: PropTypes.objectOf(NAMED_OBJECT),\n  shapeShort: PropTypes.shape({\n    foo: string\n  }),\n  shapeLong: PropTypes.shape({\n    foo: string,\n    prop1: string,\n    prop2: string,\n    prop3: string,\n    prop4: string,\n    prop5: string,\n    prop6: string,\n    prop7: string\n  }),\n\n  /**\n   * propType for shape with nested arrayOf\n   *\n   * Also, multi-line description\n   */\n  shapeComplex: PropTypes.shape({\n    /**\n     *  Just an internal propType for a shape.\n     *  It's also required, and as you can see it supports multi-line comments!\n     */\n    id: PropTypes.number.isRequired,\n\n    /**\n     *  A simple non-required function\n     */\n    func: PropTypes.func,\n\n    /**\n     * An \\`arrayOf\\` shape\n     */\n    arr: PropTypes.arrayOf(PropTypes.shape({\n      /**\n       * 5-level deep propType definition and still works.\n       */\n      index: PropTypes.number.isRequired\n    })),\n    shape: PropTypes.shape({\n      shape: PropTypes.shape({\n        foo: PropTypes.string,\n        oneOf: PropTypes.oneOf(['one', 'two'])\n      })\n    }),\n    oneOf: PropTypes.oneOf(['one', 'two'])\n  }),\n  shapeWithArray: PropTypes.shape({\n    arr: PropTypes.arrayOf({\n      foo: PropTypes.string\n    })\n  }),\n  namedShape: NAMED_SHAPE,\n  namedObjectInShape: PropTypes.shape(NAMED_OBJECT),\n  exact: PropTypes.exact({\n    name: PropTypes.string,\n    quantity: PropTypes.number\n  }),\n  namedExact: PropTypes.exact(NAMED_OBJECT),\n\n  /**\n   * test string with a comment that has\n   * two identical lines\n   * two identical lines\n   */\n  optionalString: PropTypes.string,\n  requiredString: PropTypes.string.isRequired,\n  nullDefaultValue: PropTypes.string,\n  undefinedDefaultValue: PropTypes.string,\n  ...SOME_INLINE_PROP_TYPES,\n  ...SOME_PROP_TYPES\n};\nPropTypesProps.defaultProps = {\n  any: 'Default any',\n  bool: false,\n  string: 'Default string',\n  func: () => {},\n  funcWithJsDoc: (foo, bar) => {\n    // eslint-disable-next-line\n    const yo = window.document; // eslint-disable-next-line\n\n    const pouf = souffle;\n    return {\n      foo,\n      bar\n    };\n  },\n  namedDefaultFunc: concat,\n  number: 5,\n  obj: {\n    key: 'value'\n  },\n  symbol: Symbol('Default symbol'),\n  node: /*#__PURE__*/React.createElement(\\\\\"div\\\\\", null, \\\\\"Hello!\\\\\"),\n  functionalElement: /*#__PURE__*/React.createElement(FunctionalComponent, {\n    className: \\\\\"toto\\\\\"\n  }),\n  functionalElementInline: () => {\n    return /*#__PURE__*/React.createElement(\\\\\"div\\\\\", null, \\\\\"Inlined FunctionalComponent!\\\\\");\n  },\n  functionalElementNamedInline: function InlinedFunctionalComponent() {\n    return /*#__PURE__*/React.createElement(\\\\\"div\\\\\", null, \\\\\"Inlined FunctionalComponent!\\\\\");\n  },\n  classElement: /*#__PURE__*/React.createElement(ClassComponent, null),\n  classElementInline: class InlinedClassComponent extends React.PureComponent {\n    render() {\n      return /*#__PURE__*/React.createElement(\\\\\"div\\\\\", null, \\\\\"Inlined ClassComponent!\\\\\");\n    }\n\n  },\n  functionalElementType: FunctionalComponent,\n  classElementType: ClassComponent,\n  elementWithProps: /*#__PURE__*/React.createElement(ClassComponent, {\n    className: \\\\\"w8 h8 fill-marine-500\\\\\"\n  }),\n  instanceOf: new Set(),\n  oneOfString: 'News',\n  oneOfNumeric: 1,\n  oneOfShapes: {\n    foo: 'bar'\n  },\n  oneOfComplexShapes: {\n    thing: {\n      id: 2,\n      func: () => {},\n      arr: []\n    }\n  },\n  oneOfComplexType: {\n    text: 'foo',\n    value: 'bar'\n  },\n  oneOfComponents: /*#__PURE__*/React.createElement(FunctionalComponent, null),\n  oneOfEval: 'Photos',\n  oneOfVar: 'top-right',\n  oneOfNested: 'top-right',\n  oneOfType: 'hello',\n  arrayOfPrimitive: [1, 2, 3],\n  arrayOfString: ['0px', '0px'],\n  arrayOfNamedObject: [{\n    text: 'foo',\n    value: 'bar'\n  }],\n  arrayOfShortInlineObject: [{\n    foo: 'bar'\n  }],\n  arrayOfInlineObject: [{\n    text: 'foo',\n    value: 'bar'\n  }],\n  arrayOfComplexInlineObject: [{\n    text: 'foo',\n    value: 'bar'\n  }],\n  arrayOfShortShape: [{\n    bar: 'foo'\n  }],\n  arrayOfComplexShape: [{\n    thing: {\n      id: 2,\n      func: () => {},\n      arr: []\n    }\n  }],\n  simpleObjectOf: {\n    key: 1\n  },\n  objectOfShortInlineObject: {\n    foo: 'bar'\n  },\n  objectOfInlineObject: {\n    foo: 'bar',\n    bar: 'foo'\n  },\n  objectOfShortShape: {\n    foo: 'bar'\n  },\n  objectOfComplexShape: {\n    thing: {\n      id: 2,\n      func: () => {},\n      arr: []\n    }\n  },\n  namedObjectOf: {\n    text: 'foo',\n    value: 'bar'\n  },\n  shapeShort: {\n    foo: 'bar'\n  },\n  shapeComplex: {\n    id: 3,\n    func: () => {},\n    arr: [],\n    shape: {\n      shape: {\n        foo: 'bar'\n      }\n    }\n  },\n  namedShape: {\n    foo: 'bar'\n  },\n  namedObjectInShape: {\n    text: 'foo',\n    value: 'bar'\n  },\n  exact: {\n    name: 'foo',\n    quantity: 2\n  },\n  namedExact: {\n    text: 'foo',\n    value: 'bar'\n  },\n  optionalString: 'Default String',\n  nullDefaultValue: null,\n  undefinedDefaultValue: undefined,\n  ...SOME_INLINE_DEFAULT_PROPS\n};\nexport const component = PropTypesProps;\nPropTypesProps.__docgenInfo = {\n  \\\\\"description\\\\\": \\\\\"\\\\\",\n  \\\\\"methods\\\\\": [],\n  \\\\\"displayName\\\\\": \\\\\"PropTypesProps\\\\\",\n  \\\\\"props\\\\\": {\n    \\\\\"any\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'Default any'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"any\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"bool\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"false\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"bool\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"string\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'Default string'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"func\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"() => {}\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"func\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"funcWithJsDoc\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"(foo, bar) => {\\\\\\\\n  // eslint-disable-next-line\\\\\\\\n  const yo = window.document;\\\\\\\\n  // eslint-disable-next-line\\\\\\\\n  const pouf = souffle;\\\\\\\\n\\\\\\\\n  return { foo, bar };\\\\\\\\n}\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"A function with JSDoc tags.\\\\\\\\n\\\\\\\\n@param {string} foo - A foo value.\\\\\\\\n@param {number} bar - A bar value.\\\\\\\\n@returns {ComplexObject} - Returns a complex object.\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"func\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"namedDefaultFunc\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"function concat(a, b) {\\\\\\\\n  return a + b;\\\\\\\\n}\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"func\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"number\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"5\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"number\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"obj\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{\\\\\\\\n  key: 'value',\\\\\\\\n}\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"Plain object propType (use shape!!)\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"object\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"symbol\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"Symbol('Default symbol')\\\\\",\n        \\\\\"computed\\\\\": true\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"symbol\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"node\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"<div>Hello!</div>\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"node\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"functionalElement\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"<FunctionalComponent className=\\\\\\\\\\\\\"toto\\\\\\\\\\\\\" />\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"element\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"functionalElementInline\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"() => {\\\\\\\\n  return <div>Inlined FunctionalComponent!</div>;\\\\\\\\n}\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"element\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"functionalElementNamedInline\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"function InlinedFunctionalComponent() {\\\\\\\\n  return <div>Inlined FunctionalComponent!</div>;\\\\\\\\n}\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"element\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"classElement\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"<ClassComponent />\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"element\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"classElementInline\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"class InlinedClassComponent extends React.PureComponent {\\\\\\\\n  render() {\\\\\\\\n    return <div>Inlined ClassComponent!</div>;\\\\\\\\n  }\\\\\\\\n}\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"element\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"functionalElementType\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"() => {\\\\\\\\n  return <div>FunctionalComponent!</div>;\\\\\\\\n}\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"elementType\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"classElementType\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"class ClassComponent extends React.PureComponent {\\\\\\\\n  render() {\\\\\\\\n    return <div>ClassComponent!</div>;\\\\\\\\n  }\\\\\\\\n}\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"elementType\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"elementWithProps\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"<ClassComponent className=\\\\\\\\\\\\\"w8 h8 fill-marine-500\\\\\\\\\\\\\" />\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"elementType\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"instanceOf\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"new Set()\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\`instanceOf\\` is also supported and the custom type will be shown instead of \\`instanceOf\\`\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"instanceOf\\\\\",\n        \\\\\"value\\\\\": \\\\\"Set\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"oneOfString\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'News'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\`oneOf\\` is basically an Enum which is also supported but can be pretty big.\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"enum\\\\\",\n        \\\\\"value\\\\\": [{\n          \\\\\"value\\\\\": \\\\\"'News'\\\\\",\n          \\\\\"computed\\\\\": false\n        }, {\n          \\\\\"value\\\\\": \\\\\"'Photos'\\\\\",\n          \\\\\"computed\\\\\": false\n        }]\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"oneOfNumeric\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"1\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"enum\\\\\",\n        \\\\\"value\\\\\": [{\n          \\\\\"value\\\\\": \\\\\"0\\\\\",\n          \\\\\"computed\\\\\": false\n        }, {\n          \\\\\"value\\\\\": \\\\\"1\\\\\",\n          \\\\\"computed\\\\\": false\n        }, {\n          \\\\\"value\\\\\": \\\\\"2\\\\\",\n          \\\\\"computed\\\\\": false\n        }, {\n          \\\\\"value\\\\\": \\\\\"3\\\\\",\n          \\\\\"computed\\\\\": false\n        }]\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"oneOfShapes\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{ foo: 'bar' }\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"enum\\\\\",\n        \\\\\"value\\\\\": [{\n          \\\\\"value\\\\\": \\\\\"PropTypes.shape({ foo: PropTypes.string })\\\\\",\n          \\\\\"computed\\\\\": true\n        }, {\n          \\\\\"value\\\\\": \\\\\"PropTypes.shape({ bar: PropTypes.number })\\\\\",\n          \\\\\"computed\\\\\": true\n        }]\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"oneOfComplexShapes\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{\\\\\\\\n  thing: {\\\\\\\\n    id: 2,\\\\\\\\n    func: () => {},\\\\\\\\n    arr: [],\\\\\\\\n  },\\\\\\\\n}\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"enum\\\\\",\n        \\\\\"value\\\\\": [{\n          \\\\\"value\\\\\": \\\\\"PropTypes.shape({\\\\\\\\n  /**\\\\\\\\n   *  Just an internal propType for a shape.\\\\\\\\n   *  It's also required, and as you can see it supports multi-line comments!\\\\\\\\n   */\\\\\\\\n  id: PropTypes.number.isRequired,\\\\\\\\n  /**\\\\\\\\n   *  A simple non-required function\\\\\\\\n   */\\\\\\\\n  func: PropTypes.func,\\\\\\\\n  /**\\\\\\\\n   * An \\`arrayOf\\` shape\\\\\\\\n   */\\\\\\\\n  arr: PropTypes.arrayOf(\\\\\\\\n    PropTypes.shape({\\\\\\\\n      /**\\\\\\\\n       * 5-level deep propType definition and still works.\\\\\\\\n       */\\\\\\\\n      index: PropTypes.number.isRequired,\\\\\\\\n    })\\\\\\\\n  ),\\\\\\\\n})\\\\\",\n          \\\\\"computed\\\\\": true\n        }, {\n          \\\\\"value\\\\\": \\\\\"shape({ bar: PropTypes.number })\\\\\",\n          \\\\\"computed\\\\\": true\n        }]\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"oneOfComplexType\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{ text: 'foo', value: 'bar' }\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"enum\\\\\",\n        \\\\\"value\\\\\": [{\n          \\\\\"value\\\\\": \\\\\"{\\\\\\\\n  text: PropTypes.string.isRequired,\\\\\\\\n  value: PropTypes.string.isRequired,\\\\\\\\n}\\\\\",\n          \\\\\"computed\\\\\": true\n        }, {\n          \\\\\"value\\\\\": \\\\\"{\\\\\\\\n  foo: PropTypes.string,\\\\\\\\n  bar: PropTypes.string,\\\\\\\\n}\\\\\",\n          \\\\\"computed\\\\\": true\n        }]\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"oneOfComponents\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"<FunctionalComponent />\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"enum\\\\\",\n        \\\\\"value\\\\\": [{\n          \\\\\"value\\\\\": \\\\\"() => {\\\\\\\\n  return <div>FunctionalComponent!</div>;\\\\\\\\n}\\\\\",\n          \\\\\"computed\\\\\": true\n        }, {\n          \\\\\"value\\\\\": \\\\\"class ClassComponent extends React.PureComponent {\\\\\\\\n  render() {\\\\\\\\n    return <div>ClassComponent!</div>;\\\\\\\\n  }\\\\\\\\n}\\\\\",\n          \\\\\"computed\\\\\": true\n        }]\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"oneOfEval\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'Photos'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"enum\\\\\",\n        \\\\\"computed\\\\\": true,\n        \\\\\"value\\\\\": \\\\\"(() => ['News', 'Photos'])()\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"oneOfVar\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'top-right'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"enum\\\\\",\n        \\\\\"value\\\\\": [{\n          \\\\\"value\\\\\": \\\\\"'top-left'\\\\\",\n          \\\\\"computed\\\\\": false\n        }, {\n          \\\\\"value\\\\\": \\\\\"'top-right'\\\\\",\n          \\\\\"computed\\\\\": false\n        }, {\n          \\\\\"value\\\\\": \\\\\"'top-center'\\\\\",\n          \\\\\"computed\\\\\": false\n        }]\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"oneOfNested\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'top-right'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"enum\\\\\",\n        \\\\\"value\\\\\": [{\n          \\\\\"value\\\\\": \\\\\"'News'\\\\\",\n          \\\\\"computed\\\\\": false\n        }, {\n          \\\\\"value\\\\\": \\\\\"['bottom-left', 'bottom-center', 'bottom-right']\\\\\",\n          \\\\\"computed\\\\\": true\n        }]\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"oneOfType\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'hello'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"A multi-type prop is also valid and is displayed as \\`Union<String|Message>\\`\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"union\\\\\",\n        \\\\\"value\\\\\": [{\n          \\\\\"name\\\\\": \\\\\"string\\\\\"\n        }, {\n          \\\\\"name\\\\\": \\\\\"instanceOf\\\\\",\n          \\\\\"value\\\\\": \\\\\"Set\\\\\"\n        }]\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"arrayOfPrimitive\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"[1, 2, 3]\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"array of a primitive type\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"arrayOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"number\\\\\"\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"arrayOfString\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"['0px', '0px']\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"arrayOfNamedObject\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"[{ text: 'foo', value: 'bar' }]\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"arrayOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"custom\\\\\",\n          \\\\\"raw\\\\\": \\\\\"NAMED_OBJECT\\\\\"\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"arrayOfShortInlineObject\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"[{ foo: 'bar' }]\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"arrayOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"custom\\\\\",\n          \\\\\"raw\\\\\": \\\\\"{\\\\\\\\n  foo: PropTypes.string,\\\\\\\\n}\\\\\"\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"arrayOfInlineObject\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"[{ text: 'foo', value: 'bar' }]\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"arrayOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"custom\\\\\",\n          \\\\\"raw\\\\\": \\\\\"{\\\\\\\\n  text: PropTypes.string.isRequired,\\\\\\\\n  value: PropTypes.string.isRequired,\\\\\\\\n}\\\\\"\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"arrayOfComplexInlineObject\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"[{ text: 'foo', value: 'bar' }]\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"arrayOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"custom\\\\\",\n          \\\\\"raw\\\\\": \\\\\"{\\\\\\\\n  text: PropTypes.string.isRequired,\\\\\\\\n  value: PropTypes.string.isRequired,\\\\\\\\n  shape: {\\\\\\\\n    id: PropTypes.string.isRequired,\\\\\\\\n    age: PropTypes.number.isRequired,\\\\\\\\n  },\\\\\\\\n}\\\\\"\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"arrayOfShortShape\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"[{ bar: 'foo' }]\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"arrayOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"shape\\\\\",\n          \\\\\"value\\\\\": {\n            \\\\\"bar\\\\\": {\n              \\\\\"name\\\\\": \\\\\"string\\\\\",\n              \\\\\"required\\\\\": false\n            }\n          }\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"arrayOfComplexShape\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"[\\\\\\\\n  {\\\\\\\\n    thing: {\\\\\\\\n      id: 2,\\\\\\\\n      func: () => {},\\\\\\\\n      arr: [],\\\\\\\\n    },\\\\\\\\n  },\\\\\\\\n]\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"arrayOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"shape\\\\\",\n          \\\\\"value\\\\\": {\n            \\\\\"id\\\\\": {\n              \\\\\"name\\\\\": \\\\\"number\\\\\",\n              \\\\\"description\\\\\": \\\\\"Just an internal propType for a shape.\\\\\\\\n It's also required, and as you can see it supports multi-line comments!\\\\\",\n              \\\\\"required\\\\\": true\n            },\n            \\\\\"func\\\\\": {\n              \\\\\"name\\\\\": \\\\\"func\\\\\",\n              \\\\\"description\\\\\": \\\\\"A simple non-required function\\\\\",\n              \\\\\"required\\\\\": false\n            },\n            \\\\\"arr\\\\\": {\n              \\\\\"name\\\\\": \\\\\"arrayOf\\\\\",\n              \\\\\"value\\\\\": {\n                \\\\\"name\\\\\": \\\\\"shape\\\\\",\n                \\\\\"value\\\\\": {\n                  \\\\\"index\\\\\": {\n                    \\\\\"name\\\\\": \\\\\"number\\\\\",\n                    \\\\\"description\\\\\": \\\\\"5-level deep propType definition and still works.\\\\\",\n                    \\\\\"required\\\\\": true\n                  }\n                }\n              },\n              \\\\\"description\\\\\": \\\\\"An \\`arrayOf\\` shape\\\\\",\n              \\\\\"required\\\\\": false\n            }\n          }\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"simpleObjectOf\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{ key: 1 }\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"A simple \\`objectOf\\` propType.\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"objectOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"number\\\\\"\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"objectOfShortInlineObject\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{ foo: 'bar' }\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"objectOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"custom\\\\\",\n          \\\\\"raw\\\\\": \\\\\"{\\\\\\\\n  foo: PropTypes.string,\\\\\\\\n}\\\\\"\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"objectOfInlineObject\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{ foo: 'bar', bar: 'foo' }\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"objectOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"custom\\\\\",\n          \\\\\"raw\\\\\": \\\\\"{\\\\\\\\n  foo: PropTypes.string,\\\\\\\\n  bar: PropTypes.string,\\\\\\\\n  barry: PropTypes.string,\\\\\\\\n}\\\\\"\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"objectOfShortShape\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{ foo: 'bar' }\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"objectOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"shape\\\\\",\n          \\\\\"value\\\\\": {\n            \\\\\"foo\\\\\": {\n              \\\\\"name\\\\\": \\\\\"string\\\\\",\n              \\\\\"required\\\\\": false\n            }\n          }\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"objectOfComplexShape\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{\\\\\\\\n  thing: {\\\\\\\\n    id: 2,\\\\\\\\n    func: () => {},\\\\\\\\n    arr: [],\\\\\\\\n  },\\\\\\\\n}\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"A very complex \\`objectOf\\` propType.\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"objectOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"shape\\\\\",\n          \\\\\"value\\\\\": {\n            \\\\\"id\\\\\": {\n              \\\\\"name\\\\\": \\\\\"number\\\\\",\n              \\\\\"description\\\\\": \\\\\"Just an internal propType for a shape.\\\\\\\\n It's also required, and as you can see it supports multi-line comments!\\\\\",\n              \\\\\"required\\\\\": true\n            },\n            \\\\\"func\\\\\": {\n              \\\\\"name\\\\\": \\\\\"func\\\\\",\n              \\\\\"description\\\\\": \\\\\"A simple non-required function\\\\\",\n              \\\\\"required\\\\\": false\n            },\n            \\\\\"arr\\\\\": {\n              \\\\\"name\\\\\": \\\\\"arrayOf\\\\\",\n              \\\\\"value\\\\\": {\n                \\\\\"name\\\\\": \\\\\"shape\\\\\",\n                \\\\\"value\\\\\": {\n                  \\\\\"index\\\\\": {\n                    \\\\\"name\\\\\": \\\\\"number\\\\\",\n                    \\\\\"description\\\\\": \\\\\"5-level deep propType definition and still works.\\\\\",\n                    \\\\\"required\\\\\": true\n                  }\n                }\n              },\n              \\\\\"description\\\\\": \\\\\"An \\`arrayOf\\` shape\\\\\",\n              \\\\\"required\\\\\": false\n            }\n          }\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"namedObjectOf\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{ text: 'foo', value: 'bar' }\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"objectOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"custom\\\\\",\n          \\\\\"raw\\\\\": \\\\\"NAMED_OBJECT\\\\\"\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"shapeShort\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{ foo: 'bar' }\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"shape\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"foo\\\\\": {\n            \\\\\"name\\\\\": \\\\\"string\\\\\",\n            \\\\\"required\\\\\": false\n          }\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"shapeComplex\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{\\\\\\\\n  id: 3,\\\\\\\\n  func: () => {},\\\\\\\\n  arr: [],\\\\\\\\n  shape: {\\\\\\\\n    shape: {\\\\\\\\n      foo: 'bar',\\\\\\\\n    },\\\\\\\\n  },\\\\\\\\n}\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"propType for shape with nested arrayOf\\\\\\\\n\\\\\\\\nAlso, multi-line description\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"shape\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"id\\\\\": {\n            \\\\\"name\\\\\": \\\\\"number\\\\\",\n            \\\\\"description\\\\\": \\\\\"Just an internal propType for a shape.\\\\\\\\n It's also required, and as you can see it supports multi-line comments!\\\\\",\n            \\\\\"required\\\\\": true\n          },\n          \\\\\"func\\\\\": {\n            \\\\\"name\\\\\": \\\\\"func\\\\\",\n            \\\\\"description\\\\\": \\\\\"A simple non-required function\\\\\",\n            \\\\\"required\\\\\": false\n          },\n          \\\\\"arr\\\\\": {\n            \\\\\"name\\\\\": \\\\\"arrayOf\\\\\",\n            \\\\\"value\\\\\": {\n              \\\\\"name\\\\\": \\\\\"shape\\\\\",\n              \\\\\"value\\\\\": {\n                \\\\\"index\\\\\": {\n                  \\\\\"name\\\\\": \\\\\"number\\\\\",\n                  \\\\\"description\\\\\": \\\\\"5-level deep propType definition and still works.\\\\\",\n                  \\\\\"required\\\\\": true\n                }\n              }\n            },\n            \\\\\"description\\\\\": \\\\\"An \\`arrayOf\\` shape\\\\\",\n            \\\\\"required\\\\\": false\n          },\n          \\\\\"shape\\\\\": {\n            \\\\\"name\\\\\": \\\\\"shape\\\\\",\n            \\\\\"value\\\\\": {\n              \\\\\"shape\\\\\": {\n                \\\\\"name\\\\\": \\\\\"shape\\\\\",\n                \\\\\"value\\\\\": {\n                  \\\\\"foo\\\\\": {\n                    \\\\\"name\\\\\": \\\\\"string\\\\\",\n                    \\\\\"required\\\\\": false\n                  },\n                  \\\\\"oneOf\\\\\": {\n                    \\\\\"name\\\\\": \\\\\"enum\\\\\",\n                    \\\\\"value\\\\\": [{\n                      \\\\\"value\\\\\": \\\\\"'one'\\\\\",\n                      \\\\\"computed\\\\\": false\n                    }, {\n                      \\\\\"value\\\\\": \\\\\"'two'\\\\\",\n                      \\\\\"computed\\\\\": false\n                    }],\n                    \\\\\"required\\\\\": false\n                  }\n                },\n                \\\\\"required\\\\\": false\n              }\n            },\n            \\\\\"required\\\\\": false\n          },\n          \\\\\"oneOf\\\\\": {\n            \\\\\"name\\\\\": \\\\\"enum\\\\\",\n            \\\\\"value\\\\\": [{\n              \\\\\"value\\\\\": \\\\\"'one'\\\\\",\n              \\\\\"computed\\\\\": false\n            }, {\n              \\\\\"value\\\\\": \\\\\"'two'\\\\\",\n              \\\\\"computed\\\\\": false\n            }],\n            \\\\\"required\\\\\": false\n          }\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"namedShape\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{ foo: 'bar' }\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"custom\\\\\",\n        \\\\\"raw\\\\\": \\\\\"NAMED_SHAPE\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"namedObjectInShape\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{ text: 'foo', value: 'bar' }\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"shape\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"text\\\\\": {\n            \\\\\"name\\\\\": \\\\\"string\\\\\",\n            \\\\\"required\\\\\": true\n          },\n          \\\\\"value\\\\\": {\n            \\\\\"name\\\\\": \\\\\"string\\\\\",\n            \\\\\"required\\\\\": true\n          }\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"exact\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{ name: 'foo', quantity: 2 }\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"exact\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": {\n            \\\\\"name\\\\\": \\\\\"string\\\\\",\n            \\\\\"required\\\\\": false\n          },\n          \\\\\"quantity\\\\\": {\n            \\\\\"name\\\\\": \\\\\"number\\\\\",\n            \\\\\"required\\\\\": false\n          }\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"namedExact\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{ text: 'foo', value: 'bar' }\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"exact\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"text\\\\\": {\n            \\\\\"name\\\\\": \\\\\"string\\\\\",\n            \\\\\"required\\\\\": true\n          },\n          \\\\\"value\\\\\": {\n            \\\\\"name\\\\\": \\\\\"string\\\\\",\n            \\\\\"required\\\\\": true\n          }\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"optionalString\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'Default String'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"test string with a comment that has\\\\\\\\ntwo identical lines\\\\\\\\ntwo identical lines\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"nullDefaultValue\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"null\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"undefinedDefaultValue\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"undefined\\\\\",\n        \\\\\"computed\\\\\": true\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"inlineString\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'Inline prop default value'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"Hey Hey!\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"inlineBool\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"true\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"bool\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"inlineNumber\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"10\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"number\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"inlineObj\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{ foo: 'bar' }\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"shape\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"foo\\\\\": {\n            \\\\\"name\\\\\": \\\\\"string\\\\\",\n            \\\\\"required\\\\\": false\n          }\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"inlineArray\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"[1, 2, 3]\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"arrayOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"number\\\\\"\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"inlineArrayOfObjects\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"[\\\\\\\\n  { foo: 'bar' },\\\\\\\\n  { foo: 'bar' },\\\\\\\\n  { foo: 'bar' },\\\\\\\\n  { foo: 'bar' },\\\\\\\\n  { foo: 'bar' },\\\\\\\\n]\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"arrayOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"custom\\\\\",\n          \\\\\"raw\\\\\": \\\\\"{ foo: PropTypes.string }\\\\\"\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"inlineFunctionalElement\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"<FunctionalComponent />\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"element\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"inlineFunctionalElementInline\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"() => {\\\\\\\\n  return <div>Inlined FunctionalComponent!</div>;\\\\\\\\n}\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"element\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"inlineFunctionalElementInlineReturningNull\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"() => {\\\\\\\\n  return null;\\\\\\\\n}\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"element\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"inlineHtmlElement\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"<div>Hey!</div>\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"element\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"inlineFunctionalElementInlineWithProps\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"({ foo }) => {\\\\\\\\n  return <div>{foo}</div>;\\\\\\\\n}\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"element\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"inlineFunctionalElementNamedInline\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"function InlinedFunctionalComponent() {\\\\\\\\n  return <div>Inlined FunctionalComponent!</div>;\\\\\\\\n}\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"element\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"inlineClassElement\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"<ClassComponent />\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"element\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"inlineClassElementWithProps\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"<ClassComponent className=\\\\\\\\\\\\\"toto\\\\\\\\\\\\\" />\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"element\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"inlineClassElementWithChildren\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"<ClassComponent>\\\\\\\\n  <div>hey!</div>\\\\\\\\n</ClassComponent>\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"element\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"inlineClassElementInline\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"class InlinedClassComponent extends React.PureComponent {\\\\\\\\n  render() {\\\\\\\\n    return <div>Inlined ClassComponent!</div>;\\\\\\\\n  }\\\\\\\\n}\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"element\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"inlineFunc\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"function add(a, b) {\\\\\\\\n  return a + b;\\\\\\\\n}\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"func\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"semiLongFuncWithJsDoc\\\\\": {\n      \\\\\"description\\\\\": \\\\\"@param {string} foo - A foo value.\\\\\\\\n@param {number} bar - A bar value.\\\\\\\\n@param {number} bar1 - A bar value.\\\\\\\\n@param {number} bar2 - A bar value.\\\\\\\\n@param {number} bar3 - A bar value.\\\\\\\\n@param {number} bar4 - A bar value.\\\\\\\\n@param {number} bar5 - A bar value.\\\\\\\\n@returns {ComplexObject} - Returns a complex object.\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"func\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"veryLongFuncWithJsDoc\\\\\": {\n      \\\\\"description\\\\\": \\\\\"@param {string} foo - A foo value.\\\\\\\\n@param {number} bar - A bar value.\\\\\\\\n@param {number} bar1 - A bar value.\\\\\\\\n@param {number} bar2 - A bar value.\\\\\\\\n@param {number} bar3 - A bar value.\\\\\\\\n@param {number} bar4 - A bar value.\\\\\\\\n@param {number} bar5 - A bar value.\\\\\\\\n@param {number} bar6 - A bar value.\\\\\\\\n@param {number} bar7 - A bar value.\\\\\\\\n@param {number} bar8 - A bar value.\\\\\\\\n@param {number} bar9 - A bar value.\\\\\\\\n@param {number} bar10 - A bar value.\\\\\\\\n@returns {ComplexObject} - Returns a complex object.\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"func\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"useCustomPropType\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"custom\\\\\",\n        \\\\\"raw\\\\\": \\\\\"customPropType\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"useNestedCustomPropType\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"custom\\\\\",\n        \\\\\"raw\\\\\": \\\\\"nestedCustomPropType.custom\\\\\"\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"oneOfNestedSimpleInlineObject\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"enum\\\\\",\n        \\\\\"value\\\\\": [{\n          \\\\\"value\\\\\": \\\\\"'News'\\\\\",\n          \\\\\"computed\\\\\": false\n        }, {\n          \\\\\"value\\\\\": \\\\\"[{ foo: PropTypes.string }]\\\\\",\n          \\\\\"computed\\\\\": true\n        }]\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"oneOfNestedComplexInlineObject\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"enum\\\\\",\n        \\\\\"value\\\\\": [{\n          \\\\\"value\\\\\": \\\\\"'News'\\\\\",\n          \\\\\"computed\\\\\": false\n        }, {\n          \\\\\"value\\\\\": \\\\\"[{ nested: { foo: PropTypes.string } }]\\\\\",\n          \\\\\"computed\\\\\": true\n        }]\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"oneOfNestedComplexShape\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"enum\\\\\",\n        \\\\\"value\\\\\": [{\n          \\\\\"value\\\\\": \\\\\"'News'\\\\\",\n          \\\\\"computed\\\\\": false\n        }, {\n          \\\\\"value\\\\\": \\\\\"[{ nested: PropTypes.shape({ foo: PropTypes.string }) }]\\\\\",\n          \\\\\"computed\\\\\": true\n        }]\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"arrayExternalShape\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"arrayOf\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"name\\\\\": \\\\\"shape\\\\\",\n          \\\\\"value\\\\\": \\\\\"import { PRESET_SHAPE, SOME_PROP_TYPES } from './ext';\\\\\",\n          \\\\\"computed\\\\\": true\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"shapeLong\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"shape\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"foo\\\\\": {\n            \\\\\"name\\\\\": \\\\\"string\\\\\",\n            \\\\\"required\\\\\": false\n          },\n          \\\\\"prop1\\\\\": {\n            \\\\\"name\\\\\": \\\\\"string\\\\\",\n            \\\\\"required\\\\\": false\n          },\n          \\\\\"prop2\\\\\": {\n            \\\\\"name\\\\\": \\\\\"string\\\\\",\n            \\\\\"required\\\\\": false\n          },\n          \\\\\"prop3\\\\\": {\n            \\\\\"name\\\\\": \\\\\"string\\\\\",\n            \\\\\"required\\\\\": false\n          },\n          \\\\\"prop4\\\\\": {\n            \\\\\"name\\\\\": \\\\\"string\\\\\",\n            \\\\\"required\\\\\": false\n          },\n          \\\\\"prop5\\\\\": {\n            \\\\\"name\\\\\": \\\\\"string\\\\\",\n            \\\\\"required\\\\\": false\n          },\n          \\\\\"prop6\\\\\": {\n            \\\\\"name\\\\\": \\\\\"string\\\\\",\n            \\\\\"required\\\\\": false\n          },\n          \\\\\"prop7\\\\\": {\n            \\\\\"name\\\\\": \\\\\"string\\\\\",\n            \\\\\"required\\\\\": false\n          }\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"shapeWithArray\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"shape\\\\\",\n        \\\\\"value\\\\\": {\n          \\\\\"arr\\\\\": {\n            \\\\\"name\\\\\": \\\\\"arrayOf\\\\\",\n            \\\\\"value\\\\\": {\n              \\\\\"name\\\\\": \\\\\"custom\\\\\",\n              \\\\\"raw\\\\\": \\\\\"{ foo: PropTypes.string }\\\\\"\n            },\n            \\\\\"required\\\\\": false\n          }\n        }\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"requiredString\\\\\": {\n      \\\\\"description\\\\\": \\\\\"\\\\\",\n      \\\\\"type\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"required\\\\\": true\n    }\n  },\n  \\\\\"composes\\\\\": [\\\\\"./ext\\\\\"]\n};\"\n`;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-proptypes/ext.js",
    "content": "// @ts-expect-error (Converted from ts-ignore)\nimport PropTypes from 'prop-types';\n\nexport const PRESET_SHAPE = {\n  text: PropTypes.string.isRequired,\n  startDate: PropTypes.object.isRequired,\n  endDate: PropTypes.object.isRequired,\n};\n\nexport const SOME_PROP_TYPES = {\n  ext1: PropTypes.string,\n  ext2: PropTypes.number,\n};\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-proptypes/input.jsx",
    "content": "import React from 'react';\n\nimport PropTypes, { shape, string } from 'prop-types';\n\nimport { PRESET_SHAPE, SOME_PROP_TYPES } from './ext';\n\nconst NAMED_OBJECT = {\n  text: PropTypes.string.isRequired,\n  value: PropTypes.string.isRequired,\n};\n\nconst ANOTHER_OBJECT = {\n  foo: PropTypes.string,\n  bar: PropTypes.string,\n};\n\nconst NAMED_SHAPE = PropTypes.shape({\n  foo: PropTypes.string,\n});\n\nexport const POSITIONS = ['top-left', 'top-right', 'top-center'];\n\nconst FunctionalComponent = () => {\n  return <div>FunctionalComponent!</div>;\n};\n\nclass ClassComponent extends React.PureComponent {\n  render() {\n    return <div>ClassComponent!</div>;\n  }\n}\n\nfunction concat(a, b) {\n  return a + b;\n}\n\nfunction customPropType() {\n  return null;\n}\n\nconst nestedCustomPropType = {\n  custom: customPropType,\n};\n\nconst SOME_INLINE_PROP_TYPES = {\n  /** Hey Hey! */\n  inlineString: PropTypes.string,\n  inlineBool: PropTypes.bool,\n  inlineNumber: PropTypes.number,\n  inlineObj: PropTypes.shape({\n    foo: PropTypes.string,\n  }),\n  inlineArray: PropTypes.arrayOf(PropTypes.number),\n  inlineArrayOfObjects: PropTypes.arrayOf({ foo: PropTypes.string }),\n  inlineFunctionalElement: PropTypes.element,\n  inlineFunctionalElementInline: PropTypes.element,\n  inlineFunctionalElementInlineReturningNull: PropTypes.element,\n  inlineHtmlElement: PropTypes.element,\n  inlineFunctionalElementInlineWithProps: PropTypes.element,\n  inlineFunctionalElementNamedInline: PropTypes.element,\n  inlineClassElement: PropTypes.element,\n  inlineClassElementWithProps: PropTypes.element,\n  inlineClassElementWithChildren: PropTypes.element,\n  inlineClassElementInline: PropTypes.element,\n  inlineFunc: PropTypes.func,\n};\n\nconst SOME_INLINE_DEFAULT_PROPS = {\n  inlineString: 'Inline prop default value',\n  inlineBool: true,\n  inlineNumber: 10,\n  inlineObj: { foo: 'bar' },\n  inlineArray: [1, 2, 3],\n  inlineArrayOfObjects: [\n    { foo: 'bar' },\n    { foo: 'bar' },\n    { foo: 'bar' },\n    { foo: 'bar' },\n    { foo: 'bar' },\n  ],\n  inlineFunctionalElement: <FunctionalComponent />,\n  inlineFunctionalElementInline: () => {\n    return <div>Inlined FunctionalComponent!</div>;\n  },\n  inlineFunctionalElementInlineReturningNull: () => {\n    return null;\n  },\n  inlineHtmlElement: <div>Hey!</div>,\n  inlineFunctionalElementInlineWithProps: ({ foo }) => {\n    return <div>{foo}</div>;\n  },\n  inlineFunctionalElementNamedInline: function InlinedFunctionalComponent() {\n    return <div>Inlined FunctionalComponent!</div>;\n  },\n  inlineClassElement: <ClassComponent />,\n  inlineClassElementWithProps: <ClassComponent className=\"toto\" />,\n  inlineClassElementWithChildren: (\n    <ClassComponent>\n      <div>hey!</div>\n    </ClassComponent>\n  ),\n  inlineClassElementInline: class InlinedClassComponent extends React.PureComponent {\n    render() {\n      return <div>Inlined ClassComponent!</div>;\n    }\n  },\n  inlineFunc: function add(a, b) {\n    return a + b;\n  },\n};\n\nexport const PropTypesProps = () => <div>PropTypes!</div>;\n\nPropTypesProps.propTypes = {\n  any: PropTypes.any,\n  bool: PropTypes.bool,\n  string: PropTypes.string,\n  func: PropTypes.func,\n  /**\n   * A function with JSDoc tags.\n   *\n   * @param {string} foo - A foo value.\n   * @param {number} bar - A bar value.\n   * @returns {ComplexObject} - Returns a complex object.\n   */\n  funcWithJsDoc: PropTypes.func,\n  /**\n   * @param {string} foo - A foo value.\n   * @param {number} bar - A bar value.\n   * @param {number} bar1 - A bar value.\n   * @param {number} bar2 - A bar value.\n   * @param {number} bar3 - A bar value.\n   * @param {number} bar4 - A bar value.\n   * @param {number} bar5 - A bar value.\n   * @returns {ComplexObject} - Returns a complex object.\n   */\n  semiLongFuncWithJsDoc: PropTypes.func,\n  /**\n   * @param {string} foo - A foo value.\n   * @param {number} bar - A bar value.\n   * @param {number} bar1 - A bar value.\n   * @param {number} bar2 - A bar value.\n   * @param {number} bar3 - A bar value.\n   * @param {number} bar4 - A bar value.\n   * @param {number} bar5 - A bar value.\n   * @param {number} bar6 - A bar value.\n   * @param {number} bar7 - A bar value.\n   * @param {number} bar8 - A bar value.\n   * @param {number} bar9 - A bar value.\n   * @param {number} bar10 - A bar value.\n   * @returns {ComplexObject} - Returns a complex object.\n   */\n  veryLongFuncWithJsDoc: PropTypes.func,\n  namedDefaultFunc: PropTypes.func,\n  number: PropTypes.number,\n  /** Plain object propType (use shape!!) */\n  obj: PropTypes.object,\n  symbol: PropTypes.symbol,\n  node: PropTypes.node,\n  useCustomPropType: customPropType,\n  useNestedCustomPropType: nestedCustomPropType.custom,\n  functionalElement: PropTypes.element,\n  functionalElementInline: PropTypes.element,\n  functionalElementNamedInline: PropTypes.element,\n  classElement: PropTypes.element,\n  classElementInline: PropTypes.element,\n  functionalElementType: PropTypes.elementType,\n  classElementType: PropTypes.elementType,\n  elementWithProps: PropTypes.elementType,\n  /** `instanceOf` is also supported and the custom type will be shown instead of `instanceOf` */\n  instanceOf: PropTypes.instanceOf(Set),\n  /** `oneOf` is basically an Enum which is also supported but can be pretty big. */\n  oneOfString: PropTypes.oneOf(['News', 'Photos']),\n  oneOfNumeric: PropTypes.oneOf([0, 1, 2, 3]),\n  oneOfShapes: PropTypes.oneOf([\n    PropTypes.shape({ foo: PropTypes.string }),\n    PropTypes.shape({ bar: PropTypes.number }),\n  ]),\n  oneOfComplexShapes: PropTypes.oneOf([\n    PropTypes.shape({\n      /**\n       * Just an internal propType for a shape. It's also required, and as you can see it supports\n       * multi-line comments!\n       */\n      id: PropTypes.number.isRequired,\n      /** A simple non-required function */\n      func: PropTypes.func,\n      /** An `arrayOf` shape */\n      arr: PropTypes.arrayOf(\n        PropTypes.shape({\n          /** 5-level deep propType definition and still works. */\n          index: PropTypes.number.isRequired,\n        })\n      ),\n    }),\n    shape({ bar: PropTypes.number }),\n  ]),\n  oneOfComplexType: PropTypes.oneOf([NAMED_OBJECT, ANOTHER_OBJECT]),\n  oneOfComponents: PropTypes.oneOf([FunctionalComponent, ClassComponent]),\n  oneOfEval: PropTypes.oneOf((() => ['News', 'Photos'])()),\n  oneOfVar: PropTypes.oneOf(POSITIONS),\n  oneOfNested: PropTypes.oneOf(['News', ['bottom-left', 'bottom-center', 'bottom-right']]),\n  oneOfNestedSimpleInlineObject: PropTypes.oneOf(['News', [{ foo: PropTypes.string }]]),\n  oneOfNestedComplexInlineObject: PropTypes.oneOf([\n    'News',\n    [{ nested: { foo: PropTypes.string } }],\n  ]),\n  oneOfNestedComplexShape: PropTypes.oneOf([\n    'News',\n    [{ nested: PropTypes.shape({ foo: PropTypes.string }) }],\n  ]),\n  /** A multi-type prop is also valid and is displayed as `Union<String|Message>` */\n  oneOfType: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Set)]),\n  /** Array of a primitive type */\n  arrayOfPrimitive: PropTypes.arrayOf(PropTypes.number),\n  arrayOfNamedObject: PropTypes.arrayOf(NAMED_OBJECT),\n  arrayOfShortInlineObject: PropTypes.arrayOf({\n    foo: PropTypes.string,\n  }),\n  arrayOfInlineObject: PropTypes.arrayOf({\n    text: PropTypes.string.isRequired,\n    value: PropTypes.string.isRequired,\n  }),\n  arrayOfComplexInlineObject: PropTypes.arrayOf({\n    text: PropTypes.string.isRequired,\n    value: PropTypes.string.isRequired,\n    shape: {\n      id: PropTypes.string.isRequired,\n      age: PropTypes.number.isRequired,\n    },\n  }),\n  arrayOfShortShape: PropTypes.arrayOf(\n    PropTypes.shape({\n      bar: PropTypes.string,\n    })\n  ),\n  arrayOfComplexShape: PropTypes.arrayOf(\n    PropTypes.shape({\n      /**\n       * Just an internal propType for a shape. It's also required, and as you can see it supports\n       * multi-line comments!\n       */\n      id: PropTypes.number.isRequired,\n      /** A simple non-required function */\n      func: PropTypes.func,\n      /** An `arrayOf` shape */\n      arr: PropTypes.arrayOf(\n        PropTypes.shape({\n          /** 5-level deep propType definition and still works. */\n          index: PropTypes.number.isRequired,\n        })\n      ),\n    })\n  ),\n  arrayExternalShape: PropTypes.arrayOf(PropTypes.shape(PRESET_SHAPE)),\n  /** A simple `objectOf` propType. */\n  simpleObjectOf: PropTypes.objectOf(PropTypes.number),\n  objectOfShortInlineObject: PropTypes.objectOf({\n    foo: PropTypes.string,\n  }),\n  objectOfInlineObject: PropTypes.objectOf({\n    foo: PropTypes.string,\n    bar: PropTypes.string,\n    barry: PropTypes.string,\n  }),\n  objectOfShortShape: PropTypes.objectOf(\n    PropTypes.shape({\n      foo: string,\n    })\n  ),\n  /** A very complex `objectOf` propType. */\n  objectOfComplexShape: PropTypes.objectOf(\n    PropTypes.shape({\n      /**\n       * Just an internal propType for a shape. It's also required, and as you can see it supports\n       * multi-line comments!\n       */\n      id: PropTypes.number.isRequired,\n      /** A simple non-required function */\n      func: PropTypes.func,\n      /** An `arrayOf` shape */\n      arr: PropTypes.arrayOf(\n        PropTypes.shape({\n          /** 5-level deep propType definition and still works. */\n          index: PropTypes.number.isRequired,\n        })\n      ),\n    })\n  ),\n  namedObjectOf: PropTypes.objectOf(NAMED_OBJECT),\n  shapeShort: PropTypes.shape({\n    foo: string,\n  }),\n  shapeLong: PropTypes.shape({\n    foo: string,\n    prop1: string,\n    prop2: string,\n    prop3: string,\n    prop4: string,\n    prop5: string,\n    prop6: string,\n    prop7: string,\n  }),\n  /**\n   * PropType for shape with nested arrayOf\n   *\n   * Also, multi-line description\n   */\n  shapeComplex: PropTypes.shape({\n    /**\n     * Just an internal propType for a shape. It's also required, and as you can see it supports\n     * multi-line comments!\n     */\n    id: PropTypes.number.isRequired,\n    /** A simple non-required function */\n    func: PropTypes.func,\n    /** An `arrayOf` shape */\n    arr: PropTypes.arrayOf(\n      PropTypes.shape({\n        /** 5-level deep propType definition and still works. */\n        index: PropTypes.number.isRequired,\n      })\n    ),\n    shape: PropTypes.shape({\n      shape: PropTypes.shape({\n        foo: PropTypes.string,\n        oneOf: PropTypes.oneOf(['one', 'two']),\n      }),\n    }),\n    oneOf: PropTypes.oneOf(['one', 'two']),\n  }),\n  shapeWithArray: PropTypes.shape({\n    arr: PropTypes.arrayOf({ foo: PropTypes.string }),\n  }),\n  namedShape: NAMED_SHAPE,\n  namedObjectInShape: PropTypes.shape(NAMED_OBJECT),\n  exact: PropTypes.exact({\n    name: PropTypes.string,\n    quantity: PropTypes.number,\n  }),\n  namedExact: PropTypes.exact(NAMED_OBJECT),\n  /** Test string with a comment that has two identical lines two identical lines */\n  optionalString: PropTypes.string,\n  requiredString: PropTypes.string.isRequired,\n  nullDefaultValue: PropTypes.string,\n  undefinedDefaultValue: PropTypes.string,\n  ...SOME_INLINE_PROP_TYPES,\n  ...SOME_PROP_TYPES,\n};\n\nPropTypesProps.defaultProps = {\n  any: 'Default any',\n  bool: false,\n  string: 'Default string',\n  func: () => {},\n  funcWithJsDoc: (foo, bar) => {\n    const yo = window.document;\n\n    return { foo, bar };\n  },\n  namedDefaultFunc: concat,\n  number: 5,\n  obj: {\n    key: 'value',\n  },\n  symbol: Symbol('Default symbol'),\n  node: <div>Hello!</div>,\n  functionalElement: <FunctionalComponent className=\"toto\" />,\n  functionalElementInline: () => {\n    return <div>Inlined FunctionalComponent!</div>;\n  },\n  functionalElementNamedInline: function InlinedFunctionalComponent() {\n    return <div>Inlined FunctionalComponent!</div>;\n  },\n  classElement: <ClassComponent />,\n  classElementInline: class InlinedClassComponent extends React.PureComponent {\n    render() {\n      return <div>Inlined ClassComponent!</div>;\n    }\n  },\n  functionalElementType: FunctionalComponent,\n  classElementType: ClassComponent,\n  elementWithProps: <ClassComponent className=\"w8 h8 fill-marine-500\" />,\n  instanceOf: new Set(),\n  oneOfString: 'News',\n  oneOfNumeric: 1,\n  oneOfShapes: { foo: 'bar' },\n  oneOfComplexShapes: {\n    thing: {\n      id: 2,\n      func: () => {},\n      arr: [],\n    },\n  },\n  oneOfComplexType: { text: 'foo', value: 'bar' },\n  oneOfComponents: <FunctionalComponent />,\n  oneOfEval: 'Photos',\n  oneOfVar: 'top-right',\n  oneOfNested: 'top-right',\n  oneOfType: 'hello',\n  arrayOfPrimitive: [1, 2, 3],\n  arrayOfString: ['0px', '0px'],\n  arrayOfNamedObject: [{ text: 'foo', value: 'bar' }],\n  arrayOfShortInlineObject: [{ foo: 'bar' }],\n  arrayOfInlineObject: [{ text: 'foo', value: 'bar' }],\n  arrayOfComplexInlineObject: [{ text: 'foo', value: 'bar' }],\n  arrayOfShortShape: [{ bar: 'foo' }],\n  arrayOfComplexShape: [\n    {\n      thing: {\n        id: 2,\n        func: () => {},\n        arr: [],\n      },\n    },\n  ],\n  simpleObjectOf: { key: 1 },\n  objectOfShortInlineObject: { foo: 'bar' },\n  objectOfInlineObject: { foo: 'bar', bar: 'foo' },\n  objectOfShortShape: { foo: 'bar' },\n  objectOfComplexShape: {\n    thing: {\n      id: 2,\n      func: () => {},\n      arr: [],\n    },\n  },\n  namedObjectOf: { text: 'foo', value: 'bar' },\n  shapeShort: { foo: 'bar' },\n  shapeComplex: {\n    id: 3,\n    func: () => {},\n    arr: [],\n    shape: {\n      shape: {\n        foo: 'bar',\n      },\n    },\n  },\n  namedShape: { foo: 'bar' },\n  namedObjectInShape: { text: 'foo', value: 'bar' },\n  exact: { name: 'foo', quantity: 2 },\n  namedExact: { text: 'foo', value: 'bar' },\n  optionalString: 'Default String',\n  nullDefaultValue: null,\n  undefinedDefaultValue: undefined,\n  ...SOME_INLINE_DEFAULT_PROPS,\n};\n\nexport const component = PropTypesProps;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-re-exported-component/docgen.snapshot",
    "content": "export { component } from '../js-function-component/input.jsx';"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/js-re-exported-component/input.jsx",
    "content": "import { component } from '../js-function-component/input.jsx';\n\nexport { component };\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/jsdoc/argTypes.snapshot",
    "content": "{\n  \"case1\": {\n    \"control\": {\n      \"type\": \"text\",\n    },\n    \"description\": \"Simple description.\",\n    \"name\": \"case1\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"case10\": {\n    \"description\": \"Param with name\",\n    \"name\": \"case10\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event)\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case11\": {\n    \"description\": \"Param with name & type\",\n    \"name\": \"case11\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event: SyntheticEvent)\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case12\": {\n    \"description\": \"Param with name, type & description\",\n    \"name\": \"case12\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": \"React's original event\",\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event: SyntheticEvent)\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case13\": {\n    \"description\": \"Param with type\",\n    \"name\": \"case13\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case14\": {\n    \"description\": \"Param with type & description\",\n    \"name\": \"case14\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case15\": {\n    \"description\": \"Param with name & description\",\n    \"name\": \"case15\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": \"React's original event\",\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event)\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case16\": {\n    \"description\": \"Autofix event-\",\n    \"name\": \"case16\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": \"React's original event\",\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event)\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case17\": {\n    \"description\": \"Autofix event.\",\n    \"name\": \"case17\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": {\n          \"description\": null,\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"type\": \"JsdocTypeName\",\n            \"value\": \"string\",\n          },\n        },\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event) => string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case18\": {\n    \"description\": \"With an empty param.\",\n    \"name\": \"case18\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case19\": {\n    \"description\": \"With multiple empty params.\",\n    \"name\": \"case19\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case2\": {\n    \"control\": {\n      \"type\": \"text\",\n    },\n    \"description\": \"Multi lines description\",\n    \"name\": \"case2\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"case20\": {\n    \"description\": \"With arg alias.\",\n    \"name\": \"case20\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event)\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case21\": {\n    \"description\": \"With argument alias.\",\n    \"name\": \"case21\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event)\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case22\": {\n    \"description\": \"With multiple params.\",\n    \"name\": \"case22\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"event\",\n          },\n          {\n            \"description\": null,\n            \"name\": \"stringValue\",\n          },\n          {\n            \"description\": null,\n            \"name\": \"numberValue\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event: SyntheticEvent, stringValue: string, numberValue: number)\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case23\": {\n    \"description\": \"With an empty returns\",\n    \"name\": \"case23\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case24\": {\n    \"description\": \"With a returns with a type\",\n    \"name\": \"case24\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": undefined,\n        \"returns\": {\n          \"description\": null,\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"type\": \"JsdocTypeName\",\n            \"value\": \"SyntheticEvent\",\n          },\n        },\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"() => SyntheticEvent\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case25\": {\n    \"description\": \"With a returns with a type & description\",\n    \"name\": \"case25\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": undefined,\n        \"returns\": {\n          \"description\": \"React's original event\",\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"type\": \"JsdocTypeName\",\n            \"value\": \"SyntheticEvent\",\n          },\n        },\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"() => SyntheticEvent\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case26\": {\n    \"description\": \"Single param and a returns\",\n    \"name\": \"case26\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"stringValue\",\n          },\n        ],\n        \"returns\": {\n          \"description\": \"React's original event\",\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"type\": \"JsdocTypeName\",\n            \"value\": \"SyntheticEvent\",\n          },\n        },\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(stringValue: string) => SyntheticEvent\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case27\": {\n    \"description\": \"Multiple params and a returns\",\n    \"name\": \"case27\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"stringValue\",\n          },\n          {\n            \"description\": null,\n            \"name\": \"numberValue\",\n          },\n        ],\n        \"returns\": {\n          \"description\": \"React's original event\",\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"type\": \"JsdocTypeName\",\n            \"value\": \"SyntheticEvent\",\n          },\n        },\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(stringValue: string, numberValue: number) => SyntheticEvent\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case28\": {\n    \"description\": \"Multiple returns\",\n    \"name\": \"case28\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": undefined,\n        \"returns\": {\n          \"description\": \"Second returns\",\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"type\": \"JsdocTypeName\",\n            \"value\": \"string\",\n          },\n        },\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"() => string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case29\": {\n    \"description\": \"Param with unsupported JSDoc tags\",\n    \"name\": \"case29\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": \"React's original event\",\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event: SyntheticEvent)\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case3\": {\n    \"control\": {\n      \"type\": \"text\",\n    },\n    \"description\": \"_description_ **with** `formatting`\",\n    \"name\": \"case3\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"case30\": {\n    \"description\": \"Param record type\",\n    \"name\": \"case30\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"myType\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(myType: ({a: number; b: string}))\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case31\": {\n    \"description\": \"Param array type\",\n    \"name\": \"case31\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"myType\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(myType: string[])\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case32\": {\n    \"description\": \"Param union type\",\n    \"name\": \"case32\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"myType\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(myType: number|boolean)\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case33\": {\n    \"description\": \"Param any type\",\n    \"name\": \"case33\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"myType\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(myType: any)\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case34\": {\n    \"description\": \"Param repeatable type\",\n    \"name\": \"case34\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"myType\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(myType: ...number)\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case35\": {\n    \"description\": \"Optional param\",\n    \"name\": \"case35\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"myType\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(myType: number)\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case36\": {\n    \"description\": \"Optional param\",\n    \"name\": \"case36\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"myType\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(myType: number)\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case37\": {\n    \"description\": \"Dot in param name\",\n    \"name\": \"case37\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"my.type\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(my.type: number)\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case38\": {\n    \"description\": \"Returns record type\",\n    \"name\": \"case38\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": undefined,\n        \"returns\": {\n          \"description\": null,\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"elements\": [\n              {\n                \"key\": \"a\",\n                \"meta\": {\n                  \"quote\": undefined,\n                },\n                \"optional\": false,\n                \"readonly\": false,\n                \"right\": {\n                  \"type\": \"JsdocTypeName\",\n                  \"value\": \"number\",\n                },\n                \"type\": \"JsdocTypeObjectField\",\n              },\n              {\n                \"key\": \"b\",\n                \"meta\": {\n                  \"quote\": undefined,\n                },\n                \"optional\": false,\n                \"readonly\": false,\n                \"right\": {\n                  \"type\": \"JsdocTypeName\",\n                  \"value\": \"string\",\n                },\n                \"type\": \"JsdocTypeObjectField\",\n              },\n            ],\n            \"meta\": {\n              \"separator\": \"semicolon\",\n            },\n            \"type\": \"JsdocTypeObject\",\n          },\n        },\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"() => ({a: number; b: string})\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case39\": {\n    \"description\": \"Returns array type\",\n    \"name\": \"case39\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": undefined,\n        \"returns\": {\n          \"description\": null,\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"elements\": [\n              {\n                \"type\": \"JsdocTypeName\",\n                \"value\": \"string\",\n              },\n            ],\n            \"left\": {\n              \"type\": \"JsdocTypeName\",\n              \"value\": \"Array\",\n            },\n            \"meta\": {\n              \"brackets\": \"square\",\n              \"dot\": false,\n            },\n            \"type\": \"JsdocTypeGeneric\",\n          },\n        },\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"() => string[]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case4\": {\n    \"control\": {\n      \"type\": \"text\",\n    },\n    \"description\": \"Simple description and dummy JSDoc tag.\",\n    \"name\": \"case4\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"case40\": {\n    \"description\": \"Returns union type\",\n    \"name\": \"case40\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": undefined,\n        \"returns\": {\n          \"description\": null,\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"elements\": [\n              {\n                \"type\": \"JsdocTypeName\",\n                \"value\": \"number\",\n              },\n              {\n                \"type\": \"JsdocTypeName\",\n                \"value\": \"boolean\",\n              },\n            ],\n            \"type\": \"JsdocTypeUnion\",\n          },\n        },\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"() => number|boolean\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case41\": {\n    \"description\": \"Returns any type\",\n    \"name\": \"case41\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": undefined,\n        \"returns\": {\n          \"description\": null,\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"type\": \"JsdocTypeName\",\n            \"value\": \"any\",\n          },\n        },\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"() => any\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case42\": {\n    \"description\": \"Returns primitive\",\n    \"name\": \"case42\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": undefined,\n        \"returns\": {\n          \"description\": null,\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"type\": \"JsdocTypeName\",\n            \"value\": \"string\",\n          },\n        },\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"() => string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case43\": {\n    \"description\": \"Returns void\",\n    \"name\": \"case43\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": undefined,\n        \"returns\": {\n          \"description\": null,\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"type\": \"JsdocTypeName\",\n            \"value\": \"void\",\n          },\n        },\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"() => void\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case5\": {\n    \"control\": {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"case5\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"case6\": {\n    \"control\": {\n      \"type\": \"text\",\n    },\n    \"description\": \"Simple description with a @.\",\n    \"name\": \"case6\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"case7\": {\n    \"description\": \"\",\n    \"name\": \"case7\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case8\": {\n    \"description\": \"Func with a simple description.\",\n    \"name\": \"case8\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n  \"case9\": {\n    \"description\": \"\",\n    \"name\": \"case9\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event)\",\n      },\n    },\n    \"type\": {\n      \"name\": \"function\",\n      \"required\": false,\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/jsdoc/docgen.snapshot",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nconst JsDocProps = () => /*#__PURE__*/React.createElement(\"div\", null, \"JSDoc with PropTypes!\");\nJsDocProps.propTypes = {\n  /**\n   * Should not be visible since it's ignored.\n   *\n   * @ignore\n   */\n  case0: PropTypes.string,\n  /** Simple description. */\n  case1: PropTypes.string,\n  /** Multi lines description */\n  case2: PropTypes.string,\n  /** _description_ **with** `formatting` */\n  case3: PropTypes.string,\n  /**\n   * Simple description and dummy JSDoc tag.\n   *\n   * @param event\n   */\n  case4: PropTypes.string,\n  /** @param event */\n  case5: PropTypes.string,\n  /** Simple description with a @. */\n  case6: PropTypes.string,\n  case7: PropTypes.func,\n  /** Func with a simple description. */\n  case8: PropTypes.func,\n  /** @param event */\n  case9: PropTypes.func,\n  /**\n   * Param with name\n   *\n   * @param event\n   */\n  case10: PropTypes.func,\n  /**\n   * Param with name & type\n   *\n   * @param {SyntheticEvent} event\n   */\n  case11: PropTypes.func,\n  /**\n   * Param with name, type & description\n   *\n   * @param {SyntheticEvent} event - React's original event\n   */\n  case12: PropTypes.func,\n  /**\n   * Param with type\n   *\n   * @param {SyntheticEvent}\n   */\n  case13: PropTypes.func,\n  /**\n   * Param with type & description\n   *\n   * @param {SyntheticEvent} - React's original event\n   */\n  case14: PropTypes.func,\n  /**\n   * Param with name & description\n   *\n   * @param event - React's original event\n   */\n  case15: PropTypes.func,\n  /**\n   * Autofix event-\n   *\n   * @param event- React's original event\n   */\n  case16: PropTypes.func,\n  /**\n   * Autofix event.\n   *\n   * @param event.\n   * @returns {string}\n   */\n  case17: PropTypes.func,\n  /**\n   * With an empty param.\n   *\n   * @param\n   */\n  case18: PropTypes.func,\n  /**\n   * With multiple empty params.\n   *\n   * @param\n   * @param\n   * @param\n   */\n  case19: PropTypes.func,\n  /**\n   * With arg alias.\n   *\n   * @param event\n   */\n  case20: PropTypes.func,\n  /**\n   * With argument alias.\n   *\n   * @param event\n   */\n  case21: PropTypes.func,\n  /**\n   * With multiple params.\n   *\n   * @param {SyntheticEvent} event\n   * @param {string} stringValue\n   * @param {number} numberValue\n   */\n  case22: PropTypes.func,\n  /**\n   * With an empty returns\n   *\n   * @returns\n   */\n  case23: PropTypes.func,\n  /**\n   * With a returns with a type\n   *\n   * @returns {SyntheticEvent}\n   */\n  case24: PropTypes.func,\n  /**\n   * With a returns with a type & description\n   *\n   * @returns {SyntheticEvent} - React's original event\n   */\n  case25: PropTypes.func,\n  /**\n   * Single param and a returns\n   *\n   * @param {string} stringValue\n   * @returns {SyntheticEvent} - React's original event\n   */\n  case26: PropTypes.func,\n  /**\n   * Multiple params and a returns\n   *\n   * @param {string} stringValue\n   * @param {number} numberValue\n   * @returns {SyntheticEvent} - React's original event\n   */\n  case27: PropTypes.func,\n  /**\n   * Multiple returns\n   *\n   * @returns {SyntheticEvent} - React's original event\n   * @returns {string} - Second returns\n   */\n  case28: PropTypes.func,\n  /**\n   * Param with unsupported JSDoc tags\n   *\n   * @version 2\n   * @type {number}\n   * @param {SyntheticEvent} event - React's original event\n   */\n  case29: PropTypes.func,\n  /**\n   * Param record type\n   *\n   * @param {{ a: number; b: string }} myType\n   */\n  case30: PropTypes.func,\n  /**\n   * Param array type\n   *\n   * @param {string[]} myType\n   */\n  case31: PropTypes.func,\n  /**\n   * Param union type\n   *\n   * @param {number | boolean} myType\n   */\n  case32: PropTypes.func,\n  /**\n   * Param any type\n   *\n   * @param {any} myType\n   */\n  case33: PropTypes.func,\n  /**\n   * Param repeatable type\n   *\n   * @param {...number} myType\n   */\n  case34: PropTypes.func,\n  /**\n   * Optional param\n   *\n   * @param {number} [myType]\n   */\n  case35: PropTypes.func,\n  /**\n   * Optional param\n   *\n   * @param {number} [myType]\n   */\n  case36: PropTypes.func,\n  /**\n   * Dot in param name\n   *\n   * @param {number} my.type\n   */\n  case37: PropTypes.func,\n  /**\n   * Returns record type\n   *\n   * @returns {{ a: number; b: string }}\n   */\n  case38: PropTypes.func,\n  /**\n   * Returns array type\n   *\n   * @returns {string[]}\n   */\n  case39: PropTypes.func,\n  /**\n   * Returns union type\n   *\n   * @returns {number | boolean}\n   */\n  case40: PropTypes.func,\n  /**\n   * Returns any type\n   *\n   * @returns {any}\n   */\n  case41: PropTypes.func,\n  /**\n   * Returns primitive\n   *\n   * @returns {string}\n   */\n  case42: PropTypes.func,\n  /**\n   * Returns void\n   *\n   * @returns {void}\n   */\n  case43: PropTypes.func\n};\nexport const component = JsDocProps;\nJsDocProps.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"JsDocProps\",\n  \"props\": {\n    \"case0\": {\n      \"description\": \"Should not be visible since it's ignored.\\n\\n@ignore\",\n      \"type\": {\n        \"name\": \"string\"\n      },\n      \"required\": false\n    },\n    \"case1\": {\n      \"description\": \"Simple description.\",\n      \"type\": {\n        \"name\": \"string\"\n      },\n      \"required\": false\n    },\n    \"case2\": {\n      \"description\": \"Multi lines description\",\n      \"type\": {\n        \"name\": \"string\"\n      },\n      \"required\": false\n    },\n    \"case3\": {\n      \"description\": \"_description_ **with** `formatting`\",\n      \"type\": {\n        \"name\": \"string\"\n      },\n      \"required\": false\n    },\n    \"case4\": {\n      \"description\": \"Simple description and dummy JSDoc tag.\\n\\n@param event\",\n      \"type\": {\n        \"name\": \"string\"\n      },\n      \"required\": false\n    },\n    \"case5\": {\n      \"description\": \"@param event\",\n      \"type\": {\n        \"name\": \"string\"\n      },\n      \"required\": false\n    },\n    \"case6\": {\n      \"description\": \"Simple description with a @.\",\n      \"type\": {\n        \"name\": \"string\"\n      },\n      \"required\": false\n    },\n    \"case7\": {\n      \"description\": \"\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case8\": {\n      \"description\": \"Func with a simple description.\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case9\": {\n      \"description\": \"@param event\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case10\": {\n      \"description\": \"Param with name\\n\\n@param event\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case11\": {\n      \"description\": \"Param with name & type\\n\\n@param {SyntheticEvent} event\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case12\": {\n      \"description\": \"Param with name, type & description\\n\\n@param {SyntheticEvent} event - React's original event\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case13\": {\n      \"description\": \"Param with type\\n\\n@param {SyntheticEvent}\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case14\": {\n      \"description\": \"Param with type & description\\n\\n@param {SyntheticEvent} - React's original event\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case15\": {\n      \"description\": \"Param with name & description\\n\\n@param event - React's original event\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case16\": {\n      \"description\": \"Autofix event-\\n\\n@param event- React's original event\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case17\": {\n      \"description\": \"Autofix event.\\n\\n@param event.\\n@returns {string}\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case18\": {\n      \"description\": \"With an empty param.\\n\\n@param\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case19\": {\n      \"description\": \"With multiple empty params.\\n\\n@param\\n@param\\n@param\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case20\": {\n      \"description\": \"With arg alias.\\n\\n@param event\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case21\": {\n      \"description\": \"With argument alias.\\n\\n@param event\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case22\": {\n      \"description\": \"With multiple params.\\n\\n@param {SyntheticEvent} event\\n@param {string} stringValue\\n@param {number} numberValue\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case23\": {\n      \"description\": \"With an empty returns\\n\\n@returns\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case24\": {\n      \"description\": \"With a returns with a type\\n\\n@returns {SyntheticEvent}\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case25\": {\n      \"description\": \"With a returns with a type & description\\n\\n@returns {SyntheticEvent} - React's original event\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case26\": {\n      \"description\": \"Single param and a returns\\n\\n@param {string} stringValue\\n@returns {SyntheticEvent} - React's original event\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case27\": {\n      \"description\": \"Multiple params and a returns\\n\\n@param {string} stringValue\\n@param {number} numberValue\\n@returns {SyntheticEvent} - React's original event\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case28\": {\n      \"description\": \"Multiple returns\\n\\n@returns {SyntheticEvent} - React's original event\\n@returns {string} - Second returns\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case29\": {\n      \"description\": \"Param with unsupported JSDoc tags\\n\\n@version 2\\n@type {number}\\n@param {SyntheticEvent} event - React's original event\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case30\": {\n      \"description\": \"Param record type\\n\\n@param {{ a: number; b: string }} myType\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case31\": {\n      \"description\": \"Param array type\\n\\n@param {string[]} myType\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case32\": {\n      \"description\": \"Param union type\\n\\n@param {number | boolean} myType\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case33\": {\n      \"description\": \"Param any type\\n\\n@param {any} myType\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case34\": {\n      \"description\": \"Param repeatable type\\n\\n@param {...number} myType\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case35\": {\n      \"description\": \"Optional param\\n\\n@param {number} [myType]\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case36\": {\n      \"description\": \"Optional param\\n\\n@param {number} [myType]\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case37\": {\n      \"description\": \"Dot in param name\\n\\n@param {number} my.type\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case38\": {\n      \"description\": \"Returns record type\\n\\n@returns {{ a: number; b: string }}\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case39\": {\n      \"description\": \"Returns array type\\n\\n@returns {string[]}\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case40\": {\n      \"description\": \"Returns union type\\n\\n@returns {number | boolean}\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case41\": {\n      \"description\": \"Returns any type\\n\\n@returns {any}\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case42\": {\n      \"description\": \"Returns primitive\\n\\n@returns {string}\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    },\n    \"case43\": {\n      \"description\": \"Returns void\\n\\n@returns {void}\",\n      \"type\": {\n        \"name\": \"func\"\n      },\n      \"required\": false\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/jsdoc/input.jsx",
    "content": "import React from 'react';\n\nimport PropTypes from 'prop-types';\n\nconst JsDocProps = () => <div>JSDoc with PropTypes!</div>;\nJsDocProps.propTypes = {\n  /**\n   * Should not be visible since it's ignored.\n   *\n   * @ignore\n   */\n  case0: PropTypes.string,\n  /** Simple description. */\n  case1: PropTypes.string,\n  /** Multi lines description */\n  case2: PropTypes.string,\n  /** _description_ **with** `formatting` */\n  case3: PropTypes.string,\n  /**\n   * Simple description and dummy JSDoc tag.\n   *\n   * @param event\n   */\n  case4: PropTypes.string,\n  /** @param event */\n  case5: PropTypes.string,\n  /** Simple description with a @. */\n  case6: PropTypes.string,\n  case7: PropTypes.func,\n  /** Func with a simple description. */\n  case8: PropTypes.func,\n  /** @param event */\n  case9: PropTypes.func,\n  /**\n   * Param with name\n   *\n   * @param event\n   */\n  case10: PropTypes.func,\n  /**\n   * Param with name & type\n   *\n   * @param {SyntheticEvent} event\n   */\n  case11: PropTypes.func,\n  /**\n   * Param with name, type & description\n   *\n   * @param {SyntheticEvent} event - React's original event\n   */\n  case12: PropTypes.func,\n  /**\n   * Param with type\n   *\n   * @param {SyntheticEvent}\n   */\n  case13: PropTypes.func,\n  /**\n   * Param with type & description\n   *\n   * @param {SyntheticEvent} - React's original event\n   */\n  case14: PropTypes.func,\n  /**\n   * Param with name & description\n   *\n   * @param event - React's original event\n   */\n  case15: PropTypes.func,\n  /**\n   * Autofix event-\n   *\n   * @param event- React's original event\n   */\n  case16: PropTypes.func,\n  /**\n   * Autofix event.\n   *\n   * @param event.\n   * @returns {string}\n   */\n  case17: PropTypes.func,\n  /**\n   * With an empty param.\n   *\n   * @param\n   */\n  case18: PropTypes.func,\n  /**\n   * With multiple empty params.\n   *\n   * @param\n   * @param\n   * @param\n   */\n  case19: PropTypes.func,\n  /**\n   * With arg alias.\n   *\n   * @param event\n   */\n  case20: PropTypes.func,\n  /**\n   * With argument alias.\n   *\n   * @param event\n   */\n  case21: PropTypes.func,\n  /**\n   * With multiple params.\n   *\n   * @param {SyntheticEvent} event\n   * @param {string} stringValue\n   * @param {number} numberValue\n   */\n  case22: PropTypes.func,\n  /**\n   * With an empty returns\n   *\n   * @returns\n   */\n  case23: PropTypes.func,\n  /**\n   * With a returns with a type\n   *\n   * @returns {SyntheticEvent}\n   */\n  case24: PropTypes.func,\n  /**\n   * With a returns with a type & description\n   *\n   * @returns {SyntheticEvent} - React's original event\n   */\n  case25: PropTypes.func,\n  /**\n   * Single param and a returns\n   *\n   * @param {string} stringValue\n   * @returns {SyntheticEvent} - React's original event\n   */\n  case26: PropTypes.func,\n  /**\n   * Multiple params and a returns\n   *\n   * @param {string} stringValue\n   * @param {number} numberValue\n   * @returns {SyntheticEvent} - React's original event\n   */\n  case27: PropTypes.func,\n  /**\n   * Multiple returns\n   *\n   * @returns {SyntheticEvent} - React's original event\n   * @returns {string} - Second returns\n   */\n  case28: PropTypes.func,\n  /**\n   * Param with unsupported JSDoc tags\n   *\n   * @version 2\n   * @type {number}\n   * @param {SyntheticEvent} event - React's original event\n   */\n  case29: PropTypes.func,\n  /**\n   * Param record type\n   *\n   * @param {{ a: number; b: string }} myType\n   */\n  case30: PropTypes.func,\n  /**\n   * Param array type\n   *\n   * @param {string[]} myType\n   */\n  case31: PropTypes.func,\n  /**\n   * Param union type\n   *\n   * @param {number | boolean} myType\n   */\n  case32: PropTypes.func,\n  /**\n   * Param any type\n   *\n   * @param {any} myType\n   */\n  case33: PropTypes.func,\n  /**\n   * Param repeatable type\n   *\n   * @param {...number} myType\n   */\n  case34: PropTypes.func,\n  /**\n   * Optional param\n   *\n   * @param {number} [myType]\n   */\n  case35: PropTypes.func,\n  /**\n   * Optional param\n   *\n   * @param {number} [myType]\n   */\n  case36: PropTypes.func,\n  /**\n   * Dot in param name\n   *\n   * @param {number} my.type\n   */\n  case37: PropTypes.func,\n  /**\n   * Returns record type\n   *\n   * @returns {{ a: number; b: string }}\n   */\n  case38: PropTypes.func,\n  /**\n   * Returns array type\n   *\n   * @returns {string[]}\n   */\n  case39: PropTypes.func,\n  /**\n   * Returns union type\n   *\n   * @returns {number | boolean}\n   */\n  case40: PropTypes.func,\n  /**\n   * Returns any type\n   *\n   * @returns {any}\n   */\n  case41: PropTypes.func,\n  /**\n   * Returns primitive\n   *\n   * @returns {string}\n   */\n  case42: PropTypes.func,\n  /**\n   * Returns void\n   *\n   * @returns {void}\n   */\n  case43: PropTypes.func,\n};\n\nexport const component = JsDocProps;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/jsdoc/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": null,\n      \"description\": \"Simple description.\",\n      \"name\": \"case1\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"string\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Multi lines description\",\n      \"name\": \"case2\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"string\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"_description_ **with** `formatting`\",\n      \"name\": \"case3\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"string\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Simple description and dummy JSDoc tag.\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"name\": \"case4\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"string\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"name\": \"case5\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"string\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Simple description with a @.\",\n      \"name\": \"case6\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"string\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"case7\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Func with a simple description.\",\n      \"name\": \"case8\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"name\": \"case9\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event)\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Param with name\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"name\": \"case10\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event)\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Param with name & type\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"name\": \"case11\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event: SyntheticEvent)\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Param with name, type & description\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": \"React's original event\",\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"name\": \"case12\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event: SyntheticEvent)\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Param with type\",\n      \"name\": \"case13\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Param with type & description\",\n      \"name\": \"case14\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Param with name & description\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": \"React's original event\",\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"name\": \"case15\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event)\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Autofix event-\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": \"React's original event\",\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"name\": \"case16\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event)\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Autofix event.\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": {\n          \"description\": null,\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"type\": \"JsdocTypeName\",\n            \"value\": \"string\",\n          },\n        },\n      },\n      \"name\": \"case17\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event) => string\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"With an empty param.\",\n      \"name\": \"case18\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"With multiple empty params.\",\n      \"name\": \"case19\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"With arg alias.\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"name\": \"case20\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event)\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"With argument alias.\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"name\": \"case21\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event)\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"With multiple params.\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"event\",\n          },\n          {\n            \"description\": null,\n            \"name\": \"stringValue\",\n          },\n          {\n            \"description\": null,\n            \"name\": \"numberValue\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"name\": \"case22\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event: SyntheticEvent, stringValue: string, numberValue: number)\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"With an empty returns\",\n      \"name\": \"case23\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"func\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"With a returns with a type\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": undefined,\n        \"returns\": {\n          \"description\": null,\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"type\": \"JsdocTypeName\",\n            \"value\": \"SyntheticEvent\",\n          },\n        },\n      },\n      \"name\": \"case24\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"() => SyntheticEvent\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"With a returns with a type & description\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": undefined,\n        \"returns\": {\n          \"description\": \"React's original event\",\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"type\": \"JsdocTypeName\",\n            \"value\": \"SyntheticEvent\",\n          },\n        },\n      },\n      \"name\": \"case25\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"() => SyntheticEvent\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Single param and a returns\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"stringValue\",\n          },\n        ],\n        \"returns\": {\n          \"description\": \"React's original event\",\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"type\": \"JsdocTypeName\",\n            \"value\": \"SyntheticEvent\",\n          },\n        },\n      },\n      \"name\": \"case26\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(stringValue: string) => SyntheticEvent\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Multiple params and a returns\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"stringValue\",\n          },\n          {\n            \"description\": null,\n            \"name\": \"numberValue\",\n          },\n        ],\n        \"returns\": {\n          \"description\": \"React's original event\",\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"type\": \"JsdocTypeName\",\n            \"value\": \"SyntheticEvent\",\n          },\n        },\n      },\n      \"name\": \"case27\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(stringValue: string, numberValue: number) => SyntheticEvent\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Multiple returns\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": undefined,\n        \"returns\": {\n          \"description\": \"Second returns\",\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"type\": \"JsdocTypeName\",\n            \"value\": \"string\",\n          },\n        },\n      },\n      \"name\": \"case28\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"() => string\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Param with unsupported JSDoc tags\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": \"React's original event\",\n            \"name\": \"event\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"name\": \"case29\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(event: SyntheticEvent)\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Param record type\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"myType\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"name\": \"case30\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(myType: ({a: number; b: string}))\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Param array type\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"myType\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"name\": \"case31\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(myType: string[])\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Param union type\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"myType\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"name\": \"case32\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(myType: number|boolean)\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Param any type\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"myType\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"name\": \"case33\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(myType: any)\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Param repeatable type\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"myType\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"name\": \"case34\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(myType: ...number)\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Optional param\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"myType\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"name\": \"case35\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(myType: number)\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Optional param\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"myType\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"name\": \"case36\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(myType: number)\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Dot in param name\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": [\n          {\n            \"description\": null,\n            \"name\": \"my.type\",\n          },\n        ],\n        \"returns\": null,\n      },\n      \"name\": \"case37\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"(my.type: number)\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Returns record type\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": undefined,\n        \"returns\": {\n          \"description\": null,\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"elements\": [\n              {\n                \"key\": \"a\",\n                \"meta\": {\n                  \"quote\": undefined,\n                },\n                \"optional\": false,\n                \"readonly\": false,\n                \"right\": {\n                  \"type\": \"JsdocTypeName\",\n                  \"value\": \"number\",\n                },\n                \"type\": \"JsdocTypeObjectField\",\n              },\n              {\n                \"key\": \"b\",\n                \"meta\": {\n                  \"quote\": undefined,\n                },\n                \"optional\": false,\n                \"readonly\": false,\n                \"right\": {\n                  \"type\": \"JsdocTypeName\",\n                  \"value\": \"string\",\n                },\n                \"type\": \"JsdocTypeObjectField\",\n              },\n            ],\n            \"meta\": {\n              \"separator\": \"semicolon\",\n            },\n            \"type\": \"JsdocTypeObject\",\n          },\n        },\n      },\n      \"name\": \"case38\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"() => ({a: number; b: string})\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Returns array type\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": undefined,\n        \"returns\": {\n          \"description\": null,\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"elements\": [\n              {\n                \"type\": \"JsdocTypeName\",\n                \"value\": \"string\",\n              },\n            ],\n            \"left\": {\n              \"type\": \"JsdocTypeName\",\n              \"value\": \"Array\",\n            },\n            \"meta\": {\n              \"brackets\": \"square\",\n              \"dot\": false,\n            },\n            \"type\": \"JsdocTypeGeneric\",\n          },\n        },\n      },\n      \"name\": \"case39\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"() => string[]\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Returns union type\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": undefined,\n        \"returns\": {\n          \"description\": null,\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"elements\": [\n              {\n                \"type\": \"JsdocTypeName\",\n                \"value\": \"number\",\n              },\n              {\n                \"type\": \"JsdocTypeName\",\n                \"value\": \"boolean\",\n              },\n            ],\n            \"type\": \"JsdocTypeUnion\",\n          },\n        },\n      },\n      \"name\": \"case40\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"() => number|boolean\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Returns any type\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": undefined,\n        \"returns\": {\n          \"description\": null,\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"type\": \"JsdocTypeName\",\n            \"value\": \"any\",\n          },\n        },\n      },\n      \"name\": \"case41\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"() => any\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Returns primitive\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": undefined,\n        \"returns\": {\n          \"description\": null,\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"type\": \"JsdocTypeName\",\n            \"value\": \"string\",\n          },\n        },\n      },\n      \"name\": \"case42\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"() => string\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": \"Returns void\",\n      \"jsDocTags\": {\n        \"deprecated\": null,\n        \"ignore\": false,\n        \"params\": undefined,\n        \"returns\": {\n          \"description\": null,\n          \"getTypeName\": [Function],\n          \"type\": {\n            \"type\": \"JsdocTypeName\",\n            \"value\": \"void\",\n          },\n        },\n      },\n      \"name\": \"case43\",\n      \"required\": false,\n      \"sbType\": {\n        \"name\": \"function\",\n      },\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"() => void\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-function-component/argTypes.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`react component properties ts-function-component 1`] = `\nObject {\n  \"arrayOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"arrayOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"['array',    'optional']\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Array\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"array\",\n      \"raw\": \"string[]\",\n      \"required\": false,\n      \"value\": Array [\n        Object {\n          \"name\": \"string\",\n        },\n      ],\n    },\n  },\n  \"arrayRequired\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"arrayRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Array\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"array\",\n      \"raw\": \"string[]\",\n      \"required\": true,\n      \"value\": Array [\n        Object {\n          \"name\": \"string\",\n        },\n      ],\n    },\n  },\n  \"booleanOptional\": Object {\n    \"control\": Object {\n      \"type\": \"boolean\",\n    },\n    \"description\": \"\",\n    \"name\": \"booleanOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"false\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"boolean\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"boolean\",\n      \"required\": false,\n    },\n  },\n  \"booleanRequired\": Object {\n    \"control\": Object {\n      \"type\": \"boolean\",\n    },\n    \"description\": \"\",\n    \"name\": \"booleanRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"boolean\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"boolean\",\n      \"required\": true,\n    },\n  },\n  \"dateOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"dateOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"new Date('20 Jan 1983')\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"Date\",\n    },\n  },\n  \"dateRequired\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"dateRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"other\",\n      \"required\": true,\n      \"value\": \"Date\",\n    },\n  },\n  \"functionOptional\": Object {\n    \"description\": \"\",\n    \"name\": \"functionOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"() => 'foo'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"signature\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"function\",\n      \"raw\": \"() => string\",\n      \"required\": false,\n    },\n  },\n  \"functionRequired\": Object {\n    \"description\": \"\",\n    \"name\": \"functionRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"signature\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"function\",\n      \"raw\": \"() => string\",\n      \"required\": true,\n    },\n  },\n  \"globalReference\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"globalReference\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"any\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"any\",\n    },\n  },\n  \"importedReference\": Object {\n    \"control\": Object {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"importedReference\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"imported\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"localReference\": Object {\n    \"control\": Object {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"localReference\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'local-value'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"numberOptional\": Object {\n    \"control\": Object {\n      \"type\": \"number\",\n    },\n    \"description\": \"\",\n    \"name\": \"numberOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"1\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"number\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"number\",\n      \"required\": false,\n    },\n  },\n  \"numberRequired\": Object {\n    \"control\": Object {\n      \"type\": \"number\",\n    },\n    \"description\": \"Description\",\n    \"name\": \"numberRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"number\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"number\",\n      \"required\": true,\n    },\n  },\n  \"objectOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"objectOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ object: 'optional' }\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Record\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"other\",\n      \"raw\": \"Record<string, string>\",\n      \"required\": false,\n      \"value\": \"Record\",\n    },\n  },\n  \"objectRequired\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": \"\",\n    \"name\": \"objectRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Record\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"other\",\n      \"raw\": \"Record<string, string>\",\n      \"required\": true,\n      \"value\": \"Record\",\n    },\n  },\n  \"stringGlobalName\": Object {\n    \"control\": Object {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"stringGlobalName\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'top'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"stringOptional\": Object {\n    \"control\": Object {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"stringOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'stringOptional'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n      \"required\": false,\n    },\n  },\n  \"stringRequired\": Object {\n    \"control\": Object {\n      \"type\": \"text\",\n    },\n    \"description\": \"\",\n    \"name\": \"stringRequired\",\n    \"table\": Object {\n      \"defaultValue\": null,\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": Object {\n      \"name\": \"string\",\n      \"required\": true,\n    },\n  },\n}\n`;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-function-component/docgen.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`react component properties ts-function-component 1`] = `\n\"import React from 'react';\nimport { imported } from '../imported';\nconst local = 'local-value';\n\n/**\n * A component that renders its props\n */\nexport const PropsWriter = props => /*#__PURE__*/React.createElement(\\\\\"pre\\\\\", null, JSON.stringify(props));\nPropsWriter.defaultProps = {\n  numberOptional: 1,\n  stringOptional: 'stringOptional',\n  booleanOptional: false,\n  arrayOptional: ['array', 'optional'],\n  objectOptional: {\n    object: 'optional'\n  },\n  functionOptional: () => 'foo',\n  dateOptional: new Date('20 Jan 1983'),\n  localReference: local,\n  importedReference: imported,\n  globalReference: Date,\n  stringGlobalName: 'top'\n};\nexport const component = PropsWriter;\nPropsWriter.__docgenInfo = {\n  \\\\\"description\\\\\": \\\\\"A component that renders its props\\\\\",\n  \\\\\"methods\\\\\": [],\n  \\\\\"displayName\\\\\": \\\\\"PropsWriter\\\\\",\n  \\\\\"props\\\\\": {\n    \\\\\"numberOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"1\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false,\n      \\\\\"tsType\\\\\": {\n        \\\\\"name\\\\\": \\\\\"number\\\\\"\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\"\n    },\n    \\\\\"stringOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'stringOptional'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false,\n      \\\\\"tsType\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\"\n    },\n    \\\\\"booleanOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"false\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false,\n      \\\\\"tsType\\\\\": {\n        \\\\\"name\\\\\": \\\\\"boolean\\\\\"\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\"\n    },\n    \\\\\"arrayOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"['array', 'optional']\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false,\n      \\\\\"tsType\\\\\": {\n        \\\\\"name\\\\\": \\\\\"Array\\\\\",\n        \\\\\"elements\\\\\": [{\n          \\\\\"name\\\\\": \\\\\"string\\\\\"\n        }],\n        \\\\\"raw\\\\\": \\\\\"string[]\\\\\"\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\"\n    },\n    \\\\\"objectOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{ object: 'optional' }\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false,\n      \\\\\"tsType\\\\\": {\n        \\\\\"name\\\\\": \\\\\"Record\\\\\",\n        \\\\\"elements\\\\\": [{\n          \\\\\"name\\\\\": \\\\\"string\\\\\"\n        }, {\n          \\\\\"name\\\\\": \\\\\"string\\\\\"\n        }],\n        \\\\\"raw\\\\\": \\\\\"Record<string, string>\\\\\"\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\"\n    },\n    \\\\\"functionOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"() => 'foo'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false,\n      \\\\\"tsType\\\\\": {\n        \\\\\"name\\\\\": \\\\\"signature\\\\\",\n        \\\\\"type\\\\\": \\\\\"function\\\\\",\n        \\\\\"raw\\\\\": \\\\\"() => string\\\\\",\n        \\\\\"signature\\\\\": {\n          \\\\\"arguments\\\\\": [],\n          \\\\\"return\\\\\": {\n            \\\\\"name\\\\\": \\\\\"string\\\\\"\n          }\n        }\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\"\n    },\n    \\\\\"dateOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"new Date('20 Jan 1983')\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false,\n      \\\\\"tsType\\\\\": {\n        \\\\\"name\\\\\": \\\\\"Date\\\\\"\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\"\n    },\n    \\\\\"localReference\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'local-value'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false,\n      \\\\\"tsType\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\"\n    },\n    \\\\\"importedReference\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"imported\\\\\",\n        \\\\\"computed\\\\\": true\n      },\n      \\\\\"required\\\\\": false,\n      \\\\\"tsType\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\"\n    },\n    \\\\\"globalReference\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"Date\\\\\",\n        \\\\\"computed\\\\\": true\n      },\n      \\\\\"required\\\\\": false,\n      \\\\\"tsType\\\\\": {\n        \\\\\"name\\\\\": \\\\\"any\\\\\"\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\"\n    },\n    \\\\\"stringGlobalName\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'top'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false,\n      \\\\\"tsType\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\"\n    },\n    \\\\\"numberRequired\\\\\": {\n      \\\\\"required\\\\\": true,\n      \\\\\"tsType\\\\\": {\n        \\\\\"name\\\\\": \\\\\"number\\\\\"\n      },\n      \\\\\"description\\\\\": \\\\\"Description\\\\\"\n    },\n    \\\\\"stringRequired\\\\\": {\n      \\\\\"required\\\\\": true,\n      \\\\\"tsType\\\\\": {\n        \\\\\"name\\\\\": \\\\\"string\\\\\"\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\"\n    },\n    \\\\\"booleanRequired\\\\\": {\n      \\\\\"required\\\\\": true,\n      \\\\\"tsType\\\\\": {\n        \\\\\"name\\\\\": \\\\\"boolean\\\\\"\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\"\n    },\n    \\\\\"arrayRequired\\\\\": {\n      \\\\\"required\\\\\": true,\n      \\\\\"tsType\\\\\": {\n        \\\\\"name\\\\\": \\\\\"Array\\\\\",\n        \\\\\"elements\\\\\": [{\n          \\\\\"name\\\\\": \\\\\"string\\\\\"\n        }],\n        \\\\\"raw\\\\\": \\\\\"string[]\\\\\"\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\"\n    },\n    \\\\\"objectRequired\\\\\": {\n      \\\\\"required\\\\\": true,\n      \\\\\"tsType\\\\\": {\n        \\\\\"name\\\\\": \\\\\"Record\\\\\",\n        \\\\\"elements\\\\\": [{\n          \\\\\"name\\\\\": \\\\\"string\\\\\"\n        }, {\n          \\\\\"name\\\\\": \\\\\"string\\\\\"\n        }],\n        \\\\\"raw\\\\\": \\\\\"Record<string, string>\\\\\"\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\"\n    },\n    \\\\\"functionRequired\\\\\": {\n      \\\\\"required\\\\\": true,\n      \\\\\"tsType\\\\\": {\n        \\\\\"name\\\\\": \\\\\"signature\\\\\",\n        \\\\\"type\\\\\": \\\\\"function\\\\\",\n        \\\\\"raw\\\\\": \\\\\"() => string\\\\\",\n        \\\\\"signature\\\\\": {\n          \\\\\"arguments\\\\\": [],\n          \\\\\"return\\\\\": {\n            \\\\\"name\\\\\": \\\\\"string\\\\\"\n          }\n        }\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\"\n    },\n    \\\\\"dateRequired\\\\\": {\n      \\\\\"required\\\\\": true,\n      \\\\\"tsType\\\\\": {\n        \\\\\"name\\\\\": \\\\\"Date\\\\\"\n      },\n      \\\\\"description\\\\\": \\\\\"\\\\\"\n    }\n  }\n};\"\n`;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-function-component/input.tsx",
    "content": "import React from 'react';\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore (js import not supported in TS)\nimport { imported } from '../imported';\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore no types for this\nimport * as styles from '../imported.module.css';\n\nconst local = 'local-value';\n\ninterface PropsWriterProps {\n  /** Description */\n  numberRequired: number;\n  numberOptional?: number;\n  stringRequired: string;\n  stringOptional?: string;\n  booleanRequired: boolean;\n  booleanOptional?: boolean;\n  arrayRequired: string[];\n  arrayOptional?: string[];\n  objectRequired: Record<string, string>;\n  objectOptional?: Record<string, string>;\n  functionRequired: () => string;\n  functionOptional?: () => string;\n  dateRequired: Date;\n  dateOptional?: Date;\n  localReference?: string;\n  importedReference?: string;\n  globalReference?: any;\n  stringGlobalName?: string;\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore no types for this\n  myClass: typeof styles;\n}\n\n/** A component that renders its props */\nexport const PropsWriter: React.FC<PropsWriterProps> = (props: PropsWriterProps) => (\n  <pre>{JSON.stringify(props)}</pre>\n);\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- we can't expect error as it isn't an error in 18 (development) but it is in 19 (sandbox)\n// @ts-ignore not present on react 19\nPropsWriter.defaultProps = {\n  numberOptional: 1,\n  stringOptional: 'stringOptional',\n  booleanOptional: false,\n  arrayOptional: ['array', 'optional'],\n  objectOptional: { object: 'optional' },\n  functionOptional: () => 'foo',\n  dateOptional: new Date('20 Jan 1983'),\n  localReference: local,\n  importedReference: imported,\n  globalReference: Date,\n  stringGlobalName: 'top',\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore no types for this\n  myClass: styles.foo,\n};\n\nexport const component = PropsWriter;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-function-component/properties.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`react component properties ts-function-component 1`] = `\nObject {\n  \"rows\": Array [\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"1\",\n      },\n      \"description\": \"\",\n      \"name\": \"numberOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"number\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"number\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'stringOptional'\",\n      },\n      \"description\": \"\",\n      \"name\": \"stringOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"false\",\n      },\n      \"description\": \"\",\n      \"name\": \"booleanOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"boolean\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"boolean\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"['array',    'optional']\",\n      },\n      \"description\": \"\",\n      \"name\": \"arrayOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"array\",\n        \"raw\": \"string[]\",\n        \"value\": Array [\n          Object {\n            \"name\": \"string\",\n          },\n        ],\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Array\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ object: 'optional' }\",\n      },\n      \"description\": \"\",\n      \"name\": \"objectOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"other\",\n        \"raw\": \"Record<string, string>\",\n        \"value\": \"Record\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Record\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"() => 'foo'\",\n      },\n      \"description\": \"\",\n      \"name\": \"functionOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"function\",\n        \"raw\": \"() => string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"signature\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"new Date('20 Jan 1983')\",\n      },\n      \"description\": \"\",\n      \"name\": \"dateOptional\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"other\",\n        \"value\": \"Date\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'local-value'\",\n      },\n      \"description\": \"\",\n      \"name\": \"localReference\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"imported\",\n      },\n      \"description\": \"\",\n      \"name\": \"importedReference\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n      \"description\": \"\",\n      \"name\": \"globalReference\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"other\",\n        \"value\": \"any\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"any\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'top'\",\n      },\n      \"description\": \"\",\n      \"name\": \"stringGlobalName\",\n      \"required\": false,\n      \"sbType\": Object {\n        \"name\": \"string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"Description\",\n      \"name\": \"numberRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"number\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"number\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"stringRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"string\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"booleanRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"boolean\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"boolean\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"arrayRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"array\",\n        \"raw\": \"string[]\",\n        \"value\": Array [\n          Object {\n            \"name\": \"string\",\n          },\n        ],\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Array\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"objectRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"other\",\n        \"raw\": \"Record<string, string>\",\n        \"value\": \"Record\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Record\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"functionRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"function\",\n        \"raw\": \"() => string\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"signature\",\n      },\n    },\n    Object {\n      \"defaultValue\": null,\n      \"description\": \"\",\n      \"name\": \"dateRequired\",\n      \"required\": true,\n      \"sbType\": Object {\n        \"name\": \"other\",\n        \"value\": \"Date\",\n      },\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n    },\n  ],\n}\n`;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-function-component-inline-defaults/argTypes.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`react component properties ts-function-component-inline-defaults 1`] = `\nObject {\n  \"arrayOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"arrayOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"['array', 'optional']\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"booleanOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"booleanOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"false\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"dateOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"dateOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"new Date('20 Jan 1983')\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"enumGlobalName\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"enumGlobalName\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'top'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"functionOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"functionOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"() => 'foo'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"globalReference\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"globalReference\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"importedReference\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"importedReference\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"imported\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"localReference\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"localReference\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'local-value'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"numberOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"numberOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"1\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"objectOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"objectOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ object: 'optional' }\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"stringGlobalName\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"stringGlobalName\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'top'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"stringOptional\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"stringOptional\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'stringOptional'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n  \"unionGlobalName\": Object {\n    \"control\": Object {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"unionGlobalName\",\n    \"table\": Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'top'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": Object {\n      \"required\": false,\n    },\n  },\n}\n`;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-function-component-inline-defaults/docgen.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`react component properties ts-function-component-inline-defaults 1`] = `\n\"import React from 'react';\nimport { imported } from '../imported';\nconst local = 'local-value';\nvar GlobalNames;\n\n(function (GlobalNames) {\n  GlobalNames[\\\\\"top\\\\\"] = \\\\\"top\\\\\";\n  GlobalNames[\\\\\"left\\\\\"] = \\\\\"left\\\\\";\n})(GlobalNames || (GlobalNames = {}));\n\n/**\n * A component that renders its props\n */\nexport const PropsWriter = ({\n  numberOptional = 1,\n  stringOptional = 'stringOptional',\n  booleanOptional = false,\n  arrayOptional = ['array', 'optional'],\n  objectOptional = {\n    object: 'optional'\n  },\n  functionOptional = () => 'foo',\n  dateOptional = new Date('20 Jan 1983'),\n  localReference = local,\n  importedReference = imported,\n  globalReference = Date,\n  stringGlobalName = 'top',\n  unionGlobalName = 'top',\n  // If we use this default value, controls will try and render it in a JSON object editor\n  // which leads to a circular value error.\n  // unionGlobalNameMixed = 'top',\n  enumGlobalName = 'top'\n}) => /*#__PURE__*/React.createElement(\\\\\"pre\\\\\", null, JSON.stringify({\n  numberOptional,\n  stringOptional,\n  booleanOptional,\n  arrayOptional,\n  objectOptional,\n  functionOptional,\n  dateOptional,\n  localReference,\n  importedReference,\n  globalReference,\n  stringGlobalName,\n  unionGlobalName,\n  // unionGlobalNameMixed,\n  enumGlobalName\n}));\nexport const component = PropsWriter;\nPropsWriter.__docgenInfo = {\n  \\\\\"description\\\\\": \\\\\"A component that renders its props\\\\\",\n  \\\\\"methods\\\\\": [],\n  \\\\\"displayName\\\\\": \\\\\"PropsWriter\\\\\",\n  \\\\\"props\\\\\": {\n    \\\\\"numberOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"1\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"stringOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'stringOptional'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"booleanOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"false\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"arrayOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"['array', 'optional']\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"objectOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"{ object: 'optional' }\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"functionOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"() => 'foo'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"dateOptional\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"new Date('20 Jan 1983')\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"localReference\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'local-value'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"importedReference\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"imported\\\\\",\n        \\\\\"computed\\\\\": true\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"globalReference\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"Date\\\\\",\n        \\\\\"computed\\\\\": true\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"stringGlobalName\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'top'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"unionGlobalName\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'top'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    },\n    \\\\\"enumGlobalName\\\\\": {\n      \\\\\"defaultValue\\\\\": {\n        \\\\\"value\\\\\": \\\\\"'top'\\\\\",\n        \\\\\"computed\\\\\": false\n      },\n      \\\\\"required\\\\\": false\n    }\n  }\n};\"\n`;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-function-component-inline-defaults/input.tsx",
    "content": "import React from 'react';\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore-error (importing a js file)\nimport { imported } from '../imported';\n\nconst local = 'local-value';\n\nenum GlobalNames {\n  top = 'top',\n  left = 'left',\n}\n\ninterface PropsWriterProps {\n  /** Description */\n  numberRequired: number;\n  numberOptional?: number;\n  stringRequired: string;\n  stringOptional?: string;\n  booleanRequired: boolean;\n  booleanOptional?: boolean;\n  arrayRequired: string[];\n  arrayOptional?: string[];\n  objectRequired: Record<string, string>;\n  objectOptional?: Record<string, string>;\n  functionRequired: () => string;\n  functionOptional?: () => string;\n  dateRequired: Date;\n  dateOptional?: Date;\n  localReference?: string;\n  importedReference?: string;\n  globalReference?: any;\n  stringGlobalName?: string;\n  unionGlobalName?: 'top' | 'left';\n  unionGlobalNameMixed?: 'top' | number;\n  enumGlobalName?: GlobalNames;\n}\n\n/** A component that renders its props */\nexport const PropsWriter: React.FC<PropsWriterProps> = ({\n  numberOptional = 1,\n  stringOptional = 'stringOptional',\n  booleanOptional = false,\n  arrayOptional = ['array', 'optional'],\n  objectOptional = { object: 'optional' },\n  functionOptional = () => 'foo',\n  dateOptional = new Date('20 Jan 1983'),\n  localReference = local,\n  importedReference = imported,\n  globalReference = Date,\n  stringGlobalName = 'top',\n  unionGlobalName = 'top',\n  // If we use this default value, controls will try and render it in a JSON object editor\n  // which leads to a circular value error.\n  // unionGlobalNameMixed = 'top',\n  enumGlobalName = 'top',\n}) => (\n  <pre>\n    {JSON.stringify({\n      numberOptional,\n      stringOptional,\n      booleanOptional,\n      arrayOptional,\n      objectOptional,\n      functionOptional,\n      dateOptional,\n      localReference,\n      importedReference,\n      globalReference,\n      stringGlobalName,\n      unionGlobalName,\n      // unionGlobalNameMixed,\n      enumGlobalName,\n    })}\n  </pre>\n);\n\nexport const component = PropsWriter;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-function-component-inline-defaults/properties.snapshot",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`react component properties ts-function-component-inline-defaults 1`] = `\nObject {\n  \"rows\": Array [\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"1\",\n      },\n      \"description\": undefined,\n      \"name\": \"numberOptional\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'stringOptional'\",\n      },\n      \"description\": undefined,\n      \"name\": \"stringOptional\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"false\",\n      },\n      \"description\": undefined,\n      \"name\": \"booleanOptional\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"['array', 'optional']\",\n      },\n      \"description\": undefined,\n      \"name\": \"arrayOptional\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"{ object: 'optional' }\",\n      },\n      \"description\": undefined,\n      \"name\": \"objectOptional\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"() => 'foo'\",\n      },\n      \"description\": undefined,\n      \"name\": \"functionOptional\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"new Date('20 Jan 1983')\",\n      },\n      \"description\": undefined,\n      \"name\": \"dateOptional\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'local-value'\",\n      },\n      \"description\": undefined,\n      \"name\": \"localReference\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"imported\",\n      },\n      \"description\": undefined,\n      \"name\": \"importedReference\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"Date\",\n      },\n      \"description\": undefined,\n      \"name\": \"globalReference\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'top'\",\n      },\n      \"description\": undefined,\n      \"name\": \"stringGlobalName\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'top'\",\n      },\n      \"description\": undefined,\n      \"name\": \"unionGlobalName\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    Object {\n      \"defaultValue\": Object {\n        \"detail\": undefined,\n        \"summary\": \"'top'\",\n      },\n      \"description\": undefined,\n      \"name\": \"enumGlobalName\",\n      \"required\": false,\n      \"type\": Object {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n  ],\n}\n`;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-html/argTypes.snapshot",
    "content": "{}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-html/docgen.snapshot",
    "content": "import React from 'react';\nexport const TypeScriptHtmlComponent = () => /*#__PURE__*/React.createElement(\"div\", null, \"My HTML component\");\nexport const component = TypeScriptHtmlComponent;\nTypeScriptHtmlComponent.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"TypeScriptHtmlComponent\"\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-html/input.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\ninterface TypeScriptHtmlComponentProps {\n  text: string;\n}\n\nexport const TypeScriptHtmlComponent: FC<\n  React.HTMLAttributes<HTMLDivElement> & TypeScriptHtmlComponentProps\n> = () => <div>My HTML component</div>;\n\nexport const component = TypeScriptHtmlComponent;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-html/properties.snapshot",
    "content": "{\n  \"rows\": [],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-jsdoc/argTypes.snapshot",
    "content": "{}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-jsdoc/docgen.snapshot",
    "content": "import React from 'react';\n/** Button functional component (React.FC) */\nconst TypeScriptProps = ({\n  case1,\n  case2\n}) => /*#__PURE__*/React.createElement(\"button\", {\n  type: \"button\",\n  onClick: case1\n}, \"JSDoc with TypeScript! \", case2);\nexport const component = TypeScriptProps;\nTypeScriptProps.__docgenInfo = {\n  \"description\": \"Button functional component (React.FC)\",\n  \"methods\": [],\n  \"displayName\": \"TypeScriptProps\"\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-jsdoc/input.tsx",
    "content": "import type { FC, SyntheticEvent } from 'react';\nimport React from 'react';\n\ninterface TSProps {\n  /**\n   * This is case 1.\n   *\n   * @param {SyntheticEvent} event - React's original event.\n   * @returns {void}\n   */\n  case1: (event: SyntheticEvent) => void;\n  /**\n   * Should not be visible since it's ignored.\n   *\n   * @ignore\n   */\n  case2: string;\n}\n\n/** Button functional component (React.FC) */\nconst TypeScriptProps: FC<TSProps> = ({ case1, case2 }) => (\n  <button type=\"button\" onClick={case1}>\n    JSDoc with TypeScript! {case2}\n  </button>\n);\n\nexport const component = TypeScriptProps;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-jsdoc/properties.snapshot",
    "content": "{\n  \"rows\": [],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-react-fc/argTypes.snapshot",
    "content": "{}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-react-fc/docgen.snapshot",
    "content": "import React from 'react';\nvar DefaultEnum = /*#__PURE__*/function (DefaultEnum) {\n  DefaultEnum[DefaultEnum[\"TopLeft\"] = 0] = \"TopLeft\";\n  DefaultEnum[DefaultEnum[\"TopRight\"] = 1] = \"TopRight\";\n  DefaultEnum[DefaultEnum[\"TopCenter\"] = 2] = \"TopCenter\";\n  return DefaultEnum;\n}(DefaultEnum || {});\nvar NumericEnum = /*#__PURE__*/function (NumericEnum) {\n  NumericEnum[NumericEnum[\"TopLeft\"] = 0] = \"TopLeft\";\n  NumericEnum[NumericEnum[\"TopRight\"] = 1] = \"TopRight\";\n  NumericEnum[NumericEnum[\"TopCenter\"] = 2] = \"TopCenter\";\n  return NumericEnum;\n}(NumericEnum || {});\nvar StringEnum = /*#__PURE__*/function (StringEnum) {\n  StringEnum[\"TopLeft\"] = \"top-left\";\n  StringEnum[\"TopRight\"] = \"top-right\";\n  StringEnum[\"TopCenter\"] = \"top-center\";\n  return StringEnum;\n}(StringEnum || {});\nexport const TypeScriptProps = () => /*#__PURE__*/React.createElement(\"div\", null, \"TypeScript!\");\nexport const component = TypeScriptProps;\nTypeScriptProps.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"TypeScriptProps\"\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-react-fc/input.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\ninterface ItemInterface {\n  text: string;\n  value: string;\n}\n\ninterface PersonInterface {\n  name: string;\n}\n\ntype InterfaceIntersection = ItemInterface & PersonInterface;\n\ninterface GenericInterface<T> {\n  value: T;\n}\n\nenum DefaultEnum {\n  TopLeft,\n  TopRight,\n  TopCenter,\n}\n\nenum NumericEnum {\n  TopLeft = 0,\n  TopRight,\n  TopCenter,\n}\n\nenum StringEnum {\n  TopLeft = 'top-left',\n  TopRight = 'top-right',\n  TopCenter = 'top-center',\n}\n\ntype EnumUnion = DefaultEnum | NumericEnum;\n\ntype StringLiteralUnion = 'top-left' | 'top-right' | 'top-center';\ntype NumericLiteralUnion = 0 | 1 | 2;\n\ntype StringAlias = string;\ntype NumberAlias = number;\ntype AliasesIntersection = StringAlias & NumberAlias;\ntype AliasesUnion = StringAlias | NumberAlias;\ninterface GenericAlias<T> {\n  value: T;\n}\n\ninterface TypeScriptPropsProps {\n  any: any;\n  string: string;\n  bool: boolean;\n  number: number;\n  voidFunc: () => void;\n  funcWithArgsAndReturns: (a: string, b: string) => string;\n  funcWithunionArg: (a: string | number) => string;\n  funcWithMultipleUnionReturns: () => string | ItemInterface;\n  funcWithIndexTypes: <T, K extends keyof T>(o: T, propertyNames: K[]) => T[K][];\n  symbol: symbol;\n  interface: ItemInterface;\n  genericInterface: GenericInterface<string>;\n  arrayOfPrimitive: string[];\n  arrayOfComplexObject: ItemInterface[];\n  tupleOfPrimitive: [string, number];\n  tupleWithComplexType: [string, ItemInterface];\n  defaultEnum: DefaultEnum;\n  numericEnum: NumericEnum;\n  stringEnum: StringEnum;\n  enumUnion: EnumUnion;\n  recordOfPrimitive: Record<string, number>;\n  recordOfComplexObject: Record<string, ItemInterface>;\n  intersectionType: InterfaceIntersection;\n  intersectionWithInlineType: ItemInterface & { inlineValue: string };\n  unionOfPrimitive: string | number;\n  unionOfComplexType: ItemInterface | InterfaceIntersection;\n  nullablePrimitive?: string;\n  nullableComplexType?: ItemInterface;\n  nullableComplexTypeUndefinedDefaultValue?: ItemInterface;\n  readonly readonlyPrimitive: string;\n  typeAlias: StringAlias;\n  aliasesIntersection: AliasesIntersection;\n  aliasesUnion: AliasesUnion;\n  genericAlias: GenericAlias<string>;\n  namedStringLiteralUnion: StringLiteralUnion;\n  inlinedStringLiteralUnion: 'bottom-left' | 'bottom-right' | 'bottom-center';\n  namedNumericLiteralUnion: NumericLiteralUnion;\n  inlinedNumericLiteralUnion: 0 | 1 | 2;\n}\n\nexport const TypeScriptProps: FC<TypeScriptPropsProps> = () => <div>TypeScript!</div>;\n\nexport const component = TypeScriptProps;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-react-fc/properties.snapshot",
    "content": "{\n  \"rows\": [],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-types/argTypes.snapshot",
    "content": "{\n  \"aliasesUnion\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"aliasesUnion\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'foo'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"any\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"any\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'Any value'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"arrayOfComplexObject\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"arrayOfComplexObject\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"[{ text: 'foo', value: 'bar' }]\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"arrayOfPrimitive\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"arrayOfPrimitive\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"['foo', 'bar']\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"bool\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"bool\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"true\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"defaultEnum\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"defaultEnum\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"DefaultEnum.TopRight\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"enumUnion\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"enumUnion\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"DefaultEnum.TopLeft\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"funcWithArgsAndReturns\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"funcWithArgsAndReturns\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"function concat(a: string, b: string): string {\n  return a + b;\n}\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"genericAlias\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"genericAlias\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"{ value: 'foo' }\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"genericInterface\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"genericInterface\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"{ value: 'A string value' }\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"inlinedNumericLiteralUnion\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"inlinedNumericLiteralUnion\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"1\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"inlinedStringLiteralUnion\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"inlinedStringLiteralUnion\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'bottom-right'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"interface\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"interface\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"{ text: 'foo', value: 'bar' }\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"intersectionType\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"intersectionType\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"{ text: 'foo', value: 'bar', name: 'foo-bar' }\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"intersectionWithInlineType\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"intersectionWithInlineType\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"{ text: 'foo', value: 'bar', inlineValue: 'this is inlined' }\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"namedNumericLiteralUnion\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"namedNumericLiteralUnion\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"0\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"namedStringLiteralUnion\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"namedStringLiteralUnion\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'top-right'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"nullableComplexTypeUndefinedDefaultValue\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"nullableComplexTypeUndefinedDefaultValue\",\n    \"table\": {\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"number\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"number\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"5\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"numericEnum\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"numericEnum\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"NumericEnum.TopRight\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"recordOfComplexObject\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"recordOfComplexObject\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"{ foo: { text: 'bar', value: 'bar2' } }\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"recordOfPrimitive\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"recordOfPrimitive\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"{ foo: 1, bar: 2 }\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"string\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"string\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'A string value'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"stringEnum\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"stringEnum\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"StringEnum.TopRight\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"symbol\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"symbol\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"Symbol('Default symbol')\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"tupleOfPrimitive\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"tupleOfPrimitive\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"['string value', 5]\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"tupleWithComplexType\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"tupleWithComplexType\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"['string value', { text: 'foo', value: 'bar' }]\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"typeAlias\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"typeAlias\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'foo'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"unionOfComplexType\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"unionOfComplexType\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"{ text: 'foo', value: 'bar' }\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"unionOfPrimitive\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"unionOfPrimitive\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'A string value'\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n  \"voidFunc\": {\n    \"control\": {\n      \"type\": \"object\",\n    },\n    \"description\": undefined,\n    \"name\": \"voidFunc\",\n    \"table\": {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"() => {}\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    \"type\": {\n      \"required\": false,\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-types/docgen.snapshot",
    "content": "import React from 'react';\nfunction concat(a, b) {\n  return a + b;\n}\nvar DefaultEnum = /*#__PURE__*/function (DefaultEnum) {\n  DefaultEnum[DefaultEnum[\"TopLeft\"] = 0] = \"TopLeft\";\n  DefaultEnum[DefaultEnum[\"TopRight\"] = 1] = \"TopRight\";\n  DefaultEnum[DefaultEnum[\"TopCenter\"] = 2] = \"TopCenter\";\n  return DefaultEnum;\n}(DefaultEnum || {});\nvar NumericEnum = /*#__PURE__*/function (NumericEnum) {\n  NumericEnum[NumericEnum[\"TopLeft\"] = 0] = \"TopLeft\";\n  NumericEnum[NumericEnum[\"TopRight\"] = 1] = \"TopRight\";\n  NumericEnum[NumericEnum[\"TopCenter\"] = 2] = \"TopCenter\";\n  return NumericEnum;\n}(NumericEnum || {});\nvar StringEnum = /*#__PURE__*/function (StringEnum) {\n  StringEnum[\"TopLeft\"] = \"top-left\";\n  StringEnum[\"TopRight\"] = \"top-right\";\n  StringEnum[\"TopCenter\"] = \"top-center\";\n  return StringEnum;\n}(StringEnum || {});\nexport const TypeScriptProps = () => /*#__PURE__*/React.createElement(\"div\", null, \"TypeScript!\");\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- we can't expect error as it isn't an error in 18 (development) but it is in 19 (sandbox)\n// @ts-ignore not present on react 19\nTypeScriptProps.defaultProps = {\n  any: 'Any value',\n  string: 'A string value',\n  bool: true,\n  number: 5,\n  voidFunc: () => {},\n  funcWithArgsAndReturns: concat,\n  symbol: Symbol('Default symbol'),\n  interface: {\n    text: 'foo',\n    value: 'bar'\n  },\n  genericInterface: {\n    value: 'A string value'\n  },\n  arrayOfPrimitive: ['foo', 'bar'],\n  arrayOfComplexObject: [{\n    text: 'foo',\n    value: 'bar'\n  }],\n  tupleOfPrimitive: ['string value', 5],\n  tupleWithComplexType: ['string value', {\n    text: 'foo',\n    value: 'bar'\n  }],\n  defaultEnum: DefaultEnum.TopRight,\n  numericEnum: NumericEnum.TopRight,\n  stringEnum: StringEnum.TopRight,\n  enumUnion: DefaultEnum.TopLeft,\n  recordOfPrimitive: {\n    foo: 1,\n    bar: 2\n  },\n  recordOfComplexObject: {\n    foo: {\n      text: 'bar',\n      value: 'bar2'\n    }\n  },\n  intersectionType: {\n    text: 'foo',\n    value: 'bar',\n    name: 'foo-bar'\n  },\n  intersectionWithInlineType: {\n    text: 'foo',\n    value: 'bar',\n    inlineValue: 'this is inlined'\n  },\n  unionOfPrimitive: 'A string value',\n  unionOfComplexType: {\n    text: 'foo',\n    value: 'bar'\n  },\n  nullableComplexTypeUndefinedDefaultValue: undefined,\n  typeAlias: 'foo',\n  aliasesUnion: 'foo',\n  genericAlias: {\n    value: 'foo'\n  },\n  namedStringLiteralUnion: 'top-right',\n  inlinedStringLiteralUnion: 'bottom-right',\n  namedNumericLiteralUnion: 0,\n  inlinedNumericLiteralUnion: 1\n};\nexport const component = TypeScriptProps;\nTypeScriptProps.__docgenInfo = {\n  \"description\": \"\",\n  \"methods\": [],\n  \"displayName\": \"TypeScriptProps\",\n  \"props\": {\n    \"any\": {\n      \"defaultValue\": {\n        \"value\": \"'Any value'\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"string\": {\n      \"defaultValue\": {\n        \"value\": \"'A string value'\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"bool\": {\n      \"defaultValue\": {\n        \"value\": \"true\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"number\": {\n      \"defaultValue\": {\n        \"value\": \"5\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"voidFunc\": {\n      \"defaultValue\": {\n        \"value\": \"() => {}\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"funcWithArgsAndReturns\": {\n      \"defaultValue\": {\n        \"value\": \"function concat(a: string, b: string): string {\\n  return a + b;\\n}\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"symbol\": {\n      \"defaultValue\": {\n        \"value\": \"Symbol('Default symbol')\",\n        \"computed\": true\n      },\n      \"required\": false\n    },\n    \"interface\": {\n      \"defaultValue\": {\n        \"value\": \"{ text: 'foo', value: 'bar' }\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"genericInterface\": {\n      \"defaultValue\": {\n        \"value\": \"{ value: 'A string value' }\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"arrayOfPrimitive\": {\n      \"defaultValue\": {\n        \"value\": \"['foo', 'bar']\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"arrayOfComplexObject\": {\n      \"defaultValue\": {\n        \"value\": \"[{ text: 'foo', value: 'bar' }]\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"tupleOfPrimitive\": {\n      \"defaultValue\": {\n        \"value\": \"['string value', 5]\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"tupleWithComplexType\": {\n      \"defaultValue\": {\n        \"value\": \"['string value', { text: 'foo', value: 'bar' }]\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"defaultEnum\": {\n      \"defaultValue\": {\n        \"value\": \"DefaultEnum.TopRight\",\n        \"computed\": true\n      },\n      \"required\": false\n    },\n    \"numericEnum\": {\n      \"defaultValue\": {\n        \"value\": \"NumericEnum.TopRight\",\n        \"computed\": true\n      },\n      \"required\": false\n    },\n    \"stringEnum\": {\n      \"defaultValue\": {\n        \"value\": \"StringEnum.TopRight\",\n        \"computed\": true\n      },\n      \"required\": false\n    },\n    \"enumUnion\": {\n      \"defaultValue\": {\n        \"value\": \"DefaultEnum.TopLeft\",\n        \"computed\": true\n      },\n      \"required\": false\n    },\n    \"recordOfPrimitive\": {\n      \"defaultValue\": {\n        \"value\": \"{ foo: 1, bar: 2 }\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"recordOfComplexObject\": {\n      \"defaultValue\": {\n        \"value\": \"{ foo: { text: 'bar', value: 'bar2' } }\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"intersectionType\": {\n      \"defaultValue\": {\n        \"value\": \"{ text: 'foo', value: 'bar', name: 'foo-bar' }\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"intersectionWithInlineType\": {\n      \"defaultValue\": {\n        \"value\": \"{ text: 'foo', value: 'bar', inlineValue: 'this is inlined' }\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"unionOfPrimitive\": {\n      \"defaultValue\": {\n        \"value\": \"'A string value'\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"unionOfComplexType\": {\n      \"defaultValue\": {\n        \"value\": \"{ text: 'foo', value: 'bar' }\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"nullableComplexTypeUndefinedDefaultValue\": {\n      \"defaultValue\": {\n        \"value\": \"undefined\",\n        \"computed\": true\n      },\n      \"required\": false\n    },\n    \"typeAlias\": {\n      \"defaultValue\": {\n        \"value\": \"'foo'\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"aliasesUnion\": {\n      \"defaultValue\": {\n        \"value\": \"'foo'\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"genericAlias\": {\n      \"defaultValue\": {\n        \"value\": \"{ value: 'foo' }\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"namedStringLiteralUnion\": {\n      \"defaultValue\": {\n        \"value\": \"'top-right'\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"inlinedStringLiteralUnion\": {\n      \"defaultValue\": {\n        \"value\": \"'bottom-right'\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"namedNumericLiteralUnion\": {\n      \"defaultValue\": {\n        \"value\": \"0\",\n        \"computed\": false\n      },\n      \"required\": false\n    },\n    \"inlinedNumericLiteralUnion\": {\n      \"defaultValue\": {\n        \"value\": \"1\",\n        \"computed\": false\n      },\n      \"required\": false\n    }\n  }\n};"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-types/input.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nfunction concat(a: string, b: string): string {\n  return a + b;\n}\n\ninterface ItemInterface {\n  text: string;\n  value: string;\n}\n\ninterface PersonInterface {\n  name: string;\n}\n\ntype InterfaceIntersection = ItemInterface & PersonInterface;\n\ninterface GenericInterface<T> {\n  value: T;\n}\n\nenum DefaultEnum {\n  TopLeft,\n  TopRight,\n  TopCenter,\n}\n\nenum NumericEnum {\n  TopLeft = 0,\n  TopRight,\n  TopCenter,\n}\n\nenum StringEnum {\n  TopLeft = 'top-left',\n  TopRight = 'top-right',\n  TopCenter = 'top-center',\n}\n\ntype EnumUnion = DefaultEnum | NumericEnum;\n\ntype StringLiteralUnion = 'top-left' | 'top-right' | 'top-center';\ntype NumericLiteralUnion = 0 | 1 | 2;\n\ntype StringAlias = string;\ntype NumberAlias = number;\ntype AliasesIntersection = StringAlias & NumberAlias;\ntype AliasesUnion = StringAlias | NumberAlias;\ninterface GenericAlias<T> {\n  value: T;\n}\n\ninterface TypeScriptPropsProps {\n  any: any;\n  string: string;\n  bool: boolean;\n  number: number;\n  voidFunc: () => void;\n  funcWithArgsAndReturns: (a: string, b: string) => string;\n  funcWithunionArg: (a: string | number) => string;\n  funcWithMultipleUnionReturns: () => string | ItemInterface;\n  funcWithIndexTypes: <T, K extends keyof T>(o: T, propertyNames: K[]) => T[K][];\n  symbol: symbol;\n  interface: ItemInterface;\n  genericInterface: GenericInterface<string>;\n  arrayOfPrimitive: string[];\n  arrayOfComplexObject: ItemInterface[];\n  tupleOfPrimitive: [string, number];\n  tupleWithComplexType: [string, ItemInterface];\n  defaultEnum: DefaultEnum;\n  numericEnum: NumericEnum;\n  stringEnum: StringEnum;\n  enumUnion: EnumUnion;\n  recordOfPrimitive: Record<string, number>;\n  recordOfComplexObject: Record<string, ItemInterface>;\n  intersectionType: InterfaceIntersection;\n  intersectionWithInlineType: ItemInterface & { inlineValue: string };\n  unionOfPrimitive: string | number;\n  unionOfComplexType: ItemInterface | InterfaceIntersection;\n  nullablePrimitive?: string;\n  nullableComplexType?: ItemInterface;\n  nullableComplexTypeUndefinedDefaultValue?: ItemInterface;\n  readonly readonlyPrimitive: string;\n  typeAlias: StringAlias;\n  aliasesIntersection: AliasesIntersection;\n  aliasesUnion: AliasesUnion;\n  genericAlias: GenericAlias<string>;\n  namedStringLiteralUnion: StringLiteralUnion;\n  inlinedStringLiteralUnion: 'bottom-left' | 'bottom-right' | 'bottom-center';\n  namedNumericLiteralUnion: NumericLiteralUnion;\n  inlinedNumericLiteralUnion: 0 | 1 | 2;\n}\n\nexport const TypeScriptProps: FC<TypeScriptPropsProps> = () => <div>TypeScript!</div>;\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- we can't expect error as it isn't an error in 18 (development) but it is in 19 (sandbox)\n// @ts-ignore not present on react 19\nTypeScriptProps.defaultProps = {\n  any: 'Any value',\n  string: 'A string value',\n  bool: true,\n  number: 5,\n  voidFunc: () => {},\n  funcWithArgsAndReturns: concat,\n  symbol: Symbol('Default symbol'),\n  interface: { text: 'foo', value: 'bar' },\n  genericInterface: { value: 'A string value' },\n  arrayOfPrimitive: ['foo', 'bar'],\n  arrayOfComplexObject: [{ text: 'foo', value: 'bar' }],\n  tupleOfPrimitive: ['string value', 5],\n  tupleWithComplexType: ['string value', { text: 'foo', value: 'bar' }],\n  defaultEnum: DefaultEnum.TopRight,\n  numericEnum: NumericEnum.TopRight,\n  stringEnum: StringEnum.TopRight,\n  enumUnion: DefaultEnum.TopLeft,\n  recordOfPrimitive: { foo: 1, bar: 2 },\n  recordOfComplexObject: { foo: { text: 'bar', value: 'bar2' } },\n  intersectionType: { text: 'foo', value: 'bar', name: 'foo-bar' },\n  intersectionWithInlineType: { text: 'foo', value: 'bar', inlineValue: 'this is inlined' },\n  unionOfPrimitive: 'A string value',\n  unionOfComplexType: { text: 'foo', value: 'bar' },\n  nullableComplexTypeUndefinedDefaultValue: undefined,\n  typeAlias: 'foo',\n  aliasesUnion: 'foo',\n  genericAlias: { value: 'foo' },\n  namedStringLiteralUnion: 'top-right',\n  inlinedStringLiteralUnion: 'bottom-right',\n  namedNumericLiteralUnion: 0,\n  inlinedNumericLiteralUnion: 1,\n};\n\nexport const component = TypeScriptProps;\n"
  },
  {
    "path": "code/renderers/react/template/stories/docgen-components/ts-types/properties.snapshot",
    "content": "{\n  \"rows\": [\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'Any value'\",\n      },\n      \"description\": undefined,\n      \"name\": \"any\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'A string value'\",\n      },\n      \"description\": undefined,\n      \"name\": \"string\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"true\",\n      },\n      \"description\": undefined,\n      \"name\": \"bool\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"5\",\n      },\n      \"description\": undefined,\n      \"name\": \"number\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"() => {}\",\n      },\n      \"description\": undefined,\n      \"name\": \"voidFunc\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"function concat(a: string, b: string): string {\n  return a + b;\n}\",\n      },\n      \"description\": undefined,\n      \"name\": \"funcWithArgsAndReturns\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"Symbol('Default symbol')\",\n      },\n      \"description\": undefined,\n      \"name\": \"symbol\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"{ text: 'foo', value: 'bar' }\",\n      },\n      \"description\": undefined,\n      \"name\": \"interface\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"{ value: 'A string value' }\",\n      },\n      \"description\": undefined,\n      \"name\": \"genericInterface\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"['foo', 'bar']\",\n      },\n      \"description\": undefined,\n      \"name\": \"arrayOfPrimitive\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"[{ text: 'foo', value: 'bar' }]\",\n      },\n      \"description\": undefined,\n      \"name\": \"arrayOfComplexObject\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"['string value', 5]\",\n      },\n      \"description\": undefined,\n      \"name\": \"tupleOfPrimitive\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"['string value', { text: 'foo', value: 'bar' }]\",\n      },\n      \"description\": undefined,\n      \"name\": \"tupleWithComplexType\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"DefaultEnum.TopRight\",\n      },\n      \"description\": undefined,\n      \"name\": \"defaultEnum\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"NumericEnum.TopRight\",\n      },\n      \"description\": undefined,\n      \"name\": \"numericEnum\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"StringEnum.TopRight\",\n      },\n      \"description\": undefined,\n      \"name\": \"stringEnum\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"DefaultEnum.TopLeft\",\n      },\n      \"description\": undefined,\n      \"name\": \"enumUnion\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"{ foo: 1, bar: 2 }\",\n      },\n      \"description\": undefined,\n      \"name\": \"recordOfPrimitive\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"{ foo: { text: 'bar', value: 'bar2' } }\",\n      },\n      \"description\": undefined,\n      \"name\": \"recordOfComplexObject\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"{ text: 'foo', value: 'bar', name: 'foo-bar' }\",\n      },\n      \"description\": undefined,\n      \"name\": \"intersectionType\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"{ text: 'foo', value: 'bar', inlineValue: 'this is inlined' }\",\n      },\n      \"description\": undefined,\n      \"name\": \"intersectionWithInlineType\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'A string value'\",\n      },\n      \"description\": undefined,\n      \"name\": \"unionOfPrimitive\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"{ text: 'foo', value: 'bar' }\",\n      },\n      \"description\": undefined,\n      \"name\": \"unionOfComplexType\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": null,\n      \"description\": undefined,\n      \"name\": \"nullableComplexTypeUndefinedDefaultValue\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'foo'\",\n      },\n      \"description\": undefined,\n      \"name\": \"typeAlias\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'foo'\",\n      },\n      \"description\": undefined,\n      \"name\": \"aliasesUnion\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"{ value: 'foo' }\",\n      },\n      \"description\": undefined,\n      \"name\": \"genericAlias\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'top-right'\",\n      },\n      \"description\": undefined,\n      \"name\": \"namedStringLiteralUnion\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"'bottom-right'\",\n      },\n      \"description\": undefined,\n      \"name\": \"inlinedStringLiteralUnion\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"0\",\n      },\n      \"description\": undefined,\n      \"name\": \"namedNumericLiteralUnion\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n    {\n      \"defaultValue\": {\n        \"detail\": undefined,\n        \"summary\": \"1\",\n      },\n      \"description\": undefined,\n      \"name\": \"inlinedNumericLiteralUnion\",\n      \"required\": false,\n      \"type\": {\n        \"detail\": undefined,\n        \"summary\": \"unknown\",\n      },\n    },\n  ],\n}"
  },
  {
    "path": "code/renderers/react/template/stories/errors.stories.tsx",
    "content": "import React from 'react';\n\nconst badOutput = { renderable: 'no, react can not render objects' };\nconst BadComponent = () => badOutput;\n\nexport default {\n  component: BadComponent,\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n  tags: ['!test', '!vitest'],\n};\n\nexport const RenderThrows = {\n  render() {\n    throw new Error('storyFn threw an error! WHOOPS');\n  },\n};\n\nexport const ComponentIsUnrenderable = {};\n\nexport const StoryIsUnrenderable = {\n  render: () => badOutput,\n};\n\nexport const StoryContainsUnrenderable = {\n  render: () => (\n    <div>\n      {/* @ts-expect-error we're doing it wrong here on purpose */}\n      <BadComponent />\n    </div>\n  ),\n};\n"
  },
  {
    "path": "code/renderers/react/template/stories/hooks.stories.tsx",
    "content": "import type { FC } from 'react';\nimport React, { useState } from 'react';\n\nconst ButtonWithState: FC = () => {\n  const [count, setCount] = useState(0);\n  return (\n    <button type=\"button\" onClick={() => setCount(count + 1)}>\n      {`count: ${count}`}\n    </button>\n  );\n};\n\nexport default {\n  component: ButtonWithState,\n};\n\nexport const Basic = {};\n"
  },
  {
    "path": "code/renderers/react/template/stories/js-argtypes.stories.jsx",
    "content": "import React, { useState } from 'react';\n\nimport { PureArgsTable as ArgsTable } from '@storybook/addon-docs/blocks';\n\nimport { mapValues } from 'es-toolkit/object';\nimport PropTypes from 'prop-types';\nimport { inferControls } from 'storybook/preview-api';\nimport { ThemeProvider, convert, themes } from 'storybook/theming';\n\n// import { component as JsStyledDocgenComponent } from './__testfixtures__/8279-js-styled-docgen/input';\nimport { component as JsPropTypesOneofComponent } from './docgen-components/8140-js-prop-types-oneof/input.jsx';\nimport { component as JsStaticPropTypesComponent } from './docgen-components/8428-js-static-prop-types/input.jsx';\nimport { component as JsHocComponent } from './docgen-components/9023-js-hoc/input.jsx';\nimport { component as JsProptypesShapeComponent } from './docgen-components/9399-js-proptypes-shape/input.jsx';\nimport { component as JsReactMemoComponent } from './docgen-components/9586-js-react-memo/input.jsx';\n// import { component as JsStyledComponentsComponent } from './__testfixtures__/8663-js-styled-components/input';\nimport { component as JsDefaultValuesComponent } from './docgen-components/9626-js-default-values/input.jsx';\nimport { component as JsProptypesNoJsdocComponent } from './docgen-components/9668-js-proptypes-no-jsdoc/input.jsx';\nimport { component as JsClassComponentComponent } from './docgen-components/js-class-component/input.jsx';\nimport { component as JsFunctionComponentInlineDefaultsNoPropTypesComponent } from './docgen-components/js-function-component-inline-defaults-no-propTypes/input.jsx';\nimport { component as JsFunctionComponentInlineDefaultsComponent } from './docgen-components/js-function-component-inline-defaults/input.jsx';\nimport { component as JsFunctionComponentComponent } from './docgen-components/js-function-component/input.jsx';\nimport { component as JsProptypesComponent } from './docgen-components/js-proptypes/input.jsx';\nimport { component as JsRexportedComponentComponent } from './docgen-components/js-re-exported-component/input.jsx';\nimport { component as JsdocComponent } from './docgen-components/jsdoc/input.jsx';\n\n// Detect if we are running in vite in a hacky way for now\nconst isVite = typeof require === 'undefined';\n\nexport default {\n  component: {},\n  render: (_, context) => <ArgsStory parameters={context.parameters} />,\n  parameters: {\n    chromatic: {\n      disableSnapshot: isVite,\n    },\n  },\n};\n\nconst ArgsStory = ({ parameters }) => {\n  const argTypes = parameters.docs.extractArgTypes(parameters.component);\n  const rows = inferControls({ argTypes, parameters: { __isArgsStory: true } });\n  const initialArgs = mapValues(rows, (argType) => argType.defaultValue);\n  const [args, setArgs] = useState(initialArgs);\n\n  return (\n    <ThemeProvider theme={convert(themes.light)}>\n      <ArgsTable rows={rows} args={args} updateArgs={(val) => setArgs({ ...args, ...val })} />\n    </ThemeProvider>\n  );\n};\n\nArgsStory.propTypes = {\n  parameters: PropTypes.shape({\n    component: PropTypes.elementType.isRequired,\n    docs: PropTypes.shape({\n      extractArgTypes: PropTypes.func.isRequired,\n    }).isRequired,\n  }).isRequired,\n};\n\nexport const JsClassComponent = { parameters: { component: JsClassComponentComponent } };\n\nexport const JsFunctionComponent = { parameters: { component: JsFunctionComponentComponent } };\n\nexport const JsRexportedComponent = {\n  parameters: { component: JsRexportedComponentComponent },\n};\n\nexport const JsFunctionComponentInlineDefaults = {\n  parameters: { component: JsFunctionComponentInlineDefaultsComponent },\n};\n\nexport const JsFunctionComponentInlineDefaultsNoPropTypes = {\n  parameters: { component: JsFunctionComponentInlineDefaultsNoPropTypesComponent },\n};\n\nexport const JsProptypesShape = { parameters: { component: JsProptypesShapeComponent } };\n\n// export const JsStyledComponents = { parameters: { component: JsStyledComponentsComponent } };\n\nexport const JsDefaultValues = { parameters: { component: JsDefaultValuesComponent } };\n\nexport const JsProptypesNoJsdoc = { parameters: { component: JsProptypesNoJsdocComponent } };\n\n// export const JsStyledDocgen = { parameters: { component: JsStyledDocgenComponent } };\n\nexport const JsPropTypesOneof = { parameters: { component: JsPropTypesOneofComponent } };\n\nexport const JsHoc = { parameters: { component: JsHocComponent } };\n\nexport const JsReactMemo = { parameters: { component: JsReactMemoComponent } };\n\nexport const JsStaticPropTypes = { parameters: { component: JsStaticPropTypesComponent } };\n\nexport const Jsdoc = { parameters: { component: JsdocComponent } };\n\nexport const JsProptypes = { parameters: { component: JsProptypesComponent } };\n"
  },
  {
    "path": "code/renderers/react/template/stories/jsx-docgen.stories.tsx",
    "content": "import React, { type FC } from 'react';\n\nconst Component: FC<{ children: React.ReactNode }> = ({ children }) => {\n  return <div>{children}</div>;\n};\n\nexport default {\n  component: Component,\n  tags: ['autodocs'],\n};\n\n// This story is used to test whether JSX elements render correctly in autodocs and controls panel\nexport const Default = {\n  args: {\n    children: <div>Test</div>,\n  },\n};\n"
  },
  {
    "path": "code/renderers/react/template/stories/mount-in-play.stories.tsx",
    "content": "import type { FC } from 'react';\nimport React from 'react';\n\nimport type { StoryObj } from '@storybook/react';\n\nconst Button: FC<{ label?: string; disabled?: boolean }> = (props) => {\n  return <button disabled={props.disabled}>{props.label}</button>;\n};\n\nexport default {\n  component: Button,\n};\n\nexport const Basic: StoryObj<typeof Button> = {\n  args: {\n    disabled: true,\n  },\n  async play({ mount, args }) {\n    await mount(<Button {...args} label={'set in play'} />);\n  },\n};\n"
  },
  {
    "path": "code/renderers/react/template/stories/preview.ts",
    "content": "import { __definePreview } from '@storybook/react';\n\n// This file is used for CSF4 stories\nexport default __definePreview({ addons: [] });\n"
  },
  {
    "path": "code/renderers/react/template/stories/teardown.stories.tsx",
    "content": "import { useEffect } from 'react';\n\nconst LoggingComponent = () => {\n  useEffect(() => {\n    console.log('mounted');\n    return () => {\n      console.log('unmounted');\n    };\n  }, []);\n\n  return 'Component';\n};\n\nexport default {\n  component: LoggingComponent,\n  tags: ['autodocs'],\n  parameters: {\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const Default = {};\n"
  },
  {
    "path": "code/renderers/react/template/stories/test-fn.stories.tsx",
    "content": "import React from 'react';\n\nimport type { StoryContext } from '@storybook/react';\n\nimport { expect, fn } from 'storybook/test';\n\nimport preview from './preview';\n\nconst Button = (args: React.ComponentProps<'button'>) => <button {...args} />;\n\nconst meta = preview.meta({\n  component: Button,\n  args: {\n    children: 'Default',\n    onClick: fn(),\n  },\n  tags: ['some-tag'],\n});\n\nexport const Default = meta.story({\n  args: {\n    children: 'Arg from story',\n  },\n});\nDefault.test('simple', async ({ canvas, userEvent, args }) => {\n  const button = canvas.getByText('Arg from story');\n  await userEvent.click(button);\n  await expect(args.onClick).toHaveBeenCalled();\n});\n\nconst doTest = async ({\n  canvas,\n  userEvent,\n  args,\n}: StoryContext<React.ComponentProps<'button'>>) => {\n  const button = canvas.getByText('Arg from story');\n  await userEvent.click(button);\n  await expect(args.onClick).toHaveBeenCalled();\n};\nDefault.test('referring to function in file', doTest);\n\nDefault.test(\n  'with overrides',\n  {\n    args: {\n      children: 'Arg from test override',\n    },\n    parameters: {\n      viewport: {\n        options: {\n          sized: {\n            name: 'Sized',\n            styles: {\n              width: '380px',\n              height: '500px',\n            },\n          },\n        },\n      },\n      chromatic: { viewports: [380] },\n    },\n    globals: { viewport: { value: 'sized' } },\n    tags: ['!test'],\n  },\n  async ({ canvas }) => {\n    const button = canvas.getByText('Arg from test override');\n    await expect(button).toBeInTheDocument();\n    expect(document.body.clientWidth).toBe(380);\n  }\n);\nDefault.test(\n  'with play function',\n  {\n    play: async ({ canvas }) => {\n      const button = canvas.getByText('Arg from story');\n      await expect(button).toBeInTheDocument();\n    },\n  },\n  async ({ canvas }) => {\n    const button = canvas.getByText('Arg from story');\n    await expect(button).not.toHaveAttribute('aria-disabled', 'true');\n  }\n);\nexport const Extended = Default.extend({\n  args: {\n    children: 'Arg from extended story',\n  },\n});\nExtended.test('should have extended args', async ({ canvas }) => {\n  const button = canvas.getByText('Arg from extended story');\n  await expect(button).not.toHaveAttribute('aria-disabled', 'true');\n});\n"
  },
  {
    "path": "code/renderers/react/template/stories/ts-argtypes.stories.tsx",
    "content": "import React, { useState } from 'react';\n\nimport type { Args, Parameters, StoryContext } from 'storybook/internal/types';\n\nimport type { StoryObj } from '@storybook/react';\n\nimport { PureArgsTable as ArgsTable } from '@storybook/addon-docs/blocks';\n\nimport { mapValues } from 'es-toolkit/object';\nimport { inferControls } from 'storybook/preview-api';\nimport { ThemeProvider, convert, themes } from 'storybook/theming';\n\nimport { component as TsImportedTypesComponent } from './docgen-components/8143-ts-imported-types/input';\nimport { component as TsReactFcGenericsComponent } from './docgen-components/8143-ts-react-fc-generics/input';\nimport { component as TsMultiPropsComponent } from './docgen-components/8740-ts-multi-props/input';\nimport { component as TsForwardRefComponent } from './docgen-components/8894-9511-ts-forward-ref/input';\nimport { component as TsTypePropsComponent } from './docgen-components/9465-ts-type-props/input';\nimport { component as TsDisplayNameComponent } from './docgen-components/9493-ts-display-name/input';\nimport { component as TsReactDefaultExportsComponent } from './docgen-components/9556-ts-react-default-exports/input';\nimport { component as TsCamelCaseComponent } from './docgen-components/9575-ts-camel-case/input';\nimport { component as TsImportTypesComponent } from './docgen-components/9591-ts-import-types/input';\nimport { component as TsDeprecatedJsdocComponent } from './docgen-components/9721-ts-deprecated-jsdoc/input';\nimport { component as TsExtendPropsComponent } from './docgen-components/9764-ts-extend-props/input';\nimport { component as TsDefaultValuesComponent } from './docgen-components/9827-ts-default-values/input';\nimport { component as TsComponentPropsComponent } from './docgen-components/9922-ts-component-props/input';\nimport { component as TsFunctionComponentInlineDefaultsComponent } from './docgen-components/ts-function-component-inline-defaults/input';\nimport { component as TsFunctionComponentComponent } from './docgen-components/ts-function-component/input';\nimport { component as TsHtmlComponent } from './docgen-components/ts-html/input';\nimport { component as TsJsdocComponent } from './docgen-components/ts-jsdoc/input';\nimport { component as TsFCComponent } from './docgen-components/ts-react-fc/input';\nimport { component as TsTypesComponent } from './docgen-components/ts-types/input';\n\nexport default {\n  component: {},\n  render: (_: Args, context: StoryContext) => <ArgsStory parameters={context.parameters} />,\n};\n\nconst ArgsStory = ({ parameters }: { parameters: Parameters }) => {\n  const argTypes = parameters.docs.extractArgTypes(parameters.component);\n  const rows = inferControls({ argTypes, parameters: { __isArgsStory: true } } as any);\n  const initialArgs = mapValues(rows, (argType) => argType.defaultValue);\n  const [args, setArgs] = useState(initialArgs);\n\n  return (\n    <ThemeProvider theme={convert(themes.light)}>\n      <ArgsTable rows={rows} args={args} updateArgs={(val) => setArgs({ ...args, ...val })} />\n    </ThemeProvider>\n  );\n};\n\nexport const TsFunctionComponent = { parameters: { component: TsFunctionComponentComponent } };\n\nexport const TsFunctionComponentInlineDefaults = {\n  parameters: { component: TsFunctionComponentInlineDefaultsComponent },\n};\n\nexport const TsReactFcGenerics = { parameters: { component: TsReactFcGenericsComponent } };\n\nexport const TsImportedTypes = { parameters: { component: TsImportedTypesComponent } };\n\nexport const TsMultiProps = { parameters: { component: TsMultiPropsComponent } };\n\nexport const TsReactDefaultExports = { parameters: { component: TsReactDefaultExportsComponent } };\n\nexport const TsImportTypes = { parameters: { component: TsImportTypesComponent } };\n\nexport const TsDeprecatedJsdoc = { parameters: { component: TsDeprecatedJsdocComponent } };\n\nexport const TsDefaultValues = { parameters: { component: TsDefaultValuesComponent } };\n\nexport const TsCamelCase = { parameters: { component: TsCamelCaseComponent } };\n\nexport const TsDisplayName = { parameters: { component: TsDisplayNameComponent } };\n\nexport const TsForwardRef = { parameters: { component: TsForwardRefComponent } };\n\nexport const TsTypeProps = { parameters: { component: TsTypePropsComponent } };\n\nexport const TsExtendProps = { parameters: { component: TsExtendPropsComponent } };\n\nexport const TsComponentProps = { parameters: { component: TsComponentPropsComponent } };\n\nexport const TsJsdoc = { parameters: { component: TsJsdocComponent } };\n\nexport const TsFC = { parameters: { component: TsFCComponent } };\n\nexport const TsTypes: StoryObj = { parameters: { component: TsTypesComponent } };\n\nexport const TsHtml = { parameters: { component: TsHtmlComponent } };\n"
  },
  {
    "path": "code/renderers/react/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@storybook/react\": [\"./src\"]\n    }\n  },\n  \"include\": [\"src/**/*\", \"template/**/*\"]\n}\n"
  },
  {
    "path": "code/renderers/react/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    test: {\n      setupFiles: ['./vitest.setup.ts'],\n    },\n  })\n);\n"
  },
  {
    "path": "code/renderers/react/vitest.setup.ts",
    "content": "// Mocks are set up per-file. See __mocks__/fs.cjs for memfs.\n"
  },
  {
    "path": "code/renderers/server/README.md",
    "content": "# Storybook Server renderer\n\nDevelop, document, and test UI components in isolation.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/renderers/server/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./entry-preview'],\n        entryPoint: './src/entry-preview.ts',\n        dts: false,\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/renderers/server/package.json",
    "content": "{\n  \"name\": \"@storybook/server\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook Server renderer: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"server\",\n    \"renderer\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/renderers/server\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/renderers/server\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./entry-preview\": \"./dist/entry-preview.js\",\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"template/cli/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/global\": \"^5.0.0\",\n    \"ts-dedent\": \"^2.0.0\",\n    \"yaml\": \"^2.8.1\"\n  },\n  \"devDependencies\": {\n    \"typescript\": \"^5.8.3\"\n  },\n  \"peerDependencies\": {\n    \"storybook\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/renderers/server/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/renderers/server/project.json",
    "content": "{\n  \"name\": \"server\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/renderers/server/src/entry-preview.ts",
    "content": "export { render, renderToCanvas } from './render.ts';\n\nexport const parameters = { renderer: 'server' as const };\n"
  },
  {
    "path": "code/renderers/server/src/globals.ts",
    "content": "import { global } from '@storybook/global';\n\nconst { window: globalWindow } = global;\n\nglobalWindow.STORYBOOK_ENV = 'SERVER';\n"
  },
  {
    "path": "code/renderers/server/src/index.ts",
    "content": "import './globals.ts';\n\nexport * from './public-types.ts';\n"
  },
  {
    "path": "code/renderers/server/src/preset.ts",
    "content": "import { readFile } from 'node:fs/promises';\nimport { fileURLToPath } from 'node:url';\n\nimport type { ComponentTitle, PresetProperty, StoryName, Tag } from 'storybook/internal/types';\n\nimport yaml from 'yaml';\n\ntype FileContent = {\n  title: ComponentTitle;\n  tags?: Tag[];\n  stories: { name: StoryName; tags?: Tag[] }[];\n};\n\nexport const experimental_indexers: PresetProperty<'experimental_indexers'> = (\n  existingIndexers\n) => [\n  {\n    test: /(stories|story)\\.(json|ya?ml)$/,\n    createIndex: async (fileName) => {\n      const rawFile = await readFile(fileName, { encoding: 'utf8' });\n      const content: FileContent = fileName.endsWith('.json')\n        ? JSON.parse(rawFile)\n        : yaml.parse(rawFile);\n\n      return content.stories.map((story) => {\n        const tags = Array.from(new Set([...(content.tags ?? []), ...(story.tags ?? [])]));\n        return {\n          importPath: fileName,\n          exportName: story.name,\n          name: story.name,\n          title: content.title,\n          tags,\n          type: 'story',\n        };\n      });\n    },\n  },\n  ...(existingIndexers || []),\n];\n\nexport const previewAnnotations: PresetProperty<'previewAnnotations'> = async (\n  input = [],\n  options\n) => {\n  const { presetsList } = options;\n  if (!presetsList) {\n    return input;\n  }\n  const result: string[] = [];\n\n  return result\n    .concat(input)\n    .concat([fileURLToPath(import.meta.resolve('@storybook/server/entry-preview'))]);\n};\n"
  },
  {
    "path": "code/renderers/server/src/public-types.ts",
    "content": "import type {\n  AnnotatedStoryFn,\n  Args,\n  ComponentAnnotations,\n  DecoratorFunction,\n  StoryContext as GenericStoryContext,\n  LoaderFunction,\n  ProjectAnnotations,\n  StoryAnnotations,\n  StrictArgs,\n} from 'storybook/internal/types';\n\nimport type { ServerRenderer } from './types.ts';\n\nexport type { Args, ArgTypes, Parameters, StrictArgs } from 'storybook/internal/types';\n\n/**\n * Metadata to configure the stories for a component.\n *\n * @see [Default export](https://storybook.js.org/docs/api/csf#default-export)\n */\nexport type Meta<TArgs = Args> = ComponentAnnotations<ServerRenderer, TArgs>;\n\n/**\n * Story function that represents a CSFv2 component example.\n *\n * @see [Named Story exports](https://storybook.js.org/docs/api/csf#named-story-exports)\n */\nexport type StoryFn<TArgs = Args> = AnnotatedStoryFn<ServerRenderer, TArgs>;\n\n/**\n * Story object that represents a CSFv3 component example.\n *\n * @see [Named Story exports](https://storybook.js.org/docs/api/csf#named-story-exports)\n */\nexport type StoryObj<TArgs = Args> = StoryAnnotations<ServerRenderer, TArgs>;\n\nexport type { ServerRenderer };\nexport type Decorator<TArgs = StrictArgs> = DecoratorFunction<ServerRenderer, TArgs>;\nexport type Loader<TArgs = StrictArgs> = LoaderFunction<ServerRenderer, TArgs>;\nexport type StoryContext<TArgs = StrictArgs> = GenericStoryContext<ServerRenderer, TArgs>;\nexport type Preview = ProjectAnnotations<ServerRenderer>;\n"
  },
  {
    "path": "code/renderers/server/src/render.ts",
    "content": "import type { RenderContext } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { simulateDOMContentLoaded, simulatePageLoad } from 'storybook/preview-api';\nimport { dedent } from 'ts-dedent';\n\nimport type { ArgTypes, Args, StoryFn } from './public-types.ts';\nimport type { FetchStoryHtmlType, ServerRenderer } from './types.ts';\n\nconst { fetch, Node } = global;\n\nconst defaultFetchStoryHtml: FetchStoryHtmlType = async (url, path, params, storyContext) => {\n  const fetchUrl = new URL(`${url}/${path}`);\n  fetchUrl.search = new URLSearchParams({ ...storyContext.globals, ...params }).toString();\n\n  const response = await fetch(fetchUrl);\n  return response.text();\n};\n\nconst buildStoryArgs = (args: Args, argTypes: ArgTypes) => {\n  const storyArgs = { ...args };\n\n  Object.keys(argTypes).forEach((key: string) => {\n    const argType = argTypes[key];\n    const { control } = argType;\n    const controlType =\n      control && typeof control === 'object' && 'type' in control && control.type?.toLowerCase();\n    const argValue = storyArgs[key];\n    switch (controlType) {\n      case 'date':\n        // For cross framework & language support we pick a consistent representation of Dates as strings\n        storyArgs[key] = new Date(argValue).toISOString();\n        break;\n      case 'object':\n        // send objects as JSON strings\n        storyArgs[key] = JSON.stringify(argValue);\n        break;\n      default:\n    }\n  });\n\n  return storyArgs;\n};\n\nexport const render: StoryFn<ServerRenderer> = (args: Args) => {};\n\nexport async function renderToCanvas(\n  {\n    id,\n    title,\n    name,\n    showMain,\n    showError,\n    forceRemount,\n    storyFn,\n    storyContext,\n    storyContext: { parameters, args, argTypes },\n  }: RenderContext<ServerRenderer>,\n  canvasElement: ServerRenderer['canvasElement']\n) {\n  // Some addons wrap the storyFn so we need to call it even though Server doesn't need the answer\n  storyFn();\n  const storyArgs = buildStoryArgs(args, argTypes);\n\n  const {\n    server: { url, id: storyId, fetchStoryHtml = defaultFetchStoryHtml, params },\n  } = parameters;\n\n  const fetchId = storyId || id;\n  const storyParams = { ...params, ...storyArgs };\n  const element = await fetchStoryHtml(url, fetchId, storyParams, storyContext);\n\n  showMain();\n  if (typeof element === 'string') {\n    canvasElement.innerHTML = element;\n    simulatePageLoad(canvasElement);\n  } else if (element instanceof Node) {\n    // Don't re-mount the element if it didn't change and neither did the story\n    if (canvasElement.firstChild === element && forceRemount === false) {\n      return;\n    }\n\n    canvasElement.innerHTML = '';\n    canvasElement.appendChild(element);\n    simulateDOMContentLoaded();\n  } else {\n    showError({\n      title: `Expecting an HTML snippet or DOM node from the story: \"${name}\" of \"${title}\".`,\n      description: dedent`\n        Did you forget to return the HTML snippet from the story?\n        Use \"() => <your snippet or node>\" or when defining the story.\n      `,\n    });\n  }\n}\n"
  },
  {
    "path": "code/renderers/server/src/types.ts",
    "content": "import type { StoryContext as StoryContextBase, WebRenderer } from 'storybook/internal/types';\n\nexport type { RenderContext } from 'storybook/internal/types';\n\nexport type StoryFnServerReturnType = any;\nexport type StoryContext = StoryContextBase<ServerRenderer>;\n\nexport interface ServerRenderer extends WebRenderer {\n  component: string;\n  storyResult: StoryFnServerReturnType;\n}\n\nexport type FetchStoryHtmlType = (\n  url: string,\n  id: string,\n  params: any,\n  context: StoryContext\n) => Promise<string | Node>;\n\nexport interface ShowErrorArgs {\n  title: string;\n  description: string;\n}\n"
  },
  {
    "path": "code/renderers/server/src/typings.d.ts",
    "content": "declare var STORYBOOK_ENV: 'SERVER';\n"
  },
  {
    "path": "code/renderers/server/template/cli/button.stories.json",
    "content": "{\n  \"title\": \"Example/Button\",\n  \"parameters\": {\n    \"server\": {\n      \"url\": \"https://storybook-server-demo.netlify.app/api\",\n      \"id\": \"button\"\n    }\n  },\n  \"args\": { \"label\": \"Button\" },\n  \"argTypes\": {\n    \"label\": { \"control\": \"text\" },\n    \"primary\": { \"control\": \"boolean\" },\n    \"backgroundColor\": { \"control\": \"color\" },\n    \"size\": {\n      \"control\": { \"type\": \"select\", \"options\": [\"small\", \"medium\", \"large\"] }\n    }\n  },\n  \"tags\": [\"autodocs\"],\n  \"stories\": [\n    {\n      \"name\": \"Primary\",\n      \"args\": { \"primary\": true }\n    },\n    {\n      \"name\": \"Secondary\"\n    },\n    {\n      \"name\": \"Large\",\n      \"args\": { \"size\": \"large\" }\n    },\n    {\n      \"name\": \"Small\",\n      \"args\": { \"size\": \"small\" }\n    }\n  ]\n}\n"
  },
  {
    "path": "code/renderers/server/template/cli/header.stories.json",
    "content": "{\n  \"title\": \"Example/Header\",\n  \"parameters\": {\n    \"server\": {\n      \"url\": \"https://storybook-server-demo.netlify.app/api\",\n      \"id\": \"header\"\n    }\n  },\n  \"stories\": [\n    {\n      \"name\": \"LoggedIn\",\n      \"args\": { \"user\": {} }\n    },\n    {\n      \"name\": \"LoggedOut\"\n    }\n  ]\n}\n"
  },
  {
    "path": "code/renderers/server/template/cli/page.stories.yaml",
    "content": "title: 'Example/Page'\nparameters:\n  server:\n    url: 'https://storybook-server-demo.netlify.app/api'\n    id: 'page'\nstories:\n  - name: 'LoggedIn'\n    args:\n      user: {}\n  - name: 'LoggedOut'\n"
  },
  {
    "path": "code/renderers/server/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {},\n  \"include\": [\"src/**/*\", \"template/**/*\"]\n}\n"
  },
  {
    "path": "code/renderers/server/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/renderers/svelte/README.md",
    "content": "# Storybook Svelte renderer\n\nDevelop, document, and test UI components in isolation.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/renderers/svelte/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./entry-preview'],\n        entryPoint: './src/entry-preview.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./entry-preview-docs'],\n        entryPoint: './src/entry-preview-docs.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./experimental-playwright'],\n        entryPoint: './src/playwright.ts',\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n    ],\n  },\n  extraOutputs: {\n    './internal/PreviewRender.svelte': './static/PreviewRender.svelte',\n    './internal/DecoratorHandler.svelte': './static/DecoratorHandler.svelte',\n    './internal/AddStorybookIdDecorator.svelte': './static/AddStorybookIdDecorator.svelte',\n    './internal/createReactiveProps': './static/createReactiveProps.svelte.js',\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/renderers/svelte/package.json",
    "content": "{\n  \"name\": \"@storybook/svelte\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook Svelte renderer: Develop, document, and test UI components in isolation.\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-renderer\",\n    \"svelte\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/renderers/svelte\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/renderers/svelte\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./entry-preview\": \"./dist/entry-preview.js\",\n    \"./entry-preview-docs\": \"./dist/entry-preview-docs.js\",\n    \"./experimental-playwright\": {\n      \"types\": \"./dist/playwright.d.ts\",\n      \"code\": \"./src/playwright.ts\",\n      \"default\": \"./dist/playwright.js\"\n    },\n    \"./internal/AddStorybookIdDecorator.svelte\": \"./static/AddStorybookIdDecorator.svelte\",\n    \"./internal/createReactiveProps\": \"./static/createReactiveProps.svelte.js\",\n    \"./internal/DecoratorHandler.svelte\": \"./static/DecoratorHandler.svelte\",\n    \"./internal/PreviewRender.svelte\": \"./static/PreviewRender.svelte\",\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"static/**/*\",\n    \"template/cli/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"ts-dedent\": \"^2.0.0\",\n    \"type-fest\": \"~2.19\"\n  },\n  \"devDependencies\": {\n    \"@sveltejs/vite-plugin-svelte\": \"^6.2.0\",\n    \"@testing-library/svelte\": \"^5.2.4\",\n    \"svelte\": \"^5.39.5\",\n    \"svelte-check\": \"^4.3.2\",\n    \"sveltedoc-parser\": \"^4.2.1\",\n    \"typescript\": \"^5.8.3\",\n    \"vite\": \"^7.0.4\"\n  },\n  \"peerDependencies\": {\n    \"storybook\": \"workspace:^\",\n    \"svelte\": \"^5.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/renderers/svelte/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/renderers/svelte/project.json",
    "content": "{\n  \"name\": \"svelte\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {\n      \"executor\": \"nx:run-commands\",\n      \"options\": { \"cwd\": \"{projectRoot}\", \"command\": \"svelte-check\" }\n    }\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/renderers/svelte/src/__test__/Button.svelte",
    "content": "<script lang=\"ts\">\n  interface Props {\n    disabled: boolean;\n    label: string;\n    clicked?: (e: MouseEvent) => void;\n  }\n\n  // When a Svelte 5 component only uses runes, it is typed as a function component.\n  // Others are typed as class components. Hence we need to have tests for both shapes.\n  let { disabled, label, clicked}: Props = $props();\n</script>\n\n<button onclick={clicked} {disabled}>\n  {label}\n</button>\n"
  },
  {
    "path": "code/renderers/svelte/src/__test__/Decorator.svelte",
    "content": "<script lang=\"ts\">\n  import type { Snippet } from \"svelte\";\n\n  interface Props {\n    children: Snippet;\n    decoratorArg: string;\n  }\n  let { children, decoratorArg }: Props = $props();\n</script>\n\n<div>\n  Decorator: {decoratorArg}\n  {@render children()}\n</div>\n"
  },
  {
    "path": "code/renderers/svelte/src/__test__/Decorator2.svelte",
    "content": "<script lang=\"ts\">\n  import type { Snippet } from \"svelte\";\n\n  interface Props {\n    children: Snippet;\n    decoratorArg2: string;\n  }\n  let { children, decoratorArg2 }: Props = $props();\n</script>\n\n<div>\n  Decorator: {decoratorArg2}\n  {@render children()}\n</div>\n"
  },
  {
    "path": "code/renderers/svelte/src/__test__/composeStories/AddWrapperDecorator.svelte",
    "content": "<script>\n  let { children } = $props();\n</script>\n<div style=\"margin: 3em;\" data-testid=\"local-decorator\">\n  {@render children?.()}\n</div>"
  },
  {
    "path": "code/renderers/svelte/src/__test__/composeStories/Button.stories.ts",
    "content": "import { expect, fn, userEvent, within } from 'storybook/test';\n\nimport type { StoryFn as CSF2Story, Meta, StoryObj } from '../../index.ts';\nimport AddWrapperDecorator from './AddWrapperDecorator.svelte';\nimport Button from './Button.svelte';\nimport CustomRenderComponent from './CustomRenderComponent.svelte';\nimport InputFilledStoryComponent from './InputFilledStoryComponent.svelte';\nimport LoaderStoryComponent from './LoaderStoryComponent.svelte';\nimport StoryWithLocaleComponent from './StoryWithLocaleComponent.svelte';\n\nconst meta = {\n  title: 'Example/Button',\n  component: Button,\n  argTypes: {\n    backgroundColor: { control: 'color' },\n    size: {\n      control: { type: 'select' },\n      options: ['small', 'medium', 'large'],\n    },\n  },\n  excludeStories: /.*ImNotAStory$/,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype CSF3Story = StoryObj<typeof meta>;\n\n// For testing purposes. Should be ignored in ComposeStories\nexport const ImNotAStory = 123;\n\nconst Template: CSF2Story = (args) => ({\n  Component: Button,\n  props: args,\n});\n\nexport const CSF2Secondary = Template.bind({});\nCSF2Secondary.args = {\n  label: 'label coming from story args!',\n  primary: false,\n};\n\nconst getCaptionForLocale = (locale: string) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'pt':\n      return 'Olá!';\n    default:\n      return 'Hello!';\n  }\n};\n\nexport const CSF2StoryWithLocale: CSF2Story<typeof StoryWithLocaleComponent> = (\n  args,\n  { globals }\n) => ({\n  Component: StoryWithLocaleComponent,\n  props: {\n    ...args,\n    locale: globals.locale,\n    label: getCaptionForLocale(globals.locale),\n  },\n});\nCSF2StoryWithLocale.storyName = 'WithLocale';\n\nexport const CSF2StoryWithParamsAndDecorator = Template.bind({});\nCSF2StoryWithParamsAndDecorator.args = {\n  label: 'foo',\n};\nCSF2StoryWithParamsAndDecorator.parameters = {\n  layout: 'centered',\n};\nCSF2StoryWithParamsAndDecorator.decorators = [\n  () => ({\n    Component: AddWrapperDecorator,\n  }),\n];\n\nexport const NewStory: CSF3Story = {\n  args: {\n    label: 'foo',\n    size: 'large',\n    primary: true,\n  },\n  decorators: [\n    () => ({\n      Component: AddWrapperDecorator,\n    }),\n  ],\n};\n\nexport const CSF3Primary: CSF3Story = {\n  args: {\n    label: 'foo',\n    size: 'large',\n    primary: true,\n  },\n};\n\nexport const CSF3Button: CSF3Story = {\n  args: { label: 'foo' },\n};\n\nexport const CSF3ButtonWithRender: StoryObj<typeof CustomRenderComponent> = {\n  args: {\n    buttonProps: CSF3Button.args,\n  },\n  render: (args) => ({\n    Component: CustomRenderComponent,\n    props: {\n      buttonProps: args.buttonProps,\n    },\n  }),\n};\n\nexport const CSF3InputFieldFilled: StoryObj<typeof InputFilledStoryComponent> = {\n  render: () =>\n    ({\n      Component: InputFilledStoryComponent,\n    }) as any,\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    await step('Step label', async () => {\n      const inputEl = canvas.getByTestId('input');\n      await userEvent.type(inputEl, 'Hello world!');\n      await expect(inputEl).toHaveValue('Hello world!');\n    });\n  },\n};\n\nconst mockFn = fn();\nexport const LoaderStory: StoryObj<typeof LoaderStoryComponent> = {\n  args: {\n    mockFn,\n  } as any,\n  loaders: [\n    async () => {\n      mockFn.mockReturnValueOnce('mockFn return value');\n      return {\n        value: 'loaded data',\n      };\n    },\n  ],\n  render: (args, { loaded }) =>\n    ({\n      Component: LoaderStoryComponent,\n      props: {\n        ...args,\n        loaded,\n      },\n    }) as any,\n  play: async () => {\n    expect(mockFn).toHaveBeenCalledWith('render');\n  },\n};\n"
  },
  {
    "path": "code/renderers/svelte/src/__test__/composeStories/Button.svelte",
    "content": "<script lang=\"ts\">\n  type Props = {\n    /**\n     * Is this the principal call to action on the page?\n     */\n    primary?: boolean;\n\n    /**\n     * What background color to use\n     */\n    backgroundColor?: string;\n\n    /**\n     * How large should the button be?\n     */\n    size?: 'small' | 'medium' | 'large';\n\n    /**\n     * Button contents\n     */\n    label?: string;\n\n    /**\n     * Button contents\n     */\n    children?: any;\n  };\n\n  const {\n    primary = false,\n    backgroundColor = undefined,\n    size = 'medium',\n    label = '',\n    children,\n    ...props\n  }: Props = $props();\n\n  let mode = $derived(primary ? 'storybook-button--primary' : 'storybook-button--secondary');\n  let style = $derived(backgroundColor ? `background-color: ${backgroundColor}` : '');\n</script>\n\n<button\n  type=\"button\"\n  class={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n  {style}\n  {...props}\n>\n  {label}\n  {@render children?.()}\n</button>\n"
  },
  {
    "path": "code/renderers/svelte/src/__test__/composeStories/CustomRenderComponent.svelte",
    "content": "<script lang=\"ts\">\n  import Button from './Button.svelte';\n  import type { ComponentProps } from 'svelte';\n\n  let { buttonProps }: { buttonProps: ComponentProps<typeof Button> } = $props();\n</script>\n\n<div>\n  <p data-testid=\"custom-render\">I am a custom render function</p>\n  <Button {...buttonProps} />\n</div>\n"
  },
  {
    "path": "code/renderers/svelte/src/__test__/composeStories/InputFilledStoryComponent.svelte",
    "content": "<input data-testid=\"input\" />"
  },
  {
    "path": "code/renderers/svelte/src/__test__/composeStories/LoaderStoryComponent.svelte",
    "content": "<script lang=\"ts\">\n  let {\n    mockFn,\n    loaded,\n  }: {\n    mockFn: (arg: string) => string;\n    loaded: { value: string };\n  } = $props();\n\n  let data = $derived(mockFn && loaded && mockFn('render'));\n</script>\n\n<div>\n  <div data-testid=\"loaded-data\">{loaded.value}</div>\n  <div data-testid=\"spy-data\">{String(data)}</div>\n</div>\n"
  },
  {
    "path": "code/renderers/svelte/src/__test__/composeStories/StoryWithLocaleComponent.svelte",
    "content": "<script lang=\"ts\">\n  import Button from './Button.svelte';\n\n  let {\n    locale,\n    label,\n  }: {\n    locale: string;\n    label: string;\n  } = $props();\n</script>\n\n<div>\n  <p>locale: {locale}</p>\n  <Button {label} />\n</div>\n"
  },
  {
    "path": "code/renderers/svelte/src/__test__/composeStories/__snapshots__/portable-stories.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`Renders CSF2Secondary story 1`] = `\n<body>\n  <div>\n    <!---->\n    <!---->\n    <!---->\n    <button\n      class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n      style=\"\"\n      type=\"button\"\n    >\n      label coming from story args! \n      <!---->\n    </button>\n    \n    \n    \n    \n    \n    \n  </div>\n</body>\n`;\n\nexports[`Renders CSF2StoryWithParamsAndDecorator story 1`] = `\n<body>\n  <div>\n    <!---->\n    <!---->\n    <!---->\n    <!---->\n    <!---->\n    <div\n      data-testid=\"local-decorator\"\n      style=\"margin: 3em;\"\n    >\n      <!---->\n      <button\n        class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n        style=\"\"\n        type=\"button\"\n      >\n        foo \n        <!---->\n      </button>\n      \n      <!---->\n    </div>\n    \n    \n    \n    \n    \n    \n    \n    \n  </div>\n</body>\n`;\n\nexports[`Renders CSF3Button story 1`] = `\n<body>\n  <div>\n    <!---->\n    <!---->\n    <!---->\n    <button\n      class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n      style=\"\"\n      type=\"button\"\n    >\n      foo \n      <!---->\n    </button>\n    \n    \n    \n    \n    \n    \n  </div>\n</body>\n`;\n\nexports[`Renders CSF3ButtonWithRender story 1`] = `\n<body>\n  <div>\n    <!---->\n    <!---->\n    <!---->\n    <div>\n      <p\n        data-testid=\"custom-render\"\n      >\n        I am a custom render function\n      </p>\n       \n      <button\n        class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n        style=\"\"\n        type=\"button\"\n      >\n        foo \n        <!---->\n      </button>\n      <!---->\n    </div>\n    \n    \n    \n    \n    \n    \n  </div>\n</body>\n`;\n\nexports[`Renders CSF3InputFieldFilled story 1`] = `\n<body>\n  <div>\n    <!---->\n    <!---->\n    <!---->\n    <input\n      data-testid=\"input\"\n    />\n    \n    \n    \n    \n    \n    \n  </div>\n</body>\n`;\n\nexports[`Renders CSF3Primary story 1`] = `\n<body>\n  <div>\n    <!---->\n    <!---->\n    <!---->\n    <button\n      class=\"storybook-button storybook-button--large storybook-button--primary\"\n      style=\"\"\n      type=\"button\"\n    >\n      foo \n      <!---->\n    </button>\n    \n    \n    \n    \n    \n    \n  </div>\n</body>\n`;\n\nexports[`Renders LoaderStory story 1`] = `\n<body>\n  <div>\n    <!---->\n    <!---->\n    <!---->\n    <div>\n      <div\n        data-testid=\"loaded-data\"\n      >\n        loaded data\n      </div>\n       \n      <div\n        data-testid=\"spy-data\"\n      >\n        mockFn return value\n      </div>\n    </div>\n    \n    \n    \n    \n    \n    \n  </div>\n</body>\n`;\n\nexports[`Renders NewStory story 1`] = `\n<body>\n  <div>\n    <!---->\n    <!---->\n    <!---->\n    <!---->\n    <!---->\n    <div\n      data-testid=\"local-decorator\"\n      style=\"margin: 3em;\"\n    >\n      <!---->\n      <button\n        class=\"storybook-button storybook-button--large storybook-button--primary\"\n        style=\"\"\n        type=\"button\"\n      >\n        foo \n        <!---->\n      </button>\n      \n      <!---->\n    </div>\n    \n    \n    \n    \n    \n    \n    \n    \n  </div>\n</body>\n`;\n"
  },
  {
    "path": "code/renderers/svelte/src/__test__/composeStories/portable-stories.test.ts",
    "content": "// @vitest-environment happy-dom\n/// <reference types=\"@testing-library/jest-dom\" />\nimport { cleanup, render, screen } from '@testing-library/svelte';\nimport { afterEach, describe, expect, it } from 'vitest';\n\n// import '@testing-library/svelte/vitest';\nimport { expectTypeOf } from 'expect-type';\n\nimport type { Meta } from '../../index.ts';\nimport { composeStories, composeStory, setProjectAnnotations } from '../../portable-stories.ts';\nimport * as stories from './Button.stories.ts';\nimport type Button from './Button.svelte';\n\nsetProjectAnnotations([]);\n\n// example with composeStories, returns an object with all stories composed with args/decorators\nconst { CSF3Primary, LoaderStory } = composeStories(stories);\n\nafterEach(() => {\n  cleanup();\n});\n\n// example with composeStory, returns a single story composed with args/decorators\nconst Secondary = composeStory(stories.CSF2Secondary, stories.default);\ndescribe('renders', () => {\n  it('renders primary button with custom props via composeStory', () => {\n    // We unfortunately can't do the following:\n    // render(CSF3Primary.Component, { ...CSF3Primary.props, label: 'Hello world' });\n    // Because the props will be passed to the first decorator of the story instead\n    // of the actual component of the story. This is because of our current PreviewRender structure\n\n    const Composed = composeStory(\n      {\n        ...stories.CSF3Primary,\n        args: { ...stories.CSF3Primary.args, label: 'Hello world' },\n      },\n      stories.default\n    );\n\n    render(Composed.Component, Composed.props);\n    const buttonElement = screen.getByText(/Hello world/i);\n    expect(buttonElement).not.toBeNull();\n  });\n\n  it('reuses args from composed story', () => {\n    render(Secondary.Component, Secondary.props);\n    const buttonElement = screen.getByRole('button');\n    expect(buttonElement.textContent).toMatch(Secondary.args.label);\n  });\n\n  it('reuses args from composeStories', () => {\n    const { getByText } = render(CSF3Primary.Component, CSF3Primary.props);\n    const buttonElement = getByText(/foo/i);\n    expect(buttonElement).not.toBeNull();\n  });\n\n  it('should call and compose loaders data', async () => {\n    await LoaderStory.load();\n    const { getByTestId } = render(LoaderStory.Component, LoaderStory.props);\n    expect(getByTestId('spy-data').textContent).toEqual('mockFn return value');\n    expect(getByTestId('loaded-data').textContent).toEqual('loaded data');\n    // spy assertions happen in the play function and should work\n    await LoaderStory.run!();\n  });\n});\n\ndescribe('projectAnnotations', () => {\n  it('renders with default projectAnnotations', () => {\n    setProjectAnnotations([\n      {\n        parameters: { injected: true },\n        globalTypes: {\n          locale: { defaultValue: 'en' },\n        },\n      },\n    ]);\n    const WithEnglishText = composeStory(stories.CSF2StoryWithLocale, stories.default);\n    const { getByText } = render(WithEnglishText.Component, WithEnglishText.props);\n    const buttonElement = getByText('Hello!');\n    expect(buttonElement).not.toBeNull();\n    expect(WithEnglishText.parameters?.injected).toBe(true);\n  });\n\n  it('renders with custom projectAnnotations via composeStory params', () => {\n    const WithPortugueseText = composeStory(stories.CSF2StoryWithLocale, stories.default, {\n      initialGlobals: { locale: 'pt' },\n    });\n    const { getByText } = render(WithPortugueseText.Component, WithPortugueseText.props);\n    const buttonElement = getByText('Olá!');\n    expect(buttonElement).not.toBeNull();\n  });\n});\n\ndescribe('CSF3', () => {\n  it('renders with inferred globalRender', () => {\n    const Primary = composeStory(stories.CSF3Button, stories.default);\n    render(Primary.Component, Primary.props);\n    const buttonElement = screen.getByText(/foo/i);\n    expect(buttonElement).not.toBeNull();\n  });\n\n  it('renders with custom render function', () => {\n    const Primary = composeStory(stories.CSF3ButtonWithRender, stories.default);\n\n    render(Primary.Component, Primary.props);\n    expect(screen.getByTestId('custom-render')).not.toBeNull();\n  });\n\n  it('renders with play function without canvas element', async () => {\n    const CSF3InputFieldFilled = composeStory(stories.CSF3InputFieldFilled, stories.default);\n\n    await CSF3InputFieldFilled.run();\n\n    const input = screen.getByTestId('input') as HTMLInputElement;\n    expect(input.value).toEqual('Hello world!');\n  });\n\n  it('renders with play function with canvas element', async () => {\n    const CSF3InputFieldFilled = composeStory(stories.CSF3InputFieldFilled, stories.default);\n\n    const div = document.createElement('div');\n    document.body.appendChild(div);\n\n    await CSF3InputFieldFilled.run({ canvasElement: div });\n\n    const input = screen.getByTestId('input') as HTMLInputElement;\n    expect(input.value).toEqual('Hello world!');\n\n    document.body.removeChild(div);\n  });\n});\n\ndescribe('ComposeStories types', () => {\n  // this file tests Typescript types that's why there are no assertions\n  it('Should support typescript operators', () => {\n    type ComposeStoriesParam = Parameters<typeof composeStories>[0];\n\n    expectTypeOf({\n      ...stories,\n      default: stories.default as Meta<typeof Button>,\n    }).toMatchTypeOf<ComposeStoriesParam>();\n\n    expectTypeOf({\n      ...stories,\n      // TODO: @JReinhold maybe you can figure this error out?\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore-error (Type 'IsomorphicComponent<PropsWithChildren<{ primary?: boolean | undefined; backgroundColor?: string | undefined; size?: \"small\" | \"medium\" | \"large\" | undefined; label?: string | undefined; }, { default: {}; }>, { ...; } & { ...; }, { ...; }, {}, string>' has no properties in common with type 'PropsWithChildren<{ primary?: boolean | undefined; backgroundColor?: string | undefined; size?: \"small\" | \"medium\" | \"large\" | undefined; label?: string | undefined; }, { default: {}; }>'. )\n      default: stories.default satisfies Meta<typeof Button>,\n    }).toMatchTypeOf<ComposeStoriesParam>();\n  });\n});\n\n// Batch snapshot testing\nconst testCases = Object.values(composeStories(stories)).map(\n  (Story) => [Story.storyName, Story] as [string, typeof Story]\n);\nit.each(testCases)('Renders %s story', async (_storyName, Story) => {\n  if (_storyName === 'CSF2StoryWithLocale') {\n    return;\n  }\n  await Story.run();\n  expect(document.body).toMatchSnapshot();\n});\n"
  },
  {
    "path": "code/renderers/svelte/src/decorators.ts",
    "content": "import type { DecoratorFunction, LegacyStoryFn, StoryContext } from 'storybook/internal/types';\n\n/*\n! DO NOT change this DecoratorHandler import to a relative path, it will break it.\n! A relative import will be compiled at build time, and Svelte will be unable to\n! render the component together with the user's Svelte components\n! importing from @storybook/svelte will make sure that it is compiled at runtime\n! with the same bundle as the user's Svelte components\n*/\nimport DecoratorHandler from '@storybook/svelte/internal/DecoratorHandler.svelte';\n\nimport { sanitizeStoryContextUpdate } from 'storybook/preview-api';\n\nimport type { SvelteRenderer } from './types.ts';\n\n/**\n * Handle component loaded with ESM or CJS, by getting the 'default' property of the object if it\n * exists.\n *\n * @param obj Object\n */\nfunction unWrap<T>(obj: { default: T } | T): T {\n  return obj && typeof obj === 'object' && 'default' in obj ? obj.default : obj;\n}\n\n/**\n * Prepare a story to be compatible with the PreviewRender component.\n *\n * - `() => ({ Component: MyComponent, props: ...})` is already prepared, kept as-is\n * - `() => MyComponent` is transformed to `() => ({ Component: MyComponent })`\n * - `() => ({})` is transformed to component from context with `() => ({ Component: context.component\n *   })`\n * - A decorator component is wrapped with DecoratorHandler, injecting the decorated component as a\n *   child\n *\n * @param context StoryContext\n * @param story The current story\n * @param innerStory The story decorated by the current story\n */\nfunction prepareStory(\n  context: StoryContext<SvelteRenderer>,\n  rawStory: SvelteRenderer['storyResult'],\n  rawInnerStory?: SvelteRenderer['storyResult']\n) {\n  const story = unWrap(rawStory);\n  const innerStory = rawInnerStory && unWrap(rawInnerStory);\n\n  let preparedStory;\n\n  if (!story || Object.keys(story).length === 0) {\n    // story is empty or an empty object, use the component from the context\n    preparedStory = {\n      Component: context.component,\n    };\n  } else if (story.Component) {\n    // the story is already prepared\n    preparedStory = story;\n  } else {\n    // we must assume that the story is a Svelte component\n    preparedStory = {\n      Component: story,\n    };\n  }\n\n  if (innerStory) {\n    // render a DecoratorHandler with innerStory as its regular component,\n    // and the prepared story as the decorating component\n    return {\n      Component: DecoratorHandler,\n      props: {\n        // inner stories will already have been prepared, keep as is\n        ...innerStory,\n        decorator: preparedStory,\n      },\n    };\n  }\n\n  // no innerStory means this is the last story in the decorator chain, so it should create events from argTypes\n  return { ...preparedStory, argTypes: context.argTypes };\n}\n\nexport function decorateStory(storyFn: any, decorators: any[]) {\n  return decorators.reduce(\n    (decorated: LegacyStoryFn<SvelteRenderer>, decorator: DecoratorFunction<SvelteRenderer>) =>\n      (context: StoryContext<SvelteRenderer>) => {\n        let story: SvelteRenderer['storyResult'] | undefined;\n\n        const decoratedStory: SvelteRenderer['storyResult'] = decorator((update) => {\n          story = decorated({\n            ...context,\n            ...sanitizeStoryContextUpdate(update),\n          });\n          return story;\n        }, context);\n\n        if (!story) {\n          story = decorated(context);\n        }\n\n        if (decoratedStory === story) {\n          return story;\n        }\n\n        return prepareStory(context, decoratedStory, story);\n      },\n    (context: StoryContext<SvelteRenderer>) => prepareStory(context, storyFn(context))\n  );\n}\n"
  },
  {
    "path": "code/renderers/svelte/src/docs/sourceDecorator.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport type { Args } from 'storybook/internal/types';\n\nimport { generateSvelteSource } from './sourceDecorator';\n\nexpect.addSnapshotSerializer({\n  print: (val: any) => val,\n  test: (val: unknown) => typeof val === 'string',\n});\n\nconst loremIpsum = 'Lorem ipsum dolor sit amet';\nconst lotOfProperties = { property1: loremIpsum, property2: loremIpsum, property3: loremIpsum };\n\nfunction generateForArgs(args: Args, slotProperty: string | null = null) {\n  return generateSvelteSource({ name: 'Component' }, args, {}, slotProperty);\n}\n\ndescribe('generateSvelteSource', () => {\n  it('boolean true', () => {\n    expect(generateForArgs({ bool: true })).toMatchInlineSnapshot(`<Component bool/>`);\n  });\n  it('boolean false', () => {\n    expect(generateForArgs({ bool: false })).toMatchInlineSnapshot(`<Component bool={false}/>`);\n  });\n  it('null property', () => {\n    expect(generateForArgs({ propnull: null })).toMatchInlineSnapshot(`<Component />`);\n  });\n  it('string property', () => {\n    expect(generateForArgs({ str: 'mystr' })).toMatchInlineSnapshot(`<Component str=\"mystr\"/>`);\n  });\n  it('number property', () => {\n    expect(generateForArgs({ count: 42 })).toMatchInlineSnapshot(`<Component count={42}/>`);\n  });\n  it('object property', () => {\n    expect(generateForArgs({ obj: { x: true } })).toMatchInlineSnapshot(\n      `<Component obj={{\"x\":true}}/>`\n    );\n  });\n  it('multiple properties', () => {\n    expect(generateForArgs({ a: 1, b: 2 })).toMatchInlineSnapshot(`<Component a={1} b={2}/>`);\n  });\n  it('lot of properties', () => {\n    expect(generateForArgs(lotOfProperties)).toMatchInlineSnapshot(`\n      <Component\n        property1=\"Lorem ipsum dolor sit amet\"\n        property2=\"Lorem ipsum dolor sit amet\"\n        property3=\"Lorem ipsum dolor sit amet\"/>\n    `);\n  });\n  it('slot property', () => {\n    expect(generateForArgs({ content: 'xyz', myProp: 'abc' }, 'content')).toMatchInlineSnapshot(`\n      <Component myProp=\"abc\">\n          xyz\n      </Component>\n    `);\n  });\n  it('slot property with lot of properties', () => {\n    expect(generateForArgs({ content: 'xyz', ...lotOfProperties }, 'content'))\n      .toMatchInlineSnapshot(`\n      <Component\n        property1=\"Lorem ipsum dolor sit amet\"\n        property2=\"Lorem ipsum dolor sit amet\"\n        property3=\"Lorem ipsum dolor sit amet\">\n          xyz\n      </Component>\n    `);\n  });\n  it('component is not set', () => {\n    expect(generateSvelteSource(null, {}, {}, null)).toBeNull();\n  });\n  it('Skip event property', () => {\n    expect(\n      generateSvelteSource(\n        { name: 'Component' },\n        { event_click: () => {} },\n        { event_click: { action: 'click' } }\n      )\n    ).toMatchInlineSnapshot(`<Component />`);\n  });\n  it('Property value is a function', () => {\n    expect(\n      generateSvelteSource({ name: 'Component' }, { myHandler: () => {} }, {})\n    ).toMatchInlineSnapshot(`<Component myHandler={<handler>}/>`);\n  });\n});\n"
  },
  {
    "path": "code/renderers/svelte/src/docs/sourceDecorator.ts",
    "content": "import { deprecate } from 'storybook/internal/client-logger';\nimport { SourceType } from 'storybook/internal/docs-tools';\nimport type {\n  ArgTypes,\n  Args,\n  ArgsStoryFn,\n  DecoratorFunction,\n  StoryContext,\n} from 'storybook/internal/types';\n\nimport { emitTransformCode, useEffect, useRef } from 'storybook/preview-api';\nimport type { SvelteComponentDoc } from 'sveltedoc-parser';\n\nimport type { SvelteRenderer, SvelteStoryResult } from '../types';\n\n/**\n * Check if the source-code should be generated.\n *\n * @param context StoryContext\n */\nconst skipSourceRender = (context: StoryContext<SvelteRenderer>) => {\n  const sourceParams = context?.parameters.docs?.source;\n  const isArgsStory = context?.parameters.__isArgsStory;\n\n  if ((context?.tags ?? []).some((tag) => tag.startsWith('svelte-csf'))) {\n    // skip if Svelte CSF, as the addon does its own source code generation\n    return true;\n  }\n\n  // always render if the user forces it\n  if (sourceParams?.type === SourceType.DYNAMIC) {\n    return false;\n  }\n\n  // never render if the user is forcing the block to render code, or\n  // if the user provides code, or if it's not an args story.\n  return !isArgsStory || sourceParams?.code || sourceParams?.type === SourceType.CODE;\n};\n\n/**\n * Transform a key/value to a svelte declaration as string.\n *\n * Default values are ommited\n *\n * @param key Key\n * @param value Value\n * @param argTypes Component ArgTypes\n */\nfunction toSvelteProperty(key: string, value: any, argTypes: ArgTypes): string | null {\n  if (value === undefined || value === null) {\n    return null;\n  }\n\n  const argType = argTypes[key];\n\n  // default value ?\n  if (argType && argType.defaultValue === value) {\n    return null;\n  }\n\n  // event should be skipped\n  if (argType && argType.action) {\n    return null;\n  }\n\n  if (value === true) {\n    return key;\n  }\n\n  if (typeof value === 'string') {\n    return `${key}=${JSON.stringify(value)}`;\n  }\n\n  // handle function\n  if (typeof value === 'function') {\n    return `${key}={<handler>}`;\n  }\n\n  return `${key}={${JSON.stringify(value)}}`;\n}\n\n/**\n * Extract a component name.\n *\n * @param component Component\n */\nfunction getComponentName(component: any): string | null {\n  if (component == null) {\n    return null;\n  }\n\n  const { __docgen = {} } = component;\n  let { name } = __docgen;\n\n  if (!name) {\n    return component.name;\n  }\n\n  if (name.endsWith('.svelte')) {\n    name = name.substring(0, name.length - 7);\n  }\n  return name;\n}\n\n/**\n * Generate a svelte template.\n *\n * @param component Component\n * @param args Args\n * @param argTypes ArgTypes\n * @param slotProperty Property used to simulate a slot\n */\nexport function generateSvelteSource(\n  component: any,\n  args: Args,\n  argTypes: ArgTypes,\n  slotProperty?: string | null\n): string | null {\n  const name = getComponentName(component);\n\n  if (!name) {\n    return null;\n  }\n\n  const propsArray = Object.entries(args)\n    .filter(([k]) => k !== slotProperty)\n    .map(([k, v]) => toSvelteProperty(k, v, argTypes))\n    .filter((p) => p);\n\n  const props = propsArray.join(' ');\n\n  const multiline = props.length > 50;\n  const slotValue = slotProperty ? args[slotProperty] : null;\n\n  const srcStart = multiline ? `<${name}\\n  ${propsArray.join('\\n  ')}` : `<${name} ${props}`;\n  if (slotValue) {\n    return `${srcStart}>\\n    ${slotValue}\\n</${name}>`;\n  }\n  return `${srcStart}/>`;\n}\n\n/**\n * Check if the story component is a wrapper to the real component.\n *\n * A component can be annotated with `@wrapper` to indicate that it's just a wrapper for the real\n * tested component. If it's the case then the code generated references the real component, not the\n * wrapper.\n *\n * Moreover, a wrapper can annotate a property with `@slot` : this property is then assumed to be an\n * alias to the default slot.\n *\n * @param component Component\n */\nfunction getWrapperProperties(\n  component?: SvelteStoryResult['Component'] & {\n    __docgen?: SvelteComponentDoc & { keywords?: string[] };\n  }\n) {\n  const { __docgen } = component || {};\n  if (!__docgen) {\n    return { wrapper: false };\n  }\n\n  // the component should be declared as a wrapper\n  if (!__docgen.keywords?.find((kw: any) => kw.name === 'wrapper')) {\n    return { wrapper: false };\n  }\n\n  const slotProp = __docgen.data?.find((prop: any) =>\n    prop.keywords.find((kw: any) => kw.name === 'slot')\n  );\n  return { wrapper: true, slotProperty: slotProp?.name as string };\n}\n\n/**\n * Svelte source decorator.\n *\n * @param storyFn Fn\n * @param context StoryContext\n */\nexport const sourceDecorator: DecoratorFunction<SvelteRenderer> = (storyFn, context) => {\n  const skip = skipSourceRender(context);\n  const story = storyFn();\n  const source = useRef<undefined | string>(undefined);\n\n  useEffect(() => {\n    if (skip) {\n      return;\n    }\n\n    const { parameters = {}, args = {}, component: ctxComponent } = context || {};\n\n    // excludeDecorators from source generation as they'll generate the wrong code\n    // instead get the component directly from the original story function instead\n    let { Component: component } = (context.originalStoryFn as ArgsStoryFn<SvelteRenderer>)(\n      args,\n      context\n    );\n    const { wrapper, slotProperty } = getWrapperProperties(component);\n    if (wrapper) {\n      if (parameters.component) {\n        deprecate('parameters.component is deprecated. Using context.component instead.');\n      }\n\n      component = ctxComponent;\n    }\n\n    const generated = generateSvelteSource(component, args, context?.argTypes, slotProperty);\n\n    if (generated && source.current !== generated) {\n      emitTransformCode(generated, context);\n      source.current = generated;\n    }\n  });\n\n  return story;\n};\n"
  },
  {
    "path": "code/renderers/svelte/src/entry-preview-docs.ts",
    "content": "import type { DecoratorFunction } from 'storybook/internal/types';\n\nimport { sourceDecorator } from './docs/sourceDecorator.ts';\nimport type { SvelteRenderer } from './types.ts';\n\nexport const decorators: DecoratorFunction<SvelteRenderer>[] = [sourceDecorator];\n"
  },
  {
    "path": "code/renderers/svelte/src/entry-preview.ts",
    "content": "import { enhanceArgTypes } from 'storybook/internal/docs-tools';\nimport type { ArgTypesEnhancer } from 'storybook/internal/types';\n\nimport { extractArgTypes } from './extractArgTypes.ts';\nimport { extractComponentDescription } from './extractComponentDescription.ts';\nimport type { SvelteRenderer } from './types.ts';\n\nexport const parameters = {\n  renderer: 'svelte',\n  docs: {\n    story: { inline: true },\n    extractArgTypes,\n    extractComponentDescription,\n  },\n};\n\nexport { render, renderToCanvas } from './render.ts';\nexport { decorateStory as applyDecorators } from './decorators.ts';\nexport { mount } from './mount.ts';\n\nexport const argTypesEnhancers: ArgTypesEnhancer<SvelteRenderer>[] = [enhanceArgTypes];\n"
  },
  {
    "path": "code/renderers/svelte/src/extractArgTypes.test.ts",
    "content": "import { readFileSync } from 'node:fs';\n\nimport { describe, expect, it } from 'vitest';\n\nimport svelteDoc from 'sveltedoc-parser';\n\nimport { createArgTypes } from './extractArgTypes.ts';\n\nconst content = readFileSync(`${__dirname}/sample/MockButton.svelte`, 'utf-8');\ndescribe('Extracting Arguments', () => {\n  it('should be svelte', () => {\n    expect(content).toMatchInlineSnapshot(`\n      \"<script>\n        import { createEventDispatcher, afterUpdate } from 'svelte';\n        export let text = '';\n        export let rounded = true;\n\n        const dispatch = createEventDispatcher();\n\n        function onClick(event) {\n          rounded = !rounded;\n\n          /**\n           * Click Event \n           */\n          dispatch('click', event);\n        }\n\n        afterUpdate(() => {\n          /**\n           * After Update\n           */\n          dispatch('afterUpdate');\n        });\n      </script>\n\n      <style>\n        .rounded {\n          border-radius: 35px;\n        }\n\n        .button {\n          border: 3px solid;\n          padding: 10px 20px;\n          background-color: white;\n          outline: none;\n        }\n      </style>\n\n      <svelte:options accessors={true} />\n      <button class=\"button\" class:rounded on:click={onClick}>\n        <strong>{rounded ? 'Round' : 'Square'} corners</strong>\n        <br />\n        {text}\n        <!-- Default Slot -->\n        <slot {rounded}/>\n      </button>\n      \"\n    `);\n  });\n\n  it('should generate ArgTypes', async () => {\n    const doc = await svelteDoc.parse({ fileContent: content, version: 3 });\n\n    const results = createArgTypes(doc);\n\n    expect(results).toMatchInlineSnapshot(`\n      {\n        \"event_afterUpdate\": {\n          \"action\": \"afterUpdate\",\n          \"control\": false,\n          \"description\": \"After Update\",\n          \"name\": \"afterUpdate\",\n          \"table\": {\n            \"category\": \"events\",\n          },\n        },\n        \"event_click\": {\n          \"action\": \"click\",\n          \"control\": false,\n          \"description\": \"Click Event\",\n          \"name\": \"click\",\n          \"table\": {\n            \"category\": \"events\",\n          },\n        },\n        \"rounded\": {\n          \"control\": {\n            \"type\": \"boolean\",\n          },\n          \"description\": undefined,\n          \"name\": \"rounded\",\n          \"table\": {\n            \"category\": \"properties\",\n            \"defaultValue\": {\n              \"summary\": true,\n            },\n            \"type\": {\n              \"summary\": \"boolean\",\n            },\n          },\n          \"type\": {\n            \"name\": \"boolean\",\n            \"required\": false,\n          },\n        },\n        \"slot_default\": {\n          \"control\": false,\n          \"description\": \"Default Slot\n\n      \\`{rounded}\\`\",\n          \"name\": \"default\",\n          \"table\": {\n            \"category\": \"slots\",\n          },\n        },\n        \"text\": {\n          \"control\": {\n            \"type\": \"text\",\n          },\n          \"description\": undefined,\n          \"name\": \"text\",\n          \"table\": {\n            \"category\": \"properties\",\n            \"defaultValue\": {\n              \"summary\": \"\",\n            },\n            \"type\": {\n              \"summary\": \"string\",\n            },\n          },\n          \"type\": {\n            \"name\": \"string\",\n            \"required\": false,\n          },\n        },\n      }\n    `);\n  });\n});\n"
  },
  {
    "path": "code/renderers/svelte/src/extractArgTypes.ts",
    "content": "import { logger } from 'storybook/internal/client-logger';\nimport type { ArgTypesExtractor } from 'storybook/internal/docs-tools';\nimport type { SBScalarType, StrictArgTypes } from 'storybook/internal/types';\n\nimport type {\n  JSDocKeyword,\n  JSDocType,\n  JSDocTypeConst,\n  SvelteComponentDoc,\n} from 'sveltedoc-parser/typings';\n\ntype ComponentWithDocgen = {\n  __docgen: SvelteComponentDoc;\n};\n\nfunction hasKeyword(keyword: string, keywords: JSDocKeyword[]): boolean {\n  return keywords ? keywords.find((k) => k.name === keyword) != null : false;\n}\n\nexport const extractArgTypes: ArgTypesExtractor = (\n  component: ComponentWithDocgen\n): StrictArgTypes | null => {\n  try {\n    const docgen = component.__docgen;\n    if (docgen) {\n      return createArgTypes(docgen);\n    }\n  } catch (err) {\n    logger.log(`Error extracting argTypes: ${err}`);\n  }\n  return {};\n};\n\nexport const createArgTypes = (docgen: SvelteComponentDoc) => {\n  const results: StrictArgTypes = {};\n  if (docgen.data) {\n    docgen.data.forEach((item) => {\n      results[item.name] = {\n        ...parseTypeToControl(item.type),\n        name: item.name,\n        description: item.description || undefined,\n        type: {\n          required: hasKeyword('required', item.keywords || []),\n          name: item.type?.text === '{}' ? 'object' : (item.type?.text as SBScalarType['name']),\n        },\n        table: {\n          type: {\n            summary: item.type?.text,\n          },\n          defaultValue: {\n            summary: item.defaultValue,\n          },\n          category: 'properties',\n        },\n      };\n    });\n  }\n\n  if (docgen.events) {\n    docgen.events.forEach((item) => {\n      results[`event_${item.name}`] = {\n        name: item.name,\n        action: item.name,\n        control: false,\n        ...(item.description ? { description: item.description } : {}),\n        table: {\n          category: 'events',\n        },\n      };\n    });\n  }\n\n  if (docgen.slots) {\n    docgen.slots.forEach((item) => {\n      results[`slot_${item.name}`] = {\n        name: item.name,\n        control: false,\n        description: [item.description, item.params?.map((p) => `\\`${p.name}\\``).join(' ')]\n          .filter((p) => p)\n          .join('\\n\\n'),\n        table: {\n          category: 'slots',\n        },\n      };\n    });\n  }\n\n  return results;\n};\n\n/**\n * Function to convert the type from sveltedoc-parser to a storybook type\n *\n * @param type\n * @returns String\n */\nconst parseTypeToControl = (type: JSDocType | undefined): any => {\n  if (!type) {\n    return null;\n  }\n\n  if (type.kind === 'type') {\n    switch (type.type) {\n      case 'string':\n        return { control: { type: 'text' } };\n      case 'any':\n        return { control: { type: 'object' } };\n      default:\n        return { control: { type: type.type } };\n    }\n  } else if (type.kind === 'union') {\n    if (\n      Array.isArray(type.type) &&\n      !type.type.some(\n        (t) => t.kind !== 'const' || !['string', 'number', 'null', 'undefined'].includes(t.type)\n      )\n    ) {\n      const options = type.type.map((t) => (t as JSDocTypeConst).value);\n      return {\n        control: {\n          type: 'radio',\n        },\n        options,\n      };\n    }\n  } else if (type.kind === 'function') {\n    return { control: null };\n  }\n\n  return null;\n};\n"
  },
  {
    "path": "code/renderers/svelte/src/extractComponentDescription.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { extractComponentDescription } from './extractComponentDescription.ts';\n\ndescribe('extractComponentDescription', () => {\n  it('Extract from docgen', () => {\n    expect(extractComponentDescription({ __docgen: { description: 'a description' } })).toBe(\n      'a description'\n    );\n  });\n  it('Null Component', () => {\n    expect(extractComponentDescription(null)).toBeFalsy();\n  });\n  it('Missing docgen', () => {\n    expect(extractComponentDescription({})).toBeFalsy();\n  });\n});\n"
  },
  {
    "path": "code/renderers/svelte/src/extractComponentDescription.ts",
    "content": "// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function extractComponentDescription(component?: any): string {\n  return component?.__docgen?.description || '';\n}\n"
  },
  {
    "path": "code/renderers/svelte/src/globals.ts",
    "content": "globalThis.STORYBOOK_ENV = 'svelte';\n"
  },
  {
    "path": "code/renderers/svelte/src/index.ts",
    "content": "import './globals.ts';\n\nexport * from './public-types.ts';\nexport * from './portable-stories.ts';\n"
  },
  {
    "path": "code/renderers/svelte/src/mount.ts",
    "content": "import type { BaseAnnotations } from 'storybook/internal/types';\n\nimport type { StoryContext, SvelteRenderer } from './public-types.ts';\n\nexport const mount: BaseAnnotations<SvelteRenderer>['mount'] = (context: StoryContext) => {\n  return async (Component, options) => {\n    if (Component) {\n      context.originalStoryFn = () => ({\n        Component,\n        props: options && 'props' in options ? options?.props : options,\n      });\n    }\n    await context.renderToCanvas();\n    return context.canvas;\n  };\n};\n"
  },
  {
    "path": "code/renderers/svelte/src/playwright.ts",
    "content": "export { createPlaywrightTest as createTest } from 'storybook/preview-api';\n"
  },
  {
    "path": "code/renderers/svelte/src/portable-stories.ts",
    "content": "import type {\n  Args,\n  ComposedStoryFn,\n  NamedOrDefaultProjectAnnotations,\n  NormalizedProjectAnnotations,\n  ProjectAnnotations,\n  Store_CSFExports,\n  StoriesWithPartialProps,\n  StoryAnnotationsOrFn,\n} from 'storybook/internal/types';\n\nimport PreviewRender from '@storybook/svelte/internal/PreviewRender.svelte';\n// @ts-expect-error Don't know why TS doesn't pick up the types export here\nimport { createReactiveProps } from '@storybook/svelte/internal/createReactiveProps';\n\nimport {\n  composeStories as originalComposeStories,\n  composeStory as originalComposeStory,\n  setProjectAnnotations as originalSetProjectAnnotations,\n  setDefaultProjectAnnotations,\n} from 'storybook/preview-api';\n\nimport * as svelteProjectAnnotations from './entry-preview.ts';\nimport type { Meta } from './public-types.ts';\nimport type { SvelteRenderer } from './types.ts';\n\ntype ComposedStory<TArgs extends Args = any> = ComposedStoryFn<SvelteRenderer, TArgs> & {\n  Component: typeof PreviewRender;\n  // these props current refer to the props of PReviewRender, not the user's component's\n  props: any;\n};\n\ntype MapToComposed<TModule> = {\n  [K in keyof TModule]: TModule[K] extends StoryAnnotationsOrFn<\n    SvelteRenderer,\n    infer TArgs extends Args\n  >\n    ? ComposedStory<TArgs>\n    : never;\n};\n\n/**\n * Function that sets the globalConfig of your storybook. The global config is the preview module of\n * your .storybook folder.\n *\n * It should be run a single time, so that your global config (e.g. decorators) is applied to your\n * stories when using `composeStories` or `composeStory`.\n *\n * Example:\n *\n * ```jsx\n * // setup-file.js\n * import { setProjectAnnotations } from '@storybook/svelte';\n * import projectAnnotations from './.storybook/preview';\n *\n * setProjectAnnotations(projectAnnotations);\n * ```\n *\n * @param projectAnnotations - E.g. (import projectAnnotations from '../.storybook/preview')\n */\nexport function setProjectAnnotations(\n  projectAnnotations:\n    | NamedOrDefaultProjectAnnotations<any>\n    | NamedOrDefaultProjectAnnotations<any>[]\n): NormalizedProjectAnnotations<SvelteRenderer> {\n  setDefaultProjectAnnotations(INTERNAL_DEFAULT_PROJECT_ANNOTATIONS);\n  return originalSetProjectAnnotations(\n    projectAnnotations\n  ) as NormalizedProjectAnnotations<SvelteRenderer>;\n}\n\n// This will not be necessary once we have auto preset loading\nexport const INTERNAL_DEFAULT_PROJECT_ANNOTATIONS: ProjectAnnotations<SvelteRenderer> = {\n  ...svelteProjectAnnotations,\n  /** @deprecated */\n  renderToCanvas: (renderContext, canvasElement) => {\n    if (renderContext.storyContext.testingLibraryRender == null) {\n      return svelteProjectAnnotations.renderToCanvas(renderContext, canvasElement);\n    }\n    const {\n      storyFn,\n      storyContext: { testingLibraryRender: render },\n    } = renderContext;\n    const { Component, props } = storyFn();\n    const { unmount } = render(Component, { props, target: canvasElement });\n    return unmount;\n  },\n};\n\n/**\n * Function that will receive a story along with meta (e.g. a default export from a .stories file)\n * and optionally projectAnnotations e.g. (import * from '../.storybook/preview) and will return a\n * composed component that has all args/parameters/decorators/etc combined and applied to it.\n *\n * It's very useful for reusing a story in scenarios outside of Storybook like unit testing.\n *\n * Example:\n *\n * ```jsx\n * import { render } from '@testing-library/svelte';\n * import { composeStory } from '@storybook/svelte';\n * import Meta, { Primary as PrimaryStory } from './Button.stories';\n *\n * const Primary = composeStory(PrimaryStory, Meta);\n *\n * test('renders primary button with Hello World', () => {\n *   const { getByText } = render(Primary, { label: 'Hello world' });\n *   expect(getByText(/Hello world/i)).not.toBeNull();\n * });\n * ```\n *\n * @param story\n * @param componentAnnotations - E.g. (import Meta from './Button.stories')\n * @param [projectAnnotations] - E.g. (import * as projectAnnotations from '../.storybook/preview')\n *   this can be applied automatically if you use `setProjectAnnotations` in your setup files.\n * @param [exportsName] - In case your story does not contain a name and you want it to have a name.\n */\nexport function composeStory<TArgs extends Args = Args>(\n  story: StoryAnnotationsOrFn<SvelteRenderer, TArgs>,\n  componentAnnotations: Meta<TArgs | any>,\n  projectAnnotations?: ProjectAnnotations<SvelteRenderer>,\n  exportsName?: string\n): ComposedStory<TArgs> {\n  const composedStory = originalComposeStory<SvelteRenderer, TArgs>(\n    story as StoryAnnotationsOrFn<SvelteRenderer, Args>,\n    // @ts-expect-error Fix this later: Type 'Partial<{ [x: string]: any; }>' is not assignable to type 'Partial<Simplify<TArgs, {}>>'\n    componentAnnotations,\n    projectAnnotations,\n    globalThis.globalProjectAnnotations ?? INTERNAL_DEFAULT_PROJECT_ANNOTATIONS,\n    exportsName\n  );\n\n  const props = createReactiveProps({\n    storyFn: composedStory,\n    storyContext: { ...composedStory },\n    name: composedStory.storyName,\n    title: composedStory.id,\n    showError: () => {},\n  });\n\n  /**\n   * TODO: figure out the situation here. Currently, we construct props to render the PreviewRender,\n   * a \"story wrapper\" that allows to render the story and its decorators correctly. However, the\n   * props from the user's component can't be overwritten in tests e.g. render(Primary.Component, {\n   * label: 'Hello world' })\n   *\n   * In fact, the props that the user has access to are the props for PreviewRender, which should be\n   * an internal detail instead.\n   *\n   * Ideally, we should create a Svelte component with pre-configured props, so users can do\n   * something like: render(Primary) instead of render(Primary.Component, Primary.props)\n   */\n  const renderable = {\n    Component: PreviewRender,\n    props,\n  };\n  Object.assign(renderable, composedStory);\n\n  return renderable as ComposedStory<TArgs>;\n}\n\n/**\n * Function that will receive a stories import (e.g. `import * as stories from './Button.stories'`)\n * and optionally projectAnnotations (e.g. `import * from '../.storybook/preview`) and will return\n * an object containing all the stories passed, but now as a composed component that has all\n * args/parameters/decorators/etc combined and applied to it.\n *\n * It's very useful for reusing stories in scenarios outside of Storybook like unit testing.\n *\n * Example:\n *\n * ```jsx\n * import { render } from '@testing-library/svelte';\n * import { composeStories } from '@storybook/svelte';\n * import * as stories from './Button.stories';\n *\n * const { Primary, Secondary } = composeStories(stories);\n *\n * test('renders primary button with Hello World', () => {\n *   const { getByText } = render(Primary, { label: 'Hello world' });\n *   expect(getByText(/Hello world/i)).not.toBeNull();\n * });\n * ```\n *\n * @param csfExports - E.g. (import * as stories from './Button.stories')\n * @param [projectAnnotations] - E.g. (import * as projectAnnotations from '../.storybook/preview')\n *   this can be applied automatically if you use `setProjectAnnotations` in your setup files.\n */\nexport function composeStories<TModule extends Store_CSFExports<SvelteRenderer, any>>(\n  csfExports: TModule,\n  projectAnnotations?: ProjectAnnotations<SvelteRenderer>\n) {\n  // @ts-expect-error (Converted from ts-ignore)\n  const composedStories = originalComposeStories(csfExports, projectAnnotations, composeStory);\n\n  return composedStories as unknown as Omit<\n    MapToComposed<StoriesWithPartialProps<SvelteRenderer, TModule>>,\n    keyof Store_CSFExports\n  >;\n}\n"
  },
  {
    "path": "code/renderers/svelte/src/preset.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport type { PresetProperty } from 'storybook/internal/types';\n\nexport const previewAnnotations: PresetProperty<'previewAnnotations'> = async (\n  input = [],\n  options\n) => {\n  const docsEnabled = Object.keys(await options.presets.apply('docs', {}, options)).length > 0;\n  const result: string[] = [];\n\n  return result\n    .concat(input)\n    .concat([fileURLToPath(import.meta.resolve('@storybook/svelte/entry-preview'))])\n    .concat(\n      docsEnabled\n        ? [fileURLToPath(import.meta.resolve('@storybook/svelte/entry-preview-docs'))]\n        : []\n    );\n};\n"
  },
  {
    "path": "code/renderers/svelte/src/public-types.test.ts",
    "content": "// this file tests Typescript types that's why there are no assertions\nimport { describe, expectTypeOf, it } from 'vitest';\n\nimport { satisfies } from 'storybook/internal/common';\nimport type {\n  Args,\n  Canvas,\n  ComponentAnnotations,\n  StoryAnnotations,\n} from 'storybook/internal/types';\n\nimport type { Component, ComponentProps } from 'svelte';\n\nimport Button from './__test__/Button.svelte';\nimport Decorator2 from './__test__/Decorator2.svelte';\nimport Decorator1 from './__test__/Decorator.svelte';\nimport type { Decorator, Meta, StoryObj } from './public-types.ts';\nimport type { SvelteRenderer } from './types.ts';\n\ntype SvelteStory<Comp extends Component<any, any, any>, Args, RequiredArgs> = StoryAnnotations<\n  SvelteRenderer<Comp>,\n  Args,\n  RequiredArgs\n>;\n\ndescribe('Meta', () => {\n  it('Generic parameter of Meta can be a component', () => {\n    const meta: Meta<typeof Button> = {\n      component: Button,\n      args: {\n        label: 'good',\n        disabled: false,\n      },\n    };\n\n    expectTypeOf(meta).toExtend<\n      ComponentAnnotations<SvelteRenderer<typeof Button>, { disabled: boolean; label: string }>\n    >();\n  });\n\n  it('Generic parameter of Meta can be the props of the component', () => {\n    const meta: Meta<{ disabled: boolean; label: string }> = {\n      component: Button,\n      args: { label: 'good', disabled: false },\n    };\n\n    expectTypeOf(meta).toExtend<\n      ComponentAnnotations<SvelteRenderer, { disabled: boolean; label: string }>\n    >();\n  });\n});\n\ndescribe('StoryObj', () => {\n  it('✅ Required args may be provided partial in meta and the story', () => {\n    const meta = satisfies<Meta<typeof Button>>()({\n      component: Button,\n      args: { label: 'good' },\n    });\n\n    type Actual = StoryObj<typeof meta>;\n    type Expected = SvelteStory<\n      typeof Button,\n      { disabled: boolean; label: string },\n      { disabled: boolean; label?: string }\n    >;\n    expectTypeOf<Actual>().toExtend<Expected>();\n  });\n\n  it('❌ The combined shape of meta args and story args must match the required args.', () => {\n    {\n      const meta = satisfies<Meta<typeof Button>>()({ component: Button });\n\n      type Expected = SvelteStory<\n        typeof Button,\n        { disabled: boolean; label: string },\n        { disabled: boolean; label: string }\n      >;\n      expectTypeOf<StoryObj<typeof meta>>().toExtend<Expected>();\n    }\n    {\n      const meta = satisfies<Meta<typeof Button>>()({\n        component: Button,\n        args: { label: 'good' },\n      });\n      // @ts-expect-error disabled not provided ❌\n      const Basic: StoryObj<typeof meta> = {};\n\n      type Expected = SvelteStory<\n        typeof Button,\n        { disabled: boolean; label: string },\n        { disabled: boolean; label?: string }\n      >;\n      expectTypeOf(Basic).toExtend<Expected>();\n    }\n    {\n      const meta = satisfies<Meta<{ label: string; disabled: boolean }>>()({ component: Button });\n      const Basic: StoryObj<typeof meta> = {\n        // @ts-expect-error disabled not provided ❌\n        args: { label: 'good' },\n      };\n\n      type Expected = SvelteStory<\n        typeof Button,\n        { disabled: boolean; label: string },\n        { disabled: boolean; label: string }\n      >;\n      expectTypeOf(Basic).toExtend<Expected>();\n    }\n  });\n\n  it('Component can be used as generic parameter for StoryObj', () => {\n    expectTypeOf<StoryObj<typeof Button>>().toExtend<\n      SvelteStory<\n        typeof Button,\n        { disabled: boolean; label: string },\n        { disabled?: boolean; label?: string }\n      >\n    >();\n  });\n});\n\ntype ThemeData = 'light' | 'dark';\n\ndescribe('Story args can be inferred', () => {\n  it('Correct args are inferred when type is widened for render function', () => {\n    const meta = satisfies<Meta<ComponentProps<typeof Button> & { theme: ThemeData }>>()({\n      component: Button,\n      args: { disabled: false },\n      render: (args, { component }) => {\n        return {\n          Component: component,\n          props: args,\n        };\n      },\n    });\n\n    const Basic: StoryObj<typeof meta> = { args: { theme: 'light', label: 'good' } };\n\n    type Expected = SvelteStory<\n      typeof Button,\n      { theme: ThemeData; disabled: boolean; label: string },\n      { theme: ThemeData; disabled?: boolean; label: string }\n    >;\n    expectTypeOf(Basic).toExtend<Expected>();\n  });\n\n  const withDecorator: Decorator<{ decoratorArg: string }> = (\n    _storyFn,\n    { args: { decoratorArg } }\n  ) => ({\n    Component: Decorator1,\n    props: { decoratorArg },\n  });\n\n  it('Correct args are inferred when type is widened for decorators', () => {\n    type Props = ComponentProps<typeof Button> & { decoratorArg: string };\n\n    const meta = satisfies<Meta<Props>>()({\n      component: Button,\n      args: { disabled: false },\n      decorators: [withDecorator],\n    });\n\n    const Basic: StoryObj<typeof meta> = { args: { decoratorArg: 'title', label: 'good' } };\n\n    type Expected = SvelteStory<\n      typeof Button,\n      Props,\n      { decoratorArg: string; disabled?: boolean; label: string }\n    >;\n    expectTypeOf(Basic).toExtend<Expected>();\n  });\n\n  it('Correct args are inferred when type is widened for multiple decorators', () => {\n    type Props = ComponentProps<typeof Button> & { decoratorArg: string; decoratorArg2: string };\n\n    const secondDecorator: Decorator<{ decoratorArg2: string }> = (\n      _storyFn,\n      { args: { decoratorArg2 } }\n    ) => ({\n      Component: Decorator2,\n      props: { decoratorArg2 },\n    });\n\n    const meta = satisfies<Meta<Props>>()({\n      component: Button,\n      args: { disabled: false },\n      decorators: [withDecorator, secondDecorator],\n    });\n\n    const Basic: StoryObj<typeof meta> = {\n      args: { decoratorArg: '', decoratorArg2: '', label: 'good' },\n    };\n\n    type Expected = SvelteStory<\n      typeof Button,\n      Props,\n      { decoratorArg: string; decoratorArg2: string; disabled?: boolean; label: string }\n    >;\n    expectTypeOf(Basic).toExtend<Expected>();\n  });\n});\n\nit('mount accepts a Component and props', () => {\n  const Basic: StoryObj<typeof Button> = {\n    async play({ mount }) {\n      const canvas = await mount(Button, { props: { label: 'label', disabled: true } });\n      expectTypeOf(canvas).toExtend<Canvas>();\n    },\n  };\n  expectTypeOf(Basic).toExtend<StoryObj<typeof Button>>();\n});\n\nit('StoryObj can accept args directly', () => {\n  const _Story: StoryObj<Args> = {\n    args: {},\n  };\n\n  const _Story2: StoryObj<{ prop: boolean }> = {\n    args: {\n      prop: true,\n    },\n  };\n});\n"
  },
  {
    "path": "code/renderers/svelte/src/public-types.ts",
    "content": "import type {\n  AnnotatedStoryFn,\n  Args,\n  ArgsFromMeta,\n  ArgsStoryFn,\n  ComponentAnnotations,\n  DecoratorFunction,\n  StoryContext as GenericStoryContext,\n  LoaderFunction,\n  ProjectAnnotations,\n  StoryAnnotations,\n  StrictArgs,\n} from 'storybook/internal/types';\n\nimport type { Component, ComponentProps } from 'svelte';\nimport type { SetOptional, Simplify } from 'type-fest';\n\nimport type { SvelteRenderer } from './types.ts';\n\nexport type { Args, ArgTypes, Parameters, StrictArgs } from 'storybook/internal/types';\n\n/**\n * Metadata to configure the stories for a component.\n *\n * @see [Default export](https://storybook.js.org/docs/api/csf#default-export)\n */\nexport type Meta<CmpOrArgs = Args> =\n  CmpOrArgs extends Component<infer Props>\n    ? ComponentAnnotations<SvelteRenderer<CmpOrArgs>, Props>\n    : ComponentAnnotations<SvelteRenderer, CmpOrArgs>;\n\n/**\n * Story function that represents a CSFv2 component example.\n *\n * @see [Named Story exports](https://storybook.js.org/docs/api/csf#named-story-exports)\n */\nexport type StoryFn<TCmpOrArgs = Args> =\n  TCmpOrArgs extends Component<infer Props>\n    ? AnnotatedStoryFn<SvelteRenderer, Props>\n    : AnnotatedStoryFn<SvelteRenderer, TCmpOrArgs>;\n\n/**\n * Story object that represents a CSFv3 component example.\n *\n * @see [Named Story exports](https://storybook.js.org/docs/api/csf#named-story-exports)\n */\nexport type StoryObj<MetaOrCmpOrArgs = Args> = MetaOrCmpOrArgs extends {\n  render?: ArgsStoryFn<SvelteRenderer, any>;\n  component: infer Comp; // We cannot use \"extends Component\" here, because TypeScript for some reason then refuses to ever enter the true branch\n  args?: infer DefaultArgs;\n}\n  ? Simplify<\n      ComponentProps<Comp extends Component<any, any, any> ? Comp : never> &\n        ArgsFromMeta<SvelteRenderer, MetaOrCmpOrArgs>\n    > extends infer TArgs\n    ? StoryAnnotations<\n        SvelteRenderer<Comp extends Component<any, any, any> ? Comp : never>,\n        TArgs,\n        SetOptional<TArgs, Extract<keyof TArgs, keyof DefaultArgs>>\n      >\n    : never\n  : MetaOrCmpOrArgs extends Component<any, any, any>\n    ? StoryAnnotations<SvelteRenderer<MetaOrCmpOrArgs>, ComponentProps<MetaOrCmpOrArgs>>\n    : StoryAnnotations<SvelteRenderer, MetaOrCmpOrArgs>;\n\nexport type { SvelteRenderer };\nexport type Decorator<TArgs = StrictArgs> = DecoratorFunction<SvelteRenderer, TArgs>;\nexport type Loader<TArgs = StrictArgs> = LoaderFunction<SvelteRenderer, TArgs>;\nexport type StoryContext<TArgs = StrictArgs> = GenericStoryContext<SvelteRenderer, TArgs>;\nexport type Preview = ProjectAnnotations<SvelteRenderer>;\n"
  },
  {
    "path": "code/renderers/svelte/src/render.ts",
    "content": "import { RESET_STORY_ARGS } from 'storybook/internal/core-events';\nimport type { ArgsStoryFn, RenderContext } from 'storybook/internal/types';\n\n/*\n! DO NOT change these PreviewRender and createSvelte5Props imports to relative paths, it will break them.\n! Relative imports will be compiled at build time by the bundler, but we need Svelte to compile them\n! when compiling the rest of the Svelte files.\n*/\nimport PreviewRender from '@storybook/svelte/internal/PreviewRender.svelte';\n// @ts-expect-error Don't know why TS doesn't pick up the types export here\nimport { createReactiveProps } from '@storybook/svelte/internal/createReactiveProps';\n\nimport { addons } from 'storybook/preview-api';\nimport * as svelte from 'svelte';\n\nimport type { SvelteRenderer } from './types.ts';\n\n/**\n * This is a workaround for the issue that when resetting args, the story needs to be remounted\n * completely to revert to the component's default props. This is because Svelte does not itself\n * revert to defaults when a prop is undefined. See\n * https://github.com/storybookjs/storybook/issues/21470#issuecomment-1467056479\n *\n * We listen for the `RESET_STORY_ARGS` event and store the storyId to be reset We then use this in\n * the renderToCanvas function to force remount the story\n */\nconst storyIdsToRemountFromResetArgsEvent = new Set<string>();\n\naddons.getChannel().on(RESET_STORY_ARGS, ({ storyId }) => {\n  storyIdsToRemountFromResetArgsEvent.add(storyId);\n});\n\nconst componentsByDomElement = new Map<\n  SvelteRenderer['canvasElement'],\n  { mountedComponent: ReturnType<(typeof svelte)['mount']>; props: RenderContext }\n>();\n\nexport async function renderToCanvas(\n  {\n    storyFn,\n    title,\n    name,\n    showMain,\n    showError,\n    storyContext,\n    forceRemount,\n  }: RenderContext<SvelteRenderer>,\n  canvasElement: SvelteRenderer['canvasElement']\n) {\n  function unmount(canvasElementToUnmount: SvelteRenderer['canvasElement']) {\n    const { mountedComponent } = componentsByDomElement.get(canvasElementToUnmount) ?? {};\n    if (!mountedComponent) {\n      return;\n    }\n    svelte.unmount(mountedComponent);\n    componentsByDomElement.delete(canvasElementToUnmount);\n  }\n\n  const existingComponent = componentsByDomElement.get(canvasElement);\n\n  let remount = forceRemount;\n  if (storyIdsToRemountFromResetArgsEvent.has(storyContext.id)) {\n    remount = true;\n    storyIdsToRemountFromResetArgsEvent.delete(storyContext.id);\n  }\n\n  if (remount) {\n    unmount(canvasElement);\n  }\n\n  if (!existingComponent || remount) {\n    const props = createReactiveProps({\n      storyFn,\n      storyContext,\n      name,\n      title,\n      showError,\n    });\n    const mountedComponent = svelte.mount(PreviewRender, {\n      target: canvasElement,\n      props,\n    });\n    componentsByDomElement.set(canvasElement, { mountedComponent, props });\n    await svelte.tick();\n  } else {\n    // We need to mutate the existing props for Svelte reactivity to work, we can't just re-assign them\n    Object.assign(existingComponent.props, {\n      storyFn,\n      storyContext,\n      name,\n      title,\n      showError,\n    });\n    await svelte.tick();\n  }\n\n  showMain();\n\n  // unmount the component when the story changes\n  return () => {\n    unmount(canvasElement);\n  };\n}\n\nexport const render: ArgsStoryFn<SvelteRenderer> = (args, context) => {\n  const { id, component: Component } = context;\n  if (!Component) {\n    throw new Error(\n      `Unable to render story ${id} as the component annotation is missing from the default export`\n    );\n  }\n\n  return { Component, props: args };\n};\n"
  },
  {
    "path": "code/renderers/svelte/src/sample/MockButton.svelte",
    "content": "<script>\n  import { createEventDispatcher, afterUpdate } from 'svelte';\n  export let text = '';\n  export let rounded = true;\n\n  const dispatch = createEventDispatcher();\n\n  function onClick(event) {\n    rounded = !rounded;\n\n    /**\n     * Click Event \n     */\n    dispatch('click', event);\n  }\n\n  afterUpdate(() => {\n    /**\n     * After Update\n     */\n    dispatch('afterUpdate');\n  });\n</script>\n\n<style>\n  .rounded {\n    border-radius: 35px;\n  }\n\n  .button {\n    border: 3px solid;\n    padding: 10px 20px;\n    background-color: white;\n    outline: none;\n  }\n</style>\n\n<svelte:options accessors={true} />\n<button class=\"button\" class:rounded on:click={onClick}>\n  <strong>{rounded ? 'Round' : 'Square'} corners</strong>\n  <br />\n  {text}\n  <!-- Default Slot -->\n  <slot {rounded}/>\n</button>\n"
  },
  {
    "path": "code/renderers/svelte/src/types.ts",
    "content": "import type {\n  Canvas,\n  StoryContext as StoryContextBase,\n  WebRenderer,\n} from 'storybook/internal/types';\n\nimport type { Component, ComponentProps } from 'svelte';\n\nexport type StoryContext = StoryContextBase<SvelteRenderer>;\n\nexport interface SvelteRenderer<\n  C extends Component<any, any, any> = Component<any, any, any>,\n> extends WebRenderer {\n  component: Component<this['T'] extends Record<string, any> ? this['T'] : any>;\n  storyResult: this['T'] extends Record<string, any>\n    ? SvelteStoryResult<this['T']>\n    : SvelteStoryResult;\n\n  mount: (\n    Component?: C,\n    // TODO add proper typesafety\n    options?: Record<string, any> & { props: ComponentProps<C> }\n  ) => Promise<Canvas>;\n}\n\nexport interface SvelteStoryResult<\n  Props extends Record<string, any> = any,\n  Exports extends Record<string, any> = any,\n  Bindings extends keyof Props | '' = string,\n> {\n  Component?: Component<Props, Exports, Bindings>;\n  props?: Props;\n  decorator?: Component<Props, Exports, Bindings>;\n}\n"
  },
  {
    "path": "code/renderers/svelte/src/typings.d.ts",
    "content": "declare var STORYBOOK_ENV: 'svelte';\ndeclare var LOGLEVEL: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent' | undefined;\n\ndeclare module '*.svelte' {\n  import type { Component } from 'svelte';\n\n  const component: Component;\n  export default component;\n}\n"
  },
  {
    "path": "code/renderers/svelte/static/AddStorybookIdDecorator.svelte",
    "content": "<script>\n  const { storyId, children } = $props();\n</script>\n\n<div data-story=\"true\" id={storyId}>\n  {@render children()}\n</div>\n"
  },
  {
    "path": "code/renderers/svelte/static/DecoratorHandler.svelte",
    "content": "<script>\n  const { decorator, Component, props } = $props();\n\n  /*\n    Svelte Docgen will create argTypes for events with the name 'event_eventName'\n    The Actions addon will convert these to args because they are type: 'action'\n    We need to filter these args out so they are not passed to the component\n  */\n  let propsWithoutDocgenEvents = $derived(\n    Object.fromEntries(Object.entries(props).filter(([key]) => !key.startsWith('event_')))\n  );\n</script>\n\n{#if decorator}\n  <decorator.Component {...decorator.props}>\n    <Component {...propsWithoutDocgenEvents} />\n  </decorator.Component>\n{:else}\n  <Component {...propsWithoutDocgenEvents} />\n{/if}\n"
  },
  {
    "path": "code/renderers/svelte/static/PreviewRender.svelte",
    "content": "<script>\n  import DecoratorHandler from './DecoratorHandler.svelte';\n  import { dedent } from 'ts-dedent';\n\n  const { name, title, storyFn, showError } = $props();\n\n  let {\n    /** @type {import('svelte').SvelteComponent} */\n    Component,\n    props = {},\n  } = $derived.by(() => {\n    return storyFn();\n  });\n\n  $effect(() => {\n    if (!Component) {\n      showError({\n        title: `Expecting a Svelte component from the story: \"${name}\" of \"${title}\".`,\n        description: dedent`\n        Did you forget to return the Svelte component configuration from the story?\n        Use \"() => ({ Component: YourComponent, props: {} })\"\n        when defining the story.\n      `,\n      });\n    }\n  });\n</script>\n\n<svelte:boundary>\n  {#snippet pending()}\n    <div id=\"sb-pending-async-component-notice\">Pending async component...</div>\n  {/snippet}\n  <DecoratorHandler {Component} {props} />\n</svelte:boundary>\n"
  },
  {
    "path": "code/renderers/svelte/static/createReactiveProps.svelte.js",
    "content": "/**\n * Turns an object into reactive props in Svelte 5. Needs to be in a separate .svelte.js file to\n * ensure Svelte compiles it. As proposed in\n * https://github.com/sveltejs/svelte/issues/9827#issuecomment-1845589616\n *\n * @template TProps\n * @param {TProps} data - The data to create Svelte 5 props from.\n * @returns {TProps} - The created Svelte 5 props.\n */\nexport const createReactiveProps = (data) => {\n  const props = $state(data);\n  return props;\n};\n"
  },
  {
    "path": "code/renderers/svelte/svelte.config.js",
    "content": "//! this config isn't actually used, it's just here to tell svelte-check that we have async enabled\n\nconst config = {\n  kit: {\n    experimental: {\n      remoteFunctions: true,\n    },\n  },\n  compilerOptions: {\n    experimental: {\n      async: true,\n    },\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/renderers/svelte/template/cli/js/Button.stories.svelte",
    "content": "<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import Button from './Button.svelte';\n  import { fn } from 'storybook/test';\n\n  // More on how to set up stories at: https://storybook.js.org/docs/writing-stories\n  const { Story } = defineMeta({\n    title: 'Example/Button',\n    component: Button,\n    tags: ['autodocs'],\n    argTypes: {\n      backgroundColor: { control: 'color' },\n      size: {\n        control: { type: 'select' },\n        options: ['small', 'medium', 'large'],\n      },\n    },\n    args: {\n      onclick: fn(),\n    }\n  });\n</script>\n\n<!-- More on writing stories with args: https://storybook.js.org/docs/writing-stories/args -->\n<Story name=\"Primary\" args={{ primary: true, label: 'Button' }} />\n\n<Story name=\"Secondary\" args={{ label: 'Button' }} />\n\n<Story name=\"Large\" args={{ size: 'large', label: 'Button' }} />\n\n<Story name=\"Small\" args={{ size: 'small', label: 'Button' }} />\n"
  },
  {
    "path": "code/renderers/svelte/template/cli/js/Button.svelte",
    "content": "<script>\n  import './button.css';\n\n  /**\n   * @typedef {Object} Props\n   * @property {boolean} [primary] Is this the principal call to action on the page?\n   * @property {string} [backgroundColor] What background color to use\n   * @property {'small' | 'medium' | 'large'} [size] How large should the button be?\n   * @property {string} label Button contents\n   * @property {() => void} [onclick] The onclick event handler\n   */\n\n  /** @type {Props} */\n  const { primary = false, backgroundColor, size = 'medium', label, ...props } = $props();\n\n  let mode = $derived(primary ? 'storybook-button--primary' : 'storybook-button--secondary');\n  let style = $derived(backgroundColor ? `background-color: ${backgroundColor}` : '');\n</script>\n\n<button\n  type=\"button\"\n  class={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n  {style}\n  {...props}\n>\n  {label}\n</button>\n"
  },
  {
    "path": "code/renderers/svelte/template/cli/js/Header.stories.svelte",
    "content": "<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import Header from './Header.svelte';\n  import { fn } from 'storybook/test';\n\n  // More on how to set up stories at: https://storybook.js.org/docs/writing-stories\n  const { Story } = defineMeta({\n    title: 'Example/Header',\n    component: Header,\n    // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n    tags: ['autodocs'],\n    parameters: {\n      // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n      layout: 'fullscreen',\n    },\n    args: {\n      onLogin: fn(),\n      onLogout: fn(),\n      onCreateAccount: fn(),\n    }\n  });\n</script>\n\n<Story name=\"Logged In\" args={{ user: { name: 'Jane Doe' } }} />\n\n<Story name=\"Logged Out\" />\n"
  },
  {
    "path": "code/renderers/svelte/template/cli/js/Header.svelte",
    "content": "<script>\n  import './header.css';\n  import Button from './Button.svelte';\n\n  /**\n   * @typedef {Object} Props\n   * @property {{name: string}} [user] The user object\n   * @property {() => void} [onLogin] The login event handler\n   * @property {() => void} [onLogout] The logout event handler\n   * @property {() => void} [onCreateAccount] The account creation event handler\n   */\n\n  /** @type {Props} */\n  const { user, onLogin, onLogout, onCreateAccount } = $props();\n</script>\n\n<header>\n  <div class=\"storybook-header\">\n    <div>\n      <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n        <g fill=\"none\" fill-rule=\"evenodd\">\n          <path\n            d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n            fill=\"#FFF\"\n          />\n          <path\n            d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n            fill=\"#555AB9\"\n          />\n          <path d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\" fill=\"#91BAF8\" />\n        </g>\n      </svg>\n      <h1>Acme</h1>\n    </div>\n    <div>\n      {#if user}\n        <span class=\"welcome\">\n          Welcome, <b>{user.name}</b>!\n        </span>\n        <Button size=\"small\" onclick={onLogout} label=\"Log out\" />\n      {:else}\n        <Button size=\"small\" onclick={onLogin} label=\"Log in\" />\n        <Button primary size=\"small\" onclick={onCreateAccount} label=\"Sign up\" />\n      {/if}\n    </div>\n  </div>\n</header>\n"
  },
  {
    "path": "code/renderers/svelte/template/cli/js/Page.stories.svelte",
    "content": "<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import { expect, userEvent, waitFor, within } from 'storybook/test';\n  import Page from './Page.svelte';\n  import { fn } from 'storybook/test';\n\n  // More on how to set up stories at: https://storybook.js.org/docs/writing-stories\n  const { Story } = defineMeta({\n    title: 'Example/Page',\n    component: Page,\n    parameters: {\n      // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n      layout: 'fullscreen',\n    },\n  });\n</script>\n\n<Story name=\"Logged In\" play={async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await waitFor(() => expect(loginButton).not.toBeInTheDocument());\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  }}\n  />\n\n<Story name=\"Logged Out\" />\n"
  },
  {
    "path": "code/renderers/svelte/template/cli/js/Page.svelte",
    "content": "<script>\n  import './page.css';\n  import Header from './Header.svelte';\n\n  let user = $state(null);\n</script>\n\n<article>\n  <Header\n    {user}\n    onLogin={() => (user = { name: 'Jane Doe' })}\n    onLogout={() => (user = null)}\n    onCreateAccount={() => (user = { name: 'Jane Doe' })}\n  />\n\n  <section class=\"storybook-page\">\n    <h2>Pages in Storybook</h2>\n    <p>\n      We recommend building UIs with a\n      <a\n        href=\"https://blog.hichroma.com/component-driven-development-ce1109d56c8e\"\n        target=\"_blank\"\n        rel=\"noopener noreferrer\"\n      >\n        <strong>component-driven</strong>\n      </a>\n      process starting with atomic components and ending with pages.\n    </p>\n    <p>\n      Render pages with mock data. This makes it easy to build and review page states without\n      needing to navigate to them in your app. Here are some handy patterns for managing page data\n      in Storybook:\n    </p>\n    <ul>\n      <li>\n        Use a higher-level connected component. Storybook helps you compose such data from the\n        \"args\" of child component stories\n      </li>\n      <li>\n        Assemble data in the page component from your services. You can mock these services out\n        using Storybook.\n      </li>\n    </ul>\n    <p>\n      Get a guided tutorial on component-driven development at\n      <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n        Storybook tutorials\n      </a>\n      . Read more in the\n      <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">docs</a>\n      .\n    </p>\n    <div class=\"tip-wrapper\">\n      <span class=\"tip\">Tip</span>\n      Adjust the width of the canvas with the\n      <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n        <g fill=\"none\" fill-rule=\"evenodd\">\n          <path\n            d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0\n            01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0\n            010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n            id=\"a\"\n            fill=\"#999\"\n          />\n        </g>\n      </svg>\n      Viewports addon in the toolbar\n    </div>\n  </section>\n</article>\n"
  },
  {
    "path": "code/renderers/svelte/template/cli/ts/Button.stories.svelte",
    "content": "<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import Button from './Button.svelte';\n  import { fn } from 'storybook/test';\n\n  // More on how to set up stories at: https://storybook.js.org/docs/writing-stories\n  const { Story } = defineMeta({\n    title: 'Example/Button',\n    component: Button,\n    tags: ['autodocs'],\n    argTypes: {\n      backgroundColor: { control: 'color' },\n      size: {\n        control: { type: 'select' },\n        options: ['small', 'medium', 'large'],\n      },\n    },\n    args: {\n      onclick: fn(),\n    }\n  });\n</script>\n\n<!-- More on writing stories with args: https://storybook.js.org/docs/writing-stories/args -->\n<Story name=\"Primary\" args={{ primary: true, label: 'Button' }} />\n\n<Story name=\"Secondary\" args={{ label: 'Button' }} />\n\n<Story name=\"Large\" args={{ size: 'large', label: 'Button' }} />\n\n<Story name=\"Small\" args={{ size: 'small', label: 'Button' }} />\n"
  },
  {
    "path": "code/renderers/svelte/template/cli/ts/Button.svelte",
    "content": "<script lang=\"ts\">\n  import './button.css';\n\n  interface Props {\n    /** Is this the principal call to action on the page? */\n    primary?: boolean;\n    /** What background color to use */\n    backgroundColor?: string;\n    /** How large should the button be? */\n    size?: 'small' | 'medium' | 'large';\n    /** Button contents */\n    label: string;\n    /** The onclick event handler */\n    onclick?: () => void;\n  }\n\n  const { primary = false, backgroundColor, size = 'medium', label, ...props }: Props = $props();\n  \n  let mode = $derived(primary ? 'storybook-button--primary' : 'storybook-button--secondary');\n  let style = $derived(backgroundColor ? `background-color: ${backgroundColor}` : '');\n</script>\n\n<button\n  type=\"button\"\n  class={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n  {style}\n  {...props}\n>\n  {label}\n</button>\n"
  },
  {
    "path": "code/renderers/svelte/template/cli/ts/Header.stories.svelte",
    "content": "<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import Header from './Header.svelte';\n  import { fn } from 'storybook/test';\n\n  // More on how to set up stories at: https://storybook.js.org/docs/writing-stories\n  const { Story } = defineMeta({\n    title: 'Example/Header',\n    component: Header,\n    // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n    tags: ['autodocs'],\n    parameters: {\n      // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n      layout: 'fullscreen',\n    },\n    args: {\n      onLogin: fn(),\n      onLogout: fn(),\n      onCreateAccount: fn(),\n    }\n  });\n</script>\n\n<Story name=\"Logged In\" args={{ user: { name: 'Jane Doe' } }} />\n\n<Story name=\"Logged Out\" />\n"
  },
  {
    "path": "code/renderers/svelte/template/cli/ts/Header.svelte",
    "content": "<script lang=\"ts\">\n  import './header.css';\n  import Button from './Button.svelte';\n\n  interface Props {\n    user?: { name: string };\n    onLogin?: () => void;\n    onLogout?: () => void;\n    onCreateAccount?: () => void;\n  }\n\n  const { user, onLogin, onLogout, onCreateAccount }: Props = $props();\n</script>\n\n<header>\n  <div class=\"storybook-header\">\n    <div>\n      <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n        <g fill=\"none\" fill-rule=\"evenodd\">\n          <path\n            d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n            fill=\"#FFF\"\n          />\n          <path\n            d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n            fill=\"#555AB9\"\n          />\n          <path d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\" fill=\"#91BAF8\" />\n        </g>\n      </svg>\n      <h1>Acme</h1>\n    </div>\n    <div>\n      {#if user}\n        <span class=\"welcome\">\n          Welcome, <b>{user.name}</b>!\n        </span>\n        <Button size=\"small\" onclick={onLogout} label=\"Log out\" />\n      {:else}\n        <Button size=\"small\" onclick={onLogin} label=\"Log in\" />\n        <Button primary size=\"small\" onclick={onCreateAccount} label=\"Sign up\" />\n      {/if}\n    </div>\n  </div>\n</header>\n"
  },
  {
    "path": "code/renderers/svelte/template/cli/ts/Page.stories.svelte",
    "content": "<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import { expect, userEvent, waitFor, within } from 'storybook/test';\n  import Page from './Page.svelte';\n  import { fn } from 'storybook/test';\n\n  // More on how to set up stories at: https://storybook.js.org/docs/writing-stories\n  const { Story } = defineMeta({\n    title: 'Example/Page',\n    component: Page,\n    parameters: {\n      // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n      layout: 'fullscreen',\n    },\n  });\n</script>\n\n<Story name=\"Logged In\" play={async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await waitFor(() => expect(loginButton).not.toBeInTheDocument());\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  }}\n/>\n\n<Story name=\"Logged Out\" />\n"
  },
  {
    "path": "code/renderers/svelte/template/cli/ts/Page.svelte",
    "content": "<script lang=\"ts\">\n  import './page.css';\n  import Header from './Header.svelte';\n\n  let user = $state<{ name: string }>();\n</script>\n\n<article>\n  <Header\n    {user}\n    onLogin={() => (user = { name: 'Jane Doe' })}\n    onLogout={() => (user = undefined)}\n    onCreateAccount={() => (user = { name: 'Jane Doe' })}\n  />\n\n  <section class=\"storybook-page\">\n    <h2>Pages in Storybook</h2>\n    <p>\n      We recommend building UIs with a\n      <a\n        href=\"https://blog.hichroma.com/component-driven-development-ce1109d56c8e\"\n        target=\"_blank\"\n        rel=\"noopener noreferrer\"\n      >\n        <strong>component-driven</strong>\n      </a>\n      process starting with atomic components and ending with pages.\n    </p>\n    <p>\n      Render pages with mock data. This makes it easy to build and review page states without\n      needing to navigate to them in your app. Here are some handy patterns for managing page data\n      in Storybook:\n    </p>\n    <ul>\n      <li>\n        Use a higher-level connected component. Storybook helps you compose such data from the\n        \"args\" of child component stories\n      </li>\n      <li>\n        Assemble data in the page component from your services. You can mock these services out\n        using Storybook.\n      </li>\n    </ul>\n    <p>\n      Get a guided tutorial on component-driven development at\n      <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n        Storybook tutorials\n      </a>\n      . Read more in the\n      <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">docs</a>\n      .\n    </p>\n    <div class=\"tip-wrapper\">\n      <span class=\"tip\">Tip</span>\n      Adjust the width of the canvas with the\n      <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n        <g fill=\"none\" fill-rule=\"evenodd\">\n          <path\n            d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0\n            01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0\n            010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n            id=\"a\"\n            fill=\"#999\"\n          />\n        </g>\n      </svg>\n      Viewports addon in the toolbar\n    </div>\n  </section>\n</article>\n"
  },
  {
    "path": "code/renderers/svelte/template/components/Button.svelte",
    "content": "<script>\n  /**\n   * @typedef {Object} Props\n   * @property {boolean} [primary] Is this the principal call to action on the page?\n   * @property {string} [backgroundColor] What background color to use\n   * @property {'small' | 'medium' | 'large'} [size] How large should the button be?\n   * @property {string} label Button contents\n   * @property {() => void} [onClick] The onclick event handler\n   */\n\n  /** @type {Props} */\n  const { primary = false, backgroundColor, size = 'medium', label, onClick } = $props();\n\n  let mode = $derived(primary ? 'storybook-button--primary' : 'storybook-button--secondary');\n  let style = $derived(backgroundColor ? `background-color: ${backgroundColor}` : '');\n</script>\n\n<button\n  type=\"button\"\n  class={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n  {style}\n  onclick={onClick}\n>\n  {label}\n</button>\n\n<style>\n  .storybook-button {\n    display: inline-block;\n    cursor: pointer;\n    border: 0;\n    border-radius: 3em;\n    font-weight: 700;\n    line-height: 1;\n    font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n  }\n  .storybook-button--primary {\n    background-color: #555ab9;\n    color: white;\n  }\n  .storybook-button--secondary {\n    box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;\n    background-color: transparent;\n    color: #333;\n  }\n  .storybook-button--small {\n    padding: 10px 16px;\n    font-size: 12px;\n  }\n  .storybook-button--medium {\n    padding: 11px 20px;\n    font-size: 14px;\n  }\n  .storybook-button--large {\n    padding: 12px 24px;\n    font-size: 16px;\n  }\n</style>\n"
  },
  {
    "path": "code/renderers/svelte/template/components/Form.svelte",
    "content": "<script>\n  const { onSuccess } = $props();\n\n  let value = $state('');\n  let complete = $state(false);\n\n  function handleClick(event) {\n    value = event.target.value;\n  }\n\n  function handleSubmit(event) {\n    event.preventDefault();\n    onSuccess(value);\n\n    setTimeout(() => {\n      complete = true;\n    }, 500);\n\n    setTimeout(() => {\n      complete = false;\n    }, 1500);\n  }\n</script>\n\n<form id=\"interaction-test-form\" onsubmit={handleSubmit}>\n  <label>\n    Enter Value\n    <input type=\"text\" data-testid=\"value\" bind:value required onclick={handleClick} />\n  </label>\n  <button type=\"submit\">Submit</button>\n  {#if complete}<p>Completed!!</p>{/if}\n</form>\n"
  },
  {
    "path": "code/renderers/svelte/template/components/Html.svelte",
    "content": "<script>\n  const { content } = $props();\n</script>\n\n<div>{@html content}</div>\n"
  },
  {
    "path": "code/renderers/svelte/template/components/Pre.svelte",
    "content": "<script>\n  const { style = {}, object, text = '' } = $props();\n\n  let finalText = $derived(object ? JSON.stringify(object, null, 2) : text);\n</script>\n\n<pre data-testid=\"pre\" {style}>{finalText}</pre>\n"
  },
  {
    "path": "code/renderers/svelte/template/components/index.js",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport Button from './Button.svelte';\nimport Form from './Form.svelte';\nimport Html from './Html.svelte';\nimport Pre from './Pre.svelte';\n\nglobalThis.__TEMPLATE_COMPONENTS__ = { Button, Pre, Form, Html };\nglobalThis.storybookRenderer = 'svelte';\n"
  },
  {
    "path": "code/renderers/svelte/template/stories/AsyncComponent.svelte",
    "content": "<script lang=\"ts\">\n  let shown = $state(false);\n\n  let { onEffect }: { onEffect?: () => void } = $props();\n\n  await new Promise<void>((resolve) => {\n    setTimeout(() => {\n      onEffect?.();\n      shown = true;\n      resolve();\n    }, 100);\n  });\n</script>\n\n{#if shown}\n  <div data-testid=\"after-effect\">This element is shown after the component's effect runs</div>\n{/if}\n"
  },
  {
    "path": "code/renderers/svelte/template/stories/BorderDecoratorBlue.svelte",
    "content": "<script>\n  const { children } = $props();\n</script>\n\n<div style=\"border: 3px solid blue; padding: 10px; margin: 10px;\">\n  {@render children()}\n</div>\n"
  },
  {
    "path": "code/renderers/svelte/template/stories/BorderDecoratorProps.svelte",
    "content": "<script>\n  const { color = 'violet', children } = $props();\n</script>\n\n<div style=\"border: 3px solid {color}; padding: 10px; margin: 10px;\">\n  {@render children()}\n</div>\n"
  },
  {
    "path": "code/renderers/svelte/template/stories/BorderDecoratorRed.svelte",
    "content": "<script>\n  const { children } = $props();\n</script>\n\n<div style=\"border: 3px solid red; padding: 10px; margin: 10px;\">\n  {@render children()}\n</div>\n"
  },
  {
    "path": "code/renderers/svelte/template/stories/Button.svelte",
    "content": "<script>\n  const Button = globalThis.__TEMPLATE_COMPONENTS__?.Button;\n\n  const { text = 'You clicked' } = $props();\n\n  let count = $state(0);\n</script>\n\n<Button onClick={() => (count += 1)} label=\"{text}: {count}\" />\n\n<p>A little text to show this is a view.</p>\n<p>If we need to test components in a Svelte environment, for instance to test slot behaviour,</p>\n<p>then wrapping the component up in a view</p>\n<p>made just for the story is the simplest way to achieve this.</p>\n"
  },
  {
    "path": "code/renderers/svelte/template/stories/SyncComponent.svelte",
    "content": "<script lang=\"ts\">\n  let shown = $state(false);\n\n  let { onEffect }: { onEffect?: () => void } = $props();\n\n  $effect(() => {\n    onEffect?.();\n    shown = true;\n  });\n</script>\n\n{#if shown}\n  <div data-testid=\"after-effect\">This element is shown after the component's effect runs</div>\n{/if}\n"
  },
  {
    "path": "code/renderers/svelte/template/stories/args.stories.js",
    "content": "import {\n  RESET_STORY_ARGS,\n  STORY_RENDERED,\n  UPDATE_STORY_ARGS,\n} from 'storybook/internal/core-events';\n\nimport { addons } from 'storybook/preview-api';\nimport { expect, userEvent, waitFor } from 'storybook/test';\n\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  tags: ['!vitest'],\n};\n\nexport const UpdatingArgs = {\n  play: async ({ canvas, id, step }) => {\n    const channel = addons.getChannel();\n\n    await step('Reset story args', async () => {\n      // Just to ensure the story is always in a clean state from the beginning, not really part of the test\n      channel.emit(RESET_STORY_ARGS, { storyId: id });\n      await new Promise((resolve) => {\n        channel.once(STORY_RENDERED, resolve);\n      });\n      await waitFor(async () => {\n        await expect(canvas.getByRole('button')).toHaveTextContent('You clicked: 0');\n      });\n    });\n\n    await step('Change state', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n      await waitFor(async () => {\n        await expect(canvas.getByRole('button')).toHaveTextContent('You clicked: 1');\n      });\n    });\n\n    await step(\"Update story args with { text: 'Changed' }\", async () => {\n      channel.emit(UPDATE_STORY_ARGS, { storyId: id, updatedArgs: { text: 'Changed' } });\n      await new Promise((resolve) => {\n        channel.once(STORY_RENDERED, resolve);\n      });\n      await waitFor(async () => {\n        await expect(canvas.getByRole('button')).toHaveTextContent('Changed: 1');\n      });\n    });\n  },\n};\n\nexport const RemountOnResetStoryArgs = {\n  play: async (playContext) => {\n    await UpdatingArgs.play(playContext);\n\n    const channel = addons.getChannel();\n    const { canvas, id, step } = playContext;\n\n    // expect that all state and args are reset after RESET_STORY_ARGS because Svelte needs to remount the component\n    // most other renderers would have 'You clicked: 1' here because they don't remount the component\n    // if this doesn't fully remount it would be 'undefined: 1' because undefined args are used as is in Svelte, and the state is kept\n    await step('Reset story args', () => channel.emit(RESET_STORY_ARGS, { storyId: id }));\n\n    await waitFor(async () => {\n      await expect(canvas.getByRole('button')).toHaveTextContent('You clicked: 0');\n    });\n  },\n};\n"
  },
  {
    "path": "code/renderers/svelte/template/stories/decorators.stories.js",
    "content": "import { expect, fn } from 'storybook/test';\n\nimport BorderDecoratorBlue from './BorderDecoratorBlue.svelte';\nimport BorderDecoratorProps from './BorderDecoratorProps.svelte';\nimport BorderDecoratorRed from './BorderDecoratorRed.svelte';\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  decorators: [() => BorderDecoratorRed],\n  tags: ['autodocs'],\n};\n\nexport const WithDefaultRedBorder = {};\nexport const WithBareBlueBorder = {\n  decorators: [() => BorderDecoratorBlue],\n};\nexport const WithPreparedBlueBorder = {\n  decorators: [\n    () => ({\n      Component: BorderDecoratorBlue,\n    }),\n  ],\n};\nexport const WithPropsBasedBorder = {\n  decorators: [\n    () => ({\n      Component: BorderDecoratorProps,\n      props: { color: 'green' },\n    }),\n  ],\n};\nexport const WithArgsBasedBorderUnset = {\n  argTypes: {\n    color: { control: 'color' },\n  },\n  decorators: [(_, { args }) => ({ Component: BorderDecoratorProps, props: args })],\n};\nexport const WithArgsBasedBorder = {\n  ...WithArgsBasedBorderUnset,\n  args: { color: 'lightblue' },\n};\n\nconst decoratorCalled = fn();\n\nexport const DecoratorsRunOnce = {\n  decorators: [\n    (Story) => {\n      decoratorCalled();\n      return Story();\n    },\n  ],\n  play: async () => {\n    expect(decoratorCalled).toHaveBeenCalledTimes(1);\n  },\n};\n"
  },
  {
    "path": "code/renderers/svelte/template/stories/mount-in-play.stories.ts",
    "content": "import type { StoryObj } from '@storybook/svelte';\n\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n};\n\nexport const Basic: StoryObj = {\n  args: {\n    disabled: true,\n  },\n  async play({ mount, args }) {\n    await mount(Button, { props: { ...args, label: 'set in play' } });\n  },\n};\n"
  },
  {
    "path": "code/renderers/svelte/template/stories/settled.stories.ts",
    "content": "import type { StoryObj } from '@storybook/svelte';\n\nimport { expect, fn, waitFor } from 'storybook/test';\n\nimport AsyncComponent from './AsyncComponent.svelte';\nimport SyncComponent from './SyncComponent.svelte';\n\nexport default {\n  title: 'stories/renderers/svelte/settled',\n};\n\nexport const Sync: StoryObj<typeof SyncComponent> = {\n  render: (args) => ({\n    Component: SyncComponent,\n    props: args,\n  }),\n  args: {\n    onEffect: fn(),\n  },\n  play: async ({ canvas, args }) => {\n    await expect(args.onEffect).toHaveBeenCalledOnce();\n    await expect(canvas.getByTestId('after-effect')).toBeInTheDocument();\n  },\n};\n\nexport const Async: StoryObj<typeof AsyncComponent> = {\n  render: (args) => ({\n    Component: AsyncComponent,\n    props: args,\n  }),\n  args: {\n    onEffect: fn(),\n  },\n  play: async ({ canvas, canvasElement, args }) => {\n    await expect(args.onEffect).not.toHaveBeenCalled();\n    await expect(\n      canvasElement.querySelector('#sb-pending-async-component-notice')\n    ).toBeInTheDocument();\n\n    // TODO: Ideally we should be able to call await svelte.settled() here instead of waitFor, but currently there's a bug making it never resolve\n    // await svelte.settled();\n\n    await waitFor(async () => {\n      await expect(args.onEffect).toHaveBeenCalledOnce();\n      await expect(canvas.getByTestId('after-effect')).toBeInTheDocument();\n      await expect(\n        canvasElement.querySelector('#sb-pending-async-component-notice')\n      ).not.toBeInTheDocument();\n    });\n  },\n};\n"
  },
  {
    "path": "code/renderers/svelte/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"module\": \"ESNext\",\n    \"verbatimModuleSyntax\": true\n  },\n  \"include\": [\"src/**/*\", \"src/**/*.svelte\", \"template/**/*\", \"template/**/*.svelte\"]\n}\n"
  },
  {
    "path": "code/renderers/svelte/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default defineConfig(\n  mergeConfig(vitestCommonConfig, {\n    plugins: [\n      import('@sveltejs/vite-plugin-svelte').then(({ svelte }) => svelte()),\n      // @ts-expect-error -- types don't match our TS module resolution setting\n      import('@testing-library/svelte/vite').then(({ svelteTesting }) => svelteTesting()),\n    ],\n    test: {\n      environment: 'happy-dom',\n    },\n  })\n);\n"
  },
  {
    "path": "code/renderers/vue3/README.md",
    "content": "# Storybook Vue3 renderer\n\nDevelop, document, and test UI components in isolation.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/renderers/vue3/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./entry-preview'],\n        entryPoint: './src/entry-preview.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./entry-preview-docs'],\n        entryPoint: './src/entry-preview-docs.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./experimental-playwright'],\n        entryPoint: './src/playwright.ts',\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/renderers/vue3/package.json",
    "content": "{\n  \"name\": \"@storybook/vue3\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook Vue 3 renderer: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-renderer\",\n    \"vue\",\n    \"components\",\n    \"component\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/renderers/vue3\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/renderers/vue3\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./entry-preview\": \"./dist/entry-preview.js\",\n    \"./entry-preview-docs\": \"./dist/entry-preview-docs.js\",\n    \"./experimental-playwright\": {\n      \"types\": \"./dist/playwright.d.ts\",\n      \"code\": \"./src/playwright.ts\",\n      \"default\": \"./dist/playwright.js\"\n    },\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"template/cli/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/global\": \"^5.0.0\",\n    \"type-fest\": \"~2.19\",\n    \"vue-component-type-helpers\": \"latest\"\n  },\n  \"devDependencies\": {\n    \"@testing-library/vue\": \"^8.0.0\",\n    \"@vitejs/plugin-vue\": \"^4.6.2\",\n    \"typescript\": \"^5.8.3\",\n    \"vue\": \"^3.2.47\",\n    \"vue-tsc\": \"latest\"\n  },\n  \"peerDependencies\": {\n    \"storybook\": \"workspace:^\",\n    \"vue\": \"^3.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/renderers/vue3/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/renderers/vue3/project.json",
    "content": "{\n  \"name\": \"vue3\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {\n      \"executor\": \"nx:run-commands\",\n      \"options\": { \"cwd\": \"{projectRoot}\", \"command\": \"vue-tsc --noEmit\" }\n    }\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/renderers/vue3/src/__snapshots__/extractArgTypes.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`extractArgTypes (vue-docgen-api) > should extract events for Vue component 1`] = `\n{\n  \"bar\": {\n    \"control\": {\n      \"disable\": true,\n    },\n    \"description\": \"\",\n    \"name\": \"bar\",\n    \"table\": {\n      \"category\": \"events\",\n      \"type\": {\n        \"summary\": \"[value: { year: number; title?: any; }]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"value\": \"[value: { year: number; title?: any; }]\",\n    },\n  },\n  \"baz\": {\n    \"control\": {\n      \"disable\": true,\n    },\n    \"description\": \"\",\n    \"name\": \"baz\",\n    \"table\": {\n      \"category\": \"events\",\n      \"type\": {\n        \"summary\": \"[]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"value\": \"[]\",\n    },\n  },\n  \"foo\": {\n    \"control\": {\n      \"disable\": true,\n    },\n    \"description\": \"\",\n    \"name\": \"foo\",\n    \"table\": {\n      \"category\": \"events\",\n      \"type\": {\n        \"summary\": \"[data?: { foo: string; }]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"value\": \"[data?: { foo: string; } | undefined]\",\n    },\n  },\n}\n`;\n\nexports[`extractArgTypes (vue-docgen-api) > should extract events for component 1`] = `\n{\n  \"bar\": {\n    \"control\": {\n      \"disable\": true,\n    },\n    \"description\": \"Test description bar\",\n    \"name\": \"bar\",\n    \"table\": {\n      \"category\": \"events\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"{ year: number; title?: any }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"{ year: number; title?: any }\",\n    },\n  },\n  \"baz\": {\n    \"control\": {\n      \"disable\": true,\n    },\n    \"description\": \"Test description baz\",\n    \"name\": \"baz\",\n    \"table\": {\n      \"category\": \"events\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": undefined,\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"\",\n    },\n  },\n}\n`;\n\nexports[`extractArgTypes (vue-docgen-api) > should extract expose for component 1`] = `\n{\n  \"count\": {\n    \"control\": {\n      \"disable\": true,\n    },\n    \"description\": \"a count number\",\n    \"name\": \"count\",\n    \"table\": {\n      \"category\": \"expose\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": undefined,\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"value\": \"\",\n    },\n  },\n  \"label\": {\n    \"control\": {\n      \"disable\": true,\n    },\n    \"description\": \"a label string\",\n    \"name\": \"label\",\n    \"table\": {\n      \"category\": \"expose\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": undefined,\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"value\": \"\",\n    },\n  },\n}\n`;\n\nexports[`extractArgTypes (vue-docgen-api) > should extract props for component 1`] = `\n{\n  \"array\": {\n    \"defaultValue\": undefined,\n    \"description\": \"description required array object\",\n    \"name\": \"array\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedProps[]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"array\",\n      \"required\": true,\n      \"value\": {\n        \"name\": \"object\",\n        \"required\": false,\n        \"value\": {},\n      },\n    },\n  },\n  \"arrayOptional\": {\n    \"defaultValue\": undefined,\n    \"description\": \"description optional array object\",\n    \"name\": \"arrayOptional\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedProps[]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"array\",\n      \"required\": false,\n      \"value\": {\n        \"name\": \"object\",\n        \"required\": false,\n        \"value\": {},\n      },\n    },\n  },\n  \"bar\": {\n    \"defaultValue\": {\n      \"summary\": \"1\",\n    },\n    \"description\": \"description bar is optional number\",\n    \"name\": \"bar\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": {\n        \"summary\": \"1\",\n      },\n      \"type\": {\n        \"summary\": \"number\",\n      },\n    },\n    \"type\": {\n      \"name\": \"number\",\n      \"required\": false,\n    },\n  },\n  \"baz\": {\n    \"defaultValue\": undefined,\n    \"description\": \"description baz is required boolean\",\n    \"name\": \"baz\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"boolean\",\n      },\n    },\n    \"type\": {\n      \"name\": \"boolean\",\n      \"required\": true,\n    },\n  },\n  \"enumValue\": {\n    \"defaultValue\": undefined,\n    \"description\": \"description enum value\",\n    \"name\": \"enumValue\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"MyEnum\",\n      },\n    },\n    \"type\": {\n      \"name\": \"enum\",\n      \"required\": true,\n      \"value\": [\n        \"MyEnum.Small\",\n        \"MyEnum.Medium\",\n        \"MyEnum.Large\",\n      ],\n    },\n  },\n  \"foo\": {\n    \"defaultValue\": undefined,\n    \"description\": \"@default: \"rounded\"<br>@since: v1.0.0<br>@see: https://vuejs.org/<br>@deprecated: v1.1.0<br><br>string foo\",\n    \"name\": \"foo\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"string\",\n      \"required\": true,\n    },\n  },\n  \"inlined\": {\n    \"defaultValue\": undefined,\n    \"description\": \"\",\n    \"name\": \"inlined\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"{ foo: string; }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"object\",\n      \"required\": true,\n      \"value\": {},\n    },\n  },\n  \"literalFromContext\": {\n    \"defaultValue\": undefined,\n    \"description\": \"description literal type alias that require context\",\n    \"name\": \"literalFromContext\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"\"Uncategorized\" | \"Content\" | \"Interaction\" | \"Display\" | \"Forms\" | \"Addons\"\",\n      },\n    },\n    \"type\": {\n      \"name\": \"enum\",\n      \"required\": true,\n      \"value\": [\n        \"Uncategorized\",\n        \"Content\",\n        \"Interaction\",\n        \"Display\",\n        \"Forms\",\n        \"Addons\",\n      ],\n    },\n  },\n  \"nested\": {\n    \"defaultValue\": undefined,\n    \"description\": \"description nested is required nested object\",\n    \"name\": \"nested\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedProps\",\n      },\n    },\n    \"type\": {\n      \"name\": \"object\",\n      \"required\": true,\n      \"value\": {},\n    },\n  },\n  \"nestedIntersection\": {\n    \"defaultValue\": undefined,\n    \"description\": \"description required nested object with intersection\",\n    \"name\": \"nestedIntersection\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedProps & { additionalProp: string; }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"object\",\n      \"required\": true,\n      \"value\": {},\n    },\n  },\n  \"nestedOptional\": {\n    \"defaultValue\": undefined,\n    \"description\": \"description optional nested object\",\n    \"name\": \"nestedOptional\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedProps | MyIgnoredNestedProps\",\n      },\n    },\n    \"type\": {\n      \"name\": \"union\",\n      \"required\": false,\n      \"value\": [\n        {\n          \"name\": \"object\",\n          \"required\": false,\n          \"value\": {},\n        },\n        {\n          \"name\": \"object\",\n          \"required\": false,\n          \"value\": {},\n        },\n      ],\n    },\n  },\n  \"recursive\": {\n    \"defaultValue\": undefined,\n    \"description\": \"\",\n    \"name\": \"recursive\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedRecursiveProps\",\n      },\n    },\n    \"type\": {\n      \"name\": \"object\",\n      \"required\": false,\n      \"value\": {},\n    },\n  },\n  \"stringArray\": {\n    \"defaultValue\": {\n      \"summary\": \"[\"foo\", \"bar\"]\",\n    },\n    \"description\": \"description stringArray is string array\",\n    \"name\": \"stringArray\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": {\n        \"summary\": \"[\"foo\", \"bar\"]\",\n      },\n      \"type\": {\n        \"summary\": \"string[]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"array\",\n      \"required\": false,\n      \"value\": {\n        \"name\": \"string\",\n        \"required\": false,\n      },\n    },\n  },\n  \"union\": {\n    \"defaultValue\": undefined,\n    \"description\": \"description union is required union type\",\n    \"name\": \"union\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"string | number\",\n      },\n    },\n    \"type\": {\n      \"name\": \"union\",\n      \"required\": true,\n      \"value\": [\n        {\n          \"name\": \"string\",\n          \"required\": false,\n        },\n        {\n          \"name\": \"number\",\n          \"required\": false,\n        },\n      ],\n    },\n  },\n  \"unionOptional\": {\n    \"defaultValue\": undefined,\n    \"description\": \"description unionOptional is optional union type\",\n    \"name\": \"unionOptional\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"string | number | boolean\",\n      },\n    },\n    \"type\": {\n      \"name\": \"union\",\n      \"required\": false,\n      \"value\": [\n        {\n          \"name\": \"string\",\n          \"required\": false,\n        },\n        {\n          \"name\": \"number\",\n          \"required\": false,\n        },\n        {\n          \"name\": \"boolean\",\n          \"required\": false,\n        },\n      ],\n    },\n  },\n}\n`;\n\nexports[`extractArgTypes (vue-docgen-api) > should extract props for component 2`] = `\n{\n  \"array\": {\n    \"description\": \"description required array object\",\n    \"name\": \"array\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedProps[]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": true,\n      \"value\": \"Array([object Object])\",\n    },\n  },\n  \"arrayOptional\": {\n    \"description\": \"description optional array object\",\n    \"name\": \"arrayOptional\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedProps[]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"Array([object Object])\",\n    },\n  },\n  \"bar\": {\n    \"description\": \"description bar is optional number\",\n    \"name\": \"bar\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": {\n        \"summary\": \"1\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"number\",\n      },\n    },\n    \"type\": {\n      \"name\": \"number\",\n      \"required\": false,\n    },\n  },\n  \"baz\": {\n    \"description\": \"description baz is required boolean\",\n    \"name\": \"baz\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"boolean\",\n      },\n    },\n    \"type\": {\n      \"name\": \"boolean\",\n      \"required\": true,\n    },\n  },\n  \"enumValue\": {\n    \"description\": \"description enum value\",\n    \"name\": \"enumValue\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"MyEnum\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": true,\n      \"value\": \"MyEnum\",\n    },\n  },\n  \"foo\": {\n    \"description\": \"string foo\",\n    \"name\": \"foo\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"string\",\n      \"required\": true,\n    },\n  },\n  \"inlined\": {\n    \"description\": undefined,\n    \"name\": \"inlined\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"{ foo: string }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": true,\n      \"value\": \"{ foo: string }\",\n    },\n  },\n  \"literalFromContext\": {\n    \"description\": \"description literal type alias that require context\",\n    \"name\": \"literalFromContext\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"MyCategories\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": true,\n      \"value\": \"MyCategories\",\n    },\n  },\n  \"nested\": {\n    \"description\": \"description nested is required nested object\",\n    \"name\": \"nested\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedProps\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": true,\n      \"value\": \"MyNestedProps\",\n    },\n  },\n  \"nestedIntersection\": {\n    \"description\": \"description required nested object with intersection\",\n    \"name\": \"nestedIntersection\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedProps & {\n  /**\n   * description required additional property\n   */\n  additionalProp: string;\n}\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": true,\n      \"value\": \"intersection([object Object],[object Object])\",\n    },\n  },\n  \"nestedOptional\": {\n    \"description\": \"description optional nested object\",\n    \"name\": \"nestedOptional\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedProps | MyIgnoredNestedProps\",\n      },\n    },\n    \"type\": {\n      \"name\": \"union\",\n      \"required\": false,\n      \"value\": [\n        {\n          \"name\": \"other\",\n          \"value\": \"MyNestedProps\",\n        },\n        {\n          \"name\": \"other\",\n          \"value\": \"MyIgnoredNestedProps\",\n        },\n      ],\n    },\n  },\n  \"recursive\": {\n    \"description\": undefined,\n    \"name\": \"recursive\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedRecursiveProps\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"MyNestedRecursiveProps\",\n    },\n  },\n  \"stringArray\": {\n    \"description\": \"description stringArray is string array\",\n    \"name\": \"stringArray\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": {\n        \"summary\": \"() => ['foo', 'bar']\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"string[]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"Array([object Object])\",\n    },\n  },\n  \"union\": {\n    \"description\": \"description union is required union type\",\n    \"name\": \"union\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"string | number\",\n      },\n    },\n    \"type\": {\n      \"name\": \"union\",\n      \"required\": true,\n      \"value\": [\n        {\n          \"name\": \"string\",\n        },\n        {\n          \"name\": \"number\",\n        },\n      ],\n    },\n  },\n  \"unionOptional\": {\n    \"description\": \"description unionOptional is optional union type\",\n    \"name\": \"unionOptional\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"string | number | boolean\",\n      },\n    },\n    \"type\": {\n      \"name\": \"union\",\n      \"required\": false,\n      \"value\": [\n        {\n          \"name\": \"string\",\n        },\n        {\n          \"name\": \"number\",\n        },\n        {\n          \"name\": \"boolean\",\n        },\n      ],\n    },\n  },\n}\n`;\n\nexports[`extractArgTypes (vue-docgen-api) > should extract slots for component 1`] = `\n{\n  \"default\": {\n    \"description\": undefined,\n    \"name\": \"default\",\n    \"table\": {\n      \"category\": \"slots\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"{ num: unknown }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"{ num: unknown }\",\n    },\n  },\n  \"named\": {\n    \"description\": undefined,\n    \"name\": \"named\",\n    \"table\": {\n      \"category\": \"slots\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"{ str: unknown }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"{ str: unknown }\",\n    },\n  },\n  \"no-bind\": {\n    \"description\": undefined,\n    \"name\": \"no-bind\",\n    \"table\": {\n      \"category\": \"slots\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": undefined,\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"\",\n    },\n  },\n  \"vbind\": {\n    \"description\": undefined,\n    \"name\": \"vbind\",\n    \"table\": {\n      \"category\": \"slots\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"{ num: unknown; str: unknown }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"{ num: unknown; str: unknown }\",\n    },\n  },\n}\n`;\n\nexports[`extractArgTypes (vue-docgen-api) > should extract slots type for Vue component 1`] = `\n{\n  \"default\": {\n    \"description\": \"\",\n    \"name\": \"default\",\n    \"table\": {\n      \"category\": \"slots\",\n      \"type\": {\n        \"summary\": \"{ num: number; }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"value\": \"{ num: number; }\",\n    },\n  },\n  \"named\": {\n    \"description\": \"\",\n    \"name\": \"named\",\n    \"table\": {\n      \"category\": \"slots\",\n      \"type\": {\n        \"summary\": \"{ str: string; }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"value\": \"{ str: string; }\",\n    },\n  },\n  \"no-bind\": {\n    \"description\": \"\",\n    \"name\": \"no-bind\",\n    \"table\": {\n      \"category\": \"slots\",\n      \"type\": {\n        \"summary\": \"{}\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"value\": \"{}\",\n    },\n  },\n  \"vbind\": {\n    \"description\": \"\",\n    \"name\": \"vbind\",\n    \"table\": {\n      \"category\": \"slots\",\n      \"type\": {\n        \"summary\": \"{ num: number; str: string; }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"value\": \"{ num: number; str: string; }\",\n    },\n  },\n}\n`;\n"
  },
  {
    "path": "code/renderers/vue3/src/__tests__/BaseLayout.vue",
    "content": "<script setup lang=\"ts\">\ndefineProps<{ otherProp: boolean }>();\n</script>\n\n<template>\n  <div>\n    <header>\n      <slot name=\"header\" title=\"Some title\"></slot>\n    </header>\n    <main>\n      <slot></slot>\n    </main>\n    <footer>\n      <slot name=\"footer\"></slot>\n    </footer>\n  </div>\n</template>\n"
  },
  {
    "path": "code/renderers/vue3/src/__tests__/Button.vue",
    "content": "<script setup lang=\"ts\">\ndefineProps<{ disabled: boolean; label: string }>();\n\nconst emit = defineEmits<{\n  (e: 'myChangeEvent', id: number): void;\n  (e: 'myClickEvent', id: number): void;\n}>();\n</script>\n\n<template>\n  <button :disabled=\"disabled\" @change=\"emit('myChangeEvent', 0)\" @click=\"emit('myClickEvent', 0)\">\n    {{ label }}\n  </button>\n</template>\n\n<style scoped></style>\n"
  },
  {
    "path": "code/renderers/vue3/src/__tests__/Decorator.vue",
    "content": "<script setup lang=\"ts\">\ndefineProps<{ decoratorArg: string }>();\n</script>\n\n<template>\n  Decorator: {decoratorArg}\n  <slot></slot>\n</template>\n"
  },
  {
    "path": "code/renderers/vue3/src/__tests__/Decorator2.vue",
    "content": "<script setup lang=\"ts\">\ndefineProps<{ decoratorArg2: string }>();\n</script>\n\n<template>\n  Decorator: {decoratorArg2}\n  <slot></slot>\n</template>\n"
  },
  {
    "path": "code/renderers/vue3/src/__tests__/GenericComponent.vue",
    "content": "<template>\n  <ul class=\"generic-list\">\n    <li\n      v-for=\"(item, index) in items\"\n      :key=\"index\"\n      :class=\"{ selected: selectedItem === item }\"\n      @click=\"selectItem(item)\"\n    >\n      {{ getLabel(item) }}\n    </li>\n  </ul>\n</template>\n\n<script lang=\"ts\" setup generic=\"T\">\nimport { ref } from 'vue';\n\nconst props = defineProps<{\n  items: T[];\n  getLabel: (item: T) => string;\n  defaultSelected?: T;\n}>();\n\nconst emit = defineEmits<{\n  (e: 'select', item: T): void;\n}>();\n\nconst selectedItem = ref<T | undefined>(props.defaultSelected);\n\nconst selectItem = (item: T) => {\n  selectedItem.value = item;\n  emit('select', item);\n};\n</script>\n"
  },
  {
    "path": "code/renderers/vue3/src/__tests__/button.css",
    "content": ".storybook-button {\n  display: inline-block;\n  cursor: pointer;\n  border: 0;\n  border-radius: 3em;\n  font-weight: 700;\n  line-height: 1;\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n.storybook-button--primary {\n  background-color: #555ab9;\n  color: white;\n}\n.storybook-button--secondary {\n  box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;\n  background-color: transparent;\n  color: #333;\n}\n.storybook-button--small {\n  padding: 10px 16px;\n  font-size: 12px;\n}\n.storybook-button--medium {\n  padding: 11px 20px;\n  font-size: 14px;\n}\n.storybook-button--large {\n  padding: 12px 24px;\n  font-size: 16px;\n}\n"
  },
  {
    "path": "code/renderers/vue3/src/__tests__/composeStories/Button.stories.ts",
    "content": "import { expect, fn, userEvent, within } from 'storybook/test';\n\nimport type { StoryFn as CSF2Story, Meta, StoryObj } from '../../index.ts';\nimport Button from './Button.vue';\n\nconst meta = {\n  title: 'Example/Button',\n  component: Button,\n  argTypes: {\n    size: { control: 'select', options: ['small', 'medium', 'large'] },\n    backgroundColor: { control: 'color' },\n    onClick: { action: 'clicked' },\n  },\n  args: { primary: false },\n  excludeStories: /.*ImNotAStory$/,\n} as Meta<typeof Button>;\n\nexport default meta;\ntype CSF3Story = StoryObj<typeof meta>;\n\n// For testing purposes. Should be ignored in ComposeStories\nexport const ImNotAStory = 123;\n\nconst Template: CSF2Story = (args) => ({\n  components: { Button },\n  setup() {\n    return { args };\n  },\n  template: '<Button v-bind=\"args\" />',\n});\n\nexport const CSF2Secondary = Template.bind({});\nCSF2Secondary.args = {\n  label: 'label coming from story args!',\n  primary: false,\n};\n\nconst getCaptionForLocale = (locale: string) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'pt':\n      return 'Olá!';\n    case 'en':\n      return 'Hello!';\n    default:\n      return undefined;\n  }\n};\n\nexport const CSF2StoryWithLocale: CSF2Story = (args, { globals }) => ({\n  components: { Button },\n  setup() {\n    const label = getCaptionForLocale(globals.locale);\n    return { args: { ...args, label } };\n  },\n  template: `<div>\n    <p>locale: ${globals.locale}</p>\n    <Button v-bind=\"args\" label=\"${getCaptionForLocale(globals.locale)}\" />\n  </div>`,\n});\nCSF2StoryWithLocale.storyName = 'WithLocale';\n\nexport const CSF2StoryWithParamsAndDecorator = Template.bind({});\nCSF2StoryWithParamsAndDecorator.args = {\n  label: 'foo',\n};\nCSF2StoryWithParamsAndDecorator.parameters = {\n  layout: 'centered',\n};\nCSF2StoryWithParamsAndDecorator.decorators = [\n  () => ({ template: '<div style=\"margin: 3em;\"><story/></div>' }),\n];\n\nexport const CSF3Primary: CSF3Story = {\n  args: {\n    label: 'foo',\n    size: 'large',\n    primary: true,\n  },\n};\n\nexport const CSF3Button: CSF3Story = {\n  args: { label: 'foo' },\n};\n\nexport const CSF3ButtonWithRender: CSF3Story = {\n  ...CSF3Button,\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: `\n      <div>\n        <p data-testid=\"custom-render\">I am a custom render function</p>\n        <Button v-bind=\"args\" />\n      </div>\n    `,\n  }),\n};\n\nexport const CSF3InputFieldFilled: CSF3Story = {\n  ...CSF3Button,\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: '<input data-testid=\"input\" />',\n  }),\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    await step('Step label', async () => {\n      const inputEl = canvas.getByTestId('input');\n      await userEvent.type(inputEl, 'Hello world!');\n      await expect(inputEl).toHaveValue('Hello world!');\n    });\n  },\n};\n\nconst mockFn = fn();\nexport const LoaderStory: StoryObj<{ mockFn: (val: string) => string }> = {\n  args: {\n    mockFn,\n  },\n  loaders: [\n    async () => {\n      mockFn.mockReturnValueOnce('mockFn return value');\n      return {\n        value: 'loaded data',\n      };\n    },\n  ],\n  render: (args, { loaded }) => ({\n    components: { Button },\n    setup() {\n      return { args, data: args.mockFn('render'), loaded: loaded.value };\n    },\n    template: `\n      <div>\n        <div data-testid=\"loaded-data\">{{loaded}}</div>\n        <div data-testid=\"spy-data\">{{data}}</div>\n      </div>\n    `,\n  }),\n  play: async () => {\n    expect(mockFn).toHaveBeenCalledWith('render');\n  },\n};\n"
  },
  {
    "path": "code/renderers/vue3/src/__tests__/composeStories/Button.vue",
    "content": "<template>\n  <button type=\"button\" :class=\"classes\" :style=\"style\" @click=\"emit('myClickEvent', 0)\">\n    {{ label }}\n  </button>\n</template>\n\n<script lang=\"ts\" setup>\nimport { computed } from 'vue';\n\nconst props = withDefaults(\n  defineProps<{\n    /**\n     * The label of the button\n     */\n    label: string;\n    /**\n     * primary or secondary button\n     */\n    primary?: boolean;\n    /**\n     * size of the button\n     */\n    size?: 'small' | 'medium' | 'large';\n    /**\n     * background color of the button\n     */\n    backgroundColor?: string;\n  }>(),\n  { primary: false }\n);\n\nconst emit = defineEmits<{\n  (e: 'myClickEvent', id: number): void;\n}>();\n\nconst classes = computed(() => ({\n  'storybook-button': true,\n  'storybook-button--primary': props.primary,\n  'storybook-button--secondary': !props.primary,\n  [`storybook-button--${props.size || 'medium'}`]: true,\n}));\n\nconst style = computed(() => ({\n  backgroundColor: props.backgroundColor,\n}));\n</script>\n"
  },
  {
    "path": "code/renderers/vue3/src/__tests__/composeStories/__snapshots__/portable-stories.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`Renders CSF2Secondary story 1`] = `\n<body>\n  <div\n    data-v-app=\"\"\n  >\n    <button\n      class=\"storybook-button storybook-button--secondary storybook-button--medium\"\n      type=\"button\"\n    >\n      label coming from story args!\n    </button>\n  </div>\n</body>\n`;\n\nexports[`Renders CSF2StoryWithParamsAndDecorator story 1`] = `\n<body>\n  <div\n    data-v-app=\"\"\n  >\n    <div\n      style=\"margin: 3em;\"\n    >\n      <button\n        class=\"storybook-button storybook-button--secondary storybook-button--medium\"\n        type=\"button\"\n      >\n        foo\n      </button>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`Renders CSF3Button story 1`] = `\n<body>\n  <div\n    data-v-app=\"\"\n  >\n    <button\n      class=\"storybook-button storybook-button--secondary storybook-button--medium\"\n      type=\"button\"\n    >\n      foo\n    </button>\n  </div>\n</body>\n`;\n\nexports[`Renders CSF3ButtonWithRender story 1`] = `\n<body>\n  <div\n    data-v-app=\"\"\n  >\n    <div>\n      <p\n        data-testid=\"custom-render\"\n      >\n        I am a custom render function\n      </p>\n      <button\n        class=\"storybook-button storybook-button--secondary storybook-button--medium\"\n        type=\"button\"\n      >\n        foo\n      </button>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`Renders CSF3InputFieldFilled story 1`] = `\n<body>\n  <div\n    data-v-app=\"\"\n  >\n    <input\n      data-testid=\"input\"\n    />\n  </div>\n</body>\n`;\n\nexports[`Renders CSF3Primary story 1`] = `\n<body>\n  <div\n    data-v-app=\"\"\n  >\n    <button\n      class=\"storybook-button storybook-button--primary storybook-button--large\"\n      type=\"button\"\n    >\n      foo\n    </button>\n  </div>\n</body>\n`;\n\nexports[`Renders LoaderStory story 1`] = `\n<body>\n  <div\n    data-v-app=\"\"\n  >\n    <div>\n      <div\n        data-testid=\"loaded-data\"\n      >\n        loaded data\n      </div>\n      <div\n        data-testid=\"spy-data\"\n      >\n        mockFn return value\n      </div>\n    </div>\n  </div>\n</body>\n`;\n"
  },
  {
    "path": "code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts",
    "content": "// @vitest-environment happy-dom\n/// <reference types=\"@testing-library/jest-dom\" />\nimport { cleanup, render, screen } from '@testing-library/vue';\nimport { afterEach, describe, expect, it, vi } from 'vitest';\n\nimport type { Meta } from '@storybook/vue3';\n\nimport { expectTypeOf } from 'expect-type';\nimport { addons } from 'storybook/preview-api';\n\nimport { composeStories, composeStory, setProjectAnnotations } from '../../portable-stories.ts';\nimport * as stories from './Button.stories.ts';\nimport type Button from './Button.vue';\n\nsetProjectAnnotations([]);\n\n// example with composeStories, returns an object with all stories composed with args/decorators\nconst { CSF3Primary, LoaderStory } = composeStories(stories);\n\n// example with composeStory, returns a single story composed with args/decorators\nconst Secondary = composeStory(stories.CSF2Secondary, stories.default);\n\nafterEach(() => {\n  cleanup();\n});\n\ndescribe('renders', () => {\n  it('renders primary button', () => {\n    render(CSF3Primary, { props: { label: 'Hello world' } });\n    const buttonElement = screen.getByText(/Hello world/i);\n    expect(buttonElement).toBeInTheDocument();\n  });\n\n  it('reuses args from composed story', () => {\n    render(Secondary);\n    const buttonElement = screen.getByRole('button');\n    expect(buttonElement.textContent).toEqual(Secondary.args.label);\n  });\n\n  it('myClickEvent handler is called', async () => {\n    const myClickEventSpy = vi.fn();\n    render(Secondary, { props: { onMyClickEvent: myClickEventSpy } });\n    const buttonElement = screen.getByRole('button');\n    buttonElement.click();\n    expect(myClickEventSpy).toHaveBeenCalled();\n  });\n\n  it('reuses args from composeStories', () => {\n    const { getByText } = render(CSF3Primary);\n    const buttonElement = getByText(/foo/i);\n    expect(buttonElement).toBeInTheDocument();\n  });\n\n  it('should call and compose loaders data', async () => {\n    await LoaderStory.load();\n    const { getByTestId } = render(LoaderStory);\n    expect(getByTestId('spy-data').textContent).toEqual('mockFn return value');\n    expect(getByTestId('loaded-data').textContent).toEqual('loaded data');\n    // spy assertions happen in the play function and should work\n    await LoaderStory.run!();\n  });\n});\n\ndescribe('projectAnnotations', () => {\n  it('renders with default projectAnnotations', () => {\n    setProjectAnnotations([\n      {\n        parameters: { injected: true },\n        initialGlobals: { locale: 'en' },\n      },\n    ]);\n    const WithEnglishText = composeStory(stories.CSF2StoryWithLocale, stories.default);\n    const { getByText } = render(WithEnglishText);\n    const buttonElement = getByText('Hello!');\n    expect(buttonElement).toBeInTheDocument();\n    expect(WithEnglishText.parameters?.injected).toBe(true);\n  });\n\n  it('renders with custom projectAnnotations via composeStory params', () => {\n    const WithPortugueseText = composeStory(stories.CSF2StoryWithLocale, stories.default, {\n      initialGlobals: { locale: 'pt' },\n    });\n    const { getByText } = render(WithPortugueseText);\n    const buttonElement = getByText('Olá!');\n    expect(buttonElement).toBeInTheDocument();\n  });\n});\n\ndescribe('CSF3', () => {\n  it('renders with inferred globalRender', () => {\n    const Primary = composeStory(stories.CSF3Button, stories.default);\n\n    render(Primary, { props: { label: 'Hello world' } });\n    const buttonElement = screen.getByText(/Hello world/i);\n    expect(buttonElement).toBeInTheDocument();\n  });\n\n  it('renders with custom render function', () => {\n    const Primary = composeStory(stories.CSF3ButtonWithRender, stories.default);\n\n    render(Primary);\n    expect(screen.getByTestId('custom-render')).toBeInTheDocument();\n  });\n\n  it('renders with play function', async () => {\n    const CSF3InputFieldFilled = composeStory(stories.CSF3InputFieldFilled, stories.default);\n\n    await CSF3InputFieldFilled.run();\n\n    const input = screen.getByTestId('input') as HTMLInputElement;\n    expect(input.value).toEqual('Hello world!');\n  });\n});\n\n// common in addons that need to communicate between manager and preview\nit('should pass with decorators that need addons channel', () => {\n  const PrimaryWithChannels = composeStory(stories.CSF3Primary, stories.default, {\n    decorators: [\n      (StoryFn: any) => {\n        addons.getChannel();\n        return StoryFn();\n      },\n    ],\n  });\n  render(PrimaryWithChannels, { props: { label: 'Hello world' } });\n  const buttonElement = screen.getByText(/Hello world/i);\n  expect(buttonElement).not.toBeNull();\n});\n\ndescribe('ComposeStories types', () => {\n  it('Should support typescript operators', () => {\n    type ComposeStoriesParam = Parameters<typeof composeStories>[0];\n\n    expectTypeOf({\n      ...stories,\n      default: stories.default as Meta<typeof Button>,\n    }).toMatchTypeOf<ComposeStoriesParam>();\n\n    expectTypeOf({\n      ...stories,\n      default: stories.default satisfies Meta<typeof Button>,\n    }).toMatchTypeOf<ComposeStoriesParam>();\n  });\n});\n\n// Batch snapshot testing\nconst testCases = Object.values(composeStories(stories)).map((Story) => [Story.storyName, Story]);\nit.each(testCases)('Renders %s story', async (_storyName, Story) => {\n  if (typeof Story === 'string' || _storyName === 'CSF2StoryWithLocale') {\n    return;\n  }\n  await Story.run();\n  await new Promise((resolve) => setTimeout(resolve, 0));\n  expect(document.body).toMatchSnapshot();\n});\n"
  },
  {
    "path": "code/renderers/vue3/src/csf-factories.test.ts",
    "content": "// this file tests Typescript types that's why there are no assertions\nimport { describe, expect, expectTypeOf, it, test } from 'vitest';\n\nimport type { Canvas } from 'storybook/internal/types';\n\nimport { h } from 'vue';\n\nimport BaseLayout from './__tests__/BaseLayout.vue';\nimport Button from './__tests__/Button.vue';\nimport Decorator2TsVue from './__tests__/Decorator2.vue';\nimport DecoratorTsVue from './__tests__/Decorator.vue';\nimport GenericComponent from './__tests__/GenericComponent.vue';\nimport { __definePreview } from './preview.ts';\nimport type { ComponentPropsAndSlots, Decorator, Meta, StoryObj } from './public-types.ts';\n\ntype ButtonProps = ComponentPropsAndSlots<typeof Button>;\n\nconst preview = __definePreview({\n  addons: [],\n});\n\ntest('csf factories', () => {\n  const config = __definePreview({\n    addons: [\n      {\n        decorators: [],\n      },\n    ],\n  });\n\n  const meta = config.meta({ component: Button, args: { disabled: false } });\n\n  const MyStory = meta.story({\n    args: {\n      label: 'Hello world',\n    },\n  });\n\n  expect(MyStory.input.args?.label).toBe('Hello world');\n});\n\ndescribe('Meta', () => {\n  it('Generic parameter of Meta can be a component', () => {\n    const meta = preview.meta({\n      component: Button,\n      args: { label: 'good', disabled: false },\n    });\n  });\n\n  it('Events are inferred from component', () => {\n    const meta = preview.meta({\n      component: Button,\n      args: {\n        label: 'good',\n        disabled: false,\n        onMyChangeEvent: (value) => {\n          expectTypeOf(value).toMatchTypeOf<number>();\n        },\n      },\n      render: (args) => {\n        return h(Button, {\n          ...args,\n          onMyChangeEvent: (value) => {\n            expectTypeOf(value).toMatchTypeOf<number>();\n          },\n        });\n      },\n    });\n  });\n});\n\ndescribe('StoryObj', () => {\n  it('✅ Required args may be provided partial in meta and the story', () => {\n    const meta = preview.meta({\n      component: Button,\n      args: { label: 'good' },\n    });\n\n    const Story = meta.story({\n      args: {\n        disabled: true,\n      },\n    });\n  });\n\n  it('❌ The combined shape of meta args and story args must match the required args.', () => {\n    {\n      const meta = preview.meta({\n        component: Button,\n        args: { label: 'good' },\n      });\n      // @ts-expect-error disabled not provided ❌\n      const Basic = meta.story();\n    }\n    {\n      const meta = preview.meta({ component: Button });\n      // @ts-expect-error disabled not provided ❌\n      const Basic = meta.story({\n        args: { label: 'good' },\n      });\n    }\n  });\n});\n\ntype ThemeData = 'light' | 'dark';\n\ndescribe('Story args can be inferred', () => {\n  it('Correct args are inferred when type is widened for render function', () => {\n    const meta = preview.type<{ args: { theme: ThemeData } }>().meta({\n      component: Button,\n      render: (args) => {\n        return h('div', [h('div', `Use the theme ${args.theme}`), h(Button, args)]);\n      },\n      args: { disabled: false },\n    });\n\n    const Basic = meta.story({ args: { theme: 'light', label: 'good' } });\n  });\n\n  const withDecorator: Decorator<{ decoratorArg: string }> = (\n    storyFn,\n    { args: { decoratorArg } }\n  ) => h(DecoratorTsVue, { decoratorArg }, h(storyFn()));\n\n  it('Correct args are inferred when type is widened for decorators', () => {\n    type Props = ButtonProps & { decoratorArg: string };\n\n    const meta = preview.meta({\n      component: Button,\n      args: { disabled: false },\n      decorators: [withDecorator],\n    });\n\n    const Basic = meta.story({ args: { decoratorArg: 'title', label: 'good' } });\n  });\n\n  it('Correct args are inferred when type is widened for multiple decorators', () => {\n    type Props = ButtonProps & {\n      decoratorArg: string;\n      decoratorArg2: string;\n    };\n\n    const secondDecorator: Decorator<{ decoratorArg2: string }> = (\n      storyFn,\n      { args: { decoratorArg2 } }\n    ) => h(Decorator2TsVue, { decoratorArg2 }, h(storyFn()));\n\n    const meta = preview.meta({\n      component: Button,\n      args: { disabled: false },\n      decorators: [withDecorator, secondDecorator],\n    });\n\n    const Basic = meta.story({\n      args: { decoratorArg: '', decoratorArg2: '', label: 'good' },\n    });\n  });\n});\n\nit('Infer type of slots', () => {\n  const meta = preview.meta({\n    component: BaseLayout,\n  });\n\n  const Basic = meta.story({\n    args: {\n      otherProp: true,\n      header: ({ title }) =>\n        h({\n          components: { Button },\n          template: `<Button :primary='true' label='${title}'></Button>`,\n        }),\n      default: 'default slot',\n      footer: h(Button, { disabled: true, label: 'footer' }),\n    },\n  });\n});\n\nit('mount accepts a Component', () => {\n  const Basic: StoryObj<typeof Button> = {\n    async play({ mount }) {\n      const canvas = await mount(Button, { props: { label: 'label', disabled: true } });\n      expectTypeOf(canvas).toMatchTypeOf<Canvas>();\n    },\n  };\n});\n\nit('allow types to be inferred from render as well', () => {\n  const meta = preview.meta({\n    render: (args: ButtonProps) => ({\n      data: () => ({ args }),\n      template: `<Button v-bind=\"args\" />`,\n    }),\n    args: { label: 'hello' },\n  });\n\n  const Story = meta.story({\n    args: { disabled: true },\n  });\n});\n\ndescribe('Generic components (issue #24238)', () => {\n  // Generic Vue components with TypeScript generics work with CSF factories\n  // by passing the type parameter directly: GenericComponent<ConcreteType>\n  // See: https://github.com/storybookjs/storybook/issues/24238\n\n  it('✅ Generic components work by passing type parameter directly', () => {\n    const meta = preview.meta({\n      component: GenericComponent<{ id: number; name: string }>,\n    });\n\n    const Story = meta.story({\n      args: {\n        items: [\n          {\n            id: 1,\n            name: 'John Doe',\n          },\n        ],\n        getLabel: (item) => {\n          // item is correctly typed as { id: number; name: string }\n          expectTypeOf(item).toMatchObjectType<{ id: number; name: string }>();\n          return item.name;\n        },\n      },\n    });\n\n    // Verify the story has the correct args\n    expect(Story.input.args?.items).toHaveLength(1);\n  });\n});\n"
  },
  {
    "path": "code/renderers/vue3/src/decorateStory.ts",
    "content": "import type { DecoratorFunction, LegacyStoryFn, StoryContext } from 'storybook/internal/types';\n\nimport { sanitizeStoryContextUpdate } from 'storybook/preview-api';\nimport type { Component, ComponentOptions, ConcreteComponent } from 'vue';\nimport { h } from 'vue';\n\nimport type { VueRenderer } from './types.ts';\n\n/*\n  This normalizes a functional component into a render method in ComponentOptions.\n\n  The concept is taken from Vue 3's `defineComponent` but changed from creating a `setup`\n  method on the ComponentOptions so end-users don't need to specify a \"thunk\" as a decorator.\n */\n\nfunction normalizeFunctionalComponent(options: ConcreteComponent): ComponentOptions {\n  return typeof options === 'function' ? { render: options, name: options.name } : options;\n}\n\nfunction prepare(\n  rawStory: VueRenderer['storyResult'],\n  innerStory?: ConcreteComponent\n): Component | null {\n  const story = rawStory as ComponentOptions;\n  if (story === null) {\n    return null;\n  }\n\n  if (typeof story === 'function') {\n    return story;\n  } // we don't need to wrap a functional component nor to convert it to a component options // we don't need to wrap a functional component nor to convert it to a component options\n  if (innerStory) {\n    return {\n      // Normalize so we can always spread an object\n      ...normalizeFunctionalComponent(story),\n      components: { ...(story.components || {}), story: innerStory },\n    };\n  }\n\n  return {\n    render() {\n      return h(story);\n    },\n  };\n}\n\nexport function decorateStory(\n  storyFn: LegacyStoryFn<VueRenderer>,\n  decorators: DecoratorFunction<VueRenderer>[]\n): LegacyStoryFn<VueRenderer> {\n  return decorators.reduce(\n    (decorated: LegacyStoryFn<VueRenderer>, decorator) => (context: StoryContext<VueRenderer>) => {\n      let story: VueRenderer['storyResult'] | undefined;\n\n      const decoratedStory: VueRenderer['storyResult'] = decorator((update) => {\n        const sanitizedUpdate = sanitizeStoryContextUpdate(update);\n        // update the args in a reactive way\n\n        // update the args in a reactive way\n        if (update) {\n          sanitizedUpdate.args = Object.assign(context.args, sanitizedUpdate.args);\n        }\n        story = decorated({ ...context, ...sanitizedUpdate });\n        return story;\n      }, context);\n\n      if (!story) {\n        story = decorated(context);\n      }\n\n      if (decoratedStory === story) {\n        return story;\n      }\n\n      const innerStory = () => h(story!);\n      return prepare(decoratedStory, innerStory) as VueRenderer['storyResult'];\n    },\n    (context) => prepare(storyFn(context)) as LegacyStoryFn<VueRenderer>\n  );\n}\n"
  },
  {
    "path": "code/renderers/vue3/src/docs/__snapshots__/extractArgTypes.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`extractArgTypes (vue-docgen-api) > should extract events for Vue component 1`] = `\n{\n  \"bar\": {\n    \"control\": {\n      \"disable\": true,\n    },\n    \"description\": \"\",\n    \"name\": \"bar\",\n    \"table\": {\n      \"category\": \"events\",\n      \"type\": {\n        \"summary\": \"[value: { year: number; title?: any; }]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"value\": \"[value: { year: number; title?: any; }]\",\n    },\n  },\n  \"baz\": {\n    \"control\": {\n      \"disable\": true,\n    },\n    \"description\": \"\",\n    \"name\": \"baz\",\n    \"table\": {\n      \"category\": \"events\",\n      \"type\": {\n        \"summary\": \"[]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"value\": \"[]\",\n    },\n  },\n  \"foo\": {\n    \"control\": {\n      \"disable\": true,\n    },\n    \"description\": \"\",\n    \"name\": \"foo\",\n    \"table\": {\n      \"category\": \"events\",\n      \"type\": {\n        \"summary\": \"[data?: { foo: string; }]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"value\": \"[data?: { foo: string; } | undefined]\",\n    },\n  },\n}\n`;\n\nexports[`extractArgTypes (vue-docgen-api) > should extract events for component 1`] = `\n{\n  \"bar\": {\n    \"control\": {\n      \"disable\": true,\n    },\n    \"description\": \"Test description bar\",\n    \"name\": \"bar\",\n    \"table\": {\n      \"category\": \"events\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"{ year: number; title?: any }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"{ year: number; title?: any }\",\n    },\n  },\n  \"baz\": {\n    \"control\": {\n      \"disable\": true,\n    },\n    \"description\": \"Test description baz\",\n    \"name\": \"baz\",\n    \"table\": {\n      \"category\": \"events\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": undefined,\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"\",\n    },\n  },\n}\n`;\n\nexports[`extractArgTypes (vue-docgen-api) > should extract expose for component 1`] = `\n{\n  \"count\": {\n    \"control\": {\n      \"disable\": true,\n    },\n    \"description\": \"a count number\",\n    \"name\": \"count\",\n    \"table\": {\n      \"category\": \"expose\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": undefined,\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"value\": \"\",\n    },\n  },\n  \"label\": {\n    \"control\": {\n      \"disable\": true,\n    },\n    \"description\": \"a label string\",\n    \"name\": \"label\",\n    \"table\": {\n      \"category\": \"expose\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": undefined,\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"value\": \"\",\n    },\n  },\n}\n`;\n\nexports[`extractArgTypes (vue-docgen-api) > should extract props for component 1`] = `\n{\n  \"array\": {\n    \"defaultValue\": undefined,\n    \"description\": \"description required array object\",\n    \"name\": \"array\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedProps[]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"array\",\n      \"required\": true,\n      \"value\": {\n        \"name\": \"object\",\n        \"required\": false,\n        \"value\": {},\n      },\n    },\n  },\n  \"arrayOptional\": {\n    \"defaultValue\": undefined,\n    \"description\": \"description optional array object\",\n    \"name\": \"arrayOptional\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedProps[]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"array\",\n      \"required\": false,\n      \"value\": {\n        \"name\": \"object\",\n        \"required\": false,\n        \"value\": {},\n      },\n    },\n  },\n  \"bar\": {\n    \"defaultValue\": {\n      \"summary\": \"1\",\n    },\n    \"description\": \"description bar is optional number\",\n    \"name\": \"bar\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": {\n        \"summary\": \"1\",\n      },\n      \"type\": {\n        \"summary\": \"number\",\n      },\n    },\n    \"type\": {\n      \"name\": \"number\",\n      \"required\": false,\n    },\n  },\n  \"baz\": {\n    \"defaultValue\": undefined,\n    \"description\": \"description baz is required boolean\",\n    \"name\": \"baz\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"boolean\",\n      },\n    },\n    \"type\": {\n      \"name\": \"boolean\",\n      \"required\": true,\n    },\n  },\n  \"enumValue\": {\n    \"defaultValue\": undefined,\n    \"description\": \"description enum value\",\n    \"name\": \"enumValue\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"MyEnum\",\n      },\n    },\n    \"type\": {\n      \"name\": \"enum\",\n      \"required\": true,\n      \"value\": [\n        \"MyEnum.Small\",\n        \"MyEnum.Medium\",\n        \"MyEnum.Large\",\n      ],\n    },\n  },\n  \"foo\": {\n    \"defaultValue\": undefined,\n    \"description\": \"@default: \"rounded\"<br>@since: v1.0.0<br>@see: https://vuejs.org/<br>@deprecated: v1.1.0<br><br>string foo\",\n    \"name\": \"foo\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"string\",\n      \"required\": true,\n    },\n  },\n  \"inlined\": {\n    \"defaultValue\": undefined,\n    \"description\": \"\",\n    \"name\": \"inlined\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"{ foo: string; }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"object\",\n      \"required\": true,\n      \"value\": {},\n    },\n  },\n  \"literalFromContext\": {\n    \"defaultValue\": undefined,\n    \"description\": \"description literal type alias that require context\",\n    \"name\": \"literalFromContext\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"\"Uncategorized\" | \"Content\" | \"Interaction\" | \"Display\" | \"Forms\" | \"Addons\"\",\n      },\n    },\n    \"type\": {\n      \"name\": \"enum\",\n      \"required\": true,\n      \"value\": [\n        \"Uncategorized\",\n        \"Content\",\n        \"Interaction\",\n        \"Display\",\n        \"Forms\",\n        \"Addons\",\n      ],\n    },\n  },\n  \"nested\": {\n    \"defaultValue\": undefined,\n    \"description\": \"description nested is required nested object\",\n    \"name\": \"nested\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedProps\",\n      },\n    },\n    \"type\": {\n      \"name\": \"object\",\n      \"required\": true,\n      \"value\": {},\n    },\n  },\n  \"nestedIntersection\": {\n    \"defaultValue\": undefined,\n    \"description\": \"description required nested object with intersection\",\n    \"name\": \"nestedIntersection\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedProps & { additionalProp: string; }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"object\",\n      \"required\": true,\n      \"value\": {},\n    },\n  },\n  \"nestedOptional\": {\n    \"defaultValue\": undefined,\n    \"description\": \"description optional nested object\",\n    \"name\": \"nestedOptional\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedProps | MyIgnoredNestedProps\",\n      },\n    },\n    \"type\": {\n      \"name\": \"union\",\n      \"required\": false,\n      \"value\": [\n        {\n          \"name\": \"object\",\n          \"required\": false,\n          \"value\": {},\n        },\n        {\n          \"name\": \"object\",\n          \"required\": false,\n          \"value\": {},\n        },\n      ],\n    },\n  },\n  \"recursive\": {\n    \"defaultValue\": undefined,\n    \"description\": \"\",\n    \"name\": \"recursive\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedRecursiveProps\",\n      },\n    },\n    \"type\": {\n      \"name\": \"object\",\n      \"required\": false,\n      \"value\": {},\n    },\n  },\n  \"stringArray\": {\n    \"defaultValue\": {\n      \"summary\": \"[\"foo\", \"bar\"]\",\n    },\n    \"description\": \"description stringArray is string array\",\n    \"name\": \"stringArray\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": {\n        \"summary\": \"[\"foo\", \"bar\"]\",\n      },\n      \"type\": {\n        \"summary\": \"string[]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"array\",\n      \"required\": false,\n      \"value\": {\n        \"name\": \"string\",\n        \"required\": false,\n      },\n    },\n  },\n  \"union\": {\n    \"defaultValue\": undefined,\n    \"description\": \"description union is required union type\",\n    \"name\": \"union\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"string | number\",\n      },\n    },\n    \"type\": {\n      \"name\": \"union\",\n      \"required\": true,\n      \"value\": [\n        {\n          \"name\": \"string\",\n          \"required\": false,\n        },\n        {\n          \"name\": \"number\",\n          \"required\": false,\n        },\n      ],\n    },\n  },\n  \"unionOptional\": {\n    \"defaultValue\": undefined,\n    \"description\": \"description unionOptional is optional union type\",\n    \"name\": \"unionOptional\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"type\": {\n        \"summary\": \"string | number | boolean\",\n      },\n    },\n    \"type\": {\n      \"name\": \"union\",\n      \"required\": false,\n      \"value\": [\n        {\n          \"name\": \"string\",\n          \"required\": false,\n        },\n        {\n          \"name\": \"number\",\n          \"required\": false,\n        },\n        {\n          \"name\": \"boolean\",\n          \"required\": false,\n        },\n      ],\n    },\n  },\n}\n`;\n\nexports[`extractArgTypes (vue-docgen-api) > should extract props for component 2`] = `\n{\n  \"array\": {\n    \"description\": \"description required array object\",\n    \"name\": \"array\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedProps[]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": true,\n      \"value\": \"Array([object Object])\",\n    },\n  },\n  \"arrayOptional\": {\n    \"description\": \"description optional array object\",\n    \"name\": \"arrayOptional\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedProps[]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"Array([object Object])\",\n    },\n  },\n  \"bar\": {\n    \"description\": \"description bar is optional number\",\n    \"name\": \"bar\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": {\n        \"summary\": \"1\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"number\",\n      },\n    },\n    \"type\": {\n      \"name\": \"number\",\n      \"required\": false,\n    },\n  },\n  \"baz\": {\n    \"description\": \"description baz is required boolean\",\n    \"name\": \"baz\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"boolean\",\n      },\n    },\n    \"type\": {\n      \"name\": \"boolean\",\n      \"required\": true,\n    },\n  },\n  \"enumValue\": {\n    \"description\": \"description enum value\",\n    \"name\": \"enumValue\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"MyEnum\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": true,\n      \"value\": \"MyEnum\",\n    },\n  },\n  \"foo\": {\n    \"description\": \"string foo\",\n    \"name\": \"foo\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"string\",\n      \"required\": true,\n    },\n  },\n  \"inlined\": {\n    \"description\": undefined,\n    \"name\": \"inlined\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"{ foo: string }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": true,\n      \"value\": \"{ foo: string }\",\n    },\n  },\n  \"literalFromContext\": {\n    \"description\": \"description literal type alias that require context\",\n    \"name\": \"literalFromContext\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"MyCategories\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": true,\n      \"value\": \"MyCategories\",\n    },\n  },\n  \"nested\": {\n    \"description\": \"description nested is required nested object\",\n    \"name\": \"nested\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedProps\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": true,\n      \"value\": \"MyNestedProps\",\n    },\n  },\n  \"nestedIntersection\": {\n    \"description\": \"description required nested object with intersection\",\n    \"name\": \"nestedIntersection\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedProps & {\n  /**\n   * description required additional property\n   */\n  additionalProp: string;\n}\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": true,\n      \"value\": \"intersection([object Object],[object Object])\",\n    },\n  },\n  \"nestedOptional\": {\n    \"description\": \"description optional nested object\",\n    \"name\": \"nestedOptional\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedProps | MyIgnoredNestedProps\",\n      },\n    },\n    \"type\": {\n      \"name\": \"union\",\n      \"required\": false,\n      \"value\": [\n        {\n          \"name\": \"other\",\n          \"value\": \"MyNestedProps\",\n        },\n        {\n          \"name\": \"other\",\n          \"value\": \"MyIgnoredNestedProps\",\n        },\n      ],\n    },\n  },\n  \"recursive\": {\n    \"description\": undefined,\n    \"name\": \"recursive\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"MyNestedRecursiveProps\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"MyNestedRecursiveProps\",\n    },\n  },\n  \"stringArray\": {\n    \"description\": \"description stringArray is string array\",\n    \"name\": \"stringArray\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": {\n        \"summary\": \"() => ['foo', 'bar']\",\n      },\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"string[]\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"Array([object Object])\",\n    },\n  },\n  \"union\": {\n    \"description\": \"description union is required union type\",\n    \"name\": \"union\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"string | number\",\n      },\n    },\n    \"type\": {\n      \"name\": \"union\",\n      \"required\": true,\n      \"value\": [\n        {\n          \"name\": \"string\",\n        },\n        {\n          \"name\": \"number\",\n        },\n      ],\n    },\n  },\n  \"unionOptional\": {\n    \"description\": \"description unionOptional is optional union type\",\n    \"name\": \"unionOptional\",\n    \"table\": {\n      \"category\": \"props\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"string | number | boolean\",\n      },\n    },\n    \"type\": {\n      \"name\": \"union\",\n      \"required\": false,\n      \"value\": [\n        {\n          \"name\": \"string\",\n        },\n        {\n          \"name\": \"number\",\n        },\n        {\n          \"name\": \"boolean\",\n        },\n      ],\n    },\n  },\n}\n`;\n\nexports[`extractArgTypes (vue-docgen-api) > should extract slots for component 1`] = `\n{\n  \"default\": {\n    \"description\": undefined,\n    \"name\": \"default\",\n    \"table\": {\n      \"category\": \"slots\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"{ num: unknown }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"{ num: unknown }\",\n    },\n  },\n  \"named\": {\n    \"description\": undefined,\n    \"name\": \"named\",\n    \"table\": {\n      \"category\": \"slots\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"{ str: unknown }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"{ str: unknown }\",\n    },\n  },\n  \"no-bind\": {\n    \"description\": undefined,\n    \"name\": \"no-bind\",\n    \"table\": {\n      \"category\": \"slots\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": undefined,\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"\",\n    },\n  },\n  \"vbind\": {\n    \"description\": undefined,\n    \"name\": \"vbind\",\n    \"table\": {\n      \"category\": \"slots\",\n      \"defaultValue\": undefined,\n      \"jsDocTags\": undefined,\n      \"type\": {\n        \"summary\": \"{ num: unknown; str: unknown }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"required\": false,\n      \"value\": \"{ num: unknown; str: unknown }\",\n    },\n  },\n}\n`;\n\nexports[`extractArgTypes (vue-docgen-api) > should extract slots type for Vue component 1`] = `\n{\n  \"default\": {\n    \"description\": \"\",\n    \"name\": \"default\",\n    \"table\": {\n      \"category\": \"slots\",\n      \"type\": {\n        \"summary\": \"{ num: number; }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"value\": \"{ num: number; }\",\n    },\n  },\n  \"named\": {\n    \"description\": \"\",\n    \"name\": \"named\",\n    \"table\": {\n      \"category\": \"slots\",\n      \"type\": {\n        \"summary\": \"{ str: string; }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"value\": \"{ str: string; }\",\n    },\n  },\n  \"no-bind\": {\n    \"description\": \"\",\n    \"name\": \"no-bind\",\n    \"table\": {\n      \"category\": \"slots\",\n      \"type\": {\n        \"summary\": \"{}\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"value\": \"{}\",\n    },\n  },\n  \"vbind\": {\n    \"description\": \"\",\n    \"name\": \"vbind\",\n    \"table\": {\n      \"category\": \"slots\",\n      \"type\": {\n        \"summary\": \"{ num: number; str: string; }\",\n      },\n    },\n    \"type\": {\n      \"name\": \"other\",\n      \"value\": \"{ num: number; str: string; }\",\n    },\n  },\n}\n`;\n"
  },
  {
    "path": "code/renderers/vue3/src/docs/sourceDecorator.test.ts",
    "content": "import { expect, test } from 'vitest';\n\nimport { h } from 'vue';\n\nimport type { SourceCodeGeneratorContext } from './sourceDecorator';\nimport {\n  generatePropsSourceCode,\n  generateSlotSourceCode,\n  generateSourceCode,\n  getFunctionParamNames,\n  parseDocgenInfo,\n} from './sourceDecorator';\n\ntest('should generate source code for props', () => {\n  const ctx: SourceCodeGeneratorContext = {\n    scriptVariables: {},\n    imports: {},\n  };\n\n  const code = generatePropsSourceCode(\n    {\n      a: 'foo',\n      b: '\"I am double quoted\"',\n      c: 42,\n      d: true,\n      e: false,\n      f: [1, 2, 3],\n      g: {\n        g1: 'foo',\n        g2: 42,\n      },\n      h: undefined,\n      i: null,\n      j: '',\n      k: BigInt(9007199254740991),\n      l: Symbol(),\n      m: Symbol('foo'),\n      modelValue: 'test-v-model',\n      otherModelValue: 42,\n      default: 'default slot',\n      testSlot: 'test slot',\n    },\n    ['default', 'testSlot'],\n    ['update:modelValue', 'update:otherModelValue'],\n    ctx\n  );\n\n  expect(code).toBe(\n    `a=\"foo\" b='\"I am double quoted\"' :c=\"42\" d :e=\"false\" :f=\"f\" :g=\"g\" :k=\"BigInt(9007199254740991)\" :l=\"Symbol()\" :m=\"Symbol('foo')\" v-model=\"modelValue\" v-model:otherModelValue=\"otherModelValue\"`\n  );\n\n  expect(ctx.scriptVariables).toStrictEqual({\n    f: `[1,2,3]`,\n    g: `{\"g1\":\"foo\",\"g2\":42}`,\n    modelValue: 'ref(\"test-v-model\")',\n    otherModelValue: 'ref(42)',\n  });\n\n  expect(Array.from(ctx.imports.vue.values())).toStrictEqual(['ref']);\n});\n\ntest('should generate source code for slots', () => {\n  // slot code generator should support primitive values (string, number etc.)\n  // but also VNodes (e.g. created using h()) so custom Vue components can also be used\n  // inside slots with proper generated code\n\n  const slots = {\n    default: 'default content',\n    a: 'a content',\n    b: 42,\n    c: true,\n    // single VNode without props\n    d: h('div', 'd content'),\n    // VNode with props and single child\n    e: h('div', { style: 'color:red' }, 'e content'),\n    // VNode with props and single child returned as getter\n    f: h('div', { style: 'color:red' }, () => 'f content'),\n    // VNode with multiple children\n    g: h('div', { style: 'color:red' }, [\n      'child 1',\n      h('span', { style: 'color:green' }, 'child 2'),\n    ]),\n    // VNode multiple children but returned as getter\n    h: h('div', { style: 'color:red' }, () => [\n      'child 1',\n      h('span', { style: 'color:green' }, 'child 2'),\n    ]),\n    // VNode with multiple and nested children\n    i: h('div', { style: 'color:red' }, [\n      'child 1',\n      h('span', { style: 'color:green' }, ['nested child 1', h('p', 'nested child 2')]),\n    ]),\n    j: ['child 1', 'child 2'],\n    k: null,\n    l: { foo: 'bar' },\n    m: BigInt(9007199254740991),\n  };\n\n  const expectedCode = `default content\n\n<template #a>a content</template>\n\n<template #b>42</template>\n\n<template #c>true</template>\n\n<template #d><div>d content</div></template>\n\n<template #e><div style=\"color:red\">e content</div></template>\n\n<template #f><div style=\"color:red\">f content</div></template>\n\n<template #g><div style=\"color:red\">child 1\n<span style=\"color:green\">child 2</span></div></template>\n\n<template #h><div style=\"color:red\">child 1\n<span style=\"color:green\">child 2</span></div></template>\n\n<template #i><div style=\"color:red\">child 1\n<span style=\"color:green\">nested child 1\n<p>nested child 2</p></span></div></template>\n\n<template #j>child 1\nchild 2</template>\n\n<template #l>{\"foo\":\"bar\"}</template>\n\n<template #m>{{ BigInt(9007199254740991) }}</template>`;\n\n  let actualCode = generateSlotSourceCode(slots, Object.keys(slots), {\n    scriptVariables: {},\n    imports: {},\n  });\n  expect(actualCode).toBe(expectedCode);\n\n  // should generate the same code if getters/functions are used to return the slot content\n  const slotsWithGetters = Object.entries(slots).reduce<\n    Record<string, () => (typeof slots)[keyof typeof slots]>\n  >((obj, [slotName, value]) => {\n    obj[slotName] = () => value;\n    return obj;\n  }, {});\n\n  actualCode = generateSlotSourceCode(slotsWithGetters, Object.keys(slotsWithGetters), {\n    scriptVariables: {},\n    imports: {},\n  });\n  expect(actualCode).toBe(expectedCode);\n});\n\ntest('should generate source code for slots with bindings', () => {\n  type TestBindings = {\n    foo: string;\n    bar?: number;\n    boo: {\n      mimeType: string;\n    };\n  };\n\n  const slots = {\n    a: ({ foo, bar, boo }: TestBindings) => `Slot with bindings ${foo}, ${bar} and ${boo.mimeType}`,\n    b: ({ foo, boo }: TestBindings) =>\n      h('a', { href: foo, target: foo, type: boo.mimeType, ...boo }, `Test link: ${foo}`),\n  };\n\n  const expectedCode = `<template #a=\"{ foo, bar, boo }\">Slot with bindings {{ foo }}, {{ bar }} and {{ boo.mimeType }}</template>\n\n<template #b=\"{ foo, boo }\"><a :href=\"foo\" :target=\"foo\" :type=\"boo.mimeType\" v-bind=\"boo\">Test link: {{ foo }}</a></template>`;\n\n  const actualCode = generateSlotSourceCode(slots, Object.keys(slots), {\n    imports: {},\n    scriptVariables: {},\n  });\n  expect(actualCode).toBe(expectedCode);\n});\n\ntest('should generate source code with <script setup> block', () => {\n  const actualCode = generateSourceCode({\n    title: 'MyComponent',\n    component: {\n      __docgenInfo: {\n        slots: [{ name: 'mySlot' }],\n        events: [{ name: 'update:c' }],\n      },\n    },\n    args: {\n      a: 42,\n      b: 'foo',\n      c: [1, 2, 3],\n      d: { bar: 'baz' },\n      mySlot: () => h('div', { test: [1, 2], d: { nestedProp: 'foo' } }),\n    },\n  });\n\n  expect(actualCode).toBe(`<script lang=\"ts\" setup>\nimport { ref } from \"vue\";\n\nconst c = ref([1,2,3]);\n\nconst d = {\"bar\":\"baz\"};\n\nconst d1 = {\"nestedProp\":\"foo\"};\n\nconst test = [1,2];\n</script>\n\n<template>\n  <MyComponent :a=\"42\" b=\"foo\" v-model:c=\"c\" :d=\"d\"> <template #mySlot><div :d=\"d1\" :test=\"test\" /></template> </MyComponent>\n</template>`);\n});\n\ntest.each([\n  { __docgenInfo: 'invalid-value', slotNames: [] },\n  { __docgenInfo: {}, slotNames: [] },\n  { __docgenInfo: { slots: 'invalid-value' }, slotNames: [] },\n  { __docgenInfo: { slots: ['invalid-value'] }, slotNames: [] },\n  {\n    __docgenInfo: { slots: [{ name: 'slot-1' }, { name: 'slot-2' }, { notName: 'slot-3' }] },\n    slotNames: ['slot-1', 'slot-2'],\n  },\n])('should parse slots names from __docgenInfo', ({ __docgenInfo, slotNames }) => {\n  const docgenInfo = parseDocgenInfo({ __docgenInfo });\n  expect(docgenInfo.slotNames).toStrictEqual(slotNames);\n});\n\ntest.each([\n  { __docgenInfo: 'invalid-value', eventNames: [] },\n  { __docgenInfo: {}, eventNames: [] },\n  { __docgenInfo: { events: 'invalid-value' }, eventNames: [] },\n  { __docgenInfo: { events: ['invalid-value'] }, eventNames: [] },\n  {\n    __docgenInfo: { events: [{ name: 'event-1' }, { name: 'event-2' }, { notName: 'event-3' }] },\n    eventNames: ['event-1', 'event-2'],\n  },\n])('should parse event names from __docgenInfo', ({ __docgenInfo, eventNames }) => {\n  const docgenInfo = parseDocgenInfo({ __docgenInfo });\n  expect(docgenInfo.eventNames).toStrictEqual(eventNames);\n});\n\ntest.each<{ fn: (...args: any[]) => unknown; expectedNames: string[] }>([\n  { fn: () => ({}), expectedNames: [] },\n  { fn: (a) => ({}), expectedNames: ['a'] },\n  { fn: (a, b) => ({}), expectedNames: ['a', 'b'] },\n  { fn: (a, b, { c }) => ({}), expectedNames: ['a', 'b', '{', 'c', '}'] },\n  { fn: ({ a, b }) => ({}), expectedNames: ['{', 'a', 'b', '}'] },\n  {\n    fn: {\n      // simulate minified function after running \"storybook build\"\n      toString: () => '({a:foo,b:bar})=>({})',\n    } as (...args: any[]) => unknown,\n    expectedNames: ['{', 'a', 'b', '}'],\n  },\n])('should extract function parameter names', ({ fn, expectedNames }) => {\n  const paramNames = getFunctionParamNames(fn);\n  expect(paramNames).toStrictEqual(expectedNames);\n});\n"
  },
  {
    "path": "code/renderers/vue3/src/docs/sourceDecorator.ts",
    "content": "import { SourceType } from 'storybook/internal/docs-tools';\n\nimport { emitTransformCode, useEffect, useRef } from 'storybook/preview-api';\nimport type { VNode } from 'vue';\nimport { isVNode } from 'vue';\n\nimport type { Args, Decorator, StoryContext } from '../public-types';\n\n/**\n * Context that is passed down to nested components/slots when generating the source code for a\n * single story.\n */\nexport type SourceCodeGeneratorContext = {\n  /**\n   * Properties/variables that should be placed inside a `<script lang=\"ts\" setup>` block. Usually\n   * contains complex property values like objects and arrays.\n   */\n  scriptVariables: Record<string, string>;\n  /**\n   * Optional imports to add inside the `<script lang=\"ts\" setup>` block. e.g. to add 'import { ref\n   * } from \"vue\";'\n   *\n   * Key = package name, values = imports\n   */\n  imports: Record<string, Set<string>>;\n};\n\n/**\n * Used to get the tracking data from the proxy. A symbol is unique, so when using it as a key it\n * can't be accidentally accessed.\n */\nconst TRACKING_SYMBOL = Symbol('DEEP_ACCESS_SYMBOL');\n\ntype TrackingProxy = {\n  [TRACKING_SYMBOL]: true;\n  toString: () => string;\n};\n\nconst isProxy = (obj: unknown): obj is TrackingProxy =>\n  !!(obj && typeof obj === 'object' && TRACKING_SYMBOL in obj);\n\n/** Decorator to generate Vue source code for stories. */\nexport const sourceDecorator: Decorator = (storyFn, ctx) => {\n  const story = storyFn();\n\n  useEffect(() => {\n    const sourceCode = generateSourceCode(ctx);\n\n    if (shouldSkipSourceCodeGeneration(ctx)) {\n      return;\n    }\n\n    emitTransformCode(sourceCode, ctx);\n  });\n\n  return story;\n};\n\n/**\n * Generate Vue source code for the given Story.\n *\n * @returns Source code or empty string if source code could not be generated.\n */\nexport const generateSourceCode = (\n  ctx: Pick<StoryContext, 'title' | 'component' | 'args'> & {\n    component?: StoryContext['component'] & { __docgenInfo?: unknown };\n  }\n): string => {\n  const sourceCodeContext: SourceCodeGeneratorContext = {\n    imports: {},\n    scriptVariables: {},\n  };\n\n  const { displayName, slotNames, eventNames } = parseDocgenInfo(ctx.component);\n\n  const props = generatePropsSourceCode(ctx.args, slotNames, eventNames, sourceCodeContext);\n  const slotSourceCode = generateSlotSourceCode(ctx.args, slotNames, sourceCodeContext);\n  const componentName = displayName || ctx.title.split('/').at(-1)!;\n\n  // prefer self closing tag if no slot content exists\n  const templateCode = slotSourceCode\n    ? `<${componentName} ${props}> ${slotSourceCode} </${componentName}>`\n    : `<${componentName} ${props} />`;\n\n  const variablesCode = Object.entries(sourceCodeContext.scriptVariables)\n    .map(([name, value]) => `const ${name} = ${value};`)\n    .join('\\n\\n');\n\n  const importsCode = Object.entries(sourceCodeContext.imports)\n    .map(([packageName, imports]) => {\n      return `import { ${Array.from(imports.values()).sort().join(', ')} } from \"${packageName}\";`;\n    })\n    .join('\\n');\n\n  const template = `<template>\\n  ${templateCode}\\n</template>`;\n\n  if (!importsCode && !variablesCode) {\n    return template;\n  }\n\n  return `<script lang=\"ts\" setup>\n${importsCode ? `${importsCode}\\n\\n${variablesCode}` : variablesCode}\n</script>\n\n${template}`;\n};\n\n/**\n * Checks if the source code generation should be skipped for the given Story context. Will be true\n * if one of the following is true:\n *\n * - Story is no arg story\n * - Story has set custom source code via parameters.docs.source.code\n * - Story has set source type to \"code\" via parameters.docs.source.type\n */\nexport const shouldSkipSourceCodeGeneration = (context: StoryContext): boolean => {\n  const sourceParams = context?.parameters.docs?.source;\n  if (sourceParams?.type === SourceType.DYNAMIC) {\n    // always render if the user forces it\n    return false;\n  }\n\n  const isArgsStory = context?.parameters.__isArgsStory;\n\n  // never render if the user is forcing the block to render code, or\n  // if the user provides code, or if it's not an args story.\n  return !isArgsStory || sourceParams?.code || sourceParams?.type === SourceType.CODE;\n};\n\n/**\n * Parses the __docgenInfo of the given component. Requires Storybook docs addon to be enabled.\n * Default slot will always be sorted first, remaining slots are sorted alphabetically.\n */\nexport const parseDocgenInfo = (\n  component?: StoryContext['component'] & { __docgenInfo?: unknown }\n) => {\n  // type check __docgenInfo to prevent errors\n  if (\n    !component ||\n    !('__docgenInfo' in component) ||\n    !component.__docgenInfo ||\n    typeof component.__docgenInfo !== 'object'\n  ) {\n    return {\n      displayName: component?.__name,\n      eventNames: [],\n      slotNames: [],\n    };\n  }\n\n  const docgenInfo = component.__docgenInfo as Record<string, unknown>;\n\n  const displayName =\n    'displayName' in docgenInfo && typeof docgenInfo.displayName === 'string'\n      ? docgenInfo.displayName\n      : undefined;\n\n  const parseNames = (key: 'slots' | 'events') => {\n    if (!(key in docgenInfo) || !Array.isArray(docgenInfo[key])) {\n      return [];\n    }\n\n    const values = docgenInfo[key] as unknown[];\n\n    return values\n      .map((i) => (i && typeof i === 'object' && 'name' in i ? i.name : undefined))\n      .filter((i): i is string => typeof i === 'string');\n  };\n\n  return {\n    displayName: displayName || component.__name,\n    slotNames: parseNames('slots').sort((a, b) => {\n      if (a === 'default') {\n        return -1;\n      }\n\n      if (b === 'default') {\n        return 1;\n      }\n      return a.localeCompare(b);\n    }),\n    eventNames: parseNames('events'),\n  };\n};\n\n/**\n * Generates the source code for the given Vue component properties. Props with complex values\n * (objects and arrays) and v-models will be added to the ctx.scriptVariables because they should be\n * generated in a `<script lang=\"ts\" setup>` block.\n *\n * @example `:a=\"42\" b=\"Hello World\" v-model=\"modelValue\" v-model:search=\"search\"`\n *\n * @param args Story args / property values.\n * @param slotNames All slot names of the component. Needed to not generate code for args that are\n *   slots. Can be extracted using `parseDocgenInfo()`.\n * @param eventNames All event names of the component. Needed to generate v-model properties. Can be\n *   extracted using `parseDocgenInfo()`.\n */\nexport const generatePropsSourceCode = (\n  args: Record<string, unknown>,\n  slotNames: string[],\n  eventNames: string[],\n  ctx: SourceCodeGeneratorContext\n) => {\n  type Property = {\n    /** Property name */\n    name: string;\n    /** Stringified property value */\n    value: string;\n    /**\n     * Function that returns the source code when used inside the `<template>`. If unset, the\n     * property will be generated inside the `<script lang=\"ts\" setup>` block.\n     */\n    templateFn?: (name: string, value: string) => string;\n  };\n\n  const properties: Property[] = [];\n\n  Object.entries(args).forEach(([propName, value]) => {\n    // ignore slots\n\n    // ignore slots\n    if (slotNames.includes(propName)) {\n      return;\n    }\n\n    if (value == undefined) {\n      return;\n    } // do not render undefined/null values // do not render undefined/null values\n\n    if (isProxy(value)) {\n      value = value.toString();\n    }\n\n    switch (typeof value) {\n      case 'string':\n        if (value === '') {\n          return;\n        } // do not render empty strings // do not render empty strings\n\n        properties.push({\n          name: propName,\n          value: value.includes('\"') ? `'${value}'` : `\"${value}\"`,\n          templateFn: (name, propValue) => `${name}=${propValue}`,\n        });\n        break;\n      case 'number':\n        properties.push({\n          name: propName,\n          value: value.toString(),\n          templateFn: (name, propValue) => `:${name}=\"${propValue}\"`,\n        });\n        break;\n      case 'bigint':\n        properties.push({\n          name: propName,\n          value: `BigInt(${value.toString()})`,\n          templateFn: (name, propValue) => `:${name}=\"${propValue}\"`,\n        });\n        break;\n      case 'boolean':\n        properties.push({\n          name: propName,\n          value: value ? 'true' : 'false',\n          templateFn: (name, propValue) => (propValue === 'true' ? name : `:${name}=\"false\"`),\n        });\n        break;\n      case 'symbol':\n        properties.push({\n          name: propName,\n          value: `Symbol(${value.description ? `'${value.description}'` : ''})`,\n          templateFn: (name, propValue) => `:${name}=\"${propValue}\"`,\n        });\n        break;\n      case 'object': {\n        properties.push({\n          name: propName,\n          value: formatObject(value ?? {}),\n          // to follow Vue best practices, complex values like object and arrays are\n          // usually placed inside the <script setup> block instead of inlining them in the <template>\n          templateFn: undefined,\n        });\n        break;\n      }\n      case 'function':\n        // TODO: check if functions should be rendered in source code\n        break;\n    }\n  });\n\n  properties.sort((a, b) => a.name.localeCompare(b.name));\n\n  /** List of generated source code for the props. */\n  const props: string[] = [];\n\n  // now that we have all props parsed, we will generate them either inside the `<script lang=\"ts\" setup>` block\n  // or inside the `<template>`.\n  // we also make sure to render v-model properties accordingly (see https://vuejs.org/guide/components/v-model)\n  properties.forEach((prop) => {\n    const isVModel = eventNames.includes(`update:${prop.name}`);\n\n    if (!isVModel && prop.templateFn) {\n      props.push(prop.templateFn(prop.name, prop.value));\n      return;\n    }\n\n    let variableName = prop.name;\n\n    // a variable with the same name might already exist (e.g. from a parent component)\n    // so we need to make sure to use a unique name here to not generate multiple variables with the same name\n    if (variableName in ctx.scriptVariables) {\n      let index = 1;\n      do {\n        variableName = `${prop.name}${index}`;\n        index++;\n      } while (variableName in ctx.scriptVariables);\n    }\n\n    if (!isVModel) {\n      ctx.scriptVariables[variableName] = prop.value;\n      props.push(`:${prop.name}=\"${variableName}\"`);\n      return;\n    }\n\n    // always generate v-models inside the `<script lang=\"ts\" setup>` block\n    ctx.scriptVariables[variableName] = `ref(${prop.value})`;\n\n    if (!ctx.imports.vue) {\n      ctx.imports.vue = new Set();\n    }\n    ctx.imports.vue.add('ref');\n\n    if (prop.name === 'modelValue') {\n      props.push(`v-model=\"${variableName}\"`);\n    } else {\n      props.push(`v-model:${prop.name}=\"${variableName}\"`);\n    }\n  });\n\n  return props.join(' ');\n};\n\n/**\n * Generates the source code for the given Vue component slots. Supports primitive slot content\n * (e.g. strings, numbers etc.) and nested components/VNodes (e.g. created using Vue's `h()`\n * function).\n *\n * @example `<template #slotName=\"{ foo }\">Content {{ foo }}</template>`\n *\n * @param args Story args.\n * @param slotNames All slot names of the component. Needed to only generate slots and ignore props\n *   etc. Can be extracted using `parseDocgenInfo()`.\n * @param ctx Context so complex props of nested slot children will be set in the\n *   ctx.scriptVariables.\n */\nexport const generateSlotSourceCode = (\n  args: Args,\n  slotNames: string[],\n  ctx: SourceCodeGeneratorContext\n): string => {\n  /** List of slot source codes (e.g. <template #slotName>Content</template>) */\n  const slotSourceCodes: string[] = [];\n\n  slotNames.forEach((slotName) => {\n    const arg = args[slotName];\n\n    if (!arg) {\n      return;\n    }\n\n    const slotContent = generateSlotChildrenSourceCode([arg], ctx);\n\n    if (!slotContent) {\n      return;\n    } // do not generate source code for empty slots // do not generate source code for empty slots\n\n    const slotBindings = typeof arg === 'function' ? getFunctionParamNames(arg) : [];\n\n    if (slotName === 'default' && !slotBindings.length) {\n      // do not add unnecessary \"<template #default>\" tag since the default slot content without bindings\n      // can be put directly into the slot without need of \"<template #default>\"\n      slotSourceCodes.push(slotContent);\n    } else {\n      slotSourceCodes.push(\n        `<template ${slotBindingsToString(slotName, slotBindings)}>${slotContent}</template>`\n      );\n    }\n  });\n\n  return slotSourceCodes.join('\\n\\n');\n};\n\n/**\n * Generates the source code for the given slot children (the code inside <template\n * #slotName></template>).\n */\nconst generateSlotChildrenSourceCode = (\n  children: unknown[],\n  ctx: SourceCodeGeneratorContext\n): string => {\n  const slotChildrenSourceCodes: string[] = [];\n\n  /**\n   * Recursively generates the source code for a single slot child and all its children.\n   *\n   * @returns Source code for child and all nested children or empty string if child is of a\n   *   non-supported type.\n   */\n  const generateSingleChildSourceCode = (child: unknown): string => {\n    if (isVNode(child)) {\n      return generateVNodeSourceCode(child, ctx);\n    }\n\n    switch (typeof child) {\n      case 'string':\n      case 'number':\n      case 'boolean':\n        return child.toString();\n\n      case 'object':\n        if (child === null) {\n          return '';\n        }\n        if (Array.isArray(child)) {\n          // if child also has children, we generate them recursively\n          return child\n            .map(generateSingleChildSourceCode)\n            .filter((code) => code !== '')\n            .join('\\n');\n        }\n        return JSON.stringify(child);\n\n      case 'function': {\n        const paramNames = getFunctionParamNames(child).filter(\n          (param) => !['{', '}'].includes(param)\n        );\n\n        // We create proxy to track how and which properties of a parameter are accessed\n        const parameters: Record<string, string> = {};\n        // TODO: it should be possible to extend the proxy logic here and maybe get rid of the `generatePropsSourceCode` and `getFunctionParamNames`\n        const proxied: Record<string, TrackingProxy> = {};\n        paramNames.forEach((param) => {\n          parameters[param] = `{{ ${param} }}`;\n          proxied[param] = new Proxy(\n            {\n              // we use the symbol to identify the proxy\n              [TRACKING_SYMBOL]: true,\n            } as TrackingProxy,\n            {\n              // getter is called when any prop of the parameter is read\n              get: (t, key) => {\n                if (key === TRACKING_SYMBOL) {\n                  // allow retrieval of the tracking data\n                  return t[TRACKING_SYMBOL];\n                }\n                if ([Symbol.toPrimitive, Symbol.toStringTag, 'toString'].includes(key)) {\n                  // when the parameter is used as a string we return the parameter name\n                  // we use the double brace notation as we don't know if the parameter is used in text or in a binding\n                  return () => `{{ ${param} }}`;\n                }\n                if (key === 'v-bind') {\n                  // if this key is returned we just return the parameter name\n                  return `${param}`;\n                }\n                // otherwise a specific key of the parameter was accessed\n                // we use the double brace notation as we don't know if the parameter is used in text or in a binding\n                return `{{ ${param}.${key.toString()} }}`;\n              },\n              // ownKeys is called, among other uses, when an object is destructured\n              // in this case we assume the parameter is supposed to be bound using \"v-bind\"\n              // Therefore we only return one special key \"v-bind\" and the getter will be called afterwards with it\n              ownKeys: () => {\n                return [`v-bind`];\n              },\n              /** Called when destructured */\n              getOwnPropertyDescriptor: () => ({\n                configurable: true,\n                enumerable: true,\n                value: param,\n                writable: true,\n              }),\n            }\n          );\n        });\n\n        const returnValue = child(proxied);\n        const slotSourceCode = generateSlotChildrenSourceCode([returnValue], ctx);\n\n        // if slot bindings are used for properties of other components, our {{ paramName }} is incorrect because\n        // it would generate e.g. my-prop=\"{{ paramName }}\", therefore, we replace it here to e.g. :my-prop=\"paramName\"\n        return slotSourceCode.replaceAll(/ (\\S+)=\"{{ (\\S+) }}\"/g, ` :$1=\"$2\"`);\n      }\n\n      case 'bigint':\n        return `{{ BigInt(${child.toString()}) }}`;\n\n      // the only missing case here is \"symbol\"\n      // because rendering a symbol as slot / HTML does not make sense and is not supported by Vue\n      default:\n        return '';\n    }\n  };\n\n  children.forEach((child) => {\n    const sourceCode = generateSingleChildSourceCode(child);\n\n    if (sourceCode !== '') {\n      slotChildrenSourceCodes.push(sourceCode);\n    }\n  });\n\n  return slotChildrenSourceCodes.join('\\n');\n};\n\n/**\n * Generates source code for the given VNode and all its children (e.g. created using\n * `h(MyComponent)` or `h(\"div\")`).\n */\nconst generateVNodeSourceCode = (vnode: VNode, ctx: SourceCodeGeneratorContext): string => {\n  const componentName = getVNodeName(vnode);\n  let childrenCode = '';\n\n  if (typeof vnode.children === 'string') {\n    childrenCode = vnode.children;\n  } else if (Array.isArray(vnode.children)) {\n    childrenCode = generateSlotChildrenSourceCode(vnode.children, ctx);\n  } else if (vnode.children) {\n    // children are an object, just like if regular Story args where used\n    // so we can generate the source code with the regular \"generateSlotSourceCode()\".\n    childrenCode = generateSlotSourceCode(\n      vnode.children,\n      // $stable is a default property in vnode.children so we need to filter it out\n      // to not generate source code for it\n      Object.keys(vnode.children).filter((i) => i !== '$stable'),\n      ctx\n    );\n  }\n\n  const props = vnode.props ? generatePropsSourceCode(vnode.props, [], [], ctx) : '';\n\n  // prefer self closing tag if no children exist\n  if (childrenCode) {\n    return `<${componentName}${props ? ` ${props}` : ''}>${childrenCode}</${componentName}>`;\n  }\n  return `<${componentName}${props ? ` ${props}` : ''} />`;\n};\n\n/**\n * Gets the name for the given VNode. Will return \"component\" if name could not be extracted.\n *\n * @example `div` for `h(\"div\")` or \"MyComponent\" for `h(MyComponent)`\n */\nconst getVNodeName = (vnode: VNode) => {\n  // this is e.g. the case when rendering native HTML elements like, h(\"div\")\n\n  // this is e.g. the case when rendering native HTML elements like, h(\"div\")\n  if (typeof vnode.type === 'string') {\n    return vnode.type;\n  }\n\n  if (typeof vnode.type === 'object') {\n    // this is the case when using custom Vue components like h(MyComponent)\n    if ('name' in vnode.type && vnode.type.name) {\n      // prefer custom component name set by the developer\n      return vnode.type.name;\n    } else if ('__name' in vnode.type && vnode.type.__name) {\n      // otherwise use name inferred by Vue from the file name\n      return vnode.type.__name;\n    }\n  }\n\n  return 'component';\n};\n\n/**\n * Gets a list of parameters for the given function since func.arguments can not be used since it\n * throws a TypeError.\n *\n * If the arguments are destructured (e.g. \"func({ foo, bar })\"), the returned array will also\n * include \"{\" and \"}\".\n *\n * @see Based on https://stackoverflow.com/a/9924463\n */\nexport const getFunctionParamNames = (func: Function): string[] => {\n  const STRIP_COMMENTS = /((\\/\\/.*$)|(\\/\\*[\\s\\S]*?\\*\\/))/gm;\n  const ARGUMENT_NAMES = /([^\\s,]+)/g;\n\n  const fnStr = func.toString().replace(STRIP_COMMENTS, '');\n  const result = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);\n\n  if (!result) {\n    return [];\n  }\n\n  // when running \"storybook build\", the function will be minified, so result for e.g.\n  // `({ foo, bar }) => { // function body }` will be `[\"{foo:e\", \"bar:a}\"]`\n  // therefore we need to remove the :e and :a mappings and extract the \"{\" and \"}\"\" from the destructured object\n  // so the final result becomes `[\"{\", \"foo\", \"bar\", \"}\"]`\n\n  // when running \"storybook build\", the function will be minified, so result for e.g.\n  // `({ foo, bar }) => { // function body }` will be `[\"{foo:e\", \"bar:a}\"]`\n  // therefore we need to remove the :e and :a mappings and extract the \"{\" and \"}\"\" from the destructured object\n  // so the final result becomes `[\"{\", \"foo\", \"bar\", \"}\"]`\n  return result.flatMap((param) => {\n    if (['{', '}'].includes(param)) {\n      return param;\n    }\n    const nonMinifiedName = param.split(':')[0].trim();\n    if (nonMinifiedName.startsWith('{')) {\n      return ['{', nonMinifiedName.substring(1)];\n    }\n    if (param.endsWith('}') && !nonMinifiedName.endsWith('}')) {\n      return [nonMinifiedName, '}'];\n    }\n    return nonMinifiedName;\n  });\n};\n\n/**\n * Converts the given slot bindings/parameters to a string.\n *\n * @example\n *\n * ```\n * If no params: '#slotName'\n * If params: '#slotName=\"{ foo, bar }\"'\n * ```\n */\nconst slotBindingsToString = (\n  slotName: string,\n  params: string[]\n): `#${string}` | `#${string}=\"${string}\"` => {\n  if (!params.length) {\n    return `#${slotName}`;\n  }\n\n  if (params.length === 1) {\n    return `#${slotName}=\"${params[0]}\"`;\n  }\n\n  // parameters might be destructured so remove duplicated brackets here\n\n  // parameters might be destructured so remove duplicated brackets here\n  return `#${slotName}=\"{ ${params.filter((i) => !['{', '}'].includes(i)).join(', ')} }\"`;\n};\n\n/**\n * Formats the given object as string. Will format in single line if it only contains non-object\n * values. Otherwise will format multiline.\n */\nexport const formatObject = (obj: object): string => {\n  const isPrimitive = Object.values(obj).every(\n    (value) => value == null || typeof value !== 'object'\n  );\n\n  // if object/array only contains non-object values, we format all values in one line\n\n  // if object/array only contains non-object values, we format all values in one line\n  if (isPrimitive) {\n    return JSON.stringify(obj);\n  }\n\n  // otherwise, we use a \"pretty\" formatting with newlines and spaces\n\n  // otherwise, we use a \"pretty\" formatting with newlines and spaces\n  return JSON.stringify(obj, null, 2);\n};\n"
  },
  {
    "path": "code/renderers/vue3/src/docs/tests-meta-components/meta-components.ts",
    "content": "import { TypeSystem } from 'storybook/internal/docs-tools';\n\nimport type { VueDocgenInfo } from '../../../../../frameworks/vue3-vite/src';\n\ntype TestComponent = { __docgenInfo: VueDocgenInfo<'vue-component-meta'> };\n\nexport const referenceTypeProps: TestComponent = {\n  __docgenInfo: {\n    type: 1,\n    props: [\n      {\n        name: 'bar',\n        global: false,\n        description: 'description bar is optional number',\n        tags: [],\n        required: false,\n        type: 'number | undefined',\n        declarations: [],\n        schema: {\n          kind: 'enum',\n          type: 'number | undefined',\n          schema: ['undefined', 'number'],\n        },\n        default: '1',\n      },\n      {\n        name: 'stringArray',\n        global: false,\n        description: 'description stringArray is string array',\n        tags: [],\n        required: false,\n        type: 'string[] | undefined',\n        declarations: [],\n        schema: {\n          kind: 'enum',\n          type: 'string[] | undefined',\n          schema: [\n            'undefined',\n            {\n              kind: 'array',\n              type: 'string[]',\n              schema: ['string'],\n            },\n          ],\n        },\n        default: '[\"foo\", \"bar\"]',\n      },\n      {\n        name: 'key',\n        global: true,\n        description: '',\n        tags: [],\n        required: false,\n        type: 'string | number | symbol | undefined',\n        declarations: [],\n        schema: {\n          kind: 'enum',\n          type: 'string | number | symbol | undefined',\n          schema: ['undefined', 'string', 'number', 'symbol'],\n        },\n      },\n      {\n        name: 'ref',\n        global: true,\n        description: '',\n        tags: [],\n        required: false,\n        type: 'VNodeRef | undefined',\n        declarations: [],\n        schema: {\n          kind: 'enum',\n          type: 'VNodeRef | undefined',\n          schema: [\n            'undefined',\n            'string',\n            'Ref<any>',\n            {\n              kind: 'event',\n              type: '(ref: Element | ComponentPublicInstance<{}, {}, {}, {}, {}, {}, {}, {}, false, ComponentOptionsBase<any, any, any, any, any, any, any, any, any, {}, {}, string, {}>, {}, {}> | null, refs: Record<...>): void',\n              schema: [],\n            },\n          ],\n        },\n      },\n      {\n        name: 'ref_for',\n        global: true,\n        description: '',\n        tags: [],\n        required: false,\n        type: 'boolean | undefined',\n        declarations: [],\n        schema: {\n          kind: 'enum',\n          type: 'boolean | undefined',\n          schema: ['undefined', 'false', 'true'],\n        },\n      },\n      {\n        name: 'ref_key',\n        global: true,\n        description: '',\n        tags: [],\n        required: false,\n        type: 'string | undefined',\n        declarations: [],\n        schema: {\n          kind: 'enum',\n          type: 'string | undefined',\n          schema: ['undefined', 'string'],\n        },\n      },\n      {\n        name: 'class',\n        global: true,\n        description: '',\n        tags: [],\n        required: false,\n        type: 'unknown',\n        declarations: [],\n        schema: 'unknown',\n      },\n      {\n        name: 'style',\n        global: true,\n        description: '',\n        tags: [],\n        required: false,\n        type: 'unknown',\n        declarations: [],\n        schema: 'unknown',\n      },\n      {\n        name: 'foo',\n        global: false,\n        description: 'string foo',\n        tags: [\n          {\n            name: 'default',\n            text: '\"rounded\"',\n          },\n          {\n            name: 'since',\n            text: 'v1.0.0',\n          },\n          {\n            name: 'see',\n            text: 'https://vuejs.org/',\n          },\n          {\n            name: 'deprecated',\n            text: 'v1.1.0',\n          },\n        ],\n        required: true,\n        type: 'string',\n        declarations: [],\n        schema: 'string',\n      },\n      {\n        name: 'baz',\n        global: false,\n        description: 'description baz is required boolean',\n        tags: [],\n        required: true,\n        type: 'boolean',\n        declarations: [],\n        schema: {\n          kind: 'enum',\n          type: 'boolean',\n          schema: ['false', 'true'],\n        },\n      },\n      {\n        name: 'union',\n        global: false,\n        description: 'description union is required union type',\n        tags: [],\n        required: true,\n        type: 'string | number',\n        declarations: [],\n        schema: {\n          kind: 'enum',\n          type: 'string | number',\n          schema: ['string', 'number'],\n        },\n      },\n      {\n        name: 'unionOptional',\n        global: false,\n        description: 'description unionOptional is optional union type',\n        tags: [],\n        required: false,\n        type: 'string | number | boolean | undefined',\n        declarations: [],\n        schema: {\n          kind: 'enum',\n          type: 'string | number | boolean | undefined',\n          schema: ['undefined', 'string', 'number', 'false', 'true'],\n        },\n      },\n      {\n        name: 'nested',\n        global: false,\n        description: 'description nested is required nested object',\n        tags: [],\n        required: true,\n        type: 'MyNestedProps',\n        declarations: [],\n        schema: {\n          kind: 'object',\n          type: 'MyNestedProps',\n          schema: {\n            nestedProp: {\n              name: 'nestedProp',\n              global: false,\n              description: 'nested prop documentation',\n              tags: [],\n              required: true,\n              type: 'string',\n              declarations: [],\n              schema: 'string',\n            },\n          },\n        },\n      },\n      {\n        name: 'nestedIntersection',\n        global: false,\n        description: 'description required nested object with intersection',\n        tags: [],\n        required: true,\n        type: 'MyNestedProps & { additionalProp: string; }',\n        declarations: [],\n        schema: {\n          kind: 'object',\n          type: 'MyNestedProps & { additionalProp: string; }',\n          schema: {\n            nestedProp: {\n              name: 'nestedProp',\n              global: false,\n              description: 'nested prop documentation',\n              tags: [],\n              required: true,\n              type: 'string',\n              declarations: [],\n              schema: 'string',\n            },\n            additionalProp: {\n              name: 'additionalProp',\n              global: false,\n              description: 'description required additional property',\n              tags: [],\n              required: true,\n              type: 'string',\n              declarations: [],\n              schema: 'string',\n            },\n          },\n        },\n      },\n      {\n        name: 'nestedOptional',\n        global: false,\n        description: 'description optional nested object',\n        tags: [],\n        required: false,\n        type: 'MyNestedProps | MyIgnoredNestedProps | undefined',\n        declarations: [],\n        schema: {\n          kind: 'enum',\n          type: 'MyNestedProps | MyIgnoredNestedProps | undefined',\n          schema: [\n            'undefined',\n            {\n              kind: 'object',\n              type: 'MyNestedProps',\n              schema: {\n                nestedProp: {\n                  name: 'nestedProp',\n                  global: false,\n                  description: 'nested prop documentation',\n                  tags: [],\n                  required: true,\n                  type: 'string',\n                  declarations: [],\n                  schema: 'string',\n                },\n              },\n            },\n            {\n              kind: 'object',\n              type: 'MyIgnoredNestedProps',\n              schema: {\n                nestedProp: {\n                  name: 'nestedProp',\n                  global: false,\n                  description: '',\n                  tags: [],\n                  required: true,\n                  type: 'string',\n                  declarations: [],\n                  schema: 'string',\n                },\n              },\n            },\n          ],\n        },\n      },\n      {\n        name: 'array',\n        global: false,\n        description: 'description required array object',\n        tags: [],\n        required: true,\n        type: 'MyNestedProps[]',\n        declarations: [],\n        schema: {\n          kind: 'array',\n          type: 'MyNestedProps[]',\n          schema: [\n            {\n              kind: 'object',\n              type: 'MyNestedProps',\n              schema: {\n                nestedProp: {\n                  name: 'nestedProp',\n                  global: false,\n                  description: 'nested prop documentation',\n                  tags: [],\n                  required: true,\n                  type: 'string',\n                  declarations: [],\n                  schema: 'string',\n                },\n              },\n            },\n          ],\n        },\n      },\n      {\n        name: 'arrayOptional',\n        global: false,\n        description: 'description optional array object',\n        tags: [],\n        required: false,\n        type: 'MyNestedProps[] | undefined',\n        declarations: [],\n        schema: {\n          kind: 'enum',\n          type: 'MyNestedProps[] | undefined',\n          schema: [\n            'undefined',\n            {\n              kind: 'array',\n              type: 'MyNestedProps[]',\n              schema: [\n                {\n                  kind: 'object',\n                  type: 'MyNestedProps',\n                  schema: {\n                    nestedProp: {\n                      name: 'nestedProp',\n                      global: false,\n                      description: 'nested prop documentation',\n                      tags: [],\n                      required: true,\n                      type: 'string',\n                      declarations: [],\n                      schema: 'string',\n                    },\n                  },\n                },\n              ],\n            },\n          ],\n        },\n      },\n      {\n        name: 'enumValue',\n        global: false,\n        description: 'description enum value',\n        tags: [],\n        required: true,\n        type: 'MyEnum',\n        declarations: [],\n        schema: {\n          kind: 'enum',\n          type: 'MyEnum',\n          schema: ['MyEnum.Small', 'MyEnum.Medium', 'MyEnum.Large'],\n        },\n      },\n      {\n        name: 'literalFromContext',\n        global: false,\n        description: 'description literal type alias that require context',\n        tags: [],\n        required: true,\n        type: '\"Uncategorized\" | \"Content\" | \"Interaction\" | \"Display\" | \"Forms\" | \"Addons\"',\n        declarations: [],\n        schema: {\n          kind: 'enum',\n          type: '\"Uncategorized\" | \"Content\" | \"Interaction\" | \"Display\" | \"Forms\" | \"Addons\"',\n          schema: [\n            '\"Uncategorized\"',\n            '\"Content\"',\n            '\"Interaction\"',\n            '\"Display\"',\n            '\"Forms\"',\n            '\"Addons\"',\n          ],\n        },\n      },\n      {\n        name: 'inlined',\n        global: false,\n        description: '',\n        tags: [],\n        required: true,\n        type: '{ foo: string; }',\n        declarations: [],\n        schema: {\n          kind: 'object',\n          type: '{ foo: string; }',\n          schema: {\n            foo: {\n              name: 'foo',\n              global: false,\n              description: '',\n              tags: [],\n              required: true,\n              type: 'string',\n              declarations: [],\n              schema: 'string',\n            },\n          },\n        },\n      },\n      {\n        name: 'recursive',\n        global: false,\n        description: '',\n        tags: [],\n        required: false,\n        type: 'MyNestedRecursiveProps | undefined',\n        declarations: [],\n        schema: {\n          kind: 'enum',\n          type: 'MyNestedRecursiveProps | undefined',\n          schema: [\n            'undefined',\n            {\n              kind: 'object',\n              type: 'MyNestedRecursiveProps',\n              schema: {\n                recursive: {\n                  name: 'recursive',\n                  global: false,\n                  description: '',\n                  tags: [],\n                  required: true,\n                  type: 'MyNestedRecursiveProps',\n                  declarations: [],\n                  schema: 'MyNestedRecursiveProps',\n                },\n              },\n            },\n          ],\n        },\n      },\n    ],\n    events: [],\n    slots: [],\n    exposed: [],\n  },\n};\n\nexport const mockExtractComponentPropsReturn = [\n  {\n    propDef: {\n      name: 'bar',\n      type: {},\n      required: false,\n      description: 'description bar is optional number',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'bar',\n      global: false,\n      description: 'description bar is optional number',\n      tags: [],\n      required: false,\n      type: 'number | undefined',\n      declarations: [],\n      schema: {\n        kind: 'enum',\n        type: 'number | undefined',\n        schema: ['undefined', 'number'],\n      },\n      default: '1',\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'stringArray',\n      type: {},\n      required: false,\n      description: 'description stringArray is string array',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'stringArray',\n      global: false,\n      description: 'description stringArray is string array',\n      tags: [],\n      required: false,\n      type: 'string[] | undefined',\n      declarations: [],\n      schema: {\n        kind: 'enum',\n        type: 'string[] | undefined',\n        schema: [\n          'undefined',\n          {\n            kind: 'array',\n            type: 'string[]',\n            schema: ['string'],\n          },\n        ],\n      },\n      default: '[\"foo\", \"bar\"]',\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'key',\n      type: {},\n      required: false,\n      description: '',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'key',\n      global: true,\n      description: '',\n      tags: [],\n      required: false,\n      type: 'string | number | symbol | undefined',\n      declarations: [],\n      schema: {\n        kind: 'enum',\n        type: 'string | number | symbol | undefined',\n        schema: ['undefined', 'string', 'number', 'symbol'],\n      },\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'ref',\n      type: {},\n      required: false,\n      description: '',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'ref',\n      global: true,\n      description: '',\n      tags: [],\n      required: false,\n      type: 'VNodeRef | undefined',\n      declarations: [],\n      schema: {\n        kind: 'enum',\n        type: 'VNodeRef | undefined',\n        schema: [\n          'undefined',\n          'string',\n          'Ref<any>',\n          {\n            kind: 'event',\n            type: '(ref: Element | ComponentPublicInstance<{}, {}, {}, {}, {}, {}, {}, {}, false, ComponentOptionsBase<any, any, any, any, any, any, any, any, any, {}, {}, string, {}>, {}, {}> | null, refs: Record<...>): void',\n            schema: [],\n          },\n        ],\n      },\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'ref_for',\n      type: {},\n      required: false,\n      description: '',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'ref_for',\n      global: true,\n      description: '',\n      tags: [],\n      required: false,\n      type: 'boolean | undefined',\n      declarations: [],\n      schema: {\n        kind: 'enum',\n        type: 'boolean | undefined',\n        schema: ['undefined', 'false', 'true'],\n      },\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'ref_key',\n      type: {},\n      required: false,\n      description: '',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'ref_key',\n      global: true,\n      description: '',\n      tags: [],\n      required: false,\n      type: 'string | undefined',\n      declarations: [],\n      schema: {\n        kind: 'enum',\n        type: 'string | undefined',\n        schema: ['undefined', 'string'],\n      },\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'class',\n      type: {},\n      required: false,\n      description: '',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'class',\n      global: true,\n      description: '',\n      tags: [],\n      required: false,\n      type: 'unknown',\n      declarations: [],\n      schema: 'unknown',\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'style',\n      type: {},\n      required: false,\n      description: '',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'style',\n      global: true,\n      description: '',\n      tags: [],\n      required: false,\n      type: 'unknown',\n      declarations: [],\n      schema: 'unknown',\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'foo',\n      type: {},\n      required: true,\n      description: 'string foo',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'foo',\n      global: false,\n      description: 'string foo',\n      tags: [\n        {\n          name: 'default',\n          text: '\"rounded\"',\n        },\n        {\n          name: 'since',\n          text: 'v1.0.0',\n        },\n        {\n          name: 'see',\n          text: 'https://vuejs.org/',\n        },\n        {\n          name: 'deprecated',\n          text: 'v1.1.0',\n        },\n      ],\n      required: true,\n      type: 'string',\n      declarations: [],\n      schema: 'string',\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'baz',\n      type: {},\n      required: true,\n      description: 'description baz is required boolean',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'baz',\n      global: false,\n      description: 'description baz is required boolean',\n      tags: [],\n      required: true,\n      type: 'boolean',\n      declarations: [],\n      schema: {\n        kind: 'enum',\n        type: 'boolean',\n        schema: ['false', 'true'],\n      },\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'union',\n      type: {},\n      required: true,\n      description: 'description union is required union type',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'union',\n      global: false,\n      description: 'description union is required union type',\n      tags: [],\n      required: true,\n      type: 'string | number',\n      declarations: [],\n      schema: {\n        kind: 'enum',\n        type: 'string | number',\n        schema: ['string', 'number'],\n      },\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'unionOptional',\n      type: {},\n      required: false,\n      description: 'description unionOptional is optional union type',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'unionOptional',\n      global: false,\n      description: 'description unionOptional is optional union type',\n      tags: [],\n      required: false,\n      type: 'string | number | boolean | undefined',\n      declarations: [],\n      schema: {\n        kind: 'enum',\n        type: 'string | number | boolean | undefined',\n        schema: ['undefined', 'string', 'number', 'false', 'true'],\n      },\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'nested',\n      type: {},\n      required: true,\n      description: 'description nested is required nested object',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'nested',\n      global: false,\n      description: 'description nested is required nested object',\n      tags: [],\n      required: true,\n      type: 'MyNestedProps',\n      declarations: [],\n      schema: {\n        kind: 'object',\n        type: 'MyNestedProps',\n        schema: {\n          nestedProp: {\n            name: 'nestedProp',\n            global: false,\n            description: 'nested prop documentation',\n            tags: [],\n            required: true,\n            type: 'string',\n            declarations: [],\n            schema: 'string',\n          },\n        },\n      },\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'nestedIntersection',\n      type: {},\n      required: true,\n      description: 'description required nested object with intersection',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'nestedIntersection',\n      global: false,\n      description: 'description required nested object with intersection',\n      tags: [],\n      required: true,\n      type: 'MyNestedProps & { additionalProp: string; }',\n      declarations: [],\n      schema: {\n        kind: 'object',\n        type: 'MyNestedProps & { additionalProp: string; }',\n        schema: {\n          nestedProp: {\n            name: 'nestedProp',\n            global: false,\n            description: 'nested prop documentation',\n            tags: [],\n            required: true,\n            type: 'string',\n            declarations: [],\n            schema: 'string',\n          },\n          additionalProp: {\n            name: 'additionalProp',\n            global: false,\n            description: 'description required additional property',\n            tags: [],\n            required: true,\n            type: 'string',\n            declarations: [],\n            schema: 'string',\n          },\n        },\n      },\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'nestedOptional',\n      type: {},\n      required: false,\n      description: 'description optional nested object',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'nestedOptional',\n      global: false,\n      description: 'description optional nested object',\n      tags: [],\n      required: false,\n      type: 'MyNestedProps | MyIgnoredNestedProps | undefined',\n      declarations: [],\n      schema: {\n        kind: 'enum',\n        type: 'MyNestedProps | MyIgnoredNestedProps | undefined',\n        schema: [\n          'undefined',\n          {\n            kind: 'object',\n            type: 'MyNestedProps',\n            schema: {\n              nestedProp: {\n                name: 'nestedProp',\n                global: false,\n                description: 'nested prop documentation',\n                tags: [],\n                required: true,\n                type: 'string',\n                declarations: [],\n                schema: 'string',\n              },\n            },\n          },\n          {\n            kind: 'object',\n            type: 'MyIgnoredNestedProps',\n            schema: {\n              nestedProp: {\n                name: 'nestedProp',\n                global: false,\n                description: '',\n                tags: [],\n                required: true,\n                type: 'string',\n                declarations: [],\n                schema: 'string',\n              },\n            },\n          },\n        ],\n      },\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'array',\n      type: {},\n      required: true,\n      description: 'description required array object',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'array',\n      global: false,\n      description: 'description required array object',\n      tags: [],\n      required: true,\n      type: 'MyNestedProps[]',\n      declarations: [],\n      schema: {\n        kind: 'array',\n        type: 'MyNestedProps[]',\n        schema: [\n          {\n            kind: 'object',\n            type: 'MyNestedProps',\n            schema: {\n              nestedProp: {\n                name: 'nestedProp',\n                global: false,\n                description: 'nested prop documentation',\n                tags: [],\n                required: true,\n                type: 'string',\n                declarations: [],\n                schema: 'string',\n              },\n            },\n          },\n        ],\n      },\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'arrayOptional',\n      type: {},\n      required: false,\n      description: 'description optional array object',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'arrayOptional',\n      global: false,\n      description: 'description optional array object',\n      tags: [],\n      required: false,\n      type: 'MyNestedProps[] | undefined',\n      declarations: [],\n      schema: {\n        kind: 'enum',\n        type: 'MyNestedProps[] | undefined',\n        schema: [\n          'undefined',\n          {\n            kind: 'array',\n            type: 'MyNestedProps[]',\n            schema: [\n              {\n                kind: 'object',\n                type: 'MyNestedProps',\n                schema: {\n                  nestedProp: {\n                    name: 'nestedProp',\n                    global: false,\n                    description: 'nested prop documentation',\n                    tags: [],\n                    required: true,\n                    type: 'string',\n                    declarations: [],\n                    schema: 'string',\n                  },\n                },\n              },\n            ],\n          },\n        ],\n      },\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'enumValue',\n      type: {},\n      required: true,\n      description: 'description enum value',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'enumValue',\n      global: false,\n      description: 'description enum value',\n      tags: [],\n      required: true,\n      type: 'MyEnum',\n      declarations: [],\n      schema: {\n        kind: 'enum',\n        type: 'MyEnum',\n        schema: ['MyEnum.Small', 'MyEnum.Medium', 'MyEnum.Large'],\n      },\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'literalFromContext',\n      type: {},\n      required: true,\n      description: 'description literal type alias that require context',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'literalFromContext',\n      global: false,\n      description: 'description literal type alias that require context',\n      tags: [],\n      required: true,\n      type: '\"Uncategorized\" | \"Content\" | \"Interaction\" | \"Display\" | \"Forms\" | \"Addons\"',\n      declarations: [],\n      schema: {\n        kind: 'enum',\n        type: '\"Uncategorized\" | \"Content\" | \"Interaction\" | \"Display\" | \"Forms\" | \"Addons\"',\n        schema: [\n          '\"Uncategorized\"',\n          '\"Content\"',\n          '\"Interaction\"',\n          '\"Display\"',\n          '\"Forms\"',\n          '\"Addons\"',\n        ],\n      },\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'inlined',\n      type: {},\n      required: true,\n      description: '',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'inlined',\n      global: false,\n      description: '',\n      tags: [],\n      required: true,\n      type: '{ foo: string; }',\n      declarations: [],\n      schema: {\n        kind: 'object',\n        type: '{ foo: string; }',\n        schema: {\n          foo: {\n            name: 'foo',\n            global: false,\n            description: '',\n            tags: [],\n            required: true,\n            type: 'string',\n            declarations: [],\n            schema: 'string',\n          },\n        },\n      },\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'recursive',\n      type: {},\n      required: false,\n      description: '',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'recursive',\n      global: false,\n      description: '',\n      tags: [],\n      required: false,\n      type: 'MyNestedRecursiveProps | undefined',\n      declarations: [],\n      schema: {\n        kind: 'enum',\n        type: 'MyNestedRecursiveProps | undefined',\n        schema: [\n          'undefined',\n          {\n            kind: 'object',\n            type: 'MyNestedRecursiveProps',\n            schema: {\n              recursive: {\n                name: 'recursive',\n                global: false,\n                description: '',\n                tags: [],\n                required: true,\n                type: 'MyNestedRecursiveProps',\n                declarations: [],\n                schema: 'MyNestedRecursiveProps',\n              },\n            },\n          },\n        ],\n      },\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n];\n\nexport const referenceTypeEvents: TestComponent = {\n  __docgenInfo: {\n    type: 1,\n    props: [],\n    events: [\n      {\n        name: 'foo',\n        description: '',\n        tags: [],\n        type: '[data?: { foo: string; } | undefined]',\n        signature: '(event: \"foo\", data?: { foo: string; } | undefined): void',\n        declarations: [],\n        schema: [\n          {\n            kind: 'enum',\n            type: '{ foo: string; } | undefined',\n            schema: [\n              'undefined',\n              {\n                kind: 'object',\n                type: '{ foo: string; }',\n                schema: {\n                  foo: {\n                    name: 'foo',\n                    global: false,\n                    description: '',\n                    tags: [],\n                    required: true,\n                    type: 'string',\n                    declarations: [],\n                    schema: 'string',\n                  },\n                },\n              },\n            ],\n          },\n        ],\n      },\n      {\n        name: 'bar',\n        description: '',\n        tags: [],\n        type: '[value: { year: number; title?: any; }]',\n        signature: '(event: \"bar\", value: { year: number; title?: any; }): void',\n        declarations: [],\n        schema: [\n          {\n            kind: 'object',\n            type: '{ year: number; title?: any; }',\n            schema: {\n              year: {\n                name: 'year',\n                global: false,\n                description: '',\n                tags: [],\n                required: true,\n                type: 'number',\n                declarations: [],\n                schema: 'number',\n              },\n              title: {\n                name: 'title',\n                global: false,\n                description: '',\n                tags: [],\n                required: false,\n                type: 'any',\n                declarations: [],\n                schema: 'any',\n              },\n            },\n          },\n        ],\n      },\n      {\n        name: 'baz',\n        description: '',\n        tags: [],\n        type: '[]',\n        signature: '(event: \"baz\"): void',\n        declarations: [],\n        schema: [],\n      },\n    ],\n    slots: [],\n    exposed: [],\n  },\n};\n\nexport const mockExtractComponentEventsReturn = [\n  {\n    propDef: {\n      name: 'foo',\n      type: {},\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'foo',\n      type: '[data?: { foo: string; } | undefined]',\n      signature: '(event: \"foo\", data?: { foo: string; } | undefined): void',\n      declarations: [],\n      schema: [\n        {\n          kind: 'enum',\n          type: '{ foo: string; } | undefined',\n          schema: [\n            'undefined',\n            {\n              kind: 'object',\n              type: '{ foo: string; }',\n              schema: {\n                foo: {\n                  name: 'foo',\n                  global: false,\n                  description: '',\n                  tags: [],\n                  required: true,\n                  type: 'string',\n                  declarations: [],\n                  schema: 'string',\n                },\n              },\n            },\n          ],\n        },\n      ],\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'bar',\n      type: {},\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'bar',\n      type: '[value: { year: number; title?: any; }]',\n      signature: '(event: \"bar\", value: { year: number; title?: any; }): void',\n      declarations: [],\n      schema: [\n        {\n          kind: 'object',\n          type: '{ year: number; title?: any; }',\n          schema: {\n            year: {\n              name: 'year',\n              global: false,\n              description: '',\n              tags: [],\n              required: true,\n              type: 'number',\n              declarations: [],\n              schema: 'number',\n            },\n            title: {\n              name: 'title',\n              global: false,\n              description: '',\n              tags: [],\n              required: false,\n              type: 'any',\n              declarations: [],\n              schema: 'any',\n            },\n          },\n        },\n      ],\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'baz',\n      type: {},\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'baz',\n      type: '[]',\n      signature: '(event: \"baz\"): void',\n      declarations: [],\n      schema: [],\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n];\n\nexport const templateSlots: TestComponent = {\n  __docgenInfo: {\n    type: 1,\n    props: [],\n    events: [],\n    slots: [\n      {\n        name: 'no-bind',\n        type: '{}',\n        description: '',\n        declarations: [],\n        schema: {\n          kind: 'object',\n          type: '{}',\n          schema: {},\n        },\n      },\n      {\n        name: 'default',\n        type: '{ num: number; }',\n        description: '',\n        declarations: [],\n        schema: {\n          kind: 'object',\n          type: '{ num: number; }',\n          schema: {\n            num: {\n              name: 'num',\n              global: false,\n              description: '',\n              tags: [],\n              required: true,\n              type: 'number',\n              declarations: [],\n              schema: 'number',\n            },\n          },\n        },\n      },\n      {\n        name: 'named',\n        type: '{ str: string; }',\n        description: '',\n        declarations: [],\n        schema: {\n          kind: 'object',\n          type: '{ str: string; }',\n          schema: {\n            str: {\n              name: 'str',\n              global: false,\n              description: '',\n              tags: [],\n              required: true,\n              type: 'string',\n              declarations: [],\n              schema: 'string',\n            },\n          },\n        },\n      },\n      {\n        name: 'vbind',\n        type: '{ num: number; str: string; }',\n        description: '',\n        declarations: [],\n        schema: {\n          kind: 'object',\n          type: '{ num: number; str: string; }',\n          schema: {\n            num: {\n              name: 'num',\n              global: false,\n              description: '',\n              tags: [],\n              required: true,\n              type: 'number',\n              declarations: [],\n              schema: 'number',\n            },\n            str: {\n              name: 'str',\n              global: false,\n              description: '',\n              tags: [],\n              required: true,\n              type: 'string',\n              declarations: [],\n              schema: 'string',\n            },\n          },\n        },\n      },\n    ],\n    exposed: [],\n  },\n};\n\nexport const mockExtractComponentSlotsReturn = [\n  {\n    propDef: {\n      name: 'no-bind',\n      type: {},\n      description: '',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'no-bind',\n      type: '{}',\n      description: '',\n      declarations: [],\n      schema: {\n        kind: 'object',\n        type: '{}',\n        schema: {},\n      },\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'default',\n      type: {},\n      description: '',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'default',\n      type: '{ num: number; }',\n      description: '',\n      declarations: [],\n      schema: {\n        kind: 'object',\n        type: '{ num: number; }',\n        schema: {\n          num: {\n            name: 'num',\n            global: false,\n            description: '',\n            tags: [],\n            required: true,\n            type: 'number',\n            declarations: [],\n            schema: 'number',\n          },\n        },\n      },\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'named',\n      type: {},\n      description: '',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'named',\n      type: '{ str: string; }',\n      description: '',\n      declarations: [],\n      schema: {\n        kind: 'object',\n        type: '{ str: string; }',\n        schema: {\n          str: {\n            name: 'str',\n            global: false,\n            description: '',\n            tags: [],\n            required: true,\n            type: 'string',\n            declarations: [],\n            schema: 'string',\n          },\n        },\n      },\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n  {\n    propDef: {\n      name: 'vbind',\n      type: {},\n      description: '',\n      defaultValue: null,\n      sbType: {\n        name: 'other',\n      },\n    },\n    docgenInfo: {\n      name: 'vbind',\n      type: '{ num: number; str: string; }',\n      description: '',\n      declarations: [],\n      schema: {\n        kind: 'object',\n        type: '{ num: number; str: string; }',\n        schema: {\n          num: {\n            name: 'num',\n            global: false,\n            description: '',\n            tags: [],\n            required: true,\n            type: 'number',\n            declarations: [],\n            schema: 'number',\n          },\n          str: {\n            name: 'str',\n            global: false,\n            description: '',\n            tags: [],\n            required: true,\n            type: 'string',\n            declarations: [],\n            schema: 'string',\n          },\n        },\n      },\n    },\n    typeSystem: TypeSystem.JAVASCRIPT,\n  },\n];\n\nexport const vueDocgenMocks = {\n  props: {\n    component: {\n      __docgenInfo: {\n        description: '',\n        tags: {},\n        props: [\n          {\n            name: 'foo',\n            description: 'string foo',\n            tags: {\n              default: [\n                {\n                  description: '\"rounded\"',\n                  title: 'default',\n                },\n              ],\n              since: [\n                {\n                  description: 'v1.0.0',\n                  title: 'since',\n                },\n              ],\n              see: [\n                {\n                  description: 'https://vuejs.org/',\n                  title: 'see',\n                },\n              ],\n              deprecated: [\n                {\n                  description: 'v1.1.0',\n                  title: 'deprecated',\n                },\n              ],\n            },\n            required: true,\n            type: {\n              name: 'string',\n            },\n          },\n          {\n            name: 'bar',\n            description: 'description bar is optional number',\n            required: false,\n            type: {\n              name: 'number',\n            },\n            defaultValue: {\n              func: false,\n              value: '1',\n            },\n          },\n          {\n            name: 'baz',\n            description: 'description baz is required boolean',\n            required: true,\n            type: {\n              name: 'boolean',\n            },\n          },\n          {\n            name: 'stringArray',\n            description: 'description stringArray is string array',\n            required: false,\n            type: {\n              name: 'Array',\n              elements: [\n                {\n                  name: 'string',\n                },\n              ],\n            },\n            defaultValue: {\n              func: false,\n              value: \"() => ['foo', 'bar']\",\n            },\n          },\n          {\n            name: 'union',\n            description: 'description union is required union type',\n            required: true,\n            type: {\n              name: 'union',\n              elements: [\n                {\n                  name: 'string',\n                },\n                {\n                  name: 'number',\n                },\n              ],\n            },\n          },\n          {\n            name: 'unionOptional',\n            description: 'description unionOptional is optional union type',\n            required: false,\n            type: {\n              name: 'union',\n              elements: [\n                {\n                  name: 'string',\n                },\n                {\n                  name: 'number',\n                },\n                {\n                  name: 'boolean',\n                },\n              ],\n            },\n          },\n          {\n            name: 'nested',\n            description: 'description nested is required nested object',\n            required: true,\n            type: {\n              name: 'MyNestedProps',\n            },\n          },\n          {\n            name: 'nestedIntersection',\n            description: 'description required nested object with intersection',\n            required: true,\n            type: {\n              name: 'intersection',\n              elements: [\n                {\n                  name: 'MyNestedProps',\n                },\n                {\n                  name: '{\\n  /**\\n   * description required additional property\\n   */\\n  additionalProp: string;\\n}',\n                },\n              ],\n            },\n          },\n          {\n            name: 'nestedOptional',\n            description: 'description optional nested object',\n            required: false,\n            type: {\n              name: 'union',\n              elements: [\n                {\n                  name: 'MyNestedProps',\n                },\n                {\n                  name: 'MyIgnoredNestedProps',\n                },\n              ],\n            },\n          },\n          {\n            name: 'array',\n            description: 'description required array object',\n            required: true,\n            type: {\n              name: 'Array',\n              elements: [\n                {\n                  name: 'MyNestedProps',\n                },\n              ],\n            },\n          },\n          {\n            name: 'arrayOptional',\n            description: 'description optional array object',\n            required: false,\n            type: {\n              name: 'Array',\n              elements: [\n                {\n                  name: 'MyNestedProps',\n                },\n              ],\n            },\n          },\n          {\n            name: 'enumValue',\n            description: 'description enum value',\n            required: true,\n            type: {\n              name: 'MyEnum',\n            },\n          },\n          {\n            name: 'literalFromContext',\n            description: 'description literal type alias that require context',\n            required: true,\n            type: {\n              name: 'MyCategories',\n            },\n          },\n          {\n            name: 'inlined',\n            required: true,\n            type: {\n              name: '{ foo: string }',\n            },\n          },\n          {\n            name: 'recursive',\n            required: false,\n            type: {\n              name: 'MyNestedRecursiveProps',\n            },\n          },\n        ],\n      },\n    },\n    extractedProps: [\n      {\n        propDef: {\n          name: 'foo',\n          type: {\n            summary: 'string',\n          },\n          required: true,\n          description: 'string foo',\n          defaultValue: null,\n          sbType: {\n            name: 'string',\n          },\n        },\n        docgenInfo: {\n          name: 'foo',\n          description: 'string foo',\n          tags: {\n            default: [\n              {\n                description: '\"rounded\"',\n                title: 'default',\n              },\n            ],\n            since: [\n              {\n                description: 'v1.0.0',\n                title: 'since',\n              },\n            ],\n            see: [\n              {\n                description: 'https://vuejs.org/',\n                title: 'see',\n              },\n            ],\n            deprecated: [\n              {\n                description: 'v1.1.0',\n                title: 'deprecated',\n              },\n            ],\n          },\n          required: true,\n          type: {\n            name: 'string',\n          },\n        },\n        typeSystem: TypeSystem.JAVASCRIPT,\n      },\n      {\n        propDef: {\n          name: 'bar',\n          type: {\n            summary: 'number',\n          },\n          required: false,\n          description: 'description bar is optional number',\n          defaultValue: {\n            summary: '1',\n          },\n          sbType: {\n            name: 'number',\n          },\n        },\n        docgenInfo: {\n          name: 'bar',\n          description: 'description bar is optional number',\n          required: false,\n          type: {\n            name: 'number',\n          },\n          defaultValue: {\n            func: false,\n            value: '1',\n          },\n        },\n        typeSystem: TypeSystem.JAVASCRIPT,\n      },\n      {\n        propDef: {\n          name: 'baz',\n          type: {\n            summary: 'boolean',\n          },\n          required: true,\n          description: 'description baz is required boolean',\n          defaultValue: null,\n          sbType: {\n            name: 'boolean',\n          },\n        },\n        docgenInfo: {\n          name: 'baz',\n          description: 'description baz is required boolean',\n          required: true,\n          type: {\n            name: 'boolean',\n          },\n        },\n        typeSystem: TypeSystem.JAVASCRIPT,\n      },\n      {\n        propDef: {\n          name: 'stringArray',\n          type: {\n            summary: 'Array',\n          },\n          required: false,\n          description: 'description stringArray is string array',\n          defaultValue: {\n            summary: \"() => ['foo', 'bar']\",\n          },\n          sbType: {\n            name: 'other',\n            value: 'Array([object Object])',\n          },\n        },\n        docgenInfo: {\n          name: 'stringArray',\n          description: 'description stringArray is string array',\n          required: false,\n          type: {\n            name: 'Array',\n            elements: [\n              {\n                name: 'string',\n              },\n            ],\n            value: [\n              {\n                name: 'string',\n              },\n            ],\n          },\n          defaultValue: {\n            func: false,\n            value: \"() => ['foo', 'bar']\",\n          },\n        },\n        typeSystem: TypeSystem.JAVASCRIPT,\n      },\n      {\n        propDef: {\n          name: 'union',\n          type: {\n            summary: 'union',\n          },\n          required: true,\n          description: 'description union is required union type',\n          defaultValue: null,\n          sbType: {\n            name: 'union',\n            value: [\n              {\n                name: 'string',\n              },\n              {\n                name: 'number',\n              },\n            ],\n          },\n        },\n        docgenInfo: {\n          name: 'union',\n          description: 'description union is required union type',\n          required: true,\n          type: {\n            name: 'union',\n            elements: [\n              {\n                name: 'string',\n              },\n              {\n                name: 'number',\n              },\n            ],\n            value: [\n              {\n                name: 'string',\n              },\n              {\n                name: 'number',\n              },\n            ],\n          },\n        },\n        typeSystem: TypeSystem.JAVASCRIPT,\n      },\n      {\n        propDef: {\n          name: 'unionOptional',\n          type: {\n            summary: 'union',\n          },\n          required: false,\n          description: 'description unionOptional is optional union type',\n          defaultValue: null,\n          sbType: {\n            name: 'union',\n            value: [\n              {\n                name: 'string',\n              },\n              {\n                name: 'number',\n              },\n              {\n                name: 'boolean',\n              },\n            ],\n          },\n        },\n        docgenInfo: {\n          name: 'unionOptional',\n          description: 'description unionOptional is optional union type',\n          required: false,\n          type: {\n            name: 'union',\n            elements: [\n              {\n                name: 'string',\n              },\n              {\n                name: 'number',\n              },\n              {\n                name: 'boolean',\n              },\n            ],\n            value: [\n              {\n                name: 'string',\n              },\n              {\n                name: 'number',\n              },\n              {\n                name: 'boolean',\n              },\n            ],\n          },\n        },\n        typeSystem: TypeSystem.JAVASCRIPT,\n      },\n      {\n        propDef: {\n          name: 'nested',\n          type: {\n            summary: 'MyNestedProps',\n          },\n          required: true,\n          description: 'description nested is required nested object',\n          defaultValue: null,\n          sbType: {\n            name: 'other',\n            value: 'MyNestedProps',\n          },\n        },\n        docgenInfo: {\n          name: 'nested',\n          description: 'description nested is required nested object',\n          required: true,\n          type: {\n            name: 'MyNestedProps',\n          },\n        },\n        typeSystem: TypeSystem.JAVASCRIPT,\n      },\n      {\n        propDef: {\n          name: 'nestedIntersection',\n          type: {\n            summary: 'intersection',\n          },\n          required: true,\n          description: 'description required nested object with intersection',\n          defaultValue: null,\n          sbType: {\n            name: 'other',\n            value: 'intersection([object Object],[object Object])',\n          },\n        },\n        docgenInfo: {\n          name: 'nestedIntersection',\n          description: 'description required nested object with intersection',\n          required: true,\n          type: {\n            name: 'intersection',\n            elements: [\n              {\n                name: 'MyNestedProps',\n              },\n              {\n                name: '{\\n  /**\\n   * description required additional property\\n   */\\n  additionalProp: string;\\n}',\n              },\n            ],\n            value: [\n              {\n                name: 'MyNestedProps',\n              },\n              {\n                name: '{\\n  /**\\n   * description required additional property\\n   */\\n  additionalProp: string;\\n}',\n              },\n            ],\n          },\n        },\n        typeSystem: TypeSystem.JAVASCRIPT,\n      },\n      {\n        propDef: {\n          name: 'nestedOptional',\n          type: {\n            summary: 'union',\n          },\n          required: false,\n          description: 'description optional nested object',\n          defaultValue: null,\n          sbType: {\n            name: 'union',\n            value: [\n              {\n                name: 'other',\n                value: 'MyNestedProps',\n              },\n              {\n                name: 'other',\n                value: 'MyIgnoredNestedProps',\n              },\n            ],\n          },\n        },\n        docgenInfo: {\n          name: 'nestedOptional',\n          description: 'description optional nested object',\n          required: false,\n          type: {\n            name: 'union',\n            elements: [\n              {\n                name: 'MyNestedProps',\n              },\n              {\n                name: 'MyIgnoredNestedProps',\n              },\n            ],\n            value: [\n              {\n                name: 'MyNestedProps',\n              },\n              {\n                name: 'MyIgnoredNestedProps',\n              },\n            ],\n          },\n        },\n        typeSystem: TypeSystem.JAVASCRIPT,\n      },\n      {\n        propDef: {\n          name: 'array',\n          type: {\n            summary: 'Array',\n          },\n          required: true,\n          description: 'description required array object',\n          defaultValue: null,\n          sbType: {\n            name: 'other',\n            value: 'Array([object Object])',\n          },\n        },\n        docgenInfo: {\n          name: 'array',\n          description: 'description required array object',\n          required: true,\n          type: {\n            name: 'Array',\n            elements: [\n              {\n                name: 'MyNestedProps',\n              },\n            ],\n            value: [\n              {\n                name: 'MyNestedProps',\n              },\n            ],\n          },\n        },\n        typeSystem: TypeSystem.JAVASCRIPT,\n      },\n      {\n        propDef: {\n          name: 'arrayOptional',\n          type: {\n            summary: 'Array',\n          },\n          required: false,\n          description: 'description optional array object',\n          defaultValue: null,\n          sbType: {\n            name: 'other',\n            value: 'Array([object Object])',\n          },\n        },\n        docgenInfo: {\n          name: 'arrayOptional',\n          description: 'description optional array object',\n          required: false,\n          type: {\n            name: 'Array',\n            elements: [\n              {\n                name: 'MyNestedProps',\n              },\n            ],\n            value: [\n              {\n                name: 'MyNestedProps',\n              },\n            ],\n          },\n        },\n        typeSystem: TypeSystem.JAVASCRIPT,\n      },\n      {\n        propDef: {\n          name: 'enumValue',\n          type: {\n            summary: 'MyEnum',\n          },\n          required: true,\n          description: 'description enum value',\n          defaultValue: null,\n          sbType: {\n            name: 'other',\n            value: 'MyEnum',\n          },\n        },\n        docgenInfo: {\n          name: 'enumValue',\n          description: 'description enum value',\n          required: true,\n          type: {\n            name: 'MyEnum',\n          },\n        },\n        typeSystem: TypeSystem.JAVASCRIPT,\n      },\n      {\n        propDef: {\n          name: 'literalFromContext',\n          type: {\n            summary: 'MyCategories',\n          },\n          required: true,\n          description: 'description literal type alias that require context',\n          defaultValue: null,\n          sbType: {\n            name: 'other',\n            value: 'MyCategories',\n          },\n        },\n        docgenInfo: {\n          name: 'literalFromContext',\n          description: 'description literal type alias that require context',\n          required: true,\n          type: {\n            name: 'MyCategories',\n          },\n        },\n        typeSystem: TypeSystem.JAVASCRIPT,\n      },\n      {\n        propDef: {\n          name: 'inlined',\n          type: {\n            summary: '{ foo: string }',\n          },\n          required: true,\n          defaultValue: null,\n          sbType: {\n            name: 'other',\n            value: '{ foo: string }',\n          },\n        },\n        docgenInfo: {\n          name: 'inlined',\n          required: true,\n          type: {\n            name: '{ foo: string }',\n          },\n        },\n        typeSystem: TypeSystem.JAVASCRIPT,\n      },\n      {\n        propDef: {\n          name: 'recursive',\n          type: {\n            summary: 'MyNestedRecursiveProps',\n          },\n          required: false,\n          defaultValue: null,\n          sbType: {\n            name: 'other',\n            value: 'MyNestedRecursiveProps',\n          },\n        },\n        docgenInfo: {\n          name: 'recursive',\n          required: false,\n          type: {\n            name: 'MyNestedRecursiveProps',\n          },\n        },\n        typeSystem: TypeSystem.JAVASCRIPT,\n      },\n    ],\n  },\n  events: {\n    component: {\n      __docgenInfo: {\n        exportName: 'default',\n        displayName: 'component',\n        description: '',\n        tags: {},\n        events: [\n          {\n            name: 'bar',\n            type: {\n              names: ['{ year: number; title?: any }'],\n            },\n            description: 'Test description bar',\n          },\n          {\n            name: 'baz',\n            description: 'Test description baz',\n          },\n        ],\n      },\n    },\n    extractedProps: [\n      {\n        propDef: {\n          name: 'bar',\n          type: {},\n          description: 'Test description bar',\n          defaultValue: null,\n          sbType: {\n            name: 'other',\n          },\n        },\n        docgenInfo: {\n          name: 'bar',\n          type: {\n            names: ['{ year: number; title?: any }'],\n          },\n          description: 'Test description bar',\n        },\n        typeSystem: TypeSystem.JAVASCRIPT,\n      },\n      {\n        propDef: {\n          name: 'baz',\n          type: null,\n          description: 'Test description baz',\n          defaultValue: null,\n          sbType: null,\n        },\n        docgenInfo: {\n          name: 'baz',\n          description: 'Test description baz',\n        },\n        typeSystem: TypeSystem.JAVASCRIPT,\n      },\n    ],\n  },\n  slots: {\n    component: {\n      __docgenInfo: {\n        displayName: 'component',\n        exportName: 'default',\n        description: '',\n        tags: {},\n        slots: [\n          {\n            name: 'no-bind',\n          },\n          {\n            name: 'default',\n            scoped: true,\n            bindings: [\n              {\n                name: 'num',\n                title: 'binding',\n              },\n            ],\n          },\n          {\n            name: 'named',\n            scoped: true,\n            bindings: [\n              {\n                name: 'str',\n                title: 'binding',\n              },\n            ],\n          },\n          {\n            name: 'vbind',\n            scoped: true,\n            bindings: [\n              {\n                name: 'num',\n                title: 'binding',\n              },\n              {\n                name: 'str',\n                title: 'binding',\n              },\n            ],\n          },\n        ],\n      },\n    },\n    extractedProps: [\n      {\n        propDef: {\n          name: 'no-bind',\n          type: {\n            summary: 'unknown',\n          },\n          defaultValue: null,\n        },\n        docgenInfo: {\n          name: 'no-bind',\n        },\n        typeSystem: TypeSystem.UNKNOWN,\n      },\n      {\n        propDef: {\n          name: 'default',\n          type: {\n            summary: 'unknown',\n          },\n          defaultValue: null,\n        },\n        docgenInfo: {\n          name: 'default',\n          scoped: true,\n          bindings: [\n            {\n              name: 'num',\n              title: 'binding',\n            },\n          ],\n        },\n        typeSystem: TypeSystem.UNKNOWN,\n      },\n      {\n        propDef: {\n          name: 'named',\n          type: {\n            summary: 'unknown',\n          },\n          defaultValue: null,\n        },\n        docgenInfo: {\n          name: 'named',\n          scoped: true,\n          bindings: [\n            {\n              name: 'str',\n              title: 'binding',\n            },\n          ],\n        },\n        typeSystem: TypeSystem.UNKNOWN,\n      },\n      {\n        propDef: {\n          name: 'vbind',\n          type: {\n            summary: 'unknown',\n          },\n          defaultValue: null,\n        },\n        docgenInfo: {\n          name: 'vbind',\n          scoped: true,\n          bindings: [\n            {\n              name: 'num',\n              title: 'binding',\n            },\n            {\n              name: 'str',\n              title: 'binding',\n            },\n          ],\n        },\n        typeSystem: TypeSystem.UNKNOWN,\n      },\n    ],\n  },\n  expose: {\n    component: {\n      __docgenInfo: {\n        exportName: 'default',\n        displayName: 'component',\n        description: '',\n        tags: {},\n        expose: [\n          {\n            name: 'label',\n            description: 'a label string',\n          },\n          {\n            name: 'count',\n            description: 'a count number',\n          },\n        ],\n      },\n    },\n    extractedProps: [\n      {\n        propDef: {\n          name: 'label',\n          type: {\n            summary: 'unknown',\n          },\n          description: 'a label string',\n          defaultValue: null,\n        },\n        docgenInfo: {\n          name: 'label',\n          description: 'a label string',\n        },\n        typeSystem: TypeSystem.UNKNOWN,\n      },\n      {\n        propDef: {\n          name: 'count',\n          type: {\n            summary: 'unknown',\n          },\n          description: 'a count number',\n          defaultValue: null,\n        },\n        docgenInfo: {\n          name: 'count',\n          description: 'a count number',\n        },\n        typeSystem: TypeSystem.UNKNOWN,\n      },\n    ],\n  },\n};\n"
  },
  {
    "path": "code/renderers/vue3/src/entry-preview-docs.ts",
    "content": "import { sourceDecorator } from './docs/sourceDecorator.ts';\n\nexport const decorators = [sourceDecorator];\n"
  },
  {
    "path": "code/renderers/vue3/src/entry-preview.ts",
    "content": "import { enhanceArgTypes, extractComponentDescription } from 'storybook/internal/docs-tools';\nimport type { ArgTypesEnhancer } from 'storybook/internal/types';\n\nimport { extractArgTypes } from './extractArgTypes.ts';\nimport type { VueRenderer } from './types.ts';\n\nexport { render, renderToCanvas } from './render.ts';\nexport { decorateStory as applyDecorators } from './decorateStory.ts';\nexport { mount } from './mount.ts';\n\nexport const parameters = {\n  renderer: 'vue3',\n  docs: {\n    story: { inline: true },\n    extractArgTypes,\n    extractComponentDescription,\n  },\n};\n\nexport const argTypesEnhancers: ArgTypesEnhancer<VueRenderer>[] = [enhanceArgTypes];\n"
  },
  {
    "path": "code/renderers/vue3/src/extractArgTypes.test.ts",
    "content": "import type { Mock } from 'vitest';\nimport { beforeEach, describe, expect, it, vi, vitest } from 'vitest';\n\nimport { extractComponentProps, hasDocgen } from 'storybook/internal/docs-tools';\n\nimport {\n  mockExtractComponentEventsReturn,\n  mockExtractComponentPropsReturn,\n  mockExtractComponentSlotsReturn,\n  referenceTypeEvents,\n  referenceTypeProps,\n  templateSlots,\n  vueDocgenMocks,\n} from './docs/tests-meta-components/meta-components.ts';\nimport { extractArgTypes } from './extractArgTypes.ts';\n\nvitest.mock('storybook/internal/docs-tools', async (importOriginal) => {\n  const module: Record<string, unknown> = await importOriginal();\n  return {\n    ...module,\n    extractComponentProps: vi.fn(),\n    hasDocgen: vi.fn(),\n  };\n});\n\ndescribe('extractArgTypes (vue-docgen-api)', () => {\n  beforeEach(() => {\n    vi.resetAllMocks();\n  });\n\n  it('should return null if component does not contain docs', () => {\n    (hasDocgen as unknown as Mock).mockReturnValueOnce(false);\n    (extractComponentProps as Mock).mockReturnValueOnce([] as any);\n\n    expect(extractArgTypes({} as any)).toBeNull();\n  });\n\n  it('should extract props for component', () => {\n    const component = referenceTypeProps;\n    (hasDocgen as unknown as Mock).mockReturnValueOnce(true);\n\n    (extractComponentProps as Mock).mockImplementation((_, section) => {\n      return section === 'props' ? mockExtractComponentPropsReturn : [];\n    });\n\n    const argTypes = extractArgTypes(component);\n\n    expect(argTypes).toMatchSnapshot();\n  });\n\n  it('should extract events for Vue component', () => {\n    const component = referenceTypeEvents;\n    (hasDocgen as unknown as Mock).mockReturnValueOnce(true);\n    (extractComponentProps as Mock).mockImplementation((_, section) => {\n      return section === 'events' ? mockExtractComponentEventsReturn : [];\n    });\n\n    const argTypes = extractArgTypes(component);\n\n    expect(argTypes).toMatchSnapshot();\n  });\n\n  it('should extract slots type for Vue component', () => {\n    const component = templateSlots;\n    (hasDocgen as unknown as Mock).mockReturnValueOnce(true);\n    (extractComponentProps as Mock).mockImplementation((_, section) => {\n      return section === 'slots' ? mockExtractComponentSlotsReturn : [];\n    });\n\n    const argTypes = extractArgTypes(component);\n\n    expect(argTypes).toMatchSnapshot();\n  });\n});\n\ndescribe('extractArgTypes (vue-docgen-api)', () => {\n  beforeEach(() => {\n    vi.resetAllMocks();\n  });\n\n  it('should extract props for component', async () => {\n    const component = vueDocgenMocks.props.component;\n    (hasDocgen as unknown as Mock).mockReturnValueOnce(true);\n\n    (extractComponentProps as Mock).mockImplementation((_, section) => {\n      return section === 'props' ? vueDocgenMocks.props.extractedProps : [];\n    });\n\n    const argTypes = extractArgTypes(component);\n\n    expect(argTypes).toMatchSnapshot();\n  });\n\n  it('should extract events for component', async () => {\n    const component = vueDocgenMocks.events.component;\n    (hasDocgen as unknown as Mock).mockReturnValueOnce(true);\n\n    (extractComponentProps as Mock).mockImplementation((_, section) => {\n      return section === 'events' ? vueDocgenMocks.events.extractedProps : [];\n    });\n\n    const argTypes = extractArgTypes(component);\n\n    expect(argTypes).toMatchSnapshot();\n  });\n\n  it('should extract slots for component', async () => {\n    const component = vueDocgenMocks.slots.component;\n    (hasDocgen as unknown as Mock).mockReturnValueOnce(true);\n\n    (extractComponentProps as Mock).mockImplementation((_, section) => {\n      return section === 'slots' ? vueDocgenMocks.slots.extractedProps : [];\n    });\n\n    const argTypes = extractArgTypes(component);\n\n    expect(argTypes).toMatchSnapshot();\n  });\n\n  it('should extract expose for component', async () => {\n    const component = vueDocgenMocks.expose.component;\n    (hasDocgen as unknown as Mock).mockReturnValueOnce(true);\n\n    (extractComponentProps as Mock).mockImplementation((_, section) => {\n      return section === 'expose' ? vueDocgenMocks.expose.extractedProps : [];\n    });\n\n    const argTypes = extractArgTypes(component);\n\n    expect(argTypes).toMatchSnapshot();\n  });\n});\n"
  },
  {
    "path": "code/renderers/vue3/src/extractArgTypes.ts",
    "content": "import type { ExtractedProp } from 'storybook/internal/docs-tools';\nimport {\n  type ArgTypesExtractor,\n  convert,\n  extractComponentProps,\n  hasDocgen,\n} from 'storybook/internal/docs-tools';\nimport type { SBType, StrictArgTypes, StrictInputType } from 'storybook/internal/types';\n\nimport type { VueDocgenInfo, VueDocgenInfoEntry, VueDocgenPlugin } from '@storybook/vue3-vite';\n\ntype PropertyMetaSchema = VueDocgenInfoEntry<'vue-component-meta', 'props'>['schema'];\n\n// \"exposed\" is used by the vue-component-meta plugin while \"expose\" is used by vue-docgen-api\nconst ARG_TYPE_SECTIONS = ['props', 'events', 'slots', 'exposed', 'expose'] as const;\n\nexport const extractArgTypes: ArgTypesExtractor = (component): StrictArgTypes | null => {\n  if (!hasDocgen<VueDocgenInfo<VueDocgenPlugin>>(component)) {\n    return null;\n  }\n\n  const usedDocgenPlugin: VueDocgenPlugin =\n    'exposed' in component.__docgenInfo ? 'vue-component-meta' : 'vue-docgen-api';\n\n  const argTypes: StrictArgTypes = {};\n\n  ARG_TYPE_SECTIONS.forEach((section) => {\n    const props = extractComponentProps(component, section);\n\n    props.forEach((extractedProp) => {\n      let argType: StrictInputType | undefined;\n\n      // use the corresponding extractor whether vue-docgen-api or vue-component-meta\n      // was used for the docinfo\n      if (usedDocgenPlugin === 'vue-docgen-api') {\n        const docgenInfo = extractedProp.docgenInfo as VueDocgenInfoEntry<'vue-docgen-api'>;\n        argType = extractFromVueDocgenApi(docgenInfo, section, extractedProp);\n      } else {\n        const docgenInfo =\n          extractedProp.docgenInfo as unknown as VueDocgenInfoEntry<'vue-component-meta'>;\n        argType = extractFromVueComponentMeta(docgenInfo, section);\n      }\n\n      // skip duplicate and global props\n\n      // skip duplicate and global props\n      if (!argType || argTypes[argType.name]) {\n        return;\n      }\n\n      // disable controls for events and exposed since they can not be controlled\n\n      // disable controls for events and exposed since they can not be controlled\n      const sectionsToDisableControls: (typeof section)[] = ['events', 'expose', 'exposed'];\n      if (sectionsToDisableControls.includes(section)) {\n        argType.control = { disable: true };\n      }\n\n      argTypes[argType.name] = argType;\n    });\n  });\n\n  return argTypes;\n};\n\n/**\n * Extracts the argType for a prop/event/slot/expose generated with \"vue-docgen-api\".\n *\n * @param docgenInfo __docgenInfo from \"vue-docgen-api\"\n * @param section Whether the arg is a prop, event, slot or expose\n * @param extractedProp Extracted prop, needed when \"section\" is \"slots\"\n */\nexport const extractFromVueDocgenApi = (\n  docgenInfo: VueDocgenInfoEntry<'vue-docgen-api'>,\n  section: (typeof ARG_TYPE_SECTIONS)[number],\n  extractedProp?: ExtractedProp\n): StrictInputType => {\n  let type: string | undefined;\n  let sbType: SBType | undefined;\n\n  if (section === 'events') {\n    const eventInfo = docgenInfo as VueDocgenInfoEntry<'vue-docgen-api', 'events'>;\n    type = eventInfo.type?.names.join();\n    sbType = { name: 'other', value: type ?? '', required: false };\n  }\n\n  if (section === 'slots') {\n    const slotInfo = docgenInfo as VueDocgenInfoEntry<'vue-docgen-api', 'slots'>;\n\n    // extract type of slot bindings/props\n    const slotBindings = slotInfo.bindings\n      ?.filter((binding) => !!binding.name)\n      .map((binding) => {\n        return `${binding.name}: ${binding.type?.name ?? 'unknown'}`;\n      })\n      .join('; ');\n\n    type = slotBindings ? `{ ${slotBindings} }` : undefined;\n    sbType = { name: 'other', value: type ?? '', required: false };\n  }\n\n  if (section === 'props') {\n    const propInfo = docgenInfo as VueDocgenInfoEntry<'vue-docgen-api', 'props'>;\n\n    type = propInfo.type?.name;\n    sbType = extractedProp ? convert(extractedProp.docgenInfo) : { name: 'other', value: type };\n\n    // try to get more specific types for array, union and intersection\n    // e.g. \"string[]\" instead of \"Array\"\n    if (\n      propInfo.type &&\n      'elements' in propInfo.type &&\n      Array.isArray(propInfo.type.elements) &&\n      propInfo.type.elements.length > 0\n    ) {\n      const elements = (propInfo.type.elements as { name: string }[]).map((i) => i.name);\n\n      if (type === 'Array') {\n        const arrayElements = elements.length === 1 ? elements[0] : `(${elements.join(' | ')})`;\n        type = `${arrayElements}[]`;\n      }\n\n      if (type === 'union') {\n        type = elements.join(' | ');\n      } else if (type === 'intersection') {\n        type = elements.join(' & ');\n      }\n    }\n  }\n\n  const required = 'required' in docgenInfo ? (docgenInfo.required ?? false) : false;\n\n  return {\n    name: docgenInfo.name,\n    description: docgenInfo.description,\n    type: sbType ? { ...sbType, required } : { name: 'other', value: type ?? '' },\n    table: {\n      type: type ? { summary: type } : undefined,\n      defaultValue: extractedProp?.propDef.defaultValue ?? undefined,\n      jsDocTags: extractedProp?.propDef.jsDocTags,\n      category: section,\n    },\n  };\n};\n\n/**\n * Extracts the argType for a prop/event/slot/exposed generated with \"vue-component-meta\".\n *\n * @param docgenInfo __docgenInfo from \"vue-component-meta\"\n * @param section Whether the arg is a prop, event, slot or exposed\n */\nexport const extractFromVueComponentMeta = (\n  docgenInfo: VueDocgenInfoEntry<'vue-component-meta'>,\n  section: (typeof ARG_TYPE_SECTIONS)[number]\n): StrictInputType | undefined => {\n  // ignore global props\n\n  // ignore global props\n  if ('global' in docgenInfo && docgenInfo.global) {\n    return;\n  }\n\n  const tableType = { summary: docgenInfo.type.replace(' | undefined', '') };\n\n  if (section === 'props') {\n    const propInfo = docgenInfo as VueDocgenInfoEntry<'vue-component-meta', 'props'>;\n    const defaultValue = propInfo.default ? { summary: propInfo.default } : undefined;\n\n    return {\n      name: propInfo.name,\n      description: formatDescriptionWithTags(propInfo.description, propInfo.tags),\n      defaultValue,\n      type: convertVueComponentMetaProp(propInfo),\n      table: {\n        type: tableType,\n        defaultValue,\n        category: section,\n      },\n    };\n  } else {\n    return {\n      name: docgenInfo.name,\n      description: 'description' in docgenInfo ? docgenInfo.description : '',\n      type: { name: 'other', value: docgenInfo.type },\n      table: { type: tableType, category: section },\n    };\n  }\n};\n\n/** Converts the given prop info that was generated with \"vue-component-meta\" into a SBType. */\nexport const convertVueComponentMetaProp = (\n  propInfo: Pick<VueDocgenInfoEntry<'vue-component-meta', 'props'>, 'schema' | 'required' | 'type'>\n): SBType => {\n  const schema = propInfo.schema;\n  const required = propInfo.required;\n  const fallbackSbType: SBType = { name: 'other', value: propInfo.type, required };\n\n  const KNOWN_SCHEMAS = ['string', 'number', 'function', 'boolean', 'symbol'] as const;\n  type KnownSchema = (typeof KNOWN_SCHEMAS)[number];\n\n  if (typeof schema === 'string') {\n    if (KNOWN_SCHEMAS.includes(schema as KnownSchema)) {\n      return { name: schema as KnownSchema, required };\n    }\n    return fallbackSbType;\n  }\n\n  switch (schema.kind) {\n    case 'enum': {\n      // filter out empty or \"undefined\" for optional props\n      let definedSchemas = schema.schema?.filter((item) => item !== 'undefined') ?? [];\n\n      if (isBooleanSchema(definedSchemas)) {\n        return { name: 'boolean', required };\n      }\n\n      if (isLiteralUnionSchema(definedSchemas) || isEnumSchema(definedSchemas)) {\n        // remove quotes from literals\n        const literals = definedSchemas.map((literal) => literal.replace(/\"/g, ''));\n        return { name: 'enum', value: literals, required };\n      }\n\n      if (definedSchemas.length === 1) {\n        return convertVueComponentMetaProp({\n          schema: definedSchemas[0],\n          type: propInfo.type,\n          required,\n        });\n      }\n\n      // for union types like \"string | number | boolean\",\n      // the schema will be \"string | number | true | false\"\n      // so we need to replace \"true | false\" with boolean\n      if (\n        definedSchemas.length > 2 &&\n        definedSchemas.includes('true') &&\n        definedSchemas.includes('false')\n      ) {\n        definedSchemas = definedSchemas.filter((i) => i !== 'true' && i !== 'false');\n        definedSchemas.push('boolean');\n      }\n\n      // recursively convert every type of the union\n      return {\n        name: 'union',\n        value: definedSchemas.map((i) => {\n          if (typeof i === 'object') {\n            return convertVueComponentMetaProp({\n              schema: i,\n              type: i.type,\n              required: false,\n            });\n          } else {\n            return convertVueComponentMetaProp({ schema: i, type: i, required: false });\n          }\n        }),\n        required,\n      };\n    }\n\n    case 'array': {\n      // filter out empty or \"undefined\" for optional props\n      const definedSchemas = schema.schema?.filter((item) => item !== 'undefined') ?? [];\n\n      if (definedSchemas.length === 0) {\n        return fallbackSbType;\n      }\n\n      if (definedSchemas.length === 1) {\n        return {\n          name: 'array',\n          value: convertVueComponentMetaProp({\n            schema: definedSchemas[0],\n            type: propInfo.type,\n            required: false,\n          }),\n          required,\n        };\n      }\n\n      // recursively convert every type of the array\n      // e.g. \"(string | number)[]\"\n      return {\n        name: 'union',\n        value: definedSchemas.map((i) => {\n          if (typeof i === 'object') {\n            return convertVueComponentMetaProp({\n              schema: i,\n              type: i.type,\n              required: false,\n            });\n          } else {\n            return convertVueComponentMetaProp({ schema: i, type: i, required: false });\n          }\n        }),\n        required,\n      };\n    }\n\n    case 'object':\n      return {\n        name: 'object',\n        // while Storybook generates simple JSON object controls, nested schemas don't have specialized controls\n        // so we don't need to recursively map the object schema here\n        value: {},\n        required,\n      };\n\n    default:\n      return fallbackSbType;\n  }\n};\n\n/** Adds the descriptions for the given tags if available. */\nconst formatDescriptionWithTags = (\n  description: string,\n  tags: VueDocgenInfoEntry<'vue-component-meta', 'props'>['tags']\n): string => {\n  if (!tags?.length || !description) {\n    return description ?? '';\n  }\n  const tagDescriptions = tags.map((tag) => `@${tag.name}: ${tag.text}`).join('<br>');\n  return `${tagDescriptions}<br><br>${description}`;\n};\n\n/**\n * Checks whether the given schemas are all literal union schemas.\n *\n * @example Foo | \"bar\" | \"baz\"\n */\nconst isLiteralUnionSchema = (schemas: PropertyMetaSchema[]): schemas is `\"${string}\"`[] => {\n  return schemas.every(\n    (schema) => typeof schema === 'string' && schema.startsWith('\"') && schema.endsWith('\"')\n  );\n};\n\n/**\n * Checks whether the given schemas are all enums.\n *\n * @example MyEnum.Foo, MyEnum.Bar\n */\nconst isEnumSchema = (schemas: PropertyMetaSchema[]): schemas is string[] => {\n  return schemas.every((schema) => typeof schema === 'string' && schema.includes('.'));\n};\n\n/**\n * Checks whether the given schemas are representing a boolean.\n *\n * @example\n *\n * ```\n * (true, false);\n * ```\n */\nconst isBooleanSchema = (\n  schemas: PropertyMetaSchema[]\n): schemas is ['true', 'false'] | ['false', 'true'] => {\n  return schemas.length === 2 && schemas.includes('true') && schemas.includes('false');\n};\n"
  },
  {
    "path": "code/renderers/vue3/src/globals.ts",
    "content": "import { global } from '@storybook/global';\n\nimport type { App } from 'vue';\n\nimport type { StoryContext } from './public-types.ts';\n\nconst { window: globalWindow } = global;\n\nglobalWindow.STORYBOOK_ENV = 'vue3';\nglobalWindow.PLUGINS_SETUP_FUNCTIONS ||= new Set<\n  (app: App<any>, context: StoryContext) => unknown\n>();\n"
  },
  {
    "path": "code/renderers/vue3/src/index.ts",
    "content": "import './globals.ts';\n\nexport { setup } from './render.ts';\nexport * from './public-types.ts';\nexport * from './portable-stories.ts';\n\nexport * from './preview.ts';\n\nexport type { VueTypes } from './types.ts';\n"
  },
  {
    "path": "code/renderers/vue3/src/mount.ts",
    "content": "import { type BaseAnnotations } from 'storybook/internal/types';\n\nimport { h } from 'vue';\n\nimport { type StoryContext, type VueRenderer } from './public-types.ts';\n\nexport const mount: BaseAnnotations<VueRenderer>['mount'] = (context: StoryContext) => {\n  return async (Component, options) => {\n    if (Component) {\n      context.originalStoryFn = () => () => h(Component, options?.props, options?.slots);\n    }\n    await context.renderToCanvas();\n    return context.canvas;\n  };\n};\n"
  },
  {
    "path": "code/renderers/vue3/src/playwright.ts",
    "content": "export { createPlaywrightTest as createTest } from 'storybook/preview-api';\n"
  },
  {
    "path": "code/renderers/vue3/src/portable-stories.ts",
    "content": "import type {\n  Args,\n  ComposedStoryFn,\n  NamedOrDefaultProjectAnnotations,\n  NormalizedProjectAnnotations,\n  ProjectAnnotations,\n  Store_CSFExports,\n  StoriesWithPartialProps,\n  StoryAnnotationsOrFn,\n} from 'storybook/internal/types';\n\nimport {\n  composeStories as originalComposeStories,\n  composeStory as originalComposeStory,\n  setProjectAnnotations as originalSetProjectAnnotations,\n  setDefaultProjectAnnotations,\n} from 'storybook/preview-api';\nimport { h } from 'vue';\n\nimport * as defaultProjectAnnotations from './entry-preview.ts';\nimport type { Meta } from './public-types.ts';\nimport type { VueRenderer } from './types.ts';\n\ntype JSXAble<TElement> = TElement & {\n  new (...args: any[]): any;\n  $props: any;\n};\ntype MapToJSXAble<T> = {\n  [K in keyof T]: JSXAble<T[K]>;\n};\n\n/**\n * Function that sets the globalConfig of your Storybook. The global config is the preview module of\n * your .storybook folder.\n *\n * It should be run a single time, so that your global config (e.g. decorators) is applied to your\n * stories when using `composeStories` or `composeStory`.\n *\n * Example:\n *\n * ```jsx\n * // setup-file.js\n * import { setProjectAnnotations } from '@storybook/vue3';\n * import projectAnnotations from './.storybook/preview';\n *\n * setProjectAnnotations(projectAnnotations);\n * ```\n *\n * @param projectAnnotations - E.g. (import projectAnnotations from '../.storybook/preview')\n */\nexport function setProjectAnnotations(\n  projectAnnotations:\n    | NamedOrDefaultProjectAnnotations<any>\n    | NamedOrDefaultProjectAnnotations<any>[]\n): NormalizedProjectAnnotations<VueRenderer> {\n  setDefaultProjectAnnotations(vueProjectAnnotations);\n  return originalSetProjectAnnotations(\n    projectAnnotations\n  ) as NormalizedProjectAnnotations<VueRenderer>;\n}\n\n// This will not be necessary once we have auto preset loading\nexport const vueProjectAnnotations: ProjectAnnotations<VueRenderer> = {\n  ...defaultProjectAnnotations,\n  /** @deprecated */\n  renderToCanvas: (renderContext, canvasElement) => {\n    if (renderContext.storyContext.testingLibraryRender == null) {\n      return defaultProjectAnnotations.renderToCanvas(renderContext, canvasElement);\n    }\n    const {\n      storyFn,\n      storyContext: { testingLibraryRender: render },\n    } = renderContext;\n    const { unmount } = render(storyFn(), { container: canvasElement });\n    return unmount;\n  },\n};\n\n/**\n * Function that will receive a story along with meta (e.g. a default export from a .stories file)\n * and optionally projectAnnotations e.g. (import * from '../.storybook/preview) and will return a\n * composed component that has all args/parameters/decorators/etc combined and applied to it.\n *\n * It's very useful for reusing a story in scenarios outside of Storybook like unit testing.\n *\n * Example:\n *\n * ```jsx\n * import { render } from '@testing-library/vue';\n * import { composeStory } from '@storybook/vue3';\n * import Meta, { Primary as PrimaryStory } from './Button.stories';\n *\n * const Primary = composeStory(PrimaryStory, Meta);\n *\n * test('renders primary button with Hello World', () => {\n *   const { getByText } = render(Primary, { props: { label: 'Hello world' } });\n *   expect(getByText(/Hello world/i)).not.toBeNull();\n * });\n * ```\n *\n * @param story\n * @param componentAnnotations - E.g. (import Meta from './Button.stories')\n * @param [projectAnnotations] - E.g. (import * as projectAnnotations from '../.storybook/preview')\n *   this can be applied automatically if you use `setProjectAnnotations` in your setup files.\n * @param [exportsName] - In case your story does not contain a name and you want it to have a name.\n */\nexport function composeStory<TArgs extends Args = Args>(\n  story: StoryAnnotationsOrFn<VueRenderer, TArgs>,\n  componentAnnotations: Meta<TArgs | any>,\n  projectAnnotations?: ProjectAnnotations<VueRenderer>,\n  exportsName?: string\n): JSXAble<ComposedStoryFn<VueRenderer, Partial<TArgs>>> {\n  const composedStory = originalComposeStory<VueRenderer, TArgs>(\n    story as StoryAnnotationsOrFn<VueRenderer, Args>,\n    componentAnnotations,\n    projectAnnotations,\n    globalThis.globalProjectAnnotations ?? vueProjectAnnotations,\n    exportsName\n  );\n\n  // Returning h(composedStory) instead makes it an actual Vue component renderable by @testing-library/vue, Playwright CT, etc.\n  const renderable = (...args: Parameters<typeof composedStory>) => h(composedStory(...args));\n  Object.assign(renderable, composedStory);\n\n  // typing this as newable means TS allows it to be used as a JSX element\n  // TODO: we should do the same for composeStories as well\n  return renderable as unknown as JSXAble<typeof composedStory>;\n}\n\n/**\n * Function that will receive a stories import (e.g. `import * as stories from './Button.stories'`)\n * and optionally projectAnnotations (e.g. `import * from '../.storybook/preview`) and will return\n * an object containing all the stories passed, but now as a composed component that has all\n * args/parameters/decorators/etc combined and applied to it.\n *\n * It's very useful for reusing stories in scenarios outside of Storybook like unit testing.\n *\n * Example:\n *\n * ```jsx\n * import { render } from '@testing-library/vue';\n * import { composeStories } from '@storybook/vue3';\n * import * as stories from './Button.stories';\n *\n * const { Primary, Secondary } = composeStories(stories);\n *\n * test('renders primary button with Hello World', () => {\n *   const { getByText } = render(Primary, { props: { label: 'Hello world' } });\n *   expect(getByText(/Hello world/i)).not.toBeNull();\n * });\n * ```\n *\n * @param csfExports - E.g. (import * as stories from './Button.stories')\n * @param [projectAnnotations] - E.g. (import * as projectAnnotations from '../.storybook/preview')\n *   this can be applied automatically if you use `setProjectAnnotations` in your setup files.\n */\nexport function composeStories<TModule extends Store_CSFExports<VueRenderer, any>>(\n  csfExports: TModule,\n  projectAnnotations?: ProjectAnnotations<VueRenderer>\n) {\n  // @ts-expect-error Deep down TRenderer['canvasElement'] resolves to canvasElement: unknown but VueRenderer uses WebRenderer where canvasElement is HTMLElement, so the types clash\n  const composedStories = originalComposeStories(csfExports, projectAnnotations, composeStory);\n\n  return composedStories as unknown as MapToJSXAble<\n    Omit<StoriesWithPartialProps<VueRenderer, TModule>, keyof Store_CSFExports>\n  >;\n}\n"
  },
  {
    "path": "code/renderers/vue3/src/preset.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport type { PresetProperty } from 'storybook/internal/types';\n\nexport const previewAnnotations: PresetProperty<'previewAnnotations'> = async (\n  input = [],\n  options\n) => {\n  const docsEnabled = Object.keys(await options.presets.apply('docs', {}, options)).length > 0;\n  const result: string[] = [];\n\n  return result\n    .concat(input)\n    .concat([fileURLToPath(import.meta.resolve('@storybook/vue3/entry-preview'))])\n    .concat(\n      docsEnabled ? [fileURLToPath(import.meta.resolve('@storybook/vue3/entry-preview-docs'))] : []\n    );\n};\n"
  },
  {
    "path": "code/renderers/vue3/src/preview.ts",
    "content": "import type {\n  AddonTypes,\n  InferTypes,\n  Meta,\n  Preview,\n  PreviewAddon,\n  Story,\n} from 'storybook/internal/csf';\nimport { definePreview as definePreviewBase } from 'storybook/internal/csf';\nimport type {\n  ArgsStoryFn,\n  ComponentAnnotations,\n  DecoratorFunction,\n  ProjectAnnotations,\n  Renderer,\n  StoryAnnotations,\n} from 'storybook/internal/types';\n\nimport type { RemoveIndexSignature, SetOptional, Simplify, UnionToIntersection } from 'type-fest';\n\nimport * as vueAnnotations from './entry-preview.ts';\nimport * as vueDocsAnnotations from './entry-preview-docs.ts';\nimport { type Args, type ComponentPropsAndSlots } from './public-types.ts';\nimport { type VueTypes } from './types.ts';\n\n/**\n * Creates a Vue3-specific preview configuration with CSF factories support.\n *\n * This function wraps the base `definePreview` and adds Vue3-specific annotations for rendering and\n * documentation. It returns a `VuePreview` that provides type-safe `meta()` and `story()` factory\n * methods.\n *\n * @example\n *\n * ```ts\n * // .storybook/preview.ts\n * import { definePreview } from '@storybook/vue3';\n *\n * export const preview = definePreview({\n *   addons: [],\n *   parameters: { layout: 'centered' },\n * });\n * ```\n */\nexport function __definePreview<Addons extends PreviewAddon<never>[]>(\n  input: { addons: Addons } & ProjectAnnotations<VueTypes & InferTypes<Addons>>\n): VuePreview<VueTypes & InferTypes<Addons>> {\n  const preview = definePreviewBase({\n    ...input,\n    addons: [vueAnnotations, vueDocsAnnotations, ...(input.addons ?? [])],\n  }) as unknown as VuePreview<VueTypes & InferTypes<Addons>>;\n\n  return preview;\n}\n\ntype InferArgs<TArgs, T, Decorators> = Simplify<\n  TArgs & Simplify<RemoveIndexSignature<DecoratorsArgs<VueTypes & T, Decorators>>>\n>;\n\ntype InferVueTypes<T, TArgs, Decorators> = VueTypes &\n  T & { args: Simplify<InferArgs<TArgs, T, Decorators>> };\n\n/**\n * Vue3-specific Preview interface that provides type-safe CSF factory methods.\n *\n * Use `preview.meta()` to create a meta configuration for a component, and then `meta.story()` to\n * create individual stories. The type system will infer args from the component props, slots,\n * decorators, and any addon types.\n *\n * @example\n *\n * ```ts\n * const meta = preview.meta({ component: Button });\n * export const Primary = meta.story({ args: { label: 'Click me' } });\n * ```\n */\nexport interface VuePreview<T extends AddonTypes> extends Preview<VueTypes & T> {\n  /**\n   * Narrows the type of the preview to include additional type information. This is useful when you\n   * need to add args that aren't inferred from the component.\n   *\n   * @example\n   *\n   * ```ts\n   * const meta = preview.type<{ args: { theme: 'light' | 'dark' } }>().meta({\n   *   component: Button,\n   * });\n   * ```\n   */\n  type<R>(): VuePreview<T & R>;\n\n  meta<\n    C,\n    Decorators extends DecoratorFunction<VueTypes & T, any>,\n    // Try to make Exact<Partial<TArgs>, TMetaArgs> work\n    TMetaArgs extends Partial<ComponentPropsAndSlots<C> & T['args']>,\n  >(\n    meta: {\n      component?: C;\n      args?: TMetaArgs;\n      decorators?: Decorators | Decorators[];\n    } & Omit<\n      ComponentAnnotations<VueTypes & T, ComponentPropsAndSlots<C> & T['args']>,\n      'decorators' | 'component' | 'args'\n    >\n  ): VueMeta<\n    InferVueTypes<T, ComponentPropsAndSlots<C>, Decorators>,\n    Omit<ComponentAnnotations<InferVueTypes<T, ComponentPropsAndSlots<C>, Decorators>>, 'args'> & {\n      args: {} extends TMetaArgs ? {} : TMetaArgs;\n    }\n  >;\n\n  meta<\n    TArgs extends Args,\n    Decorators extends DecoratorFunction<VueTypes & T, any>,\n    // Try to make Exact<Partial<TArgs>, TMetaArgs> work\n    TMetaArgs extends Partial<TArgs>,\n  >(\n    meta: {\n      render?: ArgsStoryFn<VueTypes & T, TArgs>;\n      args?: TMetaArgs;\n      decorators?: Decorators | Decorators[];\n    } & Omit<\n      ComponentAnnotations<VueTypes & T, TArgs & T['args']>,\n      'decorators' | 'component' | 'args' | 'render'\n    >\n  ): VueMeta<\n    InferVueTypes<T, TArgs, Decorators>,\n    Omit<ComponentAnnotations<InferVueTypes<T, TArgs, Decorators>>, 'args'> & {\n      args: {} extends TMetaArgs ? {} : TMetaArgs;\n    }\n  >;\n}\n\n/** Extracts and unions all args types from an array of decorators. */\ntype DecoratorsArgs<TRenderer extends Renderer, Decorators> = UnionToIntersection<\n  Decorators extends DecoratorFunction<TRenderer, infer TArgs> ? TArgs : unknown\n>;\n\n/**\n * Vue3-specific Meta interface returned by `preview.meta()`.\n *\n * Provides the `story()` method to create individual stories with proper type inference. Args\n * provided in meta become optional in stories, while missing required args must be provided at the\n * story level.\n */\nexport interface VueMeta<T extends VueTypes, MetaInput extends ComponentAnnotations<T>>\n  // @ts-expect-error VueMeta requires two type parameters, but Meta's constraints differ\n  extends Meta<T, MetaInput> {\n  /**\n   * Creates a story with a custom render function that takes no args.\n   *\n   * This overload allows you to define a story using just a render function or an object with a\n   * render function that doesn't depend on args. Since the render function doesn't use args, no\n   * args need to be provided regardless of what's required by the component.\n   *\n   * @example\n   *\n   * ```ts\n   * // Using just a render function\n   * export const CustomRender = meta.story(() => h('div', 'Custom content'));\n   *\n   * // Using defineComponent\n   * export const WithDefineComponent = meta.story(() =>\n   *   defineComponent({\n   *     template: '<div>Static component</div>',\n   *   })\n   * );\n   * ```\n   */\n  story<\n    TInput extends\n      | (() => VueTypes['storyResult'])\n      | (StoryAnnotations<T, T['args']> & {\n          render: () => VueTypes['storyResult'];\n        }),\n  >(\n    story: TInput\n  ): VueStory<T, TInput extends () => VueTypes['storyResult'] ? { render: TInput } : TInput>;\n\n  /**\n   * Creates a story with custom configuration including args, decorators, or other annotations.\n   *\n   * This is the primary overload for defining stories. Args that were already provided in meta\n   * become optional, while any remaining required args must be specified here.\n   *\n   * @example\n   *\n   * ```ts\n   * // Provide required args not in meta\n   * export const Primary = meta.story({\n   *   args: { label: 'Click me', disabled: false },\n   * });\n   *\n   * // Override meta args and add story-specific configuration\n   * export const Disabled = meta.story({\n   *   args: { disabled: true },\n   *   decorators: [withCustomWrapper],\n   * });\n   * ```\n   */\n  story<\n    TInput extends Simplify<\n      StoryAnnotations<\n        T,\n        T['args'],\n        SetOptional<T['args'], keyof T['args'] & keyof MetaInput['args']>\n      >\n    >,\n  >(\n    story: TInput\n  ): VueStory<T, TInput>;\n\n  /**\n   * Creates a story with no additional configuration.\n   *\n   * This overload is only available when all required args have been provided in meta. The\n   * conditional type `Partial<T['args']> extends SetOptional<...>` checks if the remaining required\n   * args (after accounting for args provided in meta) are all optional. If so, the function accepts\n   * zero arguments `[]`. Otherwise, it requires `[never]` which makes this overload unmatchable,\n   * forcing the user to provide args.\n   *\n   * @example\n   *\n   * ```ts\n   * // When meta provides all required args, story() can be called with no arguments\n   * const meta = preview.meta({ component: Button, args: { label: 'Hi', disabled: false } });\n   * export const Default = meta.story(); // Valid - all args provided in meta\n   * ```\n   */\n  story(\n    ..._args: Partial<T['args']> extends SetOptional<\n      T['args'],\n      keyof T['args'] & keyof MetaInput['args']\n    >\n      ? []\n      : [never]\n  ): VueStory<T, {}>;\n}\n\n/**\n * Vue3-specific Story interface returned by `meta.story()`.\n *\n * Represents a single story with its configuration and provides access to the composed story for\n * testing via `story.run()`.\n */\nexport interface VueStory<\n  T extends VueTypes,\n  TInput extends StoryAnnotations<T, T['args']>,\n> extends Story<T, TInput> {}\n"
  },
  {
    "path": "code/renderers/vue3/src/public-types.test.ts",
    "content": "// this file tests Typescript types that's why there are no assertions\nimport { describe, it } from 'vitest';\n\nimport { satisfies } from 'storybook/internal/common';\nimport type { Canvas, ComponentAnnotations, StoryAnnotations } from 'storybook/internal/types';\n\nimport { expectTypeOf } from 'expect-type';\nimport type { SetOptional } from 'type-fest';\nimport { h } from 'vue';\n\nimport BaseLayout from './__tests__/BaseLayout.vue';\nimport Button from './__tests__/Button.vue';\nimport Decorator2TsVue from './__tests__/Decorator2.vue';\nimport DecoratorTsVue from './__tests__/Decorator.vue';\nimport type { ComponentPropsAndSlots, Decorator, Meta, StoryObj } from './public-types.ts';\nimport type { VueRenderer } from './types.ts';\n\ntype ButtonProps = ComponentPropsAndSlots<typeof Button>;\n\ndescribe('Meta', () => {\n  it('Generic parameter of Meta can be a component', () => {\n    const meta: Meta<typeof Button> = {\n      component: Button,\n      args: { label: 'good', disabled: false },\n    };\n\n    expectTypeOf(meta).toMatchTypeOf<ComponentAnnotations<VueRenderer, ButtonProps>>();\n  });\n\n  it('Generic parameter of Meta can be the props of the component', () => {\n    const meta: Meta<{ disabled: boolean; label: string }> = {\n      component: Button,\n      args: { label: 'good', disabled: false },\n    };\n\n    expectTypeOf(meta).toMatchTypeOf<\n      ComponentAnnotations<VueRenderer, { disabled: boolean; label: string }>\n    >();\n  });\n\n  it('Events are inferred from component', () => {\n    const meta: Meta<typeof Button> = {\n      component: Button,\n      args: {\n        label: 'good',\n        disabled: false,\n        onMyChangeEvent: (value) => {\n          expectTypeOf(value).toMatchTypeOf<number>();\n        },\n      },\n      render: (args) => {\n        return h(Button, {\n          ...args,\n          onMyChangeEvent: (value) => {\n            expectTypeOf(value).toMatchTypeOf<number>();\n          },\n        });\n      },\n    };\n    expectTypeOf(meta).toMatchTypeOf<Meta<typeof Button>>();\n  });\n});\n\ndescribe('StoryObj', () => {\n  it('✅ Required args may be provided partial in meta and the story', () => {\n    const meta = satisfies<Meta<typeof Button>>()({\n      component: Button,\n      args: { label: 'good' },\n    });\n\n    type Actual = StoryObj<typeof meta>;\n    type Expected = StoryAnnotations<VueRenderer, ButtonProps, SetOptional<ButtonProps, 'label'>>;\n    expectTypeOf<Actual>().toMatchTypeOf<Expected>();\n  });\n\n  it('❌ The combined shape of meta args and story args must match the required args.', () => {\n    {\n      const meta = satisfies<Meta<typeof Button>>()({ component: Button });\n\n      type Expected = StoryAnnotations<VueRenderer, ButtonProps, ButtonProps>;\n      expectTypeOf<StoryObj<typeof meta>>().toMatchTypeOf<Expected>();\n    }\n    {\n      const meta = satisfies<Meta<typeof Button>>()({\n        component: Button,\n        args: { label: 'good' },\n      });\n      // @ts-expect-error disabled not provided ❌\n      const Basic: StoryObj<typeof meta> = {};\n\n      type Expected = StoryAnnotations<VueRenderer, ButtonProps, SetOptional<ButtonProps, 'label'>>;\n      expectTypeOf(Basic).toMatchTypeOf<Expected>();\n    }\n    {\n      const meta = satisfies<Meta<{ label: string; disabled: boolean }>>()({ component: Button });\n      const Basic: StoryObj<typeof meta> = {\n        // @ts-expect-error disabled not provided ❌\n        args: { label: 'good' },\n      };\n\n      type Expected = StoryAnnotations<VueRenderer, ButtonProps, ButtonProps>;\n      expectTypeOf(Basic).toMatchTypeOf<Expected>();\n    }\n  });\n\n  it('Component can be used as generic parameter for StoryObj', () => {\n    expectTypeOf<StoryObj<typeof Button>>().toMatchTypeOf<\n      StoryAnnotations<VueRenderer, ButtonProps>\n    >();\n  });\n});\n\ntype ThemeData = 'light' | 'dark';\n\ndescribe('Story args can be inferred', () => {\n  it('Correct args are inferred when type is widened for render function', () => {\n    type Props = ButtonProps & { theme: ThemeData };\n\n    const meta = satisfies<Meta<Props>>()({\n      component: Button,\n      args: { disabled: false },\n      render: (args) => {\n        return h('div', [h('div', `Use the theme ${args.theme}`), h(Button, args)]);\n      },\n    });\n\n    const Basic: StoryObj<typeof meta> = { args: { theme: 'light', label: 'good' } };\n\n    type Expected = StoryAnnotations<VueRenderer, Props, SetOptional<Props, 'disabled'>>;\n    expectTypeOf(Basic).toMatchTypeOf<Expected>();\n  });\n\n  const withDecorator: Decorator<{ decoratorArg: string }> = (\n    storyFn,\n    { args: { decoratorArg } }\n  ) => h(DecoratorTsVue, { decoratorArg }, h(storyFn()));\n\n  it('Correct args are inferred when type is widened for decorators', () => {\n    type Props = ButtonProps & { decoratorArg: string };\n\n    const meta = satisfies<Meta<Props>>()({\n      component: Button,\n      args: { disabled: false },\n      decorators: [withDecorator],\n    });\n\n    const Basic: StoryObj<typeof meta> = { args: { decoratorArg: 'title', label: 'good' } };\n\n    type Expected = StoryAnnotations<VueRenderer, Props, SetOptional<Props, 'disabled'>>;\n    expectTypeOf(Basic).toMatchTypeOf<Expected>();\n  });\n\n  it('Correct args are inferred when type is widened for multiple decorators', () => {\n    type Props = ButtonProps & {\n      decoratorArg: string;\n      decoratorArg2: string;\n    };\n\n    const secondDecorator: Decorator<{ decoratorArg2: string }> = (\n      storyFn,\n      { args: { decoratorArg2 } }\n    ) => h(Decorator2TsVue, { decoratorArg2 }, h(storyFn()));\n\n    const meta = satisfies<Meta<Props>>()({\n      component: Button,\n      args: { disabled: false },\n      decorators: [withDecorator, secondDecorator],\n    });\n\n    const Basic: StoryObj<typeof meta> = {\n      args: { decoratorArg: '', decoratorArg2: '', label: 'good' },\n    };\n\n    type Expected = StoryAnnotations<VueRenderer, Props, SetOptional<Props, 'disabled'>>;\n    expectTypeOf(Basic).toMatchTypeOf<Expected>();\n  });\n});\n\nit('Infer type of slots', () => {\n  const meta = {\n    component: BaseLayout,\n  } satisfies Meta<typeof BaseLayout>;\n\n  const Basic: StoryObj<typeof meta> = {\n    args: {\n      otherProp: true,\n      header: ({ title }) =>\n        h({\n          components: { Button },\n          template: `<Button :primary='true' label='${title}'></Button>`,\n        }),\n      default: 'default slot',\n      footer: h(Button, { disabled: true, label: 'footer' }),\n    },\n  };\n\n  type Props = ComponentPropsAndSlots<typeof BaseLayout>;\n\n  type Expected = StoryAnnotations<VueRenderer, Props, Props>;\n  expectTypeOf(Basic).toMatchTypeOf<Expected>();\n});\n\nit('mount accepts a Component', () => {\n  const Basic: StoryObj<typeof Button> = {\n    async play({ mount }) {\n      const canvas = await mount(Button, { props: { label: 'label', disabled: true } });\n      expectTypeOf(canvas).toMatchTypeOf<Canvas>();\n    },\n  };\n  expectTypeOf(Basic).toMatchTypeOf<StoryObj<typeof Button>>();\n});\n"
  },
  {
    "path": "code/renderers/vue3/src/public-types.ts",
    "content": "import type {\n  AnnotatedStoryFn,\n  Args,\n  ArgsFromMeta,\n  ArgsStoryFn,\n  ComponentAnnotations,\n  DecoratorFunction,\n  StoryContext as GenericStoryContext,\n  LoaderFunction,\n  ProjectAnnotations,\n  StoryAnnotations,\n  StrictArgs,\n} from 'storybook/internal/types';\n\nimport type { Constructor, RemoveIndexSignature, SetOptional, Simplify } from 'type-fest';\nimport type { FunctionalComponent, VNodeChild } from 'vue';\nimport type { ComponentProps, ComponentSlots } from 'vue-component-type-helpers';\n\nimport type { VueRenderer } from './types.ts';\n\nexport type { Args, ArgTypes, Parameters, StrictArgs } from 'storybook/internal/types';\nexport type { VueRenderer };\n\n/**\n * Metadata to configure the stories for a component.\n *\n * @see [Default export](https://storybook.js.org/docs/api/csf#default-export)\n */\nexport type Meta<TCmpOrArgs = Args> = ComponentAnnotations<\n  VueRenderer,\n  ComponentPropsOrProps<TCmpOrArgs>\n>;\n\n/**\n * Story function that represents a CSFv2 component example.\n *\n * @see [Named Story exports](https://storybook.js.org/docs/api/csf#named-story-exports)\n */\nexport type StoryFn<TCmpOrArgs = Args> = AnnotatedStoryFn<\n  VueRenderer,\n  ComponentPropsOrProps<TCmpOrArgs>\n>;\n\n/**\n * Story object that represents a CSFv3 component example.\n *\n * @see [Named Story exports](https://storybook.js.org/docs/api/csf#named-story-exports)\n */\nexport type StoryObj<TMetaOrCmpOrArgs = Args> = TMetaOrCmpOrArgs extends {\n  render?: ArgsStoryFn<VueRenderer, any>;\n  component?: infer Component;\n  args?: infer DefaultArgs;\n}\n  ? Simplify<\n      ComponentPropsAndSlots<Component> & ArgsFromMeta<VueRenderer, TMetaOrCmpOrArgs>\n    > extends infer TArgs\n    ? StoryAnnotations<\n        VueRenderer,\n        TArgs,\n        SetOptional<TArgs, Extract<keyof TArgs, keyof DefaultArgs>>\n      >\n    : never\n  : StoryAnnotations<VueRenderer, ComponentPropsOrProps<TMetaOrCmpOrArgs>>;\n\ntype ExtractSlots<C> = AllowNonFunctionSlots<Partial<RemoveIndexSignature<ComponentSlots<C>>>>;\n\ntype AllowNonFunctionSlots<Slots> = {\n  [K in keyof Slots]: Slots[K] | VNodeChild;\n};\n\nexport type ComponentPropsAndSlots<C> = ComponentProps<C> & ExtractSlots<C>;\n\ntype ComponentPropsOrProps<TCmpOrArgs> =\n  TCmpOrArgs extends Constructor<any>\n    ? ComponentPropsAndSlots<TCmpOrArgs>\n    : TCmpOrArgs extends FunctionalComponent<any>\n      ? ComponentPropsAndSlots<TCmpOrArgs>\n      : TCmpOrArgs;\n\nexport type Decorator<TArgs = StrictArgs> = DecoratorFunction<VueRenderer, TArgs>;\nexport type Loader<TArgs = StrictArgs> = LoaderFunction<VueRenderer, TArgs>;\nexport type StoryContext<TArgs = StrictArgs> = GenericStoryContext<VueRenderer, TArgs>;\nexport type Preview = ProjectAnnotations<VueRenderer>;\n"
  },
  {
    "path": "code/renderers/vue3/src/render.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport type { Args, Globals } from 'storybook/internal/types';\n\nimport { expectTypeOf } from 'expect-type';\nimport { computed, reactive } from 'vue';\n\nimport { updateArgs } from './render.ts';\n\ndescribe('Render Story', () => {\n  it('update reactive Args updateArgs()', () => {\n    const reactiveArgs = reactive({ argFoo: 'foo', argBar: 'bar' }); // get reference to reactiveArgs or create a new one;\n    expectTypeOf(reactiveArgs).toMatchTypeOf<Record<string, any>>();\n    expectTypeOf(reactiveArgs).toEqualTypeOf<{ argFoo: string; argBar: string }>();\n\n    const newArgs = { argFoo: 'foo2', argBar: 'bar2' };\n    updateArgs(reactiveArgs, newArgs);\n    expectTypeOf(reactiveArgs).toEqualTypeOf<{ argFoo: string; argBar: string }>();\n    expect(reactiveArgs).toEqual({ argFoo: 'foo2', argBar: 'bar2' });\n  });\n\n  it('update reactive Args component inherit objectArg updateArgs()', () => {\n    const reactiveArgs = reactive({ objectArg: { argFoo: 'foo', argBar: 'bar' } }); // get reference to reactiveArgs or create a new one;\n    expectTypeOf(reactiveArgs).toMatchTypeOf<Record<string, any>>();\n    expectTypeOf(reactiveArgs).toEqualTypeOf<{ objectArg: { argFoo: string; argBar: string } }>();\n\n    const newArgs = { argFoo: 'foo2', argBar: 'bar2' };\n    updateArgs<Args>(reactiveArgs, newArgs);\n    expectTypeOf(reactiveArgs).toEqualTypeOf<{ objectArg: { argFoo: string; argBar: string } }>();\n    expect(reactiveArgs).toEqual({\n      argFoo: 'foo2',\n      argBar: 'bar2',\n    });\n  });\n\n  it('update reactive Args component inherit objectArg', () => {\n    const reactiveArgs = reactive({ objectArg: { argFoo: 'foo' } }); // get reference to reactiveArgs or create a new one;\n    expectTypeOf(reactiveArgs).toMatchTypeOf<Record<string, any>>();\n    expectTypeOf(reactiveArgs).toEqualTypeOf<{ objectArg: { argFoo: string } }>();\n\n    const newArgs = { argFoo: 'foo2', argBar: 'bar2' };\n    updateArgs<Args>(reactiveArgs, newArgs);\n    expect(reactiveArgs).toEqual({ argFoo: 'foo2', argBar: 'bar2' });\n  });\n\n  it('update reactive Args component 2 object args  ->  updateArgs()', () => {\n    const reactiveArgs = reactive({\n      objectArg: { argFoo: 'foo' },\n      objectArg2: { argBar: 'bar' },\n    }); // get reference to reactiveArgs or create a new one;\n    expectTypeOf(reactiveArgs).toMatchTypeOf<Record<string, any>>();\n    expectTypeOf(reactiveArgs).toEqualTypeOf<{\n      objectArg: { argFoo: string };\n      objectArg2: { argBar: string };\n    }>();\n\n    const newArgs = { argFoo: 'foo2', argBar: 'bar2' };\n    updateArgs<Args>(reactiveArgs, newArgs);\n\n    expect(reactiveArgs).toEqual({\n      argFoo: 'foo2',\n      argBar: 'bar2',\n    });\n  });\n\n  it('update reactive Args component object with object  ->  updateArgs()', () => {\n    const reactiveArgs = reactive({\n      objectArg: { argFoo: 'foo' },\n    }); // get reference to reactiveArgs or create a new one;\n    expectTypeOf(reactiveArgs).toMatchTypeOf<Record<string, any>>();\n    expectTypeOf(reactiveArgs).toEqualTypeOf<{\n      objectArg: { argFoo: string };\n    }>();\n\n    const newArgs = { objectArg: { argFoo: 'bar' } };\n    updateArgs(reactiveArgs, newArgs);\n\n    expect(reactiveArgs).toEqual({ objectArg: { argFoo: 'bar' } });\n  });\n\n  it('update reactive Args component no arg with all args -> updateArgs()', () => {\n    const reactiveArgs = reactive({ objectArg: { argFoo: 'foo' } }); // get reference to reactiveArgs or create a new one;\n    expectTypeOf(reactiveArgs).toMatchTypeOf<Record<string, any>>();\n    expectTypeOf(reactiveArgs).toEqualTypeOf<{\n      objectArg: { argFoo: string };\n    }>();\n\n    const newArgs = { objectArg: { argFoo: 'bar' } };\n    updateArgs(reactiveArgs, newArgs);\n\n    expect(reactiveArgs).toEqual({ objectArg: { argFoo: 'bar' } });\n  });\n\n  it('update reactive Globals', async () => {\n    const reactiveGlobals = reactive<Globals>({ theme: 'light', locale: 'en' });\n\n    let observedTheme: string | undefined;\n    const watcher = computed(() => {\n      observedTheme = reactiveGlobals.theme as string;\n      return reactiveGlobals.theme;\n    });\n\n    expect(watcher.value).toBe('light');\n    expect(observedTheme).toBe('light');\n\n    updateArgs<Globals>(reactiveGlobals, { theme: 'dark', locale: 'en' });\n\n    expect(watcher.value).toBe('dark');\n    expect(observedTheme).toBe('dark');\n    expect(reactiveGlobals).toEqual({ theme: 'dark', locale: 'en' });\n  });\n});\n"
  },
  {
    "path": "code/renderers/vue3/src/render.ts",
    "content": "/* eslint-disable local-rules/no-uncategorized-errors */\nimport type { Globals } from 'storybook/internal/types';\nimport {\n  type Args,\n  type ArgsStoryFn,\n  type RenderContext,\n  type StoryContext,\n} from 'storybook/internal/types';\n\nimport type { PreviewWeb } from 'storybook/preview-api';\nimport type { App } from 'vue';\nimport { createApp, h, isReactive, isVNode, reactive } from 'vue';\n\nimport type { StoryFnVueReturnType, StoryID, VueRenderer } from './types.ts';\n\nexport const render: ArgsStoryFn<VueRenderer> = (props, context) => {\n  const { id, component: Component } = context;\n  if (!Component) {\n    throw new Error(\n      `Unable to render story ${id} as the component annotation is missing from the default export`\n    );\n  }\n\n  return () => h(Component, props, getSlots(props, context));\n};\n\nexport const setup = <AppHostElement = any>(\n  fn: (app: App<AppHostElement>, storyContext?: StoryContext<VueRenderer>) => unknown\n) => {\n  globalThis.PLUGINS_SETUP_FUNCTIONS ??= new Set();\n  globalThis.PLUGINS_SETUP_FUNCTIONS.add(fn);\n};\n\nconst runSetupFunctions = async (\n  app: App,\n  storyContext: StoryContext<VueRenderer>\n): Promise<void> => {\n  if (globalThis && globalThis.PLUGINS_SETUP_FUNCTIONS) {\n    await Promise.all([...globalThis.PLUGINS_SETUP_FUNCTIONS].map((fn) => fn(app, storyContext)));\n  }\n};\n\nconst map = new Map<\n  VueRenderer['canvasElement'] | StoryID,\n  {\n    vueApp: ReturnType<typeof createApp>;\n    reactiveArgs: Args;\n    reactiveGlobals: Globals;\n  }\n>();\n\nexport async function renderToCanvas(\n  { storyFn, forceRemount, showMain, showException, storyContext, id }: RenderContext<VueRenderer>,\n  canvasElement: VueRenderer['canvasElement']\n) {\n  const existingApp = map.get(canvasElement);\n\n  // if the story is already rendered and we are not forcing a remount, we just update the reactive args\n  if (existingApp && !forceRemount) {\n    // normally storyFn should be call once only in setup function,but because the nature of react and how storybook rendering the decorators\n    // we need to call here to run the decorators again\n    // i may wrap each decorator in memoized function to avoid calling it if the args are not changed\n    const element = storyFn(); // call the story function to get the root element with all the decorators\n    const args = getArgs(element, storyContext); // get args in case they are altered by decorators otherwise use the args from the context\n\n    updateArgs<Args>(existingApp.reactiveArgs, args);\n    updateArgs<Globals>(existingApp.reactiveGlobals, storyContext.globals);\n    return () => {\n      teardown(existingApp.vueApp, canvasElement);\n    };\n  }\n\n  if (existingApp && forceRemount) {\n    teardown(existingApp.vueApp, canvasElement);\n  }\n\n  // create vue app for the story\n  const vueApp = createApp({\n    setup() {\n      storyContext.args = reactive(storyContext.args);\n      storyContext.globals = reactive(storyContext.globals);\n      const rootElement = storyFn(); // call the story function to get the root element with all the decorators\n      const args = getArgs(rootElement, storyContext); // get args in case they are altered by decorators otherwise use the args from the context\n      const appState = {\n        vueApp,\n        reactiveArgs: reactive(args),\n        reactiveGlobals: storyContext.globals,\n      };\n      map.set(canvasElement, appState);\n      return () => {\n        // not passing args here as props\n        // treat the rootElement as a component without props\n        return h(rootElement);\n      };\n    },\n  });\n\n  vueApp.config.errorHandler = (e: unknown, instance, info) => {\n    const preview = (window as Record<string, any>)\n      .__STORYBOOK_PREVIEW__ as PreviewWeb<VueRenderer>;\n    const isPlaying = preview?.storyRenders.some(\n      (renderer) => renderer.id === id && renderer.phase === 'playing'\n    );\n    // Errors thrown during playing need be shown in the interactions panel.\n    if (isPlaying) {\n      // Make sure that Vue won't swallow this error, by stacking it as a different event.\n      setTimeout(() => {\n        throw e;\n      }, 0);\n    } else {\n      showException(e as Error);\n    }\n  };\n  await runSetupFunctions(vueApp, storyContext);\n  vueApp.mount(canvasElement);\n\n  showMain();\n  return () => {\n    teardown(vueApp, canvasElement);\n  };\n}\n\n/** Generate slots for default story without render function template */\nfunction getSlots(props: Args, context: StoryContext<VueRenderer, Args>) {\n  const { argTypes } = context;\n  const slots = Object.entries(props)\n    .filter(([key]) => argTypes[key]?.table?.category === 'slots')\n    .map(([key, value]) => [key, typeof value === 'function' ? value : () => value]);\n\n  return Object.fromEntries(slots);\n}\n\n/**\n * Get the args from the root element props if it is a vnode otherwise from the context\n *\n * @param element Is the root element of the story\n * @param storyContext Is the story context\n */\n\nfunction getArgs(element: StoryFnVueReturnType, storyContext: StoryContext<VueRenderer, Args>) {\n  return element.props && isVNode(element) ? element.props : storyContext.args;\n}\n\n/**\n * Update the reactive args\n *\n * @param reactiveArgs\n * @param nextArgs\n * @returns\n */\nexport function updateArgs<\n  T extends {\n    [name: string]: unknown;\n  },\n>(reactiveArgs: T, nextArgs: T) {\n  if (Object.keys(nextArgs).length === 0) {\n    return;\n  }\n  const currentArgs = isReactive(reactiveArgs) ? reactiveArgs : reactive(reactiveArgs);\n  // delete all args in currentArgs that are not in nextArgs\n  Object.keys(currentArgs).forEach((key) => {\n    if (!(key in nextArgs)) {\n      delete currentArgs[key];\n    }\n  });\n  // update currentArgs with nextArgs\n  Object.assign(currentArgs, nextArgs);\n}\n\n/**\n * Unmount the vue app\n *\n * @private\n * @param storybookApp\n * @param canvasElement\n * @returns Void\n */\n\nfunction teardown(\n  storybookApp: ReturnType<typeof createApp>,\n  canvasElement: VueRenderer['canvasElement']\n) {\n  storybookApp?.unmount();\n\n  if (map.has(canvasElement)) {\n    map.delete(canvasElement);\n  }\n}\n"
  },
  {
    "path": "code/renderers/vue3/src/types.ts",
    "content": "import {\n  type Canvas,\n  type StoryContext as StoryContextBase,\n  type WebRenderer,\n} from 'storybook/internal/types';\n\nimport type { App, ConcreteComponent } from 'vue';\n\nexport type { RenderContext } from 'storybook/internal/types';\n\nexport type StoryID = string;\n\nexport interface ShowErrorArgs {\n  title: string;\n  description: string;\n}\n\nexport type StoryFnVueReturnType = ConcreteComponent<any>;\n\nexport type StoryContext = StoryContextBase<VueRenderer>;\n\nexport type StorybookVueApp = { vueApp: App<any>; storyContext: StoryContext };\n\nexport interface VueRenderer extends WebRenderer {\n  // We are omitting props, as we don't use it internally, and more importantly, it completely changes the assignability of meta.component.\n  // Try not omitting, and check the type errros in the test file, if you want to learn more.\n  component: Omit<ConcreteComponent<this['T']>, 'props'>;\n  storyResult: StoryFnVueReturnType;\n\n  mount: (\n    Component?: StoryFnVueReturnType,\n    // TODO add proper typesafety\n    options?: { props?: Record<string, any>; slots?: Record<string, any> }\n  ) => Promise<Canvas>;\n}\n\nexport interface VueTypes extends VueRenderer {}\n"
  },
  {
    "path": "code/renderers/vue3/src/typings.d.ts",
    "content": "declare var STORYBOOK_ENV: 'vue3';\n\ndeclare var PLUGINS_SETUP_FUNCTIONS: Set<(app, context) => unknown>;\n"
  },
  {
    "path": "code/renderers/vue3/template/cli/js/Button.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport MyButton from './Button.vue';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories\nexport default {\n  title: 'Example/Button',\n  component: MyButton,\n  tags: ['autodocs'],\n  argTypes: {\n    size: { control: { type: 'select' }, options: ['small', 'medium', 'large'] },\n    backgroundColor: { control: 'color' },\n  },\n  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n  args: { onClick: fn() },\n};\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/cli/js/Button.vue",
    "content": "<template>\n  <button type=\"button\" :class=\"classes\" @click=\"onClick\" :style=\"style\">{{ label }}</button>\n</template>\n\n<script>\nimport { computed, reactive } from 'vue';\n\nimport './button.css';\n\nexport default {\n  name: 'my-button',\n\n  props: {\n    label: {\n      type: String,\n      required: true,\n    },\n    primary: {\n      type: Boolean,\n      default: false,\n    },\n    size: {\n      type: String,\n      validator: function (value) {\n        return ['small', 'medium', 'large'].indexOf(value) !== -1;\n      },\n    },\n    backgroundColor: {\n      type: String,\n    },\n  },\n\n  emits: ['click'],\n\n  setup(props, { emit }) {\n    props = reactive(props);\n    return {\n      classes: computed(() => ({\n        'storybook-button': true,\n        'storybook-button--primary': props.primary,\n        'storybook-button--secondary': !props.primary,\n        [`storybook-button--${props.size || 'medium'}`]: true,\n      })),\n      style: computed(() => ({\n        backgroundColor: props.backgroundColor,\n      })),\n      onClick() {\n        emit('click');\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "code/renderers/vue3/template/cli/js/Header.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport MyHeader from './Header.vue';\n\nexport default {\n  title: 'Example/Header',\n  component: MyHeader,\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  render: (args) => ({\n    // Components used in your story `template` are defined in the `components` object\n    components: {\n      MyHeader,\n    },\n    // The story's `args` need to be mapped into the template through the `setup()` method\n    setup() {\n      // Story args can be spread into the returned object\n      return {\n        ...args,\n      };\n    },\n    // Then, the spread values can be accessed directly in the template\n    template: '<my-header :user=\"user\" />',\n  }),\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n};\n\nexport const LoggedIn = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut = {\n  args: {\n    user: null,\n  },\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/cli/js/Header.vue",
    "content": "<template>\n  <header>\n    <div class=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fill-rule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        <span class=\"welcome\" v-if=\"user\"\n          >Welcome, <b>{{ user.name }}</b\n          >!</span\n        >\n        <my-button size=\"small\" @click=\"$emit('logout')\" label=\"Log out\" v-if=\"user\" />\n        <my-button size=\"small\" @click=\"$emit('login')\" label=\"Log in\" v-if=\"!user\" />\n        <my-button\n          primary\n          size=\"small\"\n          @click=\"$emit('createAccount')\"\n          label=\"Sign up\"\n          v-if=\"!user\"\n        />\n      </div>\n    </div>\n  </header>\n</template>\n\n<script>\nimport MyButton from './Button.vue';\nimport './header.css';\n\nexport default {\n  name: 'my-header',\n\n  components: { MyButton },\n\n  props: {\n    user: {\n      type: Object,\n    },\n  },\n\n  emits: ['login', 'logout', 'createAccount'],\n};\n</script>\n"
  },
  {
    "path": "code/renderers/vue3/template/cli/js/Page.stories.js",
    "content": "import { expect, userEvent, within } from 'storybook/test';\n\nimport MyPage from './Page.vue';\n\nexport default {\n  title: 'Example/Page',\n  component: MyPage,\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n};\n\nexport const LoggedOut = {};\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn = {\n  render: () => ({\n    components: {\n      MyPage,\n    },\n    template: '<my-page />',\n  }),\n  play: async ({ canvasElement }) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await expect(loginButton).not.toBeInTheDocument();\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/cli/js/Page.vue",
    "content": "<template>\n  <article>\n    <my-header :user=\"user\" @login=\"onLogin\" @logout=\"onLogout\" @createAccount=\"onCreateAccount\" />\n\n    <section class=\"storybook-page\">\n      <h2>Pages in Storybook</h2>\n      <p>\n        We recommend building UIs with a\n        <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n          <strong>component-driven</strong>\n        </a>\n        process starting with atomic components and ending with pages.\n      </p>\n      <p>\n        Render pages with mock data. This makes it easy to build and review page states without\n        needing to navigate to them in your app. Here are some handy patterns for managing page data\n        in Storybook:\n      </p>\n      <ul>\n        <li>\n          Use a higher-level connected component. Storybook helps you compose such data from the\n          \"args\" of child component stories\n        </li>\n        <li>\n          Assemble data in the page component from your services. You can mock these services out\n          using Storybook.\n        </li>\n      </ul>\n      <p>\n        Get a guided tutorial on component-driven development at\n        <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\"\n          >Storybook tutorials</a\n        >\n        . Read more in the\n        <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">docs</a>\n        .\n      </p>\n      <div class=\"tip-wrapper\">\n        <span class=\"tip\">Tip</span>\n        Adjust the width of the canvas with the\n        <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fill-rule=\"evenodd\">\n            <path\n              d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n              id=\"a\"\n              fill=\"#999\"\n            />\n          </g>\n        </svg>\n        Viewports addon in the toolbar\n      </div>\n    </section>\n  </article>\n</template>\n\n<script>\nimport MyHeader from './Header.vue';\nimport './page.css';\n\nexport default {\n  name: 'my-page',\n\n  components: { MyHeader },\n\n  data() {\n    return {\n      user: null,\n    };\n  },\n\n  methods: {\n    onLogin() {\n      this.user = { name: 'Jane Doe' };\n    },\n    onLogout() {\n      this.user = null;\n    },\n    onCreateAccount() {\n      this.user = { name: 'Jane Doe' };\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "code/renderers/vue3/template/cli/ts/Button.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3';\n\nimport { fn } from 'storybook/test';\n\nimport Button from './Button.vue';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories\nconst meta = {\n  title: 'Example/Button',\n  component: Button,\n  // This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  argTypes: {\n    size: { control: 'select', options: ['small', 'medium', 'large'] },\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    primary: false,\n    // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n    onClick: fn(),\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    primary: false,\n    label: 'Button',\n  },\n};\n\nexport const Large: Story = {\n  args: {\n    label: 'Button',\n    size: 'large',\n  },\n};\n\nexport const Small: Story = {\n  args: {\n    label: 'Button',\n    size: 'small',\n  },\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/cli/ts/Button.vue",
    "content": "<template>\n  <button type=\"button\" :class=\"classes\" @click=\"onClick\" :style=\"style\">{{ label }}</button>\n</template>\n\n<script lang=\"ts\" setup>\nimport { computed } from 'vue';\n\nimport './button.css';\n\nconst props = withDefaults(\n  defineProps<{\n    /**\n     * The label of the button\n     */\n    label: string;\n    /**\n     * primary or secondary button\n     */\n    primary?: boolean;\n    /**\n     * size of the button\n     */\n    size?: 'small' | 'medium' | 'large';\n    /**\n     * background color of the button\n     */\n    backgroundColor?: string;\n  }>(),\n  { primary: false }\n);\n\nconst emit = defineEmits<{\n  (e: 'click', id: number): void;\n}>();\n\nconst classes = computed(() => ({\n  'storybook-button': true,\n  'storybook-button--primary': props.primary,\n  'storybook-button--secondary': !props.primary,\n  [`storybook-button--${props.size || 'medium'}`]: true,\n}));\n\nconst style = computed(() => ({\n  backgroundColor: props.backgroundColor,\n}));\n\nconst onClick = () => {\n  emit('click', 1);\n};\n</script>\n"
  },
  {
    "path": "code/renderers/vue3/template/cli/ts/Header.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3';\n\nimport { fn } from 'storybook/test';\n\nimport MyHeader from './Header.vue';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Example/Header',\n  component: MyHeader,\n  render: (args: any) => ({\n    components: { MyHeader },\n    setup() {\n      return { args };\n    },\n    template: '<my-header :user=\"args.user\" />',\n  }),\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n  // This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n} satisfies Meta<typeof MyHeader>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const LoggedIn: Story = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut: Story = {\n  args: {\n    user: null,\n  },\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/cli/ts/Header.vue",
    "content": "<template>\n  <header>\n    <div class=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fill-rule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        <span class=\"welcome\" v-if=\"user\"\n          >Welcome, <b>{{ user.name }}</b\n          >!</span\n        >\n        <my-button size=\"small\" @click=\"$emit('logout')\" label=\"Log out\" v-if=\"user\" />\n        <my-button size=\"small\" @click=\"$emit('login')\" label=\"Log in\" v-if=\"!user\" />\n        <my-button\n          primary\n          size=\"small\"\n          @click=\"$emit('createAccount')\"\n          label=\"Sign up\"\n          v-if=\"!user\"\n        />\n      </div>\n    </div>\n  </header>\n</template>\n\n<script lang=\"ts\" setup>\nimport MyButton from './Button.vue';\nimport './header.css';\n\ndefineProps<{ user: { name: string } | null }>();\n\ndefineEmits<{\n  (event: 'createAccount'): void;\n  (event: 'login'): void;\n  (event: 'logout'): void;\n}>();\n</script>\n"
  },
  {
    "path": "code/renderers/vue3/template/cli/ts/Page.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3';\n\nimport { expect, userEvent, within } from 'storybook/test';\n\nimport MyPage from './Page.vue';\n\nconst meta = {\n  title: 'Example/Page',\n  component: MyPage,\n  render: () => ({\n    components: { MyPage },\n    template: '<my-page />',\n  }),\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  // This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n} satisfies Meta<typeof MyPage>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn: Story = {\n  play: async ({ canvasElement }: any) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await expect(loginButton).not.toBeInTheDocument();\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n\nexport const LoggedOut: Story = {};\n"
  },
  {
    "path": "code/renderers/vue3/template/cli/ts/Page.vue",
    "content": "<template>\n  <article>\n    <my-header :user=\"user\" @login=\"onLogin\" @logout=\"onLogout\" @create-account=\"onCreateAccount\" />\n\n    <section class=\"storybook-page\">\n      <h2>Pages in Storybook</h2>\n      <p>\n        We recommend building UIs with a\n        <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n          <strong>component-driven</strong>\n        </a>\n        process starting with atomic components and ending with pages.\n      </p>\n      <p>\n        Render pages with mock data. This makes it easy to build and review page states without\n        needing to navigate to them in your app. Here are some handy patterns for managing page data\n        in Storybook:\n      </p>\n      <ul>\n        <li>\n          Use a higher-level connected component. Storybook helps you compose such data from the\n          \"args\" of child component stories\n        </li>\n        <li>\n          Assemble data in the page component from your services. You can mock these services out\n          using Storybook.\n        </li>\n      </ul>\n      <p>\n        Get a guided tutorial on component-driven development at\n        <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\"\n          >Storybook tutorials</a\n        >\n        . Read more in the\n        <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">docs</a>\n        .\n      </p>\n      <div class=\"tip-wrapper\">\n        <span class=\"tip\">Tip</span>\n        Adjust the width of the canvas with the\n        <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fill-rule=\"evenodd\">\n            <path\n              d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n              id=\"a\"\n              fill=\"#999\"\n            />\n          </g>\n        </svg>\n        Viewports addon in the toolbar\n      </div>\n    </section>\n  </article>\n</template>\n\n<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport MyHeader from './Header.vue';\nimport './page.css';\n\nconst user = ref<{ name: string } | null>(null);\n\nconst onLogin = () => {\n  user.value = { name: 'Jane Doe' };\n};\nconst onLogout = () => {\n  user.value = null;\n};\nconst onCreateAccount = () => {\n  user.value = { name: 'Jane Doe' };\n};\n</script>\n"
  },
  {
    "path": "code/renderers/vue3/template/components/Button.vue",
    "content": "<template>\n  <button type=\"button\" :class=\"classes\" @click=\"onClick\" :style=\"style\">{{ label }}</button>\n</template>\n\n<script>\nimport { computed, reactive } from 'vue';\n\nimport './button.css';\n\nexport default {\n  name: 'my-button',\n\n  props: {\n    label: {\n      type: String,\n      required: true,\n    },\n    primary: {\n      type: Boolean,\n      default: false,\n    },\n    size: {\n      type: String,\n      validator: function (value) {\n        return ['small', 'medium', 'large'].indexOf(value) !== -1;\n      },\n    },\n    backgroundColor: {\n      type: String,\n    },\n  },\n\n  emits: ['click'],\n\n  setup(props, { emit }) {\n    props = reactive(props);\n    return {\n      classes: computed(() => ({\n        'storybook-button': true,\n        'storybook-button--primary': props.primary,\n        'storybook-button--secondary': !props.primary,\n        [`storybook-button--${props.size || 'medium'}`]: true,\n      })),\n      style: computed(() => ({\n        backgroundColor: props.backgroundColor,\n      })),\n      onClick() {\n        emit('click');\n      },\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "code/renderers/vue3/template/components/Form.vue",
    "content": "<template>\n  <form id=\"interaction-test-form\" @submit.prevent=\"onSubmit\">\n    <label>\n      Enter Value\n      <input type=\"text\" data-testid=\"value\" v-model=\"value\" required />\n    </label>\n    <button type=\"submit\">Submit</button>\n    <p v-if=\"complete\">Completed!!</p>\n  </form>\n</template>\n\n<script>\nexport default {\n  name: 'my-form',\n\n  props: {\n    onSuccess: {\n      type: Function,\n    },\n  },\n\n  data() {\n    return {\n      value: '',\n      complete: false,\n    };\n  },\n\n  methods: {\n    onSubmit() {\n      this.onSuccess(this.value);\n      setTimeout(() => {\n        this.complete = true;\n      }, 500);\n      setTimeout(() => {\n        this.complete = false;\n      }, 1500);\n    },\n  },\n};\n</script>\n"
  },
  {
    "path": "code/renderers/vue3/template/components/Html.vue",
    "content": "<template>\n  <div v-html=\"content\"></div>\n</template>\n\n<script>\nexport default {\n  name: 'my-html',\n  props: {\n    content: {\n      type: String,\n      required: true,\n    },\n  },\n  setup() {},\n};\n</script>\n"
  },
  {
    "path": "code/renderers/vue3/template/components/Pre.vue",
    "content": "<template>\n  <pre data-testid=\"pre\" :style=\"style\">{{ finalText }}</pre>\n</template>\n\n<script>\nimport { computed, reactive } from 'vue';\n\nexport default {\n  name: 'my-pre',\n\n  props: {\n    // deepscan-disable-next-line\n    style: {\n      type: Object,\n    },\n    object: {\n      type: Object,\n    },\n    text: {\n      type: String,\n      default: '',\n    },\n  },\n\n  setup(props, { emit }) {\n    props = reactive(props);\n    return {\n      finalText: computed(() =>\n        props.object ? JSON.stringify(props.object, null, 2) : props.text\n      ),\n    };\n  },\n};\n</script>\n"
  },
  {
    "path": "code/renderers/vue3/template/components/button.css",
    "content": ".storybook-button {\n  display: inline-block;\n  cursor: pointer;\n  border: 0;\n  border-radius: 3em;\n  font-weight: 700;\n  line-height: 1;\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n.storybook-button--primary {\n  background-color: #555ab9;\n  color: white;\n}\n.storybook-button--secondary {\n  box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;\n  background-color: transparent;\n  color: #333;\n}\n.storybook-button--small {\n  padding: 10px 16px;\n  font-size: 12px;\n}\n.storybook-button--medium {\n  padding: 11px 20px;\n  font-size: 14px;\n}\n.storybook-button--large {\n  padding: 12px 24px;\n  font-size: 16px;\n}\n"
  },
  {
    "path": "code/renderers/vue3/template/components/index.js",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport Button from './Button.vue';\nimport Form from './Form.vue';\nimport Html from './Html.vue';\nimport Pre from './Pre.vue';\n\nglobalThis.__TEMPLATE_COMPONENTS__ = { Button, Pre, Form, Html };\nglobalThis.storybookRenderer = 'vue3';\n"
  },
  {
    "path": "code/renderers/vue3/template/stories/preview.js",
    "content": "import { global as globalThis } from '@storybook/global';\nimport { setup } from '@storybook/vue3';\n\nconst somePlugin = {\n  install: (app, options) => {\n    // inject a globally available $greetingText() method\n\n    app.config.globalProperties.$greetingMessage = (key) => {\n      // retrieve a nested property in `options`\n      // using `key`\n      return options.greetings[key];\n    };\n  },\n};\nconst someColor = 'someColor';\n\n// add components to global scope\nsetup((app) => {\n  // This adds a component that can be used globally in stories\n  app.component('GlobalButton', globalThis.__TEMPLATE_COMPONENTS__.Button);\n});\n\n// this adds a plugin to vue app that can be used globally in stories\nsetup((app, context) => {\n  app.use(somePlugin, {\n    greetings: {\n      hello: `Hello Story! from some plugin your name is ${context?.name}!`,\n      welcome: `Welcome Story! from some plugin your name is ${context?.name}!`,\n      hi: `Hi Story! from some plugin your name is ${context?.name}!`,\n    },\n  });\n});\n\n// additonal setup to provide some propriety  to the app\nsetup((app, context) => {\n  app.provide(someColor, 'green');\n});\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/BaseLayout.vue",
    "content": "<script setup lang=\"ts\">\ndefineProps({\n  label: String,\n});\n</script>\n<template>\n  <div>\n    <header data-testid=\"header-slot\">\n      <slot name=\"header\" title=\"Header title from the slot\"></slot>\n    </header>\n    <main data-testid=\"default-slot\">\n      <slot></slot>\n    </main>\n    <footer data-testid=\"footer-slot\">\n      <slot name=\"footer\"></slot>\n    </footer>\n  </div>\n</template>\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/CustomRenderFunctionalComponent.stories.ts",
    "content": "import type { Meta } from '@storybook/vue3';\n\nimport { h } from 'vue';\n\nimport * as ReactiveDecorators from './ReactiveDecorators.stories';\nimport Reactivity from './Reactivity.vue';\n\nconst meta = {\n  ...ReactiveDecorators.default,\n  component: Reactivity,\n  // storybook render function is not a functional component. it returns a functional component or a component options\n  render: (args) => {\n    // create the slot contents as a functional components\n    const header = ({ title }: { title: string }) => h('h3', `${args.header} - Title: ${title}`);\n    const defaultSlot = () => h('p', `${args.default}`);\n    const footer = () => h('p', `${args.footer}`);\n    // vue render function is a functional components\n    return () =>\n      h('div', [\n        `Custom render uses a functional component, and passes slots to the component:`,\n        h(Reactivity, args, { header, default: defaultSlot, footer }),\n      ]);\n  },\n  tags: ['!vitest'],\n} satisfies Meta<typeof Reactivity>;\n\nexport default meta;\n\nexport {\n  NoDecorators,\n  DecoratorFunctionalComponent,\n  DecoratorFunctionalComponentArgsFromContext,\n  DecoratorComponentOptions,\n  DecoratorComponentOptionsArgsFromData,\n} from './ReactiveDecorators.stories';\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/CustomRenderOptionsArgsFromData.stories.ts",
    "content": "import type { Meta } from '@storybook/vue3';\n\nimport { defineComponent, shallowReactive } from 'vue';\n\nimport * as ReactiveDecorators from './ReactiveDecorators.stories';\nimport Reactivity from './Reactivity.vue';\n\n// when you use custom render, you can use any vue api to create your story and garanti reactivity, otherwise i can ease kill the reactivity.\nconst state = shallowReactive<{ header: any; default: any; footer: any }>({\n  header: '',\n  default: '',\n  footer: '',\n}); // or reactive\n\nconst meta = {\n  ...ReactiveDecorators.default,\n  component: Reactivity,\n  render: (args, { argTypes }) => {\n    state.header = args.header;\n    state.default = args.default;\n    state.footer = args.footer;\n    // return a component options\n    return defineComponent({\n      data: () => ({ args, header: state.header, default: state.default, footer: state.footer }),\n      components: {\n        Reactivity,\n      },\n      template: `<div>Custom render uses options api and binds args to data: \n                    <Reactivity v-bind=\"args\">\n                      <template #header=\"{title}\"><h3>{{ args.header }} - Title: {{ title }}</h3></template>\n                      <template #default>{{ args.default }}</template>\n                      <template #footer>{{ args.footer }} </template>\n                    </Reactivity>\n                  </div>`,\n    });\n  },\n  // this story can't be reliably tested because the (inherited) args changes results in renderPhases disrupting test runs\n  tags: ['!vitest', '!test'],\n} satisfies Meta<typeof Reactivity>;\n\nexport default meta;\n\nexport {\n  NoDecorators,\n  DecoratorFunctionalComponent,\n  DecoratorFunctionalComponentArgsFromContext,\n  DecoratorComponentOptions,\n  DecoratorComponentOptionsArgsFromData,\n} from './ReactiveDecorators.stories';\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/GlobalSetup.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3';\n\nimport { expect, within } from 'storybook/test';\nimport { inject } from 'vue';\n\nimport GlobalSetup from './GlobalSetup.vue';\n\nconst meta: Meta = {\n  component: GlobalSetup,\n  argTypes: {},\n  render: (args: any) => ({\n    // Components used in your story `template` are defined in the `components` object\n    components: { GlobalUsage: GlobalSetup },\n    // The story's `args` need to be mapped into the template through the `setup()` method\n    setup() {\n      const color = inject('someColor', 'red'); // <-- this is the global setup from .storybook/preview.ts\n      return { args: { ...args, backgroundColor: color } };\n    },\n    // And then the `args` are bound to your component with `v-bind=\"args\"`\n    template: '<global-usage v-bind=\"args\" />',\n  }),\n} satisfies Meta<typeof GlobalSetup>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'someColor injected from .storybook/preview.ts',\n  },\n  play: async ({ canvasElement, id }) => {\n    const canvas = within(canvasElement);\n\n    const button = await canvas.getByRole('button');\n    await expect(button).toHaveStyle('background-color: rgb(0, 128, 0)'); // <-- this provide themeColor = green from .storybook/preview.ts\n\n    const h2 = await canvas.getByRole('heading', { level: 2 });\n    await expect(h2).toHaveTextContent('Hi Story! from some plugin your name is Primary!');\n\n    const h3 = await canvas.getByRole('heading', { level: 3 });\n    await expect(h3).toHaveTextContent('Hello Story! from some plugin your name is Primary!');\n\n    const h4 = await canvas.getByRole('heading', { level: 4 });\n    await expect(h4).toHaveTextContent('Welcome Story! from some plugin your name is Primary!');\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    label: 'someColor injected from .storybook/preview.ts',\n  },\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/GlobalSetup.vue",
    "content": "<template>\n  <global-button v-bind=\"$attrs\"> </global-button>\n  <h2>Hi message: {{ $greetingMessage('hi') }}</h2>\n  <h3>Hello message: {{ $greetingMessage('hello') }}</h3>\n  <h4>Welcome message: {{ $greetingMessage('welcome') }}</h4>\n</template>\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/GlobalUsage.stories.ts",
    "content": "import GlobalUsage from './GlobalUsage.vue';\n\nexport default {\n  component: GlobalUsage,\n  argTypes: {},\n  render: (args: any) => ({\n    // Components used in your story `template` are defined in the `components` object\n    components: { GlobalUsage },\n    // The story's `args` need to be mapped into the template through the `setup()` method\n    setup() {\n      return { args };\n    },\n    // And then the `args` are bound to your component with `v-bind=\"args\"`\n    template: '<global-usage v-bind=\"args\" />',\n  }),\n};\n\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Globally Defined',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    label: 'Globally Defined',\n  },\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/GlobalUsage.vue",
    "content": "<template>\n  <global-button />\n</template>\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/MySlotComponent.vue",
    "content": "<!-- <MyComponent> template -->\n<script setup lang=\"ts\">\nconst props = defineProps({\n  label: String,\n  year: Number,\n});\n</script>\n<template>\n  <div data-testid=\"scoped-slot\">\n    <slot :text=\"`Hello ${props.label} from the slot`\" :year=\"props.year\"></slot>\n  </div>\n</template>\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/OverrideArgs.stories.js",
    "content": "import OverrideArgs from './OverrideArgs.vue';\n\n// Emulate something that isn't serializable\nconst icons = {\n  Primary: {\n    template: '<span>Primary Icon</span>',\n  },\n  Secondary: {\n    template: '<span>Secondary Icon</span>',\n  },\n};\n\nconst meta = {\n  component: OverrideArgs,\n  argTypes: {\n    // To show that other props are passed through\n    backgroundColor: { control: 'color' },\n    icon: {\n      control: {\n        type: 'select',\n        options: Object.keys(icons),\n      },\n    },\n  },\n  render: (args) => {\n    // Individual properties can be overridden by spreading the args\n    // and the replacing the key-values that need to be updated\n    args = { ...args, icon: icons[args.icon || 'Primary'] };\n    return {\n      // Components used in your story `template` are defined in the `components` object\n      components: { OverrideArgs },\n      // Updated `args` need to be mapped into the template through the `setup()` method\n      setup() {\n        return { args };\n      },\n      // And then the `args` are bound to your component with `v-bind=\"args\"`\n      template: '<override-args v-bind=\"args\" />',\n    };\n  },\n};\n\nexport default meta;\n\nexport const TestOne = {};\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/OverrideArgs.vue",
    "content": "<template>\n  <button type=\"button\" :class=\"classes\" :style=\"style\">\n    <!-- You can use <component /> with `:is` when passing a component as a prop -->\n    <component :is=\"icon\" />\n  </button>\n</template>\n\n<script lang=\"ts\">\nimport { computed } from 'vue';\n\nexport default {\n  name: 'override-args',\n\n  props: {\n    icon: {\n      type: Object,\n      required: true,\n    },\n\n    backgroundColor: {\n      type: String,\n    },\n  },\n\n  setup(props, { emit }) {\n    const classes = {\n      'storybook-button': true,\n      'storybook-button--primary': true,\n      'storybook-button--large': true,\n    };\n    const style = computed(() => ({\n      backgroundColor: props.backgroundColor,\n    }));\n\n    // Notice that `icon` prop component is still passed through even though it isn't mapped\n    return { classes, style };\n  },\n};\n</script>\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/ReactiveArgs.stories.ts",
    "content": "import {\n  RESET_STORY_ARGS,\n  STORY_ARGS_UPDATED,\n  UPDATE_STORY_ARGS,\n} from 'storybook/internal/core-events';\n\nimport type { Meta, StoryFn, StoryObj } from '@storybook/vue3';\n\nimport { expect, userEvent, within } from 'storybook/test';\n\nimport ReactiveArgs from './ReactiveArgs.vue';\n\nconst meta = {\n  component: ReactiveArgs,\n  argTypes: {\n    // To show that other props are passed through\n    backgroundColor: { control: 'color' },\n  },\n  tags: ['!vitest'],\n} satisfies Meta<typeof ReactiveArgs>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const ReactiveTest: Story = {\n  args: {\n    label: 'Button',\n  },\n  // test that args are updated correctly in rective mode\n  play: async ({ canvasElement, id }) => {\n    const channel = globalThis.__STORYBOOK_ADDONS_CHANNEL__;\n    const canvas = within(canvasElement);\n\n    await channel.emit(RESET_STORY_ARGS, { storyId: id });\n    await new Promise((resolve) => {\n      channel.once(STORY_ARGS_UPDATED, resolve);\n    });\n    const reactiveButton = await canvas.getByRole('button');\n    await expect(reactiveButton).toHaveTextContent('Button 0');\n\n    await userEvent.click(reactiveButton); // click to update the label to increment the count + 1\n    await channel.emit(UPDATE_STORY_ARGS, {\n      storyId: id,\n      updatedArgs: { label: 'updated' },\n    });\n    await new Promise((resolve) => {\n      channel.once(STORY_ARGS_UPDATED, resolve);\n    });\n    await expect(canvas.getByRole('button')).toHaveTextContent('updated 1');\n\n    await userEvent.click(reactiveButton); // click to update the label to increment the count + 1\n    await expect(reactiveButton).toHaveTextContent('updated 2');\n  },\n};\n\nexport const ReactiveHtmlWrapper: Story = {\n  args: { label: 'Wrapped Button' },\n\n  decorators: [\n    () => ({\n      template: `\n        <div style=\"border: 5px solid red;\">\n          <story/>\n        </div>\n        `,\n    }),\n  ],\n  play: async ({ canvasElement, id }) => {\n    const channel = globalThis.__STORYBOOK_ADDONS_CHANNEL__;\n    const canvas = within(canvasElement);\n\n    await channel.emit(RESET_STORY_ARGS, { storyId: id });\n    await new Promise((resolve) => {\n      channel.once(STORY_ARGS_UPDATED, resolve);\n    });\n    const reactiveButton = await canvas.getByRole('button');\n    await expect(reactiveButton).toHaveTextContent('Wrapped Button 0');\n\n    await userEvent.click(reactiveButton); // click to update the label to increment the count + 1\n    await channel.emit(UPDATE_STORY_ARGS, {\n      storyId: id,\n      updatedArgs: { label: 'updated Wrapped Button' },\n    });\n    await new Promise((resolve) => {\n      channel.once(STORY_ARGS_UPDATED, resolve);\n    });\n    await expect(canvas.getByRole('button')).toHaveTextContent('updated Wrapped Button 1');\n\n    await userEvent.click(reactiveButton); // click to update the label to increment the count + 1\n    await expect(reactiveButton).toHaveTextContent('updated Wrapped Button 2');\n  },\n};\n\n// to test that Simple html Decorators in CSF2 format are applied correctly in reactive mode\nconst ReactiveCSF2WrapperTempl: StoryFn = (args) => ({\n  components: { ReactiveArgs },\n  setup() {\n    return { args };\n  },\n  template: '<ReactiveArgs v-bind=\"args\" />',\n});\n\nexport const ReactiveCSF2Wrapper = ReactiveCSF2WrapperTempl.bind({});\n\nReactiveCSF2Wrapper.tags = ['!test'];\n\nReactiveCSF2Wrapper.args = {\n  label: 'CSF2 Wrapped Button',\n};\nReactiveCSF2Wrapper.decorators = [\n  () => ({\n    template: `\n      <div style=\"border: 5px solid red;\">\n        <story/>\n      </div>\n      `,\n  }),\n];\n\nReactiveCSF2Wrapper.play = async ({ canvasElement, id }) => {\n  const channel = globalThis.__STORYBOOK_ADDONS_CHANNEL__;\n  const canvas = within(canvasElement);\n\n  await channel.emit(RESET_STORY_ARGS, { storyId: id });\n  await new Promise((resolve) => {\n    channel.once(STORY_ARGS_UPDATED, resolve);\n  });\n  const reactiveButton = await canvas.getByRole('button');\n  await expect(reactiveButton).toHaveTextContent('CSF2 Wrapped Button 0');\n\n  await userEvent.click(reactiveButton); // click to update the label to increment the count + 1\n  await channel.emit(UPDATE_STORY_ARGS, {\n    storyId: id,\n    updatedArgs: { label: 'updated CSF2 Wrapped Button' },\n  });\n  await new Promise((resolve) => {\n    channel.once(STORY_ARGS_UPDATED, resolve);\n  });\n  await expect(canvas.getByRole('button')).toHaveTextContent('updated CSF2 Wrapped Button 1');\n\n  await userEvent.click(reactiveButton); // click to update the label to increment the count + 1\n  await expect(reactiveButton).toHaveTextContent('updated CSF2 Wrapped Button 2');\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/ReactiveArgs.vue",
    "content": "<template>\n  <button type=\"button\" @click=\"onClick\" :class=\"classes\" :style=\"style\">\n    {{ label }} {{ counter }}\n  </button>\n</template>\n\n<script>\nimport { computed, ref } from 'vue';\n\nexport default {\n  name: 'reactive-args',\n\n  props: {\n    label: {\n      type: String,\n    },\n\n    backgroundColor: {\n      type: String,\n    },\n  },\n\n  setup(props, { emit }) {\n    const classes = {\n      'storybook-button': true,\n      'storybook-button--primary': true,\n      'storybook-button--large': true,\n    };\n    const style = computed(() => ({\n      backgroundColor: props.backgroundColor,\n    }));\n    const counter = ref(0);\n    const onClick = () => {\n      emit('click', 1);\n      counter.value += 1;\n    };\n\n    // Notice that `icon` prop component is still passed through even though it isn't mapped\n    return { classes, style, counter, onClick };\n  },\n};\n</script>\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/ReactiveDecorators.stories.ts",
    "content": "import {\n  RESET_STORY_ARGS,\n  STORY_ARGS_UPDATED,\n  UPDATE_STORY_ARGS,\n} from 'storybook/internal/core-events';\n\nimport { global as globalThis } from '@storybook/global';\nimport type { Meta, StoryObj } from '@storybook/vue3';\n\nimport { userEvent, within } from 'storybook/test';\nimport { h } from 'vue';\n\nimport Reactivity from './Reactivity.vue';\n\nconst meta = {\n  component: Reactivity,\n  argTypes: {\n    header: { control: { type: 'text' } },\n    footer: { control: { type: 'text' } },\n    default: { control: { type: 'text' } },\n  },\n  args: {\n    label: 'If you see this then the label arg was not reactive.',\n    default: 'If you see this then the default slot was not reactive.',\n    header: 'If you see this, the header slot was not reactive.', // this can be useless if you have custom render function that overrides the slot\n    footer: 'If you see this, the footer slot was not reactive.',\n  },\n  play: async ({ canvasElement, id, args }) => {\n    const channel = (globalThis as any).__STORYBOOK_ADDONS_CHANNEL__;\n\n    const canvas = within(canvasElement);\n\n    await channel.emit(RESET_STORY_ARGS, { storyId: id });\n    await new Promise((resolve) => channel.once(STORY_ARGS_UPDATED, resolve));\n\n    const input = await canvas.findByLabelText<HTMLInputElement>('Some input:');\n    await userEvent.type(input, 'value');\n\n    await channel.emit(UPDATE_STORY_ARGS, {\n      storyId: id,\n      updatedArgs: {\n        label: 'updated label',\n        header: 'updated header slot', // this can be useless if you have custom render function that overrides the slot which the case here\n        footer: 'updated footer slot',\n        default: 'updated default slot',\n      },\n    });\n    await new Promise((resolve) => channel.once(STORY_ARGS_UPDATED, resolve));\n  },\n  tags: ['!vitest'],\n} satisfies Meta<typeof Reactivity>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const NoDecorators: Story = {};\n\nexport const DecoratorFunctionalComponent: Story = {\n  decorators: [\n    (storyFn, context) => {\n      const story = storyFn();\n      return () => h('div', [h('h2', ['Decorator not using args']), [h(story)]]);\n    },\n  ],\n};\n\nexport const DecoratorFunctionalComponentArgsFromContext: Story = {\n  decorators: [\n    (storyFn, context) => {\n      const story = storyFn();\n      return () =>\n        h('div', [h('h2', ['Decorator using args.label: ', context.args.label]), [h(story)]]);\n    },\n  ],\n};\n\nexport const DecoratorComponentOptions: Story = {\n  decorators: [\n    (storyFn, context) => {\n      return {\n        template: '<div><h2>Decorator not using args</h2><story/></div>',\n      };\n    },\n  ],\n};\n\nexport const DecoratorComponentOptionsArgsFromData: Story = {\n  decorators: [\n    (storyFn, context) => {\n      return {\n        data: () => ({ args: context.args }),\n        template: '<div><h2>Decorator using args.label: {{args.label}}</h2><story/></div>',\n      };\n    },\n  ],\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/ReactiveSlots.stories.ts",
    "content": "import {\n  RESET_STORY_ARGS,\n  STORY_ARGS_UPDATED,\n  UPDATE_STORY_ARGS,\n} from 'storybook/internal/core-events';\n\nimport { global as globalThis } from '@storybook/global';\nimport type { Meta, StoryObj } from '@storybook/vue3';\n\nimport { expect, within } from 'storybook/test';\nimport { h } from 'vue';\n\nimport BaseLayout from './BaseLayout.vue';\n\nconst meta = {\n  component: BaseLayout,\n  args: {\n    label: 'Storybook Day',\n    default: () => 'Default Text Slot',\n    footer: h('p', 'Footer VNode Slot'),\n  },\n  tags: ['autodocs', '!vitest'],\n} satisfies Meta<typeof BaseLayout>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const SimpleSlotTest: Story = {\n  args: {\n    label: 'Storybook Day',\n    header: () => h('h1', 'Header Text Slot'),\n    default: () => 'Default Text Slot',\n    footer: h('p', 'Footer VNode Slot'),\n  },\n  play: async ({ canvasElement, id }) => {\n    const channel = globalThis.__STORYBOOK_ADDONS_CHANNEL__;\n    const canvas = within(canvasElement);\n\n    await channel.emit(RESET_STORY_ARGS, { storyId: id });\n    await new Promise((resolve) => {\n      channel.once(STORY_ARGS_UPDATED, resolve);\n    });\n    await expect(canvas.getByTestId('footer-slot').innerText).toContain('Footer VNode Slot');\n    await expect(canvas.getByTestId('default-slot').innerText).toContain('Default Text Slot');\n\n    await channel.emit(UPDATE_STORY_ARGS, {\n      storyId: id,\n      updatedArgs: {\n        default: () => 'Default Text Slot Updated',\n        footer: h('p', 'Footer VNode Slot Updated'),\n      },\n    });\n    await new Promise((resolve) => {\n      channel.once(STORY_ARGS_UPDATED, resolve);\n    });\n    await expect(canvas.getByTestId('default-slot').innerText).toContain(\n      'Default Text Slot Updated'\n    );\n    await expect(canvas.getByTestId('footer-slot').innerText).toContain(\n      'Footer VNode Slot Updated'\n    );\n  },\n};\n\nexport const NamedSlotTest: Story = {\n  args: {\n    label: 'Storybook Day',\n    header: ({ title }: { title: string }) => h('h1', title),\n    default: () => 'Default Text Slot',\n    footer: h('p', 'Footer VNode Slot'),\n  },\n  // test that args are updated correctly in rective mode\n  play: async ({ canvasElement, id }) => {\n    const channel = globalThis.__STORYBOOK_ADDONS_CHANNEL__;\n    const canvas = within(canvasElement);\n\n    await channel.emit(RESET_STORY_ARGS, { storyId: id });\n    await new Promise((resolve) => {\n      channel.once(STORY_ARGS_UPDATED, resolve);\n    });\n    await expect(canvas.getByTestId('header-slot').innerText).toContain(\n      'Header title from the slot'\n    );\n    await expect(canvas.getByTestId('default-slot').innerText).toContain('Default Text Slot');\n    await expect(canvas.getByTestId('footer-slot').innerText).toContain('Footer VNode Slot');\n\n    await channel.emit(UPDATE_STORY_ARGS, {\n      storyId: id,\n      updatedArgs: {\n        default: () => 'Default Text Slot Updated',\n        footer: h('p', 'Footer VNode Slot Updated'),\n      },\n    });\n    await new Promise((resolve) => {\n      channel.once(STORY_ARGS_UPDATED, resolve);\n    });\n    await expect(canvas.getByTestId('default-slot').innerText).toContain(\n      'Default Text Slot Updated'\n    );\n    await expect(canvas.getByTestId('footer-slot').innerText).toContain(\n      'Footer VNode Slot Updated'\n    );\n  },\n};\n\nexport const SlotWithRenderFn: Story = {\n  args: {\n    label: 'Storybook Day',\n    header: ({ title }: { title: string }) => `${title}`,\n    default: () => 'Default Text Slot',\n    footer: h('p', 'Footer VNode Slot'),\n  },\n  render: (args) => ({\n    components: { BaseLayout },\n    setup() {\n      return { args };\n    },\n    template: `<BaseLayout :label=\"args.label\" data-testid=\"layout\">\n  \t            {{args.default()}}\n                <template #header=\"{ title }\"><h1>{{args.header({title})}}</h1></template>\n              </BaseLayout>`,\n  }),\n  play: async ({ canvasElement, id }) => {\n    const channel = globalThis.__STORYBOOK_ADDONS_CHANNEL__;\n    const canvas = within(canvasElement);\n\n    await channel.emit(RESET_STORY_ARGS, { storyId: id });\n    await new Promise((resolve) => {\n      channel.once(STORY_ARGS_UPDATED, resolve);\n    });\n    await expect(canvas.getByTestId('layout').innerText).toContain('Default Text Slot');\n  },\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/Reactivity.vue",
    "content": "<script setup lang=\"ts\">\ndefineProps<{ label: string }>();\n</script>\n<template>\n  <div style=\"padding: 20px; background-color: pink\">\n    <header data-testid=\"header-slot\">\n      <slot name=\"header\" title=\"Header title from the slot\">\n        If you see this, the header slot was not reactive.\n      </slot>\n    </header>\n    <div id=\"content\">\n      <label>\n        Some input:\n        <input\n          style=\"width: 400px\"\n          placeholder=\"If you see this, an args update caused the input field to loose state\"\n        />\n      </label>\n      <hr />\n      <button class=\"storybook-button storybook-button--primary storybook-button--medium\">\n        {{ label }}\n      </button>\n    </div>\n\n    <main data-testid=\"default-slot\">\n      <slot>Default slot placeholder</slot>\n    </main>\n    <footer data-testid=\"footer-slot\">\n      <slot name=\"footer\"> Footer slot placeholder </slot>\n    </footer>\n  </div>\n</template>\n\n<style>\nheader,\nfooter {\n  background-color: #fff0ff;\n  padding: 20px;\n}\n\nmain,\n#content {\n  background-color: #f0f0f0;\n  padding: 20px;\n}\n</style>\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/ScopedSlots.stories.ts",
    "content": "import {\n  RESET_STORY_ARGS,\n  STORY_ARGS_UPDATED,\n  UPDATE_STORY_ARGS,\n} from 'storybook/internal/core-events';\n\nimport { global as globalThis } from '@storybook/global';\nimport type { Meta, StoryObj } from '@storybook/vue3';\n\nimport { expect, within } from 'storybook/test';\n\nimport MySlotComponent from './MySlotComponent.vue';\n\ndeclare global {\n  // eslint-disable-next-line no-var\n  var __STORYBOOK_ADDONS_CHANNEL__: any;\n}\n\nconst meta = {\n  component: MySlotComponent,\n  args: {\n    label: 'Storybook Day',\n    year: 2022,\n    default: ({ text, year }) => `${text}, ${year}`,\n  },\n  tags: ['autodocs', '!vitest'],\n} satisfies Meta<typeof MySlotComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  // test that args are updated correctly in reactive mode\n  play: async ({ canvasElement, id }) => {\n    const channel = globalThis.__STORYBOOK_ADDONS_CHANNEL__;\n    const canvas = within(canvasElement);\n\n    await channel.emit(RESET_STORY_ARGS, { storyId: id });\n    await new Promise((resolve) => channel.once(STORY_ARGS_UPDATED, resolve));\n    await expect(canvas.getByTestId('scoped-slot').innerText).toMatch(\n      'Hello Storybook Day from the slot, 2022'\n    );\n\n    await channel.emit(UPDATE_STORY_ARGS, {\n      storyId: id,\n      updatedArgs: {\n        label: 'Storybook Day updated',\n        year: 2023,\n      },\n    });\n    await new Promise((resolve) => {\n      channel.once(STORY_ARGS_UPDATED, resolve);\n    });\n\n    await expect(canvas.getByTestId('scoped-slot').innerText).toMatch(\n      'Hello Storybook Day updated from the slot, 2023'\n    );\n  },\n};\n\nexport const CustomRender: Story = {\n  render: (args) => ({\n    components: { MySlotComponent },\n    setup() {\n      return { args };\n    },\n    template: `<MySlotComponent v-bind=\"args\" v-slot=\"slotProps\">\n  \t              {{ slotProps.text }}, {{ slotProps.year }}\n              </MySlotComponent>`,\n  }),\n  play: Basic.play,\n};\n\nexport const CustomRenderUsingFunctionSlot: Story = {\n  render: (args: any) => ({\n    components: { MySlotComponent },\n    setup() {\n      return { args };\n    },\n    template: `<MySlotComponent v-bind=\"args\" v-slot=\"slotProps\">\n  \t            {{args.default(slotProps)}}\n              </MySlotComponent>`,\n  }),\n  play: Basic.play,\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/SourceCode.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3';\n\nimport { h } from 'vue';\n\nimport SourceCode from './SourceCode.vue';\n\nconst meta: Meta<typeof SourceCode> = {\n  component: SourceCode,\n  tags: ['autodocs'],\n};\n\nexport default meta;\ntype Story = StoryObj<typeof SourceCode>;\n\nexport const Default = {\n  args: {\n    foo: 'Example string',\n    bar: 42,\n    array: ['A', 'B', 'C'],\n    object: {\n      a: 'Test A',\n      b: 42,\n    },\n    modelValue: 'Model value',\n    default: 'Default slot content',\n    namedSlot: ({ foo }) => [\n      'Plain text',\n      h('div', { style: 'color:red' }, ['Div child', h('span', foo)]),\n    ],\n  },\n} satisfies Story;\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/SourceCode.vue",
    "content": "<script lang=\"ts\" setup>\nconst props = defineProps<{\n  foo: string;\n  bar?: number;\n  array: string[];\n  object: Record<string, unknown>;\n  modelValue?: string;\n}>();\n\nconst emit = defineEmits<{\n  'update:modelValue': [value: string];\n}>();\n\ndefineSlots<{\n  default(): any;\n  namedSlot(props: { foo: string }): any;\n}>();\n</script>\n\n<template>\n  <div>\n    <pre>{{ props }}</pre>\n\n    <slot></slot>\n    <slot name=\"namedSlot\" foo=\"Hello World\"></slot>\n  </div>\n</template>\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/SourceDecorator.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3';\n\nimport GlobalSetup from './GlobalSetup.vue';\nimport GlobalUsage from './GlobalUsage.vue';\n\nconst meta: Meta = {\n  component: GlobalUsage,\n  argTypes: {},\n  tags: ['autodocs'],\n} satisfies Meta<typeof GlobalUsage>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const MultiComponents: Story = {\n  args: {\n    label: 'Button',\n    size: 'large',\n    backgroundColor: '#aa00ff',\n    btn1Args: { label: 'Button 10', size: 'small', backgroundColor: '#aa00ff' },\n  },\n  render(args: any) {\n    return {\n      components: { GlobalUsage, GlobalSetup },\n      setup() {\n        return { args };\n      },\n      template: `<div style=\"background-color:pink;opacity:0.9;padding:20px\" >\n                  \n                  <div style=\"display:flex;gap:10px\">\n                    <img src=\"https://user-images.githubusercontent.com/263385/199832481-bbbf5961-6a26-481d-8224-51258cce9b33.png\" width=\"200\" />  \n                    <GlobalUsage v-bind=\"args.btn1Args\" />&nbsp;\n                  </div>\n                  <h2>Complex Story Custom template </h2> <br/> <hr/>\n                \n                <GlobalSetup  :label=\"args.label\" />\n                <div style=\"margin:8px\"><span style=\"font-size:28px;color:green\">Multiple </span>\n                <span style=\"background-color:magenta;opacity:0.9;padding:8px\"><i>Components</i></span></div>\n                <div style=\"display:flex;gap:10px\">\n                  <GlobalUsage v-bind=\"args\" />\n                  <GlobalUsage label=\"Static Label Dynamic color\" :background-color=\"args.backgroundColor\"/>  \n                </div>   \n               </div>`,\n    };\n  },\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/DefineModel.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3';\n\nimport Component from './define-model/component.vue';\n\nconst meta = {\n  component: Component,\n  tags: ['autodocs'],\n} satisfies Meta<typeof Component>;\n\ntype Story = StoryObj<typeof meta>;\nexport default meta;\n\nexport const Default: Story = {\n  args: {\n    modelValue: 'Test value',\n  },\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/DefineSlots.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3';\n\nimport Component from './define-slots/component.vue';\n\nconst meta = {\n  component: Component,\n  tags: ['autodocs'],\n} satisfies Meta<typeof Component>;\n\ntype Story = StoryObj<typeof meta>;\nexport default meta;\n\nexport const Default: Story = {\n  args: {\n    default: ({ num }) => `Default slot: num=${num}`,\n    named: ({ str }) => `Named slot: str=${str}`,\n    vbind: ({ num, str }) => `Named v-bind slot: num=${num}, str=${str}`,\n  },\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/OptionApi.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3';\n\nimport Component from './options-api/component';\n\nconst meta = {\n  component: Component,\n  tags: ['autodocs'],\n} satisfies Meta<typeof Component>;\n\ntype Story = StoryObj<typeof meta>;\nexport default meta;\n\nexport const Default: Story = {\n  args: {\n    numberDefault: 12,\n    objectDefault: { bar: 'foo' },\n    arrayDefault: [1, 2, 3],\n    complexDefault: [1, 2, 3, 4, 5],\n  },\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/ReferenceTypeEvents.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3';\n\nimport Component from './reference-type-events/component.vue';\n\nconst meta = {\n  component: Component,\n  tags: ['autodocs'],\n} satisfies Meta<typeof Component>;\n\ntype Story = StoryObj<typeof meta>;\nexport default meta;\n\nexport const ReferenceTypeEvents: Story = {};\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/ReferenceTypeExposed.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3';\n\nimport Component from './reference-type-exposed/component.vue';\n\nconst meta = {\n  component: Component,\n  tags: ['autodocs'],\n} satisfies Meta<typeof Component>;\n\ntype Story = StoryObj<typeof meta>;\nexport default meta;\n\nexport const ReferenceTypeExposed: Story = {};\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/ReferenceTypeProps.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3';\n\nimport Component from './reference-type-props/component.vue';\n\nconst meta = {\n  component: Component,\n  tags: ['autodocs'],\n} satisfies Meta<typeof Component>;\n\ntype Story = StoryObj<typeof meta>;\nexport default meta;\n\nenum MyEnum {\n  Small,\n  Medium,\n  Large,\n}\n\nexport const ReferenceTypeProps: Story = {\n  args: {\n    foo: 'Foo',\n    baz: true,\n    stringArray: ['Foo', 'Bar', 'Baz'],\n    bar: 1,\n    unionOptional: 'Foo',\n    union: 'Foo',\n    inlined: { foo: 'Foo' },\n    nested: { nestedProp: 'Nested Prop' },\n    nestedIntersection: { nestedProp: 'Nested Prop', additionalProp: 'Additional Prop' },\n    array: [{ nestedProp: 'Nested Prop' }],\n    literalFromContext: 'Uncategorized',\n    enumValue: MyEnum.Small,\n  },\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/TemplateSlots.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3';\n\nimport { h } from 'vue';\n\nimport Component from './template-slots/component.vue';\n\nconst meta = {\n  component: Component,\n  tags: ['autodocs'],\n} satisfies Meta<typeof Component>;\n\ntype Story = StoryObj<typeof meta>;\nexport default meta;\n\nexport const Default: Story = {\n  args: {\n    default: ({ num }) => `Default slot: num=${num}`,\n    named: ({ str }) => `Named slot: str=${str}`,\n    vbind: ({ num, str, obj }) => [\n      `Named v-bind slot: num=${num}, str=${str}, obj.title=${obj.title}`,\n      h('br'),\n      h('button', obj, 'button'),\n      h('br'),\n      h('button', { disabled: true, ...obj }, 'merged props'),\n    ],\n  },\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/TsComponent.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3';\n\nimport Component from './ts-component/component';\n\nconst meta = {\n  component: Component,\n  tags: ['autodocs'],\n} satisfies Meta<typeof Component>;\n\ntype Story = StoryObj<typeof meta>;\nexport default meta;\n\nexport const Default: Story = {\n  args: {\n    foo: 'bar',\n    bar: 20,\n  },\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/TsNameExport.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3';\n\nimport { ComponentA } from './ts-named-export/component';\n\nconst meta = {\n  component: ComponentA,\n  tags: ['autodocs'],\n} satisfies Meta<typeof ComponentA>;\n\ntype Story = StoryObj<typeof meta>;\nexport default meta;\n\nexport const Default: Story = {\n  args: {\n    size: 'large',\n    backgroundColor: 'blue',\n  },\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/class-slots/component.vue",
    "content": "<script lang=\"ts\">\nimport { VNode } from 'vue';\n\nexport default {} as any as new () => {\n  $slots: {\n    default(_: { num: number }): VNode[];\n    foo(_: { str: string }): VNode[];\n  };\n};\n</script>\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/define-model/component.vue",
    "content": "<script setup lang=\"ts\">\nconst model = defineModel<string>();\n</script>\n\n<template>\n  {{ model }}\n</template>\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/define-slots/component.vue",
    "content": "<script setup lang=\"ts\">\ndefineSlots<{\n  /** Some description for \"no-bind\" slot. */\n  'no-bind'(): any;\n  /** Some description for \"default\" slot. */\n  default(props: { num: number }): any;\n  /** Some description for \"named\" slot. */\n  named(props: { str: string }): any;\n  /** Some description for \"vbind\" slot. */\n  vbind(props: { num: number; str: string }): any;\n}>();\n</script>\n\n<template>\n  <slot name=\"no-bind\"></slot>\n  <br />\n  <slot :num=\"123\"></slot>\n  <br />\n  <slot name=\"named\" str=\"str\"></slot>\n  <br />\n  <slot name=\"vbind\" v-bind=\"{ num: 123, str: 'str' }\"></slot>\n</template>\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/options-api/component.ts",
    "content": "import { defineComponent, h } from 'vue';\n\ninterface SubmitPayload {\n  /** Email of user */\n  email: string;\n  /** Password of same user */\n  password: string;\n}\n\nexport default defineComponent({\n  emits: {\n    // Validate submit event\n    submit: ({ email, password }: SubmitPayload) => {\n      if (email && password) {\n        return true;\n      }\n\n      return false;\n    },\n  },\n  props: {\n    /** Number prop with default */\n    numberDefault: {\n      type: Number,\n      default: 42,\n    },\n    /** Object prop with default */\n    objectDefault: {\n      type: Object,\n      default: () => ({\n        foo: 'bar',\n      }),\n    },\n    /** Array prop with default */\n    arrayDefault: {\n      type: Array,\n      default: () => [1, 2, 3],\n    },\n    /** Default function more complex */\n    complexDefault: {\n      type: Array,\n      default: (props: any) => {\n        if (props.arrayDefault.length > props.numberDefault) {\n          return [];\n        }\n        return undefined;\n      },\n    },\n  },\n  render() {\n    return h('pre', JSON.stringify(this.$props, null, 2));\n  },\n});\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/reference-type-events/component.vue",
    "content": "<script setup lang=\"ts\">\ntype MyFooEvent = 'foo';\n\ninterface MyEvents {\n  /** Test description foo */\n  (event: MyFooEvent, data?: { foo: string }): void;\n  /** Test description bar */\n  (event: 'bar', value: { year: number; title?: any }): void;\n  /** Test description baz */\n  (e: 'baz'): void;\n}\n\nconst emit = defineEmits<MyEvents>();\n</script>\n\n<template>\n  <div>\n    foo:\n    <button @click=\"emit('bar', { year: 2023, title: 'Storybook' })\">\n      event: 'bar', value: {year: 2023, title:'Storybook' }\n    </button>\n  </div>\n  <div>\n    bar:\n    <button @click=\"emit('baz')\">event: 'baz'</button>\n  </div>\n  <div>\n    foo:\n    <button @click=\"emit('foo', { foo: 'foo' })\">event: 'foo', data: {foo: 'foo'}</button>\n  </div>\n</template>\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/reference-type-exposed/component.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue';\n\nconst label = ref('Button');\nconst count = ref(100);\n\ndefineExpose({\n  /**\n   * a label string\n   */\n  label,\n  /**\n   * a count number\n   */\n  count,\n});\n</script>\n\n<template>\n  <Pre>{{ JSON.stringify({ label, count }, null, 2) }} </Pre>\n</template>\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/reference-type-props/component-js-setup.vue",
    "content": "<script lang=\"ts\" setup>\nimport { StringEmpty, StringRequired, StringUndefined } from './my-props';\n\ndefineProps({\n  /**\n   * The foo property is required.\n   * @since v1.0.0\n   * @deprecated v1.1.0\n   * @description This is a description of the foo property.\n   */\n  foo: {\n    type: String,\n    required: true,\n  },\n  /**\n   * The bar property has default value\n   */\n  bar: {\n    type: String,\n    default: 'BAR',\n  },\n  /**\n   * The baz property is optional.\n   */\n  baz: {\n    type: String,\n  },\n  /**\n   * The xfoo property is required.\n   */\n  xfoo: StringRequired,\n  /**\n   * The xbar property is empty.\n   */\n  xbar: StringEmpty,\n  /**\n   * The xbaz property is undefined.\n   */\n  xbaz: StringUndefined,\n  /**\n   * The hello property.\n   *\n   * @since v1.0.0\n   */\n  hello: {\n    type: String,\n    default: 'Hello',\n  },\n  numberOrStringProp: {\n    type: [Number, String],\n    default: 42,\n  },\n  arrayProps: {\n    type: Array,\n    default: () => [42, 43, 44],\n  },\n});\n</script>\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/reference-type-props/component-js.vue",
    "content": "<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nimport { StringEmpty, StringRequired, StringUndefined } from './my-props';\n\nexport default defineComponent({\n  props: {\n    /**\n     * foo description, required prop\n     * @required\n     */\n    foo: {\n      type: String,\n      required: true,\n    },\n    /**\n     * bar description, default value BAR\n     */\n    bar: {\n      type: String,\n      default: 'BAR',\n    },\n    /**\n     * baz description, optional prop\n     */\n    baz: {\n      type: String,\n    },\n    /**\n     * xfoo description, required string prop\n     */\n    xfoo: StringRequired,\n    /**\n     * xbar description, empty string prop\n     */\n    xbar: StringEmpty,\n    xbaz: StringUndefined,\n  },\n});\n</script>\n\n<template>\n  <pre> {{ $props }}</pre>\n</template>\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/reference-type-props/component.vue",
    "content": "<script setup lang=\"ts\">\nexport interface MyNestedProps {\n  /**\n   * nested prop documentation\n   */\n  nestedProp: string;\n}\n\ninterface MyIgnoredNestedProps {\n  nestedProp: string;\n}\n\ninterface MyNestedRecursiveProps {\n  recursive: MyNestedRecursiveProps;\n}\n\nenum MyEnum {\n  Small,\n  Medium,\n  Large,\n}\n\nconst categories = [\n  'Uncategorized',\n  'Content',\n  'Interaction',\n  'Display',\n  'Forms',\n  'Addons',\n] as const;\n\ntype MyCategories = (typeof categories)[number];\n\ninterface MyProps {\n  /**\n   * string foo\n   *\n   * @default \"rounded\"\n   * @since v1.0.0\n   * @see https://vuejs.org/\n   * @deprecated v1.1.0\n   */\n  foo: string;\n  /**\n   * description bar is optional number\n   */\n  bar?: number;\n  /**\n   * description baz is required boolean\n   */\n  baz: boolean;\n  /**\n   * description stringArray is string array\n   */\n  stringArray?: string[];\n  /**\n   * description union is required union type\n   */\n  union: string | number;\n  /**\n   * description unionOptional is optional union type\n   */\n  unionOptional?: string | number | boolean;\n  /**\n   * description nested is required nested object\n   */\n  nested: MyNestedProps;\n  /**\n   * description required nested object with intersection\n   */\n  nestedIntersection: MyNestedProps & {\n    /**\n     * description required additional property\n     */\n    additionalProp: string;\n  };\n  /**\n   * description optional nested object\n   */\n  nestedOptional?: MyNestedProps | MyIgnoredNestedProps;\n  /**\n   * description required array object\n   */\n  array: MyNestedProps[];\n  /**\n   * description optional array object\n   */\n  arrayOptional?: MyNestedProps[];\n  /**\n   * description enum value\n   */\n  enumValue: MyEnum;\n  /**\n   * description literal type alias that require context\n   */\n  literalFromContext: MyCategories;\n  inlined: { foo: string };\n  recursive?: MyNestedRecursiveProps;\n}\n\nwithDefaults(defineProps<MyProps>(), {\n  bar: 1,\n  stringArray: () => ['foo', 'bar'],\n});\n</script>\n\n<template>\n  <pre>{{ JSON.stringify($props, null, 2) }}</pre>\n</template>\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/reference-type-props/my-props.ts",
    "content": "export interface MyNestedProps {\n  /** Nested prop documentation */\n  nestedProp: string;\n}\n\nexport interface MyIgnoredNestedProps {\n  nestedProp: string;\n}\n\nexport interface MyNestedRecursiveProps {\n  recursive: MyNestedRecursiveProps;\n}\n\nenum MyEnum {\n  Small,\n  Medium,\n  Large,\n}\n\nconst categories = [\n  'Uncategorized',\n  'Content',\n  'Interaction',\n  'Display',\n  'Forms',\n  'Addons',\n] as const;\n\ntype MyCategories = (typeof categories)[number];\n\nexport interface MyProps {\n  /**\n   * String foo\n   *\n   * @since V1.0.0\n   * @example\n   *\n   * ```vue\n   * <template>\n   *   <component foo=\"straight\" />\n   * </template>;\n   * ```\n   *\n   * @default 'rounded'\n   * @see https://vuejs.org/\n   */\n  foo: string;\n  /** Optional number bar */\n  bar?: number;\n  /** String array baz */\n  baz?: string[];\n  /** Required union type */\n  union: string | number;\n  /** Optional union type */\n  unionOptional?: string | number;\n  /** Required nested object */\n  nested: MyNestedProps;\n  /** Required nested object with intersection */\n  nestedIntersection: MyNestedProps & {\n    /** Required additional property */\n    additionalProp: string;\n  };\n  /** Optional nested object */\n  nestedOptional?: MyNestedProps | MyIgnoredNestedProps;\n  /** Required array object */\n  array: MyNestedProps[];\n  /** Optional array object */\n  arrayOptional?: MyNestedProps[];\n  /** Enum value */\n  enumValue: MyEnum;\n  /** Literal type alias that require context */\n  literalFromContext: MyCategories;\n  inlined: { foo: string };\n  recursive: MyNestedRecursiveProps;\n}\n\nexport const StringRequired = {\n  type: String,\n  required: true,\n} as const;\n\nexport const StringEmpty = {\n  type: String,\n  value: '',\n} as const;\n\nexport const StringUndefined = {\n  type: String,\n} as const;\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/template-slots/component-no-script.vue",
    "content": "<template>\n  <slot name=\"no-bind\"></slot>\n  <slot :num=\"123\"></slot>\n  <slot name=\"named-slot\" str=\"str\"></slot>\n  <slot name=\"vbind\" v-bind=\"{ num: 123, str: 'str' }\"></slot>\n</template>\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/template-slots/component.vue",
    "content": "<script setup lang=\"ts\"></script>\n\n<template>\n  <slot name=\"no-bind\"></slot>\n  <br />\n  <slot :num=\"123\"></slot>\n  <br />\n  <slot name=\"named\" str=\"str\"></slot>\n  <br />\n  <slot\n    name=\"vbind\"\n    v-bind=\"{ num: 123, str: 'str', obj: { title: 'see me', style: { color: 'blue' } } }\"\n  ></slot>\n</template>\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/ts-component/component.ts",
    "content": "import { defineComponent, h } from 'vue';\n\nexport default defineComponent({\n  props: {\n    /** String foo */\n    foo: {\n      type: String,\n      required: true,\n    },\n    /** Optional number bar */\n    bar: {\n      type: Number,\n    },\n  },\n  setup(props) {\n    return () => h('pre', JSON.stringify(props, null, 2));\n  },\n});\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/component-meta/ts-named-export/component.ts",
    "content": "import type { PropType } from 'vue';\nimport { defineComponent, h } from 'vue';\n\nexport const ComponentA = defineComponent({\n  name: 'MyCompo1',\n  props: {\n    /**\n     * This is a description of the prop\n     *\n     * @defaultValue 'medium'\n     * @values 'small', 'medium', 'large'\n     * @control select\n     * @group Size\n     */\n    size: {\n      type: String as PropType<'small' | 'medium' | 'large'>,\n      default: 'medium',\n    },\n    /**\n     * This is a description of the prop\n     *\n     * @defaultValue false\n     * @control color\n     * @group Style\n     */\n    backgroundColor: {\n      type: String,\n      default: 'red',\n    },\n  },\n  setup(props: any) {\n    return () => h('pre', JSON.stringify(props, null, 2));\n  },\n});\n\nexport const ComponentB = defineComponent({\n  name: 'MyCompo2',\n  props: {\n    /**\n     * This is a description of the prop\n     *\n     * @defaultValue false\n     * @values true, false\n     * @control boolean\n     * @group Size\n     */\n    primary: {\n      type: Boolean,\n      default: false,\n    },\n  },\n  setup(props: any) {\n    return () => h('pre', JSON.stringify(props, null, 2));\n  },\n});\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/decorators.stories.ts",
    "content": "import type { DecoratorFunction } from 'storybook/internal/types';\n\nimport { global as globalThis } from '@storybook/global';\nimport type { Meta, StoryObj, VueRenderer } from '@storybook/vue3';\n\nimport { useArgs } from 'storybook/preview-api';\nimport { h } from 'vue';\nimport { computed } from 'vue';\n\nconst { Button, Pre } = (globalThis as any).__TEMPLATE_COMPONENTS__;\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nconst ComponentTemplateWrapper = () => ({\n  components: {\n    Pre,\n  },\n  template: `\n    <Pre text=\"decorator\" />\n    <story v-bind=\"$attrs\"/>\n  `,\n});\n\nconst SimpleTemplateWrapper = () => ({\n  template: `\n    <div style=\"border: 5px solid red;\">\n      <story/>\n    </div>\n    `,\n});\n\nconst VueWrapperWrapper: DecoratorFunction<VueRenderer> = (storyFn, context) => {\n  // Call the `storyFn` to receive a component that Vue can render\n  const story = storyFn();\n  // Vue 3 \"Functional\" component as decorator\n  return () => {\n    return h('div', { style: 'border: 5px solid blue' }, h(story, context.args));\n  };\n};\n\nconst DynamicWrapperWrapper: DecoratorFunction<VueRenderer> = (storyFn, { args }) => ({\n  template: `<div :style=\"{ borderWidth: level, borderColor: 'green', borderStyle: 'solid' }\"><story /></div>`,\n  computed: { level: () => `${args.level}px` },\n});\n\nconst getCaptionForLocale = (locale: string) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'zh':\n      return '你好!';\n    case 'en':\n      return 'Hello!';\n    default:\n      return undefined;\n  }\n};\n\nconst updateArgsDecorator: DecoratorFunction<VueRenderer> = (story, { args }) => {\n  const [, updateArgs] = useArgs();\n  return {\n    components: { story },\n    setup() {\n      return {\n        args,\n        updateArgs,\n      };\n    },\n    template: `\n      <div>\n        <button @click=\"() => updateArgs({ label: Number(args.label) + 1 })\">Add 1</button>\n        <hr />\n        <story />\n      </div>\n    `,\n  };\n};\n\nconst localeDecorator: DecoratorFunction<VueRenderer> = (story, { globals }) => {\n  return {\n    components: { story },\n    setup() {\n      const ctxGreeting = computed(() => getCaptionForLocale(globals?.locale) || 'Hello!');\n\n      return {\n        ctxGreeting,\n        globals,\n      };\n    },\n    template: `\n      <div>\n        <p>Greeting: {{ctxGreeting}}</p>\n        <p>Locale: {{globals?.locale}}</p>\n        <story />\n      </div>\n    `,\n  };\n};\n\nexport const ComponentTemplate: Story = {\n  args: { label: 'With component' },\n  decorators: [ComponentTemplateWrapper],\n};\n\nexport const SimpleTemplate: Story = {\n  args: { label: 'With border' },\n  decorators: [SimpleTemplateWrapper],\n};\n\nexport const VueWrapper: Story = {\n  args: { label: 'With Vue wrapper' },\n  decorators: [VueWrapperWrapper],\n};\n\nexport const DynamicWrapper: Story = {\n  args: { label: 'With dynamic wrapper', primary: true },\n  argTypes: {\n    // Number type is detected, but we still want to constrain the range from 1-6\n    level: { control: { type: 'range', min: 1, max: 6 } },\n  },\n  decorators: [DynamicWrapperWrapper],\n};\n\nexport const MultipleWrappers = {\n  args: { label: 'With multiple wrappers' },\n  argTypes: {\n    // Number type is detected, but we still want to constrain the range from 1-6\n    level: { control: { type: 'range', min: 1, max: 6 } },\n  },\n  decorators: [\n    ComponentTemplateWrapper,\n    SimpleTemplateWrapper,\n    VueWrapperWrapper,\n    DynamicWrapperWrapper,\n  ],\n};\n\nexport const UpdateArgs = {\n  args: { label: '0' },\n  decorators: [updateArgsDecorator],\n};\n\nexport const ReactiveGlobalDecorator = {\n  args: { label: 'With reactive global decorator' },\n  decorators: [localeDecorator],\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/mount-in-play.stories.ts",
    "content": "import type { StoryObj } from '@storybook/vue3';\n\nimport { defineComponent } from 'vue';\n\nconst Button = defineComponent({\n  template: '<button :disabled=\"disabled\">{{label}}</button>',\n  props: ['disabled', 'label'],\n});\n\nexport default {\n  component: Button,\n};\n\nexport const Basic: StoryObj<typeof Button> = {\n  args: {\n    disabled: true,\n  },\n  async play({ mount, args }) {\n    await mount(Button, { props: { ...args, label: 'set in play' } });\n  },\n};\n"
  },
  {
    "path": "code/renderers/vue3/template/stories_vue3-vite-default-ts/preview.ts",
    "content": "declare module 'vue' {\n  interface ComponentCustomProperties {\n    $greetingMessage: (key: string) => string;\n  }\n}\n\ndeclare global {\n  // eslint-disable-next-line no-var\n  var Components: Record<string, any>;\n}\n\nexport default {};\n"
  },
  {
    "path": "code/renderers/vue3/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"allowJs\": true\n  },\n  \"include\": [\"src/**/*\", \"src/**/*.vue\", \"template/**/*\", \"template/**/*.vue\"],\n  \"vueCompilerOptions\": {\n    \"target\": 3\n  }\n}\n"
  },
  {
    "path": "code/renderers/vue3/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport vue from '@vitejs/plugin-vue';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  // @ts-expect-error seems like there's a type mismatch in the vue plugin\n  defineConfig({\n    // @ts-expect-error seems like there's a type mismatch in the vue plugin\n    plugins: [vue()],\n  })\n);\n"
  },
  {
    "path": "code/renderers/web-components/README.md",
    "content": "# Storybook web-components renderer\n\nDevelop, document, and test UI components in isolation.\n\nLearn more about Storybook at [storybook.js.org](https://storybook.js.org/?ref=readme).\n"
  },
  {
    "path": "code/renderers/web-components/build-config.ts",
    "content": "import type { BuildEntries } from '../../../scripts/build/utils/entry-utils.ts';\n\nconst config: BuildEntries = {\n  entries: {\n    browser: [\n      {\n        exportEntries: ['.'],\n        entryPoint: './src/index.ts',\n      },\n      {\n        exportEntries: ['./entry-preview'],\n        entryPoint: './src/entry-preview.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./entry-preview-argtypes'],\n        entryPoint: './src/entry-preview-argtypes.ts',\n        dts: false,\n      },\n      {\n        exportEntries: ['./entry-preview-docs'],\n        entryPoint: './src/entry-preview-docs.ts',\n        dts: false,\n      },\n    ],\n    node: [\n      {\n        exportEntries: ['./preset'],\n        entryPoint: './src/preset.ts',\n        dts: false,\n      },\n    ],\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "code/renderers/web-components/package.json",
    "content": "{\n  \"name\": \"@storybook/web-components\",\n  \"version\": \"10.4.0-alpha.6\",\n  \"description\": \"Storybook Web Components renderer: Develop, document, and test UI components in isolation\",\n  \"keywords\": [\n    \"storybook\",\n    \"storybook-renderer\",\n    \"lit\",\n    \"lit-html\",\n    \"web-components\",\n    \"component\",\n    \"components\"\n  ],\n  \"homepage\": \"https://github.com/storybookjs/storybook/tree/next/code/renderers/web-components\",\n  \"bugs\": {\n    \"url\": \"https://github.com/storybookjs/storybook/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/storybookjs/storybook.git\",\n    \"directory\": \"code/renderers/web-components\"\n  },\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/storybook\"\n  },\n  \"license\": \"MIT\",\n  \"type\": \"module\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"code\": \"./src/index.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./entry-preview\": \"./dist/entry-preview.js\",\n    \"./entry-preview-argtypes\": \"./dist/entry-preview-argtypes.js\",\n    \"./entry-preview-docs\": \"./dist/entry-preview-docs.js\",\n    \"./package.json\": \"./package.json\",\n    \"./preset\": \"./dist/preset.js\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"template/cli/**/*\",\n    \"README.md\",\n    \"*.js\",\n    \"*.d.ts\",\n    \"!src/**/*\"\n  ],\n  \"dependencies\": {\n    \"@storybook/global\": \"^5.0.0\",\n    \"tiny-invariant\": \"^1.3.1\",\n    \"ts-dedent\": \"^2.0.0\"\n  },\n  \"devDependencies\": {\n    \"@types/cross-spawn\": \"^6.0.6\",\n    \"@types/node\": \"^22.19.1\",\n    \"@types/tmp\": \"^0.2.6\",\n    \"cross-spawn\": \"^7.0.6\",\n    \"lit\": \"2.3.1\",\n    \"tmp\": \"^0.2.3\",\n    \"typescript\": \"^5.8.3\",\n    \"web-component-analyzer\": \"^1.1.6\"\n  },\n  \"peerDependencies\": {\n    \"lit\": \"^2.0.0 || ^3.0.0\",\n    \"storybook\": \"workspace:^\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"gitHead\": \"a8e7fd8a655c69780bc20b9749d2699e45beae1l\"\n}\n"
  },
  {
    "path": "code/renderers/web-components/preset.js",
    "content": "export * from './dist/preset.js';\n"
  },
  {
    "path": "code/renderers/web-components/project.json",
    "content": "{\n  \"name\": \"web-components\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"library\",\n  \"targets\": {\n    \"compile\": {},\n    \"check\": {}\n  },\n  \"tags\": [\"library\"]\n}\n"
  },
  {
    "path": "code/renderers/web-components/src/csf-factories.test.ts",
    "content": "// this file primarily tests TypeScript types with some runtime assertions\nimport { describe, expect, it, test } from 'vitest';\n\nimport type { Args } from 'storybook/internal/types';\n\nimport { LitElement, html } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\n\nimport { __definePreview } from './preview.ts';\nimport type { Decorator } from './public-types.ts';\n\ntype ButtonProps = { label: string; disabled: boolean };\n\nclass MyButton extends LitElement {\n  disabled!: boolean;\n  label!: string;\n\n  render() {\n    return html`<button>${this.label}</button>`;\n  }\n}\n\nclass MyComponent extends LitElement {\n  render() {\n    return html`\n      <button></button>\n    `;\n  }\n}\ndeclare global {\n  interface HTMLElementTagNameMap {\n    'my-button': MyButton;\n    'my-component': MyComponent;\n  }\n}\n\nconst preview = __definePreview({\n  addons: [],\n});\n\ntest('csf factories', () => {\n  const meta = preview.meta({\n    component: 'my-button',\n    args: { label: '1' },\n  });\n\n  const MyStory = meta.story({\n    args: {\n      label: 'Hello world',\n    },\n  });\n\n  expect(MyStory.input.args?.label).toBe('Hello world');\n});\n\ndescribe('Args can be provided in multiple ways', () => {\n  it('✅ All required args may be provided in meta', () => {\n    const meta = preview.meta({\n      component: 'my-button',\n      args: { label: 'good', disabled: false },\n    });\n\n    const Basic = meta.story({});\n  });\n\n  it('✅ Required args may be provided partial in meta and the story', () => {\n    const meta = preview.meta({\n      component: 'my-button',\n      args: { label: 'good' },\n    });\n    const Basic = meta.story({\n      args: { disabled: false },\n    });\n  });\n\n  it('❌ The combined shape of meta args and story args must match the required args.', () => {\n    {\n      const meta = preview.type<{ args: ButtonProps }>().meta({ component: 'my-button' });\n      // @ts-expect-error disabled not provided ❌\n      const Basic = meta.story({\n        args: { label: 'good' },\n      });\n    }\n    {\n      const meta = preview.type<{ args: ButtonProps }>().meta({\n        component: 'my-button',\n        args: { label: 'good' },\n      });\n      // @ts-expect-error disabled not provided ❌\n      const Basic = meta.story();\n    }\n    {\n      const meta = preview.type<{ args: ButtonProps }>().meta({ component: 'my-button' });\n      // @ts-expect-error disabled not provided ❌\n      const Basic = meta.story({\n        args: { label: 'good' },\n      });\n    }\n  });\n\n  it(\"✅ Required args don't need to be provided when the user uses an empty render\", () => {\n    const meta = preview.meta({\n      component: 'my-button',\n      args: { label: 'good' },\n    });\n    const Basic = meta.story({\n      render: () =>\n        html`\n          <div>Hello world</div>\n        `,\n    });\n\n    const CSF1 = meta.story(\n      () =>\n        html`\n          <div>Hello world</div>\n        `\n    );\n  });\n\n  it('❌ Required args need to be provided when the user uses a non-empty render', () => {\n    const meta = preview.type<{ args: ButtonProps }>().meta({\n      component: 'my-button',\n      args: { label: 'good' },\n    });\n    // @ts-expect-error disabled not provided ❌\n    const Basic = meta.story({\n      args: {\n        label: 'good',\n      },\n      render: (args) =>\n        html`\n          <div>Hello world</div>\n        `,\n    });\n  });\n});\n\ntype ThemeData = 'light' | 'dark';\n\ndescribe('Story args can be inferred', () => {\n  it('Correct args are inferred when type is widened for render function', () => {\n    const meta = preview.type<{ args: { theme: ThemeData } }>().meta({\n      component: 'my-button',\n      args: { disabled: false },\n      render: (args) => {\n        return html`<div class=\"theme-${args.theme}\">\n          <my-button .label=${args.label} .disabled=${args.disabled}></my-button>\n        </div>`;\n      },\n    });\n\n    const Basic = meta.story({ args: { theme: 'light', label: 'good' } });\n  });\n\n  const withDecorator: Decorator<{ decoratorArg: number }> = (Story, { args }) => html`\n    <div>Decorator: ${args.decoratorArg} ${Story()}</div>\n  `;\n\n  it('Correct args are inferred when type is widened for decorators', () => {\n    const meta = preview.meta({\n      component: 'my-button',\n      args: { disabled: false },\n      decorators: [withDecorator],\n    });\n\n    const Basic = meta.story({ args: { decoratorArg: 0, label: 'good' } });\n  });\n\n  it('Correct args are inferred when type is widened for multiple decorators', () => {\n    const secondDecorator: Decorator<{ decoratorArg2: string }> = (Story, { args }) => html`\n      <div>Decorator: ${args.decoratorArg2} ${Story()}</div>\n    `;\n\n    // decorator is not using args\n    const thirdDecorator: Decorator<Args> = (Story) => html` <div>${Story()}</div> `;\n\n    // decorator is not using args\n    const fourthDecorator: Decorator = (Story) => html` <div>${Story()}</div> `;\n\n    const meta = preview.meta({\n      component: 'my-button',\n      args: { disabled: false },\n      decorators: [withDecorator, secondDecorator, thirdDecorator, fourthDecorator],\n    });\n\n    const Basic = meta.story({\n      args: { decoratorArg: 0, decoratorArg2: '', label: 'good' },\n    });\n  });\n\n  it('args can be reused', () => {\n    const meta = preview.meta({\n      component: 'my-button',\n    });\n\n    const Enabled = meta.story({ args: { label: 'hello', disabled: false } });\n    const Disabled = meta.story({ args: { ...Enabled.input.args, disabled: true } });\n  });\n\n  it('stories can be extended', () => {\n    const meta = preview.meta({\n      component: 'my-button',\n    });\n\n    const Enabled = meta.story({ args: { label: 'hello', disabled: false } });\n    const Disabled = Enabled.extend({ args: { disabled: true } });\n  });\n});\n\nit('Components without Props can be used', () => {\n  const withDecorator: Decorator = (Story) => html` <div>${Story()}</div> `;\n\n  const meta = preview.meta({\n    component: 'my-component',\n    decorators: [withDecorator],\n  });\n\n  const Basic = meta.story();\n});\n\n// https://github.com/storybookjs/storybook/issues/33524\nit('✅ Kebab-case HTML attribute names are allowed in args', () => {\n  const meta = preview.meta({\n    component: 'my-button',\n    args: {\n      label: 'hello',\n      'aria-label': 'my button', // kebab-case attribute\n    },\n  });\n\n  const Basic = meta.story({\n    args: {\n      'data-testid': 'button-1', // kebab-case attribute\n    },\n  });\n\n  expect(meta.input.args?.['aria-label']).toBe('my button');\n  expect(Basic.input.args?.['data-testid']).toBe('button-1');\n});\n"
  },
  {
    "path": "code/renderers/web-components/src/docs/__testfixtures__/custom-elements.json",
    "content": "{\n  \"schemaVersion\": \"1.0.0\",\n  \"readme\": \"\",\n  \"modules\": [\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"demo-wc-card.js\",\n      \"declarations\": [],\n      \"exports\": [\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"demo-wc-card\",\n          \"declaration\": {\n            \"name\": \"DemoWcCard\",\n            \"module\": \"/src/stories/misc/to-update/DemoWcCard.js\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/typings.d.ts\",\n      \"declarations\": [],\n      \"exports\": []\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/components/sb-button.ts\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"description\": \"\",\n          \"name\": \"SbButton\",\n          \"cssProperties\": [\n            {\n              \"description\": \"Controls the color of bar\",\n              \"name\": \"--sb-primary-color\",\n              \"default\": \"#1ea7fd\"\n            }\n          ],\n          \"members\": [\n            {\n              \"kind\": \"field\",\n              \"name\": \"primary\",\n              \"type\": {\n                \"text\": \"boolean\"\n              },\n              \"description\": \"Set button in primary mode\",\n              \"privacy\": \"public\"\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"backgroundColor\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"privacy\": \"public\"\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"size\",\n              \"type\": {\n                \"text\": \"'small' | 'medium' | 'large'\"\n              },\n              \"default\": \"'medium'\",\n              \"privacy\": \"public\"\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"label\",\n              \"default\": \"''\",\n              \"privacy\": \"public\"\n            },\n            {\n              \"kind\": \"method\",\n              \"name\": \"onClick\",\n              \"privacy\": \"private\"\n            }\n          ],\n          \"events\": [\n            {\n              \"name\": \"sb-button:click\",\n              \"type\": {\n                \"text\": \"CustomEvent\"\n              },\n              \"description\": \"Custom event send when the button is clicked\"\n            }\n          ],\n          \"attributes\": [\n            {\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"description\": \"Label of the button\",\n              \"name\": \"label\"\n            },\n            {\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"description\": \"Size of the button, can be \\\"small\\\", \\\"medium\\\" or \\\"large\\\"; default is \\\"medium\\\".\",\n              \"name\": \"size\"\n            },\n            {\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"description\": \"Color of the button's background\",\n              \"name\": \"backgroundColor\"\n            },\n            {\n              \"name\": \"label\",\n              \"fieldName\": \"label\"\n            },\n            {\n              \"name\": \"primary\",\n              \"fieldName\": \"primary\"\n            },\n            {\n              \"name\": \"size\",\n              \"fieldName\": \"size\"\n            },\n            {\n              \"name\": \"backgroundColor\",\n              \"fieldName\": \"backgroundColor\"\n            }\n          ],\n          \"superclass\": {\n            \"name\": \"LitElement\",\n            \"package\": \"lit\"\n          },\n          \"tagName\": \"sb-button\",\n          \"summary\": \"This is a simple Storybook Button\",\n          \"customElement\": true\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"SbButton\",\n          \"declaration\": {\n            \"name\": \"SbButton\",\n            \"module\": \"src/components/sb-button.ts\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"sb-button\",\n          \"declaration\": {\n            \"name\": \"SbButton\",\n            \"module\": \"src/components/sb-button.ts\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/components/sb-header.ts\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"description\": \"\",\n          \"name\": \"SbHeader\",\n          \"members\": [\n            {\n              \"kind\": \"field\",\n              \"name\": \"user\",\n              \"type\": {\n                \"text\": \"{}\"\n              },\n              \"privacy\": \"public\"\n            },\n            {\n              \"kind\": \"method\",\n              \"name\": \"dispatchCustomEvent\",\n              \"privacy\": \"private\",\n              \"parameters\": [\n                {\n                  \"name\": \"eventName\",\n                  \"type\": {\n                    \"text\": \"string\"\n                  }\n                }\n              ]\n            },\n            {\n              \"kind\": \"method\",\n              \"name\": \"logInOutButton\",\n              \"privacy\": \"private\"\n            }\n          ],\n          \"events\": [\n            {\n              \"type\": {\n                \"text\": \"CustomEvent\"\n              }\n            },\n            {\n              \"type\": {\n                \"text\": \"CustomEvent\"\n              },\n              \"description\": \"Event send when user clicks on create account button\",\n              \"name\": \"sb-header:createAccount\"\n            },\n            {\n              \"type\": {\n                \"text\": \"CustomEvent\"\n              },\n              \"description\": \"Event send when user clicks on login button\",\n              \"name\": \"sb-header:login\"\n            },\n            {\n              \"type\": {\n                \"text\": \"CustomEvent\"\n              },\n              \"description\": \"Event send when user clicks on logout button\",\n              \"name\": \"sb-header:logout\"\n            }\n          ],\n          \"attributes\": [\n            {\n              \"type\": {\n                \"text\": \"Object\"\n              },\n              \"description\": \"User of the app\",\n              \"name\": \"user\"\n            },\n            {\n              \"name\": \"user\",\n              \"fieldName\": \"user\"\n            }\n          ],\n          \"superclass\": {\n            \"name\": \"LitElement\",\n            \"package\": \"lit\"\n          },\n          \"tagName\": \"sb-header\",\n          \"summary\": \"This is a simple Storybook Header\",\n          \"customElement\": true\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"SbHeader\",\n          \"declaration\": {\n            \"name\": \"SbHeader\",\n            \"module\": \"src/components/sb-header.ts\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"sb-header\",\n          \"declaration\": {\n            \"name\": \"SbHeader\",\n            \"module\": \"src/components/sb-header.ts\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/components/sb-page.ts\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"description\": \"\",\n          \"name\": \"SbPage\",\n          \"members\": [\n            {\n              \"kind\": \"field\",\n              \"name\": \"user\",\n              \"type\": {\n                \"text\": \"{}\"\n              },\n              \"privacy\": \"public\"\n            }\n          ],\n          \"attributes\": [\n            {\n              \"type\": {\n                \"text\": \"Object\"\n              },\n              \"description\": \"User of the app\",\n              \"name\": \"user\"\n            },\n            {\n              \"name\": \"user\",\n              \"fieldName\": \"user\"\n            }\n          ],\n          \"superclass\": {\n            \"name\": \"LitElement\",\n            \"package\": \"lit\"\n          },\n          \"tagName\": \"sb-page\",\n          \"summary\": \"This is a simple Storybook Page\",\n          \"customElement\": true\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"SbPage\",\n          \"declaration\": {\n            \"name\": \"SbPage\",\n            \"module\": \"src/components/sb-page.ts\"\n          }\n        },\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"sb-page\",\n          \"declaration\": {\n            \"name\": \"SbPage\",\n            \"module\": \"src/components/sb-page.ts\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/stories/misc/to-update/DemoWcCard.js\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"description\": \"This is a container looking like a card with a back and front side you can switch\",\n          \"name\": \"DemoWcCard\",\n          \"cssProperties\": [\n            {\n              \"description\": \"Header font size\",\n              \"name\": \"--demo-wc-card-header-font-size\"\n            },\n            {\n              \"description\": \"Font color for front\",\n              \"name\": \"--demo-wc-card-front-color\"\n            },\n            {\n              \"description\": \"Font color for back\",\n              \"name\": \"--demo-wc-card-back-color\"\n            }\n          ],\n          \"cssParts\": [\n            {\n              \"description\": \"Front of the card\",\n              \"name\": \"front\"\n            },\n            {\n              \"description\": \"Back of the card\",\n              \"name\": \"back\"\n            }\n          ],\n          \"slots\": [\n            {\n              \"description\": \"This is an unnamed slot (the default slot)\",\n              \"name\": \"\"\n            }\n          ],\n          \"members\": [\n            {\n              \"kind\": \"method\",\n              \"name\": \"toggle\"\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"backSide\",\n              \"privacy\": \"public\",\n              \"description\": \"Indicates that the back of the card is shown\",\n              \"default\": \"false\"\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"header\",\n              \"privacy\": \"public\",\n              \"description\": \"Header message\",\n              \"default\": \"'Your Message'\"\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"rows\",\n              \"privacy\": \"public\",\n              \"description\": \"Data rows\",\n              \"default\": \"[]\"\n            }\n          ],\n          \"events\": [\n            {\n              \"name\": \"side-changed\",\n              \"type\": {\n                \"text\": \"CustomEvent\"\n              },\n              \"description\": \"Fires whenever it switches between front/back\"\n            }\n          ],\n          \"attributes\": [\n            {\n              \"name\": \"back-side\",\n              \"fieldName\": \"backSide\"\n            },\n            {\n              \"name\": \"header\",\n              \"fieldName\": \"header\"\n            },\n            {\n              \"name\": \"rows\",\n              \"fieldName\": \"rows\"\n            }\n          ],\n          \"superclass\": {\n            \"name\": \"LitElement\",\n            \"package\": \"lit\"\n          },\n          \"tagName\": \"demo-wc-card\",\n          \"customElement\": true\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"DemoWcCard\",\n          \"declaration\": {\n            \"name\": \"DemoWcCard\",\n            \"module\": \"src/stories/misc/to-update/DemoWcCard.js\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"src/stories/misc/to-update/demoWcCardStyle.css.js\",\n      \"declarations\": [\n        {\n          \"kind\": \"variable\",\n          \"name\": \"demoWcCardStyle\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"demoWcCardStyle\",\n          \"declaration\": {\n            \"name\": \"demoWcCardStyle\",\n            \"module\": \"src/stories/misc/to-update/demoWcCardStyle.css.js\"\n          }\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "code/renderers/web-components/src/docs/__testfixtures__/lit-element-demo-card/custom-elements.snapshot",
    "content": "{\n  \"tags\": [\n    {\n      \"attributes\": [\n        {\n          \"default\": \"false\",\n          \"description\": \"Indicates that the back of the card is shown\",\n          \"name\": \"back-side\",\n          \"type\": \"boolean\",\n        },\n        {\n          \"default\": \"\"Your Message\"\",\n          \"description\": \"Header message\",\n          \"name\": \"header\",\n          \"type\": \"string\",\n        },\n        {\n          \"default\": \"[]\",\n          \"description\": \"Data rows\",\n          \"name\": \"rows\",\n          \"type\": \"object\",\n        },\n      ],\n      \"cssParts\": [\n        {\n          \"description\": \"Front of the card\",\n          \"name\": \"front\",\n        },\n        {\n          \"description\": \"Back of the card\",\n          \"name\": \"back\",\n        },\n      ],\n      \"cssProperties\": [\n        {\n          \"description\": \"Header font size\",\n          \"name\": \"--demo-wc-card-header-font-size\",\n        },\n        {\n          \"description\": \"Font color for front\",\n          \"name\": \"--demo-wc-card-front-color\",\n        },\n        {\n          \"description\": \"Font color for back\",\n          \"name\": \"--demo-wc-card-back-color\",\n        },\n      ],\n      \"description\": \"This is a container looking like a card with a back and front side you can switch\",\n      \"events\": [\n        {\n          \"description\": \"Fires whenever it switches between front/back\",\n          \"name\": \"side-changed\",\n        },\n      ],\n      \"name\": \"input\",\n      \"path\": \"dummy-path-to-component\",\n      \"properties\": [\n        {\n          \"attribute\": \"back-side\",\n          \"default\": \"false\",\n          \"description\": \"Indicates that the back of the card is shown\",\n          \"name\": \"backSide\",\n          \"type\": \"boolean\",\n        },\n        {\n          \"attribute\": \"header\",\n          \"default\": \"\"Your Message\"\",\n          \"description\": \"Header message\",\n          \"name\": \"header\",\n          \"type\": \"string\",\n        },\n        {\n          \"attribute\": \"rows\",\n          \"default\": \"[]\",\n          \"description\": \"Data rows\",\n          \"name\": \"rows\",\n          \"type\": \"object\",\n        },\n      ],\n      \"slots\": [\n        {\n          \"description\": \"This is an unnamed slot (the default slot)\",\n          \"name\": \"\",\n        },\n      ],\n    },\n  ],\n  \"version\": \"experimental\",\n}"
  },
  {
    "path": "code/renderers/web-components/src/docs/__testfixtures__/lit-element-demo-card/input.js",
    "content": "import { global } from '@storybook/global';\n\nimport { LitElement, css, html } from 'lit-element';\n\nconst { CustomEvent } = global;\n\nconst demoWcCardStyle = css`\n  :host {\n    display: block;\n    position: relative;\n    width: 250px;\n    height: 200px;\n    border-radius: 10px;\n    transform-style: preserve-3d;\n    transition: all 0.8s ease;\n  }\n\n  .header {\n    font-weight: bold;\n    font-size: var(--demo-wc-card-header-font-size, 16px);\n    text-align: center;\n  }\n\n  .content {\n    padding: 20px 10px 0 10px;\n    flex-grow: 1;\n  }\n\n  .footer {\n    display: flex;\n  }\n\n  dl {\n    margin: 0;\n    text-align: left;\n  }\n\n  dd {\n    margin-left: 15px;\n  }\n\n  button {\n    border-radius: 15px;\n    width: 30px;\n    height: 30px;\n    background: #fff;\n    border: 1px solid #ccc;\n    color: #000;\n    font-size: 21px;\n    line-height: 27px;\n    font-weight: bold;\n    cursor: pointer;\n    margin: 5px;\n  }\n\n  .note {\n    flex-grow: 1;\n    color: #666;\n    font-size: 16px;\n    font-weight: bold;\n    text-align: left;\n    padding-top: 15px;\n  }\n\n  :host([back-side]) {\n    transform: rotateY(180deg);\n  }\n\n  #front,\n  #back {\n    position: absolute;\n    width: 250px;\n    box-sizing: border-box;\n    box-shadow: #ccc 3px 3px 2px 1px;\n    padding: 10px;\n    display: flex;\n    flex-flow: column;\n    top: 0;\n    left: 0;\n    height: 100%;\n    border-radius: 10px;\n    backface-visibility: hidden;\n    overflow: hidden;\n  }\n\n  #front {\n    background: linear-gradient(141deg, #aaa 25%, #eee 40%, #ddd 55%);\n    color: var(--demo-wc-card-front-color, #000);\n  }\n\n  #back {\n    background: linear-gradient(141deg, #333 25%, #aaa 40%, #666 55%);\n    color: var(--demo-wc-card-back-color, #fff);\n    text-align: center;\n    transform: rotateY(180deg) translate3d(0px, 0, 1px);\n  }\n\n  #back .note {\n    color: #fff;\n  }\n`;\n\n/**\n * This is a container looking like a card with a back and front side you can switch\n *\n * @fires side-changed - Fires whenever it switches between front/back\n * @slot - This is an unnamed slot (the default slot)\n * @cssprop --demo-wc-card-header-font-size - Header font size\n * @cssprop --demo-wc-card-front-color - Font color for front\n * @cssprop --demo-wc-card-back-color - Font color for back\n * @csspart front - Front of the card\n * @csspart back - Back of the card\n */\nexport class DemoWcCard extends LitElement {\n  static get properties() {\n    return {\n      backSide: {\n        type: Boolean,\n        reflect: true,\n        attribute: 'back-side',\n      },\n      header: { type: String },\n      rows: { type: Object },\n    };\n  }\n\n  static get styles() {\n    return demoWcCardStyle;\n  }\n\n  constructor() {\n    super();\n\n    /** Indicates that the back of the card is shown */\n    this.backSide = false;\n\n    /** Header message */\n    this.header = 'Your Message';\n\n    /** Data rows */\n    this.rows = [];\n  }\n\n  toggle() {\n    this.backSide = !this.backSide;\n  }\n\n  render() {\n    return html`\n      <div id=\"front\" part=\"front\">\n        <div class=\"header\">${this.header}</div>\n        <div class=\"content\">\n          <slot></slot>\n        </div>\n        <div class=\"footer\">\n          <div class=\"note\">A</div>\n          <button @click=${this.toggle}>></button>\n        </div>\n      </div>\n      <div id=\"back\" part=\"back\">\n        <div class=\"header\">${this.header}</div>\n\n        <div class=\"content\">\n          ${\n            this.rows.length === 0\n              ? html``\n              : html`\n                <dl>\n                  ${this.rows.map(\n                    (row) => html`\n                      <dt>${row.header}</dt>\n                      <dd>${row.value}</dd>\n                    `\n                  )}\n                </dl>\n              `\n          }\n        </div>\n        <div class=\"footer\">\n          <div class=\"note\">B</div>\n          <button @click=${this.toggle}>></button>\n        </div>\n      </div>\n    `;\n  }\n\n  updated(changedProperties) {\n    if (changedProperties.has('backSide') && changedProperties.get('backSide') !== undefined) {\n      this.dispatchEvent(new CustomEvent('side-changed'));\n    }\n  }\n}\n\ncustomElements.define('input', DemoWcCard);\n"
  },
  {
    "path": "code/renderers/web-components/src/docs/__testfixtures__/lit-element-demo-card/properties.snapshot",
    "content": "{\n  \"--demo-wc-card-back-color\": {\n    \"description\": \"Font color for back\",\n    \"name\": \"--demo-wc-card-back-color\",\n    \"required\": false,\n    \"table\": {\n      \"category\": \"css custom properties\",\n      \"defaultValue\": {\n        \"summary\": undefined,\n      },\n      \"type\": {\n        \"summary\": undefined,\n      },\n    },\n    \"type\": {\n      \"name\": \"void\",\n    },\n  },\n  \"--demo-wc-card-front-color\": {\n    \"description\": \"Font color for front\",\n    \"name\": \"--demo-wc-card-front-color\",\n    \"required\": false,\n    \"table\": {\n      \"category\": \"css custom properties\",\n      \"defaultValue\": {\n        \"summary\": undefined,\n      },\n      \"type\": {\n        \"summary\": undefined,\n      },\n    },\n    \"type\": {\n      \"name\": \"void\",\n    },\n  },\n  \"--demo-wc-card-header-font-size\": {\n    \"description\": \"Header font size\",\n    \"name\": \"--demo-wc-card-header-font-size\",\n    \"required\": false,\n    \"table\": {\n      \"category\": \"css custom properties\",\n      \"defaultValue\": {\n        \"summary\": undefined,\n      },\n      \"type\": {\n        \"summary\": undefined,\n      },\n    },\n    \"type\": {\n      \"name\": \"void\",\n    },\n  },\n  \"back\": {\n    \"description\": \"Back of the card\",\n    \"name\": \"back\",\n    \"required\": false,\n    \"table\": {\n      \"category\": \"css shadow parts\",\n      \"defaultValue\": {\n        \"summary\": undefined,\n      },\n      \"type\": {\n        \"summary\": undefined,\n      },\n    },\n    \"type\": {\n      \"name\": \"void\",\n    },\n  },\n  \"back-side\": {\n    \"description\": \"Indicates that the back of the card is shown\",\n    \"name\": \"back-side\",\n    \"required\": false,\n    \"table\": {\n      \"category\": \"attributes\",\n      \"defaultValue\": {\n        \"summary\": \"false\",\n      },\n      \"type\": {\n        \"summary\": \"boolean\",\n      },\n    },\n    \"type\": {\n      \"name\": \"boolean\",\n    },\n  },\n  \"backSide\": {\n    \"description\": \"Indicates that the back of the card is shown\",\n    \"name\": \"backSide\",\n    \"required\": false,\n    \"table\": {\n      \"category\": \"properties\",\n      \"defaultValue\": {\n        \"summary\": \"false\",\n      },\n      \"type\": {\n        \"summary\": \"boolean\",\n      },\n    },\n    \"type\": {\n      \"name\": \"boolean\",\n    },\n  },\n  \"front\": {\n    \"description\": \"Front of the card\",\n    \"name\": \"front\",\n    \"required\": false,\n    \"table\": {\n      \"category\": \"css shadow parts\",\n      \"defaultValue\": {\n        \"summary\": undefined,\n      },\n      \"type\": {\n        \"summary\": undefined,\n      },\n    },\n    \"type\": {\n      \"name\": \"void\",\n    },\n  },\n  \"header\": {\n    \"description\": \"Header message\",\n    \"name\": \"header\",\n    \"required\": false,\n    \"table\": {\n      \"category\": \"attributes\",\n      \"defaultValue\": {\n        \"summary\": \"\"Your Message\"\",\n      },\n      \"type\": {\n        \"summary\": \"string\",\n      },\n    },\n    \"type\": {\n      \"name\": \"string\",\n    },\n  },\n  \"onSideChanged\": {\n    \"action\": {\n      \"name\": \"side-changed\",\n    },\n    \"name\": \"onSideChanged\",\n    \"table\": {\n      \"disable\": true,\n    },\n  },\n  \"rows\": {\n    \"description\": \"Data rows\",\n    \"name\": \"rows\",\n    \"required\": false,\n    \"table\": {\n      \"category\": \"attributes\",\n      \"defaultValue\": {\n        \"summary\": \"[]\",\n      },\n      \"type\": {\n        \"summary\": \"object\",\n      },\n    },\n    \"type\": {\n      \"name\": \"object\",\n    },\n  },\n  \"side-changed\": {\n    \"description\": \"Fires whenever it switches between front/back\",\n    \"name\": \"side-changed\",\n    \"required\": false,\n    \"table\": {\n      \"category\": \"events\",\n      \"defaultValue\": {\n        \"summary\": undefined,\n      },\n      \"type\": {\n        \"summary\": undefined,\n      },\n    },\n    \"type\": {\n      \"name\": \"void\",\n    },\n  },\n}"
  },
  {
    "path": "code/renderers/web-components/src/docs/__testfixtures__/lit-html-welcome/custom-elements.snapshot",
    "content": "{\n  \"tags\": [\n    {\n      \"name\": \"input\",\n      \"path\": \"dummy-path-to-component\",\n    },\n  ],\n  \"version\": \"experimental\",\n}"
  },
  {
    "path": "code/renderers/web-components/src/docs/__testfixtures__/lit-html-welcome/input.js",
    "content": "import { html } from 'lit';\n\nexport const Welcome = () => html`\n  <div class=\"main\">\n    <h1>Welcome to Storybook for Web Components</h1>\n    <p>This is a UI component dev environment for your plain HTML snippets.</p>\n    <p>\n      We've added some basic stories inside the <code class=\"code\">stories</code> directory.\n      <br />\n      A story is a single state of one or more UI components. You can have as many stories as you\n      want.\n      <br />\n      (Basically a story is like a visual test case.)\n    </p>\n    <p>\n      See these sample\n      <a class=\"link\" href=\"#\" data-sb-kind=\"Demo Card\" data-sb-story=\"Front\">stories</a>\n    </p>\n    <p>\n      Just like that, you can add your own snippets as stories.\n      <br />\n      You can also edit those snippets and see changes right away.\n      <br />\n    </p>\n    <p>\n      Usually we create stories with smaller UI components in the app.<br />\n      Have a look at the\n      <a class=\"link\" href=\"https://storybook.js.org/basics/writing-stories\" target=\"_blank\">\n        Writing Stories\n      </a>\n      section in our documentation.\n    </p>\n  </div>\n\n  <style>\n    .main {\n      padding: 15px;\n      line-height: 1.4;\n      font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;\n      background-color: #ffffff;\n    }\n\n    .logo {\n      width: 256px;\n      margin: 15px;\n    }\n\n    .code {\n      font-size: 15px;\n      font-weight: 600;\n      padding: 2px 5px;\n      border: 1px solid #eae9e9;\n      border-radius: 4px;\n      background-color: #f3f2f2;\n      color: #3a3a3a;\n    }\n  </style>\n`;\n\ncustomElements.define('input', Welcome);\n"
  },
  {
    "path": "code/renderers/web-components/src/docs/__testfixtures__/lit-html-welcome/properties.snapshot",
    "content": "{}"
  },
  {
    "path": "code/renderers/web-components/src/docs/custom-elements.test.ts",
    "content": "// @vitest-environment happy-dom\nimport { afterEach, beforeEach, describe, expect, it } from 'vitest';\n\nimport { global } from '@storybook/global';\n\nimport customElementsManifest from './__testfixtures__/custom-elements.json';\nimport { extractArgTypes } from './custom-elements';\n\nconst { window } = global;\n\ndescribe('extractArgTypes', () => {\n  beforeEach(() => {\n    window.__STORYBOOK_CUSTOM_ELEMENTS_MANIFEST__ = customElementsManifest;\n  });\n\n  afterEach(() => {\n    window.__STORYBOOK_CUSTOM_ELEMENTS_MANIFEST__ = undefined;\n  });\n\n  describe('events', () => {\n    it('should map to an action event handler', () => {\n      const extractedArgType = extractArgTypes('sb-header');\n\n      expect(extractedArgType?.onSbHeaderCreateAccount).toEqual({\n        name: 'onSbHeaderCreateAccount',\n        action: { name: 'sb-header:createAccount' },\n        table: { disable: true },\n      });\n    });\n\n    it('should map to a regular item', () => {\n      const extractedArgType = extractArgTypes('sb-header');\n\n      expect(extractedArgType?.['sb-header:createAccount']).toEqual({\n        name: 'sb-header:createAccount',\n        required: false,\n        description: 'Event send when user clicks on create account button',\n        type: { name: 'void' },\n        table: {\n          category: 'events',\n          type: { summary: 'CustomEvent' },\n          defaultValue: { summary: undefined },\n        },\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "code/renderers/web-components/src/docs/custom-elements.ts",
    "content": "import { logger } from 'storybook/internal/client-logger';\nimport type { ArgTypes, InputType } from 'storybook/internal/types';\n\nimport invariant from 'tiny-invariant';\n\nimport { getCustomElements, isValidComponent, isValidMetaData } from '..';\n\ninterface TagItem {\n  name: string;\n  type: { [key: string]: any };\n  description: string;\n  default?: any;\n  kind?: string;\n  defaultValue?: any;\n}\n\ninterface Tag {\n  name: string;\n  description: string;\n  attributes?: TagItem[];\n  properties?: TagItem[];\n  events?: TagItem[];\n  methods?: TagItem[];\n  members?: TagItem[];\n  slots?: TagItem[];\n  cssProperties?: TagItem[];\n  cssParts?: TagItem[];\n}\n\ninterface CustomElements {\n  tags: Tag[];\n  modules?: [];\n}\n\ninterface Module {\n  declarations?: [];\n  exports?: [];\n}\n\ninterface Declaration {\n  tagName: string;\n}\n\nfunction mapItem(item: TagItem, category: string): InputType {\n  let type;\n  switch (category) {\n    case 'attributes':\n    case 'properties':\n      type = { name: item.type?.text || item.type };\n      break;\n    case 'slots':\n      type = { name: 'string' };\n      break;\n    default:\n      type = { name: 'void' };\n      break;\n  }\n\n  return {\n    name: item.name,\n    required: false,\n    description: item.description,\n    type,\n    table: {\n      category,\n      type: { summary: item.type?.text || item.type },\n      defaultValue: {\n        summary: item.default !== undefined ? item.default : item.defaultValue,\n      },\n    },\n  };\n}\n\nfunction mapEvent(item: TagItem): InputType[] {\n  let name = item.name\n    .replace(/(-|_|:|\\.|\\s)+(.)?/g, (_match, _separator, chr: string) => {\n      return chr ? chr.toUpperCase() : '';\n    })\n    .replace(/^([A-Z])/, (match) => match.toLowerCase());\n\n  name = `on${name.charAt(0).toUpperCase() + name.substr(1)}`;\n\n  return [{ name, action: { name: item.name }, table: { disable: true } }, mapItem(item, 'events')];\n}\n\nfunction mapData(data: TagItem[], category: string) {\n  return (\n    data &&\n    data\n      .filter((item) => item && item.name)\n      .reduce((acc, item) => {\n        if (item.kind === 'method') {\n          return acc;\n        }\n\n        switch (category) {\n          case 'events':\n            mapEvent(item).forEach((argType) => {\n              invariant(argType.name, `${argType} should have a name property.`);\n              acc[argType.name] = argType;\n            });\n            break;\n          default:\n            acc[item.name] = mapItem(item, category);\n            break;\n        }\n\n        return acc;\n      }, {} as ArgTypes)\n  );\n}\n\nconst getMetaDataExperimental = (tagName: string, customElements: CustomElements) => {\n  if (!isValidComponent(tagName) || !isValidMetaData(customElements)) {\n    return null;\n  }\n  const metaData = customElements.tags.find(\n    (tag) => tag.name.toUpperCase() === tagName.toUpperCase()\n  );\n  if (!metaData) {\n    logger.warn(`Component not found in custom-elements.json: ${tagName}`);\n  }\n  return metaData;\n};\n\nconst getMetaDataV1 = (tagName: string, customElements: CustomElements) => {\n  if (!isValidComponent(tagName) || !isValidMetaData(customElements)) {\n    return null;\n  }\n\n  let metadata;\n  customElements?.modules?.forEach((_module: Module) => {\n    _module?.declarations?.forEach((declaration: Declaration) => {\n      if (declaration.tagName === tagName) {\n        metadata = declaration;\n      }\n    });\n  });\n\n  if (!metadata) {\n    logger.warn(`Component not found in custom-elements.json: ${tagName}`);\n  }\n  return metadata;\n};\n\nconst getMetaData = (tagName: string, manifest: any) => {\n  if (manifest?.version === 'experimental') {\n    return getMetaDataExperimental(tagName, manifest);\n  }\n  return getMetaDataV1(tagName, manifest);\n};\n\nexport const extractArgTypesFromElements = (tagName: string, customElements: CustomElements) => {\n  const metaData = getMetaData(tagName, customElements);\n  return (\n    metaData && {\n      ...mapData(metaData.members ?? [], 'properties'),\n      ...mapData(metaData.properties ?? [], 'properties'),\n      ...mapData(metaData.attributes ?? [], 'attributes'),\n      ...mapData(metaData.events ?? [], 'events'),\n      ...mapData(metaData.slots ?? [], 'slots'),\n      ...mapData(metaData.cssProperties ?? [], 'css custom properties'),\n      ...mapData(metaData.cssParts ?? [], 'css shadow parts'),\n    }\n  );\n};\n\nexport const extractArgTypes = (tagName: string) => {\n  const cem = getCustomElements();\n  return extractArgTypesFromElements(tagName, cem);\n};\n\nexport const extractComponentDescription = (tagName: string) => {\n  const metaData = getMetaData(tagName, getCustomElements());\n  return metaData && metaData.description;\n};\n"
  },
  {
    "path": "code/renderers/web-components/src/docs/sourceDecorator.test.ts",
    "content": "/** @vitest-environment happy-dom */\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { SourceType } from 'storybook/internal/docs-tools';\n\nimport { render } from 'lit';\nimport { addons, emitTransformCode, useEffect, useRef } from 'storybook/preview-api';\n\nimport { sourceDecorator } from './sourceDecorator';\n\nvi.mock('storybook/preview-api', () => ({\n  addons: {\n    getChannel: vi.fn(),\n  },\n  useEffect: vi.fn((cb) => cb()),\n  useRef: vi.fn(),\n  emitTransformCode: vi.fn((code) => code),\n}));\n\nvi.mock('lit', () => ({\n  render: vi.fn(),\n}));\n\nconst tick = () => new Promise((r) => setTimeout(r, 0));\n\ndescribe('sourceDecorator', () => {\n  const mockChannel = {\n    emit: vi.fn(),\n  };\n\n  const mockContext = {\n    id: 'test-story',\n    args: { foo: 'bar' },\n    unmappedArgs: { foo: 'bar' },\n    parameters: {\n      docs: {\n        source: {},\n      },\n      __isArgsStory: true,\n    },\n    originalStoryFn: vi.fn(),\n  };\n\n  beforeEach(() => {\n    vi.clearAllMocks();\n    vi.mocked(useRef).mockReturnValue({ current: undefined });\n    vi.mocked(addons.getChannel).mockReturnValue(mockChannel as any);\n    vi.mocked(useEffect).mockImplementation((cb) => setTimeout(() => cb(), 0));\n  });\n\n  it('should render source for a basic story', () => {\n    const storyFn = () => document.createElement('div');\n    const mockDiv = document.createElement('div');\n    mockDiv.innerHTML = '<test-element>content</test-element>';\n    vi.mocked(render).mockImplementation((_, container): any => {\n      if (container instanceof HTMLElement) {\n        container.innerHTML = '<test-element>content</test-element>';\n      }\n    });\n\n    sourceDecorator(storyFn, mockContext as any);\n\n    expect(render).toHaveBeenCalled();\n  });\n\n  it('should skip source rendering when type is CODE', () => {\n    const storyFn = () => document.createElement('div');\n    const contextWithCode = {\n      ...mockContext,\n      parameters: {\n        docs: {\n          source: {\n            type: SourceType.CODE,\n          },\n        },\n      },\n    };\n\n    sourceDecorator(storyFn, contextWithCode as any);\n\n    expect(render).not.toHaveBeenCalled();\n    expect(mockChannel.emit).not.toHaveBeenCalled();\n  });\n\n  it('should handle DocumentFragment stories', async () => {\n    const fragment = document.createDocumentFragment();\n    const element = document.createElement('test-element');\n    element.textContent = 'fragment content';\n    fragment.appendChild(element);\n\n    const storyFn = () => fragment;\n    vi.mocked(render).mockImplementation((_, container): any => {\n      if (container instanceof HTMLElement) {\n        container.innerHTML = '<test-element>fragment content</test-element>';\n      }\n    });\n\n    sourceDecorator(storyFn, mockContext as any);\n    await tick();\n\n    expect(render).toHaveBeenCalled();\n    expect(emitTransformCode).toHaveBeenCalledWith(\n      '<test-element>fragment content</test-element>',\n      mockContext\n    );\n  });\n\n  it('should force render when type is DYNAMIC', async () => {\n    const storyFn = () => document.createElement('div');\n    const contextWithDynamic = {\n      ...mockContext,\n      parameters: {\n        docs: {\n          source: {\n            type: SourceType.DYNAMIC,\n          },\n        },\n        __isArgsStory: false, // This would normally prevent rendering\n      },\n    };\n\n    vi.mocked(render).mockImplementation((_, container): any => {\n      if (container instanceof HTMLElement) {\n        container.innerHTML = '<test-element>dynamic content</test-element>';\n      }\n    });\n\n    sourceDecorator(storyFn, contextWithDynamic as any);\n\n    await tick();\n\n    expect(render).toHaveBeenCalled();\n    expect(emitTransformCode).toHaveBeenCalledWith(\n      '<test-element>dynamic content</test-element>',\n      contextWithDynamic\n    );\n  });\n});\n"
  },
  {
    "path": "code/renderers/web-components/src/docs/sourceDecorator.ts",
    "content": "import { SourceType } from 'storybook/internal/docs-tools';\nimport type { ArgsStoryFn, PartialStoryFn, StoryContext } from 'storybook/internal/types';\n\nimport { render } from 'lit';\nimport { emitTransformCode, useEffect } from 'storybook/preview-api';\n\nimport type { WebComponentsRenderer } from '../types';\n\n// Taken from https://github.com/lit/lit/blob/main/packages/lit-html/src/test/test-utils/strip-markers.ts\nconst LIT_EXPRESSION_COMMENTS = /<!--\\?lit\\$[0-9]+\\$-->|<!--\\??-->/g;\n\nfunction skipSourceRender(context: StoryContext<WebComponentsRenderer>) {\n  const sourceParams = context?.parameters.docs?.source;\n  const isArgsStory = context?.parameters.__isArgsStory;\n\n  // always render if the user forces it\n  if (sourceParams?.type === SourceType.DYNAMIC) {\n    return false;\n  }\n\n  // never render if the user is forcing the block to render code, or\n  // if the user provides code, or if it's not an args story.\n  return !isArgsStory || sourceParams?.code || sourceParams?.type === SourceType.CODE;\n}\n\nexport function sourceDecorator(\n  storyFn: PartialStoryFn<WebComponentsRenderer>,\n  context: StoryContext<WebComponentsRenderer>\n): WebComponentsRenderer['storyResult'] {\n  const story = storyFn();\n  const renderedForSource = context?.parameters.docs?.source?.excludeDecorators\n    ? (context.originalStoryFn as ArgsStoryFn<WebComponentsRenderer>)(context.args, context)\n    : story;\n\n  let source: string;\n\n  useEffect(() => {\n    if (source) {\n      emitTransformCode(source, context);\n    }\n  });\n\n  if (!skipSourceRender(context)) {\n    const container = window.document.createElement('div');\n    if (renderedForSource instanceof DocumentFragment) {\n      render(renderedForSource.cloneNode(true), container);\n    } else {\n      render(renderedForSource, container);\n    }\n    source = container.innerHTML.replace(LIT_EXPRESSION_COMMENTS, '');\n  }\n\n  return story;\n}\n"
  },
  {
    "path": "code/renderers/web-components/src/docs/web-components-properties.test.ts",
    "content": "// @vitest-environment happy-dom\nimport { readdirSync } from 'node:fs';\nimport { readFile, readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { describe, expect, it, vi } from 'vitest';\n\nimport { spawn } from 'cross-spawn';\nimport tmp from 'tmp';\n\nimport { extractArgTypesFromElements } from './custom-elements';\n\n// File hierarchy:\n// __testfixtures__ / some-test-case / input.*\nconst inputRegExp = /^input\\..*$/;\n\nconst runWebComponentsAnalyzer = async (inputPath: string): Promise<string> => {\n  const { name: tmpDir, removeCallback } = tmp.dirSync();\n  const customElementsFile = `${tmpDir}/custom-elements.json`;\n  const process = await spawn(\n    join(__dirname, '../../../../../node_modules/.bin/wca'),\n    ['analyze', inputPath, '--outFile', customElementsFile],\n    {\n      stdio: 'ignore',\n      shell: true,\n    }\n  );\n\n  await new Promise((resolve, reject) => {\n    process.on('close', resolve);\n    process.on('error', reject);\n  });\n\n  const output = await readFile(customElementsFile, 'utf8');\n  try {\n    removeCallback();\n  } catch (e) {\n    //\n  }\n  return output;\n};\n\nvi.mock('lit', () => ({ default: {} }));\nvi.mock('lit/directive-helpers.js', () => ({ default: {} }));\n\ndescribe('web-components component properties', { timeout: 15000, retry: 3 }, () => {\n  // we need to mock lit and dynamically require custom-elements\n  // because lit is distributed as ESM not CJS\n  // https://github.com/Polymer/lit-html/issues/516\n\n  const fixturesDir = join(__dirname, '__testfixtures__');\n  const testEntries = readdirSync(fixturesDir, { withFileTypes: true });\n\n  it.each(testEntries)('$name', async (testEntry) => {\n    if (testEntry.isDirectory()) {\n      const testDir = join(fixturesDir, testEntry.name);\n      const testFile = (await readdir(testDir)).find((fileName) => inputRegExp.test(fileName));\n      if (testFile) {\n        const inputPath = join(testDir, testFile);\n\n        // snapshot the output of wca\n        const customElementsJson = await runWebComponentsAnalyzer(inputPath);\n        const customElements = JSON.parse(customElementsJson);\n        customElements.tags.forEach((tag: any) => {\n          tag.path = 'dummy-path-to-component';\n        });\n        await expect(customElements).toMatchFileSnapshot(join(testDir, 'custom-elements.snapshot'));\n\n        // snapshot the properties\n        const properties = extractArgTypesFromElements('input', customElements);\n        await expect(properties).toMatchFileSnapshot(join(testDir, 'properties.snapshot'));\n      }\n    }\n  });\n});\n"
  },
  {
    "path": "code/renderers/web-components/src/entry-preview-argtypes.ts",
    "content": "import { enhanceArgTypes } from 'storybook/internal/docs-tools';\nimport type { ArgTypesEnhancer } from 'storybook/internal/types';\n\nimport { extractArgTypes, extractComponentDescription } from './docs/custom-elements.ts';\nimport type { WebComponentsRenderer } from './types.ts';\n\nexport const parameters = {\n  docs: {\n    extractArgTypes,\n    extractComponentDescription,\n  },\n};\n\nexport const argTypesEnhancers: ArgTypesEnhancer<WebComponentsRenderer>[] = [enhanceArgTypes];\n"
  },
  {
    "path": "code/renderers/web-components/src/entry-preview-docs.ts",
    "content": "import { SourceType } from 'storybook/internal/docs-tools';\nimport type { DecoratorFunction } from 'storybook/internal/types';\n\nimport { sourceDecorator } from './docs/sourceDecorator.ts';\nimport type { WebComponentsRenderer } from './types.ts';\n\nexport const decorators: DecoratorFunction<WebComponentsRenderer>[] = [sourceDecorator];\n\nexport const parameters = {\n  docs: {\n    source: {\n      type: SourceType.DYNAMIC,\n      language: 'html',\n    },\n    story: { inline: true },\n  },\n};\n"
  },
  {
    "path": "code/renderers/web-components/src/entry-preview.ts",
    "content": "export { render, renderToCanvas } from './render.ts';\n\nexport const parameters = {\n  renderer: 'web-components',\n};\n"
  },
  {
    "path": "code/renderers/web-components/src/framework-api.ts",
    "content": "import { global } from '@storybook/global';\n\nexport function isValidComponent(tagName: string) {\n  if (!tagName) {\n    return false;\n  }\n  if (typeof tagName === 'string') {\n    return true;\n  }\n  throw new Error('Provided component needs to be a string. e.g. component: \"my-element\"');\n}\n\nexport function isValidMetaData(customElements: any) {\n  if (!customElements) {\n    return false;\n  }\n\n  if (\n    (customElements.tags && Array.isArray(customElements.tags)) ||\n    (customElements.modules && Array.isArray(customElements.modules))\n  ) {\n    return true;\n  }\n  throw new Error(`You need to setup valid meta data in your config.js via setCustomElements().\n    See the readme of addon-docs for web components for more details.`);\n}\n\n/** @param customElements `any` for now as spec is not super stable yet */\nexport function setCustomElements(customElements: any) {\n  global.__STORYBOOK_CUSTOM_ELEMENTS__ = customElements;\n}\n\nexport function setCustomElementsManifest(customElements: any) {\n  global.__STORYBOOK_CUSTOM_ELEMENTS_MANIFEST__ = customElements;\n}\n\nexport function getCustomElements() {\n  return global.__STORYBOOK_CUSTOM_ELEMENTS__ || global.__STORYBOOK_CUSTOM_ELEMENTS_MANIFEST__;\n}\n"
  },
  {
    "path": "code/renderers/web-components/src/globals.ts",
    "content": "import { global } from '@storybook/global';\n\nconst { window: globalWindow } = global;\n\nglobalWindow.STORYBOOK_ENV = 'web-components';\n"
  },
  {
    "path": "code/renderers/web-components/src/index.ts",
    "content": "import { global } from '@storybook/global';\n\nimport './globals.ts';\n\nconst { window, EventSource } = global;\n\nexport * from './public-types.ts';\nexport * from './framework-api.ts';\nexport * from './portable-stories.ts';\nexport * from './preview.ts';\n\nexport type { WebComponentsTypes } from './types.ts';\n\n// TODO: disable HMR and do full page loads because of customElements.define\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nif (typeof module !== 'undefined' && module?.hot?.decline) {\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  module.hot.decline();\n\n  // forcing full reloads for customElements as elements can only be defined once per page\n  const hmr = new EventSource('__webpack_hmr');\n  hmr.addEventListener('message', function fullPageReload(event: { data: string }) {\n    try {\n      // Only care for built events.  Heartbeats are not parsable so we ignore those\n      const { action } = JSON.parse(event.data);\n      if (action === 'built') {\n        window.location.reload();\n      }\n    } catch (error) {\n      // Most part we only get here from the data in the server-sent event not being parsable which is ok\n    }\n  });\n}\n"
  },
  {
    "path": "code/renderers/web-components/src/portable-stories.ts",
    "content": "import type {\n  NamedOrDefaultProjectAnnotations,\n  NormalizedProjectAnnotations,\n} from 'storybook/internal/types';\n\nimport {\n  setProjectAnnotations as originalSetProjectAnnotations,\n  setDefaultProjectAnnotations,\n} from 'storybook/preview-api';\n\nimport * as webComponentsAnnotations from './entry-preview.ts';\nimport type { WebComponentsRenderer } from './types.ts';\n\n/**\n * Function that sets the globalConfig of your storybook. The global config is the preview module of\n * your .storybook folder.\n *\n * It should be run a single time, so that your global config (e.g. decorators) is applied to your\n * stories when using `composeStories` or `composeStory`.\n *\n * Example:\n *\n * ```jsx\n * // setup-file.js\n * import { setProjectAnnotations } from '@storybook/web-components';\n * import projectAnnotations from './.storybook/preview';\n *\n * setProjectAnnotations(projectAnnotations);\n * ```\n *\n * @param projectAnnotations - E.g. (import projectAnnotations from '../.storybook/preview')\n */\nexport function setProjectAnnotations(\n  projectAnnotations:\n    | NamedOrDefaultProjectAnnotations<any>\n    | NamedOrDefaultProjectAnnotations<any>[]\n): NormalizedProjectAnnotations<WebComponentsRenderer> {\n  setDefaultProjectAnnotations(webComponentsAnnotations);\n  return originalSetProjectAnnotations(\n    projectAnnotations\n  ) as NormalizedProjectAnnotations<WebComponentsRenderer>;\n}\n"
  },
  {
    "path": "code/renderers/web-components/src/preset.ts",
    "content": "import { fileURLToPath } from 'node:url';\n\nimport type { PresetProperty } from 'storybook/internal/types';\n\nexport const previewAnnotations: PresetProperty<'previewAnnotations'> = async (\n  input = [],\n  options\n) => {\n  const docsEnabled = Object.keys(await options.presets.apply('docs', {}, options)).length > 0;\n  const result: string[] = [];\n\n  return result\n    .concat(input)\n    .concat([\n      fileURLToPath(import.meta.resolve('@storybook/web-components/entry-preview')),\n      fileURLToPath(import.meta.resolve('@storybook/web-components/entry-preview-argtypes')),\n    ])\n    .concat(\n      docsEnabled\n        ? [fileURLToPath(import.meta.resolve('@storybook/web-components/entry-preview-docs'))]\n        : []\n    );\n};\n"
  },
  {
    "path": "code/renderers/web-components/src/preview.ts",
    "content": "import type {\n  AddonTypes,\n  InferTypes,\n  Meta,\n  Preview,\n  PreviewAddon,\n  Story,\n} from 'storybook/internal/csf';\nimport { definePreview as definePreviewBase } from 'storybook/internal/csf';\nimport type {\n  ArgsStoryFn,\n  ComponentAnnotations,\n  DecoratorFunction,\n  ProjectAnnotations,\n  Renderer,\n  StoryAnnotations,\n} from 'storybook/internal/types';\n\nimport type { RemoveIndexSignature, SetOptional, Simplify, UnionToIntersection } from 'type-fest';\n\nimport * as webComponentsAnnotations from './entry-preview.ts';\nimport * as webComponentsDocsAnnotations from './entry-preview-docs.ts';\nimport { type WebComponentsTypes } from './types.ts';\n\n/**\n * Creates a Web Components-specific preview configuration with CSF factories support.\n *\n * This function wraps the base `definePreview` and adds Web Components-specific annotations for\n * rendering and documentation. It returns a `WebComponentsPreview` that provides type-safe `meta()`\n * and `story()` factory methods.\n *\n * @example\n *\n * ```ts\n * // .storybook/preview.ts\n * import { definePreview } from '@storybook/web-components';\n *\n * export const preview = definePreview({\n *   addons: [],\n *   parameters: { layout: 'centered' },\n * });\n * ```\n */\nexport function __definePreview<Addons extends PreviewAddon<never>[]>(\n  input: { addons: Addons } & ProjectAnnotations<WebComponentsTypes & InferTypes<Addons>>\n): WebComponentsPreview<WebComponentsTypes & InferTypes<Addons>> {\n  const preview = definePreviewBase({\n    ...input,\n    addons: [webComponentsAnnotations, webComponentsDocsAnnotations, ...(input.addons ?? [])],\n  }) as unknown as WebComponentsPreview<WebComponentsTypes & InferTypes<Addons>>;\n\n  return preview;\n}\n\ntype InferArgs<TArgs, T, Decorators> = Simplify<\n  TArgs & Simplify<RemoveIndexSignature<DecoratorsArgs<WebComponentsTypes & T, Decorators>>>\n>;\n\ntype InferWebComponentsTypes<T, TArgs, Decorators> = WebComponentsTypes &\n  T & { args: Simplify<InferArgs<TArgs, T, Decorators>> };\n\n/**\n * Infers args from a web component's HTMLElement type, allowing both camelCase properties and\n * kebab-case HTML attribute names (e.g., 'aria-label', 'data-testid', 'static-color').\n */\ntype InferArgsFromComponent<C extends keyof HTMLElementTagNameMap> = Partial<\n  HTMLElementTagNameMap[C]\n> &\n  Record<`${string}-${string}`, unknown>;\n\n/**\n * Web Components-specific Preview interface that provides type-safe CSF factory methods.\n *\n * Use `preview.meta()` to create a meta configuration for a component, and then `meta.story()` to\n * create individual stories. The type system will infer args from the HTMLElement type when using a\n * tag name as the component.\n *\n * @example\n *\n * ```ts\n * const meta = preview.meta({ component: 'my-button' });\n * export const Primary = meta.story({ args: { label: 'Click me' } });\n * ```\n */\nexport interface WebComponentsPreview<T extends AddonTypes> extends Preview<\n  WebComponentsTypes & T\n> {\n  /**\n   * Narrows the type of the preview to include additional type information. This is useful when you\n   * need to add args that aren't inferred from the component.\n   *\n   * @example\n   *\n   * ```ts\n   * const meta = preview.type<{ args: { theme: 'light' | 'dark' } }>().meta({\n   *   component: 'my-button',\n   * });\n   * ```\n   */\n  type<S>(): WebComponentsPreview<T & S>;\n\n  meta<\n    C extends keyof HTMLElementTagNameMap,\n    Decorators extends DecoratorFunction<WebComponentsTypes & T, any>,\n    // Try to make Exact<Partial<TArgs>, TMetaArgs> work\n    TMetaArgs extends InferArgsFromComponent<C> & Partial<T['args']>,\n  >(\n    meta: {\n      component?: C;\n      args?: TMetaArgs;\n      decorators?: Decorators | Decorators[];\n    } & Omit<\n      ComponentAnnotations<WebComponentsTypes & T, InferArgsFromComponent<C> & T['args']>,\n      'decorators' | 'component' | 'args'\n    >\n  ): WebComponentsMeta<\n    InferWebComponentsTypes<T, InferArgsFromComponent<C>, Decorators>,\n    Omit<\n      ComponentAnnotations<InferWebComponentsTypes<T, InferArgsFromComponent<C>, Decorators>>,\n      'args'\n    > & {\n      args: {} extends TMetaArgs ? {} : TMetaArgs;\n    }\n  >;\n\n  meta<\n    TArgs,\n    Decorators extends DecoratorFunction<WebComponentsTypes & T, any>,\n    // Try to make Exact<Partial<TArgs>, TMetaArgs> work\n    TMetaArgs extends Partial<TArgs>,\n  >(\n    meta: {\n      render?: ArgsStoryFn<WebComponentsTypes & T, TArgs>;\n      args?: TMetaArgs;\n      decorators?: Decorators | Decorators[];\n    } & Omit<\n      ComponentAnnotations<WebComponentsTypes & T, TArgs & T['args']>,\n      'decorators' | 'component' | 'args' | 'render'\n    >\n  ): WebComponentsMeta<\n    InferWebComponentsTypes<T, TArgs, Decorators>,\n    Omit<ComponentAnnotations<InferWebComponentsTypes<T, TArgs, Decorators>>, 'args'> & {\n      args: {} extends TMetaArgs ? {} : TMetaArgs;\n    }\n  >;\n}\n\n/** Extracts and unions all args types from an array of decorators. */\ntype DecoratorsArgs<TRenderer extends Renderer, Decorators> = UnionToIntersection<\n  Decorators extends DecoratorFunction<TRenderer, infer TArgs> ? TArgs : unknown\n>;\n\n/**\n * Web Components-specific Meta interface returned by `preview.meta()`.\n *\n * Provides the `story()` method to create individual stories with proper type inference. Args\n * provided in meta become optional in stories, while missing required args must be provided at the\n * story level.\n */\nexport interface WebComponentsMeta<\n  T extends WebComponentsTypes,\n  MetaInput extends ComponentAnnotations<T>,\n>\n  // @ts-expect-error WebComponentsMeta requires two type parameters, but Meta's constraints differ\n  extends Meta<T, MetaInput> {\n  /**\n   * Creates a story with a custom render function that takes no args.\n   *\n   * This overload allows you to define a story using just a render function or an object with a\n   * render function that doesn't depend on args. Since the render function doesn't use args, no\n   * args need to be provided regardless of what's required by the component.\n   *\n   * @example\n   *\n   * ```ts\n   * // Using just a render function with lit-html\n   * export const CustomTemplate = meta.story(() => html`<div>Custom content</div>`);\n   *\n   * // Using an object with render\n   * export const WithRender = meta.story({\n   *   render: () => html`<my-element></my-element>`,\n   * });\n   * ```\n   */\n  story<\n    TInput extends\n      | (() => WebComponentsTypes['storyResult'])\n      | (StoryAnnotations<T, T['args']> & {\n          render: () => WebComponentsTypes['storyResult'];\n        }),\n  >(\n    story: TInput\n  ): WebComponentsStory<\n    T,\n    TInput extends () => WebComponentsTypes['storyResult'] ? { render: TInput } : TInput\n  >;\n\n  /**\n   * Creates a story with custom configuration including args, decorators, or other annotations.\n   *\n   * This is the primary overload for defining stories. Args that were already provided in meta\n   * become optional, while any remaining required args must be specified here.\n   *\n   * @example\n   *\n   * ```ts\n   * // Provide required args not in meta\n   * export const Primary = meta.story({\n   *   args: { label: 'Click me', disabled: false },\n   * });\n   *\n   * // Override meta args and add story-specific configuration\n   * export const Disabled = meta.story({\n   *   args: { disabled: true },\n   *   decorators: [withCustomWrapper],\n   * });\n   * ```\n   */\n  story<\n    TInput extends Simplify<\n      StoryAnnotations<\n        T,\n        T['args'],\n        SetOptional<T['args'], keyof T['args'] & keyof MetaInput['args']>\n      >\n    >,\n  >(\n    story: TInput\n  ): WebComponentsStory<T, TInput>;\n\n  /**\n   * Creates a story with no additional configuration.\n   *\n   * This overload is only available when all required args have been provided in meta. The\n   * conditional type `Partial<T['args']> extends SetOptional<...>` checks if the remaining required\n   * args (after accounting for args provided in meta) are all optional. If so, the function accepts\n   * zero arguments `[]`. Otherwise, it requires `[never]` which makes this overload unmatchable,\n   * forcing the user to provide args.\n   *\n   * @example\n   *\n   * ```ts\n   * // When meta provides all required args, story() can be called with no arguments\n   * const meta = preview.meta({ component: 'my-button', args: { label: 'Hi' } });\n   * export const Default = meta.story(); // Valid - all args provided in meta\n   * ```\n   */\n  story(\n    ..._args: Partial<T['args']> extends SetOptional<\n      T['args'],\n      keyof T['args'] & keyof MetaInput['args']\n    >\n      ? []\n      : [never]\n  ): WebComponentsStory<T, {}>;\n}\n\n/**\n * Web Components-specific Story interface returned by `meta.story()`.\n *\n * Represents a single story with its configuration and provides access to the composed story for\n * testing via `story.run()`.\n */\nexport interface WebComponentsStory<\n  T extends WebComponentsTypes,\n  TInput extends StoryAnnotations<T, T['args']>,\n> extends Story<T, TInput> {}\n"
  },
  {
    "path": "code/renderers/web-components/src/public-types.ts",
    "content": "import type {\n  AnnotatedStoryFn,\n  Args,\n  ComponentAnnotations,\n  DecoratorFunction,\n  StoryContext as GenericStoryContext,\n  LoaderFunction,\n  ProjectAnnotations,\n  StoryAnnotations,\n  StrictArgs,\n} from 'storybook/internal/types';\n\nimport type { WebComponentsRenderer } from './types.ts';\n\nexport type { Args, ArgTypes, Parameters, StrictArgs } from 'storybook/internal/types';\nexport type { WebComponentsRenderer };\n\n/**\n * Metadata to configure the stories for a component.\n *\n * @see [Default export](https://storybook.js.org/docs/api/csf#default-export)\n */\nexport type Meta<TArgs = Args> = ComponentAnnotations<WebComponentsRenderer, TArgs>;\n\n/**\n * Story function that represents a CSFv2 component example.\n *\n * @see [Named Story exports](https://storybook.js.org/docs/api/csf#named-story-exports)\n */\nexport type StoryFn<TArgs = Args> = AnnotatedStoryFn<WebComponentsRenderer, TArgs>;\n\n/**\n * Story object that represents a CSFv3 component example.\n *\n * @see [Named Story exports](https://storybook.js.org/docs/api/csf#named-story-exports)\n */\nexport type StoryObj<TArgs = Args> = StoryAnnotations<WebComponentsRenderer, TArgs>;\n\nexport type Decorator<TArgs = StrictArgs> = DecoratorFunction<WebComponentsRenderer, TArgs>;\nexport type Loader<TArgs = StrictArgs> = LoaderFunction<WebComponentsRenderer, TArgs>;\nexport type StoryContext<TArgs = StrictArgs> = GenericStoryContext<WebComponentsRenderer, TArgs>;\nexport type Preview = ProjectAnnotations<WebComponentsRenderer>;\n"
  },
  {
    "path": "code/renderers/web-components/src/render.ts",
    "content": "/* eslint-disable @typescript-eslint/ban-ts-comment */\nimport type { ArgsStoryFn, RenderContext } from 'storybook/internal/types';\n\nimport { global } from '@storybook/global';\n\nimport { render as litRender } from 'lit';\n// Keep `.js` extension to avoid issue with Webpack (related to export map?)\nimport { isTemplateResult } from 'lit/directive-helpers.js';\nimport { simulateDOMContentLoaded, simulatePageLoad } from 'storybook/preview-api';\nimport { dedent } from 'ts-dedent';\n\nimport type { WebComponentsRenderer } from './types.ts';\n\nconst { Node } = global;\n\nexport const render: ArgsStoryFn<WebComponentsRenderer> = (args, context) => {\n  const { id, component } = context;\n  if (!component) {\n    throw new Error(\n      `Unable to render story ${id} as the component annotation is missing from the default export`\n    );\n  }\n\n  const element = document.createElement(component);\n  Object.entries(args).forEach(([key, val]) => {\n    // @ts-ignore\n    element[key] = val;\n  });\n  return element;\n};\n\nexport function renderToCanvas(\n  { storyFn, kind, name, showMain, showError, forceRemount }: RenderContext<WebComponentsRenderer>,\n  canvasElement: WebComponentsRenderer['canvasElement']\n) {\n  const element = storyFn();\n\n  showMain();\n  if (isTemplateResult(element)) {\n    // `render` stores the TemplateInstance in the Node and tries to update based on that.\n    // Since we reuse `canvasElement` for all stories, remove the stored instance first.\n    // But forceRemount means that it's the same story, so we want too keep the state in that case.\n    if (forceRemount || !canvasElement.querySelector('[id=\"root-inner\"]')) {\n      canvasElement.innerHTML = '<div id=\"root-inner\"></div>';\n    }\n    const renderTo = canvasElement.querySelector<HTMLElement>('[id=\"root-inner\"]') as HTMLElement;\n\n    litRender(element, renderTo);\n    simulatePageLoad(canvasElement);\n  } else if (typeof element === 'string') {\n    canvasElement.innerHTML = element;\n    simulatePageLoad(canvasElement);\n  } else if (element instanceof Node) {\n    // Don't re-mount the element if it didn't change and neither did the story\n    if (canvasElement.firstChild === element && !forceRemount) {\n      return;\n    }\n\n    canvasElement.innerHTML = '';\n    canvasElement.appendChild(element);\n    simulateDOMContentLoaded();\n  } else {\n    showError({\n      title: `Expecting an HTML snippet or DOM node from the story: \"${name}\" of \"${kind}\".`,\n      description: dedent`\n        Did you forget to return the HTML snippet from the story?\n        Use \"() => <your snippet or node>\" or when defining the story.\n      `,\n    });\n  }\n}\n"
  },
  {
    "path": "code/renderers/web-components/src/types.ts",
    "content": "import type { StoryContext as StoryContextBase, WebRenderer } from 'storybook/internal/types';\n\nimport type { SVGTemplateResult, TemplateResult } from 'lit';\n\nexport type StoryFnHtmlReturnType =\n  | string\n  | Node\n  | DocumentFragment\n  | TemplateResult\n  | SVGTemplateResult;\n\nexport type StoryContext = StoryContextBase<WebComponentsRenderer>;\n\nexport interface WebComponentsRenderer extends WebRenderer {\n  component: string;\n  storyResult: StoryFnHtmlReturnType;\n}\n\nexport interface ShowErrorArgs {\n  title: string;\n  description: string;\n}\n\nexport interface WebComponentsTypes extends WebComponentsRenderer {}\n"
  },
  {
    "path": "code/renderers/web-components/src/typings.d.ts",
    "content": "declare var STORYBOOK_ENV: 'web-components';\ndeclare var __STORYBOOK_CUSTOM_ELEMENTS_MANIFEST__: any;\ndeclare var __STORYBOOK_CUSTOM_ELEMENTS__: any;\ndeclare var LOGLEVEL: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent' | undefined;\n"
  },
  {
    "path": "code/renderers/web-components/template/cli/.eslintrc.json",
    "content": "{\n  \"rules\": {\n    \"import/extensions\": \"off\"\n  }\n}\n"
  },
  {
    "path": "code/renderers/web-components/template/cli/js/Button.js",
    "content": "import { html } from 'lit';\nimport { styleMap } from 'lit/directives/style-map.js';\n\nimport './button.css';\n\n/** Primary UI component for user interaction */\nexport const Button = ({ primary, backgroundColor = null, size, label, onClick }) => {\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n\n  return html`\n    <button\n      type=\"button\"\n      class=${['storybook-button', `storybook-button--${size || 'medium'}`, mode].join(' ')}\n      style=${styleMap({ backgroundColor })}\n      @click=${onClick}\n    >\n      ${label}\n    </button>\n  `;\n};\n"
  },
  {
    "path": "code/renderers/web-components/template/cli/js/Button.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport { Button } from './Button';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories\nexport default {\n  title: 'Example/Button',\n  tags: ['autodocs'],\n  render: (args) => Button(args),\n  argTypes: {\n    backgroundColor: { control: 'color' },\n    size: {\n      control: { type: 'select' },\n      options: ['small', 'medium', 'large'],\n    },\n  },\n  args: { onClick: fn() },\n};\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/renderers/web-components/template/cli/js/Header.js",
    "content": "import { html } from 'lit';\n\nimport { Button } from './Button';\nimport './header.css';\n\nexport const Header = ({ user, onLogin, onLogout, onCreateAccount }) => html`\n  <header>\n    <div class=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        ${\n          user\n            ? Button({ size: 'small', onClick: onLogout, label: 'Log out' })\n            : html`${Button({\n                size: 'small',\n                onClick: onLogin,\n                label: 'Log in',\n              })}\n            ${Button({\n              primary: true,\n              size: 'small',\n              onClick: onCreateAccount,\n              label: 'Sign up',\n            })}`\n        }\n      </div>\n    </div>\n  </header>\n`;\n"
  },
  {
    "path": "code/renderers/web-components/template/cli/js/Header.stories.js",
    "content": "import { fn } from 'storybook/test';\n\nimport { Header } from './Header';\n\nexport default {\n  title: 'Example/Header',\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/web-components/vue/writing-docs/autodocs\n  tags: ['autodocs'],\n  render: (args) => Header(args),\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n};\nexport const LoggedIn = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut = {};\n"
  },
  {
    "path": "code/renderers/web-components/template/cli/js/Page.js",
    "content": "import { html } from 'lit';\n\nimport { Header } from './Header';\nimport './page.css';\n\nexport const Page = ({ user, onLogin, onLogout, onCreateAccount }) => html`\n  <article>\n    ${Header({\n      user,\n      onLogin,\n      onLogout,\n      onCreateAccount,\n    })}\n\n    <section class=\"storybook-page\">\n      <h2>Pages in Storybook</h2>\n      <p>\n        We recommend building UIs with a\n        <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n          <strong>component-driven</strong> </a\n        >process starting with atomic components and ending with pages.\n      </p>\n      <p>\n        Render pages with mock data. This makes it easy to build and review page states without\n        needing to navigate to them in your app. Here are some handy patterns for managing page data\n        in Storybook:\n      </p>\n      <ul>\n        <li>\n          Use a higher-level connected component. Storybook helps you compose such data from the\n          \"args\" of child component stories\n        </li>\n        <li>\n          Assemble data in the page component from your services. You can mock these services out\n          using Storybook.\n        </li>\n      </ul>\n      <p>\n        Get a guided tutorial on component-driven development at\n        <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n          Storybook tutorials\n        </a>\n        . Read more in the\n        <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\"> docs </a>\n        .\n      </p>\n      <div class=\"tip-wrapper\">\n        <span class=\"tip\">Tip</span> Adjust the width of the canvas with the\n        <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n              id=\"a\"\n              fill=\"#999\"\n            />\n          </g>\n        </svg>\n        Viewports addon in the toolbar\n      </div>\n    </section>\n  </article>\n`;\n"
  },
  {
    "path": "code/renderers/web-components/template/cli/js/Page.stories.js",
    "content": "import * as HeaderStories from './Header.stories';\nimport { Page } from './Page';\n\nexport default {\n  title: 'Example/Page',\n  render: (args) => Page(args),\n};\n\nexport const LoggedIn = {\n  args: {\n    // More on composing args: https://storybook.js.org/docs/writing-stories/args#args-composition\n    ...HeaderStories.LoggedIn.args,\n  },\n};\n\nexport const LoggedOut = {\n  args: {\n    ...HeaderStories.LoggedOut.args,\n  },\n};\n"
  },
  {
    "path": "code/renderers/web-components/template/cli/ts/Button.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/web-components';\n\nimport { fn } from 'storybook/test';\n\nimport type { ButtonProps } from './Button';\nimport { Button } from './Button';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories\nconst meta = {\n  title: 'Example/Button',\n  tags: ['autodocs'],\n  render: (args) => Button(args),\n  argTypes: {\n    backgroundColor: { control: 'color' },\n    size: {\n      control: { type: 'select' },\n      options: ['small', 'medium', 'large'],\n    },\n  },\n  args: { onClick: fn() },\n} satisfies Meta<ButtonProps>;\n\nexport default meta;\ntype Story = StoryObj<ButtonProps>;\n\n// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const Large: Story = {\n  args: {\n    size: 'large',\n    label: 'Button',\n  },\n};\n\nexport const Small: Story = {\n  args: {\n    size: 'small',\n    label: 'Button',\n  },\n};\n"
  },
  {
    "path": "code/renderers/web-components/template/cli/ts/Button.ts",
    "content": "import { html } from 'lit';\nimport { styleMap } from 'lit/directives/style-map.js';\n\nimport './button.css';\n\nexport interface ButtonProps {\n  /** Is this the principal call to action on the page? */\n  primary?: boolean;\n  /** What background color to use */\n  backgroundColor?: string;\n  /** How large should the button be? */\n  size?: 'small' | 'medium' | 'large';\n  /** Button contents */\n  label: string;\n  /** Optional click handler */\n  onClick?: () => void;\n}\n/** Primary UI component for user interaction */\nexport const Button = ({ primary, backgroundColor, size, label, onClick }: ButtonProps) => {\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n\n  return html`\n    <button\n      type=\"button\"\n      class=${['storybook-button', `storybook-button--${size || 'medium'}`, mode].join(' ')}\n      style=${styleMap({ backgroundColor })}\n      @click=${onClick}\n    >\n      ${label}\n    </button>\n  `;\n};\n"
  },
  {
    "path": "code/renderers/web-components/template/cli/ts/Header.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/web-components';\n\nimport { fn } from 'storybook/test';\n\nimport type { HeaderProps } from './Header';\nimport { Header } from './Header';\n\nconst meta = {\n  title: 'Example/Header',\n  // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  render: (args: HeaderProps) => Header(args),\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n} satisfies Meta<HeaderProps>;\n\nexport default meta;\ntype Story = StoryObj<HeaderProps>;\n\nexport const LoggedIn: Story = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut: Story = {};\n"
  },
  {
    "path": "code/renderers/web-components/template/cli/ts/Header.ts",
    "content": "import { html } from 'lit';\n\nimport { Button } from './Button';\nimport './header.css';\n\ntype User = {\n  name: string;\n};\n\nexport interface HeaderProps {\n  user?: User;\n  onLogin?: () => void;\n  onLogout?: () => void;\n  onCreateAccount?: () => void;\n}\n\nexport const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => html`\n  <header>\n    <div class=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        ${\n          user\n            ? Button({ size: 'small', onClick: onLogout, label: 'Log out' })\n            : html`${Button({\n                size: 'small',\n                onClick: onLogin,\n                label: 'Log in',\n              })}\n            ${Button({\n              primary: true,\n              size: 'small',\n              onClick: onCreateAccount,\n              label: 'Sign up',\n            })}`\n        }\n      </div>\n    </div>\n  </header>\n`;\n"
  },
  {
    "path": "code/renderers/web-components/template/cli/ts/Page.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/web-components';\n\nimport * as HeaderStories from './Header.stories';\nimport type { PageProps } from './Page';\nimport { Page } from './Page';\n\nconst meta = {\n  title: 'Example/Page',\n  render: (args: PageProps) => Page(args),\n} satisfies Meta<PageProps>;\n\nexport default meta;\ntype Story = StoryObj<PageProps>;\n\nexport const LoggedIn: Story = {\n  args: {\n    // More on composing args: https://storybook.js.org/docs/writing-stories/args#args-composition\n    ...HeaderStories.LoggedIn.args,\n  },\n};\n\nexport const LoggedOut: Story = {\n  args: {\n    ...HeaderStories.LoggedOut.args,\n  },\n};\n"
  },
  {
    "path": "code/renderers/web-components/template/cli/ts/Page.ts",
    "content": "import { html } from 'lit';\n\nimport { Header } from './Header';\nimport './page.css';\n\ntype User = {\n  name: string;\n};\n\nexport interface PageProps {\n  user?: User;\n  onLogin?: () => void;\n  onLogout?: () => void;\n  onCreateAccount?: () => void;\n}\n\nexport const Page = ({ user, onLogin, onLogout, onCreateAccount }: PageProps) => html`\n  <article>\n    ${Header({\n      user,\n      onLogin,\n      onLogout,\n      onCreateAccount,\n    })}\n\n    <section class=\"storybook-page\">\n      <h2>Pages in Storybook</h2>\n      <p>\n        We recommend building UIs with a\n        <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n          <strong>component-driven</strong> </a\n        >process starting with atomic components and ending with pages.\n      </p>\n      <p>\n        Render pages with mock data. This makes it easy to build and review page states without\n        needing to navigate to them in your app. Here are some handy patterns for managing page data\n        in Storybook:\n      </p>\n      <ul>\n        <li>\n          Use a higher-level connected component. Storybook helps you compose such data from the\n          \"args\" of child component stories\n        </li>\n        <li>\n          Assemble data in the page component from your services. You can mock these services out\n          using Storybook.\n        </li>\n      </ul>\n      <p>\n        Get a guided tutorial on component-driven development at\n        <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\">\n          Storybook tutorials\n        </a>\n        . Read more in the\n        <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\"> docs </a>\n        .\n      </p>\n      <div class=\"tip-wrapper\">\n        <span class=\"tip\">Tip</span> Adjust the width of the canvas with the\n        <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n              id=\"a\"\n              fill=\"#999\"\n            />\n          </g>\n        </svg>\n        Viewports addon in the toolbar\n      </div>\n    </section>\n  </article>\n`;\n"
  },
  {
    "path": "code/renderers/web-components/template/components/Button.js",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { LitElement, html } from 'lit';\n\nconst { CustomEvent, customElements } = globalThis;\n\n/**\n * @property {boolean} primary - Set button in primary mode\n * @attr {string} label - Label of the button\n * @attr {string} size - Size of the button, can be \"small\", \"medium\" or \"large\"; default is \"medium\".\n * @attr {string} backgroundColor - Color of the button's background\n *\n * @cssprop [--sb-primary-color=#1ea7fd] - Controls the color of bar. Default is `#1ea7fd`\n * @event {CustomEvent} sb-button:click - Custom event send when the button is clicked\n *\n * @summary This is a simple Storybook Button\n *\n * @tag sb-button\n */\nexport class SbButton extends LitElement {\n  // Currently TS decorators are not reflected so we have to use static `properties` function\n  // https://github.com/Polymer/lit-html/issues/1476\n  static get properties() {\n    return {\n      label: { type: String, reflect: true },\n      primary: { type: Boolean },\n      size: { type: String },\n      backgroundColor: { type: String, attribute: 'background-color' },\n    };\n  }\n\n  constructor() {\n    super();\n    this.primary = undefined;\n    this.backgroundColor = undefined;\n    this.size = 'medium';\n    this.label = '';\n  }\n\n  onClick() {\n    const options = {\n      bubbles: true,\n      composed: true,\n    };\n    this.dispatchEvent(new CustomEvent('sb-button:click', options));\n  }\n\n  render() {\n    const mode = this.primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n\n    return html`\n      <button\n        type=\"button\"\n        class=${['storybook-button', `storybook-button--${this.size ?? 'medium'}`, mode].join(' ')}\n        @click=${this.onClick}\n      >\n        ${this.label}\n      </button>\n    `;\n  }\n\n  // render into the light dom so we can test this\n  createRenderRoot() {\n    return this;\n  }\n}\n\nexport const ButtonTag = 'sb-button';\ncustomElements.define(ButtonTag, SbButton);\n"
  },
  {
    "path": "code/renderers/web-components/template/components/Form.js",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { LitElement, html } from 'lit';\n\nconst { CustomEvent, customElements } = globalThis;\n\n/**\n * Form test component for framework-independent stories\n *\n * @tag sb-form\n */\nexport class SbForm extends LitElement {\n  // Currently TS decorators are not reflected so we have to use static `properties` function\n  // https://github.com/Polymer/lit-html/issues/1476\n  static get properties() {\n    return {\n      value: { type: String },\n      complete: { type: Boolean },\n      onSuccess: { type: Function },\n    };\n  }\n\n  constructor() {\n    super();\n    this.value = '';\n    this.complete = false;\n    this.onSuccess = undefined;\n  }\n\n  onSubmit(event) {\n    event.preventDefault();\n    const options = {\n      bubbles: true,\n      composed: true,\n    };\n\n    this.dispatchEvent(new CustomEvent('sb-form:success', options));\n    if (this.onSuccess) {\n      this.onSuccess(this.value);\n    }\n\n    setTimeout(() => {\n      this.complete = true;\n    }, 500);\n\n    setTimeout(() => {\n      this.complete = false;\n    }, 1500);\n  }\n\n  render() {\n    return html`\n      <form id=\"interaction-test-form\" @submit=${this.onSubmit}>\n        <label>\n          Enter Value\n          <input\n            type=\"text\"\n            data-testid=\"value\"\n            value=${this.value}\n            required\n            @change=${(event) => {\n              event.preventDefault();\n              this.value = event.target.value;\n              return false;\n            }}\n          />\n        </label>\n        <button type=\"submit\">Submit</button>\n        ${this.complete ? 'Completed!!' : ''}\n      </form>\n    `;\n  }\n\n  // render into the light dom so we can test this\n  createRenderRoot() {\n    return this;\n  }\n}\n\nexport const FormTag = 'sb-form';\ncustomElements.define(FormTag, SbForm);\n"
  },
  {
    "path": "code/renderers/web-components/template/components/Html.js",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { LitElement } from 'lit';\n\nconst { customElements } = globalThis;\n/** @tag sb-html */\nexport class SbHtml extends LitElement {\n  static get properties() {\n    return {\n      content: { type: String },\n    };\n  }\n\n  constructor() {\n    super();\n    this.content = '';\n  }\n\n  render() {\n    this.renderRoot.innerHTML = this.content;\n  }\n\n  // render into the light dom so we can test this\n  createRenderRoot() {\n    return this;\n  }\n}\nexport const HtmlTag = 'sb-html';\ncustomElements.define(HtmlTag, SbHtml);\n"
  },
  {
    "path": "code/renderers/web-components/template/components/Pre.js",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { LitElement, html } from 'lit';\nimport { styleMap } from 'lit/directives/style-map.js';\n\nconst { customElements } = globalThis;\n\n/** @tag sb-pre */\nexport class SbPre extends LitElement {\n  // Currently TS decorators are not reflected so we have to use static `properties` function\n  // https://github.com/Polymer/lit-html/issues/1476\n  static get properties() {\n    return {\n      style: { type: Object },\n      object: { type: Object },\n      text: { type: String },\n    };\n  }\n\n  constructor() {\n    super();\n    this.style = {};\n    this.object = undefined;\n    this.text = undefined;\n  }\n\n  render() {\n    const text = this.object ? JSON.stringify(this.object, null, 2) : this.text;\n    return html`<pre data-testid=\"pre\" style=${styleMap(this.style)}>${text}</pre>`;\n  }\n\n  // render into the light dom so we can test this\n  createRenderRoot() {\n    return this;\n  }\n}\n\nexport const PreTag = 'sb-pre';\ncustomElements.define(PreTag, SbPre);\n"
  },
  {
    "path": "code/renderers/web-components/template/components/button.css",
    "content": ".storybook-button {\n  display: inline-block;\n  cursor: pointer;\n  border: 0;\n  border-radius: 3em;\n  font-weight: 700;\n  line-height: 1;\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n.storybook-button--primary {\n  background-color: #555ab9;\n  color: white;\n}\n.storybook-button--secondary {\n  box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;\n  background-color: transparent;\n  color: #333;\n}\n.storybook-button--small {\n  padding: 10px 16px;\n  font-size: 12px;\n}\n.storybook-button--medium {\n  padding: 11px 20px;\n  font-size: 14px;\n}\n.storybook-button--large {\n  padding: 12px 24px;\n  font-size: 16px;\n}\n"
  },
  {
    "path": "code/renderers/web-components/template/components/index.js",
    "content": "import { global as globalThis } from '@storybook/global';\n\nimport { ButtonTag } from './Button';\nimport { FormTag } from './Form';\nimport { HtmlTag } from './Html';\nimport { PreTag } from './Pre';\n\nglobalThis.__TEMPLATE_COMPONENTS__ = {\n  Button: ButtonTag,\n  Form: FormTag,\n  Html: HtmlTag,\n  Pre: PreTag,\n};\nglobalThis.storybookRenderer = 'web-components';\n"
  },
  {
    "path": "code/renderers/web-components/template/stories/custom-elements-experimental.json",
    "content": "{\n  \"version\": \"experimental\",\n  \"tags\": [\n    {\n      \"name\": \"demo-wc-card\",\n      \"path\": \"./demo-wc-card.js\",\n      \"description\": \"This is a container looking like a card with a back and front side you can switch\",\n      \"attributes\": [\n        {\n          \"name\": \"back-side\",\n          \"description\": \"Indicates that the back of the card is shown\",\n          \"type\": \"boolean\",\n          \"default\": \"false\"\n        },\n        {\n          \"name\": \"header\",\n          \"description\": \"Header message\",\n          \"type\": \"string\",\n          \"default\": \"\\\"Your Message\\\"\"\n        },\n        {\n          \"name\": \"rows\",\n          \"description\": \"Data rows\",\n          \"type\": \"object\",\n          \"default\": \"[]\"\n        }\n      ],\n      \"properties\": [\n        {\n          \"name\": \"backSide\",\n          \"attribute\": \"back-side\",\n          \"description\": \"Indicates that the back of the card is shown\",\n          \"type\": \"boolean\",\n          \"default\": \"false\"\n        },\n        {\n          \"name\": \"header\",\n          \"attribute\": \"header\",\n          \"description\": \"Header message\",\n          \"type\": \"string\",\n          \"default\": \"\\\"Your Message\\\"\"\n        },\n        {\n          \"name\": \"rows\",\n          \"attribute\": \"rows\",\n          \"description\": \"Data rows\",\n          \"type\": \"object\",\n          \"default\": \"[]\"\n        }\n      ],\n      \"events\": [\n        {\n          \"name\": \"side-changed\",\n          \"description\": \"Fires whenever it switches between front/back\"\n        }\n      ],\n      \"methods\": [\n        {\n          \"name\": \"testMethod\",\n          \"description\": \"Some web component frameworks like Stencil generate extra docs for methods. These are also displayed in the ArgsTable.\"\n        }\n      ],\n      \"slots\": [\n        {\n          \"name\": \"\",\n          \"description\": \"This is an unnamed slot (the default slot)\"\n        }\n      ],\n      \"cssProperties\": [\n        {\n          \"name\": \"--demo-wc-card-header-font-size\",\n          \"description\": \"Header font size\"\n        },\n        {\n          \"name\": \"--demo-wc-card-front-color\",\n          \"description\": \"Font color for front\"\n        },\n        {\n          \"name\": \"--demo-wc-card-back-color\",\n          \"description\": \"Font color for back\"\n        }\n      ],\n      \"cssParts\": [\n        {\n          \"name\": \"front\",\n          \"description\": \"Front of the card\"\n        },\n        {\n          \"name\": \"back\",\n          \"description\": \"Back of the card\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "code/renderers/web-components/template/stories/custom-elements.json",
    "content": "{\n  \"schemaVersion\": \"1.0.0\",\n  \"readme\": \"\",\n  \"modules\": [\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"demo-wc-card/index.js\",\n      \"declarations\": [],\n      \"exports\": [\n        {\n          \"kind\": \"custom-element-definition\",\n          \"name\": \"demo-wc-card\",\n          \"declaration\": {\n            \"name\": \"DemoWcCard\",\n            \"module\": \"demo-wc-card/DemoWcCard.js\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"demo-wc-card/DemoWcCard.js\",\n      \"declarations\": [\n        {\n          \"kind\": \"class\",\n          \"description\": \"This is a container looking like a card with a back and front side you can switch\",\n          \"name\": \"DemoWcCard\",\n          \"cssProperties\": [\n            {\n              \"description\": \"Header font size\",\n              \"name\": \"--demo-wc-card-header-font-size\"\n            },\n            {\n              \"description\": \"Font color for front\",\n              \"name\": \"--demo-wc-card-front-color\"\n            },\n            {\n              \"description\": \"Font color for back\",\n              \"name\": \"--demo-wc-card-back-color\"\n            }\n          ],\n          \"cssParts\": [\n            {\n              \"description\": \"Front of the card\",\n              \"name\": \"front\"\n            },\n            {\n              \"description\": \"Back of the card\",\n              \"name\": \"back\"\n            }\n          ],\n          \"slots\": [\n            {\n              \"name\": \"prefix\",\n              \"description\": \"Label prefix\"\n            }\n          ],\n          \"members\": [\n            {\n              \"kind\": \"method\",\n              \"name\": \"toggle\"\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"backSide\",\n              \"type\": {\n                \"text\": \"boolean\"\n              },\n              \"description\": \"Indicates that the back of the card is shown\",\n              \"default\": \"false\",\n              \"privacy\": \"public\",\n              \"attribute\": \"back-side\",\n              \"reflects\": true\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"header\",\n              \"type\": {\n                \"text\": \"string\"\n              },\n              \"description\": \"Header message\",\n              \"default\": \"'Your Message'\",\n              \"privacy\": \"public\",\n              \"attribute\": \"header\"\n            },\n            {\n              \"kind\": \"field\",\n              \"name\": \"rows\",\n              \"type\": {\n                \"text\": \"array\"\n              },\n              \"description\": \"Data rows\",\n              \"default\": \"[]\",\n              \"privacy\": \"public\",\n              \"attribute\": \"rows\"\n            }\n          ],\n          \"events\": [\n            {\n              \"name\": \"side-changed\",\n              \"type\": {\n                \"text\": \"CustomEvent\"\n              },\n              \"description\": \"Fires whenever it switches between front/back\"\n            }\n          ],\n          \"attributes\": [\n            {\n              \"name\": \"back-side\",\n              \"fieldName\": \"backSide\"\n            },\n            {\n              \"name\": \"header\",\n              \"fieldName\": \"header\"\n            },\n            {\n              \"name\": \"rows\",\n              \"fieldName\": \"rows\"\n            }\n          ],\n          \"superclass\": {\n            \"name\": \"LitElement\",\n            \"package\": \"lit\"\n          },\n          \"tagName\": \"demo-wc-card\",\n          \"customElement\": true\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"DemoWcCard\",\n          \"declaration\": {\n            \"name\": \"DemoWcCard\",\n            \"module\": \"demo-wc-card/DemoWcCard.js\"\n          }\n        }\n      ]\n    },\n    {\n      \"kind\": \"javascript-module\",\n      \"path\": \"demo-wc-card/demoWcCardStyle.css.js\",\n      \"declarations\": [\n        {\n          \"kind\": \"variable\",\n          \"name\": \"demoWcCardStyle\",\n          \"default\": \"css`\\n  :host {\\n    display: block;\\n    position: relative;\\n    width: 250px;\\n    height: 200px;\\n    border-radius: 10px;\\n    transform-style: preserve-3d;\\n    transition: all 0.8s ease;\\n  }\\n\\n  .header {\\n    font-weight: bold;\\n    font-size: var(--demo-wc-card-header-font-size, 16px);\\n    text-align: center;\\n  }\\n\\n  .content {\\n    padding: 20px 10px 0 10px;\\n    flex-grow: 1;\\n  }\\n\\n  .footer {\\n    display: flex;\\n  }\\n\\n  dl {\\n    margin: 0;\\n    text-align: left;\\n  }\\n\\n  dd {\\n    margin-left: 15px;\\n  }\\n\\n  button {\\n    border-radius: 15px;\\n    width: 30px;\\n    height: 30px;\\n    background: #fff;\\n    border: 1px solid #ccc;\\n    color: #000;\\n    font-size: 21px;\\n    line-height: 27px;\\n    font-weight: bold;\\n    cursor: pointer;\\n    margin: 5px;\\n  }\\n\\n  .note {\\n    flex-grow: 1;\\n    color: #666;\\n    font-size: 16px;\\n    font-weight: bold;\\n    text-align: left;\\n    padding-top: 15px;\\n  }\\n\\n  :host([back-side]) {\\n    transform: rotateY(180deg);\\n  }\\n\\n  #front,\\n  #back {\\n    position: absolute;\\n    width: 250px;\\n    box-sizing: border-box;\\n    box-shadow: #ccc 3px 3px 2px 1px;\\n    padding: 10px;\\n    display: flex;\\n    flex-flow: column;\\n    top: 0;\\n    left: 0;\\n    height: 100%;\\n    border-radius: 10px;\\n    backface-visibility: hidden;\\n    overflow: hidden;\\n  }\\n\\n  #front {\\n    background: linear-gradient(141deg, #aaa 25%, #eee 40%, #ddd 55%);\\n    color: var(--demo-wc-card-front-color, #000);\\n  }\\n\\n  #back {\\n    background: linear-gradient(141deg, #333 25%, #aaa 40%, #666 55%);\\n    color: var(--demo-wc-card-back-color, #fff);\\n    text-align: center;\\n    transform: rotateY(180deg) translate3d(0px, 0, 1px);\\n  }\\n\\n  #back .note {\\n    color: #fff;\\n  }\\n`\"\n        }\n      ],\n      \"exports\": [\n        {\n          \"kind\": \"js\",\n          \"name\": \"demoWcCardStyle\",\n          \"declaration\": {\n            \"name\": \"demoWcCardStyle\",\n            \"module\": \"demo-wc-card/demoWcCardStyle.css.js\"\n          }\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "code/renderers/web-components/template/stories/demo-wc-card/DemoWcCard.js",
    "content": "import { global } from '@storybook/global';\n\nimport { LitElement, html } from 'lit';\n\nimport { demoWcCardStyle } from './demoWcCardStyle.css.js';\n\nconst { CustomEvent } = global;\n\n/**\n * This is a container looking like a card with a back and front side you can switch\n *\n * @fires side-changed - Fires whenever it switches between front/back\n * @slot - This is an unnamed slot (the default slot)\n * @cssprop --demo-wc-card-header-font-size - Header font size\n * @cssprop --demo-wc-card-front-color - Font color for front\n * @cssprop --demo-wc-card-back-color - Font color for back\n * @csspart front - Front of the card\n * @csspart back - Back of the card\n */\nexport class DemoWcCard extends LitElement {\n  static get properties() {\n    return {\n      backSide: {\n        type: Boolean,\n        reflect: true,\n        attribute: 'back-side',\n      },\n      header: { type: String },\n      rows: { type: Object },\n    };\n  }\n\n  static get styles() {\n    return demoWcCardStyle;\n  }\n\n  constructor() {\n    super();\n\n    /** Indicates that the back of the card is shown */\n    this.backSide = false;\n\n    /** Header message */\n    this.header = 'Your Message';\n\n    /** Data rows */\n    this.rows = [];\n  }\n\n  toggle() {\n    this.backSide = !this.backSide;\n  }\n\n  render() {\n    return html`\n      <div id=\"front\" part=\"front\">\n        <div class=\"header\">${this.header}</div>\n        <div class=\"content\">\n          <slot></slot>\n        </div>\n        <div class=\"footer\">\n          <div class=\"note\">A</div>\n          <button @click=${this.toggle}>></button>\n        </div>\n      </div>\n      <div id=\"back\" part=\"back\">\n        <div class=\"header\"><slot name=\"prefix\"></slot> ${this.header}</div>\n\n        <div class=\"content\">\n          ${\n            this.rows.length === 0\n              ? html``\n              : html`\n                <dl>\n                  ${this.rows.map(\n                    (row) => html`\n                      <dt>${row.header}</dt>\n                      <dd>${row.value}</dd>\n                    `\n                  )}\n                </dl>\n              `\n          }\n        </div>\n        <div class=\"footer\">\n          <div class=\"note\">B</div>\n          <button @click=${this.toggle}>></button>\n        </div>\n      </div>\n    `;\n  }\n\n  updated(changedProperties) {\n    if (changedProperties.has('backSide') && changedProperties.get('backSide') !== undefined) {\n      this.dispatchEvent(new CustomEvent('side-changed'));\n    }\n  }\n}\n"
  },
  {
    "path": "code/renderers/web-components/template/stories/demo-wc-card/demoWcCardStyle.css.js",
    "content": "import { css } from 'lit';\n\nexport const demoWcCardStyle = css`\n  :host {\n    display: block;\n    position: relative;\n    width: 250px;\n    height: 200px;\n    border-radius: 10px;\n    transform-style: preserve-3d;\n    transition: all 0.8s ease;\n  }\n\n  .header {\n    font-weight: bold;\n    font-size: var(--demo-wc-card-header-font-size, 16px);\n    text-align: center;\n  }\n\n  .content {\n    padding: 20px 10px 0 10px;\n    flex-grow: 1;\n  }\n\n  .footer {\n    display: flex;\n  }\n\n  dl {\n    margin: 0;\n    text-align: left;\n  }\n\n  dd {\n    margin-left: 15px;\n  }\n\n  button {\n    border-radius: 15px;\n    width: 30px;\n    height: 30px;\n    background: #fff;\n    border: 1px solid #ccc;\n    color: #000;\n    font-size: 21px;\n    line-height: 27px;\n    font-weight: bold;\n    cursor: pointer;\n    margin: 5px;\n  }\n\n  .note {\n    flex-grow: 1;\n    color: #666;\n    font-size: 16px;\n    font-weight: bold;\n    text-align: left;\n    padding-top: 15px;\n  }\n\n  :host([back-side]) {\n    transform: rotateY(180deg);\n  }\n\n  #front,\n  #back {\n    position: absolute;\n    width: 250px;\n    box-sizing: border-box;\n    box-shadow: #ccc 3px 3px 2px 1px;\n    padding: 10px;\n    display: flex;\n    flex-flow: column;\n    top: 0;\n    left: 0;\n    height: 100%;\n    border-radius: 10px;\n    backface-visibility: hidden;\n    overflow: hidden;\n  }\n\n  #front {\n    background: linear-gradient(141deg, #aaa 25%, #eee 40%, #ddd 55%);\n    color: var(--demo-wc-card-front-color, #000);\n  }\n\n  #back {\n    background: linear-gradient(141deg, #333 25%, #aaa 40%, #666 55%);\n    color: var(--demo-wc-card-back-color, #fff);\n    text-align: center;\n    transform: rotateY(180deg) translate3d(0px, 0, 1px);\n  }\n\n  #back .note {\n    color: #fff;\n  }\n`;\n"
  },
  {
    "path": "code/renderers/web-components/template/stories/demo-wc-card/index.js",
    "content": "import { DemoWcCard } from './DemoWcCard.js';\n\ncustomElements.define('demo-wc-card', DemoWcCard);\n"
  },
  {
    "path": "code/renderers/web-components/template/stories/demo-wc-card.stories.js",
    "content": "import { html } from 'lit';\n\nimport './demo-wc-card';\n\nexport default {\n  component: 'demo-wc-card',\n  render: ({ backSide, header, rows, prefix }) => html`\n    <demo-wc-card .backSide=${backSide} .header=${header} .rows=${rows}\n      ><span slot=\"prefix\">${prefix}</span>A simple card</demo-wc-card\n    >\n  `,\n};\n\nexport const Front = {\n  args: { backSide: false, header: undefined, rows: [] },\n};\n\nexport const Back = {\n  args: { backSide: true, header: undefined, rows: [] },\n};\n\nexport const Prefix = {\n  args: { backSide: false, prefix: 'prefix:', header: 'my header', rows: [] },\n};\n"
  },
  {
    "path": "code/renderers/web-components/template/stories/preview.js",
    "content": "import { setCustomElementsManifest } from '@storybook/web-components';\n\nimport customElementsManifest from './custom-elements.json';\n\nsetCustomElementsManifest(customElementsManifest);\n"
  },
  {
    "path": "code/renderers/web-components/template/stories/script.stories.js",
    "content": "import { html } from 'lit';\n\nexport default {\n  component: undefined,\n};\n\nexport const InTemplate = () => html`\n  <div>JS alert</div>\n  <script>\n    alert('hello');\n  </script>\n`;\n\nexport const InString = () => '<div>JS alert</div><script>alert(\"hello\")</script>';\n\nexport const TypeModule = () =>\n  '<div>JS alert from module</div><script type=\"module\">alert(\"hello from module\"); export const a = 1;</script>';\n"
  },
  {
    "path": "code/renderers/web-components/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"resolveJsonModule\": true,\n    \"paths\": {\n      \"storybook/internal/*\": [\"../../lib/cli/core/*\"]\n    }\n  },\n  \"include\": [\"src/**/*\", \"template/**/*\"]\n}\n"
  },
  {
    "path": "code/renderers/web-components/vitest.config.ts",
    "content": "import { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { vitestCommonConfig } from '../../vitest.shared.ts';\n\nexport default mergeConfig(\n  vitestCommonConfig,\n  defineConfig({\n    // Add custom config here\n  })\n);\n"
  },
  {
    "path": "code/sandbox/angular-cli-default-ts/project.json",
    "content": "{\n  \"name\": \"angular-cli/default-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"angular\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"angular-cli-default-ts\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"angular-cli-default-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:normal\", \"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/angular-cli-prerelease/project.json",
    "content": "{\n  \"name\": \"angular-cli/prerelease\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"angular\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"angular-cli-prerelease\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"angular-cli-prerelease\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/bench-react-vite-default-ts/project.json",
    "content": "{\n  \"name\": \"bench/react-vite-default-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"react-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"bench-react-vite-default-ts\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"bench-react-vite-default-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {}\n  },\n  \"tags\": [\"ci:normal\", \"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/bench-react-vite-default-ts-nodocs/project.json",
    "content": "{\n  \"name\": \"bench/react-vite-default-ts-nodocs\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"react-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"bench-react-vite-default-ts-nodocs\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"bench-react-vite-default-ts-nodocs\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {}\n  },\n  \"tags\": [\"ci:normal\", \"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/bench-react-vite-default-ts-test-build/project.json",
    "content": "{\n  \"name\": \"bench/react-vite-default-ts-test-build\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"react-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"bench-react-vite-default-ts-test-build\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"bench-react-vite-default-ts-test-build\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {}\n  },\n  \"tags\": [\"ci:normal\", \"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/bench-react-webpack-18-ts/project.json",
    "content": "{\n  \"name\": \"bench/react-webpack-18-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"react-webpack5\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"bench-react-webpack-18-ts\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"bench-react-webpack-18-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {}\n  },\n  \"tags\": [\"ci:normal\", \"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/bench-react-webpack-18-ts-test-build/project.json",
    "content": "{\n  \"name\": \"bench/react-webpack-18-ts-test-build\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"react-webpack5\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"bench-react-webpack-18-ts-test-build\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"bench-react-webpack-18-ts-test-build\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {}\n  },\n  \"tags\": [\"ci:normal\", \"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/cra-default-js/project.json",
    "content": "{\n  \"name\": \"cra/default-js\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"react-webpack5\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"cra-default-js\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"cra-default-js\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": []\n}\n"
  },
  {
    "path": "code/sandbox/cra-default-ts/project.json",
    "content": "{\n  \"name\": \"cra/default-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"react-webpack5\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"cra-default-ts\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"cra-default-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": []\n}\n"
  },
  {
    "path": "code/sandbox/ember-3-js/project.json",
    "content": "{\n  \"name\": \"ember/3-js\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"ember\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"ember-3-js\"\n      }\n    },\n    \"dev\": {},\n    \"vitest-integration\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"ember-3-js\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": []\n}\n"
  },
  {
    "path": "code/sandbox/ember-default-js/project.json",
    "content": "{\n  \"name\": \"ember/default-js\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"ember\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"ember-default-js\"\n      }\n    },\n    \"dev\": {},\n    \"vitest-integration\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"ember-default-js\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": []\n}\n"
  },
  {
    "path": "code/sandbox/html-rsbuild-default-ts/project.json",
    "content": "{\n  \"name\": \"html-rsbuild/default-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"html-rsbuild-default-ts\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"html-rsbuild-default-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/html-vite-default-js/project.json",
    "content": "{\n  \"name\": \"html-vite/default-js\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"html-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"html-vite-default-js\"\n      }\n    },\n    \"dev\": {},\n    \"vitest-integration\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"html-vite-default-js\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/html-vite-default-ts/project.json",
    "content": "{\n  \"name\": \"html-vite/default-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"html-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"html-vite-default-ts\"\n      }\n    },\n    \"dev\": {},\n    \"vitest-integration\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"html-vite-default-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/internal-react16-webpack/project.json",
    "content": "{\n  \"name\": \"internal/react16-webpack\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"react-webpack5\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"internal-react16-webpack\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"internal-react16-webpack\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/internal-react18-webpack-babel/project.json",
    "content": "{\n  \"name\": \"internal/react18-webpack-babel\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"react-webpack5\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"internal-react18-webpack-babel\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"internal-react18-webpack-babel\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/internal-server-webpack5/project.json",
    "content": "{\n  \"name\": \"internal/server-webpack5\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"server-webpack5\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"internal-server-webpack5\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"internal-server-webpack5\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": []\n}\n"
  },
  {
    "path": "code/sandbox/lit-rsbuild-default-ts/project.json",
    "content": "{\n  \"name\": \"lit-rsbuild/default-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"lit-rsbuild-default-ts\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"lit-rsbuild-default-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/lit-vite-default-js/project.json",
    "content": "{\n  \"name\": \"lit-vite/default-js\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"web-components-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"lit-vite-default-js\"\n      }\n    },\n    \"dev\": {},\n    \"vitest-integration\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"lit-vite-default-js\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/lit-vite-default-ts/project.json",
    "content": "{\n  \"name\": \"lit-vite/default-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"web-components-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"lit-vite-default-ts\"\n      }\n    },\n    \"dev\": {},\n    \"vitest-integration\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"lit-vite-default-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:normal\", \"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/nextjs-14-ts/project.json",
    "content": "{\n  \"name\": \"nextjs/14-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"nextjs\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"nextjs-14-ts\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"nextjs-14-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/nextjs-15-ts/project.json",
    "content": "{\n  \"name\": \"nextjs/15-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"nextjs\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"nextjs-15-ts\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"nextjs-15-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/nextjs-default-ts/project.json",
    "content": "{\n  \"name\": \"nextjs/default-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"nextjs\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"nextjs-default-ts\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"nextjs-default-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:normal\", \"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/nextjs-prerelease/project.json",
    "content": "{\n  \"name\": \"nextjs/prerelease\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"nextjs\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"nextjs-prerelease\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"nextjs-prerelease\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/nextjs-vite-14-ts/project.json",
    "content": "{\n  \"name\": \"nextjs-vite/14-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"nextjs-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"nextjs-vite-14-ts\"\n      }\n    },\n    \"dev\": {},\n    \"vitest-integration\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"nextjs-vite-14-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/nextjs-vite-15-ts/project.json",
    "content": "{\n  \"name\": \"nextjs-vite/15-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"nextjs-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"nextjs-vite-15-ts\"\n      }\n    },\n    \"dev\": {},\n    \"vitest-integration\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"nextjs-vite-15-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/nextjs-vite-default-ts/project.json",
    "content": "{\n  \"name\": \"nextjs-vite/default-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"nextjs-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"nextjs-vite-default-ts\"\n      }\n    },\n    \"dev\": {},\n    \"vitest-integration\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"nextjs-vite-default-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:normal\", \"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/preact-vite-default-js/project.json",
    "content": "{\n  \"name\": \"preact-vite/default-js\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"preact-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"preact-vite-default-js\"\n      }\n    },\n    \"dev\": {},\n    \"vitest-integration\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"preact-vite-default-js\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/preact-vite-default-ts/project.json",
    "content": "{\n  \"name\": \"preact-vite/default-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"preact-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"preact-vite-default-ts\"\n      }\n    },\n    \"dev\": {},\n    \"vitest-integration\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"preact-vite-default-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/qwik-vite-default-ts/project.json",
    "content": "{\n  \"name\": \"qwik-vite/default-ts\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\"\n  ],\n  \"targets\": {\n    \"sandbox\": { \"options\": { \"dir\": \"qwik-vite-default-ts\" } },\n    \"dev\": {},\n    \"build\": { \"options\": { \"dir\": \"qwik-vite-default-ts\" } },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": []\n}\n"
  },
  {
    "path": "code/sandbox/react-native-web-vite-expo-ts/project.json",
    "content": "{\n  \"name\": \"react-native-web-vite/expo-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"react-native-web-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"react-native-web-vite-expo-ts\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"react-native-web-vite-expo-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/react-native-web-vite-rn-cli-ts/project.json",
    "content": "{\n  \"name\": \"react-native-web-vite/rn-cli-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"react-native-web-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"react-native-web-vite-rn-cli-ts\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"react-native-web-vite-rn-cli-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": []\n}\n"
  },
  {
    "path": "code/sandbox/react-rsbuild-default-ts/project.json",
    "content": "{\n  \"name\": \"react-rsbuild/default-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"react-rsbuild-default-ts\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"react-rsbuild-default-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:normal\", \"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/react-vite-default-js/project.json",
    "content": "{\n  \"name\": \"react-vite/default-js\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"react-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"react-vite-default-js\"\n      }\n    },\n    \"dev\": {},\n    \"vitest-integration\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"react-vite-default-js\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/react-vite-default-ts/project.json",
    "content": "{\n  \"name\": \"react-vite/default-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"react-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"react-vite-default-ts\"\n      }\n    },\n    \"dev\": {},\n    \"check-sandbox\": {},\n    \"vitest-integration\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"react-vite-default-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:normal\", \"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/react-vite-prerelease-ts/project.json",
    "content": "{\n  \"name\": \"react-vite/prerelease-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"react-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"react-vite-prerelease-ts\"\n      }\n    },\n    \"dev\": {},\n    \"vitest-integration\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"react-vite-prerelease-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/react-webpack-17-ts/project.json",
    "content": "{\n  \"name\": \"react-webpack/17-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"react-webpack5\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"react-webpack-17-ts\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"react-webpack-17-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/react-webpack-18-ts/project.json",
    "content": "{\n  \"name\": \"react-webpack/18-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"react-webpack5\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"react-webpack-18-ts\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"react-webpack-18-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/react-webpack-prerelease-ts/project.json",
    "content": "{\n  \"name\": \"react-webpack/prerelease-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"react-webpack5\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"react-webpack-prerelease-ts\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"react-webpack-prerelease-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/solid-vite-default-js/project.json",
    "content": "{\n  \"name\": \"solid-vite/default-js\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\"\n  ],\n  \"targets\": {\n    \"sandbox\": { \"options\": { \"dir\": \"solid-vite-default-js\" } },\n    \"dev\": {},\n    \"build\": { \"options\": { \"dir\": \"solid-vite-default-js\" } },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": []\n}\n"
  },
  {
    "path": "code/sandbox/solid-vite-default-ts/project.json",
    "content": "{\n  \"name\": \"solid-vite/default-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"solid-vite-default-ts\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"solid-vite-default-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/svelte-kit-skeleton-ts/project.json",
    "content": "{\n  \"name\": \"svelte-kit/skeleton-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"sveltekit\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"svelte-kit-skeleton-ts\"\n      }\n    },\n    \"dev\": {},\n    \"vitest-integration\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"svelte-kit-skeleton-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:normal\", \"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/svelte-vite-default-js/project.json",
    "content": "{\n  \"name\": \"svelte-vite/default-js\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"svelte-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"svelte-vite-default-js\"\n      }\n    },\n    \"dev\": {},\n    \"vitest-integration\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"svelte-vite-default-js\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/svelte-vite-default-ts/project.json",
    "content": "{\n  \"name\": \"svelte-vite/default-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"svelte-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"svelte-vite-default-ts\"\n      }\n    },\n    \"dev\": {},\n    \"vitest-integration\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"svelte-vite-default-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:normal\", \"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/vue3-rsbuild-default-ts/project.json",
    "content": "{\n  \"name\": \"vue3-rsbuild/default-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"vue3-rsbuild-default-ts\"\n      }\n    },\n    \"dev\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"vue3-rsbuild-default-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/vue3-vite-default-js/project.json",
    "content": "{\n  \"name\": \"vue3-vite/default-js\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"vue3-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"vue3-vite-default-js\"\n      }\n    },\n    \"dev\": {},\n    \"vitest-integration\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"vue3-vite-default-js\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:daily\"]\n}\n"
  },
  {
    "path": "code/sandbox/vue3-vite-default-ts/project.json",
    "content": "{\n  \"name\": \"vue3-vite/default-ts\",\n  \"description\": \"Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.\",\n  \"projectType\": \"application\",\n  \"implicitDependencies\": [\n    \"core\",\n    \"cli\",\n    \"addon-a11y\",\n    \"addon-docs\",\n    \"addon-vitest\",\n    \"addon-onboarding\",\n    \"vue3-vite\"\n  ],\n  \"targets\": {\n    \"sandbox\": {\n      \"options\": {\n        \"dir\": \"vue3-vite-default-ts\"\n      }\n    },\n    \"dev\": {},\n    \"vitest-integration\": {},\n    \"build\": {\n      \"options\": {\n        \"dir\": \"vue3-vite-default-ts\"\n      }\n    },\n    \"chromatic\": {},\n    \"serve\": {},\n    \"e2e-tests\": {},\n    \"e2e-tests-dev\": {},\n    \"test-runner\": {},\n    \"test-runner-dev\": {}\n  },\n  \"tags\": [\"ci:normal\", \"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "code/tsconfig.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"compilerOptions\": {\n    \"allowSyntheticDefaultImports\": true,\n    \"baseUrl\": \".\",\n    \"customConditions\": [\"code\"],\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"ignoreDeprecations\": \"5.0\",\n    \"incremental\": false,\n    \"isolatedModules\": true,\n    \"allowImportingTsExtensions\": true,\n    \"jsx\": \"preserve\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"module\": \"Preserve\",\n    \"moduleResolution\": \"bundler\",\n    \"noImplicitAny\": true,\n    \"noUnusedLocals\": false,\n    \"skipLibCheck\": true,\n    \"strict\": true,\n    \"noEmit\": true,\n    \"strictBindCallApply\": true,\n    \"target\": \"ES2020\"\n  },\n  \"exclude\": [\"dist\", \"**/dist\", \"node_modules\", \"**/node_modules\"]\n}\n"
  },
  {
    "path": "code/vitest-setup.ts",
    "content": "import '@testing-library/jest-dom/vitest';\nimport { expect, vi } from 'vitest';\n\nimport { dedent } from 'ts-dedent';\n\nconst ignoreList = [\n  (error: any) => error.message.includes('\":nth-child\" is potentially unsafe'),\n  (error: any) => error.message.includes('\":first-child\" is potentially unsafe'),\n  (error: any) =>\n    error.message.match(\n      `Support for defaultProps will be removed from function components in a future major release`\n    ),\n  (error: any) => error.message.match(/Browserslist: .* is outdated. Please run:/),\n  (error: any) => error.message.includes('Consider adding an error boundary'),\n  (error: any) =>\n    error.message.includes('react-async-component-lifecycle-hooks') &&\n    error.stack.includes('addons/knobs/src/components/__tests__/Options.js'),\n  // React will log this error even if you catch an error with a boundary. I guess it's to\n  // help in development. See https://github.com/facebook/react/issues/15069\n  (error: any) =>\n    error.message.match(\n      /React will try to recreate this component tree from scratch using the error boundary you provided/\n    ),\n  (error: any) => error.message.includes('Lit is in dev mode. Not recommended for production!'),\n  (error: any) => error.message.includes('error: `DialogContent` requires a `DialogTitle`'),\n  (error: any) =>\n    error.message.includes(\n      \"importMetaResolve from within Storybook is being used in a Vitest test, but it shouldn't be. Please report this at https://github.com/storybookjs/storybook/issues/new?template=bug_report.yml\"\n    ),\n  (error: any) =>\n    error.message.includes('<Pressable> child must forward its ref to a DOM element.'),\n  (error: any) =>\n    error.message.includes('<Focusable> child must forward its ref to a DOM element.'),\n  (error: any) => error.message.includes('Please ensure the tabIndex prop is passed through.'),\n  // Vitest only warns about this if the import comes from a file outside of `node_modules`.\n  // This only occurs locally for us and is safe to ignore.\n  // It will stop once we start importing from `vitest/browser` instead (not a Vitest 3 compatible change).\n  // TODO: can be removed in SB11 (when/if we remove Vitest 3 support)\n  (error: any) =>\n    error.message.includes('tries to load a deprecated \"@vitest/browser/context\" module.'),\n];\n\nconst throwMessage = (type: any, message: any) => {\n  // eslint-disable-next-line local-rules/no-uncategorized-errors\n  const error = new Error(`${type}${message}`);\n  if (!ignoreList.reduce((acc, item) => acc || item(error), false)) {\n    throw error;\n  }\n};\nconst throwWarning = (message: any) => throwMessage('warn: ', message);\nconst throwError = (message: any) => throwMessage('error: ', message);\n\nglobalThis.FEATURES ??= {};\n\nvi.spyOn(console, 'warn').mockImplementation(throwWarning);\nvi.spyOn(console, 'error').mockImplementation(throwError);\n\nexpect.extend({\n  toMatchPaths(regex: RegExp, paths: string[]) {\n    const matched = paths.map((p) => !!p.match(regex));\n\n    const pass = matched.every(Boolean);\n    const failures = paths.filter((_, i) => (pass ? matched[i] : !matched[i]));\n    const message = () => dedent`Expected ${regex} to ${pass ? 'not ' : ''}match all strings.\n    \n    Failures:${['', ...failures].join('\\n - ')}`;\n    return {\n      pass,\n      message,\n    };\n  },\n});\n\nvi.mock('storybook/internal/node-logger', async (importOriginal) => {\n  return {\n    ...(await importOriginal<typeof import('storybook/internal/node-logger')>()),\n    prompt: {\n      select: vi.fn(),\n      multiSelect: vi.fn(),\n      confirm: vi.fn(),\n      text: vi.fn(),\n      getPreferredStdio: vi.fn(),\n      executeTask: vi.fn(),\n      executeTaskWithSpinner: vi.fn(),\n      taskLog: vi.fn(() => ({\n        message: vi.fn(),\n        success: vi.fn(),\n        error: vi.fn(),\n      })),\n    },\n    logger: {\n      SYMBOLS: {\n        success: '✓',\n        error: '✗',\n      },\n      plain: vi.fn(),\n      line: vi.fn(),\n      error: vi.fn(),\n      log: vi.fn(),\n      warn: vi.fn(),\n      info: vi.fn(),\n      trace: vi.fn(),\n      debug: vi.fn(),\n      box: vi.fn(),\n      verbose: vi.fn(),\n      logBox: vi.fn(),\n      intro: vi.fn(),\n      outro: vi.fn(),\n      step: vi.fn(),\n    },\n  };\n});\n\nvi.mock('./core/src/shared/utils/module.ts', async (importOriginal) => {\n  return {\n    ...(await importOriginal()),\n    resolvePackageDir: vi.fn().mockReturnValue('/mocked/package/dir'),\n    importModule: vi.fn().mockResolvedValue({\n      mocked: true,\n    }),\n  };\n});\n"
  },
  {
    "path": "code/vitest.config.storybook.ts",
    "content": "import { defaultExclude, defineProject } from 'vitest/config';\n\nimport { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n\nimport { playwright } from '@vitest/browser-playwright';\nimport Inspect from 'vite-plugin-inspect';\n\nconst extraPlugins: any[] = [];\nif (process.env.INSPECT === 'true') {\n  // this plugin assists in inspecting the Storybook Vitest plugin's transformation and sourcemaps\n  extraPlugins.push(\n    Inspect({\n      outputDir: '.vite-inspect',\n      build: true,\n      open: true,\n      include: ['**/*.stories.*'],\n    })\n  );\n}\n\nexport default defineProject({\n  plugins: [\n    storybookTest({\n      configDir: import.meta.dirname + '/.storybook',\n      tags: {\n        include: ['vitest'],\n      },\n    }),\n    ...extraPlugins,\n  ],\n  test: {\n    name: 'storybook-ui',\n    exclude: [\n      ...defaultExclude,\n      'node_modules/**',\n      '**/__mockdata__/**',\n      '**/Zoom.stories.tsx', // expected to fail in Vitest because of fetching /iframe.html to cause ECONNREFUSED\n      './addons/docs/src/blocks/**', // won't work because of https://github.com/storybookjs/storybook/issues/29783\n    ],\n    // TODO: bring this back once portable stories support storybook/preview-api hooks\n    testNamePattern: /^(?!.*(UseState)).*$/,\n    browser: {\n      enabled: true,\n      provider: playwright({}),\n      instances: [\n        {\n          browser: 'chromium',\n        },\n      ],\n      headless: true,\n      screenshotFailures: false,\n    },\n    setupFiles: ['./.storybook/storybook.setup.ts'],\n    environment: 'happy-dom',\n  },\n});\n"
  },
  {
    "path": "code/vitest.helpers.ts",
    "content": "import { platform } from 'node:os';\n\nconst WINDOWS_PLATFORM = 'win32';\n// Implement these whenever needed...\n// const MACOS_PLATFORM = 'darwin';\n// const LINUX_PLATFORM = 'linux';\n\nlet currentPlatform: NodeJS.Platform;\n\nconst getPlatform = () => {\n  if (!currentPlatform) {\n    currentPlatform = platform();\n  }\n\n  return currentPlatform;\n};\n\nfunction skipOn(platfm: NodeJS.Platform) {\n  return (fn: Function) => {\n    if (getPlatform() !== platfm) {\n      fn();\n    }\n  };\n}\n\nfunction onlyOn(platfm: NodeJS.Platform) {\n  return (fn: Function) => {\n    if (getPlatform() === platfm) {\n      fn();\n    }\n  };\n}\n\nexport const IS_WINDOWS = getPlatform() === WINDOWS_PLATFORM;\nexport const skipWindows = skipOn(WINDOWS_PLATFORM);\nexport const onlyWindows = onlyOn(WINDOWS_PLATFORM);\n"
  },
  {
    "path": "code/vitest.shared.ts",
    "content": "import { resolve } from 'node:path';\n\nimport { defineConfig } from 'vitest/config';\n\nexport const vitestCommonConfig = defineConfig({\n  test: {\n    passWithNoTests: true,\n    clearMocks: true,\n    setupFiles: [resolve(__dirname, './vitest-setup.ts')],\n    // Disable globals due to https://github.com/testing-library/user-event/pull/1176 not being released yet\n    globals: false,\n    testTimeout: 10000,\n    environment: 'node',\n  },\n});\n"
  },
  {
    "path": "codecov.yml",
    "content": "comment: false\ncoverage:\n  status:\n    project:\n      default:\n        target: auto\n        threshold: 2%\n"
  },
  {
    "path": "dependabot.yml",
    "content": "version: 2\n\nupdates:\n  - package-ecosystem: \"npm\"\n    directories:\n      - \"code\"\n      - \"scripts\"\n    schedule:\n      interval: \"weekly\"\n"
  },
  {
    "path": "docs/_snippets/actions-filtering-example.md",
    "content": "```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, svelte)\nimport type { Preview } from '@storybook/your-framework';\n\nimport { action } from 'storybook/actions';\nimport { spyOn } from 'storybook/test';\n\nconst originalConsoleLog = console.log;\nconst preview: Preview = {\n  async beforeEach() {\n    spyOn(console, 'log')\n      // Disable automatic logging in the actions panel\n      .mockName('')\n      .mockImplementation((args) => {\n        // Check if the log message matches a certain pattern\n        if (someCondition(args)) {\n          // Manually log an action\n          action('console.log')(args);\n        }\n\n        // Call the original console.log function\n        originalConsoleLog(...args);\n      });\n  },\n};\n\nexport default preview;\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { action } from 'storybook/actions';\nimport { spyOn } from 'storybook/test';\n\nconst originalConsoleLog = console.log;\nexport default {\n  async beforeEach() {\n    spyOn(console, 'log')\n      // Disable automatic logging in the actions panel\n      .mockName('')\n      .mockImplementation((args) => {\n        // Check if the log message matches a certain pattern\n        if (someCondition(args)) {\n          // Manually log an action\n          action('console.log')(args);\n        }\n\n        // Call the original console.log function\n        originalConsoleLog(...args);\n      });\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { action } from 'storybook/actions';\nimport { spyOn } from 'storybook/test';\n\nconst originalConsoleLog = console.log;\n\nexport default definePreview({\n  async beforeEach() {\n    spyOn(console, 'log')\n      // Disable automatic logging in the actions panel\n      .mockName('')\n      .mockImplementation((args) => {\n        // Check if the log message matches a certain pattern\n        if (someCondition(args)) {\n          // Manually log an action\n          action('console.log')(args);\n        }\n\n        // Call the original console.log function\n        originalConsoleLog(...args);\n      });\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { action } from 'storybook/actions';\nimport { spyOn } from 'storybook/test';\n\nconst originalConsoleLog = console.log;\nexport default definePreview({\n  async beforeEach() {\n    spyOn(console, 'log')\n      // Disable automatic logging in the actions panel\n      .mockName('')\n      .mockImplementation((args) => {\n        // Check if the log message matches a certain pattern\n        if (someCondition(args)) {\n          // Manually log an action\n          action('console.log')(args);\n        }\n\n        // Call the original console.log function\n        originalConsoleLog(...args);\n      });\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport { action } from 'storybook/actions';\nimport { spyOn } from 'storybook/test';\n\nconst originalConsoleLog = console.log;\n\nexport default definePreview({\n  async beforeEach() {\n    spyOn(console, 'log')\n      // Disable automatic logging in the actions panel\n      .mockName('')\n      .mockImplementation((args) => {\n        // Check if the log message matches a certain pattern\n        if (someCondition(args)) {\n          // Manually log an action\n          action('console.log')(args);\n        }\n\n        // Call the original console.log function\n        originalConsoleLog(...args);\n      });\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport { action } from 'storybook/actions';\nimport { spyOn } from 'storybook/test';\n\nconst originalConsoleLog = console.log;\nexport default definePreview({\n  async beforeEach() {\n    spyOn(console, 'log')\n      // Disable automatic logging in the actions panel\n      .mockName('')\n      .mockImplementation((args) => {\n        // Check if the log message matches a certain pattern\n        if (someCondition(args)) {\n          // Manually log an action\n          action('console.log')(args);\n        }\n\n        // Call the original console.log function\n        originalConsoleLog(...args);\n      });\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nimport { action } from 'storybook/actions';\nimport { spyOn } from 'storybook/test';\n\nconst originalConsoleLog = console.log;\n\nexport default definePreview({\n  async beforeEach() {\n    spyOn(console, 'log')\n      // Disable automatic logging in the actions panel\n      .mockName('')\n      .mockImplementation((args) => {\n        // Check if the log message matches a certain pattern\n        if (someCondition(args)) {\n          // Manually log an action\n          action('console.log')(args);\n        }\n\n        // Call the original console.log function\n        originalConsoleLog(...args);\n      });\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { action } from 'storybook/actions';\nimport { spyOn } from 'storybook/test';\n\nconst originalConsoleLog = console.log;\n\nexport default definePreview({\n  async beforeEach() {\n    spyOn(console, 'log')\n      // Disable automatic logging in the actions panel\n      .mockName('')\n      .mockImplementation((args) => {\n        // Check if the log message matches a certain pattern\n        if (someCondition(args)) {\n          // Manually log an action\n          action('console.log')(args);\n        }\n\n        // Call the original console.log function\n        originalConsoleLog(...args);\n      });\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { action } from 'storybook/actions';\nimport { spyOn } from 'storybook/test';\n\nconst originalConsoleLog = console.log;\nexport default definePreview({\n  async beforeEach() {\n    spyOn(console, 'log')\n      // Disable automatic logging in the actions panel\n      .mockName('')\n      .mockImplementation((args) => {\n        // Check if the log message matches a certain pattern\n        if (someCondition(args)) {\n          // Manually log an action\n          action('console.log')(args);\n        }\n\n        // Call the original console.log function\n        originalConsoleLog(...args);\n      });\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/actions-spyon-basic-example.md",
    "content": "```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, svelte)\nimport type { Preview } from '@storybook/your-framework';\n\nimport { spyOn } from 'storybook/test';\n\nconst preview: Preview = {\n  async beforeEach() {\n    spyOn(console, 'log').mockName('console.log');\n  },\n};\n\nexport default preview;\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { spyOn } from 'storybook/test';\n\nexport default {\n  async beforeEach() {\n    spyOn(console, 'log').mockName('console.log');\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { spyOn } from 'storybook/test';\n\nexport default definePreview({\n  async beforeEach() {\n    spyOn(console, 'log').mockName('console.log');\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { spyOn } from 'storybook/test';\n\nexport default definePreview({\n  async beforeEach() {\n    spyOn(console, 'log').mockName('console.log');\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport { spyOn } from 'storybook/test';\n\nexport default definePreview({\n  async beforeEach() {\n    spyOn(console, 'log').mockName('console.log');\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport { spyOn } from 'storybook/test';\n\nexport default definePreview({\n  async beforeEach() {\n    spyOn(console, 'log').mockName('console.log');\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nimport { spyOn } from 'storybook/test';\n\nexport default definePreview({\n  async beforeEach() {\n    spyOn(console, 'log').mockName('console.log');\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { spyOn } from 'storybook/test';\n\nexport default definePreview({\n  async beforeEach() {\n    spyOn(console, 'log').mockName('console.log');\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { spyOn } from 'storybook/test';\n\nexport default definePreview({\n  async beforeEach() {\n    spyOn(console, 'log').mockName('console.log');\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-a11y-add.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook add @storybook/addon-a11y\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm exec storybook add @storybook/addon-a11y\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn exec storybook add @storybook/addon-a11y\n```\n"
  },
  {
    "path": "docs/_snippets/addon-a11y-config-context-in-story.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// ...rest of story file\n\nexport const ExampleStory: Story = {\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {\n        include: ['body'],\n        exclude: ['.no-a11y-check'],\n      },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\n// ...rest of story file\n\nexport const ExampleStory = {\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {\n        include: ['body'],\n        exclude: ['.no-a11y-check'],\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\n// ...rest of story file\n\nexport const ExampleStory: Story = {\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {\n        include: ['body'],\n        exclude: ['.no-a11y-check'],\n      },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const ExampleStory = meta.story({\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {\n        include: ['body'],\n        exclude: ['.no-a11y-check'],\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const ExampleStory = meta.story({\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {\n        include: ['body'],\n        exclude: ['.no-a11y-check'],\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const ExampleStory = meta.story({\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {\n        include: ['body'],\n        exclude: ['.no-a11y-check'],\n      },\n    },\n  },\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"common\" language=\"js\"\n// ...rest of story file\n\nexport const ExampleStory = {\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {\n        include: ['body'],\n        exclude: ['.no-a11y-check'],\n      },\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"ExampleStory\"\n  parameters={{\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {\n        include: ['body'],\n        exclude: ['.no-a11y-check'],\n      },\n    },\n  }}\n/>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// ...rest of story file\n\nexport const ExampleStory: Story = {\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {\n        include: ['body'],\n        exclude: ['.no-a11y-check'],\n      },\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"ExampleStory\"\n  parameters={{\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {\n        include: ['body'],\n        exclude: ['.no-a11y-check'],\n      },\n    },\n  }}\n/>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\n// ...rest of story file\n\nexport const ExampleStory = {\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {\n        include: ['body'],\n        exclude: ['.no-a11y-check'],\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const ExampleStory = meta.story({\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {\n        include: ['body'],\n        exclude: ['.no-a11y-check'],\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const ExampleStory = meta.story({\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {\n        include: ['body'],\n        exclude: ['.no-a11y-check'],\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const ExampleStory = meta.story({\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {\n        include: ['body'],\n        exclude: ['.no-a11y-check'],\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const ExampleStory = meta.story({\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {\n        include: ['body'],\n        exclude: ['.no-a11y-check'],\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-a11y-config-in-meta-and-story.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {},\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n      /*\n       * Configure test behavior\n       * See: https://storybook.js.org/docs/next/writing-tests/accessibility-testing#test-behavior\n       */\n      test: 'error',\n    },\n  },\n  globals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n};\nexport default meta;\n\ntype Story = StoryObj<Button>;\n\nexport const ExampleStory: Story = {\n  parameters: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n  globals: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {},\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n      /*\n       * Configure test behavior\n       * See: https://storybook.js.org/docs/next/writing-tests/accessibility-testing#test-behavior\n       */\n      test: 'error',\n    },\n  },\n  globals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n});\n\nexport const ExampleStory = meta.story({\n  parameters: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n  globals: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {},\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n      /*\n       * Configure test behavior\n       * See: https://storybook.js.org/docs/next/writing-tests/accessibility-testing#test-behavior\n       */\n      test: 'error',\n    },\n  },\n  globals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n} satisfies Meta<typeof Button>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const ExampleStory: Story = {\n  parameters: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n  globals: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {},\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n      /*\n       * Configure test behavior\n       * See: https://storybook.js.org/docs/next/writing-tests/accessibility-testing#test-behavior\n       */\n      test: 'error',\n    },\n  },\n  globals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n};\n\nexport const ExampleStory = {\n  parameters: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n  globals: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {},\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n      /*\n       * Configure test behavior\n       * See: https://storybook.js.org/docs/next/writing-tests/accessibility-testing#test-behavior\n       */\n      test: 'error',\n    },\n  },\n  globals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n  });\n</script>\n\n<Story\n  name=\"ExampleStory\"\n  parameters={{\n    a11y: {\n      // ...same config available as above\n    },\n  }}\n  globals={{\n    a11y: {\n      // ...same config available as above\n    },\n  }}\n/>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {},\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n      /*\n       * Configure test behavior\n       * See: https://storybook.js.org/docs/next/writing-tests/accessibility-testing#test-behavior\n       */\n      test: 'error',\n    },\n  },\n  globals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ExampleStory: Story = {\n  parameters: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n  globals: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {},\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n      /*\n       * Configure test behavior\n       * See: https://storybook.js.org/docs/next/writing-tests/accessibility-testing#test-behavior\n       */\n      test: 'error',\n    },\n  },\n  globals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n  });\n</script>\n\n<Story\n  name=\"ExampleStory\"\n  parameters={{\n    a11y: {\n      // ...same config available as above\n    },\n  }}\n  globals={{\n    a11y: {\n      // ...same config available as above\n    },\n  }}\n/>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {},\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n      /*\n       * Configure test behavior\n       * See: https://storybook.js.org/docs/next/writing-tests/accessibility-testing#test-behavior\n       */\n      test: 'error',\n    },\n  },\n  globals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n};\n\nexport const ExampleStory = {\n  parameters: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n  globals: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {},\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n      /*\n       * Configure test behavior\n       * See: https://storybook.js.org/docs/next/writing-tests/accessibility-testing#test-behavior\n       */\n      test: 'error',\n    },\n  },\n  globals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n};\nexport default meta;\n\ntype Story = StoryObj;\n\nexport const ExampleStory: Story = {\n  parameters: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n  globals: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {},\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n      /*\n       * Configure test behavior\n       * See: https://storybook.js.org/docs/next/writing-tests/accessibility-testing#test-behavior\n       */\n      test: 'error',\n    },\n  },\n  globals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n};\n\nexport const ExampleStory = {\n  parameters: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n  globals: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {},\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n      /*\n       * Configure test behavior\n       * See: https://storybook.js.org/docs/next/writing-tests/accessibility-testing#test-behavior\n       */\n      test: 'error',\n    },\n  },\n  globals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n});\n\nexport const ExampleStory = meta.story({\n  parameters: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n  globals: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {},\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n      /*\n       * Configure test behavior\n       * See: https://storybook.js.org/docs/next/writing-tests/accessibility-testing#test-behavior\n       */\n      test: 'error',\n    },\n  },\n  globals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n});\n\nexport const ExampleStory = meta.story({\n  parameters: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n  globals: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {},\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n      /*\n       * Configure test behavior\n       * See: https://storybook.js.org/docs/next/writing-tests/accessibility-testing#test-behavior\n       */\n      test: 'error',\n    },\n  },\n  globals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n});\n\nexport const ExampleStory = meta.story({\n  parameters: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n  globals: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {},\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n      /*\n       * Configure test behavior\n       * See: https://storybook.js.org/docs/next/writing-tests/accessibility-testing#test-behavior\n       */\n      test: 'error',\n    },\n  },\n  globals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n});\n\nexport const ExampleStory = meta.story({\n  parameters: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n  globals: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {},\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n      /*\n       * Configure test behavior\n       * See: https://storybook.js.org/docs/next/writing-tests/accessibility-testing#test-behavior\n       */\n      test: 'error',\n    },\n  },\n  globals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n});\n\nexport const ExampleStory = meta.story({\n  parameters: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n  globals: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more.\n       */\n      context: {},\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n      /*\n       * Configure test behavior\n       * See: https://storybook.js.org/docs/next/writing-tests/accessibility-testing#test-behavior\n       */\n      test: 'error',\n    },\n  },\n  globals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n});\n\nexport const ExampleStory = meta.story({\n  parameters: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n  globals: {\n    a11y: {\n      // ...same config available as above\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-a11y-config-in-preview.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more. Typically, this is the CSS selector for the part of the DOM you want to analyze.\n       */\n      context: 'body',\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n    },\n  },\n  initialGlobals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more. Typically, this is the CSS selector for the part of the DOM you want to analyze.\n       */\n      context: 'body',\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n    },\n  },\n  initialGlobals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more. Typically, this is the CSS selector for the part of the DOM you want to analyze.\n       */\n      context: 'body',\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n    },\n  },\n  initialGlobals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more. Typically, this is the CSS selector for the part of the DOM you want to analyze.\n       */\n      context: 'body',\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n    },\n  },\n  initialGlobals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more. Typically, this is the CSS selector for the part of the DOM you want to analyze.\n       */\n      context: 'body',\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n    },\n  },\n  initialGlobals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more. Typically, this is the CSS selector for the part of the DOM you want to analyze.\n       */\n      context: 'body',\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n    },\n  },\n  initialGlobals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more. Typically, this is the CSS selector for the part of the DOM you want to analyze.\n       */\n      context: 'body',\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n    },\n  },\n  initialGlobals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more. Typically, this is the CSS selector for the part of the DOM you want to analyze.\n       */\n      context: 'body',\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n    },\n  },\n  initialGlobals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    a11y: {\n      /*\n       * Axe's context parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter\n       * to learn more. Typically, this is the CSS selector for the part of the DOM you want to analyze.\n       */\n      context: 'body',\n      /*\n       * Axe's configuration\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure\n       * to learn more about the available properties.\n       */\n      config: {},\n      /*\n       * Axe's options parameter\n       * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter\n       * to learn more about the available options.\n       */\n      options: {},\n    },\n  },\n  initialGlobals: {\n    a11y: {\n      // Optional flag to prevent the automatic check\n      manual: true,\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-a11y-config-rules-in-story.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// ...rest of story file\n\nexport const IndividualA11yRulesExample: Story = {\n  parameters: {\n    a11y: {\n      config: {\n        rules: [\n          {\n            // The autocomplete rule will not run based on the CSS selector provided\n            id: 'autocomplete-valid',\n            selector: '*:not([autocomplete=\"nope\"])',\n          },\n          {\n            // Setting the enabled option to false will disable checks for this particular rule on all stories.\n            id: 'image-alt',\n            enabled: false,\n          },\n        ],\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const IndividualA11yRulesExample = meta.story({\n  parameters: {\n    a11y: {\n      config: {\n        rules: [\n          {\n            // The autocomplete rule will not run based on the CSS selector provided\n            id: 'autocomplete-valid',\n            selector: '*:not([autocomplete=\"nope\"])',\n          },\n          {\n            // Setting the enabled option to false will disable checks for this particular rule on all stories.\n            id: 'image-alt',\n            enabled: false,\n          },\n        ],\n      },\n    },\n  },\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\n// ...rest of story file\n\nexport const IndividualA11yRulesExample = {\n  parameters: {\n    a11y: {\n      config: {\n        rules: [\n          {\n            // The autocomplete rule will not run based on the CSS selector provided\n            id: 'autocomplete-valid',\n            selector: '*:not([autocomplete=\"nope\"])',\n          },\n          {\n            // Setting the enabled option to false will disable checks for this particular rule on all stories.\n            id: 'image-alt',\n            enabled: false,\n          },\n        ],\n      },\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"IndividualA11yRulesExample\"\n  parameters={{\n    a11y: {\n      config: {\n        rules: [\n          {\n            // The autocomplete rule will not run based on the CSS selector provided\n            id: 'autocomplete-valid',\n            selector: '*:not([autocomplete=\"nope\"])',\n          },\n          {\n            // Setting the enabled option to false will disable checks for this particular rule on all stories.\n            id: 'image-alt',\n            enabled: false,\n          },\n        ],\n      },\n    },\n  }}\n/>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// ...rest of story file\n\nexport const IndividualA11yRulesExample: Story = {\n  parameters: {\n    a11y: {\n      config: {\n        rules: [\n          {\n            // The autocomplete rule will not run based on the CSS selector provided\n            id: 'autocomplete-valid',\n            selector: '*:not([autocomplete=\"nope\"])',\n          },\n          {\n            // Setting the enabled option to false will disable checks for this particular rule on all stories.\n            id: 'image-alt',\n            enabled: false,\n          },\n        ],\n      },\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"IndividualA11yRulesExample\"\n  parameters={{\n    a11y: {\n      config: {\n        rules: [\n          {\n            // The autocomplete rule will not run based on the CSS selector provided\n            id: 'autocomplete-valid',\n            selector: '*:not([autocomplete=\"nope\"])',\n          },\n          {\n            // Setting the enabled option to false will disable checks for this particular rule on all stories.\n            id: 'image-alt',\n            enabled: false,\n          },\n        ],\n      },\n    },\n  }}\n/>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\n// ...rest of story file\n\nexport const IndividualA11yRulesExample = {\n  parameters: {\n    a11y: {\n      config: {\n        rules: [\n          {\n            // The autocomplete rule will not run based on the CSS selector provided\n            id: 'autocomplete-valid',\n            selector: '*:not([autocomplete=\"nope\"])',\n          },\n          {\n            // Setting the enabled option to false will disable checks for this particular rule on all stories.\n            id: 'image-alt',\n            enabled: false,\n          },\n        ],\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const IndividualA11yRulesExample = meta.story({\n  parameters: {\n    a11y: {\n      config: {\n        rules: [\n          {\n            // The autocomplete rule will not run based on the CSS selector provided\n            id: 'autocomplete-valid',\n            selector: '*:not([autocomplete=\"nope\"])',\n          },\n          {\n            // Setting the enabled option to false will disable checks for this particular rule on all stories.\n            id: 'image-alt',\n            enabled: false,\n          },\n        ],\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const IndividualA11yRulesExample = meta.story({\n  parameters: {\n    a11y: {\n      config: {\n        rules: [\n          {\n            // The autocomplete rule will not run based on the CSS selector provided\n            id: 'autocomplete-valid',\n            selector: '*:not([autocomplete=\"nope\"])',\n          },\n          {\n            // Setting the enabled option to false will disable checks for this particular rule on all stories.\n            id: 'image-alt',\n            enabled: false,\n          },\n        ],\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const IndividualA11yRulesExample = meta.story({\n  parameters: {\n    a11y: {\n      config: {\n        rules: [\n          {\n            // The autocomplete rule will not run based on the CSS selector provided\n            id: 'autocomplete-valid',\n            selector: '*:not([autocomplete=\"nope\"])',\n          },\n          {\n            // Setting the enabled option to false will disable checks for this particular rule on all stories.\n            id: 'image-alt',\n            enabled: false,\n          },\n        ],\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const IndividualA11yRulesExample = meta.story({\n  parameters: {\n    a11y: {\n      config: {\n        rules: [\n          {\n            // The autocomplete rule will not run based on the CSS selector provided\n            id: 'autocomplete-valid',\n            selector: '*:not([autocomplete=\"nope\"])',\n          },\n          {\n            // Setting the enabled option to false will disable checks for this particular rule on all stories.\n            id: 'image-alt',\n            enabled: false,\n          },\n        ],\n      },\n    },\n  },\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\n// ...rest of story file\n\nexport const IndividualA11yRulesExample = {\n  parameters: {\n    a11y: {\n      config: {\n        rules: [\n          {\n            // The autocomplete rule will not run based on the CSS selector provided\n            id: 'autocomplete-valid',\n            selector: '*:not([autocomplete=\"nope\"])',\n          },\n          {\n            // Setting the enabled option to false will disable checks for this particular rule on all stories.\n            id: 'image-alt',\n            enabled: false,\n          },\n        ],\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\n// ...rest of story file\n\nexport const IndividualA11yRulesExample: Story = {\n  parameters: {\n    a11y: {\n      config: {\n        rules: [\n          {\n            // The autocomplete rule will not run based on the CSS selector provided\n            id: 'autocomplete-valid',\n            selector: '*:not([autocomplete=\"nope\"])',\n          },\n          {\n            // Setting the enabled option to false will disable checks for this particular rule on all stories.\n            id: 'image-alt',\n            enabled: false,\n          },\n        ],\n      },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const IndividualA11yRulesExample = meta.story({\n  parameters: {\n    a11y: {\n      config: {\n        rules: [\n          {\n            // The autocomplete rule will not run based on the CSS selector provided\n            id: 'autocomplete-valid',\n            selector: '*:not([autocomplete=\"nope\"])',\n          },\n          {\n            // Setting the enabled option to false will disable checks for this particular rule on all stories.\n            id: 'image-alt',\n            enabled: false,\n          },\n        ],\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const IndividualA11yRulesExample = meta.story({\n  parameters: {\n    a11y: {\n      config: {\n        rules: [\n          {\n            // The autocomplete rule will not run based on the CSS selector provided\n            id: 'autocomplete-valid',\n            selector: '*:not([autocomplete=\"nope\"])',\n          },\n          {\n            // Setting the enabled option to false will disable checks for this particular rule on all stories.\n            id: 'image-alt',\n            enabled: false,\n          },\n        ],\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-a11y-config-rulesets-in-preview.md",
    "content": "```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    a11y: {\n      options: {\n        /*\n         * Opt in to running WCAG 2.x AAA rules\n         * Note that you must explicitly re-specify the defaults (all but the last array entry)\n         * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter-examples for more details\n         */\n        runOnly: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'best-practice', 'wcag2aaa'],\n      },\n    },\n  },\n};\n\nexport default preview;\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    a11y: {\n      options: {\n        /*\n         * Opt in to running WCAG 2.x AAA rules\n         * Note that you must explicitly re-specify the defaults (all but the last array entry)\n         * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter-examples for more details\n         */\n        runOnly: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'best-practice', 'wcag2aaa'],\n      },\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    a11y: {\n      options: {\n        /*\n         * Opt in to running WCAG 2.x AAA rules\n         * Note that you must explicitly re-specify the defaults (all but the last array entry)\n         * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter-examples for more details\n         */\n        runOnly: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'best-practice', 'wcag2aaa'],\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    a11y: {\n      options: {\n        /*\n         * Opt in to running WCAG 2.x AAA rules\n         * Note that you must explicitly re-specify the defaults (all but the last array entry)\n         * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter-examples for more details\n         */\n        runOnly: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'best-practice', 'wcag2aaa'],\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    a11y: {\n      options: {\n        /*\n         * Opt in to running WCAG 2.x AAA rules\n         * Note that you must explicitly re-specify the defaults (all but the last array entry)\n         * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter-examples for more details\n         */\n        runOnly: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'best-practice', 'wcag2aaa'],\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    a11y: {\n      options: {\n        /*\n         * Opt in to running WCAG 2.x AAA rules\n         * Note that you must explicitly re-specify the defaults (all but the last array entry)\n         * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter-examples for more details\n         */\n        runOnly: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'best-practice', 'wcag2aaa'],\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    a11y: {\n      options: {\n        /*\n         * Opt in to running WCAG 2.x AAA rules\n         * Note that you must explicitly re-specify the defaults (all but the last array entry)\n         * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter-examples for more details\n         */\n        runOnly: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'best-practice', 'wcag2aaa'],\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    a11y: {\n      options: {\n        /*\n         * Opt in to running WCAG 2.x AAA rules\n         * Note that you must explicitly re-specify the defaults (all but the last array entry)\n         * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter-examples for more details\n         */\n        runOnly: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'best-practice', 'wcag2aaa'],\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    a11y: {\n      options: {\n        /*\n         * Opt in to running WCAG 2.x AAA rules\n         * Note that you must explicitly re-specify the defaults (all but the last array entry)\n         * See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter-examples for more details\n         */\n        runOnly: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'best-practice', 'wcag2aaa'],\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-a11y-disable.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n};\n\nexport default meta;\ntype Story = StoryObj<MyComponent>;\n\nexport const NonA11yStory: Story = {\n  globals: {\n    a11y: {\n      // This option disables all automatic a11y checks on this story\n      manual: true,\n    },\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const NonA11yStory = meta.story({\n  globals: {\n    a11y: {\n      // This option disables all automatic a11y checks on this story\n      manual: true,\n    },\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const NonA11yStory = {\n  globals: {\n    a11y: {\n      // This option disables all automatic a11y checks on this story\n      manual: true,\n    },\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const NonA11yStory: Story = {\n  globals: {\n    a11y: {\n      // This option disables all automatic a11y checks on this story\n      manual: true,\n    },\n  },\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"NonA11yStory\"\n  globals={{\n    a11y: {\n      // This option disables all automatic a11y checks on this story\n      manual: true,\n    },\n  }}\n/>\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.svelte';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const NonA11yStory = {\n  globals: {\n    a11y: {\n      // This option disables all automatic a11y checks on this story\n      manual: true,\n    },\n  },\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"NonA11yStory\"\n  globals={{\n    a11y: {\n      // This option disables all automatic a11y checks on this story\n      manual: true,\n    },\n  }}\n/>\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport MyComponent from './MyComponent.svelte';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const NonA11yStory: Story = {\n  globals: {\n    a11y: {\n      // This option disables all automatic a11y checks on this story\n      manual: true,\n    },\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.vue';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const NonA11yStory = {\n  globals: {\n    a11y: {\n      // This option disables all automatic a11y checks on this story\n      manual: true,\n    },\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const NonA11yStory: Story = {\n  globals: {\n    a11y: {\n      // This option disables all automatic a11y checks on this story\n      manual: true,\n    },\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const NonA11yStory = meta.story({\n  globals: {\n    a11y: {\n      // This option disables all automatic a11y checks on this story\n      manual: true,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const NonA11yStory = meta.story({\n  globals: {\n    a11y: {\n      // This option disables all automatic a11y checks on this story\n      manual: true,\n    },\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'my-component',\n};\n\nexport const ExampleStory = {\n  globals: {\n    a11y: {\n      // This option disables all automatic a11y checks on this story\n      manual: true,\n    },\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'my-component',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const ExampleStory: Story = {\n  globals: {\n    a11y: {\n      // This option disables all automatic a11y checks on this story\n      manual: true,\n    },\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const ExampleStory = meta.story({\n  globals: {\n    a11y: {\n      // This option disables all automatic a11y checks on this story\n      manual: true,\n    },\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const ExampleStory = meta.story({\n  globals: {\n    a11y: {\n      // This option disables all automatic a11y checks on this story\n      manual: true,\n    },\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const NonA11yStory = meta.story({\n  globals: {\n    a11y: {\n      // This option disables all automatic a11y checks on this story\n      manual: true,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const NonA11yStory = meta.story({\n  globals: {\n    a11y: {\n      // This option disables all automatic a11y checks on this story\n      manual: true,\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-a11y-install.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm install @storybook/addon-a11y --save-dev\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm add --save-dev @storybook/addon-a11y\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn add --dev @storybook/addon-a11y\n```\n"
  },
  {
    "path": "docs/_snippets/addon-a11y-parameter-error-in-preview.md",
    "content": "```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    // 👇 Fail all accessibility tests when violations are found\n    a11y: { test: 'error' },\n  },\n};\nexport default preview;\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    // 👇 Fail all accessibility tests when violations are found\n    a11y: { test: 'error' },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    // 👇 Fail all accessibility tests when violations are found\n    a11y: { test: 'error' },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    // 👇 Fail all accessibility tests when violations are found\n    a11y: { test: 'error' },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    // 👇 Fail all accessibility tests when violations are found\n    a11y: { test: 'error' },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    // 👇 Fail all accessibility tests when violations are found\n    a11y: { test: 'error' },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    // 👇 Fail all accessibility tests when violations are found\n    a11y: { test: 'error' },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    // 👇 Fail all accessibility tests when violations are found\n    a11y: { test: 'error' },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  addons: [addonA11y()],\n  parameters: {\n    // 👇 Fail all accessibility tests when violations are found\n    a11y: { test: 'error' },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-a11y-parameter-example.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  parameters: {\n    // 👇 Applies to all stories in this file\n    a11y: { test: 'error' },\n  },\n};\nexport default meta;\n\ntype Story = StoryObj<Button>;\n\n// 👇 This story will use the 'error' value and fail on accessibility violations\nexport const Primary: Story = {\n  args: { primary: true },\n};\n\n// 👇 This story will not fail on accessibility violations\n//    (but will still run the tests and show warnings)\nexport const NoA11yFail: Story = {\n  parameters: {\n    a11y: { test: 'todo' },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    // 👇 Applies to all stories in this file\n    a11y: { test: 'error' },\n  },\n});\n\n// 👇 This story will use the 'error' value and fail on accessibility violations\nexport const Primary = meta.story({\n  args: { primary: true },\n});\n\n// 👇 This story will not fail on accessibility violations\n//    (but will still run the tests and show warnings)\nexport const NoA11yFail = meta.story({\n  parameters: {\n    a11y: { test: 'todo' },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  parameters: {\n    // 👇 Applies to all stories in this file\n    a11y: { test: 'error' },\n  },\n} satisfies Meta<typeof Button>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n// 👇 This story will use the 'error' value and fail on accessibility violations\nexport const Primary: Story = {\n  args: { primary: true },\n};\n\n// 👇 This story will not fail on accessibility violations\n//    (but will still run the tests and show warnings)\nexport const NoA11yFail: Story = {\n  parameters: {\n    a11y: { test: 'todo' },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  parameters: {\n    // 👇 Applies to all stories in this file\n    a11y: { test: 'error' },\n  },\n};\n\n// 👇 This story will use the 'error' value and fail on accessibility violations\nexport const Primary = {\n  args: { primary: true },\n};\n\n// 👇 This story will not fail on accessibility violations\n//    (but will still run the tests and show warnings)\nexport const NoA11yFail = {\n  parameters: {\n    a11y: { test: 'todo' },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    parameters: {\n      // 👇 Applies to all stories in this file\n      a11y: { test: 'error' },\n    },\n  });\n</script>\n\n<!-- 👇 This story will use the 'error' value and fail on accessibility violations -->\n<Story\n  name=\"Primary\"\n  args={{ primary: true }}\n/>\n\n<!-- 👇 This story will not fail on accessibility violations\n        (but will still run the tests and show warnings) -->\n<Story\n  name=\"NoA11yFail\"\n  parameters={{\n    a11y: { test: 'todo' },\n  }}\n/>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  parameters: {\n    // 👇 Applies to all stories in this file\n    a11y: { test: 'error' },\n  },\n} satisfies Meta<typeof Button>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n// 👇 This story will use the 'error' value and fail on accessibility violations\nexport const Primary: Story = {\n  args: { primary: true },\n};\n\n// 👇 This story will not fail on accessibility violations\n//    (but will still run the tests and show warnings)\nexport const NoA11yFail: Story = {\n  parameters: {\n    a11y: { test: 'todo' },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    parameters: {\n      // 👇 Applies to all stories in this file\n      a11y: { test: 'error' },\n    },\n  });\n</script>\n\n<!-- 👇 This story will use the 'error' value and fail on accessibility violations -->\n<Story\n  name=\"Primary\"\n  args={{ primary: true }}\n/>\n\n<!-- 👇 This story will not fail on accessibility violations\n        (but will still run the tests and show warnings) -->\n<Story\n  name=\"NoA11yFail\"\n  parameters={{\n    a11y: { test: 'todo' },\n  }}\n/>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  parameters: {\n    // 👇 Applies to all stories in this file\n    a11y: { test: 'error' },\n  },\n};\n\n// 👇 This story will use the 'error' value and fail on accessibility violations\nexport const Primary = {\n  args: { primary: true },\n};\n\n// 👇 This story will not fail on accessibility violations\n//    (but will still run the tests and show warnings)\nexport const NoA11yFail = {\n  parameters: {\n    a11y: { test: 'todo' },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  parameters: {\n    // 👇 Applies to all stories in this file\n    a11y: { test: 'error' },\n  },\n};\nexport default meta;\n\ntype Story = StoryObj;\n\n// 👇 This story will use the 'error' value and fail on accessibility violations\nexport const Primary: Story = {\n  args: { primary: true },\n};\n\n// 👇 This story will not fail on accessibility violations\n//    (but will still run the tests and show warnings)\nexport const NoA11yFail: Story = {\n  parameters: {\n    a11y: { test: 'todo' },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n  parameters: {\n    // 👇 Applies to all stories in this file\n    a11y: { test: 'error' },\n  },\n};\n\n// 👇 This story will use the 'error' value and fail on accessibility violations\nexport const Primary = {\n  args: { primary: true },\n};\n\n// 👇 This story will not fail on accessibility violations\n//    (but will still run the tests and show warnings)\nexport const NoA11yFail = {\n  parameters: {\n    a11y: { test: 'todo' },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  parameters: {\n    // 👇 Applies to all stories in this file\n    a11y: { test: 'error' },\n  },\n});\n\n// 👇 This story will use the 'error' value and fail on accessibility violations\nexport const Primary = meta.story({\n  args: { primary: true },\n});\n\n// 👇 This story will not fail on accessibility violations\n//    (but will still run the tests and show warnings)\nexport const NoA11yFail = meta.story({\n  parameters: {\n    a11y: { test: 'todo' },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  parameters: {\n    // 👇 Applies to all stories in this file\n    a11y: { test: 'error' },\n  },\n});\n\n// 👇 This story will use the 'error' value and fail on accessibility violations\nexport const Primary = meta.story({\n  args: { primary: true },\n});\n\n// 👇 This story will not fail on accessibility violations\n//    (but will still run the tests and show warnings)\nexport const NoA11yFail = meta.story({\n  parameters: {\n    a11y: { test: 'todo' },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    // 👇 Applies to all stories in this file\n    a11y: { test: 'error' },\n  },\n});\n\n// 👇 This story will use the 'error' value and fail on accessibility violations\nexport const Primary = meta.story({\n  args: { primary: true },\n});\n\n// 👇 This story will not fail on accessibility violations\n//    (but will still run the tests and show warnings)\nexport const NoA11yFail = meta.story({\n  parameters: {\n    a11y: { test: 'todo' },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    // 👇 Applies to all stories in this file\n    a11y: { test: 'error' },\n  },\n});\n\n// 👇 This story will use the 'error' value and fail on accessibility violations\nexport const Primary = meta.story({\n  args: { primary: true },\n});\n\n// 👇 This story will not fail on accessibility violations\n//    (but will still run the tests and show warnings)\nexport const NoA11yFail = meta.story({\n  parameters: {\n    a11y: { test: 'todo' },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    // 👇 Applies to all stories in this file\n    a11y: { test: 'error' },\n  },\n});\n\n// 👇 This story will use the 'error' value and fail on accessibility violations\nexport const Primary = meta.story({\n  args: { primary: true },\n});\n\n// 👇 This story will not fail on accessibility violations\n//    (but will still run the tests and show warnings)\nexport const NoA11yFail = meta.story({\n  parameters: {\n    a11y: { test: 'todo' },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    // 👇 Applies to all stories in this file\n    a11y: { test: 'error' },\n  },\n});\n\n// 👇 This story will use the 'error' value and fail on accessibility violations\nexport const Primary = meta.story({\n  args: { primary: true },\n});\n\n// 👇 This story will not fail on accessibility violations\n//    (but will still run the tests and show warnings)\nexport const NoA11yFail = meta.story({\n  parameters: {\n    a11y: { test: 'todo' },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-a11y-parameter-remove.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  parameters: {\n    // 👇 Remove this once all stories pass accessibility tests\n    // a11y: { test: 'todo' },\n  },\n};\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    // 👇 Remove this once all stories pass accessibility tests\n    // a11y: { test: 'todo' },\n  },\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  parameters: {\n    // 👇 Remove this once all stories pass accessibility tests\n    // a11y: { test: 'todo' },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  parameters: {\n    // 👇 Remove this once all stories pass accessibility tests\n    // a11y: { test: 'todo' },\n  },\n} satisfies Meta<typeof Button>;\nexport default meta;\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    parameters: {\n      // 👇 Remove this once all stories pass accessibility tests\n      // a11y: { test: 'todo' },\n    },\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport type { Meta } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  parameters: {\n    // 👇 Remove this once all stories pass accessibility tests\n    // a11y: { test: 'todo' },\n  },\n} satisfies Meta<typeof Button>;\nexport default meta;\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    parameters: {\n      // 👇 Remove this once all stories pass accessibility tests\n      // a11y: { test: 'todo' },\n    },\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  parameters: {\n    // 👇 Remove this once all stories pass accessibility tests\n    // a11y: { test: 'todo' },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  parameters: {\n    // 👇 Remove this once all stories pass accessibility tests\n    // a11y: { test: 'todo' },\n  },\n};\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n  parameters: {\n    // 👇 Remove this once all stories pass accessibility tests\n    // a11y: { test: 'todo' },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  parameters: {\n    // 👇 Remove this once all stories pass accessibility tests\n    // a11y: { test: 'todo' },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  parameters: {\n    // 👇 Remove this once all stories pass accessibility tests\n    // a11y: { test: 'todo' },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    // 👇 Remove this once all stories pass accessibility tests\n    // a11y: { test: 'todo' },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    // 👇 Remove this once all stories pass accessibility tests\n    // a11y: { test: 'todo' },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    // 👇 Remove this once all stories pass accessibility tests\n    // a11y: { test: 'todo' },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    // 👇 Remove this once all stories pass accessibility tests\n    // a11y: { test: 'todo' },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-a11y-parameter-todo-in-meta.md",
    "content": "```ts filename=\"DataTable.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { Meta } from '@storybook/angular';\n\nimport { DataTable } from './data-table.component';\n\nconst meta: Meta<DataTable> = {\n  component: DataTable,\n  parameters: {\n    // 👇 This component's accessibility tests will not fail\n    //    Instead, they display warnings in the Storybook UI\n    a11y: { test: 'todo' },\n  },\n};\nexport default meta;\n```\n\n```ts filename=\"DataTable.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { DataTable } from './data-table.component';\n\nconst meta = preview.meta({\n  component: DataTable,\n  parameters: {\n    // 👇 This component's accessibility tests will not fail\n    //    Instead, they display warnings in the Storybook UI\n    a11y: { test: 'todo' },\n  },\n});\n```\n\n```ts filename=\"DataTable.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport { Meta } from '@storybook/your-framework';\n\nimport { DataTable } from './DataTable';\n\nconst meta = {\n  component: DataTable,\n  parameters: {\n    // 👇 This component's accessibility tests will not fail\n    //    Instead, they display warnings in the Storybook UI\n    a11y: { test: 'todo' },\n  },\n} satisfies Meta<typeof DataTable>;\nexport default meta;\n```\n\n```js filename=\"DataTable.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { DataTable } from './DataTable';\n\nexport default {\n  component: DataTable,\n  parameters: {\n    // 👇 This component's accessibility tests will not fail\n    //    Instead, they display warnings in the Storybook UI\n    a11y: { test: 'todo' },\n  },\n};\n```\n\n```svelte filename=\"DataTable.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import DataTable from './DataTable.svelte';\n\n  const { Story } = defineMeta({\n    component: DataTable,\n    parameters: {\n      // 👇 This component's accessibility tests will not fail\n      //    Instead, they display warnings in the Storybook UI\n      a11y: { test: 'todo' },\n    },\n  });\n</script>\n```\n\n```ts filename=\"DataTable.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport type { Meta } from '@storybook/your-framework';\n\nimport DataTable from './DataTable.svelte';\n\nconst meta = {\n  component: DataTable,\n  parameters: {\n    // 👇 This component's accessibility tests will not fail\n    //    Instead, they display warnings in the Storybook UI\n    a11y: { test: 'todo' },\n  },\n} satisfies Meta<typeof DataTable>;\nexport default meta;\n```\n\n```svelte filename=\"DataTable.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import DataTable from './DataTable.svelte';\n\n  const { Story } = defineMeta({\n    component: DataTable,\n    parameters: {\n      // 👇 This component's accessibility tests will not fail\n      //    Instead, they display warnings in the Storybook UI\n      a11y: { test: 'todo' },\n    },\n  });\n</script>\n```\n\n```js filename=\"DataTable.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport DataTable from './DataTable.svelte';\n\nexport default {\n  component: DataTable,\n  parameters: {\n    // 👇 This component's accessibility tests will not fail\n    //    Instead, they display warnings in the Storybook UI\n    a11y: { test: 'todo' },\n  },\n};\n```\n\n```ts filename=\"DataTable.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta<DataTable> = {\n  component: 'demo-data-table',\n  parameters: {\n    // 👇 This component's accessibility tests will not fail\n    //    Instead, they display warnings in the Storybook UI\n    a11y: { test: 'todo' },\n  },\n};\nexport default meta;\n```\n\n```js filename=\"DataTable.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-data-table',\n  parameters: {\n    // 👇 This component's accessibility tests will not fail\n    //    Instead, they display warnings in the Storybook UI\n    a11y: { test: 'todo' },\n  },\n};\n```\n\n```js filename=\"DataTable.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-data-table',\n  parameters: {\n    // 👇 This component's accessibility tests will not fail\n    //    Instead, they display warnings in the Storybook UI\n    a11y: { test: 'todo' },\n  },\n});\n```\n\n```ts filename=\"DataTable.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-data-table',\n  parameters: {\n    // 👇 This component's accessibility tests will not fail\n    //    Instead, they display warnings in the Storybook UI\n    a11y: { test: 'todo' },\n  },\n});\n```\n\n```ts filename=\"DataTable.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { DataTable } from './DataTable';\n\nconst meta = preview.meta({\n  component: DataTable,\n  parameters: {\n    // 👇 This component's accessibility tests will not fail\n    //    Instead, they display warnings in the Storybook UI\n    a11y: { test: 'todo' },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"DataTable.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { DataTable } from './DataTable';\n\nconst meta = preview.meta({\n  component: DataTable,\n  parameters: {\n    // 👇 This component's accessibility tests will not fail\n    //    Instead, they display warnings in the Storybook UI\n    a11y: { test: 'todo' },\n  },\n});\n```\n\n```ts filename=\"DataTable.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport DataTable from './DataTable.vue';\n\nconst meta = preview.meta({\n  component: DataTable,\n  parameters: {\n    // 👇 This component's accessibility tests will not fail\n    //    Instead, they display warnings in the Storybook UI\n    a11y: { test: 'todo' },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"DataTable.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport DataTable from './DataTable.vue';\n\nconst meta = preview.meta({\n  component: DataTable,\n  parameters: {\n    // 👇 This component's accessibility tests will not fail\n    //    Instead, they display warnings in the Storybook UI\n    a11y: { test: 'todo' },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-a11y-register.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using (e.g., react-vite, vue3-vite, angular, etc.)\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // Other Storybook addons\n    '@storybook/addon-a11y', //👈 The a11y addon goes here\n  ],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using (e.g., react-vite, vue3-vite, angular, etc.)\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // Other Storybook addons\n    '@storybook/addon-a11y', //👈 The a11y addon goes here\n  ],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // Other Storybook addons\n    '@storybook/addon-a11y', //👈 The a11y addon goes here\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // Other Storybook addons\n    '@storybook/addon-a11y', //👈 The a11y addon goes here\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // Other Storybook addons\n    '@storybook/addon-a11y', //👈 The a11y addon goes here\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // Other Storybook addons\n    '@storybook/addon-a11y', //👈 The a11y addon goes here\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // Other Storybook addons\n    '@storybook/addon-a11y', //👈 The a11y addon goes here\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // Other Storybook addons\n    '@storybook/addon-a11y', //👈 The a11y addon goes here\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // Other Storybook addons\n    '@storybook/addon-a11y', //👈 The a11y addon goes here\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-actions-action-function.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { action } from 'storybook/actions';\n\nimport Button from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  args: {\n    // 👇 Create an action that appears when the onClick event is fired\n    onClick: action('on-click'),\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { action } from 'storybook/actions';\n\nimport preview from '../.storybook/preview';\n\nimport Button from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  args: {\n    // 👇 Create an action that appears when the onClick event is fired\n    onClick: action('on-click'),\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { action } from 'storybook/actions';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    args: {\n      // 👇 Create an action that appears when the onClick event is fired\n      onClick: action('on-click'),\n    },\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport { action } from 'storybook/actions';\n\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  args: {\n    // 👇 Create an action that appears when the onClick event is fired\n    onClick: action('on-click'),\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { action } from 'storybook/actions';\n\nimport Button from './Button';\n\nexport default {\n  component: Button,\n  args: {\n    // 👇 Create an action that appears when the onClick event is fired\n    onClick: action('on-click'),\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { action } from 'storybook/actions';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    args: {\n      // 👇 Create an action that appears when the onClick event is fired\n      onClick: action('on-click'),\n    },\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport { action } from 'storybook/actions';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  args: {\n    // 👇 Create an action that appears when the onClick event is fired\n    onClick: action('on-click'),\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { action } from 'storybook/actions';\n\nimport Button from './Button';\n\nconst meta = {\n  component: Button,\n  args: {\n    // 👇 Create an action that appears when the onClick event is fired\n    onClick: action('on-click'),\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { action } from 'storybook/actions';\n\nexport default {\n  component: 'demo-button',\n  args: {\n    // 👇 Create an action that appears when the onClick event is fired\n    onClick: action('on-click'),\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nimport { action } from 'storybook/actions';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  args: {\n    // 👇 Create an action that appears when the onClick event is fired\n    onClick: action('on-click'),\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { action } from 'storybook/actions';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  args: {\n    // 👇 Create an action that appears when the onClick event is fired\n    onClick: action('on-click'),\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { action } from 'storybook/actions';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  args: {\n    // 👇 Create an action that appears when the onClick event is fired\n    onClick: action('on-click'),\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { action } from 'storybook/actions';\n\nimport preview from '../.storybook/preview';\n\nimport Button from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  args: {\n    // 👇 Create an action that appears when the onClick event is fired\n    onClick: action('on-click'),\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { action } from 'storybook/actions';\n\nimport preview from '../.storybook/preview';\n\nimport Button from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  args: {\n    // 👇 Create an action that appears when the onClick event is fired\n    onClick: action('on-click'),\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { action } from 'storybook/actions';\n\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  args: {\n    // 👇 Create an action that appears when the onClick event is fired\n    onClick: action('on-click'),\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { action } from 'storybook/actions';\n\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  args: {\n    // 👇 Create an action that appears when the onClick event is fired\n    onClick: action('on-click'),\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-backgrounds-define-globals.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  globals: {\n    // 👇 Set background value for all component stories\n    backgrounds: { value: 'gray', grid: false },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const OnDark: Story = {\n  globals: {\n    // 👇 Override background value for this story\n    backgrounds: { value: 'dark' },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  globals: {\n    // 👇 Set background value for all component stories\n    backgrounds: { value: 'gray', grid: false },\n  },\n});\n\nexport const OnDark = meta.story({\n  globals: {\n    // 👇 Override background value for this story\n    backgrounds: { value: 'dark' },\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    globals: {\n      // 👇 Set background value for all component stories\n      backgrounds: { value: 'gray', grid: false },\n    },\n  });\n</script>\n\n<!-- 👇 Override background value for this story -->\n<Story\n  name=\"OnDark\"\n  globals={{\n    backgrounds: { value: \"dark\" },\n  }}\n/>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  globals: {\n    // 👇 Set background value for all component stories\n    backgrounds: { value: 'gray', grid: false },\n  },\n};\n\nexport const OnDark = {\n  globals: {\n    // 👇 Override background value for this story\n    backgrounds: { value: 'dark' },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    globals: {\n      // 👇 Set background value for all component stories\n      backgrounds: { value: 'gray', grid: false },\n    },\n  });\n</script>\n\n<!-- 👇 Override background value for this story-->\n<Story\n  name=\"OnDark\"\n  globals={{\n    backgrounds: { value: \"dark\" },\n  }}\n/>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  globals: {\n    // 👇 Set background value for all component stories\n    backgrounds: { value: 'gray', grid: false },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const OnDark: Story = {\n  globals: {\n    // 👇 Override background value for this story\n    backgrounds: { value: 'dark' },\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  globals: {\n    // 👇 Set background value for all component stories\n    backgrounds: { value: 'gray', grid: false },\n  },\n};\n\nexport const OnDark = {\n  globals: {\n    // 👇 Override background value for this story\n    backgrounds: { value: 'dark' },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the name of your framework (e.g., react-vite, vue3-vite, etc.)\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  globals: {\n    // 👇 Set background value for all component stories\n    backgrounds: { value: 'gray', grid: false },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const OnDark: Story = {\n  globals: {\n    // 👇 Override background value for this story\n    backgrounds: { value: 'dark' },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n  globals: {\n    // 👇 Set background value for all component stories\n    backgrounds: { value: 'gray', grid: false },\n  },\n};\n\nexport const OnDark = {\n  globals: {\n    // 👇 Override background value for this story\n    backgrounds: { value: 'dark' },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  globals: {\n    // 👇 Set background value for all component stories\n    backgrounds: { value: 'gray', grid: false },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const OnDark: Story = {\n  globals: {\n    // 👇 Override background value for this story\n    backgrounds: { value: 'dark' },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  globals: {\n    // 👇 Set background value for all component stories\n    backgrounds: { value: 'gray', grid: false },\n  },\n});\n\nexport const OnDark = meta.story({\n  globals: {\n    // 👇 Override background value for this story\n    backgrounds: { value: 'dark' },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  globals: {\n    // 👇 Set background value for all component stories\n    backgrounds: { value: 'gray', grid: false },\n  },\n});\n\nexport const OnDark = meta.story({\n  globals: {\n    // 👇 Override background value for this story\n    backgrounds: { value: 'dark' },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  globals: {\n    // 👇 Set background value for all component stories\n    backgrounds: { value: 'gray', grid: false },\n  },\n});\n\nexport const OnDark = meta.story({\n  globals: {\n    // 👇 Override background value for this story\n    backgrounds: { value: 'dark' },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  globals: {\n    // 👇 Set background value for all component stories\n    backgrounds: { value: 'gray', grid: false },\n  },\n});\n\nexport const OnDark = meta.story({\n  globals: {\n    // 👇 Override background value for this story\n    backgrounds: { value: 'dark' },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  globals: {\n    // 👇 Set background value for all component stories\n    backgrounds: { value: 'gray', grid: false },\n  },\n});\n\nexport const OnDark = meta.story({\n  globals: {\n    // 👇 Override background value for this story\n    backgrounds: { value: 'dark' },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  globals: {\n    // 👇 Set background value for all component stories\n    backgrounds: { value: 'gray', grid: false },\n  },\n});\n\nexport const OnDark = meta.story({\n  globals: {\n    // 👇 Override background value for this story\n    backgrounds: { value: 'dark' },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-backgrounds-disabled.md",
    "content": "```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Large = {\n  parameters: {\n    backgrounds: { disable: true },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Large: Story = {\n  parameters: {\n    backgrounds: { disable: true },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Large = meta.story({\n  parameters: {\n    backgrounds: { disable: true },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Large: Story = {\n  parameters: {\n    backgrounds: { disable: true },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"Large\"\n  parameters={{\n    backgrounds: { disable: true },\n  }}\n/>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n};\n\nexport const Large = {\n  parameters: {\n    backgrounds: { disable: true },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"Large\"\n  parameters={{\n    backgrounds: { disable: true },\n  }}\n/>\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Large = meta.story({\n  parameters: {\n    backgrounds: { disable: true },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Large = meta.story({\n  parameters: {\n    backgrounds: { disable: true },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Large = meta.story({\n  parameters: {\n    backgrounds: { disable: true },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Large = meta.story({\n  parameters: {\n    backgrounds: { disable: true },\n  },\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n};\n\nexport const Large = {\n  parameters: {\n    backgrounds: { disable: true },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Large: Story = {\n  parameters: {\n    backgrounds: { disable: true },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Large = meta.story({\n  parameters: {\n    backgrounds: { disable: true },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Large = meta.story({\n  parameters: {\n    backgrounds: { disable: true },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-backgrounds-grid.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\n// To apply a set of backgrounds to all stories of Button:\nconst meta: Meta<Button> = {\n  component: Button,\n  parameters: {\n    backgrounds: {\n      grid: {\n        cellSize: 20,\n        opacity: 0.5,\n        cellAmount: 5,\n        offsetX: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n        offsetY: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n      },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\n// To apply a set of backgrounds to all stories of Button:\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    backgrounds: {\n      grid: {\n        cellSize: 20,\n        opacity: 0.5,\n        cellAmount: 5,\n        offsetX: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n        offsetY: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n      },\n    },\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  // To apply a set of backgrounds to all stories of Button:\n  const { Story } = defineMeta({\n    component: Button,\n    parameters: {\n      backgrounds: {\n        grid: {\n          cellSize: 20,\n          opacity: 0.5,\n          cellAmount: 5,\n          offsetX: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n          offsetY: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n        },\n      },\n    },\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\n// To apply a grid to all stories of Button:\nexport default {\n  component: Button,\n  parameters: {\n    backgrounds: {\n      grid: {\n        cellSize: 20,\n        opacity: 0.5,\n        cellAmount: 5,\n        offsetX: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n        offsetY: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n      },\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  // To apply a set of backgrounds to all stories of Button:\n  const { Story } = defineMeta({\n    component: Button,\n    parameters: {\n      backgrounds: {\n        grid: {\n          cellSize: 20,\n          opacity: 0.5,\n          cellAmount: 5,\n          offsetX: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n          offsetY: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n        },\n      },\n    },\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\n// To apply a set of backgrounds to all stories of Button:\nconst meta = {\n  component: Button,\n  parameters: {\n    backgrounds: {\n      grid: {\n        cellSize: 20,\n        opacity: 0.5,\n        cellAmount: 5,\n        offsetX: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n        offsetY: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n      },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\n// To apply a grid to all stories of Button:\nexport default {\n  component: Button,\n  parameters: {\n    backgrounds: {\n      grid: {\n        cellSize: 20,\n        opacity: 0.5,\n        cellAmount: 5,\n        offsetX: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n        offsetY: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\n// To apply a set of backgrounds to all stories of Button:\nconst meta = {\n  component: Button,\n  parameters: {\n    backgrounds: {\n      grid: {\n        cellSize: 20,\n        opacity: 0.5,\n        cellAmount: 5,\n        offsetX: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n        offsetY: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n      },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\n// To apply a set of backgrounds to all stories of Button:\nexport default {\n  component: 'demo-button',\n  parameters: {\n    backgrounds: {\n      grid: {\n        cellSize: 20,\n        opacity: 0.5,\n        cellAmount: 5,\n        offsetX: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n        offsetY: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\n// To apply a set of backgrounds to all stories of Button:\nconst meta: Meta = {\n  component: 'demo-button',\n  parameters: {\n    backgrounds: {\n      grid: {\n        cellSize: 20,\n        opacity: 0.5,\n        cellAmount: 5,\n        offsetX: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n        offsetY: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n      },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n// To apply a set of backgrounds to all stories of Button:\nconst meta = preview.meta({\n  component: 'demo-button',\n  parameters: {\n    backgrounds: {\n      grid: {\n        cellSize: 20,\n        opacity: 0.5,\n        cellAmount: 5,\n        offsetX: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n        offsetY: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n// To apply a set of backgrounds to all stories of Button:\nconst meta = preview.meta({\n  component: 'demo-button',\n  parameters: {\n    backgrounds: {\n      grid: {\n        cellSize: 20,\n        opacity: 0.5,\n        cellAmount: 5,\n        offsetX: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n        offsetY: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\n// To apply a set of backgrounds to all stories of Button:\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    backgrounds: {\n      grid: {\n        cellSize: 20,\n        opacity: 0.5,\n        cellAmount: 5,\n        offsetX: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n        offsetY: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    backgrounds: {\n      grid: {\n        cellSize: 20,\n        opacity: 0.5,\n        cellAmount: 5,\n        offsetX: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n        offsetY: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\n// To apply a set of backgrounds to all stories of Button:\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    backgrounds: {\n      grid: {\n        cellSize: 20,\n        opacity: 0.5,\n        cellAmount: 5,\n        offsetX: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n        offsetY: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\n// To apply a set of backgrounds to all stories of Button:\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    backgrounds: {\n      grid: {\n        cellSize: 20,\n        opacity: 0.5,\n        cellAmount: 5,\n        offsetX: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n        offsetY: 16, // Default is 0 if story has 'fullscreen' layout, 16 if layout is 'padded'\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-backgrounds-options-in-meta.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Override the default `dark` option\n        dark: { name: 'Dark', value: '#000' },\n        // 👇 Add a new option\n        gray: { name: 'Gray', value: '#CCC' },\n      },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Override the default `dark` option\n        dark: { name: 'Dark', value: '#000' },\n        // 👇 Add a new option\n        gray: { name: 'Gray', value: '#CCC' },\n      },\n    },\n  },\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Override the default `dark` option\n        dark: { name: 'Dark', value: '#000' },\n        // 👇 Add a new option\n        gray: { name: 'Gray', value: '#CCC' },\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Override the default `dark` option\n        dark: { name: 'Dark', value: '#000' },\n        // 👇 Add a new option\n        gray: { name: 'Gray', value: '#CCC' },\n      },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Override the default `dark` option\n        dark: { name: 'Dark', value: '#000' },\n        // 👇 Add a new option\n        gray: { name: 'Gray', value: '#CCC' },\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Override the default `dark` option\n        dark: { name: 'Dark', value: '#000' },\n        // 👇 Add a new option\n        gray: { name: 'Gray', value: '#CCC' },\n      },\n    },\n  },\n});\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Override the default `dark` option\n        dark: { name: 'Dark', value: '#000' },\n        // 👇 Add a new option\n        gray: { name: 'Gray', value: '#CCC' },\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Override the default `dark` option\n        dark: { name: 'Dark', value: '#000' },\n        // 👇 Add a new option\n        gray: { name: 'Gray', value: '#CCC' },\n      },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.vue';\n\nexport default {\n  component: Button,\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Override the default `dark` option\n        dark: { name: 'Dark', value: '#000' },\n        // 👇 Add a new option\n        gray: { name: 'Gray', value: '#CCC' },\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/vue3-vite';\n\nimport Button from './Button.vue';\n\nconst meta = {\n  component: Button,\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Override the default `dark` option\n        dark: { name: 'Dark', value: '#000' },\n        // 👇 Add a new option\n        gray: { name: 'Gray', value: '#CCC' },\n      },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Override the default `dark` option\n        dark: { name: 'Dark', value: '#000' },\n        // 👇 Add a new option\n        gray: { name: 'Gray', value: '#CCC' },\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Override the default `dark` option\n        dark: { name: 'Dark', value: '#000' },\n        // 👇 Add a new option\n        gray: { name: 'Gray', value: '#CCC' },\n      },\n    },\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    parameters: {\n      backgrounds: {\n        options: {\n          // 👇 Override the default `dark` option\n          dark: { name: 'Dark', value: '#000' },\n          // 👇 Add a new option\n          gray: { name: 'Gray', value: '#CCC' },\n        },\n      },\n    },\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Override the default `dark` option\n        dark: { name: 'Dark', value: '#000' },\n        // 👇 Add a new option\n        gray: { name: 'Gray', value: '#CCC' },\n      },\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    parameters: {\n      backgrounds: {\n        options: {\n          // 👇 Override the default `dark` option\n          dark: { name: 'Dark', value: '#000' },\n          // 👇 Add a new option\n          gray: { name: 'Gray', value: '#CCC' },\n        },\n      },\n    },\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Override the default `dark` option\n        dark: { name: 'Dark', value: '#000' },\n        // 👇 Add a new option\n        gray: { name: 'Gray', value: '#CCC' },\n      },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Override the default `dark` option\n        dark: { name: 'Dark', value: '#000' },\n        // 👇 Add a new option\n        gray: { name: 'Gray', value: '#CCC' },\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Override the default `dark` option\n        dark: { name: 'Dark', value: '#000' },\n        // 👇 Add a new option\n        gray: { name: 'Gray', value: '#CCC' },\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-backgrounds-options-in-preview.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Default options\n        dark: { name: 'Dark', value: '#333' },\n        light: { name: 'Light', value: '#F7F9F2' },\n        // 👇 Add your own\n        maroon: { name: 'Maroon', value: '#400' },\n      },\n    },\n  },\n  initialGlobals: {\n    // 👇 Set the initial background color\n    backgrounds: { value: 'light' },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Default options\n        dark: { name: 'Dark', value: '#333' },\n        light: { name: 'Light', value: '#F7F9F2' },\n        // 👇 Add your own\n        maroon: { name: 'Maroon', value: '#400' },\n      },\n    },\n  },\n  initialGlobals: {\n    // 👇 Set the initial background color\n    backgrounds: { value: 'light' },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Default options\n        dark: { name: 'Dark', value: '#333' },\n        light: { name: 'Light', value: '#F7F9F2' },\n        // 👇 Add your own\n        maroon: { name: 'Maroon', value: '#400' },\n      },\n    },\n  },\n  initialGlobals: {\n    // 👇 Set the initial background color\n    backgrounds: { value: 'light' },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Default options\n        dark: { name: 'Dark', value: '#333' },\n        light: { name: 'Light', value: '#F7F9F2' },\n        // 👇 Add your own\n        maroon: { name: 'Maroon', value: '#400' },\n      },\n    },\n  },\n  initialGlobals: {\n    // 👇 Set the initial background color\n    backgrounds: { value: 'light' },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Default options\n        dark: { name: 'Dark', value: '#333' },\n        light: { name: 'Light', value: '#F7F9F2' },\n        // 👇 Add your own\n        maroon: { name: 'Maroon', value: '#400' },\n      },\n    },\n  },\n  initialGlobals: {\n    // 👇 Set the initial background color\n    backgrounds: { value: 'light' },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Default options\n        dark: { name: 'Dark', value: '#333' },\n        light: { name: 'Light', value: '#F7F9F2' },\n        // 👇 Add your own\n        maroon: { name: 'Maroon', value: '#400' },\n      },\n    },\n  },\n  initialGlobals: {\n    // 👇 Set the initial background color\n    backgrounds: { value: 'light' },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Default options\n        dark: { name: 'Dark', value: '#333' },\n        light: { name: 'Light', value: '#F7F9F2' },\n        // 👇 Add your own\n        maroon: { name: 'Maroon', value: '#400' },\n      },\n    },\n  },\n  initialGlobals: {\n    // 👇 Set the initial background color\n    backgrounds: { value: 'light' },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Default options\n        dark: { name: 'Dark', value: '#333' },\n        light: { name: 'Light', value: '#F7F9F2' },\n        // 👇 Add your own\n        maroon: { name: 'Maroon', value: '#400' },\n      },\n    },\n  },\n  initialGlobals: {\n    // 👇 Set the initial background color\n    backgrounds: { value: 'light' },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      options: {\n        // 👇 Default options\n        dark: { name: 'Dark', value: '#333' },\n        light: { name: 'Light', value: '#F7F9F2' },\n        // 👇 Add your own\n        maroon: { name: 'Maroon', value: '#400' },\n      },\n    },\n  },\n  initialGlobals: {\n    // 👇 Set the initial background color\n    backgrounds: { value: 'light' },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-consume-and-update-globaltype.md",
    "content": "```js filename=\"your-addon-register-file.js\" renderer=\"common\" language=\"js\"\nimport React, { useCallback } from 'react';\nimport { OutlineIcon } from '@storybook/icons';\nimport { useGlobals } from 'storybook/manager-api';\nimport { addons } from 'storybook/preview-api';\nimport { ToggleButton } from 'storybook/internal/components';\nimport { FORCE_RE_RENDER } from 'storybook/internal/core-events';\n\nconst ExampleToolbar = () => {\n  const [globals, updateGlobals] = useGlobals();\n\n  const isActive = globals['my-param-key'] || false;\n\n  // Function that will update the global value and trigger a UI refresh.\n  const refreshAndUpdateGlobal = () => {\n    // Updates Storybook global value\n    updateGlobals({\n      ['my-param-key']: !isActive,\n    });\n    // Invokes Storybook's addon API method (with the FORCE_RE_RENDER) event to trigger a UI refresh\n    addons.getChannel().emit(FORCE_RE_RENDER);\n  };\n\n  const toggleOutline = useCallback(() => refreshAndUpdateGlobal(), [isActive]);\n\n  return (\n    <ToggleButton\n      key=\"Example\"\n      padding=\"small\"\n      variant=\"ghost\"\n      pressed={isActive}\n      onClick={toggleOutline}\n      ariaLabel=\"Addon feature\"\n      tooltip=\"Toggle addon feature\"\n    >\n      <OutlineIcon />\n    </ToggleButton>\n  );\n};\n```\n"
  },
  {
    "path": "docs/_snippets/addon-consume-globaltype.md",
    "content": "```js filename=\"your-addon-register-file.js\" renderer=\"common\" language=\"js\"\nimport React from 'react';\n\nimport { useGlobals } from 'storybook/manager-api';\n\nimport {\n  AddonPanel,\n  Placeholder,\n  Separator,\n  Source,\n  Spaced,\n  Title,\n} from 'storybook/internal/components';\n\nimport { MyThemes } from '../my-theme-folder/my-theme-file';\n\n// Function to obtain the intended theme\nconst getTheme = (themeName) => {\n  return MyThemes[themeName];\n};\n\nconst ThemePanel = (props) => {\n  const [{ theme: themeName }] = useGlobals();\n\n  const selectedTheme = getTheme(themeName);\n\n  return (\n    <AddonPanel {...props}>\n      {selectedTheme ? (\n        <Spaced row={3} outer={1}>\n          <Title>{selectedTheme.name}</Title>\n          <p>The full theme object</p>\n          <Source\n            code={JSON.stringify(selectedTheme, null, 2)}\n            language=\"js\"\n            copyable\n            padded\n            showLineNumbers\n          />\n        </Spaced>\n      ) : (\n        <Placeholder>No theme selected</Placeholder>\n      )}\n    </AddonPanel>\n  );\n};\n```\n"
  },
  {
    "path": "docs/_snippets/addon-docs-options.md",
    "content": "```ts filename=\".storybook/main.ts\" renderer=\"common\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        csfPluginOptions: null,\n        mdxPluginOptions: {\n          mdxCompileOptions: {\n            remarkPlugins: [],\n          },\n        },\n      },\n    },\n  ],\n};\n\nexport default config;\n```\n\n```js filename=\".storybook/main.js\" renderer=\"common\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        csfPluginOptions: null,\n        mdxPluginOptions: {\n          mdxCompileOptions: {\n            remarkPlugins: [],\n          },\n        },\n      },\n    },\n  ],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        csfPluginOptions: null,\n        mdxPluginOptions: {\n          mdxCompileOptions: {\n            remarkPlugins: [],\n          },\n        },\n      },\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        csfPluginOptions: null,\n        mdxPluginOptions: {\n          mdxCompileOptions: {\n            remarkPlugins: [],\n          },\n        },\n      },\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        csfPluginOptions: null,\n        mdxPluginOptions: {\n          mdxCompileOptions: {\n            remarkPlugins: [],\n          },\n        },\n      },\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        csfPluginOptions: null,\n        mdxPluginOptions: {\n          mdxCompileOptions: {\n            remarkPlugins: [],\n          },\n        },\n      },\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        csfPluginOptions: null,\n        mdxPluginOptions: {\n          mdxCompileOptions: {\n            remarkPlugins: [],\n          },\n        },\n      },\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        csfPluginOptions: null,\n        mdxPluginOptions: {\n          mdxCompileOptions: {\n            remarkPlugins: [],\n          },\n        },\n      },\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        csfPluginOptions: null,\n        mdxPluginOptions: {\n          mdxCompileOptions: {\n            remarkPlugins: [],\n          },\n        },\n      },\n    },\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-mcp-add.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook add @storybook/addon-mcp\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm exec storybook add @storybook/addon-mcp\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn exec storybook add @storybook/addon-mcp\n```\n"
  },
  {
    "path": "docs/_snippets/addon-mcp-options.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using (e.g., react-vite, vue3-vite, angular, etc.)\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // ... your existing addons\n    {\n      name: '@storybook/addon-mcp',\n      options: {\n        toolsets: {\n          dev: false,\n        },\n      },\n    },\n  ],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using (e.g., react-vite, vue3-vite, angular, etc.)\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // ... your existing addons\n    {\n      name: '@storybook/addon-mcp',\n      options: {\n        toolsets: {\n          dev: false,\n        },\n      },\n    },\n  ],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // ... your existing addons\n    {\n      name: '@storybook/addon-mcp',\n      options: {\n        toolsets: {\n          dev: false,\n        },\n      },\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // ... your existing addons\n    {\n      name: '@storybook/addon-mcp',\n      options: {\n        toolsets: {\n          dev: false,\n        },\n      },\n    },\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-test-install.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook add @storybook/addon-vitest\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm exec storybook add @storybook/addon-vitest\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn exec storybook add @storybook/addon-vitest\n```\n"
  },
  {
    "path": "docs/_snippets/addon-viewport-add-viewport-in-preview.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MINIMAL_VIEWPORTS } from 'storybook/viewport';\n\nconst kindleViewports = {\n  kindleFire2: {\n    name: 'Kindle Fire 2',\n    styles: {\n      width: '600px',\n      height: '963px',\n    },\n  },\n  kindleFireHD: {\n    name: 'Kindle Fire HD',\n    styles: {\n      width: '533px',\n      height: '801px',\n    },\n  },\n};\n\nexport default {\n  parameters: {\n    viewport: {\n      options: {\n        ...MINIMAL_VIEWPORTS,\n        ...kindleViewports,\n      },\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nimport { MINIMAL_VIEWPORTS } from 'storybook/viewport';\n\nconst kindleViewports = {\n  kindleFire2: {\n    name: 'Kindle Fire 2',\n    styles: {\n      width: '600px',\n      height: '963px',\n    },\n  },\n  kindleFireHD: {\n    name: 'Kindle Fire HD',\n    styles: {\n      width: '533px',\n      height: '801px',\n    },\n  },\n};\n\nconst preview: Preview = {\n  parameters: {\n    viewport: {\n      options: {\n        ...MINIMAL_VIEWPORTS,\n        ...kindleViewports,\n      },\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { MINIMAL_VIEWPORTS } from 'storybook/viewport';\n\nconst kindleViewports = {\n  kindleFire2: {\n    name: 'Kindle Fire 2',\n    styles: {\n      width: '600px',\n      height: '963px',\n    },\n  },\n  kindleFireHD: {\n    name: 'Kindle Fire HD',\n    styles: {\n      width: '533px',\n      height: '801px',\n    },\n  },\n};\n\nexport default definePreview({\n  parameters: {\n    viewport: {\n      options: {\n        ...MINIMAL_VIEWPORTS,\n        ...kindleViewports,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { MINIMAL_VIEWPORTS } from 'storybook/viewport';\n\nconst kindleViewports = {\n  kindleFire2: {\n    name: 'Kindle Fire 2',\n    styles: {\n      width: '600px',\n      height: '963px',\n    },\n  },\n  kindleFireHD: {\n    name: 'Kindle Fire HD',\n    styles: {\n      width: '533px',\n      height: '801px',\n    },\n  },\n};\n\nexport default definePreview({\n  parameters: {\n    viewport: {\n      options: {\n        ...MINIMAL_VIEWPORTS,\n        ...kindleViewports,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport { MINIMAL_VIEWPORTS } from 'storybook/viewport';\n\nconst kindleViewports = {\n  kindleFire2: {\n    name: 'Kindle Fire 2',\n    styles: {\n      width: '600px',\n      height: '963px',\n    },\n  },\n  kindleFireHD: {\n    name: 'Kindle Fire HD',\n    styles: {\n      width: '533px',\n      height: '801px',\n    },\n  },\n};\n\nexport default definePreview({\n  parameters: {\n    viewport: {\n      options: {\n        ...MINIMAL_VIEWPORTS,\n        ...kindleViewports,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport { MINIMAL_VIEWPORTS } from 'storybook/viewport';\n\nconst kindleViewports = {\n  kindleFire2: {\n    name: 'Kindle Fire 2',\n    styles: {\n      width: '600px',\n      height: '963px',\n    },\n  },\n  kindleFireHD: {\n    name: 'Kindle Fire HD',\n    styles: {\n      width: '533px',\n      height: '801px',\n    },\n  },\n};\n\nexport default definePreview({\n  parameters: {\n    viewport: {\n      options: {\n        ...MINIMAL_VIEWPORTS,\n        ...kindleViewports,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nimport { MINIMAL_VIEWPORTS } from 'storybook/viewport';\n\nconst kindleViewports = {\n  kindleFire2: {\n    name: 'Kindle Fire 2',\n    styles: {\n      width: '600px',\n      height: '963px',\n    },\n  },\n  kindleFireHD: {\n    name: 'Kindle Fire HD',\n    styles: {\n      width: '533px',\n      height: '801px',\n    },\n  },\n};\n\nexport default definePreview({\n  parameters: {\n    viewport: {\n      options: {\n        ...MINIMAL_VIEWPORTS,\n        ...kindleViewports,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { MINIMAL_VIEWPORTS } from 'storybook/viewport';\n\nconst kindleViewports = {\n  kindleFire2: {\n    name: 'Kindle Fire 2',\n    styles: {\n      width: '600px',\n      height: '963px',\n    },\n  },\n  kindleFireHD: {\n    name: 'Kindle Fire HD',\n    styles: {\n      width: '533px',\n      height: '801px',\n    },\n  },\n};\n\nexport default definePreview({\n  parameters: {\n    viewport: {\n      options: {\n        ...MINIMAL_VIEWPORTS,\n        ...kindleViewports,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { MINIMAL_VIEWPORTS } from 'storybook/viewport';\n\nconst kindleViewports = {\n  kindleFire2: {\n    name: 'Kindle Fire 2',\n    styles: {\n      width: '600px',\n      height: '963px',\n    },\n  },\n  kindleFireHD: {\n    name: 'Kindle Fire HD',\n    styles: {\n      width: '533px',\n      height: '801px',\n    },\n  },\n};\n\nexport default definePreview({\n  parameters: {\n    viewport: {\n      options: {\n        ...MINIMAL_VIEWPORTS,\n        ...kindleViewports,\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-viewport-configuration-in-meta.md",
    "content": "```js filename=\"MyComponent.stories.js|jsx\" renderer=\"solid\" language=\"js\" tabTitle=\"Without globals API\"\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n  parameters: {\n    viewport: {\n      //👇 Set available viewports for every story in the file\n      viewports: INITIAL_VIEWPORTS,\n    },\n  },\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"solid\" language=\"ts\" tabTitle=\"Without globals API\"\nimport type { Meta } from 'storybook-solidjs-vite';\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n  parameters: {\n    viewport: {\n      //👇 Set available viewports for every story in the file\n      viewports: INITIAL_VIEWPORTS,\n    },\n  },\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n  parameters: {\n    viewport: {\n      //👇 Set available viewports for every story in the file\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  parameters: {\n    viewport: {\n      //👇 Set available viewports for every story in the file\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n  parameters: {\n    viewport: {\n      //👇 Set available viewports for every story in the file\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n  parameters: {\n    viewport: {\n      //👇 Set available viewports for every story in the file\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n    parameters: {\n      viewport: {\n        //👇 Set available viewports for every story in the file\n        options: INITIAL_VIEWPORTS,\n      },\n    },\n  });\n</script>\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nimport MyComponent from './MyComponent.svelte';\n\nexport default {\n  component: MyComponent,\n  parameters: {\n    viewport: {\n      //👇 Set available viewports for every story in the file\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n    parameters: {\n      viewport: {\n        //👇 Set available viewports for every story in the file\n        options: INITIAL_VIEWPORTS,\n      },\n    },\n  });\n</script>\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nimport MyComponent from './MyComponent.svelte';\n\nconst meta = {\n  component: MyComponent,\n  parameters: {\n    viewport: {\n      //👇 Set available viewports for every story in the file\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nimport MyComponent from './MyComponent.vue';\n\nexport default {\n  component: MyComponent,\n  parameters: {\n    viewport: {\n      //👇 Set available viewports for every story in the file\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/vue3-vite';\n\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = {\n  component: MyComponent,\n  parameters: {\n    viewport: {\n      //👇 Set available viewports for every story in the file\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  parameters: {\n    viewport: {\n      //👇 Set available viewports for every story in the file\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  parameters: {\n    viewport: {\n      //👇 Set available viewports for every story in the file\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nexport default {\n  component: 'my-component',\n  parameters: {\n    viewport: {\n      //👇 Set available viewports for every story in the file\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nconst meta: Meta = {\n  component: 'my-component',\n  parameters: {\n    viewport: {\n      //👇 Set available viewports for every story in the file\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n  parameters: {\n    viewport: {\n      //👇 Set available viewports for every story in the file\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n  parameters: {\n    viewport: {\n      //👇 Set available viewports for every story in the file\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  parameters: {\n    viewport: {\n      //👇 Set available viewports for every story in the file\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  parameters: {\n    viewport: {\n      //👇 Set available viewports for every story in the file\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-viewport-define-globals.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  globals: {\n    // 👇 Set viewport for all component stories\n    viewport: { value: 'tablet', isRotated: false },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const OnPhone: Story = {\n  globals: {\n    // 👇 Override viewport for this story\n    viewport: { value: 'mobile1', isRotated: false },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  globals: {\n    // 👇 Set viewport for all component stories\n    viewport: { value: 'tablet', isRotated: false },\n  },\n});\n\nexport const OnPhone = meta.story({\n  globals: {\n    // 👇 Override viewport for this story\n    viewport: { value: 'mobile1', isRotated: false },\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    globals: {\n      // 👇 Set viewport for all component stories\n      viewport: { value: \"tablet\", isRotated: false },\n    },\n  });\n</script>\n\n<Story\n  name=\"OnPhone\"\n  globals={{\n    viewport: { value: \"mobile1\", isRotated: false },\n  }}\n/>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  globals: {\n    // 👇 Set viewport for all component stories\n    viewport: { value: 'tablet', isRotated: false },\n  },\n};\n\nexport const OnPhone = {\n  globals: {\n    // 👇 Override viewport for this story\n    viewport: { value: 'mobile1', isRotated: false },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    globals: {\n      // 👇 Set viewport for all component stories\n      viewport: { value: \"tablet\", isRotated: false },\n    },\n  });\n</script>\n\n<Story\n  name=\"OnPhone\"\n  globals={{\n    viewport: { value: \"mobile1\", isRotated: false },\n  }}\n/>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  globals: {\n    // 👇 Set viewport for all component stories\n    viewport: { value: 'tablet', isRotated: false },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const OnPhone: Story = {\n  globals: {\n    // 👇 Override viewport for this story\n    viewport: { value: 'mobile1', isRotated: false },\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  globals: {\n    // 👇 Set viewport for all component stories\n    viewport: { value: 'tablet', isRotated: false },\n  },\n};\n\nexport const OnPhone = {\n  globals: {\n    // 👇 Override viewport for this story\n    viewport: { value: 'mobile1', isRotated: false },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  globals: {\n    // 👇 Set viewport for all component stories\n    viewport: { value: 'tablet', isRotated: false },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const OnPhone: Story = {\n  globals: {\n    // 👇 Override viewport for this story\n    viewport: { value: 'mobile1', isRotated: false },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n  globals: {\n    // 👇 Set viewport for all component stories\n    viewport: { value: 'tablet', isRotated: false },\n  },\n};\n\nexport const OnPhone = {\n  globals: {\n    // 👇 Override viewport for this story\n    viewport: { value: 'mobile1', isRotated: false },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  globals: {\n    // 👇 Set viewport for all component stories\n    viewport: { value: 'tablet', isRotated: false },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const OnPhone: Story = {\n  globals: {\n    // 👇 Override viewport for this story\n    viewport: { value: 'mobile1', isRotated: false },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  globals: {\n    // 👇 Set viewport for all component stories\n    viewport: { value: 'tablet', isRotated: false },\n  },\n});\n\nexport const OnPhone = meta.story({\n  globals: {\n    // 👇 Override viewport for this story\n    viewport: { value: 'mobile1', isRotated: false },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  globals: {\n    // 👇 Set viewport for all component stories\n    viewport: { value: 'tablet', isRotated: false },\n  },\n});\n\nexport const OnPhone = meta.story({\n  globals: {\n    // 👇 Override viewport for this story\n    viewport: { value: 'mobile1', isRotated: false },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  globals: {\n    // 👇 Set viewport for all component stories\n    viewport: { value: 'tablet', isRotated: false },\n  },\n});\n\nexport const OnPhone = meta.story({\n  globals: {\n    // 👇 Override viewport for this story\n    viewport: { value: 'mobile1', isRotated: false },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  globals: {\n    // 👇 Set viewport for all component stories\n    viewport: { value: 'tablet', isRotated: false },\n  },\n});\n\nexport const OnPhone = meta.story({\n  globals: {\n    // 👇 Override viewport for this story\n    viewport: { value: 'mobile1', isRotated: false },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  globals: {\n    // 👇 Set viewport for all component stories\n    viewport: { value: 'tablet', isRotated: false },\n  },\n});\n\nexport const OnPhone = meta.story({\n  globals: {\n    // 👇 Override viewport for this story\n    viewport: { value: 'mobile1', isRotated: false },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  globals: {\n    // 👇 Set viewport for all component stories\n    viewport: { value: 'tablet', isRotated: false },\n  },\n});\n\nexport const OnPhone = meta.story({\n  globals: {\n    // 👇 Override viewport for this story\n    viewport: { value: 'mobile1', isRotated: false },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/addon-viewport-options-in-preview.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nexport default {\n  parameters: {\n    viewport: {\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n  initialGlobals: {\n    viewport: { value: 'ipad', isRotated: false },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nconst preview: Preview = {\n  parameters: {\n    viewport: {\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n  initialGlobals: {\n    viewport: { value: 'ipad', isRotated: false },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nexport default definePreview({\n  parameters: {\n    viewport: {\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n  initialGlobals: {\n    viewport: { value: 'ipad', isRotated: false },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nexport default definePreview({\n  parameters: {\n    viewport: {\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n  initialGlobals: {\n    viewport: { value: 'ipad', isRotated: false },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nexport default definePreview({\n  parameters: {\n    viewport: {\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n  initialGlobals: {\n    viewport: { value: 'ipad', isRotated: false },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nexport default definePreview({\n  parameters: {\n    viewport: {\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n  initialGlobals: {\n    viewport: { value: 'ipad', isRotated: false },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nexport default definePreview({\n  parameters: {\n    viewport: {\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n  initialGlobals: {\n    viewport: { value: 'ipad', isRotated: false },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nexport default definePreview({\n  parameters: {\n    viewport: {\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n  initialGlobals: {\n    viewport: { value: 'ipad', isRotated: false },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { INITIAL_VIEWPORTS } from 'storybook/viewport';\n\nexport default definePreview({\n  parameters: {\n    viewport: {\n      options: INITIAL_VIEWPORTS,\n    },\n  },\n  initialGlobals: {\n    viewport: { value: 'ipad', isRotated: false },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/after-each-in-meta.md",
    "content": "```ts filename=\"Page.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Page } from './page.component';\n\nconst meta: Meta<Page> = {\n  component: Page,\n  // 👇 Runs after each story in this file\n  async afterEach(context) {\n    console.log(`✅ Tested ${context.name} story`);\n  },\n};\nexport default meta;\n\ntype Story = StoryObj<Page>;\n\nexport const Basic: Story = {\n  async play({ canvas }) {\n    // ...\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Page } from './page.component';\n\nconst meta = preview.meta({\n  component: Page,\n  // 👇 Runs after each story in this file\n  async afterEach(context) {\n    console.log(`✅ Tested ${context.name} story`);\n  },\n});\n\nexport const Basic = meta.story({\n  async play({ canvas }) {\n    // ...\n  },\n});\n```\n\n```svelte filename=\"Page.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Page from './Page.svelte';\n\n  const { Story } = defineMeta({\n    component: Page,\n    // 👇 Runs after each story in this file\n    async afterEach(context) {\n      console.log(`✅ Tested ${context.name} story`);\n    },\n  });\n</script>\n\n<Story name=\"Default\" play={async ({ canvas }) => {\n  // ...\n  }}\n/>\n```\n\n```js filename=\"Page.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Page from './Page.svelte';\n\nexport default {\n  component: Page,\n  // 👇 Runs after each story in this file\n  async afterEach(context) {\n    console.log(`✅ Tested ${context.name} story`);\n  },\n};\n\nexport const Basic = {\n  async play({ canvas }) {\n    // ...\n  },\n};\n```\n\n```js filename=\"Page.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Page } from './Page';\n\nexport default {\n  component: Page,\n  // 👇 Runs after each story in this file\n  async afterEach(context) {\n    console.log(`✅ Tested ${context.name} story`);\n  },\n};\n\nexport const Basic = {\n  async play({ canvas }) {\n    // ...\n  },\n};\n```\n\n```svelte filename=\"Page.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Page from './Page.svelte';\n\n  const { Story } = defineMeta({\n    component: Page,\n    // 👇 Runs after each story in this file\n    async afterEach(context) {\n      console.log(`✅ Tested ${context.name} story`);\n    },\n  });\n</script>\n\n<Story name=\"Default\" play={async ({ canvas }) => {\n  // ...\n  }}\n/>\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Page from './Page.svelte';\n\nconst meta = {\n  component: Page,\n  // 👇 Runs after each story in this file\n  async afterEach(context) {\n    console.log(`✅ Tested ${context.name} story`);\n  },\n} satisfies Meta<typeof Page>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  async play({ canvas }) {\n    // ...\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Page } from './Page';\n\nconst meta = {\n  component: Page,\n  // 👇 Runs after each story in this file\n  async afterEach(context) {\n    console.log(`✅ Tested ${context.name} story`);\n  },\n} satisfies Meta<typeof Page>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  async play({ canvas }) {\n    // ...\n  },\n};\n```\n\n```js filename=\"Page.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'my-page',\n  // 👇 Runs after each story in this file\n  async afterEach(context) {\n    console.log(`✅ Tested ${context.name} story`);\n  },\n};\n\nexport const Basic = {\n  async play({ canvas }) {\n    // ...\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'my-page',\n  // 👇 Runs after each story in this file\n  async afterEach(context) {\n    console.log(`✅ Tested ${context.name} story`);\n  },\n};\nexport default meta;\n\ntype Story = StoryObj;\n\nexport const Basic: Story = {\n  async play({ canvas }) {\n    // ...\n  },\n};\n```\n\n```js filename=\"Page.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-page',\n  // 👇 Runs after each story in this file\n  async afterEach(context) {\n    console.log(`✅ Tested ${context.name} story`);\n  },\n});\n\nexport const Basic = meta.story({\n  async play({ canvas }) {\n    // ...\n  },\n});\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-page',\n  // 👇 Runs after each story in this file\n  async afterEach(context) {\n    console.log(`✅ Tested ${context.name} story`);\n  },\n});\n\nexport const Basic = meta.story({\n  async play({ canvas }) {\n    // ...\n  },\n});\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Page } from './Page';\n\nconst meta = preview.meta({\n  component: Page,\n  // 👇 Runs after each story in this file\n  async afterEach(context) {\n    console.log(`✅ Tested ${context.name} story`);\n  },\n});\n\nexport const Basic = meta.story({\n  async play({ canvas }) {\n    // ...\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Page.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Page } from './Page';\n\nconst meta = preview.meta({\n  component: Page,\n  // 👇 Runs after each story in this file\n  async afterEach(context) {\n    console.log(`✅ Tested ${context.name} story`);\n  },\n});\n\nexport const Basic = meta.story({\n  async play({ canvas }) {\n    // ...\n  },\n});\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Page from './Page.vue';\n\nconst meta = preview.meta({\n  component: Page,\n  // 👇 Runs after each story in this file\n  async afterEach(context) {\n    console.log(`✅ Tested ${context.name} story`);\n  },\n});\n\nexport const Basic = meta.story({\n  async play({ canvas }) {\n    // ...\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Page.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Page from './Page.vue';\n\nconst meta = preview.meta({\n  component: Page,\n  // 👇 Runs after each story in this file\n  async afterEach(context) {\n    console.log(`✅ Tested ${context.name} story`);\n  },\n});\n\nexport const Basic = meta.story({\n  async play({ canvas }) {\n    // ...\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/angular-add-compodoc.md",
    "content": "```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Preview } from '@storybook/angular';\n\n// 👇 Add these\nimport { setCompodocJson } from '@storybook/addon-docs/angular';\nimport docJson from '../documentation.json';\nsetCompodocJson(docJson);\n\nconst preview: Preview = {\n  // ...\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\n// 👇 Add these\nimport { setCompodocJson } from '@storybook/addon-docs/angular';\nimport docJson from '../documentation.json';\nsetCompodocJson(docJson);\n\nconst preview = definePreview({\n  // ...\n});\n\nexport default preview;\n```\n"
  },
  {
    "path": "docs/_snippets/angular-add-framework.md",
    "content": "```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { StorybookConfig } from '@storybook/angular';\n\nconst config: StorybookConfig = {\n  // ...\n  framework: '@storybook/angular', // 👈 Add this\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  // ...\n  framework: '@storybook/angular', // 👈 Add this\n});\n```\n"
  },
  {
    "path": "docs/_snippets/angular-application-providers-in-meta-and-story.md",
    "content": "```ts filename=\"ChipsModule.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, type StoryObj, applicationConfig } from '@storybook/angular';\n\nimport { BrowserAnimationsModule, provideAnimations } from '@angular/platform-browser/animations';\nimport { importProvidersFrom } from '@angular/core';\n\nimport { ChipsModule } from './angular-src/chips.module';\n\nconst meta: Meta<ChipsModule> = {\n  component: ChipsModule,\n  decorators: [\n    // Apply application config to all stories\n    applicationConfig({\n      // List of providers and environment providers that should be available to the root component and all its children.\n      providers: [\n        ...\n        // Import application-wide providers from a module\n        importProvidersFrom(BrowserAnimationsModule)\n        // Or use provide-style functions if available instead, e.g.\n        provideAnimations()\n      ],\n    }),\n  ],\n};\n\nexport default meta;\ntype Story = StoryObj<ChipsModule>;\n\nexport const WithCustomApplicationProvider: Story = {\n  render: () => ({\n    // Apply application config to a specific story\n    applicationConfig: {\n      // The providers will be merged with the ones defined in the applicationConfig decorator's providers array of the global meta object\n      providers: [...],\n    }\n  })\n}\n```\n\n```ts filename=\"ChipsModule.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { applicationConfig } from '@storybook/angular';\n\nimport { BrowserAnimationsModule, provideAnimations } from '@angular/platform-browser/animations';\nimport { importProvidersFrom } from '@angular/core';\n\nimport preview from '../.storybook/preview';\n\nimport { ChipsModule } from './angular-src/chips.module';\n\nconst meta = preview.type<{ args: ChipsModule }>().meta({\n  component: ChipsModule,\n  decorators: [\n    // Apply application config to all stories\n    applicationConfig({\n      // List of providers and environment providers that should be available to the root component and all its children.\n      providers: [\n        ...\n        // Import application-wide providers from a module\n        importProvidersFrom(BrowserAnimationsModule)\n        // Or use provide-style functions if available instead, e.g.\n        provideAnimations()\n      ],\n    }),\n  ],\n});\n\nexport const WithCustomApplicationProvider = meta.story({\n  render: () => ({\n    // Apply application config to a specific story\n    applicationConfig: {\n      // The providers will be merged with the ones defined in the applicationConfig decorator's providers array of the global meta object\n      providers: [...],\n    }\n  })\n});\n```\n"
  },
  {
    "path": "docs/_snippets/angular-builder-production.md",
    "content": "```shell renderer=\"angular\" tabTitle=\"with-builder\"\n# Builds Storybook with Angular's custom builder\n# See https://storybook.js.org/docs/get-started/frameworks/angular#how-do-i-migrate-to-an-angular-storybook-builder\n# to learn how to create the custom builder\nng run my-project:build-storybook\n```\n\n```json renderer=\"angular\" language=\"js\" filename=\"package.json\" tabTitle=\"script-for-builder\"\n{\n  \"scripts\": {\n    \"build-storybook\": \"ng run my-project:build-storybook\"\n  }\n}\n```\n"
  },
  {
    "path": "docs/_snippets/angular-framework-options-enable-ivy-false.md",
    "content": "```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { StorybookConfig } from '@storybook/angular';\n\nconst config: StorybookConfig = {\n  stories: [\n    /* ... */\n  ],\n  addons: [\n    /* ... */\n  ],\n  framework: {\n    name: '@storybook/angular',\n    options: {\n      enableIvy: false,\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nconst config = defineMain({\n  stories: [\n    /* ... */\n  ],\n  addons: [\n    /* ... */\n  ],\n  framework: {\n    name: '@storybook/angular',\n    options: {\n      enableIvy: false,\n    },\n  },\n});\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/angular-framework-options-enable-ngcc-false.md",
    "content": "```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { StorybookConfig } from '@storybook/angular';\n\nconst config: StorybookConfig = {\n  stories: [\n    /* ... */\n  ],\n  addons: [\n    /* ... */\n  ],\n  framework: {\n    name: '@storybook/angular',\n    options: {\n      enableNgcc: false,\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nconst config = defineMain({\n  stories: [\n    /* ... */\n  ],\n  addons: [\n    /* ... */\n  ],\n  framework: {\n    name: '@storybook/angular',\n    options: {\n      enableNgcc: false,\n    },\n  },\n});\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/angular-framework-options.md",
    "content": "```js filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { StorybookConfig } from '@storybook/angular';\n\nconst config: StorybookConfig = {\n  framework: {\n    name: '@storybook/angular',\n    options: {\n      // ...\n    },\n  },\n};\n\nexport default config;\n```\n\n```js filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nconst config = defineMain({\n  framework: {\n    name: '@storybook/angular',\n    options: {\n      // ...\n    },\n  },\n});\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/angular-install.md",
    "content": "```shell renderer=\"angular\" language=\"js\" packageManager=\"npm\"\nnpm install --save-dev @storybook/angular\n```\n\n```shell renderer=\"angular\" language=\"js\" packageManager=\"pnpm\"\npnpm add --save-dev @storybook/angular\n```\n\n```shell renderer=\"angular\" language=\"js\" packageManager=\"yarn\"\nyarn add --dev @storybook/angular\n```\n"
  },
  {
    "path": "docs/_snippets/angular-project-compodoc-config.md",
    "content": "```jsonc filename=\"angular.json\" renderer=\"angular\" language=\"json\"\n{\n  \"$schema\": \"./node_modules/@angular/cli/lib/config/schema.json\",\n  \"version\": 1,\n  \"newProjectRoot\": \"projects\",\n  \"projects\": {\n    \"your-project\": {\n      \"projectType\": \"application\",\n      \"schematics\": {},\n      \"root\": \"\",\n      \"sourceRoot\": \"src\",\n      \"prefix\": \"app\",\n      \"architect\": {\n        \"storybook\": {\n          \"builder\": \"@storybook/angular:start-storybook\",\n          \"options\": {\n            \"configDir\": \".storybook\",\n            \"browserTarget\": \"your-project:build\",\n            \"compodoc\": true,\n            \"compodocArgs\": [\n              \"-e\",\n              \"json\",\n              \"-d\",\n              \".\", // Add this line to introspect the relevant files starting from the root directory of your project.\n            ],\n            \"port\": 6006,\n          },\n        },\n        \"build-storybook\": {\n          \"builder\": \"@storybook/angular:build-storybook\",\n          \"options\": {\n            \"configDir\": \".storybook\",\n            \"browserTarget\": \"your-project:build\",\n            \"compodoc\": true,\n            \"compodocArgs\": [\n              \"-e\",\n              \"json\",\n              \"-d\",\n              \".\", // Add this line to introspect the relevant files starting from the root directory of your project.\n            ],\n            \"outputDir\": \"storybook-static\",\n          },\n        },\n      },\n    },\n  },\n}\n```\n"
  },
  {
    "path": "docs/_snippets/api-doc-block-argtypes-parameter.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  parameters: {\n    docs: {\n      argTypes: { exclude: ['style'] },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    docs: {\n      argTypes: { exclude: ['style'] },\n    },\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    parameters: {\n      docs: {\n        argTypes: { exclude: ['style'] },\n      },\n    },\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  parameters: {\n    docs: {\n      argTypes: { exclude: ['style'] },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  parameters: {\n    docs: {\n      argTypes: { exclude: ['style'] },\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    parameters: {\n      docs: {\n        argTypes: { exclude: ['style'] },\n      },\n    },\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  parameters: {\n    docs: {\n      argTypes: { exclude: ['style'] },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  parameters: {\n    docs: {\n      argTypes: { exclude: ['style'] },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n  parameters: {\n    docs: {\n      argTypes: { exclude: ['style'] },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  parameters: {\n    docs: {\n      argTypes: { exclude: ['style'] },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  parameters: {\n    docs: {\n      argTypes: { exclude: ['style'] },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  parameters: {\n    docs: {\n      argTypes: { exclude: ['style'] },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    docs: {\n      argTypes: { exclude: ['style'] },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    docs: {\n      argTypes: { exclude: ['style'] },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    docs: {\n      argTypes: { exclude: ['style'] },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    docs: {\n      argTypes: { exclude: ['style'] },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/api-doc-block-canvas-parameter.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const Basic: Story = {\n  parameters: {\n    docs: {\n      canvas: { sourceState: 'shown' },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      canvas: { sourceState: 'shown' },\n    },\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"Basic\"\n  parameters={{\n    docs: {\n      canvas: { sourceState: 'shown' },\n    },\n  }} />\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n};\n\nexport const Basic = {\n  parameters: {\n    docs: {\n      canvas: { sourceState: 'shown' },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Basic = {\n  parameters: {\n    docs: {\n      canvas: { sourceState: 'shown' },\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"Basic\"\n  parameters={{\n    docs: {\n      canvas: { sourceState: 'shown' },\n    },\n  }} />\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  parameters: {\n    docs: {\n      canvas: { sourceState: 'shown' },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  parameters: {\n    docs: {\n      canvas: { sourceState: 'shown' },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  title: 'Button',\n  component: 'demo-button',\n};\n\nexport const Basic = {\n  parameters: {\n    docs: {\n      canvas: { sourceState: 'shown' },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  title: 'Button',\n  component: 'demo-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Basic: Story = {\n  parameters: {\n    docs: {\n      canvas: { sourceState: 'shown' },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  title: 'Button',\n  component: 'demo-button',\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      canvas: { sourceState: 'shown' },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  title: 'Button',\n  component: 'demo-button',\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      canvas: { sourceState: 'shown' },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      canvas: { sourceState: 'shown' },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      canvas: { sourceState: 'shown' },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      canvas: { sourceState: 'shown' },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      canvas: { sourceState: 'shown' },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/api-doc-block-controls-parameter.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    parameters: {\n      docs: {\n        controls: { exclude: ['style'] },\n      },\n    },\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    parameters: {\n      docs: {\n        controls: { exclude: ['style'] },\n      },\n    },\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  title: 'Button',\n  component: 'demo-button',\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  title: 'Button',\n  component: 'demo-button',\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  title: 'Button',\n  component: 'demo-button',\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  title: 'Button',\n  component: 'demo-button',\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/api-doc-block-description-example.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\n/**\n * Button stories\n * These stories showcase the button\n */\nconst meta: Meta<Button> = {\n  component: Button,\n  parameters: {\n    docs: {\n      description: {\n        component: 'Another description, overriding the comments',\n      },\n    },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\n/**\n * Primary Button\n * This is the primary button\n */\nexport const Primary: Story = {\n  parameters: {\n    docs: {\n      description: {\n        story: 'Another description on the story, overriding the comments',\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\n/**\n * Button stories\n * These stories showcase the button\n */\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    docs: {\n      description: {\n        component: 'Another description, overriding the comments',\n      },\n    },\n  },\n});\n\n/**\n * Primary Button\n * This is the primary button\n */\nexport const Primary = meta.story({\n  parameters: {\n    docs: {\n      description: {\n        story: 'Another description on the story, overriding the comments',\n      },\n    },\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  /**\n   * Button stories\n   * These stories showcase the button\n   */\n  const { Story } = defineMeta({\n    component: Button,\n    parameters: {\n      docs: {\n        description: {\n          component: 'Another description, overriding the comments',\n        },\n      },\n    },\n  });\n</script>\n\n<!--\n Button stories\n These stories showcase the button\n -->\n\n<Story\n  name=\"Primary\"\n  parameters={{\n    docs: {\n      description: {\n        story: 'Another description on the story, overriding the comments'\n      },\n    },\n  }} />\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\n/**\n * Button stories\n * These stories showcase the button\n */\nexport default {\n  component: Button,\n  parameters: {\n    docs: {\n      description: {\n        component: 'Another description, overriding the comments',\n      },\n    },\n  },\n};\n\n/**\n * Primary Button\n * This is the primary button\n */\nexport const Primary = {\n  parameters: {\n    docs: {\n      description: {\n        story: 'Another description on the story, overriding the comments',\n      },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\n/**\n * Button stories\n * These stories showcase the button\n */\nexport default {\n  component: Button,\n  parameters: {\n    docs: {\n      description: {\n        component: 'Another description, overriding the comments',\n      },\n    },\n  },\n};\n\n/**\n * Primary Button\n * This is the primary button\n */\nexport const Primary = {\n  parameters: {\n    docs: {\n      description: {\n        story: 'Another description on the story, overriding the comments',\n      },\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  /**\n   * Button stories\n   * These stories showcase the button\n   */\n  const { Story } = defineMeta({\n    component: Button,\n    parameters: {\n      docs: {\n        description: {\n          component: 'Another description, overriding the comments',\n        },\n      },\n    },\n  });\n</script>\n\n<!--\n Button stories\n These stories showcase the button\n -->\n\n<Story\n  name=\"Primary\"\n  parameters={{\n    docs: {\n      description: {\n        story: 'Another description on the story, overriding the comments'\n      },\n    },\n  }} />\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\n/**\n * Button stories\n * These stories showcase the button\n */\nconst meta = {\n  component: Button,\n  parameters: {\n    docs: {\n      description: {\n        component: 'Another description, overriding the comments',\n      },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/**\n * Primary Button\n * This is the primary button\n */\nexport const Primary: Story = {\n  parameters: {\n    docs: {\n      description: {\n        story: 'Another description on the story, overriding the comments',\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\n/**\n * Button stories\n * These stories showcase the button\n */\nconst meta = {\n  component: Button,\n  parameters: {\n    docs: {\n      description: {\n        component: 'Another description, overriding the comments',\n      },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/**\n * Primary Button\n * This is the primary button\n */\nexport const Primary: Story = {\n  parameters: {\n    docs: {\n      description: {\n        story: 'Another description on the story, overriding the comments',\n      },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\n/**\n * Button stories\n * These stories showcase the button\n */\nexport default {\n  title: 'Button',\n  component: 'demo-button',\n  parameters: {\n    docs: {\n      description: {\n        component: 'Another description, overriding the comments',\n      },\n    },\n  },\n};\n\n/**\n * # Button stories\n * These stories showcase the button\n */\nexport const Primary = {\n  parameters: {\n    docs: {\n      description: {\n        story: 'Another description on the story, overriding the comments',\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\n/**\n * Button stories\n * These stories showcase the button\n */\nconst meta: Meta = {\n  title: 'Button',\n  component: 'demo-button',\n  parameters: {\n    docs: {\n      description: {\n        component: 'Another description, overriding the comments',\n      },\n    },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\n/**\n * Primary Button\n * This is the primary button\n */\nexport const Primary: Story = {\n  parameters: {\n    docs: {\n      description: {\n        story: 'Another description on the story, overriding the comments',\n      },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n/**\n * Button stories\n * These stories showcase the button\n */\nconst meta = preview.meta({\n  title: 'Button',\n  component: 'demo-button',\n  parameters: {\n    docs: {\n      description: {\n        component: 'Another description, overriding the comments',\n      },\n    },\n  },\n});\n\n/**\n * # Button stories\n * These stories showcase the button\n */\nexport const Primary = meta.story({\n  parameters: {\n    docs: {\n      description: {\n        story: 'Another description on the story, overriding the comments',\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n/**\n * Button stories\n * These stories showcase the button\n */\nconst meta = preview.meta({\n  title: 'Button',\n  component: 'demo-button',\n  parameters: {\n    docs: {\n      description: {\n        component: 'Another description, overriding the comments',\n      },\n    },\n  },\n});\n\n/**\n * Primary Button\n * This is the primary button\n */\nexport const Primary = meta.story({\n  parameters: {\n    docs: {\n      description: {\n        story: 'Another description on the story, overriding the comments',\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\n/**\n * Button stories\n * These stories showcase the button\n */\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    docs: {\n      description: {\n        component: 'Another description, overriding the comments',\n      },\n    },\n  },\n});\n\n/**\n * Primary Button\n * This is the primary button\n */\nexport const Primary = meta.story({\n  parameters: {\n    docs: {\n      description: {\n        story: 'Another description on the story, overriding the comments',\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    docs: {\n      description: {\n        component: 'Another description, overriding the comments',\n      },\n    },\n  },\n});\n\n/**\n * Primary Button\n * This is the primary button\n */\nexport const Primary = meta.story({\n  parameters: {\n    docs: {\n      description: {\n        story: 'Another description on the story, overriding the comments',\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\n/**\n * Button stories\n * These stories showcase the button\n */\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    docs: {\n      description: {\n        component: 'Another description, overriding the comments',\n      },\n    },\n  },\n});\n\n/**\n * Primary Button\n * This is the primary button\n */\nexport const Primary = meta.story({\n  parameters: {\n    docs: {\n      description: {\n        story: 'Another description on the story, overriding the comments',\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\n/**\n * Button stories\n * These stories showcase the button\n */\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    docs: {\n      description: {\n        component: 'Another description, overriding the comments',\n      },\n    },\n  },\n});\n\n/**\n * Primary Button\n * This is the primary button\n */\nexport const Primary = meta.story({\n  parameters: {\n    docs: {\n      description: {\n        story: 'Another description on the story, overriding the comments',\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/api-doc-block-source-parameter.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const Basic: Story = {\n  parameters: {\n    docs: {\n      source: { language: 'ts' },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      source: { language: 'ts' },\n    },\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"Basic\"\n  parameters={{\n    docs: {\n      source: { language: 'tsx' },\n    },\n  }} />\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n};\n\nexport const Basic = {\n  parameters: {\n    docs: {\n      source: { language: 'jsx' },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Basic = {\n  parameters: {\n    docs: {\n      source: { language: 'js' },\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"Basic\"\n  parameters={{\n    docs: {\n      source: { language: 'tsx' },\n    },\n  }} />\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  parameters: {\n    docs: {\n      source: { language: 'tsx' },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  parameters: {\n    docs: {\n      source: { language: 'ts' },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n};\n\nexport const Basic = {\n  parameters: {\n    docs: {\n      source: { language: 'js' },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Basic: Story = {\n  parameters: {\n    docs: {\n      source: { language: 'ts' },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      source: { language: 'tsx' },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      source: { language: 'tsx' },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      source: { language: 'tsx' },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      source: { language: 'jsx' },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      source: { language: 'vue' },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      source: { language: 'vue' },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/api-doc-block-story-parameter.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const Basic: Story = {\n  parameters: {\n    docs: {\n      story: { autoplay: true },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      story: { autoplay: true },\n    },\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"Basic\"\n  parameters={{\n    docs: {\n      story: { autoplay: true },\n    },\n  }} />\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n};\n\nexport const Basic = {\n  parameters: {\n    docs: {\n      story: { autoplay: true },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Basic = {\n  parameters: {\n    docs: {\n      story: { autoplay: true },\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"Basic\"\n  parameters={{\n    docs: {\n      story: { autoplay: true },\n    },\n  }} />\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  parameters: {\n    docs: {\n      story: { autoplay: true },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  parameters: {\n    docs: {\n      story: { autoplay: true },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n};\n\nexport const Basic = {\n  parameters: {\n    docs: {\n      story: { autoplay: true },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Basic: Story = {\n  parameters: {\n    docs: {\n      story: { autoplay: true },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      story: { autoplay: true },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      story: { autoplay: true },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      story: { autoplay: true },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      story: { autoplay: true },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      story: { autoplay: true },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  parameters: {\n    docs: {\n      story: { autoplay: true },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/arg-types-control.md",
    "content": "```ts filename=\"Example.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Example } from './example.component';\n\nconst meta: Meta<Example> = {\n  component: Example,\n  argTypes: {\n    value: {\n      control: {\n        type: 'number',\n        min: 0,\n        max: 100,\n        step: 10,\n      },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './example.component';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: {\n      control: {\n        type: 'number',\n        min: 0,\n        max: 100,\n        step: 10,\n      },\n    },\n  },\n});\n```\n\n```svelte filename=\"Example.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Example from './Example.svelte';\n\n  const { Story } = defineMeta({\n    component: Example,\n    argTypes: {\n      value: {\n        control: {\n          type: 'number',\n          min: 0,\n          max: 100,\n          step: 10,\n        },\n      },\n    },\n  });\n</script>\n```\n\n```js filename=\"Example.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Example from './Example.svelte';\n\nexport default {\n  component: Example,\n  argTypes: {\n    value: {\n      control: {\n        type: 'number',\n        min: 0,\n        max: 100,\n        step: 10,\n      },\n    },\n  },\n};\n```\n\n```js filename=\"Example.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Example } from './Example';\n\nexport default {\n  component: Example,\n  argTypes: {\n    value: {\n      control: {\n        type: 'number',\n        min: 0,\n        max: 100,\n        step: 10,\n      },\n    },\n  },\n};\n```\n\n```svelte filename=\"Example.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Example from './Example.svelte';\n\n  const { Story } = defineMeta({\n    component: Example,\n    argTypes: {\n      value: {\n        control: {\n          type: 'number',\n          min: 0,\n          max: 100,\n          step: 10,\n        },\n      },\n    },\n  });\n</script>\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Example from './Example.svelte';\n\nconst meta = {\n  component: Example,\n  argTypes: {\n    value: {\n      control: {\n        type: 'number',\n        min: 0,\n        max: 100,\n        step: 10,\n      },\n    },\n  },\n} satisfies Meta<typeof Example>;\n\nexport default meta;\n```\n\n```ts filename=\"Example.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Example } from './Example';\n\nconst meta = {\n  component: Example,\n  argTypes: {\n    value: {\n      control: {\n        type: 'number',\n        min: 0,\n        max: 100,\n        step: 10,\n      },\n    },\n  },\n} satisfies Meta<typeof Example>;\n\nexport default meta;\n```\n\n```js filename=\"Example.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-example',\n  argTypes: {\n    value: {\n      control: {\n        type: 'number',\n        min: 0,\n        max: 100,\n        step: 10,\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-example',\n  argTypes: {\n    value: {\n      control: {\n        type: 'number',\n        min: 0,\n        max: 100,\n        step: 10,\n      },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Example.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-example',\n  argTypes: {\n    value: {\n      control: {\n        type: 'number',\n        min: 0,\n        max: 100,\n        step: 10,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-example',\n  argTypes: {\n    value: {\n      control: {\n        type: 'number',\n        min: 0,\n        max: 100,\n        step: 10,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './Example';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: {\n      control: {\n        type: 'number',\n        min: 0,\n        max: 100,\n        step: 10,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Example.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './Example';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: {\n      control: {\n        type: 'number',\n        min: 0,\n        max: 100,\n        step: 10,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Example from './Example.vue';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: {\n      control: {\n        type: 'number',\n        min: 0,\n        max: 100,\n        step: 10,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Example.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Example from './Example.vue';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: {\n      control: {\n        type: 'number',\n        min: 0,\n        max: 100,\n        step: 10,\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/arg-types-default-value.md",
    "content": "```ts filename=\"Example.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Example } from './example.component';\n\nconst meta: Meta<Example> = {\n  component: Example,\n  argTypes: {\n    value: {\n      // ⛔️ Deprecated, do not use\n      defaultValue: 0,\n    },\n  },\n  // ✅ Do this instead\n  args: {\n    value: 0,\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './example.component';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: {\n      // ⛔️ Deprecated, do not use\n      defaultValue: 0,\n    },\n  },\n  // ✅ Do this instead\n  args: {\n    value: 0,\n  },\n});\n```\n\n```svelte filename=\"Example.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Example from './Example.svelte';\n\n  const { Story } = defineMeta({\n    component: Example,\n    argTypes: {\n      value: {\n        // ⛔️ Deprecated, do not use\n        defaultValue: 0,\n      },\n    },\n    // ✅ Do this instead\n    args: {\n      value: 0,\n    },\n  });\n</script>\n```\n\n```js filename=\"Example.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Example from './Example.svelte';\n\nexport default {\n  component: Example,\n  argTypes: {\n    value: {\n      // ⛔️ Deprecated, do not use\n      defaultValue: 0,\n    },\n  },\n  // ✅ Do this instead\n  args: {\n    value: 0,\n  },\n};\n```\n\n```js filename=\"Example.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Example } from './Example';\n\nexport default {\n  component: Example,\n  argTypes: {\n    value: {\n      // ⛔️ Deprecated, do not use\n      defaultValue: 0,\n    },\n  },\n  // ✅ Do this instead\n  args: {\n    value: 0,\n  },\n};\n```\n\n```svelte filename=\"Example.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Example from './Example.svelte';\n\n  const { Story } = defineMeta({\n    component: Example,\n    argTypes: {\n      value: {\n        // ⛔️ Deprecated, do not use\n        defaultValue: 0,\n      },\n    },\n    // ✅ Do this instead\n    args: {\n      value: 0,\n    },\n  });\n</script>\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Example from './Example.svelte';\n\nconst meta = {\n  component: Example,\n  argTypes: {\n    value: {\n      // ❌ Deprecated\n      defaultValue: 0,\n    },\n  },\n  // ✅ Do this instead\n  args: {\n    value: 0,\n  },\n} satisfies Meta<typeof Example>;\n\nexport default meta;\n```\n\n```ts filename=\"Example.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Example } from './Example';\n\nconst meta = {\n  component: Example,\n  argTypes: {\n    value: {\n      // ❌ Deprecated\n      defaultValue: 0,\n    },\n  },\n  // ✅ Do this instead\n  args: {\n    value: 0,\n  },\n} satisfies Meta<typeof Example>;\n\nexport default meta;\n```\n\n```js filename=\"Example.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-example',\n  argTypes: {\n    value: {\n      // ⛔️ Deprecated, do not use\n      defaultValue: 0,\n    },\n  },\n  // ✅ Do this instead\n  args: {\n    value: 0,\n  },\n};\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-example',\n  argTypes: {\n    value: {\n      // ⛔️ Deprecated, do not use\n      defaultValue: 0,\n    },\n  },\n  // ✅ Do this instead\n  args: {\n    value: 0,\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Example.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-example',\n  argTypes: {\n    value: {\n      // ⛔️ Deprecated, do not use\n      defaultValue: 0,\n    },\n  },\n  // ✅ Do this instead\n  args: {\n    value: 0,\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-example',\n  argTypes: {\n    value: {\n      // ⛔️ Deprecated, do not use\n      defaultValue: 0,\n    },\n  },\n  // ✅ Do this instead\n  args: {\n    value: 0,\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './Example';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: {\n      // ❌ Deprecated\n      defaultValue: 0,\n    },\n  },\n  // ✅ Do this instead\n  args: {\n    value: 0,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Example.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './Example';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: {\n      // ⛔️ Deprecated, do not use\n      defaultValue: 0,\n    },\n  },\n  // ✅ Do this instead\n  args: {\n    value: 0,\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Example from './Example.vue';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: {\n      // ❌ Deprecated\n      defaultValue: 0,\n    },\n  },\n  // ✅ Do this instead\n  args: {\n    value: 0,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Example.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Example from './Example.vue';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: {\n      // ⛔️ Deprecated, do not use\n      defaultValue: 0,\n    },\n  },\n  // ✅ Do this instead\n  args: {\n    value: 0,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/arg-types-description.md",
    "content": "```ts filename=\"Example.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Example } from './example.component';\n\nconst meta: Meta<Example> = {\n  component: Example,\n  argTypes: {\n    value: {\n      description: 'The value of the slider',\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './example.component';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: {\n      description: 'The value of the slider',\n    },\n  },\n});\n```\n\n```svelte filename=\"Example.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Example from './Example.svelte';\n\n  const { Story } = defineMeta({\n    component: Example,\n    argTypes: {\n      value: {\n        description: 'The value of the slider',\n      },\n    },\n  });\n</script>\n```\n\n```js filename=\"Example.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Example from './Example.svelte';\n\nexport default {\n  component: Example,\n  argTypes: {\n    value: {\n      description: 'The value of the slider',\n    },\n  },\n};\n```\n\n```js filename=\"Example.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Example } from './Example';\n\nexport default {\n  component: Example,\n  argTypes: {\n    value: {\n      description: 'The value of the slider',\n    },\n  },\n};\n```\n\n```svelte filename=\"Example.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Example from './Example.svelte';\n\n  const { Story } = defineMeta({\n    component: Example,\n    argTypes: {\n      value: {\n        description: 'The value of the slider',\n      },\n    },\n  });\n</script>\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Example from './Example.svelte';\n\nconst meta = {\n  component: Example,\n  argTypes: {\n    value: {\n      description: 'The value of the slider',\n    },\n  },\n} satisfies Meta<typeof Example>;\n\nexport default meta;\n```\n\n```ts filename=\"Example.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Example } from './Example';\n\nconst meta = {\n  component: Example,\n  argTypes: {\n    value: {\n      description: 'The value of the slider',\n    },\n  },\n} satisfies Meta<typeof Example>;\n\nexport default meta;\n```\n\n```js filename=\"Example.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-example',\n  argTypes: {\n    value: {\n      description: 'The value of the slider',\n    },\n  },\n};\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-example',\n  argTypes: {\n    value: {\n      description: 'The value of the slider',\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Example.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-example',\n  argTypes: {\n    value: {\n      description: 'The value of the slider',\n    },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-example',\n  argTypes: {\n    value: {\n      description: 'The value of the slider',\n    },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './Example';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: {\n      description: 'The value of the slider',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Example.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './Example';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: {\n      description: 'The value of the slider',\n    },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Example from './Example.vue';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: {\n      description: 'The value of the slider',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Example.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Example from './Example.vue';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: {\n      description: 'The value of the slider',\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/arg-types-if.md",
    "content": "```ts filename=\"Example.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Example } from './example.component';\n\nconst meta: Meta<Example> = {\n  component: Example,\n  argTypes: {\n    parent: { control: 'select', options: ['one', 'two', 'three'] },\n\n    // 👇 Only shown when `parent` arg exists\n    parentExists: { if: { arg: 'parent', exists: true } },\n\n    // 👇 Only shown when `parent` arg does not exist\n    parentDoesNotExist: { if: { arg: 'parent', exists: false } },\n\n    // 👇 Only shown when `parent` arg value is truthy\n    parentIsTruthy: { if: { arg: 'parent' } },\n    parentIsTruthyVerbose: { if: { arg: 'parent', truthy: true } },\n\n    // 👇 Only shown when `parent` arg value is not truthy\n    parentIsNotTruthy: { if: { arg: 'parent', truthy: false } },\n\n    // 👇 Only shown when `parent` arg value is 'three'\n    parentIsEqToValue: { if: { arg: 'parent', eq: 'three' } },\n\n    // 👇 Only shown when `parent` arg value is not 'three'\n    parentIsNotEqToValue: { if: { arg: 'parent', neq: 'three' } },\n\n    // Each of the above can also be conditional on the value of a globalType, e.g.:\n\n    // 👇 Only shown when `theme` global exists\n    parentExists: { if: { global: 'theme', exists: true } },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './example.component';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    parent: { control: 'select', options: ['one', 'two', 'three'] },\n\n    // 👇 Only shown when `parent` arg exists\n    parentExists: { if: { arg: 'parent', exists: true } },\n\n    // 👇 Only shown when `parent` arg does not exist\n    parentDoesNotExist: { if: { arg: 'parent', exists: false } },\n\n    // 👇 Only shown when `parent` arg value is truthy\n    parentIsTruthy: { if: { arg: 'parent' } },\n    parentIsTruthyVerbose: { if: { arg: 'parent', truthy: true } },\n\n    // 👇 Only shown when `parent` arg value is not truthy\n    parentIsNotTruthy: { if: { arg: 'parent', truthy: false } },\n\n    // 👇 Only shown when `parent` arg value is 'three'\n    parentIsEqToValue: { if: { arg: 'parent', eq: 'three' } },\n\n    // 👇 Only shown when `parent` arg value is not 'three'\n    parentIsNotEqToValue: { if: { arg: 'parent', neq: 'three' } },\n\n    // Each of the above can also be conditional on the value of a globalType, e.g.:\n\n    // 👇 Only shown when `theme` global exists\n    parentExists: { if: { global: 'theme', exists: true } },\n  },\n});\n```\n\n```svelte filename=\"Example.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Example from './Example.svelte';\n\n  const { Story } = defineMeta({\n    component: Example,\n    argTypes: {\n      parent: { control: 'select', options: ['one', 'two', 'three'] },\n\n      // 👇 Only shown when `parent` arg exists\n      parentExists: { if: { arg: 'parent', exists: true } },\n\n      // 👇 Only shown when `parent` arg does not exist\n      parentDoesNotExist: { if: { arg: 'parent', exists: false } },\n\n      // 👇 Only shown when `parent` arg value is truthy\n      parentIsTruthy: { if: { arg: 'parent' } },\n      parentIsTruthyVerbose: { if: { arg: 'parent', truthy: true } },\n\n      // 👇 Only shown when `parent` arg value is not truthy\n      parentIsNotTruthy: { if: { arg: 'parent', truthy: false } },\n\n      // 👇 Only shown when `parent` arg value is 'three'\n      parentIsEqToValue: { if: { arg: 'parent', eq: 'three' } },\n\n      // 👇 Only shown when `parent` arg value is not 'three'\n      parentIsNotEqToValue: { if: { arg: 'parent', neq: 'three' } },\n\n      // Each of the above can also be conditional on the value of a globalType, e.g.:\n\n      // 👇 Only shown when `theme` global exists\n      parentExists: { if: { global: 'theme', exists: true } },\n    },\n  });\n</script>\n```\n\n```js filename=\"Example.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Example from './Example.svelte';\n\nexport default {\n  component: Example,\n  argTypes: {\n    parent: { control: 'select', options: ['one', 'two', 'three'] },\n\n    // 👇 Only shown when `parent` arg exists\n    parentExists: { if: { arg: 'parent', exists: true } },\n\n    // 👇 Only shown when `parent` arg does not exist\n    parentDoesNotExist: { if: { arg: 'parent', exists: false } },\n\n    // 👇 Only shown when `parent` arg value is truthy\n    parentIsTruthy: { if: { arg: 'parent' } },\n    parentIsTruthyVerbose: { if: { arg: 'parent', truthy: true } },\n\n    // 👇 Only shown when `parent` arg value is not truthy\n    parentIsNotTruthy: { if: { arg: 'parent', truthy: false } },\n\n    // 👇 Only shown when `parent` arg value is 'three'\n    parentIsEqToValue: { if: { arg: 'parent', eq: 'three' } },\n\n    // 👇 Only shown when `parent` arg value is not 'three'\n    parentIsNotEqToValue: { if: { arg: 'parent', neq: 'three' } },\n\n    // Each of the above can also be conditional on the value of a globalType, e.g.:\n\n    // 👇 Only shown when `theme` global exists\n    parentExists: { if: { global: 'theme', exists: true } },\n  },\n};\n```\n\n```js filename=\"Example.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Example } from './Example';\n\nexport default {\n  component: Example,\n  argTypes: {\n    parent: { control: 'select', options: ['one', 'two', 'three'] },\n\n    // 👇 Only shown when `parent` arg exists\n    parentExists: { if: { arg: 'parent', exists: true } },\n\n    // 👇 Only shown when `parent` arg does not exist\n    parentDoesNotExist: { if: { arg: 'parent', exists: false } },\n\n    // 👇 Only shown when `parent` arg value is truthy\n    parentIsTruthy: { if: { arg: 'parent' } },\n    parentIsTruthyVerbose: { if: { arg: 'parent', truthy: true } },\n\n    // 👇 Only shown when `parent` arg value is not truthy\n    parentIsNotTruthy: { if: { arg: 'parent', truthy: false } },\n\n    // 👇 Only shown when `parent` arg value is 'three'\n    parentIsEqToValue: { if: { arg: 'parent', eq: 'three' } },\n\n    // 👇 Only shown when `parent` arg value is not 'three'\n    parentIsNotEqToValue: { if: { arg: 'parent', neq: 'three' } },\n\n    // Each of the above can also be conditional on the value of a globalType, e.g.:\n\n    // 👇 Only shown when `theme` global exists\n    parentExists: { if: { global: 'theme', exists: true } },\n  },\n};\n```\n\n```svelte filename=\"Example.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Example from './Example.svelte';\n\n  const { Story } = defineMeta({\n    component: Example,\n    argTypes: {\n      parent: { control: 'select', options: ['one', 'two', 'three'] },\n\n      // 👇 Only shown when `parent` arg exists\n      parentExists: { if: { arg: 'parent', exists: true } },\n\n      // 👇 Only shown when `parent` arg does not exist\n      parentDoesNotExist: { if: { arg: 'parent', exists: false } },\n\n      // 👇 Only shown when `parent` arg value is truthy\n      parentIsTruthy: { if: { arg: 'parent' } },\n      parentIsTruthyVerbose: { if: { arg: 'parent', truthy: true } },\n\n      // 👇 Only shown when `parent` arg value is not truthy\n      parentIsNotTruthy: { if: { arg: 'parent', truthy: false } },\n\n      // 👇 Only shown when `parent` arg value is 'three'\n      parentIsEqToValue: { if: { arg: 'parent', eq: 'three' } },\n\n      // 👇 Only shown when `parent` arg value is not 'three'\n      parentIsNotEqToValue: { if: { arg: 'parent', neq: 'three' } },\n\n      // Each of the above can also be conditional on the value of a globalType, e.g.:\n\n      // 👇 Only shown when `theme` global exists\n      parentExists: { if: { global: 'theme', exists: true } },\n    },\n  });\n</script>\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Example from './Example.svelte';\n\nconst meta = {\n  component: Example,\n  argTypes: {\n    parent: { control: 'select', options: ['one', 'two', 'three'] },\n\n    // 👇 Only shown when `parent` arg exists\n    parentExists: { if: { arg: 'parent', exists: true } },\n\n    // 👇 Only shown when `parent` arg does not exist\n    parentDoesNotExist: { if: { arg: 'parent', exists: false } },\n\n    // 👇 Only shown when `parent` arg value is truthy\n    parentIsTruthy: { if: { arg: 'parent' } },\n    parentIsTruthyVerbose: { if: { arg: 'parent', truthy: true } },\n\n    // 👇 Only shown when `parent` arg value is not truthy\n    parentIsNotTruthy: { if: { arg: 'parent', truthy: false } },\n\n    // 👇 Only shown when `parent` arg value is 'three'\n    parentIsEqToValue: { if: { arg: 'parent', eq: 'three' } },\n\n    // 👇 Only shown when `parent` arg value is not 'three'\n    parentIsNotEqToValue: { if: { arg: 'parent', neq: 'three' } },\n\n    // Each of the above can also be conditional on the value of a globalType, e.g.:\n\n    // 👇 Only shown when `theme` global exists\n    parentExists: { if: { global: 'theme', exists: true } },\n  },\n} satisfies Meta<typeof Example>;\n\nexport default meta;\n```\n\n```ts filename=\"Example.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Example } from './Example';\n\nconst meta = {\n  component: Example,\n  argTypes: {\n    parent: { control: 'select', options: ['one', 'two', 'three'] },\n\n    // 👇 Only shown when `parent` arg exists\n    parentExists: { if: { arg: 'parent', exists: true } },\n\n    // 👇 Only shown when `parent` arg does not exist\n    parentDoesNotExist: { if: { arg: 'parent', exists: false } },\n\n    // 👇 Only shown when `parent` arg value is truthy\n    parentIsTruthy: { if: { arg: 'parent' } },\n    parentIsTruthyVerbose: { if: { arg: 'parent', truthy: true } },\n\n    // 👇 Only shown when `parent` arg value is not truthy\n    parentIsNotTruthy: { if: { arg: 'parent', truthy: false } },\n\n    // 👇 Only shown when `parent` arg value is 'three'\n    parentIsEqToValue: { if: { arg: 'parent', eq: 'three' } },\n\n    // 👇 Only shown when `parent` arg value is not 'three'\n    parentIsNotEqToValue: { if: { arg: 'parent', neq: 'three' } },\n\n    // Each of the above can also be conditional on the value of a globalType, e.g.:\n\n    // 👇 Only shown when `theme` global exists\n    parentExists: { if: { global: 'theme', exists: true } },\n  },\n} satisfies Meta<typeof Example>;\n\nexport default meta;\n```\n\n```js filename=\"Example.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-example',\n  argTypes: {\n    parent: { control: 'select', options: ['one', 'two', 'three'] },\n\n    // 👇 Only shown when `parent` arg exists\n    parentExists: { if: { arg: 'parent', exists: true } },\n\n    // 👇 Only shown when `parent` arg does not exist\n    parentDoesNotExist: { if: { arg: 'parent', exists: false } },\n\n    // 👇 Only shown when `parent` arg value is truthy\n    parentIsTruthy: { if: { arg: 'parent' } },\n    parentIsTruthyVerbose: { if: { arg: 'parent', truthy: true } },\n\n    // 👇 Only shown when `parent` arg value is not truthy\n    parentIsNotTruthy: { if: { arg: 'parent', truthy: false } },\n\n    // 👇 Only shown when `parent` arg value is 'three'\n    parentIsEqToValue: { if: { arg: 'parent', eq: 'three' } },\n\n    // 👇 Only shown when `parent` arg value is not 'three'\n    parentIsNotEqToValue: { if: { arg: 'parent', neq: 'three' } },\n\n    // Each of the above can also be conditional on the value of a globalType, e.g.:\n\n    // 👇 Only shown when `theme` global exists\n    parentExists: { if: { global: 'theme', exists: true } },\n  },\n};\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-example',\n  argTypes: {\n    parent: { control: 'select', options: ['one', 'two', 'three'] },\n\n    // 👇 Only shown when `parent` arg exists\n    parentExists: { if: { arg: 'parent', exists: true } },\n\n    // 👇 Only shown when `parent` arg does not exist\n    parentDoesNotExist: { if: { arg: 'parent', exists: false } },\n\n    // 👇 Only shown when `parent` arg value is truthy\n    parentIsTruthy: { if: { arg: 'parent' } },\n    parentIsTruthyVerbose: { if: { arg: 'parent', truthy: true } },\n\n    // 👇 Only shown when `parent` arg value is not truthy\n    parentIsNotTruthy: { if: { arg: 'parent', truthy: false } },\n\n    // 👇 Only shown when `parent` arg value is 'three'\n    parentIsEqToValue: { if: { arg: 'parent', eq: 'three' } },\n\n    // 👇 Only shown when `parent` arg value is not 'three'\n    parentIsNotEqToValue: { if: { arg: 'parent', neq: 'three' } },\n\n    // Each of the above can also be conditional on the value of a globalType, e.g.:\n\n    // 👇 Only shown when `theme` global exists\n    parentExists: { if: { global: 'theme', exists: true } },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Example.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-example',\n  argTypes: {\n    parent: { control: 'select', options: ['one', 'two', 'three'] },\n\n    // 👇 Only shown when `parent` arg exists\n    parentExists: { if: { arg: 'parent', exists: true } },\n\n    // 👇 Only shown when `parent` arg does not exist\n    parentDoesNotExist: { if: { arg: 'parent', exists: false } },\n\n    // 👇 Only shown when `parent` arg value is truthy\n    parentIsTruthy: { if: { arg: 'parent' } },\n    parentIsTruthyVerbose: { if: { arg: 'parent', truthy: true } },\n\n    // 👇 Only shown when `parent` arg value is not truthy\n    parentIsNotTruthy: { if: { arg: 'parent', truthy: false } },\n\n    // 👇 Only shown when `parent` arg value is 'three'\n    parentIsEqToValue: { if: { arg: 'parent', eq: 'three' } },\n\n    // 👇 Only shown when `parent` arg value is not 'three'\n    parentIsNotEqToValue: { if: { arg: 'parent', neq: 'three' } },\n\n    // Each of the above can also be conditional on the value of a globalType, e.g.:\n\n    // 👇 Only shown when `theme` global exists\n    parentExists: { if: { global: 'theme', exists: true } },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-example',\n  argTypes: {\n    parent: { control: 'select', options: ['one', 'two', 'three'] },\n\n    // 👇 Only shown when `parent` arg exists\n    parentExists: { if: { arg: 'parent', exists: true } },\n\n    // 👇 Only shown when `parent` arg does not exist\n    parentDoesNotExist: { if: { arg: 'parent', exists: false } },\n\n    // 👇 Only shown when `parent` arg value is truthy\n    parentIsTruthy: { if: { arg: 'parent' } },\n    parentIsTruthyVerbose: { if: { arg: 'parent', truthy: true } },\n\n    // 👇 Only shown when `parent` arg value is not truthy\n    parentIsNotTruthy: { if: { arg: 'parent', truthy: false } },\n\n    // 👇 Only shown when `parent` arg value is 'three'\n    parentIsEqToValue: { if: { arg: 'parent', eq: 'three' } },\n\n    // 👇 Only shown when `parent` arg value is not 'three'\n    parentIsNotEqToValue: { if: { arg: 'parent', neq: 'three' } },\n\n    // Each of the above can also be conditional on the value of a globalType, e.g.:\n\n    // 👇 Only shown when `theme` global exists\n    parentExists: { if: { global: 'theme', exists: true } },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './Example';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    parent: { control: 'select', options: ['one', 'two', 'three'] },\n\n    // 👇 Only shown when `parent` arg exists\n    parentExists: { if: { arg: 'parent', exists: true } },\n\n    // 👇 Only shown when `parent` arg does not exist\n    parentDoesNotExist: { if: { arg: 'parent', exists: false } },\n\n    // 👇 Only shown when `parent` arg value is truthy\n    parentIsTruthy: { if: { arg: 'parent' } },\n    parentIsTruthyVerbose: { if: { arg: 'parent', truthy: true } },\n\n    // 👇 Only shown when `parent` arg value is not truthy\n    parentIsNotTruthy: { if: { arg: 'parent', truthy: false } },\n\n    // 👇 Only shown when `parent` arg value is 'three'\n    parentIsEqToValue: { if: { arg: 'parent', eq: 'three' } },\n\n    // 👇 Only shown when `parent` arg value is not 'three'\n    parentIsNotEqToValue: { if: { arg: 'parent', neq: 'three' } },\n\n    // Each of the above can also be conditional on the value of a globalType, e.g.:\n\n    // 👇 Only shown when `theme` global exists\n    parentExists: { if: { global: 'theme', exists: true } },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Example.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './Example';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    parent: { control: 'select', options: ['one', 'two', 'three'] },\n\n    // 👇 Only shown when `parent` arg exists\n    parentExists: { if: { arg: 'parent', exists: true } },\n\n    // 👇 Only shown when `parent` arg does not exist\n    parentDoesNotExist: { if: { arg: 'parent', exists: false } },\n\n    // 👇 Only shown when `parent` arg value is truthy\n    parentIsTruthy: { if: { arg: 'parent' } },\n    parentIsTruthyVerbose: { if: { arg: 'parent', truthy: true } },\n\n    // 👇 Only shown when `parent` arg value is not truthy\n    parentIsNotTruthy: { if: { arg: 'parent', truthy: false } },\n\n    // 👇 Only shown when `parent` arg value is 'three'\n    parentIsEqToValue: { if: { arg: 'parent', eq: 'three' } },\n\n    // 👇 Only shown when `parent` arg value is not 'three'\n    parentIsNotEqToValue: { if: { arg: 'parent', neq: 'three' } },\n\n    // Each of the above can also be conditional on the value of a globalType, e.g.:\n\n    // 👇 Only shown when `theme` global exists\n    parentExists: { if: { global: 'theme', exists: true } },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Example from './Example.vue';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    parent: { control: 'select', options: ['one', 'two', 'three'] },\n\n    // 👇 Only shown when `parent` arg exists\n    parentExists: { if: { arg: 'parent', exists: true } },\n\n    // 👇 Only shown when `parent` arg does not exist\n    parentDoesNotExist: { if: { arg: 'parent', exists: false } },\n\n    // 👇 Only shown when `parent` arg value is truthy\n    parentIsTruthy: { if: { arg: 'parent' } },\n    parentIsTruthyVerbose: { if: { arg: 'parent', truthy: true } },\n\n    // 👇 Only shown when `parent` arg value is not truthy\n    parentIsNotTruthy: { if: { arg: 'parent', truthy: false } },\n\n    // 👇 Only shown when `parent` arg value is 'three'\n    parentIsEqToValue: { if: { arg: 'parent', eq: 'three' } },\n\n    // 👇 Only shown when `parent` arg value is not 'three'\n    parentIsNotEqToValue: { if: { arg: 'parent', neq: 'three' } },\n\n    // Each of the above can also be conditional on the value of a globalType, e.g.:\n\n    // 👇 Only shown when `theme` global exists\n    parentExists: { if: { global: 'theme', exists: true } },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Example.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Example from './Example.vue';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    parent: { control: 'select', options: ['one', 'two', 'three'] },\n\n    // 👇 Only shown when `parent` arg exists\n    parentExists: { if: { arg: 'parent', exists: true } },\n\n    // 👇 Only shown when `parent` arg does not exist\n    parentDoesNotExist: { if: { arg: 'parent', exists: false } },\n\n    // 👇 Only shown when `parent` arg value is truthy\n    parentIsTruthy: { if: { arg: 'parent' } },\n    parentIsTruthyVerbose: { if: { arg: 'parent', truthy: true } },\n\n    // 👇 Only shown when `parent` arg value is not truthy\n    parentIsNotTruthy: { if: { arg: 'parent', truthy: false } },\n\n    // 👇 Only shown when `parent` arg value is 'three'\n    parentIsEqToValue: { if: { arg: 'parent', eq: 'three' } },\n\n    // 👇 Only shown when `parent` arg value is not 'three'\n    parentIsNotEqToValue: { if: { arg: 'parent', neq: 'three' } },\n\n    // Each of the above can also be conditional on the value of a globalType, e.g.:\n\n    // 👇 Only shown when `theme` global exists\n    parentExists: { if: { global: 'theme', exists: true } },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/arg-types-in-meta.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  argTypes: {\n    // 👇 All Button stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    // 👇 All Button stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    argTypes: {\n      // 👇 All Button stories expect a label arg\n      label: {\n        control: 'text',\n        description: 'Overwritten description',\n      },\n    },\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  argTypes: {\n    // 👇 All Button stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  argTypes: {\n    // 👇 All Button stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    argTypes: {\n      // 👇 All Button stories expect a label arg\n      label: {\n        control: 'text',\n        description: 'Overwritten description',\n      },\n    },\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  argTypes: {\n    // 👇 All Button stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  argTypes: {\n    // 👇 All Button stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n  argTypes: {\n    // 👇 All Button stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  argTypes: {\n    // 👇 All Button stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  argTypes: {\n    // 👇 All Button stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  argTypes: {\n    // 👇 All Button stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    // 👇 All Button stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    // 👇 All Button stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    // 👇 All Button stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    // 👇 All Button stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/arg-types-in-preview.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  argTypes: {\n    // 👇 All stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview = {\n  argTypes: {\n    // 👇 All stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n} satisfies Preview;\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  argTypes: {\n    // 👇 All stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  argTypes: {\n    // 👇 All stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  argTypes: {\n    // 👇 All stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  argTypes: {\n    // 👇 All stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  argTypes: {\n    // 👇 All stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  argTypes: {\n    // 👇 All stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  argTypes: {\n    // 👇 All stories expect a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/arg-types-in-story.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\n\nexport default meta;\n\ntype Story = StoryObj<typeof Button>;\n\nexport const Basic: Story = {\n  argTypes: {\n    // 👇 This story expects a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  argTypes: {\n    // 👇 This story expects a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"Basic\"\n  argTypes={{\n    label: { control: 'text', description: 'Overwritten description' }\n  }}\n/>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n};\n\nexport const Basic = {\n  argTypes: {\n    // 👇 This story expects a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Basic = {\n  argTypes: {\n    // 👇 This story expects a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"Basic\"\n  argTypes={{\n    label: { control: 'text', description: 'Overwritten description' }\n  }}\n/>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic = {\n  argTypes: {\n    // 👇 This story expects a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n} satisfies Story;\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  argTypes: {\n    // 👇 This story expects a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n} satisfies Story;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n};\n\nexport const Basic = {\n  argTypes: {\n    // 👇 This story expects a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Basic: Story = {\n  argTypes: {\n    // 👇 This story expects a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Basic = meta.story({\n  argTypes: {\n    // 👇 This story expects a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Basic = meta.story({\n  argTypes: {\n    // 👇 This story expects a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  argTypes: {\n    // 👇 This story expects a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  argTypes: {\n    // 👇 This story expects a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  argTypes: {\n    // 👇 This story expects a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  argTypes: {\n    // 👇 This story expects a label arg\n    label: {\n      control: 'text',\n      description: 'Overwritten description',\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/arg-types-mapping.md",
    "content": "```svelte filename=\"Example.stories.svelte\" renderer=\"svelte\" language=\"js\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Example from './Example.svelte';\n\n  const { Story } = defineMeta({\n    component: Example,\n    argTypes: {\n      label: {\n        control: { type: 'select' },\n        options: ['Normal', 'Bold', 'Italic'],\n        mapping: {\n          Normal: normal,\n          Bold: bold,\n          Italic: italic,\n        },\n      },\n    },\n  });\n</script>\n\n{#snippet normal()}\n  <span>Normal</span>\n{/snippet}\n\n{#snippet bold()}\n  <b>Bold</b>\n{/snippet}\n{#snippet italic()}\n  <i>Italic</i>\n{/snippet}\n```\n\n```svelte filename=\"Example.stories.svelte\" renderer=\"svelte\" language=\"ts\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Example from './Example.svelte';\n\n  const { Story } = defineMeta({\n    component: Example,\n    argTypes: {\n      label: {\n        control: { type: 'select' },\n        options: ['Normal', 'Bold', 'Italic'],\n        mapping: {\n          Normal: normal,\n          Bold: bold,\n          Italic: italic,\n        },\n      },\n    },\n  });\n</script>\n\n{#snippet normal()}\n  <span>Normal</span>\n{/snippet}\n\n{#snippet bold()}\n  <b>Bold</b>\n{/snippet}\n{#snippet italic()}\n  <i>Italic</i>\n{/snippet}\n```\n\n```js filename=\"Example.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Example } from './Example';\n\nexport default {\n  component: Example,\n  argTypes: {\n    label: {\n      control: { type: 'select' },\n      options: ['Normal', 'Bold', 'Italic'],\n      mapping: {\n        Bold: <b>Bold</b>,\n        Italic: <i>Italic</i>,\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Example.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Example } from './Example';\n\nconst meta = {\n  component: Example,\n  argTypes: {\n    label: {\n      control: { type: 'select' },\n      options: ['Normal', 'Bold', 'Italic'],\n      mapping: {\n        Bold: <b>Bold</b>,\n        Italic: <i>Italic</i>,\n      },\n    },\n  },\n} satisfies Meta<typeof Example>;\n\nexport default meta;\n```\n\n```js filename=\"Example.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nexport default {\n  component: 'demo-example',\n  argTypes: {\n    label: {\n      control: { type: 'select' },\n      options: ['Normal', 'Bold', 'Italic'],\n      mapping: {\n        Bold: html`<b>Bold</b>`,\n        Italic: html`<i>Italic</i>`,\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nconst meta: Meta = {\n  component: 'demo-example',\n  argTypes: {\n    label: {\n      control: { type: 'select' },\n      options: ['Normal', 'Bold', 'Italic'],\n      mapping: {\n        Bold: html`<b>Bold</b>`,\n        Italic: html`<i>Italic</i>`,\n      },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Example.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-example',\n  argTypes: {\n    label: {\n      control: { type: 'select' },\n      options: ['Normal', 'Bold', 'Italic'],\n      mapping: {\n        Bold: html`<b>Bold</b>`,\n        Italic: html`<i>Italic</i>`,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-example',\n  argTypes: {\n    label: {\n      control: { type: 'select' },\n      options: ['Normal', 'Bold', 'Italic'],\n      mapping: {\n        Bold: html`<b>Bold</b>`,\n        Italic: html`<i>Italic</i>`,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './Example';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    label: {\n      control: { type: 'select' },\n      options: ['Normal', 'Bold', 'Italic'],\n      mapping: {\n        Bold: <b>Bold</b>,\n        Italic: <i>Italic</i>,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Example.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './Example';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    label: {\n      control: { type: 'select' },\n      options: ['Normal', 'Bold', 'Italic'],\n      mapping: {\n        Bold: <b>Bold</b>,\n        Italic: <i>Italic</i>,\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/arg-types-name.md",
    "content": "```ts filename=\"Example.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Example } from './example.component';\n\nconst meta: Meta<Example> = {\n  component: Example,\n  argTypes: {\n    actualArgName: {\n      name: 'Friendly name',\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './example.component';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    actualArgName: {\n      name: 'Friendly name',\n    },\n  },\n});\n```\n\n```svelte filename=\"Example.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Example from './Example.svelte';\n\n  const { Story } = defineMeta({\n    component: Example,\n    argTypes: {\n      actualArgName: {\n        name: 'Friendly name',\n      },\n    },\n  });\n</script>\n```\n\n```js filename=\"Example.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Example from './Example.svelte';\n\nexport default {\n  component: Example,\n  argTypes: {\n    actualArgName: {\n      name: 'Friendly name',\n    },\n  },\n};\n```\n\n```js filename=\"Example.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Example } from './Example';\n\nexport default {\n  component: Example,\n  argTypes: {\n    actualArgName: {\n      name: 'Friendly name',\n    },\n  },\n};\n```\n\n```svelte filename=\"Example.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Example from './Example.svelte';\n\n  const { Story } = defineMeta({\n    component: Example,\n    argTypes: {\n      actualArgName: {\n        name: 'Friendly name',\n      },\n    },\n  });\n</script>\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Example from './Example.svelte';\n\nconst meta = {\n  component: Example,\n  argTypes: {\n    actualArgName: {\n      name: 'Friendly name',\n    },\n  },\n} satisfies Meta<typeof Example>;\n\nexport default meta;\n```\n\n```ts filename=\"Example.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Example } from './Example';\n\nconst meta = {\n  component: Example,\n  argTypes: {\n    actualArgName: {\n      name: 'Friendly name',\n    },\n  },\n} satisfies Meta<typeof Example>;\n\nexport default meta;\n```\n\n```js filename=\"Example.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-example',\n  argTypes: {\n    actualArgName: {\n      name: 'Friendly name',\n    },\n  },\n};\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-example',\n  argTypes: {\n    actualArgName: {\n      name: 'Friendly name',\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Example.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-example',\n  argTypes: {\n    actualArgName: {\n      name: 'Friendly name',\n    },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-example',\n  argTypes: {\n    actualArgName: {\n      name: 'Friendly name',\n    },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './Example';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    actualArgName: {\n      name: 'Friendly name',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Example.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './Example';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    actualArgName: {\n      name: 'Friendly name',\n    },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Example from './Example.vue';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    actualArgName: {\n      name: 'Friendly name',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Example.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Example from './Example.vue';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    actualArgName: {\n      name: 'Friendly name',\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/arg-types-options.md",
    "content": "```ts filename=\"Example.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Example } from './example.component';\n\nconst meta: Meta<Example> = {\n  component: Example,\n  argTypes: {\n    icon: {\n      options: ['arrow-up', 'arrow-down', 'loading'],\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './example.component';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    icon: {\n      options: ['arrow-up', 'arrow-down', 'loading'],\n    },\n  },\n});\n```\n\n```svelte filename=\"Example.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Example from './Example.svelte';\n\n  const { Story } = defineMeta({\n    component: Example,\n    argTypes: {\n      icon: {\n        options: ['arrow-up', 'arrow-down', 'loading'],\n      },\n    },\n  });\n</script>\n```\n\n```js filename=\"Example.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Example from './Example.svelte';\n\nexport default {\n  component: Example,\n  argTypes: {\n    icon: {\n      options: ['arrow-up', 'arrow-down', 'loading'],\n    },\n  },\n};\n```\n\n```js filename=\"Example.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Example } from './Example';\n\nexport default {\n  component: Example,\n  argTypes: {\n    icon: {\n      options: ['arrow-up', 'arrow-down', 'loading'],\n    },\n  },\n};\n```\n\n```svelte filename=\"Example.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Example from './Example.svelte';\n\n  const { Story } = defineMeta({\n    component: Example,\n    argTypes: {\n      icon: {\n        options: ['arrow-up', 'arrow-down', 'loading'],\n      },\n    },\n  });\n</script>\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Example from './Example.svelte';\n\nconst meta = {\n  component: Example,\n  argTypes: {\n    icon: {\n      options: ['arrow-up', 'arrow-down', 'loading'],\n    },\n  },\n} satisfies Meta<typeof Example>;\n\nexport default meta;\n```\n\n```ts filename=\"Example.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Example } from './Example';\n\nconst meta = {\n  component: Example,\n  argTypes: {\n    icon: {\n      options: ['arrow-up', 'arrow-down', 'loading'],\n    },\n  },\n} satisfies Meta<typeof Example>;\n\nexport default meta;\n```\n\n```js filename=\"Example.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-example',\n  argTypes: {\n    icon: {\n      options: ['arrow-up', 'arrow-down', 'loading'],\n    },\n  },\n};\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-example',\n  argTypes: {\n    icon: {\n      options: ['arrow-up', 'arrow-down', 'loading'],\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Example.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-example',\n  argTypes: {\n    icon: {\n      options: ['arrow-up', 'arrow-down', 'loading'],\n    },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-example',\n  argTypes: {\n    icon: {\n      options: ['arrow-up', 'arrow-down', 'loading'],\n    },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './Example';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    icon: {\n      options: ['arrow-up', 'arrow-down', 'loading'],\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Example.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './Example';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    icon: {\n      options: ['arrow-up', 'arrow-down', 'loading'],\n    },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Example from './Example.vue';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    icon: {\n      options: ['arrow-up', 'arrow-down', 'loading'],\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Example.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Example from './Example.vue';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    icon: {\n      options: ['arrow-up', 'arrow-down', 'loading'],\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/arg-types-table.md",
    "content": "```ts filename=\"Example.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Example } from './example.component';\n\nconst meta: Meta<Example> = {\n  component: Example,\n  argTypes: {\n    value: {\n      table: {\n        defaultValue: { summary: 0 },\n        type: { summary: 'number' },\n      },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './example.component';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: {\n      table: {\n        defaultValue: { summary: 0 },\n        type: { summary: 'number' },\n      },\n    },\n  },\n});\n```\n\n```svelte filename=\"Example.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Example from './Example.svelte';\n\n  const { Story } = defineMeta({\n    component: Example,\n    argTypes: {\n      value: {\n        table: {\n          defaultValue: { summary: 0 },\n          type: { summary: 'number' },\n        },\n      },\n    },\n  });\n</script>\n```\n\n```js filename=\"Example.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Example from './Example.svelte';\n\nexport default {\n  component: Example,\n  argTypes: {\n    value: {\n      table: {\n        defaultValue: { summary: 0 },\n        type: { summary: 'number' },\n      },\n    },\n  },\n};\n```\n\n```js filename=\"Example.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Example } from './Example';\n\nexport default {\n  component: Example,\n  argTypes: {\n    value: {\n      table: {\n        defaultValue: { summary: 0 },\n        type: { summary: 'number' },\n      },\n    },\n  },\n};\n```\n\n```svelte filename=\"Example.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Example from './Example.svelte';\n\n  const { Story } = defineMeta({\n    component: Example,\n    argTypes: {\n      value: {\n        table: {\n          defaultValue: { summary: 0 },\n          type: { summary: 'number' },\n        },\n      },\n    },\n  });\n</script>\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Example from './Example.svelte';\n\nconst meta = {\n  component: Example,\n  argTypes: {\n    value: {\n      table: {\n        defaultValue: { summary: 0 },\n        type: { summary: 'number' },\n      },\n    },\n  },\n} satisfies Meta<typeof Example>;\n\nexport default meta;\n```\n\n```ts filename=\"Example.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Example } from './Example';\n\nconst meta = {\n  component: Example,\n  argTypes: {\n    value: {\n      table: {\n        defaultValue: { summary: 0 },\n        type: { summary: 'number' },\n      },\n    },\n  },\n} satisfies Meta<typeof Example>;\n\nexport default meta;\n```\n\n```js filename=\"Example.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-example',\n  argTypes: {\n    value: {\n      table: {\n        defaultValue: { summary: 0 },\n        type: { summary: 'number' },\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-example',\n  argTypes: {\n    value: {\n      table: {\n        defaultValue: { summary: 0 },\n        type: { summary: 'number' },\n      },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Example.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-example',\n  argTypes: {\n    value: {\n      table: {\n        defaultValue: { summary: 0 },\n        type: { summary: 'number' },\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-example',\n  argTypes: {\n    value: {\n      table: {\n        defaultValue: { summary: 0 },\n        type: { summary: 'number' },\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './Example';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: {\n      table: {\n        defaultValue: { summary: 0 },\n        type: { summary: 'number' },\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Example.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './Example';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: {\n      table: {\n        defaultValue: { summary: 0 },\n        type: { summary: 'number' },\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Example from './Example.vue';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: {\n      table: {\n        defaultValue: { summary: 0 },\n        type: { summary: 'number' },\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Example.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Example from './Example.vue';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: {\n      table: {\n        defaultValue: { summary: 0 },\n        type: { summary: 'number' },\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/arg-types-type.md",
    "content": "```ts filename=\"Example.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Example } from './example.component';\n\nconst meta: Meta<Example> = {\n  component: Example,\n  argTypes: {\n    value: { type: 'number' },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './example.component';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: { type: 'number' },\n  },\n});\n```\n\n```svelte filename=\"Example.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Example from './Example.svelte';\n\n  const { Story } = defineMeta({\n    component: Example,\n    argTypes: {\n      value: { type: 'number' },\n    },\n  });\n</script>\n```\n\n```js filename=\"Example.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Example from './Example.svelte';\n\nexport default {\n  component: Example,\n  argTypes: {\n    value: { type: 'number' },\n  },\n};\n```\n\n```js filename=\"Example.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Example } from './Example';\n\nexport default {\n  component: Example,\n  argTypes: {\n    value: { type: 'number' },\n  },\n};\n```\n\n```svelte filename=\"Example.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Example from './Example.svelte';\n\n  const { Story } = defineMeta({\n    component: Example,\n    argTypes: {\n      value: { type: 'number' },\n    },\n  });\n</script>\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Example from './Example.svelte';\n\nconst meta = {\n  component: Example,\n  argTypes: {\n    value: { type: 'number' },\n  },\n} satisfies Meta<typeof Example>;\n\nexport default meta;\n```\n\n```ts filename=\"Example.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Example } from './Example';\n\nconst meta = {\n  component: Example,\n  argTypes: {\n    value: { type: 'number' },\n  },\n} satisfies Meta<typeof Example>;\n\nexport default meta;\n```\n\n```js filename=\"Example.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-example',\n  argTypes: {\n    value: { type: 'number' },\n  },\n};\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-example',\n  argTypes: {\n    value: { type: 'number' },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Example.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-example',\n  argTypes: {\n    value: { type: 'number' },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-example',\n  argTypes: {\n    value: { type: 'number' },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './Example';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: { type: 'number' },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Example.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Example } from './Example';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: { type: 'number' },\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Example from './Example.vue';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: { type: 'number' },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Example.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Example from './Example.vue';\n\nconst meta = preview.meta({\n  component: Example,\n  argTypes: {\n    value: { type: 'number' },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/args-in-preview.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // The default value of the theme arg for all stories\n  args: { theme: 'light' },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  // The default value of the theme arg for all stories\n  args: { theme: 'light' },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  // The default value of the theme arg for all stories\n  args: { theme: 'light' },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  // The default value of the theme arg for all stories\n  args: { theme: 'light' },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  // The default value of the theme arg for all stories\n  args: { theme: 'light' },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  // The default value of the theme arg for all stories\n  args: { theme: 'light' },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  // The default value of the theme arg for all stories\n  args: { theme: 'light' },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  // The default value of the theme arg for all stories\n  args: { theme: 'light' },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  // The default value of the theme arg for all stories\n  args: { theme: 'light' },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/args-usage-with-addons.md",
    "content": "```js filename=\"my-addon/src/manager.js|ts\" renderer=\"common\" language=\"js\"\nimport { useArgs } from 'storybook/manager-api';\n\nconst [args, updateArgs, resetArgs] = useArgs();\n\n// To update one or more args:\nupdateArgs({ key: 'value' });\n\n// To reset one (or more) args:\nresetArgs((argNames: ['key']));\n\n// To reset all args\nresetArgs();\n```\n"
  },
  {
    "path": "docs/_snippets/automock-register-full.md",
    "content": "```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, vue3-vite, sveltekit)\nimport type { Preview } from '@storybook/your-framework';\nimport { sb } from 'storybook/test';\n\n// 👇 Automatically replaces all exports from the `lib/session` local module with mock functions\nsb.mock(import('../lib/session.ts'));\n// 👇 Automatically replaces all exports from the `uuid` package in `node_modules` with mock functions\nsb.mock(import('uuid'));\n\nconst preview: Preview = {\n  // ...\n};\n\nexport default preview;\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { sb } from 'storybook/test';\n\n// 👇 Automatically replaces all exports from the `lib/session` local module with mock functions\nsb.mock('../lib/session.js');\n// 👇 Automatically replaces all exports from the `uuid` package in `node_modules` with mock functions\nsb.mock('uuid');\n\nexport default {\n  // ...\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Automatically replaces all exports from the `lib/session` local module with mock functions\nsb.mock(import('../lib/session.ts'));\n// 👇 Automatically replaces all exports from the `uuid` package in `node_modules` with mock functions\nsb.mock(import('uuid'));\n\nexport default definePreview({\n  // ...\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Automatically replaces all exports from the `lib/session` local module with mock functions\nsb.mock('../lib/session.js');\n// 👇 Automatically replaces all exports from the `uuid` package in `node_modules` with mock functions\nsb.mock('uuid');\n\nexport default definePreview({\n  // ...\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Automatically replaces all exports from the `lib/session` local module with mock functions\nsb.mock(import('../lib/session.ts'));\n// 👇 Automatically replaces all exports from the `uuid` package in `node_modules` with mock functions\nsb.mock(import('uuid'));\n\nexport default definePreview({\n  // ...\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Automatically replaces all exports from the `lib/session` local module with mock functions\nsb.mock('../lib/session.js');\n// 👇 Automatically replaces all exports from the `uuid` package in `node_modules` with mock functions\nsb.mock('uuid');\n\nexport default definePreview({\n  // ...\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Automatically replaces all exports from the `lib/session` local module with mock functions\nsb.mock(import('../lib/session.ts'));\n// 👇 Automatically replaces all exports from the `uuid` package in `node_modules` with mock functions\nsb.mock(import('uuid'));\n\nexport default definePreview({\n  // ...\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Automatically replaces all exports from the `lib/session` local module with mock functions\nsb.mock(import('../lib/session.ts'));\n// 👇 Automatically replaces all exports from the `uuid` package in `node_modules` with mock functions\nsb.mock(import('uuid'));\n\nexport default definePreview({\n  // ...\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Automatically replaces all exports from the `lib/session` local module with mock functions\nsb.mock('../lib/session.js');\n// 👇 Automatically replaces all exports from the `uuid` package in `node_modules` with mock functions\nsb.mock('uuid');\n\nexport default definePreview({\n  // ...\n});\n```\n"
  },
  {
    "path": "docs/_snippets/automock-register-mock-file.md",
    "content": "```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, vue3-vite, sveltekit)\nimport type { Preview } from '@storybook/your-framework';\nimport { sb } from 'storybook/test';\n\n// 👇 Replaces imports of this module with imports to `../lib/__mocks__/session.ts`\nsb.mock(import('../lib/session.ts'));\n// 👇 Replaces imports of this module with imports to `../__mocks__/uuid.ts`\nsb.mock(import('uuid'));\n\nconst preview: Preview = {\n  // ...\n};\n\nexport default preview;\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { sb } from 'storybook/test';\n\n// 👇 Replaces imports of this module with imports to `../lib/__mocks__/session.ts`\nsb.mock('../lib/session.js');\n// 👇 Replaces imports of this module with imports to `../__mocks__/uuid.ts`\nsb.mock('uuid');\n\nexport default {\n  // ...\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Replaces imports of this module with imports to `../lib/__mocks__/session.ts`\nsb.mock(import('../lib/session.ts'));\n// 👇 Replaces imports of this module with imports to `../__mocks__/uuid.ts`\nsb.mock(import('uuid'));\n\nexport default definePreview({\n  // ...\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Replaces imports of this module with imports to `../lib/__mocks__/session.ts`\nsb.mock('../lib/session.js');\n// 👇 Replaces imports of this module with imports to `../__mocks__/uuid.ts`\nsb.mock('uuid');\n\nexport default definePreview({\n  // ...\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Replaces imports of this module with imports to `../lib/__mocks__/session.ts`\nsb.mock(import('../lib/session.ts'));\n// 👇 Replaces imports of this module with imports to `../__mocks__/uuid.ts`\nsb.mock(import('uuid'));\n\nexport default definePreview({\n  // ...\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Replaces imports of this module with imports to `../lib/__mocks__/session.ts`\nsb.mock('../lib/session.js');\n// 👇 Replaces imports of this module with imports to `../__mocks__/uuid.ts`\nsb.mock('uuid');\n\nexport default definePreview({\n  // ...\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Replaces imports of this module with imports to `../lib/__mocks__/session.ts`\nsb.mock(import('../lib/session.ts'));\n// 👇 Replaces imports of this module with imports to `../__mocks__/uuid.ts`\nsb.mock(import('uuid'));\n\nexport default definePreview({\n  // ...\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Replaces imports of this module with imports to `../lib/__mocks__/session.ts`\nsb.mock(import('../lib/session.ts'));\n// 👇 Replaces imports of this module with imports to `../__mocks__/uuid.ts`\nsb.mock(import('uuid'));\n\nexport default definePreview({\n  // ...\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Replaces imports of this module with imports to `../lib/__mocks__/session.ts`\nsb.mock('../lib/session.js');\n// 👇 Replaces imports of this module with imports to `../__mocks__/uuid.ts`\nsb.mock('uuid');\n\nexport default definePreview({\n  // ...\n});\n```\n"
  },
  {
    "path": "docs/_snippets/automock-register-spy.md",
    "content": "```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, vue3-vite, sveltekit)\nimport type { Preview } from '@storybook/your-framework';\nimport { sb } from 'storybook/test';\n\n// 👇 Automatically spies on all exports from the `lib/session` local module\nsb.mock(import('../lib/session.ts'), { spy: true });\n// 👇 Automatically spies on all exports from the `uuid` package in `node_modules`\nsb.mock(import('uuid'), { spy: true });\n\nconst preview: Preview = {\n  // ...\n};\n\nexport default preview;\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { sb } from 'storybook/test';\n\n// 👇 Automatically spies on all exports from the `lib/session` local module\nsb.mock('../lib/session.js', { spy: true });\n// 👇 Automatically spies on all exports from the `uuid` package in `node_modules`\nsb.mock('uuid', { spy: true });\n\nexport default {\n  // ...\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Automatically spies on all exports from the `lib/session` local module\nsb.mock(import('../lib/session.ts'), { spy: true });\n// 👇 Automatically spies on all exports from the `uuid` package in `node_modules`\nsb.mock(import('uuid'), { spy: true });\n\nexport default definePreview({\n  // ...\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Automatically spies on all exports from the `lib/session` local module\nsb.mock('../lib/session.js', { spy: true });\n// 👇 Automatically spies on all exports from the `uuid` package in `node_modules`\nsb.mock('uuid', { spy: true });\n\nexport default definePreview({\n  // ...\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Automatically spies on all exports from the `lib/session` local module\nsb.mock(import('../lib/session.ts'), { spy: true });\n// 👇 Automatically spies on all exports from the `uuid` package in `node_modules`\nsb.mock(import('uuid'), { spy: true });\n\nexport default definePreview({\n  // ...\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Automatically spies on all exports from the `lib/session` local module\nsb.mock('../lib/session.js', { spy: true });\n// 👇 Automatically spies on all exports from the `uuid` package in `node_modules`\nsb.mock('uuid', { spy: true });\n\nexport default definePreview({\n  // ...\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Automatically spies on all exports from the `lib/session` local module\nsb.mock(import('../lib/session.ts'), { spy: true });\n// 👇 Automatically spies on all exports from the `uuid` package in `node_modules`\nsb.mock(import('uuid'), { spy: true });\n\nexport default definePreview({\n  // ...\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Automatically spies on all exports from the `lib/session` local module\nsb.mock(import('../lib/session.ts'), { spy: true });\n// 👇 Automatically spies on all exports from the `uuid` package in `node_modules`\nsb.mock(import('uuid'), { spy: true });\n\nexport default definePreview({\n  // ...\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { sb } from 'storybook/test';\n\n// 👇 Automatically spies on all exports from the `lib/session` local module\nsb.mock('../lib/session.js', { spy: true });\n// 👇 Automatically spies on all exports from the `uuid` package in `node_modules`\nsb.mock('uuid', { spy: true });\n\nexport default definePreview({\n  // ...\n});\n```\n"
  },
  {
    "path": "docs/_snippets/automocked-modules-in-story.md",
    "content": "```ts filename=\"AuthButton.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\nimport { expect, mocked } from 'storybook/test';\n\nimport { AuthButton } from './auth-button.component';\n\nimport { v4 as uuidv4 } from 'uuid';\nimport { getUserFromSession } from '../lib/session';\n\nconst meta: Meta<AuthButton> = {\n  component: AuthButton,\n  // 👇 This will run before each story is rendered\n  beforeEach: async () => {\n    // 👇 Force known, consistent behavior for mocked modules\n    mocked(uuidv4).mockReturnValue('1234-5678-90ab-cdef');\n    mocked(getUserFromSession).mockReturnValue({ name: 'John Doe' });\n  },\n};\nexport default meta;\n\ntype Story = StoryObj<AuthButton>;\n\nexport const LogIn: Story = {\n  play: async ({ canvas, userEvent }) => {\n    const button = canvas.getByRole('button', { name: 'Sign in' });\n    userEvent.click(button);\n\n    // Assert that the getUserFromSession function was called\n    expect(getUserFromSession).toHaveBeenCalled();\n  },\n};\n```\n\n```ts filename=\"AuthButton.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { expect, mocked } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { AuthButton } from './auth-button.component';\n\nimport { v4 as uuidv4 } from 'uuid';\nimport { getUserFromSession } from '../lib/session';\n\nconst meta = preview.meta({\n  component: AuthButton,\n  // 👇 This will run before each story is rendered\n  beforeEach: async () => {\n    // 👇 Force known, consistent behavior for mocked modules\n    mocked(uuidv4).mockReturnValue('1234-5678-90ab-cdef');\n    mocked(getUserFromSession).mockReturnValue({ name: 'John Doe' });\n  },\n});\n\nexport const LogIn = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    const button = canvas.getByRole('button', { name: 'Sign in' });\n    userEvent.click(button);\n\n    // Assert that the getUserFromSession function was called\n    expect(getUserFromSession).toHaveBeenCalled();\n  },\n});\n```\n\n```ts filename=\"AuthButton.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the name of your framework (e.g. react-vite, vue3-vite, etc.)\nimport type { Meta, StoryObj } from '@storybook/your-framework';\nimport { expect, mocked } from 'storybook/test';\n\nimport { AuthButton } from './AuthButton';\n\nimport { v4 as uuidv4 } from 'uuid';\nimport { getUserFromSession } from '../lib/session';\n\nconst meta = {\n  component: AuthButton,\n  // 👇 This will run before each story is rendered\n  beforeEach: async () => {\n    // 👇 Force known, consistent behavior for mocked modules\n    mocked(uuidv4).mockReturnValue('1234-5678-90ab-cdef');\n    mocked(getUserFromSession).mockReturnValue({ name: 'John Doe' });\n  },\n} satisfies Meta<typeof AuthButton>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const LogIn: Story = {\n  play: async ({ canvas, userEvent }) => {\n    const button = canvas.getByRole('button', { name: 'Sign in' });\n    userEvent.click(button);\n\n    // Assert that the getUserFromSession function was called\n    expect(getUserFromSession).toHaveBeenCalled();\n  },\n};\n```\n\n```js filename=\"AuthButton.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { expect } from 'storybook/test';\n\nimport { AuthButton } from './AuthButton';\n\nimport { v4 as uuidv4 } from 'uuid';\nimport { getUserFromSession } from '../lib/session';\n\nexport default {\n  component: AuthButton,\n  // 👇 This will run before each story is rendered\n  beforeEach: async () => {\n    // 👇 Force known, consistent behavior for mocked modules\n    uuidv4.mockReturnValue('1234-5678-90ab-cdef');\n    getUserFromSession.mockReturnValue({ name: 'John Doe' });\n  },\n};\n\nexport const LogIn = {\n  play: async ({ canvas, userEvent }) => {\n    const button = canvas.getByRole('button', { name: 'Sign in' });\n    userEvent.click(button);\n\n    // Assert that the getUserFromSession function was called\n    expect(getUserFromSession).toHaveBeenCalled();\n  },\n};\n```\n\n```svelte filename=\"AuthButton.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import { expect, mocked } from 'storybook/test';\n\n  import AuthButton from './AuthButton.svelte';\n\n  import { v4 as uuidv4 } from 'uuid';\n  import { getUserFromSession } from '../lib/session';\n\n  const { Story } = defineMeta({\n    component: AuthButton,\n    // 👇 This will run before each story is rendered\n    beforeEach: async () => {\n      // 👇 Force known, consistent behavior for mocked modules\n      mocked(uuidv4).mockReturnValue('1234-5678-90ab-cdef');\n      mocked(getUserFromSession).mockReturnValue({ name: 'John Doe' });\n    },\n  });\n</script>\n\n<Story\n  name=\"LogIn\"\n  play={async ({ canvas, userEvent }) => {\n    const button = canvas.getByRole('button', { name: 'Sign in' });\n    userEvent.click(button);\n\n    // Assert that the getUserFromSession function was called\n    expect(getUserFromSession).toHaveBeenCalled();\n  }}\n/>\n```\n\n```ts filename=\"AuthButton.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\nimport { expect, mocked } from 'storybook/test';\n\nimport AuthButton from './AuthButton.svelte';\n\nimport { v4 as uuidv4 } from 'uuid';\nimport { getUserFromSession } from '../lib/session';\n\nconst meta = {\n  component: AuthButton,\n  // 👇 This will run before each story is rendered\n  beforeEach: async () => {\n    // 👇 Force known, consistent behavior for mocked modules\n    mocked(uuidv4).mockReturnValue('1234-5678-90ab-cdef');\n    mocked(getUserFromSession).mockReturnValue({ name: 'John Doe' });\n  },\n} satisfies Meta<typeof AuthButton>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const LogIn: Story = {\n  play: async ({ canvas, userEvent }) => {\n    const button = canvas.getByRole('button', { name: 'Sign in' });\n    userEvent.click(button);\n\n    // Assert that the getUserFromSession function was called\n    expect(getUserFromSession).toHaveBeenCalled();\n  },\n};\n```\n\n```svelte filename=\"AuthButton.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import { expect } from 'storybook/test';\n\n  import { AuthButton } from './AuthButton.svelte';\n\n  import { v4 as uuidv4 } from 'uuid';\n  import { getUserFromSession } from '../lib/session';\n\n  const { Story } = defineMeta({\n    component: AuthButton,\n    // 👇 This will run before each story is rendered\n    beforeEach: async () => {\n      // 👇 Force known, consistent behavior for mocked modules\n      uuidv4.mockReturnValue('1234-5678-90ab-cdef');\n      getUserFromSession.mockReturnValue({ name: 'John Doe' });\n    },\n  });\n</script>\n\n<Story\n  name=\"LogIn\"\n  play={async ({ canvas, userEvent }) => {\n    const button = canvas.getByRole('button', { name: 'Sign in' });\n    userEvent.click(button);\n\n    // Assert that the getUserFromSession function was called\n    expect(getUserFromSession).toHaveBeenCalled();\n  }}\n/>\n```\n\n```js filename=\"AuthButton.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport { expect } from 'storybook/test';\n\nimport AuthButton from './AuthButton.svelte';\n\nimport { v4 as uuidv4 } from 'uuid';\nimport { getUserFromSession } from '../lib/session';\n\nexport default {\n  component: AuthButton,\n  // 👇 This will run before each story is rendered\n  beforeEach: async () => {\n    // 👇 Force known, consistent behavior for mocked modules\n    uuidv4.mockReturnValue('1234-5678-90ab-cdef');\n    getUserFromSession.mockReturnValue({ name: 'John Doe' });\n  },\n};\n\nexport const LogIn = {\n  play: async ({ canvas, userEvent }) => {\n    const button = canvas.getByRole('button', { name: 'Sign in' });\n    userEvent.click(button);\n\n    // Assert that the getUserFromSession function was called\n    expect(getUserFromSession).toHaveBeenCalled();\n  },\n};\n```\n\n```ts filename=\"AuthButton.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\nimport { expect, mocked } from 'storybook/test';\n\nimport { v4 as uuidv4 } from 'uuid';\nimport { getUserFromSession } from '../lib/session';\n\nconst meta: Meta = {\n  component: 'demo-auth-button',\n  // 👇 This will run before each story is rendered\n  beforeEach: async () => {\n    // 👇 Force known, consistent behavior for mocked modules\n    mocked(uuidv4).mockReturnValue('1234-5678-90ab-cdef');\n    mocked(getUserFromSession).mockReturnValue({ name: 'John Doe' });\n  },\n};\nexport default meta;\n\ntype Story = StoryObj;\n\nexport const LogIn: Story = {\n  play: async ({ canvas, userEvent }) => {\n    const button = canvas.getByRole('button', { name: 'Sign in' });\n    userEvent.click(button);\n\n    // Assert that the getUserFromSession function was called\n    expect(getUserFromSession).toHaveBeenCalled();\n  },\n};\n```\n\n```js filename=\"AuthButton.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { expect } from 'storybook/test';\n\nimport { v4 as uuidv4 } from 'uuid';\nimport { getUserFromSession } from '../lib/session';\n\nexport default {\n  component: 'demo-auth-button',\n  // 👇 This will run before each story is rendered\n  beforeEach: async () => {\n    // 👇 Force known, consistent behavior for mocked modules\n    uuidv4.mockReturnValue('1234-5678-90ab-cdef');\n    getUserFromSession.mockReturnValue({ name: 'John Doe' });\n  },\n};\n\nexport const LogIn = {\n  play: async ({ canvas, userEvent }) => {\n    const button = canvas.getByRole('button', { name: 'Sign in' });\n    userEvent.click(button);\n\n    // Assert that the getUserFromSession function was called\n    expect(getUserFromSession).toHaveBeenCalled();\n  },\n};\n```\n\n```ts filename=\"AuthButton.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { expect, mocked } from 'storybook/test';\n\nimport { v4 as uuidv4 } from 'uuid';\nimport { getUserFromSession } from '../lib/session';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-auth-button',\n  // 👇 This will run before each story is rendered\n  beforeEach: async () => {\n    // 👇 Force known, consistent behavior for mocked modules\n    mocked(uuidv4).mockReturnValue('1234-5678-90ab-cdef');\n    mocked(getUserFromSession).mockReturnValue({ name: 'John Doe' });\n  },\n});\n\nexport const LogIn = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    const button = canvas.getByRole('button', { name: 'Sign in' });\n    userEvent.click(button);\n\n    // Assert that the getUserFromSession function was called\n    expect(getUserFromSession).toHaveBeenCalled();\n  },\n});\n```\n\n```js filename=\"AuthButton.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\nimport { v4 as uuidv4 } from 'uuid';\nimport { getUserFromSession } from '../lib/session';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-auth-button',\n  // 👇 This will run before each story is rendered\n  beforeEach: async () => {\n    // 👇 Force known, consistent behavior for mocked modules\n    uuidv4.mockReturnValue('1234-5678-90ab-cdef');\n    getUserFromSession.mockReturnValue({ name: 'John Doe' });\n  },\n});\n\nexport const LogIn = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    const button = canvas.getByRole('button', { name: 'Sign in' });\n    userEvent.click(button);\n\n    // Assert that the getUserFromSession function was called\n    expect(getUserFromSession).toHaveBeenCalled();\n  },\n});\n```\n\n```ts filename=\"AuthButton.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { expect, mocked } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { AuthButton } from './AuthButton';\n\nimport { v4 as uuidv4 } from 'uuid';\nimport { getUserFromSession } from '../lib/session';\n\nconst meta = preview.meta({\n  component: AuthButton,\n  // 👇 This will run before each story is rendered\n  beforeEach: async () => {\n    // 👇 Force known, consistent behavior for mocked modules\n    mocked(uuidv4).mockReturnValue('1234-5678-90ab-cdef');\n    mocked(getUserFromSession).mockReturnValue({ name: 'John Doe' });\n  },\n});\n\nexport const LogIn = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    const button = canvas.getByRole('button', { name: 'Sign in' });\n    userEvent.click(button);\n\n    // Assert that the getUserFromSession function was called\n    expect(getUserFromSession).toHaveBeenCalled();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"AuthButton.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { AuthButton } from './AuthButton';\n\nimport { v4 as uuidv4 } from 'uuid';\nimport { getUserFromSession } from '../lib/session';\n\nconst meta = preview.meta({\n  component: AuthButton,\n  // 👇 This will run before each story is rendered\n  beforeEach: async () => {\n    // 👇 Force known, consistent behavior for mocked modules\n    uuidv4.mockReturnValue('1234-5678-90ab-cdef');\n    getUserFromSession.mockReturnValue({ name: 'John Doe' });\n  },\n});\n\nexport const LogIn = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    const button = canvas.getByRole('button', { name: 'Sign in' });\n    userEvent.click(button);\n\n    // Assert that the getUserFromSession function was called\n    expect(getUserFromSession).toHaveBeenCalled();\n  },\n});\n```\n\n```ts filename=\"AuthButton.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { expect, mocked } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport AuthButton from './AuthButton.vue';\n\nimport { v4 as uuidv4 } from 'uuid';\nimport { getUserFromSession } from '../lib/session';\n\nconst meta = preview.meta({\n  component: AuthButton,\n  // 👇 This will run before each story is rendered\n  beforeEach: async () => {\n    // 👇 Force known, consistent behavior for mocked modules\n    mocked(uuidv4).mockReturnValue('1234-5678-90ab-cdef');\n    mocked(getUserFromSession).mockReturnValue({ name: 'John Doe' });\n  },\n});\n\nexport const LogIn = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    const button = canvas.getByRole('button', { name: 'Sign in' });\n    userEvent.click(button);\n\n    // Assert that the getUserFromSession function was called\n    expect(getUserFromSession).toHaveBeenCalled();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"AuthButton.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport AuthButton from './AuthButton.vue';\n\nimport { v4 as uuidv4 } from 'uuid';\nimport { getUserFromSession } from '../lib/session';\n\nconst meta = preview.meta({\n  component: AuthButton,\n  // 👇 This will run before each story is rendered\n  beforeEach: async () => {\n    // 👇 Force known, consistent behavior for mocked modules\n    uuidv4.mockReturnValue('1234-5678-90ab-cdef');\n    getUserFromSession.mockReturnValue({ name: 'John Doe' });\n  },\n});\n\nexport const LogIn = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    const button = canvas.getByRole('button', { name: 'Sign in' });\n    userEvent.click(button);\n\n    // Assert that the getUserFromSession function was called\n    expect(getUserFromSession).toHaveBeenCalled();\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/before-all-in-preview.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { init } from '../project-bootstrap';\n\nexport default {\n  async beforeAll() {\n    await init();\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nimport { init } from '../project-bootstrap';\n\nconst preview: Preview = {\n  async beforeAll() {\n    await init();\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { init } from '../project-bootstrap';\n\nexport default definePreview({\n  async beforeAll() {\n    await init();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { init } from '../project-bootstrap';\n\nexport default definePreview({\n  async beforeAll() {\n    await init();\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport { init } from '../project-bootstrap';\n\nexport default definePreview({\n  async beforeAll() {\n    await init();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport { init } from '../project-bootstrap';\n\nexport default definePreview({\n  async beforeAll() {\n    await init();\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nimport { init } from '../project-bootstrap';\n\nexport default definePreview({\n  async beforeAll() {\n    await init();\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { init } from '../project-bootstrap';\n\nexport default definePreview({\n  async beforeAll() {\n    await init();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { init } from '../project-bootstrap';\n\nexport default definePreview({\n  async beforeAll() {\n    await init();\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/before-each-in-meta-mock-date.md",
    "content": "```ts filename=\"Page.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport MockDate from 'mockdate';\n\nimport { Page } from './Page.component';\n\nconst meta: Meta<Page> = {\n  component: Page,\n  // 👇 Set the value of Date for every story in the file\n  async beforeEach() {\n    MockDate.set('2024-02-14');\n\n    // 👇 Reset the Date after each story\n    return () => {\n      MockDate.reset();\n    };\n  },\n};\nexport default meta;\n\ntype Story = StoryObj<Page>;\n\nexport const Basic: Story = {\n  async play({ canvas }) {\n    // ... This will run with the mocked Date\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport MockDate from 'mockdate';\n\nimport preview from '../.storybook/preview';\n\nimport { Page } from './Page.component';\n\nconst meta = preview.meta({\n  component: Page,\n  // 👇 Set the value of Date for every story in the file\n  async beforeEach() {\n    MockDate.set('2024-02-14');\n\n    // 👇 Reset the Date after each story\n    return () => {\n      MockDate.reset();\n    };\n  },\n});\n\nexport const Basic = meta.story({\n  async play({ canvas }) {\n    // ... This will run with the mocked Date\n  },\n});\n```\n\n```svelte filename=\"Page.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MockDate from 'mockdate';\n\n  import Page from './Page.svelte';\n\n  const { Story } = defineMeta({\n    component: Page,\n    // 👇 Set the value of Date for every story in the file\n    async beforeEach() {\n      MockDate.set('2024-02-14');\n\n      // 👇 Reset the Date after each story\n      return () => {\n        MockDate.reset();\n      };\n    },\n  });\n</script>\n\n<Story name=\"Default\" play={async ({ canvas }) => {\n  // ... This will run with the mocked Date\n  }}\n/>\n```\n\n```js filename=\"Page.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport MockDate from 'mockdate';\n\nimport Page from './Page.svelte';\n\nexport default {\n  component: Page,\n  // 👇 Set the value of Date for every story in the file\n  async beforeEach() {\n    MockDate.set('2024-02-14');\n\n    // 👇 Reset the Date after each story\n    return () => {\n      MockDate.reset();\n    };\n  },\n};\n\nexport const Basic = {\n  async play({ canvas }) {\n    // ... This will run with the mocked Date\n  },\n};\n```\n\n```js filename=\"Page.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport MockDate from 'mockdate';\n\nimport { Page } from './Page';\n\nexport default {\n  component: Page,\n  // 👇 Set the value of Date for every story in the file\n  async beforeEach() {\n    MockDate.set('2024-02-14');\n\n    // 👇 Reset the Date after each story\n    return () => {\n      MockDate.reset();\n    };\n  },\n};\n\nexport const Basic = {\n  async play({ canvas }) {\n    // ... This will run with the mocked Date\n  },\n};\n```\n\n```svelte filename=\"Page.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MockDate from 'mockdate';\n\n  import Page from './Page.svelte';\n\n  const { Story } = defineMeta({\n    component: Page,\n    // 👇 Set the value of Date for every story in the file\n    async beforeEach() {\n      MockDate.set('2024-02-14');\n\n      // 👇 Reset the Date after each story\n      return () => {\n        MockDate.reset();\n      };\n    },\n  });\n</script>\n\n<Story name=\"Default\" play={async ({ canvas }) => {\n  // ... This will run with the mocked Date\n  }}\n/>\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport MockDate from 'mockdate';\n\nimport Page from './Page.svelte';\n\nconst meta = {\n  component: Page,\n  // 👇 Set the value of Date for every story in the file\n  async beforeEach() {\n    MockDate.set('2024-02-14');\n\n    // 👇 Reset the Date after each story\n    return () => {\n      MockDate.reset();\n    };\n  },\n} satisfies Meta<typeof Page>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  async play({ canvas }) {\n    // ... This will run with the mocked Date\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport MockDate from 'mockdate';\n\nimport { Page } from './Page';\n\nconst meta = {\n  component: Page,\n  // 👇 Set the value of Date for every story in the file\n  async beforeEach() {\n    MockDate.set('2024-02-14');\n\n    // 👇 Reset the Date after each story\n    return () => {\n      MockDate.reset();\n    };\n  },\n} satisfies Meta<typeof Page>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  async play({ canvas }) {\n    // ... This will run with the mocked Date\n  },\n};\n```\n\n```js filename=\"Page.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport MockDate from 'mockdate';\n\nexport default {\n  component: 'my-page',\n  // 👇 Set the value of Date for every story in the file\n  async beforeEach() {\n    MockDate.set('2024-02-14');\n\n    // 👇 Reset the Date after each story\n    return () => {\n      MockDate.reset();\n    };\n  },\n};\n\nexport const Basic = {\n  async play({ canvas }) {\n    // ... This will run with the mocked Date\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport MockDate from 'mockdate';\n\nconst meta: Meta = {\n  component: 'my-page',\n  // 👇 Set the value of Date for every story in the file\n  async beforeEach() {\n    MockDate.set('2024-02-14');\n\n    // 👇 Reset the Date after each story\n    return () => {\n      MockDate.reset();\n    };\n  },\n};\nexport default meta;\n\ntype Story = StoryObj;\n\nexport const Basic: Story = {\n  async play({ canvas }) {\n    // ... This will run with the mocked Date\n  },\n};\n```\n\n```js filename=\"Page.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport MockDate from 'mockdate';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-page',\n  // 👇 Set the value of Date for every story in the file\n  async beforeEach() {\n    MockDate.set('2024-02-14');\n\n    // 👇 Reset the Date after each story\n    return () => {\n      MockDate.reset();\n    };\n  },\n});\n\nexport const Basic = meta.story({\n  async play({ canvas }) {\n    // ... This will run with the mocked Date\n  },\n});\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport MockDate from 'mockdate';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-page',\n  // 👇 Set the value of Date for every story in the file\n  async beforeEach() {\n    MockDate.set('2024-02-14');\n\n    // 👇 Reset the Date after each story\n    return () => {\n      MockDate.reset();\n    };\n  },\n});\n\nexport const Basic = meta.story({\n  async play({ canvas }) {\n    // ... This will run with the mocked Date\n  },\n});\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport MockDate from 'mockdate';\n\nimport preview from '../.storybook/preview';\n\nimport { Page } from './Page';\n\nconst meta = preview.meta({\n  component: Page,\n  // 👇 Set the value of Date for every story in the file\n  async beforeEach() {\n    MockDate.set('2024-02-14');\n\n    // 👇 Reset the Date after each story\n    return () => {\n      MockDate.reset();\n    };\n  },\n});\n\nexport const Basic = meta.story({\n  async play({ canvas }) {\n    // ... This will run with the mocked Date\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Page.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport MockDate from 'mockdate';\n\nimport preview from '../.storybook/preview';\n\nimport { Page } from './Page';\n\nconst meta = preview.meta({\n  component: Page,\n  // 👇 Set the value of Date for every story in the file\n  async beforeEach() {\n    MockDate.set('2024-02-14');\n\n    // 👇 Reset the Date after each story\n    return () => {\n      MockDate.reset();\n    };\n  },\n});\n\nexport const Basic = meta.story({\n  async play({ canvas }) {\n    // ... This will run with the mocked Date\n  },\n});\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport MockDate from 'mockdate';\n\nimport preview from '../.storybook/preview';\n\nimport Page from './Page.vue';\n\nconst meta = preview.meta({\n  component: Page,\n  // 👇 Set the value of Date for every story in the file\n  async beforeEach() {\n    MockDate.set('2024-02-14');\n\n    // 👇 Reset the Date after each story\n    return () => {\n      MockDate.reset();\n    };\n  },\n});\n\nexport const Basic = meta.story({\n  async play({ canvas }) {\n    // ... This will run with the mocked Date\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Page.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport MockDate from 'mockdate';\n\nimport preview from '../.storybook/preview';\n\nimport Page from './Page.vue';\n\nconst meta = preview.meta({\n  component: Page,\n  // 👇 Set the value of Date for every story in the file\n  async beforeEach() {\n    MockDate.set('2024-02-14');\n\n    // 👇 Reset the Date after each story\n    return () => {\n      MockDate.reset();\n    };\n  },\n});\n\nexport const Basic = meta.story({\n  async play({ canvas }) {\n    // ... This will run with the mocked Date\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/before-each-in-preview.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport MockDate from 'mockdate';\n\nexport default {\n  async beforeEach() {\n    MockDate.reset();\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nimport MockDate from 'mockdate';\n\nconst preview: Preview = {\n  async beforeEach() {\n    MockDate.reset();\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport MockDate from 'mockdate';\n\nexport default definePreview({\n  async beforeEach() {\n    MockDate.reset();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport MockDate from 'mockdate';\n\nexport default definePreview({\n  async beforeEach() {\n    MockDate.reset();\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport MockDate from 'mockdate';\n\nexport default definePreview({\n  async beforeEach() {\n    MockDate.reset();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport MockDate from 'mockdate';\n\nexport default definePreview({\n  async beforeEach() {\n    MockDate.reset();\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nimport MockDate from 'mockdate';\n\nexport default definePreview({\n  async beforeEach() {\n    MockDate.reset();\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport MockDate from 'mockdate';\n\nexport default definePreview({\n  async beforeEach() {\n    MockDate.reset();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport MockDate from 'mockdate';\n\nexport default definePreview({\n  async beforeEach() {\n    MockDate.reset();\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/best-practices-in-story.md",
    "content": "```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\n// ✅ Good - shows the default state\nexport const Basic = {};\n\n// ✅ Good - demonstrates a specific use case\nexport const Primary = {\n  args: { primary: true },\n};\n\n// ✅ Good - even though this story renders more than one button,\n// they both demonstrate the same concept of a disabled button\nexport const Disabled = {\n  args: { disabled: true },\n  render: (args) => (\n    <>\n      <Button {...args}>Disabled Button</Button>\n      <Button {...args} primary>\n        Disabled Primary Button\n      </Button>\n    </>\n  ),\n};\n\n// ❌ Bad - demonstrates too many concepts at once, making\n// it less clear and less useful as a reference for agents\nexport const SizesAndVariants = {\n  render: () => (\n    <>\n      <Button size=\"small\">Small Button</Button>\n      <Button>Medium Button</Button>\n      <Button size=\"large\">Large Button</Button>\n      <Button variant=\"outline\">Outline Button</Button>\n      <Button variant=\"text\">Text Button</Button>\n    </>\n  ),\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n// ✅ Good to show the default state\nexport const Basic: Story = {};\n\n// ✅ Good to demonstrate a specific use case\nexport const Primary: Story = {\n  args: { primary: true },\n};\n\n// ✅ Good - even though this story renders more than one button,\n// they both demonstrate the same concept of a disabled button\nexport const Disabled: Story = {\n  args: { disabled: true },\n    render: (args) => (\n      <>\n      <Button {...args}>Disabled Button</Button>\n      <Button {...args} primary>\n        Disabled Primary Button\n      </Button>\n    </>\n  ),\n};\n\n// ❌ Bad - demonstrates too many concepts at once, making\n// it less clear and less useful as a reference for agents\nexport const SizesAndVariants: Story = {\n  render: () => (\n    <>\n      <Button size=\"small\">Small Button</Button>\n      <Button>Medium Button</Button>\n      <Button size=\"large\">Large Button</Button>\n      <Button variant=\"outline\">Outline Button</Button>\n      <Button variant=\"text\">Text Button</Button>\n    </>\n  ),\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\n// ✅ Good to show the default state\nexport const Basic = meta.story();\n\n// ✅ Good to demonstrate a specific use case\nexport const Primary = meta.story({\n  args: { primary: true },\n});\n\n// ✅ Good - even though this story renders more than one button,\n// they both demonstrate the same concept of a disabled button\nexport const Disabled = meta.story({\n  args: { disabled: true },\n  render: (args) => (\n    <>\n      <Button {...args}>Disabled Button</Button>\n      <Button {...args} primary>\n        Disabled Primary Button\n      </Button>\n    </>\n  ),\n});\n\n// ❌ Bad - demonstrates too many concepts at once, making\n// it less clear and less useful as a reference for agents\nexport const SizesAndVariants = meta.story({\n  render: () => (\n    <>\n      <Button size=\"small\">Small Button</Button>\n      <Button>Medium Button</Button>\n      <Button size=\"large\">Large Button</Button>\n      <Button variant=\"outline\">Outline Button</Button>\n      <Button variant=\"text\">Text Button</Button>\n    </>\n  ),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\n// ✅ Good to show the default state\nexport const Basic = meta.story();\n\n// ✅ Good to demonstrate a specific use case\nexport const Primary = meta.story({\n  args: { primary: true },\n});\n\n// ✅ Good - even though this story renders more than one button,\n// they both demonstrate the same concept of a disabled button\nexport const Disabled = meta.story({\n  args: { disabled: true },\n  render: (args) => (\n    <>\n      <Button {...args}>Disabled Button</Button>\n      <Button {...args} primary>\n        Disabled Primary Button\n      </Button>\n    </>\n  ),\n});\n\n// ❌ Bad - demonstrates too many concepts at once, making\n// it less clear and less useful as a reference for agents\nexport const SizesAndVariants = meta.story({\n  render: () => (\n    <>\n      <Button size=\"small\">Small Button</Button>\n      <Button>Medium Button</Button>\n      <Button size=\"large\">Large Button</Button>\n      <Button variant=\"outline\">Outline Button</Button>\n      <Button variant=\"text\">Text Button</Button>\n    </>\n  ),\n});\n```\n"
  },
  {
    "path": "docs/_snippets/build-storybook-production-mode.md",
    "content": "```shell renderer=\"angular\" language=\"js\" tabTitle=\"with-builder\"\n# Builds Storybook with Angular's custom builder\n# See https://storybook.js.org/docs/get-started/angular\n# to learn how to create the custom builder\nng run my-project:build-storybook\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm run build-storybook\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm run build-storybook\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn build-storybook\n```\n"
  },
  {
    "path": "docs/_snippets/button-component-with-proptypes.md",
    "content": "```ts filename=\"my-button.component.ts\" renderer=\"angular\" language=\"ts\"\nimport { Component, Input } from '@angular/core';\n\n@Component({\n  selector: 'my-button',\n  template: ` <button type=\"button\" [disabled]=\"isDisabled\">\n    {{ content }}\n  </button>`,\n  styleUrls: ['./button.css'],\n})\nexport class ButtonComponent {\n  /**\n   * Checks if the button should be disabled\n   */\n  @Input()\n  isDisabled: boolean;\n\n  /**\n  The display content of the button\n  */\n  @Input()\n  content: string;\n}\n```\n\n```js filename=\"Button.js|jsx\" renderer=\"react\" language=\"js\"\nimport React from 'react';\n\nimport PropTypes from 'prop-types';\n\nexport function Button({ isDisabled, content }) {\n  return (\n    <button type=\"button\" disabled={isDisabled}>\n      {content}\n    </button>\n  );\n}\n\nButton.propTypes = {\n  /**\n   Checks if the button should be disabled\n  */\n  isDisabled: PropTypes.bool.isRequired,\n  /**\n  The display content of the button\n  */\n  content: PropTypes.string.isRequired,\n};\n```\n\n```tsx filename=\"Button.ts|tsx\" renderer=\"react\" language=\"ts\"\nexport interface ButtonProps {\n  /**\n   * Checks if the button should be disabled\n   */\n  isDisabled: boolean;\n  /**\n  The display content of the button\n  */\n  content: string;\n}\n\nexport const Button: React.FC<ButtonProps> = ({ isDisabled = false, content = '' }) => {\n  return (\n    <button type=\"button\" disabled={isDisabled}>\n      {content}\n    </button>\n  );\n};\n```\n\n```svelte filename=\"Button.svelte\" renderer=\"svelte\" language=\"js\"\n<script>\n  /**\n   * A Button Component\n   * @component\n   */\n\n  /**\n   * Disable the button\n   * @required\n   */\n  export let disabled = false;\n\n  /**\n   * Button content\n   * @required\n   */\n  export let content = '';\n<script/>\n\n<button type=\"button\" {disabled}>{content}</button>\n```\n\n```html filename=\"Button.vue\" renderer=\"vue\" language=\"js\"\n<template>\n  <button type=\"button\" :disabled=\"isDisabled\">{{ label }}</button>\n</template>\n\n<script>\n  import { reactive } from 'vue';\n\n  export default {\n    name: 'button',\n    props: {\n      /**\n       * Checks if the button should be disabled\n       */\n      isDisabled: {\n        type: Boolean,\n        default: false,\n        required: true,\n      },\n      /**\n       * The display label of the button\n       */\n      label: {\n        type: String,\n        default: 'One',\n        required: true,\n      },\n    },\n    setup(props) {\n      props = reactive(props);\n      return {\n        /**\n         * What will be returned here will available to the component\n         * Functions referenced here will act like methods\n         */\n      };\n      //\n    },\n  };\n</script>\n```\n\n```html filename=\"Button.vue\" renderer=\"vue\" language=\"ts\"\n<template>\n  <button type=\"button\" :disabled=\"isDisabled\">{{ label }}</button>\n</template>\n\n<script lang=\"ts\">\n  import { defineComponent } from 'vue';\n\n  export default defineComponent({\n    name: 'button',\n    props: {\n      /**\n       * Checks if the button should be disabled\n       */\n      isDisabled: {\n        type: Boolean,\n        default: false,\n      },\n      /**\n       * The display label of the button\n       */\n      label: {\n        type: String,\n        default: 'One',\n        required: true,\n      },\n    },\n    setup(props) {\n      /**\n       * What will be returned here will available to the component\n       * Functions referenced here will act like methods\n       */\n    },\n  });\n</script>\n```\n\n```js filename=\"Button.js\" renderer=\"web-components\" language=\"js\"\nimport { LitElement, html } from 'lit';\n\n/**\n * @prop {string} content - The display label of the button\n * @prop {boolean} isDisabled - Checks if the button should be disabled\n * @summary This is a custom button element\n * @tag custom-button\n */\n\nexport class CustomButton extends LitElement {\n  static get properties() {\n    return {\n      content: { type: String },\n      isDisabled: { type: Boolean },\n    };\n  }\n\n  constructor() {\n    super();\n    this.content = 'One';\n    this.isDisabled = false;\n  }\n\n  render() {\n    return html` <button type=\"button\" ?disabled=${this.isDisabled}>${this.content}</button> `;\n  }\n}\n\ncustomElements.define('custom-button', CustomButton);\n```\n\n```ts filename=\"Button.ts\" renderer=\"web-components\" language=\"ts\"\nimport { LitElement, html } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\n\n/**\n * @prop {string} content - The display label of the button\n * @prop {boolean} isDisabled - Checks if the button should be disabled\n * @summary This is a custom button element\n * @tag custom-button\n */\n\n@customElement('custom-button')\nexport class CustomButton extends LitElement {\n  @property()\n  content?: string = 'One';\n  @property()\n  isDisabled?: boolean = false;\n\n  render() {\n    return html` <button type=\"button\" ?disabled=${this.isDisabled}>${this.content}</button> `;\n  }\n}\n```\n"
  },
  {
    "path": "docs/_snippets/button-group-story.md",
    "content": "```ts filename=\"ButtonGroup.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, type StoryObj, moduleMetadata } from '@storybook/angular';\n\nimport { CommonModule } from '@angular/common';\n\nimport { ButtonGroup } from './button-group.component';\nimport { Button } from './button.component';\n\n//👇 Imports the Button stories\nimport * as ButtonStories from './Button.stories';\n\nconst meta: Meta<ButtonGroup> = {\n  component: ButtonGroup,\n  decorators: [\n    moduleMetadata({\n      declarations: [Button],\n      imports: [CommonModule],\n    }),\n  ],\n};\n\nexport default meta;\ntype Story = StoryObj<ButtonGroup>;\n\nexport const Pair: Story = {\n  args: {\n    buttons: [{ ...ButtonStories.Primary.args }, { ...ButtonStories.Secondary.args }],\n    orientation: 'horizontal',\n  },\n};\n```\n\n```ts filename=\"ButtonGroup.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { CommonModule } from '@angular/common';\n\nimport { moduleMetadata } from '@storybook/angular';\n\nimport preview from '../.storybook/preview';\n\nimport { ButtonGroup } from './button-group.component';\nimport { Button } from './button.component';\n\n//👇 Imports the Button stories\nimport * as ButtonStories from './Button.stories';\n\nconst meta = preview.meta({\n  component: ButtonGroup,\n  decorators: [\n    moduleMetadata({\n      declarations: [Button],\n      imports: [CommonModule],\n    }),\n  ],\n});\n\nexport const Pair = meta.story({\n  args: {\n    buttons: [{ ...ButtonStories.Primary.input.args }, { ...ButtonStories.Secondary.input.args }],\n    orientation: 'horizontal',\n  },\n});\n```\n\n```js filename=\"ButtonGroup.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { ButtonGroup } from '../ButtonGroup';\n\n//👇 Imports the Button stories\nimport * as ButtonStories from './Button.stories';\n\nexport default {\n  component: ButtonGroup,\n};\n\nexport const Pair = {\n  args: {\n    buttons: [{ ...ButtonStories.Primary.args }, { ...ButtonStories.Secondary.args }],\n    orientation: 'horizontal',\n  },\n};\n```\n\n```ts filename=\"ButtonGroup.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { ButtonGroup } from '../ButtonGroup';\n\n//👇 Imports the Button stories\nimport * as ButtonStories from './Button.stories';\n\nconst meta = {\n  component: ButtonGroup,\n} satisfies Meta<typeof ButtonGroup>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Pair: Story = {\n  args: {\n    buttons: [{ ...ButtonStories.Primary.args }, { ...ButtonStories.Secondary.args }],\n    orientation: 'horizontal',\n  },\n};\n```\n\n```js filename=\"ButtonGroup.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { ButtonGroup } from '../ButtonGroup';\n\n//👇 Imports the Button stories\nimport * as ButtonStories from './Button.stories';\n\nexport default {\n  component: ButtonGroup,\n};\n\nexport const Pair = {\n  args: {\n    buttons: [{ ...ButtonStories.Primary.args }, { ...ButtonStories.Secondary.args }],\n    orientation: 'horizontal',\n  },\n};\n```\n\n```tsx filename=\"ButtonGroup.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { ButtonGroup } from '../ButtonGroup';\n\n//👇 Imports the Button stories\nimport * as ButtonStories from './Button.stories';\n\nconst meta = {\n  component: ButtonGroup,\n} satisfies Meta<typeof ButtonGroup>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Pair: Story = {\n  args: {\n    buttons: [{ ...ButtonStories.Primary.args }, { ...ButtonStories.Secondary.args }],\n    orientation: 'horizontal',\n  },\n};\n```\n\n```svelte filename=\"ButtonGroup.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import ButtonGroup from './ButtonGroup.svelte';\n\n  //👇 Imports the Button stories\n  import * as ButtonStories from './Button.stories.svelte';\n\n  const { Story } = defineMeta({\n    component: ButtonGroup,\n  });\n</script>\n\n<Story\n  name=\"Pair\"\n  args={{\n    buttons: [{ ...ButtonStories.Primary.args }, { ...ButtonStories.Secondary.args }],\n    orientation: 'horizontal',\n  }}\n/>\n```\n\n```js filename=\"ButtonGroup.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport ButtonGroup from '../ButtonGroup.svelte';\n\n//👇 Imports the Button stories\nimport * as ButtonStories from './Button.stories';\n\nexport default {\n  component: ButtonGroup,\n};\n\nexport const Pair = {\n  args: {\n    buttons: [{ ...ButtonStories.Primary.args }, { ...ButtonStories.Secondary.args }],\n    orientation: 'horizontal',\n  },\n};\n```\n\n```svelte filename=\"ButtonGroup.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import ButtonGroup from './ButtonGroup.svelte';\n\n  //👇 Imports the Button stories\n  import * as ButtonStories from './Button.stories.svelte';\n\n  const { Story } = defineMeta({\n    component: ButtonGroup,\n  });\n</script>\n\n<Story\n  name=\"Pair\"\n  args={{\n    buttons: [{ ...ButtonStories.Primary.args }, { ...ButtonStories.Secondary.args }],\n    orientation: 'horizontal',\n  }}\n/>\n```\n\n```ts filename=\"ButtonGroup.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport ButtonGroup from './ButtonGroup.svelte';\n\n//👇 Imports the Button stories\nimport * as ButtonStories from './Button.stories';\n\nconst meta = {\n  component: ButtonGroup,\n} satisfies Meta<typeof ButtonGroup>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Pair: Story = {\n  args: {\n    buttons: [{ ...ButtonStories.Primary.args }, { ...ButtonStories.Secondary.args }],\n    orientation: 'horizontal',\n  },\n};\n```\n\n```js filename=\"ButtonGroup.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport ButtonGroup from './ButtonGroup.vue';\n\n//👇 Imports the Button stories\nimport * as ButtonStories from './Button.stories';\n\nexport default {\n  component: ButtonGroup,\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Pair = {\n  render: (args) => ({\n    components: { ButtonGroup },\n    setup() {\n      return { args };\n    },\n    template: '<ButtonGroup v-bind=\"args\" />',\n  }),\n  args: {\n    buttons: [{ ...ButtonStories.Primary.args }, { ...ButtonStories.Secondary.args }],\n    orientation: 'horizontal',\n  },\n};\n```\n\n```ts filename=\"ButtonGroup.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport ButtonGroup from './ButtonGroup.vue';\n\n//👇 Imports the Button stories\nimport * as ButtonStories from './Button.stories';\n\nconst meta = {\n  component: ButtonGroup,\n} satisfies Meta<typeof ButtonGroup>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Pair: Story = {\n  render: (args) => ({\n    components: { ButtonGroup },\n    setup() {\n      return { args };\n    },\n    template: '<ButtonGroup v-bind=\"args\" />',\n  }),\n  args: {\n    buttons: [{ ...ButtonStories.Primary.args }, { ...ButtonStories.Secondary.args }],\n    orientation: 'horizontal',\n  },\n};\n```\n\n```js filename=\"ButtonGroup.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\n// 👇 Imports the Button stories\nimport * as ButtonStories from './Button.stories';\n\nexport default {\n  component: 'demo-button-group',\n};\n\nexport const Pair = {\n  args: {\n    buttons: [{ ...ButtonStories.Primary.args }, { ...ButtonStories.Secondary.args }],\n    orientation: 'horizontal',\n  },\n};\n```\n\n```ts filename=\"ButtonGroup.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\n// 👇 Imports the Button stories\nimport * as ButtonStories from './Button.stories';\n\nconst meta: Meta = {\n  component: 'demo-button-group',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Pair: Story = {\n  args: {\n    buttons: [{ ...ButtonStories.Primary.args }, { ...ButtonStories.Secondary.args }],\n    orientation: 'horizontal',\n  },\n};\n```\n\n```js filename=\"ButtonGroup.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n// 👇 Imports the Button stories\nimport * as ButtonStories from './Button.stories';\n\nconst meta = preview.meta({\n  component: 'demo-button-group',\n});\n\nexport const Pair = meta.story({\n  args: {\n    buttons: [{ ...ButtonStories.Primary.input.args }, { ...ButtonStories.Secondary.input.args }],\n    orientation: 'horizontal',\n  },\n});\n```\n\n```ts filename=\"ButtonGroup.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n// 👇 Imports the Button stories\nimport * as ButtonStories from './Button.stories';\n\nconst meta = preview.meta({\n  component: 'demo-button-group',\n});\n\nexport const Pair = meta.story({\n  args: {\n    buttons: [{ ...ButtonStories.Primary.input.args }, { ...ButtonStories.Secondary.input.args }],\n    orientation: 'horizontal',\n  },\n});\n```\n\n```ts filename=\"ButtonGroup.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport ButtonGroup from './ButtonGroup.vue';\n\n//👇 Imports the Button stories\nimport * as ButtonStories from './Button.stories';\n\nconst meta = preview.meta({\n  component: ButtonGroup,\n});\n\nexport const Pair = meta.story({\n  render: (args) => ({\n    components: { ButtonGroup },\n    setup() {\n      return { args };\n    },\n    template: '<ButtonGroup v-bind=\"args\" />',\n  }),\n  args: {\n    buttons: [{ ...ButtonStories.Primary.input.args }, { ...ButtonStories.Secondary.input.args }],\n    orientation: 'horizontal',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"ButtonGroup.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport ButtonGroup from './ButtonGroup.vue';\n\n//👇 Imports the Button stories\nimport * as ButtonStories from './Button.stories';\n\nconst meta = preview.meta({\n  component: ButtonGroup,\n});\n\nexport const Pair = meta.story({\n  render: (args) => ({\n    components: { ButtonGroup },\n    setup() {\n      return { args };\n    },\n    template: '<ButtonGroup v-bind=\"args\" />',\n  }),\n  args: {\n    buttons: [{ ...ButtonStories.Primary.input.args }, { ...ButtonStories.Secondary.input.args }],\n    orientation: 'horizontal',\n  },\n});\n```\n\n```ts filename=\"ButtonGroup.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { ButtonGroup } from '../ButtonGroup';\n\n//👇 Imports the Button stories\nimport * as ButtonStories from './Button.stories';\n\nconst meta = preview.meta({\n  component: ButtonGroup,\n});\n\nexport const Pair = meta.story({\n  args: {\n    buttons: [{ ...ButtonStories.Primary.input.args }, { ...ButtonStories.Secondary.input.args }],\n    orientation: 'horizontal',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"ButtonGroup.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { ButtonGroup } from '../ButtonGroup';\n\n//👇 Imports the Button stories\nimport * as ButtonStories from './Button.stories';\n\nconst meta = preview.meta({\n  component: ButtonGroup,\n});\n\nexport const Pair = meta.story({\n  args: {\n    buttons: [{ ...ButtonStories.Primary.input.args }, { ...ButtonStories.Secondary.input.args }],\n    orientation: 'horizontal',\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-implementation.md",
    "content": "```ts filename=\"button.component.ts\" renderer=\"angular\" language=\"ts\"\nimport { Component, Input, Output, EventEmitter } from '@angular/core';\n\n@Component({\n  selector: 'button',\n  template: `the component implementation markup`,\n})\nexport class ButtonComponent {\n  /**\n   * Is this the principal call to action on the page?\n   */\n  @Input()\n  primary = false;\n\n  /**\n   * What background color to use\n   */\n  @Input()\n  backgroundColor?: string;\n\n  /**\n   * How large should the button be?\n   */\n  @Input()\n  size: 'small' | 'medium' | 'large' = 'medium';\n\n  /**\n   * Button contents\n   *\n   * @required\n   */\n  @Input()\n  label = 'Button';\n\n  /**\n   * Optional click handler\n   */\n  @Output()\n  onClick = new EventEmitter<Event>();\n}\n```\n\n```js filename=\"Button.js|jsx\" renderer=\"react\" language=\"js\"\nimport React from 'react';\n\nimport PropTypes from 'prop-types';\n\n/**\n * Primary UI component for user interaction\n */\nexport const Button = ({ primary, backgroundColor, size, label, ...props }) => {\n  // the component implementation\n};\n\nButton.propTypes = {\n  /**\n   * Is this the principal call to action on the page?\n   */\n  primary: PropTypes.bool,\n  /**\n   * What background color to use\n   */\n  backgroundColor: PropTypes.string,\n  /**\n   * How large should the button be?\n   */\n  size: PropTypes.oneOf(['small', 'medium', 'large']),\n  /**\n   * Button contents\n   */\n  label: PropTypes.string.isRequired,\n  /**\n   * Optional click handler\n   */\n  onClick: PropTypes.func,\n};\n```\n\n```tsx filename=\"Button.ts|tsx\" renderer=\"react\" language=\"ts\"\nexport interface ButtonProps {\n  /**\n   * Is this the principal call to action on the page?\n   */\n  primary?: boolean;\n  /**\n   * What background color to use\n   */\n  backgroundColor?: string;\n  /**\n   * How large should the button be?\n   */\n  size?: 'small' | 'medium' | 'large';\n  /**\n   * Button contents\n   */\n  label: string;\n  /**\n   * Optional click handler\n   */\n  onClick?: () => void;\n}\n\n/**\n * Primary UI component for user interaction\n */\nexport const Button: React.FC<ButtonProps> = ({\n  primary = false,\n  size = 'medium',\n  backgroundColor,\n  label,\n  ...props\n}) => {\n  // the component implementation\n};\n```\n\n```svelte filename=\"Button.svelte\" renderer=\"svelte\" language=\"js\"\n<script>\n  import { createEventDispatcher } from 'svelte';\n  /**\n   * Is this the principal call to action on the page?\n   */\n  export let primary = false;\n\n  /**\n   * What background color to use\n   */\n  export let backgroundColor = undefined;\n  /**\n   * How large should the button be?\n   */\n  export let size = 'medium';\n  /**\n   * Button contents\n   */\n  export let label = '';\n\n  $: style = backgroundColor ? `background-color: ${backgroundColor}` : '';\n\n  const dispatch = createEventDispatcher();\n\n  /**\n   * Optional click handler\n   */\n  export let onClick = (event) => {\n    dispatch('click', event);\n  };\n</script>\n\n<button type=\"button\" {style} on:click=\"{onClick}\">{label}</button>\n```\n\n```html filename=\"Button.vue\" renderer=\"vue\" language=\"js\"\n<template> <!-- The component markup implementation --> </template>\n\n<script>\n  export default {\n    name: 'button',\n    props: {\n      /**\n       * Button contents\n       */\n      label: {\n        type: String,\n        required: true,\n      },\n      /**\n       * Is this the principal call to action on the page?\n       */\n      primary: {\n        type: Boolean,\n        default: false,\n      },\n      /**\n       * How large should the button be?\n       */\n      size: {\n        type: String,\n        default: 'medium',\n        validator: function (value) {\n          return ['small', 'medium', 'large'].indexOf(value) !== -1;\n        },\n      },\n      /**\n       * What background color to use\n       */\n      backgroundColor: {\n        type: String,\n      },\n    },\n    emits: ['click'],\n    setup(props, { emit }) {\n      props = reactive(props);\n      return {\n        /**\n         * Optional click handler\n         */\n        onClick() {\n          emit('click');\n        },\n      };\n    },\n  };\n</script>\n```\n\n```html filename=\"Button.vue\" renderer=\"vue\" language=\"ts\"\n<template> <!-- The component markup implementation --> </template>\n\n<script lang=\"ts\">\n  import { defineComponent, reactive } from 'vue';\n\n  export default defineComponent({\n    // eslint-disable-next-line vue/multi-word-component-names\n    name: 'button',\n    props: {\n      /**\n       * Button contents\n       */\n      label: {\n        type: String,\n        required: true,\n      },\n      /**\n       * Is this the principal call to action on the page?\n       */\n      primary: {\n        type: Boolean,\n        default: false,\n      },\n      /**\n       * How large should the button be?\n       */\n      size: {\n        type: String,\n        default: 'medium',\n        validator: function (value) {\n          return ['small', 'medium', 'large'].indexOf(value) !== -1;\n        },\n      },\n      /**\n       * What background color to use\n       */\n      backgroundColor: {\n        type: String,\n      },\n    },\n    emits: ['click'],\n    setup(props, { emit }) {\n      props = reactive(props);\n      return {\n        /**\n         * Optional click handler\n         */\n        onClick() {\n          emit('click');\n        },\n      };\n    },\n  });\n</script>\n```\n"
  },
  {
    "path": "docs/_snippets/button-snapshot-test-portable-stories.md",
    "content": "```js filename=\"test/Button.test.js|ts\" renderer=\"react\" language=\"js\" tabTitle=\"jest\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\nimport * as stories from '../stories/Button.stories';\n\nconst { Primary } = composeStories(stories);\ntest('Button snapshot', async () => {\n  await Primary.run();\n  expect(document.body.firstChild).toMatchSnapshot();\n});\n```\n\n```js filename=\"test/Button.test.js|ts\" renderer=\"react\" language=\"js\" tabTitle=\"vitest\"\n// @vitest-environment jsdom\n\nimport { expect, test } from 'vitest';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\nimport * as stories from '../stories/Button.stories';\n\nconst { Primary } = composeStories(stories);\ntest('Button snapshot', async () => {\n  await Primary.run();\n  expect(document.body.firstChild).toMatchSnapshot();\n});\n```\n\n```js filename=\"__tests__/Button.spec.js|ts\" renderer=\"vue\" language=\"js\"\n// @vitest-environment jsdom\n\nimport { expect, test } from 'vitest';\n\nimport { composeStories } from '@storybook/vue3-vite';\n\nimport * as stories from '../stories/Button.stories';\n\nconst { Primary } = composeStories(stories);\ntest('Button snapshot', async () => {\n  await Primary.run();\n  expect(document.body.firstChild).toMatchSnapshot();\n});\n```\n\n```js filename=\"__tests__/Button.spec.js|ts\" renderer=\"svelte\" language=\"js\"\n// @vitest-environment jsdom\n\nimport { expect, test } from 'vitest';\n\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport { composeStories } from '@storybook/your-framework';\n\nimport * as stories from '../stories/Button.stories';\n\nconst { Primary } = composeStories(stories);\ntest('Button snapshot', async () => {\n  await Primary.run();\n  expect(document.body.firstChild).toMatchSnapshot();\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-argtypes-with-categories.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n      },\n    },\n    // Assigns the argType to the Text category\n    label: {\n      table: {\n        category: 'Text',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n      },\n    },\n    // Assigns the argType to the Text category\n    label: {\n      table: {\n        category: 'Text',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n});\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n      },\n    },\n    // Assigns the argType to the Text category\n    label: {\n      table: {\n        category: 'Text',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n      },\n    },\n    // Assigns the argType to the Text category\n    label: {\n      table: {\n        category: 'Text',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n      },\n    },\n    // Assigns the argType to the Text category\n    label: {\n      table: {\n        category: 'Text',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n      },\n    },\n    // Assigns the argType to the Text category\n    label: {\n      table: {\n        category: 'Text',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n      },\n    },\n    // Assigns the argType to the Text category\n    label: {\n      table: {\n        category: 'Text',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n      },\n    },\n    // Assigns the argType to the Text category\n    label: {\n      table: {\n        category: 'Text',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n      },\n    },\n    // Assigns the argType to the Text category\n    label: {\n      table: {\n        category: 'Text',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n      },\n    },\n    // Assigns the argType to the Text category\n    label: {\n      table: {\n        category: 'Text',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n      },\n    },\n    // Assigns the argType to the Text category\n    label: {\n      table: {\n        category: 'Text',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n      },\n    },\n    // Assigns the argType to the Text category\n    label: {\n      table: {\n        category: 'Text',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-argtypes-with-subcategories.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n        // Assigns the argTypes to a specific subcategory\n        subcategory: 'Button colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n        subcategory: 'Button style',\n      },\n    },\n    label: {\n      table: {\n        category: 'Text',\n        subcategory: 'Button contents',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n        subcategory: 'Button Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n        // Assigns the argTypes to a specific subcategory\n        subcategory: 'Button colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n        subcategory: 'Button style',\n      },\n    },\n    label: {\n      table: {\n        category: 'Text',\n        subcategory: 'Button contents',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n        subcategory: 'Button Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n});\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n        // Assigns the argTypes to a specific subcategory\n        subcategory: 'Button colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n        subcategory: 'Button style',\n      },\n    },\n    label: {\n      table: {\n        category: 'Text',\n        subcategory: 'Button contents',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n        subcategory: 'Button Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n        // Assigns the argTypes to a specific subcategory\n        subcategory: 'Button colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n        subcategory: 'Button style',\n      },\n    },\n    label: {\n      table: {\n        category: 'Text',\n        subcategory: 'Button contents',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n        subcategory: 'Button Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n        // Assigns the argTypes to a specific subcategory\n        subcategory: 'Button colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n        subcategory: 'Button style',\n      },\n    },\n    label: {\n      table: {\n        category: 'Text',\n        subcategory: 'Button contents',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n        subcategory: 'Button Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n        // Assigns the argTypes to a specific subcategory\n        subcategory: 'Button colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n        subcategory: 'Button style',\n      },\n    },\n    label: {\n      table: {\n        category: 'Text',\n        subcategory: 'Button contents',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n        subcategory: 'Button Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n        // Assigns the argTypes to a specific subcategory\n        subcategory: 'Button colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n        subcategory: 'Button style',\n      },\n    },\n    label: {\n      table: {\n        category: 'Text',\n        subcategory: 'Button contents',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n        subcategory: 'Button Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n        // Assigns the argTypes to a specific subcategory\n        subcategory: 'Button colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n        subcategory: 'Button style',\n      },\n    },\n    label: {\n      table: {\n        category: 'Text',\n        subcategory: 'Button contents',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n        subcategory: 'Button Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n        // Assigns the argTypes to a specific subcategory\n        subcategory: 'Button colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n        subcategory: 'Button style',\n      },\n    },\n    label: {\n      table: {\n        category: 'Text',\n        subcategory: 'Button contents',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n        subcategory: 'Button Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n        // Assigns the argTypes to a specific subcategory\n        subcategory: 'Button colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n        subcategory: 'Button style',\n      },\n    },\n    label: {\n      table: {\n        category: 'Text',\n        subcategory: 'Button contents',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n        subcategory: 'Button Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n        // Assigns the argTypes to a specific subcategory\n        subcategory: 'Button colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n        subcategory: 'Button style',\n      },\n    },\n    label: {\n      table: {\n        category: 'Text',\n        subcategory: 'Button contents',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n        subcategory: 'Button Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    // Assigns the argTypes to the Colors category\n    backgroundColor: {\n      control: 'color',\n      table: {\n        category: 'Colors',\n        // Assigns the argTypes to a specific subcategory\n        subcategory: 'Button colors',\n      },\n    },\n    primary: {\n      table: {\n        category: 'Colors',\n        subcategory: 'Button style',\n      },\n    },\n    label: {\n      table: {\n        category: 'Text',\n        subcategory: 'Button contents',\n      },\n    },\n    // Assigns the argType to the Events category\n    onClick: {\n      table: {\n        category: 'Events',\n        subcategory: 'Button Events',\n      },\n    },\n    // Assigns the argType to the Sizes category\n    size: {\n      table: {\n        category: 'Sizes',\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-baseline-with-satisfies-story-level.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Example = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n} satisfies Story;\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Example = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n} satisfies Story;\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-baseline-with-satisfies.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<Button>; // 👈 Satisfies operator being used for stricter type checking.\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>; // 👈 Satisfies operator being used for stricter type checking.\n\nexport default meta;\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-baseline.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\n//👇 Throws a type error if the args don't match the component props\nexport const Primary: Story = {\n  args: {\n    primary: true,\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\n//👇 Throws a type error if the args don't match the component props\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n//👇 Throws a type error if the args don't match the component props\nexport const Primary: Story = {\n  args: {\n    primary: true,\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\n//👇 Throws a type error if the args don't match the component props\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\n//👇 Throws a type error if the args don't match the component props\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\n//👇 Throws a type error if the args don't match the component props\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-click-handler-args.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, type StoryObj, argsToTemplate } from '@storybook/angular';\n\nimport { action } from 'storybook/actions';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const Text: Story = {\n  render: (args) => ({\n    props: args,\n    // The argsToTemplate helper function converts the args to property and event bindings.\n    // You could also write the template in plain HTML and bind to the component's inputs and outputs yourself:\n    // <storybook-button [\"label\"]=\"label\" (onClick)=\"onClick($event)\">\n    // We don't recommend the latter since it can conflict with how Storybook applies arguments via the Controls panel.\n    // Binding to the component's inputs and outputs yourself will conflict with default values set inside the component's class.\n    // In edge-case scenarios, you may need to define the template yourself, though.\n    template: `<storybook-button ${argsToTemplate(args)}></storybook-button>`,\n  }),\n  args: {\n    label: 'Hello',\n    onClick: action('clicked'),\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { argsToTemplate } from '@storybook/angular';\nimport { action } from 'storybook/actions';\n\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Text = meta.story({\n  render: (args) => ({\n    props: args,\n    // The argsToTemplate helper function converts the args to property and event bindings.\n    // You could also write the template in plain HTML and bind to the component's inputs and outputs yourself:\n    // <storybook-button [\"label\"]=\"label\" (onClick)=\"onClick($event)\">\n    // We don't recommend the latter since it can conflict with how Storybook applies arguments via the Controls panel.\n    // Binding to the component's inputs and outputs yourself will conflict with default values set inside the component's class.\n    // In edge-case scenarios, you may need to define the template yourself, though.\n    template: `<storybook-button ${argsToTemplate(args)}></storybook-button>`,\n  }),\n  args: {\n    label: 'Hello',\n    onClick: action('clicked'),\n  },\n});\n```\n\n```jsx filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { action } from 'storybook/actions';\n\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Text = {\n  args: {\n    label: 'Hello',\n    onClick: action('clicked'),\n  },\n  render: ({ label, onClick }) => <Button label={label} onClick={onClick} />,\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { action } from 'storybook/actions';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Text = {\n  args: {\n    label: 'Hello',\n    onClick: action('clicked'),\n  },\n  render: ({ label, onClick }) => <Button label={label} onClick={onClick} />,\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { action } from 'storybook/actions';\n\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Text = meta.story({\n  args: {\n    label: 'Hello',\n    onClick: action('clicked'),\n  },\n  render: ({ label, onClick }) => <Button label={label} onClick={onClick} />,\n});\n```\n\n```jsx filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { action } from 'storybook/actions';\n\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Text = meta.story({\n  args: {\n    label: 'Hello',\n    onClick: action('clicked'),\n  },\n  render: ({ label, onClick }) => <Button label={label} onClick={onClick} />,\n});\n```\n\n```jsx filename=\"Button.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { action } from 'storybook/actions';\n\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Text = {\n  args: {\n    label: 'Hello',\n    onClick: action('clicked'),\n  },\n  render: ({ label, onClick }) => <Button label={label} onClick={onClick} />,\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { action } from 'storybook/actions';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Text = {\n  args: {\n    label: 'Hello',\n    onClick: action('clicked'),\n  },\n  render: ({ label, onClick }) => <Button label={label} onClick={onClick} />,\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\"\nimport Button from './Button.svelte';\n\nimport { action } from 'storybook/actions';\n\nexport default {\n  component: Button,\n};\n\nexport const Text = {\n  render: ({ label, click }) => ({\n    Component: Button,\n    props: {\n      label,\n    },\n    on: {\n      click,\n    },\n  }),\n  args: {\n    label: 'Hello',\n    click: action('clicked'),\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\"\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { action } from 'storybook/actions';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Text: Story = {\n  render: ({ label, click }) => ({\n    Component: Button,\n    props: {\n      label,\n    },\n    on: {\n      click,\n    },\n  }),\n  args: {\n    label: 'Hello',\n    click: action('clicked'),\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport { action } from 'storybook/actions';\n\nimport Button from './Button.vue';\n\nexport default {\n  component: Button,\n};\n\nexport const Text = {\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return {\n        ...args,\n        onClick: action('clicked'),\n      };\n    },\n    template: '<Button @click=\"onClick\" :label=\"label\" />',\n  }),\n  args: {\n    label: 'Hello',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport { action } from 'storybook/actions';\n\nimport Button from './Button.vue';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Text: Story = {\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return {\n        ...args,\n        onClick: action('clicked'),\n      };\n    },\n    template: '<Button @click=\"onClick\" :label=\"label\" />',\n  }),\n  args: {\n    label: 'Hello',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { action } from 'storybook/actions';\n\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Text = meta.story({\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return {\n        ...args,\n        onClick: action('clicked'),\n      };\n    },\n    template: '<Button @click=\"onClick\" :label=\"label\" />',\n  }),\n  args: {\n    label: 'Hello',\n  },\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { action } from 'storybook/actions';\n\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Text = meta.story({\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return {\n        ...args,\n        onClick: action('clicked'),\n      };\n    },\n    template: '<Button @click=\"onClick\" :label=\"label\" />',\n  }),\n  args: {\n    label: 'Hello',\n  },\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { action } from 'storybook/actions';\n\nimport { html } from 'lit';\n\nexport default {\n  component: 'custom-button',\n};\n\nexport const Text = {\n  render: ({ label, onClick }) =>\n    html`<custom-button label=${label} @click=${onClick}></custom-button>`,\n  args: {\n    label: 'Hello',\n    onClick: action('clicked'),\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { action } from 'storybook/actions';\n\nimport { html } from 'lit';\n\nconst meta: Meta = {\n  component: 'custom-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Text: Story = {\n  render: ({ label, onClick }) =>\n    html`<custom-button label=${label} @click=${onClick}></custom-button>`,\n  args: {\n    label: 'Hello',\n    onClick: action('clicked'),\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { action } from 'storybook/actions';\n\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'custom-button',\n});\n\nexport const Text = meta.story({\n  render: ({ label, onClick }) =>\n    html`<custom-button label=${label} @click=${onClick}></custom-button>`,\n  args: {\n    label: 'Hello',\n    onClick: action('clicked'),\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { action } from 'storybook/actions';\n\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'custom-button',\n});\n\nexport const Text = meta.story({\n  render: ({ label, onClick }) =>\n    html`<custom-button label=${label} @click=${onClick}></custom-button>`,\n  args: {\n    label: 'Hello',\n    onClick: action('clicked'),\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-click-handler-simplificated.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const Text: Story = {\n  args: {},\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Text = meta.story({\n  args: {},\n});\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Text = {\n  args: {},\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Text: Story = {\n  args: {},\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Text = meta.story({\n  args: {},\n});\n```\n\n```jsx filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Text = meta.story({\n  args: {},\n});\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Text = {\n  args: {},\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Text: Story = {\n  args: {},\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n};\n\nexport const Text = {\n  args: {},\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\"\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Text: Story = {\n  args: {},\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.vue';\n\nexport default {\n  component: Button,\n  argTypes: {\n    onClick: {},\n  },\n};\n\nexport const Text = {\n  args: {},\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport Button from './Button.vue';\n\nconst meta = {\n  title: 'Button',\n  component: Button,\n  argTypes: {\n    onClick: {},\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Text: Story = {\n  args: {},\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    onClick: {},\n  },\n});\n\nexport const Text = meta.story({\n  args: {},\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    onClick: {},\n  },\n});\n\nexport const Text = meta.story({\n  args: {},\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'custom-button',\n  argTypes: {\n    onClick: { action: 'onClick' },\n  },\n};\n\nexport const Text = {\n  args: {},\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'custom-button',\n  argTypes: {\n    onClick: { action: 'onClick' },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Text: Story = {\n  args: {},\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'custom-button',\n  argTypes: {\n    onClick: { action: 'onClick' },\n  },\n});\n\nexport const Text = meta.story({\n  args: {},\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'custom-button',\n  argTypes: {\n    onClick: { action: 'onClick' },\n  },\n});\n\nexport const Text = meta.story({\n  args: {},\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-click-handler.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { action } from 'storybook/actions';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const Text: Story = {\n  render: () => ({\n    props: {\n      label: 'Button',\n      onClick: action('clicked'),\n    },\n    template: `<storybook-button [label]=\"label\" (onClick)=\"onClick($event)\"></storybook-button>`,\n  }),\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { action } from 'storybook/actions';\n\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Text = meta.story({\n  render: () => ({\n    props: {\n      label: 'Button',\n      onClick: action('clicked'),\n    },\n    template: `<storybook-button [label]=\"label\" (onClick)=\"onClick($event)\"></storybook-button>`,\n  }),\n});\n```\n\n```jsx filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { action } from 'storybook/actions';\n\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Text = {\n  render: () => <Button label=\"Hello\" onClick={action('clicked')} />,\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { action } from 'storybook/actions';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  render: () => <Button label=\"Hello\" onClick={action('clicked')} />,\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { action } from 'storybook/actions';\n\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Basic = meta.story({\n  render: () => <Button label=\"Hello\" onClick={action('clicked')} />,\n});\n```\n\n```jsx filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { action } from 'storybook/actions';\n\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Text = meta.story({\n  render: () => <Button label=\"Hello\" onClick={action('clicked')} />,\n});\n```\n\n```jsx filename=\"Button.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { action } from 'storybook/actions';\n\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Text = {\n  render: () => <Button label=\"Hello\" onClick={action('clicked')} />,\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { action } from 'storybook/actions';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  render: () => <Button label=\"Hello\" onClick={action('clicked')} />,\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\"\nimport { action } from 'storybook/actions';\n\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n};\n\nexport const Text = {\n  render: () => ({\n    Component: Button,\n    props: {\n      label: 'Hello',\n    },\n    on: {\n      click: action('clicked'),\n    },\n  }),\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\"\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { action } from 'storybook/actions';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  render: (args) => ({\n    Component: Button,\n    props: args,\n  }),\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport { action } from 'storybook/actions';\n\nimport Button from './Button.vue';\n\nexport default {\n  component: Button,\n};\n\nexport const Text = {\n  render: () => ({\n    components: { Button },\n    setup() {\n      return {\n        onClick: action('clicked'),\n      };\n    },\n    template: '<Button label=\"Hello\" @click=\"onClick\" />',\n  }),\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport { action } from 'storybook/actions';\n\nimport Button from './Button.vue';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Text: Story = {\n  render: () => ({\n    components: { Button },\n    setup() {\n      return {\n        onClick: action('clicked'),\n      };\n    },\n    template: '<Button label=\"Hello\" @click=\"onClick\" />',\n  }),\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { action } from 'storybook/actions';\n\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Text = meta.story({\n  render: () => ({\n    components: { Button },\n    setup() {\n      return {\n        onClick: action('clicked'),\n      };\n    },\n    template: '<Button label=\"Hello\" @click=\"onClick\" />',\n  }),\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { action } from 'storybook/actions';\n\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Text = meta.story({\n  render: () => ({\n    components: { Button },\n    setup() {\n      return {\n        onClick: action('clicked'),\n      };\n    },\n    template: '<Button label=\"Hello\" @click=\"onClick\" />',\n  }),\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nimport { action } from 'storybook/actions';\n\nexport default {\n  component: 'custom-button',\n};\n\nexport const Text = {\n  render: () => html`<custom-button label=\"Hello\" @click=${action('clicked')}></custom-button>`,\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { action } from 'storybook/actions';\n\nimport { html } from 'lit';\n\nconst meta: Meta = {\n  component: 'custom-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Text: Story = {\n  render: () => html`<custom-button label=\"Hello\" @click=${action('clicked')}></custom-button>`,\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport { action } from 'storybook/actions';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'custom-button',\n});\n\nexport const Text = meta.story({\n  render: () => html`<custom-button label=\"Hello\" @click=${action('clicked')}></custom-button>`,\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport { action } from 'storybook/actions';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'custom-button',\n});\n\nexport const Text = meta.story({\n  render: () => html`<custom-button label=\"Hello\" @click=${action('clicked')}></custom-button>`,\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-component-args-primary.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  //👇 Creates specific argTypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    //👇 Now all Button stories will be primary.\n    primary: true,\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  //👇 Creates specific argTypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    //👇 Now all Button stories will be primary.\n    primary: true,\n  },\n});\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  //👇 Creates specific argTypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    //👇 Now all Button stories will be primary.\n    primary: true,\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  //👇 Creates specific argTypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    //👇 Now all Button stories will be primary.\n    primary: true,\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  //👇 Creates specific argTypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    //👇 Now all Button stories will be primary.\n    primary: true,\n  },\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta } from 'storybook-solidjs-vite';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  //👇 Creates specific argTypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    //👇 Now all Button stories will be primary.\n    primary: true,\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    //👇 Creates specific argTypes\n    argTypes: {\n      backgroundColor: { control: 'color' },\n    },\n    args: {\n      //👇 Now all Button stories will be primary.\n      primary: true,\n    },\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  //👇 Creates specific argTypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    //👇 Now all Button stories will be primary.\n    primary: true,\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    //👇 Creates specific argTypes\n    argTypes: {\n      backgroundColor: { control: 'color' },\n    },\n    args: {\n      //👇 Now all Button stories will be primary.\n      primary: true,\n    },\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  //👇 Creates specific argTypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    //👇 Now all Button stories will be primary.\n    primary: true,\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.vue';\n\nexport default {\n  component: Button,\n  //👇 Creates specific argTypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    //👇 Now all Button stories will be primary.\n    primary: true,\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/vue3-vite';\n\nimport Button from './Button.vue';\n\nconst meta = {\n  component: Button,\n  //👇 Creates specific argTypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    //👇 Now all Button stories will be primary.\n    primary: true,\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  //👇 Creates specific argTypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    //👇 Now all Button stories will be primary.\n    primary: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  //👇 Creates specific argTypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    //👇 Now all Button stories will be primary.\n    primary: true,\n  },\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n  // 👇 Creates specific argTypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    // 👇 Now all Button stories will be primary.\n    primary: true,\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  // 👇 Creates specific argTypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    // 👇 Now all Button stories will be primary.\n    primary: true,\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  // 👇 Creates specific argTypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    // 👇 Now all Button stories will be primary.\n    primary: true,\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  // 👇 Creates specific argTypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    // 👇 Now all Button stories will be primary.\n    primary: true,\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  //👇 Creates specific argTypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    //👇 Now all Button stories will be primary.\n    primary: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  //👇 Creates specific argTypes\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    //👇 Now all Button stories will be primary.\n    primary: true,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-component-decorator.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, componentWrapperDecorator, moduleMetadata } from '@storybook/angular';\n\nimport { Button } from './button.component';\nimport { Parent } from './parent.component'; // Parent contains ng-content\n\nconst meta: Meta<Button> = {\n  component: Button,\n  decorators: [\n    moduleMetadata({\n      declarations: [Parent],\n    }),\n    // With template\n    componentWrapperDecorator((story) => `<div style=\"margin: 3em\">${story}</div>`),\n    // With component which contains ng-content\n    componentWrapperDecorator(Parent),\n  ],\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { componentWrapperDecorator, moduleMetadata } from '@storybook/angular';\n\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\nimport { Parent } from './parent.component'; // Parent contains ng-content\n\nconst meta = preview.meta({\n  component: Button,\n  decorators: [\n    moduleMetadata({\n      declarations: [Parent],\n    }),\n    // With template\n    componentWrapperDecorator((story) => `<div style=\"margin: 3em\">${story}</div>`),\n    // With component which contains ng-content\n    componentWrapperDecorator(Parent),\n  ],\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"html\" language=\"js\"\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  decorators: [\n    (story) => {\n      const decorator = document.createElement('div');\n      decorator.style.margin = '3em';\n      decorator.appendChild(story());\n      return decorator;\n    },\n  ],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"html\" language=\"ts\"\nimport type { Meta } from '@storybook/html';\n\nimport { ButtonArgs } from './Button';\n\nconst meta: Meta<ButtonArgs> = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  decorators: [\n    (story) => {\n      const decorator = document.createElement('div');\n      decorator.style.margin = '3em';\n      decorator.appendChild(story());\n      return decorator;\n    },\n  ],\n};\n\nexport default meta;\n```\n\n```jsx filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </div>\n    ),\n  ],\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </div>\n    ),\n  ],\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```jsx filename=\"Button.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        <Story />\n      </div>\n    ),\n  ],\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta } from 'storybook-solidjs-vite';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        <Story />\n      </div>\n    ),\n  ],\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n  import MarginDecorator from './MarginDecorator.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    decorators: [() => MarginDecorator],\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\nimport MarginDecorator from './MarginDecorator.svelte';\n\nexport default {\n  component: Button,\n  decorators: [() => MarginDecorator],\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n  import MarginDecorator from './MarginDecorator.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    decorators: [() => MarginDecorator],\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\nimport MarginDecorator from './MarginDecorator.svelte';\n\nconst meta = {\n  component: Button,\n  decorators: [() => MarginDecorator],\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.vue';\n\nexport default {\n  component: Button,\n  decorators: [() => ({ template: '<div style=\"margin: 3em;\"><story /></div>' })],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/vue3-vite';\n\nimport Button from './Button.vue';\n\nconst meta = {\n  component: Button,\n  decorators: [() => ({ template: '<div style=\"margin: 3em;\"><story /></div>' })],\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  decorators: [() => ({ template: '<div style=\"margin: 3em;\"><story /></div>' })],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  decorators: [() => ({ template: '<div style=\"margin: 3em;\"><story /></div>' })],\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nexport default {\n  component: 'demo-button',\n  decorators: [(story) => html`<div style=\"margin: 3em\">${story()}</div>`],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  decorators: [(story) => html`<div style=\"margin: 3em\">${story()}</div>`],\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  decorators: [(story) => html`<div style=\"margin: 3em\">${story()}</div>`],\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  decorators: [(story) => html`<div style=\"margin: 3em\">${story()}</div>`],\n});\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </div>\n    ),\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </div>\n    ),\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-controls-primary-variant.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const Primary: Story = {\n  args: {\n    variant: 'primary',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    variant: 'primary',\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story name=\"Primary\" args={{ variant: 'primary' }} />\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  args: {\n    variant: 'primary',\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  args: {\n    variant: 'primary',\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story name=\"Primary\" args={{ variant: 'primary' }} />\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  args: {\n    variant: 'primary',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  args: {\n    variant: 'primary',\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n};\n\nexport const Success = {\n  args: {\n    variant: 'primary',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Primary: Story = {\n  args: {\n    variant: 'primary',\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Success = meta.story({\n  args: {\n    variant: 'primary',\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Primary = meta.story({\n  args: {\n    variant: 'primary',\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    variant: 'primary',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    variant: 'primary',\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    variant: 'primary',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    variant: 'primary',\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-controls-radio-group.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  argTypes: {\n    variant: {\n      options: ['primary', 'secondary'],\n      control: { type: 'radio' },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    variant: {\n      options: ['primary', 'secondary'],\n      control: { type: 'radio' },\n    },\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    argTypes: {\n      variant: {\n        options: ['primary', 'secondary'],\n        control: { type: 'radio' },\n      },\n    },\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  argTypes: {\n    variant: {\n      options: ['primary', 'secondary'],\n      control: { type: 'radio' },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  argTypes: {\n    variant: {\n      options: ['primary', 'secondary'],\n      control: { type: 'radio' },\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    argTypes: {\n      variant: {\n        options: ['primary', 'secondary'],\n        control: { type: 'radio' },\n      },\n    },\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  argTypes: {\n    variant: {\n      options: ['primary', 'secondary'],\n      control: { type: 'radio' },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  argTypes: {\n    variant: {\n      options: ['primary', 'secondary'],\n      control: { type: 'radio' },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n  argTypes: {\n    variant: {\n      options: ['primary', 'secondary'],\n      control: { type: 'radio' },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  argTypes: {\n    variant: {\n      options: ['primary', 'secondary'],\n      control: { type: 'radio' },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  argTypes: {\n    variant: {\n      options: ['primary', 'secondary'],\n      control: { type: 'radio' },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  argTypes: {\n    variant: {\n      options: ['primary', 'secondary'],\n      control: { type: 'radio' },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    variant: {\n      options: ['primary', 'secondary'],\n      control: { type: 'radio' },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    variant: {\n      options: ['primary', 'secondary'],\n      control: { type: 'radio' },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    variant: {\n      options: ['primary', 'secondary'],\n      control: { type: 'radio' },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    variant: {\n      options: ['primary', 'secondary'],\n      control: { type: 'radio' },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-decorator.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport {\n  type Meta,\n  type StoryObj,\n  componentWrapperDecorator,\n  moduleMetadata,\n} from '@storybook/angular';\n\nimport { Button } from './button.component';\nimport { Parent } from './parent.component'; // Parent contains ng-content\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const Primary: Story = {\n  decorators: [componentWrapperDecorator((story) => `<div style=\"margin: 3em\">${story}</div>`)],\n};\n\nexport const InsideParent: Story = {\n  decorators: [\n    moduleMetadata({\n      declarations: [Parent],\n    }),\n    componentWrapperDecorator(Parent),\n  ],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { componentWrapperDecorator, moduleMetadata } from '@storybook/angular';\n\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\nimport { Parent } from './parent.component'; // Parent contains ng-content\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  decorators: [componentWrapperDecorator((story) => `<div style=\"margin: 3em\">${story}</div>`)],\n});\n\nexport const InsideParent = meta.story({\n  decorators: [\n    moduleMetadata({\n      declarations: [Parent],\n    }),\n    componentWrapperDecorator(Parent),\n  ],\n});\n```\n\n```jsx filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </div>\n    ),\n  ],\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </div>\n    ),\n  ],\n};\n```\n\n```jsx filename=\"Button.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        <Story />\n      </div>\n    ),\n  ],\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        <Story />\n      </div>\n    ),\n  ],\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n  import MarginDecorator from './MarginDecorator.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"Primary\"\n  decorators={[\n    () => MarginDecorator\n  ]}\n/>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\nimport MarginDecorator from './MarginDecorator.svelte';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  decorators: [() => MarginDecorator],\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n  import MarginDecorator from './MarginDecorator.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"Primary\"\n  decorators={[\n    () => MarginDecorator\n  ]}\n/>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\nimport MarginDecorator from './MarginDecorator.svelte';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  decorators: [() => MarginDecorator],\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.vue';\n\nexport default {\n  component: Button,\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = {\n  render: () => ({\n    components: { Button },\n    template: '<Button primary label=\"Hello World\" />',\n  }),\n  decorators: [() => ({ template: '<div style=\"margin: 3em;\"><story /></div>' })],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport Button from './Button.vue';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary: Story = {\n  render: () => ({\n    components: { Button },\n    template: '<Button primary label=\"Hello World\" />',\n  }),\n  decorators: [() => ({ template: '<div style=\"margin: 3em;\"><story /></div>' })],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = meta.story({\n  render: () => ({\n    components: { Button },\n    template: '<Button primary label=\"Hello World\" />',\n  }),\n  decorators: [() => ({ template: '<div style=\"margin: 3em;\"><story /></div>' })],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = meta.story({\n  render: () => ({\n    components: { Button },\n    template: '<Button primary label=\"Hello World\" />',\n  }),\n  decorators: [() => ({ template: '<div style=\"margin: 3em;\"><story /></div>' })],\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nexport default {\n  component: 'demo-button',\n};\n\nexport const Primary = {\n  decorators: [(story) => html`<div style=\"margin: 3em\">${story()}</div>`],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Primary: Story = {\n  decorators: [(story) => html`<div style=\"margin: 3em\">${story()}</div>`],\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Primary = meta.story({\n  decorators: [(story) => html`<div style=\"margin: 3em\">${story()}</div>`],\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Primary = meta.story({\n  decorators: [(story) => html`<div style=\"margin: 3em\">${story()}</div>`],\n});\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </div>\n    ),\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </div>\n    ),\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-default-export-with-component.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"ember\" language=\"js\"\nexport default {\n  component: 'button',\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"preact\" language=\"js\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta } from 'storybook-solidjs-vite';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.vue';\n\nexport default {\n  component: Button,\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/vue3-vite';\n\nimport Button from './Button.vue';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  title: 'Button',\n  component: 'demo-button',\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  title: 'Button',\n  component: 'demo-button',\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-default-export.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    /* 👇 The title prop is optional.\n    * See https://storybook.js.org/docs/configure/#configure-story-loading\n    * to learn how to generate automatic titles\n    */\n    title: 'Button',\n    component: Button,\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    /* 👇 The title prop is optional.\n    * See https://storybook.js.org/docs/configure/#configure-story-loading\n    * to learn how to generate automatic titles\n    */\n    title: 'Button',\n    component: Button,\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"html\" language=\"js\"\nimport { createButton } from './Button';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"html\" language=\"ts\"\nimport type { Meta } from '@storybook/html';\n\nimport { createButton, ButtonArgs } from './Button';\n\nconst meta: Meta<ButtonArgs> = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  title: 'Button',\n  component: 'demo-button',\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  title: 'Button',\n  component: 'demo-button',\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: 'demo-button',\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: 'demo-button',\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-disable-addon.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  parameters: {\n    myAddon: { disable: true }, // Disables the addon\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    myAddon: { disable: true }, // Disables the addon\n  },\n});\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n  parameters: {\n    myAddon: { disable: true }, // Disables the addon\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n  parameters: {\n    myAddon: { disable: true }, // Disables the addon\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n  parameters: {\n    myAddon: { disable: true }, // Disables the addon\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  parameters: {\n    myAddon: { disable: true }, // Disables the addon\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  parameters: {\n    myAddon: { disable: true }, // Disables the addon\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  parameters: {\n    myAddon: { disable: true }, // Disables the addon\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n  parameters: {\n    myAddon: { disable: true }, // Disables the addon\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n  parameters: {\n    myAddon: { disable: true }, // Disables the addon\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n  parameters: {\n    myAddon: { disable: true }, // Disables the addon\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n  parameters: {\n    myAddon: { disable: true }, // Disables the addon\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-grouped.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Button',\n  component: Button,\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Button',\n  component: Button,\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    /* 👇 The title prop is optional.\n     * See https://storybook.js.org/docs/configure/#configure-story-loading\n     * to learn how to generate automatic titles\n     */\n    title: 'Design System/Atoms/Button',\n    component: Button,\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Button',\n  component: Button,\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Button',\n  component: Button,\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    /* 👇 The title prop is optional.\n     * See https://storybook.js.org/docs/configure/#configure-story-loading\n     * to learn how to generate automatic titles\n     */\n    title: 'Design System/Atoms/Button',\n    component: Button,\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Button',\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Button',\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  title: 'Design System/Atoms/Button',\n  component: 'demo-button',\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  title: 'Design System/Atoms/Button',\n  component: 'demo-button',\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  title: 'Design System/Atoms/Button',\n  component: 'demo-button',\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  title: 'Design System/Atoms/Button',\n  component: 'demo-button',\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Button',\n  component: Button,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Button',\n  component: Button,\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Button',\n  component: Button,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Button',\n  component: Button,\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-hoisted.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button as ButtonComponent } from './button.component';\n\nconst meta: Meta<ButtonComponent> = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Button',\n  component: ButtonComponent,\n};\n\nexport default meta;\ntype Story = StoryObj<ButtonComponent>;\n\n// This is the only named export in the file, and it matches the component name\nexport const Button: Story = {};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button as ButtonComponent } from './button.component';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Button',\n  component: ButtonComponent,\n});\n\n// This is the only named export in the file, and it matches the component name\nexport const Button = meta.story();\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button as ButtonComponent } from './Button';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Button',\n  component: ButtonComponent,\n};\n\n// This is the only named export in the file, and it matches the component name\nexport const Button = {};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button as ButtonComponent } from './Button';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Button',\n  component: ButtonComponent,\n} satisfies Meta<typeof ButtonComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// This is the only named export in the file, and it matches the component name\nexport const Button: Story = {};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  title: 'Design System/Atoms/Button',\n  component: 'demo-button',\n};\n\n// This is the only named export in the file, and it matches the component name\nexport const Button = {};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  title: 'Design System/Atoms/Button',\n  component: 'demo-component',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\n// This is the only named export in the file, and it matches the component name\nexport const Button: Story = {};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  title: 'Design System/Atoms/Button',\n  component: 'demo-button',\n});\n\n// This is the only named export in the file, and it matches the component name\nexport const Button = meta.story();\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  title: 'Design System/Atoms/Button',\n  component: 'demo-component',\n});\n\n// This is the only named export in the file, and it matches the component name\nexport const Button = meta.story();\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button as ButtonComponent } from './Button';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Button',\n  component: ButtonComponent,\n});\n\n// This is the only named export in the file, and it matches the component name\nexport const Button = meta.story();\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button as ButtonComponent } from './Button';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Button',\n  component: ButtonComponent,\n});\n\n// This is the only named export in the file, and it matches the component name\nexport const Button = meta.story();\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport ButtonComponent from './Button.vue';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Button',\n  component: ButtonComponent,\n});\n\n// This is the only named export in the file, and it matches the component name\nexport const Button = meta.story();\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport ButtonComponent from './Button.vue';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Button',\n  component: ButtonComponent,\n});\n\n// This is the only named export in the file, and it matches the component name\nexport const Button = meta.story();\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-hypothetical-example.md",
    "content": "```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Sample = {\n  render: () => ({\n    template: '<button :label=label />',\n    data: {\n      label: 'hello button',\n    },\n  }),\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Sample: Story = {\n  render: () => ({\n    template: '<button :label=label />',\n    data: {\n      label: 'hello button',\n    },\n  }),\n};\n```\n\n<!-- These serve as abstract examples to inform how frameworks can be built, so \"common\" is fine here -->\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Sample = meta.story({\n  render: () => ({\n    template: '<button :label=label />',\n    data: {\n      label: 'hello button',\n    },\n  }),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Sample = meta.story({\n  render: () => ({\n    template: '<button :label=label />',\n    data: {\n      label: 'hello button',\n    },\n  }),\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-matching-argtypes.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  parameters: { actions: { argTypesRegex: '^on.*' } },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: { actions: { argTypesRegex: '^on.*' } },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    parameters: { actions: { argTypesRegex: '^on.*' } },\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  parameters: { actions: { argTypesRegex: '^on.*' } },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  parameters: { actions: { argTypesRegex: '^on.*' } },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    parameters: { actions: { argTypesRegex: '^on.*' } },\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  parameters: { actions: { argTypesRegex: '^on.*' } },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  parameters: { actions: { argTypesRegex: '^on.*' } },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n  parameters: { actions: { argTypesRegex: '^on.*' } },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  parameters: { actions: { argTypesRegex: '^on.*' } },\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  parameters: { actions: { argTypesRegex: '^on.*' } },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  parameters: { actions: { argTypesRegex: '^on.*' } },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: { actions: { argTypesRegex: '^on.*' } },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: { actions: { argTypesRegex: '^on.*' } },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: { actions: { argTypesRegex: '^on.*' } },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: { actions: { argTypesRegex: '^on.*' } },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-onclick-action-spy.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { fn } from 'storybook/test';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  // 👇 Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked\n  args: { onClick: fn() },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { fn } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  // 👇 Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked\n  args: { onClick: fn() },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { fn } from 'storybook/test';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    // 👇 Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked\n    args: { onClick: fn() },\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport { fn } from 'storybook/test';\n\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  // 👇 Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked\n  args: { onClick: fn() },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { fn } from 'storybook/test';\n\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  // 👇 Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked\n  args: { onClick: fn() },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { fn } from 'storybook/test';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    // 👇 Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked\n    args: { onClick: fn() },\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport { fn } from 'storybook/test';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  // 👇 Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked\n  args: { onClick: fn() },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { fn } from 'storybook/test';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  // 👇 Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked\n  args: { onClick: fn() },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { fn } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  // 👇 Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked\n  args: { onClick: fn() },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { fn } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  // 👇 Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked\n  args: { onClick: fn() },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { fn } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  // 👇 Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked\n  args: { onClick: fn() },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { fn } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  // 👇 Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked\n  args: { onClick: fn() },\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { fn } from 'storybook/test';\n\nexport default {\n  component: 'demo-button',\n  // 👇 Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked\n  args: { onClick: fn() },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nimport { fn } from 'storybook/test';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  // 👇 Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked\n  args: { onClick: fn() },\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { fn } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  // 👇 Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked\n  args: { onClick: fn() },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { fn } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  // 👇 Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked\n  args: { onClick: fn() },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-primary-composition.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    ...Primary.args,\n    primary: false,\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  args: {\n    ...Primary.input.args,\n    primary: false,\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n\n  const primaryArgs = {\n    primary: true,\n    label: 'Button',\n  }\n</script>\n\n<Story name=\"Primary\" args={primaryArgs} />\n\n<Story name=\"Secondary\" args={{...primaryArgs, primary: false}} />\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    ...Primary.args,\n    primary: false,\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    ...Primary.args,\n    primary: false,\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n\n  const primaryArgs = {\n    primary: true,\n    label: 'Button',\n  }\n</script>\n\n<Story name=\"Primary\" args={primaryArgs} />\n\n<Story name=\"Secondary\" args={{...primaryArgs, primary: false}} />\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    ...Primary.args,\n    primary: false,\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the name of your framework\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    ...Primary.args,\n    primary: false,\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n};\n\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    ...Primary.args,\n    primary: false,\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    ...Primary.args,\n    primary: false,\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  args: {\n    ...Primary.input.args,\n    primary: false,\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  args: {\n    ...Primary.input.args,\n    primary: false,\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  args: {\n    ...Primary.input.args,\n    primary: false,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  args: {\n    ...Primary.input.args,\n    primary: false,\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  args: {\n    ...Primary.input.args,\n    primary: false,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  args: {\n    ...Primary.input.args,\n    primary: false,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-primary-long-name.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const PrimaryLongName: Story = {\n  args: {\n    ...Primary.args,\n    label: 'Primary with a really long name',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n\nexport const PrimaryLongName = meta.story({\n  args: {\n    ...Primary.input.args,\n    label: 'Primary with a really long name',\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n\n  const primaryArgs = {\n    primary: true,\n    label: 'Button',\n  }\n</script>\n\n<Story name=\"Primary\" args={primaryArgs} />\n\n<Story name=\"PrimaryLongName\"\n  args={{\n    ...primaryArgs,\n    label: 'Primary with a really long name'\n  }} />\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const PrimaryLongName = {\n  args: {\n    ...Primary.args,\n    label: 'Primary with a really long name',\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const PrimaryLongName = {\n  args: {\n    ...Primary.args,\n    label: 'Primary with a really long name',\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n\n  const primaryArgs = {\n    primary: true,\n    label: 'Button',\n  }\n</script>\n\n<Story name=\"Primary\" args={primaryArgs} />\n\n<Story name=\"PrimaryLongName\"\n  args={{\n    ...primaryArgs,\n    label: 'Primary with a really long name'\n  }} />\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const PrimaryLongName: Story = {\n  args: {\n    ...Primary.args,\n    label: 'Primary with a really long name',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the name of your framework\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const PrimaryLongName: Story = {\n  args: {\n    ...Primary.args,\n    label: 'Primary with a really long name',\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n};\n\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const PrimaryLongName = {\n  args: {\n    ...Primary.args,\n    label: 'Primary with a really long name',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const PrimaryLongName: Story = {\n  args: {\n    ...Primary.args,\n    label: 'Primary with a really long name',\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n\nexport const PrimaryLongName = meta.story({\n  args: {\n    ...Primary.input.args,\n    label: 'Primary with a really long name',\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n\nexport const PrimaryLongName = meta.story({\n  args: {\n    ...Primary.input.args,\n    label: 'Primary with a really long name',\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n\nexport const PrimaryLongName = meta.story({\n  args: {\n    ...Primary.input.args,\n    label: 'Primary with a really long name',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n\nexport const PrimaryLongName = meta.story({\n  args: {\n    ...Primary.input.args,\n    label: 'Primary with a really long name',\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n\nexport const PrimaryLongName = meta.story({\n  args: {\n    ...Primary.input.args,\n    label: 'Primary with a really long name',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n\nexport const PrimaryLongName = meta.story({\n  args: {\n    ...Primary.input.args,\n    label: 'Primary with a really long name',\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-rename-story.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const Primary: Story = {\n  // 👇 Rename this story\n  name: 'I am the primary',\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  // 👇 Rename this story\n  name: 'I am the primary',\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"html\" language=\"js\"\nimport { createButton } from './Button';\n\nexport default {\n  render: (args) => createButton(args),\n};\n\nexport const Primary = {\n  // 👇 Rename this story\n  name: 'I am the primary',\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"html\" language=\"ts\"\nimport type { Meta, StoryObj } from '@storybook/html';\n\nimport { createButton, ButtonArgs } from './Button';\n\nconst meta: Meta<ButtonArgs> = {\n  render: (args) => createButton(args),\n};\n\nexport default meta;\ntype Story = StoryObj<ButtonArgs>;\n\nexport const Primary: Story = {\n  // 👇 Rename this story\n  name: 'I am the primary',\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  // 👇 Rename this story\n  name: 'I am the primary',\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  // 👇 Rename this story\n  name: 'I am the primary',\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  // 👇 Rename this story\n  name: 'I am the primary',\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  // 👇 Rename this story\n  name: 'I am the primary',\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  {/* 👇 Friendly name */}\n  name=\"I am the primary\"\n  {/* 👇 Unique export name */}\n  exportName=\"Primary\"\n/>\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  {/* 👇 Friendly name */}\n  name=\"I am the primary\"\n  {/* 👇 Unique export name */}\n  exportName=\"Primary\"\n/>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  // 👇 Rename this story\n  name: 'I am the primary',\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  // 👇 Rename this story\n  name: 'I am the primary',\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.vue';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  // 👇 Rename this story\n  name: 'I am the primary',\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport Button from './Button.vue';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  // 👇 Rename this story\n  name: 'I am the primary',\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n};\n\nexport const Primary = {\n  // 👇 Rename this story\n  name: 'I am the primary',\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Primary: Story = {\n  // 👇 Rename this story\n  name: 'I am the primary',\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Primary = meta.story({\n  // 👇 Rename this story\n  name: 'I am the primary',\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Primary = meta.story({\n  // 👇 Rename this story\n  name: 'I am the primary',\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  // 👇 Rename this story\n  name: 'I am the primary',\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  // 👇 Rename this story\n  name: 'I am the primary',\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  // 👇 Rename this story\n  name: 'I am the primary',\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  // 👇 Rename this story\n  name: 'I am the primary',\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-using-args.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const Primary: Story = {\n  args: {\n    backgroundColor: '#ff0',\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    ...Primary.args,\n    label: '😄👍😍💯',\n  },\n};\n\nexport const Tertiary: Story = {\n  args: {\n    ...Primary.args,\n    label: '📚📕📈🤓',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    backgroundColor: '#ff0',\n    label: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  args: {\n    ...Primary.input.args,\n    label: '😄👍😍💯',\n  },\n});\n\nexport const Tertiary = meta.story({\n  args: {\n    ...Primary.input.args,\n    label: '📚📕📈🤓',\n  },\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"html\" language=\"js\"\nimport { createButton } from './Button';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = {\n  render: (args) => createButton(args),\n  args: {\n    backgroundColor: '#ff0',\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  render: (args) => createButton(args),\n  args: {\n    ...Primary.args,\n    label: '😄👍😍💯',\n  },\n};\n\nexport const Tertiary = {\n  render: (args) => createButton(args),\n  args: {\n    ...Primary.args,\n    label: '📚📕📈🤓',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"html\" language=\"ts\"\nimport type { Meta, StoryObj } from '@storybook/html';\nimport { createButton, ButtonArgs } from './Button';\n\nconst meta: Meta<ButtonArgs> = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n};\n\nexport default meta;\ntype Story = StoryObj<ButtonArgs>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary: Story = {\n  render: (args) => createButton(args),\n  args: {\n    backgroundColor: '#ff0',\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  render: (args) => createButton(args),\n  args: {\n    ...Primary.args,\n    label: '😄👍😍💯',\n  },\n};\n\nexport const Tertiary: Story = {\n  render: (args) => createButton(args),\n  args: {\n    ...Primary.args,\n    label: '📚📕📈🤓',\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  args: {\n    backgroundColor: '#ff0',\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    ...Primary.args,\n    label: '😄👍😍💯',\n  },\n};\n\nexport const Tertiary = {\n  args: {\n    ...Primary.args,\n    label: '📚📕📈🤓',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  args: {\n    backgroundColor: '#ff0',\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    ...Primary.args,\n    label: '😄👍😍💯',\n  },\n};\n\nexport const Tertiary: Story = {\n  args: {\n    ...Primary.args,\n    label: '📚📕📈🤓',\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  args: {\n    backgroundColor: '#ff0',\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    ...Primary.args,\n    label: '😄👍😍💯',\n  },\n};\n\nexport const Tertiary = {\n  args: {\n    ...Primary.args,\n    label: '📚📕📈🤓',\n  },\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  args: {\n    backgroundColor: '#ff0',\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    ...Primary.args,\n    label: '😄👍😍💯',\n  },\n};\n\nexport const Tertiary: Story = {\n  args: {\n    ...Primary.args,\n    label: '📚📕📈🤓',\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"Primary\"\n  args={{\n    backgroundColor: '#ff0',\n    label: 'Button',\n  }}\n/>\n\n<Story\n  name=\"Secondary\"\n  args={{\n    backgroundColor: '#ff0',\n    label: '😄👍😍💯',\n  }}\n/>\n\n<Story\n  name=\"Tertiary\"\n  args={{\n    backgroundColor:'#ff0',\n    label: '📚📕📈🤓',\n  }}\n/>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  args: {\n    backgroundColor: '#ff0',\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    ...Primary.args,\n    label: '😄👍😍💯',\n  },\n};\n\nexport const Tertiary = {\n  args: {\n    ...Primary.args,\n    label: '📚📕📈🤓',\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"Primary\"\n  args={{\n    backgroundColor: '#ff0',\n    label: 'Button',\n  }}\n/>\n\n<Story\n  name=\"Secondary\"\n  args={{\n    backgroundColor: '#ff0',\n    label: '😄👍😍💯',\n  }}\n/>\n\n<Story\n  name=\"Tertiary\"\n  args={{\n    backgroundColor:'#ff0',\n    label: '📚📕📈🤓',\n  }}\n/>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  args: {\n    backgroundColor: '#ff0',\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    ...Primary.args,\n    label: '😄👍😍💯',\n  },\n};\n\nexport const Tertiary: Story = {\n  args: {\n    ...Primary.args,\n    label: '📚📕📈🤓',\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.vue';\n\nexport default {\n  component: Button,\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = {\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: '<Button v-bind=\"args\" />',\n  }),\n  args: {\n    backgroundColor: '#ff0',\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    ...Primary.args,\n    label: '😄👍😍💯',\n  },\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: '<Button v-bind=\"args\" />',\n  }),\n};\n\nexport const Tertiary = {\n  args: {\n    ...Primary.args,\n    label: '📚📕📈🤓',\n  },\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: '<Button v-bind=\"args\" />',\n  }),\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport Button from './Button.vue';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary: Story = {\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: '<Button v-bind=\"args\" />',\n  }),\n  args: {\n    background: '#ff0',\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: '<Button v-bind=\"args\" />',\n  }),\n  args: {\n    ...Primary.args,\n    label: '😄👍😍💯',\n  },\n};\n\nexport const Tertiary: Story = {\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: '<Button v-bind=\"args\" />',\n  }),\n  args: {\n    ...Primary.args,\n    label: '📚📕📈🤓',\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n};\n\nexport const Primary = {\n  args: {\n    backgroundColor: '#ff0',\n    label: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    ...Primary.args,\n    label: '😄👍😍💯',\n  },\n};\n\nexport const Tertiary = {\n  args: {\n    ...Primary.args,\n    label: '📚📕📈🤓',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Primary: Story = {\n  args: {\n    backgroundColor: '#ff0',\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    ...Primary.args,\n    label: '😄👍😍💯',\n  },\n};\n\nexport const Tertiary: Story = {\n  args: {\n    ...Primary.args,\n    label: '📚📕📈🤓',\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Primary = meta.story({\n  args: {\n    backgroundColor: '#ff0',\n    label: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  args: {\n    ...Primary.input.args,\n    label: '😄👍😍💯',\n  },\n});\n\nexport const Tertiary = meta.story({\n  args: {\n    ...Primary.input.args,\n    label: '📚📕📈🤓',\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Primary = meta.story({\n  args: {\n    backgroundColor: '#ff0',\n    label: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  args: {\n    ...Primary.input.args,\n    label: '😄👍😍💯',\n  },\n});\n\nexport const Tertiary = meta.story({\n  args: {\n    ...Primary.input.args,\n    label: '📚📕📈🤓',\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = meta.story({\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: '<Button v-bind=\"args\" />',\n  }),\n  args: {\n    background: '#ff0',\n    label: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: '<Button v-bind=\"args\" />',\n  }),\n  args: {\n    ...Primary.input.args,\n    label: '😄👍😍💯',\n  },\n});\n\nexport const Tertiary = meta.story({\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: '<Button v-bind=\"args\" />',\n  }),\n  args: {\n    ...Primary.input.args,\n    label: '📚📕📈🤓',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = meta.story({\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: '<Button v-bind=\"args\" />',\n  }),\n  args: {\n    backgroundColor: '#ff0',\n    label: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: '<Button v-bind=\"args\" />',\n  }),\n  args: {\n    ...Primary.input.args,\n    label: '😄👍😍💯',\n  },\n});\n\nexport const Tertiary = meta.story({\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: '<Button v-bind=\"args\" />',\n  }),\n  args: {\n    ...Primary.input.args,\n    label: '📚📕📈🤓',\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    backgroundColor: '#ff0',\n    label: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  args: {\n    ...Primary.input.args,\n    label: '😄👍😍💯',\n  },\n});\n\nexport const Tertiary = meta.story({\n  args: {\n    ...Primary.input.args,\n    label: '📚📕📈🤓',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    backgroundColor: '#ff0',\n    label: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  args: {\n    ...Primary.input.args,\n    label: '😄👍😍💯',\n  },\n});\n\nexport const Tertiary = meta.story({\n  args: {\n    ...Primary.input.args,\n    label: '📚📕📈🤓',\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-with-addon-example.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n  //👇 Creates specific parameters for the story\n  parameters: {\n    myAddon: {\n      data: 'this data is passed to the addon',\n    },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic: Story = {\n  render: () => ({\n    template: `<app-button>hello</<app-button>`,\n  }),\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n  //👇 Creates specific parameters for the story\n  parameters: {\n    myAddon: {\n      data: 'this data is passed to the addon',\n    },\n  },\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic = meta.story({\n  render: () => ({\n    template: `<app-button>hello</<app-button>`,\n  }),\n});\n```\n\n```jsx filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport * as React from 'react';\n\nimport { Button } from './Button';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n  //👇 Creates specific parameters for the story\n  parameters: {\n    myAddon: {\n      data: 'This data is passed to the addon',\n    },\n  },\n};\n\nexport const Basic = {\n  render: () => <Button>Hello</Button>,\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\nimport * as React from 'react';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n  //👇 Creates specific parameters for the story\n  parameters: {\n    myAddon: {\n      data: 'This data is passed to the addon',\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic: Story = {\n  render: () => <Button>Hello</Button>,\n};\n```\n\n```jsx filename=\"Button.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { Button } from './Button';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n  //👇 Creates specific parameters for the story\n  parameters: {\n    myAddon: {\n      data: 'This data is passed to the addon',\n    },\n  },\n};\n\nexport const Basic = {\n  render: () => <Button>Hello</Button>,\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { Button } from './Button';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n  //👇 Creates specific parameters for the story\n  parameters: {\n    myAddon: {\n      data: 'this data is passed to the addon',\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic: Story = {\n  render: () => <Button>Hello</Button>,\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    /* 👇 The title prop is optional.\n     * See https://storybook.js.org/docs/configure/#configure-story-loading\n     * to learn how to generate automatic titles\n    */\n    title: 'Button',\n    component: Button,\n    parameters: {\n      myAddon: {\n        data: 'This data is passed to the addon',\n      },\n    },\n  });\n</script>\n\n<Story name=\"Basic\"/>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n  //👇 Creates specific parameters for the story\n  parameters: {\n    myAddon: {\n      data: 'this data is passed to the addon',\n    },\n  },\n};\n\nexport const Basic = {};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    /* 👇 The title prop is optional.\n     * See https://storybook.js.org/docs/configure/#configure-story-loading\n     * to learn how to generate automatic titles\n    */\n    title: 'Button',\n    component: Button,\n    parameters: {\n      myAddon: {\n        data: 'This data is passed to the addon',\n      },\n    },\n  });\n</script>\n\n<Story name=\"Basic\"/>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n  //👇 Creates specific parameters for the story\n  parameters: {\n    myAddon: {\n      data: 'this data is passed to the addon',\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.vue';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n  //👇 Creates specific parameters for the story\n  parameters: {\n    myAddon: {\n      data: 'This data is passed to the addon',\n    },\n  },\n};\n\nexport const Basic = {\n  render: () => ({\n    components: { Button },\n    template: '<Button label=\"Hello\" />',\n  }),\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport Button from './Button.vue';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n  //👇 Creates specific parameters for the story\n  parameters: {\n    myAddon: {\n      data: 'This data is passed to the addon',\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic: Story = {\n  render: () => ({\n    components: { Button },\n    template: '<Button label=\"Hello\" />',\n  }),\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nexport default {\n  title: 'Button',\n  component: 'custom-button',\n  //👇 Creates specific parameters for the story\n  parameters: {\n    myAddon: {\n      data: 'This data is passed to the addon',\n    },\n  },\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic = {\n  render: () => html`<custom-button label=\"Hello\"></custom-button>`,\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nconst meta: Meta = {\n  title: 'Button',\n  component: 'custom-button',\n  //👇 Creates specific parameters for the story\n  parameters: {\n    myAddon: {\n      data: 'This data is passed to the addon',\n    },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic: Story = {\n  render: () => html`<custom-button label=\"Hello\"></custom-button>`,\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  title: 'Button',\n  component: 'custom-button',\n  //👇 Creates specific parameters for the story\n  parameters: {\n    myAddon: {\n      data: 'This data is passed to the addon',\n    },\n  },\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic = meta.story({\n  render: () => html`<custom-button label=\"Hello\"></custom-button>`,\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  title: 'Button',\n  component: 'custom-button',\n  //👇 Creates specific parameters for the story\n  parameters: {\n    myAddon: {\n      data: 'This data is passed to the addon',\n    },\n  },\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic = meta.story({\n  render: () => html`<custom-button label=\"Hello\"></custom-button>`,\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n  //👇 Creates specific parameters for the story\n  parameters: {\n    myAddon: {\n      data: 'This data is passed to the addon',\n    },\n  },\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic = meta.story({\n  render: () => ({\n    components: { Button },\n    template: '<Button label=\"Hello\" />',\n  }),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n  //👇 Creates specific parameters for the story\n  parameters: {\n    myAddon: {\n      data: 'This data is passed to the addon',\n    },\n  },\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic = meta.story({\n  render: () => ({\n    components: { Button },\n    template: '<Button label=\"Hello\" />',\n  }),\n});\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n  //👇 Creates specific parameters for the story\n  parameters: {\n    myAddon: {\n      data: 'This data is passed to the addon',\n    },\n  },\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic = meta.story({\n  render: () => <Button>Hello</Button>,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n  component: Button,\n  //👇 Creates specific parameters for the story\n  parameters: {\n    myAddon: {\n      data: 'This data is passed to the addon',\n    },\n  },\n});\n\nexport const Basic = meta.story({\n  render: () => <Button>Hello</Button>,\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-with-args.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular/';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"html\" language=\"js\"\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = {\n  render: (args) => {\n    const btn = document.createElement('button');\n    btn.innerText = args.label;\n\n    const mode = args.primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n    btn.className = ['storybook-button', 'storybook-button--medium', mode].join(' ');\n\n    return btn;\n  },\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"html\" language=\"ts\"\nimport type { Meta, StoryObj } from '@storybook/html';\n\ntype ButtonArgs = {\n  primary: boolean;\n  label: string;\n};\n\nconst meta: Meta<ButtonArgs> = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n};\n\nexport default meta;\ntype Story = StoryObj<ButtonArgs>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary: Story = {\n  render: (args) => {\n    const btn = document.createElement('button');\n    btn.innerText = args.label;\n\n    const mode = args.primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n    btn.className = ['storybook-button', 'storybook-button--medium', mode].join(' ');\n\n    return btn;\n  },\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"preact\" language=\"js\"\n/** @jsx h */\nimport { h } from 'preact';\n\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = {\n  render: (args) => <Button {...args} />,\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"Primary\"\n  args={{\n    primary: true,\n    label: 'Button'\n  }}\n/>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"Primary\"\n  args={{\n    primary: true,\n    label: 'Button'\n  }}\n/>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.vue';\n\nexport default {\n  component: Button,\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = {\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: '<Button v-bind=\"args\" />',\n  }),\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport Button from './Button.vue';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary: Story = {\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: '<Button v-bind=\"args\" />',\n  }),\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = meta.story({\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: '<Button v-bind=\"args\" />',\n  }),\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = meta.story({\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: '<Button v-bind=\"args\" />',\n  }),\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n};\n\nexport const Primary = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  args: {\n    label: 'Button',\n    primary: true,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-with-emojis.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary: Story = {\n  render: () => ({\n    props: {\n      label: 'Button',\n      backgroundColor: '#ff0',\n    },\n  }),\n};\n\nexport const Secondary: Story = {\n  render: () => ({\n    props: {\n      label: '😄👍😍💯',\n      backgroundColor: '#ff0',\n    },\n  }),\n};\n\nexport const Tertiary: Story = {\n  render: () => ({\n    props: {\n      label: '📚📕📈🤓',\n      backgroundColor: '#ff0',\n    },\n  }),\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = meta.story({\n  render: () => ({\n    props: {\n      label: 'Button',\n      backgroundColor: '#ff0',\n    },\n  }),\n});\n\nexport const Secondary = meta.story({\n  render: () => ({\n    props: {\n      label: '😄👍😍💯',\n      backgroundColor: '#ff0',\n    },\n  }),\n});\n\nexport const Tertiary = meta.story({\n  render: () => ({\n    props: {\n      label: '📚📕📈🤓',\n      backgroundColor: '#ff0',\n    },\n  }),\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"html\" language=\"js\"\nimport { createButton } from './Button';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = {\n  render: (args) => createButton({ backgroundColor: '#ff0', label: 'Button' }),\n};\n\nexport const Secondary = {\n  render: (args) => createButton({ backgroundColor: '#ff0', label: '😄👍😍💯' }),\n};\n\nexport const Tertiary = {\n  render: (args) => createButton({ backgroundColor: '#ff0', label: '📚📕📈🤓' }),\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"html\" language=\"ts\"\nimport type { Meta, StoryObj } from '@storybook/html';\nimport { createButton, ButtonArgs } from './Button';\n\nconst meta: Meta<ButtonArgs> = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Button',\n};\n\nexport default meta;\ntype Story = StoryObj<ButtonArgs>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary: Story = {\n  render: (args) => createButton({ backgroundColor: '#ff0', label: 'Button' }),\n};\n\nexport const Secondary: Story = {\n  render: (args) => createButton({ backgroundColor: '#ff0', label: '😄👍😍💯' }),\n};\n\nexport const Tertiary: Story = {\n  render: (args) => createButton({ backgroundColor: '#ff0', label: '📚📕📈🤓' }),\n};\n```\n\n```jsx filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = {\n  render: () => <Button backgroundColor=\"#ff0\" label=\"Button\" />,\n};\n\nexport const Secondary = {\n  render: () => <Button backgroundColor=\"#ff0\" label=\"😄👍😍💯\" />,\n};\n\nexport const Tertiary = {\n  render: () => <Button backgroundColor=\"#ff0\" label=\"📚📕📈🤓\" />,\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary: Story = {\n  render: () => <Button backgroundColor=\"#ff0\" label=\"Button\" />,\n};\n\nexport const Secondary: Story = {\n  render: () => <Button backgroundColor=\"#ff0\" label=\"😄👍😍💯\" />,\n};\n\nexport const Tertiary: Story = {\n  render: () => <Button backgroundColor=\"#ff0\" label=\"📚📕📈🤓\" />,\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary: Story = {\n  render: () => <Button backgroundColor=\"#ff0\" label=\"Button\" />,\n};\n\nexport const Secondary: Story = {\n  render: () => <Button backgroundColor=\"#ff0\" label=\"😄👍😍💯\" />,\n};\n\nexport const Tertiary: Story = {\n  render: () => <Button backgroundColor=\"#ff0\" label=\"📚📕📈🤓\" />,\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n\tconst { Story } = defineMeta({\n\t\tcomponent: Button,\n\t});\n</script>\n\n<Story name=\"Primary\">\n  <Button backgroundColor=\"#ff0\" label=\"Button\" />\n</Story>\n\n<Story name=\"Secondary\">\n  <Button backgroundColor=\"#ff0\" label=\"😄👍😍💯\" />\n</Story>\n\n<Story name=\"Tertiary\">\n  <Button backgroundColor=\"#ff0\" label=\"📚📕📈🤓\" />\n</Story>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = {\n  render: () => ({\n    Component: Button,\n    props: {\n      backgroundColor: '#ff0',\n      label: 'Button',\n    },\n  }),\n};\n\nexport const Secondary = {\n  render: () => ({\n    Component: Button,\n    props: {\n      backgroundColor: '#ff0',\n      label: '😄👍😍💯',\n    },\n  }),\n};\n\nexport const Tertiary = {\n  render: () => ({\n    Component: Button,\n    props: {\n      backgroundColor: '#ff0',\n      label: '📚📕📈🤓',\n    },\n  }),\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n\tconst { Story } = defineMeta({\n\t\tcomponent: Button,\n\t});\n</script>\n\n<Story name=\"Primary\">\n  <Button backgroundColor=\"#ff0\" label=\"Button\" />\n</Story>\n\n<Story name=\"Secondary\">\n  <Button backgroundColor=\"#ff0\" label=\"😄👍😍💯\" />\n</Story>\n\n<Story name=\"Tertiary\">\n  <Button backgroundColor=\"#ff0\" label=\"📚📕📈🤓\" />\n</Story>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/svelte/api/csf\n * to learn how to use render functions.\n */\nexport const Primary: Story = {\n  render: () => ({\n    Component: Button,\n    props: {\n      backgroundColor: '#ff0',\n      label: 'Button',\n    },\n  }),\n};\n\nexport const Secondary: Story = {\n  render: () => ({\n    Component: Button,\n    props: {\n      backgroundColor: '#ff0',\n      label: '😄👍😍💯',\n    },\n  }),\n};\n\nexport const Tertiary: Story = {\n  render: () => ({\n    Component: Button,\n    props: {\n      backgroundColor: '#ff0',\n      label: '📚📕📈🤓',\n    },\n  }),\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.vue';\n\nexport default {\n  component: Button,\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = {\n  render: () => ({\n    components: { Button },\n    template: '<Button backgroundColor=\"#ff0\" label=\"Button\" />',\n  }),\n};\n\nexport const Secondary = {\n  render: () => ({\n    components: { Button },\n    template: '<Button backgroundColor=\"#ff0\" label=\"😄👍😍💯\" />',\n  }),\n};\n\nexport const Tertiary = {\n  render: () => ({\n    components: { Button },\n    template: '<Button backgroundColor=\"#ff0\" label=\"📚📕📈🤓\" />',\n  }),\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport Button from './Button.vue';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof Button>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary: Story = {\n  render: () => ({\n    components: { Button },\n    template: '<Button backgroundColor=\"#ff0\" label=\"Button\" />',\n  }),\n};\n\nexport const Secondary: Story = {\n  render: () => ({\n    components: { Button },\n    template: '<Button backgroundColor=\"#ff0\" label=\"😄👍😍💯\" />',\n  }),\n};\n\nexport const Tertiary: Story = {\n  render: () => ({\n    components: { Button },\n    template: '<Button backgroundColor=\"#ff0\" label=\"📚📕📈🤓\" />',\n  }),\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nexport default {\n  component: 'demo-button',\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = {\n  render: () => html`<demo-button .backgroundColor=\"#ff0\" .label=\"Button\"></demo-button>`,\n};\n\nexport const Secondary = {\n  render: () => html`<demo-button .backgroundColor=\"#ff0\" .label=\"😄👍😍💯\"></demo-button>`,\n};\n\nexport const Tertiary = {\n  render: () => html`<demo-button .backgroundColor=\"#ff0\" .label=\"📚📕📈🤓\"></demo-button>`,\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nconst meta: Meta = {\n  component: 'demo-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary: Story = {\n  render: () => html`<demo-button .backgroundColor=\"#ff0\" .label=\"Button\"></demo-button>`,\n};\n\nexport const Secondary: Story = {\n  render: () => html`<demo-button .backgroundColor=\"#ff0\" .label=\"😄👍😍💯\"></demo-button>`,\n};\n\nexport const Tertiary: Story = {\n  render: () => html`<demo-button .backgroundColor=\"#ff0\" .label=\"📚📕📈🤓\"></demo-button>`,\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = meta.story({\n  render: () => html`<demo-button .backgroundColor=\"#ff0\" .label=\"Button\"></demo-button>`,\n});\n\nexport const Secondary = meta.story({\n  render: () => html`<demo-button .backgroundColor=\"#ff0\" .label=\"😄👍😍💯\"></demo-button>`,\n});\n\nexport const Tertiary = meta.story({\n  render: () => html`<demo-button .backgroundColor=\"#ff0\" .label=\"📚📕📈🤓\"></demo-button>`,\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = meta.story({\n  render: () => html`<demo-button .backgroundColor=\"#ff0\" .label=\"Button\"></demo-button>`,\n});\n\nexport const Secondary = meta.story({\n  render: () => html`<demo-button .backgroundColor=\"#ff0\" .label=\"😄👍😍💯\"></demo-button>`,\n});\n\nexport const Tertiary = meta.story({\n  render: () => html`<demo-button .backgroundColor=\"#ff0\" .label=\"📚📕📈🤓\"></demo-button>`,\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = meta.story({\n  render: () => ({\n    components: { Button },\n    template: '<Button backgroundColor=\"#ff0\" label=\"Button\" />',\n  }),\n});\n\nexport const Secondary = meta.story({\n  render: () => ({\n    components: { Button },\n    template: '<Button backgroundColor=\"#ff0\" label=\"😄👍😍💯\" />',\n  }),\n});\n\nexport const Tertiary = meta.story({\n  render: () => ({\n    components: { Button },\n    template: '<Button backgroundColor=\"#ff0\" label=\"📚📕📈🤓\" />',\n  }),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = meta.story({\n  render: () => ({\n    components: { Button },\n    template: '<Button backgroundColor=\"#ff0\" label=\"Button\" />',\n  }),\n});\n\nexport const Secondary = meta.story({\n  render: () => ({\n    components: { Button },\n    template: '<Button backgroundColor=\"#ff0\" label=\"😄👍😍💯\" />',\n  }),\n});\n\nexport const Tertiary = meta.story({\n  render: () => ({\n    components: { Button },\n    template: '<Button backgroundColor=\"#ff0\" label=\"📚📕📈🤓\" />',\n  }),\n});\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = meta.story({\n  render: () => <Button backgroundColor=\"#ff0\" label=\"Button\" />,\n});\n\nexport const Secondary = meta.story({\n  render: () => <Button backgroundColor=\"#ff0\" label=\"😄👍😍💯\" />,\n});\n\nexport const Tertiary = meta.story({\n  render: () => <Button backgroundColor=\"#ff0\" label=\"📚📕📈🤓\" />,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = meta.story({\n  render: () => <Button backgroundColor=\"#ff0\" label=\"Button\" />,\n});\n\nexport const Secondary = meta.story({\n  render: () => <Button backgroundColor=\"#ff0\" label=\"😄👍😍💯\" />,\n});\n\nexport const Tertiary = meta.story({\n  render: () => <Button backgroundColor=\"#ff0\" label=\"📚📕📈🤓\" />,\n});\n```\n"
  },
  {
    "path": "docs/_snippets/button-story-with-sample.md",
    "content": "```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Sample = {\n  render: () => <Button label=\"hello button\" />,\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Sample = {\n  render: () => <Button label=\"hello button\" />,\n};\n```\n"
  },
  {
    "path": "docs/_snippets/button-story.md",
    "content": "```jsx filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport React, { useState } from 'react';\n\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nconst ButtonWithHooks = () => {\n  // Sets the hooks for both the label and primary props\n  const [value, setValue] = useState('Secondary');\n  const [isPrimary, setIsPrimary] = useState(false);\n\n  // Sets a click handler to change the label's value\n  const handleOnChange = () => {\n    if (!isPrimary) {\n      setIsPrimary(true);\n      setValue('Primary');\n    }\n  };\n  return <Button primary={isPrimary} onClick={handleOnChange} label={value} />;\n};\n\nexport const Primary = {\n  render: () => <ButtonWithHooks />,\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\nimport React, { useState } from 'react';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nconst ButtonWithHooks = () => {\n  // Sets the hooks for both the label and primary props\n  const [value, setValue] = useState('Secondary');\n  const [isPrimary, setIsPrimary] = useState(false);\n\n  // Sets a click handler to change the label's value\n  const handleOnChange = () => {\n    if (!isPrimary) {\n      setIsPrimary(true);\n      setValue('Primary');\n    }\n  };\n  return <Button primary={isPrimary} onClick={handleOnChange} label={value} />;\n};\n\nexport const Primary = {\n  render: () => <ButtonWithHooks />,\n} satisfies Story;\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport React, { useState } from 'react';\n\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nconst ButtonWithHooks = () => {\n  // Sets the hooks for both the label and primary props\n  const [value, setValue] = useState('Secondary');\n  const [isPrimary, setIsPrimary] = useState(false);\n\n  // Sets a click handler to change the label's value\n  const handleOnChange = () => {\n    if (!isPrimary) {\n      setIsPrimary(true);\n      setValue('Primary');\n    }\n  };\n  return <Button primary={isPrimary} onClick={handleOnChange} label={value} />;\n};\n\nexport const Primary = meta.story({\n  render: () => <ButtonWithHooks />,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport React, { useState } from 'react';\n\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nconst ButtonWithHooks = () => {\n  // Sets the hooks for both the label and primary props\n  const [value, setValue] = useState('Secondary');\n  const [isPrimary, setIsPrimary] = useState(false);\n\n  // Sets a click handler to change the label's value\n  const handleOnChange = () => {\n    if (!isPrimary) {\n      setIsPrimary(true);\n      setValue('Primary');\n    }\n  };\n  return <Button primary={isPrimary} onClick={handleOnChange} label={value} />;\n};\n\nexport const Primary = meta.story({\n  render: () => <ButtonWithHooks />,\n});\n```\n\n```jsx filename=\"Button.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { createSignal } from 'solid-js';\n\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nconst ButtonWithHooks = () => {\n  // Sets the signals for both the label and primary props\n  const [value, setValue] = createSignal('Secondary');\n  const [isPrimary, setIsPrimary] = createSignal(false);\n\n  // Sets a click handler to change the label's value\n  const handleOnChange = () => {\n    if (!isPrimary()) {\n      setIsPrimary(true);\n      setValue('Primary');\n    }\n  };\n  return <Button primary={isPrimary()} onClick={handleOnChange} label={value()} />;\n};\n\nexport const Primary = {\n  render: () => <ButtonWithHooks />,\n};\n```\n\n```tsx filename=\"Button.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { createSignal } from 'solid-js';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nconst ButtonWithHooks = () => {\n  // Sets the signals for both the label and primary props\n  const [value, setValue] = createSignal('Secondary');\n  const [isPrimary, setIsPrimary] = createSignal(false);\n\n  // Sets a click handler to change the label's value\n  const handleOnChange = () => {\n    if (!isPrimary()) {\n      setIsPrimary(true);\n      setValue('Primary');\n    }\n  };\n  return <Button primary={isPrimary()} onClick={handleOnChange} label={value()} />;\n};\n\nexport const Primary = {\n  render: () => <ButtonWithHooks />,\n} satisfies Story;\n```\n"
  },
  {
    "path": "docs/_snippets/checkbox-story-csf.md",
    "content": "```ts filename=\"Checkbox.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Checkbox } from './checkbox.component';\n\nconst meta: Meta<Checkbox> = {\n  component: Checkbox,\n};\n\nexport default meta;\ntype Story = StoryObj<Checkbox>;\n\nexport const Unchecked: Story = {\n  args: {\n    label: 'Unchecked',\n  },\n};\n```\n\n```ts filename=\"Checkbox.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Checkbox } from './checkbox.component';\n\nconst meta = preview.meta({\n  component: Checkbox,\n});\n\nexport const Unchecked = meta.story({\n  args: {\n    label: 'Unchecked',\n  },\n});\n```\n\n```svelte filename=\"Checkbox.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Checkbox from './Checkbox.svelte';\n\n  const { Story } = defineMeta({\n    component: Checkbox,\n  });\n</script>\n\n<Story\n  name=\"Unchecked\"\n  args={{\n    label: 'Unchecked',\n  }}\n/>\n```\n\n```js filename=\"Checkbox.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Checkbox from './Checkbox.svelte';\n\nexport default {\n  component: Checkbox,\n};\n\nexport const Unchecked = {\n  args: {\n    label: 'Unchecked',\n  },\n};\n```\n\n```js filename=\"Checkbox.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Checkbox } from './Checkbox';\n\nexport default {\n  component: Checkbox,\n};\n\nexport const Unchecked = {\n  args: {\n    label: 'Unchecked',\n  },\n};\n```\n\n```svelte filename=\"Checkbox.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Checkbox from './Checkbox.svelte';\n\n  const { Story } = defineMeta({\n    component: Checkbox,\n  });\n</script>\n\n<Story\n  name=\"Unchecked\"\n  args={{\n    label: 'Unchecked',\n  }}\n/>\n```\n\n```ts filename=\"Checkbox.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Checkbox from './Checkbox.svelte';\n\nconst meta = {\n  component: Checkbox,\n} satisfies Meta<typeof Checkbox>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Unchecked: Story = {\n  args: {\n    label: 'Unchecked',\n  },\n};\n```\n\n```ts filename=\"Checkbox.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Checkbox } from './Checkbox';\n\nconst meta = {\n  component: Checkbox,\n} satisfies Meta<typeof Checkbox>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Unchecked: Story = {\n  args: {\n    label: 'Unchecked',\n  },\n};\n```\n\n```js filename=\"Checkbox.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-checkbox',\n};\n\nexport const Unchecked = {\n  args: {\n    label: 'Unchecked',\n  },\n};\n```\n\n```ts filename=\"Checkbox.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-checkbox',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Unchecked: Story = {\n  args: {\n    label: 'Unchecked',\n  },\n};\n```\n\n```js filename=\"Checkbox.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-checkbox',\n});\n\nexport const Unchecked = meta.story({\n  args: {\n    label: 'Unchecked',\n  },\n});\n```\n\n```ts filename=\"Checkbox.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-checkbox',\n});\n\nexport const Unchecked = meta.story({\n  args: {\n    label: 'Unchecked',\n  },\n});\n```\n\n```ts filename=\"Checkbox.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Checkbox } from './Checkbox';\n\nconst meta = preview.meta({\n  component: Checkbox,\n});\n\nexport const Unchecked = meta.story({\n  args: {\n    label: 'Unchecked',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Checkbox.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Checkbox } from './Checkbox';\n\nconst meta = preview.meta({\n  component: Checkbox,\n});\n\nexport const Unchecked = meta.story({\n  args: {\n    label: 'Unchecked',\n  },\n});\n```\n\n```ts filename=\"Checkbox.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Checkbox from './Checkbox.vue';\n\nconst meta = preview.meta({\n  component: Checkbox,\n});\n\nexport const Unchecked = meta.story({\n  args: {\n    label: 'Unchecked',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Checkbox.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Checkbox from './Checkbox.vue';\n\nconst meta = preview.meta({\n  component: Checkbox,\n});\n\nexport const Unchecked = meta.story({\n  args: {\n    label: 'Unchecked',\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/checkbox-story-grouped.md",
    "content": "```ts filename=\"Checkbox.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Checkbox } from './checkbox.component';\n\nconst meta: Meta<Checkbox> = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Checkbox',\n  component: Checkbox,\n};\n\nexport default meta;\n```\n\n```ts filename=\"Checkbox.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Checkbox } from './checkbox.component';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Checkbox',\n  component: Checkbox,\n});\n```\n\n```svelte filename=\"Checkbox.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Checkbox from './Checkbox.svelte';\n\n  const { Story } = defineMeta({\n    /* 👇 The title prop is optional.\n     * See https://storybook.js.org/docs/configure/#configure-story-loading\n     * to learn how to generate automatic titles\n     */\n    title: 'Design System/Atoms/Checkbox',\n    component: Checkbox,\n  });\n</script>\n```\n\n```js filename=\"Checkbox.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Checkbox from './Checkbox.svelte';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Checkbox',\n  component: Checkbox,\n};\n```\n\n```js filename=\"Checkbox.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Checkbox } from './Checkbox';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Checkbox',\n  component: Checkbox,\n};\n```\n\n```svelte filename=\"Checkbox.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Checkbox from './Checkbox.svelte';\n\n  const { Story } = defineMeta({\n    /* 👇 The title prop is optional.\n     * See https://storybook.js.org/docs/configure/#configure-story-loading\n     * to learn how to generate automatic titles\n     */\n    title: 'Design System/Atoms/Checkbox',\n    component: Checkbox,\n  });\n</script>\n```\n\n```ts filename=\"Checkbox.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Checkbox from './Checkbox.svelte';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Checkbox',\n  component: Checkbox,\n} satisfies Meta<typeof Checkbox>;\n\nexport default meta;\n```\n\n```ts filename=\"Checkbox.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Checkbox } from './Checkbox';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Checkbox',\n  component: Checkbox,\n} satisfies Meta<typeof Checkbox>;\n\nexport default meta;\n```\n\n```js filename=\"Checkbox.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  title: 'Design System/Atoms/Checkbox',\n  component: 'demo-checkbox',\n};\n```\n\n```ts filename=\"Checkbox.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  title: 'Design System/Atoms/Checkbox',\n  component: 'demo-checkbox',\n};\n\nexport default meta;\n```\n\n```js filename=\"Checkbox.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  title: 'Design System/Atoms/Checkbox',\n  component: 'demo-checkbox',\n});\n```\n\n```ts filename=\"Checkbox.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  title: 'Design System/Atoms/Checkbox',\n  component: 'demo-checkbox',\n});\n```\n\n```ts filename=\"Checkbox.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Checkbox } from './Checkbox';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Checkbox',\n  component: Checkbox,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Checkbox.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Checkbox } from './Checkbox';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Checkbox',\n  component: Checkbox,\n});\n```\n\n```ts filename=\"Checkbox.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Checkbox from './Checkbox.vue';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Checkbox',\n  component: Checkbox,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Checkbox.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Checkbox from './Checkbox.vue';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Design System/Atoms/Checkbox',\n  component: Checkbox,\n});\n```\n"
  },
  {
    "path": "docs/_snippets/checkbox-story.md",
    "content": "<!-- prettier-ignore -->\n```mdx filename=\"Checkbox.mdx\" renderer=\"common\" language=\"mdx\"\nimport { Canvas, Meta } from '@storybook/addon-docs/blocks';\n\nimport * as CheckboxStories from './Checkbox.stories';\n\n<Meta of={CheckboxStories} />\n\n# Checkbox\n\nA checkbox is a square box that can be activated or deactivated when ticked.\n\nUse checkboxes to select one or more options from a list of choices.\n\n<Canvas of={CheckboxStories.Unchecked} />\n```\n\n<!-- prettier-ignore -->\n```mdx filename=\"Checkbox.mdx\" renderer=\"svelte\" language=\"mdx\" tabTitle=\"Svelte CSF\"\nimport { Canvas, Meta } from '@storybook/addon-docs/blocks';\n\nimport * as CheckboxStories from './Checkbox.stories.svelte';\n\n<Meta of={CheckboxStories} />\n\n# Checkbox\n\nA checkbox is a square box that can be activated or deactivated when ticked.\n\nUse checkboxes to select one or more options from a list of choices.\n\n<Canvas of={CheckboxStories.Unchecked} />\n```\n\n<!-- prettier-ignore -->\n```mdx filename=\"Checkbox.mdx\" renderer=\"svelte\" language=\"mdx\" tabTitle=\"CSF 3\"\nimport { Canvas, Meta } from '@storybook/addon-docs/blocks';\n\nimport * as CheckboxStories from './Checkbox.stories';\n\n<Meta of={CheckboxStories} />\n\n# Checkbox\n\nA checkbox is a square box that can be activated or deactivated when ticked.\n\nUse checkboxes to select one or more options from a list of choices.\n\n<Canvas of={CheckboxStories.Unchecked} />\n```\n"
  },
  {
    "path": "docs/_snippets/chromatic-github-action.md",
    "content": "```yml filename=\".github/workflows/chromatic.yml\" renderer=\"common\" language=\"js\"\n# Workflow name\nname: 'Chromatic Publish'\n\n# Event for the workflow\non: push\n\n# List of jobs\njobs:\n  test:\n    # Operating System\n    runs-on: ubuntu-latest\n    # Job steps\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          fetch-depth: 0\n      - uses: actions/setup-node@v6\n        with:\n          node-version: 24\n          cache: 'yarn'\n      - run: yarn\n      #👇 Adds Chromatic as a step in the workflow\n      - uses: chromaui/action@latest\n        # Options required for Chromatic's GitHub Action\n        with:\n          #👇 Chromatic projectToken,\n          projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}\n          token: ${{ secrets.GITHUB_TOKEN }}\n```\n"
  },
  {
    "path": "docs/_snippets/chromatic-install.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm install chromatic --save-dev\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm add --save-dev chromatic\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn add --dev chromatic\n```\n"
  },
  {
    "path": "docs/_snippets/chromatic-storybook-add.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook@latest add @chromatic-com/storybook\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx storybook@latest add @chromatic-com/storybook\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn dlx storybook@latest add @chromatic-com/storybook\n```\n"
  },
  {
    "path": "docs/_snippets/code-panel-enable-in-preview.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    docs: {\n      codePanel: true,\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using (e.g., react-vite, vue3-vite, angular, etc.)\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    docs: {\n      codePanel: true,\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    docs: {\n      codePanel: true,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    docs: {\n      codePanel: true,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    docs: {\n      codePanel: true,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    docs: {\n      codePanel: true,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  parameters: {\n    docs: {\n      codePanel: true,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    docs: {\n      codePanel: true,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    docs: {\n      codePanel: true,\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/code-panel-in-meta-and-story.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  parameters: {\n    docs: {\n      // 👇 Enable Code panel for all stories in this file\n      codePanel: true,\n    },\n  },\n};\nexport default meta;\n\ntype Story = StoryObj<typeof Button>;\n\n// 👇 This story will display the Code panel\nexport const Primary: Story = {\n  args: {\n    children: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    children: 'Button',\n    variant: 'secondary',\n  },\n  parameters: {\n    docs: {\n      // 👇 Disable Code panel for this specific story\n      codePanel: false,\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    docs: {\n      // 👇 Enable Code panel for all stories in this file\n      codePanel: true,\n    },\n  },\n});\n\n// 👇 This story will display the Code panel\nexport const Primary = meta.story({\n  args: {\n    children: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  args: {\n    children: 'Button',\n    variant: 'secondary',\n  },\n  parameters: {\n    docs: {\n      // 👇 Disable Code panel for this specific story\n      codePanel: false,\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/react-vite';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  parameters: {\n    docs: {\n      // 👇 Enable Code panel for all stories in this file\n      codePanel: true,\n    },\n  },\n} satisfies Meta<typeof Button>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n// 👇 This story will display the Code panel\nexport const Primary: Story = {\n  args: {\n    children: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    children: 'Button',\n    variant: 'secondary',\n  },\n  parameters: {\n    docs: {\n      // 👇 Disable Code panel for this specific story\n      codePanel: false,\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  parameters: {\n    docs: {\n      // 👇 Enable Code panel for all stories in this file\n      codePanel: true,\n    },\n  },\n};\n\n// 👇 This story will display the Code panel\nexport const Primary = {\n  args: {\n    children: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    children: 'Button',\n    variant: 'secondary',\n  },\n  parameters: {\n    docs: {\n      // 👇 Disable Code panel for this specific story\n      codePanel: false,\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    parameters: {\n      docs: {\n        // 👇 Enable Code panel for all stories in this file\n        codePanel: true,\n      },\n    },\n  });\n</script>\n\n<Story\n  name=\"Primary\"\n  args={{\n    children: 'Button',\n  }}\n/>\n\n<Story\n  name=\"Secondary\"\n  args={{\n    children: 'Button',\n    variant: 'secondary',\n  }}\n  parameters={{\n    docs: {\n      // 👇 Disable Code panel for this specific story\n      codePanel: false,\n    },\n  }}\n/>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  parameters: {\n    docs: {\n      // 👇 Enable Code panel for all stories in this file\n      codePanel: true,\n    },\n  },\n} satisfies Meta<typeof Button>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n// 👇 This story will display the Code panel\nexport const Primary: Story = {\n  args: {\n    children: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    children: 'Button',\n    variant: 'secondary',\n  },\n  parameters: {\n    docs: {\n      // 👇 Disable Code panel for this specific story\n      codePanel: false,\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    parameters: {\n      docs: {\n        // 👇 Enable Code panel for all stories in this file\n        codePanel: true,\n      },\n    },\n  });\n</script>\n\n<Story\n  name=\"Primary\"\n  args={{\n    children: 'Button',\n  }}\n/>\n\n<Story\n  name=\"Secondary\"\n  args={{\n    children: 'Button',\n    variant: 'secondary',\n  }}\n  parameters={{\n    docs: {\n      // 👇 Disable Code panel for this specific story\n      codePanel: false,\n    },\n  }}\n/>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  parameters: {\n    docs: {\n      // 👇 Enable Code panel for all stories in this file\n      codePanel: true,\n    },\n  },\n};\n\n// 👇 This story will display the Code panel\nexport const Primary = {\n  args: {\n    children: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    children: 'Button',\n    variant: 'secondary',\n  },\n  parameters: {\n    docs: {\n      // 👇 Disable Code panel for this specific story\n      codePanel: false,\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport Button from './Button.vue';\n\nconst meta = {\n  component: Button,\n  parameters: {\n    docs: {\n      // 👇 Enable Code panel for all stories in this file\n      codePanel: true,\n    },\n  },\n} satisfies Meta<typeof Button>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n// 👇 This story will display the Code panel\nexport const Primary: Story = {\n  args: {\n    children: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    children: 'Button',\n    variant: 'secondary',\n  },\n  parameters: {\n    docs: {\n      // 👇 Disable Code panel for this specific story\n      codePanel: false,\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.vue';\n\nexport default {\n  component: Button,\n  parameters: {\n    docs: {\n      // 👇 Enable Code panel for all stories in this file\n      codePanel: true,\n    },\n  },\n};\n\n// 👇 This story will display the Code panel\nexport const Primary = {\n  args: {\n    children: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    children: 'Button',\n    variant: 'secondary',\n  },\n  parameters: {\n    docs: {\n      // 👇 Disable Code panel for this specific story\n      codePanel: false,\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    docs: {\n      // 👇 Enable Code panel for all stories in this file\n      codePanel: true,\n    },\n  },\n});\n\n// 👇 This story will display the Code panel\nexport const Primary = meta.story({\n  args: {\n    children: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  args: {\n    children: 'Button',\n    variant: 'secondary',\n  },\n  parameters: {\n    docs: {\n      // 👇 Disable Code panel for this specific story\n      codePanel: false,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    docs: {\n      // 👇 Enable Code panel for all stories in this file\n      codePanel: true,\n    },\n  },\n});\n\n// 👇 This story will display the Code panel\nexport const Primary = meta.story({\n  args: {\n    children: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  args: {\n    children: 'Button',\n    variant: 'secondary',\n  },\n  parameters: {\n    docs: {\n      // 👇 Disable Code panel for this specific story\n      codePanel: false,\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  parameters: {\n    docs: {\n      // 👇 Enable Code panel for all stories in this file\n      codePanel: true,\n    },\n  },\n};\nexport default meta;\n\ntype Story = StoryObj;\n\n// 👇 This story will display the Code panel\nexport const Primary: Story = {\n  args: {\n    children: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    children: 'Button',\n    variant: 'secondary',\n  },\n  parameters: {\n    docs: {\n      // 👇 Disable Code panel for this specific story\n      codePanel: false,\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n  parameters: {\n    docs: {\n      // 👇 Enable Code panel for all stories in this file\n      codePanel: true,\n    },\n  },\n};\n\n// 👇 This story will display the Code panel\nexport const Primary = {\n  args: {\n    children: 'Button',\n  },\n};\n\nexport const Secondary = {\n  args: {\n    children: 'Button',\n    variant: 'secondary',\n  },\n  parameters: {\n    docs: {\n      // 👇 Disable Code panel for this specific story\n      codePanel: false,\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  parameters: {\n    docs: {\n      // 👇 Enable Code panel for all stories in this file\n      codePanel: true,\n    },\n  },\n});\n\n// 👇 This story will display the Code panel\nexport const Primary = meta.story({\n  args: {\n    children: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  args: {\n    children: 'Button',\n    variant: 'secondary',\n  },\n  parameters: {\n    docs: {\n      // 👇 Disable Code panel for this specific story\n      codePanel: false,\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  parameters: {\n    docs: {\n      // 👇 Enable Code panel for all stories in this file\n      codePanel: true,\n    },\n  },\n});\n\n// 👇 This story will display the Code panel\nexport const Primary = meta.story({\n  args: {\n    children: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  args: {\n    children: 'Button',\n    variant: 'secondary',\n  },\n  parameters: {\n    docs: {\n      // 👇 Disable Code panel for this specific story\n      codePanel: false,\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    docs: {\n      // 👇 Enable Code panel for all stories in this file\n      codePanel: true,\n    },\n  },\n});\n\n// 👇 This story will display the Code panel\nexport const Primary = meta.story({\n  args: {\n    children: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  args: {\n    children: 'Button',\n    variant: 'secondary',\n  },\n  parameters: {\n    docs: {\n      // 👇 Disable Code panel for this specific story\n      codePanel: false,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    docs: {\n      // 👇 Enable Code panel for all stories in this file\n      codePanel: true,\n    },\n  },\n});\n\n// 👇 This story will display the Code panel\nexport const Primary = meta.story({\n  args: {\n    children: 'Button',\n  },\n});\n\nexport const Secondary = meta.story({\n  args: {\n    children: 'Button',\n    variant: 'secondary',\n  },\n  parameters: {\n    docs: {\n      // 👇 Disable Code panel for this specific story\n      codePanel: false,\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/compodoc-install.md",
    "content": "```shell renderer=\"angular\" language=\"js\" packageManager=\"npm\"\nnpm install @compodoc/compodoc --save-dev\n```\n\n```shell renderer=\"angular\" language=\"js\" packageManager=\"pnpm\"\npnpm add --save-dev @compodoc/compodoc\n```\n\n```shell renderer=\"angular\" language=\"js\" packageManager=\"yarn\"\nyarn add --dev @compodoc/compodoc\n```\n"
  },
  {
    "path": "docs/_snippets/component-cypress-test.md",
    "content": "```js filename=\"/cypress/integration/Login.spec.js\" renderer=\"common\" language=\"js\"\n/// <reference types=\"cypress\" />\n\ndescribe('Login Form', () => {\n  it('Should contain valid login information', () => {\n    cy.visit('/iframe.html?id=components-login-form--example');\n    cy.get('#login-form').within(() => {\n      cy.log('**enter the email**');\n      cy.get('#email').should('have.value', 'email@provider.com');\n      cy.log('**enter password**');\n      cy.get('#password').should('have.value', 'a-random-password');\n    });\n  });\n});\n```\n"
  },
  {
    "path": "docs/_snippets/component-playwright-test.md",
    "content": "```js filename=\"tests/login-form/login.spec.js\" renderer=\"common\" language=\"js\"\nimport { test, expect } from '@playwright/test';\n\ntest('Login Form inputs', async ({ page }) => {\n  await page.goto('http://localhost:6006/iframe.html?id=components-login-form--example');\n  const email = await page.inputValue('#email');\n  const password = await page.inputValue('#password');\n  await expect(email).toBe('email@provider.com');\n  await expect(password).toBe('a-random-password');\n});\n```\n"
  },
  {
    "path": "docs/_snippets/component-story-conditional-controls-mutual-exclusion.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  argTypes: {\n    // Button can be passed a label or an image, not both\n    label: {\n      control: 'text',\n      if: { arg: 'image', truthy: false },\n    },\n    image: {\n      control: { type: 'select', options: ['foo.jpg', 'bar.jpg'] },\n      if: { arg: 'label', truthy: false },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    // Button can be passed a label or an image, not both\n    label: {\n      control: 'text',\n      if: { arg: 'image', truthy: false },\n    },\n    image: {\n      control: { type: 'select', options: ['foo.jpg', 'bar.jpg'] },\n      if: { arg: 'label', truthy: false },\n    },\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    argTypes: {\n      // Button can be passed a label or an image, not both\n      label: {\n        control: 'text',\n        if: { arg: 'image', truthy: false },\n      },\n      image: {\n        control: { type: 'select', options: ['foo.jpg', 'bar.jpg'] },\n        if: { arg: 'label', truthy: false },\n      },\n    },\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  argTypes: {\n    // Button can be passed a label or an image, not both\n    label: {\n      control: 'text',\n      if: { arg: 'image', truthy: false },\n    },\n    image: {\n      control: { type: 'select', options: ['foo.jpg', 'bar.jpg'] },\n      if: { arg: 'label', truthy: false },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  argTypes: {\n    // Button can be passed a label or an image, not both\n    label: {\n      control: 'text',\n      if: { arg: 'image', truthy: false },\n    },\n    image: {\n      control: { type: 'select', options: ['foo.jpg', 'bar.jpg'] },\n      if: { arg: 'label', truthy: false },\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    argTypes: {\n      // Button can be passed a label or an image, not both\n      label: {\n        control: 'text',\n        if: { arg: 'image', truthy: false },\n      },\n      image: {\n        control: { type: 'select', options: ['foo.jpg', 'bar.jpg'] },\n        if: { arg: 'label', truthy: false },\n      },\n    },\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  argTypes: {\n    // Button can be passed a label or an image, not both\n    label: {\n      control: 'text',\n      if: { arg: 'image', truthy: false },\n    },\n    image: {\n      control: { type: 'select', options: ['foo.jpg', 'bar.jpg'] },\n      if: { arg: 'label', truthy: false },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  argTypes: {\n    // Button can be passed a label or an image, not both\n    label: {\n      control: 'text',\n      if: { arg: 'image', truthy: false },\n    },\n    image: {\n      control: { type: 'select', options: ['foo.jpg', 'bar.jpg'] },\n      if: { arg: 'label', truthy: false },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n  argTypes: {\n    // Button can be passed a label or an image, not both\n    label: {\n      control: 'text',\n      if: { arg: 'image', truthy: false },\n    },\n    image: {\n      control: { type: 'select', options: ['foo.jpg', 'bar.jpg'] },\n      if: { arg: 'label', truthy: false },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  argTypes: {\n    // Button can be passed a label or an image, not both\n    label: {\n      control: 'text',\n      if: { arg: 'image', truthy: false },\n    },\n    image: {\n      control: { type: 'select', options: ['foo.jpg', 'bar.jpg'] },\n      if: { arg: 'label', truthy: false },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  argTypes: {\n    // Button can be passed a label or an image, not both\n    label: {\n      control: 'text',\n      if: { arg: 'image', truthy: false },\n    },\n    image: {\n      control: { type: 'select', options: ['foo.jpg', 'bar.jpg'] },\n      if: { arg: 'label', truthy: false },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  argTypes: {\n    // Button can be passed a label or an image, not both\n    label: {\n      control: 'text',\n      if: { arg: 'image', truthy: false },\n    },\n    image: {\n      control: { type: 'select', options: ['foo.jpg', 'bar.jpg'] },\n      if: { arg: 'label', truthy: false },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    // Button can be passed a label or an image, not both\n    label: {\n      control: 'text',\n      if: { arg: 'image', truthy: false },\n    },\n    image: {\n      control: { type: 'select', options: ['foo.jpg', 'bar.jpg'] },\n      if: { arg: 'label', truthy: false },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    // Button can be passed a label or an image, not both\n    label: {\n      control: 'text',\n      if: { arg: 'image', truthy: false },\n    },\n    image: {\n      control: { type: 'select', options: ['foo.jpg', 'bar.jpg'] },\n      if: { arg: 'label', truthy: false },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    // Button can be passed a label or an image, not both\n    label: {\n      control: 'text',\n      if: { arg: 'image', truthy: false },\n    },\n    image: {\n      control: { type: 'select', options: ['foo.jpg', 'bar.jpg'] },\n      if: { arg: 'label', truthy: false },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    // Button can be passed a label or an image, not both\n    label: {\n      control: 'text',\n      if: { arg: 'image', truthy: false },\n    },\n    image: {\n      control: { type: 'select', options: ['foo.jpg', 'bar.jpg'] },\n      if: { arg: 'label', truthy: false },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/component-story-conditional-controls-toggle.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  argTypes: {\n    label: { control: 'text' }, // Always shows the control\n    advanced: { control: 'boolean' },\n    // Only enabled if advanced is true\n    margin: { control: 'number', if: { arg: 'advanced' } },\n    padding: { control: 'number', if: { arg: 'advanced' } },\n    cornerRadius: { control: 'number', if: { arg: 'advanced' } },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    label: { control: 'text' }, // Always shows the control\n    advanced: { control: 'boolean' },\n    // Only enabled if advanced is true\n    margin: { control: 'number', if: { arg: 'advanced' } },\n    padding: { control: 'number', if: { arg: 'advanced' } },\n    cornerRadius: { control: 'number', if: { arg: 'advanced' } },\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    argTypes: {\n      label: { control: 'text' }, // Always shows the control\n      advanced: { control: 'boolean' },\n      // Only enabled if advanced is true\n      margin: { control: 'number', if: { arg: 'advanced' } },\n      padding: { control: 'number', if: { arg: 'advanced' } },\n      cornerRadius: { control: 'number', if: { arg: 'advanced' } },\n    },\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  argTypes: {\n    label: { control: 'text' }, // Always shows the control\n    advanced: { control: 'boolean' },\n    // Only enabled if advanced is true\n    margin: { control: 'number', if: { arg: 'advanced' } },\n    padding: { control: 'number', if: { arg: 'advanced' } },\n    cornerRadius: { control: 'number', if: { arg: 'advanced' } },\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  argTypes: {\n    label: { control: 'text' }, // Always shows the control\n    advanced: { control: 'boolean' },\n    // Only enabled if advanced is true\n    margin: { control: 'number', if: { arg: 'advanced' } },\n    padding: { control: 'number', if: { arg: 'advanced' } },\n    cornerRadius: { control: 'number', if: { arg: 'advanced' } },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    argTypes: {\n      label: { control: 'text' }, // Always shows the control\n      advanced: { control: 'boolean' },\n      // Only enabled if advanced is true\n      margin: { control: 'number', if: { arg: 'advanced' } },\n      padding: { control: 'number', if: { arg: 'advanced' } },\n      cornerRadius: { control: 'number', if: { arg: 'advanced' } },\n    },\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  argTypes: {\n    label: { control: 'text' }, // Always shows the control\n    advanced: { control: 'boolean' },\n    // Only enabled if advanced is true\n    margin: { control: 'number', if: { arg: 'advanced' } },\n    padding: { control: 'number', if: { arg: 'advanced' } },\n    cornerRadius: { control: 'number', if: { arg: 'advanced' } },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  argTypes: {\n    label: { control: 'text' }, // Always shows the control\n    advanced: { control: 'boolean' },\n    // Only enabled if advanced is true\n    margin: { control: 'number', if: { arg: 'advanced' } },\n    padding: { control: 'number', if: { arg: 'advanced' } },\n    cornerRadius: { control: 'number', if: { arg: 'advanced' } },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n  argTypes: {\n    label: { control: 'text' }, // Always shows the control\n    advanced: { control: 'boolean' },\n    // Only enabled if advanced is true\n    margin: { control: 'number', if: { arg: 'advanced' } },\n    padding: { control: 'number', if: { arg: 'advanced' } },\n    cornerRadius: { control: 'number', if: { arg: 'advanced' } },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  argTypes: {\n    label: { control: 'text' }, // Always shows the control\n    advanced: { control: 'boolean' },\n    // Only enabled if advanced is true\n    margin: { control: 'number', if: { arg: 'advanced' } },\n    padding: { control: 'number', if: { arg: 'advanced' } },\n    cornerRadius: { control: 'number', if: { arg: 'advanced' } },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  argTypes: {\n    label: { control: 'text' }, // Always shows the control\n    advanced: { control: 'boolean' },\n    // Only enabled if advanced is true\n    margin: { control: 'number', if: { arg: 'advanced' } },\n    padding: { control: 'number', if: { arg: 'advanced' } },\n    cornerRadius: { control: 'number', if: { arg: 'advanced' } },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  argTypes: {\n    label: { control: 'text' }, // Always shows the control\n    advanced: { control: 'boolean' },\n    // Only enabled if advanced is true\n    margin: { control: 'number', if: { arg: 'advanced' } },\n    padding: { control: 'number', if: { arg: 'advanced' } },\n    cornerRadius: { control: 'number', if: { arg: 'advanced' } },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    label: { control: 'text' }, // Always shows the control\n    advanced: { control: 'boolean' },\n    // Only enabled if advanced is true\n    margin: { control: 'number', if: { arg: 'advanced' } },\n    padding: { control: 'number', if: { arg: 'advanced' } },\n    cornerRadius: { control: 'number', if: { arg: 'advanced' } },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    label: { control: 'text' }, // Always shows the control\n    advanced: { control: 'boolean' },\n    // Only enabled if advanced is true\n    margin: { control: 'number', if: { arg: 'advanced' } },\n    padding: { control: 'number', if: { arg: 'advanced' } },\n    cornerRadius: { control: 'number', if: { arg: 'advanced' } },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    label: { control: 'text' }, // Always shows the control\n    advanced: { control: 'boolean' },\n    // Only enabled if advanced is true\n    margin: { control: 'number', if: { arg: 'advanced' } },\n    padding: { control: 'number', if: { arg: 'advanced' } },\n    cornerRadius: { control: 'number', if: { arg: 'advanced' } },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    label: { control: 'text' }, // Always shows the control\n    advanced: { control: 'boolean' },\n    // Only enabled if advanced is true\n    margin: { control: 'number', if: { arg: 'advanced' } },\n    padding: { control: 'number', if: { arg: 'advanced' } },\n    cornerRadius: { control: 'number', if: { arg: 'advanced' } },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/component-story-custom-args-complex.md",
    "content": "```ts filename=\"YourComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { YourComponent } from './your-component.component';\n\nconst meta: Meta<YourComponent> = {\n  component: YourComponent,\n  //👇 Creates specific argTypes with options\n  argTypes: {\n    propertyA: {\n      options: ['Item One', 'Item Two', 'Item Three'],\n      control: { type: 'select' }, // automatically inferred when 'options' is defined\n    },\n    propertyB: {\n      options: ['Another Item One', 'Another Item Two', 'Another Item Three'],\n    },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj<YourComponent>;\n\nconst someFunction = (valuePropertyA: String, valuePropertyB: String) => {\n  // Do some logic here\n};\n\nexport const ExampleStory: Story = {\n  render: (args) => {\n    const { propertyA, propertyB } = args;\n    //👇 Assigns the function result to a variable\n    const someFunctionResult = someFunction(propertyA, propertyB);\n    return {\n      props: {\n        ...args,\n        someProperty: someFunctionResult,\n      },\n    };\n  },\n  args: { propertyA: 'Item One', propertyB: 'Another Item One' },\n};\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './your-component.component';\n\nconst someFunction = (valuePropertyA: String, valuePropertyB: String) => {\n  // Do some logic here\n};\n\nconst meta = preview.meta({\n  component: YourComponent,\n  //👇 Creates specific argTypes with options\n  argTypes: {\n    propertyA: {\n      options: ['Item One', 'Item Two', 'Item Three'],\n      control: { type: 'select' }, // automatically inferred when 'options' is defined\n    },\n    propertyB: {\n      options: ['Another Item One', 'Another Item Two', 'Another Item Three'],\n    },\n  },\n});\n\nexport const ExampleStory = meta.story({\n  render: (args) => {\n    const { propertyA, propertyB } = args;\n    //👇 Assigns the function result to a variable\n    const someFunctionResult = someFunction(propertyA, propertyB);\n    return {\n      props: {\n        ...args,\n        someProperty: someFunctionResult,\n      },\n    };\n  },\n  args: { propertyA: 'Item One', propertyB: 'Another Item One' },\n});\n```\n\n```jsx filename=\"YourComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { YourComponent } from './your-component';\n\nexport default {\n  component: YourComponent,\n  //👇 Creates specific argTypes with options\n  argTypes: {\n    propertyA: {\n      options: ['Item One', 'Item Two', 'Item Three'],\n      control: { type: 'select' }, // Automatically inferred when 'options' is defined\n    },\n    propertyB: {\n      options: ['Another Item One', 'Another Item Two', 'Another Item Three'],\n    },\n  },\n};\n\nconst someFunction = (valuePropertyA, valuePropertyB) => {\n  // Do some logic here\n};\n\nexport const ExampleStory = {\n  render: (args) => {\n    const { propertyA, propertyB } = args;\n    //👇 Assigns the function result to a variable\n    const someFunctionResult = someFunction(propertyA, propertyB);\n\n    return <YourComponent {...args} someProperty={someFunctionResult} />;\n  },\n  args: {\n    propertyA: 'Item One',\n    propertyB: 'Another Item One',\n  },\n};\n```\n\n```tsx filename=\"YourComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { YourComponent } from './your-component';\n\nconst meta = {\n  component: YourComponent,\n  //👇 Creates specific argTypes with options\n  argTypes: {\n    propertyA: {\n      options: ['Item One', 'Item Two', 'Item Three'],\n      control: { type: 'select' }, // Automatically inferred when 'options' is defined\n    },\n    propertyB: {\n      options: ['Another Item One', 'Another Item Two', 'Another Item Three'],\n    },\n  },\n} satisfies Meta<typeof YourComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nconst someFunction = (valuePropertyA, valuePropertyB) => {\n  // Do some logic here\n};\n\nexport const ExampleStory: Story = {\n  render: (args) => {\n    const { propertyA, propertyB } = args;\n    //👇 Assigns the function result to a variable\n    const someFunctionResult = someFunction(propertyA, propertyB);\n\n    return <YourComponent {...args} someProperty={someFunctionResult} />;\n  },\n  args: {\n    propertyA: 'Item One',\n    propertyB: 'Another Item One',\n  },\n};\n```\n\n```jsx filename=\"YourComponent.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { createSignal, createEffect } from 'solid-js';\n\nimport { YourComponent } from './your-component';\n\nexport default {\n  component: YourComponent,\n  //👇 Creates specific argTypes with options\n  argTypes: {\n    propertyA: {\n      options: ['Item One', 'Item Two', 'Item Three'],\n      control: { type: 'select' }, // Automatically inferred when 'options' is defined\n    },\n    propertyB: {\n      options: ['Another Item One', 'Another Item Two', 'Another Item Three'],\n    },\n  },\n};\n\nconst someFunction = (valuePropertyA, valuePropertyB) => {\n  // Do some logic here\n};\n\nexport const ExampleStory = {\n  render: (args) => {\n    const [someFunctionResult, setSomeFunctionResult] = createSignal();\n\n    //👇 Assigns the function result to a signal\n    createEffect(() => {\n      setSomeFunctionResult(someFunction(args.propertyA, args.propertyB));\n    });\n\n    return <YourComponent {...args} someProperty={someFunctionResult()} />;\n  },\n  args: {\n    propertyA: 'Item One',\n    propertyB: 'Another Item One',\n  },\n};\n```\n\n```tsx filename=\"YourComponent.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { createSignal, createEffect } from 'solid-js';\n\nimport { YourComponent } from './your-component';\n\nconst meta = {\n  component: YourComponent,\n  //👇 Creates specific argTypes with options\n  argTypes: {\n    propertyA: {\n      options: ['Item One', 'Item Two', 'Item Three'],\n      control: { type: 'select' }, // Automatically inferred when 'options' is defined\n    },\n    propertyB: {\n      options: ['Another Item One', 'Another Item Two', 'Another Item Three'],\n    },\n  },\n} satisfies Meta<typeof YourComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nconst someFunction = (valuePropertyA, valuePropertyB) => {\n  // Do some logic here\n};\n\nexport const ExampleStory: Story = {\n  render: (args) => {\n    const [someFunctionResult, setSomeFunctionResult] = createSignal();\n\n    //👇 Assigns the function result to a signal\n    createEffect(() => {\n      setSomeFunctionResult(someFunction(args.propertyA, args.propertyB));\n    });\n\n    return <YourComponent {...args} someProperty={someFunctionResult()} />;\n  },\n  args: {\n    propertyA: 'Item One',\n    propertyB: 'Another Item One',\n  },\n};\n```\n\n```svelte filename=\"YourComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import YourComponent from './YourComponent.svelte';\n\n  const { Story } = defineMeta({\n      component: YourComponent,\n      //👇 Creates specific argTypes\n      argTypes: {\n        propertyA: {\n          options: ['Item One', 'Item Two', 'Item Three'],\n          control: { type: 'select' }, // Automatically inferred when 'options' is defined\n        },\n        propertyB: {\n          options: ['Another Item One', 'Another Item Two', 'Another Item Three'],\n        },\n      },\n  });\n\n  const someFunction = (valuePropertyA, valuePropertyB) => {\n    // Do some logic here\n  };\n</script>\n\n<Story\n  name=\"ExampleStory\"\n  args={{\n    propertyA: 'Item One',\n    propertyB: 'Another Item One',\n  }}\n>\n  {#snippet template(args)}\n    <YourComponent\n      {...args}\n      someProperty={someFunction(args.propertyA, args.propertyB)}\n    />\n  {/snippet}\n</Story>\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport YourComponent from './YourComponent.svelte';\n\nexport default {\n  component: YourComponent,\n  //👇 Creates specific argTypes\n  argTypes: {\n    propertyA: {\n      options: ['Item One', 'Item Two', 'Item Three'],\n      control: { type: 'select' }, // Automatically inferred when 'options' is defined\n    },\n    propertyB: {\n      options: ['Another Item One', 'Another Item Two', 'Another Item Three'],\n    },\n  },\n};\n\nconst someFunction = (valuePropertyA, valuePropertyB) => {\n  // Do some logic here\n};\n\nexport const ExampleStory = {\n  render: (args) => {\n    //👇 Assigns the function result to a variable\n    const someFunctionResult = someFunction(args.propertyA, args.propertyB);\n    return {\n      Component: YourComponent,\n      props: {\n        ...args,\n        someProperty: someFunctionResult,\n      },\n    };\n  },\n  args: {\n    propertyA: 'Item One',\n    propertyB: 'Another Item One',\n  },\n};\n```\n\n```svelte filename=\"YourComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import YourComponent from './YourComponent.svelte';\n\n  const { Story } = defineMeta({\n      component: YourComponent,\n      //👇 Creates specific argTypes\n      argTypes: {\n        propertyA: {\n          options: ['Item One', 'Item Two', 'Item Three'],\n          control: { type: 'select' }, // Automatically inferred when 'options' is defined\n        },\n        propertyB: {\n          options: ['Another Item One', 'Another Item Two', 'Another Item Three'],\n        },\n      },\n  });\n\n  const someFunction = (valuePropertyA, valuePropertyB) => {\n    // Do some logic here\n  };\n</script>\n\n<Story\n  name=\"ExampleStory\"\n  args={{\n    propertyA: 'Item One',\n    propertyB: 'Another Item One',\n  }}\n>\n  {#snippet template(args)}\n    <YourComponent\n      {...args}\n      someProperty={someFunction(args.propertyA, args.propertyB)}\n    />\n  {/snippet}\n</Story>\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport YourComponent from './YourComponent.svelte';\n\nconst meta = {\n  component: YourComponent,\n  //👇 Creates specific argTypes\n  argTypes: {\n    propertyA: {\n      options: ['Item One', 'Item Two', 'Item Three'],\n      control: { type: 'select' }, // Automatically inferred when 'options' is defined\n    },\n    propertyB: {\n      options: ['Another Item One', 'Another Item Two', 'Another Item Three'],\n    },\n  },\n} satisfies Meta<typeof YourComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nconst someFunction = (valuePropertyA, valuePropertyB) => {\n  // Do some logic here\n};\n\nexport const ExampleStory: Story = {\n  render: (args) => {\n    //👇 Assigns the function result to a variable\n    const someFunctionResult = someFunction(args.propertyA, args.propertyB);\n    return {\n      Component: YourComponent,\n      props: {\n        ...args,\n        someProperty: someFunctionResult,\n      },\n    };\n  },\n  args: {\n    propertyA: 'Item One',\n    propertyB: 'Another Item One',\n  },\n};\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport YourComponent from './YourComponent.vue';\n\nexport default {\n  component: YourComponent,\n  //👇 Creates specific argTypes with options\n  argTypes: {\n    propertyA: {\n      options: ['Item One', 'Item Two', 'Item Three'],\n      control: { type: 'select' }, // automatically inferred when 'options' is defined\n    },\n    propertyB: {\n      options: ['Another Item One', 'Another Item Two', 'Another Item Three'],\n    },\n  },\n};\n\nconst someFunction = (valuePropertyA, valuePropertyB) => {\n  // Do some logic here\n};\n\nexport const ExampleStory = {\n  render: ({ args }) => {\n    const { propertyA, propertyB } = args;\n    //👇 Assigns the function result to a variable\n    const functionResult = someFunction(propertyA, propertyB);\n    return {\n      components: { YourComponent },\n      setup() {\n        return {\n          ...args,\n          //👇 Replaces arg variable with the override (without the need of mutation)\n          someProperty: functionResult,\n        };\n      },\n      template:\n        '<YourComponent :propertyA=\"propertyA\" :propertyB=\"propertyB\" :someProperty=\"someProperty\"/>',\n    };\n  },\n  args: {\n    propertyA: 'Item One',\n    propertyB: 'Another Item One',\n  },\n};\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport YourComponent from './YourComponent.vue';\n\nconst meta = {\n  component: YourComponent,\n  //👇 Creates specific argTypes with options\n  argTypes: {\n    propertyA: {\n      options: ['Item One', 'Item Two', 'Item Three'],\n      control: { type: 'select' }, // automatically inferred when 'options' is defined\n    },\n    propertyB: {\n      options: ['Another Item One', 'Another Item Two', 'Another Item Three'],\n    },\n  },\n} satisfies Meta<typeof YourComponent>;\n\nconst someFunction = (valuePropertyA, valuePropertyB) => {\n  // Do some logic here\n};\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ExampleStory: Story = {\n  render: ({ args }) => {\n    const { propertyA, propertyB } = args;\n    //👇 Assigns the function result to a variable\n    const functionResult = someFunction(propertyA, propertyB);\n    return {\n      components: { YourComponent },\n      setup() {\n        return {\n          ...args,\n          //👇 Replaces arg variable with the override (without the need of mutation)\n          someProperty: functionResult,\n        };\n      },\n      template:\n        '<YourComponent :propertyA=\"propertyA\" :propertyB=\"propertyB\" :someProperty=\"someProperty\"/>',\n    };\n  },\n  args: {\n    propertyA: 'Item One',\n    propertyB: 'Another Item One',\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nexport default {\n  component: 'custom-component',\n  //👇 Creates specific argTypes\n  argTypes: {\n    propertyA: {\n      options: ['Item One', 'Item Two', 'Item Three'],\n      control: { type: 'select' }, // Automatically inferred when 'options' is defined\n    },\n    propertyB: {\n      options: ['Another Item One', 'Another Item Two', 'Another Item Three'],\n    },\n  },\n};\n\nconst someFunction = (valuePropertyA, valuePropertyB) => {\n  // Do some logic here\n};\n\nexport const ExampleStory = {\n  render: ({ propertyA, propertyB }) => {\n    //👇 Assigns the function result to a variable\n    const someFunctionResult = someFunction(propertyA, propertyB);\n\n    return html`\n      <custom-component\n        .propertyA=${propertyA}\n        .propertyB=${propertyB}\n        .someProperty=${someFunctionResult}\n      ></custom-component>\n    `;\n  },\n  args: {\n    propertyA: 'Item One',\n    propertyB: 'Another Item One',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nconst meta: Meta = {\n  component: 'custom-component',\n  //👇 Creates specific argTypes with options\n  argTypes: {\n    propertyA: {\n      options: ['Item One', 'Item Two', 'Item Three'],\n      control: { type: 'select' }, // Automatically inferred when 'options' is defined\n    },\n    propertyB: {\n      options: ['Another Item One', 'Another Item Two', 'Another Item Three'],\n    },\n  },\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nconst someFunction = (valuePropertyA: any, valuePropertyB: any) => {\n  // Do some logic here\n};\n\nexport const ExampleStory: Story = {\n  render: ({ propertyA, propertyB }) => {\n    //👇 Assigns the function result to a variable\n    const someFunctionResult = someFunction(propertyA, propertyB);\n\n    return html`\n      <custom-component\n        .propertyA=${propertyA}\n        .propertyB=${propertyB}\n        .someProperty=${someFunctionResult}\n      ></custom-component>\n    `;\n  },\n  args: {\n    propertyA: 'Item One',\n    propertyB: 'Another Item One',\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'custom-component',\n  //👇 Creates specific argTypes\n  argTypes: {\n    propertyA: {\n      options: ['Item One', 'Item Two', 'Item Three'],\n      control: { type: 'select' }, // Automatically inferred when 'options' is defined\n    },\n    propertyB: {\n      options: ['Another Item One', 'Another Item Two', 'Another Item Three'],\n    },\n  },\n});\n\nconst someFunction = (valuePropertyA, valuePropertyB) => {\n  // Do some logic here\n};\n\nexport const ExampleStory = meta.story({\n  render: ({ propertyA, propertyB }) => {\n    //👇 Assigns the function result to a variable\n    const someFunctionResult = someFunction(propertyA, propertyB);\n\n    return html`\n      <custom-component\n        .propertyA=${propertyA}\n        .propertyB=${propertyB}\n        .someProperty=${someFunctionResult}\n      ></custom-component>\n    `;\n  },\n  args: {\n    propertyA: 'Item One',\n    propertyB: 'Another Item One',\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'custom-component',\n  //👇 Creates specific argTypes with options\n  argTypes: {\n    propertyA: {\n      options: ['Item One', 'Item Two', 'Item Three'],\n      control: { type: 'select' }, // Automatically inferred when 'options' is defined\n    },\n    propertyB: {\n      options: ['Another Item One', 'Another Item Two', 'Another Item Three'],\n    },\n  },\n});\n\nconst someFunction = (valuePropertyA: any, valuePropertyB: any) => {\n  // Do some logic here\n};\n\nexport const ExampleStory = meta.story({\n  render: ({ propertyA, propertyB }) => {\n    //👇 Assigns the function result to a variable\n    const someFunctionResult = someFunction(propertyA, propertyB);\n\n    return html`\n      <custom-component\n        .propertyA=${propertyA}\n        .propertyB=${propertyB}\n        .someProperty=${someFunctionResult}\n      ></custom-component>\n    `;\n  },\n  args: {\n    propertyA: 'Item One',\n    propertyB: 'Another Item One',\n  },\n});\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport YourComponent from './YourComponent.vue';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  //👇 Creates specific argTypes with options\n  argTypes: {\n    propertyA: {\n      options: ['Item One', 'Item Two', 'Item Three'],\n      control: { type: 'select' }, // automatically inferred when 'options' is defined\n    },\n    propertyB: {\n      options: ['Another Item One', 'Another Item Two', 'Another Item Three'],\n    },\n  },\n});\n\nconst someFunction = (valuePropertyA, valuePropertyB) => {\n  // Do some logic here\n};\n\nexport const ExampleStory = meta.story({\n  render: ({ args }) => {\n    const { propertyA, propertyB } = args;\n    //👇 Assigns the function result to a variable\n    const functionResult = someFunction(propertyA, propertyB);\n    return {\n      components: { YourComponent },\n      setup() {\n        return {\n          ...args,\n          //👇 Replaces arg variable with the override (without the need of mutation)\n          someProperty: functionResult,\n        };\n      },\n      template:\n        '<YourComponent :propertyA=\"propertyA\" :propertyB=\"propertyB\" :someProperty=\"someProperty\"/>',\n    };\n  },\n  args: {\n    propertyA: 'Item One',\n    propertyB: 'Another Item One',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"YourComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport YourComponent from './YourComponent.vue';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  //👇 Creates specific argTypes with options\n  argTypes: {\n    propertyA: {\n      options: ['Item One', 'Item Two', 'Item Three'],\n      control: { type: 'select' }, // automatically inferred when 'options' is defined\n    },\n    propertyB: {\n      options: ['Another Item One', 'Another Item Two', 'Another Item Three'],\n    },\n  },\n});\n\nconst someFunction = (valuePropertyA, valuePropertyB) => {\n  // Do some logic here\n};\n\nexport const ExampleStory = meta.story({\n  render: ({ args }) => {\n    const { propertyA, propertyB } = args;\n    //👇 Assigns the function result to a variable\n    const functionResult = someFunction(propertyA, propertyB);\n    return {\n      components: { YourComponent },\n      setup() {\n        return {\n          ...args,\n          //👇 Replaces arg variable with the override (without the need of mutation)\n          someProperty: functionResult,\n        };\n      },\n      template:\n        '<YourComponent :propertyA=\"propertyA\" :propertyB=\"propertyB\" :someProperty=\"someProperty\"/>',\n    };\n  },\n  args: {\n    propertyA: 'Item One',\n    propertyB: 'Another Item One',\n  },\n});\n```\n\n```tsx filename=\"YourComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './your-component';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  //👇 Creates specific argTypes with options\n  argTypes: {\n    propertyA: {\n      options: ['Item One', 'Item Two', 'Item Three'],\n      control: { type: 'select' }, // Automatically inferred when 'options' is defined\n    },\n    propertyB: {\n      options: ['Another Item One', 'Another Item Two', 'Another Item Three'],\n    },\n  },\n});\n\nconst someFunction = (valuePropertyA, valuePropertyB) => {\n  // Do some logic here\n};\n\nexport const ExampleStory = meta.story({\n  render: (args) => {\n    const { propertyA, propertyB } = args;\n    //👇 Assigns the function result to a variable\n    const someFunctionResult = someFunction(propertyA, propertyB);\n\n    return <YourComponent {...args} someProperty={someFunctionResult} />;\n  },\n  args: {\n    propertyA: 'Item One',\n    propertyB: 'Another Item One',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"YourComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './your-component';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  //👇 Creates specific argTypes with options\n  argTypes: {\n    propertyA: {\n      options: ['Item One', 'Item Two', 'Item Three'],\n      control: { type: 'select' }, // Automatically inferred when 'options' is defined\n    },\n    propertyB: {\n      options: ['Another Item One', 'Another Item Two', 'Another Item Three'],\n    },\n  },\n});\n\nconst someFunction = (valuePropertyA, valuePropertyB) => {\n  // Do some logic here\n};\n\nexport const ExampleStory = meta.story({\n  render: (args) => {\n    const { propertyA, propertyB } = args;\n    //👇 Assigns the function result to a variable\n    const someFunctionResult = someFunction(propertyA, propertyB);\n\n    return <YourComponent {...args} someProperty={someFunctionResult} />;\n  },\n  args: {\n    propertyA: 'Item One',\n    propertyB: 'Another Item One',\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/component-story-custom-args-mapping.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nimport { ArrowUp, ArrowDown, ArrowLeft, ArrowRight } from './icons';\n\nconst arrows = { ArrowUp, ArrowDown, ArrowLeft, ArrowRight };\n\nconst meta: Meta<Button> = {\n  component: Button,\n  argTypes: {\n    arrow: {\n      options: Object.keys(arrows), // An array of serializable values\n      mapping: arrows, // Maps serializable option values to complex arg values\n      control: {\n        type: 'select', // Type 'select' is automatically inferred when 'options' is defined\n        labels: {\n          // 'labels' maps option values to string labels\n          ArrowUp: 'Up',\n          ArrowDown: 'Down',\n          ArrowLeft: 'Left',\n          ArrowRight: 'Right',\n        },\n      },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nimport { ArrowUp, ArrowDown, ArrowLeft, ArrowRight } from './icons';\n\nconst arrows = { ArrowUp, ArrowDown, ArrowLeft, ArrowRight };\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    arrow: {\n      options: Object.keys(arrows), // An array of serializable values\n      mapping: arrows, // Maps serializable option values to complex arg values\n      control: {\n        type: 'select', // Type 'select' is automatically inferred when 'options' is defined\n        labels: {\n          // 'labels' maps option values to string labels\n          ArrowUp: 'Up',\n          ArrowDown: 'Down',\n          ArrowLeft: 'Left',\n          ArrowRight: 'Right',\n        },\n      },\n    },\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  import { ArrowUp, ArrowDown, ArrowLeft, ArrowRight } from './icons';\n\n  const arrows = { ArrowUp, ArrowDown, ArrowLeft, ArrowRight };\n\n  const { Story } = defineMeta({\n    component: Button,\n    argTypes: {\n      arrow: {\n        options: Object.keys(arrows), // An array of serializable values\n        mapping: arrows, // Maps serializable option values to complex arg values\n        control: {\n          type: 'select', // Type 'select' is automatically inferred when 'options' is defined\n          labels: {\n            // 'labels' maps option values to string labels\n            ArrowUp: 'Up',\n            ArrowDown: 'Down',\n            ArrowLeft: 'Left',\n            ArrowRight: 'Right',\n          },\n        },\n      },\n    },\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nimport { ArrowUp, ArrowDown, ArrowLeft, ArrowRight } from './icons';\n\nconst arrows = { ArrowUp, ArrowDown, ArrowLeft, ArrowRight };\n\nexport default {\n  component: Button,\n  argTypes: {\n    arrow: {\n      options: Object.keys(arrows), // An array of serializable values\n      mapping: arrows, // Maps serializable option values to complex arg values\n      control: {\n        type: 'select', // Type 'select' is automatically inferred when 'options' is defined\n        labels: {\n          // 'labels' maps option values to string labels\n          ArrowUp: 'Up',\n          ArrowDown: 'Down',\n          ArrowLeft: 'Left',\n          ArrowRight: 'Right',\n        },\n      },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nimport { ArrowUp, ArrowDown, ArrowLeft, ArrowRight } from './icons';\n\nconst arrows = { ArrowUp, ArrowDown, ArrowLeft, ArrowRight };\n\nexport default {\n  component: Button,\n  argTypes: {\n    arrow: {\n      options: Object.keys(arrows), // An array of serializable values\n      mapping: arrows, // Maps serializable option values to complex arg values\n      control: {\n        type: 'select', // Type 'select' is automatically inferred when 'options' is defined\n        labels: {\n          // 'labels' maps option values to string labels\n          ArrowUp: 'Up',\n          ArrowDown: 'Down',\n          ArrowLeft: 'Left',\n          ArrowRight: 'Right',\n        },\n      },\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  import { ArrowUp, ArrowDown, ArrowLeft, ArrowRight } from './icons';\n\n  const arrows = { ArrowUp, ArrowDown, ArrowLeft, ArrowRight };\n\n  const { Story } = defineMeta({\n    component: Button,\n    argTypes: {\n      arrow: {\n        options: Object.keys(arrows), // An array of serializable values\n        mapping: arrows, // Maps serializable option values to complex arg values\n        control: {\n          type: 'select', // Type 'select' is automatically inferred when 'options' is defined\n          labels: {\n            // 'labels' maps option values to string labels\n            ArrowUp: 'Up',\n            ArrowDown: 'Down',\n            ArrowLeft: 'Left',\n            ArrowRight: 'Right',\n          },\n        },\n      },\n    },\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nimport { ArrowUp, ArrowDown, ArrowLeft, ArrowRight } from './icons';\n\nconst arrows = { ArrowUp, ArrowDown, ArrowLeft, ArrowRight };\n\nconst meta = {\n  component: Button,\n  argTypes: {\n    arrow: {\n      options: Object.keys(arrows), // An array of serializable values\n      mapping: arrows, // Maps serializable option values to complex arg values\n      control: {\n        type: 'select', // Type 'select' is automatically inferred when 'options' is defined\n        labels: {\n          // 'labels' maps option values to string labels\n          ArrowUp: 'Up',\n          ArrowDown: 'Down',\n          ArrowLeft: 'Left',\n          ArrowRight: 'Right',\n        },\n      },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nimport { ArrowUp, ArrowDown, ArrowLeft, ArrowRight } from './icons';\n\nconst arrows = { ArrowUp, ArrowDown, ArrowLeft, ArrowRight };\n\nconst meta = {\n  component: Button,\n  argTypes: {\n    arrow: {\n      options: Object.keys(arrows), // An array of serializable values\n      mapping: arrows, // Maps serializable option values to complex arg values\n      control: {\n        type: 'select', // Type 'select' is automatically inferred when 'options' is defined\n        labels: {\n          // 'labels' maps option values to string labels\n          ArrowUp: 'Up',\n          ArrowDown: 'Down',\n          ArrowLeft: 'Left',\n          ArrowRight: 'Right',\n        },\n      },\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nconst arrows = {\n  Up: html`<icon-arrow-up></icon-arrow-up>`,\n  Down: html`<icon-arrow-down></icon-arrow-down>`,\n  Left: html`<icon-arrow-left></icon-arrow-left>`,\n  Right: html`<icon-arrow-right></icon-arrow-right>`,\n};\n\nexport default {\n  component: 'demo-button',\n  argTypes: {\n    arrow: {\n      options: Object.keys(arrows), // An array of serializable values\n      mapping: arrows, // Maps serializable option values to complex arg values\n      control: {\n        type: 'select', // Type 'select' is automatically inferred when 'options' is defined\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst arrows = {\n  Up: html`<icon-arrow-up></icon-arrow-up>`,\n  Down: html`<icon-arrow-down></icon-arrow-down>`,\n  Left: html`<icon-arrow-left></icon-arrow-left>`,\n  Right: html`<icon-arrow-right></icon-arrow-right>`,\n};\n\nconst meta: Meta = {\n  component: 'demo-button',\n  argTypes: {\n    arrow: {\n      options: Object.keys(arrows), // An array of serializable values\n      mapping: arrows, // Maps serializable option values to complex arg values\n      control: {\n        type: 'select', // Type 'select' is automatically inferred when 'options' is defined\n      },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst arrows = {\n  Up: html`<icon-arrow-up></icon-arrow-up>`,\n  Down: html`<icon-arrow-down></icon-arrow-down>`,\n  Left: html`<icon-arrow-left></icon-arrow-left>`,\n  Right: html`<icon-arrow-right></icon-arrow-right>`,\n};\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  argTypes: {\n    arrow: {\n      options: Object.keys(arrows), // An array of serializable values\n      mapping: arrows, // Maps serializable option values to complex arg values\n      control: {\n        type: 'select', // Type 'select' is automatically inferred when 'options' is defined\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst arrows = {\n  Up: html`<icon-arrow-up></icon-arrow-up>`,\n  Down: html`<icon-arrow-down></icon-arrow-down>`,\n  Left: html`<icon-arrow-left></icon-arrow-left>`,\n  Right: html`<icon-arrow-right></icon-arrow-right>`,\n};\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  argTypes: {\n    arrow: {\n      options: Object.keys(arrows), // An array of serializable values\n      mapping: arrows, // Maps serializable option values to complex arg values\n      control: {\n        type: 'select', // Type 'select' is automatically inferred when 'options' is defined\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nimport { ArrowUp, ArrowDown, ArrowLeft, ArrowRight } from './icons';\n\nconst arrows = { ArrowUp, ArrowDown, ArrowLeft, ArrowRight };\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    arrow: {\n      options: Object.keys(arrows), // An array of serializable values\n      mapping: arrows, // Maps serializable option values to complex arg values\n      control: {\n        type: 'select', // Type 'select' is automatically inferred when 'options' is defined\n        labels: {\n          // 'labels' maps option values to string labels\n          ArrowUp: 'Up',\n          ArrowDown: 'Down',\n          ArrowLeft: 'Left',\n          ArrowRight: 'Right',\n        },\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nimport { ArrowUp, ArrowDown, ArrowLeft, ArrowRight } from './icons';\n\nconst arrows = { ArrowUp, ArrowDown, ArrowLeft, ArrowRight };\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    arrow: {\n      options: Object.keys(arrows), // An array of serializable values\n      mapping: arrows, // Maps serializable option values to complex arg values\n      control: {\n        type: 'select', // Type 'select' is automatically inferred when 'options' is defined\n        labels: {\n          // 'labels' maps option values to string labels\n          ArrowUp: 'Up',\n          ArrowDown: 'Down',\n          ArrowLeft: 'Left',\n          ArrowRight: 'Right',\n        },\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nimport { ArrowUp, ArrowDown, ArrowLeft, ArrowRight } from './icons';\n\nconst arrows = { ArrowUp, ArrowDown, ArrowLeft, ArrowRight };\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    arrow: {\n      options: Object.keys(arrows), // An array of serializable values\n      mapping: arrows, // Maps serializable option values to complex arg values\n      control: {\n        type: 'select', // Type 'select' is automatically inferred when 'options' is defined\n        labels: {\n          // 'labels' maps option values to string labels\n          ArrowUp: 'Up',\n          ArrowDown: 'Down',\n          ArrowLeft: 'Left',\n          ArrowRight: 'Right',\n        },\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nimport { ArrowUp, ArrowDown, ArrowLeft, ArrowRight } from './icons';\n\nconst arrows = { ArrowUp, ArrowDown, ArrowLeft, ArrowRight };\n\nconst meta = preview.meta({\n  component: Button,\n  argTypes: {\n    arrow: {\n      options: Object.keys(arrows), // An array of serializable values\n      mapping: arrows, // Maps serializable option values to complex arg values\n      control: {\n        type: 'select', // Type 'select' is automatically inferred when 'options' is defined\n        labels: {\n          // 'labels' maps option values to string labels\n          ArrowUp: 'Up',\n          ArrowDown: 'Down',\n          ArrowLeft: 'Left',\n          ArrowRight: 'Right',\n        },\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/component-story-disable-controls-alt.md",
    "content": "```ts filename=\"YourComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { YourComponent } from './your-component.component';\n\nconst meta: Meta<YourComponent> = {\n  component: YourComponent,\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      control: false,\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './your-component.component';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      control: false,\n    },\n  },\n});\n```\n\n```svelte filename=\"YourComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import YourComponent from './YourComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: YourComponent,\n    argTypes: {\n      // foo is the property we want to remove from the UI\n      foo: {\n        control: false,\n      },\n    },\n  });\n</script>\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport YourComponent from './YourComponent.svelte';\n\nexport default {\n  component: YourComponent,\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      control: false,\n    },\n  },\n};\n```\n\n```js filename=\"YourComponent.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { YourComponent } from './YourComponent';\n\nexport default {\n  component: YourComponent,\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      control: false,\n    },\n  },\n};\n```\n\n```svelte filename=\"YourComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import YourComponent from './YourComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: YourComponent,\n    argTypes: {\n      // foo is the property we want to remove from the UI\n      foo: {\n        control: false,\n      },\n    },\n  });\n</script>\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport YourComponent from './YourComponent.svelte';\n\nconst meta = {\n  component: YourComponent,\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      control: false,\n    },\n  },\n} satisfies Meta<typeof YourComponent>;\n\nexport default meta;\n```\n\n```ts filename=\"YourComponent.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { YourComponent } from './YourComponent';\n\nconst meta = {\n  component: YourComponent,\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      control: false,\n    },\n  },\n} satisfies Meta<typeof YourComponent>;\n\nexport default meta;\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'your-component',\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      control: false,\n    },\n  },\n};\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'your-component',\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      control: false,\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'your-component',\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      control: false,\n    },\n  },\n});\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'your-component',\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      control: false,\n    },\n  },\n});\n```\n\n```ts filename=\"YourComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './YourComponent';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      control: false,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"YourComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './YourComponent';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      control: false,\n    },\n  },\n});\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport YourComponent from './YourComponent.vue';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      control: false,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"YourComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport YourComponent from './YourComponent.vue';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      control: false,\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/component-story-disable-controls-regex.md",
    "content": "```ts filename=\"YourComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { YourComponent } from './your-component.component';\n\nconst meta: Meta<YourComponent> = {\n  component: YourComponent,\n};\n\nexport default meta;\ntype Story = StoryObj<YourComponent>;\n\nexport const ArrayInclude: Story = {\n  parameters: {\n    controls: { include: ['foo', 'bar'] },\n  },\n};\n\nexport const RegexInclude: Story = {\n  parameters: {\n    controls: { include: /^hello*/ },\n  },\n};\n\nexport const ArrayExclude: Story = {\n  parameters: {\n    controls: { exclude: ['foo', 'bar'] },\n  },\n};\n\nexport const RegexExclude: Story = {\n  parameters: {\n    controls: { exclude: /^hello*/ },\n  },\n};\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './your-component.component';\n\nconst meta = preview.meta({\n  component: YourComponent,\n});\n\nexport const ArrayInclude = meta.story({\n  parameters: {\n    controls: { include: ['foo', 'bar'] },\n  },\n});\n\nexport const RegexInclude = meta.story({\n  parameters: {\n    controls: { include: /^hello*/ },\n  },\n});\n\nexport const ArrayExclude = meta.story({\n  parameters: {\n    controls: { exclude: ['foo', 'bar'] },\n  },\n});\n\nexport const RegexExclude = meta.story({\n  parameters: {\n    controls: { exclude: /^hello*/ },\n  },\n});\n```\n\n```svelte filename=\"YourComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import YourComponent from './YourComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: YourComponent,\n  });\n</script>\n\n<Story\n  name=\"ArrayInclude\"\n  parameters={{\n    controls: { include: ['foo', 'bar'] },\n  }}\n/>\n\n<Story\n  name=\"RegexInclude\"\n  parameters={{\n    controls: { include: /^hello*/ },\n  }}\n/>\n\n<Story\n  name=\"ArrayExclude\"\n  parameters={{\n    controls: { exclude: ['foo', 'bar'] },\n  }}\n/>\n\n<Story\n  name=\"RegexExclude\"\n  parameters={{\n    controls: { exclude: /^hello*/ },\n  }}\n/>\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport YourComponent from './YourComponent.svelte';\n\nexport default {\n  component: YourComponent,\n};\n\nexport const ArrayInclude = {\n  parameters: {\n    controls: { include: ['foo', 'bar'] },\n  },\n};\n\nexport const RegexInclude = {\n  parameters: {\n    controls: { include: /^hello*/ },\n  },\n};\n\nexport const ArrayExclude = {\n  parameters: {\n    controls: { exclude: ['foo', 'bar'] },\n  },\n};\n\nexport const RegexExclude = {\n  parameters: {\n    controls: { exclude: /^hello*/ },\n  },\n};\n```\n\n```js filename=\"YourComponent.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { YourComponent } from './YourComponent';\n\nexport default {\n  component: YourComponent,\n};\n\nexport const ArrayInclude = {\n  parameters: {\n    controls: { include: ['foo', 'bar'] },\n  },\n};\n\nexport const RegexInclude = {\n  parameters: {\n    controls: { include: /^hello*/ },\n  },\n};\n\nexport const ArrayExclude = {\n  parameters: {\n    controls: { exclude: ['foo', 'bar'] },\n  },\n};\n\nexport const RegexExclude = {\n  parameters: {\n    controls: { exclude: /^hello*/ },\n  },\n};\n```\n\n```svelte filename=\"YourComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import YourComponent from './YourComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: YourComponent,\n  });\n</script>\n\n<Story\n  name=\"ArrayInclude\"\n  parameters={{\n    controls: { include: ['foo', 'bar'] },\n  }}\n/>\n\n<Story\n  name=\"RegexInclude\"\n  parameters={{\n    controls: { include: /^hello*/ },\n  }}\n/>\n\n<Story\n  name=\"ArrayExclude\"\n  parameters={{\n    controls: { exclude: ['foo', 'bar'] },\n  }}\n/>\n\n<Story\n  name=\"RegexExclude\"\n  parameters={{\n    controls: { exclude: /^hello*/ },\n  }}\n/>\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport YourComponent from './YourComponent.svelte';\n\nconst meta = {\n  component: YourComponent,\n} satisfies Meta<typeof YourComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ArrayInclude: Story = {\n  parameters: {\n    controls: { include: ['foo', 'bar'] },\n  },\n};\n\nexport const RegexInclude: Story = {\n  parameters: {\n    controls: { include: /^hello*/ },\n  },\n};\n\nexport const ArrayExclude: Story = {\n  parameters: {\n    controls: { exclude: ['foo', 'bar'] },\n  },\n};\n\nexport const RegexExclude: Story = {\n  parameters: {\n    controls: { exclude: /^hello*/ },\n  },\n};\n```\n\n```ts filename=\"YourComponent.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { YourComponent } from './YourComponent';\n\nconst meta = {\n  component: YourComponent,\n} satisfies Meta<typeof YourComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ArrayInclude: Story = {\n  parameters: {\n    controls: { include: ['foo', 'bar'] },\n  },\n};\n\nexport const RegexInclude: Story = {\n  parameters: {\n    controls: { include: /^hello*/ },\n  },\n};\n\nexport const ArrayExclude: Story = {\n  parameters: {\n    controls: { exclude: ['foo', 'bar'] },\n  },\n};\n\nexport const RegexExclude: Story = {\n  parameters: {\n    controls: { exclude: /^hello*/ },\n  },\n};\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'your-component',\n};\n\nexport const ArrayInclude = {\n  parameters: {\n    controls: { include: ['foo', 'bar'] },\n  },\n};\n\nexport const RegexInclude = {\n  parameters: {\n    controls: { include: /^hello*/ },\n  },\n};\n\nexport const ArrayExclude = {\n  parameters: {\n    controls: { exclude: ['foo', 'bar'] },\n  },\n};\n\nexport const RegexExclude = {\n  parameters: {\n    controls: { exclude: /^hello*/ },\n  },\n};\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'your-component',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const ArrayInclude: Story = {\n  parameters: {\n    controls: { include: ['foo', 'bar'] },\n  },\n};\n\nexport const RegexInclude: Story = {\n  parameters: {\n    controls: { include: /^hello*/ },\n  },\n};\n\nexport const ArrayExclude: Story = {\n  parameters: {\n    controls: { exclude: ['foo', 'bar'] },\n  },\n};\n\nexport const RegexExclude: Story = {\n  parameters: {\n    controls: { exclude: /^hello*/ },\n  },\n};\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'your-component',\n});\n\nexport const ArrayInclude = meta.story({\n  parameters: {\n    controls: { include: ['foo', 'bar'] },\n  },\n});\n\nexport const RegexInclude = meta.story({\n  parameters: {\n    controls: { include: /^hello*/ },\n  },\n});\n\nexport const ArrayExclude = meta.story({\n  parameters: {\n    controls: { exclude: ['foo', 'bar'] },\n  },\n});\n\nexport const RegexExclude = meta.story({\n  parameters: {\n    controls: { exclude: /^hello*/ },\n  },\n});\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'your-component',\n});\n\nexport const ArrayInclude = meta.story({\n  parameters: {\n    controls: { include: ['foo', 'bar'] },\n  },\n});\n\nexport const RegexInclude = meta.story({\n  parameters: {\n    controls: { include: /^hello*/ },\n  },\n});\n\nexport const ArrayExclude = meta.story({\n  parameters: {\n    controls: { exclude: ['foo', 'bar'] },\n  },\n});\n\nexport const RegexExclude = meta.story({\n  parameters: {\n    controls: { exclude: /^hello*/ },\n  },\n});\n```\n\n```ts filename=\"YourComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './YourComponent';\n\nconst meta = preview.meta({\n  component: YourComponent,\n});\n\nexport const ArrayInclude = meta.story({\n  parameters: {\n    controls: { include: ['foo', 'bar'] },\n  },\n});\n\nexport const RegexInclude = meta.story({\n  parameters: {\n    controls: { include: /^hello*/ },\n  },\n});\n\nexport const ArrayExclude = meta.story({\n  parameters: {\n    controls: { exclude: ['foo', 'bar'] },\n  },\n});\n\nexport const RegexExclude = meta.story({\n  parameters: {\n    controls: { exclude: /^hello*/ },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"YourComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './YourComponent';\n\nconst meta = preview.meta({\n  component: YourComponent,\n});\n\nexport const ArrayInclude = meta.story({\n  parameters: {\n    controls: { include: ['foo', 'bar'] },\n  },\n});\n\nexport const RegexInclude = meta.story({\n  parameters: {\n    controls: { include: /^hello*/ },\n  },\n});\n\nexport const ArrayExclude = meta.story({\n  parameters: {\n    controls: { exclude: ['foo', 'bar'] },\n  },\n});\n\nexport const RegexExclude = meta.story({\n  parameters: {\n    controls: { exclude: /^hello*/ },\n  },\n});\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport YourComponent from './YourComponent.vue';\n\nconst meta = preview.meta({\n  component: YourComponent,\n});\n\nexport const ArrayInclude = meta.story({\n  parameters: {\n    controls: { include: ['foo', 'bar'] },\n  },\n});\n\nexport const RegexInclude = meta.story({\n  parameters: {\n    controls: { include: /^hello*/ },\n  },\n});\n\nexport const ArrayExclude = meta.story({\n  parameters: {\n    controls: { exclude: ['foo', 'bar'] },\n  },\n});\n\nexport const RegexExclude = meta.story({\n  parameters: {\n    controls: { exclude: /^hello*/ },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"YourComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport YourComponent from './YourComponent.vue';\n\nconst meta = preview.meta({\n  component: YourComponent,\n});\n\nexport const ArrayInclude = meta.story({\n  parameters: {\n    controls: { include: ['foo', 'bar'] },\n  },\n});\n\nexport const RegexInclude = meta.story({\n  parameters: {\n    controls: { include: /^hello*/ },\n  },\n});\n\nexport const ArrayExclude = meta.story({\n  parameters: {\n    controls: { exclude: ['foo', 'bar'] },\n  },\n});\n\nexport const RegexExclude = meta.story({\n  parameters: {\n    controls: { exclude: /^hello*/ },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/component-story-disable-controls.md",
    "content": "```ts filename=\"YourComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { YourComponent } from './your-component.component';\n\nconst meta: Meta<YourComponent> = {\n  component: YourComponent,\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      table: {\n        disable: true,\n      },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './your-component.component';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      table: {\n        disable: true,\n      },\n    },\n  },\n});\n```\n\n```svelte filename=\"YourComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import YourComponent from './YourComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: YourComponent,\n    argTypes: {\n      // foo is the property we want to remove from the UI\n      foo: {\n        table: {\n          disable: true,\n        },\n      },\n    },\n  });\n</script>\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport YourComponent from './YourComponent.svelte';\n\nexport default {\n  component: YourComponent,\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      table: {\n        disable: true,\n      },\n    },\n  },\n};\n```\n\n```js filename=\"YourComponent.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { YourComponent } from './YourComponent';\n\nexport default {\n  component: YourComponent,\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      table: {\n        disable: true,\n      },\n    },\n  },\n};\n```\n\n```svelte filename=\"YourComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import YourComponent from './YourComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: YourComponent,\n    argTypes: {\n      // foo is the property we want to remove from the UI\n      foo: {\n        table: {\n          disable: true,\n        },\n      },\n    },\n  });\n</script>\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport YourComponent from './YourComponent.svelte';\n\nconst meta = {\n  component: YourComponent,\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      table: {\n        disable: true,\n      },\n    },\n  },\n} satisfies Meta<typeof YourComponent>;\n\nexport default meta;\n```\n\n```ts filename=\"YourComponent.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { YourComponent } from './YourComponent';\n\nconst meta = {\n  component: YourComponent,\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      table: {\n        disable: true,\n      },\n    },\n  },\n} satisfies Meta<typeof YourComponent>;\n\nexport default meta;\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'your-component',\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      table: {\n        disable: true,\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'your-component',\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      table: {\n        disable: true,\n      },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'your-component',\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      table: {\n        disable: true,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'your-component',\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      table: {\n        disable: true,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"YourComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './YourComponent';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      table: {\n        disable: true,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"YourComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './YourComponent';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      table: {\n        disable: true,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport YourComponent from './YourComponent.vue';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      table: {\n        disable: true,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"YourComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport YourComponent from './YourComponent.vue';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  argTypes: {\n    // foo is the property we want to remove from the UI\n    foo: {\n      table: {\n        disable: true,\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/component-story-figma-integration.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { MyComponent } from './my-component.component';\n\n// More on default export: https://storybook.js.org/docs/writing-stories/#default-export\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n};\n\nexport default meta;\ntype Story = StoryObj<MyComponent>;\n\nexport const Example: Story = {\n  parameters: {\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/Sample-File',\n    },\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\n// More on default export: https://storybook.js.org/docs/writing-stories/#default-export\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Example = meta.story({\n  parameters: {\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/Sample-File',\n    },\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyComponent } from './MyComponent';\n\n// More on default export: https://storybook.js.org/docs/writing-stories/#default-export\nexport default {\n  component: MyComponent,\n};\n\nexport const Example = {\n  parameters: {\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/Sample-File',\n    },\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { MyComponent } from './MyComponent';\n\n// More on default export: https://storybook.js.org/docs/writing-stories/#default-export\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Example: Story = {\n  parameters: {\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/Sample-File',\n    },\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const Example = {\n  parameters: {\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/Sample-File',\n    },\n  },\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Example: Story = {\n  parameters: {\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/Sample-File',\n    },\n  },\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"Example\"\n  parameters={{\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/Sample-File',\n    },\n  }}\n/>\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.svelte';\n\n// More on default export: https://storybook.js.org/docs/writing-stories/#default-export\nexport default {\n  component: MyComponent,\n};\n\nexport const Example = {\n  parameters: {\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/Sample-File',\n    },\n  },\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"Example\"\n  parameters={{\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/Sample-File',\n    },\n  }}\n/>\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport MyComponent from './MyComponent.svelte';\n\n// More on default export: https://storybook.js.org/docs/svelte/writing-stories/introduction#default-export\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Example: Story = {\n  parameters: {\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/Sample-File',\n    },\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.vue';\n\n// More on default export: https://storybook.js.org/docs/writing-stories/#default-export\nexport default {\n  component: MyComponent,\n};\n\nexport const Example = {\n  parameters: {\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/Sample-File',\n    },\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport MyComponent from './MyComponent.vue';\n\n// More on default export: https://storybook.js.org/docs/writing-stories/#default-export\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Example: Story = {\n  parameters: {\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/Sample-File',\n    },\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\n// More on default export: https://storybook.js.org/docs/writing-stories/#default-export\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Example = meta.story({\n  parameters: {\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/Sample-File',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\n// More on default export: https://storybook.js.org/docs/writing-stories/#default-export\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Example = meta.story({\n  parameters: {\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/Sample-File',\n    },\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'my-component',\n};\n\nexport const Example = {\n  parameters: {\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/Sample-File',\n    },\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'my-component',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Example: Story = {\n  parameters: {\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/Sample-File',\n    },\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const Example = meta.story({\n  parameters: {\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/Sample-File',\n    },\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const Example = meta.story({\n  parameters: {\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/Sample-File',\n    },\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\n// More on default export: https://storybook.js.org/docs/writing-stories/#default-export\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Example = meta.story({\n  parameters: {\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/Sample-File',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Example = meta.story({\n  parameters: {\n    design: {\n      type: 'figma',\n      url: 'https://www.figma.com/file/Sample-File',\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/component-story-highlight.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, type StoryObj, componentWrapperDecorator } from '@storybook/angular';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n};\n\nexport default meta;\ntype Story = StoryObj<MyComponent>;\n\nexport const Highlighted: Story = {\n  decorators: [\n    componentWrapperDecorator((story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n      });\n      return story;\n    }),\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { componentWrapperDecorator } from '@storybook/angular';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Highlighted = meta.story({\n  decorators: [\n    componentWrapperDecorator((story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n      });\n      return story;\n    }),\n  ],\n});\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const Highlighted = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n      });\n      return storyFn();\n    },\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Highlighted: Story = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n      });\n      return storyFn();\n    },\n  ],\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { useChannel } from 'storybook/preview-api';\n  import { HIGHLIGHT } from 'storybook/highlight';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"Highlighted\"\n  decorators={[\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n      });\n      return storyFn();\n    },\n  ]}\n/>\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.svelte';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const Highlighted = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n      });\n      return storyFn();\n    },\n  ],\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { useChannel } from 'storybook/preview-api';\n  import { HIGHLIGHT } from 'storybook/highlight';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"Highlighted\"\n  decorators={[\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n      });\n      return storyFn();\n    },\n  ]}\n/>\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.svelte';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Highlighted: Story = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n      });\n      return storyFn();\n    },\n  ],\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.vue';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const Highlighted = {\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n      });\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Highlighted: Story = {\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n      });\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nexport default {\n  component: 'my-component',\n};\n\nexport const Highlighted = {\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n      });\n      return story();\n    },\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nconst meta: Meta = {\n  component: 'my-component',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Highlighted: Story = {\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n      });\n      return story();\n    },\n  ],\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const Highlighted = meta.story({\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n      });\n      return story();\n    },\n  ],\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const Highlighted = meta.story({\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n      });\n      return story();\n    },\n  ],\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Highlighted = meta.story({\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n      });\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Highlighted = meta.story({\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n      });\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n});\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Highlighted = meta.story({\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n      });\n      return storyFn();\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Highlighted = meta.story({\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n      });\n      return storyFn();\n    },\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/component-story-sort-controls.md",
    "content": "```ts filename=\"YourComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { YourComponent } from './your-component.component';\n\nconst meta: Meta<YourComponent> = {\n  component: YourComponent,\n  parameters: { controls: { sort: 'requiredFirst' } },\n};\n\nexport default meta;\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './your-component.component';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  parameters: { controls: { sort: 'requiredFirst' } },\n});\n```\n\n```svelte filename=\"YourComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import YourComponent from './YourComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: YourComponent,\n    parameters: { controls: { sort: 'requiredFirst' } },\n  });\n</script>\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport YourComponent from './YourComponent.svelte';\n\nexport default {\n  component: YourComponent,\n  parameters: { controls: { sort: 'requiredFirst' } },\n};\n```\n\n```js filename=\"YourComponent.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { YourComponent } from './YourComponent';\n\nexport default {\n  component: YourComponent,\n  parameters: { controls: { sort: 'requiredFirst' } },\n};\n```\n\n```svelte filename=\"YourComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import YourComponent from './YourComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: YourComponent,\n    parameters: { controls: { sort: 'requiredFirst' } },\n  });\n</script>\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport YourComponent from './YourComponent.svelte';\n\nconst meta = {\n  component: YourComponent,\n  parameters: { controls: { sort: 'requiredFirst' } },\n} satisfies Meta<typeof YourComponent>;\n\nexport default meta;\n```\n\n```ts filename=\"YourComponent.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { YourComponent } from './YourComponent';\n\nconst meta = {\n  component: YourComponent,\n  parameters: { controls: { sort: 'requiredFirst' } },\n} satisfies Meta<typeof YourComponent>;\n\nexport default meta;\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'your-component',\n  parameters: { controls: { sort: 'requiredFirst' } },\n};\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'your-component',\n  parameters: { controls: { sort: 'requiredFirst' } },\n};\n\nexport default meta;\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'your-component',\n  parameters: { controls: { sort: 'requiredFirst' } },\n});\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'your-component',\n  parameters: { controls: { sort: 'requiredFirst' } },\n});\n```\n\n```ts filename=\"YourComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './YourComponent';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  parameters: { controls: { sort: 'requiredFirst' } },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"YourComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './YourComponent';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  parameters: { controls: { sort: 'requiredFirst' } },\n});\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport YourComponent from './YourComponent.vue';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  parameters: { controls: { sort: 'requiredFirst' } },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"YourComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport YourComponent from './YourComponent.vue';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  parameters: { controls: { sort: 'requiredFirst' } },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/component-story-static-asset-cdn.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const WithAnImage: Story = {\n  render: () => ({\n    props: {\n      src: 'https://storybook.js.org/images/placeholders/350x150.png',\n      alt: 'My CDN placeholder',\n    },\n  }),\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const WithAnImage = meta.story({\n  render: () => ({\n    props: {\n      src: 'https://storybook.js.org/images/placeholders/350x150.png',\n      alt: 'My CDN placeholder',\n    },\n  }),\n});\n```\n\n```jsx filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const WithAnImage = {\n  render: () => (\n    <img src=\"https://storybook.js.org/images/placeholders/350x150.png\" alt=\"My CDN placeholder\" />\n  ),\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const WithAnImage: Story = {\n  render: () => (\n    <img src=\"https://storybook.js.org/images/placeholders/350x150.png\" alt=\"My CDN placeholder\" />\n  ),\n};\n```\n\n```jsx filename=\"MyComponent.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const WithAnImage = {\n  render: () => (\n    <img src=\"https://storybook.js.org/images/placeholders/350x150.png\" alt=\"My CDN placeholder\" />\n  ),\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const WithAnImage: Story = {\n  render: () => (\n    <img src=\"https://storybook.js.org/images/placeholders/350x150.png\" alt=\"My CDN placeholder\" />\n  ),\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n\tconst { Story } = defineMeta({\n\t\tcomponent: MyComponent,\n\t});\n</script>\n\n<Story name=\"WithAnImage\">\n  <MyComponent\n    src=\"https://storybook.js.org/images/placeholders/350x150.png\"\n    alt=\"My CDN placeholder\"\n  />\n</Story>\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.svelte';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const WithAnImage = {\n  render: () => ({\n    Component: MyComponent,\n    props: {\n      src: 'https://storybook.js.org/images/placeholders/350x150.png',\n      alt: 'My CDN placeholder',\n    },\n  }),\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n\tconst { Story } = defineMeta({\n\t\tcomponent: MyComponent,\n\t});\n</script>\n\n<Story name=\"WithAnImage\">\n  <MyComponent\n    src=\"https://storybook.js.org/images/placeholders/350x150.png\"\n    alt=\"My CDN placeholder\"\n  />\n</Story>\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport MyComponent from './MyComponent.svelte';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const WithAnImage: Story = {\n  render: () => ({\n    Component: MyComponent,\n    props: {\n      src: 'https://storybook.js.org/images/placeholders/350x150.png',\n      alt: 'My CDN placeholder',\n    },\n  }),\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.vue';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const WithAnImage = {\n  render: () => ({\n    template:\n      '<img src=\"https://storybook.js.org/images/placeholders/350x150.png\" alt=\"My CDN placeholder\"/>',\n  }),\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const WithAnImage: Story = {\n  render: () => ({\n    template:\n      '<img src=\"https://storybook.js.org/images/placeholders/350x150.png\" alt=\"My CDN placeholder\"/>',\n  }),\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const WithAnImage = meta.story({\n  render: () => ({\n    template:\n      '<img src=\"https://storybook.js.org/images/placeholders/350x150.png\" alt=\"My CDN placeholder\"/>',\n  }),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const WithAnImage = meta.story({\n  render: () => ({\n    template:\n      '<img src=\"https://storybook.js.org/images/placeholders/350x150.png\" alt=\"My CDN placeholder\"/>',\n  }),\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nexport default {\n  component: 'my-component',\n};\n\nexport const WithAnImage = {\n  render: () =>\n    html`<img\n      src=\"https://storybook.js.org/images/placeholders/350x150.png\"\n      alt=\"My CDN placeholder\"\n    />`,\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nconst meta: Meta = {\n  component: 'my-component',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const WithAnImage: Story = {\n  render: () =>\n    html`<img\n      src=\"https://storybook.js.org/images/placeholders/350x150.png\"\n      alt=\"My CDN placeholder\"\n    />`,\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const WithAnImage = meta.story({\n  render: () =>\n    html`<img\n      src=\"https://storybook.js.org/images/placeholders/350x150.png\"\n      alt=\"My CDN placeholder\"\n    />`,\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const WithAnImage = meta.story({\n  render: () =>\n    html`<img\n      src=\"https://storybook.js.org/images/placeholders/350x150.png\"\n      alt=\"My CDN placeholder\"\n    />`,\n});\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const WithAnImage = meta.story({\n  render: () => (\n    <img src=\"https://storybook.js.org/images/placeholders/350x150.png\" alt=\"My CDN placeholder\" />\n  ),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const WithAnImage = meta.story({\n  render: () => (\n    <img src=\"https://storybook.js.org/images/placeholders/350x150.png\" alt=\"My CDN placeholder\" />\n  ),\n});\n```\n"
  },
  {
    "path": "docs/_snippets/component-story-static-asset-with-import.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { MyComponent } from './my-component.component';\n\nimport imageFile from './static/image.png';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n};\n\nexport default meta;\ntype Story = StoryObj<MyComponent>;\n\nconst image = {\n  src: imageFile,\n  alt: 'my image',\n};\n\nexport const WithAnImage: Story = {\n  render: () => ({\n    props: {\n      src: image.src,\n      alt: image.alt,\n    },\n    template: `<img src=\"{{src}}\" alt=\"{{alt}}\" />`,\n  }),\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nimport imageFile from './static/image.png';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nconst image = {\n  src: imageFile,\n  alt: 'my image',\n};\n\nexport const WithAnImage = meta.story({\n  render: () => ({\n    props: {\n      src: image.src,\n      alt: image.alt,\n    },\n    template: `<img src=\"{{src}}\" alt=\"{{alt}}\" />`,\n  }),\n});\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyComponent } from './MyComponent';\n\nimport imageFile from './static/image.png';\n\nexport default {\n  component: MyComponent,\n};\n\nconst image = {\n  src: imageFile,\n  alt: 'my image',\n};\n\nexport const WithAnImage = {\n  render: () => <img src={image.src} alt={image.alt} />,\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport imageFile from './static/image.png';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nconst image = {\n  src: imageFile,\n  alt: 'my image',\n};\n\nexport const WithAnImage: Story = {\n  render: () => <img src={image.src} alt={image.alt} />,\n};\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport imageFile from './static/image.png';\n\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nconst image = {\n  src: imageFile,\n  alt: 'my image',\n};\n\nexport const WithAnImage = {\n  render: () => <img src={image.src} alt={image.alt} />,\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport imageFile from './static/image.png';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nconst image = {\n  src: imageFile,\n  alt: 'my image',\n};\n\nexport const WithAnImage: Story = {\n  render: () => <img src={image.src} alt={image.alt} />,\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  import imageFile from './static/image.png';\n\n  let image = {\n    src: imageFile,\n    alt: 'my image',\n  };\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story name=\"WithAnImage\">\n  <MyComponent {image} />\n</Story>\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.svelte';\n\nimport imageFile from './static/image.png';\n\nexport default {\n  component: MyComponent,\n};\n\nconst image = {\n  src: imageFile,\n  alt: 'my image',\n};\n\nexport const WithAnImage = {\n  render: () => ({\n    Component: MyComponent,\n    props: image,\n  }),\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  import imageFile from './static/image.png';\n\n  let image = {\n    src: imageFile,\n    alt: 'my image',\n  };\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story name=\"WithAnImage\">\n\t<MyComponent {image} />\n</Story>\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport MyComponent from './MyComponent.svelte';\n\nimport imageFile from './static/image.png';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nconst image = {\n  src: imageFile,\n  alt: 'my image',\n};\n\nexport const WithAnImage: Story = {\n  render: () => ({\n    Component: MyComponent,\n    props: image,\n  }),\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.vue';\n\nimport imageFile from './static/image.png';\n\nexport default {\n  component: MyComponent,\n};\n\nconst image = {\n  src: imageFile,\n  alt: 'my image',\n};\n\nexport const WithAnImage = {\n  render: () => ({\n    setup() {\n      //👇 Returns the content of the image object created above.\n      return { image };\n    },\n    template: `<img v-bind=\"image\"/>`,\n  }),\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport MyComponent from './MyComponent.vue';\n\nimport imageFile from './static/image.png';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nconst image = {\n  src: imageFile,\n  alt: 'my image',\n};\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const WithAnImage: Story = {\n  render: () => ({\n    setup() {\n      //👇 Returns the content of the image object created above.\n      return { image };\n    },\n    template: `<img v-bind=\"image\"/>`,\n  }),\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nimport imageFile from './static/image.png';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nconst image = {\n  src: imageFile,\n  alt: 'my image',\n};\n\nexport const WithAnImage = meta.story({\n  render: () => ({\n    setup() {\n      //👇 Returns the content of the image object created above.\n      return { image };\n    },\n    template: `<img v-bind=\"image\"/>`,\n  }),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nimport imageFile from './static/image.png';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nconst image = {\n  src: imageFile,\n  alt: 'my image',\n};\n\nexport const WithAnImage = meta.story({\n  render: () => ({\n    setup() {\n      //👇 Returns the content of the image object created above.\n      return { image };\n    },\n    template: `<img v-bind=\"image\"/>`,\n  }),\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nimport imageFile from './static/image.png';\n\nexport default {\n  component: 'my-component',\n};\n\nconst image = {\n  src: imageFile,\n  alt: 'my image',\n};\n\nexport const WithAnImage = {\n  render: () => html`<img src=${image.src} alt=${image.alt} /> `,\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nimport imageFile from './static/image.png';\n\nconst meta: Meta = {\n  component: 'my-component',\n};\n\nconst image = {\n  src: imageFile,\n  alt: 'my image',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const WithAnImage: Story = {\n  render: () => html`<img src=${image.src} alt=${image.alt} />`,\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nimport imageFile from './static/image.png';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nconst image = {\n  src: imageFile,\n  alt: 'my image',\n};\n\nexport const WithAnImage = meta.story({\n  render: () => html`<img src=${image.src} alt=${image.alt} /> `,\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nimport imageFile from './static/image.png';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nconst image = {\n  src: imageFile,\n  alt: 'my image',\n};\n\nexport const WithAnImage = meta.story({\n  render: () => html`<img src=${image.src} alt=${image.alt} />`,\n});\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport imageFile from './static/image.png';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nconst image = {\n  src: imageFile,\n  alt: 'my image',\n};\n\nexport const WithAnImage = meta.story({\n  render: () => <img src={image.src} alt={image.alt} />,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nimport imageFile from './static/image.png';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nconst image = {\n  src: imageFile,\n  alt: 'my image',\n};\n\nexport const WithAnImage = meta.story({\n  render: () => <img src={image.src} alt={image.alt} />,\n});\n```\n"
  },
  {
    "path": "docs/_snippets/component-story-static-asset-without-import.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n};\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// Assume image.png is located in the \"public\" directory.\nexport const WithAnImage: Story = {\n  render: () => ({\n    props: {\n      src: '/image.png',\n      alt: 'my image',\n    },\n  }),\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\n// Assume image.png is located in the \"public\" directory.\nexport const WithAnImage = meta.story({\n  render: () => ({\n    props: {\n      src: '/image.png',\n      alt: 'my image',\n    },\n  }),\n});\n```\n\n```jsx filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\n// Assume image.png is located in the \"public\" directory.\nexport const WithAnImage = {\n  render: () => <img src=\"/image.png\" alt=\"my image\" />,\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// Assume image.png is located in the \"public\" directory.\nexport const WithAnImage: Story = {\n  render: () => <img src=\"/image.png\" alt=\"my image\" />,\n};\n```\n\n```jsx filename=\"MyComponent.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\n// Assume image.png is located in the \"public\" directory.\nexport const WithAnImage = {\n  render: () => <img src=\"/image.png\" alt=\"my image\" />,\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// Assume image.png is located in the \"public\" directory.\nexport const WithAnImage: Story = {\n  render: () => <img src=\"/image.png\" alt=\"my image\" />,\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n\tconst { Story } = defineMeta({\n\t\tcomponent: MyComponent,\n\t});\n</script>\n\n<Story name=\"WithAnImage\">\n  <MyComponent src=\"/image.png\" alt=\"my image\" />\n</Story>\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.svelte';\n\nexport default {\n  component: MyComponent,\n};\n\n// Assume image.png is located in the \"public\" directory.\nexport const WithAnImage = {\n  render: () => ({\n    Component: MyComponent,\n    props: {\n      src: '/image.png',\n      alt: 'my image',\n    },\n  }),\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n\tconst { Story } = defineMeta({\n\t\tcomponent: MyComponent,\n\t});\n</script>\n\n<Story name=\"WithAnImage\">\n  <MyComponent src=\"/image.png\" alt=\"my image\" />\n</Story>\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport MyComponent from './MyComponent.svelte';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// Assume image.png is located in the \"public\" directory.\nexport const WithAnImage: Story = {\n  render: () => ({\n    Component: MyComponent,\n    props: {\n      src: '/image.png',\n      alt: 'my image',\n    },\n  }),\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.vue';\n\nexport default {\n  component: MyComponent,\n};\n\n// Assume image.png is located in the \"public\" directory.\nexport const WithAnImage = {\n  render: () => ({\n    template: '<img src=\"image.png\" alt=\"my image\" />',\n  }),\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const WithAnImage: Story = {\n  render: () => ({\n    template: '<img src=\"image.png\" alt=\"my image\" />',\n  }),\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\n// Assume image.png is located in the \"public\" directory.\nexport const WithAnImage = meta.story({\n  render: () => ({\n    template: '<img src=\"image.png\" alt=\"my image\" />',\n  }),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\n// Assume image.png is located in the \"public\" directory.\nexport const WithAnImage = meta.story({\n  render: () => ({\n    template: '<img src=\"image.png\" alt=\"my image\" />',\n  }),\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nexport default {\n  component: 'my-component',\n};\n\n// Assume image.png is located in the \"public\" directory.\nexport const WithAnImage = {\n  render: () => html`<img src=\"/image.png\" alt=\"image\" />`,\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nconst meta: Meta = {\n  component: 'my-component',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\n// Assume image.png is located in the \"public\" directory.\nexport const WithAnImage: Story = {\n  render: () => html`<img src=\"/image.png\" alt=\"image\" />`,\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\n// Assume image.png is located in the \"public\" directory.\nexport const WithAnImage = meta.story({\n  render: () => html`<img src=\"/image.png\" alt=\"image\" />`,\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\n// Assume image.png is located in the \"public\" directory.\nexport const WithAnImage = meta.story({\n  render: () => html`<img src=\"/image.png\" alt=\"image\" />`,\n});\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\n// Assume image.png is located in the \"public\" directory.\nexport const WithAnImage = meta.story({\n  render: () => <img src=\"/image.png\" alt=\"my image\" />,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\n// Assume image.png is located in the \"public\" directory.\nexport const WithAnImage = meta.story({\n  render: () => <img src=\"/image.png\" alt=\"my image\" />,\n});\n```\n"
  },
  {
    "path": "docs/_snippets/component-story-with-custom-render-function.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, type StoryObj, moduleMetadata, argsToTemplate } from '@storybook/angular';\n\nimport { CommonModule } from '@angular/common';\n\nimport { Layout } from './layout.component';\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n  decorators: [\n    moduleMetadata({\n      declarations: [Layout],\n      imports: [CommonModule],\n    }),\n  ],\n};\n\nexport default meta;\ntype Story = StoryObj<MyComponent>;\n\n// This story uses a render function to fully control how the component renders.\nexport const Example: Story = {\n  render: (args) => ({\n    props: args,\n    template: `\n      <app-layout>\n        <header>\n          <h1>Example</h1>\n        </header>\n        <article>\n          <app-my-component ${argsToTemplate(args)}></app-my-component>\n        </article>\n      </app-layout>\n    `,\n  }),\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { moduleMetadata, argsToTemplate } from '@storybook/angular';\n\nimport { CommonModule } from '@angular/common';\n\nimport preview from '../.storybook/preview';\n\nimport { Layout } from './layout.component';\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  decorators: [\n    moduleMetadata({\n      declarations: [Layout],\n      imports: [CommonModule],\n    }),\n  ],\n});\n\n// This story uses a render function to fully control how the component renders.\nexport const Example = meta.story({\n  render: (args) => ({\n    props: args,\n    template: `\n      <app-layout>\n        <header>\n          <h1>Example</h1>\n        </header>\n        <article>\n          <app-my-component ${argsToTemplate(args)}></app-my-component>\n        </article>\n      </app-layout>\n    `,\n  }),\n});\n```\n\n```jsx filename=\"MyComponent.stories.js|jsx\" renderer=\"preact\" language=\"js\"\n/** @jsx h */\nimport { h } from 'preact';\n\nimport { Layout } from './Layout';\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\n// This story uses a render function to fully control how the component renders.\nexport const Example = {\n  render: () => (\n    <Layout>\n      <header>\n        <h1>Example</h1>\n      </header>\n      <article>\n        <MyComponent />\n      </article>\n    </Layout>\n  ),\n};\n```\n\n```jsx filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Layout } from './Layout';\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\n// This story uses a render function to fully control how the component renders.\nexport const Example = {\n  render: () => (\n    <Layout>\n      <header>\n        <h1>Example</h1>\n      </header>\n      <article>\n        <MyComponent />\n      </article>\n    </Layout>\n  ),\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Layout } from './Layout';\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// This story uses a render function to fully control how the component renders.\nexport const Example: Story = {\n  render: () => (\n    <Layout>\n      <header>\n        <h1>Example</h1>\n      </header>\n      <article>\n        <MyComponent />\n      </article>\n    </Layout>\n  ),\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Layout } from './Layout';\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\n// This story uses a render function to fully control how the component renders.\nexport const Example = meta.story({\n  render: () => (\n    <Layout>\n      <header>\n        <h1>Example</h1>\n      </header>\n      <article>\n        <MyComponent />\n      </article>\n    </Layout>\n  ),\n});\n```\n\n```jsx filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Layout } from './Layout';\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\n// This story uses a render function to fully control how the component renders.\nexport const Example = meta.story({\n  render: () => (\n    <Layout>\n      <header>\n        <h1>Example</h1>\n      </header>\n      <article>\n        <MyComponent />\n      </article>\n    </Layout>\n  ),\n});\n```\n\n```jsx filename=\"MyComponent.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { Layout } from './Layout';\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  title: 'MyComponent',\n  component: MyComponent,\n};\n\n// This story uses a render function to fully control how the component renders.\nexport const Example = {\n  render: () => (\n    <Layout>\n      <header>\n        <h1>Example</h1>\n      </header>\n      <article>\n        <MyComponent />\n      </article>\n    </Layout>\n  ),\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { Layout } from './Layout';\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// This story uses a render function to fully control how the component renders.\nexport const Example: Story = {\n  render: () => (\n    <Layout>\n      <header>\n        <h1>Example</h1>\n      </header>\n      <article>\n        <MyComponent />\n      </article>\n    </Layout>\n  ),\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport Layout from './Layout.vue';\nimport MyComponent from './MyComponent.vue';\n\nexport default {\n  component: MyComponent,\n};\n\n// This story uses a render function to fully control how the component renders.\nexport const Example = {\n  render: () => ({\n    components: { Layout, MyComponent },\n    template: `\n      <Layout>\n        <header>\n          <h1>Example</h1>\n        </header>\n        <article>\n          <MyComponent />\n        </article>\n      </Layout>\n    `,\n  }),\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport Layout from './Layout.vue';\nimport MyComponent from './MyComponent.vue';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// This story uses a render function to fully control how the component renders.\nexport const Example: Story = {\n  render: () => ({\n    components: { Layout, MyComponent },\n    template: `\n      <Layout>\n        <header>\n          <h1>Example</h1>\n        </header>\n        <article>\n          <MyComponent />\n        </article>\n      </Layout>\n    `,\n  }),\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Layout from './Layout.vue';\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\n// This story uses a render function to fully control how the component renders.\nexport const Example = meta.story({\n  render: () => ({\n    components: { Layout, MyComponent },\n    template: `\n      <Layout>\n        <header>\n          <h1>Example</h1>\n        </header>\n        <article>\n          <MyComponent />\n        </article>\n      </Layout>\n    `,\n  }),\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Layout from './Layout.vue';\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\n// This story uses a render function to fully control how the component renders.\nexport const Example = meta.story({\n  render: () => ({\n    components: { Layout, MyComponent },\n    template: `\n      <Layout>\n        <header>\n          <h1>Example</h1>\n        </header>\n        <article>\n          <MyComponent />\n        </article>\n      </Layout>\n    `,\n  }),\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nexport default {\n  component: 'my-component',\n};\n\n// This story uses a render function to fully control how the component renders.\nexport const Example = {\n  render: () => html`\n    <my-layout>\n      <header>\n        <h1>Example</h1>\n      </header>\n      <article>\n        <my-component />\n      </article>\n    </my-layout>\n  `,\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nconst meta: Meta = {\n  component: 'my-component',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\n// This story uses a render function to fully control how the component renders.\nexport const Example: Story = {\n  render: () => html`\n    <my-layout>\n      <header>\n        <h1>Example</h1>\n      </header>\n      <article>\n        <my-component />\n      </article>\n    </my-layout>\n  `,\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\n// This story uses a render function to fully control how the component renders.\nexport const Example = meta.story({\n  render: () => html`\n    <my-layout>\n      <header>\n        <h1>Example</h1>\n      </header>\n      <article>\n        <my-component />\n      </article>\n    </my-layout>\n  `,\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\n// This story uses a render function to fully control how the component renders.\nexport const Example = meta.story({\n  render: () => html`\n    <my-layout>\n      <header>\n        <h1>Example</h1>\n      </header>\n      <article>\n        <my-component />\n      </article>\n    </my-layout>\n  `,\n});\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Layout from './Layout.svelte';\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"Example\"\n>\n  {#snippet template(args)}\n   <Layout>\n      <header>\n        <h1>Example</h1>\n      </header>\n      <article>\n        <MyComponent />\n      </article>\n    </Layout>\n  {/snippet}\n</Story>\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Layout from './Layout.svelte';\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"Example\"\n>\n  {#snippet template(args)}\n   <Layout>\n      <header>\n        <h1>Example</h1>\n      </header>\n      <article>\n        <MyComponent />\n      </article>\n    </Layout>\n  {/snippet}\n</Story>\n```\n"
  },
  {
    "path": "docs/_snippets/component-styled-variables-object-notation.md",
    "content": "```js filename=\"MyComponent.js|jsx\" renderer=\"react\" language=\"js\"\nconst Component = styled.div(({ theme }) => ({\n  background: theme.background.app,\n  width: 0,\n}));\n```\n"
  },
  {
    "path": "docs/_snippets/component-styled-variables-template-literals.md",
    "content": "```js filename=\"MyComponent.js|jsx\" renderer=\"react\" language=\"js\"\nconst Component = styled.div`\n  background: `${props => props.theme.background.app}`\n  width: 0;\n`;\n```\n"
  },
  {
    "path": "docs/_snippets/component-test-with-testing-library.md",
    "content": "```ts filename=\"form.component.spec.ts\" renderer=\"angular\" language=\"ts\"\nimport { render, screen, fireEvent } from '@testing-library/angular';\n\nimport { FormComponent } from './login-form.component';\n\nimport { InvalidForm } from './Form.stories'; //👈 Our stories imported here.\n\ntest('Checks if the form is valid ', async () => {\n  await render(FormComponent, {\n    componentProperties: InvalidForm.args,\n  });\n\n  fireEvent.click(screen.getByText('Submit'));\n\n  const isFormValid = screen.getByTestId('invalid-form');\n  expect(isFormValid).toBeInTheDocument();\n});\n```\n\n```js filename=\"Form.test.js\" renderer=\"preact\" language=\"js\"\nimport '@testing-library/jest-dom/extend-expect';\n\nimport { h } from 'preact';\n\nimport { render, fireEvent } from '@testing-library/preact';\n\nimport { InvalidForm } from './LoginForm.stories'; //👈 Our stories imported here.\n\nit('Checks if the form is valid', async () => {\n  const { getByTestId, getByText } = render(<InvalidForm {...InvalidForm.args} />);\n\n  fireEvent.click(getByText('Submit'));\n\n  const isFormValid = getByTestId('invalid-form');\n  expect(isFormValid).toBeInTheDocument();\n});\n```\n\n```js filename=\"Form.test.js|jsx\" renderer=\"react\" language=\"js\"\nimport { fireEvent, render, screen } from '@testing-library/react';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\nimport * as stories from './LoginForm.stories'; // 👈 Our stories imported here.\n\nconst { InvalidForm } = composeStories(stories);\n\ntest('Checks if the form is valid', async () => {\n  // Renders the composed story\n  await InvalidForm.run();\n\n  const buttonElement = screen.getByRole('button', {\n    name: 'Submit',\n  });\n\n  fireEvent.click(buttonElement);\n\n  const isFormValid = screen.getByLabelText('invalid-form');\n  expect(isFormValid).toBeInTheDocument();\n});\n```\n\n```ts filename=\"Form.test.ts|tsx\" renderer=\"react\" language=\"ts\"\nimport { fireEvent, render, screen } from '@testing-library/react';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\nimport * as stories from './LoginForm.stories'; // 👈 Our stories imported here.\n\nconst { InvalidForm } = composeStories(stories);\n\ntest('Checks if the form is valid', async () => {\n  // Renders the composed story\n  await InvalidForm.run();\n\n  const buttonElement = screen.getByRole('button', {\n    name: 'Submit',\n  });\n\n  fireEvent.click(buttonElement);\n\n  const isFormValid = screen.getByLabelText('invalid-form');\n  expect(isFormValid).toBeInTheDocument();\n});\n```\n\n```js filename=\"Form.test.js\" renderer=\"svelte\" language=\"js\"\nimport { fireEvent, render, screen } from '@testing-library/svelte';\n\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport { composeStories } from '@storybook/your-framework';\n\nimport * as stories from './LoginForm.stories'; // 👈 Our stories imported here.\n\nconst { InvalidForm } = composeStories(stories);\n\nit('Checks if the form is valid', async () => {\n  // Renders the composed story\n  await InvalidForm.run();\n\n  await fireEvent.click(screen.getByText('Submit'));\n\n  const isFormValid = screen.getByTestId('invalid-form');\n  expect(isFormValid).toBeInTheDocument();\n});\n```\n\n```js filename=\"tests/Form.test.js\" renderer=\"vue\" language=\"js\"\nimport { fireEvent, render, screen } from '@testing-library/vue';\n\nimport { composeStories } from '@storybook/vue3-vite';\n\nimport * as stories from './LoginForm.stories'; // 👈 Our stories imported here.\n\nconst { InvalidForm } = composeStories(stories);\n\ntest('Checks if the form is valid', async () => {\n  // Renders the composed story\n  await InvalidForm.run();\n\n  const buttonElement = screen.getByRole('button', {\n    name: 'Submit',\n  });\n\n  fireEvent.click(buttonElement);\n\n  const isFormValid = screen.getByLabelText('invalid-form');\n  expect(isFormValid).toBeInTheDocument();\n});\n```\n\n```ts filename=\"tests/Form.test.ts\" renderer=\"vue\" language=\"ts\"\nimport { fireEvent, render, screen } from '@testing-library/vue';\n\nimport { composeStories } from '@storybook/vue3-vite';\n\nimport * as stories from './LoginForm.stories'; // 👈 Our stories imported here.\n\nconst { InvalidForm } = composeStories(stories);\n\ntest('Checks if the form is valid', async () => {\n  // Renders the composed story\n  await InvalidForm.run();\n\n  const buttonElement = screen.getByRole('button', {\n    name: 'Submit',\n  });\n\n  fireEvent.click(buttonElement);\n\n  const isFormValid = screen.getByLabelText('invalid-form');\n  expect(isFormValid).toBeInTheDocument();\n});\n```\n"
  },
  {
    "path": "docs/_snippets/configure-mock-provider-with-story-parameter.md",
    "content": "```js filename=\"Button.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\n// Wrapped in light theme\nexport const Basic = {};\n\n// Wrapped in dark theme\nexport const Dark = {\n  parameters: {\n    theme: 'dark',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n// Wrapped in light theme\nexport const Basic: Story = {};\n\n// Wrapped in dark theme\nexport const Dark: Story = {\n  parameters: {\n    theme: 'dark',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\n// Wrapped in light theme\nexport const Basic = meta.story();\n\n// Wrapped in dark theme\nexport const Dark = meta.story({\n  parameters: {\n    theme: 'dark',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\n// Wrapped in light theme\nexport const Basic = meta.story();\n\n// Wrapped in dark theme\nexport const Dark = meta.story({\n  parameters: {\n    theme: 'dark',\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/create-command-custom-package-manager.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm create storybook@latest --package-manager=npm\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm create storybook@latest --package-manager=npm\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn create storybook --package-manager=npm\n```\n"
  },
  {
    "path": "docs/_snippets/create-command-custom-version.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm create storybook@8.3\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm create storybook@8.3\n```\n"
  },
  {
    "path": "docs/_snippets/create-command-manual-framework.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm create storybook@latest --type solid\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm create storybook@latest --type solid\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn create storybook --type solid\n```\n"
  },
  {
    "path": "docs/_snippets/create-command.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm create storybook@latest\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm create storybook@latest\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn create storybook\n```\n"
  },
  {
    "path": "docs/_snippets/csf-2-example-primary-dark-story.md",
    "content": "```js filename=\"CSF 2 - Button.stories.js|jsx|ts|tsx\" renderer=\"common\" language=\"js\"\nexport const PrimaryOnDark = Primary.bind({});\nPrimaryOnDark.args = Primary.args;\nPrimaryOnDark.parameters = { background: { default: 'dark' } };\n```\n"
  },
  {
    "path": "docs/_snippets/csf-2-example-starter.md",
    "content": "```ts filename=\"CSF 2 - Button.stories.ts\" renderer=\"angular\" language=\"ts\"\nimport { Meta, Story } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nexport default {\n  title: 'Button',\n  component: Button,\n} as Meta;\n\nexport const Primary: Story = (args) => ({\n  props: args,\n});\nPrimary.args = { primary: true };\n```\n\n```js filename=\"CSF 2 - Button.stories.js|jsx\" renderer=\"react\" language=\"js\"\nimport { Button } from './Button';\n\nexport default {\n  title: 'Button',\n  component: Button,\n};\n\nexport const Primary = (args) => <Button {...args} />;\nPrimary.args = { primary: true };\n```\n\n```tsx filename=\"CSF 2 - Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { ComponentStory, ComponentMeta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nexport default {\n  title: 'Button',\n  component: Button,\n} as ComponentMeta<typeof Button>;\n\nexport const Primary: ComponentStory<typeof Button> = (args) => <Button {...args} />;\nPrimary.args = { primary: true };\n```\n\n```js filename=\"CSF 2 - Button.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { Button } from './Button';\n\nexport default {\n  title: 'Button',\n  component: Button,\n};\n\nexport const Primary = (args) => <Button {...args} />;\nPrimary.args = { primary: true };\n```\n\n```tsx filename=\"CSF 2 - Button.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport { ComponentStory, ComponentMeta } from 'storybook-solidjs-vite';\n\nimport { Button } from './Button';\n\nexport default {\n  title: 'Button',\n  component: Button,\n} as ComponentMeta<typeof Button>;\n\nexport const Primary: ComponentStory<typeof Button> = (args) => <Button {...args} />;\nPrimary.args = { primary: true };\n```\n\n```js filename=\"CSF 2 - Button.stories.js\" renderer=\"svelte\" language=\"js\"\nimport Button from './Button.svelte';\n\nexport default {\n  title: 'Button',\n  component: Button,\n};\n\nexport const Primary = (args) => ({\n  Component: Button,\n  props: args,\n});\nPrimary.args = { primary: true };\n```\n\n```ts filename=\"CSF 2 - Button.stories.ts\" renderer=\"svelte\" language=\"ts\"\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport type { Meta, StoryFn } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nexport default {\n  title: 'Button',\n  component: Button,\n} as Meta<typeof Button>;\n\nexport const Primary: StoryFn<typeof Button> = (args) => ({\n  Component: Button,\n  props: args,\n});\nPrimary.args = { primary: true };\n```\n\n```js filename=\"CSF 2 - Button.stories.js\" renderer=\"vue\" language=\"js\"\nimport Button from './Button.vue';\n\nexport default {\n  title: 'Button',\n  component: Button,\n};\n\nexport const Primary = (args) => ({\n  components: { Button },\n  setup() {\n    return { args };\n  },\n  template: '<Button v-bind=\"args\" />',\n});\nPrimary.args = { primary: true };\n```\n\n```ts filename=\"CSF 2 - Button.stories.ts\" renderer=\"vue\" language=\"ts\"\nimport { Meta, StoryFn } from '@storybook/vue3-vite';\n\nimport Button from './Button.vue';\n\nexport default {\n  title: 'Button',\n  component: Button,\n} as Meta<typeof Button>;\n\nexport const Primary: StoryFn<typeof Button> = (args) => ({\n  components: { Button },\n  setup() {\n    return { args };\n  },\n  template: '<Button v-bind=\"args\" />',\n});\nPrimary.args = { primary: true };\n```\n\n```js filename=\"CSF 2 - Button.stories.js\" renderer=\"web-components\" language=\"js\"\nimport { html } from 'lit';\n\nexport default {\n  title: 'components/Button',\n  component: 'demo-button',\n};\n\nexport const Primary = ({ primary }) => html`<custom-button ?primary=${primary}></custom-button>`;\nPrimary.args = {\n  primary: true,\n};\n```\n\n```ts filename=\"CSF 2 - Button.stories.ts\" renderer=\"web-components\" language=\"ts\"\nimport type { Meta, Story } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nexport default {\n  title: 'components/Button',\n  component: 'demo-button',\n} as Meta;\n\nexport const Primary: Story = ({ primary }) =>\n  html`<demo-button ?primary=${primary}></demo-button>`;\nPrimary.args = {\n  primary: true,\n};\n```\n"
  },
  {
    "path": "docs/_snippets/csf-2-example-story.md",
    "content": "```ts filename=\"CSF 2 - Button.stories.ts\" renderer=\"angular\" language=\"ts\"\n// Other imports and story implementation\nexport const Basic: Story = (args) => ({\n  props: args,\n});\n```\n\n```js filename=\"CSF 2 - Button.stories.js|jsx\" renderer=\"react\" language=\"js\"\n// Other imports and story implementation\nexport const Basic = (args) => <Button {...args} />;\n```\n\n```ts filename=\"CSF 2 - Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\"\n// Other imports and story implementation\nexport const Basic: ComponentStory<typeof Button> = (args) => <Button {...args} />;\n```\n\n```js filename=\"CSF 2 - Button.stories.js|jsx\" renderer=\"solid\" language=\"js\"\n// Other imports and story implementation\nexport const Basic = (args) => <Button {...args} />;\n```\n\n```ts filename=\"CSF 2 - Button.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\n// Other imports and story implementation\nexport const Basic: ComponentStory<typeof Button> = (args) => <Button {...args} />;\n```\n\n```js filename=\"CSF 2 - Button.stories.js\" renderer=\"svelte\" language=\"js\"\n// Other imports and story implementation\nexport const Basic = (args) => ({\n  Component: Button,\n  props: args,\n});\n```\n\n```ts filename=\"CSF 2 - Button.stories.ts\" renderer=\"svelte\" language=\"ts\"\n// Other imports and story implementation\nexport const Basic: StoryFn<typeof Button> = (args) => ({\n  Component: Button,\n  props: args,\n});\n```\n\n```js filename=\"CSF 2 - Button.stories.js\" renderer=\"vue\" language=\"js\"\n// Other imports and story implementation\nexport const Basic = (args) => ({\n  components: { Button },\n  setup() {\n    return { args };\n  },\n  template: '<Button v-bind=\"args\" />',\n});\n```\n\n```ts filename=\"CSF 2 - Button.stories.ts\" renderer=\"vue\" language=\"ts\"\n// Other imports and story implementation\nexport const Basic: StoryFn<typeof Button> = (args) => ({\n  components: { Button },\n  setup() {\n    return { args };\n  },\n  template: '<Button v-bind=\"args\" />',\n});\n```\n\n```js filename=\"CSF 2 - Button.stories.js\" renderer=\"web-components\" language=\"js\"\n// Other imports and story implementation\n\nexport const Basic = ({ primary, size, label }) =>\n  html`<custom-button ?primary=${primary} size=${size} label=${label}></custom-button>`;\n```\n\n```ts filename=\"CSF 2 - Button.stories.ts\" renderer=\"web-components\" language=\"ts\"\n// Other imports and story implementation\n\nexport const Basic: Story = ({ primary, backgroundColor, size, label }) =>\n  html`<custom-button ?primary=${primary} size=${size} label=${label}></custom-button>`;\n```\n"
  },
  {
    "path": "docs/_snippets/csf-2-example-title.md",
    "content": "```js filename=\"CSF 2 - Button.stories.js|jsx|ts|tsx\" renderer=\"common\" language=\"js\"\nexport default {\n  title: 'components/Button',\n  component: Button,\n};\n```\n"
  },
  {
    "path": "docs/_snippets/csf-3-example-auto-title.md",
    "content": "```js filename=\"CSF 3 - Button.stories.js|jsx|ts|tsx\" renderer=\"common\" language=\"js\"\nexport default { component: Button };\n```\n"
  },
  {
    "path": "docs/_snippets/csf-3-example-default-render.md",
    "content": "```js filename=\"CSF 3 - Button.stories.js|jsx|ts|tsx\" renderer=\"common\" language=\"js\"\nexport const Basic = {};\n```\n"
  },
  {
    "path": "docs/_snippets/csf-3-example-primary-dark-story.md",
    "content": "```js filename=\"CSF 3 - Button.stories.js|jsx\" renderer=\"common\" language=\"js\"\nexport const PrimaryOnDark = {\n  ...Primary,\n  parameters: { background: { default: 'dark' } },\n};\n```\n\n```ts filename=\"CSF 3 - Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\"\nexport const PrimaryOnDark: Story = {\n  ...Primary,\n  parameters: { background: { default: 'dark' } },\n};\n```\n"
  },
  {
    "path": "docs/_snippets/csf-3-example-render.md",
    "content": "```ts filename=\"CSF 3 - Button.stories.ts\" renderer=\"angular\" language=\"ts\"\n// Other imports and story implementation\nexport const Basic: Story = {\n  render: (args) => ({\n    props: args,\n  }),\n};\n```\n\n```js filename=\"CSF 3 - Button.stories.js|jsx\" renderer=\"react\" language=\"js\"\n// Other imports and story implementation\nexport const Basic = {\n  render: (args) => <Button {...args} />,\n};\n```\n\n```ts filename=\"CSF 3 - Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\"\n// Other imports and story implementation\nexport const Basic: Story = {\n  render: (args) => <Button {...args} />,\n};\n```\n\n```js filename=\"CSF 3 - Button.stories.js|jsx\" renderer=\"solid\" language=\"js\"\n// Other imports and story implementation\nexport const Basic = {\n  render: (args) => <Button {...args} />,\n};\n```\n\n```ts filename=\"CSF 3 - Button.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\n// Other imports and story implementation\nexport const Basic: Story = {\n  render: (args) => <Button {...args} />,\n};\n```\n\n```js filename=\"CSF 3 - Button.stories.js\" renderer=\"svelte\" language=\"js\"\n// Other imports and story implementation\nexport const Basic = {\n  render: (args) => ({\n    Component: Button,\n    props: args,\n  });\n};\n```\n\n```ts filename=\"CSF 3 - Button.stories.ts\" renderer=\"svelte\" language=\"ts\"\n// Other imports and story implementation\nexport const Basic: Story = {\n  render: (args) => ({\n    Component: Button,\n    props: args,\n  }),\n};\n```\n\n```js filename=\"CSF 3 - Button.stories.js\" renderer=\"vue\" language=\"js\"\n// Other imports and story implementation\nexport const Basic = {\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: '<Button v-bind=\"args\" />',\n  }),\n};\n```\n\n```ts filename=\"CSF 3 - Button.stories.ts\" renderer=\"vue\" language=\"ts\"\n// Other imports and story implementation\nexport const Basic: Story = {\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: '<Button v-bind=\"args\" />',\n  }),\n};\n```\n\n```js filename=\"CSF 3 - Button.stories.js\" renderer=\"web-components\" language=\"js\"\n// Other imports and story implementation\n\nexport const Basic = {\n  render: (args) => html`<demo-button label=\"Hello\" @click=${action('clicked')}></demo-button>`,\n};\n```\n\n```ts filename=\"CSF 3 - Button.stories.ts\" renderer=\"web-components\" language=\"ts\"\n// Other imports and story implementation\n\nexport const Basic: Story = {\n  render: (args) => html`<demo-button label=\"Hello\" @click=${action('clicked')}></demo-button>`,\n};\n```\n"
  },
  {
    "path": "docs/_snippets/csf-3-example-starter.md",
    "content": "```ts filename=\"CSF 3 - Button.stories.ts\" renderer=\"angular\" language=\"ts\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = { component: Button };\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const Primary: Story = { args: { primary: true } };\n```\n\n```js filename=\"CSF 3 - Button.stories.js|jsx\" renderer=\"react\" language=\"js\"\nimport { Button } from './Button';\n\nexport default { component: Button };\n\nexport const Primary = { args: { primary: true } };\n```\n\n```ts filename=\"CSF 3 - Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = { args: { primary: true } };\n```\n\n```ts filename=\"CSF 3 - Button.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = { args: { primary: true } };\n```\n\n```js filename=\"CSF 3 - Button.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { Button } from './Button';\n\nexport default { component: Button };\n\nexport const Primary = { args: { primary: true } };\n```\n\n```js filename=\"CSF 3 - Button.stories.js\" renderer=\"svelte\" language=\"js\"\nimport Button from './Button.svelte';\n\nexport default { component: Button };\n\nexport const Primary = { args: { primary: true } };\n```\n\n```ts filename=\"CSF 3 - Button.stories.ts\" renderer=\"svelte\" language=\"ts\"\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = { args: { primary: true } };\n```\n\n```js filename=\"CSF 3 - Button.stories.js\" renderer=\"vue\" language=\"js\"\nimport Button from './Button.vue';\n\nexport default { component: Button };\n\nexport const Primary = { args: { primary: true } };\n```\n\n```ts filename=\"CSF 3 - Button.stories.ts\" renderer=\"vue\" language=\"ts\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport Button from './Button.vue';\n\nconst meta = { component: Button } satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = { args: { primary: true } };\n```\n\n```js filename=\"CSF 3 - Button.stories.js\" renderer=\"web-components\" language=\"js\"\nexport default {\n  title: 'components/Button',\n  component: 'demo-button',\n};\n\nexport const Primary = { args: { primary: true } };\n```\n\n```ts filename=\"CSF 3 - Button.stories.ts\" renderer=\"web-components\" language=\"ts\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  title: 'components/Button',\n  component: 'demo-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Primary: Story = { args: { primary: true } };\n```\n"
  },
  {
    "path": "docs/_snippets/csf-3-example-title.md",
    "content": "<!-- prettier-ignore -->\n```mdx filename=\"src/components/Button/Button.mdx\" renderer=\"common\" language=\"mdx\"\nimport { Meta, Story } from '@storybook/addon-docs/blocks';\n\n{/* 👇 Documentation-only page */}\n\n<Meta title=\"Documentation\" />\n\n{/* 👇 Component documentation page */}\nimport * as ButtonStories from './Button.stories';\n\n<Meta of={ButtonStories} />\n\n<Story of={ButtonStories.Primary} />\n```\n\n```js filename=\"src/components/Button/Button.stories.js|jsx\" renderer=\"common\" language=\"js\"\nimport { Button } from './Button';\n\nexport default {\n  // Sets the name for the stories container\n  title: 'components/Button',\n  // The component name will be used if `title` is not set\n  component: Button,\n};\n\n// The story variable name will be used if `name` is not set\nconst Primary = {\n  // Sets the name for that particular story\n  name: 'Primary',\n  args: {\n    label: 'Button',\n  },\n};\n```\n\n```ts filename=\"src/components/Button/Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  // Sets the name for the stories container\n  title: 'components/Button',\n  // The component name will be used if `title` is not set\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// The story variable name will be used if `name` is not set\nconst Primary: Story = {\n  // Sets the name for that particular story\n  name: 'Primary',\n  args: {\n    label: 'Button',\n  },\n};\n```\n"
  },
  {
    "path": "docs/_snippets/csf-factories-automigrate-with-config-directory.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook automigrate csf-factories -c apps/admin/.storybook\nnpx storybook automigrate csf-factories -c apps/website/.storybook\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx storybook automigrate csf-factories -c apps/admin/.storybook\npnpm dlx storybook automigrate csf-factories -c apps/website/.storybook\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn dlx storybook automigrate csf-factories -c apps/admin/.storybook\nyarn dlx storybook automigrate csf-factories -c apps/website/.storybook\n```\n"
  },
  {
    "path": "docs/_snippets/csf-factories-automigrate.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook automigrate csf-factories\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx storybook automigrate csf-factories\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn dlx storybook automigrate csf-factories\n```\n"
  },
  {
    "path": "docs/_snippets/custom-docs-page.md",
    "content": "```js filename=\"CustomDocumentationComponent.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"js-component\"\nimport React from 'react';\n\nexport function CustomDocumentationComponent() {\n  return (\n    <div>\n      <h1>Replacing DocsPage with a custom component</h1>\n      <p>\n        The Docs page can be customized with your own custom content written as a React Component.\n      </p>\n      <p>Write your own code here👇</p>\n    </div>\n  );\n}\n```\n\n<!-- prettier-ignore -->\n```mdx filename=\"Custom-MDX-Documentation.mdx\" renderer=\"common\" language=\"mdx\"\n# Replacing DocsPage with custom `MDX` content\n\nThis file is a documentation-only `MDX`file to customize Storybook's [DocsPage](https://storybook.js.org/docs/writing-docs/docs-page#replacing-docspage).\n\nIt can be further expanded with your own code snippets and include specific information related to your stories.\n\nFor example:\n\nimport { Story } from \"@storybook/addon-docs\";\n\n## Button\n\nButton is the primary component. It has four possible states.\n\n- [Primary](#primary)\n- [Secondary](#secondary)\n- [Large](#large)\n- [Small](#small)\n\n## With the story title defined\n\nIf you included the title in the story's default export, use this approach.\n\n### Primary\n\n<Story id=\"example-button--primary\" />\n\n### Secondary\n\n<Story id=\"example-button--secondary\" />\n\n### Large\n\n<Story id=\"example-button--large\" />\n\n### Small\n\n<Story id=\"example-button--small\" />\n\n## Without the story title defined\n\nIf you didn't include the title in the story's default export, use this approach.\n\n### Primary\n\n<Story id=\"your-directory-button--primary\"/>\n\n### Secondary\n\n<Story id=\"your-directory-button--secondary\"/>\n\n### Large\n\n<Story id=\"your-directory-button--large\"/>\n\n### Small\n\n<Story id=\"your-directory-button--small\" />\n```\n\n```ts filename=\"CustomDocumentationComponent.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"ts-component\"\nexport const CustomDocumentationComponent: React.FC = () => {\n  return (\n    <div>\n      <h1>Replacing DocsPage with a custom component</h1>\n      <p>\n        The Docs page can be customized with your own custom content written as a React Component.\n      </p>\n      <p>Write your own code here👇</p>\n    </div>\n  );\n};\n```\n"
  },
  {
    "path": "docs/_snippets/decorator-parameterized-in-preview.md",
    "content": "```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Preview, componentWrapperDecorator } from '@storybook/angular';\n\nconst preview: Preview = {\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    componentWrapperDecorator((story, { parameters }) => {\n      // 👇 Make it configurable by reading from parameters\n      const { pageLayout } = parameters;\n      switch (pageLayout) {\n        case 'page':\n          //  Your page layout is probably a little more complex than this\n          return `<div class=\"page-layout\">${story}</div>`;\n        case 'page-mobile':\n          return `<div class=\"page-mobile-layout\">${story}</div>`;\n        default:\n          // In the default case, don't apply a layout\n          return story;\n      }\n    }),\n  ],\n};\n\nexport default preview;\n```\n\n```js filename=\".storybook/preview.jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport React from 'react';\n\nexport default {\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    (Story, { parameters }) => {\n      // 👇 Make it configurable by reading from parameters\n      const { pageLayout } = parameters;\n      switch (pageLayout) {\n        case 'page':\n          return (\n            // Your page layout is probably a little more complex than this\n            <div className=\"page-layout\">\n              <Story />\n            </div>\n          );\n        case 'page-mobile':\n          return (\n            <div className=\"page-mobile-layout\">\n              <Story />\n            </div>\n          );\n        default:\n          // In the default case, don't apply a layout\n          return <Story />;\n      }\n    },\n  ],\n};\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\nimport React from 'react';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    (Story, { parameters }) => {\n      // 👇 Make it configurable by reading from parameters\n      const { pageLayout } = parameters;\n      switch (pageLayout) {\n        case 'page':\n          return (\n            // Your page layout is probably a little more complex than this\n            <div className=\"page-layout\">\n              <Story />\n            </div>\n          );\n        case 'page-mobile':\n          return (\n            <div className=\"page-mobile-layout\">\n              <Story />\n            </div>\n          );\n        default:\n          // In the default case, don't apply a layout\n          return <Story />;\n      }\n    },\n  ],\n};\n\nexport default preview;\n```\n\n```jsx filename=\".storybook/preview.jsx\" renderer=\"solid\" language=\"js\"\nexport default {\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    (Story, { parameters }) => {\n      // 👇 Make it configurable by reading from parameters\n      const { pageLayout } = parameters;\n      switch (pageLayout) {\n        case 'page':\n          return (\n            // Your page layout is probably a little more complex than this\n            <div className=\"page-layout\">\n              <Story />\n            </div>\n          );\n        case 'page-mobile':\n          return (\n            <div className=\"page-mobile-layout\">\n              <Story />\n            </div>\n          );\n        default:\n          // In the default case, don't apply a layout\n          return <Story />;\n      }\n    },\n  ],\n};\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Preview } from 'storybook-solidjs-vite';\n\nconst preview: Preview = {\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    (Story, { parameters }) => {\n      // 👇 Make it configurable by reading from parameters\n      const { pageLayout } = parameters;\n      switch (pageLayout) {\n        case 'page':\n          return (\n            // Your page layout is probably a little more complex than this\n            <div className=\"page-layout\">\n              <Story />\n            </div>\n          );\n        case 'page-mobile':\n          return (\n            <div className=\"page-mobile-layout\">\n              <Story />\n            </div>\n          );\n        default:\n          // In the default case, don't apply a layout\n          return <Story />;\n      }\n    },\n  ],\n};\n\nexport default preview;\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    (_, { parameters }) => {\n      // 👇 Make it configurable by reading from parameters\n      const { pageLayout } = parameters;\n      switch (pageLayout) {\n        case 'page':\n          // Your page layout is probably a little more complex than this\n          return { template: '<div class=\"page-layout\"><story/></div>' };\n        case 'page-mobile':\n          return { template: '<div class=\"page-mobile-layout\"><story/></div>' };\n        default:\n          // In the default case, don't apply a layout\n          return { template: '<story/>' };\n      }\n    },\n  ],\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Preview } from '@storybook/vue3-vite';\n\nconst preview: Preview = {\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    (_, { parameters }) => {\n      // 👇 Make it configurable by reading from parameters\n      const { pageLayout } = parameters;\n      switch (pageLayout) {\n        case 'page':\n          // Your page layout is probably a little more complex than this ;)\n          return { template: '<div class=\"page-layout\"><story/></div>' };\n        case 'page-mobile':\n          return { template: '<div class=\"page-mobile-layout\"><story/></div>' };\n        default:\n          // In the default case, don't apply a layout\n          return { template: '<story/>' };\n      }\n    },\n  ],\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Preview\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Preview } from '@storybook/your-framework';\n\nimport PageLayout from './PageLayout.svelte';\n\nconst preview: Preview = {\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    (story, { parameters }) => {\n      // 👇 Make it configurable by reading from parameters\n      const { pageLayout } = parameters;\n      return {\n        Component: PageLayout,\n        props: {\n          layout: pageLayout || 'default',\n          children: story,\n        },\n      };\n    },\n  ],\n};\n\nexport default preview;\n```\n\n```svelte filename=\".storybook/PageLayout.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Layout component\"\n<script lang=\"ts\">\n  interface Props {\n    layout?: 'page' | 'page-mobile' | 'default';\n    children?: import('svelte').Snippet;\n  }\n\n  let { layout = 'default', children }: Props = $props();\n</script>\n\n<!-- Your page layout is probably a little more complex than this -->\n<div class={layout}>\n  {@render children?.()}\n</div>\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"Preview\"\nimport PageLayout from './PageLayout.svelte';\n\nconst preview = {\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    (story, { parameters }) => {\n      // 👇 Make it configurable by reading from parameters\n      const { pageLayout } = parameters;\n      return {\n        Component: PageLayout,\n        props: {\n          layout: pageLayout || 'default',\n          children: story,\n        },\n      };\n    },\n  ],\n};\n\nexport default preview;\n```\n\n```svelte filename=\".storybook/PageLayout.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Layout component\"\n<script>\n  let { layout = 'default', children } = $props();\n</script>\n\n<!-- Your page layout is probably a little more complex than this -->\n<div class={layout}>\n  {@render children?.()}\n</div>\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Preview } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nconst preview: Preview = {\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    (story, { parameters }) => {\n      // 👇 Make it configurable by reading from parameters\n      const { pageLayout } = parameters;\n      switch (pageLayout) {\n        case 'page':\n          // Your page layout is probably a little more complex than this\n          return html`<div class=\"page-layout\">${story()}</div>`;\n        case 'page-mobile':\n          return html`<div class=\"page-mobile-layout\">${story()}</div>`;\n        default:\n          // In the default case, don't apply a layout\n          return story();\n      }\n    },\n  ],\n};\n\nexport default preview;\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\"  tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nconst preview = {\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    (story, { parameters }) => {\n      // 👇 Make it configurable by reading from parameters\n      const { pageLayout } = parameters;\n      switch (pageLayout) {\n        case 'page':\n          // Your page layout is probably a little more complex than this\n          return html`<div class=\"page-layout\">${story()}</div>`;\n        case 'page-mobile':\n          return html`<div class=\"page-mobile-layout\">${story()}</div>`;\n        default:\n          // In the default case, don't apply a layout\n          return story();\n      }\n    },\n  ],\n};\n\nexport default preview;\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport React from 'react';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    (Story, { parameters }) => {\n      // 👇 Make it configurable by reading from parameters\n      const { pageLayout } = parameters;\n      switch (pageLayout) {\n        case 'page':\n          return (\n            // Your page layout is probably a little more complex than this\n            <div className=\"page-layout\">\n              <Story />\n            </div>\n          );\n        case 'page-mobile':\n          return (\n            <div className=\"page-mobile-layout\">\n              <Story />\n            </div>\n          );\n        default:\n          // In the default case, don't apply a layout\n          return <Story />;\n      }\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport React from 'react';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    (Story, { parameters }) => {\n      // 👇 Make it configurable by reading from parameters\n      const { pageLayout } = parameters;\n      switch (pageLayout) {\n        case 'page':\n          return (\n            // Your page layout is probably a little more complex than this\n            <div className=\"page-layout\">\n              <Story />\n            </div>\n          );\n        case 'page-mobile':\n          return (\n            <div className=\"page-mobile-layout\">\n              <Story />\n            </div>\n          );\n        default:\n          // In the default case, don't apply a layout\n          return <Story />;\n      }\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    (_, { parameters }) => {\n      // 👇 Make it configurable by reading from parameters\n      const { pageLayout } = parameters;\n      switch (pageLayout) {\n        case 'page':\n          // Your page layout is probably a little more complex than this\n          return { template: '<div class=\"page-layout\"><story/></div>' };\n        case 'page-mobile':\n          return { template: '<div class=\"page-mobile-layout\"><story/></div>' };\n        default:\n          // In the default case, don't apply a layout\n          return { template: '<story/>' };\n      }\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    (_, { parameters }) => {\n      // 👇 Make it configurable by reading from parameters\n      const { pageLayout } = parameters;\n      switch (pageLayout) {\n        case 'page':\n          // Your page layout is probably a little more complex than this\n          return { template: '<div class=\"page-layout\"><story/></div>' };\n        case 'page-mobile':\n          return { template: '<div class=\"page-mobile-layout\"><story/></div>' };\n        default:\n          // In the default case, don't apply a layout\n          return { template: '<story/>' };\n      }\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview, componentWrapperDecorator } from '@storybook/angular';\n\nexport default definePreview({\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    componentWrapperDecorator((story, { parameters }) => {\n      // 👇 Make it configurable by reading from parameters\n      const { pageLayout } = parameters;\n      switch (pageLayout) {\n        case 'page':\n          //  Your page layout is probably a little more complex than this\n          return `<div class=\"page-layout\">${story}</div>`;\n        case 'page-mobile':\n          return `<div class=\"page-mobile-layout\">${story}</div>`;\n        default:\n          // In the default case, don't apply a layout\n          return story;\n      }\n    }),\n  ],\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    (story, { parameters }) => {\n      // 👇 Make it configurable by reading from parameters\n      const { pageLayout } = parameters;\n      switch (pageLayout) {\n        case 'page':\n          // Your page layout is probably a little more complex than this\n          return html`<div class=\"page-layout\">${story()}</div>`;\n        case 'page-mobile':\n          return html`<div class=\"page-mobile-layout\">${story()}</div>`;\n        default:\n          // In the default case, don't apply a layout\n          return story();\n      }\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    (story, { parameters }) => {\n      // 👇 Make it configurable by reading from parameters\n      const { pageLayout } = parameters;\n      switch (pageLayout) {\n        case 'page':\n          // Your page layout is probably a little more complex than this\n          return html`<div class=\"page-layout\">${story()}</div>`;\n        case 'page-mobile':\n          return html`<div class=\"page-mobile-layout\">${story()}</div>`;\n        default:\n          // In the default case, don't apply a layout\n          return story();\n      }\n    },\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/decorator-with-reactive-globals.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\"\nimport { computed } from 'vue';\n\nexport default {\n  decorators: [\n    (story, { globals }) => {\n      return {\n        components: { story },\n        setup() {\n          const greeting = computed(() => (globals?.locale === 'en' ? 'Hello!' : '¡Hola!'));\n\n          return { greeting, globals };\n        },\n        template: `\n          <div :lang={{globals?.locale || 'en'}}>\n            <p>Greeting: {{greeting}}</p>\n            <story />\n          </div>\n        `,\n      };\n    },\n  ],\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\"\nimport { computed } from 'vue';\nimport type { Preview } from '@storybook/vue3-vite';\n\nconst preview: Preview = {\n  decorators: [\n    (story, { globals }) => {\n      return {\n        components: { story },\n        setup() {\n          const greeting = computed(() => (globals?.locale === 'en' ? 'Hello!' : '¡Hola!'));\n\n          return { greeting, globals };\n        },\n        template: `\n          <div :lang={{globals?.locale || 'en'}}>\n            <p>Greeting: {{greeting}}</p>\n            <story />\n          </div>\n        `,\n      };\n    },\n  ],\n};\n\nexport default preview;\n```\n"
  },
  {
    "path": "docs/_snippets/decorator-with-updateArgs.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\"\nimport { useArgs } from 'storybook/preview-api';\n\nconst WithIncrementDecorator = {\n  args: {\n    counter: 0,\n  },\n  decorators: [\n    (story, { args }) => {\n      const [, updateArgs] = useArgs();\n      return {\n        components: { story },\n        setup() {\n          return { args, updateArgs };\n        },\n        template: `\n          <div>\n            <button @click=\"() => updateArgs({ counter: args.counter + 1 })\">\n              Increment\n            </button>\n            <story />\n          </div>\n        `,\n      };\n    },\n  ],\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\"\nimport { useArgs } from 'storybook/preview-api';\nimport type { Meta, StoryObj } from '@storybook/vue3';\n\nconst WithIncrementDecorator: StoryObj<Meta<typeof MyComponent>> = {\n  args: {\n    counter: 0,\n  },\n  decorators: [\n    (story, { args }) => {\n      const [, updateArgs] = useArgs();\n      return {\n        components: { story },\n        setup() {\n          return { args, updateArgs };\n        },\n        template: `\n          <div>\n            <button @click=\"() => updateArgs({ counter: args.counter + 1 })\">\n              Increment\n            </button>\n            <story />\n          </div>\n        `,\n      };\n    },\n  ],\n};\n```\n"
  },
  {
    "path": "docs/_snippets/document-screen-fetch.md",
    "content": "```ts filename=\"your-page.component.ts\" renderer=\"angular\" language=\"ts\"\nimport { Component, OnInit } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\n\n@Component({\n  selector: 'document-screen',\n  template: `\n    <div>\n      <div *ngIf=\"error\"><p>There was an error fetching the data!</p></div>\n      <div *ngIf=\"loading\"><p>Loading...</p></div>\n      <div *ngIf=\"!loading && subdocuments.length > 0\">\n        <page-layout [user]=\"user\">\n          <document-header [document]=\"document\"></document-header>\n          <document-list [documents]=\"subdocuments\"></document-list>\n        </page-layout>\n      </div>\n    </div>\n  `,\n})\nexport class DocumentScreen implements OnInit {\n  user: any = { id: 0, name: 'Some User' };\n\n  document: any = { id: 0, title: 'Some Title' };\n\n  subdocuments: any = [];\n\n  error = false;\n  loading = true;\n\n  constructor(private http: HttpClient) {}\n\n  ngOnInit() {\n    this.http.get<any>('https://your-restful-endpoint').subscribe({\n      next: (data) => {\n        this.loading = false;\n        this.user = data.user;\n        this.document = data.document;\n        this.subdocuments = data.subdocuments;\n      },\n      error: (error) => {\n        this.error = true;\n      },\n    });\n  }\n}\n```\n\n```js filename=\"YourPage.jsx\" renderer=\"react\" language=\"js\"\nimport React, { useState, useEffect } from 'react';\n\nimport { PageLayout } from './PageLayout';\nimport { DocumentHeader } from './DocumentHeader';\nimport { DocumentList } from './DocumentList';\n\n// Example hook to retrieve data from an external endpoint\nfunction useFetchData() {\n  const [status, setStatus] = useState('idle');\n  const [data, setData] = useState([]);\n  useEffect(() => {\n    setStatus('loading');\n    fetch('https://your-restful-endpoint')\n      .then((res) => {\n        if (!res.ok) {\n          throw new Error(res.statusText);\n        }\n        return res;\n      })\n      .then((res) => res.json())\n      .then((data) => {\n        setStatus('success');\n        setData(data);\n      })\n      .catch(() => {\n        setStatus('error');\n      });\n  }, []);\n  return {\n    status,\n    data,\n  };\n}\nexport function DocumentScreen() {\n  const { status, data } = useFetchData();\n\n  const { user, document, subdocuments } = data;\n\n  if (status === 'loading') {\n    return <p>Loading...</p>;\n  }\n  if (status === 'error') {\n    return <p>There was an error fetching the data!</p>;\n  }\n  return (\n    <PageLayout user={user}>\n      <DocumentHeader document={document} />\n      <DocumentList documents={subdocuments} />\n    </PageLayout>\n  );\n}\n```\n\n```ts filename=\"YourPage.tsx\" renderer=\"react\" language=\"ts\"\nimport React, { useState, useEffect } from 'react';\n\nimport { PageLayout } from './PageLayout';\nimport { DocumentHeader } from './DocumentHeader';\nimport { DocumentList } from './DocumentList';\n\n// Example hook to retrieve data from an external endpoint\nfunction useFetchData() {\n  const [status, setStatus] = useState<string>('idle');\n  const [data, setData] = useState<any[]>([]);\n  useEffect(() => {\n    setStatus('loading');\n    fetch('https://your-restful-endpoint')\n      .then((res) => {\n        if (!res.ok) {\n          throw new Error(res.statusText);\n        }\n        return res;\n      })\n      .then((res) => res.json())\n      .then((data) => {\n        setStatus('success');\n        setData(data);\n      })\n      .catch(() => {\n        setStatus('error');\n      });\n  }, []);\n\n  return {\n    status,\n    data,\n  };\n}\n\nexport function DocumentScreen() {\n  const { status, data } = useFetchData();\n\n  const { user, document, subdocuments } = data;\n\n  if (status === 'loading') {\n    return <p>Loading...</p>;\n  }\n  if (status === 'error') {\n    return <p>There was an error fetching the data!</p>;\n  }\n  return (\n    <PageLayout user={user}>\n      <DocumentHeader document={document} />\n      <DocumentList documents={subdocuments} />\n    </PageLayout>\n  );\n}\n```\n\n```js filename=\"YourPage.jsx\" renderer=\"solid\" language=\"js\"\nimport { createSignal, Match, Switch } from 'solid-js';\n\nimport { PageLayout } from './PageLayout';\nimport { DocumentHeader } from './DocumentHeader';\nimport { DocumentList } from './DocumentList';\n\n// Example hook to retrieve data from an external endpoint\nfunction useFetchData() {\n  const [status, setStatus] = createSignal('idle');\n  const [data, setData] = createSignal([]);\n\n  setStatus('loading');\n  fetch('https://your-restful-endpoint')\n    .then((res) => {\n      if (!res.ok) {\n        throw new Error(res.statusText);\n      }\n      return res;\n    })\n    .then((res) => res.json())\n    .then((data) => {\n      setStatus('success');\n      setData(data);\n    })\n    .catch(() => {\n      setStatus('error');\n    });\n\n  return {\n    status,\n    data,\n  };\n}\nexport function DocumentScreen() {\n  const { status, data } = useFetchData();\n\n  return (\n    <Switch>\n      <Match when={status() === 'loading'}>\n        <p>Loading...</p>\n      </Match>\n      <Match when={status() === 'error'}>\n        <p>There was an error fetching the data!</p>\n      </Match>\n      <Match when={user} keyed>\n        <PageLayout user={data().user}>\n          <DocumentHeader document={data().document} />\n          <DocumentList documents={data().subdocuments} />\n        </PageLayout>\n      </Match>\n    </Switch>\n  );\n}\n```\n\n```svelte filename=\"YourPage.svelte\" renderer=\"svelte\" language=\"js\"\n<script>\n  import { onMount } from 'svelte';\n\n  import PageLayout from './PageLayout.svelte';\n  import DocumentHeader from './DocumentHeader.svelte';\n  import DocumentList from './DocumentList.svelte';\n\n  export let user = {};\n  export let document = {};\n  export let subdocuments = [];\n  export let status = 'loading';\n\n  onMount(async () => {\n    await fetch('https://your-restful-endpoint')\n      .then((res) => {\n        if (!res.ok) {\n          throw new Error(res.statusText);\n        }\n        return res;\n      })\n      .then((res) => res.json())\n      .then((data) => {\n        user = data.user;\n        status = 'success';\n        document = data.document;\n        subdocuments = data.subdocuments;\n      })\n      .catch(() => {\n        status = 'error';\n      });\n  });\n</script>\n\n{#if status === \"error\"}\n<p>There was an error fetching the data!</p>\n{:else if status === \"loading\"}\n<p>Loading...</p>\n{:else}\n<PageLayout {user}>\n  <DocumentHeader {document} />\n  <DocumentList documents=\"{subdocuments}\" />\n</PageLayout>\n{/if}\n```\n\n```svelte filename=\"YourPage.svelte\" renderer=\"svelte\" language=\"ts\"\n<script lang=\"ts\">\n  import { onMount } from 'svelte';\n\n  import PageLayout from './PageLayout.svelte';\n  import DocumentHeader from './DocumentHeader.svelte';\n  import DocumentList from './DocumentList.svelte';\n\n  export let user: Record<string, unknown> = {};\n  export let document: Record<string, unknown> = {};\n  export let subdocuments: Record<string, unknown>[] = [];\n  export let status: 'error' | 'loading' | 'success' = 'loading';\n\n  onMount(async () => {\n    await fetch('https://your-restful-endpoint')\n      .then((res) => {\n        if (!res.ok) {\n          throw new Error(res.statusText);\n        }\n        return res;\n      })\n      .then((res) => res.json())\n      .then((data) => {\n        user = data.user;\n        status = 'success';\n        document = data.document;\n        subdocuments = data.subdocuments;\n      })\n      .catch(() => {\n        status = 'error';\n      });\n  });\n</script>\n\n{#if status === \"error\"}\n<p>There was an error fetching the data!</p>\n{:else if status === \"loading\"}\n<p>Loading...</p>\n{:else}\n<PageLayout {user}>\n  <DocumentHeader {document} />\n  <DocumentList documents=\"{subdocuments}\" />\n</PageLayout>\n{/if}\n```\n\n```html filename=\"YourPage.vue\" renderer=\"vue\" language=\"js\"\n<template>\n  <div v-if=\"!loading && data && data.subdocuments.length\">\n    <PageLayout :user=\"data.user\">\n      <DocumentHeader :document=\"data.document\" />\n      <DocumentList :documents=\"data.subdocuments\" />\n    </PageLayout>\n  </div>\n  <p v-if=\"loading\">Loading...</p>\n  <p v-if=\"error\">There was an error fetching the data!</p>\n</template>\n<script>\n  import { ref } from 'vue';\n\n  import PageLayout from './PageLayout';\n  import DocumentHeader from './DocumentHeader';\n  import DocumentList from './DocumentList';\n\n  export default {\n    name: 'DocumentScreen',\n    setup() {\n      const data = ref(null);\n      const loading = ref(true);\n      const error = ref(null);\n      fetch('https://your-restful-endpoint')\n        .then((res) => {\n          if (!res.ok) {\n            error.value = res.statusText;\n          }\n          return res;\n        })\n        .then((res) => res.json())\n        .then((requestData) => {\n          data.value = requestData;\n          loading.value = false;\n        })\n        .catch(() => {\n          error.value = 'error';\n        });\n      return {\n        error,\n        loading,\n        data,\n      };\n    },\n  };\n</script>\n```\n\n```html filename=\"YourPage.vue\" renderer=\"vue\" language=\"ts\"\n<template>\n  <div v-if=\"!loading && data && data.subdocuments.length\">\n    <PageLayout :user=\"data.user\">\n      <DocumentHeader :document=\"data.document\" />\n      <DocumentList :documents=\"data.subdocuments\" />\n    </PageLayout>\n  </div>\n  <p v-if=\"loading\">Loading...</p>\n  <p v-if=\"error\">There was an error fetching the data!</p>\n</template>\n<script lang=\"ts\">\n  import { defineComponent, ref } from 'vue';\n  import PageLayout from './PageLayout';\n  import DocumentHeader from './DocumentHeader';\n  import DocumentList from './DocumentList';\n\n  export default defineComponent({\n    name: 'DocumentScreen',\n    components: {\n      PageLayout,\n      DocumentHeader,\n      DocumentList,\n    },\n    setup() {\n      const data = ref(null);\n      const loading = ref(true);\n      const error = ref(null);\n      fetch('https://your-restful-endpoint')\n        .then((res) => {\n          if (!res.ok) {\n            error.value = res.statusText;\n          }\n          return res;\n        })\n        .then((res) => res.json())\n        .then((requestData) => {\n          data.value = requestData;\n          loading.value = false;\n        })\n        .catch(() => {\n          error.value = 'error';\n        });\n      return {\n        error,\n        loading,\n        data,\n      };\n    },\n  });\n</script>\n```\n\n```js filename=\"YourPage.js\" renderer=\"web-components\" language=\"js\"\nimport { LitElement, html } from 'lit-element';\n\nclass DocumentScreen extends LitElement {\n  static get properties() {\n    return {\n      _data: { type: Object },\n      _status: { state: true },\n    };\n  }\n\n  constructor() {\n    super();\n    this._status = 'idle';\n  }\n\n  connectedCallback() {\n    super.connectedCallback();\n    this.fetchData();\n  }\n\n  fetchData() {\n    this._status = 'loading';\n\n    fetch('https://your-restful-endpoint')\n      .then((response) => {\n        if (!response.ok) {\n          throw new Error('Network response was not ok');\n        }\n        return response.json();\n      })\n      .then((data) => {\n        this._status = 'success';\n        this._data = data;\n      })\n      .catch((error) => {\n        this._status = 'error';\n      });\n  }\n\n  render() {\n    if (this._status === 'error') {\n      return html`<p>There was an error fetching the data!</p>`;\n    }\n\n    if (this._status === 'loading') {\n      return html`<p>Loading...</p>`;\n    }\n\n    const { user, document, subdocuments } = this._data;\n    return html`\n      <demo-page-layout .user=${user}>\n        <demo-document-header .document=${document}></demo-document-header>\n        <demo-document-list .documents=${subdocuments}></demo-document-list>\n      </demo-page-layout>\n    `;\n  }\n}\n\ncustomElements.define('demo-document-screen', DocumentScreen);\n```\n"
  },
  {
    "path": "docs/_snippets/document-screen-with-graphql.md",
    "content": "```ts filename=\"your-page.component.ts\" renderer=\"angular\" language=\"ts\"\nimport { Component, OnInit } from '@angular/core';\nimport { Apollo } from 'apollo-angular';\nimport gql from 'graphql-tag';\n\n@Component({\n  selector: 'document-screen',\n  template: `\n    <div *ngIf=\"loading\">Loading...</div>\n    <div *ngIf=\"error\">There was an error fetching the data!</div>\n    <div *ngIf=\"!loading && subdocuments.length > 0\">\n      <page-layout [user]=\"user\">\n        <document-header [document]=\"document\"></document-header>\n        <document-list [documents]=\"subdocuments\"></document-list>\n      </page-layout>\n    </div>\n  `,\n})\nexport class SampleGraphqlComponent implements OnInit {\n  user: any = { id: 0, name: 'Some User' };\n\n  document: any = { id: 0, title: 'Some Title' };\n\n  subdocuments: any = [];\n\n  error = '';\n  loading = true;\n\n  constructor(private apollo: Apollo) {}\n  ngOnInit() {\n    this.apollo\n      .watchQuery({\n        query: gql`\n          query AllInfoQuery {\n            user {\n              userID\n              name\n            }\n            document {\n              id\n              userID\n              title\n              brief\n              status\n            }\n            subdocuments {\n              id\n              userID\n              title\n              content\n              status\n            }\n          }\n        `,\n      })\n      .valueChanges.subscribe((result: any) => {\n        this.user = result?.data?.user;\n        this.document = result?.data?.document;\n        this.subdocuments = result?.data?.subdocuments;\n        this.loading = result.loading;\n\n        // Errors is an array and we're getting the first item only\n        this.error = result.errors[0].message;\n      });\n  }\n}\n```\n\n```js filename=\"YourPage.jsx\" renderer=\"react\" language=\"js\"\nimport { useQuery, gql } from '@apollo/client';\n\nimport { PageLayout } from './PageLayout';\nimport { DocumentHeader } from './DocumentHeader';\nimport { DocumentList } from './DocumentList';\n\nconst AllInfoQuery = gql`\n  query AllInfo {\n    user {\n      userID\n      name\n    }\n    document {\n      id\n      userID\n      title\n      brief\n      status\n    }\n    subdocuments {\n      id\n      userID\n      title\n      content\n      status\n    }\n  }\n`;\n\nfunction useFetchInfo() {\n  const { loading, error, data } = useQuery(AllInfoQuery);\n\n  return { loading, error, data };\n}\n\nexport function DocumentScreen() {\n  const { loading, error, data } = useFetchInfo();\n\n  if (loading) {\n    return <p>Loading...</p>;\n  }\n\n  if (error) {\n    return <p>There was an error fetching the data!</p>;\n  }\n\n  return (\n    <PageLayout user={data.user}>\n      <DocumentHeader document={data.document} />\n      <DocumentList documents={data.subdocuments} />\n    </PageLayout>\n  );\n}\n```\n\n```ts filename=\"YourPage.tsx\" renderer=\"react\" language=\"ts\"\nimport { useQuery, gql } from '@apollo/client';\n\nimport { PageLayout } from './PageLayout';\nimport { DocumentHeader } from './DocumentHeader';\nimport { DocumentList } from './DocumentList';\n\nconst AllInfoQuery = gql`\n  query AllInfo {\n    user {\n      userID\n      name\n    }\n    document {\n      id\n      userID\n      title\n      brief\n      status\n    }\n    subdocuments {\n      id\n      userID\n      title\n      content\n      status\n    }\n  }\n`;\n\ninterface Data {\n  allInfo: {\n    user: {\n      userID: number;\n      name: string;\n      opening_crawl: boolean;\n    };\n    document: {\n      id: number;\n      userID: number;\n      title: string;\n      brief: string;\n      status: string;\n    };\n    subdocuments: {\n      id: number;\n      userID: number;\n      title: string;\n      content: string;\n      status: string;\n    };\n  };\n}\n\nfunction useFetchInfo() {\n  const { loading, error, data } = useQuery<Data>(AllInfoQuery);\n\n  return { loading, error, data };\n}\n\nexport function DocumentScreen() {\n  const { loading, error, data } = useFetchInfo();\n\n  if (loading) {\n    return <p>Loading...</p>;\n  }\n\n  if (error) {\n    return <p>There was an error fetching the data!</p>;\n  }\n\n  return (\n    <PageLayout user={data.user}>\n      <DocumentHeader document={data.document} />\n      <DocumentList documents={data.subdocuments} />\n    </PageLayout>\n  );\n}\n```\n\n```js filename=\"YourPage.jsx\" renderer=\"solid\" language=\"js\"\nimport { Match, Switch } from 'solid-js';\nimport { createGraphQLClient, gql } from '@solid-primitives/graphql';\n\nimport { PageLayout } from './PageLayout';\nimport { DocumentHeader } from './DocumentHeader';\nimport { DocumentList } from './DocumentList';\n\nconst newQuery = createGraphQLClient('https://foobar.com/v1/api');\nconst AllInfoQuery = gql`\n  query AllInfo {\n    user {\n      userID\n      name\n    }\n    document {\n      id\n      userID\n      title\n      brief\n      status\n    }\n    subdocuments {\n      id\n      userID\n      title\n      content\n      status\n    }\n  }\n`;\n\nfunction useFetchInfo() {\n  const [data] = newQuery(AllInfoQuery, { path: 'home' });\n  return data;\n}\n\nexport function DocumentScreen() {\n  const data = useFetchInfo();\n\n  return (\n    <Switch>\n      <Match when={data.loading}>\n        <p>Loading...</p>\n      </Match>\n      <Match when={data.error}>\n        <p>There was an error fetching the data!</p>\n      </Match>\n      <Match when={data()} keyed>\n        {(data) => (\n          <PageLayout user={data.user}>\n            <DocumentHeader document={data.document} />\n            <DocumentList documents={data.subdocuments} />\n          </PageLayout>\n        )}\n      </Match>\n    </Switch>\n  );\n}\n```\n\n```ts filename=\"YourPage.tsx\" renderer=\"solid\" language=\"ts\"\nimport { createGraphQLClient, gql } from '@solid-primitives/graphql';\n\nimport { PageLayout } from './PageLayout';\nimport { DocumentHeader } from './DocumentHeader';\nimport { DocumentList } from './DocumentList';\n\nconst newQuery = createGraphQLClient('https://foobar.com/v1/api');\nconst AllInfoQuery = gql`\n  query AllInfo {\n    user {\n      userID\n      name\n    }\n    document {\n      id\n      userID\n      title\n      brief\n      status\n    }\n    subdocuments {\n      id\n      userID\n      title\n      content\n      status\n    }\n  }\n`;\n\ninterface Data {\n  allInfo: {\n    user: {\n      userID: number;\n      name: string;\n      opening_crawl: boolean;\n    };\n    document: {\n      id: number;\n      userID: number;\n      title: string;\n      brief: string;\n      status: string;\n    };\n    subdocuments: {\n      id: number;\n      userID: number;\n      title: string;\n      content: string;\n      status: string;\n    };\n  };\n}\n\nfunction useFetchInfo() {\n  const [data] = newQuery<Data>(AllInfoQuery, { path: 'home' });\n  return data;\n}\n\nexport function DocumentScreen() {\n  const data = useFetchInfo();\n\n  return (\n    <Switch>\n      <Match when={data.loading}>\n        <p>Loading...</p>\n      </Match>\n      <Match when={data.error}>\n        <p>There was an error fetching the data!</p>\n      </Match>\n      <Match when={data()} keyed>\n        {(data) => (\n          <PageLayout user={data.user}>\n            <DocumentHeader document={data.document} />\n            <DocumentList documents={data.subdocuments} />\n          </PageLayout>\n        )}\n      </Match>\n    </Switch>\n  );\n}\n```\n\n```html filename=\"YourPage.vue\" renderer=\"vue\" language=\"js\"\n<template>\n  <div v-if=\"loading\">Loading...</div>\n\n  <div v-else-if=\"error\">There was an error fetching the data!</div>\n\n  <div v-if=\"!loading && data && result.subdocuments.length\">\n    <PageLayout :user=\"data.user\">\n      <DocumentHeader :document=\"result.document\" />\n      <DocumentList :documents=\"result.subdocuments\" />\n    </PageLayout>\n  </div>\n</template>\n\n<script>\n  import PageLayout from './PageLayout';\n  import DocumentHeader from './DocumentHeader';\n  import DocumentList from './DocumentList';\n\n  import gql from 'graphql-tag';\n  import { useQuery } from '@vue/apollo-composable';\n\n  export default {\n    name: 'DocumentScreen',\n    setup() {\n      const { result, loading, error } = useQuery(gql`\n        query AllInfoQuery {\n          user {\n            userID\n            name\n          }\n          document {\n            id\n            userID\n            title\n            brief\n            status\n          }\n          subdocuments {\n            id\n            userID\n            title\n            content\n            status\n          }\n        }\n      `);\n      return {\n        result,\n        loading,\n        error,\n      };\n    },\n  };\n</script>\n```\n\n```html filename=\"YourPage.vue\" renderer=\"vue\" language=\"ts\"\n<template>\n  <div v-if=\"loading\">Loading...</div>\n\n  <div v-else-if=\"error\">There was an error fetching the data!</div>\n\n  <div v-if=\"!loading && data && result.subdocuments.length\">\n    <PageLayout :user=\"data.user\">\n      <DocumentHeader :document=\"result.document\" />\n      <DocumentList :documents=\"result.subdocuments\" />\n    </PageLayout>\n  </div>\n</template>\n\n<script lang=\"ts\">\n  import PageLayout from './PageLayout';\n  import DocumentHeader from './DocumentHeader';\n  import DocumentList from './DocumentList';\n\n  import gql from 'graphql-tag';\n  import { useQuery } from '@vue/apollo-composable';\n  import { defineComponent } from 'vue';\n\n  export default defineComponent({\n    name: 'DocumentScreen',\n    setup() {\n      const { result, loading, error } = useQuery(gql`\n        query AllInfoQuery {\n          user {\n            userID\n            name\n          }\n          document {\n            id\n            userID\n            title\n            brief\n            status\n          }\n          subdocuments {\n            id\n            userID\n            title\n            content\n            status\n          }\n        }\n      `);\n\n      return {\n        result,\n        loading,\n        error,\n      };\n    },\n  });\n</script>\n```\n\n```svelte filename=\"YourPage.svelte\" renderer=\"svelte\" language=\"js\"\n<script>\n  import { queryStore, gql, getContextClient } from '@urql/svelte';\n\n  import PageLayout from './PageLayout.svelte';\n  import DocumentHeader from './DocumentHeader.svelte';\n  import DocumentList from './DocumentList.svelte';\n\n  const AllInfoQuery = queryStore({\n    client: getContextClient(),\n    query: gql`\n      query AllInfoQuery {\n        user {\n          userID\n          name\n        }\n        document {\n          id\n          userID\n          title\n          brief\n          status\n        }\n        subdocuments {\n          id\n          userID\n          title\n          content\n          status\n        }\n      }\n    `,\n  });\n</script>\n\n{#if $AllInfoQuery.fetching}\n<p>Loading...</p>\n{:else if $AllInfoQuery.error}\n<p>There was an error fetching the data!</p>\n{:else}\n<PageLayout user={$AllInfoQuery.data.AllInfoQuery.user}>\n  <DocumentHeader document={$AllInfoQuery.data.AllInfoQuery.document} />\n  <DocumentList documents={$AllInfoQuery.data.AllInfoQuery.subdocuments} />\n</PageLayout>\n{/if}\n```\n\n```svelte filename=\"YourPage.svelte\" renderer=\"svelte\" language=\"ts\"\n<script lang=\"ts\">\n  import { queryStore, gql, getContextClient } from '@urql/svelte';\n\n  import PageLayout from './PageLayout.svelte';\n  import DocumentHeader from './DocumentHeader.svelte';\n  import DocumentList from './DocumentList.svelte';\n\n  const AllInfoQuery = queryStore({\n    client: getContextClient(),\n    query: gql`\n      query AllInfoQuery {\n        user {\n          userID\n          name\n        }\n        document {\n          id\n          userID\n          title\n          brief\n          status\n        }\n        subdocuments {\n          id\n          userID\n          title\n          content\n          status\n        }\n      }\n    `,\n  });\n</script>\n\n{#if $AllInfoQuery.fetching}\n<p>Loading...</p>\n{:else if $AllInfoQuery.error}\n<p>There was an error fetching the data!</p>\n{:else}\n<PageLayout user={$AllInfoQuery.data.AllInfoQuery.user}>\n  <DocumentHeader document={$AllInfoQuery.data.AllInfoQuery.document} />\n  <DocumentList documents={$AllInfoQuery.data.AllInfoQuery.subdocuments} />\n</PageLayout>\n{/if}\n```\n"
  },
  {
    "path": "docs/_snippets/eslint-install.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm install --save-dev eslint\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm add --save-dev eslint\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn add --dev eslint\n```\n"
  },
  {
    "path": "docs/_snippets/eslint-plugin-storybook-install.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm install --save-dev eslint-plugin-storybook\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm add --save-dev eslint-plugin-storybook\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn add --dev eslint-plugin-storybook\n```\n"
  },
  {
    "path": "docs/_snippets/essential-feature-disable.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    backgrounds: false, // 👈 disable the backgrounds feature\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    backgrounds: false, // 👈 disable the backgrounds feature\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    backgrounds: false, // 👈 disable the backgrounds feature\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    backgrounds: false, // 👈 disable the backgrounds feature\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    backgrounds: false, // 👈 disable the backgrounds feature\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    backgrounds: false, // 👈 disable the backgrounds feature\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    backgrounds: false, // 👈 disable the backgrounds feature\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    backgrounds: false, // 👈 disable the backgrounds feature\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    backgrounds: false, // 👈 disable the backgrounds feature\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/foo-bar-baz-story.md",
    "content": "```ts filename=\"FooBar.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Foo } from './foo.component';\n\nconst meta: Meta<Foo> = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Foo/Bar',\n  component: Foo,\n};\n\nexport default meta;\ntype Story = StoryObj<Foo>;\n\nexport const Baz: Story = {};\n```\n\n```ts filename=\"FooBar.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Foo } from './foo.component';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Foo/Bar',\n  component: Foo,\n});\n\nexport const Baz = meta.story();\n```\n\n```svelte filename=\"FooBar.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Foo from './Foo.svelte';\n\n  const { Story } = defineMeta({\n    /* 👇 The title prop is optional.\n     * See https://storybook.js.org/docs/configure/#configure-story-loading\n     * to learn how to generate automatic titles\n     */\n    title: 'Foo/Bar',\n    component: Foo,\n  });\n</script>\n\n<Story name=\"Baz\" />\n```\n\n```js filename=\"FooBar.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Foo from './Foo.svelte';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Foo/Bar',\n  component: Foo,\n};\n\nexport const Baz = {};\n```\n\n```js filename=\"FooBar.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Foo } from './Foo';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Foo/Bar',\n  component: Foo,\n};\n\nexport const Baz = {};\n```\n\n```svelte filename=\"FooBar.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Foo from './Foo.svelte';\n\n  const { Story } = defineMeta({\n    /* 👇 The title prop is optional.\n     * See https://storybook.js.org/docs/configure/#configure-story-loading\n     * to learn how to generate automatic titles\n     */\n    title: 'Foo/Bar',\n    component: Foo,\n  });\n</script>\n\n<Story name=\"Baz\" />\n```\n\n```ts filename=\"FooBar.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Foo from './Foo.svelte';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Foo/Bar',\n  component: Foo,\n} satisfies Meta<typeof Foo>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Baz: Story = {};\n```\n\n```ts filename=\"FooBar.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the name of your framework\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Foo } from './Foo';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Foo/Bar',\n  component: Foo,\n} satisfies Meta<typeof Foo>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Baz: Story = {};\n```\n\n```ts filename=\"FooBar.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Foo } from './Foo';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Foo/Bar',\n  component: Foo,\n});\n\nexport const Baz = meta.story();\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"FooBar.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Foo } from './Foo';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Foo/Bar',\n  component: Foo,\n});\n\nexport const Baz = meta.story();\n```\n\n```ts filename=\"FooBar.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Foo from './Foo.vue';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Foo/Bar',\n  component: Foo,\n});\n\nexport const Baz = meta.story();\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"FooBar.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Foo from './Foo.vue';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Foo/Bar',\n  component: Foo,\n});\n\nexport const Baz = meta.story();\n```\n\n```js filename=\"FooBar.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Foo/Bar',\n  component: 'demo-foo',\n};\n\nexport const Baz = {};\n```\n\n```ts filename=\"FooBar.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Foo/Bar',\n  component: 'demo-foo',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Baz: Story = {};\n```\n\n```js filename=\"FooBar.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Foo/Bar',\n  component: 'demo-foo',\n});\n\nexport const Baz = meta.story();\n```\n\n```ts filename=\"FooBar.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Foo/Bar',\n  component: 'demo-foo',\n});\n\nexport const Baz = meta.story();\n```\n"
  },
  {
    "path": "docs/_snippets/ghp-github-action.md",
    "content": "```yml filename=\".github/workflows/deploy-github-pages.yml\" renderer=\"common\" language=\"js\"\nname: Build and Publish Storybook to GitHub Pages\non:\n  push:\n    branches:\n      - 'your-branch-name' # Use specific branch name\npermissions:\n  contents: read\n  pages: write\n  id-token: write\nconcurrency:\n  group: 'pages'\n  cancel-in-progress: false\njobs:\n  deploy:\n    runs-on: ubuntu-latest\n    environment:\n      name: github-pages\n      url: ${{ steps.deploy.outputs.page_url }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n        with:\n          fetch-depth: 0\n      - name: Setup Node\n        uses: actions/setup-node@v6\n        with:\n          node-version: '24'\n          cache: 'npm' # Adjust caching strategy and configuration if using other package managers\n      - name: Install dependencies\n        run: npm ci # Replace with appropriate command if using other package managers\n      - name: Build Storybook\n        run: npm run build-storybook\n      # Upload pages artifact\n      - name: Upload Pages artifact\n        uses: actions/upload-pages-artifact@v3\n        with:\n          path: 'storybook-static'\n      # Deploy to Github Pages\n      - id: deploy\n        name: Deploy to GitHub Pages\n        uses: actions/deploy-pages@v4\n        with:\n          token: ${{ github.token }}\n```\n"
  },
  {
    "path": "docs/_snippets/gizmo-story-controls-customization.md",
    "content": "```ts filename=\"Gizmo.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Gizmo } from './gizmo.component';\n\nconst meta: Meta<Gizmo> = {\n  component: Gizmo,\n  argTypes: {\n    canRotate: {\n      control: 'boolean',\n    },\n    width: {\n      control: { type: 'number', min: 400, max: 1200, step: 50 },\n    },\n    height: {\n      control: { type: 'range', min: 200, max: 1500, step: 50 },\n    },\n    rawData: {\n      control: 'object',\n    },\n    coordinates: {\n      control: 'object',\n    },\n    texture: {\n      control: {\n        type: 'file',\n        accept: '.png',\n      },\n    },\n    position: {\n      control: 'radio',\n      options: ['left', 'right', 'center'],\n    },\n    rotationAxis: {\n      control: 'check',\n      options: ['x', 'y', 'z'],\n    },\n    scaling: {\n      control: 'select',\n      options: [10, 50, 75, 100, 200],\n    },\n    label: {\n      control: 'text',\n    },\n    meshColors: {\n      control: {\n        type: 'color',\n        presetColors: ['#ff0000', '#00ff00', '#0000ff'],\n      },\n    },\n    revisionDate: {\n      control: 'date',\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Gizmo.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Gizmo } from './gizmo.component';\n\nconst meta = preview.meta({\n  component: Gizmo,\n  argTypes: {\n    canRotate: {\n      control: 'boolean',\n    },\n    width: {\n      control: { type: 'number', min: 400, max: 1200, step: 50 },\n    },\n    height: {\n      control: { type: 'range', min: 200, max: 1500, step: 50 },\n    },\n    rawData: {\n      control: 'object',\n    },\n    coordinates: {\n      control: 'object',\n    },\n    texture: {\n      control: {\n        type: 'file',\n        accept: '.png',\n      },\n    },\n    position: {\n      control: 'radio',\n      options: ['left', 'right', 'center'],\n    },\n    rotationAxis: {\n      control: 'check',\n      options: ['x', 'y', 'z'],\n    },\n    scaling: {\n      control: 'select',\n      options: [10, 50, 75, 100, 200],\n    },\n    label: {\n      control: 'text',\n    },\n    meshColors: {\n      control: {\n        type: 'color',\n        presetColors: ['#ff0000', '#00ff00', '#0000ff'],\n      },\n    },\n    revisionDate: {\n      control: 'date',\n    },\n  },\n});\n```\n\n```svelte filename=\"Gizmo.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Gizmo from './Gizmo.svelte';\n\n  const { Story } = defineMeta({\n    component: Gizmo,\n    argTypes: {\n      canRotate: {\n        control: 'boolean',\n      },\n      width: {\n        control: { type: 'number', min: 400, max: 1200, step: 50 },\n      },\n      height: {\n        control: { type: 'range', min: 200, max: 1500, step: 50 },\n      },\n      rawData: {\n        control: 'object',\n      },\n      coordinates: {\n        control: 'object',\n      },\n      texture: {\n        control: {\n          type: 'file',\n          accept: '.png',\n        },\n      },\n      position: {\n        control: 'radio',\n        options: ['left', 'right', 'center'],\n      },\n      rotationAxis: {\n        control: 'check',\n        options: ['x', 'y', 'z'],\n      },\n      scaling: {\n        control: 'select',\n        options: [10, 50, 75, 100, 200],\n      },\n      label: {\n        control: 'text',\n      },\n      meshColors: {\n        control: {\n          type: 'color',\n          presetColors: ['#ff0000', '#00ff00', '#0000ff'],\n        },\n      },\n      revisionDate: {\n        control: 'date',\n      },\n    },\n  });\n</script>\n```\n\n```js filename=\"Gizmo.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Gizmo from './Gizmo.svelte';\n\nexport default {\n  component: Gizmo,\n  argTypes: {\n    canRotate: {\n      control: 'boolean',\n    },\n    width: {\n      control: { type: 'number', min: 400, max: 1200, step: 50 },\n    },\n    height: {\n      control: { type: 'range', min: 200, max: 1500, step: 50 },\n    },\n    rawData: {\n      control: 'object',\n    },\n    coordinates: {\n      control: 'object',\n    },\n    texture: {\n      control: {\n        type: 'file',\n        accept: '.png',\n      },\n    },\n    position: {\n      control: 'radio',\n      options: ['left', 'right', 'center'],\n    },\n    rotationAxis: {\n      control: 'check',\n      options: ['x', 'y', 'z'],\n    },\n    scaling: {\n      control: 'select',\n      options: [10, 50, 75, 100, 200],\n    },\n    label: {\n      control: 'text',\n    },\n    meshColors: {\n      control: {\n        type: 'color',\n        presetColors: ['#ff0000', '#00ff00', '#0000ff'],\n      },\n    },\n    revisionDate: {\n      control: 'date',\n    },\n  },\n};\n```\n\n```js filename=\"Gizmo.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Gizmo } from './Gizmo';\n\nexport default {\n  component: Gizmo,\n  argTypes: {\n    canRotate: {\n      control: 'boolean',\n    },\n    width: {\n      control: { type: 'number', min: 400, max: 1200, step: 50 },\n    },\n    height: {\n      control: { type: 'range', min: 200, max: 1500, step: 50 },\n    },\n    rawData: {\n      control: 'object',\n    },\n    coordinates: {\n      control: 'object',\n    },\n    texture: {\n      control: {\n        type: 'file',\n        accept: '.png',\n      },\n    },\n    position: {\n      control: 'radio',\n      options: ['left', 'right', 'center'],\n    },\n    rotationAxis: {\n      control: 'check',\n      options: ['x', 'y', 'z'],\n    },\n    scaling: {\n      control: 'select',\n      options: [10, 50, 75, 100, 200],\n    },\n    label: {\n      control: 'text',\n    },\n    meshColors: {\n      control: {\n        type: 'color',\n        presetColors: ['#ff0000', '#00ff00', '#0000ff'],\n      },\n    },\n    revisionDate: {\n      control: 'date',\n    },\n  },\n};\n```\n\n```svelte filename=\"Gizmo.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Gizmo from './Gizmo.svelte';\n\n  const { Story } = defineMeta({\n    component: Gizmo,\n    argTypes: {\n      canRotate: {\n        control: 'boolean',\n      },\n      width: {\n        control: { type: 'number', min: 400, max: 1200, step: 50 },\n      },\n      height: {\n        control: { type: 'range', min: 200, max: 1500, step: 50 },\n      },\n      rawData: {\n        control: 'object',\n      },\n      coordinates: {\n        control: 'object',\n      },\n      texture: {\n        control: {\n          type: 'file',\n          accept: '.png',\n        },\n      },\n      position: {\n        control: 'radio',\n        options: ['left', 'right', 'center'],\n      },\n      rotationAxis: {\n        control: 'check',\n        options: ['x', 'y', 'z'],\n      },\n      scaling: {\n        control: 'select',\n        options: [10, 50, 75, 100, 200],\n      },\n      label: {\n        control: 'text',\n      },\n      meshColors: {\n        control: {\n          type: 'color',\n          presetColors: ['#ff0000', '#00ff00', '#0000ff'],\n        },\n      },\n      revisionDate: {\n        control: 'date',\n      },\n    },\n  });\n</script>\n```\n\n```ts filename=\"Gizmo.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Gizmo from './Gizmo.svelte';\n\nconst meta = {\n  component: Gizmo,\n  argTypes: {\n    canRotate: {\n      control: 'boolean',\n    },\n    width: {\n      control: { type: 'number', min: 400, max: 1200, step: 50 },\n    },\n    height: {\n      control: { type: 'range', min: 200, max: 1500, step: 50 },\n    },\n    rawData: {\n      control: 'object',\n    },\n    coordinates: {\n      control: 'object',\n    },\n    texture: {\n      control: {\n        type: 'file',\n        accept: '.png',\n      },\n    },\n    position: {\n      control: 'radio',\n      options: ['left', 'right', 'center'],\n    },\n    rotationAxis: {\n      control: 'check',\n      options: ['x', 'y', 'z'],\n    },\n    scaling: {\n      control: 'select',\n      options: [10, 50, 75, 100, 200],\n    },\n    label: {\n      control: 'text',\n    },\n    meshColors: {\n      control: {\n        type: 'color',\n        presetColors: ['#ff0000', '#00ff00', '#0000ff'],\n      },\n    },\n    revisionDate: {\n      control: 'date',\n    },\n  },\n} satisfies Meta<typeof Gizmo>;\n\nexport default meta;\n```\n\n```ts filename=\"Gizmo.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Gizmo } from './Gizmo';\n\nconst meta = {\n  component: Gizmo,\n  argTypes: {\n    canRotate: {\n      control: 'boolean',\n    },\n    width: {\n      control: { type: 'number', min: 400, max: 1200, step: 50 },\n    },\n    height: {\n      control: { type: 'range', min: 200, max: 1500, step: 50 },\n    },\n    rawData: {\n      control: 'object',\n    },\n    coordinates: {\n      control: 'object',\n    },\n    texture: {\n      control: {\n        type: 'file',\n        accept: '.png',\n      },\n    },\n    position: {\n      control: 'radio',\n      options: ['left', 'right', 'center'],\n    },\n    rotationAxis: {\n      control: 'check',\n      options: ['x', 'y', 'z'],\n    },\n    scaling: {\n      control: 'select',\n      options: [10, 50, 75, 100, 200],\n    },\n    label: {\n      control: 'text',\n    },\n    meshColors: {\n      control: {\n        type: 'color',\n        presetColors: ['#ff0000', '#00ff00', '#0000ff'],\n      },\n    },\n    revisionDate: {\n      control: 'date',\n    },\n  },\n} satisfies Meta<typeof Gizmo>;\n\nexport default meta;\n```\n\n```js filename=\"Gizmo.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'gizmo-element',\n  argTypes: {\n    canRotate: {\n      control: 'boolean',\n    },\n    width: {\n      control: { type: 'number', min: 400, max: 1200, step: 50 },\n    },\n    height: {\n      control: { type: 'range', min: 200, max: 1500, step: 50 },\n    },\n    rawData: {\n      control: 'object',\n    },\n    coordinates: {\n      control: 'object',\n    },\n    texture: {\n      control: {\n        type: 'file',\n        accept: '.png',\n      },\n    },\n    position: {\n      control: 'radio',\n      options: ['left', 'right', 'center'],\n    },\n    rotationAxis: {\n      control: 'check',\n      options: ['x', 'y', 'z'],\n    },\n    scaling: {\n      control: 'select',\n      options: [10, 50, 75, 100, 200],\n    },\n    label: {\n      control: 'text',\n    },\n    meshColors: {\n      control: {\n        type: 'color',\n        presetColors: ['#ff0000', '#00ff00', '#0000ff'],\n      },\n    },\n    revisionDate: {\n      control: 'date',\n    },\n  },\n};\n```\n\n```ts filename=\"Gizmo.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'gizmo-element',\n  argTypes: {\n    canRotate: {\n      control: 'boolean',\n    },\n    width: {\n      control: { type: 'number', min: 400, max: 1200, step: 50 },\n    },\n    height: {\n      control: { type: 'range', min: 200, max: 1500, step: 50 },\n    },\n    rawData: {\n      control: 'object',\n    },\n    coordinates: {\n      control: 'object',\n    },\n    texture: {\n      control: {\n        type: 'file',\n        accept: '.png',\n      },\n    },\n    position: {\n      control: 'radio',\n      options: ['left', 'right', 'center'],\n    },\n    rotationAxis: {\n      control: 'check',\n      options: ['x', 'y', 'z'],\n    },\n    scaling: {\n      control: 'select',\n      options: [10, 50, 75, 100, 200],\n    },\n    label: {\n      control: 'text',\n    },\n    meshColors: {\n      control: {\n        type: 'color',\n        presetColors: ['#ff0000', '#00ff00', '#0000ff'],\n      },\n    },\n    revisionDate: {\n      control: 'date',\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Gizmo.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'gizmo-element',\n  argTypes: {\n    canRotate: {\n      control: 'boolean',\n    },\n    width: {\n      control: { type: 'number', min: 400, max: 1200, step: 50 },\n    },\n    height: {\n      control: { type: 'range', min: 200, max: 1500, step: 50 },\n    },\n    rawData: {\n      control: 'object',\n    },\n    coordinates: {\n      control: 'object',\n    },\n    texture: {\n      control: {\n        type: 'file',\n        accept: '.png',\n      },\n    },\n    position: {\n      control: 'radio',\n      options: ['left', 'right', 'center'],\n    },\n    rotationAxis: {\n      control: 'check',\n      options: ['x', 'y', 'z'],\n    },\n    scaling: {\n      control: 'select',\n      options: [10, 50, 75, 100, 200],\n    },\n    label: {\n      control: 'text',\n    },\n    meshColors: {\n      control: {\n        type: 'color',\n        presetColors: ['#ff0000', '#00ff00', '#0000ff'],\n      },\n    },\n    revisionDate: {\n      control: 'date',\n    },\n  },\n});\n```\n\n```ts filename=\"Gizmo.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'gizmo-element',\n  argTypes: {\n    canRotate: {\n      control: 'boolean',\n    },\n    width: {\n      control: { type: 'number', min: 400, max: 1200, step: 50 },\n    },\n    height: {\n      control: { type: 'range', min: 200, max: 1500, step: 50 },\n    },\n    rawData: {\n      control: 'object',\n    },\n    coordinates: {\n      control: 'object',\n    },\n    texture: {\n      control: {\n        type: 'file',\n        accept: '.png',\n      },\n    },\n    position: {\n      control: 'radio',\n      options: ['left', 'right', 'center'],\n    },\n    rotationAxis: {\n      control: 'check',\n      options: ['x', 'y', 'z'],\n    },\n    scaling: {\n      control: 'select',\n      options: [10, 50, 75, 100, 200],\n    },\n    label: {\n      control: 'text',\n    },\n    meshColors: {\n      control: {\n        type: 'color',\n        presetColors: ['#ff0000', '#00ff00', '#0000ff'],\n      },\n    },\n    revisionDate: {\n      control: 'date',\n    },\n  },\n});\n```\n\n```ts filename=\"Gizmo.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Gizmo } from './Gizmo';\n\nconst meta = preview.meta({\n  component: Gizmo,\n  argTypes: {\n    canRotate: {\n      control: 'boolean',\n    },\n    width: {\n      control: { type: 'number', min: 400, max: 1200, step: 50 },\n    },\n    height: {\n      control: { type: 'range', min: 200, max: 1500, step: 50 },\n    },\n    rawData: {\n      control: 'object',\n    },\n    coordinates: {\n      control: 'object',\n    },\n    texture: {\n      control: {\n        type: 'file',\n        accept: '.png',\n      },\n    },\n    position: {\n      control: 'radio',\n      options: ['left', 'right', 'center'],\n    },\n    rotationAxis: {\n      control: 'check',\n      options: ['x', 'y', 'z'],\n    },\n    scaling: {\n      control: 'select',\n      options: [10, 50, 75, 100, 200],\n    },\n    label: {\n      control: 'text',\n    },\n    meshColors: {\n      control: {\n        type: 'color',\n        presetColors: ['#ff0000', '#00ff00', '#0000ff'],\n      },\n    },\n    revisionDate: {\n      control: 'date',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Gizmo.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Gizmo } from './Gizmo';\n\nconst meta = preview.meta({\n  component: Gizmo,\n  argTypes: {\n    canRotate: {\n      control: 'boolean',\n    },\n    width: {\n      control: { type: 'number', min: 400, max: 1200, step: 50 },\n    },\n    height: {\n      control: { type: 'range', min: 200, max: 1500, step: 50 },\n    },\n    rawData: {\n      control: 'object',\n    },\n    coordinates: {\n      control: 'object',\n    },\n    texture: {\n      control: {\n        type: 'file',\n        accept: '.png',\n      },\n    },\n    position: {\n      control: 'radio',\n      options: ['left', 'right', 'center'],\n    },\n    rotationAxis: {\n      control: 'check',\n      options: ['x', 'y', 'z'],\n    },\n    scaling: {\n      control: 'select',\n      options: [10, 50, 75, 100, 200],\n    },\n    label: {\n      control: 'text',\n    },\n    meshColors: {\n      control: {\n        type: 'color',\n        presetColors: ['#ff0000', '#00ff00', '#0000ff'],\n      },\n    },\n    revisionDate: {\n      control: 'date',\n    },\n  },\n});\n```\n\n```ts filename=\"Gizmo.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Gizmo from './Gizmo.vue';\n\nconst meta = preview.meta({\n  component: Gizmo,\n  argTypes: {\n    canRotate: {\n      control: 'boolean',\n    },\n    width: {\n      control: { type: 'number', min: 400, max: 1200, step: 50 },\n    },\n    height: {\n      control: { type: 'range', min: 200, max: 1500, step: 50 },\n    },\n    rawData: {\n      control: 'object',\n    },\n    coordinates: {\n      control: 'object',\n    },\n    texture: {\n      control: {\n        type: 'file',\n        accept: '.png',\n      },\n    },\n    position: {\n      control: 'radio',\n      options: ['left', 'right', 'center'],\n    },\n    rotationAxis: {\n      control: 'check',\n      options: ['x', 'y', 'z'],\n    },\n    scaling: {\n      control: 'select',\n      options: [10, 50, 75, 100, 200],\n    },\n    label: {\n      control: 'text',\n    },\n    meshColors: {\n      control: {\n        type: 'color',\n        presetColors: ['#ff0000', '#00ff00', '#0000ff'],\n      },\n    },\n    revisionDate: {\n      control: 'date',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Gizmo.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Gizmo from './Gizmo.vue';\n\nconst meta = preview.meta({\n  component: Gizmo,\n  argTypes: {\n    canRotate: {\n      control: 'boolean',\n    },\n    width: {\n      control: { type: 'number', min: 400, max: 1200, step: 50 },\n    },\n    height: {\n      control: { type: 'range', min: 200, max: 1500, step: 50 },\n    },\n    rawData: {\n      control: 'object',\n    },\n    coordinates: {\n      control: 'object',\n    },\n    texture: {\n      control: {\n        type: 'file',\n        accept: '.png',\n      },\n    },\n    position: {\n      control: 'radio',\n      options: ['left', 'right', 'center'],\n    },\n    rotationAxis: {\n      control: 'check',\n      options: ['x', 'y', 'z'],\n    },\n    scaling: {\n      control: 'select',\n      options: [10, 50, 75, 100, 200],\n    },\n    label: {\n      control: 'text',\n    },\n    meshColors: {\n      control: {\n        type: 'color',\n        presetColors: ['#ff0000', '#00ff00', '#0000ff'],\n      },\n    },\n    revisionDate: {\n      control: 'date',\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/highlight-custom-style.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, type StoryObj, componentWrapperDecorator } from '@storybook/angular';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n};\n\nexport default meta;\ntype Story = StoryObj<MyComponent>;\n\nexport const StyledHighlight: Story = {\n  decorators: [\n    componentWrapperDecorator((story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        styles: {\n          backgroundColor: `color-mix(in srgb, hotpink, transparent 90%)`,\n          outline: '3px solid hotpink',\n          animation: 'pulse 3s linear infinite',\n          transition: 'outline-offset 0.2s ease-in-out',\n        },\n        hoverStyles: {\n          outlineOffset: '3px',\n        },\n        focusStyles: {\n          backgroundColor: 'transparent',\n        },\n        keyframes: `@keyframes pulse {\n          0% { outline-color: rgba(255, 105, 180, 1); }\n          50% { outline-color: rgba(255, 105, 180, 0.2); }\n          100% { outline-color: rgba(255, 105, 180, 1); }\n        }`,\n      });\n      return story;\n    }),\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { componentWrapperDecorator } from '@storybook/angular';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const StyledHighlight = meta.story({\n  decorators: [\n    componentWrapperDecorator((story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        styles: {\n          backgroundColor: `color-mix(in srgb, hotpink, transparent 90%)`,\n          outline: '3px solid hotpink',\n          animation: 'pulse 3s linear infinite',\n          transition: 'outline-offset 0.2s ease-in-out',\n        },\n        hoverStyles: {\n          outlineOffset: '3px',\n        },\n        focusStyles: {\n          backgroundColor: 'transparent',\n        },\n        keyframes: `@keyframes pulse {\n          0% { outline-color: rgba(255, 105, 180, 1); }\n          50% { outline-color: rgba(255, 105, 180, 0.2); }\n          100% { outline-color: rgba(255, 105, 180, 1); }\n        }`,\n      });\n      return story;\n    }),\n  ],\n});\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const StyledHighlight = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        styles: {\n          backgroundColor: `color-mix(in srgb, hotpink, transparent 90%)`,\n          outline: '3px solid hotpink',\n          animation: 'pulse 3s linear infinite',\n          transition: 'outline-offset 0.2s ease-in-out',\n        },\n        hoverStyles: {\n          outlineOffset: '3px',\n        },\n        focusStyles: {\n          backgroundColor: 'transparent',\n        },\n        keyframes: `@keyframes pulse {\n          0% { outline-color: rgba(255, 105, 180, 1); }\n          50% { outline-color: rgba(255, 105, 180, 0.2); }\n          100% { outline-color: rgba(255, 105, 180, 1); }\n        }`,\n      });\n      return storyFn();\n    },\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const StyledHighlight: Story = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        styles: {\n          backgroundColor: `color-mix(in srgb, hotpink, transparent 90%)`,\n          outline: '3px solid hotpink',\n          animation: 'pulse 3s linear infinite',\n          transition: 'outline-offset 0.2s ease-in-out',\n        },\n        hoverStyles: {\n          outlineOffset: '3px',\n        },\n        focusStyles: {\n          backgroundColor: 'transparent',\n        },\n        keyframes: `@keyframes pulse {\n          0% { outline-color: rgba(255, 105, 180, 1); }\n          50% { outline-color: rgba(255, 105, 180, 0.2); }\n          100% { outline-color: rgba(255, 105, 180, 1); }\n        }`,\n      });\n      return storyFn();\n    },\n  ],\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { useChannel } from 'storybook/preview-api';\n  import { HIGHLIGHT } from 'storybook/highlight';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"StyledHighlight\"\n  decorators={[\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        styles: {\n          backgroundColor: `color-mix(in srgb, hotpink, transparent 90%)`,\n          outline: '3px solid hotpink',\n          animation: 'pulse 3s linear infinite',\n          transition: 'outline-offset 0.2s ease-in-out',\n        },\n        hoverStyles: {\n          outlineOffset: '3px',\n        },\n        focusStyles: {\n          backgroundColor: 'transparent',\n        },\n        keyframes: `@keyframes pulse {\n          0% { outline-color: rgba(255, 105, 180, 1); }\n          50% { outline-color: rgba(255, 105, 180, 0.2); }\n          100% { outline-color: rgba(255, 105, 180, 1); }\n        }`,\n      });\n      return storyFn();\n    },\n  ]}\n/>\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.svelte';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const StyledHighlight = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        styles: {\n          backgroundColor: `color-mix(in srgb, hotpink, transparent 90%)`,\n          outline: '3px solid hotpink',\n          animation: 'pulse 3s linear infinite',\n          transition: 'outline-offset 0.2s ease-in-out',\n        },\n        hoverStyles: {\n          outlineOffset: '3px',\n        },\n        focusStyles: {\n          backgroundColor: 'transparent',\n        },\n        keyframes: `@keyframes pulse {\n          0% { outline-color: rgba(255, 105, 180, 1); }\n          50% { outline-color: rgba(255, 105, 180, 0.2); }\n          100% { outline-color: rgba(255, 105, 180, 1); }\n        }`,\n      });\n      return storyFn();\n    },\n  ],\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { useChannel } from 'storybook/preview-api';\n  import { HIGHLIGHT } from 'storybook/highlight';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"StyledHighlight\"\n  decorators={[\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        styles: {\n          backgroundColor: `color-mix(in srgb, hotpink, transparent 90%)`,\n          outline: '3px solid hotpink',\n          animation: 'pulse 3s linear infinite',\n          transition: 'outline-offset 0.2s ease-in-out',\n        },\n        hoverStyles: {\n          outlineOffset: '3px',\n        },\n        focusStyles: {\n          backgroundColor: 'transparent',\n        },\n        keyframes: `@keyframes pulse {\n          0% { outline-color: rgba(255, 105, 180, 1); }\n          50% { outline-color: rgba(255, 105, 180, 0.2); }\n          100% { outline-color: rgba(255, 105, 180, 1); }\n        }`,\n      });\n      return storyFn();\n    },\n  ]}\n/>\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.svelte';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const StyledHighlight: Story = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        styles: {\n          backgroundColor: `color-mix(in srgb, hotpink, transparent 90%)`,\n          outline: '3px solid hotpink',\n          animation: 'pulse 3s linear infinite',\n          transition: 'outline-offset 0.2s ease-in-out',\n        },\n        hoverStyles: {\n          outlineOffset: '3px',\n        },\n        focusStyles: {\n          backgroundColor: 'transparent',\n        },\n        keyframes: `@keyframes pulse {\n          0% { outline-color: rgba(255, 105, 180, 1); }\n          50% { outline-color: rgba(255, 105, 180, 0.2); }\n          100% { outline-color: rgba(255, 105, 180, 1); }\n        }`,\n      });\n      return storyFn();\n    },\n  ],\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.vue';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const StyledHighlight = {\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        styles: {\n          backgroundColor: `color-mix(in srgb, hotpink, transparent 90%)`,\n          outline: '3px solid hotpink',\n          animation: 'pulse 3s linear infinite',\n          transition: 'outline-offset 0.2s ease-in-out',\n        },\n        hoverStyles: {\n          outlineOffset: '3px',\n        },\n        focusStyles: {\n          backgroundColor: 'transparent',\n        },\n        keyframes: `@keyframes pulse {\n          0% { outline-color: rgba(255, 105, 180, 1); }\n          50% { outline-color: rgba(255, 105, 180, 0.2); }\n          100% { outline-color: rgba(255, 105, 180, 1); }\n        }`,\n      });\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const StyledHighlight: Story = {\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        styles: {\n          backgroundColor: `color-mix(in srgb, hotpink, transparent 90%)`,\n          outline: '3px solid hotpink',\n          animation: 'pulse 3s linear infinite',\n          transition: 'outline-offset 0.2s ease-in-out',\n        },\n        hoverStyles: {\n          outlineOffset: '3px',\n        },\n        focusStyles: {\n          backgroundColor: 'transparent',\n        },\n        keyframes: `@keyframes pulse {\n          0% { outline-color: rgba(255, 105, 180, 1); }\n          50% { outline-color: rgba(255, 105, 180, 0.2); }\n          100% { outline-color: rgba(255, 105, 180, 1); }\n        }`,\n      });\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nexport default {\n  component: 'my-component',\n};\n\nexport const StyledHighlight = {\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        styles: {\n          backgroundColor: `color-mix(in srgb, hotpink, transparent 90%)`,\n          outline: '3px solid hotpink',\n          animation: 'pulse 3s linear infinite',\n          transition: 'outline-offset 0.2s ease-in-out',\n        },\n        hoverStyles: {\n          outlineOffset: '3px',\n        },\n        focusStyles: {\n          backgroundColor: 'transparent',\n        },\n        keyframes: `@keyframes pulse {\n          0% { outline-color: rgba(255, 105, 180, 1); }\n          50% { outline-color: rgba(255, 105, 180, 0.2); }\n          100% { outline-color: rgba(255, 105, 180, 1); }\n        }`,\n      });\n      return story();\n    },\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nconst meta: Meta = {\n  component: 'my-component',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const StyledHighlight: Story = {\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        styles: {\n          backgroundColor: `color-mix(in srgb, hotpink, transparent 90%)`,\n          outline: '3px solid hotpink',\n          animation: 'sb-highlight-pulse 3s linear infinite',\n          transition: 'outline-offset 0.2s ease-in-out',\n        },\n        hoverStyles: {\n          outlineOffset: '3px',\n        },\n        focusStyles: {\n          backgroundColor: 'transparent',\n        },\n        keyframes: `@keyframes sb-highlight-pulse {\n          0% { outline-color: rgba(255, 105, 180, 1); }\n          50% { outline-color: rgba(255, 105, 180, 0.2); }\n          100% { outline-color: rgba(255, 105, 180, 1); }\n        }`,\n      });\n      return story();\n    },\n  ],\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const StyledHighlight = meta.story({\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        styles: {\n          backgroundColor: `color-mix(in srgb, hotpink, transparent 90%)`,\n          outline: '3px solid hotpink',\n          animation: 'pulse 3s linear infinite',\n          transition: 'outline-offset 0.2s ease-in-out',\n        },\n        hoverStyles: {\n          outlineOffset: '3px',\n        },\n        focusStyles: {\n          backgroundColor: 'transparent',\n        },\n        keyframes: `@keyframes pulse {\n          0% { outline-color: rgba(255, 105, 180, 1); }\n          50% { outline-color: rgba(255, 105, 180, 0.2); }\n          100% { outline-color: rgba(255, 105, 180, 1); }\n        }`,\n      });\n      return story();\n    },\n  ],\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const StyledHighlight = meta.story({\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        styles: {\n          backgroundColor: `color-mix(in srgb, hotpink, transparent 90%)`,\n          outline: '3px solid hotpink',\n          animation: 'sb-highlight-pulse 3s linear infinite',\n          transition: 'outline-offset 0.2s ease-in-out',\n        },\n        hoverStyles: {\n          outlineOffset: '3px',\n        },\n        focusStyles: {\n          backgroundColor: 'transparent',\n        },\n        keyframes: `@keyframes sb-highlight-pulse {\n          0% { outline-color: rgba(255, 105, 180, 1); }\n          50% { outline-color: rgba(255, 105, 180, 0.2); }\n          100% { outline-color: rgba(255, 105, 180, 1); }\n        }`,\n      });\n      return story();\n    },\n  ],\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const StyledHighlight = meta.story({\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        styles: {\n          backgroundColor: `color-mix(in srgb, hotpink, transparent 90%)`,\n          outline: '3px solid hotpink',\n          animation: 'pulse 3s linear infinite',\n          transition: 'outline-offset 0.2s ease-in-out',\n        },\n        hoverStyles: {\n          outlineOffset: '3px',\n        },\n        focusStyles: {\n          backgroundColor: 'transparent',\n        },\n        keyframes: `@keyframes pulse {\n          0% { outline-color: rgba(255, 105, 180, 1); }\n          50% { outline-color: rgba(255, 105, 180, 0.2); }\n          100% { outline-color: rgba(255, 105, 180, 1); }\n        }`,\n      });\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const StyledHighlight = meta.story({\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        styles: {\n          backgroundColor: `color-mix(in srgb, hotpink, transparent 90%)`,\n          outline: '3px solid hotpink',\n          animation: 'pulse 3s linear infinite',\n          transition: 'outline-offset 0.2s ease-in-out',\n        },\n        hoverStyles: {\n          outlineOffset: '3px',\n        },\n        focusStyles: {\n          backgroundColor: 'transparent',\n        },\n        keyframes: `@keyframes pulse {\n          0% { outline-color: rgba(255, 105, 180, 1); }\n          50% { outline-color: rgba(255, 105, 180, 0.2); }\n          100% { outline-color: rgba(255, 105, 180, 1); }\n        }`,\n      });\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n});\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const StyledHighlight = meta.story({\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        styles: {\n          backgroundColor: `color-mix(in srgb, hotpink, transparent 90%)`,\n          outline: '3px solid hotpink',\n          animation: 'pulse 3s linear infinite',\n          transition: 'outline-offset 0.2s ease-in-out',\n        },\n        hoverStyles: {\n          outlineOffset: '3px',\n        },\n        focusStyles: {\n          backgroundColor: 'transparent',\n        },\n        keyframes: `@keyframes pulse {\n          0% { outline-color: rgba(255, 105, 180, 1); }\n          50% { outline-color: rgba(255, 105, 180, 0.2); }\n          100% { outline-color: rgba(255, 105, 180, 1); }\n        }`,\n      });\n      return storyFn();\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const StyledHighlight = meta.story({\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        styles: {\n          backgroundColor: `color-mix(in srgb, hotpink, transparent 90%)`,\n          outline: '3px solid hotpink',\n          animation: 'pulse 3s linear infinite',\n          transition: 'outline-offset 0.2s ease-in-out',\n        },\n        hoverStyles: {\n          outlineOffset: '3px',\n        },\n        focusStyles: {\n          backgroundColor: 'transparent',\n        },\n        keyframes: `@keyframes pulse {\n          0% { outline-color: rgba(255, 105, 180, 1); }\n          50% { outline-color: rgba(255, 105, 180, 0.2); }\n          100% { outline-color: rgba(255, 105, 180, 1); }\n        }`,\n      });\n      return storyFn();\n    },\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/highlight-menu.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, type StoryObj, componentWrapperDecorator } from '@storybook/angular';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n};\n\nexport default meta;\ntype Story = StoryObj<MyComponent>;\n\nexport const StyledHighlight: Story = {\n  decorators: [\n    componentWrapperDecorator((story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        menu: [\n          [\n            {\n              id: 'button-name',\n              title: 'Login',\n              description: 'Navigate to the login page',\n              clickEvent: 'my-menu-click-event',\n            },\n            {\n              id: 'h2-home',\n              title: 'Acme',\n              description: 'Navigate to the home page',\n            },\n          ],\n        ],\n      });\n      return story;\n    }),\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { componentWrapperDecorator } from '@storybook/angular';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const StyledHighlight = meta.story({\n  decorators: [\n    componentWrapperDecorator((story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        menu: [\n          [\n            {\n              id: 'button-name',\n              title: 'Login',\n              description: 'Navigate to the login page',\n              clickEvent: 'my-menu-click-event',\n            },\n            {\n              id: 'h2-home',\n              title: 'Acme',\n              description: 'Navigate to the home page',\n            },\n          ],\n        ],\n      });\n      return story;\n    }),\n  ],\n});\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const StyledHighlight = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        menu: [\n          [\n            {\n              id: 'button-name',\n              title: 'Login',\n              description: 'Navigate to the login page',\n              clickEvent: 'my-menu-click-event',\n            },\n            {\n              id: 'h2-home',\n              title: 'Acme',\n              description: 'Navigate to the home page',\n            },\n          ],\n        ],\n      });\n      return storyFn();\n    },\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const StyledHighlight: Story = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        menu: [\n          [\n            {\n              id: 'button-name',\n              title: 'Login',\n              description: 'Navigate to the login page',\n              clickEvent: 'my-menu-click-event',\n            },\n            {\n              id: 'h2-home',\n              title: 'Acme',\n              description: 'Navigate to the home page',\n            },\n          ],\n        ],\n      });\n      return storyFn();\n    },\n  ],\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { useChannel } from 'storybook/preview-api';\n  import { HIGHLIGHT } from 'storybook/highlight';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"StyledHighlight\"\n  decorators={[\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        menu: [\n          [\n            {\n              id: 'button-name',\n              title: 'Login',\n              description: 'Navigate to the login page',\n              clickEvent: 'my-menu-click-event',\n            },\n            {\n              id: 'h2-home',\n              title: 'Acme',\n              description: 'Navigate to the home page',\n            },\n          ]\n        ],\n      });\n      return storyFn();\n    },\n  ]}\n/>\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.svelte';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const StyledHighlight = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        menu: [\n          [\n            {\n              id: 'button-name',\n              title: 'Login',\n              description: 'Navigate to the login page',\n              clickEvent: 'my-menu-click-event',\n            },\n            {\n              id: 'h2-home',\n              title: 'Acme',\n              description: 'Navigate to the home page',\n            },\n          ],\n        ],\n      });\n      return storyFn();\n    },\n  ],\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { useChannel } from 'storybook/preview-api';\n  import { HIGHLIGHT } from 'storybook/highlight';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"StyledHighlight\"\n  decorators={[\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        menu: [\n          [\n            {\n              id: 'button-name',\n              title: 'Login',\n              description: 'Navigate to the login page',\n              clickEvent: 'my-menu-click-event',\n            },\n            {\n              id: 'h2-home',\n              title: 'Acme',\n              description: 'Navigate to the home page',\n            },\n          ]\n        ],\n      });\n      return storyFn();\n    },\n  ]}\n/>\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.svelte';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const StyledHighlight: Story = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        menu: [\n          [\n            {\n              id: 'button-name',\n              title: 'Login',\n              description: 'Navigate to the login page',\n              clickEvent: 'my-menu-click-event',\n            },\n            {\n              id: 'h2-home',\n              title: 'Acme',\n              description: 'Navigate to the home page',\n            },\n          ],\n        ],\n      });\n      return storyFn();\n    },\n  ],\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.vue';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const StyledHighlight = {\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        menu: [\n          [\n            {\n              id: 'button-name',\n              title: 'Login',\n              description: 'Navigate to the login page',\n              clickEvent: 'my-menu-click-event',\n            },\n            {\n              id: 'h2-home',\n              title: 'Acme',\n              description: 'Navigate to the home page',\n            },\n          ],\n        ],\n      });\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const StyledHighlight: Story = {\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        menu: [\n          [\n            {\n              id: 'button-name',\n              title: 'Login',\n              description: 'Navigate to the login page',\n              clickEvent: 'my-menu-click-event',\n            },\n            {\n              id: 'h2-home',\n              title: 'Acme',\n              description: 'Navigate to the home page',\n            },\n          ],\n        ],\n      });\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const StyledHighlight = meta.story({\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        menu: [\n          [\n            {\n              id: 'button-name',\n              title: 'Login',\n              description: 'Navigate to the login page',\n              clickEvent: 'my-menu-click-event',\n            },\n            {\n              id: 'h2-home',\n              title: 'Acme',\n              description: 'Navigate to the home page',\n            },\n          ],\n        ],\n      });\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const StyledHighlight = meta.story({\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        menu: [\n          [\n            {\n              id: 'button-name',\n              title: 'Login',\n              description: 'Navigate to the login page',\n              clickEvent: 'my-menu-click-event',\n            },\n            {\n              id: 'h2-home',\n              title: 'Acme',\n              description: 'Navigate to the home page',\n            },\n          ],\n        ],\n      });\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nexport default {\n  component: 'my-component',\n};\n\nexport const StyledHighlight = {\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        menu: [\n          [\n            {\n              id: 'button-name',\n              title: 'Login',\n              description: 'Navigate to the login page',\n              clickEvent: 'my-menu-click-event',\n            },\n            {\n              id: 'h2-home',\n              title: 'Acme',\n              description: 'Navigate to the home page',\n            },\n          ],\n        ],\n      });\n      return story();\n    },\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nconst meta: Meta = {\n  component: 'my-component',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const StyledHighlight: Story = {\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        menu: [\n          [\n            {\n              id: 'button-name',\n              title: 'Login',\n              description: 'Navigate to the login page',\n              clickEvent: 'my-menu-click-event',\n            },\n            {\n              id: 'h2-home',\n              title: 'Acme',\n              description: 'Navigate to the home page',\n            },\n          ],\n        ],\n      });\n      return story();\n    },\n  ],\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const StyledHighlight = meta.story({\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        menu: [\n          [\n            {\n              id: 'button-name',\n              title: 'Login',\n              description: 'Navigate to the login page',\n              clickEvent: 'my-menu-click-event',\n            },\n            {\n              id: 'h2-home',\n              title: 'Acme',\n              description: 'Navigate to the home page',\n            },\n          ],\n        ],\n      });\n      return story();\n    },\n  ],\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const StyledHighlight = meta.story({\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        menu: [\n          [\n            {\n              id: 'button-name',\n              title: 'Login',\n              description: 'Navigate to the login page',\n              clickEvent: 'my-menu-click-event',\n            },\n            {\n              id: 'h2-home',\n              title: 'Acme',\n              description: 'Navigate to the home page',\n            },\n          ],\n        ],\n      });\n      return story();\n    },\n  ],\n});\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const StyledHighlight = meta.story({\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        menu: [\n          [\n            {\n              id: 'button-name',\n              title: 'Login',\n              description: 'Navigate to the login page',\n              clickEvent: 'my-menu-click-event',\n            },\n            {\n              id: 'h2-home',\n              title: 'Acme',\n              description: 'Navigate to the home page',\n            },\n          ],\n        ],\n      });\n      return storyFn();\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const StyledHighlight = meta.story({\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        selectors: ['h2', 'a', '.storybook-button'],\n        menu: [\n          [\n            {\n              id: 'button-name',\n              title: 'Login',\n              description: 'Navigate to the login page',\n              clickEvent: 'my-menu-click-event',\n            },\n            {\n              id: 'h2-home',\n              title: 'Acme',\n              description: 'Navigate to the home page',\n            },\n          ],\n        ],\n      });\n      return storyFn();\n    },\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/highlight-remove.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, type StoryObj, componentWrapperDecorator } from '@storybook/angular';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, REMOVE_HIGHLIGHT } from 'storybook/highlight';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n};\n\nexport default meta;\ntype Story = StoryObj<MyComponent>;\n\nexport const RemoveHighlight: Story = {\n  decorators: [\n    componentWrapperDecorator((story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        id: 'my-unique-id',\n        selectors: ['header', 'section', 'footer'],\n      });\n      emit(REMOVE_HIGHLIGHT, 'my-unique-id');\n      return story;\n    }),\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { componentWrapperDecorator } from '@storybook/angular';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, REMOVE_HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const RemoveHighlight = meta.story({\n  decorators: [\n    componentWrapperDecorator((story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        id: 'my-unique-id',\n        selectors: ['header', 'section', 'footer'],\n      });\n      emit(REMOVE_HIGHLIGHT, 'my-unique-id');\n      return story;\n    }),\n  ],\n});\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, REMOVE_HIGHLIGHT } from 'storybook/highlight';\n\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const RemoveHighlight = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        id: 'my-unique-id',\n        selectors: ['header', 'section', 'footer'],\n      });\n      emit(REMOVE_HIGHLIGHT, 'my-unique-id');\n      return storyFn();\n    },\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, REMOVE_HIGHLIGHT } from 'storybook/highlight';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const RemoveHighlight: Story = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        id: 'my-unique-id',\n        selectors: ['header', 'section', 'footer'],\n      });\n      emit(REMOVE_HIGHLIGHT, 'my-unique-id');\n      return storyFn();\n    },\n  ],\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { useChannel } from 'storybook/preview-api';\n  import { HIGHLIGHT, REMOVE_HIGHLIGHT } from 'storybook/highlight';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"RemoveHighlight\"\n  decorators={[\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        id: 'my-unique-id',\n        selectors: ['header', 'section', 'footer'],\n      });\n      emit(REMOVE_HIGHLIGHT, 'my-unique-id');\n      return storyFn();\n    },\n  ]}\n/>\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, REMOVE_HIGHLIGHT } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.svelte';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const RemoveHighlight = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        id: 'my-unique-id',\n        selectors: ['header', 'section', 'footer'],\n      });\n      emit(REMOVE_HIGHLIGHT, 'my-unique-id');\n      return storyFn();\n    },\n  ],\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { useChannel } from 'storybook/preview-api';\n  import { HIGHLIGHT, REMOVE_HIGHLIGHT } from 'storybook/highlight';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"RemoveHighlight\"\n  decorators={[\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        id: 'my-unique-id',\n        selectors: ['header', 'section', 'footer'],\n      });\n      emit(REMOVE_HIGHLIGHT, 'my-unique-id');\n      return storyFn();\n    },\n  ]}\n/>\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, REMOVE_HIGHLIGHT } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.svelte';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const RemoveHighlight: Story = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        id: 'my-unique-id',\n        selectors: ['header', 'section', 'footer'],\n      });\n      emit(REMOVE_HIGHLIGHT, 'my-unique-id');\n      return storyFn();\n    },\n  ],\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, REMOVE_HIGHLIGHT } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.vue';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const RemoveHighlight = {\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        id: 'my-unique-id',\n        selectors: ['header', 'section', 'footer'],\n      });\n      emit(REMOVE_HIGHLIGHT, 'my-unique-id');\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, REMOVE_HIGHLIGHT } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const RemoveHighlight: Story = {\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        id: 'my-unique-id',\n        selectors: ['header', 'section', 'footer'],\n      });\n      emit(REMOVE_HIGHLIGHT, 'my-unique-id');\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, REMOVE_HIGHLIGHT } from 'storybook/highlight';\n\nexport default {\n  component: 'my-component',\n};\n\nexport const RemoveHighlight = {\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        id: 'my-unique-id',\n        selectors: ['header', 'section', 'footer'],\n      });\n      emit(REMOVE_HIGHLIGHT, 'my-unique-id');\n      return story();\n    },\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, REMOVE_HIGHLIGHT } from 'storybook/highlight';\n\nconst meta: Meta = {\n  component: 'my-component',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const RemoveHighlight: Story = {\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        id: 'my-unique-id',\n        selectors: ['header', 'section', 'footer'],\n      });\n      emit(REMOVE_HIGHLIGHT, 'my-unique-id');\n      return story();\n    },\n  ],\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, REMOVE_HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const RemoveHighlight = meta.story({\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        id: 'my-unique-id',\n        selectors: ['header', 'section', 'footer'],\n      });\n      emit(REMOVE_HIGHLIGHT, 'my-unique-id');\n      return story();\n    },\n  ],\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, REMOVE_HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const RemoveHighlight = meta.story({\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        id: 'my-unique-id',\n        selectors: ['header', 'section', 'footer'],\n      });\n      emit(REMOVE_HIGHLIGHT, 'my-unique-id');\n      return story();\n    },\n  ],\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, REMOVE_HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const RemoveHighlight = meta.story({\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        id: 'my-unique-id',\n        selectors: ['header', 'section', 'footer'],\n      });\n      emit(REMOVE_HIGHLIGHT, 'my-unique-id');\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, REMOVE_HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const RemoveHighlight = meta.story({\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        id: 'my-unique-id',\n        selectors: ['header', 'section', 'footer'],\n      });\n      emit(REMOVE_HIGHLIGHT, 'my-unique-id');\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n});\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, REMOVE_HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const RemoveHighlight = meta.story({\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        id: 'my-unique-id',\n        selectors: ['header', 'section', 'footer'],\n      });\n      emit(REMOVE_HIGHLIGHT, 'my-unique-id');\n      return storyFn();\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, REMOVE_HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const RemoveHighlight = meta.story({\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(HIGHLIGHT, {\n        id: 'my-unique-id',\n        selectors: ['header', 'section', 'footer'],\n      });\n      emit(REMOVE_HIGHLIGHT, 'my-unique-id');\n      return storyFn();\n    },\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/highlight-reset.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, type StoryObj, componentWrapperDecorator } from '@storybook/angular';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, RESET_HIGHLIGHT } from 'storybook/highlight';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n};\n\nexport default meta;\ntype Story = StoryObj<MyComponent>;\n\nexport const ResetHighlight: Story = {\n  decorators: [\n    componentWrapperDecorator((story) => {\n      const emit = useChannel({});\n      emit(RESET_HIGHLIGHT); //👈 Remove previously highlighted elements\n      emit(HIGHLIGHT, {\n        selectors: ['header', 'section', 'footer'],\n      });\n      return story;\n    }),\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { componentWrapperDecorator } from '@storybook/angular';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, RESET_HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ResetHighlight = meta.story({\n  decorators: [\n    componentWrapperDecorator((story) => {\n      const emit = useChannel({});\n      emit(RESET_HIGHLIGHT); //👈 Remove previously highlighted elements\n      emit(HIGHLIGHT, {\n        selectors: ['header', 'section', 'footer'],\n      });\n      return story;\n    }),\n  ],\n});\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, RESET_HIGHLIGHT } from 'storybook/highlight';\n\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const ResetHighlight = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(RESET_HIGHLIGHT); //👈 Remove previously highlighted elements\n      emit(HIGHLIGHT, {\n        selectors: ['header', 'section', 'footer'],\n      });\n      return storyFn();\n    },\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, RESET_HIGHLIGHT } from 'storybook/highlight';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ResetHighlight: Story = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(RESET_HIGHLIGHT); //👈 Remove previously highlighted elements\n      emit(HIGHLIGHT, {\n        selectors: ['header', 'section', 'footer'],\n      });\n      return storyFn();\n    },\n  ],\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { useChannel } from 'storybook/preview-api';\n  import { HIGHLIGHT, RESET_HIGHLIGHT } from 'storybook/highlight';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"ResetHighlight\"\n  decorators={[\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(RESET_HIGHLIGHT); //👈 Remove previously highlighted elements\n      emit(HIGHLIGHT, {\n        selectors: ['header', 'section', 'footer'],\n      });\n      return storyFn();\n    },\n  ]}\n/>\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, RESET_HIGHLIGHT } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.svelte';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const ResetHighlight = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(RESET_HIGHLIGHT); //👈 Remove previously highlighted elements\n      emit(HIGHLIGHT, {\n        selectors: ['header', 'section', 'footer'],\n      });\n      return storyFn();\n    },\n  ],\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { useChannel } from 'storybook/preview-api';\n  import { HIGHLIGHT, RESET_HIGHLIGHT } from 'storybook/highlight';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"ResetHighlight\"\n  decorators={[\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(RESET_HIGHLIGHT); //👈 Remove previously highlighted elements\n      emit(HIGHLIGHT, {\n        selectors: ['header', 'section', 'footer'],\n      });\n      return storyFn();\n    },\n  ]}\n/>\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, RESET_HIGHLIGHT } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.svelte';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ResetHighlight: Story = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(RESET_HIGHLIGHT); //👈 Remove previously highlighted elements\n      emit(HIGHLIGHT, {\n        selectors: ['header', 'section', 'footer'],\n      });\n      return storyFn();\n    },\n  ],\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, RESET_HIGHLIGHT } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.vue';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const ResetHighlight = {\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(RESET_HIGHLIGHT); //👈 Remove previously highlighted elements\n      emit(HIGHLIGHT, {\n        selectors: ['header', 'section', 'footer'],\n      });\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, RESET_HIGHLIGHT } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ResetHighlight: Story = {\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(RESET_HIGHLIGHT); //👈 Remove previously highlighted elements\n      emit(HIGHLIGHT, {\n        selectors: ['header', 'section', 'footer'],\n      });\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, RESET_HIGHLIGHT } from 'storybook/highlight';\n\nexport default {\n  component: 'my-component',\n};\n\nexport const ResetHighlight = {\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(RESET_HIGHLIGHT); //👈 Remove previously highlighted elements\n      emit(HIGHLIGHT, {\n        selectors: ['header', 'section', 'footer'],\n      });\n      return story();\n    },\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, RESET_HIGHLIGHT } from 'storybook/highlight';\n\nconst meta: Meta = {\n  component: 'my-component',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const ResetHighlight: Story = {\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(RESET_HIGHLIGHT); //👈 Remove previously highlighted elements\n      emit(HIGHLIGHT, {\n        selectors: ['header', 'section', 'footer'],\n      });\n      return story();\n    },\n  ],\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, RESET_HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const ResetHighlight = meta.story({\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(RESET_HIGHLIGHT); //👈 Remove previously highlighted elements\n      emit(HIGHLIGHT, {\n        selectors: ['header', 'section', 'footer'],\n      });\n      return story();\n    },\n  ],\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, RESET_HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const ResetHighlight = meta.story({\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(RESET_HIGHLIGHT); //👈 Remove previously highlighted elements\n      emit(HIGHLIGHT, {\n        selectors: ['header', 'section', 'footer'],\n      });\n      return story();\n    },\n  ],\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, RESET_HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ResetHighlight = meta.story({\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(RESET_HIGHLIGHT); //👈 Remove previously highlighted elements\n      emit(HIGHLIGHT, {\n        selectors: ['header', 'section', 'footer'],\n      });\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, RESET_HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ResetHighlight = meta.story({\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(RESET_HIGHLIGHT); //👈 Remove previously highlighted elements\n      emit(HIGHLIGHT, {\n        selectors: ['header', 'section', 'footer'],\n      });\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n});\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, RESET_HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ResetHighlight = meta.story({\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(RESET_HIGHLIGHT); //👈 Remove previously highlighted elements\n      emit(HIGHLIGHT, {\n        selectors: ['header', 'section', 'footer'],\n      });\n      return storyFn();\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { HIGHLIGHT, RESET_HIGHLIGHT } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ResetHighlight = meta.story({\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(RESET_HIGHLIGHT); //👈 Remove previously highlighted elements\n      emit(HIGHLIGHT, {\n        selectors: ['header', 'section', 'footer'],\n      });\n      return storyFn();\n    },\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/highlight-scroll-into-view.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, type StoryObj, componentWrapperDecorator } from '@storybook/angular';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { SCROLL_INTO_VIEW } from 'storybook/highlight';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n};\n\nexport default meta;\ntype Story = StoryObj<MyComponent>;\n\nexport const ScrollIntoView: Story = {\n  decorators: [\n    componentWrapperDecorator((story) => {\n      const emit = useChannel({});\n      emit(SCROLL_INTO_VIEW, '#footer');\n      return story;\n    }),\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { componentWrapperDecorator } from '@storybook/angular';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { SCROLL_INTO_VIEW } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ScrollIntoView = meta.story({\n  decorators: [\n    componentWrapperDecorator((story) => {\n      const emit = useChannel({});\n      emit(SCROLL_INTO_VIEW, '#footer');\n      return story;\n    }),\n  ],\n});\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { SCROLL_INTO_VIEW } from 'storybook/highlight';\n\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const ScrollIntoView = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(SCROLL_INTO_VIEW, '#footer');\n      return storyFn();\n    },\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { SCROLL_INTO_VIEW } from 'storybook/highlight';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ScrollIntoView: Story = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(SCROLL_INTO_VIEW, '#footer');\n      return storyFn();\n    },\n  ],\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { useChannel } from 'storybook/preview-api';\n  import { SCROLL_INTO_VIEW } from 'storybook/highlight';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"ScrollIntoView\"\n  decorators={[\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(SCROLL_INTO_VIEW, '#footer');\n      return storyFn();\n    },\n  ]}\n/>\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { SCROLL_INTO_VIEW } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.svelte';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const ScrollIntoView = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(SCROLL_INTO_VIEW, '#footer');\n      return storyFn();\n    },\n  ],\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { useChannel } from 'storybook/preview-api';\n  import { SCROLL_INTO_VIEW } from 'storybook/highlight';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"ScrollIntoView\"\n  decorators={[\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(SCROLL_INTO_VIEW, '#footer');\n      return storyFn();\n    },\n  ]}\n/>\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { SCROLL_INTO_VIEW } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.svelte';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ScrollIntoView: Story = {\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(SCROLL_INTO_VIEW, '#footer');\n      return storyFn();\n    },\n  ],\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { SCROLL_INTO_VIEW } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.vue';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const ScrollIntoView = {\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(SCROLL_INTO_VIEW, '#footer');\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { SCROLL_INTO_VIEW } from 'storybook/highlight';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ScrollIntoView: Story = {\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(SCROLL_INTO_VIEW, '#footer');\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useChannel } from 'storybook/preview-api';\nimport { SCROLL_INTO_VIEW } from 'storybook/highlight';\n\nexport default {\n  component: 'my-component',\n};\n\nexport const ScrollIntoView = {\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(SCROLL_INTO_VIEW, '#footer');\n      return story();\n    },\n  ],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { useChannel } from 'storybook/preview-api';\nimport { SCROLL_INTO_VIEW } from 'storybook/highlight';\n\nconst meta: Meta = {\n  component: 'my-component',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const ScrollIntoView: Story = {\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(SCROLL_INTO_VIEW, '#footer');\n      return story();\n    },\n  ],\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { SCROLL_INTO_VIEW } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const ScrollIntoView = meta.story({\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(SCROLL_INTO_VIEW, '#footer');\n      return story();\n    },\n  ],\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { SCROLL_INTO_VIEW } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const ScrollIntoView = meta.story({\n  decorators: [\n    (story) => {\n      const emit = useChannel({});\n      emit(SCROLL_INTO_VIEW, '#footer');\n      return story();\n    },\n  ],\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { SCROLL_INTO_VIEW } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ScrollIntoView = meta.story({\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(SCROLL_INTO_VIEW, '#footer');\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { SCROLL_INTO_VIEW } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ScrollIntoView = meta.story({\n  decorators: [\n    () => {\n      const emit = useChannel({});\n      emit(SCROLL_INTO_VIEW, '#footer');\n      return {\n        template: '<story />',\n      };\n    },\n  ],\n});\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { SCROLL_INTO_VIEW } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ScrollIntoView = meta.story({\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(SCROLL_INTO_VIEW, '#footer');\n      return storyFn();\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { useChannel } from 'storybook/preview-api';\nimport { SCROLL_INTO_VIEW } from 'storybook/highlight';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ScrollIntoView = meta.story({\n  decorators: [\n    (storyFn) => {\n      const emit = useChannel({});\n      emit(SCROLL_INTO_VIEW, '#footer');\n      return storyFn();\n    },\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/histogram-story.md",
    "content": "```ts filename=\"Histogram.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { HistogramComponent } from './histogram.component';\n\nconst meta: Meta<HistogramComponent> = {\n  component: HistogramComponent,\n};\n\nexport default meta;\ntype Story = StoryObj<HistogramComponent>;\n\nexport const Basic: Story = {\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n};\n```\n\n```ts filename=\"Histogram.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { HistogramComponent } from './histogram.component';\n\nconst meta = preview.meta({\n  component: HistogramComponent,\n});\n\nexport const Basic = meta.story({\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n});\n```\n\n```js filename=\"Histogram.stories.js\" renderer=\"html\" language=\"js\"\nimport { createHistogram } from './Histogram';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Histogram',\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic = {\n  render: (args) => createHistogram(args),\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n};\n```\n\n```ts filename=\"Histogram.stories.ts\" renderer=\"html\" language=\"ts\"\nimport type { Meta, StoryObj } from '@storybook/html';\n\nimport { createHistogram, HistogramProps } from './Histogram';\n\nconst meta: Meta<HistogramProps> = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Histogram',\n};\n\nexport default meta;\ntype Story = StoryObj<HistogramProps>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic: Story = {\n  render: (args) => createHistogram(args),\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n};\n```\n\n```js filename=\"Histogram.stories.js|jsx\" renderer=\"preact\" language=\"js\"\n/** @jsx h */\nimport { h } from 'preact';\n\nimport { Histogram } from './Histogram';\n\nexport default {\n  component: Histogram,\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic = {\n  render: (args) => <Histogram {...args} />,\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n};\n```\n\n```js filename=\"Histogram.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Histogram } from './Histogram';\n\nexport default {\n  component: Histogram,\n};\n\nexport const Basic = {\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n};\n```\n\n```ts filename=\"Histogram.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Histogram } from './Histogram';\n\nconst meta = {\n  component: Histogram,\n} satisfies Meta<typeof Histogram>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n};\n```\n\n```js filename=\"Histogram.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { Histogram } from './Histogram';\n\nexport default {\n  component: Histogram,\n};\n\nexport const Basic = {\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n};\n```\n\n```ts filename=\"Histogram.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { Histogram } from './Histogram';\n\nconst meta = {\n  component: Histogram,\n} satisfies Meta<typeof Histogram>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n};\n```\n\n```svelte filename=\"Histogram.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Histogram from './Histogram.svelte';\n\n  const { Story } = defineMeta({\n    component: Histogram,\n  });\n</script>\n\n<Story\n  name=\"Default\"\n  args={{\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  }}\n/>\n```\n\n```js filename=\"Histogram.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Histogram from './Histogram.svelte';\n\nexport default {\n  component: Histogram,\n};\n\nexport const Basic = {\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n};\n```\n\n```svelte filename=\"Histogram.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Histogram from './Histogram.svelte';\n\n  const { Story } = defineMeta({\n    component: Histogram,\n  });\n</script>\n\n<Story\n  name=\"Default\"\n  args={{\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  }}\n/>\n```\n\n```ts filename=\"Histogram.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Histogram from './Histogram.svelte';\n\nconst meta = {\n  component: Histogram,\n} satisfies Meta<typeof Histogram>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n};\n```\n\n```js filename=\"Histogram.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport Histogram from './Histogram.vue';\n\nexport default {\n  component: Histogram,\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic = {\n  render: (args) => ({\n    components: { Histogram },\n    setup() {\n      return { args };\n    },\n    template: '<Histogram v-bind=\"args\" />',\n  }),\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n};\n```\n\n```ts filename=\"Histogram.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport Histogram from './Histogram.vue';\n\nconst meta = {\n  component: Histogram,\n} satisfies Meta<typeof Histogram>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic: Story = {\n  render: (args) => ({\n    components: { Histogram },\n    setup() {\n      return { args };\n    },\n    template: '<Histogram v-bind=\"args\" />',\n  }),\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n};\n```\n\n```js filename=\"Histogram.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'histogram-component',\n};\n\nexport const Basic = {\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n};\n```\n\n```ts filename=\"Histogram.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'histogram-component',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Basic: Story = {\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n};\n```\n\n```js filename=\"Histogram.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'histogram-component',\n});\n\nexport const Basic = meta.story({\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n});\n```\n\n```ts filename=\"Histogram.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'histogram-component',\n});\n\nexport const Basic = meta.story({\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n});\n```\n\n```ts filename=\"Histogram.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Histogram from './Histogram.vue';\n\nconst meta = preview.meta({\n  component: Histogram,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic = meta.story({\n  render: (args) => ({\n    components: { Histogram },\n    setup() {\n      return { args };\n    },\n    template: '<Histogram v-bind=\"args\" />',\n  }),\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Histogram.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Histogram from './Histogram.vue';\n\nconst meta = preview.meta({\n  component: Histogram,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic = meta.story({\n  render: (args) => ({\n    components: { Histogram },\n    setup() {\n      return { args };\n    },\n    template: '<Histogram v-bind=\"args\" />',\n  }),\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n});\n```\n\n```ts filename=\"Histogram.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Histogram } from './Histogram';\n\nconst meta = preview.meta({\n  component: Histogram,\n});\n\nexport const Basic = meta.story({\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Histogram.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Histogram } from './Histogram';\n\nconst meta = preview.meta({\n  component: Histogram,\n});\n\nexport const Basic = meta.story({\n  args: {\n    dataType: 'latency',\n    showHistogramLabels: true,\n    histogramAccentColor: '#1EA7FD',\n    label: 'Latency distribution',\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/individual-snapshot-tests-portable-stories.md",
    "content": "```js filename=\"storybook.test.js\" renderer=\"common\" language=\"js\" tabTitle=\"jest\"\nimport path from 'path';\nimport * as glob from 'glob';\n\n//👇 Augment expect with jest-specific-snapshot\nimport 'jest-specific-snapshot';\n\nimport { describe, test, expect } from '@jest/globals';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\nconst compose = (entry) => {\n  try {\n    return composeStories(entry);\n  } catch (e) {\n    throw new Error(\n      `There was an issue composing stories for the module: ${JSON.stringify(entry)}, ${e}`,\n    );\n  }\n};\n\nfunction getAllStoryFiles() {\n  // Place the glob you want to match your stories files\n  const storyFiles = glob.sync(\n    path.join(process.cwd(), 'stories/**/*.{stories,story}.{js,jsx,mjs,ts,tsx}'),\n  );\n\n  return storyFiles.map((filePath) => {\n    const storyFile = require(filePath);\n    const storyDir = path.dirname(filePath);\n    const componentName = path.basename(filePath).replace(/\\.(stories|story)\\.[^/.]+$/, '');\n\n    return { filePath, storyFile, storyDir, componentName };\n  });\n}\n\ndescribe('Stories Snapshots', () => {\n  getAllStoryFiles().forEach(({ storyFile, componentName }) => {\n    const meta = storyFile.default;\n    const title = meta.title || componentName;\n\n    describe(title, () => {\n      const stories = Object.entries(compose(storyFile)).map(([name, story]) => ({ name, story }));\n\n      if (stories.length <= 0) {\n        throw new Error(\n          `No stories found for this module: ${title}. Make sure there is at least one valid story for this module.`,\n        );\n      }\n\n      stories.forEach(({ name, story }) => {\n        test(name, async () => {\n          await story.run();\n          // Ensures a consistent snapshot by waiting for the component to render by adding a delay of 1 ms before taking the snapshot.\n          await new Promise((resolve) => setTimeout(resolve, 1));\n          // Defines the custom snapshot path location and file name\n          const customSnapshotPath = `./__snapshots__/${componentName}.test.js.snap`;\n          expect(document.body.firstChild).toMatchSpecificSnapshot(customSnapshotPath);\n        });\n      });\n    });\n  });\n});\n```\n\n```ts filename=\"storybook.test.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"jest\"\n// Replace your-framework with one of the supported Storybook frameworks (react, vue3)\nimport type { Meta, StoryFn } from '@storybook/your-framework';\n\nimport path from \"path\";\nimport * as glob from \"glob\";\n\n//👇 Augment expect with jest-specific-snapshot\nimport \"jest-specific-snapshot\";\n\nimport { describe, test, expect } from \"@jest/globals\";\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\ntype StoryFile = {\n  default: Meta;\n  [name: string]: StoryFn | Meta;\n};\n\nconst compose = (\n  entry: StoryFile\n): ReturnType<typeof composeStories<StoryFile>> => {\n  try {\n    return composeStories(entry);\n  } catch (e) {\n    throw new Error(\n      `There was an issue composing stories for the module: ${JSON.stringify(entry)}, ${e}`\n    );\n  }\n};\n\nfunction getAllStoryFiles() {\n  // Place the glob you want to match your stories files\n  const storyFiles = glob.sync(\n    path.join(process.cwd(), 'stories/**/*.{stories,story}.{js,jsx,mjs,ts,tsx}'),\n  );\n\n  return storyFiles.map((filePath) => {\n    const storyFile = require(filePath);\n    const storyDir = path.dirname(filePath);\n    const componentName = path\n      .basename(filePath)\n      .replace(/\\.(stories|story)\\.[^/.]+$/, \"\");\n\n    return { filePath, storyFile, storyDir, componentName };\n  });\n}\n\ndescribe(\"Stories Snapshots\", () => {\n  getAllStoryFiles().forEach(({ storyFile, componentName }) => {\n    const meta = storyFile.default;\n    const title = meta.title || componentName;\n\n    describe(title, () => {\n      const stories = Object.entries(compose(storyFile)).map(\n        ([name, story]) => ({ name, story })\n      );\n\n      if (stories.length <= 0) {\n        throw new Error(\n          `No stories found for this module: ${title}. Make sure there is at least one valid story for this module.`\n        );\n      }\n\n      stories.forEach(({ name, story }) => {\n        test(name, async () => {\n          await story.run();\n          // Ensures a consistent snapshot by waiting for the component to render by adding a delay of 1 ms before taking the snapshot.\n          await new Promise((resolve) => setTimeout(resolve, 1));\n          // Defines the custom snapshot path location and file name\n          const customSnapshotPath = `./__snapshots__/${componentName}.test.ts.snap`;\n          expect(document.body.firstChild).toMatchSpecificSnapshot(customSnapshotPath);\n      });\n    });\n  });\n});\n```\n\n```js filename=\"storybook.test.js\" renderer=\"common\" language=\"js\" tabTitle=\"vitest\"\n// @vitest-environment jsdom\n\nimport path from 'path';\nimport { describe, expect, test } from 'vitest';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\nconst compose = (entry) => {\n  try {\n    return composeStories(entry);\n  } catch (error) {\n    throw new Error(\n      `There was an issue composing stories for the module: ${JSON.stringify(entry)}, ${error}`,\n    );\n  }\n};\nfunction getAllStoryFiles() {\n  // Place the glob you want to match your story files\n  const storyFiles = Object.entries(\n    import.meta.glob('./stories/**/*.(stories|story).@(js|jsx|mjs|ts|tsx)', {\n      eager: true,\n    }),\n  );\n\n  return storyFiles.map(([filePath, storyFile]) => {\n    const storyDir = path.dirname(filePath);\n    const componentName = path.basename(filePath).replace(/\\.(stories|story)\\.[^/.]+$/, '');\n    return { filePath, storyFile, componentName, storyDir };\n  });\n}\ndescribe('Stories Snapshots', () => {\n  getAllStoryFiles().forEach(({ storyFile, componentName }) => {\n    const meta = storyFile.default;\n    const title = meta.title || componentName;\n\n    describe(title, () => {\n      const stories = Object.entries(compose(storyFile)).map(([name, story]) => ({ name, story }));\n\n      if (stories.length <= 0) {\n        throw new Error(\n          `No stories found for this module: ${title}. Make sure there is at least one valid story for this module.`,\n        );\n      }\n\n      stories.forEach(({ name, story }) => {\n        test(name, async () => {\n          await story.run();\n          // Ensures a consistent snapshot by waiting for the component to render by adding a delay of 1 ms before taking the snapshot.\n          await new Promise((resolve) => setTimeout(resolve, 1));\n          // Defines the custom snapshot path location and file name\n          const customSnapshotPath = `./__snapshots__/${componentName}.spec.js.snap`;\n          await expect(document.body.firstChild).toMatchFileSnapshot(customSnapshotPath);\n        });\n      });\n    });\n  });\n});\n```\n\n```ts filename=\"storybook.test.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"vitest\"\n// @vitest-environment jsdom\n\n// Replace your-framework with one of the supported Storybook frameworks (react, vue3)\nimport type { Meta, StoryFn } from '@storybook/your-framework';\n\nimport path from 'path';\nimport { describe, expect, test } from 'vitest';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\ntype StoryFile = {\n  default: Meta;\n  [name: string]: StoryFn | Meta;\n};\n\nconst compose = (entry: StoryFile): ReturnType<typeof composeStories<StoryFile>> => {\n  try {\n    return composeStories(entry);\n  } catch (e) {\n    throw new Error(\n      `There was an issue composing stories for the module: ${JSON.stringify(entry)}, ${e}`,\n    );\n  }\n};\n\nfunction getAllStoryFiles() {\n  // Place the glob you want to match your story files\n  const storyFiles = Object.entries(\n    import.meta.glob<StoryFile>('./stories/**/*.(stories|story).@(js|jsx|mjs|ts|tsx)', {\n      eager: true,\n    }),\n  );\n\n  return storyFiles.map(([filePath, storyFile]) => {\n    const storyDir = path.dirname(filePath);\n    const componentName = path.basename(filePath).replace(/\\.(stories|story)\\.[^/.]+$/, '');\n    return { filePath, storyFile, componentName, storyDir };\n  });\n}\n\ndescribe('Stories Snapshots', () => {\n  getAllStoryFiles().forEach(({ storyFile, componentName }) => {\n    const meta = storyFile.default;\n    const title = meta.title || componentName;\n\n    describe(title, () => {\n      const stories = Object.entries(compose(storyFile)).map(([name, story]) => ({ name, story }));\n\n      if (stories.length <= 0) {\n        throw new Error(\n          `No stories found for this module: ${title}. Make sure there is at least one valid story for this module.`,\n        );\n      }\n\n      stories.forEach(({ name, story }) => {\n        test(name, async () => {\n          await story.run();\n          // Ensures a consistent snapshot by waiting for the component to render by adding a delay of 1 ms before taking the snapshot.\n          await new Promise((resolve) => setTimeout(resolve, 1));\n          // Defines the custom snapshot path location and file name\n          const customSnapshotPath = `./__snapshots__/${componentName}.spec.ts.snap`;\n          await expect(document.body.firstChild).toMatchFileSnapshot(customSnapshotPath);\n        });\n      });\n    });\n  });\n});\n```\n"
  },
  {
    "path": "docs/_snippets/init-command-custom-version.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook@8.2 init\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx storybook@8.2 init\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn dlx storybook@8.2 init\n```\n"
  },
  {
    "path": "docs/_snippets/init-command.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook@latest init\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx storybook@latest init\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn dlx storybook@latest init\n```\n"
  },
  {
    "path": "docs/_snippets/initialize-library-in-preview.md",
    "content": "```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nimport { initialize } from '../lib/your-library';\n\ninitialize();\n\nconst preview: Preview = {\n  // ...\n};\n\nexport default preview;\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { initialize } from '../lib/your-library';\n\ninitialize();\n\nexport default {\n  // ...\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using, e.g. nextjs, nextjs-vite, react-vite, etc.\nimport { definePreview } from '@storybook/your-framework';\n\nimport { initialize } from '../lib/your-library';\n\ninitialize();\n\nconst preview = definePreview({\n  // ...\n});\n\nexport default preview;\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using, e.g. nextjs, nextjs-vite, react-vite, etc.\nimport { definePreview } from '@storybook/your-framework';\n\nimport { initialize } from '../lib/your-library';\n\ninitialize();\n\nconst preview = definePreview({\n  // ...\n});\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { initialize } from '../lib/your-library';\n\ninitialize();\n\nconst preview = definePreview({\n  // ...\n});\n\nexport default preview;\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { initialize } from '../lib/your-library';\n\ninitialize();\n\nconst preview = definePreview({\n  // ...\n});\n\nexport default preview;\n```\n"
  },
  {
    "path": "docs/_snippets/interaction-test-complex.md",
    "content": "```ts filename=\"EventForm.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\nimport { fn, expect } from 'storybook/test';\n\nimport { users } from '../mocks/users';\nimport { EventForm } from './event-form.component';\n\nconst meta: Meta<EventForm> = {\n  component: EventForm,\n};\nexport default meta;\n\ntype Story = StoryObj<EventForm>;\n\nexport const Submits: Story = {\n  // Mock functions so we can manipulate and spy on them\n  args: {\n    getUsers: fn(),\n    onSubmit: fn(),\n  },\n  beforeEach: async ({ args }) => {\n    // Manipulate `getUsers` mock to return mocked value\n    args.getUsers.mockResolvedValue(users);\n  },\n  play: async ({ args, canvas, userEvent }) => {\n    const usersList = canvas.getAllByRole('listitem');\n    await expect(usersList).toHaveLength(4);\n    await expect(canvas.getAllByText('VIP')).toHaveLength(2);\n\n    const titleInput = await canvas.findByLabelText('Enter a title for your event');\n    await userEvent.type(titleInput, 'Holiday party');\n\n    const submitButton = canvas.getByRole('button', { name: 'Plan event' });\n    await userEvent.click(submitButton);\n\n    // Spy on `onSubmit` to verify that it is called correctly\n    await expect(args.onSubmit).toHaveBeenCalledWith({\n      name: 'Holiday party',\n      userCount: 4,\n      data: expect.anything(),\n    });\n  },\n};\n```\n\n```ts filename=\"EventForm.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { users } from '../mocks/users';\nimport { EventForm } from './event-form.component';\n\nconst meta = preview.meta({\n  component: EventForm,\n});\n\nexport const Submits = meta.story({\n  // Mock functions so we can manipulate and spy on them\n  args: {\n    getUsers: fn(),\n    onSubmit: fn(),\n  },\n  beforeEach: async ({ args }) => {\n    // Manipulate `getUsers` mock to return mocked value\n    args.getUsers.mockResolvedValue(users);\n  },\n  play: async ({ args, canvas, userEvent }) => {\n    const usersList = canvas.getAllByRole('listitem');\n    await expect(usersList).toHaveLength(4);\n    await expect(canvas.getAllByText('VIP')).toHaveLength(2);\n\n    const titleInput = await canvas.findByLabelText('Enter a title for your event');\n    await userEvent.type(titleInput, 'Holiday party');\n\n    const submitButton = canvas.getByRole('button', { name: 'Plan event' });\n    await userEvent.click(submitButton);\n\n    // Spy on `onSubmit` to verify that it is called correctly\n    await expect(args.onSubmit).toHaveBeenCalledWith({\n      name: 'Holiday party',\n      userCount: 4,\n      data: expect.anything(),\n    });\n  },\n});\n```\n\n```ts filename=\"EventForm.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the name of your framework (e.g. react-vite, vue3-vite, etc.)\nimport type { Meta, StoryObj } from '@storybook/your-framework';\nimport { fn, expect } from 'storybook/test';\n\nimport { users } from '../mocks/users';\nimport { EventForm } from './EventForm';\n\nconst meta = {\n  component: EventForm,\n} satisfies Meta<typeof EventForm>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Submits: Story = {\n  // Mock functions so we can manipulate and spy on them\n  args: {\n    getUsers: fn(),\n    onSubmit: fn(),\n  },\n  beforeEach: async ({ args }) => {\n    // Manipulate `getUsers` mock to return mocked value\n    args.getUsers.mockResolvedValue(users);\n  },\n  play: async ({ args, canvas, userEvent }) => {\n    const usersList = canvas.getAllByRole('listitem');\n    await expect(usersList).toHaveLength(4);\n    await expect(canvas.getAllByText('VIP')).toHaveLength(2);\n\n    const titleInput = await canvas.findByLabelText('Enter a title for your event');\n    await userEvent.type(titleInput, 'Holiday party');\n\n    const submitButton = canvas.getByRole('button', { name: 'Plan event' });\n    await userEvent.click(submitButton);\n\n    // Spy on `onSubmit` to verify that it is called correctly\n    await expect(args.onSubmit).toHaveBeenCalledWith({\n      name: 'Holiday party',\n      userCount: 4,\n      data: expect.anything(),\n    });\n  },\n};\n```\n\n```js filename=\"EventForm.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { fn, expect } from 'storybook/test';\n\nimport { users } from '../mocks/users';\nimport { EventForm } from './EventForm';\n\nexport default {\n  component: EventForm,\n};\n\nexport const Submits = {\n  // Mock functions so we can manipulate and spy on them\n  args: {\n    getUsers: fn(),\n    onSubmit: fn(),\n  },\n  beforeEach: async ({ args }) => {\n    // Manipulate `getUsers` mock to return mocked value\n    args.getUsers.mockResolvedValue(users);\n  },\n  play: async ({ args, canvas, userEvent }) => {\n    const usersList = canvas.getAllByRole('listitem');\n    await expect(usersList).toHaveLength(4);\n    await expect(canvas.getAllByText('VIP')).toHaveLength(2);\n\n    const titleInput = await canvas.findByLabelText('Enter a title for your event');\n    await userEvent.type(titleInput, 'Holiday party');\n\n    const submitButton = canvas.getByRole('button', { name: 'Plan event' });\n    await userEvent.click(submitButton);\n\n    // Spy on `onSubmit` to verify that it is called correctly\n    await expect(args.onSubmit).toHaveBeenCalledWith({\n      name: 'Holiday party',\n      userCount: 4,\n      data: expect.anything(),\n    });\n  },\n};\n```\n\n```svelte filename=\"EventForm.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import { fn, expect } from 'storybook/test';\n\n  import { users } from '../mocks/users';\n  import EventForm from './EventForm.svelte';\n\n  const { Story } = defineMeta({\n    component: EventForm,\n  });\n</script>\n\n<Story\n  name=\"Submits\"\n  args={{\n    // Mock functions so we can manipulate and spy on them\n    getUsers: fn(),\n    onSubmit: fn(),\n  }}\n  beforeEach={async ({ args }) => {\n    // Manipulate `getUsers` mock to return mocked value\n    args.getUsers.mockResolvedValue(users);\n  }}\n  play={async ({ args, canvas, userEvent }) => {\n    const usersList = canvas.getAllByRole('listitem');\n    await expect(usersList).toHaveLength(4);\n    await expect(canvas.getAllByText('VIP')).toHaveLength(2);\n\n    const titleInput = await canvas.findByLabelText('Enter a title for your event');\n    await userEvent.type(titleInput, 'Holiday party');\n\n    const submitButton = canvas.getByRole('button', { name: 'Plan event' });\n    await userEvent.click(submitButton);\n\n    // Spy on `onSubmit` to verify that it is called correctly\n    await expect(args.onSubmit).toHaveBeenCalledWith({\n      name: 'Holiday party',\n      userCount: 4,\n      data: expect.anything(),\n    });\n  }}\n/>\n```\n\n```ts filename=\"EventForm.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\nimport { fn, expect } from 'storybook/test';\n\nimport { users } from '../mocks/users';\nimport EventForm from './EventForm.svelte';\n\nconst meta = {\n  component: EventForm,\n} satisfies Meta<typeof EventForm>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Submits: Story = {\n  // Mock functions so we can manipulate and spy on them\n  args: {\n    getUsers: fn(),\n    onSubmit: fn(),\n  },\n  beforeEach: async ({ args }) => {\n    // Manipulate `getUsers` mock to return mocked value\n    args.getUsers.mockResolvedValue(users);\n  },\n  play: async ({ args, canvas, userEvent }) => {\n    const usersList = canvas.getAllByRole('listitem');\n    await expect(usersList).toHaveLength(4);\n    await expect(canvas.getAllByText('VIP')).toHaveLength(2);\n\n    const titleInput = await canvas.findByLabelText('Enter a title for your event');\n    await userEvent.type(titleInput, 'Holiday party');\n\n    const submitButton = canvas.getByRole('button', { name: 'Plan event' });\n    await userEvent.click(submitButton);\n\n    // Spy on `onSubmit` to verify that it is called correctly\n    await expect(args.onSubmit).toHaveBeenCalledWith({\n      name: 'Holiday party',\n      userCount: 4,\n      data: expect.anything(),\n    });\n  },\n};\n```\n\n```svelte filename=\"EventForm.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import { fn, expect } from 'storybook/test';\n\n  import { users } from '../mocks/users';\n  import EventForm from './EventForm.svelte';\n\n  const { Story } = defineMeta({\n    component: EventForm,\n  });\n</script>\n\n<Story\n  name=\"Submits\"\n  args={{\n    // Mock functions so we can manipulate and spy on them\n    getUsers: fn(),\n    onSubmit: fn(),\n  }}\n  beforeEach={async ({ args }) => {\n    // Manipulate `getUsers` mock to return mocked value\n    args.getUsers.mockResolvedValue(users);\n  }}\n  play={async ({ args, canvas, userEvent }) => {\n    const usersList = canvas.getAllByRole('listitem');\n    await expect(usersList).toHaveLength(4);\n    await expect(canvas.getAllByText('VIP')).toHaveLength(2);\n\n    const titleInput = await canvas.findByLabelText('Enter a title for your event');\n    await userEvent.type(titleInput, 'Holiday party');\n\n    const submitButton = canvas.getByRole('button', { name: 'Plan event' });\n    await userEvent.click(submitButton);\n\n    // Spy on `onSubmit` to verify that it is called correctly\n    await expect(args.onSubmit).toHaveBeenCalledWith({\n      name: 'Holiday party',\n      userCount: 4,\n      data: expect.anything(),\n    });\n  }}\n/>\n```\n\n```js filename=\"EventForm.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport { fn, expect } from 'storybook/test';\n\nimport { users } from '../mocks/users';\nimport EventForm from './EventForm.svelte';\n\nexport default {\n  component: EventForm,\n};\n\nexport const Submits = {\n  // Mock functions so we can manipulate and spy on them\n  args: {\n    getUsers: fn(),\n    onSubmit: fn(),\n  },\n  beforeEach: async ({ args }) => {\n    // Manipulate `getUsers` mock to return mocked value\n    args.getUsers.mockResolvedValue(users);\n  },\n  play: async ({ args, canvas, userEvent }) => {\n    const usersList = canvas.getAllByRole('listitem');\n    await expect(usersList).toHaveLength(4);\n    await expect(canvas.getAllByText('VIP')).toHaveLength(2);\n\n    const titleInput = await canvas.findByLabelText('Enter a title for your event');\n    await userEvent.type(titleInput, 'Holiday party');\n\n    const submitButton = canvas.getByRole('button', { name: 'Plan event' });\n    await userEvent.click(submitButton);\n\n    // Spy on `onSubmit` to verify that it is called correctly\n    await expect(args.onSubmit).toHaveBeenCalledWith({\n      name: 'Holiday party',\n      userCount: 4,\n      data: expect.anything(),\n    });\n  },\n};\n```\n\n```ts filename=\"EventForm.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\nimport { fn, expect } from 'storybook/test';\n\nimport { users } from '../mocks/users';\n\nconst meta: Meta = {\n  component: 'demo-event-form',\n};\nexport default meta;\n\ntype Story = StoryObj;\n\nexport const Submits: Story = {\n  // Mock functions so we can manipulate and spy on them\n  args: {\n    getUsers: fn(),\n    onSubmit: fn(),\n  },\n  beforeEach: async ({ args }) => {\n    // Manipulate `getUsers` mock to return mocked value\n    args.getUsers.mockResolvedValue(users);\n  },\n  play: async ({ args, canvas, userEvent }) => {\n    const usersList = canvas.getAllByRole('listitem');\n    await expect(usersList).toHaveLength(4);\n    await expect(canvas.getAllByText('VIP')).toHaveLength(2);\n\n    const titleInput = await canvas.findByLabelText('Enter a title for your event');\n    await userEvent.type(titleInput, 'Holiday party');\n\n    const submitButton = canvas.getByRole('button', { name: 'Plan event' });\n    await userEvent.click(submitButton);\n\n    // Spy on `onSubmit` to verify that it is called correctly\n    await expect(args.onSubmit).toHaveBeenCalledWith({\n      name: 'Holiday party',\n      userCount: 4,\n      data: expect.anything(),\n    });\n  },\n};\n```\n\n```js filename=\"EventForm.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { fn, expect } from 'storybook/test';\n\nimport { users } from '../mocks/users';\n\nexport default {\n  component: 'demo-event-form',\n};\n\nexport const Submits = {\n  // Mock functions so we can manipulate and spy on them\n  args: {\n    getUsers: fn(),\n    onSubmit: fn(),\n  },\n  beforeEach: async ({ args }) => {\n    // Manipulate `getUsers` mock to return mocked value\n    args.getUsers.mockResolvedValue(users);\n  },\n  play: async ({ args, canvas, userEvent }) => {\n    const usersList = canvas.getAllByRole('listitem');\n    await expect(usersList).toHaveLength(4);\n    await expect(canvas.getAllByText('VIP')).toHaveLength(2);\n\n    const titleInput = await canvas.findByLabelText('Enter a title for your event');\n    await userEvent.type(titleInput, 'Holiday party');\n\n    const submitButton = canvas.getByRole('button', { name: 'Plan event' });\n    await userEvent.click(submitButton);\n\n    // Spy on `onSubmit` to verify that it is called correctly\n    await expect(args.onSubmit).toHaveBeenCalledWith({\n      name: 'Holiday party',\n      userCount: 4,\n      data: expect.anything(),\n    });\n  },\n};\n```\n\n```js filename=\"EventForm.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { users } from '../mocks/users';\n\nconst meta = preview.meta({\n  component: 'demo-event-form',\n});\n\nexport const Submits = meta.story({\n  // Mock functions so we can manipulate and spy on them\n  args: {\n    getUsers: fn(),\n    onSubmit: fn(),\n  },\n  beforeEach: async ({ args }) => {\n    // Manipulate `getUsers` mock to return mocked value\n    args.getUsers.mockResolvedValue(users);\n  },\n  play: async ({ args, canvas, userEvent }) => {\n    const usersList = canvas.getAllByRole('listitem');\n    await expect(usersList).toHaveLength(4);\n    await expect(canvas.getAllByText('VIP')).toHaveLength(2);\n\n    const titleInput = await canvas.findByLabelText('Enter a title for your event');\n    await userEvent.type(titleInput, 'Holiday party');\n\n    const submitButton = canvas.getByRole('button', { name: 'Plan event' });\n    await userEvent.click(submitButton);\n\n    // Spy on `onSubmit` to verify that it is called correctly\n    await expect(args.onSubmit).toHaveBeenCalledWith({\n      name: 'Holiday party',\n      userCount: 4,\n      data: expect.anything(),\n    });\n  },\n});\n```\n\n```ts filename=\"EventForm.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { users } from '../mocks/users';\n\nconst meta = preview.meta({\n  component: 'demo-event-form',\n});\n\nexport const Submits = meta.story({\n  // Mock functions so we can manipulate and spy on them\n  args: {\n    getUsers: fn(),\n    onSubmit: fn(),\n  },\n  beforeEach: async ({ args }) => {\n    // Manipulate `getUsers` mock to return mocked value\n    args.getUsers.mockResolvedValue(users);\n  },\n  play: async ({ args, canvas, userEvent }) => {\n    const usersList = canvas.getAllByRole('listitem');\n    await expect(usersList).toHaveLength(4);\n    await expect(canvas.getAllByText('VIP')).toHaveLength(2);\n\n    const titleInput = await canvas.findByLabelText('Enter a title for your event');\n    await userEvent.type(titleInput, 'Holiday party');\n\n    const submitButton = canvas.getByRole('button', { name: 'Plan event' });\n    await userEvent.click(submitButton);\n\n    // Spy on `onSubmit` to verify that it is called correctly\n    await expect(args.onSubmit).toHaveBeenCalledWith({\n      name: 'Holiday party',\n      userCount: 4,\n      data: expect.anything(),\n    });\n  },\n});\n```\n\n```ts filename=\"EventForm.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { users } from '../mocks/users';\nimport { EventForm } from './EventForm';\n\nconst meta = preview.meta({\n  component: EventForm,\n});\n\nexport const Submits = meta.story({\n  // Mock functions so we can manipulate and spy on them\n  args: {\n    getUsers: fn(),\n    onSubmit: fn(),\n  },\n  beforeEach: async ({ args }) => {\n    // Manipulate `getUsers` mock to return mocked value\n    args.getUsers.mockResolvedValue(users);\n  },\n  play: async ({ args, canvas, userEvent }) => {\n    const usersList = canvas.getAllByRole('listitem');\n    await expect(usersList).toHaveLength(4);\n    await expect(canvas.getAllByText('VIP')).toHaveLength(2);\n\n    const titleInput = await canvas.findByLabelText('Enter a title for your event');\n    await userEvent.type(titleInput, 'Holiday party');\n\n    const submitButton = canvas.getByRole('button', { name: 'Plan event' });\n    await userEvent.click(submitButton);\n\n    // Spy on `onSubmit` to verify that it is called correctly\n    await expect(args.onSubmit).toHaveBeenCalledWith({\n      name: 'Holiday party',\n      userCount: 4,\n      data: expect.anything(),\n    });\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"EventForm.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { users } from '../mocks/users';\nimport { EventForm } from './EventForm';\n\nconst meta = preview.meta({\n  component: EventForm,\n});\n\nexport const Submits = meta.story({\n  // Mock functions so we can manipulate and spy on them\n  args: {\n    getUsers: fn(),\n    onSubmit: fn(),\n  },\n  beforeEach: async ({ args }) => {\n    // Manipulate `getUsers` mock to return mocked value\n    args.getUsers.mockResolvedValue(users);\n  },\n  play: async ({ args, canvas, userEvent }) => {\n    const usersList = canvas.getAllByRole('listitem');\n    await expect(usersList).toHaveLength(4);\n    await expect(canvas.getAllByText('VIP')).toHaveLength(2);\n\n    const titleInput = await canvas.findByLabelText('Enter a title for your event');\n    await userEvent.type(titleInput, 'Holiday party');\n\n    const submitButton = canvas.getByRole('button', { name: 'Plan event' });\n    await userEvent.click(submitButton);\n\n    // Spy on `onSubmit` to verify that it is called correctly\n    await expect(args.onSubmit).toHaveBeenCalledWith({\n      name: 'Holiday party',\n      userCount: 4,\n      data: expect.anything(),\n    });\n  },\n});\n```\n\n```ts filename=\"EventForm.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { users } from '../mocks/users';\nimport EventForm from './EventForm.vue';\n\nconst meta = preview.meta({\n  component: EventForm,\n});\n\nexport const Submits = meta.story({\n  // Mock functions so we can manipulate and spy on them\n  args: {\n    getUsers: fn(),\n    onSubmit: fn(),\n  },\n  beforeEach: async ({ args }) => {\n    // Manipulate `getUsers` mock to return mocked value\n    args.getUsers.mockResolvedValue(users);\n  },\n  play: async ({ args, canvas, userEvent }) => {\n    const usersList = canvas.getAllByRole('listitem');\n    await expect(usersList).toHaveLength(4);\n    await expect(canvas.getAllByText('VIP')).toHaveLength(2);\n\n    const titleInput = await canvas.findByLabelText('Enter a title for your event');\n    await userEvent.type(titleInput, 'Holiday party');\n\n    const submitButton = canvas.getByRole('button', { name: 'Plan event' });\n    await userEvent.click(submitButton);\n\n    // Spy on `onSubmit` to verify that it is called correctly\n    await expect(args.onSubmit).toHaveBeenCalledWith({\n      name: 'Holiday party',\n      userCount: 4,\n      data: expect.anything(),\n    });\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"EventForm.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { users } from '../mocks/users';\nimport EventForm from './EventForm.vue';\n\nconst meta = preview.meta({\n  component: EventForm,\n});\n\nexport const Submits = meta.story({\n  // Mock functions so we can manipulate and spy on them\n  args: {\n    getUsers: fn(),\n    onSubmit: fn(),\n  },\n  beforeEach: async ({ args }) => {\n    // Manipulate `getUsers` mock to return mocked value\n    args.getUsers.mockResolvedValue(users);\n  },\n  play: async ({ args, canvas, userEvent }) => {\n    const usersList = canvas.getAllByRole('listitem');\n    await expect(usersList).toHaveLength(4);\n    await expect(canvas.getAllByText('VIP')).toHaveLength(2);\n\n    const titleInput = await canvas.findByLabelText('Enter a title for your event');\n    await userEvent.type(titleInput, 'Holiday party');\n\n    const submitButton = canvas.getByRole('button', { name: 'Plan event' });\n    await userEvent.click(submitButton);\n\n    // Spy on `onSubmit` to verify that it is called correctly\n    await expect(args.onSubmit).toHaveBeenCalledWith({\n      name: 'Holiday party',\n      userCount: 4,\n      data: expect.anything(),\n    });\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/interaction-test-fn-mock-spy.md",
    "content": "```ts filename=\"LoginForm.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\nimport { fn, expect } from 'storybook/test';\n\nimport { LoginForm } from './login-form.component';\n\nconst meta: Meta<LoginForm> = {\n  component: LoginForm,\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n};\nexport default meta;\n\ntype Story = StoryObj<LoginForm>;\n\nexport const FilledForm: Story = {\n  play: async ({ args, canvas, userEvent }) => {\n    await userEvent.type(canvas.getByLabelText('Email'), 'email@provider.com');\n    await userEvent.type(canvas.getByLabelText('Password'), 'a-random-password');\n    await userEvent.click(canvas.getByRole('button', { name: 'Log in' }));\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await expect(args.onSubmit).toHaveBeenCalled();\n  },\n};\n```\n\n```ts filename=\"LoginForm.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { LoginForm } from './login-form.component';\n\nconst meta = preview.meta({\n  component: LoginForm,\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n});\n\nexport const FilledForm = meta.story({\n  play: async ({ args, canvas, userEvent }) => {\n    await userEvent.type(canvas.getByLabelText('Email'), 'email@provider.com');\n    await userEvent.type(canvas.getByLabelText('Password'), 'a-random-password');\n    await userEvent.click(canvas.getByRole('button', { name: 'Log in' }));\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await expect(args.onSubmit).toHaveBeenCalled();\n  },\n});\n```\n\n```ts filename=\"LoginForm.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the name of your framework (e.g. react-vite, vue3-vite, etc.)\nimport type { Meta, StoryObj } from '@storybook/your-framework';\nimport { fn, expect } from 'storybook/test';\n\nimport { LoginForm } from './LoginForm';\n\nconst meta = {\n  component: LoginForm,\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n} satisfies Meta<typeof LoginForm>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const FilledForm: Story = {\n  play: async ({ args, canvas, userEvent }) => {\n    await userEvent.type(canvas.getByLabelText('Email'), 'email@provider.com');\n    await userEvent.type(canvas.getByLabelText('Password'), 'a-random-password');\n    await userEvent.click(canvas.getByRole('button', { name: 'Log in' }));\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await expect(args.onSubmit).toHaveBeenCalled();\n  },\n};\n```\n\n```js filename=\"LoginForm.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { fn, expect } from 'storybook/test';\n\nimport { LoginForm } from './LoginForm';\n\nexport default {\n  component: LoginForm,\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n};\n\nexport const FilledForm = {\n  play: async ({ args, canvas, userEvent }) => {\n    await userEvent.type(canvas.getByLabelText('Email'), 'email@provider.com');\n    await userEvent.type(canvas.getByLabelText('Password'), 'a-random-password');\n    await userEvent.click(canvas.getByRole('button', { name: 'Log in' }));\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await expect(args.onSubmit).toHaveBeenCalled();\n  },\n};\n```\n\n```svelte filename=\"LoginForm.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import LoginForm from './LoginForm.svelte';\n\n  const { Story } = defineMeta({\n    component: LoginForm,\n    args: {\n      // 👇 Use `fn` to spy on the onSubmit arg\n      onSubmit: fn(),\n    },\n  });\n</script>\n\n<Story\n  name=\"FilledForm\"\n  play={async ({ args, canvas, userEvent }) => {\n    await userEvent.type(canvas.getByLabelText('Email'), 'email@provider.com');\n    await userEvent.type(canvas.getByLabelText('Password'), 'a-random-password');\n    await userEvent.click(canvas.getByRole('button', { name: 'Log in' }));\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await expect(args.onSubmit).toHaveBeenCalled();\n  }}\n/>\n```\n\n```ts filename=\"LoginForm.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\nimport { fn, expect } from 'storybook/test';\n\nimport LoginForm from './LoginForm.svelte';\n\nconst meta = {\n  component: LoginForm,\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n} satisfies Meta<typeof LoginForm>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const FilledForm: Story = {\n  play: async ({ args, canvas, userEvent }) => {\n    await userEvent.type(canvas.getByLabelText('Email'), 'email@provider.com');\n    await userEvent.type(canvas.getByLabelText('Password'), 'a-random-password');\n    await userEvent.click(canvas.getByRole('button', { name: 'Log in' }));\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await expect(args.onSubmit).toHaveBeenCalled();\n  },\n};\n```\n\n```svelte filename=\"LoginForm.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import LoginForm from './LoginForm.svelte';\n\n  const { Story } = defineMeta({\n    component: LoginForm,\n    args: {\n      // 👇 Use `fn` to spy on the onSubmit arg\n      onSubmit: fn(),\n    },\n  });\n</script>\n\n<Story\n  name=\"FilledForm\"\n  play={async ({ args, canvas, userEvent }) => {\n    await userEvent.type(canvas.getByLabelText('Email'), 'email@provider.com');\n    await userEvent.type(canvas.getByLabelText('Password'), 'a-random-password');\n    await userEvent.click(canvas.getByRole('button', { name: 'Log in' }));\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await expect(args.onSubmit).toHaveBeenCalled();\n  }}\n/>\n```\n\n```js filename=\"LoginForm.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport { fn, expect } from 'storybook/test';\n\nimport LoginForm from './LoginForm.svelte';\n\nexport default {\n  component: LoginForm,\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n};\n\nexport const FilledForm = {\n  play: async ({ args, canvas, userEvent }) => {\n    await userEvent.type(canvas.getByLabelText('Email'), 'email@provider.com');\n    await userEvent.type(canvas.getByLabelText('Password'), 'a-random-password');\n    await userEvent.click(canvas.getByRole('button', { name: 'Log in' }));\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await expect(args.onSubmit).toHaveBeenCalled();\n  },\n};\n```\n\n```ts filename=\"LoginForm.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\nimport { fn, expect } from 'storybook/test';\n\nconst meta: Meta = {\n  component: 'demo-login-form',\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n};\nexport default meta;\n\ntype Story = StoryObj;\n\nexport const FilledForm: Story = {\n  play: async ({ args, canvas, userEvent }) => {\n    await userEvent.type(canvas.getByLabelText('Email'), 'email@provider.com');\n    await userEvent.type(canvas.getByLabelText('Password'), 'a-random-password');\n    await userEvent.click(canvas.getByRole('button', { name: 'Log in' }));\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await expect(args.onSubmit).toHaveBeenCalled();\n  },\n};\n```\n\n```js filename=\"LoginForm.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { fn, expect } from 'storybook/test';\n\nexport default {\n  component: 'demo-login-form',\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n};\n\nexport const FilledForm = {\n  play: async ({ args, canvas, userEvent }) => {\n    await userEvent.type(canvas.getByLabelText('Email'), 'email@provider.com');\n    await userEvent.type(canvas.getByLabelText('Password'), 'a-random-password');\n    await userEvent.click(canvas.getByRole('button', { name: 'Log in' }));\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await expect(args.onSubmit).toHaveBeenCalled();\n  },\n};\n```\n\n```js filename=\"LoginForm.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-login-form',\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n});\n\nexport const FilledForm = meta.story({\n  play: async ({ args, canvas, userEvent }) => {\n    await userEvent.type(canvas.getByLabelText('Email'), 'email@provider.com');\n    await userEvent.type(canvas.getByLabelText('Password'), 'a-random-password');\n    await userEvent.click(canvas.getByRole('button', { name: 'Log in' }));\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await expect(args.onSubmit).toHaveBeenCalled();\n  },\n});\n```\n\n```ts filename=\"LoginForm.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-login-form',\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n});\n\nexport const FilledForm = meta.story({\n  play: async ({ args, canvas, userEvent }) => {\n    await userEvent.type(canvas.getByLabelText('Email'), 'email@provider.com');\n    await userEvent.type(canvas.getByLabelText('Password'), 'a-random-password');\n    await userEvent.click(canvas.getByRole('button', { name: 'Log in' }));\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await expect(args.onSubmit).toHaveBeenCalled();\n  },\n});\n```\n\n```ts filename=\"LoginForm.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { LoginForm } from './LoginForm';\n\nconst meta = preview.meta({\n  component: LoginForm,\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n});\n\nexport const FilledForm = meta.story({\n  play: async ({ args, canvas, userEvent }) => {\n    await userEvent.type(canvas.getByLabelText('Email'), 'email@provider.com');\n    await userEvent.type(canvas.getByLabelText('Password'), 'a-random-password');\n    await userEvent.click(canvas.getByRole('button', { name: 'Log in' }));\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await expect(args.onSubmit).toHaveBeenCalled();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"LoginForm.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { LoginForm } from './LoginForm';\n\nconst meta = preview.meta({\n  component: LoginForm,\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n});\n\nexport const FilledForm = meta.story({\n  play: async ({ args, canvas, userEvent }) => {\n    await userEvent.type(canvas.getByLabelText('Email'), 'email@provider.com');\n    await userEvent.type(canvas.getByLabelText('Password'), 'a-random-password');\n    await userEvent.click(canvas.getByRole('button', { name: 'Log in' }));\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await expect(args.onSubmit).toHaveBeenCalled();\n  },\n});\n```\n\n```ts filename=\"LoginForm.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport LoginForm from './LoginForm.vue';\n\nconst meta = preview.meta({\n  component: LoginForm,\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n});\n\nexport const FilledForm = meta.story({\n  play: async ({ args, canvas, userEvent }) => {\n    await userEvent.type(canvas.getByLabelText('Email'), 'email@provider.com');\n    await userEvent.type(canvas.getByLabelText('Password'), 'a-random-password');\n    await userEvent.click(canvas.getByRole('button', { name: 'Log in' }));\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await expect(args.onSubmit).toHaveBeenCalled();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"LoginForm.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport LoginForm from './LoginForm.vue';\n\nconst meta = preview.meta({\n  component: LoginForm,\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n});\n\nexport const FilledForm = meta.story({\n  play: async ({ args, canvas, userEvent }) => {\n    await userEvent.type(canvas.getByLabelText('Email'), 'email@provider.com');\n    await userEvent.type(canvas.getByLabelText('Password'), 'a-random-password');\n    await userEvent.click(canvas.getByRole('button', { name: 'Log in' }));\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await expect(args.onSubmit).toHaveBeenCalled();\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/interaction-test-simple.md",
    "content": "```ts filename=\"Dialog.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\nimport { expect } from 'storybook/test';\n\nimport { Dialog } from './dialog.component';\n\nconst meta: Meta<Dialog> = {\n  component: Dialog,\n};\nexport default meta;\n\ntype Story = StoryObj<Dialog>;\n\nexport const Opens: Story = {\n  play: async ({ canvas, userEvent }) => {\n    // Click on a button and assert that a dialog appears\n    const button = canvas.getByRole('button', { name: 'Open Modal' });\n    await userEvent.click(button);\n    await expect(canvas.getByRole('dialog')).toBeInTheDocument();\n  },\n};\n```\n\n```ts filename=\"Dialog.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { Dialog } from './dialog.component';\n\nconst meta = preview.meta({\n  component: Dialog,\n});\n\nexport const Opens = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    // Click on a button and assert that a dialog appears\n    const button = canvas.getByRole('button', { text: 'Open Modal' });\n    await userEvent.click(button);\n    await expect(canvas.getByRole('dialog')).toBeInTheDocument();\n  },\n});\n```\n\n```ts filename=\"Dialog.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the name of your framework (e.g. react-vite, vue3-vite, etc.)\nimport type { Meta, StoryObj } from '@storybook/your-framework';\nimport { expect } from 'storybook/test';\n\nimport { Dialog } from './Dialog';\n\nconst meta = {\n  component: Dialog,\n} satisfies Meta<typeof Dialog>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Opens: Story = {\n  play: async ({ canvas, userEvent }) => {\n    // Click on a button and assert that a dialog appears\n    const button = canvas.getByRole('button', { name: 'Open Modal' });\n    await userEvent.click(button);\n    await expect(canvas.getByRole('dialog')).toBeInTheDocument();\n  },\n};\n```\n\n```js filename=\"Dialog.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { expect } from 'storybook/test';\n\nimport { Dialog } from './Dialog';\n\nexport default {\n  component: Dialog,\n};\n\nexport const Opens = {\n  play: async ({ canvas, userEvent }) => {\n    // Click on a button and assert that a dialog appears\n    const button = canvas.getByRole('button', { name: 'Open Modal' });\n    await userEvent.click(button);\n    await expect(canvas.getByRole('dialog')).toBeInTheDocument();\n  },\n};\n```\n\n```svelte filename=\"Dialog.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Dialog from './Dialog.svelte';\n\n  const { Story } = defineMeta({\n    component: Dialog,\n  });\n</script>\n\n<Story\n  name=\"Opens\"\n  play={async ({ canvas, userEvent }) => {\n    // Click on a button and assert that a dialog appears\n    const button = canvas.getByRole('button', { name: 'Open Modal' });\n    await userEvent.click(button);\n    await expect(canvas.getByRole('dialog')).toBeInTheDocument();\n  }}\n/>\n```\n\n```ts filename=\"Dialog.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\nimport { expect } from 'storybook/test';\n\nimport Dialog from './Dialog.svelte';\n\nconst meta = {\n  component: Dialog,\n} satisfies Meta<typeof Dialog>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Opens: Story = {\n  play: async ({ canvas, userEvent }) => {\n    // Click on a button and assert that a dialog appears\n    const button = canvas.getByRole('button', { name: 'Open Modal' });\n    await userEvent.click(button);\n    await expect(canvas.getByRole('dialog')).toBeInTheDocument();\n  },\n};\n```\n\n```svelte filename=\"Dialog.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Dialog from './Dialog.svelte';\n\n  const { Story } = defineMeta({\n    component: Dialog,\n  });\n</script>\n\n<Story\n  name=\"Opens\"\n  play={async ({ canvas, userEvent }) => {\n    // Click on a button and assert that a dialog appears\n    const button = canvas.getByRole('button', { name: 'Open Modal' });\n    await userEvent.click(button);\n    await expect(canvas.getByRole('dialog')).toBeInTheDocument();\n  }}\n/>\n```\n\n```js filename=\"Dialog.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport { expect } from 'storybook/test';\n\nimport Dialog from './Dialog.svelte';\n\nexport default {\n  component: Dialog,\n};\n\nexport const Opens = {\n  play: async ({ canvas, userEvent }) => {\n    // Click on a button and assert that a dialog appears\n    const button = canvas.getByRole('button', { name: 'Open Modal' });\n    await userEvent.click(button);\n    await expect(canvas.getByRole('dialog')).toBeInTheDocument();\n  },\n};\n```\n\n```ts filename=\"Dialog.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\nimport { expect } from 'storybook/test';\n\nconst meta: Meta = {\n  component: 'demo-dialog',\n};\nexport default meta;\n\ntype Story = StoryObj;\n\nexport const Opens: Story = {\n  play: async ({ canvas, userEvent }) => {\n    // Click on a button and assert that a dialog appears\n    const button = canvas.getByRole('button', { name: 'Open Modal' });\n    await userEvent.click(button);\n    await expect(canvas.getByRole('dialog')).toBeInTheDocument();\n  },\n};\n```\n\n```js filename=\"Dialog.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { expect } from 'storybook/test';\n\nexport default {\n  component: 'demo-dialog',\n};\n\nexport const Opens = {\n  play: async ({ canvas, userEvent }) => {\n    // Click on a button and assert that a dialog appears\n    const button = canvas.getByRole('button', { name: 'Open Modal' });\n    await userEvent.click(button);\n    await expect(canvas.getByRole('dialog')).toBeInTheDocument();\n  },\n};\n```\n\n```js filename=\"Dialog.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-dialog',\n});\n\nexport const Opens = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    // Click on a button and assert that a dialog appears\n    const button = canvas.getByRole('button', { name: 'Open Modal' });\n    await userEvent.click(button);\n    await expect(canvas.getByRole('dialog')).toBeInTheDocument();\n  },\n});\n```\n\n```ts filename=\"Dialog.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-dialog',\n});\n\nexport const Opens = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    // Click on a button and assert that a dialog appears\n    const button = canvas.getByRole('button', { name: 'Open Modal' });\n    await userEvent.click(button);\n    await expect(canvas.getByRole('dialog')).toBeInTheDocument();\n  },\n});\n```\n\n```ts filename=\"Dialog.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { Dialog } from './Dialog';\n\nconst meta = preview.meta({\n  component: Dialog,\n});\n\nexport const Opens = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    // Click on a button and assert that a dialog appears\n    const button = canvas.getByRole('button', { name: 'Open Modal' });\n    await userEvent.click(button);\n    await expect(canvas.getByRole('dialog')).toBeInTheDocument();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Dialog.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { Dialog } from './Dialog';\n\nconst meta = preview.meta({\n  component: Dialog,\n});\n\nexport const Opens = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    // Click on a button and assert that a dialog appears\n    const button = canvas.getByRole('button', { name: 'Open Modal' });\n    await userEvent.click(button);\n    await expect(canvas.getByRole('dialog')).toBeInTheDocument();\n  },\n});\n```\n\n```ts filename=\"Dialog.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport Dialog from './Dialog.vue';\n\nconst meta = preview.meta({\n  component: Dialog,\n});\n\nexport const Opens = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    // Click on a button and assert that a dialog appears\n    const button = canvas.getByRole('button', { name: 'Open Modal' });\n    await userEvent.click(button);\n    await expect(canvas.getByRole('dialog')).toBeInTheDocument();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Dialog.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { fn, expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport Dialog from './Dialog.vue';\n\nconst meta = preview.meta({\n  component: Dialog,\n});\n\nexport const Opens = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    // Click on a button and assert that a dialog appears\n    const button = canvas.getByRole('button', { name: 'Open Modal' });\n    await userEvent.click(button);\n    await expect(canvas.getByRole('dialog')).toBeInTheDocument();\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/list-story-expanded.md",
    "content": "```ts filename=\"List.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, type StoryObj, moduleMetadata } from '@storybook/angular';\n\nimport { CommonModule } from '@angular/common';\n\nimport { List } from './list.component';\nimport { ListItem } from './list-item.component';\n\nconst meta: Meta<List> = {\n  component: List,\n  decorators: [\n    moduleMetadata({\n      declarations: [List, ListItem],\n      imports: [CommonModule],\n    }),\n  ],\n};\n\nexport default meta;\ntype Story = StoryObj<List>;\n\n// Always an empty list, not super interesting\nexport const Empty: Story = {\n  render: (args) => ({\n    props: args,\n    template: '<app-list></app-list>',\n  }),\n};\n\nexport const OneItem: Story = {\n  render: (args) => ({\n    props: args,\n    template: `\n      <app-list>\n        <app-list-item></app-list-item>\n      </app-list>`,\n  }),\n};\n\nexport const ManyItems: Story = {\n  render: (args) => ({\n    props: args,\n    template: `\n      <app-list>\n        <app-list-item></app-list-item>\n        <app-list-item></app-list-item>\n        <app-list-item></app-list-item>\n      </app-list>\n    `,\n  }),\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { CommonModule } from '@angular/common';\n\nimport { moduleMetadata } from '@storybook/angular';\n\nimport preview from '../.storybook/preview';\n\nimport { List } from './list.component';\nimport { ListItem } from './list-item.component';\n\nconst meta = preview.meta({\n  component: List,\n  decorators: [\n    moduleMetadata({\n      declarations: [List, ListItem],\n      imports: [CommonModule],\n    }),\n  ],\n});\n\n// Always an empty list, not super interesting\nexport const Empty = meta.story({\n  render: (args) => ({\n    props: args,\n    template: '<app-list></app-list>',\n  }),\n});\n\nexport const OneItem = meta.story({\n  render: (args) => ({\n    props: args,\n    template: `\n      <app-list>\n        <app-list-item></app-list-item>\n      </app-list>`,\n  }),\n});\n\nexport const ManyItems = meta.story({\n  render: (args) => ({\n    props: args,\n    template: `\n      <app-list>\n        <app-list-item></app-list-item>\n        <app-list-item></app-list-item>\n        <app-list-item></app-list-item>\n      </app-list>\n    `,\n  }),\n});\n```\n\n```js filename=\"List.stories.js\" renderer=\"html\" language=\"js\"\nimport { createList } from './List';\nimport { createListItem } from './ListItem';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'List',\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Empty = {\n  render: () => createList(args),\n};\n\nexport const OneItem = {\n  render: (args) => {\n    const list = createList(args);\n    list.appendChild(createListItem());\n    return list;\n  },\n};\n\nexport const ManyItems = {\n  render: (args) => {\n    const list = createList(args);\n    list.appendChild(createListItem());\n    list.appendChild(createListItem());\n    list.appendChild(createListItem());\n    return list;\n  },\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"html\" language=\"ts\"\nimport type { Meta, StoryObj } from '@storybook/html';\n\nimport { createList, ListArgs } from './List';\nimport { createListItem } from './ListItem';\n\nconst meta: Meta<ListArgs> = {\n  title: 'List',\n};\n\nexport default meta;\ntype Story = StoryObj<ListArgs>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Empty: Story = {\n  render: () => createList(args),\n};\n\nexport const OneItem: Story = {\n  render: (args) => {\n    const list = createList(args);\n    list.appendChild(createListItem());\n    return list;\n  },\n};\n\nexport const ManyItems: Story = {\n  render: (args) => {\n    const list = createList(args);\n    list.appendChild(createListItem());\n    list.appendChild(createListItem());\n    list.appendChild(createListItem());\n    return list;\n  },\n};\n```\n\n```jsx filename=\"List.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\nexport default {\n  component: List,\n};\n\nexport const Empty = {};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const OneItem = {\n  render: (args) => (\n    <List {...args}>\n      <ListItem />\n    </List>\n  ),\n};\n\nexport const ManyItems = {\n  render: (args) => (\n    <List {...args}>\n      <ListItem />\n      <ListItem />\n      <ListItem />\n    </List>\n  ),\n};\n```\n\n```tsx filename=\"List.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\nconst meta = {\n  component: List,\n} satisfies Meta<typeof List>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Empty: Story = {};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const OneItem: Story = {\n  render: (args) => (\n    <List {...args}>\n      <ListItem />\n    </List>\n  ),\n};\n\nexport const ManyItems: Story = {\n  render: (args) => (\n    <List {...args}>\n      <ListItem />\n      <ListItem />\n      <ListItem />\n    </List>\n  ),\n};\n```\n\n```js filename=\"List.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\nexport default {\n  component: List,\n};\n\nexport const Empty = {};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const OneItem = {\n  render: (args) => (\n    <List {...args}>\n      <ListItem />\n    </List>\n  ),\n};\n\nexport const ManyItems = {\n  render: (args) => (\n    <List {...args}>\n      <ListItem />\n      <ListItem />\n      <ListItem />\n    </List>\n  ),\n};\n```\n\n```tsx filename=\"List.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\nconst meta = {\n  component: List,\n} satisfies Meta<typeof List>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Empty: Story = {};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const OneItem: Story = {\n  render: (args) => (\n    <List {...args}>\n      <ListItem />\n    </List>\n  ),\n};\n\nexport const ManyItems: Story = {\n  render: (args) => (\n    <List {...args}>\n      <ListItem />\n      <ListItem />\n      <ListItem />\n    </List>\n  ),\n};\n```\n\n```svelte filename=\"List.stories.svelte\" renderer=\"svelte\" language=\"js\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import List from './List.svelte';\n  import ListItem from './ListItem.svelte';\n\n  const { Story } = defineMeta({\n    component: List,\n  });\n</script>\n\n<Story name=\"Empty\" />\n\n<Story name=\"One Item\">\n  {#snippet template(args)}\n    <List {...args} >\n      <ListItem />\n    </List>\n  {/snippet}\n</Story>\n\n<Story name=\"Many Items\">\n  {#snippet template(args)}\n    <List {...args} >\n      <ListItem />\n      <ListItem />\n      <ListItem />\n    </List>\n  {/snippet}\n</Story>\n```\n\n```svelte filename=\"List.stories.svelte\" renderer=\"svelte\" language=\"ts\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import List from './List.svelte';\n  import ListItem from './ListItem.svelte';\n\n  const { Story } = defineMeta({\n    component: List,\n  });\n</script>\n\n<Story name=\"Empty\" />\n\n<Story name=\"One Item\">\n  {#snippet template(args)}\n    <List {...args} >\n      <ListItem />\n    </List>\n  {/snippet}\n</Story>\n\n<Story name=\"Many Items\">\n  {#snippet template(args)}\n    <List {...args} >\n      <ListItem />\n      <ListItem />\n      <ListItem />\n    </List>\n  {/snippet}\n</Story>\n```\n\n```js filename=\"List.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport List from './ListComponent.vue';\nimport ListItem from './ListItem.vue';\n\nexport default {\n  component: List,\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Empty = {\n  render: () => ({\n    components: { List },\n    template: '<List/>',\n  }),\n};\n\nexport const OneItem = {\n  render: () => ({\n    components: { List, ListItem },\n    template: `\n      <List>\n        <list-item/>\n      </List>`,\n  }),\n};\n\nexport const ManyItems = {\n  render: () => ({\n    components: { List, ListItem },\n    template: `\n      <List>\n        <list-item/>\n        <list-item/>\n        <list-item/>\n      </List>`,\n  }),\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport List from './ListComponent.vue';\nimport ListItem from './ListItem.vue';\n\nconst meta = {\n  component: List,\n} satisfies Meta<typeof List>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Empty: Story = {\n  render: () => ({\n    components: { List },\n    template: '<List/>',\n  }),\n};\n\nexport const OneItem: Story = {\n  render: () => ({\n    components: { List, ListItem },\n    template: `\n      <List>\n        <list-item/>\n      </List>`,\n  }),\n};\n\nexport const ManyItems: Story = {\n  render: (args) => ({\n    components: { List, ListItem },\n    template: `\n      <List>\n        <list-item/>\n        <list-item/>\n        <list-item/>\n      </List>`,\n  }),\n};\n```\n\n```js filename=\"List.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nexport default {\n  component: 'demo-list',\n};\n\nexport const Empty = {\n  render: () => html`<demo-list></demo-list>`,\n};\n\nexport const OneItem = {\n  render: () => html`\n    <demo-list>\n      <demo-list-item></demo-list-item>\n    </demo-list>\n  `,\n};\n\nexport const ManyItems = {\n  render: () => html`\n    <demo-list>\n      <demo-list-item></demo-list-item>\n      <demo-list-item></demo-list-item>\n      <demo-list-item></demo-list-item>\n    </demo-list>\n  `,\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nconst meta: Meta = {\n  component: 'demo-list',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Empty: Story = {\n  render: () => html`<demo-list></demo-list>`,\n};\n\nexport const OneItem: Story = {\n  render: () => html`\n    <demo-list>\n      <demo-list-item></demo-list-item>\n    </demo-list>\n  `,\n};\n\nexport const ManyItems: Story = {\n  render: () => html`\n    <demo-list>\n      <demo-list-item></demo-list-item>\n      <demo-list-item></demo-list-item>\n      <demo-list-item></demo-list-item>\n    </demo-list>\n  `,\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-list',\n});\n\nexport const Empty = meta.story({\n  render: () => html`<demo-list></demo-list>`,\n});\n\nexport const OneItem = meta.story({\n  render: () => html`\n    <demo-list>\n      <demo-list-item></demo-list-item>\n    </demo-list>\n  `,\n});\n\nexport const ManyItems = meta.story({\n  render: () => html`\n    <demo-list>\n      <demo-list-item></demo-list-item>\n      <demo-list-item></demo-list-item>\n      <demo-list-item></demo-list-item>\n    </demo-list>\n  `,\n});\n```\n\n```js filename=\"List.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-list',\n});\n\nexport const Empty = meta.story({\n  render: () => html`<demo-list></demo-list>`,\n});\n\nexport const OneItem = meta.story({\n  render: () => html`\n    <demo-list>\n      <demo-list-item></demo-list-item>\n    </demo-list>\n  `,\n});\n\nexport const ManyItems = meta.story({\n  render: () => html`\n    <demo-list>\n      <demo-list-item></demo-list-item>\n      <demo-list-item></demo-list-item>\n      <demo-list-item></demo-list-item>\n    </demo-list>\n  `,\n});\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport List from './ListComponent.vue';\nimport ListItem from './ListItem.vue';\n\nconst meta = preview.meta({\n  component: List,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Empty = meta.story({\n  render: () => ({\n    components: { List },\n    template: '<List/>',\n  }),\n});\n\nexport const OneItem = meta.story({\n  render: () => ({\n    components: { List, ListItem },\n    template: `\n      <List>\n        <list-item/>\n      </List>`,\n  }),\n});\n\nexport const ManyItems = meta.story({\n  render: () => ({\n    components: { List, ListItem },\n    template: `\n      <List>\n        <list-item/>\n        <list-item/>\n        <list-item/>\n      </List>`,\n  }),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"List.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport List from './ListComponent.vue';\nimport ListItem from './ListItem.vue';\n\nconst meta = preview.meta({\n  component: List,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Empty = meta.story({\n  render: () => ({\n    components: { List },\n    template: '<List/>',\n  }),\n});\n\nexport const OneItem = meta.story({\n  render: () => ({\n    components: { List, ListItem },\n    template: `\n      <List>\n        <list-item/>\n      </List>`,\n  }),\n});\n\nexport const ManyItems = meta.story({\n  render: () => ({\n    components: { List, ListItem },\n    template: `\n      <List>\n        <list-item/>\n        <list-item/>\n        <list-item/>\n      </List>`,\n  }),\n});\n```\n\n```tsx filename=\"List.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\nconst meta = preview.meta({\n  component: List,\n});\n\nexport const Empty = meta.story();\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const OneItem = meta.story({\n  render: (args) => (\n    <List {...args}>\n      <ListItem />\n    </List>\n  ),\n});\n\nexport const ManyItems = meta.story({\n  render: (args) => (\n    <List {...args}>\n      <ListItem />\n      <ListItem />\n      <ListItem />\n    </List>\n  ),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"List.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\nconst meta = preview.meta({\n  component: List,\n});\n\nexport const Empty = meta.story();\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const OneItem = meta.story({\n  render: (args) => (\n    <List {...args}>\n      <ListItem />\n    </List>\n  ),\n});\n\nexport const ManyItems = meta.story({\n  render: (args) => (\n    <List {...args}>\n      <ListItem />\n      <ListItem />\n      <ListItem />\n    </List>\n  ),\n});\n```\n"
  },
  {
    "path": "docs/_snippets/list-story-reuse-data.md",
    "content": "```ts filename=\"List.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, type StoryObj, moduleMetadata } from '@storybook/angular';\n\nimport { CommonModule } from '@angular/common';\n\nimport { List } from './list.component';\nimport { ListItem } from './list-item.component';\n\n//👇 We're importing the necessary stories from ListItem\nimport { Selected, Unselected } from './ListItem.stories';\n\nconst meta: Meta<List> = {\n  component: List,\n  decorators: [\n    moduleMetadata({\n      declarations: [List, ListItem],\n      imports: [CommonModule],\n    }),\n  ],\n};\n\nexport default meta;\ntype Story = StoryObj<List>;\n\nexport const ManyItems: Story = {\n  args: {\n    Selected: Selected.args.isSelected,\n    Unselected: Unselected.args.isSelected,\n  },\n  render: (args) => ({\n    props: args,\n    template: `\n      <app-list>\n        <app-list-item [isSelected]=\"Selected\"></app-list-item>\n        <app-list-item [isSelected]=\"Unselected\"></app-list-item>\n        <app-list-item [isSelected]=\"Unselected\"></app-list-item>\n      </app-list>\n    `,\n  }),\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { CommonModule } from '@angular/common';\n\nimport { moduleMetadata } from '@storybook/angular';\n\nimport preview from '../.storybook/preview';\n\nimport { List } from './list.component';\nimport { ListItem } from './list-item.component';\n\n//👇 We're importing the necessary stories from ListItem\nimport { Selected, Unselected } from './ListItem.stories';\n\nconst meta = preview.meta({\n  component: List,\n  decorators: [\n    moduleMetadata({\n      declarations: [List, ListItem],\n      imports: [CommonModule],\n    }),\n  ],\n});\n\nexport const ManyItems = meta.story({\n  args: {\n    Selected: Selected.input.args.isSelected,\n    Unselected: Unselected.input.args.isSelected,\n  },\n  render: (args) => ({\n    props: args,\n    template: `\n      <app-list>\n        <app-list-item [isSelected]=\"Selected\"></app-list-item>\n        <app-list-item [isSelected]=\"Unselected\"></app-list-item>\n        <app-list-item [isSelected]=\"Unselected\"></app-list-item>\n      </app-list>\n    `,\n  }),\n});\n```\n\n```js filename=\"List.stories.js\" renderer=\"html\" language=\"js\"\nimport { createList } from './List';\nimport { createListItem } from './ListItem';\n\n// 👇 We're importing the necessary stories from ListItem\nimport { Selected, Unselected } from './ListItem.stories';\n\nexport default {\n  title: 'List',\n};\n\nexport const ManyItems = {\n  render: (args) => {\n    const list = createList(args);\n    list.appendChild(createListItem(Selected.args));\n    list.appendChild(createListItem(Unselected.args));\n    list.appendChild(createListItem(Unselected.args));\n    return list;\n  },\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"html\" language=\"ts\"\nimport type { Meta, StoryObj } from '@storybook/html';\n\nimport { createList, ListArgs } from './List';\nimport { createListItem } from './ListItem';\n\n// 👇 We're importing the necessary stories from ListItem\nimport { Selected, Unselected } from './ListItem.stories';\n\nconst meta: Meta<ListArgs> = {\n  title: 'List',\n};\n\nexport default meta;\ntype Story = StoryObj<ListArgs>;\n\nexport const ManyItems: Story = {\n  render: (args) => {\n    const list = createList(args);\n    list.appendChild(createListItem(Selected.args));\n    list.appendChild(createListItem(Unselected.args));\n    list.appendChild(createListItem(Unselected.args));\n    return list;\n  },\n};\n```\n\n```jsx filename=\"List.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport * as React from 'react';\n\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\n//👇 We're importing the necessary stories from ListItem\nimport { Selected, Unselected } from './ListItem.stories';\n\nexport default {\n  component: List,\n};\n\nexport const ManyItems = {\n  render: (args) => (\n    <List {...args}>\n      <ListItem {...Selected.args} />\n      <ListItem {...Unselected.args} />\n      <ListItem {...Unselected.args} />\n    </List>\n  ),\n};\n```\n\n```tsx filename=\"List.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\nimport * as React from 'react';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\n//👇 We're importing the necessary stories from ListItem\nimport { Selected, Unselected } from './ListItem.stories';\n\nconst meta = {\n  component: List,\n} satisfies Meta<typeof List>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ManyItems: Story = {\n  render: (args) => (\n    <List {...args}>\n      <ListItem {...Selected.args} />\n      <ListItem {...Unselected.args} />\n      <ListItem {...Unselected.args} />\n    </List>\n  ),\n};\n```\n\n```jsx filename=\"List.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\n//👇 We're importing the necessary stories from ListItem\nimport { Selected, Unselected } from './ListItem.stories';\n\nexport default {\n  component: List,\n};\n\nexport const ManyItems = {\n  render: (args) => (\n    <List {...args}>\n      <ListItem {...Selected.args} />\n      <ListItem {...Unselected.args} />\n      <ListItem {...Unselected.args} />\n    </List>\n  ),\n};\n```\n\n```tsx filename=\"List.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\n//👇 We're importing the necessary stories from ListItem\nimport { Selected, Unselected } from './ListItem.stories';\n\nconst meta = {\n  component: List,\n} satisfies Meta<typeof List>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ManyItems: Story = {\n  render: (args) => (\n    <List {...args}>\n      <ListItem {...Selected.args} />\n      <ListItem {...Unselected.args} />\n      <ListItem {...Unselected.args} />\n    </List>\n  ),\n};\n```\n\n```svelte filename=\"List.stories.svelte\" renderer=\"svelte\" language=\"js\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import List from './List.svelte';\n  import ListItem from './ListItem.svelte';\n\n  //👇 We're importing the necessary stories from ListItem\n  import { Selected, Unselected } from './ListItem.stories.svelte';\n\n  const { Story } = defineMeta({\n    component: List,\n  });\n</script>\n\n<Story name=\"Many Items\">\n  {#snippet children(args)}\n    <List {...args}>\n      <ListItem {...Selected.args} />\n      <ListItem {...Unselected.args} />\n      <ListItem {...Unselected.args} />\n    </List>\n  {/snippet}\n</Story>\n```\n\n```svelte filename=\"List.stories.svelte\" renderer=\"svelte\" language=\"ts\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import List from './List.svelte';\n  import ListItem from './ListItem.svelte';\n\n  //👇 We're importing the necessary stories from ListItem\n  import { Selected, Unselected } from './ListItem.stories.svelte';\n\n  const { Story } = defineMeta({\n    component: List,\n  });\n</script>\n\n<Story name=\"Many Items\">\n  {#snippet children(args)}\n    <List {...args}>\n      <ListItem {...Selected.args} />\n      <ListItem {...Unselected.args} />\n      <ListItem {...Unselected.args} />\n    </List>\n  {/snippet}\n</Story>\n```\n\n```js filename=\"List.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport List from './ListComponent.vue';\nimport ListItem from './ListItem.vue';\n\n//👇 We're importing the necessary stories from ListItem\nimport { Selected, Unselected } from './ListItem.stories';\n\nexport default {\n  component: List,\n};\n\nexport const ManyItems = {\n  render: (args) => ({\n    components: { List, ListItem },\n    setup() {\n      return { ...args };\n    },\n    template: `\n      <List v-bind=\"args\">\n        <list-item :isSelected=\"Selected\"/>\n        <list-item :isSelected=\"Unselected\"/>\n        <list-item :isSelected=\"Unselected\"/>\n      </List>`,\n  }),\n  args: {\n    Selected: Selected.args.isSelected,\n    Unselected: Unselected.args.isSelected,\n  },\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport List from './ListComponent.vue';\nimport ListItem from './ListItem.vue';\n\n//👇 We're importing the necessary stories from ListItem\nimport { Selected, Unselected } from './ListItem.stories';\n\nconst meta = {\n  component: List,\n} satisfies Meta<typeof List>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ManyItems: Story = {\n  render: (args) => ({\n    components: { List, ListItem },\n    setup() {\n      return { ...args };\n    },\n    template: `\n      <List v-bind=\"args\">\n        <list-item :isSelected=\"Selected\"/>\n        <list-item :isSelected=\"Unselected\"/>\n        <list-item :isSelected=\"Unselected\"/>\n      </List>`,\n  }),\n  args: {\n    Selected: Selected.args.isSelected,\n    Unselected: Unselected.args.isSelected,\n  },\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport List from './ListComponent.vue';\nimport ListItem from './ListItem.vue';\n\n//👇 We're importing the necessary stories from ListItem\nimport { Selected, Unselected } from './ListItem.stories';\n\nconst meta = preview.meta({\n  component: List,\n});\n\nexport const ManyItems = meta.story({\n  render: (args) => ({\n    components: { List, ListItem },\n    setup() {\n      return { ...args };\n    },\n    template: `\n      <List v-bind=\"args\">\n        <list-item :isSelected=\"Selected\"/>\n        <list-item :isSelected=\"Unselected\"/>\n        <list-item :isSelected=\"Unselected\"/>\n      </List>`,\n  }),\n  args: {\n    Selected: Selected.input.args.isSelected,\n    Unselected: Unselected.input.args.isSelected,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"List.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport List from './ListComponent.vue';\nimport ListItem from './ListItem.vue';\n\n//👇 We're importing the necessary stories from ListItem\nimport { Selected, Unselected } from './ListItem.stories';\n\nconst meta = preview.meta({\n  component: List,\n});\n\nexport const ManyItems = meta.story({\n  render: (args) => ({\n    components: { List, ListItem },\n    setup() {\n      return { ...args };\n    },\n    template: `\n      <List v-bind=\"args\">\n        <list-item :isSelected=\"Selected\"/>\n        <list-item :isSelected=\"Unselected\"/>\n        <list-item :isSelected=\"Unselected\"/>\n      </List>`,\n  }),\n  args: {\n    Selected: Selected.input.args.isSelected,\n    Unselected: Unselected.input.args.isSelected,\n  },\n});\n```\n\n```tsx filename=\"List.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\nimport preview from '../.storybook/preview';\n\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\n//👇 We're importing the necessary stories from ListItem\nimport { Selected, Unselected } from './ListItem.stories';\n\nconst meta = preview.meta({\n  component: List,\n});\n\nexport const ManyItems = meta.story({\n  render: (args) => (\n    <List {...args}>\n      <ListItem {...Selected.input.args} />\n      <ListItem {...Unselected.input.args} />\n      <ListItem {...Unselected.input.args} />\n    </List>\n  ),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"List.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\nimport preview from '../.storybook/preview';\n\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\n//👇 We're importing the necessary stories from ListItem\nimport { Selected, Unselected } from './ListItem.stories';\n\nconst meta = preview.meta({\n  component: List,\n});\n\nexport const ManyItems = meta.story({\n  render: (args) => (\n    <List {...args}>\n      <ListItem {...Selected.input.args} />\n      <ListItem {...Unselected.input.args} />\n      <ListItem {...Unselected.input.args} />\n    </List>\n  ),\n});\n```\n"
  },
  {
    "path": "docs/_snippets/list-story-starter.md",
    "content": "```ts filename=\"List.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, type StoryObj, moduleMetadata } from '@storybook/angular';\n\nimport { CommonModule } from '@angular/common';\n\nimport { List } from './list.component';\n\nconst meta: Meta<List> = {\n  component: List,\n  decorators: [\n    moduleMetadata({\n      declarations: [List],\n      imports: [CommonModule],\n    }),\n  ],\n};\n\nexport default meta;\ntype Story = StoryObj<List>;\n\n// Always an empty list, not super interesting\nexport const Empty: Story = {\n  render: (args) => ({\n    props: args,\n    template: `<app-list></app-list>`,\n  }),\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { CommonModule } from '@angular/common';\n\nimport { moduleMetadata } from '@storybook/angular';\n\nimport preview from '../.storybook/preview';\n\nimport { List } from './list.component';\n\nconst meta = preview.meta({\n  component: List,\n  decorators: [\n    moduleMetadata({\n      declarations: [List],\n      imports: [CommonModule],\n    }),\n  ],\n});\n\n// Always an empty list, not super interesting\nexport const Empty = meta.story({\n  render: (args) => ({\n    props: args,\n    template: `<app-list></app-list>`,\n  }),\n});\n```\n\n```js filename=\"List.stories.js\" renderer=\"html\" language=\"js\"\nimport { createList } from './List';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'List',\n};\n\n// Always an empty list, not super interesting\nexport const Empty = {\n  render: (args) => createList(args),\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"html\" language=\"ts\"\nimport type { Meta, StoryObj } from '@storybook/html';\n\nimport { createList, ListArgs } from './List';\n\nconst meta: Meta<ListArgs> = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'List',\n};\n\nexport default meta;\ntype Story = StoryObj<ListArgs>;\n\n// Always an empty list, not super interesting\nexport const Empty: Story = {\n  render: (args) => createList(args),\n};\n```\n\n```js filename=\"List.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { List } from './List';\n\nexport default {\n  component: List,\n};\n\n// Always an empty list, not super interesting\nexport const Empty = {};\n```\n\n```ts filename=\"List.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { List } from './List';\n\nconst meta = {\n  component: List,\n} satisfies Meta<typeof List>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// Always an empty list, not super interesting\nexport const Empty: Story = {};\n```\n\n```js filename=\"List.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { List } from './List';\n\nexport default {\n  component: List,\n};\n\n// Always an empty list, not super interesting\nexport const Empty = {};\n```\n\n```tsx filename=\"List.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { List } from './List';\n\nconst meta = {\n  component: List,\n} satisfies Meta<typeof List>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// Always an empty list, not super interesting\nexport const Empty: Story = {};\n```\n\n```svelte filename=\"List.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import List from './List.svelte';\n\n  const { Story } = defineMeta({\n    component: List,\n  });\n</script>\n\n<!-- Always an empty list, not super interesting -->\n<Story name=\"Empty\" />\n```\n\n```js filename=\"List.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport List from './List.svelte';\n\nexport default {\n  component: List,\n};\n\n// Always an empty list, not super interesting\nexport const Empty = {};\n```\n\n```svelte filename=\"List.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import List from './List.svelte';\n\n  const { Story } = defineMeta({\n    component: List,\n  });\n</script>\n\n<!-- Always an empty list, not super interesting -->\n<Story name=\"Empty\" />\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport List from './List.svelte';\n\nconst meta = {\n  component: List,\n} satisfies Meta<typeof List>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// Always an empty list, not super interesting\nexport const Empty: Story = {};\n```\n\n```js filename=\"List.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport List from './ListComponent.vue';\n\nexport default {\n  component: List,\n};\n\n// Always an empty list, not super interesting\nexport const Empty = {\n  render: () => ({\n    components: { List },\n    template: '<List/>',\n  }),\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport List from './ListComponent.vue';\n\nconst meta = {\n  component: List,\n} satisfies Meta<typeof List>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// Always an empty list, not super interesting\nexport const Empty: Story = {\n  render: () => ({\n    components: { List },\n    template: '<List/>',\n  }),\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport List from './ListComponent.vue';\n\nconst meta = preview.meta({\n  component: List,\n});\n\n// Always an empty list, not super interesting\nexport const Empty = meta.story({\n  render: () => ({\n    components: { List },\n    template: '<List/>',\n  }),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"List.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport List from './ListComponent.vue';\n\nconst meta = preview.meta({\n  component: List,\n});\n\n// Always an empty list, not super interesting\nexport const Empty = meta.story({\n  render: () => ({\n    components: { List },\n    template: '<List/>',\n  }),\n});\n```\n\n```js filename=\"List.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nexport default {\n  component: 'demo-list',\n};\n\n// Always an empty list, not super interesting\nexport const Empty = {\n  render: () => html`<demo-list></demo-list>`,\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-list',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\n// Always an empty list, not super interesting\nexport const Empty: Story = {\n  render: () => html`<demo-list></demo-list>`,\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-list',\n});\n\n// Always an empty list, not super interesting\nexport const Empty = meta.story({\n  render: () => html`<demo-list></demo-list>`,\n});\n```\n\n```js filename=\"List.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-list',\n});\n\n// Always an empty list, not super interesting\nexport const Empty = meta.story({\n  render: () => html`<demo-list></demo-list>`,\n});\n```\n\n```ts filename=\"List.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { List } from './List';\n\nconst meta = preview.meta({\n  component: List,\n});\n\n// Always an empty list, not super interesting\nexport const Empty = meta.story();\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"List.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { List } from './List';\n\nconst meta = preview.meta({\n  component: List,\n});\n\n// Always an empty list, not super interesting\nexport const Empty = meta.story();\n```\n"
  },
  {
    "path": "docs/_snippets/list-story-template.md",
    "content": "```ts filename=\"List.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, type StoryObj, moduleMetadata } from '@storybook/angular';\n\nimport { CommonModule } from '@angular/common';\n\nimport { List } from './list.component';\nimport { ListItem } from './list-item.component';\n\n//👇 Imports a specific story from ListItem stories\nimport { Unchecked } from './ListItem.stories';\n\nconst meta: Meta<List> = {\n  component: List,\n  decorators: [\n    moduleMetadata({\n      declarations: [List, ListItem],\n      imports: [CommonModule],\n    }),\n  ],\n};\n\nexport default meta;\ntype Story = StoryObj<List>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nconst ListTemplate: Story = {\n  render: (args) => ({\n    props: args,\n    template: `\n      <app-list>\n        <div *ngFor=\"let item of items\">\n          <app-list-item [item]=\"item\"></app-list-item>\n        </div>\n      </app-list>\n    `,\n  }),\n};\n\nexport const Empty: Story = {\n  ...ListTemplate,\n  args: { items: [] },\n};\n\nexport const OneItem: Story = {\n  ...ListTemplate,\n  args: {\n    items: [{ ...Unchecked.args }],\n  },\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { CommonModule } from '@angular/common';\n\nimport { moduleMetadata } from '@storybook/angular';\n\nimport preview from '../.storybook/preview';\n\nimport { List } from './list.component';\nimport { ListItem } from './list-item.component';\n\n//👇 Imports a specific story from ListItem stories\nimport { Unchecked } from './ListItem.stories';\n\nconst meta = preview.meta({\n  component: List,\n  decorators: [\n    moduleMetadata({\n      declarations: [List, ListItem],\n      imports: [CommonModule],\n    }),\n  ],\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nconst ListTemplate = {\n  render: (args) => ({\n    props: args,\n    template: `\n      <app-list>\n        <div *ngFor=\"let item of items\">\n          <app-list-item [item]=\"item\"></app-list-item>\n        </div>\n      </app-list>\n    `,\n  }),\n};\n\nexport const Empty = meta.story({\n  ...ListTemplate,\n  args: { items: [] },\n});\n\nexport const OneItem = Empty.extend({\n  args: {\n    items: [{ ...Unchecked.input.args }],\n  },\n});\n```\n\n```jsx filename=\"List.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\n//👇 Imports a specific story from ListItem stories\nimport { Unchecked } from './ListItem.stories';\n\nexport default {\n  component: List,\n};\n\n//👇 The ListTemplate construct will be spread to the existing stories.\nconst ListTemplate = {\n  render: ({ items, ...args }) => {\n    return (\n      <List>\n        {items.map((item) => (\n          <ListItem {...item} />\n        ))}\n      </List>\n    );\n  },\n};\n\nexport const Empty = {\n  ...ListTemplate,\n  args: {\n    items: [],\n  },\n};\n\nexport const OneItem = {\n  ...ListTemplate,\n  args: {\n    items: [{ ...Unchecked.args }],\n  },\n};\n```\n\n```tsx filename=\"List.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\n//👇 Imports a specific story from ListItem stories\nimport { Unchecked } from './ListItem.stories';\n\nconst meta = {\n  component: List,\n} satisfies Meta<typeof List>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n//👇 The ListTemplate construct will be spread to the existing stories.\nconst ListTemplate: Story = {\n  render: ({ items, ...args }) => {\n    return (\n      <List>\n        {items.map((item) => (\n          <ListItem {...item} />\n        ))}\n      </List>\n    );\n  },\n};\n\nexport const Empty = {\n  ...ListTemplate,\n  args: {\n    items: [],\n  },\n};\n\nexport const OneItem = {\n  ...ListTemplate,\n  args: {\n    items: [{ ...Unchecked.args }],\n  },\n};\n```\n\n```jsx filename=\"List.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\n//👇 Imports a specific story from ListItem stories\nimport { Unchecked } from './ListItem.stories';\n\nexport default {\n  component: List,\n};\n\n//👇 The ListTemplate construct will be spread to the existing stories.\nconst ListTemplate = {\n  render: ({ items, ...args }) => {\n    return (\n      <List>\n        {items.map((item) => (\n          <ListItem {...item} />\n        ))}\n      </List>\n    );\n  },\n};\n\nexport const Empty = {\n  ...ListTemplate,\n  args: {\n    items: [],\n  },\n};\n\nexport const OneItem = {\n  ...ListTemplate,\n  args: {\n    items: [{ ...Unchecked.args }],\n  },\n};\n```\n\n```tsx filename=\"List.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\n//👇 Imports a specific story from ListItem stories\nimport { Unchecked } from './ListItem.stories';\n\nconst meta = {\n  component: List,\n} satisfies Meta<typeof List>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n//👇 The ListTemplate construct will be spread to the existing stories.\nconst ListTemplate: Story = {\n  render: ({ items, ...args }) => {\n    return (\n      <List>\n        {items.map((item) => (\n          <ListItem {...item} />\n        ))}\n      </List>\n    );\n  },\n};\n\nexport const Empty = {\n  ...ListTemplate,\n  args: {\n    items: [],\n  },\n};\n\nexport const OneItem = {\n  ...ListTemplate,\n  args: {\n    items: [{ ...Unchecked.args }],\n  },\n};\n```\n\n```svelte filename=\"List.stories.svelte\" renderer=\"svelte\" language=\"js\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import List from './List.svelte';\n  import ListItem from './ListItem.svelte';\n\n  //👇 Imports a specific story from ListItem stories\n  import { Unchecked } from './ListItem.stories.svelte';\n\n  const { Story } = defineMeta({\n    component: List,\n  });\n</script>\n\n<!--\n  The template construct will be spread to the existing stories.\n  It's based on Svelte's snippet syntax allowing you share the same UI with small variations.\n-->\n{#snippet template(args)}\n  <List {...args}>\n    {#each args.items as item}\n      <ListItem {...item} />\n    {/each}\n  </List>\n{/snippet}\n\n<Story name=\"Empty\" args={{ items: [] }} {template} />\n\n<Story\n  name=\"One Item\"\n  args={{\n    items: [{ ...Unchecked.args }],\n  }}\n  {template}\n/>\n```\n\n```svelte filename=\"List.stories.svelte\" renderer=\"svelte\" language=\"ts\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import List from './List.svelte';\n  import ListItem from './ListItem.svelte';\n\n  //👇 Imports a specific story from ListItem stories\n  import { Unchecked } from './ListItem.stories.svelte';\n\n  const { Story } = defineMeta({\n    component: List,\n  });\n</script>\n\n<!--\n  The template construct will be spread to the existing stories.\n  It's based on Svelte's snippet syntax allowing you share the same UI with small variations.\n-->\n{#snippet template(args)}\n  <List {...args}>\n    {#each args.items as item}\n      <ListItem {...item} />\n    {/each}\n  </List>\n{/snippet}\n\n<Story name=\"Empty\" args={{ items: [] }} {template} />\n\n<Story\n  name=\"One Item\"\n  args={{\n    items: [{ ...Unchecked.args }],\n  }}\n  {template}\n/>\n```\n\n```js filename=\"List.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport List from './List.vue';\nimport ListItem from './ListItem.vue';\n\n//👇 Imports a specific story from ListItem stories\nimport { Unchecked } from './ListItem.stories';\n\nexport default {\n  component: List,\n};\n\n//👇 The ListTemplate construct will be spread to the existing stories.\nconst ListTemplate = {\n  render: (args) => ({\n    components: { List, ListItem },\n    setup() {\n      return { ...args };\n    },\n    template: `\n      <List v-bind=\"args\">\n        <div v-for=\"item in items\" :key=\"item.title\">\n          <ListItem :item=\"item\"/>\n        </div>\n      </List>\n    `,\n  }),\n};\n\nexport const Empty = {\n  ...ListTemplate,\n  args: {\n    items: [],\n  },\n};\nexport const OneItem = {\n  ...ListTemplate,\n  args: {\n    items: [{ ...Unchecked.args }],\n  },\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport List from './List.vue';\nimport ListItem from './ListItem.vue';\n\n//👇 Imports a specific story from ListItem stories\nimport { Unchecked } from './ListItem.stories';\n\nconst meta = {\n  component: List,\n} satisfies Meta<typeof List>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n//👇 The ListTemplate construct will be spread to the existing stories.\nexport const ListTemplate: Story = {\n  render: (args) => ({\n    components: { List, ListItem },\n    setup() {\n      return { ...args };\n    },\n    template: `\n      <List v-bind=\"args\">\n        <div v-for=\"item in items\" :key=\"item.title\">\n          <ListItem :item=\"item\"/>\n        </div>\n      </List>\n    `,\n  }),\n};\n\nexport const Empty: Story = {\n  ...ListTemplate,\n  args: {\n    items: [],\n  },\n};\nexport const OneItem: Story = {\n  ...ListTemplate,\n  args: {\n    items: [{ ...Unchecked.args }],\n  },\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport List from './List.vue';\nimport ListItem from './ListItem.vue';\n\n//👇 Imports a specific story from ListItem stories\nimport { Unchecked } from './ListItem.stories';\n\nconst meta = preview.meta({\n  component: List,\n});\n\nexport const Empty = meta.story({\n  render: (args) => ({\n    components: { List, ListItem },\n    setup() {\n      return { ...args };\n    },\n    template: `\n      <List v-bind=\"args\">\n        <div v-for=\"item in items\" :key=\"item.title\">\n          <ListItem :item=\"item\"/>\n        </div>\n      </List>\n    `,\n  }),\n  args: {\n    items: [],\n  },\n});\n\nexport const OneItem = Empty.extend({\n  args: {\n    items: [{ ...Unchecked.input.args }],\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"List.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport List from './List.vue';\nimport ListItem from './ListItem.vue';\n\n//👇 Imports a specific story from ListItem stories\nimport { Unchecked } from './ListItem.stories';\n\nconst meta = preview.meta({\n  component: List,\n});\n\nexport const Empty = meta.story({\n  render: (args) => ({\n    components: { List, ListItem },\n    setup() {\n      return { ...args };\n    },\n    template: `\n      <List v-bind=\"args\">\n        <div v-for=\"item in items\" :key=\"item.title\">\n          <ListItem :item=\"item\"/>\n        </div>\n      </List>\n    `,\n  }),\n  args: {\n    items: [],\n  },\n});\n\nexport const OneItem = Empty.extend({\n  args: {\n    items: [{ ...Unchecked.input.args }],\n  },\n});\n```\n\n```js filename=\"List.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\nimport { repeat } from 'lit/directives/repeat.js';\n\nimport { Unchecked } from './ListItem.stories';\n\nexport default {\n  component: 'demo-list',\n};\n\n//👇 The ListTemplate construct will be spread to the existing stories.\nconst ListTemplate = {\n  render: ({ items, ...args }) => {\n    return html`\n      <demo-list>\n        ${repeat(items, (item) => html`<demo-list-item>${item}</demo-list-item>`)}\n      </demo-list>\n    `;\n  },\n};\nexport const Empty = {\n  ...ListTemplate,\n  args: {\n    items: [],\n  },\n};\n\nexport const OneItem = {\n  ...ListTemplate,\n  args: {\n    items: [{ ...Unchecked.args }],\n  },\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\nimport { repeat } from 'lit/directives/repeat.js';\n\nconst meta: Meta = {\n  component: 'demo-list',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\n//👇 The ListTemplate construct will be spread to the existing stories.\nconst ListTemplate = {\n  render: ({ items, ...args }) => {\n    return html`\n      <demo-list>\n        ${repeat(items, (item) => html`<demo-list-item>${item}</demo-list-item>`)}\n      </demo-list>\n    `;\n  },\n};\n\nexport const Empty: Story = {\n  ...ListTemplate,\n  args: {\n    items: [],\n  },\n};\n\nexport const OneItem: Story = {\n  ...ListTemplate,\n  args: {\n    items: [{ ...Unchecked.args }],\n  },\n};\n```\n\n```js filename=\"List.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\nimport { repeat } from 'lit/directives/repeat.js';\n\nimport preview from '../.storybook/preview';\n\nimport { Unchecked } from './ListItem.stories';\n\nconst meta = preview.meta({\n  component: 'demo-list',\n});\n\nexport const Empty = meta.story({\n  render: ({ items, ...args }) => {\n    return html`\n      <demo-list>\n        ${repeat(items, (item) => html`<demo-list-item>${item}</demo-list-item>`)}\n      </demo-list>\n    `;\n  },\n  args: {\n    items: [],\n  },\n});\n\nexport const OneItem = Empty.extend({\n  args: {\n    items: [{ ...Unchecked.input.args }],\n  },\n});\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\nimport { repeat } from 'lit/directives/repeat.js';\n\nimport preview from '../.storybook/preview';\n\nimport { Unchecked } from './ListItem.stories';\n\nconst meta = preview.meta({\n  component: 'demo-list',\n});\n\nexport const Empty = meta.story({\n  render: ({ items, ...args }) => {\n    return html`\n      <demo-list>\n        ${repeat(items, (item) => html`<demo-list-item>${item}</demo-list-item>`)}\n      </demo-list>\n    `;\n  },\n  args: {\n    items: [],\n  },\n});\n\nexport const OneItem = Empty.extend({\n  args: {\n    items: [{ ...Unchecked.input.args }],\n  },\n});\n```\n\n```tsx filename=\"List.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\n//👇 Imports a specific story from ListItem stories\nimport { Unchecked } from './ListItem.stories';\n\nconst meta = preview.meta({\n  component: List,\n});\n\nexport const Empty = meta.story({\n  render: ({ items, ...args }) => {\n    return (\n      <List>\n        {items.map((item) => (\n          <ListItem {...item} />\n        ))}\n      </List>\n    );\n  },\n  args: {\n    items: [],\n  },\n});\n\nexport const OneItem = Empty.extend({\n  args: {\n    items: [{ ...Unchecked.input.args }],\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"List.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\n//👇 Imports a specific story from ListItem stories\nimport { Unchecked } from './ListItem.stories';\n\nconst meta = preview.meta({\n  component: List,\n});\n\nexport const Empty = meta.story({\n  render: ({ items, ...args }) => {\n    return (\n      <List>\n        {items.map((item) => (\n          <ListItem {...item} />\n        ))}\n      </List>\n    );\n  },\n  args: {\n    items: [],\n  },\n});\n\nexport const OneItem = Empty.extend({\n  args: {\n    items: [{ ...Unchecked.input.args }],\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/list-story-unchecked.md",
    "content": "```ts filename=\"List.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, type StoryObj, moduleMetadata } from '@storybook/angular';\n\nimport { CommonModule } from '@angular/common';\n\nimport { List } from './list.component';\nimport { ListItem } from './list-item.component';\n\n//👇 Imports a specific story from ListItem stories\nimport { Unchecked } from './ListItem.stories';\n\nconst meta: Meta<List> = {\n  component: List,\n  decorators: [\n    moduleMetadata({\n      declarations: [List, ListItem],\n      imports: [CommonModule],\n    }),\n  ],\n};\n\nexport default meta;\ntype Story = StoryObj<List>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const OneItem: Story = {\n  render: (args) => ({\n    props: args,\n    template: `\n      <app-list>\n        <app-list-item [item]=\"item\"></app-list-item>\n      </app-list>\n   `,\n  }),\n  args: {\n    ...Unchecked.args,\n  },\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { CommonModule } from '@angular/common';\n\nimport { moduleMetadata } from '@storybook/angular';\n\nimport preview from '../.storybook/preview';\n\nimport { List } from './list.component';\nimport { ListItem } from './list-item.component';\n\n//👇 Imports a specific story from ListItem stories\nimport { Unchecked } from './ListItem.stories';\n\nconst meta = preview.meta({\n  component: List,\n  decorators: [\n    moduleMetadata({\n      declarations: [List, ListItem],\n      imports: [CommonModule],\n    }),\n  ],\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const OneItem = meta.story({\n  render: (args) => ({\n    props: args,\n    template: `\n      <app-list>\n        <app-list-item [item]=\"item\"></app-list-item>\n      </app-list>\n   `,\n  }),\n  args: {\n    ...Unchecked.input.args,\n  },\n});\n```\n\n```jsx filename=\"List.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { List } from './List';\n\n//👇 Instead of importing ListItem, we import the stories\nimport { Unchecked } from './ListItem.stories';\n\nexport default {\n  component: List,\n};\n\nexport const OneItem = {\n  render: (args) => (\n    <List {...args}>\n      <Unchecked {...Unchecked.args} />\n    </List>\n  ),\n};\n```\n\n```tsx filename=\"List.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { List } from './List';\n\n//👇 Instead of importing ListItem, we import the stories\nimport { Unchecked } from './ListItem.stories';\n\nexport const meta = {\n  component: List,\n} satisfies Meta<typeof List>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const OneItem: Story = {\n  render: (args) => (\n    <List {...args}>\n      <Unchecked {...Unchecked.args} />\n    </List>\n  ),\n};\n```\n\n```jsx filename=\"List.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { List } from './List';\n\n//👇 Instead of importing ListItem, we import the stories\nimport { Unchecked } from './ListItem.stories';\n\nexport default {\n  component: List,\n};\n\nexport const OneItem = {\n  render: (args) => (\n    <List {...args}>\n      <Unchecked {...Unchecked.args} />\n    </List>\n  ),\n};\n```\n\n```tsx filename=\"List.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { List } from './List';\n\n//👇 Instead of importing ListItem, we import the stories\nimport { Unchecked } from './ListItem.stories';\n\nexport const meta = {\n  component: List,\n} satisfies Meta<typeof List>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const OneItem: Story = {\n  render: (args) => (\n    <List {...args}>\n      <Unchecked {...Unchecked.args} />\n    </List>\n  ),\n};\n```\n\n```js filename=\"List.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport List from './List.vue';\nimport ListItem from './ListItem.vue';\n\n//👇 Imports a specific story from ListItem stories\nimport { Unchecked } from './ListItem.stories';\n\nexport default {\n  component: List,\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const OneItem = {\n  args: {\n    ...Unchecked.args,\n  },\n  render: (args) => ({\n    components: { List, ListItem },\n    setup() {\n      //👇 The args will now be passed down to the template\n      return { args };\n    },\n    template: '<List v-bind=\"args\"><ListItem v-bind=\"args\"/></List>',\n  }),\n};\n```\n\n```ts filename=\"List.stories.js\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport List from './List.vue';\nimport ListItem from './ListItem.vue';\n\n//👇 Imports a specific story from ListItem stories\nimport { Unchecked } from './ListItem.stories';\n\nconst meta = {\n  component: List,\n} satisfies Meta<typeof List>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const OneItem: Story = {\n  render: (args) => ({\n    components: { List, ListItem },\n    setup() {\n      //👇 The args will now be passed down to the template\n      return { args };\n    },\n    template: '<List v-bind=\"args\"><ListItem v-bind=\"args\"/></List>',\n  }),\n  args: {\n    ...Unchecked.args,\n  },\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport List from './List.vue';\nimport ListItem from './ListItem.vue';\n\n//👇 Imports a specific story from ListItem stories\nimport { Unchecked } from './ListItem.stories';\n\nconst meta = preview.meta({\n  component: List,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const OneItem = meta.story({\n  render: (args) => ({\n    components: { List, ListItem },\n    setup() {\n      //👇 The args will now be passed down to the template\n      return { args };\n    },\n    template: '<List v-bind=\"args\"><ListItem v-bind=\"args\"/></List>',\n  }),\n  args: {\n    ...Unchecked.input.args,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"List.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport List from './List.vue';\nimport ListItem from './ListItem.vue';\n\n//👇 Imports a specific story from ListItem stories\nimport { Unchecked } from './ListItem.stories';\n\nconst meta = preview.meta({\n  component: List,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const OneItem = meta.story({\n  render: (args) => ({\n    components: { List, ListItem },\n    setup() {\n      //👇 The args will now be passed down to the template\n      return { args };\n    },\n    template: '<List v-bind=\"args\"><ListItem v-bind=\"args\"/></List>',\n  }),\n  args: {\n    ...Unchecked.input.args,\n  },\n});\n```\n\n```tsx filename=\"List.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { List } from './List';\n\n//👇 Instead of importing ListItem, we import the stories\nimport { Unchecked } from './ListItem.stories';\n\nconst meta = preview.meta({\n  component: List,\n});\n\nexport const OneItem = meta.story({\n  render: (args) => (\n    <List {...args}>\n      <Unchecked {...Unchecked.input.args} />\n    </List>\n  ),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"List.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { List } from './List';\n\n//👇 Instead of importing ListItem, we import the stories\nimport { Unchecked } from './ListItem.stories';\n\nconst meta = preview.meta({\n  component: List,\n});\n\nexport const OneItem = meta.story({\n  render: (args) => (\n    <List {...args}>\n      <Unchecked {...Unchecked.input.args} />\n    </List>\n  ),\n});\n```\n"
  },
  {
    "path": "docs/_snippets/list-story-with-subcomponents.md",
    "content": "```ts filename=\"List.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, type StoryObj, moduleMetadata } from '@storybook/angular';\n\nimport { CommonModule } from '@angular/common';\n\nimport { List } from './list.component';\nimport { ListItem } from './list-item.component';\n\nconst meta: Meta<List> = {\n  component: List,\n  subcomponents: { ListItem }, //👈 Adds the ListItem component as a subcomponent\n  decorators: [\n    moduleMetadata({\n      declarations: [List, ListItem],\n      imports: [CommonModule],\n    }),\n  ],\n};\nexport default meta;\n\ntype Story = StoryObj<List>;\n\nexport const Empty: Story = {};\n\nexport const OneItem: Story = {\n  args: {},\n  render: (args) => ({\n    props: args,\n    template: `\n      <app-list>\n        <app-list-item></app-list-item>\n      </app-list>\n  `,\n  }),\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { CommonModule } from '@angular/common';\n\nimport { moduleMetadata } from '@storybook/angular';\n\nimport preview from '../.storybook/preview';\n\nimport { List } from './list.component';\nimport { ListItem } from './list-item.component';\n\nconst meta = preview.meta({\n  component: List,\n  subcomponents: { ListItem }, //👈 Adds the ListItem component as a subcomponent\n  decorators: [\n    moduleMetadata({\n      declarations: [List, ListItem],\n      imports: [CommonModule],\n    }),\n  ],\n});\n\nexport const Empty = meta.story();\n\nexport const OneItem = meta.story({\n  args: {},\n  render: (args) => ({\n    props: args,\n    template: `\n      <app-list>\n        <app-list-item></app-list-item>\n      </app-list>\n  `,\n  }),\n});\n```\n\n```jsx filename=\"List.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport * as React from 'react';\n\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\nexport default {\n  component: List,\n  subcomponents: { ListItem }, //👈 Adds the ListItem component as a subcomponent\n};\n\nexport const Empty = {};\n\nexport const OneItem = {\n  render: (args) => (\n    <List {...args}>\n      <ListItem />\n    </List>\n  ),\n};\n```\n\n```tsx filename=\"List.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\nimport * as React from 'react';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\nconst meta = {\n  component: List,\n  subcomponents: { ListItem }, //👈 Adds the ListItem component as a subcomponent\n} satisfies Meta<typeof List>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Empty: Story = {};\n\nexport const OneItem: Story = {\n  render: (args) => (\n    <List {...args}>\n      <ListItem />\n    </List>\n  ),\n};\n```\n\n```jsx filename=\"List.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'List',\n  component: List,\n  subcomponents: { ListItem }, //👈 Adds the ListItem component as a subcomponent\n};\n\nexport const Empty = {};\n\nexport const OneItem = {\n  render: (args) => (\n    <List {...args}>\n      <ListItem />\n    </List>\n  ),\n};\n```\n\n```tsx filename=\"List.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'List',\n  component: List,\n  //👈 Adds the ListItem component as a subcomponent\n  subcomponents: { ListItem },\n} satisfies Meta<typeof List>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Empty: Story = {};\n\nexport const OneItem: Story = {\n  render: (args) => (\n    <List {...args}>\n      <ListItem />\n    </List>\n  ),\n};\n```\n\n```svelte filename=\"List.stories.svelte\" renderer=\"svelte\" language=\"js\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import List from './List.svelte';\n  import ListItem from './ListItem.svelte';\n\n  const { Story } = defineMeta({\n    component: List,\n    subcomponents: { ListItem },\n  });\n</script>\n\n<Story name=\"Empty\" />\n\n<Story name=\"One Item\">\n  {#snippet children(args)}\n    <List {...args}>\n      <ListItem />\n    </List>\n  {/snippet}\n</Story>\n```\n\n```svelte filename=\"List.stories.svelte\" renderer=\"svelte\" language=\"ts\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import List from './List.svelte';\n  import ListItem from './ListItem.svelte';\n\n  const { Story } = defineMeta({\n    component: List,\n    subcomponents: { ListItem },\n  });\n</script>\n\n<Story name=\"Empty\" />\n\n<Story name=\"One Item\">\n  {#snippet children(args)}\n    <List {...args}>\n      <ListItem />\n    </List>\n  {/snippet}\n</Story>\n```\n\n```js filename=\"List.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nexport default {\n  title: 'List',\n  component: 'demo-list',\n  subcomponents: { ListItem: 'demo-list-item' }, // 👈 Adds the ListItem component as a subcomponent\n};\n\nexport const Empty = {};\n\nexport const OneItem = {\n  render: () => html`\n    <demo-list>\n      <demo-list-item></demo-list-item>\n    </demo-list>\n  `,\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nconst meta: Meta = {\n  title: 'List',\n  component: 'demo-list',\n  subcomponents: { ListItem: 'demo-list-item' }, // 👈 Adds the ListItem component as a subcomponent\n};\nexport default meta;\n\ntype Story = StoryObj;\n\nexport const Empty: Story = {};\n\nexport const OneItem: Story = {\n  render: () => html`\n    <demo-list>\n      <demo-list-item></demo-list-item>\n    </demo-list>\n  `,\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-list',\n  subcomponents: { ListItem: 'demo-list-item' }, // 👈 Adds the ListItem component as a subcomponent\n});\n\nexport const Empty = meta.story();\n\nexport const OneItem = meta.story({\n  render: () => html`\n    <demo-list>\n      <demo-list-item></demo-list-item>\n    </demo-list>\n  `,\n});\n```\n\n```js filename=\"List.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-list',\n  subcomponents: { ListItem: 'demo-list-item' }, // 👈 Adds the ListItem component as a subcomponent\n});\n\nexport const Empty = meta.story();\n\nexport const OneItem = meta.story({\n  render: () => html`\n    <demo-list>\n      <demo-list-item></demo-list-item>\n    </demo-list>\n  `,\n});\n```\n\n```js filename=\"List.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport List from './List.vue';\nimport ListItem from './ListItem.vue';\n\nexport default {\n  component: List,\n  subcomponents: { ListItem }, //👈 Adds the ListItem component as a subcomponent\n};\n\nexport const Empty = {\n  render: () => ({\n    components: { List },\n    template: '<List/>',\n  }),\n};\n\nexport const OneItem = {\n  render: (args) => ({\n    components: { List, ListItem },\n    setup() {\n      return { args };\n    },\n    template: '<List v-bind=\"args\"><ListItem /></List>',\n  }),\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport List from './List.vue';\nimport ListItem from './ListItem.vue';\n\nconst meta = {\n  component: List,\n  subcomponents: { ListItem }, //👈 Adds the ListItem component as a subcomponent\n} satisfies Meta<typeof List>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Empty: Story = {\n  render: () => ({\n    components: { List },\n    template: '<List />',\n  }),\n};\n\nexport const OneItem: Story = {\n  render: (args) => ({\n    components: { List, ListItem },\n    setup() {\n      return { args };\n    },\n    template: '<List v-bind=\"args\"><ListItem /></List>',\n  }),\n};\n```\n\n```ts filename=\"List.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport List from './List.vue';\nimport ListItem from './ListItem.vue';\n\nconst meta = preview.meta({\n  component: List,\n  subcomponents: { ListItem }, //👈 Adds the ListItem component as a subcomponent\n});\n\nexport const Empty = meta.story({\n  render: () => ({\n    components: { List },\n    template: '<List/>',\n  }),\n});\n\nexport const OneItem = meta.story({\n  render: (args) => ({\n    components: { List, ListItem },\n    setup() {\n      return { args };\n    },\n    template: '<List v-bind=\"args\"><ListItem /></List>',\n  }),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"List.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport List from './List.vue';\nimport ListItem from './ListItem.vue';\n\nconst meta = preview.meta({\n  component: List,\n  subcomponents: { ListItem }, //👈 Adds the ListItem component as a subcomponent\n});\n\nexport const Empty = meta.story({\n  render: () => ({\n    components: { List },\n    template: '<List/>',\n  }),\n});\n\nexport const OneItem = meta.story({\n  render: (args) => ({\n    components: { List, ListItem },\n    setup() {\n      return { args };\n    },\n    template: '<List v-bind=\"args\"><ListItem /></List>',\n  }),\n});\n```\n\n```tsx filename=\"List.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\nimport preview from '../.storybook/preview';\n\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\nconst meta = preview.meta({\n  component: List,\n  subcomponents: { ListItem }, //👈 Adds the ListItem component as a subcomponent\n});\n\nexport const Empty = meta.story();\n\nexport const OneItem = meta.story({\n  render: (args) => (\n    <List {...args}>\n      <ListItem />\n    </List>\n  ),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"List.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\nimport preview from '../.storybook/preview';\n\nimport { List } from './List';\nimport { ListItem } from './ListItem';\n\nconst meta = preview.meta({\n  component: List,\n  subcomponents: { ListItem }, // 👈 Adds the ListItem component as a subcomponent\n});\n\nexport const Empty = meta.story();\n\nexport const OneItem = meta.story({\n  render: (args) => (\n    <List {...args}>\n      <ListItem />\n    </List>\n  ),\n});\n```\n"
  },
  {
    "path": "docs/_snippets/list-story-with-unchecked-children.md",
    "content": "```jsx filename=\"List.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { List } from './List';\n\n//👇 Instead of importing ListItem, we import the stories\nimport { Unchecked } from './ListItem.stories';\n\nexport default {\n  component: List,\n};\n\nexport const OneItem = {\n  args: {\n    children: <Unchecked {...Unchecked.args} />,\n  },\n};\n```\n\n```tsx filename=\"List.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { List } from './List';\n\n//👇 Instead of importing ListItem, we import the stories\nimport { Unchecked } from './ListItem.stories';\n\nconst meta = {\n  component: List,\n} satisfies Meta<typeof List>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const OneItem: Story = {\n  args: {\n    children: <Unchecked {...Unchecked.args} />,\n  },\n};\n```\n\n```jsx filename=\"List.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { List } from './List';\n\n//👇 Instead of importing ListItem, we import the stories\nimport { Unchecked } from './ListItem.stories';\n\nexport default {\n  component: List,\n};\n\nexport const OneItem = {\n  args: {\n    children: <Unchecked {...Unchecked.args} />,\n  },\n};\n```\n\n```tsx filename=\"List.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { List } from './List';\n\n//👇 Instead of importing ListItem, we import the stories\nimport { Unchecked } from './ListItem.stories';\n\nconst meta = {\n  component: List,\n} satisfies Meta<typeof List>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const OneItem: Story = {\n  args: {\n    children: <Unchecked {...Unchecked.args} />,\n  },\n};\n```\n\n```tsx filename=\"List.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { List } from './List';\n\n//👇 Instead of importing ListItem, we import the stories\nimport { Unchecked } from './ListItem.stories';\n\nconst meta = preview.meta({\n  component: List,\n});\n\nexport const OneItem = meta.story({\n  args: {\n    children: <Unchecked {...Unchecked.input.args} />,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"List.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { List } from './List';\n\n//👇 Instead of importing ListItem, we import the stories\nimport { Unchecked } from './ListItem.stories';\n\nconst meta = preview.meta({\n  component: List,\n});\n\nexport const OneItem = meta.story({\n  args: {\n    children: <Unchecked {...Unchecked.input.args} />,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/loader-story.md",
    "content": "```ts filename=\"TodoItem.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, type StoryObj, moduleMetadata } from '@storybook/angular';\n\nimport { CommonModule } from '@angular/common';\n\nimport { TodoItem } from './TodoItem.component';\n\nconst meta: Meta<TodoItem> = {\n  component: TodoItem,\n  decorators: [\n    moduleMetadata({\n      declarations: [TodoItem],\n      imports: [CommonModule],\n    }),\n  ],\n};\n\nexport default meta;\ntype Story = StoryObj<TodoItem>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary: Story = {\n  render: (args, { loaded: { todo } }) => ({\n    props: {\n      args,\n      todo,\n    },\n  }),\n  loaders: [\n    async () => ({\n      todo: await (await fetch('https://jsonplaceholder.typicode.com/todos/1')).json(),\n    }),\n  ],\n};\n```\n\n```ts filename=\"TodoItem.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { CommonModule } from '@angular/common';\n\nimport { moduleMetadata } from '@storybook/angular';\n\nimport preview from '../.storybook/preview';\n\nimport { TodoItem } from './TodoItem.component';\n\nconst meta = preview.meta({\n  component: TodoItem,\n  decorators: [\n    moduleMetadata({\n      declarations: [TodoItem],\n      imports: [CommonModule],\n    }),\n  ],\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = meta.story({\n  render: (args, { loaded: { todo } }) => ({\n    props: {\n      args,\n      todo,\n    },\n  }),\n  loaders: [\n    async () => ({\n      todo: await (await fetch('https://jsonplaceholder.typicode.com/todos/1')).json(),\n    }),\n  ],\n});\n```\n\n```jsx filename=\"TodoItem.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { TodoItem } from './TodoItem';\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport default {\n  component: TodoItem,\n  render: (args, { loaded: { todo } }) => <TodoItem {...args} {...todo} />,\n};\n\nexport const Primary = {\n  loaders: [\n    async () => ({\n      todo: await (await fetch('https://jsonplaceholder.typicode.com/todos/1')).json(),\n    }),\n  ],\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { TodoItem } from './TodoItem';\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nconst meta = {\n  component: TodoItem,\n  render: (args, { loaded: { todo } }) => <TodoItem {...args} {...todo} />,\n} satisfies Meta<typeof TodoItem>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  loaders: [\n    async () => ({\n      todo: await (await fetch('https://jsonplaceholder.typicode.com/todos/1')).json(),\n    }),\n  ],\n};\n```\n\n```jsx filename=\"TodoItem.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { TodoItem } from './TodoItem';\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport default {\n  component: TodoItem,\n  render: (args, { loaded: { todo } }) => <TodoItem {...args} {...todo} />,\n};\n\nexport const Primary = {\n  loaders: [\n    async () => ({\n      todo: await (await fetch('https://jsonplaceholder.typicode.com/todos/1')).json(),\n    }),\n  ],\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { TodoItem } from './TodoItem';\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nconst meta = {\n  component: TodoItem,\n  render: (args, { loaded: { todo } }) => <TodoItem {...args} {...todo} />,\n} satisfies Meta<typeof TodoItem>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  loaders: [\n    async () => ({\n      todo: await (await fetch('https://jsonplaceholder.typicode.com/todos/1')).json(),\n    }),\n  ],\n};\n```\n\n```svelte filename=\"TodoItem.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import TodoItem from './TodoItem.svelte';\n\n  const { Story } = defineMeta({\n    component: TodoItem,\n    render: template,\n  });\n</script>\n\n{#snippet template(args, { loaded: { todo } })}\n  <TodoItem {...args} {...todo} />\n{/snippet}\n\n<Story\n  name=\"Primary\"\n  loaders={[\n    async () => ({\n      todo: await (\n        await fetch('https://jsonplaceholder.typicode.com/todos/1')\n      ).json(),\n    }),\n  ]}\n/>\n```\n\n```js filename=\"TodoItem.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport TodoItem from './TodoItem.svelte';\n\nexport default {\n  component: TodoItem,\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = {\n  render: (args, { loaded: { todo } }) => ({\n    Component: TodoItem,\n    props: {\n      ...args,\n      todo,\n    },\n  }),\n  loaders: [\n    async () => ({\n      todo: await (await fetch('https://jsonplaceholder.typicode.com/todos/1')).json(),\n    }),\n  ],\n};\n```\n\n```svelte filename=\"TodoItem.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import TodoItem from './TodoItem.svelte';\n\n  const { Story } = defineMeta({\n    component: TodoItem,\n    render: template,\n  });\n</script>\n\n{#snippet template(args, { loaded: { todo } })}\n  <TodoItem {...args} {...todo} />\n{/snippet}\n\n<Story\n  name=\"Primary\"\n  loaders={[\n    async () => ({\n      todo: await (\n        await fetch('https://jsonplaceholder.typicode.com/todos/1')\n      ).json(),\n    }),\n  ]}\n/>\n```\n\n```ts filename=\"TodoItem.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport TodoItem from './TodoItem.svelte';\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/svelte/api/csf\n * to learn how to use render functions.\n */\nconst meta = {\n  component: TodoItem,\n  render: (args, { loaded: { todo } }) => ({\n    Component: TodoItem,\n    props: {\n      ...args,\n      ...todo,\n    },\n  }),\n} satisfies Meta<typeof TodoItem>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  loaders: [\n    async () => ({\n      todo: await (await fetch('https://jsonplaceholder.typicode.com/todos/1')).json(),\n    }),\n  ],\n};\n```\n\n```js filename=\"TodoItem.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport TodoItem from './TodoItem.vue';\n\nexport default {\n  component: TodoItem,\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = {\n  render: (args, { loaded: { todo } }) => ({\n    components: { TodoItem },\n    setup() {\n      return { args, todo: todo };\n    },\n    template: '<TodoItem :todo=\"todo\" />',\n  }),\n  loaders: [\n    async () => ({\n      todo: await (await fetch('https://jsonplaceholder.typicode.com/todos/1')).json(),\n    }),\n  ],\n};\n```\n\n```ts filename=\"TodoItem.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport TodoItem from './TodoItem.vue';\n\nconst meta = {\n  component: TodoItem,\n} satisfies Meta<typeof TodoItem>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary: Story = {\n  render: (args, { loaded: { todo } }) => ({\n    components: { TodoItem },\n    setup() {\n      return { args, todo: todo };\n    },\n    template: '<TodoItem :todo=\"todo\" />',\n  }),\n  loaders: [\n    async () => ({\n      todo: await (await fetch('https://jsonplaceholder.typicode.com/todos/1')).json(),\n    }),\n  ],\n};\n```\n\n```ts filename=\"TodoItem.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport TodoItem from './TodoItem.vue';\n\nconst meta = preview.meta({\n  component: TodoItem,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = meta.story({\n  render: (args, { loaded: { todo } }) => ({\n    components: { TodoItem },\n    setup() {\n      return { args, todo: todo };\n    },\n    template: '<TodoItem :todo=\"todo\" />',\n  }),\n  loaders: [\n    async () => ({\n      todo: await (await fetch('https://jsonplaceholder.typicode.com/todos/1')).json(),\n    }),\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"TodoItem.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport TodoItem from './TodoItem.vue';\n\nconst meta = preview.meta({\n  component: TodoItem,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary = meta.story({\n  render: (args, { loaded: { todo } }) => ({\n    components: { TodoItem },\n    setup() {\n      return { args, todo: todo };\n    },\n    template: '<TodoItem :todo=\"todo\" />',\n  }),\n  loaders: [\n    async () => ({\n      todo: await (await fetch('https://jsonplaceholder.typicode.com/todos/1')).json(),\n    }),\n  ],\n});\n```\n\n```js filename=\"TodoItem.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport default {\n  component: 'demo-todo-item',\n  render: (args, { loaded: { todo } }) => TodoItem({ ...args, ...todo }),\n};\n\nexport const Primary = {\n  loaders: [\n    async () => ({\n      todo: await (await fetch('https://jsonplaceholder.typicode.com/todos/1')).json(),\n    }),\n  ],\n};\n```\n\n```ts filename=\"TodoItem.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nconst meta: Meta = {\n  component: 'demo-todo-item',\n  render: (args, { loaded: { todo } }) => TodoItem({ ...args, ...todo }),\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Primary: Story = {\n  loaders: [\n    async () => ({\n      todo: await (await fetch('https://jsonplaceholder.typicode.com/todos/1')).json(),\n    }),\n  ],\n};\n```\n\n```ts filename=\"TodoItem.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nconst meta = preview.meta({\n  component: 'demo-todo-item',\n  render: (args, { loaded: { todo } }) => TodoItem({ ...args, ...todo }),\n});\n\nexport const Primary = meta.story({\n  loaders: [\n    async () => ({\n      todo: await (await fetch('https://jsonplaceholder.typicode.com/todos/1')).json(),\n    }),\n  ],\n});\n```\n\n```js filename=\"TodoItem.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nconst meta = preview.meta({\n  component: 'demo-todo-item',\n  render: (args, { loaded: { todo } }) => TodoItem({ ...args, ...todo }),\n});\n\nexport const Primary = meta.story({\n  loaders: [\n    async () => ({\n      todo: await (await fetch('https://jsonplaceholder.typicode.com/todos/1')).json(),\n    }),\n  ],\n});\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { TodoItem } from './TodoItem';\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nconst meta = preview.meta({\n  component: TodoItem,\n  render: (args, { loaded: { todo } }) => <TodoItem {...args} {...todo} />,\n});\n\nexport const Primary = meta.story({\n  loaders: [\n    async () => ({\n      todo: await (await fetch('https://jsonplaceholder.typicode.com/todos/1')).json(),\n    }),\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"TodoItem.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { TodoItem } from './TodoItem';\n\nconst meta = preview.meta({\n  component: TodoItem,\n  render: (args, { loaded: { todo } }) => <TodoItem {...args} {...todo} />,\n});\n\nexport const Primary = meta.story({\n  loaders: [\n    async () => ({\n      todo: await (await fetch('https://jsonplaceholder.typicode.com/todos/1')).json(),\n    }),\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/login-form-with-play-function.md",
    "content": "```ts filename=\"LoginForm.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { expect } from 'storybook/test';\n\nimport { LoginForm } from './login-form.component';\n\nconst meta: Meta<LoginForm> = {\n  component: LoginForm,\n};\nexport default meta;\n\ntype Story = StoryObj<LoginForm>;\n\nexport const EmptyForm: Story = {};\n\nexport const FilledForm: Story = {\n  play: async ({ canvas, userEvent }) => {\n    // 👇 Simulate interactions with the component\n    await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');\n\n    await userEvent.type(canvas.getByTestId('password'), 'a-random-password');\n\n    // See https://storybook.js.org/docs/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel\n    await userEvent.click(canvas.getByRole('button'));\n\n    // 👇 Assert DOM structure\n    await expect(\n      canvas.getByText(\n        'Everything is perfect. Your account is ready and we should probably get you started!',\n      ),\n    ).toBeInTheDocument();\n  },\n};\n```\n\n```ts filename=\"LoginForm.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { LoginForm } from './login-form.component';\n\nconst meta = preview.meta({\n  component: LoginForm,\n});\n\nexport const EmptyForm = meta.story();\n\nexport const FilledForm = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    // 👇 Simulate interactions with the component\n    await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');\n\n    await userEvent.type(canvas.getByTestId('password'), 'a-random-password');\n\n    // See https://storybook.js.org/docs/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel\n    await userEvent.click(canvas.getByRole('button'));\n\n    // 👇 Assert DOM structure\n    await expect(\n      canvas.getByText(\n        'Everything is perfect. Your account is ready and we should probably get you started!',\n      ),\n    ).toBeInTheDocument();\n  },\n});\n```\n\n```js filename=\"LoginForm.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { expect } from 'storybook/test';\n\nimport { LoginForm } from './LoginForm';\n\nexport default {\n  component: LoginForm,\n};\n\nexport const EmptyForm = {};\n\nexport const FilledForm = {\n  play: async ({ canvas, userEvent }) => {\n    // 👇 Simulate interactions with the component\n    await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');\n\n    await userEvent.type(canvas.getByTestId('password'), 'a-random-password');\n\n    // See https://storybook.js.org/docs/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel\n    await userEvent.click(canvas.getByRole('button'));\n\n    // 👇 Assert DOM structure\n    await expect(\n      canvas.getByText(\n        'Everything is perfect. Your account is ready and we should probably get you started!',\n      ),\n    ).toBeInTheDocument();\n  },\n};\n```\n\n```ts filename=\"LoginForm.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { expect } from 'storybook/test';\n\nimport { LoginForm } from './LoginForm';\n\nconst meta = {\n  component: LoginForm,\n} satisfies Meta<typeof LoginForm>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const EmptyForm: Story = {};\n\nexport const FilledForm: Story = {\n  play: async ({ canvas, userEvent }) => {\n    // 👇 Simulate interactions with the component\n    await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');\n\n    await userEvent.type(canvas.getByTestId('password'), 'a-random-password');\n\n    // See https://storybook.js.org/docs/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel\n    await userEvent.click(canvas.getByRole('button'));\n\n    // 👇 Assert DOM structure\n    await expect(\n      canvas.getByText(\n        'Everything is perfect. Your account is ready and we should probably get you started!',\n      ),\n    ).toBeInTheDocument();\n  },\n};\n```\n\n```js filename=\"LoginForm.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { expect } from 'storybook/test';\n\nimport { LoginForm } from './LoginForm';\n\nexport default {\n  component: LoginForm,\n};\n\nexport const EmptyForm = {};\n\nexport const FilledForm = {\n  play: async ({ canvas, userEvent }) => {\n    // 👇 Simulate interactions with the component\n    await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');\n\n    await userEvent.type(canvas.getByTestId('password'), 'a-random-password');\n\n    // See https://storybook.js.org/docs/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel\n    await userEvent.click(canvas.getByRole('button'));\n\n    // 👇 Assert DOM structure\n    await expect(\n      canvas.getByText(\n        'Everything is perfect. Your account is ready and we should probably get you started!',\n      ),\n    ).toBeInTheDocument();\n  },\n};\n```\n\n```tsx filename=\"LoginForm.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { expect } from 'storybook/test';\n\nimport { LoginForm } from './LoginForm';\n\nconst meta = {\n  component: LoginForm,\n} satisfies Meta<typeof LoginForm>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const EmptyForm: Story = {};\n\nexport const FilledForm: Story = {\n  play: async ({ canvas, userEvent }) => {\n    // 👇 Simulate interactions with the component\n    await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');\n\n    await userEvent.type(canvas.getByTestId('password'), 'a-random-password');\n\n    // See https://storybook.js.org/docs/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel\n    await userEvent.click(canvas.getByRole('button'));\n\n    // 👇 Assert DOM structure\n    await expect(\n      canvas.getByText(\n        'Everything is perfect. Your account is ready and we should probably get you started!',\n      ),\n    ).toBeInTheDocument();\n  },\n};\n```\n\n```svelte filename=\"LoginForm.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { expect, within } from 'storybook/test';\n\n  import LoginForm from './LoginForm.svelte';\n\n  const { Story } = defineMeta({\n    component: LoginForm,\n  });\n</script>\n\n<Story name=\"EmptyForm\" />\n\n<!--\n  See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n  to learn more about using the canvas to query the DOM\n-->\n<Story\n  name=\"FilledForm\"\n  play={async ({ canvas, userEvent }) => {\n    // 👇 Simulate interactions with the component\n    await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');\n\n    await userEvent.type(canvas.getByTestId('password'), 'a-random-password');\n\n    // See https://storybook.js.org/docs/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel\n    await userEvent.click(canvas.getByRole('button'));\n\n    // 👇 Assert DOM structure\n    await expect(\n      canvas.getByText(\n        'Everything is perfect. Your account is ready and we should probably get you started!'\n      )\n    ).toBeInTheDocument();\n  }}\n/>\n```\n\n```js filename=\"LoginForm.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport { expect, within } from 'storybook/test';\n\nimport LoginForm from './LoginForm.svelte';\n\nexport default {\n  component: LoginForm,\n};\n\nexport const EmptyForm = {};\n\nexport const FilledForm = {\n  play: async ({ canvas, userEvent }) => {\n    // 👇 Simulate interactions with the component\n    await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');\n\n    await userEvent.type(canvas.getByTestId('password'), 'a-random-password');\n\n    // See https://storybook.js.org/docs/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel\n    await userEvent.click(canvas.getByRole('button'));\n\n    // 👇 Assert DOM structure\n    await expect(\n      canvas.getByText(\n        'Everything is perfect. Your account is ready and we should probably get you started!',\n      ),\n    ).toBeInTheDocument();\n  },\n};\n```\n\n```svelte filename=\"LoginForm.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { expect, within } from 'storybook/test';\n\n  import LoginForm from './LoginForm.svelte';\n\n  const { Story } = defineMeta({\n    component: LoginForm,\n  });\n</script>\n\n<Story name=\"EmptyForm\" />\n\n<!--\n  See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n  to learn more about using the canvas to query the DOM\n-->\n<Story\n  name=\"FilledForm\"\n  play={async ({ canvas, userEvent }) => {\n    // 👇 Simulate interactions with the component\n    await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');\n\n    await userEvent.type(canvas.getByTestId('password'), 'a-random-password');\n\n    // See https://storybook.js.org/docs/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel\n    await userEvent.click(canvas.getByRole('button'));\n\n    // 👇 Assert DOM structure\n    await expect(\n      canvas.getByText(\n        'Everything is perfect. Your account is ready and we should probably get you started!'\n      )\n    ).toBeInTheDocument();\n  }}\n/>\n```\n\n```ts filename=\"LoginForm.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { expect, within } from 'storybook/test';\n\nimport LoginForm from './LoginForm.svelte';\n\nconst meta = {\n  component: LoginForm,\n} satisfies Meta<typeof LoginForm>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const EmptyForm: Story = {};\n\nexport const FilledForm: Story = {\n  play: async ({ canvas, userEvent }) => {\n    // 👇 Simulate interactions with the component\n    await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');\n\n    await userEvent.type(canvas.getByTestId('password'), 'a-random-password');\n\n    // See https://storybook.js.org/docs/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel\n    await userEvent.click(canvas.getByRole('button'));\n\n    // 👇 Assert DOM structure\n    await expect(\n      canvas.getByText(\n        'Everything is perfect. Your account is ready and we should probably get you started!',\n      ),\n    ).toBeInTheDocument();\n  },\n};\n```\n\n```js filename=\"LoginForm.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport { expect } from 'storybook/test';\n\nimport LoginForm from './LoginForm.vue';\n\nexport default {\n  component: LoginForm,\n};\n\nexport const EmptyForm = {\n  render: () => ({\n    components: { LoginForm },\n    template: `<LoginForm />`,\n  }),\n};\n\nexport const FilledForm = {\n  render: () => ({\n    components: { LoginForm },\n    template: `<LoginForm />`,\n  }),\n  play: async ({ canvas, userEvent }) => {\n    // 👇 Simulate interactions with the component\n    await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');\n\n    await userEvent.type(canvas.getByTestId('password'), 'a-random-password');\n\n    // See https://storybook.js.org/docs/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel\n    await userEvent.click(canvas.getByRole('button'));\n\n    // 👇 Assert DOM structure\n    await expect(\n      canvas.getByText(\n        'Everything is perfect. Your account is ready and we should probably get you started!',\n      ),\n    ).toBeInTheDocument();\n  },\n};\n```\n\n```ts filename=\"LoginForm.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport { expect } from 'storybook/test';\n\nimport LoginForm from './LoginForm.vue';\n\nconst meta = {\n  component: LoginForm,\n} satisfies Meta<typeof LoginForm>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const EmptyForm: Story = {\n  render: () => ({\n    components: { LoginForm },\n    template: `<LoginForm />`,\n  }),\n};\n\nexport const FilledForm: Story = {\n  render: () => ({\n    components: { LoginForm },\n    template: `<LoginForm />`,\n  }),\n  play: async ({ canvas, userEvent }) => {\n    // 👇 Simulate interactions with the component\n    await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');\n\n    await userEvent.type(canvas.getByTestId('password'), 'a-random-password');\n\n    // See https://storybook.js.org/docs/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel\n    await userEvent.click(canvas.getByRole('button'));\n\n    // 👇 Assert DOM structure\n    await expect(\n      canvas.getByText(\n        'Everything is perfect. Your account is ready and we should probably get you started!',\n      ),\n    ).toBeInTheDocument();\n  },\n};\n```\n\n```ts filename=\"LoginForm.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport LoginForm from './LoginForm.vue';\n\nconst meta = preview.meta({\n  component: LoginForm,\n});\n\nexport const EmptyForm = meta.story({\n  render: () => ({\n    components: { LoginForm },\n    template: `<LoginForm />`,\n  }),\n});\n\nexport const FilledForm = meta.story({\n  render: () => ({\n    components: { LoginForm },\n    template: `<LoginForm />`,\n  }),\n  play: async ({ canvas, userEvent }) => {\n    // 👇 Simulate interactions with the component\n    await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');\n\n    await userEvent.type(canvas.getByTestId('password'), 'a-random-password');\n\n    // See https://storybook.js.org/docs/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel\n    await userEvent.click(canvas.getByRole('button'));\n\n    // 👇 Assert DOM structure\n    await expect(\n      canvas.getByText(\n        'Everything is perfect. Your account is ready and we should probably get you started!',\n      ),\n    ).toBeInTheDocument();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"LoginForm.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport LoginForm from './LoginForm.vue';\n\nconst meta = preview.meta({\n  component: LoginForm,\n});\n\nexport const EmptyForm = meta.story({\n  render: () => ({\n    components: { LoginForm },\n    template: `<LoginForm />`,\n  }),\n});\n\nexport const FilledForm = meta.story({\n  render: () => ({\n    components: { LoginForm },\n    template: `<LoginForm />`,\n  }),\n  play: async ({ canvas, userEvent }) => {\n    // 👇 Simulate interactions with the component\n    await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');\n\n    await userEvent.type(canvas.getByTestId('password'), 'a-random-password');\n\n    // See https://storybook.js.org/docs/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel\n    await userEvent.click(canvas.getByRole('button'));\n\n    // 👇 Assert DOM structure\n    await expect(\n      canvas.getByText(\n        'Everything is perfect. Your account is ready and we should probably get you started!',\n      ),\n    ).toBeInTheDocument();\n  },\n});\n```\n\n```js filename=\"LoginForm.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { expect } from 'storybook/test';\n\nexport default {\n  component: 'demo-login-form',\n};\n\nexport const EmptyForm = {};\n\nexport const FilledForm = {\n  play: async ({ canvas, userEvent }) => {\n    // 👇 Simulate interactions with the component\n    await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');\n\n    await userEvent.type(canvas.getByTestId('password'), 'a-random-password');\n\n    // See https://storybook.js.org/docs/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel\n    await userEvent.click(canvas.getByRole('button'));\n\n    // 👇 Assert DOM structure\n    await expect(\n      canvas.getByText(\n        'Everything is perfect. Your account is ready and we should probably get you started!',\n      ),\n    ).toBeInTheDocument();\n  },\n};\n```\n\n```ts filename=\"LoginForm.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { expect } from 'storybook/test';\n\nconst meta: Meta = {\n  component: 'demo-login-form',\n};\nexport default meta;\n\ntype Story = StoryObj;\n\nexport const EmptyForm: Story = {};\n\nexport const FilledForm: Story = {\n  play: async ({ canvas, userEvent }) => {\n    // 👇 Simulate interactions with the component\n    await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');\n\n    await userEvent.type(canvas.getByTestId('password'), 'a-random-password');\n\n    // See https://storybook.js.org/docs/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel\n    await userEvent.click(canvas.getByRole('button'));\n\n    // 👇 Assert DOM structure\n    await expect(\n      canvas.getByText(\n        'Everything is perfect. Your account is ready and we should probably get you started!',\n      ),\n    ).toBeInTheDocument();\n  },\n};\n```\n\n```js filename=\"LoginForm.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-login-form',\n});\n\nexport const EmptyForm = meta.story();\n\nexport const FilledForm = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    // 👇 Simulate interactions with the component\n    await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');\n\n    await userEvent.type(canvas.getByTestId('password'), 'a-random-password');\n\n    // See https://storybook.js.org/docs/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel\n    await userEvent.click(canvas.getByRole('button'));\n\n    // 👇 Assert DOM structure\n    await expect(\n      canvas.getByText(\n        'Everything is perfect. Your account is ready and we should probably get you started!',\n      ),\n    ).toBeInTheDocument();\n  },\n});\n```\n\n```ts filename=\"LoginForm.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-login-form',\n});\n\nexport const EmptyForm = meta.story();\n\nexport const FilledForm = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    // 👇 Simulate interactions with the component\n    await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');\n\n    await userEvent.type(canvas.getByTestId('password'), 'a-random-password');\n\n    // See https://storybook.js.org/docs/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel\n    await userEvent.click(canvas.getByRole('button'));\n\n    // 👇 Assert DOM structure\n    await expect(\n      canvas.getByText(\n        'Everything is perfect. Your account is ready and we should probably get you started!',\n      ),\n    ).toBeInTheDocument();\n  },\n});\n```\n\n```ts filename=\"LoginForm.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { LoginForm } from './LoginForm';\n\nconst meta = preview.meta({\n  component: LoginForm,\n});\n\nexport const EmptyForm = meta.story();\n\nexport const FilledForm = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    // 👇 Simulate interactions with the component\n    await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');\n\n    await userEvent.type(canvas.getByTestId('password'), 'a-random-password');\n\n    // See https://storybook.js.org/docs/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel\n    await userEvent.click(canvas.getByRole('button'));\n\n    // 👇 Assert DOM structure\n    await expect(\n      canvas.getByText(\n        'Everything is perfect. Your account is ready and we should probably get you started!',\n      ),\n    ).toBeInTheDocument();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"LoginForm.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { LoginForm } from './LoginForm';\n\nconst meta = preview.meta({\n  component: LoginForm,\n});\n\nexport const EmptyForm = meta.story();\n\nexport const FilledForm = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    // 👇 Simulate interactions with the component\n    await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');\n\n    await userEvent.type(canvas.getByTestId('password'), 'a-random-password');\n\n    // See https://storybook.js.org/docs/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel\n    await userEvent.click(canvas.getByRole('button'));\n\n    // 👇 Assert DOM structure\n    await expect(\n      canvas.getByText(\n        'Everything is perfect. Your account is ready and we should probably get you started!',\n      ),\n    ).toBeInTheDocument();\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-addons.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { fileURLToPath } from 'node:url';\n\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    '@storybook/addon-docs',\n    {\n      name: '@storybook/addon-styling-webpack',\n      options: {\n        rules: [\n          {\n            test: /\\.css$/,\n            use: [\n              'style-loader',\n              'css-loader',\n              {\n                loader: 'postcss-loader',\n                options: {\n                  implementation: fileURLToPath(import.meta.resolve('postcss')),\n                },\n              },\n            ],\n          },\n        ],\n      },\n    },\n  ],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { fileURLToPath } from 'node:url';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    '@storybook/addon-docs',\n    {\n      name: '@storybook/addon-styling-webpack',\n      options: {\n        rules: [\n          {\n            test: /\\.css$/,\n            use: [\n              'style-loader',\n              'css-loader',\n              {\n                loader: 'postcss-loader',\n                options: {\n                  implementation: fileURLToPath(import.meta.resolve('postcss')),\n                },\n              },\n            ],\n          },\n        ],\n      },\n    },\n  ],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { fileURLToPath } from 'node:url';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    '@storybook/addon-docs',\n    {\n      name: '@storybook/addon-styling-webpack',\n      options: {\n        rules: [\n          {\n            test: /\\.css$/,\n            use: [\n              'style-loader',\n              'css-loader',\n              {\n                loader: 'postcss-loader',\n                options: {\n                  implementation: fileURLToPath(import.meta.resolve('postcss')),\n                },\n              },\n            ],\n          },\n        ],\n      },\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { fileURLToPath } from 'node:url';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    '@storybook/addon-docs',\n    {\n      name: '@storybook/addon-styling-webpack',\n      options: {\n        rules: [\n          {\n            test: /\\.css$/,\n            use: [\n              'style-loader',\n              'css-loader',\n              {\n                loader: 'postcss-loader',\n                options: {\n                  implementation: fileURLToPath(import.meta.resolve('postcss')),\n                },\n              },\n            ],\n          },\n        ],\n      },\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { fileURLToPath } from 'node:url';\n\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    '@storybook/addon-docs',\n    {\n      name: '@storybook/addon-styling-webpack',\n      options: {\n        rules: [\n          {\n            test: /\\.css$/,\n            use: [\n              'style-loader',\n              'css-loader',\n              {\n                loader: 'postcss-loader',\n                options: {\n                  implementation: fileURLToPath(import.meta.resolve('postcss')),\n                },\n              },\n            ],\n          },\n        ],\n      },\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { fileURLToPath } from 'node:url';\n\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    '@storybook/addon-docs',\n    {\n      name: '@storybook/addon-styling-webpack',\n      options: {\n        rules: [\n          {\n            test: /\\.css$/,\n            use: [\n              'style-loader',\n              'css-loader',\n              {\n                loader: 'postcss-loader',\n                options: {\n                  implementation: fileURLToPath(import.meta.resolve('postcss')),\n                },\n              },\n            ],\n          },\n        ],\n      },\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { fileURLToPath } from 'node:url';\n\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    '@storybook/addon-docs',\n    {\n      name: '@storybook/addon-styling-webpack',\n      options: {\n        rules: [\n          {\n            test: /\\.css$/,\n            use: [\n              'style-loader',\n              'css-loader',\n              {\n                loader: 'postcss-loader',\n                options: {\n                  implementation: fileURLToPath(import.meta.resolve('postcss')),\n                },\n              },\n            ],\n          },\n        ],\n      },\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { fileURLToPath } from 'node:url';\n\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    '@storybook/addon-docs',\n    {\n      name: '@storybook/addon-styling-webpack',\n      options: {\n        rules: [\n          {\n            test: /\\.css$/,\n            use: [\n              'style-loader',\n              'css-loader',\n              {\n                loader: 'postcss-loader',\n                options: {\n                  implementation: fileURLToPath(import.meta.resolve('postcss')),\n                },\n              },\n            ],\n          },\n        ],\n      },\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { fileURLToPath } from 'node:url';\n\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    '@storybook/addon-docs',\n    {\n      name: '@storybook/addon-styling-webpack',\n      options: {\n        rules: [\n          {\n            test: /\\.css$/,\n            use: [\n              'style-loader',\n              'css-loader',\n              {\n                loader: 'postcss-loader',\n                options: {\n                  implementation: fileURLToPath(import.meta.resolve('postcss')),\n                },\n              },\n            ],\n          },\n        ],\n      },\n    },\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-babel.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async babel(config, { configType }) {\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return config;\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async babel(config, { configType }) {\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return config;\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async babel(config, { configType }) {\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return config;\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async babel(config, { configType }) {\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return config;\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async babel(config, { configType }) {\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return config;\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async babel(config, { configType }) {\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return config;\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async babel(config, { configType }) {\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return config;\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async babel(config, { configType }) {\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return config;\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async babel(config, { configType }) {\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return config;\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-builder-custom-config.md",
    "content": "```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: {\n      name: '@storybook/builder-vite',\n      options: {\n        viteConfigPath: '../customVite.config.js',\n      },\n    },\n  },\n};\n\nexport default config;\n```\n\n```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: {\n      name: '@storybook/builder-vite',\n      options: {\n        viteConfigPath: '../customVite.config.js',\n      },\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: {\n      name: '@storybook/builder-vite',\n      options: {\n        viteConfigPath: '../customVite.config.js',\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n\n  core: {\n    builder: {\n      name: '@storybook/builder-vite',\n      options: {\n        viteConfigPath: '../customVite.config.js',\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n\n  core: {\n    builder: {\n      name: '@storybook/builder-vite',\n      options: {\n        viteConfigPath: '../customVite.config.js',\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n\n  core: {\n    builder: {\n      name: '@storybook/builder-vite',\n      options: {\n        viteConfigPath: '../customVite.config.js',\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n\n  core: {\n    builder: {\n      name: '@storybook/builder-vite',\n      options: {\n        viteConfigPath: '../customVite.config.js',\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n\n  core: {\n    builder: {\n      name: '@storybook/builder-vite',\n      options: {\n        viteConfigPath: '../customVite.config.js',\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-core-allowed-hosts.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    allowedHosts: ['storybook.example.local'],\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    allowedHosts: ['storybook.example.local'],\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  framework: '@storybook/your-framework',\n  core: {\n    allowedHosts: ['storybook.example.local'],\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    allowedHosts: ['storybook.example.local'],\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    allowedHosts: ['storybook.example.local'],\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    allowedHosts: ['storybook.example.local'],\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    allowedHosts: ['storybook.example.local'],\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    allowedHosts: ['storybook.example.local'],\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    allowedHosts: ['storybook.example.local'],\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-core-builder.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: {\n      name: '@storybook/builder-vite',\n      options: {\n        viteConfigPath: '../../../vite.config.js',\n      },\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  framework: '@storybook/your-framework',\n  core: {\n    builder: {\n      name: '@storybook/builder-vite',\n      options: {\n        viteConfigPath: '../../../vite.config.js',\n      },\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  framework: '@storybook/your-framework',\n  core: {\n    builder: {\n      name: '@storybook/builder-vite',\n      options: {\n        viteConfigPath: '../../../vite.config.js',\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: {\n      name: '@storybook/builder-vite',\n      options: {\n        viteConfigPath: '../../../vite.config.js',\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: {\n      name: '@storybook/builder-vite',\n      options: {\n        viteConfigPath: '../../../vite.config.js',\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: {\n      name: '@storybook/builder-vite',\n      options: {\n        viteConfigPath: '../../../vite.config.js',\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: {\n      name: '@storybook/builder-vite',\n      options: {\n        viteConfigPath: '../../../vite.config.js',\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: {\n      name: '@storybook/builder-vite',\n      options: {\n        viteConfigPath: '../../../vite.config.js',\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-core-cross-origin-isolated.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    crossOriginIsolated: true,\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    crossOriginIsolated: true,\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    crossOriginIsolated: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    crossOriginIsolated: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    crossOriginIsolated: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    crossOriginIsolated: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    crossOriginIsolated: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    crossOriginIsolated: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    crossOriginIsolated: true,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-core-disable-project-json.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableProjectJson: true,\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableProjectJson: true,\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableProjectJson: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableProjectJson: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableProjectJson: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableProjectJson: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableProjectJson: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableProjectJson: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableProjectJson: true,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-core-disable-telemetry.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableTelemetry: true,\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableTelemetry: true,\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableTelemetry: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableTelemetry: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableTelemetry: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableTelemetry: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableTelemetry: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableTelemetry: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableTelemetry: true,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-core-disable-update-notifications.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableWhatsNewNotifications: true,\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableWhatsNewNotifications: true,\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableWhatsNewNotifications: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableWhatsNewNotifications: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableWhatsNewNotifications: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableWhatsNewNotifications: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableWhatsNewNotifications: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableWhatsNewNotifications: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableWhatsNewNotifications: true,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-core-disable-webpack-defaults.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-webpack5, nextjs, angular, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableWebpackDefaults: true,\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-webpack5, nextjs, angular, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableWebpackDefaults: true,\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableWebpackDefaults: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableWebpackDefaults: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableWebpackDefaults: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableWebpackDefaults: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableWebpackDefaults: true,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-core-enable-crash-reports.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    enableCrashReports: true, // 👈 Appends the crash reports to the telemetry events\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    enableCrashReports: true, // 👈 Appends the crash reports to the telemetry events\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    enableCrashReports: true, // 👈 Appends the crash reports to the telemetry events\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    enableCrashReports: true, // 👈 Appends the crash reports to the telemetry events\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    enableCrashReports: true, // 👈 Appends the crash reports to the telemetry events\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    enableCrashReports: true, // 👈 Appends the crash reports to the telemetry events\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    enableCrashReports: true, // 👈 Appends the crash reports to the telemetry events\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    enableCrashReports: true, // 👈 Appends the crash reports to the telemetry events\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    enableCrashReports: true, // 👈 Appends the crash reports to the telemetry events\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-docs-default-name.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  docs: {\n    defaultName: 'Documentation',\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  docs: {\n    defaultName: 'Documentation',\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  docs: {\n    defaultName: 'Documentation',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  docs: {\n    defaultName: 'Documentation',\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  docs: {\n    defaultName: 'Documentation',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  docs: {\n    defaultName: 'Documentation',\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  docs: {\n    defaultName: 'Documentation',\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  docs: {\n    defaultName: 'Documentation',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  docs: {\n    defaultName: 'Documentation',\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-docs-docs-mode.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  docs: {\n    docsMode: true,\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  docs: {\n    docsMode: true,\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  docs: {\n    docsMode: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  docs: {\n    docsMode: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  docs: {\n    docsMode: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  docs: {\n    docsMode: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  docs: {\n    docsMode: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  docs: {\n    docsMode: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  docs: {\n    docsMode: true,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-env.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  /*\n   * 👇 The `config` argument contains all the other existing environment variables.\n   * Either configured in an `.env` file or configured on the command line.\n   */\n  env: (config) => ({\n    ...config,\n    EXAMPLE_VAR: 'An environment variable configured in Storybook',\n  }),\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  /*\n   * 👇 The `config` argument contains all the other existing environment variables.\n   * Either configured in an `.env` file or configured on the command line.\n   */\n  env: (config) => ({\n    ...config,\n    EXAMPLE_VAR: 'An environment variable configured in Storybook',\n  }),\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  /*\n   * 👇 The `config` argument contains all the other existing environment variables.\n   * Either configured in an `.env` file or configured on the command line.\n   */\n  env: (config) => ({\n    ...config,\n    EXAMPLE_VAR: 'An environment variable configured in Storybook',\n  }),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  /*\n   * 👇 The `config` argument contains all the other existing environment variables.\n   * Either configured in an `.env` file or configured on the command line.\n   */\n  env: (config) => ({\n    ...config,\n    EXAMPLE_VAR: 'An environment variable configured in Storybook',\n  }),\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  /*\n   * 👇 The `config` argument contains all the other existing environment variables.\n   * Either configured in an `.env` file or configured on the command line.\n   */\n  env: (config) => ({\n    ...config,\n    EXAMPLE_VAR: 'An environment variable configured in Storybook',\n  }),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  /*\n   * 👇 The `config` argument contains all the other existing environment variables.\n   * Either configured in an `.env` file or configured on the command line.\n   */\n  env: (config) => ({\n    ...config,\n    EXAMPLE_VAR: 'An environment variable configured in Storybook',\n  }),\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  /*\n   * 👇 The `config` argument contains all the other existing environment variables.\n   * Either configured in an `.env` file or configured on the command line.\n   */\n  env: (config) => ({\n    ...config,\n    EXAMPLE_VAR: 'An environment variable configured in Storybook',\n  }),\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  /*\n   * 👇 The `config` argument contains all the other existing environment variables.\n   * Either configured in an `.env` file or configured on the command line.\n   */\n  env: (config) => ({\n    ...config,\n    EXAMPLE_VAR: 'An environment variable configured in Storybook',\n  }),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  /*\n   * 👇 The `config` argument contains all the other existing environment variables.\n   * Either configured in an `.env` file or configured on the command line.\n   */\n  env: (config) => ({\n    ...config,\n    EXAMPLE_VAR: 'An environment variable configured in Storybook',\n  }),\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-features-arg-type-targets-v7.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    argTypeTargetsV7: true,\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    argTypeTargetsV7: true,\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    argTypeTargetsV7: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    argTypeTargetsV7: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    argTypeTargetsV7: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    argTypeTargetsV7: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    argTypeTargetsV7: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    argTypeTargetsV7: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    argTypeTargetsV7: true,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-features-components-manifest.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    componentsManifest: false,\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    componentsManifest: false,\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    componentsManifest: false,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    componentsManifest: false,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-features-development-mode-for-build.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    developmentModeForBuild: true,\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    developmentModeForBuild: true,\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    developmentModeForBuild: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    developmentModeForBuild: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    developmentModeForBuild: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    developmentModeForBuild: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    developmentModeForBuild: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    developmentModeForBuild: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    developmentModeForBuild: true,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-features-experimental-code-examples.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    experimentalCodeExamples: true,\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    experimentalCodeExamples: true,\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    experimentalCodeExamples: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    experimentalCodeExamples: true,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-features-experimental-test-syntax.md",
    "content": "```ts filename=\".storybook/main.js|ts (CSF Next 🧪)\" renderer=\"react\" language=\"ts\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    experimentalTestSyntax: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.js|ts (CSF Next 🧪)\" renderer=\"vue\" language=\"ts\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    experimentalTestSyntax: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.js|ts (CSF Next 🧪)\" renderer=\"angular\" language=\"ts\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    experimentalTestSyntax: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.js|ts (CSF Next 🧪)\" renderer=\"web-components\" language=\"ts\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    experimentalTestSyntax: true,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-features-legacy-decorator-file-order.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    legacyDecoratorFileOrder: true,\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    legacyDecoratorFileOrder: true,\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    legacyDecoratorFileOrder: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    legacyDecoratorFileOrder: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    legacyDecoratorFileOrder: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    legacyDecoratorFileOrder: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    legacyDecoratorFileOrder: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    legacyDecoratorFileOrder: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  features: {\n    legacyDecoratorFileOrder: true,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-framework.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  framework: {\n    // Replace react-vite with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\n    name: '@storybook/your-framework',\n    options: {\n      legacyRootApi: true,\n    },\n  },\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: {\n    name: '@storybook/your-framework',\n    options: {\n      legacyRootApi: true,\n    },\n  },\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: {\n    name: '@storybook/your-framework',\n    options: {\n      legacyRootApi: true,\n    },\n  },\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: {\n    name: '@storybook/your-framework',\n    options: {\n      legacyRootApi: true,\n    },\n  },\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: {\n    name: '@storybook/vue3-vite',\n    options: {},\n  },\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: {\n    name: '@storybook/vue3-vite',\n    options: {},\n  },\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: {\n    name: '@storybook/angular',\n    options: {},\n  },\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: {\n    name: '@storybook/web-components-vite',\n    options: {},\n  },\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: {\n    name: '@storybook/web-components-vite',\n    options: {},\n  },\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-indexers-jsonstories.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport fs from 'fs/promises';\n\nconst jsonStoriesIndexer = {\n  test: /stories\\.json$/,\n  createIndex: async (fileName) => {\n    const content = JSON.parse(fs.readFileSync(fileName));\n\n    const stories = generateStoryIndexesFromJson(content);\n\n    return stories.map((story) => ({\n      type: 'story',\n      importPath: `virtual:jsonstories--${fileName}--${story.componentName}`,\n      exportName: story.name,\n    }));\n  },\n};\n\nconst config = {\n  framework: '@storybook/your-framework',\n  stories: [\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n    // 👇 Make sure files to index are included in `stories`\n    '../src/**/*.stories.json',\n  ],\n  experimental_indexers: async (existingIndexers) => [...existingIndexers, jsonStoriesIndexer],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Indexer } from 'storybook/internal/types';\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nimport fs from 'fs/promises';\n\nconst jsonStoriesIndexer: Indexer = {\n  test: /stories\\.json$/,\n  createIndex: async (fileName) => {\n    const content = JSON.parse(fs.readFileSync(fileName));\n\n    const stories = generateStoryIndexesFromJson(content);\n\n    return stories.map((story) => ({\n      type: 'story',\n      importPath: `virtual:jsonstories--${fileName}--${story.componentName}`,\n      exportName: story.name,\n    }));\n  },\n};\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: [\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n    // 👇 Make sure files to index are included in `stories`\n    '../src/**/*.stories.json',\n  ],\n  experimental_indexers: async (existingIndexers) => [...existingIndexers, jsonStoriesIndexer],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport type { Indexer } from 'storybook/internal/types';\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nimport fs from 'fs/promises';\n\nconst jsonStoriesIndexer: Indexer = {\n  test: /stories\\.json$/,\n  createIndex: async (fileName) => {\n    const content = JSON.parse(fs.readFileSync(fileName));\n\n    const stories = generateStoryIndexesFromJson(content);\n\n    return stories.map((story) => ({\n      type: 'story',\n      importPath: `virtual:jsonstories--${fileName}--${story.componentName}`,\n      exportName: story.name,\n    }));\n  },\n};\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: [\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n    // 👇 Make sure files to index are included in `stories`\n    '../src/**/*.stories.json',\n  ],\n  experimental_indexers: async (existingIndexers) => [...existingIndexers, jsonStoriesIndexer],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nimport fs from 'fs/promises';\n\nconst jsonStoriesIndexer = {\n  test: /stories\\.json$/,\n  createIndex: async (fileName) => {\n    const content = JSON.parse(fs.readFileSync(fileName));\n\n    const stories = generateStoryIndexesFromJson(content);\n\n    return stories.map((story) => ({\n      type: 'story',\n      importPath: `virtual:jsonstories--${fileName}--${story.componentName}`,\n      exportName: story.name,\n    }));\n  },\n};\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: [\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n    // 👇 Make sure files to index are included in `stories`\n    '../src/**/*.stories.json',\n  ],\n  experimental_indexers: async (existingIndexers) => [...existingIndexers, jsonStoriesIndexer],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nimport fs from 'fs/promises';\n\nconst jsonStoriesIndexer = {\n  test: /stories\\.json$/,\n  createIndex: async (fileName) => {\n    const content = JSON.parse(fs.readFileSync(fileName));\n\n    const stories = generateStoryIndexesFromJson(content);\n\n    return stories.map((story) => ({\n      type: 'story',\n      importPath: `virtual:jsonstories--${fileName}--${story.componentName}`,\n      exportName: story.name,\n    }));\n  },\n};\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: [\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n    // 👇 Make sure files to index are included in `stories`\n    '../src/**/*.stories.json',\n  ],\n  experimental_indexers: async (existingIndexers) => [...existingIndexers, jsonStoriesIndexer],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nimport fs from 'fs/promises';\n\nconst jsonStoriesIndexer = {\n  test: /stories\\.json$/,\n  createIndex: async (fileName) => {\n    const content = JSON.parse(fs.readFileSync(fileName));\n\n    const stories = generateStoryIndexesFromJson(content);\n\n    return stories.map((story) => ({\n      type: 'story',\n      importPath: `virtual:jsonstories--${fileName}--${story.componentName}`,\n      exportName: story.name,\n    }));\n  },\n};\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: [\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n    // 👇 Make sure files to index are included in `stories`\n    '../src/**/*.stories.json',\n  ],\n  experimental_indexers: async (existingIndexers) => [...existingIndexers, jsonStoriesIndexer],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nimport fs from 'fs/promises';\n\nconst jsonStoriesIndexer = {\n  test: /stories\\.json$/,\n  createIndex: async (fileName) => {\n    const content = JSON.parse(fs.readFileSync(fileName));\n\n    const stories = generateStoryIndexesFromJson(content);\n\n    return stories.map((story) => ({\n      type: 'story',\n      importPath: `virtual:jsonstories--${fileName}--${story.componentName}`,\n      exportName: story.name,\n    }));\n  },\n};\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: [\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n    // 👇 Make sure files to index are included in `stories`\n    '../src/**/*.stories.json',\n  ],\n  experimental_indexers: async (existingIndexers) => [...existingIndexers, jsonStoriesIndexer],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nimport fs from 'fs/promises';\n\nconst jsonStoriesIndexer = {\n  test: /stories\\.json$/,\n  createIndex: async (fileName) => {\n    const content = JSON.parse(fs.readFileSync(fileName));\n\n    const stories = generateStoryIndexesFromJson(content);\n\n    return stories.map((story) => ({\n      type: 'story',\n      importPath: `virtual:jsonstories--${fileName}--${story.componentName}`,\n      exportName: story.name,\n    }));\n  },\n};\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: [\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n    // 👇 Make sure files to index are included in `stories`\n    '../src/**/*.stories.json',\n  ],\n  experimental_indexers: async (existingIndexers) => [...existingIndexers, jsonStoriesIndexer],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nimport fs from 'fs/promises';\n\nconst jsonStoriesIndexer = {\n  test: /stories\\.json$/,\n  createIndex: async (fileName) => {\n    const content = JSON.parse(fs.readFileSync(fileName));\n\n    const stories = generateStoryIndexesFromJson(content);\n\n    return stories.map((story) => ({\n      type: 'story',\n      importPath: `virtual:jsonstories--${fileName}--${story.componentName}`,\n      exportName: story.name,\n    }));\n  },\n};\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: [\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n    // 👇 Make sure files to index are included in `stories`\n    '../src/**/*.stories.json',\n  ],\n  experimental_indexers: async (existingIndexers) => [...existingIndexers, jsonStoriesIndexer],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-indexers-title.md",
    "content": "```js filename=\".storybook/main.ts\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nconst combosIndexer = {\n  test: /\\.stories\\.[tj]sx?$/,\n  createIndex: async (fileName, { makeTitle }) => {\n    // 👇 Grab title from fileName\n    const title = fileName.match(/\\/(.*)\\.stories/)[1];\n\n    // Read file and generate entries ...\n    let entries = [];\n    // Read file and generate entries...\n\n    return entries.map((entry) => ({\n      type: 'story',\n      // 👇 Use makeTitle to format the title\n      title: `${makeTitle(title)} Custom`,\n      importPath: fileName,\n      exportName: entry.name,\n    }));\n  },\n};\n\nconst config = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],\n  experimental_indexers: async (existingIndexers) => [...existingIndexers, combosIndexer],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\nimport type { Indexer } from 'storybook/internal/types';\n\nconst combosIndexer: Indexer = {\n  test: /\\.stories\\.[tj]sx?$/,\n  createIndex: async (fileName, { makeTitle }) => {\n    // 👇 Grab title from fileName\n    const title = fileName.match(/\\/(.*)\\.stories/)[1];\n\n    // Read file and generate entries ...\n    const entries = [];\n\n    return entries.map((entry) => ({\n      type: 'story',\n      // 👇 Use makeTitle to format the title\n      title: `${makeTitle(title)} Custom`,\n      importPath: fileName,\n      exportName: entry.name,\n    }));\n  },\n};\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],\n  experimental_indexers: async (existingIndexers) => [...existingIndexers, combosIndexer],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport type { Indexer } from 'storybook/internal/types';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nconst combosIndexer: Indexer = {\n  test: /\\.stories\\.[tj]sx?$/,\n  createIndex: async (fileName, { makeTitle }) => {\n    // 👇 Grab title from fileName\n    const title = fileName.match(/\\/(.*)\\.stories/)[1];\n\n    // Read file and generate entries ...\n    const entries = [];\n\n    return entries.map((entry) => ({\n      type: 'story',\n      // 👇 Use makeTitle to format the title\n      title: `${makeTitle(title)} Custom`,\n      importPath: fileName,\n      exportName: entry.name,\n    }));\n  },\n};\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],\n  experimental_indexers: async (existingIndexers) => [...existingIndexers, combosIndexer],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.ts\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nconst combosIndexer = {\n  test: /\\.stories\\.[tj]sx?$/,\n  createIndex: async (fileName, { makeTitle }) => {\n    // 👇 Grab title from fileName\n    const title = fileName.match(/\\/(.*)\\.stories/)[1];\n\n    // Read file and generate entries ...\n    let entries = [];\n    // Read file and generate entries...\n\n    return entries.map((entry) => ({\n      type: 'story',\n      // 👇 Use makeTitle to format the title\n      title: `${makeTitle(title)} Custom`,\n      importPath: fileName,\n      exportName: entry.name,\n    }));\n  },\n};\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],\n  experimental_indexers: async (existingIndexers) => [...existingIndexers, combosIndexer],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nconst combosIndexer = {\n  test: /\\.stories\\.[tj]sx?$/,\n  createIndex: async (fileName, { makeTitle }) => {\n    // 👇 Grab title from fileName\n    const title = fileName.match(/\\/(.*)\\.stories/)[1];\n\n    // Read file and generate entries ...\n    let entries = [];\n    // Read file and generate entries...\n\n    return entries.map((entry) => ({\n      type: 'story',\n      // 👇 Use makeTitle to format the title\n      title: `${makeTitle(title)} Custom`,\n      importPath: fileName,\n      exportName: entry.name,\n    }));\n  },\n};\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],\n  experimental_indexers: async (existingIndexers) => [...existingIndexers, combosIndexer],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nconst combosIndexer = {\n  test: /\\.stories\\.[tj]sx?$/,\n  createIndex: async (fileName, { makeTitle }) => {\n    // 👇 Grab title from fileName\n    const title = fileName.match(/\\/(.*)\\.stories/)[1];\n\n    // Read file and generate entries ...\n    let entries = [];\n    // Read file and generate entries...\n\n    return entries.map((entry) => ({\n      type: 'story',\n      // 👇 Use makeTitle to format the title\n      title: `${makeTitle(title)} Custom`,\n      importPath: fileName,\n      exportName: entry.name,\n    }));\n  },\n};\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],\n  experimental_indexers: async (existingIndexers) => [...existingIndexers, combosIndexer],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nconst combosIndexer = {\n  test: /\\.stories\\.[tj]sx?$/,\n  createIndex: async (fileName, { makeTitle }) => {\n    // 👇 Grab title from fileName\n    const title = fileName.match(/\\/(.*)\\.stories/)[1];\n\n    // Read file and generate entries ...\n    let entries = [];\n    // Read file and generate entries...\n\n    return entries.map((entry) => ({\n      type: 'story',\n      // 👇 Use makeTitle to format the title\n      title: `${makeTitle(title)} Custom`,\n      importPath: fileName,\n      exportName: entry.name,\n    }));\n  },\n};\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],\n  experimental_indexers: async (existingIndexers) => [...existingIndexers, combosIndexer],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nconst combosIndexer = {\n  test: /\\.stories\\.[tj]sx?$/,\n  createIndex: async (fileName, { makeTitle }) => {\n    // 👇 Grab title from fileName\n    const title = fileName.match(/\\/(.*)\\.stories/)[1];\n\n    // Read file and generate entries ...\n    let entries = [];\n    // Read file and generate entries...\n\n    return entries.map((entry) => ({\n      type: 'story',\n      // 👇 Use makeTitle to format the title\n      title: `${makeTitle(title)} Custom`,\n      importPath: fileName,\n      exportName: entry.name,\n    }));\n  },\n};\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],\n  experimental_indexers: async (existingIndexers) => [...existingIndexers, combosIndexer],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nconst combosIndexer = {\n  test: /\\.stories\\.[tj]sx?$/,\n  createIndex: async (fileName, { makeTitle }) => {\n    // 👇 Grab title from fileName\n    const title = fileName.match(/\\/(.*)\\.stories/)[1];\n\n    // Read file and generate entries ...\n    let entries = [];\n    // Read file and generate entries...\n\n    return entries.map((entry) => ({\n      type: 'story',\n      // 👇 Use makeTitle to format the title\n      title: `${makeTitle(title)} Custom`,\n      importPath: fileName,\n      exportName: entry.name,\n    }));\n  },\n};\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],\n  experimental_indexers: async (existingIndexers) => [...existingIndexers, combosIndexer],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-indexers.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: [\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n    // 👇 Make sure files to index are included in `stories`\n    '../src/**/*.custom-stories.@(js|jsx|ts|tsx)',\n  ],\n  experimental_indexers: async (existingIndexers) => {\n    const customIndexer = {\n      test: /\\.custom-stories\\.[tj]sx?$/,\n      createIndex: async (fileName) => {\n        // See API and examples below...\n      },\n    };\n    return [...existingIndexers, customIndexer];\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: [\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n    // 👇 Make sure files to index are included in `stories`\n    '../src/**/*.custom-stories.@(js|jsx|ts|tsx)',\n  ],\n  experimental_indexers: async (existingIndexers) => {\n    const customIndexer = {\n      test: /\\.custom-stories\\.[tj]sx?$/,\n      createIndex: async (fileName) => {\n        // See API and examples below...\n      },\n    };\n    return [...existingIndexers, customIndexer];\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: [\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n    // 👇 Make sure files to index are included in `stories`\n    '../src/**/*.custom-stories.@(js|jsx|ts|tsx)',\n  ],\n  experimental_indexers: async (existingIndexers) => {\n    const customIndexer = {\n      test: /\\.custom-stories\\.[tj]sx?$/,\n      createIndex: async (fileName) => {\n        // See API and examples below...\n      },\n    };\n    return [...existingIndexers, customIndexer];\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: [\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n    // 👇 Make sure files to index are included in `stories`\n    '../src/**/*.custom-stories.@(js|jsx|ts|tsx)',\n  ],\n  experimental_indexers: async (existingIndexers) => {\n    const customIndexer = {\n      test: /\\.custom-stories\\.[tj]sx?$/,\n      createIndex: async (fileName) => {\n        // See API and examples below...\n      },\n    };\n    return [...existingIndexers, customIndexer];\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: [\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n    // 👇 Make sure files to index are included in `stories`\n    '../src/**/*.custom-stories.@(js|jsx|ts|tsx)',\n  ],\n  experimental_indexers: async (existingIndexers) => {\n    const customIndexer = {\n      test: /\\.custom-stories\\.[tj]sx?$/,\n      createIndex: async (fileName) => {\n        // See API and examples below...\n      },\n    };\n    return [...existingIndexers, customIndexer];\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: [\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n    // 👇 Make sure files to index are included in `stories`\n    '../src/**/*.custom-stories.@(js|jsx|ts|tsx)',\n  ],\n  experimental_indexers: async (existingIndexers) => {\n    const customIndexer = {\n      test: /\\.custom-stories\\.[tj]sx?$/,\n      createIndex: async (fileName) => {\n        // See API and examples below...\n      },\n    };\n    return [...existingIndexers, customIndexer];\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: [\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n    // 👇 Make sure files to index are included in `stories`\n    '../src/**/*.custom-stories.@(js|jsx|ts|tsx)',\n  ],\n  experimental_indexers: async (existingIndexers) => {\n    const customIndexer = {\n      test: /\\.custom-stories\\.[tj]sx?$/,\n      createIndex: async (fileName) => {\n        // See API and examples below...\n      },\n    };\n    return [...existingIndexers, customIndexer];\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: [\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n    // 👇 Make sure files to index are included in `stories`\n    '../src/**/*.custom-stories.@(js|jsx|ts|tsx)',\n  ],\n  experimental_indexers: async (existingIndexers) => {\n    const customIndexer = {\n      test: /\\.custom-stories\\.[tj]sx?$/,\n      createIndex: async (fileName) => {\n        // See API and examples below...\n      },\n    };\n    return [...existingIndexers, customIndexer];\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: [\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n    // 👇 Make sure files to index are included in `stories`\n    '../src/**/*.custom-stories.@(js|jsx|ts|tsx)',\n  ],\n  experimental_indexers: async (existingIndexers) => {\n    const customIndexer = {\n      test: /\\.custom-stories\\.[tj]sx?$/,\n      createIndex: async (fileName) => {\n        // See API and examples below...\n      },\n    };\n    return [...existingIndexers, customIndexer];\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-log-level.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  logLevel: 'debug',\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  logLevel: 'debug',\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  logLevel: 'debug',\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  logLevel: 'debug',\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  logLevel: 'debug',\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  logLevel: 'debug',\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  logLevel: 'debug',\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  logLevel: 'debug',\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-manager-head.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  managerHead: (head) => `\n    ${head}\n    <link rel=\"preload\" href=\"/fonts/my-custom-manager-font.woff2\" />\n  `,\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  managerHead: (head) => `\n    ${head}\n    <link rel=\"preload\" href=\"/fonts/my-custom-manager-font.woff2\" />\n  `,\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  managerHead: (head) => `\n    ${head}\n    <link rel=\"preload\" href=\"/fonts/my-custom-manager-font.woff2\" />\n  `,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  managerHead: (head) => `\n    ${head}\n    <link rel=\"preload\" href=\"/fonts/my-custom-manager-font.woff2\" />\n  `,\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  managerHead: (head) => `\n    ${head}\n    <link rel=\"preload\" href=\"/fonts/my-custom-manager-font.woff2\" />\n  `,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  managerHead: (head) => `\n    ${head}\n    <link rel=\"preload\" href=\"/fonts/my-custom-manager-font.woff2\" />\n  `,\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  managerHead: (head) => `\n    ${head}\n    <link rel=\"preload\" href=\"/fonts/my-custom-manager-font.woff2\" />\n  `,\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  managerHead: (head) => `\n    ${head}\n    <link rel=\"preload\" href=\"/fonts/my-custom-manager-font.woff2\" />\n  `,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  managerHead: (head) => `\n    ${head}\n    <link rel=\"preload\" href=\"/fonts/my-custom-manager-font.woff2\" />\n  `,\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-preview-body.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  previewBody: (body) => `\n    ${body}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  previewBody: (body) => `\n    ${body}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  previewBody: (body) => `\n    ${body}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  previewBody: (body) => `\n    ${body}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  previewBody: (body) => `\n    ${body}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  previewBody: (body) => `\n    ${body}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  previewBody: (body) => `\n    ${body}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  previewBody: (body) => `\n    ${body}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  previewBody: (body) => `\n    ${body}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-preview-head.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  previewHead: (head) => `\n    ${head}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  previewHead: (head) => `\n    ${head}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  previewHead: (head) => `\n    ${head}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  previewHead: (head) => `\n    ${head}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  previewHead: (head) => `\n    ${head}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  previewHead: (head) => `\n    ${head}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  previewHead: (head) => `\n    ${head}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  previewHead: (head) => `\n    ${head}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  previewHead: (head) => `\n    ${head}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-preview.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"Body (CSF 3)\"\nexport default {\n  previewBody: (body) => `\n    ${body}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"Body (CSF 3)\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  previewBody: (body) => `\n    ${body}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n};\n\nexport default config;\n```\n\n```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"Head (CSF 3)\"\nexport default {\n  previewHead: (head) => `\n    ${head}\n    <style>\n      html, body {\n        background: #827979;\n      }\n    </style>\n `,\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"Head (CSF 3)\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  previewHead: (head) => `\n    ${head}\n    <style>\n      html, body {\n        background: #827979;\n      }\n    </style>\n `,\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"Body (CSF Next 🧪)\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  previewBody: (body) => `\n    ${body}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"Body (CSF Next 🧪)\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  previewBody: (body) => `\n    ${body}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"Head (CSF Next 🧪)\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  previewHead: (head) => `\n    ${head}\n    <style>\n      html, body {\n        background: #827979;\n      }\n    </style>\n `,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"Head (CSF Next 🧪)\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  previewHead: (head) => `\n    ${head}\n    <style>\n      html, body {\n        background: #827979;\n      }\n    </style>\n `,\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"Head (CSF Next 🧪)\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  previewHead: (head) => `\n    ${head}\n    <style>\n      html, body {\n        background: #827979;\n      }\n    </style>\n `,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"Head (CSF Next 🧪)\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  previewHead: (head) => `\n    ${head}\n    <style>\n      html, body {\n        background: #827979;\n      }\n    </style>\n `,\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"Body (CSF Next 🧪)\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  previewBody: (body) => `\n    ${body}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"angular\" language=\"js\" tabTitle=\"Body (CSF Next 🧪)\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  previewBody: (body) => `\n    ${body}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"Head (CSF Next 🧪)\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  previewHead: (head) => `\n    ${head}\n    <style>\n      html, body {\n        background: #827979;\n      }\n    </style>\n `,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"angular\" language=\"js\" tabTitle=\"Head (CSF Next 🧪)\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  previewHead: (head) => `\n    ${head}\n    <style>\n      html, body {\n        background: #827979;\n      }\n    </style>\n `,\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"Body (CSF Next 🧪)\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  previewBody: (body) => `\n    ${body}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"Body (CSF Next 🧪)\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  previewBody: (body) => `\n    ${body}\n    ${\n      process.env.ANALYTICS_ID ? '<script src=\"https://cdn.example.com/analytics.js\"></script>' : ''\n    }\n  `,\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"Head (CSF Next 🧪)\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  previewHead: (head) => `\n    ${head}\n    <style>\n      html, body {\n        background: #827979;\n      }\n    </style>\n `,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"Head (CSF Next 🧪)\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  previewHead: (head) => `\n    ${head}\n    <style>\n      html, body {\n        background: #827979;\n      }\n    </style>\n `,\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-refs-disable.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    'package-name': { disable: true },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    'package-name': { disable: true },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    'package-name': { disable: true },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    'package-name': { disable: true },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    'package-name': { disable: true },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    'package-name': { disable: true },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    'package-name': { disable: true },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    'package-name': { disable: true },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    'package-name': { disable: true },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-refs-with-function.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  // 👇 Retrieve the current environment from the configType argument\n  refs: (config, { configType }) => {\n    if (configType === 'DEVELOPMENT') {\n      return {\n        react: {\n          title: 'Composed React Storybook running in development mode',\n          url: 'http://localhost:7007',\n        },\n        angular: {\n          title: 'Composed Angular Storybook running in development mode',\n          url: 'http://localhost:7008',\n        },\n      };\n    }\n    return {\n      react: {\n        title: 'Composed React Storybook running in production',\n        url: 'https://your-production-react-storybook-url',\n      },\n      angular: {\n        title: 'Composed Angular Storybook running in production',\n        url: 'https://your-production-angular-storybook-url',\n      },\n    };\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  // 👇 Retrieve the current environment from the configType argument\n  refs: (config, { configType }) => {\n    if (configType === 'DEVELOPMENT') {\n      return {\n        react: {\n          title: 'Composed React Storybook running in development mode',\n          url: 'http://localhost:7007',\n        },\n        angular: {\n          title: 'Composed Angular Storybook running in development mode',\n          url: 'http://localhost:7008',\n        },\n      };\n    }\n    return {\n      react: {\n        title: 'Composed React Storybook running in production',\n        url: 'https://your-production-react-storybook-url',\n      },\n      angular: {\n        title: 'Composed Angular Storybook running in production',\n        url: 'https://your-production-angular-storybook-url',\n      },\n    };\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  // 👇 Retrieve the current environment from the configType argument\n  refs: (config, { configType }) => {\n    if (configType === 'DEVELOPMENT') {\n      return {\n        react: {\n          title: 'Composed React Storybook running in development mode',\n          url: 'http://localhost:7007',\n        },\n        angular: {\n          title: 'Composed Angular Storybook running in development mode',\n          url: 'http://localhost:7008',\n        },\n      };\n    }\n    return {\n      react: {\n        title: 'Composed React Storybook running in production',\n        url: 'https://your-production-react-storybook-url',\n      },\n      angular: {\n        title: 'Composed Angular Storybook running in production',\n        url: 'https://your-production-angular-storybook-url',\n      },\n    };\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  // 👇 Retrieve the current environment from the configType argument\n  refs: (config, { configType }) => {\n    if (configType === 'DEVELOPMENT') {\n      return {\n        react: {\n          title: 'Composed React Storybook running in development mode',\n          url: 'http://localhost:7007',\n        },\n        angular: {\n          title: 'Composed Angular Storybook running in development mode',\n          url: 'http://localhost:7008',\n        },\n      };\n    }\n    return {\n      react: {\n        title: 'Composed React Storybook running in production',\n        url: 'https://your-production-react-storybook-url',\n      },\n      angular: {\n        title: 'Composed Angular Storybook running in production',\n        url: 'https://your-production-angular-storybook-url',\n      },\n    };\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  // 👇 Retrieve the current environment from the configType argument\n  refs: (config, { configType }) => {\n    if (configType === 'DEVELOPMENT') {\n      return {\n        react: {\n          title: 'Composed React Storybook running in development mode',\n          url: 'http://localhost:7007',\n        },\n        angular: {\n          title: 'Composed Angular Storybook running in development mode',\n          url: 'http://localhost:7008',\n        },\n      };\n    }\n    return {\n      react: {\n        title: 'Composed React Storybook running in production',\n        url: 'https://your-production-react-storybook-url',\n      },\n      angular: {\n        title: 'Composed Angular Storybook running in production',\n        url: 'https://your-production-angular-storybook-url',\n      },\n    };\n  },\n});\n```\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  // 👇 Retrieve the current environment from the configType argument\n  refs: (config, { configType }) => {\n    if (configType === 'DEVELOPMENT') {\n      return {\n        react: {\n          title: 'Composed React Storybook running in development mode',\n          url: 'http://localhost:7007',\n        },\n        angular: {\n          title: 'Composed Angular Storybook running in development mode',\n          url: 'http://localhost:7008',\n        },\n      };\n    }\n    return {\n      react: {\n        title: 'Composed React Storybook running in production',\n        url: 'https://your-production-react-storybook-url',\n      },\n      angular: {\n        title: 'Composed Angular Storybook running in production',\n        url: 'https://your-production-angular-storybook-url',\n      },\n    };\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  // 👇 Retrieve the current environment from the configType argument\n  refs: (config, { configType }) => {\n    if (configType === 'DEVELOPMENT') {\n      return {\n        react: {\n          title: 'Composed React Storybook running in development mode',\n          url: 'http://localhost:7007',\n        },\n        angular: {\n          title: 'Composed Angular Storybook running in development mode',\n          url: 'http://localhost:7008',\n        },\n      };\n    }\n    return {\n      react: {\n        title: 'Composed React Storybook running in production',\n        url: 'https://your-production-react-storybook-url',\n      },\n      angular: {\n        title: 'Composed Angular Storybook running in production',\n        url: 'https://your-production-angular-storybook-url',\n      },\n    };\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  // 👇 Retrieve the current environment from the configType argument\n  refs: (config, { configType }) => {\n    if (configType === 'DEVELOPMENT') {\n      return {\n        react: {\n          title: 'Composed React Storybook running in development mode',\n          url: 'http://localhost:7007',\n        },\n        angular: {\n          title: 'Composed Angular Storybook running in development mode',\n          url: 'http://localhost:7008',\n        },\n      };\n    }\n    return {\n      react: {\n        title: 'Composed React Storybook running in production',\n        url: 'https://your-production-react-storybook-url',\n      },\n      angular: {\n        title: 'Composed Angular Storybook running in production',\n        url: 'https://your-production-angular-storybook-url',\n      },\n    };\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  // 👇 Retrieve the current environment from the configType argument\n  refs: (config, { configType }) => {\n    if (configType === 'DEVELOPMENT') {\n      return {\n        react: {\n          title: 'Composed React Storybook running in development mode',\n          url: 'http://localhost:7007',\n        },\n        angular: {\n          title: 'Composed Angular Storybook running in development mode',\n          url: 'http://localhost:7008',\n        },\n      };\n    }\n    return {\n      react: {\n        title: 'Composed React Storybook running in production',\n        url: 'https://your-production-react-storybook-url',\n      },\n      angular: {\n        title: 'Composed Angular Storybook running in production',\n        url: 'https://your-production-angular-storybook-url',\n      },\n    };\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-refs.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    'design-system': {\n      title: 'Storybook Design System',\n      url: 'https://master--5ccbc373887ca40020446347.chromatic.com/',\n      expanded: false, // Optional, true by default\n      sourceUrl: 'https://github.com/storybookjs/storybook', // Optional\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    'design-system': {\n      title: 'Storybook Design System',\n      url: 'https://master--5ccbc373887ca40020446347.chromatic.com/',\n      expanded: false, // Optional, true by default,\n      sourceUrl: 'https://github.com/storybookjs/storybook', // Optional\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    'design-system': {\n      title: 'Storybook Design System',\n      url: 'https://master--5ccbc373887ca40020446347.chromatic.com/',\n      expanded: false, // Optional, true by default,\n      sourceUrl: 'https://github.com/storybookjs/storybook', // Optional\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    'design-system': {\n      title: 'Storybook Design System',\n      url: 'https://master--5ccbc373887ca40020446347.chromatic.com/',\n      expanded: false, // Optional, true by default\n      sourceUrl: 'https://github.com/storybookjs/storybook', // Optional\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    'design-system': {\n      title: 'Storybook Design System',\n      url: 'https://master--5ccbc373887ca40020446347.chromatic.com/',\n      expanded: false, // Optional, true by default\n      sourceUrl: 'https://github.com/storybookjs/storybook', // Optional\n    },\n  },\n});\n```\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    'design-system': {\n      title: 'Storybook Design System',\n      url: 'https://master--5ccbc373887ca40020446347.chromatic.com/',\n      expanded: false, // Optional, true by default\n      sourceUrl: 'https://github.com/storybookjs/storybook', // Optional\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    'design-system': {\n      title: 'Storybook Design System',\n      url: 'https://master--5ccbc373887ca40020446347.chromatic.com/',\n      expanded: false, // Optional, true by default\n      sourceUrl: 'https://github.com/storybookjs/storybook', // Optional\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    'design-system': {\n      title: 'Storybook Design System',\n      url: 'https://master--5ccbc373887ca40020446347.chromatic.com/',\n      expanded: false, // Optional, true by default\n      sourceUrl: 'https://github.com/storybookjs/storybook', // Optional\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    'design-system': {\n      title: 'Storybook Design System',\n      url: 'https://master--5ccbc373887ca40020446347.chromatic.com/',\n      expanded: false, // Optional, true by default\n      sourceUrl: 'https://github.com/storybookjs/storybook', // Optional\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-static-dirs-with-object.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  staticDirs: [{ from: '../my-custom-assets/images', to: '/assets' }],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  staticDirs: [{ from: '../my-custom-assets/images', to: '/assets' }],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  staticDirs: [{ from: '../my-custom-assets/images', to: '/assets' }],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  staticDirs: [{ from: '../my-custom-assets/images', to: '/assets' }],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  staticDirs: [{ from: '../my-custom-assets/images', to: '/assets' }],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  staticDirs: [{ from: '../my-custom-assets/images', to: '/assets' }],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  staticDirs: [{ from: '../my-custom-assets/images', to: '/assets' }],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  staticDirs: [{ from: '../my-custom-assets/images', to: '/assets' }],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  staticDirs: [{ from: '../my-custom-assets/images', to: '/assets' }],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-static-dirs.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  staticDirs: ['../public', '../static'],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  staticDirs: ['../public', '../static'],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  staticDirs: ['../public', '../static'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  staticDirs: ['../public', '../static'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  staticDirs: ['../public', '../static'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  staticDirs: ['../public', '../static'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  staticDirs: ['../public', '../static'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  staticDirs: ['../public', '../static'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  staticDirs: ['../public', '../static'],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-stories-only-mdx.md",
    "content": "```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g., nextjs-vite, vue3-vite, angular, sveltekit, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  // ...\n  // define at least one local story/page here\n  stories: ['../Introduction.mdx'],\n  // define composed Storybooks here\n  refs: {\n    firstProject: { title: 'First', url: 'some-url' },\n    secondProject: { title: 'Second', url: 'other-url' },\n  },\n};\n\nexport default preview;\n```\n\n```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // ...\n  // define at least one local story/page here\n  stories: ['../Introduction.mdx'],\n  // define composed Storybooks here\n  refs: {\n    firstProject: { title: 'First', url: 'some-url' },\n    secondProject: { title: 'Second', url: 'other-url' },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using, e.g., nextjs, nextjs-vite, react-vite, etc.\nimport { defineMain } from '@storybook/your-framework/node';\n\nconst config = defineMain({\n  // ...\n  // define at least one local story/page here\n  stories: ['../Introduction.mdx'],\n  // define composed Storybooks here\n  refs: {\n    firstProject: { title: 'First', url: 'some-url' },\n    secondProject: { title: 'Second', url: 'other-url' },\n  },\n});\n\nexport default config;\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using, e.g., nextjs, nextjs-vite, react-vite, etc.\nimport { defineMain } from '@storybook/your-framework/node';\n\nconst config = defineMain({\n  // ...\n  // define at least one local story/page here\n  stories: ['../Introduction.mdx'],\n  // define composed Storybooks here\n  refs: {\n    firstProject: { title: 'First', url: 'some-url' },\n    secondProject: { title: 'Second', url: 'other-url' },\n  },\n});\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nconst config = defineMain({\n  // ...\n  // define at least one local story/page here\n  stories: ['../Introduction.mdx'],\n  // define composed Storybooks here\n  refs: {\n    firstProject: { title: 'First', url: 'some-url' },\n    secondProject: { title: 'Second', url: 'other-url' },\n  },\n});\n\nexport default config;\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nconst config = defineMain({\n  // ...\n  // define at least one local story/page here\n  stories: ['../Introduction.mdx'],\n  // define composed Storybooks here\n  refs: {\n    firstProject: { title: 'First', url: 'some-url' },\n    secondProject: { title: 'Second', url: 'other-url' },\n  },\n});\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nconst config = defineMain({\n  // ...\n  // define at least one local story/page here\n  stories: ['../Introduction.mdx'],\n  // define composed Storybooks here\n  refs: {\n    firstProject: { title: 'First', url: 'some-url' },\n    secondProject: { title: 'Second', url: 'other-url' },\n  },\n});\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nconst config = defineMain({\n  // ...\n  // define at least one local story/page here\n  stories: ['../Introduction.mdx'],\n  // define composed Storybooks here\n  refs: {\n    firstProject: { title: 'First', url: 'some-url' },\n    secondProject: { title: 'Second', url: 'other-url' },\n  },\n});\n\nexport default config;\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nconst config = defineMain({\n  // ...\n  // define at least one local story/page here\n  stories: ['../Introduction.mdx'],\n  // define composed Storybooks here\n  refs: {\n    firstProject: { title: 'First', url: 'some-url' },\n    secondProject: { title: 'Second', url: 'other-url' },\n  },\n});\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-stories-ordered.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: [\n    '../src/**/*.mdx', // 👈 These will display first in the sidebar\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)', // 👈 Followed by these\n  ],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: [\n    '../src/**/*.mdx', // 👈 These will display first in the sidebar\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)', // 👈 Followed by these\n  ],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: [\n    '../src/**/*.mdx', // 👈 These will display first in the sidebar\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)', // 👈 Followed by these\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: [\n    '../src/**/*.mdx', // 👈 These will display first in the sidebar\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)', // 👈 Followed by these\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: [\n    '../src/**/*.mdx', // 👈 These will display first in the sidebar\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)', // 👈 Followed by these\n  ],\n});\n```\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: [\n    '../src/**/*.mdx', // 👈 These will display first in the sidebar\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)', // 👈 Followed by these\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: [\n    '../src/**/*.mdx', // 👈 These will display first in the sidebar\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)', // 👈 Followed by these\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: [\n    '../src/**/*.mdx', // 👈 These will display first in the sidebar\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)', // 👈 Followed by these\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: [\n    '../src/**/*.mdx', // 👈 These will display first in the sidebar\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)', // 👈 Followed by these\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-stories-with-logic.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nasync function findStories() {\n  // your custom logic returns a list of files\n}\n\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: async (list) => [\n    ...list,\n    // 👇 Add your found stories to the existing list of story files\n    ...(await findStories()),\n  ],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\nimport type { StoriesEntry } from 'storybook/internal/types';\n\nasync function findStories(): Promise<StoriesEntry[]> {\n  // your custom logic returns a list of files\n}\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: async (list: StoriesEntry[]) => [\n    ...list,\n    // 👇 Add your found stories to the existing list of story files\n    ...(await findStories()),\n  ],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport type { StoriesEntry } from 'storybook/internal/types';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nasync function findStories(): Promise<StoriesEntry[]> {\n  // your custom logic returns a list of files\n}\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: async (list: StoriesEntry[]) => [\n    ...list,\n    // 👇 Add your found stories to the existing list of story files\n    ...(await findStories()),\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nasync function findStories() {\n  // your custom logic returns a list of files\n}\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: async (list) => [\n    ...list,\n    // 👇 Add your found stories to the existing list of story files\n    ...(await findStories()),\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\nimport type { StoriesEntry } from 'storybook/internal/types';\n\nasync function findStories(): Promise<StoriesEntry[]> {\n  // your custom logic returns a list of files\n}\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: async (list: StoriesEntry[]) => [\n    ...list,\n    // 👇 Add your found stories to the existing list of story files\n    ...(await findStories()),\n  ],\n});\n```\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nasync function findStories() {\n  // your custom logic returns a list of files\n}\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: async (list) => [\n    ...list,\n    // 👇 Add your found stories to the existing list of story files\n    ...(await findStories()),\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nasync function findStories() {\n  // your custom logic returns a list of files\n}\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: async (list) => [\n    ...list,\n    // 👇 Add your found stories to the existing list of story files\n    ...(await findStories()),\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\nimport type { StoriesEntry } from 'storybook/internal/types';\n\nasync function findStories(): Promise<StoriesEntry[]> {\n  // your custom logic returns a list of files\n}\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: async (list: StoriesEntry[]) => [\n    ...list,\n    // 👇 Add your found stories to the existing list of story files\n    ...(await findStories()),\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nasync function findStories() {\n  // your custom logic returns a list of files\n}\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: async (list) => [\n    ...list,\n    // 👇 Add your found stories to the existing list of story files\n    ...(await findStories()),\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-stories-with-object.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: [\n    {\n      // 👇 Sets the directory containing your stories\n      directory: '../packages/components',\n      // 👇 Storybook will load all files that match this glob\n      files: '*.stories.*',\n      // 👇 Used when generating automatic titles for your stories\n      titlePrefix: 'MyComponents',\n    },\n  ],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: [\n    {\n      // 👇 Sets the directory containing your stories\n      directory: '../packages/components',\n      // 👇 Storybook will load all files that match this glob\n      files: '*.stories.*',\n      // 👇 Used when generating automatic titles for your stories\n      titlePrefix: 'MyComponents',\n    },\n  ],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: [\n    {\n      // 👇 Sets the directory containing your stories\n      directory: '../packages/components',\n      // 👇 Storybook will load all files that match this glob\n      files: '*.stories.*',\n      // 👇 Used when generating automatic titles for your stories\n      titlePrefix: 'MyComponents',\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: [\n    {\n      // 👇 Sets the directory containing your stories\n      directory: '../packages/components',\n      // 👇 Storybook will load all files that match this glob\n      files: '*.stories.*',\n      // 👇 Used when generating automatic titles for your stories\n      titlePrefix: 'MyComponents',\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: [\n    {\n      // 👇 Sets the directory containing your stories\n      directory: '../packages/components',\n      // 👇 Storybook will load all files that match this glob\n      files: '*.stories.*',\n      // 👇 Used when generating automatic titles for your stories\n      titlePrefix: 'MyComponents',\n    },\n  ],\n});\n```\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: [\n    {\n      // 👇 Sets the directory containing your stories\n      directory: '../packages/components',\n      // 👇 Storybook will load all files that match this glob\n      files: '*.stories.*',\n      // 👇 Used when generating automatic titles for your stories\n      titlePrefix: 'MyComponents',\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: [\n    {\n      // 👇 Sets the directory containing your stories\n      directory: '../packages/components',\n      // 👇 Storybook will load all files that match this glob\n      files: '*.stories.*',\n      // 👇 Used when generating automatic titles for your stories\n      titlePrefix: 'MyComponents',\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: [\n    {\n      // 👇 Sets the directory containing your stories\n      directory: '../packages/components',\n      // 👇 Storybook will load all files that match this glob\n      files: '*.stories.*',\n      // 👇 Used when generating automatic titles for your stories\n      titlePrefix: 'MyComponents',\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: [\n    {\n      // 👇 Sets the directory containing your stories\n      directory: '../packages/components',\n      // 👇 Storybook will load all files that match this glob\n      files: '*.stories.*',\n      // 👇 Used when generating automatic titles for your stories\n      titlePrefix: 'MyComponents',\n    },\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-stories.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-svelte-csf-register.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"svelte\" language=\"js\"\nexport default {\n  stories: ['../src/**/*.stories.@(js|jsx|ts|tsx|svelte)'],\n  addons: [\n    // Other Storybook addons\n    '@storybook/addon-svelte-csf',\n  ],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"svelte\" language=\"ts\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  stories: ['../src/**/*.stories.@(js|jsx|ts|tsx|svelte)'],\n  addons: [\n    // Other Storybook addons\n    '@storybook/addon-svelte-csf',\n  ],\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-swc-jsx-transform.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  framework: {\n    name: '@storybook/your-framework',\n    options: {},\n  },\n  swc: (config, options) => ({\n    jsc: {\n      transform: {\n        react: {\n          runtime: 'automatic',\n        },\n      },\n    },\n  }),\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the webpack-based framework you are using (e.g., react-webpack5)\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: {\n    name: '@storybook/your-framework',\n    options: {},\n  },\n  swc: (config, options) => ({\n    jsc: {\n      transform: {\n        react: {\n          runtime: 'automatic',\n        },\n      },\n    },\n  }),\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: {\n    name: '@storybook/your-framework',\n    options: {},\n  },\n  swc: (config, options) => ({\n    jsc: {\n      transform: {\n        react: {\n          runtime: 'automatic',\n        },\n      },\n    },\n  }),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: {\n    name: '@storybook/your-framework',\n    options: {},\n  },\n  swc: (config, options) => ({\n    jsc: {\n      transform: {\n        react: {\n          runtime: 'automatic',\n        },\n      },\n    },\n  }),\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-swc.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  framework: {\n    name: '@storybook/your-framework',\n    options: {},\n  },\n  swc: (config, options) => {\n    return {\n      ...config,\n      // Apply your custom SWC configuration\n    };\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Options } from '@swc/core';\n\n// Replace your-framework with the webpack-based framework you are using (e.g., react-webpack5)\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: {\n    name: '@storybook/your-framework',\n    options: {},\n  },\n  swc: (config: Options, options): Options => {\n    return {\n      ...config,\n      // Apply your custom SWC configuration\n    };\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport type { Options } from '@swc/core';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: {\n    name: '@storybook/your-framework',\n    options: {},\n  },\n  swc: (config: Options, options): Options => {\n    return {\n      ...config,\n      // Apply your custom SWC configuration\n    };\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: {\n    name: '@storybook/your-framework',\n    options: {},\n  },\n  swc: (config, options) => {\n    return {\n      ...config,\n      // Apply your custom SWC configuration\n    };\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-tags-test-fn-exclude.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  tags: {\n    // 👇 Adjust the default configuration of this tag\n    _test: {\n      defaultFilterSelection: 'exclude',\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  tags: {\n    // 👇 Adjust the default configuration of this tag\n    _test: {\n      defaultFilterSelection: 'exclude',\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  tags: {\n    // 👇 Adjust the default configuration of this tag\n    _test: {\n      defaultFilterSelection: 'exclude',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\n  framework: '@storybook/your-framework',\n\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n\n  tags: {\n    // 👇 Adjust the default configuration of this tag\n    _test: {\n      defaultFilterSelection: 'exclude',\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  tags: {\n    // 👇 Adjust the default configuration of this tag\n    _test: {\n      defaultFilterSelection: 'exclude',\n    },\n  },\n});\n```\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  tags: {\n    // 👇 Adjust the default configuration of this tag\n    _test: {\n      defaultFilterSelection: 'exclude',\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  tags: {\n    // 👇 Adjust the default configuration of this tag\n    _test: {\n      defaultFilterSelection: 'exclude',\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  tags: {\n    // 👇 Adjust the default configuration of this tag\n    _test: {\n      defaultFilterSelection: 'exclude',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  tags: {\n    // 👇 Adjust the default configuration of this tag\n    _test: {\n      defaultFilterSelection: 'exclude',\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-tags.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  tags: {\n    // 👇 Define a custom tag named \"experimental\"\n    experimental: {\n      defaultFilterSelection: 'exclude', // Or 'include'\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  tags: {\n    // 👇 Define a custom tag named \"experimental\"\n    experimental: {\n      defaultFilterSelection: 'exclude', // Or 'include'\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  tags: {\n    // 👇 Define a custom tag named \"experimental\"\n    experimental: {\n      defaultFilterSelection: 'exclude', // Or 'include'\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  tags: {\n    // 👇 Define a custom tag named \"experimental\"\n    experimental: {\n      defaultFilterSelection: 'exclude', // Or 'include'\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  tags: {\n    // 👇 Define a custom tag named \"experimental\"\n    experimental: {\n      defaultFilterSelection: 'exclude', // Or 'include'\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  tags: {\n    // 👇 Define a custom tag named \"experimental\"\n    experimental: {\n      defaultFilterSelection: 'exclude', // Or 'include'\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  tags: {\n    // 👇 Define a custom tag named \"experimental\"\n    experimental: {\n      defaultFilterSelection: 'exclude', // Or 'include'\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  tags: {\n    // 👇 Define a custom tag named \"experimental\"\n    experimental: {\n      defaultFilterSelection: 'exclude', // Or 'include'\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  tags: {\n    // 👇 Define a custom tag named \"experimental\"\n    experimental: {\n      defaultFilterSelection: 'exclude', // Or 'include'\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-test-disable-autodocs.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableAutoDocs: false,\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableAutoDocs: false,\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableAutoDocs: false,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableAutoDocs: false,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableAutoDocs: false,\n    },\n  },\n});\n```\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableAutoDocs: false,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableAutoDocs: false,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableAutoDocs: false,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableAutoDocs: false,\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-test-disable-blocks.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableBlocks: false,\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableBlocks: false,\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableBlocks: false,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableBlocks: false,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableBlocks: false,\n    },\n  },\n});\n```\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableBlocks: false,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableBlocks: false,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableBlocks: false,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableBlocks: false,\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-test-disable-disableaddons.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-a11y', '@storybook/addon-vitest'],\n  build: {\n    test: {\n      disabledAddons: ['@storybook/addon-a11y'],\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-a11y', '@storybook/addon-vitest'],\n  build: {\n    test: {\n      disabledAddons: ['@storybook/addon-a11y'],\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-a11y', '@storybook/addon-vitest'],\n  build: {\n    test: {\n      disabledAddons: ['@storybook/addon-a11y'],\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-a11y', '@storybook/addon-vitest'],\n  build: {\n    test: {\n      disabledAddons: ['@storybook/addon-a11y'],\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-a11y', '@storybook/addon-vitest'],\n  build: {\n    test: {\n      disabledAddons: ['@storybook/addon-a11y'],\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-a11y', '@storybook/addon-vitest'],\n  build: {\n    test: {\n      disabledAddons: ['@storybook/addon-a11y'],\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-a11y', '@storybook/addon-vitest'],\n  build: {\n    test: {\n      disabledAddons: ['@storybook/addon-a11y'],\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-a11y', '@storybook/addon-vitest'],\n  build: {\n    test: {\n      disabledAddons: ['@storybook/addon-a11y'],\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-a11y', '@storybook/addon-vitest'],\n  build: {\n    test: {\n      disabledAddons: ['@storybook/addon-a11y'],\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-test-disable-docgen.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableDocgen: false,\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableDocgen: false,\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableDocgen: false,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableDocgen: false,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableDocgen: false,\n    },\n  },\n});\n```\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableDocgen: false,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableDocgen: false,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableDocgen: false,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableDocgen: false,\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-test-disable-mdx.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableMDXEntries: false,\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableMDXEntries: false,\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableMDXEntries: false,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableMDXEntries: false,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableMDXEntries: false,\n    },\n  },\n});\n```\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableMDXEntries: false,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableMDXEntries: false,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableMDXEntries: false,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableMDXEntries: false,\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-test-disable-sourcemaps.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableSourcemaps: false,\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableSourcemaps: false,\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableSourcemaps: false,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableSourcemaps: false,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableSourcemaps: false,\n    },\n  },\n});\n```\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableSourcemaps: false,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableSourcemaps: false,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableSourcemaps: false,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableSourcemaps: false,\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-test-disable-treeshaking.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableTreeShaking: false,\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableTreeShaking: false,\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableTreeShaking: false,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableTreeShaking: false,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableTreeShaking: false,\n    },\n  },\n});\n```\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableTreeShaking: false,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableTreeShaking: false,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableTreeShaking: false,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  build: {\n    test: {\n      disableTreeShaking: false,\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-typescript-check-options.md",
    "content": "```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-webpack5, nextjs, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    check: true,\n    checkOptions: {\n      eslint: true,\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-webpack5, nextjs, nextjs-webpack5)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    check: true,\n    checkOptions: {\n      eslint: true,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    check: true,\n    checkOptions: {\n      eslint: true,\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-typescript-check.md",
    "content": "```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    check: true,\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    check: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    check: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    check: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    check: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    check: true,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-typescript-react-docgen-typescript-options.md",
    "content": "```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    reactDocgen: 'react-docgen-typescript',\n    reactDocgenTypescriptOptions: {\n      shouldExtractLiteralValuesFromEnum: true,\n      // 👇 Default prop filter, which excludes props from node_modules\n      propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    reactDocgen: 'react-docgen-typescript',\n    reactDocgenTypescriptOptions: {\n      shouldExtractLiteralValuesFromEnum: true,\n      // 👇 Default prop filter, which excludes props from node_modules\n      propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-typescript-react-docgen.md",
    "content": "```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    reactDocgen: 'react-docgen',\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    reactDocgen: 'react-docgen',\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-typescript-skip-compiler.md",
    "content": "```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    skipCompiler: true,\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    skipCompiler: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    skipCompiler: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    skipCompiler: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    skipCompiler: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    skipCompiler: true,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-typical.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nconst config = {\n  // Required\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  // Optional\n  addons: ['@storybook/addon-docs'],\n  staticDirs: ['../public'],\n};\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  // Required\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  // Optional\n  addons: ['@storybook/addon-docs'],\n  staticDirs: ['../public'],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // Required\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  // Optional\n  addons: ['@storybook/addon-docs'],\n  staticDirs: ['../public'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // Required\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  // Optional\n  addons: ['@storybook/addon-docs'],\n  staticDirs: ['../public'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  // Required\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  // Optional\n  addons: ['@storybook/addon-docs'],\n  staticDirs: ['../public'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  // Required\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  // Optional\n  addons: ['@storybook/addon-docs'],\n  staticDirs: ['../public'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  // Required\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  // Optional\n  addons: ['@storybook/addon-docs'],\n  staticDirs: ['../public'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  // Required\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  // Optional\n  addons: ['@storybook/addon-docs'],\n  staticDirs: ['../public'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  // Required\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  // Optional\n  addons: ['@storybook/addon-docs'],\n  staticDirs: ['../public'],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-vite-final-env.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using (e.g., react-vite, vue3-vite, angular, etc.)\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config, { configType }) {\n    const { mergeConfig } = await import('vite');\n\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return mergeConfig(config, {\n      // Your environment configuration here\n    });\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using (e.g., react-vite, vue3-vite, angular, etc.)\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config, { configType }) {\n    const { mergeConfig } = await import('vite');\n\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return mergeConfig(config, {\n      // Your environment configuration here\n    });\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config, { configType }) {\n    const { mergeConfig } = await import('vite');\n\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return mergeConfig(config, {\n      // Your environment configuration here\n    });\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config, { configType }) {\n    const { mergeConfig } = await import('vite');\n\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return mergeConfig(config, {\n      // Your environment configuration here\n    });\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config, { configType }) {\n    const { mergeConfig } = await import('vite');\n\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return mergeConfig(config, {\n      // Your environment configuration here\n    });\n  },\n});\n```\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config, { configType }) {\n    const { mergeConfig } = await import('vite');\n\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return mergeConfig(config, {\n      // Your environment configuration here\n    });\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config, { configType }) {\n    const { mergeConfig } = await import('vite');\n\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return mergeConfig(config, {\n      // Your environment configuration here\n    });\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config, { configType }) {\n    const { mergeConfig } = await import('vite');\n\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return mergeConfig(config, {\n      // Your environment configuration here\n    });\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-vite-final.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs-vite, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config, { configType }) {\n    const { mergeConfig } = await import('vite');\n\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return mergeConfig(config, {\n      // Your environment configuration here\n    });\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs-vite, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config, { configType }) {\n    const { mergeConfig } = await import('vite');\n\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return mergeConfig(config, {\n      // Your environment configuration here\n    });\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config, { configType }) {\n    const { mergeConfig } = await import('vite');\n\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return mergeConfig(config, {\n      // Your environment configuration here\n    });\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config, { configType }) {\n    const { mergeConfig } = await import('vite');\n\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return mergeConfig(config, {\n      // Your environment configuration here\n    });\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config, { configType }) {\n    const { mergeConfig } = await import('vite');\n\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return mergeConfig(config, {\n      // Your environment configuration here\n    });\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config, { configType }) {\n    const { mergeConfig } = await import('vite');\n\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return mergeConfig(config, {\n      // Your environment configuration here\n    });\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config, { configType }) {\n    const { mergeConfig } = await import('vite');\n\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return mergeConfig(config, {\n      // Your environment configuration here\n    });\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config, { configType }) {\n    const { mergeConfig } = await import('vite');\n\n    if (configType === 'DEVELOPMENT') {\n      // Your development configuration goes here\n    }\n    if (configType === 'PRODUCTION') {\n      // Your production configuration goes here.\n    }\n    return mergeConfig(config, {\n      // Your environment configuration here\n    });\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/main-config-webpack-final.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-webpack5, nextjs, angular, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config, { configType }) => {\n    if (configType === 'DEVELOPMENT') {\n      // Modify config for development\n    }\n    if (configType === 'PRODUCTION') {\n      // Modify config for production\n    }\n    return config;\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-webpack5, nextjs, angular, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config, { configType }) => {\n    if (configType === 'DEVELOPMENT') {\n      // Modify config for development\n    }\n    if (configType === 'PRODUCTION') {\n      // Modify config for production\n    }\n    return config;\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config, { configType }) => {\n    if (configType === 'DEVELOPMENT') {\n      // Modify config for development\n    }\n    if (configType === 'PRODUCTION') {\n      // Modify config for production\n    }\n    return config;\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config, { configType }) => {\n    if (configType === 'DEVELOPMENT') {\n      // Modify config for development\n    }\n    if (configType === 'PRODUCTION') {\n      // Modify config for production\n    }\n    return config;\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config, { configType }) => {\n    if (configType === 'DEVELOPMENT') {\n      // Modify config for development\n    }\n    if (configType === 'PRODUCTION') {\n      // Modify config for production\n    }\n    return config;\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/margindecorator.md",
    "content": "```svelte filename=\"MarginDecorator.svelte\" renderer=\"svelte\" language=\"js\"\n<script>\n  let { children } = $props();\n</script>\n\n<div>\n  {@render children()}\n</div>\n\n<style>\n  div {\n    margin: 3em;\n  }\n</style>\n```\n\n```svelte filename=\"MarginDecorator.svelte\" renderer=\"svelte\" language=\"ts\"\n<script>\n  import type { Snippet } from 'svelte';\n\n  let { children }: { children: Snippet } = $props();\n</script>\n\n<div>\n  {@render children()}\n</div>\n\n<style>\n  div {\n    margin: 3em;\n  }\n</style>\n```\n"
  },
  {
    "path": "docs/_snippets/mcp-add.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx mcp-add --type http --url \"http://localhost:6006/mcp\" --scope project\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm exec mcp-add --type http --url \"http://localhost:6006/mcp\" --scope project\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn exec mcp-add --type http --url \"http://localhost:6006/mcp\" --scope project\n```\n"
  },
  {
    "path": "docs/_snippets/migrate-csf-2-to-3.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook migrate csf-2-to-3 --glob=\"**/*.stories.tsx\" --parser=tsx\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm exec storybook migrate csf-2-to-3 --glob=\"**/*.stories.tsx\" --parser=tsx\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn exec storybook migrate csf-2-to-3 --glob=\"**/*.stories.tsx\" --parser=tsx\n```\n"
  },
  {
    "path": "docs/_snippets/mock-context-container-global.md",
    "content": "```jsx filename=\".storybook/preview.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport * as React from 'react';\n\nimport { normal as NavigationNormal } from '../components/Navigation.stories';\nimport GlobalContainerContext from '../components/lib/GlobalContainerContext';\n\nconst context = {\n  NavigationContainer: NavigationNormal,\n};\n\nconst AppDecorator = (storyFn) => {\n  return (\n    <GlobalContainerContext.Provider value={context}>{storyFn()}</GlobalContainerContext.Provider>\n  );\n};\n\nexport default { decorators: [AppDecorator] };\n```\n\n```tsx filename=\".storybook/preview.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\nimport * as React from 'react';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { normal as NavigationNormal } from '../components/Navigation.stories';\nimport GlobalContainerContext from '../components/lib/GlobalContainerContext';\n\nconst context = {\n  NavigationContainer: NavigationNormal,\n};\n\nconst AppDecorator = (storyFn) => {\n  return (\n    <GlobalContainerContext.Provider value={context}>{storyFn()}</GlobalContainerContext.Provider>\n  );\n};\n\nconst preview: Preview = {\n  decorators: [AppDecorator],\n};\n\nexport default preview;\n```\n\n```jsx filename=\".storybook/preview.js\" renderer=\"solid\" language=\"js\"\nimport { normal as NavigationNormal } from '../components/Navigation.stories';\nimport GlobalContainerContext from '../components/lib/GlobalContainerContext';\n\nconst context = {\n  NavigationContainer: NavigationNormal,\n};\n\nconst AppDecorator = (storyFn) => {\n  return (\n    <GlobalContainerContext.Provider value={context}>{storyFn()}</GlobalContainerContext.Provider>\n  );\n};\nexport const decorators = [AppDecorator];\n```\n\n```tsx filename=\".storybook/preview.ts\" renderer=\"solid\" language=\"ts\"\nimport { normal as NavigationNormal } from '../components/Navigation.stories';\nimport GlobalContainerContext from '../components/lib/GlobalContainerContext';\n\nconst context = {\n  NavigationContainer: NavigationNormal,\n};\n\nconst AppDecorator = (storyFn) => {\n  return (\n    <GlobalContainerContext.Provider value={context}>{storyFn()}</GlobalContainerContext.Provider>\n  );\n};\n\nconst preview: Preview = {\n  decorators: [AppDecorator],\n};\n\nexport default preview;\n```\n\n```tsx filename=\".storybook/preview.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { normal as NavigationNormal } from '../components/Navigation.stories';\nimport GlobalContainerContext from '../components/lib/GlobalContainerContext';\n\nconst context = {\n  NavigationContainer: NavigationNormal,\n};\n\nconst AppDecorator = (storyFn) => {\n  return (\n    <GlobalContainerContext.Provider value={context}>{storyFn()}</GlobalContainerContext.Provider>\n  );\n};\n\nexport default definePreview({\n  decorators: [AppDecorator],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\".storybook/preview.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { normal as NavigationNormal } from '../components/Navigation.stories';\nimport GlobalContainerContext from '../components/lib/GlobalContainerContext';\n\nconst context = {\n  NavigationContainer: NavigationNormal,\n};\n\nconst AppDecorator = (storyFn) => {\n  return (\n    <GlobalContainerContext.Provider value={context}>{storyFn()}</GlobalContainerContext.Provider>\n  );\n};\n\nexport default definePreview({\n  decorators: [AppDecorator],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/mock-context-container-provider.md",
    "content": "```js filename=\"pages/profile.js|jsx\" renderer=\"react\" language=\"js\"\nimport React from 'react';\n\nimport ProfilePageContext from './ProfilePageContext';\nimport { ProfilePageContainer } from './ProfilePageContainer';\nimport { UserPostsContainer } from './UserPostsContainer';\nimport { UserFriendsContainer } from './UserFriendsContainer';\n\n//👇 Ensure that your context value remains referentially equal between each render.\nconst context = {\n  UserPostsContainer,\n  UserFriendsContainer,\n};\n\nexport const AppProfilePage = () => {\n  return (\n    <ProfilePageContext.Provider value={context}>\n      <ProfilePageContainer />\n    </ProfilePageContext.Provider>\n  );\n};\n```\n\n```js filename=\"pages/profile.js|jsx\" renderer=\"solid\" language=\"js\"\nimport ProfilePageContext from './ProfilePageContext';\nimport { ProfilePageContainer } from './ProfilePageContainer';\nimport { UserPostsContainer } from './UserPostsContainer';\nimport { UserFriendsContainer } from './UserFriendsContainer';\n\n//👇 Ensure that your context value remains referentially equal between each render.\nconst context = {\n  UserPostsContainer,\n  UserFriendsContainer,\n};\n\nexport const AppProfilePage = () => {\n  return (\n    <ProfilePageContext.Provider value={context}>\n      <ProfilePageContainer />\n    </ProfilePageContext.Provider>\n  );\n};\n```\n"
  },
  {
    "path": "docs/_snippets/mock-context-container.md",
    "content": "```js filename=\"ProfilePage.stories.js|jsx\" renderer=\"react\" language=\"js\"\nimport React from 'react';\n\nimport { ProfilePage } from './ProfilePage';\nimport { UserPosts } from './UserPosts';\n\n//👇 Imports a specific story from a story file\nimport { Normal as UserFriendsNormal } from './UserFriends.stories';\n\nexport default {\n  component: ProfilePage,\n};\n\nconst ProfilePageProps = {\n  name: 'Jimi Hendrix',\n  userId: '1',\n};\n\nconst context = {\n  //👇 We can access the `userId` prop here if required:\n  UserPostsContainer({ userId }) {\n    return <UserPosts {...UserPostsProps} />;\n  },\n  // Most of the time we can simply pass in a story.\n  // In this case we're passing in the `normal` story export\n  // from the `UserFriends` component stories.\n  UserFriendsContainer: UserFriendsNormal,\n};\n\nexport const Normal = {\n  render: () => (\n    <ProfilePageContext.Provider value={context}>\n      <ProfilePage {...ProfilePageProps} />\n    </ProfilePageContext.Provider>\n  ),\n};\n```\n\n```js filename=\"ProfilePage.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { ProfilePage } from './ProfilePage';\nimport { UserPosts } from './UserPosts';\n\n//👇 Imports a specific story from a story file\nimport { Normal as UserFriendsNormal } from './UserFriends.stories';\n\nexport default {\n  component: ProfilePage,\n};\n\nconst ProfilePageProps = {\n  name: 'Jimi Hendrix',\n  userId: '1',\n};\n\nconst context = {\n  //👇 We can access the `userId` prop here if required:\n  UserPostsContainer({ userId }) {\n    return <UserPosts {...UserPostsProps} />;\n  },\n  // Most of the time we can simply pass in a story.\n  // In this case we're passing in the `normal` story export\n  // from the `UserFriends` component stories.\n  UserFriendsContainer: UserFriendsNormal,\n};\n\nexport const Normal = {\n  render: () => (\n    <ProfilePageContext.Provider value={context}>\n      <ProfilePage {...ProfilePageProps} />\n    </ProfilePageContext.Provider>\n  ),\n};\n```\n"
  },
  {
    "path": "docs/_snippets/mock-context-create.md",
    "content": "```js filename=\"ProfilePageContext.js|jsx\" renderer=\"react\" language=\"js\"\nimport { createContext } from 'react';\n\nconst ProfilePageContext = createContext();\n\nexport default ProfilePageContext;\n```\n\n```js filename=\"ProfilePageContext.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { createContext } from 'solid-js';\n\nconst ProfilePageContext = createContext();\n\nexport default ProfilePageContext;\n```\n"
  },
  {
    "path": "docs/_snippets/mock-context-in-use.md",
    "content": "```js filename=\"ProfilePage.js|jsx\" renderer=\"react\" language=\"js\"\nimport { useContext } from 'react';\n\nimport ProfilePageContext from './ProfilePageContext';\n\nexport const ProfilePage = ({ name, userId }) => {\n  const { UserPostsContainer, UserFriendsContainer } = useContext(ProfilePageContext);\n\n  return (\n    <div>\n      <h1>{name}</h1>\n      <UserPostsContainer userId={userId} />\n      <UserFriendsContainer userId={userId} />\n    </div>\n  );\n};\n```\n\n```js filename=\"ProfilePage.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { useContext } from 'solid-js';\n\nimport ProfilePageContext from './ProfilePageContext';\n\nexport const ProfilePage = (props) => {\n  const { UserPostsContainer, UserFriendsContainer } = useContext(ProfilePageContext);\n\n  return (\n    <div>\n      <h1>{props.name}</h1>\n      <UserPostsContainer userId={props.userId} />\n      <UserFriendsContainer userId={props.userId} />\n    </div>\n  );\n};\n```\n"
  },
  {
    "path": "docs/_snippets/mock-provider-in-preview.md",
    "content": "```jsx filename=\".storybook/preview.jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport React from 'react';\n\nimport { ThemeProvider } from 'styled-components';\n\n// themes = { light, dark }\nimport * as themes from '../src/themes';\n\nexport default {\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    (Story, { parameters }) => {\n      // 👇 Make it configurable by reading the theme value from parameters\n      const { theme = 'light' } = parameters;\n      return (\n        <ThemeProvider theme={themes[theme]}>\n          <Story />\n        </ThemeProvider>\n      );\n    },\n  ],\n};\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\nimport React from 'react';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nimport { ThemeProvider } from 'styled-components';\n\n// themes = { light, dark }\nimport * as themes from '../src/themes';\n\nconst preview: Preview = {\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    (Story, { parameters }) => {\n      // 👇 Make it configurable by reading the theme value from parameters\n      const { theme = 'light' } = parameters;\n      return (\n        <ThemeProvider theme={themes[theme]}>\n          <Story />\n        </ThemeProvider>\n      );\n    },\n  ],\n};\n\nexport default preview;\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport React from 'react';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { ThemeProvider } from 'styled-components';\n\n// themes = { light, dark }\nimport * as themes from '../src/themes';\n\nexport default definePreview({\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    (Story, { parameters }) => {\n      // 👇 Make it configurable by reading the theme value from parameters\n      const { theme = 'light' } = parameters;\n      return (\n        <ThemeProvider theme={themes[theme]}>\n          <Story />\n        </ThemeProvider>\n      );\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\".storybook/preview.jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport React from 'react';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { ThemeProvider } from 'styled-components';\n\n// themes = { light, dark }\nimport * as themes from '../src/themes';\n\nexport default definePreview({\n  decorators: [\n    // 👇 Defining the decorator in the preview file applies it to all stories\n    (Story, { parameters }) => {\n      // 👇 Make it configurable by reading the theme value from parameters\n      const { theme = 'light' } = parameters;\n      return (\n        <ThemeProvider theme={themes[theme]}>\n          <Story />\n        </ThemeProvider>\n      );\n    },\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/module-aliases-config.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"Vite (CSF 3)\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs-vite, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  viteFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.alias = {\n        ...config.resolve?.alias,\n        // 👇 External module\n        lodash: import.meta.resolve('./lodash.mock'),\n        // 👇 Internal modules\n        '@/api': import.meta.resolve('./api.mock.ts'),\n        '@/app/actions': import.meta.resolve('./app/actions.mock.ts'),\n        '@/lib/session': import.meta.resolve('./lib/session.mock.ts'),\n        '@/lib/db': import.meta.resolve('./lib/db.mock.ts'),\n      };\n    }\n\n    return config;\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"Vite (CSF 3)\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs-vite, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  viteFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.alias = {\n        ...config.resolve?.alias,\n        // 👇 External module\n        lodash: import.meta.resolve('./lodash.mock'),\n        // 👇 Internal modules\n        '@/api': import.meta.resolve('./api.mock.ts'),\n        '@/app/actions': import.meta.resolve('./app/actions.mock.ts'),\n        '@/lib/session': import.meta.resolve('./lib/session.mock.ts'),\n        '@/lib/db': import.meta.resolve('./lib/db.mock.ts'),\n      };\n    }\n\n    return config;\n  },\n};\n\nexport default config;\n```\n\n```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"Webpack (CSF 3)\"\nexport default {\n  // Replace your-framework with the framework you are using (e.g., nextjs, react-webpack5)\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.alias = {\n        ...config.resolve.alias,\n        // 👇 External module\n        lodash: import.meta.resolve('./lodash.mock'),\n        // 👇 Internal modules\n        '@/api$': import.meta.resolve('./api.mock.ts'),\n        '@/app/actions$': import.meta.resolve('./app/actions.mock.ts'),\n        '@/lib/session$': import.meta.resolve('./lib/session.mock.ts'),\n        '@/lib/db$': import.meta.resolve('./lib/db.mock.ts'),\n      };\n    }\n\n    return config;\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"Webpack (CSF 3)\"\n// Replace your-framework with the framework you are using (e.g., nextjs, react-webpack5)\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.alias = {\n        ...config.resolve.alias,\n        // 👇 External module\n        lodash: import.meta.resolve('./lodash.mock'),\n        // 👇 Internal modules\n        '@/api$': import.meta.resolve('./api.mock.ts'),\n        '@/app/actions$': import.meta.resolve('./app/actions.mock.ts'),\n        '@/lib/session$': import.meta.resolve('./lib/session.mock.ts'),\n        '@/lib/db$': import.meta.resolve('./lib/db.mock.ts'),\n      };\n    }\n\n    return config;\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"Vite (CSF Next 🧪)\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  viteFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.alias = {\n        ...config.resolve?.alias,\n        // 👇 External module\n        lodash: import.meta.resolve('./lodash.mock'),\n        // 👇 Internal modules\n        '@/api': import.meta.resolve('./api.mock.ts'),\n        '@/app/actions': import.meta.resolve('./app/actions.mock.ts'),\n        '@/lib/session': import.meta.resolve('./lib/session.mock.ts'),\n        '@/lib/db': import.meta.resolve('./lib/db.mock.ts'),\n      };\n    }\n\n    return config;\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"Vite (CSF Next 🧪)\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  viteFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.alias = {\n        ...config.resolve?.alias,\n        // 👇 External module\n        lodash: import.meta.resolve('./lodash.mock'),\n        // 👇 Internal modules\n        '@/api': import.meta.resolve('./api.mock.ts'),\n        '@/app/actions': import.meta.resolve('./app/actions.mock.ts'),\n        '@/lib/session': import.meta.resolve('./lib/session.mock.ts'),\n        '@/lib/db': import.meta.resolve('./lib/db.mock.ts'),\n      };\n    }\n\n    return config;\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"Webpack (CSF Next 🧪)\"\n// Replace your-framework with the framework you are using (e.g., nextjs, react-webpack5)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.alias = {\n        ...config.resolve.alias,\n        // 👇 External module\n        lodash: import.meta.resolve('./lodash.mock'),\n        // 👇 Internal modules\n        '@/api$': import.meta.resolve('./api.mock.ts'),\n        '@/app/actions$': import.meta.resolve('./app/actions.mock.ts'),\n        '@/lib/session$': import.meta.resolve('./lib/session.mock.ts'),\n        '@/lib/db$': import.meta.resolve('./lib/db.mock.ts'),\n      };\n    }\n\n    return config;\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"Webpack (CSF Next 🧪)\"\n// Replace your-framework with the framework you are using (e.g., nextjs, react-webpack5)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.alias = {\n        ...config.resolve.alias,\n        // 👇 External module\n        lodash: import.meta.resolve('./lodash.mock'),\n        // 👇 Internal modules\n        '@/api$': import.meta.resolve('./api.mock.ts'),\n        '@/app/actions$': import.meta.resolve('./app/actions.mock.ts'),\n        '@/lib/session$': import.meta.resolve('./lib/session.mock.ts'),\n        '@/lib/db$': import.meta.resolve('./lib/db.mock.ts'),\n      };\n    }\n\n    return config;\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"Vite (CSF Next 🧪)\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  viteFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.alias = {\n        ...config.resolve?.alias,\n        // 👇 External module\n        lodash: import.meta.resolve('./lodash.mock'),\n        // 👇 Internal modules\n        '@/api': import.meta.resolve('./api.mock.ts'),\n        '@/app/actions': import.meta.resolve('./app/actions.mock.ts'),\n        '@/lib/session': import.meta.resolve('./lib/session.mock.ts'),\n        '@/lib/db': import.meta.resolve('./lib/db.mock.ts'),\n      };\n    }\n\n    return config;\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"Vite (CSF Next 🧪)\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  viteFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.alias = {\n        ...config.resolve?.alias,\n        // 👇 External module\n        lodash: import.meta.resolve('./lodash.mock'),\n        // 👇 Internal modules\n        '@/api': import.meta.resolve('./api.mock.ts'),\n        '@/app/actions': import.meta.resolve('./app/actions.mock.ts'),\n        '@/lib/session': import.meta.resolve('./lib/session.mock.ts'),\n        '@/lib/db': import.meta.resolve('./lib/db.mock.ts'),\n      };\n    }\n\n    return config;\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"Webpack (CSF Next 🧪)\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.alias = {\n        ...config.resolve.alias,\n        // 👇 External module\n        lodash: import.meta.resolve('./lodash.mock'),\n        // 👇 Internal modules\n        '@/api$': import.meta.resolve('./api.mock.ts'),\n        '@/app/actions$': import.meta.resolve('./app/actions.mock.ts'),\n        '@/lib/session$': import.meta.resolve('./lib/session.mock.ts'),\n        '@/lib/db$': import.meta.resolve('./lib/db.mock.ts'),\n      };\n    }\n\n    return config;\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"angular\" language=\"js\" tabTitle=\"Webpack (CSF Next 🧪)\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.alias = {\n        ...config.resolve.alias,\n        // 👇 External module\n        lodash: import.meta.resolve('./lodash.mock'),\n        // 👇 Internal modules\n        '@/api$': import.meta.resolve('./api.mock.ts'),\n        '@/app/actions$': import.meta.resolve('./app/actions.mock.ts'),\n        '@/lib/session$': import.meta.resolve('./lib/session.mock.ts'),\n        '@/lib/db$': import.meta.resolve('./lib/db.mock.ts'),\n      };\n    }\n\n    return config;\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"Vite (CSF Next 🧪)\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  viteFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.alias = {\n        ...config.resolve?.alias,\n        // 👇 External module\n        lodash: import.meta.resolve('./lodash.mock'),\n        // 👇 Internal modules\n        '@/api': import.meta.resolve('./api.mock.ts'),\n        '@/app/actions': import.meta.resolve('./app/actions.mock.ts'),\n        '@/lib/session': import.meta.resolve('./lib/session.mock.ts'),\n        '@/lib/db': import.meta.resolve('./lib/db.mock.ts'),\n      };\n    }\n\n    return config;\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"Vite (CSF Next 🧪)\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  viteFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.alias = {\n        ...config.resolve?.alias,\n        // 👇 External module\n        lodash: import.meta.resolve('./lodash.mock'),\n        // 👇 Internal modules\n        '@/api': import.meta.resolve('./api.mock.ts'),\n        '@/app/actions': import.meta.resolve('./app/actions.mock.ts'),\n        '@/lib/session': import.meta.resolve('./lib/session.mock.ts'),\n        '@/lib/db': import.meta.resolve('./lib/db.mock.ts'),\n      };\n    }\n\n    return config;\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/mount-advanced.md",
    "content": "```tsx filename=\"Page.stories.tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g., react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\n// 👇 Automocked module resolves to '../lib/__mocks__/db'\nimport db from '../lib/db';\nimport { Page } from './Page';\n\nconst meta = { component: Page } satisfies Meta<typeof Page>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  play: async ({ mount, args, userEvent }) => {\n    const note = await db.note.create({\n      data: { title: 'Mount inside of play' },\n    });\n\n    const canvas = await mount(\n      // 👇 Pass data that is created inside of the play function to the component\n      //   For example, a just-generated UUID\n      <Page {...args} params={{ id: String(note.id) }} />,\n    );\n\n    await userEvent.click(await canvas.findByRole('menuitem', { name: /login to add/i }));\n  },\n  argTypes: {\n    // 👇 Make the params prop un-controllable, as the value is always overridden in the play function.\n    params: { control: { disable: true } },\n  },\n};\n```\n\n```jsx filename=\"Page.stories.jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\n// 👇 Automocked module resolves to '../lib/__mocks__/db'\nimport db from '../lib/db';\nimport { Page } from './Page';\n\nexport default { component: Page };\n\nexport const Basic = {\n  play: async ({ mount, args, userEvent }) => {\n    const note = await db.note.create({\n      data: { title: 'Mount inside of play' },\n    });\n\n    const canvas = await mount(\n      // 👇 Pass data that is created inside of the play function to the component\n      //   For example, a just-generated UUID\n      <Page {...args} params={{ id: String(note.id) }} />,\n    );\n\n    await userEvent.click(await canvas.findByRole('menuitem', { name: /login to add/i }));\n  },\n  argTypes: {\n    // 👇 Make the params prop un-controllable, as the value is always overridden in the play function.\n    params: { control: { disable: true } },\n  },\n};\n```\n\n```tsx filename=\"Page.stories.tsx\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\n// 👇 Automocked module resolves to '../lib/__mocks__/db'\nimport db from '../lib/db';\nimport { Page } from './page.component';\n\nconst meta = { component: Page } satisfies Meta<typeof Page>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  play: async ({ mount, args, userEvent }) => {\n    const note = await db.note.create({\n      data: { title: 'Mount inside of play' },\n    });\n\n    const canvas = await mount(\n      Page,\n      // 👇 Pass data that is created inside of the play function to the component\n      //   For example, a just-generated UUID\n      { props: { ...args, params: { id: String(note.id) } } },\n    );\n\n    await userEvent.click(await canvas.findByRole('menuitem', { name: /login to add/i }));\n  },\n  argTypes: {\n    // 👇 Make the params prop un-controllable, as the value is always overridden in the play function.\n    params: { control: { disable: true } },\n  },\n};\n```\n\n```tsx filename=\"Page.stories.tsx\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n// 👇 Automocked module resolves to '../lib/__mocks__/db'\nimport db from '../lib/db';\nimport { Page } from './page.component';\n\nconst meta = preview.meta({ component: Page });\n\nexport const Basic = meta.story({\n  play: async ({ mount, args, userEvent }) => {\n    const note = await db.note.create({\n      data: { title: 'Mount inside of play' },\n    });\n\n    const canvas = await mount(\n      Page,\n      // 👇 Pass data that is created inside of the play function to the component\n      //   For example, a just-generated UUID\n      { props: { ...args, params: { id: String(note.id) } } },\n    );\n\n    await userEvent.click(await canvas.findByRole('menuitem', { name: /login to add/i }));\n  },\n  argTypes: {\n    // 👇 Make the params prop un-controllable, as the value is always overridden in the play function.\n    params: { control: { disable: true } },\n  },\n});\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"svelte\" language=\"ts\"\n// Replace your-framework with the framework you are using, e.g., svelte-vite, sveltekit, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\n// 👇 Automocked module resolves to '../lib/__mocks__/db'\nimport db from '../lib/db';\nimport Page from './Page.svelte';\n\nconst meta = { component: Page } satisfies Meta<typeof Page>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  play: async ({ mount, args, userEvent }) => {\n    const note = await db.note.create({\n      data: { title: 'Mount inside of play' },\n    });\n\n    const canvas = await mount(\n      Page,\n      // 👇 Pass data that is created inside of the play function to the component\n      //   For example, a just-generated UUID\n      { props: { ...args, params: { id: String(note.id) } } },\n    );\n\n    await userEvent.click(await canvas.findByRole('menuitem', { name: /login to add/i }));\n  },\n  argTypes: {\n    // 👇 Make the params prop un-controllable, as the value is always overridden in the play function.\n    params: { control: { disable: true } },\n  },\n};\n```\n\n```js filename=\"Page.stories.js\" renderer=\"svelte\" language=\"js\"\n// 👇 Automocked module resolves to '../lib/__mocks__/db'\nimport db from '../lib/db';\nimport Page from './Page.svelte';\n\nexport default { component: Page };\n\nexport const Basic = {\n  play: async ({ mount, args, userEvent }) => {\n    const note = await db.note.create({\n      data: { title: 'Mount inside of play' },\n    });\n\n    const canvas = await mount(\n      Page,\n      // 👇 Pass data that is created inside of the play function to the component\n      //   For example, a just-generated UUID\n      { props: { ...args, params: { id: String(note.id) } } },\n    );\n\n    await userEvent.click(await canvas.findByRole('menuitem', { name: /login to add/i }));\n  },\n  argTypes: {\n    // 👇 Make the params prop un-controllable, as the value is always overridden in the play function.\n    params: { control: { disable: true } },\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\n// 👇 Automocked module resolves to '../lib/__mocks__/db'\nimport db from '../lib/db';\nimport Page from './Page.vue';\n\nconst meta = { component: Page } satisfies Meta<typeof Page>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  play: async ({ mount, args, userEvent }) => {\n    const note = await db.note.create({\n      data: { title: 'Mount inside of play' },\n    });\n\n    const canvas = await mount(\n      Page,\n      // 👇 Pass data that is created inside of the play function to the component\n      //   For example, a just-generated UUID\n      { props: { ...args, params: { id: String(note.id) } } },\n    );\n\n    await userEvent.click(await canvas.findByRole('menuitem', { name: /login to add/i }));\n  },\n  argTypes: {\n    // 👇 Make the params prop un-controllable, as the value is always overridden in the play function.\n    params: { control: { disable: true } },\n  },\n};\n```\n\n```js filename=\"Page.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\n// 👇 Automocked module resolves to '../lib/__mocks__/db'\nimport db from '../lib/db';\nimport Page from './Page.vue';\n\nexport default { component: Page };\n\nexport const Basic = {\n  play: async ({ mount, args, userEvent }) => {\n    const note = await db.note.create({\n      data: { title: 'Mount inside of play' },\n    });\n\n    const canvas = await mount(\n      Page,\n      // 👇 Pass data that is created inside of the play function to the component\n      //   For example, a just-generated UUID\n      { props: { ...args, params: { id: String(note.id) } } },\n    );\n\n    await userEvent.click(await canvas.findByRole('menuitem', { name: /login to add/i }));\n  },\n  argTypes: {\n    // 👇 Make the params prop un-controllable, as the value is always overridden in the play function.\n    params: { control: { disable: true } },\n  },\n};\n```\n\n```tsx filename=\"Page.stories.tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n// 👇 Automocked module resolves to '../lib/__mocks__/db'\nimport db from '../lib/db';\nimport { Page } from './Page';\n\nconst meta = preview.meta({ component: Page });\n\nexport const Basic = meta.story({\n  play: async ({ mount, args, userEvent }) => {\n    const note = await db.note.create({\n      data: { title: 'Mount inside of play' },\n    });\n\n    const canvas = await mount(\n      // 👇 Pass data that is created inside of the play function to the component\n      //   For example, a just-generated UUID\n      <Page {...args} params={{ id: String(note.id) }} />,\n    );\n\n    await userEvent.click(await canvas.findByRole('menuitem', { name: /login to add/i }));\n  },\n  argTypes: {\n    // 👇 Make the params prop un-controllable, as the value is always overridden in the play function.\n    params: { control: { disable: true } },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"Page.stories.jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n// 👇 Automocked module resolves to '../lib/__mocks__/db'\nimport db from '../lib/db';\nimport { Page } from './Page';\n\nconst meta = preview.meta({\n  component: Page,\n});\n\nexport const Basic = meta.story({\n  play: async ({ mount, args, userEvent }) => {\n    const note = await db.note.create({\n      data: { title: 'Mount inside of play' },\n    });\n\n    const canvas = await mount(\n      // 👇 Pass data that is created inside of the play function to the component\n      //   For example, a just-generated UUID\n      <Page {...args} params={{ id: String(note.id) }} />,\n    );\n\n    await userEvent.click(await canvas.findByRole('menuitem', { name: /login to add/i }));\n  },\n  argTypes: {\n    // 👇 Make the params prop un-controllable, as the value is always overridden in the play function.\n    params: { control: { disable: true } },\n  },\n});\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n// 👇 Automocked module resolves to '../lib/__mocks__/db'\nimport db from '../lib/db';\nimport Page from './Page.vue';\n\nconst meta = preview.meta({ component: Page });\n\nexport const Basic = meta.story({\n  play: async ({ mount, args, userEvent }) => {\n    const note = await db.note.create({\n      data: { title: 'Mount inside of play' },\n    });\n\n    const canvas = await mount(\n      Page,\n      // 👇 Pass data that is created inside of the play function to the component\n      //   For example, a just-generated UUID\n      { props: { ...args, params: { id: String(note.id) } } },\n    );\n\n    await userEvent.click(await canvas.findByRole('menuitem', { name: /login to add/i }));\n  },\n  argTypes: {\n    // 👇 Make the params prop un-controllable, as the value is always overridden in the play function.\n    params: { control: { disable: true } },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Page.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n// 👇 Automocked module resolves to '../lib/__mocks__/db'\nimport db from '../lib/db';\nimport Page from './Page.vue';\n\nconst meta = preview.meta({ component: Page });\n\nexport const Basic = meta.story({\n  play: async ({ mount, args, userEvent }) => {\n    const note = await db.note.create({\n      data: { title: 'Mount inside of play' },\n    });\n\n    const canvas = await mount(\n      Page,\n      // 👇 Pass data that is created inside of the play function to the component\n      //   For example, a just-generated UUID\n      { props: { ...args, params: { id: String(note.id) } } },\n    );\n\n    await userEvent.click(await canvas.findByRole('menuitem', { name: /login to add/i }));\n  },\n  argTypes: {\n    // 👇 Make the params prop un-controllable, as the value is always overridden in the play function.\n    params: { control: { disable: true } },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/mount-basic.md",
    "content": "```js filename=\"Page.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport MockDate from 'mockdate';\n\n// ...rest of story file\n\nexport const ChristmasUI = {\n  async play({ mount }) {\n    MockDate.set('2024-12-25');\n    // 👇 Render the component with the mocked date\n    await mount();\n    // ...rest of test\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\nimport MockDate from 'mockdate';\n\n// ...rest of story file\n\nexport const ChristmasUI: Story = {\n  async play({ mount }) {\n    MockDate.set('2024-12-25');\n    // 👇 Render the component with the mocked date\n    await mount();\n    // ...rest of test\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport MockDate from 'mockdate';\n\nimport preview from '../.storybook/preview';\n\nimport Page from './page.component';\n\nconst meta = preview.meta({\n  component: Page,\n});\n\nexport const ChristmasUI = meta.story({\n  async play({ mount }) {\n    MockDate.set('2024-12-25');\n    // 👇 Render the component with the mocked date\n    await mount();\n    // ...rest of test\n  },\n});\n```\n\n```svelte filename=\"Page.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Page from './Page.svelte';\n\n  const { Story } = defineMeta({\n    component: Page,\n  });\n</script>\n\n<Story\n  name=\"ChristmasUI\"\n  play={async ({ mount }) {\n    MockDate.set('2024-12-25');\n    // 👇 Render the component with the mocked date\n    await mount();\n    // ...rest of test\n  }}\n/>\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\nimport MockDate from 'mockdate';\n\n// ...rest of story file\n\nexport const ChristmasUI: Story = {\n  async play({ mount }) {\n    MockDate.set('2024-12-25');\n    // 👇 Render the component with the mocked date\n    await mount();\n    // ...rest of test\n  },\n};\n```\n\n```svelte filename=\"Page.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Page from './Page.svelte';\n\n  const { Story } = defineMeta({\n    component: Page,\n  });\n</script>\n\n<Story\n  name=\"ChristmasUI\"\n  play={async ({ mount }) {\n    MockDate.set('2024-12-25');\n    // 👇 Render the component with the mocked date\n    await mount();\n    // ...rest of test\n  }}\n/>\n```\n\n```js filename=\"Page.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport MockDate from 'mockdate';\n\n// ...rest of story file\n\nexport const ChristmasUI = {\n  async play({ mount }) {\n    MockDate.set('2024-12-25');\n    // 👇 Render the component with the mocked date\n    await mount();\n    // ...rest of test\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport MockDate from 'mockdate';\n\nimport preview from '../.storybook/preview';\n\nimport Page from './Page';\n\nconst meta = preview.meta({\n  component: Page,\n});\n\nexport const ChristmasUI = meta.story({\n  async play({ mount }) {\n    MockDate.set('2024-12-25');\n    // 👇 Render the component with the mocked date\n    await mount();\n    // ...rest of test\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Page.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport MockDate from 'mockdate';\n\nimport preview from '../.storybook/preview';\n\nimport Page from './Page';\n\nconst meta = preview.meta({\n  component: Page,\n});\n\nexport const ChristmasUI = meta.story({\n  async play({ mount }) {\n    MockDate.set('2024-12-25');\n    // 👇 Render the component with the mocked date\n    await mount();\n    // ...rest of test\n  },\n});\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport MockDate from 'mockdate';\n\nimport preview from '../.storybook/preview';\n\nimport Page from './Page.vue';\n\nconst meta = preview.meta({\n  component: Page,\n});\n\nexport const ChristmasUI = meta.story({\n  async play({ mount }) {\n    MockDate.set('2024-12-25');\n    // 👇 Render the component with the mocked date\n    await mount();\n    // ...rest of test\n  },\n});\n```\n\n```js filename=\"Page.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport MockDate from 'mockdate';\n\nimport preview from '../.storybook/preview';\n\nimport Page from './Page.vue';\n\nconst meta = preview.meta({\n  component: Page,\n});\n\nexport const ChristmasUI = meta.story({\n  async play({ mount }) {\n    MockDate.set('2024-12-25');\n    // 👇 Render the component with the mocked date\n    await mount();\n    // ...rest of test\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/msw-addon-configure-handlers-graphql.md",
    "content": "```ts filename=\"YourPage.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"story CSF 3\"\nimport { type Meta, type StoryObj, moduleMetadata } from '@storybook/angular';\n\nimport { CommonModule } from '@angular/common';\nimport { HttpClientModule } from '@angular/common/http';\nimport { graphql, HttpResponse, delay } from 'msw';\n\nimport { DocumentHeader } from './document-header.component';\nimport { DocumentList } from './document-list.component';\nimport { PageLayout } from './page-layout.component';\nimport { DocumentScreen } from './your-page.component';\nimport { MockGraphQLModule } from './mock-graphql.module';\n\nconst meta: Meta<DocumentScreen> = {\n  component: DocumentScreen,\n  decorators: [\n    moduleMetadata({\n      declarations: [DocumentList, DocumentHeader, PageLayout],\n      imports: [CommonModule, HttpClientModule, MockGraphQLModule],\n    }),\n  ],\n};\n\nexport default meta;\n\n//👇The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\ntype Story = StoryObj<DocumentScreen>;\n\nexport const MockedSuccess: Story = {\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', () => {\n          return HttpResponse.json({\n            data: {\n              allInfo: {\n                ...TestData,\n              },\n            },\n          });\n        }),\n      ],\n    },\n  },\n};\n\nexport const MockedError: Story = {\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', async () => {\n          await delay(800);\n          return HttpResponse.json({\n            errors: [\n              {\n                message: 'Access denied',\n              },\n            ],\n          });\n        }),\n      ],\n    },\n  },\n};\n```\n\n```ts filename=\"YourPage.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"story CSF Next 🧪\"\nimport { moduleMetadata } from '@storybook/angular';\n\nimport { CommonModule } from '@angular/common';\nimport { HttpClientModule } from '@angular/common/http';\nimport { graphql, HttpResponse, delay } from 'msw';\n\nimport preview from '../.storybook/preview';\n\nimport { DocumentHeader } from './document-header.component';\nimport { DocumentList } from './document-list.component';\nimport { PageLayout } from './page-layout.component';\nimport { DocumentScreen } from './your-page.component';\nimport { MockGraphQLModule } from './mock-graphql.module';\n\nconst meta = preview.meta({\n  component: DocumentScreen,\n  decorators: [\n    moduleMetadata({\n      declarations: [DocumentList, DocumentHeader, PageLayout],\n      imports: [CommonModule, HttpClientModule, MockGraphQLModule],\n    }),\n  ],\n});\n\n//👇The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nexport const MockedSuccess = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', () => {\n          return HttpResponse.json({\n            data: {\n              allInfo: {\n                ...TestData,\n              },\n            },\n          });\n        }),\n      ],\n    },\n  },\n});\n\nexport const MockedError = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', async () => {\n          await delay(800);\n          return HttpResponse.json({\n            errors: [\n              {\n                message: 'Access denied',\n              },\n            ],\n          });\n        }),\n      ],\n    },\n  },\n});\n```\n\n```ts filename=\"mock-graphql.module.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"mock-apollo-module\"\nimport { NgModule } from '@angular/core';\nimport { APOLLO_OPTIONS } from 'apollo-angular';\n\nimport { ApolloClientOptions, InMemoryCache } from '@apollo/client/core';\nimport { HttpLink } from 'apollo-angular/http';\n\n// See here for docs https://apollo-angular.com/docs/get-started\n\nconst uri = 'https://your-graphql-endpoint';\nexport function createApollo(httpLink: HttpLink): ApolloClientOptions<any> {\n  return {\n    link: httpLink.create({ uri }),\n    cache: new InMemoryCache(),\n    defaultOptions: {\n      watchQuery: {\n        fetchPolicy: 'no-cache',\n        errorPolicy: 'all',\n      },\n      query: {\n        fetchPolicy: 'no-cache',\n        errorPolicy: 'all',\n      },\n    },\n  };\n}\n\n@NgModule({\n  providers: [\n    {\n      provide: APOLLO_OPTIONS,\n      useFactory: createApollo,\n      deps: [HttpLink],\n    },\n  ],\n})\nexport class MockGraphQLModule {}\n```\n\n```jsx filename=\"YourPage.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport * as React from 'react';\nimport { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client';\nimport { graphql, HttpResponse, delay } from 'msw';\n\nimport { DocumentScreen } from './YourPage';\n\nconst mockedClient = new ApolloClient({\n  uri: 'https://your-graphql-endpoint',\n  cache: new InMemoryCache(),\n  defaultOptions: {\n    watchQuery: {\n      fetchPolicy: 'no-cache',\n      errorPolicy: 'all',\n    },\n    query: {\n      fetchPolicy: 'no-cache',\n      errorPolicy: 'all',\n    },\n  },\n});\n\n//👇The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nexport default {\n  component: DocumentScreen,\n  decorators: [\n    (Story) => (\n      <ApolloProvider client={mockedClient}>\n        <Story />\n      </ApolloProvider>\n    ),\n  ],\n};\n\nexport const MockedSuccess = {\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', () => {\n          return HttpResponse.json({\n            data: {\n              allInfo: {\n                ...TestData,\n              },\n            },\n          });\n        }),\n      ],\n    },\n  },\n};\n\nexport const MockedError = {\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', async () => {\n          await delay(800);\n          return HttpResponse.json({\n            errors: [\n              {\n                message: 'Access denied',\n              },\n            ],\n          });\n        }),\n      ],\n    },\n  },\n};\n```\n\n```tsx filename=\"YourPage.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\nimport * as React from 'react';\nimport { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client';\nimport { graphql, HttpResponse, delay } from 'msw';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { DocumentScreen } from './YourPage';\n\nconst mockedClient = new ApolloClient({\n  uri: 'https://your-graphql-endpoint',\n  cache: new InMemoryCache(),\n  defaultOptions: {\n    watchQuery: {\n      fetchPolicy: 'no-cache',\n      errorPolicy: 'all',\n    },\n    query: {\n      fetchPolicy: 'no-cache',\n      errorPolicy: 'all',\n    },\n  },\n});\n\n//👇The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\nconst meta = {\n  component: DocumentScreen,\n  decorators: [\n    (Story) => (\n      <ApolloProvider client={mockedClient}>\n        <Story />\n      </ApolloProvider>\n    ),\n  ],\n} satisfies Meta<typeof DocumentScreen>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const MockedSuccess: Story = {\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', () => {\n          return HttpResponse.json({\n            data: {\n              allInfo: {\n                ...TestData,\n              },\n            },\n          });\n        }),\n      ],\n    },\n  },\n};\n\nexport const MockedError: Story = {\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', async () => {\n          await delay(800);\n          return HttpResponse.json({\n            errors: [\n              {\n                message: 'Access denied',\n              },\n            ],\n          });\n        }),\n      ],\n    },\n  },\n};\n```\n\n```svelte filename=\"YourPage.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { graphql, HttpResponse, delay } from 'msw';\n\n  import MockApolloWrapperClient from './MockApolloWrapperClient.svelte';\n  import DocumentScreen from './YourPage.svelte';\n\n  const { Story } = defineMeta({\n    component: DocumentScreen,\n    decorators: [() => MockApolloWrapperClient],\n  });\n\n  //👇The mocked data that will be used in the story\n  const TestData = {\n    user: {\n      userID: 1,\n      name: 'Someone',\n    },\n    document: {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n      status: 'approved',\n    },\n    subdocuments: [\n      {\n        id: 1,\n        userID: 1,\n        title: 'Something',\n        content:\n          'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n        status: 'approved',\n      },\n    ],\n  };\n</script>\n\n<Story\n  name=\"MockedSuccess\"\n  parameters={{\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', () => {\n          return HttpResponse.json({\n            data: {\n              AllInfoQuery: {\n                ...TestData,\n              },\n            },\n          });\n        }),\n      ],\n    },\n  }}\n/>\n\n<Story\n  name=\"MockedError\"\n  parameters={{\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', async () => {\n          await delay(800);\n          return HttpResponse.json({\n            errors: [\n              {\n                message: 'Access denied',\n              },\n            ],\n          });\n        }),\n      ],\n    },\n  }}\n/>\n```\n\n```js filename=\"YourPage.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport { graphql, HttpResponse, delay } from 'msw';\n\nimport MockApolloWrapperClient from './MockApolloWrapperClient.svelte';\nimport DocumentScreen from './YourPage.svelte';\n\nexport default {\n  component: DocumentScreen,\n  decorators: [() => MockApolloWrapperClient],\n};\n\n//👇The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nexport const MockedSuccess = {\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', () => {\n          return HttpResponse.json({\n            data: {\n              allInfo: {\n                ...TestData,\n              },\n            },\n          });\n        }),\n      ],\n    },\n  },\n};\n\nexport const MockedError = {\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', async () => {\n          await delay(800);\n          return HttpResponse.json({\n            errors: [\n              {\n                message: 'Access denied',\n              },\n            ],\n          });\n        }),\n      ],\n    },\n  },\n};\n```\n\n```svelte filename=\"MockApolloWrapperClient.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"apollo-wrapper-component\"\n<script>\n  import {\n    Client,\n    setContextClient,\n    cacheExchange,\n    fetchExchange,\n  } from '@urql/svelte';\n\n  const client = new Client({\n    url: 'https://your-graphql-endpoint',\n    exchanges: [cacheExchange, fetchExchange],\n  });\n\n  setContextClient(client);\n\n  const { children } = $props();\n</script>\n\n<div>\n  {@render children()}\n</div>\n```\n\n```svelte filename=\"YourPage.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { graphql, HttpResponse, delay } from 'msw';\n\n  import MockApolloWrapperClient from './MockApolloWrapperClient.svelte';\n  import DocumentScreen from './YourPage.svelte';\n\n  const { Story } = defineMeta({\n    component: DocumentScreen,\n    decorators: [() => MockApolloWrapperClient],\n  });\n\n  //👇The mocked data that will be used in the story\n  const TestData = {\n    user: {\n      userID: 1,\n      name: 'Someone',\n    },\n    document: {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n      status: 'approved',\n    },\n    subdocuments: [\n      {\n        id: 1,\n        userID: 1,\n        title: 'Something',\n        content:\n          'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n        status: 'approved',\n      },\n    ],\n  };\n</script>\n\n<Story\n  name=\"MockedSuccess\"\n  parameters={{\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', () => {\n          return HttpResponse.json({\n            data: {\n              AllInfoQuery: {\n                ...TestData,\n              },\n            },\n          });\n        }),\n      ],\n    },\n  }}\n/>\n\n<Story\n  name=\"MockedError\"\n  parameters={{\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', async () => {\n          await delay(800);\n          return HttpResponse.json({\n            errors: [\n              {\n                message: 'Access denied',\n              },\n            ],\n          });\n        }),\n      ],\n    },\n  }}\n/>\n```\n\n```ts filename=\"YourPage.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { graphql, HttpResponse, delay } from 'msw';\n\nimport MockApolloWrapperClient from './MockApolloWrapperClient.svelte';\nimport DocumentScreen from './YourPage.svelte';\n\nconst meta = {\n  component: DocumentScreen,\n  decorators: [() => MockApolloWrapperClient],\n} satisfies Meta<typeof DocumentScreen>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n//👇The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nexport const MockedSuccess: Story = {\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', () => {\n          return HttpResponse.json({\n            data: {\n              allInfo: {\n                ...TestData,\n              },\n            },\n          });\n        }),\n      ],\n    },\n  },\n};\n\nexport const MockedError: Story = {\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', async () => {\n          await delay(800);\n          return HttpResponse.json({\n            errors: [\n              {\n                message: 'Access denied',\n              },\n            ],\n          });\n        }),\n      ],\n    },\n  },\n};\n```\n\n```svelte filename=\"MockApolloWrapperClient.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"apollo-wrapper-component\"\n<script lang=\"ts\">\n  import {\n    Client,\n    setContextClient,\n    cacheExchange,\n    fetchExchange,\n  } from '@urql/svelte';\n\n  const client = new Client({\n    url: 'https://your-graphql-endpoint',\n    exchanges: [cacheExchange, fetchExchange],\n  });\n\n  setContextClient(client);\n\n  interface Props {\n    children: any;\n  }\n  const { children }: Props = $props();\n</script>\n\n<div>\n  {@render children?.()}\n</div>\n\n```\n\n```js filename=\"YourPage.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"story\"\nimport { graphql, HttpResponse, delay } from 'msw';\n\nimport WrapperComponent from './ApolloWrapperClient.vue';\nimport DocumentScreen from './YourPage.vue';\n\nexport default {\n  component: DocumentScreen,\n  render: () => ({\n    components: { DocumentScreen, WrapperComponent },\n    template: '<WrapperComponent><DocumentScreen /></WrapperComponent>',\n  }),\n};\n\n//👇The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nexport const MockedSuccess = {\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', () => {\n          return HttpResponse.json({\n            data: {\n              allInfo: {\n                ...TestData,\n              },\n            },\n          });\n        }),\n      ],\n    },\n  },\n};\n\nexport const MockedError = {\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', async () => {\n          await delay(800);\n          return HttpResponse.json({\n            errors: [\n              {\n                message: 'Access denied',\n              },\n            ],\n          });\n        }),\n      ],\n    },\n  },\n};\n```\n\n```html filename=\"ApolloWrapperClient.vue\" renderer=\"vue\" language=\"js\" tabTitle=\"apollo-wrapper-component\"\n<template>\n  <div><slot /></div>\n</template>\n\n<script>\n  import { defineComponent, provide } from 'vue';\n  import { DefaultApolloClient } from '@vue/apollo-composable';\n  import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client/core';\n\n  // Apollo client wrapper component that can be used within your app and Storybook\n  export default defineComponent({\n    name: 'WrapperComponent',\n    setup() {\n      const httpLink = createHttpLink({\n        // You should use an absolute URL here\n        uri: 'https://your-graphql-endpoint',\n      });\n      const cache = new InMemoryCache();\n\n      const mockedClient = new ApolloClient({\n        link: httpLink,\n        cache,\n        defaultOptions: {\n          watchQuery: {\n            fetchPolicy: 'no-cache',\n            errorPolicy: 'all',\n          },\n          query: {\n            fetchPolicy: 'no-cache',\n            errorPolicy: 'all',\n          },\n        },\n      });\n      provide(DefaultApolloClient, mockedClient);\n    },\n  });\n</script>\n```\n\n```ts filename=\"YourPage.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"story\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport { graphql, HttpResponse, delay } from 'msw';\n\nimport WrapperComponent from './ApolloWrapperClient.vue';\nimport DocumentScreen from './YourPage.vue';\n\nconst meta = {\n  component: DocumentScreen,\n  render: () => ({\n    components: { DocumentScreen, WrapperComponent },\n    template: '<WrapperComponent><DocumentScreen /></WrapperComponent>',\n  }),\n} satisfies Meta<typeof DocumentScreen>;\n\n//👇The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const MockedSuccess: Story = {\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', () => {\n          return HttpResponse.json({\n            data: {\n              allInfo: {\n                ...TestData,\n              },\n            },\n          });\n        }),\n      ],\n    },\n  },\n};\n\nexport const MockedError: Story = {\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', async () => {\n          await delay(800);\n          return HttpResponse.json({\n            errors: [\n              {\n                message: 'Access denied',\n              },\n            ],\n          });\n        }),\n      ],\n    },\n  },\n};\n```\n\n```html filename=\"ApolloWrapperClient.vue\" renderer=\"vue\" language=\"ts\" tabTitle=\"apollo-wrapper-component\"\n<template>\n  <div><slot /></div>\n</template>\n\n<script>\n  import { defineComponent, provide } from 'vue';\n  import { DefaultApolloClient } from '@vue/apollo-composable';\n  import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client/core';\n\n  // Apollo client wrapper component that can be used within your app and Storybook\n  export default defineComponent({\n    name: 'WrapperComponent',\n    setup() {\n      const httpLink = createHttpLink({\n        // You should use an absolute URL here\n        uri: 'https://your-graphql-endpoint',\n      });\n      const cache = new InMemoryCache();\n\n      const mockedClient = new ApolloClient({\n        link: httpLink,\n        cache,\n        defaultOptions: {\n          watchQuery: {\n            fetchPolicy: 'no-cache',\n            errorPolicy: 'all',\n          },\n          query: {\n            fetchPolicy: 'no-cache',\n            errorPolicy: 'all',\n          },\n        },\n      });\n      provide(DefaultApolloClient, mockedClient);\n    },\n  });\n</script>\n```\n\n```tsx filename=\"YourPage.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\nimport { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client';\nimport { graphql, HttpResponse, delay } from 'msw';\n\nimport preview from '../.storybook/preview';\n\nimport { DocumentScreen } from './YourPage';\n\nconst mockedClient = new ApolloClient({\n  uri: 'https://your-graphql-endpoint',\n  cache: new InMemoryCache(),\n  defaultOptions: {\n    watchQuery: {\n      fetchPolicy: 'no-cache',\n      errorPolicy: 'all',\n    },\n    query: {\n      fetchPolicy: 'no-cache',\n      errorPolicy: 'all',\n    },\n  },\n});\n\n//👇The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\nconst meta = preview.meta({\n  component: DocumentScreen,\n  decorators: [\n    (Story) => (\n      <ApolloProvider client={mockedClient}>\n        <Story />\n      </ApolloProvider>\n    ),\n  ],\n});\n\nexport const MockedSuccess = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', () => {\n          return HttpResponse.json({\n            data: {\n              allInfo: {\n                ...TestData,\n              },\n            },\n          });\n        }),\n      ],\n    },\n  },\n});\n\nexport const MockedError = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', async () => {\n          await delay(800);\n          return HttpResponse.json({\n            errors: [\n              {\n                message: 'Access denied',\n              },\n            ],\n          });\n        }),\n      ],\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"YourPage.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\nimport { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client';\nimport { graphql, HttpResponse, delay } from 'msw';\n\nimport preview from '../.storybook/preview';\n\nimport { DocumentScreen } from './YourPage';\n\nconst mockedClient = new ApolloClient({\n  uri: 'https://your-graphql-endpoint',\n  cache: new InMemoryCache(),\n  defaultOptions: {\n    watchQuery: {\n      fetchPolicy: 'no-cache',\n      errorPolicy: 'all',\n    },\n    query: {\n      fetchPolicy: 'no-cache',\n      errorPolicy: 'all',\n    },\n  },\n});\n\n//👇The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nconst meta = preview.meta({\n  component: DocumentScreen,\n  decorators: [\n    (Story) => (\n      <ApolloProvider client={mockedClient}>\n        <Story />\n      </ApolloProvider>\n    ),\n  ],\n});\n\nexport const MockedSuccess = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', () => {\n          return HttpResponse.json({\n            data: {\n              allInfo: {\n                ...TestData,\n              },\n            },\n          });\n        }),\n      ],\n    },\n  },\n});\n\nexport const MockedError = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', async () => {\n          await delay(800);\n          return HttpResponse.json({\n            errors: [\n              {\n                message: 'Access denied',\n              },\n            ],\n          });\n        }),\n      ],\n    },\n  },\n});\n```\n\n```ts filename=\"YourPage.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { graphql, HttpResponse, delay } from 'msw';\n\nimport preview from '../.storybook/preview';\n\nimport WrapperComponent from './ApolloWrapperClient.vue';\nimport DocumentScreen from './YourPage.vue';\n\n//👇The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nconst meta = preview.meta({\n  component: DocumentScreen,\n  render: () => ({\n    components: { DocumentScreen, WrapperComponent },\n    template: '<WrapperComponent><DocumentScreen /></WrapperComponent>',\n  }),\n});\n\nexport const MockedSuccess = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', () => {\n          return HttpResponse.json({\n            data: {\n              allInfo: {\n                ...TestData,\n              },\n            },\n          });\n        }),\n      ],\n    },\n  },\n});\n\nexport const MockedError = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', async () => {\n          await delay(800);\n          return HttpResponse.json({\n            errors: [\n              {\n                message: 'Access denied',\n              },\n            ],\n          });\n        }),\n      ],\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"YourPage.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { graphql, HttpResponse, delay } from 'msw';\n\nimport preview from '../.storybook/preview';\n\nimport WrapperComponent from './ApolloWrapperClient.vue';\nimport DocumentScreen from './YourPage.vue';\n\n//👇The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nconst meta = preview.meta({\n  component: DocumentScreen,\n  render: () => ({\n    components: { DocumentScreen, WrapperComponent },\n    template: '<WrapperComponent><DocumentScreen /></WrapperComponent>',\n  }),\n});\n\nexport const MockedSuccess = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', () => {\n          return HttpResponse.json({\n            data: {\n              allInfo: {\n                ...TestData,\n              },\n            },\n          });\n        }),\n      ],\n    },\n  },\n});\n\nexport const MockedError = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        graphql.query('AllInfoQuery', async () => {\n          await delay(800);\n          return HttpResponse.json({\n            errors: [\n              {\n                message: 'Access denied',\n              },\n            ],\n          });\n        }),\n      ],\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/msw-addon-configure-handlers-http.md",
    "content": "```ts filename=\"YourPage.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { http, HttpResponse, delay } from 'msw';\n\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { DocumentScreen } from './your-page.component';\n\nconst meta: Meta<DocumentScreen> = {\n  component: DocumentScreen,\n};\n\nexport default meta;\ntype Story = StoryObj<DocumentScreen>;\n\n// 👇 The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nexport const MockedSuccess: Story = {\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint/', () => {\n          return HttpResponse.json(TestData);\n        }),\n      ],\n    },\n  },\n};\n\nexport const MockedError: Story = {\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint', async () => {\n          await delay(800);\n          return new HttpResponse(null, {\n            status: 403,\n          });\n        }),\n      ],\n    },\n  },\n};\n```\n\n```ts filename=\"YourPage.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { http, HttpResponse, delay } from 'msw';\n\nimport preview from '../.storybook/preview';\n\nimport { DocumentScreen } from './your-page.component';\n\nconst meta = preview.meta({\n  component: DocumentScreen,\n});\n\n// 👇 The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nexport const MockedSuccess = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint/', () => {\n          return HttpResponse.json(TestData);\n        }),\n      ],\n    },\n  },\n});\n\nexport const MockedError = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint', async () => {\n          await delay(800);\n          return new HttpResponse(null, {\n            status: 403,\n          });\n        }),\n      ],\n    },\n  },\n});\n```\n\n```svelte filename=\"YourPage.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { http, HttpResponse, delay } from 'msw';\n\n  import DocumentScreen  from './YourPage.svelte';\n\n  const { Story } = defineMeta({\n    component: DocumentScreen,\n  });\n\n  // 👇 The mocked data that will be used in the story\n  const TestData = {\n    user: {\n      userID: 1,\n      name: 'Someone',\n    },\n    document: {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n      status: 'approved',\n    },\n    subdocuments: [\n      {\n        id: 1,\n        userID: 1,\n        title: 'Something',\n        content:\n          'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n        status: \"approved\",\n      },\n    ],\n  };\n</script>\n\n<Story\n  name=\"MockedSuccess\"\n  parameters={{\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint', () => {\n          return HttpResponse.json(TestData);\n        }),\n      ],\n    },\n  }}\n/>\n\n<Story\n  name=\"MockedError\"\n  parameters={{\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint', async () => {\n          await delay(800);\n          return new HttpResponse(null, {\n            status: 403,\n          });\n        }),\n      ],\n    },\n  }}\n/>\n```\n\n```js filename=\"YourPage.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport { http, HttpResponse, delay } from 'msw';\n\nimport DocumentScreen from './YourPage.svelte';\n\nexport default {\n  component: DocumentScreen,\n};\n\n// 👇 The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nexport const MockedSuccess = {\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint/', () => {\n          return HttpResponse.json(TestData);\n        }),\n      ],\n    },\n  },\n};\n\nexport const MockedError = {\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint', async () => {\n          await delay(800);\n          return new HttpResponse(null, {\n            status: 403,\n          });\n        }),\n      ],\n    },\n  },\n};\n```\n\n```js filename=\"YourPage.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { http, HttpResponse, delay } from 'msw';\n\nimport { DocumentScreen } from './YourPage';\n\nexport default {\n  component: DocumentScreen,\n};\n\n// 👇 The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nexport const MockedSuccess = {\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint/', () => {\n          return HttpResponse.json(TestData);\n        }),\n      ],\n    },\n  },\n};\n\nexport const MockedError = {\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint', async () => {\n          await delay(800);\n          return new HttpResponse(null, {\n            status: 403,\n          });\n        }),\n      ],\n    },\n  },\n};\n```\n\n```svelte filename=\"YourPage.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { http, HttpResponse, delay } from 'msw';\n\n  import DocumentScreen  from './YourPage.svelte';\n\n  const { Story } = defineMeta({\n    component: DocumentScreen,\n  });\n\n  // 👇 The mocked data that will be used in the story\n  const TestData = {\n    user: {\n      userID: 1,\n      name: 'Someone',\n    },\n    document: {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n      status: 'approved',\n    },\n    subdocuments: [\n      {\n        id: 1,\n        userID: 1,\n        title: 'Something',\n        content:\n          'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n        status: \"approved\",\n      },\n    ],\n  };\n</script>\n\n<Story\n  name=\"MockedSuccess\"\n  parameters={{\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint', () => {\n          return HttpResponse.json(TestData);\n        }),\n      ],\n    },\n  }}\n/>\n\n<Story\n  name=\"MockedError\"\n  parameters={{\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint', async () => {\n          await delay(800);\n          return new HttpResponse(null, {\n            status: 403,\n          });\n        }),\n      ],\n    },\n  }}\n/>\n```\n\n```ts filename=\"YourPage.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { http, HttpResponse, delay } from 'msw';\n\nimport DocumentScreen from './YourPage.svelte';\n\nconst meta = {\n  component: DocumentScreen,\n} satisfies Meta<typeof DocumentScreen>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// 👇 The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nexport const MockedSuccess: Story = {\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint/', () => {\n          return HttpResponse.json(TestData);\n        }),\n      ],\n    },\n  },\n};\n\nexport const MockedError: Story = {\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint', async () => {\n          await delay(800);\n          return new HttpResponse(null, {\n            status: 403,\n          });\n        }),\n      ],\n    },\n  },\n};\n```\n\n```ts filename=\"YourPage.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { http, HttpResponse, delay } from 'msw';\n\nimport { DocumentScreen } from './YourPage';\n\nconst meta = {\n  component: DocumentScreen,\n} satisfies Meta<typeof DocumentScreen>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// 👇 The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nexport const MockedSuccess: Story = {\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint/', () => {\n          return HttpResponse.json(TestData);\n        }),\n      ],\n    },\n  },\n};\n\nexport const MockedError: Story = {\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint', async () => {\n          await delay(800);\n          return new HttpResponse(null, {\n            status: 403,\n          });\n        }),\n      ],\n    },\n  },\n};\n```\n\n```js filename=\"YourPage.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { http, HttpResponse, delay } from 'msw';\n\nexport default {\n  component: 'demo-document-screen',\n};\n\n// 👇 The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nexport const MockedSuccess = {\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint/', () => {\n          return HttpResponse.json(TestData);\n        }),\n      ],\n    },\n  },\n};\n\nexport const MockedError = {\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint', async () => {\n          await delay(800);\n          return new HttpResponse(null, {\n            status: 403,\n          });\n        }),\n      ],\n    },\n  },\n};\n```\n\n```ts filename=\"YourPage.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { http, HttpResponse, delay } from 'msw';\n\nconst meta: Meta = {\n  component: 'demo-document-screen',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\n// 👇 The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nexport const MockedSuccess: Story = {\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint/', () => {\n          return HttpResponse.json(TestData);\n        }),\n      ],\n    },\n  },\n};\n\nexport const MockedError: Story = {\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint', async () => {\n          await delay(800);\n          return new HttpResponse(null, {\n            status: 403,\n          });\n        }),\n      ],\n    },\n  },\n};\n```\n\n```ts filename=\"YourPage.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { http, HttpResponse, delay } from 'msw';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-document-screen',\n});\n\n// 👇 The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nexport const MockedSuccess = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint/', () => {\n          return HttpResponse.json(TestData);\n        }),\n      ],\n    },\n  },\n});\n\nexport const MockedError = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint', async () => {\n          await delay(800);\n          return new HttpResponse(null, {\n            status: 403,\n          });\n        }),\n      ],\n    },\n  },\n});\n```\n\n```js filename=\"YourPage.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { http, HttpResponse, delay } from 'msw';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-document-screen',\n});\n\n// 👇 The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nexport const MockedSuccess = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint/', () => {\n          return HttpResponse.json(TestData);\n        }),\n      ],\n    },\n  },\n});\n\nexport const MockedError = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint', async () => {\n          await delay(800);\n          return new HttpResponse(null, {\n            status: 403,\n          });\n        }),\n      ],\n    },\n  },\n});\n```\n\n```ts filename=\"YourPage.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { http, HttpResponse, delay } from 'msw';\n\nimport preview from '../.storybook/preview';\n\nimport { DocumentScreen } from './YourPage';\n\nconst meta = preview.meta({\n  component: DocumentScreen,\n});\n\n// 👇 The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nexport const MockedSuccess = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint/', () => {\n          return HttpResponse.json(TestData);\n        }),\n      ],\n    },\n  },\n});\n\nexport const MockedError = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint', async () => {\n          await delay(800);\n          return new HttpResponse(null, {\n            status: 403,\n          });\n        }),\n      ],\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"YourPage.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { http, HttpResponse, delay } from 'msw';\n\nimport preview from '../.storybook/preview';\n\nimport { DocumentScreen } from './YourPage';\n\n// 👇 The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nconst meta = preview.meta({\n  component: DocumentScreen,\n});\n\nexport const MockedSuccess = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint/', () => {\n          return HttpResponse.json(TestData);\n        }),\n      ],\n    },\n  },\n});\n\nexport const MockedError = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint', async () => {\n          await delay(800);\n          return new HttpResponse(null, {\n            status: 403,\n          });\n        }),\n      ],\n    },\n  },\n});\n```\n\n```ts filename=\"YourPage.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { http, HttpResponse, delay } from 'msw';\n\nimport preview from '../.storybook/preview';\n\nimport DocumentScreen from './YourPage.vue';\n\n// 👇 The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nconst meta = preview.meta({\n  component: DocumentScreen,\n});\n\nexport const MockedSuccess = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint/', () => {\n          return HttpResponse.json(TestData);\n        }),\n      ],\n    },\n  },\n});\n\nexport const MockedError = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint', async () => {\n          await delay(800);\n          return new HttpResponse(null, {\n            status: 403,\n          });\n        }),\n      ],\n    },\n  },\n});\n```\n\n```js filename=\"YourPage.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { http, HttpResponse, delay } from 'msw';\n\nimport preview from '../.storybook/preview';\n\nimport DocumentScreen from './YourPage.vue';\n\nconst meta = preview.meta({\n  component: DocumentScreen,\n});\n\n// 👇 The mocked data that will be used in the story\nconst TestData = {\n  user: {\n    userID: 1,\n    name: 'Someone',\n  },\n  document: {\n    id: 1,\n    userID: 1,\n    title: 'Something',\n    brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',\n    status: 'approved',\n  },\n  subdocuments: [\n    {\n      id: 1,\n      userID: 1,\n      title: 'Something',\n      content:\n        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n      status: 'approved',\n    },\n  ],\n};\n\nexport const MockedSuccess = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint/', () => {\n          return HttpResponse.json(TestData);\n        }),\n      ],\n    },\n  },\n});\n\nexport const MockedError = meta.story({\n  parameters: {\n    msw: {\n      handlers: [\n        http.get('https://your-restful-endpoint', async () => {\n          await delay(800);\n          return new HttpResponse(null, {\n            status: 403,\n          });\n        }),\n      ],\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/msw-addon-initialize.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { initialize, mswLoader } from 'msw-storybook-addon';\n\n/*\n * Initializes MSW\n * See https://github.com/mswjs/msw-storybook-addon#configuring-msw\n * to learn how to customize it\n */\ninitialize();\n\nexport default {\n  loaders: [mswLoader], // 👈 Add the MSW loader to all stories\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nimport { initialize, mswLoader } from 'msw-storybook-addon';\n\n/*\n * Initializes MSW\n * See https://github.com/mswjs/msw-storybook-addon#configuring-msw\n * to learn how to customize it\n */\ninitialize();\n\nconst preview: Preview = {\n  loaders: [mswLoader], // 👈 Add the MSW loader to all stories\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { initialize, mswLoader } from 'msw-storybook-addon';\n\n/*\n * Initializes MSW\n * See https://github.com/mswjs/msw-storybook-addon#configuring-msw\n * to learn how to customize it\n */\ninitialize();\n\nexport default definePreview({\n  loaders: [mswLoader], // 👈 Add the MSW loader to all stories\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { initialize, mswLoader } from 'msw-storybook-addon';\n\n/*\n * Initializes MSW\n * See https://github.com/mswjs/msw-storybook-addon#configuring-msw\n * to learn how to customize it\n */\ninitialize();\n\nexport default definePreview({\n  loaders: [mswLoader], // 👈 Add the MSW loader to all stories\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport { initialize, mswLoader } from 'msw-storybook-addon';\n\n/*\n * Initializes MSW\n * See https://github.com/mswjs/msw-storybook-addon#configuring-msw\n * to learn how to customize it\n */\ninitialize();\n\nexport default definePreview({\n  loaders: [mswLoader], // 👈 Add the MSW loader to all stories\n});\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport { initialize, mswLoader } from 'msw-storybook-addon';\n\n/*\n * Initializes MSW\n * See https://github.com/mswjs/msw-storybook-addon#configuring-msw\n * to learn how to customize it\n */\ninitialize();\n\nexport default definePreview({\n  loaders: [mswLoader], // 👈 Add the MSW loader to all stories\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nimport { initialize, mswLoader } from 'msw-storybook-addon';\n\n/*\n * Initializes MSW\n * See https://github.com/mswjs/msw-storybook-addon#configuring-msw\n * to learn how to customize it\n */\ninitialize();\n\nexport default definePreview({\n  loaders: [mswLoader], // 👈 Add the MSW loader to all stories\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { initialize, mswLoader } from 'msw-storybook-addon';\n\n/*\n * Initializes MSW\n * See https://github.com/mswjs/msw-storybook-addon#configuring-msw\n * to learn how to customize it\n */\ninitialize();\n\nexport default definePreview({\n  loaders: [mswLoader], // 👈 Add the MSW loader to all stories\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { initialize, mswLoader } from 'msw-storybook-addon';\n\n/*\n * Initializes MSW\n * See https://github.com/mswjs/msw-storybook-addon#configuring-msw\n * to learn how to customize it\n */\ninitialize();\n\nexport default definePreview({\n  loaders: [mswLoader], // 👈 Add the MSW loader to all stories\n});\n```\n"
  },
  {
    "path": "docs/_snippets/msw-addon-install.md",
    "content": "```sh renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm install msw msw-storybook-addon --save-dev\n```\n\n```sh renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm add msw msw-storybook-addon --save-dev\n```\n\n```sh renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn add msw msw-storybook-addon --save-dev\n```\n"
  },
  {
    "path": "docs/_snippets/msw-generate-service-worker.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx msw init public/\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn dlx msw init public/\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx msw init public/\n```\n"
  },
  {
    "path": "docs/_snippets/multiple-stories-test.md",
    "content": "```js filename=\"Form.test.js|jsx\" renderer=\"react\" language=\"js\"\nimport { fireEvent, screen } from '@testing-library/react';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\nimport * as FormStories from './LoginForm.stories';\n\nconst { InvalidForm, ValidForm } = composeStories(FormStories);\n\ntest('Tests invalid form state', async () => {\n  await InvalidForm.run();\n\n  const buttonElement = screen.getByRole('button', {\n    name: 'Submit',\n  });\n\n  fireEvent.click(buttonElement);\n\n  const isFormValid = screen.getByLabelText('invalid-form');\n  expect(isFormValid).toBeInTheDocument();\n});\n\ntest('Tests filled form', async () => {\n  await ValidForm.run();\n\n  const buttonElement = screen.getByRole('button', {\n    name: 'Submit',\n  });\n\n  fireEvent.click(buttonElement);\n\n  const isFormValid = screen.getByLabelText('invalid-form');\n  expect(isFormValid).not.toBeInTheDocument();\n});\n```\n\n```ts filename=\"Form.test.ts|tsx\" renderer=\"react\" language=\"ts\"\nimport { fireEvent, screen } from '@testing-library/react';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\nimport * as FormStories from './LoginForm.stories';\n\nconst { InvalidForm, ValidForm } = composeStories(FormStories);\n\ntest('Tests invalid form state', async () => {\n  await InvalidForm.run();\n\n  const buttonElement = screen.getByRole('button', {\n    name: 'Submit',\n  });\n\n  fireEvent.click(buttonElement);\n\n  const isFormValid = screen.getByLabelText('invalid-form');\n  expect(isFormValid).toBeInTheDocument();\n});\n\ntest('Tests filled form', async () => {\n  await ValidForm.run();\n\n  const buttonElement = screen.getByRole('button', {\n    name: 'Submit',\n  });\n\n  fireEvent.click(buttonElement);\n\n  const isFormValid = screen.getByLabelText('invalid-form');\n  expect(isFormValid).not.toBeInTheDocument();\n});\n```\n\n```js filename=\"tests/Form.test.js\" renderer=\"vue\" language=\"js\"\nimport { fireEvent, screen } from '@testing-library/vue';\n\nimport { composeStories } from '@storybook/vue3-vite';\n\nimport * as FormStories from './LoginForm.stories';\n\nconst { InvalidForm, ValidForm } = composeStories(FormStories);\n\ntest('Tests invalid form state', async () => {\n  await InvalidForm.run();\n\n  const buttonElement = screen.getByRole('button', {\n    name: 'Submit',\n  });\n\n  fireEvent.click(buttonElement);\n\n  const isFormValid = screen.getByLabelText('invalid-form');\n  expect(isFormValid).toBeInTheDocument();\n});\n\ntest('Tests filled form', async () => {\n  await ValidForm.run();\n\n  const buttonElement = screen.getByRole('button', {\n    name: 'Submit',\n  });\n\n  fireEvent.click(buttonElement);\n\n  const isFormValid = screen.getByLabelText('invalid-form');\n  expect(isFormValid).not.toBeInTheDocument();\n});\n```\n\n```ts filename=\"tests/Form.test.ts\" renderer=\"vue\" language=\"ts\"\nimport { fireEvent, screen } from '@testing-library/vue';\n\nimport { composeStories } from '@storybook/vue3-vite';\n\nimport * as FormStories from './LoginForm.stories';\n\nconst { InvalidForm, ValidForm } = composeStories(FormStories);\n\ntest('Tests invalid form state', async () => {\n  await InvalidForm.run();\n\n  const buttonElement = screen.getByRole('button', {\n    name: 'Submit',\n  });\n\n  fireEvent.click(buttonElement);\n\n  const isFormValid = screen.getByLabelText('invalid-form');\n  expect(isFormValid).toBeInTheDocument();\n});\n\ntest('Tests filled form', async () => {\n  await ValidForm.run();\n\n  const buttonElement = screen.getByRole('button', {\n    name: 'Submit',\n  });\n\n  fireEvent.click(buttonElement);\n\n  const isFormValid = screen.getByLabelText('invalid-form');\n  expect(isFormValid).not.toBeInTheDocument();\n});\n```\n"
  },
  {
    "path": "docs/_snippets/my-component-disable-toc.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      toc: {\n        disable: true, // 👈 Disables the table of contents\n      },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      toc: {\n        disable: true, // 👈 Disables the table of contents\n      },\n    },\n  },\n});\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n    tags: ['autodocs'],\n    parameters: {\n      docs: {\n        toc: {\n          disable: true, // 👈 Disables the table of contents\n        },\n      },\n    },\n  });\n</script>\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.svelte';\n\nexport default {\n  component: MyComponent,\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      toc: {\n        disable: true, // 👈 Disables the table of contents\n      },\n    },\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      toc: {\n        disable: true, // 👈 Disables the table of contents\n      },\n    },\n  },\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n    tags: ['autodocs'],\n    parameters: {\n      docs: {\n        toc: {\n          disable: true, // 👈 Disables the table of contents\n        },\n      },\n    },\n  });\n</script>\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport MyComponent from './MyComponent.svelte';\n\nconst meta = {\n  component: MyComponent,\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      toc: {\n        disable: true, // 👈 Disables the table of contents\n      },\n    },\n  },\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      toc: {\n        disable: true, // 👈 Disables the table of contents\n      },\n    },\n  },\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'my-component',\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      toc: {\n        disable: true, // 👈 Disables the table of contents\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'my-component',\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      toc: {\n        disable: true, // 👈 Disables the table of contents\n      },\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      toc: {\n        disable: true, // 👈 Disables the table of contents\n      },\n    },\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      toc: {\n        disable: true, // 👈 Disables the table of contents\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      toc: {\n        disable: true, // 👈 Disables the table of contents\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      toc: {\n        disable: true, // 👈 Disables the table of contents\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      toc: {\n        disable: true, // 👈 Disables the table of contents\n      },\n    },\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  tags: ['autodocs'],\n  parameters: {\n    docs: {\n      toc: {\n        disable: true, // 👈 Disables the table of contents\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/my-component-env-var-config.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n};\n\nexport default meta;\ntype Story = StoryObj<MyComponent>;\n\nexport const Basic: Story = {\n  args: {\n    exampleProp: process.env.EXAMPLE_VAR,\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Basic = meta.story({\n  args: {\n    exampleProp: process.env.EXAMPLE_VAR,\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const Basic = {\n  args: {\n    exampleProp: process.env.EXAMPLE_VAR,\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  args: {\n    exampleProp: process.env.EXAMPLE_VAR,\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'my-component',\n};\n\nexport const Basic = {\n  args: {\n    exampleProp: process.env.EXAMPLE_VAR,\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'my-component',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Basic: Story = {\n  args: {\n    exampleProp: process.env.EXAMPLE_VAR,\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const Basic = meta.story({\n  args: {\n    exampleProp: process.env.EXAMPLE_VAR,\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const Basic = meta.story({\n  args: {\n    exampleProp: process.env.EXAMPLE_VAR,\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Basic = meta.story({\n  args: {\n    exampleProp: process.env.EXAMPLE_VAR,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Basic = meta.story({\n  args: {\n    exampleProp: process.env.EXAMPLE_VAR,\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Basic = meta.story({\n  args: {\n    exampleProp: process.env.EXAMPLE_VAR,\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Basic = meta.story({\n  args: {\n    exampleProp: process.env.EXAMPLE_VAR,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/my-component-exclude-tags.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n  //👇 Provides the `no-tests` tag to all stories in this file\n  tags: ['no-tests'],\n};\n\nexport default meta;\ntype Story = StoryObj<MyComponent>;\n\nexport const ExcludeStory: Story = {\n  //👇 Adds the `no-tests` tag to this story to exclude it from the tests when enabled in the test-runner configuration\n  tags: ['no-tests'],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  //👇 Provides the `no-tests` tag to all stories in this file\n  tags: ['no-tests'],\n});\n\nexport const ExcludeStory = meta.story({\n  //👇 Adds the `no-tests` tag to this story to exclude it from the tests when enabled in the test-runner configuration\n  tags: ['no-tests'],\n});\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n  //👇 Provides the `no-tests` tag to all stories in this file\n  tags: ['no-tests'],\n};\n\nexport const ExcludeStory = {\n  //👇 Adds the `no-tests` tag to this story to exclude it from the tests when enabled in the test-runner configuration\n  tags: ['no-tests'],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the name of your framework\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n  //👇 Provides the `no-tests` tag to all stories in this file\n  tags: ['no-tests'],\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ExcludeStory: Story = {\n  //👇 Adds the `no-tests` tag to this story to exclude it from the tests when enabled in the test-runner configuration\n  tags: ['no-tests'],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  //👇 Provides the `no-tests` tag to all stories in this file\n  tags: ['no-tests'],\n});\n\nexport const ExcludeStory = meta.story({\n  //👇 Adds the `no-tests` tag to this story to exclude it from the tests when enabled in the test-runner configuration\n  tags: ['no-tests'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  //👇 Provides the `no-tests` tag to all stories in this file\n  tags: ['no-tests'],\n});\n\nexport const ExcludeStory = meta.story({\n  //👇 Adds the `no-tests` tag to this story to exclude it from the tests when enabled in the test-runner configuration\n  tags: ['no-tests'],\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  //👇 Provides the `no-tests` tag to all stories in this file\n  tags: ['no-tests'],\n});\n\nexport const ExcludeStory = meta.story({\n  //👇 Adds the `no-tests` tag to this story to exclude it from the tests when enabled in the test-runner configuration\n  tags: ['no-tests'],\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  //👇 Provides the `no-tests` tag to all stories in this file\n  tags: ['no-tests'],\n});\n\nexport const ExcludeStory = meta.story({\n  //👇 Adds the `no-tests` tag to this story to exclude it from the tests when enabled in the test-runner configuration\n  tags: ['no-tests'],\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'my-component',\n  //👇 Provides the `no-tests` tag to all stories in this file\n  tags: ['no-tests'],\n};\n\nexport const ExcludeStory = {\n  //👇 Adds the `no-tests` tag to this story to exclude it from the tests when enabled in the test-runner configuration\n  tags: ['no-tests'],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'my-component',\n  //👇 Provides the `no-tests` tag to all stories in this file\n  tags: ['no-tests'],\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const ExcludeStory: Story = {\n  //👇 Adds the `no-tests` tag to this story to exclude it from the tests when enabled in the test-runner configuration\n  tags: ['no-tests'],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n  //👇 Provides the `no-tests` tag to all stories in this file\n  tags: ['no-tests'],\n});\n\nexport const ExcludeStory = meta.story({\n  //👇 Adds the `no-tests` tag to this story to exclude it from the tests when enabled in the test-runner configuration\n  tags: ['no-tests'],\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n  //👇 Provides the `no-tests` tag to all stories in this file\n  tags: ['no-tests'],\n});\n\nexport const ExcludeStory = meta.story({\n  //👇 Adds the `no-tests` tag to this story to exclude it from the tests when enabled in the test-runner configuration\n  tags: ['no-tests'],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/my-component-include-tags.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n  //👇 Provides the `test-only` tag to all stories in this file\n  tags: ['test-only'],\n};\n\nexport default meta;\ntype Story = StoryObj<MyComponent>;\n\nexport const IncludeStory: Story = {\n  //👇 Adds the `test-only` tag to this story to be included in the tests when enabled in the test-runner configuration\n  tags: ['test-only'],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  //👇 Provides the `test-only` tag to all stories in this file\n  tags: ['test-only'],\n});\n\nexport const IncludeStory = meta.story({\n  //👇 Adds the `test-only` tag to this story to be included in the tests when enabled in the test-runner configuration\n  tags: ['test-only'],\n});\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n  //👇 Provides the `test-only` tag to all stories in this file\n  tags: ['test-only'],\n};\n\nexport const IncludeStory = {\n  //👇 Adds the `test-only` tag to this story to be included in the tests when enabled in the test-runner configuration\n  tags: ['test-only'],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the name of your framework\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n  //👇 Provides the `test-only` tag to all stories in this file\n  tags: ['test-only'],\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const IncludeStory: Story = {\n  //👇 Adds the `test-only` tag to this story to be included in the tests when enabled in the test-runner configuration\n  tags: ['test-only'],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  //👇 Provides the `test-only` tag to all stories in this file\n  tags: ['test-only'],\n});\n\nexport const IncludeStory = meta.story({\n  //👇 Adds the `test-only` tag to this story to be included in the tests when enabled in the test-runner configuration\n  tags: ['test-only'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  //👇 Provides the `test-only` tag to all stories in this file\n  tags: ['test-only'],\n});\n\nexport const IncludeStory = meta.story({\n  //👇 Adds the `test-only` tag to this story to be included in the tests when enabled in the test-runner configuration\n  tags: ['test-only'],\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  //👇 Provides the `test-only` tag to all stories in this file\n  tags: ['test-only'],\n});\n\nexport const IncludeStory = meta.story({\n  //👇 Adds the `test-only` tag to this story to be included in the tests when enabled in the test-runner configuration\n  tags: ['test-only'],\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  //👇 Provides the `test-only` tag to all stories in this file\n  tags: ['test-only'],\n});\n\nexport const IncludeStory = meta.story({\n  //👇 Adds the `test-only` tag to this story to be included in the tests when enabled in the test-runner configuration\n  tags: ['test-only'],\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'my-component',\n  //👇 Provides the `test-only` tag to all stories in this file\n  tags: ['test-only'],\n};\n\nexport const IncludeStory = {\n  //👇 Adds the `test-only` tag to this story to be included in the tests when enabled in the test-runner configuration\n  tags: ['test-only'],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'my-component',\n  //👇 Provides the `test-only` tag to all stories in this file\n  tags: ['test-only'],\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const IncludeStory: Story = {\n  //👇 Adds the `test-only` tag to this story to be included in the tests when enabled in the test-runner configuration\n  tags: ['test-only'],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n  //👇 Provides the `test-only` tag to all stories in this file\n  tags: ['test-only'],\n});\n\nexport const IncludeStory = meta.story({\n  //👇 Adds the `test-only` tag to this story to be included in the tests when enabled in the test-runner configuration\n  tags: ['test-only'],\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n  //👇 Provides the `test-only` tag to all stories in this file\n  tags: ['test-only'],\n});\n\nexport const IncludeStory = meta.story({\n  //👇 Adds the `test-only` tag to this story to be included in the tests when enabled in the test-runner configuration\n  tags: ['test-only'],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/my-component-skip-tags.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n  //👇 Provides the `skip-test` tag to all stories in this file\n  tags: ['skip-test'],\n};\n\nexport default meta;\ntype Story = StoryObj<MyComponent>;\n\nexport const SkipStory: Story = {\n  //👇 Adds the `skip-test` tag to this story to allow it to be skipped in the tests when enabled in the test-runner configuration\n  tags: ['skip-test'],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  //👇 Provides the `skip-test` tag to all stories in this file\n  tags: ['skip-test'],\n});\n\nexport const SkipStory = meta.story({\n  //👇 Adds the `skip-test` tag to this story to allow it to be skipped in the tests when enabled in the test-runner configuration\n  tags: ['skip-test'],\n});\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n  //👇 Provides the `skip-test` tag to all stories in this file\n  tags: ['skip-test'],\n};\n\nexport const SkipStory = {\n  //👇 Adds the `skip-test` tag to this story to allow it to be skipped in the tests when enabled in the test-runner configuration\n  tags: ['skip-test'],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the name of your framework\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n  //👇 Provides the `skip-test` tag to all stories in this file\n  tags: ['skip-test'],\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const SkipStory: Story = {\n  //👇 Adds the `skip-test` tag to this story to allow it to be skipped in the tests when enabled in the test-runner configuration\n  tags: ['skip-test'],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  //👇 Provides the `skip-test` tag to all stories in this file\n  tags: ['skip-test'],\n});\n\nexport const SkipStory = meta.story({\n  //👇 Adds the `skip-test` tag to this story to allow it to be skipped in the tests when enabled in the test-runner configuration\n  tags: ['skip-test'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  //👇 Provides the `skip-test` tag to all stories in this file\n  tags: ['skip-test'],\n});\n\nexport const SkipStory = meta.story({\n  //👇 Adds the `skip-test` tag to this story to allow it to be skipped in the tests when enabled in the test-runner configuration\n  tags: ['skip-test'],\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  //👇 Provides the `skip-test` tag to all stories in this file\n  tags: ['skip-test'],\n});\n\nexport const SkipStory = meta.story({\n  //👇 Adds the `skip-test` tag to this story to allow it to be skipped in the tests when enabled in the test-runner configuration\n  tags: ['skip-test'],\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  //👇 Provides the `skip-test` tag to all stories in this file\n  tags: ['skip-test'],\n});\n\nexport const SkipStory = meta.story({\n  //👇 Adds the `skip-test` tag to this story to allow it to be skipped in the tests when enabled in the test-runner configuration\n  tags: ['skip-test'],\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'my-component',\n  //👇 Provides the `skip-test` tag to all stories in this file\n  tags: ['skip-test'],\n};\n\nexport const SkipStory = {\n  //👇 Adds the `skip-test` tag to this story to exclude it from the tests when enabled in the test-runner configuration\n  tags: ['skip-test'],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'my-component',\n  //👇 Provides the `skip-test` tag to all stories in this file\n  tags: ['skip-test'],\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const SkipStory: Story = {\n  //👇 Adds the `skip-test` tag to this story to exclude it from the tests when enabled in the test-runner configuration\n  tags: ['skip-test'],\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n  //👇 Provides the `skip-test` tag to all stories in this file\n  tags: ['skip-test'],\n});\n\nexport const SkipStory = meta.story({\n  //👇 Adds the `skip-test` tag to this story to exclude it from the tests when enabled in the test-runner configuration\n  tags: ['skip-test'],\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n  //👇 Provides the `skip-test` tag to all stories in this file\n  tags: ['skip-test'],\n});\n\nexport const SkipStory = meta.story({\n  //👇 Adds the `skip-test` tag to this story to exclude it from the tests when enabled in the test-runner configuration\n  tags: ['skip-test'],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/my-component-story-basic-and-props.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n};\n\nexport default meta;\ntype Story = StoryObj<MyComponent>;\n\nexport const Basic: Story = {};\n\nexport const WithProp: Story = {\n  render: () => ({\n    props: {\n      prop: 'value',\n    },\n  }),\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Basic = meta.story();\n\nexport const WithProp = meta.story({\n  render: () => ({\n    props: {\n      prop: 'value',\n    },\n  }),\n});\n```\n\n```jsx filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const Basic = {};\n\nexport const WithProp = {\n  render: () => <MyComponent prop=\"value\" />,\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {};\n\nexport const WithProp: Story = {\n  render: () => <MyComponent prop=\"value\" />,\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Basic = meta.story();\n\nexport const WithProp = meta.story({\n  render: () => <MyComponent prop=\"value\" />,\n});\n```\n\n```jsx filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Basic = meta.story();\n\nexport const WithProp = meta.story({\n  render: () => <MyComponent prop=\"value\" />,\n});\n```\n\n```jsx filename=\"MyComponent.story.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const Basic = {};\n\nexport const WithProp = {\n  render: () => <MyComponent prop=\"value\" />,\n};\n```\n\n```tsx filename=\"MyComponent.story.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {};\n\nexport const WithProp: Story = {\n  render: () => <MyComponent prop=\"value\" />,\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story name=\"Basic\">\n  <MyComponent />\n</Story>\n\n<Story name=\"WithProp\">\n  <MyComponent prop=\"value\" />\n</Story>\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.svelte';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const Basic = {};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const WithProp = {\n  render: () => ({\n    Component: MyComponent,\n    props: {\n      prop: 'value',\n    },\n  }),\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story name=\"Basic\">\n  <MyComponent />\n</Story>\n\n<Story name=\"WithProp\">\n  <MyComponent prop=\"value\" />\n</Story>\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport MyComponent from './MyComponent.svelte';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const WithProp: Story = {\n  render: () => ({\n    Component: MyComponent,\n    props: {\n      prop: 'value',\n    },\n  }),\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.vue';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const Basic = {\n  render: () => ({\n    components: { MyComponent },\n    template: '<MyComponent />',\n  }),\n};\n\nexport const WithProp = {\n  render: () => ({\n    components: { MyComponent },\n    template: '<MyComponent prop=\"value\"/>',\n  }),\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  render: () => ({\n    components: { MyComponent },\n    template: '<MyComponent />',\n  }),\n};\n\nexport const WithProp: Story = {\n  render: () => ({\n    components: { MyComponent },\n    template: '<MyComponent prop=\"value\"/>',\n  }),\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Basic = meta.story({\n  render: () => ({\n    components: { MyComponent },\n    template: '<MyComponent />',\n  }),\n});\n\nexport const WithProp = meta.story({\n  render: () => ({\n    components: { MyComponent },\n    template: '<MyComponent prop=\"value\"/>',\n  }),\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Basic = meta.story({\n  render: () => ({\n    components: { MyComponent },\n    template: '<MyComponent />',\n  }),\n});\n\nexport const WithProp = meta.story({\n  render: () => ({\n    components: { MyComponent },\n    template: '<MyComponent prop=\"value\"/>',\n  }),\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nexport default {\n  title: 'Path/To/MyComponent',\n  component: 'my-component',\n};\n\nexport const Basic = {};\n\nexport const WithProp = {\n  render: () => html`<my-component prop=\"value\" />`,\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nconst meta: Meta = {\n  component: 'my-component',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Basic: Story = {};\n\nexport const WithProp: Story = {\n  render: () => html`<my-component prop=\"value\" />`,\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const Basic = meta.story();\n\nexport const WithProp = meta.story({\n  render: () => html`<my-component prop=\"value\" />`,\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const Basic = meta.story();\n\nexport const WithProp = meta.story({\n  render: () => html`<my-component prop=\"value\" />`,\n});\n```\n"
  },
  {
    "path": "docs/_snippets/my-component-story-import-json.md",
    "content": "```js filename=\"MyComponent.stories.js|jsx|mjs|ts|tsx\" renderer=\"common\" language=\"js\"\n// This will automatically be parsed to the contents of `data.json`\nimport data from './data.json';\n```\n"
  },
  {
    "path": "docs/_snippets/my-component-story-import-static-asset.md",
    "content": "```js filename=\"MyComponent.stories.js|jsx|mjs|ts|tsx\" renderer=\"common\" language=\"js\"\n// This will include './static/image.png' in the bundle.\n// And return a path to be included in a src attribute\nimport imageFile from './static/image.png';\n```\n"
  },
  {
    "path": "docs/_snippets/my-component-story-mandatory-export.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Path/To/MyComponent',\n  component: MyComponent,\n  decorators: [\n    /* ... */\n  ],\n  parameters: {\n    /* ... */\n  },\n};\n\nexport default meta;\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    /* 👇 The title prop is optional.\n     * See https://storybook.js.org/docs/configure/#configure-story-loading\n     * to learn how to generate automatic titles\n     */\n    title: 'Path/To/MyComponent',\n    component: MyComponent,\n    decorators: [\n      /* ... */\n    ],\n    parameters: {\n      /* ... */\n    },\n  });\n</script>\n```\n\n```js filename=\"MyComponent.story.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.svelte';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Path/To/MyComponent',\n  component: MyComponent,\n  decorators: [\n    /* ... */\n  ],\n  parameters: {\n    /* ... */\n  },\n};\n```\n\n```js filename=\"MyComponent.story.js|jsx\" renderer=\"common\" language=\"js\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Path/To/MyComponent',\n  component: MyComponent,\n  decorators: [\n    /* ... */\n  ],\n  parameters: {\n    /* ... */\n  },\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    /* 👇 The title prop is optional.\n     * See https://storybook.js.org/docs/configure/#configure-story-loading\n     * to learn how to generate automatic titles\n     */\n    title: 'Path/To/MyComponent',\n    component: MyComponent,\n    decorators: [\n      /* ... */\n    ],\n    parameters: {\n      /* ... */\n    },\n  });\n</script>\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport MyComponent from './MyComponent.svelte';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Path/To/MyComponent',\n  component: MyComponent,\n  decorators: [\n    /* ... */\n  ],\n  parameters: {\n    /* ... */\n  },\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"common\" language=\"ts\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Path/To/MyComponent',\n  component: MyComponent,\n  decorators: [\n    /* ... */\n  ],\n  parameters: {\n    /* ... */\n  },\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\"\nexport default {\n  title: 'Path/To/MyComponent',\n  component: 'my-component',\n  decorators: [\n    /* ... */\n  ],\n  parameters: {\n    /* ... */\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  title: 'Path/To/MyComponent',\n  component: 'my-component',\n  decorators: [\n    /* ... */\n  ],\n  parameters: {\n    /* ... */\n  },\n};\n\nexport default meta;\n```\n"
  },
  {
    "path": "docs/_snippets/my-component-story-use-globaltype.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n};\n\nexport default meta;\ntype Story = StoryObj<MyComponent>;\n\nconst getCaptionForLocale = (locale) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'zh':\n      return '你好!';\n    default:\n      return 'Hello!';\n  }\n};\n\nexport const StoryWithLocale: Story = {\n  render: (args, { globals: { locale } }) => {\n    const caption = getCaptionForLocale(locale);\n    return {\n      template: `<p>${caption}</p>`,\n    };\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nconst getCaptionForLocale = (locale) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'zh':\n      return '你好!';\n    default:\n      return 'Hello!';\n  }\n};\n\nexport const StoryWithLocale = meta.story({\n  render: (args, { globals: { locale } }) => {\n    const caption = getCaptionForLocale(locale);\n    return {\n      template: `<p>${caption}</p>`,\n    };\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nconst getCaptionForLocale = (locale) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'zh':\n      return '你好!';\n    default:\n      return 'Hello!';\n  }\n};\n\nexport const StoryWithLocale = {\n  render: (args, { globals: { locale } }) => {\n    const caption = getCaptionForLocale(locale);\n    return <p>{caption}</p>;\n  },\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nconst getCaptionForLocale = (locale) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'zh':\n      return '你好!';\n    default:\n      return 'Hello!';\n  }\n};\n\nexport const StoryWithLocale = {\n  render: (args, { globals: { locale } }) => {\n    const caption = getCaptionForLocale(locale);\n    return <p>{caption}</p>;\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nconst getCaptionForLocale = (locale) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'zh':\n      return '你好!';\n    default:\n      return 'Hello!';\n  }\n};\n\nexport const StoryWithLocale = {\n  render: (args, { globals: { locale } }) => {\n    const caption = getCaptionForLocale(locale);\n    return <p>{caption}</p>;\n  },\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nconst getCaptionForLocale = (locale) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'zh':\n      return '你好!';\n    default:\n      return 'Hello!';\n  }\n};\n\nexport const StoryWithLocale = {\n  render: (args, { globals: { locale } }) => {\n    const caption = getCaptionForLocale(locale);\n    return <p>{caption}</p>;\n  },\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from \"@storybook/addon-svelte-csf\";\n\n  import MyComponent from \"./MyComponent.svelte\";\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<script>\n  const getCaptionForLocale = (locale) => {\n    switch (locale) {\n      case 'es':\n        return 'Hola!';\n      case 'fr':\n        return 'Bonjour!';\n      case \"kr\":\n        return '안녕하세요!';\n      case \"zh\":\n        return '你好!';\n      default:\n        return 'Hello!';\n    }\n  };\n</script>\n\n<Story name=\"StoryWithLocale\">\n  {#snippet template(args, { globals: { locale } })}\n    <MyComponent\n      {...args}\n      locale={getCaptionForLocale(locale)}\n    />\n  {/snippet}\n</Story>\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.svelte';\n\nexport default {\n  component: MyComponent,\n};\n\nconst getCaptionForLocale = (locale) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'zh':\n      return '你好!';\n    default:\n      return 'Hello!';\n  }\n};\n\nexport const StoryWithLocale = {\n  render: (args, { globals: { locale } }) => {\n    const caption = getCaptionForLocale(locale);\n    return {\n      Component: MyComponent,\n      props: {\n        locale: caption,\n      },\n    };\n  },\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from \"@storybook/addon-svelte-csf\";\n\n  import MyComponent from \"./MyComponent.svelte\";\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<script lang=\"ts\">\n  const getCaptionForLocale = (locale:string) => {\n    switch (locale) {\n      case 'es':\n        return 'Hola!';\n      case 'fr':\n        return 'Bonjour!';\n      case \"kr\":\n        return '안녕하세요!';\n      case \"zh\":\n        return '你好!';\n      default:\n        return 'Hello!';\n    }\n  };\n</script>\n\n<Story name=\"StoryWithLocale\">\n  {#snippet template(args, { globals: { locale } })}\n    <MyComponent\n      {...args}\n      locale={getCaptionForLocale(locale)}\n    />\n  {/snippet}\n</Story>\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport MyComponent from './MyComponent.svelte';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nconst getCaptionForLocale = (locale) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'zh':\n      return '你好!';\n    default:\n      return 'Hello!';\n  }\n};\n\nexport const StoryWithLocale: Story = {\n  render: (args, { globals: { locale } }) => {\n    const caption = getCaptionForLocale(locale);\n    return {\n      Component: MyComponent,\n      props: {\n        locale: caption,\n      },\n    };\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.vue';\n\nexport default {\n  component: MyComponent,\n};\n\nconst getCaptionForLocale = (locale) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'zh':\n      return '你好!';\n    default:\n      return 'Hello!';\n  }\n};\n\nexport const StoryWithLocale = {\n  render: (args, { globals: { locale } }) => {\n    const caption = getCaptionForLocale(locale);\n    return {\n      template: `<p>${caption}</p>`,\n    };\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nconst getCaptionForLocale = (locale) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'zh':\n      return '你好!';\n    default:\n      return 'Hello!';\n  }\n};\n\nexport default meta;\ntype Story = StoryObj<typeof MyComponent>;\n\nexport const MyStory: Story = {\n  render: (args, { globals: { locale } }) => {\n    const caption = getCaptionForLocale(locale);\n    return {\n      template: `<p>${caption}</p>`,\n    };\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nexport default {\n  component: 'my-component',\n};\n\nconst getCaptionForLocale = (locale) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'zh':\n      return '你好!';\n    default:\n      return 'Hello!';\n  }\n};\n\nexport const StoryWithLocale = {\n  render: (args, { globals: { locale } }) => {\n    const caption = getCaptionForLocale(locale);\n    return html`<p>${caption}</p>`;\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nconst meta: Meta = {\n  component: 'my-component',\n};\n\nconst getCaptionForLocale = (locale) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'zh':\n      return '你好!';\n    default:\n      return 'Hello!';\n  }\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const StoryWithLocale: Story = {\n  render: (args, { globals: { locale } }) => {\n    const caption = getCaptionForLocale(locale);\n    return html`<p>${caption}</p>`;\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nconst getCaptionForLocale = (locale) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'zh':\n      return '你好!';\n    default:\n      return 'Hello!';\n  }\n};\n\nexport const StoryWithLocale = meta.story({\n  render: (args, { globals: { locale } }) => {\n    const caption = getCaptionForLocale(locale);\n    return html`<p>${caption}</p>`;\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nconst getCaptionForLocale = (locale) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'zh':\n      return '你好!';\n    default:\n      return 'Hello!';\n  }\n};\n\nexport const StoryWithLocale = meta.story({\n  render: (args, { globals: { locale } }) => {\n    const caption = getCaptionForLocale(locale);\n    return html`<p>${caption}</p>`;\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nconst getCaptionForLocale = (locale) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'zh':\n      return '你好!';\n    default:\n      return 'Hello!';\n  }\n};\n\nexport const StoryWithLocale = meta.story({\n  render: (args, { globals: { locale } }) => {\n    const caption = getCaptionForLocale(locale);\n    return {\n      template: `<p>${caption}</p>`,\n    };\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nconst getCaptionForLocale = (locale) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'zh':\n      return '你好!';\n    default:\n      return 'Hello!';\n  }\n};\n\nexport const StoryWithLocale = meta.story({\n  render: (args, { globals: { locale } }) => {\n    const caption = getCaptionForLocale(locale);\n    return {\n      template: `<p>${caption}</p>`,\n    };\n  },\n});\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nconst getCaptionForLocale = (locale) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'zh':\n      return '你好!';\n    default:\n      return 'Hello!';\n  }\n};\n\nexport const StoryWithLocale = meta.story({\n  render: (args, { globals: { locale } }) => {\n    const caption = getCaptionForLocale(locale);\n    return <p>{caption}</p>;\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nconst getCaptionForLocale = (locale) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'zh':\n      return '你好!';\n    default:\n      return 'Hello!';\n  }\n};\n\nexport const StoryWithLocale = meta.story({\n  render: (args, { globals: { locale } }) => {\n    const caption = getCaptionForLocale(locale);\n    return <p>{caption}</p>;\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/my-component-story-with-nonstory.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { MyComponent } from './my-component.component';\n\nimport someData from './data.json';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n  includeStories: ['SimpleStory', 'ComplexStory'], // 👈 Storybook loads these stories\n  excludeStories: /.*Data$/, // 👈 Storybook ignores anything that contains Data\n};\n\nexport default meta;\n\nexport const simpleData = { foo: 1, bar: 'baz' };\nexport const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n\ntype Story = StoryObj<MyComponent>;\n\nexport const SimpleStory: Story = {\n  args: {\n    data: simpleData,\n  },\n};\n\nexport const ComplexStory: Story = {\n  args: {\n    data: complexData,\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nimport someData from './data.json';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  includeStories: ['SimpleStory', 'ComplexStory'], // 👈 Storybook loads these stories\n  excludeStories: /.*Data$/, // 👈 Storybook ignores anything that contains Data\n});\n\nexport const simpleData = { foo: 1, bar: 'baz' };\nexport const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n\nexport const SimpleStory = meta.story({\n  args: {\n    data: simpleData,\n  },\n});\n\nexport const ComplexStory = meta.story({\n  args: {\n    data: complexData,\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyComponent } from './MyComponent';\n\nimport someData from './data.json';\n\nexport default {\n  component: MyComponent,\n  includeStories: ['SimpleStory', 'ComplexStory'], // 👈 Storybook loads these stories\n  excludeStories: /.*Data$/, // 👈 Storybook ignores anything that contains Data\n};\n\nexport const simpleData = { foo: 1, bar: 'baz' };\nexport const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n\nexport const SimpleStory = {\n  args: {\n    data: simpleData,\n  },\n};\n\nexport const ComplexStory = {\n  args: {\n    data: complexData,\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { MyComponent } from './MyComponent';\n\nimport someData from './data.json';\n\nconst meta = {\n  component: MyComponent,\n  includeStories: ['SimpleStory', 'ComplexStory'], // 👈 Storybook loads these stories\n  excludeStories: /.*Data$/, // 👈 Storybook ignores anything that contains Data\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const simpleData = { foo: 1, bar: 'baz' };\nexport const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n\nexport const SimpleStory: Story = {\n  args: {\n    data: simpleData,\n  },\n};\n\nexport const ComplexStory: Story = {\n  args: {\n    data: complexData,\n  },\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nimport someData from './data.json';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  includeStories: ['SimpleStory', 'ComplexStory'], // 👈 Storybook loads these stories\n  excludeStories: /.*Data$/, // 👈 Storybook ignores anything that contains Data\n});\n\nexport const simpleData = { foo: 1, bar: 'baz' };\nexport const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n\nexport const SimpleStory = meta.story({\n  args: {\n    data: simpleData,\n  },\n});\n\nexport const ComplexStory = meta.story({\n  args: {\n    data: complexData,\n  },\n});\n```\n\n```jsx filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nimport someData from './data.json';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  includeStories: ['SimpleStory', 'ComplexStory'], // 👈 Storybook loads these stories\n  excludeStories: /.*Data$/, // 👈 Storybook ignores anything that contains Data\n});\n\nexport const simpleData = { foo: 1, bar: 'baz' };\nexport const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n\nexport const SimpleStory = meta.story({\n  args: {\n    data: simpleData,\n  },\n});\n\nexport const ComplexStory = meta.story({\n  args: {\n    data: complexData,\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { MyComponent } from './MyComponent';\n\nimport someData from './data.json';\n\nexport default {\n  component: MyComponent,\n  includeStories: ['SimpleStory', 'ComplexStory'], // 👈 Storybook loads these stories\n  excludeStories: /.*Data$/, // 👈 Storybook ignores anything that contains Data\n};\n\nexport const simpleData = { foo: 1, bar: 'baz' };\nexport const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n\nexport const SimpleStory = {\n  args: {\n    data: simpleData,\n  },\n};\n\nexport const ComplexStory = {\n  args: {\n    data: complexData,\n  },\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { MyComponent } from './MyComponent';\n\nimport someData from './data.json';\n\nconst meta = {\n  component: MyComponent,\n  includeStories: ['SimpleStory', 'ComplexStory'], // 👈 Storybook loads these stories\n  excludeStories: /.*Data$/, // 👈 Storybook ignores anything that contains Data\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const simpleData = { foo: 1, bar: 'baz' };\nexport const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n\nexport const SimpleStory: Story = {\n  args: {\n    data: simpleData,\n  },\n};\n\nexport const ComplexStory: Story = {\n  args: {\n    data: complexData,\n  },\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  import someData from './data.json';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n    includeStories: ['SimpleStory', 'ComplexStory'], // 👈 Storybook loads these stories\n    excludeStories: /.*Data$/, // 👈 Storybook ignores anything that contains Data\n  });\n\n  export const simpleData = { foo: 1, bar: 'baz' };\n\n  export const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n</script>\n\n<Story name=\"SimpleStory\" args={{ data: simpleData }} />\n\n<Story name=\"ComplexStory\" args={{ data: complexData }} />\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.svelte';\n\nimport someData from './data.json';\n\nexport default {\n  component: MyComponent,\n  includeStories: ['SimpleStory', 'ComplexStory'], // 👈 Storybook loads these stories\n  excludeStories: /.*Data$/, // 👈 Storybook ignores anything that contains Data\n};\n\nexport const simpleData = { foo: 1, bar: 'baz' };\nexport const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n\nexport const SimpleStory = {\n  args: {\n    data: simpleData,\n  },\n};\n\nexport const ComplexStory = {\n  args: {\n    data: complexData,\n  },\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  import someData from './data.json';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n    includeStories: ['SimpleStory', 'ComplexStory'], // 👈 Storybook loads these stories\n    excludeStories: /.*Data$/, // 👈 Storybook ignores anything that contains Data\n  });\n\n  export const simpleData = { foo: 1, bar: 'baz' };\n\n  export const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n</script>\n\n<Story name=\"SimpleStory\" args={{ data: simpleData }} />\n\n<Story name=\"ComplexStory\" args={{ data: complexData }} />\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport MyComponent from './MyComponent.svelte';\n\nimport someData from './data.json';\n\nconst meta = {\n  component: MyComponent,\n  includeStories: ['SimpleStory', 'ComplexStory'], // 👈 Storybook loads these stories\n  excludeStories: /.*Data$/, // 👈 Storybook ignores anything that contains Data\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const simpleData = { foo: 1, bar: 'baz' };\nexport const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n\nexport const SimpleStory: Story = {\n  args: {\n    data: simpleData,\n  },\n};\n\nexport const ComplexStory: Story = {\n  args: {\n    data: complexData,\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.vue';\n\nimport someData from './data.json';\n\nexport default {\n  component: MyComponent,\n  includeStories: ['SimpleStory', 'ComplexStory'],\n  excludeStories: /.*Data$/, // 👈 Storybook ignores anything that contains Data\n};\n\nexport const simpleData = { foo: 1, bar: 'baz' };\nexport const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n\nexport const SimpleStory = {\n  args: {\n    data: simpleData,\n  },\n};\n\nexport const ComplexStory = {\n  args: {\n    data: complexData,\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport MyComponent from './MyComponent.vue';\n\nimport someData from './data.json';\n\nconst meta = {\n  component: MyComponent,\n  includeStories: ['SimpleStory', 'ComplexStory'],\n  excludeStories: /.*Data$/, // 👈 Storybook ignores anything that contains Data\n} satisfies Meta<typeof MyComponent>;\n\nexport const simpleData = { foo: 1, bar: 'baz' };\nexport const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const SimpleStory: Story = {\n  args: {\n    data: simpleData,\n  },\n};\n\nexport const ComplexStory: Story = {\n  args: {\n    data: complexData,\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nimport someData from './data.json';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  includeStories: ['SimpleStory', 'ComplexStory'],\n  excludeStories: /.*Data$/, // 👈 Storybook ignores anything that contains Data\n});\n\nexport const simpleData = { foo: 1, bar: 'baz' };\nexport const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n\nexport const SimpleStory = meta.story({\n  args: {\n    data: simpleData,\n  },\n});\n\nexport const ComplexStory = meta.story({\n  args: {\n    data: complexData,\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nimport someData from './data.json';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  includeStories: ['SimpleStory', 'ComplexStory'],\n  excludeStories: /.*Data$/, // 👈 Storybook ignores anything that contains Data\n});\n\nexport const simpleData = { foo: 1, bar: 'baz' };\nexport const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n\nexport const SimpleStory = meta.story({\n  args: {\n    data: simpleData,\n  },\n});\n\nexport const ComplexStory = meta.story({\n  args: {\n    data: complexData,\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'my-component',\n  includeStories: ['SimpleStory', 'ComplexStory'], // 👈 Storybook loads these stories\n  excludeStories: /.*Data$/, // 👈 Storybook ignores anything that contains Data\n};\n\nexport const simpleData = { foo: 1, bar: 'baz' };\nexport const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n\nexport const SimpleStory = {\n  args: {\n    data: simpleData,\n  },\n};\n\nexport const ComplexStory = {\n  args: {\n    data: complexData,\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'my-component',\n  includeStories: ['SimpleStory', 'ComplexStory'], // 👈 Storybook loads these stories\n  excludeStories: /.*Data$/, // 👈 Storybook ignores anything that contains Data\n};\n\nexport const simpleData = { foo: 1, bar: 'baz' };\nexport const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const SimpleStory: Story = {\n  args: {\n    data: simpleData,\n  },\n};\n\nexport const ComplexStory: Story = {\n  args: {\n    data: complexData,\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n  includeStories: ['SimpleStory', 'ComplexStory'], // 👈 Storybook loads these stories\n  excludeStories: /.*Data$/, // 👈 Storybook ignores anything that contains Data\n});\n\nexport const simpleData = { foo: 1, bar: 'baz' };\nexport const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n\nexport const SimpleStory = meta.story({\n  args: {\n    data: simpleData,\n  },\n});\n\nexport const ComplexStory = meta.story({\n  args: {\n    data: complexData,\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n  includeStories: ['SimpleStory', 'ComplexStory'], // 👈 Storybook loads these stories\n  excludeStories: /.*Data$/, // 👈 Storybook ignores anything that contains Data\n});\n\nexport const simpleData = { foo: 1, bar: 'baz' };\nexport const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } };\n\nexport const SimpleStory = meta.story({\n  args: {\n    data: simpleData,\n  },\n});\n\nexport const ComplexStory = meta.story({\n  args: {\n    data: complexData,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/my-component-story-with-storyname.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<Button> = {\n  component: MyComponent,\n};\n\nexport default meta;\ntype Story = StoryObj<MyComponent>;\n\nexport const Simple: Story = {\n  name: 'So simple!',\n  // ...\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Simple = meta.story({\n  name: 'So simple!',\n  // ...\n});\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const Simple = {\n  name: 'So simple!',\n  // ...\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Simple: Story = {\n  name: 'So simple!',\n  // ...\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Simple = meta.story({\n  name: 'So simple!',\n  // ...\n});\n```\n\n```jsx filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Simple = meta.story({\n  name: 'So simple!',\n  // ...\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Simple = meta.story({\n  name: 'So simple!',\n  // ...\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Simple = meta.story({\n  name: 'So simple!',\n  // ...\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'my-component',\n};\n\nexport const Simple = {\n  name: 'So simple!',\n  // ...\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'my-component',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Simple: Story = {\n  name: 'So simple!',\n  // ...\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const Simple = meta.story({\n  name: 'So simple!',\n  // ...\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const Simple = meta.story({\n  name: 'So simple!',\n  // ...\n});\n```\n"
  },
  {
    "path": "docs/_snippets/my-component-story.md",
    "content": "```js filename=\"MyComponent.stories.js|jsx|mjs|ts|tsx\" renderer=\"common\" language=\"js\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'MyComponent',\n  component: MyComponent,\n};\n\n// Your stories\n```\n"
  },
  {
    "path": "docs/_snippets/my-component-vite-env-variables.md",
    "content": "```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"ExampleStory\"\n  args={{\n    propertyA: import.meta.env.STORYBOOK_DATA_KEY,\n    propertyB: import.meta.env.VITE_CUSTOM_VAR,\n  }}\n/>\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.svelte';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const ExampleStory = {\n  args: {\n    propertyA: import.meta.env.STORYBOOK_DATA_KEY,\n    propertyB: import.meta.env.VITE_CUSTOM_VAR,\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const ExampleStory = {\n  args: {\n    propertyA: import.meta.env.STORYBOOK_DATA_KEY,\n    propertyB: import.meta.env.VITE_CUSTOM_VAR,\n  },\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"ExampleStory\"\n  args={{\n    propertyA: import.meta.env.STORYBOOK_DATA_KEY,\n    propertyB: import.meta.env.VITE_CUSTOM_VAR,\n  }}\n/>\n```\n\n```tsx filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport MyComponent from './MyComponent.svelte';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ExampleStory: Story = {\n  args: {\n    propertyA: import.meta.env.STORYBOOK_DATA_KEY,\n    propertyB: import.meta.env.VITE_CUSTOM_VAR,\n  },\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ExampleStory: Story = {\n  args: {\n    propertyA: import.meta.env.STORYBOOK_DATA_KEY,\n    propertyB: import.meta.env.VITE_CUSTOM_VAR,\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'my-component',\n};\n\nexport const ExampleStory = {\n  args: {\n    propertyA: import.meta.env.STORYBOOK_DATA_KEY,\n    propertyB: import.meta.env.VITE_CUSTOM_VAR,\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'my-component',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const ExampleStory: Story = {\n  args: {\n    propertyA: import.meta.env.STORYBOOK_DATA_KEY,\n    propertyB: import.meta.env.VITE_CUSTOM_VAR,\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const ExampleStory = meta.story({\n  args: {\n    propertyA: import.meta.env.STORYBOOK_DATA_KEY,\n    propertyB: import.meta.env.VITE_CUSTOM_VAR,\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const ExampleStory = meta.story({\n  args: {\n    propertyA: import.meta.env.STORYBOOK_DATA_KEY,\n    propertyB: import.meta.env.VITE_CUSTOM_VAR,\n  },\n});\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ExampleStory = meta.story({\n  args: {\n    propertyA: import.meta.env.STORYBOOK_DATA_KEY,\n    propertyB: import.meta.env.VITE_CUSTOM_VAR,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ExampleStory = meta.story({\n  args: {\n    propertyA: import.meta.env.STORYBOOK_DATA_KEY,\n    propertyB: import.meta.env.VITE_CUSTOM_VAR,\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ExampleStory = meta.story({\n  args: {\n    propertyA: import.meta.env.STORYBOOK_DATA_KEY,\n    propertyB: import.meta.env.VITE_CUSTOM_VAR,\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ExampleStory = meta.story({\n  args: {\n    propertyA: import.meta.env.STORYBOOK_DATA_KEY,\n    propertyB: import.meta.env.VITE_CUSTOM_VAR,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/my-component-with-custom-syntax-highlight.md",
    "content": "<!-- prettier-ignore -->\n```mdx filename=\"MyComponent.mdx\" renderer=\"common\" language=\"mdx\"\nimport { Meta } from '@storybook/addon-docs/blocks';\nimport { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';\n\n<Meta title=\"A Storybook doc with a custom syntax highlight for SCSS\" />\n\n# SCSS example\n\nThis is a sample SCSS code block example highlighted in Storybook\n\n{/* Don't forget to replace (\") with (```) when you copy the snippet to your own app */}\n\n\"scss\n$font-stack: Helvetica, sans-serif;\n$primary-color: #333;\n\nbody {\n  font: 100% $font-stack;\n  color: $primary-color;\n}\n\"\n\n{/* The usage of this \"Component\" is intentional to enable react-syntax-highlighter's own highlighter */}\n\nexport const Component = () => {\n  return <SyntaxHighlighter/>;\n};\n```\n"
  },
  {
    "path": "docs/_snippets/my-component-with-env-variables.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n};\n\nexport default meta;\ntype Story = StoryObj<MyComponent>;\n\nexport const ExampleStory: Story = {\n  args: {\n    propertyA: process.env.STORYBOOK_DATA_KEY,\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ExampleStory = meta.story({\n  args: {\n    propertyA: process.env.STORYBOOK_DATA_KEY,\n  },\n});\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"ExampleStory\"\n  args={{\n    propertyA: process.env.STORYBOOK_DATA_KEY\n  }}\n/>\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.svelte';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const ExampleStory = {\n  args: {\n    propertyA: process.env.STORYBOOK_DATA_KEY,\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const ExampleStory = {\n  args: {\n    propertyA: process.env.STORYBOOK_DATA_KEY,\n  },\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"ExampleStory\"\n  args={{\n    propertyA: process.env.STORYBOOK_DATA_KEY\n  }}\n/>\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport MyComponent from './MyComponent.svelte';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ExampleStory: Story = {\n  args: {\n    propertyA: process.env.STORYBOOK_DATA_KEY,\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ExampleStory: Story = {\n  args: {\n    propertyA: process.env.STORYBOOK_DATA_KEY,\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'my-component',\n};\n\nexport const ExampleStory = {\n  args: {\n    propertyA: process.env.STORYBOOK_DATA_KEY,\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'my-component',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const ExampleStory: Story = {\n  args: {\n    propertyA: process.env.STORYBOOK_DATA_KEY,\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const ExampleStory = meta.story({\n  args: {\n    propertyA: process.env.STORYBOOK_DATA_KEY,\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const ExampleStory = meta.story({\n  args: {\n    propertyA: process.env.STORYBOOK_DATA_KEY,\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ExampleStory = meta.story({\n  args: {\n    propertyA: process.env.STORYBOOK_DATA_KEY,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ExampleStory = meta.story({\n  args: {\n    propertyA: process.env.STORYBOOK_DATA_KEY,\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ExampleStory = meta.story({\n  args: {\n    propertyA: process.env.STORYBOOK_DATA_KEY,\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ExampleStory = meta.story({\n  args: {\n    propertyA: process.env.STORYBOOK_DATA_KEY,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/my-component-with-global-syntax-highlight.md",
    "content": "<!-- prettier-ignore -->\n```mdx filename=\"MyComponent.mdx\" renderer=\"common\" language=\"mdx\"\nimport { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"A storybook story with syntax highlight registered globally\" />\n\n# SCSS example\n\nThis is a sample Sass snippet example with Storybook docs\n\n{/* Don't forget to replace (\") with (```) when you copy the snippet to your own app */}\n\n\"scss\n$font-stack: Helvetica, sans-serif;\n$primary-color: #333;\n\nbody {\nfont: 100% $font-stack;\n  color: $primary-color;\n}\n\"\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-add-framework.md",
    "content": "```diff filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // ...\n-  framework: '@storybook/react-webpack5',\n+  framework: '@storybook/nextjs',\n};\n```\n\n```diff filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n- import type { StorybookConfig } from '@storybook/your-previous-framework';\n+ import type { StorybookConfig } from '@storybook/nextjs';\n\nconst config: StorybookConfig = {\n  // ...\n-  framework: '@storybook/react-webpack5',\n+  framework: '@storybook/nextjs',\n};\n\nexport default config;\n```\n\n```diff filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n- import { defineMain } from '@storybook/your-previous-framework/node';\n+ import { defineMain } from '@storybook/nextjs/node';\n\nexport default defineMain({\n  // ...\n-  framework: '@storybook/react-webpack5',\n+  framework: '@storybook/nextjs',\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```diff filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n- import { defineMain } from '@storybook/your-previous-framework/node';\n+ import { defineMain } from '@storybook/nextjs/node';\n\nexport default defineMain({\n  // ...\n-  framework: '@storybook/react-webpack5',\n+  framework: '@storybook/nextjs',\n});\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-app-directory-in-meta.md",
    "content": "```js filename=\"NavigationBasedComponent.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport NavigationBasedComponent from './NavigationBasedComponent';\n\nexport default {\n  component: NavigationBasedComponent,\n  parameters: {\n    nextjs: {\n      appDirectory: true, // 👈 Set this\n    },\n  },\n};\n```\n\n```ts filename=\"NavigationBasedComponent.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with nextjs or nextjs-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport NavigationBasedComponent from './NavigationBasedComponent';\n\nconst meta = {\n  component: NavigationBasedComponent,\n  parameters: {\n    nextjs: {\n      appDirectory: true, // 👈 Set this\n    },\n  },\n} satisfies Meta<typeof NavigationBasedComponent>;\nexport default meta;\n```\n\n```ts filename=\"NavigationBasedComponent.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport NavigationBasedComponent from './NavigationBasedComponent';\n\nconst meta = preview.meta({\n  component: NavigationBasedComponent,\n  parameters: {\n    nextjs: {\n      appDirectory: true, // 👈 Set this\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"NavigationBasedComponent.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport NavigationBasedComponent from './NavigationBasedComponent';\n\nconst meta = preview.meta({\n  component: NavigationBasedComponent,\n  parameters: {\n    nextjs: {\n      appDirectory: true, // 👈 Set this\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-app-directory-in-preview.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // ...\n  parameters: {\n    // ...\n    nextjs: {\n      appDirectory: true,\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with nextjs or nextjs-vite\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  // ...\n  parameters: {\n    // ...\n    nextjs: {\n      appDirectory: true,\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with nextjs or nextjs-vite\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  // ...\n  parameters: {\n    // ...\n    nextjs: {\n      appDirectory: true,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with nextjs or nextjs-vite\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  // ...\n  parameters: {\n    // ...\n    nextjs: {\n      appDirectory: true,\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-cache-mock.md",
    "content": "```js filename=\"MyForm.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { expect } from 'storybook/test';\n\n// Replace your-framework with nextjs or nextjs-vite\nimport { revalidatePath } from '@storybook/your-framework/cache';\n\nimport MyForm from './my-form';\n\nexport default {\n  component: MyForm,\n};\n\nexport const Submitted = {\n  async play({ canvas, userEvent }) {\n    const submitButton = canvas.getByRole('button', { name: /submit/i });\n    await userEvent.click(saveButton);\n    // 👇 Use any mock assertions on the function\n    await expect(revalidatePath).toHaveBeenCalledWith('/');\n  },\n};\n```\n\n```ts filename=\"MyForm.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with nextjs or nextjs-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { expect } from 'storybook/test';\n\n// 👇 Must include the `.mock` portion of filename to have mocks typed correctly\nimport { revalidatePath } from '@storybook/your-framework/cache.mock';\n\nimport MyForm from './my-form';\n\nconst meta = {\n  component: MyForm,\n} satisfies Meta<typeof MyForm>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Submitted: Story = {\n  async play({ canvas, userEvent }) {\n    const submitButton = canvas.getByRole('button', { name: /submit/i });\n    await userEvent.click(saveButton);\n    // 👇 Use any mock assertions on the function\n    await expect(revalidatePath).toHaveBeenCalledWith('/');\n  },\n};\n```\n\n```ts filename=\"MyForm.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\n/*\n * Replace your-framework with nextjs or nextjs-vite\n * 👇 Must include the `.mock` portion of filename to have mocks typed correctly\n */\nimport { revalidatePath } from '@storybook/your-framework/cache.mock';\n\nimport preview from '../.storybook/preview';\n\nimport MyForm from './my-form';\n\nconst meta = preview.meta({\n  component: MyForm,\n});\n\nexport const Submitted = meta.story({\n  async play({ canvas, userEvent }) {\n    const submitButton = canvas.getByRole('button', { name: /submit/i });\n    await userEvent.click(saveButton);\n    // 👇 Use any mock assertions on the function\n    await expect(revalidatePath).toHaveBeenCalledWith('/');\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyForm.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\n// Replace your-framework with nextjs or nextjs-vite\nimport { revalidatePath } from '@storybook/your-framework/cache';\n\nimport preview from '../.storybook/preview';\n\nimport MyForm from './my-form';\n\nconst meta = preview.meta({\n  component: MyForm,\n});\n\nexport const Submitted = meta.story({\n  async play({ canvas, userEvent }) {\n    const submitButton = canvas.getByRole('button', { name: /submit/i });\n    await userEvent.click(saveButton);\n    // 👇 Use any mock assertions on the function\n    await expect(revalidatePath).toHaveBeenCalledWith('/');\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-configure-svgr.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // ...\n  webpackFinal: async (config) => {\n    config.module = config.module || {};\n    config.module.rules = config.module.rules || [];\n\n    // This modifies the existing image rule to exclude .svg files\n    // since you want to handle those files with @svgr/webpack\n    const imageRule = config.module.rules.find((rule) => rule?.['test']?.test('.svg'));\n    if (imageRule) {\n      imageRule['exclude'] = /\\.svg$/;\n    }\n\n    // Configure .svg files to be loaded with @svgr/webpack\n    config.module.rules.push({\n      test: /\\.svg$/,\n      use: ['@svgr/webpack'],\n    });\n\n    return config;\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { StorybookConfig } from '@storybook/nextjs';\n\nconst config: StorybookConfig = {\n  // ...\n  webpackFinal: async (config) => {\n    config.module = config.module || {};\n    config.module.rules = config.module.rules || [];\n\n    // This modifies the existing image rule to exclude .svg files\n    // since you want to handle those files with @svgr/webpack\n    const imageRule = config.module.rules.find((rule) => rule?.['test']?.test('.svg'));\n    if (imageRule) {\n      imageRule['exclude'] = /\\.svg$/;\n    }\n\n    // Configure .svg files to be loaded with @svgr/webpack\n    config.module.rules.push({\n      test: /\\.svg$/,\n      use: ['@svgr/webpack'],\n    });\n\n    return config;\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with nextjs or nextjs-vite\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // ...\n  webpackFinal: async (config) => {\n    config.module = config.module || {};\n    config.module.rules = config.module.rules || [];\n\n    // This modifies the existing image rule to exclude .svg files\n    // since you want to handle those files with @svgr/webpack\n    const imageRule = config.module.rules.find((rule) => rule?.['test']?.test('.svg'));\n    if (imageRule) {\n      imageRule['exclude'] = /\\.svg$/;\n    }\n\n    // Configure .svg files to be loaded with @svgr/webpack\n    config.module.rules.push({\n      test: /\\.svg$/,\n      use: ['@svgr/webpack'],\n    });\n\n    return config;\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with nextjs or nextjs-vite\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // ...\n  webpackFinal: async (config) => {\n    config.module = config.module || {};\n    config.module.rules = config.module.rules || [];\n\n    // This modifies the existing image rule to exclude .svg files\n    // since you want to handle those files with @svgr/webpack\n    const imageRule = config.module.rules.find((rule) => rule?.['test']?.test('.svg'));\n    if (imageRule) {\n      imageRule['exclude'] = /\\.svg$/;\n    }\n\n    // Configure .svg files to be loaded with @svgr/webpack\n    config.module.rules.push({\n      test: /\\.svg$/,\n      use: ['@svgr/webpack'],\n    });\n\n    return config;\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-framework-options-next-config-path.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport path from 'node:path';\n\nexport default {\n  // ...\n  framework: {\n    name: '@storybook/your-framework',\n    options: {\n      nextConfigPath: path.resolve(process.cwd(), 'next.config.js'),\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\nimport path from 'node:path';\n\n// Replace your-framework with nextjs or nextjs-vite\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  // ...\n  framework: {\n    name: '@storybook/your-framework',\n    options: {\n      nextConfigPath: path.resolve(process.cwd(), 'next.config.js'),\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport path from 'node:path';\n\n// Replace your-framework with nextjs or nextjs-vite\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // ...\n  framework: {\n    name: '@storybook/your-framework',\n    options: {\n      nextConfigPath: path.resolve(process.cwd(), 'next.config.js'),\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport path from 'node:path';\n\n// Replace your-framework with nextjs or nextjs-vite\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // ...\n  framework: {\n    name: '@storybook/your-framework',\n    options: {\n      nextConfigPath: path.resolve(process.cwd(), 'next.config.js'),\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-headers-mock.md",
    "content": "```js filename=\"MyForm.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { expect, fn } from 'storybook/test';\n\n// Replace your-framework with nextjs or nextjs-vite\nimport { cookies, headers, draftMode } from '@storybook/your-framework/headers';\n\nimport MyForm from './my-form';\n\nexport default {\n  component: MyForm,\n};\n\nexport const LoggedInEurope = {\n  async beforeEach() {\n    // 👇 Set mock cookies, headers and draft mode ahead of rendering\n    cookies().set('username', 'Sol');\n    headers().set('timezone', 'Central European Summer Time');\n    draftMode.mockReturnValue({\n      isEnabled: true,\n      enable: fn(),\n      disable: fn(),\n    });\n  },\n  async play() {\n    // 👇 Assert that your component called the mocks\n    await expect(cookies().get).toHaveBeenCalledOnce();\n    await expect(cookies().get).toHaveBeenCalledWith('username');\n    await expect(headers().get).toHaveBeenCalledOnce();\n    await expect(headers().get).toHaveBeenCalledWith('timezone');\n    await expect(draftMode).toHaveBeenCalled();\n  },\n};\n```\n\n```ts filename=\"MyForm.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with nextjs or nextjs-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { expect, fn } from 'storybook/test';\n\n// 👇 Must include the `.mock` portion of filename to have mocks typed correctly\nimport { cookies, headers, draftMode } from '@storybook/your-framework/headers.mock';\n\nimport MyForm from './my-form';\n\nconst meta = {\n  component: MyForm,\n} satisfies Meta<typeof MyForm>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const LoggedInEurope: Story = {\n  async beforeEach() {\n    // 👇 Set mock cookies, headers and draft mode ahead of rendering\n    cookies().set('username', 'Sol');\n    headers().set('timezone', 'Central European Summer Time');\n    draftMode.mockReturnValue({\n      isEnabled: true,\n      enable: fn(),\n      disable: fn(),\n    });\n  },\n  async play() {\n    // 👇 Assert that your component called the mocks\n    await expect(cookies().get).toHaveBeenCalledOnce();\n    await expect(cookies().get).toHaveBeenCalledWith('username');\n    await expect(headers().get).toHaveBeenCalledOnce();\n    await expect(headers().get).toHaveBeenCalledWith('timezone');\n    await expect(draftMode).toHaveBeenCalled();\n  },\n};\n```\n\n```ts filename=\"MyForm.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { expect, fn } from 'storybook/test';\n\n/*\n * Replace your-framework with nextjs or nextjs-vite\n * 👇 Must include the `.mock` portion of filename to have mocks typed correctly\n */\nimport { cookies, headers, draftMode } from '@storybook/your-framework/headers.mock';\n\nimport preview from '../.storybook/preview';\n\nimport MyForm from './my-form';\n\nconst meta = preview.meta({\n  component: MyForm,\n});\n\nexport const LoggedInEurope = meta.story({\n  async beforeEach() {\n    // 👇 Set mock cookies, headers and draft mode ahead of rendering\n    cookies().set('username', 'Sol');\n    headers().set('timezone', 'Central European Summer Time');\n    draftMode.mockReturnValue({\n      isEnabled: true,\n      enable: fn(),\n      disable: fn(),\n    });\n  },\n  async play() {\n    // 👇 Assert that your component called the mocks\n    await expect(cookies().get).toHaveBeenCalledOnce();\n    await expect(cookies().get).toHaveBeenCalledWith('username');\n    await expect(headers().get).toHaveBeenCalledOnce();\n    await expect(headers().get).toHaveBeenCalledWith('timezone');\n    await expect(draftMode).toHaveBeenCalled();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyForm.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { expect, fn } from 'storybook/test';\n\n// Replace your-framework with nextjs or nextjs-vite\nimport { cookies, headers, draftMode } from '@storybook/your-framework/headers';\n\nimport preview from '../.storybook/preview';\n\nimport MyForm from './my-form';\n\nconst meta = preview.meta({\n  component: MyForm,\n});\n\nexport const LoggedInEurope = meta.story({\n  async beforeEach() {\n    // 👇 Set mock cookies, headers and draft mode ahead of rendering\n    cookies().set('username', 'Sol');\n    headers().set('timezone', 'Central European Summer Time');\n    draftMode.mockReturnValue({\n      isEnabled: true,\n      enable: fn(),\n      disable: fn(),\n    });\n  },\n  async play() {\n    // 👇 Assert that your component called the mocks\n    await expect(cookies().get).toHaveBeenCalledOnce();\n    await expect(cookies().get).toHaveBeenCalledWith('username');\n    await expect(headers().get).toHaveBeenCalledOnce();\n    await expect(headers().get).toHaveBeenCalledWith('timezone');\n    await expect(draftMode).toHaveBeenCalled();\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-image-static-dirs.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // ...\n  staticDirs: [\n    {\n      from: '../src/components/fonts',\n      to: 'src/components/fonts',\n    },\n  ],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with nextjs or nextjs-vite\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  // ...\n  staticDirs: [\n    {\n      from: '../src/components/fonts',\n      to: 'src/components/fonts',\n    },\n  ],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with nextjs or nextjs-vite\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // ...\n  staticDirs: [\n    {\n      from: '../src/components/fonts',\n      to: 'src/components/fonts',\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with nextjs or nextjs-vite\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // ...\n  staticDirs: [\n    {\n      from: '../src/components/fonts',\n      to: 'src/components/fonts',\n    },\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-install.md",
    "content": "```shell renderer=\"react\" language=\"js\" packageManager=\"npm\"\nnpm install --save-dev @storybook/nextjs\n```\n\n```shell renderer=\"react\" language=\"js\" packageManager=\"pnpm\"\npnpm add --save-dev @storybook/nextjs\n```\n\n```shell renderer=\"react\" language=\"js\" packageManager=\"yarn\"\nyarn add --dev @storybook/nextjs\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-navigation-mock.md",
    "content": "```js filename=\"MyForm.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { expect } from 'storybook/test';\n\n// Replace your-framework with nextjs or nextjs-vite\nimport { redirect, getRouter } from '@storybook/your-framework/navigation';\n\nimport MyForm from './my-form';\n\nexport default {\n  component: MyForm,\n  parameters: {\n    nextjs: {\n      // 👇 As in the Next.js application, next/navigation only works using App Router\n      appDirectory: true,\n    },\n  },\n};\n\nexport const Unauthenticated = {\n  async play() {\n    // 👇 Assert that your component called redirect()\n    await expect(redirect).toHaveBeenCalledWith('/login', 'replace');\n  },\n};\n\nexport const GoBack = {\n  async play({ canvas, userEvent }) {\n    const backBtn = await canvas.findByText('Go back');\n\n    await userEvent.click(backBtn);\n    // 👇 Assert that your component called back()\n    await expect(getRouter().back).toHaveBeenCalled();\n  },\n};\n```\n\n```ts filename=\"MyForm.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with nextjs or nextjs-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { expect } from 'storybook/test';\n\n// 👇 Must include the `.mock` portion of filename to have mocks typed correctly\nimport { redirect, getRouter } from '@storybook/your-framework/navigation.mock';\n\nimport MyForm from './my-form';\n\nconst meta = {\n  component: MyForm,\n  parameters: {\n    nextjs: {\n      // 👇 As in the Next.js application, next/navigation only works using App Router\n      appDirectory: true,\n    },\n  },\n} satisfies Meta<typeof MyForm>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Unauthenticated: Story = {\n  async play() {\n    // 👇 Assert that your component called redirect()\n    await expect(redirect).toHaveBeenCalledWith('/login', 'replace');\n  },\n};\n\nexport const GoBack: Story = {\n  async play({ canvas, userEvent }) {\n    const backBtn = await canvas.findByText('Go back');\n\n    await userEvent.click(backBtn);\n    // 👇 Assert that your component called back()\n    await expect(getRouter().back).toHaveBeenCalled();\n  },\n};\n```\n\n```ts filename=\"MyForm.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\n/*\n * Replace your-framework with nextjs or nextjs-vite\n * 👇 Must include the `.mock` portion of filename to have mocks typed correctly\n */\nimport { redirect, getRouter } from '@storybook/your-framework/navigation.mock';\n\nimport preview from '../.storybook/preview';\n\nimport MyForm from './my-form';\n\nconst meta = preview.meta({\n  component: MyForm,\n  parameters: {\n    nextjs: {\n      // 👇 As in the Next.js application, next/navigation only works using App Router\n      appDirectory: true,\n    },\n  },\n});\n\nexport const Unauthenticated = meta.story({\n  async play() {\n    // 👇 Assert that your component called redirect()\n    await expect(redirect).toHaveBeenCalledWith('/login', 'replace');\n  },\n});\n\nexport const GoBack = meta.story({\n  async play({ canvas, userEvent }) {\n    const backBtn = await canvas.findByText('Go back');\n\n    await userEvent.click(backBtn);\n    // 👇 Assert that your component called back()\n    await expect(getRouter().back).toHaveBeenCalled();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyForm.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\n// Replace your-framework with nextjs or nextjs-vite\nimport { redirect, getRouter } from '@storybook/your-framework/navigation.mock';\n\nimport preview from '../.storybook/preview';\n\nimport MyForm from './my-form';\n\nconst meta = preview.meta({\n  component: MyForm,\n  parameters: {\n    nextjs: {\n      // 👇 As in the Next.js application, next/navigation only works using App Router\n      appDirectory: true,\n    },\n  },\n});\n\nexport const Unauthenticated = meta.story({\n  async play() {\n    // 👇 Assert that your component called redirect()\n    await expect(redirect).toHaveBeenCalledWith('/login', 'replace');\n  },\n});\n\nexport const GoBack = meta.story({\n  async play({ canvas, userEvent }) {\n    const backBtn = await canvas.findByText('Go back');\n\n    await userEvent.click(backBtn);\n    // 👇 Assert that your component called back()\n    await expect(getRouter().back).toHaveBeenCalled();\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-navigation-override-in-preview.md",
    "content": "```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with nextjs or nextjs-vite\nimport { getRouter } from '@storybook/your-framework/navigation';\n\nexport default {\n  parameters: {\n    nextjs: {\n      // 👇 Override the default navigation properties\n      navigation: {\n        pathname: '/app/',\n      },\n    },\n  },\n  async beforeEach() {\n    // 👇 Manipulate the default navigation method mocks\n    getRouter().push.mockImplementation(() => {\n      /* ... */\n    });\n  },\n};\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\n// Replace your-framework with nextjs or nextjs-vite\nimport type { Preview } from '@storybook/your-framework';\n\n// 👇 Must include the `.mock` portion of filename to have mocks typed correctly\nimport { getRouter } from \"@storybook/your-framework/navigation.mock\";\n\nconst preview: Preview = {\n  parameters: {\n    nextjs: {\n      // 👇 Override the default navigation properties\n      navigation: {\n        pathname: '/app/',\n      },\n    },\n  },\n  async beforeEach() {\n    // 👇 Manipulate the default navigation method mocks\n    getRouter().push.mockImplementation(() => {\n      /* ... */\n    });\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with nextjs or nextjs-vite\nimport { definePreview } from '@storybook/your-framework';\n\n// 👇 Must include the `.mock` portion of filename to have mocks typed correctly\nimport { getRouter } from '@storybook/your-framework/navigation.mock';\n\nconst preview = definePreview({\n  parameters: {\n    nextjs: {\n      // 👇 Override the default navigation properties\n      navigation: {\n        pathname: '/app/',\n      },\n    },\n  },\n  async beforeEach() {\n    // 👇 Manipulate the default navigation method mocks\n    getRouter().push.mockImplementation(() => {\n      /* ... */\n    });\n  },\n});\n\nexport default preview;\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with nextjs or nextjs-vite\nimport { definePreview } from '@storybook/your-framework';\n\n// 👇 Must include the `.mock` portion of filename to have mocks typed correctly\nimport { getRouter } from '@storybook/your-framework/navigation.mock';\n\nconst preview = definePreview({\n  parameters: {\n    nextjs: {\n      // 👇 Override the default navigation properties\n      navigation: {\n        pathname: '/app/',\n      },\n    },\n  },\n  async beforeEach() {\n    // 👇 Manipulate the default navigation method mocks\n    getRouter().push.mockImplementation(() => {\n      /* ... */\n    });\n  },\n});\n\nexport default preview;\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-navigation-override-in-story.md",
    "content": "```js filename=\"NavigationBasedComponent.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport NavigationBasedComponent from './NavigationBasedComponent';\n\nexport default {\n  component: NavigationBasedComponent,\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n    },\n  },\n};\n\n// Interact with the links to see the route change events in the Actions panel.\nexport const Example = {\n  parameters: {\n    nextjs: {\n      navigation: {\n        pathname: '/profile',\n        query: {\n          user: '1',\n        },\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"NavigationBasedComponent.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with nextjs or nextjs-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport NavigationBasedComponent from './NavigationBasedComponent';\n\nconst meta = {\n  component: NavigationBasedComponent,\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n    },\n  },\n} satisfies Meta<typeof NavigationBasedComponent>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n// Interact with the links to see the route change events in the Actions panel.\nexport const Example: Story = {\n  parameters: {\n    nextjs: {\n      navigation: {\n        pathname: '/profile',\n        query: {\n          user: '1',\n        },\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"NavigationBasedComponent.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport NavigationBasedComponent from './NavigationBasedComponent';\n\nconst meta = preview.meta({\n  component: NavigationBasedComponent,\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n    },\n  },\n});\n\n// Interact with the links to see the route change events in the Actions panel.\nexport const Example = meta.story({\n  parameters: {\n    nextjs: {\n      navigation: {\n        pathname: '/profile',\n        query: {\n          user: '1',\n        },\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"NavigationBasedComponent.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport NavigationBasedComponent from './NavigationBasedComponent';\n\nconst meta = preview.meta({\n  component: NavigationBasedComponent,\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n    },\n  },\n});\n\n// Interact with the links to see the route change events in the Actions panel.\nexport const Example = meta.story({\n  parameters: {\n    nextjs: {\n      navigation: {\n        pathname: '/profile',\n        query: {\n          user: '1',\n        },\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-navigation-segments-for-use-params-override-in-meta.md",
    "content": "```js filename=\"NavigationBasedComponent.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport NavigationBasedComponent from './NavigationBasedComponent';\n\nexport default {\n  component: NavigationBasedComponent,\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        segments: [\n          ['slug', 'hello'],\n          ['framework', 'nextjs'],\n        ],\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"NavigationBasedComponent.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with nextjs or nextjs-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport NavigationBasedComponent from './NavigationBasedComponent';\n\nconst meta = {\n  component: NavigationBasedComponent,\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        segments: [\n          ['slug', 'hello'],\n          ['framework', 'nextjs'],\n        ],\n      },\n    },\n  },\n} satisfies Meta<typeof NavigationBasedComponent>;\nexport default meta;\n```\n\n```ts filename=\"NavigationBasedComponent.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport NavigationBasedComponent from './NavigationBasedComponent';\n\nconst meta = preview.meta({\n  component: NavigationBasedComponent,\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        segments: [\n          ['slug', 'hello'],\n          ['framework', 'nextjs'],\n        ],\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"NavigationBasedComponent.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport NavigationBasedComponent from './NavigationBasedComponent';\n\nconst meta = preview.meta({\n  component: NavigationBasedComponent,\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        segments: [\n          ['slug', 'hello'],\n          ['framework', 'nextjs'],\n        ],\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-navigation-segments-override-in-meta.md",
    "content": "```js filename=\"NavigationBasedComponent.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport NavigationBasedComponent from './NavigationBasedComponent';\n\nexport default {\n  component: NavigationBasedComponent,\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        segments: ['dashboard', 'analytics'],\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"NavigationBasedComponent.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with nextjs or nextjs-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport NavigationBasedComponent from './NavigationBasedComponent';\n\nconst meta = {\n  component: NavigationBasedComponent,\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        segments: ['dashboard', 'analytics'],\n      },\n    },\n  },\n} satisfies Meta<typeof NavigationBasedComponent>;\nexport default meta;\n```\n\n```ts filename=\"NavigationBasedComponent.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport NavigationBasedComponent from './NavigationBasedComponent';\n\nconst meta = preview.meta({\n  component: NavigationBasedComponent,\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        segments: ['dashboard', 'analytics'],\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"NavigationBasedComponent.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport NavigationBasedComponent from './NavigationBasedComponent';\n\nconst meta = preview.meta({\n  component: NavigationBasedComponent,\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        segments: ['dashboard', 'analytics'],\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-remove-addons.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // ...\n  addons: [\n    // ...\n    // 👇 These can both be removed\n    // 'storybook-addon-next',\n    // 'storybook-addon-next-router',\n  ],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with nextjs or nextjs-vite\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  // ...\n  addons: [\n    // ...\n    // 👇 These can both be removed\n    // 'storybook-addon-next',\n    // 'storybook-addon-next-router',\n  ],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with nextjs or nextjs-vite\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // ...\n  addons: [\n    // ...\n    // 👇 These can both be removed\n    // 'storybook-addon-next',\n    // 'storybook-addon-next-router',\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with nextjs or nextjs-vite\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // ...\n  addons: [\n    // ...\n    // 👇 These can both be removed\n    // 'storybook-addon-next',\n    // 'storybook-addon-next-router',\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-router-mock.md",
    "content": "```js filename=\"MyForm.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { expect } from 'storybook/test';\n\n// Replace your-framework with nextjs or nextjs-vite\nimport { getRouter } from '@storybook/your-framework/router';\n\nimport MyForm from './my-form';\n\nexport default {\n  component: MyForm,\n};\n\nexport const GoBack = {\n  async play({ canvas, userEvent }) {\n    const backBtn = await canvas.findByText('Go back');\n\n    await userEvent.click(backBtn);\n    // 👇 Assert that your component called back()\n    await expect(getRouter().back).toHaveBeenCalled();\n  },\n};\n```\n\n```ts filename=\"MyForm.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with nextjs or nextjs-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { expect } from 'storybook/test';\n\n// 👇 Must include the `.mock` portion of filename to have mocks typed correctly\nimport { getRouter } from '@storybook/your-framework/router.mock';\n\nimport MyForm from './my-form';\n\nconst meta = {\n  component: MyForm,\n} satisfies Meta<typeof MyForm>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const GoBack: Story = {\n  async play({ canvas, userEvent }) {\n    const backBtn = await canvas.findByText('Go back');\n\n    await userEvent.click(backBtn);\n    // 👇 Assert that your component called back()\n    await expect(getRouter().back).toHaveBeenCalled();\n  },\n};\n```\n\n```ts filename=\"MyForm.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\n/*\n * Replace your-framework with nextjs or nextjs-vite\n * 👇 Must include the `.mock` portion of filename to have mocks typed correctly\n */\nimport { getRouter } from '@storybook/your-framework/router.mock';\n\nimport preview from '../.storybook/preview';\n\nimport MyForm from './my-form';\n\nconst meta = preview.meta({\n  component: MyForm,\n});\n\nexport const GoBack = meta.story({\n  async play({ canvas, userEvent }) {\n    const backBtn = await canvas.findByText('Go back');\n\n    await userEvent.click(backBtn);\n    // 👇 Assert that your component called back()\n    await expect(getRouter().back).toHaveBeenCalled();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyForm.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\n// Replace your-framework with nextjs or nextjs-vite\nimport { getRouter } from '@storybook/your-framework/router';\n\nimport preview from '../.storybook/preview';\n\nimport MyForm from './my-form';\n\nconst meta = preview.meta({\n  component: MyForm,\n});\n\nexport const GoBack = meta.story({\n  async play({ canvas, userEvent }) {\n    const backBtn = await canvas.findByText('Go back');\n\n    await userEvent.click(backBtn);\n    // 👇 Assert that your component called back()\n    await expect(getRouter().back).toHaveBeenCalled();\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-router-override-in-preview.md",
    "content": "```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with nextjs or nextjs-vite\nimport { getRouter } from '@storybook/your-framework/router';\n\nexport default {\n  parameters: {\n    nextjs: {\n      // 👇 Override the default router properties\n      router: {\n        basePath: '/app/',\n      },\n    },\n  },\n  async beforeEach() {\n    // 👇 Manipulate the default router method mocks\n    getRouter().push.mockImplementation(() => {\n      /* ... */\n    });\n  },\n};\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\n// Replace your-framework with nextjs or nextjs-vite\nimport type { Preview } from '@storybook/your-framework';\n\n// 👇 Must include the `.mock` portion of filename to have mocks typed correctly\nimport { getRouter } from \"@storybook/your-framework/router.mock\";\n\nconst preview: Preview = {\n  parameters: {\n    nextjs: {\n      // 👇 Override the default router properties\n      router: {\n        basePath: '/app/',\n      },\n    },\n  },\n  async beforeEach() {\n    // 👇 Manipulate the default router method mocks\n    getRouter().push.mockImplementation(() => {\n      /* ... */\n    });\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with nextjs or nextjs-vite\nimport { definePreview } from '@storybook/your-framework';\n\n// 👇 Must include the `.mock` portion of filename to have mocks typed correctly\nimport { getRouter } from '@storybook/your-framework/router.mock';\n\nconst preview = definePreview({\n  parameters: {\n    nextjs: {\n      // 👇 Override the default router properties\n      router: {\n        basePath: '/app/',\n      },\n    },\n  },\n  async beforeEach() {\n    // 👇 Manipulate the default router method mocks\n    getRouter().push.mockImplementation(() => {\n      /* ... */\n    });\n  },\n});\n\nexport default preview;\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with nextjs or nextjs-vite\nimport { definePreview } from '@storybook/your-framework';\n\n// 👇 Must include the `.mock` portion of filename to have mocks typed correctly\nimport { getRouter } from '@storybook/your-framework/router.mock';\n\nconst preview = definePreview({\n  parameters: {\n    nextjs: {\n      // 👇 Override the default router properties\n      router: {\n        basePath: '/app/',\n      },\n    },\n  },\n  async beforeEach() {\n    // 👇 Manipulate the default router method mocks\n    getRouter().push.mockImplementation(() => {\n      /* ... */\n    });\n  },\n});\n\nexport default preview;\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-router-override-in-story.md",
    "content": "```js filename=\"RouterBasedComponent.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport RouterBasedComponent from './RouterBasedComponent';\n\nexport default {\n  component: RouterBasedComponent,\n};\n\n// Interact with the links to see the route change events in the Actions panel.\nexport const Example = {\n  parameters: {\n    nextjs: {\n      router: {\n        pathname: '/profile/[id]',\n        asPath: '/profile/1',\n        query: {\n          id: '1',\n        },\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"RouterBasedComponent.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with nextjs or nextjs-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport RouterBasedComponent from './RouterBasedComponent';\n\nconst meta = {\n  component: RouterBasedComponent,\n} satisfies Meta<typeof RouterBasedComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// Interact with the links to see the route change events in the Actions panel.\nexport const Example: Story = {\n  parameters: {\n    nextjs: {\n      router: {\n        pathname: '/profile/[id]',\n        asPath: '/profile/1',\n        query: {\n          id: '1',\n        },\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"RouterBasedComponent.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport RouterBasedComponent from './RouterBasedComponent';\n\nconst meta = preview.meta({\n  component: RouterBasedComponent,\n});\n\n// Interact with the links to see the route change events in the Actions panel.\nexport const Example = meta.story({\n  parameters: {\n    nextjs: {\n      router: {\n        pathname: '/profile/[id]',\n        asPath: '/profile/1',\n        query: {\n          id: '1',\n        },\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"RouterBasedComponent.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport RouterBasedComponent from './RouterBasedComponent';\n\nconst meta = preview.meta({\n  component: RouterBasedComponent,\n});\n\n// Interact with the links to see the route change events in the Actions panel.\nexport const Example = meta.story({\n  parameters: {\n    nextjs: {\n      router: {\n        pathname: '/profile/[id]',\n        asPath: '/profile/1',\n        query: {\n          id: '1',\n        },\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-styling-css-modules.md",
    "content": "```js filename=\"src/components/Button.js\" renderer=\"react\" language=\"js\"\n// This import will work in Storybook\nimport styles from './Button.module.css';\n// Sass/Scss modules are also supported\n// import styles from './Button.module.scss'\n// import styles from './Button.module.sass'\n\nexport function Button() {\n  return (\n    <button type=\"button\" className={styles.error}>\n      Destroy\n    </button>\n  );\n}\n```\n\n```ts filename=\"src/components/Button.ts\" renderer=\"react\" language=\"ts\"\n// This import will work in Storybook\nimport styles from './Button.module.css';\n// Sass/Scss modules are also supported\n// import styles from './Button.module.scss'\n// import styles from './Button.module.sass'\n\nexport function Button() {\n  return (\n    <button type=\"button\" className={styles.error}>\n      Destroy\n    </button>\n  );\n}\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-styling-sass-config.md",
    "content": "```js filename=\"next.config.js\" language=\"js\" renderer=\"react\"\nimport path from 'node:path';\n\nexport default {\n  // Any options here are included in Sass compilation for your stories\n  sassOptions: {\n    includePaths: [path.join(process.cwd(), 'styles')],\n  },\n};\n```\n\n```ts filename=\"next.config.ts\" language=\"ts\" renderer=\"react\"\nimport type { NextConfig } from 'next';\n\nimport * as path from 'node:path';\n\nconst config: NextConfig = {\n  // Any options here are included in Sass compilation for your stories\n  sassOptions: {\n    includePaths: [path.join(process.cwd(), 'styles')],\n  },\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-styling-sass-preview.md",
    "content": "```js filename=\".storybook/preview.js\" language=\"js\" renderer=\"react\"\nimport '../styles/globals.scss';\n```\n\n```ts filename=\".storybook/preview.ts\" language=\"ts\" renderer=\"react\"\nimport '../styles/globals.scss';\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-styling-styled-jsx-component.md",
    "content": "```js filename=\"src/components/HelloWorld.js\" renderer=\"react\" language=\"js\"\n// This will work in Storybook\nfunction HelloWorld() {\n  return (\n    <div>\n      Hello world\n      <p>scoped!</p>\n      <style jsx>{`\n        p {\n          color: blue;\n        }\n        div {\n          background: red;\n        }\n        @media (max-width: 600px) {\n          div {\n            background: blue;\n          }\n        }\n      `}</style>\n      <style global jsx>{`\n        body {\n          background: black;\n        }\n      `}</style>\n    </div>\n  );\n}\n\nexport default HelloWorld;\n```\n\n```ts filename=\"src/components/HelloWorld.ts\" renderer=\"react\" language=\"ts\"\n// This will work in Storybook\nfunction HelloWorld() {\n  return (\n    <div>\n      Hello world\n      <p>scoped!</p>\n      <style jsx>{`\n        p {\n          color: blue;\n        }\n        div {\n          background: red;\n        }\n        @media (max-width: 600px) {\n          div {\n            background: blue;\n          }\n        }\n      `}</style>\n      <style global jsx>{`\n        body {\n          background: black;\n        }\n      `}</style>\n    </div>\n  );\n}\n\nexport default HelloWorld;\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-styling-tailwind.md",
    "content": "```js filename=\".storybook/preview.js\" language=\"js\" renderer=\"react\"\nimport '../app/globals.css';\n```\n\n```ts filename=\".storybook/preview.ts\" language=\"ts\" renderer=\"react\"\nimport '../app/globals.css';\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-vite-add-framework.md",
    "content": "```diff filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // ...\n-  framework: '@storybook/react-webpack5',\n+  framework: '@storybook/nextjs-vite',\n};\n```\n\n```diff filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n- import type { StorybookConfig } from '@storybook/your-previous-framework';\n+ import type { StorybookConfig } from '@storybook/nextjs-vite';\n\nconst config: StorybookConfig = {\n  // ...\n-  framework: '@storybook/react-webpack5',\n+  framework: '@storybook/nextjs-vite',\n};\n\nexport default config;\n```\n\n```diff filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n- import { defineMain } from '@storybook/your-previous-framework/node';\n+ import { defineMain } from '@storybook/nextjs-vite/node';\n\nexport default defineMain({\n  // ...\n-  framework: '@storybook/react-webpack5',\n+  framework: '@storybook/nextjs-vite',\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```diff filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n- import { defineMain } from '@storybook/your-previous-framework/node';\n+ import { defineMain } from '@storybook/nextjs-vite/node';\n\nexport default defineMain({\n  // ...\n-  framework: '@storybook/react-webpack5',\n+  framework: '@storybook/nextjs-vite',\n});\n```\n"
  },
  {
    "path": "docs/_snippets/nextjs-vite-install.md",
    "content": "```shell renderer=\"react\" language=\"js\" packageManager=\"npm\"\nnpm install --save-dev @storybook/nextjs-vite\n```\n\n```shell renderer=\"react\" language=\"js\" packageManager=\"pnpm\"\npnpm add --save-dev @storybook/nextjs-vite\n```\n\n```shell renderer=\"react\" language=\"js\" packageManager=\"yarn\"\nyarn add --dev @storybook/nextjs-vite\n```\n"
  },
  {
    "path": "docs/_snippets/other-foo-bar-story.md",
    "content": "```ts filename=\"FooBar.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Foo } from './foo.component';\n\nconst meta: Meta<Foo> = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'OtherFoo/Bar',\n  component: Foo,\n  id: 'Foo/Bar', // Or 'foo-bar' if you prefer\n};\n\nexport default meta;\ntype Story = StoryObj<Foo>;\n\nexport const Baz: Story = {\n  name: 'Insert name here',\n};\n```\n\n```ts filename=\"FooBar.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Foo } from './foo.component';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'OtherFoo/Bar',\n  component: Foo,\n  id: 'Foo/Bar', // Or 'foo-bar' if you prefer\n});\n\nexport const Baz = meta.story({\n  name: 'Insert name here',\n});\n```\n\n```js filename=\"FooBar.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Foo } from './Foo';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'OtherFoo/Bar',\n  component: Foo,\n  id: 'Foo/Bar', // Or 'foo-bar' if you prefer\n};\n\nexport const Baz = {\n  name: 'Insert name here',\n};\n```\n\n```ts filename=\"FooBar.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Foo } from './Foo';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'OtherFoo/Bar',\n  component: Foo,\n  id: 'Foo/Bar', // Or 'foo-bar' if you prefer\n} satisfies Meta<typeof Foo>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Baz: Story = {\n  name: 'Insert name here',\n};\n```\n\n```js filename=\"FooBar.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  title: 'OtherFoo/Bar',\n  component: 'demo-foo',\n  id: 'Foo/Bar', // Or 'foo-bar' if you prefer\n};\n\nexport const Baz = {\n  name: 'Insert name here',\n};\n```\n\n```ts filename=\"FooBar.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  title: 'OtherFoo/Bar',\n  component: 'demo-foo',\n  id: 'Foo/Bar', // Or 'foo-bar' if you prefer\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Baz: Story = {\n  name: 'Insert name here',\n};\n```\n\n```ts filename=\"FooBar.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  title: 'OtherFoo/Bar',\n  component: 'demo-foo',\n  id: 'Foo/Bar', // Or 'foo-bar' if you prefer\n});\n\nexport const Baz = meta.story({\n  name: 'Insert name here',\n});\n```\n\n```js filename=\"FooBar.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  title: 'OtherFoo/Bar',\n  component: 'demo-foo',\n  id: 'Foo/Bar', // Or 'foo-bar' if you prefer\n});\n\nexport const Baz = meta.story({\n  name: 'Insert name here',\n});\n```\n\n```ts filename=\"FooBar.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Foo } from './Foo';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'OtherFoo/Bar',\n  component: Foo,\n  id: 'Foo/Bar', // Or 'foo-bar' if you prefer\n});\n\nexport const Baz = meta.story({\n  name: 'Insert name here',\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"FooBar.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Foo } from './Foo';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'OtherFoo/Bar',\n  component: Foo,\n  // Or 'foo-bar' if you prefer\n  id: 'Foo/Bar',\n});\n\nexport const Baz = meta.story({\n  name: 'Insert name here',\n});\n```\n\n```ts filename=\"FooBar.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Foo from './Foo.vue';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'OtherFoo/Bar',\n  component: Foo,\n  id: 'Foo/Bar', // Or 'foo-bar' if you prefer\n});\n\nexport const Baz = meta.story({\n  name: 'Insert name here',\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"FooBar.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Foo from './Foo.vue';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'OtherFoo/Bar',\n  component: Foo,\n  // Or 'foo-bar' if you prefer\n  id: 'Foo/Bar',\n});\n\nexport const Baz = meta.story({\n  name: 'Insert name here',\n});\n```\n"
  },
  {
    "path": "docs/_snippets/override-compose-story-test.md",
    "content": "```js filename=\"Form.test.js|ts\" renderer=\"common\" language=\"js\" tabTitle=\"compose-stories\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\nimport * as stories from './LoginForm.stories';\n\nconst { ValidForm } = composeStories(stories, {\n  decorators: [\n    // Decorators defined here will be added to all composed stories from this function\n  ],\n  globalTypes: {\n    // Override globals for all composed stories from this function\n  },\n  parameters: {\n    // Override parameters for all composed stories from this function\n  },\n});\n```\n\n```js filename=\"Form.test.js|ts\" renderer=\"common\" language=\"js\" tabTitle=\"compose-story\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\nimport Meta, { ValidForm as ValidFormStory } from './LoginForm.stories';\n\nconst ValidForm = composeStory(ValidFormStory, Meta, {\n  decorators: [\n    // Decorators defined here will be added to this story\n  ],\n  globalTypes: {\n    // Override globals for this story\n  },\n  parameters: {\n    // Override parameters for this story\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/page-story-args-within-story.md",
    "content": "```jsx filename=\"my-component/component.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { useArgs } from 'storybook/preview-api';\n\nimport { Checkbox } from './checkbox';\n\nexport default {\n  title: 'Inputs/Checkbox',\n  component: Checkbox,\n};\n\nexport const Example = {\n  args: {\n    isChecked: false,\n    label: 'Try Me!',\n  },\n  /**\n   * 👇 To avoid linting issues, it is recommended to use a function with a capitalized name.\n   * If you are not concerned with linting, you may use an arrow function.\n   */\n  render: function Render(args) {\n    const [{ isChecked }, updateArgs] = useArgs();\n\n    function onChange() {\n      updateArgs({ isChecked: !isChecked });\n    }\n\n    return <Checkbox {...args} onChange={onChange} isChecked={isChecked} />;\n  },\n};\n```\n\n```tsx filename=\"my-component/component.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\nimport { useArgs } from 'storybook/preview-api';\n\nimport { Checkbox } from './checkbox';\n\nconst meta = {\n  title: 'Inputs/Checkbox',\n  component: Checkbox,\n} satisfies Meta<typeof Checkbox>;\nexport default meta;\n\ntype Story = StoryObj<typeof Checkbox>;\n\nexport const Example = {\n  args: {\n    isChecked: false,\n    label: 'Try Me!',\n  },\n  /**\n   * 👇 To avoid linting issues, it is recommended to use a function with a capitalized name.\n   * If you are not concerned with linting, you may use an arrow function.\n   */\n  render: function Render(args) {\n    const [{ isChecked }, updateArgs] = useArgs();\n\n    function onChange() {\n      updateArgs({ isChecked: !isChecked });\n    }\n\n    return <Checkbox {...args} onChange={onChange} isChecked={isChecked} />;\n  },\n} satisfies Story;\n```\n\n```tsx filename=\"my-component/component.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { useArgs } from 'storybook/preview-api';\n\nimport preview from '../.storybook/preview';\n\nimport { Checkbox } from './checkbox';\n\nconst meta = preview.meta({\n  title: 'Inputs/Checkbox',\n  component: Checkbox,\n});\n\nexport const Example = meta.story({\n  args: {\n    isChecked: false,\n    label: 'Try Me!',\n  },\n  /**\n   * 👇 To avoid linting issues, it is recommended to use a function with a capitalized name.\n   * If you are not concerned with linting, you may use an arrow function.\n   */\n  render: function Render(args) {\n    const [{ isChecked }, updateArgs] = useArgs();\n\n    function onChange() {\n      updateArgs({ isChecked: !isChecked });\n    }\n\n    return <Checkbox {...args} onChange={onChange} isChecked={isChecked} />;\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"my-component/component.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { useArgs } from 'storybook/preview-api';\n\nimport preview from '../.storybook/preview';\n\nimport { Checkbox } from './checkbox';\n\nconst meta = preview.meta({\n  title: 'Inputs/Checkbox',\n  component: Checkbox,\n});\n\nexport const Example = meta.story({\n  args: {\n    isChecked: false,\n    label: 'Try Me!',\n  },\n  /**\n   * 👇 To avoid linting issues, it is recommended to use a function with a capitalized name.\n   * If you are not concerned with linting, you may use an arrow function.\n   */\n  render: function Render(args) {\n    const [{ isChecked }, updateArgs] = useArgs();\n\n    function onChange() {\n      updateArgs({ isChecked: !isChecked });\n    }\n\n    return <Checkbox {...args} onChange={onChange} isChecked={isChecked} />;\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/page-story-slots.md",
    "content": "```ts filename=\"Page.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, type StoryObj, argsToTemplate } from '@storybook/angular';\n\nimport { Page } from './page.component';\n\ntype PagePropsAndCustomArgs = Page & { footer?: string };\n\nconst meta: Meta<PagePropsAndCustomArgs> = {\n  component: Page,\n  render: ({ footer, ...args }) => ({\n    props: args,\n    template: `\n      <storybook-page ${argsToTemplate(args)}>\n        <ng-container footer>${footer}</ng-container>\n      </storybook-page>`,\n  }),\n};\nexport default meta;\n\ntype Story = StoryObj<PagePropsAndCustomArgs>;\n\nexport const CustomFooter: Story = {\n  args: {\n    footer: 'Built with Storybook',\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { argsToTemplate } from '@storybook/angular';\n\nimport preview from '../.storybook/preview';\n\nimport { Page } from './page.component';\n\ntype PagePropsAndCustomArgs = Page & { footer?: string };\n\nconst meta = preview.type<{ args: PagePropsAndCustomArgs }>().meta({\n  component: Page,\n  render: ({ footer, ...args }) => ({\n    props: args,\n    template: `\n      <storybook-page ${argsToTemplate(args)}>\n        <ng-container footer>${footer}</ng-container>\n      </storybook-page>`,\n  }),\n});\n\nexport const CustomFooter = meta.story({\n  args: {\n    footer: 'Built with Storybook',\n  },\n});\n```\n\n```jsx filename=\"Page.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Page } from './Page';\n\nexport default {\n  component: Page,\n  render: ({ footer, ...args }) => (\n    <Page {...args}>\n      <footer>{footer}</footer>\n    </Page>\n  ),\n};\n\nexport const CustomFooter = {\n  args: {\n    footer: 'Built with Storybook',\n  },\n};\n```\n\n```tsx filename=\"Page.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Page } from './Page';\n\ntype PagePropsAndCustomArgs = React.ComponentProps<typeof Page> & { footer?: string };\n\nconst meta = {\n  component: Page,\n  render: ({ footer, ...args }) => (\n    <Page {...args}>\n      <footer>{footer}</footer>\n    </Page>\n  ),\n} satisfies Meta<PagePropsAndCustomArgs>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const CustomFooter = {\n  args: {\n    footer: 'Built with Storybook',\n  },\n} satisfies Story;\n```\n\n```jsx filename=\"Page.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { Page } from './Page';\n\nexport default {\n  component: Page,\n  render: ({ footer, ...args }) => (\n    <Page {...args}>\n      <footer>{footer}</footer>\n    </Page>\n  ),\n};\n\nexport const CustomFooter = {\n  args: {\n    footer: 'Built with Storybook',\n  },\n};\n```\n\n```tsx filename=\"Page.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { ComponentProps } from 'solid-js';\n\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { Page } from './Page';\n\ntype PagePropsAndCustomArgs = ComponentProps<typeof Page> & { footer?: string };\n\nconst meta = {\n  component: Page,\n  render: ({ footer, ...args }) => (\n    <Page {...args}>\n      <footer>{footer}</footer>\n    </Page>\n  ),\n} satisfies Meta<PagePropsAndCustomArgs>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const CustomFooter = {\n  args: {\n    footer: 'Built with Storybook',\n  },\n} satisfies Story;\n```\n\n```svelte filename=\"Page.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Page from './Page.svelte';\n\n  const { Story } = defineMeta({\n    component: Page\n  });\n</script>\n\n<Story name=\"CustomFooter\" args={{ footer: 'Built with Storybook' }}>\n  {#snippet template(args)}\n    <Page {...args} >\n      <footer>{args.footer}</footer>\n    </Page>\n  {/snippet}\n</Story>\n```\n\n```svelte filename=\"Page.stories.svelte\" renderer=\"svelte\" language=\"ts\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Page from './Page.svelte';\n\n  const { Story } = defineMeta({\n    component: Page\n  });\n</script>\n\n<Story name=\"CustomFooter\" args={{ footer: 'Built with Storybook' }}>\n  {#snippet template(args)}\n    <Page {...args} >\n      <footer>{args.footer}</footer>\n    </Page>\n  {/snippet}\n</Story>\n```\n\n```js filename=\"Page.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport Page from './Page.vue';\n\nexport default {\n  component: Page,\n  render: (args) => ({\n    components: { Page },\n    setup() {\n      return { args };\n    },\n    template: `\n      <page v-bind=\"args\">\n        <template v-slot:footer>\n          <footer v-if=\"args.footer\" v-html=\"args.footer\" />\n        </template>\n      </page>\n    `,\n  }),\n};\n\nexport const CustomFooter = {\n  args: {\n    footer: 'Built with Storybook',\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { ComponentPropsAndSlots, Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport Page from './Page.vue';\n\ntype PagePropsAndCustomArgs = ComponentPropsAndSlots<typeof Page> & { footer?: string };\n\nconst meta = {\n  component: Page,\n  render: (args) => ({\n    components: { Page },\n    setup() {\n      return { args };\n    },\n    template: `\n      <page v-bind=\"args\">\n        <template v-slot:footer>\n          <footer v-if=\"args.footer\" v-html=\"args.footer\" />\n        </template>\n      </page>\n    `,\n  }),\n} satisfies Meta<PagePropsAndCustomArgs>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary = {\n  args: {\n    footer: 'Built with Storybook',\n  },\n} satisfies Story;\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport type { ComponentPropsAndSlots } from '@storybook/vue3-vite';\n\nimport preview from '../.storybook/preview';\n\nimport Page from './Page.vue';\n\ntype PagePropsAndCustomArgs = ComponentPropsAndSlots<typeof Page> & { footer?: string };\n\nconst meta = preview.type<{ args: PagePropsAndCustomArgs }>().meta({\n  component: Page,\n  render: (args) => ({\n    components: { Page },\n    setup() {\n      return { args };\n    },\n    template: `\n      <page v-bind=\"args\">\n        <template v-slot:footer>\n          <footer v-if=\"args.footer\" v-html=\"args.footer\" />\n        </template>\n      </page>\n    `,\n  }),\n});\n\nexport const Primary = meta.story({\n  args: {\n    footer: 'Built with Storybook',\n  },\n});\n```\n\n```js filename=\"Page.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Page from './Page.vue';\n\nconst meta = preview.meta({\n  component: Page,\n  render: (args) => ({\n    components: { Page },\n    setup() {\n      return { args };\n    },\n    template: `\n      <page v-bind=\"args\">\n        <template v-slot:footer>\n          <footer v-if=\"args.footer\" v-html=\"args.footer\" />\n        </template>\n      </page>\n    `,\n  }),\n});\n\nexport const CustomFooter = meta.story({\n  args: {\n    footer: 'Built with Storybook',\n  },\n});\n```\n\n```js filename=\"Page.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nexport default {\n  title: 'Page',\n  component: 'demo-page',\n  render: ({ footer }) => html`\n    <demo-page>\n      <footer>${footer}</footer>\n    </demo-page>\n  `,\n};\n\nexport const CustomFooter = {\n  args: {\n    footer: 'Built with Storybook',\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  title: 'Page',\n  component: 'demo-page',\n  render: ({ footer }) => html`\n    <demo-page>\n      <footer>${footer}</footer>\n    </demo-page>\n  `,\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const CustomFooter: Story = {\n  args: {\n    footer: 'Built with Storybook',\n  },\n};\n```\n\n```js filename=\"Page.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  title: 'Page',\n  component: 'demo-page',\n  render: ({ footer }) => html`\n    <demo-page>\n      <footer>${footer}</footer>\n    </demo-page>\n  `,\n});\n\nexport const CustomFooter = meta.story({\n  args: {\n    footer: 'Built with Storybook',\n  },\n});\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\ntype CustomArgs = { footer?: string };\n\nconst meta = preview.type<{ args: CustomArgs }>()meta({\n  title: 'Page',\n  component: 'demo-page',\n  render: ({ footer }) => html`\n    <demo-page>\n      <footer>${footer}</footer>\n    </demo-page>\n  `,\n});\n\nexport const CustomFooter = meta.story({\n  args: {\n    footer: 'Built with Storybook',\n  },\n});\n```\n\n```tsx filename=\"Page.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Page } from './Page';\n\ntype PagePropsAndCustomArgs = React.ComponentProps<typeof Page> & {\n  footer?: string;\n};\n\nconst meta = preview.type<{ args: PagePropsAndCustomArgs }>().meta({\n  component: Page,\n  render: ({ footer, ...args }) => (\n    <Page {...args}>\n      <footer>{footer}</footer>\n    </Page>\n  ),\n});\n\nexport const CustomFooter = meta.story({\n  args: {\n    footer: 'Built with Storybook',\n  },\n});\n```\n\n```jsx filename=\"Page.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Page } from './Page';\n\nconst meta = preview.meta({\n  component: Page,\n  render: ({ footer, ...args }) => (\n    <Page {...args}>\n      <footer>{footer}</footer>\n    </Page>\n  ),\n});\n\nexport const CustomFooter = meta.story({\n  args: {\n    footer: 'Built with Storybook',\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/page-story-with-args-composition.md",
    "content": "```ts filename=\"YourPage.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { DocumentScreen } from './your-page.component';\n\n// 👇 Imports the required stories\nimport * as PageLayout from './PageLayout.stories';\nimport * as DocumentHeader from './DocumentHeader.stories';\nimport * as DocumentList from './DocumentList.stories';\n\nconst meta: Meta<DocumentScreen> = {\n  component: DocumentScreen,\n};\n\nexport default meta;\ntype Story = StoryObj<DocumentScreen>;\n\nexport const Simple: Story = {\n  args: {\n    user: PageLayout.Simple.args.user,\n    document: DocumentHeader.Simple.args.document,\n    subdocuments: DocumentList.Simple.args.documents,\n  },\n};\n```\n\n```ts filename=\"YourPage.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { DocumentScreen } from './your-page.component';\n\n// 👇 Imports the required stories\nimport * as PageLayout from './PageLayout.stories';\nimport * as DocumentHeader from './DocumentHeader.stories';\nimport * as DocumentList from './DocumentList.stories';\n\nconst meta = preview.meta({\n  component: DocumentScreen,\n});\n\nexport const Simple = meta.story({\n  args: {\n    user: PageLayout.Simple.input.args.user,\n    document: DocumentHeader.Simple.input.args.document,\n    subdocuments: DocumentList.Simple.input.args.documents,\n  },\n});\n```\n\n```svelte filename=\"YourPage.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import DocumentScreen from './YourPage.svelte';\n\n  // 👇 Imports the required stories\n  import * as PageLayout from './PageLayout.stories.svelte';\n  import * as DocumentHeader from './DocumentHeader.stories.svelte';\n  import * as DocumentList from './DocumentList.stories.svelte';\n\n  const { Story } = defineMeta({\n    component: DocumentScreen,\n  });\n</script>\n\n<Story\n  name=\"Simple\"\n  args={{\n    user: PageLayout.Simple.args.user,\n    document: DocumentHeader.Simple.args.document,\n    subdocuments: DocumentList.Simple.args.documents,\n  }}\n/>\n```\n\n```js filename=\"YourPage.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport DocumentScreen from './YourPage.svelte';\n\n// 👇 Imports the required stories\nimport * as PageLayout from './PageLayout.stories';\nimport * as DocumentHeader from './DocumentHeader.stories';\nimport * as DocumentList from './DocumentList.stories';\n\nexport default {\n  component: DocumentScreen,\n};\n\nexport const Simple = {\n  args: {\n    user: PageLayout.Simple.args.user,\n    document: DocumentHeader.Simple.args.document,\n    subdocuments: DocumentList.Simple.args.documents,\n  },\n};\n```\n\n```js filename=\"YourPage.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { DocumentScreen } from './YourPage';\n\n// 👇 Imports the required stories\nimport * as PageLayout from './PageLayout.stories';\nimport * as DocumentHeader from './DocumentHeader.stories';\nimport * as DocumentList from './DocumentList.stories';\n\nexport default {\n  component: DocumentScreen,\n};\n\nexport const Simple = {\n  args: {\n    user: PageLayout.Simple.args.user,\n    document: DocumentHeader.Simple.args.document,\n    subdocuments: DocumentList.Simple.args.documents,\n  },\n};\n```\n\n```svelte filename=\"YourPage.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import DocumentScreen from './YourPage.svelte';\n\n  // 👇 Imports the required stories\n  import * as PageLayout from './PageLayout.stories.svelte';\n  import * as DocumentHeader from './DocumentHeader.stories.svelte';\n  import * as DocumentList from './DocumentList.stories.svelte';\n\n  const { Story } = defineMeta({\n    component: DocumentScreen,\n  });\n</script>\n\n<Story\n  name=\"Simple\"\n  args={{\n    user: PageLayout.Simple.args.user,\n    document: DocumentHeader.Simple.args.document,\n    subdocuments: DocumentList.Simple.args.documents,\n  }}\n/>\n```\n\n```ts filename=\"YourPage.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport DocumentScreen from './YourPage.svelte';\n\n// 👇 Imports the required stories\nimport * as PageLayout from './PageLayout.stories';\nimport * as DocumentHeader from './DocumentHeader.stories';\nimport * as DocumentList from './DocumentList.stories';\n\nconst meta = {\n  component: DocumentScreen,\n} satisfies Meta<typeof DocumentScreen>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Simple: Story = {\n  args: {\n    user: PageLayout.Simple.args.user,\n    document: DocumentHeader.Simple.args.document,\n    subdocuments: DocumentList.Simple.args.documents,\n  },\n};\n```\n\n```ts filename=\"YourPage.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { DocumentScreen } from './YourPage';\n\n// 👇 Imports the required stories\nimport * as PageLayout from './PageLayout.stories';\nimport * as DocumentHeader from './DocumentHeader.stories';\nimport * as DocumentList from './DocumentList.stories';\n\nconst meta = {\n  component: DocumentScreen,\n} satisfies Meta<typeof DocumentScreen>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Simple: Story = {\n  args: {\n    user: PageLayout.Simple.args.user,\n    document: DocumentHeader.Simple.args.document,\n    subdocuments: DocumentList.Simple.args.documents,\n  },\n};\n```\n\n```js filename=\"YourPage.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\n// 👇 Imports the required stories\nimport * as PageLayout from './PageLayout.stories';\nimport * as DocumentHeader from './DocumentHeader.stories';\nimport * as DocumentList from './DocumentList.stories';\n\nexport default {\n  component: 'demo-document-screen',\n};\n\nexport const Simple = {\n  args: {\n    user: PageLayout.Simple.args.user,\n    document: DocumentHeader.Simple.args.document,\n    subdocuments: DocumentList.Simple.args.documents,\n  },\n};\n```\n\n```ts filename=\"YourPage.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\n// 👇 Imports the required stories\nimport PageLayout from './PageLayout.stories';\nimport DocumentHeader from './DocumentHeader.stories';\nimport DocumentList from './DocumentList.stories';\n\nconst meta: Meta = {\n  component: 'demo-document-screen',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Simple: Story = {\n  args: {\n    user: PageLayout.Simple.args.user,\n    document: DocumentHeader.Simple.args.document,\n    subdocuments: DocumentList.Simple.args.documents,\n  },\n};\n```\n\n```ts filename=\"YourPage.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n// 👇 Imports the required stories\nimport * as PageLayout from './PageLayout.stories';\nimport * as DocumentHeader from './DocumentHeader.stories';\nimport * as DocumentList from './DocumentList.stories';\n\nconst meta = preview.meta({\n  component: 'demo-document-screen',\n});\n\nexport const Simple = meta.story({\n  args: {\n    user: PageLayout.Simple.input.args.user,\n    document: DocumentHeader.Simple.input.args.document,\n    subdocuments: DocumentList.Simple.input.args.documents,\n  },\n});\n```\n\n```js filename=\"YourPage.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n// 👇 Imports the required stories\nimport * as PageLayout from './PageLayout.stories';\nimport * as DocumentHeader from './DocumentHeader.stories';\nimport * as DocumentList from './DocumentList.stories';\n\nconst meta = preview.meta({\n  component: 'demo-document-screen',\n});\n\nexport const Simple = meta.story({\n  args: {\n    user: PageLayout.Simple.input.args.user,\n    document: DocumentHeader.Simple.input.args.document,\n    subdocuments: DocumentList.Simple.input.args.documents,\n  },\n});\n```\n\n```ts filename=\"YourPage.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { DocumentScreen } from './YourPage';\n\n// 👇 Imports the required stories\nimport * as PageLayout from './PageLayout.stories';\nimport * as DocumentHeader from './DocumentHeader.stories';\nimport * as DocumentList from './DocumentList.stories';\n\nconst meta = preview.meta({\n  component: DocumentScreen,\n});\n\nexport const Simple = meta.story({\n  args: {\n    user: PageLayout.Simple.input.args.user,\n    document: DocumentHeader.Simple.input.args.document,\n    subdocuments: DocumentList.Simple.input.args.documents,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"YourPage.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { DocumentScreen } from './YourPage';\n\n// 👇 Imports the required stories\nimport * as PageLayout from './PageLayout.stories';\nimport * as DocumentHeader from './DocumentHeader.stories';\nimport * as DocumentList from './DocumentList.stories';\n\nconst meta = preview.meta({\n  component: DocumentScreen,\n});\n\nexport const Simple = meta.story({\n  args: {\n    user: PageLayout.Simple.input.args.user,\n    document: DocumentHeader.Simple.input.args.document,\n    subdocuments: DocumentList.Simple.input.args.documents,\n  },\n});\n```\n\n```ts filename=\"YourPage.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport DocumentScreen from './YourPage.vue';\n\n// 👇 Imports the required stories\nimport * as PageLayout from './PageLayout.stories';\nimport * as DocumentHeader from './DocumentHeader.stories';\nimport * as DocumentList from './DocumentList.stories';\n\nconst meta = preview.meta({\n  component: DocumentScreen,\n});\n\nexport const Simple = meta.story({\n  args: {\n    user: PageLayout.Simple.input.args.user,\n    document: DocumentHeader.Simple.input.args.document,\n    subdocuments: DocumentList.Simple.input.args.documents,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"YourPage.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport DocumentScreen from './YourPage.vue';\n\n// 👇 Imports the required stories\nimport * as PageLayout from './PageLayout.stories';\nimport * as DocumentHeader from './DocumentHeader.stories';\nimport * as DocumentList from './DocumentList.stories';\n\nconst meta = preview.meta({\n  component: DocumentScreen,\n});\n\nexport const Simple = meta.story({\n  args: {\n    user: PageLayout.Simple.input.args.user,\n    document: DocumentHeader.Simple.input.args.document,\n    subdocuments: DocumentList.Simple.input.args.documents,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/page-story.md",
    "content": "```ts filename=\"Page.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { CommonModule } from '@angular/common';\n\nimport { type Meta, type StoryObj, moduleMetadata } from '@storybook/angular';\n\nimport { Button } from './button.component';\nimport { Header } from './header.component';\nimport { Page } from './page.component';\n\n//👇 Imports all Header stories\nimport * as HeaderStories from './Header.stories';\n\nconst meta: Meta<Page> = {\n  component: Page,\n  decorators: [\n    moduleMetadata({\n      declarations: [Button, Header],\n      imports: [CommonModule],\n    }),\n  ],\n};\n\nexport default meta;\ntype Story = StoryObj<Page>;\n\nexport const LoggedIn: Story = {\n  args: {\n    ...HeaderStories.LoggedIn.args,\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { CommonModule } from '@angular/common';\n\nimport { moduleMetadata } from '@storybook/angular';\n\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\nimport { Header } from './header.component';\nimport { Page } from './page.component';\n\n//👇 Imports all Header stories\nimport * as HeaderStories from './Header.stories';\n\nconst meta = preview.meta({\n  component: Page,\n  decorators: [\n    moduleMetadata({\n      declarations: [Button, Header],\n      imports: [CommonModule],\n    }),\n  ],\n});\n\nexport const LoggedIn = meta.story({\n  args: {\n    ...HeaderStories.LoggedIn.input.args,\n  },\n});\n```\n\n```js filename=\"Page.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Page } from './Page';\n\n//👇 Imports all Header stories\nimport * as HeaderStories from './Header.stories';\n\nexport default {\n  component: Page,\n};\n\nexport const LoggedIn = {\n  args: {\n    ...HeaderStories.LoggedIn.args,\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Page } from './Page';\n\n//👇 Imports all Header stories\nimport * as HeaderStories from './Header.stories';\n\nconst meta = {\n  component: Page,\n} satisfies Meta<typeof Page>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const LoggedIn: Story = {\n  args: {\n    ...HeaderStories.LoggedIn.args,\n  },\n};\n```\n\n```js filename=\"Page.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { Page } from './Page';\n\n//👇 Imports all Header stories\nimport * as HeaderStories from './Header.stories';\n\nexport default {\n  component: Page,\n};\n\nexport const LoggedIn = {\n  args: {\n    ...HeaderStories.LoggedIn.args,\n  },\n};\n```\n\n```tsx filename=\"Page.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { Page } from './Page';\n\n//👇 Imports all Header stories\nimport * as HeaderStories from './Header.stories';\n\nconst meta = {\n  component: Page,\n} satisfies Meta<typeof Page>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const LoggedIn: Story = {\n  args: {\n    ...HeaderStories.LoggedIn.args,\n  },\n};\n```\n\n```svelte filename=\"Page.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Page from './Page.svelte';\n  //👇 Imports all Header stories\n  import * as HeaderStories from './Header.stories.svelte';\n\n  const { Story } = defineMeta({\n    component: Page,\n  });\n</script>\n\n<Story name=\"LoggedIn\" args={{ ...HeaderStories.LoggedIn.args }} />\n```\n\n```js filename=\"Page.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Page from './Page.svelte';\n\n//👇 Imports all Header stories\nimport * as HeaderStories from './Header.stories';\n\nexport default {\n  component: Page,\n};\n\nexport const LoggedIn = {\n  args: {\n    ...HeaderStories.LoggedIn.args,\n  },\n};\n```\n\n```svelte filename=\"Page.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Page from './Page.svelte';\n  //👇 Imports all Header stories\n  import * as HeaderStories from './Header.stories.svelte';\n\n  const { Story } = defineMeta({\n    component: Page,\n  });\n</script>\n\n<Story name=\"LoggedIn\" args={{ ...HeaderStories.LoggedIn.args }} />\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Page from './Page.svelte';\n\n//👇 Imports all Header stories\nimport * as HeaderStories from './Header.stories';\n\nconst meta = {\n  component: Page,\n} satisfies Meta<typeof Page>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const LoggedIn: Story = {\n  args: {\n    ...HeaderStories.LoggedIn.args,\n  },\n};\n```\n\n```js filename=\"Page.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport Page from './Page.vue';\n\n//👇 Imports all Header stories\nimport * as HeaderStories from './Header.stories';\n\nexport default {\n  component: Page,\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const LoggedIn = {\n  render: (args) => ({\n    components: { Page },\n    setup() {\n      return { args };\n    },\n    template: '<page v-bind=\"args\" />',\n  }),\n  args: {\n    ...HeaderStories.LoggedIn.args,\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport Page from './Page.vue';\n\n//👇 Imports all Header stories\nimport * as HeaderStories from './Header.stories';\n\nconst meta = {\n  component: Page,\n} satisfies Meta<typeof Page>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary: Story = {\n  render: (args) => ({\n    components: { Page },\n    setup() {\n      return { args };\n    },\n    template: '<page v-bind=\"args\" />',\n  }),\n  args: {\n    ...HeaderStories.LoggedIn.args,\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Page from './Page.vue';\n\n//👇 Imports all Header stories\nimport * as HeaderStories from './Header.stories';\n\nconst meta = preview.meta({\n  component: Page,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const LoggedIn = meta.story({\n  render: (args) => ({\n    components: { Page },\n    setup() {\n      return { args };\n    },\n    template: '<page v-bind=\"args\" />',\n  }),\n  args: {\n    ...HeaderStories.LoggedIn.input.args,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Page.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Page from './Page.vue';\n\n//👇 Imports all Header stories\nimport * as HeaderStories from './Header.stories';\n\nconst meta = preview.meta({\n  component: Page,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const LoggedIn = meta.story({\n  render: (args) => ({\n    components: { Page },\n    setup() {\n      return { args };\n    },\n    template: '<page v-bind=\"args\" />',\n  }),\n  args: {\n    ...HeaderStories.LoggedIn.input.args,\n  },\n});\n```\n\n```js filename=\"Page.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\n// 👇 Imports all Header stories\nimport * as HeaderStories from './Header.stories';\n\nexport default {\n  component: 'demo-page',\n};\n\nexport const LoggedIn = {\n  args: {\n    ...HeaderStories.LoggedIn.args,\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\n// 👇 Imports all Header stories\nimport * as HeaderStories from './Header.stories';\n\nconst meta: Meta = {\n  component: 'demo-page',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const LoggedIn: Story = {\n  args: {\n    ...HeaderStories.LoggedIn.args,\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n// 👇 Imports all Header stories\nimport * as HeaderStories from './Header.stories';\n\nconst meta = preview.meta({\n  component: 'demo-page',\n});\n\nexport const LoggedIn = meta.story({\n  args: {\n    ...HeaderStories.LoggedIn.input.args,\n  },\n});\n```\n\n```js filename=\"Page.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n// 👇 Imports all Header stories\nimport * as HeaderStories from './Header.stories';\n\nconst meta = preview.meta({\n  component: 'demo-page',\n});\n\nexport const LoggedIn = meta.story({\n  args: {\n    ...HeaderStories.LoggedIn.input.args,\n  },\n});\n```\n\n```ts filename=\"Page.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Page } from './Page';\n\n//👇 Imports all Header stories\nimport * as HeaderStories from './Header.stories';\n\nconst meta = preview.meta({\n  component: Page,\n});\n\nexport const LoggedIn = meta.story({\n  args: {\n    ...HeaderStories.LoggedIn.input.args,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Page.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Page } from './Page';\n\n//👇 Imports all Header stories\nimport * as HeaderStories from './Header.stories';\n\nconst meta = preview.meta({\n  component: Page,\n});\n\nexport const LoggedIn = meta.story({\n  args: {\n    ...HeaderStories.LoggedIn.input.args,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/parameters-docs-source-transform-in-preview.md",
    "content": "```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g., nextjs-vite, vue3-vite, angular, sveltekit, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    docs: {\n      source: {\n        transform: async (source) => {\n          const prettier = await import('prettier/standalone');\n          const prettierPluginBabel = await import('prettier/plugins/babel');\n          const prettierPluginEstree = await import('prettier/plugins/estree');\n\n          return prettier.format(source, {\n            parser: 'babel',\n            plugins: [prettierPluginBabel, prettierPluginEstree],\n          });\n        },\n      },\n    },\n  },\n};\n\nexport default preview;\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    docs: {\n      source: {\n        transform: async (source) => {\n          const prettier = await import('prettier/standalone');\n          const prettierPluginBabel = await import('prettier/plugins/babel');\n          const prettierPluginEstree = await import('prettier/plugins/estree');\n\n          return prettier.format(source, {\n            parser: 'babel',\n            plugins: [prettierPluginBabel, prettierPluginEstree],\n          });\n        },\n      },\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using, e.g., nextjs, nextjs-vite, react-vite, etc.\nimport { definePreview } from '@storybook/your-framework';\n\nconst preview = definePreview({\n  parameters: {\n    docs: {\n      source: {\n        transform: async (source) => {\n          const prettier = await import('prettier/standalone');\n          const prettierPluginBabel = await import('prettier/plugins/babel');\n          const prettierPluginEstree = await import('prettier/plugins/estree');\n\n          return prettier.format(source, {\n            parser: 'babel',\n            plugins: [prettierPluginBabel, prettierPluginEstree],\n          });\n        },\n      },\n    },\n  },\n});\n\nexport default preview;\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using, e.g., nextjs, nextjs-vite, react-vite, etc.\nimport { definePreview } from '@storybook/your-framework';\n\nconst preview = definePreview({\n  parameters: {\n    docs: {\n      source: {\n        transform: async (source) => {\n          const prettier = await import('prettier/standalone');\n          const prettierPluginBabel = await import('prettier/plugins/babel');\n          const prettierPluginEstree = await import('prettier/plugins/estree');\n\n          return prettier.format(source, {\n            parser: 'babel',\n            plugins: [prettierPluginBabel, prettierPluginEstree],\n          });\n        },\n      },\n    },\n  },\n});\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nconst preview = definePreview({\n  parameters: {\n    docs: {\n      source: {\n        transform: async (source) => {\n          const prettier = await import('prettier/standalone');\n          const prettierPluginBabel = await import('prettier/plugins/babel');\n          const prettierPluginEstree = await import('prettier/plugins/estree');\n\n          return prettier.format(source, {\n            parser: 'babel',\n            plugins: [prettierPluginBabel, prettierPluginEstree],\n          });\n        },\n      },\n    },\n  },\n});\n\nexport default preview;\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nconst preview = definePreview({\n  parameters: {\n    docs: {\n      source: {\n        transform: async (source) => {\n          const prettier = await import('prettier/standalone');\n          const prettierPluginBabel = await import('prettier/plugins/babel');\n          const prettierPluginEstree = await import('prettier/plugins/estree');\n\n          return prettier.format(source, {\n            parser: 'babel',\n            plugins: [prettierPluginBabel, prettierPluginEstree],\n          });\n        },\n      },\n    },\n  },\n});\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nconst preview = definePreview({\n  parameters: {\n    docs: {\n      source: {\n        transform: async (source) => {\n          const prettier = await import('prettier/standalone');\n          const prettierPluginBabel = await import('prettier/plugins/babel');\n          const prettierPluginEstree = await import('prettier/plugins/estree');\n\n          return prettier.format(source, {\n            parser: 'babel',\n            plugins: [prettierPluginBabel, prettierPluginEstree],\n          });\n        },\n      },\n    },\n  },\n});\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nconst preview = definePreview({\n  parameters: {\n    docs: {\n      source: {\n        transform: async (source) => {\n          const prettier = await import('prettier/standalone');\n          const prettierPluginBabel = await import('prettier/plugins/babel');\n          const prettierPluginEstree = await import('prettier/plugins/estree');\n\n          return prettier.format(source, {\n            parser: 'babel',\n            plugins: [prettierPluginBabel, prettierPluginEstree],\n          });\n        },\n      },\n    },\n  },\n});\n\nexport default preview;\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nconst preview = definePreview({\n  parameters: {\n    docs: {\n      source: {\n        transform: async (source) => {\n          const prettier = await import('prettier/standalone');\n          const prettierPluginBabel = await import('prettier/plugins/babel');\n          const prettierPluginEstree = await import('prettier/plugins/estree');\n\n          return prettier.format(source, {\n            parser: 'babel',\n            plugins: [prettierPluginBabel, prettierPluginEstree],\n          });\n        },\n      },\n    },\n  },\n});\n\nexport default preview;\n```\n"
  },
  {
    "path": "docs/_snippets/parameters-in-meta.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  //👇 Creates specific parameters at the component level\n  parameters: {\n    backgrounds: {\n      options: {},\n    },\n  },\n};\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  //👇 Creates specific parameters at the component level\n  parameters: {\n    backgrounds: {\n      options: {},\n    },\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    //👇 Creates specific parameters at the component level\n    parameters: {\n      backgrounds: {\n        options: {},\n      },\n    },\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  //👇 Creates specific parameters at the component level\n  parameters: {\n    backgrounds: {\n      options: {},\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  //👇 Creates specific parameters at the component level\n  parameters: {\n    backgrounds: {\n      options: {},\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    //👇 Creates specific parameters at the component level\n    parameters: {\n      backgrounds: {\n        options: {},\n      },\n    },\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  //👇 Creates specific parameters at the component level\n  parameters: {\n    backgrounds: {\n      options: {},\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  //👇 Creates specific parameters at the component level\n  parameters: {\n    backgrounds: {\n      options: {},\n    },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n  //👇 Creates specific parameters at the component level\n  parameters: {\n    backgrounds: {\n      options: {},\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  //👇 Creates specific parameters at the component level\n  parameters: {\n    backgrounds: {\n      options: {},\n    },\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  //👇 Creates specific parameters at the component level\n  parameters: {\n    backgrounds: {\n      options: {},\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  //👇 Creates specific parameters at the component level\n  parameters: {\n    backgrounds: {\n      options: {},\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  //👇 Creates specific parameters at the component level\n  parameters: {\n    backgrounds: {\n      options: {},\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  //👇 Creates specific parameters at the component level\n  parameters: {\n    backgrounds: {\n      options: {},\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  //👇 Creates specific parameters at the component level\n  parameters: {\n    backgrounds: {\n      options: {},\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  //👇 Creates specific parameters at the component level\n  parameters: {\n    backgrounds: {\n      options: {},\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/parameters-in-preview.md",
    "content": "```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    backgrounds: {\n      options: {\n        light: { name: 'Light', value: '#fff' },\n        dark: { name: 'Dark', value: '#333' },\n      },\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    backgrounds: {\n      options: {\n        light: { name: 'Light', value: '#fff' },\n        dark: { name: 'Dark', value: '#333' },\n      },\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      options: {\n        light: { name: 'Light', value: '#fff' },\n        dark: { name: 'Dark', value: '#333' },\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      options: {\n        light: { name: 'Light', value: '#fff' },\n        dark: { name: 'Dark', value: '#333' },\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      options: {\n        light: { name: 'Light', value: '#fff' },\n        dark: { name: 'Dark', value: '#333' },\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      options: {\n        light: { name: 'Light', value: '#fff' },\n        dark: { name: 'Dark', value: '#333' },\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      options: {\n        light: { name: 'Light', value: '#fff' },\n        dark: { name: 'Dark', value: '#333' },\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      options: {\n        light: { name: 'Light', value: '#fff' },\n        dark: { name: 'Dark', value: '#333' },\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      options: {\n        light: { name: 'Light', value: '#fff' },\n        dark: { name: 'Dark', value: '#333' },\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/parameters-in-story.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const Primary: Story = {\n  // 👇 Story-level parameters\n  parameters: {\n    backgrounds: {\n      options: {\n        red: { name: 'Red', value: '#f00' },\n        green: { name: 'Green', value: '#0f0' },\n        blue: { name: 'Blue', value: '#00f' },\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  // 👇 Story-level parameters\n  parameters: {\n    backgrounds: {\n      options: {\n        red: { name: 'Red', value: '#f00' },\n        green: { name: 'Green', value: '#0f0' },\n        blue: { name: 'Blue', value: '#00f' },\n      },\n    },\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<!-- 👇 Story-level parameters-->\n<Story\n  name=\"Primary\"\n  parameters={{\n    backgrounds: {\n      options: {\n        red: { name: 'Red', value: '#f00' },\n        green: { name: 'Green', value: '#0f0' },\n        blue: { name: 'Blue', value: '#00f' },\n      },\n    },\n  }}\n/>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  // 👇 Story-level parameters\n  parameters: {\n    backgrounds: {\n      options: {\n        red: { name: 'Red', value: '#f00' },\n        green: { name: 'Green', value: '#0f0' },\n        blue: { name: 'Blue', value: '#00f' },\n      },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  // 👇 Story-level parameters\n  parameters: {\n    backgrounds: {\n      options: {\n        red: { name: 'Red', value: '#f00' },\n        green: { name: 'Green', value: '#0f0' },\n        blue: { name: 'Blue', value: '#00f' },\n      },\n    },\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<!-- 👇 Story-level parameters-->\n<Story\n  name=\"Primary\"\n  parameters={{\n    backgrounds: {\n      options: {\n        red: { name: 'Red', value: '#f00' },\n        green: { name: 'Green', value: '#0f0' },\n        blue: { name: 'Blue', value: '#00f' },\n      },\n    },\n  }}\n/>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  // 👇 Story-level parameters\n  parameters: {\n    backgrounds: {\n      options: {\n        red: { name: 'Red', value: '#f00' },\n        green: { name: 'Green', value: '#0f0' },\n        blue: { name: 'Blue', value: '#00f' },\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Primary: Story = {\n  // 👇 Story-level parameters\n  parameters: {\n    backgrounds: {\n      options: {\n        red: { name: 'Red', value: '#f00' },\n        green: { name: 'Green', value: '#0f0' },\n        blue: { name: 'Blue', value: '#00f' },\n      },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n};\n\nexport const Primary = {\n  // 👇 Story-level parameters\n  parameters: {\n    backgrounds: {\n      options: {\n        red: { name: 'Red', value: '#f00' },\n        green: { name: 'Green', value: '#0f0' },\n        blue: { name: 'Blue', value: '#00f' },\n      },\n    },\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Primary = {\n  // 👇 Story-level parameters\n  parameters: {\n    backgrounds: {\n      options: {\n        red: { name: 'Red', value: '#f00' },\n        green: { name: 'Green', value: '#0f0' },\n        blue: { name: 'Blue', value: '#00f' },\n      },\n    },\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Primary = meta.story({\n  // 👇 Story-level parameters\n  parameters: {\n    backgrounds: {\n      options: {\n        red: { name: 'Red', value: '#f00' },\n        green: { name: 'Green', value: '#0f0' },\n        blue: { name: 'Blue', value: '#00f' },\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const Primary = meta.story({\n  // 👇 Story-level parameters\n  parameters: {\n    backgrounds: {\n      options: {\n        red: { name: 'Red', value: '#f00' },\n        green: { name: 'Green', value: '#0f0' },\n        blue: { name: 'Blue', value: '#00f' },\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  // 👇 Story-level parameters\n  parameters: {\n    backgrounds: {\n      options: {\n        red: { name: 'Red', value: '#f00' },\n        green: { name: 'Green', value: '#0f0' },\n        blue: { name: 'Blue', value: '#00f' },\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  // 👇 Story-level parameters\n  parameters: {\n    backgrounds: {\n      options: {\n        red: { name: 'Red', value: '#f00' },\n        green: { name: 'Green', value: '#0f0' },\n        blue: { name: 'Blue', value: '#00f' },\n      },\n    },\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  // 👇 Story-level parameters\n  parameters: {\n    backgrounds: {\n      options: {\n        red: { name: 'Red', value: '#f00' },\n        green: { name: 'Green', value: '#0f0' },\n        blue: { name: 'Blue', value: '#00f' },\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Primary = meta.story({\n  // 👇 Story-level parameters\n  parameters: {\n    backgrounds: {\n      options: {\n        red: { name: 'Red', value: '#f00' },\n        green: { name: 'Green', value: '#0f0' },\n        blue: { name: 'Blue', value: '#00f' },\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/play-function-composition.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n};\nexport default meta;\n\ntype Story = StoryObj<MyComponent>;\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FirstStory: Story = {\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('an-element'), 'example-value');\n  },\n};\n\nexport const SecondStory: Story = {\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('other-element'), 'another value');\n  },\n};\n\nexport const CombinedStories: Story = {\n  play: async ({ context, canvas, userEvent }) => {\n    // Runs the FirstStory and Second story play function before running this story's play function\n    await FirstStory.play(context);\n    await SecondStory.play(context);\n    await userEvent.type(canvas.getByTestId('another-element'), 'random value');\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FirstStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('an-element'), 'example-value');\n  },\n});\n\nexport const SecondStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('other-element'), 'another value');\n  },\n});\n\nexport const CombinedStories = meta.story({\n  play: async ({ context, canvas, userEvent }) => {\n    // Runs the FirstStory and Second story play function before running this story's play function\n    await FirstStory.play(context);\n    await SecondStory.play(context);\n    await userEvent.type(canvas.getByTestId('another-element'), 'random value');\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FirstStory = {\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('an-element'), 'example-value');\n  },\n};\n\nexport const SecondStory = {\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('other-element'), 'another value');\n  },\n};\n\nexport const CombinedStories = {\n  play: async ({ context, canvas, userEvent }) => {\n    // Runs the FirstStory and Second story play function before running this story's play function\n    await FirstStory.play(context);\n    await SecondStory.play(context);\n    await userEvent.type(canvas.getByTestId('another-element'), 'random value');\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FirstStory: Story = {\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('an-element'), 'example-value');\n  },\n};\n\nexport const SecondStory: Story = {\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('other-element'), 'another value');\n  },\n};\n\nexport const CombinedStories: Story = {\n  play: async ({ context, canvas, userEvent }) => {\n    // Runs the FirstStory and Second story play function before running this story's play function\n    await FirstStory.play(context);\n    await SecondStory.play(context);\n    await userEvent.type(canvas.getByTestId('another-element'), 'random value');\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-my-component',\n};\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FirstStory = {\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('an-element'), 'example-value');\n  },\n};\n\nexport const SecondStory = {\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('other-element'), 'another value');\n  },\n};\n\nexport const CombinedStories = {\n  play: async ({ context, canvas, userEvent }) => {\n    // Runs the FirstStory and Second story play function before running this story's play function\n    await FirstStory.play(context);\n    await SecondStory.play(context);\n    await userEvent.type(canvas.getByTestId('another-element'), 'random value');\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\nconst meta: Meta = {\n  component: 'demo-my-component',\n};\nexport default meta;\n\ntype Story = StoryObj;\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FirstStory: Story = {\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('an-element'), 'example-value');\n  },\n};\n\nexport const SecondStory: Story = {\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('other-element'), 'another value');\n  },\n};\n\nexport const CombinedStories: Story = {\n  play: async ({ context, canvas, userEvent }) => {\n    // Runs the FirstStory and Second story play function before running this story's play function\n    await FirstStory.play(context);\n    await SecondStory.play(context);\n    await userEvent.type(canvas.getByTestId('another-element'), 'random value');\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-my-component',\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FirstStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('an-element'), 'example-value');\n  },\n});\n\nexport const SecondStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('other-element'), 'another value');\n  },\n});\n\nexport const CombinedStories = meta.story({\n  play: async ({ context, canvas, userEvent }) => {\n    // Runs the FirstStory and Second story play function before running this story's play function\n    await FirstStory.play(context);\n    await SecondStory.play(context);\n    await userEvent.type(canvas.getByTestId('another-element'), 'random value');\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-my-component',\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FirstStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('an-element'), 'example-value');\n  },\n});\n\nexport const SecondStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('other-element'), 'another value');\n  },\n});\n\nexport const CombinedStories = meta.story({\n  play: async ({ context, canvas, userEvent }) => {\n    // Runs the FirstStory and Second story play function before running this story's play function\n    await FirstStory.play(context);\n    await SecondStory.play(context);\n    await userEvent.type(canvas.getByTestId('another-element'), 'random value');\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FirstStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('an-element'), 'example-value');\n  },\n});\n\nexport const SecondStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('other-element'), 'another value');\n  },\n});\n\nexport const CombinedStories = meta.story({\n  play: async ({ context, canvas, userEvent }) => {\n    // Runs the FirstStory and Second story play function before running this story's play function\n    await FirstStory.play(context);\n    await SecondStory.play(context);\n    await userEvent.type(canvas.getByTestId('another-element'), 'random value');\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FirstStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('an-element'), 'example-value');\n  },\n});\n\nexport const SecondStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('other-element'), 'another value');\n  },\n});\n\nexport const CombinedStories = meta.story({\n  play: async ({ context, canvas, userEvent }) => {\n    // Runs the FirstStory and Second story play function before running this story's play function\n    await FirstStory.play(context);\n    await SecondStory.play(context);\n    await userEvent.type(canvas.getByTestId('another-element'), 'random value');\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FirstStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('an-element'), 'example-value');\n  },\n});\n\nexport const SecondStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('other-element'), 'another value');\n  },\n});\n\nexport const CombinedStories = meta.story({\n  play: async ({ context, canvas, userEvent }) => {\n    // Runs the FirstStory and Second story play function before running this story's play function\n    await FirstStory.play(context);\n    await SecondStory.play(context);\n    await userEvent.type(canvas.getByTestId('another-element'), 'random value');\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FirstStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('an-element'), 'example-value');\n  },\n});\n\nexport const SecondStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.type(canvas.getByTestId('other-element'), 'another value');\n  },\n});\n\nexport const CombinedStories = meta.story({\n  play: async ({ context, canvas, userEvent }) => {\n    // Runs the FirstStory and Second story play function before running this story's play function\n    await FirstStory.play(context);\n    await SecondStory.play(context);\n    await userEvent.type(canvas.getByTestId('another-element'), 'random value');\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/play-function-with-canvas.md",
    "content": "```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  component: MyComponent,\n};\nexport default meta;\n\ntype Story = StoryObj<MyComponent>;\n\nexport const ExampleStory: Story = {\n  play: async ({ canvas, userEvent }) => {\n    // Starts querying from the component's root element\n    await userEvent.type(canvas.getByTestId('example-element'), 'something');\n    await userEvent.click(canvas.getByRole('button'));\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ExampleStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    // Starts querying from the component's root element\n    await userEvent.type(canvas.getByTestId('example-element'), 'something');\n    await userEvent.click(canvas.getByRole('button'));\n  },\n});\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"ExampleStory\"\n  play={async ({ canvas, userEvent }) => {\n    // Starts querying from the component's root element\n    await userEvent.type(canvas.getByTestId('example-element'), 'something');\n    await userEvent.click(canvas.getByRole('button'));\n  }} />\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.svelte';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const ExampleStory = {\n  play: async ({ canvas, userEvent }) => {\n    // Starts querying from the component's root element\n    await userEvent.type(canvas.getByTestId('example-element'), 'something');\n    await userEvent.click(canvas.getByRole('button'));\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const ExampleStory = {\n  play: async ({ canvas, userEvent }) => {\n    // Starts querying from the component's root element\n    await userEvent.type(canvas.getByTestId('example-element'), 'something');\n    await userEvent.click(canvas.getByRole('button'));\n  },\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"ExampleStory\"\n  play={async ({ canvas, userEvent }) => {\n    // Starts querying from the component's root element\n    await userEvent.type(canvas.getByTestId('example-element'), 'something');\n    await userEvent.click(canvas.getByRole('button'));\n  }} />\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport MyComponent from './MyComponent.svelte';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const ExampleStory: Story = {\n  play: async ({ canvas, userEvent }) => {\n    // Starts querying from the component's root element\n    await userEvent.type(canvas.getByTestId('example-element'), 'something');\n    await userEvent.click(canvas.getByRole('button'));\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const ExampleStory: Story = {\n  play: async ({ canvas, userEvent }) => {\n    // Starts querying from the component's root element\n    await userEvent.type(canvas.getByTestId('example-element'), 'something');\n    await userEvent.click(canvas.getByRole('button'));\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-my-component',\n};\n\nexport const ExampleStory = {\n  play: async ({ canvas, userEvent }) => {\n    // Starts querying from the component's root element\n    await userEvent.type(canvas.getByTestId('example-element'), 'something');\n    await userEvent.click(canvas.getByRole('button'));\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-my-component',\n};\nexport default meta;\n\ntype Story = StoryObj;\n\nexport const ExampleStory: Story = {\n  play: async ({ canvas, userEvent }) => {\n    // Starts querying from the component's root element\n    await userEvent.type(canvas.getByTestId('example-element'), 'something');\n    await userEvent.click(canvas.getByRole('button'));\n  },\n};\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-my-component',\n});\n\nexport const ExampleStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    // Starts querying from the component's root element\n    await userEvent.type(canvas.getByTestId('example-element'), 'something');\n    await userEvent.click(canvas.getByRole('button'));\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-my-component',\n});\n\nexport const ExampleStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    // Starts querying from the component's root element\n    await userEvent.type(canvas.getByTestId('example-element'), 'something');\n    await userEvent.click(canvas.getByRole('button'));\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ExampleStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    // Starts querying from the component's root element\n    await userEvent.type(canvas.getByTestId('example-element'), 'something');\n    await userEvent.click(canvas.getByRole('button'));\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ExampleStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    // Starts querying from the component's root element\n    await userEvent.type(canvas.getByTestId('example-element'), 'something');\n    await userEvent.click(canvas.getByRole('button'));\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ExampleStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    // Starts querying from the component's root element\n    await userEvent.type(canvas.getByTestId('example-element'), 'something');\n    await userEvent.click(canvas.getByRole('button'));\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const ExampleStory = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    // Starts querying from the component's root element\n    await userEvent.type(canvas.getByTestId('example-element'), 'something');\n    await userEvent.click(canvas.getByRole('button'));\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/play-function-with-screen.md",
    "content": "```ts filename=\"Dialog.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\nimport { screen } from 'storybook/test';\n\nimport { Dialog } from './dialog.component';\n\nconst meta: Meta<Dialog> = {\n  component: Dialog,\n};\nexport default meta;\n\ntype Story = StoryObj<Dialog>;\n\nexport const Open: Story = {\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(canvas.getByRole('button', { name: 'Open dialog' }));\n\n    // Starts querying from the document\n    const dialog = screen.getByRole('dialog');\n    await expect(dialog).toBeVisible();\n  },\n};\n```\n\n```ts filename=\"Dialog.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { screen } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { Dialog } from './dialog.component';\n\nconst meta = preview.meta({\n  component: Dialog,\n});\n\nexport const Open = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(canvas.getByRole('button', { name: 'Open dialog' }));\n\n    // Starts querying from the document\n    const dialog = screen.getByRole('dialog');\n    await expect(dialog).toBeVisible();\n  },\n});\n```\n\n```svelte filename=\"Dialog.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import { screen } from 'storybook/test';\n\n  import Dialog from './Dialog.svelte';\n\n  const { Story } = defineMeta({\n    component: Dialog,\n  });\n</script>\n\n<Story\n  name=\"Open\"\n  play={async ({ canvas, userEvent }) => {\n    await userEvent.click(canvas.getByRole('button', { name: 'Open dialog' }));\n\n    // Starts querying from the document\n    const dialog = screen.getByRole('dialog');\n    await expect(dialog).toBeVisible();\n  }} />\n```\n\n```js filename=\"Dialog.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Dialog from './Dialog.svelte';\n\nexport default {\n  component: Dialog,\n};\n\nexport const Open = {\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(canvas.getByRole('button', { name: 'Open dialog' }));\n\n    // Starts querying from the document\n    const dialog = screen.getByRole('dialog');\n    await expect(dialog).toBeVisible();\n  },\n};\n```\n\n```js filename=\"Dialog.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { screen } from 'storybook/test';\n\nimport { Dialog } from './Dialog';\n\nexport default {\n  component: Dialog,\n};\n\nexport const Open = {\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(canvas.getByRole('button', { name: 'Open dialog' }));\n\n    // Starts querying from the document\n    const dialog = screen.getByRole('dialog');\n    await expect(dialog).toBeVisible();\n  },\n};\n```\n\n```svelte filename=\"Dialog.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import { screen } from 'storybook/test';\n\n  import Dialog from './Dialog.svelte';\n\n  const { Story } = defineMeta({\n    component: Dialog,\n  });\n</script>\n\n<Story\n  name=\"Open\"\n  play={async ({ canvas, userEvent }) => {\n    await userEvent.click(canvas.getByRole('button', { name: 'Open dialog' }));\n\n    // Starts querying from the document\n    const dialog = screen.getByRole('dialog');\n    await expect(dialog).toBeVisible();\n  }} />\n```\n\n```ts filename=\"Dialog.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\nimport { screen } from 'storybook/test';\n\nimport Dialog from './Dialog.svelte';\n\nconst meta = {\n  component: Dialog,\n} satisfies Meta<typeof Dialog>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Open: Story = {\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(canvas.getByRole('button', { name: 'Open dialog' }));\n\n    // Starts querying from the document\n    const dialog = screen.getByRole('dialog');\n    await expect(dialog).toBeVisible();\n  },\n};\n```\n\n```ts filename=\"Dialog.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\nimport { screen } from 'storybook/test';\n\nimport { Dialog } from './Dialog';\n\nconst meta = {\n  component: Dialog,\n} satisfies Meta<typeof Dialog>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Open: Story = {\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(canvas.getByRole('button', { name: 'Open dialog' }));\n\n    // Starts querying from the document\n    const dialog = screen.getByRole('dialog');\n    await expect(dialog).toBeVisible();\n  },\n};\n```\n\n```js filename=\"Dialog.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { screen } from 'storybook/test';\n\nexport default {\n  component: 'demo-dialog',\n};\n\nexport const Open = {\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(canvas.getByRole('button', { name: 'Open dialog' }));\n\n    // Starts querying from the document\n    const dialog = screen.getByRole('dialog');\n    await expect(dialog).toBeVisible();\n  },\n};\n```\n\n```ts filename=\"Dialog.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\nimport { screen } from 'storybook/test';\n\nconst meta: Meta = {\n  component: 'demo-dialog',\n};\nexport default meta;\n\ntype Story = StoryObj;\n\nexport const Open: Story = {\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(canvas.getByRole('button', { name: 'Open dialog' }));\n\n    // Starts querying from the document\n    const dialog = screen.getByRole('dialog');\n    await expect(dialog).toBeVisible();\n  },\n};\n```\n\n```js filename=\"Dialog.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { screen } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-dialog',\n});\n\nexport const Open = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(canvas.getByRole('button', { name: 'Open dialog' }));\n\n    // Starts querying from the document\n    const dialog = screen.getByRole('dialog');\n    await expect(dialog).toBeVisible();\n  },\n});\n```\n\n```ts filename=\"Dialog.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { screen } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-dialog',\n});\n\nexport const Open = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(canvas.getByRole('button', { name: 'Open dialog' }));\n\n    // Starts querying from the document\n    const dialog = screen.getByRole('dialog');\n    await expect(dialog).toBeVisible();\n  },\n});\n```\n\n```ts filename=\"Dialog.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { screen } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { Dialog } from './Dialog';\n\nconst meta = preview.meta({\n  component: Dialog,\n});\n\nexport const Open = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(canvas.getByRole('button', { name: 'Open dialog' }));\n\n    // Starts querying from the document\n    const dialog = screen.getByRole('dialog');\n    await expect(dialog).toBeVisible();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Dialog.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { screen } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { Dialog } from './Dialog';\n\nconst meta = preview.meta({\n  component: Dialog,\n});\n\nexport const Open = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(canvas.getByRole('button', { name: 'Open dialog' }));\n\n    // Starts querying from the document\n    const dialog = screen.getByRole('dialog');\n    await expect(dialog).toBeVisible();\n  },\n});\n```\n\n```ts filename=\"Dialog.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { screen } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport Dialog from './Dialog.vue';\n\nconst meta = preview.meta({\n  component: Dialog,\n});\n\nexport const Open = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(canvas.getByRole('button', { name: 'Open dialog' }));\n\n    // Starts querying from the document\n    const dialog = screen.getByRole('dialog');\n    await expect(dialog).toBeVisible();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Dialog.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { screen } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport Dialog from './Dialog.vue';\n\nconst meta = preview.meta({\n  component: Dialog,\n});\n\nexport const Open = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    await userEvent.click(canvas.getByRole('button', { name: 'Open dialog' }));\n\n    // Starts querying from the document\n    const dialog = screen.getByRole('dialog');\n    await expect(dialog).toBeVisible();\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/play-function.md",
    "content": "```ts filename=\"RegistrationForm.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { RegistrationForm } from './registration-form.component';\n\nconst meta: Meta<RegistrationForm> = {\n  component: RegistrationForm,\n};\n\nexport default meta;\ntype Story = StoryObj<RegistrationForm>;\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FilledForm: Story = {\n  play: async ({ canvas, userEvent }) => {\n    const emailInput = canvas.getByLabelText('email', {\n      selector: 'input',\n    });\n\n    await userEvent.type(emailInput, 'example-email@email.com', {\n      delay: 100,\n    });\n\n    const passwordInput = canvas.getByLabelText('password', {\n      selector: 'input',\n    });\n\n    await userEvent.type(passwordInput, 'ExamplePassword', {\n      delay: 100,\n    });\n\n    const submitButton = canvas.getByRole('button');\n    await userEvent.click(submitButton);\n  },\n};\n```\n\n```ts filename=\"RegistrationForm.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { RegistrationForm } from './registration-form.component';\n\nconst meta = preview.meta({\n  component: RegistrationForm,\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FilledForm = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    const emailInput = canvas.getByLabelText('email', {\n      selector: 'input',\n    });\n\n    await userEvent.type(emailInput, 'example-email@email.com', {\n      delay: 100,\n    });\n\n    const passwordInput = canvas.getByLabelText('password', {\n      selector: 'input',\n    });\n\n    await userEvent.type(passwordInput, 'ExamplePassword', {\n      delay: 100,\n    });\n\n    const submitButton = canvas.getByRole('button');\n    await userEvent.click(submitButton);\n  },\n});\n```\n\n```svelte filename=\"RegistrationForm.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import RegistrationForm from './RegistrationForm.svelte';\n\n  const { Story } = defineMeta({\n    component: RegistrationForm,\n  });\n</script>\n\n<!--\n  See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n  to learn more about using the canvas to query the DOM\n-->\n<Story\n  name=\"FilledForm\"\n  play={async ({ canvas, userEvent }) => {\n    const emailInput = canvas.getByLabelText('email', {\n      selector: 'input',\n    });\n\n    await userEvent.type(emailInput, 'example-email@email.com', {\n      delay: 100,\n    });\n\n    const passwordInput = canvas.getByLabelText('password', {\n      selector: 'input',\n    });\n\n    await userEvent.type(passwordInput, 'ExamplePassword', {\n      delay: 100,\n    });\n\n    const submitButton = canvas.getByRole('button');\n    await userEvent.click(submitButton);\n  }}\n/>\n```\n\n```js filename=\"RegistrationForm.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport RegistrationForm from './RegistrationForm.svelte';\n\nexport default {\n  component: RegistrationForm,\n};\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FilledForm = {\n  play: async ({ canvas, userEvent }) => {\n    const emailInput = canvas.getByLabelText('email', {\n      selector: 'input',\n    });\n\n    await userEvent.type(emailInput, 'example-email@email.com', {\n      delay: 100,\n    });\n\n    const passwordInput = canvas.getByLabelText('password', {\n      selector: 'input',\n    });\n\n    await userEvent.type(passwordInput, 'ExamplePassword', {\n      delay: 100,\n    });\n\n    const submitButton = canvas.getByRole('button');\n    await userEvent.click(submitButton);\n  },\n};\n```\n\n```js filename=\"RegistrationForm.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { RegistrationForm } from './RegistrationForm';\n\nexport default {\n  component: RegistrationForm,\n};\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FilledForm = {\n  play: async ({ canvas, userEvent }) => {\n    const emailInput = canvas.getByLabelText('email', {\n      selector: 'input',\n    });\n\n    await userEvent.type(emailInput, 'example-email@email.com', {\n      delay: 100,\n    });\n\n    const passwordInput = canvas.getByLabelText('password', {\n      selector: 'input',\n    });\n\n    await userEvent.type(passwordInput, 'ExamplePassword', {\n      delay: 100,\n    });\n\n    const submitButton = canvas.getByRole('button');\n    await userEvent.click(submitButton);\n  },\n};\n```\n\n```svelte filename=\"RegistrationForm.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import RegistrationForm from './RegistrationForm.svelte';\n\n  const { Story } = defineMeta({\n    component: RegistrationForm,\n  });\n</script>\n\n<!--\n  See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n  to learn more about using the canvas to query the DOM\n-->\n<Story\n  name=\"FilledForm\"\n  play={async ({ canvas, userEvent }) => {\n    const emailInput = canvas.getByLabelText('email', {\n      selector: 'input',\n    });\n\n    await userEvent.type(emailInput, 'example-email@email.com', {\n      delay: 100,\n    });\n\n    const passwordInput = canvas.getByLabelText('password', {\n      selector: 'input',\n    });\n\n    await userEvent.type(passwordInput, 'ExamplePassword', {\n      delay: 100,\n    });\n\n    const submitButton = canvas.getByRole('button');\n    await userEvent.click(submitButton);\n  }}\n/>\n```\n\n```ts filename=\"RegistrationForm.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport RegistrationForm from './RegistrationForm.svelte';\n\nconst meta = {\n  component: RegistrationForm,\n} satisfies Meta<typeof RegistrationForm>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FilledForm: Story = {\n  play: async ({ canvas, userEvent }) => {\n    const emailInput = canvas.getByLabelText('email', {\n      selector: 'input',\n    });\n\n    await userEvent.type(emailInput, 'example-email@email.com', {\n      delay: 100,\n    });\n\n    const passwordInput = canvas.getByLabelText('password', {\n      selector: 'input',\n    });\n\n    await userEvent.type(passwordInput, 'ExamplePassword', {\n      delay: 100,\n    });\n\n    const submitButton = canvas.getByRole('button');\n    await userEvent.click(submitButton);\n  },\n};\n```\n\n```ts filename=\"RegistrationForm.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { RegistrationForm } from './RegistrationForm';\n\nconst meta = {\n  component: RegistrationForm,\n} satisfies Meta<typeof RegistrationForm>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FilledForm: Story = {\n  play: async ({ canvas, userEvent }) => {\n    const emailInput = canvas.getByLabelText('email', {\n      selector: 'input',\n    });\n\n    await userEvent.type(emailInput, 'example-email@email.com', {\n      delay: 100,\n    });\n\n    const passwordInput = canvas.getByLabelText('password', {\n      selector: 'input',\n    });\n\n    await userEvent.type(passwordInput, 'ExamplePassword', {\n      delay: 100,\n    });\n\n    const submitButton = canvas.getByRole('button');\n    await userEvent.click(submitButton);\n  },\n};\n```\n\n```js filename=\"RegistrationForm.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-registration-form',\n};\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FilledForm = {\n  play: async ({ canvas, userEvent }) => {\n    const emailInput = canvas.getByLabelText('email', {\n      selector: 'input',\n    });\n\n    await userEvent.type(emailInput, 'example-email@email.com', {\n      delay: 100,\n    });\n\n    const passwordInput = canvas.getByLabelText('password', {\n      selector: 'input',\n    });\n\n    await userEvent.type(passwordInput, 'ExamplePassword', {\n      delay: 100,\n    });\n\n    const submitButton = canvas.getByRole('button');\n    await userEvent.click(submitButton);\n  },\n};\n```\n\n```ts filename=\"RegistrationForm.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-registration-form',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FilledForm: Story = {\n  play: async ({ canvas, userEvent }) => {\n    const emailInput = canvas.getByLabelText('email', {\n      selector: 'input',\n    });\n\n    await userEvent.type(emailInput, 'example-email@email.com', {\n      delay: 100,\n    });\n\n    const passwordInput = canvas.getByLabelText('password', {\n      selector: 'input',\n    });\n\n    await userEvent.type(passwordInput, 'ExamplePassword', {\n      delay: 100,\n    });\n\n    const submitButton = canvas.getByRole('button');\n    await userEvent.click(submitButton);\n  },\n};\n```\n\n```ts filename=\"RegistrationForm.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-registration-form',\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FilledForm = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    const emailInput = canvas.getByLabelText('email', {\n      selector: 'input',\n    });\n\n    await userEvent.type(emailInput, 'example-email@email.com', {\n      delay: 100,\n    });\n\n    const passwordInput = canvas.getByLabelText('password', {\n      selector: 'input',\n    });\n\n    await userEvent.type(passwordInput, 'ExamplePassword', {\n      delay: 100,\n    });\n\n    const submitButton = canvas.getByRole('button');\n    await userEvent.click(submitButton);\n  },\n});\n```\n\n```js filename=\"RegistrationForm.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-registration-form',\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FilledForm = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    const emailInput = canvas.getByLabelText('email', {\n      selector: 'input',\n    });\n\n    await userEvent.type(emailInput, 'example-email@email.com', {\n      delay: 100,\n    });\n\n    const passwordInput = canvas.getByLabelText('password', {\n      selector: 'input',\n    });\n\n    await userEvent.type(passwordInput, 'ExamplePassword', {\n      delay: 100,\n    });\n\n    const submitButton = canvas.getByRole('button');\n    await userEvent.click(submitButton);\n  },\n});\n```\n\n```ts filename=\"RegistrationForm.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { RegistrationForm } from './RegistrationForm';\n\nconst meta = preview.meta({\n  component: RegistrationForm,\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FilledForm = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    const emailInput = canvas.getByLabelText('email', {\n      selector: 'input',\n    });\n\n    await userEvent.type(emailInput, 'example-email@email.com', {\n      delay: 100,\n    });\n\n    const passwordInput = canvas.getByLabelText('password', {\n      selector: 'input',\n    });\n\n    await userEvent.type(passwordInput, 'ExamplePassword', {\n      delay: 100,\n    });\n\n    const submitButton = canvas.getByRole('button');\n    await userEvent.click(submitButton);\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"RegistrationForm.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { RegistrationForm } from './RegistrationForm';\n\nconst meta = preview.meta({\n  component: RegistrationForm,\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FilledForm = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    const emailInput = canvas.getByLabelText('email', {\n      selector: 'input',\n    });\n\n    await userEvent.type(emailInput, 'example-email@email.com', {\n      delay: 100,\n    });\n\n    const passwordInput = canvas.getByLabelText('password', {\n      selector: 'input',\n    });\n\n    await userEvent.type(passwordInput, 'ExamplePassword', {\n      delay: 100,\n    });\n\n    const submitButton = canvas.getByRole('button');\n    await userEvent.click(submitButton);\n  },\n});\n```\n\n```ts filename=\"RegistrationForm.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport RegistrationForm from './RegistrationForm.vue';\n\nconst meta = preview.meta({\n  component: RegistrationForm,\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FilledForm = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    const emailInput = canvas.getByLabelText('email', {\n      selector: 'input',\n    });\n\n    await userEvent.type(emailInput, 'example-email@email.com', {\n      delay: 100,\n    });\n\n    const passwordInput = canvas.getByLabelText('password', {\n      selector: 'input',\n    });\n\n    await userEvent.type(passwordInput, 'ExamplePassword', {\n      delay: 100,\n    });\n\n    const submitButton = canvas.getByRole('button');\n    await userEvent.click(submitButton);\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"RegistrationForm.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport RegistrationForm from './RegistrationForm.vue';\n\nconst meta = preview.meta({\n  component: RegistrationForm,\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const FilledForm = meta.story({\n  play: async ({ canvas, userEvent }) => {\n    const emailInput = canvas.getByLabelText('email', {\n      selector: 'input',\n    });\n\n    await userEvent.type(emailInput, 'example-email@email.com', {\n      delay: 100,\n    });\n\n    const passwordInput = canvas.getByLabelText('password', {\n      selector: 'input',\n    });\n\n    await userEvent.type(passwordInput, 'ExamplePassword', {\n      delay: 100,\n    });\n\n    const submitButton = canvas.getByRole('button');\n    await userEvent.click(submitButton);\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/portable-stories-csf-factory-render.md",
    "content": "```tsx filename=\"Button.test.tsx\" renderer=\"react\" language=\"ts\"\nimport { test, expect } from 'vitest';\nimport { render, screen } from '@testing-library/react';\n\n// Import all stories from the stories file\nimport * as stories from './Button.stories';\n\nconst { Primary, Secondary } = stories;\n\ntest('renders primary button with default args', async () => {\n  // Access the story's component via the .Component property\n  render(<Primary.Component />);\n  const buttonElement = screen.getByText('Text coming from args in stories file!');\n  expect(buttonElement).not.toBeNull();\n});\n\ntest('renders primary button with overridden props', async () => {\n  // You can override props by passing them directly to the story's component\n  render(<Primary.Component>Hello world</Primary.Component>);\n  const buttonElement = screen.getByText(/Hello world/i);\n  expect(buttonElement).not.toBeNull();\n});\n```\n"
  },
  {
    "path": "docs/_snippets/portable-stories-csf-factory-run.md",
    "content": "```tsx filename=\"Button.test.tsx\" renderer=\"react\" language=\"ts\"\nimport { test, expect } from 'vitest';\nimport { screen } from '@testing-library/react';\n\n// Import all stories from the stories file\nimport * as stories from './Button.stories';\n\nconst { Primary, Secondary } = stories;\n\ntest('renders primary button with default args', async () => {\n  // The run function will mount the component and run all of Storybook's lifecycle hooks\n  await Primary.run();\n  const buttonElement = screen.getByText('Text coming from args in stories file!');\n  expect(buttonElement).not.toBeNull();\n});\n\ntest('renders primary button with overridden props', async () => {\n  // You can override props by passing them in the context argument of the run function\n  await Primary.run({ args: { ...Primary.composed.args, children: 'Hello world' } });\n  const buttonElement = screen.getByText(/Hello world/i);\n  expect(buttonElement).not.toBeNull();\n});\n```\n"
  },
  {
    "path": "docs/_snippets/portable-stories-jest-compose-stories.md",
    "content": "```tsx filename=\"Button.test.tsx\" renderer=\"react\" language=\"ts\"\nimport { test, expect } from '@jest/globals';\nimport { render, screen } from '@testing-library/react';\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\n// Import all stories and the component annotations from the stories file\nimport * as stories from './Button.stories';\n\n// Every component that is returned maps 1:1 with the stories,\n// but they already contain all annotations from story, meta, and project levels\nconst { Primary, Secondary } = composeStories(stories);\n\ntest('renders primary button with default args', () => {\n  render(<Primary />);\n  const buttonElement = screen.getByText('Text coming from args in stories file!');\n  expect(buttonElement).not.toBeNull();\n});\n\ntest('renders primary button with overridden props', () => {\n  // You can override props and they will get merged with values from the story's args\n  render(<Primary>Hello world</Primary>);\n  const buttonElement = screen.getByText(/Hello world/i);\n  expect(buttonElement).not.toBeNull();\n});\n```\n\n```ts filename=\"Button.test.ts\" renderer=\"vue\" language=\"ts\"\nimport { test, expect } from '@jest/globals';\nimport { render, screen } from '@testing-library/vue';\nimport { composeStories } from '@storybook/vue3-vite';\n\n// Import all stories and the component annotations from the stories file\nimport * as stories from './Button.stories';\n\n// Every component that is returned maps 1:1 with the stories,\n// but they already contain all annotations from story, meta, and project levels\nconst { Primary, Secondary } = composeStories(stories);\n\ntest('renders primary button with default args', () => {\n  render(Primary);\n  const buttonElement = screen.getByText('Text coming from args in stories file!');\n  expect(buttonElement).not.toBeNull();\n});\n\ntest('renders primary button with overridden props', () => {\n  // You can override props and they will get merged with values from the story's args\n  render(Primary, { props: { label: 'Hello world' } });\n  const buttonElement = screen.getByText(/Hello world/i);\n  expect(buttonElement).not.toBeNull();\n});\n```\n"
  },
  {
    "path": "docs/_snippets/portable-stories-jest-compose-story.md",
    "content": "```tsx filename=\"Button.test.tsx\" renderer=\"react\" language=\"ts\"\nimport { jest, test, expect } from '@jest/globals';\nimport { render, screen } from '@testing-library/react';\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { composeStory } from '@storybook/your-framework';\n\nimport meta, { Primary as PrimaryStory } from './Button.stories';\n\ntest('onclick handler is called', () => {\n  // Returns a story which already contains all annotations from story, meta and global levels\n  const Primary = composeStory(PrimaryStory, meta);\n\n  const onClickSpy = jest.fn();\n  await Primary.run({ args: { ...Primary.args, onClick: onClickSpy } });\n\n  const buttonElement = screen.getByRole('button');\n  buttonElement.click();\n  expect(onClickSpy).toHaveBeenCalled();\n});\n```\n\n```ts filename=\"Button.test.ts\" renderer=\"vue\" language=\"ts\"\nimport { jest, test, expect } from '@jest/globals';\nimport { render, screen } from '@testing-library/vue';\nimport { composeStory } from '@storybook/vue3-vite';\n\nimport meta, { Primary as PrimaryStory } from './Button.stories';\n\ntest('onclick handler is called', () => {\n  // Returns a story which already contains all annotations from story, meta and global levels\n  const Primary = composeStory(PrimaryStory, meta);\n\n  const onClickSpy = jest.fn();\n  await Primary.run({ args: { ...Primary.args, onClick: onClickSpy } });\n\n  const buttonElement = screen.getByRole('button');\n  buttonElement.click();\n  expect(onClickSpy).toHaveBeenCalled();\n});\n```\n"
  },
  {
    "path": "docs/_snippets/portable-stories-jest-multi-snapshot-test.md",
    "content": "```js filename=\"storybook.test.js|ts\" renderer=\"common\" language=\"js\"\n// 👇 Augment expect with jest-specific-snapshot\nimport 'jest-specific-snapshot';\n\n// ...Code omitted for brevity\n\ndescribe(options.suite, () => {\n  //👇 Add storyDir in the arguments list\n  getAllStoryFiles().forEach(({ filePath, storyFile, storyDir }) => {\n    // ...Previously existing code\n    describe(title, () => {\n      // ...Previously existing code\n      stories.forEach(({ name, story }) => {\n        // ...Previously existing code\n        testFn(name, async () => {\n          await story.run();\n          // Ensures a consistent snapshot by waiting for the component to render by adding a delay of 1 ms before taking the snapshot.\n          await new Promise((resolve) => setTimeout(resolve, 1));\n\n          //👇 Define the path to save the snapshot to:\n          const snapshotPath = path.join(\n            storyDir,\n            options.snapshotsDirName,\n            `${componentName}${options.snapshotExtension}`,\n          );\n          expect(document.body.firstChild).toMatchSpecificSnapshot(snapshotPath);\n        });\n      });\n    });\n  });\n});\n```\n"
  },
  {
    "path": "docs/_snippets/portable-stories-jest-override-globals.md",
    "content": "```tsx filename=\"Button.test.tsx\" renderer=\"react\" language=\"ts\"\nimport { test } from '@jest/globals';\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { composeStory } from '@storybook/your-framework';\n\nimport meta, { Primary as PrimaryStory } from './Button.stories';\n\ntest('renders in English', async () => {\n  const Primary = composeStory(\n    PrimaryStory,\n    meta,\n    { globals: { locale: 'en' } }, // 👈 Project annotations to override the locale\n  );\n\n  await Primary.run();\n});\n\ntest('renders in Spanish', async () => {\n  const Primary = composeStory(PrimaryStory, meta, { globals: { locale: 'es' } });\n\n  await Primary.run();\n});\n```\n\n```ts filename=\"Button.test.ts\" renderer=\"vue\" language=\"ts\"\nimport { test } from '@jest/globals';\nimport { render } from '@testing-library/vue';\nimport { composeStory } from '@storybook/vue3-vite';\n\nimport meta, { Primary as PrimaryStory } from './Button.stories';\n\ntest('renders in English', async () => {\n  const Primary = composeStory(\n    PrimaryStory,\n    meta,\n    { globals: { locale: 'en' } }, // 👈 Project annotations to override the locale\n  );\n\n  await Primary.run();\n});\n\ntest('renders in Spanish', async () => {\n  const Primary = composeStory(PrimaryStory, meta, { globals: { locale: 'es' } });\n\n  await Primary.run();\n});\n```\n"
  },
  {
    "path": "docs/_snippets/portable-stories-jest-set-project-annotations.md",
    "content": "```tsx filename=\"setupTest.ts\" renderer=\"react\" language=\"ts\"\nimport { beforeAll } from '@jest/globals';\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { setProjectAnnotations } from '@storybook/your-framework';\n// 👇 Import the exported annotations, if any, from the addons you're using; otherwise remove this\nimport * as addonAnnotations from 'my-addon/preview';\nimport * as previewAnnotations from './.storybook/preview';\n\nconst annotations = setProjectAnnotations([previewAnnotations, addonAnnotations]);\n\n// Supports beforeAll hook from Storybook\nbeforeAll(annotations.beforeAll);\n```\n\n```tsx filename=\"setupTest.ts\" renderer=\"vue\" language=\"ts\"\nimport { beforeAll } from '@jest/globals';\nimport { setProjectAnnotations } from '@storybook/vue3-vite';\n// 👇 Import the exported annotations, if any, from the addons you're using; otherwise remove this\nimport * as addonAnnotations from 'my-addon/preview';\nimport * as previewAnnotations from './.storybook/preview';\n\nconst annotations = setProjectAnnotations([previewAnnotations, addonAnnotations]);\n\n// Supports beforeAll hook from Storybook\nbeforeAll(annotations.beforeAll);\n```\n"
  },
  {
    "path": "docs/_snippets/portable-stories-jest-snapshot-test.md",
    "content": "```js filename=\"storybook.test.js\" renderer=\"common\" language=\"js\"\nimport path from 'path';\nimport * as glob from 'glob';\n\nimport { describe, test, expect } from '@jest/globals';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\nconst compose = (entry) => {\n  try {\n    return composeStories(entry);\n  } catch (e) {\n    throw new Error(\n      `There was an issue composing stories for the module: ${JSON.stringify(entry)}, ${e}`,\n    );\n  }\n};\n\nfunction getAllStoryFiles() {\n  // Place the glob you want to match your stories files\n  const storyFiles = glob.sync(\n    path.join(process.cwd(), 'stories/**/*.{stories,story}.{js,jsx,mjs,ts,tsx}'),\n  );\n\n  return storyFiles.map((filePath) => {\n    const storyFile = require(filePath);\n    return { filePath, storyFile };\n  });\n}\n\n// Recreate similar options to Storyshots. Place your configuration below\nconst options = {\n  suite: 'Storybook Tests',\n  storyKindRegex: /^.*?DontTest$/,\n  storyNameRegex: /UNSET/,\n  snapshotsDirName: '__snapshots__',\n  snapshotExtension: '.storyshot',\n};\n\ndescribe(options.suite, () => {\n  getAllStoryFiles().forEach(({ storyFile, componentName }) => {\n    const meta = storyFile.default;\n    const title = meta.title || componentName;\n\n    if (options.storyKindRegex.test(title) || meta.parameters?.storyshots?.disable) {\n      // Skip component tests if they are disabled\n      return;\n    }\n\n    describe(title, () => {\n      const stories = Object.entries(compose(storyFile))\n        .map(([name, story]) => ({ name, story }))\n        .filter(({ name, story }) => {\n          // Implements a filtering mechanism to avoid running stories that are disabled via parameters or that match a specific regex mirroring the default behavior of Storyshots.\n          return !options.storyNameRegex.test(name) && !story.parameters.storyshots?.disable;\n        });\n\n      if (stories.length <= 0) {\n        throw new Error(\n          `No stories found for this module: ${title}. Make sure there is at least one valid story for this module, without a disable parameter, or add parameters.storyshots.disable in the default export of this file.`,\n        );\n      }\n\n      stories.forEach(({ name, story }) => {\n        // Instead of not running the test, you can create logic to skip it, flagging it accordingly in the test results.\n        const testFn = story.parameters.storyshots?.skip ? test.skip : test;\n\n        testFn(name, async () => {\n          await story.run();\n          // Ensures a consistent snapshot by waiting for the component to render by adding a delay of 1 ms before taking the snapshot.\n          await new Promise((resolve) => setTimeout(resolve, 1));\n          expect(document.body.firstChild).toMatchSnapshot();\n        });\n      });\n    });\n  });\n});\n```\n\n```ts filename=\"storybook.test.ts\" renderer=\"common\" language=\"ts\"\nimport path from 'path';\nimport * as glob from 'glob';\n\n// Replace your-framework with one of the supported Storybook frameworks (react, vue3)\nimport type { Meta, StoryFn } from '@storybook/your-framework';\n\nimport { describe, test, expect } from '@jest/globals';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\ntype StoryFile = {\n  default: Meta;\n  [name: string]: StoryFn | Meta;\n};\n\nconst compose = (entry: StoryFile): ReturnType<typeof composeStories<StoryFile>> => {\n  try {\n    return composeStories(entry);\n  } catch (e) {\n    throw new Error(\n      `There was an issue composing stories for the module: ${JSON.stringify(entry)}, ${e}`,\n    );\n  }\n};\n\nfunction getAllStoryFiles() {\n  // Place the glob you want to match your stories files\n  const storyFiles = glob.sync(\n    path.join(process.cwd(), 'stories/**/*.{stories,story}.{js,jsx,mjs,ts,tsx}'),\n  );\n\n  return storyFiles.map((filePath) => {\n    const storyFile = require(filePath);\n    return { filePath, storyFile };\n  });\n}\n\n// Recreate similar options to Storyshots. Place your configuration below\nconst options = {\n  suite: 'Storybook Tests',\n  storyKindRegex: /^.*?DontTest$/,\n  storyNameRegex: /UNSET/,\n  snapshotsDirName: '__snapshots__',\n  snapshotExtension: '.storyshot',\n};\n\ndescribe(options.suite, () => {\n  getAllStoryFiles().forEach(({ storyFile, componentName }) => {\n    const meta = storyFile.default;\n    const title = meta.title || componentName;\n\n    if (options.storyKindRegex.test(title) || meta.parameters?.storyshots?.disable) {\n      // Skip component tests if they are disabled\n      return;\n    }\n\n    describe(title, () => {\n      const stories = Object.entries(compose(storyFile))\n        .map(([name, story]) => ({ name, story }))\n        .filter(({ name, story }) => {\n          // Implements a filtering mechanism to avoid running stories that are disabled via parameters or that match a specific regex mirroring the default behavior of Storyshots.\n          return !options.storyNameRegex.test(name) && !story.parameters.storyshots?.disable;\n        });\n\n      if (stories.length <= 0) {\n        throw new Error(\n          `No stories found for this module: ${title}. Make sure there is at least one valid story for this module, without a disable parameter, or add parameters.storyshots.disable in the default export of this file.`,\n        );\n      }\n\n      stories.forEach(({ name, story }) => {\n        // Instead of not running the test, you can create logic to skip it, flagging it accordingly in the test results.\n        const testFn = story.parameters.storyshots?.skip ? test.skip : test;\n\n        testFn(name, async () => {\n          await story.run();\n          // Ensures a consistent snapshot by waiting for the component to render by adding a delay of 1 ms before taking the snapshot.\n          await new Promise((resolve) => setTimeout(resolve, 1));\n          expect(document.body.firstChild).toMatchSnapshot();\n        });\n      });\n    });\n  });\n});\n```\n"
  },
  {
    "path": "docs/_snippets/portable-stories-jest-with-play-function.md",
    "content": "```tsx filename=\"Button.test.tsx\" renderer=\"react\" language=\"ts\"\nimport { test } from '@jest/globals';\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\nimport * as stories from './Button.stories';\n\nconst { Primary } = composeStories(stories);\n\ntest('renders and executes the play function', async () => {\n  // Mount story and run interactions\n  await Primary.run();\n});\n```\n\n```ts filename=\"Button.test.ts\" renderer=\"vue\" language=\"ts\"\nimport { test } from '@jest/globals';\nimport { composeStories } from '@storybook/vue3-vite';\n\nimport * as stories from './Button.stories';\n\nconst { Primary } = composeStories(stories);\n\ntest('renders and executes the play function', async () => {\n  // Mount story and run interactions\n  await Primary.run();\n});\n```\n"
  },
  {
    "path": "docs/_snippets/portable-stories-playwright-ct-compose-stories.md",
    "content": "```tsx filename=\"playwright/index.tsx\" renderer=\"react\" language=\"ts\"\nimport { test } from '@playwright/experimental-ct-react';\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { setProjectAnnotations } from '@storybook/your-framework';\n// 👇 Import the exported annotations, if any, from the addons you're using; otherwise remove this\nimport * as addonAnnotations from 'my-addon/preview';\nimport * as previewAnnotations from './.storybook/preview';\n\nconst annotations = setProjectAnnotations([previewAnnotations, addonAnnotations]);\n\n// Supports beforeAll hook from Storybook\ntest.beforeAll(annotations.beforeAll);\n```\n\n```tsx filename=\"playwright/index.tsx\"  renderer=\"vue\" language=\"ts\"\nimport { test } from '@playwright/experimental-ct-vue';\nimport { setProjectAnnotations } from '@storybook/vue3-vite';\n// 👇 Import the exported annotations, if any, from the addons you're using; otherwise remove this\nimport * as addonAnnotations from 'my-addon/preview';\nimport * as previewAnnotations from './.storybook/preview';\n\nconst annotations = setProjectAnnotations([previewAnnotations, addonAnnotations]);\n\n// Supports beforeAll hook from Storybook\ntest.beforeAll(annotations.beforeAll);\n```\n"
  },
  {
    "path": "docs/_snippets/portable-stories-playwright-ct-override-globals.md",
    "content": "```ts filename=\"Button.stories.portable.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { composeStory } from '@storybook/your-framework';\n\nimport meta, { Primary } from './Button.stories';\n\nexport const PrimaryEnglish = composeStory(\n  Primary,\n  meta,\n  { globals: { locale: 'en' } }, // 👈 Project annotations to override the locale\n);\n\nexport const PrimarySpanish = composeStory(Primary, meta, { globals: { locale: 'es' } });\n```\n\n```ts filename=\"Button.stories.portable.ts\" renderer=\"vue\" language=\"ts\"\nimport { composeStory } from '@storybook/vue3-vite';\n\nimport meta, { Primary } from './Button.stories';\n\nexport const PrimaryEnglish = composeStory(\n  Primary,\n  meta,\n  { globals: { locale: 'en' } }, // 👈 Project annotations to override the locale\n);\n\nexport const PrimarySpanish = composeStory(Primary, meta, { globals: { locale: 'es' } });\n```\n\n```ts filename=\"Button.stories.portable.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { Primary } from './Button.stories';\n\nexport const PrimaryEnglish = Primary.extend({\n  globals: { locale: 'en' }, // 👈 Project annotations to override the locale\n});\n\nexport const PrimarySpanish = Primary.extend({\n  globals: { locale: 'es' },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/portable-stories-playwright-ct.md",
    "content": "```tsx filename=\"Button.playwright.test.tsx\" renderer=\"react\" language=\"ts\"\nimport { createTest } from '@storybook/react/experimental-playwright';\nimport { test as base } from '@playwright/experimental-ct-react';\n\n// See explanation below for `.portable` stories file\nimport stories from './Button.stories.portable';\n\nconst test = createTest(base);\n\ntest('renders primary button', async ({ mount }) => {\n  // The mount function will execute all the necessary steps in the story,\n  // such as loaders, render, and play function\n  await mount(<stories.Primary />);\n});\n\ntest('renders primary button with overridden props', async ({ mount }) => {\n  // You can pass custom props to your component via JSX\n  const component = await mount(<stories.Primary label=\"label from test\" />);\n  await expect(component).toContainText('label from test');\n  await expect(component.getByRole('button')).toHaveClass(/storybook-button--primary/);\n});\n```\n\n```ts filename=\"Button.playwright.test.ts\" renderer=\"vue\" language=\"ts\"\nimport { createTest } from '@storybook/vue3/experimental-playwright';\nimport { test as base } from '@playwright/experimental-ct-vue';\n\n// See explanation below for `.portable` stories file\nimport stories from './Button.stories.portable';\n\nconst test = createTest(base);\n\n// 👉 Important: Due to current limitations, you can only reference your stories as JSX elements.\n\ntest('renders primary button', async ({ mount }) => {\n  // The mount function will execute all the necessary steps in the story,\n  // such as loaders, render, and play function\n  await mount(<stories.Primary />);\n});\n\ntest('renders primary button with overridden props', async ({ mount }) => {\n  // You can pass custom props to your component via JSX\n  const component = await mount(<stories.Primary label=\"label from test\" />);\n  await expect(component).toContainText('label from test');\n  await expect(component.getByRole('button')).toHaveClass(/storybook-button--primary/);\n});\n```\n"
  },
  {
    "path": "docs/_snippets/portable-stories-vitest-compose-stories.md",
    "content": "```tsx filename=\"Button.test.tsx\" renderer=\"react\" language=\"ts\"\nimport { test, expect } from 'vitest';\nimport { screen } from '@testing-library/react';\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\n// Import all stories and the component annotations from the stories file\nimport * as stories from './Button.stories';\n\n// Every component that is returned maps 1:1 with the stories,\n// but they already contain all annotations from story, meta, and project levels\nconst { Primary, Secondary } = composeStories(stories);\n\ntest('renders primary button with default args', async () => {\n  await Primary.run();\n  const buttonElement = screen.getByText('Text coming from args in stories file!');\n  expect(buttonElement).not.toBeNull();\n});\n\ntest('renders primary button with overridden props', async () => {\n  // You can override props by passing them in the context argument of the run function\n  await Primary.run({ args: { ...Primary.args, children: 'Hello world' } });\n  const buttonElement = screen.getByText(/Hello world/i);\n  expect(buttonElement).not.toBeNull();\n});\n```\n\n```ts filename=\"Button.test.ts\" renderer=\"svelte\" language=\"ts\"\nimport { test, expect } from 'vitest';\nimport { screen } from '@testing-library/svelte';\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport { composeStories } from '@storybook/your-framework';\n\n// Import all stories and the component annotations from the stories file\nimport * as stories from './Button.stories';\n\n// Every component that is returned maps 1:1 with the stories,\n// but they already contain all annotations from story, meta, and project levels\nconst { Primary, Secondary } = composeStories(stories);\n\ntest('renders primary button with default args', async () => {\n  await Primary.run();\n  const buttonElement = screen.getByText('Text coming from args in stories file!');\n  expect(buttonElement).not.toBeNull();\n});\n\ntest('renders primary button with overridden props', async () => {\n  // You can override props by passing them in the context argument of the run function\n  await Primary.run({ args: { ...Primary.args, children: 'Hello world' } });\n  const buttonElement = screen.getByText(/Hello world/i);\n  expect(buttonElement).not.toBeNull();\n});\n```\n\n```ts filename=\"Button.test.ts\" renderer=\"vue\" language=\"ts\"\nimport { test, expect } from 'vitest';\nimport { screen } from '@testing-library/vue';\nimport { composeStories } from '@storybook/vue3-vite';\n\n// Import all stories and the component annotations from the stories file\nimport * as stories from './Button.stories';\n\n// Every component that is returned maps 1:1 with the stories,\n// but they already contain all annotations from story, meta, and project levels\nconst { Primary, Secondary } = composeStories(stories);\n\ntest('renders primary button with default args', async () => {\n  await Primary.run();\n  const buttonElement = screen.getByText('Text coming from args in stories file!');\n  expect(buttonElement).not.toBeNull();\n});\n\ntest('renders primary button with overridden props', async () => {\n  // You can override props by passing them in the context argument of the run function\n  await Primary.run({ args: { ...Primary.args, children: 'Hello world' } });\n  const buttonElement = screen.getByText(/Hello world/i);\n  expect(buttonElement).not.toBeNull();\n});\n```\n"
  },
  {
    "path": "docs/_snippets/portable-stories-vitest-compose-story.md",
    "content": "```tsx filename=\"Button.test.tsx\" renderer=\"react\" language=\"ts\"\nimport { vi, test, expect } from 'vitest';\nimport { screen } from '@testing-library/react';\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { composeStory } from '@storybook/your-framework';\n\nimport meta, { Primary as PrimaryStory } from './Button.stories';\n\n// Returns a story which already contains all annotations from story, meta and global levels\nconst Primary = composeStory(PrimaryStory, meta);\n\ntest('renders primary button with default args', async () => {\n  await Primary.run();\n\n  const buttonElement = screen.getByText('Text coming from args in stories file!');\n  expect(buttonElement).not.toBeNull();\n});\n\ntest('renders primary button with overridden props', async () => {\n  await Primary.run({ args: { ...Primary.args, label: 'Hello world' } });\n\n  const buttonElement = screen.getByText(/Hello world/i);\n  expect(buttonElement).not.toBeNull();\n});\n```\n\n```ts filename=\"Button.test.ts\" renderer=\"svelte\" language=\"ts\"\nimport { vi, test, expect } from 'vitest';\nimport { render, screen } from '@testing-library/svelte';\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport { composeStory } from '@storybook/your-framework';\n\nimport meta, { Primary as PrimaryStory } from './Button.stories';\n\n// Returns a story which already contains all annotations from story, meta and global levels\nconst Primary = composeStory(PrimaryStory, meta);\n\ntest('renders primary button with default args', async () => {\n  await Primary.run();\n\n  const buttonElement = screen.getByText('Text coming from args in stories file!');\n  expect(buttonElement).not.toBeNull();\n});\n\ntest('renders primary button with overridden props', async () => {\n  await Primary.run({ args: { ...Primary.args, label: 'Hello world' } });\n\n  const buttonElement = screen.getByText(/Hello world/i);\n  expect(buttonElement).not.toBeNull();\n});\n```\n\n```ts filename=\"Button.test.ts\" renderer=\"vue\" language=\"ts\"\nimport { vi, test, expect } from 'vitest';\nimport { render, screen } from '@testing-library/vue';\nimport { composeStory } from '@storybook/vue3-vite';\n\nimport meta, { Primary as PrimaryStory } from './Button.stories';\n\n// Returns a story which already contains all annotations from story, meta and global levels\nconst Primary = composeStory(PrimaryStory, meta);\n\ntest('renders primary button with default args', async () => {\n  await Primary.run();\n\n  const buttonElement = screen.getByText('Text coming from args in stories file!');\n  expect(buttonElement).not.toBeNull();\n});\n\ntest('renders primary button with overridden props', async () => {\n  await Primary.run({ args: { ...Primary.args, label: 'Hello world' } });\n\n  const buttonElement = screen.getByText(/Hello world/i);\n  expect(buttonElement).not.toBeNull();\n});\n```\n"
  },
  {
    "path": "docs/_snippets/portable-stories-vitest-multi-snapshot-test.md",
    "content": "```ts filename=\"storybook.test.js|ts\" renderer=\"common\" language=\"js\"\n// ...Code omitted for brevity\n\ndescribe(options.suite, () => {\n  // 👇 Add storyDir in the arguments list\n  getAllStoryFiles().forEach(({ filePath, storyFile, storyDir }) => {\n    // ...Previously existing code\n    describe(title, () => {\n      // ...Previously existing code\n      stories.forEach(({ name, story }) => {\n        // ...Previously existing code\n        testFn(name, async () => {\n          await story.run();\n          // Ensures a consistent snapshot by waiting for the component to render by adding a delay of 1 ms before taking the snapshot.\n          await new Promise((resolve) => setTimeout(resolve, 1));\n\n          // 👇 Define the path to save the snapshot to:\n          const snapshotPath = path.join(\n            storyDir,\n            options.snapshotsDirName,\n            `${componentName}${options.snapshotExtension}`,\n          );\n          await expect(document.body.firstChild).toMatchFileSnapshot(snapshotPath);\n        });\n      });\n    });\n  });\n});\n```\n"
  },
  {
    "path": "docs/_snippets/portable-stories-vitest-override-globals.md",
    "content": "```tsx filename=\"Button.test.tsx\" renderer=\"react\" language=\"ts\"\nimport { test } from 'vitest';\nimport { render } from '@testing-library/react';\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { composeStory } from '@storybook/your-framework';\n\nimport meta, { Primary as PrimaryStory } from './Button.stories';\n\ntest('renders in English', async () => {\n  const Primary = composeStory(\n    PrimaryStory,\n    meta,\n    { globals: { locale: 'en' } }, // 👈 Project annotations to override the locale\n  );\n\n  await Primary.run();\n});\n\ntest('renders in Spanish', async () => {\n  const Primary = composeStory(PrimaryStory, meta, { globals: { locale: 'es' } });\n\n  await Primary.run();\n});\n```\n\n```ts filename=\"Button.test.ts\" renderer=\"svelte\" language=\"ts\"\nimport { test } from 'vitest';\nimport { render } from '@testing-library/svelte';\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport { composeStory } from '@storybook/your-framework';\n\nimport meta, { Primary as PrimaryStory } from './Button.stories';\n\ntest('renders in English', async () => {\n  const Primary = composeStory(\n    PrimaryStory,\n    meta,\n    { globals: { locale: 'en' } }, // 👈 Project annotations to override the locale\n  );\n\n  await Primary.run();\n});\n\ntest('renders in Spanish', async () => {\n  const Primary = composeStory(PrimaryStory, meta, { globals: { locale: 'es' } });\n\n  await Primary.run();\n});\n```\n\n```ts filename=\"Button.test.ts\" renderer=\"vue\" language=\"ts\"\nimport { test } from 'vitest';\nimport { render } from '@testing-library/vue';\nimport { composeStory } from '@storybook/vue3-vite';\n\nimport meta, { Primary as PrimaryStory } from './Button.stories';\n\ntest('renders in English', async () => {\n  const Primary = composeStory(\n    PrimaryStory,\n    meta,\n    { globals: { locale: 'en' } }, // 👈 Project annotations to override the locale\n  );\n\n  await Primary.run();\n});\n\ntest('renders in Spanish', async () => {\n  const Primary = composeStory(PrimaryStory, meta, { globals: { locale: 'es' } });\n\n  await Primary.run();\n});\n```\n"
  },
  {
    "path": "docs/_snippets/portable-stories-vitest-set-project-annotations.md",
    "content": "```tsx filename=\"setupTest.ts\" renderer=\"react\" language=\"ts\"\nimport { beforeAll } from 'vitest';\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { setProjectAnnotations } from '@storybook/your-framework';\n// 👇 Import the exported annotations, if any, from the addons you're using; otherwise remove this\nimport * as addonAnnotations from 'my-addon/preview';\nimport * as previewAnnotations from './.storybook/preview';\n\nconst annotations = setProjectAnnotations([previewAnnotations, addonAnnotations]);\n\n// Run Storybook's beforeAll hook\nbeforeAll(annotations.beforeAll);\n```\n\n```tsx filename=\"setupTest.ts\" renderer=\"svelte\" language=\"ts\"\nimport { beforeAll } from 'vitest';\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport { setProjectAnnotations } from '@storybook/your-framework';\n// 👇 Import the exported annotations, if any, from the addons you're using; otherwise remove this\nimport * as addonAnnotations from 'my-addon/preview';\nimport * as previewAnnotations from './.storybook/preview';\n\nconst annotations = setProjectAnnotations([previewAnnotations, addonAnnotations]);\n\n// Run Storybook's beforeAll hook\nbeforeAll(annotations.beforeAll);\n```\n\n```tsx filename=\"setupTest.ts\" renderer=\"vue\" language=\"ts\"\nimport { beforeAll } from 'vitest';\nimport { setProjectAnnotations } from '@storybook/vue3-vite';\n// 👇 Import the exported annotations, if any, from the addons you're using; otherwise remove this\nimport * as addonAnnotations from 'my-addon/preview';\nimport * as previewAnnotations from './.storybook/preview';\n\nconst annotations = setProjectAnnotations([previewAnnotations, addonAnnotations]);\n\n// Run Storybook's beforeAll hook\nbeforeAll(annotations.beforeAll);\n```\n"
  },
  {
    "path": "docs/_snippets/portable-stories-vitest-snapshot-test.md",
    "content": "```js filename=\"storybook.test.js\" renderer=\"common\" language=\"js\"\n// @vitest-environment jsdom\n\nimport { describe, expect, test } from 'vitest';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\nconst compose = (entry) => {\n  try {\n    return composeStories(entry);\n  } catch (e) {\n    throw new Error(\n      `There was an issue composing stories for the module: ${JSON.stringify(entry)}, ${e}`,\n    );\n  }\n};\n\nfunction getAllStoryFiles() {\n  // Place the glob you want to match your story files\n  const storyFiles = Object.entries(\n    import.meta.glob('./stories/**/*.(stories|story).@(js|jsx|mjs|ts|tsx)', {\n      eager: true,\n    }),\n  );\n\n  return storyFiles.map(([filePath, storyFile]) => {\n    const storyDir = path.dirname(filePath);\n    const componentName = path.basename(filePath).replace(/\\.(stories|story)\\.[^/.]+$/, '');\n    return { filePath, storyFile, componentName, storyDir };\n  });\n}\n\n// Recreate similar options to Storyshots. Place your configuration below\nconst options = {\n  suite: 'Storybook Tests',\n  storyKindRegex: /^.*?DontTest$/,\n  storyNameRegex: /UNSET/,\n  snapshotsDirName: '__snapshots__',\n  snapshotExtension: '.storyshot',\n};\n\ndescribe(options.suite, () => {\n  getAllStoryFiles().forEach(({ storyFile, componentName, storyDir }) => {\n    const meta = storyFile.default;\n    const title = meta.title || componentName;\n\n    if (options.storyKindRegex.test(title) || meta.parameters?.storyshots?.disable) {\n      // Skip component tests if they are disabled\n      return;\n    }\n\n    describe(title, () => {\n      const stories = Object.entries(compose(storyFile))\n        .map(([name, story]) => ({ name, story }))\n        .filter(({ name, story }) => {\n          // Implements a filtering mechanism to avoid running stories that are disabled via parameters or that match a specific regex mirroring the default behavior of Storyshots.\n          return !options.storyNameRegex?.test(name) && !story.parameters.storyshots?.disable;\n        });\n\n      if (stories.length <= 0) {\n        throw new Error(\n          `No stories found for this module: ${title}. Make sure there is at least one valid story for this module, without a disable parameter, or add parameters.storyshots.disable in the default export of this file.`,\n        );\n      }\n\n      stories.forEach(({ name, story }) => {\n        // Instead of not running the test, you can create logic to skip it, flagging it accordingly in the test results.\n        const testFn = story.parameters.storyshots?.skip ? test.skip : test;\n\n        testFn(name, async () => {\n          await story.run();\n          // Ensures a consistent snapshot by waiting for the component to render by adding a delay of 1 ms before taking the snapshot.\n          await new Promise((resolve) => setTimeout(resolve, 1));\n\n          expect(document.body.firstChild).toMatchSnapshot();\n        });\n      });\n    });\n  });\n});\n```\n\n```ts filename=\"storybook.test.ts\" renderer=\"common\" language=\"ts\"\n// @vitest-environment jsdom\n\n// Replace your-framework with one of the supported Storybook frameworks (react, vue3)\nimport type { Meta, StoryFn } from '@storybook/your-framework';\n\nimport { describe, expect, test } from 'vitest';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\ntype StoryFile = {\n  default: Meta;\n  [name: string]: StoryFn | Meta;\n};\n\nconst compose = (entry: StoryFile): ReturnType<typeof composeStories<StoryFile>> => {\n  try {\n    return composeStories(entry);\n  } catch (e) {\n    throw new Error(\n      `There was an issue composing stories for the module: ${JSON.stringify(entry)}, ${e}`,\n    );\n  }\n};\n\nfunction getAllStoryFiles() {\n  // Place the glob you want to match your story files\n  const storyFiles = Object.entries(\n    import.meta.glob<StoryFile>('./stories/**/*.(stories|story).@(js|jsx|mjs|ts|tsx)', {\n      eager: true,\n    }),\n  );\n\n  return storyFiles.map(([filePath, storyFile]) => {\n    const storyDir = path.dirname(filePath);\n    const componentName = path.basename(filePath).replace(/\\.(stories|story)\\.[^/.]+$/, '');\n    return { filePath, storyFile, componentName, storyDir };\n  });\n}\n\n// Recreate similar options to Storyshots. Place your configuration below\nconst options = {\n  suite: 'Storybook Tests',\n  storyKindRegex: /^.*?DontTest$/,\n  storyNameRegex: /UNSET/,\n  snapshotsDirName: '__snapshots__',\n  snapshotExtension: '.storyshot',\n};\n\ndescribe(options.suite, () => {\n  getAllStoryFiles().forEach(({ storyFile, componentName, storyDir }) => {\n    const meta = storyFile.default;\n    const title = meta.title || componentName;\n\n    if (options.storyKindRegex.test(title) || meta.parameters?.storyshots?.disable) {\n      // Skip component tests if they are disabled\n      return;\n    }\n\n    describe(title, () => {\n      const stories = Object.entries(compose(storyFile))\n        .map(([name, story]) => ({ name, story }))\n        .filter(({ name, story }) => {\n          // Implements a filtering mechanism to avoid running stories that are disabled via parameters or that match a specific regex mirroring the default behavior of Storyshots.\n          return !options.storyNameRegex?.test(name) && !story.parameters.storyshots?.disable;\n        });\n\n      if (stories.length <= 0) {\n        throw new Error(\n          `No stories found for this module: ${title}. Make sure there is at least one valid story for this module, without a disable parameter, or add parameters.storyshots.disable in the default export of this file.`,\n        );\n      }\n\n      stories.forEach(({ name, story }) => {\n        // Instead of not running the test, you can create logic to skip it, flagging it accordingly in the test results.\n        const testFn = story.parameters.storyshots?.skip ? test.skip : test;\n\n        testFn(name, async () => {\n          await story.run();\n          // Ensures a consistent snapshot by waiting for the component to render by adding a delay of 1 ms before taking the snapshot.\n          await new Promise((resolve) => setTimeout(resolve, 1));\n\n          expect(document.body.firstChild).toMatchSnapshot();\n        });\n      });\n    });\n  });\n});\n```\n"
  },
  {
    "path": "docs/_snippets/portable-stories-vitest-with-play-function.md",
    "content": "```tsx filename=\"Button.test.tsx\" renderer=\"react\" language=\"ts\"\nimport { test } from 'vitest';\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\nimport * as stories from './Button.stories';\n\nconst { Primary } = composeStories(stories);\n\ntest('renders and executes the play function', async () => {\n  // Mount story and run interactions\n  await Primary.run();\n});\n```\n\n```ts filename=\"Button.test.ts\" renderer=\"svelte\" language=\"ts\"\nimport { test } from 'vitest';\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport { composeStories } from '@storybook/your-framework';\n\nimport * as stories from './Button.stories';\n\nconst { Primary } = composeStories(stories);\n\ntest('renders and executes the play function', async () => {\n  // Mount story and run interactions\n  await Primary.run();\n});\n```\n\n```ts filename=\"Button.test.ts\" renderer=\"vue\" language=\"ts\"\nimport { test } from 'vitest';\nimport { composeStory } from '@storybook/vue3-vite';\n\nimport * as stories from './Button.stories';\n\nconst { Primary } = composeStories(stories);\n\ntest('renders and executes the play function', async () => {\n  // Mount story and run interactions\n  await Primary.run();\n});\n```\n"
  },
  {
    "path": "docs/_snippets/preact-vite-add-framework.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"preact\" language=\"js\"\nexport default {\n  // ...\n  // framework: '@storybook/preact-webpack5', 👈 Remove this\n  framework: '@storybook/preact-vite', // 👈 Add this\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"preact\" language=\"ts\"\nimport type { StorybookConfig } from '@storybook/preact-vite';\n\nconst config: StorybookConfig = {\n  // ...\n  // framework: '@storybook/preact-webpack5', 👈 Remove this\n  framework: '@storybook/preact-vite', // 👈 Add this\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/preact-vite-framework-options.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"preact\" language=\"js\"\nexport default {\n  framework: {\n    name: '@storybook/preact-vite',\n    options: {\n      // ...\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"preact\" language=\"ts\"\nimport type { StorybookConfig } from '@storybook/preact-vite';\n\nconst config: StorybookConfig = {\n  framework: {\n    name: '@storybook/preact-vite',\n    options: {\n      // ...\n    },\n  },\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/preact-vite-install.md",
    "content": "```shell renderer=\"preact\" language=\"js\" packageManager=\"npm\"\nnpm install --save-dev @storybook/preact-vite\n```\n\n```shell renderer=\"preact\" language=\"js\" packageManager=\"pnpm\"\npnpm add --save-dev @storybook/preact-vite\n```\n\n```shell renderer=\"preact\" language=\"js\" packageManager=\"yarn\"\nyarn add --dev @storybook/preact-vite\n```\n"
  },
  {
    "path": "docs/_snippets/preview-storybook-production-mode.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx http-server ./path/to/build\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx http-server ./path/to/build\n```\n"
  },
  {
    "path": "docs/_snippets/react-framework-options-legacy-root-api.md",
    "content": "```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using (e.g., nextjs, react-webpack5)\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: {\n    name: '@storybook/your-framework',\n    options: {\n      legacyRootApi: true,\n    },\n  },\n};\n\nexport default config;\n```\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  framework: {\n    // Replace your-framework with the framework you are using (e.g., nextjs, react-webpack5)\n    name: '@storybook/your-framework',\n    options: {\n      legacyRootApi: true,\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., nextjs, react-webpack5)\nimport { defineMain } from '@storybook/your-framework/node';\n\nconst config = defineMain({\n  framework: {\n    name: '@storybook/your-framework',\n    options: {\n      legacyRootApi: true,\n    },\n  },\n});\n\nexport default config;\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., nextjs, react-webpack5)\nimport { defineMain } from '@storybook/your-framework/node';\n\nconst config = defineMain({\n  framework: {\n    name: '@storybook/your-framework',\n    options: {\n      legacyRootApi: true,\n    },\n  },\n});\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/react-native-web-vite-add-framework.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\"\nexport default {\n  addons: [\n    '@storybook/addon-react-native-web', // 👈 Remove the addon\n  ],\n  // Replace @storybook/react-webpack5 with the Vite framework\n  framework: '@storybook/react-native-web-vite',\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\"\nimport type { StorybookConfig } from '@storybook/react-native-web-vite';\n\nconst config: StorybookConfig = {\n  addons: [\n    '@storybook/addon-react-native-web', // 👈 Remove the addon\n  ],\n  // Replace @storybook/react-webpack5 with the Vite framework\n  framework: '@storybook/react-native-web-vite',\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/react-native-web-vite-install.md",
    "content": "```shell renderer=\"common\" language=\"sh\" packageManager=\"npm\"\nnpm install --save-dev @storybook/react-native-web-vite vite\n```\n\n```shell renderer=\"common\" language=\"sh\" packageManager=\"pnpm\"\npnpm add --save-dev @storybook/react-native-web-vite vite\n```\n\n```shell renderer=\"common\" language=\"sh\" packageManager=\"yarn\"\nyarn add --dev @storybook/react-native-web-vite vite\n```\n"
  },
  {
    "path": "docs/_snippets/react-vite-add-framework.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // ...\n  // framework: '@storybook/react-webpack5', 👈 Remove this\n  framework: '@storybook/react-vite', // 👈 Add this\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { StorybookConfig } from '@storybook/react-vite';\n\nconst config: StorybookConfig = {\n  // ...\n  // framework: '@storybook/react-webpack5', 👈 Remove this\n  framework: '@storybook/react-vite', // 👈 Add this\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // ...\n  // framework: '@storybook/react-webpack5', 👈 Remove this\n  framework: '@storybook/react-vite', // 👈 Add this\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // ...\n  // framework: '@storybook/react-webpack5', 👈 Remove this\n  framework: '@storybook/react-vite', // 👈 Add this\n});\n```\n"
  },
  {
    "path": "docs/_snippets/react-vite-framework-options.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  framework: {\n    name: '@storybook/react-vite',\n    options: {\n      // ...\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { StorybookConfig } from '@storybook/react-vite';\n\nconst config: StorybookConfig = {\n  framework: {\n    name: '@storybook/react-vite',\n    options: {\n      // ...\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: {\n    name: '@storybook/react-vite',\n    options: {\n      // ...\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: {\n    name: '@storybook/react-vite',\n    options: {\n      // ...\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/react-vite-install.md",
    "content": "```shell renderer=\"react\" language=\"js\" packageManager=\"npm\"\nnpm install --save-dev @storybook/react-vite\n```\n\n```shell renderer=\"react\" language=\"js\" packageManager=\"pnpm\"\npnpm add --save-dev @storybook/react-vite\n```\n\n```shell renderer=\"react\" language=\"js\" packageManager=\"yarn\"\nyarn add --dev @storybook/react-vite\n```\n"
  },
  {
    "path": "docs/_snippets/react-webpack5-add-framework.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // ...\n  framework: '@storybook/react-webpack5', // 👈 Add this\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { StorybookConfig } from '@storybook/react-webpack5';\n\nconst config: StorybookConfig = {\n  // ...\n  framework: '@storybook/react-webpack5', // 👈 Add this\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // ...\n  framework: '@storybook/react-webpack5', // 👈 Add this\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // ...\n  framework: '@storybook/react-webpack5', // 👈 Add this\n});\n```\n"
  },
  {
    "path": "docs/_snippets/react-webpack5-framework-options.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  framework: {\n    name: '@storybook/react-webpack5',\n    options: {\n      // ...\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { StorybookConfig } from '@storybook/react-webpack5';\n\nconst config: StorybookConfig = {\n  framework: {\n    name: '@storybook/react-webpack5',\n    options: {\n      // ...\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: {\n    name: '@storybook/react-webpack5',\n    options: {\n      // ...\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: {\n    name: '@storybook/react-webpack5',\n    options: {\n      // ...\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/react-webpack5-install.md",
    "content": "```shell renderer=\"react\" language=\"js\" packageManager=\"npm\"\nnpm install --save-dev @storybook/react-webpack5\n```\n\n```shell renderer=\"react\" language=\"js\" packageManager=\"pnpm\"\npnpm add --save-dev @storybook/react-webpack5\n```\n\n```shell renderer=\"react\" language=\"js\" packageManager=\"yarn\"\nyarn add --dev @storybook/react-webpack5\n```\n"
  },
  {
    "path": "docs/_snippets/render-custom-in-meta.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, type StoryObj, argsToTemplate } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  render: (args) => ({\n    props: args,\n\n    template: `\n      <demo-alert>\n        Alert text\n        <demo-button ${argsToTemplate(args)}></demo-button>\n      </demo-alert>\n    `,\n  }),\n};\n\nexport default meta;\n\ntype Story = StoryObj<Button>;\n\nexport const DefaultInAlert: Story = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const PrimaryInAlert: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { argsToTemplate } from '@storybook/angular';\n\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  render: (args) => ({\n    props: args,\n    template: `\n      <demo-alert>\n        Alert text\n        <demo-button ${argsToTemplate(args)}></demo-button>\n      </demo-alert>\n    `,\n  }),\n});\n\nexport const DefaultInAlert = meta.story({\n  args: {\n    label: 'Button',\n  },\n});\n\nexport const PrimaryInAlert = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n```\n\n```jsx filename=\"Button.stories.jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Alert } from './Alert';\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  render: (args) => (\n    <Alert>\n      Alert text\n      <Button {...args} />\n    </Alert>\n  ),\n};\n\nexport const DefaultInAlert = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const PrimaryInAlert = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```tsx filename=\"Button.stories.tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Alert } from './Alert';\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  render: (args) => (\n    <Alert>\n      Alert text\n      <Button {...args} />\n    </Alert>\n  ),\n} satisfies Meta<typeof Button>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const DefaultInAlert: Story = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const PrimaryInAlert: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport Alert from './Alert.vue';\nimport Button from './Button.vue';\n\nexport default {\n  component: Button,\n  render: (args) => ({\n    components: { Alert, Button },\n    setup() {\n      return { args };\n    },\n    template: '<Alert><Button v-bind=\"args\" /></Alert>',\n  }),\n};\n\nexport const DefaultInAlert = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const PrimaryInAlert = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport Alert from './Alert.vue';\nimport Button from './Button.vue';\n\nconst meta = {\n  component: Button,\n  render: (args) => ({\n    components: { Alert, Button },\n    setup() {\n      return { args };\n    },\n    template: '<Alert><Button v-bind=\"args\" /></Alert>',\n  }),\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const DefaultInAlert: Story = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const PrimaryInAlert: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Alert from './Alert.vue';\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  render: (args) => ({\n    components: { Alert, Button },\n    setup() {\n      return { args };\n    },\n    template: '<Alert><Button v-bind=\"args\" /></Alert>',\n  }),\n});\n\nexport const DefaultInAlert = meta.story({\n  args: {\n    label: 'Button',\n  },\n});\n\nexport const PrimaryInAlert = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Alert from './Alert.vue';\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  render: (args) => ({\n    components: { Alert, Button },\n    setup() {\n      return { args };\n    },\n    template: '<Alert><Button v-bind=\"args\" /></Alert>',\n  }),\n});\n\nexport const DefaultInAlert = meta.story({\n  args: {\n    label: 'Button',\n  },\n});\n\nexport const PrimaryInAlert = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport html from 'lit';\n\nexport default {\n  component: 'demo-button',\n  render: (args) => html`\n    <demo-alert>\n      Alert text\n      <demo-button ?primary=${args.primary} label=${args.label}></demo-button>\n    </demo-alert>\n  `,\n};\n\nexport const DefaultInAlert = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const PrimaryInAlert = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\nimport html from 'lit';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  render: (args) => html`\n    <demo-alert>\n      Alert text\n      <demo-button ?primary=${args.primary} label=${args.label}></demo-button>\n    </demo-alert>\n  `,\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const DefaultInAlert: Story = {\n  args: {\n    label: 'Button',\n  },\n};\n\nexport const PrimaryInAlert: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport html from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  render: (args) => html`\n    <demo-alert>\n      Alert text\n      <demo-button ?primary=${args.primary} label=${args.label}></demo-button>\n    </demo-alert>\n  `,\n});\n\nexport const DefaultInAlert = meta.story({\n  args: {\n    label: 'Button',\n  },\n});\n\nexport const PrimaryInAlert = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport html from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  render: (args) => html`\n    <demo-alert>\n      Alert text\n      <demo-button ?primary=${args.primary} label=${args.label}></demo-button>\n    </demo-alert>\n  `,\n});\n\nexport const DefaultInAlert = meta.story({\n  args: {\n    label: 'Button',\n  },\n});\n\nexport const PrimaryInAlert = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n```\n\n```tsx filename=\"Button.stories.tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Alert } from './Alert';\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  render: (args) => (\n    <Alert>\n      Alert text\n      <Button {...args} />\n    </Alert>\n  ),\n});\n\nexport const DefaultInAlert = meta.story({\n  args: {\n    label: 'Button',\n  },\n});\n\nexport const PrimaryInAlert = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"Button.stories.jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Alert } from './Alert';\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  render: (args) => (\n    <Alert>\n      Alert text\n      <Button {...args} />\n    </Alert>\n  ),\n});\n\nexport const DefaultInAlert = meta.story({\n  args: {\n    label: 'Button',\n  },\n});\n\nexport const PrimaryInAlert = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/render-custom-in-story.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, type StoryObj, argsToTemplate } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const PrimaryInAlert: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n  render: (args) => ({\n    props: args,\n    template: `\n      <demo-alert>\n        Alert text\n        <demo-button ${argsToTemplate(args)}></demo-button>\n      </demo-alert>\n    `,\n  }),\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { argsToTemplate } from '@storybook/angular';\n\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const PrimaryInAlert = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n  render: (args) => ({\n    props: args,\n    template: `\n      <demo-alert>\n        Alert text\n        <demo-button ${argsToTemplate(args)}></demo-button>\n      </demo-alert>\n    `,\n  }),\n});\n```\n\n```jsx filename=\"Button.stories.jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Alert } from './Alert';\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const PrimaryInAlert = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n  render: (args) => (\n    <Alert>\n      Alert text\n      <Button {...args} />\n    </Alert>\n  ),\n};\n```\n\n```tsx filename=\"Button.stories.tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Alert } from './Alert';\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const PrimaryInAlert: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n  render: (args) => (\n    <Alert>\n      Alert text\n      <Button {...args} />\n    </Alert>\n  ),\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport Alert from './Alert.vue';\nimport Button from './Button.vue';\n\nexport default {\n  component: Button,\n};\n\nexport const PrimaryInAlert = {\n  render: (args) => ({\n    components: { Alert, Button },\n    setup() {\n      return { args };\n    },\n    template: '<Alert><Button v-bind=\"args\" /></Alert>',\n  }),\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport Alert from './Alert.vue';\nimport Button from './Button.vue';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const PrimaryInAlert: Story = {\n  render: (args) => ({\n    components: { Alert, Button },\n    setup() {\n      return { args };\n    },\n    template: '<Alert><Button v-bind=\"args\" /></Alert>',\n  }),\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Alert from './Alert.vue';\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const PrimaryInAlert = meta.story({\n  render: (args) => ({\n    components: { Alert, Button },\n    setup() {\n      return { args };\n    },\n    template: '<Alert><Button v-bind=\"args\" /></Alert>',\n  }),\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Alert from './Alert.vue';\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const PrimaryInAlert = meta.story({\n  render: (args) => ({\n    components: { Alert, Button },\n    setup() {\n      return { args };\n    },\n    template: '<Alert><Button v-bind=\"args\" /></Alert>',\n  }),\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport html from 'lit';\n\nexport default {\n  component: 'demo-button',\n};\n\nexport const PrimaryInAlert = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n  render: (args) => html`\n    <demo-alert>\n      Alert text\n      <demo-button ?primary=${args.primary} label=${args.label}></demo-button>\n    </demo-alert>\n  `,\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\nimport html from 'lit';\n\nconst meta: Meta = {\n  component: 'demo-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const PrimaryInAlert: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n  render: (args) => html`\n    <demo-alert>\n      Alert text\n      <demo-button ?primary=${args.primary} label=${args.label}></demo-button>\n    </demo-alert>\n  `,\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport html from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const PrimaryInAlert = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n  render: (args) => html`\n    <demo-alert>\n      Alert text\n      <demo-button ?primary=${args.primary} label=${args.label}></demo-button>\n    </demo-alert>\n  `,\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport html from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const PrimaryInAlert = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n  render: (args) => html`\n    <demo-alert>\n      Alert text\n      <demo-button ?primary=${args.primary} label=${args.label}></demo-button>\n    </demo-alert>\n  `,\n});\n```\n\n```tsx filename=\"Button.stories.tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Alert } from './Alert';\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const PrimaryInAlert = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n  render: (args) => (\n    <Alert>\n      Alert text\n      <Button {...args} />\n    </Alert>\n  ),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"Button.stories.jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Alert } from './Alert';\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const PrimaryInAlert = meta.story({\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n  render: (args) => (\n    <Alert>\n      Alert text\n      <Button {...args} />\n    </Alert>\n  ),\n});\n```\n"
  },
  {
    "path": "docs/_snippets/reuse-args-test.md",
    "content": "```js filename=\"Button.test.js|jsx\" renderer=\"react\" language=\"js\"\nimport { render, screen } from '@testing-library/react';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\nimport * as stories from './Button.stories';\n\nconst { Primary } = composeStories(stories);\n\ntest('reuses args from composed story', () => {\n  render(<Primary />);\n\n  const buttonElement = screen.getByRole('button');\n  // Testing against values coming from the story itself! No need for duplication\n  expect(buttonElement.textContent).toEqual(Primary.args.label);\n});\n```\n\n```ts filename=\"Button.test.ts|tsx\" renderer=\"react\" language=\"ts\"\nimport { render, screen } from '@testing-library/react';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\nimport * as stories from './Button.stories';\n\nconst { Primary } = composeStories(stories);\n\ntest('reuses args from composed story', () => {\n  render(<Primary />);\n\n  const buttonElement = screen.getByRole('button');\n  // Testing against values coming from the story itself! No need for duplication\n  expect(buttonElement.textContent).toEqual(Primary.args.label);\n});\n```\n\n```js filename=\"tests/Button.test.js\" renderer=\"vue\" language=\"js\"\nimport { render, screen } from '@testing-library/vue';\n\nimport { composeStories } from '@storybook/vue3-vite';\n\nimport * as stories from './Button.stories';\n\nconst { Primary } = composeStories(stories);\n\ntest('reuses args from composed story', () => {\n  render(Primary());\n\n  const buttonElement = screen.getByRole('button');\n  // Testing against values coming from the story itself! No need for duplication\n  expect(buttonElement.textContent).toEqual(Primary.args.label);\n});\n```\n\n```ts filename=\"tests/Button.test.ts\" renderer=\"vue\" language=\"ts\"\nimport { render, screen } from '@testing-library/vue';\n\nimport { composeStories } from '@storybook/vue3-vite';\n\nimport * as stories from './Button.stories';\n\nconst { Primary } = composeStories(stories);\n\ntest('reuses args from composed story', () => {\n  render(Primary());\n\n  const buttonElement = screen.getByRole('button');\n  // Testing against values coming from the story itself! No need for duplication\n  expect(buttonElement.textContent).toEqual(Primary.args.label);\n});\n```\n"
  },
  {
    "path": "docs/_snippets/rsc-feature-flag.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // ...\n  features: {\n    experimentalRSC: true,\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with nextjs or nextjs-vite\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  // ...\n  features: {\n    experimentalRSC: true,\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with nextjs or nextjs-vite\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // ...\n  features: {\n    experimentalRSC: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with nextjs or nextjs-vite\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // ...\n  features: {\n    experimentalRSC: true,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/rsc-parameter-in-meta.md",
    "content": "```js filename=\"MyServerComponent.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyServerComponent from './MyServerComponent';\n\nexport default {\n  component: MyServerComponent,\n  parameters: {\n    react: { rsc: false },\n  },\n};\n```\n\n```ts filename=\"MyServerComponent.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with nextjs or nextjs-vite\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport MyServerComponent from './MyServerComponent';\n\nconst meta = {\n  component: MyServerComponent,\n  parameters: {\n    react: { rsc: false },\n  },\n} satisfies Meta<typeof MyServerComponent>;\nexport default meta;\n```\n\n```ts filename=\"MyServerComponent.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyServerComponent from './MyServerComponent';\n\nconst meta = preview.meta({\n  component: MyServerComponent,\n  parameters: {\n    react: { rsc: false },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyServerComponent.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyServerComponent from './MyServerComponent';\n\nconst meta = preview.meta({\n  component: MyServerComponent,\n  parameters: {\n    react: { rsc: false },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/seo-description.md",
    "content": "```html filename=\".storybook/manager-head.html\" renderer=\"common\" language=\"js\"\n<meta name=\"description\" content=\"Components for my awesome project\" key=\"desc\" />\n```\n"
  },
  {
    "path": "docs/_snippets/seo-noindex.md",
    "content": "```html filename=\".storybook/manager-head.html\" renderer=\"common\" language=\"js\"\n<meta name=\"robots\" content=\"noindex\" />\n```\n"
  },
  {
    "path": "docs/_snippets/shadow-dom-testing-library-in-preview.md",
    "content": "```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Preview } from '@storybook/web-components-vite';\n\nimport { within as withinShadow } from 'shadow-dom-testing-library';\n\nconst preview: Preview = {\n  // 👇 Augment the canvas with the shadow DOM queries\n  beforeEach({ canvasElement, canvas }) {\n    Object.assign(canvas, { ...withinShadow(canvasElement) });\n  },\n  // ...\n};\n\n// 👇 Extend TypeScript types for safety\nexport type ShadowQueries = ReturnType<typeof withinShadow>;\n\n// Since Storybook@8.6\ndeclare module 'storybook/internal/csf' {\n  interface Canvas extends ShadowQueries {}\n}\n\nexport default preview;\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { within as withinShadow } from 'shadow-dom-testing-library';\n\nexport default {\n  // 👇 Augment the canvas with the shadow DOM queries\n  beforeEach({ canvasElement, canvas }) {\n    Object.assign(canvas, { ...withinShadow(canvasElement) });\n  },\n  // ...\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { within as withinShadow } from 'shadow-dom-testing-library';\n\n// 👇 Extend TypeScript types for safety\nexport type ShadowQueries = ReturnType<typeof withinShadow>;\n\n// Since Storybook@8.6\ndeclare module 'storybook/internal/csf' {\n  interface Canvas extends ShadowQueries {}\n}\n\nexport default definePreview({\n  // 👇 Augment the canvas with the shadow DOM queries\n  beforeEach({ canvasElement, canvas }) {\n    Object.assign(canvas, { ...withinShadow(canvasElement) });\n  },\n  // ...\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { within as withinShadow } from 'shadow-dom-testing-library';\n\nexport default definePreview({\n  // 👇 Augment the canvas with the shadow DOM queries\n  beforeEach({ canvasElement, canvas }) {\n    Object.assign(canvas, { ...withinShadow(canvasElement) });\n  },\n  // ...\n});\n```\n"
  },
  {
    "path": "docs/_snippets/shadow-dom-testing-library-in-story.md",
    "content": "```ts filename=\"Example.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nexport const ShadowDOMExample: Story = {\n  async play({ canvas }) {\n    // 👇 Will find an element even if it's within a shadow root\n    const button = await canvas.findByShadowRole('button', { name: /Reset/i });\n  },\n};\n```\n\n```js filename=\"Example.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport const ShadowDOMExample = {\n  async play({ canvas }) {\n    // 👇 Will find an element even if it's within a shadow root\n    const button = await canvas.findByShadowRole('button', { name: /Reset/i });\n  },\n};\n```\n\n```js filename=\"Example.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nexport const ShadowDOMExample = meta.story({\n  async play({ canvas }) {\n    // 👇 Will find an element even if it's within a shadow root\n    const button = await canvas.findByShadowRole('button', { name: /Reset/i });\n  },\n});\n```\n\n```ts filename=\"Example.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nexport const ShadowDOMExample = meta.story({\n  async play({ canvas }) {\n    // 👇 Will find an element even if it's within a shadow root\n    const button = await canvas.findByShadowRole('button', { name: /Reset/i });\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/simple-page-implementation.md",
    "content": "```ts filename=\"your-page.component.ts\" renderer=\"angular\" language=\"ts\"\nimport { Component, Input } from '@angular/core';\n\n@Component({\n  selector: 'document-screen',\n  template: `\n    <page-layout [user]=\"user\">\n      <document-header [document]=\"document\"></document-header>\n      <document-list [documents]=\"subdocuments\"></document-list>\n    </page-layout>\n  `,\n})\nexport class DocumentScreen {\n  @Input()\n  user: any = { id: 0, name: 'Some User' };\n\n  @Input()\n  document: any = { id: 0, title: 'Some Title' };\n\n  @Input()\n  subdocuments: any = [];\n}\n```\n\n```js filename=\"YourPage.js|jsx\" renderer=\"react\" language=\"js\"\nimport React from 'react';\n\nimport { PageLayout } from './PageLayout';\nimport { DocumentHeader } from './DocumentHeader';\nimport { DocumentList } from './DocumentList';\n\nexport function DocumentScreen({ user, document, subdocuments }) {\n  return (\n    <PageLayout user={user}>\n      <DocumentHeader document={document} />\n      <DocumentList documents={subdocuments} />\n    </PageLayout>\n  );\n}\n```\n\n```tsx filename=\"YourPage.ts|tsx\" renderer=\"react\" language=\"ts\"\nimport PageLayout from './PageLayout';\nimport Document from './Document';\nimport SubDocuments from './SubDocuments';\nimport DocumentHeader from './DocumentHeader';\nimport DocumentList from './DocumentList';\n\nexport interface DocumentScreenProps {\n  user?: {};\n  document?: Document;\n  subdocuments?: SubDocuments[];\n}\n\nexport function DocumentScreen({ user, document, subdocuments }: DocumentScreenProps) {\n  return (\n    <PageLayout user={user}>\n      <DocumentHeader document={document} />\n      <DocumentList documents={subdocuments} />\n    </PageLayout>\n  );\n}\n```\n\n```js filename=\"YourPage.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { PageLayout } from './PageLayout';\nimport { DocumentHeader } from './DocumentHeader';\nimport { DocumentList } from './DocumentList';\n\nexport function DocumentScreen({ user, document, subdocuments }) {\n  return (\n    <PageLayout user={user}>\n      <DocumentHeader document={document} />\n      <DocumentList documents={subdocuments} />\n    </PageLayout>\n  );\n}\n```\n\n```tsx filename=\"YourPage.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport PageLayout from './PageLayout';\nimport Document from './Document';\nimport SubDocuments from './SubDocuments';\nimport DocumentHeader from './DocumentHeader';\nimport DocumentList from './DocumentList';\n\nexport interface DocumentScreen {\n  user?: {};\n  document?: Document;\n  subdocuments?: SubDocuments[];\n}\n\nfunction DocumentScreen({ user, document, subdocuments }) {\n  return (\n    <PageLayout user={user}>\n      <DocumentHeader document={document} />\n      <DocumentList documents={subdocuments} />\n    </PageLayout>\n  );\n}\n```\n\n```svelte filename=\"YourPage.svelte\" renderer=\"svelte\" language=\"js\"\n<script>\n  import PageLayout from './PageLayout.svelte';\n  import DocumentHeader from './DocumentHeader.svelte';\n  import DocumentList from './DocumentList.svelte';\n\n  export let user = {};\n  export let document = {};\n  export let subdocuments = [];\n</script>\n\n<div>\n  <PageLayout {user}>\n    <DocumentHeader {document} />\n    <DocumentList documents=\"{subdocuments}\" />\n  </PageLayout>\n</div>\n```\n\n```svelte filename=\"YourPage.svelte\" renderer=\"svelte\" language=\"ts\"\n<script lang=\"ts\">\n  import PageLayout from './PageLayout.svelte';\n  import DocumentHeader from './DocumentHeader.svelte';\n  import DocumentList from './DocumentList.svelte';\n\n  export let user: Record<string, unknown> = {};\n  export let document: Record<string, unknown> = {};\n  export let subdocuments: Record<string, unknown>[] = [];\n</script>\n\n<div>\n  <PageLayout {user}>\n    <DocumentHeader {document} />\n    <DocumentList documents=\"{subdocuments}\" />\n  </PageLayout>\n</div>\n```\n\n```html filename=\"YourPage.vue\" renderer=\"vue\" language=\"js\"\n<template>\n  <PageLayout :user=\"user\">\n    <DocumentHeader :document=\"document\" />\n    <DocumentList :documents=\"subdocuments\" />\n  </PageLayout>\n</template>\n\n<script>\n  import PageLayout from './PageLayout';\n  import DocumentHeader from './DocumentHeader';\n  import DocumentList from './DocumentList';\n  import { reactive } from 'vue';\n\n  export default {\n    name: 'DocumentScreen',\n    components: { PageLayout, DocumentHeader, DocumentList },\n    props: {\n      user: {\n        type: String,\n        default: 'N/A',\n      },\n      document: {\n        type: Object,\n        default: () => ({\n          id: 1,\n          title: 'A document',\n          content: 'Lorem Ipsum',\n        }),\n      },\n      subdocuments: {\n        type: Array,\n        default: () => [],\n      },\n    },\n    setup(props) {\n      props = reactive(props);\n      return {\n        /**\n         * What will be returned here will available to the component\n         * Functions referenced here will act like methods\n         */\n      };\n    },\n  };\n</script>\n```\n\n```js filename=\"YourPage.js\" renderer=\"web-components\" language=\"js\"\nimport { LitElement, html } from 'lit-element';\n\nclass DocumentScreen extends LitElement {\n  static get properties() {\n    return {\n      data: { type: Object },\n    };\n  }\n\n  constructor() {\n    super();\n    this.data = {};\n  }\n\n  render() {\n    const { user, document, subdocuments } = this.data;\n    return html`\n      <demo-page-layout .user=${user}>\n        <demo-document-header .document=${document}></demo-document-header>\n        <demo-document-list .documents=${subdocuments}></demo-document-list>\n      </demo-page-layout>\n    `;\n  }\n}\n\ncustomElements.define('demo-document-screen', DocumentScreen);\n```\n\n```ts filename=\"YourPage.ts\" renderer=\"web-components\" language=\"ts\"\nimport { LitElement, html } from 'lit-element';\n\n@customElement('demo-document-screen')\nclass DocumentScreen extends LitElement {\n  @property({ type: Object })\n  data: {\n    user: Record<string, unknown>;\n    document: Record<string, unknown>;\n    subdocuments: Array<Record<string, unknown>>;\n  } = {};\n\n  constructor() {\n    super();\n  }\n\n  render() {\n    const { user, document, subdocuments } = this.data;\n    return html`\n      <demo-page-layout .user=${user}>\n        <demo-document-header .document=${document}></demo-document-header>\n        <demo-document-list .documents=${subdocuments}></demo-document-list>\n      </demo-page-layout>\n    `;\n  }\n}\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    'demo-document-screen': DocumentScreen;\n  }\n}\n```\n"
  },
  {
    "path": "docs/_snippets/single-story-test.md",
    "content": "```js filename=\"Form.test.js|jsx\" renderer=\"react\" language=\"js\"\nimport { fireEvent, screen } from '@testing-library/react';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { composeStory } from '@storybook/your-framework';\n\nimport Meta, { ValidForm as ValidFormStory } from './LoginForm.stories';\n\nconst ValidForm = composeStory(ValidFormStory, Meta);\n\ntest('Validates form', async () => {\n  await ValidForm.run();\n\n  const buttonElement = screen.getByRole('button', {\n    name: 'Submit',\n  });\n\n  fireEvent.click(buttonElement);\n\n  const isFormValid = screen.getByLabelText('invalid-form');\n  expect(isFormValid).not.toBeInTheDocument();\n});\n```\n\n```ts filename=\"Form.test.ts|tsx\" renderer=\"react\" language=\"ts\"\nimport { fireEvent, screen } from '@testing-library/react';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { composeStory } from '@storybook/your-framework';\n\nimport Meta, { ValidForm as ValidFormStory } from './LoginForm.stories';\n\nconst ValidForm = composeStory(ValidFormStory, Meta);\n\ntest('Validates form', async () => {\n  await ValidForm.run();\n\n  const buttonElement = screen.getByRole('button', {\n    name: 'Submit',\n  });\n\n  fireEvent.click(buttonElement);\n\n  const isFormValid = screen.getByLabelText('invalid-form');\n  expect(isFormValid).not.toBeInTheDocument();\n});\n```\n\n```js filename=\"tests/Form.test.js\" renderer=\"vue\" language=\"js\"\nimport { fireEvent, screen } from '@testing-library/vue';\n\nimport { composeStory } from '@storybook/vue3-vite';\n\nimport Meta, { ValidForm as ValidFormStory } from './LoginForm.stories';\n\nconst ValidForm = composeStory(ValidFormStory, Meta);\n\ntest('Validates form', async () => {\n  await ValidForm.run();\n\n  const buttonElement = screen.getByRole('button', {\n    name: 'Submit',\n  });\n\n  fireEvent.click(buttonElement);\n\n  const isFormValid = screen.getByLabelText('invalid-form');\n  expect(isFormValid).not.toBeInTheDocument();\n});\n```\n\n```ts filename=\"tests/Form.test.ts\" renderer=\"vue\" language=\"ts\"\nimport { fireEvent, screen } from '@testing-library/vue';\n\nimport { composeStory } from '@storybook/vue3-vite';\n\nimport Meta, { ValidForm as ValidFormStory } from './LoginForm.stories';\n\nconst ValidForm = composeStory(ValidFormStory, Meta);\n\ntest('Validates form', async () => {\n  await ValidForm.run();\n\n  const buttonElement = screen.getByRole('button', {\n    name: 'Submit',\n  });\n\n  fireEvent.click(buttonElement);\n\n  const isFormValid = screen.getByLabelText('invalid-form');\n  expect(isFormValid).not.toBeInTheDocument();\n});\n```\n"
  },
  {
    "path": "docs/_snippets/snapshot-tests-portable-stories.md",
    "content": "```js filename=\"storybook.test.js\" renderer=\"common\" language=\"js\" tabTitle=\"jest\"\nimport path from 'path';\nimport * as glob from 'glob';\n\nimport { describe, test, expect } from '@jest/globals';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\nconst compose = (entry) => {\n  try {\n    return composeStories(entry);\n  } catch (e) {\n    throw new Error(\n      `There was an issue composing stories for the module: ${JSON.stringify(entry)}, ${e}`,\n    );\n  }\n};\n\nfunction getAllStoryFiles() {\n  // Place the glob you want to match your stories files\n  const storyFiles = glob.sync(\n    path.join(process.cwd(), 'stories/**/*.{stories,story}.{js,jsx,mjs,ts,tsx}'),\n  );\n\n  return storyFiles.map((filePath) => {\n    const storyFile = require(filePath);\n    const storyDir = path.dirname(filePath);\n    const componentName = path.basename(filePath).replace(/\\.(stories|story)\\.[^/.]+$/, '');\n\n    return { filePath, storyFile, storyDir, componentName };\n  });\n}\n\ndescribe('Stories Snapshots', () => {\n  getAllStoryFiles().forEach(({ storyFile, componentName }) => {\n    const meta = storyFile.default;\n    const title = meta.title || componentName;\n\n    describe(title, () => {\n      const stories = Object.entries(compose(storyFile)).map(([name, story]) => ({ name, story }));\n\n      if (stories.length <= 0) {\n        throw new Error(\n          `No stories found for this module: ${title}. Make sure there is at least one valid story for this module.`,\n        );\n      }\n\n      stories.forEach(({ name, story }) => {\n        test(name, async () => {\n          const mounted = render(story());\n          // Ensures a consistent snapshot by waiting for the component to render by adding a delay of 1 ms before taking the snapshot.\n          await new Promise((resolve) => setTimeout(resolve, 1));\n          expect(mounted.container).toMatchSnapshot();\n        });\n      });\n    });\n  });\n});\n```\n\n```ts filename=\"storybook.test.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"jest\"\n// Replace your-framework with one of the supported Storybook frameworks (react, vue3)\nimport type { Meta, StoryFn } from '@storybook/your-framework';\n\nimport path from 'path';\nimport * as glob from 'glob';\n\nimport { describe, test, expect } from '@jest/globals';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\ntype StoryFile = {\n  default: Meta;\n  [name: string]: StoryFn | Meta;\n};\n\nconst compose = (entry: StoryFile): ReturnType<typeof composeStories<StoryFile>> => {\n  try {\n    return composeStories(entry);\n  } catch (e) {\n    throw new Error(\n      `There was an issue composing stories for the module: ${JSON.stringify(entry)}, ${e}`,\n    );\n  }\n};\n\nfunction getAllStoryFiles() {\n  // Place the glob you want to match your stories files\n  const storyFiles = glob.sync(\n    path.join(process.cwd(), 'stories/**/*.{stories,story}.{js,jsx,mjs,ts,tsx}'),\n  );\n\n  return storyFiles.map((filePath) => {\n    const storyFile = require(filePath);\n    const storyDir = path.dirname(filePath);\n    const componentName = path.basename(filePath).replace(/\\.(stories|story)\\.[^/.]+$/, '');\n\n    return { filePath, storyFile, storyDir, componentName };\n  });\n}\n\ndescribe('Stories Snapshots', () => {\n  getAllStoryFiles().forEach(({ storyFile, componentName }) => {\n    const meta = storyFile.default;\n    const title = meta.title || componentName;\n\n    describe(title, () => {\n      const stories = Object.entries(compose(storyFile)).map(([name, story]) => ({ name, story }));\n\n      if (stories.length <= 0) {\n        throw new Error(\n          `No stories found for this module: ${title}. Make sure there is at least one valid story for this module.`,\n        );\n      }\n\n      stories.forEach(({ name, story }) => {\n        test(name, async () => {\n          await story.run();\n          // Ensures a consistent snapshot by waiting for the component to render by adding a delay of 1 ms before taking the snapshot.\n          await new Promise((resolve) => setTimeout(resolve, 1));\n          expect(document.body.firstChild).toMatchSnapshot();\n        });\n      });\n    });\n  });\n});\n```\n\n```js filename=\"storybook.test.js\" renderer=\"common\" language=\"js\" tabTitle=\"vitest\"\n// @vitest-environment jsdom\n\nimport path from 'path';\nimport { describe, expect, test } from 'vitest';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\nconst compose = (entry) => {\n  try {\n    return composeStories(entry);\n  } catch (error) {\n    throw new Error(\n      `There was an issue composing stories for the module: ${JSON.stringify(entry)}, ${error}`,\n    );\n  }\n};\nfunction getAllStoryFiles() {\n  // Place the glob you want to match your story files\n  const storyFiles = Object.entries(\n    import.meta.glob('./stories/**/*.(stories|story).@(js|jsx|mjs|ts|tsx)', {\n      eager: true,\n    }),\n  );\n\n  return storyFiles.map(([filePath, storyFile]) => {\n    const storyDir = path.dirname(filePath);\n    const componentName = path.basename(filePath).replace(/\\.(stories|story)\\.[^/.]+$/, '');\n    return { filePath, storyFile, componentName, storyDir };\n  });\n}\ndescribe('Stories Snapshots', () => {\n  getAllStoryFiles().forEach(({ storyFile, componentName }) => {\n    const meta = storyFile.default;\n    const title = meta.title || componentName;\n\n    describe(title, () => {\n      const stories = Object.entries(compose(storyFile)).map(([name, story]) => ({ name, story }));\n\n      if (stories.length <= 0) {\n        throw new Error(\n          `No stories found for this module: ${title}. Make sure there is at least one valid story for this module.`,\n        );\n      }\n\n      stories.forEach(({ name, story }) => {\n        test(name, async () => {\n          await story.run();\n          // Ensures a consistent snapshot by waiting for the component to render by adding a delay of 1 ms before taking the snapshot.\n          await new Promise((resolve) => setTimeout(resolve, 1));\n          expect(document.body.firstChild).toMatchSnapshot();\n        });\n      });\n    });\n  });\n});\n```\n\n```ts filename=\"storybook.test.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"vitest\"\n// @vitest-environment jsdom\n\n// Replace your-framework with one of the supported Storybook frameworks (react, vue3)\nimport type { Meta, StoryFn } from '@storybook/your-framework';\n\nimport path from 'path';\nimport { describe, expect, test } from 'vitest';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport { composeStories } from '@storybook/your-framework';\n\ntype StoryFile = {\n  default: Meta;\n  [name: string]: StoryFn | Meta;\n};\n\nconst compose = (entry: StoryFile): ReturnType<typeof composeStories<StoryFile>> => {\n  try {\n    return composeStories(entry);\n  } catch (e) {\n    throw new Error(\n      `There was an issue composing stories for the module: ${JSON.stringify(entry)}, ${e}`,\n    );\n  }\n};\n\nfunction getAllStoryFiles() {\n  // Place the glob you want to match your story files\n  const storyFiles = Object.entries(\n    import.meta.glob<StoryFile>('./stories/**/*.(stories|story).@(js|jsx|mjs|ts|tsx)', {\n      eager: true,\n    }),\n  );\n\n  return storyFiles.map(([filePath, storyFile]) => {\n    const storyDir = path.dirname(filePath);\n    const componentName = path.basename(filePath).replace(/\\.(stories|story)\\.[^/.]+$/, '');\n    return { filePath, storyFile, componentName, storyDir };\n  });\n}\n\ndescribe('Stories Snapshots', () => {\n  getAllStoryFiles().forEach(({ storyFile, componentName }) => {\n    const meta = storyFile.default;\n    const title = meta.title || componentName;\n\n    describe(title, () => {\n      const stories = Object.entries(compose(storyFile)).map(([name, story]) => ({ name, story }));\n\n      if (stories.length <= 0) {\n        throw new Error(\n          `No stories found for this module: ${title}. Make sure there is at least one valid story for this module.`,\n        );\n      }\n\n      stories.forEach(({ name, story }) => {\n        test(name, async () => {\n          await story.run();\n          // Ensures a consistent snapshot by waiting for the component to render by adding a delay of 1 ms before taking the snapshot.\n          await new Promise((resolve) => setTimeout(resolve, 1));\n          expect(document.body.firstChild).toMatchSnapshot();\n        });\n      });\n    });\n  });\n});\n```\n"
  },
  {
    "path": "docs/_snippets/story-description-and-summary.md",
    "content": "```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\n/**\n * Primary buttons are used for the main action in a view.\n * There should not be more than one primary button per view.\n *\n * @summary for the main action in a view\n */\nexport const Primary = {\n  args: { primary: true },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * Primary buttons are used for the main action in a view.\n * There should not be more than one primary button per view.\n *\n * @summary for the main action in a view\n */\nexport const Primary: Story = {\n  args: { primary: true },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\n/**\n * Primary buttons are used for the main action in a view.\n * There should not be more than one primary button per view.\n *\n * @summary for the main action in a view\n */\nexport const Primary = meta.story({\n  args: { primary: true },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\n/**\n * Primary buttons are used for the main action in a view.\n * There should not be more than one primary button per view.\n *\n * @summary for the main action in a view\n */\nexport const Primary = meta.story({\n  args: { primary: true },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-add-command.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook@latest add @storybook/addon-a11y\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx storybook@latest add @storybook/addon-a11y\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn dlx storybook@latest add @storybook/addon-a11y\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-compiler-babel-auto-install.md",
    "content": "```sh renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook@latest add @storybook/addon-webpack5-compiler-babel\n```\n\n```sh renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx storybook@latest add @storybook/addon-webpack5-compiler-babel\n```\n\n```sh renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn dlx storybook@latest add @storybook/addon-webpack5-compiler-babel\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-compiler-swc-auto-install.md",
    "content": "```sh renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook@latest add @storybook/addon-webpack5-compiler-swc\n```\n\n```sh renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx storybook@latest add @storybook/addon-webpack5-compiler-swc\n```\n\n```sh renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn dlx storybook@latest add @storybook/addon-webpack5-compiler-swc\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-controls-custom-matchers.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-css-example.md",
    "content": "```ts filename=\"src/OutlineCSS.ts\" renderer=\"common\" language=\"ts\"\nimport { dedent } from 'ts-dedent';\n\nexport default function outlineCSS(selector: string) {\n  return dedent /* css */ `\n    ${selector} body {\n      outline: 1px solid #2980b9 !important;\n    }\n\n    ${selector} article {\n      outline: 1px solid #3498db !important;\n    }\n\n    ${selector} nav {\n      outline: 1px solid #0088c3 !important;\n    }\n\n    ${selector} aside {\n      outline: 1px solid #33a0ce !important;\n    }\n\n    ${selector} section {\n      outline: 1px solid #66b8da !important;\n    }\n\n    ${selector} header {\n      outline: 1px solid #99cfe7 !important;\n    }\n\n    ${selector} footer {\n      outline: 1px solid #cce7f3 !important;\n    }\n\n    ${selector} h1 {\n      outline: 1px solid #162544 !important;\n    }\n\n    ${selector} h2 {\n      outline: 1px solid #314e6e !important;\n    }\n\n    ${selector} h3 {\n      outline: 1px solid #3e5e85 !important;\n    }\n\n    ${selector} h4 {\n      outline: 1px solid #449baf !important;\n    }\n\n    ${selector} h5 {\n      outline: 1px solid #c7d1cb !important;\n    }\n\n    ${selector} h6 {\n      outline: 1px solid #4371d0 !important;\n    }\n\n    ${selector} main {\n      outline: 1px solid #2f4f90 !important;\n    }\n\n    ${selector} address {\n      outline: 1px solid #1a2c51 !important;\n    }\n\n    ${selector} div {\n      outline: 1px solid #036cdb !important;\n    }\n\n    ${selector} p {\n      outline: 1px solid #ac050b !important;\n    }\n\n    ${selector} hr {\n      outline: 1px solid #ff063f !important;\n    }\n\n    ${selector} pre {\n      outline: 1px solid #850440 !important;\n    }\n\n    ${selector} blockquote {\n      outline: 1px solid #f1b8e7 !important;\n    }\n\n    ${selector} ol {\n      outline: 1px solid #ff050c !important;\n    }\n\n    ${selector} ul {\n      outline: 1px solid #d90416 !important;\n    }\n\n    ${selector} li {\n      outline: 1px solid #d90416 !important;\n    }\n\n    ${selector} dl {\n      outline: 1px solid #fd3427 !important;\n    }\n\n    ${selector} dt {\n      outline: 1px solid #ff0043 !important;\n    }\n\n    ${selector} dd {\n      outline: 1px solid #e80174 !important;\n    }\n\n    ${selector} figure {\n      outline: 1px solid #ff00bb !important;\n    }\n\n    ${selector} figcaption {\n      outline: 1px solid #bf0032 !important;\n    }\n\n    ${selector} table {\n      outline: 1px solid #00cc99 !important;\n    }\n\n    ${selector} caption {\n      outline: 1px solid #37ffc4 !important;\n    }\n\n    ${selector} thead {\n      outline: 1px solid #98daca !important;\n    }\n\n    ${selector} tbody {\n      outline: 1px solid #64a7a0 !important;\n    }\n\n    ${selector} tfoot {\n      outline: 1px solid #22746b !important;\n    }\n\n    ${selector} tr {\n      outline: 1px solid #86c0b2 !important;\n    }\n\n    ${selector} th {\n      outline: 1px solid #a1e7d6 !important;\n    }\n\n    ${selector} td {\n      outline: 1px solid #3f5a54 !important;\n    }\n\n    ${selector} col {\n      outline: 1px solid #6c9a8f !important;\n    }\n\n    ${selector} colgroup {\n      outline: 1px solid #6c9a9d !important;\n    }\n\n    ${selector} button {\n      outline: 1px solid #da8301 !important;\n    }\n\n    ${selector} datalist {\n      outline: 1px solid #c06000 !important;\n    }\n\n    ${selector} fieldset {\n      outline: 1px solid #d95100 !important;\n    }\n\n    ${selector} form {\n      outline: 1px solid #d23600 !important;\n    }\n\n    ${selector} input {\n      outline: 1px solid #fca600 !important;\n    }\n\n    ${selector} keygen {\n      outline: 1px solid #b31e00 !important;\n    }\n\n    ${selector} label {\n      outline: 1px solid #ee8900 !important;\n    }\n\n    ${selector} legend {\n      outline: 1px solid #de6d00 !important;\n    }\n\n    ${selector} meter {\n      outline: 1px solid #e8630c !important;\n    }\n\n    ${selector} optgroup {\n      outline: 1px solid #b33600 !important;\n    }\n\n    ${selector} option {\n      outline: 1px solid #ff8a00 !important;\n    }\n\n    ${selector} output {\n      outline: 1px solid #ff9619 !important;\n    }\n\n    ${selector} progress {\n      outline: 1px solid #e57c00 !important;\n    }\n\n    ${selector} select {\n      outline: 1px solid #e26e0f !important;\n    }\n\n    ${selector} textarea {\n      outline: 1px solid #cc5400 !important;\n    }\n\n    ${selector} details {\n      outline: 1px solid #33848f !important;\n    }\n\n    ${selector} summary {\n      outline: 1px solid #60a1a6 !important;\n    }\n\n    ${selector} command {\n      outline: 1px solid #438da1 !important;\n    }\n\n    ${selector} menu {\n      outline: 1px solid #449da6 !important;\n    }\n\n    ${selector} del {\n      outline: 1px solid #bf0000 !important;\n    }\n\n    ${selector} ins {\n      outline: 1px solid #400000 !important;\n    }\n\n    ${selector} img {\n      outline: 1px solid #22746b !important;\n    }\n\n    ${selector} iframe {\n      outline: 1px solid #64a7a0 !important;\n    }\n\n    ${selector} embed {\n      outline: 1px solid #98daca !important;\n    }\n\n    ${selector} object {\n      outline: 1px solid #00cc99 !important;\n    }\n\n    ${selector} param {\n      outline: 1px solid #37ffc4 !important;\n    }\n\n    ${selector} video {\n      outline: 1px solid #6ee866 !important;\n    }\n\n    ${selector} audio {\n      outline: 1px solid #027353 !important;\n    }\n\n    ${selector} source {\n      outline: 1px solid #012426 !important;\n    }\n\n    ${selector} canvas {\n      outline: 1px solid #a2f570 !important;\n    }\n\n    ${selector} track {\n      outline: 1px solid #59a600 !important;\n    }\n\n    ${selector} map {\n      outline: 1px solid #7be500 !important;\n    }\n\n    ${selector} area {\n      outline: 1px solid #305900 !important;\n    }\n\n    ${selector} a {\n      outline: 1px solid #ff62ab !important;\n    }\n\n    ${selector} em {\n      outline: 1px solid #800b41 !important;\n    }\n\n    ${selector} strong {\n      outline: 1px solid #ff1583 !important;\n    }\n\n    ${selector} i {\n      outline: 1px solid #803156 !important;\n    }\n\n    ${selector} b {\n      outline: 1px solid #cc1169 !important;\n    }\n\n    ${selector} u {\n      outline: 1px solid #ff0430 !important;\n    }\n\n    ${selector} s {\n      outline: 1px solid #f805e3 !important;\n    }\n\n    ${selector} small {\n      outline: 1px solid #d107b2 !important;\n    }\n\n    ${selector} abbr {\n      outline: 1px solid #4a0263 !important;\n    }\n\n    ${selector} q {\n      outline: 1px solid #240018 !important;\n    }\n\n    ${selector} cite {\n      outline: 1px solid #64003c !important;\n    }\n\n    ${selector} dfn {\n      outline: 1px solid #b4005a !important;\n    }\n\n    ${selector} sub {\n      outline: 1px solid #dba0c8 !important;\n    }\n\n    ${selector} sup {\n      outline: 1px solid #cc0256 !important;\n    }\n\n    ${selector} time {\n      outline: 1px solid #d6606d !important;\n    }\n\n    ${selector} code {\n      outline: 1px solid #e04251 !important;\n    }\n\n    ${selector} kbd {\n      outline: 1px solid #5e001f !important;\n    }\n\n    ${selector} samp {\n      outline: 1px solid #9c0033 !important;\n    }\n\n    ${selector} var {\n      outline: 1px solid #d90047 !important;\n    }\n\n    ${selector} mark {\n      outline: 1px solid #ff0053 !important;\n    }\n\n    ${selector} bdi {\n      outline: 1px solid #bf3668 !important;\n    }\n\n    ${selector} bdo {\n      outline: 1px solid #6f1400 !important;\n    }\n\n    ${selector} ruby {\n      outline: 1px solid #ff7b93 !important;\n    }\n\n    ${selector} rt {\n      outline: 1px solid #ff2f54 !important;\n    }\n\n    ${selector} rp {\n      outline: 1px solid #803e49 !important;\n    }\n\n    ${selector} span {\n      outline: 1px solid #cc2643 !important;\n    }\n\n    ${selector} br {\n      outline: 1px solid #db687d !important;\n    }\n\n    ${selector} wbr {\n      outline: 1px solid #db175b !important;\n    }`;\n}\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-css-helpers.md",
    "content": "```ts filename=\"src/helpers.ts\" renderer=\"common\" language=\"ts\"\nimport { global } from '@storybook/global';\n\nexport const clearStyles = (selector: string | string[]) => {\n  const selectors = Array.isArray(selector) ? selector : [selector];\n  selectors.forEach(clearStyle);\n};\n\nconst clearStyle = (input: string | string[]) => {\n  const selector = typeof input === 'string' ? input : input.join('');\n  const element = global.document.getElementById(selector);\n  if (element && element.parentElement) {\n    element.parentElement.removeChild(element);\n  }\n};\n\nexport const addOutlineStyles = (selector: string, css: string) => {\n  const existingStyle = global.document.getElementById(selector);\n  if (existingStyle) {\n    if (existingStyle.innerHTML !== css) {\n      existingStyle.innerHTML = css;\n    }\n  } else {\n    const style = global.document.createElement('style');\n    style.setAttribute('id', selector);\n    style.innerHTML = css;\n    global.document.head.appendChild(style);\n  }\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-disable-addon.md",
    "content": "```js filename=\"/my-addon/manager.js\" renderer=\"common\" language=\"js\"\naddons.register(ADDON_ID, () => {\n  addons.add(PANEL_ID, {\n    type: types.PANEL,\n    title: 'My Addon',\n    render: () => <div>Addon tab content</div>,\n    paramKey: 'myAddon', // this element\n  });\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-load-external-addons-preset.md",
    "content": "```js filename=\"my-preset/index.js\" renderer=\"common\" language=\"js\"\nfunction managerEntries(entry = []) {\n  return [...entry, import.meta.resolve('my-other-addon/manager')];\n}\n\nconst previewAnnotations = (entry = [], options) => {\n  return [...entry, import.meta.resolve('my-other-addon/preview')];\n};\n\nexport default {\n  managerEntries,\n  previewAnnotations,\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-manager-initial-state.md",
    "content": "```ts filename=\"src/manager.ts\" renderer=\"common\" language=\"ts\"\nimport { addons, types } from 'storybook/manager-api';\nimport { ADDON_ID, TOOL_ID } from './constants';\nimport { Tool } from './Tool';\n\n// Register the addon\naddons.register(ADDON_ID, () => {\n  // Register the tool\n  addons.add(TOOL_ID, {\n    type: types.TOOL,\n    title: 'My addon',\n    match: ({ tabId, viewMode }) => !tabId && viewMode === 'story',\n    render: Tool,\n  });\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-panel-example.md",
    "content": "```js filename=\"addon-panel/manager.js\" renderer=\"common\" language=\"js\"\nimport React from 'react';\n\nimport { AddonPanel } from 'storybook/internal/components';\n\nimport { useGlobals, addons, types } from 'storybook/manager-api';\n\naddons.register('my/panel', () => {\n  addons.add('my-panel-addon/panel', {\n    title: 'Example Storybook panel',\n    //👇 Sets the type of UI element in Storybook\n    type: types.PANEL,\n    render: ({ active }) => (\n      <AddonPanel active={active}>\n        <h2>I'm a panel addon in Storybook</h2>\n      </AddonPanel>\n    ),\n  });\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-panel-initial.md",
    "content": "```js filename=\"my-addon/src/manager.js|ts\" renderer=\"common\" language=\"js\"\nimport React from 'react';\n\nimport { addons, types } from 'storybook/manager-api';\n\nimport { AddonPanel } from 'storybook/internal/components';\n\nconst ADDON_ID = 'myaddon';\nconst PANEL_ID = `${ADDON_ID}/panel`;\n\naddons.register(ADDON_ID, (api) => {\n  addons.add(PANEL_ID, {\n    type: types.PANEL,\n    title: 'My Addon',\n    render: ({ active }) => (\n      <AddonPanel active={active}>\n        <div> Storybook addon panel </div>\n      </AddonPanel>\n    ),\n  });\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-preset-example.md",
    "content": "```js filename=\".storybook/my-addon/preset.js\" renderer=\"common\" language=\"js\"\nexport function previewAnnotations(entry = []) {\n  return [...entry, import.meta.resolve('./defaultParameters')];\n}\n\nexport function managerEntries(entries) {\n  return [...entries, import.meta.resolve('./register')];\n}\n\nexport default {\n  parameters: {\n    backgrounds: {\n      values: [\n        { name: 'light', value: '#F8F8F8' },\n        { name: 'dark', value: '#333333' },\n      ],\n    },\n  },\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-release.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm run release\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm run release\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn release\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-run-dev-mode.md",
    "content": "```sh renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm run start\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm run start\n```\n\n```sh renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn start\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-tab-example.md",
    "content": "```js filename=\"addon-tab/manager.js\" renderer=\"common\" language=\"js\"\nimport React from 'react';\n\nimport { addons, types } from 'storybook/manager-api';\n\naddons.register('my-addon', () => {\n  addons.add('my-addon/tab', {\n    type: types.TAB,\n    title: 'Example Storybook tab',\n    render: () => (\n      <div>\n        <h2>I'm a tabbed addon in Storybook</h2>\n      </div>\n    ),\n  });\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-themes-classname-decorator.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { withThemeByClassName } from '@storybook/addon-themes';\n\nimport '../src/index.css'; // Your application's global CSS file\n\nconst preview = {\n  decorators: [\n    withThemeByClassName({\n      themes: {\n        light: '',\n        dark: 'dark',\n      },\n      defaultTheme: 'light',\n    }),\n  ],\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport { Preview, Renderer } from '@storybook/your-framework';\n\nimport { withThemeByClassName } from '@storybook/addon-themes';\n\nimport '../src/index.css'; // Your application's global CSS file\n\nconst preview: Preview = {\n  decorators: [\n    withThemeByClassName<Renderer>({\n      themes: {\n        light: '',\n        dark: 'dark',\n      },\n      defaultTheme: 'light',\n    }),\n  ],\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { Renderer, definePreview } from '@storybook/your-framework';\n\nimport addonThemes from '@storybook/addon-themes';\n\nimport '../src/index.css'; // Your application's global CSS file\n\nexport default definePreview({\n  addons: [addonThemes()],\n  decorators: [\n    addonThemes.withThemeByClassName<Renderer>({\n      themes: {\n        light: '',\n        dark: 'dark',\n      },\n      defaultTheme: 'light',\n    }),\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport addonThemes from '@storybook/addon-themes';\n\nimport '../src/index.css'; // Your application's global CSS file\n\nexport default definePreview({\n  addons: [addonThemes()],\n  decorators: [\n    addonThemes.withThemeByClassName({\n      themes: {\n        light: '',\n        dark: 'dark',\n      },\n      defaultTheme: 'light',\n    }),\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-themes-data-attribute-decorator.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { withThemeByDataAttribute } from '@storybook/addon-themes';\n\nimport '../src/index.css'; // Your application's global CSS file\n\nconst preview = {\n  decorators: [\n    withThemeByDataAttribute({\n      themes: {\n        light: 'light',\n        dark: 'dark',\n      },\n      defaultTheme: 'light',\n      attributeName: 'data-theme',\n    }),\n  ],\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport { Preview, Renderer } from '@storybook/your-framework';\n\nimport { withThemeByDataAttribute } from '@storybook/addon-themes';\n\nimport '../src/index.css'; // Your application's global CSS file\n\nconst preview: Preview = {\n  decorators: [\n    withThemeByDataAttribute<Renderer>({\n      themes: {\n        light: 'light',\n        dark: 'dark',\n      },\n      defaultTheme: 'light',\n      attributeName: 'data-theme',\n    }),\n  ],\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { Renderer, definePreview } from '@storybook/your-framework';\n\nimport addonThemes from '@storybook/addon-themes';\n\nimport '../src/index.css'; // Your application's global CSS file\n\nexport default definePreview({\n  addons: [addonThemes()],\n  decorators: [\n    addonThemes.withThemeByDataAttribute<Renderer>({\n      themes: {\n        light: 'light',\n        dark: 'dark',\n      },\n      defaultTheme: 'light',\n      attributeName: 'data-theme',\n    }),\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport addonThemes from '@storybook/addon-themes';\n\nimport '../src/index.css'; // Your application's global CSS file\n\nexport default definePreview({\n  addons: [addonThemes()],\n  decorators: [\n    addonThemes.withThemeByDataAttribute({\n      themes: {\n        light: 'light',\n        dark: 'dark',\n      },\n      defaultTheme: 'light',\n      attributeName: 'data-theme',\n    }),\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-themes-jsx-provider-decorator.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { withThemeFromJSXProvider } from '@storybook/addon-themes';\n\nimport { createGlobalStyle, ThemeProvider } from 'styled-components';\nimport { lightTheme, darkTheme } from '../src/themes';\n\nconst GlobalStyles = createGlobalStyle`\n  body {\n    font-family: \"Nunito Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  }\n`;\n\nconst preview = {\n  decorators: [\n    withThemeFromJSXProvider({\n      themes: {\n        light: lightTheme,\n        dark: darkTheme,\n      },\n      defaultTheme: 'light',\n      Provider: ThemeProvider,\n      GlobalStyles,\n    }),\n  ],\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport { Preview, Renderer } from '@storybook/your-framework';\n\nimport { withThemeFromJSXProvider } from '@storybook/addon-themes';\n\nimport { createGlobalStyle, ThemeProvider } from 'styled-components';\nimport { lightTheme, darkTheme } from '../src/themes';\n\nconst GlobalStyles = createGlobalStyle`\n  body {\n    font-family: \"Nunito Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  }\n`;\n\nconst preview: Preview = {\n  decorators: [\n    withThemeFromJSXProvider<Renderer>({\n      themes: {\n        light: lightTheme,\n        dark: darkTheme,\n      },\n      defaultTheme: 'light',\n      Provider: ThemeProvider,\n      GlobalStyles,\n    }),\n  ],\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { Renderer, definePreview } from '@storybook/your-framework';\n\nimport addonThemes from '@storybook/addon-themes';\n\nimport { ThemeProvider, createGlobalStyle } from 'styled-components';\n\nimport { darkTheme, lightTheme } from '../src/themes';\n\nconst GlobalStyles = createGlobalStyle`\n  body {\n    font-family: \"Nunito Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  }\n`;\n\nexport default definePreview({\n  addons: [addonThemes()],\n  decorators: [\n    addonThemes.withThemeFromJSXProvider<Renderer>({\n      themes: {\n        light: lightTheme,\n        dark: darkTheme,\n      },\n      defaultTheme: 'light',\n      Provider: ThemeProvider,\n      GlobalStyles,\n    }),\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport addonThemes from '@storybook/addon-themes';\n\nimport { ThemeProvider, createGlobalStyle } from 'styled-components';\n\nimport { darkTheme, lightTheme } from '../src/themes';\n\nconst GlobalStyles = createGlobalStyle`\n  body {\n    font-family: \"Nunito Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  }\n`;\n\nexport default definePreview({\n  addons: [addonThemes()],\n  decorators: [\n    addonThemes.withThemeFromJSXProvider({\n      themes: {\n        light: lightTheme,\n        dark: darkTheme,\n      },\n      defaultTheme: 'light',\n      Provider: ThemeProvider,\n      GlobalStyles,\n    }),\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-tool-initial-setup.md",
    "content": "```tsx filename=\"src/Tool.tsx\" renderer=\"common\" language=\"ts\"\nimport React, { memo, useCallback, useEffect } from 'react';\n\nimport { useGlobals, useStorybookApi } from 'storybook/manager-api';\nimport { ToggleButton } from 'storybook/internal/components';\nimport { LightningIcon } from '@storybook/icons';\n\nimport { ADDON_ID, PARAM_KEY, TOOL_ID } from './constants';\n\nexport const Tool = memo(function MyAddonSelector() {\n  const [globals, updateGlobals] = useGlobals();\n  const api = useStorybookApi();\n\n  const isActive = [true, 'true'].includes(globals[PARAM_KEY]);\n\n  const toggleMyTool = useCallback(() => {\n    updateGlobals({\n      [PARAM_KEY]: !isActive,\n    });\n  }, [isActive]);\n\n  useEffect(() => {\n    api.setAddonShortcut(ADDON_ID, {\n      label: 'Toggle Addon [8]',\n      defaultShortcut: ['8'],\n      actionName: 'myaddon',\n      showInMenu: false,\n      action: toggleMyTool,\n    });\n  }, [toggleMyTool, api]);\n\n  return (\n    <ToggleButton\n      padding=\"small\"\n      variant=\"ghost\"\n      key={TOOL_ID}\n      pressed={isActive}\n      ariaLabel=\"Addon feature\"\n      tooltip=\"Toggle addon feature\"\n      onClick={toggleMyTool}\n    >\n      <LightningIcon />\n    </ToggleButton>\n  );\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-toolbar-example.md",
    "content": "```js filename=\"addon-toolbar/manager.js\" renderer=\"common\" language=\"js\"\nimport React from 'react';\n\nimport { addons, types } from 'storybook/manager-api';\nimport { ToggleButton } from 'storybook/internal/components';\nimport { OutlineIcon } from '@storybook/icons';\n\naddons.register('my-addon', () => {\n  addons.add('my-addon/toolbar', {\n    title: 'Example Storybook toolbar',\n    //👇 Sets the type of UI element in Storybook\n    type: types.TOOL,\n    //👇 Shows the Toolbar UI element if the story canvas is being viewed\n    match: ({ tabId, viewMode }) => !tabId && viewMode === 'story',\n    render: ({ active }) => (\n      <ToggleButton\n        key=\"Example\"\n        padding=\"small\"\n        variant=\"ghost\"\n        pressed={active}\n        ariaLabel=\"Addon feature\"\n        tooltip=\"Toggle addon feature\"\n      >\n        <OutlineIcon />\n      </ToggleButton>\n    ),\n  });\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-toolkit-types.md",
    "content": "```tsx filename=\"src/Tool.tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"Toolbar\"\nimport React, { memo, useCallback, useEffect } from 'react';\n\nimport { useGlobals, useStorybookApi } from 'storybook/manager-api';\nimport { ToggleButton } from 'storybook/internal/components';\nimport { LightningIcon } from '@storybook/icons';\n\nimport { ADDON_ID, PARAM_KEY, TOOL_ID } from './constants';\n\nexport const Tool = memo(function MyAddonSelector() {\n  const [globals, updateGlobals] = useGlobals();\n  const api = useStorybookApi();\n\n  const isActive = [true, 'true'].includes(globals[PARAM_KEY]);\n\n  const toggleMyTool = useCallback(() => {\n    updateGlobals({\n      [PARAM_KEY]: !isActive,\n    });\n  }, [isActive]);\n\n  useEffect(() => {\n    api.setAddonShortcut(ADDON_ID, {\n      label: 'Toggle Outline',\n      defaultShortcut: ['alt', 'O'],\n      actionName: 'outline',\n      showInMenu: false,\n      action: toggleMyTool,\n    });\n  }, [toggleMyTool, api]);\n\n  return (\n    <ToggleButton\n      padding=\"small\"\n      variant=\"ghost\"\n      key={TOOL_ID}\n      pressed={isActive}\n      ariaLabel=\"Addon feature\"\n      tooltip=\"Toggle addon feature\"\n      onClick={toggleMyTool}\n    >\n      <LightningIcon />\n    </ToggleButton>\n  );\n});\n```\n\n```tsx filename=\"src/Panel.tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"Panel\"\nimport React from 'react';\n\nimport { useAddonState, useChannel } from 'storybook/manager-api';\nimport { AddonPanel } from 'storybook/internal/components';\n\nimport { ADDON_ID, EVENTS } from './constants';\n\n// See https://github.com/storybookjs/addon-kit/blob/main/src/components/PanelContent.tsx for an example of a PanelContent component\nimport { PanelContent } from './components/PanelContent';\n\ninterface PanelProps {\n  active: boolean;\n}\n\nexport const Panel: React.FC<PanelProps> = (props) => {\n  // https://storybook.js.org/docs/addons/addons-api#useaddonstate\n  const [results, setState] = useAddonState(ADDON_ID, {\n    danger: [],\n    warning: [],\n  });\n\n  // https://storybook.js.org/docs/addons/addons-api#usechannel\n  const emit = useChannel({\n    [EVENTS.RESULT]: (newResults) => setState(newResults),\n  });\n\n  return (\n    <AddonPanel {...props}>\n      <PanelContent\n        results={results}\n        fetchData={() => {\n          emit(EVENTS.REQUEST);\n        }}\n        clearData={() => {\n          emit(EVENTS.CLEAR);\n        }}\n      />\n    </AddonPanel>\n  );\n};\n```\n\n```tsx filename=\"src/Tab.tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"Tab\"\nimport React from 'react';\n\nimport { useParameter } from 'storybook/manager-api';\n\nimport { PARAM_KEY } from './constants';\n\n// See https://github.com/storybookjs/addon-kit/blob/main/src/components/TabContent.tsx for an example of a TabContent component\nimport { TabContent } from './components/TabContent';\n\ninterface TabProps {\n  active: boolean;\n}\n\nexport const Tab: React.FC<TabProps> = ({ active }) => {\n  // https://storybook.js.org/docs/addons/addons-api#useparameter\n  const paramData = useParameter<string>(PARAM_KEY, '');\n\n  return active ? <TabContent code={paramData} /> : null;\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addon-use-global.md",
    "content": "```ts filename=\"src/withGlobals.ts\" renderer=\"common\" language=\"ts\"\nimport type {\n  Renderer,\n  PartialStoryFn as StoryFunction,\n  StoryContext,\n} from 'storybook/internal/types';\n\nimport { useEffect, useMemo, useGlobals } from 'storybook/preview-api';\nimport { PARAM_KEY } from './constants';\n\nimport { clearStyles, addOutlineStyles } from './helpers';\n\nimport outlineCSS from './outlineCSS';\n\nexport const withGlobals = (StoryFn: StoryFunction<Renderer>, context: StoryContext<Renderer>) => {\n  const [globals] = useGlobals();\n\n  const isActive = [true, 'true'].includes(globals[PARAM_KEY]);\n\n  // Is the addon being used in the docs panel\n  const isInDocs = context.viewMode === 'docs';\n\n  const outlineStyles = useMemo(() => {\n    const selector = isInDocs\n      ? `#anchor--${context.id} .docs-story, #anchor--primary--${context.id} .docs-story`\n      : '.sb-show-main';\n\n    return outlineCSS(selector);\n  }, [context.id]);\n  useEffect(() => {\n    const selectorId = isInDocs ? `my-addon-docs-${context.id}` : `my-addon`;\n\n    if (!isActive) {\n      clearStyles(selectorId);\n      return;\n    }\n\n    addOutlineStyles(selectorId, outlineStyles);\n\n    return () => {\n      clearStyles(selectorId);\n    };\n  }, [isActive, outlineStyles, context.id]);\n\n  return StoryFn();\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-addnotification.md",
    "content": "```js\nimport { addons } from '@storybook/manager-api';\nimport { CheckIcon } from '@storybook/icons';\n\naddons.register('my-organisation/my-addon', (api) => {\n  // Add a simple notification\n  api.addNotification({\n    id: 'my-notification',\n    content: {\n      headline: 'Action completed',\n      subHeadline: 'Your changes have been saved successfully',\n    },\n    duration: 5000, // 5 seconds\n  });\n\n  // Add a notification with an icon\n  api.addNotification({\n    id: 'success-notification',\n    content: {\n      headline: 'Success!',\n      subHeadline: 'Operation completed successfully',\n    },\n    icon: <CheckIcon />,\n    duration: 3000,\n  });\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-disablequeryparams.md",
    "content": "```js filename=\"my-addon/src/manager.js|ts\" renderer=\"common\" language=\"js\"\naddons.register('my-organisation/my-addon', (api) => {\n  api.setQueryParams({\n    exampleParameter: null,\n  });\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-getchannel.md",
    "content": "```js filename=\"my-addon/src/manager.js|ts\" renderer=\"common\" language=\"js\"\nimport React, { useCallback } from 'react';\nimport { OutlineIcon } from '@storybook/icons';\nimport { useGlobals } from 'storybook/manager-api';\nimport { addons } from 'storybook/preview-api';\nimport { ToggleButton } from 'storybook/internal/components';\nimport { FORCE_RE_RENDER } from 'storybook/internal/core-events';\n\nconst ExampleToolbar = () => {\n  const [globals, updateGlobals] = useGlobals();\n\n  const isActive = globals['my-param-key'] || false;\n\n  // Function that will update the global value and trigger a UI refresh.\n  const refreshAndUpdateGlobal = () => {\n    updateGlobals({\n      ['my-param-key']: !isActive,\n    });\n    // Invokes Storybook's addon API method (with the FORCE_RE_RENDER) event to trigger a UI refresh\n    addons.getChannel().emit(FORCE_RE_RENDER);\n  };\n\n  const toggleToolbarAddon = useCallback(() => refreshAndUpdateGlobal(), [isActive]);\n\n  return (\n    <ToggleButton\n      key=\"Example\"\n      padding=\"small\"\n      variant=\"ghost\"\n      pressed={isActive}\n      onClick={toggleToolbarAddon}\n      ariaLabel=\"Addon feature\"\n      tooltip=\"Toggle addon feature\"\n    >\n      <OutlineIcon />\n    </ToggleButton>\n  );\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-getcurrentstorydata.md",
    "content": "```js\naddons.register('my-organisation/my-addon', (api) => {\n  // Get data about the currently selected story\n  const storyData = api.getCurrentStoryData();\n  console.log('Current story:', storyData.id, storyData.title);\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-getqueryparam.md",
    "content": "```js filename=\"my-addon/src/manager.js|ts\" renderer=\"common\" language=\"js\"\naddons.register('my-organisation/my-addon', (api) => {\n  api.getQueryParam('exampleParameter');\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-getstoryhrefs.md",
    "content": "```js\naddons.register('my-organisation/my-addon', (api) => {\n  // Get the manager and preview URLs for a story\n  const { managerHref, previewHref } = api.getStoryHrefs('button--primary');\n\n  // Get absolute URLs based on the current manager URL (origin)\n  api.getStoryHrefs('button--primary', { base: 'origin' });\n\n  // Get absolute URLs based on the dev server's local network IP address\n  api.getStoryHrefs('button--primary', { base: 'network' });\n\n  // Get clean URLs without args or globals\n  api.getStoryHrefs('button--primary', { inheritArgs: false, inheritGlobals: false });\n\n  // With args and globals (merged on top of inherited args/globals) as well as a custom query param\n  // Note that args and globals should be serialized (see `buildArgsParam` from `storybook/internal/router`)\n  api.getStoryHrefs('button--primary', {\n    queryParams: { args: 'label:Label', globals: 'outline:!true', custom: 'value' },\n  });\n\n  // Link to a story from an external ref\n  api.getStoryHrefs('button--primary', { refId: 'external-ref' });\n\n  // Link to a docs page\n  api.getStoryHrefs('button--docs', { viewMode: 'docs' });\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-geturlstate.md",
    "content": "```js filename=\"my-addon/src/manager.js|ts\" renderer=\"common\" language=\"js\"\naddons.register('my-organisation/my-addon', (api) => {\n  const href = api.getUrlState({\n    selectedKind: 'kind',\n    selectedStory: 'story',\n  }).url;\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-imports.md",
    "content": "```js filename=\"my-addon/src/manager.js|ts\" renderer=\"common\" language=\"js\"\nimport { addons } from 'storybook/preview-api';\n\nimport { useStorybookApi } from 'storybook/manager-api';\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-makedecorator.md",
    "content": "```js filename=\"my-addon/src/decorator.js|ts\" renderer=\"common\" language=\"js\"\nimport { makeDecorator } from 'storybook/preview-api';\n\nexport const withAddonDecorator = makeDecorator({\n  name: 'withSomething',\n  parameterName: 'CustomParameter',\n  skipIfNoParametersOrOptions: true,\n  wrapper: (getStory, context, { parameters }) => {\n    /*\n     * Write your custom logic here based on the parameters passed in Storybook's stories.\n     * Although not advised, you can also alter the story output based on the parameters.\n     */\n    return getStory(context);\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-on.md",
    "content": "```js filename=\"my-addon/src/manager.js|ts\" renderer=\"common\" language=\"js\"\naddons.register('my-organisation/my-addon', (api) => {\n  // Logs the event data to the browser console whenever the event is emitted.\n  api.on('custom-addon-event', (eventData) => console.log(eventData));\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-openineditor.md",
    "content": "```js\naddons.register('my-organisation/my-addon', (api) => {\n  // Open a file in the editor\n  api.openInEditor({\n    file: './src/components/Button.tsx',\n  });\n\n  // Handle the api response\n  api\n    .openInEditor({\n      file: './src/components/Button.tsx',\n      line: 42,\n      column: 15,\n    })\n    .then((response) => {\n      if (response.error) {\n        console.error('Failed to open file:', response.error);\n      } else {\n        console.log('File opened successfully');\n      }\n    });\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-register.md",
    "content": "```js filename=\"my-addon/src/manager.js|ts\" renderer=\"common\" language=\"js\"\nimport { addons } from 'storybook/preview-api';\n\n// Register the addon with a unique name.\naddons.register('my-organisation/my-addon', (api) => {});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-selectincurrentkind.md",
    "content": "```js filename=\"my-addon/src/manager.js|ts\" renderer=\"common\" language=\"js\"\naddons.register('my-organisation/my-addon', (api) => {\n  api.selectInCurrentKind('Default');\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-selectstory.md",
    "content": "```js filename=\"my-addon/src/manager.js|ts\" renderer=\"common\" language=\"js\"\naddons.register('my-organisation/my-addon', (api) => {\n  api.selectStory('Button', 'Default');\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-setqueryparams.md",
    "content": "```js filename=\"my-addon/src/manager.js|ts\" renderer=\"common\" language=\"js\"\naddons.register('my-organisation/my-addon', (api) => {\n  api.setQueryParams({\n    exampleParameter: 'Sets the example parameter value',\n    anotherParameter: 'Sets the another parameter value',\n  });\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-togglefullscreen.md",
    "content": "```js\naddons.register('my-organisation/my-addon', (api) => {\n  // Toggle fullscreen mode\n  api.toggleFullscreen();\n\n  // Enable fullscreen\n  api.toggleFullscreen(true);\n\n  // Disable fullscreen\n  api.toggleFullscreen(false);\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-togglepanel.md",
    "content": "```js\naddons.register('my-organisation/my-addon', (api) => {\n  // Toggle panel visibility\n  api.togglePanel();\n\n  // Show the panel\n  api.togglePanel(true);\n\n  // Hide the panel\n  api.togglePanel(false);\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-useaddonstate.md",
    "content": "```js filename=\"my-addon/manager.js|ts\" renderer=\"common\" language=\"js\"\nimport React from 'react';\n\nimport { useAddonState } from 'storybook/manager-api';\nimport { AddonPanel, Button, ToggleButton } from 'storybook/internal/components';\nimport { LightningIcon } from '@storybook/icons';\n\nexport const Panel = () => {\n  const [state, setState] = useAddonState('addon-unique-identifier', 'initial state');\n\n  return (\n    <AddonPanel key=\"custom-panel\" active=\"true\">\n      <Button ariaLabel={false} onClick={() => setState('Example')}>\n        Click to update Storybook's internal state\n      </Button>\n    </AddonPanel>\n  );\n};\nexport const Tool = () => {\n  const [state, setState] = useAddonState('addon-unique-identifier', 'initial state');\n\n  return (\n    <ToggleButton\n      padding=\"small\"\n      variant=\"ghost\"\n      key=\"custom-toolbar\"\n      pressed=\"true\"\n      ariaLabel=\"Enable my addon\"\n      onClick={() => setState('Example')}\n    >\n      <LightningIcon />\n    </ToggleButton>\n  );\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-useapi.md",
    "content": "```js filename=\"my-addon/manager.js|ts\" renderer=\"common\" language=\"js\"\nimport React, { useEffect, useCallback } from 'react';\n\nimport { useGlobals, useStorybookApi } from 'storybook/manager-api';\nimport { ToggleButton } from 'storybook/internal/components';\nimport { ChevronDownIcon } from '@storybook/icons';\n\nexport const Panel = () => {\n  const [globals, updateGlobals] = useGlobals();\n  const api = useStorybookApi();\n\n  const isActive = [true, 'true'].includes(globals[PARAM_KEY]);\n\n  const toggleMyTool = useCallback(() => {\n    updateGlobals({\n      [PARAM_KEY]: !isActive,\n    });\n  }, [isActive]);\n\n  useEffect(() => {\n    api.setAddonShortcut('custom-toolbar-addon', {\n      label: 'Enable my addon',\n      defaultShortcut: ['G'],\n      actionName: 'Toggle',\n      showInMenu: false,\n      action: toggleMyTool,\n    });\n  }, [api]);\n\n  return (\n    <ToggleButton\n      padding=\"small\"\n      variant=\"ghost\"\n      key=\"custom-toolbar\"\n      pressed={isActive}\n      ariaLabel=\"My addon\"\n      tooltip=\"Enable my addon\"\n      onClick={toggleMyTool}\n    >\n      <ChevronDownIcon />\n    </ToggleButton>\n  );\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-usechannel.md",
    "content": "```js filename=\"my-addon/manager.js|ts\" renderer=\"common\" language=\"js\"\nimport React from 'react';\nimport { useChannel } from 'storybook/manager-api';\nimport { AddonPanel, Button } from 'storybook/internal/components';\nimport { STORY_CHANGED } from 'storybook/internal/core-events';\n\nexport const Panel = () => {\n  // Creates a Storybook API channel and subscribes to the STORY_CHANGED event\n  const emit = useChannel({\n    STORY_CHANGED: (...args) => console.log(...args),\n  });\n\n  return (\n    <AddonPanel key=\"custom-panel\" active=\"true\">\n      <Button onClick={() => emit('my-event-type', { sampleData: 'example' })}>\n        Emit a Storybook API event with custom data\n      </Button>\n    </AddonPanel>\n  );\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-useglobal.md",
    "content": "```js filename=\"my-addon/manager.js|ts\" renderer=\"common\" language=\"js\"\nimport React from 'react';\n\nimport { AddonPanel, Button } from 'storybook/internal/components';\n\nimport { useGlobals } from 'storybook/manager-api';\n\nexport const Panel = () => {\n  const [globals, updateGlobals] = useGlobals();\n\n  const isActive = globals['my-param-key'] || false; // 👈 Sets visibility based on the global value.\n\n  return (\n    <AddonPanel key=\"custom-panel\" active={isActive}>\n      <Button onClick={() => updateGlobals({ ['my-param-key']: !isActive })}>\n        {isActive ? 'Hide the addon panel' : 'Show the panel'}\n      </Button>\n    </AddonPanel>\n  );\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-useparameter.md",
    "content": "```js filename=\"my-addon/manager.js|ts\" renderer=\"common\" language=\"js\"\nimport React from 'react';\n\nimport { AddonPanel } from 'storybook/internal/components';\n\nimport { useParameter } from 'storybook/manager-api';\n\nexport const Panel = () => {\n  // Connects to Storybook's API and retrieves the value of the custom parameter for the current story\n  const value = useParameter('custom-parameter', 'initial value');\n\n  return (\n    <AddonPanel key=\"custom-panel\" active=\"true\">\n      {value === 'initial value' ? (\n        <h2>The story doesn't contain custom parameters. Defaulting to the initial value.</h2>\n      ) : (\n        <h2>You've set {value} as the parameter.</h2>\n      )}\n    </AddonPanel>\n  );\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-api-usestorybookstate.md",
    "content": "```js filename=\"my-addon/src/manager.js|ts\" renderer=\"common\" language=\"js\"\nimport React from 'react';\n\nimport { AddonPanel } from 'storybook/internal/components';\n\nimport { useStorybookState } from 'storybook/manager-api';\n\nexport const Panel = () => {\n  const state = useStorybookState();\n  return (\n    <AddonPanel {...props}>\n      {state.viewMode !== 'docs' ? (\n        <h2>Do something with the documentation</h2>\n      ) : (\n        <h2>Show the panel when viewing the story</h2>\n      )}\n    </AddonPanel>\n  );\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-local-preset.md",
    "content": "```js filename=\"example-addon/src/preset.js\" renderer=\"common\" language=\"js\"\nimport { webpackFinal as webpack } from './webpack/webpackFinal';\nimport { viteFinal as vite } from './vite/viteFinal';\nimport { babelDefault as babel } from './babel/babelDefault';\n\nexport const webpackFinal = webpack;\nexport const viteFinal = vite;\nexport const babelDefault = babel;\n```\n\n```ts filename=\"example-addon/src/preset.ts\" renderer=\"common\" language=\"ts\"\nimport { webpackFinal as webpack } from './webpack/webpackFinal';\n\nimport { viteFinal as vite } from './vite/viteFinal';\n\nimport { babelDefault as babel } from './babel/babelDefault';\n\nexport const webpackFinal = webpack as any;\n\nexport const viteFinal = vite as any;\n\nexport const babelDefault = babel as any;\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-preset-babelDefault.md",
    "content": "```js filename=\"example-addon/src/babel/babelDefault.js\" renderer=\"common\" language=\"js\"\nexport function babelDefault(config) {\n  return {\n    ...config,\n    plugins: [\n      ...config.plugins,\n      [import.meta.resolve('@babel/plugin-transform-react-jsx'), {}, 'preset'],\n    ],\n  };\n}\n```\n\n```ts filename=\"example-addon/src/babel/babelDefault.ts\" renderer=\"common\" language=\"ts\"\nimport { TransformOptions } from '@babel/core';\n\nexport function babelDefault(config: TransformOptions) {\n  return {\n    ...config,\n    plugins: [\n      ...config.plugins,\n      [import.meta.resolve('@babel/plugin-transform-react-jsx'), {}, 'preset'],\n    ],\n  };\n}\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-preset-preview.md",
    "content": "```js filename=\"example-addon/src/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { PARAM_KEY } from './constants';\n\nimport { CustomDecorator } from './decorators';\n\nconst preview = {\n  decorators: [CustomDecorator],\n  globals: {\n    [PARAM_KEY]: false,\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\"example-addon/src/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Renderer, ProjectAnnotations } from 'storybook/internal/types';\nimport { PARAM_KEY } from './constants';\nimport { CustomDecorator } from './decorators';\n\nconst preview: ProjectAnnotations<Renderer> = {\n  decorators: [CustomDecorator],\n  globals: {\n    [PARAM_KEY]: false,\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\"example-addon/src/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport type { ProjectAnnotations, Renderer } from 'storybook/internal/types';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { PARAM_KEY } from './constants';\nimport { CustomDecorator } from './decorators';\n\nexport default definePreview({\n  decorators: [CustomDecorator],\n  globals: {\n    [PARAM_KEY]: false,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"example-addon/src/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { PARAM_KEY } from './constants';\nimport { CustomDecorator } from './decorators';\n\nexport default definePreview({\n  decorators: [CustomDecorator],\n  globals: {\n    [PARAM_KEY]: false,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-preset-viteFinal.md",
    "content": "```js filename=\"example-addon/src/vite/viteFinal.js\" renderer=\"common\" language=\"js\"\nexport function ViteFinal(config, options = {}) {\n  config.plugins.push(\n    new MyCustomPlugin({\n      someOption: true,\n    }),\n  );\n\n  return config;\n}\n```\n\n```ts filename=\"example-addon/src/vite/viteFinal.ts\" renderer=\"common\" language=\"ts\"\nexport function ViteFinal(config: any, options: any = {}) {\n  config.plugins.push(\n    new MyCustomPlugin({\n      someOption: true,\n    }),\n  );\n\n  return config;\n}\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-preset-webpackFinal.md",
    "content": "```js filename=\"example-addon/src/webpack/webpackFinal.js\" renderer=\"common\" language=\"js\"\nimport { fileURLtoPath } from 'node:url';\nexport function webpackFinal(config, options = {}) {\n  const rules = [\n    ...(config.module?.rules || []),\n    {\n      test: /\\.custom-file-extension$/,\n      loader: fileURLToPath(import.meta.resolve(`custom-loader`)),\n    },\n  ];\n  config.module.rules = rules;\n\n  return config;\n}\n```\n\n```ts filename=\"example-addon/src/webpack/webpackFinal.ts\" renderer=\"common\" language=\"ts\"\nimport { fileURLtoPath } from 'node:url';\nimport type { Configuration as WebpackConfig } from 'webpack';\n\nexport function webpackFinal(config: WebpackConfig, options: any = {}) {\n  const rules = [\n    ...(config.module?.rules || []),\n    {\n      test: /\\.custom-file$/,\n      loader: fileURLToPath(import.meta.resolve(`custom-loader`)),\n    },\n  ];\n  config.module.rules = rules;\n\n  return config;\n}\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-preset.md",
    "content": "```js filename=\"preset.js\" renderer=\"common\" language=\"js\" tabTitle=\"root-preset\"\nexport const previewAnnotations = (entry = [], options) => {\n  return [...entry, import.meta.resolve('./dist/preview')];\n};\n```\n\n```ts filename=\"preset.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"root-preset\"\nexport const previewAnnotations = (entry = [], options) => {\n  return [...entry, import.meta.resolve('./dist/preview')];\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-root-preset-manager-entries.md",
    "content": "```js filename=\"example-addon/preset.js\" renderer=\"common\" language=\"js\"\nexport const managerEntries = (entry = []) => {\n  return [...entry, import.meta.resolve('path-to-third-party-addon')];\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-root-preset-preview-annotations.md",
    "content": "```js filename=\"preset.js\" renderer=\"common\" language=\"js\"\nexport const previewAnnotations = (entry = [], options) => {\n  return [...entry, import.meta.resolve('./dist/preview')];\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-addons-root-preset.md",
    "content": "```js filename=\"example-addon/preset.js\" renderer=\"common\" language=\"js\"\nexport const previewAnnotations = [import.meta.resolve('./dist/preview')];\n\nexport const managerEntries = [import.meta.resolve('./dist/manager')];\n\nexport * from './dist/preset.js';\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-args-url-params-converted.md",
    "content": "```js renderer=\"common\" language=\"js\"\n{\n  obj: { key: 'val' },\n  arr: ['one', 'two'],\n  nil: null\n}\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-argtypes-with-addon.md",
    "content": "```js filename=\".storybook/my-addon/manager.js\" renderer=\"common\" language=\"js\"\nimport { useArgTypes } from 'storybook/manager-api';\n\n// inside your panel\nconst { argTypes } = useArgTypes();\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-auto-docs-baseline-example.md",
    "content": "<!-- prettier-ignore -->\n```mdx filename=\"Button.mdx\" renderer=\"common\" language=\"mdx\" tabTitle=\"custom-title\"\nimport { Meta, Controls } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Button\" />\n\n# Definition\n\nButton is a clickable interactive element that triggers a response.\n\nYou can place text and icons inside of a button.\n\nButtons are often used for form submissions and to toggle elements into view.\n\n## Usage\n\nThe component comes in different variants such as `primary`, `secondary`, `large` and `small` which you can use to alter the look and feel of the button.\n\n## Inputs\n\nButton has the following properties:\n\n<Controls />\n```\n\n<!-- prettier-ignore -->\n```mdx filename=\"Button.mdx\" renderer=\"common\" language=\"mdx\" tabTitle=\"of-prop\"\nimport { Meta, Controls } from '@storybook/addon-docs/blocks';\n\nimport * as ButtonStories from './Button.stories';\n\n<Meta of={ButtonStories} />\n\n# Definition\n\nButton is a clickable interactive element that triggers a response.\n\nYou can place text and icons inside of a button.\n\nButtons are often used for form submissions and to toggle elements into view.\n\n## Usage\n\nThe component comes in different variants such as `primary`, `secondary`, `large` and `small` which you can use to alter the look and feel of the button.\n\n## Inputs\n\nButton has the following properties:\n\n<Controls />\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-auto-docs-custom-file.md",
    "content": "<!-- prettier-ignore -->\n```mdx filename=\"src/components/Select.mdx\" renderer=\"common\" language=\"mdx\"\n# Select\n\nSelect is a type of input that allows users to choose one or more options from a list of choices.\n\nThe options are hidden by default and revealed when a user interacts with an element.\n\nIt shows the currently selected option in its default collapsed state.\n\n## Design implementation\n\nTo help users get acquainted with the existing UI elements, it is recommended to use check the Figma file to see how the select input is implemented.\n\n### When to use?\n\nIn a select input where there are less than 3-4 items, consider using radio boxes, or radio inputs instead.\n\n### How to use?\n\nTo help users understand the options available in a select input, include a default option that is unselectable and acts as a label.\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-auto-docs-full-config.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-docs'],\n  docs: {\n    //👇 See the table below for the list of supported options\n    defaultName: 'Documentation',\n    docsMode: true,\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-docs'],\n  docs: {\n    //👇 See the table below for the list of supported options\n    defaultName: 'Documentation',\n    docsMode: true,\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-docs'],\n  docs: {\n    //👇 See the table below for the list of supported options\n    defaultName: 'Documentation',\n    docsMode: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-docs'],\n  docs: {\n    //👇 See the table below for the list of supported options\n    defaultName: 'Documentation',\n    docsMode: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-docs'],\n  docs: {\n    //👇 See the table below for the list of supported options\n    defaultName: 'Documentation',\n    docsMode: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-docs'],\n  docs: {\n    //👇 See the table below for the list of supported options\n    defaultName: 'Documentation',\n    docsMode: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-docs'],\n  docs: {\n    //👇 See the table below for the list of supported options\n    defaultName: 'Documentation',\n    docsMode: true,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-docs'],\n  docs: {\n    //👇 See the table below for the list of supported options\n    defaultName: 'Documentation',\n    docsMode: true,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-docs'],\n  docs: {\n    //👇 See the table below for the list of supported options\n    defaultName: 'Documentation',\n    docsMode: true,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-auto-docs-main-mdx-config.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: [\n    //👇 Your documentation written in MDX along with your stories goes here\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n  ],\n  addons: ['@storybook/addon-docs'],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: [\n    //👇 Your documentation written in MDX along with your stories goes here\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n  ],\n  addons: ['@storybook/addon-docs'],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  // Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\n  framework: '@storybook/your-framework',\n  stories: [\n    //👇 Your documentation written in MDX along with your stories goes here\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n  ],\n  addons: ['@storybook/addon-docs'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: [\n    //👇 Your documentation written in MDX along with your stories goes here\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n  ],\n  addons: ['@storybook/addon-docs'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: [\n    //👇 Your documentation written in MDX along with your stories goes here\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n  ],\n  addons: ['@storybook/addon-docs'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: [\n    //👇 Your documentation written in MDX along with your stories goes here\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n  ],\n  addons: ['@storybook/addon-docs'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: [\n    //👇 Your documentation written in MDX along with your stories goes here\n    '../src/**/*.mdx',\n    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',\n  ],\n  addons: ['@storybook/addon-docs'],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-auto-docs-mdx-docs-definition.md",
    "content": "```md renderer=\"common\" language=\"mdx\"\n# Checkbox\n\nA checkbox is a square box that can be activated or deactivated when ticked.\n\nUse checkboxes to select one or more options from a list of choices.\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-auto-docs-mdx-docs-docs-only-page.md",
    "content": "<!-- prettier-ignore -->\n```mdx filename=\"ExampleDocumentation.mdx\" renderer=\"common\" language=\"mdx\"\nimport { Meta } from '@storybook/addon-docs/blocks';\n\nimport * as ExampleComponentStories from './ExampleComponent.stories';\n\n{/* 👇 Documentation-only page */}\n\n<Meta title=\"Documentation\" />\n\n{/* 👇 Component documentation page */}\n\n<Meta of={ExampleComponentStories} />\n```\n\n<!-- prettier-ignore -->\n```mdx filename=\"ExampleDocumentation.mdx\" renderer=\"svelte\" language=\"mdx\" tabTitle=\"Svelte CSF\"\nimport { Meta } from '@storybook/addon-docs/blocks';\n\nimport * as ExampleComponentStories from './ExampleComponent.stories.svelte';\n\n{/* 👇 Documentation-only page */}\n\n<Meta title=\"Documentation\" />\n\n{/* 👇 Component documentation page */}\n\n<Meta of={ExampleComponentStories} />\n```\n\n<!-- prettier-ignore -->\n```mdx filename=\"ExampleDocumentation.mdx\" renderer=\"svelte\" language=\"mdx\" tabTitle=\"CSF 3\"\nimport { Meta } from '@storybook/addon-docs/blocks';\n\nimport * as ExampleComponentStories from './ExampleComponent.stories';\n\n{/* 👇 Documentation-only page */}\n\n<Meta title=\"Documentation\" />\n\n{/* 👇 Component documentation page */}\n\n<Meta of={ExampleComponentStories} />\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-auto-docs-mdx-docs-dos-donts.md",
    "content": "<!-- prettier-ignore -->\n```mdx filename=\"Guideline.mdx\" renderer=\"common\" language=\"mdx\"\n<Guidelines>\n  <Dos>\n    - Use buttons for the main actions on your page\n    - Identify the primary action and make it `primary`\n  </Dos>\n  <Donts>\n    - Use a button when a link will do (e.g., for navigation-only actions)\n    - Use multiple `primary` buttons in a single UI state\n  </Donts>\n</Guidelines>\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-auto-docs-mdx-docs-imports.md",
    "content": "<!-- prettier-ignore -->\n```mdx filename=\"Checkbox.mdx\" renderer=\"common\" language=\"mdx\"\nimport { Canvas, Meta } from '@storybook/addon-docs/blocks';\n\nimport * as CheckboxStories from './Checkbox.stories';\n```\n\n<!-- prettier-ignore -->\n```mdx filename=\"Checkbox.mdx\" renderer=\"svelte\" language=\"mdx\" tabTitle=\"Svelte CSF\"\nimport { Canvas, Meta } from '@storybook/addon-docs/blocks';\n\nimport * as CheckboxStories from './Checkbox.stories.svelte';\n```\n\n<!-- prettier-ignore -->\n```mdx filename=\"Checkbox.mdx\" renderer=\"svelte\" language=\"mdx\" tabTitle=\"CSF 3\"\nimport { Canvas, Meta } from '@storybook/addon-docs/blocks';\n\nimport * as CheckboxStories from './Checkbox.stories';\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-auto-docs-mdx-docs-meta-block.md",
    "content": "<!-- prettier-ignore -->\n```mdx filename=\"Checkbox.mdx\" renderer=\"common\" language=\"mdx\"\nimport { Meta } from '@storybook/addon-docs/blocks';\n\nimport * as CheckboxStories from './Checkbox.stories';\n\n<Meta of={CheckboxStories} />\n```\n\n<!-- prettier-ignore -->\n```mdx filename=\"Checkbox.mdx\" renderer=\"svelte\" language=\"mdx\" tabTitle=\"Svelte CSF\"\nimport { Meta } from '@storybook/addon-docs/blocks';\n\nimport * as CheckboxStories from './Checkbox.stories.svelte';\n\n<Meta of={CheckboxStories} />\n```\n\n<!-- prettier-ignore -->\n```mdx filename=\"Checkbox.mdx\" renderer=\"svelte\" language=\"mdx\" tabTitle=\"CSF 3\"\nimport { Meta } from '@storybook/addon-docs/blocks';\n\nimport * as CheckboxStories from './Checkbox.stories';\n\n<Meta of={CheckboxStories} />\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-auto-docs-mdx-docs-story.md",
    "content": "<!-- prettier-ignore -->\n```mdx filename=\"Checkbox.mdx\" renderer=\"common\" language=\"mdx\"\nimport { Canvas } from '@storybook/addon-docs/blocks';\n\nimport * as CheckboxStories from './Checkbox.stories';\n\n<Canvas of={CheckboxStories.Unchecked} />\n```\n\n```mdx filename=\"Checkbox.mdx\" renderer=\"svelte\" language=\"mdx\" tabTitle=\"Svelte CSF\"\nimport { Canvas } from '@storybook/addon-docs/blocks';\n\nimport * as CheckboxStories from './Checkbox.stories.svelte';\n\n<Canvas of={CheckboxStories.Unchecked} />\n```\n\n<!-- prettier-ignore -->\n```mdx filename=\"Checkbox.mdx\" renderer=\"svelte\" language=\"mdx\" tabTitle=\"CSF 3\"\nimport { Canvas } from '@storybook/addon-docs/blocks';\n\nimport * as CheckboxStories from './Checkbox.stories';\n\n<Canvas of={CheckboxStories.Unchecked} />\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-auto-docs-mdx-file.md",
    "content": "<!-- prettier-ignore -->\n```mdx filename=\"Page.mdx\" renderer=\"common\" language=\"mdx\"\nimport { Canvas, Meta, Story } from '@storybook/addon-docs/blocks';\n\nimport * as ListStories from './List.stories';\n\nimport * as ListItemStories from './ListItem.stories';\n\nimport * as PageStories from './Page.stories';\n\n<Meta of={PageStories} />\n\n# Page\n\nPage is a layout container that is used to position children in predetermined areas.\n\nIt's often used to apply consistent positioning for content across pages in an application\n\n## Usage\n\n<Canvas of={PageStories.Basic} />\n\n# List\n\nList is a grouping of related items. List can be ordered with multiple levels of nesting.\n\n## Usage\n\n<Story of={ListStories.Filled} />\n\n# List Item\n\nList items are used to group related content in a list. They must be nested within a List component.\n\n## Usage\n\n<Story of={ListItemStories.Starter} meta={ListItemStories} />\n```\n\n<!-- prettier-ignore -->\n```mdx filename=\"Page.mdx\" renderer=\"svelte\" language=\"mdx\" tabTitle=\"Svelte CSF\"\nimport { Canvas, Meta, Story } from '@storybook/addon-docs/blocks';\n\nimport * as ListStories from './List.stories.svelte';\n\nimport * as ListItemStories from './ListItem.stories.svelte';\n\nimport * as PageStories from './Page.stories.svelte';\n\n<Meta of={PageStories} />\n\n# Page\n\nPage is a layout container that is used to position children in predetermined areas.\n\nIt's often used to apply consistent positioning for content across pages in an application\n\n## Usage\n\n<Canvas of={PageStories.Basic} />\n\n# List\n\nList is a grouping of related items. List can be ordered with multiple levels of nesting.\n\n## Usage\n\n<Story of={ListStories.Filled} />\n\n# List Item\n\nList items are used to group related content in a list. They must be nested within a List component.\n\n## Usage\n\n<Story of={ListItemStories.Starter} meta={ListItemStories} />\n```\n\n<!-- prettier-ignore -->\n```mdx filename=\"Page.mdx\" renderer=\"svelte\" language=\"mdx\" tabTitle=\"CSF 3\"\nimport { Canvas, Meta, Story } from '@storybook/addon-docs/blocks';\n\nimport * as ListStories from './List.stories';\n\nimport * as ListItemStories from './ListItem.stories';\n\nimport * as PageStories from './Page.stories';\n\n<Meta of={PageStories} />\n\n# Page\n\nPage is a layout container that is used to position children in predetermined areas.\n\nIt's often used to apply consistent positioning for content across pages in an application\n\n## Usage\n\n<Canvas of={PageStories.Basic} />\n\n# List\n\nList is a grouping of related items. List can be ordered with multiple levels of nesting.\n\n## Usage\n\n<Story of={ListStories.Filled} />\n\n# List Item\n\nList items are used to group related content in a list. They must be nested within a List component.\n\n## Usage\n\n<Story of={ListItemStories.Starter} meta={ListItemStories} />\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-auto-docs-standalone-page.md",
    "content": "<!-- prettier-ignore -->\n```mdx filename=\"src/GettingStarted.mdx\" renderer=\"common\" language=\"mdx\"\n# Getting Started\n\nWelcome! Whether you're a designer or a developer, this guide will help you get started and connect you to the essential resources you need.\n\n## Table of Contents\n\n- [Design Resources](#design-resources)\n\n  - [Figma](#figma)\n  - [UI/UX Design Guidelines](#uiux-design-guidelines)\n  - [Design Assets](#design-assets)\n\n- [Development Resources](#development-resources)\n  - [Coding Standards](#coding-standards)\n  - [Version Control](#version-control)\n  - [Development Tools](#development-tools)\n\n---\n\n## Design Resources\n\n### Figma\n\n[Figma](https://www.figma.com/) is a collaborative design and prototyping tool. It's the heart of the design process, allowing designers to work together seamlessly.\n\n- **Get Access**: If you're not already part of the Figma project, request access from the project lead or manager.\n\n### UI/UX Design Guidelines\n\nBefore you dive into designing, familiarize yourself with our UI/UX design guidelines. They provide valuable insights into our design philosophy and standards.\n\n- [UI/UX Guidelines Document](https://your-design-guidelines-link.com)\n\n### Design Assets\n\nAll the essential design assets like logos, icons, and brand guidelines can be found in the Figma project. Ensure you have access and familiarize yourself with these assets for consistency.\n\n---\n\n## Development Resources\n\n### Coding Standards\n\nMaintaining a consistent code style is essential for collaborative development. Our coding standards document will guide you on best practices.\n\n- [Coding Standards Document](https://your-coding-standards-link.com)\n\n### Version Control\n\nWe use Git for version control. Make sure you have Git installed and are familiar with its basics.\n\n### Development Tools\n\nYour development environment is critical. Here are some tools and resources to help you set up your workspace:\n\n- **Code Editor**: We recommend using [Visual Studio Code](https://code.visualstudio.com/) for development. It's highly customizable and supports a wide range of extensions.\n\n- **Package Manager**: [npm](https://www.npmjs.com/) is the package manager we use for JavaScript projects. Install it to manage project dependencies.\n\n---\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-auto-docs-starter-example.md",
    "content": "<!-- prettier-ignore -->\n```mdx filename=\"Button.mdx\" renderer=\"common\" language=\"mdx\"\nimport { Meta, Story } from '@storybook/addon-docs/blocks';\n\nimport * as ButtonStories from './Button.stories';\n\n<Meta of={ButtonStories} />\n\n# Button\n\nButton is a clickable interactive element that triggers a response.\n\nYou can place text and icons inside of a button.\n\nButtons are often used for form submissions and to toggle elements into view.\n\n## Usage\n\n<Story of={ButtonStories.Basic} />\n```\n\n<!-- prettier-ignore -->\n```mdx filename=\"Button.mdx\" renderer=\"svelte\" language=\"mdx\" tabTitle=\"Svelte CSF\"\nimport { Meta, Story } from '@storybook/addon-docs/blocks';\n\nimport * as ButtonStories from './Button.stories.svelte';\n\n<Meta of={ButtonStories} />\n\n# Button\n\nButton is a clickable interactive element that triggers a response.\n\nYou can place text and icons inside of a button.\n\nButtons are often used for form submissions and to toggle elements into view.\n\n## Usage\n\n<Story of={ButtonStories.Basic} />\n```\n\n<!-- prettier-ignore -->\n```mdx filename=\"Button.mdx\" renderer=\"svelte\" language=\"mdx\" tabTitle=\"CSF 3\"\nimport { Meta, Story } from '@storybook/addon-docs/blocks';\n\nimport * as ButtonStories from './Button.stories';\n\n<Meta of={ButtonStories} />\n\n# Button\n\nButton is a clickable interactive element that triggers a response.\n\nYou can place text and icons inside of a button.\n\nButtons are often used for form submissions and to toggle elements into view.\n\n## Usage\n\n<Story of={ButtonStories.Basic} />\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-automigrate.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook@latest automigrate\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx storybook@latest automigrate\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn dlx storybook@latest automigrate\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-babel-configuration-example.md",
    "content": "```ts renderer=\"common\" language=\"ts\"\nimport { TransformOptions } from '@babel/core';\n\nexport function babelDefault(config: TransformOptions) {\n  return {\n    plugins: [[import.meta.resolve('@babel/plugin-transform-react-jsx'), {}, 'preset']],\n  };\n}\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-backgrounds-addon-default-params.md",
    "content": "```js filename=\"addons/backgrounds/src/preset/addParameter.tsx\" renderer=\"common\" language=\"js\"\nexport default {\n  parameters: {\n    backgrounds: {\n      values: [\n        { name: 'light', value: '#F8F8F8' },\n        { name: 'dark', value: '#333333' },\n      ],\n    },\n  },\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-backgrounds-preset-config.md",
    "content": "```js filename=\"preset.js\" renderer=\"common\" language=\"js\"\nexport function previewAnnotations(entry = []) {\n  return [...entry, import.meta.resolve('./defaultParameters')];\n}\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-build-test-flag.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm run build-storybook -- --test\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm run build-storybook --test\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn build-storybook --test\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-builder-api-build-server.md",
    "content": "```ts filename=\"build.ts\" renderer=\"common\" language=\"ts\"\nimport { build as viteBuild } from 'vite';\nimport { stringifyProcessEnvs } from './envs';\nimport { commonConfig } from './vite-config';\n\nimport type { EnvsRaw, ExtendedOptions } from './types';\n\nexport async function build(options: ExtendedOptions) {\n  const { presets } = options;\n\n  const baseConfig = await commonConfig(options, 'build');\n  const config = {\n    ...baseConfig,\n    build: {\n      outDir: options.outputDir,\n      emptyOutDir: false,\n      sourcemap: true,\n    },\n  };\n\n  const finalConfig = await presets.apply('viteFinal', config, options);\n\n  const envsRaw = await presets.apply<Promise<EnvsRaw>>('env');\n  // Stringify env variables after getting `envPrefix` from the final config\n  const envs = stringifyProcessEnvs(envsRaw, finalConfig.envPrefix);\n  // Update `define`\n  finalConfig.define = {\n    ...finalConfig.define,\n    ...envs,\n  };\n\n  await viteBuild(finalConfig);\n}\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-builder-api-configuration-options.md",
    "content": "```ts filename=\"vite-server.ts\" renderer=\"common\" language=\"ts\"\nimport { stringifyProcessEnvs } from './envs';\nimport { getOptimizeDeps } from './optimizeDeps';\nimport { commonConfig } from './vite-config';\n\nimport type { EnvsRaw, ExtendedOptions } from './types';\n\nexport async function createViteServer(options: ExtendedOptions, devServer: Server) {\n  const { port, presets } = options;\n\n  // Defines the baseline config.\n  const baseConfig = await commonConfig(options, 'development');\n  const defaultConfig = {\n    ...baseConfig,\n    server: {\n      middlewareMode: true,\n      hmr: {\n        port,\n        server: devServer,\n      },\n      fs: {\n        strict: true,\n      },\n    },\n    optimizeDeps: await getOptimizeDeps(baseConfig, options),\n  };\n\n  const finalConfig = await presets.apply('viteFinal', defaultConfig, options);\n\n  const envsRaw = await presets.apply<Promise<EnvsRaw>>('env');\n\n  // Remainder implementation\n}\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-builder-api-dev-server.md",
    "content": "```ts filename=\"server.ts\" renderer=\"common\" language=\"ts\"\nimport { createServer } from 'vite';\n\nexport async function createViteServer(options: ExtendedOptions, devServer: Server) {\n  const { port } = options;\n  // Remainder server configuration\n\n  // Creates the server.\n  return createServer({\n    // The server configuration goes here\n    server: {\n      middlewareMode: true,\n      hmr: {\n        port,\n        server: devServer,\n      },\n    },\n  });\n}\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-builder-api-interface.md",
    "content": "```ts filename=\"core-common.ts\" renderer=\"common\" language=\"ts\"\nexport interface Builder<Config, BuilderStats extends Stats = Stats> {\n  getConfig: (options: Options) => Promise<Config>;\n  start: (args: {\n    options: Options;\n    startTime: ReturnType<typeof process.hrtime>;\n    router: ServerApp;\n    server: HttpServer;\n    channel: ServerChannel;\n  }) => Promise<void | {\n    stats?: BuilderStats;\n    totalTime: ReturnType<typeof process.hrtime>;\n    bail: (e?: Error) => Promise<void>;\n  }>;\n  build: (arg: {\n    options: Options;\n    startTime: ReturnType<typeof process.hrtime>;\n  }) => Promise<void | BuilderStats>;\n  bail: (e?: Error) => Promise<void>;\n  corePresets?: string[];\n  overridePresets?: string[];\n}\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-builder-api-mdx.md",
    "content": "```ts filename=\"mdx-plugin.ts\" renderer=\"common\" language=\"ts\"\nimport mdx from 'vite-plugin-mdx';\n\nimport { createCompiler } from 'storybook/internal/csf-tools/mdx';\n\nexport function mdxPlugin() {\n  return mdx((filename) => {\n    const compilers = [];\n\n    if (filename.endsWith('stories.mdx') || filename.endsWith('story.mdx')) {\n      compilers.push(createCompiler({}));\n    }\n    return {\n      compilers,\n    };\n  });\n}\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-builder-api-preview-exports.md",
    "content": "```ts renderer=\"common\" language=\"ts\"\nimport { virtualPreviewFile, virtualStoriesFile } from './virtual-file-names';\nimport { transformAbsPath } from './utils/transform-abs-path';\nimport type { ExtendedOptions } from './types';\n\nexport async function generateIframeScriptCode(options: ExtendedOptions) {\n  const { presets, frameworkPath, framework } = options;\n  const frameworkImportPath = frameworkPath || `@storybook/${framework}`;\n\n  const presetEntries = await presets.apply('config', [], options);\n  const configEntries = [...presetEntries].filter(Boolean);\n\n  const absoluteFilesToImport = (files: string[], name: string) =>\n    files\n      .map((el, i) => `import ${name ? `* as ${name}_${i} from ` : ''}'${transformAbsPath(el)}'`)\n      .join('\\n');\n\n  const importArray = (name: string, length: number) =>\n    new Array(length).fill(0).map((_, i) => `${name}_${i}`);\n\n  const code = `\n    // Ensure that the client API is initialized by the framework before any other iframe code\n    // is loaded. That way our client-apis can assume the existence of the API+store\n    import { configure } from '${frameworkImportPath}';\n\n    import {\n      addDecorator,\n      addParameters,\n      addArgTypesEnhancer,\n      addArgsEnhancer,\n      setGlobalRender\n    } from 'storybook/preview-api';\n    import { logger } from 'storybook/internal/client-logger';\n    ${absoluteFilesToImport(configEntries, 'config')}\n    import * as preview from '${virtualPreviewFile}';\n    import { configStories } from '${virtualStoriesFile}';\n\n    const configs = [${importArray('config', configEntries.length)\n      .concat('preview.default')\n      .join(',')}].filter(Boolean)\n\n    configs.forEach(config => {\n      Object.keys(config).forEach((key) => {\n        const value = config[key];\n        switch (key) {\n          case 'args':\n          case 'argTypes': {\n            return logger.warn('Invalid args/argTypes in config, ignoring.', JSON.stringify(value));\n          }\n          case 'decorators': {\n            return value.forEach((decorator) => addDecorator(decorator, false));\n          }\n          case 'parameters': {\n            return addParameters({ ...value }, false);\n          }\n          case 'render': {\n            return setGlobalRender(value)\n          }\n          case 'globals':\n          case 'globalTypes': {\n            const v = {};\n            v[key] = value;\n            return addParameters(v, false);\n          }\n          case 'decorateStory':\n          case 'renderToCanvas': {\n            return null;\n          }\n          default: {\n            // eslint-disable-next-line prefer-template\n            return console.log(key + ' was not supported :( !');\n          }\n        }\n      });\n    })\n    configStories(configure);\n    `.trim();\n  return code;\n}\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-builder-api-shutdown-server.md",
    "content": "```ts filename=\"index.ts\" renderer=\"common\" language=\"ts\"\nimport { createViteServer } from './vite-server';\n\nlet server: ViteDevServer;\nexport async function bail(): Promise<void> {\n  return server?.close();\n}\n\nexport const start: ViteBuilder['start'] = async ({ options, server: devServer }) => {\n  // Remainder implementation goes here\n  server = await createViteServer(options as ExtendedOptions, devServer);\n\n  return {\n    bail,\n    totalTime: process.hrtime(startTime),\n  };\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-canvas-doc-block-story.md",
    "content": "```jsx filename=\"MyComponent.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { ColorItem, ColorPalette } from '@storybook/addon-docs/blocks';\n\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\nconst theme = {\n  colors: {\n    primaryDark: {\n      value: '#1C1C1C',\n    },\n    primaryRegular: {\n      value: '#363636',\n    },\n    primaryLight1: {\n      value: '#4D4D4D',\n    },\n    primaryLight2: {\n      value: '#878787',\n    },\n    primaryLight3: {\n      value: '#D1D1D1',\n    },\n    primaryLight4: {\n      value: '#EDEDED',\n    },\n  },\n};\n\n// ❌ Don't use the Doc Blocks inside your stories. It will break Storybook with a cryptic error.\nexport const Colors = {\n  render: () => (\n    <ColorPalette>\n      {Object.entries(theme.colors).map(([key, { value }]) => (\n        <ColorItem\n          colors={{\n            [key]: value,\n          }}\n          key={key}\n          subtitle={`theme.colors.${key}`}\n          title={key}\n        />\n      ))}\n    </ColorPalette>\n  ),\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { ColorItem, ColorPalette } from '@storybook/addon-docs/blocks';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nconst theme = {\n  colors: {\n    primaryDark: {\n      value: '#1C1C1C',\n    },\n    primaryRegular: {\n      value: '#363636',\n    },\n    primaryLight1: {\n      value: '#4D4D4D',\n    },\n    primaryLight2: {\n      value: '#878787',\n    },\n    primaryLight3: {\n      value: '#D1D1D1',\n    },\n    primaryLight4: {\n      value: '#EDEDED',\n    },\n  },\n};\n\n// ❌ Don't use the Doc Blocks inside your stories. It will break Storybook with a cryptic error.\nexport const Colors: Story = {\n  render: () => (\n    <ColorPalette>\n      {Object.entries(theme.colors).map(([key, { value }]) => (\n        <ColorItem\n          colors={{\n            [key]: value,\n          }}\n          key={key}\n          subtitle={`theme.colors.${key}`}\n          title={key}\n        />\n      ))}\n    </ColorPalette>\n  ),\n};\n```\n\n```tsx filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { ColorItem, ColorPalette } from '@storybook/addon-docs/blocks';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nconst theme = {\n  colors: {\n    primaryDark: {\n      value: '#1C1C1C',\n    },\n    primaryRegular: {\n      value: '#363636',\n    },\n    primaryLight1: {\n      value: '#4D4D4D',\n    },\n    primaryLight2: {\n      value: '#878787',\n    },\n    primaryLight3: {\n      value: '#D1D1D1',\n    },\n    primaryLight4: {\n      value: '#EDEDED',\n    },\n  },\n};\n\n// ❌ Don't use the Doc Blocks inside your stories. It will break Storybook with a cryptic error.\nexport const Colors = meta.story({\n  render: () => (\n    <ColorPalette>\n      {Object.entries(theme.colors).map(([key, { value }]) => (\n        <ColorItem\n          colors={{\n            [key]: value,\n          }}\n          key={key}\n          subtitle={`theme.colors.${key}`}\n          title={key}\n        />\n      ))}\n    </ColorPalette>\n  ),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { ColorItem, ColorPalette } from '@storybook/addon-docs/blocks';\n\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nconst theme = {\n  colors: {\n    primaryDark: {\n      value: '#1C1C1C',\n    },\n    primaryRegular: {\n      value: '#363636',\n    },\n    primaryLight1: {\n      value: '#4D4D4D',\n    },\n    primaryLight2: {\n      value: '#878787',\n    },\n    primaryLight3: {\n      value: '#D1D1D1',\n    },\n    primaryLight4: {\n      value: '#EDEDED',\n    },\n  },\n};\n\n// ❌ Don't use the Doc Blocks inside your stories. It will break Storybook with a cryptic error.\nexport const Colors = meta.story({\n  render: () => (\n    <ColorPalette>\n      {Object.entries(theme.colors).map(([key, { value }]) => (\n        <ColorItem\n          colors={{\n            [key]: value,\n          }}\n          key={key}\n          subtitle={`theme.colors.${key}`}\n          title={key}\n        />\n      ))}\n    </ColorPalette>\n  ),\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-client-globals-example-file.md",
    "content": "```ts filename=\"vue/src/client/preview/globals.ts\" renderer=\"common\" language=\"ts\"\nimport { global } from '@storybook/global';\n\nconst { window: globalWindow } = global;\n\nglobalWindow.STORYBOOK_ENV = 'vue';\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-client-preview.md",
    "content": "```ts filename=\"your-framework/src/client/preview/index.ts\" renderer=\"common\" language=\"ts\"\nimport { start } from 'storybook/preview-api';\n\nimport './globals';\n\nimport render from './render';\n\nconst api = start(render);\n\n// the boilerplate code\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-component-layout-param.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  // Sets the layout parameter component wide.\n  parameters: {\n    layout: 'centered',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  // Sets the layout parameter component wide.\n  parameters: {\n    layout: 'centered',\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    // Sets the layout parameter component wide.\n    parameters: {\n      layout: 'centered',\n    },\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  // Sets the layout parameter component wide.\n  parameters: {\n    layout: 'centered',\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  // Sets the layout parameter component wide.\n  parameters: {\n    layout: 'centered',\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    // Sets the layout parameter component wide.\n    parameters: {\n      layout: 'centered',\n    },\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  // Sets the layout parameter component wide.\n  parameters: {\n    layout: 'centered',\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n  // Sets the layout parameter component wide.\n  parameters: {\n    layout: 'centered',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n  // Sets the layout parameter component wide.\n  parameters: {\n    layout: 'centered',\n  },\n};\n\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  // Sets the layout parameter component wide.\n  parameters: {\n    layout: 'centered',\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  // Sets the layout parameter component wide.\n  parameters: {\n    layout: 'centered',\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  // Sets the layout parameter component wide.\n  parameters: {\n    layout: 'centered',\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  // Sets the layout parameter component wide.\n  parameters: {\n    layout: 'centered',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  // Sets the layout parameter component wide.\n  parameters: {\n    layout: 'centered',\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-config-layout.md",
    "content": "```js filename=\".storybook/manager.js\" renderer=\"common\" language=\"js\"\nimport { addons } from 'storybook/manager-api';\n\naddons.setConfig({\n  navSize: 300,\n  bottomPanelHeight: 300,\n  rightPanelWidth: 300,\n  panelPosition: 'bottom',\n  enableShortcuts: true,\n  showToolbar: true,\n  theme: undefined,\n  selectedPanel: undefined,\n  initialActive: 'sidebar',\n  layoutCustomisations: {\n    showSidebar(state, defaultValue) {\n      return state.storyId === 'landing' ? false : defaultValue;\n    },\n    showToolbar(state, defaultValue) {\n      return state.viewMode === 'docs' ? false : defaultValue;\n    },\n  },\n  sidebar: {\n    showRoots: false,\n    collapsedRoots: ['other'],\n  },\n  toolbar: {\n    title: { hidden: false },\n    zoom: { hidden: false },\n    eject: { hidden: false },\n    copy: { hidden: false },\n    fullscreen: { hidden: false },\n  },\n});\n```\n\n```ts filename=\".storybook/manager.ts\" renderer=\"common\" language=\"ts\"\nimport { addons, type State } from 'storybook/manager-api';\n\naddons.setConfig({\n  navSize: 300,\n  bottomPanelHeight: 300,\n  rightPanelWidth: 300,\n  panelPosition: 'bottom',\n  enableShortcuts: true,\n  showToolbar: true,\n  theme: undefined,\n  selectedPanel: undefined,\n  initialActive: 'sidebar',\n  layoutCustomisations: {\n    showSidebar(state: State, defaultValue: boolean) {\n      return state.storyId === 'landing' ? false : defaultValue;\n    },\n    showToolbar(state: State, defaultValue: boolean) {\n      return state.viewMode === 'docs' ? false : defaultValue;\n    },\n  },\n  sidebar: {\n    showRoots: false,\n    collapsedRoots: ['other'],\n  },\n  toolbar: {\n    title: { hidden: false },\n    zoom: { hidden: false },\n    eject: { hidden: false },\n    copy: { hidden: false },\n    fullscreen: { hidden: false },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-coverage-addon-config-options.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  stories: [],\n  addons: [\n    // Other Storybook addons\n    {\n      name: '@storybook/addon-coverage',\n      options: {\n        istanbul: {\n          include: ['**/stories/**'],\n          exclude: ['**/exampleDirectory/**'],\n        },\n      },\n    },\n  ],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// For Vite support add the following import\n// import type { AddonOptionsVite } from '@storybook/addon-coverage';\n\nimport type { AddonOptionsWebpack } from '@storybook/addon-coverage';\n\n// Replace your-framework with the framework and builder you are using (e.g., react-webpack5, vue3-webpack5)\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst coverageConfig: AddonOptionsWebpack = {\n  istanbul: {\n    include: ['**/stories/**'],\n    exclude: ['**/exampleDirectory/**'],\n  },\n};\n\nconst config: StorybookConfig = {\n  stories: [],\n  addons: [\n    // Other Storybook addons\n    {\n      name: '@storybook/addon-coverage',\n      options: coverageConfig,\n    },\n  ],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\n// For Vite support add the following import\n// import type { AddonOptionsVite } from '@storybook/addon-coverage';\nimport type { AddonOptionsWebpack } from '@storybook/addon-coverage';\n\nconst coverageConfig: AddonOptionsWebpack = {\n  istanbul: {\n    include: ['**/stories/**'],\n    exclude: ['**/exampleDirectory/**'],\n  },\n};\n\nexport default defineMain({\n  stories: [],\n  addons: [\n    // Other Storybook addons\n    {\n      name: '@storybook/addon-coverage',\n      options: coverageConfig,\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  stories: [],\n  addons: [\n    // Other Storybook addons\n    {\n      name: '@storybook/addon-coverage',\n      options: {\n        istanbul: {\n          include: ['**/stories/**'],\n          exclude: ['**/exampleDirectory/**'],\n        },\n      },\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nimport type { AddonOptionsVite } from '@storybook/addon-coverage';\n\nconst coverageConfig: AddonOptionsVite = {\n  istanbul: {\n    include: ['**/stories/**'],\n    exclude: ['**/exampleDirectory/**'],\n  },\n};\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: [],\n  addons: [\n    // Other Storybook addons\n    {\n      name: '@storybook/addon-coverage',\n      options: coverageConfig,\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: [],\n  addons: [\n    // Other Storybook addons\n    {\n      name: '@storybook/addon-coverage',\n      options: {\n        istanbul: {\n          include: ['**/stories/**'],\n          exclude: ['**/exampleDirectory/**'],\n        },\n      },\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\n// For Vite support add the following import\n// import type { AddonOptionsVite } from '@storybook/addon-coverage';\nimport type { AddonOptionsWebpack } from '@storybook/addon-coverage';\n\nconst coverageConfig: AddonOptionsWebpack = {\n  istanbul: {\n    include: ['**/stories/**'],\n    exclude: ['**/exampleDirectory/**'],\n  },\n};\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: [],\n  addons: [\n    // Other Storybook addons\n    {\n      name: '@storybook/addon-coverage',\n      options: coverageConfig,\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nimport type { AddonOptionsVite } from '@storybook/addon-coverage';\n\nconst coverageConfig: AddonOptionsVite = {\n  istanbul: {\n    include: ['**/stories/**'],\n    exclude: ['**/exampleDirectory/**'],\n  },\n};\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: [],\n  addons: [\n    // Other Storybook addons\n    {\n      name: '@storybook/addon-coverage',\n      options: coverageConfig,\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: [],\n  addons: [\n    // Other Storybook addons\n    {\n      name: '@storybook/addon-coverage',\n      options: {\n        istanbul: {\n          include: ['**/stories/**'],\n          exclude: ['**/exampleDirectory/**'],\n        },\n      },\n    },\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-coverage-addon-install.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook@latest add @storybook/addon-coverage\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx storybook@latest add @storybook/addon-coverage\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn dlx storybook@latest add @storybook/addon-coverage\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-coverage-addon-optimized-config.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-docs', '@storybook/addon-vitest', '@storybook/addon-coverage'],\n  build: {\n    test: {\n      disabledAddons: ['@storybook/addon-docs'],\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-docs', '@storybook/addon-vitest', '@storybook/addon-coverage'],\n  build: {\n    test: {\n      disabledAddons: ['@storybook/addon-docs'],\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-docs', '@storybook/addon-vitest', '@storybook/addon-coverage'],\n  build: {\n    test: {\n      disabledAddons: ['@storybook/addon-docs'],\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-docs', '@storybook/addon-vitest', '@storybook/addon-coverage'],\n  build: {\n    test: {\n      disabledAddons: ['@storybook/addon-docs'],\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-docs', '@storybook/addon-vitest', '@storybook/addon-coverage'],\n  build: {\n    test: {\n      disabledAddons: ['@storybook/addon-docs'],\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-docs', '@storybook/addon-vitest', '@storybook/addon-coverage'],\n  build: {\n    test: {\n      disabledAddons: ['@storybook/addon-docs'],\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-docs', '@storybook/addon-vitest', '@storybook/addon-coverage'],\n  build: {\n    test: {\n      disabledAddons: ['@storybook/addon-docs'],\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-docs', '@storybook/addon-vitest', '@storybook/addon-coverage'],\n  build: {\n    test: {\n      disabledAddons: ['@storybook/addon-docs'],\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-docs', '@storybook/addon-vitest', '@storybook/addon-coverage'],\n  build: {\n    test: {\n      disabledAddons: ['@storybook/addon-docs'],\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-coverage-report-lcov.md",
    "content": "```shell renderer=\"common\" language=\"js\"\nnpx nyc report --reporter=lcov -t coverage/storybook --report-dir coverage/storybook\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-coverage-report-vue.md",
    "content": "```js filename=\".nyc.config.js\" renderer=\"common\" language=\"js\" tabTitle=\"JavaScript configuration\"\nexport default {\n  // Other configuration options\n  extension: ['.js', '.cjs', '.mjs', '.ts', '.tsx', '.jsx', '.vue'],\n};\n```\n\n```json filename=\".nycrc.json\" renderer=\"common\" language=\"json\" tabTitle=\"JSON configuration\"\n{\n  \"extension\": [\".js\", \".cjs\", \".mjs\", \".ts\", \".tsx\", \".jsx\", \".vue\"]\n}\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-csf-3-auto-title-redundant.md",
    "content": "```ts filename=\"components/MyComponent/MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  component: MyComponent,\n  title: 'components/MyComponent/MyComponent',\n};\n\nexport default meta;\ntype Story = StoryObj<MyComponent>;\n\nexport const Basic: Story = {\n  args: {\n    something: 'Something else',\n  },\n};\n```\n\n```ts filename=\"components/MyComponent/MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  component: MyComponent,\n  title: 'components/MyComponent/MyComponent',\n});\n\nexport const Basic = meta.story({\n  args: {\n    something: 'Something else',\n  },\n});\n```\n\n```svelte filename=\"components/MyComponent/MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n    title: 'components/MyComponent/MyComponent',\n  });\n</script>\n\n<Story name=\"Default\" args={{ something: 'Something else' }} />\n```\n\n```js filename=\"components/MyComponent/MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.svelte';\n\nexport default {\n  component: MyComponent,\n  title: 'components/MyComponent/MyComponent',\n};\n\nexport const Basic = {\n  args: {\n    something: 'Something else',\n  },\n};\n```\n\n```js filename=\"components/MyComponent/MyComponent.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n  title: 'components/MyComponent/MyComponent',\n};\n\nexport const Basic = {\n  args: {\n    something: 'Something else',\n  },\n};\n```\n\n```svelte filename=\"components/MyComponent/MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n    title: 'components/MyComponent/MyComponent',\n  });\n</script>\n\n<Story name=\"Default\" args={{ something: 'Something else'}} />\n```\n\n```ts filename=\"components/MyComponent/MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport MyComponent from './MyComponent.svelte';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  component: MyComponent,\n  title: 'components/MyComponent/MyComponent',\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  args: {\n    something: 'Something else',\n  },\n};\n```\n\n```ts filename=\"components/MyComponent/MyComponent.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  component: MyComponent,\n  title: 'components/MyComponent/MyComponent',\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  args: {\n    something: 'Something else',\n  },\n};\n```\n\n```js filename=\"components/MyComponent/MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'my-component',\n  title: 'components/MyComponent/MyComponent',\n};\n\nexport const Basic = {\n  args: {\n    something: 'Something else',\n  },\n};\n```\n\n```ts filename=\"components/MyComponent/MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'my-component',\n  title: 'components/MyComponent/MyComponent',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Basic: Story = {\n  args: {\n    something: 'Something else',\n  },\n};\n```\n\n```js filename=\"components/MyComponent/MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n  title: 'components/MyComponent/MyComponent',\n});\n\nexport const Basic = meta.story({\n  args: {\n    something: 'Something else',\n  },\n});\n```\n\n```ts filename=\"components/MyComponent/MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n  title: 'components/MyComponent/MyComponent',\n});\n\nexport const Basic = meta.story({\n  args: {\n    something: 'Something else',\n  },\n});\n```\n\n```ts filename=\"components/MyComponent/MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  component: MyComponent,\n  title: 'components/MyComponent/MyComponent',\n});\n\nexport const Basic = meta.story({\n  args: {\n    something: 'Something else',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"components/MyComponent/MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n  title: 'components/MyComponent/MyComponent',\n});\n\nexport const Basic = meta.story({\n  args: {\n    something: 'Something else',\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-custom-docs-markdown.md",
    "content": "<!-- prettier-ignore -->\n```mdx filename=\"Changelog.mdx\" renderer=\"common\" language=\"mdx\"\nimport { Meta, Markdown } from '@storybook/addon-docs/blocks';\n\nimport Readme from '../../Changelog.md?raw';\n\n<Meta title=\"Changelog\" />\n\n# Changelog\n\n<Markdown>{Readme}</Markdown>\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-custom-manager-head.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  managerHead: (head) => `\n    ${head}\n    <link rel=\"icon\" type=\"image/png\" href=\"/logo192.png\" sizes=\"192x192\" />\n  `,\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  managerHead: (head) => `\n    ${head}\n    <link rel=\"icon\" type=\"image/png\" href=\"/logo192.png\" sizes=\"192x192\" />\n  `,\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  managerHead: (head) => `\n    ${head}\n    <link rel=\"icon\" type=\"image/png\" href=\"/logo192.png\" sizes=\"192x192\" />\n  `,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  managerHead: (head) => `\n    ${head}\n    <link rel=\"icon\" type=\"image/png\" href=\"/logo192.png\" sizes=\"192x192\" />\n  `,\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  managerHead: (head) => `\n    ${head}\n    <link rel=\"icon\" type=\"image/png\" href=\"/logo192.png\" sizes=\"192x192\" />\n  `,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  managerHead: (head) => `\n    ${head}\n    <link rel=\"icon\" type=\"image/png\" href=\"/logo192.png\" sizes=\"192x192\" />\n  `,\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  managerHead: (head) => `\n    ${head}\n    <link rel=\"icon\" type=\"image/png\" href=\"/logo192.png\" sizes=\"192x192\" />\n  `,\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  managerHead: (head) => `\n    ${head}\n    <link rel=\"icon\" type=\"image/png\" href=\"/logo192.png\" sizes=\"192x192\" />\n  `,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  managerHead: (head) => `\n    ${head}\n    <link rel=\"icon\" type=\"image/png\" href=\"/logo192.png\" sizes=\"192x192\" />\n  `,\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-debug-webpack-dev.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm run storybook -- --debug-webpack\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn storybook --debug-webpack\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-debug-webpack-prod.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm run build-storybook -- --debug-webpack\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn build-storybook --debug-webpack\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-disable-telemetry-env.md",
    "content": "```shell renderer=\"common\" language=\"js\"\nSTORYBOOK_DISABLE_TELEMETRY=true yarn storybook\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-disable-telemetry-flag.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm run storybook -- --disable-telemetry\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm run storybook --disable-telemetry\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn storybook --disable-telemetry\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-doctor.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook@latest doctor\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx storybook@latest doctor\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn dlx storybook@latest doctor\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-ember-cli-build.md",
    "content": "```js filename=\"ember-cli-build.js\" renderer=\"ember\" language=\"js\"\n'use strict';\n\nconst EmberApp = require('ember-cli/lib/broccoli/ember-app');\n\nmodule.exports = function (defaults) {\n  const app = new EmberApp(defaults, {\n    '@storybook/ember-cli-storybook': {\n      enableAddonDocsIntegration: true,\n    },\n  });\n\n  return app.toTree();\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-extract-specific-version.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook@7.5.3 extract\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx storybook@7.5.3 extract\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn dlx storybook@7.5.3 extract\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-figma-addon-install.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook@latest add @storybook/addon-designs\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx storybook@latest add @storybook/addon-designs\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn dlx storybook@latest add @storybook/addon-designs\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-fix-imports-autodocs-monorepo.md",
    "content": "```js filename=\"MyComponent.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\n// ❌ Don't use the package's index file to import the component.\n// import { MyComponent } from '@component-package';\n\n// ✅ Use the component's export to import it directly.\nimport { MyComponent } from '@component-package/src/MyComponent';\n\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'MyComponent',\n  component: MyComponent,\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\n// ❌ Don't use the package's index file to import the component.\n// import { MyComponent } from '@component-package';\n\n// ✅ Use the component's export to import it directly.\nimport { MyComponent } from '@component-package/src/MyComponent';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'MyComponent',\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\n// ❌ Don't use the package's index file to import the component.\n// import { MyComponent } from '@component-package';\n\n// ✅ Use the component's export to import it directly.\nimport { MyComponent } from '@component-package/src/my-component.component';\n\nconst meta: Meta<MyComponent> = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'MyComponent',\n  component: MyComponent,\n};\n\nexport default meta;\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n// ❌ Don't use the package's index file to import the component.\n// import { MyComponent } from '@component-package';\n\n// ✅ Use the component's export to import it directly.\nimport { MyComponent } from '@component-package/src/my-component.component';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'MyComponent',\n  component: MyComponent,\n});\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n// ❌ Don't use the package's index file to import the component.\n// import { MyComponent } from '@component-package';\n\n// ✅ Use the component's export to import it directly.\nimport { MyComponent } from '@component-package/src/MyComponent';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'MyComponent',\n  component: MyComponent,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n// ❌ Don't use the package's index file to import the component.\n// import { MyComponent } from '@component-package';\n\n// ✅ Use the component's export to import it directly.\nimport { MyComponent } from '@component-package/src/MyComponent';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'MyComponent',\n  component: MyComponent,\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n// ❌ Don't use the package's index file to import the component.\n// import { MyComponent } from '@component-package';\n\n// ✅ Use the component's export to import it directly.\nimport MyComponent from '@component-package/src/MyComponent.vue';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'MyComponent',\n  component: MyComponent,\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n// ❌ Don't use the package's index file to import the component.\n// import { MyComponent } from '@component-package';\n\n// ✅ Use the component's export to import it directly.\nimport MyComponent from '@component-package/src/MyComponent.vue';\n\nconst meta = preview.meta({\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'MyComponent',\n  component: MyComponent,\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-framework-render-function.md",
    "content": "```js filename=\"your-framework/src/client/preview/render.ts\" renderer=\"common\" language=\"js\"\nconst rootElement = document.getElementById('root');\n\nexport default function renderMain({ storyFn }: RenderMainArgs) {\n  const storyObj = storyFn();\n  const html = fn(storyObj);\n  rootElement.innerHTML = html;\n}\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-generated-argtypes.md",
    "content": "```js renderer=\"common\" language=\"js\"\nconst argTypes = {\n  label: {\n    name: 'label',\n    type: { name: 'string', required: false },\n    defaultValue: 'Hello',\n    description: 'demo description',\n    table: {\n      type: { summary: 'string' },\n      defaultValue: { summary: 'Hello' },\n    },\n    control: {\n      type: 'text',\n    },\n  },\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-init-v7.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook@^7 init\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx storybook@^7 init\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn dlx storybook@^7 init\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-interactions-play-function.md",
    "content": "```ts filename=\"Form.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\nimport { expect, fn, waitFor } from 'storybook/test';\n\nimport { Form } from './form.component';\n\nconst meta: Meta<Form> = {\n  component: Form,\n  args: {\n    // 👇 Use `fn` to spy on the submit output\n    submit: fn(),\n  },\n};\nexport default meta;\n\ntype Story = StoryObj<Form>;\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const Submitted: Story = {\n  play: async ({ args, canvas, step, userEvent }) => {\n    await step('Enter credentials', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await waitFor(() => expect(args.onSubmit).toHaveBeenCalled());\n  },\n};\n```\n\n```ts filename=\"Form.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { expect, fn, waitFor } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { Form } from './form.component';\n\nconst meta = preview.meta({\n  component: Form,\n  args: {\n    // 👇 Use `fn` to spy on the submit output\n    submit: fn(),\n  },\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const Submitted = meta.story({\n  play: async ({ args, canvas, step, userEvent }) => {\n    await step('Enter credentials', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await waitFor(() => expect(args.onSubmit).toHaveBeenCalled());\n  },\n});\n```\n\n```svelte filename=\"Form.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { expect, fn, waitFor } from 'storybook/test';\n\n  import Form from './Form.svelte';\n\n  const { Story } = defineMeta({\n    component: Form,\n    args: {\n      // 👇 Use `fn` to spy on the submit output\n      onSubmit: fn(),\n    },\n  });\n</script>\n\n<!--\n  See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n  to learn more about using the canvas to query the DOM\n -->\n<Story\n  name=\"Submitted\"\n  play={async ({ args, canvas, step, userEvent }) => {\n    await step('Enter credentials', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await waitFor(() => expect(args.onSubmit).toHaveBeenCalled());\n  }}\n/>\n```\n\n```js filename=\"Form.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport { expect, fn, waitFor } from 'storybook/test';\n\nimport Form from './Form.svelte';\n\nexport default {\n  component: Form,\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n};\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const Submitted = {\n  play: async ({ args, canvas, step, userEvent }) => {\n    // Starts querying the component from its root element\n    await step('Enter credentials', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await waitFor(() => expect(args.onSubmit).toHaveBeenCalled());\n  },\n};\n```\n\n```js filename=\"Form.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { expect, fn, waitFor } from 'storybook/test';\n\nimport { Form } from './Form';\n\nexport default {\n  component: Form,\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n};\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const Submitted = {\n  play: async ({ args, canvas, step, userEvent }) => {\n    // Starts querying the component from its root element\n    await step('Enter credentials', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await waitFor(() => expect(args.onSubmit).toHaveBeenCalled());\n  },\n};\n```\n\n```svelte filename=\"Form.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import { expect, fn, waitFor } from 'storybook/test';\n\n  import Form from './Form.svelte';\n\n  const { Story } = defineMeta({\n    component: Form,\n    args: {\n      // 👇 Use `fn` to spy on the submit output\n      onSubmit: fn(),\n    },\n  });\n</script>\n\n<!--\n  See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n  to learn more about using the canvas to query the DOM\n -->\n<Story\n  name=\"Submitted\"\n  play={async ({ args, canvas, step, userEvent }) => {\n    await step('Enter credentials', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await waitFor(() => expect(args.onSubmit).toHaveBeenCalled());\n  }}\n/>\n```\n\n```ts filename=\"Form.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { expect, fn, waitFor } from 'storybook/test';\n\nimport Form from './Form.svelte';\n\nconst meta = {\n  component: Form,\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n} satisfies Meta<typeof Form>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const Submitted: Story = {\n  play: async ({ args, canvas, step, userEvent }) => {\n    await step('Enter credentials', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await waitFor(() => expect(args.onSubmit).toHaveBeenCalled());\n  },\n};\n```\n\n```ts filename=\"Form.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { expect, fn, waitFor } from 'storybook/test';\n\nimport { Form } from './Form';\n\nconst meta = {\n  component: Form,\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n} satisfies Meta<typeof Form>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const Submitted: Story = {\n  play: async ({ args, canvas, step, userEvent }) => {\n    await step('Enter credentials', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await waitFor(() => expect(args.onSubmit).toHaveBeenCalled());\n  },\n};\n```\n\n```js filename=\"Form.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { expect, fn, waitFor } from 'storybook/test';\n\nexport default {\n  component: 'my-form-element',\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n};\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const Submitted = {\n  play: async ({ args, canvas, step, userEvent }) => {\n    await step('Enter credentials', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await waitFor(() => expect(args.onSubmit).toHaveBeenCalled());\n  },\n};\n```\n\n```ts filename=\"Form.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { expect, fn, waitFor } from 'storybook/test';\n\nconst meta: Meta = {\n  component: 'my-form-element',\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n};\nexport default meta;\n\ntype Story = StoryObj;\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const Submitted: Story = {\n  play: async ({ args, canvas, step, userEvent }) => {\n    await step('Enter credentials', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await waitFor(() => expect(args.onSubmit).toHaveBeenCalled());\n  },\n};\n```\n\n```js filename=\"Form.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { expect, fn, waitFor } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-form-element',\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const Submitted = meta.story({\n  play: async ({ args, canvas, step, userEvent }) => {\n    await step('Enter credentials', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await waitFor(() => expect(args.onSubmit).toHaveBeenCalled());\n  },\n});\n```\n\n```ts filename=\"Form.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { expect, fn, waitFor } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-form-element',\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const Submitted = meta.story({\n  play: async ({ args, canvas, step, userEvent }) => {\n    await step('Enter credentials', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await waitFor(() => expect(args.onSubmit).toHaveBeenCalled());\n  },\n});\n```\n\n```ts filename=\"Form.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { expect, fn, waitFor } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { Form } from './Form';\n\nconst meta = preview.meta({\n  component: Form,\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const Submitted = meta.story({\n  play: async ({ args, canvas, step, userEvent }) => {\n    await step('Enter credentials', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await waitFor(() => expect(args.onSubmit).toHaveBeenCalled());\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Form.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { expect, fn, waitFor } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport { Form } from './Form';\n\nconst meta = preview.meta({\n  component: Form,\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const Submitted = meta.story({\n  play: async ({ args, canvas, step, userEvent }) => {\n    // Starts querying the component from its root element\n    await step('Enter credentials', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await waitFor(() => expect(args.onSubmit).toHaveBeenCalled());\n  },\n});\n```\n\n```ts filename=\"Form.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { expect, fn, waitFor } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport Form from './Form.vue';\n\nconst meta = preview.meta({\n  component: Form,\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const Submitted = meta.story({\n  play: async ({ args, canvas, step, userEvent }) => {\n    await step('Enter credentials', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await waitFor(() => expect(args.onSubmit).toHaveBeenCalled());\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Form.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { expect, fn, waitFor } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\nimport Form from './Form.vue';\n\nconst meta = preview.meta({\n  component: Form,\n  args: {\n    // 👇 Use `fn` to spy on the onSubmit arg\n    onSubmit: fn(),\n  },\n});\n\n/*\n * See https://storybook.js.org/docs/writing-stories/play-function#working-with-the-canvas\n * to learn more about using the canvas to query the DOM\n */\nexport const Submitted = meta.story({\n  play: async ({ args, canvas, step, userEvent }) => {\n    // Starts querying the component from its root element\n    await step('Enter credentials', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n\n    // 👇 Now we can assert that the onSubmit arg was called\n    await waitFor(() => expect(args.onSubmit).toHaveBeenCalled());\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-interactions-step-function.md",
    "content": "```js filename=\"MyComponent.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\n// ...rest of story file\n\nexport const Submitted = {\n  play: async ({ args, canvas, step, userEvent }) => {\n    await step('Enter email and password', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// ...rest of story file\n\nexport const Submitted: Story = {\n  play: async ({ args, canvas, step, userEvent }) => {\n    await step('Enter email and password', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n  },\n};\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Submitted = meta.story({\n  play: async ({ args, canvas, step, userEvent }) => {\n    await step('Enter email and password', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Submitted = meta.story({\n  play: async ({ args, canvas, step }) => {\n    await step('Enter email and password', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Submitted = meta.story({\n  play: async ({ args, canvas, step }) => {\n    await step('Enter email and password', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Submitted = meta.story({\n  play: async ({ args, canvas, step }) => {\n    await step('Enter email and password', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport MyComponent from './MyComponent.vue';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\nexport const Submitted = meta.story({\n  play: async ({ args, canvas, step }) => {\n    await step('Enter email and password', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n  },\n});\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const Submitted = meta.story({\n  play: async ({ args, canvas, step }) => {\n    await step('Enter email and password', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n  },\n});\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'my-component',\n});\n\nexport const Submitted = meta.story({\n  play: async ({ args, canvas, step }) => {\n    await step('Enter email and password', async () => {\n      await userEvent.type(canvas.getByTestId('email'), 'hi@example.com');\n      await userEvent.type(canvas.getByTestId('password'), 'supersecret');\n    });\n\n    await step('Submit form', async () => {\n      await userEvent.click(canvas.getByRole('button'));\n    });\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-advanced-config-example.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  viteFinal: async (config, options) => {\n    // Update config here\n    return config;\n  },\n  webpackFinal: async (config, options) => {\n    // Change webpack config\n    return config;\n  },\n  babel: async (config, options) => {\n    return config;\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, angular, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  viteFinal: async (config, options) => {\n    // Update config here\n    return config;\n  },\n  webpackFinal: async (config, options) => {\n    // Change webpack config\n    return config;\n  },\n  babel: async (config, options) => {\n    return config;\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  viteFinal: async (config, options) => {\n    // Update config here\n    return config;\n  },\n  webpackFinal: async (config, options) => {\n    // Change webpack config\n    return config;\n  },\n  babel: async (config, options) => {\n    return config;\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  viteFinal: async (config, options) => {\n    // Update config here\n    return config;\n  },\n  webpackFinal: async (config, options) => {\n    // Change webpack config\n    return config;\n  },\n  babel: async (config, options) => {\n    return config;\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  viteFinal: async (config, options) => {\n    // Update config here\n    return config;\n  },\n  webpackFinal: async (config, options) => {\n    // Change webpack config\n    return config;\n  },\n  babel: async (config, options) => {\n    return config;\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  viteFinal: async (config, options) => {\n    // Update config here\n    return config;\n  },\n  webpackFinal: async (config, options) => {\n    // Change webpack config\n    return config;\n  },\n  babel: async (config, options) => {\n    return config;\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  viteFinal: async (config, options) => {\n    // Update config here\n    return config;\n  },\n  webpackFinal: async (config, options) => {\n    // Change webpack config\n    return config;\n  },\n  babel: async (config, options) => {\n    return config;\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  viteFinal: async (config, options) => {\n    // Update config here\n    return config;\n  },\n  webpackFinal: async (config, options) => {\n    // Change webpack config\n    return config;\n  },\n  babel: async (config, options) => {\n    return config;\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  viteFinal: async (config, options) => {\n    // Update config here\n    return config;\n  },\n  webpackFinal: async (config, options) => {\n    // Change webpack config\n    return config;\n  },\n  babel: async (config, options) => {\n    return config;\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-auto-title-custom.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: [\n    {\n      directory: '../src',\n      titlePrefix: 'Custom', // 👈 Configure the title prefix\n    },\n  ],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: [\n    {\n      directory: '../src',\n      titlePrefix: 'Custom', // 👈 Configure the title prefix\n    },\n  ],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: [\n    {\n      directory: '../src',\n      titlePrefix: 'Custom', // 👈 Configure the title prefix\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: [\n    {\n      directory: '../src',\n      titlePrefix: 'Custom', // 👈 Configure the title prefix\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: [\n    {\n      directory: '../src',\n      titlePrefix: 'Custom', // 👈 Configure the title prefix\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: [\n    {\n      directory: '../src',\n      titlePrefix: 'Custom', // 👈 Configure the title prefix\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: [\n    {\n      directory: '../src',\n      titlePrefix: 'Custom', // 👈 Configure the title prefix\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: [\n    {\n      directory: '../src',\n      titlePrefix: 'Custom', // 👈 Configure the title prefix\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: [\n    {\n      directory: '../src',\n      titlePrefix: 'Custom', // 👈 Configure the title prefix\n    },\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-config-remark-options.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport remarkGfm from 'remark-gfm';\n\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // Other addons go here\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        mdxPluginOptions: {\n          mdxCompileOptions: {\n            remarkPlugins: [remarkGfm],\n          },\n        },\n      },\n    },\n  ],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\nimport remarkGfm from 'remark-gfm';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // Other addons go here\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        mdxPluginOptions: {\n          mdxCompileOptions: {\n            remarkPlugins: [remarkGfm],\n          },\n        },\n      },\n    },\n  ],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nimport remarkGfm from 'remark-gfm';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // Other addons go here\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        mdxPluginOptions: {\n          mdxCompileOptions: {\n            remarkPlugins: [remarkGfm],\n          },\n        },\n      },\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nimport remarkGfm from 'remark-gfm';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // Other addons go here\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        mdxPluginOptions: {\n          mdxCompileOptions: {\n            remarkPlugins: [remarkGfm],\n          },\n        },\n      },\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nimport remarkGfm from 'remark-gfm';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // Other addons go here\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        mdxPluginOptions: {\n          mdxCompileOptions: {\n            remarkPlugins: [remarkGfm],\n          },\n        },\n      },\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nimport remarkGfm from 'remark-gfm';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // Other addons go here\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        mdxPluginOptions: {\n          mdxCompileOptions: {\n            remarkPlugins: [remarkGfm],\n          },\n        },\n      },\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nimport remarkGfm from 'remark-gfm';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // Other addons go here\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        mdxPluginOptions: {\n          mdxCompileOptions: {\n            remarkPlugins: [remarkGfm],\n          },\n        },\n      },\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nimport remarkGfm from 'remark-gfm';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // Other addons go here\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        mdxPluginOptions: {\n          mdxCompileOptions: {\n            remarkPlugins: [remarkGfm],\n          },\n        },\n      },\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nimport remarkGfm from 'remark-gfm';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    // Other addons go here\n    {\n      name: '@storybook/addon-docs',\n      options: {\n        mdxPluginOptions: {\n          mdxCompileOptions: {\n            remarkPlugins: [remarkGfm],\n          },\n        },\n      },\n    },\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-configuration-src-dir.md",
    "content": "```js filename=\"./storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src'],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src'],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"./storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src'],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-disable-telemetry.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableTelemetry: true, // 👈 Disables telemetry\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableTelemetry: true, // 👈 Disables telemetry\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableTelemetry: true, // 👈 Disables telemetry\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableTelemetry: true, // 👈 Disables telemetry\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableTelemetry: true, // 👈 Disables telemetry\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableTelemetry: true, // 👈 Disables telemetry\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableTelemetry: true, // 👈 Disables telemetry\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableTelemetry: true, // 👈 Disables telemetry\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    disableTelemetry: true, // 👈 Disables telemetry\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-extend-ts-config.md",
    "content": "```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    check: false,\n    checkOptions: {},\n    skipCompiler: false,\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    check: false,\n    checkOptions: {},\n    skipCompiler: false,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    skipCompiler: false,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    check: false,\n    checkOptions: {},\n    skipCompiler: false,\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    skipCompiler: false,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-fix-imports-autodocs-monorepo.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    // Overrides the default Typescript configuration to allow multi-package components to be documented via Autodocs.\n    reactDocgen: 'react-docgen',\n    check: false,\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    // Overrides the default Typescript configuration to allow multi-package components to be documented via Autodocs.\n    reactDocgen: 'react-docgen',\n    check: false,\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    // Overrides the default Typescript configuration to allow multi-package components to be documented via Autodocs.\n    reactDocgen: 'react-docgen',\n    check: false,\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    // Overrides the default Typescript configuration to allow multi-package components to be documented via Autodocs.\n    reactDocgen: 'react-docgen',\n    check: false,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-js-md-files.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../my-project/src/components/*.@(js|md)'],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../my-project/src/components/*.@(js|md)'],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../my-project/src/components/*.@(js|md)'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../my-project/src/components/*.@(js|md)'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../my-project/src/components/*.@(js|md)'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../my-project/src/components/*.@(js|md)'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../my-project/src/components/*.@(js|md)'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../my-project/src/components/*.@(js|md)'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../my-project/src/components/*.@(js|md)'],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-pnpm-with-module-resolution.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst getAbsolutePath = (packageName) =>\n  dirname(fileURLToPath(import.meta.resolve(`${packageName}/package.json`)));\n\nexport default {\n  framework: {\n    // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n    name: getAbsolutePath('@storybook/your-framework'),\n    options: {},\n  },\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    //👇 Use getAbsolutePath when referencing Storybook's addons and frameworks\n    getAbsolutePath('@storybook/addon-docs'),\n  ],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nimport { dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst getAbsolutePath = (packageName: string) =>\n  dirname(fileURLToPath(import.meta.resolve(`${packageName}/package.json`)));\n\nconst config: StorybookConfig = {\n  framework: {\n    // Replace your-framework with the same one you've imported above.\n    name: getAbsolutePath('@storybook/your-framework'),\n    options: {},\n  },\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    //👇 Use getAbsolutePath when referencing Storybook's addons and frameworks\n    getAbsolutePath('@storybook/addon-docs'),\n  ],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nconst getAbsolutePath = (packageName: string) =>\n  dirname(fileURLToPath(import.meta.resolve(join(packageName, 'package.json'))));\n\nexport default defineMain({\n  framework: {\n    // Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\n    name: getAbsolutePath('@storybook/your-framework'),\n    options: {},\n  },\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    //👇 Use getAbsolutePath when referencing Storybook's addons and frameworks\n    getAbsolutePath('@storybook/addon-docs'),\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nconst getAbsolutePath = (packageName) =>\n  dirname(fileURLToPath(import.meta.resolve(join(packageName, 'package.json'))));\n\nexport default defineMain({\n  framework: {\n    name: getAbsolutePath('@storybook/your-framework'),\n    options: {},\n  },\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    //👇 Use getAbsolutePath when referencing Storybook's addons and frameworks\n    getAbsolutePath('@storybook/addon-docs'),\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nconst getAbsolutePath = (packageName: string) =>\n  dirname(fileURLToPath(import.meta.resolve(join(packageName, 'package.json'))));\n\nexport default defineMain({\n  framework: {\n    name: getAbsolutePath('@storybook/vue3-vite'),\n    options: {},\n  },\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    //👇 Use getAbsolutePath when referencing Storybook's addons and frameworks\n    getAbsolutePath('@storybook/addon-docs'),\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nconst getAbsolutePath = (packageName) =>\n  dirname(fileURLToPath(import.meta.resolve(join(packageName, 'package.json'))));\n\nexport default defineMain({\n  framework: {\n    name: getAbsolutePath('@storybook/vue3-vite'),\n    options: {},\n  },\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    //👇 Use getAbsolutePath when referencing Storybook's addons and frameworks\n    getAbsolutePath('@storybook/addon-docs'),\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { defineMain } from '@storybook/angular/node';\n\nconst getAbsolutePath = (packageName: string) =>\n  dirname(fileURLToPath(import.meta.resolve(join(packageName, 'package.json'))));\n\nexport default defineMain({\n  framework: {\n    name: getAbsolutePath('@storybook/angular'),\n    options: {},\n  },\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    //👇 Use getAbsolutePath when referencing Storybook's addons and frameworks\n    getAbsolutePath('@storybook/addon-docs'),\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nconst getAbsolutePath = (packageName: string) =>\n  dirname(fileURLToPath(import.meta.resolve(join(packageName, 'package.json'))));\n\nexport default defineMain({\n  framework: {\n    name: getAbsolutePath('@storybook/web-components-vite'),\n    options: {},\n  },\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    //👇 Use getAbsolutePath when referencing Storybook's addons and frameworks\n    getAbsolutePath('@storybook/addon-docs'),\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nconst getAbsolutePath = (packageName) =>\n  dirname(fileURLToPath(import.meta.resolve(join(packageName, 'package.json'))));\n\nexport default defineMain({\n  framework: {\n    name: getAbsolutePath('@storybook/web-components-vite'),\n    options: {},\n  },\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: [\n    //👇 Use getAbsolutePath when referencing Storybook's addons and frameworks\n    getAbsolutePath('@storybook/addon-docs'),\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-preview-head.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\"\nexport default {\n  previewHead: (head) => (`\n    ${head}\n    <style>\n      #main {\n        background-color: yellow;\n      }\n    </style>\n  `);\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-prop-filter.md",
    "content": "```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    reactDocgen: 'react-docgen-typescript',\n    reactDocgenTypescriptOptions: {\n      compilerOptions: {\n        allowSyntheticDefaultImports: false,\n        esModuleInterop: false,\n      },\n      // Filter out third-party props from node_modules except @mui packages.\n      propFilter: (prop) =>\n        prop.parent ? !/node_modules\\/(?!@mui)/.test(prop.parent.fileName) : true,\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    reactDocgen: 'react-docgen-typescript',\n    reactDocgenTypescriptOptions: {\n      compilerOptions: {\n        allowSyntheticDefaultImports: false,\n        esModuleInterop: false,\n      },\n      // Filter out third-party props from node_modules except @mui packages.\n      propFilter: (prop) =>\n        prop.parent ? !/node_modules\\/(?!@mui)/.test(prop.parent.fileName) : true,\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-rdt-monorepo-include.md",
    "content": "```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    reactDocgen: 'react-docgen-typescript',\n    reactDocgenTypescriptOptions: {\n      // 👇 Add your workspace package source files so they're included in the TS program\n      include: ['**/*.tsx', '../../packages/ui/src/**/*.tsx'],\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    reactDocgen: 'react-docgen-typescript',\n    reactDocgenTypescriptOptions: {\n      // 👇 Add your workspace package source files so they're included in the TS program\n      include: ['**/*.tsx', '../../packages/ui/src/**/*.tsx'],\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-react-docgen-typescript.md",
    "content": "```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    reactDocgen: 'react-docgen-typescript',\n    // Provide your own options if necessary.\n    // See https://storybook.js.org/docs/configure/typescript for more information.\n    reactDocgenTypescriptOptions: {},\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  typescript: {\n    reactDocgen: 'react-docgen-typescript',\n    // Provide your own options if necessary.\n    // See https://storybook.js.org/docs/configure/typescript for more information.\n    reactDocgenTypescriptOptions: {},\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-ref-local.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    react: {\n      title: 'React',\n      url: 'http://localhost:7007',\n    },\n    angular: {\n      title: 'Angular',\n      url: 'http://localhost:7008',\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    react: {\n      title: 'React',\n      url: 'http://localhost:7007',\n    },\n    angular: {\n      title: 'Angular',\n      url: 'http://localhost:7008',\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    react: {\n      title: 'React',\n      url: 'http://localhost:7007',\n    },\n    angular: {\n      title: 'Angular',\n      url: 'http://localhost:7008',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    react: {\n      title: 'React',\n      url: 'http://localhost:7007',\n    },\n    angular: {\n      title: 'Angular',\n      url: 'http://localhost:7008',\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    react: {\n      title: 'React',\n      url: 'http://localhost:7007',\n    },\n    angular: {\n      title: 'Angular',\n      url: 'http://localhost:7008',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    react: {\n      title: 'React',\n      url: 'http://localhost:7007',\n    },\n    angular: {\n      title: 'Angular',\n      url: 'http://localhost:7008',\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    react: {\n      title: 'React',\n      url: 'http://localhost:7007',\n    },\n    angular: {\n      title: 'Angular',\n      url: 'http://localhost:7008',\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    react: {\n      title: 'React',\n      url: 'http://localhost:7007',\n    },\n    angular: {\n      title: 'Angular',\n      url: 'http://localhost:7008',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  refs: {\n    react: {\n      title: 'React',\n      url: 'http://localhost:7007',\n    },\n    angular: {\n      title: 'Angular',\n      url: 'http://localhost:7008',\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-register-addon.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\"\nexport default {\n  addons: ['path/to/manager.js'],\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-register-example-addon.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  addons: [\n    // Other Storybook addons\n    '@storybook/addon-a11y',\n  ],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  addons: [\n    // Other Storybook addons\n    '@storybook/addon-a11y',\n  ],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  addons: [\n    // Other Storybook addons\n    '@storybook/addon-a11y',\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  addons: [\n    // Other Storybook addons\n    '@storybook/addon-a11y',\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  addons: [\n    // Other Storybook addons\n    '@storybook/addon-a11y',\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  addons: [\n    // Other Storybook addons\n    '@storybook/addon-a11y',\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  addons: [\n    // Other Storybook addons\n    '@storybook/addon-a11y',\n  ],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  addons: [\n    // Other Storybook addons\n    '@storybook/addon-a11y',\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  addons: [\n    // Other Storybook addons\n    '@storybook/addon-a11y',\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-register-presets-managerentry.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\"\nexport default {\n  addons: [\n    '@storybook/addon-docs/preset', // A preset registered here, in this case from the addon-docs addon.\n  ],\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-simplified-config.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-webpack5, nextjs, angular, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    config.plugins.push(/* ... */);\n    return config;\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-webpack5, nextjs, angular, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    config.plugins.push(/* ... */);\n    return config;\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using, e.g. react-webpack5, nextjs, etc.\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    config.plugins.push(/* ... */);\n    return config;\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using, e.g. react-webpack5, nextjs, etc.\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    config.plugins.push(/* ... */);\n    return config;\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    config.plugins.push(/* ... */);\n    return config;\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-ts-module-resolution-atsign-import.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport path from 'path';\n\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-webpack5, nextjs, angular, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],\n  webpackFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.alias = {\n        ...config.resolve.alias,\n        '@': path.resolve(process.cwd(), 'src'),\n      };\n    }\n    return config;\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\nimport path from 'path';\n// Replace your-framework with the framework you are using, e.g. react-webpack5, nextjs, angular, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],\n  webpackFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.alias = {\n        ...config.resolve.alias,\n        '@': path.resolve(process.cwd(), 'src'),\n      };\n    }\n    return config;\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using, e.g. react-webpack5, nextjs, etc.\nimport { defineMain } from '@storybook/your-framework/node';\n\nimport path from 'path';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],\n  webpackFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.alias = {\n        ...config.resolve.alias,\n        '@': path.resolve(process.cwd(), 'src'),\n      };\n    }\n    return config;\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using, e.g. react-webpack5, nextjs, etc.\nimport { defineMain } from '@storybook/your-framework/node';\n\nimport path from 'path';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],\n  webpackFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.alias = {\n        ...config.resolve.alias,\n        '@': path.resolve(process.cwd(), 'src'),\n      };\n    }\n    return config;\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nimport path from 'path';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],\n  webpackFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.alias = {\n        ...config.resolve.alias,\n        '@': path.resolve(process.cwd(), 'src'),\n      };\n    }\n    return config;\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-ts-module-resolution.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin';\n\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-webpack5, nextjs, angular, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.plugins = [\n        ...(config.resolve.plugins || []),\n        new TsconfigPathsPlugin({\n          extensions: config.resolve.extensions,\n        }),\n      ];\n    }\n    return config;\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-webpack5, nextjs, angular, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nimport TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.plugins = [\n        ...(config.resolve.plugins || []),\n        new TsconfigPathsPlugin({\n          extensions: config.resolve.extensions,\n        }),\n      ];\n    }\n    return config;\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nimport TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.plugins = [\n        ...(config.resolve.plugins || []),\n        new TsconfigPathsPlugin({\n          extensions: config.resolve.extensions,\n        }),\n      ];\n    }\n    return config;\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nimport TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.plugins = [\n        ...(config.resolve.plugins || []),\n        new TsconfigPathsPlugin({\n          extensions: config.resolve.extensions,\n        }),\n      ];\n    }\n    return config;\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nimport TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    if (config.resolve) {\n      config.resolve.plugins = [\n        ...(config.resolve.plugins || []),\n        new TsconfigPathsPlugin({\n          extensions: config.resolve.extensions,\n        }),\n      ];\n    }\n    return config;\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-use-manager-entries.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\"\nexport default {\n  managerEntries: ['some-storybook-addon/entry-point.js'],\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-using-existing-config.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport custom from '../webpack.config.js'; // 👈 Custom Webpack configuration being imported.\n\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-webpack5, nextjs, angular, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    return {\n      ...config,\n      module: { ...config.module, rules: [...config.module.rules, ...custom.module.rules] },\n    };\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-webpack5, nextjs, angular, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nimport custom from '../webpack.config.js'; // 👈 Custom Webpack configuration being imported.\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    return {\n      ...config,\n      module: { ...config.module, rules: [...config.module.rules, ...custom.module.rules] },\n    };\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs)\nimport { defineMain } from '@storybook/your-framework/node';\n\nimport custom from '../webpack.config.js'; // 👈 Custom Webpack configuration being imported.\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    return {\n      ...config,\n      module: { ...config.module, rules: [...config.module.rules, ...custom.module.rules] },\n    };\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs)\nimport { defineMain } from '@storybook/your-framework/node';\n\nimport custom from '../webpack.config.js'; // 👈 Custom Webpack configuration being imported.\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    return {\n      ...config,\n      module: { ...config.module, rules: [...config.module.rules, ...custom.module.rules] },\n    };\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nimport custom from '../webpack.config.js'; // 👈 Custom Webpack configuration being imported.\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  webpackFinal: async (config) => {\n    return {\n      ...config,\n      module: { ...config.module, rules: [...config.module.rules, ...custom.module.rules] },\n    };\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-versioned-webpack.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\"\nexport function webpackFinal(config, { presets }) {\n  const version = await presets.apply('webpackVersion');\n  const instance = (await presets.apply('webpackInstance'))?.default;\n\n  logger.info(`=> Running in webpack ${version}: ${instance}`);\n  return config;\n}\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-webpack-options.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-webpack5, nextjs, angular, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: {\n      name: '@storybook/builder-webpack5',\n      options: {\n        fsCache: true,\n        lazyCompilation: true,\n      },\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-webpack5, nextjs, angular, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: {\n      name: '@storybook/builder-webpack5',\n      options: {\n        fsCache: true,\n        lazyCompilation: true,\n      },\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: {\n      name: '@storybook/builder-webpack5',\n      options: {\n        fsCache: true,\n        lazyCompilation: true,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: {\n      name: '@storybook/builder-webpack5',\n      options: {\n        fsCache: true,\n        lazyCompilation: true,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: {\n      name: '@storybook/builder-webpack5',\n      options: {\n        fsCache: true,\n        lazyCompilation: true,\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-webpack-preset-config.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\"\nexport async function webpack(baseConfig, options) {\n  // Modify or replace config.\n  // Mutating the original reference object can cause unexpected bugs,\n  // so in this example we replace.\n  const { module = {} } = baseConfig;\n\n  return {\n    ...baseConfig,\n    module: {\n      ...module,\n      rules: [\n        ...(module.rules || []),\n        {\n          /* some new loader */\n        },\n      ],\n    },\n  };\n}\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-webpack5-fsCache.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\"\nexport default {\n  core: {\n    builder: {\n      name: 'webpack5',\n      options: {\n        fsCache: true,\n      },\n    },\n  },\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-webpack5-lazyCompilation.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\"\nexport default {\n  core: {\n    builder: {\n      name: 'webpack5',\n      options: {\n        lazyCompilation: true,\n      },\n    },\n  },\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-webpack5.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\"\nexport default {\n  core: {\n    builder: '@storybook/builder-webpack5',\n  },\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-main-webpackfinal-example.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\"\nexport function webpackFinal(config, { configDir }) {\n  if (!isReactScriptsInstalled()) {\n    logger.info('Using base config because react-scripts is not installed.');\n    return config;\n  }\n\n  logger.info('Loading create-react-app config.');\n  return applyCRAWebpackConfig(config, configDir);\n}\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-manager-addon-panel-hide-on-showcase.md",
    "content": "```js filename=\"./storybook/manager.js\" renderer=\"common\" language=\"js\"\nimport { addons } from 'storybook/manager-api';\n\naddons.setConfig({\n  layoutCustomisations: {\n    showPanel(state, defaultValue) {\n      const tags = state.index?.[state.storyId]?.tags ?? [];\n\n      // Hide the panel on stories designed to showcase multiple variants or usage examples.\n      if (tags.includes('showcase') || tags.includes('kitchensink')) {\n        return false;\n      }\n\n      return defaultValue;\n    },\n  },\n});\n```\n\n```ts filename=\"./storybook/manager.ts\" renderer=\"common\" language=\"ts\"\nimport { addons, type State } from 'storybook/manager-api';\n\naddons.setConfig({\n  layoutCustomisations: {\n    showPanel(state: State, defaultValue: boolean) {\n      const tags = state.index?.[state.storyId]?.tags ?? [];\n\n      // Hide the panel on stories designed to showcase multiple variants or usage examples.\n      if (tags.includes('showcase') || tags.includes('kitchensink')) {\n        return false;\n      }\n\n      return defaultValue;\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-manager-custom-theme.md",
    "content": "```js filename=\".storybook/manager.js\" renderer=\"common\" language=\"js\"\nimport { addons } from 'storybook/manager-api';\nimport yourTheme from './YourTheme';\n\naddons.setConfig({\n  theme: yourTheme,\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-manager-dark-theme.md",
    "content": "```js filename=\".storybook/manager.js\" renderer=\"common\" language=\"js\"\nimport { addons } from 'storybook/manager-api';\nimport { themes } from 'storybook/theming';\n\naddons.setConfig({\n  theme: themes.dark,\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-manager-disable-roots.md",
    "content": "```js filename=\"./storybook/manager.js\" renderer=\"common\" language=\"js\"\nimport { addons } from 'storybook/manager-api';\n\naddons.setConfig({\n  sidebar: {\n    showRoots: false,\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-manager-render-label-stories.md",
    "content": "```js filename=\".storybook/manager.js\" renderer=\"common\" language=\"js\"\nimport { addons } from 'storybook/manager-api';\n\nimport startCase from 'lodash/startCase.js';\n\naddons.setConfig({\n  sidebar: {\n    renderLabel: ({ name, type }) => (type === 'story' ? name : startCase(name)),\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-manager-sidebar-hide-on-landing.md",
    "content": "```js filename=\"./storybook/manager.js\" renderer=\"common\" language=\"js\"\nimport { addons } from 'storybook/manager-api';\n\naddons.setConfig({\n  layoutCustomisations: {\n    // Hide the sidebar on the landing page, which has its own nav links to other pages.\n    showSidebar(state, defaultValue) {\n      if (state.storyId === 'landing' && state.viewMode === 'docs') {\n        return false;\n      }\n\n      return defaultValue;\n    },\n  },\n});\n```\n\n```ts filename=\"./storybook/manager.ts\" renderer=\"common\" language=\"ts\"\nimport { addons, type State } from 'storybook/manager-api';\n\naddons.setConfig({\n  layoutCustomisations: {\n    // Hide the sidebar on the landing page, which has its own nav links to other pages.\n    showSidebar(state: State, defaultValue: boolean) {\n      if (state.storyId === 'landing' && state.viewMode === 'docs') {\n        return false;\n      }\n\n      return defaultValue;\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-manager-toolbar-hide-on-docs.md",
    "content": "```js filename=\"./storybook/manager.js\" renderer=\"common\" language=\"js\"\nimport { addons } from 'storybook/manager-api';\n\naddons.setConfig({\n  layoutCustomisations: {\n    // Always hide the toolbar on docs pages, and respect user preferences elsewhere.\n    showToolbar(state, defaultValue) {\n      if (state.viewMode === 'docs') {\n        return false;\n      }\n\n      return defaultValue;\n    },\n  },\n});\n```\n\n```ts filename=\"./storybook/manager.ts\" renderer=\"common\" language=\"ts\"\nimport { addons, type State } from 'storybook/manager-api';\n\naddons.setConfig({\n  layoutCustomisations: {\n    // Always hide the toolbar on docs pages, and respect user preferences elsewhere.\n    showToolbar(state: State, defaultValue: boolean) {\n      if (state.viewMode === 'docs') {\n        return false;\n      }\n\n      return defaultValue;\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-mdx-template-with-prop.md",
    "content": "<!-- prettier-ignore -->\n```mdx filename=\"DocumentationTemplate.mdx\" renderer=\"common\" language=\"mdx\"\nimport { Meta, Title, Primary, Controls, Stories } from '@storybook/addon-docs/blocks';\n\n{/*\n  * 👇 The isTemplate property is required to tell Storybook that this is a template\n  * See https://storybook.js.org/docs/api/doc-blocks/doc-block-meta\n  * to learn how to use\n*/}\n\n<Meta isTemplate />\n\n<Title />\n\n# Default implementation\n\n<Primary />\n\n## Inputs\n\nThe component accepts the following inputs (props):\n\n<Controls />\n\n---\n\n## Additional variations\n\nListed below are additional variations of the component.\n\n<Stories />\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-merged-argtypes.md",
    "content": "```js renderer=\"common\" language=\"js\"\nconst argTypes = {\n  label: {\n    name: 'label',\n    type: { name: 'string', required: false },\n    defaultValue: 'Hello',\n    description: 'overwritten description',\n    table: {\n      type: {\n        summary: 'something short',\n        detail: 'something really really long',\n      },\n      defaultValue: { summary: 'Hello' },\n    },\n    control: {\n      type: null,\n    },\n  },\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-migrate-csf-2-to-3.md",
    "content": "```sh renderer=\"common\" language=\"js\" packageManager=\"npm\"\n# Convert CSF 2 to CSF 3\nnpx storybook@latest migrate csf-2-to-3 --glob=\"**/*.stories.tsx\" --parser=tsx\n```\n\n```sh renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\n# Convert CSF 2 to CSF 3\npnpm dlx storybook@latest migrate csf-2-to-3 --glob=\"**/*.stories.tsx\" --parser=tsx\n```\n\n```sh renderer=\"common\" language=\"js\" packageManager=\"yarn\"\n# Convert CSF 2 to CSF 3\nyarn dlx storybook@latest migrate csf-2-to-3 --glob=\"**/*.stories.tsx\" --parser=tsx\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-migrate-mdx-to-csf.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\n# Convert stories in MDX to CSF\nnpx storybook@latest migrate mdx-to-csf --glob \"src/**/*.stories.mdx\"\n```\n\n```sh renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\n# Convert stories in MDX to CSF\npnpm dlx storybook@latest migrate mdx-to-csf --glob \"src/**/*.stories.mdx\"\n```\n\n```sh renderer=\"common\" language=\"js\" packageManager=\"yarn\"\n# Convert stories in MDX to CSF\nyarn dlx storybook@latest migrate mdx-to-csf --glob \"src/**/*.stories.mdx\"\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-migrate-stories-of-to-csf.md",
    "content": "```sh renderer=\"common\" language=\"js\" packageManager=\"npm\"\n# Convert storiesOf to CSF 1\nnpx storybook@latest migrate storiesof-to-csf --glob=\"**/*.stories.tsx\" --parser=tsx\n```\n\n```sh renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\n# Convert storiesOf to CSF 1\npnpm dlx storybook@latest migrate storiesof-to-csf --glob=\"**/*.stories.tsx\" --parser=tsx\n```\n\n```sh renderer=\"common\" language=\"js\" packageManager=\"yarn\"\n# Convert storiesOf to CSF 1\nyarn dlx storybook@latest migrate storiesof-to-csf --glob=\"**/*.stories.tsx\" --parser=tsx\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preset-full-config-object.md",
    "content": "```js filename=\".storybook/my-preset.js\" renderer=\"common\" language=\"js\"\nexport default {\n  managerWebpack: async (config, options) => {\n    // Update config here\n    return config;\n  },\n  webpackFinal: async (config, options) => {\n    return config;\n  },\n  babel: async (config, options) => {\n    return config;\n  },\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-auto-docs-custom-docs-container.md",
    "content": "```jsx filename=\".storybook/preview.jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport * as React from 'react';\n\nimport { DocsContainer } from '@storybook/addon-docs/blocks';\n\nconst ExampleContainer = ({ children, ...props }) => {\n  return <DocsContainer {...props}>{children}</DocsContainer>;\n};\n\nexport default {\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      container: ExampleContainer,\n    },\n  },\n};\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\nimport * as React from 'react';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\nimport { DocsContainer } from '@storybook/addon-docs/blocks';\n\nconst ExampleContainer = ({ children, ...props }) => {\n  return <DocsContainer {...props}>{children}</DocsContainer>;\n};\n\nconst preview: Preview = {\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      container: ExampleContainer,\n    },\n  },\n};\n\nexport default preview;\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport addonDocs from '@storybook/addon-docs';\nimport { DocsContainer } from '@storybook/addon-docs/blocks';\n\nconst ExampleContainer = ({ children, ...props }) => {\n  return <DocsContainer {...props}>{children}</DocsContainer>;\n};\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      container: ExampleContainer,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\".storybook/preview.jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport addonDocs from '@storybook/addon-docs';\nimport { DocsContainer } from '@storybook/addon-docs/blocks';\n\nconst ExampleContainer = ({ children, ...props }) => {\n  return <DocsContainer {...props}>{children}</DocsContainer>;\n};\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      container: ExampleContainer,\n    },\n  },\n});\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\nimport { DocsContainer } from '@storybook/addon-docs/blocks';\n\nconst ExampleContainer = ({ children, ...props }) => {\n  return <DocsContainer {...props}>{children}</DocsContainer>;\n};\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      container: ExampleContainer,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\".storybook/preview.jsx\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\nimport { DocsContainer } from '@storybook/addon-docs/blocks';\n\nconst ExampleContainer = ({ children, ...props }) => {\n  return <DocsContainer {...props}>{children}</DocsContainer>;\n};\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      container: ExampleContainer,\n    },\n  },\n});\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\nimport { definePreview } from '@storybook/angular';\nimport addonDocs from '@storybook/addon-docs';\nimport { DocsContainer } from '@storybook/addon-docs/blocks';\n\nconst ExampleContainer = ({ children, ...props }) => {\n  return <DocsContainer {...props}>{children}</DocsContainer>;\n};\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      container: ExampleContainer,\n    },\n  },\n});\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\nimport { DocsContainer } from '@storybook/addon-docs/blocks';\n\nconst ExampleContainer = ({ children, ...props }) => {\n  return <DocsContainer {...props}>{children}</DocsContainer>;\n};\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      container: ExampleContainer,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\".storybook/preview.jsx\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\nimport { DocsContainer } from '@storybook/addon-docs/blocks';\n\nconst ExampleContainer = ({ children, ...props }) => {\n  return <DocsContainer {...props}>{children}</DocsContainer>;\n};\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      container: ExampleContainer,\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-auto-docs-custom-mdx-template.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport DocumentationTemplate from './DocumentationTemplate.mdx';\n\nexport default {\n  parameters: {\n    docs: {\n      page: DocumentationTemplate,\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nimport DocumentationTemplate from './DocumentationTemplate.mdx';\n\nconst preview = {\n  parameters: {\n    docs: {\n      page: DocumentationTemplate,\n    },\n  },\n} satisfies Preview;\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\n\nimport DocumentationTemplate from './DocumentationTemplate.mdx';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      page: DocumentationTemplate,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\n\nimport DocumentationTemplate from './DocumentationTemplate.mdx';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      page: DocumentationTemplate,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nimport DocumentationTemplate from './DocumentationTemplate.mdx';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      page: DocumentationTemplate,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nimport DocumentationTemplate from './DocumentationTemplate.mdx';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      page: DocumentationTemplate,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\nimport addonDocs from '@storybook/addon-docs';\n\nimport DocumentationTemplate from './DocumentationTemplate.mdx';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      page: DocumentationTemplate,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nimport DocumentationTemplate from './DocumentationTemplate.mdx';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      page: DocumentationTemplate,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nimport DocumentationTemplate from './DocumentationTemplate.mdx';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      page: DocumentationTemplate,\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-auto-docs-custom-template-function.md",
    "content": "```jsx filename=\".storybook/preview.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport * as React from 'react';\n\nimport {\n  Title,\n  Subtitle,\n  Description,\n  Primary,\n  Controls,\n  Stories,\n} from '@storybook/addon-docs/blocks';\n\nexport default {\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      page: () => (\n        <>\n          <Title />\n          <Subtitle />\n          <Description />\n          <Primary />\n          <Controls />\n          <Stories />\n        </>\n      ),\n    },\n  },\n};\n```\n\n```tsx filename=\".storybook/preview.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\nimport * as React from 'react';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\nimport {\n  Title,\n  Subtitle,\n  Description,\n  Primary,\n  Controls,\n  Stories,\n} from '@storybook/addon-docs/blocks';\n\nconst preview: Preview = {\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      page: () => (\n        <>\n          <Title />\n          <Subtitle />\n          <Description />\n          <Primary />\n          <Controls />\n          <Stories />\n        </>\n      ),\n    },\n  },\n};\n\nexport default preview;\n```\n\n```tsx filename=\".storybook/preview.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\nimport {\n  Controls,\n  Description,\n  Primary,\n  Stories,\n  Subtitle,\n  Title,\n} from '@storybook/addon-docs/blocks';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      page: () => (\n        <>\n          <Title />\n          <Subtitle />\n          <Description />\n          <Primary />\n          <Controls />\n          <Stories />\n        </>\n      ),\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\".storybook/preview.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\nimport {\n  Controls,\n  Description,\n  Primary,\n  Stories,\n  Subtitle,\n  Title,\n} from '@storybook/addon-docs/blocks';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      page: () => (\n        <>\n          <Title />\n          <Subtitle />\n          <Description />\n          <Primary />\n          <Controls />\n          <Stories />\n        </>\n      ),\n    },\n  },\n});\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\nimport {\n  Controls,\n  Description,\n  Primary,\n  Stories,\n  Subtitle,\n  Title,\n} from '@storybook/addon-docs/blocks';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      page: () => (\n        <>\n          <Title />\n          <Subtitle />\n          <Description />\n          <Primary />\n          <Controls />\n          <Stories />\n        </>\n      ),\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\".storybook/preview.jsx\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\nimport {\n  Controls,\n  Description,\n  Primary,\n  Stories,\n  Subtitle,\n  Title,\n} from '@storybook/addon-docs/blocks';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      page: () => (\n        <>\n          <Title />\n          <Subtitle />\n          <Description />\n          <Primary />\n          <Controls />\n          <Stories />\n        </>\n      ),\n    },\n  },\n});\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\nimport { definePreview } from '@storybook/angular';\nimport addonDocs from '@storybook/addon-docs';\nimport {\n  Controls,\n  Description,\n  Primary,\n  Stories,\n  Subtitle,\n  Title,\n} from '@storybook/addon-docs/blocks';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      page: () => (\n        <>\n          <Title />\n          <Subtitle />\n          <Description />\n          <Primary />\n          <Controls />\n          <Stories />\n        </>\n      ),\n    },\n  },\n});\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\nimport {\n  Controls,\n  Description,\n  Primary,\n  Stories,\n  Subtitle,\n  Title,\n} from '@storybook/addon-docs/blocks';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      page: () => (\n        <>\n          <Title />\n          <Subtitle />\n          <Description />\n          <Primary />\n          <Controls />\n          <Stories />\n        </>\n      ),\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\".storybook/preview.jsx\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\n\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\nimport {\n  Controls,\n  Description,\n  Primary,\n  Stories,\n  Subtitle,\n  Title,\n} from '@storybook/addon-docs/blocks';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      page: () => (\n        <>\n          <Title />\n          <Subtitle />\n          <Description />\n          <Primary />\n          <Controls />\n          <Stories />\n        </>\n      ),\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-auto-docs-override-mdx-container.md",
    "content": "```jsx filename=\".storybook/preview.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport * as React from 'react';\nimport { MDXProvider } from '@mdx-js/react';\n\nimport { DocsContainer } from '@storybook/addon-docs/blocks';\n\nimport * as DesignSystem from 'your-design-system';\n\nexport const MyDocsContainer = (props) => (\n  <MDXProvider\n    components={{\n      h1: DesignSystem.H1,\n      h2: DesignSystem.H2,\n    }}\n  >\n    <DocsContainer {...props} />\n  </MDXProvider>\n);\n\nexport default {\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      container: MyDocsContainer,\n    },\n  },\n};\n```\n\n```tsx filename=\".storybook/preview.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\nimport * as React from 'react';\nimport { MDXProvider } from '@mdx-js/react';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\nimport { DocsContainer } from '@storybook/addon-docs/blocks';\n\nimport * as DesignSystem from 'your-design-system';\n\nexport const MyDocsContainer = (props) => (\n  <MDXProvider\n    components={{\n      h1: DesignSystem.H1,\n      h2: DesignSystem.H2,\n    }}\n  >\n    <DocsContainer {...props} />\n  </MDXProvider>\n);\n\nconst preview: Preview = {\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      container: MyDocsContainer,\n    },\n  },\n};\n\nexport default preview;\n```\n\n```tsx filename=\".storybook/preview.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\nimport { MDXProvider } from '@mdx-js/react';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\nimport { DocsContainer } from '@storybook/addon-docs/blocks';\n\nimport * as DesignSystem from 'your-design-system';\n\nexport const MyDocsContainer = (props) => (\n  <MDXProvider\n    components={{\n      h1: DesignSystem.H1,\n      h2: DesignSystem.H2,\n    }}\n  >\n    <DocsContainer {...props} />\n  </MDXProvider>\n);\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      container: MyDocsContainer,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\".storybook/preview.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\nimport { MDXProvider } from '@mdx-js/react';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\nimport { DocsContainer } from '@storybook/addon-docs/blocks';\n\nimport * as DesignSystem from 'your-design-system';\n\nexport const MyDocsContainer = (props) => (\n  <MDXProvider\n    components={{\n      h1: DesignSystem.H1,\n      h2: DesignSystem.H2,\n    }}\n  >\n    <DocsContainer {...props} />\n  </MDXProvider>\n);\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      container: MyDocsContainer,\n    },\n  },\n});\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\nimport { MDXProvider } from '@mdx-js/react';\n\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\nimport { DocsContainer } from '@storybook/addon-docs/blocks';\n\nimport * as DesignSystem from 'your-design-system';\n\nexport const MyDocsContainer = (props) => (\n  <MDXProvider\n    components={{\n      h1: DesignSystem.H1,\n      h2: DesignSystem.H2,\n    }}\n  >\n    <DocsContainer {...props} />\n  </MDXProvider>\n);\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      container: MyDocsContainer,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\".storybook/preview.jsx\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\nimport { MDXProvider } from '@mdx-js/react';\n\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\nimport { DocsContainer } from '@storybook/addon-docs/blocks';\n\nimport * as DesignSystem from 'your-design-system';\n\nexport const MyDocsContainer = (props) => (\n  <MDXProvider\n    components={{\n      h1: DesignSystem.H1,\n      h2: DesignSystem.H2,\n    }}\n  >\n    <DocsContainer {...props} />\n  </MDXProvider>\n);\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      container: MyDocsContainer,\n    },\n  },\n});\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\nimport { MDXProvider } from '@mdx-js/react';\n\nimport { definePreview } from '@storybook/angular';\nimport addonDocs from '@storybook/addon-docs';\nimport { DocsContainer } from '@storybook/addon-docs/blocks';\n\nimport * as DesignSystem from 'your-design-system';\n\nexport const MyDocsContainer = (props) => (\n  <MDXProvider\n    components={{\n      h1: DesignSystem.H1,\n      h2: DesignSystem.H2,\n    }}\n  >\n    <DocsContainer {...props} />\n  </MDXProvider>\n);\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      container: MyDocsContainer,\n    },\n  },\n});\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\nimport { MDXProvider } from '@mdx-js/react';\n\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\nimport { DocsContainer } from '@storybook/addon-docs/blocks';\n\nimport * as DesignSystem from 'your-design-system';\n\nexport const MyDocsContainer = (props) => (\n  <MDXProvider\n    components={{\n      h1: DesignSystem.H1,\n      h2: DesignSystem.H2,\n    }}\n  >\n    <DocsContainer {...props} />\n  </MDXProvider>\n);\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      container: MyDocsContainer,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\".storybook/preview.jsx\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport * as React from 'react';\nimport { MDXProvider } from '@mdx-js/react';\n\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\nimport { DocsContainer } from '@storybook/addon-docs/blocks';\n\nimport * as DesignSystem from 'your-design-system';\n\nexport const MyDocsContainer = (props) => (\n  <MDXProvider\n    components={{\n      h1: DesignSystem.H1,\n      h2: DesignSystem.H2,\n    }}\n  >\n    <DocsContainer {...props} />\n  </MDXProvider>\n);\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      container: MyDocsContainer,\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-auto-docs-override-theme.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { themes, ensure } from 'storybook/theming';\n\nexport default {\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      theme: ensure(themes.dark), // The replacement theme to use\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\nimport { themes, ensure } from 'storybook/theming';\n\nconst preview: Preview = {\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      theme: ensure(themes.dark), // The replacement theme to use\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\nimport { ensure, themes } from 'storybook/theming';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      theme: ensure(themes.dark), // The replacement theme to use\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\nimport { ensure, themes } from 'storybook/theming';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      theme: ensure(themes.dark), // The replacement theme to use\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\nimport { ensure, themes } from 'storybook/theming';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      theme: ensure(themes.dark), // The replacement theme to use\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\nimport { ensure, themes } from 'storybook/theming';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      theme: ensure(themes.dark), // The replacement theme to use\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\nimport addonDocs from '@storybook/addon-docs';\nimport { ensure, themes } from 'storybook/theming';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      theme: ensure(themes.dark), // The replacement theme to use\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\nimport { ensure, themes } from 'storybook/theming';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      theme: ensure(themes.dark), // The replacement theme to use\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\nimport { ensure, themes } from 'storybook/theming';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n    docs: {\n      theme: ensure(themes.dark), // The replacement theme to use\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-body-example.md",
    "content": "```html filename=\".storybook/preview-body.html\" renderer=\"common\" language=\"js\"\n<div id=\"custom-root\"></div>\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-body-font-size.md",
    "content": "```html filename=\".storybook/preview-body.html\" renderer=\"common\" language=\"js\"\n<style>\n  html {\n    font-size: 15px;\n  }\n</style>\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-compodoc-config.md",
    "content": "```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\"\nimport type { Preview } from '@storybook/angular';\nimport { setCompodocJson } from '@storybook/addon-docs/angular';\n\nimport docJson from '../documentation.json'; // The path to your generated json file from Compodoc contains all your documentation information.\n\nsetCompodocJson(docJson);\n\nconst preview: Preview = {\n  parameters: {\n    actions: { argTypesRegex: '^on[A-Z].*' },\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n};\n\nexport default preview;\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-configure-globaltypes.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nconst preview = {\n  globalTypes: {\n    theme: {\n      description: 'Global theme for components',\n      toolbar: {\n        // The label to show for this toolbar item\n        title: 'Theme',\n        icon: 'circlehollow',\n        // Array of plain string values or MenuItem shape (see below)\n        items: ['light', 'dark'],\n        // Change title based on selected value (recommended for consistency with the Storybook UI)\n        dynamicTitle: true,\n      },\n    },\n  },\n  initialGlobals: {\n    theme: 'light',\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  globalTypes: {\n    theme: {\n      description: 'Global theme for components',\n      toolbar: {\n        // The label to show for this toolbar item\n        title: 'Theme',\n        icon: 'circlehollow',\n        // Array of plain string values or MenuItem shape (see below)\n        items: ['light', 'dark'],\n        // Change title based on selected value (recommended for consistency with the Storybook UI)\n        dynamicTitle: true,\n      },\n    },\n  },\n  initialGlobals: {\n    theme: 'light',\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  globalTypes: {\n    theme: {\n      description: 'Global theme for components',\n      toolbar: {\n        // The label to show for this toolbar item\n        title: 'Theme',\n        icon: 'circlehollow',\n        // Array of plain string values or MenuItem shape (see below)\n        items: ['light', 'dark'],\n        // Change title based on selected value (recommended for consistency with the Storybook UI)\n        dynamicTitle: true,\n      },\n    },\n  },\n  initialGlobals: {\n    theme: 'light',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  globalTypes: {\n    theme: {\n      description: 'Global theme for components',\n      toolbar: {\n        // The label to show for this toolbar item\n        title: 'Theme',\n        icon: 'circlehollow',\n        // Array of plain string values or MenuItem shape (see below)\n        items: ['light', 'dark'],\n        // Change title based on selected value (recommended for consistency with the Storybook UI)\n        dynamicTitle: true,\n      },\n    },\n  },\n  initialGlobals: {\n    theme: 'light',\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  globalTypes: {\n    theme: {\n      description: 'Global theme for components',\n      toolbar: {\n        // The label to show for this toolbar item\n        title: 'Theme',\n        icon: 'circlehollow',\n        // Array of plain string values or MenuItem shape (see below)\n        items: ['light', 'dark'],\n        // Change title based on selected value\n        dynamicTitle: true,\n      },\n    },\n  },\n  initialGlobals: {\n    theme: 'light',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  globalTypes: {\n    theme: {\n      description: 'Global theme for components',\n      toolbar: {\n        // The label to show for this toolbar item\n        title: 'Theme',\n        icon: 'circlehollow',\n        // Array of plain string values or MenuItem shape (see below)\n        items: ['light', 'dark'],\n        // Change title based on selected value\n        dynamicTitle: true,\n      },\n    },\n  },\n  initialGlobals: {\n    theme: 'light',\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  globalTypes: {\n    theme: {\n      description: 'Global theme for components',\n      toolbar: {\n        // The label to show for this toolbar item\n        title: 'Theme',\n        icon: 'circlehollow',\n        // Array of plain string values or MenuItem shape (see below)\n        items: ['light', 'dark'],\n        // Change title based on selected value\n        dynamicTitle: true,\n      },\n    },\n  },\n  initialGlobals: {\n    theme: 'light',\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  globalTypes: {\n    theme: {\n      description: 'Global theme for components',\n      toolbar: {\n        // The label to show for this toolbar item\n        title: 'Theme',\n        icon: 'circlehollow',\n        // Array of plain string values or MenuItem shape (see below)\n        items: ['light', 'dark'],\n        // Change title based on selected value\n        dynamicTitle: true,\n      },\n    },\n  },\n  initialGlobals: {\n    theme: 'light',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  globalTypes: {\n    theme: {\n      description: 'Global theme for components',\n      toolbar: {\n        // The label to show for this toolbar item\n        title: 'Theme',\n        icon: 'circlehollow',\n        // Array of plain string values or MenuItem shape (see below)\n        items: ['light', 'dark'],\n        // Change title based on selected value\n        dynamicTitle: true,\n      },\n    },\n  },\n  initialGlobals: {\n    theme: 'light',\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-custom-canvas.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyCanvas } from './MyCanvas';\n\nexport default {\n  parameters: {\n    docs: {\n      components: {\n        Canvas: MyCanvas,\n      },\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nimport { MyCanvas } from './MyCanvas';\n\nconst preview: Preview = {\n  parameters: {\n    docs: {\n      components: {\n        Canvas: MyCanvas,\n      },\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { MyCanvas } from './MyCanvas';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      components: {\n        Canvas: MyCanvas,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { MyCanvas } from './MyCanvas';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      components: {\n        Canvas: MyCanvas,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { MyCanvas } from './MyCanvas';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      components: {\n        Canvas: MyCanvas,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { MyCanvas } from './MyCanvas';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      components: {\n        Canvas: MyCanvas,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { MyCanvas } from './MyCanvas';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      components: {\n        Canvas: MyCanvas,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { MyCanvas } from './MyCanvas';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      components: {\n        Canvas: MyCanvas,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { MyCanvas } from './MyCanvas';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      components: {\n        Canvas: MyCanvas,\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-custom-code-renderer.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { CodeBlock } from './CodeBlock';\n\nexport default {\n  parameters: {\n    docs: {\n      components: {\n        code: CodeBlock,\n      },\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nimport { CodeBlock } from './CodeBlock';\n\nconst preview: Preview = {\n  parameters: {\n    docs: {\n      components: {\n        code: CodeBlock,\n      },\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { CodeBlock } from './CodeBlock';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      components: {\n        code: CodeBlock,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { CodeBlock } from './CodeBlock';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      components: {\n        code: CodeBlock,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { CodeBlock } from './CodeBlock';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      components: {\n        code: CodeBlock,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { CodeBlock } from './CodeBlock';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      components: {\n        code: CodeBlock,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { CodeBlock } from './CodeBlock';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      components: {\n        code: CodeBlock,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { CodeBlock } from './CodeBlock';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      components: {\n        code: CodeBlock,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { CodeBlock } from './CodeBlock';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      components: {\n        code: CodeBlock,\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-custom-elements-config.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\"\nimport { setCustomElementsManifest } from '@storybook/web-components-vite';\n\nimport customElements from '../custom-elements.json';\n\nsetCustomElementsManifest(customElements);\n\nexport default {\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\"\nimport type { Preview } from '@storybook/web-components-vite';\n\nimport { setCustomElementsManifest } from '@storybook/web-components-vite';\n\nimport customElements from '../custom-elements.json';\n\nsetCustomElementsManifest(customElements);\n\nconst preview: Preview = {\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/i,\n      },\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview, setCustomElementsManifest } from '@storybook/web-components-vite';\n\nimport customElements from '../custom-elements.json';\n\nsetCustomElementsManifest(customElements);\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/i,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview, setCustomElementsManifest } from '@storybook/web-components-vite';\n\nimport customElements from '../custom-elements.json';\n\nsetCustomElementsManifest(customElements);\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-custom-metadata.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"ember\" language=\"js\"\nimport { setJSONDoc } from '@storybook/addon-docs/ember';\n\nimport docJson from '../dist/storybook-docgen/index.json';\nsetJSONDoc(docJson);\n\nexport default {\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-custom-params.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    backgrounds: {\n      values: [\n        { name: 'red', value: '#f00' },\n        { name: 'green', value: '#0f0' },\n      ],\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    backgrounds: {\n      values: [\n        { name: 'red', value: '#f00' },\n        { name: 'green', value: '#0f0' },\n      ],\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      values: [\n        { name: 'red', value: '#f00' },\n        { name: 'green', value: '#0f0' },\n      ],\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      values: [\n        { name: 'red', value: '#f00' },\n        { name: 'green', value: '#0f0' },\n      ],\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      values: [\n        { name: 'red', value: '#f00' },\n        { name: 'green', value: '#0f0' },\n      ],\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      values: [\n        { name: 'red', value: '#f00' },\n        { name: 'green', value: '#0f0' },\n      ],\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      values: [\n        { name: 'red', value: '#f00' },\n        { name: 'green', value: '#0f0' },\n      ],\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      values: [\n        { name: 'red', value: '#f00' },\n        { name: 'green', value: '#0f0' },\n      ],\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      values: [\n        { name: 'red', value: '#f00' },\n        { name: 'green', value: '#0f0' },\n      ],\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-custom-toc.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    docs: {\n      toc: {\n        contentsSelector: '.sbdocs-content',\n        headingSelector: 'h1, h2, h3',\n        ignoreSelector: '#primary',\n        title: 'Table of Contents',\n        disable: false,\n        unsafeTocbotOptions: {\n          orderedList: false,\n        },\n      },\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    docs: {\n      toc: {\n        contentsSelector: '.sbdocs-content',\n        headingSelector: 'h1, h2, h3',\n        ignoreSelector: '#primary',\n        title: 'Table of Contents',\n        disable: false,\n        unsafeTocbotOptions: {\n          orderedList: false,\n        },\n      },\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      toc: {\n        contentsSelector: '.sbdocs-content',\n        headingSelector: 'h1, h2, h3',\n        ignoreSelector: '#primary',\n        title: 'Table of Contents',\n        disable: false,\n        unsafeTocbotOptions: {\n          orderedList: false,\n        },\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      toc: {\n        contentsSelector: '.sbdocs-content',\n        headingSelector: 'h1, h2, h3',\n        ignoreSelector: '#primary',\n        title: 'Table of Contents',\n        disable: false,\n        unsafeTocbotOptions: {\n          orderedList: false,\n        },\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      toc: {\n        contentsSelector: '.sbdocs-content',\n        headingSelector: 'h1, h2, h3',\n        ignoreSelector: '#primary',\n        title: 'Table of Contents',\n        disable: false,\n        unsafeTocbotOptions: {\n          orderedList: false,\n        },\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      toc: {\n        contentsSelector: '.sbdocs-content',\n        headingSelector: 'h1, h2, h3',\n        ignoreSelector: '#primary',\n        title: 'Table of Contents',\n        disable: false,\n        unsafeTocbotOptions: {\n          orderedList: false,\n        },\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      toc: {\n        contentsSelector: '.sbdocs-content',\n        headingSelector: 'h1, h2, h3',\n        ignoreSelector: '#primary',\n        title: 'Table of Contents',\n        disable: false,\n        unsafeTocbotOptions: {\n          orderedList: false,\n        },\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      toc: {\n        contentsSelector: '.sbdocs-content',\n        headingSelector: 'h1, h2, h3',\n        ignoreSelector: '#primary',\n        title: 'Table of Contents',\n        disable: false,\n        unsafeTocbotOptions: {\n          orderedList: false,\n        },\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      toc: {\n        contentsSelector: '.sbdocs-content',\n        headingSelector: 'h1, h2, h3',\n        ignoreSelector: '#primary',\n        title: 'Table of Contents',\n        disable: false,\n        unsafeTocbotOptions: {\n          orderedList: false,\n        },\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-doc-blocks-controls-exclude-prop.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      controls: { exclude: ['style'] },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-docs-dark-theme.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { themes } from 'storybook/theming';\n\nexport default {\n  parameters: {\n    docs: {\n      theme: themes.dark,\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nimport { themes } from 'storybook/theming';\n\nconst preview: Preview = {\n  parameters: {\n    docs: {\n      theme: themes.dark,\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { themes } from 'storybook/theming';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      theme: themes.dark,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { themes } from 'storybook/theming';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      theme: themes.dark,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { themes } from 'storybook/theming';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      theme: themes.dark,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { themes } from 'storybook/theming';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      theme: themes.dark,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { themes } from 'storybook/theming';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      theme: themes.dark,\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { themes } from 'storybook/theming';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      theme: themes.dark,\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nimport { themes } from 'storybook/theming';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      theme: themes.dark,\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-empty-sort-object.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    options: {\n      storySort: {\n        method: '',\n        order: [],\n        locales: '',\n      },\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    options: {\n      storySort: {\n        method: '',\n        order: [],\n        locales: '',\n      },\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        method: '',\n        order: [],\n        locales: '',\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        method: '',\n        order: [],\n        locales: '',\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        method: '',\n        order: [],\n        locales: '',\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        method: '',\n        order: [],\n        locales: '',\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        method: '',\n        order: [],\n        locales: '',\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        method: '',\n        order: [],\n        locales: '',\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        method: '',\n        order: [],\n        locales: '',\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-enable-toc.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    docs: {\n      toc: true, // 👈 Enables the table of contents\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    docs: {\n      toc: true, // 👈 Enables the table of contents\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      toc: true, // 👈 Enables the table of contents\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      toc: true, // 👈 Enables the table of contents\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      toc: true, // 👈 Enables the table of contents\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      toc: true, // 👈 Enables the table of contents\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      toc: true, // 👈 Enables the table of contents\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      toc: true, // 👈 Enables the table of contents\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      toc: true, // 👈 Enables the table of contents\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-expanded-controls.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    controls: { expanded: true },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    controls: { expanded: true },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    controls: { expanded: true },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    controls: { expanded: true },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    controls: { expanded: true },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    controls: { expanded: true },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  parameters: {\n    controls: { expanded: true },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    controls: { expanded: true },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    controls: { expanded: true },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-extended-theme-variables.md",
    "content": "```js renderer=\"common\" language=\"js\"\naddonActionsTheme: {\n  ...chromeLight,\n  BASE_FONT_FAMILY: typography.fonts.mono,\n  BASE_BACKGROUND_COLOR: 'transparent',\n}\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-global-decorator.md",
    "content": "```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\"\nimport { type Preview, componentWrapperDecorator } from '@storybook/angular';\n\nconst preview: Preview = {\n  decorators: [componentWrapperDecorator((story) => `<div style=\"margin: 3em\">${story}</div>`)],\n};\n\nexport default preview;\n```\n\n```jsx filename=\".storybook/preview.jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport React from 'react';\n\nexport default {\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </div>\n    ),\n  ],\n};\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\nimport React from 'react';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </div>\n    ),\n  ],\n};\n\nexport default preview;\n```\n\n```jsx filename=\".storybook/preview.js\" renderer=\"solid\" language=\"js\"\nexport default {\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        <Story />\n      </div>\n    ),\n  ],\n};\n```\n\n```js filename=\".storybook/preview.tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Preview } from 'storybook-solidjs-vite';\n\nconst preview: Preview = {\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        <Story />\n      </div>\n    ),\n  ],\n};\n\nexport default preview;\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"svelte\" language=\"js\"\nimport MarginDecorator from './MarginDecorator.svelte';\n\nexport default { decorators: [() => MarginDecorator] };\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"svelte\" language=\"ts\"\n// Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\nimport type { Preview } from '@storybook/your-framework';\n\nimport MarginDecorator from './MarginDecorator.svelte';\n\nconst preview: Preview = {\n  decorators: [() => MarginDecorator],\n};\n\nexport default preview;\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  decorators: [\n    (story) => ({\n      components: { story },\n      template: '<div style=\"margin: 3em;\"><story /></div>',\n    }),\n  ],\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Preview } from '@storybook/vue3-vite';\n\nconst preview: Preview = {\n  decorators: [\n    (story) => ({\n      components: { story },\n      template: '<div style=\"margin: 3em;\"><story /></div>',\n    }),\n  ],\n};\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  decorators: [\n    (story) => ({\n      components: { story },\n      template: '<div style=\"margin: 3em;\"><story /></div>',\n    }),\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  decorators: [\n    (story) => ({\n      components: { story },\n      template: '<div style=\"margin: 3em;\"><story /></div>',\n    }),\n  ],\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { componentWrapperDecorator, definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  decorators: [componentWrapperDecorator((story) => `<div style=\"margin: 3em\">${story}</div>`)],\n});\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\"\nimport { html } from 'lit';\n\nexport default {\n  decorators: [(story) => html`<div style=\"margin: 3em\">${story()}</div>`],\n};\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"ts\"\nimport type { Preview } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nconst preview: Preview = {\n  decorators: [(story) => html`<div style=\"margin: 3em\">${story()}</div>`],\n};\n\nexport default preview;\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport React from 'react';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </div>\n    ),\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\".storybook/preview.jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport React from 'react';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </div>\n    ),\n  ],\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nexport default definePreview({\n  decorators: [(story) => html`<div style=\"margin: 3em\">${story()}</div>`],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nexport default definePreview({\n  decorators: [(story) => html`<div style=\"margin: 3em\">${story()}</div>`],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-global-loader.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  loaders: [\n    async () => ({\n      currentUser: await (await fetch('https://jsonplaceholder.typicode.com/users/1')).json(),\n    }),\n  ],\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  loaders: [\n    async () => ({\n      currentUser: await (await fetch('https://jsonplaceholder.typicode.com/users/1')).json(),\n    }),\n  ],\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  loaders: [\n    async () => ({\n      currentUser: await (await fetch('https://jsonplaceholder.typicode.com/users/1')).json(),\n    }),\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  loaders: [\n    async () => ({\n      currentUser: await (await fetch('https://jsonplaceholder.typicode.com/users/1')).json(),\n    }),\n  ],\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  loaders: [\n    async () => ({\n      currentUser: await (await fetch('https://jsonplaceholder.typicode.com/users/1')).json(),\n    }),\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  loaders: [\n    async () => ({\n      currentUser: await (await fetch('https://jsonplaceholder.typicode.com/users/1')).json(),\n    }),\n  ],\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  loaders: [\n    async () => ({\n      currentUser: await (await fetch('https://jsonplaceholder.typicode.com/users/1')).json(),\n    }),\n  ],\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  loaders: [\n    async () => ({\n      currentUser: await (await fetch('https://jsonplaceholder.typicode.com/users/1')).json(),\n    }),\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  loaders: [\n    async () => ({\n      currentUser: await (await fetch('https://jsonplaceholder.typicode.com/users/1')).json(),\n    }),\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-global-parameters.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    backgrounds: {\n      values: [\n        { name: 'red', value: '#f00' },\n        { name: 'green', value: '#0f0' },\n      ],\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    backgrounds: {\n      values: [\n        { name: 'red', value: '#f00' },\n        { name: 'green', value: '#0f0' },\n      ],\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      values: [\n        { name: 'red', value: '#f00' },\n        { name: 'green', value: '#0f0' },\n      ],\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      values: [\n        { name: 'red', value: '#f00' },\n        { name: 'green', value: '#0f0' },\n      ],\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      values: [\n        { name: 'red', value: '#f00' },\n        { name: 'green', value: '#0f0' },\n      ],\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      values: [\n        { name: 'red', value: '#f00' },\n        { name: 'green', value: '#0f0' },\n      ],\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      values: [\n        { name: 'red', value: '#f00' },\n        { name: 'green', value: '#0f0' },\n      ],\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      values: [\n        { name: 'red', value: '#f00' },\n        { name: 'green', value: '#0f0' },\n      ],\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    backgrounds: {\n      values: [\n        { name: 'red', value: '#f00' },\n        { name: 'green', value: '#0f0' },\n      ],\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-head-example.md",
    "content": "```html filename=\".storybook/preview-head.html\" renderer=\"common\" language=\"js\"\n<!--\nPull in static files served from your Static directory or the internet\nExample:\n`main.js|ts` is configured with staticDirs: ['../public'] and your font is located in the `fonts`\ndirectory inside your `public` directory\n-->\n<link rel=\"preload\" href=\"/fonts/my-font.woff2\" />\n\n<!-- Or you can load custom head-tag JavaScript: -->\n<script src=\"https://use.typekit.net/xxxyyy.js\"></script>\n<script>\n  try {\n    Typekit.load();\n  } catch (e) {}\n</script>\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-head-import-global-styles.md",
    "content": "```html filename=\".storybook/preview-head.html\" renderer=\"common\" language=\"ts\"\n<!-- Loads a font from a CDN -->\n<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin />\n<link\n  href=\"https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap\"\n  rel=\"stylesheet\"\n/>\n<!-- Load your CSS file -->\n<link rel=\"stylesheet\" href=\"path/to/your/styles.css\" />\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-import-global-styles.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport '../src/styles/global.css';\n\nexport default {\n  parameters: {},\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nimport '../src/styles/global.css';\n\nconst preview: Preview = {\n  parameters: {},\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport '../src/styles/global.css';\n\nexport default definePreview({\n  parameters: {},\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport '../src/styles/global.css';\n\nexport default definePreview({\n  parameters: {},\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport '../src/styles/global.css';\n\nexport default definePreview({\n  parameters: {},\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport '../src/styles/global.css';\n\nexport default definePreview({\n  parameters: {},\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nimport '../src/styles/global.css';\n\nexport default definePreview({\n  parameters: {},\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport '../src/styles/global.css';\n\nexport default definePreview({\n  parameters: {},\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport '../src/styles/global.css';\n\nexport default definePreview({\n  parameters: {},\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-layout-param.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    layout: 'centered',\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    layout: 'centered',\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    layout: 'centered',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    layout: 'centered',\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    layout: 'centered',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    layout: 'centered',\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  parameters: {\n    layout: 'centered',\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    layout: 'centered',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    layout: 'centered',\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-locales-globaltype.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nconst preview = {\n  globalTypes: {\n    locale: {\n      description: 'Internationalization locale',\n      toolbar: {\n        icon: 'globe',\n        items: [\n          { value: 'en', right: '🇺🇸', title: 'English' },\n          { value: 'fr', right: '🇫🇷', title: 'Français' },\n          { value: 'es', right: '🇪🇸', title: 'Español' },\n          { value: 'zh', right: '🇨🇳', title: '中文' },\n          { value: 'kr', right: '🇰🇷', title: '한국어' },\n        ],\n      },\n    },\n  },\n  initialGlobals: {\n    locale: 'en',\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  globalTypes: {\n    locale: {\n      description: 'Internationalization locale',\n      toolbar: {\n        icon: 'globe',\n        items: [\n          { value: 'en', right: '🇺🇸', title: 'English' },\n          { value: 'fr', right: '🇫🇷', title: 'Français' },\n          { value: 'es', right: '🇪🇸', title: 'Español' },\n          { value: 'zh', right: '🇨🇳', title: '中文' },\n          { value: 'kr', right: '🇰🇷', title: '한국어' },\n        ],\n      },\n    },\n  },\n  initialGlobals: {\n    locale: 'en',\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  globalTypes: {\n    locale: {\n      description: 'Internationalization locale',\n      toolbar: {\n        icon: 'globe',\n        items: [\n          { value: 'en', right: '🇺🇸', title: 'English' },\n          { value: 'fr', right: '🇫🇷', title: 'Français' },\n          { value: 'es', right: '🇪🇸', title: 'Español' },\n          { value: 'zh', right: '🇨🇳', title: '中文' },\n          { value: 'kr', right: '🇰🇷', title: '한국어' },\n        ],\n      },\n    },\n  },\n  initialGlobals: {\n    locale: 'en',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  globalTypes: {\n    locale: {\n      description: 'Internationalization locale',\n      toolbar: {\n        icon: 'globe',\n        items: [\n          { value: 'en', right: '🇺🇸', title: 'English' },\n          { value: 'fr', right: '🇫🇷', title: 'Français' },\n          { value: 'es', right: '🇪🇸', title: 'Español' },\n          { value: 'zh', right: '🇨🇳', title: '中文' },\n          { value: 'kr', right: '🇰🇷', title: '한국어' },\n        ],\n      },\n    },\n  },\n  initialGlobals: {\n    locale: 'en',\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  globalTypes: {\n    locale: {\n      description: 'Internationalization locale',\n      toolbar: {\n        icon: 'globe',\n        items: [\n          { value: 'en', right: '🇺🇸', title: 'English' },\n          { value: 'fr', right: '🇫🇷', title: 'Français' },\n          { value: 'es', right: '🇪🇸', title: 'Español' },\n          { value: 'zh', right: '🇨🇳', title: '中文' },\n          { value: 'kr', right: '🇰🇷', title: '한국어' },\n        ],\n      },\n    },\n  },\n  initialGlobals: {\n    locale: 'en',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  globalTypes: {\n    locale: {\n      description: 'Internationalization locale',\n      toolbar: {\n        icon: 'globe',\n        items: [\n          { value: 'en', right: '🇺🇸', title: 'English' },\n          { value: 'fr', right: '🇫🇷', title: 'Français' },\n          { value: 'es', right: '🇪🇸', title: 'Español' },\n          { value: 'zh', right: '🇨🇳', title: '中文' },\n          { value: 'kr', right: '🇰🇷', title: '한국어' },\n        ],\n      },\n    },\n  },\n  initialGlobals: {\n    locale: 'en',\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  globalTypes: {\n    locale: {\n      description: 'Internationalization locale',\n      toolbar: {\n        icon: 'globe',\n        items: [\n          { value: 'en', right: '🇺🇸', title: 'English' },\n          { value: 'fr', right: '🇫🇷', title: 'Français' },\n          { value: 'es', right: '🇪🇸', title: 'Español' },\n          { value: 'zh', right: '🇨🇳', title: '中文' },\n          { value: 'kr', right: '🇰🇷', title: '한국어' },\n        ],\n      },\n    },\n  },\n  initialGlobals: {\n    locale: 'en',\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  globalTypes: {\n    locale: {\n      description: 'Internationalization locale',\n      toolbar: {\n        icon: 'globe',\n        items: [\n          { value: 'en', right: '🇺🇸', title: 'English' },\n          { value: 'fr', right: '🇫🇷', title: 'Français' },\n          { value: 'es', right: '🇪🇸', title: 'Español' },\n          { value: 'zh', right: '🇨🇳', title: '中文' },\n          { value: 'kr', right: '🇰🇷', title: '한국어' },\n        ],\n      },\n    },\n  },\n  initialGlobals: {\n    locale: 'en',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  globalTypes: {\n    locale: {\n      description: 'Internationalization locale',\n      toolbar: {\n        icon: 'globe',\n        items: [\n          { value: 'en', right: '🇺🇸', title: 'English' },\n          { value: 'fr', right: '🇫🇷', title: 'Français' },\n          { value: 'es', right: '🇪🇸', title: 'Español' },\n          { value: 'zh', right: '🇨🇳', title: '中文' },\n          { value: 'kr', right: '🇰🇷', title: '한국어' },\n        ],\n      },\n    },\n  },\n  initialGlobals: {\n    locale: 'en',\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-matching-argtypes.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    actions: { argTypesRegex: '^on.*' },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    actions: { argTypesRegex: '^on.*' },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    actions: { argTypesRegex: '^on.*' },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    actions: { argTypesRegex: '^on.*' },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    actions: { argTypesRegex: '^on.*' },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    actions: { argTypesRegex: '^on.*' },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  parameters: {\n    actions: { argTypesRegex: '^on.*' },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    actions: { argTypesRegex: '^on.*' },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    actions: { argTypesRegex: '^on.*' },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-optout-inline.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    docs: {\n      // Opt-out of inline rendering\n      story: { inline: false },\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    docs: {\n      // Opt-out of inline rendering\n      story: { inline: false },\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      // Opt-out of inline rendering\n      story: { inline: false },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      // Opt-out of inline rendering\n      story: { inline: false },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      // Opt-out of inline rendering\n      story: { inline: false },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      // Opt-out of inline rendering\n      story: { inline: false },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      // Opt-out of inline rendering\n      story: { inline: false },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      // Opt-out of inline rendering\n      story: { inline: false },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  parameters: {\n    docs: {\n      // Opt-out of inline rendering\n      story: { inline: false },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-parameters-color-swatches.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    controls: {\n      presetColors: [{ color: '#ff4785', title: 'Coral' }, 'rgba(0, 159, 183, 1)', '#fe4a49'],\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    controls: {\n      presetColors: [{ color: '#ff4785', title: 'Coral' }, 'rgba(0, 159, 183, 1)', '#fe4a49'],\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      presetColors: [{ color: '#ff4785', title: 'Coral' }, 'rgba(0, 159, 183, 1)', '#fe4a49'],\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      presetColors: [{ color: '#ff4785', title: 'Coral' }, 'rgba(0, 159, 183, 1)', '#fe4a49'],\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      presetColors: [{ color: '#ff4785', title: 'Coral' }, 'rgba(0, 159, 183, 1)', '#fe4a49'],\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      presetColors: [{ color: '#ff4785', title: 'Coral' }, 'rgba(0, 159, 183, 1)', '#fe4a49'],\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      presetColors: [{ color: '#ff4785', title: 'Coral' }, 'rgba(0, 159, 183, 1)', '#fe4a49'],\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      presetColors: [{ color: '#ff4785', title: 'Coral' }, 'rgba(0, 159, 183, 1)', '#fe4a49'],\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      presetColors: [{ color: '#ff4785', title: 'Coral' }, 'rgba(0, 159, 183, 1)', '#fe4a49'],\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-prepareforinline.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\"\nimport React from 'react';\nimport { render } from 'react-dom';\nimport toReact from '@egoist/vue-to-react';\n\nexport default {\n  parameters: {\n    docs: {\n      // deprecated do not use\n    },\n  },\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-register-language-globally.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport scss from 'react-syntax-highlighter/dist/esm/languages/prism/scss';\n\n// Registers and enables scss language support\nSyntaxHighlighter.registerLanguage('scss', scss);\n\nexport default {\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nimport { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport scss from 'react-syntax-highlighter/dist/esm/languages/prism/scss';\n\n// Registers and enables scss language support\nSyntaxHighlighter.registerLanguage('scss', scss);\n\nconst preview: Preview = {\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport scss from 'react-syntax-highlighter/dist/esm/languages/prism/scss';\n\n// Registers and enables scss language support\nSyntaxHighlighter.registerLanguage('scss', scss);\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport scss from 'react-syntax-highlighter/dist/esm/languages/prism/scss';\n\n// Registers and enables scss language support\nSyntaxHighlighter.registerLanguage('scss', scss);\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport scss from 'react-syntax-highlighter/dist/esm/languages/prism/scss';\n\n// Registers and enables scss language support\nSyntaxHighlighter.registerLanguage('scss', scss);\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport scss from 'react-syntax-highlighter/dist/esm/languages/prism/scss';\n\n// Registers and enables scss language support\nSyntaxHighlighter.registerLanguage('scss', scss);\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nimport { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport scss from 'react-syntax-highlighter/dist/esm/languages/prism/scss';\n\n// Registers and enables scss language support\nSyntaxHighlighter.registerLanguage('scss', scss);\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport scss from 'react-syntax-highlighter/dist/esm/languages/prism/scss';\n\n// Registers and enables scss language support\nSyntaxHighlighter.registerLanguage('scss', scss);\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport scss from 'react-syntax-highlighter/dist/esm/languages/prism/scss';\n\n// Registers and enables scss language support\nSyntaxHighlighter.registerLanguage('scss', scss);\n\nexport default definePreview({\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-sort-function.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    options: {\n      storySort: (a, b) =>\n        a.id === b.id ? 0 : a.id.localeCompare(b.id, undefined, { numeric: true }),\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    options: {\n      // The `a` and `b` arguments in this function have a type of `import('storybook/internal/types').IndexEntry`. Remember that the function is executed in a JavaScript environment, so use JSDoc for IntelliSense to introspect it.\n      storySort: (a, b) =>\n        a.id === b.id ? 0 : a.id.localeCompare(b.id, undefined, { numeric: true }),\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      // The `a` and `b` arguments in this function have a type of `import('storybook/internal/types').IndexEntry`. Remember that the function is executed in a JavaScript environment, so use JSDoc for IntelliSense to introspect it.\n      storySort: (a, b) =>\n        a.id === b.id ? 0 : a.id.localeCompare(b.id, undefined, { numeric: true }),\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: (a, b) =>\n        a.id === b.id ? 0 : a.id.localeCompare(b.id, undefined, { numeric: true }),\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      // The `a` and `b` arguments in this function have a type of `import('storybook/internal/types').IndexEntry`. Remember that the function is executed in a JavaScript environment, so use JSDoc for IntelliSense to introspect it.\n      storySort: (a, b) =>\n        a.id === b.id ? 0 : a.id.localeCompare(b.id, undefined, { numeric: true }),\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: (a, b) =>\n        a.id === b.id ? 0 : a.id.localeCompare(b.id, undefined, { numeric: true }),\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      // The `a` and `b` arguments in this function have a type of `import('storybook/internal/types').IndexEntry`. Remember that the function is executed in a JavaScript environment, so use JSDoc for IntelliSense to introspect it.\n      storySort: (a, b) =>\n        a.id === b.id ? 0 : a.id.localeCompare(b.id, undefined, { numeric: true }),\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      // The `a` and `b` arguments in this function have a type of `import('storybook/internal/types').IndexEntry`. Remember that the function is executed in a JavaScript environment, so use JSDoc for IntelliSense to introspect it.\n      storySort: (a, b) =>\n        a.id === b.id ? 0 : a.id.localeCompare(b.id, undefined, { numeric: true }),\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: (a, b) =>\n        a.id === b.id ? 0 : a.id.localeCompare(b.id, undefined, { numeric: true }),\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-use-global-type.md",
    "content": "```ts filename=\".storybook/preview.js\" renderer=\"angular\" language=\"ts\"\nimport { type Preview, componentWrapperDecorator } from '@storybook/angular';\n\nconst preview: Preview = {\n  decorators: [\n    componentWrapperDecorator(\n      (story) => `<div [class]=\"myTheme\">${story}</div>`,\n      ({ globals }) => {\n        return { myTheme: globals['theme'] };\n      },\n    ),\n  ],\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { componentWrapperDecorator, definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  decorators: [\n    componentWrapperDecorator(\n      (story) => `<div [class]=\"myTheme\">${story}</div>`,\n      ({ globals }) => {\n        return { myTheme: globals['theme'] };\n      },\n    ),\n  ],\n});\n```\n\n```jsx filename=\".storybook/preview.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { ThemeProvider } from 'styled-components';\n\nimport { MyThemes } from '../my-theme-folder/my-theme-file';\n\nconst preview = {\n  decorators: [\n    (Story, context) => {\n      const theme = MyThemes[context.globals.theme];\n      return (\n        <ThemeProvider theme={theme}>\n          <Story />\n        </ThemeProvider>\n      );\n    },\n  ],\n};\n\nexport default preview;\n```\n\n```tsx filename=\".storybook/preview.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nimport { ThemeProvider } from 'styled-components';\n\nimport { MyThemes } from '../my-theme-folder/my-theme-file';\n\nconst preview: Preview = {\n  decorators: [\n    (Story, context) => {\n      const theme = MyThemes[context.globals.theme];\n      return (\n        <ThemeProvider theme={theme}>\n          <Story />\n        </ThemeProvider>\n      );\n    },\n  ],\n};\n\nexport default preview;\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport { setup } from '@storybook/vue3-vite';\n\nimport { VApp } from 'vuetify/components';\n\nimport { registerPlugins } from '../src/plugins';\n\nsetup((app) => {\n  // Registers your app's plugins including Vuetify into Storybook\n  registerPlugins(app);\n});\n\nconst preview = {\n  decorators: [\n    (story, context) => {\n      const theme = context.globals.theme || 'light';\n      return {\n        components: { story, VApp },\n        template: `\n          <v-app theme=\"${theme}\">\n            <div>\n              <story/>\n            </div>\n          </v-app>\n      `,\n      };\n    },\n  ],\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Preview, setup } from '@storybook/vue3-vite';\n\nimport { VApp } from 'vuetify/components';\n\nimport { registerPlugins } from '../src/plugins';\n\nsetup((app) => {\n  // Registers your app's plugins including Vuetify into Storybook\n  registerPlugins(app);\n});\n\nconst preview: Preview = {\n  decorators: [\n    (story, context) => {\n      const theme = context.globals.theme || 'light';\n      return {\n        components: { story, VApp },\n        template: `\n          <v-app theme=\"${theme}\">\n            <div class=\"d-flex\">\n              <story/>\n            </div>\n          </v-app>\n      `,\n      };\n    },\n  ],\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview, setup } from '@storybook/vue3-vite';\n\nimport { VApp } from 'vuetify/components';\n\nimport { registerPlugins } from '../src/plugins';\n\nsetup((app) => {\n  // Registers your app's plugins including Vuetify into Storybook\n  registerPlugins(app);\n});\n\nexport default definePreview({\n  decorators: [\n    (story, context) => {\n      const theme = context.globals.theme || 'light';\n      return {\n        components: { story, VApp },\n        template: `\n          <v-app theme=\"${theme}\">\n            <div class=\"d-flex\">\n              <story/>\n            </div>\n          </v-app>\n      `,\n      };\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview, setup } from '@storybook/vue3-vite';\n\nimport { VApp } from 'vuetify/components';\n\nimport { registerPlugins } from '../src/plugins';\n\nsetup((app) => {\n  // Registers your app's plugins including Vuetify into Storybook\n  registerPlugins(app);\n});\n\nexport default definePreview({\n  decorators: [\n    (story, context) => {\n      const theme = context.globals.theme || 'light';\n      return {\n        components: { story, VApp },\n        template: `\n          <v-app theme=\"${theme}\">\n            <div>\n              <story/>\n            </div>\n          </v-app>\n      `,\n      };\n    },\n  ],\n});\n```\n\n```tsx filename=\".storybook/preview.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { ThemeProvider } from 'styled-components';\n\nimport { MyThemes } from '../my-theme-folder/my-theme-file';\n\nexport default definePreview({\n  decorators: [\n    (Story, context) => {\n      const theme = MyThemes[context.globals.theme];\n      return (\n        <ThemeProvider theme={theme}>\n          <Story />\n        </ThemeProvider>\n      );\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\".storybook/preview.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport { ThemeProvider } from 'styled-components';\n\nimport { MyThemes } from '../my-theme-folder/my-theme-file';\n\nexport default definePreview({\n  decorators: [\n    (Story, context) => {\n      const theme = MyThemes[context.globals.theme];\n      return (\n        <ThemeProvider theme={theme}>\n          <Story />\n        </ThemeProvider>\n      );\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nexport default definePreview({\n  decorators: [\n    (story, context) => {\n      const theme = context.globals.theme || 'light';\n      return html`<div class=${theme}>${story()}</div>`;\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nexport default definePreview({\n  decorators: [\n    (story, context) => {\n      const theme = context.globals.theme || 'light';\n      return html`<div class=${theme}>${story()}</div>`;\n    },\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-with-library-decorator.md",
    "content": "```js filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"preview\"\nimport type { Preview } from '@storybook/angular';\n\nimport { setCompodocJson } from '@storybook/addon-docs/angular';\n\nimport docJson from '../documentation.json';\n\nimport '../src/polyfills';\n\nsetCompodocJson(docJson);\n\nconst preview: Preview = {\n  parameters: {\n    controls: {\n      matchers: {\n        color: /(background|color)$/i,\n        date: /Date$/,\n      },\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\"src/polyfills.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"polyfills\"\nimport '@angular/localize/init';\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"library (CSF 3)\"\nimport { setup } from '@storybook/vue3-vite';\n\nimport { createPinia } from 'pinia';\n\nsetup((app) => {\n  //👇 Registers a global Pinia instance inside Storybook to be consumed by existing stories\n  app.use(createPinia());\n});\n\nexport default {\n  decorators: [\n    (story) => ({\n      components: { story },\n      template: '<div style=\"margin: 3em;\"><story /></div>',\n    }),\n  ],\n};\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"component (CSF 3)\"\nimport { setup } from '@storybook/vue3-vite';\n\nimport { library } from '@fortawesome/fontawesome-svg-core';\nimport { faPlusSquare as fasPlusSquare } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';\n\nsetup((app) => {\n  //👇 Adds the icon to the library so you can use it in your story.\n  library.add(fasPlusSquare);\n  app.component('font-awesome-icon', FontAwesomeIcon);\n});\n\nexport default {\n  decorators: [\n    (story) => ({\n      components: { story },\n      template: '<div style=\"margin: 3em;\"><story /></div>',\n    }),\n  ],\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"library (CSF 3)\"\nimport { setup, type Preview } from '@storybook/vue3-vite';\n\nimport { createPinia } from 'pinia';\n\nsetup((app) => {\n  //👇 Registers a global Pinia instance inside Storybook to be consumed by existing stories\n  app.use(createPinia());\n});\n\nconst preview: Preview = {\n  decorators: [\n    (story) => ({\n      components: { story },\n      template: '<div style=\"margin: 3em;\"><story /></div>',\n    }),\n  ],\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"component (CSF 3)\"\nimport { setup, type Preview } from '@storybook/vue3-vite';\n\nimport { library } from '@fortawesome/fontawesome-svg-core';\nimport { faPlusSquare as fasPlusSquare } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';\n\nsetup((app) => {\n  //👇 Adds the icon to the library so you can use it in your story.\n  library.add(fasPlusSquare);\n  app.component('font-awesome-icon', FontAwesomeIcon);\n});\n\nconst preview: Preview = {\n  decorators: [\n    (story) => ({\n      components: { story },\n      template: '<div style=\"margin: 3em;\"><story /></div>',\n    }),\n  ],\n};\n\nexport default preview;\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"library (CSF Next 🧪)\"\nimport { definePreview, setup } from '@storybook/vue3-vite';\n\nimport { createPinia } from 'pinia';\n\nsetup((app) => {\n  //👇 Registers a global Pinia instance inside Storybook to be consumed by existing stories\n  app.use(createPinia());\n});\n\nexport default definePreview({\n  decorators: [\n    (story) => ({\n      components: { story },\n      template: '<div style=\"margin: 3em;\"><story /></div>',\n    }),\n  ],\n});\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"component (CSF Next 🧪)\"\nimport { definePreview, setup } from '@storybook/vue3-vite';\n\nimport { library } from '@fortawesome/fontawesome-svg-core';\nimport { faPlusSquare as fasPlusSquare } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';\n\nsetup((app) => {\n  //👇 Adds the icon to the library so you can use it in your story.\n  library.add(fasPlusSquare);\n  app.component('font-awesome-icon', FontAwesomeIcon);\n});\n\nexport default definePreview({\n  decorators: [\n    (story) => ({\n      components: { story },\n      template: '<div style=\"margin: 3em;\"><story /></div>',\n    }),\n  ],\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"library (CSF Next 🧪)\"\nimport { definePreview, setup } from '@storybook/vue3-vite';\n\nimport { createPinia } from 'pinia';\n\nsetup((app) => {\n  //👇 Registers a global Pinia instance inside Storybook to be consumed by existing stories\n  app.use(createPinia());\n});\n\nexport default definePreview({\n  decorators: [\n    (story) => ({\n      components: { story },\n      template: '<div style=\"margin: 3em;\"><story /></div>',\n    }),\n  ],\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"component (CSF Next 🧪)\"\nimport { definePreview, setup } from '@storybook/vue3-vite';\n\nimport { library } from '@fortawesome/fontawesome-svg-core';\nimport { faPlusSquare as fasPlusSquare } from '@fortawesome/free-solid-svg-icons';\nimport { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';\n\nsetup((app) => {\n  //👇 Adds the icon to the library so you can use it in your story.\n  library.add(fasPlusSquare);\n  app.component('font-awesome-icon', FontAwesomeIcon);\n});\n\nexport default definePreview({\n  decorators: [\n    (story) => ({\n      components: { story },\n      template: '<div style=\"margin: 3em;\"><story /></div>',\n    }),\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-with-ordered-pages-and-wildcard.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    options: {\n      storySort: {\n        order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components', '*', 'WIP'],\n      },\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    options: {\n      storySort: {\n        order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components', '*', 'WIP'],\n      },\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components', '*', 'WIP'],\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components', '*', 'WIP'],\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components', '*', 'WIP'],\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components', '*', 'WIP'],\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components', '*', 'WIP'],\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components', '*', 'WIP'],\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components', '*', 'WIP'],\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-with-ordered-pages.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  parameters: {\n    options: {\n      storySort: {\n        order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components'],\n      },\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  parameters: {\n    options: {\n      storySort: {\n        order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components'],\n      },\n    },\n  },\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components'],\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components'],\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components'],\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components'],\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components'],\n      },\n    },\n  },\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components'],\n      },\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  parameters: {\n    options: {\n      storySort: {\n        order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components'],\n      },\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-preview-with-styled-components-decorator.md",
    "content": "```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\"\nimport { type Preview, componentWrapperDecorator } from '@storybook/angular';\n\nimport { ThemeProvider } from './theme-provider.component';\n\nconst preview: Preview = {\n  decorators: [\n    moduleMetadata({ declarations: [ThemeProvider] }),\n    componentWrapperDecorator(\n      (story) => `<theme-provider class=\"default\">${story}</theme-provider>`,\n    ),\n  ],\n};\nexport default preview;\n\n// or with globals of story context\nconst preview: Preview = {\n  decorators: [\n    moduleMetadata({ declarations: [ThemeProvider] }),\n    componentWrapperDecorator(\n      (story) => `<theme-provider [class]=\"theme\">${story}</theme-provider>`,\n      ({ globals }) => ({ theme: globals.theme }),\n    ),\n  ],\n};\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"Preview\"\nimport { type Preview, setup } from '@storybook/vue3-vite';\n\nimport 'vuetify/styles';\nimport '@mdi/font/css/materialdesignicons.css';\nimport vuetify from '../src/plugins/vuetify';\n\nimport StoryWrapper from './StoryWrapper.vue';\n\n// Registers the Vuetify plugin in Storybook's Vue app instance\nsetup((app) => {\n  app.use(vuetify);\n});\n\nconst preview: Preview = {\n  decorators: [\n    (_, { globals }) => {\n      // The theme can be accessed via the story context's globals\n      const themeName = globals.theme || 'light';\n      return {\n        components: { StoryWrapper },\n        setup() {\n          return { themeName };\n        },\n        template: `\n          <StoryWrapper :themeName=\"themeName\">\n            <template #story>\n              <story />\n            </template>\n          </StoryWrapper>\n        `,\n      };\n    },\n  ],\n};\n\nexport default preview;\n```\n\n```html filename=\".storybook/StoryWrapper.vue\" renderer=\"vue\" language=\"ts\" tabTitle=\"Theme Provider\"\n<template>\n  <v-app :theme=\"themeName\">\n    <v-main>\n      <slot name=\"story\"></slot>\n    </v-main>\n  </v-app>\n</template>\n\n<script lang=\"ts\" setup>\n  defineProps<{ themeName?: string }>();\n</script>\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"Preview\"\nimport { setup } from '@storybook/vue3-vite';\n\nimport 'vuetify/styles';\nimport '@mdi/font/css/materialdesignicons.css';\nimport vuetify from '../src/plugins/vuetify';\n\nimport StoryWrapper from './StoryWrapper.vue';\n\n// Registers the Vuetify plugin in Storybook's Vue app instance\nsetup((app) => {\n  app.use(vuetify);\n});\n\nconst preview = {\n  decorators: [\n    (_, { globals }) => {\n      // The theme can be accessed via the story context's globals\n      const themeName = globals.theme || 'light';\n      return {\n        components: { StoryWrapper },\n        setup() {\n          return { themeName };\n        },\n        template: `\n          <StoryWrapper :themeName=\"themeName\">\n            <template #story>\n              <story />\n            </template>\n          </StoryWrapper>\n        `,\n      };\n    },\n  ],\n};\n\nexport default preview;\n```\n\n```html filename=\".storybook/StoryWrapper.vue\" renderer=\"vue\" language=\"js\" tabTitle=\"Theme Provider\"\n<template>\n  <v-app :theme=\"themeName\">\n    <v-main>\n      <slot name=\"story\"></slot>\n    </v-main>\n  </v-app>\n</template>\n\n<script>\n  export default {\n    name: 'StoryWrapper',\n    props: {\n      themeName: {\n        type: String,\n        default: 'light',\n      },\n    },\n  };\n</script>\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Preview\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Preview } from '@storybook/your-framework';\n\nimport ThemeProvider from './ThemeProvider.svelte';\n\nconst preview: Preview = {\n  decorators: [\n    // The theme can be accessed via the story context's globals\n    (story, { globals }) => {\n      return {\n        Component: ThemeProvider,\n        props: {\n          theme: globals.theme || 'light',\n          children: story,\n        },\n      };\n    },\n  ],\n};\n\nexport default preview;\n```\n\n```svelte filename=\".storybook/ThemeProvider.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Theme Provider\"\n<script lang=\"ts\">\n  import { BitsConfig } from 'bits-ui';\n\n  interface Props {\n    theme?: 'light' | 'dark';\n    children?: import('svelte').Snippet;\n  }\n\n  let { theme = 'light', children }: Props = $props();\n</script>\n\n<BitsConfig defaultPortalTo=\"body\">\n  <div data-theme={theme} class=\"theme-wrapper\">\n    {@render children?.()}\n  </div>\n</BitsConfig>\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"Preview\"\nimport ThemeProvider from './ThemeProvider.svelte';\n\nconst preview = {\n  decorators: [\n    // The theme can be accessed via the story context's globals\n    (story, { globals }) => {\n      return {\n        Component: ThemeProvider,\n        props: {\n          theme: globals.theme || 'light',\n          children: story,\n        },\n      };\n    },\n  ],\n};\n\nexport default preview;\n```\n\n```svelte filename=\".storybook/ThemeProvider.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Theme Provider\"\n<script>\n  import { BitsConfig } from 'bits-ui';\n\n  let { theme = 'light', children } = $props();\n</script>\n\n<BitsConfig defaultPortalTo=\"body\">\n  <div data-theme={theme} class=\"theme-wrapper\">\n    {@render children?.()}\n  </div>\n</BitsConfig>\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"Preview (CSF 3)\"\nimport { html } from 'lit';\n\nimport type { Preview } from '@storybook/web-components-vite';\n\nconst preview: Preview = {\n  decorators: [\n    // The theme can be accessed via the story context's globals\n    (story, { globals }) => {\n      const theme = globals.theme || 'light';\n      return html`<theme-provider theme=${theme}>${story()}</theme-provider>`;\n    },\n  ],\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/ThemeProvider.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"Theme Provider\"\nimport { LitElement, html } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\n\nexport type Theme = 'light' | 'dark';\n\n@customElement('theme-provider')\nexport class ThemeProvider extends LitElement {\n  @property({ type: String, reflect: true })\n  theme: Theme = 'light';\n\n  public setTheme(theme: Theme): void {\n    this.theme = theme;\n  }\n  public getTheme(): Theme {\n    return this.theme;\n  }\n\n  override render() {\n    return html` <slot></slot> `;\n  }\n}\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"Preview (CSF 3)\"\nimport { html } from 'lit';\n\nconst preview = {\n  decorators: [\n    // The theme can be accessed via the story context's globals\n    (story, { globals }) => {\n      const theme = globals.theme || 'light';\n      return html`<theme-provider theme=${theme}>${story()}</theme-provider>`;\n    },\n  ],\n};\n\nexport default preview;\n```\n\n```js filename=\".storybook/ThemeProvider.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"Theme Provider\"\nimport { LitElement, html } from 'lit';\n\nexport class ThemeProvider extends LitElement {\n  static properties = {\n    theme: { type: String, reflect: true },\n  };\n\n  constructor() {\n    super();\n    this.theme = 'light';\n  }\n\n  setTheme(theme) {\n    this.theme = theme;\n  }\n\n  getTheme() {\n    return this.theme;\n  }\n\n  render() {\n    return html`<slot></slot>`;\n  }\n}\n\nif (!customElements.get('theme-provider')) {\n  customElements.define('theme-provider', ThemeProvider);\n}\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"Preview (CSF Next 🧪)\"\nimport { html } from 'lit';\n\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  decorators: [\n    // The theme can be accessed via the story context's globals\n    (story, { globals }) => {\n      const theme = globals.theme || 'light';\n      return html`<theme-provider theme=${theme}>${story()}</theme-provider>`;\n    },\n  ],\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"Preview (CSF Next 🧪)\"\nimport { html } from 'lit';\n\nimport { definePreview } from '@storybook/web-components-vite';\n\nexport default definePreview({\n  decorators: [\n    // The theme can be accessed via the story context's globals\n    (story, { globals }) => {\n      const theme = globals.theme || 'light';\n      return html`<theme-provider theme=${theme}>${story()}</theme-provider>`;\n    },\n  ],\n});\n```\n\n```jsx filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport React from 'react';\n\nimport { ThemeProvider } from 'styled-components';\n\nexport default {\n  decorators: [\n    (Story) => (\n      <ThemeProvider theme=\"default\">\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </ThemeProvider>\n    ),\n  ],\n};\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\nimport React from 'react';\n\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nimport { ThemeProvider } from 'styled-components';\n\nconst preview: Preview = {\n  decorators: [\n    (Story) => (\n      <ThemeProvider theme=\"default\">\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </ThemeProvider>\n    ),\n  ],\n};\n\nexport default preview;\n```\n\n```js filename=\".storybook/preview.js\" renderer=\"solid\" language=\"js\"\nimport { ThemeProvider } from 'solid-styled-components';\n\nconst theme = {\n  colors: {\n    primary: 'hotpink',\n  },\n};\n\nexport const decorators = [\n  (Story) => (\n    <ThemeProvider theme={theme}>\n      <Story />\n    </ThemeProvider>\n  ),\n];\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Preview } from 'storybook-solidjs-vite';\n\nimport { ThemeProvider, DefaultTheme } from 'solid-styled-components';\n\nconst theme: DefaultTheme = {\n  colors: {\n    primary: 'hotpink',\n  },\n};\n\nconst preview: Preview = {\n  decorators: [\n    (Story) => (\n      <ThemeProvider theme={theme}>\n        <Story />\n      </ThemeProvider>\n    ),\n  ],\n};\n\nexport default preview;\n```\n\n```tsx filename=\".storybook/preview.tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport React from 'react';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { ThemeProvider } from 'styled-components';\n\nexport default definePreview({\n  decorators: [\n    (Story) => (\n      <ThemeProvider theme=\"default\">\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </ThemeProvider>\n    ),\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport React from 'react';\n\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\n\nimport { ThemeProvider } from 'styled-components';\n\nexport default definePreview({\n  decorators: [\n    (Story) => (\n      <ThemeProvider theme=\"default\">\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </ThemeProvider>\n    ),\n  ],\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport 'vuetify/styles';\nimport '@mdi/font/css/materialdesignicons.css';\nimport vuetify from '../src/plugins/vuetify';\n\nimport StoryWrapper from './StoryWrapper.vue';\n\n// Registers the Vuetify plugin in Storybook's Vue app instance\nexport default definePreview({\n  decorators: [\n    (_, { globals }) => {\n      // The theme can be accessed via the story context's globals\n      const themeName = globals.theme || 'light';\n      return {\n        components: { StoryWrapper },\n        setup() {\n          return { themeName };\n        },\n        template: `\n          <StoryWrapper :themeName=\"themeName\">\n            <template #story>\n              <story />\n            </template>\n          </StoryWrapper>\n        `,\n      };\n    },\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\n\nimport 'vuetify/styles';\nimport '@mdi/font/css/materialdesignicons.css';\nimport vuetify from '../src/plugins/vuetify';\n\nimport StoryWrapper from './StoryWrapper.vue';\n\n// Registers the Vuetify plugin in Storybook's Vue app instance\nexport default definePreview({\n  decorators: [\n    (_, { globals }) => {\n      // The theme can be accessed via the story context's globals\n      const themeName = globals.theme || 'light';\n      return {\n        components: { StoryWrapper },\n        setup() {\n          return { themeName };\n        },\n        template: `\n          <StoryWrapper :themeName=\"themeName\">\n            <template #story>\n              <story />\n            </template>\n          </StoryWrapper>\n        `,\n      };\n    },\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-read-environment-variables.md",
    "content": "```js renderer=\"common\" language=\"js\" tabTitle=\"node-env\"\nconsole.log(process.env.STORYBOOK_THEME);\nconsole.log(process.env.STORYBOOK_DATA_KEY);\n```\n\n```js renderer=\"common\" language=\"js\" tabTitle=\"vite-env\"\nconsole.log(import.meta.env.STORYBOOK_THEME);\nconsole.log(import.meta.env.STORYBOOK_DATA_KEY);\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-remove-command.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook@latest remove @storybook/addon-a11y\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx storybook@latest remove @storybook/addon-a11y\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn dlx storybook@latest remove @storybook/addon-a11y\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-run-dev.md",
    "content": "```shell renderer=\"angular\" language=\"js\" tabTitle=\"with-builder\"\nng run my-project:storybook\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm run storybook\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm run storybook\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn storybook\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-server-framework-options.md",
    "content": "```ts filename=\"my-framework/src/server/options.ts\" renderer=\"common\" language=\"ts\"\nimport { readFileSync } from 'node:fs';\nimport * as pkg from 'empathic/package';\n\nexport default {\n  packageJson: JSON.parse(readFileSync(pkg.up({ cwd: process.cwd() }))),\n  framework: 'my-framework',\n  frameworkPath: '@my-framework/storybook',\n  frameworkPresets: [import.meta.resolve('./framework-preset-my-framework.js')],\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-server-options.md",
    "content": "```ts filename=\"vue/src/server/options.ts\" renderer=\"common\" language=\"ts\"\nimport { readFileSync } from 'node:fs';\nimport * as pkg from 'empathic/package';\n\nexport default {\n  packageJson: JSON.parse(readFileSync(pkg.up({ cwd: process.cwd() }))),\n  framework: 'vue',\n  frameworkPresets: [import.meta.resolve('./framework-preset-vue.js')],\n};\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-start-dev-server.md",
    "content": "```ts filename=\"your-framework/src/server/index.ts\" renderer=\"common\" language=\"ts\"\nimport { buildDev } from '@storybook/core/server';\n\nimport options from './options';\n\nbuildDev(options);\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-story-layout-param.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const WithLayout: Story = {\n  parameters: {\n    layout: 'centered',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const WithLayout = meta.story({\n  parameters: {\n    layout: 'centered',\n  },\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"WithLayout\"\n  parameters={{\n    layout: 'centered',\n  }}\n/>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n};\n\nexport const WithLayout = {\n  parameters: {\n    layout: 'centered',\n  },\n};\n```\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const WithLayout = {\n  parameters: {\n    layout: 'centered',\n  },\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<Story\n  name=\"WithLayout\"\n  parameters={{\n    layout: 'centered',\n  }}\n/>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const WithLayout: Story = {\n  parameters: {\n    layout: 'centered',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const WithLayout: Story = {\n  parameters: {\n    layout: 'centered',\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  component: 'demo-button',\n};\n\nexport const WithLayout = {\n  parameters: {\n    layout: 'centered',\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  component: 'demo-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const WithLayout: Story = {\n  parameters: {\n    layout: 'centered',\n  },\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const WithLayout = meta.story({\n  parameters: {\n    layout: 'centered',\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n});\n\nexport const WithLayout = meta.story({\n  parameters: {\n    layout: 'centered',\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const WithLayout = meta.story({\n  parameters: {\n    layout: 'centered',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const WithLayout = meta.story({\n  parameters: {\n    layout: 'centered',\n  },\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const WithLayout = meta.story({\n  parameters: {\n    layout: 'centered',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const WithLayout = meta.story({\n  parameters: {\n    layout: 'centered',\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-storyloading-with-directory.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  // 👇 Storybook will load all existing stories within the MyStories folder\n  stories: ['../packages/MyStories'],\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  // 👇 Storybook will load all existing stories within the MyStories folder\n  stories: ['../packages/MyStories'],\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  // 👇 Storybook will load all existing stories within the MyStories folder\n  stories: ['../packages/MyStories'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  // 👇 Storybook will load all existing stories within the MyStories folder\n  stories: ['../packages/MyStories'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  // 👇 Storybook will load all existing stories within the MyStories folder\n  stories: ['../packages/MyStories'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  // 👇 Storybook will load all existing stories within the MyStories folder\n  stories: ['../packages/MyStories'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  // 👇 Storybook will load all existing stories within the MyStories folder\n  stories: ['../packages/MyStories'],\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  // 👇 Storybook will load all existing stories within the MyStories folder\n  stories: ['../packages/MyStories'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  // 👇 Storybook will load all existing stories within the MyStories folder\n  stories: ['../packages/MyStories'],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-storysource-manager-entries.md",
    "content": "```js filename=\"storysource/preset.js\" renderer=\"common\" language=\"js\"\n/* nothing needed */\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-telemetry-crash-report-event.md",
    "content": "```js renderer=\"common\" language=\"js\"\n{\n  stack: 'Error: Your button is not working\\n' +\n    '    at Object.<anonymous> ($SNIP/test.js:39:27)\\n' +\n    '    at Module._compile (node:internal/modules/cjs/loader:1103:14)\\n' +\n    '    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)\\n' +\n    '    at Module.load (node:internal/modules/cjs/loader:981:32)\\n' +\n    '    at Function.Module._load (node:internal/modules/cjs/loader:822:12)\\n' +\n    '    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)\\n' +\n    '    at node:internal/main/run_main_module:17:47',\n  message: 'Your button is not working'\n}\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-telemetry-main-enable-crash-reports.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    enableCrashReports: true, // 👈 Appends the crash reports to the telemetry events\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    enableCrashReports: true, // 👈 Appends the crash reports to the telemetry events\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    enableCrashReports: true, // 👈 Appends the crash reports to the telemetry events\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    enableCrashReports: true, // 👈 Appends the crash reports to the telemetry events\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/angular/node';\n\nexport default defineMain({\n  framework: '@storybook/angular',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    enableCrashReports: true, // 👈 Appends the crash reports to the telemetry events\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    enableCrashReports: true, // 👈 Appends the crash reports to the telemetry events\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    enableCrashReports: true, // 👈 Appends the crash reports to the telemetry events\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-telemetry-preview-event.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nSTORYBOOK_TELEMETRY_DEBUG=1 npm run storybook\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nSTORYBOOK_TELEMETRY_DEBUG=1 yarn storybook\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-telemetry-storybook-enable-crash-reports-env.md",
    "content": "```shell renderer=\"common\" language=\"js\"\nSTORYBOOK_ENABLE_CRASH_REPORTS=1 yarn storybook\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-telemetry-storybook-enable-crash-reports-flag.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm run storybook -- --enable-crash-reports\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm run storybook --enable-crash-reports\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn storybook --enable-crash-reports\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-test-fn-mock-spy.md",
    "content": "```ts filename=\"NoteUI.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\nimport { expect } from 'storybook/test';\n\n// 👇 Automocked module resolves to '../app/__mocks__/actions'\nimport { saveNote } from '../app/actions';\nimport { createNotes } from '../app/mocks/notes';\n\nimport NoteUI from './note-ui.component';\n\nconst meta: Meta<NoteUI> = { component: NoteUI };\nexport default meta;\n\ntype Story = StoryObj<NoteUI>;\n\nconst notes = createNotes();\n\nexport const SaveFlow: Story = {\n  name: 'Save Flow ▶',\n  args: {\n    isEditing: true,\n    note: notes[0],\n  },\n  play: async ({ canvas, userEvent }) => {\n    const saveButton = canvas.getByRole('menuitem', { name: /done/i });\n    await userEvent.click(saveButton);\n    // 👇 This is the mock function, so you can assert its behavior\n    await expect(saveNote).toHaveBeenCalled();\n  },\n};\n```\n\n```ts filename=\"NoteUI.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\n// 👇 Automocked module resolves to '../app/__mocks__/actions'\nimport { saveNote } from '../app/actions';\nimport { createNotes } from '../app/mocks/notes';\n\nimport NoteUI from './note-ui.component';\n\nconst meta = preview.meta({ component: NoteUI });\n\nconst notes = createNotes();\n\nexport const SaveFlow = meta.story({\n  name: 'Save Flow ▶',\n  args: {\n    isEditing: true,\n    note: notes[0],\n  },\n  play: async ({ canvas, userEvent }) => {\n    const saveButton = canvas.getByRole('menuitem', { name: /done/i });\n    await userEvent.click(saveButton);\n    // 👇 This is the mock function, so you can assert its behavior\n    await expect(saveNote).toHaveBeenCalled();\n  },\n});\n```\n\n```svelte filename=\"NoteUI.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import { expect } from 'storybook/test';\n\n  // 👇 Automocked module resolves to '../app/__mocks__/actions'\n  import { saveNote } from '../app/actions';\n  import { createNotes } from '../app/mocks/notes';\n\n  import NoteUI from './note-ui.svelte';\n\n  const { Story } = defineMeta({\n    title: 'Mocked/NoteUI',\n    component: NoteUI,\n  });\n</script>\n\n<script>\n  const notes = createNotes();\n</script>\n\n<Story name=\"Save Flow ▶\"\n  args={{ isEditing: true, note: notes[0] }}\n  play={async ({ canvas, userEvent }) => {\n    const saveButton = canvas.getByRole('menuitem', { name: /done/i });\n    await userEvent.click(saveButton);\n    // 👇 This is the mock function, so you can assert its behavior\n    await expect(saveNote).toHaveBeenCalled();\n  }} />\n```\n\n```js filename=\"NoteUI.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport { expect } from 'storybook/test';\n\n// 👇 Automocked module resolves to '../app/__mocks__/actions'\nimport { saveNote } from '../app/actions';\nimport { createNotes } from '../app/mocks/notes';\n\nimport NoteUI from './note-ui.svelte';\n\nexport default {\n  title: 'Mocked/NoteUI',\n  component: NoteUI,\n};\n\nconst notes = createNotes();\n\nexport const SaveFlow = {\n  name: 'Save Flow ▶',\n  args: {\n    isEditing: true,\n    note: notes[0],\n  },\n  play: async ({ canvas, userEvent }) => {\n    const saveButton = canvas.getByRole('menuitem', { name: /done/i });\n    await userEvent.click(saveButton);\n    // 👇 This is the mock function, so you can assert its behavior\n    await expect(saveNote).toHaveBeenCalled();\n  },\n};\n```\n\n```svelte filename=\"NoteUI.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import { expect } from 'storybook/test';\n\n  // 👇 Automocked module resolves to '../app/__mocks__/actions'\n  import { saveNote } from '../app/actions';\n  import { createNotes } from '../app/mocks/notes';\n\n  import NoteUI from './note-ui.svelte';\n\n  const { Story } = defineMeta({\n    title: 'Mocked/NoteUI',\n    component: NoteUI,\n  });\n</script>\n\n<script>\n  const notes = createNotes();\n</script>\n\n<Story name=\"Save Flow ▶\"\n  args={{ isEditing: true, note: notes[0] }}\n  play={async ({ canvas, userEvent }) => {\n    const saveButton = canvas.getByRole('menuitem', { name: /done/i });\n    await userEvent.click(saveButton);\n    // 👇 This is the mock function, so you can assert its behavior\n    await expect(saveNote).toHaveBeenCalled();\n  }} />\n```\n\n```ts filename=\"NoteUI.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\nimport { expect } from 'storybook/test';\n\n// 👇 Automocked module resolves to '../app/__mocks__/actions'\nimport { saveNote } from '../app/actions';\nimport { createNotes } from '../app/mocks/notes';\n\nimport NoteUI from './note-ui.svelte';\n\nconst meta = {\n  title: 'Mocked/NoteUI',\n  component: NoteUI,\n} satisfies Meta<typeof NoteUI>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nconst notes = createNotes();\n\nexport const SaveFlow: Story = {\n  name: 'Save Flow ▶',\n  args: {\n    isEditing: true,\n    note: notes[0],\n  },\n  play: async ({ canvas, userEvent }) => {\n    const saveButton = canvas.getByRole('menuitem', { name: /done/i });\n    await userEvent.click(saveButton);\n    // 👇 This is the mock function, so you can assert its behavior\n    await expect(saveNote).toHaveBeenCalled();\n  },\n};\n```\n\n```ts filename=\"NoteUI.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\nimport { expect } from 'storybook/test';\n\n// 👇 Automocked module resolves to '../app/__mocks__/actions'\nimport { saveNote } from '../app/actions';\nimport { createNotes } from '../app/mocks/notes';\n\nimport NoteUI from './note-ui';\n\nconst meta = { component: NoteUI } satisfies Meta<typeof NoteUI>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nconst notes = createNotes();\n\nexport const SaveFlow: Story = {\n  name: 'Save Flow ▶',\n  args: {\n    isEditing: true,\n    note: notes[0],\n  },\n  play: async ({ canvas, userEvent }) => {\n    const saveButton = canvas.getByRole('menuitem', { name: /done/i });\n    await userEvent.click(saveButton);\n    // 👇 This is the mock function, so you can assert its behavior\n    await expect(saveNote).toHaveBeenCalled();\n  },\n};\n```\n\n```js filename=\"NoteUI.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { expect } from 'storybook/test';\n\n// 👇 Automocked module resolves to '../app/__mocks__/actions'\nimport { saveNote } from '../app/actions';\nimport { createNotes } from '../app/mocks/notes';\n\nimport NoteUI from './note-ui';\n\nexport default { component: NoteUI };\n\nconst notes = createNotes();\n\nexport const SaveFlow = {\n  name: 'Save Flow ▶',\n  args: {\n    isEditing: true,\n    note: notes[0],\n  },\n  play: async ({ canvas, userEvent }) => {\n    const saveButton = canvas.getByRole('menuitem', { name: /done/i });\n    await userEvent.click(saveButton);\n    // 👇 This is the mock function, so you can assert its behavior\n    await expect(saveNote).toHaveBeenCalled();\n  },\n};\n```\n\n```js filename=\"NoteUI.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { expect } from 'storybook/test';\n\n// 👇 Automocked module resolves to '../app/__mocks__/actions'\nimport { saveNote } from '../app/actions';\nimport { createNotes } from '../app/mocks/notes';\n\nexport default {\n  component: 'note-ui',\n};\n\nconst notes = createNotes();\n\nexport const SaveFlow = {\n  name: 'Save Flow ▶',\n  args: {\n    isEditing: true,\n    note: notes[0],\n  },\n  play: async ({ canvas, userEvent }) => {\n    const saveButton = canvas.getByRole('menuitem', { name: /done/i });\n    await userEvent.click(saveButton);\n    // 👇 This is the mock function, so you can assert its behavior\n    await expect(saveNote).toHaveBeenCalled();\n  },\n};\n```\n\n```ts filename=\"NoteUI.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\nimport { expect } from 'storybook/test';\n\n// 👇 Automocked module resolves to '../app/__mocks__/actions'\nimport { saveNote } from '../app/actions';\nimport { createNotes } from '../app/mocks/notes';\n\nconst meta: Meta = {\n  component: 'note-ui',\n};\nexport default meta;\n\ntype Story = StoryObj;\n\nconst notes = createNotes();\n\nexport const SaveFlow: Story = {\n  name: 'Save Flow ▶',\n  args: {\n    isEditing: true,\n    note: notes[0],\n  },\n  play: async ({ canvas, userEvent }) => {\n    const saveButton = canvas.getByRole('menuitem', { name: /done/i });\n    await userEvent.click(saveButton);\n    // 👇 This is the mock function, so you can assert its behavior\n    await expect(saveNote).toHaveBeenCalled();\n  },\n};\n```\n\n```js filename=\"NoteUI.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\n// 👇 Automocked module resolves to '../app/__mocks__/actions'\nimport { saveNote } from '../app/actions';\nimport { createNotes } from '../app/mocks/notes';\n\nconst meta = preview.meta({\n  component: 'note-ui',\n});\n\nconst notes = createNotes();\n\nexport const SaveFlow = meta.story({\n  name: 'Save Flow ▶',\n  args: {\n    isEditing: true,\n    note: notes[0],\n  },\n  play: async ({ canvas, userEvent }) => {\n    const saveButton = canvas.getByRole('menuitem', { name: /done/i });\n    await userEvent.click(saveButton);\n    // 👇 This is the mock function, so you can assert its behavior\n    await expect(saveNote).toHaveBeenCalled();\n  },\n});\n```\n\n```ts filename=\"NoteUI.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\n// 👇 Automocked module resolves to '../app/__mocks__/actions'\nimport { saveNote } from '../app/actions';\nimport { createNotes } from '../app/mocks/notes';\n\nconst meta = preview.meta({\n  component: 'note-ui',\n});\n\nconst notes = createNotes();\n\nexport const SaveFlow = meta.story({\n  name: 'Save Flow ▶',\n  args: {\n    isEditing: true,\n    note: notes[0],\n  },\n  play: async ({ canvas, userEvent }) => {\n    const saveButton = canvas.getByRole('menuitem', { name: /done/i });\n    await userEvent.click(saveButton);\n    // 👇 This is the mock function, so you can assert its behavior\n    await expect(saveNote).toHaveBeenCalled();\n  },\n});\n```\n\n```ts filename=\"NoteUI.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\n// 👇 Automocked module resolves to '../app/__mocks__/actions'\nimport { saveNote } from '../app/actions';\nimport { createNotes } from '../app/mocks/notes';\n\nimport NoteUI from './note-ui';\n\nconst meta = preview.meta({ component: NoteUI });\n\nconst notes = createNotes();\n\nexport const SaveFlow = meta.story({\n  name: 'Save Flow ▶',\n  args: {\n    isEditing: true,\n    note: notes[0],\n  },\n  play: async ({ canvas, userEvent }) => {\n    const saveButton = canvas.getByRole('menuitem', { name: /done/i });\n    await userEvent.click(saveButton);\n    // 👇 This is the mock function, so you can assert its behavior\n    await expect(saveNote).toHaveBeenCalled();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"NoteUI.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\n// 👇 Automocked module resolves to '../app/__mocks__/actions'\nimport { saveNote } from '../app/actions';\nimport { createNotes } from '../app/mocks/notes';\n\nimport NoteUI from './note-ui';\n\nconst meta = preview.meta({\n  component: NoteUI,\n});\n\nconst notes = createNotes();\n\nexport const SaveFlow = meta.story({\n  name: 'Save Flow ▶',\n  args: {\n    isEditing: true,\n    note: notes[0],\n  },\n  play: async ({ canvas, userEvent }) => {\n    const saveButton = canvas.getByRole('menuitem', { name: /done/i });\n    await userEvent.click(saveButton);\n    // 👇 This is the mock function, so you can assert its behavior\n    await expect(saveNote).toHaveBeenCalled();\n  },\n});\n```\n\n```ts filename=\"NoteUI.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\n// 👇 Automocked module resolves to '../app/__mocks__/actions'\nimport { saveNote } from '../app/actions';\nimport { createNotes } from '../app/mocks/notes';\n\nimport NoteUI from './note-ui.vue';\n\nconst meta = preview.meta({ component: NoteUI });\n\nconst notes = createNotes();\n\nexport const SaveFlow = meta.story({\n  name: 'Save Flow ▶',\n  args: {\n    isEditing: true,\n    note: notes[0],\n  },\n  play: async ({ canvas, userEvent }) => {\n    const saveButton = canvas.getByRole('menuitem', { name: /done/i });\n    await userEvent.click(saveButton);\n    // 👇 This is the mock function, so you can assert its behavior\n    await expect(saveNote).toHaveBeenCalled();\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"NoteUI.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { expect } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\n// 👇 Automocked module resolves to '../app/__mocks__/actions'\nimport { saveNote } from '../app/actions';\nimport { createNotes } from '../app/mocks/notes';\n\nimport NoteUI from './note-ui.vue';\n\nconst meta = preview.meta({\n  component: NoteUI,\n});\n\nconst notes = createNotes();\n\nexport const SaveFlow = meta.story({\n  name: 'Save Flow ▶',\n  args: {\n    isEditing: true,\n    note: notes[0],\n  },\n  play: async ({ canvas, userEvent }) => {\n    const saveButton = canvas.getByRole('menuitem', { name: /done/i });\n    await userEvent.click(saveButton);\n    // 👇 This is the mock function, so you can assert its behavior\n    await expect(saveNote).toHaveBeenCalled();\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-test-mock-file-example.md",
    "content": "```ts filename=\"lib/session.mock.ts\" renderer=\"common\" language=\"ts\"\nimport { fn } from 'storybook/test';\nimport * as actual from './session';\n\nexport * from './session';\nexport const getUserFromSession = fn(actual.getUserFromSession).mockName('getUserFromSession');\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-test-mock-return-value.md",
    "content": "```ts filename=\"Page.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\nimport { mocked } from 'storybook/test';\n\n// 👇 Automocked module resolves to '../lib/__mocks__/session'\nimport { getUserFromSession } from '../lib/session';\n\nimport { Page } from './Page.component';\n\nconst meta: Meta<Page> = {\n  component: Page,\n};\nexport default meta;\n\ntype Story = StoryObj<Page>;\n\nexport const Basic: Story = {\n  async beforeEach() {\n    // 👇 Set the return value for the getUserFromSession function\n    mocked(getUserFromSession).mockReturnValue({ id: '1', name: 'Alice' });\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { mocked } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\n// 👇 Automocked module resolves to '../lib/__mocks__/session'\nimport { getUserFromSession } from '../lib/session';\n\nimport { Page } from './Page.component';\n\nconst meta = preview.meta({\n  component: Page,\n});\n\nexport const Basic = meta.story({\n  async beforeEach() {\n    // 👇 Set the return value for the getUserFromSession function\n    mocked(getUserFromSession).mockReturnValue({ id: '1', name: 'Alice' });\n  },\n});\n```\n\n```svelte filename=\"Page.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  // 👇 Automocked module resolves to '../lib/__mocks__/session'\n  import { getUserFromSession } from '../lib/session';\n\n  import Page from './Page.svelte';\n\n  const { Story } = defineMeta({\n    component: Page,\n  });\n</script>\n\n<Story name=\"Default\" beforeEach={() => {\n  // 👇 Set the return value for the getUserFromSession function\n  getUserFromSession.mockReturnValue({ id: '1', name: 'Alice' });\n}} />\n```\n\n```js filename=\"Page.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\n// 👇 Automocked module resolves to '../lib/__mocks__/session'\nimport { getUserFromSession } from '../lib/session';\n\nimport Page from './Page.svelte';\n\nexport default {\n  component: Page,\n};\n\nexport const Basic = {\n  async beforeEach() {\n    // 👇 Set the return value for the getUserFromSession function\n    getUserFromSession.mockReturnValue({ id: '1', name: 'Alice' });\n  },\n};\n```\n\n```js filename=\"Page.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\n// 👇 Automocked module resolves to '../lib/__mocks__/session'\nimport { getUserFromSession } from '../lib/session';\n\nimport { Page } from './Page';\n\nexport default {\n  component: Page,\n};\n\nexport const Basic = {\n  async beforeEach() {\n    // 👇 Set the return value for the getUserFromSession function\n    getUserFromSession.mockReturnValue({ id: '1', name: 'Alice' });\n  },\n};\n```\n\n```svelte filename=\"Page.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import { mocked } from 'storybook/test';\n\n  // 👇 Automocked module resolves to '../lib/__mocks__/session'\n  import { getUserFromSession } from '../lib/session';\n\n  import Page from './Page.svelte';\n\n  const { Story } = defineMeta({\n    component: Page,\n  });\n</script>\n\n<Story name=\"Default\" beforeEach={() => {\n  // 👇 Set the return value for the getUserFromSession function\n  mocked(getUserFromSession).mockReturnValue({ id: '1', name: 'Alice' });\n}} />\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\nimport { mocked } from 'storybook/test';\n\n// 👇 Automocked module resolves to '../lib/__mocks__/session'\nimport { getUserFromSession } from '../lib/session';\n\nimport Page from './Page.svelte';\n\nconst meta = {\n  component: Page,\n} satisfies Meta<typeof Page>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  async beforeEach() {\n    // 👇 Set the return value for the getUserFromSession function\n    mocked(getUserFromSession).mockReturnValue({ id: '1', name: 'Alice' });\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\nimport { mocked } from 'storybook/test';\n\n// 👇 Automocked module resolves to '../lib/__mocks__/session'\nimport { getUserFromSession } from '../lib/session';\n\nimport { Page } from './Page';\n\nconst meta = {\n  component: Page,\n} satisfies Meta<typeof Page>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  async beforeEach() {\n    // 👇 Set the return value for the getUserFromSession function\n    mocked(getUserFromSession).mockReturnValue({ id: '1', name: 'Alice' });\n  },\n};\n```\n\n```js filename=\"Page.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\n// 👇 Automocked module resolves to '../lib/__mocks__/session'\nimport { getUserFromSession } from '../lib/session';\n\nexport default {\n  component: 'my-page',\n};\n\nexport const Basic = {\n  async beforeEach() {\n    // 👇 Set the return value for the getUserFromSession function\n    getUserFromSession.mockReturnValue({ id: '1', name: 'Alice' });\n  },\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\nimport { mocked } from 'storybook/test';\n\n// 👇 Automocked module resolves to '../lib/__mocks__/session'\nimport { getUserFromSession } from '../lib/session';\n\nconst meta: Meta = {\n  component: 'my-page',\n};\nexport default meta;\n\ntype Story = StoryObj;\n\nexport const Basic: Story = {\n  async beforeEach() {\n    // 👇 Set the return value for the getUserFromSession function\n    mocked(getUserFromSession).mockReturnValue({ id: '1', name: 'Alice' });\n  },\n};\n```\n\n```js filename=\"Page.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n// 👇 Automocked module resolves to '../lib/__mocks__/session'\nimport { getUserFromSession } from '../lib/session';\n\nconst meta = preview.meta({\n  component: 'my-page',\n});\n\nexport const Basic = meta.story({\n  async beforeEach() {\n    // 👇 Set the return value for the getUserFromSession function\n    getUserFromSession.mockReturnValue({ id: '1', name: 'Alice' });\n  },\n});\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { mocked } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\n// 👇 Automocked module resolves to '../lib/__mocks__/session'\nimport { getUserFromSession } from '../lib/session';\n\nconst meta = preview.meta({\n  component: 'my-page',\n});\n\nexport const Basic = meta.story({\n  async beforeEach() {\n    // 👇 Set the return value for the getUserFromSession function\n    mocked(getUserFromSession).mockReturnValue({ id: '1', name: 'Alice' });\n  },\n});\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { mocked } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\n// 👇 Automocked module resolves to '../lib/__mocks__/session'\nimport { getUserFromSession } from '../lib/session';\n\nimport { Page } from './Page';\n\nconst meta = preview.meta({\n  component: Page,\n});\n\nexport const Basic = meta.story({\n  async beforeEach() {\n    // 👇 Set the return value for the getUserFromSession function\n    mocked(getUserFromSession).mockReturnValue({ id: '1', name: 'Alice' });\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Page.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n// 👇 Automocked module resolves to '../lib/__mocks__/session'\nimport { getUserFromSession } from '../lib/session';\n\nimport { Page } from './Page';\n\nconst meta = preview.meta({\n  component: Page,\n});\n\nexport const Basic = meta.story({\n  async beforeEach() {\n    // 👇 Set the return value for the getUserFromSession function\n    getUserFromSession.mockReturnValue({ id: '1', name: 'Alice' });\n  },\n});\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { mocked } from 'storybook/test';\n\nimport preview from '../.storybook/preview';\n\n// 👇 Automocked module resolves to '../lib/__mocks__/session'\nimport { getUserFromSession } from '../lib/session';\n\nimport Page from './Page.vue';\n\nconst meta = preview.meta({\n  component: Page,\n});\n\nexport const Basic = meta.story({\n  async beforeEach() {\n    // 👇 Set the return value for the getUserFromSession function\n    mocked(getUserFromSession).mockReturnValue({ id: '1', name: 'Alice' });\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Page.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n// 👇 Automocked module resolves to '../lib/__mocks__/session'\nimport { getUserFromSession } from '../lib/session';\n\nimport Page from './Page.vue';\n\nconst meta = preview.meta({\n  component: Page,\n});\n\nexport const Basic = meta.story({\n  async beforeEach() {\n    // 👇 Set the return value for the getUserFromSession function\n    getUserFromSession.mockReturnValue({ id: '1', name: 'Alice' });\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-test-with-storyname.md",
    "content": "```js filename=\"MyComponent-test.js\" renderer=\"common\" language=\"js\"\nit('should format CSF exports with sensible defaults', () => {\n  const testCases = {\n    name: 'Name',\n    someName: 'Some Name',\n    someNAME: 'Some NAME',\n    some_custom_NAME: 'Some Custom NAME',\n    someName1234: 'Some Name 1234',\n    someName1_2_3_4: 'Some Name 1 2 3 4',\n  };\n  Object.entries(testCases).forEach(([key, val]) => {\n    expect(storyNameFromExport(key)).toBe(val);\n  });\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-theme-example-variables.md",
    "content": "```js filename=\".storybook/YourTheme.js\" renderer=\"common\" language=\"js\"\nimport { create } from 'storybook/theming';\n\nexport default create({\n  base: 'light',\n  brandTitle: 'My custom Storybook',\n  brandUrl: 'https://example.com',\n  brandImage: 'https://storybook.js.org/images/placeholders/350x150.png',\n  brandTarget: '_self',\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-theming-styled-import.md",
    "content": "```js filename=\"YourTheme.js\" renderer=\"common\" language=\"js\"\nimport { styled } from 'storybook/theming';\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-upgrade-prerelease.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook@next upgrade\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx storybook@next upgrade\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn dlx storybook@next upgrade\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-upgrade-to-prior-major.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook@^7 upgrade\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx storybook@^7 upgrade\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn dlx storybook@^7 upgrade\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-upgrade.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook@latest upgrade\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx storybook@latest upgrade\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn dlx storybook@latest upgrade\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-vite-builder-aliasing.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using (e.g., react-vite, vue3-vite, etc.)\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: '@storybook/builder-vite',\n  },\n  async viteFinal(config) {\n    // Merge custom configuration into the default config\n    const { mergeConfig } = await import('vite');\n\n    return mergeConfig(config, {\n      // Add dependencies to pre-optimization\n      optimizeDeps: {\n        include: ['storybook-dark-mode'],\n      },\n    });\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using (e.g., react-vite, vue3-vite, etc.)\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: '@storybook/builder-vite',\n  },\n  async viteFinal(config) {\n    // Merge custom configuration into the default config\n    const { mergeConfig } = await import('vite');\n\n    return mergeConfig(config, {\n      // Add dependencies to pre-optimization\n      optimizeDeps: {\n        include: ['storybook-dark-mode'],\n      },\n    });\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: '@storybook/builder-vite',\n  },\n  async viteFinal(config) {\n    // Merge custom configuration into the default config\n    const { mergeConfig } = await import('vite');\n\n    return mergeConfig(config, {\n      // Add dependencies to pre-optimization\n      optimizeDeps: {\n        include: ['storybook-dark-mode'],\n      },\n    });\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: '@storybook/builder-vite',\n  },\n  async viteFinal(config) {\n    // Merge custom configuration into the default config\n    const { mergeConfig } = await import('vite');\n\n    return mergeConfig(config, {\n      // Add dependencies to pre-optimization\n      optimizeDeps: {\n        include: ['storybook-dark-mode'],\n      },\n    });\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: '@storybook/builder-vite',\n  },\n  async viteFinal(config) {\n    // Merge custom configuration into the default config\n    const { mergeConfig } = await import('vite');\n\n    return mergeConfig(config, {\n      // Add dependencies to pre-optimization\n      optimizeDeps: {\n        include: ['storybook-dark-mode'],\n      },\n    });\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: '@storybook/builder-vite',\n  },\n  async viteFinal(config) {\n    // Merge custom configuration into the default config\n    const { mergeConfig } = await import('vite');\n\n    return mergeConfig(config, {\n      // Add dependencies to pre-optimization\n      optimizeDeps: {\n        include: ['storybook-dark-mode'],\n      },\n    });\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: '@storybook/builder-vite',\n  },\n  async viteFinal(config) {\n    // Merge custom configuration into the default config\n    const { mergeConfig } = await import('vite');\n\n    return mergeConfig(config, {\n      // Add dependencies to pre-optimization\n      optimizeDeps: {\n        include: ['storybook-dark-mode'],\n      },\n    });\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: '@storybook/builder-vite',\n  },\n  async viteFinal(config) {\n    // Merge custom configuration into the default config\n    const { mergeConfig } = await import('vite');\n\n    return mergeConfig(config, {\n      // Add dependencies to pre-optimization\n      optimizeDeps: {\n        include: ['storybook-dark-mode'],\n      },\n    });\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-vite-builder-install.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm install @storybook/builder-vite --save-dev\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm add --save-dev @storybook/builder-vite\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn add --dev @storybook/builder-vite\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-vite-builder-jest-mock.md",
    "content": "```html filename=\".storybook/preview-head.html\" renderer=\"common\" language=\"js\"\n<script>\n  window.global = window;\n</script>\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-vite-builder-react-docgen.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using (e.g., react-vite, vue3-vite, angular, etc.)\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: '@storybook/builder-vite',\n  },\n  typescript: {\n    // Enables the `react-docgen-typescript` parser.\n    // See https://storybook.js.org/docs/api/main-config/main-config-typescript for more information about this option.\n    reactDocgen: 'react-docgen-typescript',\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using (e.g., react-vite, vue3-vite, angular, etc.)\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: '@storybook/builder-vite',\n  },\n  typescript: {\n    // Enables the `react-docgen-typescript` parser.\n    // See https://storybook.js.org/docs/api/main-config/main-config-typescript for more information about this option.\n    reactDocgen: 'react-docgen-typescript',\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: '@storybook/builder-vite',\n  },\n  typescript: {\n    // Enables the `react-docgen-typescript` parser.\n    // See https://storybook.js.org/docs/api/main-config/main-config-typescript for more information about this option.\n    reactDocgen: 'react-docgen-typescript',\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: '@storybook/builder-vite',\n  },\n  typescript: {\n    // Enables the `react-docgen-typescript` parser.\n    // See https://storybook.js.org/docs/api/main-config/main-config-typescript for more information about this option.\n    reactDocgen: 'react-docgen-typescript',\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-vite-builder-register.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // Replace your-framework with the framework you are using (e.g., react-vite, nextjs-vite, vue3-vite, etc.)\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: '@storybook/builder-vite', // 👈 The builder enabled here.\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs-vite, vue3-vite, etc.)\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: '@storybook/builder-vite', // 👈 The builder enabled here.\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: '@storybook/builder-vite', // 👈 The builder enabled here.\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: '@storybook/builder-vite', // 👈 The builder enabled here.\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: '@storybook/builder-vite', // 👈 The builder enabled here.\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: '@storybook/builder-vite', // 👈 The builder enabled here.\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: '@storybook/builder-vite', // 👈 The builder enabled here.\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  core: {\n    builder: '@storybook/builder-vite', // 👈 The builder enabled here.\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/storybook-vite-builder-ts-configure.md",
    "content": "```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs-vite, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config, options) {\n    // Add your configuration here\n    return config;\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config, options) {\n    // Add your configuration here\n    return config;\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/vue3-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config, options) {\n    // Add your configuration here\n    return config;\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config, options) {\n    // Add your configuration here\n    return config;\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/subpath-imports-config.md",
    "content": "```jsonc filename=\"package.json\" renderer=\"common\" language=\"json\"\n{\n  \"imports\": {\n    \"#api\": {\n      // storybook condition applies to Storybook\n      \"storybook\": \"./api.mock.ts\",\n      \"default\": \"./api.ts\",\n    },\n    \"#app/actions\": {\n      \"storybook\": \"./app/actions.mock.ts\",\n      \"default\": \"./app/actions.ts\",\n    },\n    \"#lib/session\": {\n      \"storybook\": \"./lib/session.mock.ts\",\n      \"default\": \"./lib/session.ts\",\n    },\n    \"#lib/db\": {\n      // test condition applies to test environments *and* Storybook\n      \"test\": \"./lib/db.mock.ts\",\n      \"default\": \"./lib/db.ts\",\n    },\n    \"#*\": [\"./*\", \"./*.ts\", \"./*.tsx\"],\n  },\n}\n```\n"
  },
  {
    "path": "docs/_snippets/svelte-csf-addon-install.md",
    "content": "```shell renderer=\"svelte\" language=\"js\" packageManager=\"npm\"\nnpx storybook@latest add @storybook/addon-svelte-csf\n```\n\n```shell renderer=\"svelte\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx storybook@latest add @storybook/addon-svelte-csf\n```\n\n```shell renderer=\"svelte\" language=\"js\" packageManager=\"yarn\"\nyarn storybook@latest add @storybook/addon-svelte-csf\n```\n"
  },
  {
    "path": "docs/_snippets/svelte-csf-addon-options.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"svelte\" language=\"js\"\nexport default {\n  // Other configuration\n  addons: [\n    {\n      name: '@storybook/addon-svelte-csf',\n      options: {\n        legacyTemplate: true, // Enables the legacy template syntax\n      },\n    },\n  ],\n};\n```\n\n```js filename=\".storybook/main.ts\" renderer=\"svelte\" language=\"ts\"\n// Replace your-framework with the name of your Svelte framework\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  // Other configuration\n  addons: [\n    {\n      name: '@storybook/addon-svelte-csf',\n      options: {\n        legacyTemplate: true, // Enables the legacy template syntax\n      },\n    },\n  ],\n};\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/svelte-csf-addon-tags.md",
    "content": "```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Before\"\n<script>\n  import { Meta, Template, Story } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n</script>\n\n<Meta title=\"MyComponent\" component={MyComponent} />\n\n<Template let:args>\n  <MyComponent {...args} />\n</Template>\n\n<Story name=\"Default\" autodocs />\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"After\"\n\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n\n</script>\n\n<Story name=\"Default\" tags={['autodocs']} />\n```\n"
  },
  {
    "path": "docs/_snippets/svelte-csf-story-custom-children.md",
    "content": "```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Before\"\n<script>\n  import { Meta, Template, Story } from '@storybook/addon-svelte-csf';\n\n  import OuterComponent from './OuterComponent.svelte';\n  import MyComponent from './MyComponent.svelte';\n</script>\n\n<Meta title=\"MyComponent\" component={MyComponent} />\n\n<Template let:args>\n  <OuterComponent>\n    <MyComponent />\n  </OuterComponent>\n</Template>\n\n<Story name=\"Default\" />\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"After\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import OuterComponent from './OuterComponent.svelte';\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n\n</script>\n\n<Story name=\"Default\">\n  <OuterComponent>\n    <MyComponent />\n  </OuterComponent>\n</Story>\n```\n"
  },
  {
    "path": "docs/_snippets/svelte-csf-story-migration.md",
    "content": "```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Before\"\n<script>\n  import { Meta, Story } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n</script>\n\n\n<Meta title=\"MyComponent\" component={MyComponent} />\n\n<Story name=\"Default\" />\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"After\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    title: 'MyComponent',\n    component: MyComponent,\n  });\n</script>\n\n<Story name=\"Default\" />\n```\n"
  },
  {
    "path": "docs/_snippets/svelte-framework-options-docgen.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"svelte\" language=\"js\"\n// Replace your-framework with svelte-vite or sveltekit\nexport default {\n  framework: {\n    name: '@storybook/your-framework',\n    options: {\n      docgen: false, // Disable docgen for better performance\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"svelte\" language=\"ts\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: {\n    name: '@storybook/your-framework',\n    options: {\n      docgen: false, // Disable docgen for better performance\n    },\n  },\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/svelte-vite-add-framework.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"svelte\" language=\"js\"\nexport default {\n  // ...\n  framework: '@storybook/svelte-vite', // 👈 Add this\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"svelte\" language=\"ts\"\nimport type { StorybookConfig } from '@storybook/svelte-vite';\n\nconst config: StorybookConfig = {\n  // ...\n  framework: '@storybook/svelte-vite', // 👈 Add this\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/svelte-vite-framework-options.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"svelte\" language=\"js\"\nexport default {\n  // ...\n  framework: {\n    name: '@storybook/svelte-vite',\n    options: {\n      // ...\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"svelte\" language=\"ts\"\nimport type { StorybookConfig } from '@storybook/svelte-vite';\n\nconst config: StorybookConfig = {\n  // ...\n  framework: {\n    name: '@storybook/svelte-vite',\n    options: {\n      // ...\n    },\n  },\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/svelte-vite-install.md",
    "content": "```shell renderer=\"svelte\" language=\"js\" packageManager=\"npm\"\nnpm install --save-dev @storybook/svelte-vite\n```\n\n```shell renderer=\"svelte\" language=\"js\" packageManager=\"pnpm\"\npnpm add --save-dev @storybook/svelte-vite\n```\n\n```shell renderer=\"svelte\" language=\"js\" packageManager=\"yarn\"\nyarn add --dev @storybook/svelte-vite\n```\n"
  },
  {
    "path": "docs/_snippets/sveltekit-add-framework.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"svelte\" language=\"js\"\nexport default {\n  // ...\n  framework: '@storybook/sveltekit', // 👈 Add this\n  // svelteOptions: { ... }, 👈 Remove this\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"svelte\" language=\"ts\"\nimport type { StorybookConfig } from '@storybook/sveltekit';\n\nconst config: StorybookConfig = {\n  // ...\n  framework: '@storybook/sveltekit', // 👈 Add this\n  // svelteOptions: { ... }, 👈 Remove this\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/sveltekit-framework-options.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"svelte\" language=\"js\"\nexport default {\n  // ...\n  framework: {\n    name: '@storybook/sveltekit',\n    options: {\n      // ...\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"svelte\" language=\"ts\"\nimport type { StorybookConfig } from '@storybook/sveltekit';\n\nconst config: StorybookConfig = {\n  // ...\n  framework: {\n    name: '@storybook/sveltekit',\n    options: {\n      // ...\n    },\n  },\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/sveltekit-install.md",
    "content": "```shell renderer=\"svelte\" language=\"js\" packageManager=\"npm\"\nnpm install --save-dev @storybook/sveltekit\n```\n\n```shell renderer=\"svelte\" language=\"js\" packageManager=\"pnpm\"\npnpm add --save-dev @storybook/sveltekit\n```\n\n```shell renderer=\"svelte\" language=\"js\" packageManager=\"yarn\"\nyarn add --dev @storybook/sveltekit\n```\n"
  },
  {
    "path": "docs/_snippets/sveltekit-mock-features.md",
    "content": "```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"MyStory\"\n  parameters={{\n    sveltekit_experimental: {\n      state: {\n        page: {\n          data: {\n            test: 'passed',\n          },\n        },\n        navigating: {\n          to: {\n            route: { id: '/storybook' },\n            params: {},\n            url: new URL('http://localhost/storybook'),\n          },\n        },\n        updated: {\n          current: true,\n        },\n      },\n    },\n  }}\n/>\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.svelte';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const MyStory = {\n  parameters: {\n    sveltekit_experimental: {\n      state: {\n        page: {\n          data: {\n            test: 'passed',\n          },\n        },\n        navigating: {\n          to: {\n            route: { id: '/storybook' },\n            params: {},\n            url: new URL('http://localhost/storybook'),\n          },\n        },\n        updated: {\n          current: true,\n        },\n      },\n    },\n  },\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"MyStory\"\n  parameters={{\n    sveltekit_experimental: {\n      state: {\n        page: {\n          data: {\n            test: 'passed',\n          },\n        },\n        navigating: {\n          to: {\n            route: { id: '/storybook' },\n            params: {},\n            url: new URL('http://localhost/storybook'),\n          },\n        },\n        updated: {\n          current: true,\n        },\n      },\n    },\n  }}\n/>\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/sveltekit';\n\nimport MyComponent from './MyComponent.svelte';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const MyStory: Story = {\n  parameters: {\n    sveltekit_experimental: {\n      state: {\n        page: {\n          data: {\n            test: 'passed',\n          },\n        },\n        navigating: {\n          to: {\n            route: { id: '/storybook' },\n            params: {},\n            url: new URL('http://localhost/storybook'),\n          },\n        },\n        updated: {\n          current: true,\n        },\n      },\n    },\n  },\n};\n```\n"
  },
  {
    "path": "docs/_snippets/sveltekit-mock-links.md",
    "content": "```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"MyStory\"\n  parameters={{\n    sveltekit_experimental: {\n      hrefs: {\n        '/basic-href': (to, event) => {\n          console.log(to, event);\n        },\n        '/root.*': {\n          callback: (to, event) => {\n            console.log(to, event);\n          },\n          asRegex: true,\n        },\n      },\n    },\n  }}\n/>\n```\n\n```js filename=\"MyComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport MyComponent from './MyComponent.svelte';\n\nexport default {\n  component: MyComponent,\n};\n\nexport const MyStory = {\n  parameters: {\n    sveltekit_experimental: {\n      hrefs: {\n        '/basic-href': (to, event) => {\n          console.log(to, event);\n        },\n        '/root.*': {\n          callback: (to, event) => {\n            console.log(to, event);\n          },\n          asRegex: true,\n        },\n      },\n    },\n  },\n};\n```\n\n```svelte filename=\"MyComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story\n  name=\"MyStory\"\n  parameters={{\n    sveltekit_experimental: {\n      hrefs: {\n        '/basic-href': (to, event) => {\n          console.log(to, event);\n        },\n        '/root.*': {\n          callback: (to, event) => {\n            console.log(to, event);\n          },\n          asRegex: true,\n        },\n      },\n    },\n  }}\n/>\n```\n\n```ts filename=\"MyComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/sveltekit';\n\nimport MyComponent from './MyComponent.svelte';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const MyStory: Story = {\n  parameters: {\n    sveltekit_experimental: {\n      hrefs: {\n        '/basic-href': (to, event) => {\n          console.log(to, event);\n        },\n        '/root.*': {\n          callback: (to, event) => {\n            console.log(to, event);\n          },\n          asRegex: true,\n        },\n      },\n    },\n  },\n};\n```\n"
  },
  {
    "path": "docs/_snippets/tag-manifest-remove-in-story.md",
    "content": "```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { MyComponent } from './MyComponent';\n\nexport default {\n  component: MyComponent,\n};\n\n// 👇 This story will be included in the manifest because it has the implicit 'manifest' tag\nexport const Basic = {};\n\nexport const ForInstructionOnly = {\n  tags: ['!manifest'], // 👈 Remove the 'manifest' tag to exclude this story from the manifests\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = {\n  component: MyComponent,\n} satisfies Meta<typeof MyComponent>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n// 👇 This story will be included in the manifest because it has the implicit 'manifest' tag\nexport const Basic = {};\n\nexport const ForInstructionOnly = {\n  tags: ['!manifest'], // 👈 Remove the 'manifest' tag to exclude this story from the manifests\n};\n```\n\n```ts filename=\"MyComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\n// 👇 This story will be included in the manifest because it has the implicit 'manifest' tag\nexport const Basic = meta.story();\n\nexport const ForInstructionOnly = meta.story({\n  tags: ['!manifest'], // 👈 Remove the 'manifest' tag to exclude this story from the manifests\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"MyComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './MyComponent';\n\nconst meta = preview.meta({\n  component: MyComponent,\n});\n\n// 👇 This story will be included in the manifest because it has the implicit 'manifest' tag\nexport const Basic = meta.story();\n\nexport const ForInstructionOnly = meta.story({\n  tags: ['!manifest'], // 👈 Remove the 'manifest' tag to exclude this story from the manifests\n});\n```\n"
  },
  {
    "path": "docs/_snippets/tags-autodocs-in-meta.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Button } from './Button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n};\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    //👇 Enables auto-generated documentation for this component and includes all stories in this file\n    tags: ['autodocs'],\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    //👇 Enables auto-generated documentation for this component and includes all stories in this file\n    tags: ['autodocs'],\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n} satisfies Meta<typeof Button>;\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n} satisfies Meta<typeof Button>;\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  title: 'Button',\n  component: 'demo-button',\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  title: 'Button',\n  component: 'demo-button',\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n};\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/tags-autodocs-in-preview.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  //👇 Enables auto-generated documentation for all stories\n  tags: ['autodocs'],\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  //👇 Enables auto-generated documentation for all stories\n  tags: ['autodocs'],\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  //👇 Enables auto-generated documentation for all stories\n  tags: ['autodocs'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  //👇 Enables auto-generated documentation for all stories\n  tags: ['autodocs'],\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  //👇 Enables auto-generated documentation for all stories\n  tags: ['autodocs'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  //👇 Enables auto-generated documentation for all stories\n  tags: ['autodocs'],\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  //👇 Enables auto-generated documentation for all stories\n  tags: ['autodocs'],\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  //👇 Enables auto-generated documentation for all stories\n  tags: ['autodocs'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  //👇 Enables auto-generated documentation for all stories\n  tags: ['autodocs'],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/tags-autodocs-remove-component.md",
    "content": "```ts filename=\"Page.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/angular';\n\nimport { Page } from './Page.component';\n\nconst meta: Meta<Page> = {\n  component: Page,\n  // 👇 Disable auto-generated documentation for this component\n  tags: ['!autodocs'],\n};\nexport default meta;\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Page } from './Page.component';\n\nconst meta = preview.meta({\n  component: Page,\n  // 👇 Disable auto-generated documentation for this component\n  tags: ['!autodocs'],\n});\n```\n\n```svelte filename=\"Page.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Page from './Page.svelte';\n\n  const { Story } = defineMeta({\n    component: Page,\n    // 👇 Disable auto-generated documentation for this component\n    tags: ['!autodocs'],\n  });\n</script>\n```\n\n```js filename=\"Page.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Page from './Page.svelte';\n\nexport default {\n  component: Page,\n  // 👇 Disable auto-generated documentation for this component\n  tags: ['!autodocs'],\n};\n```\n\n```js filename=\"Page.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Page } from './Page';\n\nexport default {\n  component: Page,\n  // 👇 Disable auto-generated documentation for this component\n  tags: ['!autodocs'],\n};\n```\n\n```svelte filename=\"Page.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Page from './Page.svelte';\n\n  const { Story } = defineMeta({\n    component: Page,\n    // 👇 Disable auto-generated documentation for this component\n    tags: ['!autodocs'],\n  });\n</script>\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Page from './Page.svelte';\n\nconst meta = {\n  component: Page,\n  // 👇 Disable auto-generated documentation for this component\n  tags: ['!autodocs'],\n} satisfies Meta<typeof Page>;\nexport default meta;\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Page } from './Page';\n\nconst meta = {\n  component: Page,\n  // 👇 Disable auto-generated documentation for this component\n  tags: ['!autodocs'],\n} satisfies Meta<typeof Page>;\nexport default meta;\n```\n\n```js filename=\"Page.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  title: 'Page',\n  component: 'demo-page',\n  // 👇 Disable auto-generated documentation for this component\n  tags: ['!autodocs'],\n};\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  title: 'Page',\n  component: 'demo-page',\n  // 👇 Disable auto-generated documentation for this component\n  tags: ['!autodocs'],\n};\nexport default meta;\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-page',\n  // 👇 Disable auto-generated documentation for this component\n  tags: ['!autodocs'],\n});\n```\n\n```js filename=\"Page.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-page',\n  // 👇 Disable auto-generated documentation for this component\n  tags: ['!autodocs'],\n});\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Page } from './Page';\n\nconst meta = preview.meta({\n  component: Page,\n  // 👇 Disable auto-generated documentation for this component\n  tags: ['!autodocs'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Page.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Page } from './Page';\n\nconst meta = preview.meta({\n  component: Page,\n  // 👇 Disable auto-generated documentation for this component\n  tags: ['!autodocs'],\n});\n```\n\n```ts filename=\"Page.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Page from './Page.vue';\n\nconst meta = preview.meta({\n  component: Page,\n  // 👇 Disable auto-generated documentation for this component\n  tags: ['!autodocs'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Page.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Page from './Page.vue';\n\nconst meta = preview.meta({\n  component: Page,\n  // 👇 Disable auto-generated documentation for this component\n  tags: ['!autodocs'],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/tags-autodocs-remove-story.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './Button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n};\nexport default meta;\n\ntype Story = StoryObj<Button>;\n\nexport const UndocumentedStory: Story = {\n  // 👇 Removes this story from auto-generated documentation\n  tags: ['!autodocs'],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n});\n\nexport const UndocumentedStory = meta.story({\n  // 👇 Removes this story from auto-generated documentation\n  tags: ['!autodocs'],\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    //👇 Enables auto-generated documentation for this component and includes all stories in this file\n    tags: ['autodocs'],\n  });\n</script>\n\n<!--👇 Removes this story from auto-generated documentation -->\n<Story name=\"UndocumentedStory\" tags={['!autodocs']} />\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n};\n\nexport const UndocumentedStory = {\n  // 👇 Removes this story from auto-generated documentation\n  tags: ['!autodocs'],\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n};\n\nexport const UndocumentedStory = {\n  // 👇 Removes this story from auto-generated documentation\n  tags: ['!autodocs'],\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    //👇 Enables auto-generated documentation for this component and includes all stories in this file\n    tags: ['autodocs'],\n  });\n</script>\n\n<!--👇 Removes this story from auto-generated documentation -->\n<Story name=\"UndocumentedStory\" tags={['!autodocs']} />\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n} satisfies Meta<typeof Button>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const UndocumentedStory: Story = {\n  // 👇 Removes this story from auto-generated documentation\n  tags: ['!autodocs'],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n} satisfies Meta<typeof Button>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const UndocumentedStory: Story = {\n  // 👇 Removes this story from auto-generated documentation\n  tags: ['!autodocs'],\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  title: 'Button',\n  component: 'demo-button',\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n};\n\nexport const UndocumentedStory = {\n  // 👇 Removes this story from auto-generated documentation\n  tags: ['!autodocs'],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  title: 'Button',\n  component: 'demo-button',\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n};\nexport default meta;\n\ntype Story = StoryObj;\n\nexport const UndocumentedStory: Story = {\n  // 👇 Removes this story from auto-generated documentation\n  tags: ['!autodocs'],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n});\n\nexport const UndocumentedStory = meta.story({\n  // 👇 Removes this story from auto-generated documentation\n  tags: ['!autodocs'],\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n});\n\nexport const UndocumentedStory = meta.story({\n  // 👇 Removes this story from auto-generated documentation\n  tags: ['!autodocs'],\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n});\n\nexport const UndocumentedStory = meta.story({\n  // 👇 Removes this story from auto-generated documentation\n  tags: ['!autodocs'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n});\n\nexport const UndocumentedStory = meta.story({\n  // 👇 Removes this story from auto-generated documentation\n  tags: ['!autodocs'],\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n});\n\nexport const UndocumentedStory = meta.story({\n  // 👇 Removes this story from auto-generated documentation\n  tags: ['!autodocs'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  //👇 Enables auto-generated documentation for this component and includes all stories in this file\n  tags: ['autodocs'],\n});\n\nexport const UndocumentedStory = meta.story({\n  // 👇 Removes this story from auto-generated documentation\n  tags: ['!autodocs'],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/tags-combo-example.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './Button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\nexport default meta;\n\ntype Story = StoryObj<Button>;\n\nexport const Variant1: Story = {\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 1 },\n};\n\nexport const Variant2: Story = {\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 2 },\n};\n\nexport const Combo: Story = {\n  // 👇 This story should not be tested, but will appear in the sidebar and docs page\n  tags: ['!test'],\n  render: () => ({\n    template: `\n      <div>\n        <demo-button [variant]=\"1\"></demo-button>\n        <demo-button [variant]=\"2\"></demo-button>\n      </div>\n    `,\n  }),\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button.component';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Variant1 = meta.story({\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 1 },\n});\n\nexport const Variant2 = meta.story({\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 2 },\n});\n\nexport const Combo = meta.story({\n  // 👇 This story should not be tested, but will appear in the sidebar and docs page\n  tags: ['!test'],\n  render: () => ({\n    template: `\n      <div>\n        <demo-button [variant]=\"1\"></demo-button>\n        <demo-button [variant]=\"2\"></demo-button>\n      </div>\n    `,\n  }),\n});\n```\n\n```jsx filename=\"Button.stories.jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Variant1 = {\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 1 },\n};\n\nexport const Variant2 = {\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 2 },\n};\n\nexport const Combo = {\n  // 👇 This story should not be tested, but will appear in the sidebar and docs page\n  tags: ['!test'],\n  render: () => (\n    <>\n      <Button variant={1} />\n      <Button variant={2} />\n    </>\n  ),\n};\n```\n\n```tsx filename=\"Button.stories.tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Variant1: Story = {\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 1 },\n};\n\nexport const Variant2: Story = {\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 2 },\n};\n\nexport const Combo: Story = {\n  // 👇 This story should not be tested, but will appear in the sidebar and docs page\n  tags: ['!test'],\n  render: () => (\n    <>\n      <Button variant={1} />\n      <Button variant={2} />\n    </>\n  ),\n};\n```\n\n```jsx filename=\"Button.stories.jsx\" renderer=\"solid\" language=\"js\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Variant1 = {\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 1 },\n};\n\nexport const Variant2 = {\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 2 },\n};\n\nexport const Combo = {\n  // 👇 This story should not be tested, but will appear in the sidebar and docs page\n  tags: ['!test'],\n  render: () => (\n    <>\n      <Button variant={1} />\n      <Button variant={2} />\n    </>\n  ),\n};\n```\n\n```tsx filename=\"Button.stories.tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Variant1: Story = {\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 1 },\n};\n\nexport const Variant2: Story = {\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 2 },\n};\n\nexport const Combo: Story = {\n  // 👇 This story should not be tested, but will appear in the sidebar and docs page\n  tags: ['!test'],\n  render: () => (\n    <>\n      <Button variant={1} />\n      <Button variant={2} />\n    </>\n  ),\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<!-- 👇 This story will not appear in Storybook's sidebar or docs page -->\n<Story\n  name=\"Variant1\"\n  tags={['!dev', '!autodocs']}\n  args={{ variant: 1 }}\n/>\n\n<!-- 👇 This story will not appear in Storybook's sidebar or docs page -->\n<Story\n  name=\"Variant2\"\n  tags={['!dev', '!autodocs']}\n  args={{ variant: 2 }}\n/>\n\n<!-- 👇 This story should not be tested, but will appear in the sidebar and docs page -->\n<Story name=\"Combo\" tags={['!test']}>\n  <Button variant={1}>\n  <Button variant={2}>\n</Story>\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n  });\n</script>\n\n<!-- 👇 This story will not appear in Storybook's sidebar or docs page -->\n<Story\n  name=\"Variant1\"\n  tags={['!dev', '!autodocs']}\n  args={{ variant: 1 }}\n/>\n\n<!-- 👇 This story will not appear in Storybook's sidebar or docs page -->\n<Story\n  name=\"Variant2\"\n  tags={['!dev', '!autodocs']}\n  args={{ variant: 2 }}\n/>\n\n<!-- 👇 This story should not be tested, but will appear in the sidebar and docs page -->\n<Story name=\"Combo\" tags={['!test']}>\n  <Button variant={1} />\n  <Button variant={2} />\n</Story>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.vue';\n\nexport default {\n  component: Button,\n};\n\nexport const Variant1 = {\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 1 },\n};\n\nexport const Variant2 = {\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 2 },\n};\n\nexport const Combo = {\n  // 👇 This story should not be tested, but will appear in the sidebar and docs page\n  tags: ['!test'],\n  render: () => ({\n    components: { Button },\n    template: `\n      <div>\n        <Button :variant=\"1\" />\n        <Button :variant=\"2\" />\n      </div>\n    `,\n  }),\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport Button from './Button.vue';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Variant1: Story = {\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 1 },\n};\n\nexport const Variant2: Story = {\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 2 },\n};\n\nexport const Combo: Story = {\n  // 👇 This story should not be tested, but will appear in the sidebar and docs page\n  tags: ['!test'],\n  render: () => ({\n    components: { Button },\n    template: `\n      <div>\n        <Button :variant=\"1\" />\n        <Button :variant=\"2\" />\n      </div>\n    `,\n  }),\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Variant1 = meta.story({\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 1 },\n});\n\nexport const Variant2 = meta.story({\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 2 },\n});\n\nexport const Combo = meta.story({\n  // 👇 This story should not be tested, but will appear in the sidebar and docs page\n  tags: ['!test'],\n  render: () => ({\n    components: { Button },\n    template: `\n      <div>\n        <Button :variant=\"1\" />\n        <Button :variant=\"2\" />\n      </div>\n    `,\n  }),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Variant1 = meta.story({\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 1 },\n});\n\nexport const Variant2 = meta.story({\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 2 },\n});\n\nexport const Combo = meta.story({\n  // 👇 This story should not be tested, but will appear in the sidebar and docs page\n  tags: ['!test'],\n  render: () => ({\n    components: { Button },\n    template: `\n      <div>\n        <Button :variant=\"1\" />\n        <Button :variant=\"2\" />\n      </div>\n    `,\n  }),\n});\n```\n\n```ts filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nexport default {\n  title: 'Button',\n  component: 'demo-button',\n};\n\nexport const Variant1 = {\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 1 },\n};\n\nexport const Variant2 = {\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 2 },\n};\n\nexport const Combo = {\n  // 👇 This story should not be tested, but will appear in the sidebar and docs page\n  tags: ['!test'],\n  render: () => html`\n    <div>\n      <demo-button variant=\"1\" />\n      <demo-button variant=\"2\" />\n    </div>\n  `,\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nconst meta: Meta = {\n  title: 'Button',\n  component: 'demo-button',\n};\nexport default meta;\n\ntype Story = StoryObj;\n\nexport const Variant1: Story = {\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 1 },\n};\n\nexport const Variant2: Story = {\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 2 },\n};\n\nexport const Combo: Story = {\n  // 👇 This story should not be tested, but will appear in the sidebar and docs page\n  tags: ['!test'],\n  render: () => html`\n    <div>\n      <demo-button variant=\"1\" />\n      <demo-button variant=\"2\" />\n    </div>\n  `,\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  title: 'Button',\n  component: 'demo-button',\n});\n\nexport const Variant1 = meta.story({\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 1 },\n});\n\nexport const Variant2 = meta.story({\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 2 },\n});\n\nexport const Combo = meta.story({\n  // 👇 This story should not be tested, but will appear in the sidebar and docs page\n  tags: ['!test'],\n  render: () => html`\n    <div>\n      <demo-button variant=\"1\" />\n      <demo-button variant=\"2\" />\n    </div>\n  `,\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  title: 'Button',\n  component: 'demo-button',\n});\n\nexport const Variant1 = meta.story({\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 1 },\n});\n\nexport const Variant2 = meta.story({\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 2 },\n});\n\nexport const Combo = meta.story({\n  // 👇 This story should not be tested, but will appear in the sidebar and docs page\n  tags: ['!test'],\n  render: () => html`\n    <div>\n      <demo-button variant=\"1\" />\n      <demo-button variant=\"2\" />\n    </div>\n  `,\n});\n```\n\n```tsx filename=\"Button.stories.tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Variant1 = meta.story({\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 1 },\n});\n\nexport const Variant2 = meta.story({\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 2 },\n});\n\nexport const Combo = meta.story({\n  // 👇 This story should not be tested, but will appear in the sidebar and docs page\n  tags: ['!test'],\n  render: () => (\n    <>\n      <Button variant={1} />\n      <Button variant={2} />\n    </>\n  ),\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"Button.stories.jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n});\n\nexport const Variant1 = meta.story({\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 1 },\n});\n\nexport const Variant2 = meta.story({\n  // 👇 This story will not appear in Storybook's sidebar or docs page\n  tags: ['!dev', '!autodocs'],\n  args: { variant: 2 },\n});\n\nexport const Combo = meta.story({\n  // 👇 This story should not be tested, but will appear in the sidebar and docs page\n  tags: ['!test'],\n  render: () => (\n    <>\n      <Button variant={1} />\n      <Button variant={2} />\n    </>\n  ),\n});\n```\n"
  },
  {
    "path": "docs/_snippets/tags-docs-only-in-meta.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './Button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  /*\n   * All stories in this file will:\n   * - Be included in the docs page\n   * - Not appear in Storybook's sidebar\n   */\n  tags: ['autodocs', '!dev'],\n};\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  /*\n   * All stories in this file will:\n   * - Be included in the docs page\n   * - Not appear in Storybook's sidebar\n   */\n  tags: ['autodocs', '!dev'],\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    /*\n     * All stories in this file will:\n     * - Be included in the docs page\n     * - Not appear in Storybook's sidebar\n     */\n    tags: ['autodocs', '!dev'],\n  });\n</script>\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  /*\n   * All stories in this file will:\n   * - Be included in the docs page\n   * - Not appear in Storybook's sidebar\n   */\n  tags: ['autodocs', '!dev'],\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  /*\n   * All stories in this file will:\n   * - Be included in the docs page\n   * - Not appear in Storybook's sidebar\n   */\n  tags: ['autodocs', '!dev'],\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    /*\n     * All stories in this file will:\n     * - Be included in the docs page\n     * - Not appear in Storybook's sidebar\n     */\n    tags: ['autodocs', '!dev'],\n  });\n</script>\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  /*\n   * All stories in this file will:\n   * - Be included in the docs page\n   * - Not appear in Storybook's sidebar\n   */\n  tags: ['autodocs', '!dev'],\n} satisfies Meta<typeof Button>;\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  /*\n   * All stories in this file will:\n   * - Be included in the docs page\n   * - Not appear in Storybook's sidebar\n   */\n  tags: ['autodocs', '!dev'],\n} satisfies Meta<typeof Button>;\nexport default meta;\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  title: 'Button',\n  component: 'demo-button',\n  /*\n   * All stories in this file will:\n   * - Be included in the docs page\n   * - Not appear in Storybook's sidebar\n   */\n  tags: ['autodocs', '!dev'],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  title: 'Button',\n  component: 'demo-button',\n  /*\n   * All stories in this file will:\n   * - Be included in the docs page\n   * - Not appear in Storybook's sidebar\n   */\n  tags: ['autodocs', '!dev'],\n};\nexport default meta;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  /*\n   * All stories in this file will:\n   * - Be included in the docs page\n   * - Not appear in Storybook's sidebar\n   */\n  tags: ['autodocs', '!dev'],\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  /*\n   * All stories in this file will:\n   * - Be included in the docs page\n   * - Not appear in Storybook's sidebar\n   */\n  tags: ['autodocs', '!dev'],\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  /*\n   * All stories in this file will:\n   * - Be included in the docs page\n   * - Not appear in Storybook's sidebar\n   */\n  tags: ['autodocs', '!dev'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n\n  /*\n   * All stories in this file will:\n   * - Be included in the docs page\n   * - Not appear in Storybook's sidebar\n   */\n  tags: ['autodocs', '!dev'],\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  /*\n   * All stories in this file will:\n   * - Be included in the docs page\n   * - Not appear in Storybook's sidebar\n   */\n  tags: ['autodocs', '!dev'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n\n  /*\n   * All stories in this file will:\n   * - Be included in the docs page\n   * - Not appear in Storybook's sidebar\n   */\n  tags: ['autodocs', '!dev'],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/tags-in-meta-and-story.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './Button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  /*\n   * All stories in this file will have these tags applied:\n   * - autodocs\n   * - dev (implicit default, inherited from preview)\n   * - test (implicit default, inherited from preview)\n   */\n  tags: ['autodocs'],\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const ExperimentalFeatureStory: Story = {\n  /*\n   * This particular story will have these tags applied:\n   * - experimental\n   * - autodocs (inherited from meta)\n   * - dev (inherited from meta)\n   * - test (inherited from meta)\n   */\n  tags: ['experimental'],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  /*\n   * All stories in this file will have these tags applied:\n   * - autodocs\n   * - dev (implicit default, inherited from preview)\n   * - test (implicit default, inherited from preview)\n   */\n  tags: ['autodocs'],\n});\n\nexport const ExperimentalFeatureStory = meta.story({\n  /*\n   * This particular story will have these tags applied:\n   * - experimental\n   * - autodocs (inherited from meta)\n   * - dev (inherited from meta)\n   * - test (inherited from meta)\n   */\n  tags: ['experimental'],\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    /*\n     * All stories in this file will have these tags applied:\n     * - autodocs\n     * - dev (implicit default, inherited from preview)\n     * - test (implicit default, inherited from preview)\n     */\n    tags: ['autodocs'],\n  });\n</script>\n\n<!--\n  This particular story will have these tags applied:\n  - experimental\n  - autodocs (inherited from meta)\n  - dev (inherited from meta)\n  - test (inherited from meta)\n-->\n<Story name=\"ExperimentalFeatureStory\" tags={['experimental']} />\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  /*\n   * All stories in this file will have these tags applied:\n   * - autodocs\n   * - dev (implicit default, inherited from preview)\n   * - test (implicit default, inherited from preview)\n   */\n  tags: ['autodocs'],\n};\n\nexport const ExperimentalFeatureStory = {\n  /*\n   * This particular story will have these tags applied:\n   * - experimental\n   * - autodocs (inherited from meta)\n   * - dev (inherited from meta)\n   * - test (inherited from meta)\n   */\n  tags: ['experimental'],\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  /*\n   * All stories in this file will have these tags applied:\n   * - autodocs\n   * - dev (implicit default, inherited from preview)\n   * - test (implicit default, inherited from preview)\n   */\n  tags: ['autodocs'],\n};\n\nexport const ExperimentalFeatureStory = {\n  /*\n   * This particular story will have these tags applied:\n   * - experimental\n   * - autodocs (inherited from meta)\n   * - dev (inherited from meta)\n   * - test (inherited from meta)\n   */\n  tags: ['experimental'],\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    /*\n     * All stories in this file will have these tags applied:\n     * - autodocs\n     * - dev (implicit default, inherited from preview)\n     * - test (implicit default, inherited from preview)\n     */\n    tags: ['autodocs'],\n  });\n</script>\n\n<!--\n  This particular story will have these tags applied:\n  - experimental\n  - autodocs (inherited from meta)\n  - dev (inherited from meta)\n  - test (inherited from meta)\n-->\n<Story name=\"ExperimentalFeatureStory\" tags={['experimental']} />\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  /*\n   * All stories in this file will have these tags applied:\n   * - autodocs\n   * - dev (implicit default, inherited from preview)\n   * - test (implicit default, inherited from preview)\n   */\n  tags: ['autodocs'],\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ExperimentalFeatureStory: Story = {\n  /*\n   * This particular story will have these tags applied:\n   * - experimental\n   * - autodocs (inherited from meta)\n   * - dev (inherited from meta)\n   * - test (inherited from meta)\n   */\n  tags: ['experimental'],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  /*\n   * All stories in this file will have these tags applied:\n   * - autodocs\n   * - dev (implicit default, inherited from preview)\n   * - test (implicit default, inherited from preview)\n   */\n  tags: ['autodocs'],\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ExperimentalFeatureStory: Story = {\n  /*\n   * This particular story will have these tags applied:\n   * - experimental\n   * - autodocs (inherited from meta)\n   * - dev (inherited from meta)\n   * - test (inherited from meta)\n   */\n  tags: ['experimental'],\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  title: 'Button',\n  component: 'demo-button',\n  /*\n   * All stories in this file will have these tags applied:\n   * - autodocs\n   * - dev (implicit default, inherited from preview)\n   * - test (implicit default, inherited from preview)\n   */\n  tags: ['autodocs'],\n};\n\nexport const ExperimentalFeatureStory = {\n  /*\n   * This particular story will have these tags applied:\n   * - experimental\n   * - autodocs (inherited from meta)\n   * - dev (inherited from meta)\n   * - test (inherited from meta)\n   */\n  tags: ['experimental'],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  title: 'Button',\n  component: 'demo-button',\n  /*\n   * All stories in this file will have these tags applied:\n   *  - autodocs\n   * - dev (implicit default, inherited from preview)\n   * - test (implicit default, inherited from preview)\n   */\n  tags: ['autodocs'],\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const ExperimentalFeatureStory: Story = {\n  /*\n   * This particular story will have these tags applied:\n   * - experimental\n   * - autodocs (inherited from meta)\n   * - dev (inherited from meta)\n   * - test (inherited from meta)\n   */\n  tags: ['experimental'],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  /*\n   * All stories in this file will have these tags applied:\n   * - autodocs\n   * - dev (implicit default, inherited from preview)\n   * - test (implicit default, inherited from preview)\n   */\n  tags: ['autodocs'],\n});\n\nexport const ExperimentalFeatureStory = meta.story({\n  /*\n   * This particular story will have these tags applied:\n   * - experimental\n   * - autodocs (inherited from meta)\n   * - dev (inherited from meta)\n   * - test (inherited from meta)\n   */\n  tags: ['experimental'],\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  /*\n   * All stories in this file will have these tags applied:\n   * - autodocs\n   * - dev (implicit default, inherited from preview)\n   * - test (implicit default, inherited from preview)\n   */\n  tags: ['autodocs'],\n});\n\nexport const ExperimentalFeatureStory = meta.story({\n  /*\n   * This particular story will have these tags applied:\n   * - experimental\n   * - autodocs (inherited from meta)\n   * - dev (inherited from meta)\n   * - test (inherited from meta)\n   */\n  tags: ['experimental'],\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  /*\n   * All stories in this file will have these tags applied:\n   * - autodocs\n   * - dev (implicit default, inherited from preview)\n   * - test (implicit default, inherited from preview)\n   */\n  tags: ['autodocs'],\n});\n\nexport const ExperimentalFeatureStory = meta.story({\n  /*\n   * This particular story will have these tags applied:\n   * - experimental\n   * - autodocs (inherited from meta)\n   * - dev (inherited from meta)\n   * - test (inherited from meta)\n   */\n  tags: ['experimental'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n\n  /*\n   * All stories in this file will have these tags applied:\n   * - autodocs\n   * - dev (implicit default, inherited from preview)\n   * - test (implicit default, inherited from preview)\n   */\n  tags: ['autodocs'],\n});\n\nexport const ExperimentalFeatureStory = meta.story({\n  /*\n   * This particular story will have these tags applied:\n   * - experimental\n   * - autodocs (inherited from meta)\n   * - dev (inherited from meta)\n   * - test (inherited from meta)\n   */\n  tags: ['experimental'],\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  /*\n   * All stories in this file will have these tags applied:\n   * - autodocs\n   * - dev (implicit default, inherited from preview)\n   * - test (implicit default, inherited from preview)\n   */\n  tags: ['autodocs'],\n});\n\nexport const ExperimentalFeatureStory = meta.story({\n  /*\n   * This particular story will have these tags applied:\n   * - experimental\n   * - autodocs (inherited from meta)\n   * - dev (inherited from meta)\n   * - test (inherited from meta)\n   */\n  tags: ['experimental'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n\n  /*\n   * All stories in this file will have these tags applied:\n   * - autodocs\n   * - dev (implicit default, inherited from preview)\n   * - test (implicit default, inherited from preview)\n   */\n  tags: ['autodocs'],\n});\n\nexport const ExperimentalFeatureStory = meta.story({\n  /*\n   * This particular story will have these tags applied:\n   * - experimental\n   * - autodocs (inherited from meta)\n   * - dev (inherited from meta)\n   * - test (inherited from meta)\n   */\n  tags: ['experimental'],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/tags-in-preview.md",
    "content": "```js filename=\".storybook/preview.js\" renderer=\"common\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  /*\n   * All stories in your project will have these tags applied:\n   * - autodocs\n   * - dev (implicit default)\n   * - test (implicit default)\n   */\n  tags: ['autodocs'],\n};\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Preview } from '@storybook/your-framework';\n\nconst preview: Preview = {\n  /*\n   * All stories in your project will have these tags applied:\n   * - autodocs\n   * - dev (implicit default)\n   * - test (implicit default)\n   */\n  tags: ['autodocs'],\n};\n\nexport default preview;\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  /*\n   * All stories in your project will have these tags applied:\n   * - autodocs\n   * - dev (implicit default)\n   * - test (implicit default)\n   */\n  tags: ['autodocs'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  /*\n   * All stories in your project will have these tags applied:\n   * - autodocs\n   * - dev (implicit default)\n   * - test (implicit default)\n   */\n  tags: ['autodocs'],\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  /*\n   * All stories in your project will have these tags applied:\n   * - autodocs\n   * - dev (implicit default)\n   * - test (implicit default)\n   */\n  tags: ['autodocs'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/vue3-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  /*\n   * All stories in your project will have these tags applied:\n   * - autodocs\n   * - dev (implicit default)\n   * - test (implicit default)\n   */\n  tags: ['autodocs'],\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/angular';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  /*\n   * All stories in your project will have these tags applied:\n   * - autodocs\n   * - dev (implicit default)\n   * - test (implicit default)\n   */\n  tags: ['autodocs'],\n});\n```\n\n```ts filename=\".storybook/preview.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  /*\n   * All stories in your project will have these tags applied:\n   * - autodocs\n   * - dev (implicit default)\n   * - test (implicit default)\n   */\n  tags: ['autodocs'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/preview.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { definePreview } from '@storybook/web-components-vite';\nimport addonDocs from '@storybook/addon-docs';\n\nexport default definePreview({\n  addons: [addonDocs()],\n  /*\n   * All stories in your project will have these tags applied:\n   * - autodocs\n   * - dev (implicit default)\n   * - test (implicit default)\n   */\n  tags: ['autodocs'],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/tags-remove-in-story.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n  // 👇 Applies to all stories in this file\n  tags: ['stable'],\n};\n\nexport default meta;\ntype Story = StoryObj<Button>;\n\nexport const ExperimentalFeatureStory: Story = {\n  //👇 For this particular story, remove the inherited `stable` tag and apply the `experimental` tag\n  tags: ['!stable', 'experimental'],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './button.component';\n\nconst meta = preview.meta({\n  component: Button,\n  // 👇 Applies to all stories in this file\n  tags: ['stable'],\n});\n\nexport const ExperimentalFeatureStory = meta.story({\n  //👇 For this particular story, remove the inherited `stable` tag and apply the `experimental` tag\n  tags: ['!stable', 'experimental'],\n});\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    // 👇 Applies to all stories in this file\n    tags: ['stable'],\n  });\n</script>\n\n<!-- 👇 For this particular story, remove the inherited `stable` tag and apply the `experimental` tag -->\n<Story name=\"ExperimentalFeatureStory\" tags={['!stable', 'experimental']} />\n```\n\n```js filename=\"Button.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.svelte';\n\nexport default {\n  component: Button,\n  // 👇 Applies to all stories in this file\n  tags: ['stable'],\n};\n\nexport const ExperimentalFeatureStory = {\n  //👇 For this particular story, remove the inherited `stable` tag and apply the `experimental` tag\n  tags: ['!stable', 'experimental'],\n};\n```\n\n```svelte filename=\"Button.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    // 👇 Applies to all stories in this file\n    tags: ['stable'],\n  });\n</script>\n\n<!-- 👇 For this particular story, remove the inherited `stable` tag and apply the `experimental` tag -->\n<Story name=\"ExperimentalFeatureStory\" tags={['!stable', 'experimental']} />\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  component: Button,\n  // 👇 Applies to all stories in this file\n  tags: ['stable'],\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ExperimentalFeatureStory: Story = {\n  //👇 For this particular story, remove the inherited `stable` tag and apply the `experimental` tag\n  tags: ['!stable', 'experimental'],\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  title: 'Button',\n  component: 'demo-button',\n  // 👇 Applies to all stories in this file\n  tags: ['stable'],\n};\n\nexport const ExperimentalFeatureStory = {\n  //👇 For this particular story, remove the inherited `stable` tag and apply the `experimental` tag\n  tags: ['!stable', 'experimental'],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  title: 'Button',\n  component: 'demo-button',\n  // 👇 Applies to all stories in this file\n  tags: ['stable'],\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const ExperimentalFeatureStory: Story = {\n  //👇 For this particular story, remove the inherited `stable` tag and apply the `experimental` tag\n  tags: ['!stable', 'experimental'],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  // 👇 Applies to all stories in this file\n  tags: ['stable'],\n});\n\nexport const ExperimentalFeatureStory = meta.story({\n  //👇 For this particular story, remove the inherited `stable` tag and apply the `experimental` tag\n  tags: ['!stable', 'experimental'],\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-button',\n  // 👇 Applies to all stories in this file\n  tags: ['stable'],\n});\n\nexport const ExperimentalFeatureStory = meta.story({\n  //👇 For this particular story, remove the inherited `stable` tag and apply the `experimental` tag\n  tags: ['!stable', 'experimental'],\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n  // 👇 Applies to all stories in this file\n  tags: ['stable'],\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ExperimentalFeatureStory: Story = {\n  //👇 For this particular story, remove the inherited `stable` tag and apply the `experimental` tag\n  tags: ['!stable', 'experimental'],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  // 👇 Applies to all stories in this file\n  tags: ['stable'],\n});\n\nexport const ExperimentalFeatureStory = meta.story({\n  //👇 For this particular story, remove the inherited `stable` tag and apply the `experimental` tag\n  tags: ['!stable', 'experimental'],\n});\n```\n\n```js filename=\"Button.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n  // 👇 Applies to all stories in this file\n  tags: ['stable'],\n};\n\nexport const ExperimentalFeatureStory = {\n  //👇 For this particular story, remove the inherited `stable` tag and apply the `experimental` tag\n  tags: ['!stable', 'experimental'],\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  // 👇 Applies to all stories in this file\n  tags: ['stable'],\n});\n\nexport const ExperimentalFeatureStory = meta.story({\n  //👇 For this particular story, remove the inherited `stable` tag and apply the `experimental` tag\n  tags: ['!stable', 'experimental'],\n});\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport Button from './Button.vue';\n\nconst meta = {\n  component: Button,\n  // 👇 Applies to all stories in this file\n  tags: ['stable'],\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const ExperimentalFeatureStory: Story = {\n  //👇 For this particular story, remove the inherited `stable` tag and apply the `experimental` tag\n  tags: ['!stable', 'experimental'],\n};\n```\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport Button from './Button.vue';\n\nexport default {\n  component: Button,\n  // 👇 Applies to all stories in this file\n  tags: ['stable'],\n};\n\nexport const ExperimentalFeatureStory = {\n  //👇 For this particular story, remove the inherited `stable` tag and apply the `experimental` tag\n  tags: ['!stable', 'experimental'],\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  // 👇 Applies to all stories in this file\n  tags: ['stable'],\n});\n\nexport const ExperimentalFeatureStory = meta.story({\n  //👇 For this particular story, remove the inherited `stable` tag and apply the `experimental` tag\n  tags: ['!stable', 'experimental'],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"Button.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport Button from './Button.vue';\n\nconst meta = preview.meta({\n  component: Button,\n  // 👇 Applies to all stories in this file\n  tags: ['stable'],\n});\n\nexport const ExperimentalFeatureStory = meta.story({\n  //👇 For this particular story, remove the inherited `stable` tag and apply the `experimental` tag\n  tags: ['!stable', 'experimental'],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-a11y-config.md",
    "content": "```js filename=\".storybook/test-runner.js\" renderer=\"common\" language=\"js\"\nconst { injectAxe, checkA11y } = require('axe-playwright');\n\n/*\n * See https://storybook.js.org/docs/writing-tests/integrations/test-runner#test-hook-api\n * to learn more about the test-runner hooks API.\n */\nmodule.exports = {\n  async preVisit(page) {\n    await injectAxe(page);\n  },\n  async postVisit(page) {\n    await checkA11y(page, 'body', {\n      detailedReport: true,\n      detailedReportOptions: {\n        html: true,\n      },\n    });\n  },\n};\n```\n\n```ts filename=\".storybook/test-runner.ts\" renderer=\"common\" language=\"ts\"\nimport type { TestRunnerConfig } from '@storybook/test-runner';\nimport { injectAxe, checkA11y } from 'axe-playwright';\n\n/*\n * See https://storybook.js.org/docs/writing-tests/integrations/test-runner#test-hook-api\n * to learn more about the test-runner hooks API.\n */\nconst config: TestRunnerConfig = {\n  async preVisit(page) {\n    await injectAxe(page);\n  },\n  async postVisit(page) {\n    await checkA11y(page, 'body', {\n      detailedReport: true,\n      detailedReportOptions: {\n        html: true,\n      },\n    });\n  },\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-a11y-configure.md",
    "content": "```js filename=\".storybook/test-runner.js\" renderer=\"common\" language=\"js\"\nconst { injectAxe, checkA11y, configureAxe } = require('axe-playwright');\n\nconst { getStoryContext } = require('@storybook/test-runner');\n\n/*\n * See https://storybook.js.org/docs/writing-tests/integrations/test-runner#test-hook-api\n * to learn more about the test-runner hooks API.\n */\nmodule.exports = {\n  async preVisit(page) {\n    await injectAxe(page);\n  },\n  async postVisit(page, context) {\n    // Get the entire context of a story, including parameters, args, argTypes, etc.\n    const storyContext = await getStoryContext(page, context);\n\n    // Apply story-level a11y rules\n    await configureAxe(page, {\n      rules: storyContext.parameters?.a11y?.config?.rules,\n    });\n\n    const element = storyContext.parameters?.a11y?.element ?? 'body';\n    await checkA11y(page, element, {\n      detailedReport: true,\n      detailedReportOptions: {\n        html: true,\n      },\n    });\n  },\n};\n```\n\n```ts filename=\".storybook/test-runner.ts\" renderer=\"common\" language=\"ts\"\nimport type { TestRunnerConfig } from '@storybook/test-runner';\nimport { getStoryContext } from '@storybook/test-runner';\n\nimport { injectAxe, checkA11y, configureAxe } from 'axe-playwright';\n\n/*\n * See https://storybook.js.org/docs/writing-tests/integrations/test-runner#test-hook-api\n * to learn more about the test-runner hooks API.\n */\nconst config: TestRunnerConfig = {\n  async preVisit(page) {\n    await injectAxe(page);\n  },\n  async postVisit(page, context) {\n    // Get the entire context of a story, including parameters, args, argTypes, etc.\n    const storyContext = await getStoryContext(page, context);\n\n    // Apply story-level a11y rules\n    await configureAxe(page, {\n      rules: storyContext.parameters?.a11y?.config?.rules,\n    });\n\n    const element = storyContext.parameters?.a11y?.element ?? 'body';\n    await checkA11y(page, element, {\n      detailedReport: true,\n      detailedReportOptions: {\n        html: true,\n      },\n    });\n  },\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-a11y-disable.md",
    "content": "```js filename=\".storybook/test-runner.js\" renderer=\"common\" language=\"js\"\nconst { getStoryContext } = require('@storybook/test-runner');\n\nconst { injectAxe, checkA11y } = require('axe-playwright');\n/*\n * See https://storybook.js.org/docs/writing-tests/integrations/test-runner#test-hook-api\n * to learn more about the test-runner hooks API.\n */\nmodule.exports = {\n  async preVisit(page) {\n    await injectAxe(page);\n  },\n  async postVisit(page, context) {\n    // Get the entire context of a story, including parameters, args, argTypes, etc.\n    const storyContext = await getStoryContext(page, context);\n\n    // Do not run a11y tests on disabled stories.\n    if (storyContext.parameters?.a11y?.disable) {\n      return;\n    }\n    await checkA11y(page, 'body', {\n      detailedReport: true,\n      detailedReportOptions: {\n        html: true,\n      },\n    });\n  },\n};\n```\n\n```ts filename=\".storybook/test-runner.ts\" renderer=\"common\" language=\"ts\"\nimport type { TestRunnerConfig } from '@storybook/test-runner';\nimport { getStoryContext } from '@storybook/test-runner';\n\nimport { injectAxe, checkA11y } from 'axe-playwright';\n\n/*\n * See https://storybook.js.org/docs/writing-tests/integrations/test-runner#test-hook-api\n * to learn more about the test-runner hooks API.\n */\nconst config: TestRunnerConfig = {\n  async preVisit(page) {\n    await injectAxe(page);\n  },\n  async postVisit(page, context) {\n    // Get the entire context of a story, including parameters, args, argTypes, etc.\n    const storyContext = await getStoryContext(page, context);\n\n    // Do not run a11y tests on disabled stories.\n    if (storyContext.parameters?.a11y?.disable) {\n      return;\n    }\n    await checkA11y(page, 'body', {\n      detailedReport: true,\n      detailedReportOptions: {\n        html: true,\n      },\n    });\n  },\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-auth.md",
    "content": "```js filename=\".storybook/test-runner.js\" renderer=\"common\" language=\"js\"\nmodule.exports = {\n  getHttpHeaders: async (url) => {\n    const token = url.includes('prod') ? 'XYZ' : 'ABC';\n    return {\n      Authorization: `Bearer ${token}`,\n    };\n  },\n};\n```\n\n```ts filename=\".storybook/test-runner.ts\" renderer=\"common\" language=\"ts\"\nimport type { TestRunnerConfig } from '@storybook/test-runner';\n\nconst config: TestRunnerConfig = {\n  getHttpHeaders: async (url) => {\n    const token = url.includes('prod') ? 'prod-token' : 'dev-token';\n    return {\n      Authorization: `Bearer ${token}`,\n    };\n  },\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-axe-playwright.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm install axe-playwright --save-dev\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm add --save-dev axe-playwright\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn add --dev axe-playwright\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-config-serializer.md",
    "content": "```js filename=\"./test-runner-jest.config.js\" renderer=\"common\" language=\"js\"\nimport { getJestConfig } from '@storybook/test-runner';\n\nconst defaultConfig = getJestConfig();\n\nconst config = {\n  ...defaultConfig,\n  snapshotSerializers: [\n    // Sets up the custom serializer to preprocess the HTML before it's passed onto the test-runner\n    './snapshot-serializer.js',\n    ...defaultConfig.snapshotSerializers,\n  ],\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-config-snapshot-resolver.md",
    "content": "```js filename=\"./test-runner-jest.config.js\" renderer=\"common\" language=\"js\"\nimport { getJestConfig } from '@storybook/test-runner';\n\nconst defaultConfig = getJestConfig();\n\nconst config = {\n  // The default Jest configuration comes from @storybook/test-runner\n  ...defaultConfig,\n  snapshotResolver: './snapshot-resolver.js',\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-coverage.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm run test-storybook -- --coverage\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm run test-storybook --coverage\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn test-storybook --coverage\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-custom-page-viewport.md",
    "content": "```js filename=\".storybook/test-runner.js\" renderer=\"common\" language=\"js\"\nconst { getStoryContext } = require('@storybook/test-runner');\nconst { MINIMAL_VIEWPORTS } = require('storybook/viewport');\n\nconst DEFAULT_VIEWPORT_SIZE = { width: 1280, height: 720 };\n\nmodule.exports = {\n  async preVisit(page, story) {\n    // Accesses the story's parameters and retrieves the viewport used to render it\n    const context = await getStoryContext(page, story);\n    const viewportName = context.parameters?.viewport?.defaultViewport;\n    const viewportParameter = MINIMAL_VIEWPORTS[viewportName];\n\n    if (viewportParameter) {\n      const viewportSize = Object.entries(viewportParameter.styles).reduce(\n        (acc, [screen, size]) => ({\n          ...acc,\n          // Converts the viewport size from percentages to numbers\n          [screen]: parseInt(size),\n        }),\n        {},\n      );\n      // Configures the Playwright page to use the viewport size\n      page.setViewportSize(viewportSize);\n    } else {\n      page.setViewportSize(DEFAULT_VIEWPORT_SIZE);\n    }\n  },\n};\n```\n\n```ts filename=\".storybook/test-runner.ts\" renderer=\"common\" language=\"ts\"\nimport type { TestRunnerConfig } from '@storybook/test-runner';\nimport { getStoryContext } from '@storybook/test-runner';\nimport { MINIMAL_VIEWPORTS } from 'storybook/viewport';\n\nconst DEFAULT_VIEWPORT_SIZE = { width: 1280, height: 720 };\n\nconst config: TestRunnerConfig = {\n  async preVisit(page, story) {\n    // Accesses the story's parameters and retrieves the viewport used to render it\n    const context = await getStoryContext(page, story);\n    const viewportName = context.parameters?.viewport?.defaultViewport;\n    const viewportParameter = MINIMAL_VIEWPORTS[viewportName];\n\n    if (viewportParameter) {\n      const viewportSize = Object.entries(viewportParameter.styles).reduce(\n        (acc, [screen, size]) => ({\n          ...acc,\n          // Converts the viewport size from percentages to numbers\n          [screen]: parseInt(size),\n        }),\n        {},\n      );\n      // Configures the Playwright page to use the viewport size\n      page.setViewportSize(viewportSize);\n    } else {\n      page.setViewportSize(DEFAULT_VIEWPORT_SIZE);\n    }\n  },\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-custom-snapshot-resolver.md",
    "content": "```js filename=\"./snapshot-resolver.js\" renderer=\"common\" language=\"js\"\nimport path from 'path';\n\nexport default {\n  resolveSnapshotPath: (testPath) => {\n    const fileName = path.basename(testPath);\n    const fileNameWithoutExtension = fileName.replace(/\\.[^/.]+$/, '');\n    const modifiedFileName = `${fileNameWithoutExtension}.storyshot`;\n\n    // Configure Jest to generate snapshot files using the following naming convention (__snapshots__/Button.storyshot)\n    return path.join(path.dirname(testPath), '__snapshots__', modifiedFileName);\n  },\n  resolveTestPath: (snapshotFilePath, snapshotExtension) =>\n    path.basename(snapshotFilePath, snapshotExtension),\n  testPathForConsistencyCheck: 'example.storyshot',\n};\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-custom-snapshot-serializer.md",
    "content": "```js filename=\"./snapshot-serializer.js\" renderer=\"common\" language=\"js\"\n// The jest-serializer-html package is available as a dependency of the test-runner\nconst jestSerializerHtml = require('jest-serializer-html');\n\nconst DYNAMIC_ID_PATTERN = /\"react-aria-\\d+(\\.\\d+)?\"/g;\n\nmodule.exports = {\n  /*\n   * The test-runner calls the serialize function when the test reaches the expect(SomeHTMLElement).toMatchSnapshot().\n   * It will replace all dynamic IDs with a static ID so that the snapshot is consistent.\n   * For instance, from <label id=\"react-aria970235672-:rl:\" for=\"react-aria970235672-:rk:\">Favorite color</label> to <label id=\"react-mocked_id\" for=\"react-mocked_id\">Favorite color</label>\n   */\n  serialize(val) {\n    const withFixedIds = val.replace(DYNAMIC_ID_PATTERN, 'mocked_id');\n    return jestSerializerHtml.print(withFixedIds);\n  },\n  test(val) {\n    return jestSerializerHtml.test(val);\n  },\n};\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-dom-snapshot-testing.md",
    "content": "```js filename=\".storybook/test-runner.js\" renderer=\"common\" language=\"js\"\nmodule.exports = {\n  async postVisit(page, context) {\n    // the #storybook-root element wraps the story. In Storybook 6.x, the selector is #root\n    const elementHandler = await page.$('#storybook-root');\n    const innerHTML = await elementHandler.innerHTML();\n    expect(innerHTML).toMatchSnapshot();\n  },\n};\n```\n\n```ts filename=\".storybook/test-runner.ts\" renderer=\"common\" language=\"ts\"\nimport type { TestRunnerConfig } from '@storybook/test-runner';\n\nconst config: TestRunnerConfig = {\n  async postVisit(page, context) {\n    // the #storybook-root element wraps the story. In Storybook 6.x, the selector is #root\n    const elementHandler = await page.$('#storybook-root');\n    const innerHTML = await elementHandler.innerHTML();\n    expect(innerHTML).toMatchSnapshot();\n  },\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-eject-config.md",
    "content": "```sh renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm run test-storybook -- --eject\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm run test-storybook --eject\n```\n\n```sh renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn test-storybook --eject\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-execute-with-flags.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm run test-storybook -- --watch\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm run test-storybook --watch\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn test-storybook --watch\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-execute-with-url.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm run test-storybook -- --url https://the-storybook-url-here.com\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm run test-storybook  --url https://the-storybook-url-here.com\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn test-storybook --url https://the-storybook-url-here.com\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-execute.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm run test-storybook\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm run test-storybook\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn test-storybook\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-helper-function.md",
    "content": "```js filename=\".storybook/test-runner.js\" renderer=\"common\" language=\"js\"\nconst { getStoryContext, waitForPageReady } = require('@storybook/test-runner');\n\nmodule.exports = {\n  // Hook that is executed before the test runner starts running tests\n  setup() {\n    // Add your configuration here.\n  },\n  /* Hook to execute before a story is initially visited before being rendered in the browser.\n   * The page argument is the Playwright's page object for the story.\n   * The context argument is a Storybook object containing the story's id, title, and name.\n   */\n  async preVisit(page, context) {\n    // Add your configuration here.\n  },\n  /* Hook to execute after a story is visited and fully rendered.\n   * The page argument is the Playwright's page object for the story\n   * The context argument is a Storybook object containing the story's id, title, and name.\n   */\n  async postVisit(page, context) {\n    // Get the entire context of a story, including parameters, args, argTypes, etc.\n    const storyContext = await getStoryContext(page, context);\n\n    // This utility function is designed for image snapshot testing. It will wait for the page to be fully loaded, including all the async items (e.g., images, fonts, etc.).\n    await waitForPageReady(page);\n\n    // Add your configuration here.\n  },\n};\n```\n\n```ts filename=\".storybook/test-runner.ts\" renderer=\"common\" language=\"ts\"\nimport type { TestRunnerConfig } from '@storybook/test-runner';\nimport { getStoryContext, waitForPageReady } from '@storybook/test-runner';\n\nconst config: TestRunnerConfig = {\n  // Hook that is executed before the test runner starts running tests\n  setup() {\n    // Add your configuration here.\n  },\n  /* Hook to execute before a story is initially visited before being rendered in the browser.\n   * The page argument is the Playwright's page object for the story.\n   * The context argument is a Storybook object containing the story's id, title, and name.\n   */\n  async preVisit(page, context) {\n    // Add your configuration here.\n  },\n  /* Hook to execute after a story is visited and fully rendered.\n   * The page argument is the Playwright's page object for the story\n   * The context argument is a Storybook object containing the story's id, title, and name.\n   */\n  async postVisit(page, context) {\n    // Get the entire context of a story, including parameters, args, argTypes, etc.\n    const storyContext = await getStoryContext(page, context);\n\n    // This utility function is designed for image snapshot testing. It will wait for the page to be fully loaded, including all the async items (e.g., images, fonts, etc.).\n    await waitForPageReady(page);\n\n    // Add your configuration here.\n  },\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-hooks-example.md",
    "content": "```js filename=\".storybook/test-runner.js\" renderer=\"common\" language=\"js\"\nmodule.exports = {\n  // Hook that is executed before the test runner starts running tests\n  setup() {\n    // Add your configuration here.\n  },\n  /* Hook to execute before a story is initially visited before being rendered in the browser.\n   * The page argument is the Playwright's page object for the story.\n   * The context argument is a Storybook object containing the story's id, title, and name.\n   */\n  async preVisit(page, context) {\n    // Add your configuration here.\n  },\n  /* Hook to execute after a story is visited and fully rendered.\n   * The page argument is the Playwright's page object for the story\n   * The context argument is a Storybook object containing the story's id, title, and name.\n   */\n  async postVisit(page, context) {\n    // Add your configuration here.\n  },\n};\n```\n\n```ts filename=\".storybook/test-runner.ts\" renderer=\"common\" language=\"ts\"\nimport type { TestRunnerConfig } from '@storybook/test-runner';\n\nconst config: TestRunnerConfig = {\n  // Hook that is executed before the test runner starts running tests\n  setup() {\n    // Add your configuration here.\n  },\n  /* Hook to execute before a story is initially visited before being rendered in the browser.\n   * The page argument is the Playwright's page object for the story.\n   * The context argument is a Storybook object containing the story's id, title, and name.\n   */\n  async preVisit(page, context) {\n    // Add your configuration here.\n  },\n  /* Hook to execute after a story is visited and fully rendered.\n   * The page argument is the Playwright's page object for the story\n   * The context argument is a Storybook object containing the story's id, title, and name.\n   */\n  async postVisit(page, context) {\n    // Add your configuration here.\n  },\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-image-snapshot-testing.md",
    "content": "```js filename=\".storybook/test-runner.js\" renderer=\"common\" language=\"js\"\nconst { waitForPageReady } = require('@storybook/test-runner');\n\nconst { toMatchImageSnapshot } = require('jest-image-snapshot');\n\nconst customSnapshotsDir = `${process.cwd()}/__snapshots__`;\n\n/** @type { import('@storybook/test-runner').TestRunnerConfig } */\nmodule.exports = {\n  setup() {\n    expect.extend({ toMatchImageSnapshot });\n  },\n  async postVisit(page, context) {\n    // Waits for the page to be ready before taking a screenshot to ensure consistent results\n    await waitForPageReady(page);\n\n    // To capture a screenshot for different browsers, add page.context().browser().browserType().name() to get the browser name to prefix the file name\n    const image = await page.screenshot();\n    expect(image).toMatchImageSnapshot({\n      customSnapshotsDir,\n      customSnapshotIdentifier: context.id,\n    });\n  },\n};\n```\n\n```ts filename=\".storybook/test-runner.ts\" renderer=\"common\" language=\"ts\"\nimport { TestRunnerConfig, waitForPageReady } from '@storybook/test-runner';\n\nimport { toMatchImageSnapshot } from 'jest-image-snapshot';\n\nconst customSnapshotsDir = `${process.cwd()}/__snapshots__`;\n\nconst config: TestRunnerConfig = {\n  setup() {\n    expect.extend({ toMatchImageSnapshot });\n  },\n  async postVisit(page, context) {\n    // Waits for the page to be ready before taking a screenshot to ensure consistent results\n    await waitForPageReady(page);\n\n    // To capture a screenshot for for different browsers, add page.context().browser().browserType().name() to get the browser name to prefix the file name\n    const image = await page.screenshot();\n    expect(image).toMatchImageSnapshot({\n      customSnapshotsDir,\n      customSnapshotIdentifier: context.id,\n    });\n  },\n};\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-install.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm install @storybook/test-runner --save-dev\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm add --save-dev @storybook/test-runner\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn add --dev @storybook/test-runner\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-local-build-workflow.md",
    "content": "```yml filename=\".github/workflows/storybook-tests.yml\" renderer=\"common\" language=\"ts\" tabTitle=\"yml\"\nname: 'Storybook Tests'\n\non: push\n\njobs:\n  test:\n    timeout-minutes: 60\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-node@v4\n        with:\n          node-version-file: '.nvmrc'\n      - name: Install dependencies\n        run: yarn\n      - name: Install Playwright\n        run: npx playwright install --with-deps\n      - name: Build Storybook\n        run: yarn build-storybook --quiet\n      - name: Serve Storybook and run tests\n        run: |\n          npx concurrently -k -s first -n \"SB,TEST\" -c \"magenta,blue\" \\\n            \"npx http-server storybook-static --port 6006 --silent\" \\\n            \"npx wait-on tcp:127.0.0.1:6006 && yarn test-storybook\"\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-no-index-json.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm run test-storybook -- --no-index-json\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm run test-storybook --no-index-json\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn test-storybook --no-index-json\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-snapshot-resolver-custom-directory.md",
    "content": "```js filename=\"./snapshot-resolver.js\" renderer=\"common\" language=\"js\"\nimport path from 'path';\n\nexport default {\n  resolveSnapshotPath: (testPath) => {\n    const fileName = path.basename(testPath);\n    const fileNameWithoutExtension = fileName.replace(/\\.[^/.]+$/, '');\n    // Defines the file extension for the snapshot file\n    const modifiedFileName = `${fileNameWithoutExtension}.snap`;\n\n    // Configure Jest to generate snapshot files using the following convention (./src/test/__snapshots__/Button.stories.snap)\n    return path.join('./src/test/__snapshots__', modifiedFileName);\n  },\n  resolveTestPath: (snapshotFilePath, snapshotExtension) =>\n    path.basename(snapshotFilePath, snapshotExtension),\n  testPathForConsistencyCheck: 'example',\n};\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-tags-config.md",
    "content": "```js filename=\".storybook/test-runner.js\" renderer=\"common\" language=\"js\"\nmodule.exports = {\n  tags: {\n    include: ['test-only', 'pages'],\n    exclude: ['no-tests', 'tokens'],\n    skip: ['skip-test', 'layout'],\n  },\n};\n```\n\n```ts filename=\".storybook/test-runner.ts\" renderer=\"common\" language=\"ts\"\nimport type { TestRunnerConfig } from '@storybook/test-runner';\n\nconst config: TestRunnerConfig = {\n  tags: {\n    include: ['test-only', 'pages'],\n    exclude: ['no-tests', 'tokens'],\n    skip: ['skip-test', 'layout'],\n  },\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-tags-exclude.md",
    "content": "```js filename=\".storybook/test-runner.js\" renderer=\"common\" language=\"js\" tabTitle=\"config\"\nmodule.exports = {\n  tags: {\n    exclude: ['no-tests'],\n  },\n};\n```\n\n```ts filename=\".storybook/test-runner.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"config\"\nimport type { TestRunnerConfig } from '@storybook/test-runner';\n\nconst config: TestRunnerConfig = {\n  tags: {\n    exclude: ['no-tests'],\n  },\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-tags-include.md",
    "content": "```js filename=\".storybook/test-runner.js\" renderer=\"common\" language=\"js\" tabTitle=\"config\"\nmodule.exports = {\n  tags: {\n    include: ['test-only'],\n  },\n};\n```\n\n```ts filename=\".storybook/test-runner.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"config\"\nimport type { TestRunnerConfig } from '@storybook/test-runner';\n\nconst config: TestRunnerConfig = {\n  tags: {\n    include: ['test-only'],\n  },\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-tags-skip.md",
    "content": "```js filename=\".storybook/test-runner.js\" renderer=\"common\" language=\"js\" tabTitle=\"config\"\nmodule.exports = {\n  tags: {\n    skip: ['skip-test'],\n  },\n};\n```\n\n```ts filename=\".storybook/test-runner.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"config\"\nimport type { TestRunnerConfig } from '@storybook/test-runner';\n\nconst config: TestRunnerConfig = {\n  tags: {\n    skip: ['skip-test'],\n  },\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-waitpageready.md",
    "content": "```js filename=\".storybook/test-runner.js\" renderer=\"common\" language=\"js\"\nconst { waitForPageReady } = require('@storybook/test-runner');\n\nconst { toMatchImageSnapshot } = require('jest-image-snapshot');\n\nconst customSnapshotsDir = `${process.cwd()}/__snapshots__`;\n\nmodule.exports = {\n  setup() {\n    expect.extend({ toMatchImageSnapshot });\n  },\n  async postVisit(page, context) {\n    // Awaits for the page to be loaded and available including assets (e.g., fonts)\n    await waitForPageReady(page);\n\n    // Generates a snapshot file based on the story identifier\n    const image = await page.screenshot();\n    expect(image).toMatchImageSnapshot({\n      customSnapshotsDir,\n      customSnapshotIdentifier: context.id,\n    });\n  },\n};\n```\n\n```ts filename=\".storybook/test-runner.ts\" renderer=\"common\" language=\"ts\"\nimport type { TestRunnerConfig } from '@storybook/test-runner';\n\nimport { waitForPageReady } from '@storybook/test-runner';\n\nimport { toMatchImageSnapshot } from 'jest-image-snapshot';\n\nconst customSnapshotsDir = `${process.cwd()}/__snapshots__`;\n\nconst config: TestRunnerConfig = {\n  setup() {\n    expect.extend({ toMatchImageSnapshot });\n  },\n  async postVisit(page, context) {\n    // Awaits for the page to be loaded and available including assets (e.g., fonts)\n    await waitForPageReady(page);\n\n    // Generates a snapshot file based on the story identifier\n    const image = await page.screenshot();\n    expect(image).toMatchImageSnapshot({\n      customSnapshotsDir,\n      customSnapshotIdentifier: context.id,\n    });\n  },\n};\n\nexport default config;\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-with-deploy-event-workflow.md",
    "content": "```yml filename=\".github/workflows/storybook-tests.yml\" renderer=\"common\" language=\"ts\" tabTitle=\"yml\"\nname: Storybook Tests\n\non: deployment_status\n\njobs:\n  test:\n    timeout-minutes: 60\n    runs-on: ubuntu-latest\n    if: github.event.deployment_status.state == 'success'\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-node@v4\n        with:\n          node-version-file: '.nvmrc'\n      - name: Install dependencies\n        run: yarn\n      - name: Install Playwright\n        run: npx playwright install --with-deps\n      - name: Run Storybook tests\n        run: yarn test-storybook\n        env:\n          TARGET_URL: '${{ github.event.deployment_status.target_url }}'\n```\n"
  },
  {
    "path": "docs/_snippets/test-runner-with-index-json.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm run test-storybook -- --index-json\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm run test-storybook --index-json\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn test-storybook --index-json\n```\n"
  },
  {
    "path": "docs/_snippets/typed-csf-file.md",
    "content": "```ts filename=\"Button.stories.ts\" renderer=\"angular\" language=\"ts\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { Button } from './button.component';\n\nconst meta: Meta<Button> = {\n  component: Button,\n};\nexport default meta;\n\ntype Story = StoryObj<Button>;\n\nexport const Basic: Story = {};\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n  },\n};\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"common\" language=\"ts\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\nconst meta = {\n  component: Button,\n} satisfies Meta<typeof Button>;\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic = {} satisfies Story;\n\nexport const Primary = {\n  args: {\n    primary: true,\n  },\n} satisfies Story;\n```\n\n```ts filename=\"Button.stories.ts\" renderer=\"web-components\" language=\"ts\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\nconst meta: Meta = {\n  title: 'Button',\n  component: 'demo-button',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Basic: Story = {};\n\nexport const Primary: Story = {\n  args: {\n    primary: true,\n  },\n};\n```\n"
  },
  {
    "path": "docs/_snippets/upgrade-command-specific-version.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpx storybook@7.6.6 upgrade\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm dlx storybook@7.6.6 upgrade\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn dlx storybook@7.6.6 upgrade\n```\n"
  },
  {
    "path": "docs/_snippets/vite-includeStorybookNextjsPlugin.md",
    "content": "```ts filename=\"vitest.config.ts\" renderer=\"react\" language=\"ts\"\nimport { defineConfig } from 'vite';\nimport { storybookNextJsPlugin } from '@storybook/nextjs-vite/vite-plugin';\n\nexport default defineConfig({\n  // only necessary when not using @storybook/addon-vitest, otherwise the plugin is loaded automatically\n  plugins: [storybookNextJsPlugin()],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/vitest-plugin-install-coverage-support-packages.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\n# For v8\nnpm install --save-dev @vitest/coverage-v8\n\n# For istanbul\nnpm install --save-dev @vitest/coverage-istanbul\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\n# For v8\npnpm add --save-dev @vitest/coverage-v8\n\n# For istanbul\npnpm add --save-dev @vitest/coverage-istanbul\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\n# For v8\nyarn add --dev @vitest/coverage-v8\n\n# For istanbul\nyarn add --dev @vitest/coverage-istanbul\n```\n"
  },
  {
    "path": "docs/_snippets/vitest-plugin-run-tests.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm run test-storybook\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm run test-storybook\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn test-storybook\n```\n"
  },
  {
    "path": "docs/_snippets/vitest-plugin-run-with-coverage.md",
    "content": "```shell renderer=\"common\" language=\"js\" packageManager=\"npm\"\nnpm run test-storybook -- --coverage\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"pnpm\"\npnpm run test-storybook --coverage\n```\n\n```shell renderer=\"common\" language=\"js\" packageManager=\"yarn\"\nyarn test-storybook --coverage\n```\n"
  },
  {
    "path": "docs/_snippets/vitest-plugin-vitest-config.md",
    "content": "```ts filename=\"vitest.config.ts\" renderer=\"react\" tabTitle=\"Vitest 4\"\nimport { defineConfig, mergeConfig } from 'vitest/config';\nimport { playwright } from '@vitest/browser-playwright';\n\nimport { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst dirname = path.dirname(fileURLToPath(import.meta.url));\n\nimport viteConfig from './vite.config';\n\nexport default mergeConfig(\n  viteConfig,\n  defineConfig({\n    test: {\n      // Use `workspace` field in Vitest < 3.2\n      projects: [\n        {\n          extends: true,\n          plugins: [\n            storybookTest({\n              // The location of your Storybook config, main.js|ts\n              configDir: path.join(dirname, '.storybook'),\n              // This should match your package.json script to run Storybook\n              // The --no-open flag will skip the automatic opening of a browser\n              storybookScript: 'yarn storybook --no-open',\n            }),\n          ],\n          test: {\n            name: 'storybook',\n            // Enable browser mode\n            browser: {\n              enabled: true,\n              // Make sure to install Playwright\n              provider: playwright({}),\n              headless: true,\n              instances: [{ browser: 'chromium' }],\n            },\n            setupFiles: ['./.storybook/vitest.setup.ts'],\n          },\n        },\n      ],\n    },\n  }),\n);\n```\n\n```ts filename=\"vitest.config.ts\" renderer=\"react\" tabTitle=\"Vitest 3\"\nimport { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst dirname = path.dirname(fileURLToPath(import.meta.url));\n\nimport viteConfig from './vite.config';\n\nexport default mergeConfig(\n  viteConfig,\n  defineConfig({\n    test: {\n      // Use `workspace` field in Vitest < 3.2\n      projects: [\n        {\n          extends: true,\n          plugins: [\n            storybookTest({\n              // The location of your Storybook config, main.js|ts\n              configDir: path.join(dirname, '.storybook'),\n              // This should match your package.json script to run Storybook\n              // The --no-open flag will skip the automatic opening of a browser\n              storybookScript: 'yarn storybook --no-open',\n            }),\n          ],\n          test: {\n            name: 'storybook',\n            // Enable browser mode\n            browser: {\n              enabled: true,\n              // Make sure to install Playwright\n              provider: 'playwright',\n              headless: true,\n              instances: [{ browser: 'chromium' }],\n            },\n            setupFiles: ['./.storybook/vitest.setup.ts'],\n          },\n        },\n      ],\n    },\n  }),\n);\n```\n\n```ts filename=\"vitest.config.ts\" renderer=\"vue\" tabTitle=\"Vitest 4\"\nimport { defineConfig, mergeConfig } from 'vitest/config';\nimport { playwright } from '@vitest/browser-playwright';\n\nimport { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst dirname = path.dirname(fileURLToPath(import.meta.url));\n\nimport viteConfig from './vite.config';\n\nexport default mergeConfig(\n  viteConfig,\n  defineConfig({\n    test: {\n      // Use `workspace` field in Vitest < 3.2\n      projects: [\n        {\n          extends: true,\n          plugins: [\n            storybookTest({\n              // The location of your Storybook config, main.js|ts\n              configDir: path.join(dirname, '.storybook'),\n              // This should match your package.json script to run Storybook\n              // The --no-open flag will skip the automatic opening of a browser\n              storybookScript: 'yarn storybook --no-open',\n            }),\n          ],\n          test: {\n            name: 'storybook',\n            // Enable browser mode\n            browser: {\n              enabled: true,\n              // Make sure to install Playwright\n              provider: playwright({}),\n              headless: true,\n              instances: [{ browser: 'chromium' }],\n            },\n            setupFiles: ['./.storybook/vitest.setup.ts'],\n          },\n        },\n      ],\n    },\n  }),\n);\n```\n\n```ts filename=\"vitest.config.ts\" renderer=\"vue\" tabTitle=\"Vitest 3\"\nimport { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport viteConfig from './vite.config';\n\nconst dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport default mergeConfig(\n  viteConfig,\n  defineConfig({\n    test: {\n      // Use `workspace` field in Vitest < 3.2\n      projects: [\n        {\n          extends: true,\n          plugins: [\n            storybookTest({\n              // The location of your Storybook config, main.js|ts\n              configDir: path.join(dirname, '.storybook'),\n              // This should match your package.json script to run Storybook\n              // The --no-open flag will skip the automatic opening of a browser\n              storybookScript: 'yarn storybook --no-open',\n            }),\n          ],\n          test: {\n            name: 'storybook',\n            // Enable browser mode\n            browser: {\n              enabled: true,\n              // Make sure to install Playwright\n              provider: 'playwright',\n              headless: true,\n              instances: [{ browser: 'chromium' }],\n            },\n            setupFiles: ['./.storybook/vitest.setup.ts'],\n          },\n        },\n      ],\n    },\n  }),\n);\n```\n\n```ts filename=\"vitest.config.ts\" renderer=\"svelte\" tabTitle=\"Vitest 4\"\nimport { defineConfig, mergeConfig } from 'vitest/config';\nimport { playwright } from '@vitest/browser-playwright';\n\nimport { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst dirname = path.dirname(fileURLToPath(import.meta.url));\n\nimport viteConfig from './vite.config';\n\nexport default mergeConfig(\n  viteConfig,\n  defineConfig({\n    test: {\n      // Use `workspace` field in Vitest < 3.2\n      projects: [\n        {\n          extends: true,\n          plugins: [\n            storybookTest({\n              // The location of your Storybook config, main.js|ts\n              configDir: path.join(dirname, '.storybook'),\n              // This should match your package.json script to run Storybook\n              // The --no-open flag will skip the automatic opening of a browser\n              storybookScript: 'yarn storybook --no-open',\n            }),\n          ],\n          test: {\n            name: 'storybook',\n            // Enable browser mode\n            browser: {\n              enabled: true,\n              // Make sure to install Playwright\n              provider: playwright({}),\n              headless: true,\n              instances: [{ browser: 'chromium' }],\n            },\n            setupFiles: ['./.storybook/vitest.setup.ts'],\n          },\n        },\n      ],\n    },\n  }),\n);\n```\n\n```ts filename=\"vitest.config.ts\" renderer=\"svelte\" tabTitle=\"Vitest 3\"\nimport { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst dirname = path.dirname(fileURLToPath(import.meta.url));\n\nimport viteConfig from './vite.config';\n\nexport default mergeConfig(\n  viteConfig,\n  defineConfig({\n    test: {\n      // Use `workspace` field in Vitest < 3.2\n      projects: [\n        {\n          extends: true,\n          plugins: [\n            storybookTest({\n              // The location of your Storybook config, main.js|ts\n              configDir: path.join(dirname, '.storybook'),\n              // This should match your package.json script to run Storybook\n              // The --no-open flag will skip the automatic opening of a browser\n              storybookScript: 'yarn storybook --no-open',\n            }),\n          ],\n          test: {\n            name: 'storybook',\n            // Enable browser mode\n            browser: {\n              enabled: true,\n              // Make sure to install Playwright\n              provider: 'playwright',\n              headless: true,\n              instances: [{ browser: 'chromium' }],\n            },\n            setupFiles: ['./.storybook/vitest.setup.ts'],\n          },\n        },\n      ],\n    },\n  }),\n);\n```\n\n```ts filename=\"vitest.config.ts\" renderer=\"web-components\" tabTitle=\"Vitest 4\"\nimport { defineConfig, mergeConfig } from 'vitest/config';\nimport { playwright } from '@vitest/browser-playwright';\n\nimport { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst dirname = path.dirname(fileURLToPath(import.meta.url));\n\nimport viteConfig from './vite.config';\n\nexport default mergeConfig(\n  viteConfig,\n  defineConfig({\n    test: {\n      // Use `workspace` field in Vitest < 3.2\n      projects: [\n        {\n          extends: true,\n          plugins: [\n            storybookTest({\n              // The location of your Storybook config, main.js|ts\n              configDir: path.join(dirname, '.storybook'),\n              // This should match your package.json script to run Storybook\n              // The --no-open flag will skip the automatic opening of a browser\n              storybookScript: 'yarn storybook --no-open',\n            }),\n          ],\n          test: {\n            name: 'storybook',\n            // Enable browser mode\n            browser: {\n              enabled: true,\n              // Make sure to install Playwright\n              provider: playwright({}),\n              headless: true,\n              instances: [{ browser: 'chromium' }],\n            },\n            setupFiles: ['./.storybook/vitest.setup.ts'],\n          },\n        },\n      ],\n    },\n  }),\n);\n```\n\n```ts filename=\"vitest.config.ts\" renderer=\"web-components\" tabTitle=\"Vitest 3\"\nimport { defineConfig, mergeConfig } from 'vitest/config';\n\nimport { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\n\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst dirname = path.dirname(fileURLToPath(import.meta.url));\n\nimport viteConfig from './vite.config';\n\nexport default mergeConfig(\n  viteConfig,\n  defineConfig({\n    test: {\n      // Use `workspace` field in Vitest < 3.2\n      projects: [\n        {\n          extends: true,\n          plugins: [\n            storybookTest({\n              // The location of your Storybook config, main.js|ts\n              configDir: path.join(dirname, '.storybook'),\n              // This should match your package.json script to run Storybook\n              // The --no-open flag will skip the automatic opening of a browser\n              storybookScript: 'yarn storybook --no-open',\n            }),\n          ],\n          test: {\n            name: 'storybook',\n            // Enable browser mode\n            browser: {\n              enabled: true,\n              // Make sure to install Playwright\n              provider: 'playwright',\n              headless: true,\n              instances: [{ browser: 'chromium' }],\n            },\n            setupFiles: ['./.storybook/vitest.setup.ts'],\n          },\n        },\n      ],\n    },\n  }),\n);\n```\n"
  },
  {
    "path": "docs/_snippets/vitest-plugin-vitest-debug-option-ci.md",
    "content": "```ts filename=\"vitest.config.ts\" renderer=\"common\" tabTitle=\"Vitest 4\"\nexport default defineConfig({\n  // ...\n  test: {\n    // ...\n    projects: [\n      {\n        plugins: [\n          storybookTest({\n            // ...\n            // 👇 Use the environment variable you passed\n            storybookUrl: process.env.SB_URL,\n          }),\n        ],\n      },\n    ],\n  },\n});\n```\n\n```ts filename=\"vitest.workspace.ts\" renderer=\"common\" tabTitle=\"Vitest 3\"\nexport default defineWorkspace([\n  // ...\n  {\n    // ...\n    {\n      plugins: [\n        storybookTest({\n        // ...\n         // 👇 Use the environment variable you passed\n         storybookUrl: process.env.SB_URL\n        }),\n      ],\n    },\n  },\n]);\n```\n"
  },
  {
    "path": "docs/_snippets/vitest-plugin-vitest-tags-configuration.md",
    "content": "```ts filename=\"vitest.config.ts\" renderer=\"common\" tabTitle=\"Vitest 4\"\nexport default defineConfig({\n  // ...\n  test: {\n    // ...\n    projects: [\n      {\n        plugins: [\n          storybookTest({\n            // ...\n            tags: {\n              include: ['test'],\n              exclude: ['experimental'],\n            },\n          }),\n        ],\n        // ...\n      },\n    ],\n  },\n});\n```\n\n```ts filename=\"vitest.workspace.ts\" renderer=\"common\" tabTitle=\"Vitest 3\"\nexport default defineWorkspace([\n  // ...\n  {\n    // ...\n    {\n      plugins: [\n        storybookTest({\n          // ...\n          tags: {\n            include: ['test'],\n            exclude: ['experimental'],\n          },\n        }),\n      ],\n    },\n  },\n]);\n```\n"
  },
  {
    "path": "docs/_snippets/vitest-plugin-vitest-workspace.md",
    "content": "```ts filename=\"vitest.workspace.ts\" renderer=\"react\"\nimport { defineWorkspace } from 'vitest/config';\nimport { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport default defineWorkspace([\n  // This is the path to your existing Vitest config file\n  './vitest.config.ts',\n  {\n    // This is the path to your existing Vite config file\n    extends: './vite.config.ts',\n    plugins: [\n      storybookTest({\n        // The location of your Storybook config, main.js|ts\n        configDir: path.join(dirname, '.storybook'),\n        // This should match your package.json script to run Storybook\n        // The --ci flag will skip prompts and not open a browser\n        storybookScript: 'yarn storybook --ci',\n      }),\n    ],\n    test: {\n      name: 'storybook',\n      // Enable browser mode\n      browser: {\n        enabled: true,\n        // Make sure to install Playwright\n        provider: 'playwright',\n        headless: true,\n        instances: [{ browser: 'chromium' }],\n      },\n      setupFiles: ['./.storybook/vitest.setup.ts'],\n    },\n  },\n]);\n```\n\n```ts filename=\"vitest.config.ts\" renderer=\"vue\"\nimport { defineConfig, mergeConfig } from 'vitest/config';\nimport { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport viteConfig from './vite.config';\n\nconst dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport default defineWorkspace([\n  // This is the path to your existing Vitest config file\n  './vitest.config.ts',\n  {\n    // This is the path to your existing Vite config file\n    extends: './vite.config.ts',\n    plugins: [\n      storybookTest({\n        // The location of your Storybook config, main.js|ts\n        configDir: path.join(dirname, '.storybook'),\n        // This should match your package.json script to run Storybook\n        // The --ci flag will skip prompts and not open a browser\n        storybookScript: 'yarn storybook --ci',\n      }),\n    ],\n    test: {\n      name: 'storybook',\n      // Enable browser mode\n      browser: {\n        enabled: true,\n        // Make sure to install Playwright\n        provider: 'playwright',\n        headless: true,\n        instances: [{ browser: 'chromium' }],\n      },\n      setupFiles: ['./.storybook/vitest.setup.ts'],\n    },\n  },\n]);\n```\n\n```ts filename=\"vitest.config.ts\" renderer=\"svelte\"\nimport { defineConfig, mergeConfig } from 'vitest/config';\nimport { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport viteConfig from './vite.config';\n\nconst dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport default defineWorkspace([\n  // This is the path to your existing Vitest config file\n  './vitest.config.ts',\n  {\n    // This is the path to your existing Vite config file\n    extends: './vite.config.ts',\n    plugins: [\n      storybookTest({\n        // The location of your Storybook config, main.js|ts\n        configDir: path.join(dirname, '.storybook'),\n        // This should match your package.json script to run Storybook\n        // The --ci flag will skip prompts and not open a browser\n        storybookScript: 'yarn storybook --ci',\n      }),\n    ],\n    test: {\n      name: 'storybook',\n      // Enable browser mode\n      browser: {\n        enabled: true,\n        // Make sure to install Playwright\n        provider: 'playwright',\n        headless: true,\n        instances: [{ browser: 'chromium' }],\n      },\n      setupFiles: ['./.storybook/vitest.setup.ts'],\n    },\n  },\n]);\n```\n\n```ts filename=\"vitest.config.ts\" renderer=\"web-components\"\nimport { defineConfig, mergeConfig } from 'vitest/config';\nimport { storybookTest } from '@storybook/addon-vitest/vitest-plugin';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport viteConfig from './vite.config';\n\nconst dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport default defineWorkspace([\n  // This is the path to your existing Vitest config file\n  './vitest.config.ts',\n  {\n    // This is the path to your existing Vite config file\n    extends: './vite.config.ts',\n    plugins: [\n      storybookTest({\n        // The location of your Storybook config, main.js|ts\n        configDir: path.join(dirname, '.storybook'),\n        // This should match your package.json script to run Storybook\n        // The --ci flag will skip prompts and not open a browser\n        storybookScript: 'yarn storybook --ci',\n      }),\n    ],\n    test: {\n      name: 'storybook',\n      // Enable browser mode\n      browser: {\n        enabled: true,\n        // Make sure to install Playwright\n        provider: 'playwright',\n        headless: true,\n        instances: [{ browser: 'chromium' }],\n      },\n      setupFiles: ['./.storybook/vitest.setup.ts'],\n    },\n  },\n]);\n```\n"
  },
  {
    "path": "docs/_snippets/vue-vite-framework-options.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  framework: {\n    name: '@storybook/vue3-vite',\n    options: {\n      docgen: 'vue-component-meta',\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { StorybookConfig } from '@storybook/vue3-vite';\n\nconst config: StorybookConfig = {\n  framework: {\n    name: '@storybook/vue3-vite',\n    options: {\n      docgen: 'vue-component-meta',\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: {\n    name: '@storybook/vue3-vite',\n    options: {\n      docgen: 'vue-component-meta',\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  framework: {\n    name: '@storybook/vue3-vite',\n    options: {\n      docgen: 'vue-component-meta',\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/vue3-vite-add-framework.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nexport default {\n  // ...\n  framework: '@storybook/vue3-vite', // 👈 Add this\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { StorybookConfig } from '@storybook/vue3-vite';\n\nconst config: StorybookConfig = {\n  // ...\n  framework: '@storybook/vue3-vite', // 👈 Add this\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  // ...\n  framework: '@storybook/vue3-vite', // 👈 Add this\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/vue3-vite/node';\n\nexport default defineMain({\n  // ...\n  framework: '@storybook/vue3-vite', // 👈 Add this\n});\n```\n"
  },
  {
    "path": "docs/_snippets/vue3-vite-install.md",
    "content": "```shell renderer=\"vue\" language=\"js\" packageManager=\"npm\"\nnpm install --save-dev @storybook/vue3-vite\n```\n\n```shell renderer=\"vue\" language=\"js\" packageManager=\"pnpm\"\npnpm add --save-dev @storybook/vue3-vite\n```\n\n```shell renderer=\"vue\" language=\"js\" packageManager=\"yarn\"\nyarn add --dev @storybook/vue3-vite\n```\n"
  },
  {
    "path": "docs/_snippets/web-components-vite-add-framework.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\"\nexport default {\n  // ...\n  framework: '@storybook/web-components-vite', // 👈 Add this\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\"\nimport type { StorybookConfig } from '@storybook/web-components-vite';\n\nconst config: StorybookConfig = {\n  // ...\n  framework: '@storybook/web-components-vite', // 👈 Add this\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  // ...\n  framework: '@storybook/web-components-vite', // 👈 Add this\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  // ...\n  framework: '@storybook/web-components-vite', // 👈 Add this\n});\n```\n"
  },
  {
    "path": "docs/_snippets/web-components-vite-framework-options.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\"\nexport default {\n  framework: {\n    name: '@storybook/web-components-vite',\n    options: {\n      // ...\n    },\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\"\nimport type { StorybookConfig } from '@storybook/web-components-vite';\n\nconst config: StorybookConfig = {\n  framework: {\n    name: '@storybook/web-components-vite',\n    options: {\n      // ...\n    },\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: {\n    name: '@storybook/web-components-vite',\n    options: {\n      // ...\n    },\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nexport default defineMain({\n  framework: {\n    name: '@storybook/web-components-vite',\n    options: {\n      // ...\n    },\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/web-components-vite-install.md",
    "content": "```shell renderer=\"web-components\" language=\"js\" packageManager=\"npm\"\nnpm install --save-dev @storybook/web-components-vite\n```\n\n```shell renderer=\"web-components\" language=\"js\" packageManager=\"pnpm\"\npnpm add --save-dev @storybook/web-components-vite\n```\n\n```shell renderer=\"web-components\" language=\"js\" packageManager=\"yarn\"\nyarn add --dev @storybook/web-components-vite\n```\n"
  },
  {
    "path": "docs/_snippets/webpack-final-to-vite-final.md",
    "content": "```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"With Webpack (CSF 3)\"\nexport default {\n  // Replace your-framework with the framework you are using (e.g., react-webpack5, nextjs, etc.)\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async webpackFinal(config) {\n    config.module?.rules?.push({\n      test: /\\.(graphql|gql)$/,\n      include: [path.resolve('./lib/emails')],\n      exclude: /node_modules/,\n      loader: 'graphql-tag/loader',\n    });\n    config.module?.rules?.push({\n      test: /\\.(graphql|gql)$/,\n      include: [path.resolve('./lib/schema')],\n      exclude: /node_modules/,\n      loader: 'raw-loader',\n    });\n\n    return config;\n  },\n};\n```\n\n```js filename=\".storybook/main.js\" renderer=\"common\" language=\"js\" tabTitle=\"With Vite (CSF 3)\"\nimport graphql from 'vite-plugin-graphql-loader';\n\nexport default {\n  // Replace your-framework with the framework you are using, e.g. react-vite, nextjs-vite, vue3-vite, etc.\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config) {\n    return {\n      ...config,\n      plugins: [...(config.plugins ?? []), graphql()],\n    };\n  },\n};\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"With Webpack (CSF 3)\"\n// Replace your-framework with the framework you are using (e.g., react-webpack5, nextjs, etc.)\nimport type { StorybookConfig } from '@storybook/your-framework';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async webpackFinal(config) {\n    config.module?.rules?.push({\n      test: /\\.(graphql|gql)$/,\n      include: [path.resolve('./lib/emails')],\n      exclude: /node_modules/,\n      loader: 'graphql-tag/loader',\n    });\n    config.module?.rules?.push({\n      test: /\\.(graphql|gql)$/,\n      include: [path.resolve('./lib/schema')],\n      exclude: /node_modules/,\n      loader: 'raw-loader',\n    });\n\n    return config;\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"common\" language=\"ts\" tabTitle=\"With Vite (CSF 3)\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs-vite, vue3-vite, etc.\nimport type { StorybookConfig } from '@storybook/your-framework';\nimport graphql from 'vite-plugin-graphql-loader';\n\nconst config: StorybookConfig = {\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config) {\n    return {\n      ...config,\n      plugins: [...(config.plugins ?? []), graphql()],\n    };\n  },\n};\n\nexport default config;\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"With Webpack (CSF Next 🧪)\"\n// Replace your-framework with the framework you are using (e.g., react-webpack5, nextjs)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async webpackFinal(config) {\n    config.module?.rules?.push({\n      test: /\\.(graphql|gql)$/,\n      include: [path.resolve('./lib/emails')],\n      exclude: /node_modules/,\n      loader: 'graphql-tag/loader',\n    });\n    config.module?.rules?.push({\n      test: /\\.(graphql|gql)$/,\n      include: [path.resolve('./lib/schema')],\n      exclude: /node_modules/,\n      loader: 'raw-loader',\n    });\n\n    return config;\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"With Webpack (CSF Next 🧪)\"\n// Replace your-framework with the framework you are using (e.g., react-webpack5, nextjs)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async webpackFinal(config) {\n    config.module?.rules?.push({\n      test: /\\.(graphql|gql)$/,\n      include: [path.resolve('./lib/emails')],\n      exclude: /node_modules/,\n      loader: 'graphql-tag/loader',\n    });\n    config.module?.rules?.push({\n      test: /\\.(graphql|gql)$/,\n      include: [path.resolve('./lib/schema')],\n      exclude: /node_modules/,\n      loader: 'raw-loader',\n    });\n\n    return config;\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"react\" language=\"ts\" tabTitle=\"With Vite (CSF Next 🧪)\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nimport graphql from 'vite-plugin-graphql-loader';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config) {\n    return {\n      ...config,\n      plugins: [...(config.plugins ?? []), graphql()],\n    };\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"react\" language=\"js\" tabTitle=\"With Vite (CSF Next 🧪)\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nimport graphql from 'vite-plugin-graphql-loader';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config) {\n    return {\n      ...config,\n      plugins: [...(config.plugins ?? []), graphql()],\n    };\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"With Webpack (CSF Next 🧪)\"\nimport { defineMain } from '@storybook/web-components-webpack5/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-webpack5',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async webpackFinal(config) {\n    config.module?.rules?.push({\n      test: /\\.(graphql|gql)$/,\n      include: [path.resolve('./lib/emails')],\n      exclude: /node_modules/,\n      loader: 'graphql-tag/loader',\n    });\n    config.module?.rules?.push({\n      test: /\\.(graphql|gql)$/,\n      include: [path.resolve('./lib/schema')],\n      exclude: /node_modules/,\n      loader: 'raw-loader',\n    });\n\n    return config;\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"With Webpack (CSF Next 🧪)\"\nimport { defineMain } from '@storybook/web-components-webpack5/node';\n\nexport default defineMain({\n  framework: '@storybook/web-components-webpack5',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async webpackFinal(config) {\n    config.module?.rules?.push({\n      test: /\\.(graphql|gql)$/,\n      include: [path.resolve('./lib/emails')],\n      exclude: /node_modules/,\n      loader: 'graphql-tag/loader',\n    });\n    config.module?.rules?.push({\n      test: /\\.(graphql|gql)$/,\n      include: [path.resolve('./lib/schema')],\n      exclude: /node_modules/,\n      loader: 'raw-loader',\n    });\n\n    return config;\n  },\n});\n```\n\n```ts filename=\".storybook/main.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"With Vite (CSF Next 🧪)\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nimport graphql from 'vite-plugin-graphql-loader';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config) {\n    return {\n      ...config,\n      plugins: [...(config.plugins ?? []), graphql()],\n    };\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\".storybook/main.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"With Vite (CSF Next 🧪)\"\nimport { defineMain } from '@storybook/web-components-vite/node';\n\nimport graphql from 'vite-plugin-graphql-loader';\n\nexport default defineMain({\n  framework: '@storybook/web-components-vite',\n  stories: ['../src/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  async viteFinal(config) {\n    return {\n      ...config,\n      plugins: [...(config.plugins ?? []), graphql()],\n    };\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/your-component-with-decorator-with-props.md",
    "content": "```svelte filename=\"YourComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import YourComponent from './YourComponent.svelte';\n  import MarginDecorator from './MarginDecorator.svelte';\n\n  const { Story } = defineMeta({\n    component: YourComponent,\n    decorators: [\n      ({ parameters }) => ({\n        Component: MarginDecorator,\n        // 👇 Pass props to the MarginDecorator component\n        props: { size: parameters.smallMargin ? 'small' : 'medium' },\n      })\n    ],\n  });\n</script>\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport YourComponent from './YourComponent.svelte';\nimport MarginDecorator from './MarginDecorator.svelte';\n\nexport default {\n  component: YourComponent,\n  decorators: [\n    ({ parameters }) => ({\n      Component: MarginDecorator,\n      // 👇 Pass props to the MarginDecorator component\n      props: { size: parameters.smallMargin ? 'small' : 'medium' },\n    }),\n  ],\n};\n```\n\n```svelte filename=\"YourComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import YourComponent from './YourComponent.svelte';\n  import MarginDecorator from './MarginDecorator.svelte';\n\n  const { Story } = defineMeta({\n    component: YourComponent,\n    decorators: [\n      ({ parameters }) => ({\n        Component: MarginDecorator,\n        // 👇 Pass props to the MarginDecorator component\n        props: { size: parameters.smallMargin ? 'small' : 'medium' },\n      })\n    ],\n  });\n</script>\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport YourComponent from './YourComponent.svelte';\nimport MarginDecorator from './MarginDecorator.svelte';\n\nconst meta = {\n  component: YourComponent,\n  decorators: [\n    ({ parameters }) => ({\n      Component: MarginDecorator,\n      // 👇 Pass props to the MarginDecorator component\n      props: { size: parameters.smallMargin ? 'small' : 'medium' },\n    }),\n  ],\n} satisfies Meta<typeof YourComponent>;\n\nexport default meta;\n```\n"
  },
  {
    "path": "docs/_snippets/your-component-with-decorator.md",
    "content": "```ts filename=\"YourComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport { type Meta, componentWrapperDecorator } from '@storybook/angular';\n\nimport { YourComponent } from './your.component';\n\nconst meta: Meta<YourComponent> = {\n  component: YourComponent,\n  decorators: [componentWrapperDecorator((story) => `<div style=\"margin: 3em\">${story}</div>`)],\n};\n\nexport default meta;\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { componentWrapperDecorator } from '@storybook/angular';\n\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './your.component';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  decorators: [componentWrapperDecorator((story) => `<div style=\"margin: 3em\">${story}</div>`)],\n});\n```\n\n```jsx filename=\"YourComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { YourComponent } from './YourComponent';\n\nexport default {\n  component: YourComponent,\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </div>\n    ),\n  ],\n};\n```\n\n```tsx filename=\"YourComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta } from '@storybook/your-framework';\n\nimport { YourComponent } from './YourComponent';\n\nconst meta = {\n  component: YourComponent,\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </div>\n    ),\n  ],\n} satisfies Meta<typeof YourComponent>;\n\nexport default meta;\n```\n\n```jsx filename=\"YourComponent.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { YourComponent } from './YourComponent';\n\nexport default {\n  component: YourComponent,\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </div>\n    ),\n  ],\n};\n```\n\n```tsx filename=\"YourComponent.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta } from 'storybook-solidjs-vite';\n\nimport { YourComponent } from './YourComponent';\n\nconst meta = {\n  component: YourComponent,\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </div>\n    ),\n  ],\n} satisfies Meta<typeof YourComponent>;\n\nexport default meta;\n```\n\n```svelte filename=\"YourComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import YourComponent from './YourComponent.svelte';\n  import MarginDecorator from './MarginDecorator.svelte';\n\n  const { Story } = defineMeta({\n    component: YourComponent,\n    decorators: [() => MarginDecorator],\n  });\n</script>\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport YourComponent from './YourComponent.svelte';\nimport MarginDecorator from './MarginDecorator.svelte';\n\nexport default {\n  component: YourComponent,\n  decorators: [() => MarginDecorator],\n};\n```\n\n```svelte filename=\"YourComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import YourComponent from './YourComponent.svelte';\n  import MarginDecorator from './MarginDecorator.svelte';\n\n  const { Story } = defineMeta({\n    component: YourComponent,\n    decorators: [() => MarginDecorator],\n  });\n</script>\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta } from '@storybook/your-framework';\n\nimport YourComponent from './YourComponent.svelte';\nimport MarginDecorator from './MarginDecorator.svelte';\n\nconst meta = {\n  component: YourComponent,\n  decorators: [() => MarginDecorator],\n} satisfies Meta<typeof YourComponent>;\n\nexport default meta;\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport YourComponent from './YourComponent.vue';\n\nexport default {\n  component: YourComponent,\n  decorators: [() => ({ template: '<div style=\"margin: 3em;\"><story/></div>' })],\n};\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/vue3-vite';\n\nimport YourComponent from './YourComponent.vue';\n\nconst meta = {\n  component: YourComponent,\n  decorators: [() => ({ template: '<div style=\"margin: 3em;\"><story/></div>' })],\n} satisfies Meta<typeof YourComponent>;\n\nexport default meta;\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport YourComponent from './YourComponent.vue';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  decorators: [() => ({ template: '<div style=\"margin: 3em;\"><story/></div>' })],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"YourComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport YourComponent from './YourComponent.vue';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  decorators: [() => ({ template: '<div style=\"margin: 3em;\"><story/></div>' })],\n});\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\nimport { html } from 'lit';\n\nexport default {\n  component: 'demo-your-component',\n  decorators: [(story) => html`<div style=\"margin: 3em\">${story()}</div>`],\n};\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta } from '@storybook/web-components-vite';\n\nimport { html } from 'lit';\n\nconst meta: Meta = {\n  component: 'demo-your-component',\n  decorators: [(story) => html`<div style=\"margin: 3em\">${story()}</div>`],\n};\nexport default meta;\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-your-component',\n  decorators: [(story) => html`<div style=\"margin: 3em\">${story()}</div>`],\n});\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport { html } from 'lit';\n\nimport preview from '../.storybook/preview';\n\nconst meta = preview.meta({\n  component: 'demo-your-component',\n  decorators: [(story) => html`<div style=\"margin: 3em\">${story()}</div>`],\n});\n```\n\n```tsx filename=\"YourComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './YourComponent';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </div>\n    ),\n  ],\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```jsx filename=\"YourComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './YourComponent';\n\nconst meta = preview.meta({\n  component: YourComponent,\n  decorators: [\n    (Story) => (\n      <div style={{ margin: '3em' }}>\n        {/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it  */}\n        <Story />\n      </div>\n    ),\n  ],\n});\n```\n"
  },
  {
    "path": "docs/_snippets/your-component.md",
    "content": "```ts filename=\"YourComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/angular';\n\nimport { YourComponent } from './your.component';\n\n//👇 This default export determines where your story goes in the story list\nconst meta: Meta<YourComponent> = {\n  component: YourComponent,\n};\n\nexport default meta;\ntype Story = StoryObj<YourComponent>;\n\nexport const Basic: Story = {\n  args: {\n    //👇 The args you need here will depend on your component\n  },\n};\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"angular\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './your.component';\n\n//👇 This default export determines where your story goes in the story list\nconst meta = preview.meta({\n  component: YourComponent,\n});\n\nexport const Basic = meta.story({\n  args: {\n    //👇 The args you need here will depend on your component\n  },\n});\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"html\" language=\"js\"\nimport { createYourComponent } from './YourComponent';\n\n// 👇 This default export determines where your story goes in the story list\nexport default {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'YourComponent',\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic = {\n  render: (args) => createYourComponent(args),\n  args: {\n    // 👇 The args you need here will depend on your component\n  },\n};\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"html\" language=\"ts\"\nimport type { Meta, StoryObj } from '@storybook/html';\n\nimport { createYourComponent, ComponentProps } from './YourComponent';\n\n//👇 This default export determines where your story goes in the story list\nconst meta: Meta<ComponentProps> = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'YourComponent',\n};\n\nexport default meta;\ntype Story = StoryObj<ComponentProps>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic: Story = {\n  render: (args) => createYourComponent(args),\n  args: {\n    // 👇 The args you need here will depend on your component\n  },\n};\n```\n\n```js filename=\"YourComponent.stories.js|jsx\" renderer=\"preact\" language=\"js\"\n/** @jsx h */\nimport { h } from 'preact';\n\nimport { YourComponent } from './YourComponent';\n\n//👇 This default export determines where your story goes in the story list\nexport default {\n  component: YourComponent,\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic = {\n  render: (args) => <YourComponent {...args} />,\n  args: {\n    //👇 The args you need here will depend on your component\n  },\n};\n```\n\n```js filename=\"YourComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF 3\"\nimport { YourComponent } from './YourComponent';\n\n//👇 This default export determines where your story goes in the story list\nexport default {\n  component: YourComponent,\n};\n\nexport const Basic = {\n  args: {\n    //👇 The args you need here will depend on your component\n  },\n};\n```\n\n```ts filename=\"YourComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { YourComponent } from './YourComponent';\n\n//👇 This default export determines where your story goes in the story list\nconst meta = {\n  component: YourComponent,\n} satisfies Meta<typeof YourComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  args: {\n    //👇 The args you need here will depend on your component\n  },\n};\n```\n\n```js filename=\"YourComponent.stories.js|jsx\" renderer=\"solid\" language=\"js\"\nimport { YourComponent } from './YourComponent';\n\n//👇 This default export determines where your story goes in the story list\nexport default {\n  component: YourComponent,\n};\n\nexport const Basic = {\n  args: {\n    //👇 The args you need here will depend on your component\n  },\n};\n```\n\n```tsx filename=\"YourComponent.stories.ts|tsx\" renderer=\"solid\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-solidjs-vite';\n\nimport { YourComponent } from './YourComponent';\n\n//👇 This default export determines where your story goes in the story list\nconst meta = {\n  component: YourComponent,\n} satisfies Meta<typeof YourComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  args: {\n    //👇 The args you need here will depend on your component\n  },\n};\n```\n\n```svelte filename=\"YourComponent.stories.svelte\" renderer=\"svelte\" language=\"js\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import YourComponent from './YourComponent.svelte';\n\n  //👇 This export determines where your story goes in the story list\n  const { Story } = defineMeta({\n    component: YourComponent,\n  });\n</script>\n\n<Story\n  name=\"Basic\"\n  args={{\n    /*👇 The args you need here will depend on your component */\n  }}\n/>\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"svelte\" language=\"js\" tabTitle=\"CSF 3\"\nimport YourComponent from './YourComponent.svelte';\n\n//👇 This default export determines where your story goes in the story list\nexport default {\n  component: YourComponent,\n};\n\nexport const Basic = {\n  args: {\n    //👇 The args you need here will depend on your component\n  },\n};\n```\n\n```svelte filename=\"YourComponent.stories.svelte\" renderer=\"svelte\" language=\"ts\" tabTitle=\"Svelte CSF\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import YourComponent from './YourComponent.svelte';\n\n  //👇 This export determines where your story goes in the story list\n  const { Story } = defineMeta({\n    component: YourComponent,\n  });\n</script>\n\n<Story\n  name=\"Basic\"\n  args={{\n    /*👇 The args you need here will depend on your component */\n  }}\n/>\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"svelte\" language=\"ts\" tabTitle=\"CSF 3\"\n// Replace your-framework with svelte-vite or sveltekit\nimport type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport YourComponent from './YourComponent.svelte';\n\n//👇 This default export determines where your story goes in the story list\nconst meta = {\n  component: YourComponent,\n} satisfies Meta<typeof YourComponent>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Basic: Story = {\n  args: {\n    //👇 The args you need here will depend on your component\n  },\n};\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF 3\"\nimport YourComponent from './YourComponent.vue';\n\n//👇 This default export determines where your story goes in the story list\nexport default {\n  component: YourComponent,\n};\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic = {\n  render: (args) => ({\n    components: { YourComponent },\n    setup() {\n      return { args };\n    },\n    template: '<YourComponent v-bind=\"args\" />',\n  }),\n  args: {\n    //👇 The args you need here will depend on your component\n  },\n};\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport YourComponent from './YourComponent.vue';\n\nconst meta = {\n  component: YourComponent,\n} satisfies Meta<typeof YourComponent>;\n\n//👇 This default export determines where your story goes in the story list\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic: Story = {\n  render: (args) => ({\n    components: { YourComponent },\n    setup() {\n      return { args };\n    },\n    template: '<YourComponent v-bind=\"args\" />',\n  }),\n  args: {\n    //👇 The args you need here will depend on your component\n  },\n};\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport YourComponent from './YourComponent.vue';\n\n//👇 This default export determines where your story goes in the story list\nconst meta = preview.meta({\n  component: YourComponent,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic = meta.story({\n  render: (args) => ({\n    components: { YourComponent },\n    setup() {\n      return { args };\n    },\n    template: '<YourComponent v-bind=\"args\" />',\n  }),\n  args: {\n    //👇 The args you need here will depend on your component\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"YourComponent.stories.js\" renderer=\"vue\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport YourComponent from './YourComponent.vue';\n\n//👇 This default export determines where your story goes in the story list\nconst meta = preview.meta({\n  component: YourComponent,\n});\n\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Basic = meta.story({\n  render: (args) => ({\n    components: { YourComponent },\n    setup() {\n      return { args };\n    },\n    template: '<YourComponent v-bind=\"args\" />',\n  }),\n  args: {\n    //👇 The args you need here will depend on your component\n  },\n});\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF 3\"\n// This default export determines where your story goes in the story list\nexport default {\n  component: 'demo-your-component',\n};\n\nexport const Basic = {\n  args: {\n    // 👇 The args you need here will depend on your component\n  },\n};\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF 3\"\nimport type { Meta, StoryObj } from '@storybook/web-components-vite';\n\n// This default export determines where your story goes in the story list\nconst meta: Meta = {\n  component: 'demo-your-component',\n};\n\nexport default meta;\ntype Story = StoryObj;\n\nexport const Basic: Story = {\n  args: {\n    // 👇 The args you need here will depend on your component\n  },\n};\n```\n\n```js filename=\"YourComponent.stories.js\" renderer=\"web-components\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n// 👇 This default export determines where your story goes in the story list\nconst meta = preview.meta({\n  component: 'demo-your-component',\n});\n\nexport const Basic = meta.story({\n  args: {\n    // 👇 The args you need here will depend on your component\n  },\n});\n```\n\n```ts filename=\"YourComponent.stories.ts\" renderer=\"web-components\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\n// 👇 This default export determines where your story goes in the story list\nconst meta = preview.meta({\n  component: 'demo-your-component',\n});\n\nexport const Basic = meta.story({\n  args: {\n    // 👇 The args you need here will depend on your component\n  },\n});\n```\n\n```ts filename=\"YourComponent.stories.ts|tsx\" renderer=\"react\" language=\"ts\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './YourComponent';\n\n//👇 This default export determines where your story goes in the story list\nconst meta = preview.meta({\n  component: YourComponent,\n});\n\nexport const Basic = meta.story({\n  args: {\n    //👇 The args you need here will depend on your component\n  },\n});\n```\n\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\n\n```js filename=\"YourComponent.stories.js|jsx\" renderer=\"react\" language=\"js\" tabTitle=\"CSF Next 🧪\"\nimport preview from '../.storybook/preview';\n\nimport { YourComponent } from './YourComponent';\n\nconst meta = preview.meta({\n  component: YourComponent,\n});\n\nexport const Basic = meta.story({\n  args: {\n    //👇 The args you need here will depend on your component\n  },\n});\n```\n"
  },
  {
    "path": "docs/_snippets/your-theme.md",
    "content": "```js filename=\".storybook/YourTheme.js\" renderer=\"common\" language=\"js\"\nimport { create } from 'storybook/theming/create';\n\nexport default create({\n  base: 'light',\n  // Typography\n  fontBase: '\"Open Sans\", sans-serif',\n  fontCode: 'monospace',\n  brandTitle: 'My custom Storybook',\n  brandUrl: 'https://example.com',\n  brandImage: 'https://storybook.js.org/images/placeholders/350x150.png',\n  brandTarget: '_self',\n\n  //\n  colorPrimary: '#3A10E5',\n  colorSecondary: '#585C6D',\n\n  // UI\n  appBg: '#ffffff',\n  appContentBg: '#ffffff',\n  appPreviewBg: '#ffffff',\n  appBorderColor: '#585C6D',\n  appBorderRadius: 4,\n\n  // Text colors\n  textColor: '#10162F',\n  textInverseColor: '#ffffff',\n\n  // Toolbar default and active colors\n  barTextColor: '#9E9E9E',\n  barSelectedColor: '#585C6D',\n  barHoverColor: '#585C6D',\n  barBg: '#ffffff',\n\n  // Form colors\n  inputBg: '#ffffff',\n  inputBorder: '#10162F',\n  inputTextColor: '#10162F',\n  inputBorderRadius: 2,\n});\n```\n"
  },
  {
    "path": "docs/addons/addon-knowledge-base.mdx",
    "content": "---\ntitle: Addon knowledge base\nsidebar:\n  order: 7\n  title: Knowledge base\n---\n\nOnce you understand the basics of writing addons, there are a variety of common enhancements to make your addon better. This page details additional information about addon creation. Use it as a quick reference guide when creating your own addons.\n\n## Disable the addon panel\n\nIt’s possible to disable the addon panel for a particular story.\n\nTo make that possible, you need to pass the `paramKey` element when you register the panel:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-disable-addon.md\" />\n\n{/* prettier-ignore-end */}\n\nThen when adding a story, you can pass a disabled parameter.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-disable-addon.md\" />\n\n{/* prettier-ignore-end */}\n\n## Style your addon\n\nStorybook uses [Emotion](https://emotion.sh/docs/introduction) for styling. Alongside with a theme that you can customize!\n\nWe recommend using Emotion to style your addon’s UI components. That allows you to use the active Storybook theme to deliver a seamless developer experience.\nIf you don’t want to use Emotion, you can use inline styles or another css-in-js lib. You can receive the theme as a prop by using Emotion's `withTheme` HOC. [Read more about theming](../configure/user-interface/theming.mdx).\n\n## Storybook components\n\nAddon authors can develop their UIs using any React library. But we recommend using Storybook’s UI components in `storybook/internal/components` to build addons faster. When you use Storybook components, you get:\n\n* Battle-tested off-the-shelf components\n* Storybook native look and feel\n* Built-in support for Storybook theming\n\nUse the components listed below with your next addon.\n\n| Component          | Source                                                                                                                                                          | Story                                                                                                                          |\n| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |\n| Action Bar         | [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/ActionBar/ActionBar.tsx)                  | [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-actionbar--single-item)         |\n| Addon Panel        | [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/addon-panel/addon-panel.tsx)              | N/A                                                                                                                            |\n| Badge              | [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/Badge/Badge.tsx)                          | [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-badge--all-badges)              |\n| Button             | [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/Button/Button.tsx)                        | [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-button--all-buttons)            |\n| Form               | [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/form/index.tsx)                           | [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-form-button--sizes)             |\n| Loader             | [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/Loader/Loader.tsx)                        | [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-loader--progress-bar)           |\n| PlaceHolder        | [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/placeholder/placeholder.tsx)              | [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-placeholder--single-child)      |\n| Scroll Area        | [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/ScrollArea/ScrollArea.tsx)                | [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-scrollarea--vertical)           |\n| Space              | [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/spaced/Spaced.tsx)                        | [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-spaced--row)                    |\n| Syntax Highlighter | [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/syntaxhighlighter/syntaxhighlighter.tsx)  | [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-syntaxhighlighter--bash)        |\n| Tabs               | [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/tabs/tabs.tsx)                            | [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-tabs--stateful-static)          |\n| ToolBar            | [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/bar/bar.tsx)                              | N/A                                                                                                                            |\n| ToolTip            | [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/tooltip/Tooltip.tsx)                      | [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-tooltip-tooltip--basic-default) |\n| Zoom               | [See component implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/Zoom/Zoom.tsx)                            | [See component story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-zoom--element-actual-size)      |\n\nComplementing the components, also included is a set of UI primitives. Use the content listed below as a reference for styling your addon.\n\n| Component                      | Source                                                                                                                                 | Story                                                                                                    |\n| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------| -------------------------------------------------------------------------------------------------------- |\n| Color Palette (see note below) | [See implementation](https://github.com/storybookjs/storybook/blob/next/code/addons/docs/src/blocks/components/ColorPalette.tsx)       | [See story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-colorpalette--page) |\n| Icon                           | [See implementation](https://github.com/storybookjs/storybook/blob/next/code/core/src/components/components/icon/icon.tsx)             | [See story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-icon--labels)       |\n| Typography                     | [See implementation](https://github.com/storybookjs/storybook/tree/next/code/core/src/components/components/typography)                | [See story](https://main--5a375b97f4b14f0020b0cda3.chromatic.com/?path=/story/basics-typography--all)    |\n\n<Callout variant=\"info\">\n\n  The color palette implemented by `@storybook/addon-docs/blocks` is a high-level abstraction of the [`storybook/theming`](https://github.com/storybookjs/storybook/tree/next/code/core/src/theming) module.\n  \n</Callout>\n\n## Build system\n\nWhen you're developing your addon as a package, you can’t use `npm link` to add it to your project. List your addon as a local dependency into your package.json:\n\n```json title=\"package.json\"\n{\n  \"dependencies\": {\n    \"@storybook/addon-controls\": \"file:///home/username/myrepo\"\n  }\n}\n```\n\n<Callout variant=\"info\">\n  Run either `yarn` or `npm install` to install the addon.\n</Callout>\n\n## Hot module replacement\n\nWhile developing your addon, you can configure HMR (hot module replacement) to reflect the changes made.\n\n## Standalone Storybook addons\n\nIf you're developing a standalone addon, add a new script to `package.json` with the following:\n\n```json title=\"package.json\"\n{\n  \"scripts\": {\n    \"start\": \"npm run build -- --watch\"\n  }\n}\n```\n\n### Local Storybook addons\n\nIf you're developing a local Storybook addon built on top of an existing Storybook installation, HMR (hot module replacement) is available out of the box.\n\n## Composing addons in presets\n\nIf you're working on a preset that loads third-party addons, which you don't have control over, and you need access to certain features (e.g., decorators) or provide additional configurations. In that case, you'll need to update your preset to the following to allow you to load and configure the other addons:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-load-external-addons-preset.md\" />\n\n{/* prettier-ignore-end */}\n\nIf you have control over the addons you want to customize. In that case, you can update your preset and implement a custom function to load any additional presets and provide the necessary configuration.\n"
  },
  {
    "path": "docs/addons/addon-migration-guide.mdx",
    "content": "---\ntitle: Addon migration guide for Storybook 10.0\nsidebar:\n  order: 9\n  title: Migrate addons to 10.0\n---\n\nWe sincerely appreciate the dedication and effort addon creators put into keeping the Storybook ecosystem vibrant and up-to-date. As Storybook evolves to version 10.0, bringing new features and improvements, this guide is here to assist you in migrating your addons from 9.x to 10.0. If you need to migrate your addon from an earlier version of Storybook, please first refer to the [Addon migration guide for Storybook 9.0](../../../release-9-1/docs/addons/addon-migration-guide.mdx).\n\n<Callout variant=\"info\">\n  We also have a general [Storybook migration guide](../releases/migration-guide.mdx) that covers updates to your Storybook instance rather than your addon code.\n</Callout>\n\n## Dependency updates\n\nYou will need to update your Storybook dependencies. Peer dependencies must point to `^10.0.0` to ensure broad compatibility for your end users. Development dependencies can be set to `^10.0.0`, or to `next` if you want to try the latest prerelease all year round.\n\n```jsonc title=\"package.json\"\n{\n  \"devDependencies\": {\n    \"@storybook/addon-docs\": \"next\",\n    \"@storybook/react-vite\": \"next\",\n    \"storybook\": \"next\"\n  },\n  \"peerDependencies\": {\n    \"storybook\": \"^10.0.0\"\n  }\n}\n```\n\nIf you still have `@storybook/addon-essentials`, `@storybook/addon-interactions`, `@storybook/addon-links`, or `@storybook/blocks` in your dependencies, you will need to remove them. These packages are empty since Storybook 9 and will no longer be published going forward.\n\n### Supporting earlier versions\n\nIf your addon supports multiple major versions of Storybook, you can specify a wider version range in your peer dependencies:\n\n```jsonc title=\"package.json\"\n{\n  \"name\": \"your-storybook-addon\",\n  \"peerDependencies\": {\n    \"storybook\": \"^9.0.0 || ^10.0.0\"\n  },\n  \"devDependencies\": {\n    \"storybook\": \">=10.0.0-0 <11.0.0-0\" // For local development\n  }\n}\n```\n\nHowever, we recommend releasing a new major version of your addon alongside new major versions of Storybook. This practice:\n1. Makes it easier to maintain your code\n2. Allows you to take advantage of new features and improvements\n3. Provides a clearer upgrade path for your users\n\n## Key changes for addons\n\nHere are the changes in version 10.0 that impact addon development.\n\n### ESM-only builds\n\nStorybook 10 requires all addons to be built as ESM-only. This change simplifies the build process and reduces maintenance overhead. You'll need to make many changes to `tsup.config.ts`, so it can be easier to copy the reference file in the [`addon-kit` repository](https://github.com/storybookjs/addon-kit/blob/main/tsup.config.ts).\n\nThis update brings the following changes:\n* The Node target moves from Node 20.0 to Node 20.19\n* You no longer need to build CJS files\n* You no longer need to pass `globalManagerPackages` and `globalPreviewPackages`\n* The `bundler` config in `package.json` no longer needs to be manually typed\n* We recommend you stop using `exportEntries` and switch exported entries to `previewEntries` and `managerEntries` instead based on where they are consumed by your users\n\n```diff title=\"tsup.config.ts\"\n- import { readFile } from \"node:fs/promises\";\n\nimport { defineConfig, type Options } from \"tsup\";\n\n- import { globalPackages as globalManagerPackages } from \"storybook/internal/manager/globals\";\n- import { globalPackages as globalPreviewPackages } from \"storybook/internal/preview/globals\";\n\n- const NODE_TARGET: Options[\"target\"] = \"node20\";\n+ const NODE_TARGET = \"node20.19\"; // Minimum Node version supported by Storybook 10\n\n- type BundlerConfig = {\n-   bundler?: {\n-     exportEntries?: string[];\n-     nodeEntries?: string[];\n-     managerEntries?: string[];\n-     previewEntries?: string[];\n-   };\n- };\n\nexport default defineConfig(async (options) => {\n  // reading the three types of entries from package.json, which has the following structure:\n  // {\n  //  ...\n  //   \"bundler\": {\n-  //     \"exportEntries\": [\"./src/index.ts\"],\n  //     \"managerEntries\": [\"./src/manager.ts\"],\n-  //     \"previewEntries\": [\"./src/preview.ts\"],\n+  //     \"previewEntries\": [\"./src/preview.ts\", \"./src/index.ts\"],\n  //     \"nodeEntries\": [\"./src/preset.ts\"]\n  //   }\n  // }\n-   const packageJson = (await readFile(\"./package.json\", \"utf8\").then(\n-     JSON.parse,\n-   )) as BundlerConfig;\n+   const packageJson = (\n+     await import(\"./package.json\", { with: { type: \"json\" } })\n+   ).default;\n+\n  const {\n    bundler: {\n-      exportEntries = [],\n      managerEntries = [],\n      previewEntries = [],\n      nodeEntries = [],\n-    } = {},\n+    },\n  } = packageJson;\n\n  const commonConfig: Options = {\n-    splitting: false,\n+    splitting: true,\n+    format: [\"esm\"],\n-    minify: !options.watch,\n    treeshake: true,\n-    sourcemap: true,\n    // keep this line commented until https://github.com/egoist/tsup/issues/1270 is resolved\n    // clean: options.watch ? false : true,\n    clean: false,\n+    // The following packages are provided by Storybook and should always be externalized\n+    // Meaning they shouldn't be bundled with the addon, and they shouldn't be regular dependencies either\n+    external: [\"react\", \"react-dom\", \"@storybook/icons\"],\n  };\n\n  const configs: Options[] = [];\n-\n-   // export entries are entries meant to be manually imported by the user\n-   // they are not meant to be loaded by the manager or preview\n-   // they'll be usable in both node and browser environments, depending on which features and modules they depend on\n-   if (exportEntries.length) {\n-     configs.push({\n-       ...commonConfig,\n-       entry: exportEntries,\n-       dts: {\n-         resolve: true,\n-       },\n-       format: [\"esm\", \"cjs\"],\n-       platform: \"neutral\",\n-       target: NODE_TARGET,\n-       external: [...globalManagerPackages, ...globalPreviewPackages],\n-     });\n-   }\n\n  // manager entries are entries meant to be loaded into the manager UI\n  // they'll have manager-specific packages externalized and they won't be usable in node\n  // they won't have types generated for them as they're usually loaded automatically by Storybook\n  if (managerEntries.length) {\n    configs.push({\n      ...commonConfig,\n      entry: managerEntries,\n-      format: [\"esm\"],\n      platform: \"browser\",\n-      target: BROWSER_TARGETS,\n+      target: \"esnext\", // we can use esnext for manager entries since Storybook will bundle the addon's manager entries again anyway\n-      external: globalManagerPackages,\n    });\n  }\n\n  // preview entries are entries meant to be loaded into the preview iframe\n  // they'll have preview-specific packages externalized and they won't be usable in node\n  // they'll have types generated for them so they can be imported when setting up Portable Stories\n  if (previewEntries.length) {\n    configs.push({\n      ...commonConfig,\n      entry: previewEntries,\n-      dts: {\n-        resolve: true,\n-      },\n-      format: [\"esm\", \"cjs\"],\n      platform: \"browser\",\n-      target: BROWSER_TARGETS,\n+      target: \"esnext\", // we can use esnext for preview entries since Storybook will bundle the addon's preview entries again anyway\n-      external: globalPreviewPackages,\n+      dts: true,\n    });\n  }\n\n  // node entries are entries meant to be used in node-only\n  // this is useful for presets, which are loaded by Storybook when setting up configurations\n  // they won't have types generated for them as they're usually loaded automatically by Storybook\n  if (nodeEntries.length) {\n    configs.push({\n      ...commonConfig,\n      entry: nodeEntries,\n-      format: [\"cjs\"],\n      platform: \"node\",\n      target: NODE_TARGET,\n    });\n```\n\nNext, update the `exports` field in your `package.json` to remove mentions of CJS files.\n\n```diff title=\"package.json\"\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n-      \"import\": \"./dist/index.js\",\n-      \"require\": \"./dist/index.cjs\"\n+      \"default\": \"./dist/index.js\"\n    },\n    \"./preview\": {\n-      \"types\": \"./dist/index.d.ts\",\n-      \"import\": \"./dist/preview.js\",\n-      \"require\": \"./dist/preview.cjs\"\n+      \"types\": \"./dist/preview.d.ts\",\n+      \"default\": \"./dist/preview.js\"\n    },\n-    \"./preset\": \"./dist/preset.cjs\",\n+    \"./preset\": \"./dist/preset.js\",\n    \"./manager\": \"./dist/manager.js\",\n    \"./package.json\": \"./package.json\"\n  },\n```\n\nUpdate `tsconfig.json`.\n\n```diff title=\"tsconfig.json\"\n{\n  \"compilerOptions\": {\n    // …\n+    \"moduleResolution\": \"bundler\",\n    // …\n-    \"module\": \"commonjs\",\n+    \"module\": \"preserve\",\n    // …\n-    \"target\": \"ES2020\",\n+    \"target\": \"esnext\",\n    // …\n-    \"lib\": [\"es2020\", \"dom\", \"dom.iterable\"],\n+    \"lib\": [\"esnext\", \"dom\", \"dom.iterable\"],\n    // …\n-    \"rootDir\": \"./src\",\n+    \"rootDir\": \".\",\n  },\n-  \"include\": [\"src/**/*\"]\n+  \"include\": [\"src/**/*\", \"tsup.config.ts\"]\n }\n```\n\nFinally, change the `preset.js` file at the top-level of your addon to be ESM. This file used to be CJS because the Storybook Node app only supported CJS.\n\n```diff title=\"preset.js\"\n-// this file is slightly misleading. It needs to be CJS, and thus in this \"type\": \"module\" package it should be named preset.cjs\n-// but Storybook won't pick that filename up so we have to name it preset.js instead\n-\n-module.exports = require('./dist/preset.cjs');\n+export * from './dist/preset.js';\n```\n\n### Local addon loading\n\nBecause addons are now ESM-only, you must change how you load your own addon in your development Storybook instance. Imports and exports must now follow ESM syntax, and relative paths must use `import.meta.resolve`.\n\n\nRemove `.storybook/local-preset.cjs` and create `.storybook/local-preset.ts` with the following content:\n\n```ts title=\".storybook/local-preset.ts\"\nimport { fileURLToPath } from \"node:url\";\n\nexport function previewAnnotations(entry = []) {\n  return [...entry, fileURLToPath(import.meta.resolve(\"../dist/preview.js\"))];\n}\n\nexport function managerEntries(entry = []) {\n  return [...entry, fileURLToPath(import.meta.resolve(\"../dist/manager.js\"))];\n}\n\nexport * from \"../dist/preset.js\";\n```\n\nNext, update your `main.ts` to reference the new preset file:\n\n```diff title=\".storybook/main.ts\"\n- addons: [\"@storybook/addon-docs\", \"./local-preset.cjs\"],\n+ addons: [\"@storybook/addon-docs\", import.meta.resolve(\"./local-preset.ts\")],\n```\n\n## Optional changes\n\nThe following changes are not strictly required yet, but we recommend making them to improve your users' experience.\n\n### CSF Factories support\nTo support CSF Factories annotations in your addon, you will need to update your `src/index.ts` file to use the new `definePreviewAddon`. This feature will be part of [CSF Next](../api/csf/csf-next.mdx). This change is highly recommended, as it will help your own users reap the benefits of CSF Factories.\n\nWith CSF Factories, users can chain their preview configuration and benefit from better typing and more flexibility. Addons must export annotations to be compatible with this new syntax. CSF Factories will be the default way to write stories in Storybook 11.\n\n```diff title=\"src/index.ts\"\n- // make it work with --isolatedModules\n- export default {};\n+ import { definePreviewAddon } from \"storybook/internal/csf\";\n+ import addonAnnotations from \"./preview\";\n+\n+ export default () => definePreviewAddon(addonAnnotations);\n```\n\n### Removal of exportEntries\n\nThe `exportEntries` property in `package.json`'s `bundler` was used to produce the `index.js` build output from `src/index.ts`. It was compatible with Node.js, rather than strictly with browsers. This build configuration could cause subtle bugs when addon authors exported code in `index.js` for use in the Storybook preview or manager.\n\nIn the Storybook 10 [addon-kit](https://github.com/storybookjs/addon-kit), we removed `exportEntries` from the `bundler` config, and we moved `src/index.ts` to be part of `previewEntries` instead. This way, any code exported from `src/index.ts` is bundled for browsers and usable with CSF Next. If you need to export additional code to run in the preview (such as optional decorators), you can add them to `src/index.ts`.\n\nIf you need to export code for the manager (such as a `renderLabel` function for the sidebar), you can create a new `src/manager-helpers.ts` file and add it to `managerEntries`, like so:\n\n```diff title=\"package.json\"\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./preview\": {\n      \"types\": \"./dist/preview.d.ts\",\n      \"default\": \"./dist/preview.js\"\n    },\n    \"./preset\": \"./dist/preset.js\",\n    \"./manager\": \"./dist/manager.js\",\n+    \"./manager-helpers\": \"./dist/manager-helpers.js\",\n    \"./package.json\": \"./package.json\"\n  },\n  \"bundler\": {\n    \"managerEntries\": [\n+      \"src/manager-helpers.ts\",\n      \"src/manager.tsx\"\n    ]\n  }\n```\n\n### Build file cleanup\n\nWe recommend removing your old build files as you build. This will avoid your `dist` folder growing with expired JS chunks. You may add the following to your `package.json` scripts:\n\n```diff title=\"package.json\"\n{\n  \"scripts\": {\n+    \"prebuild\": \"node -e \\\"fs.rmSync('./dist', { recursive: true, force: true })\\\"\",\n  }\n}\n```\n\n### Package keyword changes\n\nWe've updated default keywords for addons in the Storybook `addon-kit` template.\n\n```diff title=\"package.json\"\n  \"keywords\": [\n-    \"storybook-addons\",\n+    \"storybook-addon\",\n  ],\n```\n\n## 10.0.0 full migration guide\n\nFor a full list of changes, please visit the [Migration.md](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#from-version-9x-to-1000) file\n\n## Migration example\n\nFor a complete example of an addon updated to support Storybook 10.0, refer to the [Addon Kit migration PR](https://github.com/storybookjs/addon-kit/pull/82).\nOnce merged, it will demonstrate all the necessary and recommended changes for Storybook 10.\n\n## Releasing\n\nTo support Storybook 10.0, we encourage you to release a new major version of your addon. For experimental features or testing, use the `next` tag. This allows you to gather feedback before releasing a stable version.\n\n## Support\n\nIf you're having issues with your addon after following this guide, please open a [new discussion](https://github.com/storybookjs/storybook/discussions/new?category=migrations) in our GitHub repository or come talk to us in our [dedicated addon developer channel, `#addons`](https://discord.gg/KKXFQy9sFc) on Discord.\n"
  },
  {
    "path": "docs/addons/addon-types.mdx",
    "content": "---\ntitle: 'Types of addons'\nsidebar:\n  order: 6\n  title: Types of addons\n---\n\nEach Storybook addon is classified into two general categories, UI-based or Presets. Each type of addons feature is documented here. Use this as a reference when creating your addon.\n\n## UI-based addons\n\nUI-based addons allow you to customize Storybook's UI with the following elements.\n\n### Panels\n\nPanel addons allow you to add your own UI in Storybook's addon panel. This is the most common type of addon in the ecosystem. For example, the official [`@storybook/addon-a11y`](https://github.com/storybookjs/storybook/tree/next/code/addons/a11y) uses this pattern.\n\n![Storybook panel](../_assets/addons/storybook-panel.png)\n\nUse this boilerplate code to add a new `Panel` to Storybook's UI:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-panel-example.md\" />\n\n{/* prettier-ignore-end */}\n\n### Toolbars\n\nToolbar addons allow you to add your own custom tools in Storybook's Toolbar. For example, the official [`@storybook/addon-themes`](https://storybook.js.org/addons/@storybook/addon-themes) uses this pattern.\n\n![Storybook toolbar addon](../_assets/addons/storybook-toolbar.png)\n\nUse this boilerplate code to add a new `button` to Storybook's Toolbar:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-toolbar-example.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  The `match` property allows you to conditionally render your toolbar addon, [based on the current view](./writing-addons.mdx#conditionally-render-the-addon). The `icon` element used in the example loads the icons from the `storybook/internal/components` module. See [here](../faq.mdx#what-icons-are-available-for-my-toolbar-or-my-addon) for the list of available icons that you can use.\n</Callout>\n\n### Tabs\n\nTab addons allow you to create your own custom tabs in Storybook.\n\n![Storybook tab addon](../_assets/addons/storybook-tab.png)\n\nUse this boilerplate code to add a new `Tab` to Storybook's UI:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-tab-example.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  Learn how to write your own addon that includes these UI elements [here](./writing-addons.mdx).\n</Callout>\n\n## Preset addons\n\nStorybook preset addons are grouped collections of `babel`, `webpack`, and `addons` configurations to integrate Storybook and other technologies. For example the official [preset-create-react-app](https://github.com/storybookjs/presets/tree/master/packages/preset-create-react-app).\n\nUse this boilerplate code while writing your own preset addon.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preset-full-config-object.md\" />\n\n{/* prettier-ignore-end */}\n\n**Learn more about the Storybook addon ecosystem**\n\n* Types of addons for other types of addons\n* [Writing addons](./writing-addons.mdx) for the basics of addon development\n* [Presets](./writing-presets.mdx) for preset development\n* [Integration catalog](./integration-catalog.mdx) for requirements and available recipes\n* [API reference](./addons-api.mdx) to learn about the available APIs\n"
  },
  {
    "path": "docs/addons/addons-api.mdx",
    "content": "---\ntitle: 'Addon API'\nsidebar:\n  order: 8\n  title: Addon API\n---\n\nStorybook's API allows developers to interact programmatically with Storybook. With the API, developers can build and deploy custom addons and other tools that enhance Storybook's functionality.\n\n## Core Addon API\n\nOur API is exposed via two distinct packages, each one with a different purpose:\n\n* `storybook/manager-api` used to interact with the Storybook manager UI or access the Storybook API.\n* `storybook/preview-api` used to control and configure the addon's behavior.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-imports.md\" />\n\n{/* prettier-ignore-end */}\n\n### addons.add()\n\nThe `add` method allows you to register the type of UI component associated with the addon (e.g., panels, toolbars, tabs). For a minimum viable Storybook addon, you should provide the following arguments:\n\n* `type`: The type of UI component to register.\n* `title`: The title to feature in the Addon Panel.\n* `render`: The function that renders the addon's UI component.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-panel-initial.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  The render function is called with `active`. The `active` value will be true when the panel is focused on the UI.\n</Callout>\n\n### addons.register()\n\nServes as the entry point for all addons. It allows you to register an addon and access the Storybook [API](#storybook-api). For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-register.md\" />\n\n{/* prettier-ignore-end */}\n\nNow you'll get an instance to our StorybookAPI. See the [api docs](#storybook-api) for Storybook API regarding using that.\n\n### addons.getChannel()\n\nGet an instance to the channel to communicate with the manager and the preview. You can find this in both the addon register code and your addon’s wrapper component (where used inside a story).\n\nIt has a NodeJS [EventEmitter](https://nodejs.org/api/events.html) compatible API. So, you can use it to emit events and listen to events.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-getchannel.md\" />\n\n{/* prettier-ignore-end */}\n\n### makeDecorator\n\nUse the `makeDecorator` API to create decorators in the style of the official addons. Like so:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-makedecorator.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  If the story's parameters include `{ exampleParameter: { disable: true } }` (where `exampleParameter` is the `parameterName` of your addon), your decorator will not be called.\n</Callout>\n\nThe `makeDecorator` API requires the following arguments:\n\n* `name`: Unique name to identify the custom addon decorator.\n* `parameterName`: Sets a unique parameter to be consumed by the addon.\n* `skipIfNoParametersOrOptions`: (Optional) Doesn't run the decorator if the user hasn't options either via [decorators](../writing-stories/decorators.mdx) or [parameters](../writing-stories/parameters.mdx).\n* `wrapper`: your decorator function. Takes the `getStory`, `context`, and both the `options` and `parameters` (as defined in `skipIfNoParametersOrOptions` above).\n\n***\n\n## Storybook API\n\nStorybook's API allows you to access different functionalities of Storybook UI.\n\n### api.selectStory()\n\nThe `selectStory` API method allows you to select a single story. It accepts the following two parameters; story kind name and an optional story name. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-with-addon-example.md\" />\n\n{/* prettier-ignore-end */}\n\nThis is how you can select the above story:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-selectstory.md\" />\n\n{/* prettier-ignore-end */}\n\n### api.selectInCurrentKind()\n\nSimilar to the `selectStory` API method, but it only accepts the story as the only parameter.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-selectincurrentkind.md\" />\n\n{/* prettier-ignore-end */}\n\n### api.setQueryParams()\n\nThis method allows you to set query string parameters. You can use that as temporary storage for addons. Here's how you define query params:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-setqueryparams.md\" />\n\n{/* prettier-ignore-end */}\n\nAdditionally, if you need to remove a query parameter, set it as `null` instead of removing them from the addon. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-disablequeryparams.md\" />\n\n{/* prettier-ignore-end */}\n\n### api.getQueryParam()\n\nAllows retrieval of a query parameter enabled via the `setQueryParams` API method. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-getqueryparam.md\" />\n\n{/* prettier-ignore-end */}\n\n### api.getUrlState(overrideParams)\n\nThis method allows you to get the application URL state, including any overridden or custom parameter values. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-geturlstate.md\" />\n\n{/* prettier-ignore-end */}\n\n### api.getStoryHrefs(storyId, options?)\n\nGet the manager and preview URLs for a story. URLs are relative to the current Storybook, unless `base` is set, or in case of previewHref with `refId` set.\n\n- `storyId` (required): The ID of the story to get the URLs for\n- `options` (optional):\n  - `base`: Return an absolute href based on the current origin or network address.\n  - `inheritArgs`: Inherit args from the current URL. If `storyId` matches current story, `inheritArgs` defaults to true.\n  - `inheritGlobals`: Inherit globals from the current URL. Defaults to true.\n  - `queryParams`: Additional query params to append to the URL (`args` and `globals` are merged when inheriting).\n  - `refId`: ID of the ref to get the URL for (for composed Storybooks)\n  - `viewMode`: The view mode to use, defaults to 'story'.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-getstoryhrefs.md\" />\n\n{/* prettier-ignore-end */}\n\n### api.on(eventName, fn)\n\nThis method allows you to register a handler function called whenever the user navigates between stories.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-on.md\" />\n\n{/* prettier-ignore-end */}\n\n### api.openInEditor(payload)\n\nOpens a file in the configured code editor. Useful for \"Edit in IDE\" functionality in addons.\n\n- `payload.file`: The file path to open (required)\n- `payload.line`: Optional line number to jump to\n- `payload.column`: Optional column number to jump to\n\nReturns a Promise that resolves with information about whether the operation was successful.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-openineditor.md\" />\n\n{/* prettier-ignore-end */}\n\n### api.getCurrentStoryData()\n\nReturns the current story's data, including its ID, kind, name, and parameters.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-getcurrentstorydata.md\" />\n\n{/* prettier-ignore-end */}\n\n### api.toggleFullscreen(toggled?)\n\nToggles the fullscreen mode of the Storybook UI. Pass `true` to enable fullscreen, `false` to disable, or omit to toggle the current state.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-togglefullscreen.md\" />\n\n{/* prettier-ignore-end */}\n\n### api.togglePanel(toggled?)\n\nToggles the visibility of the addon panel. Pass `true` to show the panel, `false` to hide, or omit to toggle the current state.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-togglepanel.md\" />\n\n{/* prettier-ignore-end */}\n\n### api.addNotification(notification)\n\nDisplays a notification in the Storybook UI. The notification object should contain `id`, `content`, and optionally `duration` and `icon`.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-addnotification.md\" />\n\n{/* prettier-ignore-end */}\n\n### addons.setConfig(config)\n\nThis method allows you to override the default Storybook UI configuration (e.g., set up a [theme](../configure/user-interface/theming.mdx) or hide UI elements):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-config-layout.md\" />\n\n{/* prettier-ignore-end */}\n\nThe following table details how to use the API values:\n\n| Name                  | Type            | Description                                             | Example Value                         |\n| --------------------- | --------------- | ------------------------------------------------------- | ------------------------------------- |\n| **navSize**           | Number (pixels) | The size of the sidebar that shows a list of stories    | `300`                                 |\n| **bottomPanelHeight** | Number (pixels) | The size of the addon panel when in the bottom position | `200`                                 |\n| **rightPanelWidth**   | Number (pixels) | The size of the addon panel when in the right position  | `200`                                 |\n| **panelPosition**     | String          | Where to show the addon panel                           | `'bottom'` or `'right'`               |\n| **enableShortcuts**   | Boolean         | Enable/disable shortcuts                                | `true`                                |\n| **showToolbar**       | Boolean         | Show/hide toolbar                                       | `true`                                |\n| **theme**             | Object          | Storybook Theme, see next section                       | `undefined`                           |\n| **selectedPanel**     | String          | Id to select an addon panel                             | `storybook/actions/panel`             |\n| **initialActive**     | String          | Select the default active tab on Mobile                 | `sidebar` or `canvas` or `addons`     |\n| **sidebar**           | Object          | Sidebar options, see below                              | `{ showRoots: false }`                |\n| **toolbar**           | Object          | Modify the tools in the toolbar using the addon id      | `{ fullscreen: { hidden: false } }`   |\n\nThe following options are configurable under the `sidebar` namespace:\n\n| Name               | Type     | Description                                                   | Example Value                                         |\n| ------------------ | -------- | ------------------------------------------------------------- | ----------------------------------------------------- |\n| **showRoots**      | Boolean  | Display the top-level nodes as a \"root\" in the sidebar        | `false`                                               |\n| **collapsedRoots** | Array    | Set of root node IDs to visually collapse by default          | `['misc', 'other']`                                   |\n| **renderLabel**    | Function | Create a custom label for tree nodes; must return a ReactNode | `(item, api) => <abbr title=\"...\">{item.name}</abbr>` |\n\nThe following options are configurable under the `toolbar` namespace:\n\n| Name      | Type   | Description                                                          | Example Value       |\n| --------- | ------ | -------------------------------------------------------------------- | ------------------- |\n| **[id]**  | String | Toggle visibility for a specific toolbar item (e.g. `title`, `zoom`) | `{ hidden: false }` |\n\n***\n\n## Storybook hooks\n\nTo help streamline addon development and reduce boilerplate code, the API exposes a set of hooks to access Storybook's internals. These hooks are an extension of the `storybook/manager-api` module.\n\n### useStorybookState\n\nIt allows access to Storybook's internal state. Similar to the [`useglobals`](#useglobals) hook, we recommend optimizing your addon to rely on [`React.memo`](https://react.dev/reference/react/memo), or the following hooks; [`useMemo`](https://react.dev/reference/react/useMemo), [`useCallback`](https://react.dev/reference/react/useCallback) to prevent a high volume of re-render cycles.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-usestorybookstate.md\" />\n\n{/* prettier-ignore-end */}\n\n### useStorybookApi\n\nThe `useStorybookApi` hook is a convenient helper to allow you full access to the [Storybook API](#storybook-api) methods.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-useapi.md\" />\n\n{/* prettier-ignore-end */}\n\n### useChannel\n\nAllows setting subscriptions to events and getting the emitter to emit custom events to the channel.\n\nThe messages can be listened to on both the iframe and the manager.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-usechannel.md\" />\n\n{/* prettier-ignore-end */}\n\n### useAddonState\n\nThe `useAddonState` is a useful hook for addons that require data persistence, either due to Storybook's UI lifecycle or for more complex addons involving multiple types (e.g., toolbars, panels).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-useaddonstate.md\" />\n\n{/* prettier-ignore-end */}\n\n### useParameter\n\nThe `useParameter` retrieves the current story's parameters. If the parameter's value is not defined, it will automatically default to the second value defined.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-useparameter.md\" />\n\n{/* prettier-ignore-end */}\n\n### useGlobals\n\nExtremely useful hook for addons that rely on Storybook [Globals](../essentials/toolbars-and-globals.mdx). It allows you to obtain and update `global` values. We also recommend optimizing your addon to rely on [`React.memo`](https://react.dev/reference/react/memo), or the following hooks; [`useMemo`](https://react.dev/reference/react/useMemo), [`useCallback`](https://react.dev/reference/react/useCallback) to prevent a high volume of re-render cycles.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-api-useglobal.md\" />\n\n{/* prettier-ignore-end */}\n\n### useArgs\n\nHook that allows you to retrieve or update a story's [`args`](../writing-stories/args.mdx).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"args-usage-with-addons.md\" />\n\n{/* prettier-ignore-end */}\n\n**Learn more about the Storybook addon ecosystem**\n\n* [Types of addons](./addon-types.mdx) for other types of addons\n* [Writing addons](./writing-addons.mdx) for the basics of addon development\n* [Presets](./writing-presets.mdx) for preset development\n* [Integration catalog](./integration-catalog.mdx) for requirements and available recipes\n* API reference to learn about the available APIs\n"
  },
  {
    "path": "docs/addons/configure-addons.mdx",
    "content": "---\ntitle: 'Configure and communicate with an addon'\nsidebar:\n  order: 3\n  title: Configure addons\n---\n\nThe addon API is designed for customization. It offers addon authors different ways to configure and communicate with their users' Storybook. Let's look at what these are and their suggested use cases.\n\n## Preset\n\nPresets offload the burden of configuration from the user to the addon. Preset options are global and are accessible from NodeJS. They're ideal for pre-configuring Webpack loaders, Babel plugins, and other library or framework-specific configurations.\n\nFor example, many libraries require that the app be wrapped by a `Provider` which *provides* data to components down the tree. Presets can describe behavior like adding wrappers automatically, without users having to do any manual configuration. If a user installs an addon that has Presets, the addon can instruct Storybook to wrap all stories in `Provider`. This allows folks to start using your library with Storybook, with just 1 line of config!\n\nFor more on presets, see: [Write a preset addon](./writing-presets.mdx)\n\nThe mechanism for wrapping each story is referred to as a Storybook [decorator](../writing-stories/decorators.mdx). They allow you to augment stories with extra rendering functionality or by providing data.\n\n## Parameters\n\nParameters are available in the browser and are great for configuring addon behavior globally, at the component level, or at the story level.\n\nFor example, the [Pseudo States addon](https://storybook.js.org/addons/storybook-addon-pseudo-states) uses parameters to enable the various pseudo-states. Users can provide global defaults and then override them at the story level.\n\nUse the [`useParameter`](./addons-api.mdx#useparameter) hook to access the parameter values within your addon.\n\n```js\nexport const Hover = {\n  render: () => <Button>Label</Button>,\n  parameters: { pseudo: { hover: true } },\n};\n```\n\n## Channels\n\nChannels enable two-way communication between the manager and the preview pane, using a NodeJS [EventEmitter](https://nodejs.org/api/events.html) compatible API. Your addons can plug into specific channels and respond to these events.\n\nFor example, [Actions](https://storybook.js.org/docs/essentials/actions) captures user events and displays their data in a panel.\n\nUse the [`useChannel`](./addons-api.mdx#usechannel) hook to access the channel data within your addon.\n\nFor a complete example, check out [storybookjs/addon-kit/withRoundTrip.ts](https://github.com/storybookjs/addon-kit/blob/main/src/withRoundTrip.ts)\n"
  },
  {
    "path": "docs/addons/index.mdx",
    "content": "---\ntitle: 'Introduction to addons'\nhideRendererSelector: true\nsidebar:\n  order: 9\n  title: Addons\n---\n\nAddons extend Storybook with features and integrations that are not built into the core. Most Storybook features are implemented as addons. For instance: [documentation](../writing-docs/index.mdx), [accessibility testing](../writing-tests/accessibility-testing.mdx), [interactive controls](../essentials/controls.mdx), among others.\nThe [addon API](./addons-api.mdx) makes it easy for you to configure and customize Storybook in new ways. There are countless addons made by the community that unlocks time-saving workflows.\n\nBrowse our [addon catalog](https://storybook.js.org/addons) to install an existing addon or as inspiration for your own addon.\n\n## Storybook basics\n\nBefore writing your first [addon](https://storybook.js.org/addons), let’s take a look at the basics of Storybook’s architecture. While Storybook presents a unified user interface, under the hood it’s divided down the middle into **Manager** and **Preview**.\n\nThe **Manager** is the UI responsible for rendering the:\n\n* 🔍 Search\n* 🧭 Navigation\n* 🔗 Toolbars\n* 📦 Addons\n\nThe **Preview** area is an `iframe` where your stories are rendered.\n\n![Storybook detailed window](../_assets/addons/manager-preview.png)\n\nBecause both elements run in their own separate `iframes`, they use a communication channel to keep in sync. For example, when you select a story in the Manager an event is dispatched across the channel notifying the Preview to render the story.\n\n## Anatomy of an addon\n\nStorybook addons allow you to extend what's already possible with Storybook, everything from the [user interface](./addon-types.mdx) to the [API](./addons-api.mdx). Each one is classified into two broader categories.\n\n### UI-based addons\n\n[UI-based addons](./addon-types.mdx#ui-based-addons) focus on customizing Storybook's user interface to extend your development workflow. Examples of UI-based addons include: [Controls](../essentials/controls.mdx), [Docs](../writing-docs/index.mdx) and [Accessibility](../writing-tests/accessibility-testing.mdx).\n\n[Learn how to write an addon »](./writing-addons.mdx)\n\n### Preset addons\n\n[Preset addons](./addon-types.mdx#preset-addons) help you integrate Storybook with other technologies and libraries. An examples of a preset addons is [preset-create-react-app](https://github.com/storybookjs/presets/tree/master/packages/preset-create-react-app).\n\n[Learn how to write a preset addon »](./writing-presets.mdx)\n"
  },
  {
    "path": "docs/addons/install-addons.mdx",
    "content": "---\ntitle: 'Install addons'\nsidebar:\n  order: 1\n  title: Install\n---\n\nStorybook has [hundreds of reusable addons](https://storybook.js.org/integrations) packaged as NPM modules. Let's walk through how to extend Storybook by installing and registering addons.\n\n## Automatic installation\n\nStorybook includes a [`storybook add`](../api/cli-options.mdx#add) command to automate the setup of addons. Several community-led addons can be added using this command, except for preset addons. We encourage you to read the addon's documentation to learn more about its installation process.\n\nRun the `storybook add` command using your chosen package manager, and the CLI will update your Storybook configuration to include the addon and install any necessary dependencies.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-add-command.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"warning\">\n  If you're attempting to install multiple addons at once, it will only install the first addon that was specified. This is a known limitation of the current implementation and will be addressed in a future release.\n</Callout>\n\n### Manual installation\n\nStorybook addons are always added through the [`addons`](../api/main-config/main-config-addons.mdx) configuration array in [`.storybook/main.js|ts`](../configure/index.mdx). The following example shows how to manually add the [Accessibility addon](https://storybook.js.org/addons/@storybook/addon-a11y) to Storybook.\n\nRun the following command with your package manager of choice to install the addon.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"addon-a11y-install.md\" />\n\n{/* prettier-ignore-end */}\n\nNext, update `.storybook/main.js|ts` to the following:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"addon-a11y-register.md\" />\n\n{/* prettier-ignore-end */}\n\nWhen you run Storybook, the accessibility testing addon will be enabled.\n\n![Storybook addon installed and registered](../_assets/addons/storybook-addon-installed-registered.png)\n\n### Removing addons\n\nTo remove an addon from Storybook, you can choose to manually uninstall it and remove it from the configuration file (i.e., [`.storybook/main.js|ts`](../configure/index.mdx)) or opt-in to do it automatically via the CLI with the [`remove`](../api/cli-options.mdx#remove) command. For example, to remove the [Accessibility addon](https://storybook.js.org/addons/@storybook/addon-a11y) from Storybook with the CLI, run the following command:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-remove-command.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/addons/integration-catalog.mdx",
    "content": "---\ntitle: 'Add to the integration catalog'\nsidebar:\n  order: 5\n  title: Add to catalog\n---\n\nStorybook has two types of integrations, addons and recipes, which are listed in the [integration catalog](https://storybook.js.org/integrations/).\n\n## Addons\n\nStorybook addons are distributed via npm. The catalog is populated by querying npm's registry for Storybook-specific metadata in `package.json`.\n\nAdd your addon to the catalog by publishing a npm package that follows these requirements:\n\n* `package.json` with [module information](./writing-addons.mdx#setup) and [addon metadata](#addon-metadata)\n* `README.md` file with installation and configuration instructions\n* `/dist` directory containing transpiled ES5 code\n* `preset.js` file written as an ES5 module at the root level\n\n<Callout variant=\"info\" icon=\"💡\">\n  Get a refresher on how to [write a Storybook addon](./writing-addons.mdx).\n</Callout>\n\n### Addon metadata\n\nWe rely on metadata to organize your addon in the catalog. You must add the <code>storybook-addon</code> as the first keyword, followed by your addon's category. Additional keywords will be used in search and as tags.\n\n| Property      | Description                            | Example                                                                   |\n| ------------- | -------------------------------------- | ------------------------------------------------------------------------- |\n| `name`        | Addon package name                     | storybook-addon-example                                                   |\n| `description` | Addon description                      | Outline all elements with CSS to help with layout placement and alignment |\n| `author`      | Name of the author                     | winkerVSbecks                                                             |\n| `keywords`    | List of keywords to describe the addon | `[\"storybook-addon\",\"style\",\"debug\"]`                                    |\n| `repository`  | Addon repository                       | `{\"type\": \"git\",\"url\": \"https://github.com/someone/my-addon\" }`           |\n\nCustomize your addon's appearance by adding the `storybook` property with the following fields.\n\n| Property                | Description                                               | Example                               |\n| ----------------------- | --------------------------------------------------------- | ------------------------------------- |\n| `displayName`           | Display name                                              | Example                               |\n| `icon`                  | Link to custom icon for the addon (SVG are not supported) | https://yoursite.com/addon-icon.png   |\n| `unsupportedFrameworks` | List of unsupported frameworks                            | `[\"vue\"]`                             |\n| `supportedFrameworks`   | List of supported frameworks                              | `[\"react\", \"angular\"]`                |\n\nUse the list below as a reference when filling in the values for both the `supportedFrameworks` and `unsupportedFrameworks` fields.\n\n* react\n* vue\n* angular\n* web-components\n* ember\n* html\n* svelte\n* preact\n* react-native\n\n<Callout variant=\"info\" icon=\"💡\">\n  Make sure to copy each item **exactly** as listed so that we can properly index your addon in our catalog.\n</Callout>\n\n```json title=\"package.json\"\n{\n  \"name\": \"storybook-addon-example\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Outline all elements with CSS to help with layout placement and alignment\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/chromaui/storybook-addon-example\"\n  },\n  \"author\": \"winkerVSbecks\",\n  \"keywords\": [\"storybook-addon\", \"style\", \"debug\", \"layout\", \"css\"],\n  \"storybook\": {\n    \"displayName\": \"Outline\",\n    \"unsupportedFrameworks\": [\"vue\"],\n    \"supportedFrameworks\": [\"react\", \"angular\"],\n    \"icon\": \"https://yoursite.com/addon-icon.png\"\n  }\n}\n```\n\nThe `package.json` above appears like below in the catalog. See an example of a production package.json [here](https://github.com/chromaui/storybook-outline/blob/main/package.json).\n\n![Storybook addon in the catalog](../_assets/addons/addon-display.png)\n\n#### How long does it take for my addon to show up in the catalog?\n\nOnce you publish the addon, it will appear in the catalog. There may be a delay between the time you publish your addon and when it's listed in the catalog. If your addon doesn't show up within 24 hours, [open an issue](https://github.com/storybookjs/frontpage/issues).\n\n## Recipes\n\nRecipes are a set of instructions to integrate third-party libraries into Storybook in cases where an addon does not exist or the integration requires some manual effort.\n\n### Who owns them?\n\nRecipes are written and maintained by the Storybook team. We create recipes based on community popularity, tool maturity, and stability of the integration. Our goal is to ensure that recipes continue to work over time.\n\nNot finding the recipe that you want? If it's popular in the community, our docs team will write one. In the mean time, try searching for a solution — it's likely that someone has the same requirements as you do. You can also help us out by writing recipes on your own site which speeds up the research process.\n\n### Request a recipe\n\nIf you'd like to request a recipe, open a [new discussion](https://github.com/storybookjs/storybook/discussions/new?category=ideas) in our GitHub repo. We'll review your request, and if it's popular, we'll add it to our backlog and prioritize it.\n\n**Learn more about the Storybook addon ecosystem**\n\n* [Types of addons](./addon-types.mdx) for other types of addons\n* [Writing addons](./writing-addons.mdx) for the basics of addon development\n* [Presets](./writing-presets.mdx) for preset development\n* Integration catalog for requirements and available recipes\n* [API reference](./addons-api.mdx) to learn about the available APIs\n"
  },
  {
    "path": "docs/addons/writing-addons.mdx",
    "content": "---\ntitle: 'Write an addon'\nsidebar:\n  order: 2\n  title: Write\n---\n\nStorybook addons are a powerful way to extend Storybook's functionality and customize the development experience. They can be used to add new features, customize the UI, or integrate with third-party tools.\n\n## What are we going to build?\n\nThis reference guide is to help you develop a mental model for how Storybook addons work by building a simple addon based on the popular [Outline addon](https://storybook.js.org/addons/@storybook/addon-outline/) (which is the historical basis for the built-in [outline feature](../essentials/measure-and-outline.mdx#outline)). Throughout this guide, you'll learn how addons are structured, Storybook's APIs, how to test your addon locally, and how to publish it.\n\n![Fully implemented Storybook addon](../_assets/addons/storybook-addon-finished-state.png)\n\n## Addon anatomy\n\nThere are two main categories of addons, each with its role:\n\n- **UI-based**: These addons are responsible for customizing the interface, enabling shortcuts for common tasks, or displaying additional information in the UI.\n- **Presets**: [These](./writing-presets.mdx) are pre-configured settings or configurations that enable developers to quickly set up and customize their environment with a specific set of features, functionality, or technology.\n\n### UI-based addons\n\nThe addon built in this guide is a UI-based addon, specifically a [toolbar](./addon-types.mdx#toolbars) addon, enabling users to draw outlines around each element in the story through a shortcut or click of a button. UI addons can create other types of UI elements, each with its function: [panels](./addon-types.mdx#panels) and [tabs](./addon-types.mdx#tabs), providing users with various ways to interact with the UI.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-toolkit-types.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\nAddons with a UI must use the same React version as Storybook. If your component library uses a different React version, you must use addons that are built and published as standalone packages. We'll cover how to do this with the [Addon Kit](https://github.com/storybookjs/addon-kit).\n</Callout>\n\n## Setup\n\nTo create your first addon, you're going to use the [Addon Kit](https://github.com/storybookjs/addon-kit), a ready-to-use template featuring all the required building blocks, dependencies and configurations to help you get started building your addon. In the Addon Kit repository, click the **Use this template** button to create a new repository based on the Addon Kit's code.\n\n<Video src=\"../_assets/addons/addon-kit-clone-repo.mp4\" />\n\nClone the repository you just created and install its dependencies. When the installation process finishes, you will be prompted with questions to configure your addon. Answer them, and when you're ready to start building your addon, run the following command to start Storybook in development mode and develop your addon in watch mode:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-run-dev-mode.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  The Addon Kit uses [Typescript](https://www.typescriptlang.org/) by default. If you want to use\n  JavaScript instead, you can run the `eject-ts` command to convert the project to JavaScript.\n</Callout>\n\n### Understanding the build system\n\nAddons built in the Storybook ecosystem rely on [tsup](https://tsup.egoist.dev/), a fast, zero-config bundler powered by [esbuild](https://esbuild.github.io/) to transpile your addon's code into modern JavaScript that can run in the browser. Out of the box, the Addon Kit comes with a pre-configured `tsup` configuration file that you can use to customize the build process of your addon.\n\nWhen the build scripts run, it will look for the configuration file and pre-bundle the addon's code based on the configuration provided. Addons can interact with Storybook in various ways. They can define presets to modify the configuration, add behavior to the manager UI, or add behavior to the preview iframe. These different use cases require different bundle outputs because they target different runtimes and environments. Presets are executed in a Node environment. Storybook's manager and preview environments provide certain packages in the global scope, so addons don't need to bundle them or include them as dependencies in their `package.json` file.\n\nThe `tsup` configuration handles these complexities by default, but you can customize it according to their requirements. For a detailed explanation of the bundling techniques used, please refer to [the README of the addon-kit](https://github.com/storybookjs/addon-kit#bundling), and check out the default `tsup` configuration [here](https://github.com/storybookjs/addon-kit/blob/main/tsup.config.ts).\n\n## Register the addon\n\nBy default, code for the UI-based addons is located in one of the following files, depending on the type of addon built: **`src/Tool.tsx`**, **`src/Panel.tsx`**, or **`src/Tab.tsx`**. Since we're building a toolbar addon, we can safely remove the `Panel` and `Tab` files and update the remaining file to the following:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-tool-initial-setup.md\" />\n\n{/* prettier-ignore-end */}\n\nGoing through the code blocks in sequence:\n\n```ts title=\"src/Tool.tsx\"\nimport { useGlobals, useStorybookApi } from 'storybook/manager-api';\nimport { Button } from 'storybook/internal/components';\nimport { LightningIcon } from '@storybook/icons';\n```\n\nThe [`useGlobals`](./addons-api.mdx#useglobals) and [`useStorybookApi`](./addons-api.mdx#usestorybookapi) hooks from the `manager-api` package are used to access the Storybook's APIs, allowing users to interact with the addon, such as enabling or disabling it.\n\nThe `Button` component from the `storybook/internal/components` module can be used to render the buttons in the toolbar. The [`@storybook/icons`](https://github.com/storybookjs/icons) package provides a large set of appropriately sized and styled icons to choose from.\n\n```ts title=\"src/Tool.tsx\"\nexport const Tool = memo(function MyAddonSelector() {\n  const [globals, updateGlobals] = useGlobals();\n  const api = useStorybookApi();\n\n  const isActive = [true, 'true'].includes(globals[PARAM_KEY]);\n\n  const toggleMyTool = useCallback(() => {\n    updateGlobals({\n      [PARAM_KEY]: !isActive,\n    });\n  }, [isActive]);\n\n  useEffect(() => {\n    api.setAddonShortcut(ADDON_ID, {\n      label: 'Toggle Addon [8]',\n      defaultShortcut: ['8'],\n      actionName: 'myaddon',\n      showInMenu: false,\n      action: toggleMyTool,\n    });\n  }, [toggleMyTool, api]);\n\n  return (\n    <Button\n      padding=\"small\"\n      variant=\"ghost\"\n      key={TOOL_ID}\n      active={isActive}\n      ariaLabel=\"Enable my addon\"\n      onClick={toggleMyTool}\n    >\n      <LightningIcon />\n    </Button>\n  );\n});\n```\n\nThe `Tool` component is the entry point of the addon. It renders the UI elements in the toolbar, registers a keyboard shortcut, and handles the logic to enable and disable the addon.\n\nMoving onto the manager, here we register the addon with Storybook using a unique name and identifier. Since we've removed the `Panel` and `Tab` files, we'll need to adjust the file to only reference the addon we're building.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-manager-initial-state.md\" />\n\n{/* prettier-ignore-end */}\n\n### Conditionally render the addon\n\nNotice the `match` property. It allows you to control the view mode (story or docs) and tab (the story canvas or [custom tabs](./addon-types.mdx#tabs)) where the toolbar addon is visible. For example:\n\n- `({ tabId }) => tabId === 'my-addon/tab'` will show your addon when viewing the tab with the ID `my-addon/tab`.\n- `({ viewMode }) => viewMode === 'story'` will show your addon when viewing a story in the canvas.\n- `({ viewMode }) => viewMode === 'docs'` will show your addon when viewing the documentation for a component.\n- `({ tabId, viewMode }) => !tabId && viewMode === 'story'` will show your addon when viewing a story in the canvas and not in a custom tab (i.e. when `tabId === undefined`).\n\nRun the `start` script to build and start Storybook and verify that the addon is registered correctly and showing in the UI.\n\n![Addon registered in the toolbar](../_assets/addons/storybook-addon-initial-state.png)\n\n### Style the addon\n\nIn Storybook, applying styles for addons is considered a side-effect. Therefore, we'll need to make some changes to our addon to allow it to use the styles when it is active and remove them when it's disabled. We're going to rely on two of Storybook's features to handle this: [decorators](../writing-stories/decorators.mdx) and [globals](../essentials/toolbars-and-globals.mdx#globals). To handle the CSS logic, we must include some helper functions to inject and remove the stylesheets from the DOM. Start by creating the helper file with the following content:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-css-helpers.md\" />\n\n{/* prettier-ignore-end */}\n\nNext, create the file with the styles we want to inject with the following content:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-css-example.md\" />\n\n{/* prettier-ignore-end */}\n\nSince the addon can be active in both the story and documentation modes, the DOM node for Storybook's preview `iframe` is different in these two modes. In fact, Storybook renders multiple story previews on one page when in documentation mode. Therefore, we'll need to choose the correct selector for the DOM node where the styles will be injected and ensure the CSS is scoped to that particular selector. That mechanism is provided as an example within the `src/withGlobals.ts` file, which we'll use to connect the styling and helper functions to the addon logic. Update the file to the following:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-use-global.md\" />\n\n{/* prettier-ignore-end */}\n\n## Packaging and publishing\n\nStorybook addons, similar to most packages in the JavaScript ecosystem, are distributed as NPM packages. However, they have specific criteria that need to be met to be published to NPM and crawled by the integration catalog:\n\n1. Have a `dist` folder with the transpiled code.\n2. A `package.json` file declaring:\n   - Module-related information\n   - Integration catalog metadata\n\n### Module Metadata\n\nThe first category of metadata is related to the addon itself. This includes the entry for the module, which files to include when the addon is published. And the required configuration to integrate the addon with Storybook, allowing it to be used by its consumers.\n\n```json title=\"package.json\"\n{\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"node\": \"./dist/index.js\",\n      \"require\": \"./dist/index.js\",\n      \"import\": \"./dist/index.mjs\"\n    },\n    \"./manager\": \"./dist/manager.mjs\",\n    \"./preview\": \"./dist/preview.mjs\",\n    \"./package.json\": \"./package.json\"\n  },\n  \"main\": \"dist/index.js\",\n  \"module\": \"dist/index.mjs\",\n  \"types\": \"dist/index.d.ts\",\n  \"files\": [\"dist/**/*\", \"README.md\", \"*.js\", \"*.d.ts\"],\n  \"devDependencies\": {\n    \"@storybook/addon-docs\": \"^9.0.0\",\n    \"storybook\": \"^9.0.0\"\n  },\n  \"bundler\": {\n    \"exportEntries\": [\"src/index.ts\"],\n    \"managerEntries\": [\"src/manager.ts\"],\n    \"previewEntries\": [\"src/preview.ts\"]\n  }\n}\n```\n\n### Integration Catalog Metadata\n\nThe second metadata category is related to the [integration catalog](https://storybook.js.org/integrations). Most of this information is already pre-configured by the Addon Kit. However, items like the display name, icon, and frameworks must be configured via the `storybook` property to be displayed in the catalog.\n\n```json title=\"package.json\"\n{\n  \"name\": \"my-storybook-addon\",\n  \"version\": \"1.0.0\",\n  \"description\": \"My first storybook addon\",\n  \"author\": \"Your Name\",\n  \"storybook\": {\n    \"displayName\": \"My Storybook Addon\",\n    \"unsupportedFrameworks\": [\"react-native\"],\n    \"icon\": \"https://yoursite.com/link-to-your-icon.png\"\n  },\n  \"keywords\": [\"storybook-addon\", \"appearance\", \"style\", \"css\", \"layout\", \"debug\"]\n}\n```\n\n<Callout variant=\"info\">\n  The `storybook` configuration element includes additional properties that help customize the\n  addon's searchability and indexing. For more information, see the [Integration catalog\n  documentation](./integration-catalog.mdx).\n</Callout>\n\nOne essential item to note is the `keywords` property as it maps to the catalog's tag system. Adding the `storybook-addon` keyword ensures that the addon is discoverable in the catalog when searching for addons. The remaining keywords help with the searchability and categorization of the addon.\n\n### Publishing to NPM\n\nOnce you're ready to publish your addon to NPM, the Addon Kit comes pre-configured with the [Auto](https://github.com/intuit/auto) package for release management. It generates a changelog and uploads the package to NPM and GitHub automatically. Therefore, you need to configure access to both.\n\n1. Authenticate using [npm adduser](https://docs.npmjs.com/cli/v9/commands/npm-adduser)\n2. Generate a [access token](https://docs.npmjs.com/creating-and-viewing-access-tokens#creating-access-tokens) with both `read` and `publish` permissions.\n3. Create a [personal access token](https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token) with `repo` and `workflow` scoped permissions.\n4. Create a `.env` file in the root of your project and add the following:\n\n```plaintext\nGH_TOKEN=value_you_just_got_from_github\nNPM_TOKEN=value_you_just_got_from_npm\n```\n\nNext, run the following command to create labels on GitHub. You'll use these labels to categorize changes to the package.\n\n```shell\nnpx auto create-labels\n```\n\nFinally, run the following command to create a release for your addon. This will build and package the addon code, bump the version, push the release into GitHub and npm, and generate a changelog.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-release.md\" />\n\n{/* prettier-ignore-end */}\n\n### CI automation\n\nBy default, the Addon Kit comes pre-configured with a GitHub Actions workflow, enabling you to automate the release management process. This ensures that the package is always up to date with the latest changes and that the changelog is updated accordingly. However, you'll need additional configuration to use your NPM and GitHub tokens to publish the package successfully. In your repository, click the **Settings** tab, then the **Secrets and variables** dropdown, followed by the **Actions** item. You should see the following screen:\n\n![GitHub secrets page](../_assets/addons/github-secrets-screen.png)\n\nThen, click the **New repository secret**, name it `NPM_TOKEN`, and paste the token you generated earlier. Whenever you merge a pull request to the default branch, the workflow will run and publish a new release, automatically incrementing the version number and updating the changelog.\n\n**Learn more about the Storybook addon ecosystem**\n\n- [Types of addons](./addon-types.mdx) for other types of addons\n- Writing addons for the basics of addon development\n- [Presets](./writing-presets.mdx) for preset development\n- [Integration catalog](./integration-catalog.mdx) for requirements and available recipes\n- [API reference](./addons-api.mdx) to learn about the available APIs\n"
  },
  {
    "path": "docs/addons/writing-presets.mdx",
    "content": "---\ntitle: 'Write a preset addon'\nsidebar:\n  order: 4\n  title: Write a preset\n---\n\nStorybook presets are pre-configured settings or configurations that enable developers quickly set up and customize their environment with a specific set of features, functionalities, or integrations.\n\n## How presets work\n\nPreset addons allow developers to compose various configuration options and plugins via APIs to integrate with Storybook and customize its behavior and functionality. Typically, presets are separated into two files, each with its specific role.\n\n### Local presets\n\nThis type of preset allows you to encapsulate and organize configurations specific to the addon, including [builder](../builders/index.mdx) support, [Babel](https://babeljs.io/), or third-party integrations. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-local-preset.md\" />\n\n{/* prettier-ignore-end */}\n\n### Root-level presets\n\nThis type of preset is user-facing and responsible for registering the addon without any additional configuration from the user by bundling Storybook-related features (e.g., [parameters](../writing-stories/parameters.mdx)) via the [`previewAnnotations`](../api/main-config/main-config-preview-annotations.mdx) and UI related features (e.g., addons) via the `managerEntries` API. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-root-preset.md\" />\n\n{/* prettier-ignore-end */}\n\n## Presets API\n\nWhen writing a preset, you can access a select set of APIs to interact with the Storybook environment, including the supported builders (e.g., Webpack, Vite), the Storybook configuration, and UI. Below are the available APIs you can use when writing a preset addon.\n\n### Babel\n\nTo customize Storybook's Babel configuration and add support for additional features, you can use the [`babelDefault`](../api/main-config/main-config-babel-default.mdx) API. It will apply the provided configuration ahead of any other user presets, which can be further customized by the end user via the [`babel`](../api/main-config/main-config-babel.mdx) configuration option. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-preset-babelDefault.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  The Babel configuration is only applied to frameworks that use Babel internally. If you enable it for a framework that uses a different compiler, like [SWC](https://swc.rs/) or [esbuild](https://esbuild.github.io/), it will be ignored.\n</Callout>\n\n### Builders\n\nBy default, Storybook provides support for the leading industry builders, including [Webpack](../builders/webpack.mdx) and [Vite](../builders/vite.mdx). If you need additional features for any of these builders, you can use APIs to extend the builder configuration based on your specific needs.\n\n#### Vite\n\nIf you are creating a preset and want to include Vite support, the `viteFinal` API can be used to modify the default configuration and enable additional features. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-preset-viteFinal.md\" />\n\n{/* prettier-ignore-end */}\n\n#### Webpack\n\nTo customize the Webpack configuration in Storybook to add support for additional file types, apply specific loaders, configure plugins, or make any other necessary modifications, you can use the `webpackFinal` API. Once invoked, it will extend the default Webpack configuration with the provided configuration. An example of this would be:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-preset-webpackFinal.md\" />\n\n{/* prettier-ignore-end */}\n\n### ManagerEntries\n\nIf you're writing a preset that loads third-party addons, which you may not have control over, but require access to specific features or additional configuration, you can use the `managerEntries` API. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-root-preset-manager-entries.md\" />\n\n{/* prettier-ignore-end */}\n\n### PreviewAnnotations\n\nIf you need additional settings to render stories for a preset, like [decorators](../writing-stories/decorators.mdx) or [parameters](../writing-stories/parameters.mdx), you can use the `previewAnnotations` API. For example, to apply a decorator to all stories, create a preview file that includes the decorator and make it available to the preset as follows:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addons-preset-preview.md\" />\n\n{/* prettier-ignore-end */}\n\n## Advanced configuration\n\nThe presets API is designed to be flexible and allow you to customize Storybook to your specific needs, including using presets for more advanced use cases without publishing them. In such cases, you can rely on a private preset. These private presets contain configuration options meant for development purposes and not for end-users. The `.storybook/main.js|ts` file is an example of such a private preset that empowers you to modify the behavior and functionality of Storybook.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-advanced-config-example.md\" />\n\n{/* prettier-ignore-end */}\n\n### Addons\n\nFor addon consumers, the [`managerEntries`](#managerentries) API can be too technical, making it difficult to use. To make it easier to add addons to Storybook, the preset API provides the [`addons`](../api/main-config/main-config-addons.mdx) API, which accepts an array of addon names and will automatically load them for you. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-register-example-addon.md\" />\n\n{/* prettier-ignore-end */}\n\nThe array of values supports references to additional presets and addons that should be included in the manager. Storybook will automatically detect whether the provided value is a preset or an addon and load it accordingly.\n\n### Entries\n\nEntries are the place to register entry points for the preview. This feature can be utilized to create a configure-storybook preset that automatically loads all `*.stories.js` files into Storybook, eliminating the need for users to copy-paste the same configuration repeatedly.\n\n### UI configuration\n\nThe Storybook preset API also provides access to the UI configuration, including the `head` and `body` HTML elements of the preview, configured by the [`previewHead`](../api/main-config/main-config-preview-head.mdx) and [`previewBody`](../api/main-config/main-config-preview-body.mdx) APIs. Both allow you to set up Storybook in a way that is similar to using the [`preview-head.html`](../configure/story-rendering.mdx#adding-to-head) and [`preview-body.html`](../configure/story-rendering.mdx#adding-to-body) files. These methods accept a string and return a modified version, injecting the provided content into the HTML element.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-preview.md\" />\n\n{/* prettier-ignore-end */}\n\nAdditionally, if you need to customize the manager (i.e., where Storybook’s search, navigation, toolbars, and addons render), you can use the [`managerHead`](../api/main-config/main-config-manager-head.mdx) to modify the UI, similar to how you would do it with the `manager-head.html` file. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-custom-manager-head.md\" />\n\n{/* prettier-ignore-end */}\n\nHowever, if you need, you can also customize the template used by Storybook to render the UI. To do so, you can use the `previewMainTemplate` API and provide a reference for a custom template created as a `ejs` file. For an example of how to do this, see the [template](https://github.com/storybookjs/storybook/blob/next/code/builders/builder-webpack5/templates/preview.ejs) used by the Webpack 5 builder.\n\n## Troubleshooting\n\n### Storybook doesn't load files in my preset\n\nAs Storybook relies on [esbuild](https://esbuild.github.io/) instead of Webpack to build the UI, presets that depend on the `managerWebpack` API to configure the manager or load additional files other than CSS or images will no longer work. We recommend removing it from your preset and adjusting your configuration to convert any additional files to JavaScript.\n\n**Learn more about the Storybook addon ecosystem**\n\n* [Types of addons](./addon-types.mdx) for other types of addons\n* [Writing addons](./writing-addons.mdx) for the basics of addon development\n* Presets for preset development\n* [Integration catalog](./integration-catalog.mdx) for requirements and available recipes\n* [API reference](./addons-api.mdx) to learn about the available APIs\n"
  },
  {
    "path": "docs/ai/best-practices.mdx",
    "content": "---\ntitle: Best practices for using Storybook with AI\nsidebar:\n  order: 2\n  title: Best practices\n---\n  \n<Callout variant=\"info\" icon=\"🧪\">\n  The best practices here relate to the [generated manifests](./manifests.mdx), which are currently only supported for [React](?renderer=react) projects.\n\n  Additionally, the API may change in future releases. We welcome feedback and contributions to help improve this feature.\n</Callout>\n\n<If renderer={['react']}>\n\nUse Storybook together with an AI agent effectively by following these best practices.\n\n## Writing effective stories\n\nStories are referenced by the [MCP server](./mcp/overview.mdx) to provide examples of how your components are used. They are also tested to ensure your components work as expected. Whenever possible, they should demonstrate one concept or use case, and be as descriptive about the \"why\" behind the story, not just the \"what\". This will help agents understand when and why to use certain components or patterns.\n\n<CodeSnippets path=\"best-practices-in-story.md\" />\n\nYou might be wondering how well an agent handles abstractions like [`args`](../writing-stories/args.mdx) or [decorators](../writing-stories/decorators.mdx). The manifest generation process evaluates the final rendered story with all args, decorators, etc. applied, so it can focus on the concept being demonstrated, rather than the specifics of how it's implemented.\n\n## Documenting your components\n\nTo reuse your components effectively, agents depend on how well you document their purpose, usage, and APIs. There are a few key aspects that are well worth taking the time to document (ask your agent to help!). To provide these details, you can use [JSDoc comments](https://jsdoc.app/about-getting-started) in your code, which Storybook will automatically extract and include in the generated [manifest](./manifests.mdx) for the agent.\n\nOf course, with [Autodocs](../writing-docs/autodocs.mdx), any documentation efforts you make will help human developers, too!\n\n### Component summary and description\n\nHelp the agent understand what a component should be used for by providing a description (and optional summary) as a JSDoc comment above the export of the component.\n\nThe agent will receive the summary, if present, or a truncated version of the description.\n\n```ts title=\"Button.tsx\"\n/**\n * Button is used for user interactions that do not navigate to another route.\n * For navigation, use [Link](?path=/docs/link--default) instead.\n *\n * @summary for user interactions that do not navigate to another route\n */\nexport const Button = // ...\n```\n\nYou can use Markdown syntax in your description to add formatting or links.\n\n### Story summary and descriptions\n\nSimilarly, you can provide descriptions (and summaries) for each story, which serve as usage examples for the agent. Don't just repeat what the story is demonstrating; describe _why_ you would use whatever is demonstrated.\n\nThe agent will receive the summary, if present, or the first 60 characters of the description.\n\n<CodeSnippets path=\"story-description-and-summary.md\" />\n\n### Prop type extraction\n\nWe highly recommend using `react-docgen-typescript` for prop type extraction (set with the [`reactDocgen`](../api/main-config/main-config-typescript.mdx#reactdocgen) config option), because it provides more accurate and comprehensive information about your components' props, which will help agents use them more effectively. If manifest generation seems too slow, you can switch to `react-docgen`, which is faster but less detailed.\n\n### Prop descriptions\n\nIt's also helpful to provide descriptions for your component's props in the JSDoc comments in your component code, as agents will use these to understand how to use the component effectively.\n\n```ts title=\"Button.tsx\"\nexport interface ButtonProps {\n  /** The icon to render before the button text */\n  icon?: ReactNode;\n}\n```\n\n## Docs summaries\n\nFor unattached MDX docs pages (such as documentation for design tokens, guidelines, etc.), you can provide a summary in the `Meta` tag, which will be included in the manifest and provided to the agent.\n\n```jsx title=\"Colors.mdx\"\nimport { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Design Tokens/Colors\" summary=\"A list of our color tokens, their usages, and guidelines for using them.\" />\n```\n\n## Docs content\n\nStorybook generates this docs manifest through static analysis of your MDX files, which means it is limited to the information that is explicitly present in those files. For example, the manifest will _not_ include the color tokens in the document below, because their values are not explicitly in the source:\n\n```jsx title=\"Colors.mdx\"\nimport { Meta, ColorPalette, ColorItem } from '@storybook/addon-docs/blocks';\nimport { colors } from '../src/tokens/colors';\n\n<Meta title=\"Design Tokens/Colors\" />\n\n# Colors\n\n{/* 👇 These colors are *not* included in the manifest, because their values are not explicitly in the source */}\n<ColorPalette>\n  {colors.map((color) => (\n    <ColorItem key={color.name} color={color.value} name={color.name} />\n  ))}\n</ColorPalette>\n```\n\nTo ensure that your agents have access to all the necessary information, it's important to include any relevant details directly in your MDX files, rather than referencing external sources.\n\nWe hope to improve this in the future, possibly by evaluating the MDX files and including the result in the manifest.\n\n## Manifest curation\n\nIt's possible to provide too little _or_ too much context to your agent. If your manifest is missing key information about your components, the agent may not be able to use them effectively. On the other hand, if your manifest includes information irrelevant to the task at hand, it may be overwhelming for the agent and lead to worse performance.\n\nFor stories or docs which the agent does not need to reference (e.g. a story demonstrating an anti-pattern or a docs page about deprecated components), you can exclude them from the manifest by removing the `manifest` [tag](../writing-stories/tags.mdx):\n\n<CodeSnippets path=\"tag-manifest-remove-in-story.md\" />\n\nYou can also remove an entire component from the manifest, by removing the tag in the meta (or default export) of the file, which will exclude all stories in that file from the manifests.\n\nSimilarly, to exclude an entire MDX docs page from the manifests, you can remove the `manifest` tag from the page's metadata:\n\n```jsx title=\"DocForHumansOnly.mdx\"\nimport { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Doc for Humans Only\" tags={['!manifest']} />\n```\n\n</If>\n{/* End supported renderers */}\n\n**More AI resources**\n\n- [MCP server overview](./mcp/overview.mdx)\n- [MCP server API](./mcp/api.mdx)\n- [Sharing your MCP server](./mcp/sharing.mdx)\n- [Manifests](./manifests.mdx)\n\n\n"
  },
  {
    "path": "docs/ai/index.mdx",
    "content": "---\ntitle: Using Storybook with AI\nsidebar:\n  order: 5\n  title: AI\n---\n  \n<Callout variant=\"info\" icon=\"🧪\">\n  While they are in [preview](../releases/features.mdx#preview), Storybook's AI capabilities (specifically, the [manifests](./manifests.mdx) and [MCP server](./mcp/overview.mdx)) are currently only supported for [React](?renderer=react) projects.\n\n  Additionally, the API may change in future releases. We welcome feedback and contributions to help improve this feature.\n</Callout>\n\n<If renderer={['react']}>\n\nWith Storybook's AI capabilities, you can leverage the power of AI agents to speed up your development workflow. By connecting your Storybook to an AI agent via the [Storybook MCP server](./mcp/overview.mdx), you can enable your agent to understand your components and documentation, generate stories, run tests, and more.\n\n## Get started\n\n### 1. Install the addon\n\nRun this command to install and register the Storybook MCP addon:\n\n<CodeSnippets path=\"addon-mcp-add.md\" />\n\nNow, when running Storybook's dev server, you can access the MCP server at `http://localhost:6006/mcp` (your port may be different). When viewed in the browser, you'll see a page showing which tools are available and a link to the [manifest debugger](./manifests.mdx#debugging).\n\n![The MCP server page in the browser](../_assets/ai/addon-mcp-splash.png)\n\n### 2. Add the MCP server to your agent\n\nThen run this command to configure your agent to use the MCP server:\n\n<CodeSnippets path=\"mcp-add.md\" />\n\nYou may need to update the port number in the URL. You will be prompted for a name for your MCP server (e.g. \"my-project-sb-mcp\"). This is the name you'll use when calling the tools from your agent, so choose something descriptive and unique to avoid confusion with other tools.\n\n[`mcp-add`](https://github.com/paoloricciuti/mcp-add) is a CLI tool designed to simplify adding MCP servers to various agents.\n\nYou can also follow your agent's documentation to add the MCP server as a tool provider manually, e.g. [Claude Code](https://code.claude.com/docs/en/mcp#option-1-add-a-remote-http-server), [Google Gemini CLI](https://geminicli.com/docs/tools/mcp-server/#adding-an-http-server), [OpenAI Codex](https://developers.openai.com/codex/mcp/), [VS Code Copilot](https://code.visualstudio.com/docs/copilot/customization/mcp-servers#_configure-the-mcpjson-file), etc.\n\n### 3. Adjust your agent instructions\n\nTo guide your agent to use your MCP server, you should adjust your [`AGENTS.md`](https://agents.md/) (or [`CLAUDE.md`](https://code.claude.com/docs/en/memory#claude-md-files), if you're using Claude). The specifics will depend on your project and how you use agents in your development process, but something like this is a good starting point. Just make sure to replace `your-project-sb-mcp` with the name you chose for your MCP server toolset in the previous step.\n\n<details>\n<summary>Example instructions for AGENTS.md</summary>\n\n```md title=\"AGENTS.md\"\nWhen working on UI components, always use the `your-project-sb-mcp` MCP tools to access Storybook's component and documentation knowledge before answering or taking any action.\n\n- **CRITICAL: Never hallucinate component properties!** Before using ANY property on a component from a design system (including common-sounding ones like `shadow`, etc.), you MUST use the MCP tools to check if the property is actually documented for that component.\n- Query `list-all-documentation` to get a list of all components\n- Query `get-documentation` for that component to see all available properties and examples\n- Only use properties that are explicitly documented or shown in example stories\n- If a property isn't documented, do not assume properties based on naming conventions or common patterns from other libraries. Check back with the user in these cases.\n- Use the `get-storybook-story-instructions` tool to fetch the latest instructions for creating or updating stories. This will ensure you follow current conventions and recommendations.\n- Check your work by running `run-story-tests`.\n\nRemember: A story name might not reflect the property name correctly, so always verify properties through documentation or example stories before using them.\n```\n\n</details>\n\nFinally, test your agent's access to the MCP server. First, make sure your Storybook is running, then run a prompt like \"List all documented components\". You should see a call to the [`list-all-documentation`](./mcp/overview.mdx#list-all-documentation) tool with a response listing components from your Storybook.\n\n## Key concepts\n\nUnderstanding these concepts will help you make the most of Storybook's AI capabilities and guide you in using the MCP server to enhance your development workflow.\n\n### Manifests\n\nStorybook collects all of the metadata about your components, stories, and docs into [manifests](./manifests.mdx). Each manifest is a JSON object that serves as a comprehensive map of your Storybook's content and structure. There are manifests for components, based on stories files, and for documentation, based on MDX files.\n\nThese manifests are automatically generated and updated as you work on your Storybook, ensuring that your agent always has access to the latest information about your project.\n\n### MCP server\n\n[Model Context Protocol](https://modelcontextprotocol.io/) (MCP) is a standard for communication between AI agents and external tools. Storybook's [MCP server](./mcp/index.mdx) exposes your Storybook's content and functionality as a set of tools that your agent can call to retrieve component information, generate stories, run component tests, and more.\n\n</If>\n{/* End supported renderers */}\n\n**More AI resources**\n\n- [MCP server overview](./mcp/overview.mdx)\n- [MCP server API](./mcp/api.mdx)\n- [Sharing your MCP server](./mcp/sharing.mdx)\n- [Best practices for using Storybook with AI](./best-practices.mdx)\n- [Manifests](./manifests.mdx)\n"
  },
  {
    "path": "docs/ai/manifests.mdx",
    "content": "---\ntitle: Manifests\nsidebar:\n  order: 3\n---\n\n<Callout variant=\"info\" icon=\"🧪\">\n  While they are in [preview](../releases/features.mdx#preview), Storybook's AI capabilities (specifically, the manifests and [MCP server](./mcp/overview.mdx)) are currently only supported for [React](?renderer=react) projects.\n\n  Additionally, the API may change in future releases. We welcome feedback and contributions to help improve this feature.\n</Callout>\n\n<If renderer={['react']}>\n\nYour Storybook holds a wealth of information about your components: their names, descriptions, API, usage examples, and more. Manifests are JSON objects that describe the contents of your Storybook in a concise, structured way that is easy for AI agents to understand and use. The manifests are generated automatically from your Storybook's CSF and MDX files, and they are designed to be comprehensive and up-to-date representations of your Storybook's contents.\n\nThere are two types of manifests generated by Storybook: components and docs.\n\n## Components manifest\n\nThe components manifest is generated from static analysis of the CSF files in your Storybook and prop type extraction from their associated component source code. It contains information about the components you have documented, such as their names, descriptions, props, and usage examples. This manifest is designed to help AI agents understand which components are available and how to use them.\n\nFor prop type extraction, the manifest generation will use whatever is specified in the [`reactDocgen`](../api/main-config/main-config-typescript.mdx#reactdocgen) option, or `react-docgen` by default. We recommend using `react-docgen-typescript` for most projects, because it provides more accurate and comprehensive information about your components' props. If manifest generation seems too slow, you can switch to `react-docgen`, which is faster but less detailed.\n\nWhile the types themselves provide a basic level of information, JSDoc comments in your component source code can provide additional metadata for the manifest, which can be helpful for AI agents. We highly recommend adding JSDoc comments to your components and their props to provide as much context as possible for the agents. For example:\n\n```ts title=\"Button.tsx\"\nimport React from 'react';\n\ntype ButtonProps = {\n  /**\n   * Optional click handler\n   */\n  onClick?: () => void;\n};\n\n/**\n * Button is used for user interactions that do not navigate to another route.\n * For navigation, use [Link](?path=/docs/link--default) instead.\n */\nexport const Button: React.FC<ButtonProps> = ({ onClick }) => { /* ... */ };\n```\n\n<Callout icon=\"💡\">\n  Check the [best practices](./best-practices.mdx) guide for tips on writing effective JSDoc comments for your components and other ways to provide helpful context for the agents.\n</Callout>\n\nThe raw JSON components manifest can be accessed at `http://localhost:6006/manifests/components.json` (your port may vary) when your Storybook is running or at the `/manifests/components.json` route in a built Storybook.\n\n<details>\n<summary>Example components manifest entry</summary>\n\n<Callout variant=\"info\">\n  While in [preview](../releases/features.mdx#preview), this manifest schema is not yet stable and should not be considered a public API. We include it here only as an aid for understanding.\n</Callout>\n\n```json\n{\n  \"components\": {\n    \"components-button\": {\n      \"id\": \"components-button\",\n      \"name\": \"Button\",\n      \"path\": \"./src/components/Button/Button.stories.tsx\",\n      \"stories\": [\n        {\n          \"id\": \"components-button--default\",\n          \"name\": \"Default\",\n          \"snippet\": \"const Default = () =\\u003E \\u003CButton\\u003EButton\\u003C/Button\\u003E;\"\n        },\n        {\n          \"id\": \"components-button--disabled\",\n          \"name\": \"Disabled\",\n          \"snippet\": \"const Disabled = () =\\u003E \\u003CButton disabled\\u003EButton\\u003C/Button\\u003E;\"\n        }\n      ],\n      \"import\": \"import { Button } from \\\"@mealdrop/ui\\\";\",\n      \"jsDocTags\": {\n\n      },\n      \"description\": \"Primary UI component for user interaction\",\n      \"reactDocgen\": {\n        \"description\": \"Primary UI component for user interaction\",\n        \"methods\": [],\n        \"displayName\": \"Button\",\n        \"definedInFile\": \"/path/to/project/src/components/Button/Button.tsx\",\n        \"actualName\": \"Button\",\n        \"exportName\": \"Button\",\n        \"props\": {\n          \"clear\": {\n            \"required\": false,\n            \"tsType\": {\n              \"name\": \"boolean\"\n            },\n            \"description\": \"Clear button styles leaving just a text\",\n            \"defaultValue\": {\n              \"value\": \"false\",\n              \"computed\": false\n            }\n          },\n          \"round\": {\n            \"required\": false,\n            \"tsType\": {\n              \"name\": \"boolean\"\n            },\n            \"description\": \"\",\n            \"defaultValue\": {\n              \"value\": \"false\",\n              \"computed\": false\n            }\n          },\n          \"large\": {\n            \"required\": false,\n            \"tsType\": {\n              \"name\": \"boolean\"\n            },\n            \"description\": \"Is the button large?\",\n            \"defaultValue\": {\n              \"value\": \"false\",\n              \"computed\": false\n            }\n          },\n          \"icon\": {\n            \"required\": false,\n            \"tsType\": {\n              \"name\": \"union\",\n              \"raw\": \"| 'arrow-right'\\n| 'arrow-left'\\n| 'cross'\\n| 'cart'\\n| 'minus'\\n| 'plus'\\n| 'moon'\\n| 'sun'\\n| 'star'\",\n              \"elements\": [\n                {\n                  \"name\": \"literal\",\n                  \"value\": \"'arrow-right'\"\n                },\n                {\n                  \"name\": \"literal\",\n                  \"value\": \"'arrow-left'\"\n                },\n                {\n                  \"name\": \"literal\",\n                  \"value\": \"'cross'\"\n                },\n                {\n                  \"name\": \"literal\",\n                  \"value\": \"'cart'\"\n                },\n                {\n                  \"name\": \"literal\",\n                  \"value\": \"'minus'\"\n                },\n                {\n                  \"name\": \"literal\",\n                  \"value\": \"'plus'\"\n                },\n                {\n                  \"name\": \"literal\",\n                  \"value\": \"'moon'\"\n                },\n                {\n                  \"name\": \"literal\",\n                  \"value\": \"'sun'\"\n                },\n                {\n                  \"name\": \"literal\",\n                  \"value\": \"'star'\"\n                }\n              ]\n            },\n            \"description\": \"Does the button have an icon?\"\n          },\n          \"iconSize\": {\n            \"required\": false,\n            \"tsType\": {\n              \"name\": \"number\"\n            },\n            \"description\": \"Size of the icon\"\n          },\n          \"disabled\": {\n            \"required\": false,\n            \"tsType\": {\n              \"name\": \"boolean\"\n            },\n            \"description\": \"Is the button disabled?\"\n          },\n          \"children\": {\n            \"required\": false,\n            \"tsType\": {\n              \"name\": \"union\",\n              \"raw\": \"string | React.ReactNode\",\n              \"elements\": [\n                {\n                  \"name\": \"string\"\n                },\n                {\n                  \"name\": \"ReactReactNode\",\n                  \"raw\": \"React.ReactNode\"\n                }\n              ]\n            },\n            \"description\": \"The content of the button\"\n          },\n          \"onClick\": {\n            \"required\": false,\n            \"tsType\": {\n              \"name\": \"signature\",\n              \"type\": \"function\",\n              \"raw\": \"() =\\u003E void\",\n              \"signature\": {\n                \"arguments\": [],\n                \"return\": {\n                  \"name\": \"void\"\n                }\n              }\n            },\n            \"description\": \"Optional click handler\"\n          }\n        }\n      }\n    }\n  }\n}\n```\n</details>\n\n## Docs (MDX) manifest\n\nThe docs manifest is generated from the [MDX files](../writing-docs/mdx.mdx) in your Storybook. These files are used to document specific components or to create standalone documentation pages (e.g. a \"Getting Started\" guide, accessibility guidelines, design tokens, etc.), all of which can offer helpful context to the agent.\n\nThe raw JSON docs manifest can be accessed at `http://localhost:6006/manifests/docs.json` (your port may vary) when your Storybook is running or at the `/manifests/docs.json` route in a built Storybook.\n\n<Callout variant=\"info\" icon=\"💡\">\n  Check the [best practices](./best-practices.mdx) guide for tips on writing effective documentation and providing helpful context for the agents.\n</Callout>\n\n<details>\n<summary>Example docs manifest entry</summary>\n\n<Callout variant=\"info\">\n  While in [preview](../releases/features.mdx#preview), this manifest schema is not yet stable and should not be considered a public API. We include it here only as an aid for understanding.\n</Callout>\n\n```json\n{\n  \"docs\": {\n    \"design-system-typography--docs\": {\n      \"id\": \"design-system-typography--docs\",\n      \"name\": \"Docs\",\n      \"path\": \"./src/docs/Typography.mdx\",\n      \"title\": \"Design System/Typography\",\n      \"content\": \"import { Meta, Typeset } from '@storybook/addon-docs/blocks'\\n\\n\\u003CMeta title=\\\"Design System/Typography\\\" /\\u003E\\n\\n# Typography\\n\\n## Font: Hind\\n\\nUsed for body texts, descriptions and general info\\n\\n**Weight:** 400(regular)\\n\\n\\u003CTypeset\\n  sampleText=\\\"Feel like having pizza, sushi or your favourite dish from Tatooine?\\\"\\n  fontSizes={[12, 14, 18, 24]}\\n  fontWeight={400}\\n  fontFamily=\\\"Hind\\\"\\n/\\u003E\\n\\n**Weight:** 500(medium)\\n\\n\\u003CTypeset\\n  sampleText=\\\"Feel like having pizza, sushi or your favourite dish from Tatooine?\\\"\\n  fontSizes={[12, 14, 18, 24]}\\n  fontWeight={500}\\n  fontFamily=\\\"Hind\\\"\\n/\\u003E\\n\\n## Font: Montserrat\\n\\nUsed for headings and titles\\n\\n**Weight:** 400 (regular)\\n\\n\\u003CTypeset\\n  sampleText=\\\"Feel like having pizza, sushi or your favourite dish from Tatooine?\\\"\\n  fontSizes={[12, 14, 18, 24]}\\n  fontWeight={400}\\n  fontFamily=\\\"Montserrat\\\"\\n/\\u003E\\n\\n**Weight:** 500 (medium)\\n\\n\\u003CTypeset\\n  sampleText=\\\"Feel like having pizza, sushi or your favourite dish from Tatooine?\\\"\\n  fontSizes={[12, 14, 18, 24]}\\n  fontWeight={500}\\n  fontFamily=\\\"Montserrat\\\"\\n/\\u003E\\n\\n**Weight:** 700 (bold)\\n\\n\\u003CTypeset\\n  sampleText=\\\"Feel like having pizza, sushi or your favourite dish from Tatooine?\\\"\\n  fontSizes={[12, 14, 18, 24]}\\n  fontWeight={700}\\n  fontFamily=\\\"Montserrat\\\"\\n/\\u003E\\n\\n**Weight:** 900 (black)\\n\\n\\u003CTypeset\\n  sampleText=\\\"Feel like having pizza, sushi or your favourite dish from Tatooine?\\\"\\n  fontSizes={[12, 14, 18, 24]}\\n  fontWeight={900}\\n  fontFamily=\\\"Montserrat\\\"\\n/\\u003E\\n\"\n    }\n  }\n}\n```\n</details>\n\n## Debugging\n\nTo help you get a better picture of what is and is not in the manifests, Storybook provides a combined manifest debugger at `http://localhost:6006/manifests/components.html` (your port may vary). This page shows the contents of both the component and docs manifests in a human-readable format, along with any errors or warnings that were encountered during manifest generation.\n\n![Manifest debugger](../_assets/ai/manifest-debugger.png)\n\nAt the top of the page, you can see any errors or warnings that were encountered during manifest generation. You can click these buttons to filter the manifest to show only the relevant entries, which can be helpful for debugging.\n\n## Curating\n\nBy default, all stories and independent docs pages have the `manifest` [tag](../writing-stories/tags.mdx) applied, which means they will be included in the manifests. You can curate what is included in the manifests by adding or removing the `manifest` tag from your stories and docs pages. For example, if you have a story that is for instructional purposes only and the agent should not be aware of it, you can remove the `manifest` tag from that story to exclude it from the manifests:\n\n<CodeSnippets path=\"tag-manifest-remove-in-story.md\" />\n\nYou can also remove an entire component from the manifest by removing the tag in the file's meta (or default export), which will exclude all stories in that file from the manifests.\n\nSimilarly, to exclude an entire MDX docs page from the manifests, you can remove the `manifest` tag from the page's metadata:\n\n```jsx title=\"DocForHumansOnly.mdx\"\nimport { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Doc for Humans Only\" tags={['!manifest']} />\n```\n\n</If>\n{/* End supported renderers */}\n\n**More AI resources**\n\n- [MCP server overview](./mcp/overview.mdx)\n- [MCP server API](./mcp/api.mdx)\n- [Sharing your MCP server](./mcp/sharing.mdx)\n- [Best practices for using Storybook with AI](./best-practices.mdx)\n"
  },
  {
    "path": "docs/ai/mcp/api.mdx",
    "content": "---\ntitle: MCP server API\nsidebar:\n  order: 2\n  title: API\n---\n  \n<Callout variant=\"info\" icon=\"🧪\">\n  While they are in [preview](../../releases/features.mdx#preview), Storybook's AI capabilities (specifically, the [manifests](../manifests.mdx) and MCP server) are currently only supported for [React](?renderer=react) projects.\n\n  Additionally, the API may change in future releases. We welcome feedback and contributions to help improve this feature.\n</Callout>\n\n<If renderer={['react']}>\n\n## `@storybook/addon-mcp` options\n\nThe MCP server addon accepts the following options to configure the tools provided by the MCP server. You can provide these options when registering the addon in your `main.js|ts` file:\n\n<CodeSnippets path=\"addon-mcp-options.md\" />\n\n### `toolsets`\n\nType:\n\n```ts\n{\n  dev?: boolean;\n  docs?: boolean;\n  test?: boolean;\n}\n```\n\nDefault: \n\n```ts\n{\n  dev: true,\n  docs: true,\n  test: true,\n}\n```\n\nConfiguration object to toggle which toolsets are enabled in the MCP server. By default, all toolsets are enabled.\n\n#### `dev`\n\nType: `boolean`\n\nDefault: `true`\n\nThe development toolset includes the [`get-storybook-story-instructions`](./overview.mdx#get-storybook-story-instructions) and [`preview-stories`](./overview.mdx#preview-stories) tools.\n\n#### `docs`\n\nType: `boolean`\n\nDefault: `true`\n\nThe docs toolset includes the [`get-documentation`](./overview.mdx#get-documentation), [`get-documentation-for-story`](./overview.mdx#get-documentation-for-story), and [`list-all-documentation`](./overview.mdx#list-all-documentation) tools.\n\n#### `test`\n\nType: `boolean`\n\nDefault: `true`\n\nThe testing toolset includes the [`run-story-tests`](./overview.mdx#run-story-tests) tool.\n\n</If>\n{/* End supported renderers */}\n\n**More AI resources**\n\n- [MCP server overview](./overview.mdx)\n- [Sharing your MCP server](./sharing.mdx)\n- [Best practices for using Storybook with AI](../best-practices.mdx)\n- [Manifests](../manifests.mdx)\n"
  },
  {
    "path": "docs/ai/mcp/index.mdx",
    "content": "---\ntitle: MCP server\nhideRendererSelector: true\nsidebar:\n  order: 1\n---\n\nStorybook's MCP server connects your Storybook to AI agents, enabling them to understand your components and documentation, generate stories, run tests, and more. It follows the [Model Context Protocol](https://modelcontextprotocol.io/) standard so that any MCP-compatible agent can use it.\n\n- [**Overview**](./overview.mdx) — Learn how the MCP server works, how to install and configure it, and see a walkthrough of a typical workflow.\n- [**API**](./api.mdx) — Reference documentation for the addon configuration options and MCP server tools.\n- [**Sharing**](./sharing.mdx) — Publish or self-host your MCP server so your team or community can use it.\n"
  },
  {
    "path": "docs/ai/mcp/overview.mdx",
    "content": "---\ntitle: MCP server\nsidebar:\n  order: 1\n  title: Overview\n---\n\n<Callout variant=\"info\" icon=\"🧪\">\n  While they are in [preview](../../releases/features.mdx#preview), Storybook's AI capabilities (specifically, the [manifests](../manifests.mdx) and MCP server) are currently only supported for [React](?renderer=react) projects.\n\n  Additionally, the API may change in future releases. We welcome feedback and contributions to help improve this feature.\n</Callout>\n\n<If renderer={['react']}>\n\nStorybook's MCP server connects your Storybook to AI agents, allowing them to understand your components and documentation, generate stories, run tests, and more. Agents will be equipped to reuse your existing components and follow your documented usage guidelines when generating UI, helping ensure the generated UI is consistent with your existing design system. Then they can write stories so you can preview the generated UI and automatically run interaction tests (and accessibility checks) on those stories to validate their work. If any issues are found, the agent can fix them and re-run the tests to confirm they are resolved, creating a self-healing loop that helps ensure the quality of the generated UI without requiring you to intervene.\n\n## Installation\n\n### 1. Install the addon\n\nRun this command to install and register the Storybook MCP addon:\n\n<CodeSnippets path=\"addon-mcp-add.md\" />\n\nNow, when running Storybook's dev server, you can access the MCP server at `http://localhost:6006/mcp` (your port may be different). When viewed in the browser, you'll see a page showing which tools are available and a link to the [manifest debugger](../manifests.mdx#debugging).\n\n![The MCP server page in the browser](../../_assets/ai/addon-mcp-splash.png)\n\n### 2. Add the MCP server to your agent\n\nThen run this command to configure your agent to use the MCP server:\n\n<CodeSnippets path=\"mcp-add.md\" />\n\nYou may need to update the port number in the URL. You will be prompted for a name for your MCP server (e.g. \"my-project-sb-mcp\"). This is the name you'll use when calling the tools from your agent, so choose something descriptive and unique to avoid confusion with other tools.\n\n[`mcp-add`](https://github.com/paoloricciuti/mcp-add) is a CLI tool designed to simplify adding MCP servers to various agents.\n\nYou can also follow your agent's documentation to add the MCP server as a tool provider manually, e.g. [Claude Code](https://code.claude.com/docs/en/mcp#option-1-add-a-remote-http-server), [Google Gemini CLI](https://geminicli.com/docs/tools/mcp-server/#adding-an-http-server), [OpenAI Codex](https://developers.openai.com/codex/mcp/), [VS Code Copilot](https://code.visualstudio.com/docs/copilot/customization/mcp-servers#_configure-the-mcpjson-file), etc.\n\n### 3. Adjust your agent instructions\n\nTo guide your agent to use your MCP server, you should adjust your [`AGENTS.md`](https://agents.md/) (or [`CLAUDE.md`](https://code.claude.com/docs/en/memory#claude-md-files), if you're using Claude). The specifics will depend on your project and how you use agents in your development process, but something like this is a good starting point. Just make sure to replace `your-project-sb-mcp` with the name you chose for your MCP server toolset in the previous step.\n\n```md title=\"AGENTS.md\"\nWhen working on UI components, always use the `your-project-sb-mcp` MCP tools to access Storybook's component and documentation knowledge before answering or taking any action.\n\n- **CRITICAL: Never hallucinate component properties!** Before using ANY property on a component from a design system (including common-sounding ones like `shadow`, etc.), you MUST use the MCP tools to check if the property is actually documented for that component.\n- Query `list-all-documentation` to get a list of all components\n- Query `get-documentation` for that component to see all available properties and examples\n- Only use properties that are explicitly documented or shown in example stories\n- If a property isn't documented, do not assume properties based on naming conventions or common patterns from other libraries. Check back with the user in these cases.\n- Use the `get-storybook-story-instructions` tool to fetch the latest instructions for creating or updating stories. This will ensure you follow current conventions and recommendations.\n- Check your work by running `run-story-tests`.\n\nRemember: A story name might not reflect the property name correctly, so always verify properties through documentation or example stories before using them.\n```\n\nFinally, test your agent's access to the MCP server. First, make sure your Storybook is running, then run a prompt like \"List all documented components\". You should see a call to the [`list-all-documentation`](#list-all-documentation) tool with a response listing components from your Storybook.\n\n## Usage\n\nOnce you have your MCP server and agent configured, using it is as simple as prompting your agent to do some UI development. Let's demonstrate how these toolsets can work together in some typical workflows.\n\n**1. Generating UI with existing components**\n\n_Prompt: Build a login form_\n\n1. The agent queries the [docs toolset](#docs) to find components that match the requirements of a login form, e.g. a `TextInput` component for the username and password fields, and a `Button` component for the submit button.\n\n1. The agent queries the [docs toolset](#docs) again to reference more detailed information about specific components, e.g., it learns that the `TextInput` component has a `type` prop that can be set to \"password\" to obscure the input.\n\n1. The agent generates a LoginForm component that composes those components together.\n\n1. The agent uses the [development toolset](#development) to generate stories that render LoginForm in its various states.\n\n1. The agent uses the [testing toolset](#testing) to run tests on the generated component, and finds that the submit button does not have an accessible level of color contrast.\n\n1. The agent updates the LoginForm component to use a different color (found by using the [docs toolset](#docs) to reference your documented theme colors) for the submit button.\n\n1. The agent uses the [testing toolset](#testing) to re-run the tests to confirm that the issue is resolved.\n1. The agent uses the [development toolset](#development) to show you previews of each relevant story.\n\n**2. Previewing work with stories**\n\n_Prompt: Show me the Button in dark mode_\n\n1. The agent uses the [development toolset](#development) to share a preview of or link to the default Button story in dark mode.\n\n**3. Running tests**\n\n_Prompt: Run tests for all the stories that contain the Header component_\n\n1. Agent uses grep (or \"file system lookup\") to determine which components use Header.\n\n1. Agent finds all the stories for those components.\n\n1. The agent uses the [testing toolset](#testing) to run tests on those stories, and returns a summary of the results.\n\n**4. Generating tests**\n\n_Prompt: Write a story to test the login form submit action_\n\n1. The agent uses the [development toolset](#development) to generate a story that demonstrates the submit action of the login form, e.g. by writing a [play function](../../writing-tests/interaction-testing.mdx#writing-interaction-tests) to simulate a user filling out the form and clicking the submit button, then asserting that the expected outcome occurs (e.g. a success message appears, the user is redirected, etc.).\n\n## Toolsets\n\nThe MCP server provides a set of tools that an agent can call to interact with your Storybook. The available tools are organized into three toolsets: development, docs, and testing. Each toolset provides a different set of capabilities for the agent to use when developing UI.\n\n### Development\n\nThe development toolset provides tools for authoring well-considered stories (including [interaction tests](../../writing-tests/interaction-testing.mdx)) and previewing those stories in the agent's chat interface. This allows you to easily check the agent's work, and the generated stories can serve as tests (which the agent can run, with the [testing toolset](#testing), to validate that the generated UI works as intended).\n\nThe development toolset includes the following tools:\n\n#### `get-storybook-story-instructions`\n\nReturns instructions on how to write useful stories, including which props to capture and how to write interaction tests for the story (if applicable).\n\n#### `preview-stories`\n\nReturns story previews rendered in the agent's chat interface, if the agent supports [MCP Apps](https://modelcontextprotocol.io/extensions/apps/overview#client-support). Otherwise, it returns links to relevant stories in Storybook.\n\n### Docs\n\nThe docs toolset provides tools that help the agent reuse components from your Storybook when generating UI. The agent can query the manifests to find components that match the requirements of the UI it's trying to build, and reference your documentation to understand how to use those components correctly. This helps ensure the generated UI is consistent with your existing design system and uses the components you've already built.\n\nThe docs toolset includes the following tools:\n\n#### `get-documentation`\n\nReturns the detailed documentation for a specific component, including its props, the first three stories, an index of the remaining stories, and any additional documentation you've provided.\n\n#### `get-documentation-for-story`\n\nReturns the full story and associated documentation for a specific story. The agent calls this tool when `get-documentation` doesn't provide enough information for the agent to use a component effectively.\n\n#### `list-all-documentation`\n\nReturns an index containing components and unattached docs entries.\n\n### Testing\n\nIf you have [Storybook Test](../../writing-tests/index.mdx) set up in your Storybook, the testing toolset provides tools that allow the agent to run component tests (including [accessibility checks](../../writing-tests/accessibility-testing.mdx), if set up) and interpret their results. It also includes instructions to resolve issues. As the agent develops, it can choose to run tests to validate its work. If it finds issues, it can fix them and re-run the tests to confirm they are resolved. This creates a _self-healing_ loop that helps ensure the quality of the generated UI, without requiring you to intervene.\n\nThe testing toolset includes the following tool:\n\n#### `run-story-tests`\n\nRuns tests for specific stories and returns results, including any accessibility issues (if configured). Also instructs the agent to interpret the results and resolve any issues found.\n\n## Composition\n\nIf you need to develop UI using components from multiple Storybooks, you can take advantage of [Storybook composition](../../sharing/storybook-composition.mdx). If a composed Storybook has [manifests](../manifests.mdx), the MCP server will automatically include the content from those manifests in its responses, allowing your agent to access the combined knowledge from all composed Storybooks. This means that your agent can find and reference components from any of the composed Storybooks when generating UI.\n\n## FAQ\n\n### Which agents are supported?\n\nWe built Storybook's capabilities as an MCP server, which is a standard protocol for AI agent tool providers. Any agent that supports MCP can be connected to Storybook's MCP server, and will be able to use Storybook's manifests and tools. This includes popular agents like [Claude](https://claude.ai/), [Google Gemini](https://gemini.google.dev/), [Microsoft Copilot](https://copilot.microsoft.com/), and many more.\n\n### Why is the docs toolset React-only?\n\nThe docs toolset relies on the [manifests](../manifests.mdx) generated by Storybook, which is currently limited to React projects. After we ensure a solid experience with React projects, we plan to expand support to the other core Storybook renderers: Vue, Angular, Web Components, and Svelte.\n\n</If>\n{/* End supported renderers */}\n\n**More AI resources**\n\n- [MCP server API](./api.mdx)\n- [Sharing your MCP server](./sharing.mdx)\n- [Best practices for using Storybook with AI](../best-practices.mdx)\n- [Manifests](../manifests.mdx)\n"
  },
  {
    "path": "docs/ai/mcp/sharing.mdx",
    "content": "---\ntitle: Sharing your MCP server\nsidebar:\n  order: 3\n  title: Sharing\n---\n\n<Callout variant=\"info\" icon=\"🧪\">\n  While they are in [preview](../../releases/features.mdx#preview), Storybook's AI capabilities (specifically, the [manifests](../manifests.mdx) and [MCP server](./overview.mdx)) are currently only supported for [React](?renderer=react) projects.\n\n  Additionally, the API may change in future releases. We welcome feedback and contributions to help improve this feature.\n</Callout>\n\n<If renderer={['react']}>\n\nJust as [publishing your Storybook](../../sharing/publish-storybook.mdx) can help your team work more effectively, sharing your MCP server can enable your team to share the benefits of AI-assisted development.\n\nThe MCP server is made of [development](./overview.mdx#development), [docs](./overview.mdx#docs), and [testing](./overview.mdx#testing) toolsets that an agent can call to interact with your Storybook. The development and testing toolsets are only relevant to the locally-running Storybook instance, but the docs toolset can be published and shared so that agents outside of your local environment can access the knowledge from your Storybook's [manifest](../manifests.mdx) to reference your components and documentation when generating UI.\n\nThere are two different ways you can share your MCP server.\n\n## Automatic publishing with Chromatic\n\nThe easiest way to share your MCP server is to [publish your Storybook with Chromatic](../../sharing/publish-storybook.mdx#publish-storybook-with-chromatic), which will [automatically publish your MCP server](https://chromatic.com/docs/mcp/) as well. If your Storybook is private, your MCP server will be private as well, and only accessible to those you invite to your Chromatic project. If your Storybook is public, your MCP server will be public as well, and accessible to anyone with the URL.\n\nOnce published, you can share the [MCP server URL](https://chromatic.com/docs/mcp/#grab-your-mcp-server-url) with your team or community, and they can configure their agent to use that URL to access it.\n\nBy publishing with Chromatic, you can be sure that your MCP server is always up-to-date with your latest Storybook, it's safeguarded by UI tests, and you don't have to worry about hosting or maintaining it yourself.\n\n## Self-hosting with `@storybook/mcp`\n\nIf you prefer full control over your MCP server, you can self-host it. This approach allows you to manage the server's infrastructure, security, and updates according to your team's requirements. You will need to ensure your MCP server is accessible to your team or community and properly maintained.\n\nWe provide a package, `@storybook/mcp`, which is a library that creates a [`tmcp`-based](https://github.com/paoloricciuti/tmcp/) MCP server exposing Storybook component/docs knowledge from [manifests](../manifests.mdx).\n\n### Prerequisites\n\n- Node.js 20+\n- A [manifest](../manifests.mdx) source containing:\n  - `components.json` (required)\n  - `docs.json` (optional)\n\n### API\n\nThe full API for `@storybook/mcp` is documented in the [package's repository](https://github.com/storybookjs/mcp/tree/main/packages/mcp).\n\n### Example implementation\n\nYou can reference [self-hosting patterns](https://github.com/storybookjs/mcp/tree/main/apps/self-host-mcp) for both a Node.js process and a Netlify Function.\n\nThis is the minimal implementation of a server using `@storybook/mcp`:\n\n```ts title=\"server.ts\"\nimport { createStorybookMcpHandler } from '@storybook/mcp';\n\nconst storybookMcpHandler = await createStorybookMcpHandler();\n\nexport async function handleRequest(request: Request): Promise<Response> {\n\tif (new URL(request.url).pathname === '/mcp') {\n\t\treturn storybookMcpHandler(request);\n\t}\n\n\treturn new Response('Not found', { status: 404 });\n}\n```\n\n</If>\n{/* End supported renderers */}\n\n**More AI resources**\n\n- [MCP server overview](./overview.mdx)\n- [MCP server API](./api.mdx)\n- [Best practices for using Storybook with AI](../best-practices.mdx)\n- [Manifests](../manifests.mdx)\n"
  },
  {
    "path": "docs/api/arg-types.mdx",
    "content": "---\ntitle: 'ArgTypes'\nsidebar:\n  order: 3\n  title: ArgTypes\n---\n\nArgTypes specify the behavior of [args](../writing-stories/args.mdx). By specifying the type of an arg, you constrain the values that it can accept and provide information about args that are not explicitly set (i.e., [description](#description)).\n\nYou can also use argTypes to “annotate” args with information used by addons that make use of those args. For instance, to instruct the [controls panel](../essentials/controls.mdx) to render a color picker, you could specify the `'color'` [control type](#control).\n\nThe most concrete realization of argTypes is the [`ArgTypes` doc block](./doc-blocks/doc-block-argtypes.mdx) ([`Controls`](./doc-blocks/doc-block-controls.mdx) is similar). Each row in the table corresponds to a single argType and the current value of that arg.\n\n![ArgTypes table](../_assets/api/doc-block-argtypes.png)\n\n## Automatic argType inference\n\nIf you are using the Storybook [docs](../writing-docs/index.mdx) addon, then Storybook will infer a set of argTypes for each story based on the `component` specified in the [meta (or default export)](../writing-stories/index.mdx#default-export) of the CSF file.\n\nTo do so, Storybook uses various static analysis tools depending on your framework.\n\n| Framework     | Static analysis tool                                                                                                                                    |\n| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| React         | [react-docgen](https://github.com/reactjs/react-docgen) (default) or [react-docgen-typescript](https://github.com/styleguidist/react-docgen-typescript) |\n| Vue           | [vue-docgen-api](https://github.com/vue-styleguidist/vue-styleguidist/tree/dev/packages/vue-docgen-api)                                                 |\n| Angular       | [compodoc](https://compodoc.app/)                                                                                                                       |\n| WebComponents | [custom-element.json](https://github.com/webcomponents/custom-elements-json)                                                                            |\n| Ember         | [YUI doc](https://github.com/ember-learn/ember-cli-addon-docs-yuidoc#documenting-components)                                                            |\n\nThe data structure of `argTypes` is designed to match the output of the these tools. Properties specified manually will override what is inferred.\n\n## Manually specifying argTypes\n\nFor most Storybook projects, argTypes are [automatically inferred](#automatic-argtype-inference) from your components. Any argTypes specified manually will override the inferred values.\n\nArgTypes are most often specified at the component level, in the [meta (or default export)](../writing-stories/index.mdx#default-export) of the CSF file:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"arg-types-in-meta.md\" />\n\n{/* prettier-ignore-end */}\n\nThey can apply to all stories when specified at the project (global) level, in the `preview.js|ts` configuration file:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"arg-types-in-preview.md\" />\n\n{/* prettier-ignore-end */}\n\nOr they can apply only to a [specific story](../writing-stories/index.mdx#defining-stories):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"arg-types-in-story.md\" />\n\n{/* prettier-ignore-end */}\n\n## `argTypes`\n\nType:\n\n```ts\n{\n  [key: string]: {\n    control?: ControlType | { type: ControlType; /* See below for more */ } | false;\n    description?: string;\n    if?: Conditional;\n    mapping?: { [key: string]: { [option: string]: any } };\n    name?: string;\n    options?: string[];\n    table?: {\n      category?: string;\n      defaultValue?: { summary: string; detail?: string };\n      disable?: boolean;\n      subcategory?: string;\n      type?: { summary?: string; detail?: string };\n    },\n    type?: SBType | SBScalarType['name'];\n  }\n}\n```\n\nYou configure argTypes using an object with keys matching the name of args. The value of each key is an object with the following properties:\n\n### `control`\n\nType:\n\n```ts\n| ControlType\n| {\n    type: ControlType,\n    accept?: string;\n    labels?: { [option: string]: string };\n    max?: number;\n    min?: number;\n    presetColors?: string[];\n    step?: number;\n  }\n| false\n```\n\nDefault:\n\n1. `'select'`, if [`options`](#options) are specified\n2. Else, inferred from [`type`](#type)\n3. Else, `'object'`\n\nSpecify the behavior of the [controls panel](../essentials/controls.mdx) for the arg. If you specify a string, it's used as the [`type`](#controltype) of the control. If you specify an object, you can provide additional configuration. Specifying `false` will prevent the control from rendering.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"arg-types-control.md\" />\n\n{/* prettier-ignore-end */}\n\n#### `control.type`\n\nType: `ControlType | null`\n\nDefault: [Inferred](#automatic-argtype-inference); `'select'`, if [`options`](#options) are specified; falling back to `'object'`\n\nSpecifies the type of control used to change the arg value with the [controls panel](../essentials/controls.mdx). Here are the available types, `ControlType`, grouped by the type of data they handle:\n\n| Data type      | ControlType      | Description                                                                                                                                                                             |\n| -------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| **array**      | `'object'`       | Provides a JSON-based editor to handle the values of the array. Also allows editing in raw mode.<br /> `{ control: 'object' }`                                                          |\n| **boolean**    | `'boolean'`      | Provides a toggle for switching between possible states.<br /> `{ control: 'boolean' }`                                                                                                 |\n| **enum**       | `'check'`        | Provides a set of stacked checkboxes for selecting multiple options.<br /> `{ control: 'check', options: ['email', 'phone', 'mail'] }`                                                  |\n|                | `'inline-check'` | Provides a set of inlined checkboxes for selecting multiple options.<br /> `{ control: 'inline-check', options: ['email', 'phone', 'mail'] }`                                           |\n|                | `'radio'`        | Provides a set of stacked radio buttons based on the available options.<br /> `{ control: 'radio', options: ['email', 'phone', 'mail'] }`                                               |\n|                | `'inline-radio'` | Provides a set of inlined radio buttons based on the available options.<br /> `{ control: 'inline-radio', options: ['email', 'phone', 'mail'] }`                                        |\n|                | `'select'`       | Provides a select to choose a single value from the options.<br /> `{ control: 'select', options: [20, 30, 40, 50] }`                                                                   |\n|                | `'multi-select'` | Provides a select to choose multiple values from the options.<br /> `{ control: 'multi-select', options: ['USA', 'Canada', 'Mexico'] }`                                                 |\n| **number**     | `'number'`       | Provides a numeric input to include the range of all possible values.<br /> `{ control: { type: 'number', min:1, max:30, step: 2 } }`                                                   |\n|                | `'range'`        | Provides a range slider to include all possible values.<br /> `{ control: { type: 'range', min: 1, max: 30, step: 3 } }`                                                                |\n| **object**     | `'file'`         | Provides a file input that returns an array of URLs. Can be further customized to accept specific file types.<br /> `{ control: { type: 'file', accept: '.png' } }`                     |\n|                | `'object'`       | Provides a JSON-based editor to handle the object's values. Also allows editing in raw mode.<br /> `{ control: 'object' }`                                                              |\n| **string**     | `'color'`        | Provides a color picker to choose color values. Can be additionally configured to include a set of color presets.<br /> `{ control: { type: 'color', presetColors: ['red', 'green']} }` |\n|                | `'date'`         | Provides a datepicker to choose a date.<br /> `{ control: 'date' }`                                                                                                                     |\n|                | `'text'`         | Provides a freeform text input.<br /> `{ control: 'text' }`                                                                                                                             |\n\n<Callout variant=\"info\" icon=\"💡\">\n  The `date` control will convert the date into a UNIX timestamp when the value changes. It's a known limitation that will be fixed in a future release. If you need to represent the actual date, you'll need to update the story's implementation and convert the value into a date object.\n</Callout>\n\n#### `control.accept`\n\nType: `string`\n\nWhen `type` is `'file'`, you can specify the file types that are accepted. The value should be a string of comma-separated MIME types.\n\n#### `control.labels`\n\nType: `{ [option: string]: string }`\n\nMap [`options`](#options) to labels. `labels` doesn't have to be exhaustive. If an option is not in the object's keys, it's used verbatim.\n\n#### `control.max`\n\nType: `number`\n\nWhen `type` is `'number'` or `'range'`, sets the maximum allowed value.\n\n#### `control.min`\n\nType: `number`\n\nWhen `type` is `'number'` or `'range'`, sets the minimum allowed value.\n\n#### `control.presetColors`\n\nType: `string[]`\n\nWhen `type` is `'color'`, defines the set of colors that are available in addition to the general color picker. The values in the array should be valid CSS color values.\n\n#### `control.step`\n\nType: `number`\n\nWhen `type` is `'number'` or `'range'`, sets the granularity allowed when incrementing/decrementing the value.\n\n### `description`\n\nType: `string`\n\nDefault: [Inferred](#automatic-argtype-inference)\n\nDescribe the arg. (If you intend to describe the type of the arg, you should use [`table.type`](#tabletype), instead.)\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"arg-types-description.md\" />\n\n{/* prettier-ignore-end */}\n\n### `if`\n\nType:\n\n```ts\n{\n  [predicateType: 'arg' | 'global']: string;\n  eq?: any;\n  exists?: boolean;\n  neq?: any;\n  truthy?: boolean;\n}\n```\n\nConditionally render an argType based on the value of another [arg](../writing-stories/args.mdx) or [global](../essentials/toolbars-and-globals.mdx).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"arg-types-if.md\" />\n\n{/* prettier-ignore-end */}\n\n### `mapping`\n\nType: `{ [key: string]: { [option: string]: any } }`\n\nMap [`options`](#options) to values.\n\nWhen dealing with non-primitive values, you'll notice that you'll run into some limitations. The most obvious issue is that not every value can be represented as part of the `args` param in the URL, losing the ability to share and deeplink to such a state. Beyond that, complex values such as JSX cannot be synchronized between the manager (e.g., Controls panel) and the preview (your story).\n\n`mapping` doesn't have to be exhaustive. If the currently selected option is not listed, it's used verbatim. Can be used with [`control.labels`](#labels).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"arg-types-mapping.md\" />\n\n{/* prettier-ignore-end */}\n\n### `name`\n\nType: `string`\n\nThe `argTypes` object uses the name of the arg as the key. By default, that key is used when displaying the argType in Storybook. You can override the displayed name by specifying a `name` property.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"arg-types-name.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"warning\">\n  Be careful renaming args in this way. Users of the component you're documenting will not be able to use the documented name as a property of your component and the actual name will not displayed.\n\n  For this reason, the `name` property is best used when defining an `argType` that is only used for documentation purposes and not an actual property of the component. For example, when [providing argTypes for each property of an object](https://stackblitz.com/edit/github-uplqzp?file=src/stories/Button.stories.tsx).\n</Callout>\n\n### `options`\n\nType: `string[]`\n\nDefault: [Inferred](#automatic-argtype-inference)\n\nIf the arg accepts a finite set of values, you can specify them with `options`. If those values are [complex](../essentials/controls.mdx#dealing-with-complex-values), like JSX elements, you can use [`mapping`](#mapping) to map them to string values. You can use [`control.labels`](#labels) to provide custom labels for the options.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"arg-types-options.md\" />\n\n{/* prettier-ignore-end */}\n\n### `table`\n\nType:\n\n```ts\n{\n  category?: string;\n  defaultValue?: {\n    detail?: string;\n    summary: string;\n  };\n  disable?: boolean;\n  subcategory?: string;\n  type?: {\n    detail?: string;\n    summary: string;\n  };\n}\n```\n\nDefault: [Inferred](#automatic-argtype-inference)\n\nSpecify how the arg is documented in the [`ArgTypes` doc block](./doc-blocks/doc-block-argtypes.mdx), [`Controls` doc block](./doc-blocks/doc-block-controls.mdx), and [Controls panel](../essentials/controls.mdx).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"arg-types-table.md\" />\n\n{/* prettier-ignore-end */}\n\n#### `table.category`\n\nType: `string`\n\nDefault: [Inferred](#automatic-argtype-inference), in some frameworks\n\nDisplay the argType under a category heading, with the label specified by `category`.\n\n#### `table.defaultValue`\n\nType: `{ detail?: string; summary: string }`\n\nDefault: [Inferred](#automatic-argtype-inference)\n\nThe documented default value of the argType. `summary` is typically used for the value itself, while `detail` is used for additional information.\n\n#### `table.disable`\n\nType: `boolean`\n\nSet to `true` to remove the argType's row from the table.\n\n#### `table.readonly`\n\nType: `boolean`\n\nSet to `true` to indicate that the argType is read-only.\n\n#### `table.subcategory`\n\nType: `string`\n\nDisplay the argType under a subcategory heading (which displays under the \\[`category`] heading), with the label specified by `subcategory`.\n\n#### `table.type`\n\nType: `{ detail?: string; summary: string }`\n\nDefault: Inferred from [`type`](#type)\n\nThe documented type of the argType. `summary` is typically used for the type itself, while `detail` is used for additional information.\n\nIf you need to specify the actual, semantic type, you should use [`type`](#type), instead.\n\n### `type`\n\nType: `'boolean' | 'function' | 'number' | 'string' | 'symbol' | SBType`\n\nThe full type of `SBType` is:\n\n<details>\n  <summary>SBType</summary>\n\n  ```ts\n  interface SBBaseType {\n    required?: boolean;\n    raw?: string;\n  }\n\n  type SBScalarType = SBBaseType & {\n    name: 'boolean' | 'string' | 'number' | 'function' | 'symbol';\n  };\n\n  type SBArrayType = SBBaseType & {\n    name: 'array';\n    value: SBType;\n  };\n  type SBObjectType = SBBaseType & {\n    name: 'object';\n    value: Record<string, SBType>;\n  };\n  type SBEnumType = SBBaseType & {\n    name: 'enum';\n    value: (string | number)[];\n  };\n  type SBIntersectionType = SBBaseType & {\n    name: 'intersection';\n    value: SBType[];\n  };\n  type SBUnionType = SBBaseType & {\n    name: 'union';\n    value: SBType[];\n  };\n  type SBOtherType = SBBaseType & {\n    name: 'other';\n    value: string;\n  };\n\n  type SBType =\n    | SBScalarType\n    | SBEnumType\n    | SBArrayType\n    | SBObjectType\n    | SBIntersectionType\n    | SBUnionType\n    | SBOtherType;\n  ```\n</details>\n\nDefault: [Inferred](#automatic-argtype-inference)\n\nSpecifies the semantic type of the argType. When an argType is [inferred](#automatic-argtype-inference), the information from the various tools is summarized in this property, which is then used to infer other properties, like [`control`](#control) and [`table.type`](#tabletype).\n\nIf you only need to specify the documented type, you should use [`table.type`](#tabletype), instead.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"arg-types-type.md\" />\n\n{/* prettier-ignore-end */}\n\n### `defaultValue`\n\n(⛔️ **Deprecated**)\n\nType: `any`\n\nDefine the default value of the argType. Deprecated in favor of defining the [`arg`](../writing-stories/args.mdx) value directly.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"arg-types-default-value.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/api/cli-options.mdx",
    "content": "---\ntitle: 'CLI options'\nhideRendererSelector: true\nsidebar:\n  order: 8\n  title: CLI options\n---\n\nThe Storybook command line interface (CLI) is the main tool you use to build and develop Storybook.\n\n<Callout variant=\"info\">\n  Storybook collects completely anonymous data to help us improve user experience. Participation is\n  optional, and you may [opt-out](../configure/telemetry.mdx#how-to-opt-out) if you'd not like to\n  share any information.\n</Callout>\n\n## CLI commands\n\nAll of the following documentation is available in the CLI by running `storybook --help`.\n\n<Callout variant=\"info\" icon=\"💡\">\n  Passing options to these commands works slightly differently if you're using npm instead of Yarn.\n  You must prefix all of your options with `--`. For example, `npm run storybook build -- -o\n  ./path/to/build --quiet`.\n</Callout>\n\n### `dev`\n\nCompiles and serves a development build of your Storybook that reflects your source code changes in the browser in real-time. It should be run from the root of your project.\n\n```shell\nstorybook dev [options]\n```\n\nOptions include:\n\n| Option                          | Description                                                                                                                                                                                                                                         |\n| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `--help`                        | Output usage information.<br />`storybook dev --help`                                                                                                                                                                                               |\n| `-V`, `--version`               | Output the version number.<br />`storybook dev -V`                                                                                                                                                                                                  |\n| `-p`, `--port [number]`         | Port to run Storybook.<br />`storybook dev -p 9009`                                                                                                                                                                                                 |\n| `--exact-port`                  | Attempts to run Storybook on the exact port number specified.<br />If the port is already in use, Storybook will exit with an error message.<br />`storybook dev -p 9009 --exact-port`                                                              |\n| `-h`, `--host [string]`         | Host to run Storybook.<br />`storybook dev -h my-host.com`                                                                                                                                                                                          |\n| `-c`, `--config-dir [dir-name]` | Storybook configuration directory.<br />`storybook dev -c .storybook`                                                                                                                                                                               |\n| `--loglevel [level]`            | Controls level of logging during build.<br />Available options: `trace`, `debug`, `info` (default), `warn`, `error`, `silent`<br />`storybook dev --loglevel warn`                                                                                |\n| `--https`                       | Serve Storybook over HTTPS. Note: You must provide your own certificate information.<br />`storybook dev --https`                                                                                                                                   |\n| `--ssl-ca`                      | Provide an SSL certificate authority. (Optional with --https, required if using a self-signed certificate)<br />`storybook dev --ssl-ca my-certificate`                                                                                             |\n| `--ssl-cert`                    | Provide an SSL certificate. (Required with --https)<br />`storybook dev --ssl-cert my-ssl-certificate`                                                                                                                                              |\n| `--ssl-key`                     | Provide an SSL key. (Required with --https)<br />`storybook dev --ssl-key my-ssl-key`                                                                                                                                                               |\n| `--smoke-test`                  | Exit after successful start.<br />`storybook dev --smoke-test`                                                                                                                                                                                      |\n| `--ci`                          | CI mode (skip interactive prompts, don't open browser).<br />`storybook dev --ci`                                                                                                                                                                   |\n| `--no-open`                     | Do not open Storybook automatically in the browser.<br />`storybook dev --no-open`                                                                                                                                                                  |\n| `--quiet`                       | Suppress verbose build output.<br />`storybook dev --quiet`                                                                                                                                                                                         |\n| `--debug`                       | Outputs more logs in the CLI to assist debugging.<br />`storybook dev --debug`                                                                                                                                                                      |\n| `--debug-webpack`               | Display final webpack configurations for debugging purposes.<br />`storybook dev --debug-webpack`                                                                                                                                                   |\n| `--stats-json [dir-name]`       | Write stats JSON to disk.<br />Requires Webpack<br />`storybook dev --stats-json /tmp/stats`                                                                                                                                                        |\n| `--no-version-updates`          | Skips Storybook's update check.<br />`storybook dev --no-version-updates`                                                                                                                                                                           |\n| `--docs`                        | Starts Storybook in documentation mode. Learn more about it in [here](../writing-docs/build-documentation.mdx#preview-storybooks-documentation).<br />`storybook dev --docs`                                                                        |\n| `--initial-path [path]`         | Configures the URL Storybook should open when it opens the browser for the first time.<br />`storybook dev --initial-path=/docs/getting-started--docs`                                                                                              |\n| `--preview-url [path]`          | Overrides the default Storybook preview with a custom built preview URL.<br />`storybook dev --preview-url=http://localhost:1337/external-iframe.html`                                                                                              |\n| `--force-build-preview`         | Forcefully builds Storybook's preview iframe.<br />Useful if you're experiencing issues, or combined with `--preview-url` to ensure the preview is up-to-date.<br />`storybook dev --force-build-preview`                                           |\n| `--disable-telemetry`           | Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry.mdx#how-to-opt-out).<br />`storybook dev --disable-telemetry`                                                                                                     |\n| `--enable-crash-reports`        | Enables sending crash reports to Storybook's telemetry. Learn more about it [here](../configure/telemetry.mdx#crash-reports-disabled-by-default).<br />`storybook dev --enable-crash-reports`                                                       |\n| `--preview-only`                | Skips Storybook's manager from building and opens the app in \"preview only\" mode, which is designed to be used in [unsupported browsers](../sharing/publish-storybook.mdx#build-storybook-for-older-browsers). <br />`storybook dev --preview-only` |\n\n<Callout variant=\"warning\" id=\"static-dir-deprecation\">\n  With the release of Storybook 8, the `-s` CLI flag was removed. We recommend using the [static\n  directory](../configure/integration/images-and-assets.mdx#serving-static-files-via-storybook)\n  instead if you need to serve static files.\n</Callout>\n\n### `build`\n\nCompiles your Storybook instance so it can be [deployed](../sharing/publish-storybook.mdx). It should be run from the root of your project.\n\n```shell\nstorybook build [options]\n```\n\nOptions include:\n\n| Option                          | Description                                                                                                                                                                                                                                    |\n| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `-h`, `--help`                  | Output usage information.<br />`storybook build --help`                                                                                                                                                                                        |\n| `-V`, `--version`               | Output the version number.<br />`storybook build -V`                                                                                                                                                                                           |\n| `-o`, `--output-dir [dir-name]` | Directory where to store built files.<br />`storybook build -o /my-deployed-storybook`                                                                                                                                                         |\n| `-c`, `--config-dir [dir-name]` | Storybook configuration directory.<br />`storybook build -c .storybook`                                                                                                                                                                        |\n| `--loglevel [level]`            | Controls level of logging during build.<br />Available options: `trace`, `debug`, `info` (default), `warn`, `error`, `silent`.<br />`storybook build --loglevel warn`                                                                        |\n| `--quiet`                       | Suppress verbose build output.<br />`storybook build --quiet`                                                                                                                                                                                  |\n| `--debug`                       | Outputs more logs in the CLI to assist debugging.<br />`storybook build --debug`                                                                                                                                                               |\n| `--debug-webpack`               | Display final webpack configurations for debugging purposes.<br />`storybook build --debug-webpack`                                                                                                                                            |\n| `--stats-json [dir-name]`       | Write stats JSON to disk.<br />Requires Webpack<br />`storybook build --stats-json /tmp/stats`                                                                                                                                                 |\n| `--docs`                        | Builds Storybook in documentation mode. Learn more about it in [here](../writing-docs/build-documentation.mdx#publish-storybooks-documentation).<br />`storybook build --docs`                                                                 |\n| `--test`                        | Optimize Storybook's production build for performance and tests by removing unnecessary features with the `test` option. Learn more [here](../api/main-config/main-config-build.mdx).<br />`storybook build --test`                            |\n| `--preview-url [path]`          | Overrides the default Storybook preview with a custom built preview URL.<br />`storybook build --preview-url=http://localhost:1337/external-iframe.html`                                                                                       |\n| `--force-build-preview`         | Forcefully builds Storybook's preview iframe.<br />Useful if you're experiencing issues, or combined with `--preview-url` to ensure the preview is up-to-date.<br />`storybook build --force-build-preview`                                    |\n| `--disable-telemetry`           | Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry.mdx#how-to-opt-out).<br />`storybook build --disable-telemetry`                                                                                              |\n| `--enable-crash-reports`        | Enables sending crash reports to Storybook's telemetry. Learn more about it [here](../configure/telemetry.mdx#crash-reports-disabled-by-default).<br />`storybook build --enable-crash-reports`                                                |\n| `--preview-only`                | Skips Storybook's manager from building and produces a \"preview only\" app, which is designed to be used in [unsupported browsers](../sharing/publish-storybook.mdx#build-storybook-for-older-browsers). <br />`storybook build --preview-only` |\n\n### `init`\n\n<Callout variant=\"info\">\n  We recommend [`create-storybook`](#create-storybook) for new projects. The `init` command will\n  remain available for backwards compatibility.\n</Callout>\n\nInstalls and initializes the specified version (e.g., `@latest`, `@8`, `@next`) of Storybook into your project. If no version is specified, the latest version is installed. Read more in the [installation guide](../get-started/install.mdx).\n\n```shell\nstorybook[@version] init [options]\n```\n\nFor example, `storybook@8.4 init` will install Storybook 8.4 into your project.\n\nOptions include:\n\n| Option                   | Description                                                                                                                                                                                    |\n| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `-h`, `--help`           | Output usage information.<br />`storybook init --help`                                                                                                                                         |\n| `-b`, `--builder`        | Defines the [builder](../builders/index.mdx) to use for your Storybook instance.<br />`storybook init --builder webpack5`                                                                      |\n| `-f`, `--force`          | Forcefully installs Storybook into your project, prompting you to overwrite existing files.<br />`storybook init --force`                                                                      |\n| `-s`, `--skip-install`   | Skips the dependency installation step. Used only when you need to configure Storybook manually.<br />`storybook init --skip-install`                                                          |\n| `-t`, `--type`           | Defines the [framework](../configure/integration/frameworks.mdx) to use for your Storybook instance.<br />`storybook init --type solid`                                                        |\n| `-y`, `--yes`            | Skips interactive prompts and automatically installs Storybook per specified version, including all features.<br />`storybook init --yes`                                                      |\n| `--features [...values]` | Use these features when installing, skipping the prompt. Supported values are `docs`, `test`, and `a11y`, space separated.<br />`storybook init --features docs test a11y`                                   |\n| `--package-manager`      | Sets the package manager to use when installing Storybook.<br />Available package managers include `npm`, `yarn`, and `pnpm`.<br />`storybook init --package-manager pnpm`                     |\n| `--use-pnp`              | Enables [Plug'n'Play](https://yarnpkg.com/features/pnp) support for Yarn. This option is only available when using Yarn as your package manager.<br />`storybook init --use-pnp`               |\n| `-p`, `--parser`         | Sets the [jscodeshift parser](https://github.com/facebook/jscodeshift#parser).<br />Available parsers include `babel`, `babylon`, `flow`, `ts`, and `tsx`.<br />`storybook init --parser tsx`  |\n| `--debug`                | Outputs more logs in the CLI to assist debugging.<br />`storybook init --debug`                                                                                                                |\n| `--disable-telemetry`    | Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry.mdx#how-to-opt-out).<br />`storybook init --disable-telemetry`                                               |\n| `--enable-crash-reports` | Enables sending crash reports to Storybook's telemetry. Learn more about it [here](../configure/telemetry.mdx#crash-reports-disabled-by-default).<br />`storybook init --enable-crash-reports` |\n| `--loglevel <level>`     | Controls level of logging during initialization.<br />Available options: `trace`, `debug`, `info` (default), `warn`, `error`, `silent`<br />`storybook init --loglevel debug`                  |\n| `--logfile [path]`       | Write all debug logs to the specified file at the end of the run. Defaults to debug-storybook.log when [path] is not provided.<br />`storybook init --logfile /tmp/debug-storybook.log`         |\n| `--no-dev`               | Complete the initialization of Storybook without running the Storybook dev server.<br />`storybook init --no-dev`                                                                              |\n\n### `add`\n\nInstalls a Storybook addon and configures your project for it. Read more in the [addon installation guide](../addons/install-addons.mdx).\n\n```shell\nstorybook add [addon] [options]\n```\n\nOptions include:\n\n| Option                     | Description                                                                                                                                                                       |\n| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `-h`, `--help`             | Output usage information.<br />`storybook add --help`                                                                                                                             |\n| `-c`, `--config-dir`       | Storybook configuration directory.<br />`storybook migrate --config-dir .storybook`                                                                           |\n| `--package-manager`        | Sets the package manager to use when installing the addon.<br />Available package managers include `npm`, `yarn`, and `pnpm`.<br />`storybook add [addon] --package-manager pnpm` |\n| `-s`, `--skip-postinstall` | Skips post-install configuration. Used only when you need to configure the addon yourself.<br />`storybook add [addon] --skip-postinstall`                                        |\n| `--debug`                  | Outputs more logs in the CLI to assist debugging.<br />`storybook add --debug`                                                                                                    |\n| `--loglevel <level>`      | Controls level of logging during addon installation.<br />Available options: `trace`, `debug`, `info` (default), `warn`, `error`, `silent`<br />`storybook add [addon] --loglevel debug`    |\n| `--logfile [path]`        | Write all debug logs to the specified file at the end of the run. Defaults to debug-storybook.log when [path] is not provided.<br />`storybook add [addon] --logfile /tmp/debug-storybook.log` |\n\n### `remove`\n\nDeletes a Storybook addon from your project. Read more in the [addon installation guide](../addons/install-addons.mdx#removing-addons).\n\n```shell\nstorybook remove [addon] [options]\n```\n\nOptions include:\n\n| Option                   | Description                                                                                                                                                                                      |\n| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `-h`, `--help`           | Output usage information.<br />`storybook remove --help`                                                                                                                                         |\n| `--package-manager`      | Sets the package manager to use when removing the addon.<br />Available package managers include `npm`, `yarn`, and `pnpm`.<br />`storybook remove [addon]--package-manager pnpm`                |\n| `--debug`                | Outputs more logs in the CLI to assist debugging.<br />`storybook remove --debug`                                                                                                                |\n| `--disable-telemetry`    | Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry.mdx#how-to-opt-out).<br />`storybook remove --disable-telemetry`                                               |\n| `--enable-crash-reports` | Enables sending crash reports to Storybook's telemetry. Learn more about it [here](../configure/telemetry.mdx#crash-reports-disabled-by-default).<br />`storybook remove --enable-crash-reports` |\n\n### `upgrade`\n\nUpgrades your Storybook instance to the specified version (e.g., `@latest`, `@8`, `@next`). Read more in the [upgrade guide](../releases/upgrading.mdx).\n\n```shell\nstorybook[@version] upgrade [options]\n```\n\nFor example, `storybook@latest upgrade --dry-run` will perform a dry run (no actual changes) of upgrading your project to the latest version of Storybook.\n\nOptions include:\n\n| Option                   | Description                                                                                                                                                                                       |\n| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `-h`, `--help`           | Output usage information.<br />`storybook upgrade --help`                                                                                                                                         |\n| `-c, --config-dir <dir-name...>` | Directory or directories to find Storybook configurations<br />`storybook upgrade --config-dir .storybook`                                                                                |\n| `-n`, `--dry-run`        | Checks for version upgrades without installing them.<br />`storybook upgrade --dry-run`                                                                                                           |\n| `-s`, `--skip-check`     | Skips the migration check step during the upgrade process.<br />`storybook upgrade --skip-check`                                                                                                  |\n| `-y`, `--yes`            | Skips interactive prompts and automatically upgrades Storybook to the latest version.<br />`storybook upgrade --yes`                                                                              |\n| `-f`,`--force`           | Force the upgrade, skipping autoblockers check.<br />`storybook upgrade --force`                                                                                                                  |\n| `--package-manager`      | Sets the package manager to use when upgrading Storybook.<br />Available package managers include `npm`, `yarn`, and `pnpm`.<br />`storybook upgrade --package-manager pnpm`                      |\n| `--debug`                | Outputs more logs in the CLI to assist debugging.<br />`storybook upgrade --debug`                                                                                                                |\n| `--disable-telemetry`    | Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry.mdx#how-to-opt-out).<br />`storybook upgrade --disable-telemetry`                                               |\n| `--enable-crash-reports` | Enables sending crash reports to Storybook's telemetry. Learn more about it [here](../configure/telemetry.mdx#crash-reports-disabled-by-default).<br />`storybook upgrade --enable-crash-reports` |\n| `-logfile [path]`       | Write all debug logs to the specified file at the end of the run. Defaults to debug-storybook.log when [path] is not provided.<br />`storybook upgrade --logfile /tmp/debug-storybook.log`         |\n| `--loglevel <level>`     | Define log level: `debug`, `error`, `info`, `silent`, `trace`, or `warn` (default: `info`).<br />`storybook upgrade --loglevel debug`                                                             |\n\n### `migrate`\n\nRuns the provided codemod to ensure your Storybook project is compatible with the specified version. Read more in the [migration guide](../releases/upgrading.mdx).\n\n```shell\nstorybook[@version] migrate [codemod] [options]\n```\n\n<Callout variant=\"info\">\n  The command requires the codemod name (e.g., `csf-2-to-3`) as an argument to apply the necessary\n  changes to your project. You can find the list of available codemods by running `storybook migrate\n  --list`.\n</Callout>\n\nFor example, `storybook@latest migrate csf-2-to-3 --dry-run`, checks your project to verify if the codemod can be applied without making any changes, providing you with a report of which files would be affected.\n\nOptions include:\n\n| Option                     | Description                                                                                                                                                                                      |\n| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `-h`, `--help`             | Output usage information.<br />`storybook migrate --help`                                                                                                                                        |\n| `-c`, `--config-dir`       | Storybook configuration directory.<br />`storybook migrate --config-dir .storybook`                                                                                          |\n| `-n`, `--dry-run`          | Verify the migration exists and show the files to which it will be applied.<br />`storybook migrate --dry-run`                                                                                   |\n| `-l`, `--list`             | Shows a list of available codemods.<br />`storybook migrate --list`                                                                                                                              |\n| `-g`, `--glob`             | Glob for files upon which to apply the codemods.<br />`storybook migrate --glob src/**/*.stories.tsx`                                                                                            |\n| `-p`, `--parser`           | Sets the [jscodeshift parser](https://github.com/facebook/jscodeshift#parser).<br />Available parsers include `babel`, `babylon`, `flow`, `ts`, and `tsx`.<br />`storybook migrate --parser tsx` |\n| `-r`, `--rename [from-to]` | Renames the files affected by the codemod to include the provided suffix.<br />`storybook migrate --rename \".js:.ts\"`                                                                            |\n| `--debug`                  | Outputs more logs in the CLI to assist debugging.<br />`storybook migrate --debug`                                                                                                               |\n\n### `automigrate`\n\nPerform standard configuration checks to determine if your Storybook project can be automatically migrated to the specified version. Read more in the [migration guide](../releases/upgrading.mdx#automigrate-script).\n\n```shell\nstorybook[@version] automigrate [fixId] [options]\n```\n\nFor example, `storybook@latest automigrate --dry-run` scans your project for potential migrations that can be applied automatically without making any changes.\n\nOptions include:\n\n| Option                   | Description                                                                                                                                                                                                               |\n| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `-h`, `--help`           | Output usage information.<br />`storybook automigrate --help`                                                                                                                                                             |\n| `-c`, `--config-dir`     | Storybook configuration directory.<br />`storybook automigrate --config-dir .storybook`                                                                                                               |\n| `-n`, `--dry-run`        | Checks for available migrations without applying them.<br />`storybook automigrate --dry-run`                                                                                                                             |\n| `-s`, `--skip-install`   | Skip installing dependencies whenever applicable.<br />`storybook automigrate --skip-install`                                                                                                                             |\n| `-y`, `--yes`            | Applies available migrations automatically without prompting for confirmation.<br />`storybook automigrate --yes`                                                                                                         |\n| `-l`, `--list`           | Shows a list of available automigrations.<br />`storybook automigrate --list`                                                                                                                                             |\n| `--package-manager`      | Sets the package manager to use when running the auto migration.<br />Available package managers include `npm`, `yarn`, and `pnpm`.<br />`storybook automigrate --package-manager pnpm`                                   |\n| `--renderer`             | Specifies Storybook's renderer to use when running the automigration.<br />Useful for monorepo environments where multiple Storybook instances can exist in the same project.<br />`storybook automigrate --renderer vue` |\n| `--debug`                | Outputs more logs in the CLI to assist debugging.<br />`storybook automigrate --debug`                                                                                                                                    |\n| `--disable-telemetry`    | Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry.mdx#how-to-opt-out).<br />`storybook automigrate --disable-telemetry`                                                                   |\n| `--enable-crash-reports` | Enables sending crash reports to Storybook's telemetry. Learn more about it [here](../configure/telemetry.mdx#crash-reports-disabled-by-default).<br />`storybook automigrate --enable-crash-reports`                     |\n\n### `doctor`\n\nPerforms a health check on your Storybook project for common issues (e.g., duplicate dependencies, incompatible addons or mismatched versions) and provides suggestions on how to fix them. Applicable when [upgrading](../releases/upgrading.mdx#verifying-the-upgrade) Storybook versions.\n\n```shell\nstorybook doctor [options]\n```\n\nOptions include:\n\n| Option               | Description                                                                                                                                                                      |\n| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `-h`, `--help`       | Output usage information.<br />`storybook doctor --help`                                                                                                                         |\n| `-c`, `--config-dir` | Storybook configuration directory.<br />`storybook doctor --config-dir .storybook`                                                                           |\n| `--package-manager`  | Sets the package manager to use when running the health check.<br />Available package managers include `npm`, `yarn`, and `pnpm`.<br />`storybook doctor --package-manager pnpm` |\n| `--debug`            | Outputs more logs in the CLI to assist debugging.<br />`storybook doctor --debug`                                                                                                |\n\n### `info`\n\nReports useful debugging information about your environment. Helpful in providing information when opening an issue or a discussion.\n\n```shell\nstorybook info\n```\n\nExample output:\n\n```shell\nStorybook Environment Info:\n\n  System:\n    OS: macOS 14.2\n    CPU: (8) arm64 Apple M3\n    Shell: 5.9 - /bin/zsh\n  Binaries:\n    Node: 18.19.0 - ~/.nvm/versions/node/v18.19.0/bin/node\n    npm: 10.2.3 - ~/.nvm/versions/node/v18.19.0/bin/npm <----- active\n  Browsers:\n    Chrome: 120.0.6099.199\n  npmPackages:\n    @storybook/addon-onboarding: ^1.0.10 => 1.0.10\n    @storybook/react: ^7.6.6 => 7.6.6\n    @storybook/react-vite: ^7.6.6 => 7.6.6\n    storybook: ^7.6.6 => 7.6.6\n  npmGlobalPackages:\n    chromatic: ^10.2.0 => 10.2.0\n```\n\n### `index`\n\nBuild an `index.json` that lists all stories and docs entries in your Storybook.\n\n```shell\nstorybook index [options]\n```\n\nOptions include:\n\n| Option                            | Description                                            |\n| --------------------------------- | ------------------------------------------------------ |\n| `-o`, `--output-file <file-name>` | JSON file to output index                              |\n| `-c`, `--config-dir <dir-name>`   | Storybook configuration directory  |\n| `--quiet`                         | Suppress verbose build output                          |\n| `--loglevel <level>`              | Control level of logging during build                  |\n| `--disable-telemetry`             | Disables Storybook's telemetry                         |\n| `--debug`                         | Outputs more logs in the CLI to assist debugging.      |\n| `--enable-crash-reports`          | Enables sending crash reports to Storybook's telemetry |\n\n### `sandbox`\n\nGenerates a local sandbox project using the specified version (e.g., `@latest`, `@8`, `@next`) for testing Storybook features based on the list of supported [frameworks](../configure/integration/frameworks.mdx). Useful for reproducing bugs when opening an issue or a discussion.\n\n```shell\nstorybook[@version] sandbox [framework-filter] [options]\n```\n\nFor example, `storybook@next sandbox` will generated sandboxes using the newest pre-release version of Storybook.\n\nThe `framework-filter` argument is optional and can filter the list of available frameworks. For example, `storybook@next sandbox react` will only offer to generate React-based sandboxes.\n\nOptions include:\n\n| Option                      | Description                                                                                                                                                                                       |\n| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `-h`, `--help`              | Output usage information.<br />`storybook sandbox --help`                                                                                                                                         |\n| `-o`, `--output [dir-name]` | Configures the location of the sandbox project.<br />`storybook sandbox --output /my-sandbox-project`                                                                                             |\n| `--no-init`                 | Generates a sandbox project without initializing Storybook.<br />`storybook sandbox --no-init`                                                                                                    |\n| `--debug`                   | Outputs more logs in the CLI to assist debugging.<br />`storybook sandbox --debug`                                                                                                                |\n| `--disable-telemetry`       | Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry.mdx#how-to-opt-out).<br />`storybook sandbox --disable-telemetry`                                               |\n| `--enable-crash-reports`    | Enables sending crash reports to Storybook's telemetry. Learn more about it [here](../configure/telemetry.mdx#crash-reports-disabled-by-default).<br />`storybook sandbox --enable-crash-reports` |\n\n<Callout variant=\"info\">\n  If you're looking for a hosted version of the available sandboxes, see\n  [storybook.new](https://storybook.new).\n</Callout>\n\n## `create-storybook`\n\nTo streamline the process of creating a new Storybook project, a separate CLI called `create-storybook` is provided. Package managers such as npm, pnpm, and Yarn will execute this command when running `create storybook`. You can specify a version (e.g., `@latest`, `@8`, `@next`) or it will default to the latest version. Read more in the [installation guide](../get-started/install.mdx).\n\n```shell\ncreate storybook[@version] [options]\n```\n\nFor example, `create storybook@8.6` will install Storybook 8.6 into your project.\n\nOptions include:\n\n| Option                   | Description                                                                                                                                                                                      |\n| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `-h`, `--help`           | Output usage information.<br />`create storybook --help`                                                                                                                                         |\n| `-b`, `--builder`        | Defines the [builder](../builders/index.mdx) to use for your Storybook instance.<br />`create storybook --builder webpack5`                                                                      |\n| `-f`, `--force`          | Forcefully installs Storybook into your project, prompting you to overwrite existing files.<br />`create storybook --force`                                                                      |\n| `-s`, `--skip-install`   | Skips the dependency installation step. Used only when you need to configure Storybook manually.<br />`create storybook --skip-install`                                                          |\n| `-t`, `--type`           | Defines the [framework](../configure/integration/frameworks.mdx) to use for your Storybook instance.<br />`create storybook --type solid`                                                        |\n| `-y`, `--yes`            | Skips interactive prompts and automatically installs Storybook per specified version, including all features.<br />`create storybook --yes`                                                      |\n| `--features [...values]` | Use these features when installing, skipping the prompt. Supported values are `docs`, `test`, and `a11y`, space separated.<br />`create storybook --features docs test a11y`                     |\n| `--package-manager`      | Sets the package manager to use when installing Storybook.<br />Available package managers include `npm`, `yarn`, and `pnpm`.<br />`create storybook --package-manager pnpm`                     |\n| `--use-pnp`              | Enables [Plug'n'Play](https://yarnpkg.com/features/pnp) support for Yarn. This option is only available when using Yarn as your package manager.<br />`create storybook --use-pnp`               |\n| `-p`, `--parser`         | Sets the [jscodeshift parser](https://github.com/facebook/jscodeshift#parser).<br />Available parsers include `babel`, `babylon`, `flow`, `ts`, and `tsx`.<br />`create storybook --parser tsx`  |\n| `--debug`                | Outputs more logs in the CLI to assist debugging.<br />`create storybook --debug`                                                                                                                |\n| `--disable-telemetry`    | Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry.mdx#how-to-opt-out).<br />`create storybook --disable-telemetry`                                               |\n| `--enable-crash-reports` | Enables sending crash reports to Storybook's telemetry. Learn more about it [here](../configure/telemetry.mdx#crash-reports-disabled-by-default).<br />`create storybook --enable-crash-reports` |\n| `--loglevel <level>`     | Controls level of logging during initialization.<br />Available options: `trace`, `debug`, `info` (default), `warn`, `error`, `silent`<br />`storybook init --loglevel debug`                    |\n| `--logfile [path]`       | Write all debug logs to the specified file at the end of the run. Defaults to debug-storybook.log when [path] is not provided.<br />`storybook init --logfile /tmp/debug-storybook.log`         |\n| `--no-dev`               | Complete the initialization of Storybook without running the Storybook dev server.<br />`create storybook --no-dev`                                                                              |\n"
  },
  {
    "path": "docs/api/csf/csf-next.mdx",
    "content": "---\ntitle: 'Component Story Format (CSF)'\nisTab: true\ntab:\n  order: 2\n  title: CSF Next (Preview)\n---\n\n<If notRenderer={['react', 'vue', 'angular', 'web-components']}>\n\n<Callout variant=\"info\">\n  CSF Next is currently only supported in [React](?renderer=react), [Vue](?renderer=vue), [Angular](?renderer=angular), and [Web Components](?renderer=web-components) projects.\n</Callout>\n\n</If>\n\n<If renderer={['react', 'vue', 'angular', 'web-components']}>\n\n<Callout variant=\"warning\" icon=\"🧪\">\n  This is a [**preview**](../../releases/features.mdx#preview) feature and (though unlikely) the API may change in future releases. We [welcome feedback](https://github.com/storybookjs/storybook/discussions/30112) and contributions to help improve this feature.\n</Callout>\n\nCSF Next is the next evolution of Storybook's Component Story Format (CSF). This new API uses a pattern called factory functions to provide full type safety to your Storybook stories, making it easier to configure addons correctly and unlocking the full potential of Storybook's features.\n\nThis reference provides an overview of the API and a migration guide to upgrade from prior CSF versions.\n\n## Overview\n\nThe CSF Next API is composed of functions to help you write stories. Note how three of the functions operate as factories, each producing the next function in the chain (`definePreview` → `preview.meta` → `meta.story`), providing full type safety at each step.\n\n### `defineMain`\n\nWith CSF Next, your [main Storybook config](../main-config/main-config.mdx) is specified by the `defineMain` function. This function is type-safe and will automatically infer types for your project.\n\n```ts title=\".storybook/main.js|ts\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { defineMain } from '@storybook/your-framework/node';\n\nexport default defineMain({\n  framework: '@storybook/your-framework',\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],\n  addons: ['@storybook/addon-a11y'],\n});\n```\n\n### `definePreview`\n\nSimilarly, the `definePreview` function specifies your project's story configuration. This function is also type-safe and will infer types throughout your project.\n\nImportantly, by specifying addons here, their types will be available throughout your project, enabling autocompletion and type checking.\n\nYou will import the result of this function, `preview`, in your story files to define the component meta.\n\n```ts title=\".storybook/preview.js|ts\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\nimport { definePreview } from '@storybook/your-framework';\nimport addonA11y from '@storybook/addon-a11y';\n\nexport default definePreview({\n  // 👇 Add your addons here\n  addons: [addonA11y()],\n  parameters: {\n    // type-safe!\n    a11y: {\n      options: { xpath: true },\n    },\n  },\n});\n```\n\n<Callout variant=\"info\">\n  The preview configuration will be automatically updated to reference the [necessary addons](#preview-addons) when installing an addon via `npx storybook add <addon-name>` or running `storybook dev`.\n</Callout>\n\n### `preview.meta`\n\nThe `meta` function on the `preview` object is used to define the [metadata for your stories](./index.mdx#default-export). It accepts an object containing the `component`, `title`, `parameters`, and other story properties.\n\n```ts title=\"Button.stories.js|ts\"\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\nconst meta = preview.meta({\n  component: Button,\n  parameters: {\n    // type-safe!\n    layout: 'centered',\n  }\n});\n```\n\n<Callout variant=\"info\" icon=\"💡\">\n\n<a name=\"subpath-imports\" />\n\nIf you would like to use absolute imports instead of relative imports for your preview config, like below, you can configure that using subpath imports or an alias.\n\n```ts\n// ✅ Absolute imports won't break if you move story files around\nimport preview from '#.storybook/preview';\n\n// ❌ Relative imports can break if you move story files around\nimport preview from '../../../.storybook/preview';\n```\n\n<details>\n<summary>Configuration</summary>\n\nSubpath imports are a Node.js standard that allows you to define custom import paths in your project, which you can then use throughout your codebase.\n\nTo configure subpath imports, add the following to your `package.json`:\n\n```json title=\"package.json\"\n{\n  \"imports\": {\n    \"#*\": [\"./*\", \"./*.ts\", \"./*.tsx\"],\n  },\n}\n```\n\nFor more information, refer to the [subpath imports documentation](../../writing-stories/mocking-data-and-modules/mocking-modules.mdx#subpath-imports).\n\n---\n\nAlternatively, you can [configure an alias in your builder](../../writing-stories/mocking-data-and-modules/mocking-modules.mdx#builder-aliases) (Vite or Webpack).\n\n</details>\n\n</Callout>\n\n#### `preview.type.meta`\n\nBy default, `preview.meta` will infer the type of your component's props automatically. However, if you need to extend or modify the inferred types, you can use the `preview.type` function to specify custom types.\n\nThis example is for React, but the same API applies to all supported renderers.\n\n```tsx title=\"Button.stories.ts|tsx\"\nimport * as React from 'react';\n\nimport preview from '../.storybook/preview';\n\nimport { Button } from './Button';\n\ntype CustomProps = React.ComponentProps<typeof Button> & { customProp: string };\n\nconst meta = preview.type<{ args: CustomProps }>().meta({\n  component: Button,\n  // 👇 Correct types\n  render: ({ customProp, ...args }) => <>{customProp} <Button {...args} /></>,\n});\n\nexport const Primary = meta.story({\n  // 👇 Correct types\n  args: {\n    customProp: 'Hello, world!',\n  },\n});\n```\n\nFor more information on typing your stories, refer to the [writing stories in TypeScript guide](../../writing-stories/typescript.mdx).\n\n### `meta.story`\n\nFinally, the `story` function on the `meta` object defines the stories. This function accepts an object containing the [`name`](../../writing-stories/index.mdx#rename-stories), [`args`](../../writing-stories/args.mdx), [`parameters`](../../writing-stories/parameters.mdx), and other story properties.\n\n```ts title=\"Button.stories.js|ts\"\n// ...from above\nconst meta = preview.meta({ /* ... */ });\n\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n  },\n});\n```\n\n#### `<Story>.extend`\n\nYou can use the `.extend` method to create a new story based on an existing one, with the option to override or add new properties.\n\n<details>\n<summary>Property merging details</summary>\n\nProperties are merged intelligently:\n\n- [`args`](../../writing-stories/args.mdx) are shallow merged\n- [`parameters`](../../writing-stories/parameters.mdx) are deep merged, except for arrays, which are replaced\n- [`decorators`](../../writing-stories/decorators.mdx) and [`tags`](../../writing-stories/tags.mdx) are concatenated\n\n```ts title=\"Button.stories.js|ts\"\n// ...from above\nconst meta = preview.meta({ /* ... */ });\n\nexport const Example = meta.story({\n  args: {\n    primary: true,\n    exampleArray: ['a', 'b'],\n    exampleObject: { a: 'a', b: 'b' },\n  },\n  parameters: {\n    exampleArray: ['a', 'b'],\n    exampleObject: { a: 'a', b: 'b' },\n  },\n  tags: ['a'],\n});\n\n/* \n * 👇 Final values applied:\n *    {\n *      args: {\n *        primary: true,\n *        disabled: true,\n *        exampleArray: ['c'],\n *        exampleObject: { a: 'c' }\n *      },\n *      parameters: {\n *        exampleArray: ['c'],\n *        exampleObject: { a: 'c', b: 'b' }\n *      },\n *      tags: ['a', 'b']\n *    }\n */\nexport const ExtendedExample = Example.extend({\n  args: {\n    disabled: true,\n    exampleArray: ['c'],\n    exampleObject: { a: 'c' },\n  },\n  parameters: {\n    disabled: true,\n    exampleArray: ['c'],\n    exampleObject: { a: 'c' },\n  },\n  tags: ['b'],\n});\n```\n\n</details>\n\n```ts title=\"Button.stories.js|ts\"\n// ...from above\nconst meta = preview.meta({ /* ... */ });\n\nexport const Primary = meta.story({\n  args: {\n    primary: true,\n  },\n});\n\nexport const PrimaryDisabled = Primary.extend({\n  args: {\n    disabled: true,\n  },\n});\n```\n\n#### `<Story>.test`\n\n(⚠️ **Experimental**)\n\nA more ergonomic way to define [tests for your stories](../../writing-tests/index.mdx). While this API is still experimental, it is [documented in the RFC to gather feedback](https://github.com/storybookjs/storybook/discussions/30119) and must be enabled via the [`experimentalTestSyntax` feature flag](../main-config/main-config-features.mdx#experimentaltestsyntax).\n\n```ts title=\"Button.stories.js|ts\"\n// ...from above\nexport const PrimaryDisabled = Primary.extend({ args: { disabled: true } });\n\n// 👇 .test method: Attach tests to a story\n//    The test function can run the same code as the play function\nPrimaryDisabled.test('should be disabled', async ({ canvas, userEvent, args }) => {\n  const button = await canvas.findByRole('button');\n  await userEvent.click(button);\n\n  await expect(button).toHaveAttribute('aria-disabled', 'true');\n  await expect(args.onClick).not.toHaveBeenCalled();\n});\n```\n\n## Upgrade to CSF Next\n\nYou can upgrade your stories to CSF Next either automatically (from CSF 3) or manually (from CSF 1, 2, or 3). CSF Next is designed to be usable incrementally; you do not have to upgrade all of your story files at once. However, you cannot mix story formats within the same file.\n\nBefore proceeding, be sure you're using the latest version of Storybook. You can upgrade your Storybook automatically with this command:\n\n<CodeSnippets path=\"storybook-upgrade.md\" />\n\n### Automatically\n\nYou can automatically upgrade all of your project's stories from CSF 3 to CSF Next with this command:\n\n<CodeSnippets path=\"csf-factories-automigrate.md\" />\n\n#### Monorepos\n\nIf your project has multiple Storybook configurations, run the command with the `-c` flag pointing to each config directory:\n\n<CodeSnippets path=\"csf-factories-automigrate-with-config-directory.md\" />\n\nIt will run through each of the manual upgrade steps below on all of your story files.\n\n<details>\n<summary>Upgrading from CSF 2 to 3</summary>\n\nYou must be using CSF 3 to automatically upgrade to CSF Next. If you are using CSF 2, you can upgrade to CSF 3 first using this command:\n\n<CodeSnippets path=\"migrate-csf-2-to-3.md\" />\n\n</details>\n\n### Manual\n\nYou can also upgrade your project's story files to CSF Next manually. Before using CSF Next in a story file, you must upgrade your `.storybook/main.js|ts` and `.storybook/preview.js|ts` files.\n\n**1. Update your main Storybook config file**\n\nUpdate your `.storybook/main.js|ts` file to use the new [`defineMain`](#definemain) function.\n\n```diff title=\".storybook/main.js|ts\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\n+ import { defineMain } from '@storybook/your-framework/node';\n- import { StorybookConfig } from '@storybook/your-framework';\n\n+ export default defineMain({\n- export const config: StorybookConfig = {\n    // ...config itself is unchanged\n+ });\n- };\n- export default config;\n```\n\n**2. Update your preview config file**\n<a name=\"preview-addons\" />\n\nUpdate your `.storybook/preview.js|ts` file to use the new [`definePreview`](#definepreview) function.\n\n<details>\n<summary>Which addons should be specified in `preview`?</summary>\n\nThe ability for an addon to provide annotation types (`parameters`, `globals`, etc.) is new and not all addons support it yet.\n\nIf an addon provides annotations (i.e. it distributes a `./preview` export), it can be imported in two ways:\n\n1. For official Storybook addons, you import the default export:\n   `import addonName from '@storybook/addon-name'`\n\n2. For community addons, you should import the entire module and access the addon from there:\n   `import * as addonName from 'community-addon-name'`\n\n</details>\n\n```diff title=\".storybook/preview.js|ts\"\n// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\n+ import { definePreview } from '@storybook/your-framework';\n- import type { Preview } from '@storybook/your-framework';\n// 👇 Import the addons you are using\n+ import addonA11y from '@storybook/addon-a11y';\n\n+ export default definePreview({\n- export const preview: Preview = {\n    // ...current config\n    // 👇 Add your addons here\n+   addons: [addonA11y()],\n+ });\n- };\n- export default preview;\n```\n\n**3. Update your story files**\n\nStory files have been updated for improved usability. With the new format:\n\n- Import the preview construct from the Storybook preview file\n- The meta object is now created via the [`preview.meta`](#previewmeta) function and does not have to be exported as a default export\n- Stories are now created from the meta object, via the [`meta.story`](#metastory) function\n\n<Callout variant=\"info\">\nThe examples below show the changes needed to upgrade a story file from CSF 3 to CSF Next. You can also upgrade from CSF 1 or 2 using similar steps.\n</Callout>\n\n```diff title=\"Button.stories.js|ts\"\n+ import preview from '../.storybook/preview';\n- import type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\n+ const meta = preview.meta({\n- const meta = {\n    // ...meta object is unchanged\n+ });\n- } satisfies Meta<typeof Button>;\n- export default meta;\n\n- type Story = StoryObj<typeof meta>;\n\n+ export const Primary = meta.story({\n- export const Primary: Story = {\n    // ...story object is unchanged\n+ });\n- };\n```\n\nNote that importing or manually applying the component props type to the meta or stories is no longer necessary. Thanks to the factory function pattern, the types are now inferred automatically.\n\n<details>\n<summary>Handling complex types</summary>\n\nIf you were previously using complex types for your meta or stories, such as intersection types to add custom args, you can now use the [`preview.type.meta`](#previewtypemeta) pattern to explicitly specify types.\n\n```diff title=\"Button.stories.js|ts\"\n+ import preview from '../.storybook/preview';\n- import type { Meta, StoryObj } from '@storybook/your-framework';\n\nimport { Button } from './Button';\n\ntype CustomProps = React.ComponentProps<typeof Button> & { customProp: string };\n\n+ const meta = preview.type<{ args: CustomProps }>().meta({\n- const meta = {\n    // ...meta object is unchanged\n+ });\n- } satisfies Meta<CustomProps>;\n- export default meta;\n\n- type Story = StoryObj<typeof meta>;\n\n+ export const Primary = meta.story({\n- export const Primary: Story = {\n    // ...story object is unchanged\n+ });\n- };\n```\n\n</details>\n\n**3.1 Reusing story properties**\n\n<Callout variant=\"info\" icon=\"💡\">\n\nIf you are reusing story properties to create a new story based on another, the [`<Story>.extend`](#storyextend) method is the recommended way to do so.\n\n</Callout>\n\nPreviously, story properties such as `Story.args` or `Story.parameters` were accessed directly when reusing them in another story. While accessing them like this is still supported, it is deprecated in CSF Next.\n\nAll of the story properties are now contained within a new property called `composed` and should be accessed from that property instead. For instance, `Story.composed.args` or `Story.composed.parameters`.\n\n```diff title=\"Button.stories.js|ts\"\n// ...rest of file\n\n+ export const Primary = meta.story({\n- export const Primary: Story = {\n    args: { primary: true },\n+ });\n- };\n\n+ export const PrimaryDisabled = meta.story({\n- export const PrimaryDisabled: Story = {\n    args: {\n+     ...Primary.composed.args,\n-     ...Primary.args,\n      disabled: true,\n    }\n+ });\n- };\n```\n\n<Callout variant=\"info\">\n  The property name \"composed\" was chosen because the values within are composed from the story, its component meta, and the preview configuration.\n\n  If you want to access the direct input to the story, you can use `Story.input` instead of `Story.composed`.\n</Callout>\n\n**4. Update your Vitest setup file**\n\nIf you're using [Storybook's Vitest addon](../../writing-tests/integrations/vitest-addon/index.mdx), you can remove your Vitest setup file (`.storybook/vitest.setup.ts`).\n\nIf you are using [portable stories in Vitest](../portable-stories/portable-stories-vitest.mdx), you may use a Vitest setup file to configure your stories. This file must be updated to use the new CSF Next format.\n\n<Callout variant=\"warning\">\nNote that this only applies if you use CSF Next for all your tested stories. If you use a mix of CSF 1, 2, or 3 and CSF Next, you must maintain two separate setup files.\n</Callout>\n\n```diff title=\"vitest.setup.js|ts\"\nimport { beforeAll } from 'vitest';\n// 👇 No longer necessary\n- // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.\nimport { setProjectAnnotations } from '@storybook/your-framework';\n- import * as addonAnnotations from 'my-addon/preview';\n+ import preview from './.storybook/preview';\n- import * as previewAnnotations from './.storybook/preview';\n\n// No longer necessary\n- const annotations = setProjectAnnotations([previewAnnotations, addonAnnotations]);\n\n// Run Storybook's beforeAll hook\n+ beforeAll(preview.composed.beforeAll);\n- beforeAll(annotations.beforeAll);\n```\n\n**5. Reusing stories in test files**\n\n[Storybook's Vitest addon](../../writing-tests/integrations/vitest-addon/index.mdx) allows you to test your components directly inside Storybook. All the stories are automatically turned into Vitest tests, making integration seamless in your testing suite.\n\nIf you cannot use Storybook Test, you can still reuse the stories in your test files using [portable stories](../portable-stories/portable-stories-vitest.mdx). In prior story formats, you had to compose the stories before rendering them in your test files. With CSF Next, you can now reuse the stories directly.\n\n```diff title=\"Button.test.js|ts\"\nimport { test, expect } from 'vitest';\nimport { screen } from '@testing-library/react';\n- import { composeStories } from '@storybook/your-framework';\n\n// Import all stories from the stories file\nimport * as stories from './Button.stories';\n\n+ const { Primary } = stories;\n- const { Primary } = composeStories(stories);\n\ntest('renders primary button with default args', async () => {\n  // The run function will mount the component and run all of Storybook's lifecycle hooks\n  await Primary.run();\n  const buttonElement = screen.getByText('Text coming from args in stories file!');\n  expect(buttonElement).not.toBeNull();\n});\n```\n\nThe `Story` object also provides a `Component` property, enabling you to render the component with any method you choose, such as [Testing Library](https://testing-library.com/). You can also access its composed properties ([`args`](../../writing-stories/args.mdx), [`parameters`](../../writing-stories/parameters.mdx), etc.) via the `composed` property.\n\nHere's an example of how you can reuse a story in a test file by rendering its component:\n\n{/* prettier-ignore-start */}\n<CodeSnippets path=\"portable-stories-csf-factory-render.md\" />\n{/* prettier-ignore-end */}\n\n## Frequently asked questions (FAQ)\n\n### Will I have to migrate all of my stories to this new format?\n\nStorybook will continue to support CSF 1, [CSF 2](../../../release-6-5/docs/api/stories/csf.mdx), and [CSF 3](./index.mdx) for the foreseeable future. None of these prior formats are deprecated.\n\nWhile using CSF Next, you can still use the older formats, as long as they are not mixed in the same file. If you want to migrate your existing files to the new format, refer to [the upgrade section](#upgrading-from-csf-1-2-or-3), above.\n\n### Will this format work with MDX docs pages?\n\nYes, the [doc blocks](../../writing-docs/doc-blocks.mdx) used to reference stories in MDX files support the CSF Next format with no changes needed.\n\n### How can I know more about this format and provide feedback?\n\nFor more information on this experimental format's original proposal, refer to its [RFC on GitHub](https://github.com/storybookjs/storybook/discussions/30112). We welcome your comments!\n\n</If>"
  },
  {
    "path": "docs/api/csf/index.mdx",
    "content": "---\ntitle: 'Component Story Format (CSF)'\nsidebar:\n  order: 2\n  title: Component Story Format (CSF)\nisTab: true\ntab:\n  order: 1\n  title: CSF 3\n---\n\nComponent Story Format (CSF) is the recommended way to [write stories](../../writing-stories/index.mdx). It's an open standard based on ES6 modules that is portable beyond Storybook.\n\nIn CSF, stories and component metadata are defined as ES Modules. Every component story file consists of a required [default export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export#Using_the_default_export) and one or more [named exports](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export).\n\n## Default export\n\nThe default export defines metadata about your component, including the `component` itself, its `title` (where it will show up in the [navigation UI story hierarchy](../../writing-stories/naming-components-and-hierarchy.mdx#sorting-stories)), [decorators](../../writing-stories/decorators.mdx), and [parameters](../../writing-stories/parameters.mdx).\n\n<If renderer=\"svelte\">\n\n<Callout variant=\"info\">\n\nWhen writing Svelte CSF stories, you use the `defineMeta` function instead of the default export to define the metadata for your component. \n\n</Callout>\n\n</If>\n\nThe `component` field is required and used by addons for automatic prop table generation and display of other component metadata. The `title` field is optional and should be unique (i.e., not re-used across files).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"my-component-story-mandatory-export.md\" />\n\n{/* prettier-ignore-end */}\n\nFor more examples, see [writing stories](../../writing-stories/index.mdx).\n\n## Named story exports\n\nWith CSF, every named export in the file represents a story object by default.\n\n<If renderer=\"svelte\">\n\n<Callout variant=\"info\">\n\nWith Svelte CSF, you use the `Story` component returned by `defineMeta` instead of a named export to define a story. The name of the story, shown in the sidebar, is defined by the `name` attribute of the Story component. Annotations, such as `args`, `decorators`, and `parameters`, are defined as attributes on the Story component.\n\n</Callout>\n\n</If>\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"my-component-story-basic-and-props.md\" />\n\n{/* prettier-ignore-end */}\n\nThe exported identifiers will be converted to \"start case\" using Lodash's [startCase](https://lodash.com/docs/#startCase) function. For example:\n\n| Identifier       | Transformation      |\n| ---------------- | ------------------- |\n| name             | Name                |\n| someName         | Some Name           |\n| someNAME         | Some NAME           |\n| some\\_custom\\_NAME | Some Custom NAME  |\n| someName1234     | Some Name 1 2 3 4   |\n\nWe recommend that all export names to start with a capital letter.\n\nStory objects can be annotated with a few different fields to define story-level [decorators](../../writing-stories/decorators.mdx) and [parameters](../../writing-stories/parameters.mdx), and also to define the `name` of the story.\n\nStorybook's `name` configuration element is helpful in specific circumstances. Common use cases are names with special characters or Javascript restricted words. If not specified, Storybook defaults to the named export.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"my-component-story-with-storyname.md\" />\n\n{/* prettier-ignore-end */}\n\n## Args story inputs\n\nStarting in SB 6.0, stories accept named inputs called Args. Args are dynamic data that are provided (and possibly updated by) Storybook and its addons.\n\nConsider Storybook’s [\"Button\" example](../../writing-stories/index.mdx#defining-stories) of a text button that logs its click events:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-click-handler.md\" />\n\n{/* prettier-ignore-end */}\n\nNow consider the same example, re-written with args:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-click-handler-args.md\" />\n\n{/* prettier-ignore-end */}\n\nOr even more simply:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-click-handler-simplificated.md\" />\n\n{/* prettier-ignore-end */}\n\nNot only are these versions shorter and more accessible to write than their no-args counterparts, but they are also more portable since the code doesn't depend on the actions feature specifically.\n\nFor more information on setting up [Docs](../../writing-docs/index.mdx) and [Actions](../../essentials/actions.mdx), see their respective documentation.\n\n## Play function\n\nStorybook's `play` functions are small snippets of code executed when the story renders in the UI. They are convenient helper methods to help you test use cases that otherwise weren't possible or required user intervention.\n\nA good use case for the `play` function is a form component. With previous Storybook versions, you'd write your set of stories and had to interact with the component to validate it. With Storybook's play functions, you could write the following story:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"login-form-with-play-function.md\" />\n\n{/* prettier-ignore-end */}\n\nWhen the story renders in the UI, Storybook executes each step defined in the `play` function and runs the assertions without the need for user interaction.\n\n<IfRenderer renderer={[ 'angular', 'ember', 'html', 'preact', 'qwik', 'react', 'solid', 'vue', 'web-components' ]}>\n  ## Custom render functions\n\n  Starting in Storybook 6.4, you can write your stories as JavaScript objects, reducing the boilerplate code you need to generate to test your components, thus improving functionality and usability. `Render` functions are helpful methods to give you additional control over how the story renders. For example, if you were writing a story as an object and you wanted to specify how your component should render, you could write the following:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"component-story-with-custom-render-function.md\" />\n\n  {/* prettier-ignore-end */}\n\n  When Storybook loads this story, it will detect the existence of a `render` function and adjust the component rendering accordingly based on what's defined.\n</IfRenderer>\n\n<IfRenderer renderer=\"svelte\">\n   ## Custom render functions\n\n   If you're using Svelte CSF to write your stories, you can add a custom snippet to allow you additional control over how your story renders. For example, if you were writing a story and you wanted to specify how your component should render, you could write the following:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"component-story-with-custom-render-function.md\" />\n\n  {/* prettier-ignore-end */}\n  \n</IfRenderer>\n\n## Storybook export vs. name handling\n\nStorybook handles named exports and the `name` option slightly differently. When should you use one vs. the other?\n\nStorybook will always use the named export to determine the story ID and URL.\n\nIf you specify the `name` option, it will be used as the story display name in the UI. Otherwise, it defaults to the named export, processed through Storybook's `storyNameFromExport` and `lodash.startCase` functions.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-test-with-storyname.md\" />\n\n{/* prettier-ignore-end */}\n\nWhen you want to change the name of your story, rename the CSF export. It will change the name of the story and also change the story's ID and URL.\n\nIt would be best if you used the `name` configuration element in the following cases:\n\n1. You want the name to show up in the Storybook UI in a way that's not possible with a named export, e.g., reserved keywords like \"default\", special characters like emoji, spacing/capitalization other than what's provided by `storyNameFromExport`.\n2. You want to preserve the Story ID independently from changing how it's displayed. Having stable Story IDs is helpful for integration with third-party tools.\n\n## Non-story exports\n\nIn some cases, you may want to export a mixture of stories and non-stories (e.g., mocked data).\n\nYou can use the optional configuration fields `includeStories` and `excludeStories` in the default export to make this possible. You can define them as an array of strings or regular expressions.\n\nConsider the following story file:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"my-component-story-with-nonstory.md\" />\n\n{/* prettier-ignore-end */}\n\nWhen this file renders in Storybook, it treats `ComplexStory` and `SimpleStory` as stories and ignores the `data` named exports.\n\nFor this particular example, you could achieve the same result in different ways, depending on what's convenient:\n\n* `includeStories: /^[A-Z]/`\n* `includeStories: /.*Story$/`\n* `includeStories: ['SimpleStory', 'ComplexStory']`\n* `excludeStories: /^[a-z]/`\n* `excludeStories: /.*Data$/`\n* `excludeStories: ['simpleData', 'complexData']`\n\nThe first option is the recommended solution if you follow the best practice of starting story exports with an uppercase letter (i.e., use UpperCamelCase).\n\n## Upgrading from CSF 2 to CSF 3\n\n<Callout variant=\"info\">\n\nStorybook provides a codemod to help you upgrade from CSF 2 to CSF 3. You can run it with the following command:\n\n<CodeSnippets path=\"migrate-csf-2-to-3.md\" />\n\n</Callout>\n\nIn CSF 2, the named exports are always functions that instantiate a component, and those functions can be annotated with configuration options. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"csf-2-example-starter.md\" />\n\n{/* prettier-ignore-end */}\n\nThis declares a Primary story for a Button that renders itself by spreading `{ primary: true }` into the component. The `default.title` metadata says where to place the story in a navigation hierarchy.\n\nHere's the CSF 3 equivalent:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"csf-3-example-starter.md\" />\n\n{/* prettier-ignore-end */}\n\nLet's go through the changes individually to understand what's going on.\n\n### Spreadable story objects\n\nIn CSF 3, the named exports are **objects**, not functions. This allows us to reuse stories more efficiently with the JS spread operator.\n\nConsider the following addition to the intro example, which creates a `PrimaryOnDark` story that renders against a dark background:\n\nHere's the CSF 2 implementation:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"csf-2-example-primary-dark-story.md\" />\n\n{/* prettier-ignore-end */}\n\n`Primary.bind({})` copies the story function, but it doesn't copy the annotations hanging off the function, so we must add `PrimaryOnDark.args = Primary.args` to inherit the args.\n\nIn CSF 3, we can spread the `Primary` object to carry over all its annotations:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"csf-3-example-primary-dark-story.md\" />\n\nLearn more about [named story exports](#named-story-exports).\n\n{/* prettier-ignore-end */}\n\n### Default render functions\n\nIn CSF 3, you specify how a story renders through a `render` function. We can rewrite a CSF 2 example to CSF 3 through the following steps.\n\nLet's start with a simple CSF 2 story function:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"csf-2-example-story.md\" />\n\n{/* prettier-ignore-end */}\n\nNow, let's rewrite it as a story object in CSF 3 with an explicit `render` function that tells the story how to render itself. Like CSF 2, this gives us full control of how we render a component or even a collection of components.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"csf-3-example-render.md\" />\n\n<IfRenderer renderer={[ 'angular', 'ember', 'html', 'preact', 'qwik', 'react', 'solid', 'vue', 'web-components' ]}>\n  Learn more about [render functions](#custom-render-functions).\n</IfRenderer>\n\n{/* prettier-ignore-end */}\n\nBut in CSF 2, a lot of story functions are identical: take the component specified in the default export and spread args into it. What's interesting about these stories is not the function, but the args passed into the function.\n\nCSF 3 provides default render functions for each renderer. If all you're doing is spreading args into your component—which is the most common case—you don't need to specify any `render` function at all:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"csf-3-example-default-render.md\" />\n\n{/* prettier-ignore-end */}\n\n<IfRenderer renderer={[ 'angular', 'ember', 'html', 'preact', 'qwik', 'react', 'solid', 'vue', 'web-components' ]}>\n  For more information, see the section on [custom render functions](#custom-render-functions).\n</IfRenderer>\n\n### Generate titles automatically\n\nFinally, CSF 3 can automatically generate titles.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"csf-2-example-title.md\" />\n\n{/* prettier-ignore-end */}\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"csf-3-example-auto-title.md\" />\n\n{/* prettier-ignore-end */}\n\nYou can still specify a title like in CSF 2, but if you don't specify one, it can be inferred from the story's path on disk. For more information, see the section on [configuring story loading](../../configure/index.mdx#configure-story-loading).\n"
  },
  {
    "path": "docs/api/doc-blocks/doc-block-argtypes.mdx",
    "content": "---\ntitle: 'ArgTypes'\nsidebar:\n  order: 1\n  title: ArgTypes\n---\n\nThe `ArgTypes` block can be used to show a static table of [arg types](../arg-types.mdx) for a given component, as a way to document its interface.\n\n<Callout variant=\"info\" icon=\"💡\">\n  If you’re looking for a dynamic table that shows a story’s current arg values for a story and supports users changing them, see the [`Controls`](./doc-block-controls.mdx) block instead.\n</Callout>\n\n![Screenshot of ArgTypes block](../../_assets/api/doc-block-argtypes.png)\n\n{/* prettier-ignore-start */}\n\n```md title=\"ButtonDocs.mdx\"\nimport { Meta, ArgTypes } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from './Button.stories';\n\n<Meta of={ButtonStories} />\n\n<ArgTypes of={ButtonStories} />\n```\n\n{/* prettier-ignore-end */}\n\n## ArgTypes\n\n```js\nimport { ArgTypes } from '@storybook/addon-docs/blocks';\n```\n\n<details>\n  <summary>Configuring with props <strong>and</strong> parameters</summary>\n\n  ℹ️ Like most blocks, the `ArgTypes` block is configured with props in MDX. Many of those props derive their default value from a corresponding [parameter](../../writing-stories/parameters.mdx) in the block's namespace, `parameters.docs.argTypes`.\n\n  The following `exclude` configurations are equivalent:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"api-doc-block-argtypes-parameter.md\" />\n\n  {/* prettier-ignore-end */}\n\n  {/* prettier-ignore-start */}\n\n  ```md title=\"ButtonDocs.mdx\"\n  <ArgTypes of={ButtonStories} exclude={['style']} />\n  ```\n\n  {/* prettier-ignore-end */}\n\n  The example above applied the parameter at the [component](../../writing-stories/parameters.mdx#component-parameters) (or meta) level, but it could also be applied at the [project](../../writing-stories/parameters.mdx#global-parameters) or [story](../../writing-stories/parameters.mdx#story-parameters) level.\n</details>\n\n### `exclude`\n\nType: `string[] | RegExp`\n\nDefault: `parameters.docs.argTypes.exclude`\n\nSpecifies which arg types to exclude from the args table. Any arg types whose names match the regex or are part of the array will be left out.\n\n### `include`\n\nType: `string[] | RegExp`\n\nDefault: `parameters.docs.argTypes.include`\n\nSpecifies which arg types to include in the args table. Any arg types whose names don’t match the regex or are not part of the array will be left out.\n\n### `of`\n\nType: Story export or CSF file exports\n\nSpecifies which story to get the arg types from. If a CSF file exports is provided, it will use the primary (first) story in the file.\n\n### `sort`\n\nType: `'none' | 'alpha' | 'requiredFirst'`\n\nDefault: `parameters.docs.argTypes.sort` or `'none'`\n\nSpecifies how the arg types are sorted.\n\n* **none**: Unsorted, displayed in the same order the arg types are processed in\n* **alpha**: Sorted alphabetically, by the arg type's name\n* **requiredFirst**: Same as `alpha`, with any required arg types displayed first\n"
  },
  {
    "path": "docs/api/doc-blocks/doc-block-canvas.mdx",
    "content": "---\ntitle: 'Canvas'\nsidebar:\n  order: 2\n  title: Canvas\n---\n\nThe `Canvas` block is a wrapper around a [`Story`](./doc-block-story.mdx), featuring a toolbar that allows you to interact with its content while automatically providing the required [`Source`](./doc-block-source.mdx) snippets.\n\n![Screenshot of Canvas block](../../_assets/api/doc-block-canvas.png)\n\nWhen using the Canvas block in MDX, it references a story with the `of` prop:\n\n{/* prettier-ignore-start */}\n\n```md title=\"ButtonDocs.mdx\"\nimport { Meta, Canvas } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from './Button.stories';\n\n<Meta of={ButtonStories} />\n\n<Canvas of={ButtonStories.Primary} />\n```\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  In previous versions of Storybook it was possible to pass in arbitrary components as children to `Canvas`. That is deprecated and the `Canvas` block now only supports a single story.\n</Callout>\n\n## Canvas\n\n```js\nimport { Canvas } from '@storybook/addon-docs/blocks';\n```\n\n<details>\n  <summary>Configuring with props <strong>and</strong> parameters</summary>\n\n  ℹ️ Like most blocks, the `Canvas` block is configured with props in MDX. Many of those props derive their default value from a corresponding [parameter](../../writing-stories/parameters.mdx) in the block's namespace, `parameters.docs.canvas`.\n\n  The following `sourceState` configurations are equivalent:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"api-doc-block-canvas-parameter.md\" />\n\n  {/* prettier-ignore-end */}\n\n  {/* prettier-ignore-start */}\n\n  ```md title=\"ButtonDocs.mdx\"\n  <Canvas of={ButtonStories.Basic} sourceState=\"shown\" />\n  ```\n\n  {/* prettier-ignore-end */}\n\n  The example above applied the parameter at the [story](../../writing-stories/parameters.mdx#story-parameters) level, but it could also be applied at the [component](../../writing-stories/parameters.mdx#component-parameters) (or meta) level or [project](../../writing-stories/parameters.mdx#global-parameters) level.\n</details>\n\n### `additionalActions`\n\nType:\n\n{/* prettier-ignore-start */}\n\n```ts\nArray<{\n  title: string | JSX.Element;\n  className?: string;\n  onClick: () => void;\n  disabled?: boolean;\n}>;\n```\n\n{/* prettier-ignore-end */}\n\nDefault: `parameters.docs.canvas.additionalActions`\n\nProvides any additional custom actions to show in the bottom right corner. These are simple buttons that do anything you specify in the `onClick` function.\n\n{/* prettier-ignore-start */}\n\n```md title=\"ButtonDocs.mdx\"\nimport { Meta, Story, Canvas, SourceState } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from './Button.stories';\n\n<Meta of={ButtonStories} />\n\n{/* With an additional action */}\n<Canvas\n  additionalActions={[\n    {\n      title: 'Open in GitHub',\n      onClick: () => {\n        window.open(\n          'https://github.com/storybookjs/storybook/blob/next/code/ui/blocks/src/examples/Button.stories.tsx',\n          '_blank'\n        );\n      },\n    }\n  ]}\n  of={ButtonStories.Primary}\n/>\n```\n\n{/* prettier-ignore-end */}\n\n### `className`\n\nType: `string`\n\nDefault: `parameters.docs.canvas.className`\n\nProvides HTML class(es) to the preview element, for custom styling.\n\n### `layout`\n\nType: `'centered' | 'fullscreen' | 'padded'`\n\nDefault: `parameters.layout` or `parameters.docs.canvas.layout` or `'padded'`\n\nSpecifies how the canvas should layout the story.\n\n* **centered**: Center the story within the canvas\n* **padded**: (default) Add padding to the story\n* **fullscreen**: Show the story as-is, without padding\n\nIn addition to the `parameters.docs.canvas.layout` property or the `layout` prop, the `Canvas` block will respect the `parameters.layout` value that defines [how a story is laid out](../../configure/story-layout.mdx) in the regular story view.\n\n### `meta`\n\nType: CSF file exports\n\nSpecifies the CSF file to which the story is associated.\n\nYou can render a story from a CSF file that you haven’t attached to the MDX file (via `Meta`) by using the `meta` prop. Pass the **full set of exports** from the CSF file (not the default export!).\n\n{/* prettier-ignore-start */}\n\n```md title=\"ButtonDocs.mdx\"\nimport { Meta, Canvas } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from './Button.stories';\nimport * as HeaderStories from './Header.stories';\n\n<Meta of={ButtonStories} />\n\n{/* Although this MDX file is largely concerned with Button,\n    it can render Header stories too */}\n<Canvas of={HeaderStories.LoggedIn} meta={HeaderStories} />\n```\n\n{/* prettier-ignore-end */}\n\n### `of`\n\nType: Story export\n\nSpecifies which story's source is displayed.\n\n### `source`\n\nType: `SourceProps['code'] | SourceProps['format'] | SourceProps['language'] | SourceProps['type']`\n\nSpecifies the props passed to the inner `Source` block. For more information, see the `Source` Doc Block [documentation](./doc-block-source.mdx).\n\n<Callout variant=\"info\" icon=\"💡\">\n  The dark prop is ignored, as the `Source` block is always rendered in dark mode when shown as part of a `Canvas` block.\n</Callout>\n\n### `sourceState`\n\nType: `'hidden' | 'shown' | 'none'`\n\nDefault: `parameters.docs.canvas.sourceState` or `'hidden'`\n\nSpecifies the initial state of the source panel.\n\n* **hidden**: the source panel is hidden by default\n* **shown**: the source panel is shown by default\n* **none**: the source panel is not available and the button to show it is not rendered\n\n### `story`\n\nType: `StoryProps['inline'] | StoryProps['height'] | StoryProps['autoplay']`\n\nSpecifies the props passed to the inner `Story` block. For more information, see the `Story` Doc Block [documentation](./doc-block-story.mdx).\n\n### `withToolbar`\n\nType: `boolean`\n\nDefault: `parameters.docs.canvas.withToolbar`\n\nDetermines whether to render a toolbar containing tools to interact with the story.\n"
  },
  {
    "path": "docs/api/doc-blocks/doc-block-colorpalette.mdx",
    "content": "---\ntitle: 'ColorPalette'\nsidebar:\n  order: 3\n  title: ColorPalette\n---\n\nThe `ColorPalette` block allows you to document all color-related items (e.g., swatches) used throughout your project.\n\n![Screenshot of ColorPalette and ColorItem blocks](../../_assets/api/doc-block-colorpalette.png)\n\n{/* prettier-ignore-start */}\n\n```md title=\"Colors.mdx\"\nimport { Meta, ColorPalette, ColorItem } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Colors\" />\n\n<ColorPalette>\n  <ColorItem\n    title=\"theme.color.greyscale\"\n    subtitle=\"Some of the greys\"\n    colors={{ White: '#FFFFFF', Alabaster: '#F8F8F8', Concrete: '#F3F3F3' }}\n  />\n  <ColorItem \n    title=\"theme.color.primary\" \n    subtitle=\"Coral\" \n    colors={{ WildWatermelon: '#FF4785' }} \n  />\n  <ColorItem \n    title=\"theme.color.secondary\" \n    subtitle=\"Ocean\" \n    colors={{ DodgerBlue: '#1EA7FD' }} \n  />\n  <ColorItem\n    title=\"theme.color.positive\"\n    subtitle=\"Green\"\n    colors={{\n      Apple: 'rgba(102,191,60,1)',\n      Apple80: 'rgba(102,191,60,.8)',\n      Apple60: 'rgba(102,191,60,.6)',\n      Apple30: 'rgba(102,191,60,.3)',\n    }}\n  />\n  <ColorItem\n    title=\"gradient\"\n    subtitle=\"Grayscale\"\n    colors={{\n      Gradient: 'linear-gradient(to right,white,black)',\n    }}\n  />\n  <ColorItem\n    title=\"gradient\"\n    subtitle=\"Grayscale\"\n    colors={['linear-gradient(65deg,white,black)']}\n  />\n</ColorPalette>\n```\n\n{/* prettier-ignore-end */}\n\n## ColorPalette\n\n```js\nimport { ColorPalette } from '@storybook/addon-docs/blocks';\n```\n\n`ColorPalette` is configured with the following props:\n\n### `children`\n\nType: `React.ReactNode`\n\n`ColorPalette` expects only `ColorItem` children.\n\n## ColorItem\n\n```js\nimport { ColorItem } from '@storybook/addon-docs/blocks';\n```\n\n`ColorItem` is configured with the following props:\n\n### `colors`\n\n(**Required**)\n\nType: `string[] | { [key: string]: string }`\n\nProvides the list of colors to be displayed. Accepts any valid CSS color format (hex, RGB, HSL, etc.). When an object is provided, the keys will be displayed above the values. Additionally, it supports gradients such as 'linear-gradient(to right, white, black)' or 'linear-gradient(65deg, white, black)', etc. \n\n### `subtitle`\n\n(**Required**)\n\nType: `string`\n\nProvides an additional description of the color.\n\n### `title`\n\n(**Required**)\n\nType: `string`\n\nSets the name of the color to be displayed.\n"
  },
  {
    "path": "docs/api/doc-blocks/doc-block-controls.mdx",
    "content": "---\ntitle: 'Controls'\nsidebar:\n  order: 4\n  title: Controls\n---\n\nThe `Controls` block can be used to show a dynamic table of args for a given story, as a way to document its interface, and to allow you to change the args for a (separately) rendered story (via the [`Story`](./doc-block-story.mdx) or [`Canvas`](./doc-block-canvas.mdx) blocks).\n\n<Callout variant=\"info\" icon=\"💡\">\n  If you’re looking for a static table that shows a component's arg types with no controls, see the [`ArgTypes`](./doc-block-argtypes.mdx) block instead.\n</Callout>\n\n![Screenshot of Controls block](../../_assets/api/doc-block-controls.png)\n\n{/* prettier-ignore-start */}\n\n```md title=\"ButtonDocs.mdx\"\nimport { Meta, Canvas, Controls } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from './Button.stories'\n\n<Meta of={ButtonStories} />\n\n<Canvas of={ButtonStories.Primary} />\n\n<Controls of={ButtonStories.Primary} />\n```\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"warning\">\n\n  The Controls doc block will only have functioning UI controls if you haven't turned off inline stories with the [`inline`](./doc-block-story.mdx#inline) configuration option.\n\n</Callout>\n\n## Controls\n\n```js\nimport { Controls } from '@storybook/addon-docs/blocks';\n```\n\n<details>\n  <summary>Configuring with props <strong>and</strong> parameters</summary>\n\n  ℹ️ Like most blocks, the `Controls` block is configured with props in MDX. Many of those props derive their default value from a corresponding [parameter](../../writing-stories/parameters.mdx) in the block's namespace, `parameters.docs.controls`.\n\n  The following `exclude` configurations are equivalent:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"api-doc-block-controls-parameter.md\" />\n\n  {/* prettier-ignore-end */}\n\n  {/* prettier-ignore-start */}\n\n  ```md title=\"ButtonDocs.mdx\"\n  <Controls of={ButtonStories} exclude={['style']} />\n  ```\n\n  {/* prettier-ignore-end */}\n\n  The example above applied the parameter at the [component](../../writing-stories/parameters.mdx#component-parameters) (or meta) level, but it could also be applied at the [project](../../writing-stories/parameters.mdx#global-parameters) or [story](../../writing-stories/parameters.mdx#story-parameters) level.\n</details>\n\n<Callout variant=\"info\" icon=\"💡\">\n\n This API configures the `Controls` blocks used within docs pages. To configure the Controls panel, see the [feature documentation](../../essentials/controls.mdx). To configure individual controls, specify [argTypes](../arg-types.mdx#control) for each.\n\n</Callout>\n\n### `exclude`\n\nType: `string[] | RegExp`\n\nDefault: `parameters.docs.controls.exclude`\n\nSpecifies which controls to exclude from the args table. Any controls whose names match the regex or are part of the array will be left out.\n\n### `include`\n\nType: `string[] | RegExp`\n\nDefault: `parameters.docs.controls.include`\n\nSpecifies which controls to include in the args table. Any controls whose names don't match the regex or are not part of the array will be left out.\n\n### `of`\n\nType: Story export or CSF file exports\n\nSpecifies which story to get the controls from. If a CSF file exports is provided, it will use the primary (first) story in the file.\n\n### `sort`\n\nType: `'none' | 'alpha' | 'requiredFirst'`\n\nDefault: `parameters.docs.controls.sort` or `'none'`\n\nSpecifies how the controls are sorted.\n\n* **none**: Unsorted, displayed in the same order the controls are processed in\n* **alpha**: Sorted alphabetically, by the arg type's name\n* **requiredFirst**: Same as `alpha`, with any required controls displayed first\n"
  },
  {
    "path": "docs/api/doc-blocks/doc-block-description.mdx",
    "content": "---\ntitle: 'Description'\nsidebar:\n  order: 5\n  title: Description\n---\n\nThe `Description` block displays the description for a component, story, or meta, obtained from their respective JSDoc comments.\n\n![Screenshot of Description block](../../_assets/api/doc-block-title-subtitle-description.png)\n\n{/* prettier-ignore-start */}\n\n```md title=\"ButtonDocs.mdx\"\nimport { Meta, Description } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from './Button.stories';\n\n<Meta of={ButtonStories} />\n\n<Description of={ButtonStories.Primary} />\n```\n\n{/* prettier-ignore-end */}\n\n## Description\n\n```js\nimport { Description } from '@storybook/addon-docs/blocks';\n```\n\n`Description` is configured with the following props:\n\n### `of`\n\nType: Story export or CSF file exports\n\nSpecifies where to pull the description from. It can either point to a story or a meta, depending on which description you want to show.\n\nDescriptions are pulled from the JSDoc comments or parameters, and they are rendered as markdown. See [Writing descriptions](#writing-descriptions) for more details.\n\n## Writing descriptions\n\nThere are multiple places to write the description of a component/story, depending on what you want to achieve. Descriptions can be written at the story level to describe each story of a component, or they can be written at the meta or component level to describe the component in general.\n\nDescriptions can be written as [JSDoc comments](https://jsdoc.app/about-getting-started.html) above stories, meta, or components. Alternatively they can also be specified in [`parameters`](../../writing-stories/parameters.mdx). To describe a story via parameters instead of comments, add it to `parameters.docs.description.story`; to describe meta/component, add it to `parameters.docs.description.component`.\n\nWe recommend using JSDoc comments for descriptions, and only use the `parameters.docs.description.X` properties in situations where comments are not possible to write for some reason, or where you want the description shown in Storybook to be different from the comments. Comments provide a better writing experience as you don’t have to worry about indentation, and they are more discoverable for other developers that are exploring the story/component sources.\n\nWhen documenting a story, reference a story export in the `of` prop (see below) and the Description block will look for descriptions in the following order:\n\n1. `parameters.docs.description.story` in the story\n2. JSDoc comments above the story\n\nWhen documenting a component, reference a meta export in the `of` prop (see below) and the Description block will look for descriptions in the following order:\n\n1. `parameters.docs.description.component` in the meta\n2. JSDoc comments above the meta\n3. JSDoc comments above the component\n\nThis flow gives you powerful ways to override the description for each scenario. Take the following example:\n\n```jsx title=\"Button.jsx\"\n/**\n * The Button component shows a button\n */\nexport const Button = () => <button>Click me</button>;\n```\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"api-doc-block-description-example.md\" />\n\n{/* prettier-ignore-end */}\n\n{/* prettier-ignore-start */}\n\n```md title=\"ButtonDocs.mdx\"\nimport { Meta, Description } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from './Button.stories';\n\n<Meta of={ButtonStories} />\n\n{/* Shows the description for the default export (the meta).\n    If that didn't have any comments, it would show the \n    comments from the component instead */}\n<Description of={ButtonStories} />\n\n{/* Shows the description for the Primary export */}\n<Description of={ButtonStories.Primary} />\n```\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/api/doc-blocks/doc-block-icongallery.mdx",
    "content": "---\ntitle: 'IconGallery'\nsidebar:\n  order: 6\n  title: IconGallery\n---\n\nThe `IconGallery` block enables you to easily document React icon components associated with your project, displayed in a neat grid.\n\n![Screenshot of IconGallery and IconItem blocks](../../_assets/api/doc-block-icongallery.png)\n\n## Documenting icons\n\nTo document a set of icons, use the `IconGallery` block to display them in a grid. Each icon is wrapped in an `IconItem` block, enabling you to specify its properties, such as the name and the icon itself.\n\n{/* prettier-ignore-start */}\n\n```md title=\"Iconography.mdx\"\nimport { Meta, IconGallery, IconItem } from '@storybook/addon-docs/blocks';\n\nimport { Icon as IconExample } from './Icon';\n\n<Meta title=\"Iconography\" />\n\n# Iconography\n\n<IconGallery>\n  <IconItem name=\"mobile\">\n    <IconExample name=\"mobile\" />\n  </IconItem>\n  <IconItem name=\"user\">\n    <IconExample name=\"user\" />\n  </IconItem>\n  <IconItem name=\"browser\">\n    <IconExample name=\"browser\" />\n  </IconItem>\n  <IconItem name=\"component\">\n    <IconExample name=\"component\" />\n  </IconItem>\n  <IconItem name=\"calendar\">\n    <IconExample name=\"calendar\" />\n  </IconItem>\n   <IconItem name=\"paintbrush\">\n    <IconExample name=\"paintbrush\" />\n  </IconItem>\n   <IconItem name=\"add\">\n    <IconExample name=\"add\" />\n  </IconItem>\n  <IconItem name=\"subtract\">\n    <IconExample name=\"subtract\" />\n  </IconItem>\n   <IconItem name=\"document\">\n    <IconExample name=\"document\" />\n  </IconItem>\n  <IconItem name=\"graphline\">\n    <IconExample name=\"graphline\" />\n  </IconItem>\n</IconGallery>\n```\n\n{/* prettier-ignore-end */}\n\n### Automate icon documentation\n\nIf you're working on a project that contains a large number of icons that you want to document, you can extend the `IconGallery` block, wrap `IconItem` in a loop, and iterate over the icons you want to document, including their properties. For example:\n\n{/* prettier-ignore-start */}\n\n```md title=\"Iconography.mdx\"\nimport { Meta, IconGallery, IconItem } from '@storybook/addon-docs/blocks';\n\nimport { Icon as IconExample } from './Icon';\nimport * as icons from './icons';\n\n# Iconography\n\n<IconGallery>\n  {Object.keys(icons).map((icon) => (\n    <IconItem name={icon}>\n      <IconExample icon={icon} />\n    </IconItem>\n  ))}\n</IconGallery>\n```\n\n{/* prettier-ignore-end */}\n\n## IconGallery\n\n```js\nimport { IconGallery } from '@storybook/addon-docs/blocks';\n```\n\n`IconGallery` is configured with the following props:\n\n### `children`\n\nType: `React.ReactNode`\n\n`IconGallery` expects only `IconItem` children.\n\n## IconItem\n\n```js\nimport { IconItem } from '@storybook/addon-docs/blocks';\n```\n\n`IconItem` is configured with the following props:\n\n### `name`\n\n(**Required**)\n\nType: `string`\n\nSets the name of the icon.\n\n### `children`\n\nType: `React.ReactNode`\n\nProvides the icon to be displayed.\n"
  },
  {
    "path": "docs/api/doc-blocks/doc-block-markdown.mdx",
    "content": "---\ntitle: 'Markdown'\nsidebar:\n  order: 7\n  title: Markdown\n---\n\nThe `Markdown` block allows you to import and include plain markdown in your MDX files.\n\n![Screenshot of Markdown block](../../_assets/api/doc-block-markdown.png)\n\nWhen importing markdown files, it’s important to use the `?raw` suffix on the import path to ensure the content is imported as-is, and isn’t being evaluated:\n\n{/* prettier-ignore-start */}\n\n````md title=\"README.md\"\n# Button\n\nPrimary UI component for user interaction\n\n```js\nimport { Button } from \"@storybook/design-system\";\n```\n````\n\n{/* prettier-ignore-end */}\n\n{/* prettier-ignore-start */}\n\n```md title=\"Header.mdx\"\n// DON'T do this, will error\nimport ReadMe from './README.md';\n// DO this, will work\nimport ReadMe from './README.md?raw';\n\nimport { Markdown } from '@storybook/addon-docs/blocks';\n\n# A header \n\n<Markdown>{ReadMe}</Markdown>\n```\n\n{/* prettier-ignore-end */}\n\n## Markdown\n\n```js\nimport { Markdown } from '@storybook/addon-docs/blocks';\n```\n\n`Markdown` is configured with the following props:\n\n### `children`\n\nType: `string`\n\nProvides the markdown-formatted string to parse and display.\n\n### `options`\n\nSpecifies the options passed to the underlying [`markdown-to-jsx` library](https://github.com/probablyup/markdown-to-jsx/blob/main/README.md).\n\n## Why not import markdown directly?\n\nFrom a purely technical standpoint, we could include the imported markdown directly in the MDX file like this:\n\n{/* prettier-ignore-start */}\n\n```md\n{/* THIS WON'T WORK, THIS IS TO DEMONSTRATE AN ERROR */}\n\nimport ReadMe from './README.md';\n\n# A header \n\n{ReadMe}\n```\n\n{/* prettier-ignore-end */}\n\nHowever, there are small syntactical differences between plain markdown and MDX2. MDX2 is more strict and will interpret certain content as JSX expressions. Here’s an example of a perfectly valid markdown file, that would break if it was handled directly by MDX2:\n\n{/* prettier-ignore-start */}\n\n```md\n# A header\n\n{ this is valid in a plain markdown file, but MDX2 will try to evaluate this as an expression }\n\n<This is also valid, but MDX2 thinks this is a JSX component />\n```\n\n{/* prettier-ignore-end */}\n\nFurthermore, MDX2 wraps all strings on newlines in `p` tags or similar, meaning that content would render differently between a plain `.md` file and an `.mdx` file.\n\n{/* prettier-ignore-start */}\n\n```md\n# A header\n\n<div>\n  Some text\n</div>\n\nThe example above will remain as-is in plain markdown, but MDX2 will compile it to:\n\n# A header\n\n<div>\n  <p>Some text</p>\n</div>\n```\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/api/doc-blocks/doc-block-meta.mdx",
    "content": "---\ntitle: 'Meta'\nsidebar:\n  order: 8\n  title: Meta\n---\n\nThe `Meta` block is used to [attach](#attached-vs-unattached) a custom MDX docs page alongside a component’s list of stories. It doesn’t render any content, but serves two purposes in an MDX file:\n\n* Attaches the MDX file to a component and its stories, or\n* Controls the location of the unattached docs entry in the sidebar.\n\n{/* prettier-ignore-start */}\n\n```md title=\"ButtonDocs.mdx\"\nimport { Meta } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from './Button.stories';\n\n<Meta of={ButtonStories} />\n```\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  The Meta block doesn’t render anything visible.\n</Callout>\n\n## Meta\n\n```js\nimport { Meta } from '@storybook/addon-docs/blocks';\n```\n\n`Meta` is configured with the following props:\n\n### `isTemplate`\n\nType: `boolean`\n\nDetermines whether the MDX file serves as an [automatic docs template](../../writing-docs/autodocs.mdx#with-mdx). When true, the MDX file is not indexed as it normally would be.\n\n### `name`\n\nType: `string`\n\nSets the name of the [attached](#attached-vs-unattached) doc entry. You can attach more than one MDX file to the same component in the sidebar by setting different names for each file's `Meta`.\n\n{/* prettier-ignore-start */}\n\n```md title=\"Component.mdx\"\nimport { Meta } from '@storybook/addon-docs/blocks';\nimport * as ComponentStories from './component.stories';\n\n{/* This MDX file is now called \"Special Docs\" */}\n<Meta of={ComponentStories} name=\"Special Docs\" />\n```\n\n{/* prettier-ignore-end */}\n\n### `of`\n\nType: CSF file exports\n\nSpecifies which CSF file is [attached](#attached-vs-unattached) to this MDX file. Pass the **full set of exports** from the CSF file (not the default export!).\n\n{/* prettier-ignore-start */}\n\n```md title=\"ButtonDocs.mdx\"\nimport { Meta, Story } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from './Button.stories';\n\n<Meta of={ButtonStories} />\n```\n\n{/* prettier-ignore-end */}\n\nAttaching an MDX file to a component’s stories with the `of` prop serves two purposes:\n\n1. Ensures the MDX content appears in the sidebar inside the component’s story list. By default, it will be named whatever the `docs.defaultName` (which defaults to `\"Docs\"`) option is set to in `main.js`. But this can be overridden with the [`name` prop](#name).\n2. Attaches the component and its stories to the MDX file, allowing you to use other doc blocks in “attached” mode (for instance to use the `Stories` block).\n\n<Callout variant=\"info\" icon=\"💡\">\n\n  The `of` prop is optional. If you don’t want to attach a specific CSF file to this MDX file, you can either use the `title` prop to control the location, or emit `Meta` entirely, and let [autotitle](../../configure/user-interface/sidebar-and-urls.mdx#csf-30-auto-titles) decide where it goes.\n\n</Callout>\n\n### `title`\n\nType: `string`\n\nSets the title of an [unattached](#attached-vs-unattached) MDX file.\n\n{/* prettier-ignore-start */}\n\n```md\n{/* Introduction.mdx */}\n\nimport { Meta } from '@storybook/addon-docs/blocks';\n\n{/* Override the docs entry's location in the sidebar with title */}\n<Meta title=\"path/to/Introduction\" />\n```\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n\n  If you want to change the sorting of the docs entry with the component’s stories, use [Story Sorting](../../writing-stories/naming-components-and-hierarchy.mdx#sorting-stories), or add specific MDX files to your `stories` field in `main.js` in order.\n  \n</Callout>\n\n## Attached vs. unattached\n\nIn Storybook, a docs entry (MDX file) is \"attached\" when it is associated with a stories file, via `Meta`'s [`of` prop](#of). Attached docs entries display next to the stories list under the component in the sidebar.\n\n\"Unattached\" docs entries are not associated with a stories file and can be displayed anywhere in the sidebar via `Meta`'s [`title` prop](#title).\n"
  },
  {
    "path": "docs/api/doc-blocks/doc-block-primary.mdx",
    "content": "---\ntitle: 'Primary'\nsidebar:\n  order: 9\n  title: Primary\n---\n\nThe `Primary` block displays the primary (first defined in the stories file) story, in a [`Story`](./doc-block-story.mdx) block. It is typically rendered immediately under the title in a docs entry.\n\n![Screenshot of Primary block](../../_assets/api/doc-block-primary.png)\n\n{/* prettier-ignore-start */}\n\n```md title=\"ButtonDocs.mdx\"\nimport { Meta, Primary } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from './Button.stories';\n\n<Meta of={ButtonStories} />\n\n<Primary />\n```\n\n{/* prettier-ignore-end */}\n\n## Primary\n\n```js\nimport { Primary } from '@storybook/addon-docs/blocks';\n```\n\n`Primary` is configured with the following props:\n\n### `of`\n\nType: CSF file exports\n\nSpecifies which CSF file is used to find the first story, which is then rendered by this block. Pass the full set of exports from the CSF file (not the default export!).\n"
  },
  {
    "path": "docs/api/doc-blocks/doc-block-source.mdx",
    "content": "---\ntitle: 'Source'\nsidebar:\n  order: 10\n  title: Source\n---\n\nThe `Source` block is used to render a snippet of source code directly.\n\n![Screenshot of Source block](../../_assets/api/doc-block-source.png)\n\n{/* prettier-ignore-start */}\n\n```md title=\"ButtonDocs.mdx\"\nimport { Meta, Source } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from './Button.stories';\n\n<Meta of={ButtonStories} />\n\n<Source of={ButtonStories.Primary} />\n```\n\n{/* prettier-ignore-end */}\n\n## Source\n\n```js\nimport { Source } from '@storybook/addon-docs/blocks';\n```\n\n<details>\n  <summary>Configuring with props <strong>and</strong> parameters</summary>\n\n  ℹ️ Like most blocks, the `Source` block is configured with props in MDX. Many of those props derive their default value from a corresponding [parameter](../../writing-stories/parameters.mdx) in the block's namespace, `parameters.docs.source`.\n\n  The following `language` configurations are equivalent:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"api-doc-block-source-parameter.md\" />\n\n  {/* prettier-ignore-end */}\n\n  {/* prettier-ignore-start */}\n\n  ```md title=\"ButtonDocs.mdx\"\n  <Source of={ButtonStories.Basic} language=\"tsx\" />\n  ```\n\n  {/* prettier-ignore-end */}\n\n  The example above applied the parameter at the [story](../../writing-stories/parameters.mdx#story-parameters) level, but it could also be applied at the [component](../../writing-stories/parameters.mdx#component-parameters) (or meta) level or [project](../../writing-stories/parameters.mdx#global-parameters) level.\n</details>\n\n### `code`\n\nType: `string`\n\nDefault: `parameters.docs.source.code`\n\nProvides the source code to be rendered.\n\n{/* prettier-ignore-start */}\n\n```md title=\"ButtonDocs.mdx\"\nimport { Meta, Source } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from './Button.stories';\n\n<Meta of={ButtonStories} />\n\n<Source code={`const thisIsCustomSource = true;\nif (isSyntaxHighlighted) {\n  console.log('syntax highlighting is working');\n}`} />\n```\n\n{/* prettier-ignore-end */}\n\n### `dark`\n\nType: `boolean`\n\nDefault: `parameters.docs.source.dark`\n\nDetermines if the snippet is rendered in dark mode.\n\n<Callout variant=\"info\" icon=\"💡\">\n\n  Light mode is only supported when the `Source` block is rendered independently. When rendered as part of a [`Canvas` block](./doc-block-canvas.mdx)—like it is in [autodocs](../../writing-docs/autodocs.mdx)—it will always use dark mode.\n\n</Callout>\n\n<IfRenderer renderer={['angular', 'react', 'html', 'web-components' ]}>\n  ### `excludeDecorators`\n\n  Type: `boolean`\n\n  Default: `parameters.docs.source.excludeDecorators`\n\n  Determines if [decorators](../../writing-stories/decorators.mdx) are rendered in the source code snippet.\n</IfRenderer>\n\n### `language`\n\nType:\n\n{/* prettier-ignore-start */}\n\n```ts\n'jsextra' | 'jsx' | 'json' | 'yml' | 'md' | 'bash' | 'css' | 'html' | 'tsx' | 'typescript' | 'graphql'\n```\n\n{/* prettier-ignore-end */}\n\nDefault: `parameters.docs.source.language` or `'jsx'`\n\nSpecifies the language used for syntax highlighting.\n\n### `of`\n\nType: Story export\n\nSpecifies which story's source is rendered.\n\n### `transform`\n\nType: `(code: string, storyContext: StoryContext) => string | Promise<string>`\n\nDefault: `parameters.docs.source.transform`\n\nAn async function to dynamically transform the source before being rendered, based on the original source and any story context necessary. The returned string is displayed as-is.\nIf both [`code`](#code) and `transform` are specified, `transform` will be ignored.\n\n<CodeSnippets path=\"parameters-docs-source-transform-in-preview.md\" />\n\nThis example shows how to use Prettier to format all source code snippets in your documentation. The transform function is applied globally through the preview configuration, ensuring consistent code formatting across all stories.\n\n### `type`\n\nType: `'auto' | 'code' | 'dynamic'`\n\nDefault: `parameters.docs.source.type` or `'auto'`\n\nSpecifies how the source code is rendered.\n\n* **auto**: Same as **dynamic**, if the story's `render` function accepts args inputs and **dynamic** is supported by the framework in use; otherwise same as **code**\n* **code**: Renders the value of [`code` prop](#code), otherwise renders static story source\n* **dynamic**: Renders the story source with dynamically updated arg values\n\n<Callout variant=\"info\" icon=\"💡\">\n\n  Note that dynamic snippets will only work if the story uses [`args`](../../writing-stories/args.mdx) and the [`Story` block](./doc-block-story.mdx) for that story is rendered along with the `Source` block.\n  \n</Callout>\n"
  },
  {
    "path": "docs/api/doc-blocks/doc-block-stories.mdx",
    "content": "---\ntitle: 'Stories'\nsidebar:\n  order: 11\n  title: Stories\n---\n\nThe `Stories` block renders the full collection of stories in a stories file.\n\n![Screenshot of Stories block](../../_assets/api/doc-block-stories.png)\n\n{/* prettier-ignore-start */}\n\n```md title=\"ButtonDocs.mdx\"\nimport { Meta, Stories } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from './Button.stories';\n\n<Meta of={ButtonStories} />\n\n<Stories />\n```\n\n{/* prettier-ignore-end */}\n\n## Stories\n\n```js\nimport { Stories } from '@storybook/addon-docs/blocks';\n```\n\n`Stories` is configured with the following props:\n\n### `includePrimary`\n\nType: `boolean`\n\nDefault: `true`\n\nDetermines if the collection of stories includes the primary (first) story.\n\n<Callout variant=\"info\" icon=\"💡\">\n\n  If a stories file contains only one story and `includePrimary={true}`, the `Stories` block will render nothing to avoid a potentially confusing situation.\n  \n</Callout>\n\n### `title`\n\nType: `string`\n\nDefault: `'Stories'`\n\nSets the heading content preceding the collection of stories.\n"
  },
  {
    "path": "docs/api/doc-blocks/doc-block-story.mdx",
    "content": "---\ntitle: 'Story'\nsidebar:\n  order: 12\n  title: Story\n---\n\n[Stories](../../writing-stories/index.mdx) are Storybook's fundamental building blocks.\n\nIn Storybook Docs, you can render any of your stories from your CSF files in the context of an MDX file with all annotations (parameters, args, loaders, decorators, play function) applied using the `Story` block.\n\n<Callout variant=\"info\">\n\n  Typically you want to use the [`Canvas` block](./doc-block-canvas.mdx) to render a story with a surrounding border and the source block, but you can use the `Story` block to render just the story.\n  \n</Callout>\n\n![Screenshot of Story block](../../_assets/api/doc-block-story.png)\n\n{/* prettier-ignore-start */}\n\n```md title=\"ButtonDocs.mdx\"+\nimport { Meta, Story } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from './Button.stories';\n\n<Meta of={ButtonStories} />\n\n<Story of={ButtonStories.Primary} />\n```\n\n{/* prettier-ignore-end */}\n\n## Story\n\n```js\nimport { Story } from '@storybook/addon-docs/blocks';\n```\n\n<details>\n  <summary>Configuring with props <strong>and</strong> parameters</summary>\n\n  ℹ️ Like most blocks, the `Story` block is configured with props in MDX. Many of those props derive their default value from a corresponding [parameter](../../writing-stories/parameters.mdx) in the block's namespace, `parameters.docs.story`.\n\n  The following `autoplay` configurations are equivalent:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"api-doc-block-story-parameter.md\" />\n\n  {/* prettier-ignore-end */}\n\n  {/* prettier-ignore-start */}\n\n  ```md title=\"ButtonDocs.mdx\"\n  <Story of={ButtonStories.Basic} autoplay />\n  ```\n\n  {/* prettier-ignore-end */}\n\n  The example above applied the parameter at the [story](../../writing-stories/parameters.mdx#story-parameters) level, but it could also be applied at the [component](../../writing-stories/parameters.mdx#component-parameters) (or meta) level or [project](../../writing-stories/parameters.mdx#global-parameters) level.\n</details>\n\n### `autoplay`\n\nType: `boolean`\n\nDefault: `parameters.docs.story.autoplay`\n\nDetermines whether a story's play function runs.\n\nBecause all stories render simultaneously in docs entries, play functions can perform arbitrary actions that can interact with each other (such as stealing focus or scrolling the screen). For that reason, by default, stories **do not run play functions in docs mode**.\n\nHowever, if you know your play function is “safe” to run in docs, you can use this prop to run it automatically.\n\n<Callout variant=\"info\">\n  If a story uses [`mount` in its play function](../../writing-tests/interaction-testing.mdx#run-code-before-the-component-gets-rendered), it will not render in docs unless `autoplay` is set to `true`.\n</Callout>\n\n### `height`\n\nType: `string`\n\nDefault: `parameters.docs.story.height`\n\nSet a minimum height (note for an iframe this is the actual height) when rendering a story in an iframe or inline. This overrides `parameters.docs.story.iframeHeight` for iframes.\n\n### `inline`\n\nType: `boolean`\n\nDefault: `parameters.docs.story.inline` or `true` (for [supported frameworks](../../configure/integration/frameworks-feature-support.mdx))\n\nDetermines whether the story is rendered `inline` (in the same browser frame as the other docs content) or in an iframe.\n\n<Callout variant=\"info\">\n\n  Setting the `inline` option to false will prevent the associated [controls](./doc-block-controls.mdx) from updating the story within the documentation page. This is a known limitation of the current implementation and will be addressed in a future release.\n  \n</Callout>\n\n### `meta`\n\nType: CSF file exports\n\nSpecifies the CSF file to which the story is associated.\n\nYou can render a story from a CSF file that you haven’t attached to the MDX file (via `Meta`) by using the `meta` prop. Pass the **full set of exports** from the CSF file (not the default export!).\n\n{/* prettier-ignore-start */}\n\n```md title=\"ButtonDocs.mdx\"\nimport { Meta, Story } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from './Button.stories';\nimport * as HeaderStories from './Header.stories';\n\n<Meta of={ButtonStories} />\n\n{/* Although this MDX file is largely concerned with Button,\n    it can render Header stories too */}\n<Story of={HeaderStories.LoggedIn} meta={HeaderStories} />\n```\n\n{/* prettier-ignore-end */}\n\n### `of`\n\nType: Story export\n\nSpecifies which story is rendered by the `Story` block. If no `of` is defined and the MDX file is [attached](./doc-block-meta.mdx#attached-vs-unattached), the primary (first) story will be rendered.\n\n"
  },
  {
    "path": "docs/api/doc-blocks/doc-block-subtitle.mdx",
    "content": "---\ntitle: 'Subtitle'\nsidebar:\n  order: 13\n  title: Subtitle\n---\n\nThe `Subtitle` block can serve as a secondary heading for your docs entry.\n\n![Screenshot of Subtitle block](../../_assets/api/doc-block-title-subtitle-description.png)\n\n{/* prettier-ignore-start */}\n\n```md title=\"ButtonDocs.mdx\"\nimport { Subtitle } from '@storybook/addon-docs/blocks';\n\n<Subtitle>This is the subtitle</Subtitle>\n```\n\n{/* prettier-ignore-end */}\n\n## Subtitle\n\n```js\nimport { Subtitle } from '@storybook/addon-docs/blocks';\n```\n\n`Subtitle` is configured with the following props:\n\n### `children`\n\nType: `JSX.Element | string`\n\nDefault: `parameters.docs.subtitle`\n\nProvides the content.\n\n### `of`\n\nType: CSF file exports\n\nSpecifies which meta's subtitle is displayed.\n"
  },
  {
    "path": "docs/api/doc-blocks/doc-block-tableofcontents.mdx",
    "content": "---\ntitle: 'TableOfContents'\nsidebar:\n  order: 14\n  title: TableOfContents\n---\n\nThe `TableOfContents` block renders a table of contents for the current documentation page, allowing users to navigate between sections quickly. It appears as a fixed sidebar on the right side of the documentation page and is hidden on smaller screens (below 768px).\n\nThe table of contents is enabled and configured via the `docs.toc` [parameter](../../writing-stories/parameters.mdx) rather than being added directly to MDX files. When enabled, it is automatically rendered alongside the page content by [Storybook's docs container](../doc-blocks/doc-block-meta.mdx).\n\n<Callout variant=\"info\">\n\n  For a step-by-step guide on enabling and customizing the table of contents, see the [Generate a table of contents](../../writing-docs/autodocs.mdx#generate-a-table-of-contents) section in the Autodocs documentation.\n\n</Callout>\n\n## Enabling the table of contents\n\nEnable the table of contents globally in your Storybook preview configuration:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-enable-toc.md\" />\n\n{/* prettier-ignore-end */}\n\nYou can also enable or disable it for specific components in their stories file:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"my-component-disable-toc.md\" />\n\n{/* prettier-ignore-end */}\n\n## `toc` parameter options\n\nThe `docs.toc` parameter accepts either `true` (to enable with defaults) or an object with the following properties:\n\n### `contentsSelector`\n\nType: `string`\n\nDefault: `'.sbdocs-content'`\n\nCSS selector for the container to search for headings. Use this if you have a custom docs page layout.\n\n### `disable`\n\nType: `boolean`\n\nDefault: `false`\n\nWhen `true`, it hides the table of contents for the documentation page. A hidden (empty) container is still rendered to preserve the page layout.\n\n### `headingSelector`\n\nType: `string`\n\nDefault: `'h3'`\n\nCSS selector that defines which heading levels to include in the table of contents. For example, use `'h1, h2, h3'` to include the top three heading levels.\n\n### `ignoreSelector`\n\nType: `string`\n\nDefault: `'.docs-story *, .skip-toc'`\n\nCSS selector for headings to exclude from the table of contents. By default, headings inside story blocks are excluded. To also exclude a specific heading, add the `skip-toc` class to it.\n\n### `title`\n\nType: `string | null | ReactElement`\n\nDefault: `'Table of contents'` (visually hidden)\n\nText or element to display as the title above the table of contents. Set to `null` to render no title. When a string is provided, it is rendered as a visually hidden `<h2>` by default; pass a non-empty string to make it visible.\n\n### `unsafeTocbotOptions`\n\nType: `object`\n\nProvides additional configuration options passed directly to the underlying [`Tocbot`](https://tscanlin.github.io/tocbot/) library. These options are not guaranteed to remain available in future versions of Storybook.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-custom-toc.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/api/doc-blocks/doc-block-title.mdx",
    "content": "---\ntitle: 'Title'\nsidebar:\n  order: 15\n  title: Title\n---\n\nThe `Title` block serves as the primary heading for your docs entry. It is typically used to provide the component or page name.\n\n![Screenshot of Title block](../../_assets/api/doc-block-title-subtitle-description.png)\n\n{/* prettier-ignore-start */}\n\n```md title=\"ButtonDocs.mdx\"\nimport { Title } from '@storybook/addon-docs/blocks';\n\n<Title>This is the title</Title>\n```\n\n{/* prettier-ignore-end */}\n\n## Title\n\n```js\nimport { Title } from '@storybook/addon-docs/blocks';\n```\n\n`Title` is configured with the following props:\n\n### `children`\n\nType: `JSX.Element | string`\n\nProvides the content. Falls back to value of `title` in an [attached](./doc-block-meta.mdx#attached-vs-unattached) CSF file (or value derived from [autotitle](../../configure/user-interface/sidebar-and-urls.mdx#csf-30-auto-titles)), trimmed to the last segment. For example, if the title value is `'path/to/components/Button'`, the default content is `'Button'`.\n\n### `of`\n\nType: CSF file exports\n\nSpecifies which meta's title is displayed.\n"
  },
  {
    "path": "docs/api/doc-blocks/doc-block-typeset.mdx",
    "content": "---\ntitle: 'Typeset'\nsidebar:\n  order: 16\n  title: Typeset\n---\n\nThe `Typeset` block helps document the fonts used throughout your project.\n\n![Screenshot of Typeset block](../../_assets/api/doc-block-typeset.png)\n\n{/* prettier-ignore-start */}\n\n```md title=\"Typography.mdx\"\nimport { Meta, Typeset } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Typography\" />\n\nexport const typography = {\n  type: {\n    primary: '\"Nunito Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif',\n  },\n  weight: {\n    regular: '400',\n    bold: '700',\n    extrabold: '800',\n    black: '900',\n  },\n  size: {\n    s1: 12,\n    s2: 14,\n    s3: 16,\n    m1: 20,\n    m2: 24,\n    m3: 28,\n    l1: 32,\n    l2: 40,\n    l3: 48,\n  },\n};\n\nexport const SampleText = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';\n\n# Typography\n\n**Font:** Nunito Sans\n\n**Weights:** 400(regular), 700(bold), 800(extrabold), 900(black)\n\n<Typeset\n  fontSizes={[\n    Number(typography.size.s1),\n    Number(typography.size.s2),\n    Number(typography.size.s3),\n    Number(typography.size.m1),\n    Number(typography.size.m2),\n    Number(typography.size.m3),\n    Number(typography.size.l1),\n    Number(typography.size.l2),\n    Number(typography.size.l3),\n  ]}\n  fontWeight={typography.weight.black}\n  sampleText={SampleText}\n  fontFamily={typography.type.primary}\n/>\n```\n\n{/* prettier-ignore-end */}\n\n## Typeset\n\n```js\nimport { Typeset } from '@storybook/addon-docs/blocks';\n```\n\n`Typeset` is configured with the following props:\n\n### `fontFamily`\n\nType: `string`\n\nProvides a font family to be displayed.\n\n### `fontSizes`\n\nType: `(string | number)[]`\n\nProvides a list of available font sizes (in `px`).\n\n### `fontWeight`\n\nType: `number`\n\nSpecifies the weight of the font to be displayed.\n\n### `sampleText`\n\nType: `string`\n\nSets the text to be displayed.\n"
  },
  {
    "path": "docs/api/doc-blocks/doc-block-unstyled.mdx",
    "content": "---\ntitle: 'Unstyled'\nsidebar:\n  order: 17\n  title: Unstyled\n---\n\nThe `Unstyled` block is a special block that disables Storybook's default styling in MDX docs wherever it is added.\n\nBy default, most elements (like `h1`, `p`, etc.) in docs have a few default styles applied to ensure the docs look good. However, sometimes you might want some of your content to not have these styles applied. In those cases, wrap the content with the `Unstyled` block to remove the default styles.\n\n{/* prettier-ignore-start */}\n\n```md title=\"ButtonDocs.mdx\"\nimport { Meta, Unstyled } from \"@storybook/addon-docs/blocks\";\nimport { Header } from \"./Header.tsx\";\n\n<Meta title=\"Unstyled\" />\n\n> This block quote will be styled\n\n... and so will this paragraph.\n\n<Unstyled>\n  > This block quote will not be styled\n\n  ... neither will this paragraph, nor the following component (which contains an \\<h1\\>):\n\n  <Header />\n\n</Unstyled>\n```\n\n{/* prettier-ignore-end */}\n\nYields:\n\n![Screenshot of Unstyled Doc Block](../../_assets/api/doc-block-unstyled.png)\n\n<Callout variant=\"info\">\n\n  The other blocks like [`Story`](./doc-block-story.mdx) and [`Canvas`](./doc-block-canvas.mdx) are already unstyled, so there’s no need to wrap those in the `Unstyled` block to ensure that Storybook’s styles don’t bleed into the stories. However, if you import your components directly in the MDX, you most likely want to wrap them in the Unstyled block.\n  \n</Callout>\n\n<Callout variant=\"info\" icon=\"💡\">\n  Due to how CSS inheritance works it’s best to always add the Unstyled block to the root of your MDX, and not nested into other elements. The following example will cause some Storybook styles like `color` to be inherited into `CustomComponent` because they are applied to the root `div`:\n\n  {/* prettier-ignore-start */}\n\n  ```md\n  <div>\n    <Unstyled>\n      <CustomComponent/>\n    </Unstyled>\n  </div>\n  ```\n\n  {/* prettier-ignore-end */}\n</Callout>\n\n## Unstyled\n\n```js\nimport { Unstyled } from '@storybook/addon-docs/blocks';\n```\n\n`Unstyled` is configured with the following props:\n\n### `children`\n\nType: `React.ReactNode`\n\nProvides the content to which you do *not* want to apply default docs styles.\n"
  },
  {
    "path": "docs/api/doc-blocks/doc-block-useof.mdx",
    "content": "---\ntitle: 'useOf'\nsidebar:\n  order: 18\n  title: useOf\n---\n\nThe default blocks supplied by Storybook do not fit all use cases, so you might want to write your own blocks.\n\nIf your own doc blocks need to interface with annotations from Storybook—that is stories, meta or components—you can use the `useOf` hook. Pass in a module export of a story, meta, or component and it will return its annotated form (with applied parameters, args, loaders, decorators, play function) that you can then use for anything you like. In fact, most of the existing blocks like [`Description`](./doc-block-description.mdx) and [`Canvas`](./doc-block-canvas.mdx) use `useOf` under the hood.\n\nHere’s an example of how the`useOf` hook could be used to create a custom block that displays the name of the story:\n\n```jsx title=\".storybook/blocks/StoryName.jsx\"\nimport { useOf } from '@storybook/addon-docs/blocks';\n\n/**\n * A block that displays the story name or title from the of prop\n * - if a story reference is passed, it renders the story name\n * - if a meta reference is passed, it renders the stories' title\n * - if nothing is passed, it defaults to the primary story\n */\nexport const StoryName = ({ of }) => {\n  const resolvedOf = useOf(of || 'story', ['story', 'meta']);\n  switch (resolvedOf.type) {\n    case 'story': {\n      return <h1>{resolvedOf.story.name}</h1>;\n    }\n    case 'meta': {\n      return <h1>{resolvedOf.preparedMeta.title}</h1>;\n    }\n  }\n  return null;\n};\n```\n\n{/* prettier-ignore-start */}\n\n```md title=\"ButtonDocs.mdx\"\nimport { Meta } from '@storybook/addon-docs/blocks';\nimport { StoryName } from '../.storybook/blocks/StoryName';\nimport * as ButtonStories from './Button.stories';\n\n<Meta of={ButtonStories} />\n\n{/* Renders \"Secondary\" */}\n<StoryName of={ButtonStories.Secondary} />\n\n{/* Renders \"Primary\" */}\n<StoryName />\n\n{/* Renders \"Button\" */}\n<StoryName of={ButtonStories} />\n```\n\n{/* prettier-ignore-end */}\n\n## useOf\n\n### Type\n\n{/* prettier-ignore-start */}\n\n```ts\n(\n  moduleExportOrType: ModuleExport | 'story' | 'meta' | 'component',\n  validTypes?: Array<'story' | 'meta' | 'component'>\n) => EnhancedResolvedModuleExportType\n```\n\n{/* prettier-ignore-end */}\n\n### Parameters\n\n#### `moduleExportOrType`\n\n(**Required**)\n\nType: `ModuleExport | 'story' | 'meta' | 'component'`\n\nProvides the story export, meta export, component export, or CSF file exports from which you get annotations.\n\nWhen the custom block is in an [attached doc](./doc-block-meta.mdx#attached-vs-unattached), it’s also possible to get the primary (first) story, meta, or component by passing in a string instead. This is useful as a fallback, so the `of` prop can be omitted in your block. The most common pattern is using this as `useOf(props.of || 'story')` which will fall back to the primary story if no `of` prop is defined.\n\n* `useOf('story')` returns the annotated primary story in attached mode; error in unattached mode\n* `useOf('meta')` returns the annotated meta in attached mode; error in unattached mode\n* `useOf('component')` returns the annotated component specified in the meta in attached mode; error in unattached mode\n\n#### `validTypes`\n\nType: `Array<'story' | 'meta' | 'component'>`\n\nOptionally specify an array of valid types that your block accepts. Passing anything other than the valid type(s) will result in an error. For example, the [`Canvas`](./doc-block-canvas.mdx) block uses `useOf(of, ['story'])`, which ensures it only accepts a reference to a story, not a meta or component.\n\n### Return\n\nThe return value depends on the matched type:\n\n#### `EnhancedResolvedModuleExportType['type'] === 'story'`\n\nType: `{ type: 'story', story: PreparedStory }`\n\nFor stories, annotated stories are returned as is. They are prepared, meaning that they are already merged with project and meta annotations.\n\n#### `EnhancedResolvedModuleExportType['type'] === 'meta'`\n\nType: `{ type: 'meta', csfFile: CSFFile, preparedMeta: PreparedMeta }`\n\nFor meta, the parsed CSF file is returned, along with prepared annotated meta. That is, project annotations merged with meta annotations, but no story annotations.\n\n#### `EnhancedResolvedModuleExportType['type'] === 'component'`\n\nType: `{ type: 'component', component: Component, projectAnnotations: NormalizedProjectAnnotations }`\n\nFor components, the component is returned along with project annotations; no meta or story annotations.\n\nNote that it’s often impossible for the hook to determine if a component is passed in or any other object, so it behaves like an `unknown` type as well.\n"
  },
  {
    "path": "docs/api/doc-blocks/index.mdx",
    "content": "---\ntitle: Doc Blocks\nsidebar:\n  order: 5\n  title: Doc Blocks\n---"
  },
  {
    "path": "docs/api/index.mdx",
    "content": "---\ntitle: 'API references'\nhideRendererSelector: true\nsidebar:\n  order: 12\n  title: API\n---\n\n{/*\n  We intentionally do not use markdown tables here because the required formatting (one row per line)\n  makes it very difficult to read, particularly when comparing changes.\n  Also, using HTML directly allows us to apply a consistent width to the first column.\n  However, this means the links won't work when viewing in GitHub. :(\n*/}\n\nAn overview of all available API references for Storybook.\n\n## Configuration\n\n<Table>\n  <thead>\n    <Tr>\n      <Th scope=\"col\" width=\"33%\">Name</Th>\n      <Th scope=\"col\">Description</Th>\n    </Tr>\n  </thead>\n\n  <tbody>\n    <Tr>\n      <Td><A href=\"./api/main-config/main-config\"><code>main.js|ts</code></A></Td>\n\n      <Td>\n        Storybook's primary configuration file, which specifies your Storybook project's behavior,\n        including the location of your stories, the addons you use, feature flags and other\n        project-specific settings.\n      </Td>\n    </Tr>\n\n    <Tr>\n      <Td><A href=\"./configure/#configure-story-rendering\"><code>preview.js|jsx|ts|tsx</code></A></Td>\n\n      <Td>\n        This configuration file controls the way stories are rendered. You can also use it to run\n        code that applies to all stories.\n      </Td>\n    </Tr>\n\n    <Tr>\n      <Td><A href=\"./configure/#configure-storybooks-ui\"><code>manager.js|ts</code></A></Td>\n\n      <Td>\n        This configuration file controls the behavior of Storybook's UI, the manager.\n      </Td>\n    </Tr>\n\n    <Tr>\n      <Td><A href=\"./api/cli-options\">CLI</A></Td>\n\n      <Td>\n        Storybook is a CLI tool. You can start Storybook in development mode or build a static\n        version of your Storybook.\n      </Td>\n    </Tr>\n  </tbody>\n</Table>\n\n## Stories\n\n<Table>\n  <thead>\n    <Tr>\n      <Th scope=\"col\" width=\"33%\">Name</Th>\n      <Th scope=\"col\">Description</Th>\n    </Tr>\n  </thead>\n\n  <tbody>\n    <Tr>\n      <Td><A href=\"./api/csf\">CSF</A></Td>\n\n      <Td>\n        Component Story Format (CSF) is the API for writing stories. It's an\n        open standard based on ES6 modules that\n        is portable beyond Storybook.\n      </Td>\n    </Tr>\n\n    <Tr>\n      <Td><A href=\"./api/arg-types\">ArgTypes</A></Td>\n\n      <Td>\n        ArgTypes specify the behavior of <a href=\"./writing-stories/args\">args</a>. By specifying\n        the type of an arg, you constrain the values that it can accept and provide information\n        about args that are not explicitly set.\n      </Td>\n    </Tr>\n\n    <Tr>\n      <Td><A href=\"./api/parameters\">Parameters</A></Td>\n\n      <Td>\n        Parameters are static metadata used to configure your <a href=\"./get-started/whats-a-story\">stories</a> <a href=\"./addons\">addons</a> in Storybook. They are specified at the story, meta (component), project (global) levels.\n      </Td>\n    </Tr>\n  </tbody>\n</Table>\n\n## Docs\n\n<Table>\n  <thead>\n    <Tr>\n      <Th scope=\"col\" width=\"33%\">Name</Th>\n      <Th scope=\"col\">Description</Th>\n    </Tr>\n  </thead>\n\n  <tbody>\n    <Tr>\n      <Td><A href=\"./writing-docs/doc-blocks/#available-blocks\">Doc blocks</A></Td>\n\n      <Td>\n        Storybook offers several doc blocks to help document your components and other aspects of\n        your project.\n      </Td>\n    </Tr>\n  </tbody>\n</Table>\n"
  },
  {
    "path": "docs/api/main-config/index.mdx",
    "content": "---\ntitle: 'main.js|ts configuration'\nsidebar:\n  order: 1\n  title: main.js|ts configuration\n---"
  },
  {
    "path": "docs/api/main-config/main-config-addons.mdx",
    "content": "---\ntitle: 'addons'\nsidebar:\n  order: 4\n  title: addons\n---\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType: `(string | { name: string; options?: AddonOptions })[]`\n\nRegisters the [addons](../../addons/install-addons.mdx) loaded by Storybook.\n\nFor each addon's available options, see their respective [documentation](https://storybook.js.org/integrations).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-addons.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/api/main-config/main-config-babel-default.mdx",
    "content": "---\ntitle: 'babelDefault'\nsidebar:\n  order: 6\n  title: babelDefault\n---\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType: `(config: Babel.Config, options: Options) => Babel.Config | Promise<Babel.Config>`\n\n`babelDefault` allows customization of Storybook's [Babel](https://babeljs.io/) setup. It is applied to the preview config before any user presets have been applied, which makes it useful and recommended for [addon authors](../../addons/writing-presets.mdx#babel) so that the end user's [`babel`](./main-config-babel.mdx) setup can override it.\n\n<Callout variant=\"info\" icon=\"💡\">\n\n  To adjust your Storybook's Babel setup directly—not via an addon—use [`babel`](./main-config-babel.mdx) instead.\n  \n</Callout>\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-babel-configuration-example.md\" />\n\n{/* prettier-ignore-end */}\n\n## `Babel.Config`\n\nThe options provided by [Babel](https://babeljs.io/docs/options) are only applicable if you've enabled the [`@storybook/addon-webpack5-compiler-babel`](https://storybook.js.org/addons/@storybook/addon-webpack5-compiler-babel) addon.\n\n## `Options`\n\nType: `{ configType?: 'DEVELOPMENT' | 'PRODUCTION' }`\n\nThere are other options that are difficult to document here. Please introspect the type definition for more information.\n"
  },
  {
    "path": "docs/api/main-config/main-config-babel.mdx",
    "content": "---\ntitle: 'babel'\nsidebar:\n  order: 5\n  title: babel\n---\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType: `(config: Babel.Config, options: Options) => Babel.Config | Promise<Babel.Config>`\n\nCustomize Storybook's [Babel](https://babeljs.io/) setup.\n\n<Callout variant=\"info\" icon=\"💡\">\n\n  [Addon authors](../../addons/writing-presets.mdx#babel) should use [`babelDefault`](./main-config-babel-default.mdx) instead, which is applied to the preview config before any user presets have been applied.\n\n</Callout>\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-babel.md\" />\n\n{/* prettier-ignore-end */}\n\n## `Babel.Config`\n\nThe options provided by [Babel](https://babeljs.io/docs/options) are only applicable if you've enabled the [`@storybook/addon-webpack5-compiler-babel`](https://storybook.js.org/addons/@storybook/addon-webpack5-compiler-babel) addon.\n\n<Callout variant=\"info\">\n\n  If you have an existing Babel configuration file (e.g., `.babelrc`), it will be automatically detected and used by Storybook without any additional configuration required.\n  \n</Callout>\n\n## `Options`\n\nType: `{ configType?: 'DEVELOPMENT' | 'PRODUCTION' }`\n\nThere are other options that are difficult to document here. Please introspect the type definition for more information.\n"
  },
  {
    "path": "docs/api/main-config/main-config-build.mdx",
    "content": "---\ntitle: 'build'\nsidebar:\n  order: 7\n  title: build\n---\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType: `TestBuildConfig`\n\nProvides configuration options to optimize Storybook's production build output.\n\n## `test`\n\nType: `TestBuildFlags`\n\n```ts\n{\n  disableBlocks?: boolean;\n  disabledAddons?: string[];\n  disableMDXEntries?: boolean;\n  disableAutoDocs?: boolean;\n  disableDocgen?: boolean;\n  disableSourcemaps?: boolean;\n  disableTreeShaking?: boolean;\n\n}\n```\n\nConfigures Storybook's production builds for performance testing purposes by disabling certain features from the build. When running `storybook build`, this feature is enabled by setting the `--test` [flag](../cli-options.mdx#build).\n\n<Callout variant=\"info\" icon=\"💡\">\n\n  The options documented on this page are automatically enabled when the `--test` flag is provided to the [`storybook build`](../cli-options.mdx#build) command. We encourage you to override these options only if you need to disable a specific feature for your project or if you are debugging a build issue.\n\n</Callout>\n\n### `test.disableBlocks`\n\nType: `boolean`\n\nExcludes the `@storybook/addon-docs/blocks` module from the build, which generates automatic documentation with [Docs Blocks](../../writing-docs/doc-blocks.mdx).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-test-disable-blocks.md\" />\n\n{/* prettier-ignore-end */}\n\n### `test.disabledAddons`\n\nType: `string[]`\n\nSets the list of addons that will be disabled in the build output.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-test-disable-disableaddons.md\" />\n\n{/* prettier-ignore-end */}\n\n### `test.disableMDXEntries`\n\nType: `boolean`\n\nEnabling this option removes user-written documentation entries in MDX format from the build.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-test-disable-mdx.md\" />\n\n{/* prettier-ignore-end */}\n\n### `test.disableAutoDocs`\n\nType: `boolean`\n\nPrevents automatic documentation generated with the [autodocs](../../writing-docs/autodocs.mdx) feature from being included in the build.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-test-disable-autodocs.md\" />\n\n{/* prettier-ignore-end */}\n\n### `test.disableDocgen`\n\nType: `boolean`\n\nDisables [automatic argType](../arg-types.mdx#automatic-argtype-inference) and component property inference with any of the supported static analysis tools based on the framework you are using.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-test-disable-docgen.md\" />\n\n{/* prettier-ignore-end */}\n\n### `test.disableSourcemaps`\n\nType: `boolean`\n\nOverrides the default behavior of generating source maps for the build.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-test-disable-sourcemaps.md\" />\n\n{/* prettier-ignore-end */}\n\n### `test.disableTreeShaking`\n\nType: `boolean`\n\nDisables [tree shaking](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking) in the build.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-test-disable-treeshaking.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/api/main-config/main-config-core.mdx",
    "content": "---\ntitle: 'core'\nsidebar:\n  order: 8\n  title: core\n---\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType:\n\n```ts\n{\n  allowedHosts?: string[] | true;\n  builder?: string | { name: string; options?: BuilderOptions };\n  channelOptions?: ChannelOptions;\n  crossOriginIsolated?: boolean;\n  disableProjectJson?: boolean;\n  disableTelemetry?: boolean;\n  disableWebpackDefaults?: boolean;\n  disableWhatsNewNotifications?: boolean;\n  enableCrashReports?: boolean;\n  renderer?: RendererName;\n}\n```\n\nConfigures Storybook's internal features.\n\n## `allowedHosts`\n\nType: `string[] | true`\n\nDefault: `[]`\n\nConfigures the allowed hosts for the Storybook dev server, used for Origin and Host header validation. Storybook's localhost and local network (or [`--host`](../cli-options.mdx#dev)) addresses are always allowed. Use this when accessing your local Storybook instance through a reverse proxy (e.g. your webapp dev server). Set to `true` to disable hostname validation (insecure).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-core-allowed-hosts.md\" />\n\n{/* prettier-ignore-end */}\n\n## `builder`\n\nType:\n\n```ts\n| '@storybook/builder-vite' | '@storybook/builder-webpack5'\n| {\n    name: '@storybook/builder-vite' | '@storybook/builder-webpack5';\n    options?: BuilderOptions;\n  }\n```\n\nConfigures Storybook's builder, [Vite](../../builders/vite.mdx) or [Webpack](../../builders/webpack.mdx).\n\n<Callout variant=\"info\" icon=\"💡\">\n  With the new [Framework API](../new-frameworks.mdx), [`framework.options.builder`](./main-config-framework.mdx#optionsbuilder) is now the preferred way to configure the builder.\n\n  You should only use `core.builder.options` if you need to configure a builder that is not part of a framework.\n</Callout>\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-core-builder.md\" />\n\n{/* prettier-ignore-end */}\n\n## `channelOptions`\n\nType: `ChannelOptions`\n\n```ts\n{\n  allowDate: boolean;\n  allowRegExp: boolean;\n  allowSymbol: boolean;\n  allowUndefined: boolean;\n  maxDepth: number;\n  space: number | undefined;\n}\n```\n\nConfigures the channel used by Storybook to communicate between the manager and preview.\n\nOnly two properties are likely to be used:\n\n\n### `channelOptions.maxDepth`\n\nType: `number`\n\nDefault: `3`\n\nThe maximum depth of nested objects to serialize across the channel. Larger values will be slower.\n\n## `crossOriginIsolated`\n\nType: `boolean`\n\nEnable CORS headings to run document in a \"secure context\". See [SharedArrayBuffer security requirements](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements)\n\nThis enables these headers in development-mode:\n\n* `Cross-Origin-Opener-Policy: same-origin`\n* `Cross-Origin-Embedder-Policy: require-corp`\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-core-cross-origin-isolated.md\" />\n\n{/* prettier-ignore-end */}\n\n## `disableProjectJson`\n\nType: `boolean`\n\nDisables the generation of `project.json`, a file containing Storybook metadata\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-core-disable-project-json.md\" />\n\n{/* prettier-ignore-end */}\n\n## `disableTelemetry`\n\nType: `boolean`\n\nDisables Storybook's [telemetry collection](../../configure/telemetry.mdx).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-core-disable-telemetry.md\" />\n\n{/* prettier-ignore-end */}\n\n## `disableWebpackDefaults`\n\nType: `boolean`\n\nDisables Storybook's default Webpack configuration.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-core-disable-webpack-defaults.md\" />\n\n{/* prettier-ignore-end */}\n\n## `disableWhatsNewNotifications`\n\nType: `boolean`\n\nDisables the \"What's New\" notifications in the UI for new Storybook versions and ecosystem updates (e.g., [addons](https://storybook.js.org/integrations/), [content](https://storybook.js.org/blog/), etc.).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-core-disable-update-notifications.md\" />\n\n{/* prettier-ignore-end */}\n\n## `enableCrashReports`\n\nType: `boolean`\n\nEnable crash reports to be sent to Storybook [telemetry](../../configure/telemetry.mdx).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-core-enable-crash-reports.md\" />\n\n{/* prettier-ignore-end */}\n\n## `renderer`\n\nType: `RendererName`\n\n{/* TODO: Is this used? Should it be documented? */}\n"
  },
  {
    "path": "docs/api/main-config/main-config-docs.mdx",
    "content": "---\ntitle: 'docs'\nsidebar:\n  order: 9\n  title: docs\n---\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType:\n\n```ts\n{\n  defaultName?: string;\n  docsMode?: boolean;\n}\n```\n\nConfigures Storybook's [auto-generated documentation](../../writing-docs/autodocs.mdx).\n\n## `defaultName`\n\nType: `string`\n\nDefault: `'Docs'`\n\nName used for generated documentation pages.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-docs-default-name.md\" />\n\n{/* prettier-ignore-end */}\n\n## `docsMode`\n\nType: `boolean`\n\nOnly show documentation pages in the sidebar (usually set with the `--docs` CLI flag).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-docs-docs-mode.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/api/main-config/main-config-env.mdx",
    "content": "---\ntitle: 'env'\nsidebar:\n  order: 10\n  title: env\n---\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType: `(config: { [key: string]: string }) => { [key: string]: string }`\n\nDefines custom Storybook [environment variables](../../configure/environment-variables.mdx#using-storybook-configuration).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-env.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/api/main-config/main-config-features.mdx",
    "content": "---\ntitle: 'features'\nsidebar:\n  order: 11\n  title: features\n---\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType:\n\n<If renderer=\"react\">\n\n```ts\n{\n  actions?: boolean;\n  argTypeTargetsV7?: boolean;\n  backgrounds?: boolean;\n  changeDetection?: boolean;\n  componentsManifest?: boolean;\n  controls?: boolean;\n  developmentModeForBuild?: boolean;\n  experimentalCodeExamples?: boolean;\n  experimentalTestSyntax?: boolean;\n  highlight?: boolean;\n  interactions?: boolean;\n  legacyDecoratorFileOrder?: boolean;\n  measure?: boolean;\n  outline?: boolean;\n  sidebarOnboardingChecklist?: boolean;\n  toolbars?: boolean;\n  viewport?: boolean;\n}\n```\n</If>\n\n<If renderer=\"angular\">\n\n```ts\n{\n  actions?: boolean;\n  angularFilterNonInputControls?: boolean;\n  argTypeTargetsV7?: boolean;\n  backgrounds?: boolean;\n  changeDetection?: boolean;\n  controls?: boolean;\n  developmentModeForBuild?: boolean;\n  highlight?: boolean;\n  interactions?: boolean;\n  legacyDecoratorFileOrder?: boolean;\n  measure?: boolean;\n  outline?: boolean;\n  sidebarOnboardingChecklist?: boolean;\n  toolbars?: boolean;\n  viewport?: boolean;\n}\n```\n</If>\n\n<If notRenderer={['react','angular']}>\n\n```ts\n{\n  actions?: boolean;\n  argTypeTargetsV7?: boolean;\n  backgrounds?: boolean;\n  changeDetection?: boolean;\n  controls?: boolean;\n  developmentModeForBuild?: boolean;\n  highlight?: boolean;\n  interactions?: boolean;\n  legacyDecoratorFileOrder?: boolean;\n  measure?: boolean;\n  outline?: boolean;\n  sidebarOnboardingChecklist?: boolean;\n  toolbars?: boolean;\n  viewport?: boolean;\n}\n```\n</If>\n\n\nEnables Storybook's additional features.\n\n## `actions`\n\nType: `boolean`\n\nDefault: `true`\n\nEnable the [Actions](../../essentials/actions.mdx) feature.\n\n<If renderer=\"angular\">\n\n## `angularFilterNonInputControls`\n\nType: `boolean`\n\nFilter non-input controls in Angular.\n\n</If>\n\n## `argTypeTargetsV7`\n\n(⚠️ **Experimental**)\n\nType: `boolean`\n\nDefault: `true`\n\nFilter args with a \"target\" on the type from the render function.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-features-arg-type-targets-v7.md\" />\n\n{/* prettier-ignore-end */}\n\n## `backgrounds`\n\nType: `boolean`\n\nDefault: `true`\n\nEnable the [Backgrounds](../../essentials/backgrounds.mdx) feature.\n\n<If renderer=\"react\">\n\n## `componentsManifest`\n\nType: `boolean`\n\nDefault: `true`\n\nGenerate [manifests](../../ai/manifests.mdx), used by the [MCP server](../../ai/mcp/overview.mdx).\n\n<CodeSnippets path=\"main-config-features-components-manifest.md\" />\n\n</If>\n\n## `changeDetection`\n\nType: `boolean`\n\nDefault: `true`\n\nEnable change detection.\n\n## `controls`\n\nType: `boolean`\n\nDefault: `true`\n\nEnable the [Controls](../../essentials/controls.mdx) feature.\n\n## `developmentModeForBuild`\n\nType: `boolean`\n\nSet `NODE_ENV` to `'development'` in built Storybooks for better testing and debugging capabilities.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-features-development-mode-for-build.md\" />\n\n{/* prettier-ignore-end */}\n\n<If renderer=\"react\">\n\n## `experimentalCodeExamples`\n\n(⚠️ **Experimental**)\n\nType: `boolean`\n\nEnable the new code example generation method for React components (as seen in the story previews in an [autodocs](../../writing-docs/autodocs.mdx) page).\n\nUnlike the current implementation, this method reads the actual stories source file, which is faster to generate, more readable, and more accurate. However, they are not dynamic: they won't update if you change values in the Controls table.\n\n<CodeSnippets path=\"main-config-features-experimental-code-examples.md\" />\n\n## `experimentalTestSyntax`\n\n(⚠️ **Experimental**)\n\nType: `boolean`\n\nEnable the [experimental `.test` method with the CSF Next format](../csf/csf-next#storytest).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-features-experimental-test-syntax.md\" />\n\n{/* prettier-ignore-end */}\n\n</If>\n\n## `highlight`\n\nType: `boolean`\n\nDefault: `true`\n\nEnable the [Highlight](../../essentials/highlight.mdx) feature.\n\n## `interactions`\n\nType: `boolean`\n\nDefault: `true`\n\nEnable the [Interactions](../../writing-tests/interaction-testing.mdx#debugging-interaction-tests) feature.\n\n## `legacyDecoratorFileOrder`\n\nType: `boolean`\n\nApply decorators from preview.js before decorators from addons or frameworks. [More information](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#changed-decorator-order-between-previewjs-and-addonsframeworks).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-features-legacy-decorator-file-order.md\" />\n\n{/* prettier-ignore-end */}\n\n## `measure`\n\nType: `boolean`\n\nDefault: `true`\n\nEnable the [Measure](../../essentials/measure-and-outline.mdx#measure) feature.\n\n## `outline`\n\nType: `boolean`\n\nDefault: `true`\n\nEnable the [Outline](../../essentials/measure-and-outline.mdx#outline) feature.\n\n## `sidebarOnboardingChecklist`\n\nType: `boolean`\n\nDefault: `true`\n\nEnable the onboarding checklist sidebar widget.\n\n## `viewport`\n\nType: `boolean`\n\nDefault: `true`\n\nEnable the [Viewport](../../essentials/viewport.mdx) feature.\n"
  },
  {
    "path": "docs/api/main-config/main-config-framework.mdx",
    "content": "---\ntitle: 'framework'\nsidebar:\n  order: 2\n  title: framework\n---\n\n(**Required**)\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType: `FrameworkName | { name: FrameworkName; options?: FrameworkOptions }`\n\nConfigures Storybook based on a set of [framework-specific](../../configure/integration/frameworks.mdx) settings.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-framework.md\" />\n\n{/* prettier-ignore-end */}\n\n## `name`\n\nType: `string`\n\nFor available frameworks and their options, see their respective [documentation](https://github.com/storybookjs/storybook/tree/next/code/frameworks).\n\n## `options`\n\nType: `Record<string, any>`\n\nWhile many options are specific to a framework, there are some options that are shared across some frameworks, e.g. those that configure Storybook's [builder](./main-config-core.mdx#builder).\n\n### `options.builder`\n\nType: `Record<string, any>`\n\nConfigures Storybook's builder, [Vite](../../builders/vite.mdx) or [Webpack](../../builders/webpack.mdx).\n"
  },
  {
    "path": "docs/api/main-config/main-config-indexers.mdx",
    "content": "---\ntitle: 'indexers'\nsidebar:\n  order: 12\n  title: indexers\n---\n\n(⚠️ **Experimental**)\n\n<Callout variant=\"warning\" icon=\"🧪\">\n  While this feature is experimental, it must be specified by the `experimental_indexers` property of [`StorybookConfig`](./main-config.mdx).\n</Callout>\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType: `(existingIndexers: Indexer[]) => Promise<Indexer[]>`\n\nIndexers are responsible for building Storybook's index of stories—the list of all stories and a subset of their metadata like `id`, `title`, `tags`, and more. The index can be read at the `/index.json` route of your Storybook.\n\nThe indexers API is an advanced feature that allows you to customize Storybook's indexers, which dictate how Storybook indexes and parses files into story entries. This adds more flexibility to how you can write stories, including which language stories are defined in or where to get stories from.\n\nThey are defined as a function that returns the full list of indexers, including the existing ones. This allows you to add your own indexer to the list, or to replace an existing one:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-indexers.md\" />\n\n{/* prettier-ignore-end */}\n\nUnless your indexer is doing something relatively trivial (e.g. [indexing stories with a different naming convention](../../configure/user-interface/sidebar-and-urls.mdx#story-indexers)), in addition to indexing the file, you will likely need to [transpile it to CSF](#transpiling-to-csf) so that Storybook can read them in the browser.\n\n## `Indexer`\n\nType:\n\n```ts\n{\n  test: RegExp;\n  createIndex: (fileName: string, options: IndexerOptions) => Promise<IndexInput[]>;\n}\n```\n\nSpecifies which files to index and how to index them as stories.\n\n### `test`\n\n(Required)\n\nType: `RegExp`\n\nA regular expression run against file names included in the [`stories`](./main-config-stories.mdx) configuration that should match all files to be handled by this indexer.\n\n### `createIndex`\n\n(Required)\n\nType: `(fileName: string, options: IndexerOptions) => Promise<IndexInput[]>`\n\nFunction that accepts a single CSF file and returns a list of entries to index.\n\n#### `fileName`\n\nType: `string`\n\nThe name of the CSF file used to create entries to index.\n\n#### `IndexerOptions`\n\nType:\n\n```ts\n{\n  makeTitle: (userTitle?: string) => string;\n}\n```\n\nOptions for indexing the file.\n\n##### `makeTitle`\n\nType: `(userTitle?: string) => string`\n\nA function that takes a user-provided title and returns a formatted title for the index entry, which is used in the sidebar. If no user title is provided, one is automatically generated based on the file name and path.\n\nSee [`IndexInput.title`](#title) for example usage.\n\n#### `IndexInput`\n\nType:\n\n```ts\n{\n  exportName: string;\n  importPath: string;\n  type: 'story';\n  subtype?: 'story' | 'test';\n  rawComponentPath?: string;\n  metaId?: string;\n  name?: string;\n  tags?: string[];\n  title?: string;\n  __id?: string;\n}\n```\n\nAn object representing a story to be added to the stories index.\n\n##### `exportName`\n\n(Required)\n\nType: `string`\n\nFor each `IndexInput`, the indexer will add this export (from the file found at `importPath`) as an entry in the index.\n\n##### `importPath`\n\nType: `string`\n\nDefault: The original [`fileName`](#filename) passed to the `createIndex` function\n\nThe file to import from, e.g. the [CSF](../csf/index.mdx) file.\n\nIt is likely that the [`fileName`](#filename) being indexed is not CSF, in which you will need to [transpile it to CSF](#transpiling-to-csf) so that Storybook can read it in the browser.\n\n⚠️ Custom `importPath`s are only supported in Vite-based projects. To use them in Webpack-based projects, you will need to [transpile the source file to CSF](#transpiling-to-csf) and leave `importPath` empty to use the original `fileName`.\n\n##### `type`\n\n(Required)\n\nType: `'story'`\n\nThe type of entry.\n\n##### `subtype`\n\n(⚠️ **Experimental**)\n\nType: `'story' | 'test'`\n\nDefault: `'story'`\n\nThe subtype of the story entry when [`type`](#type) is `'story'`. Use this to mark an entry as a [_test_ (experimental)](https://github.com/storybookjs/storybook/discussions/30119). If not specified, defaults to `'story'`.\n\n##### `rawComponentPath`\n\nType: `string`\n\nThe raw path/package of the file that provides `meta.component`, if one exists.\n\n##### `metaId`\n\nType: `string`\n\nDefault: Auto-generated from [`title`](#title)\n\nDefine the custom id for meta of the entry.\n\nIf specified, the export default (meta) in the CSF file *must* have a corresponding `id` property, to be correctly matched.\n\n##### `name`\n\nType: `string`\n\nDefault: Auto-generated from [`exportName`](#exportname)\n\nThe name of the entry.\n\n##### `tags`\n\nType: `string[]`\n\nTags for filtering entries in Storybook and its tools.\n\n##### `title`\n\nType: `string`\n\nDefault: Auto-generated from the meta (or default export) of [`importPath`](#importpath)\n\nDetermines the location of the entry in the sidebar.\n\nMost of the time, you should **not** specify a title, so that your indexer will use the default naming behavior. When specifying a title, you **must** use the [`makeTitle`](#maketitle) function provided in [`IndexerOptions`](#indexeroptions) to also use this behavior. For example, here's an indexer that merely appends a \"Custom\" prefix to the title derived from the file name:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-indexers-title.md\" />\n\n{/* prettier-ignore-end */}\n\n##### `__id`\n\nType: `string`\n\nDefault: Auto-generated from [`title`](#title)/[`metaId`](#metaid) and [`exportName`](#exportname)\n\nDefine the custom id for the story of the entry.\n\nIf specified, the story in the CSF file **must** have a corresponding `__id` property, to be correctly matched.\n\nOnly use this if you need to override the auto-generated id.\n\n## Transpiling to CSF\n\nThe value of [`importPath`](#importpath) in an [`IndexInput`](#indexinput) must resolve to a [CSF](../csf/index.mdx) file. Most custom indexers, however, are only necessary because the input is *not* CSF. Therefore, you will likely need to transpile the input to CSF, so that Storybook can read it in the browser and render your stories.\n\nTranspiling the custom source format to CSF is beyond the scope of this documentation. This transpilation is often done at the builder level ([Vite](../../builders/vite.mdx) and/or [Webpack](../../builders/webpack.mdx)), and we recommend using [unplugin](https://github.com/unjs/unplugin) to create plugins for multiple builders.\n\nThe general architecture looks something like this:\n\n![Architecture diagram showing how a custom indexer indexes stories from a source file](../../_assets/api/main-config-indexers-arch-indexer.jpg)\n\n1. Using the [`stories`](./main-config-stories.mdx) configuration, Storybook finds all files that match the [`test`](#test) property of your indexer\n2. Storybook passes each matching file to your indexer's [`createIndex` function](#createindex), which uses the file contents to generate and return a list of index entries (stories) to add to the index\n3. The index populates the sidebar in the Storybook UI\n\n![Architecture diagram showing how a build plugin transforms a source file into CSF](../../_assets/api/main-config-indexers-arch-build-plugin.jpg)\n\n4. In the Storybook UI, the user navigates to a URL matching the story id and the browser requests the CSF file specified by the [`importPath`](#importpath) property of the index entry\n5. Back on the server, your builder plugin transpiles the source file to CSF, and serves it to the client\n6. The Storybook UI reads the CSF file, imports the story specified by [`exportName`](#exportname), and renders it\n\nLet's look at an example of how this might work.\n\nFirst, here's an example of a non-CSF source file:\n\n```ts\n// Button.variants.js|ts\n\nimport { variantsFromComponent, createStoryFromVariant } from '../utils';\nimport { Button } from './Button';\n\n/**\n * Returns raw strings representing stories via component props, eg.\n * 'export const PrimaryVariant = {\n *    args: {\n *      primary: true\n *    },\n *  };'\n */\nexport const generateStories = () => {\n  const variants = variantsFromComponent(Button);\n  return variants.map((variant) => createStoryFromVariant(variant));\n};\n```\n\nThe builder plugin would then:\n\n1. Receive and read the source file\n2. Import the exported `generateStories` function\n3. Run the function to generate the stories\n4. Write the stories to a CSF file\n\nThat resulting CSF file would then be indexed by Storybook. It would look something like this:\n\n```js\n// virtual:Button.variants.js|ts\n\nimport { Button } from './Button';\n\nexport default {\n  component: Button,\n};\n\nexport const Primary = {\n  args: {\n    primary: true,\n  },\n};\n```\n\n### Examples\n\nSome example usages of custom indexers include:\n\n<details open>\n  <summary>Generating stories dynamically from fixture data or API endpoints</summary>\n\n  This indexer generates stories for components based on JSON fixture data. It looks for `*.stories.json` files in the project, adds them to the index and separately converts their content to CSF.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"main-config-indexers-jsonstories.md\" />\n\n  {/* prettier-ignore-end */}\n\n  An example input JSON file could look like this:\n\n  ```json\n  {\n    \"Button\": {\n      \"componentPath\": \"./button/Button.jsx\",\n      \"stories\": {\n        \"Primary\": {\n          \"args\": {\n            \"primary\": true\n          },\n        \"Secondary\": {\n          \"args\": {\n            \"primary\": false\n          }\n        }\n      }\n    },\n    \"Dialog\": {\n      \"componentPath\": \"./dialog/Dialog.jsx\",\n      \"stories\": {\n        \"Closed\": {},\n        \"Open\": {\n          \"args\": {\n            \"isOpen\": true\n          }\n        },\n      }\n    }\n  }\n  ```\n\n  A builder plugin will then need to transform the JSON file into a regular CSF file. This transformation could be done with a Vite plugin similar to this:\n\n  ```ts\n  // vite-plugin-storybook-json-stories.ts\n\n  import type { PluginOption } from 'vite';\n  import fs from 'fs/promises';\n\n  function JsonStoriesPlugin(): PluginOption {\n    return {\n      name: 'vite-plugin-storybook-json-stories',\n      load(id) {\n        if (!id.startsWith('virtual:jsonstories')) {\n          return;\n        }\n\n        const [, fileName, componentName] = id.split('--');\n        const content = JSON.parse(fs.readFileSync(fileName));\n\n        const { componentPath, stories } = getComponentStoriesFromJson(content, componentName);\n\n        return `\n          import ${componentName} from '${componentPath}';\n\n          export default { component: ${componentName} };\n\n          ${stories.map((story) => `export const ${story.name} = ${story.config};\\n`)}\n        `;\n      },\n    };\n  }\n  ```\n</details>\n\n<details>\n  <summary>Generating stories with an alternative API</summary>\n\n  You can use a custom indexer and builder plugin to create your API to define stories extending the CSF format. To learn more, see the following [proof of concept](https://stackblitz.com/edit/github-h2rgfk?file=README.md) to set up a custom indexer to generate stories dynamically. It contains everything needed to support such a feature, including the indexer, a Vite plugin, and a Webpack loader.\n</details>\n\n<details>\n  <summary>Defining stories in non-JavaScript language</summary>\n\n  Custom indexers can be used for an advanced purpose: defining stories in any language, including template languages, and converting the files to CSF. To see examples of this in action, you can refer to [`@storybook/addon-svelte-csf`](https://github.com/storybookjs/addon-svelte-csf) for Svelte template syntax and [`storybook-vue-addon`](https://github.com/tobiasdiez/storybook-vue-addon) for Vue template syntax.\n</details>\n\n\n<details>\n  <summary>Adding sidebar links from a URL collection</summary>\n\n  The indexer API is flexible enough to let you process arbitrary content, so long as your framework tooling can transform the exports in that content into actual stories it can run. This advanced example demonstrates how you can create a custom indexer to process a collection of URLs, extract the title and URL from each page, and render them as sidebar links in the UI. Implemented with Svelte, it can be adapted to any framework.\n\n  Start by creating the URL collection file (i.e., `src/MyLinks.url.js`) with a list of URLs listed as named exports. The indexer will use the export name as the story title and the value as the unique identifier.\n\n  ```js title=\"MyLinks.url.js\"\n  export default {};\n\n  export const DesignTokens = 'https://www.designtokens.org/';\n  export const CobaltUI = 'https://cobalt-ui.pages.dev/';\n  export const MiseEnMode = 'https://mode.place/';\n  export const IndexerAPI = 'https://github.com/storybookjs/storybook/discussions/23176';\n  ```\n\n  Adjust your Vite configuration file to include a custom plugin complementing the indexer. This will allow Storybook to process and import the URL collection file as stories.\n\n  ```ts title=\"vite.config.ts\"\n  import * as acorn from 'acorn';\n  import * as walk from 'acorn-walk';\n  import { defineConfig, type Plugin } from 'vite';\n  import { svelte } from '@sveltejs/vite-plugin-svelte';\n\n  function StorybookUrlLinksPlugin(): Plugin {\n    return {\n      name: 'storybook-url-links',\n      async transform(code: string, id: string) {\n        if (id.endsWith('.url.js')) {\n          const ast = acorn.parse(code, {\n            ecmaVersion: 2020,\n            sourceType: 'module',\n          });\n\n          const namedExports: string[] = [];\n          let defaultExport = 'export default {};';\n\n          walk.simple(ast, {\n            // Extracts the named exports, those represent our stories, and for each of them, we'll return a valid Svelte component.\n            ExportNamedDeclaration(node: acorn.ExportNamedDeclaration) {\n              if (\n                node.declaration &&\n                node.declaration.type === 'VariableDeclaration'\n              ) {\n                node.declaration.declarations.forEach((declaration) => {\n                  if ('name' in declaration.id) {\n                    namedExports.push(declaration.id.name);\n                  }\n                });\n              }\n            },\n            // Preserve our default export.\n            ExportDefaultDeclaration(node: acorn.ExportDefaultDeclaration) {\n              defaultExport = code.slice(node.start, node.end);\n            },\n          });\n\n          return {\n            code: `\n              import RedirectBack from '../../.storybook/components/RedirectBack.svelte';\n              ${namedExports\n                .map(\n                  (name) =>\n                    `export const ${name} = () => new RedirectBack();`\n                )\n                .join('\\n')}\n              ${defaultExport}\n            `,\n            map: null,\n          };\n        }\n      },\n    };\n  }\n\n  export default defineConfig({\n    plugins: [StorybookUrlLinksPlugin(), svelte()],\n  })\n  ```\n\n  Update your Storybook configuration (i.e., `.storybook/main.js|ts`) to include the custom indexer.\n\n  ```ts title=\".storybook/main.js|ts\"\n  // Replace your-framework with the framework you are using, e.g. sveltekit or svelte-vite\n  import type { StorybookConfig } from '@storybook/your-framework';\n  import type { Indexer } from 'storybook/internal/types';\n\n  const urlIndexer: Indexer = {\n    test: /\\.url\\.js$/,\n    createIndex: async (fileName, { makeTitle }) => {\n      const fileData = await import(fileName);\n\n      return Object.entries(fileData)\n        .filter(([key]) => key != 'default')\n        .map(([name, url]) => {\n          return {\n            type: 'docs',\n            importPath: fileName,\n            exportName: name,\n            title: makeTitle(name)\n              .replace(/([a-z])([A-Z])/g, '$1 $2')\n              .trim(),\n            __id: `url--${name}--${encodeURIComponent(url as string)}`,\n            tags: ['!autodocs', 'url']\n          };\n        });\n    }\n  };\n\n  const config: StorybookConfig = {\n    stories: ['../src/**/*.stories.@(js|ts|svelte)', '../src/**/*.url.js'],\n    framework: {\n      name: '@storybook/svelte-vite',\n      options: {},\n    },\n    experimental_indexers: async (existingIndexers) => [urlIndexer, ...existingIndexers]\n  };\n  export default config;\n  ```\n\n  Add a Storybook UI configuration file (i.e., `.storybook/manager.js|ts`) to render the indexed URLs as sidebar links in the UI:\n\n  ```ts title=\".storybook/manager.ts\"\n  import { addons } from 'storybook/manager-api';\n\n  import SidebarLabelWrapper from './components/SidebarLabelWrapper.tsx';\n\n  addons.setConfig({\n      sidebar: {\n        renderLabel: (item) => SidebarLabelWrapper({ item }),\n      },\n  });\n  ```\n\n  This example's code and live demo are available on [StackBlitz](https://stackblitz.com/~/github.com/Sidnioulz/storybook-sidebar-urls).\n\n</details>\n"
  },
  {
    "path": "docs/api/main-config/main-config-log-level.mdx",
    "content": "---\ntitle: 'logLevel'\nsidebar:\n  order: 13\n  title: logLevel\n---\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType: `'debug' | 'error' | 'info' | 'trace' | 'warn'`\n\nDefault: `'info'`\n\nConfigures Storybook's logs in the browser terminal. Useful for debugging.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-log-level.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/api/main-config/main-config-manager-head.mdx",
    "content": "---\ntitle: 'managerHead'\nsidebar:\n  order: 14\n  title: managerHead\n---\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType: `(head: string) => string`\n\nProgrammatically adjust the manager's `<head>` of your Storybook. For example, load a custom font or add a script. Most often used by [addon authors](../../addons/writing-presets.mdx#ui-configuration).\n\n<Callout variant=\"info\" icon=\"💡\">\n\n  If you don't need to programmatically adjust the manager head, you can add scripts and styles to `manager-head.html` instead.\n  \n</Callout>\n\nFor example, you can conditionally add scripts or styles, depending on the environment:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-manager-head.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/api/main-config/main-config-preview-annotations.mdx",
    "content": "---\ntitle: 'previewAnnotations'\nsidebar:\n  order: 15\n  title: previewAnnotations\n---\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType: `string[] | ((config: string[], options: Options) => string[] | Promise<string[]>)`\n\nAdd additional scripts to run in the story preview.\n\n<Callout variant=\"info\" icon=\"💡\">\n  Mostly used by [frameworks](../../contribute/framework.mdx#previewjs-example). Storybook users and [addon authors](../../addons/writing-presets.mdx) should add scripts to [`preview.js`](../../configure/index.mdx#configure-story-rendering) instead.\n</Callout>\n\n```ts\n// @storybook/nextjs framework's src/preset.ts\n\nimport type { StorybookConfig } from './types';\n\nexport const previewAnnotations: StorybookConfig['previewAnnotations'] = (entry = []) => [\n  ...entry,\n  import.meta.resolve('@storybook/nextjs/preview'),\n];\n```\n"
  },
  {
    "path": "docs/api/main-config/main-config-preview-body.mdx",
    "content": "---\ntitle: 'previewBody'\nsidebar:\n  order: 16\n  title: previewBody\n---\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType: `(body: string) => string`\n\nProgrammatically adjust the [preview `<body>`](../../configure/story-rendering.mdx#adding-to-body) of your Storybook. Most often used by [addon authors](../../addons/writing-presets.mdx#ui-configuration).\n\n<Callout variant=\"info\" icon=\"💡\">\n\n  If you don't need to programmatically adjust the preview body, you can add scripts and styles to [`preview-body.html`](../../configure/story-rendering.mdx#adding-to-body) instead.\n  \n</Callout>\n\nFor example, you can conditionally add scripts or styles, depending on the environment:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-preview-body.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/api/main-config/main-config-preview-head.mdx",
    "content": "---\ntitle: 'previewHead'\nsidebar:\n  order: 17\n  title: previewHead\n---\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType: `(head: string) => string`\n\nProgrammatically adjust the [preview `<head>`](../../configure/story-rendering.mdx#adding-to-head) of your Storybook. Most often used by [addon authors](../../addons/writing-presets.mdx#ui-configuration).\n\n<Callout variant=\"info\" icon=\"💡\">\n  If you don't need to programmatically adjust the preview head, you can add scripts and styles to [`preview-head.html`](../../configure/story-rendering.mdx#adding-to-head) instead.\n</Callout>\n\nFor example, you can conditionally add scripts or styles, depending on the environment:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-preview-head.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/api/main-config/main-config-refs.mdx",
    "content": "---\ntitle: 'refs'\nsidebar:\n  order: 18\n  title: refs\n---\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType:\n\n```ts\n{ [key: string]:\n  | { title: string; url: string; expanded?: boolean, sourceUrl?: string }\n  | (config: { title: string; url: string; expanded?: boolean, sourceUrl: string }) => { title: string; url: string; expanded?: boolean, sourceUrl?: string }\n  | { disable: boolean }\n}\n```\n\nConfigures [Storybook composition](../../sharing/storybook-composition.mdx).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-refs.md\" />\n\n{/* prettier-ignore-end */}\n\n## Using a function\n\nYou can use a function to dynamically configure refs:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-refs-with-function.md\" />\n\n{/* prettier-ignore-end */}\n\n## Disable a ref\n\nSome package dependencies automatically [compose their Storybook in yours](../../sharing/package-composition.mdx). You can disable this behavior by setting `disable` to `true` for the package name:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-refs-disable.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/api/main-config/main-config-static-dirs.mdx",
    "content": "---\ntitle: 'staticDirs'\nsidebar:\n  order: 19\n  title: staticDirs\n---\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType: `(string | { from: string; to: string })[]`\n\nSets a list of directories of [static files](../../configure/integration/images-and-assets.mdx#serving-static-files-via-storybook-configuration) to be loaded by Storybook.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-static-dirs.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\nWhen using Vite-based frameworks, additional directories may be copied to your build directory because of Vite's own [static asset handling](https://vite.dev/guide/assets#the-public-directory). You can set Vite's `publicDir` option to `false` to disable this behavior.\n</Callout>\n\n## With configuration objects\n\nYou can also use a configuration object to define the directories:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-static-dirs-with-object.md\" />\n\n{/* prettier-ignore-end */}"
  },
  {
    "path": "docs/api/main-config/main-config-stories.mdx",
    "content": "---\ntitle: 'stories'\nsidebar:\n  order: 3\n  title: stories\n---\n\n(**Required**)\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType:\n\n```ts\n| (string | StoriesSpecifier)[]\n| async (list: (string | StoriesSpecifier)[]) => (string | StoriesSpecifier)[]\n```\n\nConfigures Storybook to load stories from the specified locations. The intention is for you to colocate a story file along with the component it documents:\n\n```\n•\n└── components\n    ├── Button.ts\n    └── Button.stories.ts\n```\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-stories.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  If you want to use a different naming convention, you can alter the glob using the syntax supported by [picomatch](https://github.com/micromatch/picomatch#globbing-features).\n\n  Keep in mind that some addons may assume Storybook's default naming convention.\n</Callout>\n\n## With an array of globs\n\nStorybook will load stories from your project as found by this array of globs (pattern matching strings).\n\nStories are loaded in the order they are defined in the array. This allows you to control the order in which stories are displayed in the sidebar:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-stories-ordered.md\" />\n\n{/* prettier-ignore-end */}\n\n## With a configuration object\n\nAdditionally, you can customize your Storybook configuration to load your stories based on a configuration object. This object is of the type `StoriesSpecifier`, defined below.\n\nFor example, if you wanted to load your stories from a `packages/components` directory, you could adjust your `stories` configuration field into the following:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-stories-with-object.md\" />\n\n{/* prettier-ignore-end */}\n\nWhen Storybook starts, it will look for any file containing the `stories` extension inside the `packages/components` directory and generate the titles for your stories.\n\n### `StoriesSpecifier`\n\nType:\n\n```ts\n{\n  directory: string;\n  files?: string;\n  titlePrefix?: string;\n}\n```\n\n#### `StoriesSpecifier.directory`\n\n(**Required**)\n\nType: `string`\n\nWhere to start looking for story files, relative to the root of your project.\n\n#### `StoriesSpecifier.files`\n\nType: `string`\n\nDefault: `'**/*.@(mdx|stories.@(js|jsx|mjs|ts|tsx))'`\n\nA glob, relative to `StoriesSpecifier.directory` (with no leading `./`), that matches the filenames to load.\n\n#### `StoriesSpecifier.titlePrefix`\n\nType: `string`\n\nDefault: `''`\n\nWhen [auto-titling](../../configure/user-interface/sidebar-and-urls.mdx#csf-30-auto-titles), prefix used when generating the title for your stories.\n\n## With a custom implementation\n\n<Callout variant=\"info\" icon=\"💡\">\n  💡 Storybook now statically analyzes the configuration file to improve performance. Loading stories with a custom implementation may de-optimize or break this ability.\n</Callout>\n\nYou can also adjust your Storybook configuration and implement custom logic to load your stories. For example, suppose you were working on a project that includes a particular pattern that the conventional ways of loading stories could not solve. In that case, you could adjust your configuration as follows:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-stories-with-logic.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/api/main-config/main-config-swc.mdx",
    "content": "---\ntitle: 'swc'\nsidebar:\n  order: 20\n  title: swc\n---\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType: `(config: swc.Options, options: Options) => swc.Options | Promise<swc.Options>`\n\nCustomize Storybook's [SWC](https://swc.rs/) setup for Webpack-based projects enabled via the [`@storybook/addon-webpack5-compiler-swc`](https://storybook.js.org/addons/@storybook/addon-webpack5-compiler-swc) addon based on the supported [frameworks](../../configure/integration/frameworks.mdx), except Angular, Create React App, Ember.js and Next.js.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-swc.md\" />\n\n{/* prettier-ignore-end */}\n\n## `SWC.Options`\n\nThe options provided by [SWC](https://swc.rs/) are only applicable if you've enabled the [`@storybook/addon-webpack5-compiler-swc`](https://storybook.js.org/addons/@storybook/addon-webpack5-compiler-swc) addon.\n\n## Options\n\nType: `{ configType?: 'DEVELOPMENT' | 'PRODUCTION' }`\n\nThere are other options that are difficult to document here. Please introspect the type definition for more information.\n"
  },
  {
    "path": "docs/api/main-config/main-config-tags.mdx",
    "content": "---\ntitle: 'tags'\nsidebar:\n  order: 21\n  title: tags\n---\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType: `{ [tagName: string]: { defaultFilterSelection?: 'include' | 'exclude' } }`\n\nDefine custom [tags](../../writing-stories/tags.mdx) for your stories, or alter the default configuration of built-in tags.\n\n<CodeSnippets path=\"main-config-tags.md\" />\n\n## `[tagName]`\n\nType: `string`\n\nThe name of the tag. This can be any static (i.e. not created dynamically) string, either a built-in tag or a custom tag of your own design.\n\n### `[tagName].defaultFilterSelection`\n\nType: `'include' | 'exclude'`\n\nSet the default filter selection state for a tag in the Storybook sidebar. If set to `include`, stories with this tag are selected as included. If set to `exclude`, stories with this tag are selected as excluded, and must be explicitly included by selecting the tag in the sidebar filter menu. If not set, the tag has no default selection.\n\n![Filtering by tags](../../_assets/writing-stories/tag-filter.png)\n"
  },
  {
    "path": "docs/api/main-config/main-config-typescript.mdx",
    "content": "---\ntitle: 'typescript'\nsidebar:\n  order: 22\n  title: typescript\n---\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType:\n\n<IfRenderer renderer=\"react\">\n  ```ts\n  {\n    check?: boolean;\n    checkOptions?: CheckOptions;\n    reactDocgen?: 'react-docgen' | 'react-docgen-typescript' | false;\n    reactDocgenTypescriptOptions?: ReactDocgenTypescriptOptions;\n    skipCompiler?: boolean;\n  }\n  ```\n</IfRenderer>\n\n<IfRenderer renderer={['angular', 'vue', 'web-components', 'ember', 'html', 'svelte', 'preact', 'qwik','solid' ]}>\n  ```ts\n  {\n    check?: boolean;\n    checkOptions?: CheckOptions;\n    skipCompiler?: boolean;\n  }\n  ```\n</IfRenderer>\n\nConfigures how Storybook handles [TypeScript files](../../configure/integration/typescript.mdx).\n\n## `check`\n\nType: `boolean`\n\nOptionally run [fork-ts-checker-webpack-plugin](https://github.com/TypeStrong/fork-ts-checker-webpack-plugin). Note that because this uses a Webpack plugin, it is only available when using the [Webpack builder](../../builders/webpack.mdx).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-typescript-check.md\" />\n\n{/* prettier-ignore-end */}\n\n## `checkOptions`\n\nType: `CheckOptions`\n\nOptions to pass to `fork-ts-checker-webpack-plugin`, if [enabled](#check). See [docs for available options](https://github.com/TypeStrong/fork-ts-checker-webpack-plugin/blob/v4.1.6/README.md#options).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-typescript-check-options.md\" />\n\n{/* prettier-ignore-end */}\n\n<IfRenderer renderer=\"react\">\n  ## `reactDocgen`\n\n  Type: `'react-docgen' | 'react-docgen-typescript' | false`\n\n  Default:\n\n  * `false`: if `@storybook/react` is not installed\n  * `'react-docgen'`: if `@storybook/react` is installed\n\n  Configures which library, if any, Storybook uses to parse React components, [react-docgen](https://github.com/reactjs/react-docgen) or [react-docgen-typescript](https://github.com/styleguidist/react-docgen-typescript). Set to `false` to disable parsing React components. `react-docgen-typescript` invokes the TypeScript compiler, which makes it slow but generally accurate. `react-docgen` performs its own analysis, which is much faster but incomplete.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"main-config-typescript-react-docgen.md\" />\n\n  {/* prettier-ignore-end */}\n\n  ## `reactDocgenTypescriptOptions`\n\n  Type: `ReactDocgenTypescriptOptions`\n\n  Configures the options to pass to `react-docgen-typescript-plugin` if `react-docgen-typescript` is enabled. See docs for available options [for Webpack projects](https://github.com/hipstersmoothie/react-docgen-typescript-plugin) or [for Vite projects](https://github.com/joshwooding/vite-plugin-react-docgen-typescript).\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"main-config-typescript-react-docgen-typescript-options.md\" />\n\n  {/* prettier-ignore-end */}\n</IfRenderer>\n\n## `skipCompiler`\n\nType: `boolean`\n\nDisable parsing of TypeScript files through the compiler, which is used for Webpack5.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-typescript-skip-compiler.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/api/main-config/main-config-vite-final.mdx",
    "content": "---\ntitle: 'viteFinal'\nsidebar:\n  order: 23\n  title: viteFinal\n---\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType: `(config: Vite.InlineConfig, options: Options) => Vite.InlineConfig | Promise<Vite.InlineConfig>`\n\nCustomize Storybook's Vite setup when using the [Vite builder](../../builders/vite.mdx).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-vite-final.md\" />\n\n{/* prettier-ignore-end */}\n\n## `Options`\n\nType: `{ configType?: 'DEVELOPMENT' | 'PRODUCTION' }`\n\nThere are other options that are difficult to document here. Please introspect the type definition for more information.\n"
  },
  {
    "path": "docs/api/main-config/main-config-webpack-final.mdx",
    "content": "---\ntitle: 'webpackFinal'\nsidebar:\n  order: 24\n  title: webpackFinal\n---\n\nParent: [main.js|ts configuration](./main-config.mdx)\n\nType: `async (config: Config, options: WebpackOptions) => Config`\n\nCustomize Storybook's Webpack setup when using the [webpack builder](../../builders/webpack.mdx).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-webpack-final.md\" />\n\n{/* prettier-ignore-end */}\n\n## `Options`\n\nType: `{ configType?: 'DEVELOPMENT' | 'PRODUCTION' }`\n\nThere are other options that are difficult to document here. Please introspect the type definition for more information.\n"
  },
  {
    "path": "docs/api/main-config/main-config.mdx",
    "content": "---\ntitle: 'Main configuration'\nsidebar:\n  order: 1\n  title: Overview\n---\n\nThe main configuration defines a Storybook project's behavior, including the location of stories, addons to use, feature flags, and other project-specific settings.\n\n\n## The main configuration file: `main.js` or `main.ts`\n\n<Callout variant=\"warning\">\n\nThis file must be valid ESM. In other words, it must use `import` instead of `require`, and neither `__dirname` nor `__filename` are available.\n\n</Callout>\n\nThis configuration is defined in `.storybook/main.js|ts`, which is located relative to the root of your project.\n\nA typical Storybook configuration file looks like this:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-typical.md\" />\n\n{/* prettier-ignore-end */}\n\n## config\n\nAn object to configure Storybook containing the following properties:\n\n* [`framework`](./main-config-framework.mdx) (Required)\n* [`stories`](./main-config-stories.mdx) (Required)\n* [`addons`](./main-config-addons.mdx)\n* [`babel`](./main-config-babel.mdx)\n* [`babelDefault`](./main-config-babel-default.mdx)\n* [`build`](./main-config-build.mdx)\n* [`core`](./main-config-core.mdx)\n* [`docs`](./main-config-docs.mdx)\n* [`env`](./main-config-env.mdx)\n* [`features`](./main-config-features.mdx)\n* [`indexers`](./main-config-indexers.mdx) (⚠️ Experimental)\n* [`logLevel`](./main-config-log-level.mdx)\n* [`managerHead`](./main-config-manager-head.mdx)\n* [`previewAnnotations`](./main-config-preview-annotations.mdx)\n* [`previewBody`](./main-config-preview-body.mdx)\n* [`previewHead`](./main-config-preview-head.mdx)\n* [`refs`](./main-config-refs.mdx)\n* [`staticDirs`](./main-config-static-dirs.mdx)\n* [`swc`](./main-config-swc.mdx)\n* [`tags`](./main-config-tags.mdx)\n* [`typescript`](./main-config-typescript.mdx)\n* [`viteFinal`](./main-config-vite-final.mdx)\n* [`webpackFinal`](./main-config-webpack-final.mdx)\n"
  },
  {
    "path": "docs/api/new-frameworks.mdx",
    "content": "---\ntitle: 'Frameworks'\nsidebar:\n  order: 7\n  title: Frameworks\n---\n\nStorybook is architected to support diverse web frameworks, including React, Vue, Angular, Web Components, Svelte, and over a dozen others. This guide helps you get started on adding new framework support for Storybook.\n\n## Scaffolding a new framework\n\nThe first thing to do is to scaffold your framework support in its own repo.\n\nWe recommend adopting the same project structure as the Storybook monorepo. That structure contains the framework package (`app/<framework>`) and an example app (`examples/<framework>-kitchen-sink`) as well as other associated documentation and configuration as needed.\n\nIt may seem like a little more hierarchy than what’s necessary. But because the structure mirrors the way Storybook’s monorepo is structured, you can reuse Storybook’s tooling. It also makes it easier to move the framework into the Storybook monorepo later if that is desirable.\n\nWe recommend using `@storybook/html` as a starter framework since it’s the simplest and contains no framework-specific peculiarities. There is a boilerplate to get you started [here](https://github.com/CodeByAlex/storybook-framework-boilerplate).\n\n## Framework architecture\n\nSupporting a new framework in Storybook typically consists of two main aspects:\n\n1. Configuring the server. In Storybook, the server is the node process that runs when you run `storybook dev` or `storybook build`. Configuring the server typically means configuring babel and webpack in framework-specific ways.\n\n2. Configuring the client. The client is the code that runs in the browser, and configuring it, means providing a framework-specific story rendering function.\n\n## Configuring the server\n\nStorybook has the concept of [presets](../addons/writing-presets.mdx), which are typically babel/webpack configurations for file loading. If your framework has its own file format (e.g., “.vue”), you might need to transform them into JavaScript files at load time. If you assume every user of your framework needs this, you should add it to the framework. So far, every framework added to Storybook has done it because Storybook’s core configuration is extremely minimal.\n\n### Package structure\n\nIt's helpful to understand Storybook's package structure before adding a framework preset. Each framework typically exposes two executables in its `package.json`:\n\n```json title=\"package.json\"\n{\n  \"bin\": {\n    \"storybook\": \"./bin/index.js\",\n    \"build-storybook\": \"./bin/build.js\"\n  }\n}\n```\n\nThese scripts pass an `options` object to `storybook/internal/server`, a library that abstracts all of Storybook’s framework-independent code.\n\nFor example, here’s the boilerplate to start the dev server with `storybook dev`:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-start-dev-server.md\" />\n\n{/* prettier-ignore-end */}\n\nThus the essence of adding framework presets is just filling in that options object.\n\n### Server options\n\nAs described above, the server `options` object does the heavy lifting of configuring the server.\n\nLet’s look at the `@storybook/vue`’s options definition:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-server-options.md\" />\n\n{/* prettier-ignore-end */}\n\nThe value of the `framework` option (i.e., ‘vue’) is something that gets passed to addons and allows them to do specific tasks related to your framework.\n\nThe essence of this file is the framework presets, and these are standard [Storybook presets](../addons/writing-presets.mdx) -- you can look at framework packages in the Storybook monorepo (e.g. [React](https://github.com/storybookjs/storybook/blob/next/code/frameworks/react-vite/src/preset.ts), [Vue](https://github.com/storybookjs/storybook/blob/next/code/frameworks/vue3-vite/src/preset.ts), [Web Components](https://github.com/storybookjs/storybook/blob/next/code/frameworks/web-components-vite/src/preset.ts)) to see examples of framework-specific customizations.\n\nWhile developing your custom framework, not maintained by Storybook, you can specify the path to the location file with the `frameworkPath` key:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-server-framework-options.md\" />\n\n{/* prettier-ignore-end */}\n\nYou can add a relative path to `frameworkPath`. Don't forget that they resolve from the Storybook configuration directory (i.e., `.storybook`) by default.\n\nMake sure the `frameworkPath` ends up at the `dist/client/index.js` file within your framework app.\n\n## Configuring the client\n\nTo configure the client, you must provide a framework-specific render function. Before diving into the details, it’s essential to understand how user-written stories relate to what renders on the screen.\n\n### Renderable objects\n\nStorybook stories are ES6 objects that return a “renderable object.”\n\nConsider the following React story:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-with-sample.md\" />\n\n{/* prettier-ignore-end */}\n\nIn this case, the renderable object is the React element, `<Button .../>`.\n\nIn most other frameworks, the renderable object is actually a plain JavaScript object.\n\nConsider the following hypothetical example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-hypothetical-example.md\" />\n\n{/* prettier-ignore-end */}\n\nThe design of this “renderable object” is framework-specific and should ideally match the idioms of that framework.\n\n### Render function\n\nThe framework's render function is the entity responsible for converting the renderable object into DOM nodes. It is typically of the form:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-framework-render-function.md\" />\n\n{/* prettier-ignore-end */}\n\n### Package structure\n\nOn the client side, the key file is [`src/client/preview.js`](../configure/index.mdx#configure-story-rendering):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-client-preview.md\" />\n\n{/* prettier-ignore-end */}\n\nThe globals file typically sets up a single global variable that client-side code (such as addon-provided decorators) can refer to if needed to understand which framework it's running in:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-client-globals-example-file.md\" />\n\n{/* prettier-ignore-end */}\n\nThe `start` function abstracts all of Storybook’s framework-independent client-side (browser) code, and it takes the render function we defined above. For examples of render functions, see [React](https://github.com/storybookjs/storybook/blob/next/code/renderers/react/src/render.tsx), [Vue](https://github.com/storybookjs/storybook/blob/next/code/renderers/vue3/src/render.ts), [Angular](https://github.com/storybookjs/storybook/blob/next/code/frameworks/angular/src/client/render.ts), and [Web Components](https://github.com/storybookjs/storybook/blob/next/code/renderers/web-components/src/render.ts) in the Storybook monorepo.\n"
  },
  {
    "path": "docs/api/parameters.mdx",
    "content": "---\ntitle: 'Parameters'\nsidebar:\n  order: 4\n  title: Parameters\n---\n\nParameters are static metadata used to configure your [stories](../get-started/whats-a-story.mdx) and [addons](../addons/index.mdx) in Storybook. They are specified at the story, meta (component), project (global) levels.\n\n## Story parameters\n\nParameters specified at the story level apply to that story only. They are defined in the `parameters` property of the story (named export):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"parameters-in-story.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  Parameters specified at the story level will [override](#parameter-inheritance) those specified at the project level and meta (component) level.\n</Callout>\n\n## Meta parameters\n\nParameter's specified in a [CSF](../writing-stories/index.mdx#component-story-format-csf) file's meta configuration apply to all stories in that file. They are defined in the `parameters` property of the meta (or default export):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"parameters-in-meta.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  Parameters specified at the meta (component) level will [override](#parameter-inheritance) those specified at the project level.\n</Callout>\n\n## Project parameters\n\nParameters specified at the project (global) level apply to **all stories** in your Storybook. They are defined in the `parameters` property of the meta (or default export) in your `.storybook/preview.js|ts` file:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"parameters-in-preview.md\" />\n\n{/* prettier-ignore-end */}\n\n## Available parameters\n\nStorybook only accepts a few parameters directly.\n\n### `layout`\n\nType: `'centered' | 'fullscreen' | 'padded'`\n\nDefault: `'padded'`\n\nSpecifies how the canvas should [lay out the story](../configure/story-layout.mdx).\n\n* **centered**: Center the story within the canvas\n* **padded**: (default) Add padding to the story\n* **fullscreen**: Show the story as-is, without padding\n\n### `options`\n\nType:\n\n```ts\n{\n  storySort?: StorySortConfig | StorySortFn;\n}\n```\n\n<Callout variant=\"warning\">\n  The `options` parameter can *only* be applied at the [project level](#project-parameters).\n</Callout>\n\n#### `options.storySort`\n\nType: `StorySortConfig | StorySortFn`\n\n```ts\ntype StorySortConfig = {\n  includeNames?: boolean;\n  locales?: string;\n  method?: 'alphabetical' | 'alphabetical-by-kind' | 'custom';\n  order?: string[];\n};\n\ntype Story = {\n  id: string;\n  importPath: string;\n  name: string;\n  title: string;\n};\n\ntype StorySortFn = (a: Story, b: Story) => number;\n```\n\nSpecifies the order in which stories are displayed in the Storybook UI.\n\nWhen specifying a configuration object, the following options are available:\n\n* **includeNames**: Whether to include the story name in the sorting algorithm. Defaults to `false`.\n* **locales**: The locale to use when sorting stories. Defaults to your system locale.\n* **method**: The sorting method to use. Defaults to `alphabetical`.\n  * **alphabetical**: Sort stories alphabetically by name.\n  * **alphabetical-by-kind**: Sort stories alphabetically by kind, then by name.\n  * **custom**: Use a custom sorting function.\n* **order**: Stories in the specified order will be displayed first, in the order specified. All other stories will be displayed after, in alphabetical order. The order array can accept a nested array to sort 2nd-level story kinds, e.g. `['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components']`.\n\nWhen specifying a custom sorting function, the function behaves like a typical JavaScript sorting function. It accepts two stories to compare and returns a number. For example:\n\n```js\n(a, b) => (a.id === b.id ? 0 : a.id.localeCompare(b.id, undefined, { numeric: true }));\n```\n\nSee [the guide](../writing-stories/naming-components-and-hierarchy.mdx#sorting-stories) for usage examples.\n\n### `test`\n\nType:\n\n```ts\n{\n  clearMocks?: boolean;\n  mockReset?: boolean;\n  restoreMocks?: boolean;\n  dangerouslyIgnoreUnhandledErrors?: boolean;\n}\n```\n\n#### `clearMocks`\n\nType: `boolean`\n\nDefault: `false`\n\n[Similar to Vitest](https://vitest.dev/config/#clearmocks), it will call `.mockClear()` on all spies created with `fn()` from `storybook/test` when a story unmounts. This will clear mock history, but not reset its implementation to the default one.\n\n#### `mockReset`\n\nType: `boolean`\n\nDefault: `false`\n\n[Similar to Vitest](https://vitest.dev/config/#mockreset), it will call `.mockReset()` on all spies created with `fn()` from `storybook/test` when a story unmounts. This will clear mock history and reset its implementation to an empty function (will return `undefined`).\n\n#### `restoreMocks`\n\nType: `boolean`\n\nDefault: `true`\n\n[Similar to Vitest](https://vitest.dev/config/#restoremocks), it will call `.restoreMocks()` on all spies created with `fn()` from `storybook/test` when a story unmounts. This will clear mock history and reset its implementation to the original one.\n\n#### `dangerouslyIgnoreUnhandledErrors`\n\nType: `boolean`\n\nDefault: `false`\n\nUnhandled errors might cause false positive assertions. Setting this to `true` will prevent the [play function](../writing-stories/play-function.mdx) from failing and showing a warning when unhandled errors are thrown during execution.\n\n***\n\n### Essentials\n\nAll other parameters are contributed by features. The [essential feature's](../essentials/index.mdx) parameters are documented on their individual pages:\n\n* [Actions](../essentials/actions.mdx#parameters)\n* [Backgrounds](../essentials/backgrounds.mdx#parameters)\n* [Controls](../essentials/controls.mdx#parameters)\n* [Highlight](../essentials/highlight.mdx#parameters)\n* [Measure & Outline](../essentials/measure-and-outline.mdx#parameters)\n* [Viewport](../essentials/viewport.mdx#parameters)\n\n## Parameter inheritance\n\nNo matter where they're specified, parameters are ultimately applied to a single story. Parameters specified at the project (global) level are applied to every story in that project. Those specified at the meta (component) level are applied to every story associated with that meta. And parameters specified for a story only apply to that story.\n\nWhen specifying parameters, they are merged together in order of increasing specificity:\n\n1. Project (global) parameters\n2. Meta (component) parameters\n3. Story parameters\n\n<Callout variant=\"info\">\n  Parameters are **merged**, so objects are deep-merged, but arrays and other properties are overwritten.\n</Callout>\n\nIn other words, the following specifications of parameters:\n\n```js title=\".storybook/preview.js|ts\"\nconst preview = {\n  // 👇 Project-level parameters\n  parameters: {\n    layout: 'centered',\n    demo: {\n      demoProperty: 'a',\n      demoArray: [1, 2],\n    },\n  },\n  // ...\n};\nexport default preview;\n```\n\n```js title=\"Dialog.stories.js|ts\"\nconst meta = {\n  component: Dialog,\n  // 👇 Meta-level parameters\n  parameters: {\n    layout: 'fullscreen',\n    demo: {\n      demoProperty: 'b',\n      anotherDemoProperty: 'b',\n    },\n  },\n};\nexport default meta;\n\n// (no additional parameters specified)\nexport const Basic = {};\n\nexport const LargeScreen = {\n  // 👇 Story-level parameters\n  parameters: {\n    layout: 'padded',\n    demo: {\n      demoArray: [3, 4],\n    },\n  },\n};\n```\n\nWill result in the following parameter values applied to each story:\n\n```js\n// Applied story parameters\n\n// For the Basic story:\n{\n  layout: 'fullscreen',\n  demo: {\n    demoProperty: 'b',\n    anotherDemoProperty: 'b',\n    demoArray: [1, 2],\n  },\n}\n\n// For the LargeScreen story:\n{\n  layout: 'padded',\n  demo: {\n    demoProperty: 'b',\n    anotherDemoProperty: 'b',\n    demoArray: [3, 4],\n  },\n}\n```\n"
  },
  {
    "path": "docs/api/portable-stories/index.mdx",
    "content": "---\ntitle: Portable Stories\nsidebar:\n  order: 6\n  title: Portable Stories\n---"
  },
  {
    "path": "docs/api/portable-stories/portable-stories-jest.mdx",
    "content": "---\ntitle: 'Portable stories in Jest'\nsidebar:\n  title: Jest\n  order: 2\n---\n\n<If notRenderer={['react', 'vue']}>\n  <Callout variant=\"info\">\n    Portable stories in Jest are currently only supported in [React](?renderer=react) and [Vue](?renderer=vue) projects.\n  </Callout>\n\n  {/* End non-supported renderers */}\n</If>\n\n<If renderer=\"react\">\n  <Callout variant=\"info\" icon=\"💡\">\n    If you are using the [experimental CSF Factories format](../../api/csf/csf-next.mdx), you don't need to use the portable stories API. Instead, you can [import and use your stories directly](../../api/csf/csf-next.mdx#manual).\n  </Callout>\n</If>\n\n<If renderer={['react', 'vue']}>\n  Portable stories are Storybook [stories](../../writing-stories/index.mdx) which can be used in external environments, such as [Jest](https://jestjs.io).\n\n  Normally, Storybook composes a story and its [annotations](#annotations) automatically, as part of the [story pipeline](#story-pipeline). When using stories in Jest tests, you must handle the story pipeline yourself, which is what the [`composeStories`](#composestories) and [`composeStory`](#composestory) functions enable.\n\n  <Callout variant=\"info\">\n    The API specified here is available in Storybook `8.2.7` and up. If you're using an older version of Storybook, you can upgrade to the latest version (`npx storybook@latest upgrade`) to use this API. If you're unable to upgrade, you can use previous API, which uses the `.play()` method instead of `.run()`, but is otherwise identical.\n  </Callout>\n\n  <If renderer=\"react\">\n    <Callout variant=\"info\">\n      **Using `Next.js`?** You need to do three things differently when using portable stories in Jest with Next.js projects:\n\n      * Configure the [`next/jest.js` transformer](https://nextjs.org/docs/pages/building-your-application/testing/jest#manual-setup), which will handle all of the necessary Next.js configuration for you.\n      * Import [`composeStories`](#composestories) or [`composeStory`](#composestory) from the `@storybook/nextjs` package (e.g. `import { composeStories } from '@storybook/nextjs'`).\n      * Set up [internal module aliases](../../get-started/frameworks/nextjs.mdx#storybooknextjsexport-mocks) to ensure the framework configuration works correctly and to be able to mock and assert on them.\n    </Callout>\n  </If>\n\n  ## composeStories\n\n  `composeStories` will process the component's stories you specify, compose each of them with the necessary [annotations](#annotations), and return an object containing the composed stories.\n\n  By default, the composed story will render the component with the [args](../../writing-stories/args.mdx) that are defined in the story. You can also pass any props to the component in your test and those props will override the values passed in the story's args.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"portable-stories-jest-compose-stories.md\" />\n\n  {/* prettier-ignore-end */}\n\n  ### Type\n\n  {/* prettier-ignore-start */}\n\n  ```ts\n  (\n    csfExports: CSF file exports,\n    projectAnnotations?: ProjectAnnotations\n  ) => Record<string, ComposedStoryFn>\n  ```\n\n  {/* prettier-ignore-end */}\n\n  ### Parameters\n\n  #### `csfExports`\n\n  (**Required**)\n\n  Type: CSF file exports\n\n  Specifies which component's stories you want to compose. Pass the **full set of exports** from the CSF file (not the default export!). E.g. `import * as stories from './Button.stories'`\n\n  #### `projectAnnotations`\n\n  Type: `ProjectAnnotation | ProjectAnnotation[]`\n\n  Specifies the project annotations to be applied to the composed stories.\n\n  This parameter is provided for convenience. You should likely use [`setProjectAnnotations`](#setprojectannotations) instead. Details about the `ProjectAnnotation` type can be found in that function's [`projectAnnotations`](#projectannotations-2) parameter.\n\n  This parameter can be used to [override](#overriding-globals) the project annotations applied via `setProjectAnnotations`.\n\n  ### Return\n\n  Type: `Record<string, ComposedStoryFn>`\n\n  An object where the keys are the names of the stories and the values are the composed stories.\n\n  Additionally, the composed story will have the following properties:\n\n  | Property   | Type                                      | Description                                                                           |\n  | ---------- | ----------------------------------------- | ------------------------------------------------------------------------------------- |\n  | args       | `Record<string, any>`                     | The story's [args](../../writing-stories/args.mdx)                                    |\n  | argTypes   | `ArgType`                                 | The story's [argTypes](../arg-types.mdx)                                              |\n  | id         | `string`                                  | The story's id                                                                        |\n  | parameters | `Record<string, any>`                     | The story's [parameters](../parameters.mdx)                                           |\n  | play       | `(context) => Promise<void> \\| undefined` | Executes the play function of a given story                                |\n  | run        | `(context) => Promise<void> \\| undefined` | [Mounts and executes the play function](#3-run) of a given story                     |\n  | storyName  | `string`                                  | The story's name                                                                      |\n  | tags       | `string[]`                                | The story's [tags](../../writing-stories/tags.mdx)                                    |\n\n  ## composeStory\n\n  You can use `composeStory` if you wish to compose a single story for a component.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"portable-stories-jest-compose-story.md\" />\n\n  {/* prettier-ignore-end */}\n\n  ### Type\n\n  {/* prettier-ignore-start */}\n\n  ```ts\n  (\n    story: Story export,\n    componentAnnotations: Meta,\n    projectAnnotations?: ProjectAnnotations,\n    exportsName?: string\n  ) => ComposedStoryFn\n  ```\n\n  {/* prettier-ignore-end */}\n\n  ### Parameters\n\n  #### `story`\n\n  (**Required**)\n\n  Type: `Story export`\n\n  Specifies which story you want to compose.\n\n  #### `componentAnnotations`\n\n  (**Required**)\n\n  Type: `Meta`\n\n  The default export from the stories file containing the [`story`](#story).\n\n  #### `projectAnnotations`\n\n  Type: `ProjectAnnotation | ProjectAnnotation[]`\n\n  Specifies the project annotations to be applied to the composed story.\n\n  This parameter is provided for convenience. You should likely use [`setProjectAnnotations`](#setprojectannotations) instead. Details about the `ProjectAnnotation` type can be found in that function's [`projectAnnotations`](#projectannotations-2) parameter.\n\n  This parameter can be used to [override](#overriding-globals) the project annotations applied via `setProjectAnnotations`.\n\n  #### `exportsName`\n\n  Type: `string`\n\n  You probably don't need this. Because `composeStory` accepts a single story, it does not have access to the name of that story's export in the file (like `composeStories` does). If you must ensure unique story names in your tests and you cannot use `composeStories`, you can pass the name of the story's export here.\n\n  ### Return\n\n  Type: `ComposedStoryFn`\n\n  A single [composed story](#return).\n\n  ## setProjectAnnotations\n\n  This API should be called once, before the tests run, typically in a [setup file](https://jestjs.io/docs/configuration#setupfiles-array). This will make sure that whenever `composeStories` or `composeStory` are called, the project annotations are taken into account as well.\n\n  These are the configurations needed in the setup file:\n  - preview annotations: those defined in `.storybook/preview.ts`\n  - addon annotations (optional): those exported by addons\n  - beforeAll: code that runs before all tests ([more info](../../writing-tests/interaction-testing.mdx#beforeall))\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"portable-stories-jest-set-project-annotations.md\" />\n\n  {/* prettier-ignore-end */}\n\n  Sometimes a story can require an addon's [decorator](../../writing-stories/decorators.mdx) or [loader](../../writing-stories/loaders.mdx) to render properly. For example, an addon can apply a decorator that wraps your story in the necessary router context. In this case, you must include that addon's `preview` export in the project annotations set. See `addonAnnotations` in the example above.\n\n  Note: If the addon doesn't automatically apply the decorator or loader itself, but instead exports them for you to apply manually in `.storybook/preview.js|ts` (e.g. using `withThemeFromJSXProvider` from [@storybook/addon-themes](https://github.com/storybookjs/storybook/blob/next/code/addons/themes/docs/api.md#withthemefromjsxprovider)), then you do not need to do anything else. They are already included in the `previewAnnotations` in the example above.\n\n  If you need to configure Testing Library's `render` or use a different render function, please let us know in [this discussion](https://github.com/storybookjs/storybook/discussions/28532) so we can learn more about your needs.\n\n  ### Type\n\n  ```ts\n  (projectAnnotations: ProjectAnnotation | ProjectAnnotation[]) => ProjectAnnotation\n  ```\n\n  ### Parameters\n\n  #### `projectAnnotations`\n\n  (**Required**)\n\n  Type: `ProjectAnnotation | ProjectAnnotation[]`\n\n  A set of project [annotations](#annotations) (those defined in `.storybook/preview.js|ts`) or an array of sets of project annotations, which will be applied to all composed stories.\n\n  ## Annotations\n\n  Annotations are the metadata applied to a story, like [args](../../writing-stories/args.mdx), [decorators](../../writing-stories/decorators.mdx), [loaders](../../writing-stories/loaders.mdx), and [play functions](../../writing-stories/play-function.mdx). They can be defined for a specific story, all stories for a component, or all stories in the project.\n\n  ## Story pipeline\n\n  To preview your stories in Storybook, Storybook runs a story pipeline, which includes applying project annotations, loading data, rendering the story, and playing interactions. This is a simplified version of the pipeline:\n\n  ![A flow diagram of the story pipeline. First, set project annotations. Collect annotations (decorators, args, etc) which are exported by addons and the preview file. Second, compose story. Create renderable elements based on the stories passed onto the API. Third, run. Mount the component and execute all the story lifecycle hooks, including the play function.](../../_assets/api/story-pipeline.png)\n\n  When you want to reuse a story in a different environment, however, it's crucial to understand that all these steps make a story. The portable stories API provides you with the mechanism to recreate that story pipeline in your external environment:\n\n  ### 1. Apply project-level annotations\n\n  [Annotations](#annotations) come from the story itself, that story's component, and the project. The project-level annotations are those defined in your `.storybook/preview.js` file and by addons you're using. In portable stories, these annotations are not applied automatically — you must apply them yourself.\n\n  👉 For this, you use the [`setProjectAnnotations`](#setprojectannotations) API.\n\n  ### 2. Compose\n\n  The story is prepared by running [`composeStories`](#composestories) or [`composeStory`](#composestory). The outcome is a renderable component that represents the render function of the story.\n\n  ### 3. Run\n\n  Finally, stories can prepare data they need (e.g. setting up some mocks or fetching data) before rendering by defining [loaders](../../writing-stories/loaders.mdx), [beforeEach](../../writing-tests/interaction-testing.mdx#run-code-before-each-story) or by having all the story code in the play function when using the [mount](../../writing-tests/interaction-testing.mdx#run-code-before-the-component-gets-rendered). In portable stories, all of these steps will be executed when you call the `run` method of the composed story.\n\n  👉 For this, you use the [`composeStories`](#composestories) or [`composeStory`](#composestory) API. The composed story will return a `run` method to be called.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"portable-stories-jest-with-play-function.md\" />\n\n  {/* prettier-ignore-end */}\n\n  <Callout variant=\"info\">\n    If your play function contains assertions (e.g. `expect` calls), your test will fail when those assertions fail.\n  </Callout>\n\n  ## Overriding globals\n\n  If your stories behave differently based on [globals](../../essentials/toolbars-and-globals.mdx#globals) (e.g. rendering text in English or Spanish), you can define those global values in portable stories by overriding project annotations when composing a story:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"portable-stories-jest-override-globals.md\" />\n\n  {/* prettier-ignore-end */}\n\n  {/* End supported renderers */}\n</If>\n"
  },
  {
    "path": "docs/api/portable-stories/portable-stories-playwright.mdx",
    "content": "---\ntitle: 'Portable stories in Playwright CT'\nsidebar:\n  title: Playwright\n  order: 3\n---\n\n(⚠️ **Experimental**)\n\n<If notRenderer={['react', 'vue']}>\n  <Callout variant=\"info\">\n    Portable stories are currently only supported in [React](?renderer=react) and [Vue](?renderer=vue) projects.\n  </Callout>\n\n  {/* End non-supported renderers */}\n</If>\n\n<If renderer={['react', 'vue']}>\n  <Callout variant=\"info\">\n    The portable stories API for Playwright CT is experimental. Playwright CT itself is also experimental. Breaking changes might occur in either library in upcoming releases.\n  </Callout>\n\n  Portable stories are Storybook [stories](../../writing-stories/index.mdx) which can be used in external environments, such as [Playwright Component Tests (CT)](https://playwright.dev/docs/test-components).\n\n  Normally, Storybook composes a story and its [annotations](#annotations) automatically, as part of the [story pipeline](#story-pipeline). When using stories in Playwright CT, you can use the [`createTest`](#createtest) function, which extends Playwright's test functionality to add a custom `mount` mechanism, to take care of the story pipeline for you.\n\n  <If renderer=\"react\">\n    <Callout variant=\"warning\">\n      Your project must be using React 18+ to use the portable stories API with Playwright CT.\n\n      **Using `Next.js`?** The portable stories API is not yet supported in Next.js with Playwright CT.\n    </Callout>\n  </If>\n\n  <If renderer=\"vue\">\n    <Callout variant=\"info\">\n      If your stories use template-based Vue components, you may need to [alias the `vue` module](https://vuejs.org/guide/scaling-up/tooling#note-on-in-browser-template-compilation) to resolve correctly in the Playwright CT environment. You can do this via the [`ctViteConfig` property](https://playwright.dev/docs/test-components#i-have-a-project-that-already-uses-vite-can-i-reuse-the-config):\n\n      <details>\n        <summary>Example Playwright configuration</summary>\n\n        ```ts\n        // playwright-config.ts\n        import { defineConfig } from '@playwright/experimental-ct-vue';\n\n        export default defineConfig({\n          ctViteConfig: {\n            resolve: {\n              alias: {\n                vue: 'vue/dist/vue.esm-bundler.js',\n              },\n            },\n          },\n        });\n        ```\n      </details>\n    </Callout>\n  </If>\n\n  ## createTest\n\n  (⚠️ **Experimental**)\n\n  Instead of using Playwright's own `test` function, you can use Storybook's special `createTest` function to [extend Playwright's base fixture](https://playwright.dev/docs/test-fixtures#creating-a-fixture) and override the `mount` function to load, render, and play the story. This function is experimental and is subject to changes.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"portable-stories-playwright-ct.md\" />\n\n  {/* prettier-ignore-end */}\n\n  <Callout icon=\"ℹ️\">\n    The code which you write in your Playwright test file is transformed and orchestrated by Playwright, where part of the code executes in Node, while other parts execute in the browser.\n\n    Because of this, you have to compose the stories *in a separate file than your own test file*:\n\n    ```ts title=\"Button.stories.portable.ts\"\n    // Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.\n    import { composeStories } from '@storybook/your-framework';\n\n    import * as stories from './Button.stories';\n\n    // This function will be executed in the browser\n    // and compose all stories, exporting them in a single object\n    export default composeStories(stories);\n    ```\n\n    You can then import the composed stories in your Playwright test file, as in the example above.\n  </Callout>\n\n  ### Type\n\n  ```ts\n  createTest(\n    baseTest: PlaywrightFixture\n  ) => PlaywrightFixture\n  ```\n\n  ### Parameters\n\n  #### `baseTest`\n\n  (**Required**)\n\n  Type: `PlaywrightFixture`\n\n  The base test function to use, e.g. `test` from Playwright.\n\n  ### Return\n\n  Type: `PlaywrightFixture`\n\n  A Storybook-specific test function with the custom `mount` mechanism.\n\n  ## setProjectAnnotations\n\n  This API should be called once, before the tests run, in [`playwright/index.ts`](https://playwright.dev/docs/test-components#step-1-install-playwright-test-for-components-for-your-respective-framework). This will make sure that when `mount` is called, the project annotations are taken into account as well.\n\n  These are the configurations needed in the setup file:\n  - preview annotations: those defined in `.storybook/preview.ts`\n  - addon annotations (optional): those exported by addons\n  - beforeAll: code that runs before all tests ([more info](../../writing-tests/interaction-testing.mdx#beforeall))\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"portable-stories-playwright-ct-compose-stories.md\" />\n\n  {/* prettier-ignore-end */}\n\n  Sometimes a story can require an addon's [decorator](../../writing-stories/decorators.mdx) or [loader](../../writing-stories/loaders.mdx) to render properly. For example, an addon can apply a decorator that wraps your story in the necessary router context. In this case, you must include that addon's `preview` export in the project annotations set. See `addonAnnotations` in the example above.\n\n  Note: If the addon doesn't automatically apply the decorator or loader itself, but instead exports them for you to apply manually in `.storybook/preview.js|ts` (e.g. using `withThemeFromJSXProvider` from [@storybook/addon-themes](https://github.com/storybookjs/storybook/blob/next/code/addons/themes/docs/api.md#withthemefromjsxprovider)), then you do not need to do anything else. They are already included in the `previewAnnotations` in the example above.\n\n  ### Type\n\n  ```ts\n  (projectAnnotations: ProjectAnnotation | ProjectAnnotation[]) => ProjectAnnotation\n  ```\n\n  ### Parameters\n\n  #### `projectAnnotations`\n\n  (**Required**)\n\n  Type: `ProjectAnnotation | ProjectAnnotation[]`\n\n  A set of project [annotations](#annotations) (those defined in `.storybook/preview.js|ts`) or an array of sets of project annotations, which will be applied to all composed stories.\n\n  ## Annotations\n\n  Annotations are the metadata applied to a story, like [args](../../writing-stories/args.mdx), [decorators](../../writing-stories/decorators.mdx), [loaders](../../writing-stories/loaders.mdx), and [play functions](../../writing-stories/play-function.mdx). They can be defined for a specific story, all stories for a component, or all stories in the project.\n\n  <Callout variant=\"info\">\n    [Read more about Playwright's component testing](https://playwright.dev/docs/test-components#test-stories).\n  </Callout>\n\n  ## Story pipeline\n\n  To preview your stories, Storybook runs a story pipeline, which includes applying project annotations, loading data, rendering the story, and playing interactions. This is a simplified version of the pipeline:\n\n  ![A flow diagram of the story pipeline. First, set project annotations. Collect annotations (decorators, args, etc) which are exported by addons and the preview file. Second, compose story. Create renderable elements based on the stories passed onto the API. Third, render story. Load, mount, and execute the play function as part of the portable stories API.](../../_assets/api/story-pipeline-playwright.png)\n\n  When you want to reuse a story in a different environment, however, it's crucial to understand that all these steps make a story. The portable stories API provides you with the mechanism to recreate that story pipeline in your external environment:\n\n  ### 1. Apply project-level annotations\n\n  [Annotations](#annotations) come from the story itself, that story's component, and the project. The project-level annotations are those defined in your `.storybook/preview.js` file and by addons you're using. In portable stories, these annotations are not applied automatically — you must apply them yourself.\n\n  👉 For this, you use the [`setProjectAnnotations`](#setprojectannotations) API.\n\n  ### 2. Prepare, load, render, and play\n\n  The story pipeline includes preparing the story, [loading data](../../writing-stories/loaders.mdx), rendering the story, and [playing interactions](../../writing-tests/interaction-testing.mdx#debugging-interaction-tests). In portable stories within Playwright CT, the `mount` function takes care of these steps for you.\n\n  👉 For this, you use the [`createTest`](#createtest) API.\n\n  <Callout variant=\"info\">\n    If your play function contains assertions (e.g. `expect` calls), your test will fail when those assertions fail.\n  </Callout>\n\n  ## Overriding globals\n\n  If your stories behave differently based on [globals](../../essentials/toolbars-and-globals.mdx#globals) (e.g. rendering text in English or Spanish), you can define those global values in portable stories by overriding project annotations when composing a story:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"portable-stories-playwright-ct-override-globals.md\" />\n\n  You can then use those composed stories in your Playwright test file using the [`createTest`](#createtest) function.\n\n  {/* prettier-ignore-end */}\n\n  {/* End supported renderers */}\n</If>\n"
  },
  {
    "path": "docs/api/portable-stories/portable-stories-vitest.mdx",
    "content": "---\ntitle: 'Portable stories in Vitest'\nsidebar:\n  title: Vitest\n  order: 1\n  hidden: true\n---\n\n<If notRenderer={['react', 'vue', 'svelte']}>\n  <Callout variant=\"info\">\n    Portable stories in Vitest are currently only supported in [React](?renderer=react), [Vue](?renderer=vue) and [Svelte](?renderer=svelte) projects.\n  </Callout>\n\n  {/* End non-supported renderers */}\n</If>\n\n<If renderer=\"svelte\">\n  (⚠️ **Experimental**)\n\n    <Callout variant=\"info\">\n\n    This feature is not supported with the Svelte CSF. To opt-in to this feature with Svelte, you must use Storybook's [Component Story Format](../csf/index.mdx).\n\n  </Callout>\n\n</If>\n\n<If renderer={['react', 'vue', 'svelte']}>\n  <Callout variant=\"warning\">\n    Storybook now recommends testing your stories in Vitest with the [Vitest addon](../../writing-tests/integrations/vitest-addon/index.mdx), which automatically transforms stories into real Vitest tests (using this API under the hood).\n    \n    This API is still available for those who prefer to use portable stories directly, but we recommend using the Vitest addon for a more streamlined testing experience.\n  </Callout>\n\n  Portable stories are Storybook [stories](../../writing-stories/index.mdx) which can be used in external environments, such as [Vitest](https://vitest.dev).\n\n  Normally, Storybook composes a story and its [annotations](#annotations) automatically, as part of the [story pipeline](#story-pipeline). When using stories in Vitest tests, you must handle the story pipeline yourself, which is what the [`composeStories`](#composestories) and [`composeStory`](#composestory) functions enable.\n\n  <If renderer=\"react\">\n    <Callout variant=\"warning\">\n      **Using `Next.js`?** You can test your Next.js stories with Vitest by installing and setting up the `@storybook/nextjs-vite` which re-exports [vite-plugin-storybook-nextjs](https://github.com/storybookjs/vite-plugin-storybook-nextjs) package.\n    </Callout>\n  </If>\n\n  ## composeStories\n\n  `composeStories` will process the component's stories you specify, compose each of them with the necessary [annotations](#annotations), and return an object containing the composed stories.\n\n  <If notRenderer=\"svelte\">\n    By default, the composed story will render the component with the [args](../../writing-stories/args.mdx) that are defined in the story. You can also pass any props to the component in your test and those props will override the values passed in the story's args.\n  </If>\n\n  <If renderer=\"svelte\">\n    By default, the composed story will render the component with the [args](../../writing-stories/args.mdx) that are defined in the story. If you need to override props for an individual story, you can use the [`composeStory`](#composestory) function to do so.\n  </If>\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"portable-stories-vitest-compose-stories.md\" />\n\n  {/* prettier-ignore-end */}\n\n  ### Type\n\n  {/* prettier-ignore-start */}\n\n  ```ts\n  (\n    csfExports: CSF file exports,\n    projectAnnotations?: ProjectAnnotations\n  ) => Record<string, ComposedStoryFn>\n  ```\n\n  {/* prettier-ignore-end */}\n\n  ### Parameters\n\n  #### `csfExports`\n\n  (**Required**)\n\n  Type: CSF file exports\n\n  Specifies which component's stories you want to compose. Pass the **full set of exports** from the CSF file (not the default export!). E.g. `import * as stories from './Button.stories'`\n\n  #### `projectAnnotations`\n\n  Type: `ProjectAnnotation | ProjectAnnotation[]`\n\n  Specifies the project annotations to be applied to the composed stories.\n\n  This parameter is provided for convenience. You should likely use [`setProjectAnnotations`](#setprojectannotations) instead. Details about the `ProjectAnnotation` type can be found in that function's [`projectAnnotations`](#projectannotations-2) parameter.\n\n  This parameter can be used to [override](#overriding-globals) the project annotations applied via `setProjectAnnotations`.\n\n  ### Return\n\n  Type: `Record<string, ComposedStoryFn>`\n\n  An object where the keys are the names of the stories and the values are the composed stories.\n\n  Additionally, the composed story will have the following properties:\n\n  | Property   | Type                                      | Description                                                                           |\n  | ---------- | ----------------------------------------- | ------------------------------------------------------------------------------------- |\n  | args       | `Record<string, any>`                     | The story's [args](../../writing-stories/args.mdx)                                    |\n  | argTypes   | `ArgType`                                 | The story's [argTypes](../arg-types.mdx)                                              |\n  | id         | `string`                                  | The story's id                                                                        |\n  | parameters | `Record<string, any>`                     | The story's [parameters](../parameters.mdx)                                           |\n  | play       | `(context) => Promise<void> \\| undefined` | Executes the play function of a given story                                |\n  | run        | `(context) => Promise<void> \\| undefined` | [Mounts and executes the play function](#3-run) of a given story                     |\n  | storyName  | `string`                                  | The story's name                                                                      |\n  | tags       | `string[]`                                | The story's [tags](../../writing-stories/tags.mdx)                                    |\n\n  ## composeStory\n\n  You can use `composeStory` if you wish to compose a single story for a component.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"portable-stories-vitest-compose-story.md\" />\n\n  {/* prettier-ignore-end */}\n\n  ### Type\n\n  {/* prettier-ignore-start */}\n\n  ```ts\n  (\n    story: Story export,\n    componentAnnotations: Meta,\n    projectAnnotations?: ProjectAnnotations,\n    exportsName?: string\n  ) => ComposedStoryFn\n  ```\n\n  {/* prettier-ignore-end */}\n\n  ### Parameters\n\n  #### `story`\n\n  (**Required**)\n\n  Type: `Story export`\n\n  Specifies which story you want to compose.\n\n  #### `componentAnnotations`\n\n  (**Required**)\n\n  Type: `Meta`\n\n  The default export from the stories file containing the [`story`](#story).\n\n  #### `projectAnnotations`\n\n  Type: `ProjectAnnotation | ProjectAnnotation[]`\n\n  Specifies the project annotations to be applied to the composed story.\n\n  This parameter is provided for convenience. You should likely use [`setProjectAnnotations`](#setprojectannotations) instead. Details about the `ProjectAnnotation` type can be found in that function's [`projectAnnotations`](#projectannotations-2) parameter.\n\n  This parameter can be used to [override](#overriding-globals) the project annotations applied via `setProjectAnnotations`.\n\n  #### `exportsName`\n\n  Type: `string`\n\n  You probably don't need this. Because `composeStory` accepts a single story, it does not have access to the name of that story's export in the file (like `composeStories` does). If you must ensure unique story names in your tests and you cannot use `composeStories`, you can pass the name of the story's export here.\n\n  ### Return\n\n  Type: `ComposedStoryFn`\n\n  A single [composed story](#return).\n\n  ## setProjectAnnotations\n\n  This API should be called once, before the tests run, typically in a [setup file](https://vitest.dev/config/#setupfiles). This will make sure that whenever `composeStories` or `composeStory` are called, the project annotations are taken into account as well.\n\n  These are the configurations needed in the setup file:\n  - preview annotations: those defined in `.storybook/preview.ts`\n  - addon annotations (optional): those exported by addons\n  - beforeAll: code that runs before all tests ([more info](../../writing-tests/interaction-testing.mdx#beforeall))\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"portable-stories-vitest-set-project-annotations.md\" />\n\n  {/* prettier-ignore-end */}\n\n  {/* TODO: Create issue for interest in non-Testing Library render option, with recipe, and mention here (Jest, too) */}\n\n  Sometimes a story can require an addon's [decorator](../../writing-stories/decorators.mdx) or [loader](../../writing-stories/loaders.mdx) to render properly. For example, an addon can apply a decorator that wraps your story in the necessary router context. In this case, you must include that addon's `preview` export in the project annotations set. See `addonAnnotations` in the example above.\n\n  Note: If the addon doesn't automatically apply the decorator or loader itself, but instead exports them for you to apply manually in `.storybook/preview.js|ts` (e.g. using `withThemeFromJSXProvider` from [@storybook/addon-themes](https://github.com/storybookjs/storybook/blob/next/code/addons/themes/docs/api.md#withthemefromjsxprovider)), then you do not need to do anything else. They are already included in the `previewAnnotations` in the example above.\n\n  If you need to configure Testing Library's `render` or use a different render function, please let us know in [this discussion](https://github.com/storybookjs/storybook/discussions/28532) so we can learn more about your needs.\n\n  ### Type\n\n  ```ts\n  (projectAnnotations: ProjectAnnotation | ProjectAnnotation[]) => ProjectAnnotation\n  ```\n\n  ### Parameters\n\n  #### `projectAnnotations`\n\n  (**Required**)\n\n  Type: `ProjectAnnotation | ProjectAnnotation[]`\n\n  A set of project [annotations](#annotations) (those defined in `.storybook/preview.js|ts`) or an array of sets of project annotations, which will be applied to all composed stories.\n\n  ## Annotations\n\n  Annotations are the metadata applied to a story, like [args](../../writing-stories/args.mdx), [decorators](../../writing-stories/decorators.mdx), [loaders](../../writing-stories/loaders.mdx), and [play functions](../../writing-stories/play-function.mdx). They can be defined for a specific story, all stories for a component, or all stories in the project.\n\n  ## Story pipeline\n\n  To preview your stories in Storybook, Storybook runs a story pipeline, which includes applying project annotations, loading data, rendering the story, and playing interactions. This is a simplified version of the pipeline:\n\n  ![A flow diagram of the story pipeline. First, set project annotations. Collect annotations (decorators, args, etc) which are exported by addons and the preview file. Second, compose story. Create renderable elements based on the stories passed onto the API. Third, run. Mount the component and execute all the story lifecycle hooks, including the play function.](../../_assets/api/story-pipeline.png)\n\n  When you want to reuse a story in a different environment, however, it's crucial to understand that all these steps make a story. The portable stories API provides you with the mechanism to recreate that story pipeline in your external environment:\n\n  ### 1. Apply project-level annotations\n\n  [Annotations](#annotations) come from the story itself, that story's component, and the project. The project-level annotations are those defined in your `.storybook/preview.js` file and by addons you're using. In portable stories, these annotations are not applied automatically — you must apply them yourself.\n\n  👉 For this, you use the [`setProjectAnnotations`](#setprojectannotations) API.\n\n  ### 2. Compose\n\n  The story is prepared by running [`composeStories`](#composestories) or [`composeStory`](#composestory). The outcome is a renderable component that represents the render function of the story.\n\n  ### 3. Run\n\n  Finally, stories can prepare data they need (e.g. setting up some mocks or fetching data) before rendering by defining [loaders](../../writing-stories/loaders.mdx), [beforeEach](../../writing-tests/interaction-testing.mdx#run-code-before-each-story) or by having all the story code in the play function when using the [mount](../../writing-tests/interaction-testing.mdx#run-code-before-the-component-gets-rendered). In portable stories, all of these steps will be executed when you call the `run` method of the composed story.\n\n  👉 For this, you use the [`composeStories`](#composestories) or [`composeStory`](#composestory) API. The composed story will return a `run` method to be called.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"portable-stories-vitest-with-play-function.md\" />\n\n  {/* prettier-ignore-end */}\n\n  <Callout variant=\"info\">\n    If your play function contains assertions (e.g. `expect` calls), your test will fail when those assertions fail.\n  </Callout>\n\n  ## Overriding globals\n\n  If your stories behave differently based on [globals](../../essentials/toolbars-and-globals.mdx#globals) (e.g. rendering text in English or Spanish), you can define those global values in portable stories by overriding project annotations when composing a story:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"portable-stories-vitest-override-globals.md\" />\n\n  {/* prettier-ignore-end */}\n\n  {/* End supported renderers */}\n</If>\n"
  },
  {
    "path": "docs/builders/builder-api.mdx",
    "content": "---\ntitle: 'Builder API'\nsidebar:\n  order: 3\n  title: API\n---\n\nStorybook is architected to support multiple builders, including [Webpack](https://webpack.js.org/), [Vite](https://vitejs.dev/), and [ESBuild](https://esbuild.github.io/). The builder API is the set of interfaces you can use to add a new builder to Storybook.\n\n![Storybook builders](../_assets/builders/storybook-builders.png)\n\n## How do builders work?\n\nIn Storybook, a builder is responsible for compiling your components and stories into JS bundles that run in the browser. A builder also provides a development server for interactive development and a production mode for optimized bundles.\n\nTo opt into a builder, the user must add it as a dependency and then edit their configuration file (`.storybook/main.js`) to enable it. For example, with the Vite builder:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-vite-builder-install.md\" />\n\n{/* prettier-ignore-end */}\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-vite-builder-register.md\" />\n\n{/* prettier-ignore-end */}\n\n## Builder API\n\nIn Storybook, every builder must implement the following [API](https://github.com/storybookjs/storybook/blob/next/code/core/src/types/modules/core-common.ts#L255-L275), exposing the following configuration options and entry points:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-builder-api-interface.md\" />\n\n{/* prettier-ignore-end */}\n\nIn development mode, the `start` API call is responsible for initializing the development server to monitor the file system for changes (for example, components and stories) then execute a hot module reload in the browser.\nIt also provides a **bail** function to allow the running process to end gracefully, either via user input or error.\n\nIn production, the `build` API call is responsible for generating a static Storybook build, storing it by default in the `storybook-static` directory if no additional configuration is provided. The generated output should contain everything the user needs to view its Storybook by opening either the `index.html` or `iframe.html` in a browser with no other processes running.\n\n## Implementation\n\nUnder the hood, a builder is responsible for serving/building the preview `iframe`, which has its own set of requirements. To fully support Storybook, including the [essential features](../writing-stories/index.mdx) that ship with Storybook, it must consider the following.\n\n### Import stories\n\nThe `stories` configuration field enables story loading in Storybook. It defines an array of file globs containing the physical location of the component's stories. The builder must be able to load those files and monitor them for changes and update the UI accordingly.\n\n### Provide configuration options\n\nBy default, Storybook's configuration is handled in a dedicated file (`storybook/main.js|ts`), giving the user the option to customize it to suit its needs. The builder should also provide its own configuration support through additional fields or some other builder-appropriate mechanism. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-builder-api-configuration-options.md\" />\n\n{/* prettier-ignore-end */}\n\n### Handle preview.js exports\n\nThe [`preview.js`](../configure/index.mdx#configure-story-rendering) configuration file allows users to control how the story renders in the UI. This is provided via the [decorators](../writing-stories/decorators.mdx) named export. When Storybook starts, it converts these named exports into internal API calls via virtual module entry, for example, `addDecorator()`. The builder must also provide a similar implementation. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-builder-api-preview-exports.md\" />\n\n{/* prettier-ignore-end */}\n\n### MDX support\n\n[Storybook's Docs](../writing-docs/index.mdx) includes the ability to author stories/documentation in MDX using a Webpack loader. The builder must also know how to interpret MDX and invoke Storybook's special extensions. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-builder-api-mdx.md\" />\n\n{/* prettier-ignore-end */}\n\n### Generate source code snippets\n\nStorybook annotates components and stories with additional metadata related to their inputs to automatically generate interactive controls and documentation. Currently, this is provided via Webpack loaders/plugins. The builder must re-implement this to support those features.\n\n### Generate a static build\n\nOne of Storybook's core features it's the ability to generate a static build that can be [published](../sharing/publish-storybook.mdx) to a web hosting service. The builder must also be able to provide a similar mechanism. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-builder-api-build-server.md\" />\n\n{/* prettier-ignore-end */}\n\n### Development server integration\n\nBy default, when Storybook starts in development mode, it relies on its internal development server. The builder needs to be able to integrate with it. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-builder-api-dev-server.md\" />\n\n{/* prettier-ignore-end */}\n\n### Shutdown the development server\n\nThe builder must provide a way to stop the development server once the process terminates; this can be via user input or error. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-builder-api-shutdown-server.md\" />\n\n{/* prettier-ignore-end */}\n\n### HMR support\n\nWhile running in development mode, the builder's development server must be able to reload the page once a change happens, either in a story, component, or helper function.\n\n### More information\n\nThis area is under rapid development, and the associated documentation is still in progress and subject to change. If you are interested in creating a builder, you can learn more about implementing a builder in Storybook by checking the source code for [Vite](https://github.com/storybookjs/storybook/tree/next/code/builders/builder-vite), [Webpack](https://github.com/storybookjs/storybook/tree/next/code/builders/builder-webpack5), or Modern Web's [dev-server-storybook](https://github.com/modernweb-dev/web/blob/master/packages/dev-server-storybook/src/serve/storybookPlugin.ts). When you're ready, open an [RFC](../contribute/RFC.mdx) to discuss your proposal with the Storybook community and maintainers.\n\n**Learn more about builders**\n\n* [Vite builder](./vite.mdx) for bundling with Vite\n* [Webpack builder](./webpack.mdx) for bundling with Webpack\n* Builder API for building a Storybook builder\n"
  },
  {
    "path": "docs/builders/index.mdx",
    "content": "---\ntitle: 'Builders'\nhideRendererSelector: true\nsidebar:\n  order: 11\n  title: Builders\n---\n\nStorybook, at its core, is powered by builders such as Webpack and Vite. These builders spin up a development environment, compile your code—Javascript, CSS, and MDX—into an executable bundle and update the browser in real-time.\n\n![Storybook builder overview](../_assets/builders/storybook-builder-workflow.png)\n\n## CLI basics\n\nBefore diving into setting up Storybook's builders, let's look at how the CLI configures them. When you initialize Storybook (via `npx storybook@latest init`), the CLI automatically detects which builder to use based on your application. For example, if you're working with Vite, it will install the Vite builder. If you're working with Webpack, it installs the Webpack 5 builder by default.\n\nAdditionally, you can also provide a flag to Storybook's CLI and specify the builder you want to use:\n\n```shell\nnpx storybook@latest init --builder <webpack5 | vite>\n```\n\n## Manual setup\n\nStorybook uses the Webpack 5 builder by default if you don't specify one. If you want to use a different builder in your application, these docs detail how you can set up Storybook's supported builders.\n\n* [**Vite builder**](./vite.mdx) for bundling your stories with Vite with near-instant HMR.\n* [**Webpack**](./webpack.mdx) for bundling your stories with Webpack with improved performance\n* [**Rspack / Rsbuild**](https://github.com/rspack-contrib/storybook-rsbuild) for bundling your stories with blazing fast Rspack and Rsbuild.\n"
  },
  {
    "path": "docs/builders/vite.mdx",
    "content": "---\ntitle: 'Vite'\nsidebar:\n  order: 1\n  title: Vite\n---\n\nStorybook Vite builder bundles your components and stories with [Vite](https://vitejs.dev/), a fast ESM bundler.\n\n* For applications built with Vite: it allows reusing the existing configuration in Storybook.\n* For applications built with Webpack: it provides faster startup and refresh times, with the disadvantage that your component's execution environment differs from your application.\n\n## Setup\n\nIf you ran `npx storybook@latest init` to include Storybook in your Vite application, the builder is already installed and configured for you. If you want, you can also opt into it manually.\n\nRun the following command to install the builder.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-vite-builder-install.md\" />\n\n{/* prettier-ignore-end */}\n\nUpdate your Storybook configuration (in `.storybook/main.js|ts`) to include the builder.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-vite-builder-register.md\" />\n\n{/* prettier-ignore-end */}\n\n## Configuration\n\nOut of the box, Storybook's Vite builder includes a set of configuration defaults for the supported frameworks, which are merged alongside your existing configuration file. For an optimal experience when using the Vite builder, we recommend applying any configuration directly inside Vite's configuration file (i.e., [`vite.config.js|ts`](https://vitejs.dev/config/)).\n\nWhen Storybook loads, it automatically merges the configuration into its own. However, since different projects may have specific requirements, you may need to provide a custom configuration for Storybook. In such cases, you can modify your configuration file (`.storybook/main.js|ts`) and add the `viteFinal` configuration function as follows:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-vite-builder-aliasing.md\" />\n\n{/* prettier-ignore-end */}\n\nThe asynchronous function [`viteFinal`](../api/main-config/main-config-vite-final.mdx) receives a `config` object with the default builder configuration and returns the updated configuration.\n\n### Environment-based configuration\n\nIf you need to customize the builder's configuration and apply specific options based on your environment, extend the `viteFinal` function as follows:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-vite-final-env.md\" />\n\n{/* prettier-ignore-end */}\n\n### Override the default configuration\n\nBy default, the Vite builder in Storybook searches for the Vite configuration file in the root directory of your Storybook project. However, you can customize it to look for the configuration file in a different location. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-builder-custom-config.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  If you do not want Storybook to load the Vite configuration file automatically, you can use the `viteConfigPath` option to point to a non-existent file.\n</Callout>\n\n### TypeScript\n\nIf you need, you can also configure Storybook's Vite builder using TypeScript. Rename your `.storybook/main.js` to `.storybook/main.ts` and adjust it as follows:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-vite-builder-ts-configure.md\" />\n\n{/* prettier-ignore-end */}\n\n***\n\n## Troubleshooting\n\n### Migrating from Webpack\n\nVite generally handles more use cases out of the box than Webpack. For example, loading styles just works for most projects. So, when migrating a Webpack-based project to Vite, you may find that you don't need all of your previous configuration.\n\nWe recommend starting with no Storybook-specific Vite configuration and only adding what you determine your project actually requires.\n\nFor reference, here is a Webpack configuration to handle loading graphql queries and its equivalent, using a plugin, in Vite:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"webpack-final-to-vite-final.md\" />\n\n{/* prettier-ignore-end */}\n\n### Working directory not being detected\n\nBy default, the Vite builder enables Vite's [`server.fs.strict`](https://vitejs.dev/config/#server-fs-strict) option for increased security, defining the project's `root` to Storybook's configuration directory.\nIf you need to override it, you can use the `viteFinal` function and adjust it.\n\n### ArgTypes are not generated automatically\n\nCurrently, [automatic argType inference](../api/arg-types.mdx#automatic-argtype-inference) is only available for React, Vue 3, and Svelte (JSDocs only). With React, the Vite builder defaults to `react-docgen`, a faster alternative to `react-docgen-typescript` for parsing React components. If you run into any issues, you can revert to `react-docgen-typescript` by updating your Storybook configuration file as follows:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-vite-builder-react-docgen.md\" />\n\n{/* prettier-ignore-end */}\n\n### Interaction tests not working as expected\n\nIf you are migrating from a Webpack-based project, such as [CRA](https://create-react-app.dev/), to Vite, and you are [interaction testing](../writing-tests/interaction-testing.mdx), you may run into a situation where your tests fail to execute notifying you that the `window` object is not defined. To resolve this issue, you can create a `preview-head.html` file in your Storybook configuration directory and include the following:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-vite-builder-jest-mock.md\" />\n\n{/* prettier-ignore-end */}\n\n**Learn more about builders**\n\n* Vite builder for bundling with Vite\n* [Webpack builder](./webpack.mdx) for bundling with Webpack\n* [Builder API](./builder-api.mdx) for building a Storybook builder\n"
  },
  {
    "path": "docs/builders/webpack.mdx",
    "content": "---\ntitle: 'Webpack'\nsidebar:\n  order: 2\n  title: Webpack\n---\n\nStorybook Webpack builder is the default builder for Storybook. This builder enables you to create a seamless development and testing experience for your components and provides an efficient way to develop UI components in isolation allowing you to leverage your existing Webpack configuration with Storybook.\n\n## Configure\n\nBy default, Storybook provides zero-config support for Webpack and automatically sets up a baseline configuration created to work with the most common use cases. However, you can extend your Storybook configuration file (i.e., `.storybook/main.js|ts`) and provide additional options to improve your Storybook's performance or customize it to your needs. Listed below are the available options and examples of how to use them.\n\n| Option            | Description                                                                                                                                                                                        |\n| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `lazyCompilation` | Enables Webpack's experimental [`lazy compilation`](https://webpack.js.org/configuration/experiments/#experimentslazycompilation)<br />`core: { builder: { options: { lazyCompilation: true } } }` |\n| `fsCache`         | Configures Webpack's filesystem [caching](https://webpack.js.org/configuration/cache/#cachetype) feature<br /> `core: { builder: { options: { fsCache: true } } }`                                 |\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-webpack-options.md\" />\n\n{/* prettier-ignore-end */}\n\n### Override the default configuration\n\nStorybook's Webpack configuration is based on [Webpack 5](https://webpack.js.org/), allowing it to be extended to fit your project's needs. If you need to add a loader or a plugin, you can provide the `webpackFinal` configuration element in your [`.storybook/main.js|ts`](../configure/index.mdx#configure-your-storybook-project) file. The configuration element should export a function that receives the baseline configuration as the first argument and Storybook's options object as the second argument. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-webpack-final.md\" />\n\n{/* prettier-ignore-end */}\n\nWhen Storybook starts, it automatically merges the configuration into its own. However, when providing the `webpackFinal` configuration element, you're responsible for merging the configuration yourself. We recommend that you handle the changes to the `config` object responsibly, preserving both the `entry` and `output` properties.\n\n#### Working with Webpack plugins\n\nAnother way to customize your Storybook configuration is to add a custom plugin or loader to help with code optimization, asset management, or other tasks. Nevertheless, since Storybook relies on the `HtmlWebpackPlugin` to generate the preview page, we recommend that you append the changes to the `config.plugins` array rather than overwriting it. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-simplified-config.md\" />\n\n{/* prettier-ignore-end */}\n\nAdditionally, when working with Webpack loaders that don't explicitly include specific file extensions (i.e., via the `test` property), you should `exclude` the `.ejs` file extension for that loader.\n\n### Import a custom Webpack configuration\n\nIf you already have an existing Webpack configuration file that you need to reuse with Storybook, you can import it and merge it into the default configuration. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-using-existing-config.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  Projects scaffolded based on generators may require that you import their specific Webpack configuration files. We suggest reading your generator's documentation for more information.\n</Callout>\n\n### Debug Webpack configuration\n\nIf you intend to debug the Webpack configuration used by Storybook, you can use the Storybook CLI to help you. If you're running in [development mode](../api/cli-options.mdx#dev), you can use the following command:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-debug-webpack-dev.md\" />\n\n{/* prettier-ignore-end */}\n\nAdditionally, if you're generating a [static build](../api/cli-options.mdx#build) of your Storybook, you can use the following command:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-debug-webpack-prod.md\" />\n\n{/* prettier-ignore-end */}\n\n## Compiler support\n\nStorybook takes a compiler-agnostic approach to bundling. This allows you to bring your own application bundler (e.g., [Babel](https://babeljs.io/), [SWC](https://swc.rs/)) and ensures compatibility within the vast ecosystem of Webpack 5-based projects.\n\n### SWC\n\nIf your project is built using [SWC](https://swc.rs/), use the [`@storybook/addon-webpack5-compiler-swc`](https://storybook.js.org/addons/@storybook/addon-webpack5-compiler-swc) addon. This addon increases ecosystem compatibility with Webpack 5 projects while maintaining high performance. Run the following command to set up the addon automatically:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-compiler-swc-auto-install.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  Additional options can be provided to customize the SWC configuration. See the [SWC API documentation](../api/main-config/main-config-swc.mdx) for more information.\n</Callout>\n\nWhen enabled, this addon adjusts the Webpack configuration to use the [`swc-loader`](https://swc.rs/docs/usage/swc-loader) for JavaScript and TypeScript files. Additionally, it will detect and use your project's SWC configuration.\n\n### Babel\n\nIf you're working with a project that relies on Babel's tooling to provide support for specific features, including TypeScript or other modern JavaScript features, you can use the [`@storybook/addon-webpack5-compiler-babel`](https://storybook.js.org/addons/@storybook/addon-webpack5-compiler-babel) addon to allow you to include them in your Storybook to ensure compatibility with your project. Run the following command to set up the addon automatically:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-compiler-babel-auto-install.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  Additional options can be provided to customize the Babel configuration. See the [`babel` API documentation](../api/main-config/main-config-babel.mdx) for more information, or if you're working on an addon, the [`babelDefault` documentation](../api/main-config/main-config-babel-default.mdx) for more information.\n</Callout>\n\nWhen enabled, the addon will adjust the Webpack configuration to use the [`babel-loader`](https://webpack.js.org/loaders/babel-loader/) as the default loader for JavaScript and TypeScript files. Additionally, it will detect and use your project's Babel configuration.\n\n## Troubleshooting\n\n### TypeScript modules are not resolved within Storybook\n\nStorybook's default Webpack configuration provides support for most project setups without the need for any additional configuration. Nevertheless, depending on your project configuration, or the framework of choice, you may run into issues with TypeScript modules not being resolved within Storybook when aliased from your [`tsconfig` file](https://www.typescriptlang.org/tsconfig). If you encounter this issue, you can use [`tsconfig-paths-webpack-plugin`](https://github.com/dividab/tsconfig-paths-webpack-plugin#tsconfig-paths-webpack-plugin) while [extending Storybook's Webpack config](#override-the-default-configuration) as follows:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-ts-module-resolution.md\" />\n\n{/* prettier-ignore-end */}\n\nHowever, if you're working with a framework that provides a default aliasing configuration (e.g., Next.js, Nuxt) and you want to configure Storybook to use the same aliases, you may not need to install any additional packages. Instead, you can extend the default configuration of Storybook to use the same aliases provided by the framework. For example, to set up an alias for the `@` import path, you can add the following to your `.storybook/main.js|ts` file:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-ts-module-resolution-atsign-import.md\" />\n\n{/* prettier-ignore-end */}\n\n### Pre-bundled assets do not show in the Storybook UI\n\nAs Storybook relies on [esbuild](https://esbuild.github.io/) to build its internal manager, support for bundling assets with the `managerWebpack` will no longer have an impact on the Storybook UI. We recommend removing existing `managerWebpack` configuration elements from your Storybook configuration file and bundling assets other than images or CSS into JavaScript beforehand.\n\n### Storybook doesn't run with Webpack 4\n\nSupport for Webpack 4 has been removed and is no longer being maintained. If you're upgrading your Storybook, it will automatically use Webpack 5 and attempt to migrate your configuration. However, if you're working with a custom Webpack configuration, you may need to update it to work with Webpack 5. The migration process is necessary to ensure that your project runs smoothly with the latest version of Storybook. You can follow the instructions provided on the Webpack [website](https://webpack.js.org/migrate/5/) to update your configuration.\n\n**Learn more about builders**\n\n* [Vite builder](./vite.mdx) for bundling with Vite\n* Webpack builder for bundling with Webpack\n* [Builder API](./builder-api.mdx) for building a Storybook builder\n"
  },
  {
    "path": "docs/configure/environment-variables.mdx",
    "content": "---\ntitle: 'Environment variables'\nsidebar:\n  order: 8\n  title: Environment variables\n---\n\nYou can use environment variables in Storybook to change its behavior in different “modes”.\nIf you supply an environment variable prefixed with `STORYBOOK_`, it will be available in `process.env` when using Webpack, or `import.meta.env` when using the Vite builder:\n\n```shell\nSTORYBOOK_THEME=red STORYBOOK_DATA_KEY=12345 npm run storybook\n```\n\n<Callout variant=\"info\" icon=\"💡\">\n  Do not store any secrets (e.g., private API keys) or other types of sensitive information in your Storybook. Environment variables are embedded into the build, meaning anyone can view them by inspecting your files.\n</Callout>\n\nThen we can access these environment variables anywhere inside our preview JavaScript code like below:\n\n<IfRenderer renderer={['angular', 'ember' ]}>\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"storybook-read-environment-variables.md\" />\n</IfRenderer>\n\n{/* prettier-ignore-end */}\n\n<IfRenderer renderer={['html', 'react', 'qwik', 'preact','svelte', 'solid', 'vue', 'web-components' ]}>\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"storybook-read-environment-variables.md\" />\n</IfRenderer>\n\n{/* prettier-ignore-end */}\n\nYou can also access these variables in your custom `<head>`/`<body>` using the substitution `%STORYBOOK_X%`, for example: `%STORYBOOK_THEME%` will become `red`.\n\n<Callout variant=\"info\" icon=\"💡\">\n  If using the environment variables as attributes or values in JavaScript, you may need to add quotes, as the value will be inserted directly, for example: `<link rel=\"stylesheet\" href=\"%STORYBOOK_STYLE_URL%\" />`.\n</Callout>\n\n## Using .env files\n\nYou can also use `.env` files to change Storybook's behavior in different modes. For example, if you add a `.env` file to your project with the following:\n\n```\nSTORYBOOK_DATA_KEY=12345\n```\n\nThen you can access this environment variable anywhere, even within your stories:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"my-component-with-env-variables.md\" />\n\n{/* prettier-ignore-end */}\n\n<IfRenderer renderer={['html', 'react', 'qwik', 'preact','svelte', 'solid', 'vue', 'web-components' ]}>\n  ### With Vite\n\n  Out of the box, Storybook provides a [Vite builder](../builders/vite.mdx), which does not output Node.js globals like `process.env`. To access environment variables in Storybook (e.g., `STORYBOOK_`, `VITE_`), you can use `import.meta.env`. For example:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"my-component-vite-env-variables.md\" />\n\n  {/* prettier-ignore-end */}\n</IfRenderer>\n\n<Callout variant=\"info\">\n  You can also use specific files for specific modes. Add a `.env.development` or `.env.production` to apply different values to your environment variables.\n</Callout>\n\nYou can also pass these environment variables when you are [building your Storybook](../sharing/publish-storybook.mdx) with `build-storybook`.\n\nThen they'll be hardcoded to the static version of your Storybook.\n\n## Using Storybook configuration\n\nAdditionally, you can extend your Storybook configuration file (i.e., [`.storybook/main.js|.ts`](../configure/index.mdx#configure-story-rendering)) and provide a configuration field that you can use to define specific variables (e.g., API URLs). For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-env.md\" />\n\n{/* prettier-ignore-end */}\n\nWhen Storybook loads, it will enable you to access them in your stories similar as you would do if you were working with an `env` file:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"my-component-env-var-config.md\" />\n\n{/* prettier-ignore-end */}\n\n## Using environment variables to choose the browser\n\nStorybook allows you to choose the browser you want to preview your stories. Either through a `.env` file entry or directly in your `storybook` script.\n\nThe table below lists the available options:\n\n| Browser  | Example              |\n| -------- | -------------------- |\n| Safari   | `BROWSER=\"safari\"`   |\n| Firefox  | `BROWSER=\"firefox\"`  |\n| Chromium | `BROWSER=\"chromium\"` |\n\n<Callout variant=\"info\" icon=\"💡\">\n  By default, Storybook will open a new Chrome window as part of its startup process. If you don't have Chrome installed, make sure to include one of the following options, or set your default browser accordingly.\n</Callout>\n\n## Troubleshooting\n\n### Environment variables are not working\n\nIf you're trying to use framework-specific environment variables (e.g.,`VUE_APP_`), you may run into issues primarily due to the fact that Storybook and your framework may have specific configurations and may not be able to recognize and use those environment variables. If you run into a similar situation, you may need to adjust your framework configuration to make sure that it can recognize and use those environment variables. For example, if you're working with a Vite-based framework, you can extend the configuration file and enable the [`envPrefix`](https://vitejs.dev/config/shared-options.html#envprefix) option. Other frameworks may require a similar approach.\n"
  },
  {
    "path": "docs/configure/index.mdx",
    "content": "---\ntitle: 'Configure Storybook'\nsidebar:\n  order: 10\n  title: Configure\n---\n\nStorybook is configured via a folder called `.storybook`, which contains various configuration files.\n\n<Callout variant=\"info\">\n  Note that you can change the folder that Storybook uses by setting the `-c` flag to your `storybook dev` and `storybook build` [CLI commands](../api/cli-options.mdx).\n</Callout>\n\n## Configure your Storybook project\n\nStorybook's main configuration (i.e., the `main.js|ts`) defines your Storybook project's behavior, including the location of your stories, the addons you use, feature flags and other project-specific settings. This file should be in the `.storybook` folder in your project's root directory. You can author this file in either JavaScript or [TypeScript](./integration/typescript.mdx). Listed below are the available options and examples of how to use them.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-typical.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  This configuration file is a [preset](../addons/addon-types.mdx) and, as such, has a powerful interface, which can be further customized. Read our documentation on writing [presets](../addons/writing-presets.mdx) to learn more.\n</Callout>\n\n| Configuration element | Description                                                                                                                                                                                                                       |\n| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `stories`             | The array of globs that indicates the [location of your story files](#configure-story-loading), relative to `main.js`                                                                                                             |\n| `staticDirs`          | Sets a list of directories of [static files](./integration/images-and-assets.mdx#serving-static-files-via-storybook-configuration) to be loaded by Storybook <br /> `staticDirs: ['../public']`                                   |\n| `addons`              | Sets the list of [addons](https://storybook.js.org/integrations) loaded by Storybook <br /> `addons: ['@storybook/addon-docs']`                                                                                             |\n| `typescript`          | Configures how Storybook handles [TypeScript files](./integration/typescript.mdx) <br /> `typescript: { check: false, checkOptions: {} }`                                                                                         |\n| `framework`           | Configures Storybook based on a set of [framework-specific](./integration/frameworks.mdx) settings <br /> `framework: { name: '@storybook/svelte-vite', options:{} }`                                                             |\n| `core`                | Configures Storybook's [internal features](../api/main-config/main-config-core.mdx) <br /> `core: { disableTelemetry: true, }`                                                                                                    |\n| `docs`                | Configures Storybook's [auto-generated documentation](../writing-docs/autodocs.mdx)<br /> `docs: { defaultName: 'Documentation' }`                                                                                                             |\n| `features`            | Enables Storybook's [additional features](../api/main-config/main-config-features.mdx)<br /> See table below for a list of available features                                                                                     |\n| `refs`                | Configures [Storybook composition](../sharing/storybook-composition.mdx) <br /> `refs: { example: { title: 'ExampleStorybook', url:'https://your-url.com' } }`                                                                    |\n| `logLevel`            | Configures Storybook's logs in the browser terminal. Useful for debugging <br /> `logLevel: 'debug'`                                                                                                                              |\n| `webpackFinal`        | Customize Storybook's [Webpack](../builders/webpack.mdx) setup <br /> `webpackFinal: async (config:any) => { return config; }`                                                                                                    |\n| `viteFinal`           | Customize Storybook's Vite setup when using the [vite builder](https://github.com/storybookjs/builder-vite) <br /> `viteFinal: async (config: Vite.InlineConfig, options: Options) => { return config; }`                         |\n| `env`                 | Defines custom Storybook [environment variables](./environment-variables.mdx#using-storybook-configuration). <br /> `env: (config) => ({...config, EXAMPLE_VAR: 'Example var' }),`                                                |\n| `build`               | Optimizes Storybook's production [build](../api/main-config/main-config-build.mdx) for performance by excluding specific features from the bundle. Useful when decreased build times are a priority. <br /> `build: { test: {} }` |\n\n## Configure story loading\n\nBy default, Storybook will load stories from your project based on a glob (pattern matching string) in `.storybook/main.js|ts` that matches all files in your project with extension `.stories.*`. The intention is for you to colocate a story file along with the component it documents.\n\n```\n•\n└── components\n    ├── Button.js\n    └── Button.stories.js\n```\n\nIf you want to use a different naming convention, you can alter the glob using the syntax supported by [picomatch](https://github.com/micromatch/picomatch#globbing-features).\n\nFor example, if you wanted to pull both `.md` and `.js` files from the `my-project/src/components` directory, you could write:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-js-md-files.md\" />\n\n{/* prettier-ignore-end */}\n\n### With a configuration object\n\nAdditionally, you can customize your Storybook configuration to load your stories based on a configuration object. For example, if you wanted to load your stories from a `packages/components` directory, you could adjust your `stories` configuration field into the following:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-stories-with-object.md\" />\n\n{/* prettier-ignore-end */}\n\nWhen Storybook starts, it will look for any file containing the `stories` extension inside the `packages/components` directory and generate the titles for your stories.\n\n### With a directory\n\nYou can also simplify your Storybook configuration and load the stories using a directory. For example, if you want to load all the stories inside a `packages/MyStories`, you can adjust the configuration as such:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-storyloading-with-directory.md\" />\n\n{/* prettier-ignore-end */}\n\n### With a custom implementation\n\nYou can also adjust your Storybook configuration and implement custom logic to load your stories. For example, suppose you were working on a project that includes a particular pattern that the conventional ways of loading stories could not solve. In that case, you could adjust your configuration as follows:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-stories-with-logic.md\" />\n\n{/* prettier-ignore-end */}\n\n#### Known limitations\n\nBecause of the way stories are currently indexed in Storybook, loading stories on demand has a couple of minor limitations at the moment:\n\n* [CSF formats](../api/csf/index.mdx) from version 1 to version 3 are supported.\n* Custom `storySort` functions are allowed based on a restricted API.\n\n## Configure story rendering\n\nTo control the way stories are rendered and add global [decorators](../writing-stories/decorators.mdx#global-decorators) and [parameters](../writing-stories/parameters.mdx#global-parameters), create a `.storybook/preview.js` file. This is loaded in the Canvas UI, the “preview” iframe that renders your components in isolation. Use `preview.js` for global code (such as [CSS imports](../get-started/setup.mdx#render-component-styles) or JavaScript mocks) that applies to all stories.\n\nThe `preview.js` file can be an ES module and export the following keys:\n\n* `decorators` - an array of global [decorators](../writing-stories/decorators.mdx#global-decorators)\n* `parameters` - an object of global [parameters](../writing-stories/parameters.mdx#global-parameters)\n* `globalTypes` - definition of [globalTypes](../essentials/toolbars-and-globals.mdx#global-types-and-the-toolbar-annotation)\n\nIf you’re looking to change how to order your stories, read about [sorting stories](../writing-stories/naming-components-and-hierarchy.mdx#sorting-stories).\n\n## Configure Storybook’s UI\n\nTo control the behavior of Storybook’s UI (the **“manager”**), you can create a `.storybook/manager.js` file.\n\nThis file does not have a specific API but is the place to set [UI options](./user-interface/features-and-behavior.mdx) and to configure Storybook’s [theme](./user-interface/theming.mdx).\n"
  },
  {
    "path": "docs/configure/integration/compilers.mdx",
    "content": "---\ntitle: 'Compiler support'\nsidebar:\n  order: 3\n  title: Compilers\n---\n\nJavascript compilers are essential in optimizing and transforming code, enhancing performance, and ensuring compatibility across different environments. Storybook provides support for the leading compilers, ensuring lightning-fast build time and execution with [SWC](https://swc.rs/) or leveraging [Babel](https://babeljs.io/) with its extensive ecosystem of plugins and presets to allow you to use the latest features of the ecosystem with minimal configuration required for your Webpack-based project.\n\n## SWC\n\nSWC is a fast, highly extensible tool for compiling and bundling modern JavaScript applications. Powered by [Rust](https://www.rust-lang.org/), it improves performance and reduces build times. Storybook includes a built-in integration with SWC, allowing zero-configuration setup and built-in types for APIs. If you've initialized Storybook in a Webpack-based project with any of the supported [frameworks](./frameworks.mdx), except Angular, Create React App, Ember.js and Next.js, it will automatically use SWC as its default, providing you with faster loading time.\n\n<Callout variant=\"info\">\n  Support for the SWC builder is currently experimental for Next.js projects, and it's not enabled by default. It requires you to opt in to use it. For more information on configuring SWC with the supported frameworks, see the [SWC API](../../api/main-config/main-config-swc.mdx) documentation.\n</Callout>\n\n## Babel\n\nBabel is a widely adopted JavaScript compiler providing a modular architecture and extensive plugin system to support a wide range of use cases, enabling access to the cutting-edge features of the tooling ecosystem. Storybook provides a seamless integration with Babel, allowing you to share a standard setup between your project and Storybook without any additional configuration.\n\n<Callout variant=\"info\">\n  If you're not using Storybook 7, please reference the [previous documentation](../../../release-6-5/docs/configure/babel.mdx) for guidance on configuring your Babel setup.\n</Callout>\n\n### Configure\n\nBy default, Babel provides an opinionated [configuration](https://babeljs.io/docs/config-files) that works for most projects, relying on two distinct methods for configuring projects with the tool:\n\n* **Project-wide configuration**: Babel will look for a `babel.config.js` or equivalent file in the root of your project and use it to configure your project's Babel setup.\n* **File-relative configuration**: Babel will look for a `.babelrc.json` or equivalent file, introspecting the project structure until it finds a configuration file. This will allow you to configure Babel individually for multiple aspects of your project.\n\nStorybook relies on an agnostic approach to configuring Babel, enabling you to provide the necessary configuration for your project, and it will use it. Based on the supported frameworks, builders, and addons, it may include minor adjustments to ensure compatibility with Storybook's features.\n\n<Callout variant=\"info\">\n  For custom project configurations such as monorepos, where you have multiple Storybook configurations, creating a `.babelrc.json` file in your project's current working directory may not be sufficient. In those cases, you can create a `babel.config.js` file to override Babel's configuration, and Storybook will automatically detect and use it. See the Babel [documentation](https://babeljs.io/docs/config-files) for more information.\n</Callout>\n\n### Working with Create React App\n\nIf you're working with a project that was initialized with [Create React App](https://create-react-app.dev/), Storybook will automatically detect and use the Babel configuration provided by the tool enabled via the `@storybook/preset-create-react-app` preset, allowing to use Storybook without any additional configuration.\n\n## Troubleshooting\n\n<IfRenderer renderer=\"react\">\n  ### The SWC compiler doesn't work with React\n\n  If you have enabled the SWC builder option in a React-based project and you are not explicitly importing React in your `jsx|tsx` files, it can cause Storybook to fail to load. SWC does not automatically import the `jsx-runtime` module when using the SWC builder. To resolve this issue, you need to adjust your Storybook configuration file (i.e., `.storybook/main.js|ts`) and configure the `swc` option as follows:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"main-config-swc-jsx-transform.md\" />\n\n  {/* prettier-ignore-end */}\n</IfRenderer>\n\n### Babel configuration not working\n\nOut of the box, Storybook can detect and apply any Babel configuration you provided in your project. However, if you're running into a situation where your configuration is not being used, you configure the [`BABEL_SHOW_CONFIG_FOR`](https://babeljs.io/docs/configuration#print-effective-configs) environment variable and set it to the file you want to inspect. For example:\n\n```sh\nBABEL_SHOW_CONFIG_FOR=.storybook/preview.js yarn storybook\n```\n\nWhen the command runs, it will output the Babel configuration applied to the file you specified despite showing a transpilation error in the console and preventing Storybook from loading. This is a known issue with Babel unrelated to Storybook, which you address by turning off the environment variable after inspecting the configuration and restarting Storybook.\n"
  },
  {
    "path": "docs/configure/integration/eslint-plugin.mdx",
    "content": "---\ntitle: \"ESLint plugin\"\nhideRendererSelector: true\nsidebar:\n  order: 5\n  title: ESLint plugin\n---\n\nStorybook provides a dedicated [ESLint plugin](https://github.com/storybookjs/storybook/tree/next/code/lib/eslint-plugin) to help you write stories and components aligned with the latest Storybook and frontend development best practices.\n\n## Installation\n\nYou'll first need to install [ESLint](https://eslint.org/):\n\n<CodeSnippets path=\"eslint-install.md\" />\n\nNext, install `eslint-plugin-storybook`:\n\n<CodeSnippets path=\"eslint-plugin-storybook-install.md\" />\n\nThen add `plugin:storybook/recommended` to the extends section of your `.eslintrc` configuration file. Note that we can omit the `eslint-plugin-` prefix:\n\n```js title=\".eslintrc\"\n{\n  // extend plugin:storybook/<configuration>, such as:\n  \"extends\": [\"plugin:storybook/recommended\"]\n}\n```\n\nAnd finally, add this to your `.eslintignore` file:\n\n```txt title=\".eslintignore\"\n!.storybook\n```\n\nThis ensures that the plugin will also lint your configuration files inside the `.storybook` directory, so that you always have a correct configuration. For example, it can catch mistyped addon names in your `main.js|ts` file.\n\nFor more details on why this line is required in the `.eslintignore` file, refer to the [ESLint documentation](https://eslint.org/docs/latest/use/configure/ignore-deprecated#:~:text=In%20addition%20to,contents%20are%20ignored).\n\nIf you are using [flat config style](https://eslint.org/docs/latest/use/configure/configuration-files-new), add this to your configuration file:\n\n```js title=\"eslint.config.js\"\nimport { defineConfig, globalIgnores } from \"eslint/config\";\n\nexport default defineConfig([\n  globalIgnores([\"!.storybook\"], \"Include Storybook Directory\"),\n  // ...\n]);\n```\n\n## ESLint compatibility\n\nDepending on the version of ESLint you are using, you may need to install a specific version of the Storybook plugin. Use the table below to match the plugin version to your ESLint version.\n\n| ESLint version | Storybook plugin version |\n| -------------- | ------------------------ |\n| `^9.0.0`       | `^9.0.0` or `^0.10.0`    |\n| `^8.57.0`      | `^9.0.0` or `^0.10.0`    |\n| `^7.0.0`       | `~0.9.0`                 |\n\n## Usage\n\n### Configuration (`.eslintrc`)\n\nUse `.eslintrc.*` file to configure rules in ESLint < v9. See also: https://eslint.org/docs/latest/use/configure/.\n\nThis plugin will only be applied to files following the `*.stories.*` (recommended) or `*.story.*` pattern. This is an automatic configuration, so no action is required.\n\n#### Overriding/disabling rules\n\nOptionally, you can override, add to, or disable individual rules. You likely don't want these settings to be applied in every file, so make sure that you add a `overrides` section in your `.eslintrc.*` file that applies the overrides only to your story files.\n\n```js title=\".eslintrc\"\n{\n  \"overrides\": [\n    {\n      // 👇 This should match the `stories` property in .storybook/main.js|ts\n      \"files\": [\"**/*.stories.@(ts|tsx|js|jsx|mjs|cjs)\"],\n      \"rules\": {\n        // 👇 Enable this rule\n        \"storybook/csf-component\": \"error\",\n        // 👇 Disable this rule\n        \"storybook/default-exports\": \"off\",\n      }\n    }\n  ]\n}\n```\n\n### Configuration (flat config format)\n\nUse the `eslint.config.js` file to configure rules using the [flat config style](https://eslint.org/docs/latest/use/configure/configuration-files-new). This is the default in ESLint v9, but can be used starting from ESLint v8.57.0. See also: https://eslint.org/docs/latest/use/configure/configuration-files-new.\n\n```js title=\"eslint.config.js\"\nimport storybook from \"eslint-plugin-storybook\";\n// Replace the eslint/config package with @eslint/config-helpers if you're using an older version of ESLint.\nimport { defineConfig } from \"eslint/config\";\n\nexport default defineConfig([\n  ...storybook.configs[\"flat/recommended\"],\n  // Add more configuration options and generic rulesets here, such as js.configs.recommended\n]);\n```\n\nIn case you are using utility functions from tools like `tseslint`, you might need to register the plugin a little differently:\n\n```ts title=\"eslint.config.ts\"\nimport storybook from \"eslint-plugin-storybook\";\nimport somePlugin from \"some-plugin\";\nimport tseslint from \"typescript-eslint\";\n\nexport default tseslint.config(\n  somePlugin,\n  storybook.configs[\"flat/recommended\"], // notice that it is not destructured\n);\n```\n\n#### Overriding/disabling rules\n\nOptionally, you can override, add, or disable individual rules. You likely don't want these settings to be applied to every file, so ensure that you add a flat config section in your `eslint.config.js` file that applies the overrides only to your story files.\n\n```js title=\"eslint.config.js\"\nimport storybook from \"eslint-plugin-storybook\";\nimport { defineConfig } from \"eslint/config\";\n\nexport default defineConfig([\n  ...storybook.configs[\"flat/recommended\"],\n  {\n    // 👇 This should match the `stories` property in .storybook/main.js|ts\n    files: [\"**/*.stories.@(ts|tsx|js|jsx|mjs|cjs)\"],\n    rules: {\n      // 👇 Enable this rule\n      \"storybook/csf-component\": \"error\",\n      // 👇 Disable this rule\n      \"storybook/default-exports\": \"off\",\n    },\n  },\n]);\n```\n\n### MDX Support\n\nThis plugin does not support MDX files.\n\n## Supported Rules and configurations\n\n{/* RULES-LIST:START */}\n\n**Configurations**: csf, csf-strict, addon-interactions, recommended\n\n| Name                                                                                                                                                               | Description                                                                                                                   | Automatically fixable | Included in configurations                                                                                                     |\n| ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------ |\n| [`storybook/await-interactions`](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin/docs/rules/await-interactions.md)                       | Interactions should be awaited                                                                                                | ✅                    | <ul><li>addon-interactions</li><li>flat/addon-interactions</li><li>recommended</li><li>flat/recommended</li></ul>              |\n| [`storybook/context-in-play-function`](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin/docs/rules/context-in-play-function.md)           | Pass a context when invoking play function of another story                                                                   |                       | <ul><li>recommended</li><li>flat/recommended</li><li>addon-interactions</li><li>flat/addon-interactions</li></ul>              |\n| [`storybook/csf-component`](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin/docs/rules/csf-component.md)                                 | The component property should be set                                                                                          |                       | <ul><li>csf</li><li>flat/csf</li><li>csf-strict</li><li>flat/csf-strict</li></ul>                                              |\n| [`storybook/default-exports`](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin/docs/rules/default-exports.md)                             | Story files should have a default export                                                                                      | ✅                    | <ul><li>csf</li><li>flat/csf</li><li>recommended</li><li>flat/recommended</li><li>csf-strict</li><li>flat/csf-strict</li></ul> |\n| [`storybook/hierarchy-separator`](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin/docs/rules/hierarchy-separator.md)                     | Deprecated hierarchy separator in title property                                                                              | ✅                    | <ul><li>csf</li><li>flat/csf</li><li>recommended</li><li>flat/recommended</li><li>csf-strict</li><li>flat/csf-strict</li></ul> |\n| [`storybook/meta-inline-properties`](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin/docs/rules/meta-inline-properties.md)               | Meta should only have inline properties                                                                                       |                       | N/A                                                                                                                            |\n| [`storybook/meta-satisfies-type`](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin/docs/rules/meta-satisfies-type.md)                     | Meta should use `satisfies Meta`                                                                                              | ✅                    | N/A                                                                                                                            |\n| [`storybook/no-redundant-story-name`](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin/docs/rules/no-redundant-story-name.md)             | A story should not have a redundant name property                                                                             | ✅                    | <ul><li>csf</li><li>flat/csf</li><li>recommended</li><li>flat/recommended</li><li>csf-strict</li><li>flat/csf-strict</li></ul> |\n| [`storybook/no-renderer-packages`](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin/docs/rules/no-renderer-packages.md)                   | Do not import renderer packages directly in stories                                                                           |                       | <ul><li>recommended</li><li>flat/recommended</li></ul>                                                                         |\n| [`storybook/no-stories-of`](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin/docs/rules/no-stories-of.md)                                 | storiesOf is deprecated and should not be used                                                                                |                       | <ul><li>csf-strict</li><li>flat/csf-strict</li></ul>                                                                           |\n| [`storybook/no-title-property-in-meta`](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin/docs/rules/no-title-property-in-meta.md)         | Do not define a title in meta                                                                                                 | ✅                    | <ul><li>csf-strict</li><li>flat/csf-strict</li></ul>                                                                           |\n| [`storybook/no-uninstalled-addons`](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin/docs/rules/no-uninstalled-addons.md)                 | This rule identifies storybook addons that are invalid because they are either not installed or contain a typo in their name. |                       | <ul><li>recommended</li><li>flat/recommended</li></ul>                                                                         |\n| [`storybook/prefer-pascal-case`](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin/docs/rules/prefer-pascal-case.md)                       | Stories should use PascalCase                                                                                                 | ✅                    | <ul><li>recommended</li><li>flat/recommended</li></ul>                                                                         |\n| [`storybook/story-exports`](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin/docs/rules/story-exports.md)                                 | A story file must contain at least one story export                                                                           |                       | <ul><li>recommended</li><li>flat/recommended</li><li>csf</li><li>flat/csf</li><li>csf-strict</li><li>flat/csf-strict</li></ul> |\n| [`storybook/use-storybook-expect`](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin/docs/rules/use-storybook-expect.md)                   | Use expect from `@storybook/test`, `storybook/test` or `@storybook/jest`                                                      | ✅                    | <ul><li>addon-interactions</li><li>flat/addon-interactions</li><li>recommended</li><li>flat/recommended</li></ul>              |\n| [`storybook/use-storybook-testing-library`](https://github.com/storybookjs/storybook/blob/next/code/lib/eslint-plugin/docs/rules/use-storybook-testing-library.md) | Do not use testing-library directly on stories                                                                                | ✅                    | <ul><li>addon-interactions</li><li>flat/addon-interactions</li><li>recommended</li><li>flat/recommended</li></ul>              |\n\n{/* RULES-LIST:END */}\n"
  },
  {
    "path": "docs/configure/integration/frameworks-feature-support.mdx",
    "content": "---\ntitle: 'Feature support for frameworks'\nhideRendererSelector: true\nsidebar:\n  order: 2\n  title: Feature support for frameworks\n---\n\nStorybook integrates with many popular frontend frameworks. We do our best to keep feature parity amongst frameworks, but it’s tricky for our modest team to support every framework.\n\nBelow is a comprehensive table of what’s supported in which framework integration. If you’d like a certain feature supported in your framework, we welcome pull requests.\n\n## Core frameworks\n\nCore frameworks have dedicated maintainers or contributors who are responsible for maintaining the integration. As such, you can use most Storybook features in these frameworks.\n\n|                                                                                               | React | Vue 3 | Angular | Web Components |\n| --------------------------------------------------------------------------------------------- | ----- | ----- | ------- | -------------- |\n| **Essentials**                                                                                |       |       |         |                |\n| [Actions](../../essentials/actions.mdx)                                                       | ✅    | ✅    | ✅      | ✅             |\n| [Backgrounds](../../essentials/backgrounds.mdx)                                               | ✅    | ✅    | ✅      | ✅             |\n| [Controls](../../essentials/controls.mdx)                                                     | ✅    | ✅    | ✅      | ✅             |\n| [Interactions](../../writing-tests/interaction-testing.mdx#debugging-interaction-tests)       | ✅    | ✅    | ✅      | ✅             |\n| [Measure](../../essentials/measure-and-outline.mdx#measure-addon)                             | ✅    | ✅    | ✅      | ✅             |\n| [Outline](../../essentials/measure-and-outline.mdx#outline-addon)                             | ✅    | ✅    | ✅      | ✅             |\n| [Viewport](../../essentials/viewport.mdx)                                                     | ✅    | ✅    | ✅      | ✅             |\n| **Addons**                                                                                    |       |       |         |                |\n| [A11y](../../writing-tests/accessibility-testing.mdx)                                         | ✅    | ✅    | ✅      | ✅             |\n| [Docs](../../writing-docs/index.mdx)                                                          | ✅    | ✅    | ✅      | ✅             |\n| [Test runner](../../writing-tests/integrations/test-runner.mdx)                               | ✅    | ✅    | ✅      | ✅             |\n| [Test coverage](../../writing-tests/test-coverage.mdx)                                        | ✅    | ✅    | ✅      | ✅             |\n| [CSS resources](https://github.com/storybookjs/addon-cssresources)                            | ✅    | ✅    | ✅      | ✅             |\n| [Design assets](https://github.com/storybookjs/addon-design-assets)                           | ✅    | ✅    | ✅      | ✅             |\n| [Events](https://github.com/storybookjs/addon-events)                                         | ✅    | ✅    | ✅      | ✅             |\n| [Google analytics](https://github.com/storybookjs/addon-google-analytics)                     | ✅    | ✅    | ✅      | ✅             |\n| [GraphQL](https://github.com/storybookjs/addon-graphql)                                       | ✅    |       | ✅      |                |\n| [Jest](https://github.com/storybookjs/addon-jest)                                             | ✅    | ✅    | ✅      | ✅             |\n| [Links](https://github.com/storybookjs/storybook/tree/next/code/addons/links)                 | ✅    | ✅    | ✅      | ✅             |\n| [Queryparams](https://github.com/storybookjs/addon-queryparams)                               | ✅    | ✅    | ✅      | ✅             |\n| **Docs**                                                                                      |       |       |         |                |\n| [CSF Stories](../../api/csf/index.mdx)                                                              | ✅    | ✅    | ✅      | ✅             |\n| [Autodocs](../../writing-docs/autodocs.mdx)                                                   | ✅    | ✅    | ✅      | ✅             |\n| [Doc Blocks - ArgTypes](../../api/doc-blocks/doc-block-argtypes.mdx)                          | ✅    | ✅    | ✅      | ✅             |\n| [Doc Blocks - Canvas](../../api/doc-blocks/doc-block-canvas.mdx)                              | ✅    | ✅    | ✅      | ✅             |\n| [Doc Blocks - ColorPalette](../../api/doc-blocks/doc-block-colorpalette.mdx)                  | ✅    | ✅    | ✅      | ✅             |\n| [Doc Blocks - Controls](../../api/doc-blocks/doc-block-controls.mdx)                          | ✅    | ✅    | ✅      | ✅             |\n| [Doc Blocks - Description](../../api/doc-blocks/doc-block-description.mdx)                    | ✅    | ✅    | ✅      | ✅             |\n| [Doc Blocks - IconGallery](../../api/doc-blocks/doc-block-icongallery.mdx)                    | ✅    | ✅    | ✅      | ✅             |\n| [Doc Blocks - Markdown](../../api/doc-blocks/doc-block-markdown.mdx)                          | ✅    | ✅    | ✅      | ✅             |\n| [Doc Blocks - Meta](../../api/doc-blocks/doc-block-meta.mdx)                                  | ✅    | ✅    | ✅      | ✅             |\n| [Doc Blocks - Primary](../../api/doc-blocks/doc-block-primary.mdx)                            | ✅    | ✅    | ✅      | ✅             |\n| [Doc Blocks - Source](../../api/doc-blocks/doc-block-source.mdx)                              | ✅    | ✅    | ✅      | ✅             |\n| [Doc Blocks - Story](../../api/doc-blocks/doc-block-story.mdx)                                | ✅    | ✅    | ✅      | ✅             |\n| [Doc Blocks - Stories](../../api/doc-blocks/doc-block-stories.mdx)                            | ✅    | ✅    | ✅      | ✅             |\n| [Doc Blocks - Subtitle](../../api/doc-blocks/doc-block-subtitle.mdx)                          | ✅    | ✅    | ✅      | ✅             |\n| [Doc Blocks - Title](../../api/doc-blocks/doc-block-title.mdx)                                | ✅    | ✅    | ✅      | ✅             |\n| [Doc Blocks - Typeset](../../api/doc-blocks/doc-block-typeset.mdx)                            | ✅    | ✅    | ✅      | ✅             |\n| [Doc Blocks - Unstyled](../../api/doc-blocks/doc-block-unstyled.mdx)                          | ✅    | ✅    | ✅      | ✅             |\n| [Doc Blocks - UseOf](../../api/doc-blocks/doc-block-useof.mdx)                                | ✅    | ✅    | ✅      | ✅             |\n| Inline stories                                                                                | ✅    | ✅    | ✅      | ✅             |\n\n## Community frameworks\n\nCommunity frameworks have fewer contributors which means they may not be as up to date as core frameworks. If you use one of these frameworks for your job, please consider contributing to its integration with Storybook.\n\n|                                                                                               | Ember | HTML | Svelte | Preact | Qwik | SolidJS |\n| --------------------------------------------------------------------------------------------- | ----- | ---- | ------ | ------ | ---- | ------- |\n| **Essentials**                                                                                |       |      |        |        |      |         |\n| [Actions](../../essentials/actions.mdx)                                                       | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Backgrounds](../../essentials/backgrounds.mdx)                                               | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Controls](../../essentials/controls.mdx)                                                     | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Interactions](../../writing-tests/interaction-testing.mdx#debugging-interaction-tests)       |       | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Measure](../../essentials/measure-and-outline.mdx#measure-addon)                             | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Outline](../../essentials/measure-and-outline.mdx#outline-addon)                             | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Viewport](../../essentials/viewport.mdx)                                                     | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| **Addons**                                                                                    |       |      |        |        |      |         |\n| [A11y](../../writing-tests/accessibility-testing.mdx)                                         | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Docs](../../writing-docs/index.mdx)                                                          | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Test runner](../../writing-tests/integrations/test-runner.mdx)                               |       | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Test coverage](../../writing-tests/test-coverage.mdx)                                        |       | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [CSS resources](https://github.com/storybookjs/addon-cssresources)                            | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Design assets](https://github.com/storybookjs/addon-design-assets)                           | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Events](https://github.com/storybookjs/addon-events)                                         | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Google analytics](https://github.com/storybookjs/addon-google-analytics)                     | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [GraphQL](https://github.com/storybookjs/addon-graphql)                                       |       |      |        |        |      |         |\n| [Jest](https://github.com/storybookjs/addon-jest)                                             | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Links](https://github.com/storybookjs/storybook/tree/next/code/addons/links)                 | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Queryparams](https://github.com/storybookjs/addon-queryparams)                               | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| **Docs**                                                                                      |       |      |        |        |      |         |\n| [CSF Stories](../../api/csf/index.mdx)                                                              | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Autodocs](../../writing-docs/autodocs.mdx)                                                   |       | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Doc Blocks - ArgTypes](../../api/doc-blocks/doc-block-argtypes.mdx)                          | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Doc Blocks - Canvas](../../api/doc-blocks/doc-block-canvas.mdx)                              | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Doc Blocks - ColorPalette](../../api/doc-blocks/doc-block-colorpalette.mdx)                  | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Doc Blocks - Controls](../../api/doc-blocks/doc-block-controls.mdx)                          | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Doc Blocks - Description](../../api/doc-blocks/doc-block-description.mdx)                    | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Doc Blocks - IconGallery](../../api/doc-blocks/doc-block-icongallery.mdx)                    | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Doc Blocks - Markdown](../../api/doc-blocks/doc-block-markdown.mdx)                          | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Doc Blocks - Meta](../../api/doc-blocks/doc-block-meta.mdx)                                  | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Doc Blocks - Primary](../../api/doc-blocks/doc-block-primary.mdx)                            | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Doc Blocks - Source](../../api/doc-blocks/doc-block-source.mdx)                              | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Doc Blocks - Story](../../api/doc-blocks/doc-block-story.mdx)                                | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Doc Blocks - Stories](../../api/doc-blocks/doc-block-stories.mdx)                            | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Doc Blocks - Subtitle](../../api/doc-blocks/doc-block-subtitle.mdx)                          | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Doc Blocks - Title](../../api/doc-blocks/doc-block-title.mdx)                                | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Doc Blocks - Typeset](../../api/doc-blocks/doc-block-typeset.mdx)                            | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Doc Blocks - Unstyled](../../api/doc-blocks/doc-block-unstyled.mdx)                          | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| [Doc Blocks - UseOf](../../api/doc-blocks/doc-block-useof.mdx)                                | ✅    | ✅   | ✅     | ✅     | ✅   | ✅      |\n| Inline stories                                                                                |       | ✅   | ✅     |        |      |         |\n\n## Deprecated\n\nTo align the Storybook ecosystem with the current state of frontend development, the following features and addons are now deprecated, no longer maintained, and will be removed in future versions of Storybook\n\n| Feature                                                                            | Status                                                                                                                                                                                                                                                                                                             |\n| ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| [Knobs](https://github.com/storybookjs/addon-knobs)                                | The Knobs addon was officially deprecated with the release of Storybook 6.3 and is no longer actively maintained. We recommend using the [controls](../../essentials/controls.mdx) instead.                                                                                                                        |\n| Storyshots                                                                         | The Storyshots addon was officially deprecated with the release of Storybook 7.6, is no longer actively maintained and was removed in Storybook 8. See the [migration guide](../../../release-8-6/docs/writing-tests/snapshot-testing/storyshots-migration-guide.mdx) for the available alternatives.                 |\n| StoriesOf                                                                          | The `storiesOf` API was officially removed with the release of Storybook 8 and is no longer maintained. We recommend using the [CSF API](../../api/csf/index.mdx) instead for writing stories.<br />See the [migration guide](../../releases/migration-guide-from-older-version.mdx#major-breaking-changes) for more information. |\n| Storysource                                                                        | The Storysource addon was officially removed with the release of Storybook 9 and is no longer maintained. To display your stories' source code, we recommend using the [`codePanel`](../../writing-docs/code-panel.mdx) parameter instead.                                                                         |\n"
  },
  {
    "path": "docs/configure/integration/frameworks.mdx",
    "content": "---\ntitle: 'Framework support'\nsidebar:\n  order: 1\n  title: Frameworks\n---\n\nFrameworks are packages that auto-configure Storybook to work with most common environment setups. They simplify the setup process and reduce boilerplate by mirroring your framework's conventions to create applications.\n\n## How do frameworks work in Storybook?\n\nYou start by [installing](../../get-started/install.mdx) Storybook into an existing project. Then, it tries to detect the framework you're using and automatically configures Storybook to work with it. That means adding the necessary libraries as dependencies and adjusting the configuration. Finally, starting Storybook will automatically load the framework configuration before loading any existing addons to match your application environment.\n\n## Which frameworks are supported?\n\nStorybook provides support for the leading industry builders and frameworks. However, that doesn't mean you can't use Storybook with other frameworks. Below is a list of currently supported frameworks divided by their builders.\n\n| Builder | Framework                                                                  |\n| ------- | -------------------------------------------------------------------------- |\n| Webpack | React, Angular, Vue 3, Web Components, NextJS, HTML, Ember, Preact, Svelte |\n| Vite    | React, Vue 3, Web Components, HTML, Svelte, SvelteKit, Qwik, Solid         |\n\n### What about feature support?\n\nIn addition to supporting the most popular frameworks in the industry, Storybook also tries to retain the same level of feature support for each framework, including the addon ecosystem. For more information, see [Framework support](./frameworks-feature-support.mdx) for a comprehensive list of which features and addons are currently maintained with the community's help.\n\n## Configure\n\nEvery modern web application has unique requirements and relies on various tools and frameworks. By default, with Storybook, you get an out-of-the-box configuration generated to work with most frameworks. However, you can extend your existing configuration file (i.e., `./storybook/main.js|ts|cjs`) and provide additional options. Below is an abridged table with available options and examples of configuring Storybook for your framework.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-framework.md\" />\n\n{/* prettier-ignore-end */}\n\n| Option           | Description                                                                                                                                                                                                                                                      | Framework |\n| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |\n| `nextConfigPath` | Sets the default path for the NextJS configuration file<br />`framework: { name: '@storybook/nextjs', options: { nextConfigPath: '../next.config.js'} }`                                                                                                         | NextJS    |\n| `builder`        | Configures [Webpack 5](../../builders/webpack.mdx) builder options for NextJS<br /> `core: { builder: { name:'webpack5', options: { lazyCompilation: true} }}`                                                                                                   | NextJS    |\n| `strictMode`     | Enables React's [strict mode](https://reactjs.org/docs/strict-mode.html)<br />`framework: { name: '@storybook/react-webpack5', options: { strictMode: false } }`                                                                                                 | React     |\n| `legacyRootApi`  | Requires React 18. Toggles support for React's [legacy root API](https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html#updates-to-client-rendering-apis)<br />`framework: { name: '@storybook/react-webpack5', options: { legacyRootApi: true } }`     | React     |\n| `enableIvy`      | Enabled by default with Angular 9+. Replaces the default compiler with the [Ivy compiler](https://docs.angular.lat/guide/ivy)<br />`framework: { name: '@storybook/angular', options: { enableIvy: true } }`                                                     | Angular   |\n| `enableNgcc`     | Enabled by default with Angular 9+. Adds support for ngcc for backwards compatibility<br />`framework: { name: '@storybook/angular', options: { enableNgcc: false } }`                                                                                           | Angular   |\n\n***\n\n## Troubleshooting\n\n### NextJS 13 doesn't work with Storybook\n\nWith the release of Next.js [version 13](https://nextjs.org/blog/next-13), it introduced breaking changes (e.g., [TurboPack](https://turbo.build/pack), [Server Components](https://nextjs.org/docs/advanced-features/react-18/server-components)) that are not yet fully supported by Storybook. The Storybook team is working on adding support for these features. In the meantime, you can still use Storybook alongside your Next.js 13 project if you're not relying on them.\n\n### My framework doesn't work with Storybook\n\nOut of the box, most frameworks work seamlessly with Storybook. However, some frameworks (e.g., [CRACO](https://craco.js.org/)) provide their own configuration that Storybook isn't prepared to handle without additional steps, either [via addon](../../addons/writing-presets.mdx) or integration. To learn more, read our [addons guide](../../addons/index.mdx).\n\n### How do I build a Storybook framework?\n\nStorybook is a framework-agnostic tool. It can be used with any framework. However, to make it easier for you to get started, we provide instructions that you can use to build your framework. To learn more, read our [frameworks guide](../../contribute/framework.mdx).\n\n### Legacy framework support\n\nWe're deprecating support for several frameworks, including [Aurelia](https://github.com/aurelia/framework), [Marionette](https://github.com/marionettejs/backbone.marionette), [Mithril](https://github.com/MithrilJS/mithril.js), [Rax](https://github.com/alibaba/rax), and [Riot](https://github.com/riot/riot). Nevertheless, we're always looking for help maintaining these frameworks. If you're working with one of them and you want to continue supporting them, visit the dedicated [Storybook End-of-Life repository](https://github.com/storybook-eol). To learn more about the sunsetting process and view instructions on how to contribute, read our [documentation](../../contribute/index.mdx).\n\n### Learn about configuring Storybook\n\n* [Theming](../user-interface/theming.mdx) to customize the look and feel of Storybook's UI\n* [CSS](../styling-and-css.mdx) to configure CSS support\n* [Images & assets](./images-and-assets.mdx) for static asset handling\n* [Environment variables](../environment-variables.mdx) to configure environment variables\n"
  },
  {
    "path": "docs/configure/integration/images-and-assets.mdx",
    "content": "---\ntitle: 'Images, fonts, and assets'\nsidebar:\n  order: 6\n  title: Images and assets\n---\n\nComponents often rely on images, videos, fonts, and other assets to render as the user expects. There are many ways to use these assets in your story files.\n\n## Import assets into stories\n\nYou can import any media assets by importing (or requiring) them. It works out of the box with our default config. But, if you are using a custom webpack config, you’ll need to add the [file loader](https://webpack.js.org/loaders/) to handle the required files.\n\nAfterward, you can use any asset in your stories:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"component-story-static-asset-with-import.md\" />\n\n{/* prettier-ignore-end */}\n\n## Serving static files via Storybook Configuration\n\nWe recommend serving static files via Storybook to ensure that your components always have the assets they need to load. We recommend this technique for assets that your components often use, like logos, fonts, and icons.\n\nConfigure a directory (or a list of directories) where your assets live when starting Storybook. Use the `staticDirs` configuration element in your main Storybook configuration file (i.e., `.storybook/main.js|ts`) to specify the directories:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-static-dirs.md\" />\n\n{/* prettier-ignore-end */}\n\nHere `../public` is your static directory. Now use it in a component or story like this.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"component-story-static-asset-without-import.md\" />\n\n{/* prettier-ignore-end */}\n\nYou can also pass a list of directories separated by commas without spaces instead of a single directory.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-static-dirs.md\" />\n\n{/* prettier-ignore-end */}\n\nOr even use a configuration object to define the directories:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-static-dirs-with-object.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\nWhen using Vite-based frameworks, additional directories may be copied to your build directory because of Vite's own [static asset handling](https://vite.dev/guide/assets#the-public-directory). You can set Vite's `publicDir` option to `false` to disable this behavior.\n</Callout>\n\n## Reference assets from a CDN\n\nUpload your files to an online CDN and reference them. In this example, we’re using a placeholder image service.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"component-story-static-asset-cdn.md\" />\n\n{/* prettier-ignore-end */}\n\n## Absolute versus relative paths\n\nSometimes, you may want to deploy your Storybook into a subpath, like `https://example.com/storybook`.\n\nIn this case, you need to have all your images and media files with relative paths. Otherwise, the browser cannot locate those files.\n\nIf you load static content via importing, this is automatic, and you do not have to do anything.\n\nSuppose you are serving assets in a [static directory](#serving-static-files-via-storybook-configuration) along with your Storybook. In that case, you need to use relative paths to load images or use the base element.\n\n## Referencing Fonts in Stories\n\nAfter configuring Storybook to serve assets from your static folder, you can reference those assets in Storybook. For example, you can reference and apply a custom font to your stories. To do this, create a [`preview-head.html`](../story-rendering.mdx) file inside the configuration directory (i.e., `.storybook`) and add a `<link />` tag to reference your font.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-head-example.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/configure/integration/index.mdx",
    "content": "---\ntitle: Integration\nsidebar:\n  order: 4\n  title: Integration\n---"
  },
  {
    "path": "docs/configure/integration/typescript.mdx",
    "content": "---\ntitle: 'TypeScript'\nsidebar:\n  order: 4\n  title: Typescript\n---\n\nStorybook provides an integrated [TypeScript](https://www.typescriptlang.org/) experience, including zero-configuration setup and built-in types for APIs, addons, and stories.\n\n## Configure Storybook with TypeScript\n\nStorybook's configuration file (i.e., `main.ts`) is defined as an ESM module written in TypeScript, providing you with the baseline configuration to support your existing framework while enabling you stricter type-checking and autocompletion in your editor. Below is an abridged configuration file.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-typical.md\" />\n\n{/* prettier-ignore-end */}\n\nSee the [main configuration API reference](../../api/main-config/main-config.mdx) for more details and additional properties.\n\n<Callout variant=\"info\" icon=\"💡\">\n  See the Vite builder [TypeScript documentation](https://github.com/storybookjs/builder-vite#typescript) if using `@storybook/builder-vite`.\n</Callout>\n\n### Extending the default configuration\n\n<IfRenderer renderer={['angular', 'vue', 'web-components', 'ember', 'html', 'svelte', 'preact', 'qwik', 'solid' ]}>\n  Out of the box, Storybook is built to work with a wide range of third-party libraries, enabling you to safely access and document metadata (e.g., props, inputs) from your components without any additional configuration. Since Storybook supports multiple frameworks, it also includes a set of third-party packages to support each framework (e.g., `ts-loader`, `vue-docgen-api` for Vue). If you need to customize the default configuration for a specific use case scenario, you can adjust your Storybook configuration file and provide the required options. Listed below are the available options and examples of how to use them.\n\n  | Option         | Description                                                                                                                                                                                                    |\n  | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n  | `check`        | Available for Webpack-based projects.<br />Enables type checking within Storybook<br />`typescript: { check: true },`                                                                                          |\n  | `checkOptions` | Requires the `check` option to be enabled.<br />Configures the [`fork-ts-checker-webpack-plugin`](https://github.com/TypeStrong/fork-ts-checker-webpack-plugin) plugin<br />`typescript: { checkOptions:{},},` |\n  | `skipCompiler` | Disables parsing Typescript files through the compiler<br />`typescript: { skipCompiler:false,},`                                                                                                              |\n</IfRenderer>\n\n<IfRenderer renderer=\"react\">\n  Out of the box, Storybook is built to work with a wide range of third-party libraries, enabling you to safely access and document metadata (e.g., props) for your components without any additional configuration. It relies on [`react-docgen`](https://github.com/reactjs/react-docgen), a fast and highly customizable parser to process TypeScript files to infer the component's metadata and generate types automatically for improved performance and type safety. If you need to customize the default configuration for a specific use case scenario, you can adjust your Storybook configuration file and provide the required options. Listed below are the available options and examples of how to use them.\n\n  | Option                         | Description                                                                                                                                                                                                                                 |\n  | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n  | `check`                        | Available for Webpack-based projects.<br />Enables type checking within Storybook<br />`typescript: { check: true },`                                                                                                                       |\n  | `checkOptions`                 | Requires the `check` option to be enabled.<br />Configures the [`fork-ts-checker-webpack-plugin`](https://github.com/TypeStrong/fork-ts-checker-webpack-plugin) plugin<br />`typescript: { checkOptions: {},},`                             |\n  | `reactDocgen`                  | Configures the TypeScript parser used by Storybook.<br />Available options: `react-docgen` (default), `react-docgen-typescript`,` false`<br /> `typescript: { reactDocgen: 'react-docgen'},`                                                |\n  | `reactDocgenTypescriptOptions` | Requires the `reactDocgen`option to be `react-docgen-typescript`.<br /> Configures the `react-docgen-typescript-plugin` plugin per builder<br />`typescript: { reactDocgen: 'react-docgen-typescript', reactDocgenTypescriptOptions: {},},` |\n  | `skipCompiler`                 | Disables parsing Typescript files through the compiler<br />`typescript: { skipCompiler:false,},`                                                                                                                                           |\n</IfRenderer>\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-extend-ts-config.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout>\n  Additional options are available for the `typescript` configuration option. See the [`config.typescript` API reference](../../api/main-config/main-config-typescript.mdx) for more information.\n</Callout>\n\n## Write stories with TypeScript\n\nStorybook provides zero-config TypeScript support, allowing you to write stories using this language without additional configuration. You can use this format for improved type safety and code completion. For example, if you're testing a `Button` component, you could do the following in your story file:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-baseline.md\" />\n\n{/* prettier-ignore-end */}\n\nThe example above uses the power of TypeScript in combination with the exported generic types (`Meta` and `StoryObj`) to tell Storybook how to infer the component's metadata and the type of the component's inputs (e.g., props). This can greatly improve the developer experience by letting your IDE show you what properties are injected by Storybook.\n\n### TypeScript 4.9 support\n\nAssuming that you're working on a project that uses TypeScript 4.9+, you can update your component stories to use the new [`satisfies`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html) operator to ensure stricter type checking for your component stories. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-baseline-with-satisfies.md\" />\n\n{/* prettier-ignore-end */}\n\nNow, when you define a story or update an existing one, you'll automatically get notified that you're missing a required [`arg`](../../writing-stories/args.mdx). However, you're not limited to using the `satisfies` operator at the component level. If you need, you can also use it at the story level. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-baseline-with-satisfies-story-level.md\" />\n\n{/* prettier-ignore-end */}\n\n## Troubleshooting\n\n### The `satisfies` operator is not working as expected\n\nOut of the box, Storybook supports the `satisfies` operator for almost every framework already using TypeScript version 4.9 or higher. However, due to the constraints of the Angular and Web Components framework, you might run into issues when applying this operator for additional type safety. This is primarily due to how both frameworks are currently implemented, making it almost impossible for Storybook to determine if the component property is required. If you encounter this issue, please open up a support request on [GitHub Discussions](https://github.com/storybookjs/storybook/discussions/new?category=help).\n\n<IfRenderer renderer={[ 'vue', 'svelte' ]}>\n  ### The TypeScript auto-completion is not working on my editor\n\n  If you're using Vue single file components and TypeScript, you can add the official [Vue](https://marketplace.visualstudio.com/items?itemName=Vue.volar) extension for editor support, additional type safety and auto-completion. Nevertheless, if you're working with Svelte, you can add the [Svelte for VSCode extension](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) for similar benefits.\n</IfRenderer>\n\n<IfRenderer renderer=\"react\">\n  ### Storybook doesn't create the required types for external packages\n\n  If your project relies on a third-party library and the expected types are not being generated, preventing you from accurately documenting your components, you can adjust the `reactDocgen` configuration option in your Storybook configuration file to use `react-docgen-typescript` instead and include the required options. For example:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"storybook-main-prop-filter.md\" />\n\n  {/* prettier-ignore-end */}\n\n  ### Inherited args are missing for components from workspace packages\n\n  If you're using `react-docgen-typescript` in a monorepo with npm/yarn/pnpm workspaces, you may find that components imported from a workspace package are missing inherited args (e.g., MUI's `ButtonProps`), while the same component imported locally works fine.\n\n  This happens because the underlying Vite plugin creates a TypeScript program from files matching its `include` glob (default: `**/**.tsx`), resolved from the Storybook project's directory. Workspace package files are outside that directory and aren't included in the program, so inherited types can't be resolved.\n\n  To fix this, add your workspace package source files to the `include` option:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"storybook-main-rdt-monorepo-include.md\" />\n\n  {/* prettier-ignore-end */}\n\n  Adjust the path (`../../packages/ui/src/**/*.tsx`) to match your monorepo layout. You might expect that pointing `tsconfigPath` to a tsconfig that includes your workspace packages would solve this, but `tsconfigPath` only affects which compiler options are used. It does not change which files are included in the TypeScript program.\n\n  ### The types are not being generated for my component\n\n  If you're working with a React project, type inference is automatically enabled for your components using the `react-docgen` library for improved build times and type safety. However, you may run into a situation where some options may not work as expected (e.g., [`Enums`](https://www.typescriptlang.org/docs/handbook/enums.html), React's [`forwardRef`](https://react.dev/reference/react/forwardRef)). This is primarily due to how the `react-docgen` package is implemented, making it difficult for Storybook to infer the component's metadata and generate types automatically. To solve this, you can update the `typescript` configuration option in your Storybook configuration file to use `react-docgen-typescript` instead. For example:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"storybook-main-react-docgen-typescript.md\" />\n\n  {/* prettier-ignore-end */}\n\n  If you're still encountering issues, we recommend reaching out to the community using the default communication channels (e.g., [GitHub discussions](https://github.com/storybookjs/storybook/discussions/new?category=help)).\n</IfRenderer>\n"
  },
  {
    "path": "docs/configure/story-layout.mdx",
    "content": "---\ntitle: 'Story layout'\nsidebar:\n  order: 6\n  title: Story layout\n---\n\nThe `layout` [parameter](../writing-stories/parameters.mdx) allows you to configure how stories are positioned in Storybook's Canvas tab.\n\n## Global layout\n\nYou can add the parameter to your [`./storybook/preview.js`](./index.mdx#configure-story-rendering), like so:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-layout-param.md\" />\n\n{/* prettier-ignore-end */}\n\n![Layout params centered story](../_assets/configure/layout-params-story-centered.png)\n\nIn the example above, Storybook will center all stories in the UI. `layout` accepts these options:\n\n* `centered`: center the component horizontally and vertically in the Canvas\n* `fullscreen`: allow the component to expand to the full width and height of the Canvas\n* `padded`: *(default)* Add extra padding around the component\n\n## Component layout\n\nYou can also set it at a component level like so:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-component-layout-param.md\" />\n\n{/* prettier-ignore-end */}\n\n## Story layout\n\nOr even apply it to specific stories like so:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-story-layout-param.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/configure/story-rendering.mdx",
    "content": "---\ntitle: 'Story rendering'\nsidebar:\n  order: 5\n  title: Story rendering\n---\n\nIn Storybook, your stories render in a particular “preview” iframe (also called the Canvas) inside the larger Storybook web application. The JavaScript build configuration of the preview is controlled by a [builder](../builders/index.mdx) config, but you also may want to run some code for every story or directly control the rendered HTML to help your stories render correctly.\n\n## Running code for every story\n\nCode executed in the preview file (`.storybook/preview.js|ts`) runs for every story in your Storybook. This is useful for setting up global styles, initializing libraries, or anything else required to render your components.\n\n<If notRenderer={['angular', 'vue']}>\n  Here's an example of how you might use the preview file to initialize a library that must run before your components render:\n\n  <CodeSnippets path=\"initialize-library-in-preview.md\" />\n</If>\n\n<If renderer={['angular', 'vue']}>\n  For example, with Vue, you can extend Storybook's application and register your library (e.g., [Fontawesome](https://github.com/FortAwesome/vue-fontawesome)). Or with Angular, add the package ([localize](https://angular.io/api/localize)) into your `polyfills.ts` and import it:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"storybook-preview-with-library-decorator.md\" />\n\n  {/* prettier-ignore-end */}\n</If>\n\n## Adding to \\<head>\n\nIf you need to add extra elements to the `head` of the preview iframe, for instance, to load static stylesheets, font files, or similar, you can create a file called [`.storybook/preview-head.html`](./index.mdx#configure-story-rendering) and add tags like this:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-head-example.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  Storybook will inject these tags into the *preview iframe* where your components render, not the Storybook application UI.\n</Callout>\n\nHowever, it's also possible to modify the preview head HTML programmatically using a preset defined in the `main.js` file. Read the [presets documentation](../addons/writing-presets.mdx#ui-configuration) for more information.\n\n## Adding to \\<body>\n\nSometimes, you may need to add different tags to the `<body>`. Helpful for adding some custom content roots.\n\nYou can accomplish this by creating a file called `preview-body.html` inside your `.storybook` directory and adding tags like this:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-body-example.md\" />\n\n{/* prettier-ignore-end */}\n\nIf using relative sizing in your project (like `rem` or `em`), you may update the base `font-size` by adding a `style` tag to `preview-body.html`:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-body-font-size.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  Storybook will inject these tags into the *preview iframe* where your components render, not the Storybook application UI.\n</Callout>\n\nJust like how you have the ability to customize the preview `head` HTML tag, you can also follow the same steps to customize the preview `body` with a preset. To obtain more information on how to do this, refer to the [presets documentation](../addons/writing-presets.mdx#ui-configuration).\n"
  },
  {
    "path": "docs/configure/styling-and-css.mdx",
    "content": "---\ntitle: 'Styling and CSS'\nsidebar:\n  order: 1\n  title: Styling and CSS\n---\n\n{/* Not Angular */}\n\n<If notRenderer=\"angular\">\n  There are many ways to include CSS in a web application, and correspondingly there are many ways to include CSS in Storybook. Usually, it is best to try and replicate what your application does with styling in Storybook’s configuration.\n\n  ## CSS\n\n  Storybook supports importing CSS files in a few different ways. Storybook will inject these tags into the preview iframe where your components render, not the Storybook Manager UI. The best way to import CSS depends on your project's configuration and your preferences.\n\n  ### Import bundled CSS (Recommended)\n\n  All Storybooks are pre-configured to recognize imports for CSS files. To add global CSS for all your stories, import it in [`.storybook/preview.ts`](./index.mdx#configure-story-rendering). These files will be subject to HMR, so you can see your changes without restarting your Storybook server.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"storybook-preview-import-global-styles.md\" />\n\n  {/* prettier-ignore-end */}\n\n  If your component files import their CSS files, this will work too. However, if you're using CSS processor tools like Sass or Postcss, you may need some more configuration.\n\n  ### Include static CSS\n\n  If you have a global CSS file that you want to include in all your stories, you can import it in [`.storybook/preview-head.html`](./story-rendering.mdx#adding-to-head).\n  However, these files will not be subject to HMR, so you'll need to restart your Storybook server to see your changes.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"storybook-preview-head-import-global-styles.md\" />\n\n  {/* prettier-ignore-end */}\n\n  ## CSS modules\n\n  ### Vite\n\n  Vite comes with CSS modules support out-of-the-box. If you have customized the CSS modules configuration in your `vite.config.js` this will automatically be applied to your Storybook as well. Read more about [Vite's CSS modules support](https://vitejs.dev/guide/features.html#css-modules).\n\n  ### Webpack\n\n  <IfRenderer renderer=\"react\">\n    <Callout variant=\"info\" icon=\"📣\" title=\"Using `@storybook/nextjs`?\">\n      Storybook recreates your Next.js configuration, so you can use CSS modules in your stories without any extra configuration.\n    </Callout>\n  </IfRenderer>\n\n  If you're using Webpack and want to use CSS modules, you'll need some extra configuration. We recommend installing [`@storybook/addon-styling-webpack`](https://storybook.js.org/addons/@storybook/addon-styling-webpack/) to help you configure these tools.\n\n  ## PostCSS\n\n  ### Vite\n\n  Vite comes with PostCSS support out-of-the-box. If you have customized the PostCSS configuration in your `vite.config.js` this will automatically be applied to your Storybook as well. Read more about [Vite's PostCSS support](https://vitejs.dev/guide/features.html#postcss).\n\n  ### Webpack\n\n  <IfRenderer renderer=\"react\">\n    <Callout variant=\"info\" icon=\"📣\" title=\"Using `@storybook/nextjs`?\">\n      Storybook recreates your Next.js configuration, so you can use PostCSS in your stories without any extra configuration.\n    </Callout>\n  </IfRenderer>\n\n  If you're using Webpack and want to use PostCSS, you'll need some extra configuration. We recommend installing [`@storybook/addon-styling-webpack`](https://storybook.js.org/addons/@storybook/addon-styling-webpack/) to help you configure these tools.\n\n  ## CSS pre-processors\n\n  ### Vite\n\n  Vite comes with Sass, Less, and Stylus support out-of-the-box. Read more about [Vite's CSS Pre-processor support](https://vitejs.dev/guide/features.html#css-pre-processors).\n\n  ### Webpack\n\n  <IfRenderer renderer=\"react\">\n    <Callout variant=\"info\" icon=\"📣\" title=\"Using `@storybook/nextjs`?\">\n      Storybook recreates your Next.js configuration, so you can use Sass in your stories without any extra configuration.\n    </Callout>\n  </IfRenderer>\n\n  If you're using Webpack and want to use Sass or less, you'll need some extra configuration. We recommend installing [`@storybook/addon-styling-webpack`](https://storybook.js.org/addons/@storybook/addon-styling-webpack/) to help you configure these tools. Or if you'd prefer, you can customize [Storybook's webpack configuration yourself](../builders/webpack.mdx#override-the-default-configuration) to include the appropriate loader(s).\n\n  ## CSS-in-JS\n\n  CSS-in-JS libraries are designed to use basic JavaScript, and they often work in Storybook without any extra configuration. Some libraries expect components to render in a specific rendering “context” (for example, to provide themes), which can be accomplished with `@storybook/addon-themes`'s [`withThemeFromJSXProvider` decorator](https://github.com/storybookjs/storybook/blob/next/code/addons/themes/docs/api.md#withthemefromjsxprovider).\n\n  ## Adding webfonts\n\n  ### `.storybook/preview-head.html`\n\n  If you need webfonts to be available, you may need to add some code to the [`.storybook/preview-head.html`](./story-rendering.mdx#adding-to-head) file. We recommend including any assets with your Storybook if possible, in which case you likely want to configure the [static file location](./integration/images-and-assets.mdx#serving-static-files-via-storybook-configuration).\n\n  ### `.storybook/preview.ts`\n\n  If you're using something like [`fontsource`](https://fontsource.org/) for your fonts, you can import the needed css files in your [`.storybook/preview.ts`](./index.mdx#configure-story-rendering) file.\n</If>\n\n{/* Angular only */}\n\n<IfRenderer renderer=\"angular\">\n  Storybook for Angular relies on the Angular CLI to build your stories. This means that you can use any CSS preprocessor that the Angular CLI supports. You can read more about this in the [Angular CLI documentation](https://angular.io/guide/workspace-config#style-script-config).\n\n  ## Global styles\n\n  To add global styles to your Storybook, you can add them to the `styles` array in your `angular.json` file. This will add the styles to the preview iframe where your components render, not the Storybook Manager UI.\n\n  Don't forget to also add your global styles to your `build-storybook` target in your `angular.json` file. This will ensure that your global styles are included in the static build of your Storybook as well.\n\n  ```json title=\"angular.json\"\n  {\n    \"storybook\": {\n      \"builder\": \"@storybook/angular:start-storybook\",\n      \"options\": {\n        \"configDir\": \".storybook\",\n        \"browserTarget\": \"angular-latest:build\",\n        \"compodoc\": true,\n        \"compodocArgs\": [\"-e\", \"json\", \"-d\", \".\"],\n        \"port\": 6006,\n        \"styles\": [\n          // Add your global styles here\n          \"@angular/material/prebuilt-themes/indigo-pink.css\",\n          \"@fontsource/roboto/300.css\",\n          \"@fontsource/roboto/400.css\",\n          \"@fontsource/roboto/500.css\",\n          \"@fontsource/roboto/700.css\",\n          \"@fontsource/material-icons\",\n          \"src/styles.scss\"\n        ]\n      }\n    },\n    \"build-storybook\": {\n      \"builder\": \"@storybook/angular:build-storybook\",\n      \"options\": {\n        \"configDir\": \".storybook\",\n        \"browserTarget\": \"angular-latest:build\",\n        \"compodoc\": true,\n        \"compodocArgs\": [\"-e\", \"json\", \"-d\", \".\"],\n        \"styles\": [\n          // Add your global styles here\n          \"@angular/material/prebuilt-themes/indigo-pink.css\",\n          \"@fontsource/roboto/300.css\",\n          \"@fontsource/roboto/400.css\",\n          \"@fontsource/roboto/500.css\",\n          \"@fontsource/roboto/700.css\",\n          \"@fontsource/material-icons\",\n          \"src/styles.scss\"\n        ],\n        \"outputDir\": \"storybook-static\"\n      }\n    }\n  }\n  ```\n\n  ## Troubleshooting\n\n  If you're working with Storybook and [Nx libraries](https://nx.dev/structure/library-types), you can extend your project's configuration (i.e., project.json) and provide the application's styles.\n\n  For earlier Nx versions (before 14.1.8), your configuration would look like this:\n\n  ```json title=\"project.json\"\n  {\n    \"build-storybook\": {\n      \"executor\": \"@nrwl/storybook:build\",\n      \"outputs\": [\"{options.outputPath}\"],\n      \"options\": {\n        \"uiFramework\": \"@storybook/angular\",\n        \"outputPath\": \"dist/storybook/example-lib\",\n        \"config\": {\n          \"configFolder\": \"libs/example-lib/storybook/.storybook\"\n        },\n        \"projectBuildConfig\": \"example-lib:build-storybook\",\n        \"styles\": [\"apps/example-app/src/styles.scss\"]\n      }\n    },\n  }\n  ```\n\n  Starting with version 14.1.8, Nx uses the Storybook builder directly, which means any configuration supplied to the builder also applies to the NX setup. If you're working with a library, you'll need to configure the styling options ( e.g., preprocessors) inside the `build-storybook` options configuration object. For example:\n\n  ```json title=\"workspace.json\"\n  {\n    \"storybook\": {\n      \"executor\": \"@storybook/angular:start-storybook\",\n      \"options\": {\n        \"configDir\": \"apps/example-lib/.storybook\",\n        \"browserTarget\": \"example-lib:build-storybook\",\n      },\n    },\n    \"build-storybook\": {\n      \"executor\": \"@storybook/angular:build-storybook\",\n      \"outputs\": [\"{options.outputPath}\"],\n      \"options\": {\n        \"outputDir\": \"dist/storybook/example-lib\",\n        \"configDir\": \"apps/example-lib/.storybook\",\n        \"browserTarget\": \"example-lib:build-storybook\",\n        \"styles\": [\".storybook/custom-styles.scss\"],\n        \"stylePreprocessorOptions\": {\n          \"includePaths\": [\n            \"libs/design-system/src/lib\"\n          ]\n        }\n      }\n    },\n  }\n  ```\n\n  When Nx runs, it will load Storybook's configuration and styling based on [`storybook.browserTarget`](https://nx.dev/storybook/extra-topics-for-angular-projects#setting-up-browsertarget).\n</IfRenderer>\n"
  },
  {
    "path": "docs/configure/telemetry.mdx",
    "content": "---\ntitle: 'Telemetry'\nhideRendererSelector: true\nsidebar:\n  order: 3\n  title: Telemetry\n---\n\nStorybook collects completely anonymous data to help us improve user experience. Participation in this anonymous program is optional, and you may opt-out if you'd not like to share any information.\n\n## Why is telemetry collected?\n\nHundreds of thousands of developers use Storybook daily to build, test, and document components. Storybook is framework agnostic and integrates with the front-end ecosystem:\n\n* **JavaScript frameworks** such as [React](https://reactjs.org/), [Vue 3](https://vuejs.org/), [Svelte](https://svelte.dev/) and [Solid](https://www.solidjs.com/)\n* **Libraries** such as [Styled-Components](https://styled-components.com/), [Tailwind](https://tailwindcss.com/), [Redux](https://redux.js.org/)\n* **Design tools** such as [Figma](https://figma.com/), [Sketch](https://www.sketch.com/), [Zeplin](https://zeplin.io/) and [InVision](https://www.invisionapp.com/)\n* **Workflow tools** such as [Notion](https://www.notion.so/product), [Confluence](https://www.atlassian.com/software/confluence), and [Jira](https://www.atlassian.com/software/jira)\n\nIn the past, our improvement process relied on manually gathering feedback. But with a growing userbase and the need to support a wide variety of integrations, we need a more accurate method for gauging Storybook usage and pain points.\n\nThese telemetry data help us (the maintainers) to prioritize the highest impact projects. That allows us to keep up with trends in the front-end ecosystem and verify that our community's hard work achieves the intended result.\n\n## What is being collected?\n\nWe collect general usage details, including command invocation, Storybook version, addons, and the view layer.\n\nSpecifically, we track the following information in our telemetry events:\n\n* Timestamp of the occurrence.\n* Command invoked (e.g., `init`, `upgrade`, `dev`, `build`).\n* Storybook unique identifier: One-way hash generated during Storybook installation process.\n* One way hash of the IP address where the event occurred for spam detection.\n* Story count.\n* Storybook version.\n* Storybook metadata:\n  * Language (e.g., TypeScript, JavaScript).\n  * Supported view layers (e.g., React, Vue 3, Angular, Svelte).\n  * Builder (e.g., Webpack5, Vite).\n  * Meta framework (e.g., [Next](https://nextjs.org/), [Gatsby](https://www.gatsbyjs.com/), [CRA](https://create-react-app.dev/)).\n  * [Addons](https://storybook.js.org/integrations) (e.g., [Accessibility](https://storybook.js.org/addons/@storybook/addon-a11y/)).\n  * Testing tools (e.g. [Jest](https://jestjs.io/), [Vitest](https://vitest.dev/), [Playwright](https://playwright.dev/)).\n* Package manager information (e.g., `npm`, `yarn`).\n* Monorepo information (e.g., [NX](https://nx.dev/), [Turborepo](https://turborepo.org/)).\n* In-app events (e.g., [Storybook guided tour](https://github.com/storybookjs/addon-onboarding), [UI test run](../writing-tests/integrations/vitest-addon/index.mdx#storybook-ui)).\n\nAccess to the raw data is highly controlled, limited to select members of Storybook's core team who maintain the telemetry. We cannot identify individual users from the dataset: it is anonymized and untraceable back to the user.\n\n## What about sensitive information?\n\nWe take your privacy and our security very seriously. We perform additional steps to ensure that secure data (e.g., environment variables or other forms of sensitive data) **do not** make their way into our analytics. You can view all the information we collect by setting the `STORYBOOK_TELEMETRY_DEBUG` to `1` to print out the information gathered. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-telemetry-preview-event.md\" />\n\n{/* prettier-ignore-end */}\n\nWill generate the following output:\n\n```json\n{\n  \"anonymousId\": \"8bcfdfd5f9616a1923dd92adf89714331b2d18693c722e05152a47f8093392bb\",\n  \"eventType\": \"dev\",\n  \"context\": {\n    \"isTTY\": true,\n    \"platform\": \"macOS\",\n    \"nodeVersion\": \"24.11.0\",\n    \"storybookVersion\": \"10.3.0-alpha.9\",\n    \"cliVersion\": \"10.3.0-alpha.9\",\n    \"projectSince\": 1717334400000\n  },\n  \"payload\": {\n    \"versionStatus\": \"cached\",\n    \"storyIndex\": {\n      \"storyCount\": 0,\n      \"componentCount\": 0,\n      \"pageStoryCount\": 0,\n      \"playStoryCount\": 0,\n      \"autodocsCount\": 0,\n      \"mdxCount\": 0,\n      \"exampleStoryCount\": 8,\n      \"exampleDocsCount\": 3,\n      \"onboardingStoryCount\": 0,\n      \"onboardingDocsCount\": 0,\n      \"version\": 5\n    },\n    \"storyStats\": {\n      \"factory\": 0,\n      \"play\": 0,\n      \"render\": 1,\n      \"loaders\": 0,\n      \"beforeEach\": 0,\n      \"globals\": 0,\n      \"storyFn\": 5,\n      \"mount\": 0,\n      \"moduleMock\": 0,\n      \"tags\": 0\n    }\n  },\n  \"metadata\": {\n    \"generatedAt\": 1689007841223,\n    \"settingsCreatedAt\": 1689007841223,\n    \"hasCustomBabel\": false,\n    \"hasCustomWebpack\": false,\n    \"hasStaticDirs\": false,\n    \"hasStorybookEslint\": false,\n    \"refCount\": 0,\n    \"portableStoriesFileCount\": 0,\n    \"packageManager\": {\n      \"type\": \"yarn\",\n      \"version\": \"3.1.1\"\n    },\n    \"monorepo\": \"Nx\",\n    \"framework\": {\n      \"name\": \"@storybook/react-vite\",\n      \"options\": {}\n    },\n    \"builder\": \"@storybook/builder-vite\",\n    \"renderer\": \"@storybook/react\",\n    \"storybookVersion\": \"9.0.0\",\n    \"storybookVersionSpecifier\": \"^9.0.0\",\n    \"language\": \"typescript\",\n    \"storybookPackages\": {\n      \"@storybook/addon-docs/blocks\": {\n        \"version\": \"9.0.0\"\n      },\n      \"@storybook/react\": {\n        \"version\": \"9.0.0\"\n      },\n      \"@storybook/react-vite\": {\n        \"version\": \"9.0.0\"\n      },\n      \"storybook\": {\n        \"version\": \"9.0.0\"\n      }\n    },\n    \"addons\": {\n      \"@storybook/addon-onboarding\": {\n        \"version\": \"1.0.6\"\n      }\n    }\n  }\n}\n```\n\nAdditionally, if Storybook's guided tour is enabled, it will generate the following output:\n\n```json\n{\n  \"eventType\": \"addon-onboarding\",\n  \"payload\": {\n    \"step\": \"1:Welcome\",\n    \"addonVersion\": \"1.0.6\"\n  },\n  \"metadata\": {\n    // See above for metadata that's collected.\n  }\n}\n```\n\n## Will this data be shared?\n\nThe data we collect is anonymous, not traceable to the source, and only meaningful in aggregate form. No data we collect is personally identifiable.\nIn the future, we plan to share relevant data with the community through public dashboards (or similar data representation formats).\n\n## How to opt-out\n\nYou may opt out of the telemetry within your Storybook configuration by setting the `disableTelemetry` configuration element to `true`.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-disable-telemetry.md\" />\n\n{/* prettier-ignore-end */}\n\nIf necessary, you can also turn off telemetry via the command line with the `--disable-telemetry` flag.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-disable-telemetry-flag.md\" />\n\n{/* prettier-ignore-end */}\n\nOr via the `STORYBOOK_DISABLE_TELEMETRY` environment variable.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-disable-telemetry-env.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  There is a `boot` event containing no metadata (used to ensure the telemetry is working). It is sent prior to evaluating your [Storybook configuration file](../api/main-config/main-config.mdx) (i.e., `main.js|ts`), so it is unaffected by the `disableTelemetry` option. If you want to ensure that the event is not sent, use the `STORYBOOK_DISABLE_TELEMETRY` environment variable.\n</Callout>\n\n## Crash reports (disabled by default)\n\nIn addition to general usage telemetry, you may also choose to share crash reports. Storybook will then sanitize the error object (removing all user paths) and append it to the telemetry event. To enable crash reporting, you can set the `enableCrashReports` configuration element to `true`.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-telemetry-main-enable-crash-reports.md\" />\n\n{/* prettier-ignore-end */}\n\nYou can also enable crash reporting via the command line with the `--enable-crash-reports` flag.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-telemetry-storybook-enable-crash-reports-flag.md\" />\n\n{/* prettier-ignore-end */}\n\nOr by setting the `STORYBOOK_ENABLE_CRASH_REPORTS` environment variable to `1`.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-telemetry-storybook-enable-crash-reports-env.md\" />\n\n{/* prettier-ignore-end */}\n\nEnabling any of the options will generate the following item in the telemetry event:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-telemetry-crash-report-event.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/configure/user-interface/features-and-behavior.mdx",
    "content": "---\ntitle: 'Features and behavior'\nsidebar:\n  order: 1\n  title: Features and behavior\n---\n\nTo control the layout of Storybook’s UI you can use `addons.setConfig` in your `.storybook/manager.js`:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-config-layout.md\" />\n\n{/* prettier-ignore-end */}\n\nThe following table details how to use the API values:\n\n| Name                     | Type            | Description                                             | Example Value                                                                                  |\n| ------------------------ | --------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |\n| **navSize**              | Number (pixels) | The size of the sidebar that shows a list of stories    | `300`                                                                                          |\n| **bottomPanelHeight**    | Number (pixels) | The size of the addon panel when in the bottom position | `200`                                                                                          |\n| **rightPanelWidth**      | Number (pixels) | The size of the addon panel when in the right position  | `200`                                                                                          |\n| **panelPosition**        | String          | Where to show the addon panel                           | `'bottom'` or `'right'`                                                                        |\n| **enableShortcuts**      | Boolean         | Enable/disable shortcuts                                | `true`                                                                                         |\n| **showToolbar**          | Boolean         | Show/hide tool bar                                      | `true`                                                                                         |\n| **theme**                | Object          | Storybook Theme, see next section                       | `undefined`                                                                                    |\n| **selectedPanel**        | String          | Id to select an addon panel                             | `'storybook/actions/panel'`                                                                    |\n| **initialActive**        | String          | Select the default active tab on Mobile                 | `'sidebar'` or `'canvas'` or `'addons'`                                                        |\n| **layoutCustomisations** | Object          | Layout customisation options, see below                 | `{ showSidebar: ({ viewMode }, defaultValue) => viewMode === 'docs' ? false : defaultValue` }` |\n| **sidebar**              | Object          | Sidebar options, see below                              | `{ showRoots: false }`                                                                         |\n| **toolbar**              | Object          | Modify the tools in the toolbar using the addon id      | `{ fullscreen: { hidden: false } } `                                                           |\n\nThe following options are configurable under the `sidebar` namespace:\n\n| Name               | Type     | Description                                                   | Example Value                                         |\n| ------------------ | -------- | ------------------------------------------------------------- | ----------------------------------------------------- |\n| **showRoots**      | Boolean  | Display the top-level nodes as a \"root\" in the sidebar        | `false`                                               |\n| **collapsedRoots** | Array    | Set of root node IDs to visually collapse by default          | `['misc', 'other']`                                   |\n| **renderLabel**    | Function | Create a custom label for tree nodes; must return a ReactNode | `(item, api) => <abbr title=\"...\">{item.name}</abbr>` |\n\nThe following options are configurable under the `toolbar` namespace:\n\n| Name     | Type   | Description                                                          | Example Value        |\n| ---------| ------ | -------------------------------------------------------------------- | -------------------- |\n| **[id]** | String | Toggle visibility for a specific toolbar item (e.g. `title`, `zoom`) | `{ hidden: false }`  |\n\nThe following options are configurable under the `layoutCustomisations` namespace:\n\n| Name            | Type     | Description                       | Example Value                                                                 |\n| --------------- | -------- | --------------------------------- | ----------------------------------------------------------------------------- |\n| **showSidebar** | Function | Toggle visibility for the sidebar | `({ storyId }, defaultValue) => storyId === 'landing' ? false : defaultValue` |\n| **showToolbar** | Function | Toggle visibility for the toolbar | `({ viewMode }, defaultValue) => viewMode === 'docs' ? false : defaultValue`  |\n\n<Callout variant=\"warning\">\n  The `showSidebar` and `showToolbar` functions let you hide parts of the UI that are essential to Storybook's functionality. If misused, they can make navigation impossible. When hiding the sidebar, ensure the displayed page provides an alternative means of navigation.\n</Callout>\n\n## Customize the UI\n\nStorybook's UI is highly customizable. Its API and configuration options, available via the `showSidebar`, `showPanel` and `showToolbar` functions, allow you to control how the sidebar, addon panel and toolbar elements are displayed. Each function will enable you to include some default behavior and can be overridden to customize the UI to your needs.\n\n### Override sidebar visibility\n\nThe sidebar, present on the left of the screen, contains the search function and navigation menu. Users may show or hide it with a keyboard shortcut. If you want to force the sidebar to be visible or hidden in certain places, you can define a `showSidebar` function in `layoutCustomisations`. Below are the available parameters passed to this function and an overview of how to use them.\n\n| Name                     | Type     | Description                                                    | Example Value                         |\n| ------------------------ | -------- | -------------------------------------------------------------- | ------------------------------------- |\n| **path**                 | String   | Path to the page being displayed                               | `'/story/components-button--default'` |\n| **viewMode**             | String   | Whether the current page is a story or docs                    | `'docs'` or `'story'`                 |\n| **singleStory**          | Boolean  | Whether the current page is the only story for a component     | `true` or `false`                     |\n| **storyId**              | String   | The id of the current story or docs page                       | `'blocks-unstyled--docs'`      |\n| **index**              | Object   | The index containing statically analysed metadata for every story    | `{ 'blocks-unstyled--docs': { tags: ['autodocs'] } }`  |\n| **layout**               | Object   | The current layout state                                       | *see below*                           |\n| **layout.isFullscreen**  | Boolean  | Whether the preview canvas is in fullscreen mode               | `true` or `false`                     |\n| **layout.panelPosition** | String   | Whether the panel is shown below or on the side of the preview | `'bottom'` or `'right'`               |\n| **layout.showNav**       | Boolean  | The setting for whether the end user wants to see the sidebar  | `true` or `false`                     |\n| **layout.showPanel**     | Boolean  | The setting for whether the end user wants to see the panel    | `true` or `false`                     |\n| **layout.showToolbar**   | Boolean  | The setting for whether the end user wants to see the toolbar  | `true` or `false`                     |\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-manager-sidebar-hide-on-landing.md\"  />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"warning\">\n\n  If you're hiding the sidebar through `showSidebar`, ensure the displayed page provides an alternative means of navigation.\n\n</Callout>\n\n### Configure the addon panel\n\nWhen viewing a story, Storybook displays the addon panel on the bottom or right of the UI. The panel shows UIs for available addons (e.g., the [interactions panel](../../writing-tests/interaction-testing#debugging-interaction-tests), [accessibility tests panel](../../writing-tests/accessibility-testing) or [controls panel](../../essentials/controls)). If you want to customize when the addon panel appears, you can use the `showPanel` function. Listed below are the available options and an overview of how to use them.\n\n| Name                     | Type     | Description                                                    | Example Value                         |\n| ------------------------ | -------- | -------------------------------------------------------------- | ------------------------------------- |\n| **path**                 | String   | Path to the page being displayed                               | `'/story/components-button--default'` |\n| **viewMode**             | String   | Whether the current page is a story or docs                    | `'docs'` or `'story'`                 |\n| **singleStory**          | Boolean  | Whether the current page is the only story for a component     | `true` or `false`                     |\n| **storyId**              | String   | The id of the current story or docs page                       | `'blocks-unstyled--docs'`      |\n| **index**              | Object   | The index containing statically analysed metadata for every story    | `{ 'blocks-unstyled--docs': { tags: ['autodocs'] } }`  |\n| **layout**               | Object   | The current layout state                                       | *see below*                           |\n| **layout.isFullscreen**  | Boolean  | Whether the preview canvas is in fullscreen mode               | `true` or `false`                     |\n| **layout.panelPosition** | String   | Whether the panel is shown below or on the side of the preview | `'bottom'` or `'right'`               |\n| **layout.showNav**       | Boolean  | The setting for whether the end user wants to see the sidebar  | `true` or `false`                     |\n| **layout.showPanel**     | Boolean  | The setting for whether the end user wants to see the panel    | `true` or `false`                     |\n| **layout.showToolbar**   | Boolean  | The setting for whether the end user wants to see the toolbar  | `true` or `false`                     |\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-manager-addon-panel-hide-on-showcase.md\"  />\n\n{/* prettier-ignore-end */}\n\n### Configure the toolbar\n\nBy default, Storybook displays a toolbar at the top of the UI, allowing you to access menus from addons (e.g., [viewport](../../essentials/viewport.mdx), [background](../../essentials/backgrounds.mdx)), or custom defined [menus](../../essentials/toolbars-and-globals.mdx#global-types-and-the-toolbar-annotation). However, if you want to customize the toolbar's behavior, you can use the `showToolbar` function. Listed below are the available options and an overview of how to use them.\n\n| Name                     | Type     | Description                                                    | Example Value                         |\n| ------------------------ | -------- | -------------------------------------------------------------- | ------------------------------------- |\n| **path**                 | String   | Path to the page being displayed                               | `'/story/components-button--default'` |\n| **viewMode**             | String   | Whether the current page is a story or docs                    | `'docs'` or `'story'`                 |\n| **singleStory**          | Boolean  | Whether the current page is the only story for a component     | `true` or `false`                     |\n| **storyId**              | String   | The id of the current story or docs page                       | `'blocks-unstyled--docs'`      |\n| **index**              | Object   | The index containing statically analysed metadata for every story    | `{ 'blocks-unstyled--docs': { tags: ['autodocs'] } }`  |\n| **layout**               | Object   | The current layout state                                       | *see below*                           |\n| **layout.isFullscreen**  | Boolean  | Whether the preview canvas is in fullscreen mode               | `true` or `false`                     |\n| **layout.panelPosition** | String   | Whether the panel is shown below or on the side of the preview | `'bottom'` or `'right'`               |\n| **layout.showNav**       | Boolean  | The setting for whether the end user wants to see the sidebar  | `true` or `false`                     |\n| **layout.showPanel**     | Boolean  | The setting for whether the end user wants to see the panel    | `true` or `false`                     |\n| **layout.showToolbar**   | Boolean  | The setting for whether the end user wants to see the toolbar  | `true` or `false`                     |\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-manager-toolbar-hide-on-docs.md\"  />\n\n{/* prettier-ignore-end */}\n\n## Configuring through URL parameters\n\nYou can use URL parameters to configure some of the available features:\n\n| Config option       | Query param  | Supported values               |\n| ------------------- | ------------ | ------------------------------ |\n| **enableShortcuts** | `shortcuts`  | `false`                        |\n| --- (fullscreen)    | `full`       | `true`, `false`                |\n| --- (show sidebar)  | `nav`        | `true`, `false`                |\n| --- (show panel)    | `panel`      | `false`, `'right'`, `'bottom'` |\n| **selectedPanel**   | `addonPanel` | Any panel ID                   |\n| **showTabs**        | `tabs`       | `true`                         |\n| ---                 | `instrument` | `false`, `true`                |\n"
  },
  {
    "path": "docs/configure/user-interface/index.mdx",
    "content": "---\ntitle: User Interface\nsidebar:\n  order: 7\n  title: User Interface\n---"
  },
  {
    "path": "docs/configure/user-interface/sidebar-and-urls.mdx",
    "content": "---\ntitle: 'Sidebar & URLS'\nsidebar:\n  order: 3\n  title: Sidebar & URLS\n---\n\n<YouTubeCallout id=\"zrdcCSTGo4A\" title=\"How to Configure the Sidebar\" />\n\nStorybook’s sidebar lists all your stories grouped by component. When you have many components, you may also wish to group those components. To do so, you can add the `/` separator to the `title` of your CSF file, and Storybook will group the stories into groups based on common prefixes:\n\n![Storybook sidebar anatomy](../../_assets/configure/sidebar-anatomy.png)\n\nWe recommend using a nesting scheme that mirrors the filesystem path of the components. For example, if you have a file `components/modals/Alert.js`, name the CSF file `components/modals/Alert.stories.js` and title it `Components/Modals/Alert`.\n\n## Roots\n\nBy default, Storybook will treat your top-level nodes as “roots”. Roots are displayed in the UI as “sections” of the hierarchy. Lower level groups will show up as folders:\n\n![Storybook sidebar story roots](../../_assets/configure/sidebar-roots.png)\n\nIf you’d prefer to show top-level nodes as folders rather than roots, you can set the `sidebar.showRoots` option to `false` in [`./storybook/manager.js`](./features-and-behavior.mdx):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-manager-disable-roots.md\" />\n\n{/* prettier-ignore-end */}\n\n## Permalink to stories\n\nBy default, Storybook generates an `id` for each story based on the component title and the story name. This `id` in particular is used in the URL for each story, and that URL can serve as a permalink (primarily when you [publish](../../sharing/publish-storybook.mdx) your Storybook).\n\nConsider the following story:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"foo-bar-baz-story.md\" />\n\n{/* prettier-ignore-end */}\n\nStorybook's ID-generation logic will give this the `id` `foo-bar--baz`, so the link would be `?path=/story/foo-bar--baz`.\n\nIt is possible to manually set the story's id, which is helpful if you want to rename stories without breaking permalinks. Suppose you want to change the position in the hierarchy to `OtherFoo/Bar` and the story name to `Moo`. Here's how to do that:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"other-foo-bar-story.md\" />\n\n{/* prettier-ignore-end */}\n\nStorybook will prioritize the `id` over the title for ID generation if provided and prioritize the `story.name` over the export key for display.\n\n## CSF 3.0 auto-titles\n\nStorybook 6.4 introduced [CSF 3.0](https://storybook.js.org/blog/component-story-format-3-0/) as an experimental feature, allowing you to write stories more compactly. Suppose you're already using this format to write your stories. In that case, you can omit the `title` element from the meta (or default export) and allow Storybook automatically infer it based on the file's physical location. For example, given the following configuration and story:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-configuration-src-dir.md\" />\n\n{/* prettier-ignore-end */}\n\nWhen Storybook loads, the story can show up in the sidebar as `components/My Component`.\n\nAuto-titles work with explicit titling options like the component's `title` and the story's `name`:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"csf-3-example-title.md\" />\n\n{/* prettier-ignore-end */}\n\n### Auto-title filename case\n\nStarting with Storybook 6.5, story titles generated automatically no longer rely on Lodash's [startCase](https://lodash.com/docs/#startCase).\nInstead, the file name casing is preserved, allowing additional control over the story title. For example, `components/My Component` will be defined as `components/MyComponent`.\n\nIf you need, you can revert to the previous pattern by adding the following configuration:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-manager-render-label-stories.md\" />\n\n{/* prettier-ignore-end */}\n\n### Auto-title redundant filenames\n\nIn addition to improvements to the story file name casing, a new heuristic was introduced, removing redundant names in case the filename has the same name as the directory name, or if it's called `index.stories.js|ts`. For example, before `components/MyComponent/MyComponent.stories.js` was defined as `Components/MyComponent/MyComponent` in the sidebar. Now it will be defined as `Components/MyComponent`.\n\nIf you need to preserve the naming scheme, you can add the `title` element to the meta (or default export). For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-csf-3-auto-title-redundant.md\" usesCsf3 />\n\n{/* prettier-ignore-end */}\n\n### Auto-title prefixes\n\nAdditionally, if you customize your Storybook to load your stories based on a [configuration object](../index.mdx#with-a-configuration-object), including a `titlePrefix`, Storybook automatically prefixes all titles to matching stories. For example, assuming you have the following configuration:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-auto-title-custom.md\" />\n\n{/* prettier-ignore-end */}\n\nWhen Storybook generates the titles for all matching stories, they'll retain the `Custom` prefix.\n\n### Story Indexers\n\n[Story Indexers](../../api/main-config/main-config-indexers.mdx) are a set of heuristics used by Storybook to crawl your filesystem based on a given glob pattern searching for matching stories, which is then used to generate an `index.json` (formerly `stories.json`) file responsible for populating the sidebar with the necessary information. By default, this heuristic will look for files that contain the following scheme `*.stories.@(js|jsx|mjs|ts|tsx)`.\n\nYou can provide your own indexer to include stories with a different naming convention, adjust the automatic title generation beyond a prefix, and many other use cases. For more information, see the [Story Indexers API reference](../../api/main-config/main-config-indexers.mdx).\n"
  },
  {
    "path": "docs/configure/user-interface/storybook-addons.mdx",
    "content": "---\ntitle: 'Storybook Addons'\nsidebar:\n  order: 4\n  title: Storybook Addons\n---\n\nA key strength of Storybook is its extensibility. Use addons to extend and customize Storybook to fit your team’s development workflow.\n\nAddons are integral to the way Storybook works. Many of Storybook's core features are implemented as addons, such as [`addon-docs`](https://storybook.js.org/addons/@storybook/addon-docs).\n\n## Addon features\n\nThe most obvious thing addons affect in Storybook is the UI of Storybook itself. Within the UI the **toolbar** and **addons panel** are the two chief places addons will appear.\n\n![Storybook addons locations](../../_assets/configure/addon-locations.png)\n\nAddons can also hook into the rendering of your story in the preview pane via injecting their own [decorators](../../writing-stories/decorators.mdx).\n\nFinally, addons can affect the build setup of Storybook by injecting their own webpack configuration to allow the use of other tools in Storybook. Addons that do only this are often referred to as [presets](../../addons/addon-types.mdx).\n\n## Essential, core and community addons\n\nThere are many, many Storybook addons, but they can be roughly categorized into two areas:\n\n* **Core** addons are developed by the core team. They are kept in sync with the development of Storybook itself and written in idiomatic ways as templates for other addons. They can be found within the [Storybook monorepo](https://github.com/storybookjs/storybook/tree/next/code/addons).\n* **Community** addons are addons written by the massive Storybook community. They can be found on our [website](https://storybook.js.org/addons/), [GitHub](https://github.com/), and [npm](https://www.npmjs.com/).\n"
  },
  {
    "path": "docs/configure/user-interface/theming.mdx",
    "content": "---\ntitle: 'Theming'\nsidebar:\n  order: 2\n  title: Theming\n---\n\nStorybook is theme-able using a lightweight theming API.\n\n## Global theming\n\nIt's possible to theme Storybook globally.\n\nStorybook includes a set of built-in themes that you can use to customize the appearance of your Storybook UI. The built-in themes are light, dark, and the \"normal\" theme that matches your preferred color scheme. Unless you specify otherwise, Storybook uses the normal theme by default.\n\nAs an example, you can tell Storybook to use the \"dark\" theme by modifying [`.storybook/manager.js`](./features-and-behavior.mdx):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-manager-dark-theme.md\" />\n\n{/* prettier-ignore-end */}\n\nWhen setting a theme, set a complete theme object. The theme is replaced, not combined.\n\n## Theming docs\n\n[Storybook Docs](../../writing-docs/index.mdx) uses the same theme system as Storybook’s UI but is themed independently from the main UI. The default theme for Docs is always the \"light\" theme, regardless of the main UI theme.\n\nSupposing you have a Storybook theme defined for the main UI in [`.storybook/manager.js`](./features-and-behavior.mdx):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-manager-dark-theme.md\" />\n\n{/* prettier-ignore-end */}\n\nHere's how you'd specify the same theme for docs in [`.storybook/preview.js`](../index.mdx#configure-story-rendering):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-docs-dark-theme.md\" />\n\n{/* prettier-ignore-end */}\n\nContinue to read if you want to learn how to create your theme.\n\n## Create a theme quickstart\n\nThe easiest way to customize Storybook is to generate a new theme using the `create()` function from `storybook/theming`. This function includes shorthands for the most common theme variables. Here's how to use it:\n\nInside your `.storybook` directory, create a new file called `YourTheme.js` and add the following:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-theme-example-variables.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n\n  If you're using `brandImage` to add your custom logo, you can use any of the most common image formats.\n  \n</Callout>\n\nAbove, we're creating a new theme that will:\n\n* Use Storybook's `light` theme as a baseline.\n* Replace Storybook's logo in the sidebar with our own (defined in the brandImage variable).\n* Add custom branding information.\n* Set the brand link to open in the same window (as opposed to a new one), via the `target` attribute.\n\nFinally, we'll need to import the theme into Storybook. Create a new file called `manager.js` in your `.storybook` directory and add the following:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-manager-custom-theme.md\" />\n\n{/* prettier-ignore-end */}\n\nNow your custom theme will replace Storybook's default theme, and you'll see a similar set of changes in the UI.\n\n![Storybook starter theme](../../_assets/configure/storybook-starter-custom-theme.png)\n\nLet's take a look at a more complex example. Copy the code below and paste it in `.storybook/YourTheme.js`.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"your-theme.md\" />\n\n{/* prettier-ignore-end */}\n\nAbove, we're updating the theme with the following changes:\n\n* A custom color palette (defined in the `app` and `color` variables).\n* Custom fonts (defined in the `font` and `text` variables).\n\nWith the new changes introduced, the custom theme should yield a similar result.\n\n![Storybook custom theme loaded](../../_assets/configure/storybook-custom-theme.png)\n\n<Callout variant=\"info\" icon=\"💡\">\n  Many theme variables are optional, the <code>base</code> property is **NOT**.\n</Callout>\n\nThe `storybook/theming` module is built using TypeScript, which should help create a valid theme for TypeScript users. The types are part of the package itself.\n\n## CSS escape hatches\n\nThe Storybook theme API is narrow by design. If you want to have fine-grained control over the CSS, all UI and Docs components are tagged with class names to make this possible. **Use at your own risk** as this is an advanced feature.\n\nTo style these elements, insert style tags into:\n\n* For Storybook’s UI, use `.storybook/manager-head.html`\n* For Storybook Docs, use `.storybook/preview-head.html`\n\n<Callout variant=\"warning\" title=\"Caution\">\n  The same way as you can adjust your [preview’s head tag](../story-rendering.mdx#adding-to-head), Storybook allows you to modify the code on the manager's side, through `.storybook/manager-head.html`. It can be helpful when adding theme styles that target Storybook's HTML, but it comes with a cost as Storybook's inner HTML can change at any time through the release cycle.\n</Callout>\n\n## MDX component overrides\n\nIf you're using MDX for docs, there's one more level of \"themability\". MDX allows you to completely override the rendered components from Markdown using a `components` parameter. It's an advanced usage that we don't officially support in Storybook, but it's a powerful construct if you need it.\n\nHere's how you might insert a custom code renderer for `code` blocks on the page, in [`.storybook/preview.js`](../index.mdx#configure-story-rendering):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-custom-code-renderer.md\" />\n\n{/* prettier-ignore-end */}\n\nYou can even override a Storybook block component.\n\nHere's how you might insert a custom `<Canvas />` block:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-custom-canvas.md\" />\n\n{/* prettier-ignore-end */}\n\n## Addons and theme creation\n\nSome addons require specific theme variables that a Storybook user must add. If you share your theme with the community, make sure to support the official API and other popular addons, so your users have a consistent experience.\n\nFor example, the popular Actions feature uses [react-inspector](https://github.com/storybookjs/react-inspector/blob/master/src/styles/themes/chromeLight.tsx), which has themes of its own. Supply additional theme variables to style it like so:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-extended-theme-variables.md\" />\n\n{/* prettier-ignore-end */}\n\n## Using the theme for addon authors\n\nReuse the theme variables above for a native Storybook developer experience. The theming engine relies on [emotion](https://emotion.sh/), a CSS-in-JS library.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-theming-styled-import.md\" />\n\n{/* prettier-ignore-end */}\n\nUse the theme variables in object notation:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"component-styled-variables-object-notation.md\" />\n\n{/* prettier-ignore-end */}\n\nOr with template literals:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"component-styled-variables-template-literals.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/configure/webpack.mdx",
    "content": "---\ntitle: 'Webpack'\ndraft: true\n---\n\nStorybook displays your components in a custom web application built using [Webpack](https://webpack.js.org/). Webpack is a complex tool, but our default configuration is intended to cover most use cases. [Addons](https://storybook.js.org/addons/) are also available that extend the configuration for other everyday use cases.\n\nYou can customize Storybook's webpack setup by providing a `webpackFinal` field in [`.storybook/main.js`](./index.mdx#configure-your-storybook-project) file.\n\nThe value should be an async function that receives a webpack config and eventually returns a webpack config.\n\n### Default configuration\n\nBy default, Storybook's webpack configuration will allow you to:\n\n#### Import images and other static files\n\nYou can import images and other local files and have them built into the Storybook:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"my-component-story-import-static-asset.md\" />\n\n{/* prettier-ignore-end */}\n\n#### Import JSON as JavaScript\n\nYou can import `.json` files and have them expanded to a JavaScript object:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"my-component-story-import-json.md\" />\n\n{/* prettier-ignore-end */}\n\nIf you want to know the exact details of the webpack config, the best way is to run either of the following:\n\n```shell\n\n## Development mode\nyarn storybook dev --debug-webpack\n\n## Production mode\nyarn storybook build --debug-webpack\n```\n\nWhen you start your Storybook, you'll see an improvement in loading times. Read more about it in the [announcement post](https://storybook.js.org/blog/storybook-on-demand-architecture/) and the [configuration documentation](./index.mdx#on-demand-story-loading).\n\n### Webpack 5\n\nStorybook builds your project with Webpack 4 by default. If your project uses Webpack 5, you can opt into the Webpack 5 builder by installing the required dependencies (i.e., `@storybook/builder-webpack5`, `@storybook/manager-webpack5`) and update your Storybook configuration as follows:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-webpack5.md\" />\n\n{/* prettier-ignore-end */}\n\nOnce you are using Webpack 5, you can further opt into some features to optimize your build:\n\n#### Lazy Compilation\n\nStorybook supports Webpack's experimental [lazy compilation](https://webpack.js.org/configuration/experiments/#experimentslazycompilation) feature, via the `lazyCompilation` builder flag:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-webpack5-lazyCompilation.md\" />\n\n{/* prettier-ignore-end */}\n\nThis feature applies in development mode, and will mean your Storybook will start up faster, at the cost of slightly slower browsing time when you change stories.\n\n#### Filesystem Caching\n\nStorybook supports Webpack's [filesystem caching](https://webpack.js.org/configuration/cache/#cachetype) feature, via the `fsCache` builder flag:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-webpack5-fsCache.md\" />\n\n{/* prettier-ignore-end */}\n\nThis feature will mean build output is cached between runs of Storybook, speeding up subsequent startup times.\n\n### Extending Storybook’s webpack config\n\nTo extend the above configuration, use the `webpackFinal` field of [`.storybook/main.js`](./index.mdx#configure-story-rendering).\n\nThe value should export a `function`, which will receive the default config as its first argument. The second argument is an options object from Storybook, and this will have information about where config came from, whether we're in production or development mode, etc.\n\nFor example, if you need to adjust the config for a specific environment, you can do so like this:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-webpack-final.md\" />\n\n{/* prettier-ignore-end */}\n\nStorybook uses the config returned from the above function to render your components in Storybook's \"preview\" iframe. Note that Storybook has an entirely separate webpack config for its UI (also referred to as the \"manager\"), so the customizations you make only apply to the rendering of your stories, i.e., you can completely replace `config.module.rules` if you want.\n\nNevertheless, edit `config` with care. Make sure to preserve the following config options:\n\n* **entry**\n* **output**\n\nFurthermore, `config` requires the `HtmlWebpackplugin` to generate the preview page, so rather than overwriting `config.plugins` you should probably append to it (or overwrite it with care), see [the following issue](https://github.com/storybookjs/storybook/issues/6020) for examples on how to handle this:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-simplified-config.md\" />\n\n{/* prettier-ignore-end */}\n\nFinally, if your custom webpack config uses a loader that does not explicitly include specific file extensions via the `test` property, in that case, it is necessary to `exclude` the `.ejs` file extension from that loader.\n\nIf you're using a non-standard Storybook config directory, you should put `main.js` there instead of `.storybook` and update the `include` path to ensure it resolves to your project root.\n\n### Using your existing config\n\nSuppose you have an existing webpack config for your project and want to reuse this app's configuration. In that case, you can import your main webpack config into Storybook's [`.storybook/main.js`](./index.mdx#configure-story-rendering) and merge both:\n\nThe following code snippet shows how you can replace the loaders from Storybook with the ones from your app's `webpack.config.js`:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-using-existing-config.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  Projects initialized via generators (e.g, Vue CLI) may require that you import their own webpack config file (i.e., <code>/projectRoot/node\\_modules/@vue/cli-service/webpack.config.js</code>) to use a certain feature with Storybook. For other generators, make sure to check the documentation for instructions.\n</Callout>\n\n### TypeScript Module Resolution\n\nWhen working with TypeScript projects, the default Webpack configuration may fail to resolve module aliases defined in your [`tsconfig` file](https://www.typescriptlang.org/tsconfig). To work around this issue you may use [`tsconfig-paths-webpack-plugin`](https://github.com/dividab/tsconfig-paths-webpack-plugin#tsconfig-paths-webpack-plugin) while [extending Storybook's Webpack config](#extending-storybooks-webpack-config) like:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-ts-module-resolution.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  Learn more about Storybook's <a href=\"./typescript\">built-in TypeScript support</a> or see <a href=\"https://github.com/storybookjs/storybook/issues/14087\">this issue</a> for more information.\n</Callout>\n"
  },
  {
    "path": "docs/contribute/RFC.mdx",
    "content": "---\ntitle: 'RFC process'\nhideRendererSelector: true\nsidebar:\n  order: 1\n  title: RFC process\n---\n\nThe RFC (Request for Comment) process is intended to provide a consistent and controlled path for new features to enter the project. It helps ensure that new features are well-designed, well-implemented, and well-tested, and they do not conflict with the project's overall direction and scope.\n\n## Goal\n\nMany changes, such as bug fixes and documentation improvements, can be implemented and reviewed via the normal GitHub pull request workflow. Some changes, however, are considered “substantial”, and we ask that these undergo a design process, solicit community input, and reach a consensus among the Storybook core team.\n\nThe purpose of the RFC (Request for Comment) process is to:\n\n* Provide a transparent system for proposing new feature ideas.\n* Establish a reliable and well-regulated process for introducing new features into the project.\n* Provide a way for the community to participate in developing new features.\n\n### “Feature Request” vs. “RFC”\n\nA *feature request* is a straightforward and relatively informal way for Storybook users to suggest a new feature or enhancement to the project. While feature requests can provide valuable insights and ideas, they typically do not involve an in-depth design process or require consensus among the core team. Feature requests are usually open to discussion and may or may not be implemented based on factors like popularity, feasibility, and alignment with the project's goals.\n\nOn the other hand, an *RFC* is a more formalized and structured process for proposing substantial changes or additions to the project. It involves following a defined set of steps to ensure that the proposed feature or modification receives proper consideration, design, and feedback. RFCs are typically used for changes that significantly impact the project, such as introducing new API functionality, removing existing features, or establishing new usage conventions. The RFC process aims to foster discussions, gather feedback from a wider audience, and reach consensus among the core team before integrating the proposed change into the project. Accepted RFCs are more likely to be implemented than regular feature requests.\n\n## The RFC lifecycle\n\n### 1. `Status: Proposed`\n\nOpen a new GitHub discussion in the [“RFC” category](https://github.com/storybookjs/storybook/discussions/new?category=rfc). Fill out the form as instructed.\n\n*Details matter*: RFCs that do not present convincing motivation, demonstrate a lack of understanding of the design's impact, or are disingenuous about the drawbacks or alternatives tend to be poorly received.\n\n### 2. `Status: In review`\n\nRFCs tend to remain in this stage for a while, giving the community and core team members time to weigh in. During this period, the author of an RFC should be prepared to revise the proposal, integrate feedback, and build consensus. RFCs that have broad support are much more likely to make progress than those that don't receive any comments.\n\nEvery week, the Storybook core team conducts a triage meeting to review open RFCs as part of the meeting's agenda. The event is publicly scheduled in the [Storybook Discord](https://discord.gg/storybook) and held in the [Storybook Discord's Watercooler channel](https://discord.com/channels/486522875931656193/486522876388704260). We invite the RFC author(s) and interested members of the community to participate and engage in a more detailed discussion of the RFC. If a core team member deems it necessary, they will be assigned as the \"champion\" of the RFC. The champion will collaborate with the RFC author and assist them throughout the RFC process.\n\n### 3. `Status: accepted/rejected`\n\nEventually, the team will decide whether the RFC is a candidate for inclusion in Storybook. On the other hand, an RFC may be rejected by the team after a public discussion has settled and comments have been made summarizing the rationale for rejection.\n\n## Implementing an accepted RFC\n\nThe author of an RFC is not obligated to implement it. Of course, the RFC author (like any other developer) is welcome to post an implementation for review after the RFC has been accepted. However, note that the “accepted” status does not indicate priority nor whether it’s being actively worked on.\n\nIf you are interested in implementing an \"active\" RFC, but cannot determine if someone else is already working on it, feel free to ask (e.g., by leaving a comment on the associated issue).\n\nThis RFC process took heavy inspiration from the RFC processes from [Rust](https://github.com/rust-lang/rfcs) and [Gatsby](https://www.gatsbyjs.com/contributing/rfc-process/).\n\n**Learn more about contributing to Storybook**\n\n* RFC process for authoring feature requests\n* [Code](./code.mdx) for features and bug fixes\n* [Frameworks](./framework.mdx) to get started with a new framework\n* [Documentation](./documentation/documentation-updates.mdx) for documentation improvements, typos, and clarifications\n* [Examples](./documentation/new-snippets.mdx) for new snippets\n"
  },
  {
    "path": "docs/contribute/code.mdx",
    "content": "---\ntitle: 'Code contributions'\nhideRendererSelector: true\nsidebar:\n  order: 2\n  title: Code\n---\n\nContribute a new feature or bug fix to [Storybook's monorepo](https://github.com/storybookjs/storybook). This page outlines how to get your environment set up to contribute code.\n\n## Prerequisites\n\n* Ensure you have Node version 18 installed (suggestion: v18.16.0).\n* If you're working with Windows, all commands should be run in a terminal with administrator privileges.\n\n## Initial setup\n\nStart by [forking](https://docs.github.com/en/github/getting-started-with-github/quickstart/fork-a-repo) the Storybook monorepo and cloning it locally.\n\n```shell\ngit clone https://github.com/your-username/storybook.git\ncd storybook\n```\n\nStorybook uses the [Yarn](https://yarnpkg.com/) package manager. Use [Corepack](https://github.com/nodejs/corepack) to set up the correct version for use with Storybook.\n\n```shell\ncorepack enable\n```\n\n## Run your first sandbox\n\nStorybook development happens in a set of *sandboxes* which are templated Storybook environments corresponding to different user setups. Within each sandbox, we inject a set of generalized stories that allow us to test core features and addons in all such environments.\n\nTo run a sandbox locally, you can use the `start` command:\n\n```shell\nyarn start\n```\n\nIt will install the required prerequisites, build the code, create and link a starter example based on a Vite React setup and finally start the Storybook server.\n\nIf all goes well, you should see the sandbox running.\n\n![Storybook sandbox running](../_assets/get-started/example-welcome.png)\n\n## Running a different sandbox template\n\nBy default, the `start` command is configured to initialize a Vite-based React template. If you're planning on working on a different renderer instead, you can do so as well. Start by running the `task` command as follows:\n\n```shell\nyarn task\n```\n\nWhen prompted, answer the questions as accurately as possible to allow Storybook to determine your goals. After answering these questions, you should see the entire command with the options you've selected should you require to re-run it.\n\n<Callout variant=\"info\" icon=\"💡\">\n\n  The `yarn task` command takes a few development shortcuts that can catch you off guard when switching branches and may require you to re-run both the `install` and `compile` tasks. You can speed up the process by running the command with the `start-from=install` flag.\n\n</Callout>\n\n## Running tests\n\nAfter successfully running your [first sandbox](#run-your-first-sandbox), you should have a fully functional Storybook version built on your local machine. Before jumping onto any code changes, verifying everything is working is essential—specifically, the test suite.\n\nRun the following command to execute the tests:\n\n```shell\nyarn test\n```\n\n## Start developing\n\nNow that you've [verified your setup](#running-tests), it's time to jump into code. The simplest way is to run one of the sandboxes in one terminal window and the interactive build process in a separate terminal.\n\nAssuming you're still running the Vite-based React sandbox initialized after running the `yarn start` command, open a new terminal window and navigate to the `code` directory of the Storybook monorepo. Then, create a new branch for your contribution by running the following command:\n\n```shell\ngit checkout -b my-first-storybook-contribution\n```\n\nLastly, run the build process with the following:\n\n```shell\nyarn build\n```\n\nWhen prompted to start the build process in `watch` mode, answer **yes** to develop in interactive mode. Afterward, choose which packages you want to build. For example, if you're going to work on a feature for `@storybook/addon-docs`, you might want to select both `@storybook/addon-docs` and `storybook`.\n\n<Callout variant=\"info\" icon=\"💡\">\n\n  Build's `watch` mode is great for interactive development. However, for performance reasons, it only transpiles your code and doesn't execute the TypeScript compiler. If something isn't working as expected, try running the `build` command **WITHOUT** enabling watch mode: it will re-generate TypeScript types and perform automatic type checking for you.\n\n</Callout>\n\n![Storybook package selector](../_assets/contribute/storybook-build-packages-selection-optimized.png)\n\nIf the work you'll be doing affects the `Preview` (the innermost Storybook `iframe`, where the stories are displayed), it will automatically refresh one to two seconds after you save.\n\nOtherwise, if it affects the `Manager` (the outermost Storybook `iframe` where the addons are displayed), you'll need to refresh manually after saving.\n\n![Storybook manager preview](../_assets/addons/manager-preview.png)\n\nThe `yarn build` commands accepts arguments to help speed up your development workflow:\n* `--all` will cause all packages to be built\n* `--watch` will enable watch mode (and skip the watch mode prompt)\n* `--prod` will build for production (and skip the production mode prompt)\n* individual package names can be passed, without the `@storybook/` prefix, e.g. `storybook`, `addon-docs`, etc.\n\nFor example, to build Storybook and the docs addon in watch mode, run:\n\n```shell\nyarn build --watch storybook addon-docs\n```\n\n\n## Check your work\n\nWhen you're done coding, add documentation and tests as appropriate. That simplifies the PR review process, which means your code will get merged faster.\n\n### Add stories\n\nAdding a story or set of generic stories to our suite helps you test your work.\n\nAssuming you're working on one of the [essential features](../essentials/index.mdx), there's a chance that a complete set of stories already exists. Check the addon's `template/stories` directory that documents how it's supposed to work and add your stories there.\n\nIf you're modifying something related to a specific renderer (e.g., React, Vue 3, etc.), it will also have a similar `template/stories` directory in which you'll need to add your stories.\n\n### Add tests\n\nUnit tests ensure that Storybook doesn't break accidentally. If your code can regress in non-obvious ways, include unit tests with your pull request. Use the following naming convention:\n\n```\n+-- parentFolder\n|   +-- [filename].ts\n|   +-- [filename].test.ts\n```\n\n### End-to-end tests (e2e)\n\nStorybook's monorepo is set up to rely on end-to-end testing with [Playwright](https://playwright.dev) during CI. To help with testing, we encourage running this test suite before submitting your contribution.\n\nTo run an e2e test against a sandbox, you can use the `e2e-tests` task:\n\n```shell\nyarn task --task e2e-tests --template=react-vite/default-ts --start-from=auto\n```\n\nIf there are issues and you'd like to debug them, you can pass a `DEBUG=1` environment variable, and Playwright will run in watch mode.\n\n```shell\nDEBUG=1 yarn task --task e2e-tests --template=react-vite/default-ts --start-from=auto\n```\n\n## Submit a pull request\n\nBefore submitting your contribution, run the test suite one last time with the following:\n\n```shell\nyarn test\n```\n\n<Callout variant=\"info\" icon=\"💡\">\n\n  Storybook relies on [Vitest](https://vitest.dev/) as part of it's testing suite. During the test run, if you spot that snapshot tests are failing, re-run the command with the `-u` flag to update them.\n  \n</Callout>\n\nDoing this prevents last-minute bugs and is a great way to merge your contribution faster once you submit your pull request. Failing to do so will lead to one of the maintainers mark the pull request with the **Work in Progress** label until all tests pass.\n\n### Target `next` branch\n\nOnce the test suite finishes, it's time to commit, push and open a pull request against Storybook's `next` (default) branch. This branch is where all active development happens and is associated with the latest prerelease version (e.g., `7.0.0-alpha.47`).\n\nIf your contribution focuses on a bugfix and you want it featured in the next stable release, mention it in the pull request description. We'll try to patch it if it appears non-disruptive and fixes a critical bug.\n\n#### Useful resources when working with forks\n\n* [Sync a fork](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/working-with-forks/syncing-a-fork)\n* [Merge an upstream repository into your fork](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/working-with-forks/merging-an-upstream-repository-into-your-fork)\n\n### Reproducing job failures\n\nAfter creating your PR, if one of the CI jobs failed, when checking the logs of that job, you will see that it printed a message explaining how to reproduce the task locally. Typically that involves running the task against the right template:\n\n```shell\nyarn task --task e2e-tests --template=react-vite/default-ts --start-from=install\n```\n\nTypically it is a good idea to start from the `install` task to ensure your local code is completely up to date. If you reproduce the failure, you can try and make fixes, [compile them](#start-developing) with `build`, then rerun the task with `--start-from=auto`.\n\n<Callout variant=\"info\" icon=\"💡\">\n  The default instructions run the code in \"linked\" mode, meaning built changes to Storybook library code will be reflected in the sandbox immediately (the next time you run the task). However, CI runs in \"unlinked\" mode, which in rare cases, will behave differently.\n\n  If you are having trouble reproducing, try rerunning the command with the `--no-link` flag. If you need to do that, you'll need to run it with `--start-from=compile` after each code change.\n</Callout>\n\n## How to work with reproductions\n\nWe encourage bug reports to include reproductions. In the same way that it's possible to [develop interactively](#start-developing) against example projects in the monorepo, it's also possible to develop against a reproduction repository.\n\nTo do so, run the following command in the root of the monorepo:\n\n```shell\nnpx storybook@next link https://github.com/your-username/your-project.git\n```\n\nThis command creates a project `../storybook-repros/your-project`, and automatically links it to your local Storybook code. After connecting it, you should be able to run Storybook and develop as mentioned [above](#start-developing).\n\nIf you already have a reproduction on your local machine, you can similarly link it to your monorepo dev setup with the `--local` flag:\n\n```shell\nnpx storybook@next link --local /path/to/local-repro-directory\n```\n\n<Callout variant=\"info\" icon=\"💡\">\n  The `storybook link` command relies on [Yarn linking](https://yarnpkg.com/cli/link/) under the hood. It requires your local reproduction to be using [Yarn 2 or higher](https://yarnpkg.com/) as well, which is the case if you've already enabled it with the [`storybook sandbox`](./how-to-reproduce.mdx) command per our contribution guidelines. The process will fail if you're trying to link a non-Yarn 2 project.\n</Callout>\n\n## Developing a template\n\nThe first step is to add an entry to `code/lib/cli-storybook/src/sandbox-templates.ts`, which is the master list of all repro templates:\n\n```ts\n'cra/default-js': {\n    name: 'Create React App (Javascript)',\n    script: 'npx create-react-app .',\n    inDevelopment: true,\n    expected: {\n      framework: '@storybook/cra',\n      renderer: '@storybook/react',\n      builder: '@storybook/builder-webpack5',\n    },\n  },\n```\n\nAdd the `inDevelopment` flag until the PR is merged (you can fast-follow it with a second PR to remove the flag), as it'll make the development process much easier.\n\nThe **`key`** `cra/default-js` consists of two parts:\n\n* The prefix is the tool that was used to generate the repro app\n* The suffix is options that modify the default install, e.g. a specific version or options\n\nThe **`script`** field is what generates the application environment. The `.` argument is “the current working directory” which is auto-generated based on the key (e.g. `repros/cra/default-js/before-storybook`). The `{{beforeDir}}` key can also be used, which will be replaced by the path of that directory.\n\nThe rest of the fields are self-explanatory:\n\nThe **`skipTasks`** field exists because some sandboxes might not work properly in specific tasks temporarily, but we might still want to run the other tasks. For instance, a bug was introduced outside of our control, which fails only in the `test-runner` task.\n\nThe **`name`** field should contain a human readable name/description of the template.\n\nThe **`expected`** field reflects what framework/renderer/builder we expect `sb init` to generate. This is useful for assertions while generating sandboxes. If the template is generated with a different expected framework, for instance, it will fail, serving as a way to detect regressions.\n\n### Running a sandbox\n\nIf your template has a `inDevelopment` flag, it will be generated (locally) as part of the sandbox process. You can create the sandbox with the following command, where `<template-key>` is replaced by the id of the selected template e.g. `cra/default-js`:\n\n```bash\nyarn task --task dev --template <template-key> --start-from=install\n```\n\nTemplates with `inDevelopment` will automatically run with `--no-link` flag as it is required for the local template generation to work.\n\nOnce the PR is merged, the template will be generated on a nightly cadence and you can remove the `inDevelopment` flag and the sandbox will pull the code from our templates repository.\n\n## Troubleshooting\n\n<details>\n  <summary><code>yarn build --all --watch</code> watches everything but is resource-intensive</summary>\n\n  It's troublesome to know which packages you'll change ahead of time, and watching them can be highly demanding, even on modern machines. If you're working on a powerful enough machine, you can use `yarn build --all --watch` instead of `yarn build`.\n</details>\n\n**Learn more about contributing to Storybook**\n\n* [RFC process](./RFC.mdx) for authoring feature requests\n* Code for features and bug fixes\n* [Frameworks](./framework.mdx) to get started with a new framework\n* [Documentation](./documentation/documentation-updates.mdx) for documentation improvements, typos, and clarifications\n* [Examples](./documentation/new-snippets.mdx) for new snippets\n"
  },
  {
    "path": "docs/contribute/documentation/documentation-updates.mdx",
    "content": "---\ntitle: 'Documentation updates'\nhideRendererSelector: true\nsidebar:\n  order: 1\n  title: Content\n---\n\nFix a typo or clarify a section of the docs. This page outlines how to edit the documentation.\n\n## Find the Markdown file\n\nScroll to the bottom of the document in question, then click ✍️ Edit on GitHub – PRs welcome! This will open the Markdown file on GitHub.\n\n![Storybook documentation edit](../../_assets/contribute/storybook-edit-docs-optimized.png)\n\nUse GitHub's web editor by clicking the pencil icon on the right-hand corner. Tweak the document to your liking.\n\n![GitHub edit documentation](../../_assets/contribute/github-docs-edit-optimized.png)\n\nScroll down to the bottom of the document page on GitHub and describe what you changed and why. Select the `Create a new branch for this commit and start a pull request` option then click the `Propose changes` button.\n\n![Fill the commit information](../../_assets/contribute/storybook-docs-submit-changes-optimized.png)\n\n## Create the pull request\n\nIn the Storybook repository, create a pull request that describes changes and includes additional context that would help maintainers review. Once you submit the PR, a maintainer will guide you through the triage and merge process.\n\n**Learn more about contributing to Storybook**\n\n* [RFC process](../RFC.mdx) for authoring feature requests\n* [Code](../code.mdx) for features and bug fixes\n* [Frameworks](../framework.mdx) to get started with a new framework\n* Documentation for documentation improvements, typos, and clarifications\n* [Examples](./new-snippets.mdx) for new snippets\n"
  },
  {
    "path": "docs/contribute/documentation/index.mdx",
    "content": "---\ntitle: Documentation\nsidebar:\n  order: 3\n  title: Documentation\n---"
  },
  {
    "path": "docs/contribute/documentation/new-snippets.mdx",
    "content": "---\ntitle: 'Code snippets contributions'\nhideRendererSelector: true\nsidebar:\n  order: 2\n  title: Code snippets\n---\n\nAdd or update the code snippets in the documentation. This page outlines how the code snippets are structured.\n\n## Documented frameworks\n\nStorybook maintains code snippets for a [variety of frameworks](../../configure/integration/frameworks-feature-support.mdx). We try to keep them up to date as framework APIs evolve. But keeping track of every API change in every framework is tricky.\n\nWe welcome community contributions to the code snippets. Here's a matrix of the frameworks for which we have snippets. Help us add snippets for your favorite framework.\n\n\n| React  | Vue 3 | Angular   | Web Components | Svelte | Solid  | Ember | HTML | Preact | Qwik |\n| ------ | ----- | --------- | ---------------|--------|--------|-------|------| -------|------|\n| ✅     | ✅    | ✅        | ✅             | ✅     | ✅     | ❌    | ❌   | ❌     | ❌  |\n\n\n## Snippet syntax\n\nThe code snippets referenced throughout the Storybook documentation are located in the [`docs/_snippets`](https://github.com/storybookjs/storybook/tree/next/docs/_snippets) directory inside individual Markdown files, containing the [supported frameworks](../../configure/integration/frameworks-feature-support.mdx), features and languages (i.e., JavaScript, MDX, TypeScript).\n\n### Example\n\nThe following code block demonstrates how to structure a code snippet in the Storybook documentation and the attributes you can use to provide additional context to the code snippet.\n\n{/* prettier-ignore-start */}\n\n````md title=\"docs/_snippets/button-group-story.md\"\n```ts filename=\"ButtonGroup.stories.ts\" renderer=\"vue\" language=\"ts\" tabTitle=\"3\"\nimport type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport ButtonGroup from './ButtonGroup.vue';\n\n//👇 Imports the Button stories\nimport * as ButtonStories from './Button.stories';\n\nconst meta = {\n  component: ButtonGroup,\n}} satisfies Meta<typeof ButtonGroup>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Pair: Story = {\n  render: (args) => ({\n    components: { ButtonGroup },\n    setup() {\n      return { args };\n    },\n    template: '<ButtonGroup v-bind=\"args\" />',\n  }),\n  args: {\n    buttons: [{ ...ButtonStories.Primary.args }, { ...ButtonStories.Secondary.args }],\n    orientation: 'horizontal',\n  },\n};\n``` \n````\n\n{/* prettier-ignore-end */}\n\n\n## Common attributes for code snippets\n\nFollowing are the attributes you'll use most often in the Storybook documentation code snippets, as well as a brief explanation of each to help you understand the context in which they are used.\n\n### File name as title\n\nMost code examples should include a file name so readers can understand which file they relate to and where to paste it into their project. For code examples, include the `filename` attribute wrapped with quotation marks to indicate the file name. This is not required if the example relates to a terminal command.\n\n{/* prettier-ignore-start */}\n\n````md title=\"docs/_snippets/button-stories.md\"\n```ts filename=\"Button.stories.ts\"\n```\n````\n\n{/* prettier-ignore-end */}\n\n### Language configuration\n\nUse the `language` attribute to define the language to which the code snippet applies. The documentation uses this attribute to determine which variant to display (e.g., JavaScript, TypeScript, MDX).\n\n{/* prettier-ignore-start */}\n\n````md title=\"docs/_snippets/button-stories.md\"\n```ts filename=\"Button.stories.ts\" language=\"js|ts|mdx\"\n```\n````\n\n{/* prettier-ignore-end */}\n\n### Framework-specific code\n\nUse the `renderer` attribute to indicate which of the [supported frameworks](../../configure/integration/frameworks-feature-support.mdx) the code snippet belongs to.\n\n{/* prettier-ignore-start */}\n\n````md title=\"docs/_snippets/button-stories.md\"\n```ts filename=\"Button.stories.ts\" language=\"ts\" renderer=\"react|vue|angular|web-components|ember|html|svelte|preact|qwik|solid\"\n```\n````\n\n{/* prettier-ignore-end */}\n\nAlternatively, if you're documenting examples that apply to multiple frameworks, use the `renderer` attribute with the `common` value to indicate that the code snippet is framework-agnostic.\n\n{/* prettier-ignore-start */}\n\n````md title=\"docs/_snippets/button-stories.md\"\n```ts filename=\"Button.stories.ts\" language=\"ts\" renderer=\"common\"\n```\n````\n\n{/* prettier-ignore-end */}\n\n### Package manager configuration\n\nUse the `packageManager` attribute to configure the package manager used in the example from the following options: `npm`, `yarn`, or `pnpm`.\n\n\n{/* prettier-ignore-start */}\n\n````md title=\"docs/_snippets/storybook-run-dev.md\"\n```shell renderer=\"common\" language=\"js\" packageManager=\"npm|yarn|pnpm\"\n```\n````\n\n{/* prettier-ignore-end */}\n\n### Working with multiple snippets\n\nUse the `tabTitle` attribute to indicate the tab title in which the code snippet will be displayed. This attribute should only be used when multiple examples are in a single code snippet file.\n \n{/* prettier-ignore-start */}\n\n````md title=\"docs/_snippets/component-decorator.md\"\n```ts filename=\"YourComponent.stories.ts\" language=\"ts\" renderer=\"common\" tabTitle=\"Story\"\n```\n```ts filename=\".storybook/preview.ts\" language=\"ts\" renderer=\"common\" tabTitle=\"Storybook configuration\"\n```\n````\n\n{/* prettier-ignore-end */}\n\n## Contributing code snippets\n\nYou can start contributing to the Storybook documentation by now that you're familiar with how the documentation is organized, the code snippet's structure, and available options. Assuming that you have already set up your [local development environment](../code.mdx#initial-setup) and are ready to contribute, the following steps will guide you through contributing code snippets to the Storybook documentation.\n\nStart by creating a new branch on your local Storybook monorepo with the following command:\n\n{/* prettier-ignore-start */}\n\n```shell\ngit checkout -b code-snippets-for-framework\n```\n  \n{/* prettier-ignore-end */}\n\nBrowse the documentation and look for the code snippets you want to contribute. For example, on the [setup page](https://github.com/storybookjs/storybook/blob/next/docs/get-started/setup.mdx) you should see the following:\n\n{/* prettier-ignore-start */}\n\n ```jsx title=\"docs/get-started/setup.mdx\"\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"your-component.md\" usesCsf3 />\n\n{/* prettier-ignore-end */}\n```\n\n{/* prettier-ignore-end */}\n\n\nOpen the file inside the `docs/_snippets` directory and adjust the content to match the code snippet you're willing to contribute. For example:\n\n{/* prettier-ignore-start */}\n\n````md title=\"docs/_snippets/your-component.md\"\n```ts filename=\"YourComponent.stories.ts\" renderer=\"qwik\" language=\"ts\"\nimport type { Meta, StoryObj } from 'storybook-framework-qwik';\n\nimport type { YourComponentProps } from './YourComponent';\n\nimport { YourComponent } from './YourComponent';\n\n//👇 This default export determines where your story goes in the story list\nconst meta = {\n  component: YourComponent,\n} satisfies Meta<YourComponentProps>;\n\nexport default meta;\ntype Story = StoryObj<YourComponentProps>;\n\nexport const FirstStory: Story = {\n  args: {\n  //👇 The args you need here will depend on your component\n  },\n};\n```\n````\n\n{/* prettier-ignore-end */}\n\nGo through the rest of the documentation and repeat the process.\n\n## Preview your work\n\nBefore submitting your contribution, we encourage you to check your work against the Storybook website. Doing this prevents last-minute issues with the documentation and is also an excellent way for the maintainers to merge faster once you submit the pull request. However, failing to do so will lead one of the maintainers to notify you that your contribution has an issue.\n\nStart by forking the Storybook [website repository](https://github.com/storybookjs/web) and cloning it locally.\n\n{/* prettier-ignore-start */}\n\n```shell\ngit clone https://github.com/your-username/web.git\n```\n  \n{/* prettier-ignore-end */}\n\nNavigate to the `web` directory and install the required dependencies.\n\n{/* prettier-ignore-start */}\n\n```shell\nnpm install\n```\n\n{/* prettier-ignore-end */}\n\nWe recommend that you generate a website build first to ensure you can preview your changes locally and verify that everything is working as expected. To do so, run the following command:\n\n{/* prettier-ignore-start */}\n\n```shell\nnpm run build:frontpage\n```\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n\nWhen executed, this command will retrieve the required files needed to successfully build the Storybook website, including current documentation versions (e.g., `6.5`, `7.6`, `8.x`), and copy them to the `apps/frontpage/docs/` directory, organized by version number.\n\n</Callout>\n\nRun the `sync-docs` command to connect the documentation from the Storybook monorepo to the Storybook website. When prompted, provide the path to your local fork of the Storybook monorepo and the documentation version you're working on.\n\n{/* prettier-ignore-start */}\n\n```shell\nnpm run sync-docs\n```\n\n{/* prettier-ignore-end */}\n\nFinally, open a new terminal window and run the `dev` command to start the Storybook website.\n\n{/* prettier-ignore-start */}\n\n```shell\nnpm run dev\n```\n\n{/* prettier-ignore-end */}\n\nIf all goes well, you should see the Storybook website running. Open a browser window to `http://localhost:3000`, click the Docs link to open the documentation, and select your framework from the dropdown.\n\n<Video src=\"../_assets/contribute/local-storybook-website-dropdown-optimized.mp4\" />\n\nGo through the documentation and check your work.\n\n## Submit your contribution\n\nOnce you have verified that your changes are working as expected, you're ready to create a \"Pull Request\". This will let the Storybook maintainers know you have some changes to propose. At this point, we can give you feedback and request changes. To help with the review process, we encourage you to add a clear title and description of your work.\n\n\n## Troubleshooting\n\n### Code snippets not displaying\n\nIf you're documenting an example that includes the `packageManager` attribute combined with another example, the documentation might not display the code snippets correctly. To avoid this, you can divide the examples into separate files and reference them in the documentation.\n\n## Learn more about contributing to Storybook\n\n* [RFC process](../RFC.mdx) for authoring feature requests\n* [Code](../code.mdx) for features and bug fixes\n* [Frameworks](../framework.mdx) to get started with a new framework\n* [Documentation](./documentation-updates.mdx) for documentation improvements, typos, and clarifications\n* Examples for new snippets"
  },
  {
    "path": "docs/contribute/framework.mdx",
    "content": "---\ntitle: 'Contributing a Storybook framework'\nhideRendererSelector: true\nsidebar:\n  order: 4\n  title: Frameworks\n---\n\nA Storybook framework is a node package that enables out-of-the-box support for either a metaframework (Next.js, NuxtJS, SvelteKit) or a combination of [builder](../builders/index.mdx) (Webpack, Vite) plus renderer (React, Angular, Vue 3, web components, etc).\n\nFor metaframeworks, the Storybook framework also takes care of additional configuration necessary to make Storybook behave similarly to apps generated by the metaframework. For example, `@storybook/nextjs` [recreates or mocks a number of features of Next.js apps](https://github.com/storybookjs/storybook/blob/next/code/frameworks/nextjs/README.md#supported-features) inside Storybook.\n\nFor your reference, you can view [all of the official Storybook frameworks](https://github.com/storybookjs/storybook/tree/next/code/frameworks), including their full source code and documentation.\n\n## How to make a framework\n\n### 1. Decide on a package name\n\nThe name should start with `storybook-framework-` and then correspond to what your framework supports. For example, a framework targeting SvelteKit would be `storybook-framework-svelte-kit` and a framework targeting Stencil with Vite would be `storybook-framework-stencil-vite`. When not targeting a metaframework, the naming convention is `storybook-framework-<renderer>-<builder>`.\n\n### 2. Consider what your framework will need to do\n\nThe goal is to make Storybook behave—out-of-the-box—as similarly as possible to the metaframework or builder-renderer combination you’re targeting.\n\nFor metaframeworks, this means attempting to recreate any builder or babel configuration provided by the metaframework. You should try to do so in a way that respects the user's existing project configuration as much as possible.\n\nThe library or libraries your framework supports may have different major versions available. Consider which versions of each library your framework will support. You will need to account for the changes within those different versions or split your framework into different versions/packages itself to support each library version. To speed up maintenance, please consider adding integration tests for the various library versions your framework supports.\n\n### 3. Write the documentation\n\nBefore writing any code, write a helpful README that contains installation instructions and a list of available features. Use the [README for `@storybook/nextjs`](https://github.com/storybookjs/storybook/blob/next/code/frameworks/nextjs/README.md) as a template. Writing the documentation first helps guide your other work.\n\n### 4. Author the framework itself\n\nA framework can contain the following parts:\n\n#### `package.json` ([example](https://github.com/storybookjs/storybook/blob/next/code/frameworks/nextjs/package.json))\n\nBecause a framework is a node package, it must contain a `package.json` file. Here’s a template you can use to start:\n\n<details>\n  <summary><code>package.json</code> template</summary>\n\n  ```json title=\"package.json\"\n  {\n    \"name\": \"<your-framework-name>\",\n    \"version\": \"1.0.0\",\n    \"description\": \"Storybook for <meta-framework-name> or <renderer> & <builder>\",\n    \"keywords\": [\n      \"Storybook\",\n      \"<meta-framework-name>\",\n      \"<renderer>\",\n      \"<builder>\",\n      \"<anything>\",\n      \"<else>\",\n      \"<relevant>\"\n    ],\n    \"homepage\": \"<your package's homepage>\",\n    \"bugs\": {\n      \"url\": \"https://github.com/<your-org>/<your-repo>/issues\"\n    },\n    \"repository\": {\n      \"type\": \"git\",\n      \"url\": \"https://github.com/<your-org>/<your-repo>.git\",\n      \"directory\": \"<path/to/your/framework>\"\n    },\n    \"license\": \"MIT\",\n    \"exports\": {\n      \".\": {\n        \"types\": \"./dist/index.d.ts\",\n        \"require\": \"./dist/index.js\",\n        \"import\": \"./dist/index.mjs\"\n      },\n      \"./preset\": {\n        \"types\": \"./dist/preset.d.ts\",\n        \"require\": \"./dist/preset.js\",\n        \"import\": \"./dist/preset.mjs\"\n      },\n      \"./preview.js\": {\n        \"types\": \"./dist/preview.d.ts\",\n        \"require\": \"./dist/preview.js\",\n        \"import\": \"./dist/preview.mjs\"\n      },\n      \"./package.json\": \"./package.json\"\n    },\n    \"main\": \"dist/index.js\",\n    \"module\": \"dist/index.mjs\",\n    \"types\": \"dist/index.d.ts\",\n    \"files\": [\"dist/**/*\", \"types/**/*\", \"README.md\", \"*.js\", \"*.d.ts\"],\n    \"scripts\": {\n      \"check\": \"tsc --noEmit\",\n      \"test\": \"...\"\n    },\n    \"dependencies\": {\n      \"storybook\": \"^9.0.0\",\n      \"@storybook/<builder>\": \"^9.0.0\",\n      \"@storybook/<renderer>\": \"^9.0.0\"\n    },\n    \"devDependencies\": {\n      \"typescript\": \"x.x.x\",\n      \"<meta-framework>\": \"^x.x.x\",\n      \"<builder>\": \"^x.x.x\"\n    },\n    \"peerDependencies\": {\n      \"<meta-framework>\": \"^x.x.x || ^x.x.x\",\n      \"<renderer>\": \"^x.x.x || ^x.x.x\",\n      \"<builder>\": \"^x.x.x\"\n    },\n    \"engines\": {\n      \"node\": \">=20.0.0\"\n    },\n    \"publishConfig\": {\n      \"access\": \"public\"\n    }\n  }\n  ```\n\n  A few notes on some of those properties:\n\n  * `exports`: The root, `./preset`, and `package.json` exports are required. If your framework has a `preview.js`, then that is required as well.\n  * `types`: We strongly encourage you to author your framework in TypeScript and distribute the types.\n  * `dependencies` and `devDependencies`: These are just examples. Yours may look quite different.\n  * `peerDependencies`: If your framework provides support for multiple versions of the libraries you’re targeting, be sure that is represented here.\n</details>\n\n#### `preset.js` ([example](https://github.com/storybookjs/storybook/blob/next/code/frameworks/nextjs/src/preset.ts))\n\nThe [preset API](../addons/writing-presets.mdx) is where you will configure the Storybook core (which builder and renderer are used by your framework), the builder (via either the [`webpackFinal`](../builders/webpack.mdx#override-the-default-configuration) or [`viteFinal`](../builders/vite.mdx#configuration) export), babel (via the `babel` export), any necessary addons, and any available options for your framework.\n\n#### `preview.js` ([example](https://github.com/storybookjs/storybook/blob/next/code/frameworks/nextjs/src/preview.tsx))\n\nThe (optional) [preview API](../configure/index.mdx#configure-story-rendering) is where you configure the rendering of stories, such as global decorators or initializing some runtime config needed for your framework to behave as expected. If your framework requires this file, note that you also need to [configure the `previewAnnotations` in `preset.js`](https://github.com/storybookjs/storybook/blob/next/code/frameworks/nextjs/src/preset.ts#L71-L74).\n\n#### `types.ts` ([example](https://github.com/storybookjs/storybook/blob/next/code/frameworks/nextjs/src/types.ts))\n\nIf you author your framework in TypeScript (recommended), you should export the type for `StorybookConfig` which reflects the available options of your framework.\n\n### 5. Test your framework\n\nTest it in a fresh project using a Storybook set up as close as possible to your framework. For example, for `@storybook/nextjs`, which uses React and Webpack5, start with a project that uses `@storybook/react` and `@storybook/builder-webpack5`. Follow the installation instructions from your README and ensure everything works as expected. Remember to test the various versions, configs, and options for the libraries you’re supporting.\n\n### 6. Let us know!\n\nOnce it's fully tested and released, please let us know about your framework by either announcing it in the [`#showcase`](https://discord.com/channels/486522875931656193/1048740936953376859) Discord channel or tweeting it and mentioning `@storybookjs`. It's our hope that well-made community frameworks can eventually move into the Storybook codebase and be considered \"officially\" supported.\n\n**Learn more about contributing to Storybook**\n\n* [RFC process](./RFC.mdx) for authoring feature requests\n* [Code](./code.mdx) for features and bug fixes\n* Frameworks to get started with a new framework\n* [Documentation](./documentation/documentation-updates.mdx) for documentation improvements, typos, and clarifications\n* [Examples](./documentation/new-snippets.mdx) for new snippets\n"
  },
  {
    "path": "docs/contribute/how-to-reproduce.mdx",
    "content": "---\ntitle: 'Create a reproduction'\nhideRendererSelector: true\nsidebar:\n  order: 5\n  title: Reproduce\n---\n\nA reproducible test case lets you isolate the cause of a problem, which is the first step towards fixing it! This page outlines how to get set up to create a reproduction.\n\n## Why should you create a reproduction?\n\nA reproducible test case is a great way to share a specific set of conditions that causes a bug. It allows both the maintainers and the community to verify, narrow down the cause of the problem and help you fix the issue.\n\n## Pre-requisites\n\nMake sure you have:\n\n* Installed [`Yarn`](https://yarnpkg.com/) on your local development machine.\n* A [GitHub account](https://github.com/signup) for hosting the reproduction's code.\n* A [Chromatic account](https://www.chromatic.com/start/?utm_source=storybook_website\\&utm_medium=link\\&utm_campaign=storybook) for publishing your Storybook.\n\n## Initial setup\n\nFirst, open a terminal and run the following command:\n\n```shell\nnpx storybook@next sandbox\n```\n\n<Callout variant=\"info\" icon=\"💡\">\n  You can append a template name in the command to get filtered results (e.g., `npx storybook@next sandbox react`).\n</Callout>\n\nNext, choose the template you want to work with:\n\n![Storybook reproduction generator template](../_assets/contribute/storybook-reproduction-generator-template.png)\n\nFinally, enter a location for your reproduction:\n\n![Storybook reproduction location](../_assets/contribute/storybook-reproduction-generator-location.png)\n\n<Callout variant=\"info\" icon=\"💡\">\n  If you don't provide a full path for the reproduction it will be generated in the current directory.\n</Callout>\n\nIf everything worked as it should, you should have a fully functional Storybook set up in your local environment.\n\n## Third-party dependencies & addons\n\nBefore adding code, install and configure any necessary packages. For example, if you run into a problem with a CSS framework (e.g., [Tailwind](https://tailwindcss.com/)), you should install and configure it.\n\nInstall and configure any Storybook [addons](https://storybook.js.org/addons/) that relate to the issue (e.g.,`@storybook/addon-a11y`).\n\n## Add stories\n\nAny Storybook reproduction wouldn't be complete without [stories](../writing-stories/index.mdx). To help fix your issue faster, we encourage you to include the minimum amount of stories that will replicate your issue.\n\n## Host\n\nWhen you've finished your work, you'll need to host your reproduction. Start by signing into GitHub.com and create a [new repository](https://github.com/new).\n\n![github repository for reproductions](../_assets/contribute/github-new-repository-reproduction-optimized.png)\n\nThen, follow GitHub's instructions to set up the repository.\n\n![github repository instructions](../_assets/contribute/github-repository-steps-optimized.png)\n\n<Callout variant=\"info\" icon=\"💡\">\n  Don't forget to replace `your-username` with your own account name.\n</Callout>\n\n## Publish\n\nAn excellent way to check your reproduction is to have it deployed online. We recommend [Chromatic](https://www.chromatic.com/?utm_source=storybook_website\\&utm_medium=link\\&utm_campaign=storybook), a free publishing service created by the Storybook maintainers. It allows you to deploy and host your reproduction safely and securely in the cloud.\n\n### Helpful resources when working with Chromatic\n\n* [Publish Storybook](../sharing/publish-storybook.mdx)\n* [Setup Chromatic](https://www.chromatic.com/docs/setup?utm_source=storybook_website\\&utm_medium=link\\&utm_campaign=storybook)\n* [Automate Chromatic with continuous integration](https://www.chromatic.com/docs/ci?utm_source=storybook_website\\&utm_medium=link\\&utm_campaign=storybook)\n\n## Submit the issue\n\nFinally, create your issue in the [Storybook issue tracker](https://github.com/storybookjs/storybook/issues/new/choose), go through the required steps, and provide a detailed description of the problem. Add the GitHub repository and [deployed reproduction](https://www.chromatic.com/docs/setup?utm_source=storybook_website\\&utm_medium=link\\&utm_campaign=storybook#view-published-storybook) to help with the triage process.\n"
  },
  {
    "path": "docs/contribute/index.mdx",
    "content": "---\ntitle: 'How to contribute'\nhideRendererSelector: true\nsidebar:\n  order: 14\n  title: Contribute\n---\n\nStorybook is a community-oriented open source project that welcomes contributions. Some of our most popular features started with a developer wanting to solve a problem for themselves.\n\n## Contributor covenant\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. [Continue reading our contributor covenant »](https://github.com/storybookjs/storybook/blob/next/CODE_OF_CONDUCT.md)\n\n## Ways to contribute\n\n* [**RFC process**](./RFC.mdx) for authoring feature requests\n* [**Code**](./code.mdx) for features and bug fixes\n* [**Frameworks**](./framework.mdx) to get started with a new framework\n* [**Documentation**](./documentation/documentation-updates.mdx) for documentation improvements, typos, and clarifications\n* [**Examples**](./documentation/new-snippets.mdx) for new snippets and examples\n* [**Addons**](../addons/index.mdx) for new addons\n\n## Not sure how to get started?\n\n* [Chat in Discord `#contributing`](https://discord.com/channels/486522875931656193/839297503446695956)\n* [Browse \"good first issues\" to fix](https://github.com/storybookjs/storybook/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)\n* [Submit a bug report or feature request](https://github.com/storybookjs/storybook/issues)\n"
  },
  {
    "path": "docs/essentials/actions.mdx",
    "content": "---\ntitle: 'Actions'\nsidebar:\n  order: 1\n  title: Actions\n---\n\nActions are used to show that an event handler (callback) has been called, and to display its arguments. The actions panel can show both story args and other function calls.\n\n<Video src=\"../_assets/essentials/addon-actions-demo-optimized.mp4\" />\n\n## Story args\nActions work via supplying special Storybook-generated mock functions to your story's event handler args. There are two ways to get an action arg:\n\n### Via storybook/test fn spies\n\nThe recommended way to write actions is to use the `fn` utility from `storybook/test` to mock and spy args. This is very useful for writing [interaction tests](../writing-tests/interaction-testing.mdx). You can mock your component's methods by assigning them to the `fn()` function:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-onclick-action-spy.md\" />\n\n{/* prettier-ignore-end */}\n\nIf your component calls an arg (because of either the user's interaction or the `play` function) and that arg is spied on, the event will show up in the action panel:\n\n![Actions usage](../_assets/essentials/addon-actions-screenshot.png)\n\n### Automatically matching args\n\nAnother option is to use a global parameter to match all [argTypes](../api/arg-types.mdx) that match a certain pattern. The following configuration automatically creates actions for each `on` argType (which you can either specify manually or can be [inferred automatically](../api/arg-types.mdx#automatic-argtype-inference)).\n\nThis is quite useful when your component has dozens (or hundreds) of methods and you do not want to manually apply the `fn` utility for each of those methods. However, **this is not the recommended** way of writing actions. That's because automatically inferred args **are not available as spies in your play function**. If you use `argTypesRegex` and your stories have play functions, you will need to also define args with the `fn` utility to test them in your play function.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-matching-argtypes.md\" />\n\n{/* prettier-ignore-end */}\n\nIf you need more granular control over which `argTypes` are matched, you can adjust your stories and include the `argTypesRegex` parameter. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-matching-argtypes.md\" />\n\n{/* prettier-ignore-end */}\n\nThis will bind a standard HTML event handler to the outermost HTML element rendered by your component and trigger an action when the event is called for a given selector. The format is `<eventname> <selector>`. The selector is optional; it defaults to all elements.\n\n\n\n## Non-story function calls\n\nYou can still use the actions panel if you need to log function calls that are unrelated to any story. This can be helpful for debugging or logging purposes. There are two main ways to do this: `spyOn` from `storybook/test` or the `action` function from `storybook/actions`. For basic logging, we recommend creating a function spy, and for more complex scenarios, you can use the `action` function directly.\n\n### Via storybook/test spyOn\n\nMocks and spies from `storybook/test` are automatically logged as actions. The easiest way to show function calls in the actions panel is to use the `spyOn` utility function. Spies appear with a default name, which you can customize by calling the `mockName` method.\n\n<CodeSnippets path=\"actions-spyon-basic-example.md\" />\n\n\n### Via the `action` function\n\nTo filter which function calls are logged, you can override the `spyOn` function's behavior by providing a custom implementation that calls the  `action` function from `storybook/actions` only if it matches a specific condition to prevent it from logging all calls to the function it spies on.\n\n<CodeSnippets path=\"actions-filtering-example.md\" />\n\n\n## API\n\n### Parameters\n\nThis contributes the following [parameters](../writing-stories/parameters.mdx) to Storybook, under the `actions` namespace:\n\n#### `argTypesRegex`\n\nType: `string`\n\nCreate actions for each arg that matches the regex. Please note the significant [limitations of this approach](#automatically-matching-args), as described above.\n\n#### `disable`\n\nType: `boolean`\n\nDisable the action panel.\n\nThis parameter is most useful to allow overriding at more specific levels. For example, if this parameter is set to `true` at the project level, it could then be re-enabled by setting it to `false` at the meta (component) or story level.\n\n#### `expandLevel`\n\nType: `number`\n\nDefault: `1`\n\nControls how many levels deep the action tree is initially expanded. Useful when action arguments contain nested objects and you want to see more detail by default.\n\n### Exports\n\n```js\nimport { action } from 'storybook/actions';\n```\n\n#### `action`\n\nType: `(name?: string) => void`\n\nAllows you to create an action that appears in the actions panel of the Storybook UI when clicked. The action function takes an optional name parameter, which is used to identify the action in the UI.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"addon-actions-action-function.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/essentials/backgrounds.mdx",
    "content": "---\ntitle: 'Backgrounds'\nsidebar:\n  order: 2\n  title: Backgrounds\n---\n\nThe backgrounds feature allows you to set the background color on which the story renders in the UI:\n\n![Storybook with available backgrounds visible](../_assets/essentials/addon-backgrounds.png)\n\n## Configuration\n\nBy default, the backgrounds feature includes a light and dark background.\n\nBut you're not restricted to these backgrounds. You can configure your own set of colors with the `backgrounds` [parameter](../writing-stories/parameters.mdx) in your [`.storybook/preview.js|ts`](../configure/index.mdx#configure-story-rendering).\n\nYou can define the available background colors using the [`options` property](#options) and set the initial background color using the `initialGlobals` property:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"addon-backgrounds-options-in-preview.md\" />\n\n{/* prettier-ignore-end */}\n\n## Defining the background for a story\n\nThe backgrounds feature enables you to change the background color applied to a story by selecting from the list of predefined background colors in the toolbar. If needed, you can set a story to default to a specific background color, by using the `globals` option:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"addon-backgrounds-define-globals.md\" usesCsf3 />\n\n{/* prettier-ignore-end */}\n\n\n<Callout variant=\"info\">\n\n  When you specify a background color for a story (or a component's stories) using `globals`, the color is applied and cannot be changed using the toolbar. This is useful to ensure a story is always rendered on a specific background color.\n\n</Callout>\n\n## Extending the configuration\n\nYou can also configure backgrounds on a per-component or per-story basis through [parameter inheritance](../writing-stories/parameters.mdx#component-parameters).\n\nTo set the available background colors, use the [`options` property](#options). In this example, we'll adjust the colors for all of the Button component's stories:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"addon-backgrounds-options-in-meta.md\" />\n\n{/* prettier-ignore-end */}\n\n\n## Disable backgrounds\n\nIf you want to turn off backgrounds in a story, you can do so by configuring the `backgrounds` parameter like so:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"addon-backgrounds-disabled.md\" usesCsf3/>\n\n{/* prettier-ignore-end */}\n\n## Grid\n\nThe backgrounds feature also includes a Grid selector, which allows you to quickly see if your components are aligned.\n\nYou don't need additional configuration to get started. But its properties are fully customizable; if you don't supply any value to any of its properties, they'll default to the following values:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"addon-backgrounds-grid.md\" />\n\n{/* prettier-ignore-end */}\n\n## API\n\n### Globals\n\nThis module contributes the following globals to Storybook, under the `backgrounds` namespace:\n\n#### `grid`\n\nType: `boolean`\n\nWhether the [grid](#grid) is displayed.\n\n#### `value`\n\nType: `string`\n\nWhen set, the background color is applied and cannot be changed using the toolbar. Must match the key of one of the [available colors](#options).\n\n### Parameters\n\nThis module contributes the following [parameters](../writing-stories/parameters.mdx) to Storybook, under the `backgrounds` namespace:\n\n#### `disable`\n\nType: `boolean`\n\nDisable this feature's behavior. If you wish to disable this feature for the entire Storybook, you should [do so in your main configuration file](./index.mdx#disabling-features).\n\nThis parameter is most useful to allow overriding at more specific levels. For example, if this parameter is set to `true` at the project level, it could then be re-enabled by setting it to `false` at the meta (component) or story level.\n\n#### `grid`\n\nType:\n\n```ts\n{\n  cellAmount?: number;\n  cellSize?: number;\n  disable?: boolean;\n  offsetX?: number;\n  offsetY?: number;\n  opacity?: number;\n}\n```\n\nConfiguration for the [background grid](#grid).\n\n##### `grid.cellAmount`\n\nType: `number`\n\nDefault: `5`\n\nSpecify the size of the minor grid lines.\n\n##### `grid.cellSize`\n\nType: `number`\n\nDefault: `20`\n\nSpecify the size of the major grid lines.\n\n##### `grid.disable`\n\nType: `boolean`\n\nTurn off the grid.\n\n##### `grid.offsetX`\n\nType: `number`\n\nDefault: `0` if [story layout](../api/parameters.mdx#layout) is `'fullscreen'`; `16` if story layout is `'padded'`\n\nHorizontal offset of the grid.\n\n##### `grid.offsetY`\n\nType: `number`\n\nDefault: `0` if [story layout](../api/parameters.mdx#layout) is `'fullscreen'`; `16` if story layout is `'padded'`\n\nVertical offset of the grid.\n\n##### `grid.opacity`\n\nType: `number`\n\nDefault: `0.5`\n\nThe opacity of the grid lines.\n\n#### `options`\n\n(Required, see description)\n\nType:\n\n```ts\n{\n  [key: string]: {\n    name: string;\n    value: string;\n  };\n}\n```\n\nAvailable background colors. See above for a [usage example](#configuration).\n"
  },
  {
    "path": "docs/essentials/controls.mdx",
    "content": "---\ntitle: 'Controls'\nsidebar:\n  order: 3\n  title: Controls\n---\n\nStorybook Controls gives you a graphical UI to interact with a component's arguments dynamically without needing to code. Use the Controls panel to edit the inputs to your stories and see the results in real-time. It's a great way to explore your components and test different states.\n\n<Video src=\"../_assets/essentials/addon-controls-demo-optimized.mp4\" />\n\nControls do not require any modification to your components. Stories for controls are:\n\n* Convenient. Auto-generate controls based on React/Vue/Angular/etc. components.\n* Portable. Reuse your interactive stories in documentation, tests, and even in designs.\n* Rich. Customize the controls and interactive data to suit your exact needs.\n\nTo use Controls, you need to write your stories using [args](../writing-stories/args.mdx). Storybook will automatically generate UI controls based on your args and what it can infer about your component. Still, you can configure the controls further using [argTypes](../api/arg-types.mdx), see below.\n\n<Callout variant=\"info\" icon=\"💡\">\n  If you have stories in the older pre-Storybook 6 style, check the [args & controls migration guide](https://medium.com/storybookjs/storybook-6-migration-guide-200346241bb5) to learn how to convert your existing stories for args.\n</Callout>\n\n## Choosing the control type\n\n<IfRenderer renderer=\"angular\">\n  By default, Storybook will try to infer the required argTypes and associated controls for your stories based on the component's definition and initial value of the args using [Compodoc](https://compodoc.app/), a documentation generator for Angular applications that can extract the metadata of your components, including first-class support for Angular's `inputs`, `outputs`, `properties`, `methods`, and `view/content child/children`. If you opt-in to use it, you must take additional steps to set it up properly.\n\n  Run the following command to install the tooling.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"compodoc-install.md\" />\n\n  {/* prettier-ignore-end */}\n\n  Update your `angular.json` file to include the following configuration to include it in the Storybook's inbuilt builder configuration.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"angular-project-compodoc-config.md\" />\n\n  {/* prettier-ignore-end */}\n\n  Finally, update your `.storybook/preview.ts` file to include the following configuration to import the metadata generated by Compodoc and use it to generate the controls and argTypes for your stories.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"storybook-preview-compodoc-config.md\" />\n\n  {/* prettier-ignore-end */}\n\n  When you set the `component` annotation of the meta (or default export) of your story file, it will be used to infer the controls and auto-generate the matching [`argTypes`](../api/arg-types.mdx) for your component.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"button-story-default-export-with-component.md\" />\n\n  {/* prettier-ignore-end */}\n</IfRenderer>\n\n<IfRenderer renderer=\"ember\">\n  By default, Storybook will try to infer the required argTypes and associated controls for your stories based on the metadata provided by the [`@storybook/ember-cli-storybook`](https://github.com/storybookjs/ember-cli-storybook) adapter. You'll need to take some additional steps to set it up properly.\n\n  Update your `ember-cli-build.js` configuration file to include the adapter.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"storybook-ember-cli-build.md\" />\n\n  {/* prettier-ignore-end */}\n\n  Restart your application to generate the metadata file (i.e., `storybook-docgen/index.json`) and update your `.storybook/preview.js` file to include it, which will be used to create the controls and argTypes for your stories.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"storybook-preview-custom-metadata.md\" />\n\n  {/* prettier-ignore-end */}\n\n  <Callout variant=\"info\">\n    Enabling this feature will generate a `storybook-docgen/index.json` automatically with each build. For more information on how the metadata is generated, refer to [documentation](https://github.com/storybookjs/storybook/tree/next/code/frameworks/ember) for the Ember framework.\n  </Callout>\n\n  When you set the `component` annotation of the meta (or default export) of your story file, it will be used to infer the controls and auto-generate the matching [`argTypes`](../api/arg-types.mdx) for your component.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"button-story-default-export-with-component.md\" />\n\n  {/* prettier-ignore-end */}\n</IfRenderer>\n\n<IfRenderer renderer=\"react\">\n  By default, Storybook will choose a control for each arg based on its initial value. This will work well with specific arg types (e.g., `boolean` or `string`). To enable them, add the `component` annotation to the meta (or default export) of your story file, and it will be used to infer the controls and auto-generate the matching [`argTypes`](../api/arg-types.mdx) for your component using [`react-docgen`](https://github.com/reactjs/react-docgen), a documentation generator for React components that also includes first-class support for TypeScript.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"button-story-default-export-with-component.md\" />\n\n  {/* prettier-ignore-end */}\n</IfRenderer>\n\n<IfRenderer renderer=\"vue\">\n  By default, Storybook will choose a control for each arg based on its initial value. This will work well with specific arg types (e.g., `boolean` or `string`). To enable them, add the `component` annotation to the meta (or default export) of your story file, and it will be used to infer the controls and auto-generate the matching [`argTypes`](../api/arg-types.mdx) for your component using [`vue-docgen-api`](https://github.com/vue-styleguidist/vue-styleguidist/tree/dev/packages/vue-docgen-api), including first-class support for Vue's `props`, `events`, and `slots`.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"button-story-default-export-with-component.md\" />\n\n  {/* prettier-ignore-end */}\n</IfRenderer>\n\n<IfRenderer renderer=\"web-components\">\n  By default, Storybook will try to infer the required argTypes and associated controls for your stories based on the component's definition and the initial value of the args. You'll need to take some additional steps to set it up properly. You can opt to generate a [`custom-elements.json`](https://github.com/webcomponents/custom-elements-json) file with [`@custom-elements-manifest/analyzer`](https://github.com/open-wc/custom-elements-manifest) if you're using the `pre-v1.0.0` version of the elements file or [`@custom-elements-manifest/analyzer`](https://github.com/open-wc/custom-elements-manifest/tree/master/packages/analyzer) for newer versions and configure it in your Storybook UI configuration file (i.e., `.storybook/preview.js|ts`) to enable it.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"storybook-preview-custom-elements-config.md\" />\n\n  {/* prettier-ignore-end */}\n\n  When you set the `component` annotation of the meta (or default export) of your story file, it will be used to infer the controls and auto-generate the matching [`argTypes`](../api/arg-types.mdx) for your component.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"button-story-default-export-with-component.md\" />\n\n  {/* prettier-ignore-end */}\n</IfRenderer>\n\n<IfRenderer renderer={[ 'html', 'svelte', 'preact', 'qwik', 'solid' ]}>\n  By default, Storybook will choose a control for each arg based on its initial value. This will work well with specific arg types (e.g., `boolean` or `string`). To enable them, add the `component` annotation to the meta (or default export) of your story file, and it will be used to infer the controls and auto-generate the matching [`argTypes`](../api/arg-types.mdx) for your component provided by the framework you've chosen to use.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"button-story-default-export-with-component.md\" />\n\n  {/* prettier-ignore-end */}\n\n  <Callout variant=\"info\">\n    If you're using a framework that doesn't support this feature, you'll need to define the `argTypes` for your component [manually](#fully-custom-args).\n  </Callout>\n</IfRenderer>\n\nFor instance, suppose you have a `variant` arg on your story that should be `primary` or `secondary`:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-controls-primary-variant.md\" />\n\n{/* prettier-ignore-end */}\n\nBy default, Storybook will render a free text input for the `variant` arg:\n\n![Control using a string](../_assets/essentials/addon-controls-args-variant-string.png)\n\nIt works as long as you type a valid string into the auto-generated text control. Still, it's not the best UI for our scenario, given that the component only accepts `primary` or `secondary` as variants. Let’s replace it with Storybook’s radio component.\n\nWe can specify which controls get used by declaring a custom [argType](../api/arg-types.mdx) for the `variant` property. ArgTypes encode basic metadata for args, such as name, description, and defaultValue for an arg. These get automatically filled in by Storybook Docs.\n\n<IfRenderer renderer=\"svelte\">\n\n  `ArgTypes` can also contain arbitrary annotations, which the user can override. Since `variant` is a component property, let's put that annotation on the `defineMeta` function, or the default export if you're using standard CSF.\n\n</IfRenderer>\n\n<If notRenderer=\"svelte\">\n\n  `ArgTypes` can also contain arbitrary annotations, which the user can override. Since `variant` is a component property, let's put that annotation on the meta (or default export).\n\n</If>\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-controls-radio-group.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  ArgTypes are a powerful feature that can be used to customize the controls for your stories. For more information, see the documentation about [customizing controls](#annotation) with `argTypes` annotation.\n</Callout>\n\nThis replaces the input with a radio group for a more intuitive experience.\n\n![Control with a radio group](../_assets/essentials/addon-controls-args-variant-optimized.png)\n\n## Custom control type matchers\n\nControls can automatically be inferred from arg's name with [regex](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/RegExp), but currently only for the color picker and date picker controls. If you've used the Storybook CLI to setup your project, it should have automatically created the following defaults in `.storybook/preview.js|ts`:\n\n| Control   | Default regex                            | Description                                               |\n| --------- | ---------------------------------------- | --------------------------------------------------------- |\n| **color** | <code>{`/(background\\|color)$/i`}</code> | Will display a color picker UI for the args that match it |\n| **date**  | `/Date$/`                                | Will display a date picker UI for the args that match it  |\n\nIf you haven't used the CLI to set the configuration, or if you want to define your patterns, use the `matchers` property in the `controls` parameter:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-controls-custom-matchers.md\" />\n\n{/* prettier-ignore-end */}\n\n## Fully custom args\n\nUntil now, we only used auto-generated controls based on the component for which we're writing stories. If we are writing [complex stories](../writing-stories/stories-for-multiple-components.mdx), we may want to add controls for args that aren’t part of the component. For example, here's how you could use a `footer` arg to populate a child component:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"page-story-slots.md\"/>\n\n{/* prettier-ignore-end */}\n\nBy default, Storybook will add controls for all args that:\n\n  * It infers from the component definition [if your framework supports it](../configure/integration/frameworks-feature-support.mdx).\n\n  * Appear in the list of args for your story.\n\nUsing `argTypes`, you can change the display and behavior of each control.\n\n\n### Dealing with complex values\n\nWhen dealing with non-primitive values, you'll notice that you'll run into some limitations. The most obvious issue is that not every value can be represented as part of the `args` param in the URL, losing the ability to share and deep link to such a state. Beyond that, complex values such as JSX cannot be synchronized between the manager (e.g., the Controls panel) and the preview (your story).\n\nOne way to deal with this is to use primitive values (e.g., strings) as arg values and add a custom `render` function to convert them to their complex counterpart before rendering. It isn't the nicest way to do it (see below), but certainly the most flexible.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"component-story-custom-args-complex.md\" />\n\n{/* prettier-ignore-end */}\n\nUnless you need the flexibility of a function, an easier way to map primitives to complex values before rendering is to define a `mapping`; additionally, you can specify `control.labels` to configure custom labels for your checkbox, radio, or select input.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"component-story-custom-args-mapping.md\" />\n\n{/* prettier-ignore-end */}\n\nNote that both `mapping` and `control.labels` don't have to be exhaustive. If the currently selected option is not listed, it's used verbatim.\n\n## Creating and editing stories from controls\n\n<If renderer=\"svelte\">\n\n  <Callout variant=\"info\">\n\n    This feature is not supported with the Svelte CSF. To opt-in to this feature with Svelte, you must use Storybook's [Component Story Format](../api/csf/index.mdx).\n  \n  </Callout>\n  \n</If>\n\nYou can create or edit stories, directly from the Controls panel.\n\n### Create a new story\n\nOpen the Controls panel for a story and adjust the value of a control. Then save those changes as a new story.\n\n<Video src=\"../_assets/get-started/new-story-from-controls-optimized.mp4\" />\n\n<If renderer=\"react\">\n  If you're working on a component that does not yet have any stories, you can click the ➕ button in the sidebar to search for your component and have a basic story created for you.\n\n  <Video src=\"../_assets/get-started/new-component-story-from-plus-button-optimized.mp4\" />\n</If>\n\n### Edit a story\n\nYou can also update a control's value, then save the changes to the story. The story file's code will be updated for you.\n\n<Video src=\"../_assets/get-started/edit-story-from-controls-optimized.mp4\" />\n\n### Disable creating and editing of stories\n\nIf you don't want to allow the creation or editing of stories from the Controls panel, you can disable this feature by setting the `disableSaveFromUI` parameter to `true` in the `parameters.controls` parameter in your `.storybook/preview.js|ts` file.\n\n## Configuration\n\nControls can be configured in two ways:\n\n* Individual controls can be configured via control annotations.\n* The panel's appearance can be configured via parameters.\n\n### Annotation\n\nAs shown above, you can configure individual controls with the “control\" annotation in the [argTypes](../api/arg-types.mdx) field of either a component or story. Below is a condensed example and table featuring all available controls.\n\n| Data Type   | Control        | Description                                                                                                                                                                                                                 |\n| ----------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| **boolean** | `boolean`      | Provides a toggle for switching between possible states.<br /> `argTypes: { active: { control: 'boolean' }}`                                                                                                                |\n| **number**  | `number`       | Provides a numeric input to include the range of all possible values.<br /> `argTypes: { even: { control: { type: 'number', min:1, max:30, step: 2 } }}`                                                                    |\n|             | `range`        | Provides a range slider component to include all possible values.<br /> `argTypes: { odd: { control: { type: 'range', min: 1, max: 30, step: 3 } }}`                                                                        |\n| **object**  | `object`       | Provides a JSON-based editor component to handle the object's values.<br /> Also allows edition in raw mode.<br /> `argTypes: { user: { control: 'object' }}`                                                               |\n| **array**   | `object`       | Provides a JSON-based editor component to handle the array's values.<br /> Also allows edition in raw mode.<br /> `argTypes: { odd: { control: 'object' }}`                                                                 |\n|             | `file`         | Provides a file input component that returns an array of URLs.<br /> Can be further customized to accept specific file types.<br /> `argTypes: { avatar: { control: { type: 'file', accept: '.png' } }}`                    |\n| **enum**    | `radio`        | Provides a set of radio buttons based on the available options.<br /> `argTypes: { contact: { control: 'radio', options: ['email', 'phone', 'mail'] }}`                                                                     |\n|             | `inline-radio` | Provides a set of inlined radio buttons based on the available options.<br /> `argTypes: { contact: { control: 'inline-radio', options: ['email', 'phone', 'mail'] }}`                                                      |\n|             | `check`        | Provides a set of checkbox components for selecting multiple options.<br /> `argTypes: { contact: { control: 'check', options: ['email', 'phone', 'mail'] }}`                                                               |\n|             | `inline-check` | Provides a set of inlined checkbox components for selecting multiple options.<br /> `argTypes: { contact: { control: 'inline-check', options: ['email', 'phone', 'mail'] }}`                                                |\n|             | `select`       | Provides a drop-down list component to handle single value selection. `argTypes: { age: { control: 'select', options: [20, 30, 40, 50] }}`                                                                                  |\n|             | `multi-select` | Provides a drop-down list that allows multiple selected values. `argTypes: { countries: { control: 'multi-select', options: ['USA', 'Canada', 'Mexico'] }}`                                                                 |\n| **string**  | `text`         | Provides a freeform text input. <br /> `argTypes: { label: { control: 'text' }}`                                                                                                                                            |\n|             | `color`        | Provides a color picker component to handle color values.<br /> Can be additionally configured to include a set of color presets.<br /> `argTypes: { color: { control: { type: 'color', presetColors: ['red', 'green']} }}` |\n|             | `date`         | Provides a datepicker component to handle date selection. `argTypes: { startDate: { control: 'date' }}`                                                                                                                     |\n\n<Callout variant=\"info\" icon=\"💡\">\n  The `date` control will convert the date into a UNIX timestamp when the value changes. It's a known limitation that will be fixed in a future release. If you need to represent the actual date, you'll need to update the story's implementation and convert the value into a date object.\n</Callout>\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"gizmo-story-controls-customization.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  Numeric data types will default to a `number` control unless additional configuration is provided.\n</Callout>\n\n### Parameters\n\nControls supports the following configuration [parameters](../writing-stories/parameters.mdx), either globally or on a per-story basis:\n\n#### Show full documentation for each property\n\nSince Controls is built on the same engine as Storybook Docs, it can also show property documentation alongside your controls using the expanded parameter (defaults to false). This means you embed a complete [`Controls`](../api/doc-blocks/doc-block-controls.mdx) doc block in the controls panel. The description and default value rendering can be [customized](#fully-custom-args) like the doc block.\n\nTo enable expanded mode globally, add the following to [`.storybook/preview.js|ts`](../configure/index.mdx#configure-story-rendering):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-expanded-controls.md\" />\n\n{/* prettier-ignore-end */}\n\nHere's what the resulting UI looks like:\n\n![Controls table expanded](../_assets/essentials/addon-controls-expanded.png)\n\n#### Specify initial preset color swatches\n\nFor `color` controls, you can specify an array of `presetColors`, either on the `control` in `argTypes`, or as a parameter under the `controls` namespace:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-parameters-color-swatches.md\" />\n\n{/* prettier-ignore-end */}\n\nColor presets can be defined as an object with `color` and `title` or a simple CSS color string. These will then be available as swatches in the color picker. When you hover over the color swatch, you'll be able to see its title. It will default to the nearest CSS color name if none is specified.\n\n#### Filtering controls\n\nIn specific cases, you may be required to display only a limited number of controls in the controls panel or all except a particular set.\n\nTo make this possible, you can use optional `include` and `exclude` configuration fields in the `controls` parameter, which you can define as an array of strings or a regular expression.\n\nConsider the following story snippets:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"component-story-disable-controls-regex.md\" />\n\n{/* prettier-ignore-end */}\n\n#### Sorting controls\n\nBy default, controls are unsorted and use whatever order the args data is processed in (`none`). Additionally, you can sort them alphabetically by the arg's name (`alpha`) or with the required args first (`requiredFirst`).\n\nConsider the following snippet to force required args first:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"component-story-sort-controls.md\" />\n\n{/* prettier-ignore-end */}\n\n### Disable controls for specific properties\n\nAside from the features already documented here, Controls can also be disabled for individual properties.\n\nSuppose you want to turn off Controls for a property called `foo` in a component's story. The following example illustrates how:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"component-story-disable-controls.md\" />\n\n{/* prettier-ignore-end */}\n\nResulting in the following change in Storybook UI:\n\n<Video src=\"../_assets/essentials/addon-controls-disable-specific-prop-optimized.mp4\" />\n\nThe previous example also removed the prop documentation from the table. In some cases, this is fine. However, sometimes you might want to render the prop documentation without a control. The following example illustrates how:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"component-story-disable-controls-alt.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  As with other Storybook properties, such as [decorators](../writing-stories/decorators.mdx), you can apply the same pattern at a story level for more granular cases.\n</Callout>\n\n### Conditional controls\n\nIn some cases, it's useful to be able to conditionally exclude a control based on the value of another control. Controls supports basic versions of these use cases with the `if`, which can take a simple query object to determine whether to include the control.\n\nConsider a collection of \"advanced\" settings only visible when the user toggles an \"advanced\" toggle.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"component-story-conditional-controls-toggle.md\" />\n\n{/* prettier-ignore-end */}\n\nOr consider a constraint where if the user sets one control value, it doesn't make sense for the user to be able to set another value.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"component-story-conditional-controls-mutual-exclusion.md\" />\n\n{/* prettier-ignore-end */}\n\nThe query object must contain either an `arg` or `global` target:\n\n| field  | type   | meaning                       |\n| ------ | ------ | ----------------------------- |\n| arg    | string | The ID of the arg to test.    |\n| global | string | The ID of the global to test. |\n\nIt may also contain at most one of the following operators:\n\n| operator | type    | meaning                                              |\n| -------- | ------- | ---------------------------------------------------- |\n| truthy   | boolean | Is the target value truthy?                          |\n| exists   | boolean | Is the target value defined?                         |\n| eq       | any     | Is the target value equal to the provided value?     |\n| neq      | any     | Is the target value NOT equal to the provided value? |\n\nIf no operator is provided, that is equivalent to `{ truthy: true }`.\n\n## Troubleshooting\n\n<IfRenderer renderer={['angular', 'ember', 'web-components']}>\n  ### Controls are not automatically generated for my component\n\n  If you're working with Angular, Ember, or Web Components, automatic argTypes and controls inference will not work out of the box and requires you to provide [additional configuration](#choosing-the-control-type) to allow Storybook to retrieve the necessary metadata and generate the needed argTypes and controls for your stories. However, if you need additional customization, you can always [define them manually](#fully-custom-args).\n</IfRenderer>\n\n### The controls are not updating the story within the auto-generated documentation\n\nIf you turned off inline rendering for your stories via the [`inline`](../api/doc-blocks/doc-block-story.mdx#inline) configuration option, you would run into a situation where the associated controls are not updating the story within the documentation page. This is a known limitation of the current implementation and will be addressed in a future release.\n\n## API\n\n### Parameters\n\nThis feature contributes the following [parameters](../writing-stories/parameters.mdx) to Storybook, under the `controls` namespace:\n\n#### `disable`\n\nType: `boolean`\n\nDisable this feature's behavior. If you wish to disable this feature for the entire Storybook, you should [do so in your main configuration file](./index.mdx#disabling-features).\n\nThis parameter is most useful to allow overriding at more specific levels. For example, if this parameter is set to `true` at the project level, it could then be re-enabled by setting it to `false` at the meta (component) or story level.\n\n#### `exclude`\n\nType: `string[] | RegExp`\n\nSpecifies which properties to exclude from the Controls panel. Any properties whose names match the regex or are part of the array will be left out. See [usage example](#filtering-controls), above.\n\n#### `expanded`\n\nType: `boolean`\n\nShow the full documentation for each property in the Controls panel, including the description and default value. See [usage example](#show-full-documentation-for-each-property), above.\n\n#### `include`\n\nType: `string[] | RegExp`\n\nSpecifies which properties to include in the Controls panel. Any properties whose names don't match the regex or are not part of the array will be left out. See [usage example](#filtering-controls), above.\n\n#### `presetColors`\n\nType: `(string | { color: string; title?: string })[]`\n\nSpecify preset color swatches for the color picker control. The color value may be any valid CSS color. See [usage example](#specify-initial-preset-color-swatches), above.\n\n#### `sort`\n\nType: `'none' | 'alpha' | 'requiredFirst'`\n\nDefault: `'none'`\n\nSpecifies how the controls are sorted.\n\n* **none**: Unsorted, displayed in the same order the arg types are processed in\n* **alpha**: Sorted alphabetically, by the arg type's name\n* **requiredFirst**: Same as `alpha`, with any required arg types displayed first\n\n#### `disableSaveFromUI`\n\nType: `boolean`\n\nDefault: `false`\n\nDisable the ability to create or edit stories from the Controls panel.\n"
  },
  {
    "path": "docs/essentials/highlight.mdx",
    "content": "---\ntitle: 'Highlight'\nsidebar:\n  order: 4\n  title: Highlight\n---\n\nStorybook's Highlight feature is a helpful tool for visually debugging your components. It allows you to highlight specific DOM nodes within your story when used directly or enhancing addons such as the [Accessibility addon](../writing-tests/accessibility-testing.mdx) to inform you of accessibility issues within your components.\n\n![Story with highlighted elements](../_assets/essentials/highlight.png)\n\n## Highlighting DOM Elements\n\nTo highlight DOM elements with the feature, you'll need to emit the `HIGHLIGHT` event from within a story or an addon. The event payload must contain a `selectors` property assigned to an array of selectors matching the elements you want to highlight. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"component-story-highlight.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  We recommend choosing the most specific selector possible to avoid highlighting elements other addons use. This is because the feature tries to match selectors against the entire DOM tree.\n</Callout>\n\n### Customize style\n\nBy default, highlighted elements contain a standard outline style applied to the selected elements. However, you can enable your custom style by extending the payload object with additional properties to customize the appearance of the highlighted elements. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"highlight-custom-style.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  These properties are optional, and you can use them to customize the appearance of the highlighted elements. The `hoverStyles` and `focusStyles` properties are recommended for use with the `menu` property. Pseudo-classes and pseudo-elements are not supported.\n</Callout>\n\n### Highlight menu\n\nThe Highlight feature includes a built-in debugging option, allowing you to select the highlighted elements when you click them. This is particularly useful for inspecting the elements affected by the feature, as it lets you preview a list of elements matching the selector you provided. To enable it, add a `menu` property in the payload object containing additional information about the elements or trigger actions. Each item must include an `id` and a `title`, and you can also provide an optional `selectors` property to limit the menu item to specific highlighted elements.\n\n![Menu with custom items](../_assets/essentials/highlight-menu.png)\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"highlight-menu.md\" />\n\n{/* prettier-ignore-end */ }\n\nWhen enabled, the menu will be displayed when you click on the selected element matching your provided selectors. However, if you don't want to show any information, you can omit the items or set the `menu` property to an empty array to show the default menu.\n\n![Menu of selectable targets](../_assets/essentials/highlight-selectable.png)\n\n## Remove highlights\n\nIf you need to remove a highlight from a specific element, you can do so by emitting the `REMOVE_HIGHLIGHT` event and providing the `id` of the highlight you want to remove. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"highlight-remove.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  The `emit` function derived from the `useChannel` API hook creates a communication channel in Storybook's UI to listen for events and update the UI accordingly. The Highlight feature uses this channel to listen to custom events and update the highlighted elements (if any) accordingly.\n</Callout>\n\n## Reset highlighted elements\n\nOut of the box, Storybook automatically removes highlighted elements when transitioning between stories. However, if you need to clear them manually, you can emit the `RESET_HIGHLIGHT` event from within a story or an addon. This removes all highlights, even ones created by other addons. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"highlight-reset.md\" />\n\n{/* prettier-ignore-end */}\n\n## Scroll element into view\n\nThe Highlight feature allows you to scroll an element into view and highlight it. To enable it, emit the `SCROLL_INTO_VIEW` event from within a story or an addon. The event payload must contain a `selector` property to target the element you want to scroll into view. When the element is visible, it will be highlighted for a brief moment.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"highlight-scroll-into-view.md\" />\n\n{/* prettier-ignore-end */}\n\n## API\n\n### Parameters\n\nThis feature contributes the following [parameters](../writing-stories/parameters.mdx) to Storybook, under the `highlight` namespace:\n\n#### `disable`\n\nType: `boolean`\n\nDisable this feature's behavior. If you wish to turn off this feature for the entire Storybook, you should [do so in your main configuration file](./index.mdx#disabling-features).\n\nThis parameter is most useful to allow overriding at more specific levels. For example, if this parameter is set to `true` at the project level, it could be re-enabled by setting it to `false` at the meta (component) or story level.\n\n### Exports\n\nThis feature contributes the following exports to Storybook:\n\n```js\nimport { HIGHLIGHT, REMOVE_HIGHLIGHT, RESET_HIGHLIGHT, SCROLL_INTO_VIEW } from 'storybook/highlight';\n```\n\n#### `HIGHLIGHT`\n\nAn event to highlight DOM elements. The event payload must contain a `selectors` property assigned to an array of selectors matching the elements you want to highlight. It can be extended with an optional object containing additional configuration options. See the [usage example](#highlighting-dom-elements) above.\n\n```ts\nimport { HIGHLIGHT, type HighlightOptions } from 'storybook/highlight';\n\nchannel.emit(\n  HIGHLIGHT,\n  options // The available configuration options inheriting from the HighlightOptions API\n);\n```\n\nThe `options` object contains the following properties:\n\n```ts\ninterface HighlightOptions {\n  /** Unique identifier for the highlight, required if you want to remove the highlight later */\n  id?: string;\n  /** HTML selectors of the elements */\n  selectors: string[];\n  /** Priority of the highlight, higher takes precedence, defaults to 0 */\n  priority?: number;\n  /** CSS styles to apply to the highlight */\n  styles?: Record<string, string>;\n  /** CSS styles to apply to the highlight when it is hovered */\n  hoverStyles?: Record<string, string>;\n  /** CSS styles to apply to the highlight when it is focused or selected */\n  focusStyles?: Record<string, string>;\n  /** Keyframes required for animations */\n  keyframes?: string;\n  /** Groups of menu items to show when the highlight is selected */\n  menu?: HighlightMenuItem[][];\n}\n\ninterface HighlightMenuItem {\n  /** Unique identifier for the menu item */\n  id: string;\n  /** Title of the menu item */\n  title: string;\n  /** Description of the menu item */\n  description?: string;\n  /** Icon for the menu item, left side */\n  iconLeft?: \"chevronLeft\" | \"chevronRight\" | \"info\" | \"shareAlt\";\n  /** Icon for the menu item, right side */\n  iconRight?: \"chevronLeft\" | \"chevronRight\" | \"info\" | \"shareAlt\";\n  /** Name for a channel event to trigger when the menu item is clicked */\n  clickEvent?: string;\n  /** HTML selectors for which this menu item should show (subset of HighlightOptions['selectors']) */\n  selectors?: HighlightOptions['selectors'];\n}\n```\n\nMenu items can specify a `clickEvent` to be emitted on the channel when the item is clicked. The channel event will receive two arguments: the menu item `id` and a `ClickEventDetails` object with the following properties:\n\n```ts\ninterface ClickEventDetails {\n  // Position and dimensions of the element on the page\n  top: number;\n  left: number;\n  width: number;\n  height: number;\n  // Selector(s) which matched the element\n  selectors: string[];\n  // DOM element details\n  element: {\n    attributes: Record<string, string>;\n    localName: string;\n    tagName: string;\n    outerHTML: string;\n  };\n}\n```\n\nTo listen for this event (assuming `clickEvent: 'MY_CLICK_EVENT'`):\n\n```ts\nimport type { ClickEventDetails } from 'storybook/highlight';\n\nconst handleClickEvent = (itemId: string, details: ClickEventDetails) => {\n  // Handle the menu item click event\n}\n\n// When you have a channel instance:\nchannel.on('MY_CLICK_EVENT', handleClickEvent)\n\n// Or from a decorator:\nuseChannel({\n  MY_CLICK_EVENT: handleClickEvent,\n}, [handleClickEvent])\n```\n\n#### `REMOVE_HIGHLIGHT`\n\nAn event that removes a previously created highlight. The event payload must contain an `id` property assigned to the id of the highlight you want to remove. See the [usage example](#remove-highlights) above.\n\n```ts\nimport { REMOVE_HIGHLIGHT } from 'storybook/highlight';\n\nchannel.emit(\n  REMOVE_HIGHLIGHT,\n  id // The id of the previously created highlight to be removed\n);\n```\n\n#### `RESET_HIGHLIGHT`\n\nAn event to clear all highlights from highlighted elements. See the [usage example](#reset-highlighted-elements) above.\n\n```ts\nimport { RESET_HIGHLIGHT } from 'storybook/highlight';\n\nchannel.emit(RESET_HIGHLIGHT);\n```\n\n#### `SCROLL_INTO_VIEW`\n\nAn event to scroll a DOM element into view and briefly highlight it. The event payload must contain a selector property assigned to the selector of the element you want to scroll into view. Optionally, you can provide a [`options`](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView#scrollintoviewoptions) object to customize the scroll behavior. See the [usage example](#scroll-element-into-view) above.\n\n```ts\nimport { SCROLL_INTO_VIEW } from 'storybook/highlight';\n\nchannel.emit(\n  SCROLL_INTO_VIEW,\n  selector // Element selector to scroll into view\n  options // An object inheriting from ScrollIntoViewOptions API to customize the scroll behavior\n);\n```\n"
  },
  {
    "path": "docs/essentials/index.mdx",
    "content": "---\ntitle: Essentials\nhideRendererSelector: true\nsidebar:\n  order: 8\n  title: Essentials\n---\n\nStorybook essentials is a set of tools that help you build, test, and document your components within Storybook. It includes the following:\n\n* [Actions](./actions.mdx)\n* [Backgrounds](./backgrounds.mdx)\n* [Controls](./controls.mdx)\n* [Highlight](./highlight.mdx)\n* [Measure & outline](./measure-and-outline.mdx)\n* [Toolbars & globals](./toolbars-and-globals.mdx)\n* [Viewport](./viewport.mdx)\n\n### Configuration\n\nEssentials is \"zero-config”. It comes with a recommended configuration out of the box.\n\nMany of the features above can be configured via [parameters](../writing-stories/parameters.mdx). See each feature's documentation (linked above) for more details.\n\n### Disabling features\n\nIf you need to disable any of the essential features, you can do it by changing your [`.storybook/main.js|ts`](../configure/index.mdx#configure-your-storybook-project) file.\n\nFor example, if you wanted to disable the [backgrounds feature](./backgrounds.mdx), you would apply the following change to your Storybook configuration:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"essential-feature-disable.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  You can use the following keys for each individual feature: `actions`, `backgrounds`, `controls`, `highlight`, `measure`, `outline`, `toolbars`, and `viewport`.\n</Callout>\n"
  },
  {
    "path": "docs/essentials/measure-and-outline.mdx",
    "content": "---\ntitle: 'Measure & outline'\nsidebar:\n  order: 6\n  title: Measure & outline\n---\n\nStorybook's measure and outline features give you the necessary tooling to inspect and visually debug CSS layout and alignment issues within your stories. It makes it easy to catch UI bugs early in development.\n\n## Measure\n\nWhile working with composite components or page layouts, dealing with whitespace (i.e., `margin`, `padding`, `border`) and individual component measurements can be tedious. It would require that you open up the browser's development tools and manually inspect the DOM tree for issues and UI bugs.\n\nInstead, you can quickly visualize each component's measurements by clicking the measure button in the toolbar. Now when you hover over an element in your story, that element's dimensions and any whitespace (i.e., `margin`, `padding`, `border`) will be shown.\n\n![Measure feature enabled displaying the component's dimensions](../_assets/essentials/addon-measure.png)\n\n<Callout variant=\"info\" icon=\"💡\">\n  Alternatively you can press the `m` key on your keyboard to toggle measure on and off.\n</Callout>\n\n## Outline\n\nWhen building your layouts, checking the visual alignment of all components can be pretty complicated, especially if your components are spread apart or contain unique shapes.\n\nClick the outline button in the toolbar to toggle the outlines associated with all your UI elements, allowing you to spot bugs and broken layouts instantly.\n\n![Outline feature enabled on the component's story](../_assets/essentials/addon-outline.png)\n\n## API\n\n### Parameters\n\nThese features contribute the following [parameters](../writing-stories/parameters.mdx) to Storybook, under the `measure` or `outline` namespace:\n\n#### `disable`\n\nType: `boolean`\n\nDisable the feature's behavior. If you wish to disable the feature for the entire Storybook, you should [do so in your main configuration file](./index.mdx#disabling-features).\n\nThis parameter is most useful to allow overriding at more specific levels. For example, if this parameter is set to `true` at the project level, it could then be re-enabled by setting it to `false` at the meta (component) or story level.\n"
  },
  {
    "path": "docs/essentials/themes.mdx",
    "content": "---\ntitle: Themes\ndraft: true\nsidebar:\n  order: 9\n  title: Themes\n---\n\nStorybook's [Themes](https://github.com/storybookjs/storybook/tree/next/code/addons/themes) addon allows you to switch between multiple themes for your components inside of the preview in [Storybook](https://storybook.js.org).\n\n![Switching between themes in Storybook](../_assets/essentials/addon-themes-example.gif)\n\n## Theme decorators\n\nTo make your themes accessible to your stories, `@storybook/addon-themes` exposes three [decorators](https://storybook.js.org/docs/writing-stories/decorators) for different methods of theming.\n\n### JSX providers\n\nFor libraries that expose themes to components through providers, such as [Material UI](https://storybook.js.org/recipes/@mui/material/), [Styled-components](https://storybook.js.org/recipes/styled-components/), and [Emotion](https://storybook.js.org/recipes/@emotion/styled/), use the `withThemeFromJSXProvider`.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-themes-jsx-provider-decorator.md\" />\n\n{/* prettier-ignore-end */}\n\n### CSS classes\n\nFor libraries that rely on CSS classes on a parent element to determine the theme, you can use the `withThemeByClassName` decorator.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-themes-classname-decorator.md\" />\n\n{/* prettier-ignore-end */}\n\n### Data attributes\n\nFor libraries that rely on data attributes on a parent element to determine the theme, you can use the `withThemeByDataAttribute` decorator.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-themes-data-attribute-decorator.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/essentials/toolbars-and-globals.mdx",
    "content": "---\ntitle: 'Toolbars & globals'\nsidebar:\n  order: 7\n  title: Toolbars & globals\n---\n\nStorybook ships with features to control the [viewport](./viewport.mdx) and [background](./backgrounds.mdx) the story renders in. Similarly, you can use built-in features to create toolbar items which control special “globals”. You can then read the global values to create [decorators](../writing-stories/decorators.mdx) to control story rendering.\n\n![Toolbars and globals](../_assets/essentials/toolbars-and-globals.png)\n\n## Globals\n\nGlobals in Storybook represent “global” (as in not story-specific) inputs to the rendering of the story. As they aren’t specific to the story, they aren’t passed in the `args` argument to the story function (although they are accessible as `context.globals`). Instead, they are typically used in decorators, which apply to all stories.\n\nWhen the globals change, the story re-renders and the decorators rerun with the new values. The easiest way to change globals is to create a toolbar item for them.\n\n## Global types and the toolbar annotation\n\nStorybook has a simple, declarative syntax for configuring toolbar menus. In your [`.storybook/preview.js|ts`](../configure/index.mdx#configure-story-rendering), you can add your own toolbars by creating `globalTypes` with a `toolbar` annotation:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-configure-globaltypes.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n\n As globals are *global* you can *only* set `globalTypes` and `initialGlobals` in [`.storybook/preview.js|ts`](../configure/index.mdx#configure-story-rendering).\n\n</Callout>\n\nWhen you start your Storybook, your toolbar should have a new dropdown menu with the `light` and `dark` options.\n\n## Create a decorator\n\nWe have a `global` implemented. Let's wire it up! We can consume our new `theme` global in a decorator using the `context.globals.theme` value.\n\n<IfRenderer renderer=\"react\">\n For example, suppose you are using [`styled-components`](https://styled-components.com/). You can add a theme provider decorator to your [`.storybook/preview.js|ts`](../configure/index.mdx#configure-story-rendering) config:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"storybook-preview-use-global-type.md\" />\n\n  {/* prettier-ignore-end */}\n</IfRenderer>\n\n<IfRenderer renderer=\"vue\">\n For example, suppose you are using [`Vuetify`](https://vuetifyjs.com/en/). You can add a theme provider decorator to your [`.storybook/preview.js|ts`](../configure/index.mdx#configure-story-rendering) config:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"storybook-preview-use-global-type.md\" />\n\n  {/* prettier-ignore-end */}\n</IfRenderer>\n\n<IfRenderer renderer=\"angular\">\n For example, suppose you are using [`Angular Material`](https://material.angular.io/). You can add a theme provider decorator to your [`.storybook/preview.js|ts`](../configure/index.mdx#configure-story-rendering) config:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"storybook-preview-use-global-type.md\" />\n\n  {/* prettier-ignore-end */}\n</IfRenderer>\n\n<IfRenderer renderer={['ember', 'html', 'preact', 'qwik', 'svelte', 'solid', 'web-components' ]}>\n Depending on your framework and theming library, you can extend your [`.storybook/preview.js|ts`](../configure/index.mdx#configure-story-rendering) and provide a decorator to load the theme. For example:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"storybook-preview-use-global-type.md\" />\n\n  {/* prettier-ignore-end */}\n</IfRenderer>\n\n## Setting globals on a story\n\nWhen a global value is changed with a toolbar menu in Storybook, that value continues to be used as you navigate between stories. But sometimes a story requires a specific value to render correctly, e.g., when testing against a particular environment.\n\nTo ensure that a story always uses a specific global value, regardless of what has been chosen in the toolbar, you can set the `globals` annotation on a story or component. This overrides the global value for those stories and disables the toolbar menu for that global when viewing the stories.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"addon-backgrounds-define-globals.md\" />\n\n{/* prettier-ignore-end */}\n\nIn the example above, Storybook will force all Button stories to use a gray background color, except the `OnDark` story, which will use the dark background. For all Button stories, the toolbar menu will be disabled for the `backgrounds` global, with a tooltip explaining that the global is set at the story level.\n\n<Callout variant=\"info\" icon=\"💡\">\n\nConfiguring a story's `globals` annotation to override the project-level global settings is useful but should be used with moderation. Globals that are _not_ defined at the story level can be selected interactively in Storybook's UI, allowing users to explore every existing combination of values (e.g., global values, [`args`](../writing-stories/args.mdx)). Setting them at the story level will disable that control, preventing users from exploring the available options.\n\n</Callout>\n\n## Advanced usage\n\nSo far, we've created and used a global inside Storybook.\n\nNow, let's take a look at a more complex example. Suppose we wanted to implement a new global called **locale** for internationalization, which shows a flag on the right side of the toolbar.\n\nIn your [`.storybook/preview.js|ts`](../configure/index.mdx#configure-story-rendering), add the following:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-locales-globaltype.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\" style={{ marginBottom: '10px' }}>\n\nThe `icon` element used in the examples loads the icons from the `@storybook/icons` package. See [here](../faq.mdx#what-icons-are-available-for-my-toolbar-or-my-addon) for the list of available icons that you can use.\n  \n</Callout>\n\nAdding the configuration element `right` will display the text on the right side in the toolbar menu once you connect it to a decorator.\n\nHere's a list of the available configuration options.\n\n| MenuItem  | Type   | Description                                                     | Required |\n| --------- | ------ | --------------------------------------------------------------- | -------- |\n| **value** | String | The string value of the menu that gets set in the globals       | Yes      |\n| **title** | String | The main text of the title                                      | Yes      |\n| **right** | String | A string that gets displayed on the right side of the menu      | No       |\n| **icon**  | String | An icon that gets shown in the toolbar if this item is selected | No       |\n\n## Consuming globals from within a story\n\nWe recommend consuming globals from within a decorator and defining a global setting for all stories.\n\nBut we're aware that sometimes it's more beneficial to use toolbar options on a per-story basis.\n\nUsing the example above, you can modify any story to retrieve the **Locale** `global` from the story context:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"my-component-story-use-globaltype.md\" />\n\n{/* prettier-ignore-end */}\n\n## Consuming globals from within an addon\n\nIf you're working on a Storybook addon and need to retrieve globals, you can do so. The `storybook/manager-api` module provides a hook for this scenario. You can use the [`useGlobals()`](../addons/addons-api.mdx#useglobals) hook to retrieve any globals you want.\n\nUsing the ThemeProvider example above, you could expand it to display which theme is active inside a panel as such:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"addon-consume-globaltype.md\" />\n\n{/* prettier-ignore-end */}\n\n## Updating globals from within an addon\n\nIf you're working on a Storybook addon that needs to update the global and refresh the UI, you can do so. As mentioned previously, the `storybook/manager-api` module provides the necessary hook for this scenario. You can use the `updateGlobals` function to update any global values you need.\n\nFor example, if you were working on a [toolbar addon](../addons/addon-types.mdx#toolbars), and you want to refresh the UI and update the global once the user clicks on a button:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"addon-consume-and-update-globaltype.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/essentials/viewport.mdx",
    "content": "---\ntitle: 'Viewport'\nsidebar:\n  order: 8\n  title: Viewport\n---\n\nThe viewport feature allows you to adjust the dimensions of the iframe your story is rendered in. It makes it easy to develop responsive UIs.\n\n![Storybook with default viewports visible](../_assets/essentials/addon-viewports.png)\n\n## Configuration\n\nOut of the box, the viewport feature offers you a standard set of viewports that you can use. If you want to change the default set of viewports, you can configure your own viewports with the `viewport` [parameter](../writing-stories/parameters.mdx) in your [`.storybook/preview.js|ts`](../configure/index.mdx#configure-story-rendering).\n\nYou can define the available viewports using the [`options` property](#options) and set the initial viewport using the `initialGlobals` property:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"addon-viewport-options-in-preview.md\" />\n\n{/* prettier-ignore-end */}\n\n### Use a detailed set of devices\n\nBy default, the viewport feature will use a minimal set of viewports, which enables you to test your UI in common responsive scenarios. These are also available in the [`MINIMAL_VIEWPORTS` export](#minimal_viewports) and include the following devices:\n\n| Key       | Description  | Dimensions<br />(<abbr title=\"width\">w</abbr>×<abbr title=\"height\">h</abbr>, px) |\n| ----------|------------- | -------------------------------------------------------------------------------- |\n| `mobile1` | Small mobile | 320 × 568                                                                        |\n| `mobile2` | Large mobile | 414 × 896                                                                        |\n| `tablet`  | Tablet       | 834 × 1112                                                                       |\n| `desktop` | Desktop      | 1024 × 1280                                                                      |\n\nIf you need a more detailed set of devices, you can use the [`INITIAL_VIEWPORTS` export](#initial_viewports), which includes the following devices:\n\n| Key              | Description                                     | Dimensions<br />(<abbr title=\"width\">w</abbr>×<abbr title=\"height\">h</abbr>, px) |\n| -----------------| ----------------------------------------------- | -------------------------------------------------------------------------------- |\n| `iphone5`        | iPhone 5                                        | 320 × 568                                                                        |\n| `iphone6`        | iPhone 6                                        | 375 × 667                                                                        |\n| `iphone6p`       | iPhone 6 Plus                                   | 414 × 736                                                                        |\n| `iphone8p`       | iPhone 8 Plus                                   | 414 × 736                                                                        |\n| `iphonex`        | iPhone X                                        | 375 × 812                                                                        |\n| `iphonexr`       | iPhone XR                                       | 414 × 896                                                                        |\n| `iphonexsmax`    | iPhone XS Max                                   | 414 × 896                                                                        |\n| `iphonese2`      | iPhone SE (2nd generation)                      | 375 × 667                                                                        |\n| `iphone12mini`   | iPhone 12 mini                                  | 375 × 812                                                                        |\n| `iphone12`       | iPhone 12                                       | 390 × 844                                                                        |\n| `iphone12promax` | iPhone 12 Pro Max                               | 428 × 926                                                                        |\n| `iphoneSE3`      | iPhone SE 3rd generation                        | 375 × 667                                                                        |\n| `iphone13`       | iPhone 13                                       | 390 × 844                                                                        |\n| `iphone13pro`    | iPhone 13 Pro                                   | 390 × 844                                                                        |\n| `iphone13promax` | iPhone 13 Pro Max                               | 428 × 926                                                                        |\n| `iphone14`       | iPhone 14                                       | 390 × 844                                                                        |\n| `iphone14pro`    | iPhone 14 Pro                                   | 393 × 852                                                                        |\n| `iphone14promax` | iPhone 14 Pro Max                               | 430 × 932                                                                        |\n| `galaxys5`       | Galaxy S5                                       | 360 × 640                                                                        |\n| `galaxys9`       | Galaxy S9                                       | 360 × 740                                                                        |\n| `nexus5x`        | Nexus 5X                                        | 412 × 668                                                                        |\n| `nexus6p`        | Nexus 6P                                        | 412 × 732                                                                        |\n| `pixel`          | Pixel                                           | 540 × 960                                                                        |\n| `pixelxl`        | Pixel XL                                        | 720 × 1280                                                                       |\n| `ipad`           | iPad                                            | 768 × 1024                                                                       |\n| `ipad10p`        | iPad Pro 10.5-in                                | 834 × 1112                                                                       |\n| `ipad11p`        | iPad Pro 11-in                                  | 834 × 1194                                                                       |\n| `ipad12p`        | iPad Pro 12.9-in                                | 1024 × 1366                                                                      |\n\nTo use the detailed set of devices, you can adjust the `options` property in your configuration to include the `INITIAL_VIEWPORTS` export:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"addon-viewport-options-in-preview.md\" />\n\n{/* prettier-ignore-end */}\n\n### Add new devices\n\nIf the predefined viewports don't meet your needs, you can add new devices to the list of viewports. For example, let's add two Kindle devices to the default set of minimal viewports:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"addon-viewport-add-viewport-in-preview.md\" />\n\n{/* prettier-ignore-end */}\n\n### Configuring per component or story\n\nIn some cases, it's not practical for you to use a specific visual viewport on a global scale, and you need to adjust it to an individual story or set of stories for a component.\n\n[Parameters](../writing-stories/parameters.mdx) can be applied at the project, component, and story levels, which allows you to specify the configuration where needed. For example, you can set the available viewports for all of the stories for a component like so:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"addon-viewport-configuration-in-meta.md\" usesCsf3 />\n\n{/* prettier-ignore-end */}\n\n## Defining the viewport for a story\n\nThe Viewport module enables you to change the viewport applied to a story by selecting from the list of predefined viewports in the toolbar. If needed, you can set a story to default to a specific viewport by using the `globals` option:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"addon-viewport-define-globals.md\" usesCsf3 />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n\nWhen you specify a viewport for a story (or a component's stories) using `globals`, the viewport is applied and cannot be changed using the toolbar. This is useful to ensure a story is always rendered on a specific viewport.\n\n</Callout>\n\n## API\n\n### Keyboard shortcuts\n\nIf you need, you can edit these on the shortcuts page.\n\n* Next viewport: <kbd>alt</kbd> + <kbd>v</kbd>\n* Previous viewport: <kbd>alt</kbd> + <kbd>shift</kbd> + <kbd>v</kbd>\n* Reset viewport: <kbd>alt</kbd> + <kbd>control</kbd> + <kbd>v</kbd>\n\n### Globals\n\nThis module contributes the following globals to Storybook, under the `viewport` namespace:\n\n#### `value`\n\nType: `string`\n\nWhen set, the viewport is applied and cannot be changed using the toolbar. Must match the key of one of the [available viewports](#options).\n\n#### `isRotated`\n\nType: `boolean`\n\nWhen true, the viewport applied will be rotated 90°, e.g., from portrait to landscape orientation.\n\n### Parameters\n\nThis module contributes the following [parameters](../writing-stories/parameters.mdx) to Storybook, under the `viewport` namespace:\n\n#### `disable`\n\nType: `boolean`\n\nTurn off this module's behavior. This parameter is most useful to allow overriding at more specific levels. For example, if this parameter is set to `true` at the project level, it could be re-enabled by setting it to `false` at the meta (component) or story level.\n\n#### `options`\n\nType:\n\n```ts\n{\n  [key: string]: {\n    name: string;\n    styles: { height: string, width: string };\n    type: 'desktop' | 'mobile' | 'tablet' | 'other';\n  };\n}\n```\n\nSpecify the available viewports. See [usage example](#add-new-devices) above. The `width` and `height` values must include the unit, e.g. `'320px'`.\n\n\n### Exports\n\nThis module contributes the following exports to Storybook:\n\n```js\nimport { INITIAL_VIEWPORTS, MINIMAL_VIEWPORTS } from 'storybook/viewport';\n```\n\n#### `INITIAL_VIEWPORTS`\n\nType: `object`\n\nThe full set of initial viewports provided by the Viewport module [listed above](#use-a-detailed-set-of-devices).\n\n#### `MINIMAL_VIEWPORTS`\n\nType: `object`\n\nA minimal set of viewports provided by the Viewport module [listed above](#use-a-detailed-set-of-devices). These are used by default.\n\n"
  },
  {
    "path": "docs/faq.mdx",
    "content": "---\ntitle: 'Frequently Asked Questions'\nsidebar:\n  order: 15\n  title: FAQ\n---\n\nHere are some answers to frequently asked questions. If you have a question, you can ask it in our [GitHub discussions](https://github.com/storybookjs/storybook/discussions/new?category=help).\n\n## Error: No angular.json file found\n\nStorybook can be set up for both single-project and multi-project Angular workspaces. To set up Storybook for a project, run [the install command](./get-started/install) at the root of the workspace where the `angular.json` file is located. During initialization, the `.storybook` folder will be created and the `angular.json` file will be edited to add the Storybook configuration for the selected project. It's important to run the command at the root level to ensure that Storybook detects all projects correctly.\n\n## How can I opt-out of Angular Ivy?\n\nIn case you are having trouble with Angular Ivy you can deactivate it in your `main.js|ts`:\n\n<CodeSnippets path=\"angular-framework-options-enable-ivy-false.md\" />\n\n## How can I opt-out of Angular ngcc?\n\nIn case you postinstall ngcc, you can disable it:\n\n<CodeSnippets path=\"angular-framework-options-enable-ngcc-false.md\" />\n\nPlease report any issues related to Ivy in our [GitHub Issue Tracker](https://github.com/storybookjs/storybook/labels/app%3A%20angular) as the support for View Engine will be dropped in a future release of Angular.\n\n## How can I run coverage tests with Create React App and leave out stories?\n\nCreate React App does not allow providing options to Jest in your `package.json`, however you can run `jest` with commandline arguments:\n\n```sh\nnpm test -- --coverage --collectCoverageFrom='[\"src/**/*.{js,jsx}\",\"!src/**/stories/*\"]'\n```\n\n<Callout variant=\"info\" icon=\"💡\">\n\n  If you're using [`Yarn`](https://yarnpkg.com/) as a package manager, you'll need to adjust the command accordingly.\n\n</Callout>\n\n## How do I setup Storybook to share Webpack configuration with Next.js?\n\nStorybook's [Next.js framework](./get-started/frameworks/nextjs.mdx) will read from your `next.config.js` file by default. If your configuration file is named or located differently, you can specify the path in your Storybook main configuration file:\n\n<CodeSnippets path=\"nextjs-framework-options-next-config-path.md\" />\n\n## How do I fix module resolution in special environments?\n\nIn case you are using [Yarn Plug-n-Play](https://yarnpkg.com/features/pnp) or your project is set up within a mono repository environment, you might run into issues with module resolution similar to this when running Storybook:\n\n```shell\nWARN   Failed to load preset: \"@storybook/react-webpack5/preset\"\nRequired package: @storybook/react-webpack5 (via \"@storybook/react-webpack5/preset\")\n```\n\nTo fix this, you can wrap the package name inside your Storybook configuration file (i.e., `.storybook/main.js|ts`) as follows:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-pnpm-with-module-resolution.md\" />\n\n{/* prettier-ignore-end */}\n\n## Extensionless imports in Storybook main config\n\nWhen upgrading or running Storybook, you may see warnings about extensionless relative imports in `.storybook/main.<js|ts>` (for example: `import sharedMain from '../main'`). \nStorybook requires explicit extensions in config imports to avoid this deprecation warning.\n\nTo fix the issue, just make sure to include the extension of the file (TypeScript or Javascript) you're importing:\n\n```ts title=\".storybook/main.<js|ts>\"\n// Change from this 👇\nimport sharedMain from '../main';\n\n// To this 👇\nimport sharedMain from '../main.js'; // or .ts\n```\n\n### For TypeScript users (`.storybook/main.ts`)\nYou will also need to configure TypeScript so these imports type-check without emitting JavaScript:\n\n```json title=\".storybook/tsconfig.json\"\n{\n  \"extends\": \"<path-to-your-main-tsconfig>\",\n  \"compilerOptions\": {\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"noEmit\": true\n  }\n}\n```\n\n<Callout variant=\"info\">\n  It is advisable to add a `.storybook/tsconfig.json` file so that you apply changes only to Storybook config files, and not your entire project.\n</Callout>\n\n## How do I setup the new React Context Root API with Storybook?\n\nIf your installed React Version equals or is higher than 18.0.0, the new React Root API is automatically used and the newest React [concurrent features](https://reactjs.org/docs/concurrent-mode-intro.html) can be used.\n\nYou can opt-out from the new React Root API by setting the following property in your `.storybook/main.js|ts` file:\n\n<CodeSnippets path=\"react-framework-options-legacy-root-api.md\" />\n\n## Why is there no addons channel?\n\nA common error is that an addon tries to access the \"channel\", but the channel is not set. It can happen in a few different cases:\n\n1. You're trying to access addon channel (e.g., by calling `setOptions`) in a non-browser environment like Jest. You may need to add a channel mock:\n\n   ```js\n   import { addons, mockChannel } from 'storybook/preview-api';\n\n   addons.setChannel(mockChannel());\n   ```\n\n2. In React Native, it's a special case documented in [#1192](https://github.com/storybookjs/storybook/issues/1192)\n\n## Why aren't the addons working in a composed Storybook?\n\nComposition is a new feature that we released with version 6.0, and there are still some limitations to it.\n\nFor now, the addons you're using in a composed Storybook will not work.\n\nWe're working on overcoming this limitation, and soon you'll be able to use them as if you are working with a non-composed Storybook.\n\n## Can I have a Storybook with no local stories?\n\nStorybook does not work unless you have at least one local story (or docs page) defined in your project. In this context, local means a `.stories.*` or `.mdx` file that is referenced in your project's `.storybook/main.js` config.\n\nIf you're in a [Storybook composition](./sharing/storybook-composition.mdx) scenario, where you have multiple Storybooks, and want to have an extra Storybook with no stories of its own, that serves as a \"glue\" for all the other Storybooks in a project for demo/documentation purposes, you can do the following steps:\n\nIntroduce a single `.mdx` docs page (addon-docs required), that serves as an Introduction page, like so:\n\n```mdx title=\"Introduction.mdx\"\n# Welcome\n\nSome description here\n```\n\nAnd then refer to it in your Storybook config file:\n\n<CodeSnippets path=\"main-config-stories-only-mdx.md\" />\n\n## Which community addons are compatible with the latest version of Storybook?\n\nStarting with Storybook version 6.0, we've introduced some great features aimed at streamlining your development workflow.\n\nWith this, we would like to point out that if you plan on using addons created by our fantastic community, you need to consider that some of those addons might be working with an outdated version of Storybook.\n\nWe're actively working to provide a better way to address this situation, but in the meantime, we'd like to ask for a bit of caution on your end so that you don't run into unexpected problems. Let us know by leaving a comment in the following [GitHub issue](https://github.com/storybookjs/storybook/issues/26031) so that we can gather information and expand the current list of addons that need to be updated to work with the latest version of Storybook.\n\n## Is it possible to browse the documentation for past versions of Storybook?\n\nWith the release of version 6.0, we updated our documentation as well. That doesn't mean that the old documentation was removed. We kept it to help you with your Storybook migration process. Use the content from the table below in conjunction with our [migration guide](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md).\n\nWe're only covering versions 5.3 and 5.0 as they were important milestones for Storybook. If you want to go back in time a little more, you'll have to check the specific release in the monorepo.\n\n| Section          | Page                                            | Current Location                                                                                     | Version 5.3 location                                                                                                                                                                                                                                                 | Version 5.0 location                                                                                                                                     |\n| ---------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| N/A              | Why Storybook                                   | [See current documentation](./get-started/why-storybook.mdx)                                         | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n| Get started      | Install                                         | [See current documentation](./get-started/install.mdx)                                               | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides/quick-start-guide)                                                                                                                                     | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/guides/quick-start-guide)                         |\n|                  | What's a story                                  | [See current documentation](./get-started/whats-a-story.mdx)                                         | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides)                                                                                                                                    | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/guides)                        |\n|                  | Browse Stories                                  | [See current documentation](./get-started/browse-stories.mdx)                                        | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides)                                                                                                                                    | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/blob/release/5.0/docs/src/pages/guides)                        |\n|                  | Setup                                           | [See current documentation](./get-started/setup.mdx)                                                 | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides)                                                                                                                                    | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/guides)                        |\n| Write stories    | Introduction                                    | [See current documentation](./writing-stories/index.mdx)                                             | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories)                                                                                                                                       | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories)                           |\n|                  | Parameters                                      | [See current documentation](./writing-stories/parameters.mdx)                                        | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories/index.md#parameters)                                                                                                                   | Non existing feature or undocumented                                                                                                                     |\n|                  | Decorators                                      | [See current documentation](./writing-stories/decorators.mdx)                                        | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories/index.md#decorators)                                                                                                                   | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories/index.md#using-decorators) |\n|                  | Naming components and hierarchy                 | [See current documentation](./writing-stories/naming-components-and-hierarchy.mdx)                   | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories)                                                                                                                                       | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories)                           |\n|                  | Build pages and screens                         | [See current documentation](./writing-stories/build-pages-with-storybook.mdx)                        | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | Stories for multiple components                 | [See current documentation](./writing-stories/stories-for-multiple-components.mdx)                   | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n| Write docs       | Autodocs                                        | [See current documentation](./writing-docs/autodocs.mdx)                                             | See versioned addon documentation                                                                                                                                                                                                                                    | Non existing feature or undocumented                                                                                                                     |\n|                  | MDX                                             | [See current documentation](./writing-docs/mdx.mdx)                                                  | See versioned addon documentation                                                                                                                                                                                                                                    | Non existing feature or undocumented                                                                                                                     |\n|                  | Doc Blocks                                      | [See current documentation](./writing-docs/doc-blocks.mdx)                                           | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | Preview and build docs                          | [See current documentation](./writing-docs/build-documentation.mdx)                                  | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n| Testing          | Visual tests                                    | [See current documentation](./writing-tests/visual-testing.mdx)                                      | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/automated-visual-testing)                                                                                                                             | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/automated-visual-testing)                 |\n|                  | Accessibility tests                             | [See current documentation](./writing-tests/accessibility-testing.mdx)                               | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | Interaction tests                               | [See current documentation](./writing-tests/interaction-testing.mdx)                                 | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/interaction-testing)                                                                                                                                  | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/interaction-testing)                      |\n|                  | Snapshot tests                                  | [See current documentation](./writing-tests/snapshot-testing.mdx)                                    | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/structural-testing)                                                                                                                                   | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/structural-testing)                       |\n|                  | Import stories in tests/Unit tests              | [See current documentation](./writing-tests/integrations/stories-in-unit-tests.mdx)       | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/react-ui-testing)                                                                                                                                     | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/react-ui-testing)                         |\n|                  | Import stories in tests/End-to-end testing      | [See current documentation](./writing-tests/integrations/stories-in-end-to-end-tests.mdx) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/react-ui-testing)                                                                                                                                     | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/react-ui-testing)                         |\n| Sharing          | Publish Storybook                               | [See current documentation](./sharing/publish-storybook.mdx)                                         | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/exporting-storybook)                                                                                                                                   | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/exporting-storybook)                       |\n|                  | Embed                                           | [See current documentation](./sharing/embed.mdx)                                                     | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | Composition                                     | [See current documentation](./sharing/storybook-composition.mdx)                                     | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | Package Composition                             | [See current documentation](./sharing/package-composition.mdx)                                       | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n| Essentials       | Controls                                        | [See current documentation](./essentials/controls.mdx)                                               | Controls are specific to version 6.0 see [Knobs versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/knobs)                                                                                                                     | Controls are specific to version 6.0 see [Knobs versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/knobs)         |\n|                  | Actions                                         | [See current documentation](./essentials/actions.mdx)                                                | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/actions)                                                                                                                                                        | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/actions)                                            |\n|                  | Viewport                                        | [See current documentation](./essentials/viewport.mdx)                                               | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/viewport)                                                                                                                                                       | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/viewport)                                           |\n|                  | Backgrounds                                     | [See current documentation](./essentials/backgrounds.mdx)                                            | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/backgrounds)                                                                                                                                                    | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/backgrounds)                                        |\n|                  | Toolbars and globals                            | [See current documentation](./essentials/toolbars-and-globals.mdx)                                   | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/toolbar-guide)                                                                                                                                         | Non existing feature or undocumented                                                                                                                     |\n| Configure        | Overview                                        | [See current documentation](./configure/index.mdx)                                                   | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/overview)                                                                                                                                      | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories)                           |\n|                  | Integration/Frameworks                          | [See current documentation](./configure/integration/frameworks.mdx)                                  | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | Integration/Framework support for frameworks    | [See current documentation](./configure/integration/frameworks-feature-support.mdx)                  | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | Integration/Compilers                           | [See current documentation](./configure/integration/compilers.mdx)                                   | See versioned documentation [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/custom-babel-config)                                                                                                                      | See versioned documentation [here](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/custom-babel-config)          |\n|                  | Integration/Typescript                          | [See current documentation](./configure/integration/typescript.mdx)                                  | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/typescript-config)                                                                                                                             | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/typescript-config)                 |\n|                  | Integration/Styling and CSS                     | [See current documentation](./configure/styling-and-css.mdx)                                         | See versioned documentation                                                                                                                                                                                                                                          | See versioned documentation                                                                                                                              |\n|                  | Integration/Images and assets                   | [See current documentation](./configure/integration/images-and-assets.mdx)                           | See versioned documentation                                                                                                                                                                                                                                          | See versioned documentation                                                                                                                              |\n|                  | Story rendering                                 | [See current documentation](./configure/story-rendering.mdx)                                         | See versioned documentation [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/add-custom-head-tags) and [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/add-custom-body) | See versioned documentation [here](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/add-custom-head-tags)         |\n|                  | Story Layout                                    | [See current documentation](./configure/story-layout.mdx)                                            | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | User Interface/Features and behavior            | [See current documentation](./configure/user-interface/features-and-behavior.mdx)                    | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/options-parameter)                                                                                                                             | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/options-parameter)                 |\n|                  | User Interface/Theming                          | [See current documentation](./configure/user-interface/theming.mdx)                                  | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/theming)                                                                                                                                       | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/theming)                           |\n|                  | User Interface/Sidebar & URLS                   | [See current documentation](./configure/user-interface/sidebar-and-urls.mdx)                         | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/options-parameter)                                                                                                                             | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/options-parameter)                 |\n|                  | Environment variables                           | [See current documentation](./configure/environment-variables.mdx)                                   | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/env-vars)                                                                                                                                      | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/env-vars)                          |\n| Builders         | Introduction                                    | [See current documentation](./builders/index.mdx)                                                    | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | Vite                                            | [See current documentation](./builders/vite.mdx)                                                     | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | Webpack                                         | [See current documentation](./builders/webpack.mdx)                                                  | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/custom-webpack-config/index.md)                                                                                                               | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/custom-webpack-config/index.md)   |\n|                  | Builder API                                     | [See current documentation](./builders/builder-api.mdx)                                              | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n| Addons           | Introduction                                    | [See current documentation](./addons/index.mdx)                                                      | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons)                                                                                                                                        | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons)                            |\n|                  | Install addons                                  | [See current documentation](./addons/install-addons.mdx)                                             | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/using-addons/)                                                                                                                                         | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/using-addons/)                             |\n|                  | Writing Addons                                  | [See current documentation](./addons/writing-addons.mdx)                                             | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons)                                                                                                                                        | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons)                            |\n|                  | Writing Presets                                 | [See current documentation](./addons/writing-presets.mdx)                                            | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/presets/writing-presets)                                                                                                                                      | Non existing feature or undocumented                                                                                                                     |\n|                  | Addons Knowledge Base                           | [See current documentation](./addons/addon-knowledge-base.mdx)                                       | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons)                                                                                                                                        | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons)                            |\n|                  | Types of addons                                 | [See current documentation](./addons/addon-types.mdx)                                                | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | Addons API                                      | [See current documentation](./addons/addons-api.mdx)                                                 | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/api)                                                                                                                                                   | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/api)                                       |\n| API              | @storybook/addon-docs/blocks/ArgTypes           | [See current documentation](./api/doc-blocks/doc-block-argtypes.mdx)                                 | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | @storybook/addon-docs/blocks/Canvas             | [See current documentation](./api/doc-blocks/doc-block-canvas.mdx)                                   | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | @storybook/addon-docs/blocks/ColorPalette       | [See current documentation](./api/doc-blocks/doc-block-colorpalette.mdx)                             | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | @storybook/addon-docs/blocks/Controls           | [See current documentation](./api/doc-blocks/doc-block-controls.mdx)                                 | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | @storybook/addon-docs/blocks/Description        | [See current documentation](./api/doc-blocks/doc-block-description.mdx)                              | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | @storybook/addon-docs/blocks/IconGallery        | [See current documentation](./api/doc-blocks/doc-block-icongallery.mdx)                              | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | @storybook/addon-docs/blocks/Markdown           | [See current documentation](./api/doc-blocks/doc-block-markdown.mdx)                                 | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | @storybook/addon-docs/blocks/Meta               | [See current documentation](./api/doc-blocks/doc-block-meta.mdx)                                     | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | @storybook/addon-docs/blocks/Primary            | [See current documentation](./api/doc-blocks/doc-block-primary.mdx)                                  | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | @storybook/addon-docs/blocks/Source             | [See current documentation](./api/doc-blocks/doc-block-source.mdx)                                   | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | @storybook/addon-docs/blocks/Stories            | [See current documentation](./api/doc-blocks/doc-block-stories.mdx)                                  | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | @storybook/addon-docs/blocks/Story              | [See current documentation](./api/doc-blocks/doc-block-story.mdx)                                    | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | @storybook/addon-docs/blocks/Subtitle           | [See current documentation](./api/doc-blocks/doc-block-subtitle.mdx)                                 | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | @storybook/addon-docs/blocks/Title              | [See current documentation](./api/doc-blocks/doc-block-title.mdx)                                    | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | @storybook/addon-docs/blocks/Typeset            | [See current documentation](./api/doc-blocks/doc-block-typeset.mdx)                                  | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | @storybook/addon-docs/blocks/Unstyled           | [See current documentation](./api/doc-blocks/doc-block-unstyled.mdx)                                 | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | @storybook/addon-docs/blocks/useOf              | [See current documentation](./api/doc-blocks/doc-block-useof.mdx)                                    | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | Stories/Component Story Format (see note below) | [See current documentation](./api/csf/index.mdx)                                                           | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/formats/component-story-format)                                                                                                                               | Non existing feature or undocumented                                                                                                                     |\n|                  | ArgTypes                                        | [See current documentation](./api/arg-types.mdx)                                                     | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/Overview                | [See current documentation](./api/main-config/main-config.mdx)                                       | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/framework               | [See current documentation](./api/main-config/main-config-framework.mdx)                             | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/stories                 | [See current documentation](./api/main-config/main-config-stories.mdx)                               | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/addons                  | [See current documentation](./api/main-config/main-config-addons.mdx)                                | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/babel                   | [See current documentation](./api/main-config/main-config-babel.mdx)                                 | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/babelDefault            | [See current documentation](./api/main-config/main-config-babel-default.mdx)                         | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/build                   | [See current documentation](./api/main-config/main-config-build.mdx)                                 | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/core                    | [See current documentation](./api/main-config/main-config-core.mdx)                                  | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/docs                    | [See current documentation](./api/main-config/main-config-docs.mdx)                                  | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/env                     | [See current documentation](./api/main-config/main-config-env.mdx)                                   | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/features                | [See current documentation](./api/main-config/main-config-features.mdx)                              | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/indexers                | [See current documentation](./api/main-config/main-config-indexers.mdx)                              | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/logLevel                | [See current documentation](./api/main-config/main-config-log-level.mdx)                             | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/managerHead             | [See current documentation](./api/main-config/main-config-manager-head.mdx)                          | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/previewAnnotations      | [See current documentation](./api/main-config/main-config-preview-annotations.mdx)                   | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/previewBody             | [See current documentation](./api/main-config/main-config-preview-body.mdx)                          | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/previewHead             | [See current documentation](./api/main-config/main-config-preview-head.mdx)                          | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/refs                    | [See current documentation](./api/main-config/main-config-refs.mdx)                                  | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/staticDirs              | [See current documentation](./api/main-config/main-config-static-dirs.mdx)                           | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/swc                     | [See current documentation](./api/main-config/main-config-swc.mdx)                                   | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/typescript              | [See current documentation](./api/main-config/main-config-typescript.mdx)                            | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/viteFinal               | [See current documentation](./api/main-config/main-config-vite-final.mdx)                            | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | `main.js` configuration/webpackFinal            | [See current documentation](./api/main-config/main-config-webpack-final.mdx)                         | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | Frameworks                                      | [See current documentation](./api/new-frameworks.mdx)                                                | Non existing feature or undocumented                                                                                                                                                                                                                                 | Non existing feature or undocumented                                                                                                                     |\n|                  | CLI options                                     | [See current documentation](./api/cli-options.mdx)                                                   | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/cli-options)                                                                                                                                   | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/cli-options)                       |\n\n<Callout variant=\"info\">\n  If you have stories written with the older `storiesOf` format, it was removed in Storybook 8.0 and is no longer maintained. We recommend that you migrate your stories to CSF. See the [migration guide](./releases/migration-guide.mdx#major-breaking-changes) for more information. However, if you need, you can still access the old `storiesOf` [documentation](https://github.com/storybookjs/storybook/blob/release/5.3/docs/src/pages/formats/storiesof-api/index.md) for reference.\n</Callout>\n\n## What icons are available for my toolbar or my addon?\n\nWith the [`@storybook/icons`](https://www.npmjs.com/package/@storybook/icons) package, you get a set of icons that you can use to customize your UI. Go through the [documentation](https://main--64b56e737c0aeefed9d5e675.chromatic.com/?path=/docs/introduction--docs) to see how the icons look and use it as a reference when writing your addon or defining your Storybook global types.\n\n## I see a \"No Preview\" error with a Storybook production build\n\nIf you're using the `serve` package to verify your production build of Storybook, you'll get that error. It relates to how `serve` handles rewrites. For instance, `/iframe.html` is rewritten into `/iframe`, and you'll get that error.\n\nWe recommend that you use [http-server](https://www.npmjs.com/package/http-server) instead and use the following command to preview Storybook:\n\n```shell\nnpx http-server storybook-static\n```\n\n<Callout variant=\"info\">\n  Suppose you don't want to run the command above frequently. Add `http-server` as a development dependency and create a new script to preview your production build of Storybook.\n</Callout>\n\n## Can I use Storybook with Vue 2?\n\nVue 2 entered [End of Life](https://v2.vuejs.org/lts/) (EOL) on December 31, 2023, and is no longer supported by the Vue team. As a result, we've stopped supporting Vue 2 in Storybook 8 and above and will not be releasing any new versions that support it. We recommend upgrading your project to Vue 3, which Storybook fully supports. If that's not an option, you can still use Storybook with Vue 2 by installing the latest version of Storybook 7 with the following command:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-init-v7.md\" />\n\n{/* prettier-ignore-end */}\n\n## Why aren't my code blocks highlighted with Storybook MDX?\n\nOut of the box, Storybook provides syntax highlighting for a set of languages (e.g., Javascript, Markdown, CSS, HTML, Typescript, GraphQL) you can use with your code blocks. Currently, there's a known limitation when you try to register a custom language to get syntax highlighting. We're working on a fix for this and will update this section once it's available.\n\n## Why aren't my MDX styles working in Storybook?\n\nWriting documentation with MDX can be troublesome, especially regarding how your code is formatted when using line breaks with code blocks. For example, this will break:\n\n{/* prettier-ignore-start */}\n\n```mdx title=\"Example.mdx\"\n<style>{`\n  .class1 {\n    ...\n  }\n\n  .class2 {\n    ...\n  }\n`}</style>\n```\n\n{/* prettier-ignore-end */}\n\nBut this will work:\n\n{/* prettier-ignore-start */}\n\n```mdx title=\"Example.mdx\"\n<style>\n  {`\n    .class1 {\n      ...\n    }\n\n    .class2 {\n      ...\n    }\n  `}\n</style>\n```\n\n{/* prettier-ignore-end */}\n\nSee the following [issue](https://github.com/mdx-js/mdx/issues/1945) for more information.\n\n## Why are my mocked GraphQL queries failing with Storybook's MSW addon?\n\nIf you're working with Vue 3, you'll need to install [`@vue/apollo-composable`](https://www.npmjs.com/package/@vue/apollo-composable).\n\nWith Svelte, you'll need to install [`@rollup/plugin-replace`](https://www.npmjs.com/package/@rollup/plugin-replace) and update your `rollup.config` file to the following:\n\n```js title=\"rollup.config.js\"\n// Boilerplate imports\n\nimport replace from '@rollup/plugin-replace';\nconst production = !process.env.ROLLUP_WATCH;\n\n// Remainder rollup.config implementation\n\nexport default {\n  input: 'src/main.js',\n  output: {\n    sourcemap: true,\n    format: 'iife',\n    name: 'app',\n    file: 'public/build/bundle.js',\n  },\n  plugins: [\n    // Other plugins\n\n    // Configures the replace plugin to allow GraphQL Queries to work properly\n    replace({\n      'process.env.NODE_ENV': JSON.stringify('development'),\n    }),\n  ]\n};\n```\n\nWith Angular, the most common issue is the placement of the `mockServiceWorker.js` file. Use this [example](https://github.com/mswjs/examples/tree/main/examples/with-angular) as a point of reference.\n\n## Can I use other GraphQL providers with Storybook's MSW addon?\n\nYes, check the [addon's examples](https://github.com/mswjs/msw-storybook-addon/tree/main/packages/docs/src/demos) to learn how to integrate different providers.\n\n## Can I mock GraphQL mutations with Storybook's MSW addon?\n\nNo, currently, the MSW addon only has support for GraphQL queries. If you're interested in including this feature, open an issue in the [MSW addon repository](https://github.com/mswjs/msw-storybook-addon) and follow up with the maintainer.\n\n## Why are my stories not showing up correctly when using certain characters?\n\nStorybook allows you to use most characters while naming your stories. Still, specific characters (e.g., `#`) can lead to issues when Storybook generates the internal identifier for the story, leading to collisions and incorrectly outputting the correct story. We recommend using such characters sparsely.\n\n## Why is Storybook's source loader returning undefined with curried functions?\n\nThis is a known issue with Storybook. If you're interested in getting it fixed, open an issue with a [working reproduction](./contribute/how-to-reproduce.mdx) so that it can be triaged and fixed in future releases.\n\n## Why isn't Storybook's test runner working?\n\nThere's an issue with Storybook's test runner and the latest version of Jest (i.e., version 28), which prevents it from running effectively. As a workaround, you can downgrade Jest to the previous stable version (i.e., version 27), and you'll be able to run it. See the following [issue](https://github.com/storybookjs/test-runner/issues/99) for more information.\n\n## How does Storybook handle environment variables?\n\nStorybook has built-in support for [environment variables](./configure/environment-variables.mdx). By default, environment variables are only available in Node.js code and are not available in the browser as some variables should be kept secret (e.g., API keys) and **not** exposed to anyone visiting the published Storybook.\n\nTo expose a variable, you must preface its name with `STORYBOOK_`. So `STORYBOOK_API_URL` will be available in browser code but `API_KEY` will not. Additionally you can also customize which variables are exposed by setting the [`env`](./configure/environment-variables.mdx#using-storybook-configuration) field in the `.storybook/main.js` file.\n\nVariables are set when JavaScript is compiled so when the development server is started or you build your Storybook. Environment variable files should not be committed to Git as they often contain secrets which are not safe to add to Git. Instead, add `.env.*` to your `.gitignore` file and set up the environment variables manually on your hosting provider (e.g., [GitHub](https://docs.github.com/en/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository)).\n"
  },
  {
    "path": "docs/frameworks.js",
    "content": "module.exports = {\n  coreFrameworks: ['react', 'vue', 'angular', 'web-components'],\n  communityFrameworks: ['ember', 'html', 'svelte', 'preact', 'qwik', 'solid'],\n  featureGroups: [\n    {\n      name: 'Essentials',\n      features: [\n        {\n          name: 'Actions',\n          unsupported: [],\n          path: 'essentials/actions',\n        },\n        {\n          name: 'Backgrounds',\n          unsupported: [],\n          path: 'essentials/backgrounds',\n        },\n        {\n          name: 'Docs',\n          unsupported: [],\n          path: 'writing-docs',\n        },\n        {\n          name: 'Viewport',\n          unsupported: [],\n          path: 'essentials/viewport',\n        },\n        {\n          name: 'Controls',\n          supported: ['react', 'vue', 'angular', 'web-components', 'ember'],\n          path: 'essentials/controls',\n        },\n        {\n          name: 'Measure',\n          unsupported: [],\n          path: 'essentials/measure-and-outline#measure-addon',\n        },\n        {\n          name: 'Outline',\n          unsupported: [],\n          path: 'essentials/measure-and-outline#outline-addon',\n        },\n      ],\n    },\n    {\n      name: 'Addons',\n      features: [\n        {\n          name: 'a11y',\n          unsupported: [],\n        },\n        {\n          name: 'interactions',\n          supported: [\n            'react',\n            'vue',\n            'angular',\n            'web-components',\n            'nextjs',\n            'html',\n            'svelte',\n            'preact',\n          ],\n          unsupported: ['ember', 'qwik'],\n        },\n        {\n          name: 'test-runner',\n          supported: [\n            'react',\n            'vue',\n            'angular',\n            'web-components',\n            'nextjs',\n            'html',\n            'svelte',\n            'preact',\n          ],\n          unsupported: ['ember'],\n          path: 'writing-tests/integrations/test-runner',\n        },\n        {\n          name: 'test coverage',\n          supported: [\n            'react',\n            'vue',\n            'angular',\n            'web-components',\n            'nextjs',\n            'html',\n            'svelte',\n            'preact',\n          ],\n          unsupported: ['ember'],\n          path: 'writing-tests/test-coverage',\n        },\n        {\n          name: 'cssresources',\n          unsupported: [],\n        },\n        {\n          name: 'design-assets',\n          unsupported: [],\n        },\n        {\n          name: 'events',\n          unsupported: ['svelte'],\n        },\n        {\n          name: 'google-analytics',\n          unsupported: [],\n        },\n        {\n          name: 'graphql',\n          supported: ['react', 'angular'],\n        },\n        {\n          name: 'jest',\n          unsupported: [],\n        },\n        {\n          name: 'knobs',\n          unsupported: [],\n        },\n        {\n          name: 'links',\n          unsupported: [],\n        },\n        {\n          name: 'queryparams',\n          unsupported: [],\n        },\n        {\n          name: 'storysource',\n          unsupported: [],\n        },\n      ],\n    },\n    {\n      name: 'Docs',\n      features: [\n        {\n          name: 'CSF Stories',\n          unsupported: [],\n          path: 'api/csf',\n        },\n        {\n          name: 'Autodocs',\n          supported: [\n            'react',\n            'vue',\n            'angular',\n            'web-components',\n            'nextjs',\n            'html',\n            'svelte',\n            'preact',\n          ],\n        },\n        {\n          name: 'Doc Blocks - ArgTypes',\n          unsupported: [],\n          path: 'api/doc-blocks/doc-block-argtypes',\n        },\n        {\n          name: 'Doc Blocks - Canvas',\n          unsupported: [],\n          path: 'api/doc-blocks/doc-block-canvas',\n        },\n        {\n          name: 'Doc Blocks - ColorPalette',\n          unsupported: [],\n          path: 'api/doc-blocks/doc-block-colorpalette',\n        },\n        {\n          name: 'Doc Blocks - Controls',\n          unsupported: [],\n          path: 'api/doc-blocks/doc-block-controls',\n        },\n        {\n          name: 'Doc Blocks - Description',\n          unsupported: [],\n          path: 'api/doc-blocks/doc-block-description',\n        },\n        {\n          name: 'Doc Blocks - IconGallery',\n          unsupported: [],\n          path: 'api/doc-blocks/doc-block-icongallery',\n        },\n        {\n          name: 'Doc Blocks - Markdown',\n          unsupported: [''],\n          path: 'api/doc-blocks/doc-block-markdown',\n        },\n        {\n          name: 'Doc Blocks - Meta',\n\n          unsupported: [''],\n          path: 'api/doc-blocks/doc-block-meta',\n        },\n        {\n          name: 'Doc Blocks - Primary',\n\n          unsupported: [''],\n          path: 'api/doc-blocks/doc-block-primary',\n        },\n        {\n          name: 'Doc Blocks - Source',\n          unsupported: [],\n          path: 'api/doc-blocks/doc-block-source',\n        },\n        {\n          name: 'Doc Blocks - Story',\n          unsupported: [],\n          path: 'api/doc-blocks/doc-block-story',\n        },\n        {\n          name: 'Doc Blocks - Stories',\n          unsupported: [],\n          path: 'api/doc-blocks/doc-block-stories',\n        },\n        {\n          name: 'Doc Blocks - Subtitle',\n          unsupported: [],\n          path: 'api/doc-blocks/doc-block-subtitle',\n        },\n        {\n          name: 'Doc Blocks - Title',\n          unsupported: [],\n          path: 'api/doc-blocks/doc-block-title',\n        },\n        {\n          name: 'Doc Blocks - Typeset',\n          unsupported: [],\n          path: 'api/doc-blocks/doc-block-typeset',\n        },\n        {\n          name: 'Doc Blocks - Unstyled',\n          unsupported: [],\n          path: 'api/doc-blocks/doc-block-unstyled',\n        },\n        {\n          name: 'Doc Blocks - UseOf',\n          unsupported: [],\n          path: 'api/doc-blocks/doc-block-useof',\n        },\n        {\n          name: 'storiesOf stories',\n          unsupported: [\n            'react',\n            'vue',\n            'angular',\n            'svelte',\n            'web-components',\n            'nextjs',\n            'html',\n            'ember',\n            'html',\n            'svelte',\n            'preact',\n            'qwik',\n          ],\n          repoPath: 'lib/core/preview-api/storiesOf.md',\n        },\n        {\n          name: 'Inline stories',\n          supported: ['react', 'vue', 'web-components', 'html', 'svelte', 'angular'],\n        },\n      ],\n    },\n  ],\n};\n"
  },
  {
    "path": "docs/get-started/browse-stories.mdx",
    "content": "---\ntitle: Browse Stories\nhideRendererSelector: true\nsidebar:\n  order: 5\n  title: Browse stories\n---\n\nLast chapter, we learned that stories correspond with discrete component states. This chapter demonstrates how to use Storybook as a workshop for building components.\n\n## Sidebar and Preview\n\nA `*.stories.js|ts|svelte` file defines all the stories for a component. Each story has a corresponding sidebar item. When you click on a story, it renders in an isolated preview iframe.\n\n<Video src=\"../_assets/get-started/example-browse-all-stories-optimized.mp4\" />\n\nThe sidebar contains three areas: sidebar search, story explorer, and [testing widget](../writing-tests/index.mdx). Try the sidebar search to find a story by name. Navigate between stories by clicking on them in the explorer. Run component tests for all stories using the widget at the bottom of the sidebar.\n\nOr use keyboard shortcuts. Click on the Storybook menu to see a list of available shortcuts.\n\n![Storybook keyboard shortcuts examples](../_assets/get-started/storybook-keyboard-shortcuts.png)\n\n<Callout variant=\"info\" icon=\"♿\">\n  Storybook supports fast keyboard navigation between landmark regions. Press <kbd>F6</kbd> and <kbd>Shift+F6</kbd> to navigate between the sidebar, toolbar, preview, and addons panel.\n</Callout>\n\n## Toolbar\n\nStorybook ships with time-saving tools built-in. The toolbar contains tools that allow you to adjust how the story renders in the Canvas:\n\n* 🔍 Zooming visually scales the component so you can check the details.\n* 🖼 Background changes the rendered background behind your component so you can verify how your component renders in different visual contexts.\n* 📐 Grid renders your component on top of a grid layout so you can verify if your component is aligned correctly.\n* 📏 Measure toggles a measurement overlay to help you inspect the dimensions of components.\n* 🎚️ Outline displays the component's bounding box so you can verify if your component is positioned correctly.\n* 📱 Viewport renders the component in a variety of dimensions and orientations. It’s ideal for checking the responsiveness of components.\n\n<Video src=\"../_assets/get-started/toolbar-walkthrough-optimized.mp4\" />\n\nThe [“Docs”](../writing-docs/index.mdx) page displays auto-generated documentation for components (inferred from the source code). Usage documentation is helpful when sharing reusable components with your team, for example, in an application.\n\n![Storybook keyboard shortcuts examples](../_assets/get-started/mdx-example.png)\n\nThe toolbar is customizable. You can use [globals](../essentials/toolbars-and-globals.mdx) to quickly toggle themes and languages. Or install Storybook toolbar [addons](../configure/user-interface/storybook-addons.mdx) from the community to enable advanced workflows.\n\n## Addons\n\nAddons are plugins that extend Storybook's core functionality. You can find them in the addons panel, a reserved place in the Storybook UI below the Canvas. Each tab shows the generated metadata, logs, or static analysis for the selected story by the addon.\n\n![Storybook addon examples](../_assets/get-started/addons.png)\n\n* **Controls** allows you to interact with a component’s args (inputs) dynamically. Experiment with alternate configurations of the component to discover edge cases.\n* **Actions** help you verify interactions produce the correct outputs via callbacks. For instance, if you view the “Logged In” story of the `Header` component, we can verify that clicking the “Log out” button triggers the `onLogout` callback, which would be provided by the component that made use of the Header.\n* **Interactions** provides a helpful user interface for debugging [interaction tests](../writing-tests/interaction-testing.mdx) with the `play` function.\n* **Accessibility** helps you identify [accessibility violations](../writing-tests/accessibility-testing.mdx) in your components.\n* **Visual Tests** lets you pinpoint UI bugs in your local development environment by providing instant feedback directly in Storybook.\n\n<Video src=\"../_assets/get-started/addons-walkthrough-optimized.mp4\" />\n\nStorybook is extensible. Our rich ecosystem of addons helps you test, document, and optimize your stories. You can also create an addon to satisfy your workflow requirements. Read more in the [addons section](../addons/index.mdx).\n\nIn the next chapter, we'll get your components rendering in Storybook so you can use it to supercharge component development.\n\n## Use stories to build UIs\n\nWhen building apps, one of the biggest challenges is to figure out if a piece of UI already exists in your codebase and how to use it for the new feature you're building.\n\nStorybook catalogues all your components and their use cases. Therefore, you can quickly browse it to find what you're looking for.\n\nHere's what the workflow looks like:\n\n* 🗃 Use the sidebar to find a suitable component\n* 👀 Review its stories to pick a variant that suits your needs\n* 📝 Copy/paste the story definition into your app code and wire it up to data\n\nYou can access the story definition from the stories file or make it available in your published Storybook using the [Docs addon](../api/doc-blocks/doc-block-source.mdx).\n\n![Docblock source](../_assets/get-started/docblock-source.png)\n"
  },
  {
    "path": "docs/get-started/conclusion.mdx",
    "content": "---\ntitle: Conclusion\nhideRendererSelector: true\nsidebar:\n  order: 7\n  title: Conclusion\n---\n\nCongratulations! You learned the basics. Storybook is the most popular tool for UI component development and documentation. You’ll be able to transfer these skills to thousands of companies that use Storybook to build UIs including GitHub, Airbnb, and Stripe.\n\nIf you’d like to learn workflows for building app UIs with Storybook, check out our in-depth guides over at the [tutorials](https://storybook.js.org/tutorials/) page. Continue reading for detailed information on how to use Storybook APIs.\n\n* [How to write stories](../writing-stories/index.mdx)\n* [How to document components and design systems](../writing-docs/index.mdx)\n* [View example Storybooks from leading companies](https://storybook.js.org/showcase)\n"
  },
  {
    "path": "docs/get-started/frameworks/angular.mdx",
    "content": "---\ntitle: Storybook for Angular\nhideRendererSelector: true\nsidebar:\n  order: 1\n  title: Angular\n---\n\nStorybook for Angular is a [framework](../../contribute/framework.mdx) that makes it easy to develop and test UI components in isolation for [Angular](https://angular.io/) applications. It uses Angular builders and integrates with [Compodoc](https://compodoc.app/) to provide automatic documentation generation.\n\n## Install\n\nTo install Storybook in an existing Angular project, run this command in your project's root directory:\n\n<CodeSnippets path=\"create-command.md\" variant=\"new-users\" copyEvent=\"CreateCommandCopy\" />\n\nYou can then get started [writing stories](../whats-a-story.mdx), [running tests](../../writing-tests/index.mdx) and [documenting your components](../../writing-docs/index.mdx). For more control over the installation process, refer to the [installation guide](../install.mdx).\n\n### Requirements\n\n<GetStartedVersions versions={[{\n  name: 'Angular',\n  range: '≥ 18.0 < 22.0',\n  icon: '/images/logos/renderers/logo-angular.svg'\n}, {\n  name: 'Webpack',\n  range: '5',\n  icon: '/images/logos/builders/webpack.svg'\n}]} />\n\n## Run Storybook\n\nTo run Storybook for a particular project, run the following:\n\n```sh\nng run <your-project>:storybook\n```\n\nTo build Storybook, run:\n\n```sh\nng run <your-project>:build-storybook\n```\n\nYou will find the output in the configured `outputDir` (default is `dist/storybook/<your-project>`).\n\n## Configure\n\nTo make the most out of Storybook in your Angular project, you can set up Compodoc integration and Storybook [decorators](../../writing-stories/decorators.mdx) based on your project needs.\n\n### Compodoc\n\nYou can include JSDoc comments above components, directives, and other parts of your Angular code to include documentation for those elements. Compodoc uses these comments to [generate documentation](../../writing-docs/autodocs.mdx) for your application. In Storybook, it is useful to add explanatory comments above `@Inputs` and `@Outputs`, since these are the main elements that Storybook displays in its user interface. The `@Inputs` and `@Outputs` are elements you can interact with in Storybook, such as [controls](../../essentials/controls.mdx).\n\n#### Automatic setup\n\nWhen installing Storybook via `npx storybook@latest init`, you can set up Compodoc automatically.\n\n#### Manual setup\n\nIf you have already installed Storybook, you can set up Compodoc manually.\n\nInstall the following dependencies:\n\n```sh\nnpm install --save-dev @compodoc/compodoc\n```\n\nAdd the following option to your Storybook Builder:\n\n```jsonc title=\"angular.json\"\n{\n  \"projects\": {\n    \"your-project\": {\n      \"architect\": {\n        \"storybook\": {\n          \"builder\": \"@storybook/angular:start-storybook\",\n          \"options\": {\n            // 👇 Add these\n            \"compodoc\": true,\n            \"compodocArgs\": [\n              \"-e\",\n              \"json\",\n              \"-d\",\n              // Where to store the generated documentation. It's usually the root of your Angular project. It's not necessarily the root of your Angular Workspace!\n              \".\"\n            ],\n          }\n        },\n        \"build-storybook\": {\n          \"builder\": \"@storybook/angular:build-storybook\",\n          \"options\": {\n            // 👇 Add these\n            \"compodoc\": true,\n            \"compodocArgs\": [\n              \"-e\",\n              \"json\",\n              \"-d\",\n              \".\"\n            ],\n          }\n        }\n      }\n    }\n  }\n}\n```\n\nGo to your `.storybook/preview.ts` and add the following:\n\n<CodeSnippets path=\"angular-add-compodoc.md\" />\n\n### Application-wide providers\n\nIf your component relies on application-wide providers, like the ones defined by [`BrowserAnimationsModule`](https://angular.dev/api/platform-browser/animations/BrowserAnimationsModule) or any other modules that use the forRoot pattern to provide a [`ModuleWithProviders`](https://angular.dev/api/core/ModuleWithProviders), you can apply the `applicationConfig` [decorator](../../writing-stories/decorators.mdx) to all stories for that component. This will provide them with the [bootstrapApplication function](https://angular.dev/api/platform-browser/bootstrapApplication), used to bootstrap the component in Storybook.\n\n<CodeSnippets path=\"angular-application-providers-in-meta-and-story.md\" />\n\n### Angular dependencies\n\nIf your component has dependencies on other Angular directives and modules, these can be supplied using the `moduleMetadata` [decorator](../../writing-stories/decorators.mdx) either for all stories of a component or for individual stories.\n\n```ts title=\"YourComponent.stories.ts\"\nimport { Meta, moduleMetadata, StoryObj } from '@storybook/angular';\n\nimport { YourComponent } from './your.component';\n\nconst meta: Meta<YourComponent> = {\n  component: YourComponent,\n  decorators: [\n    // Apply metadata to all stories\n    moduleMetadata({\n      // import necessary ngModules or standalone components\n      imports: [...],\n      // declare components that are used in the template\n      declarations: [...],\n      // List of providers that should be available to the root component and all its children.\n      providers: [...],\n    }),\n  ],\n};\nexport default meta;\ntype Story = StoryObj<YourComponent>;\n\nexport const Base: Story = {};\n\nexport const WithCustomProvider: Story = {\n  decorators: [\n    // Apply metadata to a specific story\n    moduleMetadata({\n      imports: [...],\n      declarations: [...],\n      providers: [...],\n    }),\n  ],\n};\n```\n\n## FAQ\n\n### How do I manually install the Angular framework?\n\nThe easiest way to install the Angular framework is to run the upgrade command, but you can also set it up manually. First, install the framework:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"angular-install.md\" />\n\n{/* prettier-ignore-end */}\n\nThen, update your `.storybook/main.js|ts` to change the framework property:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"angular-add-framework.md\" />\n\n{/* prettier-ignore-end */}\n\nFinally, update your `angular.json` to include the Storybook builder:\n\n```jsonc title=\"angular.json\"\n{\n  \"projects\": {\n    \"your-project\": {\n      \"architect\": {\n        \"storybook\": {\n          \"builder\": \"@storybook/angular:start-storybook\",\n          \"options\": {\n            // The path to the storybook config directory\n            \"configDir\": \".storybook\",\n            // The build target of your project\n            \"browserTarget\": \"your-project:build\",\n            // The port you want to start Storybook on\n            \"port\": 6006\n            // More options available, documented here:\n            // https://github.com/storybookjs/storybook/tree/next/code/frameworks/angular/src/builders/start-storybook/schema.json\n          }\n        },\n        \"build-storybook\": {\n          \"builder\": \"@storybook/angular:build-storybook\",\n          \"options\": {\n            \"configDir\": \".storybook\",\n            \"browserTarget\": \"your-project:build\",\n            \"outputDir\": \"dist/storybook/your-project\"\n            // More options available, documented here:\n            // https://github.com/storybookjs/storybook/tree/next/code/frameworks/angular/src/builders/build-storybook/schema.json\n          }\n        }\n      }\n    }\n  }\n}\n```\n\n### How do I migrate to an Angular Storybook builder?\n\nThe Storybook [Angular builder](https://angular.io/guide/glossary#builder) is a way to run Storybook in an Angular workspace. It is a drop-in replacement for running `storybook dev` and `storybook build` directly.\n\nYou can run `npx storybook@latest automigrate` to let Storybook detect and automatically fix your configuration. Otherwise, you can follow the next steps to adjust your configuration manually.\n\n#### With a single project in your Angular workspace\n\nGo to your `angular.json` and add `storybook` and `build-storybook` entries in your project's `architect` section, as shown [above](#manual-setup).\n\nThen, adjust your `package.json` script section, to replace the existing Storybook scripts with the Angular CLI commands:\n\n```diff title=\"package.json\"\n{\n  \"scripts\": {\n-    \"storybook\": \"start-storybook -p 6006\", // or `storybook dev -p 6006`\n-    \"build-storybook\": \"build-storybook\" // or `storybook build`\n+    \"storybook\": \"ng run <project-name:storybook\",\n+    \"storybook\": \"ng run <project-name:storybook\",\n  }\n}\n```\n\nNote that `compodoc` is now built into `@storybook/angular`; you don't have to call it explicitly. If you were running `compodoc` in your `package.json` scripts, you can remove the related script:\n\n```diff title=\"package.json\"\n{\n  \"scripts\": {\n-    \"docs:json\": \"compodoc -p tsconfig.json -e json -d ./documentation\",\n-    \"storybook\": \"npm run docs:json && start-storybook -p 6006\",\n-    \"build-storybook\": \"npm run docs:json && build-storybook\"\n+    \"storybook\": \"ng run <project-name:storybook\",\n+    \"storybook\": \"ng run <project-name:storybook\",\n  }\n}\n```\n\n\n#### With multiple projects in your Angular workspace\n\nIn case you have multiple projects, you will have to adjust your `angular.json` and `package.json` as described above for each project you want to use Storybook with. Please note that each project should have a dedicated `.storybook` folder placed at the project's root directory.\n\nYou can run `npx storybook@latest init` sequentially for each project to set up Storybook for each of them to automatically create the `.storybook` folder and create the necessary configuration in your `angular.json`.\n\nYou can then combine multiple Storybooks with [Storybook composition](../../sharing/storybook-composition.mdx).\n\n### How do I configure Angular's builder for Storybook?\n\nThese are common options you may need for the Angular builder:\n\n| Configuration element        | Description                                                                                                                                                                                     |\n| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `\"browserTarget\"`            | Build target to be served using the following format. <br /> `\"example-project:builder:config\"`                                                                                                 |\n| `\"debugWebpack\"`             | Debug the Webpack configuration <br /> `\"debugWebpack\": true`                                                                                                                                   |\n| `\"tsConfig\"`                 | Location of the TypeScript configuration file relative to the current workspace. <br /> `\"tsConfig\": \"./tsconfig.json\"`.                                                                        |\n| `\"preserveSymlinks\"`         | Do not use the real path when resolving modules. If true, symlinks are resolved to their real path; otherwise, they are resolved to their symlinked path. <br /> `\"preserveSymlinks\": true`     |\n| `\"port\"`                     | Port used by Storybook. <br /> `\"port\": 6006`                                                                                                                                                   |\n| `\"host\"`                     | Set up a custom host for Storybook. <br /> `\"host\": \"http://my-custom-host\"`                                                                                                                    |\n| `\"configDir\"`                | Storybook configuration directory location. <br /> `\"configDir\": \".storybook\"`                                                                                                                  |\n| `\"https\"`                    | Starts Storybook with HTTPS enabled. <br /> `\"https\": true` <br /> Requires custom certificate information.                                                                                     |\n| `\"sslCa\"`                    | Provides an SSL certificate authority. <br /> `\"sslCa\": \"your-custom-certificate-authority\"` <br /> Optional usage with `\"https\"`                                                               |\n| `\"sslCert\"`                  | Provides an SSL certificate. <br /> `\"sslCert\": \"your-custom-certificate\"` <br /> Required for `https`                                                                                          |\n| `\"sslKey\"`                   | Provides an SSL key to serve Storybook. <br /> `\"sslKey\": \"your-ssl-key\"`                                                                                                                       |\n| `\"smokeTest\"`                | Exit Storybook after successful start. <br /> `\"smokeTest\": true`                                                                                                                               |\n| `\"ci\"`                       | Starts Storybook in CI mode (skips interactive prompts and will not open browser window). <br /> `\"ci\": true`                                                                                   |\n| `\"open\"`                     | Whether to open Storybook automatically in the browser. <br /> `\"open\": true`                                                                                                                   |\n| `\"quiet\"`                    | Filters Storybook verbose build output. <br /> `\"quiet\": true`                                                                                                                                  |\n| `\"enableProdMode\"`           | Disable Angular's development mode, which turns off assertions and other checks within the framework. <br /> `\"enableProdMode\": true`                                                           |\n| `\"docs\"`                     | Starts Storybook in [documentation mode](../../writing-docs/build-documentation.mdx#preview-storybooks-documentation). <br /> `\"docs\": true`                                                    |\n| `\"compodoc\"`                 | Execute compodoc before. <br /> `\"compodoc\": true`                                                                                                                                              |\n| `\"compodocArgs\"`             | Compodoc [options](https://compodoc.app/guides/options.html). Options `-p` with tsconfig path and `-d` with workspace root is always given. <br /> `\"compodocArgs\": [\"-e\", \"json\"]`             |\n| `\"styles\"`                   | Provide the location of the [application's styles](../../configure/styling-and-css.mdx#global-styles) to be used with Storybook. <br /> `\"styles\": [\"src/styles.css\", \"src/styles.scss\"]`       |\n| `\"stylePreprocessorOptions\"` | Provides further customization for style preprocessors resolved to the workspace root. <br /> `\"stylePreprocessorOptions\": { \"includePaths\": [\"src/styles\"] }`                                  |\n| `\"assets\"`                   | List of static application assets. <br /> `\"assets\": [\"src/assets\"]`                                                                                                                            |\n| `\"initialPath\"`              | URL path to be appended when visiting Storybook for the first time. <br /> `\"initialPath\": \"docs/configure-your-project--docs\"`                                                                 |\n| `\"webpackStatsJson\"`         | Write Webpack Stats JSON to disk. <br /> `\"webpackStatsJson\": true`                                                                                                                             |\n| `\"previewUrl\"`               | Disables the default storybook preview and lets you use your own. <br /> `\"previewUrl\": \"iframe.html\"`                                                                                          |\n| `\"loglevel\"`                 | Controls level of logging during build. Can be one of: [trace, debug, info (default), warn, error, silent]. <br /> `\"loglevel\": \"info\"`                                                       |\n| `\"sourceMap\"`                | Configure [sourcemaps](https://angular.dev/reference/configs/workspace-config#source-map-configuration.). <br /> `\"sourceMap\": true`                                                                         |\n| `\"experimentalZoneless\"`     | Configure [zoneless change detection](https://angular.dev/guide/zoneless). <br /> `\"experimentalZoneless\": true`                                                                 |\n\nThe full list of options can be found in the Angular builder schemas:\n\n* [Build Storybook](https://github.com/storybookjs/storybook/blob/next/code/frameworks/angular/build-schema.json)\n* [Start Storybook](https://github.com/storybookjs/storybook/blob/next/code/frameworks/angular/start-schema.json)\n\n## API\n\n### Options\n\nYou can pass an options object for additional configuration if needed:\n\n<CodeSnippets path=\"angular-framework-options.md\" />\n\nThe available options are:\n\n#### `builder`\n\nType: `Record<string, any>`\n\nConfigure options for the [framework's builder](../../api/main-config/main-config-framework.mdx#optionsbuilder). For this framework, available options can be found in the [Webpack builder docs](../../builders/webpack.mdx).\n"
  },
  {
    "path": "docs/get-started/frameworks/index.mdx",
    "content": "---\ntitle: Frameworks\nsidebar:\n  order: 3\n  title: Frameworks\n---\n\n\n## Supported frameworks\n\n<HomeRenderers />\n\n## Community-maintained frameworks\n\nStorybook includes an active community that supports additional frameworks and libraries. These community-maintained frameworks are actively developed and maintained by community contributors.\n\n<CommunityRenderers />"
  },
  {
    "path": "docs/get-started/frameworks/nextjs-vite.mdx",
    "content": "---\ntitle: Storybook for Next.js with Vite\nhideRendererSelector: true\nsidebar:\n  order: 2\n  title: Next.js (Vite)\n---\n\nStorybook for Next.js (Vite) is the **recommended** [framework](../../contribute/framework.mdx) for developing and testing UI components in isolation for [Next.js](https://nextjs.org/) applications. It uses [Vite](https://vitejs.dev/) for faster builds, better performance and [Storybook Testing](../../writing-tests/index.mdx) support.\n\n## Install\n\nTo install Storybook in an existing Next.js project, run this command in your project's root directory:\n\n<CodeSnippets path=\"create-command.md\" variant=\"new-users\" copyEvent=\"CreateCommandCopy\" />\n\nYou can then get started [writing stories](../whats-a-story.mdx), [running tests](../../writing-tests/index.mdx) and [documenting your components](../../writing-docs/index.mdx). For more control over the installation process, refer to the [installation guide](../install.mdx).\n\n### Requirements\n\n<GetStartedVersions versions={[{\n  name: 'Next.js',\n  range: '≥ 14.1',\n  icon: '/images/logos/renderers/logo-nextjs.svg'\n}, {\n  name: 'Vite',\n  range: '≥ 5',\n  icon: '/images/logos/builders/vite.svg'\n}]} />\n\n## Choose between Vite and Webpack\n\nThis Vite-based framework offers several advantages over the Webpack-based [`@storybook/nextjs`](./nextjs.mdx) framework, and is the recommended option:\n\n* ⚡ **Faster builds** - Vite's build system is significantly faster than Webpack\n* 🔧 **Modern tooling** - Uses the latest build tools and optimizations\n* 🧪 **Better test support** - Full support for the [Vitest addon](../../writing-tests/integrations/vitest-addon/index.mdx) and other testing features\n* 📦 **Simpler configuration** - No need for Babel or complex Webpack configurations\n* 🎯 **Better development experience** - Faster Hot Module Replacement and dev server startup\n\nStorybook will automatically detect your project and select the `nextjs-vite` framework **unless** your project has custom Webpack or Babel configurations. If you have custom configurations, Storybook will ask you which framework to install.\n\nChoose `nextjs-vite` if you're willing to migrate existing Babel or Webpack configurations to Vite. Choose `nextjs` (Webpack 5) if you need to keep your existing Webpack/Babel setup.\n\n\n## Run Storybook\n\nTo run Storybook for a particular project, run the following:\n\n<CodeSnippets path=\"storybook-run-dev.md\" />\n\nTo build Storybook, run:\n\n<CodeSnippets path=\"build-storybook-production-mode.md\" />\n\nYou will find the output in the configured `outputDir` (default is `storybook-static`).\n\n## Configure\n\nStorybook for Next.js with Vite supports many Next.js features including:\n\n* 🖼 [Image optimization](#nextjss-image-component)\n* 🔤 [Font optimization](#nextjs-font-optimization)\n* 🔀 [Routing and navigation](#nextjs-routing)\n* 🌐 [`next/head`](#nextjs-head)\n* ⤵️ [Absolute imports](#imports)\n* 🎨 [Styling](#styling)\n* 🎭 [Module mocking](#mocking-modules)\n* ☁️ [React Server Component (experimental)](#react-server-components-rsc)\n\n### Next.js's Image component\n\nThis framework allows you to use Next.js's [next/image](https://nextjs.org/docs/pages/api-reference/components/image) with no configuration.\n\n#### Local images\n\n[Local images](https://nextjs.org/docs/pages/building-your-application/optimizing/images#local-images) are supported.\n\n```jsx title=\"index.jsx\"\nimport Image from 'next/image';\nimport profilePic from '../public/me.png';\n\nfunction Home() {\n  return (\n    <>\n      <h1>My Homepage</h1>\n      <Image\n        src={profilePic}\n        alt=\"Picture of the author\"\n        // width={500} automatically provided\n        // height={500} automatically provided\n        // blurDataURL=\"../public/me.png\" set to equal the image itself (for this framework)\n        // placeholder=\"blur\" // Optional blur-up while loading\n      />\n      <p>Welcome to my homepage!</p>\n    </>\n  );\n}\n```\n\n#### Remote images\n\n[Remote images](https://nextjs.org/docs/pages/building-your-application/optimizing/images#remote-images) are also supported.\n\n```jsx title=\"index.jsx\"\nimport Image from 'next/image';\n\nexport default function Home() {\n  return (\n    <>\n      <h1>My Homepage</h1>\n      <Image src=\"/me.png\" alt=\"Picture of the author\" width={500} height={500} />\n      <p>Welcome to my homepage!</p>\n    </>\n  );\n}\n```\n\n### Next.js font optimization\n\n[next/font](https://nextjs.org/docs/pages/building-your-application/optimizing/fonts) is partially supported in Storybook. The packages `next/font/google` and `next/font/local` are supported.\n\n#### `next/font/google`\n\nYou don't have to do anything. `next/font/google` is supported out of the box.\n\n#### `next/font/local`\n\nFor local fonts you have to define the [src](https://nextjs.org/docs/pages/building-your-application/optimizing/fonts#local-fonts) property.\nThe path is relative to the directory where the font loader function is called.\n\nIf the following component defines your localFont like this:\n\n```js title=\"src/components/MyComponent.js\"\nimport localFont from 'next/font/local';\n\nconst localRubikStorm = localFont({ src: './fonts/RubikStorm-Regular.ttf' });\n```\n\nThe Vite-based framework automatically handles font path mapping, so you don't need to configure `staticDirs` for fonts like you would with the Webpack-based framework.\n\n#### Not supported features of `next/font`\n\nThe following features are not supported (yet). Support for these features might be planned for the future:\n\n* [Support font loaders configuration in next.config.js](https://nextjs.org/docs/pages/building-your-application/optimizing/fonts#local-fonts)\n* [fallback](https://nextjs.org/docs/pages/api-reference/components/font#fallback) option\n* [adjustFontFallback](https://nextjs.org/docs/pages/api-reference/components/font#adjustfontfallback) option\n* [preload](https://nextjs.org/docs/pages/api-reference/components/font#preload) option gets ignored. Storybook handles Font loading its own way.\n* [display](https://nextjs.org/docs/pages/api-reference/components/font#display) option gets ignored. All fonts are loaded with display set to \"block\" to make Storybook load the font properly.\n\n#### Mocking fonts during testing\n\nOccasionally fetching fonts from Google may fail as part of your Storybook build step. It is highly recommended to mock these requests, as those failures can cause your pipeline to fail as well. Next.js [supports mocking fonts](https://github.com/vercel/next.js/blob/725ddc7371f80cca273779d37f961c3e20356f95/packages/font/src/google/fetch-css-from-google-fonts.ts#L36) via a JavaScript module located where the env var `NEXT_FONT_GOOGLE_MOCKED_RESPONSES` references.\n\nFor example, using [GitHub Actions](https://www.chromatic.com/docs/github-actions):\n\n```yaml title=\".github/workflows/ci.yml\"\n- uses: chromaui/action@latest\n  env:\n    #👇 the location of mocked fonts to use\n    NEXT_FONT_GOOGLE_MOCKED_RESPONSES: ${{ github.workspace }}/mocked-google-fonts.js\n  with:\n    projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}\n    token: ${{ secrets.GITHUB_TOKEN }}\n```\n\nYour mocked fonts will look something like this:\n\n```js title=\"mocked-google-fonts.js\"\n//👇 Mocked responses of google fonts with the URL as the key\nmodule.exports = {\n  'https://fonts.googleapis.com/css?family=Inter:wght@400;500;600;800&display=block': `\n    /* cyrillic-ext */\n    @font-face {\n      font-family: 'Inter';\n      font-style: normal;\n      font-weight: 400;\n      font-display: block;\n      src: url(https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZJhiJ-Ek-_EeAmM.woff2) format('woff2');\n      unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n    }\n    /* more font declarations go here */\n    /* latin */\n    @font-face {\n      font-family: 'Inter';\n      font-style: normal;\n      font-weight: 400;\n      font-display: block;\n      src: url(https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZ9hiJ-Ek-_EeA.woff2) format('woff2');\n      unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n    }`,\n};\n```\n\n### Next.js routing\n\n[Next.js's router](https://nextjs.org/docs/pages/building-your-application/routing) is automatically stubbed for you so that when the router is interacted with, all of its interactions are automatically logged to the [Actions panel](../../essentials/actions.mdx).\n\n<Callout>\n\nYou should only use `next/router` in the `pages` directory. In the `app` directory, it is necessary to use `next/navigation`.\n\n</Callout>\n\n#### Overriding defaults\n\nPer-story overrides can be done by adding a `nextjs.router` property onto the story [parameters](../../writing-stories/parameters.mdx). The framework will shallowly merge whatever you put here into the router.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-router-override-in-story.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout>\n\nThese overrides can also be applied to [all stories for a component](../../api/parameters.mdx#meta-parameters) or [all stories in your project](../../api/parameters.mdx#project-parameters). Standard [parameter inheritance](../../api/parameters.mdx#parameter-inheritance) rules apply.\n\n</Callout>\n\n#### Default router\n\nThe default values on the stubbed router are as follows (see [globals](../../essentials/toolbars-and-globals.mdx#globals) for more details on how globals work).\n\n```ts\n// Default router\nconst defaultRouter = {\n  // The locale should be configured globally: https://storybook.js.org/docs/essentials/toolbars-and-globals#globals\n  locale: globals?.locale,\n  asPath: '/',\n  basePath: '/',\n  isFallback: false,\n  isLocaleDomain: false,\n  isReady: true,\n  isPreview: false,\n  route: '/',\n  pathname: '/',\n  query: {},\n};\n```\n\nAdditionally, the [`router` object](https://nextjs.org/docs/pages/api-reference/functions/use-router#router-object) contains all of the original methods (such as `push()`, `replace()`, etc.) as mock functions that can be manipulated and asserted on using [regular mock APIs](https://vitest.dev/api/mock.html).\n\nTo override these defaults, you can use [parameters](../../writing-stories/parameters.mdx) and [`beforeEach`](../../writing-stories/mocking-data-and-modules/mocking-modules.mdx#setting-up-and-cleaning-up):\n\n<CodeSnippets path=\"nextjs-router-override-in-preview.md\" />\n\n### Next.js navigation\n\n<Callout>\n\nPlease note that [`next/navigation`](https://nextjs.org/docs/app/building-your-application/routing) can only be used in components/pages in the `app` directory.\n\n</Callout>\n\n#### Set `nextjs.appDirectory` to `true`\n\nIf your story imports components that use `next/navigation`, you need to set the parameter `nextjs.appDirectory` to `true` in for that component's stories:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-app-directory-in-meta.md\" />\n\n{/* prettier-ignore-end */}\n\nIf your Next.js project uses the `app` directory for every page (in other words, it does not have a `pages` directory), you can set the parameter `nextjs.appDirectory` to `true` in the [`.storybook/preview.js|ts`](../../configure/index.mdx#configure-story-rendering) file to apply it to all stories.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-app-directory-in-preview.md\" />\n\n{/* prettier-ignore-end */}\n\n#### Overriding defaults\n\nPer-story overrides can be done by adding a `nextjs.navigation` property onto the story [parameters](../../writing-stories/parameters.mdx). The framework will shallowly merge whatever you put here into the router.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-navigation-override-in-story.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout>\n\nThese overrides can also be applied to [all stories for a component](../../api/parameters.mdx#meta-parameters) or [all stories in your project](../../api/parameters.mdx#project-parameters). Standard [parameter inheritance](../../api/parameters.mdx#parameter-inheritance) rules apply.\n\n</Callout>\n\n#### `useSelectedLayoutSegment`, `useSelectedLayoutSegments`, and `useParams` hooks\n\nThe `useSelectedLayoutSegment`, `useSelectedLayoutSegments`, and `useParams` hooks are supported in Storybook. You have to set the `nextjs.navigation.segments` parameter to return the segments or the params you want to use.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-navigation-segments-override-in-meta.md\" />\n\nWith the above configuration, the component rendered in the stories would receive the following values from the hooks:\n\n```js title=\"NavigationBasedComponent.js\"\nimport { useSelectedLayoutSegment, useSelectedLayoutSegments, useParams } from 'next/navigation';\n\nexport default function NavigationBasedComponent() {\n  const segment = useSelectedLayoutSegment(); // dashboard\n  const segments = useSelectedLayoutSegments(); // [\"dashboard\", \"analytics\"]\n  const params = useParams(); // {}\n  // ...\n}\n```\n\n{/* prettier-ignore-end */}\n\nTo use `useParams`, you have to use a segments array where each element is an array containing two strings. The first string is the param key and the second string is the param value.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-navigation-segments-for-use-params-override-in-meta.md\" />\n\n{/* prettier-ignore-end */}\n\nWith the above configuration, the component rendered in the stories would receive the following values from the hooks:\n\n```js title=\"ParamsBasedComponent.js\"\nimport { useSelectedLayoutSegment, useSelectedLayoutSegments, useParams } from 'next/navigation';\n\nexport default function ParamsBasedComponent() {\n  const segment = useSelectedLayoutSegment(); // hello\n  const segments = useSelectedLayoutSegments(); // [\"hello\", \"nextjs\"]\n  const params = useParams(); // { slug: \"hello\", framework: \"nextjs\" }\n  ...\n}\n```\n\n<Callout>\n\nThese overrides can also be applied to [a single story](../../api/parameters.mdx#story-parameters) or [all stories in your project](../../api/parameters.mdx#project-parameters). Standard [parameter inheritance](../../api/parameters.mdx#parameter-inheritance) rules apply.\n\n</Callout>\n\nThe default value of `nextjs.navigation.segments` is `[]` if not set.\n\n#### Default navigation context\n\nThe default values on the stubbed navigation context are as follows:\n\n```ts\n// Default navigation context\nconst defaultNavigationContext = {\n  pathname: '/',\n  query: {},\n};\n```\n\nAdditionally, the [`router` object](https://nextjs.org/docs/app/api-reference/functions/use-router#userouter) contains all of the original methods (such as `push()`, `replace()`, etc.) as mock functions that can be manipulated and asserted on using [regular mock APIs](https://vitest.dev/api/mock.html).\n\nTo override these defaults, you can use [parameters](../../writing-stories/parameters.mdx) and [`beforeEach`](../../writing-stories/mocking-data-and-modules/mocking-modules.mdx#setting-up-and-cleaning-up):\n\n<CodeSnippets path=\"nextjs-navigation-override-in-preview.md\" />\n\n### Next.js Head\n\n[`next/head`](https://nextjs.org/docs/pages/api-reference/components/head) is supported out of the box. You can use it in your stories like you would in your Next.js application. Please keep in mind, that the Head `children` are placed into the head element of the iframe that Storybook uses to render your stories.\n\n\n## Next.js styling\n\n### Sass/Scss\n\n[Global Sass/SCSS stylesheets](https://nextjs.org/docs/pages/building-your-application/styling/sass) are also supported without any additional configuration. Just import them into [the preview config file](../../configure/index.mdx#configure-story-rendering).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-styling-sass-preview.md\" />\n\n{/* prettier-ignore-end */}\n\nThis will automatically include any of your [custom Sass configurations](https://nextjs.org/docs/pages/building-your-application/styling/sass#customizing-sass-options) in your Next.js config file.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-styling-sass-config.md\" />\n\n{/* prettier-ignore-end */}\n\n### CSS/Sass/Scss Modules\n\n[CSS modules](https://nextjs.org/docs/pages/building-your-application/styling/css-modules) work as expected.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-styling-css-modules.md\" />\n\n{/* prettier-ignore-end */}\n\n### Styled JSX\n\nThe built-in CSS-in-JS solution for Next.js is [styled-jsx](https://nextjs.org/docs/pages/building-your-application/styling/css-in-js), and this framework supports that out of the box, too, with zero config.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-styling-styled-jsx-component.md\" />\n\n{/* prettier-ignore-end */}\n\n### Tailwind\n\nTailwind in Next.js [is supported via PostCSS](https://nextjs.org/docs/app/getting-started/css#tailwind-css). Storybook will automatically handle the PostCSS config for you, including any custom PostCSS configuration, so that you can import your global CSS directly into [the preview config file](../../configure/index.mdx#configure-story-rendering):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-styling-tailwind.md\" />\n\n{/* prettier-ignore-end */}\n\n### PostCSS\n\nNext.js lets you [customize PostCSS config](https://nextjs.org/docs/pages/building-your-application/configuring/post-css). Thus this framework will automatically handle your PostCSS config for you.\n\n### Imports\n#### Absolute imports\n\n[Absolute imports](https://nextjs.org/docs/pages/building-your-application/configuring/absolute-imports-and-module-aliases#absolute-imports) from the root directory are supported.\n\n```jsx title=\"index.jsx|tsx\"\n// All good!\nimport Button from 'components/button';\n// Also good!\nimport styles from 'styles/HomePage.module.css';\n\nexport default function HomePage() {\n  return (\n    <>\n      <h1 className={styles.title}>Hello World</h1>\n      <Button />\n    </>\n  );\n}\n```\n\nAlso OK for global styles in `.storybook/preview.js|ts`!\n\n```js title=\".storybook/preview.js|ts\"\nimport 'styles/globals.scss';\n\n// ...\n```\n\n<Callout variant=\"warning\">\n\nAbsolute imports **cannot** be mocked in stories/tests. See the [Mocking modules](#mocking-modules) section for more information.\n\n</Callout>\n\n#### Module aliases\n\n[Module aliases](https://nextjs.org/docs/app/building-your-application/configuring/absolute-imports-and-module-aliases#module-aliases) are also supported.\n\n```jsx title=\"index.jsx|tsx\"\n// All good!\nimport Button from '@/components/button';\n// Also good!\nimport styles from '@/styles/HomePage.module.css';\n\nexport default function HomePage() {\n  return (\n    <>\n      <h1 className={styles.title}>Hello World</h1>\n      <Button />\n    </>\n  );\n}\n```\n\n#### Subpath imports\n\nAs an alternative to [module aliases](#module-aliases), you can use [subpath imports](https://nodejs.org/api/packages.html#subpath-imports) to import modules. This follows Node package standards and has benefits when [mocking modules](#mocking-modules).\n\nTo configure subpath imports, you define the `imports` property in your project's `package.json` file. This property maps the subpath to the actual file path. The example below configures subpath imports for all modules in the project:\n\n```json title=\"package.json\"\n{\n  \"imports\": {\n    \"#*\": [\"./*\", \"./*.ts\", \"./*.tsx\"]\n  }\n}\n```\n\n<Callout variant=\"info\">\n\nBecause subpath imports replace module aliases, you can remove the path aliases from your TypeScript configuration.\n\n</Callout>\n\nWhich can then be used like this:\n\n```jsx title=\"index.jsx|tsx\"\nimport Button from '#components/button';\nimport styles from '#styles/HomePage.module.css';\n\nexport default function HomePage() {\n  return (\n    <>\n      <h1 className={styles.title}>Hello World</h1>\n      <Button />\n    </>\n  );\n}\n```\n\n### Mocking modules\n\nComponents often depend on modules that are imported into the component file. These can be from external packages or internal to your project. When rendering those components in Storybook or testing them, you may want to [mock those modules](../../writing-stories/mocking-data-and-modules/mocking-modules.mdx) to control and assert their behavior.\n\n#### Built-in mocked modules\n\nThis framework provides mocks for many of Next.js' internal modules:\n\n1. [`@storybook/nextjs-vite/cache.mock`](#storybooknextjs-vitecachemock)\n2. [`@storybook/nextjs-vite/headers.mock`](#storybooknextjs-viteheadersmock)\n3. [`@storybook/nextjs-vite/navigation.mock`](#storybooknextjs-vitenavigationmock)\n4. [`@storybook/nextjs-vite/router.mock`](#storybooknextjs-viteroutermock)\n\n#### Mocking other modules\n\nTo mock other modules, use [automocking](../../writing-stories/mocking-data-and-modules/mocking-modules.mdx#automocking) or one of the [alternative methods](../../writing-stories/mocking-data-and-modules/mocking-modules.mdx#alternative-methods) documented in the mocking modules guide.\n\n### Runtime config\n\nNext.js allows for [Runtime Configuration](https://nextjs.org/docs/pages/api-reference/next-config-js/runtime-configuration) which lets you import a handy `getConfig` function to get certain configuration defined in your `next.config.js` file at runtime.\n\nIn the context of Storybook with this framework, you can expect Next.js's [Runtime Configuration](https://nextjs.org/docs/pages/api-reference/next-config-js/runtime-configuration) feature to work just fine.\n\nNote, because Storybook doesn't server render your components, your components will only see what they normally see on the client side (i.e. they won't see `serverRuntimeConfig` but will see `publicRuntimeConfig`).\n\nFor example, consider the following Next.js config:\n\n```js title=\"next.config.js\"\nmodule.exports = {\n  serverRuntimeConfig: {\n    mySecret: 'secret',\n    secondSecret: process.env.SECOND_SECRET, // Pass through env variables\n  },\n  publicRuntimeConfig: {\n    staticFolder: '/static',\n  },\n};\n```\n\nCalls to `getConfig` would return the following object when called within Storybook:\n\n```jsonc\n// Runtime config\n{\n  \"serverRuntimeConfig\": {},\n  \"publicRuntimeConfig\": {\n    \"staticFolder\": \"/static\"\n  }\n}\n```\n\n### Custom Vite configuration\n\nYou can customize the [Vite configuration](../../builders/vite.mdx#configuration) used by Storybook in your `.storybook/main.js|ts` file. By default, Storybook's configuration extends the Vite configuration used by your project, but you can configure it to not do so.\n\nNot all Vite modifications are copy/paste-able between `next.config.js` and `.storybook/main.js|ts`. It is recommended to do your research on how to properly make your modification to Storybook's Vite config and on how [Vite works](https://vitejs.dev/guide/).\n\n### Typescript\n\nStorybook handles most [Typescript](https://www.typescriptlang.org/) configurations, but this framework adds additional support for Next.js's support for [Absolute Imports and Module path aliases](https://nextjs.org/docs/pages/building-your-application/configuring/absolute-imports-and-module-aliases). In short, it takes into account your `tsconfig.json`'s [baseUrl](https://www.typescriptlang.org/tsconfig#baseUrl) and [paths](https://www.typescriptlang.org/tsconfig#paths). Thus, a `tsconfig.json` like the one below would work out of the box.\n\n```json title=\"tsconfig.json\"\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@/components/*\": [\"components/*\"]\n    }\n  }\n}\n```\n\n### React Server Components (RSC)\n\n(⚠️ **Experimental**)\n\nIf your app uses [React Server Components (RSC)](https://nextjs.org/docs/app/building-your-application/rendering/server-components), Storybook can render them in stories in the browser.\n\nTo enable this set the `experimentalRSC` feature flag in your `.storybook/main.js|ts` config:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"rsc-feature-flag.md\" />\n\n{/* prettier-ignore-end */}\n\nSetting this flag automatically wraps your story in a [Suspense](https://react.dev/reference/react/Suspense) wrapper, which is able to render asynchronous components in NextJS's version of React.\n\nIf this wrapper causes problems in any of your existing stories, you can selectively disable it using the `react.rsc` [parameter](../../writing-stories/parameters.mdx) at the global/component/story level:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"rsc-parameter-in-meta.md\" />\n\n{/* prettier-ignore-end */}\n\nNote that wrapping your server components in Suspense does not help if your server components access server-side resources like the file system or Node-specific libraries. To work around this, you'll need to mock out your data access layer using [Vite aliases](https://vitejs.dev/config/shared-options.html#resolve-alias) or an addon like [storybook-addon-module-mock](https://storybook.js.org/addons/storybook-addon-module-mock).\n\nIf your server components access data via the network, we recommend using the [MSW Storybook Addon](https://storybook.js.org/addons/msw-storybook-addon) to mock network requests.\n\nIn the future we will provide better mocking support in Storybook and support for [Server Actions](https://nextjs.org/docs/app/api-reference/functions/server-actions).\n\n## FAQ\n\n### How do I migrate from the `nextjs` (Webpack 5) addon?\n\n#### Automatic migration\n\nStorybook provides a migration tool for migrating to this framework from the Webpack-based Next.js framework, [`@storybook/nextjs`](./nextjs.mdx). To migrate, run this command:\n\n```bash\nnpx storybook automigrate nextjs-to-nextjs-vite\n```\n\nThis automigration tool performs the following actions:\n\n1. Updates `package.json` files to replace `@storybook/nextjs` with `@storybook/nextjs-vite`\n2. Updates `.storybook/main.js|ts` to change the framework property\n3. Scans and updates import statements in your story files and configuration files\n\n<Callout variant=\"info\">\n\nIf your project has custom Webpack configurations in `.storybook/main.js|ts` (via `webpackFinal`), you'll need to migrate those to Vite configuration (via `viteFinal`) after running this automigration. See the [Vite builder documentation](../../builders/vite.mdx#migrating-from-webpack) for more information.\n\n</Callout>\n\n#### Manual migration\n\nFirst, install the framework:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-vite-install.md\" />\n\n{/* prettier-ignore-end */}\n\nThen, update your `.storybook/main.js|ts` to change the framework property:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-vite-add-framework.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n\nIf your Storybook configuration contains custom Webpack operations in [`webpackFinal`](../../api/main-config/main-config-webpack-final.mdx), you will likely need to create equivalents in [`viteFinal`](../../api/main-config/main-config-vite-final.mdx).\n\nFor more information, see the [Vite builder documentation](../../builders/vite.mdx#migrating-from-webpack).\n\n</Callout>\n\nFinally, if you were using Storybook plugins to integrate with Next.js, those are no longer necessary when using this framework and can be removed:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-remove-addons.md\" />\n\n{/* prettier-ignore-end */}\n\n### Stories for pages/components which fetch data\n\nNext.js pages can fetch data directly within server components in the `app` directory, which often include module imports that only run in a node environment. This does not (currently) work within Storybook, because if you import from a Next.js page file containing those node module imports in your stories, your Storybook's Vite build will crash because those modules will not run in a browser. To get around this, you can extract the component in your page file into a separate file and import that pure component in your stories. Or, if that's not feasible for some reason, you can [configure Vite to handle those modules](https://vitejs.dev/config/dep-optimization-options.html#optimizedeps-exclude) in your Storybook's [`viteFinal` configuration](../../builders/vite.mdx#configuration).\n\n**Before**\n\n```jsx title=\"app/my-page/index.jsx\"\nasync function getData() {\n  const res = await fetch(...);\n  // ...\n}\n\n// Using this component in your stories will break the Storybook build\nexport default async function Page() {\n  const data = await getData();\n\n  return // ...\n}\n```\n\n**After**\n\n```jsx title=\"app/my-page/index.jsx\"\n// Use this component in your stories\nimport MyPage from './components/MyPage';\n\nasync function getData() {\n  const res = await fetch(...);\n  // ...\n}\n\nexport default async function Page() {\n  const data = await getData();\n\n  return <MyPage {...data} />;\n}\n```\n\n### Statically imported images won't load\n\nMake sure you are treating image imports the same way you treat them when using `next/image` in normal development.\n\nBefore using this framework, image imports would import the raw path to the image (e.g. `'static/media/stories/assets/logo.svg'`). Now image imports work the \"Next.js way\", meaning that you now get an object when importing an image. For example:\n\n```jsonc\n// Image import object\n{\n  \"src\": \"static/media/stories/assets/logo.svg\",\n  \"height\": 48,\n  \"width\": 48,\n  \"blurDataURL\": \"static/media/stories/assets/logo.svg\"\n}\n```\n\nTherefore, if something in Storybook isn't showing the image properly, make sure you expect the object to be returned from an import instead of only the asset path.\n\nSee [local images](https://nextjs.org/docs/pages/building-your-application/optimizing/images#local-images) for more detail on how Next.js treats static image imports.\n\n### Error: You are importing avif images, but you don't have sharp installed. You have to install sharp in order to use image optimization features in Next.js.\n\n`sharp` is a dependency of Next.js's image optimization feature. If you see this error, you need to install `sharp` in your project.\n\n```bash\nnpm install sharp\n```\n\n```bash\nyarn add sharp\n```\n\n```bash\npnpm add sharp\n```\n\nYou can refer to the [Install `sharp` to Use Built-In Image Optimization](https://nextjs.org/docs/messages/install-sharp) in the Next.js documentation for more information.\n\n### Should I use the Vite or Webpack version?\n\nWe recommend using `@storybook/nextjs-vite` (this framework) for most projects because it offers:\n\n* Faster builds and development server startup\n* Better support for modern testing features like the [Vitest addon](../../writing-tests/integrations/vitest-addon/index.mdx)\n* Simpler configuration without Babel\n* Better developer experience with faster HMR\n\nHowever, if your project has custom Webpack configurations that are incompatible with Vite, or you need specific Webpack features, you should use [`@storybook/nextjs`](./nextjs.mdx) (Webpack 5) instead.\n\n## API\n\n### Modules\n\nThe `@storybook/nextjs-vite` package exports several modules that enable you to [mock](#mocking-modules) Next.js's internal behavior.\n\n#### `@storybook/nextjs-vite/cache.mock`\n\nType: `typeof import('next/cache')`\n\nThis module exports mocked implementations of the `next/cache` module's exports. You can use it to create your own mock implementations or assert on mock calls in a story's [play function](../../writing-stories/play-function.mdx).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-cache-mock.md\" />\n\n{/* prettier-ignore-end */}\n\n#### `@storybook/nextjs-vite/headers.mock`\n\nType: [`cookies`](https://nextjs.org/docs/app/api-reference/functions/cookies#cookiessetname-value-options), [`headers`](https://nextjs.org/docs/app/api-reference/functions/headers) and [`draftMode`](https://nextjs.org/docs/app/api-reference/functions/draft-mode) from Next.js\n\nThis module exports *writable* mocked implementations of the `next/headers` module's exports. You can use it to set up cookies or headers that are read in your story, and to later assert that they have been called.\n\nNext.js's default [`headers()`](https://nextjs.org/docs/app/api-reference/functions/headers) export is read-only, but this module exposes methods allowing you to write to the headers:\n\n* **`headers().append(name: string, value: string)`**: Appends the value to the header if it exists already.\n* **`headers().delete(name: string)`**: Deletes the header\n* **`headers().set(name: string, value: string)`**: Sets the header to the value provided.\n\nFor cookies, you can use the existing API to write them. E.g., `cookies().set('firstName', 'Jane')`.\n\nBecause `headers()`, `cookies()` and their sub-functions are all mocks you can use any [mock utilities](https://vitest.dev/api/mock.html) in your stories, like `headers().getAll.mock.calls`.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-headers-mock.md\" />\n\n{/* prettier-ignore-end */}\n\n#### `@storybook/nextjs-vite/navigation.mock`\n\nType: `typeof import('next/navigation') & getRouter: () => ReturnType<typeof import('next/navigation')['useRouter']>`\n\nThis module exports mocked implementations of the `next/navigation` module's exports. It also exports a `getRouter` function that returns a mocked version of [Next.js's `router` object from `useRouter`](https://nextjs.org/docs/app/api-reference/functions/use-router#userouter), allowing the properties to be manipulated and asserted on. You can use it mock implementations or assert on mock calls in a story's [play function](../../writing-stories/play-function.mdx).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-navigation-mock.md\" />\n\n{/* prettier-ignore-end */}\n\n#### `@storybook/nextjs-vite/router.mock`\n\nType: `typeof import('next/router') & getRouter: () => ReturnType<typeof import('next/router')['useRouter']>`\n\nThis module exports mocked implementations of the `next/router` module's exports. It also exports a `getRouter` function that returns a mocked version of [Next.js's `router` object from `useRouter`](https://nextjs.org/docs/pages/api-reference/functions/use-router#router-object), allowing the properties to be manipulated and asserted on. You can use it mock implementations or assert on mock calls in a story's [play function](../../writing-stories/play-function.mdx).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-router-mock.md\" />\n\n{/* prettier-ignore-end */}\n\n### Options\n\nYou can pass an options object for additional configuration if needed:\n\n<CodeSnippets path=\"nextjs-framework-options-next-config-path.md\" />\n\nThe available options are:\n\n#### `builder`\n\nType: `Record<string, any>`\n\nConfigure options for the [framework's builder](../../api/main-config/main-config-framework.mdx#optionsbuilder). For Next.js with Vite, available options can be found in the [Vite builder docs](../../builders/vite.mdx).\n\n#### `image`\n\nType: `object`\n\nProps to pass to every instance of `next/image`. See [next/image docs](https://nextjs.org/docs/pages/api-reference/components/image) for more details.\n\n#### `nextConfigPath`\n\nType: `string`\n\nThe absolute path to the `next.config.js` file. This is necessary if you have a custom `next.config.js` file that is not in the root directory of your project.\n\n### Parameters\n\nThis framework contributes the following [parameters](../../writing-stories/parameters.mdx) to Storybook, under the `nextjs` namespace:\n\n#### `appDirectory`\n\nType: `boolean`\n\nDefault: `false`\n\nIf your story imports components that use `next/navigation`, you need to set the parameter `nextjs.appDirectory` to `true`. Because this is a parameter, you can apply it to a [single story](../../api/parameters.mdx#story-parameters), [all stories for a component](../../api/parameters.mdx#meta-parameters), or [every story in your Storybook](../../api/parameters.mdx#project-parameters). See [Next.js Navigation](#nextjs-navigation) for more details.\n\n#### `navigation`\n\nType:\n\n```ts\n{\n  asPath?: string;\n  pathname?: string;\n  query?: Record<string, string>;\n  segments?: (string | [string, string])[];\n}\n```\n\nDefault value:\n\n```js\n{\n  segments: [];\n}\n```\n\nThe router object that is passed to the `next/navigation` context. See [Next.js's navigation docs](https://nextjs.org/docs/app/building-your-application/routing) for more details.\n\n#### `router`\n\nType:\n\n```ts\n{\n  asPath?: string;\n  pathname?: string;\n  query?: Record<string, string>;\n}\n```\n\nThe router object that is passed to the `next/router` context. See [Next.js's router docs](https://nextjs.org/docs/pages/building-your-application/routing) for more details.\n\n"
  },
  {
    "path": "docs/get-started/frameworks/nextjs.mdx",
    "content": "---\ntitle: Storybook for Next.js with Webpack\nhideRendererSelector: true\nsidebar:\n  order: 3\n  title: Next.js (Webpack)\n---\n\nStorybook for Next.js (Webpack) is a [framework](../../contribute/framework.mdx) that makes it easy to develop and test UI components in isolation for [Next.js](https://nextjs.org/) applications using [Webpack 5](https://webpack.js.org/).\n\n<Callout variant=\"info\">\n\n**We recommend using [`@storybook/nextjs-vite`](./nextjs-vite.mdx)** for most Next.js projects. The Vite-based framework is faster, more modern, and offers better support for testing features.\n\nUse this Webpack-based framework (`@storybook/nextjs`) only if:\n- Your project has custom Webpack configurations that are incompatible with Vite\n- Your project has custom Babel configurations that require Webpack\n- You need specific Webpack features not available in Vite\n</Callout>\n\n## Install\n\nTo install Storybook in an existing Next.js project, run this command in your project's root directory:\n\n<CodeSnippets path=\"create-command.md\" variant=\"new-users\" copyEvent=\"CreateCommandCopy\" />\n\nThe command will prompt you to choose between this framework and [`@storybook/nextjs-vite`](./nextjs-vite.mdx). We recommend the Vite-based framework ([learn why](./nextjs-vite.mdx#choose-between-vite-and-webpack)).\n\nYou can then get started [writing stories](../whats-a-story.mdx), [running tests](../../writing-tests/index.mdx) and [documenting your components](../../writing-docs/index.mdx). For more control over the installation process, refer to the [installation guide](../install.mdx).\n\n### Requirements\n\n<GetStartedVersions versions={[{\n  name: 'Next.js',\n  range: '≥ 14.1',\n  icon: '/images/logos/renderers/logo-nextjs.svg'\n}, {\n  name: 'Webpack',\n  range: '5',\n  icon: '/images/logos/builders/webpack.svg'\n}]} />\n\n## Run Storybook\n\nTo run Storybook for a particular project, run the following:\n\n<CodeSnippets path=\"storybook-run-dev.md\" />\n\nTo build Storybook, run:\n\n<CodeSnippets path=\"build-storybook-production-mode.md\" />\n\nYou will find the output in the configured `outputDir` (default is `storybook-static`).\n\n## Configure\n\nStorybook for Next.js with Vite supports many Next.js features including:\n\n* 🖼 [Image optimization](#nextjss-image-component)\n* 🔤 [Font optimization](#nextjs-font-optimization)\n* 🔀 [Routing and navigation](#nextjs-routing)\n* 🌐 [`next/head`](#nextjs-head)\n* ⤵️ [Absolute imports](#imports)\n* 🎨 [Styling](#styling)\n* 🎭 [Module mocking](#mocking-modules)\n* ☁️ [React Server Component (experimental)](#react-server-components-rsc)\n\n### Next.js's Image component\n\nThis framework allows you to use Next.js's [next/image](https://nextjs.org/docs/pages/api-reference/components/image) with no configuration.\n\n#### Local images\n\n[Local images](https://nextjs.org/docs/pages/building-your-application/optimizing/images#local-images) are supported.\n\n```jsx title=\"index.jsx\"\nimport Image from 'next/image';\nimport profilePic from '../public/me.png';\n\nfunction Home() {\n  return (\n    <>\n      <h1>My Homepage</h1>\n      <Image\n        src={profilePic}\n        alt=\"Picture of the author\"\n        // width={500} automatically provided\n        // height={500} automatically provided\n        // blurDataURL=\"../public/me.png\" set to equal the image itself (for this framework)\n        // placeholder=\"blur\" // Optional blur-up while loading\n      />\n      <p>Welcome to my homepage!</p>\n    </>\n  );\n}\n```\n\n#### Remote images\n\n[Remote images](https://nextjs.org/docs/pages/building-your-application/optimizing/images#remote-images) are also supported.\n\n```jsx title=\"index.jsx\"\nimport Image from 'next/image';\n\nexport default function Home() {\n  return (\n    <>\n      <h1>My Homepage</h1>\n      <Image src=\"/me.png\" alt=\"Picture of the author\" width={500} height={500} />\n      <p>Welcome to my homepage!</p>\n    </>\n  );\n}\n```\n\n### Next.js font optimization\n\n[next/font](https://nextjs.org/docs/pages/building-your-application/optimizing/fonts) is partially supported in Storybook. The packages `next/font/google` and `next/font/local` are supported.\n\n#### `next/font/google`\n\nYou don't have to do anything. `next/font/google` is supported out of the box.\n\n#### `next/font/local`\n\nFor local fonts you have to define the [src](https://nextjs.org/docs/pages/building-your-application/optimizing/fonts#local-fonts) property.\nThe path is relative to the directory where the font loader function is called.\n\nIf the following component defines your localFont like this:\n\n```js title=\"src/components/MyComponent.js\"\nimport localFont from 'next/font/local';\n\nconst localRubikStorm = localFont({ src: './fonts/RubikStorm-Regular.ttf' });\n```\n\n##### `staticDir` mapping\n\nYou have to tell Storybook where the `fonts` directory is located, via the [`staticDirs` configuration](../../api/main-config/main-config-static-dirs.mdx#with-configuration-objects). The `from` value is relative to the `.storybook` directory. The `to` value is relative to the execution context of Storybook. Very likely it is the root of your project.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-image-static-dirs.md\" />\n\n{/* prettier-ignore-end */}\n\n#### Not supported features of `next/font`\n\nThe following features are not supported (yet). Support for these features might be planned for the future:\n\n* [Support font loaders configuration in next.config.js](https://nextjs.org/docs/pages/building-your-application/optimizing/fonts#local-fonts)\n* [fallback](https://nextjs.org/docs/pages/api-reference/components/font#fallback) option\n* [adjustFontFallback](https://nextjs.org/docs/pages/api-reference/components/font#adjustfontfallback) option\n* [preload](https://nextjs.org/docs/pages/api-reference/components/font#preload) option gets ignored. Storybook handles Font loading its own way.\n* [display](https://nextjs.org/docs/pages/api-reference/components/font#display) option gets ignored. All fonts are loaded with display set to \"block\" to make Storybook load the font properly.\n\n#### Mocking fonts during testing\n\nOccasionally fetching fonts from Google may fail as part of your Storybook build step. It is highly recommended to mock these requests, as those failures can cause your pipeline to fail as well. Next.js [supports mocking fonts](https://github.com/vercel/next.js/blob/725ddc7371f80cca273779d37f961c3e20356f95/packages/font/src/google/fetch-css-from-google-fonts.ts#L36) via a JavaScript module located where the env var `NEXT_FONT_GOOGLE_MOCKED_RESPONSES` references.\n\nFor example, using [GitHub Actions](https://www.chromatic.com/docs/github-actions):\n\n```yaml title=\".github/workflows/ci.yml\"\n- uses: chromaui/action@latest\n  env:\n    #👇 the location of mocked fonts to use\n    NEXT_FONT_GOOGLE_MOCKED_RESPONSES: ${{ github.workspace }}/mocked-google-fonts.js\n  with:\n    projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}\n    token: ${{ secrets.GITHUB_TOKEN }}\n```\n\nYour mocked fonts will look something like this:\n\n```js title=\"mocked-google-fonts.js\"\n//👇 Mocked responses of google fonts with the URL as the key\nmodule.exports = {\n  'https://fonts.googleapis.com/css?family=Inter:wght@400;500;600;800&display=block': `\n    /* cyrillic-ext */\n    @font-face {\n      font-family: 'Inter';\n      font-style: normal;\n      font-weight: 400;\n      font-display: block;\n      src: url(https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZJhiJ-Ek-_EeAmM.woff2) format('woff2');\n      unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n    }\n    /* more font declarations go here */\n    /* latin */\n    @font-face {\n      font-family: 'Inter';\n      font-style: normal;\n      font-weight: 400;\n      font-display: block;\n      src: url(https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZ9hiJ-Ek-_EeA.woff2) format('woff2');\n      unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n    }`,\n};\n```\n\n### Next.js routing\n\n[Next.js's router](https://nextjs.org/docs/pages/building-your-application/routing) is automatically stubbed for you so that when the router is interacted with, all of its interactions are automatically logged to the [Actions panel](../../essentials/actions.mdx).\n\n<Callout>\n  You should only use `next/router` in the `pages` directory. In the `app` directory, it is necessary to use `next/navigation`.\n</Callout>\n\n#### Overriding defaults\n\nPer-story overrides can be done by adding a `nextjs.router` property onto the story [parameters](../../writing-stories/parameters.mdx). The framework will shallowly merge whatever you put here into the router.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-router-override-in-story.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout>\n  These overrides can also be applied to [all stories for a component](../../api/parameters.mdx#meta-parameters) or [all stories in your project](../../api/parameters.mdx#project-parameters). Standard [parameter inheritance](../../api/parameters.mdx#parameter-inheritance) rules apply.\n</Callout>\n\n#### Default router\n\nThe default values on the stubbed router are as follows (see [globals](../../essentials/toolbars-and-globals.mdx#globals) for more details on how globals work).\n\n```ts\n// Default router\nconst defaultRouter = {\n  // The locale should be configured globally: https://storybook.js.org/docs/essentials/toolbars-and-globals#globals\n  locale: globals?.locale,\n  asPath: '/',\n  basePath: '/',\n  isFallback: false,\n  isLocaleDomain: false,\n  isReady: true,\n  isPreview: false,\n  route: '/',\n  pathname: '/',\n  query: {},\n};\n```\n\nAdditionally, the [`router` object](https://nextjs.org/docs/pages/api-reference/functions/use-router#router-object) contains all of the original methods (such as `push()`, `replace()`, etc.) as mock functions that can be manipulated and asserted on using [regular mock APIs](https://vitest.dev/api/mock.html).\n\nTo override these defaults, you can use [parameters](../../writing-stories/parameters.mdx) and [`beforeEach`](../../writing-stories/mocking-data-and-modules/mocking-modules.mdx#setting-up-and-cleaning-up):\n\n<CodeSnippets path=\"nextjs-router-override-in-preview.md\" />\n\n### Next.js navigation\n\n<Callout>\n  Please note that [`next/navigation`](https://nextjs.org/docs/app/building-your-application/routing) can only be used in components/pages in the `app` directory.\n</Callout>\n\n#### Set `nextjs.appDirectory` to `true`\n\nIf your story imports components that use `next/navigation`, you need to set the parameter `nextjs.appDirectory` to `true` in for that component's stories:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-app-directory-in-meta.md\" />\n\n{/* prettier-ignore-end */}\n\nIf your Next.js project uses the `app` directory for every page (in other words, it does not have a `pages` directory), you can set the parameter `nextjs.appDirectory` to `true` in the [`.storybook/preview.js|ts`](../../configure/index.mdx#configure-story-rendering) file to apply it to all stories.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-app-directory-in-preview.md\" />\n\n{/* prettier-ignore-end */}\n\n#### Overriding defaults\n\nPer-story overrides can be done by adding a `nextjs.navigation` property onto the story [parameters](../../writing-stories/parameters.mdx). The framework will shallowly merge whatever you put here into the router.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-navigation-override-in-story.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout>\n  These overrides can also be applied to [all stories for a component](../../api/parameters.mdx#meta-parameters) or [all stories in your project](../../api/parameters.mdx#project-parameters). Standard [parameter inheritance](../../api/parameters.mdx#parameter-inheritance) rules apply.\n</Callout>\n\n#### `useSelectedLayoutSegment`, `useSelectedLayoutSegments`, and `useParams` hooks\n\nThe `useSelectedLayoutSegment`, `useSelectedLayoutSegments`, and `useParams` hooks are supported in Storybook. You have to set the `nextjs.navigation.segments` parameter to return the segments or the params you want to use.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-navigation-segments-override-in-meta.md\" />\n\nWith the above configuration, the component rendered in the stories would receive the following values from the hooks:\n\n```js title=\"NavigationBasedComponent.js\"\nimport { useSelectedLayoutSegment, useSelectedLayoutSegments, useParams } from 'next/navigation';\n\nexport default function NavigationBasedComponent() {\n  const segment = useSelectedLayoutSegment(); // dashboard\n  const segments = useSelectedLayoutSegments(); // [\"dashboard\", \"analytics\"]\n  const params = useParams(); // {}\n  // ...\n}\n```\n\n{/* prettier-ignore-end */}\n\nTo use `useParams`, you have to use a segments array where each element is an array containing two strings. The first string is the param key and the second string is the param value.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-navigation-segments-for-use-params-override-in-meta.md\" />\n\n{/* prettier-ignore-end */}\n\nWith the above configuration, the component rendered in the stories would receive the following values from the hooks:\n\n```js title=\"ParamsBasedComponent.js\"\nimport { useSelectedLayoutSegment, useSelectedLayoutSegments, useParams } from 'next/navigation';\n\nexport default function ParamsBasedComponent() {\n  const segment = useSelectedLayoutSegment(); // hello\n  const segments = useSelectedLayoutSegments(); // [\"hello\", \"nextjs\"]\n  const params = useParams(); // { slug: \"hello\", framework: \"nextjs\" }\n  ...\n}\n```\n\n<Callout>\n  These overrides can also be applied to [a single story](../../api/parameters.mdx#story-parameters) or [all stories in your project](../../api/parameters.mdx#project-parameters). Standard [parameter inheritance](../../api/parameters.mdx#parameter-inheritance) rules apply.\n</Callout>\n\nThe default value of `nextjs.navigation.segments` is `[]` if not set.\n\n#### Default navigation context\n\nThe default values on the stubbed navigation context are as follows:\n\n```ts\n// Default navigation context\nconst defaultNavigationContext = {\n  pathname: '/',\n  query: {},\n};\n```\n\nAdditionally, the [`router` object](https://nextjs.org/docs/app/api-reference/functions/use-router#userouter) contains all of the original methods (such as `push()`, `replace()`, etc.) as mock functions that can be manipulated and asserted on using [regular mock APIs](https://vitest.dev/api/mock.html).\n\nTo override these defaults, you can use [parameters](../../writing-stories/parameters.mdx) and [`beforeEach`](../../writing-stories/mocking-data-and-modules/mocking-modules.mdx#setting-up-and-cleaning-up):\n\n<CodeSnippets path=\"nextjs-navigation-override-in-preview.md\" />\n\n### Next.js Head\n\n[`next/head`](https://nextjs.org/docs/pages/api-reference/components/head) is supported out of the box. You can use it in your stories like you would in your Next.js application. Please keep in mind, that the Head `children` are placed into the head element of the iframe that Storybook uses to render your stories.\n\n## Next.js styling\n\n### Sass/Scss\n\n[Global Sass/SCSS stylesheets](https://nextjs.org/docs/pages/building-your-application/styling/sass) are also supported without any additional configuration. Just import them into [the preview config file](../../configure/index.mdx#configure-story-rendering).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-styling-sass-preview.md\" />\n\n{/* prettier-ignore-end */}\n\nThis will automatically include any of your [custom Sass configurations](https://nextjs.org/docs/pages/building-your-application/styling/sass#customizing-sass-options) in your Next.js config file.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-styling-sass-config.md\" />\n\n{/* prettier-ignore-end */}\n\n### CSS/Sass/Scss Modules\n\n[CSS modules](https://nextjs.org/docs/pages/building-your-application/styling/css-modules) work as expected.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-styling-css-modules.md\" />\n\n{/* prettier-ignore-end */}\n\n### Styled JSX\n\nThe built-in CSS-in-JS solution for Next.js is [styled-jsx](https://nextjs.org/docs/pages/building-your-application/styling/css-in-js), and this framework supports that out of the box, too, with zero config.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-styling-styled-jsx-component.md\" />\n\n{/* prettier-ignore-end */}\n\nYou can use your own Babel config, too. This is an example of how you can customize styled-jsx.\n\n```jsonc\n// .babelrc (or whatever config file you use)\n{\n  \"presets\": [\n    [\n      \"next/babel\",\n      {\n        \"styled-jsx\": {\n          \"plugins\": [\"@styled-jsx/plugin-sass\"]\n        }\n      }\n    ]\n  ]\n}\n```\n\n### Tailwind\n\nTailwind in Next.js [is supported via PostCSS](https://nextjs.org/docs/app/getting-started/css#tailwind-css). Storybook will automatically handle the PostCSS config for you, including any custom PostCSS configuration, so that you can import your global CSS directly into [the preview config file](../../configure/index.mdx#configure-story-rendering):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-styling-tailwind.md\" />\n\n{/* prettier-ignore-end */}\n\n### PostCSS\n\nNext.js lets you [customize PostCSS config](https://nextjs.org/docs/pages/building-your-application/configuring/post-css). Thus this framework will automatically handle your PostCSS config for you.\n\n### Imports\n#### Absolute imports\n\n[Absolute imports](https://nextjs.org/docs/pages/building-your-application/configuring/absolute-imports-and-module-aliases#absolute-imports) from the root directory are supported.\n\n```jsx title=\"index.jsx|tsx\"\n// All good!\nimport Button from 'components/button';\n// Also good!\nimport styles from 'styles/HomePage.module.css';\n\nexport default function HomePage() {\n  return (\n    <>\n      <h1 className={styles.title}>Hello World</h1>\n      <Button />\n    </>\n  );\n}\n```\n\nAlso OK for global styles in `.storybook/preview.js|ts`!\n\n```js title=\".storybook/preview.js|ts\"\nimport 'styles/globals.scss';\n\n// ...\n```\n\n<Callout variant=\"warning\">\n  Absolute imports **cannot** be mocked in stories/tests. See the [Mocking modules](#mocking-modules) section for more information.\n</Callout>\n\n#### Module aliases\n\n[Module aliases](https://nextjs.org/docs/app/building-your-application/configuring/absolute-imports-and-module-aliases#module-aliases) are also supported.\n\n```jsx title=\"index.jsx|tsx\"\n// All good!\nimport Button from '@/components/button';\n// Also good!\nimport styles from '@/styles/HomePage.module.css';\n\nexport default function HomePage() {\n  return (\n    <>\n      <h1 className={styles.title}>Hello World</h1>\n      <Button />\n    </>\n  );\n}\n```\n\n#### Subpath imports\n\nAs an alternative to [module aliases](#module-aliases), you can use [subpath imports](https://nodejs.org/api/packages.html#subpath-imports) to import modules. This follows Node package standards and has benefits when [mocking modules](#mocking-modules).\n\nTo configure subpath imports, you define the `imports` property in your project's `package.json` file. This property maps the subpath to the actual file path. The example below configures subpath imports for all modules in the project:\n\n```json title=\"package.json\"\n{\n  \"imports\": {\n    \"#*\": [\"./*\", \"./*.ts\", \"./*.tsx\"]\n  }\n}\n```\n\n<Callout variant=\"info\">\n  Because subpath imports replace module aliases, you can remove the path aliases from your TypeScript configuration.\n</Callout>\n\nWhich can then be used like this:\n\n```jsx title=\"index.jsx|tsx\"\nimport Button from '#components/button';\nimport styles from '#styles/HomePage.module.css';\n\nexport default function HomePage() {\n  return (\n    <>\n      <h1 className={styles.title}>Hello World</h1>\n      <Button />\n    </>\n  );\n}\n```\n\n### Mocking modules\n\nComponents often depend on modules that are imported into the component file. These can be from external packages or internal to your project. When rendering those components in Storybook or testing them, you may want to [mock those modules](../../writing-stories/mocking-data-and-modules/mocking-modules.mdx) to control and assert their behavior.\n\n#### Built-in mocked modules\n\nThis framework provides mocks for many of Next.js' internal modules:\n\n1. [`@storybook/nextjs/cache.mock`](#storybooknextjscachemock)\n2. [`@storybook/nextjs/headers.mock`](#storybooknextjsheadersmock)\n3. [`@storybook/nextjs/navigation.mock`](#storybooknextjsnavigationmock)\n4. [`@storybook/nextjs/router.mock`](#storybooknextjsroutermock)\n\n#### Mocking other modules\n\nTo mock other modules, use [automocking](../../writing-stories/mocking-data-and-modules/mocking-modules.mdx#automocking) or one of the [alternative methods](../../writing-stories/mocking-data-and-modules/mocking-modules.mdx#alternative-methods) documented in the mocking modules guide.\n\n### Runtime config\n\nNext.js allows for [Runtime Configuration](https://nextjs.org/docs/pages/api-reference/next-config-js/runtime-configuration) which lets you import a handy `getConfig` function to get certain configuration defined in your `next.config.js` file at runtime.\n\nIn the context of Storybook with this framework, you can expect Next.js's [Runtime Configuration](https://nextjs.org/docs/pages/api-reference/next-config-js/runtime-configuration) feature to work just fine.\n\nNote, because Storybook doesn't server render your components, your components will only see what they normally see on the client side (i.e. they won't see `serverRuntimeConfig` but will see `publicRuntimeConfig`).\n\nFor example, consider the following Next.js config:\n\n```js title=\"next.config.js\"\nmodule.exports = {\n  serverRuntimeConfig: {\n    mySecret: 'secret',\n    secondSecret: process.env.SECOND_SECRET, // Pass through env variables\n  },\n  publicRuntimeConfig: {\n    staticFolder: '/static',\n  },\n};\n```\n\nCalls to `getConfig` would return the following object when called within Storybook:\n\n```jsonc\n// Runtime config\n{\n  \"serverRuntimeConfig\": {},\n  \"publicRuntimeConfig\": {\n    \"staticFolder\": \"/static\"\n  }\n}\n```\n\n### Custom Webpack config\n\nNext.js comes with a lot of things for free out of the box like Sass support, but sometimes you add [custom Webpack config modifications to Next.js](https://nextjs.org/docs/pages/api-reference/next-config-js/webpack). This framework takes care of most of the Webpack modifications you would want to add. If Next.js supports a feature out of the box, then that feature will work out of the box in Storybook. If Next.js doesn't support something out of the box, but makes it easy to configure, then this framework will do the same for that thing for Storybook.\n\nAny Webpack modifications desired for Storybook should be made in [`.storybook/main.js|ts`](../../builders/webpack.mdx#extending-storybooks-webpack-config).\n\nNote: Not all Webpack modifications are copy/paste-able between `next.config.js` and `.storybook/main.js|ts`. It is recommended to do your research on how to properly make your modification to Storybook's Webpack config and on how [Webpack works](https://webpack.js.org/concepts/).\n\nBelow is an example of how to add SVGR support to Storybook with this framework.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-configure-svgr.md\" />\n\n{/* prettier-ignore-end */}\n\n### Typescript\n\nStorybook handles most [Typescript](https://www.typescriptlang.org/) configurations, but this framework adds additional support for Next.js's support for [Absolute Imports and Module path aliases](https://nextjs.org/docs/pages/building-your-application/configuring/absolute-imports-and-module-aliases). In short, it takes into account your `tsconfig.json`'s [baseUrl](https://www.typescriptlang.org/tsconfig#baseUrl) and [paths](https://www.typescriptlang.org/tsconfig#paths). Thus, a `tsconfig.json` like the one below would work out of the box.\n\n```json title=\"tsconfig.json\"\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@/components/*\": [\"components/*\"]\n    }\n  }\n}\n```\n\n### React Server Components (RSC)\n\n(⚠️ **Experimental**)\n\nIf your app uses [React Server Components (RSC)](https://nextjs.org/docs/app/building-your-application/rendering/server-components), Storybook can render them in stories in the browser.\n\nTo enable this set the `experimentalRSC` feature flag in your `.storybook/main.js|ts` config:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"rsc-feature-flag.md\" />\n\n{/* prettier-ignore-end */}\n\nSetting this flag automatically wraps your story in a [Suspense](https://react.dev/reference/react/Suspense) wrapper, which is able to render asynchronous components in NextJS's version of React.\n\nIf this wrapper causes problems in any of your existing stories, you can selectively disable it using the `react.rsc` [parameter](../../writing-stories/parameters.mdx) at the global/component/story level:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"rsc-parameter-in-meta.md\" />\n\n{/* prettier-ignore-end */}\n\nNote that wrapping your server components in Suspense does not help if your server components access server-side resources like the file system or Node-specific libraries. To work around this, you'll need to mock out your data access layer using [Webpack aliases](https://webpack.js.org/configuration/resolve/#resolvealias) or an addon like [storybook-addon-module-mock](https://storybook.js.org/addons/storybook-addon-module-mock).\n\nIf your server components access data via the network, we recommend using the [MSW Storybook Addon](https://storybook.js.org/addons/msw-storybook-addon) to mock network requests.\n\nIn the future we will provide better mocking support in Storybook and support for [Server Actions](https://nextjs.org/docs/app/api-reference/functions/server-actions).\n\n{/* ## Portable stories\n\nYou can test your stories in a Jest environment by using the [portable stories](../../api/portable-stories/portable-stories-jest.mdx) API.\n\nWhen using portable stories with Next.js, you need to mock the Next.js modules on which your components depend. You can use the [`@storybook/nextjs/export-mocks` module](#storybooknextjsexport-mocks) to generate the aliases needed to set up portable stories in a Jest environment. This is needed because, to replicate Next.js configuration, Storybook sets up aliases in Webpack to make testing and developing your components easier. If you make use of the advanced functionality like the built-in mocks for common Next.js modules, you need to set up this aliasing in your Jest environment as well. */}\n\n## Notes for Yarn v2 and v3 users\n\nIf you're using [Yarn](https://yarnpkg.com/) v2 or v3, you may run into issues where Storybook can't resolve `style-loader` or `css-loader`. For example, you might get errors like:\n\n```\nModule not found: Error: Can't resolve 'css-loader'\nModule not found: Error: Can't resolve 'style-loader'\n```\n\nThis is because those versions of Yarn have different package resolution rules than Yarn v1.x. If this is the case for you, please install the package directly.\n\n## FAQ\n\n### How do I manually install the Next.js framework?\n\nFirst, install the framework:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-install.md\" />\n\n{/* prettier-ignore-end */}\n\nThen, update your `.storybook/main.js|ts` to change the framework property:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-add-framework.md\" />\n\n{/* prettier-ignore-end */}\n\nFinally, if you were using Storybook plugins to integrate with Next.js, those are no longer necessary when using this framework and can be removed:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-remove-addons.md\" />\n\n{/* prettier-ignore-end */}\n\n### How do I migrate to the Next.js Vite framework?\n\nPlease refer to the [migration instructions for `@storybook/nextjs-vite`](./nextjs-vite.mdx#how-do-i-migrate-from-the-nextjs-webpack-5-addon).\n\n### Stories for pages/components which fetch data\n\nNext.js pages can fetch data directly within server components in the `app` directory, which often include module imports that only run in a node environment. This does not (currently) work within Storybook, because if you import from a Next.js page file containing those node module imports in your stories, your Storybook's Webpack will crash because those modules will not run in a browser. To get around this, you can extract the component in your page file into a separate file and import that pure component in your stories. Or, if that's not feasible for some reason, you can [polyfill those modules](https://webpack.js.org/configuration/node/) in your Storybook's [`webpackFinal` configuration](../../builders/webpack.mdx#extending-storybooks-webpack-config).\n\n**Before**\n\n```jsx title=\"app/my-page/index.jsx\"\nasync function getData() {\n  const res = await fetch(...);\n  // ...\n}\n\n// Using this component in your stories will break the Storybook build\nexport default async function Page() {\n  const data = await getData();\n\n  return // ...\n}\n```\n\n**After**\n\n```jsx title=\"app/my-page/index.jsx\"\n// Use this component in your stories\nimport MyPage from './components/MyPage';\n\nasync function getData() {\n  const res = await fetch(...);\n  // ...\n}\n\nexport default async function Page() {\n  const data = await getData();\n\n  return <MyPage {...data} />;\n}\n```\n\n### Statically imported images won't load\n\nMake sure you are treating image imports the same way you treat them when using `next/image` in normal development.\n\nBefore using this framework, image imports would import the raw path to the image (e.g. `'static/media/stories/assets/logo.svg'`). Now image imports work the \"Next.js way\", meaning that you now get an object when importing an image. For example:\n\n```jsonc\n// Image import object\n{\n  \"src\": \"static/media/stories/assets/logo.svg\",\n  \"height\": 48,\n  \"width\": 48,\n  \"blurDataURL\": \"static/media/stories/assets/logo.svg\"\n}\n```\n\nTherefore, if something in Storybook isn't showing the image properly, make sure you expect the object to be returned from an import instead of only the asset path.\n\nSee [local images](https://nextjs.org/docs/pages/building-your-application/optimizing/images#local-images) for more detail on how Next.js treats static image imports.\n\n### Module not found: Error: Can't resolve `package name`\n\nYou might get this if you're using Yarn v2 or v3. See [Notes for Yarn v2 and v3 users](#notes-for-yarn-v2-and-v3-users) for more details.\n\n### Should I use the Vite or Webpack version?\n\nWe recommend using [`@storybook/nextjs-vite`](./nextjs-vite.mdx) (Vite-based) for most projects because it offers faster builds, better test support, and a simpler configuration. However, if your project has custom Webpack configurations that are incompatible with Vite, use this framework instead.\n\n### Error: You are importing avif images, but you don't have sharp installed. You have to install sharp in order to use image optimization features in Next.js.\n\n`sharp` is a dependency of Next.js's image optimization feature. If you see this error, you need to install `sharp` in your project.\n\n```bash\nnpm install sharp\n```\n\n```bash\nyarn add sharp\n```\n\n```bash\npnpm add sharp\n```\n\nYou can refer to the [Install `sharp` to Use Built-In Image Optimization](https://nextjs.org/docs/messages/install-sharp) in the Next.js documentation for more information.\n\n## API\n\n### Modules\n\nThe `@storybook/nextjs` package exports several modules that enable you to [mock](#mocking-modules) Next.js's internal behavior.\n\n#### `@storybook/nextjs/export-mocks`\n\nType: `{ getPackageAliases: ({ useESM?: boolean }) => void }`\n\n`getPackageAliases` is a helper for generating the aliases needed to set up [portable stories](#portable-stories).\n\n```ts title=\"jest.config.ts\"\nimport type { Config } from 'jest';\nimport nextJest from 'next/jest.js';\n// 👇 Import the utility function\nimport { getPackageAliases } from '@storybook/nextjs/export-mocks';\n\nconst createJestConfig = nextJest({\n  // Provide the path to your Next.js app to load next.config.js and .env files in your test environment\n  dir: './',\n});\n\nconst config: Config = {\n  testEnvironment: 'jsdom',\n  // ... rest of Jest config\n  moduleNameMapper: {\n    ...getPackageAliases(), // 👈 Add the utility as mapped module names\n  },\n};\n\nexport default createJestConfig(config);\n```\n\n#### `@storybook/nextjs/cache.mock`\n\nType: `typeof import('next/cache')`\n\nThis module exports mocked implementations of the `next/cache` module's exports. You can use it to create your own mock implementations or assert on mock calls in a story's [play function](../../writing-stories/play-function.mdx).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-cache-mock.md\" />\n\n{/* prettier-ignore-end */}\n\n#### `@storybook/nextjs/headers.mock`\n\nType: [`cookies`](https://nextjs.org/docs/app/api-reference/functions/cookies#cookiessetname-value-options), [`headers`](https://nextjs.org/docs/app/api-reference/functions/headers) and [`draftMode`](https://nextjs.org/docs/app/api-reference/functions/draft-mode) from Next.js\n\nThis module exports *writable* mocked implementations of the `next/headers` module's exports. You can use it to set up cookies or headers that are read in your story, and to later assert that they have been called.\n\nNext.js's default [`headers()`](https://nextjs.org/docs/app/api-reference/functions/headers) export is read-only, but this module exposes methods allowing you to write to the headers:\n\n* **`headers().append(name: string, value: string)`**: Appends the value to the header if it exists already.\n* **`headers().delete(name: string)`**: Deletes the header\n* **`headers().set(name: string, value: string)`**: Sets the header to the value provided.\n\nFor cookies, you can use the existing API to write them. E.g., `cookies().set('firstName', 'Jane')`.\n\nBecause `headers()`, `cookies()` and their sub-functions are all mocks you can use any [mock utilities](https://vitest.dev/api/mock.html) in your stories, like `headers().getAll.mock.calls`.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-headers-mock.md\" />\n\n{/* prettier-ignore-end */}\n\n#### `@storybook/nextjs/navigation.mock`\n\nType: `typeof import('next/navigation') & getRouter: () => ReturnType<typeof import('next/navigation')['useRouter']>`\n\nThis module exports mocked implementations of the `next/navigation` module's exports. It also exports a `getRouter` function that returns a mocked version of [Next.js's `router` object from `useRouter`](https://nextjs.org/docs/app/api-reference/functions/use-router#userouter), allowing the properties to be manipulated and asserted on. You can use it mock implementations or assert on mock calls in a story's [play function](../../writing-stories/play-function.mdx).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-navigation-mock.md\" />\n\n{/* prettier-ignore-end */}\n\n#### `@storybook/nextjs/router.mock`\n\nType: `typeof import('next/router') & getRouter: () => ReturnType<typeof import('next/router')['useRouter']>`\n\nThis module exports mocked implementations of the `next/router` module's exports. It also exports a `getRouter` function that returns a mocked version of [Next.js's `router` object from `useRouter`](https://nextjs.org/docs/pages/api-reference/functions/use-router#router-object), allowing the properties to be manipulated and asserted on. You can use it mock implementations or assert on mock calls in a story's [play function](../../writing-stories/play-function.mdx).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"nextjs-router-mock.md\" />\n\n{/* prettier-ignore-end */}\n\n### Options\n\nYou can pass an options object for additional configuration if needed:\n\n<CodeSnippets path=\"nextjs-framework-options-next-config-path.md\" />\n\nThe available options are:\n\n#### `builder`\n\nType: `Record<string, any>`\n\nConfigure options for the [framework's builder](../../api/main-config/main-config-framework.mdx#optionsbuilder). For Next.js, available options can be found in the [Webpack builder docs](../../builders/webpack.mdx).\n\n#### `nextConfigPath`\n\nType: `string`\n\nThe absolute path to the `next.config.js` file. This is necessary if you have a custom `next.config.js` file that is not in the root directory of your project.\n\n### Parameters\n\nThis framework contributes the following [parameters](../../writing-stories/parameters.mdx) to Storybook, under the `nextjs` namespace:\n\n#### `image`\n\nType: `object`\n\nProps to pass to every instance of `next/image`. See [next/image docs](https://nextjs.org/docs/pages/api-reference/components/image) for more details.\n\n#### `appDirectory`\n\nType: `boolean`\n\nDefault: `false`\n\nIf your story imports components that use `next/navigation`, you need to set the parameter `nextjs.appDirectory` to `true`. Because this is a parameter, you can apply it to a [single story](../../api/parameters.mdx#story-parameters), [all stories for a component](../../api/parameters.mdx#meta-parameters), or [every story in your Storybook](../../api/parameters.mdx#project-parameters). See [Next.js Navigation](#nextjs-navigation) for more details.\n\n#### `navigation`\n\nType:\n\n```ts\n{\n  asPath?: string;\n  pathname?: string;\n  query?: Record<string, string>;\n  segments?: (string | [string, string])[];\n}\n```\n\nDefault value:\n\n```js\n{\n  segments: [];\n}\n```\n\nThe router object that is passed to the `next/navigation` context. See [Next.js's navigation docs](https://nextjs.org/docs/app/building-your-application/routing) for more details.\n\n#### `router`\n\nType:\n\n```ts\n{\n  asPath?: string;\n  pathname?: string;\n  query?: Record<string, string>;\n}\n```\n\nThe router object that is passed to the `next/router` context. See [Next.js's router docs](https://nextjs.org/docs/pages/building-your-application/routing) for more details.\n"
  },
  {
    "path": "docs/get-started/frameworks/preact-vite.mdx",
    "content": "---\ntitle: Storybook for Preact with Vite\nhideRendererSelector: true\nsidebar:\n  order: 4\n  title: Preact (Vite)\n---\n\nStorybook for Preact & Vite is a [framework](../../contribute/framework.mdx) that makes it easy to develop and test UI components in isolation for [Preact](https://preactjs.com/) applications built with [Vite](https://vitejs.dev/).\n\n## Install\n\nTo install Storybook in an existing Preact project, run this command in your project's root directory:\n\n<CodeSnippets path=\"create-command.md\" variant=\"new-users\" copyEvent=\"CreateCommandCopy\" />\n\nYou can then get started [writing stories](../whats-a-story.mdx), [running tests](../../writing-tests/index.mdx) and [documenting your components](../../writing-docs/index.mdx). For more control over the installation process, refer to the [installation guide](../install.mdx).\n\n### Requirements\n\n<GetStartedVersions versions={[{\n  name: 'Preact',\n  range: '8.x || 10.x',\n  icon: '/images/logos/renderers/logo-preact.svg'\n}, {\n  name: 'Vite',\n  range: '≥ 5',\n  icon: '/images/logos/builders/vite.svg'\n}]} />\n\n\n## Run Storybook\n\nTo run Storybook for a particular project, run the following:\n\n<CodeSnippets path=\"storybook-run-dev.md\" />\n\nTo build Storybook, run:\n\n<CodeSnippets path=\"build-storybook-production-mode.md\" />\n\nYou will find the output in the configured `outputDir` (default is `storybook-static`).\n\n## FAQ\n### How do I manually install the Preact framework?\n\nFirst, install the framework:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"preact-vite-install.md\" />\n\n{/* prettier-ignore-end */}\n\nThen, update your `.storybook/main.js|ts` to change the framework property:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"preact-vite-add-framework.md\" />\n\n{/* prettier-ignore-end */}\n\n## API\n\n### Options\n\nYou can pass an options object for additional configuration if needed:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"preact-vite-framework-options.md\" />\n\n{/* prettier-ignore-end */}\n\n#### `builder`\n\nType: `Record<string, any>`\n\nConfigure options for the [framework's builder](../../api/main-config/main-config-framework.mdx#optionsbuilder). For this framework, available options can be found in the [Vite builder docs](../../builders/vite.mdx).\n"
  },
  {
    "path": "docs/get-started/frameworks/react-native-web-vite.mdx",
    "content": "---\ntitle: Storybook for React Native Web\nhideRendererSelector: true\nsidebar:\n  order: 7\n  title: React Native Web\n---\n\nStorybook for React Native Web is a [framework](../../contribute/framework.mdx) that makes it easy to develop and test UI components in isolation for [React Native](https://reactnative.dev/). It uses [Vite](https://vitejs.dev/) to build your components for web browsers.\n\n<Callout variant=\"info\">\n  In addition to React Native Web, Storybook supports on-device [React Native](https://github.com/storybookjs/react-native) development. If you're unsure what's right for you, read our [comparison](#react-native-vs-react-native-web).\n</Callout>\n\n## Install\n\nTo install Storybook in an existing React Native project, run this command in your project's root directory:\n\n<CodeSnippets path=\"create-command.md\" variant=\"new-users\" copyEvent=\"CreateCommandCopy\" />\n\nYou can then get started [writing stories](../whats-a-story.mdx), [running tests](../../writing-tests/index.mdx) and [documenting your components](../../writing-docs/index.mdx). For more control over the installation process, refer to the [installation guide](../install.mdx).\n\n### Requirements\n\n<GetStartedVersions versions={[{\n  name: 'React Native',\n  range: '≥ 0.72',\n  icon: '/images/logos/renderers/logo-react.svg'\n}, {\n  name: 'React Native Web',\n  range: '≥ 0.19',\n  icon: '/images/logos/renderers/logo-react.svg'\n}, {\n  name: 'Vite',\n  range: '≥ 5',\n  icon: '/images/logos/builders/vite.svg'\n}]} />\n\n## Run Storybook\n\nTo run Storybook for a particular project, run the following:\n\n<CodeSnippets path=\"storybook-run-dev.md\" />\n\nTo build Storybook, run:\n\n<CodeSnippets path=\"build-storybook-production-mode.md\" />\n\nYou will find the output in the configured `outputDir` (default is `storybook-static`).\n\n## React Native vs React Native Web\n\nIf you’re building React Native (RN) components, Storybook has two options: Native and Web.\n\nBoth options provide a catalog of your stories that hot refreshes as you edit the code in your favorite editor. However, their implementations are quite different:\n\n- **Native** - Runs inside your React Native application. It’s high-fidelity but has a limited feature set.\n- **Web** - Displays your React Native components in the browser. It’s based on Storybook for Web, which is feature-rich and mature.\n\n{/* TODO: Don't forget about this image, otherwise remove it */}\n\n{/* [Image: native + web] */}\n\n### Comparison\n\nSo, which option is right for you?\n\n**Native.** You should choose this option if you want:\n\n- **Native features** - Your components rely on device-specific features like native modules. It runs in your actual application, in-simulator, or on-device and provides full fidelity. The web version uses `react-native-web`, which works for most components but has [limitations](https://necolas.github.io/react-native-web/docs/react-native-compatibility/).\n- **Mobile publication** - You want to share your Storybook on-device as part of a test build or embedded inside your application.\n\n**Web.** You should choose this option if you want:\n\n- [**Sharing**](../../sharing/publish-storybook.mdx) - Publish to the web and share with your team or publicly.\n- [**Documentation**](../../writing-docs/index.mdx) - Auto-generated component docs or rich markdown docs in MDX.\n- [**Testing**](../../writing-tests/index.mdx) - Component, visual, and a11y tests for your components.\n- [**Addons**](https://storybook.js.org/addons) - 500+ addons that improve development, documentation, testing, and integration with other tools.\n\n**Both.** It’s also possible to use both options together. This increases Storybook’s install footprint but is a good option if you want native fidelity in addition to all of the web features. Learn more below.\n\n### Using both React Native and React Native Web\n\nThe easiest way to use React Native and React Native Web is to select the **\"Both\"** option when installing Storybook. This will install and create configurations for both environments, allowing you to run Storybook for both in the same project.\n\nWhen you select \"Both\", the installation will:\n1. Install and configure React Native Storybook (on-device)\n2. Install and configure React Native Web Storybook (web-based)\n3. Set up both configurations in your project\n\nAfter installation, you'll see instructions for both environments:\n- React Native Storybook will require additional manual configuration steps (replacing app entry, wrapping metro config)\n- React Native Web Storybook can be started immediately using the `storybook` command\n\nHowever, you can install them separately if one version is installed. You can add a React Native Web Storybook alongside an existing React Native Storybook by running the install command and selecting \"React Native Web\" in the setup wizard, and vice versa.\n\n## FAQ\n\n### How do I migrate from the React Native Web addon?\n\nThe [React Native Web addon](https://github.com/storybookjs/addon-react-native-web) was a Webpack-based precursor to the React Native Web Vite framework (i.e., `@storybook/react-native-web-vite`). If you're using the addon, you should migrate to the framework, which is faster, more stable, maintained, and better documented. To do so, follow the steps below.\n\nRun the following command to upgrade Storybook to the latest version:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-upgrade.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  This framework is designed to work with Storybook 8.5 and above for the best experience. We won't be able to provide support if you're using an older Storybook version.\n</Callout>\n\nInstall the framework and its peer dependencies:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"react-native-web-vite-install.md\" />\n\n{/* prettier-ignore-end */}\n\nUpdate your `.storybook/main.js|ts` to change the framework property and remove the `@storybook/addon-react-native-web` addon:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"react-native-web-vite-add-framework.md\" />\n\n{/* prettier-ignore-end */}\n\nFinally, remove the addon and similar packages (i.e., `@storybook/react-webpack5` and `@storybook/addon-react-native-web`) from your project.\n\n## API\n\n### Options\n\nYou can pass an options object for additional configuration if needed:\n\n```ts title=\".storybook/main.ts\"\nimport type { StorybookConfig } from '@storybook/react-native-web-vite';\n\nconst config: StorybookConfig = {\n  framework: {\n    name: '@storybook/react-native-web-vite',\n    options: {\n      modulesToTranspile: ['my-library'], // add libraries that are not transpiled for web by default\n\n      // You should apply babel plugins and presets here for your project that you want to apply to your code\n      // for example put the reanimated preset here if you are using reanimated\n      // or the nativewind jsxImportSource for example\n      pluginReactOptions: {\n        jsxRuntime: 'automatic' | 'classic', // default: 'automatic'\n        jsxImportSource: string, // default: 'react'\n        babel:{\n          plugins: Array<string | [string, any]>,\n          presets: Array<string | [string, any]>,\n          // ... other compatible babel options\n        }\n        include: Array<string|RegExp>, \n        exclude: Array<string|RegExp>,\n        // ... other compatible @vitejs/plugin-react options\n      }\n    },\n  },\n};\n\nexport default config;\n```\n#### Example configuration for reanimated\n\n```ts title=\".storybook/main.ts\"\nconst config: StorybookConfig = {\n  // ... rest of config\n\n  framework: {\n    name: \"@storybook/react-native-web-vite\",\n    options: {\n      pluginReactOptions: {\n        babel: {\n          plugins: [\n            \"@babel/plugin-proposal-export-namespace-from\",\n            \"react-native-reanimated/plugin\",\n          ],\n        },\n      },\n    },\n  },\n\n  // ... rest of config\n}\n```\n\n#### Example configuration for nativewind\n\n```ts title=\".storybook/main.ts\"\n\nconst config: StorybookConfig = {\n  // ... rest of config\n\n  framework: {\n    name: \"@storybook/react-native-web-vite\",\n    options: {\n      pluginReactOptions: {\n        jsxImportSource: \"nativewind\",\n      },\n    },\n  },\n}\n```\n\n#### Example configuration to transpile additional node_modules\n\nLet's say you need to transpile a library called `my-library` that is not transpiled for web by default.\nYou can add it to the `modulesToTranspile` option.\n\n```ts title=\".storybook/main.ts\"\nconst config: StorybookConfig = {\n  // ... rest of config\n\n  framework: {\n    name: \"@storybook/react-native-web-vite\",\n    options: {\n      modulesToTranspile: ['my-library'],\n    },\n  },\n}\n```\n\n#### `builder`\n\nType: `Record<string, any>`\n\nConfigure options for the [framework's builder](../../api/main-config/main-config-framework.mdx#optionsbuilder). For this framework, available options can be found in the [Vite builder docs](../../builders/vite.mdx).\n"
  },
  {
    "path": "docs/get-started/frameworks/react-vite.mdx",
    "content": "---\ntitle: Storybook for React with Vite\nhideRendererSelector: true\nsidebar:\n  order: 5\n  title: React (Vite)\n---\n\nStorybook for React & Vite is a [framework](../../contribute/framework.mdx) that makes it easy to develop and test UI components in isolation for [React](https://react.dev/) applications built with [Vite](https://vitejs.dev/).\n\n## Install\n\nTo install Storybook in an existing React project, run this command in your project's root directory:\n\n<CodeSnippets path=\"create-command.md\" variant=\"new-users\" copyEvent=\"CreateCommandCopy\" />\n\nYou can then get started [writing stories](../whats-a-story.mdx), [running tests](../../writing-tests/index.mdx) and [documenting your components](../../writing-docs/index.mdx). For more control over the installation process, refer to the [installation guide](../install.mdx).\n\n### Requirements\n\n<GetStartedVersions versions={[{\n  name: 'React',\n  range: '≥ 16.8',\n  icon: '/images/logos/renderers/logo-react.svg'\n}, {\n  name: 'Vite',\n  range: '≥ 5',\n  icon: '/images/logos/builders/vite.svg'\n}]} />\n\n## Run Storybook\n\nTo run Storybook for a particular project, run the following:\n\n<CodeSnippets path=\"storybook-run-dev.md\" />\n\nTo build Storybook, run:\n\n<CodeSnippets path=\"build-storybook-production-mode.md\" />\n\nYou will find the output in the configured `outputDir` (default is `storybook-static`).\n\n## FAQ\n### How do I migrate from the React Webpack framework?\n\nThe `upgrade` command should prompt you to migrate to `@storybook/react-vite` when you run it:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-upgrade.md\" />\n\n{/* prettier-ignore-end */}\n\nIn case that auto-migration does not work for your project, refer to the manual installation instructions below.\n\n### How do I manually install the React framework?\n\nFirst, install the framework:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"react-vite-install.md\" />\n\n{/* prettier-ignore-end */}\n\nThen, update your `.storybook/main.js|ts` to change the framework property:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"react-vite-add-framework.md\" />\n\n{/* prettier-ignore-end */}\n\n## API\n\n### Options\n\nYou can pass an options object for additional configuration if needed:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"react-vite-framework-options.md\" />\n\n{/* prettier-ignore-end */}\n\n#### `builder`\n\nType: `Record<string, any>`\n\nConfigure options for the [framework's builder](../../api/main-config/main-config-framework.mdx#optionsbuilder). For this framework, available options can be found in the [Vite builder docs](../../builders/vite.mdx).\n"
  },
  {
    "path": "docs/get-started/frameworks/react-webpack5.mdx",
    "content": "---\ntitle: Storybook for React with Webpack\nhideRendererSelector: true\nsidebar:\n  order: 6\n  title: React (Webpack)\n---\n\nStorybook for React & Webpack is a [framework](../../contribute/framework.mdx) that makes it easy to develop and test UI components in isolation for [React](https://react.dev/) applications built with [Webpack](https://webpack.js.org/).\n\n<Callout variant=\"info\">\n\n**We recommend using [`@storybook/react-vite`](./react-vite.mdx)** for most React projects. The Vite-based framework is faster, more modern, and offers better support for testing features.\n\nUse this Webpack-based framework (`@storybook/react-webpack5`) only if you need specific Webpack features not available in Vite.\n</Callout>\n\n## Install\n\nTo install Storybook in an existing React project, run this command in your project's root directory:\n\n<CodeSnippets path=\"create-command.md\" variant=\"new-users\" copyEvent=\"CreateCommandCopy\" />\n\nYou can then get started [writing stories](../whats-a-story.mdx), [running tests](../../writing-tests/index.mdx) and [documenting your components](../../writing-docs/index.mdx). For more control over the installation process, refer to the [installation guide](../install.mdx).\n\n### Requirements\n\n<GetStartedVersions versions={[{\n  name: 'React',\n  range: '≥ 16.8',\n  icon: '/images/logos/renderers/logo-react.svg'\n}, {\n  name: 'Webpack',\n  range: '5',\n  icon: '/images/logos/builders/webpack.svg'\n}]} />\n\n## Run Storybook\n\nTo run Storybook for a particular project, run the following:\n\n<CodeSnippets path=\"storybook-run-dev.md\" />\n\nTo build Storybook, run:\n\n<CodeSnippets path=\"build-storybook-production-mode.md\" />\n\nYou will find the output in the configured `outputDir` (default is `storybook-static`).\n\n## Configure\n\n### Create React App (CRA)\n\nSupport for [Create React App](https://create-react-app.dev/) is handled by [`@storybook/preset-create-react-app`](https://github.com/storybookjs/presets/tree/master/packages/preset-create-react-app).\n\nThis preset enables support for all CRA features, including Sass/SCSS and TypeScript.\n\n### Manually initialized apps\n\nIf you're working on an app that was initialized manually (i.e., without the use of CRA), ensure that your app has [react-dom](https://www.npmjs.com/package/react-dom) included as a dependency. Failing to do so can lead to unforeseen issues with Storybook and your project.\n\n## FAQ\n\n### How do I manually install the React Webpack framework?\n\nFirst, install the framework:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"react-webpack5-install.md\" />\n\n{/* prettier-ignore-end */}\n\nNext, install and register your appropriate compiler addon, depending on whether you're using SWC (recommended) or Babel:\n\n<Callout variant=\"info\">\n  If your project is using [Create React App](#create-react-app-cra), you can skip this step.\n</Callout>\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-compiler-swc-auto-install.md\" />\n\n{/* prettier-ignore-end */}\n\nor\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-addon-compiler-babel-auto-install.md\" />\n\n{/* prettier-ignore-end */}\n\nMore details can be found in the [Webpack builder docs](../../builders/webpack.mdx#compiler-support).\n\nFinally, update your `.storybook/main.js|ts` to change the framework property:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"react-webpack5-add-framework.md\" />\n\n{/* prettier-ignore-end */}\n\n### How do I migrate to the React Vite framework?\n\nPlease refer to the [migration instructions for `@storybook/react-vite`](./react-vite.mdx#how-do-i-migrate-from-the-react-webpack-framework).\n\n## API\n\n### Options\n\nYou can pass an options object for additional configuration if needed:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"react-webpack5-framework-options.md\" />\n\n{/* prettier-ignore-end */}\n\n#### `builder`\n\nType: `Record<string, any>`\n\nConfigure options for the [framework's builder](../../api/main-config/main-config-framework.mdx#optionsbuilder). For this framework, available options can be found in the [Webpack builder docs](../../builders/webpack.mdx).\n"
  },
  {
    "path": "docs/get-started/frameworks/svelte-vite.mdx",
    "content": "---\ntitle: Storybook for Svelte with Vite\nhideRendererSelector: true\nsidebar:\n  order: 9\n  title: Svelte (Vite)\n---\n\nStorybook for Svelte & Vite is a [framework](../../contribute/framework.mdx) that makes it easy to develop and test UI components in isolation for applications using [Svelte](https://svelte.dev/) built with [Vite](https://vitejs.dev/).\n\n## Install\n\nTo install Storybook in an existing Svelte project, run this command in your project's root directory:\n\n<CodeSnippets path=\"create-command.md\" variant=\"new-users\" copyEvent=\"CreateCommandCopy\" />\n\nYou can then get started [writing stories](../whats-a-story.mdx), [running tests](../../writing-tests/index.mdx) and [documenting your components](../../writing-docs/index.mdx). For more control over the installation process, refer to the [installation guide](../install.mdx).\n\n### Requirements\n\n<GetStartedVersions versions={[{\n  name: 'Svelte',\n  range: '≥ 5',\n  icon: '/images/logos/renderers/logo-svelte.svg'\n}, {\n  name: 'Vite',\n  range: '≥ 5',\n  icon: '/images/logos/builders/vite.svg'\n}]} />\n\n## Run Storybook\n\nTo run Storybook for a particular project, run the following:\n\n<CodeSnippets path=\"storybook-run-dev.md\" />\n\nTo build Storybook, run:\n\n<CodeSnippets path=\"build-storybook-production-mode.md\" />\n\nYou will find the output in the configured `outputDir` (default is `storybook-static`).\n\n## Writing native Svelte stories\n\nStorybook provides a Svelte [addon](https://storybook.js.org/addons/@storybook/addon-svelte-csf) maintained by the community, enabling you to write stories for your Svelte components using the template syntax.\n\n<Callout variant=\"info\">\n  The community actively maintains the Svelte CSF addon but still lacks some features currently available in the official Storybook Svelte framework support. For more information, see the [addon's documentation](https://github.com/storybookjs/addon-svelte-csf).\n</Callout>\n\n### Setup\n\nIf you initialized your project with the Svelte framework, the addon has already been installed and configured for you. However, if you're [migrating](#automatic-migration) from a previous version, you'll need to take additional steps to enable this feature.\n\nRun the following command to install the addon.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"svelte-csf-addon-install.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n\n  The CLI's [`add`](../../api/cli-options.mdx#add) command automates the addon's installation and setup. To install it manually, see our [documentation](../../addons/install-addons.mdx#manual-installation) on how to install addons.\n\n</Callout>\n\nUpdate your Storybook configuration file (i.e., `.storybook/main.js|ts`) to enable support for this format.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-svelte-csf-register.md\" />\n\n{/* prettier-ignore-end */}\n\n### Configure\n\nBy default, the Svelte [addon](https://storybook.js.org/addons/@storybook/addon-svelte-csf) offers zero-config support for Storybook's Svelte framework. However, you can extend your Storybook configuration file (i.e., `.storybook/main.js|ts`) and provide additional addon options. Listed below are the available options and examples of how to use them.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"svelte-csf-addon-options.md\" />\n\n{/* prettier-ignore-end */}\n\n| Options          | Description |\n| ---------------- | ------------------------------------------------------------------------------------------------------------------ |\n| `legacyTemplate` | Enables support for the `Template` component for backward compatibility. <br/> `options: { legacyTemplate: true }` |\n\n<Callout variant=\"info\">\n\n  Enabling the `legacyTemplate` option can introduce a performance overhead and should be used cautiously. For more information, refer to the [addon's documentation](https://github.com/storybookjs/addon-svelte-csf/blob/next/README.md#legacy-api).\n\n</Callout>\n\n### Upgrade to Svelte CSF addon v5\n\nWith the Svelte 5 release, Storybook's Svelte CSF addon has been updated to support the new features. This guide will help you migrate to the latest version of the addon. Below is an overview of the major changes in version 5.0 and the steps needed to upgrade your project.\n\n#### Simplified story API\n\nIf you are using the `Meta` component or the `meta` named export to define the story's metadata (e.g., [parameters](../../writing-stories/parameters.mdx)), you'll need to update your stories to use the new `defineMeta` function. This function returns an object with the required information, including a `Story` component that you must use to define your component stories.\n\n{/* prettier-ignore-start */ }\n\n<CodeSnippets path=\"svelte-csf-story-migration.md\" />\n\n{/* prettier-ignore-end */}\n\n#### Story templates\n\nIf you used the `Template` component to control how the component renders in the Storybook, this feature was replaced with built-in children support in the `Story` component, enabling you to compose components and define the UI structure directly in the story.\n\n{/* prettier-ignore-start */ }\n\n<CodeSnippets path=\"svelte-csf-story-custom-children.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n\n  If you need support for the `Template` component, the addon provides a feature flag for backward compatibility. For more information, see the [configuration options](#configure).\n\n</Callout>\n\n#### Story slots to snippets\n\nWith Svelte's slot deprecation and the introduction of reusable [`snippets`](https://svelte.dev/docs/svelte/v5-migration-guide#Snippets-instead-of-slots), the addon also introduced support for this feature allowing you to extend the `Story` component and provide a custom snippet to provide dynamic content to your stories. `Story` accepts a `template` snippet, allowing you to create dynamic stories without losing reactivity.\n\n```svelte title=\"MyComponent.stories.svelte\"\n<script>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story name=\"Default\" args={{ exampleProperty: true }}>\n  {#snippet template(args)}\n    <MyComponent {...args}>Reactive component</MyComponent>\n  {/snippet}\n</Story>\n```\n\n#### Tags support\n\nIf you enabled automatic documentation generation with the `autodocs` story property, you must replace it with [`tags`](../../writing-stories/tags.mdx). This property allows you to categorize and filter stories based on specific criteria and generate documentation based on the tags applied to the stories.\n\n{/* prettier-ignore-start */ }\n\n<CodeSnippets path=\"svelte-csf-addon-tags.md\" />\n\n{/* prettier-ignore-end */}\n\n## FAQ \n### How do I manually install the Svelte framework?\n\nFirst, install the framework:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"svelte-vite-install.md\" />\n\n{/* prettier-ignore-end */}\n\nThen, update your `.storybook/main.js|ts` to change the framework property:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"svelte-vite-add-framework.md\" />\n\n{/* prettier-ignore-end */}\n\n## API\n\n### Options\n\nYou can pass an options object for additional configuration if needed:\n\n{/* prettier-ignore-start */ }\n\n<CodeSnippets path=\"svelte-vite-framework-options.md\" />\n\n{/* prettier-ignore-end */}\n\nThe available options are:\n\n#### `builder`\n\nType: `Record<string, any>`\n\nConfigure options for the [framework's builder](../../api/main-config/main-config-framework.mdx#optionsbuilder). For this framework, available options can be found in the [Vite builder docs](../../builders/vite.mdx).\n\n#### `docgen`\n\nType: `boolean`\n\nDefault: `true`\n\nEnables or disables automatic documentation generation for component properties. When disabled, Storybook will skip the docgen processing step during build, which can improve build performance.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"svelte-framework-options-docgen.md\" />\n\n{/* prettier-ignore-end */}\n\n#### When to disable docgen\n\nDisabling docgen can improve build performance for large projects, but [argTypes won't be inferred automatically](../../api/arg-types.mdx#automatic-argtype-inference), which will prevent features like [Controls](../../essentials/controls.mdx) and [docs](../../writing-docs/autodocs.mdx) from working as expected. To use those features, you will need to [define `argTypes` manually](../../api/arg-types.mdx#manually-specifying-argtypes).\n"
  },
  {
    "path": "docs/get-started/frameworks/sveltekit.mdx",
    "content": "---\ntitle: Storybook for SvelteKit\nhideRendererSelector: true\nsidebar:\n  order: 8\n  title: SvelteKit\n---\n\nStorybook for SvelteKit is a [framework](../../contribute/framework.mdx) that makes it easy to develop and test UI components in isolation for [SvelteKit](https://kit.svelte.dev/) applications.\n\n## Install\n\nTo install Storybook in an existing SvelteKit project, run this command in your project's root directory:\n\n<CodeSnippets path=\"create-command.md\" variant=\"new-users\" copyEvent=\"CreateCommandCopy\" />\n\nYou can then get started [writing stories](../whats-a-story.mdx), [running tests](../../writing-tests/index.mdx) and [documenting your components](../../writing-docs/index.mdx). For more control over the installation process, refer to the [installation guide](../install.mdx).\n\n### Requirements\n\n<GetStartedVersions versions={[{\n  name: 'SvelteKit',\n  range: '≥ 1.0',\n  icon: '/images/logos/renderers/logo-svelte.svg'\n}, {\n  name: 'Vite',\n  range: '≥ 5',\n  icon: '/images/logos/builders/vite.svg'\n}]} />\n\n## Run Storybook\n\nTo run Storybook for a particular project, run the following:\n\n<CodeSnippets path=\"storybook-run-dev.md\" />\n\nTo build Storybook, run:\n\n<CodeSnippets path=\"build-storybook-production-mode.md\" />\n\nYou will find the output in the configured `outputDir` (default is `storybook-static`).\n\n## Configure\n\nThis section covers SvelteKit support and configuration options.\n\n### Supported features\n\nAll Svelte language features are supported out of the box, as the Storybook framework uses the Svelte compiler directly.\nHowever, SvelteKit has some [Kit-specific modules](https://kit.svelte.dev/docs/modules) that aren't supported. Here's a breakdown of what will and will not work within Storybook:\n\n| Module                                                                             | Status                 | Note                                                                                                                                    |\n| ---------------------------------------------------------------------------------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |\n| [`$app/environment`](https://svelte.dev/docs/kit/$app-environment)                 | ✅ Supported           | `version` is always empty in Storybook.                                                                                                 |\n| [`$app/forms`](https://svelte.dev/docs/kit/$app-forms)                             | ⚠️ **Experimental**    | See [How to mock](#how-to-mock).                                                                                                        |\n| [`$app/navigation`](https://svelte.dev/docs/kit/$app-navigation)                   | ⚠️ **Experimental**    | See [How to mock](#how-to-mock).                                                                                                        |\n| [`$app/paths`](https://svelte.dev/docs/kit/$app-paths)                             | ✅ Supported           | Requires SvelteKit 1.4.0 or newer.                                                                                                      |\n| [`$app/state`](https://svelte.dev/docs/kit/$app-state)                             | ⚠️ **Experimental**    | Requires SvelteKit `v2.12` or newer. See [How to mock](#how-to-mock).                                                                   |\n| [`$app/stores`](https://svelte.dev/docs/kit/$app-stores)                           | ⚠️ **Experimental**    | See [How to mock](#how-to-mock).                                                                                                        |\n| [`$env/dynamic/public`](https://svelte.dev/docs/kit/$env-dynamic-public)           | 🚧 Partially supported | Only supported in development mode. Storybook is built as a static app with no server-side API, so it cannot dynamically serve content. |\n| [`$env/static/public`](https://svelte.dev/docs/kit/$env-static-public)             | ✅ Supported           |                                                                                                                                         |\n| [`$lib`](https://svelte.dev/docs/kit/$lib)                                         | ✅ Supported           |                                                                                                                                         |\n| [`@sveltejs/kit/*`](https://svelte.dev/docs/kit/@sveltejs-kit)                     | ✅ Supported           |                                                                                                                                         |\n| [`$env/dynamic/private`](https://svelte.dev/docs/kit/$env-dynamic-private)         | ⛔ Not supported       | This is a server-side feature, and Storybook renders all components on the client.                                                      |\n| [`$env/static/private`](https://svelte.dev/docs/kit/$env-static-private)           | ⛔ Not supported       | This is a server-side feature, and Storybook renders all components on the client.                                                      |\n| [`$service-worker`](https://svelte.dev/docs/kit/$service-worker)                   | ⛔ Not supported       | This is a service worker feature, which does not apply to Storybook.                                                                    |\n\n### How to mock\n\nTo mock a SvelteKit import you can define it within `parameters.sveltekit_experimental`:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"sveltekit-mock-features.md\" />\n\n{/* prettier-ignore-end */}\n\nThe [available parameters](#parameters) are documented in the API section, below.\n\n#### Mocking links\n\nThe default link-handling behavior (e.g., when clicking an `<a href=\"...\" />` element) is to log an action to the [Actions panel](../../essentials/actions.mdx).\n\nYou can override this by assigning an object to `parameters.sveltekit_experimental.hrefs`, where the keys are strings representing an href, and the values define your mock. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"sveltekit-mock-links.md\" />\n\n{/* prettier-ignore-end */}\n\nSee the [API reference](#hrefs) for more information.\n\n## Writing native Svelte stories\n\nStorybook provides a Svelte [addon](https://storybook.js.org/addons/@storybook/addon-svelte-csf) maintained by the community, enabling you to write stories for your Svelte components using the template syntax.\n\n<Callout variant=\"info\">\n    The community actively maintains the Svelte CSF addon but still lacks some features currently available in the official Storybook Svelte framework support. For more information, see the [addon's documentation](https://github.com/storybookjs/addon-svelte-csf).\n</Callout>\n\n### Setup\n\nIf you initialized your project with the Sveltekit framework, the addon has already been installed and configured for you. However, if you're [migrating](#automatic-migration) from a previous version, you'll need to take additional steps to enable this feature.\n\nRun the following command to install the addon.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"svelte-csf-addon-install.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n\n  The CLI's [`add`](../../api/cli-options.mdx#add) command automates the addon's installation and setup. To install it manually, see our [documentation](../../addons/install-addons.mdx#manual-installation) on how to install addons.\n\n</Callout>\n\nUpdate your Storybook configuration file (i.e., `.storybook/main.js|ts`) to enable support for this format.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-svelte-csf-register.md\" />\n\n{/* prettier-ignore-end */}\n\n### Configure\n\nBy default, the Svelte [addon](https://storybook.js.org/addons/@storybook/addon-svelte-csf) addon offers zero-config support for Storybook's SvelteKit framework. However, you can extend your Storybook configuration file (i.e., `.storybook/main.js|ts`) and provide additional addon options. Listed below are the available options and examples of how to use them.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"svelte-csf-addon-options.md\" />\n\n{/* prettier-ignore-end */}\n\n| Options          | Description |\n| ---------------- | ------------------------------------------------------------------------------------------------------------------ |\n| `legacyTemplate` | Enables support for the `Template` component for backward compatibility. <br/> `options: { legacyTemplate: true }` |\n\n<Callout variant=\"info\">\n\n  Enabling the `legacyTemplate` option can introduce a performance overhead and should be used cautiously. For more information, refer to the [addon's documentation](https://github.com/storybookjs/addon-svelte-csf/blob/next/README.md#legacy-api).\n\n</Callout>\n\n### Upgrade to Svelte CSF addon v5\n\nWith the Svelte 5 release, Storybook's Svelte CSF addon has been updated to support the new features. This guide will help you migrate to the latest version of the addon. Below is an overview of the major changes in version 5.0 and the steps needed to upgrade your project.\n\n#### Simplified story API\n\nIf you are using the `Meta` component or the `meta` named export to define the story's metadata (e.g., [parameters](../../writing-stories/parameters.mdx)), you'll need to update your stories to use the new `defineMeta` function. This function returns an object with the required information, including a `Story` component that you must use to define your component stories.\n\n{/* prettier-ignore-start */ }\n\n<CodeSnippets path=\"svelte-csf-story-migration.md\" />\n\n{/* prettier-ignore-end */}\n\n#### Story templates\n\nIf you used the `Template` component to control how the component renders in the Storybook, this feature was replaced with built-in children support in the `Story` component, enabling you to compose components and define the UI structure directly in the story.\n\n{/* prettier-ignore-start */ }\n\n<CodeSnippets path=\"svelte-csf-story-custom-children.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n\n  If you need support for the `Template` component, the addon provides a feature flag for backward compatibility. For more information, see the [configuration options](#configure).\n\n</Callout>\n\n#### Story slots to snippets\n\nWith Svelte's slot deprecation and the introduction of reusable [`snippets`](https://svelte.dev/docs/svelte/v5-migration-guide#Snippets-instead-of-slots), the addon also introduced support for this feature allowing you to extend the `Story` component and provide a custom snippet to provide dynamic content to your stories. `Story` accepts a `template` snippet, allowing you to create dynamic stories without losing reactivity.\n\n```svelte title=\"MyComponent.stories.svelte\"\n<script>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n\n  import MyComponent from './MyComponent.svelte';\n\n  const { Story } = defineMeta({\n    component: MyComponent,\n  });\n</script>\n\n<Story name=\"Default\" args={{ exampleProperty: true }}>\n  {#snippet template(args)}\n    <MyComponent {...args}>Reactive component</MyComponent>\n  {/snippet}\n</Story>\n```\n\n#### Tags support\n\nIf you enabled automatic documentation generation with the `autodocs` story property, you must replace it with [`tags`](../../writing-stories/tags.mdx). This property allows you to categorize and filter stories based on specific criteria and generate documentation based on the tags applied to the stories.\n\n{/* prettier-ignore-start */ }\n\n<CodeSnippets path=\"svelte-csf-addon-tags.md\" />\n\n{/* prettier-ignore-end */}\n\n## FAQ\n\n### How do I manually install the SvelteKit framework?\n\nFirst, install the framework:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"sveltekit-install.md\" />\n\n{/* prettier-ignore-end */}\n\nThen, update your `.storybook/main.js|ts` to change the framework property:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"sveltekit-add-framework.md\" />\n\n{/* prettier-ignore-end */}\n\nFinally, these packages are now either obsolete or part of `@storybook/sveltekit`, so you no longer need to depend on them directly. You can remove them (`npm uninstall`, `yarn remove`, `pnpm remove`) from your project:\n\n* `@storybook/svelte-vite`\n* `storybook-builder-vite`\n* `@storybook/builder-vite`\n\n## API\n\n### Parameters\n\nThis framework contributes the following [parameters](../../writing-stories/parameters.mdx) to Storybook, under the `sveltekit_experimental` namespace:\n\n#### `forms`\n\nType: `{ enhance: () => void }`\n\nProvides mocks for the [`$app/forms`](https://svelte.dev/docs/kit/$app-forms) module.\n\n##### `forms.enhance`\n\nType: `() => void`\n\nA callback that will be called when a form with [`use:enhance`](https://kit.svelte.dev/docs/form-actions#progressive-enhancement-use-enhance) is submitted.\n\n#### `hrefs`\n\nType: `Record<[path: string], (to: string, event: MouseEvent) => void | { callback: (to: string, event: MouseEvent) => void, asRegex?: boolean }>`\n\nIf you have an `<a />` tag inside your code with the `href` attribute that matches one or more of the links defined (treated as regex based if the `asRegex` property is `true`) the corresponding `callback` will be called. If no matching `hrefs` are defined, an action will be logged to the [Actions panel](../../essentials/actions.mdx). See [Mocking links](#mocking-links) for an example.\n\n#### `navigation`\n\nType: See [SvelteKit docs](https://svelte.dev/docs/kit/$app-navigation)\n\nProvides mocks for the [`$app/navigation`](https://svelte.dev/docs/kit/$app-navigation) module.\n\n##### `navigation.goto`\n\nType: See [SvelteKit docs](https://svelte.dev/docs/kit/$app-navigation#goto)\n\nA callback that will be called whenever [`goto`](https://svelte.dev/docs/kit/$app-navigation#goto) is called. If no function is provided, an action will be logged to the [Actions panel](../../essentials/actions.mdx).\n\n##### `navigation.pushState`\n\nType: See [SvelteKit docs](https://svelte.dev/docs/kit/$app-navigation#pushState)\n\nA callback that will be called whenever [`pushState`](https://svelte.dev/docs/kit/$app-navigation#pushState) is called. If no function is provided, an action will be logged to the [Actions panel](../../essentials/actions.mdx).\n\n##### `navigation.replaceState`\n\nType: See [SvelteKit docs](https://svelte.dev/docs/kit/$app-navigation#replaceState)\n\nA callback that will be called whenever [`replaceState`](https://svelte.dev/docs/kit/$app-navigation#replaceState) is called. If no function is provided, an action will be logged to the [Actions panel](../../essentials/actions.mdx).\n\n##### `navigation.invalidate`\n\nType: See [SvelteKit docs](https://svelte.dev/docs/kit/$app-navigation#invalidate)\n\nA callback that will be called whenever [`invalidate`](https://svelte.dev/docs/kit/$app-navigation#invalidate) is called. If no function is provided, an action will be logged to the [Actions panel](../../essentials/actions.mdx).\n\n##### `navigation.invalidateAll`\n\nType: See [SvelteKit docs](https://svelte.dev/docs/kit/$app-navigation#invalidateAll)\n\nA callback that will be called whenever [`invalidateAll`](https://svelte.dev/docs/kit/$app-navigation#invalidateAll) is called. If no function is provided, an action will be logged to the [Actions panel](../../essentials/actions.mdx).\n\n##### `navigation.afterNavigate`\n\nType: See [SvelteKit docs](https://svelte.dev/docs/kit/$app-navigation#afterNavigate)\n\nAn object that will be passed to the [`afterNavigate`](https://svelte.dev/docs/kit/$app-navigation#afterNavigate) function, which will be invoked when the `onMount` event fires.\n\n#### `stores`\n\nType: See [SvelteKit docs](https://svelte.dev/docs/kit/$app-stores)\n\nProvides mocks for the [`$app/stores`](https://svelte.dev/docs/kit/$app-stores) module.\n\n##### `stores.navigating`\n\nType: See [SvelteKit docs](https://svelte.dev/docs/kit/$app-stores#navigating)\n\nA partial version of the [`navigating`](https://svelte.dev/docs/kit/$app-stores#navigating) store.\n\n##### `stores.page`\n\nType: See [SvelteKit docs](https://svelte.dev/docs/kit/$app-stores#page)\n\nA partial version of the [`page`](https://svelte.dev/docs/kit/$app-stores#page) store.\n\n##### `stores.updated`\n\nType: boolean\n\nA boolean representing the value of [`updated`](https://svelte.dev/docs/kit/$app-stores#updated) (you can also access `updated.check()` which will be a no-op).\n\n#### `state`\n\nType: See [SvelteKit docs](https://svelte.dev/docs/kit/$app-state)\n\nProvides mocks for the [`$app/state`](https://svelte.dev/docs/kit/$app-state) module.\n\n##### `state.navigating`\n\nType: See [SvelteKit docs](https://svelte.dev/docs/kit/$app-state#navigating)\n\nA partial version of the [`navigating`](https://svelte.dev/docs/kit/$app-state#navigating) store.\n\n##### `state.page`\n\nType: See [SvelteKit docs](https://svelte.dev/docs/kit/$app-state#page)\n\nA partial version of the [`page`](https://svelte.dev/docs/kit/$app-state#page) store.\n\n##### `state.updated`\n\nType: `{ current: boolean }`\n\nAn object representing the current value of [`updated`](https://svelte.dev/docs/kit/$app-state#updated). You can also access `updated.check()`, which will be a no-op.\n\n### Options\n\nYou can pass an options object for additional configuration if needed:\n\n{/* prettier-ignore-start */ }\n\n<CodeSnippets path=\"sveltekit-framework-options.md\" />\n\n{/* prettier-ignore-end */}\n\nThe available options are:\n\n#### `builder`\n\nType: `Record<string, any>`\n\nConfigure options for the [framework's builder](../../api/main-config/main-config-framework.mdx#optionsbuilder). For Sveltekit, available options can be found in the [Vite builder docs](../../builders/vite.mdx).\n\n#### `docgen`\n\nType: `boolean`\n\nDefault: `true`\n\nEnables or disables automatic documentation generation for component properties. When disabled, Storybook will skip the docgen processing step during build, which can improve build performance.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"svelte-framework-options-docgen.md\" />\n\n{/* prettier-ignore-end */}\n\n#### When to disable docgen\n\nDisabling docgen can improve build performance for large projects, but [argTypes won't be inferred automatically](../../api/arg-types.mdx#automatic-argtype-inference), which will prevent features like [Controls](../../essentials/controls.mdx) and [docs](../../writing-docs/autodocs.mdx) from working as expected. To use those features, you will need to [define `argTypes` manually](../../api/arg-types.mdx#manually-specifying-argtypes).\n"
  },
  {
    "path": "docs/get-started/frameworks/vue3-vite.mdx",
    "content": "---\ntitle: Storybook for Vue with Vite\nhideRendererSelector: true\nsidebar:\n  order: 10\n  title: Vue (Vite)\n---\n\nStorybook for Vue & Vite is a [framework](../../contribute/framework.mdx) that makes it easy to develop and test UI components in isolation for [Vue](https://vuejs.org/) applications built with [Vite](https://vitejs.dev/).\n\n## Install\n\nTo install Storybook in an existing Vue project, run this command in your project's root directory:\n\n<CodeSnippets path=\"create-command.md\" variant=\"new-users\" copyEvent=\"CreateCommandCopy\" />\n\nYou can then get started [writing stories](../whats-a-story.mdx), [running tests](../../writing-tests/index.mdx) and [documenting your components](../../writing-docs/index.mdx). For more control over the installation process, refer to the [installation guide](../install.mdx).\n\n### Requirements\n\n<GetStartedVersions versions={[{\n  name: 'Vue',\n  range: '≥ 3',\n  icon: '/images/logos/renderers/logo-vue.svg'\n}, {\n  name: 'Vite',\n  range: '≥ 5',\n  icon: '/images/logos/builders/vite.svg'\n}]} />\n\n## Run Storybook\n\nTo run Storybook for a particular project, run the following:\n\n<CodeSnippets path=\"storybook-run-dev.md\" />\n\nTo build Storybook, run:\n\n<CodeSnippets path=\"build-storybook-production-mode.md\" />\n\nYou will find the output in the configured `outputDir` (default is `storybook-static`).\n\n## Configure\n\nStorybook for Vue 3 with Vite is designed to work out of the box with minimal configuration. This section covers configuration options for the framework.\n\n### Extending the Vue application\n\nStorybook creates a [Vue 3 application](https://vuejs.org/api/application.html#application-api) for your component preview. When using global custom components (`app.component`), directives (`app.directive`), extensions (`app.use`), or other application methods, you will need to configure those in the `./storybook/preview.js|ts` file.\n\nTherefore, Storybook provides you with a `setup` function exported from this package. This function receives your Storybook instance as a callback, which you can interact with and add your custom configuration.\n\n```js title=\".storybook/preview.js|ts\"\nimport { setup } from '@storybook/vue3-vite';\n\nsetup((app) => {\n  app.use(MyPlugin);\n  app.component('my-component', MyComponent);\n  app.mixin({\n    // My mixin\n  });\n});\n```\n\n### Using `vue-component-meta`\n\n<Callout variant=\"info\">\n  `vue-component-meta` is only available in Storybook ≥ 8. It is currently an opt-in, but it will become the default in a future version of Storybook.\n</Callout>\n\n[`vue-component-meta`](https://github.com/vuejs/language-tools/tree/master/packages/component-meta) is a tool maintained by the Vue team that extracts metadata from Vue components. Storybook can use it to generate the [controls](../../essentials/controls.mdx) for your stories and documentation. It's a more full-featured alternative to `vue-docgen-api` and is recommended for most projects.\n\nIf you want to use `vue-component-meta`, you can configure it in your `.storybook/main.js|ts` file:\n\n```ts title=\".storybook/main.ts\"\nimport type { StorybookConfig } from '@storybook/vue3-vite';\n\nconst config: StorybookConfig = {\n  framework: {\n    name: '@storybook/vue3-vite',\n    options: {\n      docgen: 'vue-component-meta',\n    },\n  },\n};\n\nexport default config;\n```\n\n`vue-component-meta` comes with many benefits and enables more documentation features, such as:\n\n#### Support for multiple component types\n\n`vue-component-meta` supports all types of Vue components (including SFC, functional, composition/options API components) from `.vue`, `.ts`, `.tsx`, `.js`, and `.jsx` files.\n\nIt also supports both default and named component exports.\n\n#### Prop description and JSDoc tag annotations\n\nTo describe a prop, including tags, you can use JSDoc comments in your component's props definition:\n\n```html title=\"YourComponent.vue\"\n<script setup lang=\"ts\">\n  interface MyComponentProps {\n    /** The name of the user */\n    name: string;\n    /**\n      * The category of the component\n      *\n      * @since 8.0.0\n      */\n    category?: string;\n  }\n\n  withDefaults(defineProps<MyComponentProps>(), {\n    category: 'Uncategorized',\n  });\n</script>\n```\n\nThe props definition above will generate the following controls:\n\n![Controls generated from props](../../_assets/get-started/vue-component-meta-prop-types-controls.png)\n\n#### Events types extraction\n\nTo provide a type for an emitted event, you can use TypeScript types (including JSDoc comments) in your component's `defineEmits` call:\n\n```html title=\"YourComponent.vue\"\n<script setup lang=\"ts\">\n  type MyChangeEvent = 'change';\n\n  interface MyEvents {\n    /** Fired when item is changed */\n    (event: MyChangeEvent, item?: Item): void;\n    /** Fired when item is deleted */\n    (event: 'delete', id: string): void;\n    /** Fired when item is upserted into list */\n    (e: 'upsert', id: string): void;\n  }\n\n  const emit = defineEmits<MyEvents>();\n</script>\n```\n\nWhich will generate the following controls:\n\n![Controls generated from events](../../_assets/get-started/vue-component-meta-event-types-controls.png)\n\n#### Slots types extraction\n\nThe slot types are automatically extracted from your component definition and displayed in the controls panel.\n\n```html title=\"YourComponent.vue\"\n<template>\n  <slot :num=\"123\"></slot>\n  <br />\n  <slot name=\"named\" str=\"str\"></slot>\n  <br />\n  <slot name=\"no-bind\"></slot>\n  <br />\n  <slot name=\"vbind\" v-bind=\"{ num: 123, str: 'str' }\"></slot>\n</template>\n\n<script setup lang=\"ts\"></script>\n```\n\nIf you use `defineSlots`, you can describe each slot using JSDoc comments in your component's slots definition:\n\n```ts\ndefineSlots<{\n  /** Example description for default */\n  default(props: { num: number }): any;\n  /** Example description for named */\n  named(props: { str: string }): any;\n  /** Example description for no-bind */\n  noBind(props: {}): any;\n  /** Example description for vbind */\n  vbind(props: { num: number; str: string }): any;\n}>();\n```\n\nThe definition above will generate the following controls:\n\n![Controls generated from slots](../../_assets/get-started/vue-component-meta-slot-types-controls.png)\n\n#### Exposed properties and methods\n\nThe properties and methods exposed by your component are automatically extracted and displayed in the [Controls](../../essentials/controls.mdx) panel.\n\n```html title=\"YourComponent.vue\"\n<script setup lang=\"ts\">\n  import { ref } from 'vue';\n\n  const label = ref('Button');\n  const count = ref(100);\n\n  defineExpose({\n    /** A label string */\n    label,\n    /** A count number */\n    count,\n  });\n</script>\n```\n\nThe definition above will generate the following controls:\n\n![Controls generated from exposed properties and methods](../../_assets/get-started/vue-component-meta-exposed-types-controls.png)\n\n#### Override the default configuration\n\nIf you're working with a project that relies on [`tsconfig references`](https://www.typescriptlang.org/docs/handbook/project-references.html) to link to other existing configuration files (e.g., `tsconfig.app.json`, `tsconfig.node.json`), we recommend that you update your [`.storybook/main.js|ts`](../../configure/index.mdx) configuration file and add the following:\n\n```ts title=\".storybook/main.ts\"\nimport type { StorybookConfig } from '@storybook/vue3-vite';\n\nconst config: StorybookConfig = {\n  framework: {\n    name: '@storybook/vue3-vite',\n    options: {\n      docgen: {\n        plugin: 'vue-component-meta',\n        tsconfig: 'tsconfig.app.json',\n      },\n    },\n  },\n};\n\nexport default config;\n```\n\n<Callout variant=\"info\">\n  This is not a limitation of Storybook, but how `vue-component-meta` works. For more information, refer to the appropriate [GitHub issue](https://github.com/vuejs/language-tools/issues/3896).\n</Callout>\n\nOtherwise, you might face missing component types/descriptions or unresolvable import aliases like `@/some/import`.\n\n## FAQ\n\n### How do I manually install the Vue framework?\n\nFirst, install the framework:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"vue3-vite-install.md\" />\n\n{/* prettier-ignore-end */}\n\nThen, update your `.storybook/main.js|ts` to change the framework property:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"vue3-vite-add-framework.md\" />\n\n{/* prettier-ignore-end */}\n\n### Storybook doesn't work with my Vue 2 project\n\n[Vue 2 entered End of Life](https://v2.vuejs.org/lts/) (EOL) on December 31st, 2023, and is no longer maintained by the Vue team. As a result, Storybook no longer supports Vue 2. We recommend you upgrade your project to Vue 3, which Storybook fully supports. If that's not an option, you can still use Storybook with Vue 2 by installing the latest version of Storybook 7 with the following command:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-init-v7.md\" />\n\n{/* prettier-ignore-end */}\n\n## API\n\n### Options\n\nYou can pass an options object for additional configuration if needed:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"vue-vite-framework-options.md\" />\n\n{/* prettier-ignore-end */}\n\n#### `builder`\n\nType: `Record<string, any>`\n\nConfigure options for the [framework's builder](../../api/main-config/main-config-framework.mdx#optionsbuilder). For this framework, available options can be found in the [Vite builder docs](../../builders/vite.mdx).\n\n#### `docgen`\n\nType: `'vue-docgen-api' | 'vue-component-meta' | boolean`\n\nDefault: `'vue-docgen-api'`\n\nSince: `8.0`\n\nChoose which docgen tool to use when generating controls for your components. See [Using `vue-component-meta`](#using-vue-component-meta) for more information.\n\nSet to `false` to disable docgen processing entirely for improved build performance.\n\n```ts title=\".storybook/main.ts\"\nimport type { StorybookConfig } from '@storybook/vue3-vite';\n\nconst config: StorybookConfig = {\n  framework: {\n    name: '@storybook/vue3-vite',\n    options: {\n      docgen: false, // Disable docgen for better performance\n    },\n  },\n};\n\nexport default config;\n```\n\n##### When to disable docgen\n\nDisabling docgen can improve build performance for large projects, but [argTypes won't be inferred automatically](../../api/arg-types.mdx#automatic-argtype-inference), which will prevent features like [Controls](../../essentials/controls.mdx) and [docs](../../writing-docs/autodocs.mdx) from working as expected. To use those features, you will need to [define `argTypes` manually](../../api/arg-types.mdx#manually-specifying-argtypes).\n"
  },
  {
    "path": "docs/get-started/frameworks/web-components-vite.mdx",
    "content": "---\ntitle: Storybook for Web components with Vite\nhideRendererSelector: true\nsidebar:\n  order: 11\n  title: Web components (Vite)\n---\n\nStorybook for Web components & Vite is a [framework](../../contribute/framework.mdx) that makes it easy to develop and test UI components in isolation for applications using [Web components](https://www.webcomponents.org/introduction) built with [Vite](https://vitejs.dev/).\n\n## Install\n\nTo install Storybook in an existing project, run this command in your project's root directory:\n\n<CodeSnippets path=\"create-command.md\" variant=\"new-users\" copyEvent=\"CreateCommandCopy\" />\n\nYou can then get started [writing stories](../whats-a-story.mdx), [running tests](../../writing-tests/index.mdx) and [documenting your components](../../writing-docs/index.mdx). For more control over the installation process, refer to the [installation guide](../install.mdx).\n\n### Requirements\n\n<GetStartedVersions versions={[{\n  name: 'Vite',\n  range: '≥ 5',\n  icon: '/images/logos/builders/vite.svg'\n}]} />\n\n## Run Storybook\n\nTo run Storybook for a particular project, run the following:\n\n<CodeSnippets path=\"storybook-run-dev.md\" />\n\nTo build Storybook, run:\n\n<CodeSnippets path=\"build-storybook-production-mode.md\" />\n\nYou will find the output in the configured `outputDir` (default is `storybook-static`).\n\n## FAQ\n### How do I manually install the Web Components framework?\n\nFirst, install the framework:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"web-components-vite-install.md\" />\n\n{/* prettier-ignore-end */}\n\nThen, update your `.storybook/main.js|ts` to change the framework property:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"web-components-vite-add-framework.md\" />\n\n{/* prettier-ignore-end */}\n\n## API\n\n### Options\n\nYou can pass an options object for additional configuration if needed:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"web-components-vite-framework-options.md\" />\n\n{/* prettier-ignore-end */}\n\nThe available options are:\n\n#### `builder`\n\nType: `Record<string, any>`\n\nConfigure options for the [framework's builder](../../api/main-config/main-config-framework.mdx#optionsbuilder). For this framework, available options can be found in the [Vite builder docs](../../builders/vite.mdx).\n"
  },
  {
    "path": "docs/get-started/index.mdx",
    "content": "---\ntitle: Get started with Storybook\nsidebar:\n  order: 1\n  title: Get Started\n---"
  },
  {
    "path": "docs/get-started/install.mdx",
    "content": "---\ntitle: Install Storybook\nsidebar:\n  order: 2\n  title: Install\n---\n\nUse the Storybook CLI to install it in a single command. Run this inside your project’s root directory:\n\n<CodeSnippets path=\"create-command.md\" variant=\"new-users\" copyEvent=\"CreateCommandCopy\" />\n\nStorybook will look into your project's dependencies during its install process and provide you with the best configuration available.\n\n<YouTubeCallout id=\"CtfU1UnizHU\" title=\"New Storybook\" style={{ marginTop: '1em' }} />\n\n## Project requirements\n\nStorybook is designed to work with a variety of frameworks and environments. If your project is using one of the packages listed here, please ensure that you have the following versions installed:\n\n<div style={{ columns: 2, marginBottom: '1.5rem' }}>\n- Angular 18+\n- Lit 3+\n- Next.js 14+\n- Node.js 20+\n- npm 10+\n- pnpm 9+\n- Preact 8+\n- React Native 0.72+\n- React Native Web 0.19+\n- Svelte 5+\n- SvelteKit 1+\n- TypeScript 4.9+\n- Vite 5+\n- Vitest 3+\n- Vue 3+\n- Webpack 5+\n- Yarn 4+\n</div>\n\nAdditionally, the Storybook app supports the following browsers:\n\n- Chrome 131+\n- Edge 134+\n- Firefox 136+\n- Safari 18.3+\n- Opera 117+\n\n<details>\n<summary>How do I use Storybook with older browsers?</summary>\n\nYou can use Storybook with older browsers in two ways:\n\n1. Use a version of Storybook prior to `9.0.0`, which will have less strict requirements.\n2. Develop or build your Storybook in [\"preview-only\" mode](../sharing/publish-storybook.mdx#build-storybook-for-older-browsers), which can be used in older, unsupported browsers.\n\n</details>\n\n## Installation\n\nRun this command inside your project's root directory to install the latest version of Storybook:\n\n<CodeSnippets path=\"create-command.md\" variant=\"new-users\" copyEvent=\"CreateCommandCopy\" />\n\n<details id=\"custom-storybook-version\">\n  <summary>Install a specific version</summary>\n\n  To install Storybook 8.3 or newer, you can use the `create` command with a specific version:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"create-command-custom-version.md\" />\n\n  {/* prettier-ignore-end */}\n\n  To install a Storybook version prior to 8.3, you must use the `init` command:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"init-command-custom-version.md\" />\n\n  {/* prettier-ignore-end */}\n\n  For either command, you can specify either an npm tag such as `latest` or `next`, or a (partial) version number. For example:\n\n  * `storybook@latest init` will initialize the latest version\n  * `storybook@7.6.10 init` will initialize `7.6.10`\n  * `storybook@7 init` will initialize the newest `7.x.x` version\n\n</details>\n\nWhen installing, Storybook will present you with a series of interactive prompts to help customize your installation:\n\n**New to Storybook?**\n\nStorybook will ask if you're new to Storybook. If you select \"Yes\":\n\n* You will be welcomed with an interactive tour\n* Example stories will be created to help you learn\n\nIf you're experienced with Storybook, you can skip the onboarding to get a minimal setup.\n\n**What configuration should we install?**\n\nStorybook will ask what type of configuration you want to install:\n\n* **Recommended**: Includes component development, [documentation](../writing-docs/autodocs.mdx), [testing](../writing-tests/integrations/vitest-addon/index.mdx), and [accessibility](../writing-tests/accessibility-testing.mdx) features\n* **Minimal**: Just the essentials for component development\n\nYou can also manually select these features using the `--features` flag. For example:\n\n```bash\nnpm create storybook@latest --features docs test a11y\n```\n\nAfter completing the prompts, the command above will make the following changes to your local environment:\n\n* 📦 Install the required dependencies.\n* 🛠 Set up the necessary scripts to run and build Storybook.\n* 🛠 Add the default Storybook configuration.\n* 📝 Add some boilerplate stories to get you started.\n* 📡 Set up telemetry to help us improve Storybook. Read more about it [here](../configure/telemetry.mdx).\n\n<IfRenderer renderer=\"react\">\n  ## Run the Setup Wizard\n\n  If all goes well, you should see a setup wizard that will help you get started with Storybook introducing you to the main concepts and features, including how the UI is organized, how to write your first story, and how to test your components' response to various inputs utilizing [controls](../essentials/controls.mdx).\n\n  ![Storybook onboarding](../_assets/get-started/example-onboarding-wizard.png)\n\n  If you skipped the wizard, you can always run it again by adding the `?path=/onboarding` query parameter to the URL of your Storybook instance, provided that the example stories are still available.\n</IfRenderer>\n\n## Start Storybook\n\nStorybook comes with a built-in development server featuring everything you need for project development. Depending on your system configuration, running the `storybook` command will start the local development server, output the address for you, and automatically open the address in a new browser tab where a welcome screen greets you.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-run-dev.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  Storybook collects completely anonymous data to help us improve user experience. Participation is optional, and you may [opt-out](../configure/telemetry.mdx#how-to-opt-out) if you'd not like to share any information.\n</Callout>\n\n![Storybook welcome screen](../_assets/get-started/example-welcome.png)\n\nThere are some noteworthy items here:\n\n* A collection of useful links for more in-depth configuration and customization options you have at your disposal.\n* A second set of links for you to expand your Storybook knowledge and get involved with the ever-growing Storybook community.\n* A few example stories to get you started.\n\n<details>\n  <summary><h3 id=\"troubleshooting\">Troubleshooting</h3></summary>\n  #### Run Storybook with other package managers\n\n  The Storybook CLI includes support for the industry's popular package managers (e.g., [Yarn](https://yarnpkg.com/), [npm](https://www.npmjs.com/), and [pnpm](https://pnpm.io/)) automatically detecting the one you are using when you initialize Storybook. However, if you want to use a specific package manager as the default, add the `--package-manager` flag to the installation command. For example:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"create-command-custom-package-manager.md\" />\n\n  {/* prettier-ignore-end */}\n\n  #### The CLI doesn't detect my framework\n\n  If auto‑detection fails or you’re using a custom setup, pass the project type explicitly with `--type` when running the initializer. The allowed values are:\n\n  | Type                          | Framework                          |\n  | ----------------------------- | ---------------------------------- |\n  | `angular`                     | Angular                            |\n  | `ember`                       | Ember                              |\n  | `html`                        | HTML                               |\n  | `nextjs`                      | Next.js                            |\n  | `nuxt`                        | Nuxt                               |\n  | `preact`                      | Preact                             |\n  | `qwik`                        | Qwik                               |\n  | `react`                       | React                              |\n  | `react_native`                | React Native                       |\n  | `react_native_web`            | React Native Web                   |\n  | `react_native_and_rnw`        | React Native (+ Web)               |\n  | `react_scripts`               | Create React App (react-scripts)   |\n  | `react_project`               | React Project                      |\n  | `server`                      | Server renderer                    |\n  | `solid`                       | Solid                              |\n  | `svelte`                      | Svelte                             |\n  | `sveltekit`                   | SvelteKit                          |\n  | `vue3`                        | Vue 3                              |\n  | `web_components`              | Web Components                     |\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"create-command-manual-framework.md\" />\n\n  {/* prettier-ignore-end */}\n\n  #### Yarn Plug'n'Play (PnP) support with Storybook\n\n  If you've enabled Storybook in a project running on a new version of Yarn with [Plug'n'Play](https://yarnpkg.com/features/pnp) (PnP) enabled, you may notice that it will generate `node_modules` with some additional files and folders. This is a known constraint as Storybook relies on some directories (e.g., `.cache`) to store cache files and other data to improve performance and faster builds. You can safely ignore these files and folders, adjusting your `.gitignore` file to exclude them from the version control you're using.\n\n  #### Run Storybook with Webpack 4\n\n  If you previously installed Storybook in a project that uses Webpack 4, it will no longer work. This is because Storybook now uses Webpack 5 by default. To solve this issue, we recommend you upgrade your project to Webpack 5 and then run the following command to migrate your project to the latest version of Storybook:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"storybook-automigrate.md\" />\n\n  {/* prettier-ignore-end */}\n\n  <If notRenderer=\"angular\">\n\n    #### Storybook doesn't work with an empty directory\n\n    By default, Storybook is configured to detect whether you're initializing it on an empty directory or an existing project. However, if you attempt to initialize Storybook, select a Vite-based framework (e.g., [React](./frameworks/react-vite.mdx)) in a directory that only contains a `package.json` file, you may run into issues with [Yarn Modern](https://yarnpkg.com/getting-started). This is due to how Yarn handles peer dependencies and how Storybook is set up to work with Vite-based frameworks, as it requires the [Vite](https://vitejs.dev/) package to be installed. To solve this issue, you must install Vite manually and initialize Storybook.\n\n  </If>\n\n  <IfRenderer renderer=\"angular\">\n    #### Storybook doesn't work with my Angular project using the Angular CLI\n\n    Out of the box, adding Storybook to an Angular project using the Angular CLI requires you to run the installation command from the root of the project or, if you're working with a monorepo environment, from the directory where the Angular configuration file (i.e., `angular.json`) is located as it will be used to set up the builder configuration necessary to run Storybook. However, if you need, you can extend the builder configuration to customize Storybook's behavior. To learn more about the available options, see the [Angular framework documentation](./frameworks/angular.mdx#how-do-i-configure-angulars-builder-for-storybook).\n  </IfRenderer>\n\n  <IfRenderer renderer=\"ember\">\n    #### The CLI doesn't support my Ember version\n\n    The Ember framework relies on an auxiliary package named [`@storybook/ember-cli-storybook`](https://www.npmjs.com/package/@storybook/ember-cli-storybook) to help you set up Storybook in your project. During the installation process you might run into the following warning message in your terminal:\n\n    ```shell\n    The ember generate entity-name command requires an entity name to be specified.\n    For more details, use ember help.\n    ```\n\n    It may be the case that you're using an outdated version of the package and you need to update it to the latest version to solve this issue.\n  </IfRenderer>\n\n  <IfRenderer renderer=\"vue\">\n    #### Storybook doesn't work with my Vue 2 project\n\n    Vue 2 entered [End of Life](https://v2.vuejs.org/lts/) (EOL) on December 31st, 2023, and is no longer maintained by the Vue team. As a result, Storybook no longer supports Vue 2. We recommend you upgrade your project to Vue 3, which Storybook fully supports. If that's not an option, you can still use Storybook with Vue 2 by installing the latest version of Storybook 7 with the following command:\n\n    {/* prettier-ignore-start */}\n\n    <CodeSnippets path=\"storybook-init-v7.md\" />\n\n    {/* prettier-ignore-end */}\n  </IfRenderer>\n\n  <IfRenderer renderer=\"svelte\">\n    #### Writing native Svelte stories\n\n    Storybook provides a Svelte [addon](https://storybook.js.org/addons/@storybook/addon-svelte-csf) maintained by the community, enabling you to write stories for your Svelte components using the template syntax. Starting with Storybook 8.2, the addon is automatically installed and configured when you initialize your project with the Svelte framework. However, if you installed a [specific version](#custom-storybook-version) of Storybook, you'll need to take additional steps to enable this feature.\n\n    Run the following command to install the addon.\n\n    {/* prettier-ignore-start */}\n\n    <CodeSnippets path=\"svelte-csf-addon-install.md\" />\n\n    {/* prettier-ignore-end */}\n\n    <Callout variant=\"info\">\n\n      The CLI's [`add`](../api/cli-options.mdx#add) command automates the addon's installation and setup. To install it manually, see our [documentation](../addons/install-addons.mdx#manual-installation) on how to install addons.\n\n    </Callout>\n\n    Update your Storybook configuration file (i.e., `.storybook/main.js|ts`) to enable support for this format.\n\n    {/* prettier-ignore-start */}\n\n    <CodeSnippets path=\"main-config-svelte-csf-register.md\" />\n\n    {/* prettier-ignore-end */}\n\n    <Callout variant=\"info\" style={{ marginBottom: \"2rem\" }}>\n      The community actively maintains the Svelte CSF addon but still lacks some features currently available in the official Storybook Svelte framework support. For more information, see the [addon's documentation](https://github.com/storybookjs/addon-svelte-csf).\n    </Callout>\n  </IfRenderer>\n\n  #### The installation process seems flaky and keeps failing\n\n  If you're still running into some issues during the installation process, we encourage you to check out the following resources:\n\n  <IfRenderer renderer=\"angular\">\n    * Storybook's Angular [framework documentation](./frameworks/angular.mdx) for more information on how to set up Storybook in your Angular project.\n    * [Storybook's help documentation](https://storybook.js.org/community#support) to contact the community and ask for help.\n  </IfRenderer>\n\n  <IfRenderer renderer=\"ember\">\n    * [Storybook's Ember README](https://github.com/storybookjs/storybook/tree/next/code/frameworks/ember) for more information on how to set up Storybook in your Ember project.\n    * [Storybook's help documentation](https://storybook.js.org/community#support) to contact the community and ask for help.\n  </IfRenderer>\n\n  <IfRenderer renderer=\"html\">\n    * [Storybook's HTML Vite README](https://github.com/storybookjs/storybook/tree/next/code/frameworks/html-vite) for more information on how to set up Storybook in your HTML project with Vite.\n    * [Storybook's help documentation](https://storybook.js.org/community#support) to contact the community and ask for help.\n  </IfRenderer>\n\n  <IfRenderer renderer=\"preact\">\n    * Storybook's Preact Vite [framework documentation](./frameworks/preact-vite.mdx) for more information on how to set up Storybook in your Preact project with Vite.\n    * [Storybook's help documentation](https://storybook.js.org/community#support) to contact the community and ask for help.\n  </IfRenderer>\n\n  <IfRenderer renderer=\"qwik\">\n    * [Storybook's Qwik README](https://github.com/literalpie/storybook-framework-qwik) for more information on how to set up Storybook in your Qwik project.\n    * [Storybook's help documentation](https://storybook.js.org/community#support) to contact the community and ask for help.\n  </IfRenderer>\n\n  <IfRenderer renderer=\"react\">\n    * Storybook's React Vite [framework documentation](./frameworks/react-vite.mdx) for more information on how to set up Storybook in your React project with Vite.\n    * Storybook's React Webpack [framework documentation](./frameworks/react-webpack5.mdx) for more information on how to set up Storybook in your React project with Webpack 5.\n    * [Storybook's help documentation](https://storybook.js.org/community#support) to contact the community and ask for help.\n  </IfRenderer>\n\n  <IfRenderer renderer=\"solid\">\n    * [Storybook's SolidJS README](https://github.com/solidjs-community/storybook) for more information on how to set up Storybook in your SolidJS project.\n    * [Storybook's help documentation](https://storybook.js.org/community#support) to contact the community and ask for help.\n  </IfRenderer>\n\n  <IfRenderer renderer=\"svelte\">\n    * Storybook's SvelteKit [framework documentation](./frameworks/sveltekit.mdx) for more information on how to set up Storybook in your SvelteKit project.\n    * Storybook's Svelte Vite [framework documentation](./frameworks/svelte-vite.mdx) for more information on how to set up Storybook in your Svelte project with Vite.\n    * [Storybook's help documentation](https://storybook.js.org/community#support) to contact the community and ask for help.\n  </IfRenderer>\n\n  <IfRenderer renderer=\"vue\">\n    * Storybook's Vue 3 Vite [framework documentation](./frameworks/vue3-vite.mdx) for more information on how to set up Storybook in your Vue 3 project with Vite.\n    * [Storybook's help documentation](https://storybook.js.org/community#support) to contact the community and ask for help.\n  </IfRenderer>\n\n  <IfRenderer renderer=\"web-components\">\n    * Storybook's Web Components Vite [framework documentation](./frameworks/web-components-vite.mdx) for more information on how to set up Storybook in your Web Components project with Vite.\n    * [Storybook's help documentation](https://storybook.js.org/community#support) to contact the community and ask for help.\n  </IfRenderer>\n</details>\n\n<IfRenderer renderer=\"react\">\n  Now that you have successfully installed Storybook and understood how it works, let's continue where you left off in the [setup wizard](#run-the-setup-wizard) and delve deeper into writing stories.\n</IfRenderer>\n\n<IfRenderer renderer={['angular', 'vue', 'web-components', 'ember', 'html', 'svelte', 'preact', 'qwik', 'solid' ]}>\n  Now that you installed Storybook successfully, let’s take a look at a story that was written for us.\n</IfRenderer>\n"
  },
  {
    "path": "docs/get-started/setup.mdx",
    "content": "---\ntitle: Setup Storybook\nsidebar:\n  order: 6\n  title: Setup\n---\n\nNow that you’ve learned what stories are and how to browse them, let’s demo working on one of your components.\n\nPick a simple component from your project, like a Button, and write a `.stories.js`, `.stories.ts`, or `.stories.svelte` file to go along with it. It might look something like this:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"your-component.md\" />\n\n{/* prettier-ignore-end */}\n\nGo to your Storybook to view the rendered component. It’s OK if it looks a bit unusual right now.\n\nDepending on your technology stack, you also might need to configure the Storybook environment further.\n\n## Render component styles\n\nStorybook isn’t opinionated about how you generate or load CSS. It renders whatever DOM elements you provide. But sometimes, things won’t “look right” out of the box.\n\nYou may have to configure your CSS tooling for Storybook’s rendering environment. Here are some setup guides for popular tools in the community.\n\n* [Tailwind](https://storybook.js.org/recipes/tailwindcss/)\n* [Material UI](https://storybook.js.org/recipes/@mui/material/)\n* [Vuetify](https://storybook.js.org/recipes/vuetify/)\n* [Styled Components](https://storybook.js.org/recipes/styled-components/)\n* [Emotion](https://storybook.js.org/recipes/@emotion/styled/)\n* [Sass](https://storybook.js.org/recipes/sass/)\n* [Bootstrap](https://storybook.js.org/recipes/bootstrap/)\n* [Less](https://storybook.js.org/recipes/less/)\n* [Vanilla-extract](https://storybook.js.org/recipes/@vanilla-extract/css/)\n\nDon't see the tool that you're looking for? Check out the [styling and css](../configure/styling-and-css.mdx) page for more details.\n\n## Configure Storybook for your stack\n\nStorybook comes with a permissive [default configuration](../configure/index.mdx). It attempts to customize itself to fit your setup. But it’s not foolproof.\n\nYour project may have additional requirements before components can be rendered in isolation. This warrants customizing configuration further. There are three broad categories of configuration you might need.\n\n<details>\n  <summary>Build configuration like Webpack and Babel</summary>\n\n  If you see errors on the CLI when you run the `yarn storybook` command, you likely need to make changes to Storybook’s build configuration. Here are some things to try:\n\n  * [Presets](../addons/addon-types.mdx) bundle common configurations for various technologies into Storybook. In particular, presets exist for Create React App and Ant Design.\n  * Specify a custom [Babel configuration](../configure/integration/compilers.mdx#babel) for Storybook. Storybook automatically tries to use your project’s config if it can.\n  * Adjust the [Webpack configuration](../builders/webpack.mdx) that Storybook uses. Try patching in your own configuration if needed.\n</details>\n\n<details>\n  <summary>Runtime configuration</summary>\n\n  If Storybook builds but you see an error immediately when connecting to it in the browser, in that case, chances are one of your input files is not compiling/transpiling correctly to be interpreted by the browser. Storybook supports evergreen browsers, but you may need to check the Babel and Webpack settings (see above) to ensure your component code works correctly.\n</details>\n\n<details id=\"component-context\" name=\"component-context\">\n  <summary>Component context</summary>\n\n  If a particular story has a problem rendering, often it means your component expects a specific environment is available to the component.\n\n  A common frontend pattern is for components to assume that they render in a specific “context” with parent components higher up the rendering hierarchy (for instance, theme providers).\n\n  Use [decorators](../writing-stories/decorators.mdx) to “wrap” every story in the necessary context providers. The [`.storybook/preview.js|ts`](../configure/index.mdx#configure-story-rendering) file allows you to customize how components render in Canvas, the preview iframe. See how you can wrap every component rendered in Storybook with [Styled Components](https://styled-components.com/) `ThemeProvider`, [Vue's Vuetify](https://vuetifyjs.com/en/), Svelte's [Bits UI](https://bits-ui.com/) `BitsConfig`, or with an Angular theme provider component in the example below.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"storybook-preview-with-styled-components-decorator.md\" />\n\n  {/* prettier-ignore-end */}\n</details>\n\n## Load assets and resources\n\nWe recommend serving external resources and assets requested in your components statically with Storybook. It ensures that assets are always available to your stories. Read our [documentation](../configure/integration/images-and-assets.mdx) to learn how to host static files with Storybook.\n"
  },
  {
    "path": "docs/get-started/whats-a-story.mdx",
    "content": "---\ntitle: What's a story?\nsidebar:\n  order: 4\n  title: What's a story?\n---\n\nA story captures the rendered state of a UI component. Developers write multiple stories per component that describe all the “interesting” states a component can support.\n\nWhen you installed Storybook, the CLI created example components that demonstrate the types of components you can build with Storybook: Button, Header, and Page.\n\n<If renderer=\"svelte\">\n\n  Each example component has a set of stories that show the states it supports. You can browse the stories in the UI and see the code behind them in files that end with `.stories.svelte`. Stories can be written in [Component Story Format](../api/csf/index.mdx) (CSF), an ES6 modules-based standard for writing component examples or using Svelte native template syntax, via a community-led project called [`Svelte CSF`](https://storybook.js.org/addons/@storybook/addon-svelte-csf).\n\n  Let’s start with the `Button` component. With Svelte, a story can be defined as an object using standard CSF or with a `Story` component using Svelte CSF. Here’s how to render `Button` in the “primary” state and export a story called `Primary` using both approaches.\n\n</If>\n\n<If notRenderer=\"svelte\">\n  \n  Each example component has a set of stories that show the states it supports. You can browse the stories in the UI and see the code behind them in files that end with `.stories.js|ts`. The stories are written in [Component Story Format](../api/csf/index.mdx) (CSF), an ES6 modules-based standard for writing component examples.\n\n  Let’s start with the `Button` component. A story is an object that describes how to render the component in question. Here’s how to render `Button` in the “primary” state and export a story called `Primary`.\n\n</If>\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-with-args.md\" />\n\n{/* prettier-ignore-end */}\n\n![Button story with args](../_assets/get-started/example-button-args.png)\n\nView the rendered `Button` by clicking on it in the Storybook sidebar. Note how the values specified in [`args`](../writing-stories/args.mdx) are used to render the component and match those represented in the [Controls](../essentials/controls.mdx) panel. Using `args` in your stories has additional benefits:\n\n* `Button`'s callbacks are logged into the [Actions](../essentials/actions.mdx) panel. Click to try it.\n* `Button`'s arguments are dynamically editable in the Controls panel. Adjust the controls.\n\n## Working with stories\n\nStorybook makes it easy to work on one component in one state (aka a story) at a time. When you edit a component's code or its stories, Storybook will instantly re-render in the browser. No need to refresh manually.\n\n### Create a new story\n\n<If renderer=\"react\">\n  If you're working on a component that does not yet have any stories, you can click the ➕ button in the sidebar to search for your component and have a basic story created for you.\n\n  <Video src=\"../_assets/get-started/new-component-story-from-plus-button-optimized.mp4\" />\n\n  You can also create a story file for your new story. We recommend copy/pasting an existing story file next to the component source file, then adjusting it for your component.\n</If>\n\n<If renderer=\"svelte\">\n\n  <Callout variant=\"info\">\n\n    This feature is not supported with the Svelte template syntax story format. To opt-in to this feature with Svelte, you must use Storybook's [Component Story Format](../api/csf/index.mdx).\n    \n  </Callout>\n  \n</If>\n\n<If notRenderer=\"react\">\n  If you're working on a component that does not yet have any stories, you can create a story file for your component with a new story. We recommend copy/pasting an existing story file next to the component source file, then adjusting it for your component.\n</If>\n\n<Video src=\"../_assets/get-started/new-component-story-in-code-optimized.mp4\" />\n\nIf you're working on a component that already has other stories, you can use the [Controls panel](../essentials/controls.mdx) to adjust the value of a control and then save those changes as a new story.\n\n<Video src=\"../_assets/get-started/new-story-from-controls-optimized.mp4\" />\n\nOr, if you prefer, edit the story file's code to add a new named export for your story:\n\n<Video src=\"../_assets/get-started/new-story-in-code-optimized.mp4\" />\n\n### Edit a story\n\nUsing the [Controls panel](../essentials/controls.mdx), update a control's value for a story. You can then save the changes to the story and the story file's code will be updated for you.\n\n<Video src=\"../_assets/get-started/edit-story-from-controls-optimized.mp4\" />\n\nOf course, you can always update the story's code directly too:\n\n<Video src=\"../_assets/get-started/edit-story-in-code-optimized.mp4\" />\n\nStories are also helpful for checking that UI continues to look correct as you make changes. The `Button` component has four stories that show it in different use cases. View those stories now to confirm that your change to `Primary` didn’t introduce unintentional bugs in the other stories.\n\n<Video src=\"../_assets/get-started/example-button-browse-stories-optimized.mp4\" />\n\nChecking component’s stories as you develop helps prevent accidental regressions. [Tools that integrate with Storybook can automate this](../writing-tests/index.mdx) for you.\n\nNow that we’ve seen the basic anatomy of a story let’s see how we use Storybook’s UI to develop stories.\n"
  },
  {
    "path": "docs/get-started/why-storybook.mdx",
    "content": "---\ntitle: Why Storybook?\nsidebar:\n  order: 1\n  title: Why Storybook?\n---\n\n## The problem\n\nThe web’s universality is pushing more complexity into the frontend. It began with responsive web design, which turned every user interface from one to 10, 100, 1000 different user interfaces. Over time, additional requirements piled on like devices, browsers, accessibility, performance, and async states.\n\nComponent-driven tools like React, Vue 3, and Angular help break down complex UIs into simple components but they’re not silver bullets. As frontends grow, the number of components swells. Mature projects can contain hundreds of components that yield thousands of discrete variations.\n\nTo complicate matters further, those UIs are painful to debug because they’re entangled in business logic, interactive states, and app context.\n\nThe breadth of modern frontends overwhelm existing workflows. Developers must consider countless UI variations, yet aren’t equipped to develop or organize them all. You end up in a situation where UIs are tougher to build, less satisfying to work on, and brittle.\n\n![UI multiverse](../_assets/get-started/multiverse.png)\n\n## The solution\n\n### Build UIs in isolation\n\nEvery piece of UI is now a [component](https://www.componentdriven.org/). The superpower of components is that you don't need to spin up the whole app just to see how they render. You can render a specific variation in isolation by passing in props, mocking data, or faking events.\n\nStorybook is packaged as a small, development-only, [workshop](https://bradfrost.com/blog/post/a-frontend-workshop-environment/) that lives alongside your app. It provides an isolated iframe to render components without interference from app business logic and context. That helps you focus development on each variation of a component, even the hard-to-reach edge cases.\n\n<Video src=\"../_assets/get-started/whats-a-story.mp4\" />\n\n### Capture UI variations as “stories”\n\nWhen developing a component variation in isolation, save it as a story. [Stories](../writing-stories/index.mdx) are a declarative syntax for supplying props and mock data to simulate component variations. Each component can have multiple stories. Each story allows you to demonstrate a specific variation of that component to verify appearance and behavior.\n\nYou write stories for granular UI component variation and then use those stories in development, testing, and documentation.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"histogram-story.md\" />\n\n{/* prettier-ignore-end */}\n\n### Storybook keeps track of every story\n\nStorybook is an interactive directory of your UI components and their stories. In the past, you'd have to spin up the app, navigate to a page, and contort the UI into the right state. This is a huge waste of time and bogs down frontend development. With Storybook, you can skip all those steps and jump straight to working on a UI component in a specific state.\n\n<Video src=\"../_assets/get-started/histogram-stories-optimized.mp4\" />\n\n<details>\n  <summary>Where does Storybook fit into my project?</summary>\n\n  Storybook is packaged as a small, development-only, [workshop](https://bradfrost.com/blog/post/a-frontend-workshop-environment/) that lives alongside your app. Install it by [running a command](../get-started/install.mdx).\n\n  During development, run it in a separate node process. If you’re working on UI in isolation, the only thing you’ll need to run is Storybook.\n</details>\n\n<details>\n  <summary>Does Storybook work with my favorite libraries?</summary>\n\n  Storybook aims to integrate with industry-standard tools and platforms to simplify setup. Thanks to our ambitious developer community, we’ve made significant progress. There are hundreds of [addons](https://storybook.js.org/addons/) and tutorials that walk through how to set up Storybook in all types of projects.\n\n  If you’re using a niche framework or a recently launched tool, we might not have an integration for it yet. Consider creating a [proof of concept](../addons/writing-addons.mdx) yourself first to lead the way for the rest of the community.\n</details>\n\n<details>\n  <summary>What’s the recommended Storybook workflow?</summary>\n\n  Every team is different and so is their workflow. Storybook is designed to be incrementally adoptable. Teams can gradually try features to see what works best for them.\n\n  Most community members choose a [Component-Driven](https://www.componentdriven.org/) workflow. UIs are developed in isolation from the “bottom up” starting with basic components then progressively combined to assemble pages.\n\n  1. Build each component in isolation and write stories for its variations.\n  2. Compose small components together to enable more complex functionality.\n  3. Assemble pages by combining composite components.\n  4. Integrate pages into your project by hooking up data and business logic.\n</details>\n\n## Benefits\n\nWhen you write stories for components, you get a bunch of additional benefits for free.\n\n**📝 Develop UIs that are more durable**\n\nIsolate components and pages and track their use cases as [stories](../writing-stories/index.mdx). Verify hard-to-reach edge cases of UI. Use addons to mock everything a component needs—context, API requests, device features, etc.\n\n**✅ Test UIs with less effort and no flakes**\n\nStories are a pragmatic, reproducible way of tracking UI states. Use them to spot-test the UI during development. Storybook offers built-in workflows for automated [Interaction](../writing-tests/interaction-testing.mdx), [Accessibility](../writing-tests/accessibility-testing.mdx), and [Visual](../writing-tests/visual-testing.mdx) testing. Or use stories as test cases by [importing them into other JavaScript testing tools](../writing-tests/integrations/stories-in-unit-tests.mdx).\n\n**📚 Document UI for your team to reuse**\n\nStorybook is the single source of truth for your UI. Stories index all your components and their various states, making it easy for your team to find and reuse existing UI patterns. Storybook also auto-generates [documentation](../writing-docs/index.mdx) from those stories.\n\n**📤 Share how the UI actually works**\n\nStories show how UIs actually work, not just a picture of how they're supposed to work. That keeps everyone aligned on what's currently in production. [Publish Storybook](../sharing/publish-storybook.mdx) to get sign-off from teammates. Or [embed](../sharing/embed.mdx) them in wikis, Markdown, and Figma to streamline collaboration.\n\n**🚦Automate UI workflows**\n\nStorybook is compatible with your continuous integration workflow. Add it as a CI step to automate user interface testing, review implementation with teammates, and get signoff from stakeholders.\n\n## Write stories once, reuse everywhere\n\nStorybook is powered by [Component Story Format](../api/csf/index.mdx), an open standard based on JavaScript ES6 modules. This enables stories to interoperate between development, testing, and design tools. Each story is exported as a JavaScript function enabling you to reuse it with other tools. No vendor lock-in.\n\nReuse stories with [Jest](https://jestjs.io/) or [Vitest](https://vitest.dev/) and [Testing Library](https://testing-library.com/) to verify interactions. Put them in [Chromatic](https://www.chromatic.com/?utm_source=storybook_website\\&utm_medium=link\\&utm_campaign=storybook) for visual testing. Audit story accessibility with [Axe](https://github.com/dequelabs/axe-core). Or test user flows with [Playwright](https://playwright.dev/) and [Cypress](https://www.cypress.io/). Reuse unlocks more workflows at no extra cost.\n\n***\n\nStorybook is purpose-built to help you develop complex UIs faster with greater durability and lower maintenance. It’s used by 100s of [leading companies](https://storybook.js.org/showcase) and thousands of [developers](https://github.com/storybookjs/storybook/).\n"
  },
  {
    "path": "docs/index.mdx",
    "content": "---\ntitle: Get started with Storybook\nhideRendererSelector: true\n---\n\nStorybook is a frontend workshop for building UI components and pages in isolation. It helps you develop and share hard-to-reach states and edge cases without needing to run your whole app. Thousands of teams use it for UI development, testing, and documentation. It's open source and free.\n\n## Install Storybook\n\nRun this command to install Storybook into an existing project or create a new one from scratch:\n\n<CodeSnippets path=\"create-command.md\" variant=\"new-users\" copyEvent=\"CreateCommandCopy\" />\n\nWant to know more about installing Storybook? Check out the [installation guide](./get-started/install.mdx).\n\n## Supported frameworks\n\n<HomeRenderers />\n\n## Community-maintained frameworks\n\nStorybook includes an active community that supports additional frameworks and libraries. These community-maintained frameworks are actively developed and maintained by community contributors.\n\n<CommunityRenderers />\n\n## Main concepts\n\nStorybook is a powerful tool that can help you with many aspects of your UI development workflow. Here are some of the main concepts to get you started.\n\n<HomeConcepts />\n\n## Additional resources\n\nOnce you've learned the basics, explore these other ways to get the most out of Storybook.\n\n<HomeResources />\n"
  },
  {
    "path": "docs/releases/features.mdx",
    "content": "---\ntitle: 'Features Lifecycle'\nsidebar:\n  order: 4\n  title: Feature Lifecycle\n---\n\nThis page explains how the Storybook team classifies features using four lifecycle labels: **Experimental**, **Preview**, **Stable**, and **Deprecated**.\n\nThese labels help users understand our level of commitment, the expected quality, likelihood of breaking changes, and anticipated timeline for each feature. By making this process transparent, we aim to support better adoption decisions and build trust in how Storybook evolves.\n\n### Experimental\n\nThis stage marks the beginning of a feature’s development, where we’re validating ideas and shaping direction. \n\nExperimental features are functional but still evolving, with room for iteration based on real-world use. They’re ideal for trying out in prototypes or early integrations, not yet something to build critical paths around. Each experimental feature comes with an [RFC](https://github.com/storybookjs/storybook/discussions/categories/rfc) where we share the initial idea and report progress. We strongly encourage feedback to help guide the next steps. \n\nDuring this stage, we’re committed to fully exploring the concept. As such, specific implementation details may change significantly before stabilization.\n\n### Preview\n\nPreview features are nearly production-ready and generally reliable, with documentation in place and most known issues addressed. They should be fully functional for at least one supported framework, but may still be incomplete or less polished in others. These features are suitable for use in real projects, and we encourage teams to adopt them and share feedback. \n\nWhile the feature is stable in direction, we may introduce minimal breaking changes in minor releases to address gaps or refine behavior. In those cases, we provide automigrations where possible to ease the transition. We aim to collect feedback and iterate for 1-2 minor releases before promoting to stable.\n\n### Stable\n\nStable features are fully supported and safe for production use across all projects. They are well-documented, thoroughly tested in all of our core frameworks, and follow [semantic versioning](https://semver.org). Users can expect long-term support, with any breaking changes reserved for major releases.\n\n### Deprecated\n\nDeprecated features are in the process of being phased out and will be removed in an upcoming major release. Users should begin migrating to supported alternatives as soon as possible. These features no longer receive active development or bug fixes, and their functionality may degrade over time. While they may still work, they should not be used for new development. \n\nTypically, a deprecated feature is removed within the next major release cycle (for example, if deprecated in 8.x, removal is expected in 9.0).\n"
  },
  {
    "path": "docs/releases/index.mdx",
    "content": "---\ntitle: 'How we release Storybook'\nsidebar:\n  order: 13\n  title: Releases\n---\n\nStorybook packages ([`storybook`](https://www.npmjs.com/package/storybook) and everything under the [`@storybook` organization](https://www.npmjs.com/org/storybook)) follow [Semantic Versioning](https://semver.org/) (semver). We have a structured release process to ensure stability, compatibility, and a smooth upgrade path for users. This page outlines our release channels, supported versions, and the cadence of major, minor, patch, and pre releases.\n\n## Release Channels\n\nWe publish releases on two channels. You can install a specific channel via npm tags:\n\n- **Stable channel** (`latest`): Installs the latest stable release.\n\n```bash\nnpm create storybook@latest\n```\n\n- **Pre-release channel** (`next`): Installs the latest [pre-release](#pre-release).\n\n```bash\nnpm create storybook@next\n```\n\n## Supported Versions\n\nWe actively maintain the latest major version of Storybook. Within the current major, we patch only the latest minor version. Most fixes and new work go into the next minor (or sometimes major) and are not backported. Critical security fixes may be backported more broadly based on severity:\n- Latest major: Receives all security fixes\n- Previous two majors: Receive security patches for **High or Critical [CVSS vulnerabilities](https://en.wikipedia.org/wiki/Common_Vulnerability_Scoring_System) only**\n- Older versions: No longer receive any patches\n\nFor example, if the latest version is `10.2.1`:\n\n- We support `10.x.x` versions and release `10.2.x` patch versions\n- Most fixes and new work will be released as `10.3.0-alpha.x` versions\n  - If the next release is a major version, it would be `11.0.0-alpha.x`\n- We will backport **High or Critical** security fixes to the latest minor of `9.x.x` and `8.x.x`\n- Versions `7.x.x` and older will not receive security patches\n\nFor compatibility with other libraries and tools in the JavaScript ecosystem, please refer to the [compatibility tracker](https://github.com/storybookjs/storybook/issues/23279).\n\n## Release Cycle\n\n#### Major Release\n\n**Cadence**: Roughly once per year\n\n**Channel**: Stable (`latest`)\n\nMajor releases introduce breaking changes and significant new features. We use major releases to keep up with ecosystem changes, evolve Storybook’s architecture and APIs, and make the tool faster, leaner, and easier to use. \n\nOnce we start working on a major release, we pause minor releases but continue to ship patch releases as needed. Major releases go through a sequence of [pre-releases](#pre-release)—`alpha`, `beta`, and `rc` (release candidate)—before landing in the stable channel. We aim to include automated migrations and provide [a comprehensive migration guide](../releases/migration-guide.mdx) when manual changes are necessary.\n\n<Callout variant=\"info\">\n  Storybook versions prior to 7 had a very different architecture. As a result, upgrading from v6 to newer versions can be more challenging. Starting in v7, we’ve focused heavily on smoother migrations. Upgrades from v7 to v8, and v8 to v9 (and beyond), should feel significantly easier thanks to automigrations and better tooling.\n</Callout>\n\n#### Minor Release\n\n**Cadence**: Roughly every 8 weeks\n\n**Channel**: Stable (`latest`)\n\nMinor releases deliver new features, enhancements, and non-breaking improvements. Each minor release may be preceded by an alpha [pre-release](#pre-release) (e.g. `x.y.0-alpha`).\n\n#### Patch Release\n\n**Cadence**: as needed (only for the current minor)\n\n**Channel**: Stable (`latest`)\n\nPatch releases include critical bug fixes and security updates. These are issued only for the current minor version and are not pre-released.\n\n#### Pre-release\n\n**Cadence**: Regularly\n\n**Channel**: Pre-release (`next`)\n\nPre-releases are created to gather early feedback and ensure stability before an official release. Minor version stable releases are preceded by pre-releases with an `alpha` tag (e.g. `x.y.0-alpha`), with no patch pre-releases. Major version stable releases are preceded by a fuller cycle of `alpha`, `beta`, and `rc` pre-releases before the final release.\n"
  },
  {
    "path": "docs/releases/migration-guide-from-older-version.mdx",
    "content": "---\ntitle: 'Migration guide from Storybook 8.x to 9.1'\nsidebar:\n  order: 2\n  title: Migrate from 8 to 9\n---\n\n[full-migration-notes]: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#from-version-8x-to-900\n\nStorybook 9 improves performance, compatibility, and stability. Its key features include:\n\n- 🔋 Storybook Test, a batteries-included testing tool in your Storybook\n- 🧪 Component testing\n- ♿️ Accessibility testing\n- 🛡️ Test coverage\n- 🪶 48% lighter bundle\n- ⚛️ React Native for device and web\n- 🏷️ Tags-based story organization\n\nThis guide is meant to help you **upgrade from Storybook 8.x to 9.1** successfully!\n\n<Callout variant=\"info\">\n  **Migrating from Storybook 6 or 7?**\n\n  We have prior migration guides for:\n\n  - [Storybook 7.x to 8.x](../../../release-8-6/docs/migration-guide/index.mdx)\n  - [Storybook 6.x to 8.x](../../../release-8-6/docs/migration-guide/from-older-version.mdx)\n</Callout>\n\n## Major breaking changes\n\nThe rest of this guide will help you upgrade successfully, either automatically or manually. But first, there are some [breaking changes][full-migration-notes] in Storybook 9. Here are the most impactful changes you should know about before you go further:\n\n* [Packages have been consolidated/removed](#package-structure-changes)\n* [Essential addons moved to core](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#essentials-addons-viewport-controls-interactions-and-actions-moved-to-core)\n* [Test addon renamed from `experimental-addon-test` to `addon-vitest`](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#experimental-test-addon-stabilized-and-renamed)\n* [`nextjs-vite` framework stabilized](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#nextjs-vite-builder-stabilized)\n* [Removed Webpack builder support for Preact, Vue, and Web Components in favor of Vite](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#dropped-webpack5-builder-support-in-favor-of-vite)\n* [Manager builder removed alias for `util`, `assert` and `process`](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#manager-builder-removed-alias-for-util-assert-and-process)\n* Ecosystem updates\n  * [Node 20+ is now required](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#nodejs--20)\n  * [Angular 18+ is now required](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#angular-require-v18-and-up)\n  * [Lit v3+ is now required](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#lit--require-v3-and-up)\n  * [Next.js 14+ is now required](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#nextjs-require-v14-and-up)\n  * [Svelte 5+ is now required](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#svelte-require-v5-and-up)\n  * [Vite 5+ is now required](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#vite-4)\n  * [Vitest 3+ is now required](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#vitest-addon-former-storybookexperimental-addon-test-vitest-20-support-is-dropped)\n  * [npm 10+ is now required](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#package-managers)\n  * [pnpm 9+ is now required](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#package-managers)\n  * [yarn 4+ is now required](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#package-managers)\n  * [TypeScript 4.9+ is now required](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#typescript--49)\n\nIf any of these changes apply to your project, please read through the linked migration notes before continuing.\n\nIf any of these new requirements or changes are blockers for your project, we recommend to continue using Storybook 8.x.\n\nYou may wish to read the [full migration notes][full-migration-notes] before migrating. Or you can run the upgrade command below and we’ll try to take care of everything for you!\n\n## Automatic upgrade\n\nTo upgrade your Storybook, run the [upgrade](./upgrading.mdx) command in the root of your repository:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-upgrade.md\" />\n\n{/* prettier-ignore-end */}\n\nThis will:\n\n1. Find all of the Storybook projects in your repository\n2. For each project\n   1. Determine that none of the [breaking changes](#major-breaking-changes) apply to your project\n      * If they do, you will receive instructions on how to resolve them before continuing\n   2. Upgrade your Storybook dependencies to the latest version\n   3. Run a collection of *automigrations*, which will:\n      * Check for common upgrade tasks\n      * Explain the necessary changes with links to more information\n      * Ask for approval, then perform the task automatically on your behalf\n\n## New projects\n\nTo add Storybook to a project that isn’t currently using Storybook:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"create-command.md\" copyEvent=\"CreateCommandCopy\" />\n\n{/* prettier-ignore-end */}\n\nThis will:\n\n1. Figure out which renderer (React, Vue, Angular, Web Components), builder (Webpack, Vite), or meta-framework (Next.js, SvelteKit) you’re using\n2. Install Storybook 9 and auto-configure it to mirror project settings\n\n## Troubleshooting\n\nThe automatic upgrade should get your Storybook into a working state. If you encounter an error running Storybook after upgrading, here’s what to do:\n\n1. Try running the [`doctor` command](../api/cli-options.mdx#doctor) to check for common issues (such as duplicate dependencies, incompatible addons, or mismatched versions) and see suggestions for fixing them.\n2. If you’re running `storybook` with the `dev` command, try using the `build` command instead. Sometimes `build` errors are more legible than `dev` errors!\n3. Check [the full migration notes][full-migration-notes], which contains an exhaustive list of noteworthy changes in Storybook 9. Many of these are already handled by automigrations when you upgrade, but not all are. It’s also possible that you’re experiencing a corner case that we’re not aware of.\n4. Search [Storybook issues on GitHub](https://github.com/storybookjs/storybook/issues). If you’re seeing a problem, there’s a good chance other people are too. If so, upvote the issue, try out any workarounds described in the comments, and comment back if you have useful info to contribute.\n5. If there’s no existing issue, you can [file one](https://github.com/storybookjs/storybook/issues/new/choose), ideally with a reproduction attached. We’ll be on top of Storybook 9 issues as we’re stabilizing the release.\n\nIf you prefer to debug yourself, here are a few useful things you can do to help narrow down the problem:\n\n1. Try removing all addons that are not in the `@storybook` npm namespace (make sure you don't remove the `storybook` package). Community addons that work well with 8.x might not yet be compatible with 9.x, and this is the fastest way to isolate that possibility. If you find an addon that needs to be upgraded to work with Storybook 9, please post an issue on the addon’s repository, or better yet, a pull request to upgrade it!\n2. Another debugging technique is to bisect to older prerelease versions of Storybook to figure out which release broke your Storybook. For example, assuming that the current prerelease of Storybook is `9.0.0-beta.56`, you could set the version to `9.0.0-alpha.0` in your `package.json` and reinstall to verify that it still works (`alpha.0` should be nearly identical to `8.6.x`). If it works, you could then try `9.0.0-beta.0`, then `9.0.0-beta.28` and so forth. Once you’ve isolated the bad release, read through its [CHANGELOG](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.prerelease.md) entry and perhaps there’s a change that jumps out as the culprit. If you find the problem, please submit an issue or pull request to the Storybook monorepo and we’ll do our best to take care of it quickly.\n\n## Package structure changes\n\nThe following packages are no longer published. Instead they have been consolidated into Storybook's core package, `storybook`. If a consolidated package had exports, those are available via the replacement path in the table below. See the [full migration notes](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#dropped-support-for-legacy-packages) for details.\n\n| Removal                         | Replacement             |\n| ------------------------------- | ----------------------- |\n| `@storybook/addon-actions`      | `storybook/actions`     |\n| `@storybook/addon-backgrounds`  | N/A                     |\n| `@storybook/addon-controls`     | N/A                     |\n| `@storybook/addon-highlight`    | `storybook/highlight`   |\n| `@storybook/addon-interactions` | N/A                     |\n| `@storybook/addon-measure`      | N/A                     |\n| `@storybook/addon-outline`      | N/A                     |\n| `@storybook/addon-toolbars`     | N/A                     |\n| `@storybook/addon-viewport`     | `storybook/viewport`    |\n| `@storybook/manager-api`        | `storybook/manager-api` |\n| `@storybook/preview-api`        | `storybook/preview-api` |\n| `@storybook/test`               | `storybook/test`        |\n| `@storybook/theming`            | `storybook/theming`     |\n\nThe following packages have been consolidated and moved into an internal path to indicate that they are now for internal usage only. They will continue to work in `9.x` releases, but will likely be removed in `10.0`. See the [full migration notes](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#dropped-support-for-legacy-packages) for details.\n\n| Deprecation                  | Replacement                           |\n| ---------------------------- | ------------------------------------- |\n| `@storybook/builder-manager` |\t`storybook/internal/builder-manager` |\n| `@storybook/channels`        |\t`storybook/internal/channels`        |\n| `@storybook/client-logger`   |\t`storybook/internal/client-logger`   |\n| `@storybook/components`      |\t`storybook/internal/components`      |\n| `@storybook/core-common`     |\t`storybook/internal/common`          |\n| `@storybook/core-events`     |\t`storybook/internal/core-events`     |\n| `@storybook/core-server`     |\t`storybook/internal/core-server`     |\n| `@storybook/csf-tools`       |\t`storybook/internal/csf-tools`       |\n| `@storybook/docs-tools`      |\t`storybook/internal/docs-tools`      |\n| `@storybook/manager`         |\t`storybook/internal/manager`         |\n| `@storybook/node-logger`     |\t`storybook/internal/node-logger`     |\n| `@storybook/preview`         |\t`storybook/internal/preview`         |\n| `@storybook/router`          |\t`storybook/internal/router`          |\n| `@storybook/telemetry`       |\t`storybook/internal/telemetry`       |\n| `@storybook/types`           |\t`storybook/internal/types`           |\n\nAddon authors may continue to use the internal packages, there is currently not yet any replacement.\n\n## Optional migrations\n\nIn addition to the automigrations and manual migrations above, there are also optional migrations that you should consider. These are features that we’ve deprecated in Storybook 9 (but remain backwards compatible), or best practices that should help you be more productive in the future.\n\n### `test-runner` to `addon-vitest`\n\n`addon-vitest` and the rest of the [Storybook Test experience](https://storybook.js.org/blog/storybook-test-sneak-peek/) is designed to supercede the `test-runner`. It's faster and provides a better experience for writing and running tests. If your project uses React, Vue, or Svelte and is built with Vite, you should consider migrating to `addon-vitest`, by following the [installation instructions](../writing-tests/integrations/vitest-addon/index.mdx#automatic-setup).\n\n### CSF 2 to CSF 3\n\nThere are [many good reasons](/blog/storybook-csf3-is-here/) to convert your stories from CSF 2 to CSF 3. We provide a codemod which, in most cases, should automatically make the code changes for you (make sure to update the glob to fit your files):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-migrate-csf-2-to-3.md\" />\n\n{/* prettier-ignore-end */}"
  },
  {
    "path": "docs/releases/migration-guide.mdx",
    "content": "---\ntitle: 'Migration guide for Storybook 10'\nsidebar:\n  order: 1\n  title: Migrate to Storybook 10\n---\n\n[full-migration-notes]: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#from-version-9x-to-1000\n\nStorybook 10 is a breaking maintenance release focused on ESM-only package distribution. Its main features include:\n\n- 💎 ESM-only to reduce install size\n- ↗️ CSF Next preview with better typesafety and autocompletion\n- 🏷 Improved tags-based filtering\n\nComing soon:\n\n- 🧪 Familiar and ergonomic CSF test functions (experimental)\n\nThis guide is meant to help you **upgrade from Storybook 9.x to 10** successfully!\n\n<Callout variant=\"info\">\n  **Migrating from a Storybook version prior to 9?**\n\n  You'll first need to [upgrade to Storybook 9](./migration-guide-from-older-version.mdx). Then you can return to this guide.\n</Callout>\n\n## Major breaking changes\n\nThe rest of this guide will help you upgrade successfully, either automatically or manually. But first, there are some [breaking changes][full-migration-notes] in Storybook 10. Here are the most impactful changes you should know about before you go further:\n\n* [Main configuration (`.storybook/main.js|ts`) and other presets must be valid ESM](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#the-storybookmain-file-and-other-presets-must-be-valid-esm)\n* Ecosystem updates\n  * [Node 20.19+ or 22.12+ is now required](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#nodejs-2019-or-2212-required)\n\nIf any of these changes apply to your project, please read through the linked migration notes before continuing.\n\nIf any of these new requirements or changes are blockers for your project, we recommend to continue using Storybook 8.x.\n\nYou may wish to read the [full migration notes][full-migration-notes] before migrating. Or you can run the upgrade command below and we’ll try to take care of everything for you!\n\n## Automatic upgrade\n\nTo upgrade your Storybook, run the [upgrade](./upgrading.mdx) command in the root of your repository:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-upgrade.md\" />\n\n{/* prettier-ignore-end */}\n\nThis will:\n\n1. Find all of the Storybook projects in your repository\n2. For each project\n   1. Determine that none of the [breaking changes](#major-breaking-changes) apply to your project\n      * If they do, you will receive instructions on how to resolve them before continuing\n   2. Upgrade your Storybook dependencies to the latest version\n   3. Run a collection of *automigrations*, which will:\n      * Check for common upgrade tasks\n      * Explain the necessary changes with links to more information\n      * Ask for approval, then perform the task automatically on your behalf\n\n## New projects\n\nTo add Storybook to a project that isn’t currently using Storybook:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"create-command.md\" copyEvent=\"CreateCommandCopy\" />\n\n{/* prettier-ignore-end */}\n\nThis will:\n\n1. Figure out which renderer (React, Vue, Angular, Web Components), builder (Webpack, Vite), or meta-framework (Next.js, SvelteKit) you’re using\n2. Install Storybook 10 and auto-configure it to mirror project settings\n\n## Troubleshooting\n\nThe automatic upgrade should get your Storybook into a working state. If you encounter an error running Storybook after upgrading, here’s what to do:\n\n1. Try running the [`doctor` command](../api/cli-options.mdx#doctor) to check for common issues (such as duplicate dependencies, incompatible addons, or mismatched versions) and see suggestions for fixing them.\n2. If you’re running `storybook` with the `dev` command, try using the `build` command instead. Sometimes `build` errors are more legible than `dev` errors!\n3. Check [the full migration notes][full-migration-notes], which contains an exhaustive list of noteworthy changes in Storybook 10. Many of these are already handled by automigrations when you upgrade, but not all are. It’s also possible that you’re experiencing a corner case that we’re not aware of.\n4. Search [Storybook issues on GitHub](https://github.com/storybookjs/storybook/issues). If you’re seeing a problem, there’s a good chance other people are too. If so, upvote the issue, try out any workarounds described in the comments, and comment back if you have useful info to contribute.\n5. If there’s no existing issue, you can [file one](https://github.com/storybookjs/storybook/issues/new/choose), ideally with a reproduction attached. We’ll be on top of Storybook 10 issues as we’re stabilizing the release.\n\nIf you prefer to debug yourself, here are a few useful things you can do to help narrow down the problem:\n\n1. Try removing all addons that are not in the `@storybook` npm namespace (make sure you don't remove the `storybook` package). Community addons that work well with 9.x might not yet be compatible with 10.x, and this is the fastest way to isolate that possibility. If you find an addon that needs to be upgraded to work with Storybook 10, please post an issue on the addon’s repository, or better yet, a pull request to upgrade it!\n2. Another debugging technique is to bisect to older prerelease versions of Storybook to figure out which release broke your Storybook. For example, assuming that the current prerelease of Storybook is `10.0.0-beta.56`, you could set the version to `10.0.0-alpha.0` in your `package.json` and reinstall to verify that it still works (`alpha.0` should be nearly identical to `9.1.x`). If it works, you could then try `10.0.0-beta.0`, then `10.0.0-beta.28` and so forth. Once you’ve isolated the bad release, read through its [CHANGELOG](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.prerelease.md) entry and perhaps there’s a change that jumps out as the culprit. If you find the problem, please submit an issue or pull request to the Storybook monorepo and we’ll do our best to take care of it quickly.\n\n## Optional migrations\n\nIn addition to the automigrations and manual migrations above, there are also optional migrations that you should consider. These are features that we’ve deprecated in Storybook 10 (but remain backwards compatible), or best practices that should help you be more productive in the future.\n\n### `test-runner` to `addon-vitest`\n\n`addon-vitest` and the rest of the [Storybook Test experience](https://storybook.js.org/blog/storybook-test-sneak-peek/) is designed to supercede the `test-runner`. It's faster and provides a better experience for writing and running tests. If your project uses React, Vue, or Svelte and is built with Vite, you should consider migrating to `addon-vitest`, by following the [installation instructions](../writing-tests/integrations/vitest-addon/index.mdx#automatic-setup).\n"
  },
  {
    "path": "docs/releases/roadmap.mdx",
    "content": "---\ntitle: 'Roadmap'\nhideRendererSelector: true\nsidebar:\n  order: 5\n  title: Roadmap\n---\n\nThe Storybook team maintains a [public roadmap](https://github.com/orgs/storybookjs/projects/20/views/1) in the form of a GitHub project. This page explains what's in the roadmap, how to interpret it, and how to contribute to it.\n\n## What's in the roadmap?\n\nEach card represents a Storybook project. The columns represent how larger changes make their way from idea to shipped feature. Projects typically start as an [Request for Comment (RFC)](./RFC.mdx), then evolve into a [tracking issue](https://github.com/storybookjs/storybook/issues?q=is%3Aissue++sort%3Aupdated-desc+label%3ATracking+) once the team has fully scoped what it entails. We ship a Storybook [minor version](https://semver.org/) every eight weeks, and a major version once per year, typically in Feb/Mar.\n\n### Candidates\n\nThese cards are ideas on our radar that we are considering for the current major release. For example, if `8.0` is the most recent major version, these would be ideas for `8.x` or `9.0`. The ideas in this column are the fuzziest and may come and go depending on our priorities.\n\n### Under consideration\n\nThese are projects being discussed for the next dev cycle. For example, if the most recent minor version is `8.1`, and we are currently working on `8.2`, the projects in this column would be under consideration for `8.3`. Unlike the candidates column, which can contain any idea, the projects under consideration must be documented with an [RFC](./RFC.mdx).\n\n### In progress\n\nThese are projects that we are currently working on. There are two kinds of projects in this column:\n\n1. **[Tracking issues](https://github.com/storybookjs/storybook/issues?q=is%3Aissue++sort%3Aupdated-desc+label%3ATracking+)**: Fully scoped projects expected to ship in the next minor release. For example, if the most recent minor is `8.1`, these should ship in `8.2`, eight weeks after `8.1`.\n2. **Other projects**: Community projects facilitated by the core team and side projects. These don't have an ETA but we will push to have them ready as part of the current major. For example, if `8.0` is the most recent major version, these should ship in `8.x` or `9.0`.\n\n### Done\n\nThese projects are completed, documented, and released. We follow a \"fixed time, variable scope\" policy for core projects, which means we scope a project into milestones to provide the most value to users as early as possible and cut scope if necessary to ship on time. If a feature has been scoped out of a project, we might try to fit it into a follow-up project, treat it as general maintenance work, or forget about it. Storybook is open source, so PR contributions are always welcome!\n\n## Frequently asked questions\n\n### When will project X be available?\n\nThis roadmap is an estimation, not a commitment. In general, every tracking issue \"in progress\" should be available in the next two months. Everything else on the board has a decent chance of getting into the next major release. For example, if `8.0` is the most recent major release, we will try to ship everything on the board as part of `8.x` or `9.0`. If we don't think a project is likely for the next major, we will kick it off the board.\n\n### What about issue Y or discussion Z?\n\nThe Storybook core team and our community members continuously contribute bug fix bugs and smaller product improvements. The projects here are larger chunks of work. In some cases they may close out certain issues, and when possible we will call those out in the RFC or project tracking issue.\n\n### How do I get something onto the board?\n\nIf there's a significant product improvement that you want to see, and there is currently an issue or an [RFC](./RFC.mdx) for it, upvote that issue/discussion, and comment on it with more information about your need or use case if it's not currently captured. If you don't see anything that's quite right, please feel free to [submit an RFC](https://github.com/storybookjs/storybook/discussions/new?category=rfc). We prioritize based on a combination of user/contributor interest (upvotes, comments, [Discord](https://discord.gg/storybook) conversations, etc.) and our own strategic ambitions for the project.\n"
  },
  {
    "path": "docs/releases/upgrading.mdx",
    "content": "---\ntitle: 'Upgrading Storybook'\nsidebar:\n  order: 3\n  title: Upgrading\n---\n\nThe frontend ecosystem is a fast-moving place. Regular dependency upgrades are a way of life, whether upgrading a framework, library, tooling, or all of the above! Storybook provides a few resources to help ease the pain of upgrading.\n\n## Upgrade script\n\nThe most common upgrade is Storybook itself. [Storybook releases](https://storybook.js.org/releases) follow [Semantic Versioning](https://semver.org/). We publish patch releases with bug fixes continuously, minor versions of Storybook with new features every few months, and major versions of Storybook with breaking changes roughly once per year.\n\nTo help ease the pain of keeping Storybook up-to-date, we provide a command-line script that automatically detects all Storybook projects in your repository:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-upgrade.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  **Important:** Always run the upgrade command from your repository root. The script will automatically detect all Storybook projects in your repository, including in mono-repository setups.\n</Callout>\n\nThe `upgrade` command will use whichever version you specify. For example:\n\n* `storybook@latest upgrade` will upgrade to the latest version\n* `storybook@8.6.1 upgrade` will upgrade to `8.6.1`\n* `storybook@9 upgrade` will upgrade to the newest `9.x.x` version\n\n<Callout variant=\"warning\">\n  The `upgrade` command is designed to upgrade from one major version to the next.\n\n  - ✅ OK: Using Storybook 8 and running `storybook@9 upgrade`\n  - ❌ Not OK: Using Storybook 7 and running `storybook@9 upgrade`\n\n  If you want to upgrade across more than major version, run the command multiple times. For example, to upgrade from Storybook 7 to Storybook 9, you first need to upgrade to the latest version of Storybook 8 with `storybook@8 upgrade`, and then run `storybook@9 upgrade` to upgrade to the latest version of Storybook 9.\n\n  The only exception to this is when upgrading from 6 to 8, where you can run `storybook@8 upgrade` directly to upgrade from 6.x.x to 8.x.x.\n</Callout>\n\n### Mono-repository support\n\nThe upgrade script provides enhanced support for mono-repositories:\n\n- **Automatic detection**: The script automatically detects all Storybook projects in your repository\n- **Selective upgrades**: If your Storybooks are truly encapsulated (meaning each Storybook project has its own independent Storybook dependencies in its own `package.json`), you can select which Storybook project to upgrade\n- **Bulk upgrades**: If your Storybooks share dependencies, all detected projects will be upgraded together to ensure consistency\n\n#### Limiting scope in large mono-repositories\n\nFor large mono-repositories where you want to limit the upgrade to a specific directory, use the `STORYBOOK_PROJECT_ROOT` environment variable:\n\n```bash\nSTORYBOOK_PROJECT_ROOT=./packages/frontend storybook@latest upgrade\n```\n\nThis is especially helpful in huge mono-repositories with semi-encapsulated Storybooks.\n\n\n## Upgrade process\n\nAfter running the command, the script will:\n\n* Detect all Storybook projects in your repository\n* Upgrade all Storybook packages to the specified version\n* Run the relevant [automigrations](../releases/migration-guide.mdx#automatic-upgrade) factoring in the [breaking changes](../releases/migration-guide.mdx#major-breaking-changes) between your current version and the specified version\n* Automatically run the [doctor command](#automatic-health-check) to verify the upgrade\n\n<Callout variant=\"info\">\n  In addition to running the command, we also recommend checking the [MIGRATION.md file](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md), for the detailed log of relevant changes and deprecations that might affect your upgrade.\n</Callout>\n\n### Automatic health check\n\nThe upgrade script automatically runs a health check on all detected Storybook projects after the upgrade. This verifies that the upgrade was completed successfully and checks for common issues that might arise after an upgrade, such as duplicated dependencies, incompatible addons, or mismatched versions.\n\nThe health check runs automatically for all detected Storybooks. You can also run it manually at any time using the `storybook doctor` command:\n\n<CodeSnippets path=\"storybook-doctor.md\" />\n\n### Error handling and debugging\n\nIf you encounter issues during the upgrade:\n\n1. A `debug-storybook.log` file will be created in the repository root containing all relevant logs\n2. For more detailed information, set the log level to `debug` using the `--loglevel debug` flag\n3. Create a GitHub issue with the logs if you need help resolving the problem\n\n## Command-line options\n\nThe upgrade command supports several flags to customize the upgrade process:\n\n```bash\nstorybook@latest upgrade [options]\n```\n\n### Available flags\n\n| Flag                             | Description                                                                                |\n| -------------------------------- | ------------------------------------------------------------------------------------------ |\n| `-c, --config-dir <dir-name...>` | Directory or directories to find Storybook configurations                                  |\n| `--debug`                        | Enable more logs for debugging (default: false)                                            |\n| `--disable-telemetry`            | Disable sending telemetry data                                                             |\n| `--enable-crash-reports`         | Enable sending crash reports to telemetry data                                             |\n| `-f, --force`                    | Force the upgrade, skipping autoblockers                                                   |\n| `--loglevel <level>`             | Define log level: `debug`, `error`, `info`, `silent`, `trace`, or `warn` (default: `info`) |\n| `--package-manager <manager>`    | Force package manager: `npm`, `pnpm`, `yarn1`, `yarn2`, or `bun`                           |\n| `-s, --skip-check`               | Skip postinstall version and automigration checks                                          |\n| `--logfile [path]`               | Write all debug logs to the specified file at the end of the run. Defaults to debug-storybook.log when [path] is not provided.                                    |\n| `-y, --yes`                      | Skip prompting the user                                                                    |\n\n### Example usage\n\n```bash\n# Upgrade with logging for debugging\nstorybook@latest upgrade --loglevel debug --logfile debug-storybook.log\n\n# Force upgrade without prompts\nstorybook@latest upgrade --force --yes\n\n# Upgrade specific config directories only\nstorybook@latest upgrade --config-dir .storybook-app .storybook-ui\n```\n\n## Automigrate script\n\nStorybook upgrades are not the only thing to consider: changes in the ecosystem also present challenges. For example well-known frontend frameworks, such as [Angular](https://update.angular.io/?l=2\\&v=16.0-17.0), [Next.js](https://nextjs.org/docs/pages/building-your-application/upgrading) or [Svelte](https://svelte.dev/docs/v4-migration-guide) have been rolling out significant changes to their ecosystem, so even if you don't upgrade your Storybook version, you might need to update your configuration accordingly. That's what Automigrate is for:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-automigrate.md\" />\n\n{/* prettier-ignore-end */}\n\nIt runs a set of standard configuration checks, explains what is potentially out-of-date, and offers to fix it for you automatically. It also points to the relevant documentation so you can learn more. It runs automatically as part of [`storybook upgrade`](#upgrade-script) command, but it's also available on its own if you don't want to upgrade Storybook.\n\n## Prereleases\n\nIn addition to the above, Storybook is under constant development, and we publish pre-release versions almost daily. Pre-releases are the best way to try out new features before they are generally available, and we do our best to keep them as stable as possible, although this is not always possible.\n\nTo upgrade to the latest pre-release:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-upgrade-prerelease.md\" />\n\n{/* prettier-ignore-end */}\n\nThe `upgrade` command will use whichever version you specify. For example:\n\n* `storybook@next upgrade` will upgrade to the newest pre-release version\n* `storybook@8.0.0-beta.1 upgrade` will upgrade to `8.0.0-beta.1`\n* `storybook@8 upgrade` will upgrade to the newest `8.x` version\n\nIf you'd like to downgrade to a stable version, manually edit the package version numbers in your `package.json` and re-install.\n\n<Callout variant=\"info\">\n  Storybook collects completely anonymous data to help us improve user experience. Participation is optional, and you may [opt-out](../configure/telemetry.mdx#how-to-opt-out) if you'd not like to share any information.\n</Callout>\n\n\n## Troubleshooting\n\n### Storybook doesn't detect my Storybook project\n\nBy default, the upgrade script will attempt to find Storybook configuration in `.storybook` directories in your repository. If your Storybook configuration is located in a different directory, you can specify it using the `--config-dir` flag.\n\nThe `--config-dir` flag can accept multiple directories.\n\n```bash\nstorybook@latest upgrade --config-dir .storybook-app .storybook-ui\n```\n\nIf your project can be detected, but you get an error during the detection process, please check the `debug-storybook.log` file in the root of your repository. It will contain the full output of the detection process and will help you troubleshoot the issue.\n\n### Storybook doesn't automigrate non-Storybook files\n\nOur automigrations usually only transform and migrate files inside of your `.storybook` directory and your story and mdx files, which are mentioned as part of the Storybook configuration.\n\nIf you have other files that contain Storybook-specific code, you might need to manually migrate them.\n\n<IfRenderer renderer=\"vue\">\n\n  ### Storybook doesn't upgrade to the latest version when using Vue 2\n\n  If you're attempting to upgrade Storybook to the latest version in your existing Vue 2 project, you will no longer be able to. This is because Vue 2 entered [End of Life](https://v2.vuejs.org/lts/) (EOL) on December 31st, 2023, and will no longer receive any updates from the Vue team. We recommend you upgrade your Vue 2 project to Vue 3 and then upgrade Storybook to the latest version. If you cannot upgrade your Vue 2 project to Vue 3, you can still upgrade Storybook, but only for the latest 7.x version. You can do this by running the following command:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"upgrade-command-specific-version.md\" />\n\n  {/* prettier-ignore-end */}\n\n</IfRenderer>\n"
  },
  {
    "path": "docs/sharing/design-integrations.mdx",
    "content": "---\ntitle: 'Design integrations'\nsidebar:\n  order: 3\n  title: Design integrations\n---\n\nStorybook integrates with design tools to speed up your development workflow. That helps you debug inconsistencies earlier in the design process, discover existing components to reuse, and compare designs to stories.\n\n## Figma\n\n[Figma](https://www.figma.com/) is a collaborative UI design tool that allows multiple people to work on the same design simultaneously in the browser. There are two ways to integrate Storybook and Figma.\n\n* [**Embed Storybook in Figma**](#embed-storybook-in-figma-with-the-plugin)\n* [**Embed Figma in Storybook**](#embed-figma-in-storybook-with-the-addon)\n\n### Embed Storybook in Figma with the plugin\n\n[Storybook Connect](https://www.figma.com/community/plugin/1056265616080331589/Storybook-Connect) is a Figma plugin that allows you to embed component stories in Figma. It’s powered by [Storybook embeds](./embed.mdx) and [Chromatic](https://www.chromatic.com/?utm_source=storybook_website\\&utm_medium=link\\&utm_campaign=storybook), a publishing tool created by the Storybook team.\n\n<Video src=\"../_assets/sharing/figma-plugin-open-story.mp4\" />\n\n#### Install plugin\n\nBefore we begin, you must have a Storybook [published to Chromatic](./publish-storybook.mdx#publish-storybook-with-chromatic). It provides the index, versions, and access control that back the plugin.\n\nGo to [Storybook Connect](https://www.figma.com/community/plugin/1056265616080331589/Storybook-Connect) to install the plugin.\n\nIn Figma, open the command palette (in Mac OS, use `Command + /`, in Windows use `Control + /`) and type `Storybook Connect` to enable it.\n\n![Figma palette Storybook connect](../_assets/sharing/figma-plugin-open-in-figma.png)\n\nFollow the instructions to connect and authenticate with Chromatic.\n\n#### Link stories to Figma components\n\nLink stories to Figma components, variants, and instances.\n\nGo to a story in a Storybook published on Chromatic. Make sure it’s on the branch you want to link. Then copy the URL to the story.\n\nIn Figma, select the component, open the plugin, and paste the URL.\n\n![Story linked in Figma](../_assets/sharing/figma-plugin-paste-url.png)\n\nChromatic will automatically update your linked stories to reflect the most recent Storybook published on the branch you linked. That means the link persists even as you push new code.\n\n<Callout variant=\"info\" icon=\"💡\">\n  The plugin does not support linking stories to Figma layers.\n</Callout>\n\n#### View stories in Figma\n\nOnce they're connected, you'll be able to view the story by clicking the link in the sidebar. Click \"View story\". Alternatively, open the plugin by using the command palette (in Mac OS, use `Command + /`, in Windows, use `Control + /`), then type `Storybook Connect`.\n\n![Figma sidebar with story link](../_assets/sharing/figma-plugin-sidebar.png)\n\n### Embed Figma in Storybook with the addon\n\n[Designs addon](https://storybook.js.org/addons/@storybook/addon-designs) allows you to embed Figma files and prototypes in Storybook.\n\n![Storybook addon figma](../_assets/sharing/storybook-figma-addon.png)\n\n#### Install design addon\n\nRun the following command to install the addon.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-figma-addon-install.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n\nThe CLI's [`add`](../api/cli-options.mdx#add) command automates the addon's installation and setup. To install it manually, see our [documentation](../addons/install-addons.mdx#manual-installation) on how to install addons.\n\n</Callout>\n\n#### Link Figma components to stories\n\nIn Figma, open the file you want to embed in Storybook. You can embed files, prototypes, components, and frames.\n\n* Embed a file or prototype, click the \"Share\" button to generate a unique URL for the file then click \"Copy link\".\n\n* Embed a component or frame check \"Link to selected frame\" in the Share dialog. Or right click on the frame and go to \"Copy/Paste as\" » \"Copy link\".\n\nIn Storybook, add a new [parameter](../writing-stories/parameters.mdx) named `design` to your story and paste the Figma URL. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"component-story-figma-integration.md\" />\n\n{/* prettier-ignore-end */}\n\n#### View designs in Storybook\n\nClick the \"Design\" tab in the addon panel to view the embedded Figma design.\n\n![Design addon panel](../_assets/sharing/design-addon-panel.png)\n\n## Zeplin\n\n[Zeplin](https://zeplin.io/) is a design tool that generates styleguides from [Sketch](https://www.sketch.com/), [Figma](https://www.figma.com/), and [Adobe XD](https://www.adobe.com/products/xd.html).\n\nUse the [Zeplin addon](https://storybook.js.org/addons/storybook-zeplin) to connect Storybook. The addon displays designs from Zeplin alongside the currently selected story. It includes convenient tooling to overlay the design image atop the live component.\n\nZeplin's native app also supports [links to published Storybooks](https://support.zeplin.io/en/articles/5674596-connecting-your-storybook-instance-with-zeplin).\n\n![Zeplin Storybook addon](../_assets/sharing/storybook-zeplin-addon.png)\n\n## Zeroheight\n\n[Zeroheight](https://zeroheight.com/) is a collaborative styleguide generator for design systems. It showcases design, code, brand, and copywriting documentation in one place. Users can easily edit that documentation with a WYSIWYG editor.\n\nZeroheight integrates with [Storybook](https://zeroheight.com/3xlwst8/p/507ba7-storybook), enabling you to embed stories alongside your design specs.\n\n![Zeroheight Storybook integration](../_assets/sharing/storybook-zeroheight.gif)\n\n## UXPin\n\n[UXPin](https://www.uxpin.com/) is an interactive design tool that uses production code to generate prototypes.\n\nUXPin allows you to [use interactive stories](https://www.uxpin.com/docs/merge/storybook-integration/) to design user flows.\n\n<Video src=\"../_assets/sharing/storybook-uxpin.mp4\" />\n\n## InVision Design System Manager\n\n[InVision DSM](https://www.invisionapp.com/design-system-manager) is a design system documentation tool. It helps design teams consolidate UX principles, user interface design, and design tokens in a shared workspace.\n\nInVision allows you to embed [Storybook](https://support.invisionapp.com/hc/en-us/articles/360028388192-Publishing-Storybook-to-DSM) in your design system documentation.\n\n![Invision DSM Storybook integration](../_assets/sharing/storybook-invision-dsm.gif)\n\n## Adobe XD\n\n[Adobe XD](https://www.adobe.com/products/xd.html) is a UI and UX design tool for creating wireframes, interactive designs, and prototypes.\n\nIntegrate Adobe XD with Storybook using the [design addon](https://storybook.js.org/addons/storybook-addon-designs/). You can [embed design specs](https://helpx.adobe.com/xd/help/publish-design-specs.html) alongside stories by following these [instructions](https://pocka.github.io/storybook-addon-designs/?path=/story/docs-iframe-readme--page).\n\n## Build your own integration\n\nExtend and customize Storybook by building an integration. Integrate with lower-level Storybook APIs or bootstrap an addon to customize Storybook's UI and behavior.\n\n* [Addon documentation](../addons/index.mdx)\n* [Create an addon tutorial](../addons/writing-addons.mdx)\n"
  },
  {
    "path": "docs/sharing/embed.mdx",
    "content": "---\ntitle: 'Embed stories'\nsidebar:\n  order: 2\n  title: Embed\n---\n\nEmbed stories to showcase your work to teammates and the developer community at large. In order to use embeds, your Storybook must be published and publicly accessible.\n\nStorybook supports `<iframe>` embeds out of the box. If you use Chromatic to [publish Storybook](./publish-storybook.mdx#publish-storybook-with-chromatic), you can also embed stories in Notion, Medium, and countless other platforms that support the oEmbed standard.\n\n## Embed a story with the toolbar\n\nEmbed a story with the toolbar, and paste the published story URL. For example:\n\n{/* prettier-ignore-start */}\n\n```js\n// oEmbed\nhttps://5ccbc373887ca40020446347-wtuhidckxo.chromatic.com/?path=/story/shadowboxcta--default\n\n// iframe embed\n<iframe\n  src=\"https://5ccbc373887ca40020446347-wtuhidckxo.chromatic.com/?path=/story/shadowboxcta--default&full=1&shortcuts=false&singleStory=true\"\n  width=\"800\"\n  height=\"260\"\n></iframe>\n```\n\n{/* prettier-ignore-end */}\n\n<br />\n\n<iframe src=\"https://5ccbc373887ca40020446347-wtuhidckxo.chromatic.com/?path=/story/shadowboxcta--default&full=1&shortcuts=false&singleStory=true\" width=\"800\" height=\"260\" />\n\n## Embed a story without the toolbar\n\nTo embed a plain story without Storybook's toolbar, click the \"open canvas in new tab\" icon in the top-right corner of Storybook to get the canvas URL. For example:\n\n{/* prettier-ignore-start */}\n\n```js\n// oEmbed\nhttps://5ccbc373887ca40020446347-wtuhidckxo.chromatic.com/iframe.html?id=/story/shadowboxcta--default&viewMode=story\n\n// iframe embed\n <iframe\n  src=\"https://5ccbc373887ca40020446347-wtuhidckxo.chromatic.com/iframe.html?id=shadowboxcta--default&viewMode=story&shortcuts=false&singleStory=true\"\n  width=\"800\"\n  height=\"200\"\n></iframe>\n```\n\n{/* prettier-ignore-end */}\n\n<br />\n\n<iframe src=\"https://5ccbc373887ca40020446347-wtuhidckxo.chromatic.com/iframe.html?id=shadowboxcta--default&viewMode=story&shortcuts=false&singleStory=true\" width=\"800\" height=\"200\" />\n\n## Embed documentation\n\nEmbed a documentation page by replacing `viewMode=story` with the uniquely auto-generated documentation entry for the story.\n\n{/* prettier-ignore-start */}\n\n```js\n// oEmbed\nhttps://5ccbc373887ca40020446347-wtuhidckxo.chromatic.com/iframe.html?id=shadowboxcta--docs&viewMode=docs&shortcuts=false&singleStory=true\n\n// iframe embed\n <iframe\n  src=\"https://5ccbc373887ca40020446347-wtuhidckxo.chromatic.com/iframe.html?id=shadowboxcta--docs&viewMode=docs&shortcuts=false&singleStory=true\"\n  width=\"800\"\n  height=\"400\"\n></iframe>\n```\n\n{/* prettier-ignore-end */}\n\n<br />\n\n<iframe src=\"https://5ccbc373887ca40020446347-wtuhidckxo.chromatic.com/iframe.html?id=shadowboxcta--docs&viewMode=docs&shortcuts=false&singleStory=true\" width=\"800\" height=\"400\" />\n\n## Embed stories on other platforms\n\nEvery platform has different levels of embed support. Check the documentation of your service to see how they recommend embedding external content.\n\n<details>\n  <summary>How to embed in Medium</summary>\n\n  Paste the Storybook URL into your Medium article, then press Enter. The embed will automatically resize to fit the story's height.\n\n  While editing an article, Medium renders all embeds non-interactive. Once your article is published, it will become interactive. [Preview a demo on Medium](https://medium.com/@ghengeveld/embedding-storybook-on-medium-ce8a280c03ad).\n\n  <Video src=\"../_assets/sharing/embed-medium-optimized.mp4\" />\n</details>\n\n<details>\n  <summary>How to embed in Notion</summary>\n\n  In your Notion document, type /embed, press Enter, and paste the story URL as the embed link. You can resize the embed as necessary.\n\n  ![Embed Notion](../_assets/sharing/embed-notion.png)\n</details>\n\n<details>\n  <summary>How to embed in Ghost</summary>\n\n  Type `/html` in your Ghost post, press Enter and paste the iframe URL. You can resize the embed via the width and height properties as required.\n\n  ![Embed Ghost](../_assets/sharing/embed-ghost.png)\n</details>\n"
  },
  {
    "path": "docs/sharing/index.mdx",
    "content": "---\ntitle: 'Sharing'\nhideRendererSelector: true\nsidebar:\n  order: 7\n  title: Sharing\n---\n\nYou have your components ready and tested. That's great! Now you want to make your component library available to your team or community to help them understand how they work. There are multiple ways you can do that. You can publish your Storybook to services like Chromatic, embed some of your stories in your own website, or use third party services like Figma.\n\n* [Publish](./publish-storybook.mdx)\n* [Embed](./embed.mdx)\n* [Design integrations](./design-integrations.mdx)\n* [Composition](./storybook-composition.mdx)\n* [Package Composition](./package-composition.mdx)\n"
  },
  {
    "path": "docs/sharing/package-composition.mdx",
    "content": "---\ntitle: 'Package Composition'\nsidebar:\n  order: 5\n  title: Package Composition\n---\n\nStorybook is widely used by component libraries and design systems. Design system authors can automatically compose their design systems inside their consumer’s Storybooks.\n\nFor example, if you use a design system package, its stories can appear alongside your own. That makes it convenient to cross reference usage documentation without leaving Storybook.\n\n<Callout variant=\"info\">\n  Composition via a package requires a secure integration between the service where you publish Storybook and Storybook’s own APIs. We recommend [publishing Storybook to Chromatic](./publish-storybook.mdx#publish-storybook-with-chromatic) for full support of these features.\n</Callout>\n\n## For consumers\n\nComposition happens automatically if the package [supports](#for-authors) it. When you install the package, Storybook will load its stories alongside your own.\n\n![Package composition workflow](../_assets/sharing/package-composition.png)\n\n### Set up\n\nIf you want to configure how the composed Storybook behaves, you can disable the `ref` element in your [`.storybook/main.js`](../configure/index.mdx#configure-story-rendering)\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-refs-disable.md\" />\n\n{/* prettier-ignore-end */}\n\n### Switching versions\n\nChange the version of the composed Storybook to see how the library evolves. This requires [configuration](#show-a-version-selector) from the package author.\n\n![Package composition workflow](../_assets/sharing/composition-versioning.png)\n\n## For authors\n\nComponent library authors can expand adoption by composing their components in their consumer’s Storybooks.\n\nAdd a `storybook` property in your published `package.json` that contains an object with a `url` field. Point the URL field to a published Storybook at the version you want.\n\n```json title=\"package.json\"\n{\n  \"storybook\": {\n    \"url\": \"https://host.com/your-storybook-for-this-version\"\n  }\n}\n```\n\n### Automatic version selection\n\nIf you're using [Chromatic](./publish-storybook.mdx#publish-storybook-with-chromatic), you can provide a single URL for your Storybook in the `storybook.url` field. You do not need to change the URL each time you publish a new version. Storybook will automatically find the correct URL for your package. For example:\n\n```json title=\"package.json\"\n{\n  \"storybook\": {\n    \"url\": \"https://master--xyz123.chromatic.com\"\n  }\n}\n```\n\nIn this example `xyz123` is your Chromatic project id. Storybook will automatically compose in the Storybook published to that project corresponding to the version the user has installed.\n\n### Show a version selector\n\nIf you're using [Chromatic](./publish-storybook.mdx#publish-storybook-with-chromatic), you can provide a list of versions for the user to [choose from](#switching-versions) to experiment with other versions of your package.\n"
  },
  {
    "path": "docs/sharing/publish-storybook.mdx",
    "content": "---\ntitle: 'Publish Storybook'\nsidebar:\n  order: 1\n  title: Publish\n---\n\n<YouTubeCallout id=\"zhrboql8UuU\" title=\"How to Test UI AUTOMATICALLY — Storybook and Chromatic\" />\n\nTeams publish Storybook online to review and collaborate on works in progress. That allows developers, designers, PMs, and other stakeholders to check if the UI looks right without touching code or requiring a local dev environment.\n\n<Video src=\"../_assets/sharing/storybook-workflow-publish.mp4\" />\n\n## Build Storybook as a static web application\n\nFirst, we'll need to build Storybook as a static web application. The functionality is already built-in and pre-configured for most supported frameworks. Run the following command inside your project's root directory:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"build-storybook-production-mode.md\" />\n\n{/* prettier-ignore-end */}\n\n<If renderer=\"angular\">\n\nIf you're using Angular, it's often better to use the [Angular builder](../get-started/frameworks/angular.mdx#how-do-i-migrate-to-an-angular-storybook-builder) to build Storybook: \n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"angular-builder-production.md\" />\n\n{/* prettier-ignore-end */}\n\n</If>\n\n<Callout variant=\"info\" icon=\"💡\">\n  You can provide additional flags to customize the command. Read more about the flag options [here](../api/cli-options.mdx).\n</Callout>\n\nStorybook will create a static web application capable of being served by any web server. Preview it locally by running the following command:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"preview-storybook-production-mode.md\" />\n\n{/* prettier-ignore-end */}\n\n### Customizing the build for performance\n\nBy default, Storybook's production build will encapsulate all stories and documentation into the production bundle. This is ideal for small projects but can cause performance issues for larger projects or when decreased build times are a priority (e.g., testing, CI/CD). If you need, you can customize the production build with the [`test` option](../api/main-config/main-config-build.mdx#test) in your `main.js|ts` configuration file and adjust your build script to enable the optimizations with the `--test` [flag](../api/cli-options.mdx#build).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-build-test-flag.md\" />\n\n{/* prettier-ignore-end */}\n\n### Build Storybook for older browsers\n\nThe Storybook app's UI supports [modern browsers](../get-started/install.mdx#project-requirements). If you need to run the app in older, unsupported browsers, you can use the [`--preview-only` CLI flag](../api/cli-options.mdx#build) to build Storybook in \"preview-only\" mode. This skips building the Storybook manager (the UI surrounding your stories) and only builds the preview (the iframe that contains your stories). That makes your [Storybook builder](../builders/index.mdx) and its configuration solely responsible for which browsers are supported.\n\nWhen in \"preview-only\" mode, the normal entry point, `/index.html`, will result in a 404, because the client-side router is not available. To work around this, start from the `/iframe.html` route and add the `?navigator=true` query parameter to the URL. This will render a basic, HTML-only sidebar inside the preview so that you can navigate to your stories. For example, you can access the preview at `http://localhost:6006/iframe.html?navigator=true` (you may need to update the port number).\n\nThis applies to both the [`build`](../api/cli-options.mdx#build) (for publishing) and [`dev`](../api/cli-options.mdx#dev) (for local development) commands.\n\n## Publish Storybook with Chromatic\n\nOnce you've built your Storybook as a static web application, you can publish it to your web host. We recommend [Chromatic](https://www.chromatic.com/?utm_source=storybook_website\\&utm_medium=link\\&utm_campaign=storybook), a free publishing service made for Storybook that documents, versions, and indexes your UI components securely in the cloud.\n\n![Storybook publishing workflow](../_assets/sharing/workflow-publish.png)\n\nTo get started, sign up with your GitHub, GitLab, Bitbucket, or email and generate a unique *project-token* for your project.\n\nNext, install the [Chromatic CLI](https://www.npmjs.com/package/chromatic) package from npm:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"chromatic-install.md\" />\n\n{/* prettier-ignore-end */}\n\nRun the following command after the package finishes installing. Make sure that you replace `your-project-token` with your own project token.\n\n```shell\nnpx chromatic --project-token=<your-project-token>\n```\n\nWhen Chromatic finishes, you should have successfully deployed your Storybook. Preview it by clicking the link provided (i.e., https://random-uuid.chromatic.com).\n\n```shell\nBuild 1 published.\n\nView it online at https://www.chromatic.com/build?appId=...&number=1.\n```\n\n![Chromatic publish build](../_assets/sharing/build-publish-only.png)\n\n### Setup CI to publish automatically\n\nConfigure your CI environment to publish your Storybook and [run Chromatic](https://www.chromatic.com/docs/ci?utm_source=storybook_website\\&utm_medium=link\\&utm_campaign=storybook) whenever you push code to a repository. Let's see how to set it up using GitHub Actions.\n\nIn your project's root directory, add a new file called `chromatic.yml` inside the `.github/workflows` directory:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"chromatic-github-action.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  Secrets are secure environment variables provided by GitHub so that you don't need to hard code your `project-token`. Read the [official documentation](https://docs.github.com/en/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository) to learn how to configure them.\n</Callout>\n\nCommit and push the file. Congratulations, you've successfully automated publishing your Storybook. Now whenever you open a PR you’ll get a handy link to your published Storybook in your PR checks.\n\n![PR check publish](../_assets/sharing/prbadge-publish.png)\n\n### Review with your team\n\nPublishing Storybook as part of the development process makes it quick and easy to gather team feedback.\n\nA common method to ask for review is to paste a link to the published Storybook in a pull request or Slack.\n\nIf you publish your Storybook to Chromatic, you can use the [UI Review](https://www.chromatic.com/features/publish?utm_source=storybook_website\\&utm_medium=link\\&utm_campaign=storybook) feature to automatically scan your PRs for new and updated stories. That makes it easy to identify what changed and give feedback.\n\n![UI review in Chromatic](../_assets/sharing/workflow-uireview.png)\n\n### Versioning and history\n\nWhen you publish Storybook, you also get component history and versioning down to the commit. That's useful during implementation review for comparing components between branches/commits to past versions.\n\n![Library history in Chromatic](../_assets/sharing/workflow-history-versioning.png)\n\n## Publish Storybook to other services\n\nSince Storybook is built as a static web application, you can also publish it to any web host, including [GitHub Pages](https://docs.github.com/en/pages), [Netlify](https://www.netlify.com/), [AWS S3](https://aws.amazon.com/s3/), and more. However, features such as [Composition](./storybook-composition.mdx), [embedding stories](./embed.mdx), history, versioning, and assets may require tighter integration with Storybook APIs and secure authentication. If you want to know more about headers, you can refer to the [Migration guide](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deploying-build-artifacts). Additionally, if you want to learn about the Component Publishing Protocol (CPP), you can find more information below.\n\n### GitHub Pages\n\nTo deploy Storybook on GitHub Pages, use the community-built [Deploy Storybook to GitHub Pages](https://github.com/bitovi/github-actions-storybook-to-github-pages) Action. To enable it, create a new workflow file inside your `.github/workflows` directory with the following content:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"ghp-github-action.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  The GitHub Pages Action requires additional configuration options to customize the deployment process. Refer to the [official documentation](https://github.com/marketplace/actions/deploy-storybook-to-github-pages) for more information.\n</Callout>\n\n<details>\n  <summary><h3>Component Publishing Protocol (CPP)</h3></summary>\n\n  Storybook can communicate with services that host built Storybooks online. This enables features such as [Composition](./storybook-composition.mdx). We categorize services via compliance with the \"Component Publishing Protocol\" (CPP) with various levels of support in Storybook.\n\n  ### CPP level 1\n\n  This level of service serves published Storybooks and makes the following available:\n\n  * Versioned endpoints, URLs that resolve to different published Storybooks depending on a `version=x.y.z` query parameter (where `x.y.z` is the released version of the package).\n  * Support for `/index.json` (formerly `/stories.json`) endpoint, which returns a list of stories and their metadata.\n  * Support for `/metadata.json` and the `releases` field.\n\n  Example: [Chromatic](https://www.chromatic.com/?utm_source=storybook_website\\&utm_medium=link\\&utm_campaign=storybook)\n\n  ### CPP level 0\n\n  This level of service can serve published Storybooks but has no further integration with Storybook’s APIs.\n\n  Examples: [Netlify](https://www.netlify.com/), [S3](https://aws.amazon.com/en/s3/)\n</details>\n\n## Search engine optimization (SEO)\n\nIf your Storybook is publicly viewable, you may wish to configure how it is represented in search engine result pages.\n\n### Description\n\nYou can provide a description for search engines to display in the results listing, by adding the following to the `manager-head.html` file in your config directory:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"seo-description.md\" />\n\n{/* prettier-ignore-end */}\n\n### Preventing your Storybook from being crawled\n\nYou can prevent your published Storybook from appearing in search engine results by including a noindex meta tag, which you can do by adding the following to the `manager-head.html` file in your config directory:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"seo-noindex.md\" />\n\n{/* prettier-ignore-end */}\n"
  },
  {
    "path": "docs/sharing/storybook-composition.mdx",
    "content": "---\ntitle: 'Storybook Composition'\nsidebar:\n  order: 4\n  title: Composition\n---\n\nComposition allows you to browse components from any Storybook accessible via URL inside your local Storybook. You can compose any [Storybook published online](./publish-storybook.mdx) or running locally no matter the view layer, tech stack, or dependencies.\n\n![Storybook reference external](../_assets/sharing/reference-external-storybooks-composition.png)\n\nYou’ll see the composed Storybook’s stories in the sidebar alongside your own. This unlocks common workflows that teams often struggle with:\n\n* 👩‍💻 UI developers can quickly reference prior art without switching between Storybooks.\n* 🎨 Design systems can expand adoption by composing themselves into their users’ Storybooks.\n* 🛠 Frontend platform can audit how components are used across projects.\n* 📚 View multiple Storybooks with different tech stacks in one place\n\n![Storybook composition](../_assets/sharing/combine-storybooks.png)\n\n## Compose published Storybooks\n\nIn your [`.storybook/main.js|ts`](../configure/index.mdx#configure-story-rendering) file add a `refs` field with information about the reference Storybook. Pass in a URL to a statically built Storybook.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-refs.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"warning\">\n  Addons in composed Storybooks will not work as they normally do in a non-composed Storybook.\n</Callout>\n\n## Compose local Storybooks\n\nYou can also compose multiple Storybooks that are running locally. For instance, if you have a React Storybook and an Angular Storybook running on different ports, you can update your configuration file (i.e., `.storybook/main.js|ts`) and reference them as follows:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-ref-local.md\" />\n\n{/* prettier-ignore-end */}\n\nAdding this configuration will combine React and Angular Storybooks into your current one. You’ll see the changes being applied automatically when either of these changes. Enabling you to develop both frameworks in sync.\n\n## Compose Storybooks per environment\n\nYou can also compose Storybooks based on the current development environment (e.g., development, staging, production). For instance, if the project you're working on already has a published Storybook but also includes a version with cutting-edge features not yet released, you can adjust the composition based on that. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-refs-with-function.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  Similar to other fields available in Storybook’s configuration file, the `refs` field can also be a function that accepts a `config` parameter containing Storybook’s configuration object. See the [API reference](../api/main-config/main-config-refs.mdx) for more information.\n</Callout>\n\n## Troubleshooting\n\n### Storybook composition is not working with my project\n\nIf you're working with an outdated Storybook version or have a project-specific requirement that prevents you from updating your Storybook to the latest version, you can rely on the Storybook CLI to generate the `index.json` file when you deploy your Storybook. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-extract-specific-version.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  The usage of a specific version of the CLI is intended as the `extract` command is not available in Storybook 8.0 or higher. It also requires you to provide additional configuration to generate the `index.json` file accurately. See the [previous documentation](../../../release-7-6/docs/sharing/storybook-composition.mdx) for more information.\n</Callout>\n"
  },
  {
    "path": "docs/versions/latest.json",
    "content": "{ \"version\": \"10.3.0\", \"info\": { \"plain\": \"\" } }\n"
  },
  {
    "path": "docs/versions/next.json",
    "content": "{\"version\":\"10.4.0-alpha.6\",\"info\":{\"plain\":\"- Builder-Vite: Add onModuleGraphChange method - [#34323](https://github.com/storybookjs/storybook/pull/34323), thanks @ghengeveld!\\n- CLI: Add automigrate check for 'storybook' package name conflict - [#34290](https://github.com/storybookjs/storybook/pull/34290), thanks @whdjh!\\n- CLI: Prompt for init crash reports - [#34316](https://github.com/storybookjs/storybook/pull/34316), thanks @JReinhold!\\n- CSF4: Fix duplicate preview loading issue in Vitest - [#34361](https://github.com/storybookjs/storybook/pull/34361), thanks @valentinpalkovic!\\n- Maintenance: Add assertions outside step incorrectly nested in interactions panel - [#34296](https://github.com/storybookjs/storybook/pull/34296), thanks @majiayu000!\\n- Maintenance: Extract getBuilderOptions helper across framewo… - [#34260](https://github.com/storybookjs/storybook/pull/34260), thanks @alex-js-ltd!\\n- Maintenance: Use errorToErrorLike in boot-test-runner for consistent stack deduplication - [#34385](https://github.com/storybookjs/storybook/pull/34385), thanks @mixelburg!\\n- Onboarding: Fix checklist MDX instructions - [#33193](https://github.com/storybookjs/storybook/pull/33193), thanks @kylegach!\\n- React-Docgen: Add tsconfig fallback chain and warning for monorepos - [#34353](https://github.com/storybookjs/storybook/pull/34353), thanks @viditkbhatnagar!\\n- React-Docgen: Try .tsx fallback when resolving .js ESM imports in docgen resolvers - [#34393](https://github.com/storybookjs/storybook/pull/34393), thanks @mixelburg!\\n- UI: Fix mobile navigation when renderLabel returns a React node - [#34262](https://github.com/storybookjs/storybook/pull/34262), thanks @Nathan54Villaume!\\n- Vite: Use vite hook filter for performance improvements - [#34022](https://github.com/storybookjs/storybook/pull/34022), thanks @huang-julien!\"}}"
  },
  {
    "path": "docs/writing-docs/autodocs.mdx",
    "content": "---\ntitle: 'Automatic documentation and Storybook'\nsidebar:\n  order: 1\n  title: Autodocs\n---\n\nStorybook Autodocs is a powerful tool that can help you quickly generate comprehensive documentation for your UI components. By leveraging Autodocs, you're transforming your stories into living documentation which can be further extended with [MDX](./mdx.mdx) and [Doc Blocks](./doc-blocks.mdx) to provide a clear and concise understanding of your components' functionality.\n\nStorybook infers the relevant metadata (e.g., [`args`](../writing-stories/args.mdx), [`argTypes`](../api/arg-types.mdx), [`parameters`](../writing-stories/parameters.mdx)) and automatically generates a documentation page with this information positioned at the root-level of your component tree in the sidebar.\n\n![Storybook autodocs](../_assets/writing-docs/autodocs.png)\n\n## Set up automated documentation\n\nAutodocs is configured through [tags](../writing-stories/tags.mdx). If a [CSF](../api/csf/index.mdx) file contains at least one story tagged with `autodocs`, then a documentation page will be generated for that component.\n\nTo enable automatic documentation for all stories in a project, add it to `tags` in your `.storybook/preview.js|ts` file:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"tags-autodocs-in-preview.md\" />\n\n{/* prettier-ignore-end */}\n\nYou can also enable it at the component (or story) level:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"tags-autodocs-in-meta.md\" />\n\n{/* prettier-ignore-end */}\n\nYou can disable auto docs for a particular component by [removing the tag](../writing-stories/tags.mdx#removing-tags):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"tags-autodocs-remove-component.md\" />\n\n{/* prettier-ignore-end */}\n\nSimilarly, you can exclude a particular story from the auto docs page, by removing the tag:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"tags-autodocs-remove-story.md\" />\n\n{/* prettier-ignore-end */}\n\n### Configure\n\nIn addition to enabling the feature with `tags`, you can extend your Storybook configuration file (i.e., `.storybook/main.js|ts|cjs`) and provide additional options to control how documentation gets created. Listed below are the available options and examples of how to use them.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-auto-docs-full-config.md\" />\n\n{/* prettier-ignore-end */}\n\n| Option                                                               | Description                                                                                                                    |\n| ---------------------------------------------------------------------| -------------------------------------------------------------------------------------------------------------------------------|\n| [`defaultName`](../api/main-config/main-config-docs.mdx#defaultname) | Renames the auto-generated documentation page<br /> Default: `docs: { defaultName: 'Docs' }`                                   |\n| [`docsMode`](../api/main-config/main-config-docs.mdx#docsmode)       | Toggles the documentation mode, which only shows documentation pages in the sidebar<br /> Default: `docs: { docsMode: false }` |\n\n\n### Write a custom template\n\nTo replace the default documentation template used by Storybook, you can extend your UI configuration file (i.e., `.storybook/preview.js|ts`) and introduce a `docs` [parameter](./doc-blocks.mdx#customizing-the-automatic-docs-page). This parameter accepts a `page` function that returns a React component, which you can use to generate the required template. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-auto-docs-custom-template-function.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  Internally, Storybook uses a similar implementation to generate the default template. See the Doc Blocks [API reference](./doc-blocks.mdx#available-blocks) to learn more about how Doc Blocks work.\n</Callout>\n\nGoing over the code snippet in more detail. When Storybook starts up, it will override the default template with the custom one composed of the following:\n\n1. A header with the component's metadata retrieved by the `Title`, `Subtitle`, and `Description` Doc Blocks.\n2. The first story defined in the file via the `Primary` Doc Block with a handy set of UI controls to zoom in and out of the component.\n3. An interactive table with all the relevant [`args`](../writing-stories/args.mdx) and [`argTypes`](../api/arg-types.mdx) defined in the story via the `Controls` Doc Block.\n4. A overview of the remaining stories via the `Stories` Doc Block.\n\n#### With MDX\n\nYou can also use MDX to generate the documentation template. This is useful in non-React projects where JSX-handling is not configured. Normally, when you create an MDX file in your project, it is treated as normal documentation. To indicate that an MDX file is a documentation template, supply the `isTemplate` property to its [`Meta`](../api/doc-blocks/doc-block-meta.mdx) Doc Block. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-mdx-template-with-prop.md\" />\n\n{/* prettier-ignore-end */}\n\nThen you can use it in your `.storybook/preview.js|ts` or an individual story file by importing it:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-auto-docs-custom-mdx-template.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n\n  If you only need to override the documentation page for a single component, we recommend creating an MDX file and referencing it directly via the `<Meta of={} />` Doc Block.\n\n</Callout>\n\n### Generate a table of contents\n\nStorybook's auto-generated documentation pages can be quite long and difficult to navigate. To help with this, you can enable the table of contents feature to provide a quick overview of the documentation page and allow users to jump to a specific section. To enable it, extend your Storybook UI configuration file (i.e., `.storybook/preview.js|ts`) and provide a `docs` [parameter](../writing-stories/parameters.mdx#global-parameters) with a `toc` property.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-enable-toc.md\" />\n\n{/* prettier-ignore-end */}\n\n### Configure the table of contents\n\nBy default, the table of contents on the documentation page will only show the `h3` headings that are automatically generated. However, if you want to customize the table of contents, you can add more parameters to the `toc` property. The following options and examples of how to use them are available.\n\n| Option                | Description                                                                                                                                                                                                       |\n| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `contentsSelector`    | Defines the container's CSS selector for search for the headings <br /> `toc: { contentsSelector: '.sbdocs-content' }`                                                                                            |\n| `disable`             | Hides the table of contents for the documentation pages <br /> `toc: { disable: true }`                                                                                                                           |\n| `headingSelector`     | Defines the list of headings to feature in the table of contents <br /> `toc: { headingSelector: 'h1, h2, h3' }`                                                                                                  |\n| `ignoreSelector`      | Configures the table of contents to ignore specific headings or stories. By default, the table of contents will ignore all content placed within Story blocks <br /> `toc: { ignoreSelector: '.docs-story h2' }`  |\n| `title`               | Defines a title caption for the table of contents. <br />Accepts one of: `string`, `null`, React element <br /> `toc: { title: 'Table of Contents' }`                                                             |\n| `unsafeTocbotOptions` | Provides additional [`TocBot`](https://tscanlin.github.io/tocbot/) configuration options <br /> `toc: { unsafeTocbotOptions: { orderedList: true } }`                                                             |\n\n<Callout variant=\"info\">\n\n  The `contentsSelector`, `headingSelector`, and `ignoreSelector` properties allow additional customization. For more information on using them, see the [`Tocbot` documentation](https://tscanlin.github.io/tocbot/).\n  \n</Callout>\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-custom-toc.md\" />\n\n{/* prettier-ignore-end */}\n\n#### Component-level configuration\n\nIf you want to customize the table of contents for a specific story, you can include a `toc` property in the story's meta (or default export) and provide the required [configuration](#configure-the-table-of-contents). For example, if you need to hide the table of contents for a specific story, adjust your story as follows:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"my-component-disable-toc.md\" />\n\n{/* prettier-ignore-end */}\n\n### Customize component documentation\n\nCreating automated documentation with Storybook's Autodocs provides you with the starting point to build a sustainable documentation pattern. Nevertheless, it may not be suited for every case, and you may want to extend it and provide additional information. We recommend combining [MDX](./mdx.mdx) alongside Storybook's [Doc Blocks](./doc-blocks.mdx) for such cases to author your documentation.\n\n## Advanced configuration\n\n### Documenting multiple components\n\nSometimes it's helpful to document multiple components together. For example, a component library’s ButtonGroup and Button components might not make sense without one another.\n\nAutodocs allows you to document your \"main\" component, defined by the `component` property, as well as one or more `subcomponents` related to it.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"list-story-with-subcomponents.md\" />\n\n{/* prettier-ignore-end */}\n\n![Subcomponents in ArgTypes doc block](../_assets/writing-stories/doc-block-arg-types-subcomponents-for-list.png)\n\nThe main component and its subcomponents will show up in a tabbed version of the [`ArgTypes` doc block](./doc-blocks.mdx#argtypes). The tab titles will correspond to the keys of the `subcomponents` object.\n\nIf you want to organize your documentation differently for component groups, we recommend [using MDX](./mdx.mdx). It gives you complete control over how your components are displayed and supports any configuration.\n\n### Customize the Docs Container\n\nThe Docs Container is the component that wraps up the documentation page. It's responsible for rendering the documentation page in Storybook's UI. You can customize it by creating your own component and updating your Storybook UI configuration file (i.e., `.storybook/preview.js|ts`) to reference it.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-auto-docs-custom-docs-container.md\" />\n\n{/* prettier-ignore-end */}\n\n### Override the default theme\n\nBy default, Storybook provides two themes for the UI: `light` and `dark`. If you need to customize the theme used by the documentation to match the existing one, you can update your Storybook UI configuration file (i.e., `.storybook/preview.js|ts`) and apply it.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-auto-docs-override-theme.md\" />\n\n{/* prettier-ignore-end */}\n\n### Working with custom MDX components\n\nOut of the box, Storybook has a set of components that you can use to customize your documentation page. If you're working with a design system or component library and wish to add them to your documentation page, you can override the `MDXProvider` component inherited from `@mdx-js/react` with your own. However, there's a caveat to this, the component replacement will only have an impact if you're writing documentation using Markdown syntax (e.g., `#` for headings). Native HTML elements, such as `<h1>`, will not be replaced with your custom implementation.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-auto-docs-override-mdx-container.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  This is not a Storybook issue but a detail of how MDX works. From their [migration guide](https://mdxjs.com/migrating/v2/#update-mdx-content):\n\n  “We now ‘sandbox’ components, for lack of a better name. It means that when you pass a component for h1, it does get used for `# hi` but not for `<h1>hi</h1>`”\n</Callout>\n\n### Addon options\n\nThe docs addon accepts options to customize the behavior of the documentation page. You can add them to your Storybook UI configuration file (i.e., `.storybook/main.js|ts`), as part of registering the addon. The following options are available:\n\n| Option             | Description                                                                                                                                                    |\n| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `csfPluginOptions` | Provides additional configuration for Storybook's CSF plugin. Can be disabled with `null`.                                                                     |\n| `mdxPluginOptions` | Provides additional configuration options and plugin configuration for [MDX documentation](../writing-docs/mdx.mdx#markdown-tables-arent-rendering-correctly). |\n\nThis example demonstrates how to apply these options.\n\n<CodeSnippets path=\"addon-docs-options.md\" />\n\n## Troubleshooting\n\n### The table of contents doesn't render as expected\n\nWhen using Autodocs's table of contents, you may encounter situations where it appears differently than expected. To help you resolve these problems, we have compiled a list of possible scenarios that may cause issues.\n\n#### With simple documentation pages\n\nIf you have a documentation page with only one matching heading and create a table of contents for it, the table of contents will not be hidden by default. A potential solution for this issue would be to add a second heading or turn it off entirely.\n\n#### With small screens\n\nIf the screen width is less than 1200px, the table of contents will be hidden by default. Currently, there's no built-in solution for this issue that doesn't impact the documentation page's style compatibility.\n\n#### With MDX\n\nIf you're writing [unattached documentation](./mdx.mdx#writing-unattached-documentation) using MDX, you cannot customize the table of contents primarily due to the lack of support for defining parameters based on the current implementation. As a result, the table of contents will always revert to the default [configuration](#configure-the-table-of-contents) provided globally.\n\n### The auto-generated documentation is not showing up in a monorepo setup\n\nOut of the box, Storybook's Autodocs feature is built to generate documentation for your stories automatically. Nevertheless, if you're working with a monorepo setup (e.g., [`Yarn Workspaces`](https://yarnpkg.com/features/workspaces), [`pnpm Workspaces`](https://pnpm.io/workspaces)), you may run into issues where part of the documentation may not be generated for you. To help you troubleshoot those issues, we've prepared some recommendations that might help you.\n\nUpdate your import statements to reference the component directly instead of the package's root. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-fix-imports-autodocs-monorepo.md\" />\n\n{/* prettier-ignore-end */}\n\nAdditionally, if you're developing using TypeScript, you may need to update Storybook's configuration file (i.e., `.storybook/main.js|ts`) to include the following:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-fix-imports-autodocs-monorepo.md\" />\n\n{/* prettier-ignore-end */}\n\nIf you're still encountering issues, we recommend reaching out to the community using the default communication channels (e.g., [GitHub discussions](https://github.com/storybookjs/storybook/discussions/new?category=help)).\n\n### The controls are not updating the story within the auto-generated documentation\n\nIf you turned off inline rendering for your stories via the [`inline`](../api/doc-blocks/doc-block-story.mdx#inline) configuration option, you would run into a situation where the associated controls are not updating the story within the documentation page. This is a known limitation of the current implementation and will be addressed in a future release.\n\n**Learn more about Storybook documentation**\n\n* Autodocs for creating documentation for your stories\n* [MDX](./mdx.mdx) for customizing your documentation\n* [Doc Blocks](./doc-blocks.mdx) for authoring your documentation\n* [Publishing docs](./build-documentation.mdx) to automate the process of publishing your documentation\n"
  },
  {
    "path": "docs/writing-docs/build-documentation.mdx",
    "content": "---\ntitle: 'Preview and build docs'\nsidebar:\n  order: 5\n  title: Preview and build docs\n---\n\nStorybook allows you to create rich and extensive [documentation](./index.mdx) that will help you and any other stakeholder involved in the development process. Out of the box you have the tooling required to not only write it but also to preview it and build it.\n\n## Preview Storybook's documentation\n\nAt any point during your development, you can preview the documentation you've written. Storybook allows you to generate a preview of the final documentation when you use the `--docs` flag. We recommend including it in your `package.json` as a new script:\n\n```json title=\"package.json\"\n{\n  \"scripts\": {\n    \"storybook-docs\": \"storybook dev --docs\"\n  }\n}\n```\n\nDepending on your configuration, when you execute the `storybook-docs` script. Storybook will be put into documentation mode and will generate a different build.\n\nIt will look for any stories available either in [MDX](./mdx.mdx) or [CSF](../writing-stories/index.mdx#component-story-format) and based on the documentation you've added it will display it...\n\n![Storybook in documentation mode](../_assets/writing-docs/storybook-docs-build.png)\n\nThere's some caveats to this build mode, as to the normal Storybook build:\n\n* The top level item refers to the primary story for your component.\n* Each individual story is now in a flattened display mode, with a different set of icons. This allows focus on the documentation itself.\n* Storybook's layout is rendered differently. The toolbar will not be displayed.\n\n## Publish Storybook's documentation\n\nYou can also publish your documentation the same you would [publish](../sharing/publish-storybook.mdx) your Storybook. You can use the `--docs` flag with the [`storybook build`](../api/cli-options.mdx#build) command. We recommend as well including it as a script in your `package.json` file:\n\n```json title=\"package.json\"\n{\n  \"scripts\": {\n    \"build-storybook-docs\": \"storybook build --docs\"\n  }\n}\n```\n\nBased on the configuration you have, when the `build-storybook-docs` script is executed, Storybook once again will be put into documentation mode and will generate a different build and output the documentation into the `storybook-static` folder.\n\nThe same caveats mentioned above will apply.\n\nYou can use any hosting provider to deploy your documentation, for instance:\n\n* [Vercel](https://vercel.com/)\n* [Netlify](https://www.netlify.com/)\n* [S3](https://aws.amazon.com/en/s3/)\n\n**Learn more about Storybook documentation**\n\n* [Autodocs](./autodocs.mdx) for creating documentation for your stories\n* [MDX](./mdx.mdx) for customizing your documentation\n* [Doc Blocks](./doc-blocks.mdx) for authoring your documentation\n* Publishing docs to automate the process of publishing your documentation\n"
  },
  {
    "path": "docs/writing-docs/code-panel.mdx",
    "content": "---\ntitle: Code panel\nsidebar:\n  order: 4\n  title: Code panel\n---\n\n<Callout variant=\"info\">\n\nCode Panel is a replacement for the [Storysource addon](https://storybook.js.org/addons/@storybook/addon-storysource), which was [discontinued in Storybook 9](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#storysource-addon-removed).\n\n</Callout>\n\nThe Code panel renders a story’s source code when viewing that story in the canvas. Any [args](../writing-stories/args.mdx) defined in the story are replaced with their values in the output.\n\n![Code panel showing story's source code](../_assets/writing-docs/code-panel.png)\n\n## Usage\n\nTo enable the Code panel, set `parameters.docs.codePanel` to `true`. For most projects, this is best done in the `.storybook/preview.js|ts` file, to apply to all stories.\n\n<CodeSnippets path=\"code-panel-enable-in-preview.md\" />\n\nYou can also enable it at the component or story level:\n\n<CodeSnippets path=\"code-panel-in-meta-and-story.md\" />\n\n## Configuration\n\nCode panel renders the same snippet as the [Source docs block](../api/doc-blocks/doc-block-source.mdx), which is also used in [Autodocs](./autodocs.mdx) pages. The snippet is customizable and reuses the [Source configuration parameters](../api/doc-blocks/doc-block-source.mdx#source).\n"
  },
  {
    "path": "docs/writing-docs/doc-blocks.mdx",
    "content": "---\ntitle: Doc blocks\nsidebar:\n  order: 3\n  title: Doc blocks\n---\n\nStorybook offers several doc blocks to help document your components and other aspects of your project.\n\nThere are two common ways to use doc blocks in Storybook, within MDX and as part of the docs page template.\n\n## Within MDX\n\nThe blocks are most commonly used within Storybook's [MDX documentation](./mdx.mdx):\n\n![Screenshot of mdx content](../_assets/writing-docs/mdx-example.png)\n\n{/* prettier-ignore-start */}\n\n```md title=\"ButtonDocs.mdx\"\nimport { Meta, Primary, Controls, Story } from '@storybook/addon-docs/blocks';\n\nimport * as ButtonStories from './Button.stories';\n\n<Meta of={ButtonStories} />\n\n# Button\n\nA button is ...\n\n<Primary />\n\n## Props\n\n<Controls />\n\n## Stories\n\n### Primary\n\nA button can be of primary importance.\n\n<Story of={ButtonStories.Primary} />\n\nA button can be of secondary importance.\n\n<Story of={ButtonStories.Secondary} />\n\n{/* ... */}\n```\n\n{/* prettier-ignore-end */}\n\n## Customizing the automatic docs page\n\nThe blocks are also used to define the page template for [automatics docs](./autodocs.mdx). For example, here's the default template:\n\n![Screenshot of automatic docs template](../_assets/writing-docs/autodocs-default-template.png)\n\n```jsx\nimport { Title, Subtitle, Description, Primary, Controls, Stories } from '@storybook/addon-docs/blocks';\n\nexport const autoDocsTemplate = () => (\n  <>\n    <Title />\n    <Subtitle />\n    <Description />\n    <Primary />\n    <Controls />\n    <Stories />\n  </>\n);\n```\n\nIf you [override the default page template](./autodocs.mdx#write-a-custom-template), you can similarly use Doc Blocks to build the perfect documentation page for your project.\n\nNote that some doc blocks render other blocks. For example, the `<Stories />` block expands to:\n\n{/* prettier-ignore-start */}\n\n```md\n## Stories\n\n<Canvas>\n  ### Story name\n  <Description />\n  <Story />\n  <Source />\n</Canvas>\n\n{/* ... repeat <Canvas> for each story */}\n```\n\n{/* prettier-ignore-end */}\n\nAs a result, for example, customizing the [`Source`](../api/doc-blocks/doc-block-source.mdx) block via parameters (see next section) will also affect the Source blocks rendered as part of [`Canvas`](../api/doc-blocks/doc-block-canvas.mdx) blocks.\n\n## Customizing doc blocks\n\nIn both use cases (MDX and automatic docs), many of the doc blocks can be customized via [parameters](../writing-stories/parameters.mdx).\n\nFor example, you can filter out the `style` prop from all [`Controls`](../api/doc-blocks/doc-block-controls.mdx) tables through your Storybook:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-doc-blocks-controls-exclude-prop.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n\n  Parameters can also be defined at the [component](../writing-stories/parameters.mdx#component-parameters) (or meta) level or the [story](../writing-stories/parameters.mdx#story-parameters) level, allowing you to customize Doc Blocks exactly as you need, where you need.\n\n</Callout>\n\nThe blocks that accept customization via parameters are marked in the list of available blocks below.\n\nWhen using a doc block in MDX, it can also be customized with its props:\n\n{/* prettier-ignore-start */}\n\n```md\n<Controls exclude={['style']}>\n```\n\n{/* prettier-ignore-end */}\n\n## Available blocks\n\nEach block has a dedicated API reference page detailing usage, available options, and technical details.\n\n### [ArgTypes](../api/doc-blocks/doc-block-argtypes.mdx)\n\n<Callout variant=\"info\">\n\n  Accepts parameters in the namespace `parameters.docs.argTypes`.\n\n</Callout>\n\nThe `ArgTypes` block can be used to show a static table of [arg types](../api/arg-types.mdx) for a given component as a way to document its interface.\n\n![Screenshot of ArgTypes block](../_assets/api/doc-block-argtypes.png)\n\n### [Canvas](../api/doc-blocks/doc-block-canvas.mdx)\n\n<Callout variant=\"info\">\n\n  Accepts parameters in the namespace `parameters.docs.canvas`.\n\n</Callout>\n\nThe `Canvas` block is a wrapper around a [`Story`](../api/doc-blocks/doc-block-story.mdx), featuring a toolbar that allows you to interact with its content while automatically providing the required [`Source`](../api/doc-blocks/doc-block-source.mdx) snippets.\n\n![Screenshot of Canvas block](../_assets/api/doc-block-canvas.png)\n\n### [ColorPalette](../api/doc-blocks/doc-block-colorpalette.mdx)\n\nThe `ColorPalette` block allows you to document all color-related items (e.g., swatches) used throughout your project.\n\n![Screenshot of ColorPalette and ColorItem blocks](../_assets/api/doc-block-colorpalette.png)\n\n### [Controls](../api/doc-blocks/doc-block-controls.mdx)\n\n<Callout variant=\"info\">\n\n  Accepts parameters in the namespace `parameters.docs.controls`.\n\n</Callout>\n\nThe `Controls` block can be used to show a dynamic table of args for a given story, as a way to document its interface, and to allow you to change the args for a (separately) rendered story (via the [`Story`](../api/doc-blocks/doc-block-story.mdx) or [`Canvas`](../api/doc-blocks/doc-block-canvas.mdx) blocks).\n\n![Screenshot of Controls block](../_assets/api/doc-block-controls.png)\n\n### [Description](../api/doc-blocks/doc-block-description.mdx)\n\nThe `Description` block displays the description for a component, story, or meta obtained from their respective JSDoc comments.\n\n![Screenshot of Description block](../_assets/api/doc-block-title-subtitle-description.png)\n\n### [IconGallery](../api/doc-blocks/doc-block-icongallery.mdx)\n\nThe `IconGallery` block lets you quickly document all icons associated with your project, displayed in a neat grid.\n\n![Screenshot of IconGallery and IconItem blocks](../_assets/api/doc-block-icongallery.png)\n\n### [Markdown](../api/doc-blocks/doc-block-markdown.mdx)\n\nThe `Markdown` block allows you to import and include plain markdown in your MDX files.\n\n![Screenshot of Markdown block](../_assets/api/doc-block-markdown.png)\n\n### [Meta](../api/doc-blocks/doc-block-meta.mdx)\n\nThe `Meta` block is used to [attach](#attached-vs-unattached) a custom MDX docs page alongside a component’s list of stories. It doesn’t render any content but serves two purposes in an MDX file:\n\n* Attaches the MDX file to a component and its stories, or\n* Controls the location of the unattached docs entry in the sidebar.\n\n### [Primary](../api/doc-blocks/doc-block-primary.mdx)\n\nThe `Primary` block displays the primary (first defined in the stories file) story in a [`Story`](../api/doc-blocks/doc-block-story.mdx) block. It is typically rendered immediately under the title in a docs entry.\n\n![Screenshot of Primary block](../_assets/api/doc-block-primary.png)\n\n### [Source](../api/doc-blocks/doc-block-source.mdx)\n\n<Callout variant=\"info\">\n\n  Accepts parameters in the namespace `parameters.docs.source`.\n\n</Callout>\n\nThe `Source` block is used to render a snippet of source code directly.\n\n![Screenshot of Source block](../_assets/api/doc-block-source.png)\n\n### [Stories](../api/doc-blocks/doc-block-stories.mdx)\n\nThe `Stories` block renders the full collection of stories in a stories file.\n\n![Screenshot of Stories block](../_assets/api/doc-block-stories.png)\n\n### [Story](../api/doc-blocks/doc-block-story.mdx)\n\n<Callout variant=\"info\">\n\n  Accepts parameters in the namespace `parameters.docs.story`.\n  \n</Callout>\n\n[Stories](../writing-stories/index.mdx) are Storybook's fundamental building blocks.\n\nIn Storybook Docs, you can render any of your stories from your CSF files in the context of an MDX file with all annotations (parameters, args, loaders, decorators, play function) applied using the `Story` block.\n\n![Screenshot of Story block](../_assets/api/doc-block-story.png)\n\n### [Subtitle](../api/doc-blocks/doc-block-subtitle.mdx)\n\nThe `Subtitle` block can serve as a secondary heading for your docs entry.\n\n![Screenshot of Subtitle block](../_assets/api/doc-block-title-subtitle-description.png)\n\n### [TableOfContents](../api/doc-blocks/doc-block-tableofcontents.mdx)\n\n<Callout variant=\"info\">\n\n  Accepts parameters in the namespace `parameters.docs.toc`.\n\n</Callout>\n\nThe `TableOfContents` block renders a table of contents for the current documentation page, allowing users to quickly navigate between sections. It appears as a fixed sidebar on the right side of the page.\n\n### [Title](../api/doc-blocks/doc-block-title.mdx)\n\nThe `Title` block serves as the primary heading for your docs entry. It is typically used to provide the component or page name.\n\n![Screenshot of Title block](../_assets/api/doc-block-title-subtitle-description.png)\n\n### [Typeset](../api/doc-blocks/doc-block-typeset.mdx)\n\nThe `Typeset` block helps document the fonts used throughout your project.\n\n![Screenshot of Typeset block](../_assets/api/doc-block-typeset.png)\n\n### [Unstyled](../api/doc-blocks/doc-block-unstyled.mdx)\n\nThe `Unstyled` block is a unique block that disables Storybook's default styling in MDX docs wherever it is added.\n\nBy default, most elements (like `h1`, `p`, etc.) in docs have a few default styles applied to ensure the docs look good. However, sometimes you might want some of your content not to have these styles applied. In those cases, wrap the content with the `Unstyled` block to remove the default styles.\n\n![Screenshot of Unstyled block](../_assets/api/doc-block-unstyled.png)\n\n## Make your own Doc Blocks\n\nStorybook also provides a [`useOf` hook](../api/doc-blocks/doc-block-useof.mdx) to make it easier to create your own blocks that function like the built-in blocks.\n\n## Troubleshooting\n\n### Why can't I use the Doc Blocks inside my stories?\n\nStorybook's Doc Blocks are highly customizable and helpful building blocks to assist you with building your custom documentation. Although most of them enable you to customize them with parameters or globally to create custom [documentation templates](#customizing-the-automatic-docs-page), they are primarily designed for MDX files. For example, if you try to add the `ColorPalette` block to your stories as follows, you'll get an error message when the story loads in Storybook.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-canvas-doc-block-story.md\" />\n\n{/* prettier-ignore-end */}\n\n**Learn more about Storybook documentation**\n\n* [Autodocs](./autodocs.mdx) for creating documentation for your stories\n* [MDX](./mdx.mdx) for customizing your documentation\n* Doc Blocks for authoring your documentation\n* [Publishing docs](./build-documentation.mdx) to automate the process of publishing your documentation\n"
  },
  {
    "path": "docs/writing-docs/index.mdx",
    "content": "---\ntitle: 'How to document components'\nhideRendererSelector: true\nsidebar:\n  order: 4\n  title: Docs\n---\n\nWhen you write component stories during development, you also create basic documentation to revisit later.\n\nStorybook gives you tools to expand this essential documentation with prose and layout that feature your components and stories prominently. That allows you to create UI library usage guidelines, design system sites, and more.\n\n![Docs page](../_assets/writing-docs/docs-completed.png)\n\nIf you're including Storybook in your project for the [first time](../get-started/install.mdx), we provide you with a [documentation page](./autodocs.mdx) (\"Autodocs\" for short), positioned near your stories. It's a baseline template automatically generated, listing your existing stories and relevant metadata.\n\nAdditionally, you can customize this template if needed or create free-form pages for each component using [MDX](./mdx.mdx). In both cases, you’ll use Doc Blocks as the building blocks to create full-featured documentation.\n\nDocs is autoconfigured to work out of the box in most use cases. In some cases, you may need or want to tweak the configuration. Read more about it [here](https://storybook.js.org/addons/@storybook/addon-docs).\n"
  },
  {
    "path": "docs/writing-docs/mdx.mdx",
    "content": "---\ntitle: 'MDX'\nsidebar:\n  order: 2\n  title: MDX\n---\n\n[MDX](https://mdxjs.com/) files mix Markdown and Javascript/JSX to create rich interactive documentation. You can use Markdown’s readable syntax (such as `# heading`) for your documentation, include stories defined in [Component Story Format (CSF)](../api/csf/index.mdx), and freely embed JSX component blocks at any point in the file. All at once.\n\nIn addition, you can write pure documentation pages in MDX and add them to Storybook alongside your stories.\n\n![MDX simple example result](../_assets/writing-docs/mdx-hero.png)\n\n## Basic example\n\nLet's start with an example, `Checkbox.mdx`, combining Markdown with a single story.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"checkbox-story.md\" />\n\n{/* prettier-ignore-end */}\n\nThis MDX file references a story file, `Checkbox.stories.js|ts`, that is written in [Component Story Format (CSF)](../api/csf/index.mdx):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"checkbox-story-csf.md\" />\n\n{/* prettier-ignore-end */}\n\nAnd here's how that's rendered in Storybook:\n\n![MDX simple example result](../_assets/writing-docs/mdx-simple.png)\n\nThere’s a lot going on here. We're writing Markdown, we're writing JSX, and we're also defining and referencing Storybook stories that are drop-in compatible with the entire Storybook ecosystem.\n\nLet’s break it down.\n\n### MDX and CSF\n\nThe first thing you'll notice is that the component documentation is divided into distinct formats: one for writing component stories describing each possible component state and the second one for documenting how to use them. This split leverages the best qualities of each format:\n\n* **CSF** is great for succinctly defining stories (component examples). If you use TypeScript, it also provides type safety and auto-completion.\n* **MDX** is great for writing structured documentation and composing it with interactive JSX elements.\n\n### Anatomy of MDX\n\nAssuming you’re already familiar with writing stories with [CSF](../writing-stories/index.mdx), we can dissect the MDX side of things in greater detail.\n\nThe document consists of a number of blocks separated by blank lines. Since MDX mixes a few different languages together, it uses those blank lines to help distinguish where one starts, and the next begins. Failing to separate blocks by whitespace can cause (sometimes cryptic) parse errors.\n\nGoing through the code blocks in sequence:\n\n{/* prettier-ignore-start */}\n\n```mdx\n{ /* Checkbox.mdx */ }\n```\n\n{/* prettier-ignore-end */}\n\nComments in MDX are JSX blocks that contain JS comments.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-auto-docs-mdx-docs-imports.md\" />\n\n{/* prettier-ignore-end */}\n\nImports the components and stories that will be used in the JSX throughout the rest of the file.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-auto-docs-mdx-docs-meta-block.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  When providing the `of` prop to the `Meta` block, make sure that you're referencing the **full set of exports** of the story file and not the component itself to prevent render issues with the generated documentation.\n</Callout>\n\nThe `Meta` block defines where the document will be placed in the sidebar. In this case, it is adjacent to the Checkbox’s stories. By default, the docs sidebar node is titled `\"Docs\"`, but this can be customized by passing a `name` prop (e.g., `<Meta of={CheckboxStories} name=\"Info\" />`). If you want to place a docs node at an arbitrary point in the navigation hierarchy, you can use the `title` prop (e.g., `<Meta title=\"path/to/node\" />`).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-auto-docs-mdx-docs-definition.md\" />\n\n{/* prettier-ignore-end */}\n\nMDX supports standard markdown ([\"commonmark\"](https://commonmark.org/)) by default and can be extended to support [GitHub Flavored Markdown (GFM)](https://github.github.com/gfm/) and other extensions (see the [Troubleshooting section](#troubleshooting) to learn more about some of the current limitations).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-auto-docs-mdx-docs-story.md\" />\n\n{/* prettier-ignore-end */}\n\nFinally, MDX supports blocks of arbitrary JSX.\n\nIn this case, we are leveraging “Doc Blocks”, a library of documentation components designed to work with Storybook stories to show your stories, your component APIs & controls for interacting with your components inside your documentation, among other utilities.\n\nIn addition to Doc Blocks, MDX can incorporate arbitrary React components, making it a very flexible documentation system. Suppose you want a stylized list of “dos and don’ts” for your component; you can use off-the-shelf components or write your own.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-auto-docs-mdx-docs-dos-donts.md\" />\n\n{/* prettier-ignore-end */}\n\n### Known limitations\n\nWhile MDX supports a variety of runtimes ([React](https://mdxjs.com/packages/react/), [Preact](https://mdxjs.com/packages/preact/), [Vue](https://mdxjs.com/packages/vue/)), Storybook’s implementation is React-only. That means your documentation is rendered in React, while your stories render in the runtime of your choice (React, Vue, Angular, Web Components, Svelte, etc.).\n\n## Setup custom documentation\n\nIn addition, to document your components with MDX, you can also extend it to write other types of content, such as guidelines or best practices on how to use them. To enable custom documentation for your stories with this format, start by updating your Storybook configuration file (i.e., `.storybook/main.js|ts|cjs`).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-auto-docs-main-mdx-config.md\" />\n\n{/* prettier-ignore-end */}\n\nCreate an MDX file to add your custom documentation. Depending on how you want your documentation to render in the UI, you'll need to consider the following use cases.\n\n### Using the `Meta` Doc Block\n\nIf you need to match the component documentation to an existing story, you can configure the [`Meta`](../api/doc-blocks/doc-block-meta.mdx) Doc Block to control how the documentation gets rendered. Out of the box, it allows you to define a custom title or a reference to the story you need to document (i.e., via the `of` prop). For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-auto-docs-baseline-example.md\" />\n\n{/* prettier-ignore-end */}\n\n### Writing unattached documentation\n\nSuppose you're documenting an existing component and only provide the `Meta` Doc Block without additional props or other blocks. In that case, Storybook will consider it as \"unattached\" documentation, or in other words, a \"documentation-only\" page, and it will render it differently in the sidebar navigation menu:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-auto-docs-mdx-docs-docs-only-page.md\" />\n\n{/* prettier-ignore-end */}\n\n![MDX docs only story](../_assets/writing-docs/mdx-documentation-only.png)\n\n### Using the File System\n\nHowever, providing the `Meta` Doc Block may not be required for certain use cases, such as standalone pages or even as guidelines for testing your components. In that case, you can safely omit it. Storybook will instead rely on the file's physical location to place the documentation in the sidebar, overriding any pre-existent [auto-generated](./autodocs.mdx) documentation with your own. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-auto-docs-custom-file.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n\n  If you're overriding an existing auto-generated documentation page enabled via [`tags`](./autodocs.mdx#setup-automated-docs) configuration property, we recommend removing it to avoid errors.\n  \n</Callout>\n\nOnce the custom MDX documentation is loaded, Storybook will infer the title and location using the same heuristic rules to generate [auto-title stories](../configure/user-interface/sidebar-and-urls.mdx#csf-30-auto-titles) and render it in the sidebar as a `Docs` entry.\n\n#### Working with standalone documentation pages\n\nWriting standalone documentation pages is a common use case that applies not only on a per-component but also on a per-project basis. For example, you might want to document your project's onboarding process with instructions on using it. To do so, you can create a new MDX file containing your documentation using a similar structure and content:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-auto-docs-standalone-page.md\" />\n\n{/* prettier-ignore-end */}\n\n![MDX guidelines page](../_assets/writing-docs/mdx-standalone-page.png)\n\nWhen Storybook loads the documentation, it will infer the placement of the page in the sidebar navigation menu using the file's physical location and render it as a `Docs` entry.\n\n### Fully control custom documentation\n\nDocumentation can be expensive to maintain and keep up to date when applied to every project component. To help simplify this process, Storybook provides a set of useful UI components (i.e., Doc Blocks) to help cover more advanced cases. If you need additional content, use them to help create your custom documentation.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-auto-docs-starter-example.md\" />\n\n{/* prettier-ignore-end */}\n\n### Working with multiple components\n\nIf you need to document multiple components in a single documentation page, you can reference them directly inside your MDX file. Internally, Storybook looks for the story metadata and composes it alongside your existing documentation. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-auto-docs-mdx-file.md\" />\n\n{/* prettier-ignore-end */}\n\n### Generate documentation from Markdown\n\nIf you need to extend your documentation with additional content written in Markdown, you can use the `Markdown` Doc Block to import the available content, and Storybook will render it alongside your existing documentation. For example, if you have a `CHANGELOG.md` file, you can import it and render it in your documentation page as follows:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-custom-docs-markdown.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  The `Markdown` Doc Block provides additional configuration options to customize the rendering of your documentation. For more information, refer to the [API documentation](../api/doc-blocks/doc-block-markdown.mdx).\n</Callout>\n\n![Changelog markdown in an MDX story](../_assets/writing-docs/mdx-markdown-docs-import.png)\n\n### Linking to other stories and pages\n\nAnother way to improve documentation is by linking to other stories and pages. Suppose you already have a component story with the following unique identifier, `some--id`, and you want to link it to your documentation page. In that case, you can use the `path` query string to redirect to the documentation entry related to the story:\n\n```md\n[Go to specific documentation page](?path=/docs/some--id)\n```\n\nInstead, if you need to target a specific documentation section, you can adjust the link to point at it. For example:\n\n```md\n[Go to the conclusion of the documentation page](?path=/docs/some--id#conclusion)\n```\n\nHowever, cross-linking documentation isn't restricted to documentation pages. You can adjust the `path` query and supply the story's unique identifier if you need to reference a specific one. For example:\n\n{/*This redirects to the **Canvas** tab of the story: */}\n\n```md\n[Go to specific story canvas](?path=/story/some--id)\n```\n\n{/*You can also use anchors to target a specific section of a page: */}\n\n<Callout variant=\"info\" icon=\"💡\">\n\nApplying this pattern with the [Controls](../essentials/controls.mdx) feature, all anchors will be ignored in Canvas based on how Storybook handles URLs to track the args values.\n\n</Callout>\n\n## Troubleshooting\n\n### Markdown tables aren't rendering correctly\n\nIf you're extending your documentation to include specific features (e.g., tables, footnotes), you may run into some issues rendering them correctly using the current MDX version supported by Storybook. We recommend enabling the [`remark-gfm`](https://github.com/remarkjs/remark-gfm) plugin in your configuration file (i.e., [`.storybook/main.js|ts`](../configure/index.mdx)) to render them correctly.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-main-config-remark-options.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  The [`remark-gfm`](https://github.com/remarkjs/remark-gfm) package is not included by default with Storybook and must be installed separately as a development dependency. To learn more about how to use it and the other breaking changes introduced by MDX, refer to the [GFM guide](https://mdxjs.com/guides/gfm/) and the [migration guide](https://mdxjs.com/migrating/v2/) provided by the MDX team for more information.\n</Callout>\n\n### The MDX documentation doesn't render in my environment\n\nAs Storybook relies on [MDX 3](https://mdxjs.com/) to render documentation, some technical limitations may prevent you from migrating to this version. If that's the case, we've prepared a set of instructions to help you transition to this new version.\n\n#### Storybook doesn't create documentation for my component stories\n\nIf you run into a situation where Storybook is not able to detect and render the documentation for your component stories, it may be due to a misconfiguration in your Storybook. Check your configuration file (i.e., `.storybook/main.js|ts`) and ensure the `stories` configuration element provides the correct path to your stories location (e.g., `../src/**/*.stories.@(js|jsx|mjs|ts|tsx)`).\n\n### The migration seems flaky and keeps failing\n\nBy default, running the [migration](../releases/upgrading.mdx) command will prompt you to update the existing MDX files in your project according to the MDX version supported by Storybook. However, this might be a disruptive process, specifically if you're upgrading from a previous version of Storybook where you were using the legacy MDX format. To help you troubleshoot those issues, we've prepared some recommendations that might help you.\n\nStart by running the following command inside your project directory:\n\n```shell\nnpx @hipster/mdx2-issue-checker\n```\n\n<Callout variant=\"info\" icon=\"💡\">\n  Depending on the volume, you may be required to run the command multiple times to fix all the issues.\n</Callout>\n\nWhen it finishes, it will output the list of files causing issues. You can then use this information to fix the problems manually.\n\nAdditionally, if you're working with VSCode, you can add the [MDX extension](https://marketplace.visualstudio.com/items?itemName=unifiedjs.vscode-mdx) and enable MDX experimental support for linting, type checking, and auto-completion by adding the following to your user settings:\n\n```json\n{\n  \"mdx.server.enable\": true\n}\n```\n\nIf you're still encountering issues, we recommend reaching out to the community using the default communication channels (e.g., [GitHub discussions](https://github.com/storybookjs/storybook/discussions/new?category=help)).\n\n### The controls are not updating the story within the MDX documentation page\n\nIf you turned off inline rendering for your stories via the [`inline`](../api/doc-blocks/doc-block-story.mdx#inline) configuration option, you would run into a situation where the associated controls are not updating the story within the documentation page. This is a known limitation of the current implementation and will be addressed in a future release.\n\n### The React version used is unexpected\n\nFor most projects, Storybook's addon-docs uses the React version listed in your project's dependencies. If it does not find one, it will use React 18.2.0. There are two exceptions to this:\n\n* Preact projects will always use React 17\n* Next.js projects will always use the canary version that comes with the Next.js version installed, regardless of which React version is listed in the project’s dependencies.\n\nIf you're having issues with the React version used, you may need to re-create your project's `node_modules` folder to ensure the correct version is used.\n\n**Learn more about Storybook documentation**\n\n* [Autodocs](./autodocs.mdx) for creating documentation for your stories\n* MDX for customizing your documentation\n* [Doc Blocks](./doc-blocks.mdx) for authoring your documentation\n* [Publishing docs](./build-documentation.mdx) to automate the process of publishing your documentation\n"
  },
  {
    "path": "docs/writing-stories/args.mdx",
    "content": "---\ntitle: 'Args'\nsidebar:\n  order: 1\n  title: Args\n---\n\n<YouTubeCallout id=\"0gOfS6K0x0E\" title=\"Build better UIs with Storybook Args\" />\n\nA story is a component with a set of arguments that define how the component should render. “Args” are Storybook’s mechanism for defining those arguments in a single JavaScript object. Args can be used to dynamically change props, slots, styles, inputs, etc. It allows Storybook and its addons to live edit components. You *do not* need to modify your underlying component code to use args.\n\nWhen an arg’s value changes, the component re-renders, allowing you to interact with components in Storybook’s UI via addons that affect args.\n\nLearn how and why to write stories in [the introduction](./index.mdx). For details on how args work, read on.\n\n## Args object\n\nThe `args` object can be defined at the [story](#story-args), [component](#component-args) and [global level](#global-args). It is a JSON serializable object composed of string keys with matching valid value types that can be passed into a component for your framework.\n\n## Story args\n\n<IfRenderer renderer=\"svelte\">\n\n  To define the args of a single story, use the `args` property in the `Story` component if you are using Svelte CSF with the native templating syntax, or use the `args` key on a CSF story file:\n\n</IfRenderer>\n\n<If notRenderer=\"svelte\">\n\n  To define the args of a single story, use the `args` CSF story key:\n\n</If>\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-with-args.md\" />\n\n{/* prettier-ignore-end */}\n\nThese args will only apply to the story for which they are attached, although you can [reuse](./build-pages-with-storybook.mdx#args-composition-for-presentational-screens) them via JavaScript object reuse:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-primary-long-name.md\" />\n\n{/* prettier-ignore-end */}\n\nIn the above example, we use the [object spread](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) feature of ES 2015.\n\n## Component args\n\n<IfRenderer renderer=\"svelte\">\n\n  You can also define args at the component level; they will apply to all the component's stories unless you overwrite them. To do so, use the `args` property in the `defineMeta` function of a Svelte CSF story file or via the `args` key on the default CSF export:\n\n</IfRenderer>\n\n<If notRenderer=\"svelte\">\n\n  You can also define args at the component level; they will apply to all the component's stories unless you overwrite them. To do so, use the `args` key on the `default` CSF export:\n\n</If>\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-component-args-primary.md\" />\n\n{/* prettier-ignore-end */}\n\n## Global args\n\nYou can also define args at the global level; they will apply to every component's stories unless you overwrite them. To do so, define the `args` property in the default export of `preview.js|ts`:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"args-in-preview.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  For most uses of global args, [globals](../essentials/toolbars-and-globals.mdx) are a better tool for defining globally-applied settings, such as a theme. Using globals enables users to change the value with the toolbar menu.\n</Callout>\n\n## Args composition\n\nYou can separate the arguments to a story to compose in other stories. Here's how you can combine args for multiple stories of the same component.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-primary-composition.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  If you find yourself re-using the same args for most of a component's stories, you should consider using [component-level args](#component-args).\n</Callout>\n\nArgs are useful when writing stories for composite components that are assembled from other components. Composite components often pass their arguments unchanged to their child components, and similarly, their stories can be compositions of their child components stories. With args, you can directly compose the arguments:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"page-story.md\" />\n\n{/* prettier-ignore-end */}\n\n## Args can modify any aspect of your component\n\nYou can use args in your stories to configure the component's appearance, similar to what you would do in an application. For example, here's how you could use a `footer` arg to populate a child component:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"page-story-slots.md\" />\n\n{/* prettier-ignore-end */}\n\n## Setting args through the URL\n\nYou can also override the set of initial args for the active story by adding an `args` query parameter to the URL. Typically, you would use [Controls](../essentials/controls.mdx) to handle this. For example, here's how you could set a `size` and `style` arg in the Storybook's URL:\n\n```\n?path=/story/avatar--default&args=style:rounded;size:100\n```\n\nAs a safeguard against [XSS](https://owasp.org/www-community/attacks/xss/) attacks, the arg's keys and values provided in the URL are limited to alphanumeric characters, spaces, underscores, and dashes. Any other types will be ignored and removed from the URL, but you can still use them with the Controls panel and [within your story](#mapping-to-complex-arg-values).\n\nThe `args` param is always a set of `key: value` pairs delimited with a semicolon `;`. Values will be coerced (cast) to their respective `argTypes` (which may have been automatically inferred). Objects and arrays are supported. Special values `null` and `undefined` can be set by prefixing with a bang `!`. For example, `args=obj.key:val;arr[0]:one;arr[1]:two;nil:!null` will be interpreted as:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-args-url-params-converted.md\" />\n\n{/* prettier-ignore-end */}\n\nSimilarly, special formats are available for dates and colors. Date objects will be encoded as `!date(value)` with value represented as an ISO date string. Colors are encoded as `!hex(value)`, `!rgba(value)` or `!hsla(value)`. Note that rgb(a) and hsl(a) should not contain spaces or percentage signs in the URL.\n\nArgs specified through the URL will extend and override any default values of args set on the story.\n\n<IfRenderer renderer=\"react\">\n  ## Setting args from within a story\n\n  Interactive components often need to be controlled by their containing component or page to respond to events, modify their state and reflect those changes in the UI. For example, when a user toggles a switch component, the switch should be checked, and the arg shown in Storybook should reflect the change. To enable this, you can use the `useArgs` API exported by `storybook/preview-api`:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"page-story-args-within-story.md\" />\n\n  {/* prettier-ignore-end */}\n\n  <Callout variant=\"warning\">\n\n    If you're using Storybook's hooks API in the story's render function, **do not** mix them with React's hooks such as `useState`, `useEffect`, or `useRef`. This is because side effects and re-rendering triggered by React's hooks do not run through Storybook's hook context, which can cause an error on re-render. To manage state and side effects within a story, you must use Storybook's equivalent hooks, such as `useState`, `useEffect`, and `useRef` from `storybook/preview-api`.\n  \n  </Callout>\n</IfRenderer>\n\n## Mapping to complex arg values\n\nComplex values such as JSX elements cannot be serialized to the manager (e.g., the Controls panel) or synced with the URL. Arg values can be \"mapped\" from a simple string to a complex type using the `mapping` property in `argTypes` to work around this limitation. It works in any arg but makes the most sense when used with the `select` control type.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"arg-types-mapping.md\" />\n\n{/* prettier-ignore-end */}\n\nNote that `mapping` does not have to be exhaustive. If the arg value is not a property of `mapping`, the value will be used directly. Keys in `mapping` always correspond to arg *values*, not their index in the `options` array.\n\n<details>\n  <summary>Using args in addons</summary>\n\n  If you are [writing an addon](../addons/writing-addons.mdx) that wants to read or update args, use the `useArgs` hook exported by `storybook/manager-api`:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"args-usage-with-addons.md\" />\n\n  {/* prettier-ignore-end */}\n</details>"
  },
  {
    "path": "docs/writing-stories/build-pages-with-storybook.mdx",
    "content": "---\ntitle: 'Building pages with Storybook'\nsidebar:\n  order: 9\n  title: Building pages and screens\n---\n\nStorybook helps you build any component, from small “atomic” components to composed pages. But as you move up the component hierarchy toward the page level, you deal with more complexity.\n\nThere are many ways to build pages in Storybook. Here are common patterns and solutions.\n\n* Pure presentational pages.\n* Connected components (e.g., network requests, context, browser environment).\n\n## Pure presentational pages\n\nTeams at the BBC, The Guardian, and the Storybook maintainers themselves build pure presentational pages. If you take this approach, you don't need to do anything special to render your pages in Storybook.\n\nIt's straightforward to write components to be fully presentational up to the screen level. That makes it easy to show in Storybook. The idea is that you do all the messy “connected” logic in a single wrapper component in your app outside of Storybook. You can see an example of this approach in the [Data](https://storybook.js.org/tutorials/intro-to-storybook/react/en/data/) chapter of the Intro to Storybook tutorial.\n\nThe benefits:\n\n* Easy to write stories once components are in this form.\n* All the data for the story is encoded in the args of the story, which works well with other parts of Storybook's tooling (e.g. [controls](../essentials/controls.mdx)).\n\nThe downsides:\n\n* Your existing app may not be structured in this way, and it may be difficult to change it.\n\n* Fetching data in one place means that you need to drill it down to the components that use it. This can be natural in a page that composes one big GraphQL query (for instance), but other data fetching approaches may make this less appropriate.\n\n* It's less flexible if you want to load data incrementally in different places on the screen.\n\n### Args composition for presentational screens\n\nWhen you are building screens in this way, it is typical that the inputs of a composite component are a combination of the inputs of the various sub-components it renders. For instance, if your screen renders a page layout (containing details of the current user), a header (describing the document you are looking at), and a list (of the subdocuments), the inputs of the screen may consist of the user, document and subdocuments.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"simple-page-implementation.md\" />\n\n{/* prettier-ignore-end */}\n\nIn such cases, it is natural to use [args composition](./args.mdx#args-composition) to build the stories for the page based on the stories of the sub-components:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"page-story-with-args-composition.md\" />\n\n{/* prettier-ignore-end */}\n\nThis approach is beneficial when the various subcomponents export a complex list of different stories. You can pick and choose to build realistic scenarios for your screen-level stories without repeating yourself. Your story maintenance burden is minimal by reusing the data and taking a Don't-Repeat-Yourself(DRY) philosophy.\n\n## Mocking connected components\n\nConnected components are components that depend on external data or services. For example, a full page component is often a connected component. When you render a connected component in Storybook, you need to mock the data or modules that the component depends on. There are various layers in which you can do that.\n\n### [Mocking imports](./mocking-data-and-modules/mocking-modules.mdx)\n\nComponents can depend on modules that are imported into the component file. These can be from external packages or internal to your project. When rendering those components in Storybook or testing them, you may want to mock those modules to control their behavior.\n\n### [Mocking API Services](./mocking-data-and-modules/mocking-network-requests.mdx)\n\nFor components that make network requests (e.g., fetching data from a REST or GraphQL API), you can mock those requests in your stories.\n\n### [Mocking providers](./mocking-data-and-modules/mocking-providers.mdx)\n\nComponents can receive data or configuration from context providers. For example, a styled component might access its theme from a ThemeProvider or Redux uses React context to provide components access to app data. You can mock a provider and the value it's providing and wrap your component with it in your stories.\n\n<IfRenderer renderer={['react', 'solid']}>\n  ### Avoiding mocking dependencies\n\n  It's possible to avoid mocking the dependencies of connected \"container\" components entirely by passing them around via props or React context. However, it requires a strict split of the container and presentational component logic. For example, if you have a component responsible for data fetching logic and rendering DOM, it will need to be mocked as previously described.\n\n  It’s common to import and embed container components amongst presentational components. However, as we discovered earlier, we’ll likely have to mock their dependencies or the imports to render them within Storybook.\n\n  Not only can this quickly grow to become a tedious task, but it’s also challenging to mock container components that use local states. So, instead of importing containers directly, a solution to this problem is to create a React context that provides the container components. It allows you to freely embed container components as usual, at any level in the component hierarchy without worrying about subsequently mocking their dependencies; since we can swap out the containers themselves with their mocked presentational counterpart.\n\n  We recommend dividing context containers up over specific pages or views in your app. For example, if you had a `ProfilePage` component, you might set up a file structure as follows:\n\n  ```\n  ProfilePage.js\n  ProfilePage.stories.js\n  ProfilePageContainer.js\n  ProfilePageContext.js\n  ```\n\n  <Callout variant=\"info\" icon=\"💡\">\n    It’s also often helpful to set up a “global” container context (perhaps named `GlobalContainerContext`) for container components that may be rendered on every page of your app and add them to the top level of your application. While it’s possible to place every container within this global context, it should only provide globally required containers.\n  </Callout>\n\n  Let’s look at an example implementation of this approach.\n\n  First, create a React context, and name it `ProfilePageContext`. It does nothing more than export a React context:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"mock-context-create.md\" />\n\n  {/* prettier-ignore-end */}\n\n  `ProfilePage` is our presentational component. It will use the `useContext` hook to retrieve the container components from `ProfilePageContext`:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"mock-context-in-use.md\" />\n\n  {/* prettier-ignore-end */}\n\n  #### Mocking containers in Storybook\n\n  In the context of Storybook, instead of providing container components through context, we’ll instead provide their mocked counterparts. In most cases, the mocked versions of these components can often be borrowed directly from their associated stories.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"mock-context-container.md\" />\n\n  {/* prettier-ignore-end */}\n\n  <Callout variant=\"info\">\n    If the same context applies to all `ProfilePage` stories, we can use a [decorator](./decorators.mdx).\n  </Callout>\n\n  #### Providing containers to your application\n\n  Now, in the context of your application, you’ll need to provide `ProfilePage` with all of the container components it requires by wrapping it with `ProfilePageContext.Provider`:\n\n  For example, in Next.js, this would be your `pages/profile.js` component.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"mock-context-container-provider.md\" />\n\n  {/* prettier-ignore-end */}\n\n  #### Mocking global containers in Storybook\n\n  If you’ve set up `GlobalContainerContext`, you’ll need to set up a decorator within Storybook’s `preview.js` to provide context to all stories. For example:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"mock-context-container-global.md\" />\n\n  {/* prettier-ignore-end */}\n</IfRenderer>\n"
  },
  {
    "path": "docs/writing-stories/decorators.mdx",
    "content": "---\ntitle: 'Decorators'\nsidebar:\n  order: 3\n  title: Decorators\n---\n\nA decorator is a way to wrap a story in extra “rendering” functionality. Many addons define decorators to augment your stories with extra rendering or gather details about how your story renders.\n\nWhen writing stories, decorators are typically used to wrap stories with extra markup or context mocking.\n\n## Wrap stories with extra markup\n\n<IfRenderer renderer=\"svelte\">\n\n  Some components require a “harness” to render in a useful way. For instance, if a component runs right up to its edges, you might want to space it inside Storybook. With Svelte, you'll need to take additional steps to set it up properly.\n\n  ![Story without padding](../_assets/writing-stories/decorators-no-padding.png)\n\n  Start by creating a new Svelte component that will act as a decorator. This component will wrap your story and provide the required spacing or layout elements.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"margindecorator.md\" />\n\n  {/* prettier-ignore-end */}\n\n  Update your story to include the component and reference it to apply the required spacing or other functionality for all its stories.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"your-component-with-decorator.md\" />\n\n  {/* prettier-ignore-end */}\n\n  If you need to pass props to the component returned by your decorator, you can do so by returning an object with `Component` and `props` keys in the decorator function. This allows you to customize the behavior of the decorator based on the [story's context](#context-for-mocking).\n\n  <CodeSnippets path=\"your-component-with-decorator-with-props.md\" />\n\n</IfRenderer>\n\n<If notRenderer=\"svelte\">\n\n  Some components require a “harness” to render in a useful way. For instance, if a component runs right up to its edges, you might want to space it inside Storybook. Use a decorator to add spacing for all stories of the component.\n\n  ![Story without padding](../_assets/writing-stories/decorators-no-padding.png)\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"your-component-with-decorator.md\" />\n\n  {/* prettier-ignore-end */}\n\n</If>\n\n![Story with padding](../_assets/writing-stories/decorators-padding.png)\n\n## “Context” for mocking\n\nThe second argument to a decorator function is the **story context** which contains the properties:\n\n* `args` - the story arguments. You can use some [`args`](./args.mdx) in your decorators and drop them in the story implementation itself.\n* `argTypes`- Storybook's [argTypes](../api/arg-types.mdx) allow you to customize and fine-tune your stories [`args`](./args.mdx).\n* `globals` - Storybook-wide [globals](../essentials/toolbars-and-globals.mdx#globals). In particular you can use the [toolbars feature](../essentials/toolbars-and-globals.mdx#global-types-and-the-toolbar-annotation) to allow you to change these values using Storybook’s UI.\n* `hooks` - Storybook's API hooks (e.g., `useArgs`, `useGlobals`). These are available in both decorators and story render functions. When using these hooks in a render function alongside framework hooks (e.g., React's `useState`, `useEffect`), use Storybook's hook equivalents from `storybook/preview-api` instead to avoid errors on re-render.\n* `parameters`- the story's static metadata, most commonly used to control Storybook's behavior of features and addons.\n* `viewMode`- Storybook's current active window (e.g., canvas, docs).\n\nThis context can be used to adjust the behavior of your decorator based on the story's arguments or other metadata. For example, you could create a decorator that allows you to optionally apply a layout to the story, by defining `parameters.pageLayout = 'page'` (or `'page-mobile'`):\n:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"decorator-parameterized-in-preview.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  For another example, see the section on [configuring the mock provider](./mocking-data-and-modules/mocking-providers.mdx#configuring-the-mock-provider), which demonstrates how to use the same technique to change which theme is provided to the component.\n</Callout>\n\n<IfRenderer renderer=\"vue\">\n\n### Reactive globals\n\nTo ensure `globals` in Vue decorators are fully reactive, you must pass them through the `setup` function. You can also compute derived values with Vue's `computed` function.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"decorator-with-reactive-globals.md\" />\n\n{/* prettier-ignore-end */}\n\n### Preview API hooks\n\nThe same applies to Storybook hooks you want to call in your decorator. For instance, this decorator increments a counter used by its decorated story.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"decorator-with-updateArgs.md\" />\n\n{/* prettier-ignore-end */}\n\n</IfRenderer>\n\n### Using decorators to provide data\n\nIf your components are “connected” and require side-loaded data to render, you can use decorators to provide that data in a mocked way without having to refactor your components to take that data as an arg. There are several techniques to achieve this. Depending on exactly how you are loading that data. Read more in the [building pages in Storybook](./build-pages-with-storybook.mdx) section.\n\n## Story decorators\n\n<IfRenderer renderer=\"svelte\">\n\n  To define a decorator for a single story, use the `decorators` property in the `Story` component if you are using Svelte CSF with the native templating syntax, or use the `decorators` key on a CSF named export:\n\n</IfRenderer>\n\n<If notRenderer=\"svelte\">\n\n  To define a decorator for a single story, use the `decorators` key on a named export:\n\n</If>\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-decorator.md\" />\n\n{/* prettier-ignore-end */}\n\nIt is useful to ensure that the story remains a “pure” rendering of the component under test and that any extra HTML or components are used only as decorators. In particular the [Source](../api/doc-blocks/doc-block-source.mdx) Doc Block works best when you do this.\n\n## Component decorators\n\n<IfRenderer renderer=\"svelte\">\n\n  To define a decorator for all component stories, include the `decorators` property in the `defineMeta` function of a Svelte CSF story file. Alternatively, use the `decorators` key on the default CSF export:\n\n</IfRenderer>\n\n<If notRenderer=\"svelte\">\n\n  To define a decorator for all stories of a component, use the `decorators` key of the default CSF export:\n\n</If>\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-component-decorator.md\" />\n\n{/* prettier-ignore-end */}\n\n## Global decorators\n\nWe can also set a decorator for **all stories** via the `decorators` export of your [`.storybook/preview.js|ts`](../configure/index.mdx#configure-story-rendering) file (this is the file where you configure all stories):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-global-decorator.md\" />\n\n{/* prettier-ignore-end */}\n\n## Decorator inheritance\n\nLike parameters, decorators can be defined globally, at the component level, and for a single story (as we’ve seen).\n\nAll decorators relevant to a story will run in the following order once the story renders:\n\n* Global decorators, in the order they are defined\n* Component decorators, in the order they are defined\n* Story decorators, in the order they are defined, starting from the innermost decorator and working outwards and up the hierarchy in the same order\n"
  },
  {
    "path": "docs/writing-stories/index.mdx",
    "content": "---\ntitle: 'How to write stories'\nsidebar:\n  order: 2\n  title: Stories\n---\n\n<If renderer=\"svelte\">\n\n  A story captures the rendered state of a UI component. Given a set of arguments, it can be a simple object with annotations or a component that describes its behavior and appearance.\n\n</If>\n\n<If notRenderer=\"svelte\">\n\n  A story captures the rendered state of a UI component. It's an object with annotations that describe the component's behavior and appearance given a set of arguments.\n\n</If>\n\nStorybook uses the generic term arguments (args for short) when talking about React’s `props`, Vue’s `props`, Angular’s `@Input`, and other similar concepts.\n\n## Where to put stories\n\nA component’s stories are defined in a story file that lives alongside the component file. The story file is for development-only, and it won't be included in your production bundle. In your filesystem, it looks something like this:\n\n```\ncomponents/\n├─ Button/\n│  ├─ Button.js | ts | jsx | tsx | vue | svelte\n│  ├─ Button.stories.js | ts | jsx | tsx | svelte\n```\n\n## Component Story Format\n\n<If renderer=\"svelte\">\n\n  We can define stories according to the [Component Story Format](../api/csf/index.mdx) (CSF), an ES6 module-based standard that is easy to write and portable between tools, or rely on the community-led project [`Svelte CSF`](https://storybook.js.org/addons/@storybook/addon-svelte-csf) which provides a similar experience. \n   \n  With Svelte CSF, the essential elements are the `defineMeta` function, which describes the component, and the `Story` component, which describes the stories. This pattern is different from the standard CSF, which uses a [default export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export#Using_the_default_export) and [named exports](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export#Using_named_exports) to apply the same concepts.\n  \n</If>\n\n<If notRenderer=\"svelte\">\n\n  We define stories according to the [Component Story Format](../api/csf/index.mdx) (CSF), an ES6 module-based standard that is easy to write and portable between tools.\n\n  The key ingredients are the meta (or [default export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export#Using_the_default_export)) that describes the component, and [named exports](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export#Using_named_exports) that describe the stories.\n\n</If>\n\n### Default export\n\n<If renderer=\"svelte\">\n\n  The `defineMeta` function in Svelte CSF with native templating syntax controls how Storybook lists your stories and provides information used by addons. However, if you're not using this story format and relying on standard CSF, use the *default* export to achieve the same result. Below is an example of a story file with both approaches:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"button-story-default-export-with-component.md\" />\n\n  {/* prettier-ignore-end */}\n\n</If>\n\n<If notRenderer=\"svelte\">\n\n  The *default* export metadata controls how Storybook lists your stories and provides information used by addons. For example, here’s the meta (or default export) for a story file `Button.stories.js|ts`:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"button-story-default-export-with-component.md\" />\n\n  {/* prettier-ignore-end */}\n\n  <Callout variant=\"info\">\n\n    Starting with Storybook version 7.0, story titles are analyzed statically as part of the build process. The *default* export must contain a `title` property that can be read statically or a `component` property from which an automatic title can be computed. Using the `id` property to customize your story URL must also be statically readable.\n  \n  </Callout>\n\n</If>\n\n### Defining stories\n\n<If renderer=\"svelte\">\n \n  If you're using Svelte CSF, define your stories with the `Story` component, otherwise use the named exports of a standard CSF file. We recommend you use UpperCamelCase for your story exports. Here’s how to render `Button` in the “primary” state and export a story called `Primary` using both methods.\n\n</If>\n\n<If notRenderer=\"svelte\">\n\n  Use the *named* exports of a CSF file to define your component’s stories. We recommend you use UpperCamelCase for your story exports. Here’s how to render `Button` in the “primary” state and export a story called `Primary`.\n\n</If>\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-with-args.md\" />\n\n{/* prettier-ignore-end */}\n\n<If renderer=\"svelte\">\n\nUnlike regular CSF, when using Svelte CSF, you cannot use [`args`](./args.mdx) for children. Instead, you pass children in-between the opening and closing `Story` tags and it will be passed to the component as the `children` snippet prop.\n\n```svelte title=\"Alert.stories.svelte\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n \n  import Alert from './Alert.svelte';\n \n  const { Story } = defineMeta({\n    component: Alert,\n  });\n</script>\n\n{/* Renders <Alert>Alert text</Alert> */}\n<Story name=\"Alert with children\">\n  Alert text\n</Story>\n```\n\nIf you want to render the children as the entire story itself, you can use the `asChild` prop of the `Story` component, which will ignore the default component rendering and render the children directly.\n\n```svelte title=\"Button.stories.svelte\"\n<Story\n  name=\"Default Button in alert\"\n  asChild\n/>\n  <Alert>\n    Alert text\n    <Button />\n  </Alert>\n</Story>\n```\n\n<Callout variant=\"warning\">\n\nNote that features which require `args`, like [Controls](../essentials/controls.mdx), will not work when using `asChild`. You can customize the rendering of a story and retain the ability to use `args` by using a [custom render function](#custom-rendering).\n\n</Callout>\n\n</If>\n\n#### Custom rendering\n\n<If renderer=\"svelte\">\n \nBy default, stories will render the component defined in the `defineMeta` call (for Svelte CSF) or in the default export (for CSF), with the `args` passed to it.\n\nIf you need to customize the rendering of your story, you can provide a snippet (for Svelte CSF) or a `render` function (for CSF) that accepts `args` and renders whatever you need.\n\nFor example, if you want to render a `Button` inside an `Alert`:\n\n```svelte title=\"Button.stories.svelte\"\n<Story\n  name=\"Primary in alert\"\n  args={{\n    label: 'Button',\n    primary: true,\n  }}>\n  {#snippet template(args)}\n    <Alert>\n      Alert text\n      <Button {...args} />\n    </Alert>\n  {/snippet}\n</Story>\n```\n\n<Callout variant=\"info\">\n\nNote how the template snippet or `render` function spreads `args` onto the Button component. This ensures that features like [Controls](../essentials/controls.mdx) will work as expected, allowing you to dynamically change the Button's properties in the Storybook UI.\n\n</Callout>\n\nYou can re-use the same render function across stories by applying it at the meta level. For Svelte CSF, this can be done by defining the template snippet outside of the story and assigning it to the `render` property of the `defineMeta` function. For CSF, you can define a `render` function in the meta (or default export).\n\n```svelte title=\"Button.stories.svelte\"\n<script module>\n  import { defineMeta } from '@storybook/addon-svelte-csf';\n  import Button from './Button.svelte';\n\n  const { Story } = defineMeta({\n    component: Button,\n    render: template,\n  });\n</script>\n\n{#snippet template(args)}\n  <Alert>\n    Alert text\n    <Button {...args} />\n  </Alert>\n{/snippet}\n\n<Story name=\"Default in alert\" args={{ label: 'Button' }} />\n\n<Story name=\"Primary in alert\" args={{ label: 'Button', primary: true }} />\n```\n\nWhatever you define at the meta level can be overridden at the story level, so you can still customize the rendering of individual stories if needed.\n\nFinally, `render` functions and template snippets receive a second `context` argument, which contains all other details for the story, including [`parameters`](./parameters.mdx), [`globals`](../essentials/toolbars-and-globals.mdx), and more.\n\n</If>\n\n<If notRenderer=\"svelte\">\n\nBy default, stories will render the component defined in the meta (or default export), with the `args` passed to it. If you need to render something else, you can provide a function to the `render` property that returns the desired output.\n\nFor example, if you want to render a `Button` inside an `Alert`, you can define a custom render function like this:\n\n<CodeSnippets path=\"render-custom-in-story.md\" />\n\n<Callout variant=\"info\">\n\nNote how the `render` function spreads `args` onto the Button component. This ensures that features like [Controls](../essentials/controls.mdx) will work as expected, allowing you to dynamically change the Button's properties in the Storybook UI.\n\n</Callout>\n\nYou can re-use the same render function across stories by applying it at the meta level:\n\n<CodeSnippets path=\"render-custom-in-meta.md\" />\n\nWhatever you define at the meta level can be overridden at the story level, so you can still customize the rendering of individual stories if needed.\n\nFinally, `render` functions receive a second `context` argument, which contains all other details for the story, including [`parameters`](./parameters.mdx), [`globals`](../essentials/toolbars-and-globals.mdx), and more.\n\n</If>\n\n<IfRenderer renderer=\"react\">\n  #### Working with React Hooks\n\n  [React Hooks](https://react.dev/reference/react) are convenient helper methods to create components using a more streamlined approach. You can use them while creating your component's stories if you need them, although you should treat them as an advanced use case. We **recommend** [args](./args.mdx) as much as possible when writing your own stories. As an example, here’s a story that uses React Hooks to change the button's state:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"button-story.md\" />\n\n  {/* prettier-ignore-end */}\n</IfRenderer>\n\n<IfRenderer renderer=\"solid\">\n  #### Working with Solid Signals\n\n  [Solid Signals](https://docs.solidjs.com/concepts/intro-to-reactivity) are convenient helper methods to create components using a more streamlined approach. You can use them while creating your component's stories if you need them, although you should treat them as an advanced use case. We **recommend** [args](./args.mdx) as much as possible when writing your own stories. As an example, here’s a story that uses Solid Signals to change the button's state:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"button-story.md\" />\n\n  {/* prettier-ignore-end */}\n</IfRenderer>\n\n### Rename stories\n\nBy default, Storybook uses the name of the story export as the basis for the story name. However, you can customize the name of your story by adding a `name` property to the story object. This is useful when you want to provide a more descriptive or user-friendly name for your story.\n\n<If renderer=\"svelte\">\n\nIf you're using Svelte CSF, the `name` property is usually fairly descriptive and user-friendly already, so there is little need for renaming. However, the `name` is used as the basis for the export name, which must be unique within a file. In rare cases, this can lead to naming conflicts. For example, stories with the names \"Primary\" and \"Primary!\" would both be transformed to the \"Primary\" export name. To avoid this, you can use the `exportName` property to specify a unique export name for your story. `exportName` is also helpful to provide a more useful named export when re-using stories, e.g. as [portable stories](../api/portable-stories/portable-stories-vitest.mdx).\n\n</If>\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-rename-story.md\" />\n\n{/* prettier-ignore-end */}\n\n<If notRenderer=\"svelte\">\n\nYour story will now be shown in the sidebar with the given text.\n\n</If>\n\n{/* Maintaining a prior heading */}\n\n<a id=\"using-args\" />\n\n## How to write stories\n\n\n<IfRenderer renderer=\"svelte\">\n\n  With Svelte, stories can be defined as objects using standard CSF or with Svelte CSF's `Story` component. Both methods describe how to render a component. You can have multiple stories per component, and those stories can build upon one another. For example, we can add Secondary and Tertiary stories based on our Primary story above.\n\n</IfRenderer>\n\n<If notRenderer=\"svelte\">\n\n  A story is an object that describes how to render a component. You can have multiple stories per component, and those stories can build upon one another. For example, we can add Secondary and Tertiary stories based on our Primary story from above.\n\n</If>\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-using-args.md\" />\n\n{/* prettier-ignore-end */}\n\nWhat’s more, you can import `args` to reuse when writing stories for other components, and it's helpful when you’re building composite components. For example, if we make a `ButtonGroup` story, we might remix two stories from its child component `Button`.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-group-story.md\" />\n\n{/* prettier-ignore-end */}\n\nWhen Button’s signature changes, you only need to change Button’s stories to reflect the new schema, and ButtonGroup’s stories will automatically be updated. This pattern allows you to reuse your data definitions across the component hierarchy, making your stories more maintainable.\n\nThat’s not all! Each of the args from the story function are live editable using Storybook’s [Controls](../essentials/controls.mdx) panel. It means your team can dynamically change components in Storybook to stress test and find edge cases.\n\n<Video src=\"../_assets/writing-stories/addon-controls-demo-optimized.mp4\" />\n\nYou can also use the Controls panel to edit or save a new story after adjusting its control values.\n\n<Video src=\"../_assets/get-started/edit-story-from-controls-optimized.mp4\" />\n\n<If renderer=\"svelte\">\n\n  <Callout variant=\"info\">\n\n    This feature is not supported with the Svelte CSF. To opt-in to this feature with Svelte, you must use Storybook's [Component Story Format](../api/csf/index.mdx).\n  \n  </Callout>\n  \n</If>\n\nAddons can enhance args. For instance, [Actions](../essentials/actions.mdx) auto-detects which args are callbacks and appends a logging function to them. That way, interactions (like clicks) get logged in the actions panel.\n\n<Video src=\"../_assets/writing-stories/addon-actions-demo-optimized.mp4\" />\n\n### Using the play function\n\nStorybook's `play` function is a convenient helper methods to test component scenarios that otherwise require user intervention. They're small code snippets that execute once your story renders. For example, suppose you wanted to validate a form component, you could write the following story using the `play` function to check how the component responds when filling in the inputs with information:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"login-form-with-play-function.md\" />\n\nYou can interact with and debug your story's play function in the [interactions panel](../writing-tests/interaction-testing.mdx#debugging-interaction-tests).\n\n### Using parameters\n\nParameters are Storybook’s method of defining static metadata for stories. A story’s parameters can be used to provide configuration to various addons at the level of a story or group of stories.\n\nFor instance, suppose you wanted to test your Button component against a different set of backgrounds than the other components in your app. You might add a component-level `backgrounds` parameter:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"parameters-in-meta.md\" />\n\n{/* prettier-ignore-end */}\n\n![Parameters background color](../_assets/writing-stories/parameters-background-colors.png)\n\nThis parameter would instruct the backgrounds feature to reconfigure itself whenever a Button story is selected. Most features and addons are configured via a parameter-based API and can be influenced at a [global](./parameters.mdx#global-parameters), [component](./parameters.mdx#component-parameters), and [story](./parameters.mdx#story-parameters) level.\n\n### Using decorators\n\nDecorators are a mechanism to wrap a component in arbitrary markup when rendering a story. Components are often created with assumptions about ‘where’ they render. Your styles might expect a theme or layout wrapper, or your UI might expect specific context or data providers.\n\n<IfRenderer renderer=\"svelte\">\n  \n  A simple example is adding padding to a component’s stories. With Svelte, you can either use an auxiliary component to wrap your stories with the required spacing or layout elements, or ignore the concept of decorators entirely and define them inline in a template.\n   \n  { /* prettier-ignore-start */}\n  \n  <CodeSnippets path=\"margindecorator.md\" />\n  \n  { /* prettier-ignore-end */}\n  \n\n</IfRenderer>\n\n<If notRenderer=\"svelte\">\n\n  A simple example is adding padding to a component’s stories. Accomplish this using a decorator that wraps the stories in a `div` with padding, like so:\n\n</If>\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-component-decorator.md\" />\n\n{/* prettier-ignore-end */}\n\nDecorators [can be more complex](./decorators.mdx#context-for-mocking) and are often provided by [addons](../configure/user-interface/storybook-addons.mdx). You can also configure decorators at the [story](./decorators.mdx#story-decorators), [component](./decorators.mdx#component-decorators) and [global](./decorators.mdx#global-decorators) level.\n\n## Stories for two or more components\n\nSometimes you may have two or more components created to work together. For instance, if you have a parent `List` component, it may require child `ListItem` components.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"list-story-starter.md\" />\n\n{/* prettier-ignore-end */}\n\nIn such cases, it makes sense to [customize the rendering](#custom-rendering) to output the `List` component with different numbers of `ListItem` children.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"list-story-expanded.md\" />\n\n{/* prettier-ignore-end */}\n\nYou can also reuse *story data* from the child `ListItem` in your `List` component. That’s easier to maintain because you don’t have to update it in multiple places.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"list-story-reuse-data.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  Note that there are disadvantages in writing stories like this as you cannot take full advantage of the args mechanism and composing args as you build even more complex composite components. For more discussion, see the [multi component stories](../writing-stories/stories-for-multiple-components.mdx) workflow documentation.\n</Callout>\n"
  },
  {
    "path": "docs/writing-stories/loaders.mdx",
    "content": "---\ntitle: 'Loaders'\nsidebar:\n  order: 5\n  title: Loaders\n---\n\nLoaders are asynchronous functions that load data for a story and its [decorators](./decorators.mdx). A story's loaders run before the story renders, and the loaded data injected into the story via its render context.\n\nLoaders can be used to load any asset, lazy load components, or fetch data from a remote API. This feature was designed as a performance optimization to handle large story imports. However, [args](./args.mdx) is the recommended way to manage story data. We're building up an ecosystem of tools and techniques around Args that might not be compatible with loaded data.\n\nThey are an advanced feature (i.e., escape hatch), and we only recommend using them if you have a specific need that other means can't fulfill.\n\n## Fetching API data\n\nStories are isolated component examples that render internal data defined as part of the story or alongside the story as [args](./args.mdx).\n\nLoaders are helpful when you need to load story data externally (e.g., from a remote API). Consider the following example that fetches a todo item to display in a todo list:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"loader-story.md\" />\n\n{/* prettier-ignore-end */}\n\nThe response obtained from the remote API call is combined into a `loaded` field on the story context, which is the second argument to a story function. For example, in React, the story's args were spread first to prioritize them over the static data provided by the loader. With other frameworks (e.g., Angular), you can write your stories as you'd usually do.\n\n## Global loaders\n\nWe can also set a loader for **all stories** via the `loaders` export of your [`.storybook/preview.js`](../configure/index.mdx#configure-story-rendering) file (this is the file where you configure all stories):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-global-loader.md\" />\n\n{/* prettier-ignore-end */}\n\nIn this example, we load a \"current user\" available as `loaded.currentUser` for all stories.\n\n## Loader inheritance\n\nLike [parameters](./parameters.mdx), loaders can be defined globally, at the component level, and for a single story (as we’ve seen).\n\nAll loaders, defined at all levels that apply to a story, run before the story renders in Storybook's canvas.\n\n* All loaders run in parallel\n* All results are the `loaded` field in the story context\n* If there are keys that overlap, \"later\" loaders take precedence (from lowest to highest):\n  * Global loaders, in the order they are defined\n  * Component loaders, in the order they are defined\n  * Story loaders, in the order they are defined\n"
  },
  {
    "path": "docs/writing-stories/mocking-data-and-modules/index.mdx",
    "content": "---\ntitle: Mocking data and modules\nsidebar:\n  order: 8\n  title: Mocking data and modules\n---"
  },
  {
    "path": "docs/writing-stories/mocking-data-and-modules/mocking-modules.mdx",
    "content": "---\ntitle: Mocking modules\nsidebar:\n  order: 1\n  title: Modules\n---\n\nComponents often depend on other modules, such as other components, utility functions, or libraries. These can be from external packages or internal to your project. When rendering those components in Storybook or [testing](../../writing-tests/index.mdx) them, you may want to mock those modules to control their behavior and isolate the component's functionality.\n\nFor example, this simple component depends on two modules, a local utility function to access the user's browser session and an external package to generate a unique ID:\n\n{/* TODO: More renderers than just React */}\n```jsx title=\"AuthButton.jsx\"\nimport { v4 as uuidv4 } from 'uuid';\nimport { getUserFromSession } from '../lib/session';\n\nexport function AuthButton() {\n  const user = getUserFromSession();\n  const id = uuidv4();\n\n  return (\n    <button onClick={() => { console.log(`User: ${user.name}, ID: ${id}`) }}>\n      {user ? `Welcome, ${user.name}` : 'Sign in'}\n    </button>\n  );\n}\n```\n\nThe above example is written with React, but the same principles apply to other renderers like Vue, Svelte, or Web Components. The important part is the usage of the two module dependencies.\n\nWhen writing stories or tests for this component, you may want to mock the `getUserFromSession` function to control the user data returned, or mock the `uuidv4` function to return a predictable ID. This allows you to test the component's behavior without relying on the actual implementations of these modules.\n\nFor maximum flexibility, Storybook provides three ways to mock modules for your stories. Let's walk through each of them, starting with the most straightforward approach.\n\n## Automocking\n\nAutomocking is the most straightforward way to mock modules in Storybook, and we recommend it for all projects using the [Vite](../../builders/vite.mdx) and [Webpack](../../builders/webpack.mdx) builders (other builders must use one of the other techniques, below). This approach requires minimal configuration while allowing for flexible mocking of modules.\n\nIt works with two steps. First, register the modules you want to mock in your Storybook configuration. Then, control the behavior and make assertions about the mocked modules in your stories.\n\n### Registering modules to mock\n\nWhen automocking, you use the `sb.mock` utility function to register modules you want to mock. There are three ways to register modules: as spy-only, fully automocked, or with a mock file. Each method has its use cases and benefits.\n\nThere are some key details to keep in mind when using the `sb.mock` utility:\n\n- You can register both local modules (e.g., `../lib/session.ts`) and packages in `node_modules` (e.g., `uuid`).\n- You can only register mocked modules in your project-level configuration: `.storybook/preview.js|ts`. This ensures consistent and performant mocking across all stories in your project. You can modify the behavior of these modules in your stories, but you cannot register them directly in the story files.\n- When registering a mock for a local module, the path must:\n  - Not use an alias or subpath import (e.g., `@/lib/session.ts` or `#lib/session`).\n  - Be relative to the `.storybook/preview.js|ts` file.\n  - Include the file extension (e.g., `.ts` or `.js`).\n- If you are using Typescript, you can wrap the module path in `import()` to ensure the module is correctly resolved and typed. For example, `sb.mock(import('../lib/session.ts'))`.\n- If you are using the [Webpack builder](../../builders/webpack.mdx), you can only automock `node_module` packages that have ESModules (ESM) entry points. If a module has both CommonJS (CJS) and ESM entry points, Webpack doesn't correctly resolve the ESM entry and it cannot be mocked. Webpack users can still mock CJS `node_module` packages by providing a [mock file](#mock-files).\n\n#### Spy-only\n\nFor most cases, you should register a mocked module as spy-only, by setting the `spy` option to `true`. This leaves the original module's functionality intact, while still allowing you to modify the behavior if needed and make assertions in your tests.\n\nFor example, if you want to spy on the `getUserFromSession` function and the `uuidv4` function from the `uuid` package, you can call the `sb.mock` utility function in your `.storybook/preview.js|ts` file:\n\n<CodeSnippets path=\"automock-register-spy.md\" />\n\nIf you need to mock an external module that has a deeper import path (e.g. `lodash-es/add`), register the mock with that path.\n\nYou can then [control the behavior of these modules](#using-automocked-modules-in-stories) and make assertions about them in your stories, such as checking if a function was called or what arguments it was called with.\n\n#### Fully automocked modules\n\nFor cases where you need to prevent the original module's functionality from executing, set the `spy` option to `false` (or omit it, because that is the default value). This will automatically replace all exports from the module with [Vitest mock functions](https://vitest.dev/api/mock.html), allowing you to control their behavior and make assertions while being certain that the original functionality never runs.\n\n<CodeSnippets path=\"automock-register-full.md\" />\n\n<Callout variant=\"warning\">\n\nFully automocked modules do not execute their exported functions, but the module is still evaluated, along with its dependencies. This means that if the module has side effects (e.g., modifying global state, logging to the console, etc.), those side effects will still occur. Similarly, a module written to run on the server will attempt to be evaluated in the browser. If you want to prevent the original module's code from running entirely, you should use a [mock file](#mock-files) instead.\n\n</Callout>\n\nYou can then [control the behavior of these modules](#using-automocked-modules-in-stories) and make assertions about them in your stories, just like with the spy-only approach.\n\n#### Mock files\n\nIf you want to mock a module with more complex behavior or reuse a mock's behavior across multiple stories, you can create a mock file. This file should be placed in a `__mocks__` directory next to the module you want to mock, and it should export the same named exports as the original module.\n\nFor example, to mock the `session` module in the `lib` directory, create a file named `session.js|ts` in the `lib/__mocks__` directory:\n\n```js title=\"lib/__mocks__/session.js\"\nexport function getUserFromSession() {\n  return { name: 'Mocked User' };\n}\n```\n\nFor packages in your `node_modules`, create a `__mocks__` directory in the root of your project and create the mock file there. For example, to mock the `uuid` package, create a file named `uuid.js` in the `__mocks__` directory:\n\n```js title=\"__mocks__/uuid.js\"\nexport function v4() {\n  return '1234-5678-90ab-cdef';\n}\n```\n\nIf you need to mock an external module that has a deeper import path (e.g. `lodash-es/add`), create a corresponding mock file (e.g. `__mocks__/lodash-es/add.js`) in the root of your project.\n\nThe root of your project is determined differently depending on your builder:\n\n**Vite projects**\n\nThe root `__mocks__` directory should be placed in the [`root` directory](https://vite.dev/config/shared-options.html#root), as defined in your project's Vite configuration (typically `process.cwd()`) If that is unavailable, it defaults to the directory containing your `.storybook` directory.\n\n**Webpack projects**\n\nThe root `__mocks__` directory should be placed in the [`context` directory](https://webpack.js.org/configuration/entry-context/#context), as defined in your project's Webpack configuration (typically `process.cwd()`). If that is unavailable, it defaults to the root of your repository.\n\n<Callout variant=\"info\">\n\nMock files must be written with JavaScript (not TypeScript) using ESModules (not CJS).\n\nThey must export the same named exports as the original module. If you want to mock a default export, you can use `export default` in the mock file.\n\n</Callout>\n\nYou can then use the `sb.mock` utility to register these mock files in your `preview.js|ts` file:\n\n<CodeSnippets path=\"automock-register-mock-file.md\" />\n\nNote that the API for registering automatically mocked modules and mock files is the same. The only difference is that `sb.mock` will first look for a mock file in the appropriate directory before automatically mocking the module.\n\n### Using automocked modules in stories\n\nAll registered automocked modules are used the same way within your stories. You can control the behavior, such as defining what it returns, and make assertions about the modules.\n\n<CodeSnippets path=\"automocked-modules-in-story.md\" />\n\nMocked functions created with the `sb.mock` utility are full [Vitest mock functions](https://vitest.dev/api/mock.html), which means you can use all the methods available on them. Some of the most useful methods include:\n\n| Method                                                                           | Description                                           |\n| -------------------------------------------------------------------------------- | ----------------------------------------------------- |\n| [`mockReturnValue(value)`](https://vitest.dev/api/mock.html#mockreturnvalue)     | Sets the return value of the mocked function.         |\n| [`mockResolvedValue(value)`](https://vitest.dev/api/mock.html#mockresolvedvalue) | Sets the value the mocked async function resolves to. |\n| [`mockImplementation(fn)`](https://vitest.dev/api/mock.html#mockimplementation)  | Sets a custom implementation for the mocked function. |\n\n<Callout variant=\"info\">\n\nIf you are [writing your stories in TypeScript](../typescript.mdx), you can use the `mocked` utility from `storybook/test` to ensure that the mocked functions are correctly typed in your stories. This utility is a type-safe wrapper around the Vitest `vi.mocked` function.\n\n</Callout>\n\n### How it works\n\nStorybook's automocking is built on Vitest's mocking engine. The behavior adjusts depending on whether you're in development mode or build mode:\n\n**Dev Mode**\n\nIn dev mode, mocking relies on Vite's module graph invalidation. When a mock is added, changed, or removed (either in `.storybook/preview.js|ts` or the `__mocks__` directory), the plugin intelligently invalidates all affected modules and triggers a hot reload. This provides a fast and interactive development experience.\n\n**Dev and build mode**\n\n- Build-time analysis: A new Vite plugin, viteMockPlugin, scans `.storybook/preview.js|ts` for all `sb.mock()` calls during the build process.\n- Mock Processing:\n  - `__mocks__` redirects: If a corresponding file is found in the top-level `__mocks__` directory, that file is loaded and transformed by Vite.\n  - Automocking & spies: If no `__mocks__` file is found, the original module's code is transformed at build-time to replace its exports with mocks or spies.\n- No runtime overhead: Because all mocking decisions and transformations happen at build time, there is no performance penalty or complex interception logic needed in the final built application. The mocked modules are directly bundled in place of the originals.\n\n#### Comparison to Vitest mocking\n\nWhile this feature uses Vitest's mocking engine, the implementation within Storybook has some key differences:\n\n- Scope: Mocks are global and defined only in `.storybook/preview.js|ts`. Unlike Vitest, you cannot call `sb.mock()` inside individual story files.\n- Static by Design: All mocking decisions are finalized at build time. This makes the system robust and performant but less dynamic than Vitest's test-by-test mocking capabilities. There is no `sb.unmock()` or equivalent, as the module graph is fixed in a production build.\n- Runtime Mocking: While the module swap is static, you can still control the behavior of the mocked functions at runtime within a play function or `beforeEach` hook (e.g., `mocked(myFunction).mockReturnValue('new value')`).\n- No Factory Functions: The `sb.mock()` API does not accept a factory function as its second argument (e.g., `sb.mock('path', () => ({...}))`). This is because all mocking decisions are resolved at build time, whereas factories are executed at runtime.\n\n## Alternative methods\n\nIf [automocking](#automocking) is not suitable for your project, there are two alternative methods to mock modules in Storybook: [subpath imports](#subpath-imports) and [builder aliases](#builder-aliases). These methods require a bit more setup but provide similar functionality to automocking, allowing you to control the behavior of modules in your stories.\n\n### Subpath imports\n\nYou can use [subpath imports](https://nodejs.org/api/packages.html#subpath-imports), a Node feature, to mock modules. Subpath imports allow you to define custom paths for modules in your project, which can be used to replace the original module with a mock file. They work with both the [Vite](../../builders/vite.mdx) and [Webpack](../../builders/webpack.mdx) builders.\n\n#### Mock files\n\nTo mock a module, create a file with the same name and in the same directory as the module you want to mock. For example, to mock a module named `session`, create a file next to it named `session.mock.js|ts`, with a few characteristics:\n\n* It must import the original module using a relative import.\n  * Using a subpath or alias import would result in it importing itself.\n* It should re-export all exports from the original module.\n* It should use the `fn` utility to mock any necessary functionality from the original module.\n* It should use the [`mockName`](https://vitest.dev/api/mock.html#mockname) method to ensure the name is preserved when minified\n* It should not introduce side effects that could affect other tests or components. Mock files should be isolated and only affect the module they are mocking.\n\nHere's an example of a mock file for a module named `session`:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-test-mock-file-example.md\" />\n\n{/* prettier-ignore-end */}\n\nWhen you use the `fn` utility to mock a module, you create full [Vitest mock functions](https://vitest.dev/api/mock.html). See [below](#using-mocked-modules-in-stories) for examples of how you can use a mocked module in your stories.\n\n**Mock files for external modules**\n\nYou can't directly mock an external module like [`uuid`](https://github.com/uuidjs/uuid) or `node:fs`. Instead, you must wrap it in your own module, which you can mock like any other internal one. For example, with `uuid`, you could do the following:\n\n```ts title=\"lib/uuid.ts\"\nimport { v4 } from 'uuid';\n\nexport const uuidv4 = v4;\n```\n\nAnd create a mock for the wrapper:\n\n```ts title=\"lib/uuid.mock.ts\"\nimport { fn } from 'storybook/test';\n\nimport * as actual from './uuid';\n\nexport const uuidv4 = fn(actual.uuidv4).mockName('uuidv4');\n```\n\n#### Configuration\n\nTo configure subpath imports, you define the `imports` property in your project's `package.json` file. This property maps the subpath to the actual file path. The example below configures subpath imports for four internal modules:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"subpath-imports-config.md\" />\n\n{/* prettier-ignore-end */}\n\nThere are three aspects to this configuration worth noting:\n\nFirst, **each subpath must begin with `#`**, to differentiate it from a regular module path. The `#*` entry is a catch-all that maps all subpaths to the root directory.\n\nSecond, the order of the keys is important. The `default` key should come last.\n\nThird, note the **`storybook`, `test`, and `default` keys** in each module's entry. The `storybook` value is used to import the mock file when loaded in Storybook, while the `default` value is used to import the original module when loaded in your project. The `test` condition is also used within Storybook, which allows you to use the same configuration in Storybook and your other tests.\n\nWith the package configuration in place, you can then update your component file to use the subpath import:\n\n```ts title=\"AuthButton.ts\"\n// ➖ Remove this line\n// import { getUserFromSession } from '../../lib/session';\n// ➕ Add this line\nimport { getUserFromSession } from '#lib/session';\n\n// ...rest of the file\n```\n\n<Callout variant=\"info\">\n  Subpath imports will only be correctly resolved and typed when the [`moduleResolution` property](https://www.typescriptlang.org/tsconfig/#moduleResolution) is set to `'Bundler'`, `'NodeNext'`, or `'Node16'` in your TypeScript configuration.\n\n  If you are currently using `'node'`, that is intended for projects using a Node.js version older than v10. Projects written with modern code likely do not need to use `'node'`.\n\n  Storybook recommends the [TSConfig Cheat Sheet](https://www.totaltypescript.com/tsconfig-cheat-sheet) for guidance on setting up your TypeScript configuration.\n</Callout>\n\n#### Using subpath imports in stories\n\nWhen you use the `fn` utility to mock a module, you create full [Vitest mock functions](https://vitest.dev/api/mock.html), which have many methods available. Some of the most useful methods include:\n\n| Method                                                                           | Description                                           |\n| -------------------------------------------------------------------------------- | ----------------------------------------------------- |\n| [`mockReturnValue(value)`](https://vitest.dev/api/mock.html#mockreturnvalue)     | Sets the return value of the mocked function.         |\n| [`mockResolvedValue(value)`](https://vitest.dev/api/mock.html#mockresolvedvalue) | Sets the value the mocked async function resolves to. |\n| [`mockImplementation(fn)`](https://vitest.dev/api/mock.html#mockimplementation)  | Sets a custom implementation for the mocked function. |\n\nHere, we define `beforeEach` on a story (which will run before the story is rendered) to set a mocked return value for the `getUserFromSession` function used by the Page component:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-test-mock-return-value.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  If you are [writing your stories in TypeScript](../typescript.mdx), you must import your mock modules using the full mocked file name to have the functions correctly typed in your stories. You do **not** need to do this in your component files. That's what the [subpath import](#subpath-imports) or [builder alias](#builder-aliases) is for.\n</Callout>\n\n#### Spying on mocked modules\n\nThe `fn` utility also spies on the original module's functions, which you can use to assert their behavior in your tests. For example, you can use [interaction tests](../../writing-tests/interaction-testing.mdx) to verify that a function was called with specific arguments.\n\nFor example, this story checks that the `saveNote` function was called when the user clicks the save button:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-test-fn-mock-spy.md\" />\n\n{/* prettier-ignore-end */}\n\n### Builder aliases\n\nIf your project is unable to use [automocking](#automocking) or [subpath imports](#subpath-imports), you can configure your Storybook builder to alias the module to the [mock file](#mock-files-1). This will instruct the builder to replace the module with the mock file when bundling your Storybook stories.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"module-aliases-config.md\" />\n\n{/* prettier-ignore-end */}\n\nUsage of the aliased module in stories is similar to when [using subpath imports in stories](#using-subpath-imports-in-stories), but you import the module using the alias instead of the subpath.\n\n-----\n\n## Common scenarios\n\n### Setting up and cleaning up\n\nBefore the story renders, you can use the asynchronous `beforeEach` function to perform any setup you need (e.g., configure the mock behavior). This function can be defined at the story, component (which will run for all stories in the file), or project (defined in `.storybook/preview.js|ts`, which will run for all stories in the project).\n\nYou can also return a cleanup function from `beforeEach` which will be called after your story unmounts. This is useful for tasks like unsubscribing observers, etc.\n\n<Callout variant=\"info\">\n  It is *not* necessary to restore `fn()` mocks with the cleanup function, as Storybook will already do that automatically before rendering a story. See the [`parameters.test.restoreMocks` API](../../api/parameters.mdx#restoremocks) for more information.\n</Callout>\n\nHere's an example of using the [`mockdate`](https://github.com/boblauer/MockDate) package to mock the [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) and reset it when the story unmounts.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"before-each-in-meta-mock-date.md\" />\n\n{/* prettier-ignore-end */}\n\n-----\n\n## Troubleshooting\n\n### Receiving an `exports is not defined` error\n\nWebpack projects may encounter an `exports is not defined` error when using [automocking](#automocking). This is usually caused by attempting to mock a module with CommonJS (CJS) entry points. Automocking with Webpack only works with modules that have ESModules (ESM) entry points exclusively, so you must use a [mock file](#mock-files) to mock CJS modules.\n\n### Mocking conflicts with other testing tools\n\nIf you've already set up mocking with other testing tools (e.g., [Jest](https://jestjs.io/)), you may encounter conflicts when using Storybook's mocking system. These conflicts can cause unexpected behavior, errors, or incorrect mocks when both tools try to mock the same module. This is a known issue when sharing mock files or configurations between Storybook and other testing tools. To address this situation, we recommend that you verify which tool is responsible for mocking a particular module and make sure the configurations do not overlap to avoid any conflicts."
  },
  {
    "path": "docs/writing-stories/mocking-data-and-modules/mocking-network-requests.mdx",
    "content": "---\ntitle: Mocking network requests\nsidebar:\n  order: 2\n  title: Network requests\n---\n\nFor components that make network requests (e.g. fetching data from a REST or GraphQL API), you can mock those requests using a tool like [Mock Service Worker (MSW)](https://mswjs.io/). MSW is an API mocking library, which relies on service workers to capture network requests and provides mocked data in response.\n\nThe [MSW addon](https://storybook.js.org/addons/msw-storybook-addon/) brings this functionality into Storybook, allowing you to mock API requests in your stories. Below is an overview of how to set up and use the addon.\n\n## Set up the MSW addon\n\nFirst, if necessary, run this command to install MSW and the MSW addon:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"msw-addon-install.md\" />\n\n{/* prettier-ignore-end */}\n\nIf you're not already using MSW, generate the service worker file necessary for MSW to work:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"msw-generate-service-worker.md\" />\n\n{/* prettier-ignore-end */}\n\n<If renderer=\"angular\">\n  <Callout variant=\"info\" icon=\"💡\">\n    Angular projects will likely need to adjust the command to save the mock service worker file in a different directory (e.g., `src`).\n  </Callout>\n</If>\n\nThen ensure the [`staticDirs`](../../api/main-config/main-config-static-dirs.mdx) property in your Storybook configuration will include the generated service worker file (in `/public`, by default):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"main-config-static-dirs.md\" />\n\n{/* prettier-ignore-end */}\n\nFinally, initialize the addon and apply it to all stories with a [project-level loader](../loaders.mdx#global-loaders):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"msw-addon-initialize.md\" />\n\n{/* prettier-ignore-end */}\n\n## Mocking REST requests\n\nIf your component fetches data from a REST API, you can use MSW to mock those requests in Storybook. As an example, consider this document screen component:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"document-screen-fetch.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  This example uses the [`fetch` API](https://developer.mozilla.org/en-US/docs/Web/API/fetch) to make network requests. If you're using a different library (e.g. [`axios`](https://axios-http.com/)), you can apply the same principles to mock network requests in Storybook.\n</Callout>\n\nWith the MSW addon, we can write stories that use MSW to mock the REST requests. Here's an example of two stories for the document screen component: one that fetches data successfully and another that fails.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"msw-addon-configure-handlers-http.md\" />\n\n{/* prettier-ignore-end */}\n\n## Mocking GraphQL requests\n\nGraphQL is another common way to fetch data in components. You can use MSW to mock GraphQL requests in Storybook. Here's an example of a document screen component that fetches data from a GraphQL API:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"document-screen-with-graphql.md\" />\n\n{/* prettier-ignore-end */}\n\n<If renderer=\"svelte\">\n\n<Callout variant=\"info\">\n  This example uses [URQL](https://formidable.com/open-source/urql/) to make network requests. If you're using a different library (e.g., [Houdini](https://houdinigraphql.com/) or [Graffle](https://graffle.js.org/)), you can apply the same principles to mock network requests in Storybook.\n</Callout>\n\n</If>\n\n<If notRenderer=\"svelte\">\n\n<Callout variant=\"info\">\n  This example uses GraphQL with [Apollo Client](https://www.apollographql.com/docs/) to make network requests. If you're using a different library (e.g. [URQL](https://formidable.com/open-source/urql/) or [React Query](https://react-query.tanstack.com/)), you can apply the same principles to mock network requests in Storybook.\n</Callout>\n\n</If>\n\nThe MSW addon allows you to write stories that use MSW to mock the GraphQL requests. Here's an example demonstrating two stories for the document screen component. The first story fetches data successfully, while the second story fails.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"msw-addon-configure-handlers-graphql.md\" />\n\n{/* prettier-ignore-end */}\n\n## Configuring MSW for stories\n\nIn the examples above, note how each story is configured with `parameters.msw` to define the request handlers for the mock server. Because it uses parameters in this way, it can also be configured at the [component](../parameters.mdx#component-parameters) or even [project](../parameters.mdx#global-parameters) level, allowing you to share the same mock server configuration across multiple stories.\n"
  },
  {
    "path": "docs/writing-stories/mocking-data-and-modules/mocking-providers.mdx",
    "content": "---\ntitle: Mocking providers\nsidebar:\n  order: 3\n  title: Providers\n---\n\n<If notRenderer={['preact', 'react', 'solid']}>\n  <Callout variant=\"info\">\n    The [context provider pattern](https://react.dev/learn/passing-data-deeply-with-context) and how to mock it only applies to renderers that use JSX, like [React](?renderer=react) or [Solid](?renderer=solid).\n  </Callout>\n\n  {/* End non-supported renderers */}\n</If>\n\n<If renderer={['preact', 'react', 'solid']}>\n  Components can receive data or configuration from context providers. For example, a styled component might access its theme from a ThemeProvider or Redux uses React context to provide components access to app data. To mock a provider, you can wrap your component in a [decorator](../decorators.mdx) that includes the necessary context.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"storybook-preview-with-styled-components-decorator.md\" />\n\n  {/* prettier-ignore-end */}\n\n  <Callout variant=\"warning\">\n    Note the file extension above (`.tsx` or `.jsx`). You may need to adjust your preview file's extension to allow use of JSX, depending on your project's settings.\n  </Callout>\n\n  <If renderer=\"react\">\n    <Callout variant=\"info\" icon=\"💡\">\n      For another example, reference the [Screens](https://storybook.js.org/tutorials/intro-to-storybook/react/en/screen/) chapter of the Intro to Storybook tutorial, where we mock a Redux provider with mock data.\n    </Callout>\n  </If>\n\n  ## Configuring the mock provider\n\n  When mocking a provider, it may be necessary to configure the provider to supply a different value for individual stories. For example, you might want to test a component with different themes or user roles.\n\n  One way to do this is to define the decorator for each story individually. But if you imagine a scenario where you wish to create stories for each of your components in both light and dark themes, this approach can quickly become cumbersome.\n\n  For a better way, with much less repetition, you can use the [decorator function's second \"context\" argument](../decorators.mdx#context-for-mocking) to access a story's [`parameters`](../parameters.mdx) and adjust the provided value. This way, you can define the provider once and adjust its value for each story.\n\n  For example, we can adjust the decorator from above to read from `parameters.theme` to determine which theme to provide:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"mock-provider-in-preview.md\" />\n\n  {/* prettier-ignore-end */}\n\n  Now, you can define a `theme` parameter in your stories to adjust the theme provided by the decorator:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"configure-mock-provider-with-story-parameter.md\" />\n\n  {/* prettier-ignore-end */}\n\n  This powerful approach allows you to provide any value (theme, user role, mock data, etc.) to your components in a way that is both flexible and maintainable.\n</If>\n"
  },
  {
    "path": "docs/writing-stories/naming-components-and-hierarchy.mdx",
    "content": "---\ntitle: 'Naming components and hierarchy'\nsidebar:\n  order: 7\n  title: Naming components and hierarchy\n---\n\n<YouTubeCallout id=\"VPfjrhDlkVc\" title=\"How to Name Stories and Components\" />\n\nStorybook provides a powerful way to organize your stories, giving you the necessary tools to categorize, search, and filter your stories based on your organization's needs and preferences.\n\n## Structure and hierarchy\n\nWhen organizing your Storybook, there are two methods of structuring your stories: **implicit** and **explicit**. The [implicit method](../configure/user-interface/sidebar-and-urls.mdx#csf-30-auto-titles) involves relying upon the physical location of your stories to position them in the sidebar, while the [explicit method](#naming-stories) involves utilizing the `title` parameter to place the story.\n\n![Storybook sidebar hierarchy](../_assets/writing-stories/naming-hierarchy-sidebar-anatomy.png)\n\nBased on how you structure your Storybook, you can see that the story hierarchy is made up of various parts:\n\n* **Category**: The top-level grouping of stories and documentation pages generated by Storybook\n* **Folder**: A mid-level organizational unit that groups components and stories in the sidebar, representing a feature or section of your application\n* **Component**: A low-level organizational unit representing the component that the story is testing\n* **Docs**: The automatically generated [documentation page](../writing-docs/autodocs.mdx) for the component\n* **Story**: The individual story testing a specific component state\n\n## Naming stories\n\nWhen creating your stories, you can explicitly use the `title` parameter to define the story's position in the sidebar. It can also be used to [group](#grouping) related components together in an expandable interface to help with Storybook organization providing a more intuitive experience for your users. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-default-export.md\" />\n\n{/* prettier-ignore-end */}\n\nYields this:\n\n![Stories hierarchy without paths](../_assets/writing-stories/naming-hierarchy-no-path.png)\n\n## Grouping\n\nIt is also possible to group related components in an expandable interface to help with Storybook organization. To do so, use the `/` as a separator:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"button-story-grouped.md\" />\n\n{/* prettier-ignore-end */}\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"checkbox-story-grouped.md\" />\n\n{/* prettier-ignore-end */}\n\nYields this:\n\n![Stories hierarchy with paths](../_assets/writing-stories/naming-hierarchy-with-path.png)\n\n## Roots\n\nBy default, the top-level grouping will be displayed as “root” in the Storybook UI (i.e., the uppercased, non-expandable items). If you need, you can [configure Storybook](../configure/user-interface/sidebar-and-urls.mdx#roots) and disable this behavior. Useful if you need to provide a streamlined experience for your users; nevertheless, if you have a large Storybook composed of multiple component stories, we recommend naming your components according to the file hierarchy.\n\n<If notRenderer=\"svelte\">\n\n  ## Single-story hoisting\n\n  Single-story components (i.e., component stories without **siblings**) whose **display name** exactly matches the component's name (last part of `title`) are automatically hoisted up to replace their parent component in the UI. For example:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"button-story-hoisted.md\" />\n\n  {/* prettier-ignore-end */}\n\n  ![Stories hierarchy with single story hoisting](../_assets/writing-stories/naming-hierarchy-single-story-hoisting.png)\n\n  Because story exports are automatically \"start cased\" (`myStory` becomes `\"My Story\"`), your component name should match that. Alternatively, you can override the story name using `myStory.storyName = '...'` to match the component name.\n\n</If>\n\n## Sorting stories\n\nOut of the box, Storybook sorts stories based on the order in which they are imported. However, you can customize this pattern to suit your needs and provide a more intuitive experience by adding `storySort` to the `options` parameter in your `preview.js` file.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-sort-function.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n  Asides from the unique story identifier, you can also use the `title`, `name`, and import path to sort your stories using the `storySort` function.\n</Callout>\n\nThe `storySort` can also accept a configuration object.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-empty-sort-object.md\" />\n\n{/* prettier-ignore-end */}\n\n| Field            | Type    | Description                                              | Required | Default Value           | Example                   |\n| ---------------- | ------- | -------------------------------------------------------- | -------- | ----------------------- | ------------------------- |\n| **method**       | String  | Tells Storybook in which order the stories are displayed | No       | Storybook configuration | `'alphabetical'`          |\n| **order**        | Array   | The stories to be shown, ordered by supplied name        | No       | Empty Array `[]`        | `['Intro', 'Components']` |\n| **includeNames** | Boolean | Include story name in sort calculation                   | No       | `false`                 | `true`                    |\n| **locales**      | String  | The locale required to be displayed                      | No       | System locale           | `en-US`                   |\n\nTo sort your stories alphabetically, set `method` to `'alphabetical'` and optionally set the `locales` string. To sort your stories using a custom list, use the `order` array; stories that don't match an item in the `order` list will appear after the items in the list.\n\nThe `order` array can accept a nested array to sort 2nd-level story kinds. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-with-ordered-pages.md\" />\n\n{/* prettier-ignore-end */}\n\nWhich would result in this story ordering:\n\n1. `Intro` and then `Intro/*` stories\n2. `Pages` story\n3. `Pages/Home` and `Pages/Home/*` stories\n4. `Pages/Login` and `Pages/Login/*` stories\n5. `Pages/Admin` and `Pages/Admin/*` stories\n6. `Pages/*` stories\n7. `Components` and `Components/*` stories\n8. All other stories\n\nIf you want specific categories to sort to the end of the list, you can insert a `*` into your `order` array to indicate where \"all other stories\" should go:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-preview-with-ordered-pages-and-wildcard.md\" />\n\n{/* prettier-ignore-end */}\n\nIn this example, the `WIP` category would be displayed at the end of the list.\n\nNote that the `order` option is independent of the `method` option; stories are sorted first by the `order` array and then by either the `method: 'alphabetical'` or the default `configure()` import order.\n"
  },
  {
    "path": "docs/writing-stories/parameters.mdx",
    "content": "---\ntitle: 'Parameters'\nsidebar:\n  order: 2\n  title: Parameters\n---\n\nParameters are a set of static, named metadata about a story, typically used to control the behavior of Storybook features and addons.\n\n<Callout variant=\"info\">\n  Available parameters are listed in the [parameters API reference](../api/parameters.mdx#available-parameters).\n</Callout>\n\nFor example, let’s customize the backgrounds feature via a parameter. We’ll use `parameters.backgrounds` to define which backgrounds appear in the backgrounds toolbar when a story is selected.\n\n## Story parameters\n\n<IfRenderer renderer=\"svelte\">\n\n With Svelte, we can set the `parameters` property in the `Story` component to define parameters for a single story using Svelte CSF with the native templating syntax, or we can use the `parameters` key on a CSF named export:\n \n</IfRenderer>\n\n<IfRenderer renderer={['angular', 'vue', 'web-components', 'ember', 'html', 'react', 'preact', 'qwik', 'solid' ]}>\n\n  We can set a parameter for a single story with the `parameters` key on a CSF export:\n\n</IfRenderer>\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"parameters-in-story.md\" />\n\n{/* prettier-ignore-end */}\n\n## Component parameters\n\n<IfRenderer renderer=\"svelte\">\n \n  To define parameters for all stories of a component, we can add the `parameters` property in the `defineMeta` function of a Svelte CSF story file, or we can use the `parameters` key on the default CSF export:\n\n</IfRenderer>\n\n<If notRenderer=\"svelte\">\n\n  We can set the parameters for all stories of a component using the `parameters` key on the default CSF export:\n\n</If>\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"parameters-in-meta.md\" />\n\n{/* prettier-ignore-end */}\n\n## Global parameters\n\nWe can also set the parameters for **all stories** via the `parameters` export of your [`.storybook/preview.js|ts`](../configure/index.mdx#configure-story-rendering) file (this is the file where you configure all stories):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"parameters-in-preview.md\" />\n\n{/* prettier-ignore-end */}\n\nSetting a global parameter is a common way to configure addons. With backgrounds, you configure the list of backgrounds that every story can render in.\n\n## Rules of parameter inheritance\n\nThe way the global, component and story parameters are combined is:\n\n* More specific parameters take precedence (so a story parameter overwrites a component parameter which overwrites a global parameter).\n* Parameters are **merged**, so keys are only ever overwritten and never dropped.\n\nThe merging of parameters is important. This means it is possible to override a single specific sub-parameter on a per-story basis while retaining most of the parameters defined globally.\n\nIf you are defining an API that relies on parameters (e.g., an [**addon**](../addons/index.mdx)) it is a good idea to take this behavior into account.\n"
  },
  {
    "path": "docs/writing-stories/play-function.mdx",
    "content": "---\ntitle: 'Play function'\nsidebar:\n  order: 4\n  title: Play function\n---\n\n`Play` functions are small snippets of code executed after the story renders. They enable you to interact with your components and test scenarios that otherwise require user intervention.\n\n## Writing stories with the play function\n\nStorybook's `play` functions are small code snippets that run once the story finishes rendering. Aided by the [interactions panel](../writing-tests/interaction-testing.mdx#debugging-interaction-tests), it allows you to build component interactions and test scenarios that were impossible without user intervention. For example, if you were working on a registration form and wanted to validate it, you could write the following story with the `play` function:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"play-function.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  See the [interaction testing documentation](../writing-tests/interaction-testing.mdx#writing-interaction-tests) for an overview of the available API events.\n</Callout>\n\nWhen Storybook finishes rendering the story, it executes the steps defined within the `play` function, interacting with the component and filling the form's information. All of this without the need for user intervention. If you check your `Interactions` panel, you'll see the step-by-step flow.\n\n## Working with the canvas\n\nPart of the context passed to the `play` function is a `canvas` object. This object allows you to query the DOM of the rendered story. It provides a scoped version of the Testing Library queries, so you can use them as you would in a regular test.\n\n<CodeSnippets path=\"play-function-with-canvas.md\" />\n\nIf you need to query outside of the canvas (for example, to test a dialog that appears outside of the story root), you can use the `screen` object available from `storybook/test`.\n\n<CodeSnippets path=\"play-function-with-screen.md\" />\n\n## Composing stories\n\nThanks to the [Component Story Format](../api/csf/index.mdx), an ES6 module based file format, you can also combine your `play` functions, similar to other existing Storybook features (e.g., [args](./args.mdx)). For example, if you wanted to verify a specific workflow for your component, you could write the following stories:\n\n<CodeSnippets path=\"play-function-composition.md\" />\n\nBy combining the stories, you're recreating the entire component workflow and can spot potential issues while reducing the boilerplate code you need to write.\n"
  },
  {
    "path": "docs/writing-stories/stories-for-multiple-components.mdx",
    "content": "---\ntitle: 'Stories for multiple components'\nsidebar:\n  order: 10\n  title: Stories for multiple components\n---\n\nIt's useful to write stories that [render two or more components](./index.mdx#stories-for-two-or-more-components) at once if those components are designed to work together. For example, `ButtonGroup`, `List`, and `Page` components.\n\n## Subcomponents\n\nWhen the components you're documenting have a parent-child relationship, you can use the `subcomponents` property to document them together. This is especially useful when the child component is not meant to be used on its own, but only as part of the parent component.\n\nHere's an example with `List` and `ListItem` components:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"list-story-with-subcomponents.md\" />\n\n{/* prettier-ignore-end */}\n\nNote that by adding a `subcomponents` property to the meta (or default export), we get an extra panel on the [ArgTypes](../writing-docs/doc-blocks.mdx#argtypes) and [Controls](../essentials/controls.mdx#) tables, listing the props of `ListItem`:\n\n![Subcomponents in ArgTypes doc block](../_assets/writing-stories/doc-block-arg-types-subcomponents-for-list.png)\n\nSubcomponents are only intended for documentation purposes and have some limitations:\n\n1. The [argTypes](../api/arg-types.mdx) of subcomponents are [inferred (for the renderers that support that feature)](../api/arg-types.mdx#automatic-argtype-inference) and cannot be manually defined or overridden.\n2. The table for each documented subcomponent does *not* include [controls](../essentials/controls.mdx) to change the value of the props, because controls always apply to the main component's args.\n\nLet's talk about some techniques you can use to mitigate the above, which are especially useful in more complicated situations.\n\n## Reusing story definitions\n\nWe can also reduce repetition in our stories by reusing story definitions. Here, we can reuse the `ListItem` stories' args in the story for `List`:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"list-story-reuse-data.md\" />\n\n{/* prettier-ignore-end */}\n\nBy rendering the `Unchecked` story with its args, we are able to reuse the input data from the `ListItem` stories in the `List`.\n\n<If renderer=\"react\">\n  However, we still aren’t using args to control the `ListItem` stories, which means we cannot change them with controls and we cannot reuse them in other, more complex component stories.\n\n  ## Using children as an arg\n\n  One way we improve that situation is by pulling the rendered subcomponent out into a `children` arg:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"list-story-with-unchecked-children.md\" />\n\n  {/* prettier-ignore-end */}\n\n  Now that `children` is an arg, we can potentially reuse it in another story.\n\n  However, there are some caveats when using this approach that you should be aware of.\n\n  The `children` arg, just like all args, needs to be JSON serializable. To avoid errors with your Storybook, you should:\n\n  * Avoid using empty values\n  * Use [mapping](../essentials/controls.mdx#dealing-with-complex-values) if you want to adjust the value with [controls](../essentials/controls.mdx)\n  * Use caution with components that include third party libraries\n\n  <Callout variant=\"info\">\n    We're currently working on improving the overall experience for the children arg and allow you to edit children arg in a control and allow you to use other types of components in the near future. But for now you need to factor in this caveat when you're implementing your stories.\n  </Callout>\n\n  {/* End if react */}\n</If>\n\n## Creating a Template Component\n\nAnother option that is more “data”-based is to create a special “story-generating” template component:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"list-story-template.md\" />\n\n{/* prettier-ignore-end */}\n\nThis approach is a little more complex to setup, but it means you can more easily reuse the `args` to each story in a composite component. It also means you can alter the args to the component with the [Controls panel](../essentials/controls.mdx).\n"
  },
  {
    "path": "docs/writing-stories/tags.mdx",
    "content": "---\ntitle: 'Tags'\nsidebar:\n  order: 6\n  title: Tags\n---\n\nTags allow you to control which stories are included in your Storybook, enabling many different uses of the same total set of stories. For example, you can use tags to include/exclude tests from the [test runner](../writing-tests/integrations/test-runner.mdx#run-tests-for-a-subset-of-stories). For more complex use cases, see the [recipes](#recipes) section, below.\n\n## Built-in tags\n\nThe following tags are available in every Storybook project:\n\n| Tag        | Applied by default? | Description                                                                                                                                                                                                                                                   |\n| ---------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `dev`      | Yes                 | Stories tagged with `dev` are rendered in Storybook's sidebar.                                                                                                                                                                                                |\n| `manifest` | Yes                 | Stories and docs tagged with `manifest` are included in the [component or docs manifests](../ai/manifests.mdx) (Currently React-only).                                                                                                                        |\n| `test`     | Yes                 | Stories tagged with `test` are included in [test runner](../writing-tests/integrations/test-runner.mdx#run-tests-for-a-subset-of-stories) or [Vitest addon](../writing-tests/integrations/vitest-addon/index.mdx#including-excluding-or-skipping-tests) runs. |\n| `autodocs` | No                  | Stories tagged with `autodocs` are included in the [docs page](../writing-docs/autodocs.mdx). If a CSF file does not contain at least one story tagged with `autodocs`, that component will not generate a docs page.                                         |\n| `play-fn`  | No                  | Applied automatically to stories with a [play function](./play-function.mdx) defined.                                                                                                                                                                         |\n| `test-fn`  | No                  | Applied automatically to tests defined using the [experimental `.test` method on CSF Factories](../api/csf/csf-next.mdx#storytest).                                                                                                                           |\n\nThe `dev`, `manifest`, and `test` tags are automatically, implicitly applied to every story in your Storybook project.\n\n## Custom tags\n\nYou're not limited to the built-in tags. Custom tags enable a flexible layer of categorization on top of Storybook's sidebar hierarchy. Sample uses might include:\n\n- Status, such as `experimental`, `new`, `stable`, or `deprecated`\n- User persona, such as `admin`, `user`, or `developer`\n- Component/code ownership\n\nThere are two ways to create a custom tag:\n\n1. Apply it to a story, component (meta), or project (preview.js|ts) as described below.\n2. Define it in your Storybook configuration file (`.storybook/main.js|ts`) to provide more configuration options, like default [filter selection](#filtering-the-sidebar-by-tags).\n\nFor example, to define an \"experimental\" tag that is excluded by default in the sidebar, you can add this to your Storybook config:\n\n<CodeSnippets path=\"main-config-tags.md\" />\n\nIf `defaultFilterSelection` is set to `include`, stories with this tag are selected as included in the filter menu. If set to `exclude`, stories with this tag are selected as excluded, and must be explicitly included by selecting the tag in the sidebar filter menu. If not set, the tag has no default selection.\n\nYou can also use the [`tags` configuration](../api/main-config/main-config-tags.mdx) to alter the configuration of built-in tags.\n\n## Applying tags\n\nA tag can be any static (i.e. not created dynamically) string, either the [built-in tags](#built-in-tags) or [custom tags](#custom-tags) of your own design. To apply tags to a story, assign an array of strings to the `tags` property. Tags may be applied at the project, component (meta), or story levels.\n\nFor example, to apply the `autodocs` tag to all stories in your project, you can use `.storybook/preview.js|ts`:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"tags-in-preview.md\" />\n\n{/* prettier-ignore-end */}\n\nWithin a component stories file, you apply tags like so:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"tags-in-meta-and-story.md\" />\n\n{/* prettier-ignore-end */}\n\n## Removing tags\n\nTo remove a tag from a story, prefix it with `!`. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"tags-remove-in-story.md\" />\n\n{/* prettier-ignore-end */}\n\nTags can be removed for all stories in your project (in `.storybook/preview.js|ts`), all stories for a component (in the CSF file meta), or a single story (as above).\n\n## Filtering the sidebar by tags\n\nBoth built-in and custom tags are available as filters in Storybook's sidebar. Selecting a tag in the filter causes the sidebar to only show stories with that tag. Selecting multiple tags shows stories that contain any of those tags.\n\nPressing the Exclude button for a tag in the filter menu excludes stories with that tag from the sidebar. You can exclude multiple tags, and stories with any of those tags will be excluded. You can also mix inclusion and exclusion.\n\nWhen no tags are selected, all stories are shown.\n\nIn this example, the `experimental` tag has been excluded and the Documentation tag (`autodocs`) has been included, so only stories tagged with `autodocs` but not `experimental` are shown.\n\n![Filtering by tags](../_assets/writing-stories/tag-filter.png)\n\nFiltering by tags is a powerful way to focus on a subset of stories, especially in large Storybook projects. When searching, the filter is applied first, so search results are limited to the currently filtered tags.\n\n## Recipes\n\n### Docs-only stories\n\nIt can sometimes be helpful to provide example stories for documentation purposes, but you want to keep the sidebar navigation more focused on stories useful for development. By enabling the `autodocs` tag and removing the `dev` tag, a story becomes docs-only: appearing only in the [docs page](../writing-docs/autodocs.mdx) and not in Storybook's sidebar.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"tags-docs-only-in-meta.md\" />\n\n{/* prettier-ignore-end */}\n\n### Combo stories, still tested individually\n\nFor a component with many variants, like a Button, a grid of those variants all together can be a helpful way to visualize it. But you may wish to test the variants individually. You can accomplish this with tags like so:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"tags-combo-example.md\" />\n\n{/* prettier-ignore-end */}\n\n### Test cases that don't clutter the sidebar\n\n(⚠️ **Experimental**: While this API is available for all tags, the built-in `_test` tag is experimental)\n\nIf you're using the [experimental `.test` method on CSF Factories](https://github.com/storybookjs/storybook/discussions/30119), you can alter the default behavior of the `_test` tag to exclude tests from the sidebar by default. This reduces clutter in the sidebar while still allowing you to run tests for all stories, or adjust the filter to show tests when needed.\n\n<CodeSnippets path=\"main-config-tags-test-fn-exclude.md\" />\n"
  },
  {
    "path": "docs/writing-stories/typescript.mdx",
    "content": "---\ntitle: 'Writing stories in TypeScript'\n---\n\nWriting your stories in [TypeScript](https://www.typescriptlang.org/) makes you more productive. You don't have to jump between files to look up component props. Your code editor will alert you about missing required props and even autocomplete prop values, just like when using your components within your app. Plus, Storybook infers those component types to auto-generate the [Controls](../api/doc-blocks/doc-block-controls.mdx) table.\n\nStorybook has built-in TypeScript support, so you can get started with zero configuration required.\n\n<If renderer={['react', 'vue', 'angular', 'web-components']}>\n\n<Callout variant=\"positive\" icon=\"💡\">\n  [CSF Next](../api/csf/csf-next.mdx) (currently in preview) provides significantly improved TypeScript support, which infers component types automatically and requires no explicit typing for most cases. We recommend using CSF Next for all new TypeScript stories. \n\n  You only need to add types when using [custom args](#typing-custom-args).\n</Callout>\n\n</If>\n\n## Typing stories with `Meta` and `StoryObj`\n\nWhen writing stories, there are two aspects that are helpful to type. The first is the [component meta](./index.mdx#default-export), which describes and configures the component and its stories. In a [CSF file](../api/csf/index.mdx), this is the default export. The second is the [stories themselves](./index.mdx#defining-stories).\n\nStorybook provides utility types for each of these, named `Meta` and `StoryObj`. Here's an example CSF file using those types:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"typed-csf-file.md\" />\n\n{/* prettier-ignore-end */}\n\n### Props type parameter\n\n`Meta` and `StoryObj` types are both [generics](https://www.typescriptlang.org/docs/handbook/2/generics.html#working-with-generic-type-variables), so you can provide them with an optional prop type parameter for the component type or the component's props type (e.g., the `typeof Button` portion of `Meta<typeof Button>`). By doing so, TypeScript will prevent you from defining an invalid arg, and all [decorators](./decorators.mdx), [play functions](./play-function.mdx), or [loaders](./loaders.mdx) will type their function arguments.\n\nThe example above passes a component type. See [**Typing custom args**](#typing-custom-args) for an example of passing a props type.\n\n### Using `satisfies` for better type safety\n\n<IfRenderer renderer={['angular', 'web-components']}>\n  <Callout variant=\"info\">\n    We are not yet able to provide additional type safety using the `satisfies` operator with Angular and Web components.\n\n    <details>\n      <summary>More info</summary>\n\n      Both Angular and Web components utilize a class plus decorator approach. The decorators provide runtime metadata, but do not offer metadata at compile time.\n\n      As a result, it appears impossible to determine if a property in the class is a required property or an optional property (but non-nullable due to a default value) or a non-nullable internal state variable.\n\n      For more information, please refer to [this discussion](https://github.com/storybookjs/storybook/discussions/20988).\n    </details>\n  </Callout>\n</IfRenderer>\n\nIf you are using TypeScript 4.9+, you can take advantage of the new [`satisfies`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html) operator to get stricter type checking. Now you will receive type errors for missing required args, not just invalid ones.\n\nUsing `satisfies` to apply a story's type helps maintain type safety when sharing a [play function](./play-function.mdx) across stories. Without it, TypeScript will throw an error that the `play` function may be undefined. The `satisfies` operator enables TypeScript to infer whether the play function is defined or not.\n\nFinally, use of `satisfies` allows you to pass `typeof meta` to the `StoryObj` generic. This informs TypeScript of the connection between the `meta` and `StoryObj` types, which allows it to infer the `args` type from the `meta` type. In other words, TypeScript will understand that args can be defined both at the story and meta level and won't throw an error when a required arg is defined at the meta level, but not at the story level.\n\n## Typing custom args\n\nSometimes stories need to define args that aren’t included in the component's props. For this case, you can use an [intersection type](https://www.typescriptlang.org/docs/handbook/2/objects.html#intersection-types) to combine a component's props type and your custom args' type. For example, here's how you could use a `footer` arg to populate a child component:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"page-story-slots.md\"  />\n\n{/* prettier-ignore-end */}\n\n<IfRenderer renderer=\"vue\">\n\n## Vue specific tips\n\nVue has excellent support for TypeScript, and we have done our utmost to take advantage of that in the stories files. For example, consider the following strongly typed Vue 3 single file component (SFC):\n\n```html\n<script setup lang=\"ts\">\n  defineProps<{ count: number; disabled: boolean }>();\n\n  const emit = defineEmits<{\n    (e: 'increaseBy', amount: number): void;\n    (e: 'decreaseBy', amount: number): void;\n  }>();\n</script>\n\n<template>\n  <div class=\"card\">\n    {{ count }}\n    <button @click=\"emit('increaseBy', 1)\" :disabled=\"disabled\">Increase by 1</button>\n    <button @click=\"$emit('decreaseBy', 1)\" :disabled=\"disabled\">Decrease by 1</button>\n  </div>\n</template>\n```\n\nYou can type check SFC files with `vue-tsc` and get editor support in VSCode by installing the official [Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar).\n\nThis setup will add type support for `*.vue` imports to your `*.stories.ts` files, providing the same type safety and autocomplete features.\n\n[CSF Next](../api/csf/csf-next.mdx) adds support for [Generic Vue components](https://vuejs.org/api/sfc-script-setup.html#generics) (using `<script lang=\"ts\" setup generic=\"T\">`). Simply pass the type parameter directly to the component:\n\n```ts title=\"GenericList.stories.ts\"\nimport preview from '../.storybook/preview';\n\nimport GenericList from './GenericList.vue';\n\nconst meta = preview.meta({\n  // 👇 Pass the type parameter directly\n  component: GenericList<{ id: number; name: string }>,\n});\n\nexport const Example = meta.story({\n  args: {\n    items: [{ id: 1, name: 'John Doe' }],\n    // 👇 item is correctly typed as { id: number; name: string }\n    getLabel: (item) => item.name,\n  },\n});\n```\n\nPrior CSF versions suffer from a [long-standing type inference issue](https://github.com/storybookjs/storybook/issues/24238) where the generic type `T` would default to `unknown`.\n\n</IfRenderer>\n\n<IfRenderer renderer=\"svelte\">\n  ## Svelte specific tips\n\n  Svelte offers excellent TypeScript support for .svelte files. For example, consider the following component. You can run type checks using svelte-check and add VSCode editor support with the [Svelte for VSCode extension](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode).\n\n  ```svelte\n  <script lang=\"ts\">\n    let count: number = $state(0);\n    let disabled: boolean = $state(false);\n\n    const increaseBy = () => {\n      count += 1\n    };\n    \n    const decreaseBy = () => {\n      count -= 1\n    };\n  </script>\n\n  <div class=\"card\">\n    {count}\n    <button onclick={increaseBy} {disabled}> Increase by 1 </button>\n    <button onclick={decreaseBy} {disabled}> Decrease by 1 </button>\n  </div>\n  ```\n\n  The same setup works with Svelte stories files too, providing both type safety and autocompletion.\n</IfRenderer>\n\n<If renderer=\"angular\">\n\n## Angular specific tips\n\n[CSF 3](../api/csf/index.mdx) offers basic TypeScript support for Angular components, but it does not infer component types.\n\n[CSF Next](../api/csf/csf-next.mdx) is able to infer types for Angular components, but the inferred types will be optional (i.e. `Partial<T>`). In other words, required props will not be enforced.\n\nIf you wish to have required props enforced, you can explicitly provide the component's props type to `preview.type` as shown in the following example:\n\n```ts\nimport preview from '../.storybook/preview';\n\nimport { MyComponent } from './my-component.component';\n\ninterface MyComponentProps {\n  requiredProp: string;\n  optionalProp?: number;\n}\n\nconst meta = preview.type<{ args: MyComponentProps }>().meta({\n  component: 'MyComponent',\n});\n```\n\n</If>\n\n<If renderer=\"web-components\">\n\n## Web Components specific tips\n\n[CSF 3](../api/csf/index.mdx) offers basic TypeScript support for web components, but it does not infer component types and provides no type generics for `Meta` and `StoryObj`.\n\n[CSF Next](../api/csf/csf-next.mdx) is able to infer types for web components, but only if the [custom element is declared in the global `HTMLElementTagNameMap` interface](https://lit.dev/docs/components/defining/#typescript-typings). You can do this by adding a declaration like the following to your project:\n\n```ts\ndeclare global {\n  interface HTMLElementTagNameMap {\n    \"my-element\": MyElement;\n  }\n}\n```\n\nAdditionally, the inferred types will be optional (i.e. `Partial<T>`). In other words, required props will not be enforced.\n\nIf you wish to have required props enforced, you can explicitly provide the component's props type to `preview.type` as shown in the following example:\n\n```ts\nimport preview from '../.storybook/preview';\n\ninterface MyElementProps {\n  requiredProp: string;\n  optionalProp?: number;\n}\n\nconst meta = preview.type<{ args: MyElementProps }>().meta({\n  component: 'my-element',\n});\n```\n\n</If>"
  },
  {
    "path": "docs/writing-tests/accessibility-testing.mdx",
    "content": "---\ntitle: 'Accessibility tests'\nsidebar:\n  order: 3\n  title: Accessibility tests\n---\n\nWeb accessibility is the practice of making websites and apps accessible and inclusive to all people, regardless of ability or the technology they’re using. That means supporting requirements such as keyboard navigation, screen reader support, sufficient color contrast, etc.\n\nAccessibility is not only the right thing to do, but it is increasingly mandated. For example, the [European accessibility act](https://ec.europa.eu/social/main.jsp?catId=1202) is scheduled to go into law in June 2025. Similarly in the US, laws like the [Americans with Disabilities Act (ADA)](https://www.ada.gov/) and [Section 508 of the Rehabilitation Act](https://www.section508.gov/) apply to many public-facing services. Many of these laws are based on [WCAG](https://www.w3.org/WAI/standards-guidelines/wcag/), a standardized guideline for making web content accessible.\n\nAccessibility tests audit the rendered DOM against a set of heuristics based on WCAG rules and other industry-accepted best practices. They act as the first line of QA to catch blatant accessibility violations.\n\n## Install the addon\n\nStorybook provides an Accessibility (a11y) addon to help ensure the accessibility of your components. It is built on top of Deque’s [axe-core library](https://github.com/dequelabs/axe-core), which automatically catches [up to 57% of WCAG issues](https://www.deque.com/blog/automated-testing-study-identifies-57-percent-of-digital-accessibility-issues/).\n\nRun this command to install and configure the addon in your project:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"addon-a11y-add.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\">\n\nStorybook's [`add`](../api/cli-options.mdx#add) command automates the addon's installation and setup. To install it manually, see our [documentation](../addons/install-addons.mdx#manual-installation) on how to install addons.\n\n</Callout>\n\nYour Storybook will now include some features to check the accessibility of your components, including a button in the toolbar to simulate different vision impairments and an Accessibility addon panel to check for violations.\n\n![Storybook UI with accessibility features annotated](../_assets/writing-tests/addon-a11y-annotated.png)\n\n### Integration with Vitest addon\n\nThe accessibility addon is designed to integrate with the [Vitest addon](./integrations/vitest-addon/index.mdx), so that you can [run accessibility tests](#run-accessibility-tests) alongside your component tests.\n\nTo get started, run this command, which will install and configure the Vitest addon and Vitest:\n\n<CodeSnippets path=\"addon-test-install.md\" />\n\nThe full installation instructions, including project requirements, are available in the [Vitest addon documentation](./integrations/vitest-addon/index.mdx#install-and-set-up).\n\n## Check for violations\n\nWhen you navigate to a story, automated accessibility checks are run and the results are reported in the Accessibility addon panel. \n\nThe results are broken down into three sub-tabs:\n\n- **Violations** are known violations of WCAG rules and best practices\n- **Passes** are known non-violations\n- **Incomplete** highlights areas that you should confirm manually because they could not be checked automatically\n\n## Configure\n\nBecause the addon is built on top of `axe-core`, much of the configuration available maps to its available options:\n\n| Property                  | Default     | Description                                                                                                                                                                         |\n| ------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `parameters.a11y.context` | `'body'`    | [Context](https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter) passed to `axe.run`. Defines which elements to run checks against.                       |\n| `parameters.a11y.config`  | (see below) | Configuration passed to [`axe.configure()`](https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axeconfigure). Most commonly used to [configure individual rules](#individual-rules). |\n| `parameters.a11y.options` | `{}`        | [Options](https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter) passed to `axe.run`. Can be used to adjust the rulesets checked against.                 |\n| `parameters.a11y.test`    | `undefined` | Determines test behavior when run with the Vitest addon. [More details below](#test-behavior).                                                                                      |\n| `globals.a11y.manual`     | `undefined` | Set to `true` to prevent stories from being automatically analyzed when visited. [More details below](#disable-automated-checks)                                                    |\n\n<details>\n<summary>Default `parameters.a11y.config`</summary>\n\nBy default, Storybook disables the [region rule](https://dequeuniversity.com/rules/axe/4.10/region?application=RuleDescription), which does not typically apply to components in stories and can lead to false negatives.\n\n```js\n{\n  rules: [\n    {\n      id: 'region',\n      enabled: false,\n    }\n  ]\n}\n```\n\n</details>\n\nWe’ll share examples to show how to use some of these configuration properties.\n\nHere, they are applied to all stories in a project, in `.storybook/preview.ts`:\n\n<CodeSnippets path=\"addon-a11y-config-in-preview.md\" />\n\nYou can also apply the configuration for all stories in a file (in the `meta`) or an individual story:\n\n<CodeSnippets path=\"addon-a11y-config-in-meta-and-story.md\" />\n\n### Rulesets\n\nThe addon uses the `axe-core` library to run accessibility checks. By default, it runs a set of rules that are based on the WCAG 2.0 and 2.1 guidelines, as well as some best practices:\n\n- [WCAG 2.0 Level A & AA Rules](https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md#wcag-20-level-a--aa-rules)\n- [WCAG 2.1 Level A & AA Rules](https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md#wcag-21-level-a--aa-rules)\n- [Best Practices Rules](https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md#best-practices-rules)\n\nYou can find a breakdown of these rulesets, as well as the other rulesets available in [axe-core’s documentation](https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md#wcag-2x-level-aaa-rules).\n\nTo change the rules that are checked against (e.g. to check against WCAG 2.2 AA or WCAG 2.x AAA rules), use the [`runOnly` option](https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter-examples):\n\n<CodeSnippets path=\"addon-a11y-config-rulesets-in-preview.md\" />\n\n### Individual rules\n\nYou can also enable, disable, or configure individual rules. This can be done in the `config` property of the `parameters.a11y` object. For example:\n\n<CodeSnippets path=\"addon-a11y-config-rules-in-story.md\" />\n\n### Test behavior\n\nYou can configure accessibility tests with the `parameters.a11y.test` [parameter](../writing-stories/parameters.mdx), which determines the behavior of accessibility tests for a story when run with either the [Vitest addon](./integrations/vitest-addon/index.mdx) or the [test-runner](./integrations/test-runner.mdx). The parameter accepts three values:\n\n| Value     | Description                                                                              |\n| --------- | ---------------------------------------------------------------------------------------- |\n| `'off'`   | Do not run accessibility tests (you can still manually verify via the addon panel)       |\n| `'todo'`  | Run accessibility tests; violations return a warning in the Storybook UI                 |\n| `'error'` | Run accessibility tests; violations return a failing test in the Storybook UI and CLI/CI |\n\nLike other parameters, you can define it at the project level in `.storybook/preview.js|ts`, the component level in the meta (or default export) of the story file, or the individual story level. For example, to fail on accessibility tests for all stories in a file except one:\n\n<CodeSnippets path=\"addon-a11y-parameter-example.md\" />\n\n<Callout variant=\"info\">\n\nWhy is the value called \"todo\" instead of \"warn\"? This value is intended to serve as a literal `TODO` in your codebase. It can be used to mark stories that you know have accessibility issues but are not ready to fix yet. This way, you can keep track of them and address them later.\n\nThe `'off'` value should only be used for stories that do not need to be tested for accessibility, such as one used to demonstrate an antipattern in a component's usage.\n\nYou can also [disable individual rules](#individual-rules) when they are not applicable to your use case.\n\n</Callout>\n\n### Excluded elements\n\nSometimes, it may be necessary to exclude certain elements from the accessibility checks. For this, you can define a custom [context](https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter) to select which elements are included (or excluded) when running checks. For example, this story will ignore elements with the class `no-a11y-check`:\n\n<CodeSnippets path=\"addon-a11y-config-context-in-story.md\" />\n\n### Disable automated checks\n\nWhen you disable automated accessibility checks, the addon will not run any tests when you navigate to a story or when you [run the tests with the Vitest addon](#run-accessibility-tests). You can still manually trigger checks in the Accessibility addon panel. This is useful for stories that are not meant to be accessible, such as those demonstrating an antipattern or a specific use case.\n\n<If renderer=\"svelte\">\n\n  If you are using Svelte CSF, you can turn off automated accessibility checks for stories or components by adding globals to your story or adjusting the `defineMeta` function with the required configuration. With a regular CSF story, you can add the following to your stories or meta (or default export):\n\n</If>\n\n<If notRenderer={['svelte']}>\n\n  Disable automated accessibility checks for stories or components by adding the following globals to your stories or meta (or default export):\n\n</If>\n\n<CodeSnippets path=\"addon-a11y-disable.md\" />\n\n## Run accessibility tests\n\n### With the Vitest addon\n\nIf you're using the [Vitest addon](./integrations/vitest-addon/index.mdx), you can run your accessibility tests, as part of component tests, in these ways:\n\n- [In the Storybook UI](./integrations/vitest-addon/index.mdx#storybook-ui)\n- [In CI environments](./integrations/vitest-addon/index.mdx#in-ci)\n\nTo run accessibility tests in the Storybook UI, first expand the testing widget in the sidebar and check the Accessibility checkbox. Now, when you press the Run component tests button, the accessibility tests will be run along with any other tests you have configured.\n\n![Test widget, expanded, with accessibility checked](../_assets/writing-tests/test-widget-a11y-enabled.png)\n\nAfter running the tests, you will see the results in the sidebar, which will add a test status indicator next to each story that was tested. You can press on these indicators to open a menu with the Accessibility test result. Pressing on that result will navigate to that story and open the Accessibility panel, where you view details about each violation and suggestions toward how to fix them.\n\n![Storybook showing a failing accessibility test in both the sidebar story menu and the Accessibility panel](../_assets/writing-tests/test-a11y-overview.png)\n\nIf any of your tests have warnings or failures, the testing widget will show the number of warnings and failures. You can press on these to filter the stories in the sidebar to only show those with warnings or failures.\n\nIn CI, accessibility tests are run automatically for stories with [`parameters.a11y.test = 'error'`](#test-behavior) when you run the Vitest tests.\n\n### With the test-runner\n\nIf you're using the [test-runner](./integrations/test-runner.mdx), you can run your accessibility tests in the terminal or in CI environments.\n\nAccessibility tests are included in your test run when you have the Accessibility addon installed and [`parameters.a11y.test`](#test-behavior) is set to a value other than `'off'`.\n\n## Debug accessibility violations\n\nWhen you run accessibility tests, the results are reported in the Storybook UI. You can click on a violation to see more details about it, including the rule that was violated and suggestions for how to fix it.\n\nYou can also toggle on highlighting in the Storybook UI to see which elements are causing the violation, and click on a highlighted element to see the violations details in a popover menu.\n\n![Storybook UI with a highlighted element with a popover menu showing accessbility violation details](../_assets/writing-tests/addon-a11y-debug-violations.png)\n\n## Automate with CI\n\nWhen you run your accessibility tests with the Vitest addon, automating them is as simple as running them in your CI environment. For more information, please see the [testing in CI guide](./in-ci.mdx).\n\n<Callout variant=\"warning\">\n\nAccessibility tests will only produce errors in CI if you have set [`parameters.a11y.test`](#test-behavior) to `'error'`. If you set it to `'todo'`, there will be no accessibility-related errors, warnings, or output in CI, but you can still see the results as warnings in the Storybook UI when you run the tests locally.\n\n</Callout>\n\nIf you cannot use the Vitest addon, you can still run your tests in CI using the [test-runner](./integrations/test-runner.mdx).\n\n## Recommended workflow\n\nYou can use configuration to progressively work toward a more accessible UI by combining multiple test behaviors. For example, you can start with `'error'` to fail on accessibility violations, then switch to `'todo'` to mark components that need fixing, and finally remove the todos once all stories pass accessibility tests:\n\n1. Update your project configuration to fail on accessibility violations by setting [`parameters.a11y.test`](#test-behavior) to `'error'`. This ensures that all new stories are tested to meet accessibility standards.\n    \n   <CodeSnippets path=\"addon-a11y-parameter-error-in-preview.md\" />\n    \n2. You will likely find that many components have accessibility failures (and maybe feel a bit overwhelmed!).\n3. Take note of the components with accessibility issues and temporarily reduce their failures to warnings by applying the `'todo'` parameter value. This keeps accessibility issues visible while not blocking development. This is also a good time to commit your work as a baseline for future improvements.\n    \n   <CodeSnippets path=\"addon-a11y-parameter-todo-in-meta.md\" />\n    \n4. Pick a good starting point from the components you just marked `'todo'` (we recommend something like Button, for its simplicity and likelihood of being used within other components). Fix the issues in that component using the suggestions in the addon panel to ensure it passes accessibility tests, then remove the parameter.\n    \n   <CodeSnippets path=\"addon-a11y-parameter-remove.md\" />\n    \n5. Pick another component and repeat the process until you've covered all your components and you're an accessibility hero!\n\n## FAQ\n\n### What’s the difference between browser-based and linter-based accessibility tests?\n\nBrowser-based accessibility tests, like those found in Storybook, evaluate the rendered DOM because that gives you the highest accuracy. Auditing code that hasn't been compiled yet is one step removed from the real thing, so you won't catch everything the user might experience.\n\n### Why are my tests failing in different environments?\n\nWith the [Vitest addon](./integrations/vitest-addon/index.mdx), your tests run in Vitest using your project's configuration with Playwright's Chromium browser. This can lead to inconsistent test results reported in the Storybook UI or CLI. The inconsistency can be due to `axe-core` reporting different results in different environments, such as browser versions or configurations. If you encounter this issue, we recommend reaching out using the default communication channels (e.g., [GitHub discussions](https://github.com/storybookjs/storybook/discussions/new?category=help), [Github issues](https://github.com/storybookjs/storybook/issues/new?template=bug_report.yml)).\n\n### The addon panel does not show expected violations\n\nModern React components often use asynchronous techniques like [Suspense](https://react.dev/reference/react/Suspense) or [React Server Components (RSC)](https://react.dev/reference/rsc/server-components) to handle complex data fetching and rendering. These components don’t immediately render their final UI state. Storybook doesn’t inherently know when an async component has fully rendered. As a result, the a11y checks sometimes run too early, before the component finishes rendering, leading to false negatives (no reported violations even if they exist).\n\nTo address this issue, we have introduced a feature flag: `developmentModeForBuild`. This feature flag allows you to set `process.env.NODE_ENV` to `'development'` in built Storybooks, enabling development-related optimizations that are typically disabled in production builds. One of those development optimizations is React’s [`act` utility](https://react.dev/reference/react/act), which helps ensure that all updates related to a test are processed and applied before making assertions, like a11y checks.\n\nTo enable this feature flag, add the following configuration to your `.storybook/main.js|ts` file:\n\n<CodeSnippets path=\"main-config-features-development-mode-for-build.md\" />\n\n**More testing resources**\n\n* [Vitest addon](./integrations/vitest-addon/index.mdx) for running tests in Storybook\n* [Interaction testing](./interaction-testing.mdx) for user behavior simulation\n* [Visual testing](./visual-testing.mdx) for appearance\n* [Snapshot testing](./snapshot-testing.mdx) for rendering errors and warnings\n* [Test coverage](./test-coverage.mdx) for measuring code coverage\n* [CI](./in-ci.mdx) for running tests in your CI/CD pipeline\n* [End-to-end testing](./integrations/stories-in-end-to-end-tests.mdx) for simulating real user scenarios\n* [Unit testing](./integrations/stories-in-unit-tests.mdx) for functionality\n* [Test runner](./integrations/test-runner.mdx) to automate test execution\n"
  },
  {
    "path": "docs/writing-tests/in-ci.mdx",
    "content": "---\ntitle: Testing in CI\nhideRendererSelector: true\nsidebar:\n  order: 6\n  title: In CI\n---\n\nThe [Vitest addon](./integrations/vitest-addon/index.mdx) is great for automating your UI tests within Storybook. To have full confidence in your work, backed by tests, you need to run those automated tests in your continuous integration (CI) environment.\n\nThankfully, that’s quite easy!\n\n<Callout variant=\"info\">\n\nIf you cannot use the Vitest addon in your project, you can still run your stories as tests in CI using the test-runner. Follow the instructions in the [test-runner documentation](./integrations/test-runner.mdx#set-up-ci-to-run-tests) to set up the test-runner to run in CI in your project.\n\n</Callout>\n\n## Set up Storybook tests in CI\n\nRunning Storybook tests in CI is very similar to running them via CLI on your local machine: you run the same command, just in a different place.\n\nLet’s go step-by-step to set things up.\n\n### 1. Define `package.json` script\n\nFor convenience, define a script in your `package.json` to run the Storybook tests. This is the same command you would run locally, but it’s useful to have it in your CI workflow.\n\n```json title=\"package.json\"\n{ \n  \"scripts\": {\n    \"test-storybook\": \"vitest --project=storybook\"\n  }\n}\n```\n\nThis script calls the `vitest` CLI command and restricts it to the “storybook” project defined in your Vitest config, which was created when you installed the Vitest addon. (If you’ve renamed the project, adjust the script above accordingly.) You can also pass any additional `vitest` [CLI options](https://vitest.dev/guide/cli.html#options) you may require.\n\n### 2. Add a new CI workflow\n\nNext, we’ll create a new “UI Tests” workflow to run in our CI environment. You may also adjust an existing workflow, if you prefer.\n\nHere are some example configurations for popular CI providers:\n\n<details>\n<summary>GitHub Actions</summary>\n    \nCreate a file in the root of your repo, `.github/workflow/test-ui.yml`:\n\n```yaml title=\".github/workflows/test-ui.yml\"\nname: UI Tests\n\non: [push]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    container:\n      # Make sure to grab the latest version of the Playwright image\n      # https://playwright.dev/docs/docker#pull-the-image\n      image: mcr.microsoft.com/playwright:v1.58.2-noble\n    steps:\n      - uses: actions/checkout@v4\n      \n      - name: Setup Node\n        uses: actions/setup-node@v4\n        with:\n          node-version: 22.12.0\n      \n      - name: Install dependencies\n        run: npm ci\n      \n      - name: Run tests\n        run: npm run test-storybook\n```\n</details>\n\n<details>\n<summary>GitLab Pipelines</summary>\n\nCreate a file in the root of your repo, `.gitlab-ci.yml`:\n\n```yaml title=\".gitlab-ci.yml\"    \nimage: node:jod\n\nstages:\n  - UI_Tests\n\ncache:\n  key: $CI_COMMIT_REF_SLUG-$CI_PROJECT_DIR\n  paths:\n    - .npm/\n\nbefore_script:\n  # Install dependencies\n  - npm ci\nTest:\n  stage: UI_Tests\n  # Make sure to grab the latest version of the Playwright image\n  # https://playwright.dev/docs/docker#pull-the-image\n  image: mcr.microsoft.com/playwright:v1.58.2-noble\n  script:\n    - npm run test-storybook\n```\n</details>\n\n<details>\n<summary>Bitbucket Pipelines</summary>\n\nCreate a file in the root of your repo, `bitbucket-pipelines.yml`:\n\n```yaml title=\"bitbucket-pipelines.yml\"\nimage: node:jod\n\ndefinitions:\n  caches:\n    npm: $HOME/.npm\n\npipelines:\n  default:\n    - stage:\n        name: \"UI Tests\"\n        steps:\n          - step:\n              name: \"Run Tests\"\n              # Make sure to grab the latest version of the Playwright image\n              # https://playwright.dev/docs/docker#pull-the-image\n              image: mcr.microsoft.com/playwright:v1.58.2-noble\n              caches:\n                - npm\n                - node\n              script:\n                # Install dependencies\n                - npm ci\n                - npm run test-storybook\n```\n</details>\n\n<details>\n<summary>Circle CI</summary>\n\nCreate a file in the root of your repo, `.circleci/config.yml`:\n\n```yaml title=\".circleci/config.yml\"\nversion: 2.1\n    \nexecutors:\n  ui-testing:\n    docker:\n      # Make sure to grab the latest version of the Playwright image\n      # https://playwright.dev/docs/docker#pull-the-image\n      - image: mcr.microsoft.com/playwright:v1.58.2-noble\n    working_directory: ~/repo\n\njobs:\n  Test:\n    executor: ui-testing\n    steps:\n      - checkout\n      - restore_cache:\n          keys:\n            - v1-dependencies-{{ checksum \"package-lock.json\" }}\n            - v1-dependencies-\n      # Install dependencies\n      - run: npm ci\n      - run: npm run test-storybook\n      - save_cache:\n          name: Save NPM cache\n          paths:\n            - ~/.npm\n          key: v1-dependencies-{{ checksum \"package-lock.json\" }}\n\nworkflows:\n  UI_Tests:\n    jobs:\n      - Test\n```\n</details>\n\n<details>\n<summary>Travis CI</summary>\n\nCreate a file in the root of your repo, `.travis.yml`:\n\n```yaml title=\".travis.yml\"\nlanguage: node_js\nos: linux\ndist: jammy\n\nnode_js:\n  - 20\n\nbefore_script:\n  # Install dependencies and Playwright browsers so Vitest browser mode can run story tests\n  - npm ci && npm run playwright install chromium --with-deps\n\ncache: npm\n\njobs:\n  include:\n    - stage: \"UI Tests\"\n      name: \"Run tests\"\n      script: npm run test-storybook\n```\n</details>\n\n<details>\n<summary>Jenkins</summary>\n\nCreate a file in the root of your repo, `JenkinsFile`:\n\n```groovy title=\"JenkinsFile\"\npipeline {\n  agent any\n  tools {nodejs \"node\"}\n\n  stages {\n    stage('UI Tests'){\n      agent {\n        docker {\n          /*\n           * Make sure to grab the latest version of the Playwright image\n           * https://playwright.dev/docs/docker#pull-the-image\n           */\n          image 'mcr.microsoft.com/playwright:v1.58.2-noble'\n          reuseNode true\n        }\n      }\n      steps {\n        /* Install dependencies */\n        sh 'npm ci'\n        sh \"npm run test-storybook\"\n      }\n    }\n  }\n}\n```\n</details>\n\n<details>\n<summary>Azure Pipelines</summary>\n\nCreate a file in the root of your repo, `azure-pipelines.yml`:\n\n```yaml title=\"azure-pipelines.yml\"\ntrigger:\n  - main\n\npool:\n  vmImage: \"ubuntu-latest\"\n\nstages:\n  - stage: UI_Tests\n    displayName: \"UI Tests\"\n    jobs:\n      - job: Test\n        displayName: \"Storybook tests\"\n        # Make sure to grab the latest version of the Playwright image\n        # https://playwright.dev/docs/docker#pull-the-image\n        container: mcr.microsoft.com/playwright:v1.58.2-noble\n        variables:\n          npm_config_cache: $(Pipeline.Workspace)/.npm\n        steps:\n          - task: UseNode@1\n            displayName: \"Install Node.js\"\n            inputs:\n              version: \"22.12.0\"\n          - task: Cache@2\n            displayName: \"Install and cache dependencies\"\n            inputs:\n              key: 'npm | \"$(Agent.OS)\" | package-lock.json'\n              restoreKeys: |\n                npm | \"$(Agent.OS)\"\n              path: $(npm_config_cache)\n          - script: npm ci\n            condition: ne(variables.CACHE_RESTORED, 'true')\n          - task: CmdLine@2\n            displayName: \"Run tests\"\n            inputs:\n              script: npm run test-storybook\n```\n</details> \n\n<Callout variant=\"info\">\n\nStorybook Test uses Playwright to render your stories by default. For the fastest experience, you should use [a machine image that has Playwright already installed](https://playwright.dev/docs/docker#pull-the-image) (as in most of the snippets above).\n\n</Callout>\n\n#### 2.1 Debug test failures\n\nWhen a Storybook test fails, the failure output includes a link to the failing story. When running locally, this points to your local Storybook running at `localhost:6006`. But in CI, there is no active Storybook. Instead, you must first build and publish your Storybook, then inform the Vitest addon where your Storybook is published so that it can print useful story links.\n\nHere's an example using GitHub Actions. The steps are similar for other CI providers, though details in the syntax or configuration may vary.\n\nWhen deployments for services like Vercel, GitHub Pages, and others are performed, they follow a pattern of emitting a `deployment_status` event containing the newly generated URL under `deployment_status.environment_url`. This is the URL to the published Storybook instance.\n\nWe can pass that URL to the command using an environment variable, `SB_URL`.\n\n```diff title=\".github/workflows/test-storybook.yml\"\nname: Storybook Tests\n\n+ # 👇 Update this to only run when a deployment status is emitted\n+ on: deployment_status\n- on: [push]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    container:\n      image: mcr.microsoft.com/playwright:v1.58.2-noble\n+   # 👇 Only run on successful deployments\n+   if: github.event_name == 'deployment_status' && github.event.deployment_status.state == 'success'\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Setup Node\n        uses: actions/setup-node@v4\n        with:\n          node-version: 22.12.0\n          \n      - name: Install dependencies\n        run: npm ci\n\n      - name: Run tests\n        run: npm run test-storybook\n+       # 👇 Pass the Storybook URL as an environment variable\n+       env:\n+         SB_URL: '${{ github.event.deployment_status.environment_url }}'\n```\n\nFinally, we update the plugin configuration to use that environment variable in the [`storybookUrl` plugin option](./integrations/vitest-addon/index.mdx#storybookurl).\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"vitest-plugin-vitest-debug-option-ci.md\" />\n\n{/* prettier-ignore-end */}\n\nNow, when a test fails in CI, the printed story URL will point to the published Storybook, making debugging that failure a breeze!\n\n#### 2.2 Calculate code coverage\n\n<Callout variant=\"info\">\n\nFor more details on code coverage, check the [full guide](./test-coverage.mdx).\n\n</Callout>\n\nYou can calculate code coverage of your Storybook tests by passing the `--coverage` flag to the `vitest` command. Coverage is most useful when calculated comprehensively across all tests in your project, but you can also calculate it for just the Storybook tests.\n\nYou can either adjust the command in your `package.json` scripts:\n\n**For all tests:**\n\n```diff title=\"package.json\"\n{ \n  \"scripts\": {\n+   \"test\": \"vitest --coverage\"\n-   \"test\": \"vitest\"\n  }\n}\n```\n\n**For only Storybook tests:**\n\n```diff title=\"package.json\"\n{ \n  \"scripts\": {\n+   \"test-storybook\": \"vitest --project=storybook --coverage\"\n-   \"test-storybook\": \"vitest --project=storybook\"\n  }\n}\n```\n\nOr, if you only want to calculate coverage when running tests in CI, adjust your CI configuration like so:\n\n**For all tests:**\n\n```diff title=\"CI workflow file\"\n+ npm run test -- --coverage\n- npm run test\n```\n\n**For only Storybook tests:**\n\n```diff title=\"CI workflow file\"\n+ npm run test-storybook -- --coverage\n- npm run test-storybook\n```\n\n### 3. Run your workflow\n\nAssuming your CI is configured to run when you push your work to a pull request, you can test your new workflow by creating a new pull request (perhaps to fix an accessibility issue found by Storybook Test).\n\nWhen you do so, you should see the test result as a status check on the pull request screen. For example, in GitHub, a failing test run would look something like this:\n\n![GitHub pull request status checks, with a failing \"UI Tests / test\" check](../_assets/writing-tests/test-ci-workflow-pr-status-checks.png)\n\nClicking on the failure will take you to the full test output, including the link to the failing story (if you've [set up the `SB_URL` environment variable](#21-debug-test-failures)).\n\n![Test failure output in CI environment, with a link to the Storybook to debug](../_assets/writing-tests/test-ci-workflow-failure.png)\n\n## FAQs\n\n### How do I run other Vitest tests alongside my Storybook tests?\n\nSome projects have other tests run via Vitest, e.g. unit tests, in addition to those defined in Storybook.\n\nYou can run these tests independently by specifying the project filter in a separate script. For example, for a Vitest project called “unit”:\n\n```json title=\"package.json\"\n{ \n  \"scripts\": {\n    \"test-storybook\": \"vitest --project=storybook\",\n    \"test-unit\": \"vitest --project=unit\"\n  }\n}\n```\n\nThen, in your workflow, call this script alongside the Storybook one:\n\n```yaml title=\".github/workflows/test.yml\"\n- name: Run tests\n  run: |\n    npm run test-unit\n    npm run test-storybook\n```\n\nYou may also choose to run all tests together by simply omitting the `--project=storybook` filter from the `package.json` script:\n\n```json title=\"package.json\"\n{ \n  \"scripts\": {\n    \"test\": \"vitest\"\n  }\n}\n```\n\nThe workflow would then look like:\n\n```yaml title=\".github/workflows/test.yml\"\n- name: Run tests\n  run: |\n    npm run test\n```\n\n**More testing resources**\n\n* [Vitest addon](./integrations/vitest-addon/index.mdx) for running tests in Storybook\n* [Interaction testing](./interaction-testing.mdx) for user behavior simulation\n* [Accessibility testing](./accessibility-testing.mdx) for accessibility\n* [Visual testing](./visual-testing.mdx) for appearance\n* [Snapshot testing](./snapshot-testing.mdx) for rendering errors and warnings\n* [Test coverage](./test-coverage.mdx) for measuring code coverage\n* [End-to-end testing](./integrations/stories-in-end-to-end-tests.mdx) for simulating real user scenarios\n* [Unit testing](./integrations/stories-in-unit-tests.mdx) for functionality\n* [Test runner](./integrations/test-runner.mdx) to automate test execution\n"
  },
  {
    "path": "docs/writing-tests/index.mdx",
    "content": "---\ntitle: 'How to test UIs with Storybook'\nhideRendererSelector: true\nsidebar:\n  order: 3\n  title: Testing\n---\n\nStorybook [stories](../writing-stories/index.mdx) are test cases for your UI components in their various states and configurations. With Storybook, you can develop and test your components at the same time, in multiple ways, with instant feedback.\n\nStorybook tackles UI component testing from a holistic perspective, ensuring that you can not only execute component tests quickly and reliably, but that you also have well-established patterns to develop, debug, maintain, and even collaborate on these tests across the development lifecycle.\n\n## Get started\n\nIf your project is using Vite, you can likely use the [Vitest addon](./integrations/vitest-addon/index.mdx) to run your component tests in Storybook. This addon is built on top of [Vitest](https://vitest.dev/), a fast and lightweight test runner that works seamlessly with Vite.\n\nRun this command, which will install and configure the Vitest addon and Vitest:\n\n<CodeSnippets path=\"addon-test-install.md\" />\n\nThe full installation instructions, including project requirements, are available in the [Vitest addon documentation](./integrations/vitest-addon/index.mdx#install-and-set-up).\n\nOnce your project is set up, you will see a testing widget in the bottom of your sidebar. After running tests, you will also see test status indicators on sidebar items. Additionally, many tests can be debugged with an addon panel.\n\n![Storybook app with story status indicators, testing widget, and interactions panel annotated](../_assets/writing-tests/testing-ui-overview.png)\n\nIf you cannot use the Vitest addon in your project, you can still run tests using the [test-runner](./integrations/test-runner.mdx).\n\nNext, we’ll cover some key concepts of testing in Storybook.\n\n## Key concepts\n\nTesting in Storybook is similar to other testing environments. Most of the knowledge and techniques you’ve been using apply here, too. But there are also some significant improvements.\n\n### Component tests\n\nA component test is a test which:\n\n- Renders a component in the browser for high fidelity\n- Simulates a user interacting with actual UI, like an end-to-end (E2E) test\n- Only tests a unit (e.g. a single component) of UI, **and** can reach into the implementation to mock things or manipulate data, like a unit test\n\nThis combination of using a real browser, simulating behavior, and mocking provides a powerful means of testing the functional aspects of your UI.\n\nIn Storybook, the entire testing experience is built around component tests. This means that you can run your tests in the same environment as your stories, with the same tools and techniques.\n\n### Storybook Test\n\nStorybook Test enables real-time testing of your stories, through the [Vitest addon](./integrations/vitest-addon/index.mdx). It uses a Vitest plugin to automatically transform your stories into real Vitest tests, which are then run with Vitest’s browser mode.\n\n### Watch mode\n\nGet instant test feedback as you develop with watch mode. It will watch your code—either the component source or the tests—for changes and automatically re-run only the relevant tests. It’s perfect for test-driven development, where you write your tests first and then the component.\n\nTo activate watch mode, press the watch mode button (the eye icon) in the testing widget:\n\n![Testing widget with watch mode enabled](../_assets/writing-tests/test-widget-watch-mode-enabled.png)\n\n### CI\n\nIf you’re not running Storybook Test as part of your CI, you’re missing out on the biggest benefit it provides: catching bugs on PRs before you merge them.\n\nIf you are already running `vitest` as part of your CI then your stories should automatically run as tests “for free” when you commit your changes to Git.\n\nIf you’re not yet running Vitest in CI, you should set that up. First by adding a new script to your `package.json`:\n\n```json title=\"package.json\"\n{ \n  \"scripts\": {\n    \"test-storybook\": \"vitest --project=storybook\"\n  }\n}  \n```\n\nNote that this assumes you have a Vitest project called “storybook” for your stories, which is the default configuration when you install Storybook Test. If you’ve renamed it, adjust the script accordingly.\n\nNext, add a new CI workflow. \n\n<details>\n<summary>If you use Github Actions that would look like:</summary>\n    \n  ```yaml title=\".github/workflows/test-storybook.yml\"\n  name: Storybook Tests\n  \n  on: [push]\n  \n  jobs:\n    test:\n      runs-on: ubuntu-latest\n      container:\n        # Make sure to grab the latest version of the Playwright image\n        # https://playwright.dev/docs/docker#pull-the-image\n        image: mcr.microsoft.com/playwright:v1.58.2-noble\n      steps:\n        - uses: actions/checkout@v4\n        \n        - name: Setup Node\n          uses: actions/setup-node@v4\n          with:\n            node-version: 22.12.0\n        \n        - name: Install dependencies\n          run: npm ci\n        \n        - name: Run tests\n          run: npm run test-storybook\n  ```\n</details>\n\nIf you are using a different CI provider, please consult our full [CI guide](./in-ci.mdx) for more information.\n\nStorybook Test uses Playwright to render your stories by default. For the fastest experience, you should use [a machine image that has Playwright already installed](https://playwright.dev/docs/docker#pull-the-image) (as in the snippet above).\n\n### Coverage\n\nCode coverage provides insight into which code is tested or not. It functions as a guardrail as you develop, to help be sure your work is covered by the proper tests.\n\nIn Storybook Test, you can see the coverage provided by your stories in two ways. First, a summary is displayed in the testing widget. Second, clicking that coverage summary will open a full, interactive report.\n\n![Two browser windows. The frontmost one shows the interactive coverage report generated by the Vitest addon. The background one shows the Storybook sidebar with the coverage summary visible in the testing widget.](../_assets/writing-tests/coverage-summary-and-report.png)\n\nIn the report, clicking through to a specific component shows the exact branches of code that are covered or not covered:\n\n![Interactive coverage report generated by the Vitest addon, showing the Page component's reported source](../_assets/writing-tests/coverage-report-html-component.png)\n\nEach project’s coverage report will look different, but the important things to note are:\n\n1. **The overall line/branch coverage**, which serves as a high-level health check.\n2. **Specific lines/branches** that are not covered, which are potential test gaps.\n\nIn our point of view, the goal is not to get 100% coverage and fill every gap, but rather to have a barometer to help you judge code/test changes, and for the gaps to inform you of key states or interactions that are untested. For example, if you’re building a prototype you might skip testing altogether, whereas in a critical app you might want to dot every i and cross every t.\n\nRunning coverage analysis can slow down your test runs, so it is turned off by default. To activate coverage, check the coverage checkbox in the testing widget.\n\n![Testing widget with coverage activated](../_assets/writing-tests/test-widget-coverage-enabled.png)\n\n#### Coverage in CI\n\nAnd while we’re looking at coverage, update your CI workflow to include it:\n\n```diff\n- yarn test\n+ yarn test --coverage\n```\n\n<Callout variant=\"info\" icon=\"💡\">\n\nWhy are we running all tests (`yarn test`) instead of just the Storybook tests (`yarn test-storybook`)? Because a coverage report is most accurate when accounting for all tests in your project, not just the stories you've written.\n\nSeeing [Storybook-specific coverage](./test-coverage.mdx#storybook-ui) can be helpful, but in CI output, you want to see the comprehensive coverage of your project.\n\n</Callout>\n\nThis way we can track the coverage change in every PR.\n\nThose are the key concepts you’ll need to test in Storybook. Now, let’s look at the different types of tests you can perform.\n\n## Types of tests\n\nStorybook Test supports a variety of testing types to help you validate your work in multiple dimensions.\n\n### Render tests\n\nThe most important tool for testing your components in Storybook is stories that render your components in various states. \n\nHowever, you might not be aware that a basic story is also a [smoke test](https://en.wikipedia.org/wiki/Smoke_testing_(software)), which we call a **render test**. The test passes when the story renders successfully and fails when it errors.\n\n![Storybook app showing a failing render test](../_assets/writing-tests/interactions-test-failure-render.png)\n\nDepending on the complexity of your components, you might be able to capture many of your key UI states this way.\n\n### [Interaction tests](./interaction-testing.mdx)\n\nRender tests are a very basic kind of interaction test. To test stateful components or verify interactive behavior, you define a play function for your story:\n\n<CodeSnippets path=\"interaction-test-simple.md\" />\n\nBut `play` functions can also be used for setting up state, creating spies, mocking out the network, simulating user interactions with your components, asserting output, and more. They are the meat and potatoes of testing and are the foundation for the rest of your testing journey in Storybook. \n\nHere’s a more complex example, which includes [spying and mocking](./interaction-testing.mdx#spying-on-functions-with-fn) via the `fn` utility.\n\n<CodeSnippets path=\"interaction-test-complex.md\" />\n\nFor more information on how to write interaction tests and mocks using the `play` function, please see the [interaction testing guide](./interaction-testing.mdx#writing-interaction-tests).\n\n### [Accessibility tests](./accessibility-testing.mdx)\n\nStorybook’s [Accessibility (A11y) addon](https://storybook.js.org/addons/@storybook/addon-a11y) runs a set of automated checks on your stories to help ensure your components can be used by all users, regardless of ability or technology they're using. That means supporting requirements such as: keyboard navigation, screen reader support, usable color contrast, etc.\n\nAccessibility is not only the right thing to do, but it is increasingly mandated. For example, the [European accessibility act](https://ec.europa.eu/social/main.jsp?catId=1202) is scheduled to go into law in June 2025. Similarly in the US, laws like the [Americans with Disabilities Act (ADA)](https://www.ada.gov/) and [Section 508 of the Rehabilitation Act](https://www.section508.gov/) apply to many public-facing services.\n\nTo activate accessibility checks alongside your component tests, check the Accessibility checkbox in the testing widget.\n\n![Testing widget with accessibility activated](../_assets/writing-tests/test-widget-a11y-enabled.png)\n\nOnce activated, you will see accessibility failures in the sidebar.\n\n![Storybook showing a failing accessibility test in both the sidebar story menu and the Accessibility panel](../_assets/writing-tests/test-a11y-overview.png)\n\nAny failures can be debugged in the Accessibility addon panel.\n\n![Storybook app with accessibility panel open, showing violations and an interactive popover on the violating elements in the preview](../_assets/writing-tests/addon-a11y-debug-violations.png)\n\n### [Visual tests](./visual-testing.mdx)\n\nVisual tests are the most efficient way to test your components. With the click of a button you can take snapshots of every story in your Storybook and compare those snapshots to baselines — last known “good” snapshots. Not only does this allow you to check the appearance of your components, but they are also able to check a large subset of component functionality [without having to write or maintain any test code](https://storybook.js.org/blog/visual-testing-is-the-greatest-trick-in-ui-development/)!\n\nStorybook supports cross-browser visual testing natively using [Chromatic](https://www.chromatic.com/storybook/?ref=storybook_site), a cloud service made by the Storybook team. When you enable visual testing, every story is automatically turned into a test. This gives you instant feedback on UI bugs directly in Storybook.\n\n![Visual test panel with diff](../_assets/writing-tests/vta-changes-found.png)\n\n### [Snapshot tests](./snapshot-testing.mdx)\n\nIn most cases, the other testing types will provide more coverage with less effort. But there are scenarios where it can be helpful to compare the rendered markup of a story against a known baseline. For example, it can help identify markup changes that trigger rendering errors.\n\n## Reusing stories in other testing tools\n\nStories are made to be reusable, so you can use them as test cases in popular testing tools.\n\n### [End-to-end](./integrations/stories-in-end-to-end-tests.mdx)\n\nSometimes you need to test a full workflow, with the full running stack. In those cases, you can still use your stories by importing them within your Playwright or Cypress end-to-end (E2E) tests.\n\n### [Unit](./integrations/stories-in-unit-tests.mdx)\n\nIf you prefer, you can reuse your Storybook stories in a traditional testing environment, like Vitest or Jest.\n\n**More testing resources**\n\n* [Vitest addon](./integrations/vitest-addon/index.mdx) for running tests in Storybook\n* [Interaction testing](./interaction-testing.mdx) for user behavior simulation\n* [Accessibility testing](./accessibility-testing.mdx) for accessibility\n* [Visual testing](./visual-testing.mdx) for appearance\n* [Snapshot testing](./snapshot-testing.mdx) for rendering errors and warnings\n* [Test coverage](./test-coverage.mdx) for measuring code coverage\n* [CI](./in-ci.mdx) for running tests in your CI/CD pipeline\n* [End-to-end testing](./integrations/stories-in-end-to-end-tests.mdx) for simulating real user scenarios\n* [Unit testing](./integrations/stories-in-unit-tests.mdx) for functionality\n* [Test runner](./integrations/test-runner.mdx) to automate test execution\n"
  },
  {
    "path": "docs/writing-tests/integrations/index.mdx",
    "content": "---\ntitle: Integrations\nsidebar:\n  order: 7\n  title: Integrations\n---"
  },
  {
    "path": "docs/writing-tests/integrations/stories-in-end-to-end-tests.mdx",
    "content": "---\ntitle: 'Stories in end-to-end tests'\nsidebar:\n  title: End-to-end tests\n  order: 4\n---\n\nStorybook seamlessly integrates with additional testing frameworks like [Cypress](https://www.cypress.io/) and [Playwright](https://playwright.dev/) to provide a comprehensive testing solution. By leveraging the Component Story Format (CSF), developers can write test cases that simulate user interactions and verify the behavior of individual components within the Storybook environment. This approach enables developers to thoroughly test their components' functionality, responsiveness, and visual appearance across different scenarios, resulting in more robust and reliable applications.\n\n## With Cypress\n\n[Cypress](https://www.cypress.io/) is an end-to-end testing framework. It enables you to test a complete instance of your application by simulating user behavior. With Component Story Format, your stories are reusable with Cypress. Each named export (in other words, a story) is renderable within your testing setup.\n\nAn example of an end-to-end test with Cypress and Storybook is testing a login component for the correct inputs. For example, if you had the following story:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"login-form-with-play-function.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  The play function contains small snippets of code that run after the story renders. It allows you to sequence interactions in stories.\n</Callout>\n\nWith Cypress, you could write the following test:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"component-cypress-test.md\" />\n\n{/* prettier-ignore-end */}\n\nWhen Cypress runs your test, it loads Storybook's isolated iframe and checks if the inputs match the test values.\n\n## With Playwright\n\n[Playwright](https://playwright.dev/) is a browser automation tool and end-to-end testing framework from Microsoft. It offers cross-browser automation, mobile testing with device emulation, and headless testing. With Component Story Format, your stories are reusable with Playwright. Each named export (in other words, a story) is renderable within your testing setup.\n\nA real-life scenario of user flow testing with Playwright would be how to test a login form for validity. For example, if you had the following story already created:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"login-form-with-play-function.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  The play function contains small snippets of code that run after the story renders. It allows you to sequence interactions in stories.\n</Callout>\n\nWith Playwright, you can write a test to check if the inputs are filled and match the story:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"component-playwright-test.md\" />\n\n{/* prettier-ignore-end */}\n\nOnce you execute Playwright, it opens a new browser window, loads Storybook's isolated iframe, asserts if the inputs contain the specified values, and displays the test results in the terminal.\n\n**More testing resources**\n\n* [Interaction testing](../interaction-testing.mdx) for user behavior simulation\n* [Accessibility testing](../accessibility-testing.mdx) for accessibility\n* [Visual testing](../visual-testing.mdx) for appearance\n* [Snapshot testing](../snapshot-testing.mdx) for rendering errors and warnings\n* [Test coverage](../test-coverage.mdx) for measuring code coverage\n* [CI](../in-ci.mdx) for running tests in your CI/CD pipeline\n* [Vitest addon](./vitest-addon/index.mdx) for running tests in Storybook\n* [Test runner](./test-runner.mdx) to automate test execution\n* [Unit testing](./stories-in-unit-tests.mdx) for functionality\n"
  },
  {
    "path": "docs/writing-tests/integrations/stories-in-unit-tests.mdx",
    "content": "---\ntitle: 'Stories in unit tests'\nsidebar:\n  title: Unit tests\n  order: 3\n---\n\nTeams test a variety of UI characteristics using different tools. Each tool requires you to replicate the same component state over and over. That’s a maintenance headache. Ideally, you’d set up your tests similarly and reuse that across tools.\n\nStorybook enables you to isolate a component and capture its use cases in a `*.stories.js|ts` file. Stories are standard JavaScript modules that are cross-compatible with the whole JavaScript ecosystem.\n\nStories are a practical starting point for UI testing. Import stories into tools like [Jest](https://jestjs.io/), [Testing Library](https://testing-library.com/), [Vitest](https://vitest.dev/) and [Playwright](https://playwright.dev/), to save time and maintenance work.\n\n## Write a test with Testing Library\n\n[Testing Library](https://testing-library.com/) is a suite of helper libraries for browser-based component tests. With [Component Story Format](../../api/csf/index.mdx), your stories are reusable with Testing Library. Each named export (story) is renderable within your testing setup. For example, if you were working on a login component and wanted to test the invalid credentials scenario, here's how you could write your test:\n\nStorybook provides a [`composeStories`](../../api/portable-stories/portable-stories-vitest.mdx#composestories) utility that helps convert stories from a test file into renderable elements that can be reused in your Node tests with JSDOM. It also allows you to apply other Storybook features that you have enabled your project (e.g., [decorators](../../writing-stories/decorators.mdx), [args](../../writing-stories/args.mdx)) into your tests, enabling you to reuse your stories in your testing environment of choice (e.g., [Jest](https://jestjs.io/), [Vitest](https://vitest.dev/)), ensuring your tests are always in sync with your stories without having to rewrite them. This is what we refer to as portable stories in Storybook.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"component-test-with-testing-library.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"warning\">\n  \n  You **must** [configure your test environment to use portable stories](../../api/portable-stories/portable-stories-vitest.mdx#1-apply-project-level-annotations) to ensure your stories are composed with all aspects of your Storybook configuration, such as [decorators](../../writing-stories/decorators.mdx).\n\n</Callout>\n\nOnce the test runs, it loads the story and renders it. [Testing Library](https://testing-library.com/) then emulates the user's behavior and checks if the component state has been updated.\n\n### Override story properties\n\nBy default, the `setProjectAnnotations` function injects into your existing tests any global configuration you've defined in your Storybook instance (i.e., parameters, decorators in the `preview.js|ts` file). Nevertheless, this may cause unforeseen side effects for tests that are not intended to use these global configurations. For example, you may want to always test a story in a particular locale (via `globalTypes`) or configure a story to apply specific `decorators` or `parameters`.\n\nTo avoid this, you can override the global configurations by extending either the `composeStory` or `composeStories` functions to provide test-specific configurations. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"override-compose-story-test.md\" />\n\n{/* prettier-ignore-end */}\n\n## Run tests on a single story\n\nYou can use the [`composeStory`](../../api/portable-stories/portable-stories-vitest.mdx#composestory) function to allow your tests to run on a single story. However, if you're relying on this method, we recommend that you supply the story metadata (i.e., the [default export](../../writing-stories/index.mdx#default-export)) to the `composeStory` function. This ensures that your tests can accurately determine the correct information about the story. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"single-story-test.md\" />\n\n{/* prettier-ignore-end */}\n\n## Combine stories into a single test\n\nIf you intend to test multiple stories in a single test, use the [`composeStories`](../../api/portable-stories/portable-stories-vitest.mdx#composestories) function. It will process every component story you've specified, including any [`args`](../../writing-stories/args.mdx) or [`decorators`](../../writing-stories/decorators.mdx) you've defined. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"multiple-stories-test.md\" />\n\n{/* prettier-ignore-end */}\n\n## Troubleshooting\n\n### Run tests in other frameworks\n\nStorybook provides community-led addons for other frameworks like [Vue 2](https://storybook.js.org/addons/@storybook/testing-vue) and [Angular](https://storybook.js.org/addons/@storybook/testing-angular). However, these addons still lack support for the latest stable Storybook release. If you're interested in helping out, we recommend reaching out to the maintainers using the default communication channels (GitHub and [Discord server](https://discord.com/channels/486522875931656193/839297503446695956)).\n\n<IfRenderer renderer=\"react\">\n  ### The args are not being passed to the test\n\n  The components returned by `composeStories` or `composeStory` not only can be rendered as React components but also come with the combined properties from the story, meta, and global configuration. This means that if you want to access args or parameters, for instance, you can do so:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"reuse-args-test.md\" />\n\n  {/* prettier-ignore-end */}\n\n  ### Next.js Vite cannot find the module\n\n  If you are seeing error messages like `Cannot find module 'sb-original/image-context'` ensure you have included `storybookNextJsPlugin`.\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"vite-includeStorybookNextjsPlugin.md\" />\n\n  {/* prettier-ignore-end */}\n</IfRenderer>\n\n<IfRenderer renderer=\"vue\">\n  ### The args are not being passed to the test\n\n  When using the `composeStories` or `composeStory` functions, the components being rendered will have a combination of properties from the story, meta, and global configuration. Therefore, if you need to access the args or parameters, you can do so as follows:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"reuse-args-test.md\" />\n\n  {/* prettier-ignore-end */}\n</IfRenderer>\n\n**More testing resources**\n\n* [Interaction testing](../interaction-testing.mdx) for user behavior simulation\n* [Accessibility testing](../accessibility-testing.mdx) for accessibility\n* [Visual testing](../visual-testing.mdx) for appearance\n* [Snapshot testing](../snapshot-testing.mdx) for rendering errors and warnings\n* [Test coverage](../test-coverage.mdx) for measuring code coverage\n* [CI](../in-ci.mdx) for running tests in your CI/CD pipeline\n* [Vitest addon](./vitest-addon/index.mdx) for running tests in Storybook\n* [Test runner](./test-runner.mdx) to automate test execution\n* [End-to-end testing](./stories-in-end-to-end-tests.mdx) for simulating real user scenarios\n"
  },
  {
    "path": "docs/writing-tests/integrations/test-runner.mdx",
    "content": "---\ntitle: 'Test runner'\nsidebar:\n  order: 2\n  title: Test runner (Webpack)\n---\n\n<If renderer={['react', 'vue', 'svelte']}>\n<Callout variant=\"warning\">\n\nThe test runner has been superseded by the [Vitest addon](./vitest-addon/index.mdx), which offers the same functionality, powered by the faster and more modern [Vitest](https://vitest.dev/) browser mode. It also enables the full Storybook Test experience, allowing you to run interaction, accessibility, and visual tests from your Storybook app.\n\nIf you are using a Vite-powered Storybook framework, we recommend using the Vitest addon instead of the test runner.\n\n</Callout>\n</If>\n\nStorybook test runner turns all of your stories into executable tests. It is powered by [Jest](https://jestjs.io/) and [Playwright](https://playwright.dev/).\n\n* For those [without a play function](../../writing-stories/index.mdx): it verifies whether the story renders without any errors.\n* For those [with a play function](../../writing-stories/play-function.mdx): it also checks for errors in the play function and that all assertions passed.\n\nThese tests run in a live browser and can be executed via the [command line](#cli-options) or your [CI server](#set-up-ci-to-run-tests).\n\n## Setup\n\nThe test-runner is a standalone, framework-agnostic utility that runs parallel to your Storybook. You will need to take some additional steps to set it up properly. Detailed below is our recommendation to configure and execute it.\n\nRun the following command to install it.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"test-runner-install.md\" />\n\n{/* prettier-ignore-end */}\n\nUpdate your `package.json` scripts and enable the test runner.\n\n```json title=\"package.json\"\n{\n  \"scripts\": {\n    \"test-storybook\": \"test-storybook\"\n  }\n}\n```\n\nStart your Storybook with:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-run-dev.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  Storybook's test runner requires either a locally running Storybook instance or a published Storybook to run all the existing tests.\n</Callout>\n\nFinally, open a new terminal window and run the test-runner with:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"test-runner-execute.md\" />\n\n{/* prettier-ignore-end */}\n\n## Configure\n\nTest runner offers zero-config support for Storybook. However, you can run `test-storybook --eject` for more fine-grained control. It generates a `test-runner-jest.config.js` file at the root of your project, which you can modify. Additionally, you can extend the generated configuration file and provide [testEnvironmentOptions](https://github.com/playwright-community/jest-playwright#configuration) as the test runner also uses [jest-playwright](https://github.com/playwright-community/jest-playwright) under the hood.\n\n### CLI Options\n\nThe test-runner is powered by [Jest](https://jestjs.io/) and accepts a subset of its [CLI options](https://jestjs.io/docs/cli) (for example, `--watch`, `--maxWorkers`).\nIf you're already using any of those flags in your project, you should be able to migrate them into Storybook's test-runner without any issues. Listed below are all the available flags and examples of using them.\n\n| Options                         | Description                                                                                                                                                                                             |\n| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `--help`                        | Output usage information <br />`test-storybook --help`                                                                                                                                                   |\n| `-s`, `--index-json`            | Run in index json mode. Automatically detected (requires a compatible Storybook) <br />`test-storybook --index-json`                                                                                     |\n| `--no-index-json`               | Disables index json mode <br />`test-storybook --no-index-json`                                                                                                                                          |\n| `-c`, `--config-dir [dir-name]` | Directory where to load Storybook configurations from <br />`test-storybook -c .storybook`                                                                                                               |\n| `--watch`                       | Run in watch mode <br />`test-storybook --watch`                                                                                                                                                         |\n| `--watchAll`                    | Watch files for changes and rerun all tests when something changes.<br />`test-storybook --watchAll`                                                                                                     |\n| `--coverage`                    | Runs [coverage tests](#generate-code-coverage) on your stories and components <br /> `test-storybook --coverage`                                                                                              |\n| `--coverageDirectory`           | Directory where to write coverage report output <br />`test-storybook --coverage --coverageDirectory coverage/ui/storybook`                                                                              |\n| `--url`                         | Define the URL to run tests in. Useful for custom Storybook URLs <br />`test-storybook --url http://the-storybook-url-here.com`                                                                          |\n| `--browsers`                    | Define browsers to run tests in. One or multiple of: chromium, firefox, webkit <br />`test-storybook --browsers firefox chromium`                                                                        |\n| `--maxWorkers [amount]`         | Specifies the maximum number of workers the worker-pool will spawn for running tests <br />`test-storybook --maxWorkers=2`                                                                               |\n| `--testTimeout [amount]`        | Defines the maximum time in milliseconds that a test can run before it is automatically marked as failed. Useful for long-running tests <br /> `test-storybook --testTimeout=60000`                      |\n| `--no-cache`                    | Disable the cache <br />`test-storybook --no-cache`                                                                                                                                                      |\n| `--clearCache`                  | Deletes the Jest cache directory and then exits without running tests <br />`test-storybook --clearCache`                                                                                                |\n| `--verbose`                     | Display individual test results with the test suite hierarchy <br />`test-storybook --verbose`                                                                                                           |\n| `-u`, `--updateSnapshot`        | Use this flag to re-record every snapshot that fails during this test run <br />`test-storybook -u`                                                                                                      |\n| `--eject`                       | Creates a local configuration file to override defaults of the test-runner <br />`test-storybook --eject`                                                                                                |\n| `--json`                        | Prints the test results in JSON. This mode will send all other test output and user messages to stderr. <br />`test-storybook --json`                                                                    |\n| `--outputFile`                  | Write test results to a file when the --json option is also specified. <br />`test-storybook --json --outputFile results.json`                                                                           |\n| `--junit`                       | Indicates that test information should be reported in a junit file. <br />`test-storybook --**junit**`                                                                                                   |\n| `--ci`                          | Instead of the regular behavior of storing a new snapshot automatically, it will fail the test and require Jest to be run with `--updateSnapshot`. <br />`test-storybook --ci`                           |\n| `--shard [index/count]`         | Requires CI. Splits the test suite execution into multiple machines <br /> `test-storybook --shard=1/8`                                                                                                  |\n| `--failOnConsole`               | Makes tests fail on browser console errors<br />`test-storybook --failOnConsole`                                                                                                                         |\n| `--includeTags`                 | Experimental feature <br />Defines a subset of stories to be tested if they match the enabled [tags](#experimental-filter-tests). <br />`test-storybook --includeTags=\"test-only, pages\"`                 |\n| `--excludeTags`                 | Experimental feature <br />Prevents stories from being tested if they match the provided [tags](#experimental-filter-tests). <br />`test-storybook --excludeTags=\"no-tests, tokens\"`                      |\n| `--skipTags`                    | Experimental feature <br />Configures the test runner to skip running tests for stories that match the provided [tags](#experimental-filter-tests). <br />`test-storybook --skipTags=\"skip-test, layout\"` |\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"test-runner-execute-with-flags.md\" />\n\n{/* prettier-ignore-end */}\n\n### Run tests against a deployed Storybook\n\nBy default, the test-runner assumes that you're running it against a locally served Storybook on port `6006`. If you want to define a target URL to run against deployed Storybooks, you can use the `--url` flag:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"test-runner-execute-with-url.md\" />\n\n{/* prettier-ignore-end */}\n\nAlternatively, you can set the `TARGET_URL` environment variable and run the test-runner:\n\n```sh\nTARGET_URL=https://the-storybook-url-here.com yarn test-storybook\n```\n\n## Run accessibility tests\n\nWhen you have the [Accessibility addon](https://storybook.js.org/addons/@storybook/addon-a11y) installed, you can run accessibility tests alongside your interaction tests, using the test-runner.\n\nFor more details, including configuration options, see the [Accessibility testing documentation](../accessibility-testing.mdx).\n\n## Run snapshot tests\n\n[Snapshot testing](../snapshot-testing.mdx) is a helpful tool for verifying that edge cases like errors are handled correctly. It can also be used to verify that the rendered output of a component is consistent across different test runs.\n\n### Set up\n\nTo enable snapshot testing with the test-runner, you'll need to take additional steps to set it up properly.\n\nAdd a new [configuration file](#test-hook-api) inside your Storybook directory with the following inside:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"test-runner-dom-snapshot-testing.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  The `postVisit` hook allows you to extend the test runner's default configuration. Read more about them [here](#test-hook-api).\n</Callout>\n\nWhen you execute the test-runner (for example, with `yarn test-storybook`), it will run through all of your stories and run the snapshot tests, generating a snapshot file for each story in your project located in the `__snapshots__` directory.\n\n### Configure\n\nOut of the box, the test-runner provides an inbuilt snapshot testing configuration covering most use cases. You can also fine-tune the configuration to fit your needs via `test-storybook --eject` or by creating a `test-runner-jest.config.js` file at the root of your project.\n\n#### Override the default snapshot directory\n\nThe test-runner uses a specific naming convention and path for the generated snapshot files by default. If you need to customize the snapshot directory, you can define a custom snapshot resolver to specify the directory where the snapshots are stored.\n\nCreate a `snapshot-resolver.js` file to implement a custom snapshot resolver:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"test-runner-snapshot-resolver-custom-directory.md\" />\n\n{/* prettier-ignore-end */}\n\nUpdate the `test-runner-jest.config.js` file and enable the `snapshotResolver` option to use the custom snapshot resolver:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"test-runner-config-snapshot-resolver.md\" />\n\n{/* prettier-ignore-end */}\n\nWhen the test-runner is executed, it will cycle through all of your stories and run the snapshot tests, generating a snapshot file for each story in your project located in the custom directory you specified.\n\n#### Customize snapshot serialization\n\nBy default, the test-runner uses [`jest-serializer-html`](https://github.com/algolia/jest-serializer-html) to serialize HTML snapshots. This may cause issues if you use specific CSS-in-JS libraries like [Emotion](https://emotion.sh/docs/introduction), Angular's `ng` attributes, or similar libraries that generate hash-based identifiers for CSS classes. If you need to customize the serialization of your snapshots, you can define a custom snapshot serializer to specify how the snapshots are serialized.\n\nCreate a `snapshot-serializer.js` file to implement a custom snapshot serializer:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"test-runner-custom-snapshot-serializer.md\" />\n\n{/* prettier-ignore-end */}\n\nUpdate the `test-runner-jest.config.js` file and enable the `snapshotSerializers` option to use the custom snapshot resolver:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"test-runner-config-serializer.md\" />\n\n{/* prettier-ignore-end */}\n\nWhen the test-runner executes your tests, it will introspect the resulting HTML, replacing the dynamically generated attributes with the static ones provided by the regular expression in the custom serializer file before snapshotting the component. This ensures that the snapshots are consistent across different test runs.\n\n## Generate code coverage\n\nStorybook also provides a [coverage addon](https://storybook.js.org/addons/@storybook/addon-coverage). It is powered by [Istanbul](https://istanbul.js.org/), which allows out-of-the-box code instrumentation for the most commonly used frameworks and builders in the JavaScript ecosystem.\n\n### Set up\n\nEngineered to work alongside modern testing tools (e.g., [Playwright](https://playwright.dev/)), the coverage addon automatically instruments your code and generates code coverage data. For an optimal experience, we recommend using the test-runner alongside the coverage addon to run your tests.\n\nRun the following command to install the addon.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-coverage-addon-install.md\" />\n\n<Callout variant=\"info\">\n\nThe CLI's [`add`](../../api/cli-options.mdx#add) command automates the addon's installation and setup. To install it manually, see our [documentation](../../addons/install-addons.mdx#manual-installation) on how to install addons.\n\n</Callout>\n\nStart your Storybook with:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-run-dev.md\" />\n\n{/* prettier-ignore-end */}\n\nFinally, open a new terminal window and run the test-runner with:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"test-runner-coverage.md\" />\n\n{/* prettier-ignore-end */}\n\n![Coverage test output](../../_assets/writing-tests/integrations/test-runner-coverage-result.png)\n\n### Configure\n\nBy default, the [`@storybook/addon-coverage`](https://storybook.js.org/addons/@storybook/addon-coverage) offers zero-config support for Storybook and instruments your code via [`istanbul-lib-instrument`](https://www.npmjs.com/package/istanbul-lib-instrument) for [Webpack](https://webpack.js.org/), or [`vite-plugin-istanbul`](https://github.com/iFaxity/vite-plugin-istanbul) for [Vite](https://vitejs.dev/). However, you can extend your Storybook configuration file (i.e., `.storybook/main.js|ts`) and provide additional options to the addon. Listed below are the available options divided by builder and examples of how to use them.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-coverage-addon-config-options.md\" />\n\n{/* prettier-ignore-end */}\n\n<details>\n<summary>Vite options</summary>\n\n| Options           | Description                                                                                                                                                                                                                                        | Type                        |\n| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- |\n| `checkProd`            | Configures the plugin to skip instrumentation in production environments<br />`options: { istanbul: { checkProd: true,}}`                                                                                                                           | `boolean`                   |\n| `cwd`                  | Configures the working directory for the coverage tests.<br />Defaults to `process.cwd()`<br />`options: { istanbul: { cwd: process.cwd(),}}`                                                                                                        | `string`                    |\n| `cypress`              | Replaces the `VITE_COVERAGE` environment variable with `CYPRESS_COVERAGE`.<br />Requires Cypress's [code coverage](https://docs.cypress.io/guides/tooling/code-coverage)<br />`options: { istanbul: { cypress: true,}}`                              | `boolean`                   |\n| `exclude`              | Overrides the [default exclude list](https://github.com/storybookjs/addon-coverage/blob/main/src/constants.ts) with the provided list of files or directories to exclude from coverage<br />`options: { istanbul: { exclude: ['**/stories/**'],}}`  | `Array<String>` or `string` |\n| `extension`            | Extends the [default extension list](https://github.com/storybookjs/addon-coverage/blob/main/src/constants.ts) with the provided list of file extensions to include in coverage<br />`options: { istanbul: { extension: ['.js', '.cjs', '.mjs'],}}` | `Array<String>` or `string` |\n| `forceBuildInstrument` | Configures the plugin to add instrumentation in build mode <br />`options: { istanbul: { forceBuildInstrument: true,}}`                                                                                                                             | `boolean`                   |\n| `include`              | Select the files to collect coverage<br />`options: { istanbul: { include: ['**/stories/**'],}}`                                                                                                                                                    | `Array<String>` or `string` |\n| `nycrcPath`            | Defines the relative path for the existing nyc [configuration file](https://github.com/istanbuljs/nyc?tab=readme-ov-file#configuration-files)<br />`options: { istanbul: { nycrcPath: '../nyc.config.js',}}`                                        | `string`                    |\n| `requireEnv`           | Overrides the `VITE_COVERAGE` environment variable's value by granting access to the `env` variables<br />`options: { istanbul: { requireEnv: true,}}`                                                                                              | `boolean`                   |\n\n</details>\n\n<details>\n<summary>Webpack 5 options</summary>\n\n| Options      | Description                                                                                                                                                                                                                                        | Type                        |\n| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- |\n| `autoWrap`             | Provides support for top-level return statements by wrapping the program code in a function<br />`options: { istanbul: { autoWrap: true,}}`                                                                                                         | `boolean`                   |\n| `compact`              | Condenses the output of the instrumented code. Useful for debugging<br />`options: { istanbul: { compact: false,}}`                                                                                                                                 | `boolean`                   |\n| `coverageVariable`     | Defines the global variable name that Istanbul will use to store coverage results<br />`options: { istanbul: { coverageVariable: '__coverage__',}}`                                                                                                 | `string`                    |\n| `cwd`                  | Configures the working directory for the coverage tests.<br />Defaults to `process.cwd()`<br />`options: { istanbul: { cwd: process.cwd(),}}`                                                                                                        | `string`                    |\n| `debug`                | Enables the debug mode for additional logging information during the instrumentation process<br />`options: { istanbul: { debug: true,}}`                                                                                                           | `boolean`                   |\n| `esModules`            | Enables support for ES Module syntax<br />`options: { istanbul: { esModules: true,}}`                                                                                                                                                               | `boolean`                   |\n| `exclude`              | Overrides the [default exclude list](https://github.com/storybookjs/addon-coverage/blob/main/src/constants.ts) with the provided list of files or directories to exclude from coverage<br />`options: { istanbul: { exclude: ['**/stories/**'],}}`  | `Array<String>` or `string` |\n| `extension`            | Extends the [default extension list](https://github.com/storybookjs/addon-coverage/blob/main/src/constants.ts) with the provided list of file extensions to include in coverage<br />`options: { istanbul: { extension: ['.js', '.cjs', '.mjs'],}}` | `Array<String>` or `string` |\n| `include`              | Select the files to collect coverage<br />`options: { istanbul: { include: ['**/stories/**'],}}`                                                                                                                                                    | `Array<String>` or `string` |\n| `nycrcPath`            | Defines the relative path for the existing nyc [configuration file](https://github.com/istanbuljs/nyc?tab=readme-ov-file#configuration-files)<br />`options: { istanbul: { nycrcPath: '../nyc.config.js',}}`                                        | `string`                    |\n| `preserveComments`     | Includes comments in the instrumented code<br />`options: { istanbul: { preserveComments: true,}}`                                                                                                                                                  | `boolean`                   |\n| `produceSourceMap`     | Configures Instanbul to generate a source map for the instrumented code<br />`options: { istanbul: { produceSourceMap: true,}}`                                                                                                                     | `boolean`                   |\n| `sourceMapUrlCallback` | Defines a callback function invoked with the filename and the source map URL when a source map is generated<br />`options: { istanbul: { sourceMapUrlCallback: (filename, url) => {},}}`                                                            | `function`                  |\n\n</details>\n\n### What about other coverage reporting tools?\n\nOut of the box, code coverage tests work seamlessly with Storybook's test-runner and the [`@storybook/addon-coverage`](https://storybook.js.org/addons/@storybook/addon-coverage). However, that doesn't mean you can't use additional reporting tools (e.g., [Codecov](https://about.codecov.io/)). For instance, if you're working with [LCOV](https://wiki.documentfoundation.org/Development/Lcov), you can use the generated output (in `coverage/storybook/coverage-storybook.json`) and create your own report with:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-coverage-report-lcov.md\" />\n\n{/* prettier-ignore-end */}\n\n## Set up CI to run tests\n\nYou can also configure the test-runner to run tests on a CI environment. Documented below are some recipes to help you get started.\n\n### Run against deployed Storybooks via Github Actions deployment\n\nIf you're publishing your Storybook with services such as [Vercel](https://vercel.com/) or [Netlify](https://docs.netlify.com/site-deploys/notifications/#github-commit-statuses), they emit a `deployment_status` event in GitHub Actions. You can use it and set the `deployment_status.target_url` as the `TARGET_URL` environment variable. Here's how:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"test-runner-with-deploy-event-workflow.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  The published Storybook must be publicly available for this example to work. We recommend running the test server using the recipe [below](#run-against-non-deployed-storybooks) if it requires authentication.\n</Callout>\n\n### Run against non-deployed Storybooks\n\nYou can use your CI provider (for example, [GitHub Actions](https://github.com/features/actions), [GitLab Pipelines](https://docs.gitlab.com/ee/ci/pipelines/), [CircleCI](https://circleci.com/)) to build and run the test runner against your built Storybook. Here's a recipe that relies on third-party libraries, that is to say, [concurrently](https://www.npmjs.com/package/concurrently), [http-server](https://www.npmjs.com/package/http-server), and [wait-on](https://www.npmjs.com/package/wait-on) to build Storybook and run tests with the test-runner.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"test-runner-local-build-workflow.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  By default, Storybook outputs the [build](../../sharing/publish-storybook.mdx#build-storybook-as-a-static-web-application) to the `storybook-static` directory. If you're using a different build directory, you'll need to adjust the recipe accordingly.\n</Callout>\n\n## Advanced configuration\n\n### Test hook API\n\nThe test-runner renders a story and executes its [play function](../../writing-stories/play-function.mdx) if one exists. However, certain behaviors are impossible to achieve via the play function, which executes in the browser. For example, if you want the test-runner to take visual snapshots for you, this is possible via Playwright/Jest but must be executed in Node.\n\nThe test-runner exports test hooks that can be overridden globally to enable use cases like visual or DOM snapshots. These hooks give you access to the test lifecycle *before* and *after* the story is rendered.\nListed below are the available hooks and an overview of how to use them.\n\n| Hook        | Description                                                                                                     |\n| ----------- | --------------------------------------------------------------------------------------------------------------- |\n| `prepare`   | Prepares the browser for tests<br />`async prepare({ page, browserContext, testRunnerConfig }) {}`               |\n| `setup`     | Executes once before all the tests run<br />`setup() {}`                                                         |\n| `preVisit`  | Executes before a story is initially visited and rendered in the browser<br />`async preVisit(page, context) {}` |\n| `postVisit` | Executes after the story is visited and fully rendered<br />`async postVisit(page, context) {}`                  |\n\n<Callout variant=\"info\" icon=\"💡\">\n  These test hooks are experimental and may be subject to breaking changes. We encourage you to test as much as possible within the story's [play function](../../writing-stories/play-function.mdx).\n</Callout>\n\nTo enable the hooks API, you'll need to add a new configuration file inside your Storybook directory and set them up as follows:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"test-runner-hooks-example.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  Except for the `setup` function, all other functions run asynchronously. Both `preVisit` and `postVisit` functions include two additional arguments, a [Playwright page](https://playwright.dev/docs/pages) and a context object which contains the `id`, `title`, and the `name` of the story.\n</Callout>\n\nWhen the test-runner executes, your existing tests will go through the following lifecycle:\n\n* The `setup` function is executed before all the tests run.\n* The context object is generated containing the required information.\n* Playwright navigates to the story's page.\n* The `preVisit` function is executed.\n* The story is rendered, and any existing `play` functions are executed.\n* The `postVisit` function is executed.\n\n### (Experimental) Filter tests\n\nWhen you run the test-runner on Storybook, it tests every story by default. However, if you want to filter the tests, you can use the `tags` configuration option. Storybook originally introduced this feature to generate [automatic documentation](../../writing-docs/autodocs.mdx) for stories. But it can be further extended to configure the test-runner to run tests according to the provided tags using a similar configuration option or via CLI flags (e.g., `--includeTags`, `--excludeTags`, `--skipTags`), only available with the latest stable release (`0.15` or higher). Listed below are the available options and an overview of how to use them.\n\n| Option    | Description                                                                   |\n| --------- | ----------------------------------------------------------------------------- |\n| `exclude` | Prevents stories if they match the provided tags from being tested.           |\n| `include` | Defines a subset of stories only to be tested if they match the enabled tags. |\n| `skip`    | Skips testing on stories if they match the provided tags.                     |\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"test-runner-tags-config.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"ℹ️\">\n  Running tests with the CLI flags takes precedence over the options provided in the configuration file and will override the available options in the configuration file.\n</Callout>\n\n#### Disabling tests\n\nIf you want to prevent specific stories from being tested by the test-runner, you can configure your story with a custom tag, enable it to the test-runner configuration file or run the test-runner with the `--excludeTags` [CLI](#cli-options) flag and exclude them from testing. This is helpful when you want to exclude stories that are not yet ready for testing or are irrelevant to your tests. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"my-component-exclude-tags.md\" />\n\n{/* prettier-ignore-end */}\n\n#### Run tests for a subset of stories\n\nTo allow the test-runner only to run tests on a specific story or subset of stories, you can configure the story with a custom tag, enable it in the test-runner configuration file or run the test-runner with the `--includeTags` [CLI](#cli-options) flag and include them in your tests. For example, if you wanted to run tests based on the `test-only` tag, you can adjust your configuration as follows:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"my-component-include-tags.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"ℹ️\">\n  Applying tags for the component's stories should either be done at the component level (using `meta`) or at the story level. Importing tags across stories is not supported in Storybook and won't work as intended.\n</Callout>\n\n#### Skip tests\n\nIf you want to skip running tests on a particular story or subset of stories, you can configure your story with a custom tag, enable it in the test-runner configuration file, or run the test-runner with the `--skipTags` [CLI](#cli-options) flag. Running tests with this option will cause the test-runner to ignore and flag them accordingly in the test results, indicating that the tests are temporarily disabled. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"my-component-skip-tags.md\" />\n\n{/* prettier-ignore-end */}\n\n### Authentication for deployed Storybooks\n\nIf you use a secure hosting provider that requires authentication to host your Storybook, you may need to set HTTP headers. This is mainly because of how the test runner checks the status of the instance and the index of its stories through fetch requests and Playwright. To do this, you can modify the test-runner configuration file to include the `getHttpHeaders` function. This function takes the URL of the fetch calls and page visits as input and returns an object containing the headers that need to be set.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"test-runner-auth.md\" />\n\n{/* prettier-ignore-end */}\n\n### Helpers\n\nThe test-runner exports a few helpers that can be used to make your tests more readable and maintainable by accessing Storybook's internals (e.g., `args`, `parameters`). Listed below are the available helpers and an overview of how to use them.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"test-runner-helper-function.md\" />\n\n{/* prettier-ignore-end */}\n\n#### Accessing story information with the test-runner\n\nIf you need to access information about the story, such as its parameters, the test-runner includes a helper function named `getStoryContext` that you can use to retrieve it. You can then use it to customize your tests further as needed. For example, if you need to configure Playwright's page [viewport size](https://playwright.dev/docs/api/class-page#page-set-viewport-size) to use the viewport size defined in the story's parameters, you can do so as follows:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"test-runner-custom-page-viewport.md\" />\n\n{/* prettier-ignore-end */}\n\n#### Working with assets\n\nIf you're running a specific set of tests (e.g., image snapshot testing), the test-runner provides a helper function named `waitForPageReady` that you can use to ensure the page is fully loaded and ready before running the test. For example:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"test-runner-waitpageready.md\" />\n\n{/* prettier-ignore-end */}\n\n### Index.json mode\n\nThe test-runner transforms your story files into tests when testing a local Storybook. For a remote Storybook, it uses the Storybook's [index.json](../../configure/index.mdx#feature-flags) (formerly `stories.json`) file (a static index of all the stories) to run the tests.\n\n#### Why?\n\nSuppose you run into a situation where the local and remote Storybooks appear out of sync, or you might not even have access to the code. In that case, the `index.json` file is guaranteed to be the most accurate representation of the deployed Storybook you are testing. To test a local Storybook using this feature, use the `--index-json` flag as follows:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"test-runner-with-index-json.md\" />\n\n{/* prettier-ignore-end */}\n\n<Callout variant=\"info\" icon=\"💡\">\n  The `index.json` mode is not compatible with the watch mode.\n</Callout>\n\nIf you need to disable it, use the `--no-index-json` flag:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"test-runner-no-index-json.md\" />\n\n{/* prettier-ignore-end */}\n\n#### How do I check if my Storybook has a `index.json` file?\n\nIndex.json mode requires a `index.json` file. Open a browser window and navigate to your deployed Storybook instance (for example, `https://your-storybook-url-here.com/index.json`). You should see a JSON file that starts with a `\"v\": 3` key, immediately followed by another key called \"stories\", which contains a map of story IDs to JSON objects. If that is the case, your Storybook supports [index.json mode](../../configure/index.mdx#feature-flags).\n\n## What's the difference between Chromatic and Test runner?\n\nThe test-runner is a generic testing tool that can run locally or on CI and be configured or extended to run all kinds of tests.\n\n[Chromatic](https://www.chromatic.com/?utm_source=storybook_website\\&utm_medium=link\\&utm_campaign=storybook) is a cloud-based service that runs [visual](../visual-testing.mdx) and [interaction tests](../interaction-testing.mdx) (and soon [accessibility tests](../accessibility-testing.mdx)) without setting up the test runner. It also syncs with your git provider and manages access control for private projects.\n\nHowever, you might want to pair the test runner and Chromatic in some cases.\n\n* Use it locally and Chromatic on your CI.\n* Use Chromatic for visual and component tests and run other custom tests using the test runner.\n\n## Troubleshooting\n\n### The test runner seems flaky and keeps timing out\n\nIf your tests time out with the following message:\n\n```shell\nTimeout - Async callback was not invoked within the 15000 ms timeout specified by jest.setTimeout\n```\n\nIt might be that Playwright couldn't handle testing the number of stories you have in your project. Perhaps you have a large number of stories, or your CI environment has a really low RAM configuration. In such cases, you should limit the number of workers that run in parallel by adjusting your command as follows:\n\n```json title=\"package.json\"\n{\n  \"scripts\": {\n    \"test-storybook:ci\": \"yarn test-storybook --maxWorkers=2\"\n  }\n}\n```\n\n### The error output in the CLI is too short\n\nBy default, the test runner truncates error outputs at 1000 characters, and you can check the full output directly in Storybook in the browser. However, if you want to change that limit, you can do so by setting the `DEBUG_PRINT_LIMIT` environment variable to a number of your choosing, for example, `DEBUG_PRINT_LIMIT=5000 yarn test-storybook`.\n\n### Run the test runner in other CI environments\n\nAs the test runner is based on Playwright, you might need to use specific docker images or other configurations depending on your CI setup. In that case, you can refer to the [Playwright CI docs](https://playwright.dev/docs/ci) for more information.\n\n### Tests filtered by tags are incorrectly executed\n\nIf you've enabled filtering tests with tags and provided similar tags to the `include` and `exclude` lists, the test-runner will execute the tests based on the `exclude` list and ignore the `include` list. To avoid this, make sure the tags provided to the `include` and `exclude` lists differ.\n\n### The test runner doesn't support Yarn PnP out of the box\n\nIf you've enabled the test-runner in a project running on a newer version of Yarn with Plug'n'Play (PnP) enabled, the test-runner might not work as expected and may generate the following error when running tests:\n\n```shell\nPlaywrightError: jest-playwright-preset: Cannot find playwright package to use chromium\n```\n\nThis is due to the test-runner using the community-maintained package [jest-playwright-preset](https://github.com/playwright-community/jest-playwright) that still needs to support this feature. To solve this, you can either switch the [`nodeLinker`](https://yarnpkg.com/features/linkers) setting to `node-modules` or install Playwright as a direct dependency in your project, followed by adding the browser binaries via the [`install`](https://playwright.dev/docs/browsers#install-browsers) command.\n\n### Run test coverage in other frameworks\n\nIf you intend on running coverage tests in frameworks with special files like Vue 3 or Svelte, you'll need to adjust your configuration and enable the required file extensions. For example, if you're using Vue, you'll need to add the following to your nyc configuration file (i.e., `.nycrc.json` or `nyc.config.js`):\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-coverage-report-vue.md\" />\n\n{/* prettier-ignore-end */}\n\n### The coverage addon doesn't support optimized builds\n\nIf you generated a production build optimized for performance with the [`--test`](../../sharing/publish-storybook.mdx#customizing-the-build-for-performance) flag, and you're using the coverage addon to run tests against your Storybook, you may run into a situation where the coverage addon doesn't instrument your code. This is due to how the flag works, as it removes addons that have an impact on performance (e.g., [`Docs`](../../writing-docs/index.mdx), [coverage addon](https://storybook.js.org/addons/@storybook/addon-coverage)). To resolve this issue, you'll need to adjust your Storybook configuration file (i.e., `.storybook/main.js|ts`) and include the [`disabledAddons`](../../api/main-config/main-config-build.mdx#testdisabledaddons) option to allow the addon to run tests at the expense of a slower build.\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"storybook-coverage-addon-optimized-config.md\" />\n\n{/* prettier-ignore-end */}\n\n### The coverage addon doesn't support instrumented code\n\nAs the [coverage addon](https://storybook.js.org/addons/@storybook/addon-coverage) is based on Webpack5 loaders and Vite plugins for code instrumentation, frameworks that don't rely upon these libraries (e.g., Angular configured with Webpack), will require additional configuration to enable code instrumentation. In that case, you can refer to the following [repository](https://github.com/yannbf/storybook-coverage-recipes) for more information.\n\n**More testing resources**\n\n* [Interaction testing](../interaction-testing.mdx) for user behavior simulation\n* [Accessibility testing](../accessibility-testing.mdx) for accessibility\n* [Visual testing](../visual-testing.mdx) for appearance\n* [Snapshot testing](../snapshot-testing.mdx) for rendering errors and warnings\n* [Test coverage](../test-coverage.mdx) for measuring code coverage\n* [CI](../in-ci.mdx) for running tests in your CI/CD pipeline\n* [Vitest addon](./vitest-addon/index.mdx) for running tests in Storybook\n* [End-to-end testing](./stories-in-end-to-end-tests.mdx) for simulating real user scenarios\n* [Unit testing](./stories-in-unit-tests.mdx) for functionality\n"
  },
  {
    "path": "docs/writing-tests/integrations/vitest-addon/index.mdx",
    "content": "---\ntitle: 'Vitest addon'\nsidebar:\n  order: 1\n  title: Vitest addon\nisTab: true\ntab:\n  order: 1\n  title: Guide\n---\n\n<If notRenderer={['react', 'preact', 'vue', 'svelte', 'web-components']}>\n  \n<Callout variant=\"info\">\n\nThe Vitest addon is supported and recommended for [React](?renderer=react), [Preact](?renderer=preact), [Vue](?renderer=vue), [Svelte](?renderer=svelte), and [Web Components](?renderer=web-components) projects, which use the [Vite builder](../../../builders/vite.mdx) (or the [Next.js framework with Vite](../../../get-started/frameworks/nextjs-vite.mdx)).\n\nIf you are using a different renderer (such as Angular) or the Webpack builder, you can use the [Storybook test runner](../test-runner.mdx) to test your stories.\n\n</Callout>\n\n</If>\n{/* End non-supported renderers */}\n\n<If renderer={['react', 'preact', 'vue', 'svelte', 'web-components']}>\n\nStorybook's Vitest addon allows you to test your components directly inside Storybook. On its own, it transforms your [stories](../../../writing-stories/index.mdx) into component tests, which test the rendering and behavior of your components in a real browser environment. It can also calculate project [coverage](../../test-coverage.mdx) provided by your stories.\n\nIf your project is using other testing addons, such as the [Visual tests addon](../../visual-testing.mdx) or the [Accessibility addon](../../accessibility-testing.mdx), you can run those tests alongside your component tests.\n\nWhen component tests are run for a story, the status is shown in the sidebar. The sidebar can be filtered to only show failing stories, and you can press the menu button on a failing story to see debugging options.\n\nYou can also run tests in watch mode, which will automatically re-run tests when you make changes to your components or stories. To activate, press the watch mode toggle (the eye icon) in the testing widget.\n\n<Video src=\"../../../_assets/writing-tests/addon-vitest-overview.mp4\" />\n\n## Install and set up\n\nBefore installing, make sure your project meets the following requirements:\n\n- A Storybook framework that uses Vite (e.g. [`vue3-vite`](../../../get-started/frameworks/vue3-vite.mdx), [`react-vite`](../../../get-started/frameworks/react-vite.mdx), [`preact-vite`](../../../get-started/frameworks/preact-vite.mdx), [`nextjs-vite`](../../../get-started/frameworks/nextjs-vite.mdx), [`sveltekit`](../../../get-started/frameworks/sveltekit.mdx), etc.)\n- Vitest ≥ 3.0\n    - If you're not yet using Vitest, it will be installed and configured for you automatically\n- (optional) MSW ≥ 2.0\n    - If MSW is installed, it must be v2.0.0 or later to not conflict with Vitest's dependency\n\n<If renderer=\"react\">\n  <Callout variant=\"info\" icon=\"ℹ️\">\n    **Using with Next.js** — The Vitest addon is supported in Next.js ≥ 14.1 projects, but you must be using the [`@storybook/nextjs-vite` framework](../../../get-started/frameworks/nextjs-vite.mdx). When you run the setup command below, you will be prompted to install and use the framework if you haven't already.\n  </Callout>\n</If>\n\n### Automatic setup\n\nRun the following command to install and configure the addon automatically:\n\n<CodeSnippets path=\"addon-test-install.md\" />\n\nThe [`add` command](../../../addons/install-addons.mdx#automatic-installation) will:\n\n* Install and register the Vitest addon\n* Inspect your project's Vite and Vitest setup\n* Install and configure Vitest with sensible defaults if necessary\n* Set up browser mode using Playwright's Chromium browser\n* **Prompt you to install Playwright browser binaries** if needed\n\nThe setup is fully automated and handles all configuration for you. The full configuration options can be found in the [API section](#options), below.\n\n<Callout variant=\"info\">\n\nIf you're prompted to install Playwright browser binaries during setup, select \"Yes\" to install them. These are required for running tests in browser mode, which is the recommended setup for component testing.\n\nYou can install the Playwright browser binaries at any time by running [`playwright install`](https://playwright.dev/docs/browsers#install-browsers).\n\n</Callout>\n\n### Manual setup (advanced)\n\n<details>\n<summary>Manual setup instructions (only needed if automatic setup fails)</summary>\n\nFor some project setups, the `add` command may be unable to automate the addon and plugin setup and ask you to complete additional setup steps. Here's what to do:\n\n1. Make sure Vite and Vitest are configured in your project.\n1. Configure Vitest to use [browser mode](https://vitest.dev/guide/browser/).\n1. Install the addon, `@storybook/addon-vitest`, in your project and [register it in your Storybook configuration](../../../addons/install-addons.mdx#manual-installation).\n1. Adjust your Vitest configuration to include the plugin. You can use the [example configuration files](#example-configuration-files) as a guide.\n   - For projects with existing Vitest tests, we recommend using a separate [test project](https://vitest.dev/guide/projects) if you're using Vitest ≥ 4.0 and a [workspace file](https://v3.vitest.dev/config/#workspace) if you're using Vitest 3.x to define separate configurations for your Storybook tests and other tests. You can run them in isolation or together, depending on your needs.\n\n</details>\n\n### Example configuration files\n\nWhen the addon is set up automatically, it will create or adjust your Vitest configuration files for you. If you're setting up manually, you can use the following examples as a reference when configuring your project.\n\n<details id=\"example-vitest-config\">\n  <summary>Example Vitest config file</summary>\n\n  The most simple application of the plugin is to include it in your Vitest configuration file:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"vitest-plugin-vitest-config.md\" />\n\n  {/* prettier-ignore-end */}\n\n</details>\n\n<details id=\"example-vitest-workspace\">\n  <summary>Example Vitest workspace file (Vitest < 3.2)</summary>\n\n  If you're using a [Vitest workspace](https://v3.vitest.dev/config/#workspace), you can define a new workspace project:\n\n  {/* prettier-ignore-start */}\n\n  <CodeSnippets path=\"vitest-plugin-vitest-workspace.md\" />\n\n  {/* prettier-ignore-end */}\n\n</details>\n\n## Usage\n\nThere are multiple ways to run tests using the addon.\n\nWe recommend (and configure, by default) running Vitest in [browser mode](https://vitest.dev/guide/browser/), using [Playwright's](https://playwright.dev) Chromium browser. Browser mode ensures your components are tested in a real browser environment, which is more accurate than simulations like JSDom or HappyDom. This is especially important for testing components that rely on browser APIs or features.\n\n### Storybook UI\n\nThe easiest way to run tests is through the Storybook UI. With a click, you can run multiple types of tests for all stories in your project, a group of stories, or a single story.\n\nTo run all tests for your whole project, press the Run tests button in the testing widget at the bottom of the sidebar.\n\n![Screenshot of testing widget, expanded, with the Run tests button highlighted](../../../_assets/writing-tests/test-widget-run-all.png)\n\nAlternatively, you can expand the testing widget to run specific types of tests individually. The sub-types listed under component tests will all run together, including when watch mode (which will automatically re-run relevant tests upon code changes) is enabled (with the eye icon).\n\n![Screenshot of testing widget, expanded, showing test types and watch mode toggle](../../../_assets/writing-tests/test-widget-expanded.png)\n\n<Callout variant=\"info\" icon=\"ℹ️\">\n\nIf you have the [Visual tests addon](../../visual-testing.mdx) installed, you'll see an option to run Visual tests alongside Component tests.\n\n![Screenshot of testing widget, expanded, showing Visual tests](../../../_assets/writing-tests/test-widget-expanded-with-vta.png)\n\nOther addons, such as [a11y](../../accessibility-testing.mdx#run-accessibility-tests), may also provide test types that can be run from the testing widget and affect the status indicators on stories and components.\n\n</Callout>\n\nTo run tests for a specific story or group of stories, press the menu button (three dots) that appears on hover of a sidebar item. You can then select the test type you want to run.\n\n![Screenshot of story sidebar item with open menu](../../../_assets/writing-tests/context-menu.png)\n\nAfter running your tests, you will now see status indicators on stories and components for their pass, fail, or error state. You can press on the menu button when hovering a story to see the test results for that story. Selecting a result in the menu will navigate you to that story and open the appropriate debugging panel. For example, if an interaction test fails, you can jump straight to the failure in the Interactions panel. That panel provides an interactive debugger for your test, allowing you to step through each simulated behavior or assertion.\n\nThe testing widget will also show you the total number of tests run, the number of tests that passed, and the number of tests that failed or errored. You can press the failure number to filter the sidebar to only those stories that failed.\n\n<Video src=\"../../../_assets/writing-tests/addon-vitest-filter-failures.mp4\" />\n\n### CLI\n\nYou can also run tests using the Vitest CLI. We recommend adding a script to your `package.json` to make running tests easier. Here's an example of how to do that:\n\n```json title=\"package.json\"\n{\n  \"scripts\": {\n    \"test\": \"vitest\",\n    \"test-storybook\": \"vitest --project=storybook\"\n  }\n}\n```\n\nIn this example, we've added two scripts: `test` to run all tests in your project (you may already have this), and `test-storybook` to run only your Storybook tests. The `--project=storybook` flag tells Vitest to run the tests for the Storybook project.\n\nThen, run this command to run your tests (in [watch mode](https://vitest.dev/guide/cli.html#vitest-watch), by default) using the Vitest CLI:\n\n<CodeSnippets path=\"vitest-plugin-run-tests.md\" />\n\n#### Debugging\n\nWhile the plugin does not require Storybook to run when testing, you may still want to run Storybook to debug your tests. To enable this, provide the [`storybookScript` option](#storybookscript) in the plugin configuration. When you run Vitest in watch mode, the plugin will start Storybook using this script and provide links to the story in the output on test failures. This allows you to quickly jump to the story in Storybook to debug the issue.\n\nYou can also provide a [`storybookUrl` option](#storybookurl) to the plugin configuration. When you're not using watch mode and tests fail, the plugin will provide a link to the story using this URL in the output. This is useful when [running tests in CI](#in-ci) or other environments where Storybook is not already running.\n\n![Screenshot of test failure in the console, showing a failure with a link to the story](../../../_assets/writing-tests/vitest-plugin-test-failure.png)\n\n### Editor extension\n\nTransforming your stories into Vitest tests with the plugin also enables you to run and debug tests using Vitest [IDE integrations](https://vitest.dev/guide/ide.html). This allows you to run tests directly from your editor, such as VSCode and JetBrains IDE.\n\nThis screenshot shows how you can run your Vitest tests in VSCode using the [Vitest extension](https://marketplace.visualstudio.com/items?itemName=vitest.explorer). Stories are annotated with the test status, and, when a test fails, a link to the story is provided for [debugging](#debugging).\n\n![Screenshot of test failure in VSCode, showing a failure attached to a story](../../../_assets/writing-tests/vitest-plugin-vscode.png)\n\n### In CI\n\nFor the most part, running your Storybook tests in CI is done [via the CLI](#cli).\n\nHowever, to have the test output link to your published Storybook on test failures, you need to provide the [`storybookUrl` option](#storybookurl) in the plugin configuration. Please reference the [detailed example in the Testing in CI guide](../../in-ci.mdx#21-debugging-test-failures-in-ci).\n\n## How it works\n\nThe Vitest addon works by using a Vitest plugin to transform your stories into [Vitest](https://vitest.dev) tests using [portable stories](../../../api/portable-stories/portable-stories-vitest.mdx). It also configures Vitest to run those tests in [browser mode](https://vitest.dev/guide/browser/), using Playwright's Chromium browser. Because it is built on top of Vitest, the addon requires a Vite-based Storybook framework.\n\nStories are tested in two ways: a smoke test to ensure it renders and, if a [play function](../../interaction-testing.mdx#writing-interaction-tests) is defined, that function is run and any [assertions made](../../interaction-testing.mdx#asserting-with-expect) within it are validated.\n\nWhen you run tests in the [Storybook UI](#storybook-ui), the addon runs Vitest in the background and reports the results in the sidebar. \n\n## Configuring tests\n\nThe tests run by the addon can be configured in two ways. You can toggle which test types are run and include, exclude, or skip stories from being tested.\n\n### Toggling test types\n\nIn addition to component tests, the Vitest addon supports multiple types of tests, depending on which other addons you are using in your project. Some test types, like [visual tests](../../visual-testing.mdx), are run independently. Others, like [accessibility](../../accessibility-testing.mdx), must be run alongside component tests. For these dependent test types, you can toggle them on or off in the testing widget by checking or unchecking the test types you want to run.\n\n![Screenshot of testing widget, expanded, everything is checked](../../../_assets/writing-tests/test-widget-expanded-all-enabled.png)\n\nNote that you may not have all of the test types pictured, depending on which addons you have installed.\n\n### Including, excluding, or skipping tests\n\nYou can use [tags](../../../writing-stories/tags.mdx) to include, exclude, or skip stories from being tested. Included stories are tested, excluded stories are not tested, and skipped stories are not tested but are counted in the test results.\n\nBy default, the plugin will run all stories with the `test` tag. You can adjust this behavior by providing the [`tags` option](#tags) in the plugin configuration. This allows you to include, exclude, or skip stories based on their tags.\n\nIn this example, we'll apply the `stable` tag to all of the Button component's stories, except for ExperimentalFeatureStory, which will have the `experimental` tag:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"tags-remove-in-story.md\" />\n\n{/* prettier-ignore-end */}\n\nTo connect those tags to our test behavior, we can adjust the plugin configuration to exclude the `experimental` tag:\n\n{/* prettier-ignore-start */}\n\n<CodeSnippets path=\"vitest-plugin-vitest-tags-configuration.md\" />\n\n{/* prettier-ignore-end */}\n\nIf the same tag is in both the `include` and `exclude` arrays, the `exclude` behavior takes precedence.\n\n## Comparison to the test runner\n\nThe [test runner](../test-runner.mdx) requires a running Storybook instance to test your stories, because it visits each one, executes the play function, and listens for results. The Vitest plugin, however, transforms your stories into tests using Vite and portable stories, so it does not need to run Storybook to test your stories. Because of this reliance on Vite, the plugin can only be used with Storybook frameworks that use Vite (and [Next.js](../../../get-started/frameworks/nextjs-vite.mdx)). The test runner, on the other hand, can be used with any Storybook framework.\n\n| Feature                                                  | Vitest addon       | test-runner              |\n| -------------------------------------------------------- | ------------------ | ------------------------ |\n| **Test types**                                                                                           |\n| - [Interaction tests](../../interaction-testing.mdx)     | ✅                 | ✅                       |\n| - [Accessibility tests](../../accessibility-testing.mdx) | ✅                 | ✅                       |\n| - [Visual tests](../../visual-testing.mdx)               | ✅                 | ❌                       |\n| - [Snapshot tests](../../snapshot-testing.mdx)           | ❌                 | ✅                       |\n| **Testing contexts**                                                                                     |\n| - Storybook UI                                           | ✅                 | ❌                       |\n| - Editor extensions                                      | ✅                 | ❌                       |\n| - CLI                                                    | ✅                 | ✅                       |\n| - In CI                                                  | ✅                 | ✅                       |\n| Tests run via                                            | Vitest             | Jest                     |\n| Works with all Storybook frameworks                      | ❌ (requires Vite) | ✅                       |\n| Runs tests in a real browser environment                 | ✅                 | ✅                       |\n| Calculates code coverage                                 | ✅                 | ✅ (with addon-coverage) |\n| Requires a running or published Storybook                | ❌                 | ✅                       |\n| Extensible to other addons                               | ✅                 | ❌                       |\n\nThe test runner is only a CLI tool. It does not have a UI for running tests, nor does it have an editor extension. The addon, however, provides a UI in Storybook for running tests, and it enables you to run and debug tests using Vitest IDE integrations.\n\nAdditionally, the test runner ran your stories as orchestrated tests in Jest, and that orchestration came with some complexity. By comparison, this plugin transforms your stories into real tests and then runs them using Vitest, which is simpler and more configurable.\n\nFinally, because of the simpler architecture and the use of Vitest, this plugin should be faster than the test runner for most projects. We'll do more benchmarking to quantify this in the future.\n\n## FAQ\n\n### What happens if Vitest itself has an error?\n\nSometimes tests can fail because of errors within Vitest itself. When this happens, the testing widget in the Storybook UI will alert you to the error, and you can click a link to view it in full. The error will also be logged to the console.\n\n![Screenshot of testing widget, expanded, showing Vitest error](../../../_assets/writing-tests/test-widget-vitest-error.png)\n\nVitest offers [troubleshooting help for common errors](https://vitest.dev/guide/common-errors.html).\n\n### What happens when there are different test results in multiple environments?\n\nWhen you run tests with this addon, they are run as Vitest tests with whatever configuration you have set up in your project. By default, they will run in browser mode, using Playwright's Chromium browser. Sometimes, tests will fail when run in the addon (or via CLI), but then pass when viewed in the Interactions panel (or vice versa). This can happen because the tests are run in different environments, which can have different behaviors.\n\n### How do I debug my CLI tests in Storybook?\n\nThe plugin will attempt to provide links to the story in Storybook when tests fail in CLI, for [debugging](#debugging) purposes.\n\nIf the URLs are not working when running tests in watch mode, you should check two configuration options:\n\n- [`storybookUrl`](#storybookurl): Ensure this URL is correct and accessible. For example, the default is `http://localhost:6006`, which may not use the same port number you're using.\n- [`storybookScript`](#storybookscript): Ensure this script is correctly starting Storybook.\n\nIf the URLs are not working when running tests in CI, you should ensure the Storybook is built and published before running the tests. You can then provide the URL to the published Storybook using the `storybookUrl` option. See the [In CI](#in-ci) section for an example.\n\n### How do I ensure my tests can find assets in the public directory?\n\nIf your stories use assets in the public directory and you're not using the default public directory location (`public`), you need to adjust the Vitest configuration to include the public directory. You can do this by providing the [`publicDir` option in the Vitest configuration file](https://vitejs.dev/config/shared-options.html#publicdir).\n\n### How do I isolate Storybook tests from others?\n\nSome projects might contain a `test` property in their Vite configuration. Because the Vitest configuration used by this plugin extends that Vite config, the `test` properties are merged. This lack of isolation can cause issues with your Storybook tests.\n\nTo isolate your Storybook tests from other tests, you need to move the `test` property from your Vite configuration to the Vitest configuration. The Vitest config used by the plugin can then safely extend your Vite config without merging the `test` property.\n\nAdditionally, we recommend using a [test project](#example-configuration-files) if you're using Vitest ≥ 4.0, or a workspace for previous versions to define separate configurations for your Storybook tests and other tests. This ensures each can be run either in isolation or together, depending on your needs.\n\n\n### Why do we recommend browser mode?\n\nVitest's browser mode runs your tests in a real browser (Chromium, via Playwright, in the default configuration). The alternative is a simulated browser environment, like JSDom or HappyDom, which can have differences in behavior compared to a real browser. For UI components, which can often depend on browser APIs or features, running tests in a real browser is more accurate.\n\nFor more, see [Vitest's guide on using browser mode effectively](https://vitest.dev/guide/browser/#motivation).\n\n### How do I use WebDriver instead of Playwright?\n\nWe recommend running tests in a browser using Playwright, but you can use WebDriverIO instead. To do so, you need to adjust the [browser provider in the Vitest configuration file](https://vitest.dev/config/#browser-provider).\n\n### How do I use a browser other than Chromium?\n\nWe recommend using Chromium, because it is most likely to best match the experience of a majority of your users. However, you can use other browsers by adjusting the [browser name in the Vitest configuration file](https://vitest.dev/config/#browser-name). Note that [Playwright and WebDriverIO support different browsers](https://vitest.dev/guide/browser/#browser-option-types).\n\n### How do I customize a test name?\n\nBy default, the export name of a story is mapped to the test name. To create a more descriptive test description, you can provide a `name` property for the story. This allows you to include spaces, brackets, or other special characters.\n\n```js title=\"Example.stories.js|ts\"\nexport const Story = {\n  name: 'custom, descriptive name'\n};\n```\n\n<If renderer=\"react\">\n\n### How do I fix the `m.createRoot is not a function` error?\n\nThis error can occur when using the addon on a project that uses a React version other than 18. To work around the issue, you can provide an alias to ensure the correct React version is used. Here's an example of how to do that in the Vitest configuration file:\n\n```ts title=\"vitest.config.ts\"\nimport { defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n  // ...\n  resolve: {\n    alias: {\n      \"@storybook/react-dom-shim\": \"@storybook/react-dom-shim/dist/react-16\",\n    },\n  },\n});\n```\n\n</If>\n\n### How do I fix the `Error: Vitest failed to find the current suite` error?\n\nIf you encounter this error, it's often not a Vitest issue but rather related to how your stories are being transformed. Here are steps to troubleshoot:\n\n1. Check the complete error logs for additional context, particularly around story transformation\n2. Pay attention to Vite dependency optimization warnings (e.g., \"new dependencies optimized: lodash\")\n3. If you see dependency optimization warnings, these can cause test-breaking reloads during execution\n\nThe most common fix is to pre-optimize your dependencies. You can do this by adding the dependencies to your Vite config's [`optimizeDeps.include`](https://vitejs.dev/config/dep-optimization-options.html#optimizedeps-include) array.\n\nThis prevents mid-test dependency optimization, which can interfere with Vitest's test suite management.\n\n### Why do my tests fail in CI with \"Failed to fetch dynamically imported module\" or \"Cannot connect to the iframe\"?\n\nThese errors typically occur in CI environments when running a large number of tests simultaneously, which can overwhelm the available resources. They do not usually appear locally because local machines tend to have more available resources or fewer tests run in parallel.\n\nThere are two recommended approaches to fix this:\n\n**1. Disable isolation mode**\n\nBy default, Vitest isolates each test file in its own environment. Disabling this can reduce resource consumption and prevent the errors:\n\n```ts title=\"vitest.config.ts\"\nexport default defineConfig({\n  test: {\n    // ...\n    isolate: false,\n  },\n});\n```\n\nSee [Vitest's `isolate` configuration](https://vitest.dev/config/isolate.html#isolate) for more details.\n\n**2. Use sharding to split tests across multiple CI jobs**\n\nSharding distributes your test files across several parallel CI jobs, reducing the load on each individual runner:\n\n```bash\n# Run shard 1 of 3\nvitest run --shard=1/3\n\n# Run shard 2 of 3\nvitest run --shard=2/3\n\n# Run shard 3 of 3\nvitest run --shard=3/3\n```\n\nSee [Vitest's sharding guide](https://vitest.dev/guide/improving-performance.html#sharding) for more details on how to integrate this into your CI pipeline.\n\n## API\n\n### Exports\n\nThis addon has the following exports:\n\n```js\nimport { storybookTest } from '@storybook/addon-vitest/vitest-plugin'\n```\n\n#### `storybookTest`\n\nType: `function`\n\nA [Vitest plugin](https://vitejs.dev/guide/api-plugin) that transforms your stories into tests. It accepts an [options object](#options) for configuration.\n\n### Options\n\nThe plugin is configured using an options object. Here are the available properties:\n\n#### `configDir`\n\nType: `string`\n\nDefault: `.storybook`\n\nThe directory where the Storybook configuration is located, relative to the current working directory.\n\nIf your [Storybook configuration](../../../configure/index.mdx) is not in the default location, you **must** specify the location here so the plugin can function correctly.\n\n#### `storybookScript`\n\nType: `string`\n\nOptional script to run Storybook. If provided, Vitest will start Storybook using this script when run in watch mode. Only runs if the Storybook in `storybookUrl` is not already available.\n\n#### `storybookUrl`\n\nType: `string`\n\nDefault: `http://localhost:6006`\n\nThe URL where Storybook is hosted. This is used for internal checks and to provide a [link to the story in the test output on failures](#debugging).\n\n#### `tags`\n\nType:\n\n```ts\n{\n  include: string[];\n  exclude: string[];\n  skip: string[];\n}\n```\n\nDefault:\n\n```ts\n{\n  include: ['test'],\n  exclude: [],\n  skip: [],\n}\n```\n\n[Tags](../../../writing-stories/tags.mdx) to include, exclude, or skip. These tags are defined as annotations in your story, meta, or preview.\n\n- **`include`**: Stories with these tags will be tested\n- **`exclude`**: Stories with these tags will not be tested, and will not be counted in the test results\n- **`skip`**: Stories with these tags will not be tested, and will be counted in the test results\n\n#### `disableAddonDocs`\n\nType: `boolean`\n\nDefault: `true`\n\nWhether to disable addon docs MDX parsing while running tests.\n\nWhen either the preview config or stories import mdx files, they are mocked as normally they are not needed for tests.\nYou might set `disableAddonDocs` to `false` only in case your stories actually need to read and parse MDX files as part of rendering your components.\n\n</If>\n{/* End supported renderers */}\n\n**More testing resources**\n\n* [Interaction testing](../../interaction-testing.mdx) for user behavior simulation\n* [Accessibility testing](../../accessibility-testing.mdx) for accessibility\n* [Visual testing](../../visual-testing.mdx) for appearance\n* [Snapshot testing](../../snapshot-testing.mdx) for rendering errors and warnings\n* [Test coverage](../../test-coverage.mdx) for measuring code coverage\n* [CI](../../in-ci.mdx) for running tests in your CI/CD pipeline\n* [Test runner](../test-runner.mdx) to automate test execution\n* [End-to-end testing](../stories-in-end-to-end-tests.mdx) for simulating real user scenarios\n* [Unit testing](../stories-in-unit-tests.mdx) for functionality\n"
  },
  {
    "path": "docs/writing-tests/integrations/vitest-addon/migration-guide.mdx",
    "content": "---\ntitle: 'Migrating to Vitest addon from test-runner'\nisTab: true\ntab:\n  order: 2\n  title: Migrating from test-runner\n---\n\nThe [test-runner](../test-runner.mdx) was created back in 2021 to enable users to run stories as tests. It is a solution that uses Jest as a runner and Playwright as a browser environment. Over the years, Storybook has evolved and introduced many testing-related concepts, including a [Vitest-based testing solution](./index.mdx), a spiritual successor to the test-runner. Alongside it, we released a testing widget, allowing users to run tests directly from Storybook's UI and get reports such as a11y and coverage.\n\nYou **do not** have to change how you write your stories between the test-runner and the Vitest addon.\n\n![Screenshot of testing widget, expanded, with the Run tests button highlighted](../../../_assets/writing-tests/test-widget-run-all.png)\n\nThis guide explains how to migrate an existing project using `@storybook/test-runner` to the `@storybook/addon-vitest`.\n\n## Why migrate?\n\nMigrating to the Vitest addon replaces the previous Jest-based test-runner with a modern, browser-friendly testing stack. It's designed to run stories as tests directly in [Storybook's UI](./index.mdx#storybook-ui) while also integrating with Vitest's CLI and [IDE](./index.mdx#editor-extension) integrations — reducing setup complexity and bringing built-in support for accessibility and coverage. The main benefits are summarized below.\n\n- Vitest is used as a runner instead of Jest, offering faster test execution and better integration with modern JavaScript tooling.\n- Stories seamlessly integrate as tests in your Vitest setup, significantly simplifying your component test configuration.\n- There is no need to build and run Storybook to run tests, which makes the setup faster and more portable.\n- Tests are still tested in a Playwright environment, but in [Vitest's Browser mode](https://vitest.dev/guide/browser/).\n- Accessibility testing comes out of the box and integrates with the Storybook testing widget and Accessibility addon panel.\n- Code coverage is enabled via Vitest's built-in coverage support. You no longer need instrumentation from the `@storybook/addon-coverage` package, which can make your stories render faster.\n\nFor more, please refer to the comparison table in the [Vitest addon guide](./index.mdx#comparison-to-the-test-runner).\n\n## Is my project eligible to upgrade?\n\nThe [Vitest addon](./index.mdx) is supported and recommended for React, Preact, Vue, Svelte, and Web Components projects, which use the [Vite builder](../../../builders/vite.mdx) (or the [Next.js framework with Vite](../../../get-started/frameworks/nextjs-vite.mdx)).\n\nIf you are using a different renderer (such as Angular) or the Webpack builder, you should continue to use the [test runner](../test-runner.mdx) to test your stories.\n\n## Migration steps\n\nBelow you will find the essential steps to migrate from the test-runner to the Vitest addon. Additionally, you can use the [following commit](https://github.com/yannbf/test-runner-migration-example/commit/cb0ddd5137021a7ed25d15f8d23c6c5e2d01513e) as a reference for an example project being migrated.\n\n### 1. Remove test-runner dependencies\n\nRemove the following dependencies:\n\n- `@storybook/test-runner` dependency\n- `@storybook/addon-coverage` dependency (if present)\n\n### 2. Remove test-runner related files\n\nRemove the following files:\n\n- `test-runner-jest.config.js` file (if present)\n- `.storybook/test-runner.ts` file (if present)\n  - If you had configured accessibility testing, this is now done out of the box with the Vitest addon.\n  - If you had configured image snapshot testing, check [this FAQ](#what-if-i-am-doing-image-snapshot-testing).\n  - If you had configuration for custom, advanced use cases such as using [the `prepare` hook](https://github.com/storybookjs/test-runner#prepare), please reach out on [Discord](https://discord.gg/storybook) or open a [discussion on GitHub](https://github.com/storybookjs/storybook/discussions/new/choose) so we can assist you with the migration.\n\n### 3. Set up `@storybook/addon-vitest`\n\n- Run this command, which will set up all the necessary code for you.\n  \n  <CodeSnippets path=\"addon-test-install.md\" />\n  \n- Update the `package.json` script for Storybook tests, replacing the test-runner binary and using Vitest instead:\n\n  ```diff title=\"package.json\"\n  {\n    \"scripts\": {\n  -    \"test-storybook\": \"test-storybook\"\n  +    \"test-storybook\": \"vitest --project=storybook\"\n    }\n  }\n\n### 4. Update your CI to run Vitest instead of the test-runner\n\nIf you're using the Storybook test-runner in CI, replace its build/serve/wait flow with a single Vitest command. For example, in GitHub Actions:\n\n```diff title=\".github/workflows/storybook-tests.yml\"\nname: 'Storybook Tests'\n\non: push\n\njobs:\n  test:\n    timeout-minutes: 60\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-node@v4\n        with:\n          node-version-file: '.nvmrc'\n      - name: Install dependencies\n        run: npm ci\n      - name: Install Playwright\n        run: npx playwright install --with-deps\n-      - name: Build Storybook\n-        run: npm run build-storybook --quiet\n-      - name: Serve Storybook and run tests\n-        run: |\n-          npx concurrently -k -s first -n \"SB,TEST\" -c \"magenta,blue\" \\\n-            \"npx http-server storybook-static --port 6006 --silent\" \\\n-            \"npx wait-on tcp:127.0.0.1:6006 && npm run test-storybook --coverage\"\n+      - name: Run storybook tests\n+        run: |\n+          npm run test-storybook\n```\n\nIf you want to generate coverage reports in CI, use the `--coverage` flag with the test script: `npm run test-storybook -- --coverage`.\n\nFor other CI providers and for more detailed configuration info, check the [testing in CI guide](../../in-ci.mdx#2-add-a-new-ci-workflow).\n\n## FAQ\n\n### What if I am using Storybook with Webpack or RsPack?\n\nThe Vitest addon relies on Vite to transform and run your stories as tests. Which means it only works with Storybook frameworks that use Vite.\n\nIf your Storybook project uses a non-Vite builder like Webpack or RsPack, you will need to keep using the `@storybook/test-runner` for your component testing.\n\nMost Webpack-based Storybook projects which do not have complex configurations can [migrate to Vite](../../../builders/vite#migrating-from-webpack) relatively easily. If you are using Next.js, you can use the [`@storybook/nextjs-vite` framework](../../../get-started/frameworks/nextjs-vite.mdx) to use Vite with Storybook.\n\n### What if I am using Jest for my unit tests?\n\nYou can still migrate to use Vitest, but if you believe you won't benefit from it, you can keep using the `@storybook/test-runner`.\n\n### What if I am doing image snapshot testing?\n\nThere are solutions for image snapshot testing that integrate with the Storybook testing widget:\n\n- On the cloud with the [Visual tests addon](../../visual-testing.mdx)\n- Locally with [`storybook-addon-vis`](https://github.com/repobuddy/visual-testing)"
  },
  {
    "path": "docs/writing-tests/interaction-testing.mdx",
    "content": "---\ntitle: 'Interaction tests'\nsidebar:\n  order: 2\n  title: Interaction tests\n---\n\nIn Storybook, interaction tests are built as part of a [story](../writing-stories/index.mdx). That story renders the component with the necessary props and context to place it in an initial state. You then use a [play function](../writing-stories/play-function.mdx) to simulate user behavior like clicks, typing, and submitting a form and then assert on the end result.\n\nYou can preview and debug your interaction tests using the Interactions panel in the Storybook UI. They can be automated using the Vitest addon, allowing you to run tests for your project in Storybook, terminal, or CI environments.\n\n<Video src=\"../_assets/writing-tests/component-interaction-testing.mp4\" />\n\n## Writing interaction tests\n\nEvery story you write can be render tested. A **render test** is a simple version of an interaction test that only tests the ability of a component to render successfully in a given state. That works fine for relatively simple, static components like a Button. But for more complex, interactive components, you can go farther.\n\nYou can simulate user behavior and assert on functional aspects like DOM structure or function calls using the `play` function. When a component is tested, the play function is ran and any assertions within it are validated.\n\nIn this example, the EmptyForm story tests the render of the LoginForm component and the FilledForm story tests the form submission:\n\n<CodeSnippets path=\"login-form-with-play-function.md\" />\n\n![Storybook with a LoginForm component and passing interactions in the Interactions panel](../_assets/writing-tests/interaction-test-pass.png)\n\nThere’s a lot going on in that code sample, so let’s walk through the APIs one-by-one.\n\n### Querying the `canvas`\n\n`canvas` is a queryable element containing the story under test, which is provided as a parameter of your play function. You can use `canvas` to find specific elements to interact with or assert on. All query methods come directly from Testing Library and take the form of `<type><subject>`.\n\nThe available types are summarized in this table and fully documented in the [Testing Library docs](https://testing-library.com/docs/queries/about#types-of-queries):\n\n| Type of Query         | 0 Matches     | 1 Match        | >1 Matches   | Awaited |\n| --------------------- | ------------- | -------------- | ------------ | ------- |\n| **Single Element**    |               |                |              |         |\n| `getBy...`            | Throw error   | Return element | Throw error  | No      |\n| `queryBy...`          | Return `null` | Return element | Throw error  | No      |\n| `findBy...`           | Throw error   | Return element | Throw error  | Yes     |\n| **Multiple Elements** |               |                |              |         |\n| `getAllBy...`         | Throw error   | Return array   | Return array | No      |\n| `queryAllBy...`       | Return `[]`   | Return array   | Return array | No      |\n| `findAllBy...`        | Throw error   | Return array   | Return array | Yes     |\n\nThe subjects are listed here, with links to their full Testing Library documentation:\n\n1. [`ByRole`](https://testing-library.com/docs/queries/byrole) — Find elements by their accessible role\n2. [`ByLabelText`](https://testing-library.com/docs/queries/bylabeltext) — Find elements by their associated label text\n3. [`ByPlaceholderText`](https://testing-library.com/docs/queries/byplaceholdertext) — Find elements by their placeholder value\n4. [`ByText`](https://testing-library.com/docs/queries/bytext) — Find elements by the text they contain\n5. [`ByDisplayValue`](https://testing-library.com/docs/queries/bydisplayvalue) — Find `input`, `textarea`, or `select` elements by their current value\n6. [`ByAltText`](https://testing-library.com/docs/queries/byalttext) — Find elements with the given `alt` attribute value\n7. [`ByTitle`](https://testing-library.com/docs/queries/bytitle) — Find elements with the given `title` attribute value\n8. [`ByTestId`](https://testing-library.com/docs/queries/bytestid) — Find elements with the given `data-testid` attribute value\n\n<Callout variant=\"info\" icon=\"💡\">\n\nNote the order of this list! We (and [Testing Libary](https://testing-library.com/docs/queries/about#priority)) highly encourage you to query for elements in a way that resembles the way a real person would interact with your UI. For example, finding elements by their accessible role helps ensure that the most people can use your component. While using `data-testid` should be a last resort, only after trying every other approach.\n\n</Callout>\n\nPutting that altogether, some typical queries might look like:\n\n```js\n// Find the first element with a role of button with the accessible name \"Submit\"\nawait canvas.findByRole('button', { name: 'Submit' });\n\n// Get the first element with the text \"An example heading\"\ncanvas.getByText('An example heading');\n\n// Get all elements with the role of listitem\ncanvas.getAllByRole('listitem');\n```\n\n<If renderer=\"web-components\">\n\n#### Querying within shadow DOM\n\nIf your components use the shadow DOM, you can query elements within a shadow root with the help of [`shadow-dom-testing-library`](https://github.com/konnorrogers/shadow-dom-testing-library), which provides versions of the queries above that can pierce the shadow boundary. For example, `findByRole` → `findByShadowRole`, `getByText` → `getByShadowText`, and so on.\n\nWith a bit of configuration, you can use these queries in your play function. Add the following code to your `.storybook/preview.js|ts` file:\n\n<CodeSnippets path=\"shadow-dom-testing-library-in-preview.md\" />\n\nNow, those queries are available on the `canvas` object in your `play` function:\n\n<CodeSnippets path=\"shadow-dom-testing-library-in-story.md\" />\n\n{/* END only web-components */}\n</If>\n\n### Simulating behavior with `userEvent`\n\nAfter querying for elements, you will likely need to interact with them to test your component’s behavior. For this we use the `userEvent` utility, which is provided as a parameter of your play function. This utility simulates user interactions with the component, such as clicking buttons, typing in inputs, and selecting options.\n\nThere are many methods available on `userEvent`, which are detailed in the [`user-event` documentation](https://testing-library.com/docs/user-event/intro#writing-tests-with-userevent). This table will highlight some of the commonly-used methods.\n\n| Method            | Description                                                                                                              |\n| ----------------- | ------------------------------------------------------------------------------------------------------------------------ |\n| `click`           | Clicks the element, calling a click() function<br />`await userEvent.click(<element>)`                                   |\n| `dblClick`        | Clicks the element twice<br />`await userEvent.dblClick(<element>)`                                                      |\n| `hover`           | Hovers an element<br />`await userEvent.hover(<element>)`                                                                 |\n| `unhover`         | Unhovers out of element<br />`await userEvent.unhover(<element>)`                                                         |\n| `tab`             | Presses the tab key<br />`await userEvent.tab()`                                                                         |\n| `type`            | Writes text inside inputs or textareas<br />`await userEvent.type(<element>, 'Some text');`                              |\n| `keyboard`        | Simulates keyboard events<br />`await userEvent.keyboard('{Shift}');`                                                    |\n| `selectOptions`   | Selects the specified option(s) of a select element<br />`await userEvent.selectOptions(<element>, ['1','2']);`          |\n| `deselectOptions` | Removes the selection from a specific option of a select element<br />`await userEvent.deselectOptions(<element>, '1');` |\n| `clear`           | Selects the text inside inputs or textareas and deletes it<br />`await userEvent.clear(<element>);`                      |\n\n<Callout variant=\"warning\">\n\n`userEvent` methods should *always* be `await`ed inside of the play function. This ensures they can be properly logged and debugged in the Interactions panel.\n\n</Callout>\n\n### Asserting with `expect`\n\nFinally, after querying for elements and simulating behavior, you can make assertions on the result which are validated when running the test. For this we use the `expect` utility, which is available via the `storybook/test` module:\n\n```js\nimport { expect } from 'storybook/test';\n```\n\nThe `expect` utility here combines the methods available in [Vitest’s `expect`](https://vitest.dev/api/expect.html) as well as those from [`@testing-library/jest-dom`](https://github.com/testing-library/jest-dom#custom-matchers) (which, despite the name, also work in Vitest tests). There are many, many methods available. This table will highlight some of the commonly-used methods.\n\n| Method                                                                                 | Description                                                                                                                          |\n| -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |\n| [`toBeInTheDocument()`](https://github.com/testing-library/jest-dom#tobeinthedocument) | Checks if the element is in the DOM<br />`await expect(<element>).toBeInTheDocument()`                                               |\n| [`toBeVisible()`](https://github.com/testing-library/jest-dom#tobevisible)             | Checks if the element is visible to the user<br />`await expect(<element>).toBeVisible()`                                            |\n| [`toHaveAttribute()`](https://github.com/testing-library/jest-dom#tohaveattribute)     | Checks if an element has an attribute<br />`await expect(<element>).toHaveAttribute('aria-disabled', 'true')`                                                       |\n| [`toHaveBeenCalled()`](https://vitest.dev/api/expect.html#tohavebeencalled)            | Checks that a spied function was called<br />`await expect(<function-spy>).toHaveBeenCalled()`                                       |\n| [`toHaveBeenCalledWith()`](https://vitest.dev/api/expect.html#tohavebeencalledwith)    | Checks that a spied function was called with specific parameters<br />`await expect(<function-spy>).toHaveBeenCalledWith('example')` |\n\n<Callout variant=\"warning\">\n\n`expect` calls should *always* be `await`ed inside of the play function. This ensures they can be properly logged and debugged in the Interactions panel.\n\n</Callout>\n\n### Spying on functions with `fn`\n\nWhen your component calls a function, you can spy on that function to make assertions on its behavior using the `fn` utility from Vitest, available via the `storybook/test` module:\n\n```js\nimport { fn } from 'storybook/test'\n```\n\nMost of the time, you will use `fn` as an `arg` value when writing your story, then access that `arg` in your test:\n\n<CodeSnippets path=\"interaction-test-fn-mock-spy.md\" />\n\n### Run code before the component gets rendered\n\n<If notRenderer=\"angular\">\n\nYou can execute code before rendering by using the `mount` function in the `play` method.\n\nHere's an example of using the [`mockdate`](https://github.com/boblauer/MockDate) package to mock the [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date), a useful way to make your story render in a consistent state.\n\n<CodeSnippets path=\"mount-basic.md\" />\n\n<Callout variant=\"warning\">\n\nThere are two requirements to use the `mount` function:\n\n1. You *must* destructure the mount property from the `context` (the argument passed to your play function). This makes sure that Storybook does not start rendering the story before the play function begins.\n2. Your Storybook framework or builder must be configured to transpile to ES2017 or newer. This is because destructuring statements and async/await usages are otherwise transpiled away, which prevents Storybook from recognizing your usage of `mount`.\n\n</Callout>\n\n<If renderer={['react', 'vue', 'svelte']}>\n\n#### Create mock data before rendering\n\nYou can also use `mount` to create mock data that you want to pass to the component. To do so, first create your data in the play function and then call the `mount` function with a component configured with that data. In this example, we create a mock `note` and pass its `id` to the Page component, which we call `mount` with.\n\n<CodeSnippets path=\"mount-advanced.md\" />\n\n<Callout variant=\"info\">\n\nWhen you call `mount()` with no arguments, the component is rendered using the story’s render function, whether the [implicit default](../api/csf/index.mdx#default-render-functions) or the [explicit custom definition](../api/csf/index.mdx#custom-render-functions).\n\nWhen you mount a specific component inside the `mount` function like in the example above, the story’s render function will be ignored. This is why you must forward the `args` to the component.\n\n</Callout>\n\n</If>\n{/* END React, Vue, Svelte-only */}\n\n</If>\n{/* END non-Angular-only */}\n\n<If renderer=\"angular\">\n\nYou can execute code before the component is rendered by defining an asynchronous [`beforeEach` function](#beforeeach) for the story.\n\n</If>\n\n### Run code before each story in a file\n\nSometimes you might need to run the same code before each story in a file. For instance, you might need to set up the initial state of the component or modules. You can do this by adding an asynchronous `beforeEach` function to the component meta.\n\nYou can return a cleanup function from the `beforeEach` function, which will run **after** each story, when the story is remounted or navigated away from.\n\n<Callout variant=\"info\">\n\nGenerally, you should reset component and module state in the [preview file's `beforeAll` or `beforeEach` functions](#set-up-or-reset-state-for-all-tests), to ensure it applies to your entire project. However, if a component's needs are particularly unique, you can use the returned cleanup function in the component meta `beforeEach` to reset the state as needed.\n\n</Callout>\n\n<CodeSnippets path=\"before-each-in-meta-mock-date.md\" />\n\n### Set up or reset state for all tests\n\nWhen you [alter a component's state](#run-code-before-the-component-gets-rendered), it's important to reset that state before rendering another story to maintain isolation between tests.\n\nThere are two options for resetting state, `beforeAll` and `beforeEach`.\n\n#### `beforeAll`\n\nThe `beforeAll` function in the preview file (`.storybook/preview.js|ts`) will run once before any stories in the project and will _not_ re-run between stories. Beyond its initial run when kicking off a test run, it will not run again unless the preview file is updated. This is a good place to bootstrap your project or run any setup that your entire project depends on, as in the example below.\n\nYou can return a cleanup function from the `beforeAll` function, which will run before re-running the `beforeAll` function or during the teardown process in the test runner.\n\n<CodeSnippets path=\"before-all-in-preview.md\" />\n\n#### `beforeEach`\n\nUnlike `beforeAll`, which runs only once, the `beforeEach` function in the preview file (`.storybook/preview.js|ts`) will run before each story in the project. This is best used for resetting state or modules that are used by all or most of your stories. In the example below, we use it to reset the mocked Date.\n\nYou can return a cleanup function from the `beforeEach` function, which will run **after** each story, when the story is remounted or navigated away from.\n\n<CodeSnippets path=\"before-each-in-preview.md\" />\n\n<Callout variant=\"info\">\n\nIt is _not_ necessary to restore `fn()` mocks, as Storybook will already do that automatically before rendering a story. See the [`parameters.test.restoreMocks` API](../api/parameters.mdx#restoremocks) for more information.\n\n</Callout>\n\n### Make assertions after interactions\n\nSometimes, you may need to make assertions or run code after the component has been rendered and interacted with.\n\n#### `afterEach`\n\n`afterEach` runs after the story is rendered and the play function has completed. It can be used at the project level in the preview file (`.storybook/preview.js|ts`), at the component level in the component meta, or at the story level in the story definition. This is useful for making assertions after the component has been rendered and interacted with, such as running checks on the final rendered output or logging information.\n\nLike the `play` function, `afterEach` receives the `context` object, which contains the `args`, `canvas`, and other properties related to the story. You can use this to make assertions or run code after the story has been rendered.\n\n<CodeSnippets path=\"after-each-in-meta.md\" />\n\n<Callout variant=\"info\">\n\nYou should not use `afterEach` to reset state in your tests. Because it runs after the story, resetting state here could prevent you from seeing the correct end state of your story. Instead, use the [`beforeEach`'s returned cleanup function](#beforeeach) to reset state, which will run only when navigating between stories to preserve the end state.\n\n</Callout>\n\n### Group interactions with the step function\n\nFor complex flows, it can be worthwhile to group sets of related interactions together using the step function. This allows you to provide a custom label that describes a set of interactions:\n\n<CodeSnippets path=\"storybook-interactions-step-function.md\" />\n\nThis will show your interactions nested in a collapsible group:\n\n![Interaction testing with labeled steps](../_assets/writing-tests/storybook-addon-interactions-steps.png)\n\n### Mocked modules\n\nIf your component depends on modules that are imported into the component file, you can mock those modules to control and assert on their behavior. This is detailed in the [mocking modules guide](../writing-stories/mocking-data-and-modules/mocking-modules.mdx).\nYou can then import the mocked module (which has all of the helpful methods of a [Vitest mocked function](https://vitest.dev/api/mock.html)) into your story and use it to assert on the behavior of your component:\n\n<CodeSnippets path=\"storybook-test-fn-mock-spy.md\" />\n\n## Running interaction tests\n\nIf you're using the [Vitest addon](./integrations/vitest-addon/index.mdx), you can run your interaction tests in these ways:\n\n- [In the Storybook UI](./integrations/vitest-addon/index.mdx#storybook-ui)\n- [In your editor](./integrations/vitest-addon/index.mdx#editor-extension)\n- [Via the CLI](./integrations/vitest-addon/index.mdx#cli)\n- [In CI environments](./integrations/vitest-addon/index.mdx#in-ci)\n\nIn the Storybook UI, you can run interaction tests by clicking the **Run component tests** button in the expanded testing widget in the sidebar or by opening the context menu (three dots) on a story or folder and selecting **Run component tests**.\n\n![Test widget, expanded, hovering run component tests button](../_assets/writing-tests/test-widget-run-component-tests.png)\n\nIf you're using the [test-runner](./integrations/test-runner.mdx), you can run your interaction tests in the terminal or in CI environments.\n\n## Debugging interaction tests\n\nIf you check the Interactions panel, you'll see the step-by-step flow defined in your play function for each story. It also offers a handy set of UI controls to pause, resume, rewind, and step through each interaction.\n\nAny test failures will also show up here, making it easy to quickly pinpoint the exact point of failure. In this example, the logic is missing to set the `submitted` state after pressing the Log in button.\n\n<Video src=\"../_assets/writing-tests/interactions-debug.mp4\" />\n\n### Permalinks for reproductions\n\nBecause Storybook is a webapp, anyone with the URL can reproduce the failure with the same detailed information without any additional environment configuration or tooling required.\n\n![Interaction testing with a failure](../_assets/writing-tests/interactions-failure.png)\n\nStreamline interaction testing further by automatically [publishing Storybook](../sharing/publish-storybook.mdx) in pull requests. That gives teams a universal reference point to test and debug stories.\n\n## Automate with CI\n\nWhen you run your tests with the Vitest addon, automating those tests is as simple as running your tests in your CI environment. Please see the [testing in CI guide](./in-ci.mdx) for more information.\n\nIf you cannot use the Vitest addon, you can still run your tests in CI using the [test-runner](./integrations/test-runner.mdx).\n\n## Troubleshooting\n\n#### What’s the difference between interaction tests and visual tests?\n\nInteraction tests can be expensive to maintain when applied wholesale to every component. We recommend combining them with other methods like visual testing for comprehensive coverage with less maintenance work.\n\n#### What's the difference between interaction tests and using Vitest + Testing Library alone?\n\nInteraction tests integrate Vitest and Testing Library into Storybook. The biggest benefit is the ability to view the component you're testing in a real browser. That helps you debug visually, instead of getting a dump of the (fake) DOM in the command line or hitting the limitations of how JSDOM mocks browser functionality. It's also more convenient to keep stories and tests together in one file than having them spread across files.\n\n**More testing resources**\n\n* [Vitest addon](./integrations/vitest-addon/index.mdx) for running tests in Storybook\n* [Accessibility testing](./accessibility-testing.mdx) for accessibility\n* [Visual testing](./visual-testing.mdx) for appearance\n* [Snapshot testing](./snapshot-testing.mdx) for rendering errors and warnings\n* [Test coverage](./test-coverage.mdx) for measuring code coverage\n* [CI](./in-ci.mdx) for running tests in your CI/CD pipeline\n* [End-to-end testing](./integrations/stories-in-end-to-end-tests.mdx) for simulating real user scenarios\n* [Unit testing](./integrations/stories-in-unit-tests.mdx) for functionality\n* [Test runner](./integrations/test-runner.mdx) to automate test execution\n"
  },
  {
    "path": "docs/writing-tests/snapshot-testing.mdx",
    "content": "---\ntitle: Snapshot tests\nsidebar:\n  order: 5\n  title: Snapshot tests\n---\n\n## Snapshot tests\n\nSnapshot testing is simply rendering a component in a given state, taking a snapshot of the rendered DOM or HTML, and then comparing it against the previous snapshot. They’re convenient to create, but can be difficult and noisy to maintain if the snapshot contains too much information. For UI components, [visual tests](./visual-testing.mdx) (easier to review) or [interaction tests](./interaction-testing.mdx) (focused on functionality) are usually the better fit. However, there are some cases where snapshot testing may be necessary, such as ensuring an error is thrown correctly.\n\nYou can reuse your stories as the basis of snapshot tests within another test environment, like Jest or Vitest. To enable this, Storybook provides the Portable Stories API, which composes your stories with their annotations ([args](../writing-stories/args.mdx), [decorators](../writing-stories/decorators.mdx), [parameters](../writing-stories/parameters.mdx), etc) and produces a renderable element for your tests. Portable Stories are available for:\n\n- [Vitest](../api/portable-stories/portable-stories-vitest.mdx)\n- [Jest](../api/portable-stories/portable-stories-jest.mdx)\n- [Playwright CT](../api/portable-stories/portable-stories-playwright.mdx)\n\n<Callout variant=\"info\">\n\nLooking for snapshot testing with Storyshots? Storyshots is deprecated and no longer maintained. We recommend using the Portable Stories API instead.\n\nPlease reference the [Storyshots documentation](../../../release-8-6/docs/writing-tests/snapshot-testing/storyshots-migration-guide.mdx) for more information on how to migrate your tests.\n\n</Callout>\n\n## Get started with Portable Stories\n\nIf you’re using Storybook Test, your project is already configured to use Portable Stories in Vitest.\n\nIf you’re not using Storybook Test or would like to test in another testing environment, please follow the relevant documentation:\n\n- [Vitest](../api/portable-stories/portable-stories-vitest.mdx#1-apply-project-level-annotations)\n- [Jest](../api/portable-stories/portable-stories-jest.mdx#1-apply-project-level-annotations)\n- [Playwright CT](../api/portable-stories/portable-stories-playwright.mdx#1-apply-project-level-annotations)\n\n## Snapshot testing a portable story\n\nSnapshot testing a reusable story is a straightforward process of using `composeStories` from the Portable Stories API to get a renderable element, rendering that element, and then taking and comparing a snapshot.\n\nThis example renders a Button component in Vitest (by reusing one of Button’s stories) and asserts that the rendered HTML snapshot matches.\n\n<CodeSnippets path=\"button-snapshot-test-portable-stories.md\" />\n\nOnce the test has run, a snapshot will be inserted or created. Then, when you run tests again and the snapshot doesn’t match, the test will fail and you will see output something like this:\n\n```diff\nFAIL  src/components/ui/Button.test.ts > Button snapshot\nError: Snapshot `Button snapshot 1` mismatched\n\n- Expected\n+ Received\n\n  <div>\n    <button\n-     class=\"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive bg-primary text-primary-foreground shadow-xs hover:bg-primary/90 h-9 px-4 py-2 has-[>svg]:px-3\"\n+     class=\"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive bg-primary text-primary-foreground shadow-xs hover:bg-primary/90 h-9 px-3 py-2 has-[>svg]:px-3\"\n      data-slot=\"button\"\n    >\n      Button\n    </button>\n  </div>\n```\n\n<Callout variant=\"info\" icon=\"💡\">\n\nHow long did it take you to find what changed? (`px-4` → `px-3`)\n\nThis is exactly why [visual tests](./visual-testing.mdx) are so much better for testing the appearance of UI components. Not only is it immediately apparent what has changed, but it also tests the actual appearance your users will see, not merely the CSS applied.\n\n</Callout>\n\n### Verifying an error is thrown\n\nNow that we know how to do general snapshot testing, let’s apply it to a common use case: verifying that an expected error is thrown correctly.\n\nIn this example, we have a simple Button React component which for some reason accepts a prop, `doNotUseThisItWillThrowAnError`, which will (unsurprisingly) throw an error if it is used.\n\n```tsx title=\"Button.tsx\"\nfunction Button(props) {\n  if (props.doNotUseThisItWillThrowAnError) {\n    throw new Error(\"I tried to tell you...\")\n  }\n\n  return <button {...props} />\n}\n```\n\nWe then have a story which applies that prop via `args`. It also removes the default `dev` and `test` tags to prevent the story from displaying in the Storybook sidebar and from being tested as a story (by Storybook Test), respectively.\n\n```js title=\"Button.stories.js\"\nexport const ThrowError = {\n  tags: ['!dev', '!test'],\n  args: {\n    doNotUseThisItWillThrowAnError: true,\n  },\n}\n```\n\nFinally, we write a test in the test file which asserts that an error is thrown with a particular message.\n\n```ts title=\"Button.test.ts\"\n// @vitest-environment jsdom\n\nimport { expect, test } from \"vitest\";\n\nimport { composeStories } from \"@storybook/react\";\n\nimport * as stories from \"./Button.stories\";\n\nconst { ThrowError } = composeStories(stories);\n\ntest(\"Button throws error\", async () => {\n  await expect(ThrowError.run()).rejects.toThrowError('I tried to tell you...');\n});\n```\n\nThis example is simplified for educational purposes. The same technique could be applied to more complex scenarios, such as a form with invalid input or a simulated network failure.\n\n## Snapshot testing with the test-runner\n\nIf you cannot use portable stories in your project, you can still run snapshot tests using the test-runner. Follow the instructions in the [test-runner documentation](./integrations/test-runner.mdx#run-snapshot-tests) to set up the test-runner with snapshot tests in your project.\n\n## FAQ\n\n### What’s the difference between snapshot tests and visual tests?\n\nVisual tests capture images of stories and compare them against image baselines. Snapshot tests take DOM or HTML snapshots and compare them against DOM or HTML baselines. Visual tests are better suited for verifying appearance. Snapshot tests are useful for validating non-visual output and ensuring the DOM doesn’t change.\n\n**More testing resources**\n\n* [Vitest addon](./integrations/vitest-addon/index.mdx) for running tests in Storybook\n* [Interaction testing](./interaction-testing.mdx) for user behavior simulation\n* [Accessibility testing](./accessibility-testing.mdx) for accessibility\n* [Visual testing](./visual-testing.mdx) for appearance\n* [Test coverage](./test-coverage.mdx) for measuring code coverage\n* [CI](./in-ci.mdx) for running tests in your CI/CD pipeline\n* [End-to-end testing](./integrations/stories-in-end-to-end-tests.mdx) for simulating real user scenarios\n* [Unit testing](./integrations/stories-in-unit-tests.mdx) for functionality\n* [Test runner](./integrations/test-runner.mdx) to automate test execution\n"
  },
  {
    "path": "docs/writing-tests/test-coverage.mdx",
    "content": "---\ntitle: 'Test coverage'\nsidebar:\n  order: 5\n  title: Test coverage\n---\n\nTest coverage is the practice of measuring whether existing tests fully cover your code. It marks which conditions, logic branches, functions and variables in your code are and are not being tested.\n\nCoverage tests examine the instrumented code against a set of industry-accepted best practices. They act as the last line of QA to improve the quality of your test suite.\n\nEach project’s coverage report will look different, but the important things to note are:\n\n1. **The overall line/branch coverage**, which serves as a high-level health check.\n2. **Specific lines/branches** that are not covered, which are potential test gaps.\n\nWhen you run component tests with the [Vitest addon](./integrations/vitest-addon/index.mdx), it can generate a coverage report. The result is summarized in the testing widget, showing the percentage of statements covered by your tested stories.\n\n![Test widget with coverage summary](../_assets/writing-tests/test-widget-coverage-summary.png)\n\n<Callout variant=\"info\">\n\nIf you cannot use the Vitest addon in your project, you can still generate code coverage using the test-runner. Follow the instructions in the [test-runner documentation](./integrations/test-runner.mdx#generate-code-coverage) to set up the test-runner with code coverage in your project.\n\n</Callout>\n\n## Set up\n\nCoverage is included in the [Vitest addon](./integrations/vitest-addon/index.mdx) and, when enabled, will be calculated when running component tests for your project. To enable coverage, check the coverage checkbox in the testing widget.\n\n![Screenshot of testing widget, expanded, showing coverage toggle](../_assets/writing-tests/test-widget-coverage-enabled.png)\n\nBefore coverage can be calculated, you may need to install a support package corresponding to your [coverage provider](#coverage-provider):\n\n<CodeSnippets path=\"vitest-plugin-install-coverage-support-packages.md\" />\n\n## Usage\n\nBecause coverage is built into the Vitest addon, you can use it everywhere you run your tests.\n\n### Storybook UI\n\nWhen you enable coverage in the Storybook UI, the coverage report will be generated and summarized in the testing widget after you run your tests. You can see the percentage of statements covered by your tested stories, as well as whether the coverage meets the [watermarks](#watermarks).\n\nAdditionally, the full coverage report will be served at the `/coverage/index.html` route of your running Storybook.\n\n![Two browser windows. The frontmost one shows the interactive coverage report generated by the Vitest addon. The background one shows the Storybook sidebar with the coverage summary visible in the testing widget.](../_assets/writing-tests/coverage-summary-and-report.png)\n\nThe report is interactive. You can click through to a component to view its source and see which parts of your code are covered by tests or not:\n\n![Interactive coverage report generated by the Vitest addon, showing the Calendar component's reported source](../_assets/writing-tests/coverage-report-html-component.png)\n\n<Callout variant=\"info\" icon=\"⚠️\">\n\nIt's important to understand that the coverage reported in the Storybook UI has three important limitations:\n\n1. Coverage is calculated using the stories you've written, not the entire codebase. In other words, it will not include any other Vitest tests.\n2. Coverage can only be calculated for all stories in your project, not for an individual story or a group of stories.\n3. Coverage is not calculated while watch mode is activated. When coverage is enabled, enabling watch mode will disable coverage.\n\n</Callout>\n\n### CLI\n\nLike the rest of Storybook Test, coverage is built on top of Vitest. Which means you can generate a coverage report using the [Vitest CLI](https://vitest.dev/guide/cli.html).\n\nAssuming you run your tests with a package script like this:\n\n```json title=\"package.json\"\n{\n  \"scripts\": {\n    \"test-storybook\": \"vitest --project=storybook\"\n  }\n}\n```\n\nThen you can generate a coverage report with:\n\n<CodeSnippets path=\"vitest-plugin-run-with-coverage.md\" />\n\n![Generated coverage report in terminal](../_assets/writing-tests/coverage-report-cli.png)\n\nThe coverage report will be saved to the [configured coverage reports directory](https://vitest.dev/config/#coverage-reportsdirectory) (`./coverage`, by default) in your project.\n\n<Callout variant=\"info\">\n\nThe above command will only calculate coverage for the stories you've written, not the entire codebase.\n\nBecause coverage is most accurate when accounting for all tests in your project, you can also run coverage for all tests in your project with:\n\n```sh\nnpx vitest --coverage\n```\n\n</Callout>\n\n### Editor extension\n\nCoverage is also available through Vitest's [IDE integrations](https://vitest.dev/guide/ide.html). You can calculate and display coverage results directly in your editor.\n\n![Screenshot of test coverage in VSCode](../_assets/writing-tests/vitest-plugin-vscode-coverage.png)\n\n<Callout variant=\"info\">\n\nNote that this coverage will include *all* tests in your project, not just the stories you've written.\n\n</Callout>\n\n### CI\n\nTo generate coverage reports in your CI pipeline, you can use the [CLI](#cli).\n\nFor example, here's a simplified GitHub Actions workflow that runs your tests and generates a coverage report:\n\n```yaml title=\".github/workflows/test-storybook.yml\"\nname: Storybook Tests\non: push\njobs:\n  test:\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-node@v4\n        with:\n          node-version: '20.x'\n      - name: Install dependencies\n        run: yarn\n        # 👇 This will run all Vitest tests, including Storybook tests\n      - name: Run tests\n        run: yarn test --coverage\n```\n\n<Callout variant=\"info\" icon=\"💡\">\n\nWhy are we running all tests (`yarn test`) instead of just the Storybook tests (`yarn test-storybook`)? Because a coverage report is most accurate when accounting for all tests in your project, not just the stories you've written.\n\nSeeing [Storybook-specific coverage](#storybook-ui) can be helpful, but in CI output, you want to see the comprehensive coverage of your project.\n\n</Callout>\n\nFor more on testing in CI, see the [dedicated guide](./in-ci.mdx).\n\n## Configuration\n\n### Coverage provider\n\nYou can choose which provider, [v8](https://v8.dev/blog/javascript-code-coverage) (default) or [Istanbul](https://istanbul.js.org/), to use for coverage calculation by setting the `coverage.provider` option in your Vitest config:\n\n```ts title=\"vitest.config.ts\"\nimport { defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n  // ...\n  test: {\n    // ...\n    coverage: {\n      // ...\n      provider: 'istanbul', // 'v8' is the default\n    },\n  },\n});\n```\n\n### Watermarks\n\nBoth coverage providers support [watermarks](https://vitest.dev/config/#coverage-watermarks), which are threshold values for coverage. The low watermark is the minimum coverage required to pass the test, and the high watermark is the minimum coverage required to be considered good. A coverage percentage between the low and high watermarks will be considered acceptable but not ideal.\n\nIn the testing widget, the coverage summary will show the percentage of statements covered by your tested stories, as well as whether the coverage meets the watermarks. Below the low watermark, the icon will be red, between the low and high watermarks, it will be orange, and above the high watermark, it will be green.\n\n![Screenshot of testing widget, expanded, showing coverage result](../_assets/writing-tests/addon-test-module-coverage-summary.png)\n\nTo configure the watermarks, you can adjust the Vitest config:\n\n```ts title=\"vitest.config.ts\"\nimport { defineConfig } from 'vitest/config';\n \nexport default defineConfig({\n  // ...\n  test: {\n    // ...\n    coverage: {\n      // ...\n      watermarks: {\n        // These are the default values\n        statements: [50, 80],\n      },\n    },\n  },\n});\n```\n\n### Additional configuration\n\nYou can find more configuration options for coverage in the [Vitest documentation](https://vitest.dev/config/#coverage).\n\nWhen calculating coverage in the Storybook UI, the following options are always ignored:\n\n- `enabled`\n- `clean`\n- `cleanOnRerun`\n- `reportOnFailure`\n- `reporter`\n- `reportsDirectory`\n\n**More testing resources**\n\n* [Vitest addon](./integrations/vitest-addon/index.mdx) for running tests in Storybook\n* [Interaction testing](./interaction-testing.mdx) for user behavior simulation\n* [Accessibility testing](./accessibility-testing.mdx) for accessibility\n* [Visual testing](./visual-testing.mdx) for appearance\n* [Snapshot testing](./snapshot-testing.mdx) for rendering errors and warnings\n* [CI](./in-ci.mdx) for running tests in your CI/CD pipeline\n* [End-to-end testing](./integrations/stories-in-end-to-end-tests.mdx) for simulating real user scenarios\n* [Unit testing](./integrations/stories-in-unit-tests.mdx) for functionality\n* [Test runner](./integrations/test-runner.mdx) to automate test execution\n"
  },
  {
    "path": "docs/writing-tests/visual-testing.mdx",
    "content": "---\ntitle: Visual tests\nhideRendererSelector: true\nsidebar:\n  order: 4\n  title: Visual tests\n---\n\nVisual tests are the most efficient way to test your components. With the click of a button you can take snapshots of every story in your Storybook and compare those snapshots to baselines — last known “good” snapshots. Not only does this allow you to check the appearance of your components, but they are also able to check a large subset of component functionality [without having to write or maintain any test code](https://storybook.js.org/blog/visual-testing-is-the-greatest-trick-in-ui-development/)!\n\nStorybook supports cross-browser visual testing natively using [Chromatic](https://www.chromatic.com/storybook/?ref=storybook_site), a cloud service made by the Storybook team. When you enable visual testing, every story is automatically turned into a test. This gives you instant feedback on UI bugs directly in Storybook.\n\n<Video src=\"../_assets/writing-tests/component-visual-testing-optimized.mp4\" />\n\n## Install the addon\n\nAdd visual tests to your project by installing `@chromatic-com/storybook`, the official addon by Storybook maintainers:\n\n<CodeSnippets path=\"chromatic-storybook-add.md\" />\n\n## Enable visual tests\n\nWhen you start Storybook, you'll see a new addon panel for Visual Tests where you can run tests and view results.\n\n![Visual Tests addon enabled](../_assets/writing-tests/vta-enable.png)\n\n<Callout variant=\"info\">\n\nAlready using the [Vitest addon](./integrations/vitest-addon/index.mdx)? In the expanded testing widget, you’ll now see a Visual tests section:\n\n![Expanded testing widget, showing the Visual tests section](../_assets/writing-tests/test-widget-expanded-with-vta.png)\n\nClicking the Run tests button at the bottom will run *all* tests, both component and visual.\n\n</Callout>\n\nFirst, sign in to your Chromatic account. If you do not have an account, you can create one as part of the sign in process.\n\nOnce signed in, you will see your Chromatic account(s) and their projects. Either select one from the list or create a new one.\n\n![Visual Tests addon project selection](../_assets/writing-tests/vta-select-project.png)\n\nNow that you have linked your project to the addon, you can press the “Catch a UI change” button to run your first build of visual tests.\n\n![Visual test panel showing the Catch a UI change button](../_assets/writing-tests/vta-project-linked.png)\n\nThat first build will create the baseline snapshots for your stories, which will be compared against when you run visual tests again.\n\n## Run visual tests\n\nAfter you have made a code change, there are two ways to run visual tests in Storybook.\n\nIn the expanded testing widget in the sidebar, press the run button in the Visual tests section.\n\n![Test widget showing the Run visual tests button](../_assets/writing-tests/test-widget-expanded-with-vta.png)\n\nOr, in the Visual tests addon panel, press the run button in the top right corner of the panel.\n\n![Visual tests addon panel showing the Run visual tests button](../_assets/writing-tests/vta-run-from-panel.png)\n\nEither method will send your stories to the cloud to take snapshots and detect visual changes.\n\n## Review changes\n\nIf there are visual changes in your stories, they will be 🟡 highlighted in the sidebar. Click the story and go to the Visual Tests addon panel to see which pixels changed.\n\nIf the changes are intentional, ✅ accept them as baselines locally. If the changes aren't intentional, fix the story and rerun the tests using the rerun button.\n\n![Visual test panel with diff](../_assets/writing-tests/vta-changes-found.png)\n\nWhen you finish accepting changes as baselines in the addon, you're ready to push the code to your remote repository. This will sync baselines to the cloud for anyone who checks out your branch.\n\n![Visual test panel with accepted baselines](../_assets/writing-tests/vta-changes-accepted.png)\n\n## Automate with CI\n\nThe addon is designed to be used in tandem with CI. We recommend using the addon to check for changes during development and then running visual tests in CI as you get ready to merge.\n\nChanges you accept as baselines in the addon will get auto-accepted as baselines in CI so you don’t have to review twice.\n\n1. Add a step to your CI workflow to run Chromatic.\n   - [GitHub Actions](https://chromatic.com/docs/github-actions?ref=storybook_docs)\n   - [GitLab Pipelines](https://chromatic.com/docs/gitlab?ref=storybook_docs)\n   - [Bitbucket Pipelines](https://chromatic.com/docs/bitbucket-pipelines?ref=storybook_docs)\n   - [CircleCI](https://chromatic.com/docs/circleci?ref=storybook_docs)\n   - [Travis CI](https://chromatic.com/docs/travisci?ref=storybook_docs)\n   - [Jenkins](https://chromatic.com/docs/jenkins?ref=storybook_docs)\n   - [Azure Pipelines](https://chromatic.com/docs/azure-pipelines?ref=storybook_docs)\n   - [Custom CI provider](https://chromatic.com/docs/custom-ci-provider?ref=storybook_docs)\n2. Configure your CI to include environment variables to authenticate with Chromatic (project token).\n\n## PR checks\n\nOnce you successfully set up Chromatic in CI, your pull/merge requests will be badged with a UI Tests check. The badge notifies you of test errors or UI changes that need to be verified by your team. Make the check required in your Git provider to prevent accidental UI bugs from being merged.\n\n![](../_assets/writing-tests/vta-prbadge-test.png)\n\n## Configure\n\nThe addon includes configuration options covering most use cases by default. You can also fine-tune the addon configuration to match your project's requirements via the [`./chromatic.config.json`](https://www.chromatic.com/docs/visual-tests-addon/#configure) file. Below is a shortlist of addon-specific options and examples of how to use them. View the full list of [options](https://www.chromatic.com/docs/configure/#options).\n\n| Option            | Description                                                                                                                            |\n| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------- |\n| `projectId`       | Automatically configured. Sets the value for the project identifier<br />`\"projectId\": \"Project:64cbcde96f99841e8b007d75\"`             |\n| `buildScriptName` | Optional. Defines the custom Storybook build script<br />`\"buildScriptName\": \"deploy-storybook\"`                                       |\n| `debug`           | Optional. Output verbose debugging information to the console.<br />`\"debug\": true`                                                    |\n| `zip`             | Optional. Recommended for large projects. Configures the addon to deploy your Storybook to Chromatic as a zip file.<br />`\"zip\": true` |\n\n```json title=\"./chromatic.config.json\"\n{\n  \"buildScriptName\": \"deploy-storybook\",\n  \"debug\": true,\n  \"projectId\": \"Project:64cbcde96f99841e8b007d75\",\n  \"zip\": true\n}\n```\n\n## FAQs\n\n### What’s the difference between visual tests and snapshot tests?\n\n[Snapshot tests](./snapshot-testing.mdx) compare the rendered markup of every story against known baselines. This means the test compares blobs of HTML and not what the user actually sees. Which in turn, can lead to an increase in false positives as code changes don’t always yield visual changes in the component.\n\nVisual tests compare the rendered pixels of every story against known baselines. Because you're testing the same thing your users actually experience, your tests will be richer and easier to maintain.\n\n**More testing resources**\n\n* [Vitest addon](./integrations/vitest-addon/index.mdx) for running tests in Storybook\n* [Interaction testing](./interaction-testing.mdx) for user behavior simulation\n* [Accessibility testing](./accessibility-testing.mdx) for accessibility\n* [Snapshot testing](./snapshot-testing.mdx) for rendering errors and warnings\n* [Test coverage](./test-coverage.mdx) for measuring code coverage\n* [CI](./in-ci.mdx) for running tests in your CI/CD pipeline\n* [End-to-end testing](./integrations/stories-in-end-to-end-tests.mdx) for simulating real user scenarios\n* [Unit testing](./integrations/stories-in-unit-tests.mdx) for functionality\n* [Test runner](./integrations/test-runner.mdx) to automate test execution\n"
  },
  {
    "path": "nx.json",
    "content": "{\n  \"$schema\": \"./node_modules/nx/schemas/workspace-schema.json\",\n  \"nxCloudId\": \"6929fbef73e98d8094d2a343\",\n  \"defaultBase\": \"next\",\n  \"parallel\": 8,\n  \"pluginsConfig\": {\n    \"@nx/js\": {\n      \"analyzeSourceFiles\": false\n    }\n  },\n  \"defaultProject\": \"react-vite/default-ts\",\n  \"useInferencePlugins\": false,\n  \"tasksRunnerOptions\": {\n    \"default\": {\n      \"options\": {\n        \"canTrackAnalytics\": false,\n        \"showUsageWarnings\": true\n      }\n    }\n  },\n  \"tui\": {\n    \"autoExit\": true\n  },\n  \"targetDefaults\": {\n    \"compile\": {\n      \"dependsOn\": [\"^compile\"],\n      \"command\": \"yarn exec jiti ./scripts/build/build-package.ts --cwd {projectRoot}\",\n      \"configurations\": { \"production\": { \"args\": \"--prod\" } },\n      \"cache\": true,\n      \"inputs\": [\"production\", \"^production\"],\n      \"outputs\": [\n        \"{projectRoot}/dist\",\n        \"{workspaceRoot}/code/bench/esbuild-metafiles/{projectName}\"\n      ]\n    },\n    \"check\": {\n      \"dependsOn\": [{ \"projects\": [\"*\"], \"target\": \"compile\" }],\n      \"command\": \"yarn exec jiti ./scripts/check/check-package.ts --cwd {projectRoot}\",\n      \"cache\": true,\n      \"inputs\": [\"default\", \"^production\"],\n      \"configurations\": { \"production\": {} }\n    },\n    \"publish\": {\n      \"dependsOn\": [{ \"projects\": [\"*\"], \"target\": \"compile\" }],\n      \"command\": \"yarn workspace @storybook/scripts local-registry --publish\",\n      \"cache\": true,\n      \"inputs\": [\"all-production\"],\n      \"outputs\": [\"{workspaceRoot}/.verdaccio-cache\"],\n      \"configurations\": { \"production\": {} }\n    },\n    \"run-registry\": {\n      \"dependsOn\": [{ \"projects\": [\"scripts\"], \"target\": \"publish\" }],\n      \"command\": \"yarn workspace @storybook/scripts local-registry --open\",\n      \"continuous\": true,\n      \"configurations\": { \"production\": {} }\n    },\n    \"sandbox\": {\n      \"dependsOn\": [{ \"projects\": [\"scripts\"], \"target\": \"run-registry\" }],\n      \"command\": \"yarn task sandbox -s task --debug --no-link --template={projectName}\",\n      \"cache\": true,\n      \"inputs\": [\"^production\"],\n      \"outputs\": [\"{workspaceRoot}/sandbox/{options.dir}\"],\n      \"configurations\": { \"production\": {} }\n    },\n    \"check-sandbox\": {\n      \"dependsOn\": [\"sandbox\", { \"projects\": [\"scripts\"], \"target\": \"run-registry\" }],\n      \"command\": \"yarn task check-sandbox -s task --debug --no-link --template={projectName}\",\n      \"cache\": true,\n      \"inputs\": [\"^production\"],\n      \"configurations\": { \"production\": {} }\n    },\n    \"build\": {\n      \"dependsOn\": [\"sandbox\", { \"projects\": [\"scripts\"], \"target\": \"run-registry\" }],\n      \"command\": \"yarn task build -s task --debug --no-link --template={projectName}\",\n      \"cache\": true,\n      \"inputs\": [\"^production\"],\n      \"outputs\": [\"{workspaceRoot}/sandbox/{options.dir}/storybook-static\"],\n      \"configurations\": { \"production\": {} }\n    },\n    \"dev\": {\n      \"dependsOn\": [\"sandbox\", { \"projects\": [\"scripts\"], \"target\": \"run-registry\" }],\n      \"command\": \"yarn task dev -s task --debug --no-link --template={projectName}\",\n      \"continuous\": true,\n      \"configurations\": { \"production\": {} }\n    },\n    \"vitest-integration\": {\n      \"dependsOn\": [\"sandbox\", { \"projects\": [\"scripts\"], \"target\": \"run-registry\" }],\n      \"command\": \"yarn task vitest-integration -s task --debug --no-link --template={projectName}\",\n      \"cache\": true,\n      \"inputs\": [\"^production\"],\n      \"configurations\": { \"production\": {} }\n    },\n    \"chromatic\": {\n      \"dependsOn\": [\"build\", { \"projects\": [\"scripts\"], \"target\": \"run-registry\" }],\n      \"command\": \"yarn task chromatic -s task --debug --no-link --template={projectName}\",\n      \"cache\": true,\n      \"inputs\": [\"^production\"],\n      \"configurations\": { \"production\": {} }\n    },\n    \"serve\": {\n      \"dependsOn\": [\"build\", { \"projects\": [\"scripts\"], \"target\": \"run-registry\" }],\n      \"command\": \"yarn task serve -s task --debug --no-link --template={projectName}\",\n      \"continuous\": true,\n      \"configurations\": { \"production\": {} }\n    },\n    \"e2e-tests\": {\n      \"dependsOn\": [\"serve\"],\n      \"command\": \"yarn task e2e-tests --junit -s task --debug --no-link --template={projectName}\",\n      \"cache\": true,\n      \"inputs\": [\"^production\"],\n      \"outputs\": [\"{workspaceRoot}/test-results\", \"{workspaceRoot}/code/playwright-results\"],\n      \"configurations\": { \"production\": {} }\n    },\n    \"test-runner\": {\n      \"dependsOn\": [\"serve\"],\n      \"command\": \"yarn task test-runner --junit -s task --debug --no-link --template={projectName}\",\n      \"cache\": true,\n      \"inputs\": [\"^production\"],\n      \"outputs\": [\"{workspaceRoot}/test-results\", \"{workspaceRoot}/code/playwright-results\"],\n      \"configurations\": { \"production\": {} }\n    },\n    \"e2e-tests-dev\": {\n      \"dependsOn\": [\"dev\"],\n      \"command\": \"yarn task e2e-tests-dev --junit -s task --debug --no-link --template={projectName}\",\n      \"cache\": true,\n      \"inputs\": [\"^production\"],\n      \"outputs\": [\"{workspaceRoot}/test-results\", \"{workspaceRoot}/code/playwright-results\"],\n      \"configurations\": { \"production\": {} }\n    },\n    \"test-runner-dev\": {\n      \"dependsOn\": [\"dev\"],\n      \"command\": \"yarn task test-runner-dev --junit -s task --debug --no-link --template={projectName}\",\n      \"cache\": true,\n      \"inputs\": [\"^production\"],\n      \"outputs\": [\"{workspaceRoot}/test-results\", \"{workspaceRoot}/code/playwright-results\"],\n      \"configurations\": { \"production\": {} }\n    },\n\n    \"e2e-ui\": {\n      \"dependsOn\": [{ \"projects\": [\"*\"], \"target\": \"compile\" }],\n      \"executor\": \"nx:run-commands\",\n      \"options\": {\n        \"cwd\": \"{projectRoot}\",\n        \"command\": \"yarn --no-immutable && yarn playwright-e2e\"\n      },\n      \"cache\": true,\n      \"inputs\": [\"default\", \"^production\"],\n      \"outputs\": [\"{workspaceRoot}/test-results\", \"{workspaceRoot}/code/playwright-results\"],\n      \"configurations\": { \"production\": {} }\n    },\n    \"jest\": {\n      \"dependsOn\": [{ \"projects\": [\"*\"], \"target\": \"compile\" }],\n      \"executor\": \"nx:run-commands\",\n      \"options\": { \"cwd\": \"{projectRoot}\", \"command\": \"yarn --no-immutable && yarn jest\" },\n      \"cache\": true,\n      \"inputs\": [\"default\", \"^production\"],\n      \"outputs\": [\"{workspaceRoot}/test-results\"],\n      \"configurations\": { \"production\": {} }\n    },\n    \"vitest\": {\n      \"dependsOn\": [{ \"projects\": [\"*\"], \"target\": \"compile\" }],\n      \"executor\": \"nx:run-commands\",\n      \"options\": { \"cwd\": \"{projectRoot}\", \"command\": \"yarn --no-immutable && yarn vitest\" },\n      \"cache\": true,\n      \"inputs\": [\"default\", \"^production\"],\n      \"outputs\": [\"{workspaceRoot}/test-results\"],\n      \"configurations\": { \"production\": {} }\n    },\n    \"playwright-ct\": {\n      \"dependsOn\": [{ \"projects\": [\"*\"], \"target\": \"compile\" }],\n      \"executor\": \"nx:run-commands\",\n      \"options\": { \"cwd\": \"{projectRoot}\", \"command\": \"yarn --no-immutable && yarn playwright-ct\" },\n      \"cache\": true,\n      \"inputs\": [\"default\", \"^production\"],\n      \"outputs\": [\"{workspaceRoot}/test-results\", \"{workspaceRoot}/code/playwright-results\"],\n      \"configurations\": { \"production\": {} }\n    },\n    \"cypress\": {\n      \"dependsOn\": [{ \"projects\": [\"*\"], \"target\": \"compile\" }],\n      \"executor\": \"nx:run-commands\",\n      \"options\": { \"cwd\": \"{projectRoot}\", \"command\": \"yarn --no-immutable && yarn cypress\" },\n      \"cache\": true,\n      \"inputs\": [\"default\", \"^production\"],\n      \"outputs\": [\"{workspaceRoot}/test-results\"],\n      \"configurations\": { \"production\": {} }\n    }\n  },\n  \"namedInputs\": {\n    \"sharedGlobals\": [\n      \"{workspaceRoot}/code/tsconfig.json\",\n      \"{workspaceRoot}/scripts/**/*\",\n      \"{workspaceRoot}/.github/workflows/nx.yml\",\n      \"{workspaceRoot}/.nx/workflows/*\"\n    ],\n    \"default\": [\"sharedGlobals\", \"{projectRoot}/**/*\"],\n    \"production\": [\n      \"sharedGlobals\",\n      \"{projectRoot}/**/*\",\n      \"!{projectRoot}/src/**/*.{test,spec,stories}.?(c|m)[jt]s?(x)?(.snap)\"\n    ],\n    \"all-production\": [\n      \"sharedGlobals\",\n      \"{workspaceRoot}/code/**/*\",\n      \"!{workspaceRoot}/code/**/*.{test,spec,stories}.?(c|m)[jt]s?(x)?(.snap)\"\n    ]\n  },\n  \"analytics\": false,\n  \"codexCacheBust\": \"2026-03-23T12:57:22Z\"\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@storybook/root\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"workspaces\": {\n    \"packages\": [\n      \"code\",\n      \"code/addons/*\",\n      \"code/builders/*\",\n      \"code/core\",\n      \"code/frameworks/*\",\n      \"code/lib/*\",\n      \"code/presets/*\",\n      \"code/renderers/*\",\n      \"scripts\"\n    ]\n  },\n  \"scripts\": {\n    \"ci-tests\": \"cd code; yarn ci-tests\",\n    \"fmt:check\": \"oxfmt --check .\",\n    \"fmt:write\": \"oxfmt .\",\n    \"get-report-message\": \"cd scripts; yarn get-report-message\",\n    \"get-sandbox-dir\": \"cd scripts; yarn get-sandbox-dir\",\n    \"i\": \"yarn\",\n    \"postinstall\": \"husky\",\n    \"knip\": \"cd code; yarn knip\",\n    \"lint\": \"cd code; yarn lint\",\n    \"nx\": \"nx\",\n    \"start\": \"yarn task --task dev --template react-vite/default-ts --start-from=install\",\n    \"storybook:vitest\": \"NODE_OPTIONS=--max_old_space_size=4096 vitest watch --project storybook-ui\",\n    \"storybook:vitest:inspect\": \"INSPECT=true NODE_OPTIONS=--max_old_space_size=4096 vitest run --project storybook-ui\",\n    \"svelte-ecosystem-ci:before-test\": \"./scripts/ecosystem-ci/before-test.sh svelte-kit/skeleton-ts\",\n    \"svelte-ecosystem-ci:build\": \"./scripts/ecosystem-ci/build.sh svelte-kit/skeleton-ts svelte\",\n    \"svelte-ecosystem-ci:test\": \"./scripts/ecosystem-ci/test.sh svelte-kit/skeleton-ts\",\n    \"task\": \"yarn --cwd=./scripts task\",\n    \"test\": \"NODE_OPTIONS=--max_old_space_size=4096 vitest run\",\n    \"test:watch\": \"NODE_OPTIONS=--max_old_space_size=4096 vitest watch\",\n    \"upload-bench\": \"cd scripts; yarn upload-bench\",\n    \"vite-ecosystem-ci:before-test\": \"./scripts/ecosystem-ci/before-test.sh react-vite/default-ts\",\n    \"vite-ecosystem-ci:build\": \"./scripts/ecosystem-ci/build.sh react-vite/default-ts\",\n    \"vite-ecosystem-ci:test\": \"./scripts/ecosystem-ci/test.sh react-vite/default-ts\"\n  },\n  \"resolutions\": {\n    \"@babel/runtime\": \"latest\",\n    \"@babel/traverse\": \"latest\",\n    \"@babel/types\": \"^7.28.4\",\n    \"@playwright/test\": \"1.58.2\",\n    \"@testing-library/user-event@npm:^14.4.0\": \"patch:@testing-library/user-event@npm%3A14.6.1#~/.yarn/patches/@testing-library-user-event-npm-14.6.1-5da7e1d4e2.patch\",\n    \"@testing-library/user-event@npm:^14.6.1\": \"patch:@testing-library/user-event@npm%3A14.6.1#~/.yarn/patches/@testing-library-user-event-npm-14.6.1-5da7e1d4e2.patch\",\n    \"@types/babel__traverse@npm:*\": \"patch:@types/babel__traverse@npm%3A7.20.6#~/.yarn/patches/@types-babel__traverse-npm-7.20.6-fac4243243.patch\",\n    \"@types/babel__traverse@npm:^7.18.0\": \"patch:@types/babel__traverse@npm%3A7.20.6#~/.yarn/patches/@types-babel__traverse-npm-7.20.6-fac4243243.patch\",\n    \"@types/node\": \"^22.19.1\",\n    \"@types/react\": \"^18.0.0\",\n    \"@vitest/expect@npm:3.2.4\": \"patch:@vitest/expect@npm%3A3.2.4#~/.yarn/patches/@vitest-expect-npm-3.2.4-97c526d5cc.patch\",\n    \"aria-query@5.3.0\": \"^5.3.0\",\n    \"esbuild\": \"^0.27.0\",\n    \"playwright\": \"1.58.2\",\n    \"playwright-core\": \"1.58.2\",\n    \"react\": \"^18.2.0\",\n    \"type-fest\": \"~2.19\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"devDependencies\": {\n    \"@nx/workspace\": \"^22.6.1\",\n    \"@playwright/test\": \"^1.58.2\",\n    \"@types/kill-port\": \"^2.0.3\",\n    \"http-server\": \"^14.1.1\",\n    \"husky\": \"^9.1.7\",\n    \"jiti\": \"^2.6.1\",\n    \"kill-port\": \"^2.0.1\",\n    \"lint-staged\": \"^16.4.0\",\n    \"nx\": \"^22.6.1\",\n    \"oxfmt\": \"^0.41.0\",\n    \"std-env\": \"^4.0.0\",\n    \"vite\": \"^7.0.4\",\n    \"vitest\": \"^4.1.0\"\n  },\n  \"packageManager\": \"yarn@4.10.3\"\n}\n"
  },
  {
    "path": "scripts/.babelrc.cjs",
    "content": "module.exports = {\n  compact: false,\n  presets: [\n    '@babel/preset-typescript',\n    '@babel/preset-react',\n    [\n      '@babel/preset-env',\n      {\n        shippedProposals: true,\n        useBuiltIns: 'usage',\n        corejs: '3',\n        targets: { node: '22' },\n      },\n    ],\n  ],\n};\n"
  },
  {
    "path": "scripts/.eslintignore",
    "content": "dist\nlib/**/dll\nbuild\ncoverage\nnode_modules\ndocs/public\nstorybook-static\nbuilt-storybooks\nlib/cli/test\nlib/codemod/src/transforms/__testfixtures__\nscripts/storage\nscripts/repros-generator\n*.bundle.js\n*.js.map\n*.d.ts\nexamples/ember-cli/.storybook/preview-head.html\nember-output\n.yarn\n!.remarkrc.js\n!.babelrc.js\n!.eslintrc.js\n!.eslintrc-markdown.js\n!.jest.config.cjs\n!.storybook\n\n"
  },
  {
    "path": "scripts/.eslintrc.cjs",
    "content": "module.exports = {\n  root: true,\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:depend/recommended',\n    'plugin:eslint-comments/recommended',\n    'plugin:import-x/react-native',\n    'plugin:react-hooks/recommended',\n    'plugin:react/recommended',\n    'plugin:jsx-a11y/recommended',\n  ],\n  env: {\n    es6: true,\n    node: true,\n  },\n  parserOptions: {\n    tsconfigRootDir: __dirname,\n    project: ['./tsconfig.json'],\n    ecmaFeatures: {\n      jsx: true,\n    },\n    ecmaVersion: 8,\n    sourceType: 'module',\n    extraFileExtensions: ['.html', '.md', '.json', '.svg', '.tag'],\n  },\n  settings: {\n    react: {\n      version: 'detect',\n    },\n    'html/html-extensions': ['.html'],\n    'import-x/core-modules': ['enzyme'],\n    'import-x/ignore': ['node_modules\\\\/(?!@storybook)'],\n    'import-x/resolver': {\n      node: {\n        extensions: ['.js', '.ts', '.tsx', '.mjs', '.d.ts'],\n        paths: ['node_modules/', 'node_modules/@types/'],\n      },\n    },\n  },\n  plugins: [\n    'local-rules',\n    'compat',\n    'file-progress',\n    '@typescript-eslint',\n    'import-x',\n    'json',\n    'html',\n  ],\n  rules: {\n    'react/no-unescaped-entities': 'off',\n    'no-unused-vars': 'off',\n    // TODO: Storybook 10 - When we do the ESM migration we must turn this rule on\n    '@typescript-eslint/no-require-imports': 'off',\n    '@typescript-eslint/no-implied-eval': 'error',\n    '@typescript-eslint/no-explicit-any': 'warn',\n    '@typescript-eslint/no-wrapper-object-types': 'warn',\n    '@typescript-eslint/no-empty-object-type': 'warn',\n    '@typescript-eslint/ban-ts-comment': 'error',\n    '@typescript-eslint/no-unused-vars': 'warn',\n    '@typescript-eslint/no-redeclare': 'off',\n    '@typescript-eslint/no-unsafe-function-type': 'warn',\n    '@typescript-eslint/consistent-type-imports': ['error', { disallowTypeAnnotations: false }],\n    'no-use-before-define': 'off',\n    'eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }],\n    'depend/ban-dependencies': [\n      'error',\n      {\n        modules: ['lodash', 'lodash-es', 'chalk', 'qs', 'handlebars', 'fs-extra'],\n      },\n    ],\n  },\n  overrides: [\n    {\n      files: ['*.html'],\n      rules: {\n        'no-underscore-dangle': 'off',\n        '@typescript-eslint/no-unused-vars': 'off',\n      },\n    },\n    {\n      files: ['*.mjs'],\n      rules: {\n        'import-x/extensions': ['error', 'always'],\n      },\n    },\n    {\n      files: ['*.js', '*.jsx', '*.json', '*.html', '**/.storybook/*.ts', '**/.storybook/*.tsx'],\n      parserOptions: {\n        project: null,\n      },\n      rules: {\n        // '@typescript-eslint/no-var-requires': 'off',\n        '@typescript-eslint/dot-notation': 'off',\n        '@typescript-eslint/no-implied-eval': 'off',\n        '@typescript-eslint/return-await': 'off',\n      },\n    },\n    {\n      files: ['*.ts', '*.tsx', '**/*.ts', '**/*.tsx'],\n      excludedFiles: [\n        '**/*.d.ts',\n        '**/docs/**/*',\n        '**/template/**/*',\n        '**/templates/**/*',\n        '**/__testfixtures__/**/*',\n        '**/__mocks-ng-workspace__/**/*',\n      ],\n      rules: {\n        'import-x/extensions': [\n          'error',\n          'always',\n          {\n            ignorePackages: true,\n            checkTypeImports: true,\n            fix: true,\n            pathGroupOverrides: [\n              { pattern: 'storybook/**', action: 'ignore' },\n              { pattern: '@storybook/**', action: 'ignore' },\n            ],\n          },\n        ],\n      },\n    },\n  ],\n};\n"
  },
  {
    "path": "scripts/__mocks__/simple-git.ts",
    "content": "import { vi } from 'vitest';\n\nexport const __getRemotes = vi\n  .fn()\n  .mockReturnValue([{ name: 'origin', refs: { fetch: 'origin', push: 'origin' } }]);\nexport const __fetch = vi.fn();\nexport const __revparse = vi.fn().mockResolvedValue('mockedGitCommitHash');\n\nexport const simpleGit = () => {\n  return {\n    getRemotes: __getRemotes,\n    fetch: __fetch,\n    revparse: __revparse,\n    log: vi.fn(),\n  };\n};\n"
  },
  {
    "path": "scripts/__mocks__/uuid.ts",
    "content": "import { v5 } from 'uuid';\n\nlet seed = 0;\n\nexport const v4 = () => {\n  seed += 1;\n  return v5(seed.toString(), '6c7fda6d-f92f-4bd2-9d4d-da26a59196a6');\n};\n"
  },
  {
    "path": "scripts/bench/bench-packages.ts",
    "content": "import path from 'node:path';\n\nimport { BigQuery } from '@google-cloud/bigquery';\nimport { InvalidArgumentError, program } from 'commander';\nimport detectFreePort from 'detect-port';\nimport { mkdir, readdir, rm, stat, writeFile } from 'fs/promises';\nimport pLimit from 'p-limit';\nimport picocolors from 'picocolors';\nimport { x } from 'tinyexec';\nimport { dedent } from 'ts-dedent';\n\nimport versions from '../../code/core/src/common/versions.ts';\nimport { maxConcurrentTasks } from '../utils/concurrency.ts';\nimport { esMain } from '../utils/esmain.ts';\nimport { safeMetafileArg } from './safe-args.ts';\n\nconst METAFILES_DIR = path.join(__dirname, '..', '..', 'code', 'bench', 'esbuild-metafiles');\n/**\n * Returns a map of package names to their metafile arguments, that will be used in the bench story.\n *\n * This is based on the metafiles and their paths in the metafile directory\n */\nasync function getMetafileArgsByPackage() {\n  const result: Record<string, string[]> = {};\n  async function walk(dir: string, rel: string) {\n    const entries = await readdir(dir, { withFileTypes: true });\n    const subdirs = entries.filter((e) => e.isDirectory());\n    if (subdirs.length === 0) {\n      // Leaf dir\n      const files = entries\n        .filter((e) => e.isFile() && e.name.endsWith('.json'))\n        .map((e) => e.name);\n      if (files.length > 0) {\n        result[rel] = files.map((file) => safeMetafileArg(path.join(dir, file)));\n      }\n    } else {\n      for (const sub of subdirs) {\n        await walk(path.join(dir, sub.name), path.join(rel, sub.name));\n      }\n    }\n  }\n  await walk(METAFILES_DIR, '');\n  return result;\n}\n\nconst Thresholds = {\n  SELF_SIZE_RATIO: 0.1,\n  SELF_SIZE_ABSOLUTE: 10_000,\n  DEPS_SIZE_RATIO: 0.1,\n  DEPS_SIZE_ABSOLUTE: 10_000,\n  DEPS_COUNT_ABSOLUTE: 1,\n} as const;\n\nconst BENCH_PACKAGES_PATH = path.join(__dirname, '..', '..', 'bench', 'packages');\nconst REGISTRY_PORT = 6001;\nconst GCP_CREDENTIALS = JSON.parse(process.env.GCP_CREDENTIALS || '{}');\nconst bigQueryBenchTable = new BigQuery({\n  projectId: GCP_CREDENTIALS.project_id,\n  credentials: GCP_CREDENTIALS,\n})\n  .dataset('benchmark_results')\n  .table('package_bench');\n\ntype PackageName = keyof typeof versions;\ntype Result = {\n  package: PackageName;\n  dependencyCount: number;\n  selfSize: number;\n  dependencySize: number;\n};\ntype ComparisonResult = {\n  package: PackageName;\n  dependencyCount: {\n    base: number;\n    new: number;\n    diff: number;\n  };\n  selfSize: {\n    base: number;\n    new: number;\n    diff: number;\n  };\n  dependencySize: {\n    base: number;\n    new: number;\n    diff: number;\n  };\n};\ntype ResultMap = Record<PackageName, Result>;\ntype ComparisonResultMap = Record<PackageName, ComparisonResult>;\n\n/**\n * This function benchmarks the size of Storybook packages and their dependencies. For each package,\n * the steps are:\n *\n * 1. Create a temporary directory in /bench/packages and create a package.json file that only depends\n *    on that one package\n * 2. Install the package and its dependencies, without peer dependencies\n * 3. Measure the size of the package and its dependencies, and count the number of dependencies\n *    (including transitive)\n * 4. Print and return the results\n */\nexport const benchPackage = async (packageName: PackageName) => {\n  console.log(`Benching ${picocolors.blue(packageName)}...`);\n  const tmpBenchPackagePath = path.join(BENCH_PACKAGES_PATH, packageName.replace('@storybook', ''));\n\n  await rm(tmpBenchPackagePath, { recursive: true }).catch(() => {});\n  await mkdir(tmpBenchPackagePath, { recursive: true });\n\n  await writeFile(\n    path.join(tmpBenchPackagePath, 'package.json'),\n    JSON.stringify(\n      {\n        name: `${packageName}-bench`,\n        version: '1.0.0',\n        dependencies: {\n          [packageName]: versions[packageName],\n        },\n        // Overrides ensures that Storybook packages outside the monorepo are using the versions we have in the monorepo\n        overrides: versions,\n      },\n      null,\n      2\n    )\n  );\n  const npmInstallResult = await x(\n    'npm',\n    // --force to ignore peer dependency warnings, we aren't installing peer dependencies anyway\n    `install --registry http://localhost:6001 --omit peer --json --force`.split(' '),\n    {\n      nodeOptions: { cwd: tmpBenchPackagePath },\n    }\n  );\n\n  const { added } = JSON.parse(npmInstallResult.stdout) as { added: number };\n  // -1 of reported packages added because we shouldn't count the actual package as a dependency\n  const dependencyCount = added - 1;\n\n  const getDirSize = async (dirPath: string) => {\n    const entities = await readdir(dirPath, {\n      recursive: true,\n      withFileTypes: true,\n    });\n    const stats = await Promise.all(\n      entities\n        .filter((entity) => entity.isFile())\n        .map((entity) => stat(path.join(entity.parentPath, entity.name)))\n    );\n    return stats.reduce((acc, { size }) => acc + size, 0);\n  };\n\n  const nodeModulesSize = await getDirSize(path.join(tmpBenchPackagePath, 'node_modules'));\n  const selfSize = await getDirSize(path.join(tmpBenchPackagePath, 'node_modules', packageName));\n  const dependencySize = nodeModulesSize - selfSize;\n\n  const result: Result = {\n    package: packageName,\n    dependencyCount,\n    selfSize,\n    dependencySize,\n  };\n  console.log(`Done benching ${picocolors.blue(packageName)}`);\n  return result;\n};\n\nconst toHumanReadable = (result: Partial<Result> | Partial<ComparisonResult>) => {\n  const formatBytes = (bytes: number, diff = false) => {\n    const units = ['B', 'KB', 'MB', 'GB', 'TB'];\n    let size = Math.abs(bytes);\n    let unitIndex = 0;\n\n    while (size >= 1000 && unitIndex < units.length - 1) {\n      size /= 1000;\n      unitIndex++;\n    }\n\n    // B, KB = 0 decimal places\n    // MB, GB, TB = 2 decimal places\n    const decimals = unitIndex < 2 ? 0 : 2;\n    const formattedSize = `${size.toFixed(decimals)} ${units[unitIndex]}`;\n\n    if (bytes < 0) {\n      return `-${formattedSize}`;\n    }\n    if (diff && bytes > 0) {\n      return `+${formattedSize}`;\n    }\n    return formattedSize;\n  };\n\n  if (typeof result.dependencyCount === 'number') {\n    const { dependencyCount, selfSize, dependencySize } = result as Result;\n    return {\n      package: result.package,\n      dependencyCount: dependencyCount.toString(),\n      selfSize: formatBytes(selfSize),\n      dependencySize: formatBytes(dependencySize),\n      totalSize: formatBytes(selfSize + dependencySize),\n    };\n  }\n  const { dependencyCount, selfSize, dependencySize } = result as ComparisonResult;\n\n  return {\n    package: result.package,\n    dependencyCount: {\n      base: dependencyCount.base.toString(),\n      new: dependencyCount.new.toString(),\n      diff: `${dependencyCount.diff > 0 ? '+' : dependencyCount.diff < 0 ? '-' : ''}${dependencyCount.diff}`,\n    },\n    selfSize: {\n      base: formatBytes(selfSize.base),\n      new: formatBytes(selfSize.new),\n      diff: formatBytes(selfSize.diff, true),\n    },\n    dependencySize: {\n      base: formatBytes(dependencySize.base),\n      new: formatBytes(dependencySize.new),\n      diff: formatBytes(dependencySize.diff, true),\n    },\n    totalSize: {\n      base: formatBytes(selfSize.base + dependencySize.base),\n      new: formatBytes(selfSize.new + dependencySize.new),\n      diff: formatBytes(selfSize.diff + dependencySize.diff, true),\n    },\n  };\n};\n\nconst saveLocally = async ({\n  results,\n  filename,\n}: {\n  results: Partial<ResultMap | ComparisonResultMap>;\n  filename: string;\n  diff?: boolean;\n}) => {\n  const resultPath = path.join(BENCH_PACKAGES_PATH, filename);\n  console.log(`Saving results to ${picocolors.magenta(resultPath)}...`);\n\n  const humanReadableResults = Object.entries(results).reduce(\n    (acc, [packageName, result]) => {\n      acc[packageName as PackageName] = toHumanReadable(result);\n      return acc;\n    },\n    {} as Record<PackageName, ReturnType<typeof toHumanReadable>>\n  );\n  await writeFile(resultPath, JSON.stringify(humanReadableResults, null, 2));\n};\n\nconst compareResults = async ({\n  results,\n  baseBranch,\n}: {\n  results: ResultMap;\n  baseBranch: string;\n}) => {\n  console.log(`Comparing results with base branch ${picocolors.magenta(baseBranch)}...`);\n  const [baseResults] = await bigQueryBenchTable.query({\n    query: `\n      WITH\n        latest_packages AS (\n        SELECT *,\n          ROW_NUMBER() OVER (PARTITION BY package ORDER BY benchmarkedAt DESC) AS row_number\n        FROM\n          \\`storybook-benchmark.benchmark_results.package_bench\\`\n        WHERE\n          branch = @baseBranch\n          AND package IN UNNEST(@packages)\n          AND benchmarkedAt > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 DAY) )\n      SELECT *\n      FROM latest_packages\n      WHERE row_number = 1;`,\n    params: { baseBranch, packages: Object.keys(results) },\n  });\n\n  const comparisonResults = {} as ComparisonResultMap;\n  for (const result of Object.values(results)) {\n    let baseResult = baseResults.find((row) => row.package === result.package);\n    if (!baseResult) {\n      console.warn(\n        `No base result found for ${picocolors.blue(result.package)}, comparing with zero values.`\n      );\n      baseResult = {\n        package: result.package,\n        dependencyCount: 0,\n        selfSize: 0,\n        dependencySize: 0,\n      };\n    }\n\n    comparisonResults[result.package] = {\n      package: result.package,\n      dependencyCount: {\n        base: baseResult.dependencyCount,\n        new: result.dependencyCount,\n        diff: result.dependencyCount - baseResult.dependencyCount,\n      },\n      selfSize: {\n        base: baseResult.selfSize,\n        new: result.selfSize,\n        diff: result.selfSize - baseResult.selfSize,\n      },\n      dependencySize: {\n        base: baseResult.dependencySize,\n        new: result.dependencySize,\n        diff: result.dependencySize - baseResult.dependencySize,\n      },\n    };\n  }\n  console.log(picocolors.green('Done comparing results'));\n  return comparisonResults;\n};\n\nconst filterResultsByThresholds = (comparisonResults: ComparisonResultMap) => {\n  const filteredResults: Partial<ComparisonResultMap> = {};\n  for (const comparisonResult of Object.values(comparisonResults)) {\n    const exceedsThresholds =\n      Math.abs(comparisonResult.selfSize.diff) > Thresholds.SELF_SIZE_ABSOLUTE ||\n      Math.abs(comparisonResult.selfSize.diff) / comparisonResult.selfSize.base >\n        Thresholds.SELF_SIZE_RATIO ||\n      Math.abs(comparisonResult.dependencySize.diff) > Thresholds.DEPS_SIZE_ABSOLUTE ||\n      Math.abs(comparisonResult.dependencySize.diff) / comparisonResult.dependencySize.base >\n        Thresholds.DEPS_SIZE_RATIO ||\n      Math.abs(comparisonResult.dependencyCount.diff) > Thresholds.DEPS_COUNT_ABSOLUTE;\n\n    if (exceedsThresholds) {\n      filteredResults[comparisonResult.package] = comparisonResult;\n    }\n  }\n\n  const amountAboveThreshold = Object.keys(filteredResults).length;\n  const color = amountAboveThreshold === 0 ? picocolors.green : picocolors.red;\n  console.log(color(`${amountAboveThreshold} packages exceeded the thresholds`));\n\n  return filteredResults;\n};\n\nconst uploadToBigQuery = async ({\n  results,\n  branch,\n  commit,\n  benchmarkedAt,\n}: {\n  results: ResultMap;\n  branch: string;\n  commit: string;\n  benchmarkedAt: Date;\n}) => {\n  console.log('Uploading results to BigQuery...');\n  const rows = Object.values(results).map((result) => ({\n    branch,\n    commit,\n    benchmarkedAt,\n    package: result.package,\n    selfSize: result.selfSize,\n    dependencySize: result.dependencySize,\n    dependencyCount: result.dependencyCount,\n  }));\n\n  await bigQueryBenchTable.insert(rows);\n};\n\nconst uploadToGithub = async ({\n  results,\n  headBranch,\n  baseBranch,\n  commit,\n  benchmarkedAt,\n  pullRequest,\n}: {\n  results: Partial<ComparisonResultMap>;\n  headBranch: string;\n  baseBranch: string;\n  commit: string;\n  benchmarkedAt: Date;\n  pullRequest: number;\n}) => {\n  console.log('Uploading results to GitHub...');\n\n  const metafilesArgsByPackage = await getMetafileArgsByPackage();\n\n  const response = await fetch('https://storybook-benchmark-bot.netlify.app/package-bench', {\n    method: 'POST',\n    body: JSON.stringify({\n      owner: 'storybookjs',\n      repo: 'storybook',\n      issueNumber: pullRequest,\n      headBranch,\n      baseBranch,\n      commit,\n      benchmarkedAt: benchmarkedAt.toISOString(),\n      results,\n      metafilesArgsByPackage,\n    }),\n  });\n  if (response.status < 200 || response.status >= 400) {\n    const body = await response.text();\n    throw new Error(`Failed to upload results to GitHub.\n      STATUS: ${response.status} - ${response.statusText}\n      BODY:\n      ${body}`);\n  }\n};\n\nconst run = async () => {\n  program\n    .option(\n      '-b, --base-branch [branchName]',\n      'The base branch to compare the results with. Requires GCP_CREDENTIALS env var'\n    )\n    .option(\n      '-p, --pull-request [pullRequestNumber]',\n      'The PR number to add compare results to. Only used together with --baseBranch',\n      function parsePrNumber(value) {\n        if (value === '0' || value === '') {\n          return null;\n        }\n        const parsedValue = Number.parseInt(value);\n        if (Number.isNaN(parsedValue)) {\n          throw new InvalidArgumentError('Must be a number');\n        }\n        return parsedValue;\n      }\n    )\n    .option('-u, --upload', 'Upload results to BigQuery. Requires GCP_CREDENTIALS env var')\n    .argument(\n      '[packages...]',\n      'which packages to bench. If omitted, all packages are benched',\n      function parsePackages(value) {\n        const parsedValue = value.split(' ');\n        parsedValue.forEach((packageName) => {\n          if (!Object.keys(versions).includes(packageName)) {\n            throw new InvalidArgumentError(`Package '${packageName}' not found in the monorepo`);\n          }\n        });\n        return parsedValue;\n      }\n    );\n  program.parse(process.argv);\n\n  const packageNames = (\n    program.args.length > 0\n      ? program.args\n      : Object.keys(versions)\n          // the sb package is never built, it doesn't have metafiles, it's unnecessary to benchmark it\n          .filter((pkg) => pkg !== 'sb')\n  ) as PackageName[];\n  const options = program.opts<{ pullRequest?: number; baseBranch?: string; upload?: boolean }>();\n\n  if (options.upload === true || typeof options.baseBranch === 'string') {\n    if (!GCP_CREDENTIALS.project_id) {\n      throw new Error(\n        'GCP_CREDENTIALS env var is required to upload to BigQuery or compare against a base branch'\n      );\n    }\n  }\n\n  if ((await detectFreePort(REGISTRY_PORT)) === REGISTRY_PORT) {\n    throw new Error(dedent`The local verdaccio registry must be running in the background for package benching to work,\n      and packages must be published to it in --no-link mode with 'yarn --task publish --no-link'\n      Then run the registry with 'yarn --task run-registry --no-link'`);\n  }\n\n  // The amount of VCPUs for this task in CI is 2 (medium resource)\n  const amountOfVCPUs = 2;\n  const concurrentLimit = process.env.CI ? amountOfVCPUs - 1 : maxConcurrentTasks;\n  const limit = pLimit(concurrentLimit);\n\n  const progressIntervalId = setInterval(() => {\n    const doneCount = packageNames.length - limit.activeCount - limit.pendingCount;\n    if (doneCount === packageNames.length) {\n      clearInterval(progressIntervalId);\n      return;\n    }\n    console.log(\n      `Benching status: ${picocolors.red(limit.pendingCount)} pending, ${picocolors.yellow(limit.activeCount)} running, ${picocolors.green(doneCount)} done...`\n    );\n  }, 2_000);\n  const resultsArray = await Promise.all(\n    packageNames.map((packageName) => limit(() => benchPackage(packageName)))\n  );\n  const results = resultsArray.reduce((acc, result) => {\n    acc[result.package] = result;\n    return acc;\n  }, {} as ResultMap);\n  await saveLocally({\n    filename: `results.json`,\n    results,\n  });\n\n  const headBranch =\n    process.env.CIRCLE_BRANCH ||\n    (await x('git', 'rev-parse --abbrev-ref HEAD'.split(' '))).stdout.trim();\n  const commit =\n    process.env.CIRCLE_SHA1 || (await x('git', 'rev-parse HEAD'.split(' '))).stdout.trim();\n  const benchmarkedAt = new Date();\n\n  if (options.upload) {\n    await uploadToBigQuery({ results, branch: headBranch, commit, benchmarkedAt });\n  }\n\n  if (options.baseBranch) {\n    const comparisonResults = await compareResults({ results, baseBranch: options.baseBranch });\n    const resultsAboveThreshold = filterResultsByThresholds(comparisonResults);\n    if (typeof options.pullRequest === 'number') {\n      await uploadToGithub({\n        results: resultsAboveThreshold,\n        pullRequest: options.pullRequest,\n        baseBranch: options.baseBranch,\n        headBranch,\n        commit,\n        benchmarkedAt,\n      });\n    }\n  }\n\n  console.log(picocolors.green('Done benching all packages'));\n};\n\nif (esMain(import.meta.url)) {\n  run().catch((err) => {\n    console.error(err);\n    process.exit(1);\n  });\n}\n"
  },
  {
    "path": "scripts/bench/bench.schema",
    "content": "branch: STRING,\ncommit: STRING,\ntimestamp: STRING,\nlabel: STRING,\ncreateTime: INTEGER,\ngenerateTime: INTEGER,\ninitTime: INTEGER,\ncreateSize: INTEGER,\ngenerateSize: INTEGER,\ninitSize: INTEGER,\ndiffSize: INTEGER,\nbuildTime: INTEGER,\nbuildSize: INTEGER,\nbuildSbAddonsSize: INTEGER,\nbuildSbCommonSize: INTEGER,\nbuildSbManagerSize: INTEGER,\nbuildSbPreviewSize: INTEGER,\nbuildStaticSize: INTEGER,\nbuildPrebuildSize: INTEGER,\nbuildPreviewSize: INTEGER,\ntestBuildTime: INTEGER,\ntestBuildSize: INTEGER,\ntestBuildSbAddonsSize: INTEGER,\ntestBuildSbCommonSize: INTEGER,\ntestBuildSbManagerSize: INTEGER,\ntestBuildSbPreviewSize: INTEGER,\ntestBuildStaticSize: INTEGER,\ntestBuildPrebuildSize: INTEGER,\ntestBuildPreviewSize: INTEGER,\ndevPreviewResponsive: INTEGER,\ndevManagerResponsive: INTEGER,\ndevManagerHeaderVisible: INTEGER,\ndevManagerIndexVisible: INTEGER,\ndevStoryVisible: INTEGER,\ndevStoryVisibleUncached: INTEGER,\ndevAutodocsVisible: INTEGER,\ndevMDXVisible: INTEGER,\nbuildManagerHeaderVisible: INTEGER,\nbuildManagerIndexVisible: INTEGER,\nbuildStoryVisible: INTEGER,\nbuildAutodocsVisible: INTEGER,\nbuildMDXVisible: INTEGER"
  },
  {
    "path": "scripts/bench/browse.ts",
    "content": "import { chromium } from 'playwright';\n\nimport { getPreviewPage, now } from './utils.ts';\n\ninterface Result {\n  managerHeaderVisible?: number;\n  managerIndexVisible?: number;\n  storyVisible?: number;\n  storyVisibleUncached?: number;\n  autodocsVisible?: number;\n  mdxVisible?: number;\n}\n\nexport const browse = async (url: string, { disableDocs }: { disableDocs?: boolean }) => {\n  const result: Result = {};\n\n  /* Heat up time for playwright and the builder\n   * This is to avoid the first run being slower than the rest\n   * which can happen due to vite or webpack lazy compilation\n   * We visit the story and the docs page, so those should be fully cached\n   *\n   * We instantiate a new browser for each run to avoid any caching happening in the browser itself\n   */\n  const x = await benchStory(url);\n\n  if (!disableDocs) {\n    await benchAutodocs(url);\n  }\n\n  result.storyVisibleUncached = x.storyVisible;\n\n  if (!disableDocs) {\n    Object.assign(result, await benchMDX(url));\n  }\n  Object.assign(result, await benchStory(url));\n\n  if (!disableDocs) {\n    Object.assign(result, await benchAutodocs(url));\n  }\n\n  return result;\n};\n\nasync function benchAutodocs(url: string) {\n  const result: Result = {};\n  const browser = await chromium.launch(/* { headless: false } */);\n  await browser.newContext();\n  const page = await browser.newPage();\n  page.setDefaultTimeout(40000);\n\n  const start = now();\n  await page.goto(`${url}?path=/docs/example-button--docs`);\n\n  const tasks = [\n    async () => {\n      const previewPage = await getPreviewPage(page);\n      previewPage.setDefaultTimeout(40000);\n\n      await previewPage.waitForLoadState('load');\n      await previewPage.getByText('Primary UI component for user interaction');\n\n      result.autodocsVisible = now() - start;\n    },\n  ];\n\n  await Promise.all(tasks.map((t) => t()));\n  await page.close();\n\n  return result;\n}\n\nasync function benchMDX(url: string) {\n  const result: Result = {};\n  const browser = await chromium.launch(/* { headless: false } */);\n  await browser.newContext();\n  const page = await browser.newPage();\n\n  const start = now();\n  await page.goto(`${url}?path=/docs/configure-your-project--docs`);\n\n  const tasks = [\n    async () => {\n      const previewPage = await getPreviewPage(page);\n      previewPage.setDefaultTimeout(40000);\n\n      await previewPage.waitForLoadState('load');\n      await previewPage.getByText('Configure your project');\n\n      result.mdxVisible = now() - start;\n    },\n  ];\n\n  await Promise.all(tasks.map((t) => t()));\n  await page.close();\n\n  return result;\n}\n\nasync function benchStory(url: string) {\n  const result: Result = {};\n  // change this to true, to see the browser in action\n  const browser = await chromium.launch({ headless: true });\n  await browser.newContext();\n  const page = await browser.newPage();\n\n  const start = now();\n  await page.goto(`${url}?path=/story/example-button--primary`);\n\n  const tasks = [\n    async () => {\n      await page.waitForSelector('.sidebar-header', { state: 'attached' });\n      result.managerHeaderVisible = now() - start;\n    },\n    async () => {\n      await page.waitForSelector('#example-button--primary', { state: 'attached' });\n      result.managerIndexVisible = now() - start;\n    },\n    async () => {\n      const previewPage = await getPreviewPage(page);\n      previewPage.setDefaultTimeout(40000);\n\n      await previewPage.waitForLoadState('load');\n      await previewPage.getByText('Button');\n\n      result.storyVisible = now() - start;\n    },\n  ];\n\n  await Promise.all(tasks.map((t) => t()));\n  await page.close();\n\n  return result;\n}\n"
  },
  {
    "path": "scripts/bench/safe-args.ts",
    "content": "const METAFILES_DIR = 'bench/esbuild-metafiles';\n\n// allows the metafile path to be used in the URL hash\nexport const safeMetafileArg = (path: string) =>\n  path\n    .replace(new RegExp(`.*${METAFILES_DIR}/`), '')\n    .replaceAll('/', '__')\n    .replace(/(\\w*).json/, '$1');\n"
  },
  {
    "path": "scripts/bench/types.ts",
    "content": "// NOTE: this must be kept in sync with ./bench.schema, which defines\n// the table schema in BigQuery\nexport interface BenchResults {\n  branch: string;\n  commit: string;\n  timestamp: string;\n  label: string;\n\n  /** The time it takes to create the base sandbox without storybook */\n  createTime: number;\n  /** The time it takes to install the base sandbox after it has been initialized */\n  generateTime: number;\n  /** The time it takes to run `sb init` on the base sandbox */\n  initTime: number;\n  /** Size of base sandbox node_modules without storybook pre-install */\n  createSize: number;\n  /** Size of base sandbox node_modules without storybook post-install */\n  generateSize: number;\n  /** Size of the sandbox node_modules post `sb init` */\n  initSize: number;\n  /** Difference bewtween `initSize` and `generateSize` */\n  diffSize: number;\n  /** Full `sb build` time */\n  buildTime: number;\n  /** Size of the storybook-static directory in total */\n  buildSize: number;\n  /** Size of the storybook-static/sb-addons in total */\n  buildSbAddonsSize: number;\n  /** Size of the storybook-static/sb-common-assets */\n  buildSbCommonSize: number;\n  /** Size of the storybook-static/sb-manager */\n  buildSbManagerSize: number;\n  /** Size of storybook-static/sb-preview */\n  buildSbPreviewSize: number;\n  /** Size of the `static` directory if it exists */\n  buildStaticSize: number;\n  /** Total size of `sb-x` above */\n  buildPrebuildSize: number;\n  /** Total size of everything else (user's stories & components & CSS & assets etc.) */\n  buildPreviewSize: number;\n  /** Full `sb build` time */\n  testBuildTime: number;\n  /** Size of the storybook-static directory in total */\n  testBuildSize: number;\n  /** Size of the storybook-static/sb-addons in total */\n  testBuildSbAddonsSize: number;\n  /** Size of the storybook-static/sb-common-assets */\n  testBuildSbCommonSize: number;\n  /** Size of the storybook-static/sb-manager */\n  testBuildSbManagerSize: number;\n  /** Size of storybook-static/sb-preview */\n  testBuildSbPreviewSize: number;\n  /** Size of the `static` directory if it exists */\n  testBuildStaticSize: number;\n  /** Total size of `sb-x` above */\n  testBuildPrebuildSize: number;\n  /** Total size of everything else (user's stories & components & CSS & assets etc.) */\n  testBuildPreviewSize: number;\n  /** Time to wait-on iframe.html */\n  devPreviewResponsive: number;\n  /** Time to wait-on index.html */\n  devManagerResponsive: number;\n  /** Time to browse to index.html and view the SB logo */\n  devManagerHeaderVisible: number;\n  /** Time to browse to index.html and load the story index */\n  devManagerIndexVisible: number;\n  /**\n   * Time to browse to index.html and load iframe content and the story is rendered, for the very\n   * first run\n   */\n  devStoryVisibleUncached: number;\n  /** Time to browse to index.html and load iframe content and the story is rendered */\n  devStoryVisible: number;\n  /** Time to browse to index.html and load iframe content and the docs page is rendered */\n  devAutodocsVisible: number;\n  /** Time to browse to index.html and load iframe content and the MDX page is rendered */\n  devMDXVisible: number;\n  /** Time to browse to index.html and view the SB logo */\n  buildManagerHeaderVisible: number;\n  /** Time to browse to index.html and load the story index */\n  buildManagerIndexVisible: number;\n  /** Time to browse to index.html and load iframe content and the story is rendered */\n  buildStoryVisible: number;\n  /** Time to browse to index.html and load iframe content and the docs page is rendered */\n  buildAutodocsVisible: number;\n  /** Time to browse to index.html and load iframe content and the MDX page is rendered */\n  buildMDXVisible: number;\n}\n"
  },
  {
    "path": "scripts/bench/utils.ts",
    "content": "/// <reference lib=\"dom\" />\nimport { mkdir, readFile, readdir, writeFile } from 'node:fs/promises';\n\nimport { join } from 'path';\nimport type { Page } from 'playwright-core';\n\nimport type { BenchResults } from './types.ts';\n\nexport const now = () => new Date().getTime();\n\nexport interface SaveBenchOptions {\n  rootDir?: string;\n}\n\nexport const saveBench = async (\n  key: string,\n  data: Partial<BenchResults>,\n  options: SaveBenchOptions\n) => {\n  const dirName = join(options.rootDir || process.cwd(), 'bench');\n  const fileName = `${key}.json`;\n  await mkdir(dirName, { recursive: true });\n\n  const filePath = join(dirName, fileName);\n  const existing = await readFile(filePath, 'utf8')\n    .then((txt) => JSON.parse(txt))\n    .catch(() => ({}));\n\n  const merged = { ...existing, ...data };\n  await writeFile(filePath, JSON.stringify(merged, null, 2), 'utf8');\n};\n\nexport const loadBench = async (options: SaveBenchOptions): Promise<Partial<BenchResults>> => {\n  const dirName = join(options.rootDir || process.cwd(), 'bench');\n  const files = await readdir(dirName);\n  return files.reduce(async (acc, fileName) => {\n    const content = await readFile(join(dirName, fileName), 'utf8');\n    const data = JSON.parse(content);\n    return { ...(await acc), ...data };\n  }, Promise.resolve({}));\n  // return readJSON(join(dirname, `bench.json`));\n};\n\nexport async function getPreviewPage(page: Page) {\n  /**\n   * Fix flakiness in preview iframe retrieval Sometimes the iframe is not yet available when we try\n   * to access it, even after waiting for the readyState to be complete.\n   *\n   * This loop will keep trying to access the iframe until it's available.\n   */\n  for (let i = 0; i < 10; i++) {\n    await page.waitForFunction(() => {\n      return document.querySelector('iframe')?.contentDocument.readyState === 'complete';\n    });\n\n    const previewPage = page.frame({ url: /iframe.html/ })?.page();\n    if (previewPage) {\n      return previewPage;\n    }\n  }\n\n  throw new Error('The preview iframe was never found');\n}\n"
  },
  {
    "path": "scripts/build/build-package.ts",
    "content": "/**\n * This is the entrypoint to compile a singular package:\n *\n * This is not run directly, but rather through the `nr task compile` or `nr build <package-name>`\n * commands.\n *\n * It is used to compile a package, and generate the dist files, type mappers, and types files.\n *\n * The `process.cwd()` is the root of the current package to be built.\n */\n\n/* eslint-disable local-rules/no-uncategorized-errors */\nimport { mkdir, rm } from 'node:fs/promises';\nimport { pathToFileURL } from 'node:url';\nimport { parseArgs } from 'node:util';\n\nimport { join, relative } from 'pathe';\nimport picocolors from 'picocolors';\nimport prettyTime from 'pretty-hrtime';\n\nimport { ROOT_DIRECTORY } from '../utils/constants';\nimport { buildEntries, hasPrebuild, isBuildEntries } from './entry-configs';\nimport { measure } from './utils/entry-utils';\nimport { generateBundle } from './utils/generate-bundle';\nimport { generatePackageJsonFile } from './utils/generate-package-json';\nimport { generateTypesFiles } from './utils/generate-types';\n\nconst {\n  values: { prod, production, optimized, watch, cwd },\n} = parseArgs({\n  options: {\n    prod: { type: 'boolean', default: false },\n    production: { type: 'boolean', default: false },\n    optimized: { type: 'boolean', default: false },\n    watch: { type: 'boolean', default: false },\n    cwd: { type: 'string' },\n  },\n  allowNegative: true,\n});\n\nasync function run() {\n  const DIR_ROOT = join(import.meta.dirname, '..', '..');\n  const DIR_CWD = cwd ? join(ROOT_DIRECTORY, cwd) : process.cwd();\n  const DIR_DIST = join(DIR_CWD, 'dist');\n  const DIR_REL = relative(DIR_ROOT, DIR_CWD);\n\n  const isProduction = prod || production || optimized;\n  const isWatch = watch;\n\n  if (isProduction && isWatch) {\n    throw new Error('Cannot watch and build for production at the same time');\n  }\n\n  const { default: pkg } = await import(pathToFileURL(join(DIR_CWD, 'package.json')).href, {\n    with: { type: 'json' },\n  });\n\n  await rm(DIR_DIST, { recursive: true }).catch(() => {});\n  await mkdir(DIR_DIST);\n\n  console.log(\n    isWatch\n      ? `Watching ${picocolors.greenBright(DIR_REL)}`\n      : `Building ${picocolors.greenBright(DIR_REL)}`\n  );\n\n  const name = pkg.name;\n\n  if (!isBuildEntries(name)) {\n    throw new Error(`TODO BETTER ERROR: No build entries found for package ${pkg.name}`);\n  }\n\n  const entry = buildEntries[name];\n\n  let prebuildTime: Awaited<ReturnType<typeof measure>> | undefined;\n\n  if (hasPrebuild(entry)) {\n    console.log(`Running prebuild script`);\n    prebuildTime = await measure(() => entry.prebuild(DIR_CWD));\n  }\n\n  await generatePackageJsonFile(DIR_CWD, entry);\n\n  const [bundleTime, typesTime] = await Promise.all([\n    measure(async () => generateBundle({ cwd: DIR_CWD, entry, name, isWatch })),\n    measure(async () => {\n      if (isProduction) {\n        await generateTypesFiles(DIR_CWD, entry);\n      }\n    }),\n  ]);\n\n  if (prebuildTime) {\n    console.log(`Prebuild script completed in`, picocolors.yellow(prettyTime(prebuildTime)));\n  }\n\n  console.log(\n    isWatch ? 'Watcher started in' : 'Bundled in',\n    picocolors.yellow(prettyTime(bundleTime))\n  );\n  console.log(\n    isProduction ? 'Generated types in' : 'Generated type mappers in',\n    picocolors.yellow(prettyTime(typesTime))\n  );\n}\n\nrun();\n"
  },
  {
    "path": "scripts/build/entry-configs.ts",
    "content": "// @ts-ignore\nimport a11yConfig from '../../../code/addons/a11y/build-config';\n// @ts-ignore\nimport docsConfig from '../../../code/addons/docs/build-config';\n// @ts-ignore\nimport linksConfig from '../../../code/addons/links/build-config';\n// @ts-ignore\nimport onboardingConfig from '../../../code/addons/onboarding/build-config';\n// @ts-ignore\nimport pseudoStatesConfig from '../../../code/addons/pseudo-states/build-config';\n// @ts-ignore\nimport themesConfig from '../../../code/addons/themes/build-config';\n// @ts-ignore\nimport vitestConfig from '../../../code/addons/vitest/build-config';\n// @ts-ignore\nimport builderViteConfig from '../../../code/builders/builder-vite/build-config';\n// @ts-ignore\nimport builderWebpack5Config from '../../../code/builders/builder-webpack5/build-config';\n// @ts-ignore\nimport storybookConfig from '../../../code/core/build-config';\n// @ts-ignore\nimport angularFrameworkConfig from '../../../code/frameworks/angular/build-config';\n// @ts-ignore\nimport emberFrameworkConfig from '../../../code/frameworks/ember/build-config';\n// @ts-ignore\nimport htmlViteFrameworkConfig from '../../../code/frameworks/html-vite/build-config';\n// @ts-ignore\nimport nextjsViteFrameworkConfig from '../../../code/frameworks/nextjs-vite/build-config';\n// @ts-ignore\nimport nextjsFrameworkConfig from '../../../code/frameworks/nextjs/build-config';\n// @ts-ignore\nimport preactViteFrameworkConfig from '../../../code/frameworks/preact-vite/build-config';\n// @ts-ignore\nimport reactNativeWebViteFrameworkConfig from '../../../code/frameworks/react-native-web-vite/build-config';\n// @ts-ignore\nimport reactViteFrameworkConfig from '../../../code/frameworks/react-vite/build-config';\n// @ts-ignore\nimport reactWebpack5FrameworkConfig from '../../../code/frameworks/react-webpack5/build-config';\n// @ts-ignore\nimport serverWebpack5FrameworkConfig from '../../../code/frameworks/server-webpack5/build-config';\n// @ts-ignore\nimport svelteViteFrameworkConfig from '../../../code/frameworks/svelte-vite/build-config';\n// @ts-ignore\nimport sveltekitFrameworkConfig from '../../../code/frameworks/sveltekit/build-config';\n// @ts-ignore\nimport vue3ViteFrameworkConfig from '../../../code/frameworks/vue3-vite/build-config';\n// @ts-ignore\nimport webComponentsViteFrameworkConfig from '../../../code/frameworks/web-components-vite/build-config';\n// @ts-ignore\nimport cliConfig from '../../../code/lib/cli-storybook/build-config';\n// @ts-ignore\nimport codemodConfig from '../../../code/lib/codemod/build-config';\n// @ts-ignore\nimport coreWebpackConfig from '../../../code/lib/core-webpack/build-config';\n// @ts-ignore\nimport createStorybookConfig from '../../../code/lib/create-storybook/build-config';\n// @ts-ignore\nimport csfPluginConfig from '../../../code/lib/csf-plugin/build-config';\n// @ts-ignore\nimport eslintPluginConfig from '../../../code/lib/eslint-plugin/build-config';\n// @ts-ignore\nimport reactDomShimConfig from '../../../code/lib/react-dom-shim/build-config';\n// @ts-ignore\nimport presetCraConfig from '../../../code/presets/create-react-app/build-config';\n// @ts-ignore\nimport presetReactWebpackConfig from '../../../code/presets/react-webpack/build-config';\n// @ts-ignore\nimport presetServerWebpackConfig from '../../../code/presets/server-webpack/build-config';\n// @ts-ignore\nimport htmlRendererConfig from '../../../code/renderers/html/build-config';\n// @ts-ignore\nimport preactRendererConfig from '../../../code/renderers/preact/build-config';\n// @ts-ignore\nimport reactRendererConfig from '../../../code/renderers/react/build-config';\n// @ts-ignore\nimport serverRendererConfig from '../../../code/renderers/server/build-config';\n// @ts-ignore\nimport svelteRendererConfig from '../../../code/renderers/svelte/build-config';\n// @ts-ignore\nimport vue3RendererConfig from '../../../code/renderers/vue3/build-config';\n// @ts-ignore\nimport webComponentsRendererConfig from '../../../code/renderers/web-components/build-config';\nimport type { BuildEntriesByPackageName } from './utils/entry-utils';\n\nexport const buildEntries = {\n  storybook: storybookConfig,\n\n  // addons\n  '@storybook/addon-a11y': a11yConfig,\n  '@storybook/addon-docs': docsConfig,\n  '@storybook/addon-links': linksConfig,\n  '@storybook/addon-onboarding': onboardingConfig,\n  'storybook-addon-pseudo-states': pseudoStatesConfig,\n  '@storybook/addon-themes': themesConfig,\n  '@storybook/addon-vitest': vitestConfig,\n\n  // builders\n  '@storybook/builder-vite': builderViteConfig,\n  '@storybook/builder-webpack5': builderWebpack5Config,\n\n  // frameworks\n  '@storybook/angular': angularFrameworkConfig,\n  '@storybook/ember': emberFrameworkConfig,\n  '@storybook/html-vite': htmlViteFrameworkConfig,\n  '@storybook/nextjs': nextjsFrameworkConfig,\n  '@storybook/nextjs-vite': nextjsViteFrameworkConfig,\n  '@storybook/preact-vite': preactViteFrameworkConfig,\n  '@storybook/react-native-web-vite': reactNativeWebViteFrameworkConfig,\n  '@storybook/react-vite': reactViteFrameworkConfig,\n  '@storybook/react-webpack5': reactWebpack5FrameworkConfig,\n  '@storybook/server-webpack5': serverWebpack5FrameworkConfig,\n  '@storybook/svelte-vite': svelteViteFrameworkConfig,\n  '@storybook/sveltekit': sveltekitFrameworkConfig,\n  '@storybook/vue3-vite': vue3ViteFrameworkConfig,\n  '@storybook/web-components-vite': webComponentsViteFrameworkConfig,\n\n  // lib\n  '@storybook/cli': cliConfig,\n  '@storybook/codemod': codemodConfig,\n  '@storybook/core-webpack': coreWebpackConfig,\n  '@storybook/csf-plugin': csfPluginConfig,\n  '@storybook/react-dom-shim': reactDomShimConfig,\n  'create-storybook': createStorybookConfig,\n  'eslint-plugin-storybook': eslintPluginConfig,\n\n  // presets\n  '@storybook/preset-create-react-app': presetCraConfig,\n  '@storybook/preset-react-webpack': presetReactWebpackConfig,\n  '@storybook/preset-server-webpack': presetServerWebpackConfig,\n\n  // renderers\n  '@storybook/html': htmlRendererConfig,\n  '@storybook/preact': preactRendererConfig,\n  '@storybook/react': reactRendererConfig,\n  '@storybook/server': serverRendererConfig,\n  '@storybook/svelte': svelteRendererConfig,\n  '@storybook/vue3': vue3RendererConfig,\n  '@storybook/web-components': webComponentsRendererConfig,\n};\n\nexport function isBuildEntries(key: string): key is keyof typeof buildEntries {\n  return key in buildEntries;\n}\n\nexport function hasPrebuild(\n  entry: BuildEntriesByPackageName[keyof BuildEntriesByPackageName]\n): entry is BuildEntriesByPackageName[keyof BuildEntriesByPackageName] & {\n  prebuild: (cwd: string) => Promise<void>;\n} {\n  return 'prebuild' in entry;\n}\n"
  },
  {
    "path": "scripts/build/utils/dts-process.ts",
    "content": "import { writeFile } from 'node:fs/promises';\nimport { dirname, join, sep } from 'node:path';\n\nimport { rollup } from 'rollup';\nimport { dts } from 'rollup-plugin-dts';\nimport { JsxEmit, ScriptTarget } from 'typescript';\n\nimport { getExternal } from './entry-utils';\n\nasync function run() {\n  const [entryPoint] = process.argv.slice(2);\n\n  if (!entryPoint) {\n    throw new Error(\n      'No entry point provided. Usage: jiti scripts/build/utils/dts-process.ts <entryPoint>'\n    );\n  }\n  const { typesExternal: external } = await getExternal(process.cwd());\n\n  const dir = dirname(entryPoint).replace('src', 'dist');\n  const outputFile = entryPoint.replace('src', 'dist').replace(/\\.tsx?/, '.d.ts');\n  const out = await rollup({\n    input: entryPoint,\n    external: (id) => {\n      return external.some(\n        (dep) =>\n          id === dep ||\n          id.startsWith(`${dep}/`) ||\n          id.includes(`${sep}node_modules${sep}${dep}${sep}`)\n      );\n    },\n    output: { file: outputFile, format: 'es' },\n    plugins: [\n      dts({\n        respectExternal: true,\n        tsconfig: join(process.cwd(), 'tsconfig.json'),\n        compilerOptions: {\n          esModuleInterop: true,\n          baseUrl: '.',\n          jsx: JsxEmit.React,\n          declaration: true,\n          noEmit: false,\n          emitDeclarationOnly: true,\n          noEmitOnError: true,\n          checkJs: false,\n          declarationMap: false,\n          skipLibCheck: true,\n          preserveSymlinks: false,\n          target: ScriptTarget.ESNext,\n        },\n      }),\n    ],\n  });\n  const { output } = await out.generate({\n    format: 'es',\n    file: outputFile,\n  });\n\n  await Promise.all(\n    output.map(async (o) => {\n      if (o.type === 'chunk') {\n        await writeFile(join(dir, o.fileName), o.code);\n      } else {\n        throw new Error(`Unexpected output type: ${o.type} for ${entryPoint} (${o.fileName})`);\n      }\n    })\n  );\n}\n\nrun();\n"
  },
  {
    "path": "scripts/build/utils/entry-utils.ts",
    "content": "import { builtinModules } from 'node:module';\nimport { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nimport * as esbuild from 'esbuild';\n\nexport type EntryType = 'node' | 'browser' | 'runtime' | 'globalizedRuntime';\n\nexport type BuildEntry = {\n  exportEntries?: ('.' | `./${string}`)[]; // the keys in the package.json's export map, e.g. [\"./internal/manager-api\", \"./manager-api\"]\n  entryPoint: `./src/${string}`; // the source file to bundle, e.g. \"./src/manager-api/index.ts\",\n  external?: string[]; // the list of external dependencies to exclude from the bundle\n  dts?: false; // default to generating d.ts files for all entries, except if set to false\n};\nexport type BuildEntriesByPlatform = Partial<Record<EntryType, BuildEntry[]>>;\n\nexport type EsbuildContextOptions = Parameters<(typeof esbuild)['context']>[0];\n\nexport type BuildEntries = {\n  /**\n   * The map of entry points by platform\n   *\n   * Each platform is optional\n   */\n  entries: BuildEntriesByPlatform;\n  /**\n   * The map of extra outputs to be added to the package.json's exports\n   *\n   * This can be useful to expose non-compiled/non-js files such as Svelte components,\n   */\n  extraOutputs?: Record<string, any>;\n  /**\n   * The function to run before the build\n   *\n   * @note this runs only **once** when watch-mode is enabled\n   */\n  prebuild?: (cwd: string) => Promise<void>;\n  /**\n   * The function to run after each successful build (works with watch-mode)\n   *\n   * @note this runs **after** each successful build, even in watch-mode\n   */\n  postbuild?: (cwd: string) => Promise<void>;\n};\n\nexport type BuildEntriesByPackageName = Record<string, BuildEntries>;\n\nexport const measure = async (fn: () => Promise<void>) => {\n  const start = process.hrtime();\n  await fn();\n  return process.hrtime(start);\n};\n\nexport const getExternal = async (cwd: string) => {\n  const { default: packageJson } = await import(pathToFileURL(join(cwd, 'package.json')).href, {\n    with: { type: 'json' },\n  });\n\n  const runtimeExternalInclude: string[] = [\n    'react',\n    'use-sync-external-store',\n    'react-dom',\n    'react-dom/client',\n    '@storybook/icons',\n\n    /**\n     * @note This is not a real package, it's a hack to allow `frameworks/nextjs` to be able to alias\n     * whilst also able to use the nextjs version\n     *\n     * @see `code/frameworks/nextjs/src/images/next-image.tsx`\n     */\n    'sb-original',\n    packageJson.name,\n    ...Object.keys(packageJson.dependencies || {}),\n    ...Object.keys(packageJson.peerDependencies || {}),\n  ];\n  const runtimeExternalExclude = [\n    '@testing-library/jest-dom',\n    '@testing-library/user-event',\n    'chai',\n    '@vitest/expect',\n    '@vitest/mocker',\n    '@vitest/spy',\n    '@vitest/utils',\n  ];\n  const runtimeExternal = runtimeExternalInclude.filter(\n    (dep) => !runtimeExternalExclude.includes(dep)\n  );\n  const typesExternal = [\n    ...runtimeExternalInclude,\n    'ast-types',\n    ...builtinModules.flatMap((m: string) => [m, `node:${m}`]),\n  ];\n\n  return { runtimeExternal, typesExternal };\n};\n"
  },
  {
    "path": "scripts/build/utils/generate-bundle.ts",
    "content": "/* eslint-disable local-rules/no-uncategorized-errors */\nimport { existsSync, watch } from 'node:fs';\nimport { mkdir, rm, writeFile } from 'node:fs/promises';\n\nimport { globalExternals } from '@fal-works/esbuild-plugin-global-externals';\nimport * as esbuild from 'esbuild';\nimport { raw as rawPlugin } from 'esbuild-raw-plugin';\nimport { basename, join, relative } from 'pathe';\nimport picocolors from 'picocolors';\nimport { dedent } from 'ts-dedent';\n\nimport { globalsModuleInfoMap } from '../../../code/core/src/manager/globals/globals-module-info';\nimport {\n  BROWSER_TARGETS,\n  NODE_TARGET,\n  SUPPORTED_FEATURES,\n} from '../../../code/core/src/shared/constants/environments-support';\nimport { resolvePackageDir } from '../../../code/core/src/shared/utils/module';\nimport {\n  type BuildEntries,\n  type EntryType,\n  type EsbuildContextOptions,\n  getExternal,\n} from './entry-utils';\n\n// repo root/bench/esbuild-metafiles/core\nconst DIR_METAFILE_BASE = join(\n  import.meta.dirname,\n  '..',\n  '..',\n  '..',\n  'code',\n  'bench',\n  'esbuild-metafiles'\n);\nexport const DIR_CODE = join(import.meta.dirname, '..', '..', '..', 'code');\n\n/*\n * This plugin writes the metafile to a file in the output directory.\n * It is used to analyze the bundle size of the different entry points.\n * The outputDir must be the package's directory, as that is the projectName in the NX config,\n * and what will become part of the build output cache. If there is a mismatch,\n * the metafiles won't be available whenever NX uses its cached results of the build step.\n */\nfunction metafileWriterPlugin(entryType: EntryType, outputDir: string): esbuild.Plugin {\n  return {\n    name: 'metafile-writer',\n    setup(build) {\n      build.onEnd(async (result) => {\n        if (result.errors.length || !result.metafile) {\n          return;\n        }\n        const outputFile = join(outputDir, `${entryType}.json`);\n        if (existsSync(outputFile)) {\n          await rm(outputFile, { force: true });\n        }\n        await mkdir(outputDir, { recursive: true });\n        await writeFile(outputFile, JSON.stringify(result.metafile, null, 2));\n      });\n    },\n  };\n}\n\nexport async function generateBundle({\n  cwd,\n  entry,\n  isWatch,\n}: {\n  cwd: string;\n  entry: BuildEntries;\n  name: string;\n  isWatch: boolean;\n}) {\n  const DIR_CWD = cwd;\n  const DIR_REL = relative(DIR_CODE, DIR_CWD);\n  const PACKAGE_DIR_NAME = basename(DIR_CWD);\n  const external = (await getExternal(DIR_CWD)).runtimeExternal;\n  const { entries, postbuild } = entry;\n\n  const sharedOptions = {\n    absWorkingDir: DIR_CWD,\n    format: 'esm',\n    bundle: true,\n    legalComments: 'none',\n    ignoreAnnotations: true,\n    splitting: true,\n    metafile: true,\n    outbase: 'src',\n    outdir: 'dist',\n    treeShaking: true,\n    color: true,\n    external,\n    minifySyntax: true,\n    define: {\n      /*\n       * We need to disable the default behavior of replacing process.env.NODE_ENV with \"development\"\n       * Because we have code that reads this value to determine if the code is running in a production environment.\n       * @see 6th bullet in \"browser\" section in https://esbuild.github.io/api/#platform\n       */\n      'process.env.NODE_ENV': 'process.env.NODE_ENV',\n    },\n    plugins: [\n      rawPlugin(),\n      {\n        name: 'postbuild',\n        setup(build) {\n          build.onEnd(async (result) => {\n            if (!postbuild) {\n              return;\n            }\n            if (result.errors.length) {\n              console.log('Errors found, skipping postbuild');\n              return;\n            }\n            console.log('Running postbuild script');\n            await postbuild(DIR_CWD);\n          });\n        },\n      },\n    ],\n  } as const satisfies EsbuildContextOptions;\n\n  const runtimeOptions = {\n    ...sharedOptions,\n    platform: 'browser',\n    target: BROWSER_TARGETS,\n    supported: SUPPORTED_FEATURES,\n    splitting: false,\n    external: [\n      // The following modules are conditionally called inside of @vitest/mocker\n      // The actual function which calls these modules is not imported\n      // and therefore we can externalize them.\n      'msw/browser',\n      'msw/core/http',\n    ], // Prefer `alias` over `external` because we're using aliases to bundle everything into the runtimes\n    alias: {\n      // The following aliases ensures that the runtimes bundles in the actual sources of these modules\n      // instead of attempting to resolve them to the dist files, because the dist files are not available yet.\n      'storybook/preview-api': './src/preview-api',\n      'storybook/manager-api': './src/manager-api',\n      'storybook/theming': './src/theming',\n      'storybook/test': './src/test',\n      'storybook/internal': './src',\n      'storybook/outline': './src/outline',\n      'storybook/backgrounds': './src/backgrounds',\n      'storybook/highlight': './src/highlight',\n      'storybook/measure': './src/measure',\n      'storybook/actions': './src/actions',\n      'storybook/viewport': './src/viewport',\n      // The following aliases ensures that the manager has a single version of React,\n      // even if transitive dependencies would depend on other versions.\n      react: resolvePackageDir('react'),\n      'react-dom': resolvePackageDir('react-dom'),\n      'react-dom/client': join(resolvePackageDir('react-dom'), 'client'),\n    },\n    define: {\n      // This should set react in prod mode for the manager\n      'process.env.NODE_ENV': '\"production\"',\n    },\n  } as const satisfies EsbuildContextOptions;\n\n  const contexts: Array<ReturnType<typeof esbuild.context>> = [];\n\n  if (entries.node) {\n    const uid = Math.random().toString(36).substring(2, 15);\n    contexts.push(\n      esbuild.context({\n        ...sharedOptions,\n        entryPoints: entries.node.map(({ entryPoint }) => entryPoint),\n        platform: 'node',\n        target: NODE_TARGET,\n        chunkNames: '_node-chunks/[name]-[hash]',\n        banner: {\n          /*\n          This banner injects CJS compatibility code into the bundle, for when\n          dependencies need require, __filename, or __dirname.\n\n          We're adding unique names to the imports to avoid collisions\n          when one of our packages bundles in another of our packages,\n          like create-storybook bundling in parts of storybook core.\n          Similarly we're using var definitions as they can be redefined\n          without causing errors.\n          */\n          js: dedent`\n            import CJS_COMPAT_NODE_URL_${uid} from 'node:url';\n            import CJS_COMPAT_NODE_PATH_${uid} from 'node:path';\n            import CJS_COMPAT_NODE_MODULE_${uid} from \"node:module\";\n\n            var __filename = CJS_COMPAT_NODE_URL_${uid}.fileURLToPath(import.meta.url);\n            var __dirname = CJS_COMPAT_NODE_PATH_${uid}.dirname(__filename);\n            var require = CJS_COMPAT_NODE_MODULE_${uid}.createRequire(import.meta.url);\n\n            // ------------------------------------------------------------\n            // end of CJS compatibility banner, injected by Storybook's esbuild configuration\n            // ------------------------------------------------------------\n            `,\n        },\n        plugins: [\n          ...sharedOptions.plugins,\n          metafileWriterPlugin('node', join(DIR_METAFILE_BASE, PACKAGE_DIR_NAME)),\n        ],\n      })\n    );\n  }\n\n  if (entries.browser) {\n    contexts.push(\n      esbuild.context({\n        ...sharedOptions,\n        external: [\n          ...(sharedOptions.external as string[]),\n          ...(entries.browser.flatMap((entry) => entry.external) ?? []),\n        ].filter(Boolean),\n        entryPoints: entries.browser.map(({ entryPoint }) => entryPoint),\n        platform: 'browser',\n        chunkNames: '_browser-chunks/[name]-[hash]',\n        target: BROWSER_TARGETS,\n        supported: SUPPORTED_FEATURES,\n        plugins: [\n          ...sharedOptions.plugins,\n          metafileWriterPlugin('browser', join(DIR_METAFILE_BASE, PACKAGE_DIR_NAME)),\n        ],\n      })\n    );\n  }\n\n  if (entries.runtime) {\n    contexts.push(\n      esbuild.context({\n        ...runtimeOptions,\n        entryPoints: entries.runtime.map(({ entryPoint }) => entryPoint),\n        plugins: [\n          ...runtimeOptions.plugins,\n          metafileWriterPlugin('runtime', join(DIR_METAFILE_BASE, PACKAGE_DIR_NAME)),\n        ],\n      })\n    );\n  }\n\n  if (entries.globalizedRuntime) {\n    contexts.push(\n      esbuild.context({\n        ...runtimeOptions,\n        entryPoints: entries.globalizedRuntime.map(({ entryPoint }) => entryPoint),\n        plugins: [\n          ...runtimeOptions.plugins,\n          globalExternals(globalsModuleInfoMap),\n          metafileWriterPlugin('globalizedRuntime', join(DIR_METAFILE_BASE, PACKAGE_DIR_NAME)),\n        ],\n      })\n    );\n  }\n\n  const compile = await Promise.all(contexts);\n\n  await Promise.all(\n    compile.map(async (context) => {\n      if (isWatch) {\n        await context.watch();\n        // show a log message when a file is compiled\n        watch(join(DIR_CWD, 'dist'), { recursive: true }, (_event, filename) => {\n          console.log(`compiled ${picocolors.cyan(join(DIR_REL, 'dist', filename))}`);\n        });\n      } else {\n        await context.rebuild();\n        await context.dispose();\n      }\n    })\n  );\n}\n"
  },
  {
    "path": "scripts/build/utils/generate-package-json.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\n\nimport { join } from 'pathe';\nimport sortPackageJson from 'sort-package-json';\n\nimport type { BuildEntries } from './entry-utils';\n\nexport async function generatePackageJsonFile(cwd: string, data: BuildEntries) {\n  const location = join(cwd, 'package.json');\n  const pkgJson = JSON.parse(await readFile(location, { encoding: 'utf8' }));\n\n  const { entries } = data;\n\n  // Add the package.json file to the exports, so we can use it to `require.resolve` the package's root easily\n  pkgJson.exports = {\n    './package.json': './package.json',\n    ...data.extraOutputs,\n  };\n\n  for (const entry of Object.values(entries).flat()) {\n    for (const exportEntry of entry.exportEntries ?? []) {\n      const dtsPath = entry.entryPoint.replace('src', 'dist').replace(/\\.tsx?/, '.d.ts');\n      const jsPath = entry.entryPoint.replace('src', 'dist').replace(/\\.tsx?/, '.js');\n\n      if (entry.dts === undefined) {\n        pkgJson.exports[exportEntry] = {\n          code: entry.entryPoint,\n          types: dtsPath,\n          default: jsPath,\n        };\n      } else {\n        pkgJson.exports[exportEntry] = jsPath;\n      }\n    }\n  }\n\n  pkgJson.exports = sortObject(pkgJson.exports);\n\n  await writeFile(location, `${sortPackageJson(JSON.stringify(pkgJson, null, 2))}\\n`, {});\n}\n\nfunction sortObject(obj: Record<string, any>) {\n  return Object.fromEntries(Object.entries(obj).sort(([a], [b]) => a.localeCompare(b)));\n}\n"
  },
  {
    "path": "scripts/build/utils/generate-types.ts",
    "content": "import { spawn } from 'child_process';\nimport limit from 'p-limit';\nimport { join, relative } from 'pathe';\nimport picocolors from 'picocolors';\n\nimport { ROOT_DIRECTORY } from '../../utils/constants';\nimport type { BuildEntries } from './entry-utils';\n\nconst DIR_CODE = join(import.meta.dirname, '..', '..', '..', 'code');\n\nconst MAX_DTS_ATTEMPTS = 2;\nconst RETRY_DELAY_MS = 500;\n\nexport async function generateTypesFiles(cwd: string, data: BuildEntries) {\n  const DIR_CWD = cwd;\n  const DIR_REL = relative(DIR_CODE, DIR_CWD);\n\n  const dtsEntries = Object.values(data.entries)\n    .flat()\n    .filter((entry) => entry.dts !== false)\n    .map((e) => e.entryPoint);\n\n  // Spawn each entry in it's own separate process, because they are slow & synchronous\n  // ...this way we do not bog down the main process/esbuild and can run them in parallel\n  // we limit the number of concurrent processes to 3, because we don't want to overload the host machine\n  // by trial and error, 3 seems to be the sweet spot between perf and consistency\n  const limited = limit(5);\n  let processes: ReturnType<typeof spawn>[] = [];\n\n  await Promise.all(\n    dtsEntries.map(async (entryPoint) => {\n      return limited(async () => {\n        for (let attempt = 1; attempt <= MAX_DTS_ATTEMPTS; attempt++) {\n          let timer: ReturnType<typeof setTimeout> | undefined;\n          const dtsProcess = spawn(\n            `\"${join(ROOT_DIRECTORY, 'node_modules', '.bin', 'jiti')}\"`,\n            [`\"${join(import.meta.dirname, 'dts-process.ts')}\"`, `\"${entryPoint}\"`],\n            {\n              shell: true,\n              cwd: DIR_CWD,\n              stdio: ['ignore', 'inherit', 'pipe'],\n            }\n          );\n          processes.push(dtsProcess);\n\n          // Filter stderr to exclude messages containing \"are imported from external module\", which is an ignorable warning from rollup\n          dtsProcess.stderr?.on('data', (data) => {\n            const message = data.toString();\n            if (!message.includes('are imported from external module')) {\n              process.stderr.write(data);\n            }\n          });\n\n          await Promise.race([\n            new Promise((resolve) => {\n              dtsProcess.on('exit', () => {\n                resolve(void 0);\n              });\n              dtsProcess.on('error', () => {\n                resolve(void 0);\n              });\n              dtsProcess.on('close', () => {\n                resolve(void 0);\n              });\n            }),\n            new Promise((resolve) => {\n              timer = setTimeout(() => {\n                console.log('⌛ Timed out generating d.ts files for', entryPoint);\n\n                dtsProcess.kill(408); // timed out\n                resolve(void 0);\n              }, 120000);\n            }),\n          ]);\n\n          if (timer) {\n            clearTimeout(timer);\n          }\n\n          if (dtsProcess.exitCode !== 0) {\n            if (attempt < MAX_DTS_ATTEMPTS) {\n              // Race: parallel DTS can read a .d.ts another process is still writing → invalid. Retry + delay usually fixes (flake in core:compile:production since #33759).\n              console.warn(\n                `⚠️ DTS failed for ${picocolors.cyan(relative(cwd, entryPoint))}, retrying (${attempt}/${MAX_DTS_ATTEMPTS})...`\n              );\n              processes = processes.filter((p) => p !== dtsProcess);\n              await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));\n              continue;\n            }\n            console.error(\n              '\\n❌ Generating types for',\n              picocolors.cyan(relative(cwd, entryPoint)),\n              ' failed'\n            );\n            // If any fail after all retries, kill all the other processes and exit (bail)\n            processes.forEach((p) => p.kill());\n            processes = [];\n            process.exit(dtsProcess.exitCode || 1);\n          }\n\n          if (!process.env.CI) {\n            console.log('✅ Generated types for', picocolors.cyan(join(DIR_REL, entryPoint)));\n          }\n          break;\n        }\n      });\n    })\n  );\n}\n"
  },
  {
    "path": "scripts/build-package.ts",
    "content": "/**\n * This is the entrypoint for when you run:\n *\n * @example `nr build storybook --watch`\n *\n * You can pass a list of package names to build, or use the `--all` flag to build all packages.\n *\n * Pass the `--watch` flag to build in watch mode or `--no-watch` to skip the watch mode prompt.\n *\n * Pass the `--prod` flag to build in production mode or `--no-prod` to skip the production prompt.\n *\n * When you pass no package names, you will be prompted to select which packages to build.\n */\nimport { join } from 'node:path';\n\nimport { exec } from 'child_process';\nimport { program } from 'commander';\nimport { resolve } from 'path';\nimport picocolors from 'picocolors';\nimport prompts from 'prompts';\nimport windowSize from 'window-size';\n\nimport { ROOT_DIRECTORY } from './utils/constants.ts';\nimport { findMostMatchText } from './utils/diff.ts';\nimport { getCodeWorkspaces } from './utils/workspace.ts';\n\nasync function run() {\n  const packages = (await getCodeWorkspaces())\n    .filter(({ name }) => name !== '@storybook/code')\n    .sort((a) => (a.name === 'storybook' ? -1 : 0)); // Place main package first in option list\n\n  const tasks: Record<\n    string,\n    {\n      name: string;\n      defaultValue: boolean;\n      suffix: string;\n      value?: unknown;\n      location?: string;\n    }\n  > = packages\n    .map((pkg) => {\n      let suffix = pkg.name.replace('@storybook/', '');\n      if (pkg.name === '@storybook/cli') {\n        suffix = 'sb-cli';\n      }\n      return {\n        ...pkg,\n        suffix,\n        defaultValue: false,\n      };\n    })\n    .reduce(\n      (acc, next) => {\n        acc[next.name] = next;\n        return acc;\n      },\n      {} as Record<string, { name: string; defaultValue: boolean; suffix: string }>\n    );\n\n  const main = program\n    .version('5.0.0')\n    .allowExcessArguments(true)\n    .option('--all', `build everything ${picocolors.gray('(all)')}`, false)\n    .option('--watch', `build in watch mode`)\n    .option('--prod', `build in production mode`)\n    .option('--no-watch', `do not build in watch mode`)\n    .option('--no-prod', `do not build in production mode`);\n\n  main.parse(process.argv);\n\n  const opts = main.opts();\n  let watchMode = opts.watch;\n  let prodMode = opts.prod;\n\n  Object.keys(tasks).forEach((key) => {\n    // checks if a flag is passed e.g. yarn build addon-docs --watch\n    const containsFlag = main.args.includes(tasks[key].suffix);\n    tasks[key].value = containsFlag || opts.all;\n  });\n\n  let selection = Object.values(tasks).filter((item) => item.value === true);\n\n  // check for invalid package name(s) and try to guess the correct package name(s)\n  const suffixList = Object.values(tasks).map((t) => t.suffix);\n  let hasInvalidName = false;\n\n  for (const arg of main.args) {\n    if (!suffixList.includes(arg)) {\n      const matchText = findMostMatchText(suffixList, arg);\n\n      if (matchText) {\n        hasInvalidName = true;\n        process.stderr.write(\n          `${picocolors.red('Error')}: ${picocolors.cyan(\n            arg\n          )} is not a valid package name, Did you mean ${picocolors.cyan(matchText)}?\\n`\n        );\n      }\n    }\n  }\n\n  if (hasInvalidName) {\n    process.exit(1);\n  }\n\n  if (!selection.length) {\n    selection = await prompts(\n      [\n        watchMode === undefined && {\n          type: 'toggle',\n          name: 'watch',\n          message: 'Start in watch mode',\n          initial: false,\n          active: 'yes',\n          inactive: 'no',\n        },\n        prodMode === undefined && {\n          type: 'toggle',\n          name: 'prod',\n          message: 'Start in production mode',\n          initial: false,\n          active: 'yes',\n          inactive: 'no',\n        },\n        {\n          type: 'autocompleteMultiselect',\n          message: 'Select the packages to build',\n          name: 'todo',\n          min: 1,\n          hint: 'You can also run directly with package name like `yarn build storybook`, or `yarn build --all` for all packages!',\n          // @ts-expect-error @types incomplete\n          optionsPerPage: windowSize.height - 3, // 3 lines for extra info\n          choices: packages.map(({ name: key }) => ({\n            value: key,\n            title: tasks[key].name || key,\n            selected: (tasks[key] && tasks[key].defaultValue) || false,\n          })),\n        },\n      ],\n      { onCancel: () => process.exit(0) }\n    ).then(({ watch, prod, todo }: { watch: boolean; prod: boolean; todo: Array<string> }) => {\n      watchMode ??= watch;\n      prodMode ??= prod;\n      return todo?.map((key) => tasks[key]);\n    });\n  }\n\n  process.stdout.write('Building selected packages...\\n');\n  let lastName = '';\n\n  selection.forEach(async (v) => {\n    const script = join(ROOT_DIRECTORY, 'scripts', 'build', 'build-package.ts');\n    const command = `yarn exec jiti ${script}`;\n\n    const cwd = resolve(__dirname, '..', 'code', v.location);\n    const sub = exec(`${command}${watchMode ? ' --watch' : ''}${prodMode ? ' --prod' : ''}`, {\n      cwd,\n      env: {\n        NODE_ENV: 'production',\n        ...process.env,\n        FORCE_COLOR: '1',\n      },\n    });\n\n    sub.stdout?.on('data', (data) => {\n      if (lastName !== v.name) {\n        const prefix = `${picocolors.cyan(v.name)}:\\n`;\n        process.stdout.write(prefix);\n      }\n      lastName = v.name;\n      process.stdout.write(data);\n    });\n    sub.stderr?.on('data', (data) => {\n      if (lastName !== v.name) {\n        const prefix = `${picocolors.cyan(v.name)}:\\n`;\n        process.stdout.write(prefix);\n      }\n      lastName = v.name;\n      process.stderr.write(data);\n    });\n  });\n}\n\nrun().catch((e) => {\n  process.stderr.write(`${e.toString()}\\n`);\n  process.exit(1);\n});\n"
  },
  {
    "path": "scripts/check/check-package.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { isAbsolute } from 'node:path';\nimport { parseArgs } from 'node:util';\n\nimport { join } from 'pathe';\n\nimport { ROOT_DIRECTORY } from '../utils/constants.ts';\nimport { getTSDiagnostics, getTSFilesAndConfig, getTSProgramAndHost } from './utils/typescript.ts';\n\nconst {\n  values: { cwd },\n} = parseArgs({\n  options: {\n    cwd: { type: 'string' },\n  },\n  allowNegative: true,\n});\n\nconst normalizedCwd = cwd ? (isAbsolute(cwd) ? cwd : join(ROOT_DIRECTORY, cwd)) : process.cwd();\n\nconst tsconfigPath = join(normalizedCwd, 'tsconfig.json');\n\nif (existsSync(tsconfigPath)) {\n  const { options, fileNames } = getTSFilesAndConfig(tsconfigPath, normalizedCwd);\n  const { program, host } = getTSProgramAndHost(fileNames, options);\n\n  const tsDiagnostics = getTSDiagnostics(program, normalizedCwd, host);\n  if (tsDiagnostics.length > 0) {\n    console.log(tsDiagnostics);\n    process.exit(1);\n  } else if (!process.env.CI) {\n    console.log('✅ No type errors');\n  }\n}\n\n// TODO, add more package checks here, like:\n// - check for missing dependencies/peerDependencies\n// - check for unused exports\n"
  },
  {
    "path": "scripts/check/utils/typescript.ts",
    "content": "import { join } from 'node:path';\n\nimport typescript from 'typescript';\n\nexport function getTSDiagnostics(\n  program: typescript.Program,\n  cwd: string,\n  host: typescript.CompilerHost\n): any {\n  return typescript.formatDiagnosticsWithColorAndContext(\n    typescript.getPreEmitDiagnostics(program).filter((d) => d.file?.fileName.startsWith(cwd)),\n    host\n  );\n}\nexport function getTSProgramAndHost(fileNames: string[], options: typescript.CompilerOptions) {\n  const program = typescript.createProgram({\n    rootNames: fileNames,\n    options: {\n      module: typescript.ModuleKind.CommonJS,\n      ...options,\n      declaration: false,\n      noEmit: true,\n    },\n  });\n\n  const host = typescript.createCompilerHost(program.getCompilerOptions());\n  return { program, host };\n}\nexport function getTSFilesAndConfig(tsconfigPath: string, cwd: string = process.cwd()) {\n  const content = typescript.readJsonConfigFile(tsconfigPath, typescript.sys.readFile);\n  return typescript.parseJsonSourceFileConfigFileContent(\n    content,\n    {\n      useCaseSensitiveFileNames: true,\n      readDirectory: typescript.sys.readDirectory,\n      fileExists: typescript.sys.fileExists,\n      readFile: typescript.sys.readFile,\n    },\n    cwd,\n    {\n      noEmit: true,\n      outDir: join(cwd, 'types'),\n      target: typescript.ScriptTarget.ES2022,\n      declaration: false,\n    }\n  );\n}\n"
  },
  {
    "path": "scripts/check-dependencies.js",
    "content": "/**\n * This file needs to be run before any other script to ensure dependencies are installed Therefore,\n * we cannot transform this file to Typescript, because it would require esbuild to be installed\n */\nimport { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport * as url from 'node:url';\n\nconst dirname = url.fileURLToPath(new URL('.', import.meta.url));\n\nconst ROOT_DIRECTORY = join(dirname, '..');\n\nconst logger = console;\n\nconst checkDependencies = async () => {\n  if (!existsSync(join(ROOT_DIRECTORY, 'node_modules'))) {\n    logger.log('installing dependencies');\n\n    const task = spawn('yarn', ['install'], {\n      cwd: ROOT_DIRECTORY,\n      shell: true,\n      stdio: ['inherit', 'inherit', 'inherit'],\n    });\n\n    await new Promise((res, rej) => {\n      task.on('exit', (code) => {\n        if (code !== 0) {\n          rej();\n        } else {\n          res();\n        }\n      });\n    }).catch(() => {\n      task.kill();\n      throw new Error('Failed to install dependencies');\n    });\n\n    // give the filesystem some time\n    await new Promise((res) => {\n      setTimeout(res, 1000);\n    });\n  }\n};\n\ncheckDependencies().catch((e) => {\n  console.error(e);\n  process.exit(1);\n});\n"
  },
  {
    "path": "scripts/check-package.ts",
    "content": "// This script makes sure that we can support type checking,\n// without having to build dts files for all packages in the monorepo.\n// It is not implemented yet for angular, svelte and vue.\nimport { join } from 'node:path';\nimport { relative } from 'node:path';\n\nimport { program } from 'commander';\n// eslint-disable-next-line depend/ban-dependencies\nimport { execaCommand } from 'execa';\nimport { resolve } from 'path';\nimport picocolors from 'picocolors';\nimport prompts from 'prompts';\nimport Watchpack from 'watchpack';\nimport windowSize from 'window-size';\n\nimport { getTSFilesAndConfig } from './check/utils/typescript.ts';\nimport { ROOT_DIRECTORY } from './utils/constants.ts';\nimport { getCodeWorkspaces } from './utils/workspace.ts';\n\nasync function run() {\n  // Place main package first in option list\n  const packages = (await getCodeWorkspaces())\n    .filter(({ name }) => name !== '@storybook/code')\n    .sort((a) => (a.name === 'storybook' ? -1 : 0));\n\n  const tasks: Record<\n    string,\n    {\n      name: string;\n      defaultValue: boolean;\n      suffix: string;\n      value?: unknown;\n      location?: string;\n    }\n  > = packages\n    .map((pkg) => {\n      let suffix = pkg.name.replace('@storybook/', '');\n      if (pkg.name === '@storybook/cli') {\n        suffix = 'sb-cli';\n      }\n      return {\n        ...pkg,\n        suffix,\n        defaultValue: false,\n      };\n    })\n    .reduce(\n      (acc, next) => {\n        acc[next.name] = next;\n        return acc;\n      },\n      {} as Record<string, { name: string; defaultValue: boolean; suffix: string }>\n    );\n\n  const main = program\n    .version('5.0.0')\n    .allowExcessArguments(true)\n    .option('--all', `check everything ${picocolors.gray('(all)')}`)\n    .option('--watch', `build in watch mode`)\n    .option('--no-watch', `do not build in watch mode`);\n\n  main.parse(process.argv);\n\n  const opts = program.opts();\n  let watchMode = opts.watch;\n\n  Object.keys(tasks).forEach((key) => {\n    const opts = program.opts();\n    // checks if a flag is passed e.g. yarn check addon-docs --watch\n    const containsFlag = program.args.includes(tasks[key].suffix);\n    tasks[key].value = containsFlag || opts.all;\n  });\n\n  let selection = Object.values(tasks).filter((item) => item.value === true);\n  if (!selection.length) {\n    selection = await prompts([\n      watchMode === undefined && {\n        type: 'toggle',\n        name: 'watch',\n        message: 'Start in watch mode',\n        initial: false,\n        active: 'yes',\n        inactive: 'no',\n      },\n      {\n        type: 'autocompleteMultiselect',\n        message: 'Select the packages to check',\n        name: 'todo',\n        min: 1,\n        hint: 'You can also run directly with package name like `yarn check storybook`, or `yarn check --all` for all packages!',\n        // @ts-expect-error @types incomplete\n        optionsPerPage: windowSize.height - 3, // 3 lines for extra info\n        choices: packages.map(({ name: key }) => ({\n          value: key,\n          title: tasks[key].name || key,\n          selected: (tasks[key] && tasks[key].defaultValue) || false,\n        })),\n      },\n    ]).then(({ watch, todo }: { watch: boolean; todo: Array<string> }) => {\n      watchMode ??= watch;\n      return todo?.map((key) => tasks[key]);\n    });\n  }\n\n  process.stdout.write('Checking selected packages...\\n');\n  let lastName = '';\n\n  if (watchMode) {\n    // In watch mode, collect all files from all packages and watch them together\n    const allFiles: string[] = [];\n    const packageInfos: Array<{\n      name: string;\n      location: string;\n      cwd: string;\n      tsconfigPath: string;\n    }> = [];\n\n    selection.forEach((v) => {\n      const cwd = resolve(__dirname, '..', 'code', v.location);\n      const tsconfigPath = join(cwd, 'tsconfig.json');\n\n      try {\n        const { fileNames } = getTSFilesAndConfig(tsconfigPath, cwd);\n        allFiles.push(...fileNames, tsconfigPath);\n        packageInfos.push({ name: v.name, location: v.location, cwd, tsconfigPath });\n      } catch (error) {\n        process.stderr.write(`${picocolors.red('Error loading')} ${v.name}: ${error}\\n`);\n      }\n    });\n\n    const wp = new Watchpack({\n      aggregateTimeout: 200,\n    });\n\n    async function runAllChecks() {\n      const timestamp = new Date().toLocaleTimeString();\n      process.stdout.write(\n        `\\n${picocolors.dim(`[${timestamp}]`)} Checking packages: ${packageInfos.map((p) => picocolors.cyan(p.name)).join(', ')}...\\n`\n      );\n\n      for (const v of packageInfos) {\n        const script = join(ROOT_DIRECTORY, 'scripts', 'check', 'check-package.ts');\n        const command = `yarn exec jiti ${script}`;\n\n        try {\n          const sub = await execaCommand(command, {\n            cwd: v.cwd,\n            env: {\n              NODE_ENV: 'production',\n            },\n          });\n\n          if (sub.stdout) {\n            const prefix = `\\n\\n${picocolors.cyan(v.name)}:\\n`;\n            process.stdout.write(prefix);\n            process.stdout.write(sub.stdout);\n          }\n        } catch (error: any) {\n          const prefix = `\\n\\n${picocolors.cyan(v.name)}:\\n`;\n          process.stdout.write(prefix);\n          if (error.stdout) {\n            process.stdout.write(error.stdout);\n          }\n          if (error.stderr) {\n            process.stderr.write(error.stderr);\n          }\n        }\n      }\n\n      process.stdout.write(`${picocolors.dim('\\n\\nWatching for changes...')}\\n`);\n    }\n\n    // Run initial check then watch all files\n    runAllChecks();\n    wp.watch({\n      files: allFiles,\n      missing: [],\n      startTime: Date.now(),\n    });\n    wp.on('change', (filePath: string) => {\n      process.stdout.write(\n        `\\n${picocolors.yellow('File changed:')} ${picocolors.cyan(relative(ROOT_DIRECTORY, filePath))}\\n`\n      );\n      runAllChecks();\n    });\n\n    process.on('SIGINT', () => {\n      wp.close();\n      process.exit(0);\n    });\n  } else {\n    // If watch mode is off, check each individual package sequentially.\n    selection.forEach(async (v) => {\n      const script = join(ROOT_DIRECTORY, 'scripts', 'check', 'check-package.ts');\n      const command = `yarn exec jiti ${script}`;\n\n      const cwd = resolve(__dirname, '..', 'code', v.location);\n      const sub = execaCommand(`${command}${watchMode ? ' --watch' : ''}`, {\n        cwd,\n        env: {\n          NODE_ENV: 'production',\n        },\n      });\n\n      sub.stdout?.on('data', (data) => {\n        if (lastName !== v.name) {\n          const prefix = `${picocolors.cyan(v.name)}:\\n`;\n          process.stdout.write(prefix);\n        }\n        lastName = v.name;\n        process.stdout.write(data);\n      });\n      sub.stderr?.on('data', (data) => {\n        if (lastName !== v.name) {\n          const prefix = `${picocolors.cyan(v.name)}:\\n`;\n          process.stdout.write(prefix);\n        }\n        lastName = v.name;\n        process.stderr.write(data);\n      });\n    });\n  }\n}\n\nrun().catch((e) => {\n  process.stderr.write(`${e.toString()}\\n`);\n  process.exit(1);\n});\n"
  },
  {
    "path": "scripts/ci/common-jobs.ts",
    "content": "// eslint-disable-next-line depend/ban-dependencies\nimport glob from 'fast-glob';\nimport { join } from 'path/posix';\n\nimport { WINDOWS_ROOT_DIR, WORKING_DIR } from './utils/constants.ts';\nimport {\n  CACHE_KEYS,\n  CACHE_PATHS,\n  artifact,\n  cache,\n  git,\n  node,\n  npm,\n  server,\n  testResults,\n  verdaccio,\n  workflow,\n  workspace,\n} from './utils/helpers.ts';\nimport { defineJob, defineNoOpJob } from './utils/types.ts';\n\nconst dirname = import.meta.dirname;\n\nexport const build_linux = defineJob('Build (linux)', (workflowName) => ({\n  executor: {\n    name: 'sb_node_22_classic',\n    class: 'xlarge',\n  },\n  steps: [\n    git.checkout(),\n    npm.install('.'),\n    cache.persist(CACHE_PATHS, CACHE_KEYS()[0]),\n    git.check(),\n    npm.check(),\n    {\n      run: {\n        name: 'Compile',\n        working_directory: `code`,\n        command: 'yarn task --task compile --start-from=auto --no-link --debug',\n      },\n    },\n    {\n      run: {\n        name: 'Publish to Verdaccio',\n        working_directory: `code`,\n        command: 'yarn local-registry --publish',\n      },\n    },\n    ...workflow.reportOnFailure(workflowName),\n    artifact.persist(`code/bench/esbuild-metafiles`, 'bench'),\n    workspace.persist([\n      ...glob\n        .sync(['*/src', '*/*/src'], {\n          cwd: join(dirname, '../../code'),\n          onlyDirectories: true,\n        })\n        .flatMap((p) => [\n          `${WORKING_DIR}/code/${p.replace('src', 'dist')}`,\n          `${WORKING_DIR}/code/${p.replace('src', 'node_modules')}`,\n        ]),\n      `${WORKING_DIR}/.verdaccio-cache`,\n      `${WORKING_DIR}/code/bench`,\n    ]),\n  ],\n}));\n\nexport const fmt = defineJob('Format check', () => ({\n  executor: {\n    name: 'sb_node_22_classic',\n    class: 'medium+',\n  },\n  steps: [\n    git.checkout(),\n    npm.install('.'),\n    {\n      run: {\n        name: 'Format check',\n        command: 'yarn fmt:check',\n      },\n    },\n  ],\n}));\n\nexport const build_windows = defineJob('Build (windows)', () => ({\n  executor: {\n    name: 'win/default',\n    size: 'xlarge',\n    shell: 'bash.exe',\n  },\n  steps: [\n    git.checkout({ forceHttps: true }),\n    node.installOnWindows(),\n    npm.install('.'),\n    {\n      run: {\n        name: 'Compile',\n        working_directory: `code`,\n        command: 'yarn task --task compile --start-from=auto --no-link --debug',\n      },\n    },\n    verdaccio.start(),\n    workspace.persist(\n      [\n        ...glob\n          .sync(['*/src', '*/*/src'], {\n            cwd: join(dirname, '../../code'),\n            onlyDirectories: true,\n          })\n          .flatMap((p) => [\n            `code/${p.replace('src', 'dist')}`,\n            `code/${p.replace('src', 'node_modules')}`,\n          ]),\n        `.verdaccio-cache`,\n        `code/bench`,\n      ],\n      `${WINDOWS_ROOT_DIR}\\\\${WORKING_DIR}`\n    ),\n  ],\n}));\n\nexport const commonJobsNoOpJob = defineNoOpJob('Common Jobs', [build_linux]);\n\nexport const storybookChromatic = defineJob(\n  'Local storybook & chromatic',\n  () => ({\n    executor: {\n      name: 'sb_node_22_classic',\n      class: 'medium+',\n    },\n    steps: [\n      ...workflow.restoreLinux(),\n      {\n        run: {\n          name: 'Build internal storybook',\n          command: 'yarn storybook:ui:build',\n          working_directory: 'code',\n        },\n      },\n      {\n        run: {\n          name: 'Run Chromatic',\n          command: 'yarn storybook:ui:chromatic',\n          working_directory: 'code',\n        },\n      },\n    ],\n  }),\n  [commonJobsNoOpJob]\n);\n\nexport const check = defineJob(\n  'TypeScript validation',\n  (workflowName) => ({\n    executor: {\n      name: 'sb_node_22_classic',\n      class: 'medium+',\n    },\n    steps: [\n      ...workflow.restoreLinux(),\n      {\n        run: {\n          name: 'TypeCheck code',\n          working_directory: `code`,\n          command: 'yarn task --task check --no-link',\n        },\n      },\n      {\n        run: {\n          name: 'TypeCheck scripts',\n          working_directory: `scripts`,\n          command: 'yarn check',\n        },\n      },\n      ...workflow.reportOnFailure(workflowName),\n      ...workflow.cancelOnFailure(),\n    ],\n  }),\n  [commonJobsNoOpJob]\n);\n\nexport const lint = defineJob(\n  'ESLint',\n  () => ({\n    executor: {\n      name: 'sb_node_22_classic',\n      class: 'large',\n    },\n    steps: [\n      ...workflow.restoreLinux(),\n      {\n        run: {\n          name: 'Lint code JS',\n          working_directory: `code`,\n          command: 'yarn lint:js',\n        },\n      },\n      {\n        run: {\n          name: 'Lint scripts',\n          working_directory: `scripts`,\n          command: 'yarn lint',\n        },\n      },\n    ],\n  }),\n  [commonJobsNoOpJob]\n);\n\nexport const knip = defineJob(\n  'Knip validation',\n  () => ({\n    executor: {\n      name: 'sb_node_22_classic',\n      class: 'medium',\n    },\n    steps: [\n      ...workflow.restoreLinux(),\n      {\n        run: {\n          name: 'Run Knip',\n          working_directory: `code`,\n          command: 'yarn knip --no-exit-code',\n        },\n      },\n    ],\n  }),\n  [commonJobsNoOpJob]\n);\n\nexport const testsUnit_linux = defineJob(\n  'Tests (linux)',\n  (workflowName) => ({\n    executor: {\n      name: 'sb_node_22_classic',\n      class: 'large',\n    },\n    steps: [\n      ...workflow.restoreLinux(),\n      {\n        run: {\n          name: 'Run tests',\n          command: [\n            'TEST_FILES=$(circleci tests glob \"code/**/*.{test,spec}.{ts,tsx,js,jsx,cjs}\" \"scripts/**/*.{test,spec}.{ts,tsx,js,jsx,cjs}\" | sed \"/e2e-tests\\\\//d\" | sed \"/node_modules\\\\//d\")',\n            'echo \"$TEST_FILES\" | circleci tests run --command=\"xargs yarn test --reporter=junit --reporter=default --outputFile=./test-results/junit.xml\" --verbose',\n          ].join('\\n'),\n        },\n      },\n      testResults.persist(`test-results`),\n\n      git.check(),\n      ...workflow.reportOnFailure(workflowName),\n      ...workflow.cancelOnFailure(),\n    ],\n  }),\n  [commonJobsNoOpJob]\n);\n\nexport const testsStories_linux = defineJob(\n  'Tests stories (linux)',\n  (workflowName) => ({\n    executor: {\n      name: 'sb_playwright',\n      class: 'xlarge',\n    },\n    steps: [\n      ...workflow.restoreLinux(),\n      {\n        run: {\n          name: 'Run stories tests',\n          command: [\n            'TEST_FILES=$(circleci tests glob \"code/**/*.{stories}.{ts,tsx,js,jsx,cjs}\" | sed \"/e2e-tests\\\\//d\" | sed \"/node_modules\\\\//d\")',\n            'echo \"$TEST_FILES\" | circleci tests run --command=\"xargs yarn test --reporter=junit --reporter=default --outputFile=./test-results/junit.xml\" --verbose',\n          ].join('\\n'),\n        },\n      },\n      testResults.persist(`test-results`),\n\n      git.check(),\n      ...workflow.reportOnFailure(workflowName),\n      ...workflow.cancelOnFailure(),\n    ],\n  }),\n  [commonJobsNoOpJob]\n);\n\nexport const testUnit_windows = defineJob(\n  'Tests unit (windows)',\n  () => ({\n    executor: {\n      name: 'win/default',\n      size: 'large',\n      shell: 'bash.exe',\n    },\n    steps: [\n      ...workflow.restoreWindows(`${WINDOWS_ROOT_DIR}\\\\${WORKING_DIR}`),\n      {\n        run: {\n          command: 'yarn install',\n          name: 'Install dependencies',\n        },\n      },\n      {\n        run: {\n          command:\n            'yarn test --reporter=junit --reporter=default --outputFile=./test-results/junit.xml',\n          name: 'Run unit tests',\n        },\n      },\n      testResults.persist(`test-results`),\n    ],\n  }),\n  [build_windows]\n);\n\nexport const benchmarkPackages = defineJob(\n  'Benchmark packages',\n  () => ({\n    executor: {\n      name: 'sb_node_22_classic',\n      class: 'medium+',\n    },\n    steps: [\n      ...workflow.restoreLinux(),\n      verdaccio.start(),\n      server.wait([...verdaccio.ports]),\n      {\n        run: {\n          name: 'Benchmarking packages against base branch',\n          command:\n            'yarn bench-packages --base-branch << pipeline.parameters.ghBaseBranch >> --pull-request << pipeline.parameters.ghPrNumber >> --upload',\n          working_directory: 'scripts',\n        },\n      },\n    ],\n  }),\n  [commonJobsNoOpJob]\n);\n"
  },
  {
    "path": "scripts/ci/init-empty.ts",
    "content": "import { build_linux } from './common-jobs.ts';\nimport { WINDOWS_ROOT_DIR } from './utils/constants.ts';\nimport { server, verdaccio, workflow } from './utils/helpers.ts';\nimport {\n  type JobOrNoOpJob,\n  type Workflow,\n  defineJob,\n  defineNoOpJob,\n  isWorkflowOrAbove,\n} from './utils/types.ts';\n\nexport const defineEmptyInitFlow = (template: string) =>\n  defineJob(\n    `init-empty-${template}`,\n    () => ({\n      executor: {\n        name: 'sb_node_22_classic',\n        class: 'medium',\n      },\n      steps: [\n        ...workflow.restoreLinux(),\n        verdaccio.start(),\n        server.wait([...verdaccio.ports]),\n        {\n          run: {\n            name: 'Storybook init from empty directory (Linux NPM)',\n            working_directory: '/tmp',\n            command: [\n              `mkdir empty-${template}`,\n              `cd empty-${template}`,\n              `npm set registry http://localhost:6001`,\n              `npx storybook init --yes --package-manager npm`,\n            ].join('\\n'),\n            environment: {\n              IN_STORYBOOK_SANDBOX: true,\n              STORYBOOK_DISABLE_TELEMETRY: true,\n              STORYBOOK_INIT_EMPTY_TYPE: template,\n            },\n          },\n        },\n        {\n          run: {\n            name: 'Run storybook smoke test',\n            working_directory: `/tmp/empty-${template}`,\n            command: 'npm run storybook -- --smoke-test',\n          },\n        },\n      ],\n    }),\n\n    [initEmptyNoOpJob]\n  );\n\nexport function defineEmptyInitFeatures() {\n  return defineJob(\n    'init-features',\n    () => ({\n      executor: {\n        name: 'sb_node_22_classic',\n        class: 'medium',\n      },\n      steps: [\n        ...workflow.restoreLinux(),\n        verdaccio.start(),\n        server.wait([...verdaccio.ports]),\n        {\n          run: {\n            name: 'Storybook init from empty directory (Linux NPM)',\n            working_directory: '/tmp',\n            command: [\n              `mkdir empty-react-vite-ts`,\n              `cd empty-react-vite-ts`,\n              `npm set registry http://localhost:6001`,\n              `npx create-storybook --yes --package-manager npm --features docs test a11y --loglevel=debug`,\n            ].join('\\n'),\n            environment: {\n              IN_STORYBOOK_SANDBOX: true,\n              STORYBOOK_DISABLE_TELEMETRY: true,\n              STORYBOOK_INIT_EMPTY_TYPE: 'react-vite-ts',\n            },\n          },\n        },\n        {\n          run: {\n            name: 'Run storybook smoke test',\n            working_directory: `/tmp/empty-react-vite-ts`,\n            command: 'npx vitest',\n          },\n        },\n      ],\n    }),\n    [initEmptyNoOpJob]\n  );\n}\n\nexport function defineEmptyInitWindows() {\n  return defineJob(\n    'init-empty-windows',\n    () => ({\n      executor: {\n        name: 'win/default',\n        size: 'medium',\n        shell: 'bash.exe',\n      },\n      steps: [\n        ...workflow.restoreWindows(),\n        verdaccio.start(),\n        server.wait([...verdaccio.ports]),\n        {\n          run: {\n            name: 'Storybook init from empty directory (Windows NPM)',\n            working_directory: WINDOWS_ROOT_DIR,\n            command: [\n              `mkdir empty-react-vite-ts`,\n              `cd empty-react-vite-ts`,\n              `npm set registry http://localhost:6001`,\n              `npx storybook init --yes --package-manager npm`,\n            ].join('\\n'),\n            environment: {\n              IN_STORYBOOK_SANDBOX: true,\n              STORYBOOK_DISABLE_TELEMETRY: true,\n              STORYBOOK_INIT_EMPTY_TYPE: 'react-vite-ts',\n            },\n          },\n        },\n        {\n          run: {\n            name: 'Run storybook smoke test',\n            working_directory: `${WINDOWS_ROOT_DIR}\\\\empty-react-vite-ts`,\n            command: 'npm run storybook -- --smoke-test',\n          },\n        },\n      ],\n    }),\n    [initEmptyNoOpJob]\n  );\n}\n\nexport const initEmptyNoOpJob = defineNoOpJob('init-empty', [build_linux]);\n\nexport function getInitEmpty(workflow: Workflow) {\n  const initEmpty: JobOrNoOpJob[] = ['react-vite-ts'].map(defineEmptyInitFlow);\n\n  if (isWorkflowOrAbove(workflow, 'merged')) {\n    initEmpty.push(...['nextjs-ts', 'vue-vite-ts', 'lit-vite-ts'].map(defineEmptyInitFlow));\n  }\n  if (isWorkflowOrAbove(workflow, 'daily')) {\n    initEmpty.push(defineEmptyInitWindows());\n  }\n  if (isWorkflowOrAbove(workflow, 'normal')) {\n    initEmpty.push(defineEmptyInitFeatures());\n  }\n\n  return initEmpty;\n}\n"
  },
  {
    "path": "scripts/ci/main.ts",
    "content": "import fs from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { program } from 'commander';\nimport yml from 'yaml';\n\nimport {\n  benchmarkPackages,\n  build_linux,\n  build_windows,\n  check,\n  commonJobsNoOpJob,\n  knip,\n  lint,\n  fmt,\n  storybookChromatic,\n  testUnit_windows,\n  testsStories_linux,\n  testsUnit_linux,\n} from './common-jobs.ts';\nimport { getInitEmpty, initEmptyNoOpJob } from './init-empty.ts';\nimport { getSandboxes, sandboxesNoOpJob } from './sandboxes.ts';\nimport { getTestStorybooks, testStorybooksNoOpJob } from './test-storybooks.ts';\nimport { executors } from './utils/executors.ts';\nimport { ensureRequiredJobs } from './utils/helpers.ts';\nimport { orbs } from './utils/orbs.ts';\nimport { parameters } from './utils/parameters.ts';\nimport type {\n  JobImplementationObj,\n  JobOrNoOpJob,\n  NoOpJobImplementationObj,\n} from './utils/types.ts';\nimport { type Workflow, isWorkflowOrAbove } from './utils/types.ts';\n\nconst dirname = import.meta.dirname;\n\n/**\n * Generate the CircleCI config for a given workflow.\n *\n * @param workflow - The workflow to generate the config for.\n * @returns The generated config for CircleCI in JS format.\n */\nfunction generateConfig(workflow: Workflow) {\n  const jobs: JobOrNoOpJob[] = [];\n  if (isWorkflowOrAbove(workflow, 'docs')) {\n    jobs.push(fmt);\n  } else {\n    const sandboxes = getSandboxes(workflow);\n    const testStorybooks = getTestStorybooks(workflow);\n    const initEmpty = getInitEmpty(workflow);\n\n    if (isWorkflowOrAbove(workflow, 'daily')) {\n      jobs.push(build_windows, testUnit_windows);\n    }\n\n    jobs.push(\n      build_linux,\n      testsUnit_linux,\n      testsStories_linux,\n\n      commonJobsNoOpJob,\n      lint,\n      fmt,\n      check,\n      knip,\n\n      storybookChromatic,\n      benchmarkPackages,\n\n      sandboxesNoOpJob,\n      ...sandboxes,\n\n      testStorybooksNoOpJob,\n      ...testStorybooks,\n\n      initEmptyNoOpJob,\n      ...initEmpty\n    );\n  }\n\n  /**\n   * If you want to filter down to a particular job, e.g.for debugging purposes.. you can do that\n   * here.\n   *\n   * You can filter on the `job.id` for example.\n   *\n   * Though is also possible to comment-out certain sandboxes in`sandbox-templates.ts`, or comment\n   * out `todos.push`-statements above.\n   *\n   * You do not need to consider the `requires` field, as the `ensureRequiredJobs` function will\n   * handle that for you.\n   *\n   * @example\n   *\n   * ```ts\n   * const filteredTodos = todos.filter((job) => !!job.id.includes('qwik'));\n   * ```\n   */\n  const filteredJobs = jobs.filter((job) => !!job);\n\n  const isDebugging = filteredJobs.length !== jobs.length;\n\n  const ensuredJobs = ensureRequiredJobs(filteredJobs);\n\n  const sortedJobs = ensuredJobs.sort((a, b) => {\n    if (a.requires.length && b.requires.length) {\n      return a.requires.length - b.requires.length;\n    }\n    if (a.requires.length) {\n      return 1;\n    }\n    if (b.requires.length) {\n      return -1;\n    }\n    return a.id.localeCompare(b.id);\n  });\n\n  return {\n    version: 2.1,\n    orbs,\n    executors,\n    parameters,\n\n    jobs: sortedJobs.reduce(\n      (acc, job) => {\n        acc[job.id] =\n          typeof job.implementation === 'function'\n            ? job.implementation(workflow)\n            : job.implementation;\n        return acc;\n      },\n      {} as Record<string, JobImplementationObj | NoOpJobImplementationObj>\n    ),\n    workflows: {\n      [`${workflow}-generated${isDebugging ? '-debug' : ''}`]: {\n        jobs: sortedJobs.map((t) =>\n          t.requires && t.requires.length > 0\n            ? { [t.id]: { requires: t.requires.map((r) => r.id) } }\n            : t.id\n        ),\n      },\n    },\n  };\n}\n\nconsole.log('Generating CircleCI config...');\nconsole.log('--------------------------------');\n\nprogram\n  .description('Generate CircleCI config')\n  .requiredOption('-w, --workflow <string>', 'Workflow to generate config for')\n  .parse(process.argv);\n\nawait fs.writeFile(\n  join(dirname, '../../.circleci/config.generated.yml'),\n  yml.stringify(generateConfig(program.opts().workflow), null, {\n    lineWidth: 1200,\n    indent: 4,\n  })\n);\n"
  },
  {
    "path": "scripts/ci/sandboxes.ts",
    "content": "import { join } from 'path';\n\nimport * as sandboxTemplates from '../../code/lib/cli-storybook/src/sandbox-templates.ts';\nimport { type TemplateKey } from '../../code/lib/cli-storybook/src/sandbox-templates.ts';\nimport { build_linux } from './common-jobs.ts';\nimport { LINUX_ROOT_DIR, SANDBOX_DIR, WINDOWS_ROOT_DIR, WORKING_DIR } from './utils/constants.ts';\nimport {\n  CACHE_KEYS,\n  artifact,\n  cache,\n  server,\n  testResults,\n  toId,\n  verdaccio,\n  workflow,\n  workspace,\n} from './utils/helpers.ts';\nimport { defineJob, defineNoOpJob, isWorkflowOrAbove } from './utils/types.ts';\nimport type { JobOrNoOpJob, Workflow } from './utils/types.ts';\n\nfunction getSandboxSetupSteps(template: string) {\n  const extraSteps = [];\n  const templateData = sandboxTemplates.allTemplates[template as TemplateKey];\n\n  if (templateData.extraCiSteps?.ensureMinNodeVersion) {\n    extraSteps.push({\n      'node/install': {\n        'install-yarn': true,\n        // Currently using Node 22.22.1 as minimum supported version for Angular sandboxes\n        'node-version': '22.22.1',\n      },\n    });\n  }\n\n  return extraSteps;\n}\n\nfunction defineSandboxJob_build({\n  directory,\n  name,\n  template,\n  requires,\n}: {\n  directory: string;\n  name: string;\n  requires: JobOrNoOpJob[];\n  template: string;\n}) {\n  return defineJob(\n    name,\n    () => ({\n      executor: {\n        name: 'sb_node_22_classic',\n        class: 'medium+',\n      },\n      steps: [\n        ...getSandboxSetupSteps(template),\n        ...workflow.restoreLinux(),\n        {\n          run: {\n            name: 'Build storybook',\n            command: `yarn task build --template ${template} --no-link -s build`,\n          },\n        },\n        workspace.persist([`${SANDBOX_DIR}/${directory}/storybook-static`]),\n      ],\n    }),\n    requires\n  );\n}\nfunction defineSandboxJob_dev({\n  name,\n  template,\n  requires,\n  options,\n}: {\n  name: string;\n  requires: JobOrNoOpJob[];\n  template: string;\n  options: {\n    e2e: boolean;\n  };\n}) {\n  return defineJob(\n    name,\n    () => ({\n      executor: options.e2e\n        ? {\n            name: 'sb_playwright',\n            class: 'medium+',\n          }\n        : {\n            name: 'sb_node_22_classic',\n            class: 'medium',\n          },\n      steps: [\n        ...getSandboxSetupSteps(template),\n        ...workflow.restoreLinux(),\n        ...(options.e2e\n          ? [\n              {\n                run: {\n                  name: 'Run storybook',\n                  working_directory: 'code',\n                  background: true,\n                  command: `yarn task dev --template ${template} --no-link -s dev`,\n                },\n              },\n              server.wait(['6006']),\n              {\n                run: {\n                  name: 'Running E2E Tests',\n                  command: [\n                    'TEST_FILES=$(circleci tests glob \"code/e2e-tests/*.{test,spec}.{ts,js,mjs}\")',\n                    `echo \"$TEST_FILES\" | circleci tests run --command=\"xargs yarn task e2e-tests-dev --template ${template} --no-link -s e2e-tests-dev --junit\" --verbose --index=0 --total=1`,\n                  ].join('\\n'),\n                },\n              },\n              artifact.persist(join(LINUX_ROOT_DIR, WORKING_DIR, 'test-results'), 'test-results'),\n              artifact.persist(\n                join(LINUX_ROOT_DIR, WORKING_DIR, 'code', 'playwright-results'),\n                'playwright-results'\n              ),\n              testResults.persist(join(LINUX_ROOT_DIR, WORKING_DIR, 'test-results')),\n            ]\n          : [\n              {\n                run: {\n                  name: 'Run storybook smoke test',\n                  working_directory: 'code',\n                  background: true,\n                  command: `yarn task smoke-test --template ${template} --no-link -s dev`,\n                },\n              },\n            ]),\n      ],\n    }),\n    requires\n  );\n}\n\nexport function defineSandboxFlow<Key extends string>(key: Key) {\n  const id = toId(key);\n  const data = sandboxTemplates.allTemplates[key as keyof typeof sandboxTemplates.allTemplates];\n  const { skipTasks = [], name } = data;\n\n  const path = key.replace('/', '-');\n\n  const createJob = defineJob(\n    `${name} (create)`,\n    () => ({\n      executor: {\n        name: 'sb_node_22_browsers',\n        class: 'large',\n      },\n      steps: [\n        ...getSandboxSetupSteps(key),\n        ...workflow.restoreLinux(),\n        verdaccio.start(),\n        {\n          run: {\n            name: 'Start Event Collector',\n            working_directory: `scripts`,\n            background: true,\n            command: 'yarn jiti ./event-log-collector.ts',\n          },\n        },\n        server.wait([...verdaccio.ports, '6007']),\n        {\n          run: {\n            name: 'Setup Corepack',\n            command: [\n              //\n              'sudo corepack enable',\n              'which yarn',\n              'yarn --version',\n            ].join('\\n'),\n          },\n        },\n        ...('inDevelopment' in data && data.inDevelopment\n          ? [\n              {\n                run: {\n                  name: 'Generate Sandbox',\n                  command: `yarn task generate --template ${key} --no-link -s generate --debug`,\n                  environment: {\n                    STORYBOOK_SANDBOX_GENERATE: 1,\n                    STORYBOOK_TELEMETRY_DEBUG: 1,\n                    STORYBOOK_TELEMETRY_URL: 'http://127.0.0.1:6007/event-log',\n                  },\n                },\n              },\n            ]\n          : []),\n        {\n          run: {\n            name: 'Create Sandbox',\n            command: `yarn task sandbox --template ${key} --no-link -s sandbox --debug`,\n            environment: {\n              STORYBOOK_CLI_SKIP_PLAYWRIGHT_INSTALLATION: 1,\n              STORYBOOK_TELEMETRY_DEBUG: 1,\n              STORYBOOK_TELEMETRY_URL: 'http://127.0.0.1:6007/event-log',\n            },\n          },\n        },\n        /**\n         * Due to the way we create sandboxes, a unique situation arises where a sveltekit\n         * cache-config-file is missing. This generates it.\n         */\n        ...(id.includes('svelte-kit')\n          ? [\n              {\n                run: {\n                  name: 'Run prepare',\n                  working_directory: `${LINUX_ROOT_DIR}/${SANDBOX_DIR}/${id}`,\n                  command: `yarn prepare`,\n                },\n              },\n            ]\n          : []),\n        artifact.persist(`${LINUX_ROOT_DIR}/${SANDBOX_DIR}/${id}/debug-storybook.log`, 'logs'),\n        workspace.persist([`${SANDBOX_DIR}/${id}`]),\n      ],\n    }),\n    [sandboxesNoOpJob]\n  );\n  const buildJob = defineSandboxJob_build({\n    name: `${name} (build)`,\n    template: key,\n    directory: id,\n    requires: [createJob],\n  });\n  const devJob = defineSandboxJob_dev({\n    name: `${name} (dev)`,\n    template: key,\n    requires: [createJob],\n    options: { e2e: !skipTasks?.includes('e2e-tests-dev') },\n  });\n  const chromaticJob = defineJob(\n    `${name} (chromatic)`,\n    () => ({\n      executor: {\n        name: 'sb_node_22_classic',\n        class: 'medium',\n      },\n      steps: [\n        ...getSandboxSetupSteps(key),\n        'checkout', // we need the full git history for chromatic\n        workspace.attach(),\n        cache.attach(CACHE_KEYS()),\n        {\n          // we copy to the working directory to get git history, which chromatic needs for baselines\n          run: {\n            name: 'Copy sandbox to working directory',\n            command: `cp ${join(LINUX_ROOT_DIR, SANDBOX_DIR)} ${join(LINUX_ROOT_DIR, WORKING_DIR, 'sandbox')} -r --remove-destination`,\n          },\n        },\n        {\n          run: {\n            name: 'Running Chromatic',\n            command: `yarn task chromatic --template ${key} --no-link -s chromatic`,\n            environment: {\n              STORYBOOK_SANDBOX_ROOT: `./sandbox`,\n            },\n          },\n        },\n      ],\n    }),\n    [buildJob]\n  );\n  const vitestJob = defineJob(\n    `${name} (vitest)`,\n    () => ({\n      executor: {\n        name: 'sb_playwright',\n        class: 'medium',\n      },\n      steps: [\n        ...getSandboxSetupSteps(key),\n        ...workflow.restoreLinux(),\n        {\n          run: {\n            name: 'Running Vitest',\n            command: `yarn task vitest-integration --template ${key} --no-link -s vitest-integration --junit`,\n          },\n        },\n        testResults.persist(join(LINUX_ROOT_DIR, WORKING_DIR, 'test-results')),\n      ],\n    }),\n    [buildJob]\n  );\n  const e2eJob = defineJob(\n    `${name} (e2e)`,\n    () => ({\n      executor: {\n        name: 'sb_playwright',\n        class: 'medium+',\n      },\n      steps: [\n        ...getSandboxSetupSteps(key),\n        ...workflow.restoreLinux(),\n        {\n          run: {\n            name: 'Serve storybook',\n            background: true,\n            command: `yarn task serve --template ${key} --no-link -s serve`,\n          },\n        },\n        server.wait(['8001']),\n        {\n          run: {\n            name: 'Running E2E Tests',\n            command: [\n              `TEST_FILES=$(circleci tests glob \"code/e2e-tests/*.{test,spec}.{ts,js,mjs}\")`,\n              `echo \"$TEST_FILES\" | circleci tests run --command=\"xargs yarn task e2e-tests --template ${key} --no-link -s e2e-tests --junit\" --verbose --index=0 --total=1`,\n            ].join('\\n'),\n          },\n        },\n        artifact.persist(join(LINUX_ROOT_DIR, WORKING_DIR, 'test-results'), 'test-results'),\n        artifact.persist(\n          join(LINUX_ROOT_DIR, WORKING_DIR, 'code', 'playwright-results'),\n          'playwright-results'\n        ),\n        testResults.persist(join(LINUX_ROOT_DIR, WORKING_DIR, 'test-results')),\n      ],\n    }),\n    [buildJob]\n  );\n  const testRunnerJob = defineJob(\n    `${name} (test-runner)`,\n    () => ({\n      executor: {\n        name: 'sb_playwright',\n        class: 'medium',\n      },\n      steps: [\n        ...getSandboxSetupSteps(key),\n        ...workflow.restoreLinux(),\n        {\n          run: {\n            name: 'Running test-runner',\n            command: `yarn task test-runner --template ${key} --no-link -s test-runner --junit`,\n          },\n        },\n        testResults.persist(join(LINUX_ROOT_DIR, WORKING_DIR, 'test-results')),\n      ],\n    }),\n    [buildJob]\n  );\n\n  const jobs = [\n    createJob,\n    buildJob,\n    devJob,\n    !skipTasks?.includes('chromatic') ? chromaticJob : undefined,\n    !skipTasks?.includes('vitest-integration') ? vitestJob : undefined,\n    !skipTasks?.includes('e2e-tests') ? e2eJob : undefined,\n\n    /**\n     * Question: What is this for? Do we want to know if the test-runner works? Or do we want to\n     * know if the sandbox works?\n     *\n     * If it's the first, we actually only need to run the test-runner job once, on any sandbox. If\n     * it's the second, we need to run the test-runner job for each sandbox, but then we don't need\n     * to run it when we're already running the chromatic job.\n     */\n    !skipTasks?.includes('test-runner') && skipTasks.includes('chromatic')\n      ? testRunnerJob\n      : undefined,\n  ].filter(Boolean);\n  return {\n    name: key,\n    path,\n    jobs,\n  };\n}\n\nexport function defineSandboxTestRunner(sandbox: ReturnType<typeof defineSandboxFlow>) {\n  return defineJob(\n    `${sandbox.jobs[1].id}-test-runner`,\n    () => ({\n      executor: {\n        name: 'sb_playwright',\n        class: 'medium',\n      },\n      steps: [\n        ...getSandboxSetupSteps(sandbox.name),\n        ...workflow.restoreLinux(),\n        {\n          run: {\n            name: 'Running test-runner',\n            command: `yarn task test-runner --template ${sandbox.name} --no-link -s test-runner --junit`,\n          },\n        },\n        testResults.persist(join(LINUX_ROOT_DIR, WORKING_DIR, 'test-results')),\n      ],\n    }),\n    [sandbox.jobs[1]]\n  );\n}\n\nexport function defineWindowsSandboxDev(sandbox: ReturnType<typeof defineSandboxFlow>) {\n  return defineJob(\n    `${sandbox.jobs[2].id}-windows`,\n    () => ({\n      executor: {\n        name: 'win/default',\n        size: 'large',\n        shell: 'bash.exe',\n      },\n      steps: [\n        ...workflow.restoreWindows(),\n        verdaccio.start(),\n        server.wait([...verdaccio.ports]),\n        {\n          run: {\n            name: 'Run Install',\n            working_directory: `${WINDOWS_ROOT_DIR}\\\\${SANDBOX_DIR}\\\\${sandbox.path}`,\n            command: 'yarn install',\n          },\n        },\n        {\n          run: {\n            name: 'Install playwright',\n            command: 'yarn playwright install chromium --with-deps',\n          },\n        },\n        {\n          run: {\n            name: 'Run storybook',\n            background: true,\n            working_directory: `${WINDOWS_ROOT_DIR}\\\\${SANDBOX_DIR}\\\\${sandbox.path}`,\n            command: 'yarn storybook --port 8001',\n          },\n        },\n        server.wait(['8001']),\n        {\n          run: {\n            name: 'Running E2E Tests',\n            working_directory: 'code',\n            command: `yarn task e2e-tests-dev --template ${sandbox.name} --no-link -s e2e-tests-dev --junit`,\n          },\n        },\n        testResults.persist(`${WINDOWS_ROOT_DIR}\\\\${WORKING_DIR}\\\\test-results`),\n      ],\n    }),\n    [sandbox.jobs[0]]\n  );\n}\n\nexport function defineWindowsSandboxBuild(sandbox: ReturnType<typeof defineSandboxFlow>) {\n  return defineJob(\n    `${sandbox.jobs[1].id}-windows`,\n    () => ({\n      executor: {\n        name: 'win/default',\n        size: 'large',\n        shell: 'bash.exe',\n      },\n      steps: [\n        ...workflow.restoreWindows(),\n        verdaccio.start(),\n        server.wait([...verdaccio.ports]),\n        {\n          run: {\n            name: 'Run Install',\n            working_directory: `${WINDOWS_ROOT_DIR}\\\\${SANDBOX_DIR}\\\\${sandbox.path}`,\n            command: 'yarn install',\n          },\n        },\n        {\n          run: {\n            name: 'Install playwright',\n            command: 'yarn playwright install chromium --with-deps',\n          },\n        },\n        {\n          run: {\n            name: 'Build storybook',\n            command: `yarn task build --template ${sandbox.name} --no-link -s build`,\n          },\n        },\n        {\n          run: {\n            name: 'Serve storybook',\n            background: true,\n            command: `yarn task serve --template ${sandbox.name} --no-link -s serve`,\n          },\n        },\n        server.wait(['8001']),\n        {\n          run: {\n            name: 'Running E2E Tests',\n            working_directory: 'code',\n            command: `yarn task e2e-tests --template ${sandbox.name} --no-link -s e2e-tests`,\n          },\n        },\n      ],\n    }),\n    [sandbox.jobs[0]]\n  );\n}\n\nexport const sandboxesNoOpJob = defineNoOpJob('sandboxes', [build_linux]);\n\nconst getListOfSandboxes = (workflow: Workflow) => {\n  switch (workflow) {\n    case 'normal':\n      return sandboxTemplates.normal;\n    case 'merged':\n      return sandboxTemplates.merged;\n    case 'daily':\n      return sandboxTemplates.daily;\n    default:\n      return [];\n  }\n};\n\nexport function getSandboxes(workflow: Workflow) {\n  const sandboxes = getListOfSandboxes(workflow).map(defineSandboxFlow);\n\n  const list: JobOrNoOpJob[] = sandboxes.flatMap((sandbox) => sandbox.jobs);\n\n  if (isWorkflowOrAbove(workflow, 'daily')) {\n    const windows_sandbox_build = defineWindowsSandboxBuild(sandboxes[0]);\n    const windows_sandbox_dev = defineWindowsSandboxDev(sandboxes[0]);\n    const testRunner = defineSandboxTestRunner(sandboxes[0]);\n\n    list.push(windows_sandbox_build, windows_sandbox_dev, testRunner);\n  }\n\n  return list;\n}\n"
  },
  {
    "path": "scripts/ci/test-storybooks.ts",
    "content": "import { readFileSync } from 'fs';\nimport { join } from 'path/posix';\n\nimport { build_linux } from './common-jobs.ts';\nimport { artifact, workflow } from './utils/helpers.ts';\nimport {\n  type JobOrNoOpJob,\n  type Workflow,\n  defineJob,\n  defineNoOpJob,\n  isWorkflowOrAbove,\n} from './utils/types.ts';\n\nexport function definePortableStoryTest(directory: string) {\n  const working_directory = `test-storybooks/portable-stories-kitchen-sink/${directory}`;\n\n  const { scripts } = JSON.parse(\n    readFileSync(join(import.meta.dirname, '..', '..', working_directory, 'package.json'), 'utf8')\n  );\n\n  return defineJob(\n    `test-storybooks-portable-${directory}`,\n    () => ({\n      executor: {\n        name: 'sb_playwright',\n        class: 'medium+',\n      },\n      steps: [\n        ...workflow.restoreLinux(),\n        {\n          run: {\n            name: 'Install dependencies',\n            working_directory,\n            command: 'yarn install --no-immutable',\n            environment: {\n              YARN_ENABLE_IMMUTABLE_INSTALLS: false,\n            },\n          },\n        },\n        {\n          run: {\n            name: 'Run Jest tests',\n            working_directory,\n            command: 'yarn jest',\n          },\n        },\n        {\n          run: {\n            name: 'Run Vitest tests',\n            working_directory,\n            command: 'yarn vitest',\n          },\n        },\n        {\n          run: {\n            name: 'Run Playwright CT tests',\n            working_directory,\n            command: 'yarn playwright-ct',\n          },\n        },\n        ...(scripts['playwright-e2e']\n          ? [\n              {\n                run: {\n                  name: 'Run Playwright E2E tests',\n                  working_directory,\n                  command: 'yarn playwright-e2e',\n                },\n              },\n              artifact.persist(join(working_directory, 'test-results'), 'playwright'),\n            ]\n          : []),\n        {\n          run: {\n            name: 'Run Cypress CT tests',\n            working_directory,\n            command: 'yarn cypress',\n          },\n        },\n      ],\n    }),\n    [testStorybooksNoOpJob]\n  );\n}\n\nexport function definePortableStoryTestPNP() {\n  return defineJob(\n    'test-storybooks-pnp',\n    () => ({\n      executor: {\n        name: 'sb_node_22_classic',\n        class: 'medium',\n      },\n      steps: [\n        ...workflow.restoreLinux(),\n        {\n          run: {\n            name: 'Install dependencies',\n            working_directory: 'test-storybooks/yarn-pnp',\n            command: 'yarn install --no-immutable',\n            environment: {\n              YARN_ENABLE_IMMUTABLE_INSTALLS: false,\n            },\n          },\n        },\n        {\n          run: {\n            name: 'Run Storybook smoke test',\n            working_directory: 'test-storybooks/yarn-pnp',\n            command: 'yarn storybook --smoke-test',\n          },\n        },\n      ],\n    }),\n    [testStorybooksNoOpJob]\n  );\n}\n\nexport function definePortableStoryTestVitest3() {\n  return defineJob(\n    'test-storybooks-portable-vitest3',\n    () => ({\n      executor: {\n        name: 'sb_playwright',\n        class: 'medium',\n      },\n      steps: [\n        ...workflow.restoreLinux(),\n        {\n          run: {\n            name: 'Install dependencies',\n            working_directory: 'test-storybooks/portable-stories-kitchen-sink/react-vitest-3',\n            command: 'yarn install --no-immutable',\n            environment: {\n              YARN_ENABLE_IMMUTABLE_INSTALLS: false,\n            },\n          },\n        },\n        {\n          run: {\n            name: 'Run Playwright E2E tests',\n            working_directory: 'test-storybooks/portable-stories-kitchen-sink/react-vitest-3',\n            command: 'yarn playwright-e2e',\n          },\n        },\n      ],\n    }),\n    [testStorybooksNoOpJob]\n  );\n}\n\nexport const testStorybooksNoOpJob = defineNoOpJob('test-storybooks', [build_linux]);\n\nexport function getTestStorybooks(workflow: Workflow) {\n  const testStorybooks: JobOrNoOpJob[] = ['react', 'vue3', 'svelte', 'nextjs'].map(\n    definePortableStoryTest\n  );\n\n  if (isWorkflowOrAbove(workflow, 'daily')) {\n    testStorybooks.push(definePortableStoryTestPNP());\n  }\n\n  if (isWorkflowOrAbove(workflow, 'merged')) {\n    testStorybooks.push(definePortableStoryTestVitest3());\n  }\n\n  return testStorybooks;\n}\n"
  },
  {
    "path": "scripts/ci/utils/constants.ts",
    "content": "/**\n * This is the root directory for Linux CI jobs.\n *\n * Windows CI jobs use a different root directory!\n *\n * @example /tmp/project/code\n *\n * @example C:\\Users\\circleci\\project\\code\n *\n * @example /tmp/storybook-sandboxes\n *\n * @example C:\\Users\\circleci\\storybook-sandboxes\n *\n * To ensure the correct paths are used across config generation, we use the following constants.\n */\nexport const LINUX_ROOT_DIR = '/tmp';\nexport const WINDOWS_ROOT_DIR = 'C:\\\\Users\\\\circleci';\nexport const WORKING_DIR = `project`;\nexport const SANDBOX_DIR = `storybook-sandboxes`;\n"
  },
  {
    "path": "scripts/ci/utils/executors.ts",
    "content": "import { LINUX_ROOT_DIR, WORKING_DIR } from './constants.ts';\n\nexport const executors = {\n  sb_node_22_browsers: {\n    docker: [\n      {\n        environment: {\n          NODE_OPTIONS: '--max_old_space_size=6144',\n        },\n        image: 'cimg/node:22.22.1-browsers',\n      },\n    ],\n    parameters: {\n      class: {\n        default: 'small',\n        description: 'The Resource class',\n        enum: ['small', 'medium', 'medium+', 'large', 'xlarge'],\n        type: 'enum',\n      },\n    },\n    resource_class: '<<parameters.class>>',\n    working_directory: `${LINUX_ROOT_DIR}/${WORKING_DIR}`,\n  },\n  sb_node_22_classic: {\n    docker: [\n      {\n        environment: {\n          NODE_OPTIONS: '--max_old_space_size=6144',\n        },\n        image: 'cimg/node:22.22.1',\n      },\n    ],\n    parameters: {\n      class: {\n        default: 'small',\n        description: 'The Resource class',\n        enum: ['small', 'medium', 'medium+', 'large', 'xlarge'],\n        type: 'enum',\n      },\n    },\n    resource_class: '<<parameters.class>>',\n    working_directory: `${LINUX_ROOT_DIR}/${WORKING_DIR}`,\n  },\n  sb_playwright: {\n    docker: [\n      {\n        environment: {\n          NODE_OPTIONS: '--max_old_space_size=6144',\n        },\n        image: 'mcr.microsoft.com/playwright:v1.58.2-noble',\n      },\n    ],\n    parameters: {\n      class: {\n        default: 'small',\n        description: 'The Resource class',\n        enum: ['small', 'medium', 'medium+', 'large', 'xlarge'],\n        type: 'enum',\n      },\n    },\n    resource_class: '<<parameters.class>>',\n    working_directory: `${LINUX_ROOT_DIR}/${WORKING_DIR}`,\n  },\n} as const;\n"
  },
  {
    "path": "scripts/ci/utils/helpers.ts",
    "content": "import { LINUX_ROOT_DIR, WINDOWS_ROOT_DIR } from './constants.ts';\nimport { type JobOrNoOpJob, type Workflow } from './types.ts';\n\nexport const workspace = {\n  attach: (at = LINUX_ROOT_DIR) => {\n    return {\n      attach_workspace: {\n        at,\n      },\n    };\n  },\n  persist: (paths: string[], root = LINUX_ROOT_DIR) => {\n    return {\n      persist_to_workspace: {\n        paths,\n        root,\n      },\n    };\n  },\n};\n\nexport const cache = {\n  attach: (keys: string[]) => {\n    return {\n      restore_cache: {\n        keys,\n      },\n    };\n  },\n  persist: (paths: string[], key: string) => {\n    return {\n      save_cache: {\n        paths,\n        key,\n      },\n    };\n  },\n};\n\nexport const artifact = {\n  persist: (path: string, destination: string) => {\n    return {\n      store_artifacts: {\n        path,\n        destination,\n      },\n    };\n  },\n};\n\nexport const git = {\n  checkout: ({ forceHttps = false, shallow = true } = {}) => {\n    const flags = [];\n    if (shallow) {\n      flags.push('--depth 1');\n    } else {\n      flags.push('--depth 500');\n    }\n\n    if (forceHttps) {\n      flags.push('--config url.\"https://github.com/\".insteadOf=ssh://git@github.com/');\n      flags.push('--config url.\"https://github.com/\".insteadOf=git@github.com:');\n    }\n    return {\n      'git-shallow-clone/checkout_advanced': {\n        clone_options: flags.join(' '),\n      },\n    };\n  },\n  check: () => {\n    return {\n      run: {\n        name: 'Ensure no changes pending',\n        command: 'git diff --exit-code',\n      },\n    };\n  },\n};\n\nexport const node = {\n  installOnWindows: () => {\n    return {\n      run: {\n        name: 'Install Node + Yarn',\n        shell: 'powershell.exe',\n        command: [\n          '$nodeVersion = Get-Content .nvmrc | Select-Object -First 1',\n          'nvm install $nodeVersion',\n          'nvm use $nodeVersion',\n          'corepack enable',\n          'corepack prepare yarn@stable --activate',\n        ].join('\\n'),\n      },\n    };\n  },\n};\n\nexport const npm = {\n  installScripts: () => {\n    return {\n      run: {\n        name: 'Install scripts',\n        command: 'yarn workspaces focus @storybook/scripts',\n      },\n    };\n  },\n  install: (appDir: string, pkgManager: string = 'yarn') => {\n    return {\n      'node/install-packages': {\n        'app-dir': appDir,\n        'pkg-manager': pkgManager,\n        'cache-only-lockfile': true,\n      },\n    };\n  },\n  check: () => {\n    return {\n      run: {\n        name: 'Check for dedupe',\n        command: 'yarn dedupe --check',\n      },\n    };\n  },\n};\n\nexport function toId(name: string) {\n  // replace all non-alphanumeric characters with a hyphen\n  // trim leading and trailing hyphens\n  return name\n    .toLowerCase()\n    .replace(/[^a-z0-9]/g, '-')\n    .replace(/^-+|-+$/g, '');\n}\n\nexport const server = {\n  wait: (ports: string[]) => {\n    return {\n      run: {\n        name: 'Wait on servers',\n        working_directory: `code`,\n        command: ports.map((port) => `yarn wait-on tcp:127.0.0.1:${port}`).join('\\n'),\n      },\n    };\n  },\n};\n\nexport const verdaccio = {\n  start: () => {\n    return {\n      run: {\n        name: 'Verdaccio',\n        working_directory: `code`,\n        background: true,\n        command: 'yarn local-registry --open',\n      },\n    };\n  },\n  publish: () => {\n    return {\n      run: {\n        name: 'Publish to Verdaccio',\n        working_directory: `code`,\n        command: 'yarn local-registry --publish',\n      },\n    };\n  },\n  ports: ['6001', '6002'],\n};\n\nexport const workflow = {\n  restoreLinux: () => [\n    //\n    git.checkout(),\n    workspace.attach(),\n    cache.attach(CACHE_KEYS()),\n  ],\n  restoreWindows: (at = WINDOWS_ROOT_DIR) => [\n    git.checkout({ forceHttps: true }),\n    node.installOnWindows(),\n    workspace.attach(at),\n    /**\n     * I really wish this wasn't needed, but it is. I tried a lot of things to get it to not be\n     * needed, but ultimately, something kept failing. At this point I gave up:\n     * https://app.circleci.com/pipelines/github/storybookjs/storybook/110923/workflows/50076187-a5a7-4955-bff4-30bf9aec465c/jobs/976355\n     *\n     * So if you see a way to debug/solve those failing tests, please do so.\n     */\n    {\n      run: {\n        name: 'Install dependencies',\n        command: 'yarn install',\n      },\n    },\n  ],\n  cancelOnFailure: () => {\n    return [\n      {\n        run: {\n          name: 'Cancel current workflow',\n          when: 'on_fail',\n          command:\n            'curl -X POST --header \"Content-Type: application/json\" \"https://circleci.com/api/v2/workflow/${CIRCLE_WORKFLOW_ID}/cancel?circle-token=${WORKFLOW_CANCELER}\"',\n        },\n      },\n    ];\n  },\n  reportOnFailure: (workflow: Workflow, template: string = 'none') => {\n    return [\n      {\n        run: {\n          name: 'Un-shallow git',\n          when: 'on_fail',\n          command: 'git fetch --unshallow',\n        },\n      },\n      {\n        run: {\n          name: 'Report failure',\n          when: 'on_fail',\n          command: 'echo \"Workflow failed\"',\n        },\n      },\n      {\n        'discord/status': {\n          only_for_branches: ['main', 'next', 'next-release', 'latest-release'].join(','),\n          fail_only: true,\n          failure_message: `$(yarn get-report-message ${workflow} ${template})`,\n        },\n      },\n    ];\n  },\n};\n\nexport const CACHE_KEYS = (platform = 'linux') =>\n  [\n    `v5-${platform}-node_modules`,\n    '{{ checksum \".nvmrc\" }}',\n    '{{ checksum \".yarnrc.yml\" }}',\n    '{{ checksum \"yarn.lock\" }}',\n  ].map((_, index, list) => {\n    return list.slice(0, list.length - index).join('/');\n  });\n\nexport const CACHE_PATHS = [\n  '.yarn/cache',\n  '.yarn/unplugged',\n  '.yarn/build-state.yml',\n  '.yarn/root-install-state.gz',\n  'node_modules',\n  'code/node_modules',\n  'scripts/node_modules',\n];\n\nexport const testResults = {\n  persist: (path: string) => {\n    return {\n      store_test_results: {\n        path,\n      },\n    };\n  },\n};\n\n/**\n * We ensure that if (due to filtering for example) any required jobs are not present in the todos\n * array, we add them back in. This is recursive, as a required job can have required jobs itself.\n */\nexport function ensureRequiredJobs(jobs: JobOrNoOpJob[]): JobOrNoOpJob[] {\n  const results: JobOrNoOpJob[] = [];\n  while (jobs.length > 0) {\n    const job = jobs.shift();\n    if (job) {\n      if (results.find((r) => r.id === job.id)) {\n        continue;\n      }\n      results.push(job);\n      jobs.push(...job.requires);\n    }\n  }\n  return results;\n}\n"
  },
  {
    "path": "scripts/ci/utils/orbs.ts",
    "content": "/**\n * This is the list of orbs that are used in the CI config.\n *\n * These should be regularly updated to the latest version.\n *\n * @see https://circleci.com/developer/orbs\n */\nexport const orbs = {\n  // https://circleci.com/developer/orbs/orb/circleci/browser-tools\n  'browser-tools': 'circleci/browser-tools@2.3.2',\n\n  // https://circleci.com/developer/orbs/orb/codecov/codecov\n  codecov: 'codecov/codecov@5.4.3',\n\n  // https://circleci.com/developer/orbs/orb/antonioned/discord\n  discord: 'antonioned/discord@0.1.0',\n\n  // https://circleci.com/developer/orbs/orb/guitarrapc/git-shallow-clone\n  'git-shallow-clone': 'guitarrapc/git-shallow-clone@2.8.0',\n\n  // https://circleci.com/developer/orbs/orb/circleci/node\n  node: 'circleci/node@7.2.1',\n\n  // https://circleci.com/developer/orbs/orb/nrwl/nx\n  nx: 'nrwl/nx@1.7.0',\n\n  // https://circleci.com/developer/orbs/orb/circleci/windows\n  win: 'circleci/windows@5.1.1',\n};\n"
  },
  {
    "path": "scripts/ci/utils/parameters.ts",
    "content": "/** These are parameters that the CircleCI API is called with. */\nexport const parameters = {\n  ghBaseBranch: {\n    default: 'next',\n    description: 'The name of the base branch (the target of the PR)',\n    type: 'string',\n  },\n  ghPrNumber: {\n    default: '',\n    description: 'The PR number',\n    type: 'string',\n  },\n  workflow: {\n    default: 'skipped',\n    description: 'Which workflow to run',\n    enum: ['normal', 'merged', 'daily', 'skipped', 'docs'] as const,\n    type: 'enum',\n  },\n};\n"
  },
  {
    "path": "scripts/ci/utils/types.ts",
    "content": "import type { executors } from './executors.ts';\nimport { toId } from './helpers.ts';\nimport type { parameters } from './parameters.ts';\n\nexport type Job<K extends string> = {\n  id: string;\n  name: K;\n  implementation: (workflow: Workflow) => JobImplementationObj | NoOpJobImplementationObj;\n  requires: JobOrNoOpJob[];\n};\n\nexport type JobOrNoOpJob = Job<string>;\n\nexport type NoOpJobImplementationObj = {\n  type: 'no-op';\n};\n\nexport type NoOpJobImplementation = (workflow: Workflow) => NoOpJobImplementationObj;\n\nexport type JobImplementationObj = {\n  executor:\n    | {\n        name: keyof typeof executors;\n        class: 'small' | 'medium' | 'medium+' | 'large' | 'xlarge';\n      }\n    | {\n        name: 'win/default';\n        size: 'small' | 'medium' | 'medium+' | 'large' | 'xlarge';\n      };\n  /**\n   * The steps to run in the job.\n   *\n   * @example\n   *\n   * ```ts\n   * {\n   *   run: {\n   *     name: string,\n   *     working_directory: string,\n   *     command: string,\n   *     background: boolean,\n   *     shell: string,\n   *     env: Record<string, string>,\n   *   },\n   * }\n   * ```\n   *\n   * @see https://circleci.com/docs/guides/orchestrate/jobs-steps/#steps-overview\n   * @todo Make this more type-strict, maybe with a union type of step objects. See the example\n   *   above.\n   */\n  steps: unknown[];\n\n  /** I think we generally want to avoid this, since we're generating the jobs dynamically. */\n  parameters?: Record<string, unknown>;\n\n  /**\n   * We don't use this today, but it's available for future use. We might want to use it when\n   * running many many unit tests in parallel.\n   */\n  parallelism?: number;\n};\n\nexport type JobImplementation = (workflow: Workflow) => JobImplementationObj;\n\n/**\n * This function ensures the jobs adhere to the expected interface and that the job's ID is valid.\n * (i.e. no special characters, no spaces, etc.) Thus the ID can be referenced by other jobs in the\n * `requires` field.\n *\n * @param name - The name of the job\n * @param implementation - The implementation of the job\n * @param requires - The jobs that this job depends on\n * @returns The job's id, name, implementation, requires\n */\nexport function defineJob<K extends string, I extends JobImplementation>(\n  name: K,\n  implementation: I,\n  requires = [] as JobOrNoOpJob[]\n): Job<K> {\n  return {\n    id: toId(name),\n    name: name,\n    implementation: (workflow) => ({\n      description: name,\n      ...implementation(workflow),\n    }),\n    requires,\n  };\n}\n\n/**\n * A NoOpJob is a special type of job that is used to group other jobs together. It cannot contain\n * any steps/implementation.\n *\n * @param name - The name of the NoOpJob\n * @param requires - The jobs that this NoOpJob depends on\n */\nexport function defineNoOpJob<K extends string>(name: K, requires = [] as JobOrNoOpJob[]): Job<K> {\n  return {\n    id: toId(name),\n    name,\n    implementation: () =>\n      ({\n        type: 'no-op',\n      }) as const,\n    requires,\n  };\n}\n\nexport type Workflow = (typeof parameters.workflow.enum)[number];\n\n/**\n * Checks if the current workflow is at least the minimum workflow.\n *\n * `normal` → `merged` → `daily`\n *\n * `docs` is unique, in that it's not considered below of above anything.\n *\n * @example\n *\n * ```ts\n * isWorkflowOrAbove('normal', 'normal'); // true\n * isWorkflowOrAbove('normal', 'merged'); // false\n * isWorkflowOrAbove('normal', 'daily'); // false\n * isWorkflowOrAbove('daily', 'normal'); // true\n * ```\n *\n * @param current - The current workflow\n * @param minimum - The minimum workflow\n * @returns True if the current workflow is at least the minimum workflow, false otherwise\n */\nexport function isWorkflowOrAbove(current: Workflow, minimum: Workflow): boolean {\n  switch (current) {\n    case 'normal':\n      return minimum === 'normal';\n    case 'merged':\n      return minimum === 'normal' || minimum === 'merged';\n    case 'daily':\n      return minimum === 'normal' || minimum === 'merged' || minimum === 'daily';\n    case 'docs':\n      return minimum === 'docs';\n    default:\n      return false;\n  }\n}\n"
  },
  {
    "path": "scripts/clean-merged-branches.sh",
    "content": "#!/bin/sh\n#/ Usage: clean-merged-branches [-f]\n#/ Delete merged branches from the origin remote.\n#/\n#/ Options:\n#/   -f            Really delete the branches. Without this branches are shown\n#/                 but nothing is deleted.\nset -e\n\n# show usage maybe\n[ \"$1\" = \"--help\" ] && {\n    grep '^#/' <\"$0\"| cut -c4-\n    exit 0\n}\n\n# fetch and prune remote branches\ngit fetch origin --prune\n\n# grab list of merged branches\nbranches=$(\n  git branch -a --merged origin/master |\n  grep remotes/origin/ |\n  grep -v origin/master |\n  grep -v 'enterprise-.*-release' |\n  sed 's@remotes/origin/@@'\n)\n\n# bail out with no branches\n[ -z \"$branches\" ] && {\n    echo \"no merged branches detected\" 1>&2\n    exit 0\n}\n\n[ \"$1\" != -f ] && {\n    echo \"These branches will be deleted:\" 1>&2\n    echo \"$branches\"\n    read -p \"Press 'y' if you're sure. \" -n 1 -r\n    echo    # move to a new line\n}\n\n# delete the branches or just show what would be done without -f\nif [ \"$1\" = -f ] || [[ $REPLY =~ ^[Yy]$ ]]; then\n    git push origin $(echo \"$branches\" | sed 's/^ */:/')\nfi\n"
  },
  {
    "path": "scripts/combine-compodoc.ts",
    "content": "// Compodoc does not follow symlinks (it ignores them and their contents entirely)\n// So, we need to run a separate compodoc process on every symlink inside the project,\n// then combine the results into one large documentation.json\nimport { lstat, readFile, realpath, writeFile } from 'node:fs/promises';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport { execaCommand } from 'execa';\n// eslint-disable-next-line depend/ban-dependencies\nimport { globSync } from 'glob';\nimport { join, resolve } from 'path';\n\nimport { temporaryDirectory } from '../code/core/src/common/utils/cli.ts';\nimport { esMain } from './utils/esmain.ts';\n\nconst logger = console;\n\n// Find all symlinks in a directory. There may be more efficient ways to do this, but this works.\nasync function findSymlinks(dir: string) {\n  const potentialDirs = await globSync(`${dir}/**/*/`);\n\n  return (\n    await Promise.all(\n      potentialDirs.map(\n        async (p) => [p, (await lstat(p.replace(/\\/$/, ''))).isSymbolicLink()] as [string, boolean]\n      )\n    )\n  )\n    .filter(([, s]) => s)\n    .map(([p]) => p);\n}\n\nasync function run(cwd: string) {\n  const dirs = [\n    cwd,\n    ...(await findSymlinks(resolve(cwd, './src'))),\n    ...(await findSymlinks(resolve(cwd, './stories'))),\n    ...(await findSymlinks(resolve(cwd, './template-stories'))),\n  ];\n\n  const docsArray: Record<string, any>[] = await Promise.all(\n    dirs.map(async (dir) => {\n      const outputDir = await temporaryDirectory();\n      const resolvedDir = await realpath(dir);\n      await execaCommand(\n        `yarn --cwd ${cwd} compodoc ${resolvedDir} -p ./tsconfig.json -e json -d ${outputDir}`,\n        { cwd }\n      );\n      const contents = await readFile(join(outputDir, 'documentation.json'), 'utf8');\n      try {\n        return JSON.parse(contents);\n      } catch (err) {\n        logger.error(`Error parsing JSON at ${outputDir}\\n\\n`);\n        logger.error(contents);\n        throw err;\n      }\n    })\n  );\n\n  // Compose together any array entries, discard anything else (we happen to only read the array fields)\n  const documentation = docsArray.slice(1).reduce((acc, entry) => {\n    return Object.fromEntries(\n      Object.entries(acc).map(([key, accValue]) => {\n        if (Array.isArray(accValue)) {\n          return [key, [...accValue, ...entry[key]]];\n        }\n        return [key, accValue];\n      })\n    );\n  }, docsArray[0]);\n\n  await writeFile(join(cwd, 'documentation.json'), JSON.stringify(documentation));\n}\n\nif (esMain(import.meta.url)) {\n  run(resolve(process.argv[2]))\n    .then(() => process.exit(0))\n    .catch((err) => {\n      logger.error();\n      logger.error(err);\n      process.exit(1);\n    });\n}\n"
  },
  {
    "path": "scripts/create-nx-sandbox-projects.ts",
    "content": "import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\nimport { type Template } from '../code/lib/cli-storybook/src/sandbox-templates.ts';\nimport * as templates from '../code/lib/cli-storybook/src/sandbox-templates.ts';\n\n// @ts-expect-error somehow TS thinks there is a default export\nconst { allTemplates, merged, daily, normal } = (templates.default ||\n  templates) as typeof templates;\n\nconst projectJson = (\n  name: string,\n  framework: string | undefined,\n  tags: string[],\n  template: Template\n) => ({\n  name,\n  description: 'Do not edit. Auto generated by scripts/create-nx-sandbox-projects.ts.',\n  projectType: 'application',\n  implicitDependencies: [\n    'core',\n    'cli',\n    'addon-a11y',\n    'addon-docs',\n    'addon-vitest',\n    'addon-onboarding',\n    ...(framework ? [framework] : []),\n  ],\n  targets: {\n    sandbox: {\n      options: {\n        // Ensure Nx sandboxes write to a stable, slash-free folder name\n        // e.g. \"react-vite/default-ts\" -> \"react-vite-default-ts\"\n        dir: name.replaceAll('/', '-'),\n      },\n    },\n    dev: {},\n    ...(template.typeCheck === true\n      ? {\n          'check-sandbox': {},\n        }\n      : {}),\n    ...(template.skipTasks && template.skipTasks.includes('vitest-integration')\n      ? {}\n      : {\n          'vitest-integration': {},\n        }),\n    build: {\n      options: {\n        dir: name.replaceAll('/', '-'),\n      },\n    },\n    chromatic: {},\n    serve: {},\n    ...(template.skipTasks && template.skipTasks.includes('e2e-tests')\n      ? {}\n      : {\n          'e2e-tests': {},\n        }),\n    ...(template.skipTasks && template.skipTasks.includes('e2e-tests-dev')\n      ? {}\n      : {\n          'e2e-tests-dev': {},\n        }),\n    ...(template.skipTasks && template.skipTasks.includes('test-runner')\n      ? {}\n      : {\n          'test-runner': {},\n        }),\n    ...(template.skipTasks && template.skipTasks.includes('test-runner-dev')\n      ? {}\n      : {\n          'test-runner-dev': {},\n        }),\n  },\n  tags,\n});\nawait Promise.all(\n  Object.entries(allTemplates).map(async ([key, value]) => {\n    const p = key.replaceAll('/', '-');\n    const full = join(process.cwd(), '../code/sandbox', p, 'project.json');\n\n    console.log(full);\n    const framework = value.expected.framework;\n    const project = framework.includes('@storybook/')\n      ? framework.replace('@storybook/', '')\n      : undefined;\n    console.log(project);\n    console.log();\n    const tags = [\n      ...(normal.includes(key as any) && !value.inDevelopment ? ['ci:normal'] : []),\n      ...(merged.includes(key as any) && !value.inDevelopment ? ['ci:merged'] : []),\n      ...(daily.includes(key as any) && !value.inDevelopment ? ['ci:daily'] : []),\n    ];\n    ensureDirectoryExistence(full);\n    console.log(full);\n\n    const data = JSON.stringify(projectJson(key, project, tags, value), null, 2) + '\\n';\n\n    writeFileSync(full, data, { encoding: 'utf-8' });\n  })\n);\n\nfunction ensureDirectoryExistence(filePath: string): void {\n  const dir = dirname(filePath);\n  if (existsSync(dir)) {\n    return;\n  }\n  ensureDirectoryExistence(dir);\n  mkdirSync(dir);\n}\n"
  },
  {
    "path": "scripts/dangerfile.js",
    "content": "/**\n * IMPORTANT: This file has unique constraints due to how Danger.js executes it.\n *\n * Restrictions:\n *\n * - NO TypeScript: This file runs without any transpilation/transformation\n * - NO external dependencies: Scripts dependencies are not installed in CI\n * - NO Node.js built-ins: Even `fs` and other core modules don't work in Danger's runtime\n * - MUST use `import` for Danger API: The Danger runtime only processes `import` statements, not\n *   `require()`. These imports get compiled to global references by Danger.js\n * - CAN use `require()` for local files: Works for things like package.json\n *\n * Why: We want Danger to run as fast as possible in CI without installing dependencies or running\n * build processes.\n */\nimport { danger, fail, warn } from 'danger';\n\n/**\n * Returns the intersection of two arrays\n *\n * @template T\n * @param {ReadonlyArray<T>} a - First array\n * @param {ReadonlyArray<T>} b - Second array\n * @returns {T[]} Array containing elements present in both arrays\n */\nfunction intersection(a, b) {\n  return a.filter((v) => b.includes(v));\n}\n\nconst pkg = require('../code/package.json');\n\nconst Versions = {\n  PATCH: 'PATCH',\n  MINOR: 'MINOR',\n  MAJOR: 'MAJOR',\n};\n\nconst ciLabels = ['ci:normal', 'ci:merged', 'ci:daily', 'ci:docs'];\n\nconst { labels } = danger.github.issue;\n\nconst prLogConfig = pkg['pr-log'];\n\nconst branchVersion = Versions.MINOR;\nconst targetBranch = danger.github.pr.base.ref;\nconst isReleasePr = ['latest-release', 'next-release'].includes(targetBranch);\n\n/** @param {string[]} labels */\nconst checkRequiredLabels = (labels) => {\n  const forbiddenLabels = [\n    'ci: do not merge',\n    'in progress',\n    ...(branchVersion !== Versions.MAJOR ? ['BREAKING CHANGE'] : []),\n    ...(branchVersion === Versions.PATCH ? ['feature request'] : []),\n  ];\n\n  const requiredLabels = [\n    ...(prLogConfig?.skipLabels ?? []),\n    ...(prLogConfig?.validLabels ?? []).map(([label]) => label),\n  ];\n\n  const blockingLabels = intersection(forbiddenLabels, labels);\n  if (blockingLabels.length > 0) {\n    fail(\n      `PR is marked with ${blockingLabels.map((label) => `\"${label}\"`).join(', ')} label${\n        blockingLabels.length > 1 ? 's' : ''\n      }.`\n    );\n  }\n\n  if (isReleasePr) {\n    // Release PRs only need `ci:daily`.\n    if (!labels.includes('ci:daily')) {\n      fail(\n        'Release PRs targeting latest-release or next-release must include the \"ci:daily\" label.'\n      );\n    }\n    return;\n  } else {\n    // All other PRs to `next` to a qualifying change type and one of several applicable CI labels.\n    const foundRequiredLabels = intersection(requiredLabels, labels);\n    if (foundRequiredLabels.length === 0) {\n      fail(`PR is not labeled with one of: ${JSON.stringify(requiredLabels)}`);\n    } else if (foundRequiredLabels.length > 1) {\n      fail(`Please choose only one of these labels: ${JSON.stringify(foundRequiredLabels)}`);\n    }\n\n    const foundCILabels = intersection(ciLabels, labels);\n    if (foundCILabels.length === 0) {\n      fail(`PR is not labeled with one of: ${JSON.stringify(ciLabels)}`);\n    } else if (foundCILabels.length > 1) {\n      fail(`Please choose only one of these labels: ${JSON.stringify(foundCILabels)}`);\n    }\n  }\n};\n\n/** @param {string} title */\nconst checkPrTitle = (title) => {\n  const match = title.match(/^[A-Z].+:\\s[A-Z].+$/);\n  if (!match) {\n    fail(\n      `PR title must be in the format of \"Area: Summary\", With both Area and Summary starting with a capital letter\nGood examples:\n- \"Docs: Describe Canvas Doc Block\"\n- \"Svelte: Support Svelte v4\"\nBad examples:\n- \"add new api docs\"\n- \"fix: Svelte 4 support\"\n- \"Vue: improve docs\"`\n    );\n  }\n};\n\n/** @param {string} body */\nconst checkManualTestingSection = (body) => {\n  // Check if author is a core team member or maintainer\n  const author = danger.github.pr.user;\n  const authorAssociation = danger.github.pr.author_association;\n\n  // Bypass check for OWNER, MEMBER roles (but never for agent bots)\n  if (\n    (['OWNER', 'MEMBER'].includes(authorAssociation) && author.type !== 'Bot') ||\n    (author.login === 'github-actions[bot]' && author.type === 'Bot')\n  ) {\n    return;\n  }\n\n  // Check if manual testing section exists\n  const manualTestingMatch = body.match(/####\\s*Manual testing/i);\n  if (!manualTestingMatch || manualTestingMatch.index === undefined) {\n    fail(\n      'PR description is missing the mandatory \"#### Manual testing\" section. Please add it so that reviewers know how to manually test your changes.'\n    );\n    return;\n  }\n\n  // Extract content after the manual testing section\n  const manualTestingSectionStart = manualTestingMatch.index + manualTestingMatch[0].length;\n  const restOfBody = body.substring(manualTestingSectionStart);\n\n  // Find the next section\n  const nextSectionMatch = restOfBody.match(/\\n#+[^#]/);\n  const manualTestingContent = nextSectionMatch\n    ? restOfBody.substring(0, nextSectionMatch.index)\n    : restOfBody;\n\n  // Remove the initial message and check if there's any meaningful content left\n  const contentWithoutInitialMessage = manualTestingContent\n    .replace(/>\\s*\\[!CAUTION\\][^]*?This section is mandatory[^]*?Thanks!/i, '')\n    .trim();\n\n  // Check if there's any substantial content (ignoring whitespace and template comments)\n  const contentWithoutComments = contentWithoutInitialMessage\n    .replace(/<!--[^]*?-->/g, '') // Remove HTML comments\n    .replace(/\\s+/g, ''); // Remove all whitespace\n\n  if (!contentWithoutComments) {\n    fail(\n      'The \"#### Manual testing\" section must be filled in. Please describe how to test the changes you\\'ve made, step by step, so that reviewers can confirm your PR works as intended.'\n    );\n  }\n};\n\nconst checkTargetBranch = () => {\n  const targetBranch = danger.github.pr.base.ref;\n  const author = danger.github.pr.user;\n  const authorAssociation = danger.github.pr.author_association;\n\n  // Only check for non-team members (not OWNER, MEMBER) and skip GitHub Actions bot\n  if (\n    ['OWNER', 'MEMBER'].includes(authorAssociation) ||\n    (author.login === 'github-actions[bot]' && author.type === 'Bot')\n  ) {\n    return;\n  }\n\n  if (targetBranch === 'main' || targetBranch.includes('release')) {\n    fail(\n      `This PR targets \\`${targetBranch}\\`, but it should target \\`next\\`. Please update the base branch of your PR.`\n    );\n  } else if (targetBranch !== 'next') {\n    warn(\n      `This PR targets \\`${targetBranch}\\`. The default branch for contributions is \\`next\\`. Please make sure you are targeting the correct branch.`\n    );\n  }\n};\n\ncheckTargetBranch();\n\nif (prLogConfig) {\n  checkRequiredLabels(labels.map((l) => l.name));\n  checkPrTitle(danger.github.pr.title);\n  checkManualTestingSection(danger.github.pr.body);\n}\n"
  },
  {
    "path": "scripts/ecosystem-ci/before-test.js",
    "content": "/**\n * This script is used to copy the resolutions from the root package.json to the sandbox\n * package.json. This is necessary because the sandbox package.json is used to run the tests and the\n * resolutions are needed to run the tests. The vite-ecosystem-ci, though, sets the resolutions in\n * the root package.json.\n */\nimport { writeFile } from 'node:fs/promises';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport { execaCommand } from 'execa';\n\nimport { EXISTING_RESOLUTIONS } from './existing-resolutions.js';\n\nconst filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(filename);\n\nconst sandbox = process.argv[2] ?? 'react-vite/default-ts';\n\nconst sandboxPackageJsonPath = resolve(\n  __dirname,\n  `../../../storybook-sandboxes/${sandbox.replace('/', '-')}/package.json`\n);\n\nconst { default: rootPkgJson } = await import('../../package.json', { with: { type: 'json' } });\nconst { default: sandboxPkgJson } = await import(sandboxPackageJsonPath, {\n  with: { type: 'json' },\n});\n\n// copy resolutions from root package.json to sandbox package.json, excluding the known resolutions we have internally in our repo\n// ecosystem-ci will add resolutions to the root package.json, and we want to propagate ONLY those to the sandbox package.json\nconst resolutionsToCopy = rootPkgJson.resolutions\n  ? Object.fromEntries(\n      Object.entries(rootPkgJson.resolutions).filter(([pkg]) => !EXISTING_RESOLUTIONS.has(pkg))\n    )\n  : {};\n\nsandboxPkgJson.resolutions = {\n  ...(sandboxPkgJson.resolutions ?? {}),\n  ...resolutionsToCopy,\n};\n\nawait writeFile(sandboxPackageJsonPath, JSON.stringify(sandboxPkgJson, null, 2));\n\nconst sandboxDir = dirname(sandboxPackageJsonPath);\nawait execaCommand('yarn add playwright', { cwd: sandboxDir, shell: true });\nawait execaCommand('yarn playwright install', { cwd: sandboxDir, shell: true });\n"
  },
  {
    "path": "scripts/ecosystem-ci/before-test.sh",
    "content": "#!/bin/bash\nset -e\n\nTEMPLATE=${1:?Usage: $0 <template>}\nSANDBOX_NAME=${TEMPLATE//\\//-}\n\n# Run the before-test script to copy resolutions and set up Playwright\nnode ./scripts/ecosystem-ci/before-test.js \"$TEMPLATE\"\n\n# Install dependencies in the sandbox\ncd \"../storybook-sandboxes/$SANDBOX_NAME\"\nyarn install\n"
  },
  {
    "path": "scripts/ecosystem-ci/build.sh",
    "content": "#!/bin/bash\nset -e\n\nTEMPLATE=${1:?Usage: $0 <template> [renderer]}\nRENDERER=${2:-}\n\n# Install all dependencies\nyarn task --task install\n\n# If a renderer is specified, build it so it uses the resolution set by the ecosystem-ci\nif [ -n \"$RENDERER\" ]; then\n  yarn --cwd code build \"$RENDERER\"\nfi\n\n# Create the storybook-sandboxes directory with a package.json that specifies Yarn as the package manager.\n# This is required because the ecosystem-ci repo uses pnpm, and yarn refuses to install in the sandbox dir\n# if it sees a different packageManager field higher up in the directory tree.\nmkdir -p ../storybook-sandboxes\necho \"{ \\\"packageManager\\\": \\\"yarn@$(yarn -v)\\\" }\" > ../storybook-sandboxes/package.json\n\nyarn task build --template \"$TEMPLATE\" --start-from=compile --no-link --skip-cache\n"
  },
  {
    "path": "scripts/ecosystem-ci/existing-resolutions.js",
    "content": "/**\n * Set of resolutions from the root package.json that should NOT be copied to sandbox package.json.\n * These are the \"existing\" resolutions that Storybook maintains, as opposed to resolutions that\n * might be injected by ecosystem-ci repos.\n *\n * This set must stay in sync with the resolutions in the root package.json. Run the test in\n * before-test.test.ts to verify they match.\n */\nexport const EXISTING_RESOLUTIONS = new Set([\n  '@babel/runtime',\n  '@babel/traverse',\n  '@babel/types',\n  '@playwright/test',\n  '@testing-library/user-event@npm:^14.4.0',\n  '@testing-library/user-event@npm:^14.6.1',\n  '@types/babel__traverse@npm:*',\n  '@types/babel__traverse@npm:^7.18.0',\n  '@types/node',\n  '@types/react',\n  '@vitest/expect@npm:3.2.4',\n  'aria-query@5.3.0',\n  'esbuild',\n  'playwright',\n  'playwright-core',\n  'react',\n  'type-fest',\n  'typescript',\n]);\n"
  },
  {
    "path": "scripts/ecosystem-ci/existing-resolutions.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport rootPkgJson from '../../package.json';\nimport { EXISTING_RESOLUTIONS } from './existing-resolutions.js';\n\n/*\nIf this test is failing for you, it means that you have changed the list of resolutions\nin the root package.json, but you have not updated the EXISTING_RESOLUTIONS set in\nscripts/ecosystem-ci/existing-resolutions.ts.\n\nThe purpose of this test is to ensure that any changes to the resolutions in package.json\nare reflected in the EXISTING_RESOLUTIONS set, which is used by the ecosystem-ci before-test\nscript to copy the resolutions into the sandbox package.json files.\n*/\n\ndescribe('ecosystem-ci', () => {\n  it('EXISTING_RESOLUTIONS should match all keys in package.json resolutions', () => {\n    const actualKeys = new Set(Object.keys(rootPkgJson.resolutions));\n    const difference = actualKeys.symmetricDifference(EXISTING_RESOLUTIONS);\n\n    expect(difference.size).toBe(0);\n  });\n});\n"
  },
  {
    "path": "scripts/ecosystem-ci/test.sh",
    "content": "#!/bin/bash\nset -e\n\nTEMPLATE=${1:?Usage: $0 <template>}\n\n# Run Vitest integration tests\nyarn task --task vitest-integration --template \"$TEMPLATE\" --start-from=vitest-integration --no-link --skip-cache\n"
  },
  {
    "path": "scripts/eslint-plugin-local-rules/README.md",
    "content": "## ESLint plugin local rules\n\nThis package serves as a local ESLint plugin to be used in the monorepo and help maintainers keep certain code standards.\n\n### Development\n\nIf you're fixing a rule or creating a new one, make sure to:\n\n1. Make your code changes\n2. Rerun yarn install in the `code` directory. It's necessary to update the module reference\n3. Update the necessary `.eslintrc.js` files (if you are adding a new rule)\n4. Restart the ESLint server in your IDE\n"
  },
  {
    "path": "scripts/eslint-plugin-local-rules/index.js",
    "content": "module.exports = {\n  rules: {\n    'no-uncategorized-errors': require('./no-uncategorized-errors'),\n    'no-duplicated-error-codes': require('./no-duplicated-error-codes'),\n    'storybook-monorepo-imports': require('./storybook-monorepo-imports'),\n  },\n};\n"
  },
  {
    "path": "scripts/eslint-plugin-local-rules/no-duplicated-error-codes.js",
    "content": "// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\n\nmodule.exports = {\n  meta: {\n    type: 'problem',\n    docs: {\n      description: 'Ensure unique error codes per category in the same file',\n      category: 'Best Practices',\n      recommended: true,\n    },\n    fixable: null,\n  },\n  create(context) {\n    const errorClasses = {};\n\n    // both code and category are passed as arguments to the StorybookError constructor's super call\n    function findSuperArguments(node) {\n      let superArguments = [];\n\n      node.body.body.forEach((method) => {\n        if (method.type === 'MethodDefinition' && method.kind === 'constructor') {\n          method.value.body.body.forEach((expression) => {\n            if (\n              expression.type === 'ExpressionStatement' &&\n              expression.expression.type === 'CallExpression' &&\n              expression.expression.callee.type === 'Super'\n            ) {\n              superArguments = expression.expression.arguments;\n            }\n          });\n        }\n      });\n\n      return superArguments;\n    }\n\n    return {\n      ClassDeclaration(node) {\n        if (node.superClass && node.superClass.name === 'StorybookError') {\n          const superArguments = findSuperArguments(node);\n          const properties = {\n            category: null,\n            code: null,\n          };\n\n          // Process the arguments to extract category and code\n          superArguments.forEach((arg) => {\n            if (arg.type === 'ObjectExpression') {\n              arg.properties.forEach((property) => {\n                if (Object.keys(properties).includes(property.key.name)) {\n                  properties[property.key.name] = property;\n                }\n              });\n            }\n          });\n\n          const categoryValue = properties.category.value.property.name;\n          const codeValue = properties.code.value.value;\n\n          if (categoryValue && codeValue) {\n            if (!errorClasses[categoryValue]) {\n              errorClasses[categoryValue] = new Set();\n            }\n\n            if (errorClasses[categoryValue].has(codeValue)) {\n              context.report({\n                node: properties.code.key,\n                message: `Duplicate error code '${codeValue}' in category '${categoryValue}'.`,\n              });\n            } else {\n              errorClasses[categoryValue].add(codeValue);\n            }\n          }\n        }\n      },\n    };\n  },\n};\n"
  },
  {
    "path": "scripts/eslint-plugin-local-rules/no-uncategorized-errors.js",
    "content": "// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\n\nmodule.exports = {\n  meta: {\n    type: 'problem',\n    docs: {\n      description: 'Disallow usage of the Error JavaScript class.',\n      category: 'Best Practices',\n      recommended: true,\n      url: 'https://github.com/storybookjs/storybook/blob/next/code/core/src/ERRORS.md',\n    },\n  },\n  create(context) {\n    return {\n      NewExpression(node) {\n        if (node.callee.name === 'Error') {\n          context.report({\n            node,\n            message:\n              'Avoid using a generic Error class. Use a categorized StorybookError class instead. See the docs 👉',\n          });\n        }\n      },\n    };\n  },\n};\n"
  },
  {
    "path": "scripts/eslint-plugin-local-rules/package.json",
    "content": "{\n  \"name\": \"eslint-plugin-local-rules\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"license\": \"ISC\",\n  \"author\": \"\",\n  \"main\": \"index.js\"\n}\n"
  },
  {
    "path": "scripts/eslint-plugin-local-rules/storybook-monorepo-imports.js",
    "content": "// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\n\nconst path = require('path');\nconst cache = {};\n\nmodule.exports = {\n  meta: {\n    type: 'problem',\n    docs: {\n      description: 'Ensure the imports-paths of packages in the monorepo is correct',\n      category: 'Best Practices',\n      recommended: true,\n      url: 'https://github.com/storybookjs/storybook/blob/next/code/core/README.md',\n    },\n    fixable: 'code',\n  },\n  create(context) {\n    return {\n      ImportDeclaration: (node) => {\n        const fileName = context.getPhysicalFilename();\n        const isInCLI = !!fileName.includes(path.join('code', 'lib', 'cli') + path.sep);\n        const isInCodemod = !!fileName.includes(path.join('code', 'lib', 'codemod'));\n        const isInCreateStorybook = !!fileName.includes(\n          path.join('code', 'lib', 'create-storybook')\n        );\n        const isInCore = !!fileName.includes(path.join('code', 'core'));\n\n        if (\n          node.source.value.startsWith('@storybook/core/') &&\n          !isInCLI &&\n          !isInCore &&\n          !isInCodemod &&\n          !isInCreateStorybook\n        ) {\n          const newPath = node.source.value\n            .replace('@storybook/core', 'storybook/internal')\n            .replace('/src', '');\n          context.report({\n            node: node,\n            message: `Cannot import from @storybook/core in this package. Use storybook/internal instead.`,\n            fix: (fixer) => {\n              return fixer.replaceText(node.source, `'${newPath}'`);\n            },\n          });\n        }\n\n        if (\n          node.source.value.startsWith('@storybook/core/') &&\n          (isInCore || isInCLI || isInCodemod || isInCreateStorybook)\n        ) {\n          const newPath = node.source.value\n            .replace('@storybook/core', 'storybook/internal')\n            .replace('/src', '');\n          context.report({\n            node: node,\n            message: `Cannot import from @storybook/core in this package. Use storybook/internal instead.`,\n            fix: (fixer) => {\n              return fixer.replaceText(node.source, `'${newPath}'`);\n            },\n          });\n        }\n      },\n    };\n  },\n};\n"
  },
  {
    "path": "scripts/event-log-checker.ts",
    "content": "import assert from 'assert';\nimport picocolors from 'picocolors';\n\n// import versions from '../code/core/src/common/versions';\nimport { allTemplates } from '../code/lib/cli-storybook/src/sandbox-templates.ts';\nimport { esMain } from './utils/esmain.ts';\n\nconst PORT = process.env.PORT || 6007;\n\ntype EventType = 'build' | 'test-run';\ntype EventDefinition = {\n  noBoot?: boolean;\n};\n\nconst eventTypeDefinitions: Record<EventType, EventDefinition> = {\n  build: {},\n  'test-run': { noBoot: true },\n};\n\nasync function run() {\n  const [eventType, templateName] = process.argv.slice(2);\n  let testMessage = '';\n\n  // very simple jest-like test fn for better error readability\n  const test = (message: string, fn: () => void) => {\n    testMessage = message;\n    fn();\n  };\n\n  try {\n    if (!eventType || !templateName) {\n      throw new Error(\n        `Need eventType and templateName; call with ./event-log-checker <eventType> <templateName>`\n      );\n    }\n\n    const definition = eventTypeDefinitions[eventType as EventType];\n\n    if (!definition) {\n      throw new Error(`Unexpected eventType '${eventType}'`);\n    }\n\n    const template = allTemplates[templateName as keyof typeof allTemplates];\n\n    if (!template) {\n      throw new Error(`Unexpected template '${templateName}'`);\n    }\n\n    const events: any = await (await fetch(`http://localhost:${PORT}/event-log`)).json();\n    const eventsWithoutMocks = events.filter((e: any) => e.eventType !== 'mocking');\n\n    if (definition.noBoot) {\n      test('Should log 1 event', () => {\n        assert.equal(\n          eventsWithoutMocks.length,\n          1,\n          `Expected 1 event but received ${\n            eventsWithoutMocks.length\n          } instead. The following events were logged: ${JSON.stringify(events)}`\n        );\n      });\n    } else {\n      // two or three events are logged, depending on whether the template has a `vitest-integration` task\n      test('Should log 2 or 3 events', () => {\n        assert.ok(\n          eventsWithoutMocks.length === 2 || eventsWithoutMocks.length === 3,\n          `Expected 2 or 3 events but received ${\n            eventsWithoutMocks.length\n          } instead. The following events were logged: ${JSON.stringify(eventsWithoutMocks)}`\n        );\n      });\n    }\n\n    if (eventsWithoutMocks.length === 0) {\n      throw new Error('No events were logged');\n    }\n\n    const [bootEvent, mainEvent] = definition.noBoot\n      ? [null, eventsWithoutMocks[0]]\n      : eventsWithoutMocks;\n\n    // const storybookVersion = versions.storybook;\n    // if (bootEvent) {\n    //   test('boot event should have cliVersion and storybookVersion in context', () => {\n    //     assert.equal(bootEvent.context.cliVersion, storybookVersion);\n    //     assert.equal(bootEvent.context.storybookVersion, storybookVersion);\n    //   });\n    // }\n\n    // test(`main event should have storybookVersion in context`, () => {\n    //   assert.equal(mainEvent.context.storybookVersion, storybookVersion);\n    // });\n\n    // test(`main event should have storybookVersion in metadata`, () => {\n    //   assert.equal(mainEvent.metadata.storybookVersion, storybookVersion);\n    // });\n\n    if (bootEvent) {\n      test(`Should log a boot event with a payload of type ${eventType}`, () => {\n        assert.equal(bootEvent.eventType, 'boot');\n        assert.equal(bootEvent.payload?.eventType, eventType);\n      });\n    }\n\n    test(`main event should be ${eventType} and contain correct id and session id`, () => {\n      assert.equal(mainEvent.eventType, eventType);\n      assert.ok(typeof mainEvent.eventId === 'string');\n      assert.ok(typeof mainEvent.sessionId === 'string');\n      if (bootEvent) {\n        assert.notEqual(mainEvent.eventId, bootEvent.eventId);\n        assert.equal(mainEvent.sessionId, bootEvent.sessionId);\n      }\n    });\n\n    test(`main event should not contain anonymousId because it is not a git directory`, () => {\n      assert.equal(mainEvent.context.anonymousId, undefined);\n    });\n\n    // Not sure if it's worth testing this as we are not providing this value in CI.\n    // For now the code is commented out so we can discuss later.\n    // test(`main event should contain a userSince value`, () => {\n    //   assert.ok(typeof mainEvent.metadata.userSince === 'number');\n    // });\n\n    const {\n      expected: { renderer, builder, framework },\n    } = template;\n\n    test(`main event should contain correct packages from template's \"expected\" field`, () => {\n      assert.equal(mainEvent.metadata.renderer, renderer);\n      assert.equal(mainEvent.metadata.builder, builder);\n      assert.equal(mainEvent.metadata.framework.name, framework);\n    });\n  } catch (err) {\n    if (err instanceof assert.AssertionError) {\n      console.log(`Assertions failed for ${picocolors.bold(templateName)}\\n`);\n      console.log(picocolors.bold(picocolors.red(`✕ ${testMessage}:`)));\n      console.log(err);\n      process.exit(1);\n    }\n    throw err;\n  }\n}\n\nexport {};\n\nif (esMain(import.meta.url)) {\n  run()\n    .then(() => process.exit(0))\n    .catch((err) => {\n      console.log(err);\n      process.exit(1);\n    });\n}\n"
  },
  {
    "path": "scripts/event-log-collector.ts",
    "content": "import { json } from '@polka/parse';\nimport polka from 'polka';\n\nconst PORT = process.env.PORT || 6007;\n\nconst server = polka();\nserver.use(json());\n\nconst events: Record<string, unknown>[] = [];\nserver.post('/event-log', (req, res) => {\n  console.log(`Received event ${req.body.eventType}`);\n  events.push(req.body);\n  res.end('OK');\n});\n\nserver.get('/event-log', (_req, res) => {\n  console.log(`Sending ${events.length} events`);\n  res.end(JSON.stringify(events));\n});\n\nserver.listen(PORT, () => {\n  console.log(`Event log listening on ${PORT}`);\n});\n"
  },
  {
    "path": "scripts/get-report-message.ts",
    "content": "import { readFile } from 'node:fs/promises';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport { execaCommand } from 'execa';\nimport { join } from 'path';\n\nimport { CODE_DIRECTORY } from './utils/constants.ts';\nimport { esMain } from './utils/esmain.ts';\n\ntype Branch = 'main' | 'next' | 'alpha' | 'next-release' | 'latest-release';\ntype Workflow = 'merged' | 'daily';\n\nconst getFooter = async (branch: Branch, workflow: Workflow, job: string) => {\n  if (job === 'chromatic-sandboxes') {\n    return `\\n\\nThis might not necessarily be a bug, it could be a visual diff that you have to review and approve. Please check it!`;\n  }\n\n  // The CI workflows can run on release branches and we should display the version number\n  if (branch === 'next-release' || branch === 'latest-release') {\n    const content = await readFile(join(CODE_DIRECTORY, 'package.json'), 'utf8');\n    const packageJson = JSON.parse(content);\n\n    // running in alpha branch we should just show the version which failed\n    return `\\n**Version: ${packageJson.version}**`;\n  }\n\n  const mergeCommits =\n    workflow === 'merged'\n      ? // show single merge for merged workflow\n        `git log -1 --pretty=format:\"\\`%h\\` %<(12)%ar %s [%an]\"`\n      : // show last 24h merges for daily workflow\n        `git log --merges --since=\"24 hours ago\" --pretty=format:\"\\`%h\\` %<(12)%ar %s [%an]\"`;\n\n  const result = await execaCommand(mergeCommits, { shell: true, cleanup: true });\n  const formattedResult = result.stdout\n    // discord needs escaped line breaks\n    .replace(/\\n/g, '\\\\n')\n    // make links out of pull request ids\n    .replace(/Merge pull request #/g, 'https://github.com/storybookjs/storybook/pull/');\n\n  return `\\n\\n**Relevant PRs:**\\n${formattedResult}`;\n};\n\n// This command is run in Circle CI on failures, to get a rich message to report to Discord\n// Usage: yarn get-report-message type workflow branch\nasync function run() {\n  const [, , workflow = '', template = 'none'] = process.argv;\n\n  if (!workflow) {\n    throw new Error('[get-report-message] Missing workflow argument.');\n  }\n\n  const { CIRCLE_BRANCH: currentBranch = '', CIRCLE_JOB: currentJob = '' } = process.env;\n\n  if (!currentBranch || !currentJob) {\n    throw new Error(\n      '[get-report-message] Missing CIRCLE_BRANCH or CIRCLE_JOB environment variables.'\n    );\n  }\n\n  const title = `Oh no! The **${currentJob}** job has failed${\n    template !== 'none' ? ` for **${template}**.` : '.'\n  }`;\n  const body = `\\n\\n**Branch**: \\`${currentBranch}\\`\\n**Workflow:** ${workflow}`;\n  const footer = await getFooter(currentBranch as Branch, workflow as Workflow, currentJob);\n\n  console.log(`${title}${body}${footer}`.replace(/\\n/g, '\\\\n'));\n}\n\nif (esMain(import.meta.url)) {\n  run().catch((err) => {\n    console.error(err);\n    process.exit(1);\n  });\n}\n"
  },
  {
    "path": "scripts/get-sandbox-dir.ts",
    "content": "import { join } from 'node:path';\n\nimport { program } from 'commander';\n\nimport { SANDBOX_DIRECTORY } from './utils/constants.ts';\nimport { esMain } from './utils/esmain.ts';\n\ntype RunOptions = {\n  template?: string;\n};\n\n// Get sandbox directory from template name\n// replace '/' by a '-'\nasync function run({ template }: RunOptions) {\n  console.log(join(SANDBOX_DIRECTORY, template.replace('/', '-')));\n}\n\nif (esMain(import.meta.url)) {\n  program\n    .description('Retrieve the sandbox directory for template name')\n    .requiredOption('--template <template>', 'Template name');\n\n  program.parse(process.argv);\n\n  const options = program.opts() as RunOptions;\n\n  run(options).catch((err) => {\n    console.error(err);\n    process.exit(1);\n  });\n}\n"
  },
  {
    "path": "scripts/knip.config.ts",
    "content": "import { join, relative } from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport fg from 'fast-glob';\nimport type { KnipConfig } from 'knip';\nimport { match } from 'minimatch';\n\n// Files we want to exclude from analysis should be negated project patterns, not `ignores`\n// docs: https://knip.dev/guides/configuring-project-files\nconst project = [\n  'src/**/*.{js,jsx,ts,tsx}',\n  '!**/__search-files-tests__/**',\n  '!**/__testfixtures__/**',\n  '!**/__mocks-ng-workspace__/**',\n  '!**/__mockdata__/**',\n  '!**/__mocks__/**',\n  '!**/__for-testing__/**',\n];\n\n// Adding an explicit MDX \"compiler\", as the dependency knip looks for isn't listed (@mdx-js/mdx or astro)\n// Alternatively, we could ignore a few false positives\n// docs: https://knip.dev/features/compilers\nconst importMatcher = /import[^'\"]+['\"]([^'\"]+)['\"]/g;\nconst fencedCodeBlockMatcher = /```[\\s\\S]*?```/g;\nconst mdx = (text: string) =>\n  [...text.replace(fencedCodeBlockMatcher, '').matchAll(importMatcher)].join('\\n');\n\nconst baseConfig = {\n  // storybook itself configured (only) in root\n  storybook: { entry: ['**/*.@(mdx|stories.@(mdx|js|jsx|mjs|ts|tsx))'] },\n\n  workspaces: {\n    '.': {\n      project,\n    },\n    'addons/*': {\n      project,\n    },\n    'builders/*': {\n      project,\n    },\n    core: {\n      entry: [\n        'src/manager-api/index.mock.ts',\n        'src/shared/preview/csf4.ts',\n        // with srcDir → outDir in tsconfig.json we could omit all of these:\n        'src/index.ts',\n        'src/cli/bin/index.ts',\n        'src/*/{globals*,index,decorator,manager,preview,runtime}.{ts,tsx}',\n        'src/core-server/presets/*.ts',\n      ],\n      project,\n    },\n    'frameworks/{angular,ember}': {\n      entry: ['src/builders/{build,start}-storybook/index.ts', 'src/**/{index,config}.{js,ts}'],\n      project,\n    },\n    'frameworks/*': {\n      project,\n    },\n    'lib/create-storybook': {\n      entry: ['src/index.ts', 'src/ink/steps/checks/index.tsx'],\n      project,\n    },\n    'lib/*': {\n      project,\n    },\n    'presets/*': {\n      project,\n    },\n    'renderers/*': {\n      project,\n    },\n  },\n  compilers: {\n    mdx,\n  },\n} satisfies KnipConfig;\n\n// Adds package.json#bundler.entries etc. to each workspace config `entry: []`\n// Knip maps package.json#export to source files but the entries are incomplete\nexport const addBundlerEntries = async (config: KnipConfig) => {\n  // Type guard: ensure config is an object, not a function\n  if (typeof config === 'function') {\n    throw new Error('addBundlerEntries expects a config object, not a function');\n  }\n  const baseDir = join(__dirname, '..');\n  const rootManifest = await import(pathToFileURL(join(baseDir, 'package.json')).href, {\n    with: { type: 'json' },\n  });\n  const workspaceDirs = await fg(rootManifest.workspaces.packages, {\n    cwd: baseDir,\n    onlyDirectories: true,\n  });\n  const workspaceDirectories = workspaceDirs.map((dir) => relative(baseDir, join(baseDir, dir)));\n  for (const wsDir of workspaceDirectories) {\n    for (const configKey of Object.keys(baseConfig.workspaces)) {\n      if (match([wsDir], configKey)) {\n        const manifest = await import(pathToFileURL(join(baseDir, wsDir, 'package.json')).href, {\n          with: { type: 'json' },\n        });\n        const configEntries = (config.workspaces[configKey].entry as string[]) ?? [];\n        const bundler = manifest?.bundler;\n        for (const value of Object.values(bundler ?? {})) {\n          if (Array.isArray(value)) {\n            configEntries.push(\n              ...value.map((entry) => (typeof entry === 'string' ? entry : entry.file))\n            );\n          }\n        }\n        config.workspaces[configKey].entry = Array.from(new Set(configEntries));\n      }\n    }\n  }\n  return config;\n};\n\nexport default addBundlerEntries(baseConfig);\n"
  },
  {
    "path": "scripts/npm-auth.ts",
    "content": "import { writeFileSync } from 'node:fs';\nimport process from 'node:process';\n\n// @ts-expect-error no types!\nimport npmpkg from 'npm-registry-client';\n\ntype AuthOptions = {\n  username: string;\n  password: string;\n  email: string;\n  registry: string;\n};\n\n/**\n * Authenticates to the npm registry and writes a .npmrc to the specified directory. Code is based\n * on the (unmaintained) npm-auth-to-token package\n *\n * @param opts - The authentication options.\n * @returns Promise<void>\n */\nexport function npmAuth(opts: AuthOptions & { outputDir?: string }): Promise<void> {\n  const { username, password, email, registry, outputDir } = opts;\n  const client = new (npmpkg as any)();\n\n  return new Promise((resolve, reject) => {\n    client.adduser(\n      registry,\n      {\n        auth: {\n          username,\n          password,\n          email,\n          alwaysAuth: true,\n        },\n      },\n      (err: Error | null, res: { token: string }) => {\n        if (err) {\n          return reject(err);\n        }\n        const path = `${outputDir || process.cwd()}/.npmrc`;\n        let base = registry.substring(registry.indexOf('/'));\n        if (base.lastIndexOf('/') !== registry.length - 1) {\n          base += '/';\n        }\n        writeFileSync(path, `registry=${registry}\\n${base}:_authToken=${res.token}`);\n\n        console.log('Done');\n        resolve();\n      }\n    );\n  });\n}\n"
  },
  {
    "path": "scripts/package.json",
    "content": "{\n  \"name\": \"@storybook/scripts\",\n  \"version\": \"7.0.0-alpha.16\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"scripts\": {\n    \"bench-packages\": \"jiti ./bench/bench-packages.ts\",\n    \"build-package\": \"jiti ./build-package.ts\",\n    \"check\": \"jiti ./check/check-package.ts\",\n    \"check-package\": \"jiti ./check-package.ts\",\n    \"docs:codemod\": \"jiti ./snippets/codemod.ts\",\n    \"generate-sandboxes\": \"jiti ./sandbox/generate.ts\",\n    \"get-report-message\": \"jiti ./get-report-message.ts\",\n    \"get-sandbox-dir\": \"jiti ./get-sandbox-dir.ts\",\n    \"lint\": \"yarn lint:js\",\n    \"lint:js\": \"yarn lint:js:cmd .  --quiet\",\n    \"lint:js:cmd\": \"cross-env NODE_ENV=production eslint --cache --cache-location=../.cache/eslint --ext .js,.jsx,.json,.html,.ts,.tsx,.mjs --report-unused-disable-directives\",\n    \"lint:package\": \"sort-package-json\",\n    \"local-registry\": \"jiti ./run-registry.ts\",\n    \"publish\": \"jiti ./sandbox/publish.ts\",\n    \"release:cancel-preparation-runs\": \"jiti ./release/cancel-preparation-runs.ts\",\n    \"release:generate-pr-description\": \"jiti ./release/generate-pr-description.ts\",\n    \"release:get-changelog-from-file\": \"jiti ./release/get-changelog-from-file.ts\",\n    \"release:get-current-version\": \"jiti ./release/get-current-version.ts\",\n    \"release:get-version-changelog\": \"jiti ./release/get-version-changelog.ts\",\n    \"release:is-pr-frozen\": \"jiti ./release/is-pr-frozen.ts\",\n    \"release:is-prerelease\": \"jiti ./release/is-prerelease.ts\",\n    \"release:is-version-published\": \"jiti ./release/is-version-published.ts\",\n    \"release:label-patches\": \"jiti ./release/label-patches.ts\",\n    \"release:pick-patches\": \"jiti ./release/pick-patches.ts\",\n    \"release:publish\": \"jiti ./release/publish.ts\",\n    \"release:unreleased-changes-exists\": \"jiti ./release/unreleased-changes-exists.ts\",\n    \"release:version\": \"jiti ./release/version.ts\",\n    \"release:write-changelog\": \"jiti ./release/write-changelog.ts\",\n    \"strict-ts\": \"jiti ./strict-ts.ts\",\n    \"task\": \"jiti ./task.ts\",\n    \"test\": \"cd .. && NODE_OPTIONS=--max_old_space_size=4096 vitest run --project scripts\",\n    \"test:watch\": \"cd .. && NODE_OPTIONS=--max_old_space_size=4096 vitest watch --project scripts\",\n    \"upgrade\": \"jiti ./task.ts\",\n    \"upload-bench\": \"jiti ./upload-bench.ts\"\n  },\n  \"dependencies\": {\n    \"@actions/core\": \"^1.11.1\",\n    \"@fal-works/esbuild-plugin-global-externals\": \"^2.1.2\",\n    \"@google-cloud/bigquery\": \"^6.2.1\",\n    \"@octokit/graphql\": \"^5.0.6\",\n    \"@octokit/request\": \"^8.4.1\",\n    \"@polka/parse\": \"^1.0.0-next.28\",\n    \"@testing-library/dom\": \"^10.4.0\",\n    \"@testing-library/jest-dom\": \"^6.9.1\",\n    \"@testing-library/react\": \"^16.0.0\",\n    \"@testing-library/user-event\": \"^14.5.2\",\n    \"@types/cross-spawn\": \"^6.0.6\",\n    \"@types/detect-port\": \"^1.3.5\",\n    \"@types/ejs\": \"^3.1.5\",\n    \"@types/escodegen\": \"^0.0.6\",\n    \"@types/http-server\": \"^0.12.4\",\n    \"@types/jest\": \"^29.5.12\",\n    \"@types/node\": \"^22.19.1\",\n    \"@types/prettier\": \"^3.0.0\",\n    \"@types/pretty-hrtime\": \"^1.0.3\",\n    \"@types/prompts\": \"2.4.9\",\n    \"@types/react\": \"^18.3.3\",\n    \"@types/react-dom\": \"^18.3.0\",\n    \"@types/semver\": \"^7.7.1\",\n    \"@types/serve-static\": \"^1.15.7\",\n    \"@types/uuid\": \"^9.0.8\",\n    \"@types/wait-on\": \"^5.3.4\",\n    \"@types/window-size\": \"^1.1.4\",\n    \"@typescript-eslint/eslint-plugin\": \"^8.48.0\",\n    \"@typescript-eslint/experimental-utils\": \"^5.62.0\",\n    \"@typescript-eslint/parser\": \"^8.48.0\",\n    \"@vitest/coverage-v8\": \"^4.1.0\",\n    \"ansi-regex\": \"^6.0.1\",\n    \"chromatic\": \"^13.3.4\",\n    \"codecov\": \"^3.8.1\",\n    \"commander\": \"^14.0.2\",\n    \"cross-env\": \"^7.0.3\",\n    \"cross-spawn\": \"^7.0.6\",\n    \"danger\": \"^13.0.5\",\n    \"dataloader\": \"^2.2.2\",\n    \"detect-port\": \"^1.6.1\",\n    \"diff-match-patch-es\": \"^0.1.0\",\n    \"ejs\": \"^3.1.10\",\n    \"ejs-lint\": \"^2.0.1\",\n    \"empathic\": \"^2.0.0\",\n    \"es-toolkit\": \"^1.43.0\",\n    \"esbuild\": \"^0.27.0\",\n    \"esbuild-raw-plugin\": \"^0.3.1\",\n    \"eslint\": \"^8.57.1\",\n    \"eslint-config-airbnb-typescript\": \"^18.0.0\",\n    \"eslint-import-resolver-typescript\": \"^3.10.1\",\n    \"eslint-plugin-compat\": \"^6.0.2\",\n    \"eslint-plugin-depend\": \"^1.4.0\",\n    \"eslint-plugin-eslint-comments\": \"^3.2.0\",\n    \"eslint-plugin-file-progress\": \"^1.5.0\",\n    \"eslint-plugin-html\": \"^6.2.0\",\n    \"eslint-plugin-import-x\": \"^4.16.1\",\n    \"eslint-plugin-json\": \"^4.0.1\",\n    \"eslint-plugin-json-files\": \"^4.4.2\",\n    \"eslint-plugin-jsx-a11y\": \"^6.10.2\",\n    \"eslint-plugin-local-rules\": \"portal:./eslint-plugin-local-rules\",\n    \"eslint-plugin-playwright\": \"^1.8.3\",\n    \"eslint-plugin-react\": \"^7.37.5\",\n    \"eslint-plugin-react-hooks\": \"^4.6.2\",\n    \"eslint-plugin-storybook\": \"workspace:*\",\n    \"execa\": \"^9.6.1\",\n    \"fast-folder-size\": \"^2.2.0\",\n    \"fast-glob\": \"^3.3.2\",\n    \"github-release-from-changelog\": \"^2.1.1\",\n    \"glob\": \"^10.5.0\",\n    \"globby\": \"^14.1.0\",\n    \"http-server\": \"^14.1.1\",\n    \"jiti\": \"^2.6.1\",\n    \"json5\": \"^2.2.3\",\n    \"junit-xml\": \"^1.2.0\",\n    \"knip\": \"^5.70.2\",\n    \"memoizerific\": \"^1.11.3\",\n    \"minimatch\": \"^10.0.1\",\n    \"node-gyp\": \"^12.1.0\",\n    \"npm-registry-client\": \"^8.6.0\",\n    \"ora\": \"^5.4.1\",\n    \"p-limit\": \"^7.2.0\",\n    \"p-retry\": \"^7.1.0\",\n    \"picocolors\": \"^1.1.0\",\n    \"playwright\": \"1.58.2\",\n    \"playwright-core\": \"1.58.2\",\n    \"polka\": \"^1.0.0-next.28\",\n    \"prettier\": \"^3.7.1\",\n    \"pretty-bytes\": \"^6.1.1\",\n    \"pretty-hrtime\": \"^1.0.3\",\n    \"pretty-ms\": \"^8.0.0\",\n    \"process\": \"^0.11.10\",\n    \"prompts\": \"^2.4.2\",\n    \"react\": \"^18.3.1\",\n    \"react-dom\": \"^18.3.1\",\n    \"recast\": \"^0.23.9\",\n    \"rimraf\": \"^6.1.2\",\n    \"rollup\": \"^4.21.0\",\n    \"rollup-plugin-dts\": \"^6.1.1\",\n    \"semver\": \"^7.7.3\",\n    \"serve-static\": \"^1.15.0\",\n    \"simple-git\": \"^3.30.0\",\n    \"slash\": \"^3.0.0\",\n    \"sort-package-json\": \"^3.5.0\",\n    \"tiny-invariant\": \"^1.3.3\",\n    \"tinyexec\": \"^0.3.0\",\n    \"trash\": \"^7.2.0\",\n    \"ts-dedent\": \"^2.2.0\",\n    \"type-fest\": \"~2.19\",\n    \"typescript\": \"^5.9.3\",\n    \"uuid\": \"^9.0.1\",\n    \"vitest\": \"^4.1.0\",\n    \"wait-on\": \"^8.0.3\",\n    \"window-size\": \"^1.1.1\",\n    \"yaml\": \"^2.8.1\",\n    \"zod\": \"^3.25.76\"\n  },\n  \"devDependencies\": {\n    \"oxfmt\": \"^0.41.0\"\n  },\n  \"optionalDependencies\": {\n    \"@verdaccio/types\": \"^10.8.0\",\n    \"verdaccio\": \"^5.33.0\",\n    \"verdaccio-auth-memory\": \"^10.3.1\"\n  },\n  \"packageManager\": \"yarn@4.10.3\",\n  \"nx\": {\n    \"includedScripts\": []\n  }\n}\n"
  },
  {
    "path": "scripts/prepare-sandbox.ts",
    "content": "import { existsSync } from 'node:fs';\nimport { cp, rm } from 'node:fs/promises';\n\nimport { join } from 'path';\nimport waitOn from 'wait-on';\n\nimport { ROOT_DIRECTORY, SANDBOX_DIRECTORY } from './utils/constants.ts';\nimport { exec } from './utils/exec.ts';\nimport { isNxTaskExecution } from './utils/nx.ts';\n\n/**\n * Prepares a sandbox for use during NX task execution.\n *\n * In NX CI, the `sandbox` task caches its output at `sandbox/<dir>` (inside the repo,\n * without node_modules). Downstream tasks need the sandbox at `../storybook-sandboxes/<dir>`\n * with node_modules installed. This function bridges that gap by:\n *\n * 1. Copying the cached sandbox to the working directory (if needed)\n * 2. Waiting for the local verdaccio registry (when using --no-link)\n * 3. Running `yarn install` to restore node_modules\n * 4. Running framework-specific setup (e.g. svelte-kit sync)\n * 5. Copying storybook-static from cache (if a build was cached)\n *\n * This is called at the start of each downstream task's `run()` (dev, build, serve, etc.)\n * instead of being a separate NX target, so that NX Cloud doesn't have uncacheable tasks.\n *\n * No-op when not running under NX (i.e. when using `yarn task` directly),\n * or when the sandbox is already prepared (node_modules exist).\n */\nexport async function prepareSandbox({ key, link }: { key: string; link: boolean }): Promise<void> {\n  // When running via `yarn task`, the sandbox task already fully initializes\n  // the sandbox (including node_modules), so no preparation is needed.\n  if (!isNxTaskExecution()) {\n    return;\n  }\n\n  const templateDir = key.replace('/', '-');\n\n  // sandboxDir: where tasks actually run (e.g. ../storybook-sandboxes/react-vite-default-ts)\n  // cacheDir: where NX caches sandbox output (e.g. sandbox/react-vite-default-ts, inside repo)\n  const sandboxDir = join(SANDBOX_DIRECTORY, templateDir);\n  const cacheDir = join(ROOT_DIRECTORY, 'sandbox', templateDir);\n\n  // Fast path: if node_modules already exist, the sandbox was already prepared\n  // by a previous task in the same pipeline (e.g. build already prepared, so serve can skip)\n  if (!existsSync(join(sandboxDir, 'node_modules'))) {\n    // Copy from NX cache to the actual working directory\n    if (sandboxDir !== cacheDir) {\n      console.log(`🧹 copying cached ${cacheDir} to ${sandboxDir}`);\n      await rm(sandboxDir, { recursive: true, force: true });\n      if (!existsSync(cacheDir)) {\n        throw new Error(\n          `Sandbox should exist at ${cacheDir}. Did you forget to run the sandbox command first?`\n        );\n      }\n      // cache dir is created in the sandbox command that should be run before this script\n      await cp(cacheDir, sandboxDir, { recursive: true, force: true });\n    }\n\n    // In --no-link mode, packages are installed from a local verdaccio registry\n    // that must be running before we can install\n    if (!link) {\n      await waitOn({\n        log: true,\n        resources: ['http://localhost:6001', 'http://localhost:6002'],\n        interval: 16,\n        timeout: 10000,\n      });\n    }\n\n    // Restore node_modules — the NX cache deliberately excludes them to keep\n    // the remote cache small. The yarn cache is shared, so this is fast.\n    await exec('yarn install --immutable', { cwd: sandboxDir }, { debug: true });\n  }\n\n  // SvelteKit requires a sync step to generate types after install\n  if (key.includes('svelte-kit')) {\n    await exec('yarn exec svelte-kit sync', { cwd: sandboxDir }, { debug: true });\n  }\n\n  // If a `build` task already ran and cached storybook-static, copy it over\n  // so that serve/chromatic tasks can use it without rebuilding\n  const storybookStaticSandboxDir = join(sandboxDir, 'storybook-static');\n  const storybookStaticCacheDir = join(cacheDir, 'storybook-static');\n\n  if (existsSync(storybookStaticCacheDir) && !existsSync(storybookStaticSandboxDir)) {\n    console.log(`🧹 copying cached ${storybookStaticCacheDir} to ${storybookStaticSandboxDir}`);\n    await cp(storybookStaticCacheDir, storybookStaticSandboxDir, {\n      recursive: true,\n      force: true,\n    });\n  }\n}\n"
  },
  {
    "path": "scripts/project.json",
    "content": "{\n  \"name\": \"scripts\",\n  \"$schema\": \"../node_modules/nx/schemas/project-schema.json\",\n  \"tags\": [\"library\"],\n  \"includedScripts\": [],\n  \"targets\": {\n    \"check\": {\n      \"dependsOn\": [],\n      \"executor\": \"nx:run-commands\",\n      \"options\": { \"cwd\": \"{projectRoot}\", \"command\": \"yarn check\" },\n      \"inputs\": [\"default\"],\n      \"cache\": true\n    },\n    \"lint\": {\n      \"executor\": \"nx:run-commands\",\n      \"options\": { \"cwd\": \"{projectRoot}\", \"command\": \"yarn lint\" },\n      \"cache\": true,\n      \"inputs\": [\"default\"],\n      \"configurations\": { \"production\": {} }\n    },\n    \"run-registry\": {},\n    \"publish\": {}\n  }\n}\n"
  },
  {
    "path": "scripts/release/__tests__/cancel-preparation-runs.test.ts",
    "content": "import { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport {\n  PREPARE_NON_PATCH_WORKFLOW_PATH,\n  PREPARE_PATCH_WORKFLOW_PATH,\n  run as cancelPreparationWorkflows,\n} from '../cancel-preparation-runs.ts';\nimport * as github_ from '../utils/github-client.ts';\n\nvi.mock('../utils/github-client');\n\nconst github = vi.mocked(github_);\n\nvi.spyOn(console, 'log').mockImplementation(() => {});\nvi.spyOn(console, 'warn').mockImplementation(() => {});\nvi.spyOn(console, 'error').mockImplementation(() => {});\n\ndescribe('Cancel preparation runs', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n    github.githubRestClient.mockImplementation(((route: string, options: any) => {\n      switch (route) {\n        case 'GET /repos/{owner}/{repo}/actions/workflows':\n          return {\n            data: {\n              workflows: [\n                {\n                  id: 1,\n                  path: PREPARE_PATCH_WORKFLOW_PATH,\n                },\n                {\n                  id: 2,\n                  path: PREPARE_NON_PATCH_WORKFLOW_PATH,\n                },\n              ],\n            },\n          };\n        case 'GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs':\n          return {\n            data: {\n              workflow_runs: [\n                {\n                  id: options.workflow_id === 1 ? 100 : 200,\n                  status: 'in_progress',\n                },\n                {\n                  id: options.workflow_id === 1 ? 150 : 250,\n                  status: 'completed',\n                },\n              ],\n            },\n          };\n        case 'POST /repos/{owner}/{repo}/actions/runs/{run_id}/cancel':\n          return undefined; // success\n        default:\n          throw new Error(`Unexpected route: ${route}`);\n      }\n    }) as any);\n  });\n\n  it('should fail early when no GH_TOKEN is set', async () => {\n    delete process.env.GH_TOKEN;\n    await expect(cancelPreparationWorkflows()).rejects.toThrowErrorMatchingInlineSnapshot(\n      `[Error: GH_TOKEN environment variable must be set, exiting.]`\n    );\n  });\n\n  it('should cancel all running preparation workflows in GitHub', async () => {\n    process.env.GH_TOKEN = 'MY_SECRET';\n\n    await expect(cancelPreparationWorkflows()).resolves.toBeUndefined();\n\n    expect(github.githubRestClient).toHaveBeenCalledTimes(5);\n    expect(github.githubRestClient).toHaveBeenCalledWith(\n      'POST /repos/{owner}/{repo}/actions/runs/{run_id}/cancel',\n      {\n        owner: 'storybookjs',\n        repo: 'storybook',\n        run_id: 100,\n      }\n    );\n    expect(github.githubRestClient).toHaveBeenCalledWith(\n      'POST /repos/{owner}/{repo}/actions/runs/{run_id}/cancel',\n      {\n        owner: 'storybookjs',\n        repo: 'storybook',\n        run_id: 200,\n      }\n    );\n    expect(github.githubRestClient).not.toHaveBeenCalledWith(\n      'POST /repos/{owner}/{repo}/actions/runs/{run_id}/cancel',\n      {\n        owner: 'storybookjs',\n        repo: 'storybook',\n        run_id: 150,\n      }\n    );\n    expect(github.githubRestClient).not.toHaveBeenCalledWith(\n      'POST /repos/{owner}/{repo}/actions/runs/{run_id}/cancel',\n      {\n        owner: 'storybookjs',\n        repo: 'storybook',\n        run_id: 250,\n      }\n    );\n  });\n});\n"
  },
  {
    "path": "scripts/release/__tests__/generate-pr-description.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport {\n  generateNonReleaseDescription,\n  generateReleaseDescription,\n  mapCherryPicksToTodo,\n  mapToChangelist,\n} from '../generate-pr-description.ts';\nimport type { Change } from '../utils/get-changes.ts';\n\ndescribe('Generate PR Description', () => {\n  const changes: Change[] = [\n    {\n      user: 'JReinhold',\n      id: 'pr-id-42',\n      title: 'Some PR title for a bug',\n      labels: ['bug', 'build', 'other label', 'patch:yes'],\n      commit: 'abc123',\n      pull: 42,\n      state: 'MERGED',\n      links: {\n        commit: '[abc123](https://github.com/storybookjs/storybook/commit/abc123)',\n        pull: '[#42](https://github.com/storybookjs/storybook/pull/42)',\n        user: '[@JReinhold](https://github.com/JReinhold)',\n      },\n    },\n    {\n      // this Bump version commit should be ignored\n      id: null,\n      user: 'storybook-bot',\n      pull: null,\n      state: null,\n      commit: '012b58140c3606efeacbe99c0c410624b0a1ed1f',\n      title: 'Bump version on `next`: preminor (alpha) from 7.2.0 to 7.3.0-alpha.0',\n      labels: null,\n      links: {\n        commit:\n          '[`012b58140c3606efeacbe99c0c410624b0a1ed1f`](https://github.com/storybookjs/storybook/commit/012b58140c3606efeacbe99c0c410624b0a1ed1f)',\n        pull: null,\n        user: '[@storybook-bot](https://github.com/storybook-bot)',\n      },\n    },\n    {\n      id: null,\n      user: 'shilman',\n      title: 'Some title for a \"direct commit\"',\n      labels: null,\n      state: null,\n      commit: '22bb11',\n      pull: null,\n      links: {\n        commit: '[22bb11](https://github.com/storybookjs/storybook/commit/22bb11)',\n        pull: null,\n        user: '[@shilman](https://github.com/shilman)',\n      },\n    },\n    {\n      id: 'pr-id-11',\n      user: 'shilman',\n      title: 'Another PR `title` for docs',\n      labels: ['another label', 'documentation', 'patch:yes'],\n      commit: 'ddd222',\n      state: 'MERGED',\n      pull: 11,\n      links: {\n        commit: '[ddd222](https://github.com/storybookjs/storybook/commit/ddd222)',\n        pull: '[#11](https://github.com/storybookjs/storybook/pull/11)',\n        user: '[@shilman](https://github.com/shilman)',\n      },\n    },\n    {\n      id: 'pr-id-48',\n      user: 'JReinhold',\n      title: \"Some PR title for a 'new' feature\",\n      labels: ['feature request', 'other label'],\n      commit: 'wow1337',\n      pull: 48,\n      state: 'MERGED',\n      links: {\n        commit: '[wow1337](https://github.com/storybookjs/storybook/commit/wow1337)',\n        pull: '[#48](https://github.com/storybookjs/storybook/pull/48)',\n        user: '[@JReinhold](https://github.com/JReinhold)',\n      },\n    },\n    {\n      id: 'pr-id-77',\n      user: 'JReinhold',\n      title: 'Some PR title with a missing label',\n      labels: ['incorrect label', 'other label'],\n      commit: 'bad999',\n      state: 'MERGED',\n      pull: 77,\n      links: {\n        commit: '[bad999](https://github.com/storybookjs/storybook/commit/bad999)',\n        pull: '[#77](https://github.com/storybookjs/storybook/pull/77)',\n        user: '[@JReinhold](https://github.com/JReinhold)',\n      },\n    },\n  ];\n  describe('mapToChangelist', () => {\n    it('should return a correct string for patch PRs', () => {\n      expect(mapToChangelist({ changes, unpickedPatches: true })).toMatchInlineSnapshot(`\n        \"- [ ] **🐛 Bug**: Some PR title for a bug [#42](https://github.com/storybookjs/storybook/pull/42)\n        - [ ] **✨ Feature Request**: Some PR title for a 'new' feature [#48](https://github.com/storybookjs/storybook/pull/48)\n        - [ ] **⚠️ Direct commit**: Some title for a \"direct commit\" [22bb11](https://github.com/storybookjs/storybook/commit/22bb11)\n        - [ ] **📝 Documentation**: Another PR \\`title\\` for docs [#11](https://github.com/storybookjs/storybook/pull/11)\n        - [ ] **❔ Missing Label**: Some PR title with a missing label [#77](https://github.com/storybookjs/storybook/pull/77)\"\n      `);\n    });\n    it('should return a correct string for prerelease PRs', () => {\n      expect(mapToChangelist({ changes, unpickedPatches: false })).toMatchInlineSnapshot(`\n        \"- [ ] **🐛 Bug**: Some PR title for a bug [#42](https://github.com/storybookjs/storybook/pull/42) (will also be patched)\n        - [ ] **✨ Feature Request**: Some PR title for a 'new' feature [#48](https://github.com/storybookjs/storybook/pull/48)\n        - [ ] **⚠️ Direct commit**: Some title for a \"direct commit\" [22bb11](https://github.com/storybookjs/storybook/commit/22bb11)\n        - [ ] **📝 Documentation**: Another PR \\`title\\` for docs [#11](https://github.com/storybookjs/storybook/pull/11) (will also be patched)\n        - [ ] **❔ Missing Label**: Some PR title with a missing label [#77](https://github.com/storybookjs/storybook/pull/77)\"\n      `);\n    });\n  });\n\n  describe('mapCherryPicksToTodo', () => {\n    it('should return a correct string for releases', () => {\n      expect(mapCherryPicksToTodo({ changes, commits: ['abc123'] })).toMatchInlineSnapshot(`\n        \"## 🍒 Manual cherry picking needed!\n\n        The following pull requests could not be cherry-picked automatically because it resulted in merge conflicts.\n        For each pull request below, you need to either manually cherry pick it, or discard it by replacing the \"patch:yes\" label with \"patch:no\" on the PR and re-generate this PR.\n\n        - [ ] [#42](https://github.com/storybookjs/storybook/pull/42): \\`git cherry-pick -m1 -x abc123\\`\"\n      `);\n    });\n  });\n\n  describe('description generator', () => {\n    const changeList = `- **🐛 Bug**: Some PR title for a bug [#42](https://github.com/storybookjs/storybook/pull/42)\n\\t- [ ] The change is appropriate for the version bump\n\\t- [ ] The PR is labeled correctly\n\\t- [ ] The PR title is correct\n- **⚠️ Direct commit**: Some title for a \\\\\"direct commit\\\\\" [22bb11](https://github.com/storybookjs/storybook/commit/22bb11)\n\\t- [ ] The change is appropriate for the version bump\n- **📝 Documentation**: Another PR \\\\\\`title\\\\\\` for docs [#11](https://github.com/storybookjs/storybook/pull/11)\n\\t- [ ] The change is appropriate for the version bump\n\\t- [ ] The PR is labeled correctly\n\\t- [ ] The PR title is correct\n- **✨ Feature Request**: Some PR title for a \\\\'new\\\\' feature [#48](https://github.com/storybookjs/storybook/pull/48)\n\\t- [ ] The change is appropriate for the version bump\n\\t- [ ] The PR is labeled correctly\n\\t- [ ] The PR title is correct\n- **⚠️ Missing Label**: Some PR title with a missing label [#77](https://github.com/storybookjs/storybook/pull/77)\n\\t- [ ] The change is appropriate for the version bump\n\\t- [ ] The PR is labeled correctly\n\\t- [ ] The PR title is correct`;\n\n    const manualCherryPicks = `## 🍒 Manual cherry picking needed!\n\nThe following pull requests could not be cherry-picked automatically because it resulted in merge conflicts.\nFor each pull request below, you need to either manually cherry pick it, or discard it by removing the \"patch\" label from the PR and re-generate this PR.\n\n- [ ] [#42](https://github.com/storybookjs/storybook/pull/42): \\`git cherry-pick -m1 -x abc123\\``;\n\n    it('should return a correct string with cherry picks for releases', () => {\n      const changelogText = `## 7.1.0-alpha.11\n\n- Some PR \\`title\\` for a bug [#42](https://github.com/storybookjs/storybook/pull/42), thanks [@JReinhold](https://github.com/JReinhold)\n- Some PR 'title' for a feature request [#48](https://github.com/storybookjs/storybook/pull/48), thanks [@JReinhold](https://github.com/JReinhold)\n- Another PR \"title\" for maintenance [#49](https://github.com/storybookjs/storybook/pull/49), thanks [@JReinhold](https://github.com/JReinhold)`;\n      expect(\n        generateReleaseDescription({\n          currentVersion: '7.1.0-alpha.10',\n          nextVersion: '7.1.0-alpha.11',\n          changeList,\n          changelogText,\n          manualCherryPicks,\n        })\n      ).toMatchInlineSnapshot(`\n        \"This is an automated pull request that bumps the version from \\\\\\`7.1.0-alpha.10\\\\\\` to \\\\\\`7.1.0-alpha.11\\\\\\`.\n        Once this pull request is merged, it will trigger a new release of version \\\\\\`7.1.0-alpha.11\\\\\\`.\n        If you\\\\'re not a core maintainer with permissions to release you can ignore this pull request.\n\n        ## To do\n\n        Before merging the PR, there are a few QA steps to go through:\n\n        - [ ] Add the \\\\\"freeze\\\\\" label to this PR, to ensure it doesn\\\\'t get automatically forced pushed by new changes.\n        - [ ] Add the \\\\\"ci:daily\\\\\" label to this PR, to trigger the full test suite to run on this PR.\n\n        And for each change below:\n\n        1. Ensure the change is appropriate for the version bump. E.g. patch release should only contain patches, not new or de-stabilizing features. If a change is not appropriate, revert the PR.\n        2. Ensure the PR is labeled correctly with one of: \\\\\"BREAKING CHANGE\\\\\", \\\\\"feature request\\\\\", \\\\\"bug\\\\\", \\\\\"maintenance\\\\\", \\\\\"dependencies\\\\\", \\\\\"documentation\\\\\", \\\\\"build\\\\\", \\\\\"unknown\\\\\".\n        3. Ensure the PR title is correct, and follows the format \\\\\"[Area]: [Summary]\\\\\", e.g. *\\\\\"React: Fix hooks in CSF3 render functions\\\\\"*. If it is not correct, change the title in the PR.\n            - Areas include: React, Vue, Core, Docs, Controls, etc.\n            - First word of summary indicates the type: “Add”, “Fix”, “Upgrade”, etc.\n            - The entire title should fit on a line\n\n        This is a list of all the PRs merged and commits pushed directly to \\\\\\`next\\\\\\`, that will be part of this release:\n\n        - **🐛 Bug**: Some PR title for a bug [#42](https://github.com/storybookjs/storybook/pull/42)\n        \t- [ ] The change is appropriate for the version bump\n        \t- [ ] The PR is labeled correctly\n        \t- [ ] The PR title is correct\n        - **⚠️ Direct commit**: Some title for a \\\\\\\\\"direct commit\\\\\\\\\" [22bb11](https://github.com/storybookjs/storybook/commit/22bb11)\n        \t- [ ] The change is appropriate for the version bump\n        - **📝 Documentation**: Another PR \\\\\\\\\\`title\\\\\\\\\\` for docs [#11](https://github.com/storybookjs/storybook/pull/11)\n        \t- [ ] The change is appropriate for the version bump\n        \t- [ ] The PR is labeled correctly\n        \t- [ ] The PR title is correct\n        - **✨ Feature Request**: Some PR title for a \\\\\\\\'new\\\\\\\\' feature [#48](https://github.com/storybookjs/storybook/pull/48)\n        \t- [ ] The change is appropriate for the version bump\n        \t- [ ] The PR is labeled correctly\n        \t- [ ] The PR title is correct\n        - **⚠️ Missing Label**: Some PR title with a missing label [#77](https://github.com/storybookjs/storybook/pull/77)\n        \t- [ ] The change is appropriate for the version bump\n        \t- [ ] The PR is labeled correctly\n        \t- [ ] The PR title is correct\n\n        ## 🍒 Manual cherry picking needed!\n\n        The following pull requests could not be cherry-picked automatically because it resulted in merge conflicts.\n        For each pull request below, you need to either manually cherry pick it, or discard it by removing the \\\\\"patch\\\\\" label from the PR and re-generate this PR.\n\n        - [ ] [#42](https://github.com/storybookjs/storybook/pull/42): \\\\\\`git cherry-pick -m1 -x abc123\\\\\\`\n\n        If you\\\\'ve made any changes doing the above QA (change PR titles, revert PRs), manually trigger a re-generation of this PR with [this workflow](https://github.com/storybookjs/storybook/actions/workflows/prepare-non-patch-release.yml) and wait for it to finish. It will wipe your progress in this to do, which is expected.\n\n        Feel free to manually commit any changes necessary to this branch **after** you\\\\'ve done the last re-generation, following the [Make Manual Changes](https://github.com/storybookjs/storybook/blob/next/CONTRIBUTING/RELEASING.md#5-make-manual-changes) section in the docs, *especially* if you\\\\'re making changes to the changelog.\n\n        When everything above is done:\n        - Merge this PR\n        - [Follow the run of the publish action](https://github.com/storybookjs/storybook/actions/workflows/publish.yml)\n\n        ---\n\n        # Generated changelog\n\n        ## 7.1.0-alpha.11\n\n        - Some PR \\\\\\`title\\\\\\` for a bug [#42](https://github.com/storybookjs/storybook/pull/42), thanks [JReinhold](https://github.com/JReinhold)\n        - Some PR \\\\'title\\\\' for a feature request [#48](https://github.com/storybookjs/storybook/pull/48), thanks [JReinhold](https://github.com/JReinhold)\n        - Another PR \\\\\"title\\\\\" for maintenance [#49](https://github.com/storybookjs/storybook/pull/49), thanks [JReinhold](https://github.com/JReinhold)\"\n      `);\n    });\n\n    it('should return a correct string for non-releases with cherry picks', () => {\n      expect(generateNonReleaseDescription(changeList, manualCherryPicks)).toMatchInlineSnapshot(`\n        \"This is an automated pull request. None of the changes requires a version bump, they are only internal or documentation related. Merging this PR will not trigger a new release, but documentation will be updated.\n        If you\\\\'re not a core maintainer with permissions to release you can ignore this pull request.\n\n        ## To do\n\n        Before merging the PR:\n\n        - [ ] Add the \\\\\"freeze\\\\\" label to this PR, to ensure it doesn\\\\'t get automatically forced pushed by new changes.\n        - [ ] Add the \\\\\"ci:daily\\\\\" label to this PR, to trigger the full test suite to run on this PR.\n\n        This is a list of all the PRs merged and commits pushed directly to \\\\\\`next\\\\\\` since the last release:\n\n        - **🐛 Bug**: Some PR title for a bug [#42](https://github.com/storybookjs/storybook/pull/42)\n        \t- [ ] The change is appropriate for the version bump\n        \t- [ ] The PR is labeled correctly\n        \t- [ ] The PR title is correct\n        - **⚠️ Direct commit**: Some title for a \\\\\\\\\"direct commit\\\\\\\\\" [22bb11](https://github.com/storybookjs/storybook/commit/22bb11)\n        \t- [ ] The change is appropriate for the version bump\n        - **📝 Documentation**: Another PR \\\\\\\\\\`title\\\\\\\\\\` for docs [#11](https://github.com/storybookjs/storybook/pull/11)\n        \t- [ ] The change is appropriate for the version bump\n        \t- [ ] The PR is labeled correctly\n        \t- [ ] The PR title is correct\n        - **✨ Feature Request**: Some PR title for a \\\\\\\\'new\\\\\\\\' feature [#48](https://github.com/storybookjs/storybook/pull/48)\n        \t- [ ] The change is appropriate for the version bump\n        \t- [ ] The PR is labeled correctly\n        \t- [ ] The PR title is correct\n        - **⚠️ Missing Label**: Some PR title with a missing label [#77](https://github.com/storybookjs/storybook/pull/77)\n        \t- [ ] The change is appropriate for the version bump\n        \t- [ ] The PR is labeled correctly\n        \t- [ ] The PR title is correct\n\n        ## 🍒 Manual cherry picking needed!\n\n        The following pull requests could not be cherry-picked automatically because it resulted in merge conflicts.\n        For each pull request below, you need to either manually cherry pick it, or discard it by removing the \\\\\"patch\\\\\" label from the PR and re-generate this PR.\n\n        - [ ] [#42](https://github.com/storybookjs/storybook/pull/42): \\\\\\`git cherry-pick -m1 -x abc123\\\\\\`\n\n        If you\\\\'ve made any changes (change PR titles, revert PRs), manually trigger a re-generation of this PR with [this workflow](https://github.com/storybookjs/storybook/actions/workflows/prepare-patch-release.yml) and wait for it to finish.\n\n        Feel free to manually commit any changes necessary to this branch **after** you\\\\'ve done the last re-generation, following the [Make Manual Changes](https://github.com/storybookjs/storybook/blob/next/CONTRIBUTING/RELEASING.md#5-make-manual-changes) section in the docs.\n\n        When everything above is done:\n        - Merge this PR\n        - [Follow the run of the publish action](https://github.com/storybookjs/storybook/actions/workflows/publish.yml)\"\n      `);\n    });\n\n    it('should return a correct string without cherry picks for releases', () => {\n      const changelogText = `## 7.1.0-alpha.11\n\n- Some PR \\`title\\` for a bug [#42](https://github.com/storybookjs/storybook/pull/42), thanks [@JReinhold](https://github.com/JReinhold)\n- Some PR 'title' for a feature request [#48](https://github.com/storybookjs/storybook/pull/48), thanks [@JReinhold](https://github.com/JReinhold)\n- Another PR \"title\" for maintenance [#49](https://github.com/storybookjs/storybook/pull/49), thanks [@JReinhold](https://github.com/JReinhold)`;\n      expect(\n        generateReleaseDescription({\n          currentVersion: '7.1.0-alpha.10',\n          nextVersion: '7.1.0-alpha.11',\n          changeList,\n          changelogText,\n        })\n      ).toMatchInlineSnapshot(`\n        \"This is an automated pull request that bumps the version from \\\\\\`7.1.0-alpha.10\\\\\\` to \\\\\\`7.1.0-alpha.11\\\\\\`.\n        Once this pull request is merged, it will trigger a new release of version \\\\\\`7.1.0-alpha.11\\\\\\`.\n        If you\\\\'re not a core maintainer with permissions to release you can ignore this pull request.\n\n        ## To do\n\n        Before merging the PR, there are a few QA steps to go through:\n\n        - [ ] Add the \\\\\"freeze\\\\\" label to this PR, to ensure it doesn\\\\'t get automatically forced pushed by new changes.\n        - [ ] Add the \\\\\"ci:daily\\\\\" label to this PR, to trigger the full test suite to run on this PR.\n\n        And for each change below:\n\n        1. Ensure the change is appropriate for the version bump. E.g. patch release should only contain patches, not new or de-stabilizing features. If a change is not appropriate, revert the PR.\n        2. Ensure the PR is labeled correctly with one of: \\\\\"BREAKING CHANGE\\\\\", \\\\\"feature request\\\\\", \\\\\"bug\\\\\", \\\\\"maintenance\\\\\", \\\\\"dependencies\\\\\", \\\\\"documentation\\\\\", \\\\\"build\\\\\", \\\\\"unknown\\\\\".\n        3. Ensure the PR title is correct, and follows the format \\\\\"[Area]: [Summary]\\\\\", e.g. *\\\\\"React: Fix hooks in CSF3 render functions\\\\\"*. If it is not correct, change the title in the PR.\n            - Areas include: React, Vue, Core, Docs, Controls, etc.\n            - First word of summary indicates the type: “Add”, “Fix”, “Upgrade”, etc.\n            - The entire title should fit on a line\n\n        This is a list of all the PRs merged and commits pushed directly to \\\\\\`next\\\\\\`, that will be part of this release:\n\n        - **🐛 Bug**: Some PR title for a bug [#42](https://github.com/storybookjs/storybook/pull/42)\n        \t- [ ] The change is appropriate for the version bump\n        \t- [ ] The PR is labeled correctly\n        \t- [ ] The PR title is correct\n        - **⚠️ Direct commit**: Some title for a \\\\\\\\\"direct commit\\\\\\\\\" [22bb11](https://github.com/storybookjs/storybook/commit/22bb11)\n        \t- [ ] The change is appropriate for the version bump\n        - **📝 Documentation**: Another PR \\\\\\\\\\`title\\\\\\\\\\` for docs [#11](https://github.com/storybookjs/storybook/pull/11)\n        \t- [ ] The change is appropriate for the version bump\n        \t- [ ] The PR is labeled correctly\n        \t- [ ] The PR title is correct\n        - **✨ Feature Request**: Some PR title for a \\\\\\\\'new\\\\\\\\' feature [#48](https://github.com/storybookjs/storybook/pull/48)\n        \t- [ ] The change is appropriate for the version bump\n        \t- [ ] The PR is labeled correctly\n        \t- [ ] The PR title is correct\n        - **⚠️ Missing Label**: Some PR title with a missing label [#77](https://github.com/storybookjs/storybook/pull/77)\n        \t- [ ] The change is appropriate for the version bump\n        \t- [ ] The PR is labeled correctly\n        \t- [ ] The PR title is correct\n\n\n\n        If you\\\\'ve made any changes doing the above QA (change PR titles, revert PRs), manually trigger a re-generation of this PR with [this workflow](https://github.com/storybookjs/storybook/actions/workflows/prepare-non-patch-release.yml) and wait for it to finish. It will wipe your progress in this to do, which is expected.\n\n        Feel free to manually commit any changes necessary to this branch **after** you\\\\'ve done the last re-generation, following the [Make Manual Changes](https://github.com/storybookjs/storybook/blob/next/CONTRIBUTING/RELEASING.md#5-make-manual-changes) section in the docs, *especially* if you\\\\'re making changes to the changelog.\n\n        When everything above is done:\n        - Merge this PR\n        - [Follow the run of the publish action](https://github.com/storybookjs/storybook/actions/workflows/publish.yml)\n\n        ---\n\n        # Generated changelog\n\n        ## 7.1.0-alpha.11\n\n        - Some PR \\\\\\`title\\\\\\` for a bug [#42](https://github.com/storybookjs/storybook/pull/42), thanks [JReinhold](https://github.com/JReinhold)\n        - Some PR \\\\'title\\\\' for a feature request [#48](https://github.com/storybookjs/storybook/pull/48), thanks [JReinhold](https://github.com/JReinhold)\n        - Another PR \\\\\"title\\\\\" for maintenance [#49](https://github.com/storybookjs/storybook/pull/49), thanks [JReinhold](https://github.com/JReinhold)\"\n      `);\n    });\n\n    it('should return a correct string for non-releases without cherry picks', () => {\n      expect(generateNonReleaseDescription(changeList)).toMatchInlineSnapshot(`\n        \"This is an automated pull request. None of the changes requires a version bump, they are only internal or documentation related. Merging this PR will not trigger a new release, but documentation will be updated.\n        If you\\\\'re not a core maintainer with permissions to release you can ignore this pull request.\n\n        ## To do\n\n        Before merging the PR:\n\n        - [ ] Add the \\\\\"freeze\\\\\" label to this PR, to ensure it doesn\\\\'t get automatically forced pushed by new changes.\n        - [ ] Add the \\\\\"ci:daily\\\\\" label to this PR, to trigger the full test suite to run on this PR.\n\n        This is a list of all the PRs merged and commits pushed directly to \\\\\\`next\\\\\\` since the last release:\n\n        - **🐛 Bug**: Some PR title for a bug [#42](https://github.com/storybookjs/storybook/pull/42)\n        \t- [ ] The change is appropriate for the version bump\n        \t- [ ] The PR is labeled correctly\n        \t- [ ] The PR title is correct\n        - **⚠️ Direct commit**: Some title for a \\\\\\\\\"direct commit\\\\\\\\\" [22bb11](https://github.com/storybookjs/storybook/commit/22bb11)\n        \t- [ ] The change is appropriate for the version bump\n        - **📝 Documentation**: Another PR \\\\\\\\\\`title\\\\\\\\\\` for docs [#11](https://github.com/storybookjs/storybook/pull/11)\n        \t- [ ] The change is appropriate for the version bump\n        \t- [ ] The PR is labeled correctly\n        \t- [ ] The PR title is correct\n        - **✨ Feature Request**: Some PR title for a \\\\\\\\'new\\\\\\\\' feature [#48](https://github.com/storybookjs/storybook/pull/48)\n        \t- [ ] The change is appropriate for the version bump\n        \t- [ ] The PR is labeled correctly\n        \t- [ ] The PR title is correct\n        - **⚠️ Missing Label**: Some PR title with a missing label [#77](https://github.com/storybookjs/storybook/pull/77)\n        \t- [ ] The change is appropriate for the version bump\n        \t- [ ] The PR is labeled correctly\n        \t- [ ] The PR title is correct\n\n\n\n        If you\\\\'ve made any changes (change PR titles, revert PRs), manually trigger a re-generation of this PR with [this workflow](https://github.com/storybookjs/storybook/actions/workflows/prepare-patch-release.yml) and wait for it to finish.\n\n        Feel free to manually commit any changes necessary to this branch **after** you\\\\'ve done the last re-generation, following the [Make Manual Changes](https://github.com/storybookjs/storybook/blob/next/CONTRIBUTING/RELEASING.md#5-make-manual-changes) section in the docs.\n\n        When everything above is done:\n        - Merge this PR\n        - [Follow the run of the publish action](https://github.com/storybookjs/storybook/actions/workflows/publish.yml)\"\n      `);\n    });\n  });\n});\n"
  },
  {
    "path": "scripts/release/__tests__/is-pr-frozen.test.ts",
    "content": "import * as fspImp from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { describe, expect, it, vi } from 'vitest';\n\nimport * as simpleGitImp from 'simple-git';\n\nimport type * as MockedFSPExtra from '../../../code/__mocks__/fs/promises.ts';\nimport type * as MockedSimpleGit from '../../__mocks__/simple-git.ts';\nimport { CODE_DIRECTORY } from '../../utils/constants.ts';\nimport { run as isPrFrozen } from '../is-pr-frozen.ts';\nimport type { PullRequestInfo } from '../utils/get-github-info.ts';\nimport { getPullInfoFromCommit } from '../utils/get-github-info.ts';\n\nvi.mock('../utils/get-github-info');\nvi.mock('simple-git');\nvi.mock('node:fs/promises', async () => import('../../../code/__mocks__/fs/promises.ts'));\nconst fsp = fspImp as unknown as typeof MockedFSPExtra;\nconst simpleGit = simpleGitImp as unknown as typeof MockedSimpleGit;\n\nconst CODE_PACKAGE_JSON_PATH = join(CODE_DIRECTORY, 'package.json');\n\nfsp.__setMockFiles({\n  [CODE_PACKAGE_JSON_PATH]: JSON.stringify({ version: '1.0.0' }),\n});\n\ndescribe('isPrFrozen', () => {\n  it('should return true when PR is frozen', async () => {\n    vi.mocked(getPullInfoFromCommit).mockResolvedValue({\n      labels: ['freeze'],\n      state: 'OPEN',\n    } as PullRequestInfo);\n    await expect(isPrFrozen({ patch: false })).resolves.toBe(true);\n  });\n\n  it('should return false when PR is not frozen', async () => {\n    vi.mocked(getPullInfoFromCommit).mockResolvedValue({\n      labels: [],\n      state: 'OPEN',\n    } as PullRequestInfo);\n    await expect(isPrFrozen({ patch: false })).resolves.toBe(false);\n  });\n\n  it('should return false when PR is closed', async () => {\n    vi.mocked(getPullInfoFromCommit).mockResolvedValue({\n      labels: ['freeze'],\n      state: 'CLOSED',\n    } as PullRequestInfo);\n    await expect(isPrFrozen({ patch: false })).resolves.toBe(false);\n  });\n\n  it('should look for patch PRs when patch is true', async () => {\n    vi.mocked(getPullInfoFromCommit).mockResolvedValue({\n      labels: [],\n    } as PullRequestInfo);\n    await isPrFrozen({ patch: true });\n\n    expect(simpleGit.__fetch).toHaveBeenCalledWith('origin', 'version-patch-from-1.0.0', {\n      '--depth': 1,\n    });\n  });\n\n  it('should look for prerelease PRs when patch is false', async () => {\n    vi.mocked(getPullInfoFromCommit).mockResolvedValue({\n      labels: [],\n    } as PullRequestInfo);\n    await isPrFrozen({ patch: false });\n\n    expect(simpleGit.__fetch).toHaveBeenCalledWith('origin', 'version-non-patch-from-1.0.0', {\n      '--depth': 1,\n    });\n  });\n});\n"
  },
  {
    "path": "scripts/release/__tests__/label-patches.test.ts",
    "content": "import { beforeEach, expect, it, vi } from 'vitest';\n\nimport ansiRegex from 'ansi-regex';\nimport type { LogResult } from 'simple-git';\n\nimport { run } from '../label-patches.ts';\nimport * as githubInfo_ from '../utils/get-github-info.ts';\nimport * as gitClient_ from '../utils/git-client.ts';\nimport * as github_ from '../utils/github-client.ts';\n\nvi.mock('uuid');\nvi.mock('../utils/get-github-info');\nvi.mock('../utils/github-client');\nvi.mock('../utils/git-client');\n\nconst gitClient = vi.mocked(gitClient_, true);\nconst github = vi.mocked(github_, true);\nconst githubInfo = vi.mocked(githubInfo_, true);\n\nconst remoteMock = [\n  {\n    name: 'origin',\n    refs: {\n      fetch: 'https://github.com/storybookjs/storybook.git',\n      push: 'https://github.com/storybookjs/storybook.git',\n    },\n  },\n];\n\nconst gitLogMock: LogResult = {\n  all: [\n    {\n      hash: 'some-hash',\n      date: '2023-06-07T09:45:11+02:00',\n      message: 'Something else',\n      refs: 'HEAD -> main',\n      body: '',\n      author_name: 'Jeppe Reinhold',\n      author_email: 'jeppe@chromatic.com',\n    },\n    {\n      hash: 'b75879c4d3d72f7830e9c5fca9f75a303ddb194d',\n      date: '2023-06-07T09:45:11+02:00',\n      message: 'Merge pull request #55 from storybookjs/fixes',\n      refs: 'HEAD -> main',\n      body:\n        'Legal: Fix license\\n' +\n        '(cherry picked from commit 930b47f011f750c44a1782267d698ccdd3c04da3)\\n',\n      author_name: 'Jeppe Reinhold',\n      author_email: 'jeppe@chromatic.com',\n    },\n  ],\n  latest: null!,\n  total: 1,\n};\n\nconst pullInfoMock = {\n  user: 'JReinhold',\n  id: 'pr_id',\n  pull: 55,\n  commit: '930b47f011f750c44a1782267d698ccdd3c04da3',\n  title: 'Legal: Fix license',\n  labels: ['documentation', 'patch:yes', 'patch:done'],\n  state: 'MERGED',\n  links: {\n    commit:\n      '[`930b47f011f750c44a1782267d698ccdd3c04da3`](https://github.com/storybookjs/storybook/commit/930b47f011f750c44a1782267d698ccdd3c04da3)',\n    pull: '[#55](https://github.com/storybookjs/storybook/pull/55)',\n    user: '[@JReinhold](https://github.com/JReinhold)',\n  },\n};\n\nbeforeEach(() => {\n  gitClient.getLatestTag.mockResolvedValue('v7.2.1');\n  gitClient.git.log.mockResolvedValue(gitLogMock);\n  gitClient.git.getRemotes.mockResolvedValue(remoteMock);\n  githubInfo.getPullInfoFromCommit.mockResolvedValue(pullInfoMock);\n  github.getLabelIds.mockResolvedValue({ 'patch:done': 'pick-id' });\n  github.getUnpickedPRs.mockResolvedValue([\n    {\n      number: 42,\n      id: 'some-id',\n      branch: 'some-patching-branch',\n      title: 'Fix: Patch this PR',\n      mergeCommit: 'abcd1234',\n    },\n    {\n      number: 44,\n      id: 'other-id',\n      branch: 'other-patching-branch',\n      title: 'Fix: Also patch this PR',\n      mergeCommit: 'abcd1234',\n    },\n  ]);\n});\n\nit('should fail early when no GH_TOKEN is set', async () => {\n  delete process.env.GH_TOKEN;\n  await expect(run({})).rejects.toThrowErrorMatchingInlineSnapshot(\n    `[Error: GH_TOKEN environment variable must be set, exiting.]`\n  );\n});\n\nit('should label the PR associated with cherry picks in the current branch', async () => {\n  process.env.GH_TOKEN = 'MY_SECRET';\n\n  const writeStderr = vi.spyOn(process.stderr, 'write').mockImplementation((() => {}) as any);\n\n  await run({});\n  expect(github.githubGraphQlClient.mock.calls).toMatchInlineSnapshot(`\n    [\n      [\n        \"\n          mutation ($input: AddLabelsToLabelableInput!) {\n            addLabelsToLabelable(input: $input) {\n              clientMutationId\n            }\n          }\n        \",\n        {\n          \"input\": {\n            \"clientMutationId\": \"7efda802-d7d1-5d76-97d6-cc16a9f3e357\",\n            \"labelIds\": [\n              \"pick-id\",\n            ],\n            \"labelableId\": \"pr_id\",\n          },\n        },\n      ],\n    ]\n  `);\n\n  const stderrCalls = writeStderr.mock.calls\n    .map(([text]) =>\n      typeof text === 'string'\n        ? text\n            .replace(ansiRegex(), '')\n            .replace(/[^\\x20-\\x7E]/g, '')\n            .replaceAll('-', '')\n            .trim()\n        : text\n    )\n    .filter((text) => text !== '');\n\n  expect(stderrCalls).toMatchInlineSnapshot(`\n    [\n      \"Looking for latest tag\",\n      \"Found latest tag: v7.2.1\",\n      \"Looking at cherry pick commits since v7.2.1\",\n      \"Found the following picks : Commit: 930b47f011f750c44a1782267d698ccdd3c04da3 PR: [#55](https://github.com/storybookjs/storybook/pull/55)\",\n      \"Labeling 1 PRs with the patch:done label...\",\n      \"Successfully labeled all PRs with the patch:done label.\",\n    ]\n  `);\n});\n\nit('should label all PRs when the --all flag is passed', async () => {\n  process.env.GH_TOKEN = 'MY_SECRET';\n\n  // clear the git log, it shouldn't depend on it in --all mode\n  gitClient.git.log.mockResolvedValue({\n    all: [],\n    latest: null!,\n    total: 0,\n  });\n\n  const writeStderr = vi.spyOn(process.stderr, 'write').mockImplementation((() => {}) as any);\n\n  await run({ all: true });\n  expect(github.githubGraphQlClient.mock.calls).toMatchInlineSnapshot(`\n    [\n      [\n        \"\n          mutation ($input: AddLabelsToLabelableInput!) {\n            addLabelsToLabelable(input: $input) {\n              clientMutationId\n            }\n          }\n        \",\n        {\n          \"input\": {\n            \"clientMutationId\": \"39cffd21-7933-56e4-9d9c-1afeda9d5906\",\n            \"labelIds\": [\n              \"pick-id\",\n            ],\n            \"labelableId\": \"some-id\",\n          },\n        },\n      ],\n      [\n        \"\n          mutation ($input: AddLabelsToLabelableInput!) {\n            addLabelsToLabelable(input: $input) {\n              clientMutationId\n            }\n          }\n        \",\n        {\n          \"input\": {\n            \"clientMutationId\": \"cc31033b-5da7-5c9e-adf2-80a2963e19a8\",\n            \"labelIds\": [\n              \"pick-id\",\n            ],\n            \"labelableId\": \"other-id\",\n          },\n        },\n      ],\n    ]\n  `);\n\n  const stderrCalls = writeStderr.mock.calls\n    .map(([text]) =>\n      typeof text === 'string'\n        ? text\n            .replace(ansiRegex(), '')\n            .replace(/[^\\x20-\\x7E]/g, '')\n            .replaceAll('-', '')\n            .trim()\n        : text\n    )\n    .filter((t) => t !== '');\n\n  expect(stderrCalls).toMatchInlineSnapshot(`\n    [\n      \"Labeling 2 PRs with the patch:done label...\",\n      \"Successfully labeled all PRs with the patch:done label.\",\n    ]\n  `);\n  expect(github.getUnpickedPRs).toHaveBeenCalledTimes(1);\n});\n"
  },
  {
    "path": "scripts/release/__tests__/version.test.ts",
    "content": "import * as fspImp from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { describe, expect, it, vi } from 'vitest';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport { execaCommand } from 'execa';\n\nimport type * as MockedFSPToExtra from '../../../code/__mocks__/fs/promises.ts';\nimport { run as version } from '../version.ts';\n\nvi.mock('node:fs/promises', async () => import('../../../code/__mocks__/fs/promises.ts'));\nconst fspExtra = fspImp as unknown as typeof MockedFSPToExtra;\n\nvi.mock('../../../code/core/src/common/src/versions', () => ({\n  '@storybook/addon-a11y': '7.1.0-alpha.29',\n}));\n\nvi.mock('execa');\n\nvi.mock('../../utils/workspace', () => ({\n  getCodeWorkspaces: vi.fn().mockResolvedValue([\n    {\n      name: '@storybook/addon-a11y',\n      location: 'addons/a11y',\n    },\n  ]),\n}));\n\nvi.spyOn(console, 'log').mockImplementation(() => {});\nvi.spyOn(console, 'warn').mockImplementation(() => {});\nvi.spyOn(console, 'error').mockImplementation(() => {});\n\ndescribe('Version', () => {\n  const CODE_DIR_PATH = join(__dirname, '..', '..', '..', 'code');\n  const CODE_PACKAGE_JSON_PATH = join(CODE_DIR_PATH, 'package.json');\n  const MANAGER_API_VERSION_PATH = join(CODE_DIR_PATH, 'core', 'src', 'manager-api', 'version.ts');\n  const VERSIONS_PATH = join(CODE_DIR_PATH, 'core', 'src', 'common', 'versions.ts');\n  const A11Y_PACKAGE_JSON_PATH = join(CODE_DIR_PATH, 'addons', 'a11y', 'package.json');\n\n  it('should throw when release type is invalid', async () => {\n    fspExtra.__setMockFiles({\n      [CODE_PACKAGE_JSON_PATH]: JSON.stringify({ version: '1.0.0' }),\n      [MANAGER_API_VERSION_PATH]: `export const version = \"1.0.0\";`,\n      [VERSIONS_PATH]: `export default { \"@storybook/addon-a11y\": \"1.0.0\" };`,\n    });\n\n    await expect(version({ releaseType: 'invalid' })).rejects.toThrowErrorMatchingInlineSnapshot(`\n      [ZodError: [\n  {\n    \"received\": \"invalid\",\n    \"code\": \"invalid_enum_value\",\n    \"options\": [\n      \"major\",\n      \"minor\",\n      \"patch\",\n      \"prerelease\",\n      \"premajor\",\n      \"preminor\",\n      \"prepatch\"\n    ],\n    \"path\": [\n      \"releaseType\"\n    ],\n    \"message\": \"Invalid enum value. Expected 'major' | 'minor' | 'patch' | 'prerelease' | 'premajor' | 'preminor' | 'prepatch', received 'invalid'\"\n  }\n]]\n    `);\n  });\n\n  it('should throw when prerelease identifier is combined with non-pre release type', async () => {\n    fspExtra.__setMockFiles({\n      [CODE_PACKAGE_JSON_PATH]: JSON.stringify({ version: '1.0.0' }),\n      [MANAGER_API_VERSION_PATH]: `export const version = \"1.0.0\";`,\n      [VERSIONS_PATH]: `export default { \"@storybook/addon-a11y\": \"1.0.0\" };`,\n    });\n\n    await expect(version({ releaseType: 'major', preId: 'alpha' })).rejects\n      .toThrowErrorMatchingInlineSnapshot(`\n      [ZodError: [\n  {\n    \"code\": \"custom\",\n    \"message\": \"Using prerelease identifier requires one of release types: premajor, preminor, prepatch, prerelease\",\n    \"path\": []\n  }\n]]\n    `);\n  });\n\n  it('should throw when exact is combined with release type', async () => {\n    fspExtra.__setMockFiles({\n      [CODE_PACKAGE_JSON_PATH]: JSON.stringify({ version: '1.0.0' }),\n      [MANAGER_API_VERSION_PATH]: `export const version = \"1.0.0\";`,\n      [VERSIONS_PATH]: `export default { \"@storybook/addon-a11y\": \"1.0.0\" };`,\n    });\n\n    await expect(version({ releaseType: 'major', exact: '1.0.0' })).rejects\n      .toThrowErrorMatchingInlineSnapshot(`\n      [ZodError: [\n  {\n    \"code\": \"custom\",\n    \"message\": \"Combining --exact with --release-type is invalid, but having one of them is required\",\n    \"path\": []\n  }\n]]\n    `);\n  });\n\n  it('should throw when exact is invalid semver', async () => {\n    fspExtra.__setMockFiles({\n      [CODE_PACKAGE_JSON_PATH]: JSON.stringify({ version: '1.0.0' }),\n      [MANAGER_API_VERSION_PATH]: `export const version = \"1.0.0\";`,\n      [VERSIONS_PATH]: `export default { \"@storybook/addon-a11y\": \"1.0.0\" };`,\n    });\n\n    await expect(version({ exact: 'not-semver' })).rejects.toThrowErrorMatchingInlineSnapshot(`\n      [ZodError: [\n  {\n    \"code\": \"custom\",\n    \"message\": \"--exact version has to be a valid semver string\",\n    \"path\": [\n      \"exact\"\n    ]\n  }\n]]\n    `);\n  });\n\n  it('should throw when apply is combined with releaseType', async () => {\n    fspExtra.__setMockFiles({\n      [CODE_PACKAGE_JSON_PATH]: JSON.stringify({ version: '1.0.0' }),\n      [MANAGER_API_VERSION_PATH]: `export const version = \"1.0.0\";`,\n      [VERSIONS_PATH]: `export default { \"@storybook/addon-a11y\": \"1.0.0\" };`,\n    });\n\n    await expect(version({ apply: true, releaseType: 'prerelease' })).rejects\n      .toThrowErrorMatchingInlineSnapshot(`\n      [ZodError: [\n  {\n    \"code\": \"custom\",\n    \"message\": \"--apply cannot be combined with --exact or --release-type, as it will always read from code/package.json#deferredNextVersion\",\n    \"path\": []\n  }\n]]\n    `);\n  });\n\n  it('should throw when apply is combined with exact', async () => {\n    fspExtra.__setMockFiles({\n      [CODE_PACKAGE_JSON_PATH]: JSON.stringify({ version: '1.0.0' }),\n      [MANAGER_API_VERSION_PATH]: `export const version = \"1.0.0\";`,\n      [VERSIONS_PATH]: `export default { \"@storybook/addon-a11y\": \"1.0.0\" };`,\n    });\n\n    await expect(version({ apply: true, exact: '1.0.0' })).rejects\n      .toThrowErrorMatchingInlineSnapshot(`\n      [ZodError: [\n  {\n    \"code\": \"custom\",\n    \"message\": \"--apply cannot be combined with --exact or --release-type, as it will always read from code/package.json#deferredNextVersion\",\n    \"path\": []\n  }\n]]\n    `);\n  });\n\n  it('should throw when apply is combined with deferred', async () => {\n    fspExtra.__setMockFiles({\n      [CODE_PACKAGE_JSON_PATH]: JSON.stringify({ version: '1.0.0' }),\n      [MANAGER_API_VERSION_PATH]: `export const version = \"1.0.0\";`,\n      [VERSIONS_PATH]: `export default { \"@storybook/addon-a11y\": \"1.0.0\" };`,\n    });\n\n    await expect(version({ apply: true, deferred: true })).rejects\n      .toThrowErrorMatchingInlineSnapshot(`\n      [ZodError: [\n  {\n    \"code\": \"custom\",\n    \"message\": \"--deferred cannot be combined with --apply\",\n    \"path\": []\n  }\n]]\n    `);\n  });\n\n  it('should throw when applying without a \"deferredNextVersion\" set', async () => {\n    fspExtra.__setMockFiles({\n      [CODE_PACKAGE_JSON_PATH]: JSON.stringify({ version: '1.0.0' }),\n    });\n\n    await expect(version({ apply: true })).rejects.toThrowErrorMatchingInlineSnapshot(\n      `[Error: The 'deferredNextVersion' property in code/package.json is unset. This is necessary to apply a deferred version bump]`\n    );\n\n    expect(fspExtra.writeFile).not.toHaveBeenCalled();\n    expect(execaCommand).not.toHaveBeenCalled();\n  });\n\n  it.each([\n    // prettier-ignore\n    { releaseType: 'major', currentVersion: '1.1.1', expectedVersion: '2.0.0' },\n    // prettier-ignore\n    { releaseType: 'minor', currentVersion: '1.1.1', expectedVersion: '1.2.0' },\n    // prettier-ignore\n    { releaseType: 'patch', currentVersion: '1.1.1', expectedVersion: '1.1.2' },\n    // prettier-ignore\n    { releaseType: 'premajor', preId: 'alpha', currentVersion: '1.1.1', expectedVersion: '2.0.0-alpha.0' },\n    // prettier-ignore\n    { releaseType: 'preminor', preId: 'alpha', currentVersion: '1.1.1', expectedVersion: '1.2.0-alpha.0' },\n    // prettier-ignore\n    { releaseType: 'prepatch', preId: 'alpha', currentVersion: '1.1.1', expectedVersion: '1.1.2-alpha.0' },\n    // prettier-ignore\n    { releaseType: 'prerelease', currentVersion: '1.1.1-alpha.5', expectedVersion: '1.1.1-alpha.6' },\n    // prettier-ignore\n    { releaseType: 'prerelease', preId: 'alpha', currentVersion: '1.1.1-alpha.5', expectedVersion: '1.1.1-alpha.6' },\n    // prettier-ignore\n    { releaseType: 'prerelease', preId: 'beta', currentVersion: '1.1.1-alpha.10', expectedVersion: '1.1.1-beta.0' },\n    // prettier-ignore\n    { releaseType: 'major', currentVersion: '1.1.1-rc.10', expectedVersion: '2.0.0' },\n    // prettier-ignore\n    { releaseType: 'minor', currentVersion: '1.1.1-rc.10', expectedVersion: '1.2.0' },\n    // prettier-ignore\n    { releaseType: 'patch', currentVersion: '1.1.1-rc.10', expectedVersion: '1.1.1' },\n    // prettier-ignore\n    { exact: '4.2.0-canary.69', currentVersion: '1.1.1-rc.10', expectedVersion: '4.2.0-canary.69' },\n    // prettier-ignore\n    { apply: true, currentVersion: '1.0.0', deferredNextVersion: '1.2.0', expectedVersion: '1.2.0' },\n  ])(\n    'bump with type: \"$releaseType\", pre id \"$preId\" or exact \"$exact\" or apply $apply, from: $currentVersion, to: $expectedVersion',\n    async ({\n      releaseType,\n      preId,\n      exact,\n      apply,\n      currentVersion,\n      expectedVersion,\n      deferredNextVersion,\n    }) => {\n      fspExtra.__setMockFiles({\n        [CODE_PACKAGE_JSON_PATH]: JSON.stringify({ version: currentVersion, deferredNextVersion }),\n        [MANAGER_API_VERSION_PATH]: `export const version = \"${currentVersion}\";`,\n        [VERSIONS_PATH]: `export default { \"@storybook/addon-a11y\": \"${currentVersion}\" };`,\n        [A11Y_PACKAGE_JSON_PATH]: JSON.stringify({\n          version: currentVersion,\n        }),\n        [VERSIONS_PATH]: `export default { \"@storybook/addon-a11y\": \"${currentVersion}\" };`,\n      });\n\n      await version({ releaseType, preId, exact, apply });\n      expect(fspExtra.writeFile).toHaveBeenCalledTimes(apply ? 5 : 4);\n      if (apply) {\n        expect(fspExtra.writeFile).toHaveBeenCalledWith(\n          CODE_PACKAGE_JSON_PATH,\n          // this call is the write that removes the \"deferredNextVersion\" property\n          expect.stringContaining(JSON.stringify({ version: currentVersion }, null, 2))\n        );\n      }\n\n      expect(fspExtra.writeFile).toHaveBeenCalledWith(\n        CODE_PACKAGE_JSON_PATH,\n        expect.stringContaining(JSON.stringify({ version: expectedVersion }, null, 2))\n      );\n      expect(fspExtra.writeFile).toHaveBeenCalledWith(\n        MANAGER_API_VERSION_PATH,\n        `export const version = \"${expectedVersion}\";`\n      );\n      expect(fspExtra.writeFile).toHaveBeenCalledWith(\n        VERSIONS_PATH,\n        `export default { \"@storybook/addon-a11y\": \"${expectedVersion}\" };`\n      );\n      expect(fspExtra.writeFile).toHaveBeenCalledWith(\n        A11Y_PACKAGE_JSON_PATH,\n        expect.stringContaining(\n          JSON.stringify(\n            {\n              // should update package version\n              version: expectedVersion,\n            },\n            null,\n            2\n          )\n        )\n      );\n      expect(execaCommand).toHaveBeenCalledWith('yarn install --mode=update-lockfile', {\n        cwd: join(CODE_DIR_PATH),\n        cleanup: true,\n        stdio: undefined,\n      });\n    }\n  );\n\n  it('should only set version in \"deferredNextVersion\" when using --deferred', async () => {\n    fspExtra.__setMockFiles({\n      [CODE_PACKAGE_JSON_PATH]: JSON.stringify({ version: '1.0.0' }),\n    });\n\n    await version({ releaseType: 'premajor', preId: 'beta', deferred: true });\n\n    expect(fspExtra.writeFile).toHaveBeenCalledTimes(1);\n    expect(fspExtra.writeFile).toHaveBeenCalledWith(\n      CODE_PACKAGE_JSON_PATH,\n      expect.stringContaining(\n        JSON.stringify({ version: '1.0.0', deferredNextVersion: '2.0.0-beta.0' }, null, 2)\n      )\n    );\n    expect(execaCommand).not.toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "scripts/release/__tests__/write-changelog.test.ts",
    "content": "import * as fspImp from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { dedent } from 'ts-dedent';\n\nimport type * as MockedFSPToExtra from '../../../code/__mocks__/fs/promises.ts';\nimport * as changesUtils_ from '../utils/get-changes.ts';\nimport { run as writeChangelog } from '../write-changelog.ts';\n\nvi.mock('node:fs/promises', async () => import('../../../code/__mocks__/fs/promises.ts'));\nvi.mock('../utils/get-changes');\n\nconst changesUtils = vi.mocked(changesUtils_);\n\nconst fsp = fspImp as unknown as typeof MockedFSPToExtra;\n\nbeforeEach(() => {\n  vi.restoreAllMocks();\n\n  vi.spyOn(console, 'log').mockImplementation(() => {});\n  vi.spyOn(console, 'warn').mockImplementation(() => {});\n  vi.spyOn(console, 'error').mockImplementation(() => {});\n\n  fsp.__setMockFiles({\n    [STABLE_CHANGELOG_PATH]: EXISTING_STABLE_CHANGELOG,\n    [PRERELEASE_CHANGELOG_PATH]: EXISTING_PRERELEASE_CHANGELOG,\n  });\n});\n\nconst STABLE_CHANGELOG_PATH = join(__dirname, '..', '..', '..', 'CHANGELOG.md');\nconst PRERELEASE_CHANGELOG_PATH = join(__dirname, '..', '..', '..', 'CHANGELOG.prerelease.md');\nconst LATEST_VERSION_PATH = join(__dirname, '..', '..', '..', 'docs', 'versions', 'latest.json');\nconst NEXT_VERSION_PATH = join(__dirname, '..', '..', '..', 'docs', 'versions', 'next.json');\n\nconst EXISTING_STABLE_CHANGELOG = dedent`## 7.0.0\n\n- Core: Some change`;\n\nconst EXISTING_PRERELEASE_CHANGELOG = dedent`## 7.1.0-alpha.20\n\n- CLI: Super fast now`;\n\ndescribe('Write changelog', () => {\n  it('should write to stable changelogs and version files in docs', async () => {\n    changesUtils.getChanges.mockResolvedValue({\n      changes: [],\n      changelogText: `## 7.0.1\n\n- React: Make it reactive\n- CLI: Not UI`,\n    });\n\n    await writeChangelog(['7.0.1'], {});\n\n    expect(fsp.writeFile).toHaveBeenCalledTimes(2);\n    expect(fsp.writeFile.mock.calls[0][0]).toBe(STABLE_CHANGELOG_PATH);\n    expect(fsp.writeFile.mock.calls[0][1]).toMatchInlineSnapshot(`\n      \"## 7.0.1\n\n      - React: Make it reactive\n      - CLI: Not UI\n\n      ## 7.0.0\n\n      - Core: Some change\"\n    `);\n    expect(fsp.writeFile.mock.calls[1][0]).toBe(LATEST_VERSION_PATH);\n    expect(fsp.writeFile.mock.calls[1][1]).toMatchInlineSnapshot(\n      `\"{\"version\":\"7.0.1\",\"info\":{\"plain\":\"- React: Make it reactive\\\\n- CLI: Not UI\"}}\"`\n    );\n  });\n\n  it('should escape double quotes for json files', async () => {\n    changesUtils.getChanges.mockResolvedValue({\n      changes: [],\n      changelogText: `## 7.0.1\n\n- React: Make it reactive\n- Revert \"CLI: Not UI\"\n- CLI: Not UI`,\n    });\n\n    await writeChangelog(['7.0.1'], {});\n\n    expect(fsp.writeFile).toHaveBeenCalledTimes(2);\n    expect(fsp.writeFile.mock.calls[0][0]).toBe(STABLE_CHANGELOG_PATH);\n    expect(fsp.writeFile.mock.calls[0][1]).toMatchInlineSnapshot(`\n      \"## 7.0.1\n\n      - React: Make it reactive\n      - Revert \"CLI: Not UI\"\n      - CLI: Not UI\n\n      ## 7.0.0\n\n      - Core: Some change\"\n    `);\n    expect(fsp.writeFile.mock.calls[1][0]).toBe(LATEST_VERSION_PATH);\n    expect(fsp.writeFile.mock.calls[1][1]).toMatchInlineSnapshot(\n      `\"{\"version\":\"7.0.1\",\"info\":{\"plain\":\"- React: Make it reactive\\\\n- Revert \\\\\\\\\\\\\"CLI: Not UI\\\\\\\\\\\\\"\\\\n- CLI: Not UI\"}}\"`\n    );\n  });\n\n  it('should write to prerelease changelogs and version files in docs', async () => {\n    changesUtils.getChanges.mockResolvedValue({\n      changes: [],\n      changelogText: `## 7.1.0-alpha.21\n\n- React: Make it reactive\n- CLI: Not UI`,\n    });\n\n    await writeChangelog(['7.1.0-alpha.21'], {});\n\n    expect(fsp.writeFile).toHaveBeenCalledTimes(2);\n    expect(fsp.writeFile.mock.calls[0][0]).toBe(PRERELEASE_CHANGELOG_PATH);\n    expect(fsp.writeFile.mock.calls[0][1]).toMatchInlineSnapshot(`\n      \"## 7.1.0-alpha.21\n\n      - React: Make it reactive\n      - CLI: Not UI\n\n      ## 7.1.0-alpha.20\n\n      - CLI: Super fast now\"\n    `);\n    expect(fsp.writeFile.mock.calls[1][0]).toBe(NEXT_VERSION_PATH);\n    expect(fsp.writeFile.mock.calls[1][1]).toMatchInlineSnapshot(\n      `\"{\"version\":\"7.1.0-alpha.21\",\"info\":{\"plain\":\"- React: Make it reactive\\\\n- CLI: Not UI\"}}\"`\n    );\n  });\n});\n"
  },
  {
    "path": "scripts/release/cancel-preparation-runs.ts",
    "content": "/**\n * This script cancels all running preparation workflows in GitHub. It will fetch all active runs\n * for the preparation workflows, and cancel them.\n */\nimport { program } from 'commander';\nimport picocolors from 'picocolors';\nimport { dedent } from 'ts-dedent';\n\nimport { esMain } from '../utils/esmain.ts';\nimport { githubRestClient } from './utils/github-client.ts';\n\nprogram\n  .name('cancel-preparation-workflows')\n  .description('cancel all running preparation workflows in GitHub');\n\nexport const PREPARE_PATCH_WORKFLOW_PATH = '.github/workflows/prepare-patch-release.yml';\nexport const PREPARE_NON_PATCH_WORKFLOW_PATH = '.github/workflows/prepare-non-patch-release.yml';\n\nexport const run = async () => {\n  if (!process.env.GH_TOKEN) {\n    throw new Error('GH_TOKEN environment variable must be set, exiting.');\n  }\n\n  console.log(`🔎 Looking for workflows to cancel...`);\n  const allWorkflows = await githubRestClient('GET /repos/{owner}/{repo}/actions/workflows', {\n    owner: 'storybookjs',\n    repo: 'storybook',\n  });\n\n  const preparePatchWorkflowId = allWorkflows.data.workflows.find(\n    ({ path }) => path === PREPARE_PATCH_WORKFLOW_PATH\n  )?.id;\n  const prepareNonPatchWorkflowId = allWorkflows.data.workflows.find(\n    ({ path }) => path === PREPARE_NON_PATCH_WORKFLOW_PATH\n  )?.id;\n\n  console.log(`Found workflow IDs for the preparation workflows:\n    ${picocolors.blue(PREPARE_PATCH_WORKFLOW_PATH)}: ${picocolors.green(preparePatchWorkflowId)}\n    ${picocolors.blue(PREPARE_NON_PATCH_WORKFLOW_PATH)}: ${picocolors.green(prepareNonPatchWorkflowId)}`);\n\n  if (!preparePatchWorkflowId || !prepareNonPatchWorkflowId) {\n    throw new Error(dedent`🚨 Could not find workflow IDs for the preparation workflows\n    - Looked for paths: \"${picocolors.blue(PREPARE_PATCH_WORKFLOW_PATH)}\" and \"${picocolors.blue(\n      PREPARE_NON_PATCH_WORKFLOW_PATH\n    )}\", are they still correct?\n    - Found workflows:\n      ${JSON.stringify(allWorkflows.data.workflows, null, 2)}`);\n  }\n\n  console.log('🔍 Fetching patch and non-patch runs for preparation workflows...');\n  const [patchRuns, nonPatchRuns] = await Promise.all([\n    githubRestClient('GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs', {\n      owner: 'storybookjs',\n      repo: 'storybook',\n      workflow_id: preparePatchWorkflowId,\n    }),\n    githubRestClient('GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs', {\n      owner: 'storybookjs',\n      repo: 'storybook',\n      workflow_id: prepareNonPatchWorkflowId,\n    }),\n  ]);\n  console.log('✅ Successfully fetched patch and non-patch runs for preparation workflows.');\n\n  const runsToCancel = patchRuns.data.workflow_runs\n    .concat(nonPatchRuns.data.workflow_runs)\n    .filter(({ status }) =>\n      ['in_progress', 'pending', 'queued', 'requested', 'waiting'].includes(status)\n    );\n\n  if (runsToCancel.length === 0) {\n    console.log('👍 No runs to cancel.');\n    return;\n  }\n\n  console.log(`🔍 Found ${runsToCancel.length} runs to cancel. Cancelling them now:\n    ${runsToCancel\n      .map(\n        (r) =>\n          `${picocolors.green(r.path)} - ${picocolors.green(r.id)}: ${picocolors.blue(r.status)}`\n      )\n      .join('\\n    ')}`);\n\n  const result = await Promise.allSettled(\n    runsToCancel.map((r) =>\n      githubRestClient('POST /repos/{owner}/{repo}/actions/runs/{run_id}/cancel', {\n        owner: 'storybookjs',\n        repo: 'storybook',\n        run_id: r.id,\n      })\n    )\n  );\n\n  if (result.some((r) => r.status === 'rejected')) {\n    console.warn('⚠️ Some runs could not be cancelled:');\n    result.forEach((r, index) => {\n      if (r.status === 'rejected') {\n        console.warn(`Run ID: ${runsToCancel[index].id} - Reason: ${r.reason}`);\n      }\n    });\n  } else {\n    console.log('✅ Successfully cancelled all preparation runs.');\n  }\n};\n\nif (esMain(import.meta.url)) {\n  run().catch((err) => {\n    console.error(err);\n    // this is non-critical work, so we don't want to fail the CI build if this fails\n  });\n}\n"
  },
  {
    "path": "scripts/release/generate-pr-description.ts",
    "content": "import { setOutput } from '@actions/core';\nimport { program } from 'commander';\nimport picocolors from 'picocolors';\nimport semver from 'semver';\nimport { dedent } from 'ts-dedent';\nimport { z } from 'zod';\n\nimport { esMain } from '../utils/esmain.ts';\nimport { getCurrentVersion } from './get-current-version.ts';\nimport type { Change } from './utils/get-changes.ts';\nimport { LABELS_BY_IMPORTANCE, RELEASED_LABELS, getChanges } from './utils/get-changes.ts';\nimport type { PullRequestInfo } from './utils/get-github-info.ts';\n\nprogram\n  .name('generate-pr-description')\n  .description('generate a PR description for a release')\n  .option(\n    '-C, --current-version <version>',\n    'Which version to generate changelog from, eg. \"7.0.7\". Defaults to the version at code/package.json'\n  )\n  .option('-N, --next-version <version>', 'Which version to generate changelog to, eg. \"7.0.8\"')\n  .option('-P, --unpicked-patches', 'Set to only consider PRs labeled with \"patch:yes\" label')\n  .option(\n    '-M, --manual-cherry-picks <commits>',\n    'A stringified JSON array of commit hashes, of patch PRs that needs to be cherry-picked manually'\n  )\n  .option('-V, --verbose', 'Enable verbose logging', false);\n\nconst optionsSchema = z.object({\n  currentVersion: z.string().optional(),\n  nextVersion: z.string().optional(),\n  unpickedPatches: z.boolean().optional(),\n  manualCherryPicks: z\n    .string()\n    .default('[]')\n    .transform((val) => JSON.parse(val))\n    .refine((val) => Array.isArray(val)),\n  verbose: z.boolean().optional(),\n});\n\ntype Options = {\n  currentVersion?: string;\n  nextVersion?: string;\n  unpickedPatches?: boolean;\n  manualCherryPicks?: string[];\n  verbose: boolean;\n};\n\nconst CHANGE_TITLES_TO_IGNORE = [\n  /^bump version.*/i,\n  /^merge branch.*/i,\n  /\\[skip ci\\]/i,\n  /\\[ci skip\\]/i,\n  /^Update CHANGELOG\\.md for.*/i,\n  /^Release: (Pre)?(Patch|Minor|Major|Release).*\\d+$/i,\n  /^Update \\.\\/docs\\/versions/,\n];\n\nexport const mapToChangelist = ({\n  changes,\n  unpickedPatches,\n}: {\n  changes: Change[];\n  unpickedPatches: boolean;\n}): string => {\n  return changes\n    .filter((change) => {\n      for (const titleToIgnore of CHANGE_TITLES_TO_IGNORE) {\n        if (change.title?.match(titleToIgnore)) {\n          return false;\n        }\n      }\n      return true;\n    })\n    .sort((a, b) => {\n      const isReleasable = (pr: PullRequestInfo) =>\n        (pr.labels ?? []).some((label) => Object.keys(RELEASED_LABELS).includes(label));\n      return Number(isReleasable(b)) - Number(isReleasable(a));\n    })\n    .map((change) => {\n      if (!change.pull) {\n        return `- [ ] **⚠️ Direct commit**: ${change.title} ${change.links.commit}`;\n      }\n\n      const label = (change.labels\n        ?.filter((l) => Object.keys(LABELS_BY_IMPORTANCE).includes(l))\n        .sort(\n          (a, b) =>\n            Object.keys(LABELS_BY_IMPORTANCE).indexOf(a) -\n            Object.keys(LABELS_BY_IMPORTANCE).indexOf(b)\n        )[0] || 'unknown') as keyof typeof LABELS_BY_IMPORTANCE;\n\n      return `- [ ] **${LABELS_BY_IMPORTANCE[label]}**: ${change.title} ${change.links.pull}${\n        !unpickedPatches && change.labels?.includes('patch:yes') ? ' (will also be patched)' : ''\n      }`;\n    })\n    .join('\\n');\n};\n\nexport const mapCherryPicksToTodo = ({\n  commits,\n  changes,\n  verbose,\n}: {\n  commits: string[];\n  changes: Change[];\n  verbose?: boolean;\n}): string => {\n  const list = commits\n    .map((commit) => {\n      const foundChange = changes.find((change) => change.commit === commit);\n      if (!foundChange) {\n        throw new Error(\n          `Cherry pick commit \"${commit}\" not found in changes, this should not happen?!`\n        );\n      }\n      return `- [ ] ${foundChange.links.pull}: \\`git cherry-pick -m1 -x ${commit}\\``;\n    })\n    .join('\\n');\n\n  if (verbose) {\n    console.log(`🍒 Cherry pick list:\\n${list}`);\n  }\n  return dedent`## 🍒 Manual cherry picking needed!\n\n  The following pull requests could not be cherry-picked automatically because it resulted in merge conflicts.\n  For each pull request below, you need to either manually cherry pick it, or discard it by replacing the \"patch:yes\" label with \"patch:no\" on the PR and re-generate this PR.\n  \n  ${list}`;\n};\n\nexport const generateReleaseDescription = ({\n  currentVersion,\n  nextVersion,\n  changeList,\n  changelogText,\n  manualCherryPicks,\n}: {\n  currentVersion: string;\n  nextVersion: string;\n  changeList: string;\n  changelogText: string;\n  manualCherryPicks?: string;\n}): string => {\n  const workflow = semver.prerelease(nextVersion)\n    ? 'prepare-non-patch-release'\n    : 'prepare-patch-release';\n  const workflowUrl = `https://github.com/storybookjs/storybook/actions/workflows/${workflow}.yml`;\n\n  return (\n    dedent`This is an automated pull request that bumps the version from \\`${currentVersion}\\` to \\`${nextVersion}\\`.\n  Once this pull request is merged, it will trigger a new release of version \\`${nextVersion}\\`.\n  If you're not a core maintainer with permissions to release you can ignore this pull request.\n\n  ## To do\n\n  Before merging the PR, there are a few QA steps to go through:\n\n  - [ ] Add the \"freeze\" label to this PR, to ensure it doesn't get automatically forced pushed by new changes.\n  - [ ] Add the \"ci:daily\" label to this PR, to trigger the full test suite to run on this PR.\n  \n  And for each change below:\n  \n  1. Ensure the change is appropriate for the version bump. E.g. patch release should only contain patches, not new or de-stabilizing features. If a change is not appropriate, revert the PR.\n  2. Ensure the PR is labeled correctly with one of: ${Object.keys(LABELS_BY_IMPORTANCE)\n    .map((label) => `\"${label}\"`)\n    .join(', ')}.\n  3. Ensure the PR title is correct, and follows the format \"[Area]: [Summary]\", e.g. *\"React: Fix hooks in CSF3 render functions\"*. If it is not correct, change the title in the PR.\n      - Areas include: React, Vue, Core, Docs, Controls, etc.\n      - First word of summary indicates the type: “Add”, “Fix”, “Upgrade”, etc.\n      - The entire title should fit on a line\n  \n  This is a list of all the PRs merged and commits pushed directly to \\`next\\`, that will be part of this release:\n  \n  ${changeList}\n\n  ${manualCherryPicks || ''}\n\n  If you've made any changes doing the above QA (change PR titles, revert PRs), manually trigger a re-generation of this PR with [this workflow](${workflowUrl}) and wait for it to finish. It will wipe your progress in this to do, which is expected.\n\n  Feel free to manually commit any changes necessary to this branch **after** you've done the last re-generation, following the [Make Manual Changes](https://github.com/storybookjs/storybook/blob/next/CONTRIBUTING/RELEASING.md#5-make-manual-changes) section in the docs, *especially* if you're making changes to the changelog.\n\n  When everything above is done:\n  - Merge this PR\n  - [Follow the run of the publish action](https://github.com/storybookjs/storybook/actions/workflows/publish.yml)\n  \n  ---\n  \n  # Generated changelog\n  \n  ${changelogText}`\n      // don't mention contributors in the release PR, to avoid spamming them\n      .replaceAll('@', '')\n      .replaceAll('\"', '\\\\\"')\n      .replaceAll('`', '\\\\`')\n      .replaceAll(\"'\", \"\\\\'\")\n  );\n};\n\nexport const generateNonReleaseDescription = (\n  changeList: string,\n  manualCherryPicks?: string\n): string => {\n  return (\n    dedent`This is an automated pull request. None of the changes requires a version bump, they are only internal or documentation related. Merging this PR will not trigger a new release, but documentation will be updated.\n  If you're not a core maintainer with permissions to release you can ignore this pull request.\n  \n  ## To do\n\n  Before merging the PR:\n\n  - [ ] Add the \"freeze\" label to this PR, to ensure it doesn't get automatically forced pushed by new changes.\n  - [ ] Add the \"ci:daily\" label to this PR, to trigger the full test suite to run on this PR.\n\n  This is a list of all the PRs merged and commits pushed directly to \\`next\\` since the last release:\n  \n  ${changeList}\n\n  ${manualCherryPicks || ''}\n\n  If you've made any changes (change PR titles, revert PRs), manually trigger a re-generation of this PR with [this workflow](https://github.com/storybookjs/storybook/actions/workflows/prepare-patch-release.yml) and wait for it to finish.\n  \n  Feel free to manually commit any changes necessary to this branch **after** you've done the last re-generation, following the [Make Manual Changes](https://github.com/storybookjs/storybook/blob/next/CONTRIBUTING/RELEASING.md#5-make-manual-changes) section in the docs.\n\n  When everything above is done:\n  - Merge this PR\n  - [Follow the run of the publish action](https://github.com/storybookjs/storybook/actions/workflows/publish.yml)`\n      // don't mention contributors in the release PR, to avoid spamming them\n      .replaceAll('@', '')\n      .replaceAll('\"', '\\\\\"')\n      .replaceAll('`', '\\\\`')\n      .replaceAll(\"'\", \"\\\\'\")\n  );\n};\n\nexport const run = async (rawOptions: unknown) => {\n  const { nextVersion, unpickedPatches, verbose, manualCherryPicks, ...options } =\n    optionsSchema.parse(rawOptions) as Options;\n\n  if (!nextVersion) {\n    console.log(\n      '🚨 --next-version option not specified, generating PR description assuming no release is needed'\n    );\n  }\n\n  const currentVersion = options.currentVersion || (await getCurrentVersion());\n\n  console.log(\n    `💬 Generating PR description for ${picocolors.blue(nextVersion)} between ${picocolors.green(\n      currentVersion\n    )} and ${picocolors.green('HEAD')}`\n  );\n\n  const { changes, changelogText } = await getChanges({\n    version: nextVersion,\n    from: `v${currentVersion}`,\n    to: 'HEAD',\n    unpickedPatches,\n    verbose,\n  });\n\n  const hasCherryPicks = manualCherryPicks?.length > 0;\n\n  const description = nextVersion\n    ? generateReleaseDescription({\n        currentVersion,\n        nextVersion,\n        changeList: mapToChangelist({ changes, unpickedPatches }),\n        changelogText,\n        ...(hasCherryPicks && {\n          manualCherryPicks: mapCherryPicksToTodo({\n            commits: manualCherryPicks,\n            changes,\n            verbose,\n          }),\n        }),\n      })\n    : generateNonReleaseDescription(\n        mapToChangelist({ changes, unpickedPatches }),\n        hasCherryPicks\n          ? mapCherryPicksToTodo({\n              commits: manualCherryPicks,\n              changes,\n              verbose,\n            })\n          : undefined\n      );\n\n  if (process.env.GITHUB_ACTIONS === 'true') {\n    setOutput('description', description);\n  }\n  console.log(`✅ Generated PR description for ${picocolors.blue(nextVersion)}`);\n  if (verbose) {\n    console.log(description);\n  }\n};\n\nif (esMain(import.meta.url)) {\n  const parsed = program.parse();\n  run(parsed.opts()).catch((err) => {\n    console.error(err);\n    process.exit(1);\n  });\n}\n"
  },
  {
    "path": "scripts/release/get-changelog-from-file.ts",
    "content": "import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { setOutput } from '@actions/core';\nimport { program } from 'commander';\nimport picocolors from 'picocolors';\nimport semver from 'semver';\nimport { dedent } from 'ts-dedent';\n\nimport { esMain } from '../utils/esmain.ts';\nimport { getCurrentVersion } from './get-current-version.ts';\n\nprogram\n  .name('get-changelog-from-file')\n  .description(\n    'get changelog entry for specific version. If no version argument specified it will use the current version in code/package.json'\n  )\n  .arguments('[version]')\n  .option('-E, --no-escape', 'Escape quote-like characters, so the output is safe in CLIs', true)\n  .option('-V, --verbose', 'Enable verbose logging', false);\n\nexport const getChangelogFromFile = async (args: {\n  version?: string;\n  escape?: boolean;\n  verbose?: boolean;\n}) => {\n  const version = args.version || (await getCurrentVersion());\n  const isPrerelease = semver.prerelease(version) !== null;\n  const changelogFilename = isPrerelease ? 'CHANGELOG.prerelease.md' : 'CHANGELOG.md';\n  const changelogPath = join(__dirname, '..', '..', changelogFilename);\n\n  console.log(`📝 Getting changelog from ${picocolors.blue(changelogPath)}`);\n\n  const fullChangelog = await readFile(changelogPath, 'utf-8');\n  const changelogForVersion = fullChangelog.split(/(^|\\n)## /).find((v) => v.startsWith(version));\n  if (!changelogForVersion) {\n    throw new Error(\n      `Could not find changelog entry for version ${picocolors.blue(version)} in ${picocolors.green(\n        changelogPath\n      )}`\n    );\n  }\n  const result = args.escape\n    ? `## ${changelogForVersion}`\n        .replaceAll('\"', '\\\\\"')\n        .replaceAll('`', '\\\\`')\n        .replaceAll(\"'\", \"\\\\'\")\n    : `## ${changelogForVersion}`;\n\n  console.log(dedent`📝 Changelog entry found:\n      ${result}`);\n\n  if (process.env.GITHUB_ACTIONS === 'true') {\n    setOutput('changelog', result);\n  }\n  return result;\n};\n\nif (esMain(import.meta.url)) {\n  const parsed = program.parse();\n  getChangelogFromFile({\n    version: parsed.args[0],\n    escape: parsed.opts().escape,\n    verbose: parsed.opts().verbose,\n  }).catch((err) => {\n    console.error(err);\n    process.exit(1);\n  });\n}\n"
  },
  {
    "path": "scripts/release/get-current-version.ts",
    "content": "import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { setOutput } from '@actions/core';\nimport picocolors from 'picocolors';\n\nimport { esMain } from '../utils/esmain.ts';\n\nconst CODE_DIR_PATH = join(__dirname, '..', '..', 'code');\nconst CODE_PACKAGE_JSON_PATH = join(CODE_DIR_PATH, 'package.json');\n\nexport const getCurrentVersion = async () => {\n  console.log(`📐 Reading current version of Storybook...`);\n  const content = await readFile(CODE_PACKAGE_JSON_PATH, 'utf8');\n  const { version } = JSON.parse(content) as { version: string };\n  if (process.env.GITHUB_ACTIONS === 'true') {\n    setOutput('current-version', version);\n  }\n  console.log(`📦 Current version is ${picocolors.green(version)}`);\n  return version;\n};\n\nif (esMain(import.meta.url)) {\n  getCurrentVersion().catch((err) => {\n    console.error(err);\n    process.exit(1);\n  });\n}\n"
  },
  {
    "path": "scripts/release/get-version-changelog.ts",
    "content": "import { setOutput } from '@actions/core';\nimport { program } from 'commander';\nimport picocolors from 'picocolors';\n\nimport { esMain } from '../utils/esmain.ts';\nimport { getCurrentVersion } from './get-current-version.ts';\nimport { getChanges } from './utils/get-changes.ts';\n\nprogram\n  .name('get-version-changelog')\n  .description(\n    'get changelog for specific version. If no version argument specified it will use the current version in code/package.json'\n  )\n  .arguments('[version]')\n  .option('-V, --verbose', 'Enable verbose logging', false);\n\nexport const getVersionChangelog = async (args: { version?: string; verbose?: boolean }) => {\n  const version = args.version || (await getCurrentVersion());\n\n  console.log(`📝 Getting changelog for version ${picocolors.blue(version)}`);\n\n  const { changelogText } = await getChanges({ from: version, version, verbose: args.verbose });\n\n  if (process.env.GITHUB_ACTIONS === 'true') {\n    setOutput('changelog', changelogText);\n  }\n  return changelogText;\n};\n\nif (esMain(import.meta.url)) {\n  const parsed = program.parse();\n  getVersionChangelog({ version: parsed.args[0], verbose: parsed.opts().verbose }).catch((err) => {\n    console.error(err);\n    process.exit(1);\n  });\n}\n"
  },
  {
    "path": "scripts/release/is-pr-frozen.ts",
    "content": "import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { setOutput } from '@actions/core';\nimport { program } from 'commander';\nimport picocolors from 'picocolors';\n\nimport { esMain } from '../utils/esmain.ts';\nimport { getPullInfoFromCommit } from './utils/get-github-info.ts';\nimport { git } from './utils/git-client.ts';\n\nprogram\n  .name('is-pr-frozen')\n  .description(\n    'returns true if the versioning pull request associated with the current branch has the \"freeze\" label'\n  )\n  .option('-H, --patch', 'Look for patch PR instead of next PR', false)\n  .option('-V, --verbose', 'Enable verbose logging', false);\n\nconst CODE_DIR_PATH = join(__dirname, '..', '..', 'code');\nconst CODE_PACKAGE_JSON_PATH = join(CODE_DIR_PATH, 'package.json');\n\nconst getCurrentVersion = async () => {\n  console.log(`📐 Reading current version of Storybook...`);\n  const content = await readFile(CODE_PACKAGE_JSON_PATH, 'utf-8');\n  const { version } = JSON.parse(content);\n  return version;\n};\n\nconst getRepo = async (verbose?: boolean): Promise<string> => {\n  const remotes = await git.getRemotes(true);\n  const originRemote = remotes.find((remote) => remote.name === 'origin');\n  if (!originRemote) {\n    console.error(\n      'Could not determine repository URL because no remote named \"origin\" was found. Remotes found:'\n    );\n    console.dir(remotes, { depth: null, colors: true });\n    throw new Error('No remote named \"origin\" found');\n  }\n  const pushUrl = originRemote.refs.push;\n  const repo = pushUrl.replace(/\\.git$/, '').replace(/.*:(\\/\\/github\\.com\\/)*/, '');\n  if (verbose) {\n    console.log(`📦 Extracted repo: ${picocolors.blue(repo)}`);\n  }\n  return repo;\n};\n\nexport const run = async (options: unknown) => {\n  const { verbose, patch } = options as { verbose?: boolean; patch?: boolean };\n\n  const version = await getCurrentVersion();\n  const branch = `version-${patch ? 'patch' : 'non-patch'}-from-${version}`;\n\n  console.log(`💬 Determining if pull request from branch '${picocolors.blue(branch)}' is frozen`);\n\n  console.log(`⬇️ Fetching remote 'origin/${branch}'...`);\n  try {\n    await git.fetch('origin', branch, { '--depth': 1 });\n  } catch (error) {\n    console.warn(\n      `❗ Could not fetch remote 'origin/${branch}', it probably does not exist yet, which is okay`\n    );\n    console.warn(error);\n    console.log(`💧 Pull request doesn't exist yet! 😎`);\n    if (process.env.GITHUB_ACTIONS === 'true') {\n      setOutput('frozen', false);\n    }\n    return false;\n  }\n\n  const commit = await git.revparse(`origin/${branch}`);\n  console.log(`🔍 Found commit: ${commit}`);\n\n  const repo = await getRepo(verbose);\n\n  const pullRequest = await getPullInfoFromCommit({ repo, commit }).catch((err) => {\n    console.error(`🚨 Could not get pull requests from commit: ${commit}`);\n    console.error(err);\n    throw err;\n  });\n  console.log(`🔍 Found pull request:\n  ${JSON.stringify(pullRequest, null, 2)}`);\n\n  if (pullRequest.state !== 'OPEN') {\n    console.log('❌ The pull request is already closed, ignoring it');\n    if (process.env.GITHUB_ACTIONS === 'true') {\n      setOutput('frozen', false);\n    }\n    return false;\n  }\n\n  const isFrozen = pullRequest.labels?.includes('freeze');\n  if (process.env.GITHUB_ACTIONS === 'true') {\n    setOutput('frozen', isFrozen);\n  }\n  if (isFrozen) {\n    console.log(`🧊 Pull request is frozen! 🥶`);\n  } else {\n    console.log(`🔥 Pull request is on fire! 🥵`);\n  }\n  return isFrozen;\n};\n\nif (esMain(import.meta.url)) {\n  const parsed = program.parse();\n  run(parsed.opts()).catch((err) => {\n    console.error(err);\n    process.exit(1);\n  });\n}\n"
  },
  {
    "path": "scripts/release/is-prerelease.ts",
    "content": "import { setOutput } from '@actions/core';\nimport { program } from 'commander';\nimport picocolors from 'picocolors';\nimport semver from 'semver';\n\nimport { esMain } from '../utils/esmain.ts';\nimport { getCurrentVersion } from './get-current-version.ts';\n\nprogram\n  .name('is-prerelease')\n  .description(\n    'returns true if the specified version is a prerelease. If no version argument specified it will use the current version in code/package.json'\n  )\n  .arguments('[version]')\n  .option('-V, --verbose', 'Enable verbose logging', false);\n\nexport const isPrerelease = async (args: { version?: string; verbose?: boolean }) => {\n  if (args.verbose) {\n    if (args.version) {\n      console.log(`📦 Checking if version ${picocolors.blue(args.version)} is a prerelease`);\n    } else {\n      console.log(\n        `📦 Checking if current version in ${picocolors.blue('code/package.json')} is a prerelease`\n      );\n    }\n  }\n  const version = args.version || (await getCurrentVersion());\n  const result = semver.prerelease(version) !== null;\n\n  if (process.env.GITHUB_ACTIONS === 'true') {\n    setOutput('prerelease', result);\n  }\n  console.log(\n    `📦 Version ${picocolors.blue(version)} ${\n      result ? picocolors.green('IS') : picocolors.red('IS NOT')\n    } a prerelease`\n  );\n\n  return result;\n};\n\nif (esMain(import.meta.url)) {\n  const parsed = program.parse();\n  isPrerelease({\n    version: parsed.args[0],\n    verbose: parsed.opts().verbose,\n  }).catch((err) => {\n    console.error(err);\n    process.exit(1);\n  });\n}\n"
  },
  {
    "path": "scripts/release/is-version-published.ts",
    "content": "import { setOutput } from '@actions/core';\nimport { program } from 'commander';\nimport picocolors from 'picocolors';\n\nimport { esMain } from '../utils/esmain.ts';\nimport { getCurrentVersion } from './get-current-version.ts';\n\nprogram\n  .name('is-prerelease [version]')\n  .description('returns true if the current version is a prerelease')\n  .arguments('[version]');\n\nconst isVersionPublished = async ({\n  packageName,\n  version,\n  verbose,\n}: {\n  packageName: string;\n  version: string;\n  verbose?: boolean;\n}) => {\n  const prettyPackage = `${picocolors.blue(packageName)}@${picocolors.green(version)}`;\n  console.log(`⛅ Checking if ${prettyPackage} is published...`);\n\n  if (verbose) {\n    console.log(`Fetching from npm:`);\n    console.log(\n      `https://registry.npmjs.org/${picocolors.blue(packageName)}/${picocolors.green(version)}`\n    );\n  }\n  const response = await fetch(`https://registry.npmjs.org/${packageName}/${version}`);\n  if (response.status === 404) {\n    console.log(`🌤️ ${prettyPackage} is not published`);\n    return false;\n  }\n  if (response.status !== 200) {\n    console.error(\n      `Unexpected status code when checking the current version on npm: ${response.status}`\n    );\n    console.error(await response.text());\n    throw new Error(\n      `Unexpected status code when checking the current version on npm: ${response.status}`\n    );\n  }\n  const data: any = await response.json();\n  if (verbose) {\n    console.log(`Response from npm:`);\n    console.log(data);\n  }\n  if (data.version !== version) {\n    // this should never happen\n    console.error(\n      `Unexpected version received when checking the current version on npm: ${data.version}`\n    );\n    console.error(JSON.stringify(data, null, 2));\n    throw new Error(\n      `Unexpected version received when checking the current version on npm: ${data.version}`\n    );\n  }\n\n  console.log(`⛈️ ${prettyPackage} is published`);\n  return true;\n};\n\nexport const run = async (args: unknown[], options: unknown) => {\n  const { verbose } = options as { verbose?: boolean };\n\n  const version = (args[0] as string) || (await getCurrentVersion());\n\n  const isAlreadyPublished = await isVersionPublished({\n    version,\n    packageName: 'storybook',\n    verbose,\n  });\n\n  if (process.env.GITHUB_ACTIONS === 'true') {\n    setOutput('published', isAlreadyPublished);\n  }\n  return isAlreadyPublished;\n};\n\nif (esMain(import.meta.url)) {\n  const parsed = program.parse();\n  run(parsed.args, parsed.opts()).catch((err) => {\n    console.error(err);\n    process.exit(1);\n  });\n}\n"
  },
  {
    "path": "scripts/release/label-patches.ts",
    "content": "import { program } from 'commander';\n// eslint-disable-next-line depend/ban-dependencies\nimport ora from 'ora';\nimport { v4 as uuidv4 } from 'uuid';\n\nimport { esMain } from '../utils/esmain.ts';\nimport { getPullInfoFromCommits, getRepo } from './utils/get-changes.ts';\nimport { getLatestTag, git } from './utils/git-client.ts';\nimport { getLabelIds, getUnpickedPRs, githubGraphQlClient } from './utils/github-client.ts';\n\nprogram\n  .name('label-patches')\n  .description('Label all patches applied in current branch up to the latest release tag.')\n  .option(\n    '-A, --all',\n    'Label all pull requests pending patches, iregardless if they are in the git log or not',\n    false\n  );\n\nasync function labelPR(id: string, labelId: string) {\n  await githubGraphQlClient(\n    `\n      mutation ($input: AddLabelsToLabelableInput!) {\n        addLabelsToLabelable(input: $input) {\n          clientMutationId\n        }\n      }\n    `,\n    { input: { labelIds: [labelId], labelableId: id, clientMutationId: uuidv4() } }\n  );\n}\n\nasync function getPullRequestsFromLog({ repo }: { repo: string }) {\n  const spinner = ora('Looking for latest tag').start();\n  const latestTag = await getLatestTag();\n  spinner.succeed(`Found latest tag: ${latestTag}`);\n\n  const spinner2 = ora(`Looking at cherry pick commits since ${latestTag}`).start();\n  const commitsSinceLatest = await git.log({ from: latestTag });\n  console.log(commitsSinceLatest);\n  const cherryPicked = commitsSinceLatest.all.flatMap((it) => {\n    const result = it.body.match(/\\(cherry picked from commit (\\b[0-9a-f]{7,40}\\b)\\)/);\n    return result ? [result?.[1]] : [];\n  });\n\n  if (cherryPicked.length === 0) {\n    spinner2.fail('No cherry pick commits found to label.');\n    return [];\n  }\n  const pullRequests = (\n    await getPullInfoFromCommits({\n      repo,\n      commits: cherryPicked.map((hash) => ({ hash })),\n    })\n  ).filter((it) => it.id != null);\n\n  if (pullRequests.length === 0) {\n    spinner2.fail(\n      `Found picks: ${cherryPicked.join(', ')}, but no associated pull request found to label.`\n    );\n    return pullRequests;\n  }\n\n  const commitWithPr = pullRequests.map((pr) => `Commit: ${pr.commit}\\n PR: ${pr.links.pull}`);\n\n  spinner2.succeed(`Found the following picks 🍒:\\n ${commitWithPr.join('\\n')}`);\n\n  return pullRequests;\n}\n\nexport const run = async (options: unknown) => {\n  if (!process.env.GH_TOKEN) {\n    throw new Error('GH_TOKEN environment variable must be set, exiting.');\n  }\n\n  const repo = await getRepo();\n  const labelAll = typeof options === 'object' && 'all' in options && Boolean(options.all);\n\n  const pullRequestsToLabel = labelAll\n    ? await getUnpickedPRs('next')\n    : await getPullRequestsFromLog({ repo });\n  if (pullRequestsToLabel.length === 0) {\n    return;\n  }\n\n  const spinner3 = ora(\n    `Labeling ${pullRequestsToLabel.length} PRs with the patch:done label...`\n  ).start();\n  try {\n    const labelToId = await getLabelIds({ repo, labelNames: ['patch:done'] });\n    await Promise.all(pullRequestsToLabel.map((pr) => labelPR(pr.id, labelToId['patch:done'])));\n    spinner3.succeed(`Successfully labeled all PRs with the patch:done label.`);\n  } catch (e) {\n    spinner3.fail(`Something went wrong when labelling the PRs.`);\n    console.error(e);\n  }\n};\n\nif (esMain(import.meta.url)) {\n  const options = program.parse().opts();\n  run(options).catch((err) => {\n    console.error(err);\n    process.exit(1);\n  });\n}\n"
  },
  {
    "path": "scripts/release/pick-patches.ts",
    "content": "import { setOutput } from '@actions/core';\nimport { program } from 'commander';\n// eslint-disable-next-line depend/ban-dependencies\nimport ora from 'ora';\nimport picocolors from 'picocolors';\nimport invariant from 'tiny-invariant';\n\nimport { esMain } from '../utils/esmain.ts';\nimport { git } from './utils/git-client.ts';\nimport { getUnpickedPRs } from './utils/github-client.ts';\n\nprogram.name('pick-patches').description('Cherry pick patch PRs back to main');\n\nconst logger = console;\n\nconst OWNER = 'storybookjs';\nconst REPO = 'storybook';\nconst SOURCE_BRANCH = 'next';\n\ninterface PR {\n  number: number;\n  id: string;\n  branch: string;\n  title: string;\n  mergeCommit: string;\n}\n\nfunction formatPR(pr: PR): string {\n  return `https://github.com/${OWNER}/${REPO}/pull/${pr.number} \"${pr.title}\" ${picocolors.yellow(\n    pr.mergeCommit\n  )}`;\n}\n\nexport const run = async (_: unknown) => {\n  if (!process.env.GH_TOKEN) {\n    logger.error('GH_TOKEN environment variable must be set, exiting.');\n    process.exit(1);\n  }\n\n  const sourceBranch = SOURCE_BRANCH;\n\n  const spinner = ora('Searching for patch PRs to cherry-pick').start();\n\n  const patchPRs = await getUnpickedPRs(sourceBranch);\n\n  if (patchPRs.length > 0) {\n    spinner.succeed(`Found ${patchPRs.length} PRs to cherry-pick to main.`);\n  } else {\n    spinner.warn('No PRs found.');\n  }\n\n  const failedCherryPicks: string[] = [];\n\n  for (const pr of patchPRs) {\n    const prSpinner = ora(`Cherry picking #${pr.number}`).start();\n\n    try {\n      await git.raw(['cherry-pick', '-m', '1', '--keep-redundant-commits', '-x', pr.mergeCommit]);\n      prSpinner.succeed(`Picked: ${formatPR(pr)}`);\n    } catch (pickError) {\n      invariant(pickError instanceof Error);\n      prSpinner.fail(`Failed to automatically pick: ${formatPR(pr)}`);\n      logger.error(pickError.message);\n      const abort = ora(`Aborting cherry pick for merge commit: ${pr.mergeCommit}`).start();\n      try {\n        await git.raw(['cherry-pick', '--abort']);\n        abort.stop();\n      } catch (abortError) {\n        invariant(abortError instanceof Error);\n        abort.warn(`Failed to abort cherry pick (${pr.mergeCommit})`);\n        logger.error(abortError.message);\n      }\n      failedCherryPicks.push(pr.mergeCommit);\n      prSpinner.info(\n        `This PR can be picked manually with: ${picocolors.gray(\n          `git cherry-pick -m1 -x ${pr.mergeCommit}`\n        )}`\n      );\n    }\n  }\n\n  if (process.env.GITHUB_ACTIONS === 'true') {\n    setOutput('no-patch-prs', patchPRs.length === 0);\n    setOutput('failed-cherry-picks', JSON.stringify(failedCherryPicks));\n  }\n};\n\nif (esMain(import.meta.url)) {\n  const options = program.parse(process.argv);\n  run(options).catch((err) => {\n    console.error(err);\n    process.exit(1);\n  });\n}\n"
  },
  {
    "path": "scripts/release/publish.ts",
    "content": "import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { program } from 'commander';\n// eslint-disable-next-line depend/ban-dependencies\nimport { execaCommand } from 'execa';\nimport pRetry from 'p-retry';\nimport picocolors from 'picocolors';\nimport semver from 'semver';\nimport { dedent } from 'ts-dedent';\nimport { z } from 'zod';\n\nimport { esMain } from '../utils/esmain.ts';\n\nprogram\n  .name('publish')\n  .description('publish all packages')\n  .requiredOption(\n    '-T, --tag <tag>',\n    'Specify which distribution tag to set for the version being published. Required, since leaving it undefined would publish with the \"latest\" tag'\n  )\n  .option('-D, --dry-run', 'Do not publish, only output to shell', false)\n  .option('-V, --verbose', 'Enable verbose logging', false);\n\nconst optionsSchema = z\n  .object({\n    tag: z.string(),\n    verbose: z.boolean().optional(),\n    dryRun: z.boolean().optional(),\n  })\n  .refine((schema) => (schema.tag ? !semver.valid(schema.tag) : true), {\n    message:\n      'The tag can not be a valid semver version, it must be a plain string like \"next\" or \"latest\"',\n  });\n\ntype Options = {\n  tag: string;\n  verbose: boolean;\n  dryRun?: boolean;\n};\n\nconst CODE_DIR_PATH = join(__dirname, '..', '..', 'code');\nconst CODE_PACKAGE_JSON_PATH = join(CODE_DIR_PATH, 'package.json');\n\nconst validateOptions = (options: { [key: string]: any }): options is Options => {\n  optionsSchema.parse(options);\n  return true;\n};\n\nconst getCurrentVersion = async (verbose?: boolean) => {\n  if (verbose) {\n    console.log(`📐 Reading current version of Storybook...`);\n  }\n  const content = await readFile(CODE_PACKAGE_JSON_PATH, 'utf-8');\n  const { version } = JSON.parse(content);\n  console.log(`📐 Current version of Storybook is ${picocolors.green(version)}`);\n  return version;\n};\n\nconst isCurrentVersionPublished = async ({\n  packageName,\n  currentVersion,\n  verbose,\n}: {\n  packageName: string;\n  currentVersion: string;\n  verbose?: boolean;\n}) => {\n  const prettyPackage = `${picocolors.blue(packageName)}@${picocolors.green(currentVersion)}`;\n  console.log(`⛅ Checking if ${prettyPackage} is published...`);\n\n  if (verbose) {\n    console.log(`Fetching from npm:`);\n    console.log(\n      `https://registry.npmjs.org/${picocolors.blue(packageName)}/${picocolors.green(currentVersion)}`\n    );\n  }\n  const response = await fetch(`https://registry.npmjs.org/${packageName}/${currentVersion}`);\n  if (response.status === 404) {\n    console.log(`🌤️ ${prettyPackage} is not published`);\n    return false;\n  }\n  if (response.status !== 200) {\n    console.error(\n      `Unexpected status code when checking the current version on npm: ${response.status}`\n    );\n    console.error(await response.text());\n    throw new Error(\n      `Unexpected status code when checking the current version on npm: ${response.status}`\n    );\n  }\n  const data: any = await response.json();\n  if (verbose) {\n    console.log(`Response from npm:`);\n    console.log(data);\n  }\n  if (data.version !== currentVersion) {\n    // this should never happen\n    console.error(\n      `Unexpected version received when checking the current version on npm: ${data.version}`\n    );\n    console.error(JSON.stringify(data, null, 2));\n    throw new Error(\n      `Unexpected version received when checking the current version on npm: ${data.version}`\n    );\n  }\n\n  console.log(`⛈️ ${prettyPackage} is published`);\n  return true;\n};\n\nconst buildAllPackages = async () => {\n  console.log(`🏗️ Building all packages...`);\n  await execaCommand('yarn task --task=compile --start-from=compile --no-link', {\n    stdio: 'inherit',\n    cleanup: true,\n    cwd: CODE_DIR_PATH,\n  });\n  console.log(`🏗️ Packages successfully built`);\n};\n\nconst publishAllPackages = async ({\n  tag,\n  verbose,\n  dryRun,\n}: {\n  tag: string;\n  verbose?: boolean;\n  dryRun?: boolean;\n}) => {\n  console.log(`📦 Publishing all packages...`);\n  const command = `yarn workspaces foreach --all --parallel --no-private --verbose npm publish --tolerate-republish --tag ${tag}`;\n  if (verbose) {\n    console.log(`📦 Executing: ${command}`);\n  }\n  if (dryRun) {\n    console.log(`📦 Dry run, skipping publish. Would have executed:\n    ${picocolors.blue(command)}`);\n    return;\n  }\n\n  /**\n   * 'yarn npm publish' will fail if just one package fails to publish. But it will continue through\n   * with all the other packages, and --tolerate-republish makes it okay to publish the same version\n   * again. So we can safely retry the whole publishing process if it fails. It's not uncommon for\n   * the registry to fail often, which Yarn catches by checking the registry after a package has\n   * been published.\n   */\n  await pRetry(\n    () =>\n      execaCommand(command, {\n        stdio: 'inherit',\n        cleanup: true,\n        cwd: CODE_DIR_PATH,\n      }),\n    {\n      retries: 4,\n      onFailedAttempt: (error) =>\n        console.log(\n          picocolors.yellow(\n            dedent`❗One or more packages failed to publish, retrying...\n            This was attempt number ${error.attemptNumber}, there are ${error.retriesLeft} retries left. 🤞`\n          )\n        ),\n    }\n  );\n  console.log(`📦 Packages successfully published`);\n};\n\nexport const run = async (options: unknown) => {\n  if (!validateOptions(options)) {\n    return;\n  }\n  const { tag, dryRun, verbose } = options;\n\n  // Get the current version from code/package.json\n  const currentVersion = await getCurrentVersion(verbose);\n  const isAlreadyPublished = await isCurrentVersionPublished({\n    currentVersion,\n    packageName: 'storybook',\n    verbose,\n  });\n  if (isAlreadyPublished) {\n    throw new Error(\n      `⛔ Current version (${picocolors.green(currentVersion)}) is already published, aborting.`\n    );\n  }\n  await buildAllPackages();\n  await publishAllPackages({ tag, verbose, dryRun });\n\n  console.log(\n    `✅ Published all packages with version ${picocolors.green(currentVersion)}${\n      tag ? ` at tag ${picocolors.blue(tag)}` : ''\n    }`\n  );\n};\n\nif (esMain(import.meta.url)) {\n  const parsed = program.parse();\n  run(parsed.opts()).catch((err) => {\n    console.error(err);\n    process.exit(1);\n  });\n}\n"
  },
  {
    "path": "scripts/release/unreleased-changes-exists.ts",
    "content": "import { setOutput } from '@actions/core';\nimport { program } from 'commander';\nimport { intersection } from 'es-toolkit/array';\nimport picocolors from 'picocolors';\nimport { z } from 'zod';\n\nimport { esMain } from '../utils/esmain.ts';\nimport { getCurrentVersion } from './get-current-version.ts';\nimport type { Change } from './utils/get-changes.ts';\nimport { RELEASED_LABELS, getChanges } from './utils/get-changes.ts';\n\nprogram\n  .name('are-changes-unreleased')\n  .description('check if any changes since a release should be released')\n  .option(\n    '-F, --from <version>',\n    'Which version/tag/commit to go back and check changes from. Defaults to latest release tag'\n  )\n  .option('-P, --unpicked-patches', 'Set to only consider PRs labeled with \"patch:yes\" label')\n  .option('-V, --verbose', 'Enable verbose logging', false);\n\nconst optionsSchema = z.object({\n  from: z.string().optional(),\n  unpickedPatches: z.boolean().optional(),\n  verbose: z.boolean().optional(),\n});\n\ntype Options = {\n  from?: string;\n  unpickedPatches?: boolean;\n  verbose: boolean;\n};\n\nconst validateOptions = (options: { [key: string]: any }): options is Options => {\n  optionsSchema.parse(options);\n  return true;\n};\n\nexport const run = async (\n  options: unknown\n): Promise<{ changesToRelease: Change[]; hasChangesToRelease: boolean }> => {\n  if (!validateOptions(options)) {\n    // this will never return because the validator throws\n    return { changesToRelease: [], hasChangesToRelease: false };\n  }\n  const { from, unpickedPatches, verbose } = options;\n\n  const currentVersion = await getCurrentVersion();\n\n  console.log(`📐 Checking if there are any unreleased changes...`);\n\n  const { changes } = await getChanges({\n    version: currentVersion,\n    from: from || currentVersion,\n    to: 'HEAD',\n    unpickedPatches,\n    verbose,\n  });\n\n  const changesToRelease = changes.filter(\n    ({ labels }) => intersection(Object.keys(RELEASED_LABELS), labels).length > 0\n  );\n\n  const hasChangesToRelease = changesToRelease.length > 0;\n\n  if (process.env.GITHUB_ACTIONS === 'true') {\n    setOutput('has-changes-to-release', hasChangesToRelease);\n  }\n  if (hasChangesToRelease) {\n    console.log(\n      `${picocolors.green('🦋 The following changes are releasable')}:\n${picocolors.blue(changesToRelease.map(({ title, pull }) => `  #${pull}: ${title}`).join('\\n'))}`\n    );\n  } else {\n    console.log(picocolors.red('🫙 No changes to release!'));\n  }\n\n  return { changesToRelease, hasChangesToRelease };\n};\n\nif (esMain(import.meta.url)) {\n  const parsed = program.parse();\n  run(parsed.opts()).catch((err) => {\n    console.error(err);\n    process.exit(1);\n  });\n}\n"
  },
  {
    "path": "scripts/release/utils/__mocks__/get-github-info.ts",
    "content": "import { vi } from 'vitest';\n\nexport const getPullInfoFromCommit = vi.fn();\nexport const getPullInfoFromPullRequest = vi.fn();\n"
  },
  {
    "path": "scripts/release/utils/get-changes.ts",
    "content": "import picocolors from 'picocolors';\nimport semver from 'semver';\n\nimport type { PullRequestInfo } from './get-github-info.ts';\nimport { getPullInfoFromCommit } from './get-github-info.ts';\nimport { getLatestTag, git } from './git-client.ts';\nimport { getUnpickedPRs } from './github-client.ts';\n\nexport const RELEASED_LABELS = {\n  'BREAKING CHANGE': '❗ Breaking Change',\n  'feature request': '✨ Feature Request',\n  bug: '🐛 Bug',\n  maintenance: '🔧 Maintenance',\n  dependencies: '📦 Dependencies',\n} as const;\n\nexport const UNRELEASED_LABELS = {\n  documentation: '📝 Documentation',\n  build: '🏗️ Build',\n  unknown: '❔ Missing Label',\n} as const;\n\nexport const LABELS_BY_IMPORTANCE = {\n  ...RELEASED_LABELS,\n  ...UNRELEASED_LABELS,\n} as const;\n\nconst getCommitAt = async (id: string, verbose?: boolean) => {\n  if (!semver.valid(id)) {\n    console.log(\n      `🔍 ${picocolors.red(id)} is not a valid semver string, assuming it is a commit hash`\n    );\n    return id;\n  }\n  const version = id.startsWith('v') ? id : `v${id}`;\n  const commitSha = (await git.raw(['rev-list', '-n', '1', version])).split('\\n')[0];\n  if (verbose) {\n    console.log(`🔍 Commit at tag ${picocolors.green(version)}: ${picocolors.blue(commitSha)}`);\n  }\n  return commitSha;\n};\n\nexport const getFromCommit = async (from?: string | undefined, verbose?: boolean) => {\n  let actualFrom = from;\n  if (!from) {\n    console.log(`🔍 No 'from' specified, finding latest version tag, fetching all of them...`);\n    const latest = await getLatestTag();\n    if (!latest) {\n      throw new Error(\n        'Could not automatically detect which commit to generate from, because no version tag was found in the history. Have you fetch tags?'\n      );\n    }\n    actualFrom = latest;\n    if (verbose) {\n      console.log(`🔍 No 'from' specified, found latest tag: ${picocolors.blue(latest)}`);\n    }\n  }\n  const commit = await getCommitAt(actualFrom!, verbose);\n  if (verbose) {\n    console.log(`🔍 Found 'from' commit: ${picocolors.blue(commit)}`);\n  }\n  return commit;\n};\n\nexport const getToCommit = async (to?: string | undefined, verbose?: boolean) => {\n  if (!to) {\n    const head = await git.revparse('HEAD');\n    if (verbose) {\n      console.log(`🔍 No 'to' specified, HEAD is at commit: ${picocolors.blue(head)}`);\n    }\n    return head;\n  }\n\n  const commit = await getCommitAt(to, verbose);\n  if (verbose) {\n    console.log(`🔍 Found 'to' commit: ${picocolors.blue(commit)}`);\n  }\n  return commit;\n};\n\nexport const getAllCommitsBetween = async ({\n  from,\n  to,\n  verbose,\n}: {\n  from: string;\n  to?: string;\n  verbose?: boolean;\n}) => {\n  const logResult = await git.log({ from, to, '--first-parent': null });\n  if (verbose) {\n    console.log(\n      `🔍 Found ${picocolors.blue(logResult.total)} commits between ${picocolors.green(\n        `${from}`\n      )} and ${picocolors.green(`${to}`)}:`\n    );\n    console.dir(logResult.all, { depth: null, colors: true });\n  }\n  return logResult.all;\n};\n\nexport const getRepo = async (verbose?: boolean): Promise<string> => {\n  const remotes = await git.getRemotes(true);\n  const originRemote = remotes.find((remote) => remote.name === 'origin');\n  if (!originRemote) {\n    console.error(\n      'Could not determine repository URL because no remote named \"origin\" was found. Remotes found:'\n    );\n    console.dir(remotes, { depth: null, colors: true });\n    throw new Error('No remote named \"origin\" found');\n  }\n  const pushUrl = originRemote.refs.push;\n  const repo = pushUrl.replace(/\\.git$/, '').replace(/.*:(\\/\\/github\\.com\\/)*/, '');\n  if (verbose) {\n    console.log(`📦 Extracted repo: ${picocolors.blue(repo)}`);\n  }\n  return repo;\n};\n\nexport const getPullInfoFromCommits = async ({\n  repo,\n  commits,\n  verbose,\n}: {\n  repo: string;\n  commits: readonly { hash: string }[];\n  verbose?: boolean;\n}): Promise<PullRequestInfo[]> => {\n  const pullRequests = await Promise.all(\n    commits.map((commit) =>\n      getPullInfoFromCommit({\n        repo,\n        commit: commit.hash,\n      })\n    )\n  );\n  if (verbose) {\n    console.log(`🔍 Found pull requests:`);\n    console.dir(pullRequests, { depth: null, colors: true });\n  }\n  return pullRequests;\n};\n\nexport type Change = PullRequestInfo;\n\nexport const mapToChanges = ({\n  commits,\n  pullRequests,\n  unpickedPatches,\n  verbose,\n}: {\n  commits: readonly { hash: string; message?: string }[];\n  pullRequests: PullRequestInfo[];\n  unpickedPatches?: boolean;\n  verbose?: boolean;\n}): Change[] => {\n  if (pullRequests.length !== commits.length) {\n    // not all commits are associated with a pull request, but the pullRequests array should still contain those commits\n    console.error('Pull requests and commits are not the same length, this should not happen');\n    console.error(`Pull Requests: ${pullRequests.length}`);\n    console.dir(pullRequests, { depth: null, colors: true });\n    console.error(`Commits: ${commits.length}`);\n    console.dir(commits, { depth: null, colors: true });\n    throw new Error('Pull requests and commits are not the same length, this should not happen');\n  }\n  const allEntries = pullRequests.map((pr, index) => {\n    return {\n      ...pr,\n      title: pr.title || commits[index].message,\n    };\n  });\n\n  const changes: Change[] = [];\n  allEntries.forEach((entry) => {\n    // filter out any duplicate entries, eg. when multiple commits are associated with the same pull request\n    if (entry.pull && changes.findIndex((existing) => entry.pull === existing.pull) !== -1) {\n      return;\n    }\n    // filter out any entries that are not patches if unpickedPatches is set. this will also filter out direct commits\n    if (unpickedPatches && !entry.labels?.includes('patch:yes')) {\n      return;\n    }\n    changes.push(entry);\n  });\n\n  if (verbose) {\n    console.log(`📝 Generated changelog entries:`);\n    console.dir(changes, { depth: null, colors: true });\n  }\n  return changes;\n};\n\nexport const getChangelogText = ({\n  changes,\n  version,\n}: {\n  changes: Change[];\n  version: string;\n}): string => {\n  const heading = `## ${version}`;\n  const formattedEntries = changes\n    .filter((entry) => {\n      // don't include direct commits that are not from pull requests\n      if (!entry.pull) {\n        return false;\n      }\n      // only include PRs that with labels listed in LABELS_FOR_CHANGELOG\n      return entry.labels?.some((label) => Object.keys(RELEASED_LABELS).includes(label));\n    })\n    .map((entry) => {\n      const { title, user, links } = entry;\n      const { pull, commit } = links;\n      return pull\n        ? `- ${title} - ${pull}, thanks @${user}!`\n        : `- ⚠️ _Direct commit_ ${title} - ${commit} by @${user}`;\n    })\n    .sort();\n  const text = [heading, '', ...formattedEntries].join('\\n');\n\n  console.log(`✅ Generated Changelog:`);\n  console.log(text);\n\n  return text;\n};\n\nexport const getChanges = async ({\n  version,\n  from,\n  to,\n  unpickedPatches,\n  verbose,\n}: {\n  version: string;\n  from?: string;\n  to?: string;\n  unpickedPatches?: boolean;\n  verbose?: boolean;\n}) => {\n  console.log(`💬 Getting changes for ${picocolors.blue(version)}`);\n\n  let commits;\n  if (unpickedPatches) {\n    commits = (await getUnpickedPRs('next', verbose)).map((it) => ({ hash: it.mergeCommit }));\n  } else {\n    commits = await getAllCommitsBetween({\n      from: await getFromCommit(from, verbose),\n      to: await getToCommit(to, verbose),\n      verbose,\n    });\n  }\n\n  const repo = await getRepo(verbose);\n  const pullRequests = await getPullInfoFromCommits({ repo, commits, verbose }).catch((err) => {\n    console.error(\n      `🚨 Could not get pull requests from commits, this is usually because you have unpushed commits, or you haven't set the GH_TOKEN environment variable`\n    );\n    console.error(err);\n    throw err;\n  });\n  const changes = mapToChanges({ commits, pullRequests, unpickedPatches, verbose });\n  const changelogText = getChangelogText({\n    changes,\n    version,\n  });\n\n  return { changes, changelogText };\n};\n"
  },
  {
    "path": "scripts/release/utils/get-github-info.ts",
    "content": "/**\n * This file is soft-forked from @changesets/get-github-info\n * https://github.com/changesets/changesets/tree/main/packages/get-github-info\n *\n * The only modification is that it also returns the PR title and labels\n */\nimport DataLoader from 'dataloader';\n\nconst validRepoNameRegex = /^[\\w.-]+\\/[\\w.-]+$/;\n\ntype RequestData =\n  | { kind: 'commit'; repo: string; commit: string }\n  | { kind: 'pull'; repo: string; pull: number };\n\ntype ReposWithCommitsAndPRsToFetch = Record<\n  string,\n  ({ kind: 'commit'; commit: string } | { kind: 'pull'; pull: number })[]\n>;\n\nfunction makeQuery(repos: ReposWithCommitsAndPRsToFetch) {\n  const query = `\n      query {\n        ${Object.keys(repos)\n          .map(\n            (repo, i) =>\n              `a${i}: repository(\n            owner: ${JSON.stringify(repo.split('/')[0])}\n            name: ${JSON.stringify(repo.split('/')[1])}\n          ) {\n            ${repos[repo]\n              .map((data) =>\n                data.kind === 'commit'\n                  ? `a${data.commit}: object(expression: ${JSON.stringify(data.commit)}) {\n            ... on Commit {\n            commitUrl\n            associatedPullRequests(first: 50) {\n              nodes {\n                number\n                id\n                title\n                state\n                url\n                mergedAt\n                labels(first: 50) {\n                  nodes {\n                    name\n                  }\n                }\n                author {\n                  login\n                  url\n                }\n              }\n            }\n            author {\n              user {\n                login\n                url\n              }\n            }\n          }}`\n                  : `pr__${data.pull}: pullRequest(number: ${data.pull}) {\n                    url\n                    title\n                    state\n                    author {\n                      login\n                      url\n                    }\n                    labels(first: 50) {\n                      nodes {\n                        name\n                      }\n                    }\n                    mergeCommit {\n                      commitUrl\n                      oid\n                    }\n                  }`\n              )\n              .join('\\n')}\n          }`\n          )\n          .join('\\n')}\n        }\n    `;\n  return query;\n}\n\n// why are we using dataloader?\n// it provides use with two things\n// 1. caching\n// since getInfo will be called inside of changeset's getReleaseLine\n// and there could be a lot of release lines for a single commit\n// caching is important so we don't do a bunch of requests for the same commit\n// 2. batching\n// getReleaseLine will be called a large number of times but it'll be called at the same time\n// so instead of doing a bunch of network requests, we can do a single one.\nconst GHDataLoader = new DataLoader(\n  async (requests: readonly RequestData[]) => {\n    if (!process.env.GH_TOKEN) {\n      throw new Error(\n        'Please create a GitHub personal access token at https://github.com/settings/tokens/new with `read:user` and `repo:status` permissions and add it as the GH_TOKEN environment variable'\n      );\n    }\n    const repos: ReposWithCommitsAndPRsToFetch = {};\n    requests.forEach(({ repo, ...data }) => {\n      if (repos[repo] === undefined) {\n        repos[repo] = [];\n      }\n      repos[repo].push(data);\n    });\n\n    const data = await fetch('https://api.github.com/graphql', {\n      method: 'POST',\n      headers: {\n        Authorization: `Token ${process.env.GH_TOKEN}`,\n      },\n      body: JSON.stringify({ query: makeQuery(repos) }),\n    }).then((x: any) => x.json());\n\n    if (data.errors) {\n      throw new Error(\n        `An error occurred when fetching data from GitHub\\n${JSON.stringify(data.errors, null, 2)}`\n      );\n    }\n\n    // this is mainly for the case where there's an authentication problem\n    if (!data.data) {\n      throw new Error(`An error occurred when fetching data from GitHub\\n${JSON.stringify(data)}`);\n    }\n\n    const cleanedData: Record<string, { commit: Record<string, any>; pull: Record<string, any> }> =\n      {};\n    Object.keys(repos).forEach((repo, index) => {\n      const output: { commit: Record<string, any>; pull: Record<string, any> } = {\n        commit: {},\n        pull: {},\n      };\n      cleanedData[repo] = output;\n      Object.entries(data.data[`a${index}`]).forEach(([field, value]) => {\n        // this is \"a\" because that's how it was when it was first written, \"a\" means it's a commit not a pr\n        // we could change it to commit__ but then we have to get new GraphQL results from the GH API to put in the tests\n        if (field[0] === 'a') {\n          output.commit[field.substring(1)] = value;\n        } else {\n          output.pull[field.replace('pr__', '')] = value;\n        }\n      });\n    });\n\n    return requests.map(\n      ({ repo, ...rest }) =>\n        cleanedData[repo][rest.kind][rest.kind === 'pull' ? rest.pull : rest.commit]\n    );\n  },\n  { maxBatchSize: 50 }\n);\n\nexport type PullRequestInfo = {\n  user: string | null;\n  id: string | null;\n  title: string | null;\n  state: string | null;\n  commit: string | null;\n  pull: number | null;\n  labels: string[] | null;\n  links: {\n    commit: string | null;\n    pull: string | null;\n    user: string | null;\n  };\n};\n\nexport async function getPullInfoFromCommit(request: {\n  commit: string;\n  repo: string;\n}): Promise<PullRequestInfo> {\n  if (!request.commit) {\n    throw new Error('Please pass a commit SHA to getInfo');\n  }\n\n  if (!request.repo) {\n    throw new Error('Please pass a GitHub repository in the form of userOrOrg/repoName to getInfo');\n  }\n\n  if (!validRepoNameRegex.test(request.repo)) {\n    throw new Error(\n      `Please pass a valid GitHub repository in the form of userOrOrg/repoName to getInfo (it has to match the \"${validRepoNameRegex.source}\" pattern)`\n    );\n  }\n\n  const data = await GHDataLoader.load({ kind: 'commit', ...request });\n  if (!data) {\n    return {\n      id: null,\n      user: null,\n      pull: null,\n      commit: request.commit,\n      title: null,\n      state: null,\n      labels: null,\n      links: {\n        commit: request.commit,\n        pull: null,\n        user: null,\n      },\n    };\n  }\n  let user = data?.author?.user || null;\n\n  const associatedPullRequest =\n    data.associatedPullRequests &&\n    data.associatedPullRequests.nodes &&\n    data.associatedPullRequests.nodes.length\n      ? (data.associatedPullRequests.nodes as any[]).sort((a, b) => {\n          if (a.mergedAt === null && b.mergedAt === null) {\n            return 0;\n          }\n          if (a.mergedAt === null) {\n            return 1;\n          }\n          if (b.mergedAt === null) {\n            return -1;\n          }\n          const aDate = new Date(a.mergedAt);\n          const bDate = new Date(b.mergedAt);\n          if (aDate > bDate) {\n            return 1;\n          }\n          if (aDate < bDate) {\n            return -1;\n          }\n          return 0;\n        })[0]\n      : null;\n  if (associatedPullRequest) {\n    user = associatedPullRequest.author;\n  }\n\n  return {\n    user: user ? user.login : null,\n    id: associatedPullRequest ? associatedPullRequest.id : null,\n    pull: associatedPullRequest ? associatedPullRequest.number : null,\n    commit: request.commit,\n    title: associatedPullRequest ? associatedPullRequest.title : null,\n    state: associatedPullRequest ? associatedPullRequest.state : null,\n    labels: associatedPullRequest\n      ? (associatedPullRequest.labels.nodes || []).map((label: { name: string }) => label.name)\n      : null,\n    links: {\n      commit: `[\\`${request.commit}\\`](${data.commitUrl})`,\n      pull: associatedPullRequest\n        ? `[#${associatedPullRequest.number}](${associatedPullRequest.url})`\n        : null,\n      user: user ? `[@${user.login}](${user.url})` : null,\n    },\n  };\n}\n\nexport async function getPullInfoFromPullRequest(request: {\n  pull: number;\n  repo: string;\n}): Promise<PullRequestInfo> {\n  if (request.pull === undefined) {\n    throw new Error('Please pass a pull request number');\n  }\n\n  if (!request.repo) {\n    throw new Error('Please pass a GitHub repository in the form of userOrOrg/repoName to getInfo');\n  }\n\n  if (!validRepoNameRegex.test(request.repo)) {\n    throw new Error(\n      `Please pass a valid GitHub repository in the form of userOrOrg/repoName to getInfo (it has to match the \"${validRepoNameRegex.source}\" pattern)`\n    );\n  }\n\n  const data = await GHDataLoader.load({ kind: 'pull', ...request });\n  const user = data?.author;\n  const title = data?.title;\n  const commit = data?.mergeCommit;\n\n  return {\n    user: user ? user.login : null,\n    id: null,\n    pull: request.pull,\n    commit: commit ? commit.oid : null,\n    title: title || null,\n    state: data?.state || null,\n    labels: data ? (data.labels.nodes || []).map((label: { name: string }) => label.name) : null,\n    links: {\n      commit: commit ? `[\\`${commit.oid}\\`](${commit.commitUrl})` : null,\n      pull: `[#${request.pull}](https://github.com/${request.repo}/pull/${request.pull})`,\n      user: user ? `[@${user.login}](${user.url})` : null,\n    },\n  };\n}\n"
  },
  {
    "path": "scripts/release/utils/git-client.ts",
    "content": "import { simpleGit } from 'simple-git';\n\nexport const git = simpleGit({\n  config: [\n    /**\n     * Ensures that prereleases are listed as earlier than stable releases. WITHOUT the config, this\n     * is the list of tags: v7.1.0-rc.2 v7.1.0-rc.1 v7.1.0-rc.0 v7.1.0-beta.3 ... v7.1.0 v7.0.2\n     *\n     * WITH the config, v7.1.0 is correctly on the top: v7.1.0 v7.1.0-rc.2 v7.1.0-rc.1 v7.1.0-rc.0\n     * v7.1.0-beta.3 ... v7.0.2\n     *\n     * The top most tag is considered the \"latest\", which is used as a starting point for looking\n     * for changes for upcoming releases See https://stackoverflow.com/a/52680984\n     */\n    'versionsort.suffix=-',\n  ],\n});\n\nexport async function getLatestTag() {\n  return (await git.tags(['v*', '--sort=-v:refname', '--merged'])).latest;\n}\n"
  },
  {
    "path": "scripts/release/utils/github-client.ts",
    "content": "import type { GraphQlQueryResponseData } from '@octokit/graphql';\nimport { graphql } from '@octokit/graphql';\nimport { request } from '@octokit/request';\n\nexport interface PullRequest {\n  number: number;\n  id: string;\n  branch: string;\n  title: string;\n  mergeCommit: string;\n}\n\nexport const githubGraphQlClient = graphql.defaults({\n  headers: { authorization: `token ${process.env.GH_TOKEN}` },\n});\n\nexport const githubRestClient = request.defaults({\n  request: {\n    fetch,\n  },\n  headers: { authorization: `token ${process.env.GH_TOKEN}`, 'X-GitHub-Api-Version': '2022-11-28' },\n});\n\nexport async function getUnpickedPRs(\n  baseBranch: string,\n  verbose?: boolean\n): Promise<Array<PullRequest>> {\n  console.log(`💬 Getting unpicked patch pull requests...`);\n  const result = await githubGraphQlClient<GraphQlQueryResponseData>(\n    `\n      query ($owner: String!, $repo: String!, $state: PullRequestState!, $order: IssueOrder!) {\n        repository(owner: $owner, name: $repo) {\n          pullRequests(states: [$state], labels: [\"patch:yes\"], orderBy: $order, first: 50, baseRefName: \"next\") {\n            nodes {\n              id\n              number\n              title\n              baseRefName\n              mergeCommit { \n                oid\n              }\n              labels(first: 20) {\n                nodes {\n                  name\n                }\n              }\n            }\n          }\n        }\n      }\n    `,\n    {\n      owner: 'storybookjs',\n      repo: 'storybook',\n      order: {\n        field: 'UPDATED_AT',\n        direction: 'DESC',\n      },\n      state: 'MERGED',\n    }\n  );\n\n  const {\n    pullRequests: { nodes },\n  } = result.repository;\n\n  const prs = nodes.map((node: any) => ({\n    number: node.number,\n    id: node.id,\n    branch: node.baseRefName,\n    title: node.title,\n    mergeCommit: node.mergeCommit.oid,\n    labels: node.labels.nodes.map((l: any) => l.name),\n  }));\n\n  const unpickedPRs = prs\n    .filter((pr: any) => !pr.labels.includes('patch:done'))\n    .filter((pr: any) => pr.branch === baseBranch)\n    .reverse();\n\n  if (verbose) {\n    console.log(`🔍 Found unpicked patch pull requests:\n  ${JSON.stringify(unpickedPRs, null, 2)}`);\n  }\n  return unpickedPRs;\n}\n\nexport async function getLabelIds({\n  repo: fullRepo,\n  labelNames,\n}: {\n  labelNames: string[];\n  repo: string;\n}) {\n  const query = labelNames.join('+');\n  const [owner, repo] = fullRepo.split('/');\n  const result = await githubGraphQlClient<GraphQlQueryResponseData>(\n    `\n      query ($owner: String!, $repo: String!, $q: String!) {\n        repository(owner: $owner, name: $repo) {\n          labels(query: $q, first: 10) {\n            nodes {\n              id\n              name\n              description\n            }\n          }\n        }\n      }\n    `,\n    { owner, repo, q: query }\n  );\n\n  const { labels } = result.repository;\n  const labelToId: Record<string, string> = {};\n  labels.nodes.forEach((label: { name: string; id: string }) => {\n    labelToId[label.name] = label.id;\n  });\n  return labelToId;\n}\n"
  },
  {
    "path": "scripts/release/version.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { setOutput } from '@actions/core';\nimport { program } from 'commander';\n// eslint-disable-next-line depend/ban-dependencies\nimport { execaCommand } from 'execa';\nimport picocolors from 'picocolors';\nimport semver from 'semver';\nimport { z } from 'zod';\n\nimport { esMain } from '../utils/esmain.ts';\nimport type { Workspace } from '../utils/workspace.ts';\nimport { getCodeWorkspaces } from '../utils/workspace.ts';\n\nprogram\n  .name('version')\n  .description('version all packages')\n  .option(\n    '-R, --release-type <major|minor|patch|prerelease>',\n    'Which release type to use to bump the version'\n  )\n  .option(\n    '-P, --pre-id <id>',\n    'Which prerelease identifier to change to, eg. \"alpha\", \"beta\", \"rc\"'\n  )\n  .option(\n    '-E, --exact <version>',\n    'Use exact version instead of calculating from current version, eg. \"7.2.0-canary.123\". Can not be combined with --release-type or --pre-id'\n  )\n  .option(\n    '-D, --deferred',\n    'Do not bump versions everywhere, instead set it in code/package.json#deferredNextVersion'\n  )\n  .option('-A, --apply', 'Apply a deferred version bump')\n  .option('-V, --verbose', 'Enable verbose logging', false);\n\nconst optionsSchema = z\n  .object({\n    releaseType: z\n      .enum(['major', 'minor', 'patch', 'prerelease', 'premajor', 'preminor', 'prepatch'])\n      .optional(),\n    preId: z.string().optional(),\n    exact: z\n      .string()\n      .optional()\n      .refine((version) => (version ? semver.valid(version) !== null : true), {\n        message: '--exact version has to be a valid semver string',\n      }),\n    deferred: z.boolean().optional(),\n    apply: z.boolean().optional(),\n    verbose: z.boolean().optional(),\n  })\n  .superRefine((schema, ctx) => {\n    // manual union validation because zod + commander is not great in this case\n    const hasExact = 'exact' in schema && schema.exact;\n    const hasReleaseType = 'releaseType' in schema && schema.releaseType;\n    const hasDeferred = 'deferred' in schema && schema.deferred;\n    const hasApply = 'apply' in schema && schema.apply;\n    if (hasDeferred && hasApply) {\n      ctx.addIssue({\n        code: z.ZodIssueCode.custom,\n        message: '--deferred cannot be combined with --apply',\n      });\n    }\n    if (hasApply && (hasExact || hasReleaseType)) {\n      ctx.addIssue({\n        code: z.ZodIssueCode.custom,\n        message:\n          '--apply cannot be combined with --exact or --release-type, as it will always read from code/package.json#deferredNextVersion',\n      });\n    }\n    if (!hasApply && ((hasExact && hasReleaseType) || (!hasExact && !hasReleaseType))) {\n      ctx.addIssue({\n        code: z.ZodIssueCode.custom,\n        message:\n          'Combining --exact with --release-type is invalid, but having one of them is required',\n      });\n    }\n    if (schema.preId && !schema.releaseType.startsWith('pre')) {\n      ctx.addIssue({\n        code: z.ZodIssueCode.custom,\n        message:\n          'Using prerelease identifier requires one of release types: premajor, preminor, prepatch, prerelease',\n      });\n    }\n    return z.NEVER;\n  });\n\ntype BaseOptions = { verbose: boolean };\ntype BumpOptions = BaseOptions & {\n  releaseType: semver.ReleaseType;\n  preId?: string;\n  deferred?: boolean;\n};\ntype ExactOptions = BaseOptions & {\n  exact: semver.ReleaseType;\n  deferred?: boolean;\n};\ntype ApplyOptions = BaseOptions & {\n  apply: boolean;\n};\ntype Options = BumpOptions | ExactOptions | ApplyOptions;\n\nconst CODE_DIR_PATH = join(__dirname, '..', '..', 'code');\nconst CODE_PACKAGE_JSON_PATH = join(CODE_DIR_PATH, 'package.json');\n\nconst validateOptions = (options: { [key: string]: any }): options is Options => {\n  optionsSchema.parse(options);\n  return true;\n};\n\nconst readJson = async (path: string) => {\n  const content = await readFile(path, 'utf-8');\n  return JSON.parse(content);\n};\n\nconst getCurrentVersion = async () => {\n  console.log(`📐 Reading current version of Storybook...`);\n  const { version } = await readJson(CODE_PACKAGE_JSON_PATH);\n  return version;\n};\n\nconst bumpCodeVersion = async (nextVersion: string) => {\n  console.log(`🤜 Bumping version of ${picocolors.cyan('code')}'s package.json...`);\n\n  const codePkgJson = await readJson(CODE_PACKAGE_JSON_PATH);\n\n  codePkgJson.version = nextVersion;\n  await writeFile(CODE_PACKAGE_JSON_PATH, JSON.stringify(codePkgJson, null, 2) + '\\n');\n\n  console.log(`✅ Bumped version of ${picocolors.cyan('code')}'s package.json`);\n};\n\nconst bumpVersionSources = async (currentVersion: string, nextVersion: string) => {\n  const filesToUpdate = [\n    join(CODE_DIR_PATH, 'core', 'src', 'manager-api', 'version.ts'),\n    join(CODE_DIR_PATH, 'core', 'src', 'common', 'versions.ts'),\n  ];\n  console.log(`🤜 Bumping versions in...:\\n  ${picocolors.cyan(filesToUpdate.join('\\n  '))}`);\n\n  await Promise.all(\n    filesToUpdate.map(async (filename) => {\n      const currentContent = await readFile(filename, { encoding: 'utf-8' });\n      const nextContent = currentContent.replaceAll(currentVersion, nextVersion);\n      return writeFile(filename, nextContent);\n    })\n  );\n\n  console.log(`✅ Bumped versions in:\\n  ${picocolors.cyan(filesToUpdate.join('\\n  '))}`);\n};\n\nconst bumpAllPackageJsons = async ({\n  packages,\n  nextVersion,\n  verbose,\n}: {\n  packages: Workspace[];\n  nextVersion: string;\n  verbose?: boolean;\n}) => {\n  console.log(\n    `🤜 Bumping versions and dependencies in ${picocolors.cyan(\n      `all ${packages.length} package.json`\n    )}'s...`\n  );\n  // 1. go through all packages in the monorepo\n  await Promise.all(\n    packages.map(async (pkg) => {\n      // 2. get the package.json\n      const packageJsonPath = join(CODE_DIR_PATH, pkg.location, 'package.json');\n      const packageJson: {\n        version: string;\n        [key: string]: any;\n      } = await readJson(packageJsonPath);\n      // 3. bump the version\n      packageJson.version = nextVersion;\n      if (verbose) {\n        console.log(\n          `    Bumping ${picocolors.blue(pkg.name)}'s version to ${picocolors.yellow(nextVersion)}`\n        );\n      }\n      await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));\n    })\n  );\n};\n\nconst bumpDeferred = async (nextVersion: string) => {\n  console.log(\n    `⏳ Setting a ${picocolors.cyan('deferred')} version bump with ${picocolors.blue(\n      'code/package.json#deferredNextVersion'\n    )} = ${picocolors.yellow(nextVersion)}...`\n  );\n  const codePkgJson = await readJson(CODE_PACKAGE_JSON_PATH);\n\n  if (codePkgJson.deferredNextVersion) {\n    console.warn(\n      `❗ A \"deferredNextVersion\" property already exists with the value of ${picocolors.cyan(\n        codePkgJson.deferredNextVersion\n      )}. This will be overwritten and ignored.`\n    );\n  }\n\n  codePkgJson.deferredNextVersion = nextVersion;\n  await writeFile(CODE_PACKAGE_JSON_PATH, JSON.stringify(codePkgJson, null, 2) + '\\n');\n\n  console.log(`✅ Set a ${picocolors.cyan('deferred')} version bump. Not bumping any packages.`);\n};\n\nconst applyDeferredVersionBump = async () => {\n  console.log(\n    `⏩ Applying previously deferred version bump set at ${picocolors.blue(\n      'code/package.json#deferredNextVersion'\n    )}...`\n  );\n  const codePkgJson = await readJson(CODE_PACKAGE_JSON_PATH);\n\n  const { deferredNextVersion } = codePkgJson;\n\n  if (!deferredNextVersion) {\n    throw new Error(\n      \"The 'deferredNextVersion' property in code/package.json is unset. This is necessary to apply a deferred version bump\"\n    );\n  }\n\n  delete codePkgJson.deferredNextVersion;\n  await writeFile(CODE_PACKAGE_JSON_PATH, JSON.stringify(codePkgJson, null, 2) + '\\n');\n\n  console.log(\n    `✅ Extracted and removed deferred version ${picocolors.green(\n      deferredNextVersion\n    )} from ${picocolors.blue('code/package.json#deferredNextVersion')}`\n  );\n\n  return deferredNextVersion;\n};\n\nexport const run = async (options: unknown) => {\n  if (!validateOptions(options)) {\n    return;\n  }\n  const { verbose } = options;\n\n  console.log(`🚛 Finding Storybook packages...`);\n\n  const [packages, currentVersion] = await Promise.all([getCodeWorkspaces(), getCurrentVersion()]);\n\n  console.log(\n    `📦 found ${packages.length} storybook packages at version ${picocolors.red(currentVersion)}`\n  );\n  if (verbose) {\n    const formattedPackages = packages.map(\n      (pkg) => `${picocolors.green(pkg.name.padEnd(60))}: ${picocolors.cyan(pkg.location)}`\n    );\n    console.log(`📦 Packages:\n        ${formattedPackages.join('\\n    ')}`);\n  }\n\n  let nextVersion: string;\n\n  if ('apply' in options && options.apply) {\n    nextVersion = await applyDeferredVersionBump();\n  } else if ('exact' in options && options.exact) {\n    console.log(`📈 Exact version selected: ${picocolors.green(options.exact)}`);\n    nextVersion = options.exact;\n  } else {\n    const { releaseType, preId } = options as BumpOptions;\n    console.log(`📈 Release type selected: ${picocolors.green(releaseType)}`);\n    if (preId) {\n      console.log(`🆔 Version prerelease identifier selected: ${picocolors.yellow(preId)}`);\n    }\n\n    nextVersion = semver.inc(currentVersion, releaseType, preId);\n\n    console.log(\n      `⏭ Bumping version ${picocolors.blue(currentVersion)} with release type ${picocolors.green(\n        releaseType\n      )}${\n        preId ? ` and ${picocolors.yellow(preId)}` : ''\n      } results in version: ${picocolors.bold(picocolors.greenBright(nextVersion))}`\n    );\n  }\n\n  if ('deferred' in options && options.deferred) {\n    await bumpDeferred(nextVersion);\n  } else {\n    console.log(`⏭ Bumping all packages to ${picocolors.blue(nextVersion)}...`);\n\n    await bumpCodeVersion(nextVersion);\n    await bumpVersionSources(currentVersion, nextVersion);\n    await bumpAllPackageJsons({ packages, nextVersion, verbose });\n\n    console.log(\n      `⬆️ Updating lock file with ${picocolors.blue('yarn install --mode=update-lockfile')}`\n    );\n    await execaCommand(`yarn install --mode=update-lockfile`, {\n      cwd: join(CODE_DIR_PATH),\n      stdio: verbose ? 'inherit' : undefined,\n      cleanup: true,\n    });\n    console.log(\n      `✅ Updated lock file with ${picocolors.blue('yarn install --mode=update-lockfile')}`\n    );\n  }\n\n  if (process.env.GITHUB_ACTIONS === 'true') {\n    setOutput('current-version', currentVersion);\n    setOutput('next-version', nextVersion);\n  }\n};\n\nif (esMain(import.meta.url)) {\n  const options = program.parse().opts();\n  run(options).catch((err) => {\n    console.error(err);\n    process.exit(1);\n  });\n}\n"
  },
  {
    "path": "scripts/release/write-changelog.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { program } from 'commander';\nimport picocolors from 'picocolors';\nimport semver from 'semver';\nimport { z } from 'zod';\n\nimport { esMain } from '../utils/esmain.ts';\nimport { getChanges } from './utils/get-changes.ts';\n\nprogram\n  .name('write-changelog')\n  .description(\n    'write changelog based on merged PRs and commits. the <version> argument describes the changelog entry heading, but NOT which commits/PRs to include, must be a semver string'\n  )\n  .arguments('<version>')\n  .option('-P, --unpicked-patches', 'Set to only consider PRs labeled with \"patch:yes\" label')\n  .option(\n    '-F, --from <tag>',\n    'Which tag or commit to generate changelog from, eg. \"7.0.7\". Leave unspecified to select latest released tag in git history'\n  )\n  .option(\n    '-T, --to <tag>',\n    'Which tag or commit to generate changelog to, eg. \"7.1.0-beta.8\". Leave unspecified to select HEAD commit'\n  )\n  .option('-D, --dry-run', 'Do not write file, only output to shell', false)\n  .option('-V, --verbose', 'Enable verbose logging', false);\n\nconst optionsSchema = z.object({\n  unpickedPatches: z.boolean().optional(),\n  from: z.string().optional(),\n  to: z.string().optional(),\n  verbose: z.boolean().optional(),\n  dryRun: z.boolean().optional(),\n});\n\ntype Options = {\n  unpickedPatches?: boolean;\n  from?: string;\n  to?: string;\n  verbose: boolean;\n  dryRun?: boolean;\n};\n\nconst validateOptions = (args: unknown[], options: { [key: string]: any }): options is Options => {\n  optionsSchema.parse(options);\n  if (args.length !== 1 || !semver.valid(args[0] as string)) {\n    console.error(\n      `🚨 Invalid arguments, expected a single argument with the version to generate changelog for, eg. ${picocolors.green(\n        '7.1.0-beta.8'\n      )}`\n    );\n    return false;\n  }\n  return true;\n};\n\nconst writeToChangelogFile = async ({\n  changelogText,\n  version,\n  verbose,\n}: {\n  changelogText: string;\n  version: string;\n  verbose?: boolean;\n}) => {\n  const isPrerelease = semver.prerelease(version) !== null;\n  const changelogFilename = isPrerelease ? 'CHANGELOG.prerelease.md' : 'CHANGELOG.md';\n  const changelogPath = join(__dirname, '..', '..', changelogFilename);\n\n  if (verbose) {\n    console.log(`📝 Writing changelog to ${picocolors.blue(changelogPath)}`);\n  }\n\n  const currentChangelog = await readFile(changelogPath, 'utf-8');\n  const nextChangelog = [changelogText, currentChangelog].join('\\n\\n');\n\n  await writeFile(changelogPath, nextChangelog);\n};\n\nconst writeToDocsVersionFile = async ({\n  changelogText,\n  version,\n  verbose,\n}: {\n  changelogText: string;\n  version: string;\n  verbose?: boolean;\n}) => {\n  const isPrerelease = semver.prerelease(version) !== null;\n  const filename = isPrerelease ? 'next.json' : 'latest.json';\n  const filepath = join(__dirname, '..', '..', 'docs', 'versions', filename);\n\n  if (verbose) {\n    console.log(`📝 Writing changelog to ${picocolors.blue(filepath)}`);\n  }\n\n  const textWithoutHeading = changelogText.split('\\n').slice(2).join('\\n').replaceAll('\"', '\\\\\"');\n\n  const content = {\n    version,\n    info: {\n      plain: textWithoutHeading,\n    },\n  };\n\n  await writeFile(filepath, JSON.stringify(content));\n};\n\nexport const run = async (args: unknown[], options: unknown) => {\n  if (!validateOptions(args, options)) {\n    return;\n  }\n  const { from, to, unpickedPatches, dryRun, verbose } = options;\n  const version = args[0] as string;\n\n  console.log(\n    `💬 Generating changelog for ${picocolors.blue(version)} between ${picocolors.green(\n      from || 'latest'\n    )} and ${picocolors.green(to || 'HEAD')}`\n  );\n\n  const { changelogText } = await getChanges({ version, from, to, unpickedPatches, verbose });\n\n  if (dryRun) {\n    console.log(`📝 Dry run, not writing file`);\n    return;\n  }\n\n  await writeToChangelogFile({ changelogText, version, verbose });\n  await writeToDocsVersionFile({ changelogText, version, verbose });\n\n  console.log(`✅ Wrote Changelog to file`);\n};\n\nif (esMain(import.meta.url)) {\n  const parsed = program.parse();\n  run(parsed.args, parsed.opts()).catch((err) => {\n    console.error(err);\n    process.exit(1);\n  });\n}\n"
  },
  {
    "path": "scripts/reset.js",
    "content": "// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-nocheck\nimport { spawn } from 'node:child_process';\nimport { appendFile, writeFileSync } from 'node:fs';\nimport { rm } from 'node:fs/promises';\n\nimport trash from 'trash';\n\nconst logger = console;\n\nwriteFileSync('reset.log', '');\n\nconst cleaningProcess = spawn('git', [\n  'clean',\n  '-xdf',\n  '-n',\n  '--exclude=\"/.vscode\"',\n  '--exclude=\"/.idea\"',\n]);\n\ncleaningProcess.stdout.on('data', (data) => {\n  if (data && data.toString()) {\n    const l = data\n      .toString()\n      .split(/\\n/)\n      .forEach((i) => {\n        const [, uri] = i.match(/Would remove (.*)$/) || [];\n\n        if (uri) {\n          if (\n            uri.match(/node_modules/) ||\n            uri.match(/dist/) ||\n            uri.match(/ts3\\.4/) ||\n            uri.match(/\\.cache/) ||\n            uri.match(/dll/)\n          ) {\n            rm(uri, { force: true, recursive: true }).then(() => {\n              logger.log(`deleted ${uri}`);\n            });\n          } else {\n            trash(uri)\n              .then(() => {\n                logger.log(`trashed ${uri}`);\n              })\n              .catch((e) => {\n                logger.log('failed to trash, will try permanent delete');\n                rm(uri, { force: true, recursive: true }).then(() => {\n                  logger.log(`deleted ${uri}`);\n                });\n              });\n          }\n        }\n      });\n  }\n  appendFile('reset.log', data, (err) => {\n    if (err) {\n      throw err;\n    }\n  });\n});\ncleaningProcess.on('exit', (code) => {\n  if (code === 0) {\n    logger.log('all went well, files are being trashed now');\n  } else {\n    logger.error(code);\n  }\n});\n"
  },
  {
    "path": "scripts/run-registry.ts",
    "content": "import { exec } from 'node:child_process';\nimport { access, mkdir, readFile, rm } from 'node:fs/promises';\nimport http from 'node:http';\nimport type { Server } from 'node:http';\nimport { join, resolve as resolvePath } from 'node:path';\n\nimport { program } from 'commander';\nimport pLimit from 'p-limit';\nimport picocolors from 'picocolors';\nimport { parseConfigFile, runServer } from 'verdaccio';\n\nimport { npmAuth } from './npm-auth.ts';\nimport { maxConcurrentTasks } from './utils/concurrency.ts';\nimport { PACKS_DIRECTORY, ROOT_DIRECTORY } from './utils/constants.ts';\nimport { killPort } from './utils/port.ts';\nimport { getCodeWorkspaces } from './utils/workspace.ts';\n\nprogram\n  .option('-O, --open', 'keep process open')\n  .option('-P, --publish', 'should publish packages');\n\nprogram.parse(process.argv);\n\nconst logger = console;\n\nconst root = resolvePath(__dirname, '..');\n\nconst opts = program.opts();\n\nconst pathExists = async (p: string) => {\n  try {\n    await access(p);\n    return true;\n  } catch {\n    return false;\n  }\n};\n\ntype Servers = { close: () => Promise<void> };\nconst startVerdaccio = async () => {\n  // Kill Verdaccio related processes if they are already running\n  await killPort(6001);\n  await killPort(6002);\n\n  const ready = {\n    proxy: false,\n    verdaccio: false,\n  };\n  return Promise.race([\n    new Promise((resolve) => {\n      /**\n       * The proxy server will sit in front of verdaccio and tunnel traffic to either verdaccio or\n       * the actual npm global registry We do this because tunneling all traffic through verdaccio\n       * is slow (this might get fixed in verdaccio) With this heuristic we get the best of both\n       * worlds:\n       *\n       * - Verdaccio for storybook packages (including unscoped packages such as `storybook` and `sb`)\n       * - Npm global registry for all other packages\n       * - The best performance for both\n       *\n       * The proxy server listens on port 6001 and verdaccio on port 6002\n       *\n       * If you want to access the verdaccio UI, you can do so by visiting http://localhost:6002\n       */\n      const proxy = http.createServer((req, res) => {\n        // if request contains \"storybook\" redirect to verdaccio\n        if (req.url?.includes('storybook') || req.url?.includes('/sb') || req.method === 'PUT') {\n          res.writeHead(302, { Location: 'http://localhost:6002' + req.url });\n          res.end();\n        } else {\n          // forward to npm registry\n          res.writeHead(302, { Location: 'https://registry.npmjs.org' + req.url });\n          res.end();\n        }\n      });\n\n      let verdaccioApp: http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>;\n\n      const servers = {\n        close: async () => {\n          console.log('🛬 Closing servers running on port 6001 and 6002');\n          await Promise.all([\n            new Promise<void>((resolve) => {\n              verdaccioApp?.close(() => resolve());\n            }),\n            new Promise<void>((resolve) => {\n              proxy?.close(() => resolve());\n            }),\n          ]);\n        },\n      };\n\n      proxy.listen(6001, () => {\n        ready.proxy = true;\n        if (ready.verdaccio) {\n          resolve(servers);\n        }\n      });\n      const cache = join(__dirname, '..', '.verdaccio-cache');\n      const config = {\n        ...parseConfigFile(join(__dirname, 'verdaccio.yaml')),\n        self_path: cache,\n      };\n\n      // @ts-expect-error (verdaccio's interface is wrong)\n      runServer(config).then((app: Server) => {\n        verdaccioApp = app;\n\n        app.listen(6002, () => {\n          ready.verdaccio = true;\n          if (ready.proxy) {\n            resolve(servers);\n          }\n        });\n      });\n    }),\n    new Promise((_, rej) => {\n      setTimeout(() => {\n        if (!ready.verdaccio || !ready.proxy) {\n          rej(new Error(`TIMEOUT - verdaccio didn't start within 10s`));\n        }\n      }, 10000);\n    }),\n  ]) as Promise<Servers>;\n};\n\nconst currentVersion = async () => {\n  const content = await readFile(join(__dirname, '..', 'code', 'package.json'), 'utf-8');\n  const { version } = JSON.parse(content);\n  return version;\n};\n\nconst publish = async (packages: { name: string; location: string }[], url: string) => {\n  logger.log(`Publishing packages with a concurrency of ${maxConcurrentTasks}`);\n\n  const limit = pLimit(maxConcurrentTasks);\n  let i = 0;\n\n  /**\n   * We need to \"pack\" our packages before publishing to npm because our package.json files contain\n   * yarn specific version \"ranges\". such as \"workspace:*\"\n   *\n   * We can't publish to npm if the package.json contains these ranges. So with `yarn pack` we\n   * create a tarball that we can publish.\n   *\n   * However this bug exists in NPM: https://github.com/npm/cli/issues/4533! Which causes the NPM\n   * CLI to disregard the tarball CLI argument and instead re-create a tarball. But NPM doesn't\n   * replace the yarn version ranges.\n   *\n   * So we create the tarball ourselves and move it to another location on the FS. Then we\n   * change-directory to that directory and publish the tarball from there.\n   */\n  await mkdir(PACKS_DIRECTORY, { recursive: true }).catch(() => {});\n\n  return Promise.all(\n    packages.map(({ name, location }) =>\n      limit(\n        () =>\n          new Promise((resolve, reject) => {\n            const loggedLocation = location.replace(resolvePath(join(__dirname, '..')), '.');\n            const resolvedLocation = resolvePath('../code', location);\n\n            logger.log(`🛫 publishing ${name} (${loggedLocation})`);\n\n            const tarballFilename = `${name.replace('@', '').replace('/', '-')}.tgz`;\n            const command = `cd \"${resolvedLocation}\" && yarn pack --out=\"${PACKS_DIRECTORY}/${tarballFilename}\" && cd \"${PACKS_DIRECTORY}\" && npm publish \"./${tarballFilename}\" --registry ${url} --force --tag=\"xyz\" --ignore-scripts`;\n            exec(command, (e) => {\n              if (e) {\n                reject(e);\n              } else {\n                i += 1;\n                logger.log(`${i}/${packages.length} 🛬 successful publish of ${name}!`);\n                resolve(undefined);\n              }\n            });\n          })\n      )\n    )\n  );\n};\n\nlet servers: Servers | undefined;\n\nconst run = async () => {\n  const verdaccioUrl = `http://localhost:6001`;\n\n  logger.log(`📐 reading version of storybook`);\n  logger.log(`🚛 listing storybook packages`);\n\n  if (opts.publish) {\n    // when running e2e locally, clear cache to avoid EPUBLISHCONFLICT errors\n    const verdaccioCache = join(ROOT_DIRECTORY, '.verdaccio-cache');\n    if (await pathExists(verdaccioCache)) {\n      logger.log(`🗑 cleaning up cache`);\n      await rm(verdaccioCache, { force: true, recursive: true });\n    }\n  }\n\n  logger.log(`🎬 starting verdaccio (this takes ±5 seconds, so be patient)`);\n\n  const [_servers, packages, version] = await Promise.all([\n    startVerdaccio(),\n    getCodeWorkspaces(false),\n    currentVersion(),\n  ]);\n  servers = _servers;\n\n  logger.log(`🌿 verdaccio running on ${verdaccioUrl}`);\n\n  logger.log(`👤 add temp user to verdaccio`);\n  // Use npmAuth helper to authenticate to the local Verdaccio registry\n  // This will create a .npmrc file in the root directory\n  await npmAuth({\n    username: 'foo',\n    password: 's3cret',\n    email: 'test@test.com',\n    registry: 'http://localhost:6002',\n    outputDir: root,\n  });\n\n  logger.log(\n    `📦 found ${packages.length} storybook packages at version ${picocolors.blue(version)}`\n  );\n\n  if (opts.publish) {\n    try {\n      await publish(packages, 'http://localhost:6002');\n    } finally {\n      await rm(join(root, '.npmrc'), { force: true });\n    }\n  }\n\n  if (!opts.open) {\n    await servers?.close();\n    process.exit(0);\n  }\n};\n\nrun().catch(async (e) => {\n  try {\n    await servers?.close();\n  } finally {\n    await rm(join(root, '.npmrc'), { force: true });\n    throw e;\n  }\n});\n"
  },
  {
    "path": "scripts/sandbox/generate.ts",
    "content": "import { cp, mkdir, readdir, rename, rm, writeFile } from 'node:fs/promises';\nimport { readFile } from 'node:fs/promises';\nimport { join, relative } from 'node:path';\n\nimport * as ghActions from '@actions/core';\nimport { program } from 'commander';\n// eslint-disable-next-line depend/ban-dependencies\nimport type { Options as ExecaOptions } from 'execa';\n// eslint-disable-next-line depend/ban-dependencies\nimport { execaCommand } from 'execa';\nimport pLimit from 'p-limit';\nimport prettyTime from 'pretty-hrtime';\nimport { dedent } from 'ts-dedent';\n\nimport { PackageManagerName } from '../../code/core/src/common/js-package-manager/index.ts';\nimport { temporaryDirectory } from '../../code/core/src/common/utils/cli.ts';\nimport storybookVersions from '../../code/core/src/common/versions.ts';\nimport {\n  type Template,\n  allTemplates as sandboxTemplates,\n} from '../../code/lib/cli-storybook/src/sandbox-templates.ts';\nimport {\n  AFTER_DIR_NAME,\n  BEFORE_DIR_NAME,\n  LOCAL_REGISTRY_URL,\n  REPROS_DIRECTORY,\n  SCRIPT_TIMEOUT,\n} from '../utils/constants.ts';\nimport { esMain } from '../utils/esmain.ts';\nimport type { OptionValues } from '../utils/options.ts';\nimport { createOptions } from '../utils/options.ts';\nimport { getStackblitzUrl, renderTemplate } from './utils/template.ts';\nimport { localizeYarnConfigFiles, setupYarn } from './utils/yarn.ts';\n\nconst isCI = process.env.GITHUB_ACTIONS === 'true' || process.env.CI === 'true';\n\nclass BeforeScriptExecutionError extends Error {}\nclass StorybookInitError extends Error {}\n\nconst sbInit = async (\n  cwd: string,\n  envVars: Record<string, unknown> = {},\n  flags?: string[],\n  debug?: boolean\n) => {\n  const sbCliBinaryPath = join(__dirname, `../../code/lib/create-storybook/dist/bin/index.js`);\n  console.log(`🎁 Installing Storybook`);\n  const env = { STORYBOOK_DISABLE_TELEMETRY: 'true', ...envVars, CI: 'true' };\n  const fullFlags = ['--yes', ...(flags || [])];\n  await runCommand(`${sbCliBinaryPath} ${fullFlags.join(' ')}`, { cwd, env }, debug);\n};\n\ntype LocalRegistryProps = {\n  action: () => Promise<void>;\n  cwd: string;\n  env: Record<string, any>;\n  debug: boolean;\n};\n\nconst withLocalRegistry = async ({ action, cwd, env, debug }: LocalRegistryProps) => {\n  const prevUrl = 'https://registry.npmjs.org/';\n  let error;\n  try {\n    console.log(`📦 Configuring local registry: ${LOCAL_REGISTRY_URL}`);\n    // NOTE: for some reason yarn prefers the npm registry in\n    // local development, so always use npm\n    await runCommand(`npm config set registry ${LOCAL_REGISTRY_URL} -g`, { cwd, env }, debug);\n    await action();\n  } catch (e) {\n    error = e;\n  } finally {\n    console.log(`📦 Restoring registry: ${prevUrl}`);\n    await runCommand(`npm config set registry ${prevUrl} -g`, { cwd, env }, debug);\n\n    if (error) {\n      throw error;\n    }\n  }\n};\n\nconst emptyDir = async (dir: string): Promise<void> => {\n  await mkdir(dir, { recursive: true });\n\n  const names = await readdir(dir);\n  await Promise.all(names.map((name) => rm(join(dir, name), { recursive: true, force: true })));\n};\n\nconst addStorybook = async ({\n  localRegistry,\n  baseDir,\n  flags = [],\n  debug,\n  env = {},\n}: {\n  baseDir: string;\n  localRegistry: boolean;\n  flags?: string[];\n  debug?: boolean;\n  env?: Record<string, unknown>;\n}) => {\n  const beforeDir = join(baseDir, BEFORE_DIR_NAME);\n  const afterDir = join(baseDir, AFTER_DIR_NAME);\n\n  const tmpDir = await temporaryDirectory();\n\n  try {\n    await cp(beforeDir, tmpDir, { recursive: true });\n\n    if (localRegistry) {\n      await addResolutions(tmpDir);\n    }\n\n    await sbInit(tmpDir, env, [...flags, `--package-manager=${PackageManagerName.YARN1}`], debug);\n  } catch (e) {\n    console.log('error', e);\n    await rm(tmpDir, { recursive: true, force: true });\n    throw e;\n  }\n\n  await cp(tmpDir, afterDir, { recursive: true });\n  await rm(tmpDir, { recursive: true, force: true });\n};\n\nexport const runCommand = async (script: string, options: ExecaOptions, debug = false) => {\n  if (debug) {\n    console.log(`Running command: ${script}`);\n  }\n\n  return execaCommand(script, {\n    stdout: debug ? 'inherit' : 'ignore',\n    shell: true,\n    cleanup: true,\n    ...options,\n  });\n};\n\nconst addDocumentation = async (\n  baseDir: string,\n  { name, dirName }: { name: string; dirName: string }\n) => {\n  const afterDir = join(baseDir, AFTER_DIR_NAME);\n  const stackblitzConfigPath = join(__dirname, 'templates', '.stackblitzrc');\n  const readmePath = join(__dirname, 'templates', 'item.ejs');\n\n  await cp(stackblitzConfigPath, join(afterDir, '.stackblitzrc'));\n\n  const stackblitzUrl = getStackblitzUrl(dirName);\n  const contents = await renderTemplate(readmePath, {\n    name,\n    stackblitzUrl,\n  });\n  await writeFile(join(afterDir, 'README.md'), contents);\n};\n\nconst toFlags = (opts: Record<string, any>): string[] => {\n  const result: string[] = [];\n  for (const [key, value] of Object.entries(opts)) {\n    if (value === undefined || value === null) {\n      continue;\n    }\n    if (typeof value === 'boolean') {\n      if (value) {\n        result.push(`--${key}`);\n      }\n    } else if (Array.isArray(value)) {\n      for (const v of value) {\n        result.push(`--${key} ${String(v)}`);\n      }\n    } else if (typeof value === 'string') {\n      // Normalize ProjectType-like values to lower-case for CLI\n      const val = key === 'type' ? value.toLowerCase() : value;\n      result.push(`--${key} ${val}`);\n    } else {\n      // Fallback: stringify\n      result.push(`--${key} ${JSON.stringify(value)}`);\n    }\n  }\n  return result;\n};\n\nconst runGenerators = async (\n  generators: (Template & { dirName: string })[],\n  localRegistry = true,\n  debug = false\n) => {\n  if (debug) {\n    console.log('Debug mode enabled. Verbose logs will be printed to the console.');\n  }\n\n  console.log(`🤹‍♂️ Generating sandboxes with a concurrency of ${1}`);\n\n  const limit = pLimit(1);\n\n  const generationResults = await Promise.allSettled(\n    generators.map(({ dirName, name, script, env, initOptions }) =>\n      limit(async () => {\n        const baseDir = join(REPROS_DIRECTORY, dirName);\n        const beforeDir = join(baseDir, BEFORE_DIR_NAME);\n        let createBaseDir: string | undefined;\n\n        try {\n          let flags: string[] = ['--no-dev'];\n\n          if (initOptions && typeof initOptions === 'object') {\n            flags = [...flags, ...toFlags(initOptions as Record<string, any>)];\n          }\n\n          const time = process.hrtime();\n          console.log(`🧬 Generating ${name} (${dirName})`);\n          await emptyDir(baseDir);\n\n          // We do the creation inside a temp dir to avoid yarn container problems\n          createBaseDir = await temporaryDirectory();\n          if (!script.includes('pnp')) {\n            try {\n              await setupYarn({ cwd: createBaseDir });\n            } catch (error) {\n              const message = `❌ Failed to setup yarn in template: ${name} (${dirName})`;\n              if (isCI) {\n                ghActions.error(dedent`${message}\n                  ${(error as any).stack}`);\n              } else {\n                console.error(message);\n                console.error(error);\n              }\n              throw new Error(message);\n            }\n          }\n\n          const createBeforeDir = join(createBaseDir, BEFORE_DIR_NAME);\n\n          // Some tools refuse to run inside an existing directory and replace the contents,\n          // where as others are very picky about what directories can be called. So we need to\n          // handle different modes of operation.\n          try {\n            if (script.includes('{{beforeDir}}')) {\n              const scriptWithBeforeDir = script.replaceAll('{{beforeDir}}', BEFORE_DIR_NAME);\n              await runCommand(\n                scriptWithBeforeDir,\n                {\n                  cwd: createBaseDir,\n                  env: {\n                    ...env,\n                    CI: 'true',\n                  },\n                  timeout: SCRIPT_TIMEOUT,\n                },\n                debug\n              );\n            } else {\n              await mkdir(createBeforeDir, { recursive: true });\n              await runCommand(script, { cwd: createBeforeDir, timeout: SCRIPT_TIMEOUT }, debug);\n            }\n          } catch (error) {\n            const message = `❌ Failed to execute before-script for template: ${name} (${dirName})`;\n            if (isCI) {\n              ghActions.error(dedent`${message}\n                ${(error as any).stack}`);\n            } else {\n              console.error(message);\n              console.error(error);\n            }\n            throw new BeforeScriptExecutionError(message, { cause: error });\n          }\n\n          await localizeYarnConfigFiles(createBaseDir, createBeforeDir);\n\n          // Now move the created before dir into it's final location and add storybook\n          await rename(createBeforeDir, beforeDir);\n\n          // Make sure there are no git projects in the folder\n          await rm(join(beforeDir, '.git'), { recursive: true, force: true });\n\n          try {\n            await addStorybook({ baseDir, localRegistry, flags, debug, env });\n          } catch (error) {\n            const message = `❌ Failed to initialize Storybook in template: ${name} (${dirName})`;\n            if (isCI) {\n              ghActions.error(dedent`${message}\n                ${(error as any).stack}`);\n            } else {\n              console.error(message);\n              console.error(error);\n            }\n            throw new StorybookInitError(message, {\n              cause: error,\n            });\n          }\n\n          await addDocumentation(baseDir, { name, dirName });\n\n          console.log(\n            `✅ Generated ${name} (${dirName}) in ./${relative(\n              process.cwd(),\n              baseDir\n            )} successfully in ${prettyTime(process.hrtime(time))}`\n          );\n        } catch (error) {\n          throw error;\n        } finally {\n          // Remove node_modules to save space and avoid GH actions failing\n          // They're not uploaded to the git sandboxes repo anyway\n          if (process.env.CLEANUP_SANDBOX_NODE_MODULES) {\n            console.log(`🗑️ Removing ${join(beforeDir, 'node_modules')}`);\n            await rm(join(beforeDir, 'node_modules'), { recursive: true, force: true });\n            console.log(`🗑️ Removing ${join(baseDir, AFTER_DIR_NAME, 'node_modules')}`);\n            await rm(join(baseDir, AFTER_DIR_NAME, 'node_modules'), {\n              recursive: true,\n              force: true,\n            });\n          }\n\n          // Clean up the temporary base directory\n          if (createBaseDir) {\n            await rm(createBaseDir, { recursive: true, force: true });\n          }\n        }\n      })\n    )\n  );\n\n  const hasGenerationErrors = generationResults.some((result) => result.status === 'rejected');\n\n  if (!isCI || process.env.STORYBOOK_SANDBOX_GENERATE) {\n    if (hasGenerationErrors) {\n      console.log('failed:');\n      console.log(\n        generationResults\n          .filter((result) => result.status === 'rejected')\n          .map((_, index) => generators[index].name)\n      );\n      throw new Error(`Some sandboxes failed to generate`);\n    }\n    return;\n  }\n\n  ghActions.summary.addHeading('Sandbox generation summary');\n\n  if (!hasGenerationErrors) {\n    await ghActions.summary.addRaw('✅ Success!').write();\n    return;\n  }\n\n  await ghActions.summary\n    .addRaw('Some sandboxes failed, see the job log for detailed errors')\n    .addTable([\n      [\n        { data: 'Name', header: true },\n        { data: 'Key', header: true },\n        { data: 'Result', header: true },\n      ],\n      ...generationResults.map((result, index) => {\n        const { name, dirName } = generators[index];\n        const row = [name, `\\`${dirName}\\``];\n        if (result.status === 'fulfilled') {\n          row.push('🟢 Pass');\n          return row;\n        }\n        const generationError = (result as PromiseRejectedResult).reason as Error;\n        if (generationError instanceof BeforeScriptExecutionError) {\n          row.push('🔴 Failed to execute before script');\n        } else if (generationError instanceof StorybookInitError) {\n          row.push('🔴 Failed to initialize Storybook');\n        } else {\n          row.push('🔴 Failed with unknown error');\n        }\n        return row;\n      }),\n    ])\n    .write();\n\n  throw new Error(`Some sandboxes failed to generate`);\n};\n\nexport const options = createOptions({\n  templates: {\n    type: 'string[]',\n    description: 'Which templates would you like to create?',\n    values: Object.keys(sandboxTemplates),\n  },\n  exclude: {\n    type: 'string[]',\n    description: 'Space-delimited list of templates to exclude. Takes precedence over --templates',\n    promptType: false,\n  },\n  localRegistry: {\n    type: 'boolean',\n    description: 'Generate reproduction from local registry?',\n    promptType: false,\n  },\n  debug: {\n    type: 'boolean',\n    description: 'Print all the logs to the console',\n    promptType: false,\n  },\n});\n\nexport const generate = async ({\n  templates,\n  exclude,\n  localRegistry,\n  debug,\n}: OptionValues<typeof options>) => {\n  const generatorConfigs = Object.entries(sandboxTemplates)\n    .map(([dirName, configuration]) => ({\n      dirName,\n      ...configuration,\n    }))\n    .filter(({ dirName }) => {\n      let include = Array.isArray(templates) ? templates.includes(dirName) : true;\n      if (Array.isArray(exclude) && include) {\n        include = !exclude.includes(dirName);\n      }\n      return include;\n    });\n\n  await runGenerators(generatorConfigs, localRegistry, debug);\n};\n\nasync function addResolutions(beforeDir: string) {\n  const packageJson = await readFile(join(beforeDir, 'package.json'), 'utf-8').then((c) =>\n    JSON.parse(c)\n  );\n\n  packageJson.resolutions = {\n    ...storybookVersions,\n  };\n\n  await writeFile(join(beforeDir, 'package.json'), JSON.stringify(packageJson, null, 2));\n}\n\nif (esMain(import.meta.url)) {\n  program\n    .description('Generate sandboxes from a set of possible templates')\n    .option('--templates [templates...]', 'Space-delimited list of templates to include')\n    .option(\n      '--exclude [templates...]',\n      'Space-delimited list of templates to exclude. Takes precedence over --templates'\n    )\n    .option('--debug', 'Print all the logs to the console')\n    .option('--local-registry', 'Use local registry', false)\n    .action((optionValues) => {\n      let result;\n      if (optionValues.localRegistry) {\n        result = withLocalRegistry({\n          debug: optionValues.debug,\n\n          action: async () => {\n            await generate(optionValues);\n          },\n          cwd: process.cwd(),\n          env: {},\n        });\n      } else {\n        result = generate(optionValues);\n      }\n\n      result\n        .catch((e) => {\n          console.error(e);\n          process.exit(1);\n        })\n        .then(() => {\n          // FIXME: Kill dangling processes. For some reason in CI,\n          // the abort signal gets executed but the child process kill\n          // does not succeed?!?\n          process.exit(0);\n        });\n    })\n    .parse(process.argv);\n}\n"
  },
  {
    "path": "scripts/sandbox/publish.ts",
    "content": "import { cp, mkdir, readdir, rm, writeFile } from 'node:fs/promises';\n\nimport { program } from 'commander';\n// eslint-disable-next-line depend/ban-dependencies\nimport { execaCommand } from 'execa';\nimport { existsSync } from 'fs';\n// eslint-disable-next-line depend/ban-dependencies\nimport { glob } from 'glob';\nimport { dirname, join, relative } from 'path';\n\nimport { temporaryDirectory } from '../../code/core/src/common/utils/cli.ts';\nimport { REPROS_DIRECTORY } from '../utils/constants.ts';\nimport { commitAllToGit } from './utils/git.ts';\nimport { getTemplatesData, renderTemplate } from './utils/template.ts';\n\nexport const logger = console;\n\nconst emptyDir = async (dir: string): Promise<void> => {\n  await mkdir(dir, { recursive: true });\n\n  const names = await readdir(dir);\n  await Promise.all(names.map((name) => rm(join(dir, name), { recursive: true, force: true })));\n};\n\ninterface PublishOptions {\n  remote?: string;\n  push?: boolean;\n  branch?: string;\n}\n\nconst publish = async (options: PublishOptions & { tmpFolder: string }) => {\n  const { branch: inputBranch, remote, push, tmpFolder } = options;\n\n  const scriptPath = __dirname;\n  const branch = inputBranch || 'next';\n  const templatesData = await getTemplatesData(branch === 'main' ? 'main' : 'next');\n\n  logger.log(`👯‍♂️ Cloning the repository ${remote} in branch ${branch}`);\n  await execaCommand(`git clone ${remote} .`, { cwd: tmpFolder, cleanup: true });\n  await execaCommand(`git checkout ${branch}`, { cwd: tmpFolder, cleanup: true });\n\n  // otherwise old files will stick around and result inconsistent states\n  logger.log(`🗑 Delete existing template dirs from clone`);\n\n  // empty all existing directories for sandboxes that have a successful after-storybook directory\n  await Promise.all(\n    // find all successfully generated after-storybook/README.md files\n    // eg. /home/repros/react-vite/default-ts/after-storybook/README.md\n    // README.md being the last file generated, thus representing a successful generation\n    (await glob(join(REPROS_DIRECTORY, '**', 'after-storybook/README.md'))).map((readmePath) => {\n      // get the after-storybook path relative to the source 'repros' directory\n      // eg. ./react-vite/default-ts/after-storybook\n      const pathRelativeToSource = relative(REPROS_DIRECTORY, dirname(readmePath));\n      // get the actual path to the corresponding sandbox directory in the clone\n      // eg. /home/sandboxes-clone/react-vite/default-ts\n      const sandboxDirectoryToEmpty = join(tmpFolder, pathRelativeToSource, '..');\n      return emptyDir(sandboxDirectoryToEmpty);\n    })\n  );\n\n  logger.log(`🚚 Moving template files into the repository`);\n\n  const templatePath = join(scriptPath, 'templates', 'root.ejs');\n  const templateData = { data: templatesData, version: branch === 'main' ? 'latest' : 'next' };\n\n  const output = await renderTemplate(templatePath, templateData);\n\n  await writeFile(join(tmpFolder, 'README.md'), output);\n\n  logger.log(`🚛 Moving all the repros into the repository`);\n  await cp(REPROS_DIRECTORY, tmpFolder, { recursive: true });\n\n  await commitAllToGit({ cwd: tmpFolder, branch });\n\n  logger.info(`\n     🙌 All the examples were bootstrapped:\n        - in ${tmpFolder}\n        - using the '${branch}' version of Storybook CLI\n        - and committed on the '${branch}' branch of a local Git repository\n\n     Also all the files in the 'templates' folder were copied at the root of the Git repository.\n    `);\n\n  if (push) {\n    await execaCommand(`git push --set-upstream origin ${branch}`, {\n      cwd: tmpFolder,\n    });\n    const remoteRepoUrl = `${remote.replace('.git', '')}/tree/${branch}`;\n    logger.info(`🚀 Everything was pushed on ${remoteRepoUrl}`);\n  } else {\n    logger.info(`\n       To publish these examples you just need to:\n          - push the branch: 'git push --set-upstream origin ${branch}\n      `);\n  }\n};\n\nprogram\n  .description('Create a sandbox from a set of possible templates')\n  .option('--remote <remote>', 'Choose the remote to push the contents to')\n  .option('--branch <branch>', 'Choose which branch on the remote')\n  .option('--push', 'Whether to push the contents to the remote', false)\n  .option('--force-push', 'Whether to force push the changes into the repros repository', false);\n\nprogram.parse(process.argv);\n\nif (!existsSync(REPROS_DIRECTORY)) {\n  throw Error(\"Couldn't find sandbox directory. Did you forget to run generate-sandboxes?\");\n}\n\nasync function main() {\n  const tmpFolder = await temporaryDirectory();\n  logger.log(`⏱ Created tmp folder: ${tmpFolder}`);\n\n  const options = program.opts() as PublishOptions;\n\n  publish({ ...options, tmpFolder }).catch(async (e) => {\n    logger.error(e);\n\n    if (existsSync(tmpFolder)) {\n      logger.log('🚮 Removing the temporary folder..');\n      await rm(tmpFolder, { force: true, recursive: true });\n    }\n    process.exit(1);\n  });\n}\n\nmain();\n"
  },
  {
    "path": "scripts/sandbox/templates/.stackblitzrc",
    "content": "{\n  \"installDependencies\": true,\n  \"startCommand\": \"yarn storybook\"\n}"
  },
  {
    "path": "scripts/sandbox/templates/item.ejs",
    "content": "<h1>\n  <%= name %>\n</h1>\n\n<p>This is project generated to serve as a reproduction starter for Storybook.</p>\n\n<a href=\"<%= stackblitzUrl %>\">\n  View it in Stackblitz\n</a>\n\n<h3>Testing instructions</h3>\n\n<p>Install dependencies:</p>\n<pre>\n  yarn\n</pre>\n\n<p>Run Storybook:</p>\n<pre>\n  yarn storybook\n</pre>"
  },
  {
    "path": "scripts/sandbox/templates/root.ejs",
    "content": "<h1>Storybook Reproduction Templates</h1>\n\n<img alt=\"Storybook <%= version %> Badge\" src=\"https://img.shields.io/npm/v/@storybook/react/<%= version %>\" />\n\n<p>The following repros have been generated with the `<%= version %>` version of Storybook.</p>\n\n<% if (typeof data !== 'undefined' && Object.keys(data).length) { %>\n  <p>Preview any repro live on <a href=\"http://stackblitz.com/\">StackBlitz:</a></p>\n  <% for (var groupName in data) { %>\n    <% if (data[groupName] !== undefined) { %>\n      <details>\n        <summary><b><%- (groupName) %></b></summary>\n        <ul>\n        <% for (var exampleName in data[groupName]) { %>\n          <% if (data[groupName][exampleName] !== undefined) { %>\n            <li>\n              <a href=\"<%=data[groupName][exampleName]['stackblitzUrl']%>\">\n                <%=data[groupName][exampleName]['name']%>\n              </a>\n            </li>\n          <% } %>\n        <% } %>\n        </ul>\n      </details>\n    <% } %>\n  <% } %>\n<% } %>\n"
  },
  {
    "path": "scripts/sandbox/utils/getPort.ts",
    "content": "import { allTemplates } from '../../../code/lib/cli-storybook/src/sandbox-templates.ts';\nimport { type TemplateDetails, tasks } from '../../task.ts';\n\nexport function getPort(template: Pick<TemplateDetails, 'key' | 'selectedTask'>) {\n  const templateIndex = Object.values(allTemplates).indexOf(allTemplates[template.key]);\n  const taskIndex = Object.values(tasks).indexOf(tasks[template.selectedTask]);\n\n  if (templateIndex === -1 || taskIndex === -1) {\n    throw new Error(`Template ${template.key} or task ${template.selectedTask} not found`);\n  }\n\n  return 3000 + templateIndex * 100 + taskIndex;\n}\n"
  },
  {
    "path": "scripts/sandbox/utils/git.ts",
    "content": "// eslint-disable-next-line depend/ban-dependencies\nimport { execaCommand } from 'execa';\nimport invariant from 'tiny-invariant';\n\nimport { version as storybookVersion } from '../../../code/package.json';\nimport { logger } from '../publish.ts';\n\nconst getTheLastCommitHashThatUpdatedTheSandboxRepo = async (branch: string) => {\n  const owner = 'storybookjs';\n  const repo = 'sandboxes';\n\n  try {\n    const branchData: any = await (\n      await fetch(`https://api.github.com/repos/${owner}/${repo}/branches/${branch}`)\n    ).json();\n    const latestCommitSha = branchData.commit.sha;\n    const commitData: any = await (\n      await fetch(`https://api.github.com/repos/${owner}/${repo}/commits/${latestCommitSha}`)\n    ).json();\n    const latestCommitMessage = commitData.commit.message;\n\n    // The commit message will look like this: 7.0.5 - Thu Apr 13 2023 - 97dbc82537c3\n    // the hash at the end relates to the monorepo commit that updated the sandboxes\n    const lastCommitHash = latestCommitMessage.split('\\n')[0].split(' - ')[2];\n    if (!lastCommitHash) {\n      throw new Error(\n        `Could not find the last commit hash in the following commit message: \"${latestCommitMessage}\".\\nDid someone manually push to the sandboxes repo?`\n      );\n    }\n    return lastCommitHash;\n  } catch (error) {\n    invariant(error instanceof Error);\n    if (!error.message.includes('Did someone manually push to the sandboxes repo')) {\n      logger.error(\n        `⚠️  Error getting latest commit message of ${owner}/${repo} on branch ${branch}: ${error.message}`\n      );\n    }\n\n    throw error;\n  }\n};\n\n/**\n * When committing the changes to the sandboxes repo, we want to include the PRs that were merged\n * since the last commit that updated the sandboxes. This might help us debug issues or changes that\n * affected the sandboxes at some point in time.\n */\nexport async function commitAllToGit({ cwd, branch }: { cwd: string; branch: string }) {\n  try {\n    logger.log(`💪 Committing everything to the repository`);\n\n    await execaCommand('git add .', { cwd, cleanup: true });\n\n    const currentCommitHash = (await execaCommand('git rev-parse HEAD', { cleanup: true })).stdout\n      .toString()\n      .slice(0, 12);\n\n    let gitCommitCommand;\n\n    logger.log('🔍 Determining commit message');\n    try {\n      const previousCommitHash = await getTheLastCommitHashThatUpdatedTheSandboxRepo(branch);\n      const mergeCommits = (\n        await execaCommand(\n          `git log ${previousCommitHash}..${currentCommitHash} --merges --pretty=%s`,\n          { cleanup: true }\n        )\n      ).stdout\n        .toString()\n        .split('\\n')\n        .filter((s: string) => s.includes('pull request'));\n\n      const prLinks = mergeCommits.map((mergeCommit) => {\n        const prNumber = mergeCommit.match(/Merge pull request #(\\d+)/)[1];\n        const branchName = mergeCommit.match(/from (.+)/)[1].replace('storybookjs/', '');\n        return `- https://github.com/storybookjs/storybook/pull/${prNumber} (${branchName})`;\n      });\n\n      const diffLink = `https://github.com/storybookjs/storybook/compare/${previousCommitHash}...${currentCommitHash}`;\n\n      const commitTitle = `${storybookVersion} - ${new Date().toDateString()} - ${previousCommitHash}`;\n      const commitBody = [\n        `\\nCheck the diff here: ${diffLink}`,\n        '\\nList of included PRs since previous version:',\n        ...prLinks,\n      ].join('\\n');\n      gitCommitCommand = `git commit -m \"${commitTitle}\" -m \"${commitBody}\"`;\n    } catch (err) {\n      invariant(err instanceof Error);\n      logger.log(\n        `⚠️  Falling back to a simpler commit message because of an error while trying to get the previous commit hash: ${err.message}`\n      );\n      gitCommitCommand = `git commit -m \"${storybookVersion} - ${new Date().toDateString()} - ${currentCommitHash}\"`;\n    }\n\n    await execaCommand(gitCommitCommand, {\n      shell: true,\n      cleanup: true,\n      cwd,\n    });\n  } catch (e) {\n    invariant(e instanceof Error);\n    if (e.message.includes('nothing to commit')) {\n      logger.log(\n        `🤷 Git found no changes between previous versions so there is nothing to commit. Skipping publish!`\n      );\n    } else {\n      logger.error(`🤯 Something went wrong while committing to git: ${e.message}`);\n    }\n  }\n}\n"
  },
  {
    "path": "scripts/sandbox/utils/template.ts",
    "content": "import { readFile } from 'node:fs/promises';\n\nimport { render } from 'ejs';\nimport prettier from 'prettier';\n\nimport { allTemplates as sandboxTemplates } from '../../../code/lib/cli-storybook/src/sandbox-templates.ts';\nimport type { GeneratorConfig } from './types.ts';\n\nexport async function renderTemplate(templatePath: string, templateData: Record<string, any>) {\n  const template = await readFile(templatePath, 'utf8');\n\n  const output = (\n    await prettier.format(render(template, templateData), {\n      parser: 'html',\n    })\n  )\n    // overly complicated regex replacements to fix prettier's bad formatting\n    .replace(new RegExp('</li>\\\\n\\\\n', 'g'), '</li>\\n')\n    .replace(new RegExp('<a\\\\n', 'g'), '<a')\n    .replace(new RegExp('node\"\\\\n>', 'g'), 'node=\">')\n    .replace(new RegExp('/\\\\n</a>/', 'g'), '</a>');\n  return output;\n}\n\nexport const getStackblitzUrl = (path: string, branch = 'next') => {\n  return `https://stackblitz.com/github/storybookjs/sandboxes/tree/${branch}/${path}/after-storybook?preset=node`;\n};\n\nexport async function getTemplatesData(branch: string) {\n  type TemplatesData = Record<\n    string,\n    Record<\n      string,\n      GeneratorConfig & {\n        stackblitzUrl: string;\n      }\n    >\n  >;\n\n  const templatesData = Object.keys(sandboxTemplates).reduce<TemplatesData>((acc, curr) => {\n    const [dirName, templateName] = curr.split('/');\n    const groupName =\n      dirName === 'cra' ? 'CRA' : dirName.slice(0, 1).toUpperCase() + dirName.slice(1);\n    const generatorData = sandboxTemplates[curr as keyof typeof sandboxTemplates];\n    acc[groupName] = acc[groupName] || {};\n    acc[groupName][templateName] = {\n      ...generatorData,\n      stackblitzUrl: getStackblitzUrl(curr, branch),\n    };\n    return acc;\n  }, {});\n  return templatesData;\n}\n"
  },
  {
    "path": "scripts/sandbox/utils/types.ts",
    "content": "export type GeneratorConfig = {\n  name: string;\n  script: string;\n  expected: {\n    framework: string;\n    renderer: string;\n    builder: string;\n  };\n  env?: Record<string, unknown>;\n};\n"
  },
  {
    "path": "scripts/sandbox/utils/yarn.ts",
    "content": "import { rename, rm, writeFile } from 'node:fs/promises';\n\nimport { join } from 'path';\n\nimport { runCommand } from '../generate.ts';\n\ninterface SetupYarnOptions {\n  cwd: string;\n  // TODO: Evaluate if this is correct after removing pnp compatibility code in SB11\n  pnp?: boolean;\n  version?: 'berry' | 'classic';\n}\n\nexport async function setupYarn({ cwd, pnp = false, version = 'classic' }: SetupYarnOptions) {\n  // force yarn\n  await writeFile(join(cwd, 'yarn.lock'), '', { flag: 'a' });\n  await runCommand(`yarn set version ${version}`, { cwd });\n  if (version === 'berry' && !pnp) {\n    await runCommand('yarn config set nodeLinker node-modules', { cwd });\n  }\n  await rm(join(cwd, 'package.json'), { force: true });\n}\n\nexport async function localizeYarnConfigFiles(baseDir: string, beforeDir: string) {\n  await Promise.allSettled([\n    writeFile(join(beforeDir, 'yarn.lock'), '', { flag: 'a' }),\n    rename(join(baseDir, '.yarn'), join(beforeDir, '.yarn')),\n    rename(join(baseDir, '.yarnrc.yml'), join(beforeDir, '.yarnrc.yml')),\n    rename(join(baseDir, '.yarnrc'), join(beforeDir, '.yarnrc')),\n  ]);\n}\n"
  },
  {
    "path": "scripts/snippets/codemod.ts",
    "content": "/**\n * DISCLAIMER:\n *\n * This file exists with the sole purpose of assisting the documentation snippets during\n * introduction of new features. This will probably used only once or twice, but it's REALLY useful\n * to test codemods as it helps detect many bugs very quickly. It also will be used once we decide\n * to add extra snippets to more renderers.\n */\nimport os from 'node:os';\nimport { join } from 'node:path';\n\nimport { program } from 'commander';\nimport { promises as fs } from 'fs';\nimport pLimit from 'p-limit';\nimport picocolors from 'picocolors';\nimport prompts from 'prompts';\n// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\n\nimport { configToCsfFactory } from '../../code/lib/cli-storybook/src/codemod/helpers/config-to-csf-factory.ts';\nimport { storyToCsfFactory } from '../../code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.ts';\nimport { SNIPPETS_DIRECTORY } from '../utils/constants.ts';\n\nconst logger = console;\n\nexport const maxConcurrentTasks = Math.max(1, os.cpus().length - 1);\n\ntype SnippetInfo = {\n  path: string;\n  source: string;\n  attributes: {\n    filename: string;\n    language: string;\n    renderer: string;\n    tabTitle: string;\n    highlightSyntax: string;\n    [key: string]: string;\n  };\n};\n\ntype Codemod = {\n  getTargetSnippet: (snippetInfo: SnippetInfo) => boolean;\n  check: (snippetInfo: SnippetInfo, filePath: string) => boolean;\n  transform: (snippetInfo: SnippetInfo) => string | Promise<string>;\n};\n\nconst previousTabTitle = 'CSF 3';\nconst newTabTitle = 'CSF Next 🧪';\n\nexport async function runSnippetCodemod({\n  glob,\n  check,\n  getTargetSnippet,\n  transform,\n  dryRun = false,\n  promptUser = false,\n}: {\n  glob: string;\n  check: Codemod['check'];\n  getTargetSnippet: Codemod['getTargetSnippet'];\n  transform: Codemod['transform'];\n  dryRun?: boolean;\n  promptUser?: boolean;\n}) {\n  let modifiedCount = 0;\n  let unmodifiedCount = 0;\n  let errorCount = 0;\n  let skippedCount = 0;\n\n  try {\n    // Dynamically import these packages because they are pure ESM modules\n    // eslint-disable-next-line depend/ban-dependencies\n    const { globby } = await import('globby');\n\n    const files = await globby(slash(glob), {\n      followSymbolicLinks: true,\n      ignore: ['node_modules/**', 'dist/**', 'storybook-static/**', 'build/**'],\n    });\n\n    if (!files.length) {\n      logger.error(`No files found for pattern ${glob}`);\n      return;\n    }\n\n    const limit = pLimit(10);\n\n    for (const file of files) {\n      await limit(async () => {\n        try {\n          let source = await fs.readFile(file, 'utf-8');\n          const originalSource = source;\n          const snippets = extractSnippets(source).filter((snip) => check(snip, file));\n\n          if (snippets.length === 0) {\n            unmodifiedCount++;\n            return;\n          }\n\n          const targetSnippet = snippets.find(getTargetSnippet);\n          if (!targetSnippet) {\n            skippedCount++;\n            return;\n          }\n\n          if (promptUser) {\n            logger.log(`\\nFile: ${picocolors.yellow(file)}`);\n            const response = await prompts(\n              {\n                type: 'confirm',\n                name: 'apply',\n                message: `Apply codemod?`,\n                initial: true,\n              },\n              {\n                onCancel: () => process.exit(0),\n              }\n            );\n\n            if (!response.apply) {\n              skippedCount++;\n              return;\n            }\n          }\n\n          const counterpartSnippets = snippets.filter((snippet) => {\n            return (\n              snippet !== targetSnippet &&\n              snippet.attributes.tabTitle !== previousTabTitle &&\n              snippet.attributes.tabTitle !== newTabTitle &&\n              snippet.attributes.renderer === targetSnippet.attributes.renderer &&\n              snippet.attributes.language !== targetSnippet.attributes.language\n            );\n          });\n\n          const getSource = (snippet: SnippetInfo) =>\n            `\\n\\`\\`\\`${formatAttributes(snippet.attributes)}\\n${snippet.source}\\n\\`\\`\\`\\n`;\n\n          const updateTabTitle = (snippet: SnippetInfo, newTitle: string) => {\n            return snippet.attributes.tabTitle === newTitle\n              ? newTitle\n              : snippet.attributes.tabTitle\n                ? `${snippet.attributes.tabTitle} (${newTitle})`\n                : newTitle;\n          };\n\n          const allSnippets = [targetSnippet, ...counterpartSnippets];\n\n          let lastModifiedSnippet = '';\n          // clone the snippets and apply codemod, then append them to the bottom\n          try {\n            let appendedContent = '';\n\n            if (!dryRun) {\n              // replace attributes of the original snippets with CSF 3\n              await allSnippets.forEach(async (snippet) => {\n                // warn us if there is already a tab title\n                source = source.replace(\n                  formatAttributes(snippet.attributes),\n                  formatAttributes({\n                    ...snippet.attributes,\n                    tabTitle: updateTabTitle(snippet, previousTabTitle),\n                  })\n                );\n                await fs.writeFile(file, source, 'utf-8');\n              });\n            }\n\n            for (const snippet of allSnippets) {\n              // warn us if there is already a tab title\n              if (snippet !== targetSnippet) {\n                appendedContent +=\n                  '\\n<!-- JS snippets still needed while providing both CSF 3 & Next -->\\n';\n              }\n\n              const newSnippet = { ...snippet };\n              lastModifiedSnippet = formatAttributes(newSnippet.attributes);\n              let transformedSource = getSource({\n                ...newSnippet,\n                attributes: {\n                  ...newSnippet.attributes,\n                  renderer: 'react',\n                  tabTitle: updateTabTitle(newSnippet, newTabTitle),\n                },\n                source: await transform(newSnippet),\n              });\n\n              if (newSnippet.path.includes('.stories')) {\n                transformedSource = transformedSource\n                  .replace(/\\/\\/ Replace your-framework with .*\\n/, '')\n                  .replace(/\\* Replace your-framework with .*\\n/, '')\n                  .replace(\n                    /(import preview from \\\"#\\.storybook\\/preview\\\";)/g,\n                    `import preview from '../.storybook/preview';`\n                  );\n              } else {\n                transformedSource = transformedSource\n                  .replace(\n                    /Replace your-framework with .*\\n/,\n                    'Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\\n'\n                  )\n                  .replace(\n                    /(import { define(Main|Preview) .*)\\n/,\n                    '// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)\\n$1\\n'\n                  );\n              }\n              appendedContent += transformedSource;\n            }\n\n            const updatedSource = source + appendedContent;\n\n            if (!dryRun) {\n              await fs.writeFile(file, updatedSource, 'utf-8');\n            } else {\n              logger.log(\n                `Dry run: would have modified ${picocolors.yellow(file)} with new snippets \\n` +\n                  picocolors.green(appendedContent)\n              );\n            }\n\n            modifiedCount++;\n          } catch (transformError) {\n            logger.error(\n              `\\nError transforming snippet in file ${picocolors.yellow(file)}:`,\n              '\\n',\n              picocolors.green(lastModifiedSnippet),\n              '\\n',\n              picocolors.red((transformError as any).message)\n            );\n            errorCount++;\n            await fs.writeFile(file, originalSource, 'utf-8');\n          }\n        } catch (fileError) {\n          logger.error(`Error processing file ${file}:`, fileError);\n          errorCount++;\n        }\n      });\n    }\n  } catch (error) {\n    logger.error('Error applying snippet transform:', error);\n    errorCount++;\n  }\n\n  logger.log(\n    `Summary: ${picocolors.green(`${modifiedCount} files modified`)}, ${picocolors.yellow(`${unmodifiedCount} files unmodified`)}, ${picocolors.gray(`${skippedCount} skipped`)}, ${picocolors.red(`${errorCount} errors`)}`\n  );\n}\n\nexport function extractSnippets(source: string): SnippetInfo[] {\n  const snippetRegex =\n    /```(?<highlightSyntax>[a-zA-Z0-9]+)?(?<attributes>[^\\n]*)\\n(?<content>[\\s\\S]*?)```/g;\n  const snippets: SnippetInfo[] = [];\n  let match;\n\n  while ((match = snippetRegex.exec(source)) !== null) {\n    const { highlightSyntax, attributes, content } = match.groups || {};\n    const snippetAttributes = parseAttributes(attributes || '');\n    if (highlightSyntax) {\n      snippetAttributes.highlightSyntax = highlightSyntax.trim();\n    }\n\n    snippets.push({\n      path: snippetAttributes.filename || '',\n      source: content.trim(),\n      attributes: snippetAttributes,\n    });\n  }\n\n  return snippets;\n}\n\nexport function parseAttributes(attributes: string) {\n  const attributeRegex = /([a-zA-Z0-9.-]+)=\"([^\"]+)\"/g;\n  const result: Record<string, string> = {};\n  let match;\n\n  while ((match = attributeRegex.exec(attributes)) !== null) {\n    result[match[1]] = match[2];\n  }\n\n  return result as SnippetInfo['attributes'];\n}\n\nfunction formatAttributes(attributes: Record<string, string>): string {\n  const formatted = Object.entries(attributes)\n    .filter(([key]) => key !== 'highlightSyntax')\n    .map(([key, value]) => `${key}=\"${value}\"`)\n    .join(' ');\n  return `${attributes.highlightSyntax || 'js'} ${formatted}`;\n}\n\nconst codemods: Record<string, Codemod> = {\n  'csf-factory-story': {\n    check: (snippetInfo: SnippetInfo, filePath: string) => {\n      return (\n        snippetInfo.path.includes('.stories') &&\n        !snippetInfo.attributes?.filename?.includes('CSF 2') &&\n        !filePath.split('/')?.pop()?.startsWith('csf-3') &&\n        snippetInfo.attributes.highlightSyntax !== 'mdx' &&\n        snippetInfo.attributes.tabTitle !== previousTabTitle &&\n        snippetInfo.attributes.tabTitle !== newTabTitle\n      );\n    },\n    getTargetSnippet: (snippetInfo: SnippetInfo) => {\n      return (\n        snippetInfo.attributes.language === 'ts' &&\n        snippetInfo.attributes.tabTitle !== previousTabTitle &&\n        snippetInfo.attributes.tabTitle !== newTabTitle &&\n        (snippetInfo.attributes.renderer === 'react' ||\n          snippetInfo.attributes.renderer === 'common')\n      );\n    },\n    transform: (snippetInfo: SnippetInfo) => {\n      return storyToCsfFactory(snippetInfo, {\n        previewConfigPath: undefined,\n        useSubPathImports: true,\n      });\n    },\n  },\n  'csf-factory-config': {\n    check: (snippetInfo: SnippetInfo) => {\n      return (\n        snippetInfo.attributes.tabTitle !== previousTabTitle &&\n        snippetInfo.attributes.tabTitle !== newTabTitle &&\n        (snippetInfo.path.includes('/preview.') || snippetInfo.path.includes('/main.'))\n      );\n    },\n    getTargetSnippet: (snippetInfo: SnippetInfo) => {\n      return (\n        snippetInfo.attributes.language === 'ts' &&\n        snippetInfo.attributes.tabTitle !== previousTabTitle &&\n        snippetInfo.attributes.tabTitle !== newTabTitle &&\n        (snippetInfo.attributes.renderer === 'react' ||\n          snippetInfo.attributes.renderer === 'common')\n      );\n    },\n    transform: (snippetInfo: SnippetInfo) => {\n      const configType = snippetInfo.path.includes('preview') ? 'preview' : 'main';\n      return configToCsfFactory(snippetInfo, {\n        configType,\n        frameworkPackage: '@storybook/your-framework',\n      });\n    },\n  },\n};\n\nprogram\n  .name('command')\n  .description('A minimal CLI for demonstration')\n  .argument('<id>', 'ID to process')\n  .requiredOption('--glob <pattern>', 'Glob pattern to match')\n  .option('--dry-run', 'Run without making actual changes', false)\n  .option('--prompt', 'Prompt before applying changes', false)\n  .action(async (id, { glob, dryRun, prompt }) => {\n    const codemod = codemods[id as keyof typeof codemods];\n    if (!codemod) {\n      logger.error(`Unknown codemod \"${id}\"`);\n      logger.log(\n        `\\n\\nAvailable codemods: ${Object.keys(codemods)\n          .map((c) => `\\n- ${c}`)\n          .join('')}`\n      );\n      process.exit(1);\n    }\n\n    await runSnippetCodemod({\n      glob: join(SNIPPETS_DIRECTORY, glob),\n      dryRun,\n      promptUser: prompt,\n      ...codemod,\n    });\n  });\n\n// Parse and validate arguments\nprogram.parse(process.argv);\n"
  },
  {
    "path": "scripts/strict-ts.ts",
    "content": "import { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport glob from 'fast-glob';\nimport JSON5 from 'json5';\n\nconst files = glob.sync('**/*/tsconfig.json', {\n  absolute: true,\n  cwd: '..',\n});\n\n(async function main() {\n  const packages = files\n    .filter((file) => !file.includes('node_modules') && !file.includes('dist'))\n    .map((file) => {\n      const packageJson = join(dirname(file), 'package.json');\n      let packageName;\n      if (existsSync(packageJson)) {\n        const json = readFileSync(packageJson, { encoding: 'utf-8' });\n        packageName = JSON5.parse(json).name;\n      }\n\n      let strict;\n      if (existsSync(file)) {\n        const tsconfig = readFileSync(file, { encoding: 'utf-8' });\n        const tsconfigJson = JSON5.parse(tsconfig);\n        strict = tsconfigJson?.compilerOptions?.strict ?? false;\n      }\n\n      if (packageName && strict === false) {\n        return packageName;\n      }\n      return null;\n    })\n    .filter(Boolean)\n    .sort();\n\n  console.log(packages.join('\\n'));\n  console.log(packages.length);\n\n  // console.log(files.filter((file) => !file.includes('node_modules') && !file.includes('dist')));\n})();\n"
  },
  {
    "path": "scripts/task.ts",
    "content": "import { access, mkdir, readFile, writeFile } from 'node:fs/promises';\n\nimport type { TestCase } from 'junit-xml';\nimport { getJunitXml } from 'junit-xml';\nimport { dirname, join, resolve } from 'path';\nimport picocolors from 'picocolors';\nimport { prompt } from 'prompts';\nimport invariant from 'tiny-invariant';\nimport { dedent } from 'ts-dedent';\n\nimport {\n  allTemplates as TEMPLATES,\n  type Template,\n  type TemplateKey,\n} from '../code/lib/cli-storybook/src/sandbox-templates.ts';\nimport { version } from '../code/package.json';\nimport { bench } from './tasks/bench.ts';\nimport { build } from './tasks/build.ts';\nimport { check } from './tasks/check.ts';\nimport { checkSandbox } from './tasks/check-sandbox.ts';\nimport { chromatic } from './tasks/chromatic.ts';\nimport { compile } from './tasks/compile.ts';\nimport { dev } from './tasks/dev.ts';\nimport { e2eTestsBuild } from './tasks/e2e-tests-build.ts';\nimport { e2eTestsDev } from './tasks/e2e-tests-dev.ts';\nimport { generate } from './tasks/generate.ts';\nimport { install } from './tasks/install.ts';\nimport { publish } from './tasks/publish.ts';\nimport { runRegistryTask } from './tasks/run-registry.ts';\nimport { sandbox } from './tasks/sandbox.ts';\nimport { serve } from './tasks/serve.ts';\nimport { smokeTest } from './tasks/smoke-test.ts';\nimport { syncDocs } from './tasks/sync-docs.ts';\nimport { testRunnerBuild } from './tasks/test-runner-build.ts';\nimport { testRunnerDev } from './tasks/test-runner-dev.ts';\nimport { vitestTests } from './tasks/vitest-test.ts';\nimport { CODE_DIRECTORY, JUNIT_DIRECTORY, SANDBOX_DIRECTORY } from './utils/constants.ts';\nimport { findMostMatchText } from './utils/diff.ts';\nimport type { OptionValues } from './utils/options.ts';\nimport { createOptions, getCommand, getOptionsOrPrompt } from './utils/options.ts';\n\nexport const extraAddons = ['@storybook/addon-a11y'];\n\nexport type Path = string;\nexport type TemplateDetails = {\n  key: TemplateKey;\n  selectedTask: TaskKey;\n  template: Template;\n  codeDir: Path;\n  sandboxDir: Path;\n  builtSandboxDir: Path;\n  junitFilename: Path;\n};\n\ntype MaybePromise<T> = T | Promise<T>;\n\nexport type Task = {\n  /** A description of the task for a prompt */\n  description: string;\n  /**\n   * Does this task represent a service for another task?\n   *\n   * Unlink other tasks, if a service is not ready, it doesn't mean the subsequent tasks must be out\n   * of date. As such, services will never be reset back to, although they will be started if\n   * dependent tasks are.\n   */\n  service?: boolean;\n  /** Which tasks must be ready before this task can run */\n  dependsOn?: TaskKey[] | ((details: TemplateDetails, options: PassedOptionValues) => TaskKey[]);\n  /** Is this task already \"ready\", and potentially not required? */\n  ready: (details: TemplateDetails, options?: PassedOptionValues) => MaybePromise<boolean>;\n  /** Run the task */\n  run: (\n    details: TemplateDetails,\n    options: PassedOptionValues\n  ) => MaybePromise<void | AbortController>;\n  /** Does this task handle its own junit results? */\n  junit?: boolean;\n};\n\nexport const tasks = {\n  // These tasks pertain to the whole monorepo, rather than an\n  // individual template/sandbox\n  install,\n  compile,\n  check,\n  publish,\n  'sync-docs': syncDocs,\n  'run-registry': runRegistryTask,\n  // These tasks pertain to a single sandbox in the ../sandboxes dir\n  generate,\n  sandbox,\n  'check-sandbox': checkSandbox,\n  dev,\n  'smoke-test': smokeTest,\n  build,\n  serve,\n  'test-runner': testRunnerBuild,\n  'test-runner-dev': testRunnerDev,\n  chromatic,\n  'e2e-tests': e2eTestsBuild,\n  'e2e-tests-dev': e2eTestsDev,\n  bench,\n  'vitest-integration': vitestTests,\n};\nexport type TaskKey = keyof typeof tasks;\n\nfunction isSandboxTask(taskKey: TaskKey) {\n  return !['install', 'compile', 'publish', 'run-registry', 'check', 'sync-docs'].includes(taskKey);\n}\n\nexport const options = createOptions({\n  task: {\n    type: 'string',\n    description: 'Which task would you like to run?',\n    values: Object.keys(tasks) as TaskKey[],\n    valueDescriptions: Object.values(tasks).map((t) => `${t.description} (${getTaskKey(t)})`),\n    required: true,\n  },\n  startFrom: {\n    type: 'string',\n    description: 'Which task should we start execution from?',\n    values: [...(Object.keys(tasks) as TaskKey[]), 'never', 'auto', 'task'] as const,\n    // This is prompted later based on information about what's ready\n    promptType: false,\n    default: process.env.CI ? 'auto' : undefined,\n  },\n  template: {\n    type: 'string',\n    description: 'What template would you like to make a sandbox for?',\n    values: Object.keys(TEMPLATES) as TemplateKey[],\n    required: ({ task }) => !task || isSandboxTask(task),\n    promptType: (_, { task }) => isSandboxTask(task),\n  },\n  // // TODO -- feature flags\n  // sandboxDir: {\n  //   type: 'string',\n  //   description: 'What is the name of the directory the sandbox runs in?',\n  //   promptType: false,\n  // },\n  addon: {\n    type: 'string[]',\n    description: 'Which extra addons (beyond the CLI defaults) would you like installed?',\n    values: extraAddons,\n    promptType: (_, { task }) => isSandboxTask(task),\n  },\n  link: {\n    type: 'boolean',\n    description: 'Build code and link for local development?',\n    inverse: true,\n    promptType: false,\n  },\n  dir: {\n    type: 'string',\n    description: 'Name of sandbox directory',\n    required: false,\n    promptType: false,\n  },\n  prod: {\n    type: 'boolean',\n    description: 'Build code for production',\n    promptType: false,\n  },\n  dryRun: {\n    type: 'boolean',\n    description: \"Don't execute commands, just list them (dry run)?\",\n    promptType: false,\n  },\n  skipCache: {\n    type: 'boolean',\n    description: 'Skip NX remote cache?',\n    promptType: false,\n  },\n  debug: {\n    type: 'boolean',\n    description: 'Print all the logs to the console',\n    promptType: false,\n  },\n  junit: {\n    type: 'boolean',\n    description: 'Store results in junit format?',\n    promptType: false,\n  },\n  skipTemplateStories: {\n    type: 'boolean',\n    description: 'Do not include template stories and their addons',\n    promptType: false,\n  },\n  disableDocs: {\n    type: 'boolean',\n    description: 'Disable addon-docs from essentials',\n    promptType: false,\n  },\n});\n\nexport type PassedOptionValues = Omit<OptionValues<typeof options>, 'startFrom' | 'junit'>;\n\nconst logger = console;\n\nfunction getJunitFilename(taskKey: TaskKey) {\n  return join(JUNIT_DIRECTORY, `${taskKey}.xml`);\n}\n\nasync function pathExists(path: string) {\n  try {\n    await access(path);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\nasync function outputFile(file: string, data: string) {\n  await mkdir(dirname(file), { recursive: true });\n  await writeFile(file, data);\n}\n\nasync function writeJunitXml(\n  taskKey: TaskKey,\n  templateKey: TemplateKey,\n  startTime: Date,\n  err?: Error,\n  systemError?: boolean\n) {\n  let errorData = {};\n  if (err) {\n    // we want to distinguish whether the error comes from the tests we are running or from arbitrary code\n    errorData = systemError ? { errors: [{ message: err.stack }] } : { errors: [err] };\n  }\n\n  const name = `${taskKey} - ${templateKey}`;\n  const time = (Date.now() - +startTime) / 1000;\n  const testCase = { name, assertions: 1, time, ...errorData };\n  // We store the metadata as a system-err.\n  // Which is a bit unfortunate but it seems that one can't store extra data when the task is successful.\n  // system-err won't turn the whole test suite as failing, which makes it a reasonable candidate\n  const metadata: TestCase = {\n    name: `${name} - metadata`,\n    systemErr: [JSON.stringify({ ...TEMPLATES[templateKey], id: templateKey, version })],\n  };\n  const suite = { name, timestamp: startTime, time, testCases: [testCase, metadata] };\n  const junitXml = getJunitXml({ time, name, suites: [suite] });\n  const path = getJunitFilename(taskKey);\n  await outputFile(path, junitXml);\n  logger.log(`Test results written to ${resolve(path)}`);\n}\n\nfunction getTaskKey(task: Task): TaskKey {\n  return (Object.entries(tasks) as [TaskKey, Task][]).find(([_, t]) => t === task)[0];\n}\n\n/** Get a list of tasks that need to be (possibly) run, in order, to be able to run `finalTask`. */\nfunction getTaskList(finalTask: Task, details: TemplateDetails, optionValues: PassedOptionValues) {\n  const taskDeps = new Map<Task, Task[]>();\n  // Which tasks depend on a given task\n  const tasksThatDepend = new Map<Task, Task[]>();\n\n  const addTask = (task: Task, dependent?: Task) => {\n    if (tasksThatDepend.has(task)) {\n      if (!dependent) {\n        throw new Error('Unexpected task without dependent seen a second time');\n      }\n      tasksThatDepend.set(task, tasksThatDepend.get(task).concat(dependent));\n      return;\n    }\n\n    // This is the first time we've seen this task\n    tasksThatDepend.set(task, dependent ? [dependent] : []);\n\n    const dependedTaskNames =\n      typeof task.dependsOn === 'function'\n        ? task.dependsOn(details, optionValues)\n        : task.dependsOn || [];\n    const dependedTasks = dependedTaskNames.map((n) => tasks[n]);\n    taskDeps.set(task, dependedTasks);\n\n    dependedTasks.forEach((t) => addTask(t, task));\n  };\n  addTask(finalTask);\n\n  // We need to sort the tasks topologically so we run each task before the tasks that\n  // depend on it. This is Kahn's algorithm :shrug:\n  const sortedTasks = [] as Task[];\n  const tasksWithoutDependencies = [finalTask];\n\n  while (taskDeps.size !== sortedTasks.length) {\n    const task = tasksWithoutDependencies.pop();\n\n    if (!task) {\n      throw new Error('Topological sort failed, is there a cyclic task dependency?');\n    }\n\n    sortedTasks.unshift(task);\n    taskDeps.get(task).forEach((depTask) => {\n      const remainingTasksThatDepend = tasksThatDepend\n        .get(depTask)\n        .filter((t) => !sortedTasks.includes(t));\n\n      if (remainingTasksThatDepend.length === 0) {\n        tasksWithoutDependencies.push(depTask);\n      }\n    });\n  }\n\n  return { sortedTasks, tasksThatDepend };\n}\n\ntype TaskStatus =\n  | 'ready'\n  | 'unready'\n  | 'running'\n  | 'complete'\n  | 'failed'\n  | 'serving'\n  | 'notserving';\nconst statusToEmoji: Record<TaskStatus, string> = {\n  ready: '🟢',\n  unready: '🟡',\n  running: '🔄',\n  complete: '✅',\n  failed: '❌',\n  serving: '🔊',\n  notserving: '🔇',\n};\nfunction writeTaskList(statusMap: Map<Task, TaskStatus>) {\n  logger.info(\n    [...statusMap.entries()]\n      .map(([task, status]) => `${statusToEmoji[status]} ${getTaskKey(task)}`)\n      .join(' > ')\n  );\n  logger.info();\n}\n\nasync function runTask(task: Task, details: TemplateDetails, optionValues: PassedOptionValues) {\n  const { junitFilename } = details;\n  const startTime = new Date();\n  try {\n    let updatedOptions = optionValues;\n    if (details.template?.modifications?.skipTemplateStories) {\n      updatedOptions = { ...updatedOptions, skipTemplateStories: true };\n    }\n    if (details.template?.modifications?.disableDocs) {\n      updatedOptions = { ...updatedOptions, disableDocs: true };\n    }\n    const controller = await task.run(details, updatedOptions);\n\n    if (junitFilename && !task.junit) {\n      await writeJunitXml(getTaskKey(task), details.key, startTime);\n    }\n\n    return controller;\n  } catch (err) {\n    invariant(err instanceof Error);\n    const hasJunitFile = await pathExists(junitFilename);\n    // If there's a non-test related error (junit report has not been reported already), we report the general failure in a junit report\n    if (junitFilename && !hasJunitFile) {\n      await writeJunitXml(getTaskKey(task), details.key, startTime, err, true);\n    }\n\n    throw err;\n  } finally {\n    if (await pathExists(junitFilename)) {\n      const junitXml = await (await readFile(junitFilename)).toString();\n      const prefixedXml = junitXml.replace(/classname=\"(.*)\"/g, `classname=\"${details.key} $1\"`);\n      await outputFile(junitFilename, prefixedXml);\n    }\n  }\n}\n\nconst controllers: AbortController[] = [];\n\nasync function run() {\n  // useful for other scripts to know whether they're running in the creation of a sandbox in the monorepo\n  process.env.IN_STORYBOOK_SANDBOX = 'true';\n\n  const allOptionValues = await getOptionsOrPrompt('yarn task', options);\n\n  const { junit, startFrom, ...optionValues } = allOptionValues;\n\n  const taskKey = optionValues.task;\n\n  if (!(taskKey in tasks)) {\n    const matchText = findMostMatchText(Object.keys(tasks), taskKey);\n\n    if (matchText) {\n      console.log(\n        `${picocolors.red('Error')}: ${picocolors.cyan(\n          taskKey\n        )} is not a valid task name, Did you mean ${picocolors.cyan(matchText)}?`\n      );\n    }\n    process.exit(1);\n  }\n\n  const finalTask = tasks[taskKey];\n  const { template: templateKey, dir } = optionValues;\n  const template = TEMPLATES[templateKey];\n\n  const templateSandboxDir =\n    templateKey && join(SANDBOX_DIRECTORY, dir ?? templateKey.replace('/', '-'));\n  const details: TemplateDetails = {\n    key: templateKey,\n    template,\n    codeDir: CODE_DIRECTORY,\n    selectedTask: taskKey,\n    sandboxDir: templateSandboxDir,\n    builtSandboxDir: templateKey && join(templateSandboxDir, 'storybook-static'),\n    junitFilename: junit && getJunitFilename(taskKey),\n  };\n  const { sortedTasks, tasksThatDepend } = getTaskList(finalTask, details, optionValues);\n  const sortedTasksReady = await Promise.all(\n    sortedTasks.map((t) => t.ready(details, optionValues))\n  );\n\n  if (templateKey) {\n    logger.info(`👉 Selected sandbox: ${templateKey}`);\n    logger.info();\n  }\n\n  logger.info(`Task readiness up to ${taskKey}`);\n  const initialTaskStatus = (task: Task, ready: boolean) => {\n    if (task.service) {\n      return ready ? 'serving' : 'notserving';\n    }\n    return ready ? 'ready' : 'unready';\n  };\n  const statuses = new Map<Task, TaskStatus>(\n    sortedTasks.map((task, index) => [task, initialTaskStatus(task, sortedTasksReady[index])])\n  );\n  writeTaskList(statuses);\n\n  function setUnready(task: Task) {\n    // If the task is a service we don't need to set it unready but we still need to do so for\n    // it's dependencies\n\n    // If the task is a service we don't need to set it unready but we still need to do so for\n    // it's dependencies\n    if (!task.service) {\n      statuses.set(task, 'unready');\n    }\n    tasksThatDepend\n      .get(task)\n      ?.filter((t) => !t.service)\n      ?.forEach(setUnready);\n  }\n\n  // NOTE: we don't include services in the first unready task. We only need to rewind back to a\n  // service if the user explicitly asks. It's expected that a service is no longer running.\n  const firstUnready = sortedTasks.find((task) => statuses.get(task) === 'unready');\n  if (startFrom === 'auto') {\n    // Don't reset anything!\n  } else if (startFrom === 'task') {\n    // just run that one task\n  } else if (startFrom === 'never') {\n    if (!firstUnready) {\n      throw new Error(`Task ${taskKey} is ready`);\n    }\n\n    if (firstUnready !== finalTask) {\n      throw new Error(`Task ${getTaskKey(firstUnready)} was not ready`);\n    }\n  } else if (startFrom) {\n    // set to reset back to a specific task\n    if (firstUnready && sortedTasks.indexOf(tasks[startFrom]) > sortedTasks.indexOf(firstUnready)) {\n      throw new Error(\n        `Task ${getTaskKey(firstUnready)} was not ready, earlier than your request ${startFrom}.`\n      );\n    }\n    setUnready(tasks[startFrom]);\n  } else if (firstUnready === sortedTasks[0]) {\n    // We need to do everything, no need to change anything\n  } else if (sortedTasks.length === 1) {\n    setUnready(sortedTasks[0]);\n  } else {\n    // We don't know what to do! Let's ask\n    const { startFromTask } = await prompt(\n      {\n        type: 'select',\n        message: firstUnready\n          ? `We need to run all tasks from ${getTaskKey(\n              firstUnready\n            )} onwards, would you like to start from an earlier task?`\n          : `Which task would you like to start from?`,\n        name: 'startFromTask',\n        choices: sortedTasks\n          .slice(0, firstUnready && sortedTasks.indexOf(firstUnready) + 1)\n          .reverse()\n          .map((t) => ({\n            title: `${t.description} (${getTaskKey(t)})`,\n            value: t,\n          })),\n      },\n      {\n        onCancel: () => {\n          logger.log('Command cancelled by the user. Exiting...');\n          process.exit(1);\n        },\n      }\n    );\n    setUnready(startFromTask);\n  }\n\n  for (let i = 0; i < sortedTasks.length; i += 1) {\n    const task = sortedTasks[i];\n    const status = statuses.get(task);\n\n    let shouldRun = status === 'unready';\n    if (status === 'notserving') {\n      shouldRun =\n        finalTask === task ||\n        !!tasksThatDepend.get(task).find((t) => statuses.get(t) === 'unready');\n    }\n\n    if (startFrom === 'task') {\n      shouldRun = finalTask === task;\n    }\n\n    if (shouldRun) {\n      statuses.set(task, 'running');\n      writeTaskList(statuses);\n\n      try {\n        const controller = await runTask(task, details, {\n          ...optionValues,\n          // Always debug the final task so we can see it's output fully\n          debug: task === finalTask ? true : optionValues.debug,\n        });\n\n        if (controller) {\n          controllers.push(controller);\n        }\n      } catch (err) {\n        invariant(err instanceof Error);\n        let errorTitle = `Error running task ${picocolors.bold(getTaskKey(task))}`;\n        if (details.key) {\n          errorTitle += ` for ${picocolors.bgCyan(picocolors.white(details.key))}:`;\n        }\n        logger.error(errorTitle);\n        logger.error(JSON.stringify(err, null, 2));\n\n        if (process.env.CI) {\n          const separator = '\\n--------------------------------------------\\n';\n          const reproduceMessage = dedent`\n            To reproduce this error locally, run:\n\n            ${picocolors.bold(\n              getCommand('yarn task', options, {\n                ...allOptionValues,\n                link: true,\n                startFrom: 'auto',\n              })\n            )}\n\n            Note this uses locally linking which in rare cases behaves differently to CI.\n            For a closer match, add ${picocolors.bold('--no-link')} to the command above.\n          `;\n\n          err.message += `\\n${separator}${reproduceMessage}${separator}\\n`;\n        }\n\n        controllers.forEach((controller) => {\n          controller.abort();\n        });\n\n        throw err;\n      }\n      statuses.set(task, task.service ? 'serving' : 'complete');\n\n      // If the task is a service, we want to stay open until we are ctrl-ced\n      if (sortedTasks[i] === finalTask && finalTask.service) {\n        await new Promise(() => {});\n      }\n    }\n  }\n\n  return 0;\n}\n\nprocess.on('exit', () => {\n  // Make sure to kill any running tasks 🎉\n  controllers.forEach((controller) => {\n    controller.abort();\n  });\n});\n\nrun()\n  .then((status) => process.exit(status))\n  .catch((err) => {\n    logger.error();\n    logger.error(err);\n    process.exit(1);\n  });\n"
  },
  {
    "path": "scripts/tasks/bench.ts",
    "content": "import prettyBytes from 'pretty-bytes';\nimport prettyTime from 'pretty-ms';\n\nimport type { Task } from '../task.ts';\nimport { dev, PORT as devPort } from './dev.ts';\nimport { serve, PORT as servePort } from './serve.ts';\n\nconst logger = console;\n\nexport const bench: Task = {\n  description: 'Run benchmarks against a sandbox in dev mode',\n  dependsOn: ['build'],\n  async ready() {\n    return false;\n  },\n\n  async run(details, options) {\n    const controllers: AbortController[] = [];\n    try {\n      const { disableDocs } = options;\n      const { browse } = await import('../bench/browse.ts');\n      const { saveBench, loadBench } = await import('../bench/utils.ts');\n\n      const devController = await dev.run(details, { ...options, debug: false });\n      if (!devController) {\n        throw new Error('dev: controller is null');\n      }\n      controllers.push(devController);\n      const devBrowseResult = await browse(`http://localhost:${devPort}`, { disableDocs });\n\n      devController.abort();\n\n      const serveController = await serve.run(details, { ...options, debug: false });\n      if (!serveController) {\n        throw new Error('serve: controller is null');\n      }\n      controllers.push(serveController);\n\n      const buildBrowseResult = await browse(`http://localhost:${servePort}`, { disableDocs });\n      serveController.abort();\n\n      await saveBench(\n        'browse',\n        {\n          devManagerHeaderVisible: devBrowseResult.managerHeaderVisible,\n          devManagerIndexVisible: devBrowseResult.managerIndexVisible,\n          devStoryVisible: devBrowseResult.storyVisible,\n          devStoryVisibleUncached: devBrowseResult.storyVisibleUncached,\n          devAutodocsVisible: devBrowseResult.autodocsVisible,\n          devMDXVisible: devBrowseResult.mdxVisible,\n\n          buildManagerHeaderVisible: buildBrowseResult.managerHeaderVisible,\n          buildManagerIndexVisible: buildBrowseResult.managerIndexVisible,\n          buildStoryVisible: buildBrowseResult.storyVisible,\n          buildAutodocsVisible: buildBrowseResult.autodocsVisible,\n          buildMDXVisible: buildBrowseResult.mdxVisible,\n        },\n        {\n          rootDir: details.sandboxDir,\n        }\n      );\n\n      const data = await loadBench({ rootDir: details.sandboxDir });\n      Object.entries(data).forEach(([key, value]) => {\n        if (typeof value !== 'number') {\n          return;\n        }\n\n        if (key.includes('Size')) {\n          console.log(`${key}: ${prettyBytes(value)}`);\n        } else {\n          console.log(`${key}: ${prettyTime(value)}`);\n        }\n      });\n    } catch (e) {\n      logger.log(\n        `An error occurred while running the benchmarks for the ${details.sandboxDir} sandbox`\n      );\n      logger.error(e);\n      controllers.forEach((c) => c.abort());\n      throw e;\n    }\n  },\n};\n"
  },
  {
    "path": "scripts/tasks/build.ts",
    "content": "import { access, cp, rm } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport dirSize from 'fast-folder-size';\n\nimport { now, saveBench } from '../bench/utils.ts';\nimport type { Task } from '../task.ts';\nimport { ROOT_DIRECTORY } from '../utils/constants.ts';\nimport { exec } from '../utils/exec.ts';\nimport { isNxTaskExecution } from '../utils/nx.ts';\nimport { prepareSandbox } from '../prepare-sandbox.ts';\n\nasync function pathExists(path: string) {\n  try {\n    await access(path);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\nexport const build: Task = {\n  description: 'Build the static version of the sandbox',\n  dependsOn: ['sandbox'],\n  async ready({ builtSandboxDir }) {\n    return pathExists(builtSandboxDir);\n  },\n  async run({ builtSandboxDir, sandboxDir, template, key }, { dryRun, debug, link }) {\n    await prepareSandbox({ key, link });\n    const start = now();\n\n    await exec(\n      `yarn build-storybook --quiet ${template.modifications?.testBuild ? '--test' : ''}`,\n      { cwd: sandboxDir },\n      { dryRun, debug }\n    );\n\n    const buildTime = now() - start;\n    const dir = join(sandboxDir, 'storybook-static');\n    const getSize = promisify(dirSize);\n    const buildSize = await getSize(dir).catch(() => 0);\n    const buildSbAddonsSize = await getSize(join(dir, 'sb-addons')).catch(() => 0);\n    const buildSbCommonSize = await getSize(join(dir, 'sb-common-assets')).catch(() => 0);\n    const buildSbManagerSize = await getSize(join(dir, 'sb-manager')).catch(() => 0);\n    const buildSbPreviewSize = await getSize(join(dir, 'sb-preview')).catch(() => 0);\n    const buildPrebuildSize =\n      buildSbAddonsSize + buildSbCommonSize + buildSbManagerSize + buildSbPreviewSize;\n\n    const buildStaticSize = await getSize(join(dir, 'static')).catch(() => 0);\n    const buildPreviewSize = buildSize - buildPrebuildSize - buildStaticSize;\n\n    await saveBench(\n      'build',\n      {\n        buildTime,\n        buildSize,\n        buildSbAddonsSize,\n        buildSbCommonSize,\n        buildSbManagerSize,\n        buildSbPreviewSize,\n        buildStaticSize,\n        buildPrebuildSize,\n        buildPreviewSize,\n      },\n      { rootDir: sandboxDir }\n    );\n\n    const cacheDir = join(ROOT_DIRECTORY, 'sandbox', key.replace('/', '-'), 'storybook-static');\n    if (isNxTaskExecution() && builtSandboxDir !== cacheDir) {\n      console.info(`✅ Removing cache directory ${cacheDir}`);\n      await rm(cacheDir, { recursive: true, force: true });\n\n      console.info(`✅ Copy ${builtSandboxDir} to cache directory`);\n      await cp(builtSandboxDir, cacheDir, { recursive: true, force: true });\n    }\n  },\n};\n"
  },
  {
    "path": "scripts/tasks/check-sandbox.ts",
    "content": "import type { Task } from '../task.ts';\nimport { exec } from '../utils/exec.ts';\nimport { prepareSandbox } from '../prepare-sandbox.ts';\n\nexport const checkSandbox: Task = {\n  description: 'Typecheck a sandbox',\n  dependsOn: ['sandbox'],\n  async ready() {\n    return false;\n  },\n  async run({ sandboxDir, key }, { dryRun, debug, link }) {\n    await prepareSandbox({ key, link });\n    await exec(`yarn typecheck`, { cwd: sandboxDir }, { dryRun, debug });\n  },\n};\n"
  },
  {
    "path": "scripts/tasks/check.ts",
    "content": "import { join } from 'node:path';\n\n// eslint-disable-next-line depend/ban-dependencies\nimport { execaCommand } from 'execa';\n\nimport type { Task } from '../task.ts';\nimport { CODE_DIRECTORY, ROOT_DIRECTORY } from '../utils/constants.ts';\nimport { getCodeWorkspaces } from '../utils/workspace.ts';\n\nexport const check: Task = {\n  description: 'Typecheck the source code of the monorepo',\n  async ready() {\n    return false;\n  },\n  async run(_, {}) {\n    const failed: string[] = [];\n    // const command = link ? linkCommand : nolinkCommand;\n    const workspaces = await getCodeWorkspaces();\n\n    for (const workspace of workspaces) {\n      if (workspace.location === '.') {\n        continue; // skip root directory\n      }\n      const cwd = join(CODE_DIRECTORY, workspace.location);\n      console.log('');\n      console.log('Checking ' + workspace.name + ' at ' + cwd);\n\n      let command = '';\n      if (workspace.name === '@storybook/vue3') {\n        command = `npx vue-tsc --noEmit --project ${join(cwd, 'tsconfig.json')}`;\n      } else if (workspace.name === '@storybook/svelte') {\n        command = `npx svelte-check`;\n      } else {\n        const script = join(ROOT_DIRECTORY, 'scripts', 'check', 'check-package.ts');\n        command = `yarn exec jiti ${script} --cwd ${cwd}`;\n        // command = `npx tsc --noEmit --project ${join(cwd, 'tsconfig.json')}`;\n      }\n\n      const sub = execaCommand(`${command}`, {\n        cwd,\n        env: {\n          NODE_ENV: 'production',\n        },\n      });\n\n      sub.stdout?.on('data', (data) => {\n        process.stdout.write(data);\n      });\n      sub.stderr?.on('data', (data) => {\n        process.stderr.write(data);\n      });\n\n      await sub.catch(() => {\n        failed.push(workspace.name);\n      });\n    }\n\n    if (failed.length > 0) {\n      throw new Error(`Failed to check ${failed.join(', ')}`);\n    }\n  },\n};\n"
  },
  {
    "path": "scripts/tasks/chromatic.ts",
    "content": "import type { Task } from '../task.ts';\nimport { exec } from '../utils/exec.ts';\nimport { prepareSandbox } from '../prepare-sandbox.ts';\n\nexport const chromatic: Task = {\n  description: 'Run Chromatic against the sandbox',\n  dependsOn: ['build'],\n  junit: true,\n  async ready() {\n    return false;\n  },\n  async run({ key, sandboxDir, builtSandboxDir, junitFilename }, { dryRun, debug, link }) {\n    await prepareSandbox({ key, link });\n    const tokenEnvVarName = `CHROMATIC_TOKEN_${key.toUpperCase().replace(/\\/|-|\\./g, '_')}`;\n    const token = process.env[tokenEnvVarName];\n\n    await exec(\n      `npx chromatic \\\n          --debug \\\n          --exit-zero-on-changes \\\n          --storybook-build-dir=${builtSandboxDir} \\\n          ${junitFilename ? `--junit-report=${junitFilename}` : ''} \\\n          --projectToken=${token}`,\n      { cwd: sandboxDir },\n      { dryRun, debug }\n    );\n  },\n};\n"
  },
  {
    "path": "scripts/tasks/compile.ts",
    "content": "import { readFile, rm } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\n\nimport type { Task } from '../task.ts';\nimport { ROOT_DIRECTORY } from '../utils/constants.ts';\nimport { exec } from '../utils/exec.ts';\nimport { maxConcurrentTasks } from '../utils/maxConcurrentTasks.ts';\n\n// The amount of VCPUs for the check task on CI is 4 (large resource)\nconst amountOfVCPUs = 2;\n\nconst parallel = `--parallel=${process.env.CI ? amountOfVCPUs - 1 : maxConcurrentTasks}`;\n\nconst linkCommand = `yarn nx run-many -t compile ${parallel}`;\nconst noLinkCommand = `yarn nx run-many -t compile -c production ${parallel}`;\n\nexport const compile: Task = {\n  description: 'Compile the source code of the monorepo',\n  dependsOn: ['install'],\n  async ready({ codeDir }, { link }) {\n    try {\n      if (link) {\n        await readFile(resolve(codeDir, './core/dist/manager-api/index.js'), 'utf8');\n      } else {\n        await readFile(resolve(codeDir, './core/dist/manager-api/index.d.ts'), 'utf8');\n      }\n      return true;\n    } catch (err) {\n      return false;\n    }\n  },\n  async run({ codeDir }, { link, dryRun, debug, prod, skipCache }) {\n    const command = link && !prod ? linkCommand : noLinkCommand;\n    await rm(join(codeDir, 'bench/esbuild-metafiles'), { recursive: true, force: true });\n    return exec(\n      // NX cache is disabled in Circle CI during the NX Cloud experiment so we can\n      // measure the true cost of NX Cloud agents without local cache hits.\n      // This will be reverted once the experiment concludes.\n      `${command} ${skipCache || process.env.CI ? '--skip-nx-cache' : ''}`,\n      { cwd: ROOT_DIRECTORY },\n      {\n        startMessage: '🥾 Bootstrapping',\n        errorMessage: '❌ Failed to bootstrap',\n        dryRun,\n        debug,\n      }\n    );\n  },\n};\n"
  },
  {
    "path": "scripts/tasks/dev.ts",
    "content": "import waitOn from 'wait-on';\n\nimport type { AllTemplatesKey } from '../../code/lib/cli-storybook/src/sandbox-templates.ts';\nimport { now, saveBench } from '../bench/utils.ts';\nimport { getPort } from '../sandbox/utils/getPort.ts';\nimport type { Task } from '../task.ts';\nimport { exec } from '../utils/exec.ts';\nimport { isNxTaskExecution } from '../utils/nx.ts';\nimport { prepareSandbox } from '../prepare-sandbox.ts';\n\nexport const PORT = process.env.STORYBOOK_SERVE_PORT\n  ? parseInt(process.env.STORYBOOK_SERVE_PORT, 10)\n  : 6006;\n\nfunction getDevPort(key: AllTemplatesKey) {\n  return isNxTaskExecution() ? getPort({ selectedTask: 'dev', key }) : PORT;\n}\n\nexport const dev: Task = {\n  description: 'Run the sandbox in development mode',\n  service: true,\n  dependsOn: ['sandbox'],\n  async ready({ key }) {\n    const port = getDevPort(key);\n    try {\n      await fetch(`http://localhost:${port}/iframe.html`, { signal: AbortSignal.timeout(1000) });\n      return true;\n    } catch {\n      return false;\n    }\n  },\n  async run({ sandboxDir, key, selectedTask }, { dryRun, debug, link }) {\n    await prepareSandbox({ key, link });\n    const controller = new AbortController();\n    const port = getDevPort(key);\n    const devCommand = `yarn storybook --port ${port}${selectedTask === 'dev' ? '' : ' --ci'}`;\n\n    const start = now();\n    exec(\n      devCommand,\n      { cwd: sandboxDir },\n      { dryRun, debug, signal: controller.signal as AbortSignal }\n    ).catch((err) => {\n      // If aborted, we want to make sure the rejection is handled.\n      if (!err.killed) {\n        throw err;\n      }\n    });\n    const [devPreviewResponsive, devManagerResponsive] = await Promise.all([\n      waitOn({\n        resources: [`http://localhost:${port}/iframe.html`],\n        interval: 16,\n        timeout: 200000,\n      }).then(() => {\n        return now() - start;\n      }),\n      waitOn({\n        resources: [`http://localhost:${port}/index.html`],\n        interval: 16,\n        timeout: 200000,\n      }).then(() => {\n        return now() - start;\n      }),\n    ]);\n\n    await saveBench(\n      'dev',\n      {\n        devPreviewResponsive,\n        devManagerResponsive,\n      },\n      { rootDir: sandboxDir }\n    );\n\n    return controller;\n  },\n};\n"
  },
  {
    "path": "scripts/tasks/e2e-tests-build.ts",
    "content": "import { dedent } from 'ts-dedent';\nimport waitOn from 'wait-on';\n\nimport { getPort } from '../sandbox/utils/getPort.ts';\nimport type { Task } from '../task.ts';\nimport { exec } from '../utils/exec.ts';\nimport { isNxTaskExecution } from '../utils/nx.ts';\nimport { PORT } from './serve.ts';\n\nconst testFileRegex = /(test|spec)\\.(js|ts|mjs)$/;\n\nexport const e2eTestsBuild: Task & { port: number; type: 'build' | 'dev' } = {\n  description: 'Run e2e tests against a sandbox in prod mode',\n  dependsOn: ['serve'],\n  junit: true,\n  port: PORT,\n  type: 'build',\n  async ready() {\n    return false;\n  },\n  async run({ codeDir, junitFilename, key, sandboxDir, selectedTask }, { dryRun, debug }) {\n    const port = isNxTaskExecution()\n      ? getPort({ key, selectedTask: selectedTask === 'e2e-tests' ? 'serve' : 'dev' })\n      : this.port;\n\n    if (process.env.DEBUG) {\n      console.log(dedent`\n        Running e2e tests in Playwright's ui mode for chromium only (for brevity sake).\n        You can change the browser by changing the --project flag in the e2e-tests task file.\n      `);\n    }\n\n    const firstTestFileArgIndex = process.argv.findIndex((arg) => testFileRegex.test(arg));\n    const testFiles = firstTestFileArgIndex === -1 ? [] : process.argv.slice(firstTestFileArgIndex);\n\n    const playwrightCommand = process.env.DEBUG\n      ? `yarn playwright test --project=chromium --ui ${testFiles.join(' ')}`\n      : `yarn playwright test ${testFiles.join(' ')}`;\n\n    await waitOn({ resources: [`http://localhost:${port}`], interval: 16, timeout: 200000 });\n    await exec(\n      playwrightCommand,\n      {\n        env: {\n          STORYBOOK_URL: `http://localhost:${port}`,\n          STORYBOOK_TYPE: this.type,\n          STORYBOOK_TEMPLATE_NAME: key,\n          STORYBOOK_SANDBOX_DIR: sandboxDir,\n          ...(junitFilename && {\n            PLAYWRIGHT_JUNIT_OUTPUT_NAME: junitFilename,\n          }),\n        },\n        cwd: codeDir,\n      },\n      { dryRun, debug }\n    );\n  },\n};\n"
  },
  {
    "path": "scripts/tasks/e2e-tests-dev.ts",
    "content": "import { PORT } from './dev.ts';\nimport { e2eTestsBuild } from './e2e-tests-build.ts';\n\nexport const e2eTestsDev: typeof e2eTestsBuild = {\n  ...e2eTestsBuild,\n  description: 'Run e2e tests against a sandbox in dev mode',\n  dependsOn: ['dev'],\n  port: PORT,\n  type: 'dev',\n};\n"
  },
  {
    "path": "scripts/tasks/generate.ts",
    "content": "import { access, rm } from 'node:fs/promises';\n\nimport { join } from 'path';\n\nimport type { Task } from '../task.ts';\nimport { REPROS_DIRECTORY } from '../utils/constants.ts';\n\nconst logger = console;\n\nconst pathExists = async (path: string) => {\n  try {\n    await access(path);\n    return true;\n  } catch {\n    return false;\n  }\n};\n\nexport const generate: Task = {\n  description: 'Create the template repro',\n  dependsOn: ['run-registry'],\n  async ready({ key, template }, { link }) {\n    const isReady = pathExists(join(REPROS_DIRECTORY, key, 'after-storybook'));\n    if (isReady) {\n      return isReady;\n    }\n    if ('inDevelopment' in template && template.inDevelopment && link) {\n      throw new Error('Cannot link an in development template');\n    }\n    return isReady;\n  },\n  async run(details, options) {\n    const reproDir = join(REPROS_DIRECTORY, details.key);\n    if (await this.ready(details, options)) {\n      logger.info('🗑  Removing old repro dir');\n      await rm(reproDir, { force: true, recursive: true });\n    }\n\n    // This uses an async import as it depends on `lib/cli` which requires `code` to be installed.\n    const { generate: generateRepro } = await import('../sandbox/generate.ts');\n\n    await generateRepro({\n      templates: [details.key],\n      exclude: [],\n      localRegistry: true,\n      debug: options.debug,\n    });\n  },\n};\n"
  },
  {
    "path": "scripts/tasks/install.ts",
    "content": "import { access } from 'node:fs/promises';\n\nimport { join } from 'path';\n\nimport type { Task } from '../task.ts';\nimport { checkDependencies } from '../utils/cli-utils.ts';\nimport { ROOT_DIRECTORY } from '../utils/constants.ts';\n\nconst pathExists = async (path: string) => {\n  try {\n    await access(path);\n    return true;\n  } catch {\n    return false;\n  }\n};\n\nexport const install: Task = {\n  description: 'Install the dependencies of the monorepo',\n  async ready() {\n    return pathExists(join(ROOT_DIRECTORY, 'node_modules'));\n  },\n  async run() {\n    await checkDependencies();\n  },\n};\n"
  },
  {
    "path": "scripts/tasks/publish.ts",
    "content": "import { access } from 'node:fs/promises';\n\nimport { resolve } from 'path';\n\nimport type { Task } from '../task.ts';\nimport { exec } from '../utils/exec.ts';\n\nconst verdaccioCacheDir = resolve(__dirname, '../../.verdaccio-cache');\n\nconst pathExists = async (path: string) => {\n  try {\n    await access(path);\n    return true;\n  } catch {\n    return false;\n  }\n};\n\nexport const publish: Task = {\n  description: 'Publish the packages of the monorepo to an internal npm server',\n  dependsOn: ['compile'],\n  async ready() {\n    return pathExists(verdaccioCacheDir);\n  },\n  async run({ codeDir }, { dryRun, debug }) {\n    return exec(\n      'yarn local-registry --publish',\n      { cwd: codeDir },\n      {\n        startMessage: '📕 Publishing packages',\n        errorMessage: '❌ Failed publishing packages',\n        dryRun,\n        debug,\n      }\n    );\n  },\n};\n"
  },
  {
    "path": "scripts/tasks/run-registry.ts",
    "content": "import waitOn from 'wait-on';\n\nimport type { Task } from '../task.ts';\nimport { CODE_DIRECTORY } from '../utils/constants.ts';\nimport { exec } from '../utils/exec.ts';\nimport { isPortUsed } from '../utils/port.ts';\n\nconst REGISTRY_PORT = 6001;\nconst VERDACCIO_PORT = 6002;\n\nexport async function runRegistry({ dryRun, debug }: { dryRun?: boolean; debug?: boolean }) {\n  const controller = new AbortController();\n\n  void exec(\n    'yarn local-registry --open',\n    { cwd: CODE_DIRECTORY, env: { CI: 'true' } },\n    { dryRun, debug, signal: controller.signal }\n  ).catch((err) => {\n    // If aborted, we want to make sure the rejection is handled.\n    if (!err.killed) {\n      throw err;\n    }\n  });\n  await waitOn({\n    log: true,\n    resources: [`http://localhost:${REGISTRY_PORT}`, `http://localhost:${VERDACCIO_PORT}`],\n    interval: 16,\n    timeout: 20000,\n  });\n  return controller;\n}\n\nexport const runRegistryTask: Task = {\n  description: 'Run the internal npm server',\n  service: true,\n  dependsOn: ['publish'],\n  async ready() {\n    return (await isPortUsed(REGISTRY_PORT)) && (await isPortUsed(VERDACCIO_PORT));\n  },\n  async run(_, options) {\n    return runRegistry(options);\n  },\n};\n"
  },
  {
    "path": "scripts/tasks/sandbox-parts.ts",
    "content": "// This file requires many imports from `../code`, which requires both an install and bootstrap of\n// the repo to work properly. So we load it async in the task runner *after* those steps.\nimport { existsSync } from 'node:fs';\nimport { access, cp, lstat, mkdir, readFile, symlink, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\n\nimport { isFunction } from 'es-toolkit/predicate';\nimport JSON5 from 'json5';\nimport { createRequire } from 'module';\nimport { join, relative, resolve, sep } from 'path';\n// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\n\nimport { babelParse, types as t } from '../../code/core/src/babel/index.ts';\nimport { JsPackageManagerFactory } from '../../code/core/src/common/js-package-manager/index.ts';\nimport storybookPackages from '../../code/core/src/common/versions.ts';\nimport type { ConfigFile } from '../../code/core/src/csf-tools/index.ts';\nimport {\n  readConfig as csfReadConfig,\n  formatConfig,\n  writeConfig,\n} from '../../code/core/src/csf-tools/index.ts';\nimport { SupportedLanguage } from '../../code/core/src/types/index.ts';\nimport type { TemplateKey } from '../../code/lib/cli-storybook/src/sandbox-templates.ts';\nimport { ProjectTypeService } from '../../code/lib/create-storybook/src/services/ProjectTypeService.ts';\nimport type { PassedOptionValues, Task, TemplateDetails } from '../task.ts';\nimport { executeCLIStep, steps } from '../utils/cli-step.ts';\nimport { CODE_DIRECTORY, REPROS_DIRECTORY, ROOT_DIRECTORY } from '../utils/constants.ts';\nimport { exec } from '../utils/exec.ts';\nimport { filterExistsInCodeDir } from '../utils/filterExistsInCodeDir.ts';\nimport { addPreviewAnnotations, readConfig } from '../utils/main-js.ts';\nimport { updatePackageScripts } from '../utils/package-json.ts';\nimport { findFirstPath } from '../utils/paths.ts';\nimport { workspacePath } from '../utils/workspace.ts';\nimport {\n  addPackageResolutions,\n  addWorkaroundResolutions,\n  configureYarn2ForVerdaccio,\n  installYarn2,\n  isViteSandbox,\n} from '../utils/yarn.ts';\n\nasync function ensureSymlink(src: string, dest: string): Promise<void> {\n  await mkdir(dirname(dest), { recursive: true });\n\n  try {\n    await lstat(dest);\n    return;\n  } catch (e: any) {\n    if (e?.code !== 'ENOENT') {\n      throw e;\n    }\n  }\n\n  await symlink(src, dest);\n}\n\n// Windows-compatible symlink function that falls back to copying\nasync function ensureSymlinkOrCopy(source: string, target: string): Promise<void> {\n  if (process.env.CI) {\n    /**\n     * On CI, we don't need to symlink, we can just copy the files because there's no benefit in\n     * having a symlink on CI, but it does cause issues if we persist the workspace to windows.\n     */\n    await cp(source, target, { recursive: true, force: true });\n    return;\n  }\n  try {\n    await ensureSymlink(source, target);\n  } catch (error: any) {\n    // If symlink fails (typically on Windows without admin privileges), fall back to cp\n    if (error.code === 'EPERM' || error.code === 'EEXIST') {\n      logger.info(`Symlink failed for ${target}, falling back to cp`);\n      await cp(source, target, { recursive: true, force: true });\n    } else {\n      throw error;\n    }\n  }\n}\n\nasync function readJson(path: string) {\n  const content = await readFile(path, 'utf-8');\n  return JSON.parse(content);\n}\n\nasync function pathExists(path: string) {\n  try {\n    await access(path);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\nconst logger = console;\n\nexport const essentialsAddons = [\n  'actions',\n  'backgrounds',\n  'controls',\n  'highlight',\n  'measure',\n  'outline',\n  'toolbars',\n  'viewport',\n];\n\nexport const create: Task['run'] = async ({ key, template, sandboxDir }, { dryRun, debug }) => {\n  const parentDir = resolve(sandboxDir, '..');\n  await mkdir(parentDir, { recursive: true });\n\n  if ('inDevelopment' in template && template.inDevelopment) {\n    const srcDir = join(REPROS_DIRECTORY, key, 'after-storybook');\n    if (!existsSync(srcDir)) {\n      throw new Error(`Missing repro directory '${srcDir}', did the generate task run?`);\n    }\n    await cp(srcDir, sandboxDir, { recursive: true });\n  } else {\n    await executeCLIStep(steps.repro, {\n      argument: key,\n      optionValues: { output: sandboxDir, init: false, debug, loglevel: 'debug' },\n      cwd: parentDir,\n      dryRun,\n      debug,\n    });\n  }\n};\n\nexport const install: Task['run'] = async ({ sandboxDir, key }, { link, dryRun, debug }) => {\n  const cwd = sandboxDir;\n  await installYarn2({ cwd, dryRun, debug });\n\n  if (link) {\n    await executeCLIStep(steps.link, {\n      argument: `\"${sandboxDir}\"`,\n      cwd: CODE_DIRECTORY,\n      optionValues: { local: true, start: false },\n      dryRun,\n      debug,\n    });\n    await addWorkaroundResolutions({ cwd, dryRun, debug, key });\n  } else {\n    // We need to add package resolutions to ensure that we only ever install the latest version\n    // of any storybook packages as verdaccio is not able to both proxy to npm and publish over\n    // the top. In theory this could mask issues where different versions cause problems.\n    await addPackageResolutions({ cwd, dryRun, debug });\n    await configureYarn2ForVerdaccio({ cwd, dryRun, debug, key });\n\n    // Add workaround resolutions for vite-based sandboxes\n    if (isViteSandbox(key)) {\n      await addWorkaroundResolutions({ cwd, dryRun, debug, key });\n    }\n\n    await exec(\n      'yarn install',\n      { cwd },\n      {\n        debug,\n        dryRun,\n        startMessage: `⬇️ Installing local dependencies`,\n        errorMessage: `🚨 Installing local dependencies failed`,\n      }\n    );\n  }\n};\n\nexport const init: Task['run'] = async (\n  { sandboxDir, template },\n  { dryRun, debug, addon: addons, skipTemplateStories }\n) => {\n  const cwd = sandboxDir;\n\n  let extra = {};\n\n  switch (template.expected.renderer) {\n    case '@storybook/html':\n      extra = { type: 'html' };\n      break;\n    case '@storybook/server':\n      extra = { type: 'server' };\n      break;\n    case '@storybook/svelte':\n      await prepareSvelteSandbox(cwd);\n      break;\n  }\n\n  switch (template.expected.framework) {\n    case '@storybook/react-native-web-vite':\n      extra = { type: 'react_native_web' };\n      await prepareReactNativeWebSandbox(cwd);\n      break;\n  }\n\n  await executeCLIStep(steps.init, {\n    cwd,\n    optionValues: {\n      loglevel: 'debug',\n      yes: true,\n      ...extra,\n      ...(template.initOptions || {}),\n    },\n    dryRun,\n    debug,\n  });\n\n  logger.info(`🔢 Adding package scripts:`);\n\n  const nodeOptions = [\n    ...(process.env.NODE_OPTIONS || '').split(' '),\n    '--preserve-symlinks',\n    '--preserve-symlinks-main',\n  ].filter(Boolean);\n\n  const pnp = await pathExists(join(cwd, '.pnp.cjs')).catch(() => {});\n  if (pnp && !nodeOptions.find((s) => s.includes('--require'))) {\n    nodeOptions.push('--require ./.pnp.cjs');\n  }\n\n  const nodeOptionsString = nodeOptions.join(' ');\n  const prefix = `NODE_OPTIONS='${nodeOptionsString}' STORYBOOK_TELEMETRY_URL=\"http://localhost:6007/event-log\"`;\n\n  await updatePackageScripts({\n    cwd,\n    prefix,\n  });\n\n  switch (template.expected.framework) {\n    case '@storybook/angular':\n      await prepareAngularSandbox(cwd, template.name);\n      break;\n    default:\n  }\n\n  if (template.typeCheck) {\n    await prepareTypeChecking(cwd);\n  }\n\n  if (!skipTemplateStories) {\n    for (const addon of addons) {\n      await executeCLIStep(steps.add, {\n        argument: addon,\n        cwd,\n        dryRun,\n        debug,\n        optionValues: { yes: true },\n      });\n    }\n  }\n};\n\n// Ensure that sandboxes can refer to story files defined in `code/`.\n// Most WP-based build systems will not compile files outside of the project root or 'src/` or\n// similar. Plus they aren't guaranteed to handle TS files. So we need to patch in esbuild\n// loader for such files. NOTE this isn't necessary for Vite, as far as we know.\nfunction addEsbuildLoaderToStories(mainConfig: ConfigFile) {\n  // NOTE: the test regexp here will apply whether the path is symlink-preserved or otherwise\n  const require = createRequire(import.meta.url);\n  const esbuildLoaderPath = require.resolve('../../node_modules/esbuild-loader');\n  const webpackFinalCode = `\n  (config) => ({\n    ...config,\n    module: {\n      ...config.module,\n      rules: [\n        // Ensure esbuild-loader applies to all files in ./template-stories\n        {\n          test: [/\\\\/template-stories\\\\//],\n          exclude: [/\\\\.mdx$/],\n          loader: '${esbuildLoaderPath}',\n          options: {\n            loader: 'tsx',\n            target: 'es2022',\n          },\n        },\n        // Handle MDX files per the addon-docs presets (ish)\n        {\n          test: /template-stories\\\\/.*\\\\.mdx$/,\n          exclude: /\\\\.stories\\\\.mdx$/,\n          use: [\n            {\n              loader: '@storybook/addon-docs/mdx-loader',\n            },\n          ],\n        },\n        // Ensure no other loaders from the framework apply\n        ...config.module.rules.map(rule => ({\n          ...rule,\n          exclude: [/\\\\/template-stories\\\\//].concat(rule.exclude || []),\n        })),\n      ],\n    },\n  })`;\n  mainConfig.setFieldNode(\n    ['webpackFinal'],\n    // @ts-expect-error (Property 'expression' does not exist on type 'BlockStatement')\n    babelParse(webpackFinalCode).program.body[0].expression\n  );\n}\n\n/*\n  Recompile optimized deps on each startup, so you can change @storybook/* packages and not\n  have to clear caches.\n  And allow source directories to complement any existing allow patterns\n  (\".storybook\" is already being allowed by builder-vite)\n*/\nfunction setSandboxViteFinal(mainConfig: ConfigFile, template: TemplateKey) {\n  const temporaryAliasWorkaround = template.includes('nuxt')\n    ? `\n    // TODO: Remove this once Storybook Nuxt applies this internally\n    resolve: {\n      ...config.resolve,\n      alias: {\n        ...config.resolve.alias,\n        vue: 'vue/dist/vue.esm-bundler.js',\n      }\n    }\n  `\n    : '';\n  const viteFinalCode = `\n  (config) => ({\n    ...config,\n    optimizeDeps: { ...config.optimizeDeps, force: true },\n    server: {\n      ...config.server,\n      fs: {\n        ...config.server?.fs,\n        allow: ['stories', 'src', 'template-stories', 'node_modules', ...(config.server?.fs?.allow || [])],\n      },\n    },\n    ${temporaryAliasWorkaround}\n  })`;\n  // @ts-expect-error (Property 'expression' does not exist on type 'BlockStatement')\n  mainConfig.setFieldNode(['viteFinal'], babelParse(viteFinalCode).program.body[0].expression);\n}\n\n// Update the stories field to ensure that no TS files\n// that are linked from the renderer are picked up in non-TS projects\nfunction updateStoriesField(mainConfig: ConfigFile, isJs: boolean) {\n  const stories = mainConfig.getFieldValue(['stories']) as string[];\n\n  // If the project is a JS project, let's make sure any linked in TS stories from the\n  // renderer inside src|stories are simply ignored.\n  // TODO: We should definitely improve the logic here, as it will break every time the stories field change format in the generated sandboxes.\n  const updatedStories = isJs\n    ? stories.map((specifier) => specifier.replace('|ts|tsx', ''))\n    : stories;\n\n  mainConfig.setFieldValue(['stories'], [...updatedStories]);\n}\n\n// Add a stories field entry for the passed symlink\nfunction addStoriesEntry(\n  mainConfig: ConfigFile,\n  path: string,\n  disableDocs: boolean,\n  skipMocking: boolean\n) {\n  const stories = mainConfig.getFieldValue(['stories']) as string[];\n\n  const basePattern = disableDocs\n    ? '**/*.stories.@(js|jsx|mjs|ts|tsx)'\n    : '**/*.@(mdx|stories.@(js|jsx|mjs|ts|tsx))';\n\n  // When skipMocking is true and we're linking core template stories, exclude any stories\n  // with \"mocking\" in their file name (not related to docs filtering).\n  const files =\n    skipMocking && path === 'core' ? basePattern.replace('**/*', '**/!(*Mocking)*') : basePattern;\n\n  const entry = {\n    directory: slash(join('../template-stories', path)),\n    titlePrefix: slash(path),\n    files,\n  };\n\n  mainConfig.setFieldValue(['stories'], [...stories, entry]);\n}\n\nfunction getStoriesFolderWithVariant(variant?: string, folder = 'stories') {\n  return variant ? `${folder}_${variant}` : folder;\n}\n\n// packageDir is eg 'renderers/react', 'addons/actions'\nasync function linkPackageStories(\n  packageDir: string,\n  {\n    mainConfig,\n    cwd,\n    linkInDir,\n    disableDocs,\n    skipMocking,\n  }: {\n    mainConfig: ConfigFile;\n    cwd: string;\n    linkInDir?: string;\n    disableDocs: boolean;\n    skipMocking: boolean;\n  },\n  variant?: string\n) {\n  const storiesFolderName = variant ? getStoriesFolderWithVariant(variant) : 'stories';\n  const source = join(CODE_DIRECTORY, packageDir, 'template', storiesFolderName);\n  // By default we link `stories` directories\n  //   e.g '../../../code/lib/preview-api/template/stories' to 'template-stories/lib/preview-api'\n  // if the directory <code>/lib/preview-api/template/stories exists\n  //\n  // The files must be linked in the cwd, in order to ensure that any dependencies they\n  // reference are resolved in the cwd. In particular 'react' resolved by MDX files.\n  const target = linkInDir\n    ? resolve(linkInDir, variant ? getStoriesFolderWithVariant(variant, packageDir) : packageDir)\n    : resolve(cwd, 'template-stories', packageDir);\n\n  await ensureSymlinkOrCopy(source, target);\n\n  if (!linkInDir) {\n    addStoriesEntry(mainConfig, packageDir, disableDocs, skipMocking);\n  }\n\n  // Add `previewAnnotation` entries of the form\n  //   './template-stories/lib/preview-api/preview.[tj]s'\n  // if the file <code>/lib/preview-api/template/stories/preview.[jt]s exists\n  await Promise.all(\n    ['js', 'ts'].map(async (ext) => {\n      const previewFile = `preview.${ext}`;\n      const previewPath = join(\n        CODE_DIRECTORY,\n        packageDir,\n        'template',\n        storiesFolderName,\n        previewFile\n      );\n      if (await pathExists(previewPath)) {\n        let storiesDir = 'template-stories';\n        if (linkInDir) {\n          storiesDir = (await pathExists(join(cwd, 'src/stories'))) ? 'src/stories' : 'stories';\n        }\n        addPreviewAnnotations(mainConfig, [\n          `./${join(storiesDir, variant ? `${packageDir}_${variant}` : packageDir, previewFile)}`,\n        ]);\n      }\n    })\n  );\n}\n\nexport async function setupVitest(details: TemplateDetails, options: PassedOptionValues) {\n  const { sandboxDir } = details;\n  const packageJsonPath = join(sandboxDir, 'package.json');\n  const packageJson = await readJson(packageJsonPath);\n\n  packageJson.scripts = {\n    ...packageJson.scripts,\n    vitest: 'vitest --reporter=default --reporter=hanging-process --test-timeout=5000',\n  };\n\n  // This workaround is needed because Vitest seems to have issues in link mode\n  // so the /setup-file and /global-setup files from the vitest addon won't work in portal protocol\n  if (options.link) {\n    const vitestAddonPath = relative(sandboxDir, join(CODE_DIRECTORY, 'addons', 'vitest'));\n    packageJson.resolutions = {\n      ...packageJson.resolutions,\n      '@storybook/addon-vitest': `file:${vitestAddonPath}`,\n    };\n  }\n\n  await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));\n\n  const opts = { cwd: sandboxDir };\n  const viteConfigFile = await findFirstPath(['vite.config.ts', 'vite.config.js'], opts);\n  const vitestConfigFile = await findFirstPath(['vitest.config.ts', 'vitest.config.js'], opts);\n  const workspaceFile = await findFirstPath(['vitest.workspace.ts', 'vitest.workspace.js'], opts);\n\n  const configFile = workspaceFile || vitestConfigFile || viteConfigFile;\n  if (!configFile) {\n    throw new Error(`No Vitest or Vite config file found in sandbox: ${sandboxDir}`);\n  }\n\n  let fileContent = await readFile(join(sandboxDir, configFile), 'utf-8');\n\n  // Insert resolve: { preserveSymlinks: true } and optionally server.fs.allow as siblings to plugins\n  // Handles both defineConfig({ ... }) and defineWorkspace([ ... , { ... }])\n  fileContent = fileContent.replace(/(plugins\\s*:\\s*\\[[^\\]]*\\],?)/, (match) => {\n    let replacement = `${match}\\n  resolve: {\\n    preserveSymlinks: true\\n  },`;\n\n    // In linked mode, also add server.fs.allow to allow Vite to serve files from the monorepo root\n    if (options.link) {\n      replacement += `\\n  server: {\\n    fs: {\\n      allow: ['../../..']\\n    }\\n  },`;\n    }\n\n    return replacement;\n  });\n\n  // search for storybookTest({...}) and place `tags: 'vitest'` into it but tags option doesn't exist yet in the config. Also consider multi line\n  const storybookTestRegex = /storybookTest\\((\\{[\\s\\S]*?\\})\\)/g;\n  fileContent = fileContent.replace(storybookTestRegex, (match, args) => {\n    // Add tags as the last property before the closing }\n    const lastBraceIndex = args.lastIndexOf('}');\n    if (lastBraceIndex !== -1) {\n      // Insert before the last }\n      const before = args.slice(0, lastBraceIndex).trimEnd();\n      const needsComma = before.endsWith('{') || before.endsWith(',') ? '' : ',';\n      const after = args.slice(lastBraceIndex);\n      return `storybookTest(${before}${needsComma}\\n  tags: {\\n    include: ['vitest']\\n  }\\n${after})`;\n    }\n    // If tags exists and is not empty, or any other case, return as is\n    return match;\n  });\n\n  await writeFile(join(sandboxDir, configFile), fileContent);\n  // Only run story tests which are tagged with 'vitest'\n  const previewConfig = await readConfig({ cwd: sandboxDir, fileName: 'preview' });\n  previewConfig.setFieldValue(['tags'], ['vitest']);\n  await writeConfig(previewConfig);\n}\n\nexport async function addExtraDependencies({\n  cwd,\n  dryRun,\n  debug,\n  extraDeps,\n}: {\n  cwd: string;\n  dryRun: boolean;\n  debug: boolean;\n  extraDeps?: string[];\n}) {\n  const extraDevDeps = ['@storybook/test-runner@latest'];\n\n  if (debug) {\n    logger.log('\\uD83C\\uDF81 Adding extra dev deps', extraDevDeps);\n  }\n\n  if (dryRun) {\n    return;\n  }\n\n  const packageManager = JsPackageManagerFactory.getPackageManager({}, cwd);\n\n  await packageManager.addDependencies(\n    { type: 'devDependencies', skipInstall: true },\n    extraDevDeps\n  );\n\n  if (extraDeps) {\n    const versionedExtraDeps = await packageManager.getVersionedPackages(extraDeps);\n    if (debug) {\n      logger.log('\\uD83C\\uDF81 Adding extra deps', versionedExtraDeps);\n    }\n    await packageManager.addDependencies(\n      { type: 'devDependencies', skipInstall: true },\n      versionedExtraDeps\n    );\n  }\n}\n\nexport const addGlobalMocks: Task['run'] = async ({ sandboxDir }) => {\n  await cp(join(CODE_DIRECTORY, 'core', 'template', '__mocks__'), join(sandboxDir, '__mocks__'), {\n    recursive: true,\n  });\n};\n\nexport const addStories: Task['run'] = async (\n  { sandboxDir, template, key },\n  { addon: extraAddons, disableDocs }\n) => {\n  logger.log('💃 Adding stories');\n  const skipMocking = template.modifications?.skipMocking;\n  const cwd = sandboxDir;\n  const storiesPath =\n    (await findFirstPath([join('src', 'stories'), 'stories'], { cwd })) || 'stories';\n\n  const mainConfig = await readConfig({ fileName: 'main', cwd });\n  const packageManager = JsPackageManagerFactory.getPackageManager({}, sandboxDir);\n\n  // Package manager types differ slightly due to private methods and compilation differences of types\n  const projectTypeService = new ProjectTypeService(packageManager as any);\n\n  // Ensure that we match the right stories in the stories directory\n  updateStoriesField(\n    mainConfig,\n    (await projectTypeService.detectLanguage()) === SupportedLanguage.JAVASCRIPT\n  );\n\n  const isCoreRenderer =\n    template.expected.renderer.startsWith('@storybook/') &&\n    template.expected.renderer !== '@storybook/server';\n\n  const sandboxSpecificStoriesFolder = key.replaceAll('/', '-');\n  const storiesVariantFolder = getStoriesFolderWithVariant(sandboxSpecificStoriesFolder);\n\n  if (isCoreRenderer) {\n    // Link in the template/components/index.js from preview-api, the renderer and the addons\n    const rendererPath = await workspacePath('renderer', template.expected.renderer);\n    await ensureSymlinkOrCopy(\n      join(CODE_DIRECTORY, rendererPath, 'template', 'components'),\n      resolve(cwd, storiesPath, 'components')\n    );\n    addPreviewAnnotations(mainConfig, [`.${sep}${join(storiesPath, 'components')}`]);\n\n    // Add stories for the renderer. NOTE: these *do* need to be processed by the framework build system\n    await linkPackageStories(rendererPath, {\n      mainConfig,\n      cwd,\n      linkInDir: resolve(cwd, storiesPath),\n      disableDocs,\n      skipMocking,\n    });\n\n    if (\n      await pathExists(\n        resolve(CODE_DIRECTORY, rendererPath, join('template', storiesVariantFolder))\n      )\n    ) {\n      await linkPackageStories(\n        rendererPath,\n        {\n          mainConfig,\n          cwd,\n          linkInDir: resolve(cwd, storiesPath),\n          disableDocs,\n          skipMocking,\n        },\n        sandboxSpecificStoriesFolder\n      );\n    }\n  }\n\n  const isCoreFramework = template.expected.framework.startsWith('@storybook/');\n\n  if (isCoreFramework) {\n    const frameworkPath = await workspacePath('frameworks', template.expected.framework);\n\n    // Add stories for the framework if it has one. NOTE: these *do* need to be processed by the framework build system\n    if (await pathExists(resolve(CODE_DIRECTORY, frameworkPath, join('template', 'stories')))) {\n      await linkPackageStories(frameworkPath, {\n        mainConfig,\n        cwd,\n        linkInDir: resolve(cwd, storiesPath),\n        disableDocs,\n        skipMocking,\n      });\n    }\n\n    if (\n      await pathExists(\n        resolve(CODE_DIRECTORY, frameworkPath, join('template', storiesVariantFolder))\n      )\n    ) {\n      await linkPackageStories(\n        frameworkPath,\n        {\n          mainConfig,\n          cwd,\n          linkInDir: resolve(cwd, storiesPath),\n          disableDocs,\n          skipMocking,\n        },\n        sandboxSpecificStoriesFolder\n      );\n    }\n  }\n\n  if (isCoreRenderer) {\n    // Add stories for lib/preview-api (and addons below). NOTE: these stories will be in the\n    // template-stories folder and *not* processed by the framework build config (instead by esbuild-loader)\n    await linkPackageStories(await workspacePath('core package', 'storybook'), {\n      mainConfig,\n      cwd,\n      disableDocs,\n      skipMocking,\n    });\n\n    await linkPackageStories(await workspacePath('addon test package', '@storybook/addon-vitest'), {\n      mainConfig,\n      cwd,\n      disableDocs,\n      skipMocking,\n    });\n  }\n\n  const mainAddons = (mainConfig.getSafeFieldValue(['addons']) || []).reduce(\n    (acc: string[], addon: any) => {\n      const name = typeof addon === 'string' ? addon : addon.name;\n      const match = /@storybook\\/addon-(.*)/.exec(name);\n\n      if (!match) {\n        return acc;\n      }\n      const suffix = match[1];\n      if (suffix === 'essentials') {\n        const essentials = disableDocs\n          ? essentialsAddons.filter((a) => a !== 'docs')\n          : essentialsAddons;\n        return [...acc, ...essentials];\n      }\n      return [...acc, suffix];\n    },\n    []\n  );\n\n  const addonDirs = await Promise.all(\n    [...mainAddons, ...extraAddons]\n      // only include addons that are in the monorepo\n      .filter((addon: string) =>\n        Object.keys(storybookPackages).find((pkg: string) => pkg === `@storybook/addon-${addon}`)\n      )\n      .filter((addon: string) => {\n        // RSBUILD frameworks are not configured to ignore docs addon stories, which are React based\n        if (\n          template.expected.framework === 'storybook-vue3-rsbuild' ||\n          template.expected.framework === 'storybook-web-components-rsbuild' ||\n          template.expected.framework === 'storybook-html-rsbuild'\n        ) {\n          return addon !== 'docs';\n        }\n        return true;\n      })\n      .map(async (addon) => workspacePath('addon', `@storybook/addon-${addon}`))\n  );\n\n  if (isCoreRenderer) {\n    const existingStories = await filterExistsInCodeDir(addonDirs, join('template', 'stories'));\n    for (const packageDir of existingStories) {\n      await linkPackageStories(packageDir, { mainConfig, cwd, disableDocs, skipMocking });\n    }\n\n    // Add some extra settings (see above for what these do)\n    if (template.expected.builder === '@storybook/builder-webpack5') {\n      addEsbuildLoaderToStories(mainConfig);\n    }\n  }\n\n  await writeConfig(mainConfig);\n};\n\nexport const extendMain: Task['run'] = async ({ template, sandboxDir, key }, { disableDocs }) => {\n  logger.log('📝 Extending main.js');\n  const mainConfig = await readConfig({ fileName: 'main', cwd: sandboxDir });\n\n  const templateConfig: any = isFunction(template.modifications?.mainConfig)\n    ? template.modifications?.mainConfig(mainConfig)\n    : template.modifications?.mainConfig || {};\n  const configToAdd = {\n    ...templateConfig,\n    features: {\n      ...templateConfig.features,\n    },\n    ...(template.modifications?.editAddons\n      ? {\n          addons: template.modifications?.editAddons(mainConfig.getFieldValue(['addons']) || []),\n        }\n      : {}),\n    core: {\n      ...templateConfig.core,\n      // We don't want to show the \"What's new\" notifications in the sandbox as it can affect E2E tests\n      disableWhatsNewNotifications: true,\n    },\n  };\n\n  Object.entries(configToAdd).forEach(([field, value]) => mainConfig.setFieldValue([field], value));\n\n  const previewHeadCode = `\n    (head) => \\`\n      \\${head}\n      ${templateConfig.previewHead || ''}\n      <style>\n        /* explicitly set monospace font stack to workaround inconsistent fonts in Chromatic */\n        pre, code, kbd, samp {\n          font-family:\n            ui-monospace,\n            Menlo,\n            Monaco,\n            \"Cascadia Mono\",\n            \"Segoe UI Mono\",\n            \"Roboto Mono\",\n            \"Oxygen Mono\",\n            \"Ubuntu Monospace\",\n            \"Source Code Pro\",\n            \"Fira Mono\",\n            \"Droid Sans Mono\",\n            \"Courier New\",\n            monospace;\n        }\n      </style>\n    \\``;\n  // @ts-expect-error (Property 'expression' does not exist on type 'BlockStatement')\n  mainConfig.setFieldNode(['previewHead'], babelParse(previewHeadCode).program.body[0].expression);\n\n  // Simulate Storybook Lite\n  if (disableDocs) {\n    const addons = mainConfig.getFieldValue(['addons']);\n    const addonsNoDocs = addons.filter((addon: any) => addon !== '@storybook/addon-docs');\n    mainConfig.setFieldValue(['addons'], addonsNoDocs);\n\n    // remove the docs options so that docs tags are ignored\n    mainConfig.setFieldValue(['docs'], {});\n    mainConfig.setFieldValue(['typescript'], { reactDocgen: false });\n\n    let updatedStories = mainConfig.getFieldValue(['stories']) as string[];\n    updatedStories = updatedStories.filter((specifier) => !specifier.endsWith('.mdx'));\n    mainConfig.setFieldValue(['stories'], updatedStories);\n  }\n\n  if (template.expected.builder === '@storybook/builder-vite') {\n    setSandboxViteFinal(mainConfig, key);\n  }\n  await writeConfig(mainConfig);\n};\n\nexport const extendPreview: Task['run'] = async ({ template, sandboxDir }) => {\n  logger.log('📝 Extending preview.js');\n  const previewConfig = await readConfig({ cwd: sandboxDir, fileName: 'preview' });\n\n  if (template.modifications?.useCsfFactory) {\n    const storiesDir = (await pathExists(join(sandboxDir, 'src/stories')))\n      ? '../src/stories/components'\n      : '../stories/components';\n    previewConfig.setImport(null, storiesDir);\n    if (template.expected.renderer === '@storybook/vue3') {\n      previewConfig.setImport(null, '../src/stories/renderers/vue3/preview.js');\n    }\n    previewConfig.setImport(\n      { namespace: 'templateAnnotations' },\n      '../template-stories/core/preview'\n    );\n    previewConfig.appendNodeToArray(['addons'], t.identifier('templateAnnotations'));\n  }\n\n  if (template.expected.builder.includes('vite')) {\n    previewConfig.setFieldValue(['tags'], ['vitest']);\n  }\n\n  const isCoreRenderer =\n    template.expected.renderer.startsWith('@storybook/') &&\n    template.expected.renderer !== '@storybook/server';\n\n  if (template.modifications?.skipMocking || !isCoreRenderer) {\n    await writeConfig(previewConfig);\n    return;\n  }\n\n  previewConfig.setImport(['sb'], 'storybook/test');\n  let config = formatConfig(previewConfig);\n\n  const mockBlock = [\n    \"sb.mock('../template-stories/core/test/ModuleMocking.utils.ts');\",\n    \"sb.mock('../template-stories/core/test/ModuleSpyMocking.utils.ts', { spy: true });\",\n    \"sb.mock('../template-stories/core/test/ModuleAutoMocking.utils.ts');\",\n    \"sb.mock('../template-stories/core/test/ClearModuleMocksMocking.api.ts', { spy: true });\",\n    \"sb.mock(import('lodash-es'));\",\n    \"sb.mock(import('lodash-es/add'));\",\n    \"sb.mock(import('lodash-es/sum'));\",\n    \"sb.mock(import('uuid'));\",\n    '',\n  ].join('\\n');\n\n  // find last import statement and append sb.mock calls\n  config = config.replace(\n    'import { sb } from \"storybook/test\";',\n    `import { sb } from 'storybook/test';\\n\\n${mockBlock}`\n  );\n\n  await writeFile(previewConfig.fileName, config);\n};\n\nexport const runMigrations: Task['run'] = async ({ sandboxDir, template }, { dryRun, debug }) => {\n  if (template.modifications?.useCsfFactory) {\n    await executeCLIStep(steps.automigrate, {\n      cwd: sandboxDir,\n      argument: 'csf-factories',\n      dryRun,\n      debug,\n      env: {\n        STORYBOOK_PROJECT_ROOT: sandboxDir,\n      },\n    });\n  }\n};\n\nexport async function setImportMap(cwd: string) {\n  const packageJson = await readJson(join(cwd, 'package.json'));\n\n  packageJson.imports = {\n    '#utils': {\n      storybook: './template-stories/core/utils.mock.ts',\n      default: './template-stories/core/utils.ts',\n    },\n  };\n\n  await writeFile(join(cwd, 'package.json'), JSON.stringify(packageJson, null, 2));\n}\n\nasync function prepareReactNativeWebSandbox(cwd: string) {\n  // Make it so that RN sandboxes have stories in src/stories similar to\n  // other react sandboxes, for consistency.\n  if (!(await pathExists(join(cwd, 'src')))) {\n    await mkdir(join(cwd, 'src'));\n  }\n}\n\nasync function prepareSvelteSandbox(cwd: string) {\n  const svelteConfigJsPath = join(cwd, 'svelte.config.js');\n  const svelteConfigTsPath = join(cwd, 'svelte.config.ts');\n\n  // Check which config file exists\n  const configPath = (await pathExists(svelteConfigTsPath))\n    ? svelteConfigTsPath\n    : (await pathExists(svelteConfigJsPath))\n      ? svelteConfigJsPath\n      : null;\n\n  if (!configPath) {\n    throw new Error(\n      `No svelte.config.js or svelte.config.ts found in sandbox: ${cwd}, cannot modify config.`\n    );\n  }\n\n  const svelteConfig = await csfReadConfig(configPath);\n\n  // Enable async components\n  // see https://svelte.dev/docs/svelte/await-expressions\n  svelteConfig.setFieldValue(['compilerOptions', 'experimental', 'async'], true);\n\n  // Enable remote functions\n  // see https://svelte.dev/docs/kit/remote-functions\n  svelteConfig.setFieldValue(['kit', 'experimental', 'remoteFunctions'], true);\n\n  await writeConfig(svelteConfig);\n}\n\n/**\n * Prepare a sandbox for typechecking.\n *\n * 1. Add a typecheck script\n * 2. Ensure typescript compiler options compatible with our example code\n * 3. Set skipLibCheck to false to test storybook's public types\n *\n * This is currently configured for manipulating the output of `create vite` so will need some\n * adjustment when we extend to type checking webpack sandboxes (if we ever do).\n */\nasync function prepareTypeChecking(cwd: string) {\n  const packageJsonPath = join(cwd, 'package.json');\n  const packageJson = await readJson(packageJsonPath);\n\n  packageJson.scripts = {\n    ...packageJson.scripts,\n    typecheck: 'yarn tsc -p tsconfig.app.json',\n  };\n  await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));\n\n  const tsConfigPath = join(cwd, 'tsconfig.app.json');\n  const tsConfigContent = await readFile(tsConfigPath, { encoding: 'utf-8' });\n  // This does not preserve comments, but that shouldn't be an issue for sandboxes\n  const tsConfigJson = JSON5.parse(tsConfigContent);\n\n  // We use enums\n  tsConfigJson.compilerOptions.erasableSyntaxOnly = false;\n  // Lots of unnecessary imports of react that need fixing\n  tsConfigJson.compilerOptions.noUnusedLocals = false;\n  // This is much better done by eslint\n  tsConfigJson.compilerOptions.noUnusedParameters = false;\n  // Means we can check our own public types\n  tsConfigJson.compilerOptions.skipLibCheck = false;\n  // Add chai global types\n  (tsConfigJson.compilerOptions.types ??= []).push('chai');\n  await writeFile(tsConfigPath, JSON.stringify(tsConfigJson, null, 2));\n}\n\nasync function prepareAngularSandbox(cwd: string, templateName: string) {\n  const angularJson = await readJson(join(cwd, 'angular.json'));\n\n  Object.keys(angularJson.projects).forEach((projectName: string) => {\n    /**\n     * Sets compodoc option in angular.json projects to false. We have to generate compodoc manually\n     * to avoid symlink issues related to the template-stories folder. In a second step a docs:json\n     * script is placed into the package.json to generate the Compodoc documentation.json, which\n     * respects symlinks\n     */\n    angularJson.projects[projectName].architect.storybook.options.compodoc = false;\n    angularJson.projects[projectName].architect['build-storybook'].options.compodoc = false;\n    /**\n     * Sets preserveSymlinks option in angular.json projects to true. This is necessary to respect\n     * symlinks so that Angular doesn't complain about wrong types in @storybook/* packages\n     */\n    angularJson.projects[projectName].architect.storybook.options.preserveSymlinks = true;\n    angularJson.projects[projectName].architect['build-storybook'].options.preserveSymlinks = true;\n  });\n\n  await writeFile(join(cwd, 'angular.json'), JSON.stringify(angularJson, null, 2));\n\n  const packageJsonPath = join(cwd, 'package.json');\n  const packageJson = await readJson(packageJsonPath);\n\n  packageJson.scripts = {\n    ...packageJson.scripts,\n    'docs:json': `DIR=$PWD; yarn --cwd ${join(ROOT_DIRECTORY, 'scripts')} jiti combine-compodoc $DIR`,\n    storybook: `yarn docs:json && ${packageJson.scripts.storybook}`,\n    'build-storybook': `yarn docs:json && ${packageJson.scripts['build-storybook']}`,\n  };\n\n  await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));\n\n  // Set tsConfig compilerOptions\n\n  const tsConfigPath = join(cwd, '.storybook', 'tsconfig.json');\n  const tsConfigContent = await readFile(tsConfigPath, { encoding: 'utf-8' });\n  // This does not preserve comments, but that shouldn't be an issue for sandboxes\n  const tsConfigJson = JSON5.parse(tsConfigContent);\n\n  tsConfigJson.compilerOptions.noImplicitOverride = false;\n  tsConfigJson.compilerOptions.noPropertyAccessFromIndexSignature = false;\n  tsConfigJson.compilerOptions.jsx = 'react';\n  tsConfigJson.compilerOptions.skipLibCheck = true;\n  tsConfigJson.compilerOptions.noImplicitAny = false;\n  tsConfigJson.compilerOptions.strict = false;\n  tsConfigJson.include = [\n    ...tsConfigJson.include,\n    '../template-stories/**/*.stories.ts',\n    // This is necessary since template stories depend on globalThis.__TEMPLATE_COMPONENTS__, which Typescript can't look up automatically\n    '../src/stories/**/*',\n  ];\n\n  if (templateName === 'Angular CLI (Version 15)') {\n    tsConfigJson.compilerOptions.paths = {\n      '@angular-devkit/*': ['node_modules/@angular-devkit/*'],\n    };\n  }\n\n  await writeFile(tsConfigPath, JSON.stringify(tsConfigJson, null, 2));\n}\n"
  },
  {
    "path": "scripts/tasks/sandbox.ts",
    "content": "import { access, cp, rm } from 'node:fs/promises';\nimport path, { join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport dirSize from 'fast-folder-size';\n\nimport { now, saveBench } from '../bench/utils.ts';\nimport type { Task, TaskKey } from '../task.ts';\nimport { ROOT_DIRECTORY, SANDBOX_DIRECTORY } from '../utils/constants.ts';\nimport { isNxTaskExecution } from '../utils/nx.ts';\n\nconst logger = console;\n\nconst pathExists = async (path: string) => {\n  try {\n    await access(path);\n    return true;\n  } catch {\n    return false;\n  }\n};\n\nexport const sandbox: Task = {\n  description: 'Create the sandbox from a template',\n  dependsOn: ({ template, key }, { link }) => {\n    if ('inDevelopment' in template && template.inDevelopment) {\n      if (pathExists(join(SANDBOX_DIRECTORY, key))) {\n        return ['run-registry'];\n      }\n\n      return ['run-registry', 'generate'];\n    }\n\n    if (link) {\n      return ['compile'];\n    }\n\n    return ['run-registry'];\n  },\n  async ready({ sandboxDir }, { task: selectedTask }) {\n    // If the selected task requires the sandbox to exist, we check it. Else we always assume it needs to be created\n    // This avoids issues where you want to overwrite a sandbox and it will stop because it already exists\n    const tasksAfterSandbox: TaskKey[] = [\n      'vitest-integration',\n      'test-runner',\n      'test-runner-dev',\n      'e2e-tests',\n      'e2e-tests-dev',\n      'smoke-test',\n      'dev',\n      'build',\n      'serve',\n      'chromatic',\n      'bench',\n      'check-sandbox',\n    ];\n    const isSelectedTaskAfterSandboxCreation = tasksAfterSandbox.includes(selectedTask);\n    return isSelectedTaskAfterSandboxCreation && pathExists(sandboxDir);\n  },\n  async run(details, options) {\n    if (options.link && details.template.inDevelopment) {\n      logger.log(\n        `The ${options.template} has inDevelopment property enabled, therefore the sandbox for that template cannot be linked. Enabling --no-link mode..`\n      );\n\n      options.link = false;\n    }\n\n    if (!(await this.ready(details, options))) {\n      logger.info('🗑  Removing old sandbox dir');\n      await rm(details.sandboxDir, { force: true, recursive: true });\n    }\n\n    const {\n      create,\n      install,\n      addGlobalMocks,\n      addStories,\n      extendMain,\n      extendPreview,\n      init,\n      addExtraDependencies,\n      setImportMap,\n      setupVitest,\n      runMigrations,\n    } = await import('./sandbox-parts.ts');\n\n    const extraDeps = [\n      ...(details.template.modifications?.extraDependencies ?? []),\n      // The storybook package forwards some CLI commands to @storybook/cli with npx.\n      // Adding the dep makes sure that even npx will use the linked workspace version.\n      '@storybook/cli',\n      'lodash-es',\n      '@types/lodash-es',\n      '@types/aria-query',\n      'uuid',\n    ];\n\n    const shouldAddVitestIntegration = !details.template.skipTasks?.includes('vitest-integration');\n\n    if (shouldAddVitestIntegration) {\n      extraDeps.push('happy-dom');\n\n      if (details.template.expected.framework.includes('nextjs')) {\n        extraDeps.push('jsdom');\n      }\n\n      // if (details.template.expected.renderer === '@storybook/svelte') {\n      //   extraDeps.push(`@testing-library/svelte`);\n      // }\n      //\n      // if (details.template.expected.framework === '@storybook/angular') {\n      //   extraDeps.push('@testing-library/angular', '@analogjs/vitest-angular');\n      // }\n    }\n\n    let startTime = now();\n    await create(details, options);\n    const createTime = now() - startTime;\n    const createSize = 0;\n\n    startTime = now();\n    await install(details, options);\n    const generateTime = now() - startTime;\n    const generateSize = await promisify(dirSize)(join(details.sandboxDir, 'node_modules'));\n\n    startTime = now();\n    await init(details, options);\n    const initTime = now() - startTime;\n    const initSize = await promisify(dirSize)(join(details.sandboxDir, 'node_modules'));\n\n    await saveBench(\n      'sandbox',\n      {\n        createTime,\n        generateTime,\n        initTime,\n        createSize,\n        generateSize,\n        initSize,\n        diffSize: initSize - generateSize,\n      },\n      { rootDir: details.sandboxDir }\n    );\n\n    if (!options.skipTemplateStories) {\n      await addStories(details, options);\n    }\n\n    // not if sandbox is bench\n    if (!details.template.modifications?.skipMocking) {\n      await addGlobalMocks(details, options);\n    }\n\n    if (shouldAddVitestIntegration) {\n      await setupVitest(details, options);\n    }\n\n    await addExtraDependencies({\n      cwd: details.sandboxDir,\n      debug: options.debug,\n      dryRun: options.dryRun,\n      extraDeps,\n    });\n\n    await extendMain(details, options);\n\n    await setImportMap(details.sandboxDir);\n\n    const { JsPackageManagerFactory } =\n      await import('../../code/core/src/common/js-package-manager/JsPackageManagerFactory.ts');\n\n    const packageManager = JsPackageManagerFactory.getPackageManager({}, details.sandboxDir);\n\n    await rm(path.join(details.sandboxDir, 'node_modules'), { force: true, recursive: true });\n    await packageManager.installDependencies();\n\n    await runMigrations(details, options);\n\n    await extendPreview(details, options);\n\n    // For NX we move the sandbox to a directory that can be cached.\n    // We remove node_modules to keep the remote cache small and fast\n    // node_modules are already cached in the global yarn cache\n    if (isNxTaskExecution()) {\n      logger.info('✅ Moving sandbox to cache directory');\n      const sandboxDir = join(details.sandboxDir);\n      const cacheDir = join(ROOT_DIRECTORY, 'sandbox', details.key.replace('/', '-'));\n\n      if (sandboxDir !== cacheDir) {\n        logger.info(`✅ Removing cache directory ${cacheDir}`);\n        await rm(cacheDir, { recursive: true, force: true });\n\n        logger.info(`✅ Copy ${sandboxDir} to cache directory`);\n        await cp(sandboxDir, cacheDir, {\n          recursive: true,\n          force: true,\n          filter: (src) => {\n            const name = path.basename(src);\n            return (\n              name !== 'node_modules' &&\n              !(name === 'cache' && path.basename(path.dirname(src)) === '.yarn')\n            );\n          },\n        });\n      } else {\n        logger.info(`✅ Removing node_modules from cache directory ${cacheDir}`);\n        await rm(path.join(cacheDir, 'node_modules'), { force: true, recursive: true });\n        await rm(path.join(cacheDir, '.yarn', 'cache'), { force: true, recursive: true });\n      }\n    }\n\n    logger.info(`✅ Storybook sandbox created at ${details.sandboxDir}`);\n  },\n};\n"
  },
  {
    "path": "scripts/tasks/serve.ts",
    "content": "import waitOn from 'wait-on';\n\nimport type { AllTemplatesKey } from '../../code/lib/cli-storybook/src/sandbox-templates.ts';\nimport { getPort } from '../sandbox/utils/getPort.ts';\nimport { type Task } from '../task.ts';\nimport { ROOT_DIRECTORY } from '../utils/constants.ts';\nimport { exec } from '../utils/exec.ts';\nimport { isNxTaskExecution } from '../utils/nx.ts';\nimport { prepareSandbox } from '../prepare-sandbox.ts';\n\nexport const PORT = process.env.STORYBOOK_SERVE_PORT\n  ? parseInt(process.env.STORYBOOK_SERVE_PORT, 10)\n  : 8001;\n\nfunction getServePort(key: AllTemplatesKey) {\n  return isNxTaskExecution() ? getPort({ selectedTask: 'serve', key }) : PORT;\n}\n\nexport const serve: Task = {\n  description: 'Serve the build storybook for a sandbox',\n  service: true,\n  dependsOn: ['build'],\n  async ready({ key }) {\n    const port = getServePort(key);\n    try {\n      await fetch(`http://localhost:${port}/iframe.html`, { signal: AbortSignal.timeout(1000) });\n      return true;\n    } catch {\n      return false;\n    }\n  },\n  async run({ builtSandboxDir, key }, { debug, dryRun, link }) {\n    await prepareSandbox({ key, link });\n    const port = getServePort(key);\n\n    const controller = new AbortController();\n    exec(\n      `yarn http-server ${builtSandboxDir} --port ${port} -s`,\n      { cwd: ROOT_DIRECTORY },\n      { dryRun, debug, signal: controller.signal as AbortSignal }\n    ).catch((err) => {\n      // If aborted, we want to make sure the rejection is handled.\n      if (!err.killed) {\n        throw err;\n      }\n    });\n    await waitOn({ resources: [`tcp:127.0.0.1:${port}`], interval: 16, timeout: 200000 });\n\n    return controller;\n  },\n};\n"
  },
  {
    "path": "scripts/tasks/smoke-test.ts",
    "content": "import type { Task } from '../task.ts';\nimport { exec } from '../utils/exec.ts';\n\nexport const smokeTest: Task = {\n  description: 'Run the smoke tests of a sandbox',\n  dependsOn: ['sandbox'],\n  async ready() {\n    return false;\n  },\n  async run({ sandboxDir }, { dryRun, debug }) {\n    console.log(`smoke testing in ${sandboxDir}`);\n\n    return exec(`yarn storybook --smoke-test`, { cwd: sandboxDir }, { dryRun, debug });\n  },\n};\n"
  },
  {
    "path": "scripts/tasks/sync-docs.ts",
    "content": "import {\n  closeSync,\n  copyFile,\n  cpSync,\n  existsSync,\n  mkdirSync,\n  openSync,\n  rmSync,\n  unlinkSync,\n  watch,\n} from 'node:fs';\nimport { join } from 'node:path';\n\nimport type { Task } from '../task.ts';\nimport { ask } from '../utils/ask.ts';\n\nconst logger = console;\n\nexport const syncDocs: Task = {\n  description: 'Synchronize documentation',\n  service: true,\n  async ready() {\n    return false;\n  },\n  async run() {\n    const rootDir = join(__dirname, '..', '..');\n    const docsDir = join(rootDir, 'docs');\n    let frontpageDocsPath = '/src/content/docs';\n\n    const frontpagePath = await ask('Provide the frontpage project path:');\n    frontpageDocsPath = join(rootDir, frontpagePath, frontpageDocsPath);\n\n    if (!existsSync(frontpageDocsPath)) {\n      mkdirSync(frontpageDocsPath);\n    }\n\n    logger.info(`Rebuilding docs at ${frontpageDocsPath}`);\n\n    rmSync(frontpageDocsPath, { recursive: true });\n    cpSync(docsDir, frontpageDocsPath, { recursive: true });\n\n    logger.info(`Synchronizing files from: \\n${docsDir} \\nto: \\n${frontpageDocsPath}`);\n\n    watch(docsDir, { recursive: true }, (_, filename) => {\n      const srcFilePath = join(docsDir, filename);\n      const targetFilePath = join(frontpageDocsPath, filename);\n      const targetDir = targetFilePath.split('/').slice(0, -1).join('/');\n\n      // Syncs create file\n      if (!existsSync(targetFilePath)) {\n        mkdirSync(targetDir, { recursive: true });\n        closeSync(openSync(targetFilePath, 'w'));\n        logger.info(`Created ${filename}.`);\n      }\n\n      // Syncs remove file\n      if (!existsSync(srcFilePath)) {\n        unlinkSync(targetFilePath);\n        logger.info(`Removed ${filename}.`);\n        return;\n      }\n\n      // Syncs update file\n      copyFile(srcFilePath, targetFilePath, (err) => {\n        logger.info(`Updated ${filename}.`);\n\n        if (err) {\n          throw err;\n        }\n      });\n    });\n  },\n};\n"
  },
  {
    "path": "scripts/tasks/test-runner-build.ts",
    "content": "import waitOn from 'wait-on';\n\nimport { getPort } from '../sandbox/utils/getPort.ts';\nimport type { Task } from '../task.ts';\nimport { exec } from '../utils/exec.ts';\nimport { isNxTaskExecution } from '../utils/nx.ts';\nimport { PORT } from './serve.ts';\n\nexport const testRunnerBuild: Task & { port: number } = {\n  description: 'Run the test runner against a built sandbox',\n  junit: true,\n  dependsOn: ['serve'],\n  port: PORT,\n  async ready() {\n    return false;\n  },\n  async run({ sandboxDir, junitFilename, key, selectedTask }, { dryRun, debug }) {\n    const port = isNxTaskExecution()\n      ? getPort({ key, selectedTask: selectedTask === 'test-runner' ? 'serve' : 'dev' })\n      : this.port;\n\n    const execOptions = { cwd: sandboxDir };\n    const flags = [\n      `--url http://localhost:${port}`,\n      '--junit',\n      '--maxWorkers=1',\n      '--failOnConsole',\n      '--index-json',\n    ];\n\n    await waitOn({ resources: [`http://localhost:${port}`], interval: 16, timeout: 200000 });\n\n    await exec(\n      `yarn test-storybook ${flags.join(' ')}`,\n      {\n        ...execOptions,\n        env: {\n          JEST_JUNIT_OUTPUT_FILE: junitFilename,\n          TEST_ROOT: sandboxDir,\n        },\n      },\n      { dryRun, debug }\n    );\n  },\n};\n"
  },
  {
    "path": "scripts/tasks/test-runner-dev.ts",
    "content": "import { PORT } from './dev.ts';\nimport { testRunnerBuild as testRunnerProd } from './test-runner-build.ts';\n\nexport const testRunnerDev: typeof testRunnerProd = {\n  ...testRunnerProd,\n  port: PORT,\n  description: 'Run the test runner against a sandbox in dev mode',\n  dependsOn: ['dev'],\n};\n"
  },
  {
    "path": "scripts/tasks/vitest-test.ts",
    "content": "import type { Task } from '../task.ts';\nimport { exec } from '../utils/exec.ts';\nimport { prepareSandbox } from '../prepare-sandbox.ts';\n\nexport const vitestTests: Task = {\n  description: 'Run the Vitest tests of a sandbox',\n  dependsOn: ['sandbox'],\n  async ready() {\n    return false;\n  },\n  async run({ sandboxDir, key }, { dryRun, debug, link }) {\n    await prepareSandbox({ key, link });\n    console.log(`running Vitest tests in ${sandboxDir}`);\n\n    return exec(`yarn vitest run --testTimeout=15000`, { cwd: sandboxDir }, { dryRun, debug });\n  },\n};\n"
  },
  {
    "path": "scripts/tsconfig.json",
    "content": "{\n  \"compileOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"noEmit\": true,\n    \"incremental\": false,\n    \"noImplicitAny\": true,\n    \"allowJs\": true,\n    \"checkJs\": true,\n    \"jsx\": \"react\",\n    \"moduleResolution\": \"bundler\",\n    \"target\": \"ESNext\",\n    \"module\": \"Preserve\",\n    \"skipLibCheck\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"isolatedModules\": true,\n    \"allowImportingTsExtensions\": true,\n    \"strictBindCallApply\": true,\n    \"lib\": [\"ESNext\"],\n    \"types\": [\"node\"],\n    \"strict\": true,\n    \"strictNullChecks\": false,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"noImplicitReturns\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"resolveJsonModule\": true\n  },\n  \"exclude\": [\"dist\", \"**/dist\", \"node_modules\", \"**/node_modules\"],\n  \"include\": [\"./**/*\", \"./.eslintrc.cjs\"]\n}\n"
  },
  {
    "path": "scripts/upload-bench.ts",
    "content": "import { BigQuery } from '@google-cloud/bigquery';\n// eslint-disable-next-line depend/ban-dependencies\nimport { execaCommand } from 'execa';\nimport { join } from 'path';\n\nimport type { BenchResults } from './bench/types.ts';\nimport { loadBench } from './bench/utils.ts';\nimport { SANDBOX_DIRECTORY } from './utils/constants.ts';\n\nconst templateKey = process.argv[2];\nconst prNumber = process.argv[3];\nconst baseBranch = process.argv[4];\n\nconst GCP_CREDENTIALS = JSON.parse(process.env.GCP_CREDENTIALS || '{}');\nconst sandboxDir = SANDBOX_DIRECTORY;\nconst templateSandboxDir = templateKey && join(sandboxDir, templateKey.replace('/', '-'));\n\nconst defaults: Record<keyof BenchResults, null> = {\n  branch: null,\n  commit: null,\n  timestamp: null,\n  label: null,\n\n  createTime: null,\n  generateTime: null,\n  initTime: null,\n  createSize: null,\n  generateSize: null,\n  initSize: null,\n  diffSize: null,\n  buildTime: null,\n  buildSize: null,\n  buildSbAddonsSize: null,\n  buildSbCommonSize: null,\n  buildSbManagerSize: null,\n  buildSbPreviewSize: null,\n  buildStaticSize: null,\n  buildPrebuildSize: null,\n  buildPreviewSize: null,\n  testBuildTime: null,\n  testBuildSize: null,\n  testBuildSbAddonsSize: null,\n  testBuildSbCommonSize: null,\n  testBuildSbManagerSize: null,\n  testBuildSbPreviewSize: null,\n  testBuildStaticSize: null,\n  testBuildPrebuildSize: null,\n  testBuildPreviewSize: null,\n  devPreviewResponsive: null,\n  devManagerResponsive: null,\n  devManagerHeaderVisible: null,\n  devManagerIndexVisible: null,\n  devStoryVisible: null,\n  devStoryVisibleUncached: null,\n  devAutodocsVisible: null,\n  devMDXVisible: null,\n  buildManagerHeaderVisible: null,\n  buildManagerIndexVisible: null,\n  buildAutodocsVisible: null,\n  buildStoryVisible: null,\n  buildMDXVisible: null,\n};\n\nconst uploadBench = async () => {\n  const results = await loadBench({ rootDir: templateSandboxDir });\n\n  const row = {\n    ...defaults,\n    branch: await getBranchName(),\n    commit: await getCommitHash(),\n    timestamp: new Date().toISOString(),\n    label: templateKey,\n    ...results,\n  } as BenchResults;\n\n  const store = new BigQuery({\n    projectId: GCP_CREDENTIALS.project_id,\n    credentials: GCP_CREDENTIALS,\n  });\n  const dataset = store.dataset('benchmark_results');\n  const appTable = dataset.table('bench2');\n\n  async function uploadToGithub() {\n    if (\n      !prNumber ||\n      !baseBranch ||\n      prNumber === '0' ||\n      templateKey !== 'bench/react-vite-default-ts'\n    ) {\n      console.log('skip uploading results to github');\n      return;\n    }\n    const [base]: any[] = await appTable.query({\n      query: `SELECT * FROM \\`storybook-benchmark.benchmark_results.bench2\\` WHERE branch=@baseBranch AND label=@templateKey ORDER BY timestamp DESC LIMIT 20;`,\n      params: { baseBranch, templateKey },\n    });\n\n    return prNumber && prNumber !== '0'\n      ? fetch('https://storybook-benchmark-bot.netlify.app/description', {\n          method: 'POST',\n          body: JSON.stringify({\n            owner: 'storybookjs',\n            repo: 'storybook',\n            issueNumber: prNumber,\n            base: base.map((b: any) => ({ ...defaults, ...b })),\n            head: row,\n          }),\n        })\n      : Promise.resolve();\n  }\n\n  function uploadToBigQuery() {\n    return appTable.insert([row]);\n  }\n\n  await Promise.all([uploadToGithub(), uploadToBigQuery()]);\n};\n\nuploadBench()\n  .catch((err) => {\n    console.error(err);\n    if (err.errors) {\n      err.errors.forEach((elt: any) => {\n        console.log(elt);\n      });\n    }\n    process.exit(1);\n  })\n  .then(() => {\n    console.log('done');\n  });\n\nasync function getCommitHash(): Promise<string> {\n  return (\n    process.env.CIRCLE_SHA1 || (await execaCommand('git rev-parse HEAD', { cleanup: true })).stdout\n  );\n}\n\nasync function getBranchName(): Promise<string> {\n  return (\n    process.env.CIRCLE_BRANCH ||\n    (await execaCommand('git rev-parse --abbrev-ref HEAD', { cleanup: true })).stdout\n  );\n}\n"
  },
  {
    "path": "scripts/utils/ask.ts",
    "content": "import readline from 'readline';\n\nexport const ask = (query: string) => {\n  const rl = readline.createInterface({\n    input: process.stdin,\n    output: process.stdout,\n  });\n\n  return new Promise<string>((resolve) =>\n    rl.question(`${query}\\n`, (ans) => {\n      rl.close();\n      resolve(ans);\n    })\n  );\n};\n"
  },
  {
    "path": "scripts/utils/cli-step.ts",
    "content": "import { createRequire } from 'module';\n\nimport { exec } from './exec.ts';\nimport type { OptionSpecifier, OptionValues } from './options.ts';\nimport { createOptions, getCommand } from './options.ts';\n\nconst require = createRequire(import.meta.url);\nconst cliExecutable = require.resolve('../../code/core/dist/bin/dispatcher.js');\nconst toolboxExecutable = require.resolve('../../code/lib/cli-storybook/dist/bin/index.js');\nconst createStorybookExecutable =\n  require.resolve('../../code/lib/create-storybook/dist/bin/index.js');\n\nexport type CLIStep<TOptions extends OptionSpecifier> = {\n  command: string;\n  description: string;\n  hasArgument?: boolean;\n  icon: string;\n  // It would be kind of great to be able to share these with `lib/cli/src/generate.ts`\n  options: TOptions;\n};\n\nexport const steps = {\n  repro: {\n    command: 'repro',\n    description: 'Bootstrapping Template',\n    icon: '👷',\n    hasArgument: true,\n    options: createOptions({\n      output: { type: 'string' },\n      // TODO allow default values for strings\n      branch: { type: 'string', values: ['main', 'next'] },\n      loglevel: { type: 'string' },\n      init: { type: 'boolean', inverse: true },\n      debug: { type: 'boolean' },\n    }),\n  },\n  init: {\n    command: 'init',\n    description: 'Initializing Storybook',\n    icon: '⚙️',\n    options: createOptions({\n      yes: { type: 'boolean' },\n      type: { type: 'string' },\n      loglevel: { type: 'string' },\n      builder: { type: 'string' },\n      'skip-install': { type: 'boolean' },\n    }),\n  },\n  add: {\n    command: 'add',\n    description: 'Adding addon',\n    icon: '+',\n    hasArgument: true,\n    options: createOptions({\n      yes: { type: 'boolean' },\n    }),\n  },\n  link: {\n    command: 'link',\n    description: 'Linking packages',\n    icon: '🔗',\n    hasArgument: true,\n    options: createOptions({\n      local: { type: 'boolean' },\n      start: { type: 'boolean', inverse: true },\n    }),\n  },\n  build: {\n    command: 'build',\n    description: 'Building Storybook',\n    icon: '🔨',\n    options: createOptions({}),\n  },\n  dev: {\n    command: 'dev',\n    description: 'Starting Storybook',\n    icon: '🖥 ',\n    options: createOptions({}),\n  },\n  migrate: {\n    command: 'migrate',\n    hasArgument: true,\n    description: 'Run codemods',\n    icon: '🚀',\n    options: createOptions({\n      glob: { type: 'string' },\n    }),\n  },\n  automigrate: {\n    command: 'automigrate',\n    hasArgument: true,\n    description: 'Run automigrations',\n    icon: '🤖',\n    options: createOptions({}),\n  },\n};\n\nexport async function executeCLIStep<TOptions extends OptionSpecifier>(\n  cliStep: CLIStep<TOptions>,\n  options: {\n    argument?: string;\n    optionValues?: Partial<OptionValues<TOptions>>;\n    cwd: string;\n    dryRun?: boolean;\n    debug: boolean;\n    env?: Record<string, string>;\n  }\n) {\n  if (cliStep.hasArgument && !options.argument) {\n    throw new Error(`Argument required for ${cliStep.command} command.`);\n  }\n\n  const cliCommand = cliStep.command;\n\n  const prefix = ['dev', 'build'].includes(cliCommand)\n    ? `node \"${cliExecutable}\" ${cliCommand}`\n    : cliCommand === 'init'\n      ? `node \"${createStorybookExecutable}\"`\n      : `node \"${toolboxExecutable}\" ${cliCommand}`;\n  const command = getCommand(\n    cliStep.hasArgument ? `${prefix} ${options.argument}` : prefix,\n    cliStep.options,\n    options.optionValues || {}\n  );\n\n  await exec(\n    command,\n    {\n      cwd: options.cwd,\n      env: {\n        STORYBOOK_DISABLE_TELEMETRY: 'true',\n        STORYBOOK_PROJECT_ROOT: options.cwd,\n        ...options.env,\n      },\n    },\n    {\n      startMessage: `${cliStep.icon} ${cliStep.description}`,\n      errorMessage: `🚨 ${cliStep.description} failed`,\n      dryRun: options.dryRun,\n      debug: options.debug,\n    }\n  );\n}\n"
  },
  {
    "path": "scripts/utils/cli-utils.ts",
    "content": "import { spawn } from 'child_process';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\n\nimport { ROOT_DIRECTORY } from './constants.ts';\n\nconst logger = console;\n\nexport const checkDependencies = async () => {\n  if (!existsSync(join(ROOT_DIRECTORY, 'node_modules'))) {\n    logger.log('installing dependencies');\n\n    const task = spawn('yarn', ['install'], {\n      cwd: ROOT_DIRECTORY,\n      shell: true,\n      stdio: ['inherit', 'inherit', 'inherit'],\n    });\n\n    await new Promise<void>((res, rej) => {\n      task.on('exit', (code: number) => {\n        if (code !== 0) {\n          rej();\n        } else {\n          res();\n        }\n      });\n    }).catch(() => {\n      task.kill();\n      throw new Error('Failed to install dependencies');\n    });\n\n    // give the filesystem some time\n    await new Promise((res) => {\n      setTimeout(res, 1000);\n    });\n  }\n};\n"
  },
  {
    "path": "scripts/utils/command.ts",
    "content": "import { sync as spawnSync } from 'cross-spawn';\n\ntype ExecOptions = Parameters<typeof spawnSync>[2];\n\nexport const exec = async (command: string, options: ExecOptions = {}) =>\n  new Promise((resolve, reject) => {\n    const x = spawnSync(command, options);\n    if (x.status === 0) {\n      resolve(undefined);\n    } else {\n      reject(new Error(`command exited with code: ${x.status}: `));\n    }\n  });\n"
  },
  {
    "path": "scripts/utils/concurrency.ts",
    "content": "import os from 'node:os';\n\n/**\n * The maximum number of concurrent tasks we want to have on some CLI and CI tasks. The amount of\n * CPUS minus one, arbitrary limited to 5 to not overload CI executors.\n */\nexport const maxConcurrentTasks = Math.min(\n  Math.max(1, os.cpus().length - 1),\n  process.env.CI ? 5 : 15\n);\n"
  },
  {
    "path": "scripts/utils/constants.ts",
    "content": "import path from 'node:path';\n\nimport { join } from 'path';\n\nexport const AFTER_DIR_NAME = 'after-storybook';\nexport const BEFORE_DIR_NAME = 'before-storybook';\n\nexport const ROOT_DIRECTORY = join(__dirname, '..', '..');\nexport const CODE_DIRECTORY = join(ROOT_DIRECTORY, 'code');\nexport const SNIPPETS_DIRECTORY = join(ROOT_DIRECTORY, 'docs', '_snippets');\nexport const PACKS_DIRECTORY = join(ROOT_DIRECTORY, 'packs');\nexport const REPROS_DIRECTORY = join(ROOT_DIRECTORY, 'repros');\n\nexport const SANDBOX_DIRECTORY =\n  process.env.STORYBOOK_SANDBOX_ROOT && path.isAbsolute(process.env.STORYBOOK_SANDBOX_ROOT)\n    ? process.env.STORYBOOK_SANDBOX_ROOT\n    : join(ROOT_DIRECTORY, process.env.STORYBOOK_SANDBOX_ROOT || '../storybook-sandboxes');\n\nexport const JUNIT_DIRECTORY = join(ROOT_DIRECTORY, 'test-results');\n\nexport const LOCAL_REGISTRY_URL = 'http://localhost:6001';\nexport const SCRIPT_TIMEOUT = 5 * 60 * 1000;\n"
  },
  {
    "path": "scripts/utils/diff.ts",
    "content": "import { diff } from 'diff-match-patch-es';\n\nfunction matchTextScore(text: string, pattern: string) {\n  const result = diff(text, pattern);\n\n  if (!result.length) {\n    return 0;\n  }\n\n  return result.reduce((pre, cur) => {\n    const [matchIndex, matchText] = cur;\n\n    if (matchIndex === 0) {\n      return pre + matchText.length;\n    }\n\n    return pre;\n  }, 0);\n}\n\nexport function findMostMatchText(list: string[], pattern: string) {\n  let maxScore = 0;\n  let result = '';\n\n  for (const text of list) {\n    const score = matchTextScore(text, pattern);\n\n    if (score > maxScore) {\n      maxScore = score;\n      result = text;\n    }\n  }\n\n  return result !== '' ? result : null;\n}\n"
  },
  {
    "path": "scripts/utils/esmain.ts",
    "content": "import { createRequire } from 'node:module';\nimport { extname } from 'node:path';\nimport process from 'node:process';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * Strip the extension from a filename if it has one.\n *\n * @param {string} name A filename.\n * @returns {string} The filename without a path.\n */\nexport function stripExt(name: string) {\n  const extension = extname(name);\n  if (!extension) {\n    return name;\n  }\n\n  return name.slice(0, -extension.length);\n}\n\n/** Check if a module was run directly with node as opposed to being imported from another module. */\nexport function esMain(url: string) {\n  if (!url || !process.argv[1]) {\n    return false;\n  }\n\n  const require = createRequire(url);\n  const scriptPath = require.resolve(process.argv[1]);\n\n  const modulePath = fileURLToPath(url);\n\n  const extension = extname(scriptPath);\n  if (extension) {\n    return modulePath === scriptPath;\n  }\n\n  return stripExt(modulePath) === scriptPath;\n}\n"
  },
  {
    "path": "scripts/utils/exec.ts",
    "content": "// eslint-disable-next-line depend/ban-dependencies\nimport { type Options, type ResultPromise, execa } from 'execa';\nimport picocolors from 'picocolors';\n\nconst logger = console;\n\ntype StepOptions = {\n  startMessage?: string;\n  errorMessage?: string;\n  dryRun?: boolean;\n  debug?: boolean;\n  signal?: AbortSignal;\n};\n\nexport const exec = async (\n  command: string | string[],\n  options: Options = {},\n  { startMessage, errorMessage, dryRun, debug, signal }: StepOptions = {}\n): Promise<void> => {\n  logger.info();\n\n  if (startMessage) {\n    logger.info(startMessage);\n  }\n\n  if (dryRun) {\n    logger.info(`\\n> ${command}\\n`);\n    return undefined;\n  }\n\n  const defaultOptions: Options = {\n    shell: true,\n    stdout: debug ? 'inherit' : 'pipe',\n    stderr: debug ? 'inherit' : 'pipe',\n    stdin: 'inherit',\n    ...(signal && { cancelSignal: signal }),\n  };\n  let currentChild: ResultPromise;\n\n  try {\n    if (typeof command === 'string') {\n      logger.debug(`> ${command}`);\n      currentChild = execa(command, { ...defaultOptions, ...options });\n      await currentChild;\n    } else {\n      for (const subcommand of command) {\n        logger.debug(`> ${subcommand}`);\n        currentChild = execa(subcommand, { ...defaultOptions, ...options });\n        await currentChild;\n      }\n    }\n  } catch (err) {\n    if (!(typeof err === 'object' && 'killed' in err && err.killed)) {\n      logger.error(picocolors.red(`An error occurred while executing: \\`${command}\\``));\n      logger.log(`${errorMessage}\\n`);\n    }\n\n    throw err;\n  }\n\n  return undefined;\n};\n"
  },
  {
    "path": "scripts/utils/filterExistsInCodeDir.ts",
    "content": "import { access } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\n\nimport { CODE_DIRECTORY } from './constants.ts';\n\nconst pathExists = async (path: string) => {\n  try {\n    await access(path);\n    return true;\n  } catch {\n    return false;\n  }\n};\n\n// packageDirs of the form `lib/preview-api`\n// paths to check of the form 'template/stories'\nexport const filterExistsInCodeDir = async (packageDirs: string[], pathToCheck: string) =>\n  (\n    await Promise.all(\n      packageDirs.map(async (p) =>\n        (await pathExists(resolve(CODE_DIRECTORY, join(p, pathToCheck)))) ? p : null\n      )\n    )\n  ).filter(Boolean);\n"
  },
  {
    "path": "scripts/utils/githubClient.ts",
    "content": "const GITHUB_API = 'https://api.github.com/graphql';\n\nexport const githubClient = (apiKey: string) => {\n  return async (query: string, variables?: { [key: string]: any }) => {\n    const res = await fetch(GITHUB_API, {\n      method: 'POST',\n      headers: {\n        authorization: `token ${apiKey}`,\n      },\n      body: JSON.stringify({\n        query,\n        variables,\n      }),\n    });\n\n    const result: any = await res.json();\n    const { data, errors } = result;\n    if (errors) {\n      throw new Error(JSON.stringify(errors[0]));\n    }\n    return data;\n  };\n};\n"
  },
  {
    "path": "scripts/utils/main-js.ts",
    "content": "import { existsSync } from 'fs';\nimport { join, resolve } from 'path';\n// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\n\nimport { getInterpretedFile } from '../../code/core/src/common/utils/interpret-files.ts';\nimport type { ConfigFile } from '../../code/core/src/csf-tools/index.ts';\nimport { readConfig as csfReadConfig } from '../../code/core/src/csf-tools/ConfigFile.ts';\n\nexport async function readConfig({ fileName, cwd }: { fileName: string; cwd: string }) {\n  const configDir = join(cwd, '.storybook');\n  if (!existsSync(configDir)) {\n    throw new Error(\n      `Unable to find the Storybook folder in \"${configDir}\". Are you sure it exists? Or maybe this folder uses a custom Storybook config directory?`\n    );\n  }\n\n  const mainConfigPath = getInterpretedFile(resolve(configDir, fileName));\n  return csfReadConfig(mainConfigPath);\n}\n\nexport function addPreviewAnnotations(mainConfig: ConfigFile, paths: string[]) {\n  const config = mainConfig.getFieldValue(['previewAnnotations']) as string[];\n  mainConfig.setFieldValue(['previewAnnotations'], [...(config || []), ...paths.map(slash)]);\n}\n"
  },
  {
    "path": "scripts/utils/maxConcurrentTasks.ts",
    "content": "import { cpus } from 'node:os';\n\n/**\n * The maximum number of concurrent tasks we want to have on some CLI and CI tasks. The amount of\n * CPUS minus one, arbitrary limited to 15 to not overload CI executors.\n *\n * @type {number}\n */\nexport const maxConcurrentTasks = Math.min(Math.max(1, cpus().length - 1), 15);\n"
  },
  {
    "path": "scripts/utils/nx.ts",
    "content": "export function isNxTaskExecution(env: NodeJS.ProcessEnv = process.env) {\n  return Boolean(env.NX_TASK_TARGET_PROJECT);\n}\n"
  },
  {
    "path": "scripts/utils/options.test.ts",
    "content": "import { describe, expect, it } from 'vitest';\n\nimport { createCommand } from 'commander';\n\nimport { areOptionsSatisfied, createOptions, getCommand, getOptions } from './options.ts';\n\nconst allOptions = createOptions({\n  first: {\n    type: 'boolean',\n    description: 'first',\n  },\n  second: {\n    type: 'boolean',\n    description: 'second',\n    inverse: true,\n  },\n  third: {\n    type: 'string',\n    description: 'third',\n    values: ['one', 'two', 'three'] as const,\n    required: true as const,\n  },\n  fourth: {\n    type: 'string',\n    description: 'fourth',\n  },\n  fifth: {\n    type: 'string[]',\n    description: 'fifth',\n    values: ['a', 'b', 'c'] as const,\n  },\n  sixth: {\n    type: 'string[]',\n    description: 'sixth',\n  },\n});\n\ndescribe('getOptions', () => {\n  it('deals with boolean options', () => {\n    expect(getOptions(createCommand(), allOptions, ['command', 'name', '--first'])).toMatchObject({\n      first: true,\n      second: true,\n    });\n  });\n\n  it('deals with inverse boolean options', () => {\n    expect(\n      getOptions(createCommand(), allOptions, ['command', 'name', '--no-second'])\n    ).toMatchObject({\n      first: false,\n      second: false,\n    });\n  });\n\n  it('deals with short options', () => {\n    expect(getOptions(createCommand(), allOptions, ['command', 'name', '-f', '-S'])).toMatchObject({\n      first: true,\n      second: false,\n    });\n  });\n\n  it('deals with string options', () => {\n    expect(\n      getOptions(createCommand(), allOptions, ['command', 'name', '--third', 'one'])\n    ).toMatchObject({\n      third: 'one',\n    });\n  });\n\n  it('disallows invalid string options', () => {\n    expect(() =>\n      getOptions(createCommand(), allOptions, ['command', 'name', '--third', 'random'])\n    ).toThrow(/Unexpected value/);\n  });\n\n  it('allows arbitrary string options when values are not specified', () => {\n    expect(\n      getOptions(createCommand(), allOptions, ['command', 'name', '--fourth', 'random'])\n    ).toMatchObject({\n      fourth: 'random',\n    });\n  });\n\n  it('deals with multiple string options', () => {\n    expect(\n      getOptions(createCommand(), allOptions, ['command', 'name', '--fifth', 'a'])\n    ).toMatchObject({\n      fifth: ['a'],\n    });\n\n    expect(\n      getOptions(createCommand(), allOptions, ['command', 'name', '--fifth', 'a', '--fifth', 'b'])\n    ).toMatchObject({\n      fifth: ['a', 'b'],\n    });\n  });\n\n  it('disallows invalid multiple string options', () => {\n    expect(() =>\n      getOptions(createCommand(), allOptions, ['command', 'name', '--fifth', 'random'])\n    ).toThrow(/Unexpected value/);\n  });\n\n  it('allows arbitrary multiple string options when values are not specified', () => {\n    expect(\n      getOptions(createCommand(), allOptions, ['command', 'name', '--sixth', 'random'])\n    ).toMatchObject({\n      sixth: ['random'],\n    });\n  });\n});\n\ndescribe('areOptionsSatisfied', () => {\n  it('checks each required string option has a value', () => {\n    expect(\n      areOptionsSatisfied(allOptions, {\n        first: true,\n        second: true,\n        third: undefined,\n        fourth: undefined,\n        fifth: ['a', 'c'],\n        sixth: [],\n      })\n    ).toBe(false);\n    expect(\n      areOptionsSatisfied(allOptions, {\n        first: true,\n        second: true,\n        third: 'one',\n        fourth: undefined,\n        fifth: [],\n        sixth: [],\n      })\n    ).toBe(true);\n  });\n});\n\ndescribe('getCommand', () => {\n  const { first, second, third, fifth } = allOptions;\n  it('works with boolean options', () => {\n    expect(getCommand('node foo', { first, second }, { first: true, second: true })).toBe(\n      'node foo --first'\n    );\n  });\n\n  it('works with inverse boolean options', () => {\n    expect(getCommand('node foo', { first, second }, { first: false, second: false })).toBe(\n      'node foo --no-second'\n    );\n  });\n\n  it('works with string options', () => {\n    expect(getCommand('node foo', { third }, { third: 'one' })).toBe(`node foo --third \"one\"`);\n  });\n\n  it('works with multiple string options', () => {\n    expect(getCommand('node foo', { fifth }, { fifth: ['a', 'b'] })).toBe(\n      'node foo --fifth a --fifth b'\n    );\n  });\n\n  // This is for convenience\n  it('works with partial options', () => {\n    expect(getCommand('node foo', allOptions, { third: 'one' })).toBe(\n      `node foo --no-second --third \"one\"`\n    );\n  });\n\n  it('works with combinations string options', () => {\n    expect(\n      getCommand('node foo', allOptions, {\n        first: true,\n        second: false,\n        third: 'one',\n        fifth: ['a', 'b'],\n      })\n    ).toBe(`node foo --first --no-second --third \"one\" --fifth a --fifth b`);\n  });\n});\n"
  },
  {
    "path": "scripts/utils/options.ts",
    "content": "/** Use commander and prompts to gather a list of options for a script */\nimport { type Command, type Option as CommanderOption, program } from 'commander';\nimport { kebabCase } from 'es-toolkit/string';\nimport picocolors from 'picocolors';\nimport prompts from 'prompts';\nimport type { Falsy, PrevCaller, PromptObject, PromptType } from 'prompts';\nimport { dedent } from 'ts-dedent';\n\n// Option types\n\nexport type OptionId = string;\nexport type BaseOption = {\n  type: 'boolean' | 'string' | 'string[]';\n  description?: string;\n  /**\n   * By default the one-char version of the option key will be used as short flag. Override here,\n   * e.g. `shortFlag: 'c'`\n   */\n  shortFlag?: string;\n  /** What type of prompt to use? (return false to skip, true for default) */\n  promptType?: PromptType | Falsy | PrevCaller<string, PromptType | boolean>;\n};\n\nexport type BooleanOption = BaseOption & {\n  type: 'boolean';\n  /**\n   * If this option is set to true and the option value is false or undefined, the flag\n   * `--no-option` will be set. If the option value is true, the flag `--no-option` is not set.\n   */\n  inverse?: boolean;\n};\n\nexport type StringOption = BaseOption & {\n  type: 'string';\n  /** What values are allowed for this option? */\n  values?: readonly string[];\n  /** How to describe the values when selecting them */\n  valueDescriptions?: readonly string[];\n  /** Is a value required for this option? */\n  required?: boolean | ((previous: Record<string, any>) => boolean);\n};\n\nexport type StringArrayOption = BaseOption & {\n  type: 'string[]';\n  /** What values are allowed for this option? */\n  values?: readonly string[];\n  /** How to describe the values when selecting them */\n  valueDescriptions?: readonly string[];\n};\n\nexport type Option = BooleanOption | StringOption | StringArrayOption;\nexport type MaybeOptionValue<TOption extends Option> = TOption extends StringArrayOption\n  ? TOption extends { values: infer TValues }\n    ? TValues extends readonly string[]\n      ? TValues[number][]\n      : never // It isn't possible for values to not be a readonly string[], but TS can't work it out\n    : string[]\n  : TOption extends StringOption\n    ? TOption extends { values: infer TValues }\n      ? TValues extends readonly string[]\n        ? TValues[number] | undefined\n        : never // It isn't possible for values to not be a readonly string[], but TS can't work it out\n      : string | undefined\n    : TOption extends BooleanOption\n      ? boolean\n      : never;\n\nexport type OptionValue<TOption extends Option> = TOption extends { required: true }\n  ? NonNullable<MaybeOptionValue<TOption>>\n  : MaybeOptionValue<TOption>;\n\nexport type OptionSpecifier = Record<OptionId, Option>;\nexport type MaybeOptionValues<TOptions extends OptionSpecifier> = {\n  [TKey in keyof TOptions]: MaybeOptionValue<TOptions[TKey]>;\n};\n\nexport type OptionValues<TOptions extends OptionSpecifier = OptionSpecifier> = {\n  [TKey in keyof TOptions]: OptionValue<TOptions[TKey]>;\n};\n\nexport function createOptions<TOptions extends OptionSpecifier>(options: TOptions) {\n  return options;\n}\n\nconst logger = console;\n\nfunction shortFlag(key: OptionId, option: Option) {\n  const inverse = option.type === 'boolean' && option.inverse;\n  const defaultShortFlag = inverse ? key.substring(0, 1).toUpperCase() : key.substring(0, 1);\n  const short = option.shortFlag || defaultShortFlag;\n  if (short.length !== 1) {\n    throw new Error(\n      `Invalid shortFlag for ${key}: '${short}', needs to be a single character (e.g. 's')`\n    );\n  }\n  return short;\n}\n\nfunction longFlag(key: OptionId, option: Option) {\n  const inverse = option.type === 'boolean' && option.inverse;\n  return inverse ? `no-${kebabCase(key)}` : kebabCase(key);\n}\n\nfunction optionFlags(key: OptionId, option: Option, existingOptions: CommanderOption[]) {\n  const optionShortFlag = `-${shortFlag(key, option)}`;\n  let base;\n  if (existingOptions.some((opt) => opt.short === optionShortFlag)) {\n    base = `--${longFlag(key, option)}`;\n  } else {\n    base = `${optionShortFlag}, --${longFlag(key, option)}`;\n  }\n  if (option.type === 'string' || option.type === 'string[]') {\n    return `${base} <${key}>`;\n  }\n  return base;\n}\n\nexport function getOptions<TOptions extends OptionSpecifier>(\n  command: Command,\n  options: TOptions,\n  argv: string[]\n): MaybeOptionValues<TOptions> {\n  Object.entries(options)\n    .reduce((acc, [key, option]) => {\n      const flags = optionFlags(key, option, acc.options as any);\n\n      if (option.type === 'boolean') {\n        return acc.option(flags, option.description, !!option.inverse);\n      }\n\n      const checkStringValue = (raw: string) => {\n        if (option.values && !option.values.includes(raw)) {\n          const possibleOptions = picocolors.cyan(option.values.join('\\n'));\n          throw new Error(\n            dedent`Unexpected value '${picocolors.yellow(raw)}' for option '${picocolors.magenta(key)}'.\n            \n            These are the possible options:\n              ${possibleOptions}\\n\\n`\n          );\n        }\n        return raw;\n      };\n\n      if (option.type === 'string') {\n        return acc.option(flags, option.description, (raw) => {\n          return checkStringValue(raw);\n        });\n      }\n\n      if (option.type === 'string[]') {\n        return acc.option(\n          flags,\n          option.description,\n          (raw, values) => [...values, checkStringValue(raw)],\n          []\n        );\n      }\n\n      throw new Error(`Unexpected option type '${key}'`);\n    }, command)\n    .parse(argv);\n\n  const intermediate = command.opts();\n  if (intermediate.task === undefined && argv[2] && !argv[2].startsWith('-')) {\n    intermediate.task = argv[2];\n  }\n\n  // Note the code above guarantees the types as they come in, so we cast here.\n  // Not sure there is an easier way to do this\n  return intermediate as MaybeOptionValues<TOptions>;\n}\n\n// Boolean values will have a default, usually `false`, `true` if they are \"inverse\".\n// String arrays default to []\n// Currently it isn't possible to have a default for string\nexport function getDefaults<TOptions extends OptionSpecifier>(options: TOptions) {\n  return Object.fromEntries(\n    Object.entries(options)\n      .filter(([, { type }]) => type === 'boolean' || type === 'string[]')\n      .map(([key, option]): any => {\n        if (option.type === 'boolean') {\n          return [key, !!option.inverse];\n        }\n\n        if (option.type === 'string[]') {\n          return [key, []];\n        }\n        throw new Error('Not reachable');\n      })\n  );\n}\n\nfunction checkRequired<TOptions extends OptionSpecifier>(\n  option: TOptions[keyof TOptions],\n  values: MaybeOptionValues<TOptions>\n) {\n  if (option.type !== 'string' || !option.required) {\n    return false;\n  }\n\n  if (typeof option.required === 'boolean') {\n    return option.required;\n  }\n\n  return option.required(values);\n}\n\nexport function areOptionsSatisfied<TOptions extends OptionSpecifier>(\n  options: TOptions,\n  values: MaybeOptionValues<TOptions>\n) {\n  return !Object.entries(options)\n    .filter(([, option]) => checkRequired(option as TOptions[keyof TOptions], values))\n    .find(([key]) => !values[key]);\n}\n\nexport async function promptOptions<TOptions extends OptionSpecifier>(\n  options: TOptions,\n  values: MaybeOptionValues<TOptions>\n): Promise<OptionValues<TOptions>> {\n  const questions = Object.entries(options).map(([key, option]): PromptObject => {\n    let defaultType: PromptType = 'toggle';\n    if (option.type !== 'boolean') {\n      if (option.type === 'string[]') {\n        defaultType = option.values ? 'autocompleteMultiselect' : 'list';\n      } else {\n        defaultType = option.values ? 'select' : 'text';\n      }\n    }\n\n    const passedType = option.promptType;\n    let type: PromptObject['type'] = defaultType;\n    // Allow returning `undefined` from `type()` function to fallback to default\n    if (typeof passedType === 'function') {\n      type = (...args: Parameters<typeof passedType>) => {\n        const chosenType = passedType(...args);\n        return chosenType === true ? defaultType : chosenType;\n      };\n    } else if (typeof passedType !== 'undefined') {\n      type = passedType;\n    }\n\n    if (option.type !== 'boolean') {\n      if (values[key]) {\n        return { name: key, type: false };\n      }\n\n      return {\n        name: key,\n        type,\n        message: option.description,\n        choices: option.values?.map((value, index) => ({\n          title: option.valueDescriptions?.[index] || value,\n          value,\n        })),\n      };\n    }\n    return {\n      type,\n      message: option.description,\n      name: key,\n      initial: option.inverse,\n      active: 'yes',\n      inactive: 'no',\n    };\n  });\n\n  const selection = await prompts(questions, {\n    onCancel: () => {\n      logger.log('Command cancelled by the user. Exiting...');\n      process.exit(1);\n    },\n  });\n  // Again the structure of the questions guarantees we get responses of the type we need\n  return { ...values, ...selection } as OptionValues<TOptions>;\n}\n\nfunction getFlag<TOption extends Option>(\n  key: OptionId,\n  option: TOption,\n  value?: OptionValue<TOption>\n) {\n  if (option.type === 'boolean') {\n    const toggled = option.inverse ? !value : value;\n    return toggled ? `--${longFlag(key, option)}` : '';\n  }\n\n  if (option.type === 'string[]') {\n    // I'm not sure why TS isn't able to infer that OptionValue<TOption> is a\n    // OptionValue<StringArrayOption> (i.e. a string[]), given that it knows\n    // option is a StringArrayOption\n    return ((value || []) as OptionValue<StringArrayOption>)\n      .map((v) => `--${longFlag(key, option)} ${v}`)\n      .join(' ');\n  }\n\n  if (option.type === 'string') {\n    if (value) {\n      return `--${longFlag(key, option)} \"${value}\"`;\n    }\n    return '';\n  }\n\n  throw new Error(`Unknown option type for '${key}'`);\n}\n\nexport function getCommand<TOptions extends OptionSpecifier>(\n  prefix: string,\n  options: TOptions,\n  values: Partial<OptionValues<TOptions>>\n) {\n  const flags = Object.keys(options)\n    .map((key) => getFlag(key, options[key], values[key]))\n    .filter(Boolean);\n  return `${prefix} ${flags.join(' ')}`;\n}\n\nexport async function getOptionsOrPrompt<TOptions extends OptionSpecifier>(\n  commandPrefix: string,\n  options: TOptions\n): Promise<OptionValues<TOptions>> {\n  const main = program.version('5.0.0');\n  main.arguments('[tasks...]');\n  const cliValues = getOptions(main as any, options, process.argv);\n\n  if (areOptionsSatisfied(options, cliValues)) {\n    // areOptionsSatisfied could be a type predicate but I'm not quite sure how to do it\n    return cliValues as OptionValues<TOptions>;\n  }\n\n  if (process.env.CI) {\n    throw new Error(`${commandPrefix} needed to prompt for options, this is not possible in CI!`);\n  }\n\n  const finalValues = await promptOptions(options, cliValues);\n\n  const command = getCommand(commandPrefix, options, finalValues);\n  logger.log(`\\nTo run this directly next time, use:\\n  ${command}\\n`);\n\n  return finalValues;\n}\n"
  },
  {
    "path": "scripts/utils/package-json.ts",
    "content": "import { readFile, writeFile } from 'node:fs/promises';\n\nimport { join } from 'path';\n\nexport async function updatePackageScripts({ cwd, prefix }: { cwd: string; prefix: string }) {\n  const packageJsonPath = join(cwd, 'package.json');\n  const content = await readFile(packageJsonPath, 'utf-8');\n  const packageJson = JSON.parse(content);\n  packageJson.scripts = {\n    ...packageJson.scripts,\n    ...(packageJson.scripts.storybook && {\n      storybook: `${prefix} ${packageJson.scripts.storybook}`,\n      'build-storybook': `${prefix} ${packageJson.scripts['build-storybook']}`,\n    }),\n  };\n  await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));\n}\n"
  },
  {
    "path": "scripts/utils/paths.ts",
    "content": "import { access } from 'node:fs/promises';\n\nimport { join } from 'path';\n\nconst pathExists = async (path: string) => {\n  try {\n    await access(path);\n    return true;\n  } catch {\n    return false;\n  }\n};\n\nexport async function findFirstPath(paths: string[], { cwd }: { cwd: string }) {\n  for (const filePath of paths) {\n    if (await pathExists(join(cwd, filePath))) {\n      return filePath;\n    }\n  }\n  return null;\n}\n"
  },
  {
    "path": "scripts/utils/port.ts",
    "content": "import detectFreePort from 'detect-port';\nimport killProcessOnPort from 'kill-port';\n\nexport const isPortUsed = async (port: number) => (await detectFreePort(port)) !== port;\nexport const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\nexport const killPort = async (port: number) => {\n  if (await isPortUsed(port)) {\n    await killProcessOnPort(port);\n\n    let attempts = 0;\n    while ((await isPortUsed(port)) && attempts < 20) {\n      await sleep(1000);\n      attempts++;\n    }\n    if (await isPortUsed(port)) {\n      throw new Error(`Failed to free port ${port} after ${attempts} attempts`);\n    }\n  }\n};\n"
  },
  {
    "path": "scripts/utils/tools.ts",
    "content": "import { access, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport * as process from 'node:process';\n\nimport { globalExternals } from '@fal-works/esbuild-plugin-global-externals';\nimport { spawn } from 'cross-spawn';\nimport * as esbuild from 'esbuild';\n// eslint-disable-next-line depend/ban-dependencies\nimport { glob } from 'glob';\nimport limit from 'p-limit';\nimport picocolors from 'picocolors';\nimport prettyTime from 'pretty-hrtime';\nimport * as rollup from 'rollup';\nimport * as rpd from 'rollup-plugin-dts';\n// eslint-disable-next-line depend/ban-dependencies\nimport slash from 'slash';\nimport sortPackageJson from 'sort-package-json';\nimport { dedent } from 'ts-dedent';\nimport type * as typefest from 'type-fest';\nimport typescript from 'typescript';\nimport ts from 'typescript';\n\nimport { ROOT_DIRECTORY } from './constants.ts';\n\nexport { globalExternals };\n\nconst pathExists = async (path: string) => {\n  try {\n    await access(path);\n    return true;\n  } catch {\n    return false;\n  }\n};\n\nexport const dts = async (entry: string, externals: string[], tsconfig: string) => {\n  const dir = dirname(entry).replace('src', 'dist');\n  const out = await rollup.rollup({\n    input: entry,\n    external: [...externals, 'ast-types', 'react'].map((dep) => new RegExp(`^${dep}($|\\\\/|\\\\\\\\)`)),\n    output: { file: entry.replace('src', 'dist').replace('.ts', '.d.ts'), format: 'es' },\n    plugins: [\n      rpd.dts({\n        respectExternal: true,\n        tsconfig,\n        compilerOptions: {\n          esModuleInterop: true,\n          baseUrl: '.',\n          jsx: ts.JsxEmit.React,\n          declaration: true,\n          noEmit: false,\n          emitDeclarationOnly: true,\n          noEmitOnError: true,\n          checkJs: false,\n          declarationMap: false,\n          skipLibCheck: true,\n          preserveSymlinks: false,\n          target: ts.ScriptTarget.ESNext,\n        },\n      }),\n    ],\n  });\n  const { output } = await out.generate({\n    format: 'es',\n    file: entry.replace('src', 'dist').replace('.ts', '.d.ts'),\n  });\n\n  await Promise.all(\n    output.map(async (o) => {\n      if (o.type === 'chunk') {\n        await writeFile(join(dir, o.fileName), o.code);\n      } else {\n        throw new Error(`Unexpected output type: ${o.type} for ${entry} (${o.fileName})`);\n      }\n    })\n  );\n};\n\nexport { spawn };\n\nexport const defineEntry =\n  (cwd: string) =>\n  (\n    entry: string,\n    targets: ('node' | 'browser')[],\n    generateDTS: boolean = true,\n    externals: string[] = [],\n    internals: string[] = [],\n    noExternal: string[] = [],\n    isPublic: boolean = false\n  ) => ({\n    file: slash(join(cwd, entry)),\n    node: targets.includes('node'),\n    browser: targets.includes('browser'),\n    dts: generateDTS,\n    externals,\n    internals,\n    noExternal,\n    isPublic,\n  });\n\nexport const merge = <T extends Record<string, any>>(...objects: T[]): T =>\n  Object.assign({}, ...objects);\n\nexport const measure = async (fn: () => Promise<void>) => {\n  const start = process.hrtime();\n  await fn();\n  return process.hrtime(start);\n};\n\nexport {\n  typescript,\n  typefest,\n  process,\n  esbuild,\n  prettyTime,\n  picocolors,\n  dedent,\n  limit,\n  sortPackageJson,\n};\n\nexport const nodeInternals = [\n  'module',\n  'node:module',\n  ...require('module').builtinModules.flatMap((m: string) => [m, `node:${m}`]),\n];\n\ntype PackageJson = typefest.PackageJson &\n  Required<Pick<typefest.PackageJson, 'name' | 'version'>> & { path: string };\n\nexport const getWorkspace = async (): Promise<PackageJson[]> => {\n  const content = await readFile(join(ROOT_DIRECTORY, 'package.json'), 'utf-8');\n  const codePackage = JSON.parse(content);\n  const {\n    workspaces: { packages: patterns },\n  } = codePackage;\n\n  const workspaces = await Promise.all(\n    (patterns as string[]).map(async (pattern: string) => glob(pattern, { cwd: ROOT_DIRECTORY }))\n  );\n\n  return Promise.all(\n    workspaces\n      .flatMap((p) => p.map((i) => join(ROOT_DIRECTORY, i)))\n      .map(async (packagePath) => {\n        const packageJsonPath = join(packagePath, 'package.json');\n        if (!(await pathExists(packageJsonPath))) {\n          // If we delete a package, then an empty folder might still be left behind on some dev machines\n          // In this case, just ignore the folder\n          console.warn(\n            `No package.json found in ${packagePath}. You might want to delete this folder.`\n          );\n          return null;\n        }\n        const content = await readFile(packageJsonPath, 'utf-8');\n        const pkg = JSON.parse(content);\n        return { ...pkg, path: packagePath } as PackageJson;\n      })\n  ).then((packages) => packages.filter((p) => p !== null));\n};\n"
  },
  {
    "path": "scripts/utils/touch.ts",
    "content": "const isWin = process.platform === 'win32';\n\nexport default function touch(filePath: string) {\n  if (isWin) {\n    return `echo. > ${filePath}`;\n  }\n  return `touch ${filePath}`;\n}\n"
  },
  {
    "path": "scripts/utils/workspace.ts",
    "content": "// eslint-disable-next-line depend/ban-dependencies\nimport { execaCommand } from 'execa';\nimport memoize from 'memoizerific';\n\nimport { ROOT_DIRECTORY } from './constants.ts';\n\nexport type Workspace = { name: string; location: string };\n\n/**\n * Get the list of workspaces in the monorepo, excluding the scripts and code packages. And relative\n * to the code directory.\n */\nexport async function getCodeWorkspaces(includePrivate = true) {\n  const { stdout } = await execaCommand(\n    `yarn workspaces list --json ${includePrivate ? '' : '--no-private'}`,\n    {\n      cwd: ROOT_DIRECTORY,\n      shell: true,\n    }\n  );\n  return (JSON.parse(`[${stdout.split('\\n').join(',')}]`) as Workspace[])\n    .filter(({ name }: any) => name !== '@storybook/root' && name !== '@storybook/scripts')\n    .map((it) => {\n      return {\n        name: it.name,\n        // strip code from the location for backwards compatibility\n        location: it.location === 'code' ? '.' : it.location.replace('code/', ''),\n      };\n    }) as Workspace[];\n}\n\nconst getWorkspacesMemo = memoize(1)(getCodeWorkspaces);\n\nexport async function workspacePath(type: string, packageName: string) {\n  const workspaces = await getWorkspacesMemo();\n  const workspace = workspaces.find((w) => w.name === packageName);\n  if (!workspace) {\n    throw new Error(`Unknown ${type} '${packageName}', not in yarn workspace!`);\n  }\n  return workspace.location;\n}\n"
  },
  {
    "path": "scripts/utils/yarn.ts",
    "content": "import { access, mkdir, readFile, rm, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\n// TODO -- should we generate this file a second time outside of CLI?\nimport storybookVersions from '../../code/core/src/common/versions.ts';\nimport { allTemplates } from '../../code/lib/cli-storybook/src/sandbox-templates.ts';\nimport type { AllTemplatesKey } from '../../code/lib/cli-storybook/src/sandbox-templates.ts';\nimport { exec } from './exec.ts';\n\nexport type YarnOptions = {\n  cwd: string;\n  dryRun: boolean;\n  debug: boolean;\n};\n\nconst logger = console;\n\nconst pathExists = async (path: string) => {\n  try {\n    await access(path);\n    return true;\n  } catch {\n    return false;\n  }\n};\n\nexport const addPackageResolutions = async ({ cwd, dryRun }: YarnOptions) => {\n  logger.info(`🔢 Adding package resolutions:`);\n\n  if (dryRun) {\n    return;\n  }\n\n  const packageJsonPath = join(cwd, 'package.json');\n  const content = await readFile(packageJsonPath, 'utf-8');\n  const packageJson = JSON.parse(content);\n  packageJson.resolutions = {\n    ...packageJson.resolutions,\n    ...storybookVersions,\n    // this is for our CI test, ensure we use the same version as docker image, it should match version specified in `./code/package.json` and `.circleci/config.yml`\n    playwright: '1.58.2',\n    'playwright-core': '1.58.2',\n    '@playwright/test': '1.58.2',\n  };\n  await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));\n};\n\nexport const installYarn2 = async ({ cwd, dryRun, debug }: YarnOptions) => {\n  await rm(join(cwd, '.yarnrc.yml'), { force: true }).catch(() => {});\n\n  // TODO: Remove in SB11\n  const pnpApiExists = await pathExists(join(cwd, '.pnp.cjs'));\n\n  await mkdir(cwd, { recursive: true }).then(() =>\n    Promise.all([\n      //\n      writeFile(join(cwd, 'yarn.lock'), ''),\n      writeFile(join(cwd, '.yarnrc.yml'), ''),\n    ])\n  );\n\n  const command = [\n    `yarn set version berry`,\n    `yarn config set enableGlobalCache true`, // Use the global cache so we aren't re-caching dependencies each time we run sandbox\n    `yarn config set checksumBehavior ignore`,\n  ];\n\n  if (!pnpApiExists) {\n    command.push(`yarn config set nodeLinker node-modules`);\n  }\n\n  await exec(\n    command.join(' && '),\n    { cwd },\n    {\n      dryRun,\n      debug,\n      startMessage: `🧶 Installing Yarn`,\n      errorMessage: `🚨 Installing Yarn failed`,\n    }\n  );\n};\n\nexport const isViteSandbox = (key?: AllTemplatesKey) => {\n  return allTemplates[key as AllTemplatesKey]?.expected.builder === '@storybook/builder-vite';\n};\n\nexport const addWorkaroundResolutions = async ({\n  cwd,\n  dryRun,\n  key,\n}: YarnOptions & { key?: AllTemplatesKey }) => {\n  logger.info(`🔢 Adding resolutions for workarounds`);\n\n  if (dryRun) {\n    return;\n  }\n\n  const packageJsonPath = join(cwd, 'package.json');\n  const content = await readFile(packageJsonPath, 'utf-8');\n  const packageJson = JSON.parse(content);\n\n  let additionalResolutions = {};\n\n  // add additional resolutions for React 19\n  if (['nextjs/default-ts', 'nextjs/prerelease', 'react-native-web-vite/expo-ts'].includes(key)) {\n    additionalResolutions = {\n      react: '^19.0.0',\n      'react-dom': '^19.0.0',\n    };\n  }\n\n  if (key === 'react-webpack/prerelease-ts') {\n    additionalResolutions = {\n      ...additionalResolutions,\n      react: packageJson.dependencies.react,\n      'react-dom': packageJson.dependencies['react-dom'],\n    };\n  }\n\n  if (key === 'react-rsbuild/default-ts') {\n    additionalResolutions = {\n      ...additionalResolutions,\n      'react-docgen': '^8.0.2',\n    };\n  }\n\n  packageJson.resolutions = {\n    ...packageJson.resolutions,\n    '@testing-library/dom': '^9.3.4',\n    '@testing-library/jest-dom': '^6.6.3',\n    '@testing-library/user-event': '^14.5.2',\n    ...additionalResolutions,\n  };\n\n  await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));\n};\n\nexport const configureYarn2ForVerdaccio = async ({\n  cwd,\n  dryRun,\n  debug,\n  key,\n}: YarnOptions & { key: AllTemplatesKey }) => {\n  // On NX Cloud agents, we use the global cache to avoid duplicating .yarn/cache across sandboxes.\n  // Stale @storybook/* packages are cleaned from the global cache in the agent init step (agents.yaml).\n  // Locally and on CircleCI, we disable the global cache to avoid stale packages from previous runs.\n  const useGlobalCache = Boolean(process.env.STORYBOOK_NX_CLOUD_AGENT);\n\n  const command = [\n    `yarn config set enableGlobalCache ${useGlobalCache}`,\n    `yarn config set enableMirror false`,\n    // ⚠️ Need to set registry because Yarn 2 is not using the conf of Yarn 1 (URL is hardcoded in CircleCI config.yml)\n    `yarn config set npmRegistryServer \"http://localhost:6001/\"`,\n    // Some required magic to be able to fetch deps from local registry\n    `yarn config set unsafeHttpWhitelist \"localhost\"`,\n    // Disable fallback mode to make sure everything is required correctly\n    `yarn config set pnpFallbackMode none`,\n    // We need to be able to update lockfile when bootstrapping the examples\n    `yarn config set enableImmutableInstalls false`,\n  ];\n\n  if (\n    key.includes('svelte-kit') ||\n    // React prereleases will have INCOMPATIBLE_PEER_DEPENDENCY errors because of transitive dependencies not allowing v19 betas\n    key.includes('nextjs') ||\n    key.includes('react-vite/prerelease') ||\n    key.includes('react-webpack/prerelease') ||\n    key.includes('react-rsbuild/default-ts') ||\n    key.includes('vue-rsbuild/default-ts') ||\n    key.includes('html-rsbuild/default-ts') ||\n    key.includes('web-components-rsbuild/default-ts')\n  ) {\n    // Don't error with INCOMPATIBLE_PEER_DEPENDENCY for SvelteKit sandboxes, it is expected to happen with @sveltejs/vite-plugin-svelte\n    command.push(\n      `yarn config set logFilters --json \"[{\\\\\"code\\\\\":\\\\\"YN0013\\\\\",\\\\\"level\\\\\":\\\\\"discard\\\\\"}]\"`\n    );\n  } else if (key.includes('nuxt')) {\n    // Nothing to do for Nuxt\n  } else {\n    // Discard all YN0013 - FETCH_NOT_CACHED messages\n    // Error on YN0060 - INCOMPATIBLE_PEER_DEPENDENCY\n    command.push(\n      `yarn config set logFilters --json \"[{\\\\\"code\\\\\":\\\\\"YN0013\\\\\",\\\\\"level\\\\\":\\\\\"discard\\\\\"},{\\\\\"code\\\\\":\\\\\"YN0060\\\\\",\\\\\"level\\\\\":\\\\\"discard\\\\\"}]\"`\n    );\n  }\n\n  await exec(\n    command.join(' && '),\n    { cwd },\n    {\n      dryRun,\n      debug,\n      startMessage: `🎛 Configuring Yarn 2`,\n      errorMessage: `🚨 Configuring Yarn 2 failed`,\n    }\n  );\n};\n"
  },
  {
    "path": "scripts/verdaccio.yaml",
    "content": "storage: .verdaccio-cache\n\nmax_body_size: 60mb\n\nauth:\n  auth-memory:\n    users:\n      foo:\n        name: foo\n        password: s3cret\n      bar:\n        name: bar\n        password: s3cret\n\nuplinks:\n  npmjs:\n    url: https://registry.npmjs.org/\n    cache: true\n\npackages:\n  # storybook's 'legacy' packages\n  '@storybook/react-simple-di':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/react-stubber':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/builder-manager':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/channels':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/client-logger':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/components':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/core-common':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/core-events':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/core-server':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/csf-tools':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/docs-tools':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/manager-api':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/manager':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/node-logger':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/preview-api':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/preview':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/router':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/telemetry':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/theming':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/types':\n    access: $all\n    publish: $all\n    proxy: npmjs\n\n  # storybook's packages never hosted in this monorepo\n  '@storybook/csf':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/global':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/design-system':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/preset-ie11':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/preset-scss':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/bench':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/addon-coverage':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/addon-bench':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/addon-styling':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/addon-svelte-csf':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/create-svelte-with-args':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/react-docgen-typescript-plugin':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/testing-library':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/test-runner':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/expect':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/docs-mdx':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/semver':\n    # TODO: remove this when new versions of all dependents have been published and updated. It is not used anymore but still referenced in the latest packages\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/icons':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/ember-cli-storybook':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/addon-webpack5-compiler-swc':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/addon-webpack5-compiler-babel':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/addon-mcp':\n    access: $all\n    publish: $all\n    proxy: npmjs\n  '@storybook/mcp':\n    access: $all\n    publish: $all\n    proxy: npmjs\n\n  # storybook packages are NOT proxied to global registry\n  # allowing us to republish any version during tests\n  '@storybook/*':\n    access: $all\n    publish: $all\n\n  'sb':\n    access: $all\n    publish: $all\n\n  'create-storybook':\n    access: $all\n    publish: $all\n\n  'storybook':\n    access: $all\n    publish: $all\n\n  'storybook-addon-pseudo-states':\n    access: $all\n    publish: $all\n\n  'eslint-plugin-storybook':\n    access: $all\n    publish: $all\n\n  '@*/*':\n    access: $all\n    publish: $all\n    proxy: npmjs\n\n  '**':\n    access: $all\n    publish: $all\n    proxy: npmjs\n\nlogs:\n  - { type: stdout, format: pretty, level: warn }\n"
  },
  {
    "path": "scripts/vitest.config.ts",
    "content": "import { defineConfig } from 'vitest/config';\n\n/**\n * CircleCI reports the wrong number of threads to Node.js, so we need to set it manually. Script\n * tests are running with the small resource class, which has 1 vCPU.\n *\n * @see https://jahed.dev/2022/11/20/fixing-node-js-multi-threading-on-circleci/\n * @see https://vitest.dev/config/maxworkers.html#maxworkers\n * @see https://circleci.com/docs/configuration-reference/#x86\n * @see .circleci/config.yml#L187\n */\nconst threadCount = process.env.CI ? 1 : undefined;\n\nexport default defineConfig({\n  test: {\n    name: 'scripts',\n    clearMocks: true,\n    pool: 'threads',\n    maxWorkers: threadCount,\n  },\n});\n"
  },
  {
    "path": "storybook.code-workspace",
    "content": "{\n  \"folders\": [\n    {\n      \"path\": \".\",\n    },\n    {\n      \"path\": \"../storybook-sandboxes\",\n    },\n  ],\n  \"settings\": {\n    \"files.associations\": {\n      \"*.js\": \"javascriptreact\",\n    },\n    \"js/ts.implicitProjectConfig.target\": \"ESNext\",\n    \"typescript.format.enable\": false,\n    \"typescript.preferGoToSourceDefinition\": true,\n    \"typescript.tsdk\": \"./node_modules/typescript/lib\",\n    \"vitest.workspaceConfig\": \"./code/vitest.workspace.ts\",\n    \"vitest.rootConfig\": \"./code/vitest.workspace.ts\",\n  },\n}\n"
  },
  {
    "path": "test-storybooks/ember-cli/.ember-cli",
    "content": "{\n  /**\n    Ember CLI sends analytics information by default. The data is completely\n    anonymous, but there are times when you might want to disable this behavior.\n\n    Setting `disableAnalytics` to true will prevent any data from being sent.\n  */\n  \"disableAnalytics\": false\n}\n"
  },
  {
    "path": "test-storybooks/ember-cli/.eslintignore",
    "content": ".storybook/preview-head.html\n"
  },
  {
    "path": "test-storybooks/ember-cli/.eslintrc.js",
    "content": "module.exports = {\n  rules: {\n    'import/extensions': 0,\n  },\n  settings: {\n    'import/core-modules': [\n      '@ember/component',\n      '@ember/routing/router',\n      '@ember/application',\n      './config/environment',\n    ],\n  },\n};\n"
  },
  {
    "path": "test-storybooks/ember-cli/.gitignore",
    "content": "# See http://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules\n\n# testing\ncoverage\n\n# production\nbuild\n\n# misc\n.DS_Store\nnpm-debug.log\ntmp\n.env\n.storybook/preview-head.html\n"
  },
  {
    "path": "test-storybooks/ember-cli/.storybook/main.js",
    "content": "const path = require('path');\n\nconst namedBlockPolyfill = require('ember-named-blocks-polyfill/lib/named-blocks-polyfill-plugin');\n\nmodule.exports = {\n  emberOptions: {\n    polyfills: [namedBlockPolyfill],\n  },\n  stories: ['../stories/*.stories.js'],\n  logLevel: 'debug',\n  addons: [\n    '@storybook/addon-a11y',\n    '@storybook/addon-docs',\n    '@storybook/addon-links'\n  ],\n  webpackFinal: async (config) => {\n    // eslint-disable-next-line no-param-reassign\n    config.resolve.fallback = {\n      fs: false,\n      child_process: false,\n      zlib: require.resolve('browserify-zlib'),\n      vm: require.resolve('vm-browserify'),\n      stream: require.resolve('stream-browserify'),\n      os: require.resolve('os-browserify/browser'),\n      ...config.resolve.fallback,\n    };\n    return config;\n  },\n  core: {\n    channelOptions: { maxDepth: 10 },\n    disableTelemetry: true,\n  },\n  staticDirs: ['../ember-output'],\n  features: {\n    buildStoriesJson: false,\n  },\n  framework: { name: '@storybook/ember' },\n};\n"
  },
  {
    "path": "test-storybooks/ember-cli/.storybook/preview.js",
    "content": "import { setJSONDoc } from '@storybook/addon-docs/ember';\nimport docJson from '../ember-output/storybook-docgen/index.json';\n\nsetJSONDoc(docJson);\n"
  },
  {
    "path": "test-storybooks/ember-cli/.yarnrc.yml",
    "content": "nodeLinker: node-modules\nenableImmutableInstalls: false\nyarnPath: ../../.yarn/releases/yarn-4.10.3.cjs\n"
  },
  {
    "path": "test-storybooks/ember-cli/README.md",
    "content": "# Storybook Demo\n\nThis is a demo app to test Ember integration with Storybook. Run `yarn install` to sync Storybook module with the source code and run `yarn storybook` to start the Storybook.\n"
  },
  {
    "path": "test-storybooks/ember-cli/app/app.js",
    "content": "import Application from '@ember/application';\nimport loadInitializers from 'ember-load-initializers';\nimport Resolver from './resolver';\nimport config from './config/environment';\n\nconst App = Application.extend({\n  modulePrefix: config.modulePrefix,\n  podModulePrefix: config.podModulePrefix,\n  Resolver,\n});\n\nloadInitializers(App, config.modulePrefix);\n\nexport default App;\n"
  },
  {
    "path": "test-storybooks/ember-cli/app/components/welcome-banner.js",
    "content": "import Component from '@ember/component';\n\n/**\n *\n * `WelcomeBanner` renders a friendly message and is used to welcome Ember.js users when they first generate an application.\n *\n *\n * ```js\n * {{welcome-banner\n *   backgroundColor=backgroundColor\n *   titleColor=titleColor\n *   subTitleColor=subTitleColor\n *   title=title\n *   subtitle=subtitle\n *   click=(action onClick)\n * }}\n * ```\n *\n * @class WelcomeBanner\n */\nexport default Component.extend({\n  /**\n   * The hex-formatted color code for the background.\n   * @argument backgroundColor\n   * @type {string}\n   * @default null\n   */\n  backgroundColor: null,\n\n  /**\n   * The hex-formatted color code for the subtitle.\n   * @argument subTitleColor\n   * @type {string}\n   */\n  subTitleColor: null,\n\n  /**\n   * The title of the banner.\n   * @argument title\n   * @type {string}\n   */\n  title: null,\n\n  /**\n   * The subtitle of the banner.\n   * @argument subtitle\n   * @type {string}\n   */\n  subtitle: null,\n});\n"
  },
  {
    "path": "test-storybooks/ember-cli/app/components/welcome-page.js",
    "content": "import Component from '@ember/component';\n\nexport default Component.extend({});\n"
  },
  {
    "path": "test-storybooks/ember-cli/app/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n    <title>ember-example</title>\n    <meta name=\"description\" content=\"\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\n    {{content-for \"head\"}}\n\n    <link integrity=\"\" rel=\"stylesheet\" href=\"{{rootURL}}assets/vendor.css\" />\n    <link integrity=\"\" rel=\"stylesheet\" href=\"{{rootURL}}assets/ember-example.css\" />\n\n    {{content-for \"head-footer\"}}\n  </head>\n  <body>\n    {{content-for \"body\"}}\n\n    <script src=\"{{rootURL}}assets/vendor.js\"></script>\n    <script src=\"{{rootURL}}assets/ember-example.js\"></script>\n\n    {{content-for \"body-footer\"}}\n  </body>\n</html>\n"
  },
  {
    "path": "test-storybooks/ember-cli/app/initializers/.gitkeep",
    "content": ""
  },
  {
    "path": "test-storybooks/ember-cli/app/resolver.js",
    "content": "export { default } from 'ember-resolver';\n"
  },
  {
    "path": "test-storybooks/ember-cli/app/router.js",
    "content": "// eslint-disable import-x/extensions\nimport EmberRouter from '@ember/routing/router';\nimport config from './config/environment';\n\nconst Router = EmberRouter.extend({\n  location: config.locationType,\n  rootURL: config.rootURL,\n});\n\nRouter.map(() => ({}));\n\nexport default Router;\n"
  },
  {
    "path": "test-storybooks/ember-cli/app/styles/app.css",
    "content": "#app {\n  font-family: 'Avenir', Helvetica, Arial, sans-serif;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  text-align: center;\n  color: #2c3e50;\n  margin-top: 60px;\n}\n\nh1,\nh2 {\n  font-weight: normal;\n}\n\nul {\n  list-style-type: none;\n  padding: 0;\n}\n\nli {\n  display: inline-block;\n  margin: 0 10px;\n}\n\na {\n  color: #42b983;\n}\n\n.text-align-center {\n  text-align: center;\n}\n\n.main {\n  padding: 15px;\n  line-height: 1.4;\n  font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;\n  background-color: #ffffff;\n}\n\n.logo {\n  height: 150px;\n}\n\n.link {\n  color: #1474f3;\n  text-decoration: none;\n  border-bottom: 1px solid #1474f3;\n  padding-bottom: 2px;\n}\n\n.code {\n  font-size: 15;\n  font-weight: 600;\n  padding: 2px 5px;\n  border: 1px solid #eae9e9;\n  border-radius: 4px;\n  background-color: #f3f2f2;\n  color: #3a3a3a;\n}\n\n.codeBlock {\n  background-color: #f3f2f2;\n  padding: 1px 10px;\n  margin: 10px 0;\n}\n\n.note {\n  opacity: 0.5;\n}\n\n.banner {\n  padding: 10px;\n  border-radius: 5px;\n}\n"
  },
  {
    "path": "test-storybooks/ember-cli/app/templates/application.hbs",
    "content": "{{welcome-page}}\n\n{{outlet}}\n"
  },
  {
    "path": "test-storybooks/ember-cli/app/templates/components/named-block.hbs",
    "content": "<div>\n    <h1>{{yield to='title'}}</h1>\n    <div>{{yield to='body'}}</div>\n</div>\n"
  },
  {
    "path": "test-storybooks/ember-cli/app/templates/components/welcome-banner.hbs",
    "content": "<div class=\"banner\" style=\"background-color:{{backgroundColor}};{{style}}\">\n  <h1 class=\"banner-header\" style=\"color:{{titleColor}};\">{{title}}</h1>\n  <p class=\"banner-subtitle\" style=\"color:{{subTitleColor}}\">\n    {{subtitle}}\n  </p>\n</div>\n"
  },
  {
    "path": "test-storybooks/ember-cli/app/templates/components/welcome-page.hbs",
    "content": "<div class=\"main\">\n  <p class=\"text-align-center\">\n    <img class=\"logo\" src=\"./logo.png\" />\n  </p>\n  <p>\n    We've added some basic stories inside the\n    <code class=\"code\">stories</code>\n    directory.\n    <br />\n    A story is a single state of one or more UI components.\n    You can have as many stories as you want.\n    <br />\n    (Basically a story is like a visual test case.)\n  </p>\n  <p>\n    See these sample\n    <a class=\"link\">stories</a>\n    for a component called\n    <code class=\"code\">welcome-banner</code>\n    .\n  </p>\n  <p>\n    Just like that, you can add your own components as stories.\n    <br />\n    You can also edit those components and see changes right away.\n    <br />\n    (Try editing the <code class=\"code\">welcome-banner</code> component\n    located at <code class=\"code\">app/components/welcome-banner.js</code>.)\n  </p>\n  <p>\n    Usually we create stories with smaller UI components in the app.<br />\n    Have a look at the\n    <a\n      class=\"link\"\n      href=\"https://storybook.js.org/basics/writing-stories\"\n      target=\"_blank\"\n    >\n      Writing Stories\n    </a>\n    section in our documentation.\n  </p>\n  <p class=\"note\">\n    <b>NOTE:</b>\n    <br />\n    Have a look at the\n    <code class=\"code\">.storybook/webpack.config.js</code>\n    to add webpack\n    loaders and plugins you are using in this project.\n  </p>\n</div>\n"
  },
  {
    "path": "test-storybooks/ember-cli/config/environment.js",
    "content": "module.exports = function buildEnvironment(environment) {\n  const ENV = {\n    modulePrefix: 'ember-example',\n    environment,\n    rootURL: '/',\n    locationType: 'auto',\n    EmberENV: {\n      FEATURES: {\n        // Here you can enable experimental features on an ember canary build\n        // e.g. 'with-controller': true\n      },\n      EXTEND_PROTOTYPES: {\n        // Prevent Ember Data from overriding Date.parse.\n        Date: false,\n      },\n    },\n\n    APP: {\n      // Here you can pass flags/options to your application instance\n      // when it is created\n    },\n  };\n\n  if (environment === 'development') {\n    // ENV.APP.LOG_RESOLVER = true;\n    // ENV.APP.LOG_ACTIVE_GENERATION = true;\n    // ENV.APP.LOG_TRANSITIONS = true;\n    // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;\n    // ENV.APP.LOG_VIEW_LOOKUPS = true;\n  }\n\n  if (environment === 'test') {\n    // Testem prefers this...\n    ENV.locationType = 'none';\n\n    // keep test console output quieter\n    ENV.APP.LOG_ACTIVE_GENERATION = false;\n    ENV.APP.LOG_VIEW_LOOKUPS = false;\n\n    ENV.APP.rootElement = '#ember-testing';\n    ENV.APP.autoboot = false;\n  }\n\n  if (environment === 'production') {\n    // here you can enable a production-specific feature\n  }\n\n  return ENV;\n};\n"
  },
  {
    "path": "test-storybooks/ember-cli/config/optional-features.json",
    "content": "{\n  \"application-template-wrapper\": false,\n  \"jquery-integration\": false,\n  \"template-only-glimmer-components\": true\n}\n"
  },
  {
    "path": "test-storybooks/ember-cli/config/targets.js",
    "content": "module.exports = {\n  browsers: ['ie 9', 'last 1 Chrome versions', 'last 1 Firefox versions', 'last 1 Safari versions'],\n};\n"
  },
  {
    "path": "test-storybooks/ember-cli/ember-cli-build.js",
    "content": "const EmberApp = require('ember-cli/lib/broccoli/ember-app');\n\nmodule.exports = function build(defaults) {\n  const app = new EmberApp(defaults, {\n    'ember-cli-storybook': {\n      enableAddonDocsIntegration: true,\n    },\n  });\n\n  // Use `app.import` to add additional libraries to the generated\n  // output files.\n  //\n  // If you need to use different assets in different\n  // environments, specify an object as the first parameter. That\n  // object's keys should be the environment name and the values\n  // should be the asset to use in that environment.\n  //\n  // If the library that you are including contains AMD or ES6\n  // modules that you would like to import into your application\n  // please specify an object with the list of modules as keys\n  // along with the exports of each module as its value.\n\n  return app.toTree();\n};\n"
  },
  {
    "path": "test-storybooks/ember-cli/package.json",
    "content": "{\n  \"name\": \"ember-example\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"--build-storybook\": \"yarn storybook-prebuild && NODE_OPTIONS=\\\"--preserve-symlinks --preserve-symlinks-main\\\" storybook build\",\n    \"build\": \"ember build --output-path ember-output\",\n    \"dev\": \"ember serve\",\n    \"storybook\": \"yarn build && storybook dev -p 9009\",\n    \"storybook-prebuild\": \"yarn build && shx cp -r public/* ember-output\",\n    \"storybook:dev\": \"yarn dev & NODE_OPTIONS=\\\"--preserve-symlinks --preserve-symlinks-main\\\" storybook dev -p 9009\"\n  },\n  \"resolutions\": {\n    \"@storybook/addon-a11y\": \"file:../../code/addons/a11y\",\n    \"@storybook/addon-docs\": \"file:../../code/addons/docs\",\n    \"@storybook/addon-links\": \"file:../../code/addons/links\",\n    \"@storybook/addon-themes\": \"file:../../code/addons/themes\",\n    \"@storybook/angular\": \"file:../../code/frameworks/angular\",\n    \"@storybook/builder-vite\": \"file:../../code/builders/builder-vite\",\n    \"@storybook/builder-webpack5\": \"file:../../code/builders/builder-webpack5\",\n    \"@storybook/codemod\": \"file:../../code/lib/codemod\",\n    \"@storybook/core-webpack\": \"file:../../code/lib/core-webpack\",\n    \"@storybook/csf-plugin\": \"file:../../code/lib/csf-plugin\",\n    \"@storybook/ember\": \"file:../../code/frameworks/ember\",\n    \"@storybook/html\": \"file:../../code/renderers/html\",\n    \"@storybook/nextjs\": \"file:../../code/frameworks/nextjs\",\n    \"@storybook/preact\": \"file:../../code/renderers/preact\",\n    \"@storybook/preact-vite\": \"file:../../code/frameworks/preact-vite\",\n    \"@storybook/preset-create-react-app\": \"file:../../code/presets/create-react-app\",\n    \"@storybook/preset-react-webpack\": \"file:../../code/presets/react-webpack\",\n    \"@storybook/preset-server-webpack\": \"file:../../code/presets/server-webpack\",\n    \"@storybook/react\": \"file:../../code/renderers/react\",\n    \"@storybook/react-dom-shim\": \"file:../../code/lib/react-dom-shim\",\n    \"@storybook/react-vite\": \"file:../../code/frameworks/react-vite\",\n    \"@storybook/react-webpack5\": \"file:../../code/frameworks/react-webpack5\",\n    \"@storybook/server\": \"file:../../code/renderers/server\",\n    \"@storybook/server-webpack5\": \"file:../../code/frameworks/server-webpack5\",\n    \"@storybook/svelte\": \"file:../../code/renderers/svelte\",\n    \"@storybook/svelte-vite\": \"file:../../code/frameworks/svelte-vite\",\n    \"@storybook/sveltekit\": \"file:../../code/frameworks/sveltekit\",\n    \"@storybook/vue3\": \"file:../../code/renderers/vue3\",\n    \"@storybook/vue3-vite\": \"file:../../code/frameworks/vue3-vite\",\n    \"@storybook/web-components\": \"file:../../code/renderers/web-components\",\n    \"@storybook/web-components-vite\": \"file:../../code/frameworks/web-components-vite\",\n    \"storybook\": \"file:../../code/core\"\n  },\n  \"dependencies\": {\n    \"ember-named-blocks-polyfill\": \"^0.2.3\",\n    \"ember-template-compiler\": \"^1.9.0-alpha\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.22.0\",\n    \"@ember/optional-features\": \"^2.0.0\",\n    \"@storybook/addon-a11y\": \"*\",\n    \"@storybook/addon-docs\": \"*\",\n    \"@storybook/addon-links\": \"*\",\n    \"@storybook/ember\": \"*\",\n    \"@storybook/ember-cli-storybook\": \"^0.2.1\",\n    \"babel-loader\": \"^8.2.5\",\n    \"broccoli-asset-rev\": \"^3.0.0\",\n    \"browserify-zlib\": \"^0.2.0\",\n    \"cross-env\": \"^7.0.3\",\n    \"ember-ajax\": \"^5.0.0\",\n    \"ember-cli\": \"~3.24.0\",\n    \"ember-cli-app-version\": \"^4.0.0\",\n    \"ember-cli-babel\": \"^7.23.0\",\n    \"ember-cli-htmlbars\": \"^4.4.0\",\n    \"ember-cli-inject-live-reload\": \"^2.0.2\",\n    \"ember-cli-shims\": \"^1.2.0\",\n    \"ember-cli-sri\": \"^2.1.1\",\n    \"ember-cli-uglify\": \"^3.0.0\",\n    \"ember-load-initializers\": \"^2.1.2\",\n    \"ember-resolver\": \"^7.0.0\",\n    \"ember-source\": \"~3.24.0\",\n    \"loader.js\": \"^4.7.0\",\n    \"os-browserify\": \"^0.3.0\",\n    \"shx\": \"^0.3.2\",\n    \"storybook\": \"*\",\n    \"stream-browserify\": \"^3.0.0\",\n    \"vm-browserify\": \"^1.1.2\",\n    \"webpack\": \"5\",\n    \"webpack-cli\": \"^4.9.2\"\n  },\n  \"--storybook\": {\n    \"chromatic\": {\n      \"projectToken\": \"19z23qxndju\"\n    }\n  }\n}\n"
  },
  {
    "path": "test-storybooks/ember-cli/stories/index.stories.js",
    "content": "import { hbs } from 'ember-cli-htmlbars';\n\nexport default {\n  title: 'Welcome',\n  parameters: {\n    options: { showPanel: false },\n  },\n};\n\nexport const Basic = () => ({\n  template: hbs`\n        {{welcome-page}}\n      `,\n});\n"
  },
  {
    "path": "test-storybooks/ember-cli/stories/polyfill-example.stories.js",
    "content": "import { hbs } from 'ember-cli-htmlbars';\n\nexport default {\n  title: 'EmberOptions/Polyfills',\n};\n\nexport const NamedBlockExample = () => {\n  return {\n    template: hbs`\n      <NamedBlock\n      >\n        <:title>This article is awesome!</:title>\n        <:body>\n          My blog has very awesome content, and everyone should\n          read it.\n        </:body>\n      </NamedBlock>\n  `,\n  };\n};\n"
  },
  {
    "path": "test-storybooks/ember-cli/stories/welcome-banner.stories.js",
    "content": "import { hbs } from 'ember-cli-htmlbars';\n\nexport default {\n  title: 'welcome-banner',\n  component: 'WelcomeBanner',\n  parameters: {\n    docs: { story: { iframeHeight: '200px' }, },\n  },\n  argTypes: {\n    backgroundColor: { control: 'color' },\n    subTitleColor: { control: 'color' },\n  },\n};\n\nexport const Basic = (args) => ({\n  template: hbs`\n      {{welcome-banner\n        backgroundColor=backgroundColor\n        titleColor=titleColor\n        subTitleColor=subTitleColor\n        title=title\n        subtitle=subtitle\n      }}\n    `,\n  context: args,\n});\nBasic.args = {\n  backgroundColor: '#FDF4E7',\n  titleColor: '#DF4D37',\n  subTitleColor: '#B8854F',\n  title: 'Welcome to storybook',\n  subtitle: 'This environment is completely editable',\n};\n"
  },
  {
    "path": "test-storybooks/external-docs/.babelrc",
    "content": "{\n  \"presets\": [\n    \"next/babel\",\n    [\n      \"@babel/preset-env\",\n      {\n        \"targets\": {\n          \"chrome\": \"100\"\n        }\n      }\n    ]\n  ]\n}"
  },
  {
    "path": "test-storybooks/external-docs/.storybook/main.cjs",
    "content": "const config = {\n  stories: [\n    '../Introduction.mdx',\n    {\n      directory: '../components',\n      titlePrefix: 'Demo',\n      files: '**/!(Template).(stories.tsx|mdx)',\n    },\n  ],\n  logLevel: 'debug',\n  typescript: {\n    check: true,\n    checkOptions: {},\n    reactDocgenTypescriptOptions: {\n      propFilter: (prop) => ['label', 'disabled'].includes(prop.name),\n    },\n  },\n  core: {\n    channelOptions: { maxDepth: 10 },\n  },\n  features: {\n    warnOnLegacyHierarchySeparator: false,\n    previewMdx2: true,\n  },\n  framework: '@storybook/react-webpack5',\n};\nmodule.exports = config;\n"
  },
  {
    "path": "test-storybooks/external-docs/.storybook/preview.js",
    "content": "import React from 'react';\nimport { ThemeProvider, convert, themes } from 'storybook/theming';\n\nexport const parameters = {\n  options: {\n    // storySortV6: (a, b) => (\n    //   a[1].kind === b[1].kind\n    //     ? 0\n    //     : a[1].id.localeCompare(b[1].id, undefined, { numeric: true });\n    // ),\n    // storySortV7: (a, b) => (\n    //   a.title === b.title\n    //     ? 0\n    //     : a.id.localeCompare(b.id, undefined, { numeric: true });\n    // ),\n    storySort: {\n      order: ['Examples', 'Docs', 'Demo'],\n    },\n  },\n};\n\nexport const decorators = [\n  (StoryFn) => (\n    <ThemeProvider theme={convert(themes.light)}>\n      <StoryFn />\n    </ThemeProvider>\n  ),\n];\n"
  },
  {
    "path": "test-storybooks/external-docs/.yarnrc.yml",
    "content": "nodeLinker: node-modules\nenableImmutableInstalls: false\nyarnPath: ../../.yarn/releases/yarn-4.10.3.cjs\n"
  },
  {
    "path": "test-storybooks/external-docs/README.md",
    "content": "# Storybook External Docs Example\n\nThis example demonstrates using Stories in an app built outside of SB's build process.\n"
  },
  {
    "path": "test-storybooks/external-docs/components/AccountForm.mdx",
    "content": "import { Meta, Story } from '@storybook/addon-docs/blocks';\nimport * as AccountFormStories from './AccountForm.stories';\n\n## Docs for Account form\n\n<Meta of={AccountFormStories} />\n\n<Story of={AccountFormStories.Standard} />\n"
  },
  {
    "path": "test-storybooks/external-docs/components/AccountForm.stories.tsx",
    "content": "/* eslint-disable storybook/use-storybook-testing-library */\n// @TODO: use addon-interactions and remove the rule disable above\nimport type { StoryObj, Meta } from '@storybook/react';\nimport { screen } from '@testing-library/dom';\nimport userEvent from '@testing-library/user-event';\nimport { AccountForm } from './AccountForm';\n\nexport default {\n  // Title not needed due to CSF3 auto-title\n  // title: 'Demo/AccountForm',\n  component: AccountForm,\n  parameters: {\n    layout: 'centered',\n  },\n} as Meta<typeof AccountForm>;\n\ntype Story = StoryObj<typeof AccountForm>;\n\nexport const Standard: Story = {\n  args: { passwordVerification: false },\n};\n\nexport const StandardEmailFilled: Story = {\n  ...Standard,\n  play: () => userEvent.type(screen.getByTestId('email'), 'michael@chromatic.com'),\n};\n\nexport const StandardEmailFailed: Story = {\n  ...Standard,\n  play: async () => {\n    await userEvent.type(screen.getByTestId('email'), 'michael@chromatic.com.com@com');\n    await userEvent.type(screen.getByTestId('password1'), 'testpasswordthatwontfail');\n    await userEvent.click(screen.getByTestId('submit'));\n  },\n};\n\nexport const StandardPasswordFailed: Story = {\n  ...Standard,\n  play: async (context) => {\n    await StandardEmailFilled.play(context);\n    await userEvent.type(screen.getByTestId('password1'), 'asdf');\n    await userEvent.click(screen.getByTestId('submit'));\n  },\n};\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));\n\nexport const StandardFailHover: Story = {\n  ...StandardPasswordFailed,\n  play: async (context) => {\n    await StandardPasswordFailed.play(context);\n    await sleep(100);\n    await userEvent.hover(screen.getByTestId('password-error-info'));\n  },\n};\n\nexport const Verification: StoryObj<typeof AccountForm> = {\n  args: { passwordVerification: true },\n};\n\nexport const VerificationPasssword1: Story = {\n  ...Verification,\n  play: async (context) => {\n    await StandardEmailFilled.play(context);\n    await userEvent.type(screen.getByTestId('password1'), 'asdfasdf');\n    await userEvent.click(screen.getByTestId('submit'));\n  },\n};\n\nexport const VerificationPasswordMismatch: Story = {\n  ...Verification,\n  play: async (context) => {\n    await StandardEmailFilled.play(context);\n    await userEvent.type(screen.getByTestId('password1'), 'asdfasdf');\n    await userEvent.type(screen.getByTestId('password2'), 'asdf1234');\n    await userEvent.click(screen.getByTestId('submit'));\n  },\n};\n\nexport const VerificationSuccess: Story = {\n  ...Verification,\n  play: async (context) => {\n    await StandardEmailFilled.play(context);\n    await sleep(1000);\n    await userEvent.type(screen.getByTestId('password1'), 'asdfasdf', { delay: 50 });\n    await sleep(1000);\n    await userEvent.type(screen.getByTestId('password2'), 'asdfasdf', { delay: 50 });\n    await sleep(1000);\n    await userEvent.click(screen.getByTestId('submit'));\n  },\n};\n"
  },
  {
    "path": "test-storybooks/external-docs/components/AccountForm.tsx",
    "content": "import { keyframes, styled } from 'storybook/theming';\nimport {\n  ErrorMessage,\n  Field as FormikInput,\n  Form as FormikForm,\n  Formik,\n  FormikProps,\n} from 'formik';\nimport React, { FC, HTMLAttributes, useCallback, useState } from 'react';\nimport { Icons, WithTooltip } from 'storybook/internal/components';\n\nconst errorMap = {\n  email: {\n    required: {\n      normal: 'Please enter your email address',\n      tooltip:\n        'We do require an email address and a password as a minimum in order to be able to create an account for you to log in with',\n    },\n    format: {\n      normal: 'Please enter a correctly formatted email address',\n      tooltip:\n        'Your email address is formatted incorrectly and is not correct - please double check for misspelling',\n    },\n  },\n  password: {\n    required: {\n      normal: 'Please enter a password',\n      tooltip: 'A password is required to create an account',\n    },\n    length: {\n      normal: 'Please enter a password of minimum 6 characters',\n      tooltip:\n        'For security reasons we enforce a password length of minimum 6 characters - but have no other requirements',\n    },\n  },\n  verifiedPassword: {\n    required: {\n      normal: 'Please verify your password',\n      tooltip:\n        'Verification of your password is required to ensure no errors in the spelling of the password',\n    },\n    match: {\n      normal: 'Your passwords do not match',\n      tooltip:\n        'Your verification password has to match your password to make sure you have not misspelled',\n    },\n  },\n};\n\n// https://emailregex.com/\nconst email99RegExp = new RegExp(\n  // eslint-disable-next-line no-useless-escape\n  /^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/\n);\n\nexport interface AccountFormResponse {\n  success: boolean;\n}\n\nexport interface AccountFormValues {\n  email: string;\n  password: string;\n}\n\ninterface FormValues extends AccountFormValues {\n  verifiedPassword: string;\n}\n\ninterface FormErrors {\n  email?: string;\n  emailTooltip?: string;\n  password?: string;\n  passwordTooltip?: string;\n  verifiedPassword?: string;\n  verifiedPasswordTooltip?: string;\n}\n\nexport type AccountFormProps = {\n  passwordVerification?: boolean;\n  onSubmit?: (values: AccountFormValues) => void;\n  onTransactionStart?: (values: AccountFormValues) => void;\n  onTransactionEnd?: (values: AccountFormResponse) => void;\n};\n\nexport const AccountForm: FC<AccountFormProps> = ({\n  passwordVerification,\n  onSubmit,\n  onTransactionStart,\n  onTransactionEnd,\n}) => {\n  const [state, setState] = useState({\n    transacting: false,\n    transactionSuccess: false,\n    transactionFailure: false,\n  });\n\n  const handleFormSubmit = useCallback(\n    async ({ email, password }: FormValues, { setSubmitting, resetForm }) => {\n      if (onSubmit) {\n        onSubmit({ email, password });\n      }\n\n      if (onTransactionStart) {\n        onTransactionStart({ email, password });\n      }\n\n      setSubmitting(true);\n\n      setState({\n        ...state,\n        transacting: true,\n      });\n\n      await new Promise((r) => setTimeout(r, 2100));\n\n      const success = Math.random() < 1;\n\n      if (onTransactionEnd) {\n        onTransactionEnd({ success });\n      }\n\n      setSubmitting(false);\n      resetForm({ values: { email: '', password: '', verifiedPassword: '' } });\n\n      setState({\n        ...state,\n        transacting: false,\n        transactionSuccess: success === true,\n        transactionFailure: success === false,\n      });\n    },\n    [setState, onTransactionEnd, onTransactionStart]\n  );\n\n  return (\n    <Wrapper>\n      <Brand>\n        <Logo\n          aria-label=\"Storybook Logo\"\n          viewBox=\"0 0 64 64\"\n          transacting={state.transacting}\n          role=\"img\"\n        >\n          <title>Storybook icon</title>\n          <g id=\"Artboard\" stroke=\"none\" strokeWidth=\"1\" fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M8.04798541,58.7875918 L6.07908839,6.32540407 C6.01406344,4.5927838 7.34257463,3.12440831 9.07303814,3.01625434 L53.6958037,0.227331489 C55.457209,0.117243658 56.974354,1.45590096 57.0844418,3.21730626 C57.0885895,3.28366922 57.0906648,3.35014546 57.0906648,3.41663791 L57.0906648,60.5834697 C57.0906648,62.3483119 55.6599776,63.7789992 53.8951354,63.7789992 C53.847325,63.7789992 53.7995207,63.7779262 53.7517585,63.775781 L11.0978899,61.8600599 C9.43669044,61.7854501 8.11034889,60.4492961 8.04798541,58.7875918 Z\"\n              id=\"path-1\"\n              fill=\"#FF4785\"\n              fillRule=\"nonzero\"\n            />\n            <path\n              d=\"M35.9095005,24.1768792 C35.9095005,25.420127 44.2838488,24.8242707 45.4080313,23.9509748 C45.4080313,15.4847538 40.8652557,11.0358878 32.5466666,11.0358878 C24.2280775,11.0358878 19.5673077,15.553972 19.5673077,22.3311017 C19.5673077,34.1346028 35.4965208,34.3605071 35.4965208,40.7987804 C35.4965208,42.606015 34.6115646,43.6790606 32.6646607,43.6790606 C30.127786,43.6790606 29.1248356,42.3834613 29.2428298,37.9783269 C29.2428298,37.0226907 19.5673077,36.7247626 19.2723223,37.9783269 C18.5211693,48.6535354 25.1720308,51.7326752 32.7826549,51.7326752 C40.1572906,51.7326752 45.939005,47.8018145 45.939005,40.6858282 C45.939005,28.035186 29.7738035,28.3740425 29.7738035,22.1051974 C29.7738035,19.5637737 31.6617103,19.2249173 32.7826549,19.2249173 C33.9625966,19.2249173 36.0864917,19.4328883 35.9095005,24.1768792 Z\"\n              id=\"path9_fill-path\"\n              fill=\"#FFFFFF\"\n              fillRule=\"nonzero\"\n            />\n            <path\n              d=\"M44.0461638,0.830433986 L50.1874092,0.446606143 L50.443532,7.7810017 C50.4527198,8.04410717 50.2468789,8.26484453 49.9837734,8.27403237 C49.871115,8.27796649 49.7607078,8.24184808 49.6721567,8.17209069 L47.3089847,6.3104681 L44.5110468,8.43287463 C44.3012992,8.591981 44.0022839,8.55092814 43.8431776,8.34118051 C43.7762017,8.25288717 43.742082,8.14401677 43.7466857,8.03329059 L44.0461638,0.830433986 Z\"\n              id=\"Path\"\n              fill=\"#FFFFFF\"\n            />\n          </g>\n        </Logo>\n        <Title aria-label=\"Storybook\" viewBox=\"0 0 200 40\" role=\"img\">\n          <title>Storybook</title>\n          <g fill=\"none\" fillRule=\"evenodd\">\n            <path\n              d=\"M53.3 31.7c-1.7 0-3.4-.3-5-.7-1.5-.5-2.8-1.1-3.9-2l1.6-3.5c2.2 1.5 4.6 2.3 7.3 2.3 1.5 0 2.5-.2 3.3-.7.7-.5 1.1-1 1.1-1.9 0-.7-.3-1.3-1-1.7s-2-.8-3.7-1.2c-2-.4-3.6-.9-4.8-1.5-1.1-.5-2-1.2-2.6-2-.5-1-.8-2-.8-3.2 0-1.4.4-2.6 1.2-3.6.7-1.1 1.8-2 3.2-2.6 1.3-.6 2.9-.9 4.7-.9 1.6 0 3.1.3 4.6.7 1.5.5 2.7 1.1 3.5 2l-1.6 3.5c-2-1.5-4.2-2.3-6.5-2.3-1.3 0-2.3.2-3 .8-.8.5-1.2 1.1-1.2 2 0 .5.2 1 .5 1.3.2.3.7.6 1.4.9l2.9.8c2.9.6 5 1.4 6.2 2.4a5 5 0 0 1 2 4.2 6 6 0 0 1-2.5 5c-1.7 1.2-4 1.9-7 1.9zm21-3.6l1.4-.1-.2 3.5-1.9.1c-2.4 0-4.1-.5-5.2-1.5-1.1-1-1.6-2.7-1.6-4.8v-6h-3v-3.6h3V11h4.8v4.6h4v3.6h-4v6c0 1.8.9 2.8 2.6 2.8zm11.1 3.5c-1.6 0-3-.3-4.3-1a7 7 0 0 1-3-2.8c-.6-1.3-1-2.7-1-4.4 0-1.6.4-3 1-4.3a7 7 0 0 1 3-2.8c1.2-.7 2.7-1 4.3-1 1.7 0 3.2.3 4.4 1a7 7 0 0 1 3 2.8c.6 1.2 1 2.7 1 4.3 0 1.7-.4 3.1-1 4.4a7 7 0 0 1-3 2.8c-1.2.7-2.7 1-4.4 1zm0-3.6c2.4 0 3.6-1.6 3.6-4.6 0-1.5-.3-2.6-1-3.4a3.2 3.2 0 0 0-2.6-1c-2.3 0-3.5 1.4-3.5 4.4 0 3 1.2 4.6 3.5 4.6zm21.7-8.8l-2.7.3c-1.3.2-2.3.5-2.8 1.2-.6.6-.9 1.4-.9 2.5v8.2H96V15.7h4.6v2.6c.8-1.8 2.5-2.8 5-3h1.3l.3 4zm14-3.5h4.8L116.4 37h-4.9l3-6.6-6.4-14.8h5l4 10 4-10zm16-.4c1.4 0 2.6.3 3.6 1 1 .6 1.9 1.6 2.5 2.8.6 1.2.9 2.7.9 4.3 0 1.6-.3 3-1 4.3a6.9 6.9 0 0 1-2.4 2.9c-1 .7-2.2 1-3.6 1-1 0-2-.2-3-.7-.8-.4-1.5-1-2-1.9v2.4h-4.7V8.8h4.8v9c.5-.8 1.2-1.4 2-1.9.9-.4 1.8-.6 3-.6zM135.7 28c1.1 0 2-.4 2.6-1.2.6-.8 1-2 1-3.4 0-1.5-.4-2.5-1-3.3s-1.5-1.1-2.6-1.1-2 .3-2.6 1.1c-.6.8-1 2-1 3.3 0 1.5.4 2.6 1 3.4.6.8 1.5 1.2 2.6 1.2zm18.9 3.6c-1.7 0-3.2-.3-4.4-1a7 7 0 0 1-3-2.8c-.6-1.3-1-2.7-1-4.4 0-1.6.4-3 1-4.3a7 7 0 0 1 3-2.8c1.2-.7 2.7-1 4.4-1 1.6 0 3 .3 4.3 1a7 7 0 0 1 3 2.8c.6 1.2 1 2.7 1 4.3 0 1.7-.4 3.1-1 4.4a7 7 0 0 1-3 2.8c-1.2.7-2.7 1-4.3 1zm0-3.6c2.3 0 3.5-1.6 3.5-4.6 0-1.5-.3-2.6-1-3.4a3.2 3.2 0 0 0-2.5-1c-2.4 0-3.6 1.4-3.6 4.4 0 3 1.2 4.6 3.6 4.6zm18 3.6c-1.7 0-3.2-.3-4.4-1a7 7 0 0 1-3-2.8c-.6-1.3-1-2.7-1-4.4 0-1.6.4-3 1-4.3a7 7 0 0 1 3-2.8c1.2-.7 2.7-1 4.4-1 1.6 0 3 .3 4.4 1a7 7 0 0 1 2.9 2.8c.6 1.2 1 2.7 1 4.3 0 1.7-.4 3.1-1 4.4a7 7 0 0 1-3 2.8c-1.2.7-2.7 1-4.3 1zm0-3.6c2.3 0 3.5-1.6 3.5-4.6 0-1.5-.3-2.6-1-3.4a3.2 3.2 0 0 0-2.5-1c-2.4 0-3.6 1.4-3.6 4.4 0 3 1.2 4.6 3.6 4.6zm27.4 3.4h-6l-6-7v7h-4.8V8.8h4.9v13.6l5.8-6.7h5.7l-6.6 7.5 7 8.2z\"\n              fill=\"currentColor\"\n            />\n          </g>\n        </Title>\n      </Brand>\n      {!state.transactionSuccess && !state.transactionFailure && (\n        <Introduction>Create an account to join the Storybook community</Introduction>\n      )}\n      <Content>\n        {state.transactionSuccess && !state.transactionFailure && (\n          <Presentation>\n            <p>\n              Everything is perfect. Your account is ready and we should probably get you started!\n            </p>\n            <p>So why don't you get started then?</p>\n            <Submit\n              dirty\n              onClick={() => {\n                setState({\n                  transacting: false,\n                  transactionSuccess: false,\n                  transactionFailure: false,\n                });\n              }}\n            >\n              Go back\n            </Submit>\n          </Presentation>\n        )}\n        {state.transactionFailure && !state.transactionSuccess && (\n          <Presentation>\n            <p>What a mess, this API is not working</p>\n            <p>\n              Someone should probably have a stern talking to about this, but it won't be me - coz\n              I'm gonna head out into the nice weather\n            </p>\n            <Submit\n              dirty\n              onClick={() => {\n                setState({\n                  transacting: false,\n                  transactionSuccess: false,\n                  transactionFailure: false,\n                });\n              }}\n            >\n              Go back\n            </Submit>\n          </Presentation>\n        )}\n        {!state.transactionSuccess && !state.transactionFailure && (\n          <Formik\n            initialValues={{ email: '', password: '', verifiedPassword: '' }}\n            validateOnBlur={false}\n            validateOnChange={false}\n            onSubmit={handleFormSubmit}\n            validate={({ email, password, verifiedPassword }) => {\n              const errors: FormErrors = {};\n\n              if (!email) {\n                errors.email = errorMap.email.required.normal;\n                errors.emailTooltip = errorMap.email.required.tooltip;\n              } else {\n                const validEmail = email.match(email99RegExp);\n\n                if (validEmail === null) {\n                  errors.email = errorMap.email.format.normal;\n                  errors.emailTooltip = errorMap.email.format.tooltip;\n                }\n              }\n\n              if (!password) {\n                errors.password = errorMap.password.required.normal;\n                errors.passwordTooltip = errorMap.password.required.tooltip;\n              } else if (password.length < 6) {\n                errors.password = errorMap.password.length.normal;\n                errors.passwordTooltip = errorMap.password.length.tooltip;\n              }\n\n              if (passwordVerification && !verifiedPassword) {\n                errors.verifiedPassword = errorMap.verifiedPassword.required.normal;\n                errors.verifiedPasswordTooltip = errorMap.verifiedPassword.required.tooltip;\n              } else if (passwordVerification && password !== verifiedPassword) {\n                errors.verifiedPassword = errorMap.verifiedPassword.match.normal;\n                errors.verifiedPasswordTooltip = errorMap.verifiedPassword.match.tooltip;\n              }\n\n              return errors;\n            }}\n          >\n            {({ errors: _errors, isSubmitting, dirty }: FormikProps<FormValues>) => {\n              const errors = _errors as FormErrors;\n\n              return (\n                <Form noValidate aria-disabled={isSubmitting ? 'true' : 'false'}>\n                  <FieldWrapper>\n                    <Label htmlFor=\"email\">Email</Label>\n                    <FormikInput id=\"email\" name=\"email\">\n                      {({ field }: { field: HTMLAttributes<HTMLInputElement> }) => (\n                        <>\n                          <Input\n                            data-testid=\"email\"\n                            aria-required=\"true\"\n                            aria-disabled={isSubmitting ? 'true' : 'false'}\n                            disabled={isSubmitting}\n                            type=\"email\"\n                            aria-invalid={errors.email ? 'true' : 'false'}\n                            {...field}\n                          />\n                          {errors.email && (\n                            <WithTooltip\n                              tooltip={<ErrorTooltip>{errors.emailTooltip}</ErrorTooltip>}\n                            >\n                              <ErrorWrapper>\n                                <ErrorIcon icon=\"question\" height={14} />\n                                <Error name=\"email\" component=\"div\" />\n                              </ErrorWrapper>\n                            </WithTooltip>\n                          )}\n                        </>\n                      )}\n                    </FormikInput>\n                  </FieldWrapper>\n                  <FieldWrapper>\n                    <Label htmlFor=\"password\">Password</Label>\n                    <FormikInput id=\"password\" name=\"password\">\n                      {({ field }: { field: HTMLAttributes<HTMLInputElement> }) => (\n                        <Input\n                          data-testid=\"password1\"\n                          aria-required=\"true\"\n                          aria-disabled={isSubmitting ? 'true' : 'false'}\n                          aria-invalid={errors.password ? 'true' : 'false'}\n                          type=\"password\"\n                          disabled={isSubmitting}\n                          {...field}\n                        />\n                      )}\n                    </FormikInput>\n                    {errors.password && (\n                      <WithTooltip tooltip={<ErrorTooltip>{errors.passwordTooltip}</ErrorTooltip>}>\n                        <ErrorWrapper data-testid=\"password-error-info\">\n                          <ErrorIcon icon=\"question\" height={14} />\n                          <Error name=\"password\" component=\"div\" />\n                        </ErrorWrapper>\n                      </WithTooltip>\n                    )}\n                  </FieldWrapper>\n                  {passwordVerification && (\n                    <FieldWrapper>\n                      <Label htmlFor=\"verifiedPassword\">Verify Password</Label>\n                      <FormikInput id=\"verifiedPassword\" name=\"verifiedPassword\">\n                        {({ field }: { field: HTMLAttributes<HTMLInputElement> }) => (\n                          <Input\n                            data-testid=\"password2\"\n                            aria-required=\"true\"\n                            aria-disabled={isSubmitting ? 'true' : 'false'}\n                            aria-invalid={errors.verifiedPassword ? 'true' : 'false'}\n                            type=\"password\"\n                            disabled={isSubmitting}\n                            {...field}\n                          />\n                        )}\n                      </FormikInput>\n                      {errors.verifiedPassword && (\n                        <WithTooltip\n                          tooltip={<ErrorTooltip>{errors.verifiedPasswordTooltip}</ErrorTooltip>}\n                        >\n                          <ErrorWrapper>\n                            <ErrorIcon icon=\"question\" height={14} />\n                            <Error name=\"verifiedPassword\" component=\"div\" />\n                          </ErrorWrapper>\n                        </WithTooltip>\n                      )}\n                    </FieldWrapper>\n                  )}\n                  <Actions>\n                    <Submit\n                      data-testid=\"submit\"\n                      aria-disabled={isSubmitting || !dirty ? 'true' : 'false'}\n                      disabled={isSubmitting || !dirty}\n                      dirty={dirty}\n                      type=\"submit\"\n                    >\n                      Create Account\n                    </Submit>\n                    <Reset\n                      aria-disabled={isSubmitting ? 'true' : 'false'}\n                      disabled={isSubmitting}\n                      type=\"reset\"\n                    >\n                      Reset\n                    </Reset>\n                  </Actions>\n                </Form>\n              );\n            }}\n          </Formik>\n        )}\n      </Content>\n    </Wrapper>\n  );\n};\n\nconst Wrapper = styled.section(({ theme }) => ({\n  fontFamily: theme.typography.fonts.base,\n  display: 'flex',\n  flexDirection: 'column',\n  alignItems: 'center',\n  width: 450,\n  padding: 32,\n  backgroundColor: theme.background.content,\n  borderRadius: 7,\n}));\n\nconst Brand = styled.div({\n  display: 'flex',\n  alignItems: 'center',\n  justifyContent: 'center',\n});\n\nconst Title = styled.svg({\n  height: 40,\n  zIndex: 1,\n  left: -32,\n  position: 'relative',\n});\n\nconst logoAnimation = keyframes({\n  '0': {\n    transform: 'rotateY(0deg)',\n    transformOrigin: '50% 5% 0',\n  },\n  '100%': {\n    transform: 'rotateY(360deg)',\n    transformOrigin: '50% 5% 0',\n  },\n});\n\ninterface LogoProps {\n  transacting: boolean;\n}\n\nconst Logo = styled.svg<LogoProps>(\n  ({ transacting }) =>\n    transacting && {\n      animation: `${logoAnimation} 1250ms both infinite`,\n    },\n  { height: 40, zIndex: 10, marginLeft: 32 }\n);\n\nconst Introduction = styled.p({\n  marginTop: 20,\n  textAlign: 'center',\n});\n\nconst Content = styled.div({\n  display: 'flex',\n  alignItems: 'flex-start',\n  justifyContent: 'center',\n  width: 350,\n  minHeight: 189,\n  marginTop: 8,\n});\n\nconst Presentation = styled.div({\n  textAlign: 'center',\n});\n\nconst Form = styled(FormikForm)({\n  width: '100%',\n  alignSelf: 'flex-start',\n  '&[aria-disabled=\"true\"]': {\n    opacity: 0.6,\n  },\n});\n\nconst FieldWrapper = styled.div({\n  display: 'flex',\n  flexDirection: 'column',\n  justifyContent: 'stretch',\n  marginBottom: 10,\n});\n\nconst Label = styled.label({\n  fontSize: 13,\n  fontWeight: 500,\n  marginBottom: 6,\n});\n\nconst Input = styled.input(({ theme }) => ({\n  fontSize: 14,\n  color: theme.color.defaultText,\n  padding: '10px 15px',\n  borderRadius: 4,\n  appearance: 'none',\n  outline: 'none',\n  border: '0 none',\n  boxShadow: 'rgb(0 0 0 / 10%) 0px 0px 0px 1px inset',\n  '&:focus': {\n    boxShadow: 'rgb(30 167 253) 0px 0px 0px 1px inset',\n  },\n  '&:active': {\n    boxShadow: 'rgb(30 167 253) 0px 0px 0px 1px inset',\n  },\n  '&[aria-invalid=\"true\"]': {\n    boxShadow: 'rgb(255 68 0) 0px 0px 0px 1px inset',\n  },\n}));\n\nconst ErrorWrapper = styled.div({\n  display: 'flex',\n  alignItems: 'flex-start',\n  fontSize: 11,\n  marginTop: 6,\n  cursor: 'help',\n});\n\nconst ErrorIcon = styled(Icons)(({ theme }) => ({\n  fill: theme.color.defaultText,\n  opacity: 0.8,\n  marginRight: 6,\n  marginLeft: 2,\n  marginTop: 1,\n}));\n\nconst ErrorTooltip = styled.div(({ theme }) => ({\n  fontFamily: theme.typography.fonts.base,\n  fontSize: 13,\n  padding: 8,\n  maxWidth: 350,\n}));\n\nconst Actions = styled.div({\n  alignSelf: 'stretch',\n  display: 'flex',\n  justifyContent: 'space-between',\n  marginTop: 24,\n});\n\nconst Error = styled(ErrorMessage)({});\n\ninterface ButtonProps {\n  dirty?: boolean;\n}\n\nconst Button = styled.button<ButtonProps>({\n  backgroundColor: 'transparent',\n  border: '0 none',\n  outline: 'none',\n  appearance: 'none',\n  fontWeight: 500,\n  fontSize: 12,\n  flexBasis: '50%',\n  cursor: 'pointer',\n  padding: '11px 16px',\n  borderRadius: 4,\n  textTransform: 'uppercase',\n  '&:focus': {\n    textDecoration: 'underline',\n    fontWeight: 700,\n  },\n  '&:active': {\n    textDecoration: 'underline',\n    fontWeight: 700,\n  },\n  '&[aria-disabled=\"true\"]': {\n    cursor: 'default',\n  },\n});\n\nconst Submit = styled(Button)(({ theme, dirty }) => ({\n  marginRight: 8,\n  backgroundColor: theme.color.secondary,\n  color: theme.color.inverseText,\n  opacity: dirty ? 1 : 0.6,\n  boxShadow: 'rgb(30 167 253 / 10%) 0 0 0 1px inset',\n}));\n\nconst Reset = styled(Button)(({ theme }) => ({\n  marginLeft: 8,\n  boxShadow: 'rgb(30 167 253) 0 0 0 1px inset',\n  color: theme.color.secondary,\n}));\n"
  },
  {
    "path": "test-storybooks/external-docs/components/Introduction.mdx",
    "content": "## Introduction to the Design system\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n"
  },
  {
    "path": "test-storybooks/external-docs/components/Template.mdx",
    "content": "import { Title, Description, ArgsTable, Stories, PRIMARY_STORY } from '@storybook/addon-docs/blocks';\n\n# This is a template!\n\n<Title />\n<Description />\n<ArgsTable story={PRIMARY_STORY} />\n<Stories />\n"
  },
  {
    "path": "test-storybooks/external-docs/components/button.mdx",
    "content": "import { Meta } from '@storybook/addon-docs/blocks';\nimport * as ButtonStories from './button.stories.tsx';\nimport Template from './Template.mdx';\n\n<Meta of={ButtonStories} />\n\n<Template />\n"
  },
  {
    "path": "test-storybooks/external-docs/components/button.stories.tsx",
    "content": "/* eslint-disable storybook/use-storybook-testing-library */\n// @TODO: use addon-interactions and remove the rule disable above\nimport React from 'react';\nimport type { Meta, ComponentStoryFn } from '@storybook/react';\nimport { screen } from '@testing-library/dom';\nimport userEvent from '@testing-library/user-event';\nimport { Button } from './button';\n\nexport default {\n  component: Button,\n  title: 'Examples / Button',\n  argTypes: { onClick: { action: 'click ' } },\n  // render: () => <>hohoho</>,\n} as Meta;\n\nexport const WithArgs: ComponentStoryFn<typeof Button> = (args) => <Button {...args} />;\nWithArgs.args = { label: 'With args' };\n\nexport const Basic = () => <Button label=\"Click me\" />;\n\nexport const StoryObject = {\n  render: () => <>hahaha</>,\n};\n\nexport const StoryNoRender = {\n  args: { label: 'magic!' },\n};\n\nexport const StoryWithPlay = {\n  args: { label: 'play' },\n  play: () => {\n    console.log('play!!');\n    userEvent.click(screen.getByRole('button'));\n  },\n};\n\nexport const CSF2StoryWithPlay = WithArgs.bind({});\nCSF2StoryWithPlay.play = () => {\n  console.log('play!!');\n  userEvent.click(screen.getByRole('button'));\n};\n"
  },
  {
    "path": "test-storybooks/external-docs/components/button.tsx",
    "content": "import React, { ButtonHTMLAttributes } from 'react';\n\nexport interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n  /**\n   * A label to show on the button\n   */\n  label: string;\n}\n\nexport const Button = ({ label = 'Hello', ...props }: ButtonProps) => (\n  <button type=\"button\" {...props}>\n    {label}\n  </button>\n);\n"
  },
  {
    "path": "test-storybooks/external-docs/components/emoji-button.mdx",
    "content": "import { Meta } from '@storybook/addon-docs/blocks';\nimport * as EmojiButtonStories from './emoji-button.stories.tsx';\nimport Template from './Template.mdx';\n\n<Meta of={EmojiButtonStories} />\n\n<Template />\n"
  },
  {
    "path": "test-storybooks/external-docs/components/emoji-button.stories.tsx",
    "content": "import React from 'react';\nimport { EmojiButton } from './emoji-button';\n\nexport default { component: EmojiButton, title: 'Examples / Emoji Button' };\n\nexport const WithArgs = (args: any) => <EmojiButton {...args} />;\nWithArgs.args = { label: 'With args' };\nexport const Basic = () => <EmojiButton label=\"Click me\" />;\n"
  },
  {
    "path": "test-storybooks/external-docs/components/emoji-button.tsx",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\n\nexport const EmojiButton = ({ label, ...props }: { label: string }) => (\n  <button type=\"button\" {...props}>\n    ⚠️ {label}\n  </button>\n);\n\nEmojiButton.propTypes = {\n  /**\n   * A label to show on the button\n   */\n  label: PropTypes.string,\n};\n\nEmojiButton.defaultProps = {\n  label: 'Hello',\n};\n"
  },
  {
    "path": "test-storybooks/external-docs/next-env.d.ts",
    "content": "/// <reference types=\"next\" />\n/// <reference types=\"next/image-types/global\" />\n\n// NOTE: This file should not be edited\n// see https://nextjs.org/docs/basic-features/typescript for more information.\n"
  },
  {
    "path": "test-storybooks/external-docs/next.config.js",
    "content": "const { IgnorePlugin } = require('webpack');\n\n// next.config.js\nconst withNextra = require('nextra')({\n  theme: 'nextra-theme-docs',\n  themeConfig: './theme.config.js',\n  // optional: add `unstable_staticImage: true` to enable Nextra's auto image import\n});\n\nmodule.exports = withNextra({\n  reactStrictMode: true,\n\n  // We use a custom webpack config here to work around https://github.com/storybookjs/storybook/issues/17926\n  // We can remove this when the monorepo is upgraded to `react@18`.\n  //   (Currently external docs do not work with React <18, without a simlar workaround)\n  webpack(config) {\n    return {\n      ...config,\n      plugins: [...config.plugins, new IgnorePlugin({ resourceRegExp: /react-dom\\/client$/ })],\n    };\n  },\n});\n"
  },
  {
    "path": "test-storybooks/external-docs/package.json",
    "content": "{\n  \"name\": \"@storybook/external-docs\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"next build\",\n    \"build-storybook\": \"cross-env STORYBOOK_DISPLAY_WARNING=true DISPLAY_WARNING=true NODE_OPTIONS=\\\"--preserve-symlinks --preserve-symlinks-main\\\" storybook build -c .storybook\",\n    \"dev\": \"next dev\",\n    \"lint\": \"next lint\",\n    \"start\": \"next start\",\n    \"storybook\": \"cross-env STORYBOOK_DISPLAY_WARNING=true DISPLAY_WARNING=true NODE_OPTIONS=\\\"--preserve-symlinks --preserve-symlinks-main\\\" storybook dev -p 9011 -c .storybook\"\n  },\n  \"resolutions\": {\n    \"@storybook/addon-a11y\": \"file:../../code/addons/a11y\",\n    \"@storybook/addon-docs\": \"file:../../code/addons/docs\",\n    \"@storybook/addon-links\": \"file:../../code/addons/links\",\n    \"@storybook/addon-themes\": \"file:../../code/addons/themes\",\n    \"@storybook/angular\": \"file:../../code/frameworks/angular\",\n    \"@storybook/builder-vite\": \"file:../../code/builders/builder-vite\",\n    \"@storybook/builder-webpack5\": \"file:../../code/builders/builder-webpack5\",\n    \"@storybook/codemod\": \"file:../../code/lib/codemod\",\n    \"@storybook/core-webpack\": \"file:../../code/lib/core-webpack\",\n    \"@storybook/csf-plugin\": \"file:../../code/lib/csf-plugin\",\n    \"@storybook/ember\": \"file:../../code/frameworks/ember\",\n    \"@storybook/html\": \"file:../../code/renderers/html\",\n    \"@storybook/nextjs\": \"file:../../code/frameworks/nextjs\",\n    \"@storybook/preact\": \"file:../../code/renderers/preact\",\n    \"@storybook/preact-vite\": \"file:../../code/frameworks/preact-vite\",\n    \"@storybook/preset-create-react-app\": \"file:../../code/presets/create-react-app\",\n    \"@storybook/preset-react-webpack\": \"file:../../code/presets/react-webpack\",\n    \"@storybook/preset-server-webpack\": \"file:../../code/presets/server-webpack\",\n    \"@storybook/react\": \"file:../../code/renderers/react\",\n    \"@storybook/react-dom-shim\": \"file:../../code/lib/react-dom-shim\",\n    \"@storybook/react-vite\": \"file:../../code/frameworks/react-vite\",\n    \"@storybook/react-webpack5\": \"file:../../code/frameworks/react-webpack5\",\n    \"@storybook/server\": \"file:../../code/renderers/server\",\n    \"@storybook/server-webpack5\": \"file:../../code/frameworks/server-webpack5\",\n    \"@storybook/svelte\": \"file:../../code/renderers/svelte\",\n    \"@storybook/svelte-vite\": \"file:../../code/frameworks/svelte-vite\",\n    \"@storybook/sveltekit\": \"file:../../code/frameworks/sveltekit\",\n    \"@storybook/vue3\": \"file:../../code/renderers/vue3\",\n    \"@storybook/vue3-vite\": \"file:../../code/frameworks/vue3-vite\",\n    \"@storybook/web-components\": \"file:../../code/renderers/web-components\",\n    \"@storybook/web-components-vite\": \"file:../../code/frameworks/web-components-vite\",\n    \"storybook\": \"file:../../code/core\"\n  },\n  \"dependencies\": {\n    \"@storybook/addon-docs\": \"*\",\n    \"@storybook/react\": \"*\",\n    \"@storybook/react-webpack5\": \"*\",\n    \"formik\": \"^2.2.9\",\n    \"next\": \"^12.1.0\",\n    \"nextra\": \"^1.1.0\",\n    \"nextra-theme-docs\": \"^1.2.6\",\n    \"prop-types\": \"^15.8.1\",\n    \"react\": \"16.14.0\",\n    \"react-dom\": \"^18.2.0\"\n  },\n  \"devDependencies\": {\n    \"@babel/preset-env\": \"^7.22.0\",\n    \"@testing-library/dom\": \"^7.31.2\",\n    \"@testing-library/user-event\": \"^13.1.9\",\n    \"@types/babel__preset-env\": \"^7\",\n    \"@types/prop-types\": \"^15\",\n    \"@types/react\": \"^17.0.39\",\n    \"cross-env\": \"^7.0.3\",\n    \"eslint\": \"8.7.0\",\n    \"eslint-config-next\": \"12.0.8\",\n    \"storybook\": \"*\",\n    \"typescript\": \"~5.2.2\",\n    \"webpack\": \"5\"\n  }\n}\n"
  },
  {
    "path": "test-storybooks/external-docs/pages/_app.js",
    "content": "/* eslint-disable react/prop-types */\nimport React from 'react';\nimport 'nextra-theme-docs/style.css';\nimport { ExternalDocs } from '@storybook/addon-docs/blocks';\n\nimport * as reactAnnotations from '@storybook/react/preview';\nimport * as previewAnnotations from '../.storybook/preview';\n\nexport default function Nextra({ Component, pageProps }) {\n  return (\n    <ExternalDocs projectAnnotationsList={[reactAnnotations, previewAnnotations]}>\n      <Component {...pageProps} />\n    </ExternalDocs>\n  );\n}\n"
  },
  {
    "path": "test-storybooks/external-docs/pages/api/hello.js",
    "content": "// Next.js API route support: https://nextjs.org/docs/api-routes/introduction\n\nexport default function handler(req, res) {\n  res.status(200).json({ name: 'John Doe' });\n}\n"
  },
  {
    "path": "test-storybooks/external-docs/pages/index.mdx",
    "content": "import Callout from 'nextra-theme-docs/callout';\nimport { Title, Meta, Story, Canvas } from '@storybook/addon-docs/blocks';\nimport * as AccountFormStories from '../components/AccountForm.stories';\nimport * as ButtonStories from '../components/button.stories';\n\n<Title>Embedded docs demo</Title>\n\n<Meta of={AccountFormStories} />\n\nThis is an example of an MDX file that embeds Doc Blocks and CSF stories.\n\n<Canvas withSource={{ language: 'html', code: '<h1>hahaha</h1>' }}>\n  <Story of={AccountFormStories.Standard} />\n</Canvas>\n\n<Story of={ButtonStories.Basic} meta={ButtonStories} />\n\n<Callout emoji=\"✅\">\n  **MDX** (the library), at its core, transforms MDX (the syntax) to JSX. It receives an MDX string\n  and outputs a _JSX string_. It does this by parsing the MDX document to a syntax tree and then\n  generates a JSX document from that tree.\n</Callout>\n"
  },
  {
    "path": "test-storybooks/external-docs/pages/nested/item1.mdx",
    "content": "# Item 1\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Partiendo adversarium no mea. Pri posse graeco definitiones cu, id eam populo quaestio adipiscing, usu quod malorum te. Pri posse graeco definitiones cu, id eam populo quaestio adipiscing, usu quod malorum te. Et mazim recteque nam. Pri posse graeco definitiones cu, id eam populo quaestio adipiscing, usu quod malorum te. Offendit eleifend moderatius ex vix, quem odio mazim et qui, purto expetendis cotidieque quo cu, veri persius vituperata ei nec. Ad doctus gubergren duo, mel te postea suavitate. Vivendum intellegat et qui, ei denique consequuntur vix. Scripta periculis ei eam, te pro movet reformidans. Te cum aeque repudiandae delicatissimi, cu populo dictas ponderum vel, dolor consequat ut vix. Pri posse graeco definitiones cu, id eam populo quaestio adipiscing, usu quod malorum te. Offendit eleifend moderatius ex vix, quem odio mazim et qui, purto expetendis cotidieque quo cu, veri persius vituperata ei nec.\n"
  },
  {
    "path": "test-storybooks/external-docs/pages/nested/item2.mdx",
    "content": "# Item 2\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Vivendum intellegat et qui, ei denique consequuntur vix. Tritani reprehendunt pro an, his ne liber iusto. Vivendum intellegat et qui, ei denique consequuntur vix. Scripta periculis ei eam, te pro movet reformidans. Pri posse graeco definitiones cu, id eam populo quaestio adipiscing, usu quod malorum te. Per ea omnis decore, eu mei appareat tincidunt. Et clita interesset quo. Vivendum intellegat et qui, ei denique consequuntur vix. Pri posse graeco definitiones cu, id eam populo quaestio adipiscing, usu quod malorum te. Offendit eleifend moderatius ex vix, quem odio mazim et qui, purto expetendis cotidieque quo cu, veri persius vituperata ei nec. Et mazim recteque nam. Offendit eleifend moderatius ex vix, quem odio mazim et qui, purto expetendis cotidieque quo cu, veri persius vituperata ei nec. Pri veritus expetendis ex. Offendit eleifend moderatius ex vix, quem odio mazim et qui, purto expetendis cotidieque quo cu, veri persius vituperata ei nec.\n"
  },
  {
    "path": "test-storybooks/external-docs/pages/setup.mdx",
    "content": "# Setup instructions\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Errem laboramus sit ei, te sed brute viderer. Scripta periculis ei eam, te pro movet reformidans. Vivendum intellegat et qui, ei denique consequuntur vix. Pri posse graeco definitiones cu, id eam populo quaestio adipiscing, usu quod malorum te. Offendit eleifend moderatius ex vix, quem odio mazim et qui, purto expetendis cotidieque quo cu, veri persius vituperata ei nec. Scripta periculis ei eam, te pro movet reformidans. Scripta periculis ei eam, te pro movet reformidans. Accusam explicari sed ei. Vivendum intellegat et qui, ei denique consequuntur vix. Offendit eleifend moderatius ex vix, quem odio mazim et qui, purto expetendis cotidieque quo cu, veri persius vituperata ei nec. Scripta periculis ei eam, te pro movet reformidans. Offendit eleifend moderatius ex vix, quem odio mazim et qui, ei denique consequuntur vix. Vivendum intellegat et qui, ei denique consequuntur vix.\n"
  },
  {
    "path": "test-storybooks/external-docs/styles/Home.module.css",
    "content": ".container {\n  padding: 0 2rem;\n}\n\n.main {\n  min-height: 100vh;\n  padding: 4rem 0;\n  flex: 1;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n}\n\n.footer {\n  display: flex;\n  flex: 1;\n  padding: 2rem 0;\n  border-top: 1px solid #eaeaea;\n  justify-content: center;\n  align-items: center;\n}\n\n.footer a {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  flex-grow: 1;\n}\n\n.title a {\n  color: #0070f3;\n  text-decoration: none;\n}\n\n.title a:hover,\n.title a:focus,\n.title a:active {\n  text-decoration: underline;\n}\n\n.title {\n  margin: 0;\n  line-height: 1.15;\n  font-size: 4rem;\n}\n\n.title,\n.description {\n  text-align: center;\n}\n\n.description {\n  margin: 4rem 0;\n  line-height: 1.5;\n  font-size: 1.5rem;\n}\n\n.code {\n  background: #fafafa;\n  border-radius: 5px;\n  padding: 0.75rem;\n  font-size: 1.1rem;\n  font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,\n    Bitstream Vera Sans Mono, Courier New, monospace;\n}\n\n.grid {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  flex-wrap: wrap;\n  max-width: 800px;\n}\n\n.card {\n  margin: 1rem;\n  padding: 1.5rem;\n  text-align: left;\n  color: inherit;\n  text-decoration: none;\n  border: 1px solid #eaeaea;\n  border-radius: 10px;\n  transition: color 0.15s ease, border-color 0.15s ease;\n  max-width: 300px;\n}\n\n.card:hover,\n.card:focus,\n.card:active {\n  color: #0070f3;\n  border-color: #0070f3;\n}\n\n.card h2 {\n  margin: 0 0 1rem 0;\n  font-size: 1.5rem;\n}\n\n.card p {\n  margin: 0;\n  font-size: 1.25rem;\n  line-height: 1.5;\n}\n\n.logo {\n  height: 1em;\n  margin-left: 0.5rem;\n}\n\n@media (max-width: 600px) {\n  .grid {\n    width: 100%;\n    flex-direction: column;\n  }\n}\n"
  },
  {
    "path": "test-storybooks/external-docs/styles/globals.css",
    "content": "html,\nbody {\n  padding: 0;\n  margin: 0;\n  font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell,\n    Fira Sans, Droid Sans, Helvetica Neue, sans-serif;\n}\n\na {\n  color: inherit;\n  text-decoration: none;\n}\n\n* {\n  box-sizing: border-box;\n}\n"
  },
  {
    "path": "test-storybooks/external-docs/theme.config.js",
    "content": "import React from 'react';\n\n// theme.config.js\nexport default {\n  projectLink: 'https://github.com/shuding/nextra', // GitHub link in the navbar\n  docsRepositoryBase: 'https://github.com/shuding/nextra/blob/master', // base URL for the docs repository\n  titleSuffix: ' – Nextra',\n  nextLinks: true,\n  prevLinks: true,\n  search: true,\n  customSearch: null, // customizable, you can use algolia for example\n  darkMode: true,\n  footer: true,\n  footerText: `MIT ${new Date().getFullYear()} © Shu Ding.`,\n  footerEditLink: `Edit this page on GitHub`,\n  logo: (\n    <>\n      <svg>...</svg>\n      <span>Next.js Static Site Generator</span>\n    </>\n  ),\n  head: (\n    <>\n      <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n      <meta name=\"description\" content=\"Nextra: the next docs builder\" />\n      <meta name=\"og:title\" content=\"Nextra: the next docs builder\" />\n    </>\n  ),\n};\n"
  },
  {
    "path": "test-storybooks/external-docs/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"strict\": false,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noEmit\": false,\n    \"incremental\": true,\n    \"esModuleInterop\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"jsx\": \"preserve\"\n  },\n  \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/.eslintrc.json",
    "content": "{\n  \"extends\": \"next/core-web-vitals\"\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n.yarn/install-state.gz\n\n# testing\n/coverage\n\n# next.js\n/.next/\n/out/\n\n# production\n/build\n\n# misc\n.DS_Store\n*.pem\n\n# debug\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# local env files\n.env*.local\n\n# vercel\n.vercel\n\n# typescript\n*.tsbuildinfo\nnext-env.d.ts\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/.storybook/main.ts",
    "content": "import type { StorybookConfig } from \"@storybook/nextjs\";\n\nconst config: StorybookConfig = {\n  stories: [\"../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)\"],\n  framework: {\n    name: \"@storybook/nextjs\",\n    options: {},\n  },\n};\nexport default config;\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/.storybook/preview.tsx",
    "content": "import React from 'react';\nimport type { Preview } from '@storybook/react';\n\nconsole.log('preview file is called!');\n\nconst preview: Preview = {\n  decorators: [\n    (StoryFn) => (\n      <div data-testid=\"global-decorator\">\n        Global Decorator\n        <br />\n        <StoryFn />\n      </div>\n    ),\n  ],\n  globalTypes: {\n    locale: {\n      description: 'Locale for components',\n      defaultValue: 'en',\n      toolbar: {\n        title: 'Locale',\n        icon: 'circlehollow',\n        items: ['es', 'en'],\n      },\n    },\n  },\n};\n\nexport default preview;\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/.swcrc",
    "content": "{\n  \"jsc\": {\n    \"parser\": {\n      \"syntax\": \"typescript\",\n      \"tsx\": true,\n      \"decorators\": true,\n      \"dynamicImport\": true\n    },\n    \"transform\": {\n      \"react\": {\n        \"runtime\": \"automatic\"\n      }\n    },\n    \"target\": \"es2015\"\n  },\n  \"module\": {\n    \"type\": \"es6\",\n    \"noInterop\": true\n  }\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/.yarnrc.yml",
    "content": "enableImmutableInstalls: false\nnodeLinker: node-modules\nyarnPath: ../../../.yarn/releases/yarn-4.10.3.cjs\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/jest.config.js",
    "content": "const nextJest = require('next/jest.js');\nconst { getPackageAliases } = require('@storybook/nextjs/export-mocks');\n \nconst createJestConfig = nextJest({\n  // Provide the path to your Next.js app to load next.config.js and .env files in your test environment\n  dir: __dirname,\n})\n \n/** @type {import('jest').Config} */\nconst customJestConfig = {\n  coverageProvider: 'v8',\n  testEnvironment: '@happy-dom/jest-environment',\n  // Add more setup options before each test is run\n  setupFilesAfterEnv: ['./jest.setup.ts'],\n  transform: {\n    '^.+\\\\.(t|j)sx?$': [\n      '@swc/jest',\n      {\n        module: {\n          type: 'commonjs',\n        },\n      },\n    ],\n  },\n  transformIgnorePatterns: [],\n\n  moduleNameMapper: {\n    ...getPackageAliases()\n  },\n};\n\n// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async\nmodule.exports = createJestConfig(customJestConfig)"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/jest.setup.ts",
    "content": "import \"@testing-library/jest-dom\";\nimport { setProjectAnnotations } from \"@storybook/nextjs\";\n\nimport sbAnnotations from \"./.storybook/preview\";\n\nsetProjectAnnotations([sbAnnotations]);\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/next.config.mjs",
    "content": "/** @type {import('next').NextConfig} */\nconst nextConfig = {\n  reactStrictMode: true,\n};\n\nexport default nextConfig;\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/package.json",
    "content": "{\n  \"name\": \"portable-stories-nextjs\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"next build\",\n    \"cypress\": \"echo 'No cypress setup yet'\",\n    \"dev\": \"next dev\",\n    \"jest\": \"echo 'No jest setup yet'\",\n    \"jest-\": \"node node_modules/jest/bin/jest.js\",\n    \"lint\": \"next lint\",\n    \"playwright-ct\": \"echo 'No playwright setup yet'\",\n    \"start\": \"next start\",\n    \"storybook\": \"storybook dev -p 6006\",\n    \"vitest\": \"echo 'Vitest is not supported in Next.js testing'\"\n  },\n  \"resolutions\": {\n    \"@storybook/addon-a11y\": \"file:../../../code/addons/a11y\",\n    \"@storybook/addon-docs\": \"file:../../../code/addons/docs\",\n    \"@storybook/addon-links\": \"file:../../../code/addons/links\",\n    \"@storybook/addon-themes\": \"file:../../../code/addons/themes\",\n    \"@storybook/angular\": \"file:../../../code/frameworks/angular\",\n    \"@storybook/builder-vite\": \"file:../../../code/builders/builder-vite\",\n    \"@storybook/builder-webpack5\": \"file:../../../code/builders/builder-webpack5\",\n    \"@storybook/codemod\": \"file:../../../code/lib/codemod\",\n    \"@storybook/core-webpack\": \"file:../../../code/lib/core-webpack\",\n    \"@storybook/csf-plugin\": \"file:../../../code/lib/csf-plugin\",\n    \"@storybook/ember\": \"file:../../../code/frameworks/ember\",\n    \"@storybook/html\": \"file:../../../code/renderers/html\",\n    \"@storybook/nextjs\": \"file:../../../code/frameworks/nextjs\",\n    \"@storybook/preact\": \"file:../../../code/renderers/preact\",\n    \"@storybook/preact-vite\": \"file:../../../code/frameworks/preact-vite\",\n    \"@storybook/preset-create-react-app\": \"file:../../../code/presets/create-react-app\",\n    \"@storybook/preset-react-webpack\": \"file:../../../code/presets/react-webpack\",\n    \"@storybook/preset-server-webpack\": \"file:../../../code/presets/server-webpack\",\n    \"@storybook/react\": \"file:../../../code/renderers/react\",\n    \"@storybook/react-dom-shim\": \"file:../../../code/lib/react-dom-shim\",\n    \"@storybook/react-vite\": \"file:../../../code/frameworks/react-vite\",\n    \"@storybook/react-webpack5\": \"file:../../../code/frameworks/react-webpack5\",\n    \"@storybook/server\": \"file:../../../code/renderers/server\",\n    \"@storybook/server-webpack5\": \"file:../../../code/frameworks/server-webpack5\",\n    \"@storybook/svelte\": \"file:../../../code/renderers/svelte\",\n    \"@storybook/svelte-vite\": \"file:../../../code/frameworks/svelte-vite\",\n    \"@storybook/sveltekit\": \"file:../../../code/frameworks/sveltekit\",\n    \"@storybook/vue3\": \"file:../../../code/renderers/vue3\",\n    \"@storybook/vue3-vite\": \"file:../../../code/frameworks/vue3-vite\",\n    \"@storybook/web-components\": \"file:../../../code/renderers/web-components\",\n    \"@storybook/web-components-vite\": \"file:../../../code/frameworks/web-components-vite\",\n    \"eslint-plugin-storybook\": \"file:../../../code/lib/eslint-plugin\",\n    \"storybook\": \"file:../../../code/core\"\n  },\n  \"dependencies\": {\n    \"next\": \"^14.2.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\"\n  },\n  \"devDependencies\": {\n    \"@happy-dom/jest-environment\": \"^15.11.7\",\n    \"@jest/globals\": \"^29.7.0\",\n    \"@storybook/nextjs\": \"^8.0.0\",\n    \"@storybook/react\": \"^8.0.0\",\n    \"@swc/core\": \"^1.4.2\",\n    \"@swc/jest\": \"^0.2.36\",\n    \"@testing-library/jest-dom\": \"^6.6.3\",\n    \"@testing-library/react\": \"^16.0.0\",\n    \"@types/react\": \"^18.2.55\",\n    \"@types/react-dom\": \"^18.2.19\",\n    \"@typescript-eslint/eslint-plugin\": \"^6.21.0\",\n    \"@typescript-eslint/parser\": \"^6.21.0\",\n    \"eslint\": \"^8.56.0\",\n    \"eslint-plugin-storybook\": \"^0.6.15\",\n    \"jest\": \"^29.7.0\",\n    \"storybook\": \"^8.0.0\",\n    \"typescript\": \"^5.2.2\"\n  },\n  \"maintainer_please_read_this\": {\n    \"_\": \"we use file protocol to make this setup close to real life scenarios as well as avoid issues with duplicated React instances. When you recompile the SB packages, you need to rerun install.\"\n  },\n  \"nx\": {\n    \"includedScripts\": []\n  }\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/pages/_app.tsx",
    "content": "import \"@/styles/globals.css\";\nimport type { AppProps } from \"next/app\";\n\nexport default function App({ Component, pageProps }: AppProps) {\n  return <Component {...pageProps} />;\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/pages/_document.tsx",
    "content": "import { Html, Head, Main, NextScript } from \"next/document\";\n\nexport default function Document() {\n  return (\n    <Html lang=\"en\">\n      <Head />\n      <body>\n        <Main />\n        <NextScript />\n      </body>\n    </Html>\n  );\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/pages/api/hello.ts",
    "content": "// Next.js API route support: https://nextjs.org/docs/api-routes/introduction\nimport type { NextApiRequest, NextApiResponse } from \"next\";\n\ntype Data = {\n  name: string;\n};\n\nexport default function handler(\n  req: NextApiRequest,\n  res: NextApiResponse<Data>,\n) {\n  res.status(200).json({ name: \"John Doe\" });\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/pages/index.tsx",
    "content": "import Head from \"next/head\";\nimport Image from \"next/image\";\nimport { Inter } from \"next/font/google\";\nimport styles from \"@/styles/Home.module.css\";\n\nconst inter = Inter({ subsets: [\"latin\"] });\n\nexport default function Home() {\n  return (\n    <>\n      <Head>\n        <title>Create Next App</title>\n        <meta name=\"description\" content=\"Generated by create next app\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n      </Head>\n      <main className={`${styles.main} ${inter.className}`}>\n        <div className={styles.description}>\n          <p>\n            Get started by editing&nbsp;\n            <code className={styles.code}>pages/index.tsx</code>\n          </p>\n          <div>\n            <a\n              href=\"https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n            >\n              By{\" \"}\n              <Image\n                src=\"/vercel.svg\"\n                alt=\"Vercel Logo\"\n                className={styles.vercelLogo}\n                width={100}\n                height={24}\n                priority\n              />\n            </a>\n          </div>\n        </div>\n\n        <div className={styles.center}>\n          <Image\n            className={styles.logo}\n            src=\"/next.svg\"\n            alt=\"Next.js Logo\"\n            width={180}\n            height={37}\n            priority\n          />\n        </div>\n\n        <div className={styles.grid}>\n          <a\n            href=\"https://nextjs.org/docs?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app\"\n            className={styles.card}\n            target=\"_blank\"\n            rel=\"noopener noreferrer\"\n          >\n            <h2>\n              Docs <span>-&gt;</span>\n            </h2>\n            <p>\n              Find in-depth information about Next.js features and&nbsp;API.\n            </p>\n          </a>\n\n          <a\n            href=\"https://nextjs.org/learn?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app\"\n            className={styles.card}\n            target=\"_blank\"\n            rel=\"noopener noreferrer\"\n          >\n            <h2>\n              Learn <span>-&gt;</span>\n            </h2>\n            <p>\n              Learn about Next.js in an interactive course with&nbsp;quizzes!\n            </p>\n          </a>\n\n          <a\n            href=\"https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app\"\n            className={styles.card}\n            target=\"_blank\"\n            rel=\"noopener noreferrer\"\n          >\n            <h2>\n              Templates <span>-&gt;</span>\n            </h2>\n            <p>\n              Discover and deploy boilerplate example Next.js&nbsp;projects.\n            </p>\n          </a>\n\n          <a\n            href=\"https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app\"\n            className={styles.card}\n            target=\"_blank\"\n            rel=\"noopener noreferrer\"\n          >\n            <h2>\n              Deploy <span>-&gt;</span>\n            </h2>\n            <p>\n              Instantly deploy your Next.js site to a shareable URL\n              with&nbsp;Vercel.\n            </p>\n          </a>\n        </div>\n      </main>\n    </>\n  );\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/project.json",
    "content": "{\n  \"name\": \"portable-stories-kitchen-sink/nextjs\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"application\",\n  \"targets\": {\n    \"jest\": {},\n    \"vitest\": {},\n    \"playwright-ct\": {},\n    \"cypress\": {}\n  },\n  \"tags\": [\"ci:normal\", \"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/stories/DynamicImport.stories.tsx",
    "content": "import dynamic from 'next/dynamic';\nimport React, { Suspense } from 'react';\n\nconst DynamicComponent = dynamic(() => import('./dynamic-component'), {\n  ssr: false,\n});\n\nfunction Component() {\n  return (\n    <Suspense fallback=\"Loading...\">\n      <DynamicComponent />\n    </Suspense>\n  );\n}\n\nexport default {\n  component: Component,\n} as Meta<typeof Component>;\n\nexport const Default = {};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/stories/Font.stories.tsx",
    "content": "import Font from './Font';\n\nexport default {\n  component: Font,\n};\n\nexport const WithClassName = {\n  args: {\n    variant: 'className',\n  },\n};\n\nexport const WithStyle = {\n  args: {\n    variant: 'style',\n  },\n};\n\nexport const WithVariable = {\n  args: {\n    variant: 'variable',\n  },\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/stories/Font.tsx",
    "content": "/* eslint-disable react/prop-types */\nimport { Rubik_Puddles } from 'next/font/google';\nimport localFont from 'next/font/local';\n\nimport React from 'react';\n\nconst rubik = Rubik_Puddles({\n  subsets: ['latin'],\n  variable: '--font-latin-rubik',\n  weight: '400',\n});\n\nexport const localRubikStorm = localFont({\n  src: '/fonts/RubikStorm-Regular.ttf',\n  variable: '--font-rubik-storm',\n});\n\nexport default function Font({ variant }) {\n  switch (variant) {\n    case 'className':\n      return (\n        <div>\n          <h1 className={rubik.className}>Google Rubik Puddles</h1>\n          <h1 className={localRubikStorm.className}>Google Local Rubik Storm</h1>\n        </div>\n      );\n    case 'style':\n      return (\n        <div>\n          <h1 style={rubik.style}>Google Rubik Puddles</h1>\n          <h1 style={localRubikStorm.style}>Google Local Rubik Storm</h1>\n        </div>\n      );\n    case 'variable':\n      return (\n        <div>\n          <div className={rubik.variable}>\n            <h1\n              style={{\n                fontFamily: 'var(--font-latin-rubik)',\n                fontStyle: rubik.style.fontStyle,\n                fontWeight: rubik.style.fontWeight,\n              }}\n            >\n              Google Rubik Puddles\n            </h1>\n          </div>\n          <div className={localRubikStorm.variable}>\n            <h1\n              style={{\n                fontFamily: 'var(--font-rubik-storm)',\n                fontStyle: localRubikStorm.style.fontStyle,\n                fontWeight: localRubikStorm.style.fontWeight,\n              }}\n            >\n              Google Local Rubik Storm\n            </h1>\n          </div>\n        </div>\n      );\n    default:\n      return null;\n  }\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/stories/GetImageProps.stories.tsx",
    "content": "import { getImageProps } from 'next/image';\nimport React from 'react';\n\nimport Accessibility from './assets/accessibility.svg';\nimport Testing from './assets/testing.png';\n\n// referenced from https://nextjs.org/docs/pages/api-reference/components/image#theme-detection-picture\nconst Component: React.FC<any> = (props) => {\n  const {\n    props: { srcSet: dark },\n  } = getImageProps({ src: Accessibility, ...props });\n  const {\n    // capture rest on one to spread to img as default; it doesn't matter which barring art direction\n    props: { srcSet: light, ...rest },\n  } = getImageProps({ src: Testing, ...props });\n\n  return (\n    <picture>\n      <source media=\"(prefers-color-scheme: dark)\" srcSet={dark} />\n      <source media=\"(prefers-color-scheme: light)\" srcSet={light} />\n      <img {...rest} />\n    </picture>\n  );\n};\n\nexport default {\n  component: Component,\n  args: {\n    alt: 'getImageProps Example',\n  },\n};\n\nexport const Default = {};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/stories/Head.stories.tsx",
    "content": "import Head from 'next/head';\nimport React from 'react';\nimport { expect, waitFor } from 'storybook/test';\nimport { StoryObj } from '@storybook/react';\n\nfunction Component() {\n  return (\n    <div>\n      <Head>\n        <title>Next.js Head Title</title>\n        <meta property=\"og:title\" content=\"My page title\" key=\"title\" />\n      </Head>\n      <Head>\n        <meta property=\"og:title\" content=\"My new title\" key=\"title\" />\n      </Head>\n      <p>Hello world!</p>\n    </div>\n  );\n}\n\nexport default {\n  component: Component,\n} as Meta<typeof Component>;\n\nexport const Default: StoryObj = {\n  play: async () => {\n    await waitFor(() => expect(document.title).toEqual('Next.js Head Title'));\n    await expect(document.querySelectorAll('meta[property=\"og:title\"]')).toHaveLength(1);\n    await expect(document.querySelector('meta[property=\"og:title\"]').content).toEqual(\n      'My new title'\n    );\n  },\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/stories/Image.stories.tsx",
    "content": "import React, { useState } from 'react';\nimport Image from 'next/image';\n\nimport Accessibility from './assets/accessibility.svg';\nimport AvifImage from './assets/avif-test-image.avif';\nimport { StoryObj } from '@storybook/react';\n\nexport default {\n  component: Image,\n  args: {\n    src: Accessibility,\n    alt: 'Accessibility',\n  },\n};\n\ntype Story = StoryObj<typeof Image>\n\nexport const Default: Story = {};\n\nexport const Avif: Story = {\n  args: {\n    src: AvifImage,\n    alt: 'Avif Test Image',\n  },\n};\n\nexport const BlurredPlaceholder: Story = {\n  args: {\n    placeholder: 'blur',\n  },\n};\n\nexport const BlurredAbsolutePlaceholder: Story = {\n  args: {\n    src: 'https://storybook.js.org/images/placeholders/50x50.png',\n    width: 50,\n    height: 50,\n    blurDataURL:\n      'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAABP5JREFUWEeNlwtz2zgMhEGKsv/k9XFp82xe11763yOJVGcXC4m2czM3GYa0E2s/LACSTi+vv1czM/7CvPpqxY/ejPeS3khmFiPHOiVLHKaZi4ux4j18GpMlS6cALupEQBCKQM4BdnGzjIcJgs//QBxAPQAem55f3yL4PWJIdyCyhlMfPdYZot0cwj3Ayg/5JwHA13paen7pADphxr/n5VI8JQsHCCGQ3gVGLLsxQ3h/LYSn5383B05rwNOws3Z576LOTOduvwfrOd5FtVat4akx0uPTrw8BNuUz23vLsY7hmg7i4ipqM2saiAdruNuirh4ff0bNdb3Qy3vkvfAQwrkHoDxTTZtDCOKrC1bMEkdnsQh/PLyetOGHkXeRAgQAQ84efQcBdUhvFofoulpdm9WGGTA+AJEe7l+i37a2c371tCFKs5zzJjxQNBMi1im7OCudP2aNghJuzZaGdSMEZjpwf/t0UgNdg9DOyLGLnY0BUHlzwVtNDkgEQhBeKkb1tUDgQrq7frwAiIJi5BKAeIFgHk5mOpPzvgltOfcoK0Rrs7lWHwsgqtXarK3N0u23h5Ne8+3Cqxn5RYSMfHCAMgDAx4CBWlA9RAGw0GA/ol0gvFB4WjAvBAFUa83SzdUdAbYMqp28uHpxCRefxwAYhksAFBlthxCiXig+zT4TYqkC+Hq7OdAfJv8lPpZiZShWBBIuRP+jspDb2lwcDkzz7OLzbO/zvAHAoXTz5eYMQL0t2yHAiCFcfPY1QDwNFylA5bPoFpsV9fsEiMl8dhcc4PP1CYD3drYcBYdIKQrx0cbRxd2JHSDcQ297/vvoZ5smRC+AyV2AQ+nm03evge08Tyy4jGqXzWWEoIvTgXHU38pWiNgH4ixB/ukAcy/xycXfp4kwdAAAt399W+OCgMjxILQacxvRQ3gEwHgKUIr/rz53CuDFNyP/Eob4+/vEWkBq6AAA/HIi62n/Lk67Q7wDYQ0UpQB7hc54T4E6gACLTYxeAwB0YKZL6U4ATEGIBwCs7qPfQJCCHkCnoK50noJKcXcAojsEAJZZKXhgCoziGKxqWV8IMNp4kP2aC+oB0TMFvhGxDQHQfIPhDrilwKOm/YCZASAHfgBABQjr3f7CyAkA0cPB03AQULRhKd4xAIjzHymo2Gp7gN0FAMAVOoA2fPz03a9ssh/RM7Iz8QKIzYF9HyB0XEZ1xJ4DzNoDOAfAslhDDTyjDfv8A2AcBeCiu/jBHQEgxnYW6Kp6BlCVAkQM8VnieF2Xyr0ivXy+XvsCzKOihwNHCCryw8HrQXVB8dgFeRfAVQiXjMbIIgXINQYB2H7Kf5wF/2Ar7h0AgKKGuAP4zOjhzlkLbpcRXKRZhNUjxG6HIQDOjN47gCn4+fWW3xVS9urPESEEwwHMo9IhAGxS2ISiA1iEnQOoA4hXRAwItp7WzL9Ow18ESJaw/ar4NgeOR49cAHCAnaH8swBhv+6CBGjeBSxEOUAI7HyKHkD4O9xKb3/feQouAI4uLBciHRRHmgbfA7h/xFc9AngNBADthvii1sMOiPwDAFeyt6s7FSFS4PmnA1v0vQvqDqQKAAPE/weAUuEgsj8c+H11Twdw/AKANXA82EDr5cJBEEzB3oI4Mb0AdR3nNw8vQnegWuvqAABwJFJEBwDgNdA7IOs3gL0LhuJdwBY8c4BfNnDdVgooHiOqn/b7JoSW/QODjTHXhU7hMQAAAABJRU5ErkJggg==',\n    placeholder: 'blur',\n  },\n  parameters: {\n    // ignoring in Chromatic to avoid inconsistent snapshots\n    // given that the switch from blur to image is quite fast\n    chromatic: { disableSnapshot: true },\n  },\n};\n\nexport const FilledParent: Story = {\n  args: {\n    fill: true,\n  },\n  decorators: [\n    (Story) => (\n      <div style={{ width: 500, height: 500, position: 'relative' }}>\n        <Story />\n      </div>\n    ),\n  ],\n};\n\nexport const Sized: Story = {\n  args: {\n    fill: true,\n    sizes: '(max-width: 600px) 100vw, 600px',\n  },\n  decorators: [\n    (Story) => (\n      <div style={{ width: 800, height: 800, position: 'relative' }}>\n        <Story />\n      </div>\n    ),\n  ],\n};\n\nexport const Lazy: Story = {\n  args: {\n    src: 'https://storybook.js.org/images/placeholders/50x50.png',\n    width: 50,\n    height: 50,\n  },\n  decorators: [\n    (Story) => (\n      <>\n        <div style={{ height: '200vh' }} />\n        <Story />\n      </>\n    ),\n  ],\n};\n\nexport const Eager: Story = {\n  ...Lazy,\n  parameters: {\n    nextjs: {\n      image: {\n        loading: 'eager',\n      },\n    },\n  },\n};\n\nexport const WithRef: Story = {\n  render() {\n    const [ref, setRef] = useState(null);\n\n    return (\n      <div>\n        <Image src={Accessibility} alt=\"Accessibility\" ref={setRef} />\n        <p>Alt attribute of image: {ref?.alt}</p>\n      </div>\n    );\n  },\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/stories/ImageLegacy.stories.tsx",
    "content": "import Image from 'next/legacy/image';\n\nimport Accessibility from './assets/accessibility.svg';\n\nexport default {\n  component: Image,\n  args: {\n    src: Accessibility,\n    alt: 'Accessibility',\n  },\n};\n\nexport const Default = {};\n\nexport const BlurredPlaceholder = {\n  args: {\n    placeholder: 'blur',\n  },\n};\n\nexport const BlurredAbsolutePlaceholder = {\n  args: {\n    src: 'https://storybook.js.org/images/placeholders/50x50.png',\n    width: 50,\n    height: 50,\n    blurDataURL:\n      'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAABP5JREFUWEeNlwtz2zgMhEGKsv/k9XFp82xe11763yOJVGcXC4m2czM3GYa0E2s/LACSTi+vv1czM/7CvPpqxY/ejPeS3khmFiPHOiVLHKaZi4ux4j18GpMlS6cALupEQBCKQM4BdnGzjIcJgs//QBxAPQAem55f3yL4PWJIdyCyhlMfPdYZot0cwj3Ayg/5JwHA13paen7pADphxr/n5VI8JQsHCCGQ3gVGLLsxQ3h/LYSn5383B05rwNOws3Z576LOTOduvwfrOd5FtVat4akx0uPTrw8BNuUz23vLsY7hmg7i4ipqM2saiAdruNuirh4ff0bNdb3Qy3vkvfAQwrkHoDxTTZtDCOKrC1bMEkdnsQh/PLyetOGHkXeRAgQAQ84efQcBdUhvFofoulpdm9WGGTA+AJEe7l+i37a2c371tCFKs5zzJjxQNBMi1im7OCudP2aNghJuzZaGdSMEZjpwf/t0UgNdg9DOyLGLnY0BUHlzwVtNDkgEQhBeKkb1tUDgQrq7frwAiIJi5BKAeIFgHk5mOpPzvgltOfcoK0Rrs7lWHwsgqtXarK3N0u23h5Ne8+3Cqxn5RYSMfHCAMgDAx4CBWlA9RAGw0GA/ol0gvFB4WjAvBAFUa83SzdUdAbYMqp28uHpxCRefxwAYhksAFBlthxCiXig+zT4TYqkC+Hq7OdAfJv8lPpZiZShWBBIuRP+jspDb2lwcDkzz7OLzbO/zvAHAoXTz5eYMQL0t2yHAiCFcfPY1QDwNFylA5bPoFpsV9fsEiMl8dhcc4PP1CYD3drYcBYdIKQrx0cbRxd2JHSDcQ297/vvoZ5smRC+AyV2AQ+nm03evge08Tyy4jGqXzWWEoIvTgXHU38pWiNgH4ixB/ukAcy/xycXfp4kwdAAAt399W+OCgMjxILQacxvRQ3gEwHgKUIr/rz53CuDFNyP/Eob4+/vEWkBq6AAA/HIi62n/Lk67Q7wDYQ0UpQB7hc54T4E6gACLTYxeAwB0YKZL6U4ATEGIBwCs7qPfQJCCHkCnoK50noJKcXcAojsEAJZZKXhgCoziGKxqWV8IMNp4kP2aC+oB0TMFvhGxDQHQfIPhDrilwKOm/YCZASAHfgBABQjr3f7CyAkA0cPB03AQULRhKd4xAIjzHymo2Gp7gN0FAMAVOoA2fPz03a9ssh/RM7Iz8QKIzYF9HyB0XEZ1xJ4DzNoDOAfAslhDDTyjDfv8A2AcBeCiu/jBHQEgxnYW6Kp6BlCVAkQM8VnieF2Xyr0ivXy+XvsCzKOihwNHCCryw8HrQXVB8dgFeRfAVQiXjMbIIgXINQYB2H7Kf5wF/2Ar7h0AgKKGuAP4zOjhzlkLbpcRXKRZhNUjxG6HIQDOjN47gCn4+fWW3xVS9urPESEEwwHMo9IhAGxS2ISiA1iEnQOoA4hXRAwItp7WzL9Ow18ESJaw/ar4NgeOR49cAHCAnaH8swBhv+6CBGjeBSxEOUAI7HyKHkD4O9xKb3/feQouAI4uLBciHRRHmgbfA7h/xFc9AngNBADthvii1sMOiPwDAFeyt6s7FSFS4PmnA1v0vQvqDqQKAAPE/weAUuEgsj8c+H11Twdw/AKANXA82EDr5cJBEEzB3oI4Mb0AdR3nNw8vQnegWuvqAABwJFJEBwDgNdA7IOs3gL0LhuJdwBY8c4BfNnDdVgooHiOqn/b7JoSW/QODjTHXhU7hMQAAAABJRU5ErkJggg==',\n    placeholder: 'blur',\n  },\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/stories/Link.stories.module.css",
    "content": ".link {\n  color: green;\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/stories/Link.stories.tsx",
    "content": "import React from 'react';\nimport Link from 'next/link';\nimport type { Meta, StoryObj } from '@storybook/react';\n\nimport style from './Link.stories.module.css';\n\n// `onClick`, `href`, and `ref` need to be passed to the DOM element\n// for proper handling\nconst MyButton = React.forwardRef<\n  HTMLAnchorElement,\n  React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>\n>(function Button({ onClick, href, children }, ref) {\n  return (\n    <a href={href} onClick={onClick} ref={ref}>\n      {children}\n    </a>\n  );\n});\n\nconst Component = () => (\n  <ul>\n    <li>\n      <Link href=\"/\">Normal Link</Link>\n    </li>\n    <li>\n      <Link\n        href={{\n          pathname: '/with-url-object',\n          query: { name: 'test' },\n        }}\n      >\n        With URL Object\n      </Link>\n    </li>\n    <li>\n      <Link href=\"/replace-url\" replace>\n        Replace the URL instead of push\n      </Link>\n    </li>\n    <li>\n      <Link href=\"/#hashid\" scroll={false}>\n        Disables scrolling to the top\n      </Link>\n    </li>\n    <li>\n      <Link href=\"/no-prefetch\" prefetch={false}>\n        No Prefetching\n      </Link>\n    </li>\n    <li>\n      <Link style={{ color: 'red' }} href=\"/with-style\">\n        With style\n      </Link>\n    </li>\n    <li>\n      <Link className={style.link} href=\"/with-classname\">\n        With className\n      </Link>\n    </li>\n  </ul>\n);\n\nexport default {\n  component: Component,\n} as Meta<typeof Component>;\n\nexport const Default: StoryObj<typeof Component> = {};\n\nexport const InAppDir: StoryObj<typeof Component> = {\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n    },\n  },\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/stories/Navigation.stories.tsx",
    "content": "import {\n  useRouter,\n  usePathname,\n  useSearchParams,\n  useParams,\n  useSelectedLayoutSegment,\n  useSelectedLayoutSegments,\n} from 'next/navigation';\nimport React from 'react';\nimport type { Meta, StoryObj } from '@storybook/react';\nimport { expect, userEvent, within } from 'storybook/test';\nimport { getRouter } from '@storybook/nextjs/navigation.mock';\n\nfunction Component() {\n  const router = useRouter();\n  const pathname = usePathname();\n  const searchParams = useSearchParams();\n  const params = useParams();\n  const segment = useSelectedLayoutSegment();\n  const segments = useSelectedLayoutSegments();\n\n  const searchParamsList = searchParams ? Array.from(searchParams.entries()) : [];\n\n  const routerActions = [\n    {\n      cb: () => router.back(),\n      name: 'Go back',\n    },\n    {\n      cb: () => router.forward(),\n      name: 'Go forward',\n    },\n    {\n      cb: () => router.prefetch('/prefetched-html'),\n      name: 'Prefetch',\n    },\n    {\n      // @ts-expect-error (old API)\n      cb: () => router.push('/push-html', { forceOptimisticNavigation: true }),\n      name: 'Push HTML',\n    },\n    {\n      cb: () => router.refresh(),\n      name: 'Refresh',\n    },\n    {\n      // @ts-expect-error (old API)\n      cb: () => router.replace('/replaced-html', { forceOptimisticNavigation: true }),\n      name: 'Replace',\n    },\n  ];\n\n  return (\n    <div>\n      <div>pathname: {pathname}</div>\n      <div>segment: {segment}</div>\n      <div>segments: {segments.join(',')}</div>\n      <div>\n        searchparams:{' '}\n        <ul>\n          {searchParamsList.map(([key, value]) => (\n            <li key={key}>\n              {key}: {value}\n            </li>\n          ))}\n        </ul>\n      </div>\n      <div>\n        params:{' '}\n        <ul>\n          {Object.entries(params).map(([key, value]) => (\n            <li key={key}>\n              {key}: {value}\n            </li>\n          ))}\n        </ul>\n      </div>\n      {routerActions.map(({ cb, name }) => (\n        <div key={name} style={{ marginBottom: '1em' }}>\n          <button type=\"button\" onClick={cb}>\n            {name}\n          </button>\n        </div>\n      ))}\n    </div>\n  );\n}\n\ntype Story = StoryObj<typeof Component>;\n\nexport default {\n  component: Component,\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        pathname: '/hello',\n        query: {\n          foo: 'bar',\n        },\n        prefetch: () => {\n          console.log('custom prefetch');\n        },\n      },\n    },\n  },\n} as Meta<typeof Component>;\n\nexport const Default: StoryObj<typeof Component> = {\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const routerMock = getRouter();\n\n    await step('Asserts whether forward hook is called', async () => {\n      const forwardBtn = await canvas.findByText('Go forward');\n      await userEvent.click(forwardBtn);\n      await expect(routerMock.forward).toHaveBeenCalled();\n    });\n\n    await step('Asserts whether custom prefetch hook is called', async () => {\n      const prefetchBtn = await canvas.findByText('Prefetch');\n      await userEvent.click(prefetchBtn);\n      await expect(routerMock.prefetch).toHaveBeenCalledWith('/prefetched-html');\n    });\n  },\n};\n\nexport const WithSegmentDefined: Story = {\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        segments: ['dashboard', 'settings'],\n      },\n    },\n  },\n};\n\nexport const WithSegmentDefinedForParams: Story = {\n  parameters: {\n    nextjs: {\n      appDirectory: true,\n      navigation: {\n        segments: [\n          ['slug', 'hello'],\n          ['framework', 'nextjs'],\n        ],\n      },\n    },\n  },\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/stories/NextHeader.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react';\nimport { expect, userEvent, within } from 'storybook/test';\nimport { cookies, headers } from '@storybook/nextjs/headers.mock';\nimport NextHeader from './NextHeader';\n\nexport default {\n  component: NextHeader,\n} as Meta<typeof NextHeader>;\n\ntype Story = StoryObj<typeof NextHeader>;\n\nexport const Default: Story = {\n  loaders: async () => {\n    cookies().set('firstName', 'Jane');\n    cookies().set({\n      name: 'lastName',\n      value: 'Doe',\n    });\n    headers().set('timezone', 'Central European Summer Time');\n  },\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const headersMock = headers();\n    const cookiesMock = cookies();\n    await step('Cookie and header store apis are called upon rendering', async () => {\n      await expect(cookiesMock.getAll).toHaveBeenCalled();\n      await expect(headersMock.entries).toHaveBeenCalled();\n    });\n\n    await step('Upon clicking on submit, the user-id cookie is set', async () => {\n      const submitButton = await canvas.findByRole('button');\n      await userEvent.click(submitButton);\n\n      await expect(cookiesMock.set).toHaveBeenCalledWith('user-id', 'encrypted-id');\n    });\n\n    await step('The user-id cookie is available in cookie and header stores', async () => {\n      await expect(headersMock.get('cookie')).toContain('user-id=encrypted-id');\n      await expect(cookiesMock.get('user-id')).toEqual({\n        name: 'user-id',\n        value: 'encrypted-id',\n      });\n    });\n  },\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/stories/NextHeader.tsx",
    "content": "import React from 'react';\nimport { cookies, headers } from 'next/headers';\n\nexport default function Component() {\n  function handleClick() {\n    cookies().set('user-id', 'encrypted-id');\n  }\n\n  return (\n    <>\n      <h3>Cookies:</h3>\n      {cookies()\n        .getAll()\n        .map(({ name, value }) => {\n          return (\n            <p key={name} style={{ display: 'flex', flexDirection: 'row', gap: 8 }}>\n              <strong>Name:</strong> <span>{name}</span>\n              <strong>Value:</strong> <span>{value}</span>\n            </p>\n          );\n        })}\n\n      <h3>Headers:</h3>\n      {Array.from(headers()).map(([name, value]: [string, string]) => {\n        return (\n          <p key={name} style={{ display: 'flex', flexDirection: 'row', gap: 8 }}>\n            <strong>Name:</strong> <span>{name}</span>\n            <strong>Value:</strong> <span>{value}</span>\n          </p>\n        );\n      })}\n\n        <button onClick={handleClick}>add user-id cookie</button>\n    </>\n  );\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/stories/Router.stories.tsx",
    "content": "import React from 'react';\nimport type { Meta, StoryObj } from '@storybook/react';\nimport { expect, within, userEvent } from 'storybook/test';\nimport { getRouter } from '@storybook/nextjs/router.mock';\nimport Router, { useRouter } from 'next/router';\n\nfunction Component() {\n  const router = useRouter();\n  const searchParams = router.query;\n\n  const routerActions = [\n    {\n      cb: () => router.back(),\n      name: 'Go back',\n    },\n    {\n      cb: () => router.forward(),\n      name: 'Go forward',\n    },\n    {\n      cb: () => router.prefetch('/prefetched-html'),\n      name: 'Prefetch',\n    },\n    {\n      // @ts-expect-error (old API)\n      cb: () => router.push('/push-html', { forceOptimisticNavigation: true }),\n      name: 'Push HTML',\n    },\n    {\n      // @ts-expect-error (old API)\n      cb: () => router.replace('/replaced-html', { forceOptimisticNavigation: true }),\n      name: 'Replace',\n    },\n  ];\n\n  return (\n    <div>\n      <div>Router pathname: {Router.pathname}</div>\n      <div>pathname: {router.pathname}</div>\n      <div>\n        searchparams:{' '}\n        <ul>\n          {Object.entries(searchParams).map(([key, value]) => (\n            <li key={key}>\n              {key}: {value}\n            </li>\n          ))}\n        </ul>\n      </div>\n      {routerActions.map(({ cb, name }) => (\n        <div key={name} style={{ marginBottom: '1em' }}>\n          <button type=\"button\" onClick={cb}>\n            {name}\n          </button>\n        </div>\n      ))}\n    </div>\n  );\n}\n\nexport default {\n  component: Component,\n  parameters: {\n    nextjs: {\n      router: {\n        pathname: '/hello',\n        query: {\n          foo: 'bar',\n        },\n        prefetch: () => {\n          console.log('custom prefetch');\n        },\n      },\n    },\n  },\n} as Meta<typeof Component>;\n\nexport const Default: StoryObj<typeof Component> = {\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    const routerMock = getRouter();\n\n    await step('Router property overrides should be available in useRouter fn', async () => {\n      await expect(Router.pathname).toBe('/hello');\n      await expect(Router.query).toEqual({ foo: 'bar' });\n    });\n\n    await step(\n      'Router property overrides should be available in default export from next/router',\n      async () => {\n        await expect(Router.pathname).toBe('/hello');\n        await expect(Router.query).toEqual({ foo: 'bar' });\n      }\n    );\n\n    await step('Asserts whether forward hook is called', async () => {\n      const forwardBtn = await canvas.findByText('Go forward');\n      await userEvent.click(forwardBtn);\n      await expect(routerMock.forward).toHaveBeenCalled();\n    });\n\n    await step('Asserts whether custom prefetch hook is called', async () => {\n      const prefetchBtn = await canvas.findByText('Prefetch');\n      await userEvent.click(prefetchBtn);\n      await expect(routerMock.prefetch).toHaveBeenCalledWith('/prefetched-html');\n    });\n  },\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/stories/StyledJsx.stories.tsx",
    "content": "import React from 'react';\n\nconst Component = () => (\n  <div>\n    <style jsx>{`\n      .main p {\n        color: #ff4785;\n      }\n    `}</style>\n    <main className=\"main\">\n      <p>This is styled using Styled JSX</p>\n    </main>\n  </div>\n);\n\nexport default {\n  component: Component,\n} as Meta<typeof Component>;\n\nexport const Default = {};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/stories/__snapshots__/portable-stories.test.tsx.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`renders dynamicImportStories stories renders Default 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <div>\n        I am a dynamically loaded component\n      </div>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders fontStories stories renders WithClassName 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <div>\n        <h1\n          class=\"className\"\n        >\n          Google Rubik Puddles\n        </h1>\n        <h1\n          class=\"className\"\n        >\n          Google Local Rubik Storm\n        </h1>\n      </div>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders fontStories stories renders WithStyle 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <div>\n        <h1\n          style=\"font-family: fontFamily;\"\n        >\n          Google Rubik Puddles\n        </h1>\n        <h1\n          style=\"font-family: fontFamily;\"\n        >\n          Google Local Rubik Storm\n        </h1>\n      </div>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders fontStories stories renders WithVariable 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <div>\n        <div\n          class=\"variable\"\n        >\n          <h1\n            style=\"font-family: var(--font-latin-rubik);\"\n          >\n            Google Rubik Puddles\n          </h1>\n        </div>\n        <div\n          class=\"variable\"\n        >\n          <h1\n            style=\"font-family: var(--font-rubik-storm);\"\n          >\n            Google Local Rubik Storm\n          </h1>\n        </div>\n      </div>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders getImagePropsStories stories renders Default 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <picture>\n        <source\n          media=\"(prefers-color-scheme: dark)\"\n          srcset=\"/_next/image?url=%2Fimg.jpg&w=48&q=75 1x, /_next/image?url=%2Fimg.jpg&w=96&q=75 2x\"\n        />\n        <source\n          media=\"(prefers-color-scheme: light)\"\n          srcset=\"/_next/image?url=%2Fimg.jpg&w=48&q=75 1x, /_next/image?url=%2Fimg.jpg&w=96&q=75 2x\"\n        />\n        <img\n          alt=\"getImageProps Example\"\n          decoding=\"async\"\n          height=\"40\"\n          loading=\"lazy\"\n          src=\"/_next/image?url=%2Fimg.jpg&w=96&q=75\"\n          style=\"color: transparent;\"\n          width=\"40\"\n        />\n      </picture>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders headStories stories renders Default 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <div>\n        <p>\n          Hello world!\n        </p>\n      </div>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders imageLegacyStories stories renders BlurredAbsolutePlaceholder 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <span\n        style=\"box-sizing: border-box; display: inline-block; overflow: hidden; width: initial; height: initial; background: none none; opacity: 1; border: 0px; margin: 0px; padding: 0px; position: relative; max-width: 100%;\"\n      >\n        <span\n          style=\"box-sizing: border-box; display: block; width: initial; height: initial; background: none none; opacity: 1; border: 0px; margin: 0px; padding: 0px; max-width: 100%;\"\n        >\n          <img\n            alt=\"\"\n            aria-hidden=\"true\"\n            src=\"data:image/svg+xml,%3csvg%20xmlns=%27http://www.w3.org/2000/svg%27%20version=%271.1%27%20width=%2750%27%20height=%2750%27/%3e\"\n            style=\"display: block; max-width: 100%; width: initial; height: initial; background: none none; opacity: 1; border: 0px; margin: 0px; padding: 0px;\"\n          />\n        </span>\n        <img\n          alt=\"Accessibility\"\n          data-nimg=\"intrinsic\"\n          decoding=\"async\"\n          src=\"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\"\n          style=\"position: absolute; top: 0px; left: 0px; bottom: 0px; right: 0px; box-sizing: border-box; padding: 0px; border: none none; margin: auto; display: block; width: 0px; height: 0px; min-width: 100%; max-width: 100%; min-height: 100%; max-height: 100%; background-size: cover; background-position: 0% 0%; filter: blur(20px); background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAABP5JREFUWEeNlwtz2zgMhEGKsv/k9XFp82xe11763yOJVGcXC4m2czM3GYa0E2s/LACSTi+vv1czM/7CvPpqxY/ejPeS3khmFiPHOiVLHKaZi4ux4j18GpMlS6cALupEQBCKQM4BdnGzjIcJgs//QBxAPQAem55f3yL4PWJIdyCyhlMfPdYZot0cwj3Ayg/5JwHA13paen7pADphxr/n5VI8JQsHCCGQ3gVGLLsxQ3h/LYSn5383B05rwNOws3Z576LOTOduvwfrOd5FtVat4akx0uPTrw8BNuUz23vLsY7hmg7i4ipqM2saiAdruNuirh4ff0bNdb3Qy3vkvfAQwrkHoDxTTZtDCOKrC1bMEkdnsQh/PLyetOGHkXeRAgQAQ84efQcBdUhvFofoulpdm9WGGTA+AJEe7l+i37a2c371tCFKs5zzJjxQNBMi1im7OCudP2aNghJuzZaGdSMEZjpwf/t0UgNdg9DOyLGLnY0BUHlzwVtNDkgEQhBeKkb1tUDgQrq7frwAiIJi5BKAeIFgHk5mOpPzvgltOfcoK0Rrs7lWHwsgqtXarK3N0u23h5Ne8+3Cqxn5RYSMfHCAMgDAx4CBWlA9RAGw0GA/ol0gvFB4WjAvBAFUa83SzdUdAbYMqp28uHpxCRefxwAYhksAFBlthxCiXig+zT4TYqkC+Hq7OdAfJv8lPpZiZShWBBIuRP+jspDb2lwcDkzz7OLzbO/zvAHAoXTz5eYMQL0t2yHAiCFcfPY1QDwNFylA5bPoFpsV9fsEiMl8dhcc4PP1CYD3drYcBYdIKQrx0cbRxd2JHSDcQ297/vvoZ5smRC+AyV2AQ+nm03evge08Tyy4jGqXzWWEoIvTgXHU38pWiNgH4ixB/ukAcy/xycXfp4kwdAAAt399W+OCgMjxILQacxvRQ3gEwHgKUIr/rz53CuDFNyP/Eob4+/vEWkBq6AAA/HIi62n/Lk67Q7wDYQ0UpQB7hc54T4E6gACLTYxeAwB0YKZL6U4ATEGIBwCs7qPfQJCCHkCnoK50noJKcXcAojsEAJZZKXhgCoziGKxqWV8IMNp4kP2aC+oB0TMFvhGxDQHQfIPhDrilwKOm/YCZASAHfgBABQjr3f7CyAkA0cPB03AQULRhKd4xAIjzHymo2Gp7gN0FAMAVOoA2fPz03a9ssh/RM7Iz8QKIzYF9HyB0XEZ1xJ4DzNoDOAfAslhDDTyjDfv8A2AcBeCiu/jBHQEgxnYW6Kp6BlCVAkQM8VnieF2Xyr0ivXy+XvsCzKOihwNHCCryw8HrQXVB8dgFeRfAVQiXjMbIIgXINQYB2H7Kf5wF/2Ar7h0AgKKGuAP4zOjhzlkLbpcRXKRZhNUjxG6HIQDOjN47gCn4+fWW3xVS9urPESEEwwHMo9IhAGxS2ISiA1iEnQOoA4hXRAwItp7WzL9Ow18ESJaw/ar4NgeOR49cAHCAnaH8swBhv+6CBGjeBSxEOUAI7HyKHkD4O9xKb3/feQouAI4uLBciHRRHmgbfA7h/xFc9AngNBADthvii1sMOiPwDAFeyt6s7FSFS4PmnA1v0vQvqDqQKAAPE/weAUuEgsj8c+H11Twdw/AKANXA82EDr5cJBEEzB3oI4Mb0AdR3nNw8vQnegWuvqAABwJFJEBwDgNdA7IOs3gL0LhuJdwBY8c4BfNnDdVgooHiOqn/b7JoSW/QODjTHXhU7hMQAAAABJRU5ErkJggg==\");\"\n        />\n        <noscript />\n      </span>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders imageLegacyStories stories renders BlurredPlaceholder 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <span\n        style=\"box-sizing: border-box; display: inline-block; overflow: hidden; width: initial; height: initial; background: none none; opacity: 1; border: 0px; margin: 0px; padding: 0px; position: relative; max-width: 100%;\"\n      >\n        <span\n          style=\"box-sizing: border-box; display: block; width: initial; height: initial; background: none none; opacity: 1; border: 0px; margin: 0px; padding: 0px; max-width: 100%;\"\n        >\n          <img\n            alt=\"\"\n            aria-hidden=\"true\"\n            src=\"data:image/svg+xml,%3csvg%20xmlns=%27http://www.w3.org/2000/svg%27%20version=%271.1%27%20width=%2740%27%20height=%2740%27/%3e\"\n            style=\"display: block; max-width: 100%; width: initial; height: initial; background: none none; opacity: 1; border: 0px; margin: 0px; padding: 0px;\"\n          />\n        </span>\n        <img\n          alt=\"Accessibility\"\n          data-nimg=\"intrinsic\"\n          decoding=\"async\"\n          src=\"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\"\n          style=\"position: absolute; top: 0px; left: 0px; bottom: 0px; right: 0px; box-sizing: border-box; padding: 0px; border: none none; margin: auto; display: block; width: 0px; height: 0px; min-width: 100%; max-width: 100%; min-height: 100%; max-height: 100%; background-size: cover; background-position: 0% 0%; filter: blur(20px); background-image: url(\"data:image/png;base64,imagedata\");\"\n        />\n        <noscript />\n      </span>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders imageLegacyStories stories renders Default 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <span\n        style=\"box-sizing: border-box; display: inline-block; overflow: hidden; width: initial; height: initial; background: none none; opacity: 1; border: 0px; margin: 0px; padding: 0px; position: relative; max-width: 100%;\"\n      >\n        <span\n          style=\"box-sizing: border-box; display: block; width: initial; height: initial; background: none none; opacity: 1; border: 0px; margin: 0px; padding: 0px; max-width: 100%;\"\n        >\n          <img\n            alt=\"\"\n            aria-hidden=\"true\"\n            src=\"data:image/svg+xml,%3csvg%20xmlns=%27http://www.w3.org/2000/svg%27%20version=%271.1%27%20width=%2740%27%20height=%2740%27/%3e\"\n            style=\"display: block; max-width: 100%; width: initial; height: initial; background: none none; opacity: 1; border: 0px; margin: 0px; padding: 0px;\"\n          />\n        </span>\n        <img\n          alt=\"Accessibility\"\n          data-nimg=\"intrinsic\"\n          decoding=\"async\"\n          src=\"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\"\n          style=\"position: absolute; top: 0px; left: 0px; bottom: 0px; right: 0px; box-sizing: border-box; padding: 0px; border: none none; margin: auto; display: block; width: 0px; height: 0px; min-width: 100%; max-width: 100%; min-height: 100%; max-height: 100%;\"\n        />\n        <noscript />\n      </span>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders imageStories stories renders Avif 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <img\n        alt=\"Avif Test Image\"\n        data-nimg=\"1\"\n        decoding=\"async\"\n        height=\"40\"\n        loading=\"lazy\"\n        src=\"/_next/image?url=%2Fimg.jpg&w=96&q=75\"\n        srcset=\"/_next/image?url=%2Fimg.jpg&w=48&q=75 1x, /_next/image?url=%2Fimg.jpg&w=96&q=75 2x\"\n        style=\"color: transparent;\"\n        width=\"40\"\n      />\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders imageStories stories renders BlurredAbsolutePlaceholder 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <img\n        alt=\"Accessibility\"\n        data-nimg=\"1\"\n        decoding=\"async\"\n        height=\"50\"\n        loading=\"lazy\"\n        src=\"/_next/image?url=https%3A%2F%2Fstorybook.js.org%2Fimages%2Fplaceholders%2F50x50.png&w=128&q=75\"\n        srcset=\"/_next/image?url=https%3A%2F%2Fstorybook.js.org%2Fimages%2Fplaceholders%2F50x50.png&w=64&q=75 1x, /_next/image?url=https%3A%2F%2Fstorybook.js.org%2Fimages%2Fplaceholders%2F50x50.png&w=128&q=75 2x\"\n        style=\"color: transparent; background-size: cover; background-position: 50% 50%; background-repeat: no-repeat;\"\n        width=\"50\"\n      />\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders imageStories stories renders BlurredPlaceholder 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <img\n        alt=\"Accessibility\"\n        data-nimg=\"1\"\n        decoding=\"async\"\n        height=\"40\"\n        loading=\"lazy\"\n        src=\"/_next/image?url=%2Fimg.jpg&w=96&q=75\"\n        srcset=\"/_next/image?url=%2Fimg.jpg&w=48&q=75 1x, /_next/image?url=%2Fimg.jpg&w=96&q=75 2x\"\n        style=\"color: transparent; background-size: cover; background-position: 50% 50%; background-repeat: no-repeat;\"\n        width=\"40\"\n      />\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders imageStories stories renders Default 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <img\n        alt=\"Accessibility\"\n        data-nimg=\"1\"\n        decoding=\"async\"\n        height=\"40\"\n        loading=\"lazy\"\n        src=\"/_next/image?url=%2Fimg.jpg&w=96&q=75\"\n        srcset=\"/_next/image?url=%2Fimg.jpg&w=48&q=75 1x, /_next/image?url=%2Fimg.jpg&w=96&q=75 2x\"\n        style=\"color: transparent;\"\n        width=\"40\"\n      />\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders imageStories stories renders Eager 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <div\n        style=\"height: 200vh;\"\n      />\n      <img\n        alt=\"Accessibility\"\n        data-nimg=\"1\"\n        decoding=\"async\"\n        height=\"50\"\n        loading=\"lazy\"\n        src=\"/_next/image?url=https%3A%2F%2Fstorybook.js.org%2Fimages%2Fplaceholders%2F50x50.png&w=128&q=75\"\n        srcset=\"/_next/image?url=https%3A%2F%2Fstorybook.js.org%2Fimages%2Fplaceholders%2F50x50.png&w=64&q=75 1x, /_next/image?url=https%3A%2F%2Fstorybook.js.org%2Fimages%2Fplaceholders%2F50x50.png&w=128&q=75 2x\"\n        style=\"color: transparent;\"\n        width=\"50\"\n      />\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders imageStories stories renders FilledParent 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <div\n        style=\"width: 500px; height: 500px; position: relative;\"\n      >\n        <img\n          alt=\"Accessibility\"\n          data-nimg=\"fill\"\n          decoding=\"async\"\n          loading=\"lazy\"\n          sizes=\"100vw\"\n          src=\"/_next/image?url=%2Fimg.jpg&w=3840&q=75\"\n          srcset=\"/_next/image?url=%2Fimg.jpg&w=640&q=75 640w, /_next/image?url=%2Fimg.jpg&w=750&q=75 750w, /_next/image?url=%2Fimg.jpg&w=828&q=75 828w, /_next/image?url=%2Fimg.jpg&w=1080&q=75 1080w, /_next/image?url=%2Fimg.jpg&w=1200&q=75 1200w, /_next/image?url=%2Fimg.jpg&w=1920&q=75 1920w, /_next/image?url=%2Fimg.jpg&w=2048&q=75 2048w, /_next/image?url=%2Fimg.jpg&w=3840&q=75 3840w\"\n          style=\"position: absolute; height: 100%; width: 100%; left: 0px; top: 0px; right: 0px; bottom: 0px; color: transparent;\"\n        />\n      </div>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders imageStories stories renders Lazy 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <div\n        style=\"height: 200vh;\"\n      />\n      <img\n        alt=\"Accessibility\"\n        data-nimg=\"1\"\n        decoding=\"async\"\n        height=\"50\"\n        loading=\"lazy\"\n        src=\"/_next/image?url=https%3A%2F%2Fstorybook.js.org%2Fimages%2Fplaceholders%2F50x50.png&w=128&q=75\"\n        srcset=\"/_next/image?url=https%3A%2F%2Fstorybook.js.org%2Fimages%2Fplaceholders%2F50x50.png&w=64&q=75 1x, /_next/image?url=https%3A%2F%2Fstorybook.js.org%2Fimages%2Fplaceholders%2F50x50.png&w=128&q=75 2x\"\n        style=\"color: transparent;\"\n        width=\"50\"\n      />\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders imageStories stories renders Sized 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <div\n        style=\"width: 800px; height: 800px; position: relative;\"\n      >\n        <img\n          alt=\"Accessibility\"\n          data-nimg=\"fill\"\n          decoding=\"async\"\n          loading=\"lazy\"\n          sizes=\"(max-width: 600px) 100vw, 600px\"\n          src=\"/_next/image?url=%2Fimg.jpg&w=3840&q=75\"\n          srcset=\"/_next/image?url=%2Fimg.jpg&w=640&q=75 640w, /_next/image?url=%2Fimg.jpg&w=750&q=75 750w, /_next/image?url=%2Fimg.jpg&w=828&q=75 828w, /_next/image?url=%2Fimg.jpg&w=1080&q=75 1080w, /_next/image?url=%2Fimg.jpg&w=1200&q=75 1200w, /_next/image?url=%2Fimg.jpg&w=1920&q=75 1920w, /_next/image?url=%2Fimg.jpg&w=2048&q=75 2048w, /_next/image?url=%2Fimg.jpg&w=3840&q=75 3840w\"\n          style=\"position: absolute; height: 100%; width: 100%; left: 0px; top: 0px; right: 0px; bottom: 0px; color: transparent;\"\n        />\n      </div>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders imageStories stories renders WithRef 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <div>\n        <img\n          alt=\"Accessibility\"\n          data-nimg=\"1\"\n          decoding=\"async\"\n          height=\"40\"\n          loading=\"lazy\"\n          src=\"/_next/image?url=%2Fimg.jpg&w=96&q=75\"\n          srcset=\"/_next/image?url=%2Fimg.jpg&w=48&q=75 1x, /_next/image?url=%2Fimg.jpg&w=96&q=75 2x\"\n          style=\"color: transparent;\"\n          width=\"40\"\n        />\n        <p>\n          Alt attribute of image: \n          Accessibility\n        </p>\n      </div>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders linkStories stories renders Default 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <ul>\n        <li>\n          <a\n            href=\"/\"\n          >\n            Normal Link\n          </a>\n        </li>\n        <li>\n          <a\n            href=\"/with-url-object?name=test\"\n          >\n            With URL Object\n          </a>\n        </li>\n        <li>\n          <a\n            href=\"/replace-url\"\n          >\n            Replace the URL instead of push\n          </a>\n        </li>\n        <li>\n          <a\n            href=\"/#hashid\"\n          >\n            Disables scrolling to the top\n          </a>\n        </li>\n        <li>\n          <a\n            href=\"/no-prefetch\"\n          >\n            No Prefetching\n          </a>\n        </li>\n        <li>\n          <a\n            href=\"/with-style\"\n            style=\"color: red;\"\n          >\n            With style\n          </a>\n        </li>\n        <li>\n          <a\n            class=\"link\"\n            href=\"/with-classname\"\n          >\n            With className\n          </a>\n        </li>\n      </ul>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders linkStories stories renders InAppDir 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <ul>\n        <li>\n          <a\n            href=\"/\"\n          >\n            Normal Link\n          </a>\n        </li>\n        <li>\n          <a\n            href=\"/with-url-object?name=test\"\n          >\n            With URL Object\n          </a>\n        </li>\n        <li>\n          <a\n            href=\"/replace-url\"\n          >\n            Replace the URL instead of push\n          </a>\n        </li>\n        <li>\n          <a\n            href=\"/#hashid\"\n          >\n            Disables scrolling to the top\n          </a>\n        </li>\n        <li>\n          <a\n            href=\"/no-prefetch\"\n          >\n            No Prefetching\n          </a>\n        </li>\n        <li>\n          <a\n            href=\"/with-style\"\n            style=\"color: red;\"\n          >\n            With style\n          </a>\n        </li>\n        <li>\n          <a\n            class=\"link\"\n            href=\"/with-classname\"\n          >\n            With className\n          </a>\n        </li>\n      </ul>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders navigationStories stories renders Default 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <div>\n        <div>\n          pathname: \n          /hello\n        </div>\n        <div>\n          segment: \n        </div>\n        <div>\n          segments: \n        </div>\n        <div>\n          searchparams:\n           \n          <ul>\n            <li>\n              foo\n              : \n              bar\n            </li>\n          </ul>\n        </div>\n        <div>\n          params:\n           \n          <ul />\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Go back\n          </button>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Go forward\n          </button>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Prefetch\n          </button>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Push HTML\n          </button>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Refresh\n          </button>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Replace\n          </button>\n        </div>\n      </div>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders navigationStories stories renders WithSegmentDefined 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <div>\n        <div>\n          pathname: \n          /hello\n        </div>\n        <div>\n          segment: \n          dashboard\n        </div>\n        <div>\n          segments: \n          dashboard,settings\n        </div>\n        <div>\n          searchparams:\n           \n          <ul>\n            <li>\n              foo\n              : \n              bar\n            </li>\n          </ul>\n        </div>\n        <div>\n          params:\n           \n          <ul />\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Go back\n          </button>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Go forward\n          </button>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Prefetch\n          </button>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Push HTML\n          </button>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Refresh\n          </button>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Replace\n          </button>\n        </div>\n      </div>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders navigationStories stories renders WithSegmentDefinedForParams 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <div>\n        <div>\n          pathname: \n          /hello\n        </div>\n        <div>\n          segment: \n          hello\n        </div>\n        <div>\n          segments: \n          hello,nextjs\n        </div>\n        <div>\n          searchparams:\n           \n          <ul>\n            <li>\n              foo\n              : \n              bar\n            </li>\n          </ul>\n        </div>\n        <div>\n          params:\n           \n          <ul>\n            <li>\n              slug\n              : \n              hello\n            </li>\n            <li>\n              framework\n              : \n              nextjs\n            </li>\n          </ul>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Go back\n          </button>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Go forward\n          </button>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Prefetch\n          </button>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Push HTML\n          </button>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Refresh\n          </button>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Replace\n          </button>\n        </div>\n      </div>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders nextHeaderStories stories renders Default 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <h3>\n        Cookies:\n      </h3>\n      <p\n        style=\"display: flex; flex-direction: row; gap: 8px;\"\n      >\n        <strong>\n          Name:\n        </strong>\n         \n        <span>\n          firstName\n        </span>\n        <strong>\n          Value:\n        </strong>\n         \n        <span>\n          Jane\n        </span>\n      </p>\n      <p\n        style=\"display: flex; flex-direction: row; gap: 8px;\"\n      >\n        <strong>\n          Name:\n        </strong>\n         \n        <span>\n          lastName\n        </span>\n        <strong>\n          Value:\n        </strong>\n         \n        <span>\n          Doe\n        </span>\n      </p>\n      <h3>\n        Headers:\n      </h3>\n      <p\n        style=\"display: flex; flex-direction: row; gap: 8px;\"\n      >\n        <strong>\n          Name:\n        </strong>\n         \n        <span>\n          cookie\n        </span>\n        <strong>\n          Value:\n        </strong>\n         \n        <span>\n          firstName=Jane; lastName=Doe\n        </span>\n      </p>\n      <p\n        style=\"display: flex; flex-direction: row; gap: 8px;\"\n      >\n        <strong>\n          Name:\n        </strong>\n         \n        <span>\n          timezone\n        </span>\n        <strong>\n          Value:\n        </strong>\n         \n        <span>\n          Central European Summer Time\n        </span>\n      </p>\n      <button>\n        add user-id cookie\n      </button>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders routerStories stories renders Default 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <div>\n        <div>\n          Router pathname: \n          /hello\n        </div>\n        <div>\n          pathname: \n          /hello\n        </div>\n        <div>\n          searchparams:\n           \n          <ul>\n            <li>\n              foo\n              : \n              bar\n            </li>\n          </ul>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Go back\n          </button>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Go forward\n          </button>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Prefetch\n          </button>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Push HTML\n          </button>\n        </div>\n        <div\n          style=\"margin-bottom: 1em;\"\n        >\n          <button\n            type=\"button\"\n          >\n            Replace\n          </button>\n        </div>\n      </div>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`renders styledJsxStories stories renders Default 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      Global Decorator\n      <br />\n      <div\n        class=\"jsx-56e68ef07a3a21f4\"\n      >\n        <main\n          class=\"jsx-56e68ef07a3a21f4 main\"\n        >\n          <p\n            class=\"jsx-56e68ef07a3a21f4\"\n          >\n            This is styled using Styled JSX\n          </p>\n        </main>\n      </div>\n    </div>\n  </div>\n</body>\n`;\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/stories/dynamic-component.tsx",
    "content": "import React from 'react';\n\nexport default function DynamicComponent() {\n  return <div>I am a dynamically loaded component</div>;\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/stories/fonts/OFL.txt",
    "content": "Copyright 2020 The Rubik Filtered Project Authors (https://https://github.com/NaN-xyz/Rubik-Filtered)\r\n\r\nThis Font Software is licensed under the SIL Open Font License, Version 1.1.\r\nThis license is copied below, and is also available with a FAQ at:\r\nhttp://scripts.sil.org/OFL\r\n\r\n\r\n-----------------------------------------------------------\r\nSIL OPEN FONT LICENSE Version 1.1 - 26 February 2007\r\n-----------------------------------------------------------\r\n\r\nPREAMBLE\r\nThe goals of the Open Font License (OFL) are to stimulate worldwide\r\ndevelopment of collaborative font projects, to support the font creation\r\nefforts of academic and linguistic communities, and to provide a free and\r\nopen framework in which fonts may be shared and improved in partnership\r\nwith others.\r\n\r\nThe OFL allows the licensed fonts to be used, studied, modified and\r\nredistributed freely as long as they are not sold by themselves. The\r\nfonts, including any derivative works, can be bundled, embedded, \r\nredistributed and/or sold with any software provided that any reserved\r\nnames are not used by derivative works. The fonts and derivatives,\r\nhowever, cannot be released under any other type of license. The\r\nrequirement for fonts to remain under this license does not apply\r\nto any document created using the fonts or their derivatives.\r\n\r\nDEFINITIONS\r\n\"Font Software\" refers to the set of files released by the Copyright\r\nHolder(s) under this license and clearly marked as such. This may\r\ninclude source files, build scripts and documentation.\r\n\r\n\"Reserved Font Name\" refers to any names specified as such after the\r\ncopyright statement(s).\r\n\r\n\"Original Version\" refers to the collection of Font Software components as\r\ndistributed by the Copyright Holder(s).\r\n\r\n\"Modified Version\" refers to any derivative made by adding to, deleting,\r\nor substituting -- in part or in whole -- any of the components of the\r\nOriginal Version, by changing formats or by porting the Font Software to a\r\nnew environment.\r\n\r\n\"Author\" refers to any designer, engineer, programmer, technical\r\nwriter or other person who contributed to the Font Software.\r\n\r\nPERMISSION & CONDITIONS\r\nPermission is hereby granted, free of charge, to any person obtaining\r\na copy of the Font Software, to use, study, copy, merge, embed, modify,\r\nredistribute, and sell modified and unmodified copies of the Font\r\nSoftware, subject to the following conditions:\r\n\r\n1) Neither the Font Software nor any of its individual components,\r\nin Original or Modified Versions, may be sold by itself.\r\n\r\n2) Original or Modified Versions of the Font Software may be bundled,\r\nredistributed and/or sold with any software, provided that each copy\r\ncontains the above copyright notice and this license. These can be\r\nincluded either as stand-alone text files, human-readable headers or\r\nin the appropriate machine-readable metadata fields within text or\r\nbinary files as long as those fields can be easily viewed by the user.\r\n\r\n3) No Modified Version of the Font Software may use the Reserved Font\r\nName(s) unless explicit written permission is granted by the corresponding\r\nCopyright Holder. This restriction only applies to the primary font name as\r\npresented to the users.\r\n\r\n4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font\r\nSoftware shall not be used to promote, endorse or advertise any\r\nModified Version, except to acknowledge the contribution(s) of the\r\nCopyright Holder(s) and the Author(s) or with their explicit written\r\npermission.\r\n\r\n5) The Font Software, modified or unmodified, in part or in whole,\r\nmust be distributed entirely under this license, and must not be\r\ndistributed under any other license. The requirement for fonts to\r\nremain under this license does not apply to any document created\r\nusing the Font Software.\r\n\r\nTERMINATION\r\nThis license becomes null and void if any of the above conditions are\r\nnot met.\r\n\r\nDISCLAIMER\r\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\r\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\r\nOF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE\r\nCOPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\r\nINCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\r\nDAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r\nFROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM\r\nOTHER DEALINGS IN THE FONT SOFTWARE.\r\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/stories/portable-stories.test.tsx",
    "content": "import { describe, it, expect } from '@jest/globals';\nimport { jest } from '@jest/globals';\n\nimport { composeStories, setProjectAnnotations } from '@storybook/nextjs';\nimport * as imageStories from './Image.stories';\nimport * as navigationStories from './Navigation.stories';\nimport * as linkStories from './Link.stories';\nimport * as routerStories from './Router.stories';\nimport * as imageLegacyStories from './ImageLegacy.stories';\nimport * as styledJsxStories from './StyledJsx.stories';\nimport * as dynamicImportStories from './DynamicImport.stories';\nimport * as fontStories from './Font.stories';\nimport * as headStories from './Head.stories';\nimport * as nextHeaderStories from './NextHeader.stories';\nimport * as getImagePropsStories from './GetImageProps.stories';\n\n// the imageLegacyStories test is flaky\njest.retryTimes(3);\n\n// example with composeStories, returns an object with all stories composed with args/decorators\nconst runTests = (name: string, storiesModule: any) => {\n  describe(`${name} stories`, () => {\n    const composedStories = composeStories(storiesModule);\n    Object.entries(composedStories).forEach(([name, Story]: [any, any]) => {\n      it(`renders ${name}`, async () => {\n        await Story.run?.();\n        expect(document.body).toMatchSnapshot();\n      });\n    });\n  });\n};\n\n// example with composeStory, returns a single story composed with args/decorators\ndescribe('renders', () => {\n  runTests('nextHeaderStories', nextHeaderStories);\n  runTests('navigationStories', navigationStories);\n  runTests('linkStories', linkStories);\n  runTests('routerStories', routerStories);\n  runTests('imageStories', imageStories);\n  runTests('imageLegacyStories', imageLegacyStories);\n  runTests('styledJsxStories', styledJsxStories);\n  runTests('dynamicImportStories', dynamicImportStories);\n  runTests('fontStories', fontStories);\n  runTests('headStories', headStories);\n  runTests('getImagePropsStories', getImagePropsStories);\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/styles/Home.module.css",
    "content": ".main {\n  display: flex;\n  flex-direction: column;\n  justify-content: space-between;\n  align-items: center;\n  padding: 6rem;\n  min-height: 100vh;\n}\n\n.description {\n  display: inherit;\n  justify-content: inherit;\n  align-items: inherit;\n  font-size: 0.85rem;\n  max-width: var(--max-width);\n  width: 100%;\n  z-index: 2;\n  font-family: var(--font-mono);\n}\n\n.description a {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  gap: 0.5rem;\n}\n\n.description p {\n  position: relative;\n  margin: 0;\n  padding: 1rem;\n  background-color: rgba(var(--callout-rgb), 0.5);\n  border: 1px solid rgba(var(--callout-border-rgb), 0.3);\n  border-radius: var(--border-radius);\n}\n\n.code {\n  font-weight: 700;\n  font-family: var(--font-mono);\n}\n\n.grid {\n  display: grid;\n  grid-template-columns: repeat(4, minmax(25%, auto));\n  max-width: 100%;\n  width: var(--max-width);\n}\n\n.card {\n  padding: 1rem 1.2rem;\n  border-radius: var(--border-radius);\n  background: rgba(var(--card-rgb), 0);\n  border: 1px solid rgba(var(--card-border-rgb), 0);\n  transition: background 200ms, border 200ms;\n}\n\n.card span {\n  display: inline-block;\n  transition: transform 200ms;\n}\n\n.card h2 {\n  font-weight: 600;\n  margin-bottom: 0.7rem;\n}\n\n.card p {\n  margin: 0;\n  opacity: 0.6;\n  font-size: 0.9rem;\n  line-height: 1.5;\n  max-width: 30ch;\n}\n\n.center {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  position: relative;\n  padding: 4rem 0;\n}\n\n.center::before {\n  background: var(--secondary-glow);\n  border-radius: 50%;\n  width: 480px;\n  height: 360px;\n  margin-left: -400px;\n}\n\n.center::after {\n  background: var(--primary-glow);\n  width: 240px;\n  height: 180px;\n  z-index: -1;\n}\n\n.center::before,\n.center::after {\n  content: \"\";\n  left: 50%;\n  position: absolute;\n  filter: blur(45px);\n  transform: translateZ(0);\n}\n\n.logo {\n  position: relative;\n}\n/* Enable hover only on non-touch devices */\n@media (hover: hover) and (pointer: fine) {\n  .card:hover {\n    background: rgba(var(--card-rgb), 0.1);\n    border: 1px solid rgba(var(--card-border-rgb), 0.15);\n  }\n\n  .card:hover span {\n    transform: translateX(4px);\n  }\n}\n\n@media (prefers-reduced-motion) {\n  .card:hover span {\n    transform: none;\n  }\n}\n\n/* Mobile */\n@media (max-width: 700px) {\n  .content {\n    padding: 4rem;\n  }\n\n  .grid {\n    grid-template-columns: 1fr;\n    margin-bottom: 120px;\n    max-width: 320px;\n    text-align: center;\n  }\n\n  .card {\n    padding: 1rem 2.5rem;\n  }\n\n  .card h2 {\n    margin-bottom: 0.5rem;\n  }\n\n  .center {\n    padding: 8rem 0 6rem;\n  }\n\n  .center::before {\n    transform: none;\n    height: 300px;\n  }\n\n  .description {\n    font-size: 0.8rem;\n  }\n\n  .description a {\n    padding: 1rem;\n  }\n\n  .description p,\n  .description div {\n    display: flex;\n    justify-content: center;\n    position: fixed;\n    width: 100%;\n  }\n\n  .description p {\n    align-items: center;\n    inset: 0 0 auto;\n    padding: 2rem 1rem 1.4rem;\n    border-radius: 0;\n    border: none;\n    border-bottom: 1px solid rgba(var(--callout-border-rgb), 0.25);\n    background: linear-gradient(\n      to bottom,\n      rgba(var(--background-start-rgb), 1),\n      rgba(var(--callout-rgb), 0.5)\n    );\n    background-clip: padding-box;\n    backdrop-filter: blur(24px);\n  }\n\n  .description div {\n    align-items: flex-end;\n    pointer-events: none;\n    inset: auto 0 0;\n    padding: 2rem;\n    height: 200px;\n    background: linear-gradient(\n      to bottom,\n      transparent 0%,\n      rgb(var(--background-end-rgb)) 40%\n    );\n    z-index: 1;\n  }\n}\n\n/* Tablet and Smaller Desktop */\n@media (min-width: 701px) and (max-width: 1120px) {\n  .grid {\n    grid-template-columns: repeat(2, 50%);\n  }\n}\n\n@media (prefers-color-scheme: dark) {\n  .vercelLogo {\n    filter: invert(1);\n  }\n\n  .logo {\n    filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70);\n  }\n}\n\n@keyframes rotate {\n  from {\n    transform: rotate(360deg);\n  }\n  to {\n    transform: rotate(0deg);\n  }\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/styles/globals.css",
    "content": ":root {\n  --max-width: 1100px;\n  --border-radius: 12px;\n  --font-mono: ui-monospace, Menlo, Monaco, \"Cascadia Mono\", \"Segoe UI Mono\",\n    \"Roboto Mono\", \"Oxygen Mono\", \"Ubuntu Monospace\", \"Source Code Pro\",\n    \"Fira Mono\", \"Droid Sans Mono\", \"Courier New\", monospace;\n\n  --foreground-rgb: 0, 0, 0;\n  --background-start-rgb: 214, 219, 220;\n  --background-end-rgb: 255, 255, 255;\n\n  --primary-glow: conic-gradient(\n    from 180deg at 50% 50%,\n    #16abff33 0deg,\n    #0885ff33 55deg,\n    #54d6ff33 120deg,\n    #0071ff33 160deg,\n    transparent 360deg\n  );\n  --secondary-glow: radial-gradient(\n    rgba(255, 255, 255, 1),\n    rgba(255, 255, 255, 0)\n  );\n\n  --tile-start-rgb: 239, 245, 249;\n  --tile-end-rgb: 228, 232, 233;\n  --tile-border: conic-gradient(\n    #00000080,\n    #00000040,\n    #00000030,\n    #00000020,\n    #00000010,\n    #00000010,\n    #00000080\n  );\n\n  --callout-rgb: 238, 240, 241;\n  --callout-border-rgb: 172, 175, 176;\n  --card-rgb: 180, 185, 188;\n  --card-border-rgb: 131, 134, 135;\n}\n\n@media (prefers-color-scheme: dark) {\n  :root {\n    --foreground-rgb: 255, 255, 255;\n    --background-start-rgb: 0, 0, 0;\n    --background-end-rgb: 0, 0, 0;\n\n    --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0));\n    --secondary-glow: linear-gradient(\n      to bottom right,\n      rgba(1, 65, 255, 0),\n      rgba(1, 65, 255, 0),\n      rgba(1, 65, 255, 0.3)\n    );\n\n    --tile-start-rgb: 2, 13, 46;\n    --tile-end-rgb: 2, 5, 19;\n    --tile-border: conic-gradient(\n      #ffffff80,\n      #ffffff40,\n      #ffffff30,\n      #ffffff20,\n      #ffffff10,\n      #ffffff10,\n      #ffffff80\n    );\n\n    --callout-rgb: 20, 20, 20;\n    --callout-border-rgb: 108, 108, 108;\n    --card-rgb: 100, 100, 100;\n    --card-border-rgb: 200, 200, 200;\n  }\n}\n\n* {\n  box-sizing: border-box;\n  padding: 0;\n  margin: 0;\n}\n\nhtml,\nbody {\n  max-width: 100vw;\n  overflow-x: hidden;\n}\n\nbody {\n  color: rgb(var(--foreground-rgb));\n  background: linear-gradient(\n      to bottom,\n      transparent,\n      rgb(var(--background-end-rgb))\n    )\n    rgb(var(--background-start-rgb));\n}\n\na {\n  color: inherit;\n  text-decoration: none;\n}\n\n@media (prefers-color-scheme: dark) {\n  html {\n    color-scheme: dark;\n  }\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"strict\": true,\n    \"noEmit\": true,\n    \"esModuleInterop\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"bundler\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"jsx\": \"preserve\",\n    \"incremental\": true,\n    \"plugins\": [\n      {\n        \"name\": \"next\"\n      }\n    ],\n    \"paths\": {\n      \"@/*\": [\"./src/*\"]\n    }\n  },\n  \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\", \".next/types/**/*.ts\"],\n  \"exclude\": []\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/nextjs/typings.d.ts",
    "content": "declare module '*.png'\ndeclare module '*.svg'\ndeclare module '*.avif'"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/.eslintrc.cjs",
    "content": "module.exports = {\n  root: true,\n  env: { browser: true, es2020: true },\n  extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:react-hooks/recommended', 'plugin:storybook/recommended'],\n  ignorePatterns: ['dist', '.eslintrc.cjs'],\n  parser: '@typescript-eslint/parser',\n  plugins: ['react-refresh'],\n  rules: {\n    'react-refresh/only-export-components': [\n      'warn',\n      { allowConstantExport: true },\n    ],\n  },\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/.gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndist-ssr\n*.local\n\n# Editor directories and files\n.vscode/*\n!.vscode/extensions.json\n.idea\n.DS_Store\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n/test-results/\n/playwright-report/\n/blob-report/\n/playwright/.cache/\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/.storybook/aliased.ts",
    "content": "// This file is used to test that viteFinal is correctly loaded in Vitest\n// main.ts defines this file as a resolve alias, which is used in the ViteFinalTest story\n\nexport const aliasedFunction = () => true;\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/.storybook/get-decorator-string.ts",
    "content": "export const getDecoratorString = () => {\n  return \"Global Decorator\";\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/.storybook/main.ts",
    "content": "import { join } from \"node:path\";\n\nimport type { StorybookConfig } from \"@storybook/react-vite\";\n\nconst config: StorybookConfig = {\n  stories: [\"../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)\"],\n  addons: [\"@storybook/addon-vitest\", \"@storybook/addon-a11y\"],\n  framework: {\n    name: \"@storybook/react-vite\",\n    options: {},\n  },\n  core: {\n    disableWhatsNewNotifications: true,\n  },\n  previewHead: (head = \"\") => `${head}\n  <style>\n    body {\n      border: 1px solid red;\n    }\n  </style>`,\n  staticDirs: [{ from: \"./test-static-dirs\", to: \"test-static-dirs\" }],\n  viteFinal: (config) => {\n    return {\n      ...config,\n      optimizeDeps: {\n        ...config.optimizeDeps,\n        include: [...(config.optimizeDeps?.include || [])],\n      },\n      resolve: {\n        ...config.resolve,\n        alias: {\n          ...config.resolve?.alias,\n          \"test-alias\": join(import.meta.dirname, \"aliased.ts\"),\n        },\n      },\n    };\n  },\n  refs: {\n    \"storybook@8.0.0\": {\n      title: \"Storybook 8.0.0\",\n      url: \"https://635781f3500dd2c49e189caf-gckybvsekn.chromatic.com/\",\n    },\n    \"storybook@7.6.18\": {\n      title: \"Storybook 7.6.18\",\n      url: \"https://635781f3500dd2c49e189caf-oljwjdrftz.chromatic.com/\",\n    },\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/.storybook/preview-head.html",
    "content": "<style>\n  body {\n    background-color: rgb(250, 250, 210);\n  }\n</style>\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/.storybook/preview.tsx",
    "content": "import type { Preview } from '@storybook/react-vite';\nimport { getDecoratorString } from './get-decorator-string';\n\nconsole.log('preview file is called!');\n\nconst preview: Preview = {\n  decorators: [\n    (StoryFn) => (\n      <div data-testid=\"global-decorator\">\n        <div data-testid=\"decorator-string\">{getDecoratorString()}</div>\n        <br />\n        <StoryFn />\n      </div>\n    ),\n  ],\n  initialGlobals: {\n    locale: 'en',\n  },\n  globalTypes: {\n    locale: {\n      description: 'Locale for components',\n      toolbar: {\n        title: 'Locale',\n        icon: 'circlehollow',\n        items: ['es', 'en'],\n      },\n    },\n  },\n};\n\nexport default preview;\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/.storybook/setup-file-dependency.ts",
    "content": "export const getString = () => {\n  return \"initial string\";\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/.storybook/test-static-dirs/static.js",
    "content": "// This file is used to test that staticDirs are correctly loaded in Vitest\n\nexport const staticFunction = () => true;\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/.storybook/vitest.setup.ts",
    "content": "import { getString } from './setup-file-dependency';\n\nconsole.log(getString());\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/.swcrc",
    "content": "{\n  \"jsc\": {\n    \"parser\": {\n      \"syntax\": \"typescript\",\n      \"tsx\": true,\n      \"decorators\": true,\n      \"dynamicImport\": true\n    },\n    \"transform\": {\n      \"react\": {\n        \"runtime\": \"automatic\"\n      }\n    },\n    \"target\": \"es2015\"\n  },\n  \"module\": {\n    \"type\": \"es6\",\n    \"noInterop\": true\n  }\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/.yarnrc",
    "content": ""
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/.yarnrc.yml",
    "content": "yarnPath: ../../../.yarn/releases/yarn-4.10.3.cjs\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/cypress/support/commands.ts",
    "content": "/// <reference types=\"cypress\" />\n// ***********************************************\n// This example commands.ts shows you how to\n// create various custom commands and overwrite\n// existing commands.\n//\n// For more comprehensive examples of custom\n// commands please read more here:\n// https://on.cypress.io/custom-commands\n// ***********************************************"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/cypress/support/component-index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n    <title>Components App</title>\n  </head>\n  <body>\n    <div data-cy-root></div>\n  </body>\n</html>"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/cypress/support/component.ts",
    "content": "/* eslint-disable @typescript-eslint/no-namespace */\n// ***********************************************************\n// This example support/component.ts is processed and\n// loaded automatically before your test files.\n//\n// This is a great place to put global configuration and\n// behavior that modifies Cypress.\n//\n// You can change the location of this file or turn off\n// automatically serving support files with the\n// 'supportFile' configuration option.\n//\n// You can read more here:\n// https://on.cypress.io/configuration\n// ***********************************************************\n\n// Import commands.js using ES2015 syntax:\nimport \"./commands\";\n\nimport { mount } from \"cypress/react18\";\n\nimport { setProjectAnnotations } from \"@storybook/react-vite\";\nimport sbAnnotations from \"../../.storybook/preview\";\n\n// Augment the Cypress namespace to include type definitions for\n// your custom command.\n// Alternatively, can be defined in cypress/support/component.d.ts\n// with a <reference path=\"./component\" /> at the top of your spec.\ndeclare global {\n  namespace Cypress {\n    interface Chainable {\n      mount: typeof mount;\n    }\n  }\n}\n\n// This is needed because Cypress defines process but not process.env\n// And if the play function fails, testing library's internals have a check\n// for typeof process !== \"undefined\" && process.env.DEBUG_PRINT_LIMIT;\n// which will break\nprocess.env = {};\n\nCypress.Commands.add(\"mount\", mount);\n\nsetProjectAnnotations([sbAnnotations]);\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/cypress.config.ts",
    "content": "import { defineConfig } from \"cypress\";\n\nexport default defineConfig({\n  screenshotOnRunFailure: false,\n  component: {\n    devServer: {\n      framework: \"react\",\n      bundler: \"vite\",\n    },\n  },\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/e2e-tests/component-testing.spec.ts",
    "content": "import { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\n\nimport { expect, test } from \"@playwright/test\";\n\nimport { SbPage } from \"../../../../code/e2e-tests/util\";\n\nconst STORYBOOK_URL = \"http://localhost:6006\";\nconst TEST_STORY_PATH = path.resolve(\n  __dirname,\n  \"..\",\n  \"stories\",\n  \"AddonTest.stories.tsx\"\n);\nconst UNHANDLED_ERRORS_STORY_PATH = path.resolve(\n  __dirname,\n  \"..\",\n  \"stories\",\n  \"UnhandledErrors.stories.tsx\"\n);\nconst ADDON_TEST_DEPENDENCY_PATH = path.resolve(\n  __dirname,\n  \"..\",\n  \"stories\",\n  \"get-button-string.ts\"\n);\nconst PREVIEW_DEPENDENCY_PATH = path.resolve(\n  __dirname,\n  \"..\",\n  \".storybook\",\n  \"get-decorator-string.ts\"\n);\nconst SETUP_FILE_DEPENDENCY_PATH = path.resolve(\n  __dirname,\n  \"..\",\n  \".storybook\",\n  \"setup-file-dependency.ts\"\n);\n\nconst setForceFailureFlag = (content: string, value: boolean) =>\n  content.replace(/forceFailure:\\s*(true|false)/, `forceFailure: ${value}`);\n\nconst modifiedFiles = new Map<string, string>();\n\nconst modifyFile = async (\n  filePath: string,\n  modify: (content: string) => string\n) => {\n  const content = (await fs.readFile(filePath)).toString();\n  const modifiedContent = modify(content);\n  await fs.writeFile(filePath, modifiedContent);\n  if (!modifiedFiles.has(filePath)) {\n    modifiedFiles.set(filePath, content);\n  }\n\n  // the file change causes a HMR event, which causes a browser reload,and that can take a few seconds\n  await new Promise((resolve) => setTimeout(resolve, 2000));\n};\n\nconst restoreAllFiles = async () => {\n  for (const [filePath, originalContent] of modifiedFiles.entries()) {\n    await fs.writeFile(filePath, originalContent);\n  }\n  modifiedFiles.clear();\n  // the file change causes a HMR event, which causes a browser reload,and that can take a few seconds\n  await new Promise((resolve) => setTimeout(resolve, 2000));\n};\n\ntest.describe(\"component testing\", () => {\n  test.describe.configure({ mode: \"serial\" });\n  test.beforeEach(async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n\n    await page.goto(STORYBOOK_URL);\n    await page.evaluate(() => window.sessionStorage.clear());\n    await sbPage.waitUntilLoaded();\n\n    const expandTestingModule = page.getByLabel(\"Expand testing module\");\n    if (await expandTestingModule.isVisible()) {\n      await expandTestingModule.click();\n    }\n  });\n\n  test.afterEach(async ({ page }) => {\n    await page.click(\"body\");\n    try {\n      const descriptionButton = page.locator(\"#testing-module-description button\");\n      if (\n        await descriptionButton.isVisible({ timeout: 4000 }).catch(() => false)\n      ) {\n        await descriptionButton.click({ timeout: 4000, force: true });\n\n        await page\n          .getByLabel(\"Close modal\")\n          .click({ timeout: 4000, force: true });\n      }\n    } catch {\n      // Ignore any errors when trying to open the modal\n    }\n\n    await restoreAllFiles();\n\n    const expandTestingModule = page.getByLabel(\"Expand testing module\");\n    if (await expandTestingModule.isVisible()) {\n      await expandTestingModule.click();\n    }\n\n    // Make sure any popover is closed\n    await page.click(\"body\");\n\n    // Ensure that all test results are removed and features are disabled, as previous tests might have enabled them\n    const clearStatusesButton = page.getByLabel(\"Clear all statuses\");\n    if (await clearStatusesButton.isVisible()) {\n      await clearStatusesButton.click();\n    }\n\n    const watchModeToggle = page.getByRole(\"switch\", { name: \"Watch mode\" });\n    if (\n      (await watchModeToggle.isVisible()) &&\n      (await watchModeToggle.getAttribute(\"aria-checked\")) === \"true\"\n    ) {\n      await watchModeToggle.click();\n    }\n\n    const configs = [\n      page.getByRole(\"checkbox\", { name: \"Coverage\" }),\n      page.getByRole(\"checkbox\", { name: \"Accessibility\" }),\n    ];\n    for (const config of configs) {\n      if (await config.isChecked()) {\n        await config.click();\n      }\n    }\n  });\n\n  test(\"should show discrepancy between test results\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n    const sbPage = new SbPage(page, expect);\n\n    await sbPage.navigateToStory(\"addons/group/test\", \"Mismatch Failure\");\n\n    // For whatever reason, sometimes it takes longer for the story to load\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"test\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    await sbPage.viewAddonPanel(\"Interactions\");\n\n    // For whatever reason, when visiting a story sometimes the story element is collapsed and that causes flake\n    const testStoryElement = await page.getByRole(\"button\", {\n      name: \"Test\",\n      exact: true,\n    });\n    if ((await testStoryElement.getAttribute(\"aria-expanded\")) !== \"true\") {\n      await testStoryElement.click();\n    }\n\n    const testingModuleDescription = await page.locator(\n      \"#testing-module-description\"\n    );\n\n    const runTestsButton = await page.getByLabel(\"Start test run\");\n    await runTestsButton.click();\n\n    // Wait for test results to appear\n    await expect(testingModuleDescription).toHaveText(/Ran \\d+ tests/, {\n      timeout: 60000,\n    });\n\n    const errorFilter = page.getByLabel(\n      /Filter main navigation to show \\d+ tests with errors/\n    );\n    await expect(errorFilter).toBeVisible();\n\n    // Assert discrepancy: CLI pass + Browser fail\n    const failingStoryElement = page.locator(\n      '[data-item-id=\"addons-group-test--mismatch-failure\"] [data-testid=\"tree-status-button\"]'\n    );\n    await expect(failingStoryElement).toHaveAttribute(\n      \"aria-label\",\n      \"Status: success\"\n    );\n    await expect(sbPage.panelContent()).toContainText(\n      /This interaction test passed in the CLI, but the tests failed in this browser/\n    );\n\n    // Assert discrepancy: CLI fail + Browser pass\n    await sbPage.navigateToStory(\"addons/group/test\", \"Mismatch Success\");\n    const successfulStoryElement = page.locator(\n      '[data-item-id=\"addons-group-test--mismatch-success\"] [data-testid=\"tree-status-button\"]'\n    );\n    await expect(successfulStoryElement).toHaveAttribute(\n      \"aria-label\",\n      \"Status: error\"\n    );\n    await expect(sbPage.panelContent()).toContainText(\n      /This interaction test passed in this browser, but the tests failed in the CLI/\n    );\n  });\n\n  test(\"should execute tests via testing module UI\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n    await modifyFile(TEST_STORY_PATH, (content) =>\n      setForceFailureFlag(content, true)\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"addons/group/test\", \"Expected Failure\");\n\n    // For whatever reason, sometimes it takes longer for the story to load\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"test\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    await expect(page.locator(\"#testing-module-title\")).toHaveText(\n      \"Run component tests\"\n    );\n\n    const runTestsButton = await page.getByLabel(\"Start test run\");\n    const watchModeButton = await page.getByRole(\"switch\", {\n      name: \"Watch mode\",\n    });\n    await expect(runTestsButton).not.toHaveAttribute(\"aria-disabled\", \"true\");\n    await expect(watchModeButton).not.toHaveAttribute(\"aria-disabled\", \"true\");\n\n    await runTestsButton.click();\n\n    // Wait for test results to appear\n    await expect(page.locator(\"#testing-module-description\")).toHaveText(\n      /Ran \\d+ tests/,\n      { timeout: 30000 }\n    );\n\n    await expect(runTestsButton).not.toHaveAttribute(\"aria-disabled\", \"true\");\n    await expect(watchModeButton).not.toHaveAttribute(\"aria-disabled\", \"true\");\n\n    const errorFilter = page.getByLabel(\n      /Filter main navigation to show \\d+ tests with errors/\n    );\n    await expect(errorFilter).toBeVisible();\n\n    // Assert for expected success\n    const successfulStoryElement = page.locator(\n      '[data-item-id=\"addons-group-test--expected-success\"] [data-testid=\"tree-status-button\"]'\n    );\n    await expect(successfulStoryElement).toHaveAttribute(\n      \"aria-label\",\n      \"Status: success\"\n    );\n\n    // Assert for expected failure\n    const failingStoryElement = page.locator(\n      '[data-item-id=\"addons-group-test--expected-failure\"] [data-testid=\"tree-status-button\"]'\n    );\n    await expect(failingStoryElement).toHaveAttribute(\n      \"aria-label\",\n      \"Status: error\"\n    );\n\n    // Assert that filter works as intended\n    await errorFilter.click();\n\n    const sidebarItems = page.locator(\n      '.sidebar-item[data-ref-id=\"storybook_internal\"][data-nodetype=\"component\"]'\n    );\n    await expect(sidebarItems).toHaveCount(2);\n  });\n\n  test(\"should run tests in watch mode when a story file is changed\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n    await modifyFile(TEST_STORY_PATH, (content) =>\n      setForceFailureFlag(content, false)\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"addons/group/test\", \"Expected Failure\");\n\n    // For whatever reason, sometimes it takes longer for the story to load\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"test\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    await page.getByRole(\"switch\", { name: \"Watch mode\" }).click();\n\n    // We shouldn't have to do an arbitrary wait, but because there is no UI for loading state yet, we have to\n    await page.waitForTimeout(8000);\n    await modifyFile(TEST_STORY_PATH, (content) =>\n      setForceFailureFlag(content, true)\n    );\n\n    // Wait for test results to appear\n    const errorFilter = page.getByLabel(\n      /Filter main navigation to show \\d+ tests with errors/\n    );\n    await expect(errorFilter).toBeVisible({ timeout: 30000 });\n\n    // Assert for expected success\n    const successfulStoryElement = page.locator(\n      '[data-item-id=\"addons-group-test--expected-success\"] [data-testid=\"tree-status-button\"]'\n    );\n    await expect(successfulStoryElement).toHaveAttribute(\n      \"aria-label\",\n      \"Status: success\"\n    );\n\n    // Assert for expected failure\n    const failingStoryElement = page.locator(\n      '[data-item-id=\"addons-group-test--expected-failure\"] [data-testid=\"tree-status-button\"]'\n    );\n    await expect(failingStoryElement).toHaveAttribute(\n      \"aria-label\",\n      \"Status: error\"\n    );\n\n    // Assert that filter works as intended\n    await errorFilter.click();\n\n    const sidebarItems = page.locator(\n      '.sidebar-item[data-ref-id=\"storybook_internal\"][data-nodetype=\"component\"]'\n    );\n    await expect(sidebarItems).toHaveCount(1);\n  });\n\n  test(\"should run tests in watch mode when a story file's dependency is changed\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"addons/group/test\", \"Expected Failure\");\n\n    // For whatever reason, sometimes it takes longer for the story to load\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"test\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    await page.getByRole(\"switch\", { name: \"Watch mode\" }).click();\n\n    // We shouldn't have to do an arbitrary wait, but because there is no UI for loading state yet, we have to\n    await page.waitForTimeout(3000);\n    await modifyFile(ADDON_TEST_DEPENDENCY_PATH, (content) =>\n      content.replace(\"test\", \"changed\")\n    );\n\n    // Expect less than 10 tests to have run\n    await expect(page.locator(\"#testing-module-description\")).toContainText(\n      /Ran \\d tests/,\n      { timeout: 30000 }\n    );\n\n    // Assert for expected failure\n    const failingStoryElement = page.locator(\n      '[data-item-id=\"addons-group-test--expected-content\"] [data-testid=\"tree-status-button\"]'\n    );\n    await expect(failingStoryElement).toHaveAttribute(\n      \"aria-label\",\n      \"Status: error\"\n    );\n  });\n\n  test(\"should run all tests in watch mode when the preview file's dependency is changed\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"addons/group/test\", \"Expected Failure\");\n\n    // For whatever reason, sometimes it takes longer for the story to load\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"test\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    await page.getByRole(\"switch\", { name: \"Watch mode\" }).click();\n\n    // We shouldn't have to do an arbitrary wait, but because there is no UI for loading state yet, we have to\n    await page.waitForTimeout(3000);\n    await modifyFile(PREVIEW_DEPENDENCY_PATH, (content) =>\n      content.replace(\"Global Decorator\", \"Changed Decorator\")\n    );\n\n    // Expect at least 20 tests to have run\n    await expect(page.locator(\"#testing-module-description\")).toContainText(\n      /Ran [2-9]\\d tests/,\n      { timeout: 30000 }\n    );\n\n    // Assert for expected failure\n    const failingStoryElement = page.locator(\n      '[data-item-id=\"addons-group-test--expected-content\"] [data-testid=\"tree-status-button\"]'\n    );\n\n    await expect(failingStoryElement).toHaveAttribute(\n      \"aria-label\",\n      \"Status: error\"\n    );\n  });\n\n  test(\"should run all tests in watch mode when the setup file's dependency is changed\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"addons/group/test\", \"Expected Failure\");\n\n    // For whatever reason, sometimes it takes longer for the story to load\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"test\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    await page.getByRole(\"switch\", { name: \"Watch mode\" }).click();\n\n    // We shouldn't have to do an arbitrary wait, but because there is no UI for loading state yet, we have to\n    await page.waitForTimeout(3000);\n    await modifyFile(SETUP_FILE_DEPENDENCY_PATH, (content) =>\n      content.replace(\"initial string\", \"changed string\")\n    );\n\n    // Expect at least 20 tests to have run\n    await expect(page.locator(\"#testing-module-description\")).toContainText(\n      /Ran [2-9]\\d tests/,\n      { timeout: 30000 }\n    );\n  });\n\n  test(\"should collect coverage to testing module and HTML report\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n    // Arrange - Prepare Storybook\n    await modifyFile(TEST_STORY_PATH, (content) =>\n      setForceFailureFlag(content, false)\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"addons/group/test\", \"Expected Failure\");\n\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"test\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    // Assert - No coverage report initially\n    await expect(page.getByLabel(\"Open coverage report\")).toHaveCount(0);\n\n    // Act - Enable coverage and run tests\n    await page.getByLabel(\"Coverage\", { exact: true }).click();\n    // Wait for Vitest to have (re)started\n    await page.waitForTimeout(2000);\n\n    await page.getByLabel(\"Start test run\").click();\n\n    // Assert - Coverage report is collected and shown\n    await expect(page.getByLabel(\"Open coverage report\")).toBeVisible({\n      timeout: 30000,\n    });\n    const sbPercentageText = await page\n      .getByLabel(/% coverage\\)$/)\n      .textContent();\n    expect(sbPercentageText).toMatch(/^\\d+%$/);\n    const sbPercentage = Number.parseInt(\n      sbPercentageText!.replace(\"%\", \"\") ?? \"\"\n    );\n    expect(sbPercentage).toBeGreaterThanOrEqual(0);\n    expect(sbPercentage).toBeLessThanOrEqual(100);\n\n    // Act - Open HTML coverage report\n    const coverageReportLink = await page.getByLabel(\"Open coverage report\");\n    // Remove target=\"_blank\" attribute to open in the same tab\n    await coverageReportLink.evaluate((elem) => elem.removeAttribute(\"target\"));\n    await page.getByLabel(\"Open coverage report\").click();\n\n    // Assert - HTML coverage report is accessible and reports the same coverage percentage as Storybook\n    const htmlPercentageText =\n      (await page\n        .locator('span:has(+ :text(\"Statements\"))')\n        .first()\n        .textContent()) ?? \"\";\n    const htmlPercentage = Number.parseFloat(\n      htmlPercentageText.replace(\"% \", \"\")\n    );\n    expect(Math.round(htmlPercentage)).toBe(sbPercentage);\n\n    await page.goBack();\n  });\n\n  test(\"should run focused test for a single story\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n    // Arrange - Prepare Storybook\n    await modifyFile(TEST_STORY_PATH, (content) =>\n      setForceFailureFlag(content, false)\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"addons/group/test\", \"Expected Failure\");\n\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"test\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    // Act - Open sidebar context menu, start focused test then close menu\n    await page\n      .locator('[data-item-id=\"addons-group-test--expected-failure\"]')\n      .hover();\n    await page\n      .locator(\n        '[data-item-id=\"addons-group-test--expected-failure\"] button[data-testid=\"context-menu\"]'\n      )\n      .click();\n    const sidebarContextMenu = page.getByRole(\"dialog\");\n    await sidebarContextMenu.getByLabel(\"Start test run\").click();\n\n    // Assert - Only one test is running and reported\n    await expect(\n      sidebarContextMenu.locator(\"#testing-module-description\")\n    ).toContainText(\"Ran 1 test\", { timeout: 30000 });\n    await expect(\n      sidebarContextMenu.getByLabel(\"Component tests passed\")\n    ).toHaveCount(1);\n    await page.click(\"body\");\n    await expect(\n      page.locator(\n        '#storybook-explorer-menu [data-testid=\"tree-status-button\"][aria-label=\"Status: success\"]'\n      )\n    ).toHaveCount(1);\n  });\n\n  test(\"should show unhandled errors in the testing module\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n    // Arrange - Prepare Storybook\n    await modifyFile(UNHANDLED_ERRORS_STORY_PATH, (content) =>\n      setForceFailureFlag(content, true)\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"example/unhandlederrors\", \"Success\");\n\n    const storyElement = sbPage.getCanvasBodyElement().getByText(\"Hello world\");\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    // Act - Open sidebar context menu and start focused test\n    await page.locator('[data-item-id=\"example-unhandlederrors\"]').hover();\n    await page\n      .locator(\n        '[data-item-id=\"example-unhandlederrors\"] button[data-testid=\"context-menu\"]'\n      )\n      .click();\n    const sidebarContextMenu = page.getByRole(\"dialog\");\n    await sidebarContextMenu.getByLabel(\"Start test run\").click();\n\n    // HACK: the testing module popover has poor tracking of focus due to how many disabled\n    // buttons it has and how deeply it changes its UI on events. This would be solved once\n    // we move to a declarative menu, and there's an ongoing PR for that. Until then, we tab\n    // around to reset focus.\n    await page.keyboard.press(\"Tab\");\n    await page.keyboard.press(\"Escape\");\n    await page.click(\"body\");\n    await expect(sidebarContextMenu).not.toBeVisible();\n\n    // Assert - Tests are running and errors are reported\n    const errorLink = page.locator(\"#testing-module-description button\");\n    await expect(errorLink).toContainText(\"View full error\", {\n      timeout: 30000,\n    });\n    await errorLink.click();\n\n    await expect(page.locator(\"pre\")).toContainText(\n      \"I THREW AN UNHANDLED ERROR!\"\n    );\n    await expect(page.locator(\"pre\")).toContainText(\"This error originated in\");\n    await expect(page.locator(\"pre\")).toContainText(\n      \"The latest test that might've caused the error is\"\n    );\n    await page.getByLabel(\"Close modal\").click();\n  });\n\n  test(\"should run focused test for a component\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n    // Arrange - Prepare Storybook\n    await modifyFile(TEST_STORY_PATH, (content) =>\n      setForceFailureFlag(content, false)\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"addons/group/test\", \"Expected Failure\");\n\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"test\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    // Act - Open sidebar context menu and start focused test\n    await page.locator('[data-item-id=\"addons-group-test\"]').hover();\n    await page\n      .locator(\n        '[data-item-id=\"addons-group-test\"] button[data-testid=\"context-menu\"]'\n      )\n      .click();\n    const sidebarContextMenu = page.getByRole(\"dialog\");\n    await sidebarContextMenu.getByLabel(\"Start test run\").click();\n\n    // Assert - Tests are running and reported\n    await expect(\n      sidebarContextMenu.locator(\"#testing-module-description\")\n    ).toContainText(\"Ran 9 tests\", { timeout: 30000 });\n    // Assert - Failing test shows as a failed status\n    await expect(\n      sidebarContextMenu.getByLabel(\"Component tests failed\")\n    ).toHaveCount(1);\n    await expect(\n      sidebarContextMenu.getByLabel(\n        \"Component tests failed (1 errors or warnings so far)\"\n      )\n    ).toBeVisible();\n\n    // HACK: the testing module popover has poor tracking of focus due to how many disabled\n    // buttons it has and how deeply it changes its UI on events. This would be solved once\n    // we move to a declarative menu, and there's an ongoing PR for that. Until then, we tab\n    // around to reset focus.\n    await page.keyboard.press(\"Tab\");\n    await page.keyboard.press(\"Escape\");\n    await page.click(\"body\");\n    await expect(sidebarContextMenu).not.toBeVisible();\n\n    await page.click(\"body\");\n    await expect(\n      page.locator(\n        '#storybook-explorer-menu [data-testid=\"tree-status-button\"][aria-label=\"Status: success\"]'\n      )\n    ).toHaveCount(8);\n    await expect(\n      page.locator(\n        '#storybook-explorer-menu [data-testid=\"tree-status-button\"][aria-label=\"Status: error\"]'\n      )\n    ).toHaveCount(3); // 1 story, 1 component, 1 group\n  });\n\n  test(\"should run focused test for a group\", async ({ page, browserName }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n    // Arrange - Prepare Storybook\n    await modifyFile(TEST_STORY_PATH, (content) =>\n      setForceFailureFlag(content, false)\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"addons/group/test\", \"Expected Failure\");\n\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"test\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    // Act - Open sidebar context menu and start focused test\n    await page.locator('[data-item-id=\"addons-group\"]').hover();\n    await page\n      .locator(\n        '[data-item-id=\"addons-group\"] button[data-testid=\"context-menu\"]'\n      )\n      .click();\n    const sidebarContextMenu = page.getByRole(\"dialog\");\n    await sidebarContextMenu.getByLabel(\"Start test run\").click();\n\n    // Assert - 1 failing test shows as a failed status\n    await expect(\n      sidebarContextMenu.getByLabel(\n        \"Component tests failed (2 errors or warnings so far)\"\n      )\n    ).toBeVisible();\n    await expect(\n      sidebarContextMenu.getByLabel(\"Component tests failed\")\n    ).toHaveCount(1);\n\n    // HACK: the testing module popover has poor tracking of focus due to how many disabled\n    // buttons it has and how deeply it changes its UI on events. This would be solved once\n    // we move to a declarative menu, and there's an ongoing PR for that. Until then, we tab\n    // around to reset focus.\n    await page.keyboard.press(\"Tab\");\n    await page.keyboard.press(\"Escape\");\n    await page.click(\"body\");\n    await expect(sidebarContextMenu).not.toBeVisible();\n\n    // Assert - Tests are running and reported\n    await expect(page.locator(\"#testing-module-description\")).toContainText(\n      \"Ran 11 tests\",\n      { timeout: 30000 }\n    );\n    await expect(\n      page.locator(\n        '#storybook-explorer-menu [data-testid=\"tree-status-button\"][aria-label=\"Status: error\"]'\n      )\n    ).toHaveCount(4); // 1 visible/expanded story, 1 expanded component, 1 collapsed component, 1 group\n\n    await page.click(\"body\");\n    await expect(\n      page.locator(\n        '#storybook-explorer-menu [data-testid=\"tree-status-button\"][aria-label=\"Status: success\"]'\n      )\n    ).toHaveCount(8);\n    await expect(\n      page.locator(\n        '#storybook-explorer-menu [data-testid=\"tree-status-button\"][aria-label=\"Status: error\"]'\n      )\n    ).toHaveCount(4);\n  });\n\n  test(\"should run focused tests without coverage, even when enabled\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n    // Arrange - Prepare Storybook\n    await modifyFile(TEST_STORY_PATH, (content) =>\n      setForceFailureFlag(content, false)\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"example/button\", \"CSF 3 Primary\");\n\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"foo\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    // Act - Enable coverage\n    await page.getByLabel(\"Coverage\", { exact: true }).click();\n    // Wait for Vitest to have (re)started\n    await page.waitForTimeout(2000);\n\n    // Act - Open sidebar context menu and start focused test\n    await page\n      .locator('[data-item-id=\"example-button--csf-3-primary\"]')\n      .hover();\n    await page\n      .locator(\n        '[data-item-id=\"example-button--csf-3-primary\"] button[data-testid=\"context-menu\"]'\n      )\n      .click();\n    const sidebarContextMenu = page.getByRole(\"dialog\");\n    await sidebarContextMenu.getByLabel(\"Start test run\").click();\n\n    // HACK: the testing module popover has poor tracking of focus due to how many disabled\n    // buttons it has and how deeply it changes its UI on events. This would be solved once\n    // we move to a declarative menu, and there's an ongoing PR for that. Until then, we tab\n    // around to reset focus.\n    await page.keyboard.press(\"Tab\");\n    await page.keyboard.press(\"Escape\");\n    await page.click(\"body\");\n    await expect(sidebarContextMenu).not.toBeVisible();\n\n    // Arrange - Wait for test to finish and unfocus sidebar context menu\n    await expect(page.locator(\"#testing-module-description\")).toContainText(\n      \"Ran 1 test\",\n      { timeout: 30000 }\n    );\n    await page.click(\"body\");\n\n    // Assert - Coverage is not shown because Focused Tests shouldn't collect coverage\n    await expect(page.getByLabel(\"Open coverage report\")).not.toBeVisible();\n\n    // Act - Run ALL tests\n    await page.getByLabel(\"Start test run\").click();\n\n    // Arrange - Wait for tests to finish\n    await expect(page.locator(\"#testing-module-description\")).toContainText(\n      /Ran \\d{2,} tests/,\n      { timeout: 30000 }\n    );\n\n    // Assert - Coverage percentage is now collected and shown because running all tests automatically re-enables coverage\n    await expect(page.getByLabel(\"Open coverage report\")).toBeVisible({\n      timeout: 30000,\n    });\n    const sbPercentageText = await page\n      .getByLabel(/% coverage\\)$/)\n      .textContent();\n    expect(sbPercentageText).toMatch(/^\\d+%$/);\n    const sbPercentage = Number.parseInt(\n      sbPercentageText!.replace(\"%\", \"\") ?? \"\"\n    );\n    expect(sbPercentage).toBeGreaterThanOrEqual(0);\n    expect(sbPercentage).toBeLessThanOrEqual(100);\n  });\n\n  test.fixme(\n    \"should still collect statuses even when the browser is closed\",\n    () => {}\n  );\n\n  test.fixme(\n    \"should have correct status count globally and in context menus\",\n    () => {}\n  );\n\n  test.fixme(\n    \"should open the correct component test and a11y panels when clicking on statuses\",\n    () => {}\n  );\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/e2e-tests/composition.spec.ts",
    "content": "import { expect, test } from '@playwright/test';\n\nimport { SbPage } from '../../../../code/e2e-tests/util';\n\nconst STORYBOOK_URL = 'http://localhost:6006';\n\ntest.describe('composition', () => {\n  // the composed storybook can be slow to load, so we need to increase the timeout\n  test.describe.configure({ mode: 'serial', timeout: 60000, retries: 2 });\n  test('should filter and render composed stories', async ({ page }) => {\n    await page.goto(STORYBOOK_URL);\n    await new SbPage(page, expect).waitUntilLoaded();\n\n    // Expect that composed Storybooks are visible and loaded\n    await expect(page.getByTitle('Storybook 8.0.0')).toBeVisible();\n    await expect(page.locator('[id=\"storybook\\\\@8\\\\.0\\\\.0_components-badge\"]')).toBeVisible({\n      timeout: 15000,\n    });\n    await expect(page.getByTitle('Storybook 7.6.18')).toBeVisible();\n    await expect(page.locator('[id=\"storybook\\\\@7\\\\.6\\\\.18_components-badge\"]')).toBeVisible({\n      timeout: 15000,\n    });\n\n    // Expect composed stories to be available in the sidebar\n    await page.locator('[id=\"storybook\\\\@8\\\\.0\\\\.0_components-badge\"]').click();\n    await expect(\n      page.locator('[id=\"storybook\\\\@8\\\\.0\\\\.0_components-badge--default\"]')\n    ).toBeVisible();\n\n    await page.locator('[id=\"storybook\\\\@7\\\\.6\\\\.18_components-badge\"]').click();\n    await expect(\n      page\n        .locator('iframe[title=\"storybook-ref-storybook\\\\@7\\\\.6\\\\.18\"]')\n        .contentFrame()\n        .locator('#storybook-root')\n        .getByText('Default')\n    ).toBeVisible({ timeout: 15000 });\n\n    // Expect composed stories to be available in the search\n    await page.getByPlaceholder('Find components').fill('Button primary');\n    await expect(\n      page.getByRole('option', {\n        name: 'Primary Storybook 7.6.18 / @components / Button',\n      })\n    ).toBeVisible();\n\n    const buttonStory = page.getByRole('option', {\n      name: 'Primary Storybook 8.0.0 / @blocks / examples / Button',\n    });\n    await expect(buttonStory).toBeVisible();\n    await buttonStory.click();\n\n    // Note: this could potentially be flaky due to it accessing a hosted Storybook\n    await expect(\n      page\n        .locator('iframe[title=\"storybook-ref-storybook\\\\@8\\\\.0\\\\.0\"]')\n        .contentFrame()\n        .getByRole('button')\n    ).toBeVisible({ timeout: 15000 });\n  });\n\n  test('should filter and render composed stories on mobile', async ({ page }) => {\n    page.setViewportSize({ width: 320, height: 800 });\n    await page.goto(STORYBOOK_URL);\n    await new SbPage(page, expect).waitUntilLoaded();\n\n    await page.click('button[aria-label=\"Open navigation menu\"]');\n\n    // scroll down to the bottom of the element getByText('Skip to canvasStorybookSearch')\n\n    await page.getByTitle('Storybook 7.6.18').scrollIntoViewIfNeeded();\n\n    // Expect that composed Storybooks are visible\n    await expect(page.getByTitle('Storybook 8.0.0')).toBeVisible();\n    await expect(page.getByTitle('Storybook 7.6.18')).toBeVisible();\n\n    // Expect composed stories to be available in the sidebar\n    await expect(page.locator('[id=\"storybook\\\\@8\\\\.0\\\\.0_components-badge\"]')).toBeVisible();\n    await page.locator('[id=\"storybook\\\\@8\\\\.0\\\\.0_components-badge\"]').click();\n    await expect(\n      page.locator('[id=\"storybook\\\\@8\\\\.0\\\\.0_components-badge--default\"]')\n    ).toBeVisible();\n\n    await page.locator('[id=\"storybook\\\\@7\\\\.6\\\\.18_components-badge\"]').click();\n    await page.locator('[id=\"storybook\\\\@7\\\\.6\\\\.18_components-badge--default\"]').click();\n    await expect(\n      page\n        .locator('iframe[title=\"storybook-ref-storybook\\\\@7\\\\.6\\\\.18\"]')\n        .contentFrame()\n        .locator('#storybook-root')\n        .getByText('Default')\n    ).toBeVisible({ timeout: 15000 });\n\n    await page.click('button[aria-label=\"Open navigation menu\"]');\n\n    // Expect composed stories `to be available in the search\n    await page.getByPlaceholder('Find components').fill('Button primary');\n    await expect(\n      page.getByRole('option', {\n        name: 'Primary Storybook 7.6.18 / @components / Button',\n      })\n    ).toBeVisible();\n\n    const buttonStory = page.getByRole('option', {\n      name: 'Primary Storybook 8.0.0 / @blocks / examples / Button',\n    });\n    await expect(buttonStory).toBeVisible();\n    await buttonStory.click();\n\n    // Note: this could potentially be flaky due to it accessing a hosted Storybook\n    await expect(\n      page\n        .locator('iframe[title=\"storybook-ref-storybook\\\\@8\\\\.0\\\\.0\"]')\n        .contentFrame()\n        .getByRole('button')\n    ).toBeVisible({ timeout: 15000 });\n  });\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/e2e-tests/save-from-controls.spec.ts",
    "content": "import { expect, test } from \"@playwright/test\";\nimport process from \"process\";\n\nimport { SbPage } from \"../../../../code/e2e-tests/util\";\n\nconst STORYBOOK_URL = \"http://localhost:6006\";\nconst type = process.env.STORYBOOK_TYPE || \"dev\";\n\ntest.describe(\"save-from-controls\", () => {\n  test.describe.configure({ mode: \"serial\" });\n  test.skip(\n    type === \"build\",\n    `Skipping save-from-controls tests for production Storybooks`\n  );\n\n  test(\"Should be able to update a story\", async ({ page, browserName }) => {\n    // this is needed because the e2e test will generate a new file in the system\n    // which we don't know of its location (it runs in different sandboxes)\n    // so we just create a random id to make it easier to run tests\n    const id = Math.random().toString(36).substring(7);\n\n    test.skip(\n      browserName !== \"chromium\",\n      `Skipping save-from-controls tests for ${browserName}`\n    );\n\n    await page.goto(STORYBOOK_URL + \"/?path=/story/example-mybutton--primary\");\n    const sbPage = new SbPage(page, expect);\n    await sbPage.waitUntilLoaded();\n\n    await sbPage.viewAddonPanel(\"Controls\");\n\n    // Update an arg\n    const label = sbPage.panelContent().locator(\"textarea[name=children]\");\n    await label.fill(`\"Updated ${id}\"`);\n    await label.blur();\n\n    // Assert the footer is shown\n    await sbPage\n      .panelContent()\n      .locator('[data-short-label=\"Unsaved changes\"]')\n      .isVisible();\n\n    // update the story\n    await sbPage\n      .panelContent()\n      .locator(\"button\")\n      .getByText(\"Update story\")\n      .click();\n\n    // Assert the file is saved\n    const notification1 = sbPage.page.getByTitle(\"Story saved\");\n    await expect(notification1).toBeVisible();\n\n    // dismiss\n    await notification1.click();\n    await notification1.isHidden();\n\n    // Update an arg\n    const newStoryValue = `\"Copied ${id}\"`;\n    await label.fill(newStoryValue);\n    await label.blur();\n\n    // Assert the footer is shown\n    await sbPage\n      .panelContent()\n      .locator('[data-short-label=\"Unsaved changes\"]')\n      .isVisible();\n\n    const buttons = sbPage\n      .panelContent()\n      .locator('[aria-label=\"Create new story with these settings\"]');\n\n    // clone the story\n    await buttons.click();\n\n    await sbPage.page\n      .getByPlaceholder(\"Story export name\")\n      .fill(\"ClonedStory\" + id);\n    await sbPage.page.getByRole(\"button\", { exact: true, name: \"Create\" }).click();\n\n    // Assert the file is saved\n    const notification2 = sbPage.page.getByTitle(\"Story created\");\n    await expect(notification2).toBeVisible();\n    await notification2.click();\n\n    // Assert the Button components is rendered in the preview\n    await expect(sbPage.previewRoot()).toContainText(newStoryValue.replace(/\"/g, ''));\n  });\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/globals.setup.ts",
    "content": "globalThis.FEATURES = {};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/jest.config.js",
    "content": "module.exports = {\n  testMatch: ['**/?(*.)+(test).[jt]s?(x)'],\n  setupFiles: ['<rootDir>/globals.setup.ts'],\n  setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],\n  transform: {\n    '^.+\\\\.(t|j)sx?$': [\n      '@swc/jest',\n      {\n        module: {\n          type: 'commonjs',\n        },\n      },\n    ],\n  },\n  transformIgnorePatterns: [],\n  moduleNameMapper: {\n    '\\\\.css$': 'identity-obj-proxy',\n  },\n  testEnvironment: 'jsdom',\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/jest.setup.ts",
    "content": "import '@testing-library/jest-dom';\nimport { setProjectAnnotations } from '@storybook/react-vite';\nimport sbAnnotations from './.storybook/preview';\n\nsetProjectAnnotations([sbAnnotations]);\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/package.json",
    "content": "{\n  \"name\": \"portable-stories-react\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"tsc && vite build\",\n    \"cypress\": \"cypress run --component\",\n    \"cypress-open\": \"cypress open --component\",\n    \"dev\": \"vite\",\n    \"jest\": \"node node_modules/jest/bin/jest.js\",\n    \"lint\": \"eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0\",\n    \"playwright-ct\": \"playwright test -c playwright-ct.config.ts\",\n    \"playwright-e2e\": \"playwright test -c playwright-e2e.config.ts\",\n    \"preview\": \"vite preview\",\n    \"storybook\": \"NODE_OPTIONS=\\\"--preserve-symlinks --preserve-symlinks-main\\\" storybook dev -p 6006\",\n    \"vitest\": \"SKIP_FAIL_ON_PURPOSE=true vitest run\"\n  },\n  \"resolutions\": {\n    \"@playwright/test\": \"1.58.2\",\n    \"@storybook/addon-a11y\": \"file:../../../code/addons/a11y\",\n    \"@storybook/addon-docs\": \"file:../../../code/addons/docs\",\n    \"@storybook/addon-links\": \"file:../../../code/addons/links\",\n    \"@storybook/addon-themes\": \"file:../../../code/addons/themes\",\n    \"@storybook/addon-vitest\": \"file:../../../code/addons/vitest\",\n    \"@storybook/angular\": \"file:../../../code/frameworks/angular\",\n    \"@storybook/builder-vite\": \"file:../../../code/builders/builder-vite\",\n    \"@storybook/builder-webpack5\": \"file:../../../code/builders/builder-webpack5\",\n    \"@storybook/codemod\": \"file:../../../code/lib/codemod\",\n    \"@storybook/core-webpack\": \"portal:../../../code/lib/core-webpack\",\n    \"@storybook/csf-plugin\": \"portal:../../../code/lib/csf-plugin\",\n    \"@storybook/ember\": \"portal:../../../code/frameworks/ember\",\n    \"@storybook/html\": \"file:../../../code/renderers/html\",\n    \"@storybook/nextjs\": \"file:../../../code/frameworks/nextjs\",\n    \"@storybook/preact\": \"file:../../../code/renderers/preact\",\n    \"@storybook/preact-vite\": \"file:../../../code/frameworks/preact-vite\",\n    \"@storybook/preset-create-react-app\": \"file:../../../code/presets/create-react-app\",\n    \"@storybook/preset-react-webpack\": \"file:../../../code/presets/react-webpack\",\n    \"@storybook/preset-server-webpack\": \"file:../../../code/presets/server-webpack\",\n    \"@storybook/react\": \"file:../../../code/renderers/react\",\n    \"@storybook/react-dom-shim\": \"file:../../../code/lib/react-dom-shim\",\n    \"@storybook/react-vite\": \"file:../../../code/frameworks/react-vite\",\n    \"@storybook/react-webpack5\": \"file:../../../code/frameworks/react-webpack5\",\n    \"@storybook/server\": \"file:../../../code/renderers/server\",\n    \"@storybook/server-webpack5\": \"file:../../../code/frameworks/server-webpack5\",\n    \"@storybook/svelte\": \"file:../../../code/renderers/svelte\",\n    \"@storybook/svelte-vite\": \"file:../../../code/frameworks/svelte-vite\",\n    \"@storybook/sveltekit\": \"file:../../../code/frameworks/sveltekit\",\n    \"@storybook/vue3\": \"file:../../../code/renderers/vue3\",\n    \"@storybook/vue3-vite\": \"file:../../../code/frameworks/vue3-vite\",\n    \"@storybook/web-components\": \"file:../../../code/renderers/web-components\",\n    \"@storybook/web-components-vite\": \"file:../../../code/frameworks/web-components-vite\",\n    \"eslint-plugin-storybook\": \"file:../../../code/lib/eslint-plugin\",\n    \"playwright\": \"1.58.2\",\n    \"storybook\": \"portal:../../../code/core\"\n  },\n  \"dependencies\": {\n    \"react\": \"^18.0.0\",\n    \"react-dom\": \"^18.0.0\"\n  },\n  \"devDependencies\": {\n    \"@playwright/experimental-ct-react\": \"1.58.2\",\n    \"@playwright/test\": \"1.58.2\",\n    \"@storybook/addon-a11y\": \"^10.0.0\",\n    \"@storybook/addon-vitest\": \"^10.0.0\",\n    \"@storybook/react\": \"^10.0.0\",\n    \"@storybook/react-vite\": \"^10.0.0\",\n    \"@swc/core\": \"^1.4.2\",\n    \"@swc/jest\": \"^0.2.36\",\n    \"@testing-library/dom\": \"^10.4.1\",\n    \"@testing-library/jest-dom\": \"^6.6.3\",\n    \"@testing-library/react\": \"^16.2.0\",\n    \"@types/identity-obj-proxy\": \"^3\",\n    \"@types/react\": \"^19.0.8\",\n    \"@types/react-dom\": \"^19.0.3\",\n    \"@typescript-eslint/eslint-plugin\": \"^6.21.0\",\n    \"@typescript-eslint/parser\": \"^6.21.0\",\n    \"@vitejs/plugin-react\": \"^4.2.1\",\n    \"@vitest/browser\": \"4.0.4\",\n    \"@vitest/browser-playwright\": \"4.0.4\",\n    \"@vitest/coverage-v8\": \"4.0.4\",\n    \"@vitest/ui\": \"4.0.4\",\n    \"cypress\": \"^13.6.4\",\n    \"eslint\": \"^8.56.0\",\n    \"eslint-plugin-react-hooks\": \"^4.6.0\",\n    \"eslint-plugin-react-refresh\": \"^0.4.5\",\n    \"eslint-plugin-storybook\": \"^0.11.4\",\n    \"identity-obj-proxy\": \"^3.0.0\",\n    \"jest\": \"^29.7.0\",\n    \"jest-environment-jsdom\": \"^29.7.0\",\n    \"storybook\": \"^10.0.0\",\n    \"typescript\": \"^5.8.3\",\n    \"vite\": \"^7\",\n    \"vitest\": \"4.0.4\"\n  },\n  \"nx\": {\n    \"includedScripts\": []\n  }\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/playwright/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"UTF-8\" />\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n  <title>Testing Page</title>\n</head>\n\n<body>\n  <div id=\"root\"></div>\n  <script type=\"module\" src=\"./index.ts\"></script>\n</body>\n\n</html>"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/playwright/index.ts",
    "content": "import { setProjectAnnotations } from \"@storybook/react-vite\";\nimport sbAnnotations from \"../.storybook/preview\";\n\nsetProjectAnnotations([sbAnnotations]);\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/playwright-ct.config.ts",
    "content": "import { defineConfig, devices } from '@playwright/experimental-ct-react';\n\n/**\n * See https://playwright.dev/docs/test-configuration.\n */\nexport default defineConfig({\n  testDir: 'stories',\n  testMatch: '*.playwright.tsx',\n  /* The base directory, relative to the config file, for snapshot files created with toMatchSnapshot and toHaveScreenshot. */\n  snapshotDir: './__snapshots__',\n  outputDir: './test-results',\n  /* Maximum time one test can run for. */\n  timeout: 10 * 1000,\n  /* Run tests in files in parallel */\n  fullyParallel: true,\n  /* Fail the build on CI if you accidentally left test.only in the source code. */\n  forbidOnly: !!process.env.CI,\n  /* Retry on CI only */\n  retries: process.env.CI ? 2 : 0,\n  /* Opt out of parallel tests on CI. */\n  workers: process.env.CI ? 1 : undefined,\n  /* Reporter to use. See https://playwright.dev/docs/test-reporters */\n  reporter: 'line',\n  /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */\n  use: {\n    /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */\n    trace: 'on-first-retry',\n\n    /* Port to use for Playwright component endpoint. */\n    ctPort: 3100,\n  },\n\n  /* Configure projects for major browsers */\n  projects: [\n    {\n      name: 'chromium',\n      use: { ...devices['Desktop Chrome'] },\n    },\n    // {\n    //   name: 'firefox',\n    //   use: { ...devices['Desktop Firefox'] },\n    // },\n    // {\n    //   name: 'webkit',\n    //   use: { ...devices['Desktop Safari'] },\n    // },\n  ],\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/playwright-e2e.config.ts",
    "content": "import { defineConfig, devices } from \"@playwright/test\";\nimport path from \"node:path\";\n\n/**\n * See https://playwright.dev/docs/test-configuration.\n */\nexport default defineConfig({\n  testDir: \"./e2e-tests\",\n  outputDir: \"./test-results\",\n  /* Maximum time one test can run for. */\n  timeout: (process.env.CI ? 60 : 30) * 1000,\n  /* Run tests in files in parallel */\n  fullyParallel: false,\n\n  /* Fail the build on CI if you accidentally left test.only in the source code. */\n  forbidOnly: !!process.env.CI,\n  retries: 0,\n  /* Run tests serially to avoid side effects */\n  workers: 1,\n  /* Reporter to use. See https://playwright.dev/docs/test-reporters */\n  reporter: [\n    [\"line\"],\n    [\n      \"junit\",\n      {\n        embedAnnotationsAsProperties: true,\n        outputFile: path.join(__dirname, \"..\", \"..\", \"..\", \"test-results\", \"react-e2e-ui.xml\"),\n      },\n    ],\n  ],\n  /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */\n  use: {\n    /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */\n    trace: \"retain-on-failure\",\n    // video: \"retain-on-failure\",\n    // headless: false,\n  },\n\n  /* Configure projects for major browsers */\n  projects: [\n    {\n      name: \"chromium\",\n      use: { ...devices[\"Desktop Chrome\"] },\n    },\n    // {\n    //   name: 'firefox',\n    //   use: { ...devices['Desktop Firefox'] },\n    // },\n    // {\n    //   name: 'webkit',\n    //   use: { ...devices['Desktop Safari'] },\n    // },\n  ],\n\n  webServer: {\n    command: \"yarn storybook\",\n    url: \"http://127.0.0.1:6006\",\n    reuseExistingServer: true,\n  },\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/pre-e2e.js",
    "content": "/* eslint-disable no-undef */\n/* eslint-disable @typescript-eslint/no-var-requires */\nconst fs = require(\"node:fs\");\nconst path = require(\"node:path\");\n\nconst testStoryPath = path.resolve(\"stories/AddonTest.stories.tsx\");\n\nconsole.log(`Pre-e2e script: clearing ${testStoryPath}`);\nconst storyContent = fs.readFileSync(testStoryPath).toString();\nfs.writeFileSync(testStoryPath, storyContent.replace(\"forceFailure: true\", \"forceFailure: false\"));"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/project.json",
    "content": "{\n  \"name\": \"portable-stories-kitchen-sink/react\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"application\",\n  \"targets\": {\n    \"jest\": {},\n    \"vitest\": {},\n    \"cypress\": {},\n    \"e2e-ui\": {}\n  },\n  \"tags\": [\"ci:normal\", \"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/stories/AddonTest.stories.tsx",
    "content": "import { expect, within } from 'storybook/test';\nimport { Meta, type StoryObj } from '@storybook/react-vite';\nimport { instrument } from 'storybook/internal/instrumenter';\nimport { Component } from './AddonTest';\n\ndeclare global {\n  // eslint-disable-next-line no-var\n  var __vitest_browser__: boolean;\n}\n\nconst meta = {\n  title: 'Addons/Group/Test',\n  component: Component,\n} as Meta<typeof Component>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nconst { pass } = instrument({\n  pass: async () => {},\n}, { intercept: true })\n\nexport const ExpectedFailure: Story = {\n  args: {\n    forceFailure: false,\n  },\n  play: async ({ args }) => {\n    await pass();\n    if(args.forceFailure) {\n      throw new Error('Expected failure');\n    }\n  }\n};\n\nexport const ExpectedSuccess: Story = {\n  play: async () => {\n    await pass();\n  }\n};\n\nexport const ExpectedContent: Story = {\n  play: async ({ canvasElement }) => {\n    const button = within(canvasElement).getByRole('button');\n    await expect(button).toHaveTextContent('test');\n    const decoratorString = within(canvasElement).getByTestId('decorator-string');\n    await expect(decoratorString).toHaveTextContent('Global Decorator');\n  }\n};\n\nexport const LongRunning: Story = {\n  loaders: [async () => new Promise((resolve) => setTimeout(resolve, 800))],\n};\n\n// Tests will pass in browser, but fail in CLI\nexport const MismatchFailure: Story = {\n  play: async () => {\n    await pass();\n    if(!globalThis.__vitest_browser__) {\n      throw new Error('Expected failure');\n    }\n  }\n};\n\n// Tests will fail in browser, but pass in CLI\nexport const MismatchSuccess: Story = {\n  play: async () => {\n    await pass();\n    if(globalThis.__vitest_browser__) {\n      throw new Error('Unexpected success');\n    }\n  },\n  tags: ['fail-on-purpose'],\n};\n\nexport const PreviewHeadTest: Story = {\n  play: async () => {\n    const styles = window.getComputedStyle(document.body);\n    // set in preview-head.html\n    expect(styles.backgroundColor).toBe('rgb(250, 250, 210)');\n    // set in main.js#previewHead\n    expect(styles.borderColor).toBe('rgb(255, 0, 0)');\n  }\n};\n\nexport const StaticDirTest: Story = {\n  play: async () => {\n    const path = '/test-static-dirs/static.js';\n    const { staticFunction } = await import(/* @vite-ignore */path);\n    expect(staticFunction()).toBe(true);\n  }\n}\n\nexport const ViteFinalTest: Story = {\n  play: async () => {\n    // @ts-expect-error TS doesn't know about the alias\n    const { aliasedFunction } = await import('test-alias');\n    expect(aliasedFunction()).toBe(true);\n  }\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/stories/AddonTest.tsx",
    "content": "import { getButtonString } from './get-button-string';\n\nexport const Component = () => {\n  return <button>{getButtonString()}</button>;\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/stories/Button.cy.tsx",
    "content": "/// <reference types=\"cypress\" />\nimport * as stories from './Button.stories';\nimport { composeStories } from '@storybook/react-vite';\n\nconst { CSF3Primary, WithLoader } = composeStories(stories);\n\ndescribe('<Button />', () => {\n  it('renders with loaders and play function', () => {\n    cy.then(async () => {\n      await WithLoader.load();\n    });\n\n    cy.mount(<WithLoader />);\n\n    cy.then(async () => {\n      cy.get('[data-testid=\"loaded-data\"]').should('contain.text', 'loaded data');\n      cy.get('[data-testid=\"mock-data\"]').should('contain.text', 'mockFn return value');\n    });\n  });\n\n  it('renders primary button', async () => {\n    cy.mount(<CSF3Primary />);\n    cy.get('[data-decorator]').should('exist');\n  });\n\n  it('renders primary button with custom args', async () => {\n    cy.mount(<CSF3Primary>bar</CSF3Primary>);\n    cy.get('button').should('contain.text', 'bar');\n  });\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/stories/Button.playwright.tsx",
    "content": " \nimport { createTest } from '@storybook/react/experimental-playwright';\nimport { test as base, expect } from '@playwright/experimental-ct-react';\nimport stories, { SingleComposedStory, WithSpanishGlobal } from './Button.stories.playwright';\n\nconst test = createTest(base);\n\ntest('renders with composeStories (plural)', async ({ mount }) => {\n  const component = await mount(<stories.CSF3Primary />);\n  await expect(component).toContainText('Global Decorator');\n  await expect(component).toContainText('foo'); // default arg for the story\n});\n\ntest('renders with composeStory (singular)', async ({ mount }) => {\n  const component = await mount(<SingleComposedStory />);\n  await expect(component).toContainText('Global Decorator');\n  await expect(component).toContainText('foo'); // default arg for the story\n});\n\ntest('renders story with props', async ({ mount }) => {\n  let called = false\n  const component = await mount(\n    <stories.CSF3Button primary={true} onClick={() => { called = true }}>child from test</stories.CSF3Button>\n  );\n  await expect(component).toContainText('child from test');\n  await expect(component.getByRole('button')).toHaveClass(/storybook-button--primary/);\n  await component.getByRole('button').click()\n  await expect(called).toBe(true)\n});\n\ntest('renders story with custom render', async ({ mount }) => {\n  const component = await mount(<stories.CSF3ButtonWithRender />);\n  await expect(component.getByTestId('custom-render')).toContainText(\n    'I am a custom render function'\n  );\n  await expect(component.getByRole('button')).toHaveText('foo');\n});\n\ntest('renders story with global annotations', async ({ mount }) => {\n  const component = await mount(<WithSpanishGlobal />);\n  await expect(component).toContainText('Hola!');\n});\n\ntest('calls loaders', async ({ mount }) => {\n  const component = await mount(<stories.WithLoader />);\n  await expect(component.getByTestId('loaded-data')).toContainText('loaded data');\n  await expect(component.getByTestId('mock-data')).toContainText('mockFn return value');\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/stories/Button.stories.playwright.ts",
    "content": "import { composeStories, composeStory } from \"@storybook/react-vite\";\nimport * as stories from \"./Button.stories\";\n\nexport default composeStories(stories);\n\nexport const SingleComposedStory = composeStory(\n  stories.CSF3Primary,\n  stories.default\n);\n\nexport const WithSpanishGlobal = composeStory(\n  stories.CSF2StoryWithLocale,\n  stories.default,\n  { initialGlobals: { locale: \"es\" } }\n);\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/stories/Button.stories.tsx",
    "content": "import { expect, fn } from 'storybook/test';\nimport type { Meta, StoryFn as CSF2Story, StoryObj as CSF3Story } from '@storybook/react-vite';\n\nimport type { ButtonProps } from './Button';\nimport { Button } from './Button';\n\nconst meta = {\n  title: 'Example/Button',\n  component: Button,\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n\nconst Template: CSF2Story<ButtonProps> = (args) => <Button {...args} />;\n\nexport const CSF2Secondary = Template.bind({});\nCSF2Secondary.args = {\n  children: 'Children coming from story args!',\n  primary: false,\n};\n\nconst getCaptionForLocale = (locale: string) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'pt':\n      return 'Olá!';\n    case 'en':\n      return 'Hello!';\n    default:\n      return undefined;\n  }\n};\n\nexport const CSF2StoryWithLocale: CSF2Story = (args, { globals: { locale } }) => {\n  const caption = getCaptionForLocale(locale);\n  return (\n    <>\n      <p>locale: {locale}</p>\n      <Button>{caption}</Button>\n    </>\n  );\n};\nCSF2StoryWithLocale.storyName = 'WithLocale';\n\nexport const CSF2StoryWithParamsAndDecorator: CSF2Story<ButtonProps> = (args) => {\n  return <Button {...args} />;\n};\nCSF2StoryWithParamsAndDecorator.args = {\n  children: 'foo',\n};\nCSF2StoryWithParamsAndDecorator.parameters = {\n  layout: 'centered',\n};\nCSF2StoryWithParamsAndDecorator.decorators = [(StoryFn) => <StoryFn />];\n\nexport const CSF3Primary: CSF3Story<ButtonProps> = {\n  args: {\n    children: \"foo\",\n    size: 'large',\n    primary: true,\n  },\n  // Accessibility is failing for the Button\n  tags: ['fail-on-purpose'],\n};\n\nexport const CSF3Button: CSF3Story<ButtonProps> = {\n  args: { children: 'foo' },\n};\n\nexport const CSF3ButtonWithRender: CSF3Story<ButtonProps> = {\n  ...CSF3Button,\n  render: (args) => (\n    <div>\n      <p data-testid=\"custom-render\">I am a custom render function</p>\n      <Button {...args} />\n    </div>\n  ),\n};\n\nconst mockFn = fn();\nexport const WithLoader: CSF3Story<{ mockFn: (val: string) => string }> = {\n  args: {\n    mockFn,\n  },\n  loaders: [\n    async () => {\n      mockFn.mockReturnValueOnce('mockFn return value');\n      return {\n        value: 'loaded data',\n      };\n    },\n  ],\n  render: (args, { loaded }) => {\n    const data = args.mockFn('render');\n    return (\n      <div>\n        <div data-testid=\"loaded-data\">{loaded.value}</div>\n        <div data-testid=\"mock-data\">{String(data)}</div>\n      </div>\n    );\n  },\n  play: async () => {\n    expect(mockFn).toHaveBeenCalledWith('render');\n  },\n};"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/stories/Button.test.tsx",
    "content": "import { render, screen, cleanup } from '@testing-library/react';\nimport { addons } from 'storybook/preview-api';\n\nimport { setProjectAnnotations, composeStories, composeStory } from '@storybook/react-vite';\nimport * as stories from './Button.stories';\n\nafterEach(() => {\n  cleanup();\n});\n\n// example with composeStories, returns an object with all stories composed with args/decorators\nconst { CSF3Primary } = composeStories(stories);\n\n// // example with composeStory, returns a single story composed with args/decorators\nconst Secondary = composeStory(stories.CSF2Secondary, stories.default);\ndescribe('renders', () => {\n  it('renders primary button', () => {\n    render(<CSF3Primary>Hello world</CSF3Primary>);\n    const buttonElement = screen.getByText(/Hello world/i);\n    expect(buttonElement).not.toBeNull();\n  });\n\n  it('reuses args from composed story', () => {\n    render(<Secondary />);\n    const buttonElement = screen.getByRole('button');\n    expect(buttonElement.textContent).toEqual(Secondary.args.children);\n  });\n\n  it('onclick handler is called', async () => {\n    let count = 0;\n    // we don't use an actual spy so we can use this test between Jest and Vitest\n    const onClickSpy = () => {\n      count = count + 1;\n    };\n    render(<Secondary onClick={onClickSpy} />);\n    const buttonElement = screen.getByRole('button');\n    buttonElement.click();\n    expect(count).toEqual(1);\n  });\n\n  it('reuses args from composeStories', () => {\n    const { getByText } = render(<CSF3Primary />);\n    const buttonElement = getByText(/foo/i);\n    expect(buttonElement).not.toBeNull();\n  });\n});\n\ndescribe('projectAnnotations', () => {\n  it('renders with default projectAnnotations', () => {\n    const WithEnglishText = composeStory(stories.CSF2StoryWithLocale, stories.default);\n    const { getByText } = render(<WithEnglishText />);\n    const buttonElement = getByText('Hello!');\n    expect(buttonElement).not.toBeNull();\n  });\n\n  it('renders with custom projectAnnotations via composeStory params', () => {\n    const WithPortugueseText = composeStory(stories.CSF2StoryWithLocale, stories.default, {\n      initialGlobals: { locale: 'pt' },\n    });\n    const { getByText } = render(<WithPortugueseText />);\n    const buttonElement = getByText('Olá!');\n    expect(buttonElement).not.toBeNull();\n  });\n\n  it('renders with custom projectAnnotations via setProjectAnnotations', () => {\n    setProjectAnnotations([{ parameters: { injected: true } }]);\n    const Story = composeStory(stories.CSF2StoryWithLocale, stories.default);\n    expect(Story.parameters?.injected).toBe(true);\n  });\n});\n\ndescribe('CSF3', () => {\n  afterEach(() => {\n    cleanup();\n  });\n\n  it('renders with inferred globalRender', () => {\n    const Primary = composeStory(stories.CSF3Button, stories.default);\n\n    render(<Primary>Hello world</Primary>);\n    const buttonElement = screen.getByText(/Hello world/i);\n    expect(buttonElement).not.toBeNull();\n  });\n\n  it('renders with custom render function', () => {\n    const Primary = composeStory(stories.CSF3ButtonWithRender, stories.default);\n\n    render(<Primary />);\n    expect(screen.getByTestId('custom-render')).not.toBeNull();\n  });\n});\n\n// common in addons that need to communicate between manager and preview\nit('should pass with decorators that need addons channel', () => {\n  const PrimaryWithChannels = composeStory(stories.CSF3Primary, stories.default, {\n    decorators: [\n      (StoryFn) => {\n        addons.getChannel();\n        return StoryFn();\n      },\n    ],\n  });\n  render(<PrimaryWithChannels>Hello world</PrimaryWithChannels>);\n  const buttonElement = screen.getByText(/Hello world/i);\n  expect(buttonElement).not.toBeNull();\n});\n\n// Batch snapshot testing\nconst testCases = Object.values(composeStories(stories)).map((Story) => [Story.storyName, Story]);\nit.each(testCases)('Renders %s story', async (_storyName, Story) => {\n  await Story.run();\n  expect(document.body).toMatchSnapshot();\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/stories/Button.tsx",
    "content": "import React from 'react';\nimport './button.css';\n\nexport interface ButtonProps {\n  /**\n   * Is this the principal call to action on the page?\n   */\n  primary?: boolean;\n  /**\n   * What background color to use\n   */\n  backgroundColor?: string;\n  /**\n   * How large should the button be?\n   */\n  size?: 'small' | 'medium' | 'large';\n  /**\n   * Button contents\n   */\n  children: React.ReactNode;\n  /**\n   * Optional click handler\n   */\n  onClick?: () => void;\n}\n\n/**\n * Primary UI component for user interaction\n */\nexport const Button: React.FC<ButtonProps> = (props) => {\n  const { primary = false, size = 'medium', backgroundColor, children, ...otherProps } = props;\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n  console.log({props})\n  return (\n    <button\n      type=\"button\"\n      className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n      style={{ backgroundColor }}\n      {...otherProps}\n    >\n      {children}\n    </button>\n  );\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/stories/MyButton.stories.tsx",
    "content": "import type { Meta, StoryObj as CSF3Story } from '@storybook/react-vite';\n\nimport type { ButtonProps } from './Button';\nimport { Button } from './Button';\n\nconst meta = {\n  title: 'Example/MyButton',\n  component: Button,\n  tags: ['!test'],\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n\nexport const Primary: CSF3Story<ButtonProps> = {\n  args: { children: 'foo' },\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/stories/OtherComponent.stories.tsx",
    "content": "import { Meta, type StoryObj } from '@storybook/react-vite';\n\nconst Component = () => <button>test</button>\n\nconst meta = {\n  title: 'Addons/Group/Other',\n  component: Component,\n} as Meta<typeof Component>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Passes: Story = {\n};\n\nexport const Fails: Story = {\n  play: async () => {\n    throw new Error('Expected failure');\n  },\n  tags: ['fail-on-purpose'],\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/stories/UnhandledErrors.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nasync function unhandledRejection() {\n  throwError('I THREW AN UNHANDLED REJECTION!');\n}\n\nfunction unhandledError() {\n  throwError('I THREW AN UNHANDLED ERROR!');\n}\n\nfunction throwError(message: string) {\n  throw new Error(message);\n}\nconst meta = {\n  title: 'Example/UnhandledErrors',\n  args: {\n    errorType: null,\n    forceFailure: false,\n  },\n  component: ({ errorType, forceFailure }) => {\n    if (forceFailure) {\n      if (errorType === 'rejection') {\n        setTimeout(unhandledRejection, 0);\n      } else if (errorType === 'error') {\n        setTimeout(unhandledError, 0);\n      }\n    }\n    return 'Hello world';\n  },\n} as Meta<{ errorType: 'rejection' | 'error' | null; forceFailure?: boolean }>;\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const UnhandledError: Story = {\n  args: {\n    errorType: 'error',\n  },\n};\n\nexport const UnhandledRejection: Story = {\n  args: {\n    errorType: 'rejection',\n  },\n};\n\nexport const Success: Story = {};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/stories/__snapshots__/Button.test.tsx.snap",
    "content": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`Renders CSF2Secondary story 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      <div\n        data-testid=\"decorator-string\"\n      >\n        Global Decorator\n      </div>\n      <br />\n      <button\n        class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n        type=\"button\"\n      >\n        Children coming from story args!\n      </button>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`Renders CSF2StoryWithLocale story 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      <div\n        data-testid=\"decorator-string\"\n      >\n        Global Decorator\n      </div>\n      <br />\n      <p>\n        locale: \n        en\n      </p>\n      <button\n        class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n        type=\"button\"\n      >\n        Hello!\n      </button>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`Renders CSF2StoryWithParamsAndDecorator story 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      <div\n        data-testid=\"decorator-string\"\n      >\n        Global Decorator\n      </div>\n      <br />\n      <button\n        class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n        type=\"button\"\n      >\n        foo\n      </button>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`Renders CSF3Button story 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      <div\n        data-testid=\"decorator-string\"\n      >\n        Global Decorator\n      </div>\n      <br />\n      <button\n        class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n        type=\"button\"\n      >\n        foo\n      </button>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`Renders CSF3ButtonWithRender story 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      <div\n        data-testid=\"decorator-string\"\n      >\n        Global Decorator\n      </div>\n      <br />\n      <div>\n        <p\n          data-testid=\"custom-render\"\n        >\n          I am a custom render function\n        </p>\n        <button\n          class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n          type=\"button\"\n        >\n          foo\n        </button>\n      </div>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`Renders CSF3Primary story 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      <div\n        data-testid=\"decorator-string\"\n      >\n        Global Decorator\n      </div>\n      <br />\n      <button\n        class=\"storybook-button storybook-button--large storybook-button--primary\"\n        type=\"button\"\n      >\n        foo\n      </button>\n    </div>\n  </div>\n</body>\n`;\n\nexports[`Renders WithLoader story 1`] = `\n<body>\n  <div>\n    <div\n      data-testid=\"global-decorator\"\n    >\n      <div\n        data-testid=\"decorator-string\"\n      >\n        Global Decorator\n      </div>\n      <br />\n      <div>\n        <div\n          data-testid=\"loaded-data\"\n        >\n          loaded data\n        </div>\n        <div\n          data-testid=\"mock-data\"\n        >\n          mockFn return value\n        </div>\n      </div>\n    </div>\n  </div>\n</body>\n`;\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/stories/button.css",
    "content": ".storybook-button {\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n  font-weight: 700;\n  border: 0;\n  border-radius: 3em;\n  cursor: pointer;\n  display: inline-block;\n  line-height: 1;\n}\n.storybook-button--primary {\n  color: white;\n  background-color: #1ea7fd;\n}\n.storybook-button--secondary {\n  color: #333;\n  background-color: transparent;\n  box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;\n}\n.storybook-button--small {\n  font-size: 12px;\n  padding: 10px 16px;\n}\n.storybook-button--medium {\n  font-size: 14px;\n  padding: 11px 20px;\n}\n.storybook-button--large {\n  font-size: 16px;\n  padding: 12px 24px;\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/stories/get-button-string.ts",
    "content": "export const getButtonString = () => {\n  return \"test\";\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n    \"module\": \"ESNext\",\n    \"skipLibCheck\": true,\n\n    /* Bundler mode */\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\",\n\n    /* Linting */\n    \"strict\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"noFallthroughCasesInSwitch\": true\n  },\n  \"include\": [\"stories\", \"playwright\", \"e2e-tests\", \"cypress\"],\n  \"references\": [{ \"path\": \"./tsconfig.node.json\" }]\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/tsconfig.node.json",
    "content": "{\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"skipLibCheck\": true,\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"allowSyntheticDefaultImports\": true,\n    \"strict\": true\n  },\n  \"include\": [\"vite.config.ts\"]\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react/vite.config.mts",
    "content": "import { defineConfig } from \"vitest/config\";\nimport react from \"@vitejs/plugin-react\";\nimport { storybookTest } from \"@storybook/addon-vitest/vitest-plugin\";\nimport { playwright } from \"@vitest/browser-playwright\";\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [\n    react(),\n    storybookTest(\n      process.env.SKIP_FAIL_ON_PURPOSE\n        ? {\n            tags: {\n              exclude: [\"fail-on-purpose\"],\n            },\n          }\n        : undefined\n    ),\n  ],\n  test: {\n    name: \"storybook\",\n    pool: \"threads\",\n    deps: {\n      optimizer: {\n        web: {\n          enabled: false,\n        },\n      },\n    },\n    browser: {\n      enabled: true,\n      provider: playwright({}),\n      headless: true,\n      instances: [\n        {\n          browser: \"chromium\",\n        },\n      ],\n    },\n    setupFiles: [\"./.storybook/vitest.setup.ts\"],\n    environment: \"jsdom\",\n  },\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.eslintrc.cjs",
    "content": "module.exports = {\n  root: true,\n  env: { browser: true, es2020: true },\n  extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:react-hooks/recommended', 'plugin:storybook/recommended'],\n  ignorePatterns: ['dist', '.eslintrc.cjs'],\n  parser: '@typescript-eslint/parser',\n  plugins: ['react-refresh'],\n  rules: {\n    'react-refresh/only-export-components': [\n      'warn',\n      { allowConstantExport: true },\n    ],\n  },\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndist-ssr\n*.local\n\n# Editor directories and files\n.vscode/*\n!.vscode/extensions.json\n.idea\n.DS_Store\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n/test-results/\n/playwright-report/\n/blob-report/\n/playwright/.cache/\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/aliased.ts",
    "content": "// This file is used to test that viteFinal is correctly loaded in Vitest\n// main.ts defines this file as a resolve alias, which is used in the ViteFinalTest story\n\nexport const aliasedFunction = () => true;\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/get-decorator-string.ts",
    "content": "export const getDecoratorString = () => {\n  return \"Global Decorator\";\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/main.ts",
    "content": "import { join } from \"node:path\";\n\nimport type { StorybookConfig } from \"@storybook/react-vite\";\n\nconst config: StorybookConfig = {\n  stories: [\"../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)\"],\n  addons: [\"@storybook/addon-vitest\", \"@storybook/addon-a11y\"],\n  framework: {\n    name: \"@storybook/react-vite\",\n    options: {},\n  },\n  core: {\n    disableWhatsNewNotifications: true,\n  },\n  previewHead: (head = \"\") => `${head}\n  <style>\n    body {\n      border: 1px solid red;\n    }\n  </style>`,\n  staticDirs: [{ from: \"./test-static-dirs\", to: \"test-static-dirs\" }],\n  viteFinal: (config) => {\n    return {\n      ...config,\n      optimizeDeps: {\n        ...config.optimizeDeps,\n        include: [...(config.optimizeDeps?.include || [])],\n      },\n      resolve: {\n        ...config.resolve,\n        alias: {\n          ...config.resolve?.alias,\n          \"test-alias\": join(import.meta.dirname, \"aliased.ts\"),\n        },\n      },\n    };\n  },\n  refs: {\n    \"storybook@8.0.0\": {\n      title: \"Storybook 8.0.0\",\n      url: \"https://635781f3500dd2c49e189caf-gckybvsekn.chromatic.com/\",\n    },\n    \"storybook@7.6.18\": {\n      title: \"Storybook 7.6.18\",\n      url: \"https://635781f3500dd2c49e189caf-oljwjdrftz.chromatic.com/\",\n    },\n  },\n};\n\nexport default config;\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/preview-head.html",
    "content": "<style>\n  body {\n    background-color: rgb(250, 250, 210);\n  }\n</style>\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/preview.tsx",
    "content": "import type { Preview } from '@storybook/react-vite';\nimport { getDecoratorString } from './get-decorator-string';\n\nconsole.log('preview file is called!');\n\nconst preview: Preview = {\n  decorators: [\n    (StoryFn) => (\n      <div data-testid=\"global-decorator\">\n        <div data-testid=\"decorator-string\">{getDecoratorString()}</div>\n        <br />\n        <StoryFn />\n      </div>\n    ),\n  ],\n  initialGlobals: {\n    locale: 'en',\n  },\n  globalTypes: {\n    locale: {\n      description: 'Locale for components',\n      toolbar: {\n        title: 'Locale',\n        icon: 'circlehollow',\n        items: ['es', 'en'],\n      },\n    },\n  },\n};\n\nexport default preview;\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/setup-file-dependency.ts",
    "content": "export const getString = () => {\n  return \"initial string\";\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/test-static-dirs/static.js",
    "content": "// This file is used to test that staticDirs are correctly loaded in Vitest\n\nexport const staticFunction = () => true;\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.storybook/vitest.setup.ts",
    "content": "import { getString } from './setup-file-dependency';\n\nconsole.log(getString());\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.yarnrc",
    "content": ""
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/.yarnrc.yml",
    "content": "yarnPath: ../../../.yarn/releases/yarn-4.10.3.cjs\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/component-testing.spec.ts",
    "content": "import { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\n\nimport { expect, test } from \"@playwright/test\";\n\nimport { SbPage } from \"../../../../code/e2e-tests/util\";\n\nconst STORYBOOK_URL = \"http://localhost:6006\";\nconst TEST_STORY_PATH = path.resolve(\n  __dirname,\n  \"..\",\n  \"stories\",\n  \"AddonTest.stories.tsx\"\n);\nconst UNHANDLED_ERRORS_STORY_PATH = path.resolve(\n  __dirname,\n  \"..\",\n  \"stories\",\n  \"UnhandledErrors.stories.tsx\"\n);\nconst ADDON_TEST_DEPENDENCY_PATH = path.resolve(\n  __dirname,\n  \"..\",\n  \"stories\",\n  \"get-button-string.ts\"\n);\nconst PREVIEW_DEPENDENCY_PATH = path.resolve(\n  __dirname,\n  \"..\",\n  \".storybook\",\n  \"get-decorator-string.ts\"\n);\nconst SETUP_FILE_DEPENDENCY_PATH = path.resolve(\n  __dirname,\n  \"..\",\n  \".storybook\",\n  \"setup-file-dependency.ts\"\n);\n\nconst setForceFailureFlag = (content: string, value: boolean) =>\n  content.replace(/forceFailure:\\s*(true|false)/, `forceFailure: ${value}`);\n\nconst modifiedFiles = new Map<string, string>();\n\nconst modifyFile = async (\n  filePath: string,\n  modify: (content: string) => string\n) => {\n  const content = (await fs.readFile(filePath)).toString();\n  const modifiedContent = modify(content);\n  await fs.writeFile(filePath, modifiedContent);\n  if (!modifiedFiles.has(filePath)) {\n    modifiedFiles.set(filePath, content);\n  }\n\n  // the file change causes a HMR event, which causes a browser reload,and that can take a few seconds\n  await new Promise((resolve) => setTimeout(resolve, 2000));\n};\n\nconst restoreAllFiles = async () => {\n  for (const [filePath, originalContent] of modifiedFiles.entries()) {\n    await fs.writeFile(filePath, originalContent);\n  }\n  modifiedFiles.clear();\n  // the file change causes a HMR event, which causes a browser reload,and that can take a few seconds\n  await new Promise((resolve) => setTimeout(resolve, 2000));\n};\n\ntest.describe(\"component testing\", () => {\n  test.describe.configure({ mode: \"serial\" });\n  test.beforeEach(async ({ page }) => {\n    const sbPage = new SbPage(page, expect);\n\n    await page.goto(STORYBOOK_URL);\n    await page.evaluate(() => window.sessionStorage.clear());\n    await sbPage.waitUntilLoaded();\n\n    const expandTestingModule = page.getByLabel(\"Expand testing module\");\n    if (await expandTestingModule.isVisible()) {\n      await expandTestingModule.click();\n    }\n  });\n\n  test.afterEach(async ({ page }) => {\n    await page.click(\"body\");\n    try {\n      /** Sometimes the vitest instance fails, but the error-content is only shown in a modal.\n       * We click the link so the modal opens and we can close it.\n       * Having it open shortly is enough to have it be in the playwright trace, for debugging purposes.\n       */\n      const descriptionButton = page.locator(\"#testing-module-description button\");\n      if (\n        await descriptionButton.isVisible({ timeout: 4000 }).catch(() => false)\n      ) {\n        await descriptionButton.click({ timeout: 4000, force: true });\n\n        await page\n          .getByLabel(\"Close modal\")\n          .click({ timeout: 4000, force: true });\n      }\n    } catch {\n      // Ignore any errors when trying to open the modal\n    }\n\n    await restoreAllFiles();\n\n    const expandTestingModule = page.getByLabel(\"Expand testing module\");\n    if (await expandTestingModule.isVisible()) {\n      await expandTestingModule.click();\n    }\n\n    // Make sure any popover is closed\n    await page.click(\"body\");\n\n    // Ensure that all test results are removed and features are disabled, as previous tests might have enabled them\n    const clearStatusesButton = page.getByLabel(\"Clear all statuses\");\n    if (await clearStatusesButton.isVisible()) {\n      await clearStatusesButton.click();\n    }\n\n    const watchModeToggle = page.getByRole(\"switch\", { name: \"Watch mode\" });\n    if (\n      (await watchModeToggle.isVisible()) &&\n      (await watchModeToggle.getAttribute(\"aria-checked\")) === \"true\"\n    ) {\n      await watchModeToggle.click();\n    }\n\n    const configs = [\n      page.getByRole(\"checkbox\", { name: \"Coverage\" }),\n      page.getByRole(\"checkbox\", { name: \"Accessibility\" }),\n    ];\n    for (const config of configs) {\n      if (await config.isChecked()) {\n        await config.click();\n      }\n    }\n  });\n\n  test(\"should show discrepancy between test results\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n    const sbPage = new SbPage(page, expect);\n\n    await sbPage.navigateToStory(\"addons/group/test\", \"Mismatch Failure\");\n\n    // For whatever reason, sometimes it takes longer for the story to load\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"test\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    await sbPage.viewAddonPanel(\"Interactions\");\n\n    // For whatever reason, when visiting a story sometimes the story element is collapsed and that causes flake\n    const testStoryElement = await page.getByRole(\"button\", {\n      name: \"Test\",\n      exact: true,\n    });\n    if ((await testStoryElement.getAttribute(\"aria-expanded\")) !== \"true\") {\n      await testStoryElement.click();\n    }\n\n    const testingModuleDescription = await page.locator(\n      \"#testing-module-description\"\n    );\n\n    const runTestsButton = await page.getByLabel(\"Start test run\");\n    await runTestsButton.click();\n\n    // Wait for test results to appear\n    await expect(testingModuleDescription).toHaveText(/Ran \\d+ tests/, {\n      timeout: 60000,\n    });\n\n    const errorFilter = page.getByLabel(\n      /Filter main navigation to show \\d+ tests with errors/\n    );\n    await expect(errorFilter).toBeVisible();\n\n    // Assert discrepancy: CLI pass + Browser fail\n    const failingStoryElement = page.locator(\n      '[data-item-id=\"addons-group-test--mismatch-failure\"] [data-testid=\"tree-status-button\"]'\n    );\n    await expect(failingStoryElement).toHaveAttribute(\n      \"aria-label\",\n      \"Status: success\"\n    );\n    await expect(sbPage.panelContent()).toContainText(\n      /This interaction test passed in the CLI, but the tests failed in this browser/\n    );\n\n    // Assert discrepancy: CLI fail + Browser pass\n    await sbPage.navigateToStory(\"addons/group/test\", \"Mismatch Success\");\n    const successfulStoryElement = page.locator(\n      '[data-item-id=\"addons-group-test--mismatch-success\"] [data-testid=\"tree-status-button\"]'\n    );\n    await expect(successfulStoryElement).toHaveAttribute(\n      \"aria-label\",\n      \"Status: error\"\n    );\n    await expect(sbPage.panelContent()).toContainText(\n      /This interaction test passed in this browser, but the tests failed in the CLI/\n    );\n  });\n\n  test(\"should execute tests via testing module UI\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n    await modifyFile(TEST_STORY_PATH, (content) =>\n      setForceFailureFlag(content, true)\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"addons/group/test\", \"Expected Failure\");\n\n    // For whatever reason, sometimes it takes longer for the story to load\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"test\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    await expect(page.locator(\"#testing-module-title\")).toHaveText(\n      \"Run component tests\"\n    );\n\n    const runTestsButton = await page.getByLabel(\"Start test run\");\n    const watchModeButton = await page.getByRole(\"switch\", {\n      name: \"Watch mode\",\n    });\n    await expect(runTestsButton).not.toHaveAttribute(\"aria-disabled\", \"true\");\n    await expect(watchModeButton).not.toHaveAttribute(\"aria-disabled\", \"true\");\n\n    await runTestsButton.click();\n\n    // Wait for test results to appear\n    await expect(page.locator(\"#testing-module-description\")).toHaveText(\n      /Ran \\d+ tests/,\n      { timeout: 30000 }\n    );\n\n    await expect(runTestsButton).not.toHaveAttribute(\"aria-disabled\", \"true\");\n    await expect(watchModeButton).not.toHaveAttribute(\"aria-disabled\", \"true\");\n\n    const errorFilter = page.getByLabel(\n      /Filter main navigation to show \\d+ tests with errors/\n    );\n    await expect(errorFilter).toBeVisible();\n\n    // Assert for expected success\n    const successfulStoryElement = page.locator(\n      '[data-item-id=\"addons-group-test--expected-success\"] [data-testid=\"tree-status-button\"]'\n    );\n    await expect(successfulStoryElement).toHaveAttribute(\n      \"aria-label\",\n      \"Status: success\"\n    );\n\n    // Assert for expected failure\n    const failingStoryElement = page.locator(\n      '[data-item-id=\"addons-group-test--expected-failure\"] [data-testid=\"tree-status-button\"]'\n    );\n    await expect(failingStoryElement).toHaveAttribute(\n      \"aria-label\",\n      \"Status: error\"\n    );\n\n    // Assert that filter works as intended\n    await errorFilter.click();\n\n    const sidebarItems = page.locator(\n      '.sidebar-item[data-ref-id=\"storybook_internal\"][data-nodetype=\"component\"]'\n    );\n    await expect(sidebarItems).toHaveCount(2);\n  });\n\n  test(\"should run tests in watch mode when a story file is changed\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n    await modifyFile(TEST_STORY_PATH, (content) =>\n      setForceFailureFlag(content, false)\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"addons/group/test\", \"Expected Failure\");\n\n    // For whatever reason, sometimes it takes longer for the story to load\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"test\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    await page.getByRole(\"switch\", { name: \"Watch mode\" }).click();\n\n    // We shouldn't have to do an arbitrary wait, but because there is no UI for loading state yet, we have to\n    await page.waitForTimeout(8000);\n    await modifyFile(TEST_STORY_PATH, (content) =>\n      setForceFailureFlag(content, true)\n    );\n\n    // Wait for test results to appear\n    const errorFilter = page.getByLabel(\n      /Filter main navigation to show \\d+ tests with errors/\n    );\n    await expect(errorFilter).toBeVisible({ timeout: 30000 });\n\n    // Assert for expected success\n    const successfulStoryElement = page.locator(\n      '[data-item-id=\"addons-group-test--expected-success\"] [data-testid=\"tree-status-button\"]'\n    );\n    await expect(successfulStoryElement).toHaveAttribute(\n      \"aria-label\",\n      \"Status: success\"\n    );\n\n    // Assert for expected failure\n    const failingStoryElement = page.locator(\n      '[data-item-id=\"addons-group-test--expected-failure\"] [data-testid=\"tree-status-button\"]'\n    );\n    await expect(failingStoryElement).toHaveAttribute(\n      \"aria-label\",\n      \"Status: error\"\n    );\n\n    // Assert that filter works as intended\n    await errorFilter.click();\n\n    const sidebarItems = page.locator(\n      '.sidebar-item[data-ref-id=\"storybook_internal\"][data-nodetype=\"component\"]'\n    );\n    await expect(sidebarItems).toHaveCount(1);\n  });\n\n  test(\"should run tests in watch mode when a story file's dependency is changed\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"addons/group/test\", \"Expected Failure\");\n\n    // For whatever reason, sometimes it takes longer for the story to load\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"test\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    await page.getByRole(\"switch\", { name: \"Watch mode\" }).click();\n\n    // We shouldn't have to do an arbitrary wait, but because there is no UI for loading state yet, we have to\n    await page.waitForTimeout(3000);\n    await modifyFile(ADDON_TEST_DEPENDENCY_PATH, (content) =>\n      content.replace(\"test\", \"changed\")\n    );\n\n    // Expect less than 10 tests to have run\n    await expect(page.locator(\"#testing-module-description\")).toContainText(\n      /Ran \\d tests/,\n      { timeout: 30000 }\n    );\n\n    // Assert for expected failure\n    const failingStoryElement = page.locator(\n      '[data-item-id=\"addons-group-test--expected-content\"] [data-testid=\"tree-status-button\"]'\n    );\n    await expect(failingStoryElement).toHaveAttribute(\n      \"aria-label\",\n      \"Status: error\"\n    );\n  });\n\n  test(\"should run all tests in watch mode when the preview file's dependency is changed\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"addons/group/test\", \"Expected Failure\");\n\n    // For whatever reason, sometimes it takes longer for the story to load\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"test\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    await page.getByRole(\"switch\", { name: \"Watch mode\" }).click();\n\n    // We shouldn't have to do an arbitrary wait, but because there is no UI for loading state yet, we have to\n    await page.waitForTimeout(3000);\n    await modifyFile(PREVIEW_DEPENDENCY_PATH, (content) =>\n      content.replace(\"Global Decorator\", \"Changed Decorator\")\n    );\n\n    // Expect at least 20 tests to have run\n    await expect(page.locator(\"#testing-module-description\")).toContainText(\n      /Ran [2-9]\\d tests/,\n      { timeout: 30000 }\n    );\n\n    // Assert for expected failure\n    const failingStoryElement = page.locator(\n      '[data-item-id=\"addons-group-test--expected-content\"] [data-testid=\"tree-status-button\"]'\n    );\n\n    await expect(failingStoryElement).toHaveAttribute(\n      \"aria-label\",\n      \"Status: error\"\n    );\n  });\n\n  test(\"should run all tests in watch mode when the setup file's dependency is changed\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"addons/group/test\", \"Expected Failure\");\n\n    // For whatever reason, sometimes it takes longer for the story to load\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"test\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    await page.getByRole(\"switch\", { name: \"Watch mode\" }).click();\n\n    // We shouldn't have to do an arbitrary wait, but because there is no UI for loading state yet, we have to\n    await page.waitForTimeout(3000);\n    await modifyFile(SETUP_FILE_DEPENDENCY_PATH, (content) =>\n      content.replace(\"initial string\", \"changed string\")\n    );\n\n    // Expect at least 20 tests to have run\n    await expect(page.locator(\"#testing-module-description\")).toContainText(\n      /Ran [2-9]\\d tests/,\n      { timeout: 30000 }\n    );\n  });\n\n  test(\"should collect coverage to testing module and HTML report\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n    // Arrange - Prepare Storybook\n    await modifyFile(TEST_STORY_PATH, (content) =>\n      setForceFailureFlag(content, false)\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"addons/group/test\", \"Expected Failure\");\n\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"test\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    // Assert - No coverage report initially\n    await expect(page.getByLabel(\"Open coverage report\")).toHaveCount(0);\n\n    // Act - Enable coverage and run tests\n    await page.getByLabel(\"Coverage\", { exact: true }).click();\n    // Wait for Vitest to have (re)started\n    await page.waitForTimeout(2000);\n\n    await page.getByLabel(\"Start test run\").click();\n\n    // Assert - Coverage report is collected and shown\n    await expect(page.getByLabel(\"Open coverage report\")).toBeVisible({\n      timeout: 30000,\n    });\n    const sbPercentageText = await page\n      .getByLabel(/% coverage\\)$/)\n      .textContent();\n    expect(sbPercentageText).toMatch(/^\\d+%$/);\n    const sbPercentage = Number.parseInt(\n      sbPercentageText!.replace(\"%\", \"\") ?? \"\"\n    );\n    expect(sbPercentage).toBeGreaterThanOrEqual(0);\n    expect(sbPercentage).toBeLessThanOrEqual(100);\n\n    // Act - Open HTML coverage report\n    const coverageReportLink = await page.getByLabel(\"Open coverage report\");\n    // Remove target=\"_blank\" attribute to open in the same tab\n    await coverageReportLink.evaluate((elem) => elem.removeAttribute(\"target\"));\n    await page.getByLabel(\"Open coverage report\").click();\n\n    // Assert - HTML coverage report is accessible and reports the same coverage percentage as Storybook\n    const htmlPercentageText =\n      (await page\n        .locator('span:has(+ :text(\"Statements\"))')\n        .first()\n        .textContent()) ?? \"\";\n    const htmlPercentage = Number.parseFloat(\n      htmlPercentageText.replace(\"% \", \"\")\n    );\n    expect(Math.round(htmlPercentage)).toBe(sbPercentage);\n\n    await page.goBack();\n  });\n\n  test(\"should run focused test for a single story\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n    // Arrange - Prepare Storybook\n    await modifyFile(TEST_STORY_PATH, (content) =>\n      setForceFailureFlag(content, false)\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"addons/group/test\", \"Expected Failure\");\n\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"test\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    // Act - Open sidebar context menu, start focused test then close menu\n    await page\n      .locator('[data-item-id=\"addons-group-test--expected-failure\"]')\n      .hover();\n    await page\n      .locator(\n        '[data-item-id=\"addons-group-test--expected-failure\"] button[data-testid=\"context-menu\"]'\n      )\n      .click();\n    const sidebarContextMenu = page.getByRole(\"dialog\");\n    await sidebarContextMenu.getByLabel(\"Start test run\").click();\n\n    // Assert - Only one test is running and reported\n    await expect(\n      sidebarContextMenu.locator(\"#testing-module-description\")\n    ).toContainText(\"Ran 1 test\", { timeout: 30000 });\n    await expect(\n      sidebarContextMenu.getByLabel(\"Component tests passed\")\n    ).toHaveCount(1);\n    await page.click(\"body\");\n    await expect(\n      page.locator(\n        '#storybook-explorer-menu [data-testid=\"tree-status-button\"][aria-label=\"Status: success\"]'\n      )\n    ).toHaveCount(1);\n  });\n\n  test(\"should show unhandled errors in the testing module\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n    // Arrange - Prepare Storybook\n    await modifyFile(UNHANDLED_ERRORS_STORY_PATH, (content) =>\n      setForceFailureFlag(content, true)\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"example/unhandlederrors\", \"Success\");\n\n    const storyElement = sbPage.getCanvasBodyElement().getByText(\"Hello world\");\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    // Act - Open sidebar context menu and start focused test\n    await page.locator('[data-item-id=\"example-unhandlederrors\"]').hover();\n    await page\n      .locator(\n        '[data-item-id=\"example-unhandlederrors\"] button[data-testid=\"context-menu\"]'\n      )\n      .click();\n    const sidebarContextMenu = page.getByRole(\"dialog\");\n    await sidebarContextMenu.getByLabel(\"Start test run\").click();\n\n    // HACK: the testing module popover has poor tracking of focus due to how many disabled\n    // buttons it has and how deeply it changes its UI on events. This would be solved once\n    // we move to a declarative menu, and there's an ongoing PR for that. Until then, we tab\n    // around to reset focus.\n    await page.keyboard.press(\"Tab\");\n    await page.keyboard.press(\"Escape\");\n    await page.click(\"body\");\n    await expect(sidebarContextMenu).not.toBeVisible();\n\n    // Assert - Tests are running and errors are reported\n    const errorLink = page.locator(\n      \"#storybook-testing-module #testing-module-description button\"\n    );\n    await expect(errorLink).toContainText(\"View full error\", {\n      timeout: 30000,\n    });\n    await errorLink.click();\n\n    await expect(page.locator(\"pre\")).toContainText(\n      \"I THREW AN UNHANDLED ERROR!\"\n    );\n    await expect(page.locator(\"pre\")).toContainText(\"This error originated in\");\n    await expect(page.locator(\"pre\")).toContainText(\n      \"The latest test that might've caused the error is\"\n    );\n    await page.getByLabel(\"Close modal\").click();\n  });\n\n  test(\"should run focused test for a component\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n    // Arrange - Prepare Storybook\n    await modifyFile(TEST_STORY_PATH, (content) =>\n      setForceFailureFlag(content, false)\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"addons/group/test\", \"Expected Failure\");\n\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"test\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    // Act - Open sidebar context menu and start focused test\n    await page.locator('[data-item-id=\"addons-group-test\"]').hover();\n    await page\n      .locator(\n        '[data-item-id=\"addons-group-test\"] button[data-testid=\"context-menu\"]'\n      )\n      .click();\n    const sidebarContextMenu = page.getByRole(\"dialog\");\n    await sidebarContextMenu.getByLabel(\"Start test run\").click();\n\n    // Assert - Tests are running and reported\n    await expect(\n      sidebarContextMenu.locator(\"#testing-module-description\")\n    ).toContainText(\"Ran 9 tests\", { timeout: 30000 });\n    // Assert - Failing test shows as a failed status\n    await expect(\n      sidebarContextMenu.getByLabel(\"Component tests failed\")\n    ).toHaveCount(1);\n    await expect(\n      sidebarContextMenu.getByLabel(\n        \"Component tests failed (1 errors or warnings so far)\"\n      )\n    ).toBeVisible();\n\n    // HACK: the testing module popover has poor tracking of focus due to how many disabled\n    // buttons it has and how deeply it changes its UI on events. This would be solved once\n    // we move to a declarative menu, and there's an ongoing PR for that. Until then, we tab\n    // around to reset focus.\n    await page.keyboard.press(\"Tab\");\n    await page.keyboard.press(\"Escape\");\n    await page.click(\"body\");\n    await expect(sidebarContextMenu).not.toBeVisible();\n\n    await page.click(\"body\");\n    await expect(\n      page.locator(\n        '#storybook-explorer-menu [data-testid=\"tree-status-button\"][aria-label=\"Status: success\"]'\n      )\n    ).toHaveCount(8);\n    await expect(\n      page.locator(\n        '#storybook-explorer-menu [data-testid=\"tree-status-button\"][aria-label=\"Status: error\"]'\n      )\n    ).toHaveCount(3);\n  });\n\n  test(\"should run focused test for a group\", async ({ page, browserName }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n    // Arrange - Prepare Storybook\n    await modifyFile(TEST_STORY_PATH, (content) =>\n      setForceFailureFlag(content, false)\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"addons/group/test\", \"Expected Failure\");\n\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"test\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    // Act - Open sidebar context menu and start focused test\n    await page.locator('[data-item-id=\"addons-group\"]').hover();\n    await page\n      .locator(\n        '[data-item-id=\"addons-group\"] button[data-testid=\"context-menu\"]'\n      )\n      .click();\n    const sidebarContextMenu = page.getByRole(\"dialog\");\n    await sidebarContextMenu.getByLabel(\"Start test run\").click();\n\n    // Assert - 1 failing test shows as a failed status\n    await expect(\n      sidebarContextMenu.getByLabel(\n        \"Component tests failed (2 errors or warnings so far)\"\n      )\n    ).toBeVisible();\n    await expect(\n      sidebarContextMenu.getByLabel(\"Component tests failed\")\n    ).toHaveCount(1);\n\n    // HACK: the testing module popover has poor tracking of focus due to how many disabled\n    // buttons it has and how deeply it changes its UI on events. This would be solved once\n    // we move to a declarative menu, and there's an ongoing PR for that. Until then, we tab\n    // around to reset focus.\n    await page.keyboard.press(\"Tab\");\n    await page.keyboard.press(\"Escape\");\n    await page.click(\"body\");\n    await expect(sidebarContextMenu).not.toBeVisible();\n\n    // Assert - Tests are running and reported\n    await expect(page.locator(\"#testing-module-description\")).toContainText(\n      \"Ran 11 tests\",\n      { timeout: 30000 }\n    );\n    await expect(\n      page.locator(\n        '#storybook-explorer-menu [data-testid=\"tree-status-button\"][aria-label=\"Status: error\"]'\n      )\n    ).toHaveCount(4); // 1 visible/expanded story, 1 expanded component, 1 collapsed component, 1 group\n  });\n\n  test(\"should run focused tests without coverage, even when enabled\", async ({\n    page,\n    browserName,\n  }) => {\n    test.skip(browserName !== \"chromium\", `Skipping tests for ${browserName}`);\n    // Arrange - Prepare Storybook\n    await modifyFile(TEST_STORY_PATH, (content) =>\n      setForceFailureFlag(content, false)\n    );\n\n    const sbPage = new SbPage(page, expect);\n    await sbPage.navigateToStory(\"example/button\", \"CSF 3 Primary\");\n\n    const storyElement = sbPage\n      .getCanvasBodyElement()\n      .getByRole(\"button\", { name: \"foo\" });\n    await expect(storyElement).toBeVisible({ timeout: 30000 });\n\n    // Act - Enable coverage\n    await page.getByLabel(\"Coverage\", { exact: true }).click();\n    // Wait for Vitest to have (re)started\n    await page.waitForTimeout(2000);\n\n    // Act - Open sidebar context menu and start focused test\n    await page\n      .locator('[data-item-id=\"example-button--csf-3-primary\"]')\n      .hover();\n    await page\n      .locator(\n        '[data-item-id=\"example-button--csf-3-primary\"] button[data-testid=\"context-menu\"]'\n      )\n      .click();\n    const sidebarContextMenu = page.getByRole(\"dialog\");\n    await sidebarContextMenu.getByLabel(\"Start test run\").click();\n\n    // HACK: the testing module popover has poor tracking of focus due to how many disabled\n    // buttons it has and how deeply it changes its UI on events. This would be solved once\n    // we move to a declarative menu, and there's an ongoing PR for that. Until then, we tab\n    // around to reset focus.\n    await page.keyboard.press(\"Tab\");\n    await page.keyboard.press(\"Escape\");\n    await page.click(\"body\");\n    await expect(sidebarContextMenu).not.toBeVisible();\n\n    // Arrange - Wait for test to finish and unfocus sidebar context menu\n    await expect(page.locator(\"#testing-module-description\")).toContainText(\n      \"Ran 1 test\",\n      { timeout: 30000 }\n    );\n    await page.click(\"body\");\n\n    // Assert - Coverage is not shown because Focused Tests shouldn't collect coverage\n    await expect(page.getByLabel(\"Open coverage report\")).not.toBeVisible();\n\n    // Act - Run ALL tests\n    await page.getByLabel(\"Start test run\").click();\n\n    // Arrange - Wait for tests to finish\n    await expect(page.locator(\"#testing-module-description\")).toContainText(\n      /Ran \\d{2,} tests/,\n      { timeout: 30000 }\n    );\n\n    // Assert - Coverage percentage is now collected and shown because running all tests automatically re-enables coverage\n    await expect(page.getByLabel(\"Open coverage report\")).toBeVisible({\n      timeout: 30000,\n    });\n    const sbPercentageText = await page\n      .getByLabel(/% coverage\\)$/)\n      .textContent();\n    expect(sbPercentageText).toMatch(/^\\d+%$/);\n    const sbPercentage = Number.parseInt(\n      sbPercentageText!.replace(\"%\", \"\") ?? \"\"\n    );\n    expect(sbPercentage).toBeGreaterThanOrEqual(0);\n    expect(sbPercentage).toBeLessThanOrEqual(100);\n  });\n\n  test.fixme(\n    \"should still collect statuses even when the browser is closed\",\n    () => {}\n  );\n\n  test.fixme(\n    \"should have correct status count globally and in context menus\",\n    () => {}\n  );\n\n  test.fixme(\n    \"should open the correct component test and a11y panels when clicking on statuses\",\n    () => {}\n  );\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/composition.spec.ts",
    "content": "import { expect, test } from '@playwright/test';\n\nimport { SbPage } from '../../../../code/e2e-tests/util';\n\nconst STORYBOOK_URL = 'http://localhost:6006';\n\ntest.describe('composition', () => {\n  // the composed storybook can be slow to load, so we need to increase the timeout\n  test.describe.configure({ mode: 'serial', timeout: 60000, retries: 2 });\n  test('should filter and render composed stories', async ({ page }) => {\n    await page.goto(STORYBOOK_URL);\n    await new SbPage(page, expect).waitUntilLoaded();\n\n    // Expect that composed Storybooks are visible and loaded\n    await expect(page.getByTitle('Storybook 8.0.0')).toBeVisible();\n    await expect(page.locator('[id=\"storybook\\\\@8\\\\.0\\\\.0_components-badge\"]')).toBeVisible({\n      timeout: 15000,\n    });\n    await expect(page.getByTitle('Storybook 7.6.18')).toBeVisible();\n    await expect(page.locator('[id=\"storybook\\\\@7\\\\.6\\\\.18_components-badge\"]')).toBeVisible({\n      timeout: 15000,\n    });\n\n    // Expect composed stories to be available in the sidebar\n    await page.locator('[id=\"storybook\\\\@8\\\\.0\\\\.0_components-badge\"]').click();\n    await expect(\n      page.locator('[id=\"storybook\\\\@8\\\\.0\\\\.0_components-badge--default\"]')\n    ).toBeVisible();\n\n    await page.locator('[id=\"storybook\\\\@7\\\\.6\\\\.18_components-badge\"]').click();\n    await expect(\n      page\n        .locator('iframe[title=\"storybook-ref-storybook\\\\@7\\\\.6\\\\.18\"]')\n        .contentFrame()\n        .locator('#storybook-root')\n        .getByText('Default')\n    ).toBeVisible({ timeout: 15000 });\n\n    // Expect composed stories `to be available in the search\n    await page.getByPlaceholder('Find components').fill('Button primary');\n    await expect(\n      page.getByRole('option', {\n        name: 'Primary Storybook 7.6.18 / @components / Button',\n      })\n    ).toBeVisible();\n\n    const buttonStory = page.getByRole('option', {\n      name: 'Primary Storybook 8.0.0 / @blocks / examples / Button',\n    });\n    await expect(buttonStory).toBeVisible();\n    await buttonStory.click();\n\n    // Note: this could potentially be flaky due to it accessing a hosted Storybook\n    await expect(\n      page\n        .locator('iframe[title=\"storybook-ref-storybook\\\\@8\\\\.0\\\\.0\"]')\n        .contentFrame()\n        .getByRole('button')\n    ).toBeVisible({ timeout: 15000 });\n  });\n\n  test('should filter and render composed stories on mobile', async ({ page }) => {\n    page.setViewportSize({ width: 320, height: 800 });\n    await page.goto(STORYBOOK_URL);\n    await new SbPage(page, expect).waitUntilLoaded();\n\n    await page.click('button[aria-label=\"Open navigation menu\"]');\n\n    // scroll down to the bottom of the element getByText('Skip to canvasStorybookSearch')\n\n    await page.getByTitle('Storybook 7.6.18').scrollIntoViewIfNeeded();\n\n    // Expect that composed Storybooks are visible\n    await expect(page.getByTitle('Storybook 8.0.0')).toBeVisible();\n    await expect(page.getByTitle('Storybook 7.6.18')).toBeVisible();\n\n    // Expect composed stories to be available in the sidebar\n    await expect(page.locator('[id=\"storybook\\\\@8\\\\.0\\\\.0_components-badge\"]')).toBeVisible();\n    await page.locator('[id=\"storybook\\\\@8\\\\.0\\\\.0_components-badge\"]').click();\n    await expect(\n      page.locator('[id=\"storybook\\\\@8\\\\.0\\\\.0_components-badge--default\"]')\n    ).toBeVisible();\n\n    await page.locator('[id=\"storybook\\\\@7\\\\.6\\\\.18_components-badge\"]').click();\n    await page.locator('[id=\"storybook\\\\@7\\\\.6\\\\.18_components-badge--default\"]').click();\n    await expect(\n      page\n        .locator('iframe[title=\"storybook-ref-storybook\\\\@7\\\\.6\\\\.18\"]')\n        .contentFrame()\n        .locator('#storybook-root')\n        .getByText('Default')\n    ).toBeVisible({ timeout: 15000 });\n\n    await page.click('button[aria-label=\"Open navigation menu\"]');\n\n    // Expect composed stories `to be available in the search\n    await page.getByPlaceholder('Find components').fill('Button primary');\n    await expect(\n      page.getByRole('option', {\n        name: 'Primary Storybook 7.6.18 / @components / Button',\n      })\n    ).toBeVisible();\n\n    const buttonStory = page.getByRole('option', {\n      name: 'Primary Storybook 8.0.0 / @blocks / examples / Button',\n    });\n    await expect(buttonStory).toBeVisible();\n    await buttonStory.click();\n\n    // Note: this could potentially be flaky due to it accessing a hosted Storybook\n    await expect(\n      page\n        .locator('iframe[title=\"storybook-ref-storybook\\\\@8\\\\.0\\\\.0\"]')\n        .contentFrame()\n        .getByRole('button')\n    ).toBeVisible({ timeout: 15000 });\n  });\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/e2e-tests/save-from-controls.spec.ts",
    "content": "import { expect, test } from \"@playwright/test\";\nimport process from \"process\";\n\nimport { SbPage } from \"../../../../code/e2e-tests/util\";\n\nconst STORYBOOK_URL = \"http://localhost:6006\";\nconst type = process.env.STORYBOOK_TYPE || \"dev\";\n\ntest.describe(\"save-from-controls\", () => {\n  test.describe.configure({ mode: \"serial\" });\n  test.skip(\n    type === \"build\",\n    `Skipping save-from-controls tests for production Storybooks`\n  );\n\n  test(\"Should be able to update a story\", async ({ page, browserName }) => {\n    // this is needed because the e2e test will generate a new file in the system\n    // which we don't know of its location (it runs in different sandboxes)\n    // so we just create a random id to make it easier to run tests\n    const id = Math.random().toString(36).substring(7);\n\n    test.skip(\n      browserName !== \"chromium\",\n      `Skipping save-from-controls tests for ${browserName}`\n    );\n\n    await page.goto(STORYBOOK_URL + \"/?path=/story/example-mybutton--primary\");\n    const sbPage = new SbPage(page, expect);\n    await sbPage.waitUntilLoaded();\n\n    await sbPage.viewAddonPanel(\"Controls\");\n\n    // Update an arg\n    const label = sbPage.panelContent().locator(\"textarea[name=children]\");\n    await label.fill(`\"Updated ${id}\"`);\n    await label.blur();\n\n    // Assert the footer is shown\n    await sbPage\n      .panelContent()\n      .locator('[data-short-label=\"Unsaved changes\"]')\n      .isVisible();\n\n    // update the story\n    await sbPage\n      .panelContent()\n      .locator(\"button\")\n      .getByText(\"Update story\")\n      .click();\n\n    // Assert the file is saved\n    const notification1 = sbPage.page.getByTitle(\"Story saved\");\n    await expect(notification1).toBeVisible();\n\n    // dismiss\n    await notification1.click();\n    await notification1.isHidden();\n\n    // Update an arg\n    const newStoryValue = `\"Copied ${id}\"`;\n    await label.fill(newStoryValue);\n    await label.blur();\n\n    // Assert the footer is shown\n    await sbPage\n      .panelContent()\n      .locator('[data-short-label=\"Unsaved changes\"]')\n      .isVisible();\n\n    const buttons = sbPage\n      .panelContent()\n      .locator('[aria-label=\"Create new story with these settings\"]');\n\n    // clone the story\n    await buttons.click();\n\n    await sbPage.page\n      .getByPlaceholder(\"Story export name\")\n      .fill(\"ClonedStory\" + id);\n    await sbPage.page.getByRole(\"button\", { exact: true, name: \"Create\" }).click();\n\n    // Assert the file is saved\n    const notification2 = sbPage.page.getByTitle(\"Story created\");\n    await expect(notification2).toBeVisible();\n    await notification2.click();\n\n    // Assert the Button components is rendered in the preview\n    await expect(sbPage.previewRoot()).toContainText(newStoryValue.replace(/\"/g, ''));\n  });\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/package.json",
    "content": "{\n  \"name\": \"portable-stories-react-vitest-3\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"tsc && vite build\",\n    \"dev\": \"vite\",\n    \"lint\": \"eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0\",\n    \"playwright-e2e\": \"playwright test -c playwright-e2e.config.ts\",\n    \"preview\": \"vite preview\",\n    \"storybook\": \"NODE_OPTIONS=\\\"--preserve-symlinks --preserve-symlinks-main\\\" storybook dev -p 6006\",\n    \"vitest\": \"SKIP_FAIL_ON_PURPOSE=true vitest run\"\n  },\n  \"resolutions\": {\n    \"@playwright/test\": \"1.58.2\",\n    \"@storybook/addon-a11y\": \"file:../../../code/addons/a11y\",\n    \"@storybook/addon-docs\": \"file:../../../code/addons/docs\",\n    \"@storybook/addon-jest\": \"file:../../../code/addons/jest\",\n    \"@storybook/addon-links\": \"file:../../../code/addons/links\",\n    \"@storybook/addon-themes\": \"file:../../../code/addons/themes\",\n    \"@storybook/addon-vitest\": \"file:../../../code/addons/vitest\",\n    \"@storybook/angular\": \"file:../../../code/frameworks/angular\",\n    \"@storybook/builder-vite\": \"file:../../../code/builders/builder-vite\",\n    \"@storybook/builder-webpack5\": \"file:../../../code/builders/builder-webpack5\",\n    \"@storybook/codemod\": \"file:../../../code/lib/codemod\",\n    \"@storybook/core-webpack\": \"portal:../../../code/lib/core-webpack\",\n    \"@storybook/csf-plugin\": \"portal:../../../code/lib/csf-plugin\",\n    \"@storybook/ember\": \"portal:../../../code/frameworks/ember\",\n    \"@storybook/html\": \"file:../../../code/renderers/html\",\n    \"@storybook/nextjs\": \"file:../../../code/frameworks/nextjs\",\n    \"@storybook/preact\": \"file:../../../code/renderers/preact\",\n    \"@storybook/preact-vite\": \"file:../../../code/frameworks/preact-vite\",\n    \"@storybook/preset-create-react-app\": \"file:../../../code/presets/create-react-app\",\n    \"@storybook/preset-react-webpack\": \"file:../../../code/presets/react-webpack\",\n    \"@storybook/preset-server-webpack\": \"file:../../../code/presets/server-webpack\",\n    \"@storybook/react\": \"file:../../../code/renderers/react\",\n    \"@storybook/react-dom-shim\": \"file:../../../code/lib/react-dom-shim\",\n    \"@storybook/react-vite\": \"file:../../../code/frameworks/react-vite\",\n    \"@storybook/react-webpack5\": \"file:../../../code/frameworks/react-webpack5\",\n    \"@storybook/server\": \"file:../../../code/renderers/server\",\n    \"@storybook/server-webpack5\": \"file:../../../code/frameworks/server-webpack5\",\n    \"@storybook/svelte\": \"file:../../../code/renderers/svelte\",\n    \"@storybook/svelte-vite\": \"file:../../../code/frameworks/svelte-vite\",\n    \"@storybook/sveltekit\": \"file:../../../code/frameworks/sveltekit\",\n    \"@storybook/vue3\": \"file:../../../code/renderers/vue3\",\n    \"@storybook/vue3-vite\": \"file:../../../code/frameworks/vue3-vite\",\n    \"@storybook/web-components\": \"file:../../../code/renderers/web-components\",\n    \"@storybook/web-components-vite\": \"file:../../../code/frameworks/web-components-vite\",\n    \"eslint-plugin-storybook\": \"file:../../../code/lib/eslint-plugin\",\n    \"playwright\": \"1.58.2\",\n    \"storybook\": \"portal:../../../code/core\"\n  },\n  \"dependencies\": {\n    \"react\": \"^18.0.0\",\n    \"react-dom\": \"^18.0.0\"\n  },\n  \"devDependencies\": {\n    \"@playwright/test\": \"1.58.2\",\n    \"@storybook/addon-a11y\": \"^8.0.0\",\n    \"@storybook/addon-vitest\": \"^8.0.0\",\n    \"@storybook/react\": \"^8.0.0\",\n    \"@storybook/react-vite\": \"^8.0.0\",\n    \"@testing-library/jest-dom\": \"^6.6.3\",\n    \"@testing-library/react\": \"^16.2.0\",\n    \"@types/identity-obj-proxy\": \"^3\",\n    \"@types/react\": \"^19.0.8\",\n    \"@types/react-dom\": \"^19.0.3\",\n    \"@typescript-eslint/eslint-plugin\": \"^6.21.0\",\n    \"@typescript-eslint/parser\": \"^6.21.0\",\n    \"@vitejs/plugin-react\": \"^4.2.1\",\n    \"@vitest/browser\": \"^3.2.4\",\n    \"@vitest/coverage-v8\": \"^3.2.4\",\n    \"@vitest/ui\": \"^3.2.4\",\n    \"eslint\": \"^8.56.0\",\n    \"eslint-plugin-react-hooks\": \"^4.6.0\",\n    \"eslint-plugin-react-refresh\": \"^0.4.5\",\n    \"eslint-plugin-storybook\": \"^0.11.4\",\n    \"identity-obj-proxy\": \"^3.0.0\",\n    \"storybook\": \"^8.0.0\",\n    \"typescript\": \"^5.8.3\",\n    \"vite\": \"^5.1.1\",\n    \"vitest\": \"^3.2.4\"\n  },\n  \"nx\": {\n    \"includedScripts\": []\n  }\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/playwright-e2e.config.ts",
    "content": "import { defineConfig, devices } from \"@playwright/test\";\nimport path from \"node:path\";\n\n/**\n * See https://playwright.dev/docs/test-configuration.\n */\nexport default defineConfig({\n  testDir: \"./e2e-tests\",\n  outputDir: \"./test-results\",\n  /* Maximum time one test can run for. */\n  timeout: (process.env.CI ? 60 : 30) * 1000,\n  /* Run tests in files in parallel */\n  fullyParallel: false,\n\n  /* Fail the build on CI if you accidentally left test.only in the source code. */\n  forbidOnly: !!process.env.CI,\n  retries: 0,\n  /* Run tests serially to avoid side effects */\n  workers: 1,\n  /* Reporter to use. See https://playwright.dev/docs/test-reporters */\n  reporter: [\n    [\"line\"],\n    [\n      \"junit\",\n      {\n        embedAnnotationsAsProperties: true,\n        outputFile: path.join(__dirname, \"..\", \"..\", \"..\", \"test-results\", \"react-vitest3-e2e-ui.xml\"),\n      },\n    ],\n  ],\n  /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */\n  use: {\n    /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */\n    trace: \"retain-on-failure\",\n    // video: \"retain-on-failure\",\n    // headless: false,\n  },\n\n  /* Configure projects for major browsers */\n  projects: [\n    {\n      name: \"chromium\",\n      use: { ...devices[\"Desktop Chrome\"] },\n    },\n    // {\n    //   name: 'firefox',\n    //   use: { ...devices['Desktop Firefox'] },\n    // },\n    // {\n    //   name: 'webkit',\n    //   use: { ...devices['Desktop Safari'] },\n    // },\n  ],\n\n  webServer: {\n    command: \"yarn storybook\",\n    url: \"http://127.0.0.1:6006\",\n    reuseExistingServer: true,\n  },\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/pre-e2e.js",
    "content": "/* eslint-disable no-undef */\n/* eslint-disable @typescript-eslint/no-var-requires */\nconst fs = require(\"node:fs\");\nconst path = require(\"node:path\");\n\nconst testStoryPath = path.resolve(\"stories/AddonTest.stories.tsx\");\n\nconsole.log(`Pre-e2e script: clearing ${testStoryPath}`);\nconst storyContent = fs.readFileSync(testStoryPath).toString();\nfs.writeFileSync(testStoryPath, storyContent.replace(\"forceFailure: true\", \"forceFailure: false\"));"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/project.json",
    "content": "{\n  \"name\": \"portable-stories-kitchen-sink/react-vitest-3\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"application\",\n  \"targets\": {\n    \"e2e-ui\": {}\n  },\n  \"tags\": [\"ci:normal\", \"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.stories.tsx",
    "content": "import { expect, within } from 'storybook/test';\nimport { Meta, type StoryObj } from '@storybook/react-vite';\nimport { instrument } from 'storybook/internal/instrumenter';\nimport { Component } from './AddonTest';\n\ndeclare global {\n  // eslint-disable-next-line no-var\n  var __vitest_browser__: boolean;\n}\n\nconst meta = {\n  title: 'Addons/Group/Test',\n  component: Component,\n} as Meta<typeof Component>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nconst { pass } = instrument({\n  pass: async () => {},\n}, { intercept: true })\n\nexport const ExpectedFailure: Story = {\n  args: {\n    forceFailure: false,\n  },\n  play: async ({ args }) => {\n    await pass();\n    if(args.forceFailure) {\n      throw new Error('Expected failure');\n    }\n  }\n};\n\nexport const ExpectedSuccess: Story = {\n  play: async () => {\n    await pass();\n  }\n};\n\nexport const ExpectedContent: Story = {\n  play: async ({ canvasElement }) => {\n    const button = within(canvasElement).getByRole('button');\n    await expect(button).toHaveTextContent('test');\n    const decoratorString = within(canvasElement).getByTestId('decorator-string');\n    await expect(decoratorString).toHaveTextContent('Global Decorator');\n  }\n};\n\nexport const LongRunning: Story = {\n  loaders: [async () => new Promise((resolve) => setTimeout(resolve, 800))],\n};\n\n// Tests will pass in browser, but fail in CLI\nexport const MismatchFailure: Story = {\n  play: async () => {\n    await pass();\n    if(!globalThis.__vitest_browser__) {\n      throw new Error('Expected failure');\n    }\n  }\n};\n\n// Tests will fail in browser, but pass in CLI\nexport const MismatchSuccess: Story = {\n  play: async () => {\n    await pass();\n    if(globalThis.__vitest_browser__) {\n      throw new Error('Unexpected success');\n    }\n  },\n  tags: ['fail-on-purpose'],\n};\n\nexport const PreviewHeadTest: Story = {\n  play: async () => {\n    const styles = window.getComputedStyle(document.body);\n    // set in preview-head.html\n    expect(styles.backgroundColor).toBe('rgb(250, 250, 210)');\n    // set in main.js#previewHead\n    expect(styles.borderColor).toBe('rgb(255, 0, 0)');\n  }\n};\n\nexport const StaticDirTest: Story = {\n  play: async () => {\n    const path = '/test-static-dirs/static.js';\n    const { staticFunction } = await import(/* @vite-ignore */path);\n    expect(staticFunction()).toBe(true);\n  }\n}\n\nexport const ViteFinalTest: Story = {\n  play: async () => {\n    // @ts-expect-error TS doesn't know about the alias\n    const { aliasedFunction } = await import('test-alias');\n    expect(aliasedFunction()).toBe(true);\n  }\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/AddonTest.tsx",
    "content": "import { getButtonString } from './get-button-string';\n\nexport const Component = () => {\n  return <button>{getButtonString()}</button>;\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/Button.stories.tsx",
    "content": "import { expect, fn } from 'storybook/test';\nimport type { Meta, StoryFn as CSF2Story, StoryObj as CSF3Story } from '@storybook/react-vite';\n\nimport type { ButtonProps } from './Button';\nimport { Button } from './Button';\n\nconst meta = {\n  title: 'Example/Button',\n  component: Button,\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n\nconst Template: CSF2Story<ButtonProps> = (args) => <Button {...args} />;\n\nexport const CSF2Secondary = Template.bind({});\nCSF2Secondary.args = {\n  children: 'Children coming from story args!',\n  primary: false,\n};\n\nconst getCaptionForLocale = (locale: string) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'pt':\n      return 'Olá!';\n    case 'en':\n      return 'Hello!';\n    default:\n      return undefined;\n  }\n};\n\nexport const CSF2StoryWithLocale: CSF2Story = (args, { globals: { locale } }) => {\n  const caption = getCaptionForLocale(locale);\n  return (\n    <>\n      <p>locale: {locale}</p>\n      <Button>{caption}</Button>\n    </>\n  );\n};\nCSF2StoryWithLocale.storyName = 'WithLocale';\n\nexport const CSF2StoryWithParamsAndDecorator: CSF2Story<ButtonProps> = (args) => {\n  return <Button {...args} />;\n};\nCSF2StoryWithParamsAndDecorator.args = {\n  children: 'foo',\n};\nCSF2StoryWithParamsAndDecorator.parameters = {\n  layout: 'centered',\n};\nCSF2StoryWithParamsAndDecorator.decorators = [(StoryFn) => <StoryFn />];\n\nexport const CSF3Primary: CSF3Story<ButtonProps> = {\n  args: {\n    children: \"foo\",\n    size: 'large',\n    primary: true,\n  },\n  // Accessibility is failing for the Button\n  tags: ['fail-on-purpose'],\n};\n\nexport const CSF3Button: CSF3Story<ButtonProps> = {\n  args: { children: 'foo' },\n};\n\nexport const CSF3ButtonWithRender: CSF3Story<ButtonProps> = {\n  ...CSF3Button,\n  render: (args) => (\n    <div>\n      <p data-testid=\"custom-render\">I am a custom render function</p>\n      <Button {...args} />\n    </div>\n  ),\n};\n\nconst mockFn = fn();\nexport const WithLoader: CSF3Story<{ mockFn: (val: string) => string }> = {\n  args: {\n    mockFn,\n  },\n  loaders: [\n    async () => {\n      mockFn.mockReturnValueOnce('mockFn return value');\n      return {\n        value: 'loaded data',\n      };\n    },\n  ],\n  render: (args, { loaded }) => {\n    const data = args.mockFn('render');\n    return (\n      <div>\n        <div data-testid=\"loaded-data\">{loaded.value}</div>\n        <div data-testid=\"mock-data\">{String(data)}</div>\n      </div>\n    );\n  },\n  play: async () => {\n    expect(mockFn).toHaveBeenCalledWith('render');\n  },\n};"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/Button.tsx",
    "content": "import React from 'react';\nimport './button.css';\n\nexport interface ButtonProps {\n  /**\n   * Is this the principal call to action on the page?\n   */\n  primary?: boolean;\n  /**\n   * What background color to use\n   */\n  backgroundColor?: string;\n  /**\n   * How large should the button be?\n   */\n  size?: 'small' | 'medium' | 'large';\n  /**\n   * Button contents\n   */\n  children: React.ReactNode;\n  /**\n   * Optional click handler\n   */\n  onClick?: () => void;\n}\n\n/**\n * Primary UI component for user interaction\n */\nexport const Button: React.FC<ButtonProps> = (props) => {\n  const { primary = false, size = 'medium', backgroundColor, children, ...otherProps } = props;\n  const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';\n  console.log({props})\n  return (\n    <button\n      type=\"button\"\n      className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n      style={{ backgroundColor }}\n      {...otherProps}\n    >\n      {children}\n    </button>\n  );\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/MyButton.stories.tsx",
    "content": "import type { Meta, StoryObj as CSF3Story } from '@storybook/react-vite';\n\nimport type { ButtonProps } from './Button';\nimport { Button } from './Button';\n\nconst meta = {\n  title: 'Example/MyButton',\n  component: Button,\n  tags: ['!test'],\n  argTypes: {\n    backgroundColor: { control: 'color' },\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\n\nexport const Primary: CSF3Story<ButtonProps> = {\n  args: { children: 'foo' },\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/OtherComponent.stories.tsx",
    "content": "import { Meta, type StoryObj } from '@storybook/react-vite';\n\nconst Component = () => <button>test</button>\n\nconst meta = {\n  title: 'Addons/Group/Other',\n  component: Component,\n} as Meta<typeof Component>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\nexport const Passes: Story = {\n};\n\nexport const Fails: Story = {\n  play: async () => {\n    throw new Error('Expected failure');\n  },\n  tags: ['fail-on-purpose'],\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/UnhandledErrors.stories.tsx",
    "content": "import type { Meta, StoryObj } from '@storybook/react-vite';\n\nasync function unhandledRejection() {\n  throwError('I THREW AN UNHANDLED REJECTION!');\n}\n\nfunction unhandledError() {\n  throwError('I THREW AN UNHANDLED ERROR!');\n}\n\nfunction throwError(message: string) {\n  throw new Error(message);\n}\nconst meta = {\n  title: 'Example/UnhandledErrors',\n  args: {\n    errorType: null,\n    forceFailure: false,\n  },\n  component: ({ errorType, forceFailure }) => {\n    if (forceFailure) {\n      if (errorType === 'rejection') {\n        setTimeout(unhandledRejection, 0);\n      } else if (errorType === 'error') {\n        setTimeout(unhandledError, 0);\n      }\n    }\n    return 'Hello world';\n  },\n} as Meta<{ errorType: 'rejection' | 'error' | null; forceFailure?: boolean }>;\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const UnhandledError: Story = {\n  args: {\n    errorType: 'error',\n  },\n};\n\nexport const UnhandledRejection: Story = {\n  args: {\n    errorType: 'rejection',\n  },\n};\n\nexport const Success: Story = {};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/button.css",
    "content": ".storybook-button {\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n  font-weight: 700;\n  border: 0;\n  border-radius: 3em;\n  cursor: pointer;\n  display: inline-block;\n  line-height: 1;\n}\n.storybook-button--primary {\n  color: white;\n  background-color: #1ea7fd;\n}\n.storybook-button--secondary {\n  color: #333;\n  background-color: transparent;\n  box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;\n}\n.storybook-button--small {\n  font-size: 12px;\n  padding: 10px 16px;\n}\n.storybook-button--medium {\n  font-size: 14px;\n  padding: 11px 20px;\n}\n.storybook-button--large {\n  font-size: 16px;\n  padding: 12px 24px;\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/stories/get-button-string.ts",
    "content": "export const getButtonString = () => {\n  return \"test\";\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n    \"module\": \"ESNext\",\n    \"skipLibCheck\": true,\n\n    /* Bundler mode */\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\",\n\n    /* Linting */\n    \"strict\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"noFallthroughCasesInSwitch\": true\n  },\n  \"include\": [\"stories\", \"e2e-tests\"],\n  \"references\": [{ \"path\": \"./tsconfig.node.json\" }]\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/tsconfig.node.json",
    "content": "{\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"skipLibCheck\": true,\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"allowSyntheticDefaultImports\": true,\n    \"strict\": true\n  },\n  \"include\": [\"vite.config.ts\"]\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/vite.config.ts",
    "content": "import { defineConfig } from \"vite\";\nimport react from \"@vitejs/plugin-react\";\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [react()],\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/react-vitest-3/vitest.workspace.ts",
    "content": "import { defineWorkspace } from \"vitest/config\";\nimport { storybookTest } from \"@storybook/addon-vitest/vitest-plugin\";\n\nexport default defineWorkspace([\n  {\n    extends: \"vite.config.ts\",\n    plugins: [\n      storybookTest(\n        process.env.SKIP_FAIL_ON_PURPOSE\n          ? {\n              tags: {\n                exclude: [\"fail-on-purpose\"],\n              },\n            }\n          : undefined\n      ),\n    ],\n    test: {\n      name: \"storybook\",\n      pool: \"threads\",\n      deps: {\n        optimizer: {\n          web: {\n            enabled: false,\n          },\n        },\n      },\n      browser: {\n        enabled: true,\n        provider: \"playwright\",\n        headless: true,\n        instances: [\n          {\n            browser: \"chromium\",\n          },\n        ],\n      },\n      setupFiles: [\"./.storybook/vitest.setup.ts\"],\n      environment: \"jsdom\",\n    },\n  },\n]);\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/.gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndist-ssr\n*.local\n\n# Editor directories and files\n.vscode/*\n!.vscode/extensions.json\n.idea\n.DS_Store\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n\n*storybook.log\n/test-results/\n/playwright-report/\n/blob-report/\n/playwright/.cache/\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/.storybook/GlobalDecorator.svelte",
    "content": "<div data-testid=\"global-decorator\">\n  Global Decorator\n  <br />\n  <slot />\n</div>"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/.storybook/main.ts",
    "content": "import type { StorybookConfig } from '@storybook/svelte-vite';\n\nconst config: StorybookConfig = {\n  stories: [\"../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)\"],\n  framework: {\n    name: '@storybook/svelte-vite',\n    options: {},\n  },\n};\nexport default config;\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/.storybook/preview.ts",
    "content": "import type { Preview } from '@storybook/svelte';\nimport GlobalDecorator from './GlobalDecorator.svelte'\n\nconsole.log('preview file is called!');\n\nconst preview: Preview = {\n  decorators: [\n    () => (\n      {\n        Component: GlobalDecorator,\n      }\n    ),\n  ],\n  globalTypes: {\n    locale: {\n      description: 'Locale for components',\n      defaultValue: 'en',\n      toolbar: {\n        title: 'Locale',\n        icon: 'circlehollow',\n        items: ['es', 'en'],\n      },\n    },\n  },\n};\n\nexport default preview;\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/.yarnrc.yml",
    "content": "checksumBehavior: ignore\n\nenableGlobalCache: true\n\nnodeLinker: node-modules\n\nyarnPath: ../../../.yarn/releases/yarn-4.10.3.cjs\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/cypress/fixtures/example.json",
    "content": "{\n  \"name\": \"Using fixtures to represent data\",\n  \"email\": \"hello@cypress.io\",\n  \"body\": \"Fixtures are a great way to mock data for responses to routes\"\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/cypress/support/commands.ts",
    "content": "/// <reference types=\"cypress\" />\n// ***********************************************\n// This example commands.ts shows you how to\n// create various custom commands and overwrite\n// existing commands.\n//\n// For more comprehensive examples of custom\n// commands please read more here:\n// https://on.cypress.io/custom-commands\n// ***********************************************\n//\n//\n// -- This is a parent command --\n// Cypress.Commands.add('login', (email, password) => { ... })\n//\n//\n// -- This is a child command --\n// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })\n//\n//\n// -- This is a dual command --\n// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })\n//\n//\n// -- This will overwrite an existing command --\n// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })\n//\n// declare global {\n//   namespace Cypress {\n//     interface Chainable {\n//       login(email: string, password: string): Chainable<void>\n//       drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>\n//       dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>\n//       visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>\n//     }\n//   }\n// }"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/cypress/support/component-index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n    <title>Components App</title>\n  </head>\n  <body>\n    <div data-cy-root></div>\n  </body>\n</html>"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/cypress/support/component.ts",
    "content": "// ***********************************************************\n// This example support/component.ts is processed and\n// loaded automatically before your test files.\n//\n// This is a great place to put global configuration and\n// behavior that modifies Cypress.\n//\n// You can change the location of this file or turn off\n// automatically serving support files with the\n// 'supportFile' configuration option.\n//\n// You can read more here:\n// https://on.cypress.io/configuration\n// ***********************************************************\n\n// Import commands.js using ES2015 syntax:\nimport './commands'\n\n// Alternatively you can use CommonJS syntax:\n// require('./commands')\n\nimport { mount } from 'cypress/svelte'\n\nimport type { ProjectAnnotations } from 'storybook/internal/types';\nimport type { SvelteRenderer } from '@storybook/svelte';\nimport { setProjectAnnotations } from '@storybook/svelte';\nimport sbAnnotations from '../../.storybook/preview';\n\n// Augment the Cypress namespace to include type definitions for\n// your custom command.\n// Alternatively, can be defined in cypress/support/component.d.ts\n// with a <reference path=\"./component\" /> at the top of your spec.\ndeclare global {\n  namespace Cypress {\n    interface Chainable {\n      mount: typeof mount\n    }\n  }\n}\n\nCypress.Commands.add('mount', mount)\n\n// Example use:\n// cy.mount(MyComponent)\n\n// This is needed because Cypress defines process but not process.env\n// And if the play function fails, testing library's internals have a check\n// for typeof process !== \"undefined\" && process.env.DEBUG_PRINT_LIMIT;\n// which will break\nprocess.env = {};\n\nsetProjectAnnotations([\n  sbAnnotations,\n]);\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/cypress.config.ts",
    "content": "import { defineConfig } from \"cypress\";\n\nexport default defineConfig({\n  component: {\n    devServer: {\n      framework: \"svelte\",\n      bundler: \"vite\",\n    },\n  },\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/vite.svg\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Vite + Svelte + TS</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script type=\"module\" src=\"/src/main.ts\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/package.json",
    "content": "{\n  \"name\": \"portable-stories-svelte\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"vite build\",\n    \"cypress\": \"echo 'No cypress setup yet'\",\n    \"dev\": \"vite\",\n    \"jest\": \"echo 'No jest setup yet'\",\n    \"playwright-ct\": \"echo 'No Playwright setup yet'\",\n    \"preview\": \"vite preview\",\n    \"storybook\": \"STORYBOOK_TELEMETRY_URL=\\\"http://localhost:6007/event-log\\\" storybook dev -p 6006\",\n    \"vitest\": \"vitest\"\n  },\n  \"resolutions\": {\n    \"@playwright/test\": \"1.58.2\",\n    \"@storybook/addon-a11y\": \"portal:../../../code/addons/a11y\",\n    \"@storybook/addon-docs\": \"portal:../../../code/addons/docs\",\n    \"@storybook/addon-links\": \"portal:../../../code/addons/links\",\n    \"@storybook/addon-themes\": \"portal:../../../code/addons/themes\",\n    \"@storybook/angular\": \"portal:../../../code/frameworks/angular\",\n    \"@storybook/builder-vite\": \"portal:../../../code/builders/builder-vite\",\n    \"@storybook/builder-webpack5\": \"portal:../../../code/builders/builder-webpack5\",\n    \"@storybook/codemod\": \"portal:../../../code/lib/codemod\",\n    \"@storybook/core-webpack\": \"portal:../../../code/lib/core-webpack\",\n    \"@storybook/csf-plugin\": \"portal:../../../code/lib/csf-plugin\",\n    \"@storybook/ember\": \"portal:../../../code/frameworks/ember\",\n    \"@storybook/html\": \"portal:../../../code/renderers/html\",\n    \"@storybook/nextjs\": \"portal:../../../code/frameworks/nextjs\",\n    \"@storybook/preact\": \"portal:../../../code/renderers/preact\",\n    \"@storybook/preact-vite\": \"portal:../../../code/frameworks/preact-vite\",\n    \"@storybook/preset-create-react-app\": \"portal:../../../code/presets/create-react-app\",\n    \"@storybook/preset-react-webpack\": \"portal:../../../code/presets/react-webpack\",\n    \"@storybook/preset-server-webpack\": \"portal:../../../code/presets/server-webpack\",\n    \"@storybook/react\": \"portal:../../../code/renderers/react\",\n    \"@storybook/react-dom-shim\": \"portal:../../../code/lib/react-dom-shim\",\n    \"@storybook/react-vite\": \"portal:../../../code/frameworks/react-vite\",\n    \"@storybook/react-webpack5\": \"portal:../../../code/frameworks/react-webpack5\",\n    \"@storybook/server\": \"portal:../../../code/renderers/server\",\n    \"@storybook/server-webpack5\": \"portal:../../../code/frameworks/server-webpack5\",\n    \"@storybook/svelte\": \"portal:../../../code/renderers/svelte\",\n    \"@storybook/svelte-vite\": \"portal:../../../code/frameworks/svelte-vite\",\n    \"@storybook/sveltekit\": \"portal:../../../code/frameworks/sveltekit\",\n    \"@storybook/vue3\": \"portal:../../../code/renderers/vue3\",\n    \"@storybook/vue3-vite\": \"portal:../../../code/frameworks/vue3-vite\",\n    \"@storybook/web-components\": \"portal:../../../code/renderers/web-components\",\n    \"@storybook/web-components-vite\": \"portal:../../../code/frameworks/web-components-vite\",\n    \"playwright\": \"1.58.2\",\n    \"storybook\": \"portal:../../../code/core\"\n  },\n  \"devDependencies\": {\n    \"@playwright/experimental-ct-svelte\": \"1.58.2\",\n    \"@storybook/svelte\": \"9.0.0-alpha.0\",\n    \"@storybook/svelte-vite\": \"9.0.0-alpha.0\",\n    \"@sveltejs/vite-plugin-svelte\": \"^6.2.0\",\n    \"@testing-library/svelte\": \"5.2.8\",\n    \"@tsconfig/svelte\": \"^5.0.5\",\n    \"@types/node\": \"^22\",\n    \"cypress\": \"^13.6.6\",\n    \"happy-dom\": \"^15.11.7\",\n    \"storybook\": \"9.0.0-alpha.0\",\n    \"svelte\": \"^5.39.5\",\n    \"svelte-check\": \"^4.3.2\",\n    \"tslib\": \"^2.6.2\",\n    \"typescript\": \"^5.2.2\",\n    \"vite\": \"^6\",\n    \"vitest\": \"^3.2.4\"\n  },\n  \"nx\": {\n    \"includedScripts\": []\n  }\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/playwright/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Testing Page</title>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"./index.ts\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/playwright/index.ts",
    "content": "import { setProjectAnnotations } from '@storybook/svelte'\nimport sbAnnotations from '../.storybook/preview'\n\nsetProjectAnnotations([\n  sbAnnotations,\n]);\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/playwright.config.ts",
    "content": "import { defineConfig, devices } from '@playwright/experimental-ct-svelte';\nimport ctViteConfig from './vite.config';\n\n/**\n * See https://playwright.dev/docs/test-configuration.\n */\nexport default defineConfig({\n  testDir: 'stories',\n  testMatch: '*.playwright.tsx',\n  /* The base directory, relative to the config file, for snapshot files created with toMatchSnapshot and toHaveScreenshot. */\n  snapshotDir: './__snapshots__',\n  /* Maximum time one test can run for. */\n  timeout: 10 * 1000,\n  /* Run tests in files in parallel */\n  fullyParallel: true,\n  /* Fail the build on CI if you accidentally left test.only in the source code. */\n  forbidOnly: !!process.env.CI,\n  /* Retry on CI only */\n  retries: process.env.CI ? 2 : 0,\n  /* Opt out of parallel tests on CI. */\n  workers: process.env.CI ? 1 : undefined,\n  /* Reporter to use. See https://playwright.dev/docs/test-reporters */\n  reporter: 'html',\n  outputDir: './test-results',\n  /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */\n  use: {\n    /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */\n    trace: 'on-first-retry',\n\n    /* Port to use for Playwright component endpoint. */\n    ctPort: 3100,\n    ctViteConfig\n  },\n\n  /* Configure projects for major browsers */\n  projects: [\n    {\n      name: 'chromium',\n      use: { ...devices['Desktop Chrome'] },\n    },\n    // {\n    //   name: 'firefox',\n    //   use: { ...devices['Desktop Firefox'] },\n    // },\n    // {\n    //   name: 'webkit',\n    //   use: { ...devices['Desktop Safari'] },\n    // },\n  ],\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/project.json",
    "content": "{\n  \"name\": \"portable-stories-kitchen-sink/svelte\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"application\",\n  \"targets\": {\n    \"jest\": {},\n    \"vitest\": {},\n    \"playwright-ct\": {},\n    \"cypress\": {}\n  },\n  \"tags\": [\"ci:normal\", \"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/stories/AddWrapperDecorator.svelte",
    "content": "<script>\n  let { children } = $props();\n</script>\n\n<div style=\"margin: 3em;\">\n  {@render children?.()}\n</div>"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.cy.tsx",
    "content": "/// <reference types=\"cypress\"/>\nimport * as stories from './Button.stories';\nimport { composeStories, composeStory } from '@storybook/svelte';\n\n// const { CSF3Primary, WithLoader, CSF3InputFieldFilled } = composeStories(stories)\n\ndescribe('<Button()', () => {\n  it('renders primary button', async () => {\n    // TODO figure out the following issue ReferenceError: $state is not defined\n    // at createSvelte5Props (http://localhost:5173/__cypress/src/@fs/storybook/code/renderers/svelte/dist/createSvelte5Props.svelte.js:11:17)\n    const Primary = composeStory(stories.CSF3Primary, stories.default);\n    cy.mount(CSF3Primary)\n    cy.get('button').should('contain.text', 'foo');\n    // cy.get('[data-decorator]').should('exist');\n  })\n\n  // it('renders primary button with custom args', async () => {\n  //   cy.mount(CSF3Primary({ label: 'bar' }))\n  //   cy.get('button').should('contain.text', 'bar');\n  // })\n\n  // it.skip('renders with loaders and play function', () => {\n  //   cy.then(async() => {\n  //     await WithLoader.load();\n  //   });\n\n  //   cy.mount(WithLoader);\n\n  //   cy.then(async() => {\n  //     await WithLoader.play!({ canvasElement: document.querySelector('[data-cy-root]') as HTMLElement });\n  //   });\n\n  //   cy.get('[data-testid=\"loaded-data\"]').should('contain.text', 'bar');\n  //   cy.get('[data-testid=\"mock-data\"]').should('contain.text', 'mockFn return value');\n  // })\n\n  // it.skip('renders with play function', () => {\n  //   cy.mount(CSF3InputFieldFilled);\n\n  //   cy.then(async() => {\n  //     await CSF3InputFieldFilled.play!({ canvasElement: document.querySelector('[data-cy-root]') as HTMLElement });\n  //     cy.get('[data-testid=\"input\"]').should('contain.value', 'Hello world!');\n  //   });\n  // })\n})\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.playwright.ts",
    "content": "import { createTest } from '@storybook/svelte/experimental-playwright';\nimport { test as base } from '@playwright/experimental-ct-svelte';\n\nimport stories from './Button.stories.playwright';\n\nconst test = createTest(base);\n\ntest.skip('renders primary button', async ({ mount }) => {\n  // TODO: this is not working, probably the translation that Playwright does not work with portable stories yet\n  await mount(stories.WithLoader); \n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.stories.playwright.tsx",
    "content": "import { composeStories } from '@storybook/svelte';\nimport * as stories from './Button.stories';\n\nexport default composeStories(stories);"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.stories.ts",
    "content": "import { expect, fn, userEvent, within } from 'storybook/test';\nimport type { Meta, StoryFn as CSF2Story, StoryObj } from '../..';\n\nimport LoaderStoryComponent from './LoaderStoryComponent.svelte';\nimport InputFilledStoryComponent from './InputFilledStoryComponent.svelte';\nimport StoryWithLocaleComponent from './StoryWithLocaleComponent.svelte';\nimport AddWrapperDecorator from './AddWrapperDecorator.svelte';\nimport CustomRenderComponent from './CustomRenderComponent.svelte';\n\nimport Button from './Button.svelte';\n\nconst meta = {\n  title: 'Example/Button',\n  component: Button,\n  argTypes: {\n    backgroundColor: { control: 'color' },\n    size: {\n      control: { type: 'select' },\n      options: ['small', 'medium', 'large'],\n    },\n  },\n  excludeStories: /.*ImNotAStory$/,\n} satisfies Meta<Button>;\n\nexport default meta;\ntype CSF3Story = StoryObj<typeof meta>;\n\n// For testing purposes. Should be ignored in ComposeStories\nexport const ImNotAStory = 123;\n\nconst Template: CSF2Story = (args) => ({\n  Component: Button,\n  props: args,\n});\n\nexport const CSF2Secondary = Template.bind({});\nCSF2Secondary.args = {\n  label: 'label coming from story args!',\n  primary: false,\n};\n\nconst getCaptionForLocale = (locale: string) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'pt':\n      return 'Olá!';\n    default:\n      return 'Hello!';\n  }\n};\n\nexport const CSF2StoryWithLocale: CSF2Story = (args, { globals }) => ({\n  Component: StoryWithLocaleComponent,\n  props: {\n    ...args,\n    locale: globals.locale,\n    label: getCaptionForLocale(globals.locale),\n  },\n});\nCSF2StoryWithLocale.storyName = 'WithLocale';\n\nexport const CSF2StoryWithParamsAndDecorator = Template.bind({});\nCSF2StoryWithParamsAndDecorator.args = {\n  label: 'foo',\n};\nCSF2StoryWithParamsAndDecorator.parameters = {\n  layout: 'centered',\n};\nCSF2StoryWithParamsAndDecorator.decorators = [\n  () => ({\n    Component: AddWrapperDecorator,\n  }),\n];\n\nexport const NewStory: CSF3Story = {\n  args: {\n    label: 'foo',\n    size: 'large',\n    primary: true,\n  },\n  decorators: [\n    () => ({\n      Component: AddWrapperDecorator,\n    }),\n  ],\n};\n\nexport const CSF3Primary: CSF3Story = {\n  args: {\n    label: 'foo',\n    size: 'large',\n    primary: true,\n  },\n};\n\nexport const CSF3Button: CSF3Story = {\n  args: { label: 'foo' },\n};\n\nexport const CSF3ButtonWithRender: CSF3Story = {\n  ...CSF3Button,\n  render: (args) => ({\n    Component: CustomRenderComponent,\n    props: {\n      args,\n    },\n  }),\n};\n\nexport const CSF3InputFieldFilled: CSF3Story = {\n  render: () => ({\n    Component: InputFilledStoryComponent,\n  }),\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    await step('Step label', async () => {\n      const inputEl = canvas.getByTestId('input');\n      await userEvent.type(inputEl, 'Hello world!');\n      await expect(inputEl).toHaveValue('Hello world!');\n    });\n  },\n};\n\nconst mockFn = fn();\nexport const LoaderStory: StoryObj<{ mockFn: (val: string) => string }> = {\n  args: {\n    mockFn,\n  },\n  loaders: [\n    async () => {\n      mockFn.mockReturnValueOnce('mockFn return value');\n      return {\n        value: 'loaded data',\n      };\n    },\n  ],\n  render: (args, { loaded }) => ({\n    Component: LoaderStoryComponent,\n    props: {\n      ...args,\n      loaded,\n    },\n  }),\n  play: async () => {\n    expect(mockFn).toHaveBeenCalledWith('render');\n  },\n};\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.svelte",
    "content": "<script lang=\"ts\">\n  import './button.css';\n  \n  type Props = {\n    /**\n     * Is this the principal call to action on the page?\n     */\n    primary?: boolean;\n    /**\n     * What background color to use\n     */\n    backgroundColor?: string;\n    /**\n     * How large should the button be?\n     */\n    size?: 'small' | 'medium' | 'large';\n    /**\n     * Button contents\n     */\n    label?: string;\n    /**\n     * Optional click handler\n     */\n    onclick?: (event: MouseEvent) => void;\n    /**\n     * Button contents\n     */\n    children?: any;\n  };\n\n  const { \n    primary = false,\n    backgroundColor = undefined,\n    size = 'medium',\n    label = '',\n    children,\n    ...props\n  }: Props = $props();\n\n  let mode = $derived(primary ? 'storybook-button--primary' : 'storybook-button--secondary');\n  let style = $derived(backgroundColor ? `background-color: ${backgroundColor}` : '');\n</script>\n\n<button\n  type=\"button\"\n  class={['storybook-button', `storybook-button--${size}`, mode].join(' ')}\n  {style}\n  {...props}\n>\n  {label}\n  {@render children?.()}\n</button>\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/stories/Button.test.ts",
    "content": "/// <reference types=\"@testing-library/jest-dom\" />\nimport { it, expect, describe, afterEach } from 'vitest';\nimport { render, screen, cleanup } from '@testing-library/svelte';\n// import '@testing-library/svelte/vitest';\nimport * as stories from './Button.stories';\n// import type Button from './Button.svelte';\nimport { composeStories, composeStory, setProjectAnnotations } from '@storybook/svelte';\n\nsetProjectAnnotations([]);\n\n// example with composeStories, returns an object with all stories composed with args/decorators\nconst { CSF3Primary, LoaderStory } = composeStories(stories);\n\n// example with composeStory, returns a single story composed with args/decorators\nconst Secondary = composeStory(stories.CSF2Secondary, stories.default);\ndescribe('renders', () => {\n  afterEach(() => {\n    cleanup();\n  });\n\n  it('renders primary button with custom props via composeStory', () => {\n    // We unfortunately can't do the following:\n    // render(CSF3Primary.Component, { ...CSF3Primary.props, label: 'Hello world' });\n    // Because the props will be passed to the first decorator of the story instead\n    // of the actual component of the story. This is because of our current PreviewRender structure\n\n    const composedStory = composeStory(\n      {\n        ...stories.CSF3Primary,\n        args: { ...stories.CSF3Primary.args, label: 'Hello world' },\n      },\n      stories.default\n    );\n\n    render(composedStory.Component, composedStory.props);\n    const buttonElement = screen.getByText(/Hello world/i);\n    expect(buttonElement).not.toBeNull();\n  });\n\n  it('reuses args from composed story', () => {\n    render(Secondary.Component, Secondary.props);\n    const buttonElement = screen.getByRole('button');\n    expect(buttonElement.textContent).toMatch(Secondary.args.label);\n  });\n\n  it('reuses args from composeStories', () => {\n    const { getByText } = render(CSF3Primary.Component, CSF3Primary.props);\n    const buttonElement = getByText(/foo/i);\n    expect(buttonElement).not.toBeNull();\n  });\n\n  it('should call and compose loaders data', async () => {\n    await LoaderStory.load();\n    const { getByTestId } = render(LoaderStory.Component, LoaderStory.props);\n    expect(getByTestId('spy-data').textContent).toEqual('mockFn return value');\n    expect(getByTestId('loaded-data').textContent).toEqual('loaded data');\n    // spy assertions happen in the play function and should work\n    await LoaderStory.run!();\n  });\n});\n\ndescribe('projectAnnotations', () => {\n  afterEach(() => {\n    cleanup();\n  });\n\n  it('renders with default projectAnnotations', () => {\n    setProjectAnnotations([\n      {\n        parameters: { injected: true },\n        globalTypes: {\n          locale: { defaultValue: 'en' },\n        },\n      },\n    ]);\n    const WithEnglishText = composeStory(stories.CSF2StoryWithLocale, stories.default);\n    const { getByText } = render(WithEnglishText.Component, WithEnglishText.props);\n    const buttonElement = getByText('Hello!');\n    expect(buttonElement).not.toBeNull();\n    expect(WithEnglishText.parameters?.injected).toBe(true);\n  });\n\n  it('renders with custom projectAnnotations via composeStory params', () => {\n    const WithPortugueseText = composeStory(stories.CSF2StoryWithLocale, stories.default, {\n      initialGlobals: { locale: 'pt' },\n    });\n    const { getByText } = render(WithPortugueseText.Component, WithPortugueseText.props);\n    const buttonElement = getByText('Olá!');\n    expect(buttonElement).not.toBeNull();\n  });\n});\n\ndescribe('CSF3', () => {\n  afterEach(() => {\n    cleanup();\n  });\n\n  it('renders with inferred globalRender', () => {\n    const Primary = composeStory(stories.CSF3Button, stories.default);\n\n    render(Primary.Component, Primary.props);\n    const buttonElement = screen.getByText(/foo/i);\n    expect(buttonElement).not.toBeNull();\n  });\n\n  it('renders with custom render function', () => {\n    const Primary = composeStory(stories.CSF3ButtonWithRender, stories.default);\n\n    render(Primary.Component, Primary.props);\n    expect(screen.getByTestId('custom-render')).not.toBeNull();\n  });\n\n  it('renders with play function without canvas element', async () => {\n    const CSF3InputFieldFilled = composeStory(stories.CSF3InputFieldFilled, stories.default);\n\n    await CSF3InputFieldFilled.run();\n\n    const input = screen.getByTestId('input') as HTMLInputElement;\n    expect(input.value).toEqual('Hello world!');\n  });\n\n  it('renders with play function with canvas element', async () => {\n    const CSF3InputFieldFilled = composeStory(stories.CSF3InputFieldFilled, stories.default);\n\n    const div = document.createElement('div');\n    document.body.appendChild(div);\n\n    await CSF3InputFieldFilled.run({ canvasElement: div });\n\n    const input = screen.getByTestId('input') as HTMLInputElement;\n    expect(input.value).toEqual('Hello world!');\n\n    document.body.removeChild(div);\n  });\n});\n\n// // Batch snapshot testing\nconst testCases = Object.values(composeStories(stories)).map(\n  (Story) => [Story.storyName, Story] as [string, typeof Story]\n);\nit.each(testCases)('Renders %s story', async (_storyName, Story) => {\n  if (_storyName === 'CSF2StoryWithLocale') return;\n  await Story.run();\n  expect(document.body).toMatchSnapshot();\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/stories/CustomRenderComponent.svelte",
    "content": "<script>\n  import Button from './Button.svelte';\n\n  const { args } = $props();\n</script>\n\n<div>\n  <p data-testid=\"custom-render\">I am a custom render function</p>\n  <Button {...args} />\n</div>"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/stories/InputFilledStoryComponent.svelte",
    "content": "<input data-testid=\"input\" />"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/stories/LoaderStoryComponent.svelte",
    "content": "<script>\n  const { mockFn, loaded } = $props();\n  \n  let data = $state();\n  \n  $effect(() => {\n    if (mockFn && loaded) {\n      data = mockFn('render');\n    }\n  });\n</script>\n\n<div>\n  <div data-testid=\"loaded-data\">{loaded.value}</div>\n  <div data-testid=\"spy-data\">{String(data)}</div>\n</div>"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/stories/StoryWithLocaleComponent.svelte",
    "content": "<script>\n  const { label, locale } = $props();\n</script>\n\n<p>The current locale is: {locale}</p>\n<div>{label}</div>"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/stories/__snapshots__/Button.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`Renders CSF2Secondary story 1`] = `\n<body>\n  <div>\n    <button\n      class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n      style=\"\"\n      type=\"button\"\n    >\n      label coming from story args! \n      <!---->\n    </button>\n    <!---->\n    \n    <!---->\n    \n    <!---->\n    \n    \n  </div>\n</body>\n`;\n\nexports[`Renders CSF2StoryWithParamsAndDecorator story 1`] = `\n<body>\n  <div>\n    <div\n      style=\"margin: 3em;\"\n    >\n      <button\n        class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n        style=\"\"\n        type=\"button\"\n      >\n        foo \n        <!---->\n      </button>\n      <!---->\n      \n      <!---->\n    </div>\n    <!---->\n    \n    <!---->\n    \n    <!---->\n    \n    <!---->\n    \n    <!---->\n    \n    \n  </div>\n</body>\n`;\n\nexports[`Renders CSF3Button story 1`] = `\n<body>\n  <div>\n    <button\n      class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n      style=\"\"\n      type=\"button\"\n    >\n      foo \n      <!---->\n    </button>\n    <!---->\n    \n    <!---->\n    \n    <!---->\n    \n    \n  </div>\n</body>\n`;\n\nexports[`Renders CSF3ButtonWithRender story 1`] = `\n<body>\n  <div>\n    <div>\n      <p\n        data-testid=\"custom-render\"\n      >\n        I am a custom render function\n      </p>\n       \n      <button\n        class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n        style=\"\"\n        type=\"button\"\n      >\n        foo \n        <!---->\n      </button>\n      <!---->\n    </div>\n    <!---->\n    \n    <!---->\n    \n    <!---->\n    \n    \n  </div>\n</body>\n`;\n\nexports[`Renders CSF3InputFieldFilled story 1`] = `\n<body>\n  <div>\n    <input\n      data-testid=\"input\"\n    />\n    <!---->\n    \n    <!---->\n    \n    <!---->\n    \n    \n  </div>\n</body>\n`;\n\nexports[`Renders CSF3Primary story 1`] = `\n<body>\n  <div>\n    <button\n      class=\"storybook-button storybook-button--large storybook-button--primary\"\n      style=\"\"\n      type=\"button\"\n    >\n      foo \n      <!---->\n    </button>\n    <!---->\n    \n    <!---->\n    \n    <!---->\n    \n    \n  </div>\n</body>\n`;\n\nexports[`Renders LoaderStory story 1`] = `\n<body>\n  <div>\n    <div>\n      <div\n        data-testid=\"loaded-data\"\n      >\n        loaded data\n      </div>\n       \n      <div\n        data-testid=\"spy-data\"\n      >\n        mockFn return value\n      </div>\n    </div>\n    <!---->\n    \n    <!---->\n    \n    <!---->\n    \n    \n  </div>\n</body>\n`;\n\nexports[`Renders NewStory story 1`] = `\n<body>\n  <div>\n    <div\n      style=\"margin: 3em;\"\n    >\n      <button\n        class=\"storybook-button storybook-button--large storybook-button--primary\"\n        style=\"\"\n        type=\"button\"\n      >\n        foo \n        <!---->\n      </button>\n      <!---->\n      \n      <!---->\n    </div>\n    <!---->\n    \n    <!---->\n    \n    <!---->\n    \n    <!---->\n    \n    <!---->\n    \n    \n  </div>\n</body>\n`;\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/stories/__snapshots__/portable-stories.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`Renders CSF2Secondary story 1`] = `\n<body>\n  <div>\n    <button\n      class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n      style=\"\"\n      type=\"button\"\n    >\n      label coming from story args!\n       \n    </button>\n    <!--&lt;Button&gt;-->\n    \n    \n    <!--&lt;SlotDecorator&gt;-->\n    <!--&lt;PreviewRender&gt;-->\n  </div>\n</body>\n`;\n\nexports[`Renders CSF2StoryWithParamsAndDecorator story 1`] = `\n<body>\n  <div>\n    <div\n      style=\"margin: 3em;\"\n    >\n      <button\n        class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n        style=\"\"\n        type=\"button\"\n      >\n        foo\n         \n      </button>\n      <!--&lt;Button&gt;-->\n      \n    </div>\n    <!--&lt;AddWrapperDecorator&gt;-->\n    \n    \n    <!--&lt;SlotDecorator&gt;-->\n    \n    \n    <!--&lt;SlotDecorator&gt;-->\n    <!--&lt;PreviewRender&gt;-->\n  </div>\n</body>\n`;\n\nexports[`Renders CSF3Button story 1`] = `\n<body>\n  <div>\n    <button\n      class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n      style=\"\"\n      type=\"button\"\n    >\n      foo\n       \n    </button>\n    <!--&lt;Button&gt;-->\n    \n    \n    <!--&lt;SlotDecorator&gt;-->\n    <!--&lt;PreviewRender&gt;-->\n  </div>\n</body>\n`;\n\nexports[`Renders CSF3ButtonWithRender story 1`] = `\n<body>\n  <div>\n    <div>\n      <p\n        data-testid=\"custom-render\"\n      >\n        I am a custom render function\n      </p>\n       \n      <button\n        class=\"storybook-button storybook-button--medium storybook-button--secondary\"\n        style=\"\"\n        type=\"button\"\n      >\n        foo\n         \n      </button>\n      <!--&lt;Button&gt;-->\n    </div>\n    <!--&lt;CustomRenderComponent&gt;-->\n    \n    \n    <!--&lt;SlotDecorator&gt;-->\n    <!--&lt;PreviewRender&gt;-->\n  </div>\n</body>\n`;\n\nexports[`Renders CSF3InputFieldFilled story 1`] = `\n<body>\n  <div>\n    <input\n      data-testid=\"input\"\n    />\n    <!--&lt;InputFilledStoryComponent&gt;-->\n    \n    \n    <!--&lt;SlotDecorator&gt;-->\n    <!--&lt;PreviewRender&gt;-->\n  </div>\n</body>\n`;\n\nexports[`Renders CSF3Primary story 1`] = `\n<body>\n  <div>\n    <button\n      class=\"storybook-button storybook-button--large storybook-button--primary\"\n      style=\"\"\n      type=\"button\"\n    >\n      foo\n       \n    </button>\n    <!--&lt;Button&gt;-->\n    \n    \n    <!--&lt;SlotDecorator&gt;-->\n    <!--&lt;PreviewRender&gt;-->\n  </div>\n</body>\n`;\n\nexports[`Renders LoaderStory story 1`] = `\n<body>\n  <div>\n    <div>\n      <div\n        data-testid=\"loaded-data\"\n      >\n        loaded data\n      </div>\n       \n      <div\n        data-testid=\"spy-data\"\n      >\n        mockFn return value\n      </div>\n    </div>\n    <!--&lt;LoaderStoryComponent&gt;-->\n    \n    \n    <!--&lt;SlotDecorator&gt;-->\n    <!--&lt;PreviewRender&gt;-->\n  </div>\n</body>\n`;\n\nexports[`Renders NewStory story 1`] = `\n<body>\n  <div>\n    <div\n      style=\"margin: 3em;\"\n    >\n      <button\n        class=\"storybook-button storybook-button--large storybook-button--primary\"\n        style=\"\"\n        type=\"button\"\n      >\n        foo\n         \n      </button>\n      <!--&lt;Button&gt;-->\n      \n    </div>\n    <!--&lt;AddWrapperDecorator&gt;-->\n    \n    \n    <!--&lt;SlotDecorator&gt;-->\n    \n    \n    <!--&lt;SlotDecorator&gt;-->\n    <!--&lt;PreviewRender&gt;-->\n  </div>\n</body>\n`;\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/stories/button.css",
    "content": ".storybook-button {\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n  font-weight: 700;\n  border: 0;\n  border-radius: 3em;\n  cursor: pointer;\n  display: inline-block;\n  line-height: 1;\n}\n.storybook-button--primary {\n  color: white;\n  background-color: #1ea7fd;\n}\n.storybook-button--secondary {\n  color: #333;\n  background-color: transparent;\n  box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;\n}\n.storybook-button--small {\n  font-size: 12px;\n  padding: 10px 16px;\n}\n.storybook-button--medium {\n  font-size: 14px;\n  padding: 11px 20px;\n}\n.storybook-button--large {\n  font-size: 16px;\n  padding: 12px 24px;\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/svelte.config.js",
    "content": "import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'\n\nexport default {\n  // Consult https://svelte.dev/docs#compile-time-svelte-preprocess\n  // for more information about preprocessors\n  preprocess: vitePreprocess(),\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/tsconfig.json",
    "content": "{\n  \"extends\": \"@tsconfig/svelte/tsconfig.json\",\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"useDefineForClassFields\": true,\n    \"module\": \"Preserve\",\n    \"resolveJsonModule\": true,\n    /**\n     * Typecheck JS in `.svelte` and `.js` files by default.\n     * Disable checkJs if you'd like to use dynamic types in JS.\n     * Note that setting allowJs false does not prevent the use\n     * of JS in `.svelte` files.\n     */\n    \"allowJs\": true,\n    \"checkJs\": true,\n    \"isolatedModules\": true\n  },\n  \"include\": [\"src/**/*.ts\", \"src/**/*.js\", \"src/**/*.svelte\"],\n  \"references\": [{ \"path\": \"./tsconfig.node.json\" }]\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/tsconfig.node.json",
    "content": "{\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"skipLibCheck\": true,\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"strict\": true\n  },\n  \"include\": [\"vite.config.ts\"]\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/svelte/vite.config.ts",
    "content": "import { defineConfig } from 'vitest/config'\nimport { svelte } from '@sveltejs/vite-plugin-svelte'\nimport { svelteTesting } from '@testing-library/svelte/vite'\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [svelte(), svelteTesting()],\n  test: {\n    environment: 'happy-dom'\n  }\n})\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/.eslintrc.cjs",
    "content": "module.exports = {\n  root: true,\n  env: { browser: true, es2020: true },\n  extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:react-hooks/recommended', 'plugin:storybook/recommended'],\n  ignorePatterns: ['dist', '.eslintrc.cjs'],\n  parser: '@typescript-eslint/parser',\n  plugins: ['react-refresh'],\n  rules: {\n    'react-refresh/only-export-components': [\n      'warn',\n      { allowConstantExport: true },\n    ],\n  },\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/.gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndist-ssr\n*.local\n\n# Editor directories and files\n.vscode/*\n!.vscode/extensions.json\n.idea\n.DS_Store\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n/test-results/\n/playwright-report/\n/blob-report/\n/playwright/.cache/\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/.storybook/main.ts",
    "content": "import type { StorybookConfig } from \"@storybook/vue3-vite\";\n\nconst config: StorybookConfig = {\n  stories: [\"../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)\"],\n  framework: {\n    name: \"@storybook/vue3-vite\",\n    options: {},\n  },\n};\nexport default config;\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/.storybook/preview.ts",
    "content": "import type { Preview } from '@storybook/vue3';\n\nconsole.log('preview file is called!');\n\nconst preview: Preview = {\n  // TODO: figure out decorators\n  decorators: [\n    () => ({ \n      template: `\n        <div data-decorator>\n          Global Decorator\n          <br />\n          <story />\n        </div>\n      `\n    })\n  ],\n  globalTypes: {\n    locale: {\n      description: 'Locale for components',\n      defaultValue: 'en',\n      toolbar: {\n        title: 'Locale',\n        icon: 'circlehollow',\n        items: ['es', 'en'],\n      },\n    },\n  },\n};\n\nexport default preview;\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/.yarnrc.yml",
    "content": "checksumBehavior: ignore\n\nenableGlobalCache: true\n\nnodeLinker: node-modules\n\nyarnPath: ../../../.yarn/releases/yarn-4.10.3.cjs\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/cypress/support/commands.ts",
    "content": "/// <reference types=\"cypress\" />\n// ***********************************************\n// This example commands.ts shows you how to\n// create various custom commands and overwrite\n// existing commands.\n//\n// For more comprehensive examples of custom\n// commands please read more here:\n// https://on.cypress.io/custom-commands\n// ***********************************************"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/cypress/support/component-index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n    <title>Components App</title>\n  </head>\n  <body>\n    <div data-cy-root></div>\n  </body>\n</html>"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/cypress/support/component.ts",
    "content": "/* eslint-disable @typescript-eslint/no-namespace */\n// ***********************************************************\n// This example support/component.ts is processed and\n// loaded automatically before your test files.\n//\n// This is a great place to put global configuration and\n// behavior that modifies Cypress.\n//\n// You can change the location of this file or turn off\n// automatically serving support files with the\n// 'supportFile' configuration option.\n//\n// You can read more here:\n// https://on.cypress.io/configuration\n// ***********************************************************\n\n// Import commands.js using ES2015 syntax:\nimport './commands'\n\nimport { mount } from 'cypress/vue'\n\nimport type { ProjectAnnotations } from 'storybook/internal/types';\nimport { VueRenderer, setProjectAnnotations } from '@storybook/vue3';\nimport sbAnnotations from '../../.storybook/preview';\n\n\n// Augment the Cypress namespace to include type definitions for\n// your custom command.\n// Alternatively, can be defined in cypress/support/component.d.ts\n// with a <reference path=\"./component\" /> at the top of your spec.\ndeclare global {\n  namespace Cypress {\n    interface Chainable {\n      mount: typeof mount\n    }\n  }\n}\n\nCypress.Commands.add('mount', mount)\n\n// This is needed because Cypress defines process but not process.env\n// And if the play function fails, testing library's internals have a check\n// for typeof process !== \"undefined\" && process.env.DEBUG_PRINT_LIMIT;\n// which will break\nprocess.env = {};\n\nsetProjectAnnotations([\n  sbAnnotations,\n]);\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/cypress.config.ts",
    "content": "import { defineConfig } from \"cypress\";\n\nexport default defineConfig({\n  screenshotOnRunFailure: false,\n  component: {\n    devServer: {\n      framework: \"vue\",\n      bundler: \"vite\",\n    },\n  },\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/package.json",
    "content": "{\n  \"name\": \"portable-stories-vue3\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"tsc && vite build\",\n    \"cypress\": \"cypress run --component\",\n    \"cypress-open\": \"cypress open --component\",\n    \"dev\": \"vite\",\n    \"jest\": \"echo 'Jest tests are not implemented!'\",\n    \"lint\": \"eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0\",\n    \"playwright-ct\": \"playwright test\",\n    \"preview\": \"vite preview\",\n    \"storybook\": \"STORYBOOK_TELEMETRY_URL=\\\"http://localhost:6007/event-log\\\" storybook dev -p 6006\",\n    \"vitest\": \"echo 'Vitest tests are implemented in the renderer directory instead!'\"\n  },\n  \"resolutions\": {\n    \"@playwright/test\": \"1.58.2\",\n    \"@storybook/addon-a11y\": \"file:../../../code/addons/a11y\",\n    \"@storybook/addon-docs\": \"file:../../../code/addons/docs\",\n    \"@storybook/addon-links\": \"file:../../../code/addons/links\",\n    \"@storybook/addon-themes\": \"file:../../../code/addons/themes\",\n    \"@storybook/angular\": \"file:../../../code/frameworks/angular\",\n    \"@storybook/builder-vite\": \"file:../../../code/builders/builder-vite\",\n    \"@storybook/builder-webpack5\": \"file:../../../code/builders/builder-webpack5\",\n    \"@storybook/codemod\": \"file:../../../code/lib/codemod\",\n    \"@storybook/core-webpack\": \"file:../../../code/lib/core-webpack\",\n    \"@storybook/csf-plugin\": \"file:../../../code/lib/csf-plugin\",\n    \"@storybook/ember\": \"file:../../../code/frameworks/ember\",\n    \"@storybook/html\": \"file:../../../code/renderers/html\",\n    \"@storybook/nextjs\": \"file:../../../code/frameworks/nextjs\",\n    \"@storybook/preact\": \"file:../../../code/renderers/preact\",\n    \"@storybook/preact-vite\": \"file:../../../code/frameworks/preact-vite\",\n    \"@storybook/preset-create-react-app\": \"file:../../../code/presets/create-react-app\",\n    \"@storybook/preset-react-webpack\": \"file:../../../code/presets/react-webpack\",\n    \"@storybook/preset-server-webpack\": \"file:../../../code/presets/server-webpack\",\n    \"@storybook/react\": \"file:../../../code/renderers/react\",\n    \"@storybook/react-dom-shim\": \"file:../../../code/lib/react-dom-shim\",\n    \"@storybook/react-vite\": \"file:../../../code/frameworks/react-vite\",\n    \"@storybook/react-webpack5\": \"file:../../../code/frameworks/react-webpack5\",\n    \"@storybook/server\": \"file:../../../code/renderers/server\",\n    \"@storybook/server-webpack5\": \"file:../../../code/frameworks/server-webpack5\",\n    \"@storybook/svelte\": \"file:../../../code/renderers/svelte\",\n    \"@storybook/svelte-vite\": \"file:../../../code/frameworks/svelte-vite\",\n    \"@storybook/sveltekit\": \"file:../../../code/frameworks/sveltekit\",\n    \"@storybook/vue3\": \"file:../../../code/renderers/vue3\",\n    \"@storybook/vue3-vite\": \"file:../../../code/frameworks/vue3-vite\",\n    \"@storybook/web-components\": \"file:../../../code/renderers/web-components\",\n    \"@storybook/web-components-vite\": \"file:../../../code/frameworks/web-components-vite\",\n    \"eslint-plugin-storybook\": \"file:../../../code/lib/eslint-plugin\",\n    \"playwright\": \"1.58.2\",\n    \"storybook\": \"file:../../../code/core\"\n  },\n  \"dependencies\": {\n    \"vue\": \"^3.4.19\"\n  },\n  \"devDependencies\": {\n    \"@playwright/experimental-ct-vue\": \"1.58.2\",\n    \"@storybook/vue3\": \"^8.0.0\",\n    \"@storybook/vue3-vite\": \"^8.0.0\",\n    \"@testing-library/jest-dom\": \"^6.6.3\",\n    \"@typescript-eslint/eslint-plugin\": \"^6.21.0\",\n    \"@typescript-eslint/parser\": \"^6.21.0\",\n    \"@vitejs/plugin-vue\": \"^5.0.4\",\n    \"cypress\": \"^13.6.4\",\n    \"eslint\": \"^8.56.0\",\n    \"eslint-plugin-storybook\": \"^0.6.15\",\n    \"storybook\": \"^8.0.0\",\n    \"typescript\": \"^5.2.2\",\n    \"vite\": \"^5.1.1\"\n  },\n  \"nx\": {\n    \"includedScripts\": []\n  }\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/playwright/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"UTF-8\" />\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n  <title>Testing Page</title>\n</head>\n\n<body>\n  <div id=\"root\"></div>\n  <script type=\"module\" src=\"./index.ts\"></script>\n</body>\n\n</html>"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/playwright/index.ts",
    "content": "import { setProjectAnnotations } from '@storybook/vue3'\nimport sbAnnotations from '../.storybook/preview'\n\nsetProjectAnnotations([\n  sbAnnotations,\n]);\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/playwright.config.ts",
    "content": "import { defineConfig, devices } from '@playwright/experimental-ct-vue';\n\n/**\n * See https://playwright.dev/docs/test-configuration.\n */\nexport default defineConfig({\n  testDir: 'stories',\n  testMatch: '*.playwright.tsx',\n  /* The base directory, relative to the config file, for snapshot files created with toMatchSnapshot and toHaveScreenshot. */\n  snapshotDir: './__snapshots__',\n  outputDir: './test-results',\n  /* Maximum time one test can run for. */\n  timeout: 10 * 1000,\n  /* Run tests in files in parallel */\n  fullyParallel: true,\n  /* Fail the build on CI if you accidentally left test.only in the source code. */\n  forbidOnly: !!process.env.CI,\n  /* Retry on CI only */\n  retries: process.env.CI ? 2 : 0,\n  /* Opt out of parallel tests on CI. */\n  workers: process.env.CI ? 1 : undefined,\n  /* Reporter to use. See https://playwright.dev/docs/test-reporters */\n  reporter: 'line',\n  /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */\n  use: {\n    /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */\n    trace: 'on-first-retry',\n\n    /* Port to use for Playwright component endpoint. */\n    ctPort: 3100,\n    ctViteConfig: {\n      resolve: {\n        alias: {\n          vue: 'vue/dist/vue.esm-bundler.js',\n        },\n      },\n    }\n  },\n\n  /* Configure projects for major browsers */\n  projects: [\n    {\n      name: 'chromium',\n      use: { ...devices['Desktop Chrome'] },\n    },\n    // {\n    //   name: 'firefox',\n    //   use: { ...devices['Desktop Firefox'] },\n    // },\n    // {\n    //   name: 'webkit',\n    //   use: { ...devices['Desktop Safari'] },\n    // },\n  ],\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/project.json",
    "content": "{\n  \"name\": \"portable-stories-kitchen-sink/vue3\",\n  \"$schema\": \"../../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"application\",\n  \"targets\": {\n    \"jest\": {},\n    \"vitest\": {},\n    \"playwright-ct\": {},\n    \"cypress\": {}\n  },\n  \"tags\": [\"ci:normal\", \"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/stories/Button.cy.tsx",
    "content": "/// <reference types=\"cypress\"/>\nimport * as stories from './Button.stories';\nimport { composeStories } from '@storybook/vue3';\n\nconst { CSF3Primary, WithLoader, CSF3InputFieldFilled } = composeStories(stories)\n\ndescribe('<Button()', () => {\n  it('renders primary button', async () => {\n    cy.mount(CSF3Primary())\n    cy.get('button').should('contain.text', 'foo');\n    cy.get('[data-decorator]').should('exist');\n  })\n\n  it('renders primary button with custom args', async () => {\n    cy.mount(CSF3Primary({ label: 'bar' }))\n    cy.get('button').should('contain.text', 'bar');\n  })\n\n  it.skip('renders with loaders and play function', () => {\n    cy.then(async() => {\n      await WithLoader.load();\n    });\n\n    cy.mount(WithLoader());\n\n    cy.then(async() => {\n      await WithLoader.play!({ canvasElement: document.querySelector('[data-cy-root]') as HTMLElement });\n    });\n\n    cy.get('[data-testid=\"loaded-data\"]').should('contain.text', 'bar');\n    cy.get('[data-testid=\"mock-data\"]').should('contain.text', 'mockFn return value');\n  })\n\n  it.skip('renders with play function', () => {\n    cy.mount(CSF3InputFieldFilled());\n\n    cy.then(async() => {\n      await CSF3InputFieldFilled.play!({ canvasElement: document.querySelector('[data-cy-root]') as HTMLElement });\n      cy.get('[data-testid=\"input\"]').should('contain.value', 'Hello world!');\n    });\n  })\n})\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/stories/Button.playwright.tsx",
    "content": "import { test as base, expect } from '@playwright/experimental-ct-vue';\nimport { createTest } from '@storybook/vue3/experimental-playwright';\nimport stories, { SingleComposedStory, WithSpanishGlobal } from './Button.stories.portable';\n\nconst test = createTest(base);\n\ntest('renders with composeStories (plural)', async ({ mount }) => {\n  const component = await mount(<stories.CSF3Primary />);\n  await expect(component).toContainText('Global Decorator');\n  await expect(component).toContainText('foo'); // default arg for the story\n});\n\ntest('renders with composeStory (singular)', async ({ mount }) => {\n  const component = await mount(<SingleComposedStory />);\n  await expect(component).toContainText('Global Decorator');\n  await expect(component).toContainText('foo'); // default arg for the story\n});\n\ntest('renders story with props as second argument', async ({ mount }) => {\n  const component = await mount(<stories.CSF3Button primary={true} label=\"label from test\" />);\n  await expect(component).toContainText('label from test');\n  await expect(component.getByRole('button')).toHaveClass(/storybook-button--primary/);\n});\n\ntest('renders story with custom render', async ({ mount }) => {\n  const component = await mount(<stories.CSF3ButtonWithRender />);\n  await expect(component.getByTestId('custom-render')).toContainText('I am a custom render function');\n  await expect(component.getByRole('button')).toHaveText('foo');\n});\n\ntest('renders story with global annotations', async ({ mount }) => {\n  const component = await mount(<WithSpanishGlobal />);\n  await expect(component).toContainText('Hola!');\n});\n\ntest('calls loaders', async ({ mount }) => {\n  const component = await mount(<stories.WithLoader />);\n  await expect(component.getByTestId('loaded-data')).toContainText('loaded data');\n  await expect(component.getByTestId('mock-data')).toContainText('mockFn return value');\n});\n\ntest('calls play', async ({ mount }) => {\n  const component = await mount(<stories.CSF3InputFieldFilled />);\n  await expect(component.getByTestId('input')).toHaveValue('Hello world!');\n});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/stories/Button.stories.portable.ts",
    "content": "import { composeStories, composeStory } from '@storybook/vue3';\nimport * as stories from './Button.stories';\n\nexport default composeStories(stories);\n\nexport const SingleComposedStory = composeStory(stories.CSF3Primary, stories.default);\n\nexport const WithSpanishGlobal = composeStory(stories.CSF2StoryWithLocale, stories.default, {initialGlobals: { locale: 'es' }});\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/stories/Button.stories.ts",
    "content": "import { userEvent, within, expect, fn } from 'storybook/test';\nimport type { Meta, StoryFn as CSF2Story, StoryObj } from '@storybook/vue3';\n\nimport Button from './Button.vue';\n\nconst meta = {\n  title: 'Example/Button',\n  component: Button,\n  argTypes: {\n    size: { control: 'select', options: ['small', 'medium', 'large'] },\n    backgroundColor: { control: 'color' },\n    onClick: { action: 'clicked' },\n  },\n  args: { primary: false },\n  excludeStories: /.*ImNotAStory$/,\n} as Meta<typeof Button>;\n\nexport default meta;\ntype CSF3Story = StoryObj<typeof meta>;\n\n// For testing purposes. Should be ignored in ComposeStories\nexport const ImNotAStory = 123;\n\nconst Template: CSF2Story = (args) => ({\n  components: { Button },\n  setup() {\n    return { args };\n  },\n  template: '<Button v-bind=\"args\" />',\n});\n\nexport const CSF2Secondary = Template.bind({});\nCSF2Secondary.args = {\n  label: 'label coming from story args!',\n  primary: false,\n};\n\nconst getCaptionForLocale = (locale: string) => {\n  switch (locale) {\n    case 'es':\n      return 'Hola!';\n    case 'fr':\n      return 'Bonjour!';\n    case 'kr':\n      return '안녕하세요!';\n    case 'pt':\n      return 'Olá!';\n    case 'en':\n      return 'Hello!';\n    default:\n      return undefined;\n  }\n};\n\nexport const CSF2StoryWithLocale: CSF2Story = (args, { globals }) => ({\n  components: { Button },\n  setup() {\n    const label = getCaptionForLocale(globals.locale);\n    return { args: { ...args, label } };\n  },\n  template: `<div>\n    <p>locale: ${globals.locale}</p>\n    <Button v-bind=\"args\" label=\"${getCaptionForLocale(globals.locale)}\" />\n  </div>`,\n});\nCSF2StoryWithLocale.storyName = 'WithLocale';\n\nexport const CSF2StoryWithParamsAndDecorator = Template.bind({});\nCSF2StoryWithParamsAndDecorator.args = {\n  label: 'foo',\n};\nCSF2StoryWithParamsAndDecorator.parameters = {\n  layout: 'centered',\n};\nCSF2StoryWithParamsAndDecorator.decorators = [\n  () => ({ template: '<div style=\"margin: 3em;\"><story/></div>' }),\n];\n\nexport const CSF3Primary: CSF3Story = {\n  args: {\n    label: 'foo',\n    size: 'large',\n    primary: true,\n  },\n};\n\nexport const CSF3Button: CSF3Story = {\n  args: { label: 'foo' },\n};\n\nexport const CSF3ButtonWithRender: CSF3Story = {\n  ...CSF3Button,\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      console.log('hello')\n      return { args };\n    },\n    template: `\n      <div>\n        <p data-testid=\"custom-render\">I am a custom render function</p>\n        <Button v-bind=\"args\" />\n      </div>\n    `,\n  }),\n};\n\nexport const CSF3InputFieldFilled: CSF3Story = {\n  ...CSF3Button,\n  render: (args) => ({\n    components: { Button },\n    setup() {\n      return { args };\n    },\n    template: '<input data-testid=\"input\" />',\n  }),\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement);\n    await step('Step label', async () => {\n      const inputEl = canvas.getByTestId('input');\n      await userEvent.type(inputEl, 'Hello world!');\n      await expect(inputEl).toHaveValue('Hello world!');\n    });\n  },\n};\n\nconst mockFn = fn();\nexport const WithLoader: StoryObj<{ mockFn: (val: string) => string }> = {\n  args: {\n    mockFn,\n  },\n  loaders: [\n    async () => {\n      mockFn.mockReturnValueOnce('mockFn return value');\n      return {\n        value: 'loaded data',\n      };\n    },\n  ],\n  render: (args, { loaded }) => ({\n    components: { Button },\n    setup() {\n      return { args, data: args.mockFn('render'), loaded: loaded.value };\n    },\n    template: `\n      <div>\n        <div data-testid=\"loaded-data\">{{loaded}}</div>\n        <div data-testid=\"mock-data\">{{data}}</div>\n      </div>\n    `,\n  }),\n  play: async () => {\n    expect(mockFn).toHaveBeenCalledWith('render');\n  },\n};\n\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/stories/Button.vue",
    "content": "<template>\n  <button type=\"button\" :class=\"classes\" :style=\"style\" @click=\"emit('myClickEvent', 0)\">\n    {{ label }}\n  </button>\n</template>\n\n<script lang=\"ts\" setup>\nimport { computed } from 'vue';\nimport './button.css';\n\nconst props = withDefaults(\n  defineProps<{\n    /**\n     * The label of the button\n     */\n    label: string;\n    /**\n     * primary or secondary button\n     */\n    primary?: boolean;\n    /**\n     * size of the button\n     */\n    size?: 'small' | 'medium' | 'large';\n    /**\n     * background color of the button\n     */\n    backgroundColor?: string;\n  }>(),\n  { primary: false }\n);\n\nconst emit = defineEmits<{\n  (e: 'myClickEvent', id: number): void;\n}>();\n\nconst classes = computed(() => ({\n  'storybook-button': true,\n  'storybook-button--primary': props.primary,\n  'storybook-button--secondary': !props.primary,\n  [`storybook-button--${props.size || 'medium'}`]: true,\n}));\n\nconst style = computed(() => ({\n  backgroundColor: props.backgroundColor,\n}));\n</script>\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/stories/button.css",
    "content": ".storybook-button {\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n  font-weight: 700;\n  border: 0;\n  border-radius: 3em;\n  cursor: pointer;\n  display: inline-block;\n  line-height: 1;\n}\n.storybook-button--primary {\n  color: white;\n  background-color: #1ea7fd;\n}\n.storybook-button--secondary {\n  color: #333;\n  background-color: transparent;\n  box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;\n}\n.storybook-button--small {\n  font-size: 12px;\n  padding: 10px 16px;\n}\n.storybook-button--medium {\n  font-size: 14px;\n  padding: 11px 20px;\n}\n.storybook-button--large {\n  font-size: 16px;\n  padding: 12px 24px;\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"],\n    \"module\": \"ESNext\",\n    \"skipLibCheck\": true,\n\n    /* Bundler mode */\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"noEmit\": true,\n    \"jsx\": \"preserve\",\n    \"jsxImportSource\": \"vue\",\n\n    /* Linting */\n    \"strict\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"noFallthroughCasesInSwitch\": true\n  },\n  \"include\": [\"stories\", \"playwright\", \"cypress\"],\n  \"references\": [{ \"path\": \"./tsconfig.node.json\" }]\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/tsconfig.node.json",
    "content": "{\n  \"compilerOptions\": {\n    \"composite\": true,\n    \"skipLibCheck\": true,\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"allowSyntheticDefaultImports\": true,\n    \"strict\": true\n  },\n  \"include\": [\"vite.config.ts\"]\n}\n"
  },
  {
    "path": "test-storybooks/portable-stories-kitchen-sink/vue3/vite.config.ts",
    "content": "import { defineConfig } from 'vite'\nimport vue from '@vitejs/plugin-vue'\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [vue()],\n})\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/.storybook/main.ts",
    "content": "import type { StorybookConfig } from '@storybook/server-webpack5';\n\nconst mainConfig: StorybookConfig = {\n  stories: ['../stories/**/*.stories.@(json|yaml|yml)'],\n  logLevel: 'debug',\n  addons: [\n    '@storybook/addon-docs',\n    '@storybook/addon-a11y',\n    '@storybook/addon-links'\n  ],\n  core: {\n    disableTelemetry: true,\n  },\n  features: {},\n  framework: '@storybook/server-webpack5',\n};\n\nmodule.exports = mainConfig;\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/.storybook/preview.js",
    "content": "import { withLinks } from '@storybook/addon-links';\n\nexport const decorators = [withLinks];\n\nconst port = process.env.STORYBOOK_SERVER_PORT || 1337;\n\nexport const parameters = {\n  docs: {\n    story: { iframeHeight: '200px' },\n  },\n  server: {\n    url: `http://localhost:${port}/storybook_preview`,\n  },\n};\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/.yarnrc.yml",
    "content": "nodeLinker: node-modules\nenableImmutableInstalls: false\nyarnPath: ../../.yarn/releases/yarn-4.10.3.cjs\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/README.md",
    "content": "# Server Kitchen Sink\n\nThis is a demo app to test a standalone server using integration with Storybook using `@storybook/server`.\n\nRun `yarn install` to sync Storybook module with the source.\n\nRun `yarn start` to start.\n\nThis starts an ExpressJS server on port `1337` and Storybook on port `9006`.\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/package.json",
    "content": "{\n  \"name\": \"server-kitchen-sink\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"description\": \"\",\n  \"keywords\": [],\n  \"license\": \"MIT\",\n  \"author\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"build-storybook\": \"NODE_OPTIONS=\\\"--preserve-symlinks --preserve-symlinks-main\\\" storybook build\",\n    \"server\": \"PORT=1137 nodemon server.js\",\n    \"start\": \"concurrently \\\"yarn server\\\" \\\"yarn storybook\\\"\",\n    \"storybook\": \"STORYBOOK_SERVER_PORT=1137 NODE_OPTIONS=\\\"--preserve-symlinks --preserve-symlinks-main\\\" storybook dev -p 9006 --quiet\"\n  },\n  \"resolutions\": {\n    \"@storybook/addon-a11y\": \"file:../../code/addons/a11y\",\n    \"@storybook/addon-docs\": \"file:../../code/addons/docs\",\n    \"@storybook/addon-links\": \"file:../../code/addons/links\",\n    \"@storybook/addon-themes\": \"file:../../code/addons/themes\",\n    \"@storybook/angular\": \"file:../../code/frameworks/angular\",\n    \"@storybook/builder-vite\": \"file:../../code/builders/builder-vite\",\n    \"@storybook/builder-webpack5\": \"file:../../code/builders/builder-webpack5\",\n    \"@storybook/codemod\": \"file:../../code/lib/codemod\",\n    \"@storybook/core-webpack\": \"file:../../code/lib/core-webpack\",\n    \"@storybook/csf-plugin\": \"file:../../code/lib/csf-plugin\",\n    \"@storybook/ember\": \"file:../../code/frameworks/ember\",\n    \"@storybook/html\": \"file:../../code/renderers/html\",\n    \"@storybook/nextjs\": \"file:../../code/frameworks/nextjs\",\n    \"@storybook/preact\": \"file:../../code/renderers/preact\",\n    \"@storybook/preact-vite\": \"file:../../code/frameworks/preact-vite\",\n    \"@storybook/preset-create-react-app\": \"file:../../code/presets/create-react-app\",\n    \"@storybook/preset-react-webpack\": \"file:../../code/presets/react-webpack\",\n    \"@storybook/preset-server-webpack\": \"file:../../code/presets/server-webpack\",\n    \"@storybook/react\": \"file:../../code/renderers/react\",\n    \"@storybook/react-dom-shim\": \"file:../../code/lib/react-dom-shim\",\n    \"@storybook/react-vite\": \"file:../../code/frameworks/react-vite\",\n    \"@storybook/react-webpack5\": \"file:../../code/frameworks/react-webpack5\",\n    \"@storybook/server\": \"file:../../code/renderers/server\",\n    \"@storybook/server-webpack5\": \"file:../../code/frameworks/server-webpack5\",\n    \"@storybook/svelte\": \"file:../../code/renderers/svelte\",\n    \"@storybook/svelte-vite\": \"file:../../code/frameworks/svelte-vite\",\n    \"@storybook/sveltekit\": \"file:../../code/frameworks/sveltekit\",\n    \"@storybook/vue3\": \"file:../../code/renderers/vue3\",\n    \"@storybook/vue3-vite\": \"file:../../code/frameworks/vue3-vite\",\n    \"@storybook/web-components\": \"file:../../code/renderers/web-components\",\n    \"@storybook/web-components-vite\": \"file:../../code/frameworks/web-components-vite\",\n    \"storybook\": \"file:../../code/core\"\n  },\n  \"devDependencies\": {\n    \"@storybook/addon-a11y\": \"*\",\n    \"@storybook/addon-links\": \"*\",\n    \"@storybook/server\": \"*\",\n    \"@storybook/server-webpack5\": \"*\",\n    \"concurrently\": \"^5.3.0\",\n    \"cors\": \"^2.8.5\",\n    \"express\": \"^4.19.2\",\n    \"morgan\": \"^1.10.0\",\n    \"nodemon\": \"^2.0.7\",\n    \"pug\": \"^3.0.0\",\n    \"safe-identifier\": \"^0.4.1\",\n    \"storybook\": \"*\"\n  }\n}\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/public/css/button.css",
    "content": "button {\n  color: red;\n}\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/public/js/alert.js",
    "content": "function triggerAlert() {\n  // eslint-disable-next-line no-alert, no-undef\n  alert('hello');\n}\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/server.js",
    "content": "const express = require('express');\nconst cors = require('cors');\nconst morgan = require('morgan');\nconst path = require('path');\nconst { logger } = require('storybook/internal/node-logger');\n\nconst port = process.env.PORT || 8080;\n\nconst app = express();\napp.use(cors());\napp.use(morgan('dev'));\napp.use(express.static(path.join(__dirname, 'public')));\napp.set('views', path.join(__dirname, 'views'));\napp.set('view engine', 'pug');\n\napp.get('/', (req, res) => res.send('Hello World!'));\n\napp.get(/storybook_preview\\/(.*)/, (req, res) => {\n  res.render(req.params[0], req.query);\n});\n\napp.listen(port, () => logger.info(`Server listening on port ${port}!`));\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/stories/addons/actions.stories.json",
    "content": "{\n  \"parameters\": {\n    \"options\": { \"selectedPanel\": \"storybook/actions/panel\" }\n  },\n  \"stories\": [\n    {\n      \"name\": \"Hello World\",\n      \"parameters\": {\n        \"server\": { \"id\": \"addons/actions/story1\" },\n        \"actions\": {\n          \"handles\": [\"click\"]\n        }\n      }\n    },\n    {\n      \"name\": \"Multiple actions\",\n      \"parameters\": {\n        \"server\": { \"id\": \"addons/actions/story2\" },\n        \"actions\": {\n          \"handles\": [\"click\", \"contextmenu\"]\n        }\n      }\n    },\n    {\n      \"name\": \"Multiple actions + config\",\n      \"parameters\": {\n        \"server\": { \"id\": \"addons/actions/story3\" },\n        \"actions\": {\n          \"handles\": [\"click\", \"contextmenu\", { \"clearOnStoryChange\": false }]\n        }\n      }\n    },\n    {\n      \"name\": \"Multiple actions, object\",\n      \"parameters\": {\n        \"server\": { \"id\": \"addons/actions/story4\" },\n        \"actions\": {\n          \"handles\": [{ \"click\": \"clicked\", \"contextmenu\": \"right clicked\" }]\n        }\n      }\n    },\n    {\n      \"name\": \"Multiple actions, object + config\",\n      \"parameters\": {\n        \"server\": { \"id\": \"addons/actions/story6\" },\n        \"actions\": {\n          \"handles\": [\n            { \"click\": \"clicked\", \"contextmenu\": \"right clicked\" },\n            { \"clearOnStoryChange\": false }\n          ]\n        }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/stories/addons/backgrounds.stories.json",
    "content": "{\n  \"parameters\": {\n    \"backgrounds\": {\n      \"default\": \"dark\",\n      \"values\": [\n        { \"name\": \"light\", \"value\": \"#eeeeee\" },\n        { \"name\": \"dark\", \"value\": \"#222222\", \"default\": true }\n      ]\n    }\n  },\n  \"stories\": [\n    {\n      \"name\": \"Story 1\",\n      \"parameters\": {\n        \"server\": { \"id\": \"addons/backgrounds/story1\" }\n      }\n    },\n    {\n      \"name\": \"Story 2\",\n      \"parameters\": {\n        \"server\": { \"id\": \"addons/backgrounds/story2\" }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/stories/addons/controls.stories.json",
    "content": "{\n  \"parameters\": {\n    \"options\": { \"selectedPanel\": \"storybook/controls/panel\" }\n  },\n  \"stories\": [\n    {\n      \"name\": \"Simple\",\n      \"parameters\": {\n        \"server\": { \"id\": \"addons/controls/simple\" }\n      },\n      \"args\": { \"name\": \"John Doe\", \"age\": 44 }\n    },\n    {\n      \"name\": \"CSS transitions\",\n      \"parameters\": {\n        \"server\": { \"id\": \"addons/controls/css\" }\n      },\n      \"args\": { \"name\": \"John Doe\", \"color\": \"orangered\" },\n      \"argTypes\": {\n        \"color\": { \"control\": { \"type\": \"color\" } }\n      }\n    },\n    {\n      \"name\": \"All Controls\",\n      \"parameters\": {\n        \"server\": { \"id\": \"addons/controls/all\" }\n      },\n      \"args\": {\n        \"name\": \"Jane\",\n        \"stock\": 20,\n        \"fruit\": \"apples\",\n        \"price\": 2.25,\n        \"colour\": \"deeppink\",\n        \"today\": \"Jan 20 2017 GMT+0\",\n        \"items\": [\"Laptop\", \"Book\", \"Whiskey\"],\n        \"nice\": true,\n        \"other\": { \"hair\": \"brown\", \"eyes\": \"blue\" }\n      },\n      \"argTypes\": {\n        \"stock\": { \"control\": { \"type\": \"range\", \"min\": 0, \"max\": 30, \"step\": 5 } },\n        \"fruit\": {\n          \"options\": [\"apples\", \"bananas\", \"cherries\"],\n          \"control\": {\n            \"type\": \"select\",\n            \"labels\": {\n              \"apples\": \"Apple\",\n              \"bananas\": \"Banana\",\n              \"cherries\": \"Cherry\"\n            }\n          }\n        },\n        \"colour\": { \"control\": { \"type\": \"color\" } },\n        \"today\": { \"control\": { \"type\": \"date\" } }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/stories/demo.stories.json",
    "content": "{\n  \"stories\": [\n    {\n      \"name\": \"Heading\",\n      \"parameters\": {\n        \"server\": { \"id\": \"demo/heading\" }\n      }\n    },\n    {\n      \"name\": \"Headings\",\n      \"parameters\": {\n        \"server\": { \"id\": \"demo/headings\" }\n      }\n    },\n    {\n      \"name\": \"Button\",\n      \"parameters\": {\n        \"server\": { \"id\": \"demo/button\" }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/stories/html_content/scripts.stories.json",
    "content": "{\n  \"stories\": [\n    {\n      \"name\": \"Head Inline\",\n      \"parameters\": {\n        \"server\": { \"id\": \"scripts/head_inline\" }\n      }\n    },\n    {\n      \"name\": \"Head Src\",\n      \"parameters\": {\n        \"server\": { \"id\": \"scripts/head_src\" }\n      }\n    },\n    {\n      \"name\": \"Body Inline\",\n      \"parameters\": {\n        \"server\": { \"id\": \"scripts/body_inline\" }\n      }\n    },\n    {\n      \"name\": \"Body Src\",\n      \"parameters\": {\n        \"server\": { \"id\": \"scripts/body_src\" }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/stories/html_content/styles.stories.json",
    "content": "{\n  \"stories\": [\n    {\n      \"name\": \"Head Inline\",\n      \"parameters\": {\n        \"server\": { \"id\": \"styles/head_inline\" }\n      }\n    },\n    {\n      \"name\": \"Head Src\",\n      \"parameters\": {\n        \"server\": { \"id\": \"styles/head_src\" }\n      }\n    },\n    {\n      \"name\": \"Body Inline\",\n      \"parameters\": {\n        \"server\": { \"id\": \"styles/body_inline\" }\n      }\n    },\n    {\n      \"name\": \"Body Src\",\n      \"parameters\": {\n        \"server\": { \"id\": \"styles/body_src\" }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/stories/kitchen_sink.stories.json",
    "content": "{\n  \"addons\": [\"knobs\"],\n  \"parameters\": {\n    \"backgrounds\": {\n      \"default\": \"light\",\n      \"values\": [\n        { \"name\": \"light\", \"value\": \"#eeeeee\" },\n        { \"name\": \"dark\", \"value\": \"#222222\" }\n      ]\n    },\n    \"options\": { \"selectedPanel\": \"storybook/a11y/panel\" },\n    \"server\": {\n      \"params\": { \"name\": \"Jane Doe\" }\n    }\n  },\n  \"stories\": [\n    {\n      \"name\": \"All the things\",\n      \"parameters\": {\n        \"notes\": \"My notes on some person\",\n        \"server\": {\n          \"id\": \"addons/controls/simple\",\n          \"params\": {\n            \"name\": \"Jim Doe\"\n          }\n        },\n        \"actions\": [\"click\", \"contextmenu\", { \"clearOnStoryChange\": false }]\n      },\n      \"args\": { \"name\": \"John Doe\", \"age\": 44 }\n    }\n  ]\n}\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/stories/params.stories.json",
    "content": "{\n  \"parameters\": {\n    \"server\": {\n      \"params\": { \"color\": \"red\" }\n    }\n  },\n  \"stories\": [\n    {\n      \"name\": \"Story\",\n      \"parameters\": {\n        \"server\": {\n          \"id\": \"params/story\",\n          \"params\": { \"message\": \"Hello World\" }\n        }\n      }\n    },\n    {\n      \"name\": \"Override\",\n      \"parameters\": {\n        \"server\": {\n          \"id\": \"params/override\",\n          \"params\": { \"message\": \"Hello World\", \"color\": \"green\" }\n        }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/stories/welcome.stories.json",
    "content": "{\n  \"stories\": [\n    {\n      \"name\": \"Welcome\",\n      \"parameters\": {\n        \"server\": {\n          \"id\": \"welcome/welcome\"\n        }\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/stories/yaml.stories.yaml",
    "content": "stories:\n  - name: Heading\n    parameters:\n      server:\n        id: yaml/heading\n  - name: Headings\n    parameters:\n      server:\n        id: yaml/headings\n  - name: Button\n    parameters:\n      server:\n        id: yaml/button\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/stories/yml.stories.yml",
    "content": "stories:\n  - name: Heading\n    parameters:\n      server:\n        id: yaml/heading\n  - name: Headings\n    parameters:\n      server:\n        id: yaml/headings\n  - name: Button\n    parameters:\n      server:\n        id: yaml/button\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/addons/a11y/contrast.pug",
    "content": "button(style='color: black; background-color: brown;') Testing the a11y addon"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/addons/a11y/default.pug",
    "content": "button"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/addons/a11y/disabled.pug",
    "content": "button(disabled) Testing the a11y addon"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/addons/a11y/label.pug",
    "content": "button Testing the a11y addon"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/addons/actions/button.pug",
    "content": "button(type=\"button\") Hello World"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/addons/actions/story1.pug",
    "content": "include button.pug"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/addons/actions/story2.pug",
    "content": "include button.pug"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/addons/actions/story3.pug",
    "content": "include button.pug"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/addons/actions/story4.pug",
    "content": "include button.pug"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/addons/actions/story5.pug",
    "content": "div\n  | Clicks on this button will be logged:\n  button(class=\"btn\" type=\"button\") Button"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/addons/actions/story6.pug",
    "content": "include button.pug"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/addons/actions/story7.pug",
    "content": "include button.pug"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/addons/actions/story8.pug",
    "content": "include button.pug"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/addons/backgrounds/story1.pug",
    "content": "span(style=\"color: white\") You should be able to switch backgrounds for this story"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/addons/backgrounds/story2.pug",
    "content": "span(style=\"color: white\") This one too!"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/addons/controls/all.pug",
    "content": "- nice = (nice === 'true')\n- stock = parseInt(stock)\n- stockMessage = stock > 0 ? `I have a stock of ${stock} ${fruit}, costing &dollar;${price} each.` : `I'm out of ${fruit}${nice ? ', Sorry!' : '.'}`;\n- salutation = nice ? 'Nice to meet you!' : 'Leave me alone!';\n- dateOptions = { year: 'numeric', month: 'long', day: 'numeric', timeZone: 'UTC' };\n- style = `border: 2px dotted ${colour}; padding: 8px 22px; border-radius: 8px`;\n- today = new Date(today);\n- items = JSON.parse(tems);\n- other = JSON.parse(other);\n\ndiv(style=`${style}`)\n  h1 My name is #{name},\n  h3 today is #{today.toLocaleDateString('en-US', dateOptions)}\n  p !{stockMessage}\n  p Also, I have:\n  ul \n    each item in items\n      li= item\n  p Other things about me: \n    ul \n      each key in Object.keys(other)\n        li= `${key}: ${other[key]}`\n  p #{salutation}"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/addons/controls/css.pug",
    "content": "p(style=`transition: color 0.5s ease-out; color: ${textColor}`)= name"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/addons/controls/simple.pug",
    "content": "div.\n  I am #{name} and I'm #{age} years old."
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/addons/controls/xss_safety.pug",
    "content": " !{content}"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/demo/button.pug",
    "content": "button Hello Button"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/demo/heading.pug",
    "content": "h1 Hello World"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/demo/headings.pug",
    "content": "h1 Hellow World\nh2 Hellow World\nh3 Hellow World\nh4 Hellow World"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/params/override.pug",
    "content": "include params.pug"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/params/params.pug",
    "content": "h1(style=`color: ${color}`)= message "
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/params/story.pug",
    "content": "include params.pug"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/params/story_fn_override.pug",
    "content": "include params.pug"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/scripts/body_inline.pug",
    "content": "include includes/button.pug\ninclude includes/alert_script_inline.pug\n\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/scripts/body_src.pug",
    "content": "include includes/button.pug\ninclude includes/alert_script_src.pug\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/scripts/head_inline.pug",
    "content": "\ndoctype html\nhtml\n  head \n    include includes/alert_script_inline.pug\n  body\n    include includes/button.pug\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/scripts/head_src.pug",
    "content": "\ndoctype html\nhtml\n  head \n    include includes/alert_script_src.pug\n  body\n    include includes/button.pug\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/scripts/includes/alert_script_inline.pug",
    "content": "script.\n  function triggerAlert() {\n    alert('hello');\n  }"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/scripts/includes/alert_script_src.pug",
    "content": "script(src='http://localhost:1337/js/alert.js')"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/scripts/includes/button.pug",
    "content": "button(onclick='triggerAlert()') Hello Button"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/styles/body_inline.pug",
    "content": "include includes/button.pug\ninclude includes/button_styles_inline.pug\n\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/styles/body_src.pug",
    "content": "include includes/button.pug\ninclude includes/button_styles_src.pug\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/styles/head_inline.pug",
    "content": "\ndoctype html\nhtml\n  head \n    include includes/button_styles_inline.pug\n  body\n    include includes/button.pug\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/styles/head_src.pug",
    "content": "\ndoctype html\nhtml\n  head \n    include includes/button_styles_src.pug\n  body\n    include includes/button.pug\n"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/styles/includes/button.pug",
    "content": "button Hello Button"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/styles/includes/button_styles_inline.pug",
    "content": "style.\n  button {\n    color: red;\n  }"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/styles/includes/button_styles_src.pug",
    "content": "link(rel='stylesheet', type='text/css' href='http://localhost:1337/css/button.css')"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/welcome/welcome.pug",
    "content": ".main\n  h1 Welcome to Storybook for Server\n  p This is a UI component dev environment for your plain HTML snippets.\n  p.\n    We've added some basic stories inside the #[code.code stories] directory.\n    #[br]\n    A story is a single state of one or more UI components. You can have as many stories as you want.\n    #[br]\n    (Basically a story is like a visual test case.)\n  p.\n    See these sample #[a.link(href='#' data-sb-kind='Demo' data-sb-story='Headings') stories]\n  p.\n    Just like that, you can add your own snippets as stories.\n    #[br]\n    You can also edit those snippets and see changes right away.\n    #[br]\n  p.\n    Usually we create stories with smaller UI components in the app.\n    #[br]\n    Have a look at the #[a.link(href='https://storybook.js.org/basics/writing-stories' target='_blank') Writing Stories] section in our documentation.\nstyle.\n  .main {\n    padding: 15px;\n    line-height: 1.4;\n    font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;\n    background-color: #ffffff;\n  }\n  .code {\n    font-size: 15px;\n    font-weight: 600;\n    padding: 2px 5px;\n    border: 1px solid #eae9e9;\n    border-radius: 4px;\n    background-color: #f3f2f2;\n    color: #3a3a3a;\n  }"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/yaml/button.pug",
    "content": "button Hello Button"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/yaml/heading.pug",
    "content": "h1 Hello World"
  },
  {
    "path": "test-storybooks/server-kitchen-sink/views/yaml/headings.pug",
    "content": "h1 Hellow World\nh2 Hellow World\nh3 Hellow World\nh4 Hellow World"
  },
  {
    "path": "test-storybooks/standalone-preview/.babelrc.js",
    "content": "module.exports = {};\n"
  },
  {
    "path": "test-storybooks/standalone-preview/.yarnrc.yml",
    "content": "nodeLinker: node-modules\nenableImmutableInstalls: false\nyarnPath: ../../.yarn/releases/yarn-4.10.3.cjs\n"
  },
  {
    "path": "test-storybooks/standalone-preview/README.md",
    "content": "# Standalone Preview\n\nThis project demonstrates a preview running in standalone mode using `parcel`.\n\nTo run the standalone preview:\n\n```\nyarn storybook-preview\n```\n\nThis starts a `parcel` dev server on port `1337`.\n\nTo view the stories in the storybook UI:\n\n```\nyarn storybook\n```\n\nThis runs the Storybook dev server (Found in ../official-storybook), but instead of showing `official-storybook`'s stories, it attaches to the `parcel` dev server, lists its stories in the navigation, and shows its stories in the preview iframe.\n\n> NOTE: This can be run from any working storybook, not just `official-storybook`!\n"
  },
  {
    "path": "test-storybooks/standalone-preview/addPreview.ts",
    "content": "export {};\n\nglobal.PREVIEW_URL = process.env.PREVIEW_URL;\n"
  },
  {
    "path": "test-storybooks/standalone-preview/package.json",
    "content": "{\n  \"name\": \"standalone-preview\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"storybook\": \"cross-env STORYBOOK_DISPLAY_WARNING=true DISPLAY_WARNING=true NODE_OPTIONS=\\\"--preserve-symlinks --preserve-symlinks-main\\\" storybook dev -p 9011 -c ../official-storybook --preview-url=http://localhost:1337/external-iframe.html\",\n    \"storybook-preview\": \"cross-env PREVIEW_URL=external-iframe.html NODE_OPTIONS=\\\"--preserve-symlinks --preserve-symlinks-main\\\" parcel ./storybook.html --port 1337\"\n  },\n  \"resolutions\": {\n    \"@storybook/addon-a11y\": \"file:../../code/addons/a11y\",\n    \"@storybook/addon-docs\": \"file:../../code/addons/docs\",\n    \"@storybook/addon-links\": \"file:../../code/addons/links\",\n    \"@storybook/addon-themes\": \"file:../../code/addons/themes\",\n    \"@storybook/angular\": \"file:../../code/frameworks/angular\",\n    \"@storybook/builder-vite\": \"file:../../code/builders/builder-vite\",\n    \"@storybook/builder-webpack5\": \"file:../../code/builders/builder-webpack5\",\n    \"@storybook/codemod\": \"file:../../code/lib/codemod\",\n    \"@storybook/core-webpack\": \"file:../../code/lib/core-webpack\",\n    \"@storybook/csf-plugin\": \"file:../../code/lib/csf-plugin\",\n    \"@storybook/ember\": \"file:../../code/frameworks/ember\",\n    \"@storybook/html\": \"file:../../code/renderers/html\",\n    \"@storybook/nextjs\": \"file:../../code/frameworks/nextjs\",\n    \"@storybook/preact\": \"file:../../code/renderers/preact\",\n    \"@storybook/preact-vite\": \"file:../../code/frameworks/preact-vite\",\n    \"@storybook/preset-create-react-app\": \"file:../../code/presets/create-react-app\",\n    \"@storybook/preset-react-webpack\": \"file:../../code/presets/react-webpack\",\n    \"@storybook/preset-server-webpack\": \"file:../../code/presets/server-webpack\",\n    \"@storybook/react\": \"file:../../code/renderers/react\",\n    \"@storybook/react-dom-shim\": \"file:../../code/lib/react-dom-shim\",\n    \"@storybook/react-vite\": \"file:../../code/frameworks/react-vite\",\n    \"@storybook/react-webpack5\": \"file:../../code/frameworks/react-webpack5\",\n    \"@storybook/server\": \"file:../../code/renderers/server\",\n    \"@storybook/server-webpack5\": \"file:../../code/frameworks/server-webpack5\",\n    \"@storybook/svelte\": \"file:../../code/renderers/svelte\",\n    \"@storybook/svelte-vite\": \"file:../../code/frameworks/svelte-vite\",\n    \"@storybook/sveltekit\": \"file:../../code/frameworks/sveltekit\",\n    \"@storybook/vue3\": \"file:../../code/renderers/vue3\",\n    \"@storybook/vue3-vite\": \"file:../../code/frameworks/vue3-vite\",\n    \"@storybook/web-components\": \"file:../../code/renderers/web-components\",\n    \"@storybook/web-components-vite\": \"file:../../code/frameworks/web-components-vite\",\n    \"storybook\": \"file:../../../code/core\"\n  },\n  \"devDependencies\": {\n    \"@storybook/addon-docs\": \"*\",\n    \"@storybook/react\": \"*\",\n    \"@storybook/react-webpack5\": \"*\",\n    \"cross-env\": \"^7.0.3\",\n    \"parcel\": \"2.0.1\",\n    \"react\": \"16.14.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"storybook\": \"*\"\n  }\n}\n"
  },
  {
    "path": "test-storybooks/standalone-preview/stories/Component1.stories.tsx",
    "content": "import * as React from 'react';\n\nexport default {\n  title: 'Component 1',\n};\n\nexport const Story1 = () => <div>Component 1 - Story 1</div>;\n"
  },
  {
    "path": "test-storybooks/standalone-preview/stories/Component2.stories.tsx",
    "content": "import * as React from 'react';\n\nexport default {\n  title: 'Component 2',\n};\n\nexport const Story1 = () => <div>Component 2 - Story 1</div>;\nexport const Story2 = () => <div>Component 2 - Story 2</div>;\n"
  },
  {
    "path": "test-storybooks/standalone-preview/storybook.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\" />\n    <title></title>\n  </head>\n  <body>\n    <div id=\"storybook-root\"></div>\n    <div id=\"storybook-docs\"></div>\n    <script type=\"module\" src=\"./storybook.ts\"></script>\n    <div class=\"sb-errordisplay sb-wrapper\">\n      <div id=\"error-message\" class=\"sb-heading\"></div>\n      <pre class=\"sb-errordisplay_code\"><code id=\"error-stack\"></code></pre>\n    </div>\n  </body>\n</html>\n"
  },
  {
    "path": "test-storybooks/standalone-preview/storybook.ts",
    "content": "import './addPreview';\nimport { configure } from '@storybook/react';\n\nimport * as Comp1 from './stories/Component1.stories';\nimport * as Comp2 from './stories/Component2.stories';\n\nconfigure(() => [Comp1, Comp2], module);\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/.gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndist-ssr\n*.local\n\n# Editor directories and files\n.vscode/*\n!.vscode/extensions.json\n.idea\n.DS_Store\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n\n*storybook.log\nstorybook-static\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/.storybook/main.ts",
    "content": "import type { StorybookConfig } from \"@storybook/vue3-vite\";\n\nconst config: StorybookConfig = {\n  stories: [\"../src/**/*.mdx\", \"../src/**/*.stories.@(js|jsx|mjs|ts|tsx)\"],\n  addons: [\n    \"@chromatic-com/storybook\",\n    \"@storybook/addon-docs\",\n    \"@storybook/addon-a11y\",\n    \"@storybook/addon-vitest\",\n  ],\n  framework: {\n    name: \"@storybook/vue3-vite\",\n    options: {},\n  },\n};\nexport default config;\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/.storybook/preview.ts",
    "content": "import type { Preview } from '@storybook/react-vite'\n\nconst preview: Preview = {\n  parameters: {\n    controls: {\n      matchers: {\n       color: /(background|color)$/i,\n       date: /Date$/i,\n      },\n    },\n\n    a11y: {\n      // 'todo' - show a11y violations in the test UI only\n      // 'error' - fail CI on a11y violations\n      // 'off' - skip a11y checks entirely\n      test: 'todo'\n    }\n  },\n};\n\nexport default preview;"
  },
  {
    "path": "test-storybooks/yarn-pnp/.yarnrc.yml",
    "content": "# TODO: Remove this whole test-storybooks/yarn-pnp directory in SB11\n\nyarnPath: ../../.yarn/releases/yarn-4.10.3.cjs\n\nnodeLinker: pnp\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/eslint.config.js",
    "content": "// For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format\nimport storybook from \"eslint-plugin-storybook\";\n\nimport js from '@eslint/js'\nimport globals from 'globals'\nimport tseslint from 'typescript-eslint'\nimport { globalIgnores } from 'eslint/config'\n\nexport default tseslint.config([\n  globalIgnores(['dist']),\n  {\n    files: ['**/*.{ts,tsx}'],\n    extends: [\n      js.configs.recommended,\n      tseslint.configs.recommended,\n    ],\n    languageOptions: {\n      ecmaVersion: 2020,\n      globals: globals.browser,\n    },\n  },\n], storybook.configs[\"flat/recommended\"]);\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"UTF-8\" />\n  <link rel=\"icon\" type=\"image/svg+xml\" href=\"/vite.svg\" />\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n  <title>vue3-vite</title>\n</head>\n\n<body>\n  <div id=\"app\"></div>\n  <script type=\"module\" src=\"/src/main.ts\"></script>\n</body>\n\n</html>"
  },
  {
    "path": "test-storybooks/yarn-pnp/package.json",
    "content": "{\n  \"name\": \"yarn-pnp\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"vue-tsc -b && vite build\",\n    \"build-storybook\": \"storybook build\",\n    \"dev\": \"vite\",\n    \"preview\": \"vite preview\",\n    \"storybook\": \"storybook dev -p 6006\"\n  },\n  \"resolutions\": {\n    \"@playwright/test\": \"1.58.2\",\n    \"@storybook/addon-a11y\": \"file:../../code/addons/a11y\",\n    \"@storybook/addon-docs\": \"file:../../code/addons/docs\",\n    \"@storybook/addon-links\": \"file:../../code/addons/links\",\n    \"@storybook/addon-themes\": \"file:../../code/addons/themes\",\n    \"@storybook/addon-vitest\": \"file:../../code/addons/vitest\",\n    \"@storybook/angular\": \"file:../../code/frameworks/angular\",\n    \"@storybook/builder-vite\": \"file:../../code/builders/builder-vite\",\n    \"@storybook/builder-webpack5\": \"file:../../code/builders/builder-webpack5\",\n    \"@storybook/codemod\": \"file:../../code/lib/codemod\",\n    \"@storybook/core-webpack\": \"file:../../code/lib/core-webpack\",\n    \"@storybook/csf-plugin\": \"file:../../code/lib/csf-plugin\",\n    \"@storybook/ember\": \"file:../../code/frameworks/ember\",\n    \"@storybook/html\": \"file:../../code/renderers/html\",\n    \"@storybook/nextjs\": \"file:../../code/frameworks/nextjs\",\n    \"@storybook/preact\": \"file:../../code/renderers/preact\",\n    \"@storybook/preact-vite\": \"file:../../code/frameworks/preact-vite\",\n    \"@storybook/preset-create-react-app\": \"file:../../code/presets/create-react-app\",\n    \"@storybook/preset-react-webpack\": \"file:../../code/presets/react-webpack\",\n    \"@storybook/preset-server-webpack\": \"file:../../code/presets/server-webpack\",\n    \"@storybook/react\": \"file:../../code/renderers/react\",\n    \"@storybook/react-dom-shim\": \"file:../../code/lib/react-dom-shim\",\n    \"@storybook/react-vite\": \"file:../../code/frameworks/react-vite\",\n    \"@storybook/react-webpack5\": \"file:../../code/frameworks/react-webpack5\",\n    \"@storybook/server\": \"file:../../code/renderers/server\",\n    \"@storybook/server-webpack5\": \"file:../../code/frameworks/server-webpack5\",\n    \"@storybook/svelte\": \"file:../../code/renderers/svelte\",\n    \"@storybook/svelte-vite\": \"file:../../code/frameworks/svelte-vite\",\n    \"@storybook/sveltekit\": \"file:../../code/frameworks/sveltekit\",\n    \"@storybook/vue3\": \"file:../../code/renderers/vue3\",\n    \"@storybook/vue3-vite\": \"file:../../code/frameworks/vue3-vite\",\n    \"@storybook/web-components\": \"file:../../code/renderers/web-components\",\n    \"@storybook/web-components-vite\": \"file:../../code/frameworks/web-components-vite\",\n    \"eslint-plugin-storybook\": \"file:../../code/lib/eslint-plugin\",\n    \"playwright\": \"1.58.2\",\n    \"storybook\": \"file:../../code/core\"\n  },\n  \"dependencies\": {\n    \"vue\": \"^3.5.22\"\n  },\n  \"devDependencies\": {\n    \"@chromatic-com/storybook\": \"^4.1.2\",\n    \"@storybook/addon-a11y\": \"^10.1.0-alpha.6\",\n    \"@storybook/addon-docs\": \"^10.1.0-alpha.6\",\n    \"@storybook/addon-onboarding\": \"^10.1.0-alpha.6\",\n    \"@storybook/addon-vitest\": \"^10.1.0-alpha.6\",\n    \"@storybook/vue3-vite\": \"^10.1.0-alpha.6\",\n    \"@types/node\": \"^24.6.0\",\n    \"@vitejs/plugin-vue\": \"^6.0.1\",\n    \"@vitest/browser-playwright\": \"^4.0.7\",\n    \"@vitest/coverage-v8\": \"^4.0.7\",\n    \"@vue/tsconfig\": \"^0.8.1\",\n    \"eslint\": \"^9.29.0\",\n    \"eslint-plugin-storybook\": \"9.1.0-alpha.6\",\n    \"playwright\": \"^1.56.1\",\n    \"storybook\": \"^10.1.0-alpha.6\",\n    \"typescript\": \"~5.9.3\",\n    \"typescript-eslint\": \"^8.34.1\",\n    \"vite\": \"^7.1.7\",\n    \"vitest\": \"^4.0.14\",\n    \"vue-tsc\": \"^3.1.0\"\n  },\n  \"nx\": {\n    \"includedScripts\": []\n  }\n}"
  },
  {
    "path": "test-storybooks/yarn-pnp/project.json",
    "content": "{\n  \"name\": \"yarn-pnp\",\n  \"$schema\": \"../../node_modules/nx/schemas/project-schema.json\",\n  \"projectType\": \"application\",\n  \"targets\": {\n    \"test\": {\n      \"dependsOn\": [{ \"projects\": [\"*\"], \"target\": \"compile\" }],\n      \"executor\": \"nx:run-commands\",\n      \"options\": {\n        \"cwd\": \"{projectRoot}\",\n        \"command\": \"yarn --no-immutable && yarn storybook --smoke-test\"\n      },\n      \"configurations\": {\n        \"production\": {}\n      }\n    }\n  },\n  \"tags\": [\"ci:normal\", \"ci:merged\", \"ci:daily\"]\n}\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/src/App.vue",
    "content": "<script setup lang=\"ts\">\nimport HelloWorld from './components/HelloWorld.vue'\n</script>\n\n<template>\n  <div>\n    <a href=\"https://vite.dev\" target=\"_blank\">\n      <img src=\"/vite.svg\" class=\"logo\" alt=\"Vite logo\" />\n    </a>\n    <a href=\"https://vuejs.org/\" target=\"_blank\">\n      <img src=\"./assets/vue.svg\" class=\"logo vue\" alt=\"Vue logo\" />\n    </a>\n  </div>\n  <HelloWorld msg=\"Vite + Vue\" />\n</template>\n\n<style scoped>\n.logo {\n  height: 6em;\n  padding: 1.5em;\n  will-change: filter;\n  transition: filter 300ms;\n}\n.logo:hover {\n  filter: drop-shadow(0 0 2em #646cffaa);\n}\n.logo.vue:hover {\n  filter: drop-shadow(0 0 2em #42b883aa);\n}\n</style>\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/src/components/HelloWorld.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\n\ndefineProps<{ msg: string }>()\n\nconst count = ref(0)\n</script>\n\n<template>\n  <h1>{{ msg }}</h1>\n\n  <div class=\"card\">\n    <button type=\"button\" @click=\"count++\">count is {{ count }}</button>\n    <p>\n      Edit\n      <code>components/HelloWorld.vue</code> to test HMR\n    </p>\n  </div>\n\n  <p>\n    Check out\n    <a href=\"https://vuejs.org/guide/quick-start.html#local\" target=\"_blank\"\n      >create-vue</a\n    >, the official Vue + Vite starter\n  </p>\n  <p>\n    Learn more about IDE Support for Vue in the\n    <a\n      href=\"https://vuejs.org/guide/scaling-up/tooling.html#ide-support\"\n      target=\"_blank\"\n      >Vue Docs Scaling up Guide</a\n    >.\n  </p>\n  <p class=\"read-the-docs\">Click on the Vite and Vue logos to learn more</p>\n</template>\n\n<style scoped>\n.read-the-docs {\n  color: #888;\n}\n</style>\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/src/main.ts",
    "content": "import { createApp } from 'vue'\nimport './style.css'\nimport App from './App.vue'\n\ncreateApp(App).mount('#app')\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/src/stories/Button.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport { fn } from 'storybook/test';\n\nimport Button from './Button.vue';\n\n// More on how to set up stories at: https://storybook.js.org/docs/writing-stories\nconst meta = {\n  title: 'Example/Button',\n  component: Button,\n  // This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n  argTypes: {\n    size: { control: 'select', options: ['small', 'medium', 'large'] },\n    backgroundColor: { control: 'color' },\n  },\n  args: {\n    primary: false,\n    // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#story-args\n    onClick: fn(),\n  },\n} satisfies Meta<typeof Button>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n/*\n *👇 Render functions are a framework specific feature to allow you control on how the component renders.\n * See https://storybook.js.org/docs/api/csf\n * to learn how to use render functions.\n */\nexport const Primary: Story = {\n  args: {\n    primary: true,\n    label: 'Button',\n  },\n};\n\nexport const Secondary: Story = {\n  args: {\n    primary: false,\n    label: 'Button',\n  },\n};\n\nexport const Large: Story = {\n  args: {\n    label: 'Button',\n    size: 'large',\n  },\n};\n\nexport const Small: Story = {\n  args: {\n    label: 'Button',\n    size: 'small',\n  },\n};\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/src/stories/Button.vue",
    "content": "<template>\n  <button type=\"button\" :class=\"classes\" @click=\"onClick\" :style=\"style\">{{ label }}</button>\n</template>\n\n<script lang=\"ts\" setup>\nimport { computed } from 'vue';\n\nimport './button.css';\n\nconst props = withDefaults(\n  defineProps<{\n    /**\n     * The label of the button\n     */\n    label: string;\n    /**\n     * primary or secondary button\n     */\n    primary?: boolean;\n    /**\n     * size of the button\n     */\n    size?: 'small' | 'medium' | 'large';\n    /**\n     * background color of the button\n     */\n    backgroundColor?: string;\n  }>(),\n  { primary: false }\n);\n\nconst emit = defineEmits<{\n  (e: 'click', id: number): void;\n}>();\n\nconst classes = computed(() => ({\n  'storybook-button': true,\n  'storybook-button--primary': props.primary,\n  'storybook-button--secondary': !props.primary,\n  [`storybook-button--${props.size || 'medium'}`]: true,\n}));\n\nconst style = computed(() => ({\n  backgroundColor: props.backgroundColor,\n}));\n\nconst onClick = () => {\n  emit('click', 1);\n};\n</script>\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/src/stories/Configure.mdx",
    "content": "import { Meta } from \"@storybook/addon-docs/blocks\";\n\nimport Github from \"./assets/github.svg\";\nimport Discord from \"./assets/discord.svg\";\nimport Youtube from \"./assets/youtube.svg\";\nimport Tutorials from \"./assets/tutorials.svg\";\nimport Styling from \"./assets/styling.png\";\nimport Context from \"./assets/context.png\";\nimport Assets from \"./assets/assets.png\";\nimport Docs from \"./assets/docs.png\";\nimport Share from \"./assets/share.png\";\nimport FigmaPlugin from \"./assets/figma-plugin.png\";\nimport Testing from \"./assets/testing.png\";\nimport Accessibility from \"./assets/accessibility.png\";\nimport Theming from \"./assets/theming.png\";\nimport AddonLibrary from \"./assets/addon-library.png\";\n\nexport const RightArrow = () => <svg \n    viewBox=\"0 0 14 14\" \n    width=\"8px\" \n    height=\"14px\" \n    style={{ \n      marginLeft: '4px',\n      display: 'inline-block',\n      shapeRendering: 'inherit',\n      verticalAlign: 'middle',\n      fill: 'currentColor',\n      'path fill': 'currentColor'\n    }}\n>\n  <path d=\"m11.1 7.35-5.5 5.5a.5.5 0 0 1-.7-.7L10.04 7 4.9 1.85a.5.5 0 1 1 .7-.7l5.5 5.5c.2.2.2.5 0 .7Z\" />\n</svg>\n\n<Meta title=\"Configure your project\" />\n\n<div className=\"sb-container\">\n  <div className='sb-section-title'>\n    # Configure your project\n\n    Because Storybook works separately from your app, you'll need to configure it for your specific stack and setup. Below, explore guides for configuring Storybook with popular frameworks and tools. If you get stuck, learn how you can ask for help from our community.\n  </div>\n  <div className=\"sb-section\">\n    <div className=\"sb-section-item\">\n      <img\n        src={Styling}\n        alt=\"A wall of logos representing different styling technologies\"\n      />\n      <h4 className=\"sb-section-item-heading\">Add styling and CSS</h4>\n      <p className=\"sb-section-item-paragraph\">Like with web applications, there are many ways to include CSS within Storybook. Learn more about setting up styling within Storybook.</p>\n      <a\n        className=\"sb-action-link\"\n        href=\"https://storybook.js.org/docs/configure/styling-and-css/?renderer=vue&ref=configure\"\n        target=\"_blank\"\n      >Learn more<RightArrow /></a>\n    </div>\n    <div className=\"sb-section-item\">\n      <img\n        src={Context}\n        alt=\"An abstraction representing the composition of data for a component\"\n      />\n      <h4 className=\"sb-section-item-heading\">Provide context and mocking</h4>\n      <p className=\"sb-section-item-paragraph\">Often when a story doesn't render, it's because your component is expecting a specific environment or context (like a theme provider) to be available.</p>\n      <a\n        className=\"sb-action-link\"\n        href=\"https://storybook.js.org/docs/writing-stories/decorators/?renderer=vue&ref=configure#context-for-mocking\"\n        target=\"_blank\"\n      >Learn more<RightArrow /></a>\n    </div>\n    <div className=\"sb-section-item\">\n      <img src={Assets} alt=\"A representation of typography and image assets\" />\n      <div>\n        <h4 className=\"sb-section-item-heading\">Load assets and resources</h4>\n        <p className=\"sb-section-item-paragraph\">To link static files (like fonts) to your projects and stories, use the\n        `staticDirs` configuration option to specify folders to load when\n        starting Storybook.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/configure/images-and-assets/?renderer=vue&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n    </div>\n  </div>\n</div>\n<div className=\"sb-container\">\n  <div className='sb-section-title'>\n    # Do more with Storybook\n\n    Now that you know the basics, let's explore other parts of Storybook that will improve your experience. This list is just to get you started. You can customise Storybook in many ways to fit your needs.\n  </div>\n\n  <div className=\"sb-section\">\n    <div className=\"sb-features-grid\">\n      <div className=\"sb-grid-item\">\n        <img src={Docs} alt=\"A screenshot showing the autodocs tag being set, pointing a docs page being generated\" />\n        <h4 className=\"sb-section-item-heading\">Autodocs</h4>\n        <p className=\"sb-section-item-paragraph\">Auto-generate living,\n          interactive reference documentation from your components and stories.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/writing-docs/autodocs/?renderer=vue&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <img src={Share} alt=\"A browser window showing a Storybook being published to a chromatic.com URL\" />\n        <h4 className=\"sb-section-item-heading\">Publish to Chromatic</h4>\n        <p className=\"sb-section-item-paragraph\">Publish your Storybook to review and collaborate with your entire team.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/sharing/publish-storybook/?renderer=vue&ref=configure#publish-storybook-with-chromatic\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <img src={FigmaPlugin} alt=\"Windows showing the Storybook plugin in Figma\" />\n        <h4 className=\"sb-section-item-heading\">Figma Plugin</h4>\n        <p className=\"sb-section-item-paragraph\">Embed your stories into Figma to cross-reference the design and live\n          implementation in one place.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/sharing/design-integrations/?renderer=vue&ref=configure#embed-storybook-in-figma-with-the-plugin\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <img src={Testing} alt=\"Screenshot of tests passing and failing\" />\n        <h4 className=\"sb-section-item-heading\">Testing</h4>\n        <p className=\"sb-section-item-paragraph\">Use stories to test a component in all its variations, no matter how\n          complex.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/writing-tests/?renderer=vue&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <img src={Accessibility} alt=\"Screenshot of accessibility tests passing and failing\" />\n        <h4 className=\"sb-section-item-heading\">Accessibility</h4>\n        <p className=\"sb-section-item-paragraph\">Automatically test your components for a11y issues as you develop.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/writing-tests/accessibility-testing/?renderer=vue&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n      <div className=\"sb-grid-item\">\n        <img src={Theming} alt=\"Screenshot of Storybook in light and dark mode\" />\n        <h4 className=\"sb-section-item-heading\">Theming</h4>\n        <p className=\"sb-section-item-paragraph\">Theme Storybook's UI to personalize it to your project.</p>\n        <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/docs/configure/theming/?renderer=vue&ref=configure\"\n          target=\"_blank\"\n        >Learn more<RightArrow /></a>\n      </div>\n    </div>\n  </div>\n</div>\n<div className='sb-addon'>\n  <div className='sb-addon-text'>\n    <h4>Addons</h4>\n    <p className=\"sb-section-item-paragraph\">Integrate your tools with Storybook to connect workflows.</p>\n    <a\n        className=\"sb-action-link\"\n        href=\"https://storybook.js.org/addons/?ref=configure\"\n        target=\"_blank\"\n      >Discover all addons<RightArrow /></a>\n  </div>\n  <div className='sb-addon-img'>\n    <img src={AddonLibrary} alt=\"Integrate your tools with Storybook to connect workflows.\" />\n  </div>\n</div>\n\n<div className=\"sb-section sb-socials\">\n    <div className=\"sb-section-item\">\n      <img src={Github} alt=\"Github logo\" className=\"sb-explore-image\"/>\n      Join our contributors building the future of UI development.\n\n      <a\n        className=\"sb-action-link\"\n        href=\"https://github.com/storybookjs/storybook\"\n        target=\"_blank\"\n      >Star on GitHub<RightArrow /></a>\n    </div>\n    <div className=\"sb-section-item\">\n      <img src={Discord} alt=\"Discord logo\" className=\"sb-explore-image\"/>\n      <div>\n        Get support and chat with frontend developers.\n\n        <a\n          className=\"sb-action-link\"\n          href=\"https://discord.gg/storybook\"\n          target=\"_blank\"\n        >Join Discord server<RightArrow /></a>\n      </div>\n    </div>\n    <div className=\"sb-section-item\">\n      <img src={Youtube} alt=\"Youtube logo\" className=\"sb-explore-image\"/>\n      <div>\n        Watch tutorials, feature previews and interviews.\n\n        <a\n          className=\"sb-action-link\"\n          href=\"https://www.youtube.com/@chromaticui\"\n          target=\"_blank\"\n        >Watch on YouTube<RightArrow /></a>\n      </div>\n    </div>\n    <div className=\"sb-section-item\">\n      <img src={Tutorials} alt=\"A book\" className=\"sb-explore-image\"/>\n      <p>Follow guided walkthroughs on for key workflows.</p>\n\n      <a\n          className=\"sb-action-link\"\n          href=\"https://storybook.js.org/tutorials/?ref=configure\"\n          target=\"_blank\"\n        >Discover tutorials<RightArrow /></a>\n    </div>\n</div>\n\n<style>\n  {`\n  .sb-container {\n    margin-bottom: 48px;\n  }\n\n  .sb-section {\n    width: 100%;\n    display: flex;\n    flex-direction: row;\n    gap: 20px;\n  }\n\n  img {\n    object-fit: cover;\n  }\n\n  .sb-section-title {\n    margin-bottom: 32px;\n  }\n\n  .sb-section a:not(h1 a, h2 a, h3 a) {\n    font-size: 14px;\n  }\n\n  .sb-section-item, .sb-grid-item {\n    flex: 1;\n    display: flex;\n    flex-direction: column;\n  }\n\n  .sb-section-item-heading {\n    padding-top: 20px !important;\n    padding-bottom: 5px !important;\n    margin: 0 !important;\n  }\n  .sb-section-item-paragraph {\n    margin: 0;\n    padding-bottom: 10px;\n  }\n\n  .sb-action-link {\n    text-decoration: none;\n  }\n\n  .sb-action-link:hover, .sb-action-link:focus {\n    text-decoration: underline;\n    text-decoration-thickness: 0.03125rem;\n    text-underline-offset: 0.11em;\n  }\n\n  .sb-chevron {\n    margin-left: 5px;\n  }\n\n  .sb-features-grid {\n    display: grid;\n    grid-template-columns: repeat(2, 1fr);\n    grid-gap: 32px 20px;\n  }\n\n  .sb-socials {\n    display: grid;\n    grid-template-columns: repeat(4, 1fr);\n  }\n\n  .sb-socials p {\n    margin-bottom: 10px;\n  }\n\n  .sb-explore-image {\n    max-height: 32px;\n    align-self: flex-start;\n  }\n\n  .sb-addon {\n    width: 100%;\n    display: flex;\n    align-items: center;\n    position: relative;\n    background-color: #EEF3F8;\n    border-radius: 5px;\n    border: 1px solid rgba(0, 0, 0, 0.05);\n    background: #EEF3F8;\n    height: 180px;\n    margin-bottom: 48px;\n    overflow: hidden;\n  }\n\n  .sb-addon-text {\n    padding-left: 48px;\n    max-width: 240px;\n  }\n\n  .sb-addon-text h4 {\n    padding-top: 0px;\n  }\n\n  .sb-addon-img {\n    position: absolute;\n    left: 345px;\n    top: 0;\n    height: 100%;\n    width: 200%;\n    overflow: hidden;\n  }\n\n  .sb-addon-img img {\n    width: 650px;\n    transform: rotate(-15deg);\n    margin-left: 40px;\n    margin-top: -72px;\n    box-shadow: 0 0 1px rgba(255, 255, 255, 0);\n    backface-visibility: hidden;\n  }\n\n  @media screen and (max-width: 800px) {\n    .sb-addon-img {\n      left: 300px;\n    }\n  }\n\n  @media screen and (max-width: 600px) {\n    .sb-section {\n      flex-direction: column;\n    }\n\n    .sb-features-grid {\n      grid-template-columns: repeat(1, 1fr);\n    }\n\n    .sb-socials {\n      grid-template-columns: repeat(2, 1fr);\n    }\n\n    .sb-addon {\n      height: 280px;\n      align-items: flex-start;\n      padding-top: 32px;\n      overflow: hidden;\n    }\n\n    .sb-addon-text {\n      padding-left: 24px;\n    }\n\n    .sb-addon-img {\n      right: 0;\n      left: 0;\n      top: 130px;\n      bottom: 0;\n      overflow: hidden;\n      height: auto;\n      width: 124%;\n    }\n\n    .sb-addon-img img {\n      width: 1200px;\n      transform: rotate(-12deg);\n      margin-left: 0;\n      margin-top: 48px;\n      margin-bottom: -40px;\n      margin-left: -24px;\n    }\n  }\n  `}\n</style>\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/src/stories/Header.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport { fn } from 'storybook/test';\n\nimport MyHeader from './Header.vue';\n\nconst meta = {\n  /* 👇 The title prop is optional.\n   * See https://storybook.js.org/docs/configure/#configure-story-loading\n   * to learn how to generate automatic titles\n   */\n  title: 'Example/Header',\n  component: MyHeader,\n  render: (args: any) => ({\n    components: { MyHeader },\n    setup() {\n      return { args };\n    },\n    template: '<my-header :user=\"args.user\" />',\n  }),\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  args: {\n    onLogin: fn(),\n    onLogout: fn(),\n    onCreateAccount: fn(),\n  },\n  // This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n} satisfies Meta<typeof MyHeader>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const LoggedIn: Story = {\n  args: {\n    user: {\n      name: 'Jane Doe',\n    },\n  },\n};\n\nexport const LoggedOut: Story = {\n  args: {\n    user: null,\n  },\n};\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/src/stories/Header.vue",
    "content": "<template>\n  <header>\n    <div class=\"storybook-header\">\n      <div>\n        <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fill-rule=\"evenodd\">\n            <path\n              d=\"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z\"\n              fill=\"#FFF\"\n            />\n            <path\n              d=\"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z\"\n              fill=\"#555AB9\"\n            />\n            <path\n              d=\"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z\"\n              fill=\"#91BAF8\"\n            />\n          </g>\n        </svg>\n        <h1>Acme</h1>\n      </div>\n      <div>\n        <span class=\"welcome\" v-if=\"user\"\n          >Welcome, <b>{{ user.name }}</b\n          >!</span\n        >\n        <my-button size=\"small\" @click=\"$emit('logout')\" label=\"Log out\" v-if=\"user\" />\n        <my-button size=\"small\" @click=\"$emit('login')\" label=\"Log in\" v-if=\"!user\" />\n        <my-button\n          primary\n          size=\"small\"\n          @click=\"$emit('createAccount')\"\n          label=\"Sign up\"\n          v-if=\"!user\"\n        />\n      </div>\n    </div>\n  </header>\n</template>\n\n<script lang=\"ts\" setup>\nimport MyButton from './Button.vue';\nimport './header.css';\n\ndefineProps<{ user: { name: string } | null }>();\n\ndefineEmits<{\n  (event: 'createAccount'): void;\n  (event: 'login'): void;\n  (event: 'logout'): void;\n}>();\n</script>\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/src/stories/Page.stories.ts",
    "content": "import type { Meta, StoryObj } from '@storybook/vue3-vite';\n\nimport { expect, userEvent, within } from 'storybook/test';\n\nimport MyPage from './Page.vue';\n\nconst meta = {\n  title: 'Example/Page',\n  component: MyPage,\n  render: () => ({\n    components: { MyPage },\n    template: '<my-page />',\n  }),\n  parameters: {\n    // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout\n    layout: 'fullscreen',\n  },\n  // This component will have an automatically generated docsPage entry: https://storybook.js.org/docs/writing-docs/autodocs\n  tags: ['autodocs'],\n} satisfies Meta<typeof MyPage>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\n// More on component testing: https://storybook.js.org/docs/writing-tests/interaction-testing\nexport const LoggedIn: Story = {\n  play: async ({ canvasElement }: any) => {\n    const canvas = within(canvasElement);\n    const loginButton = canvas.getByRole('button', { name: /Log in/i });\n    await expect(loginButton).toBeInTheDocument();\n    await userEvent.click(loginButton);\n    await expect(loginButton).not.toBeInTheDocument();\n\n    const logoutButton = canvas.getByRole('button', { name: /Log out/i });\n    await expect(logoutButton).toBeInTheDocument();\n  },\n};\n\nexport const LoggedOut: Story = {};\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/src/stories/Page.vue",
    "content": "<template>\n  <article>\n    <my-header :user=\"user\" @login=\"onLogin\" @logout=\"onLogout\" @create-account=\"onCreateAccount\" />\n\n    <section class=\"storybook-page\">\n      <h2>Pages in Storybook</h2>\n      <p>\n        We recommend building UIs with a\n        <a href=\"https://componentdriven.org\" target=\"_blank\" rel=\"noopener noreferrer\">\n          <strong>component-driven</strong>\n        </a>\n        process starting with atomic components and ending with pages.\n      </p>\n      <p>\n        Render pages with mock data. This makes it easy to build and review page states without\n        needing to navigate to them in your app. Here are some handy patterns for managing page data\n        in Storybook:\n      </p>\n      <ul>\n        <li>\n          Use a higher-level connected component. Storybook helps you compose such data from the\n          \"args\" of child component stories\n        </li>\n        <li>\n          Assemble data in the page component from your services. You can mock these services out\n          using Storybook.\n        </li>\n      </ul>\n      <p>\n        Get a guided tutorial on component-driven development at\n        <a href=\"https://storybook.js.org/tutorials/\" target=\"_blank\" rel=\"noopener noreferrer\"\n          >Storybook tutorials</a\n        >\n        . Read more in the\n        <a href=\"https://storybook.js.org/docs\" target=\"_blank\" rel=\"noopener noreferrer\">docs</a>\n        .\n      </p>\n      <div class=\"tip-wrapper\">\n        <span class=\"tip\">Tip</span>\n        Adjust the width of the canvas with the\n        <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" xmlns=\"http://www.w3.org/2000/svg\">\n          <g fill=\"none\" fill-rule=\"evenodd\">\n            <path\n              d=\"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z\"\n              id=\"a\"\n              fill=\"#999\"\n            />\n          </g>\n        </svg>\n        Viewports addon in the toolbar\n      </div>\n    </section>\n  </article>\n</template>\n\n<script lang=\"ts\" setup>\nimport { ref } from 'vue';\n\nimport MyHeader from './Header.vue';\nimport './page.css';\n\nconst user = ref<{ name: string } | null>(null);\n\nconst onLogin = () => {\n  user.value = { name: 'Jane Doe' };\n};\nconst onLogout = () => {\n  user.value = null;\n};\nconst onCreateAccount = () => {\n  user.value = { name: 'Jane Doe' };\n};\n</script>\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/src/stories/button.css",
    "content": ".storybook-button {\n  display: inline-block;\n  cursor: pointer;\n  border: 0;\n  border-radius: 3em;\n  font-weight: 700;\n  line-height: 1;\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n.storybook-button--primary {\n  background-color: #555ab9;\n  color: white;\n}\n.storybook-button--secondary {\n  box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;\n  background-color: transparent;\n  color: #333;\n}\n.storybook-button--small {\n  padding: 10px 16px;\n  font-size: 12px;\n}\n.storybook-button--medium {\n  padding: 11px 20px;\n  font-size: 14px;\n}\n.storybook-button--large {\n  padding: 12px 24px;\n  font-size: 16px;\n}\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/src/stories/header.css",
    "content": ".storybook-header {\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n  padding: 15px 20px;\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n\n.storybook-header svg {\n  display: inline-block;\n  vertical-align: top;\n}\n\n.storybook-header h1 {\n  display: inline-block;\n  vertical-align: top;\n  margin: 6px 0 6px 10px;\n  font-weight: 700;\n  font-size: 20px;\n  line-height: 1;\n}\n\n.storybook-header button + button {\n  margin-left: 10px;\n}\n\n.storybook-header .welcome {\n  margin-right: 10px;\n  color: #333;\n  font-size: 14px;\n}\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/src/stories/page.css",
    "content": ".storybook-page {\n  margin: 0 auto;\n  padding: 48px 20px;\n  max-width: 600px;\n  color: #333;\n  font-size: 14px;\n  line-height: 24px;\n  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n}\n\n.storybook-page h2 {\n  display: inline-block;\n  vertical-align: top;\n  margin: 0 0 4px;\n  font-weight: 700;\n  font-size: 32px;\n  line-height: 1;\n}\n\n.storybook-page p {\n  margin: 1em 0;\n}\n\n.storybook-page a {\n  color: inherit;\n}\n\n.storybook-page ul {\n  margin: 1em 0;\n  padding-left: 30px;\n}\n\n.storybook-page li {\n  margin-bottom: 8px;\n}\n\n.storybook-page .tip {\n  display: inline-block;\n  vertical-align: top;\n  margin-right: 10px;\n  border-radius: 1em;\n  background: #e7fdd8;\n  padding: 4px 12px;\n  color: #357a14;\n  font-weight: 700;\n  font-size: 11px;\n  line-height: 12px;\n}\n\n.storybook-page .tip-wrapper {\n  margin-top: 40px;\n  margin-bottom: 40px;\n  font-size: 13px;\n  line-height: 20px;\n}\n\n.storybook-page .tip-wrapper svg {\n  display: inline-block;\n  vertical-align: top;\n  margin-top: 3px;\n  margin-right: 4px;\n  width: 12px;\n  height: 12px;\n}\n\n.storybook-page .tip-wrapper svg path {\n  fill: #1ea7fd;\n}\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/src/style.css",
    "content": ":root {\n  font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;\n  line-height: 1.5;\n  font-weight: 400;\n\n  color-scheme: light dark;\n  color: rgba(255, 255, 255, 0.87);\n  background-color: #242424;\n\n  font-synthesis: none;\n  text-rendering: optimizeLegibility;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\na {\n  font-weight: 500;\n  color: #646cff;\n  text-decoration: inherit;\n}\na:hover {\n  color: #535bf2;\n}\n\nbody {\n  margin: 0;\n  display: flex;\n  place-items: center;\n  min-width: 320px;\n  min-height: 100vh;\n}\n\nh1 {\n  font-size: 3.2em;\n  line-height: 1.1;\n}\n\nbutton {\n  border-radius: 8px;\n  border: 1px solid transparent;\n  padding: 0.6em 1.2em;\n  font-size: 1em;\n  font-weight: 500;\n  font-family: inherit;\n  background-color: #1a1a1a;\n  cursor: pointer;\n  transition: border-color 0.25s;\n}\nbutton:hover {\n  border-color: #646cff;\n}\nbutton:focus,\nbutton:focus-visible {\n  outline: 4px auto -webkit-focus-ring-color;\n}\n\n.card {\n  padding: 2em;\n}\n\n#app {\n  max-width: 1280px;\n  margin: 0 auto;\n  padding: 2rem;\n  text-align: center;\n}\n\n@media (prefers-color-scheme: light) {\n  :root {\n    color: #213547;\n    background-color: #ffffff;\n  }\n  a:hover {\n    color: #747bff;\n  }\n  button {\n    background-color: #f9f9f9;\n  }\n}\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/tsconfig.app.json",
    "content": "{\n  \"compilerOptions\": {\n    \"tsBuildInfoFile\": \"./node_modules/.tmp/tsconfig.app.tsbuildinfo\",\n    \"target\": \"ES2022\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n    \"module\": \"ESNext\",\n    \"skipLibCheck\": true,\n    \"types\": [\"vite/client\"],\n\n    /* Bundler mode */\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"verbatimModuleSyntax\": true,\n    \"moduleDetection\": \"force\",\n    \"noEmit\": true,\n\n    /* Linting */\n    \"strict\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"erasableSyntaxOnly\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"noUncheckedSideEffectImports\": true\n  },\n  \"include\": [\"src/**/*.ts\", \"src/**/*.tsx\", \"src/**/*.vue\"]\n}\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/tsconfig.json",
    "content": "{\n  \"files\": [],\n  \"references\": [\n    { \"path\": \"./tsconfig.app.json\" },\n    { \"path\": \"./tsconfig.node.json\" }\n  ]\n}\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/tsconfig.node.json",
    "content": "{\n  \"compilerOptions\": {\n    \"tsBuildInfoFile\": \"./node_modules/.tmp/tsconfig.node.tsbuildinfo\",\n    \"target\": \"ES2023\",\n    \"lib\": [\"ES2023\"],\n    \"module\": \"ESNext\",\n    \"types\": [\"node\"],\n    \"skipLibCheck\": true,\n\n    /* Bundler mode */\n    \"moduleResolution\": \"bundler\",\n    \"allowImportingTsExtensions\": true,\n    \"verbatimModuleSyntax\": true,\n    \"moduleDetection\": \"force\",\n    \"noEmit\": true,\n\n    /* Linting */\n    \"strict\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"erasableSyntaxOnly\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"noUncheckedSideEffectImports\": true\n  },\n  \"include\": [\"vite.config.ts\"]\n}\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/vite.config.ts",
    "content": "/// <reference types=\"vitest/config\" />\nimport { defineConfig } from \"vite\";\nimport vue from \"@vitejs/plugin-vue\";\n\n// https://vite.dev/config/\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { storybookTest } from \"@storybook/addon-vitest/vitest-plugin\";\nimport { playwright } from \"@vitest/browser-playwright\";\nconst dirname =\n  typeof __dirname !== \"undefined\"\n    ? __dirname\n    : path.dirname(fileURLToPath(import.meta.url));\n\n// More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon\nexport default defineConfig({\n  plugins: [vue()],\n  test: {\n    projects: [\n      {\n        extends: true,\n        plugins: [\n          // The plugin will run tests for the stories defined in your Storybook config\n          // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest\n          storybookTest({\n            configDir: path.join(dirname, \".storybook\"),\n          }),\n        ],\n        test: {\n          name: \"storybook\",\n          browser: {\n            enabled: true,\n            headless: true,\n            provider: playwright({}),\n            instances: [\n              {\n                browser: \"chromium\",\n              },\n            ],\n          },\n          setupFiles: [\".storybook/vitest.setup.ts\"],\n        },\n      },\n    ],\n  },\n});\n"
  },
  {
    "path": "test-storybooks/yarn-pnp/vitest.shims.d.ts",
    "content": "/// <reference types=\"@vitest/browser-playwright\" />\n"
  },
  {
    "path": "vitest.config.ts",
    "content": "import { coverageConfigDefaults, defineConfig } from 'vitest/config';\n\n/**\n * CircleCI reports the wrong number of threads to Node.js, so we need to set it manually. Unit\n * tests are running with the xlarge resource class, which has 8 vCPUs.\n *\n * @see https://jahed.dev/2022/11/20/fixing-node-js-multi-threading-on-circleci/\n * @see https://vitest.dev/config/maxworkers.html#maxworkers\n * @see https://circleci.com/docs/configuration-reference/#x86\n * @see .circleci/config.yml#L187\n */\nconst threadCount = process.env.CI ? (process.platform === 'win32' ? 4 : 7) : undefined;\nconst shouldRunStorybookTests = !(process.env.CI && process.platform === 'win32');\n\nconst projects = [\n  'code/addons/*/vitest.config.ts',\n  'code/frameworks/*/vitest.config.ts',\n  'code/lib/*/vitest.config.ts',\n  'code/core/vitest.config.ts',\n  'code/builders/*/vitest.config.ts',\n  'code/presets/*/vitest.config.ts',\n  'code/renderers/*/vitest.config.ts',\n  'scripts/vitest.config.ts',\n];\n\n/**\n * On CI, we run our own unit tests, but for performance reasons, we don't install playwright, thus\n * these tests, that need browser-mode cannot be run/added\n */\nif (shouldRunStorybookTests) {\n  projects.push('code/vitest.config.storybook.ts');\n}\n\nexport default defineConfig({\n  test: {\n    env: {\n      NODE_ENV: 'test',\n    },\n\n    pool: 'threads',\n    maxWorkers: threadCount,\n    projects,\n\n    coverage: {\n      provider: 'istanbul',\n      exclude: [\n        ...coverageConfigDefaults.exclude,\n        '**/__mocks/**',\n        '**/dist/**',\n        'playwright.config.ts',\n        'vitest-setup.ts',\n        'vitest.helpers.ts',\n        '**/*.stories.*',\n      ],\n    },\n  },\n});\n"
  }
]